vinyl-cache/bin/vinyld/cache/cache_req_fsm.c
0
/*-
1
 * Copyright (c) 2006 Verdens Gang AS
2
 * Copyright (c) 2006-2017 Varnish Software AS
3
 * All rights reserved.
4
 *
5
 * Author: Poul-Henning Kamp <phk@phk.freebsd.dk>
6
 *
7
 * SPDX-License-Identifier: BSD-2-Clause
8
 *
9
 * Redistribution and use in source and binary forms, with or without
10
 * modification, are permitted provided that the following conditions
11
 * are met:
12
 * 1. Redistributions of source code must retain the above copyright
13
 *    notice, this list of conditions and the following disclaimer.
14
 * 2. Redistributions in binary form must reproduce the above copyright
15
 *    notice, this list of conditions and the following disclaimer in the
16
 *    documentation and/or other materials provided with the distribution.
17
 *
18
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21
 * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
22
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28
 * SUCH DAMAGE.
29
 *
30
 * This file contains the request-handling state engine, which is intended to
31
 * (over time) be(come) protocol agnostic.
32
 * We already use this now with ESI:includes, which are for all relevant
33
 * purposes a different "protocol"
34
 *
35
 * A special complication is the fact that we can suspend processing of
36
 * a request when hash-lookup finds a busy objhdr.
37
 *
38
 */
39
40
#include "config.h"
41
42
#include "cache_int.h"
43
#include "cache_filter.h"
44
#include "cache_objhead.h"
45
#include "cache_transport.h"
46
#include "vcc_interface.h"
47
48
#include "http1/cache_http1.h"
49
#include "storage/storage.h"
50
#include "vcl.h"
51
#include "vct.h"
52
#include "vsha256.h"
53
#include "vtim.h"
54
55
#define REQ_STEPS \
56
  REQ_STEP(transport,           TRANSPORT,      ) \
57
  REQ_STEP(restart,             RESTART,        static) \
58
  REQ_STEP(recv,                RECV,           ) \
59
  REQ_STEP(pipe,                PIPE,           static) \
60
  REQ_STEP(pass,                PASS,           static) \
61
  REQ_STEP(lookup,              LOOKUP,         static) \
62
  REQ_STEP(purge,               PURGE,          static) \
63
  REQ_STEP(miss,                MISS,           static) \
64
  REQ_STEP(fetch,               FETCH,          static) \
65
  REQ_STEP(deliver,             DELIVER,        static) \
66
  REQ_STEP(vclfail,             VCLFAIL,        static) \
67
  REQ_STEP(synth,               SYNTH,          static) \
68
  REQ_STEP(transmit,            TRANSMIT,       static) \
69
  REQ_STEP(finish,              FINISH,         static)
70
71
#define REQ_STEP(l, U, priv) \
72
    static req_state_f cnt_##l; \
73
    priv const struct req_step R_STP_##U[1] = {{ \
74
        .name = "Req Step " #l, \
75
        .func = cnt_##l, \
76
    }};
77
REQ_STEPS
78
#undef REQ_STEP
79
80
/*--------------------------------------------------------------------
81
 * Handle "Expect:" and "Connection:" on incoming request
82
 */
83
84
static enum req_fsm_nxt v_matchproto_(req_state_f)
85 86099
cnt_transport(struct worker *wrk, struct req *req)
86
{
87
        const char *p;
88
89 86099
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
90 86099
        CHECK_OBJ_NOTNULL(req, REQ_MAGIC);
91 86099
        CHECK_OBJ_NOTNULL(req->http, HTTP_MAGIC);
92 86099
        CHECK_OBJ_NOTNULL(req->transport, TRANSPORT_MAGIC);
93 86099
        AN(req->req_body_status);
94
95 86099
        if (http_GetHdr(req->http, H_Expect, &p)) {
96 252
                if (!http_expect_eq(p, 100-continue)) {
97 42
                        req->doclose = SC_RX_JUNK;
98 42
                        (void)req->transport->minimal_response(req, 417);
99 42
                        wrk->stats->client_req_417++;
100 42
                        return (REQ_FSM_DONE);
101
                }
102 210
                if (req->http->protover >= 11 &&
103 210
                    req->htc->pipeline_b == NULL)       // XXX: HTTP1 vs 2 ?
104 189
                        req->want100cont = 1;
105 210
                http_Unset(req->http, H_Expect);
106 210
        }
107
108 86057
        AZ(req->err_code);
109
110 86057
        req->doclose = http_DoConnection(req->http, SC_REQ_CLOSE);
111 86057
        if (req->doclose == SC_RX_BAD) {
112 63
                wrk->stats->client_req_400++;
113 63
                (void)req->transport->minimal_response(req, 400);
114 63
                return (REQ_FSM_DONE);
115
        }
116
117 85994
        if (req->req_body_status->avail == 1) {
118 5712
                AN(req->transport->req_body != NULL);
119 5712
                VFP_Setup(req->vfc, wrk);
120 5712
                req->vfc->resp = req->http;             // XXX
121 5712
                req->transport->req_body(req);
122 5712
        }
123
124 85994
        req->ws_req = WS_Snapshot(req->ws);
125 85994
        HTTP_Clone(req->http0, req->http);      // For ESI & restart
126 85994
        req->req_step = R_STP_RECV;
127 85994
        return (REQ_FSM_MORE);
128 86099
}
129
130
/*--------------------------------------------------------------------
131
 * Deliver an object to client
132
 */
