varnish-cache/bin/varnishd/cache/cache_req_fsm.c
1
/*-
2
 * Copyright (c) 2006 Verdens Gang AS
3
 * Copyright (c) 2006-2017 Varnish Software AS
4
 * All rights reserved.
5
 *
6
 * Author: Poul-Henning Kamp <phk@phk.freebsd.dk>
7
 *
8
 * Redistribution and use in source and binary forms, with or without
9
 * modification, are permitted provided that the following conditions
10
 * are met:
11
 * 1. Redistributions of source code must retain the above copyright
12
 *    notice, this list of conditions and the following disclaimer.
13
 * 2. Redistributions in binary form must reproduce the above copyright
14
 *    notice, this list of conditions and the following disclaimer in the
15
 *    documentation and/or other materials provided with the distribution.
16
 *
17
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20
 * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
21
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27
 * SUCH DAMAGE.
28
 *
29
 * This file contains the request-handling state engine, which is intended to
30
 * (over time) be(ome) protocol agnostic.
31
 * We already use this now with ESI:includes, which are for all relevant
32
 * purposes a different "protocol"
33
 *
34
 * A special complication is the fact that we can suspend processing of
35
 * a request when hash-lookup finds a busy objhdr.
36
 *
37
 */
38
39
#include "config.h"
40
41
#include "cache_varnishd.h"
42
#include "cache_director.h"
43
#include "cache_filter.h"
44
#include "cache_objhead.h"
45
#include "cache_transport.h"
46
47
#include "hash/hash_slinger.h"
48
#include "storage/storage.h"
49
#include "vcl.h"
50
#include "vsha256.h"
51
#include "vtim.h"
52
53
/*--------------------------------------------------------------------
54
 * Handle "Expect:" and "Connection:" on incoming request
55
 */
56
57
static enum req_fsm_nxt
58 3350
cnt_transport(struct worker *wrk, struct req *req)
59
{
60
        const char *p;
61
62 3350
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
63 3350
        CHECK_OBJ_NOTNULL(req, REQ_MAGIC);
64 3350
        CHECK_OBJ_NOTNULL(req->http, HTTP_MAGIC);
65 3350
        CHECK_OBJ_NOTNULL(req->transport, TRANSPORT_MAGIC);
66 3350
        assert(req->req_body_status != REQ_BODY_INIT);
67 3350
        AN(req->transport->minimal_response);
68
69 3350
        if (http_GetHdr(req->http, H_Expect, &p)) {
70 24
                if (strcasecmp(p, "100-continue")) {
71 4
                        req->doclose = SC_RX_JUNK;
72 4
                        (void)req->transport->minimal_response(req, 417);
73 4
                        wrk->stats->client_req_417++;
74 4
                        return (REQ_FSM_DONE);
75
                }
76 40
                if (req->http->protover >= 11 &&
77 20
                    req->htc->pipeline_b == NULL)       // XXX: HTTP1 vs 2 ?
78 18
                        req->want100cont = 1;
79 20
                http_Unset(req->http, H_Expect);
80
        }
81
82 3346
        wrk->stats->client_req++;
83
84 3346
        AZ(req->err_code);
85
86 3346
        req->doclose = http_DoConnection(req->http);
87 3346
        if (req->doclose == SC_RX_BAD) {
88 2
                (void)req->transport->minimal_response(req, 400);
89 2
                return (REQ_FSM_DONE);
90
        }
91
92 3344
        if (req->req_body_status < REQ_BODY_TAKEN) {
93 102
                AN(req->transport->req_body != NULL);
94 102
                VFP_Setup(req->vfc, wrk);
95 102
                req->vfc->resp = req->http;             // XXX
96 102
                req->transport->req_body(req);
97
        }
98
99 3344
        req->ws_req = WS_Snapshot(req->ws);
100 3344
        HTTP_Copy(req->http0, req->http);       // For ESI & restart
101 3344
        req->req_step = R_STP_RECV;
102 3344
        return (REQ_FSM_MORE);
103
}
104
105
/*--------------------------------------------------------------------
106
 * Deliver an object to client
107
 */
