varnish-cache/bin/varnishd/http1/cache_http1_vfp.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
 * HTTP1 Fetch Filters
31
 *
32
 * These filters are used for both req.body and beresp.body to handle
33
 * the HTTP/1 aspects (C-L/Chunked/EOF)
34
 *
35
 */
36
37
#include "config.h"
38
39
#include <inttypes.h>
40
41
#include "cache/cache_varnishd.h"
42
#include "cache/cache_filter.h"
43
#include "cache_http1.h"
44
45
#include "vct.h"
46
#include "vtcp.h"
47
48
/*--------------------------------------------------------------------
49
 * Read up to len bytes, returning pipelined data first.
50
 */
51
52
static ssize_t
53 58441
v1f_read(const struct vfp_ctx *vc, struct http_conn *htc, void *d, ssize_t len)
54
{
55
        ssize_t l;
56
        unsigned char *p;
57 58441
        ssize_t i = 0;
58
59 58441
        CHECK_OBJ_NOTNULL(vc, VFP_CTX_MAGIC);
60 58441
        CHECK_OBJ_NOTNULL(htc, HTTP_CONN_MAGIC);
61 58441
        assert(len > 0);
62 58441
        l = 0;
63 58441
        p = d;
64 58441
        if (htc->pipeline_b) {
65 2957
                l = htc->pipeline_e - htc->pipeline_b;
66 2957
                assert(l > 0);
67 2957
                l = vmin(l, len);
68 2957
                memcpy(p, htc->pipeline_b, l);
69 2957
                p += l;
70 2957
                len -= l;
71 2957
                htc->pipeline_b += l;
72 2957
                if (htc->pipeline_b == htc->pipeline_e)
73 1046
                        htc->pipeline_b = htc->pipeline_e = NULL;
74 2957
        }
75 58441
        if (len > 0) {
76 55556
                i = read(*htc->rfd, p, len);
77 55556
                if (i < 0) {
78 9
                        VTCP_Assert(i);
79 18
                        VSLbs(vc->wrk->vsl, SLT_FetchError,
80 9
                            TOSTRAND(VAS_errtxt(errno)));
81 9
                        return (i);
82
                }
83 55547
                assert(i <= len);
84 55547
                if (i == 0)
85 59
                        htc->doclose = SC_RESP_CLOSE;
86 55547
        }
87 58432
        return (i + l);
88 58441
}
89
90
91
/*--------------------------------------------------------------------
92
 * read (CR)?LF at the end of a chunk
93
 */
94
static enum vfp_status
95 380
v1f_chunk_end(struct vfp_ctx *vc, struct http_conn *htc)
96
{
97
        char c;
98
99 380
        if (v1f_read(vc, htc, &c, 1) <= 0)
100 0
                return (VFP_Error(vc, "chunked read err"));
101 380
        if (c == '\r' && v1f_read(vc, htc, &c, 1) <= 0)
102 0
                return (VFP_Error(vc, "chunked read err"));
103 380
        if (c != '\n')
104 2
                return (VFP_Error(vc, "chunked tail no NL"));
105 378
        return (VFP_OK);
106 380
}
107
108
109
/*--------------------------------------------------------------------
110
 * Parse a chunk header and, for VFP_OK, return size in a pointer
111
 *
112
 * XXX: Reading one byte at a time is pretty pessimal.
113
 */