133
134
int
135 73268
Resp_Setup_Deliver(struct req *req)
136
{
137
        struct http *h;
138
        struct objcore *oc;
139
        const void *hdrs;
140
141 73268
        CHECK_OBJ_NOTNULL(req, REQ_MAGIC);
142 73268
        oc = req->objcore;
143 73268
        CHECK_OBJ_NOTNULL(oc, OBJCORE_MAGIC);
144
145 73268
        h = req->resp;
146
147 73268
        HTTP_Setup(h, req->ws, req->vsl, SLT_RespMethod);
148
149 73268
        hdrs = ObjGetAttr(req->wrk, oc, OA_HEADERS, NULL);
150 73268
        if (hdrs == NULL || HTTP_Decode(h, hdrs))
151 59
                return (-1);
152
153 73223
        http_ForceField(h, HTTP_HDR_PROTO, "HTTP/1.1");
154
155 73223
        if (req->is_hit)
156 48734
                http_PrintfHeader(h, "X-Vinyl: %ju %ju", VXID(req->vsl->wid),
157 24367
                    VXID(ObjGetXID(req->wrk, oc)));
158
        else
159 48856
                http_PrintfHeader(h, "X-Vinyl: %ju", VXID(req->vsl->wid));
160
161
        /*
162
         * We base Age calculation upon the last timestamp taken during client
163
         * request processing. This gives some inaccuracy, but since Age is only
164
         * full second resolution that shouldn't matter. (Last request timestamp
165
         * could be a Start timestamp taken before the object entered into cache
166
         * leading to negative age. Truncate to zero in that case).
167
         */
168 146446
        http_PrintfHeader(h, "Age: %.0f",
169 73223
            floor(fmax(0., req->t_prev - oc->t_origin)));
170
171 73223
        http_AppendHeader(h, H_Via, http_ViaHeader());
172
173 78998
        if (cache_param->http_gzip_support &&
174 73121
            ObjCheckFlag(req->wrk, oc, OF_GZIPED) &&
175 5775
            !RFC2616_Req_Gzip(req->http))
176 2100
                RFC2616_Weaken_Etag(h);
177 73223
        return (0);
178 73282
}
179
180
void
181 14125
Resp_Setup_Synth(struct req *req)
182
{
183
        struct http *h;
184
185 14125
        CHECK_OBJ_NOTNULL(req, REQ_MAGIC);
186
187 14125
        h = req->resp;
188
189 14125
        HTTP_Setup(h, req->ws, req->vsl, SLT_RespMethod);
190
191 14125
        AZ(req->objcore);
192 14125
        http_PutResponse(h, "HTTP/1.1", req->err_code, req->err_reason);
193
194 14125
        http_TimeHeader(h, "Date: ", W_TIM_real(req->wrk));
195 14125
        http_SetHeader(h, "Server: Vinyl-Cache");
196 14125
        http_PrintfHeader(h, "X-Vinyl: %ju", VXID(req->vsl->wid));
197
198
        /*
199
         * For late 100-continue, we suggest to VCL to close the connection to
200
         * neither send a 100-continue nor drain-read the request. But VCL has
201
         * the option to veto by removing Connection: close
202
         */
203 14125
        if (req->want100cont)
204 63
                http_SetHeader(h, "Connection: close");
205 14125
}
206
207
static enum req_fsm_nxt v_matchproto_(req_state_f)
208 73044
cnt_deliver(struct worker *wrk, struct req *req)
209
{
210
        unsigned status;
211
212 73044
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
213 73044
        CHECK_OBJ_NOTNULL(req, REQ_MAGIC);
214 73044
        CHECK_OBJ_NOTNULL(req->objcore, OBJCORE_MAGIC);
215 73044
        CHECK_OBJ_NOTNULL(req->objcore->objhead, OBJHEAD_MAGIC);
216 73044
        AZ(req->stale_oc);
217 73044
        AN(req->vcl);
218
219 73044
        assert(req->objcore->refcnt > 0);
220
221 73044
        ObjTouch(req->wrk, req->objcore, req->t_prev);
222
223 73044
        if (Resp_Setup_Deliver(req)) {
224 42
                (void)HSH_DerefObjCore(wrk, &req->objcore);
225 42
                req->err_code = 500;
226 42
                req->req_step = R_STP_SYNTH;
227 42
                return (REQ_FSM_MORE);
228
        }
229
230 73002
        status = http_GetStatus(req->resp);
231 73002
        if (cache_param->http_range_support && status == 200 &&
232 65040
            !(req->objcore->flags & OC_F_PRIVATE))
233 50158
                http_ForceHeader(req->resp, H_Accept_Ranges, "bytes");
234
235 73002
        req->esi_include_onerror = FEATURE(FEATURE_ESI_INCLUDE_ONERROR);
236
237 73002
        req->t_resp = W_TIM_real(wrk);
238 73002
        VCL_deliver_method(req->vcl, wrk, req, NULL, NULL);
239
240 73002
        assert(req->restarts <= req->max_restarts);
241
242 73002
        if (wrk->vpi->handling != VCL_RET_DELIVER) {
243 1660
                HSH_Cancel(wrk, req->objcore, NULL);
244 1660
                Req_StashObjcore(req, &req->objcore);
245 1660
                http_Teardown(req->resp);
246
247 1660
                switch (wrk->vpi->handling) {
248
                case VCL_RET_RESTART:
249 693
                        req->req_step = R_STP_RESTART;
250 693
                        break;
251
                case VCL_RET_FAIL:
252 799
                        req->req_step = R_STP_VCLFAIL;
253 799
                        break;
254
                case VCL_RET_SYNTH:
255 168
                        req->req_step = R_STP_SYNTH;
256 168
                        break;
257
                default:
258 0
                        WRONG("Illegal return from vcl_deliver{}");
259 0
                }
260
261 1660
                return (REQ_FSM_MORE);
262
        }
263
264 71342
        VSLb_ts_req(req, "Process", W_TIM_real(wrk));
265
266 71342
        assert(wrk->vpi->handling == VCL_RET_DELIVER);
267
268 71342
        if (IS_TOPREQ(req) && RFC2616_Do_Cond(req))
269 630
                http_PutResponse(req->resp, "HTTP/1.1", 304, NULL);
270
271 71342
        req->req_step = R_STP_TRANSMIT;
272 71342
        return (REQ_FSM_MORE);
273 73044
}
274
275
/*--------------------------------------------------------------------
276
 * VCL failed, die horribly
277
 */
278
279
static enum req_fsm_nxt v_matchproto_(req_state_f)
280 2371
cnt_vclfail(struct worker *wrk, struct req *req)
281
{
282
        struct vrt_ctx ctx[1];
283
284 2371
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
285 2371
        CHECK_OBJ_NOTNULL(req, REQ_MAGIC);
286
287 2371
        AZ(req->objcore);
288 2371
        AZ(req->stale_oc);
289
290 2371
        INIT_OBJ(ctx, VRT_CTX_MAGIC);
291 2371
        VCL_Req2Ctx(ctx, req);
292
293 2371
        Req_Rollback(ctx);
294
295 2371
        if (req->req_reset) {
296 565
                req->err_code = 408;
297 565
                req->err_reason = "Client disconnected";
298 565
        } else {
299 1806
                req->err_code = 503;
300 1806
                req->err_reason = "VCL failed";
301
        }
302 2371
        req->req_step = R_STP_SYNTH;
303 2371
        req->doclose = SC_VCL_FAILURE;
304 2371
        req->vdp_filter_list = NULL;
305 2371
        return (REQ_FSM_MORE);
306
}
307
308
/*--------------------------------------------------------------------
309
 * Emit a synthetic response
310
 */
