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 15525
cnt_transport(struct worker *wrk, struct req *req)
86
{
87
        const char *p;
88
89 15525
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
90 15525
        CHECK_OBJ_NOTNULL(req, REQ_MAGIC);
91 15525
        CHECK_OBJ_NOTNULL(req->http, HTTP_MAGIC);
92 15525
        CHECK_OBJ_NOTNULL(req->transport, TRANSPORT_MAGIC);
93 15525
        AN(req->req_body_status);
94
95 15525
        if (http_GetHdr(req->http, H_Expect, &p)) {
96 48
                if (!http_expect_eq(p, 100-continue)) {
97 8
                        req->doclose = SC_RX_JUNK;
98 8
                        (void)req->transport->minimal_response(req, 417);
99 8
                        wrk->stats->client_req_417++;
100 8
                        return (REQ_FSM_DONE);
101
                }
102 40
                if (req->http->protover >= 11 &&
103 40
                    req->htc->pipeline_b == NULL)       // XXX: HTTP1 vs 2 ?
104 36
                        req->want100cont = 1;
105 40
                http_Unset(req->http, H_Expect);
106 40
        }
107
108 15517
        AZ(req->err_code);
109
110 15517
        req->doclose = http_DoConnection(req->http, SC_REQ_CLOSE);
111 15517
        if (req->doclose == SC_RX_BAD) {
112 12
                wrk->stats->client_req_400++;
113 12
                (void)req->transport->minimal_response(req, 400);
114 12
                return (REQ_FSM_DONE);
115
        }
116
117 15505
        if (req->req_body_status->avail == 1) {
118 576
                AN(req->transport->req_body != NULL);
119 576
                VFP_Setup(req->vfc, wrk);
120 576
                req->vfc->resp = req->http;             // XXX
121 576
                req->transport->req_body(req);
122 576
        }
123
124 15505
        req->ws_req = WS_Snapshot(req->ws);
125 15505
        HTTP_Clone(req->http0, req->http);      // For ESI & restart
126 15505
        req->req_step = R_STP_RECV;
127 15505
        return (REQ_FSM_MORE);
128 15525
}
129
130
/*--------------------------------------------------------------------
131
 * Deliver an object to client
132
 */
133
134
int
135 13410
Resp_Setup_Deliver(struct req *req)
136
{
137
        struct http *h;
138
        struct objcore *oc;
139
        const void *hdrs;
140
141 13410
        CHECK_OBJ_NOTNULL(req, REQ_MAGIC);
142 13410
        oc = req->objcore;
143 13410
        CHECK_OBJ_NOTNULL(oc, OBJCORE_MAGIC);
144
145 13410
        h = req->resp;
146
147 13410
        HTTP_Setup(h, req->ws, req->vsl, SLT_RespMethod);
148
149 13410
        hdrs = ObjGetAttr(req->wrk, oc, OA_HEADERS, NULL);
150 13410
        if (hdrs == NULL || HTTP_Decode(h, hdrs))
151 7
                return (-1);
152
153 13405
        http_ForceField(h, HTTP_HDR_PROTO, "HTTP/1.1");
154
155 13405
        if (req->is_hit)
156 9272
                http_PrintfHeader(h, "X-Vinyl: %ju %ju", VXID(req->vsl->wid),
157 4636
                    VXID(ObjGetXID(req->wrk, oc)));
158
        else
159 8769
                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 26810
        http_PrintfHeader(h, "Age: %.0f",
169 13405
            floor(fmax(0., req->t_prev - oc->t_origin)));
170
171 13405
        http_AppendHeader(h, H_Via, http_ViaHeader());
172
173 14505
        if (cache_param->http_gzip_support &&
174 13383
            ObjCheckFlag(req->wrk, oc, OF_GZIPED) &&
175 1100
            !RFC2616_Req_Gzip(req->http))
176 400
                RFC2616_Weaken_Etag(h);
177 13405
        return (0);
178 13412
}
179
180
void
181 2352
Resp_Setup_Synth(struct req *req)
182
{
183
        struct http *h;
184
185 2352
        CHECK_OBJ_NOTNULL(req, REQ_MAGIC);
186
187 2352
        h = req->resp;
188
189 2352
        HTTP_Setup(h, req->ws, req->vsl, SLT_RespMethod);
190
191 2352
        AZ(req->objcore);
192 2352
        http_PutResponse(h, "HTTP/1.1", req->err_code, req->err_reason);
193
194 2352
        http_TimeHeader(h, "Date: ", W_TIM_real(req->wrk));
195 2352
        http_SetHeader(h, "Server: Vinyl-Cache");
196 2352
        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 2352
        if (req->want100cont)
204 12
                http_SetHeader(h, "Connection: close");
205 2352
}
206
207
static enum req_fsm_nxt v_matchproto_(req_state_f)
208 13372
cnt_deliver(struct worker *wrk, struct req *req)
209
{
210
        unsigned status;
211
212 13372
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
213 13372
        CHECK_OBJ_NOTNULL(req, REQ_MAGIC);
214 13372
        CHECK_OBJ_NOTNULL(req->objcore, OBJCORE_MAGIC);
215 13372
        CHECK_OBJ_NOTNULL(req->objcore->objhead, OBJHEAD_MAGIC);
216 13372
        AZ(req->stale_oc);
217 13372
        AN(req->vcl);
218
219 13372
        assert(req->objcore->refcnt > 0);
220
221 13372
        ObjTouch(req->wrk, req->objcore, req->t_prev);
222
223 13372
        if (Resp_Setup_Deliver(req)) {
224 8
                (void)HSH_DerefObjCore(wrk, &req->objcore);
225 8
                req->err_code = 500;
226 8
                req->req_step = R_STP_SYNTH;
227 8
                return (REQ_FSM_MORE);
228
        }
229
230 13364
        status = http_GetStatus(req->resp);
231 13364
        if (cache_param->http_range_support && status == 200 &&
232 11855
            !(req->objcore->flags & OC_F_PRIVATE))
233 9528
                http_ForceHeader(req->resp, H_Accept_Ranges, "bytes");
234
235 13364
        req->esi_include_onerror = FEATURE(FEATURE_ESI_INCLUDE_ONERROR);
236
237 13364
        req->t_resp = W_TIM_real(wrk);
238 13364
        VCL_deliver_method(req->vcl, wrk, req, NULL, NULL);
239
240 13364
        assert(req->restarts <= req->max_restarts);
241
242 13364
        if (wrk->vpi->handling != VCL_RET_DELIVER) {
243 316
                HSH_Cancel(wrk, req->objcore, NULL);
244 316
                Req_StashObjcore(req, &req->objcore);
245 316
                http_Teardown(req->resp);
246
247 316
                switch (wrk->vpi->handling) {
248
                case VCL_RET_RESTART:
249 132
                        req->req_step = R_STP_RESTART;
250 132
                        break;
251
                case VCL_RET_FAIL:
252 152
                        req->req_step = R_STP_VCLFAIL;
253 152
                        break;
254
                case VCL_RET_SYNTH:
255 32
                        req->req_step = R_STP_SYNTH;
256 32
                        break;
257
                default:
258 0
                        WRONG("Illegal return from vcl_deliver{}");
259 0
                }
260
261 316
                return (REQ_FSM_MORE);
262
        }
263
264 13048
        VSLb_ts_req(req, "Process", W_TIM_real(wrk));
265
266 13048
        assert(wrk->vpi->handling == VCL_RET_DELIVER);
267
268 13048
        if (IS_TOPREQ(req) && RFC2616_Do_Cond(req))
269 120
                http_PutResponse(req->resp, "HTTP/1.1", 304, NULL);
270
271 13048
        req->req_step = R_STP_TRANSMIT;
272 13048
        return (REQ_FSM_MORE);
273 13372
}
274
275
/*--------------------------------------------------------------------
276
 * VCL failed, die horribly
277
 */