108
109
static enum req_fsm_nxt
110 3573
cnt_deliver(struct worker *wrk, struct req *req)
111
{
112
113 3573
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
114 3573
        CHECK_OBJ_NOTNULL(req, REQ_MAGIC);
115 3573
        CHECK_OBJ_NOTNULL(req->objcore, OBJCORE_MAGIC);
116 3573
        CHECK_OBJ_NOTNULL(req->objcore->objhead, OBJHEAD_MAGIC);
117 3573
        AZ(req->stale_oc);
118 3573
        AN(req->vcl);
119
120 3573
        assert(req->objcore->refcnt > 0);
121
122 3573
        ObjTouch(req->wrk, req->objcore, req->t_prev);
123
124 3573
        HTTP_Setup(req->resp, req->ws, req->vsl, SLT_RespMethod);
125 3572
        if (HTTP_Decode(req->resp,
126 3573
            ObjGetAttr(req->wrk, req->objcore, OA_HEADERS, NULL))) {
127 2
                (void)HSH_DerefObjCore(wrk, &req->objcore, HSH_RUSH_POLICY);
128 2
                req->err_code = 500;
129 2
                req->req_step = R_STP_SYNTH;
130 2
                return (REQ_FSM_MORE);
131
        }
132 3571
        http_ForceField(req->resp, HTTP_HDR_PROTO, "HTTP/1.1");
133
134 3571
        if (req->is_hit)
135 1946
                http_PrintfHeader(req->resp,
136 973
                    "X-Varnish: %u %u", VXID(req->vsl->wid),
137
                    ObjGetXID(wrk, req->objcore));
138
        else
139 2598
                http_PrintfHeader(req->resp,
140 2598
                    "X-Varnish: %u", VXID(req->vsl->wid));
141
142
        /*
143
         * We base Age calculation upon the last timestamp taken during
144
         * client request processing. This gives some inaccuracy, but
145
         * since Age is only full second resolution that shouldn't
146
         * matter. (Last request timestamp could be a Start timestamp
147
         * taken before the object entered into cache leading to negative
148
         * age. Truncate to zero in that case).
149
         */
150 3571
        http_PrintfHeader(req->resp, "Age: %.0f",
151 3571
            floor(fmax(0., req->t_prev - req->objcore->t_origin)));
152
153 3571
        http_SetHeader(req->resp, "Via: 1.1 varnish (Varnish/5.2)");
154
155 7142
        if (cache_param->http_gzip_support &&
156 3781
            ObjCheckFlag(req->wrk, req->objcore, OF_GZIPED) &&
157 210
            !RFC2616_Req_Gzip(req->http))
158 66
                RFC2616_Weaken_Etag(req->resp);
159
160 3571
        VCL_deliver_method(req->vcl, wrk, req, NULL, NULL);
161 3569
        VSLb_ts_req(req, "Process", W_TIM_real(wrk));
162
163 3569
        assert(req->restarts <= cache_param->max_restarts);
164
165 3569
        if (wrk->handling != VCL_RET_DELIVER) {
166 154
                (void)HSH_DerefObjCore(wrk, &req->objcore, HSH_RUSH_POLICY);
167 154
                http_Teardown(req->resp);
168
169 154
                switch (wrk->handling) {
170
                case VCL_RET_RESTART:
171 28
                        req->req_step = R_STP_RESTART;
172 28
                        break;
173
                case VCL_RET_FAIL:
174 116
                        req->req_step = R_STP_VCLFAIL;
175 116
                        break;
176
                case VCL_RET_SYNTH:
177 10
                        req->req_step = R_STP_SYNTH;
178 10
                        break;
179
                default:
180 0
                        WRONG("Illegal return from vcl_deliver{}");
181
                }
182
183 154
                return (REQ_FSM_MORE);
184
        }
185
186 3415
        assert(wrk->handling == VCL_RET_DELIVER);
187
188 3415
        if (req->esi_level == 0
189 2932
            && http_IsStatus(req->resp, 200)
190 2682
            && req->http->conds && RFC2616_Do_Cond(req))
191 60
                http_PutResponse(req->resp, "HTTP/1.1", 304, NULL);
192
193 3415
        req->req_step = R_STP_TRANSMIT;
194 3415
        return (REQ_FSM_MORE);
195
}
196
197
/*--------------------------------------------------------------------
198
 * VCL failed, die horribly
199
 */
200
201
static enum req_fsm_nxt
202 148
cnt_vclfail(const struct worker *wrk, struct req *req)
203
{
204
205 148
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
206 148
        CHECK_OBJ_NOTNULL(req, REQ_MAGIC);
207
208 148
        AZ(req->objcore);
209 148
        AZ(req->stale_oc);
210
211 148
        HTTP_Copy(req->http, req->http0);
212 148
        WS_Reset(req->ws, req->ws_req);
213 148
        req->err_code = 503;
214 148
        req->err_reason = "VCL failed";
215 148
        req->req_step = R_STP_SYNTH;
216 148
        req->doclose = SC_VCL_FAILURE;
217 148
        return (REQ_FSM_MORE);
218
}
219
220
/*--------------------------------------------------------------------
221
 * Emit a synthetic response
222
 */