311
312
static enum req_fsm_nxt v_matchproto_(req_state_f)
313 14086
cnt_synth(struct worker *wrk, struct req *req)
314
{
315
        struct vsb *synth_body;
316 14086
        ssize_t sz, szl = 0;
317
        uint16_t status;
318
        uint8_t *ptr;
319
        const char *body;
320
321 14086
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
322 14086
        CHECK_OBJ_NOTNULL(req, REQ_MAGIC);
323
324 14086
        AZ(req->objcore);
325 14086
        AZ(req->stale_oc);
326
327 14086
        wrk->stats->s_synth++;
328
329 14086
        if (req->err_code < 100)
330 0
                req->err_code = 501;
331
332 14086
        Resp_Setup_Synth(req);
333
334 14086
        req->vdp_filter_list = NULL;
335
336
        // XXX  for a BocLess storage (ssy), we do not use synth_body
337
        //      otherwise (malloc), we should still copy directly to
338
        //      the object
339 14086
        synth_body = VSB_new_auto();
340 14086
        AN(synth_body);
341
342 14086
        req->t_resp = W_TIM_real(wrk);
343 14086
        VCL_synth_method(req->vcl, wrk, req, NULL, synth_body);
344
345 14086
        AZ(VSB_finish(synth_body));
346
347 14086
        VSLb_ts_req(req, "Process", W_TIM_real(wrk));
348
349 14086
        while (wrk->vpi->handling == VCL_RET_FAIL) {
350 1953
                if (req->esi_level > 0) {
351 21
                        wrk->vpi->handling = VCL_RET_DELIVER;
352 21
                        break;
353
                }
354 1932
                VSB_destroy(&synth_body);
355 1932
                (void)VRB_Ignore(req);
356 1932
                status = req->req_reset ? 408 : 500;
357 1932
                (void)req->transport->minimal_response(req, status);
358 1932
                req->doclose = SC_VCL_FAILURE; // XXX: Not necessary any more ?
359 1932
                VSLb_ts_req(req, "Resp", W_TIM_real(wrk));
360 1932
                http_Teardown(req->resp);
361 1932
                return (REQ_FSM_DONE);
362
        }
363
364 12154
        if (wrk->vpi->handling == VCL_RET_RESTART && req->restarts > req->max_restarts)
365 21
                wrk->vpi->handling = VCL_RET_DELIVER;
366
367 12154
        if (wrk->vpi->handling == VCL_RET_RESTART) {
368
                /*
369
                 * XXX: Should we reset req->doclose = SC_VCL_FAILURE
370
                 * XXX: If so, to what ?
371
                 */
372 231
                HTTP_Setup(req->resp, req->ws, req->vsl, SLT_RespMethod);
373 231
                VSB_destroy(&synth_body);
374 231
                req->req_step = R_STP_RESTART;
375 231
                return (REQ_FSM_MORE);
376
        }
377 11923
        assert(wrk->vpi->handling == VCL_RET_DELIVER);
378
379
        // also happens in cnt_transmit, but we need req->doclose earlier for VRB_Ignore
380 11923
        if (req->doclose == SC_NULL)
381 9949
                req->doclose = http_DoConnection(req->http, SC_REQ_CLOSE);
382 11923
        if (req->doclose == SC_NULL)
383 9885
                req->doclose = http_DoConnection(req->resp, SC_RESP_CLOSE);
384
385
        /* Discard any lingering request body before delivery */
386 11923
        (void)VRB_Ignore(req);
387
388 11923
        if (req->objcore == NULL)
389 1969
                (void) Resp_l_storage(req, stv_synth);
390
391 11923
        if (req->objcore == NULL)
392 0
                szl = -1;
393 11923
        else if (req->objcore->stobj->stevedore->allocobj != ssy_stevedore.allocobj) {
394 21
                CHECK_OBJ_NOTNULL(req->objcore, OBJCORE_MAGIC);
395 21
                body = VSB_data(synth_body);
396 21
                szl = VSB_len(synth_body);
397 21
                assert(szl >= 0);
398 63
                while (szl > 0) {
399 42
                        sz = szl;
400 42
                        if (! ObjGetSpace(wrk, req->objcore, &sz, &ptr)) {
401 0
                                szl = -1;
402 0
                                break;
403
                        }
404 42
                        if (sz > szl)
405 0
                                sz = szl;
406 42
                        szl -= sz;
407 42
                        vmemcpy(ptr, body, sz);
408 42
                        ObjExtend(wrk, req->objcore, sz, szl == 0 ? 1 : 0);
409 42
                        body += sz;
410
                }
411 21
                if (szl >= 0)
412 21
                        AZ(ObjSetU64(wrk, req->objcore, OA_LEN, VSB_len(synth_body)));
413 21
        }
414 11923
        if (req->objcore != NULL)
415 11923
                HSH_DerefBoc(wrk, req->objcore);
416 11923
        VSB_destroy(&synth_body);
417
418 11923
        if (szl < 0) {
419 0
                VSLb(req->vsl, SLT_Error, "Could not get storage");
420 0
                req->doclose = SC_OVERLOAD;
421 0
                VSLb_ts_req(req, "Resp", W_TIM_real(wrk));
422 0
                if (req->objcore != NULL)
423 0
                        (void)HSH_DerefObjCore(wrk, &req->objcore);
424 0
                http_Teardown(req->resp);
425 0
                return (REQ_FSM_DONE);
426
        }
427
428 11923
        req->req_step = R_STP_TRANSMIT;
429 11923
        return (REQ_FSM_MORE);
430 14086
}
431
432
/*--------------------------------------------------------------------
433
 * The mechanics of sending a response (from deliver or synth)
434
 */