278
279
static enum req_fsm_nxt v_matchproto_(req_state_f)
280 444
cnt_vclfail(struct worker *wrk, struct req *req)
281
{
282
        struct vrt_ctx ctx[1];
283
284 444
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
285 444
        CHECK_OBJ_NOTNULL(req, REQ_MAGIC);
286
287 444
        AZ(req->objcore);
288 444
        AZ(req->stale_oc);
289
290 444
        INIT_OBJ(ctx, VRT_CTX_MAGIC);
291 444
        VCL_Req2Ctx(ctx, req);
292
293 444
        Req_Rollback(ctx);
294
295 444
        if (req->req_reset) {
296 108
                req->err_code = 408;
297 108
                req->err_reason = "Client disconnected";
298 108
        } else {
299 336
                req->err_code = 503;
300 336
                req->err_reason = "VCL failed";
301
        }
302 444
        req->req_step = R_STP_SYNTH;
303 444
        req->doclose = SC_VCL_FAILURE;
304 444
        req->vdp_filter_list = NULL;
305 444
        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 2344
cnt_synth(struct worker *wrk, struct req *req)
314
{
315
        struct vsb *synth_body;
316 2344
        ssize_t sz, szl = 0;
317
        uint16_t status;
318
        uint8_t *ptr;
319
        const char *body;
320
321 2344
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
322 2344
        CHECK_OBJ_NOTNULL(req, REQ_MAGIC);
323
324 2344
        AZ(req->objcore);
325 2344
        AZ(req->stale_oc);
326
327 2344
        wrk->stats->s_synth++;
328
329 2344
        if (req->err_code < 100)
330 0
                req->err_code = 501;
331
332 2344
        Resp_Setup_Synth(req);
333
334 2344
        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 2344
        synth_body = VSB_new_auto();
340 2344
        AN(synth_body);
341
342 2344
        req->t_resp = W_TIM_real(wrk);
343 2344
        VCL_synth_method(req->vcl, wrk, req, NULL, synth_body);
344
345 2344
        AZ(VSB_finish(synth_body));
346
347 2344
        VSLb_ts_req(req, "Process", W_TIM_real(wrk));
348
349 2344
        while (wrk->vpi->handling == VCL_RET_FAIL) {
350 360
                if (req->esi_level > 0) {
351 4
                        wrk->vpi->handling = VCL_RET_DELIVER;
352 4
                        break;
353
                }
354 356
                VSB_destroy(&synth_body);
355 356
                (void)VRB_Ignore(req);
356 356
                status = req->req_reset ? 408 : 500;
357 356
                (void)req->transport->minimal_response(req, status);
358 356
                req->doclose = SC_VCL_FAILURE; // XXX: Not necessary any more ?
359 356
                VSLb_ts_req(req, "Resp", W_TIM_real(wrk));
360 356
                http_Teardown(req->resp);
361 356
                return (REQ_FSM_DONE);
362
        }
363
364 1988
        if (wrk->vpi->handling == VCL_RET_RESTART && req->restarts > req->max_restarts)
365 4
                wrk->vpi->handling = VCL_RET_DELIVER;
366
367 1988
        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 44
                HTTP_Setup(req->resp, req->ws, req->vsl, SLT_RespMethod);
373 44
                VSB_destroy(&synth_body);
374 44
                req->req_step = R_STP_RESTART;
375 44
                return (REQ_FSM_MORE);
376
        }
377 1944
        assert(wrk->vpi->handling == VCL_RET_DELIVER);
378
379
        // also happens in cnt_transmit, but we need req->doclose earlier for VRB_Ignore
380 1944
        if (req->doclose == SC_NULL)
381 1592
                req->doclose = http_DoConnection(req->http, SC_REQ_CLOSE);
382 1944
        if (req->doclose == SC_NULL)
383 1580
                req->doclose = http_DoConnection(req->resp, SC_RESP_CLOSE);
384
385
        /* Discard any lingering request body before delivery */
386 1944
        (void)VRB_Ignore(req);
387
388 1944
        if (req->objcore == NULL)
389 120
                (void) Resp_l_storage(req, stv_synth);
390
391 1944
        if (req->objcore == NULL)
392 0
                szl = -1;
393 1944
        else if (req->objcore->stobj->stevedore->allocobj != ssy_stevedore.allocobj) {
394 4
                CHECK_OBJ_NOTNULL(req->objcore, OBJCORE_MAGIC);
395 4
                body = VSB_data(synth_body);
396 4
                szl = VSB_len(synth_body);
397 4
                assert(szl >= 0);
398 12
                while (szl > 0) {
399 8
                        sz = szl;
400 8
                        if (! ObjGetSpace(wrk, req->objcore, &sz, &ptr)) {
401 0
                                szl = -1;
402 0
                                break;
403
                        }
404 8
                        if (sz > szl)
405 0
                                sz = szl;
406 8
                        szl -= sz;
407 8
                        vmemcpy(ptr, body, sz);
408 8
                        ObjExtend(wrk, req->objcore, sz, szl == 0 ? 1 : 0);
409 8
                        body += sz;
410
                }
411 4
                if (szl >= 0)
412 4
                        AZ(ObjSetU64(wrk, req->objcore, OA_LEN, VSB_len(synth_body)));
413 4
        }
414 1944
        if (req->objcore != NULL)
415 1944
                HSH_DerefBoc(wrk, req->objcore);
416 1944
        VSB_destroy(&synth_body);
417
418 1944
        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 1944
        req->req_step = R_STP_TRANSMIT;
429 1944
        return (REQ_FSM_MORE);
430 2344
}
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 14988
cnt_transmit(struct worker *wrk, struct req *req)
438
{
439 14988
        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 14988
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
446 14988
        CHECK_OBJ_NOTNULL(req, REQ_MAGIC);
447 14988
        CHECK_OBJ_NOTNULL(req->transport, TRANSPORT_MAGIC);
448 14988
        CHECK_OBJ_NOTNULL(req->objcore, OBJCORE_MAGIC);
449 14988
        AZ(req->stale_oc);
450 14988
        AZ(req->res_pipe | req->res_esi);
451 14988
        AZ(req->boc);
452 14988
        req->req_step = R_STP_FINISH;
453
454 14988
        if (req->doclose == SC_NULL)
455 14268
                req->doclose = http_DoConnection(req->http, SC_REQ_CLOSE);
456 14988
        if (req->doclose == SC_NULL)
457 14257
                req->doclose = http_DoConnection(req->resp, SC_RESP_CLOSE);
458
459
        /* Grab a ref to the bo if there is one (=streaming) */
460 14988
        req->boc = HSH_RefBoc(req->objcore);
461 14988
        if (req->boc && req->boc->state < BOS_STREAM)
462 0
                (void)ObjWaitState(req->objcore, BOS_STREAM);
463 14988
        clval = http_GetContentLength(req->resp);
464
        /* RFC 7230, 3.3.3 */
465 14988
        status = http_GetStatus(req->resp);
466 14988
        head = http_method_eq(req->http0->wkm, WKM_HEAD);
467
468 14988
        if (req->boc != NULL || (req->objcore->flags & (OC_F_FAILED)))
469 3640
                req->resp_len = clval;
470
        else
471 11348
                req->resp_len = ObjGetLen(req->wrk, req->objcore);
472
473 14988
        if (head || status < 200 || status == 204 || status == 304) {
474
                // rfc7230,l,1748,1752
475 684
                sendbody = 0;
476 684
        } else {
477 14304
                sendbody = 1;
478
        }
479
480 14988
        VDP_Init(req->vdc, req->wrk, req->vsl, req, NULL, &req->resp_len);
481 14988
        if (req->vdp_filter_list == NULL)
482 13831
                req->vdp_filter_list = resp_Get_Filter_List(req);
483 14988
        if (req->vdp_filter_list == NULL ||
484 14991
            VCL_StackVDP(req->vdc, req->vcl, req->vdp_filter_list, req, NULL)) {
485 263
                VSLb(req->vsl, SLT_Error, "Failure to push processors");
486 263
                req->doclose = SC_OVERLOAD;
487 263
                req->acct.resp_bodybytes +=
488 263
                        VDP_Close(req->vdc, req->objcore, req->boc);
489 263
        } else {
490 14731
                if (status < 200 || status == 204) {
491
                        // rfc7230,l,1691,1695
492 92
                        http_Unset(req->resp, H_Content_Length);
493 14731
                } else if (status == 304) {
494
                        // rfc7230,l,1675,1677
495 136
                        http_Unset(req->resp, H_Content_Length);
496 14639
                } else if (clval >= 0 && clval == req->resp_len) {
497
                        /* Reuse C-L header */
498 14503
                } 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 20
                        req->resp_len = 0;
504 20
                } else {
505 5591
                        http_Unset(req->resp, H_Content_Length);
506 5591
                        if (req->resp_len >= 0)
507 8176
                                http_PrintfHeader(req->resp,
508 4088
                                    "Content-Length: %jd", req->resp_len);
509
                }
510 14731
                if (req->resp_len == 0)
511 4252
                        sendbody = 0;
512 14731
                dnxt = req->transport->deliver(req, sendbody);
513 14731
                if (dnxt == VTR_D_DISEMBARK)
514 287
                        nxt = REQ_FSM_DISEMBARK;
515
                else
516 14444
                        assert(dnxt == VTR_D_DONE);
517
        }