114
115
static enum vfp_status
116 391
v1f_chunked_hdr(struct vfp_ctx *vc, struct http_conn *htc, ssize_t *szp)
117
{
118
        char buf[20];           /* XXX: 20 is arbitrary */
119
        unsigned u;
120
        uintmax_t cll;
121
        ssize_t cl, lr;
122
        char *q;
123
124 391
        CHECK_OBJ_NOTNULL(vc, VFP_CTX_MAGIC);
125 391
        CHECK_OBJ_NOTNULL(htc, HTTP_CONN_MAGIC);
126 391
        AN(szp);
127 391
        assert(*szp == -1);
128
129
        /* Skip leading whitespace */
130 391
        do {
131 391
                lr = v1f_read(vc, htc, buf, 1);
132 391
                if (lr <= 0)
133 5
                        return (VFP_Error(vc, "chunked read err"));
134 386
        } while (vct_isows(buf[0]));
135
136 386
        if (!vct_ishex(buf[0]))
137 2
                return (VFP_Error(vc, "chunked header non-hex"));
138
139
        /* Collect hex digits, skipping leading zeros */
140 692
        for (u = 1; u < sizeof buf; u++) {
141 691
                do {
142 1361
                        lr = v1f_read(vc, htc, buf + u, 1);
143 1361
                        if (lr <= 0)
144 0
                                return (VFP_Error(vc, "chunked read err"));
145 1361
                } while (u == 1 && buf[0] == '0' && buf[u] == '0');
146 691
                if (!vct_ishex(buf[u]))
147 383
                        break;
148 308
        }
149
150 384
        if (u >= sizeof buf)
151 1
                return (VFP_Error(vc, "chunked header too long"));
152
153
        /* Skip trailing white space */
154 383
        while (vct_isows(buf[u])) {
155 0
                lr = v1f_read(vc, htc, buf + u, 1);
156 0
                if (lr <= 0)
157 0
                        return (VFP_Error(vc, "chunked read err"));
158
        }
159
160 383
        if (buf[u] == '\r' && v1f_read(vc, htc, buf + u, 1) <= 0)
161 0
                return (VFP_Error(vc, "chunked read err"));
162 383
        if (buf[u] != '\n')
163 0
                return (VFP_Error(vc, "chunked header no NL"));
164
165 383
        buf[u] = '\0';
166
167 383
        cll = strtoumax(buf, &q, 16);
168 383
        if (q == NULL || *q != '\0')
169 0
                return (VFP_Error(vc, "chunked header number syntax"));
170 383
        cl = (ssize_t)cll;
171 383
        if (cl < 0 || (uintmax_t)cl != cll)
172 1
                return (VFP_Error(vc, "bogusly large chunk size"));
173
174 382
        *szp = cl;
175 382
        return (VFP_OK);
176 391
}
177
178
179
/*--------------------------------------------------------------------
180
 * Read a chunked HTTP object.
181
 *
182
 */
183
184
static enum vfp_status v_matchproto_(vfp_pull_f)
185 53237
v1f_chunked_pull(struct vfp_ctx *vc, struct vfp_entry *vfe, void *ptr,
186
    ssize_t *lp)
187
{
188
        static enum vfp_status vfps;
189
        struct http_conn *htc;
190
        ssize_t l, lr;
191
192 53237
        CHECK_OBJ_NOTNULL(vc, VFP_CTX_MAGIC);
193 53237
        CHECK_OBJ_NOTNULL(vfe, VFP_ENTRY_MAGIC);
194 53237
        CAST_OBJ_NOTNULL(htc, vfe->priv1, HTTP_CONN_MAGIC);
195 53237
        AN(ptr);
196 53237
        AN(lp);
197
198 53237
        l = *lp;
199 53237
        *lp = 0;
200 53237
        if (vfe->priv2 == -1) {
201 391
                vfps = v1f_chunked_hdr(vc, htc, &vfe->priv2);
202 391
                if (vfps != VFP_OK)
203 9
                        return (vfps);
204 382
        }
205 53228
        if (vfe->priv2 > 0) {
206 53109
                if (vfe->priv2 < l)
207 239
                        l = vfe->priv2;
208 53109
                lr = v1f_read(vc, htc, ptr, l);
209 53109
                if (lr <= 0)
210 1
                        return (VFP_Error(vc, "chunked insufficient bytes"));
211 53108
                *lp = lr;
212 53108
                vfe->priv2 -= lr;
213 53108
                if (vfe->priv2 != 0)
214 52847
                        return (VFP_OK);
215
216 261
                vfe->priv2 = -1;
217 261
                return (v1f_chunk_end(vc, htc));
218
        }
219 119
        AZ(vfe->priv2);
220 119
        vfps = v1f_chunk_end(vc, htc);
221 119
        return (vfps == VFP_OK ? VFP_END : vfps);
222 53237
}
223
224
static const struct vfp v1f_chunked = {
225
        .name = "V1F_CHUNKED",
226
        .pull = v1f_chunked_pull,
227
};
228
229
230
/*--------------------------------------------------------------------*/
231
232
static enum vfp_status v_matchproto_(vfp_pull_f)
233 2413
v1f_straight_pull(struct vfp_ctx *vc, struct vfp_entry *vfe, void *p,
234
    ssize_t *lp)