435
436
static enum req_fsm_nxt v_matchproto_(req_state_f)
437 83261
cnt_transmit(struct worker *wrk, struct req *req)
438
{
439 83261
        enum req_fsm_nxt nxt = REQ_FSM_MORE;
440
        enum vtr_deliver_e dnxt;
441
        uint16_t status;
442
        int sendbody, head;
443
        intmax_t clval;
444
445 83261
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
446 83261
        CHECK_OBJ_NOTNULL(req, REQ_MAGIC);
447 83261
        CHECK_OBJ_NOTNULL(req->transport, TRANSPORT_MAGIC);
448 83261
        CHECK_OBJ_NOTNULL(req->objcore, OBJCORE_MAGIC);
449 83261
        AZ(req->stale_oc);
450 83261
        AZ(req->res_pipe | req->res_esi);
451 83261
        AZ(req->boc);
452 83261
        req->req_step = R_STP_FINISH;
453
454 83261
        if (req->doclose == SC_NULL)
455 79337
                req->doclose = http_DoConnection(req->http, SC_REQ_CLOSE);
456 83261
        if (req->doclose == SC_NULL)
457 79284
                req->doclose = http_DoConnection(req->resp, SC_RESP_CLOSE);
458
459
        /* Grab a ref to the bo if there is one (=streaming) */
460 83261
        req->boc = HSH_RefBoc(req->objcore);
461 83261
        if (req->boc && req->boc->state < BOS_STREAM)
462 0
                (void)ObjWaitState(req->objcore, BOS_STREAM);
463 83261
        clval = http_GetContentLength(req->resp);
464
        /* RFC 7230, 3.3.3 */
465 83261
        status = http_GetStatus(req->resp);
466 83261
        head = http_method_eq(req->http0->wkm, WKM_HEAD);
467
468 83261
        if (req->boc != NULL || (req->objcore->flags & (OC_F_FAILED)))
469 19215
                req->resp_len = clval;
470
        else
471 64046
                req->resp_len = ObjGetLen(req->wrk, req->objcore);
472
473 83261
        if (head || status < 200 || status == 204 || status == 304) {
474
                // rfc7230,l,1748,1752
475 3607
                sendbody = 0;
476 3607
        } else {
477 79654
                sendbody = 1;
478
        }
479
480 83261
        VDP_Init(req->vdc, req->wrk, req->vsl, req, NULL, &req->resp_len);
481 83261
        if (req->vdp_filter_list == NULL)
482 77180
                req->vdp_filter_list = resp_Get_Filter_List(req);
483 83261
        if (req->vdp_filter_list == NULL ||
484 83253
            VCL_StackVDP(req->vdc, req->vcl, req->vdp_filter_list, req, NULL)) {
485 1366
                VSLb(req->vsl, SLT_Error, "Failure to push processors");
486 1366
                req->doclose = SC_OVERLOAD;
487 1366
                req->acct.resp_bodybytes +=
488 1366
                        VDP_Close(req->vdc, req->objcore, req->boc);
489 1366
        } else {
490 81903
                if (status < 200 || status == 204) {
491
                        // rfc7230,l,1691,1695
492 495
                        http_Unset(req->resp, H_Content_Length);
493 81903
                } else if (status == 304) {
494
                        // rfc7230,l,1675,1677
495 714
                        http_Unset(req->resp, H_Content_Length);
496 81408
                } else if (clval >= 0 && clval == req->resp_len) {
497
                        /* Reuse C-L header */
498 80694
                } else if (head) {
499
                        /* rfc9110,l,3226,3227
500
                         * "MAY send Content-Length ... [for] HEAD"
501
                         * do not touch to support cached HEAD #4245
502
                         */
503 105
                        req->resp_len = 0;
504 105
                } else {
505 31155
                        http_Unset(req->resp, H_Content_Length);
506 31155
                        if (req->resp_len >= 0)
507 46232
                                http_PrintfHeader(req->resp,
508 23116
                                    "Content-Length: %jd", req->resp_len);
509
                }
510 81903
                if (req->resp_len == 0)
511 26544
                        sendbody = 0;
512 81903
                dnxt = req->transport->deliver(req, sendbody);
513 81903
                if (dnxt == VTR_D_DISEMBARK)
514 1512
                        nxt = REQ_FSM_DISEMBARK;
515
                else
516 80391
                        assert(dnxt == VTR_D_DONE);
517
        }
518 83269
        return (nxt);
519
}
520
521
static enum req_fsm_nxt v_matchproto_(req_state_f)
522 83249
cnt_finish(struct worker *wrk, struct req *req)
523
{
524
525 83249
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
526 83249
        CHECK_OBJ_NOTNULL(req, REQ_MAGIC);
527
528 83249
        VSLb_ts_req(req, "Resp", W_TIM_real(wrk));
529
530 83249
        if (req->doclose == SC_NULL && (req->objcore->flags & OC_F_FAILED)) {
531
                /* The object we delivered failed due to a streaming error.
532
                 * Fail the request. */
533 336
                req->doclose = SC_TX_ERROR;
534 336
        }
535
536 83249
        if (req->boc != NULL) {
537 19173
                HSH_DerefBoc(wrk, req->objcore);
538 19173
                req->boc = NULL;
539 19173
        }
540
541 83249
        (void)HSH_DerefObjCore(wrk, &req->objcore);
542 83249
        http_Teardown(req->resp);
543
544 83249
        req->vdp_filter_list = NULL;
545 83249
        req->res_pipe = 0;
546 83249
        req->res_esi = 0;
547 83249
        return (REQ_FSM_DONE);
548
}
549
550
/*--------------------------------------------------------------------
551
 * Initiated a fetch (pass/miss) which we intend to deliver
552
 */
553
554
static enum req_fsm_nxt v_matchproto_(req_state_f)
555 49300
cnt_fetch(struct worker *wrk, struct req *req)
556
{
557
558 49300
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
559 49300
        CHECK_OBJ_NOTNULL(req, REQ_MAGIC);
560 49300
        CHECK_OBJ_NOTNULL(req->objcore, OBJCORE_MAGIC);
561 49300
        AZ(req->stale_oc);
562
563 49300
        wrk->stats->s_fetch++;
564 49300
        (void)VRB_Ignore(req);
565
566 49300
        if (req->objcore->flags & OC_F_FAILED) {
567 588
                req->err_code = 503;
568 588
                req->req_step = R_STP_SYNTH;
569 588
                (void)HSH_DerefObjCore(wrk, &req->objcore);
570 588
                AZ(req->objcore);
571 588
                return (REQ_FSM_MORE);
572
        }
573
574 48712
        req->req_step = R_STP_DELIVER;
575 48712
        return (REQ_FSM_MORE);
576 49300
}
577
578
/*--------------------------------------------------------------------
579
 * Attempt to lookup objhdr from hash.  We disembark and reenter
580
 * this state if we get suspended on a busy objhdr.
581
 */