518 14994
        return (nxt);
519
}
520
521
static enum req_fsm_nxt v_matchproto_(req_state_f)
522 14988
cnt_finish(struct worker *wrk, struct req *req)
523
{
524
525 14988
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
526 14988
        CHECK_OBJ_NOTNULL(req, REQ_MAGIC);
527
528 14988
        VSLb_ts_req(req, "Resp", W_TIM_real(wrk));
529
530 14988
        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 64
                req->doclose = SC_TX_ERROR;
534 64
        }
535
536 14988
        if (req->boc != NULL) {
537 3634
                HSH_DerefBoc(wrk, req->objcore);
538 3634
                req->boc = NULL;
539 3634
        }
540
541 14988
        (void)HSH_DerefObjCore(wrk, &req->objcore);
542 14988
        http_Teardown(req->resp);
543
544 14988
        req->vdp_filter_list = NULL;
545 14988
        req->res_pipe = 0;
546 14988
        req->res_esi = 0;
547 14988
        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 8853
cnt_fetch(struct worker *wrk, struct req *req)
556
{
557
558 8853
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
559 8853
        CHECK_OBJ_NOTNULL(req, REQ_MAGIC);
560 8853
        CHECK_OBJ_NOTNULL(req->objcore, OBJCORE_MAGIC);
561 8853
        AZ(req->stale_oc);
562
563 8853
        wrk->stats->s_fetch++;
564 8853
        (void)VRB_Ignore(req);
565
566 8853
        if (req->objcore->flags & OC_F_FAILED) {
567 108
                req->err_code = 503;
568 108
                req->req_step = R_STP_SYNTH;
569 108
                (void)HSH_DerefObjCore(wrk, &req->objcore);
570 108
                AZ(req->objcore);
571 108
                return (REQ_FSM_MORE);
572
        }
573
574 8745
        req->req_step = R_STP_DELIVER;
575 8745
        return (REQ_FSM_MORE);
576 8853
}
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 10699
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 10699
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
591 10699
        CHECK_OBJ_NOTNULL(req, REQ_MAGIC);