223
224
static enum req_fsm_nxt
225 396
cnt_synth(struct worker *wrk, struct req *req)
226
{
227
        struct http *h;
228
        double now;
229
        struct vsb *synth_body;
230
        ssize_t sz, szl;
231
        uint8_t *ptr;
232
233 396
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
234 396
        CHECK_OBJ_NOTNULL(req, REQ_MAGIC);
235
236 396
        AZ(req->objcore);
237 396
        AZ(req->stale_oc);
238
239 396
        wrk->stats->s_synth++;
240
241 396
        now = W_TIM_real(wrk);
242 396
        VSLb_ts_req(req, "Process", now);
243
244 396
        if (req->err_code < 100)
245 0
                req->err_code = 501;
246
247 396
        HTTP_Setup(req->resp, req->ws, req->vsl, SLT_RespMethod);
248 396
        h = req->resp;
249 396
        http_TimeHeader(h, "Date: ", now);
250 396
        http_SetHeader(h, "Server: Varnish");
251 396
        http_PrintfHeader(req->resp, "X-Varnish: %u", VXID(req->vsl->wid));
252 396
        http_PutResponse(h, "HTTP/1.1", req->err_code, req->err_reason);
253
254
        /*
255
         * For late 100-continue, we suggest to VCL to close the connection to
256
         * neither send a 100-continue nor drain-read the request. But VCL has
257
         * the option to veto by removing Connection: close
258
         */
259 396
        if (req->want100cont) {
260 6
                http_SetHeader(h, "Connection: close");
261
        }
262
263 396
        synth_body = VSB_new_auto();
264 396
        AN(synth_body);
265
266 396
        VCL_synth_method(req->vcl, wrk, req, NULL, synth_body);
267
268 396
        AZ(VSB_finish(synth_body));
269
270 396
        if (wrk->handling == VCL_RET_FAIL) {
271 6
                VSB_destroy(&synth_body);
272 6
                req->doclose = SC_VCL_FAILURE;
273 6
                VSLb_ts_req(req, "Resp", W_TIM_real(wrk));
274 6
                http_Teardown(req->resp);
275 6
                return (REQ_FSM_DONE);
276
        }
277
278 390
        if (wrk->handling == VCL_RET_RESTART) {
279
                /*
280
                 * XXX: Should we reset req->doclose = SC_VCL_FAILURE
281
                 * XXX: If so, to what ?
282
                 */
283 12
                HTTP_Setup(h, req->ws, req->vsl, SLT_RespMethod);
284 12
                VSB_destroy(&synth_body);
285 12
                req->req_step = R_STP_RESTART;
286 12
                return (REQ_FSM_MORE);
287
        }
288 378
        assert(wrk->handling == VCL_RET_DELIVER);
289
290 378
        http_Unset(h, H_Content_Length);
291 378
        http_PrintfHeader(req->resp, "Content-Length: %zd",
292
            VSB_len(synth_body));
293
294 378
        if (!req->doclose && http_HdrIs(req->resp, H_Connection, "close"))
295 6
                req->doclose = SC_RESP_CLOSE;
296
297
        /* Discard any lingering request body before delivery */
298 378
        (void)VRB_Ignore(req);
299
300 378
        req->objcore = HSH_Private(wrk);
301 378
        CHECK_OBJ_NOTNULL(req->objcore, OBJCORE_MAGIC);
302 378
        szl = -1;
303 378
        if (STV_NewObject(wrk, req->objcore, stv_transient, 1024)) {
304 376
                szl = VSB_len(synth_body);
305 376
                assert(szl >= 0);
306 376
                sz = szl;
307 728
                if (sz > 0 &&
308 704
                    ObjGetSpace(wrk, req->objcore, &sz, &ptr) && sz >= szl) {
309 352
                        memcpy(ptr, VSB_data(synth_body), szl);
310 352
                        ObjExtend(wrk, req->objcore, szl);
311 24
                } else if (sz > 0) {
312 0
                        szl = -1;
313
                }
314
        }
315
316 378
        if (szl >= 0)
317 376
                AZ(ObjSetU64(wrk, req->objcore, OA_LEN, szl));
318 378
        HSH_DerefBoc(wrk, req->objcore);
319 378
        VSB_destroy(&synth_body);
320
321 378
        if (szl < 0) {
322 2
                VSLb(req->vsl, SLT_Error, "Could not get storage");
323 2
                req->doclose = SC_OVERLOAD;
324 2
                VSLb_ts_req(req, "Resp", W_TIM_real(wrk));
325 2
                (void)HSH_DerefObjCore(wrk, &req->objcore, 1);
326 2
                http_Teardown(req->resp);
327 2
                return (REQ_FSM_DONE);
328
        }
329
330 376
        req->req_step = R_STP_TRANSMIT;
331 376
        return (REQ_FSM_MORE);
332
}
333
334
/*--------------------------------------------------------------------
335
 * The mechanics of sending a response (from deliver or synth)
336
 */
337
338
static enum req_fsm_nxt
339 3791
cnt_transmit(struct worker *wrk, struct req *req)
340
{
341
        struct boc *boc;
342
        const char *r;
343
        uint16_t status;
344
        int sendbody;
345
        intmax_t clval;
346
347 3791
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
348 3791
        CHECK_OBJ_NOTNULL(req, REQ_MAGIC);
349 3791
        CHECK_OBJ_NOTNULL(req->transport, TRANSPORT_MAGIC);
350 3791
        CHECK_OBJ_NOTNULL(req->objcore, OBJCORE_MAGIC);
351 3791
        AZ(req->stale_oc);
352
353
        /* Grab a ref to the bo if there is one */
354 3791
        boc = HSH_RefBoc(req->objcore);
355
356 3791
        clval = http_GetContentLength(req->resp);
357 3790
        if (boc != NULL)
358 1011
                req->resp_len = clval;
359
        else
360 2779
                req->resp_len = ObjGetLen(req->wrk, req->objcore);
361
362 3790
        req->res_mode = 0;
363
364
        /* RFC 7230, 3.3.3 */
365 3790
        status = http_GetStatus(req->resp);
366 3790
        if (!strcmp(req->http0->hd[HTTP_HDR_METHOD].b, "HEAD")) {
367 14
                if (req->objcore->flags & OC_F_PASS)
368 4
                        sendbody = -1;
369
                else
370 10
                        sendbody = 0;
371 3776
        } else if (status < 200 || status == 204 || status == 304) {
372 84
                req->resp_len = -1;
373 84
                sendbody = 0;
374
        } else
375 3692
                sendbody = 1;
376
377 3790
        if (sendbody >= 0) {
378 6431
                if (!req->disable_esi && req->resp_len != 0 &&
379 2645
                    ObjHasAttr(wrk, req->objcore, OA_ESIDATA))
380 200
                        VDP_push(req, &VDP_esi, NULL, 0);
381
382 7573
                if (cache_param->http_gzip_support &&
383 3995
                    ObjCheckFlag(req->wrk, req->objcore, OF_GZIPED) &&
384 208
                    !RFC2616_Req_Gzip(req->http))
385 64
                        VDP_push(req, &VDP_gunzip, NULL, 1);
386
387 7570
                if (cache_param->http_range_support &&
388 3784
                    http_IsStatus(req->resp, 200)) {
389 3200
                        http_ForceHeader(req->resp, H_Accept_Ranges, "bytes");
390 3200
                        if (sendbody && http_GetHdr(req->http, H_Range, &r))
391 62
                                VRG_dorange(req, r);
392
                }
393
        }
394
395 3791
        if (sendbody < 0) {
396
                /* Don't touch pass+HEAD C-L */
397 4
                sendbody = 0;
398 3787
        } else if (clval >= 0 && clval == req->resp_len) {
399
                /* Reuse C-L header */
400
        } else {
401 732
                http_Unset(req->resp, H_Content_Length);
402 732
                if (req->resp_len >= 0 && sendbody)
403 345
                        http_PrintfHeader(req->resp,
404
                            "Content-Length: %jd", req->resp_len);
405
        }
406
407 3791
        req->transport->deliver(req, boc, sendbody);
408
409 3790
        VSLb_ts_req(req, "Resp", W_TIM_real(wrk));
410
411 3791
        if (req->objcore->flags & (OC_F_PRIVATE | OC_F_PASS)) {
412 1113
                if (boc != NULL) {
413 393
                        HSH_Abandon(req->objcore);
414 393
                        ObjWaitState(req->objcore, BOS_FINISHED);
415
                }
416 1113
                ObjSlim(wrk, req->objcore);
417
        }
418
419 3791
        if (boc != NULL)
420 1012
                HSH_DerefBoc(wrk, req->objcore);
421
422 3791
        (void)HSH_DerefObjCore(wrk, &req->objcore, HSH_RUSH_POLICY);
423 3791
        http_Teardown(req->resp);
424
425 3791
        return (REQ_FSM_DONE);
426
}
427
428
/*--------------------------------------------------------------------
429
 * Initiated a fetch (pass/miss) which we intend to deliver
430
 */