582
583
static enum req_fsm_nxt v_matchproto_(req_state_f)
584 56377
cnt_lookup(struct worker *wrk, struct req *req)
585
{
586
        struct objcore *oc, *busy;
587
        enum lookup_e lr;
588
        int waitinglist_gen;
589
590 56377
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
591 56377
        CHECK_OBJ_NOTNULL(req, REQ_MAGIC);
592 56377
        AZ(req->stale_oc);
593
594 56377
        AN(req->vcl);
595
596 56377
        VRY_Prep(req);
597 56377
        waitinglist_gen = req->waitinglist_gen;
598
599 56377
        if (req->waitinglist_gen) {
600 1287
                CHECK_OBJ_NOTNULL(req->objcore, OBJCORE_MAGIC);
601 1287
                req->waitinglist_gen = 0;
602 1287
        } else
603 55090
                AZ(req->objcore);
604
605 56377
        wrk->strangelove = 0;
606 56377
        lr = HSH_Lookup(req, &oc, &busy);
607 56377
        if (lr == HSH_BUSY) {
608
                /*
609
                 * We lost the session to a busy object, disembark the
610
                 * worker thread.   We return to STP_LOOKUP when the busy
611
                 * object has been unbusied, and still have the objhead
612
                 * around to restart the lookup with.
613
                 */
614 1284
                return (REQ_FSM_DISEMBARK);
615
        }
616 55093
        assert(wrk->strangelove >= 0);
617 55093
        if ((unsigned)wrk->strangelove >= cache_param->vary_notice)
618 2604
                VSLb(req->vsl, SLT_Notice, "vsl: High number of variants (%d)",
619 1302
                    wrk->strangelove);
620 55093
        if (waitinglist_gen)
621 1284
                VSLb_ts_req(req, "Waitinglist", W_TIM_real(wrk));
622
623 55093
        if (req->vcf != NULL) {
624 126
                (void)req->vcf->func(req, NULL, NULL, 2);
625 126
                req->vcf = NULL;
626 126
        }
627
628 55093
        if (busy == NULL) {
629 23270
                VRY_Finish(req, DISCARD);
630 23270
        } else {
631 31823
                AN(busy->flags & OC_F_BUSY);
632 31823
                VRY_Finish(req, KEEP);
633
        }
634
635 55093
        AZ(req->objcore);
636 55093
        if (lr == HSH_MISS || lr == HSH_HITMISS) {
637 29828
                AN(busy);
638 29828
                AN(busy->flags & OC_F_BUSY);
639 29828
                req->objcore = busy;
640 29828
                req->stale_oc = oc;
641 29828
                req->req_step = R_STP_MISS;
642 29828
                if (lr == HSH_HITMISS)
643 756
                        req->is_hitmiss = 1;
644 29828
                return (REQ_FSM_MORE);
645
        }
646 25265
        if (lr == HSH_HITPASS) {
647 273
                AZ(busy);
648 273
                AZ(oc);
649 273
                req->req_step = R_STP_PASS;
650 273
                req->is_hitpass = 1;
651 273
                return (REQ_FSM_MORE);
652
        }
653
654 24992
        assert(lr == HSH_HIT || lr == HSH_GRACE);
655
656 24992
        CHECK_OBJ_NOTNULL(oc, OBJCORE_MAGIC);
657 24992
        AZ(oc->flags & (OC_F_BUSY | OC_F_HFM));
658 24992
        req->objcore = oc;
659
660 24992
        VCL_hit_method(req->vcl, wrk, req, NULL, NULL);
661
662 24992
        switch (wrk->vpi->handling) {
663
        case VCL_RET_DELIVER:
664 24352
                if (busy != NULL) {
665 1848
                        AZ(oc->flags & OC_F_HFM);
666 1848
                        CHECK_OBJ_NOTNULL(busy->boc, BOC_MAGIC);
667
                        // XXX: shouldn't we go to miss?
668 1848
                        VBF_Fetch(wrk, req, busy, oc, VBF_BACKGROUND);
669 1848
                        wrk->stats->s_fetch++;
670 1848
                        wrk->stats->s_bgfetch++;
671 1848
                } else {
672 22504
                        (void)VRB_Ignore(req);// XXX: handle err
673
                }
674 24352
                wrk->stats->cache_hit++;
675 24352
                req->is_hit = 1;
676 24352
                if (lr == HSH_GRACE)
677 1911
                        wrk->stats->cache_hit_grace++;
678 24352
                req->req_step = R_STP_DELIVER;
679 24352
                return (REQ_FSM_MORE);
680
        case VCL_RET_RESTART:
681 303
                req->req_step = R_STP_RESTART;
682 303
                break;
683
        case VCL_RET_FAIL:
684 106
                req->req_step = R_STP_VCLFAIL;
685 106
                break;
686
        case VCL_RET_SYNTH:
687 189
                req->req_step = R_STP_SYNTH;
688 189
                break;
689
        case VCL_RET_PASS:
690 42
                wrk->stats->cache_hit++;
691 42
                req->is_hit = 1;
692 42
                req->req_step = R_STP_PASS;
693 42
                break;
694
        default:
695 0
                WRONG("Illegal return from vcl_hit{}");
696 0
        }
697
698 640
        Req_StashObjcore(req, &req->objcore);
699
700 640
        if (busy != NULL) {
701 147
                HSH_Withdraw(wrk, &busy);
702 147
                VRY_Clear(req);
703 147
        }
704
705 640
        return (REQ_FSM_MORE);
706 56377
}
707
708
/*--------------------------------------------------------------------
709
 * Cache miss.
710
 */
711
712
static enum req_fsm_nxt v_matchproto_(req_state_f)
713 29807
cnt_miss(struct worker *wrk, struct req *req)
714
{
715
716 29807
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
717 29807
        CHECK_OBJ_NOTNULL(req, REQ_MAGIC);
718 29807
        AN(req->vcl);
719 29807
        CHECK_OBJ_NOTNULL(req->objcore, OBJCORE_MAGIC);
720 29807
        CHECK_OBJ_ORNULL(req->stale_oc, OBJCORE_MAGIC);
721
722 29807
        VCL_miss_method(req->vcl, wrk, req, NULL, NULL);
723 29807
        switch (wrk->vpi->handling) {
724
        case VCL_RET_FETCH:
725 29484
                wrk->stats->cache_miss++;
726 29484
                VBF_Fetch(wrk, req, req->objcore, req->stale_oc, VBF_NORMAL);
727 29484
                if (req->stale_oc != NULL)
728 1491
                        Req_StashObjcore(req, &req->stale_oc);
729 29484
                req->req_step = R_STP_FETCH;
730 29484
                return (REQ_FSM_MORE);
731
        case VCL_RET_FAIL:
732 71
                req->req_step = R_STP_VCLFAIL;
733 71
                break;
734
        case VCL_RET_SYNTH:
735 105
                req->req_step = R_STP_SYNTH;
736 105
                break;
737
        case VCL_RET_RESTART:
738 84
                req->req_step = R_STP_RESTART;
739 84
                break;
740
        case VCL_RET_PASS:
741 63
                req->req_step = R_STP_PASS;
742 63
                break;
743
        default:
744 0
                WRONG("Illegal return from vcl_miss{}");
745 0
        }
746 323
        VRY_Clear(req);
747 323
        if (req->stale_oc != NULL)
748 21
                Req_StashObjcore(req, &req->stale_oc);
749 323
        HSH_Withdraw(wrk, &req->objcore);
750 323
        return (REQ_FSM_MORE);
751 29807
}
752
753
/*--------------------------------------------------------------------
754
 * Pass processing
755
 */
756
757
static enum req_fsm_nxt v_matchproto_(req_state_f)
758 19866
cnt_pass(struct worker *wrk, struct req *req)
759
{
760
761 19866
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
762 19866
        CHECK_OBJ_NOTNULL(req, REQ_MAGIC);
763 19866
        AN(req->vcl);
764 19866
        AZ(req->objcore);
765 19866
        AZ(req->stale_oc);
766
767 19866
        VCL_pass_method(req->vcl, wrk, req, NULL, NULL);
768 19866
        switch (wrk->vpi->handling) {
769
        case VCL_RET_FAIL:
770 21
                req->req_step = R_STP_VCLFAIL;
771 21
                break;
772
        case VCL_RET_SYNTH:
773 21
                req->req_step = R_STP_SYNTH;
774 21
                break;
775
        case VCL_RET_RESTART:
776 0
                req->req_step = R_STP_RESTART;
777 0
                break;
778
        case VCL_RET_FETCH:
779 19824
                wrk->stats->s_pass++;
780 19824
                req->objcore = HSH_Private(wrk);
781 19824
                CHECK_OBJ_NOTNULL(req->objcore, OBJCORE_MAGIC);
782 19824
                VBF_Fetch(wrk, req, req->objcore, NULL, VBF_PASS);
783 19824
                req->req_step = R_STP_FETCH;
784 19824
                break;
785
        default:
786 0
                WRONG("Illegal return from cnt_pass{}");
787 0
        }
788 19866
        return (REQ_FSM_MORE);
789
}
790
791
/*--------------------------------------------------------------------
792
 * Pipe mode
793
 */