592 10699
        AZ(req->stale_oc);
593
594 10699
        AN(req->vcl);
595
596 10699
        VRY_Prep(req);
597 10699
        waitinglist_gen = req->waitinglist_gen;
598
599 10699
        if (req->waitinglist_gen) {
600 245
                CHECK_OBJ_NOTNULL(req->objcore, OBJCORE_MAGIC);
601 245
                req->waitinglist_gen = 0;
602 245
        } else
603 10454
                AZ(req->objcore);
604
605 10699
        wrk->strangelove = 0;
606 10699
        lr = HSH_Lookup(req, &oc, &busy);
607 10699
        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 245
                return (REQ_FSM_DISEMBARK);
615
        }
616 10454
        assert(wrk->strangelove >= 0);
617 10454
        if ((unsigned)wrk->strangelove >= cache_param->vary_notice)
618 496
                VSLb(req->vsl, SLT_Notice, "vsl: High number of variants (%d)",
619 248
                    wrk->strangelove);
620 10454
        if (waitinglist_gen)
621 245
                VSLb_ts_req(req, "Waitinglist", W_TIM_real(wrk));
622
623 10454
        if (req->vcf != NULL) {
624 24
                (void)req->vcf->func(req, NULL, NULL, 2);
625 24
                req->vcf = NULL;
626 24
        }
627
628 10454
        if (busy == NULL) {
629 4425
                VRY_Finish(req, DISCARD);
630 4425
        } else {
631 6029
                AN(busy->flags & OC_F_BUSY);
632 6029
                VRY_Finish(req, KEEP);
633
        }
634
635 10454
        AZ(req->objcore);
636 10454
        if (lr == HSH_MISS || lr == HSH_HITMISS) {
637 5649
                AN(busy);
638 5649
                AN(busy->flags & OC_F_BUSY);
639 5649
                req->objcore = busy;
640 5649
                req->stale_oc = oc;
641 5649
                req->req_step = R_STP_MISS;
642 5649
                if (lr == HSH_HITMISS)
643 144
                        req->is_hitmiss = 1;
644 5649
                return (REQ_FSM_MORE);
645
        }
646 4805
        if (lr == HSH_HITPASS) {
647 52
                AZ(busy);
648 52
                AZ(oc);
649 52
                req->req_step = R_STP_PASS;
650 52
                req->is_hitpass = 1;
651 52
                return (REQ_FSM_MORE);
652
        }
653
654 4753
        assert(lr == HSH_HIT || lr == HSH_GRACE);
655
656 4753
        CHECK_OBJ_NOTNULL(oc, OBJCORE_MAGIC);
657 4753
        AZ(oc->flags & (OC_F_BUSY | OC_F_HFM));
658 4753
        req->objcore = oc;
659
660 4753
        VCL_hit_method(req->vcl, wrk, req, NULL, NULL);
661
662 4753
        switch (wrk->vpi->handling) {
663
        case VCL_RET_DELIVER:
664 4632
                if (busy != NULL) {
665 352
                        AZ(oc->flags & OC_F_HFM);
666 352
                        CHECK_OBJ_NOTNULL(busy->boc, BOC_MAGIC);
667
                        // XXX: shouldn't we go to miss?
668 352
                        VBF_Fetch(wrk, req, busy, oc, VBF_BACKGROUND);
669 352
                        wrk->stats->s_fetch++;
670 352
                        wrk->stats->s_bgfetch++;
671 352
                } else {
672 4280
                        (void)VRB_Ignore(req);// XXX: handle err
673
                }
674 4632
                wrk->stats->cache_hit++;
675 4632
                req->is_hit = 1;
676 4632
                if (lr == HSH_GRACE)
677 364
                        wrk->stats->cache_hit_grace++;
678 4632
                req->req_step = R_STP_DELIVER;
679 4632
                return (REQ_FSM_MORE);
680
        case VCL_RET_RESTART:
681 57
                req->req_step = R_STP_RESTART;
682 57
                break;
683
        case VCL_RET_FAIL:
684 20
                req->req_step = R_STP_VCLFAIL;
685 20
                break;
686
        case VCL_RET_SYNTH:
687 36
                req->req_step = R_STP_SYNTH;
688 36
                break;
689
        case VCL_RET_PASS:
690 8
                wrk->stats->cache_hit++;
691 8
                req->is_hit = 1;
692 8
                req->req_step = R_STP_PASS;
693 8
                break;
694
        default:
695 0
                WRONG("Illegal return from vcl_hit{}");
696 0
        }
697
698 121
        Req_StashObjcore(req, &req->objcore);
