vinyl-cache/bin/vinyld/cache/cache_fetch.c
0
/*-
1
 * Copyright (c) 2006 Verdens Gang AS
2
 * Copyright (c) 2006-2015 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
31
#include "config.h"
32
33
#include "cache_int.h"
34
#include "cache_filter.h"
35
#include "cache_objhead.h"
36
#include "storage/storage.h"
37
#include "vcl.h"
38
#include "vtim.h"
39
#include "vcc_interface.h"
40
41
#define FETCH_STEPS \
42
        FETCH_STEP(mkbereq,           MKBEREQ) \
43
        FETCH_STEP(retry,             RETRY) \
44
        FETCH_STEP(startfetch,        STARTFETCH) \
45
        FETCH_STEP(condfetch,         CONDFETCH) \
46
        FETCH_STEP(fetch,             FETCH) \
47
        FETCH_STEP(fetchbody,         FETCHBODY) \
48
        FETCH_STEP(fetchend,          FETCHEND) \
49
        FETCH_STEP(error,             ERROR) \
50
        FETCH_STEP(fail,              FAIL) \
51
        FETCH_STEP(done,              DONE)
52
53
typedef const struct fetch_step *vbf_state_f(struct worker *, struct busyobj *);
54
55
struct fetch_step {
56
        const char      *name;
57
        vbf_state_f     *func;
58 42120
};
59 42120
60 42120
#define FETCH_STEP(l, U) \
61 42120
    static vbf_state_f vbf_stp_##l; \
62
    static const struct fetch_step F_STP_##U[1] = {{ .name = "Fetch Step " #l, .func = vbf_stp_##l, }};
63
FETCH_STEPS
64
#undef FETCH_STEP
65
66
static hdr_t const H_X_Vinyl = HDR("X-Vinyl");
67
68
static void
69 51954
init_esi_flags(struct busyobj *bo) {
70 51954
        CHECK_OBJ_NOTNULL(bo, BUSYOBJ_MAGIC);
71
#define BERESP_ESI_FLAG(lower, feature, doc) \
72
        bo->lower = FEATURE(feature);
73
#include "tbl/beresp_esi_flags.h"
74
}
75
76
/*--------------------------------------------------------------------
77
 * Allocate an object, with fall-back to Transient.
78
 * XXX: This somewhat overlaps the stuff in stevedore.c
79
 * XXX: Should this be merged over there ?
80
 */
81
82
static int
83 50694
vbf_allocobj(struct busyobj *bo, unsigned l)
84
{
85
        struct objcore *oc;
86
        const struct stevedore *stv;
87
        vtim_dur lifetime;
88
89 50694
        CHECK_OBJ_NOTNULL(bo, BUSYOBJ_MAGIC);
90 50694
        oc = bo->fetch_objcore;
91 50694
        CHECK_OBJ_NOTNULL(oc, OBJCORE_MAGIC);
92
93 50694
        lifetime = oc->ttl + oc->grace + oc->keep;
94
95 50694
        if (bo->uncacheable) {
96 22239
                stv = stv_transient;
97 22239
                bo->wrk->stats->beresp_uncacheable++;
98 22239
        }
99 28455
        else if (lifetime < cache_param->shortlived) {
100 2835
                stv = stv_transient;
101 2835
                bo->wrk->stats->beresp_shortlived++;
102 2835
        }
103
        else
104 25620
                stv = bo->storage;
105
106 50694
        bo->storage = NULL;
107
108 50694
        if (stv == NULL)
109 21
                return (0);
110
111 50673
        if (STV_NewObject(bo->wrk, oc, stv, l))
112 50505
                return (1);
113
114 168
        if (stv == stv_transient)
115 84
                return (0);
116
117
        /*
118
         * Try to salvage the transaction by allocating a shortlived object
119
         * on Transient storage.
120
         */
121
122 84
        oc->ttl = vmin_t(float, oc->ttl, cache_param->shortlived);
123 84
        oc->grace = 0.0;
124 84
        oc->keep = 0.0;
125 84
        return (STV_NewObject(bo->wrk, oc, stv_transient, l));
126 50694
}
127
128
static void
129 45927
vbf_cleanup(struct busyobj *bo)
130
{
131
        struct vfp_ctx *vfc;
132
133 45927
        CHECK_OBJ_NOTNULL(bo, BUSYOBJ_MAGIC);
134 45927
        vfc = bo->vfc;
135 45927
        CHECK_OBJ_NOTNULL(vfc, VFP_CTX_MAGIC);
136
137 45927
        bo->acct.beresp_bodybytes += VFP_Close(vfc);
138 45927
        bo->vfp_filter_list = NULL;
139
140 45927
        if (bo->director_state != DIR_S_NULL)
141 45716
                VDI_Finish(bo);
142 45927
}
143
144
void
145 210
Bereq_Rollback(VRT_CTX)
146
{
147
        struct busyobj *bo;
148
149 210
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
150 210
        bo = ctx->bo;
151 210
        CHECK_OBJ_NOTNULL(bo, BUSYOBJ_MAGIC);
152
153 231
        if (bo->htc != NULL &&
154 168
            bo->htc->body_status != BS_NONE &&
155 21
            bo->htc->body_status != BS_TAKEN)
156 21
                bo->htc->doclose = SC_RESP_CLOSE;
157
158 210
        vbf_cleanup(bo);
159 210
        VCL_TaskLeave(ctx, bo->privs);
160 210
        VCL_TaskEnter(bo->privs);
161 210
        HTTP_Clone(bo->bereq, bo->bereq0);
162 210
        bo->vfp_filter_list = NULL;
163 210
        bo->err_reason = NULL;
164 210
        AN(bo->ws_bo);
165 210
        WS_Rollback(bo->ws, bo->ws_bo);
166 210
}
167
168
/*--------------------------------------------------------------------
169
 * Turn the beresp into a obj
170
 */
