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