699
700 121
        if (busy != NULL) {
701 28
                HSH_Withdraw(wrk, &busy);
702 28
                VRY_Clear(req);
703 28
        }
704
705 121
        return (REQ_FSM_MORE);
706 10699
}
707
708
/*--------------------------------------------------------------------
709
 * Cache miss.
710
 */
711
712
static enum req_fsm_nxt v_matchproto_(req_state_f)
713 5645
cnt_miss(struct worker *wrk, struct req *req)
714
{
715
716 5645
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
717 5645
        CHECK_OBJ_NOTNULL(req, REQ_MAGIC);
718 5645
        AN(req->vcl);
719 5645
        CHECK_OBJ_NOTNULL(req->objcore, OBJCORE_MAGIC);
720 5645
        CHECK_OBJ_ORNULL(req->stale_oc, OBJCORE_MAGIC);
721
722 5645
        VCL_miss_method(req->vcl, wrk, req, NULL, NULL);
723 5645
        switch (wrk->vpi->handling) {
724
        case VCL_RET_FETCH:
725 5585
                wrk->stats->cache_miss++;
726 5585
                VBF_Fetch(wrk, req, req->objcore, req->stale_oc, VBF_NORMAL);
727 5585
                if (req->stale_oc != NULL)
728 284
                        Req_StashObjcore(req, &req->stale_oc);
729 5585
                req->req_step = R_STP_FETCH;
730 5585
                return (REQ_FSM_MORE);
731
        case VCL_RET_FAIL:
732 12
                req->req_step = R_STP_VCLFAIL;
733 12
                break;
734
        case VCL_RET_SYNTH:
735 20
                req->req_step = R_STP_SYNTH;
736 20
                break;
737
        case VCL_RET_RESTART:
738 16
                req->req_step = R_STP_RESTART;
739 16
                break;
740
        case VCL_RET_PASS:
741 12
                req->req_step = R_STP_PASS;
742 12
                break;
743
        default:
744 0
                WRONG("Illegal return from vcl_miss{}");
745 0
        }
746 60
        VRY_Clear(req);
747 60
        if (req->stale_oc != NULL)
748 4
                Req_StashObjcore(req, &req->stale_oc);
749 60
        HSH_Withdraw(wrk, &req->objcore);
750 60
        return (REQ_FSM_MORE);
751 5645
}
752
753
/*--------------------------------------------------------------------
754
 * Pass processing
755
 */
756
757
static enum req_fsm_nxt v_matchproto_(req_state_f)
758 3276
cnt_pass(struct worker *wrk, struct req *req)
759
{
760
761 3276
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
762 3276
        CHECK_OBJ_NOTNULL(req, REQ_MAGIC);
763 3276
        AN(req->vcl);
764 3276
        AZ(req->objcore);
765 3276
        AZ(req->stale_oc);
766
767 3276
        VCL_pass_method(req->vcl, wrk, req, NULL, NULL);
768 3276
        switch (wrk->vpi->handling) {
769
        case VCL_RET_FAIL:
770 4
                req->req_step = R_STP_VCLFAIL;
771 4
                break;
772
        case VCL_RET_SYNTH:
773 4
                req->req_step = R_STP_SYNTH;
774 4
                break;
775
        case VCL_RET_RESTART:
776 0
                req->req_step = R_STP_RESTART;
777 0
                break;
778
        case VCL_RET_FETCH:
779 3268
                wrk->stats->s_pass++;
780 3268
                req->objcore = HSH_Private(wrk);
781 3268
                CHECK_OBJ_NOTNULL(req->objcore, OBJCORE_MAGIC);
782 3268
                VBF_Fetch(wrk, req, req->objcore, NULL, VBF_PASS);
783 3268
                req->req_step = R_STP_FETCH;
784 3268
                break;
785
        default:
786 0
                WRONG("Illegal return from cnt_pass{}");
787 0
        }
788 3276
        return (REQ_FSM_MORE);
789
}
790
791
/*--------------------------------------------------------------------
792
 * Pipe mode
793
 */
794
795
static enum req_fsm_nxt v_matchproto_(req_state_f)
796 120
cnt_pipe(struct worker *wrk, struct req *req)
797
{
798
        struct busyobj *bo;
799
        enum req_fsm_nxt nxt;
800
801 120
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
802 120
        CHECK_OBJ_NOTNULL(req, REQ_MAGIC);
803 120
        AZ(req->objcore);
804 120
        AZ(req->stale_oc);
805 120
        AN(req->vcl);
806
807 120
        wrk->stats->s_pipe++;
808 120
        bo = VBO_GetBusyObj(wrk, req);
809 120
        CHECK_OBJ_NOTNULL(bo, BUSYOBJ_MAGIC);
810 120
        VSLb(bo->vsl, SLT_Begin, "bereq %ju pipe", VXID(req->vsl->wid));
811 120
        VSLb(req->vsl, SLT_Link, "bereq %ju pipe", VXID(bo->vsl->wid));
812 120
        VSLb_ts_busyobj(bo, "Start", W_TIM_real(wrk));
813 120
        THR_SetBusyobj(bo);
814 120
        bo->sp = req->sp;
815 120
        SES_Ref(bo->sp);
816
817 120
        HTTP_Setup(bo->bereq, req->ws, bo->vsl, SLT_BereqMethod);
818 120
        http_FilterReq(bo->bereq, req->http, 0);        // XXX: 0 ?
819 120
        http_PrintfHeader(bo->bereq, "X-Vinyl: %ju", VXID(req->vsl->wid));
820 120
        http_ForceHeader(bo->bereq, H_Connection, "close");
821
822 120
        if (req->want100cont) {
823 0
                http_SetHeader(bo->bereq, "Expect: 100-continue");
824 0
                req->want100cont = 0;
825 0
        }
826
827 120
        bo->wrk = wrk;
828 120
        bo->task_deadline = NAN; /* XXX: copy req->task_deadline */
829 120
        if (WS_Overflowed(req->ws))
830 4
                wrk->vpi->handling = VCL_RET_FAIL;
831
        else
832 116
                VCL_pipe_method(req->vcl, wrk, req, bo, NULL);
833
834 120
        switch (wrk->vpi->handling) {
835
        case VCL_RET_SYNTH:
836 12
                req->req_step = R_STP_SYNTH;
837 12
                nxt = REQ_FSM_MORE;
838 12
                break;
839
        case VCL_RET_PIPE:
840 100
                VSLb_ts_req(req, "Process", W_TIM_real(wrk));
841 100
                VSLb_ts_busyobj(bo, "Process", wrk->lastused);
842 100
                if (V1P_Enter() == 0) {
843 96
                        AZ(bo->req);
844 96
                        bo->req = req;
845 96
                        bo->wrk = wrk;
846
                        /* Unless cached, reqbody is not our job */
847 96
                        if (req->req_body_status != BS_CACHED)
848 92
                                req->req_body_status = BS_NONE;
849 96
                        SES_Close(req->sp, VDI_Http1Pipe(req, bo));
850 96
                        nxt = REQ_FSM_DONE;
851 96
                        V1P_Leave();
852 96
                        break;
853
                }
854 4
                wrk->stats->pipe_limited++;
855
                /* fall through */
856
        case VCL_RET_FAIL:
857 12
                req->req_step = R_STP_VCLFAIL;
858 12
                nxt = REQ_FSM_MORE;
859 12
                break;
860
        default:
861 0
                WRONG("Illegal return from vcl_pipe{}");
862 0
        }
863 120
        http_Teardown(bo->bereq);
864 120
        SES_Rel(bo->sp);
865 120
        VBO_ReleaseBusyObj(wrk, &bo);
866 120
        THR_SetBusyobj(NULL);
867 120
        return (nxt);
868
}
869
870
/*--------------------------------------------------------------------
871
 * Handle restart events
872
 */