171
172
static int
173 50691
vbf_beresp2obj(struct busyobj *bo)
174
{
175
        unsigned l, l2;
176
        const char *b;
177
        uint8_t *bp;
178 50691
        struct vsb *vary = NULL;
179 50691
        int varyl = 0;
180
        struct objcore *oc;
181
182 50691
        CHECK_OBJ_NOTNULL(bo, BUSYOBJ_MAGIC);
183 50691
        oc = bo->fetch_objcore;
184 50691
        CHECK_OBJ_NOTNULL(oc, OBJCORE_MAGIC);
185
186 50691
        l = 0;
187
188
        /* Create Vary instructions */
189 50691
        if (!(oc->flags & OC_F_PRIVATE)) {
190 30849
                varyl = VRY_Create(bo, &vary);
191 30849
                if (varyl > 0) {
192 4515
                        AN(vary);
193 4515
                        assert(varyl == VSB_len(vary));
194 4515
                        l += PRNDUP((intptr_t)varyl);
195 30849
                } else if (varyl < 0) {
196
                        /*
197
                         * Vary parse error
198
                         * Complain about it, and make this a pass.
199
                         */
200 105
                        VSLb(bo->vsl, SLT_Error,
201
                            "Illegal 'Vary' header from backend, "
202
                            "making this a pass.");
203 105
                        bo->uncacheable = 1;
204 105
                        AZ(vary);
205 105
                } else
206
                        /* No vary */
207 26229
                        AZ(vary);
208 30849
        }
209
210 101382
        l2 = http_EstimateWS(bo->beresp,
211 50691
            bo->uncacheable ? HTTPH_A_PASS : HTTPH_A_INS);
212 50691
        l += l2;
213
214 50691
        if (bo->uncacheable)
215 22236
                oc->flags |= OC_F_HFM;
216
217 50691
        if (!vbf_allocobj(bo, l)) {
218 126
                if (vary != NULL)
219 0
                        VSB_destroy(&vary);
220 126
                AZ(vary);
221 126
                return (VFP_Error(bo->vfc, "Could not get storage"));
222
        }
223
224 50565
        if (vary != NULL) {
225 4515
                AN(ObjSetAttr(bo->wrk, oc, OA_VARY, varyl, VSB_data(vary)));
226 4515
                VSB_destroy(&vary);
227 4515
        }
228
229 50565
        AZ(ObjSetXID(bo->wrk, oc, bo->vsl->wid));
230
231
        /* for HTTP_Encode() VSLH call */
232 50565
        bo->beresp->logtag = SLT_ObjMethod;
233
234
        /* Filter into object */
235 50565
        bp = ObjSetAttr(bo->wrk, oc, OA_HEADERS, l2, NULL);
236 50565
        AN(bp);
237 101130
        HTTP_Encode(bo->beresp, bp, l2,
238 50565
            bo->uncacheable ? HTTPH_A_PASS : HTTPH_A_INS);
239
240 50565
        if (http_GetHdr(bo->beresp, H_Last_Modified, &b))
241 903
                AZ(ObjSetDouble(bo->wrk, oc, OA_LASTMODIFIED, VTIM_parse(b)));
242
        else
243 49662
                AZ(ObjSetDouble(bo->wrk, oc, OA_LASTMODIFIED,
244
                    floor(oc->t_origin)));
245
246 50565
        return (0);
247 50691
}
248
249
/*--------------------------------------------------------------------
250
 * Copy req->bereq and release req if no body
251
 */
252
253
static const struct fetch_step * v_matchproto_(vbf_state_f)
254 51156
vbf_stp_mkbereq(struct worker *wrk, struct busyobj *bo)
255
{
256
        const char *q;
257
        struct objcore *oc;
258
259 51156
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
260 51156
        CHECK_OBJ_NOTNULL(bo, BUSYOBJ_MAGIC);
261 51156
        CHECK_OBJ_NOTNULL(bo->req, REQ_MAGIC);
262 51156
        oc = bo->fetch_objcore;
263 51156
        CHECK_OBJ_NOTNULL(oc, OBJCORE_MAGIC);
264
265 51156
        assert(oc->boc->state == BOS_INVALID);
266 51156
        AZ(bo->storage);
267
268 51156
        HTTP_Setup(bo->bereq0, bo->ws, bo->vsl, SLT_BereqMethod);
269 102312
        http_FilterReq(bo->bereq0, bo->req->http,
270 51156
            bo->uncacheable ? HTTPH_R_PASS : HTTPH_R_FETCH);
271
272 51156
        if (bo->uncacheable)
273 19824
                AZ(bo->stale_oc);
274
        else {
275 31332
                http_ForceField(bo->bereq0, HTTP_HDR_METHOD, "GET");
276 31332
                if (cache_param->http_gzip_support)
277 31227
                        http_ForceHeader(bo->bereq0, H_Accept_Encoding, "gzip");
278
        }
279 51156
        http_ForceField(bo->bereq0, HTTP_HDR_PROTO, "HTTP/1.1");
280
281 51954
        if (bo->stale_oc != NULL && !(bo->stale_oc->flags & OC_F_DYING) &&
282 3297
            ObjCheckFlag(bo->wrk, bo->stale_oc, OF_IMSCAND) &&
283 882
            (bo->stale_oc->boc != NULL || ObjGetLen(wrk, bo->stale_oc) != 0)) {
284 840
                AZ(bo->stale_oc->flags & (OC_F_HFM|OC_F_PRIVATE));
285 840
                q = RFC2616_Strong_LM(NULL, wrk, bo->stale_oc);
286 840
                if (q != NULL)
287 546
                        http_PrintfHeader(bo->bereq0,
288 273
                            "If-Modified-Since: %s", q);
289 840
                q = HTTP_GetHdrPack(bo->wrk, bo->stale_oc, H_ETag);
290 840
                if (q != NULL)
291 1176
                        http_PrintfHeader(bo->bereq0,
292 588
                            "If-None-Match: %s", q);
293 840
        }
294
295 51156
        http_CopyHome(bo->bereq0);
296 51156
        HTTP_Setup(bo->bereq, bo->ws, bo->vsl, SLT_BereqMethod);
297 51156
        bo->ws_bo = WS_Snapshot(bo->ws);
298 51156
        HTTP_Clone(bo->bereq, bo->bereq0);
299
300 51156
        if (bo->req->req_body_status->avail == 0) {
301 46306
                VBO_SetState(bo->wrk, bo, BOS_REQ_DONE);
302 51156
        } else if (bo->req->req_body_status == BS_CACHED) {
303 609
                AN(bo->req->body_oc);
304 609
                bo->bereq_body = bo->req->body_oc;
305 609
                HSH_Ref(bo->bereq_body);
306 609
                VBO_SetState(bo->wrk, bo, BOS_REQ_DONE);
307 609
        }
308 51156
        return (F_STP_STARTFETCH);
309
}
310
311
/*--------------------------------------------------------------------
312
 * Start a new VSL transaction and try again
313
 * Prepare the busyobj and fetch processors
314
 */
315
316
static const struct fetch_step * v_matchproto_(vbf_state_f)
317 819
vbf_stp_retry(struct worker *wrk, struct busyobj *bo)
318
{
319 819
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
320 819
        CHECK_OBJ_NOTNULL(bo, BUSYOBJ_MAGIC);
321
322 819
        assert(bo->fetch_objcore->boc->state <= BOS_REQ_DONE);
323
324 819
        if (bo->no_retry != NULL && bo->no_retry != retry_disabled) {
325 84
                VSLb(bo->vsl, SLT_Error,
326 42
                    "Retry not possible, %s", bo->no_retry);
327 42
                return (F_STP_FAIL);
328
        }
329
330 777
        VSLb_ts_busyobj(bo, "Retry", W_TIM_real(wrk));
331
332
        /* VDI_Finish (via vbf_cleanup) must have been called before */
333 777
        assert(bo->director_state == DIR_S_NULL);
334
335
        /* reset other bo attributes - See VBO_GetBusyObj */
336 777
        bo->storage = NULL;
337 777
        bo->do_esi = 0;
338 777
        bo->do_stream = 1;
339 777
        bo->was_304 = 0;
340 777
        bo->err_code = 0;
341 777
        bo->err_reason = NULL;
342 777
        bo->connect_timeout = NAN;
343 777
        bo->first_byte_timeout = NAN;
344 777
        bo->between_bytes_timeout = NAN;
345 777
        if (bo->htc != NULL)
346 0
                bo->htc->doclose = SC_NULL;
347 777
        init_esi_flags(bo);
348
349
        // XXX: BereqEnd + BereqAcct ?
350 777
        VSL_ChgId(bo->vsl, "bereq", "retry", VXID_Get(wrk, VSL_BACKENDMARKER));
351 777
        VSLb_ts_busyobj(bo, "Start", bo->t_prev);
352 777
        http_VSL_log(bo->bereq);
353
354 777
        return (F_STP_STARTFETCH);
355 819
}
356
357
/*--------------------------------------------------------------------
358
 * 304 setup logic
359
 */
