vinyl-cache/bin/vinyld/cache/cache_fetch_proc.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 <stdlib.h>
34
35
#include "cache_int.h"
36
#include "cache_filter.h"
37
38
/*--------------------------------------------------------------------
39
 * We want to issue the first error we encounter on fetching and
40
 * suppress the rest.  This function does that.
41
 *
42
 * Other code is allowed to look at busyobj->fetch_failed to bail out
43
 *
44
 * For convenience, always return VFP_ERROR
45
 */
46
47
enum vfp_status
48 5523
VFP_Error(struct vfp_ctx *vc, const char *fmt, ...)
49
{
50
        va_list ap;
51
52 5523
        CHECK_OBJ_NOTNULL(vc, VFP_CTX_MAGIC);
53 5523
        if (!vc->failed) {
54 3423
                va_start(ap, fmt);
55 3423
                VSLbv(vc->wrk->vsl, SLT_FetchError, fmt, ap);
56 3423
                va_end(ap);
57 3423
                vc->failed = 1;
58 3423
        }
59 5523
        return (VFP_ERROR);
60
}
61
62
/*--------------------------------------------------------------------
63
 * Fetch Storage to put object into.
64
 *
65
 */
66
67
enum vfp_status
68 1255475
VFP_GetStorage(struct vfp_ctx *vc, ssize_t *sz, uint8_t **ptr)
69
{
70
71 1255475
        CHECK_OBJ_NOTNULL(vc, VFP_CTX_MAGIC);
72 1255475
        AN(sz);
73 1255475
        assert(*sz >= 0);
74 1255475
        AN(ptr);
75
76 1255475
        if (!ObjGetSpace(vc->wrk, vc->oc, sz, ptr)) {
77 168
                *sz = 0;
78 168
                *ptr = NULL;
79 168
                return (VFP_Error(vc, "Could not get storage"));
80
        }
81 1255307
        assert(*sz > 0);
82 1255307
        AN(*ptr);
83 1255307
        return (VFP_OK);
84 1255475
}
85
86
void
87 1233006
VFP_Extend(const struct vfp_ctx *vc, ssize_t sz, enum vfp_status flg)
88
{
89 1233006
        CHECK_OBJ_NOTNULL(vc, VFP_CTX_MAGIC);
90
91 1233006
        ObjExtend(vc->wrk, vc->oc, sz, flg == VFP_END ? 1 : 0);
92 1233006
}
93
94
/**********************************************************************
95
 */
96
97
void
98 57474
VFP_Setup(struct vfp_ctx *vc, struct worker *wrk)
99
{
100
101 57474
        INIT_OBJ(vc, VFP_CTX_MAGIC);
102 57474
        VTAILQ_INIT(&vc->vfp);
103 57474
        vc->wrk = wrk;
104 57474
}
105
106
/**********************************************************************
107
 * Returns the number of bytes processed by the lowest VFP in the stack
108
 */
109
110
uint64_t
111 52353
VFP_Close(struct vfp_ctx *vc)
112
{
113
        struct vfp_entry *vfe, *tmp;
114 52353
        uint64_t rv = 0;
115
116 94016
        VTAILQ_FOREACH_SAFE(vfe, &vc->vfp, list, tmp) {
117 41663
                if (vfe->vfp->fini != NULL)
118 10227
                        vfe->vfp->fini(vc, vfe);
119 41663
                rv = vfe->bytes_out;
120 83326
                VSLb(vc->wrk->vsl, SLT_VfpAcct, "%s %ju %ju", vfe->vfp->name,
121 41663
                    (uintmax_t)vfe->calls, (uintmax_t)rv);
122 41663
                VTAILQ_REMOVE(&vc->vfp, vfe, list);
123 41663
        }
124 52353
        return (rv);
125
}
126
127
int
128 48613
VFP_Open(VRT_CTX, struct vfp_ctx *vc)
129
{
130
        struct vfp_entry *vfe;
131
132 48613
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
133 48613
        CHECK_OBJ_NOTNULL(vc, VFP_CTX_MAGIC);
134 48613
        CHECK_OBJ_NOTNULL(vc->resp, HTTP_MAGIC);
135 48613
        CHECK_OBJ_NOTNULL(vc->wrk, WORKER_MAGIC);
136 48613
        AN(vc->wrk->vsl);
137
138 87987
        VTAILQ_FOREACH_REVERSE(vfe, &vc->vfp, vfp_entry_s, list) {
139 40487
                if (vfe->vfp->init == NULL)
140 31037
                        continue;
141 9450
                if (DO_DEBUG(DBG_PROCESSORS))
142 42
                        VSLb(vc->wrk->vsl, SLT_Debug, "VFP_Open(%s)",
143 21
                             vfe->vfp->name);
144 9450
                vfe->closed = vfe->vfp->init(ctx, vc, vfe);
145 9450
                if (vfe->closed != VFP_OK && vfe->closed != VFP_NULL) {
146 2226
                        (void)VFP_Error(vc, "Fetch filter %s failed to open",
147 1113
                            vfe->vfp->name);
148 1113
                        (void)VFP_Close(vc);
149 1113
                        return (-1);
150
                }
151 8337
        }
152
153 47500
        return (0);
154 48613
}
155
156
/**********************************************************************
157
 * Suck data up from lower levels.
158
 * Once a layer return non VFP_OK, clean it up and produce the same
159
 * return value for any subsequent calls.
160
 */