873
874
static enum req_fsm_nxt v_matchproto_(req_state_f)
875 297
cnt_restart(struct worker *wrk, struct req *req)
876
{
877
878 297
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
879 297
        CHECK_OBJ_NOTNULL(req, REQ_MAGIC);
880 297
        AZ(req->objcore);
881 297
        AZ(req->stale_oc);
882
883 297
        if (++req->restarts > req->max_restarts) {
884 40
                VSLb(req->vsl, SLT_VCL_Error, "Too many restarts");
885 40
                req->err_code = 503;
886 40
                req->req_step = R_STP_SYNTH;
887 40
        } else {
888
                // XXX: ReqEnd + ReqAcct ?
889 257
                VSLb_ts_req(req, "Restart", W_TIM_real(wrk));
890 514
                VSL_ChgId(req->vsl, "req", "restart",
891 257
                    VXID_Get(wrk, VSL_CLIENTMARKER));
892 257
                VSLb_ts_req(req, "Start", req->t_prev);
893 257
                req->err_code = 0;
894 257
                req->req_step = R_STP_RECV;
895
        }
896 297
        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 15802
cnt_recv_prep(struct req *req, const char *ci)
910
{
911
912 15802
        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 15545
                http_AppendHeader(req->http, H_X_Forwarded_For, ci);
918 15545
                http_AppendHeader(req->http, H_Via, http_ViaHeader());
919 15545
                http_CollectHdr(req->http, H_Cache_Control);
920
921
                /* By default we use the first backend */
922 31090
                VRT_Assign_Backend(&req->director_hint,
923 15545
                    VCL_DefaultDirector(req->vcl));
924
925 15545
                req->d_ttl = -1;
926 15545
                req->d_grace = -1;
927 15545
                req->disable_esi = 0;
928 15545
                req->hash_always_miss = 0;
929 15545
                req->hash_ignore_busy = 0;
930 15545
                req->hash_ignore_vary = 0;
931 15545
                req->client_identity = NULL;
932 15545
                req->storage = NULL;
933 15545
                req->trace = FEATURE(FEATURE_TRACE);
934 15545
        }
935
936 15802
        req->is_hit = 0;
937 15802
        req->is_hitmiss = 0;
938 15802
        req->is_hitpass = 0;
939 15802
        req->err_code = 0;
940 15802
        req->err_reason = NULL;
941
942 15802
        req->vfp_filter_list = NULL;
943 15802
}
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 15745
cnt_recv(struct worker *wrk, struct req *req)
953
{
954
        unsigned recv_handling;
955
        struct VSHA256Context sha256ctx;
956
        const char *ci;
957
958 15745
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
959 15745
        CHECK_OBJ_NOTNULL(req, REQ_MAGIC);
960 15745
        AN(req->vcl);
961 15745
        AZ(req->objcore);
962 15745
        AZ(req->stale_oc);
963 15745
        AZ(req->err_code);
964
965 15745
        AZ(isnan(req->t_first));
966 15745
        AZ(isnan(req->t_prev));
967 15745
        AZ(isnan(req->t_req));
968
969 15745
        ci = Req_LogStart(wrk, req);
970 15745
        http_VSL_log(req->http);
971
972 15745
        if (http_CountHdr(req->http0, H_Host) > 1) {
973 8
                VSLb(req->vsl, SLT_BogoHeader, "Multiple Host: headers");
974 8
                wrk->stats->client_req_400++;
975 8
                req->doclose = SC_RX_BAD;
976 8
                (void)req->transport->minimal_response(req, 400);
977 8
                return (REQ_FSM_DONE);
978
        }
979
980 15737
        if (http_CountHdr(req->http0, H_Content_Length) > 1) {
981 4
                VSLb(req->vsl, SLT_BogoHeader, "Multiple Content-Length: headers");
982 4
                wrk->stats->client_req_400++;
983 4
                req->doclose = SC_RX_BAD;
984 4
                (void)req->transport->minimal_response(req, 400);
985 4
                return (REQ_FSM_DONE);
986
        }
987
988 15733
        cnt_recv_prep(req, ci);
989
990 15733
        if (req->req_body_status == BS_ERROR) {
991 0
                req->doclose = SC_OVERLOAD;
992 0
                return (REQ_FSM_DONE);
993
        }
994
995 15733
        VCL_recv_method(req->vcl, wrk, req, NULL, NULL);
996
997 15733
        if (wrk->vpi->handling == VCL_RET_FAIL) {
998 199
                req->req_step = R_STP_VCLFAIL;
999 199
                return (REQ_FSM_MORE);
1000
        }
1001
1002 15534
        if (wrk->vpi->handling == VCL_RET_VCL && req->restarts == 0) {
1003
                // Req_Rollback has happened in VPI_vcl_select
1004 52
                assert(WS_Snapshot(req->ws) == req->ws_req);
1005 52
                cnt_recv_prep(req, ci);
1006 52
                VCL_recv_method(req->vcl, wrk, req, NULL, NULL);
1007 52
        }
1008
1009 15534
        if (req->want100cont && !req->late100cont) {
1010 16
                req->want100cont = 0;
1011 16
                if (req->transport->minimal_response(req, 100)) {
1012 0
                        req->doclose = SC_REM_CLOSE;
1013 0
                        return (REQ_FSM_DONE);
1014
                }
1015 16
        }
1016
1017
        /* Attempts to cache req.body may fail */
1018 15534
        if (req->req_body_status == BS_ERROR) {
1019 24
                req->doclose = SC_RX_BODY;
1020 24
                (void)req->transport->minimal_response(req, 400);
1021 24
                return (REQ_FSM_DONE);
1022
        }
1023
1024 15510
        recv_handling = wrk->vpi->handling;
1025
1026
        /* We wash the A-E header here for the sake of VRY */
1027 30868
        if (cache_param->http_gzip_support &&
1028 15486
             (recv_handling != VCL_RET_PIPE) &&
1029 15358
             (recv_handling != VCL_RET_PASS)) {
1030 12166
                if (RFC2616_Req_Gzip(req->http)) {
1031 880
                        http_ForceHeader(req->http, H_Accept_Encoding, "gzip");
1032 880
                } else {
1033 11286
                        http_Unset(req->http, H_Accept_Encoding);
1034
                }
1035 12166
        }
1036
1037 15510
        VSHA256_Init(&sha256ctx);
1038 15510
        VCL_hash_method(req->vcl, wrk, req, NULL, &sha256ctx);
1039 15510
        if (wrk->vpi->handling == VCL_RET_FAIL)
1040 40
                recv_handling = wrk->vpi->handling;
1041
        else
1042 15470
                assert(wrk->vpi->handling == VCL_RET_LOOKUP);
1043 15510
        VSHA256_Final(req->digest, &sha256ctx);
1044
1045 15510
        switch (recv_handling) {
1046
        case VCL_RET_VCL:
1047 32
                VSLb(req->vsl, SLT_VCL_Error,
1048
                    "Illegal return(vcl): %s",
1049 16
                    req->restarts ? "Not after restarts" :
1050
                    "Only from active VCL");
1051 16
                req->err_code = 503;
1052 16
                req->req_step = R_STP_SYNTH;
1053 16
                break;
1054
        case VCL_RET_PURGE:
1055 40
                req->req_step = R_STP_PURGE;
1056 40
                break;
1057
        case VCL_RET_HASH:
1058 10454
                req->req_step = R_STP_LOOKUP;
1059 10454
                break;
1060
        case VCL_RET_PIPE:
1061 128
                if (!IS_TOPREQ(req)) {
1062 0
                        VSLb(req->vsl, SLT_VCL_Error,
1063
                            "vcl_recv{} returns pipe for ESI included object."
1064
                            "  Doing pass.");
1065 0
                        req->req_step = R_STP_PASS;
1066 128
                } else if (req->http0->protover > 11) {
1067 8
                        VSLb(req->vsl, SLT_VCL_Error,
1068
                            "vcl_recv{} returns pipe for HTTP/2 request."
1069
                            "  Doing pass.");
1070 8
                        req->req_step = R_STP_PASS;
1071 8
                } else {
1072 120
                        req->req_step = R_STP_PIPE;
1073
                }
1074 128
                break;
1075
        case VCL_RET_PASS:
1076 3196
                req->req_step = R_STP_PASS;
1077 3196
                break;
1078
        case VCL_RET_SYNTH:
1079 1600
                req->req_step = R_STP_SYNTH;
1080 1600
                break;
1081
        case VCL_RET_RESTART:
1082 36
                req->req_step = R_STP_RESTART;
1083 36
                break;
1084
        case VCL_RET_FAIL:
1085 40
                req->req_step = R_STP_VCLFAIL;
1086 40
                break;
1087
        default:
1088 0
                WRONG("Illegal return from vcl_recv{}");
1089 0
        }
1090 15510
        return (REQ_FSM_MORE);
1091 15745
}
1092
1093
/*--------------------------------------------------------------------
1094
 * Find the objhead, purge it.
1095
 *
1096
 * In VCL, a restart is necessary to get a new object
1097
 */