794
795
static enum req_fsm_nxt v_matchproto_(req_state_f)
796 630
cnt_pipe(struct worker *wrk, struct req *req)
797
{
798
        struct busyobj *bo;
799
        enum req_fsm_nxt nxt;
800
801 630
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
802 630
        CHECK_OBJ_NOTNULL(req, REQ_MAGIC);
803 630
        AZ(req->objcore);
804 630
        AZ(req->stale_oc);
805 630
        AN(req->vcl);
806
807 630
        wrk->stats->s_pipe++;
808 630
        bo = VBO_GetBusyObj(wrk, req);
809 630
        CHECK_OBJ_NOTNULL(bo, BUSYOBJ_MAGIC);
810 630
        VSLb(bo->vsl, SLT_Begin, "bereq %ju pipe", VXID(req->vsl->wid));
811 630
        VSLb(req->vsl, SLT_Link, "bereq %ju pipe", VXID(bo->vsl->wid));
812 630
        VSLb_ts_busyobj(bo, "Start", W_TIM_real(wrk));
813 630
        THR_SetBusyobj(bo);
814 630
        bo->sp = req->sp;
815 630
        SES_Ref(bo->sp);
816
817 630
        HTTP_Setup(bo->bereq, req->ws, bo->vsl, SLT_BereqMethod);
818 630
        http_FilterReq(bo->bereq, req->http, 0);        // XXX: 0 ?
819 630
        http_PrintfHeader(bo->bereq, "X-Vinyl: %ju", VXID(req->vsl->wid));
820 630
        http_ForceHeader(bo->bereq, H_Connection, "close");
821
822 630
        if (req->want100cont) {
823 0
                http_SetHeader(bo->bereq, "Expect: 100-continue");
824 0
                req->want100cont = 0;
825 0
        }
826
827 630
        bo->wrk = wrk;
828 630
        bo->task_deadline = NAN; /* XXX: copy req->task_deadline */
829 630
        if (WS_Overflowed(req->ws))
830 21
                wrk->vpi->handling = VCL_RET_FAIL;
831
        else
832 609
                VCL_pipe_method(req->vcl, wrk, req, bo, NULL);
833
834 630
        switch (wrk->vpi->handling) {
835
        case VCL_RET_SYNTH:
836 63
                req->req_step = R_STP_SYNTH;
837 63
                nxt = REQ_FSM_MORE;
838 63
                break;
839
        case VCL_RET_PIPE:
840 525
                VSLb_ts_req(req, "Process", W_TIM_real(wrk));
841 525
                VSLb_ts_busyobj(bo, "Process", wrk->lastused);
842 525
                if (V1P_Enter() == 0) {
843 504
                        AZ(bo->req);
844 504
                        bo->req = req;
845 504
                        bo->wrk = wrk;
846
                        /* Unless cached, reqbody is not our job */
847 504
                        if (req->req_body_status != BS_CACHED)
848 483
                                req->req_body_status = BS_NONE;
849 504
                        SES_Close(req->sp, VDI_Http1Pipe(req, bo));
850 504
                        nxt = REQ_FSM_DONE;
851 504
                        V1P_Leave();
852 504
                        break;
853
                }
854 21
                wrk->stats->pipe_limited++;
855
                /* fall through */
856
        case VCL_RET_FAIL:
857 63
                req->req_step = R_STP_VCLFAIL;
858 63
                nxt = REQ_FSM_MORE;
859 63
                break;
860
        default:
861 0
                WRONG("Illegal return from vcl_pipe{}");
862 0
        }
863 630
        http_Teardown(bo->bereq);
864 630
        SES_Rel(bo->sp);
865 630
        VBO_ReleaseBusyObj(wrk, &bo);
866 630
        THR_SetBusyobj(NULL);
867 630
        return (nxt);
868
}
869
870
/*--------------------------------------------------------------------
871
 * Handle restart events
872
 */
873
874
static enum req_fsm_nxt v_matchproto_(req_state_f)
875 1563
cnt_restart(struct worker *wrk, struct req *req)
876
{
877
878 1563
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
879 1563
        CHECK_OBJ_NOTNULL(req, REQ_MAGIC);
880 1563
        AZ(req->objcore);
881 1563
        AZ(req->stale_oc);
882
883 1563
        if (++req->restarts > req->max_restarts) {
884 210
                VSLb(req->vsl, SLT_VCL_Error, "Too many restarts");
885 210
                req->err_code = 503;
886 210
                req->req_step = R_STP_SYNTH;
887 210
        } else {
888
                // XXX: ReqEnd + ReqAcct ?
889 1353
                VSLb_ts_req(req, "Restart", W_TIM_real(wrk));
890 2706
                VSL_ChgId(req->vsl, "req", "restart",
891 1353
                    VXID_Get(wrk, VSL_CLIENTMARKER));
892 1353
                VSLb_ts_req(req, "Start", req->t_prev);
893 1353
                req->err_code = 0;
894 1353
                req->req_step = R_STP_RECV;
895
        }
896 1563
        return (REQ_FSM_MORE);
897
}
898
899
/*
900
 * prepare the request for vcl_recv, either initially or after a reset
901
 * e.g. due to vcl switching
902
 *
903
 * TODO
904
 * - make restarts == 0 bit re-usable for rollback
905
 * - remove duplication with Req_Cleanup()
906
 */
907
908
static void v_matchproto_(req_state_f)
909 87583
cnt_recv_prep(struct req *req, const char *ci)
910
{
911
912 87583
        if (req->restarts == 0) {
913
                /*
914
                 * This really should be done earlier, but we want to capture
915
                 * it in the VSL log.
916
                 */
917 86230
                http_AppendHeader(req->http, H_X_Forwarded_For, ci);
918 86230
                http_AppendHeader(req->http, H_Via, http_ViaHeader());
919 86230
                http_CollectHdr(req->http, H_Cache_Control);
920
921
                /* By default we use the first backend */
922 172460
                VRT_Assign_Backend(&req->director_hint,
923 86230
                    VCL_DefaultDirector(req->vcl));
924
925 86230
                req->d_ttl = -1;
926 86230
                req->d_grace = -1;
927 86230
                req->disable_esi = 0;
928 86230
                req->hash_always_miss = 0;
929 86230
                req->hash_ignore_busy = 0;
930 86230
                req->hash_ignore_vary = 0;
931 86230
                req->client_identity = NULL;
932 86230
                req->storage = NULL;
933 86230
                req->trace = FEATURE(FEATURE_TRACE);
934 86230
        }
935
936 87583
        req->is_hit = 0;
937 87583
        req->is_hitmiss = 0;
938 87583
        req->is_hitpass = 0;
939 87583
        req->err_code = 0;
940 87583
        req->err_reason = NULL;
941
942 87583
        req->vfp_filter_list = NULL;
943 87583
}
944
945
/*--------------------------------------------------------------------
946
 * We have a complete request, set everything up and start it.
947
 * We can come here both with a request from the client and with
948
 * a interior request during ESI delivery.
949
 */