431
432
static enum req_fsm_nxt
433 2634
cnt_fetch(struct worker *wrk, struct req *req)
434
{
435
436 2634
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
437 2634
        CHECK_OBJ_NOTNULL(req, REQ_MAGIC);
438 2634
        CHECK_OBJ_NOTNULL(req->objcore, OBJCORE_MAGIC);
439 2634
        AZ(req->stale_oc);
440
441 2634
        wrk->stats->s_fetch++;
442 2634
        (void)VRB_Ignore(req);
443
444 2634
        if (req->objcore->flags & OC_F_FAILED) {
445 32
                req->err_code = 503;
446 32
                req->req_step = R_STP_SYNTH;
447 32
                (void)HSH_DerefObjCore(wrk, &req->objcore, 1);
448 32
                AZ(req->objcore);
449 32
                return (REQ_FSM_MORE);
450
        }
451
452 2602
        req->req_step = R_STP_DELIVER;
453 2602
        return (REQ_FSM_MORE);
454
}
455
456
/*--------------------------------------------------------------------
457
 * Attempt to lookup objhdr from hash.  We disembark and reenter
458
 * this state if we get suspended on a busy objhdr.
459
 */
460
461
static enum req_fsm_nxt
462 3086
cnt_lookup(struct worker *wrk, struct req *req)
463
{
464
        struct objcore *oc, *busy;
465
        enum lookup_e lr;
466 3086
        int had_objhead = 0;
467
468 3086
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
469 3086
        CHECK_OBJ_NOTNULL(req, REQ_MAGIC);
470 3086
        AZ(req->objcore);
471 3086
        AZ(req->stale_oc);
472
473 3086
        AN(req->vcl);
474
475 3086
        VRY_Prep(req);
476
477 3087
        AZ(req->objcore);
478 3087
        if (req->hash_objhead)
479 44
                had_objhead = 1;
480 3087
        lr = HSH_Lookup(req, &oc, &busy, req->hash_always_miss ? 1 : 0);
481 3087
        if (lr == HSH_BUSY) {
482
                /*
483
                 * We lost the session to a busy object, disembark the
484
                 * worker thread.   We return to STP_LOOKUP when the busy
485
                 * object has been unbusied, and still have the objhead
486
                 * around to restart the lookup with.
487
                 */
488 44
                return (REQ_FSM_DISEMBARK);
489
        }
490 3043
        if (had_objhead)
491 27
                VSLb_ts_req(req, "Waitinglist", W_TIM_real(wrk));
492
493 3043
        if (busy == NULL) {
494 992
                VRY_Finish(req, DISCARD);
495
        } else {
496 2051
                AN(busy->flags & OC_F_BUSY);
497 2051
                VRY_Finish(req, KEEP);
498
        }
499
500 3043
        AZ(req->objcore);
501 3043
        if (lr == HSH_MISS) {
502
                /* Found nothing */
503 2005
                AZ(oc);
504 2005
                if (busy != NULL) {
505 1997
                        AN(busy->flags & OC_F_BUSY);
506 1997
                        req->objcore = busy;
507 1997
                        req->req_step = R_STP_MISS;
508
                } else {
509 8
                        req->req_step = R_STP_PASS;
510
                }
511 2005
                return (REQ_FSM_MORE);
512
        }
513
514 1038
        CHECK_OBJ_NOTNULL(oc, OBJCORE_MAGIC);
515 1038
        AZ(oc->flags & OC_F_BUSY);
516 1038
        req->objcore = oc;
517 1038
        AZ(oc->flags & OC_F_PASS);
518
519 4152
        VSLb(req->vsl, SLT_Hit, "%u %.6f %.6f %.6f",
520
            ObjGetXID(wrk, req->objcore),
521 2076
            EXP_Dttl(req, req->objcore),
522 1038
            req->objcore->grace,
523 1038
            req->objcore->keep);
524
525 1038
        VCL_hit_method(req->vcl, wrk, req, NULL, NULL);
526
527 1038
        switch (wrk->handling) {
528
        case VCL_RET_DELIVER:
529 971
                if (busy != NULL) {
530 24
                        AZ(oc->flags & OC_F_PASS);
531 24
                        CHECK_OBJ_NOTNULL(busy->boc, BOC_MAGIC);
532 24
                        VBF_Fetch(wrk, req, busy, oc, VBF_BACKGROUND);
533
                } else {
534 947
                        (void)VRB_Ignore(req);// XXX: handle err
535
                }
536 971
                wrk->stats->cache_hit++;
537 971
                req->is_hit = 1;
538 971
                if (lr == HSH_EXP || lr == HSH_EXPBUSY)
539 26
                        wrk->stats->cache_hit_grace++;
540 971
                req->req_step = R_STP_DELIVER;
541 971
                return (REQ_FSM_MORE);
542
        case VCL_RET_MISS:
543 33
                if (busy != NULL) {
544 30
                        req->objcore = busy;
545 30
                        req->stale_oc = oc;
546 30
                        req->req_step = R_STP_MISS;
547
                } else {
548 3
                        (void)HSH_DerefObjCore(wrk, &req->objcore,
549
                            HSH_RUSH_POLICY);
550
                        /*
551
                         * We don't have a busy object, so treat this
552
                         * like a pass
553
                         */
554 3
                        VSLb(req->vsl, SLT_VCL_Error,
555
                            "vcl_hit{} returns miss without busy object."
556
                            "  Doing pass.");
557 3
                        req->req_step = R_STP_PASS;
558
                }
559 33
                return (REQ_FSM_MORE);
560
        case VCL_RET_RESTART:
561 26
                req->req_step = R_STP_RESTART;
562 26
                break;
563
        case VCL_RET_FAIL:
564 2
                req->req_step = R_STP_VCLFAIL;
565 2
                break;
566
        case VCL_RET_SYNTH:
567 2
                req->req_step = R_STP_SYNTH;
568 2
                break;
569
        case VCL_RET_PASS:
570 4
                wrk->stats->cache_hit++;
571 4
                req->is_hit = 1;
572 4
                req->req_step = R_STP_PASS;
573 4
                break;
574
        default:
575 0
                WRONG("Illegal return from vcl_hit{}");
576
        }
577
578
        /* Drop our object, we won't need it */
579 34
        (void)HSH_DerefObjCore(wrk, &req->objcore, HSH_RUSH_POLICY);
580
581 34
        if (busy != NULL) {
582 0
                (void)HSH_DerefObjCore(wrk, &busy, 0);
583 0
                VRY_Clear(req);
584
        }
585
586 34
        return (REQ_FSM_MORE);
587
}
588
589
/*--------------------------------------------------------------------
590
 * Cache miss.
591
 */