360
361
static void
362 672
vbf_304_logic(struct busyobj *bo)
363
{
364
365 672
        AZ(bo->stale_oc->flags & (OC_F_HFM|OC_F_PRIVATE));
366 672
        if (ObjCheckFlag(bo->wrk, bo->stale_oc, OF_CHGCE)) {
367
                /*
368
                 * If a VFP changed C-E in the stored
369
                 * object, then don't overwrite C-E from
370
                 * the IMS fetch, and we must weaken any
371
                 * new ETag we get.
372
                 */
373 42
                RFC2616_Weaken_Etag(bo->beresp);
374 42
        }
375 672
        http_Unset(bo->beresp, H_Content_Encoding);
376 672
        http_Unset(bo->beresp, H_Content_Length);
377 672
        HTTP_Merge(bo->wrk, bo->stale_oc, bo->beresp);
378 672
}
379
380
/*--------------------------------------------------------------------
381
 * Setup bereq from bereq0, run vcl_backend_fetch
382
 */
383
384
static const struct fetch_step * v_matchproto_(vbf_state_f)
385 51931
vbf_stp_startfetch(struct worker *wrk, struct busyobj *bo)
386
{
387
        int i;
388
        const char *q;
389
        vtim_real now;
390 51931
        unsigned handling, skip_vbr = 0;
391
        struct objcore *oc;
392
393 51931
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
394 51931
        CHECK_OBJ_NOTNULL(bo, BUSYOBJ_MAGIC);
395 51931
        oc = bo->fetch_objcore;
396 51931
        CHECK_OBJ_NOTNULL(oc, OBJCORE_MAGIC);
397
398
        // this complements the stale_oc handling in vbf_stp_mkbereq():
399
        // Conditions might have changed since we made the bereq (retry)
400 51931
        if (! bo->uncacheable && bo->stale_oc != NULL &&
401 3360
            bo->stale_oc->flags & OC_F_DYING) {
402 42
                http_Unset(bo->bereq, H_If_Modified_Since);
403 42
                http_Unset(bo->bereq, H_If_None_Match);
404 42
        }
405
406 51931
        AZ(bo->storage);
407 51931
        bo->storage = bo->uncacheable ? stv_transient : STV_next();
408
409 51931
        if (bo->retries > 0)
410 777
                http_Unset(bo->bereq, H_X_Vinyl);
411
412 51931
        http_PrintfHeader(bo->bereq, "X-Vinyl: %ju", VXID(bo->vsl->wid));
413
414 51931
        if (bo->bereq_body == NULL && bo->req == NULL) {
415 47079
                if (http_method_among(bo->bereq->wkm, (WKM_GET | WKM_HEAD | WKM_DELETE |
416
                    WKM_OPTIONS | WKM_TRACE)))
417 46659
                        http_Unset(bo->bereq, H_Content_Length);
418
                else
419 420
                        http_ForceHeader(bo->bereq, H_Content_Length, "0");
420 47079
        }
421
422 51931
        VCL_backend_fetch_method(bo->vcl, wrk, NULL, bo, NULL);
423
424 51931
        if (wrk->vpi->handling == VCL_RET_ABANDON ||
425 51868
            wrk->vpi->handling == VCL_RET_FAIL)
426 143
                return (F_STP_FAIL);
427
428 51788
        assert (wrk->vpi->handling == VCL_RET_FETCH ||
429
            wrk->vpi->handling == VCL_RET_ERROR);
430
431 51788
        HTTP_Setup(bo->beresp, bo->ws, bo->vsl, SLT_BerespMethod);
432
433 51788
        assert(oc->boc->state <= BOS_REQ_DONE);
434
435 51788
        AZ(bo->htc);
436
437 51788
        VFP_Setup(bo->vfc, wrk);
438 51788
        bo->vfc->oc = oc;
439 51788
        bo->vfc->resp = bo->beresp;
440 51788
        bo->vfc->req = bo->bereq;
441
442 51788
        if (wrk->vpi->handling == VCL_RET_ERROR)
443 273
                return (F_STP_ERROR);
444
445 51515
        VSLb_ts_busyobj(bo, "Fetch", W_TIM_real(wrk));
446 51515
        i = VDI_GetHdr(bo);
447 51515
        if (bo->htc != NULL)
448 45736
                CHECK_OBJ_NOTNULL(bo->htc->doclose, STREAM_CLOSE_MAGIC);
449
450 51515
        bo->t_resp = now = W_TIM_real(wrk);
451 51515
        VSLb_ts_busyobj(bo, "Beresp", now);
452
453 51515
        if (i) {
454 5753
                assert(bo->director_state == DIR_S_NULL);
455 5753
                return (F_STP_ERROR);
456
        }
457
458 45762
        if (bo->htc != NULL && bo->htc->body_status == BS_ERROR) {
459 42
                bo->htc->doclose = SC_RX_BODY;
460 42
                vbf_cleanup(bo);
461 42
                VSLb(bo->vsl, SLT_Error, "Body cannot be fetched");
462 42
                assert(bo->director_state == DIR_S_NULL);
463 42
                return (F_STP_ERROR);
464
        }
465
466 45720
        if (!http_GetHdr(bo->beresp, H_Date, NULL)) {
467
                /*
468
                 * RFC 2616 14.18 Date: The Date general-header field
469
                 * represents the date and time at which the message was
470
                 * originated, having the same semantics as orig-date in
471
                 * RFC 822. ... A received message that does not have a
472
                 * Date header field MUST be assigned one by the recipient
473
                 * if the message will be cached by that recipient or
474
                 * gatewayed via a protocol which requires a Date.
475
                 *
476
                 * If we didn't get a Date header, we assign one here.
477
                 */
478 1848
                http_TimeHeader(bo->beresp, "Date: ", now);
479 1848
        }
480
481
        /*
482
         * These two headers can be spread over multiple actual headers
483
         * and we rely on their content outside of VCL, so collect them
484
         * into one line here.
485
         */
486 45720
        http_CollectHdr(bo->beresp, H_Cache_Control);
487 45720
        http_CollectHdr(bo->beresp, H_Vary);
488
489
        /* What does RFC2616 think about TTL ? */
490 91440
        RFC2616_Ttl(bo, now,
491 45720
            &oc->t_origin,
492 45720
            &oc->ttl,
493 45720
            &oc->grace,
494 45720
            &oc->keep);
495
496 45720
        AZ(bo->do_esi);
497 45720
        AZ(bo->was_304);
498
499 45720
        if (http_IsStatus(bo->beresp, 304) && !bo->uncacheable) {
500 861
                if (bo->stale_oc == NULL){
501 0
                        VSLb(bo->vsl, SLT_Error,
502
                            "304 response but not conditional fetch");
503 0
                        bo->htc->doclose = SC_RX_BAD;
504 0
                        vbf_cleanup(bo);
505 0
                        return (F_STP_ERROR);
506
                }
507 861
                bo->was_304 = 1;
508 861
                VCL_backend_refresh_method(bo->vcl, wrk, NULL, bo, NULL);
509 861
                switch (wrk->vpi->handling) {
510
                case VCL_RET_MERGE:
511 672
                        vbf_304_logic(bo);
512 672
                        break;
513
                case VCL_RET_BERESP:
514 42
                        http_SetStatus(bo->beresp, 200, NULL);
515 42
                        http_Unset(bo->beresp, H_Content_Length);
516 42
                        http_Unset(bo->beresp, H_Content_Encoding);
517 84
                        q = HTTP_GetHdrPack(wrk, bo->stale_oc,
518 42
                            H_Content_Length);
519 42
                        if (q != NULL) {
520 42
                                http_ForceHeader(bo->beresp,
521 21
                                    H_Content_Length, q);
522 21
                        }
523 84
                        q = HTTP_GetHdrPack(wrk, bo->stale_oc,
524 42
                            H_Content_Encoding);
525 42
                        if (q != NULL) {
526 0
                                http_ForceHeader(bo->beresp,
527 0
                                    H_Content_Encoding, q);
528 0
                        }
529 84
                        q = HTTP_GetHdrPack(wrk, bo->stale_oc,
530 42
                            H_Last_Modified);
531 42
                        if (q != NULL) {
532 0
                                http_ForceHeader(bo->beresp,
533 0
                                    H_Last_Modified, q);
534 0
                        }
535 42
                        q = HTTP_GetHdrPack(wrk, bo->stale_oc, H_ETag);
536 42
                        if (q != NULL)
537 42
                                http_ForceHeader(bo->beresp, H_ETag, q);
538 42
                        break;
539
                case VCL_RET_OBJ_STALE:
540 42
                        if (HTTP_Decode(bo->beresp, ObjGetAttr(bo->wrk,
541 21
                                bo->stale_oc, OA_HEADERS, NULL))) {
542 0
                                bo->htc->doclose = SC_RX_OVERFLOW;
543 0
                                vbf_cleanup(bo);
544 0
                                return (F_STP_ERROR);
545
                        }
546 21
                        break;
547
                case VCL_RET_RETRY:
548
                case VCL_RET_ERROR:
549
                case VCL_RET_ABANDON:
550
                case VCL_RET_FAIL:
551 126
                        skip_vbr = 1;
552 126
                        break;
553
                default:
554 0
                        WRONG("Illegal return from vcl_backend_refresh{}");
555 0
                }
556 861
        }
557
558 45720
        if (bo->htc != NULL && bo->htc->doclose == SC_NULL &&
559 43568
            http_GetHdrField(bo->bereq, H_Connection, "close", NULL))
560 273
                bo->htc->doclose = SC_REQ_CLOSE;
561 45720
        if (!skip_vbr)
562 45570
                VCL_backend_response_method(bo->vcl, wrk, NULL, bo, NULL);
563
564 45672
        if (bo->htc != NULL && bo->htc->doclose == SC_NULL &&
565 43106
            http_GetHdrField(bo->beresp, H_Connection, "close", NULL))
566 21
                bo->htc->doclose = SC_RESP_CLOSE;
567
568 45672
        if (VRG_CheckBo(bo) < 0) {
569
                /* the body is never read, so we cannot reuse it */
570 168
                if (bo->htc != NULL && bo->htc->body_status != BS_NONE)
571 147
                        bo->htc->doclose = SC_RX_BAD;
572 168
                vbf_cleanup(bo);
573 168
                return (F_STP_ERROR);
574
        }
575
576 90885
        if (wrk->vpi->handling == VCL_RET_ABANDON ||
577 45423
            wrk->vpi->handling == VCL_RET_FAIL ||
578 45381
            wrk->vpi->handling == VCL_RET_ERROR) {
579
                /* do not count deliberately ending the backend connection as
580
                 * fetch failure
581
                 */
582 336
                handling = wrk->vpi->handling;
583 336
                if (bo->htc)
584 336
                        bo->htc->doclose = SC_RESP_CLOSE;
585 336
                vbf_cleanup(bo);
586 336
                wrk->vpi->handling = handling;
587
588 336
                if (wrk->vpi->handling == VCL_RET_ERROR)
589 210
                        return (F_STP_ERROR);
590
                else
591 126
                        return (F_STP_FAIL);
592
        }
593
594 45168
        if (wrk->vpi->handling == VCL_RET_RETRY) {
595 609
                if (bo->htc && bo->htc->body_status != BS_NONE)
596 147
                        bo->htc->doclose = SC_RESP_CLOSE;
597 609
                vbf_cleanup(bo);
598
599 609
                if (bo->retries++ < bo->max_retries)
600 567
                        return (F_STP_RETRY);
601
602 42
                VSLb(bo->vsl, SLT_VCL_Error,
603
                    "Too many retries, delivering 503");
604 42
                assert(bo->director_state == DIR_S_NULL);
605 42
                return (F_STP_ERROR);
606
        }
607
608 44559
        VSLb_ts_busyobj(bo, "Process", W_TIM_real(wrk));
609 44559
        assert(oc->boc->state <= BOS_REQ_DONE);
610 44559
        if (oc->boc->state != BOS_REQ_DONE)
611 3612
                VBO_SetState(wrk, bo, BOS_REQ_DONE);
612
613 44559
        if (bo->do_esi)
614 6594
                bo->do_stream = 0;
615 44559
        if (wrk->vpi->handling == VCL_RET_PASS) {
616 630
                oc->flags |= OC_F_HFP;
617 630
                bo->uncacheable = 1;
618 630
                wrk->vpi->handling = VCL_RET_DELIVER;
619 630
        }
620 44559
        if (!bo->uncacheable || !bo->do_stream)
621 28371
                oc->boc->transit_buffer = 0;
622 44559
        if (bo->uncacheable)
623 19170
                oc->flags |= OC_F_HFM;
624
625 44559
        assert(wrk->vpi->handling == VCL_RET_DELIVER);
626
627 44559
        return (bo->was_304 ? F_STP_CONDFETCH : F_STP_FETCH);
628 51883
}
629
630
/*--------------------------------------------------------------------
631
 */