1098
1099
static enum req_fsm_nxt v_matchproto_(req_state_f)
1100 40
cnt_purge(struct worker *wrk, struct req *req)
1101
{
1102
        struct objcore *oc, *boc;
1103
        enum lookup_e lr;
1104
1105 40
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
1106 40
        CHECK_OBJ_NOTNULL(req, REQ_MAGIC);
1107 40
        AZ(req->objcore);
1108 40
        AZ(req->stale_oc);
1109
1110 40
        AN(req->vcl);
1111
1112 40
        VRY_Prep(req);
1113
1114 40
        AZ(req->objcore);
1115 40
        req->hash_always_miss = 1;
1116 40
        lr = HSH_Lookup(req, &oc, &boc);
1117 40
        assert (lr == HSH_MISS);
1118 40
        AZ(oc);
1119 40
        CHECK_OBJ_NOTNULL(boc, OBJCORE_MAGIC);
1120 40
        VRY_Finish(req, DISCARD);
1121
1122 40
        (void)HSH_Purge(wrk, boc->objhead, req->t_req, 0, 0, 0);
1123
1124 40
        HSH_Withdraw(wrk, &boc);
1125
1126 40
        VCL_purge_method(req->vcl, wrk, req, NULL, NULL);
1127 40
        switch (wrk->vpi->handling) {
1128
        case VCL_RET_RESTART:
1129 12
                req->req_step = R_STP_RESTART;
1130 12
                break;
1131
        case VCL_RET_FAIL:
1132 4
                req->req_step = R_STP_VCLFAIL;
1133 4
                break;
1134
        case VCL_RET_SYNTH:
1135 24
                req->req_step = R_STP_SYNTH;
1136 24
                break;
1137
        default:
1138 0
                WRONG("Illegal return from vcl_purge{}");
1139 0
        }
1140 40
        return (REQ_FSM_MORE);
1141
}
1142
1143
/*--------------------------------------------------------------------
1144
 * Central state engine dispatcher.
1145
 *
1146
 * Kick the session around until it has had enough.
1147
 *
1148
 */