950
951
static enum req_fsm_nxt v_matchproto_(req_state_f)
952 87258
cnt_recv(struct worker *wrk, struct req *req)
953
{
954
        unsigned recv_handling;
955
        struct VSHA256Context sha256ctx;
956
        const char *ci;
957
958 87258
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
959 87258
        CHECK_OBJ_NOTNULL(req, REQ_MAGIC);
960 87258
        AN(req->vcl);
961 87258
        AZ(req->objcore);
962 87258
        AZ(req->stale_oc);
963 87258
        AZ(req->err_code);
964
965 87258
        AZ(isnan(req->t_first));
966 87258
        AZ(isnan(req->t_prev));
967 87258
        AZ(isnan(req->t_req));
968
969 87258
        ci = Req_LogStart(wrk, req);
970 87258
        http_VSL_log(req->http);
971
972 87258
        if (http_CountHdr(req->http0, H_Host) > 1) {
973 42
                VSLb(req->vsl, SLT_BogoHeader, "Multiple Host: headers");
974 42
                wrk->stats->client_req_400++;
975 42
                req->doclose = SC_RX_BAD;
976 42
                (void)req->transport->minimal_response(req, 400);
977 42
                return (REQ_FSM_DONE);
978
        }
979
980 87216
        cnt_recv_prep(req, ci);
981
982 87216
        if (req->req_body_status == BS_ERROR) {
983 0
                req->doclose = SC_OVERLOAD;
984 0
                return (REQ_FSM_DONE);
985
        }
986
987 87216
        VCL_recv_method(req->vcl, wrk, req, NULL, NULL);
988
989 87216
        if (wrk->vpi->handling == VCL_RET_FAIL) {
990 1073
                req->req_step = R_STP_VCLFAIL;
991 1073
                return (REQ_FSM_MORE);
992
        }
993
994 86143
        if (wrk->vpi->handling == VCL_RET_VCL && req->restarts == 0) {
995
                // Req_Rollback has happened in VPI_vcl_select
996 273
                assert(WS_Snapshot(req->ws) == req->ws_req);
997 273
                cnt_recv_prep(req, ci);
998 273
                VCL_recv_method(req->vcl, wrk, req, NULL, NULL);
999 273
        }
1000
1001 86143
        if (req->want100cont && !req->late100cont) {
1002 84
                req->want100cont = 0;
1003 84
                if (req->transport->minimal_response(req, 100)) {
1004 0
                        req->doclose = SC_REM_CLOSE;
1005 0
                        return (REQ_FSM_DONE);
1006
                }
1007 84
        }
1008
1009
        /* Attempts to cache req.body may fail */
1010 86143
        if (req->req_body_status == BS_ERROR) {
1011 126
                req->doclose = SC_RX_BODY;
1012 126
                (void)req->transport->minimal_response(req, 400);
1013 126
                return (REQ_FSM_DONE);
1014
        }
1015
1016 86017
        recv_handling = wrk->vpi->handling;
1017
1018
        /* We wash the A-E header here for the sake of VRY */
1019 171252
        if (cache_param->http_gzip_support &&
1020 85908
             (recv_handling != VCL_RET_PIPE) &&
1021 85235
             (recv_handling != VCL_RET_PASS)) {
1022 65784
                if (RFC2616_Req_Gzip(req->http)) {
1023 4620
                        http_ForceHeader(req->http, H_Accept_Encoding, "gzip");
1024 4620
                } else {
1025 61164
                        http_Unset(req->http, H_Accept_Encoding);
1026
                }
1027 65784
        }
1028
1029 86017
        VSHA256_Init(&sha256ctx);
1030 86017
        VCL_hash_method(req->vcl, wrk, req, NULL, &sha256ctx);
1031 86017
        if (wrk->vpi->handling == VCL_RET_FAIL)
1032 224
                recv_handling = wrk->vpi->handling;
1033
        else
1034 85793
                assert(wrk->vpi->handling == VCL_RET_LOOKUP);
1035 86017
        VSHA256_Final(req->digest, &sha256ctx);
1036
1037 86017
        switch (recv_handling) {
1038
        case VCL_RET_VCL:
1039 168
                VSLb(req->vsl, SLT_VCL_Error,
1040
                    "Illegal return(vcl): %s",
1041 84
                    req->restarts ? "Not after restarts" :
1042
                    "Only from active VCL");
1043 84
                req->err_code = 503;
1044 84
                req->req_step = R_STP_SYNTH;
1045 84
                break;
1046
        case VCL_RET_PURGE:
1047 210
                req->req_step = R_STP_PURGE;
1048 210
                break;
1049
        case VCL_RET_HASH:
1050 55090
                req->req_step = R_STP_LOOKUP;
1051 55090
                break;
1052
        case VCL_RET_PIPE:
1053 672
                if (!IS_TOPREQ(req)) {
1054 0
                        VSLb(req->vsl, SLT_VCL_Error,
1055
                            "vcl_recv{} returns pipe for ESI included object."
1056
                            "  Doing pass.");
1057 0
                        req->req_step = R_STP_PASS;
1058 672
                } else if (req->http0->protover > 11) {
1059 42
                        VSLb(req->vsl, SLT_VCL_Error,
1060
                            "vcl_recv{} returns pipe for HTTP/2 request."
1061
                            "  Doing pass.");
1062 42
                        req->req_step = R_STP_PASS;
1063 42
                } else {
1064 630
                        req->req_step = R_STP_PIPE;
1065
                }
1066 672
                break;
1067
        case VCL_RET_PASS:
1068 19441
                req->req_step = R_STP_PASS;
1069 19441
                break;
1070
        case VCL_RET_SYNTH:
1071 10117
                req->req_step = R_STP_SYNTH;
1072 10117
                break;
1073
        case VCL_RET_RESTART:
1074 189
                req->req_step = R_STP_RESTART;
1075 189
                break;
1076
        case VCL_RET_FAIL:
1077 214
                req->req_step = R_STP_VCLFAIL;
1078 214
                break;
1079
        default:
1080 0
                WRONG("Illegal return from vcl_recv{}");
1081 0
        }
1082 86017
        return (REQ_FSM_MORE);
1083 87258
}
1084
1085
/*--------------------------------------------------------------------
1086
 * Find the objhead, purge it.
1087
 *
1088
 * In VCL, a restart is necessary to get a new object
1089
 */