632
633
static const struct fetch_step * v_matchproto_(vbf_state_f)
634 24551
vbf_stp_fetchbody(struct worker *wrk, struct busyobj *bo)
635
{
636
        ssize_t l;
637
        uint8_t *ptr;
638 24551
        enum vfp_status vfps = VFP_ERROR;
639
        ssize_t est;
640
        struct vfp_ctx *vfc;
641
        struct objcore *oc;
642
643 24551
        CHECK_OBJ_NOTNULL(bo, BUSYOBJ_MAGIC);
644 24551
        vfc = bo->vfc;
645 24551
        CHECK_OBJ_NOTNULL(vfc, VFP_CTX_MAGIC);
646 24551
        oc = bo->fetch_objcore;
647 24551
        CHECK_OBJ_NOTNULL(oc, OBJCORE_MAGIC);
648
649 24551
        AN(vfc->vfp_nxt);
650
651 24551
        est = bo->htc->content_length;
652 24551
        if (est < 0)
653 3255
                est = 0;
654
655 24551
        do {
656 1216549
                if (oc->flags & OC_F_CANCEL) {
657
                        /*
658
                         * A pass object and delivery was terminated
659
                         * We don't fail the fetch, in order for HitMiss
660
                         * objects to be created.
661
                         */
662 21
                        AN(oc->flags & OC_F_HFM);
663 21
                        VSLb(wrk->vsl, SLT_Debug,
664
                            "Fetch: Pass delivery abandoned");
665 21
                        bo->htc->doclose = SC_RX_BODY;
666 21
                        break;
667
                }
668 1216528
                AZ(vfc->failed);
669 1216528
                l = est;
670 1216528
                assert(l >= 0);
671 1216528
                if (VFP_GetStorage(vfc, &l, &ptr) != VFP_OK) {
672 105
                        bo->htc->doclose = SC_RX_BODY;
673 105
                        break;
674
                }
675
676 1216423
                AZ(vfc->failed);
677 1216423
                vfps = VFP_Suck(vfc, ptr, &l);
678 1216423
                if (l >= 0 && vfps != VFP_ERROR) {
679 1215537
                        VFP_Extend(vfc, l, vfps);
680 1215537
                        if (est >= l)
681 57859
                                est -= l;
682
                        else
683 1157678
                                est = 0;
684 1215537
                }
685 1216423
        } while (vfps == VFP_OK);
686
687 24399
        if (vfc->failed) {
688 840
                (void)VFP_Error(vfc, "Fetch pipeline failed to process");
689 840
                bo->htc->doclose = SC_RX_BODY;
690 840
                vbf_cleanup(bo);
691 840
                if (!bo->do_stream) {
692 483
                        assert(oc->boc->state < BOS_STREAM);
693
                        // XXX: doclose = ?
694 483
                        return (F_STP_ERROR);
695
                } else {
696 357
                        wrk->stats->fetch_failed++;
697 357
                        return (F_STP_FAIL);
698
                }
699
        }
700
701 23559
        return (F_STP_FETCHEND);
702 24399
}
703
704
static const struct fetch_step * v_matchproto_(vbf_state_f)
705 43847
vbf_stp_fetch(struct worker *wrk, struct busyobj *bo)
706
{
707
        struct vrt_ctx ctx[1];
708
        struct objcore *oc;
709
710 43847
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
711 43847
        CHECK_OBJ_NOTNULL(bo, BUSYOBJ_MAGIC);
712 43847
        oc = bo->fetch_objcore;
713 43847
        CHECK_OBJ_NOTNULL(oc, OBJCORE_MAGIC);
714
715 43847
        assert(wrk->vpi->handling == VCL_RET_DELIVER);
716
717 43847
        if (bo->htc == NULL) {
718 42
                (void)VFP_Error(bo->vfc, "No backend connection (rollback?)");
719 42
                vbf_cleanup(bo);
720 42
                return (F_STP_ERROR);
721
        }
722
723
        /* No body -> done */
724 43805
        if (bo->htc->body_status == BS_NONE || bo->htc->content_length == 0) {
725 17766
                http_Unset(bo->beresp, H_Content_Encoding);
726 17766
                bo->do_gzip = bo->do_gunzip = 0;
727 17766
                bo->do_stream = 0;
728 17766
                bo->vfp_filter_list = "";
729 43805
        } else if (bo->vfp_filter_list == NULL) {
730 25913
                bo->vfp_filter_list = VBF_Get_Filter_List(bo);
731 25913
        }
732
733 43805
        if (bo->vfp_filter_list == NULL ||
734 43805
            VCL_StackVFP(bo->vfc, bo->vcl, bo->vfp_filter_list)) {
735 509
                (bo)->htc->doclose = SC_OVERLOAD;
736 509
                vbf_cleanup(bo);
737 509
                return (F_STP_ERROR);
738
        }
739
740 43296
        if (oc->flags & OC_F_PRIVATE)
741 16463
                AN(bo->uncacheable);
742
743 43296
        oc->boc->fetched_so_far = 0;
744
745 43296
        INIT_OBJ(ctx, VRT_CTX_MAGIC);
746 43296
        VCL_Bo2Ctx(ctx, bo);
747
748 43296
        if (VFP_Open(ctx, bo->vfc)) {
749 1113
                (void)VFP_Error(bo->vfc, "Fetch pipeline failed to open");
750 1113
                bo->htc->doclose = SC_RX_BODY;
751 1113
                vbf_cleanup(bo);
752 1113
                return (F_STP_ERROR);
753
        }
754
755 42183
        if (vbf_beresp2obj(bo)) {
756 63
                bo->htc->doclose = SC_RX_BODY;
757 63
                vbf_cleanup(bo);
758 63
                return (F_STP_ERROR);
759
        }
760
761
#define OBJ_FLAG(U, l, v)                                               \
762
        if (bo->vfc->obj_flags & OF_##U)                                \
763
                ObjSetFlag(bo->wrk, oc, OF_##U, 1);
764
#include "tbl/obj_attr.h"
765
766 42120
        if (!(oc->flags & OC_F_HFM) &&
767 24507
            http_IsStatus(bo->beresp, 200) && (
768 24087
              RFC2616_Strong_LM(bo->beresp, NULL, NULL) != NULL ||
769 23583
              http_GetHdr(bo->beresp, H_ETag, NULL)))
770 1281
                ObjSetFlag(bo->wrk, oc, OF_IMSCAND, 1);
771
772 42120
        assert(oc->boc->refcount >= 1);
773
774 42120
        assert(oc->boc->state == BOS_REQ_DONE);
775
776 42120
        if (bo->do_stream)
777 18227
                VBO_SetState(wrk, bo, BOS_STREAM);
778
779
        VSLb(bo->vsl, SLT_Fetch_Body, "%u %s %s",
780
            bo->htc->body_status->nbr, bo->htc->body_status->name,
781
            bo->do_stream ? "stream" : "-");
782
783 42120
        if (bo->htc->body_status != BS_NONE) {
784 24396
                assert(bo->htc->body_status != BS_ERROR);
785 24396
                return (F_STP_FETCHBODY);
786
        }
787 17724
        AZ(bo->vfc->failed);
788
        return (F_STP_FETCHEND);
789
}
790
791
static const struct fetch_step * v_matchproto_(vbf_state_f)
792 41914
vbf_stp_fetchend(struct worker *wrk, struct busyobj *bo)
793
{
794
795
        struct objcore *oc;
796
797 41914
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
798 41914
        CHECK_OBJ_NOTNULL(bo, BUSYOBJ_MAGIC);
799 41914
        oc = bo->fetch_objcore;
800 41914
        CHECK_OBJ_NOTNULL(oc, OBJCORE_MAGIC);
801
802 41914
        AZ(bo->vfc->failed);
803
804
        /* Recycle the backend connection before setting BOS_FINISHED to
805
           give predictable backend reuse behavior for vinyltest */
806 41914
        vbf_cleanup(bo);
807
808 41914
        AZ(ObjSetU64(wrk, oc, OA_LEN, oc->boc->fetched_so_far));
809
810 41914
        if (bo->do_stream)
811 18478
                assert(oc->boc->state == BOS_STREAM);
812
        else
813 23436
                assert(oc->boc->state == BOS_REQ_DONE);
814
815 41914
        VBO_SetState(wrk, bo, BOS_FINISHED);
816 41914
        VSLb_ts_busyobj(bo, "BerespBody", W_TIM_real(wrk));
817 41914
        if (bo->stale_oc != NULL) {
818 3360
                VSL(SLT_ExpKill, NO_VXID, "VBF_Superseded x=%ju n=%ju",
819 1680
                    VXID(ObjGetXID(wrk, bo->stale_oc)),
820 1680
                    VXID(ObjGetXID(wrk, bo->fetch_objcore)));
821 1680
                HSH_Replace(bo->stale_oc, bo->fetch_objcore);
822 1680
        }
823 41914
        return (F_STP_DONE);
824
}
825
826
/*--------------------------------------------------------------------
827
 */
828
829
struct vbf_objiter_priv {
830
        unsigned                magic;
831
#define VBF_OBITER_PRIV_MAGIC   0x3c272a17
832
        struct vfp_ctx          *vfc;
833
        // not yet allocated
834
        ssize_t         l;
835
        // current allocation
836
        uint8_t         *p;
837
        ssize_t         pl;
838
};
839
840
static int v_matchproto_(objiterate_f)
841 714
vbf_objiterate(void *priv, unsigned flush, const void *ptr, ssize_t len)
842
{
843
        struct vbf_objiter_priv *vop;
844
        ssize_t l;
845 714
        const uint8_t *ps = ptr;
846
847 714
        CAST_OBJ_NOTNULL(vop, priv, VBF_OBITER_PRIV_MAGIC);
848 714
        CHECK_OBJ_NOTNULL(vop->vfc, VFP_CTX_MAGIC);
849
850 714
        flush &= OBJ_ITER_END;
851
852 1407
        while (len > 0) {
853 714
                if (vop->pl == 0) {
854 693
                        vop->p = NULL;
855 693
                        AN(vop->l);
856 693
                        vop->pl = vop->l;
857 1386
                        if (VFP_GetStorage(vop->vfc, &vop->pl, &vop->p)
858 693
                            != VFP_OK)
859 21
                                return (1);
860 672
                        if (vop->pl < vop->l)
861 42
                                vop->l -= vop->pl;
862
                        else
863 630
                                vop->l = 0;
864 672
                }
865 693
                AN(vop->pl);
866 693
                AN(vop->p);
867
868 693
                l = vmin(vop->pl, len);
869 693
                vmemcpy(vop->p, ps, l);
870 1323
                VFP_Extend(vop->vfc, l,
871 693
                           flush && l == len ? VFP_END : VFP_OK);
872 693
                ps += l;
873 693
                vop->p += l;
874 693
                len -= l;
875 693
                vop->pl -= l;
876
        }
877 693
        if (flush && vop->vfc->failed == 0)
878 630
                AZ(vop->l);
879 693
        return (0);
880 714
}
881
882
// Fetch oc into vfc->oc
883
// soon to be exported
884
static enum vfp_status
885 651
VBF_Obj(struct worker *wrk, struct objcore *oc, struct vfp_ctx *vfc)
886
{
887
        struct vbf_objiter_priv vop[1];
888
889 651
        INIT_OBJ(vop, VBF_OBITER_PRIV_MAGIC);
890 651
        vop->vfc = vfc;
891 651
        vop->l = ObjGetLen(wrk, oc);
892 651
        if (ObjIterate(wrk, oc, vop, vbf_objiterate, 0))
893 21
                return (VFP_Error(vfc, "Template object failed"));
894 630
        return (VFP_OK);
895 651
}
896
897
static const struct fetch_step * v_matchproto_(vbf_state_f)
898 714
vbf_stp_condfetch(struct worker *wrk, struct busyobj *bo)
899
{
900
        struct boc *stale_boc;
901
        enum boc_state_e stale_state;
902
        struct objcore *oc, *stale_oc;
903
904 714
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
905 714
        CHECK_OBJ_NOTNULL(bo, BUSYOBJ_MAGIC);
906 714
        oc = bo->fetch_objcore;
907 714
        CHECK_OBJ_NOTNULL(oc, OBJCORE_MAGIC);
908 714
        stale_oc = bo->stale_oc;
909 714
        CHECK_OBJ_NOTNULL(stale_oc, OBJCORE_MAGIC);
910
911 714
        stale_boc = HSH_RefBoc(stale_oc);
912 714
        CHECK_OBJ_ORNULL(stale_boc, BOC_MAGIC);
913 714
        if (stale_boc) {
914
                /* Wait for the stale object to become fully fetched, so
915
                 * that we can catch fetch errors, before we unbusy the
916
                 * new object. This serves two purposes. First it helps
917
                 * with request coalescing, and stops long chains of
918
                 * IMS-updated short-TTL objects all streaming from a
919
                 * single slow body fetch. Second it makes sure that all
920
                 * the object attributes are complete when we copy them
921
                 * (this would be an issue for ie OA_GZIPBITS). */
922 84
                VSLb(bo->vsl, SLT_Notice,
923
                    "vsl: Conditional fetch wait for streaming object");
924
                /* XXX: We should have a VCL controlled timeout here */
925 84
                stale_state = ObjWaitState(stale_oc, BOS_FINISHED);
926 84
                HSH_DerefBoc(bo->wrk, stale_oc);
927 84
                stale_boc = NULL;
928 84
                if (stale_state != BOS_FINISHED) {
929 42
                        assert(stale_state == BOS_FAILED);
930 42
                        AN(stale_oc->flags & OC_F_FAILED);
931 42
                }
932 84
        }
933
934 714
        AZ(stale_boc);
935 714
        if (stale_oc->flags & OC_F_FAILED) {
936 42
                (void)VFP_Error(bo->vfc, "Template object failed");
937 42
                vbf_cleanup(bo);
938 42
                wrk->stats->fetch_failed++;
939 42
                return (F_STP_FAIL);
940
        }
941
942 672
        if (vbf_beresp2obj(bo)) {
943 21
                vbf_cleanup(bo);
944 21
                wrk->stats->fetch_failed++;
945 21
                return (F_STP_FAIL);
946
        }
947
948 651
        if (ObjHasAttr(bo->wrk, stale_oc, OA_ESIDATA))
949 21
                AZ(ObjCopyAttr(bo->wrk, oc, stale_oc, OA_ESIDATA));
950
951 651
        AZ(ObjCopyAttr(bo->wrk, oc, stale_oc, OA_FLAGS));
952 651
        if (oc->flags & OC_F_HFM)
953 42
                ObjSetFlag(bo->wrk, oc, OF_IMSCAND, 0);
954 651
        AZ(ObjCopyAttr(bo->wrk, oc, stale_oc, OA_GZIPBITS));
955
956 651
        if (bo->do_stream)
957 630
                VBO_SetState(wrk, bo, BOS_STREAM);
958
959 651
        (void)VBF_Obj(wrk, stale_oc, bo->vfc);
960
961 651
        if (bo->vfc->failed) {
962 21
                vbf_cleanup(bo);
963 21
                wrk->stats->fetch_failed++;
964 21
                return (F_STP_FAIL);
965
        }
966 630
        return (F_STP_FETCHEND);
967 714
}
968
969
/*--------------------------------------------------------------------
970
 * Create synth object
971
 *
972
 * replaces a stale object unless
973
 * - abandoning the bereq or
974
 * - leaving vcl_backend_error with return (deliver)
975
 *
976
 * We do want the stale replacement to avoid an object pileup with short ttl and
977
 * long grace/keep, yet there could exist cases where a cache object is
978
 * deliberately created to momentarily override a stale object.
979
 *
980
 * If this case exists, we should add a vcl veto (e.g. beresp.replace_stale with
981
 * default true)
982
 */
983
984
static const struct fetch_step * v_matchproto_(vbf_state_f)
985 8693
vbf_stp_error(struct worker *wrk, struct busyobj *bo)
986
{
987
        ssize_t l, ll, o;
988
        vtim_real now;
989
        uint8_t *ptr;
990
        struct vsb *synth_body;
991
        struct objcore *stale, *oc;
992
993 8693
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
994 8693
        CHECK_OBJ_NOTNULL(bo, BUSYOBJ_MAGIC);
995 8693
        oc = bo->fetch_objcore;
996 8693
        CHECK_OBJ_NOTNULL(oc, OBJCORE_MAGIC);
997 8693
        CHECK_OBJ_NOTNULL(oc->boc, BOC_MAGIC);
998 8693
        assert(oc->boc->state < BOS_STREAM);
999 8693
        assert(bo->director_state == DIR_S_NULL);
1000
1001 8693
        if (wrk->vpi->handling != VCL_RET_ERROR)
1002 8211
                wrk->stats->fetch_failed++;
1003
1004 8693
        now = W_TIM_real(wrk);
1005 8693
        VSLb_ts_busyobj(bo, "Error", now);
1006
1007 8693
        if (oc->stobj->stevedore != NULL) {
1008
                // replacing an already fetched object with a "synth" one
1009 483
                assert(oc->boc->state < BOS_STREAM);
1010 483
                oc->boc->fetched_so_far = 0;
1011 483
                ObjFreeObj(bo->wrk, oc);
1012 483
        }
1013
1014 8693
        if (bo->storage == NULL)
1015 546
                bo->storage = STV_next();
1016
1017
        // XXX: reset all beresp flags ?
1018
1019 8693
        HTTP_Setup(bo->beresp, bo->ws, bo->vsl, SLT_BerespMethod);
1020 8693
        if (bo->err_code > 0)
1021 1470
                http_PutResponse(bo->beresp, "HTTP/1.1", bo->err_code,
1022 735
                    bo->err_reason);
1023
        else
1024 7958
                http_PutResponse(bo->beresp, "HTTP/1.1", 503,
1025
                    "Backend fetch failed");
1026
1027 8693
        http_TimeHeader(bo->beresp, "Date: ", now);
1028 8693
        http_SetHeader(bo->beresp, "Server: Vinyl-Cache");
1029
1030 8693
        stale = bo->stale_oc;
1031 8693
        oc->t_origin = now;
1032 8693
        oc->ttl = 0;
1033 8693
        oc->grace = 0;
1034 8693
        oc->keep = 0;
1035
1036 8693
        synth_body = VSB_new_auto();
1037 8693
        AN(synth_body);
1038
1039 8693
        VCL_backend_error_method(bo->vcl, wrk, NULL, bo, synth_body);
1040
1041 8693
        AZ(VSB_finish(synth_body));
1042
1043 8693
        if (wrk->vpi->handling == VCL_RET_ABANDON || wrk->vpi->handling == VCL_RET_FAIL) {
1044 587
                VSB_destroy(&synth_body);
1045 587
                return (F_STP_FAIL);
1046
        }
1047
1048 8106
        if (wrk->vpi->handling == VCL_RET_RETRY) {
1049 273
                VSB_destroy(&synth_body);
1050 273
                if (bo->retries++ < bo->max_retries)
1051 252
                        return (F_STP_RETRY);
1052 21
                VSLb(bo->vsl, SLT_VCL_Error, "Too many retries, failing");
1053 21
                return (F_STP_FAIL);
1054
        }
1055
1056 7833
        assert(wrk->vpi->handling == VCL_RET_DELIVER);
1057
1058 7833
        assert(bo->vfc->wrk == bo->wrk);
1059 7833
        assert(bo->vfc->oc == oc);
1060 7833
        assert(bo->vfc->resp == bo->beresp);
1061 7833
        assert(bo->vfc->req == bo->bereq);
1062
1063 7833
        if (vbf_beresp2obj(bo)) {
1064 42
                VSB_destroy(&synth_body);
1065 42
                return (F_STP_FAIL);
1066
        }
1067
1068 7791
        oc->boc->transit_buffer = 0;
1069
1070 7791
        ll = VSB_len(synth_body);
1071 7791
        o = 0;
1072 14574
        while (ll > 0) {
1073 6804
                l = ll;
1074 6804
                if (VFP_GetStorage(bo->vfc, &l, &ptr) != VFP_OK) {
1075 21
                        VSB_destroy(&synth_body);
1076 21
                        return (F_STP_FAIL);
1077
                }
1078 6783
                l = vmin(l, ll);
1079 6783
                vmemcpy(ptr, VSB_data(synth_body) + o, l);
1080 6783
                VFP_Extend(bo->vfc, l, l == ll ? VFP_END : VFP_OK);
1081 6783
                ll -= l;
1082 6783
                o += l;
1083
        }
1084 7770
        assert(o == VSB_len(synth_body));
1085 7770
        AZ(ObjSetU64(wrk, oc, OA_LEN, o));
1086 7770
        VSB_destroy(&synth_body);
1087 7770
        if (stale != NULL && oc->ttl > 0)
1088 462
                HSH_Kill(stale);
1089 7770
        VBO_SetState(wrk, bo, BOS_FINISHED);
1090 7770
        return (F_STP_DONE);
1091 8693
}
1092
1093
/*--------------------------------------------------------------------
1094
 */
1095
1096
static const struct fetch_step * v_matchproto_(vbf_state_f)
1097 1470
vbf_stp_fail(struct worker *wrk, struct busyobj *bo)
1098
{
1099
        struct objcore *oc;
1100
1101 1470
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
1102 1470
        CHECK_OBJ_NOTNULL(bo, BUSYOBJ_MAGIC);
1103 1470
        oc = bo->fetch_objcore;
1104 1470
        CHECK_OBJ_NOTNULL(oc, OBJCORE_MAGIC);
1105
1106 1470
        assert(oc->boc->state < BOS_FINISHED);
1107 1470
        VBO_SetState(wrk, bo, BOS_FAILED);
1108 1470
        HSH_Kill(oc);
1109 1470
        return (F_STP_DONE);
1110
}
1111
1112
/*--------------------------------------------------------------------
1113
 */
1114
1115
static const struct fetch_step * v_matchproto_(vbf_state_f)
1116 0
vbf_stp_done(struct worker *wrk, struct busyobj *bo)
1117
{
1118
1119 0
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
1120 0
        CHECK_OBJ_NOTNULL(bo, BUSYOBJ_MAGIC);
1121 0
        WRONG("Just plain wrong");
1122 0
        NEEDLESS(return (F_STP_DONE));
1123
}
1124
1125
static void v_matchproto_(task_func_t)
1126 51156
vbf_fetch_thread(struct worker *wrk, void *priv)
1127
{
1128
        struct vrt_ctx ctx[1];
1129
        struct busyobj *bo;
1130
        struct objcore *oc;
1131
        const struct fetch_step *stp;
1132
1133 51156
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
1134 51156
        CAST_OBJ_NOTNULL(bo, priv, BUSYOBJ_MAGIC);
1135 51156
        CHECK_OBJ_NOTNULL(bo->req, REQ_MAGIC);
1136 51156
        oc = bo->fetch_objcore;
1137 51156
        CHECK_OBJ_NOTNULL(oc, OBJCORE_MAGIC);
1138
1139 51156
        THR_SetBusyobj(bo);
1140 51156
        stp = F_STP_MKBEREQ;
1141 51156
        assert(isnan(bo->t_first));
1142 51156
        assert(isnan(bo->t_prev));
1143 51156
        VSLb_ts_busyobj(bo, "Start", W_TIM_real(wrk));
1144
1145 51156
        bo->wrk = wrk;
1146 51156
        wrk->vsl = bo->vsl;
1147
1148
#if 0
1149
        if (bo->stale_oc != NULL) {
1150
                CHECK_OBJ_NOTNULL(bo->stale_oc, OBJCORE_MAGIC);
1151
                /* We don't want the oc/stevedore ops in fetching thread */
1152
                if (!ObjCheckFlag(wrk, bo->stale_oc, OF_IMSCAND))
1153
                        (void)HSH_DerefObjCore(wrk, &bo->stale_oc, 0);
1154
        }
1155
#endif
1156
1157 51156
        VCL_TaskEnter(bo->privs);
1158 276064
        while (stp != F_STP_DONE) {
1159 224908
                CHECK_OBJ_NOTNULL(bo, BUSYOBJ_MAGIC);
1160 224908
                assert(oc->boc->refcount >= 1);
1161 224908
                if (oc->boc->state < BOS_REQ_DONE)
1162 55900
                        AN(bo->req);
1163
                else
1164 169008
                        AZ(bo->req);
1165 224908
                AN(stp);
1166 224908
                AN(stp->name);
1167 224908
                AN(stp->func);
1168 224908
                stp = stp->func(wrk, bo);
1169
        }
1170
1171 51156
        assert(bo->director_state == DIR_S_NULL);
1172
1173 51156
        INIT_OBJ(ctx, VRT_CTX_MAGIC);
1174 51156
        VCL_Bo2Ctx(ctx, bo);
1175 51156
        VCL_TaskLeave(ctx, bo->privs);
1176 51156
        http_Teardown(bo->bereq);
1177 51156
        http_Teardown(bo->beresp);
1178
        // cannot make assumptions about the number of references here #3434
1179 51156
        if (bo->bereq_body != NULL)
1180 504
                (void)HSH_DerefObjCore(bo->wrk, &bo->bereq_body);
1181
1182 51156
        if (oc->boc->state == BOS_FINISHED) {
1183 49685
                AZ(oc->flags & OC_F_FAILED);
1184 99370
                VSLb(bo->vsl, SLT_Length, "%ju",
1185 49685
                    (uintmax_t)ObjGetLen(bo->wrk, oc));
1186 49685
        }
1187
        // AZ(oc->boc); // XXX
1188
1189 51156
        if (bo->stale_oc != NULL)
1190 3318
                (void)HSH_DerefObjCore(wrk, &bo->stale_oc);
1191
1192 51156
        wrk->vsl = NULL;
1193 51156
        HSH_DerefBoc(wrk, oc);
1194 51156
        SES_Rel(bo->sp);
1195 51156
        VBO_ReleaseBusyObj(wrk, &bo);
1196 51156
        THR_SetBusyobj(NULL);
1197 51156
}
1198
1199
/*--------------------------------------------------------------------
1200
 */
1201
1202
void
1203 51177
VBF_Fetch(struct worker *wrk, struct req *req, struct objcore *oc,
1204
    struct objcore *oldoc, enum vbf_fetch_mode_e mode)
1205
{
1206
        enum boc_state_e state;
1207
        struct boc *boc;
1208
        struct busyobj *bo;
1209
        enum task_prio prio;
1210
        const char *how;
1211
1212 51177
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
1213 51177
        CHECK_OBJ_NOTNULL(req, REQ_MAGIC);
1214 51177
        CHECK_OBJ_NOTNULL(oc, OBJCORE_MAGIC);
1215 51177
        CHECK_OBJ_ORNULL(oldoc, OBJCORE_MAGIC);
1216
1217 51177
        bo = VBO_GetBusyObj(wrk, req);
1218 51177
        CHECK_OBJ_NOTNULL(bo, BUSYOBJ_MAGIC);
1219 51177
        AN(bo->vcl);
1220
1221 51177
        init_esi_flags(bo);
1222
1223 51177
        boc = HSH_RefBoc(oc);
1224 51177
        CHECK_OBJ_NOTNULL(boc, BOC_MAGIC);
1225 51177
        assert(boc->state < BOS_STREAM);
1226 51177
        boc->transit_buffer = cache_param->transit_buffer;
1227
1228 51177
        switch (mode) {
1229
        case VBF_PASS:
1230 19824
                prio = TASK_QUEUE_BO;
1231 19824
                how = "pass";
1232 19824
                bo->uncacheable = 1;
1233 19824
                break;
1234
        case VBF_NORMAL:
1235 29505
                prio = TASK_QUEUE_BO;
1236 29505
                how = "fetch";
1237 29505
                break;
1238
        case VBF_BACKGROUND:
1239 1848
                prio = TASK_QUEUE_BG;
1240 1848
                how = "bgfetch";
1241 1848
                bo->is_bgfetch = 1;
1242 1848
                break;
1243
        default:
1244 0
                WRONG("Wrong fetch mode");
1245 0
        }
1246
1247
#define REQ_BEREQ_FLAG(l, r, w, d) bo->l = req->l;
1248
#include "tbl/req_bereq_flags.h"
1249
1250
        VSLb(bo->vsl, SLT_Begin, "bereq %ju %s", VXID(req->vsl->wid), how);
1251
        VSLbs(bo->vsl, SLT_VCL_use, TOSTRAND(VCL_Name(bo->vcl)));
1252
        VSLb(req->vsl, SLT_Link, "bereq %ju %s", VXID(bo->vsl->wid), how);
1253
1254
        THR_SetBusyobj(bo);
1255
1256
        bo->sp = req->sp;
1257
        SES_Ref(bo->sp);
1258
1259
        oc->boc->vary = req->vary_b;
1260
        req->vary_b = NULL;
1261
1262
        HSH_Ref(oc);
1263 51177
        AZ(bo->fetch_objcore);
1264
        bo->fetch_objcore = oc;
1265
1266 51177
        AZ(bo->stale_oc);
1267 51177
        if (oldoc != NULL) {
1268 3339
                assert(oldoc->refcnt > 0);
1269 3339
                HSH_Ref(oldoc);
1270 3339
                bo->stale_oc = oldoc;
1271 3339
        }
1272
1273 51177
        AZ(bo->req);
1274
        bo->req = req;
1275
1276
        bo->fetch_task->priv = bo;
1277
        bo->fetch_task->func = vbf_fetch_thread;
1278
1279 51177
        if (Pool_Task(wrk->pool, bo->fetch_task, prio)) {
1280 47
                wrk->stats->bgfetch_no_thread++;
1281 47
                VSLb(bo->vsl, SLT_FetchError,
1282
                    "No thread available for bgfetch");
1283 47
                (void)vbf_stp_fail(req->wrk, bo);
1284 47
                if (bo->stale_oc != NULL)
1285 21
                        (void)HSH_DerefObjCore(wrk, &bo->stale_oc);
1286 47
                HSH_DerefBoc(wrk, oc);
1287 47
                SES_Rel(bo->sp);
1288 47
                THR_SetBusyobj(NULL);
1289 47
                VBO_ReleaseBusyObj(wrk, &bo);
1290 47
        } else {
1291 51130
                THR_SetBusyobj(NULL);
1292 51130
                bo = NULL; /* ref transferred to fetch thread */
1293 51130
                if (mode == VBF_BACKGROUND) {
1294 1827
                        (void)ObjWaitState(oc, BOS_REQ_DONE);
1295 1827
                        (void)VRB_Ignore(req);
1296 1827
                } else {
1297 49303
                        state = ObjWaitState(oc, BOS_STREAM);
1298 49303
                        AZ(oc->flags & OC_F_BUSY);
1299 49303
                        if (state == BOS_FAILED)
1300 588
                                AN(oc->flags & OC_F_FAILED);
1301
                }
1302
        }
1303 51177
        AZ(bo);
1304
        VSLb_ts_req(req, "Fetch", W_TIM_real(wrk));
1305 51177
        assert(oc->boc == boc);
1306
        HSH_DerefBoc(wrk, oc);
1307 51177
        if (mode == VBF_BACKGROUND)
1308 1848
                (void)HSH_DerefObjCore(wrk, &oc);
1309
}