1149
1150
static void v_matchproto_(req_state_f)
1151 1787
cnt_diag(struct req *req, const char *state)
1152
{
1153
1154 1787
        CHECK_OBJ_NOTNULL(req, REQ_MAGIC);
1155
1156 3574
        VSLb(req->vsl,  SLT_Debug, "vxid %ju STP_%s sp %p vcl %p",
1157 1787
            VXID(req->vsl->wid), state, req->sp, req->vcl);
1158 1787
        VSL_Flush(req->vsl, 0);
1159 1787
}
1160
1161
void
1162 16346
CNT_Embark(struct worker *wrk, struct req *req)
1163
{
1164
1165 16346
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
1166 16346
        CHECK_OBJ_NOTNULL(req, REQ_MAGIC);
1167
1168
        /* wrk can have changed for restarts */
1169 16346
        req->vfc->wrk = req->wrk = wrk;
1170 16346
        wrk->vsl = req->vsl;
1171 16346
        if (req->req_step == R_STP_TRANSPORT && req->vcl == NULL) {
1172 14053
                VCL_Refresh(&wrk->wpriv->vcl);
1173 14053
                req->vcl = wrk->wpriv->vcl;
1174 14053
                wrk->wpriv->vcl = NULL;
1175 14053
                VSLbs(req->vsl, SLT_VCL_use, TOSTRAND(VCL_Name(req->vcl)));
1176 14053
        }
1177
1178 16346
        AN(req->vcl);
1179 16346
}
1180
1181
enum req_fsm_nxt
1182 16058
CNT_Request(struct req *req)
1183
{
1184
        struct vrt_ctx ctx[1];
1185
        struct worker *wrk;
1186
        enum req_fsm_nxt nxt;
1187
1188 16058
        CHECK_OBJ_NOTNULL(req, REQ_MAGIC);
1189
1190 16058
        wrk = req->wrk;
1191 16058
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
1192
1193 16058
        CHECK_OBJ_NOTNULL(req->transport, TRANSPORT_MAGIC);
1194 16058
        AN(req->transport->deliver);
1195 16058
        AN(req->transport->minimal_response);
1196
1197
        /*
1198
         * Possible entrance states
1199
         */
1200 16058
        assert(
1201
            req->req_step == R_STP_LOOKUP ||
1202
            req->req_step == R_STP_FINISH ||
1203
            req->req_step == R_STP_TRANSPORT);
1204
1205 16058
        AN(VXID_TAG(req->vsl->wid) & VSL_CLIENTMARKER);
1206 16058
        AN(req->vcl);
1207
1208 122385
        for (nxt = REQ_FSM_MORE; nxt == REQ_FSM_MORE; ) {
1209
                /*
1210
                 * This is a good place to be paranoid about the various
1211
                 * pointers still pointing to the things we expect.
1212
                 */
1213 106327
                CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
1214 106327
                CHECK_OBJ_NOTNULL(wrk->wpriv, WORKER_PRIV_MAGIC);
1215 106327
                CHECK_OBJ_ORNULL(wrk->wpriv->nobjhead, OBJHEAD_MAGIC);
1216 106327
                CHECK_OBJ_NOTNULL(req, REQ_MAGIC);
1217 106327
                CHECK_OBJ_NOTNULL(req->doclose, STREAM_CLOSE_MAGIC);
1218
1219 106327
                AN(req->req_step);
1220 106327
                AN(req->req_step->name);
1221 106327
                AN(req->req_step->func);
1222 106327
                if (DO_DEBUG(DBG_REQ_STATE))
1223 1788
                        cnt_diag(req, req->req_step->name);
1224 106327
                nxt = req->req_step->func(wrk, req);
1225 106327
                CHECK_OBJ_ORNULL(wrk->wpriv->nobjhead, OBJHEAD_MAGIC);
1226
        }
1227 16058
        wrk->vsl = NULL;
1228 16058
        if (nxt == REQ_FSM_DONE) {
1229 15494
                INIT_OBJ(ctx, VRT_CTX_MAGIC);
1230 15494
                VCL_Req2Ctx(ctx, req);
1231 15494
                if (IS_TOPREQ(req)) {
1232 14027
                        VCL_TaskLeave(ctx, req->top->privs);
1233 14027
                        if (req->top->vcl0 != NULL)
1234 48
                                VCL_Recache(wrk, &req->top->vcl0);
1235 14027
                }
1236 15494
                VCL_TaskLeave(ctx, req->privs);
1237 15494
                assert(!IS_NO_VXID(req->vsl->wid));
1238 15494
                VRB_Free(req);
1239 15494
                VRT_Assign_Backend(&req->director_hint, NULL);
1240 15494
                req->wrk = NULL;
1241 15494
        }
1242 16058
        assert(nxt == REQ_FSM_DISEMBARK || !WS_IsReserved(req->ws));
1243 16058
        return (nxt);
1244
}