1090
1091
static enum req_fsm_nxt v_matchproto_(req_state_f)
1092 210
cnt_purge(struct worker *wrk, struct req *req)
1093
{
1094
        struct objcore *oc, *boc;
1095
        enum lookup_e lr;
1096
1097 210
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
1098 210
        CHECK_OBJ_NOTNULL(req, REQ_MAGIC);
1099 210
        AZ(req->objcore);
1100 210
        AZ(req->stale_oc);
1101
1102 210
        AN(req->vcl);
1103
1104 210
        VRY_Prep(req);
1105
1106 210
        AZ(req->objcore);
1107 210
        req->hash_always_miss = 1;
1108 210
        lr = HSH_Lookup(req, &oc, &boc);
1109 210
        assert (lr == HSH_MISS);
1110 210
        AZ(oc);
1111 210
        CHECK_OBJ_NOTNULL(boc, OBJCORE_MAGIC);
1112 210
        VRY_Finish(req, DISCARD);
1113
1114 210
        (void)HSH_Purge(wrk, boc->objhead, req->t_req, 0, 0, 0);
1115
1116 210
        HSH_Withdraw(wrk, &boc);
1117
1118 210
        VCL_purge_method(req->vcl, wrk, req, NULL, NULL);
1119 210
        switch (wrk->vpi->handling) {
1120
        case VCL_RET_RESTART:
1121 63
                req->req_step = R_STP_RESTART;
1122 63
                break;
1123
        case VCL_RET_FAIL:
1124 21
                req->req_step = R_STP_VCLFAIL;
1125 21
                break;
1126
        case VCL_RET_SYNTH:
1127 126
                req->req_step = R_STP_SYNTH;
1128 126
                break;
1129
        default:
1130 0
                WRONG("Illegal return from vcl_purge{}");
1131 0
        }
1132 210
        return (REQ_FSM_MORE);
1133
}
1134
1135
/*--------------------------------------------------------------------
1136
 * Central state engine dispatcher.
1137
 *
1138
 * Kick the session around until it has had enough.
1139
 *
1140
 */
1141
1142
static void v_matchproto_(req_state_f)
1143 9375
cnt_diag(struct req *req, const char *state)
1144
{
1145
1146 9375
        CHECK_OBJ_NOTNULL(req, REQ_MAGIC);
1147
1148 18750
        VSLb(req->vsl,  SLT_Debug, "vxid %ju STP_%s sp %p vcl %p",
1149 9375
            VXID(req->vsl->wid), state, req->sp, req->vcl);
1150 9375
        VSL_Flush(req->vsl, 0);
1151 9375
}
1152
1153
void
1154 90412
CNT_Embark(struct worker *wrk, struct req *req)
1155
{
1156
1157 90412
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
1158 90412
        CHECK_OBJ_NOTNULL(req, REQ_MAGIC);
1159
1160
        /* wrk can have changed for restarts */
1161 90412
        req->vfc->wrk = req->wrk = wrk;
1162 90412
        wrk->vsl = req->vsl;
1163 90412
        if (req->req_step == R_STP_TRANSPORT && req->vcl == NULL) {
1164 78308
                VCL_Refresh(&wrk->wpriv->vcl);
1165 78308
                req->vcl = wrk->wpriv->vcl;
1166 78308
                wrk->wpriv->vcl = NULL;
1167 78308
                VSLbs(req->vsl, SLT_VCL_use, TOSTRAND(VCL_Name(req->vcl)));
1168 78308
        }
1169
1170 90412
        AN(req->vcl);
1171 90412
}
1172
1173
enum req_fsm_nxt
1174 88900
CNT_Request(struct req *req)
1175
{
1176
        struct vrt_ctx ctx[1];
1177
        struct worker *wrk;
1178
        enum req_fsm_nxt nxt;
1179
1180 88900
        CHECK_OBJ_NOTNULL(req, REQ_MAGIC);
1181
1182 88900
        wrk = req->wrk;
1183 88900
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
1184
1185 88900
        CHECK_OBJ_NOTNULL(req->transport, TRANSPORT_MAGIC);
1186 88900
        AN(req->transport->deliver);
1187 88900
        AN(req->transport->minimal_response);
1188
1189
        /*
1190
         * Possible entrance states
1191
         */
1192 88900
        assert(
1193
            req->req_step == R_STP_LOOKUP ||
1194
            req->req_step == R_STP_FINISH ||
1195
            req->req_step == R_STP_TRANSPORT);
1196
1197 88900
        AN(VXID_TAG(req->vsl->wid) & VSL_CLIENTMARKER);
1198 88900
        AN(req->vcl);
1199
1200 675943
        for (nxt = REQ_FSM_MORE; nxt == REQ_FSM_MORE; ) {
1201
                /*
1202
                 * This is a good place to be paranoid about the various
1203
                 * pointers still pointing to the things we expect.
1204
                 */
1205 587043
                CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
1206 587043
                CHECK_OBJ_NOTNULL(wrk->wpriv, WORKER_PRIV_MAGIC);
1207 587043
                CHECK_OBJ_ORNULL(wrk->wpriv->nobjhead, OBJHEAD_MAGIC);
1208 587043
                CHECK_OBJ_NOTNULL(req, REQ_MAGIC);
1209 587043
                CHECK_OBJ_NOTNULL(req->doclose, STREAM_CLOSE_MAGIC);
1210
1211 587043
                AN(req->req_step);
1212 587043
                AN(req->req_step->name);
1213 587043
                AN(req->req_step->func);
1214 587043
                if (DO_DEBUG(DBG_REQ_STATE))
1215 9375
                        cnt_diag(req, req->req_step->name);
1216 587043
                nxt = req->req_step->func(wrk, req);
1217 587043
                CHECK_OBJ_ORNULL(wrk->wpriv->nobjhead, OBJHEAD_MAGIC);
1218
        }
1219 88900
        wrk->vsl = NULL;
1220 88900
        if (nxt == REQ_FSM_DONE) {
1221 85954
                INIT_OBJ(ctx, VRT_CTX_MAGIC);
1222 85954
                VCL_Req2Ctx(ctx, req);
1223 85954
                if (IS_TOPREQ(req)) {
1224 78183
                        VCL_TaskLeave(ctx, req->top->privs);
1225 78183
                        if (req->top->vcl0 != NULL)
1226 252
                                VCL_Recache(wrk, &req->top->vcl0);
1227 78183
                }
1228 85954
                VCL_TaskLeave(ctx, req->privs);
1229 85954
                assert(!IS_NO_VXID(req->vsl->wid));
1230 85954
                VRB_Free(req);
1231 85954
                VRT_Assign_Backend(&req->director_hint, NULL);
1232 85954
                req->wrk = NULL;
1233 85954
        }
1234 88900
        assert(nxt == REQ_FSM_DISEMBARK || !WS_IsReserved(req->ws));
1235 88900
        return (nxt);
1236
}