161
162
enum vfp_status
163 2362552
VFP_Suck(struct vfp_ctx *vc, void *p, ssize_t *lp)
164
{
165
        enum vfp_status vp;
166
        struct vfp_entry *vfe, *vfe_prev;
167 2362552
        const char *prev_name = "<storage>";
168
        ssize_t limit;
169
170 2362552
        CHECK_OBJ_NOTNULL(vc, VFP_CTX_MAGIC);
171 2362552
        AN(p);
172 2362552
        AN(lp);
173 2362552
        limit = *lp;
174 2362552
        vfe = vc->vfp_nxt;
175 2362552
        CHECK_OBJ_NOTNULL(vfe, VFP_ENTRY_MAGIC);
176 2362552
        vc->vfp_nxt = VTAILQ_NEXT(vfe, list);
177
178 2362552
        vfe_prev = VTAILQ_PREV(vfe, vfp_entry_s, list);
179 2362552
        if (vfe_prev != NULL)
180 1137177
                prev_name = vfe_prev->vfp->name;
181
182 2362552
        if (vfe->closed == VFP_NULL) {
183
                /* Layer asked to be bypassed when opened */
184 84
                vp = VFP_Suck(vc, p, lp);
185 84
                VFP_DEBUG(vc, "bypassing %s vp=%d", vfe->vfp->name, vp);
186 2362552
        } else if (vfe->closed == VFP_OK) {
187 2360893
                vp = vfe->vfp->pull(vc, vfe, p, lp);
188 2360893
                VFP_DEBUG(vc, "%s pulled %zdB/%zdB from %s vp=%d",
189
                    prev_name, *lp, limit, vfe->vfp->name, vp);
190 2360893
                if (vp != VFP_OK && vp != VFP_END && vp != VFP_ERROR)
191 0
                        vp = VFP_Error(vc, "Fetch filter %s returned %d",
192 0
                            vfe->vfp->name, vp);
193
                else
194 2360893
                        vfe->bytes_out += *lp;
195 2360893
                vfe->closed = vp;
196 2360893
                vfe->calls++;
197 2360893
        } else {
198
                /* Already closed filter */
199 1575
                *lp = 0;
200 1575
                vp = vfe->closed;
201 1575
                VFP_DEBUG(vc, "ignoring %s vp=%d", vfe->vfp->name, vp);
202
        }
203 2362552
        vc->vfp_nxt = vfe;
204 2362552
        assert(vp != VFP_NULL);
205 2362552
        return (vp);
206
}
207
208
/*--------------------------------------------------------------------
209
 */
210
211
struct vfp_entry *
212 42882
VFP_Push(struct vfp_ctx *vc, const struct vfp *vfp)
213
{
214
        struct vfp_entry *vfe;
215
216 42882
        CHECK_OBJ_NOTNULL(vc, VFP_CTX_MAGIC);
217 42882
        CHECK_OBJ_NOTNULL(vc->resp, HTTP_MAGIC);
218
219 42882
        vfe = WS_Alloc(vc->resp->ws, sizeof *vfe);
220 42882
        if (vfe == NULL) {
221 798
                (void)VFP_Error(vc, "Workspace overflow");
222 798
                return (NULL);
223
        }
224
225 42084
        INIT_OBJ(vfe, VFP_ENTRY_MAGIC);
226 42084
        vfe->vfp = vfp;
227 42084
        vfe->closed = VFP_OK;
228 42084
        VTAILQ_INSERT_HEAD(&vc->vfp, vfe, list);
229 42084
        vc->vfp_nxt = vfe;
230 42084
        return (vfe);
231 42882
}