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