592
593
static enum req_fsm_nxt
594 2027
cnt_miss(struct worker *wrk, struct req *req)
595
{
596
597 2027
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
598 2027
        CHECK_OBJ_NOTNULL(req, REQ_MAGIC);
599 2027
        AN(req->vcl);
600 2027
        CHECK_OBJ_NOTNULL(req->objcore, OBJCORE_MAGIC);
601 2027
        CHECK_OBJ_ORNULL(req->stale_oc, OBJCORE_MAGIC);
602
603 2027
        VCL_miss_method(req->vcl, wrk, req, NULL, NULL);
604 2027
        switch (wrk->handling) {
605
        case VCL_RET_FETCH:
606 1997
                wrk->stats->cache_miss++;
607 1997
                VBF_Fetch(wrk, req, req->objcore, req->stale_oc, VBF_NORMAL);
608 1995
                if (req->stale_oc != NULL)
609 30
                        (void)HSH_DerefObjCore(wrk, &req->stale_oc, 0);
610 1995
                req->req_step = R_STP_FETCH;
611 1995
                return (REQ_FSM_MORE);
612
        case VCL_RET_FAIL:
613 2
                req->req_step = R_STP_VCLFAIL;
614 2
                break;
615
        case VCL_RET_SYNTH:
616 16
                req->req_step = R_STP_SYNTH;
617 16
                break;
618
        case VCL_RET_RESTART:
619 8
                req->req_step = R_STP_RESTART;
620 8
                break;
621
        case VCL_RET_PASS:
622 4
                req->req_step = R_STP_PASS;
623 4
                break;
624
        default:
625 0
                WRONG("Illegal return from vcl_miss{}");
626
        }
627 30
        VRY_Clear(req);
628 30
        if (req->stale_oc != NULL)
629 0
                (void)HSH_DerefObjCore(wrk, &req->stale_oc, 0);
630 30
        AZ(HSH_DerefObjCore(wrk, &req->objcore, 1));
631 30
        return (REQ_FSM_MORE);
632
}
633
634
/*--------------------------------------------------------------------
635
 * Pass processing
636
 */
637
638
static enum req_fsm_nxt
639 644
cnt_pass(struct worker *wrk, struct req *req)
640
{
641
642 644
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
643 644
        CHECK_OBJ_NOTNULL(req, REQ_MAGIC);
644 644
        AN(req->vcl);
645 644
        AZ(req->objcore);
646 644
        AZ(req->stale_oc);
647
648 644
        VCL_pass_method(req->vcl, wrk, req, NULL, NULL);
649 644
        switch (wrk->handling) {
650
        case VCL_RET_FAIL:
651 4
                req->req_step = R_STP_VCLFAIL;
652 4
                break;
653
        case VCL_RET_SYNTH:
654 2
                req->req_step = R_STP_SYNTH;
655 2
                break;
656
        case VCL_RET_RESTART:
657 0
                req->req_step = R_STP_RESTART;
658 0
                break;
659
        case VCL_RET_FETCH:
660 638
                wrk->stats->s_pass++;
661 638
                req->objcore = HSH_Private(wrk);
662 639
                CHECK_OBJ_NOTNULL(req->objcore, OBJCORE_MAGIC);
663 639
                VBF_Fetch(wrk, req, req->objcore, NULL, VBF_PASS);
664 639
                req->req_step = R_STP_FETCH;
665 639
                break;
666
        default:
667 0
                WRONG("Illegal return from cnt_pass{}");
668
        }
669 645
        return (REQ_FSM_MORE);
670
}
671
672
/*--------------------------------------------------------------------
673
 * Pipe mode
674
 */