235
{
236
        ssize_t l, lr;
237
        struct http_conn *htc;
238
239 2413
        CHECK_OBJ_NOTNULL(vc, VFP_CTX_MAGIC);
240 2413
        CHECK_OBJ_NOTNULL(vfe, VFP_ENTRY_MAGIC);
241 2413
        CAST_OBJ_NOTNULL(htc, vfe->priv1, HTTP_CONN_MAGIC);
242 2413
        AN(p);
243 2413
        AN(lp);
244
245 2413
        l = *lp;
246 2413
        *lp = 0;
247
248 2413
        if (vfe->priv2 == 0) // XXX: Optimize Content-Len: 0 out earlier
249 0
                return (VFP_END);
250 2413
        l = vmin(l, vfe->priv2);
251 2413
        lr = v1f_read(vc, htc, p, l);
252 2413
        if (lr <= 0)
253 23
                return (VFP_Error(vc, "straight insufficient bytes"));
254 2390
        *lp = lr;
255 2390
        vfe->priv2 -= lr;
256 2390
        if (vfe->priv2 == 0)
257 981
                return (VFP_END);
258 1409
        return (VFP_OK);
259 2413
}
260
261
static const struct vfp v1f_straight = {
262
        .name = "V1F_STRAIGHT",
263
        .pull = v1f_straight_pull,
264
};
265
266
/*--------------------------------------------------------------------*/
267
268
static enum vfp_status v_matchproto_(vfp_pull_f)
269 69
v1f_eof_pull(struct vfp_ctx *vc, struct vfp_entry *vfe, void *p, ssize_t *lp)
270
{
271
        ssize_t l, lr;
272
        struct http_conn *htc;
273
274 69
        CHECK_OBJ_NOTNULL(vc, VFP_CTX_MAGIC);
275 69
        CHECK_OBJ_NOTNULL(vfe, VFP_ENTRY_MAGIC);
276 69
        CAST_OBJ_NOTNULL(htc, vfe->priv1, HTTP_CONN_MAGIC);
277 69
        AN(p);
278
279 69
        AN(lp);
280
281 69
        l = *lp;
282 69
        *lp = 0;
283 69
        lr = v1f_read(vc, htc, p, l);
284 69
        if (lr < 0)
285 3
                return (VFP_Error(vc, "eof socket fail"));
286 66
        if (lr == 0)
287 20
                return (VFP_END);
288 46
        *lp = lr;
289 46
        return (VFP_OK);
290 69
}
291
292
static const struct vfp v1f_eof = {
293
        .name = "V1F_EOF",
294
        .pull = v1f_eof_pull,
295
};
296
297
/*--------------------------------------------------------------------
298
 */
299
300
int
301 1293
V1F_Setup_Fetch(struct vfp_ctx *vfc, struct http_conn *htc)
302
{
303
        struct vfp_entry *vfe;
304
305 1293
        CHECK_OBJ_NOTNULL(vfc, VFP_CTX_MAGIC);
306 1293
        CHECK_OBJ_NOTNULL(htc, HTTP_CONN_MAGIC);
307
308 1293
        if (htc->body_status == BS_EOF) {
309 23
                assert(htc->content_length == -1);
310 23
                vfe = VFP_Push(vfc, &v1f_eof);
311 23
                if (vfe == NULL)
312 0
                        return (ENOSPC);
313 23
                vfe->priv2 = 0;
314 1293
        } else if (htc->body_status == BS_LENGTH) {
315 1113
                assert(htc->content_length > 0);
316 1113
                vfe = VFP_Push(vfc, &v1f_straight);
317 1113
                if (vfe == NULL)
318 0
                        return (ENOSPC);
319 1113
                vfe->priv2 = htc->content_length;
320 1270
        } else if (htc->body_status == BS_CHUNKED) {
321 157
                assert(htc->content_length == -1);
322 157
                vfe = VFP_Push(vfc, &v1f_chunked);
323 157
                if (vfe == NULL)
324 16
                        return (ENOSPC);
325 141
                vfe->priv2 = -1;
326 141
        } else {
327 0
                WRONG("Wrong body_status");
328
        }
329 1277
        vfe->priv1 = htc;
330 1277
        return (0);
331 1293
}