675
676
static enum req_fsm_nxt
677 24
cnt_pipe(struct worker *wrk, struct req *req)
678
{
679
        struct busyobj *bo;
680
        enum req_fsm_nxt nxt;
681
682 24
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
683 24
        CHECK_OBJ_NOTNULL(req, REQ_MAGIC);
684 24
        AZ(req->objcore);
685 24
        AZ(req->stale_oc);
686 24
        AN(req->vcl);
687
688 24
        wrk->stats->s_pipe++;
689 24
        bo = VBO_GetBusyObj(wrk, req);
690 24
        CHECK_OBJ_NOTNULL(bo, BUSYOBJ_MAGIC);
691 24
        VSLb(bo->vsl, SLT_Begin, "bereq %u pipe", VXID(req->vsl->wid));
692 24
        VSLb(req->vsl, SLT_Link, "bereq %u pipe", VXID(bo->vsl->wid));
693 24
        THR_SetBusyobj(bo);
694
695 24
        HTTP_Setup(bo->bereq, bo->ws, bo->vsl, SLT_BereqMethod);
696 24
        http_FilterReq(bo->bereq, req->http, 0);        // XXX: 0 ?
697 24
        http_PrintfHeader(bo->bereq, "X-Varnish: %u", VXID(req->vsl->wid));
698 24
        http_ForceHeader(bo->bereq, H_Connection, "close");
699
700 24
        if (req->want100cont) {
701 0
                http_SetHeader(bo->bereq, "Expect: 100-continue");
702 0
                req->want100cont = 0;
703
        }
704
705 24
        VCL_pipe_method(req->vcl, wrk, req, bo, NULL);
706
707 24
        switch (wrk->handling) {
708
        case VCL_RET_FAIL:
709 2
                req->req_step = R_STP_VCLFAIL;
710 2
                nxt = REQ_FSM_MORE;
711 2
                break;
712
        case VCL_RET_SYNTH:
713 2
                req->req_step = R_STP_SYNTH;
714 2
                nxt = REQ_FSM_MORE;
715 2
                break;
716
        case VCL_RET_PIPE:
717 20
                AZ(bo->req);
718 20
                bo->req = req;
719 20
                bo->wrk = wrk;
720 20
                SES_Close(req->sp, VDI_Http1Pipe(req, bo));
721 20
                nxt = REQ_FSM_DONE;
722 20
                break;
723
        default:
724 0
                WRONG("Illegal return from vcl_pipe{}");
725
        }
726 24
        http_Teardown(bo->bereq);
727 24
        VBO_ReleaseBusyObj(wrk, &bo);
728 24
        THR_SetBusyobj(NULL);
729 24
        return (nxt);
730
}
731
732
/*--------------------------------------------------------------------
733
 * Handle restart events
734
 */
735
736
static enum req_fsm_nxt
737 80
cnt_restart(struct worker *wrk, struct req *req)
738
{
739
740 80
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
741 80
        CHECK_OBJ_NOTNULL(req, REQ_MAGIC);
742 80
        AZ(req->objcore);
743 80
        AZ(req->stale_oc);
744
745 80
        if (++req->restarts > cache_param->max_restarts) {
746 10
                VSLb(req->vsl, SLT_VCL_Error, "Too many restarts");
747 10
                req->err_code = 503;
748 10
                req->req_step = R_STP_SYNTH;
749
        } else {
750
                // XXX: ReqEnd + ReqAcct ?
751 70
                VSLb_ts_req(req, "Restart", W_TIM_real(wrk));
752 70
                VSL_ChgId(req->vsl, "req", "restart",
753
                    VXID_Get(wrk, VSL_CLIENTMARKER));
754 70
                VSLb_ts_req(req, "Start", req->t_prev);
755 70
                req->err_code = 0;
756 70
                req->req_step = R_STP_RECV;
757
        }
758 80
        return (REQ_FSM_MORE);
759
}
760
761
/*
762
 * prepare the request for vcl_recv, either initially or after a reset
763
 * e.g. due to vcl switching
764
 *
765
 * TODO
766
 * - make restarts == 0 bit re-usable for rollback
767
 * - remove duplicatation with Req_Cleanup()
768
 */
769
770
static void
771 3916
cnt_recv_prep(struct req *req, const char *ci)
772
{
773
        const char *xff;
774
775 3916
        if (req->restarts == 0) {
776
                /*
777
                 * This really should be done earlier, but we want to capture
778
                 * it in the VSL log.
779
                 */
780 3847
                http_CollectHdr(req->http, H_X_Forwarded_For);
781 3847
                if (http_GetHdr(req->http, H_X_Forwarded_For, &xff)) {
782 14
                        http_Unset(req->http, H_X_Forwarded_For);
783 14
                        http_PrintfHeader(req->http, "X-Forwarded-For: %s, %s",
784
                            xff, ci);
785
                } else {
786 3833
                        http_PrintfHeader(req->http, "X-Forwarded-For: %s", ci);
787
                }
788 3847
                http_CollectHdr(req->http, H_Cache_Control);
789
790
                /* By default we use the first backend */
791 3845
                req->director_hint = VCL_DefaultDirector(req->vcl);
792 3845
                AN(req->director_hint);
793
794 3845
                req->d_ttl = -1;
795 3845
                req->disable_esi = 0;
796 3845
                req->hash_always_miss = 0;
797 3845
                req->hash_ignore_busy = 0;
798 3845
                req->client_identity = NULL;
799 3845
                req->storage = NULL;
800
        }
801
802 3914
        req->vdc->retval = 0;
803 3914
        req->is_hit = 0;
804 3914
}
805
/*--------------------------------------------------------------------
806
 * We have a complete request, set everything up and start it.
807
 * We can come here both with a request from the client and with
808
 * a interior request during ESI delivery.
809
 */
810
811
static enum req_fsm_nxt
812 3903
cnt_recv(struct worker *wrk, struct req *req)
813
{
814
        unsigned recv_handling;
815
        struct VSHA256Context sha256ctx;
816
        const char *ci, *cp;
817
818 3903
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
819 3903
        CHECK_OBJ_NOTNULL(req, REQ_MAGIC);
820 3903
        AN(req->vcl);
821 3903
        AZ(req->objcore);
822 3903
        AZ(req->stale_oc);
823 3903
        AZ(req->err_code);
824
825 3903
        AZ(isnan(req->t_first));
826 3902
        AZ(isnan(req->t_prev));
827 3902
        AZ(isnan(req->t_req));
828
829 3903
        ci = SES_Get_String_Attr(req->sp, SA_CLIENT_IP);
830 3902
        cp = SES_Get_String_Attr(req->sp, SA_CLIENT_PORT);
831 3901
        VSLb(req->vsl, SLT_ReqStart, "%s %s", ci, cp);
832
833 3903
        http_VSL_log(req->http);
834
835 3903
        cnt_recv_prep(req, ci);
836
837 3903
        if (req->req_body_status == REQ_BODY_FAIL) {
838 0
                req->doclose = SC_OVERLOAD;
839 0
                return (REQ_FSM_DONE);
840
        }
841
842 3903
        VCL_recv_method(req->vcl, wrk, req, NULL, NULL);
843 3898
        if (wrk->handling == VCL_RET_VCL && req->restarts == 0) {
844 14
                HTTP_Copy(req->http, req->http0);
845 14
                WS_Reset(req->ws, req->ws_req);
846 14
                cnt_recv_prep(req, ci);
847 14
                VCL_recv_method(req->vcl, wrk, req, NULL, NULL);
848
        }
849
850 3897
        if (req->want100cont && !req->late100cont) {
851 8
                req->want100cont = 0;
852 8
                if (req->transport->minimal_response(req, 100)) {
853 0
                        req->doclose = SC_REM_CLOSE;
854 0
                        return (REQ_FSM_DONE);
855
                }
856
        }
857
858
        /* Attempts to cache req.body may fail */
859 3897
        if (req->req_body_status == REQ_BODY_FAIL) {
860 6
                req->doclose = SC_RX_BODY;
861 6
                return (REQ_FSM_DONE);
862
        }
863
864 3891
        recv_handling = wrk->handling;
865
866
        /* We wash the A-E header here for the sake of VRY */
867 3891
        if (cache_param->http_gzip_support &&
868 3866
             (recv_handling != VCL_RET_PIPE) &&
869
             (recv_handling != VCL_RET_PASS)) {
870 3243
                if (RFC2616_Req_Gzip(req->http)) {
871 216
                        http_ForceHeader(req->http, H_Accept_Encoding, "gzip");
872
                } else {
873 3026
                        http_Unset(req->http, H_Accept_Encoding);
874
                }
875
        }
876
877 3891
        VSHA256_Init(&sha256ctx);
878 3892
        VCL_hash_method(req->vcl, wrk, req, NULL, &sha256ctx);
879 3893
        if (wrk->handling == VCL_RET_FAIL)
880 4
                recv_handling = wrk->handling;
881
        else
882 3889
                assert(wrk->handling == VCL_RET_LOOKUP);
883 3893
        VSHA256_Final(req->digest, &sha256ctx);
884
885 3893
        switch (recv_handling) {
886
        case VCL_RET_VCL:
887 6
                VSLb(req->vsl, SLT_VCL_Error,
888
                    "Illegal return(vcl): %s",
889 6
                    req->restarts ? "Not after restarts" :
890
                    "Only from active VCL");
891 6
                req->err_code = 503;
892 6
                req->req_step = R_STP_SYNTH;
893 6
                return (REQ_FSM_MORE);
894
        case VCL_RET_PURGE:
895 16
                req->req_step = R_STP_PURGE;
896 16
                return (REQ_FSM_MORE);
897
        case VCL_RET_HASH:
898 3043
                req->req_step = R_STP_LOOKUP;
899 3043
                return (REQ_FSM_MORE);
900
        case VCL_RET_PIPE:
901 26
                if (req->esi_level > 0) {
902 0
                        VSLb(req->vsl, SLT_VCL_Error,
903
                            "vcl_recv{} returns pipe for ESI included object."
904
                            "  Doing pass.");
905 0
                        req->req_step = R_STP_PASS;
906 26
                } else if (req->http0->protover > 11) {
907 2
                        VSLb(req->vsl, SLT_VCL_Error,
908
                            "vcl_recv{} returns pipe for HTTP/2 request."
909
                            "  Doing pass.");
910 2
                        req->req_step = R_STP_PASS;
911
                } else {
912 24
                        req->req_step = R_STP_PIPE;
913
                }
914 26
                return (REQ_FSM_MORE);
915
        case VCL_RET_PASS:
916 624
                req->req_step = R_STP_PASS;
917 624
                return (REQ_FSM_MORE);
918
        case VCL_RET_SYNTH:
919 160
                req->req_step = R_STP_SYNTH;
920 160
                return (REQ_FSM_MORE);
921
        case VCL_RET_FAIL:
922 18
                req->req_step = R_STP_VCLFAIL;
923 18
                return (REQ_FSM_MORE);
924
        default:
925 0
                WRONG("Illegal return from vcl_recv{}");
926
        }
927
}
928
929
/*--------------------------------------------------------------------
930
 * Find the objhead, purge it.
931
 *
932
 * XXX: We should ask VCL if we should fetch a new copy of the object.
933
 */
934
935
static enum req_fsm_nxt
936 16
cnt_purge(struct worker *wrk, struct req *req)
937
{
938
        struct objcore *oc, *boc;
939
        enum lookup_e lr;
940
941 16
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
942 16
        CHECK_OBJ_NOTNULL(req, REQ_MAGIC);
943 16
        AZ(req->objcore);
944 16
        AZ(req->stale_oc);
945
946 16
        AN(req->vcl);
947
948 16
        VRY_Prep(req);
949
950 16
        AZ(req->objcore);
951 16
        lr = HSH_Lookup(req, &oc, &boc, 1);
952 16
        assert (lr == HSH_MISS);
953 16
        AZ(oc);
954 16
        CHECK_OBJ_NOTNULL(boc, OBJCORE_MAGIC);
955 16
        VRY_Finish(req, DISCARD);
956
957 16
        (void)HSH_Purge(wrk, boc->objhead, 0, 0, 0);
958
959 16
        AZ(HSH_DerefObjCore(wrk, &boc, 1));
960
961 16
        VCL_purge_method(req->vcl, wrk, req, NULL, NULL);
962 16
        switch (wrk->handling) {
963
        case VCL_RET_RESTART:
964 6
                req->req_step = R_STP_RESTART;
965 6
                break;
966
        case VCL_RET_FAIL:
967 4
                req->req_step = R_STP_VCLFAIL;
968 4
                break;
969
        case VCL_RET_SYNTH:
970 6
                req->req_step = R_STP_SYNTH;
971 6
                break;
972
        default:
973 0
                WRONG("Illegal return from vcl_purge{}");
974
        }
975 16
        return (REQ_FSM_MORE);
976
}
977
978
/*--------------------------------------------------------------------
979
 * Central state engine dispatcher.
980
 *
981
 * Kick the session around until it has had enough.
982
 *
983
 */
984
985
static void
986 14
cnt_diag(struct req *req, const char *state)
987
{
988
989 14
        CHECK_OBJ_NOTNULL(req, REQ_MAGIC);
990
991 14
        VSLb(req->vsl,  SLT_Debug, "vxid %u STP_%s sp %p vcl %p",
992
            req->vsl->wid, state, req->sp, req->vcl);
993 14
        VSL_Flush(req->vsl, 0);
994 14
}
995
996
enum req_fsm_nxt
997 3882
CNT_Request(struct worker *wrk, struct req *req)
998
{
999
        enum req_fsm_nxt nxt;
1000
1001 3882
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
1002 3882
        CHECK_OBJ_NOTNULL(req, REQ_MAGIC);
1003
1004
        /*
1005
         * Possible entrance states
1006
         */
1007 3882
        assert(
1008
            req->req_step == R_STP_LOOKUP ||
1009
            req->req_step == R_STP_TRANSPORT ||
1010
            req->req_step == R_STP_RECV);
1011
1012 3882
        AN(req->vsl->wid & VSL_CLIENTMARKER);
1013
1014
        /* wrk can have changed for restarts */
1015 3882
        req->vfc->wrk = req->wrk = wrk;
1016 3882
        wrk->vsl = req->vsl;
1017 31429
        for (nxt = REQ_FSM_MORE; nxt == REQ_FSM_MORE; ) {
1018
                /*
1019
                 * This is a good place to be paranoid about the various
1020
                 * pointers still pointing to the things we expect.
1021
                 */
1022 23672
                CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
1023 23673
                CHECK_OBJ_ORNULL(wrk->nobjhead, OBJHEAD_MAGIC);
1024 23673
                CHECK_OBJ_NOTNULL(req, REQ_MAGIC);
1025
1026 23673
                switch (req->req_step) {
1027
#define REQ_STEP(l,u,arg) \
1028
                    case R_STP_##u: \
1029
                        if (DO_DEBUG(DBG_REQ_STATE)) \
1030
                                cnt_diag(req, #u); \
1031
                        nxt = cnt_##l arg; \
1032
                        break;
1033
#include "tbl/steps.h"
1034
                default:
1035 0
                        WRONG("State engine misfire");
1036
                }
1037 23665
                CHECK_OBJ_ORNULL(wrk->nobjhead, OBJHEAD_MAGIC);
1038
        }
1039 3875
        wrk->vsl = NULL;
1040 3875
        if (nxt == REQ_FSM_DONE) {
1041 3831
                AN(req->vsl->wid);
1042 3831
                VRB_Free(req);
1043 3831
                req->wrk = NULL;
1044
        }
1045 3875
        assert(nxt == REQ_FSM_DISEMBARK || req->ws->r == NULL);
1046 3875
        return (nxt);
1047
}