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 2339657
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 2339657
        ssize_t i = 0;
58
59 2339657
        CHECK_OBJ_NOTNULL(vc, VFP_CTX_MAGIC);
60 2339657
        CHECK_OBJ_NOTNULL(htc, HTTP_CONN_MAGIC);
61 2339657
        assert(len > 0);
62 2339657
        l = 0;
63 2339657
        p = d;
64 2339657
        if (htc->pipeline_b) {
65 118382
                l = htc->pipeline_e - htc->pipeline_b;
66 118382
                assert(l > 0);
67 118382
                l = vmin(l, len);
68 118382
                memcpy(p, htc->pipeline_b, l);
69 118382
                p += l;
70 118382
                len -= l;
71 118382
                htc->pipeline_b += l;
72 118382
                if (htc->pipeline_b == htc->pipeline_e)
73 42262
                        htc->pipeline_b = htc->pipeline_e = NULL;
74 118382
        }
75 2339657
        if (len > 0) {
76 2224193
                i = read(*htc->rfd, p, len);
77 2224193
                if (i < 0) {
78 360
                        VTCP_Assert(i);
79 720
                        VSLbs(vc->wrk->vsl, SLT_FetchError,
80 360
                            TOSTRAND(VAS_errtxt(errno)));
81 360
                        return (i);
82
                }
83 2223833
                assert(i <= len);
84 2223833
                if (i == 0)
85 2360
                        htc->doclose = SC_RESP_CLOSE;
86 2223833
        }
87 2339297
        assert(i >= 0);
88 2339297
        assert(l >= 0);
89 2339297
        assert(i < SSIZE_MAX / 2);
90 2339297
        assert(l < SSIZE_MAX / 2);
91 2339297
        return (i + l);
92 2339657
}
93
94
95
/*--------------------------------------------------------------------
96
 * read (CR)?LF at the end of a chunk
97
 */
98
static enum vfp_status
99 15442
v1f_chunk_end(struct vfp_ctx *vc, struct http_conn *htc)
100
{
101
        char c;
102
103 15442
        if (v1f_read(vc, htc, &c, 1) <= 0)
104 0
                return (VFP_Error(vc, "chunked read err"));
105 15442
        if (c == '\r' && v1f_read(vc, htc, &c, 1) <= 0)
106 0
                return (VFP_Error(vc, "chunked read err"));
107 15442
        if (c != '\n')
108 120
                return (VFP_Error(vc, "chunked tail no NL"));
109 15322
        return (VFP_OK);
110 15442
}
111
112
113
/*--------------------------------------------------------------------
114
 * Parse a chunk header and, for VFP_OK, return size in a pointer
115
 *
116
 * XXX: Reading one byte at a time is pretty pessimal.
117
 */
118
119
static enum vfp_status
120 15875
v1f_chunked_hdr(struct vfp_ctx *vc, struct http_conn *htc, ssize_t *szp)
121
{
122
        char buf[20];           /* XXX: 20 is arbitrary */
123
        unsigned u;
124
        uintmax_t cll;
125
        ssize_t cl, lr;
126
        char *q;
127
128 15875
        CHECK_OBJ_NOTNULL(vc, VFP_CTX_MAGIC);
129 15875
        CHECK_OBJ_NOTNULL(htc, HTTP_CONN_MAGIC);
130 15875
        AN(szp);
131 15875
        assert(*szp == -1);
132
133
        /* Skip leading whitespace */
134 15875
        do {
135 15882
                lr = v1f_read(vc, htc, buf, 1);
136 15882
                if (lr <= 0)
137 200
                        return (VFP_Error(vc, "chunked read err"));
138 15682
        } while (vct_isows(buf[0]));
139
140 15689
        if (!vct_ishex(buf[0]))
141 80
                return (VFP_Error(vc, "chunked header non-hex"));
142
143
        /* Collect hex digits, skipping leading zeros */
144 27929
        for (u = 1; u < sizeof buf; u++) {
145 27883
                do {
146 54681
                        lr = v1f_read(vc, htc, buf + u, 1);
147 54681
                        if (lr <= 0)
148 0
                                return (VFP_Error(vc, "chunked read err"));
149 54681
                } while (u == 1 && buf[0] == '0' && buf[u] == '0');
150 27883
                if (!vct_ishex(buf[u]))
151 15563
                        break;
152 12320
        }
153
154 15609
        if (u >= sizeof buf)
155 40
                return (VFP_Error(vc, "chunked header too long"));
156
157
        /* Skip trailing white space */
158 15569
        while (vct_isows(buf[u])) {
159 0
                lr = v1f_read(vc, htc, buf + u, 1);
160 0
                if (lr <= 0)
161 0
                        return (VFP_Error(vc, "chunked read err"));
162
        }
163
164 15569
        if (buf[u] == '\r' && v1f_read(vc, htc, buf + u, 1) <= 0)
165 0
                return (VFP_Error(vc, "chunked read err"));
166 15569
        if (buf[u] != '\n')
167 0
                return (VFP_Error(vc, "chunked header no NL"));
168
169 15561
        buf[u] = '\0';
170
171 15561
        cll = strtoumax(buf, &q, 16);
172 15561
        if (q == NULL || *q != '\0')
173 2
                return (VFP_Error(vc, "chunked header number syntax"));
174 15559
        cl = (ssize_t)cll;
175 15559
        if (cl < 0 || (uintmax_t)cl != cll)
176 40
                return (VFP_Error(vc, "bogusly large chunk size"));
177
178 15519
        *szp = cl;
179 15519
        return (VFP_OK);
180 15879
}
181
182
183
/*--------------------------------------------------------------------
184
 * Read a chunked HTTP object.
185
 *
186
 */
187
188
static enum vfp_status v_matchproto_(vfp_pull_f)
189 2131566
v1f_chunked_pull(struct vfp_ctx *vc, struct vfp_entry *vfe, void *ptr,
190
    ssize_t *lp)
191
{
192
        static enum vfp_status vfps;
193
        struct http_conn *htc;
194
        ssize_t l, lr;
195
196 2131566
        CHECK_OBJ_NOTNULL(vc, VFP_CTX_MAGIC);
197 2131566
        CHECK_OBJ_NOTNULL(vfe, VFP_ENTRY_MAGIC);
198 2131566
        CAST_OBJ_NOTNULL(htc, vfe->priv1, HTTP_CONN_MAGIC);
199 2131566
        AN(ptr);
200 2131566
        AN(lp);
201
202 2131566
        l = *lp;
203 2131566
        *lp = 0;
204 2131566
        if (vfe->priv2 == -1) {
205 15881
                vfps = v1f_chunked_hdr(vc, htc, &vfe->priv2);
206 15881
                if (vfps != VFP_OK)
207 360
                        return (vfps);
208 15521
        }
209 2131206
        if (vfe->priv2 > 0) {
210 2126402
                if (vfe->priv2 < l)
211 9890
                        l = vfe->priv2;
212 2126402
                lr = v1f_read(vc, htc, ptr, l);
213 2126402
                if (lr <= 0)
214 40
                        return (VFP_Error(vc, "chunked insufficient bytes"));
215 2126362
                *lp = lr;
216 2126362
                vfe->priv2 -= lr;
217 2126362
                if (vfe->priv2 != 0)
218 2115723
                        return (VFP_OK);
219
220 10639
                vfe->priv2 = -1;
221 10639
                return (v1f_chunk_end(vc, htc));
222
        }
223 4804
        AZ(vfe->priv2);
224 4804
        vfps = v1f_chunk_end(vc, htc);
225 4804
        return (vfps == VFP_OK ? VFP_END : vfps);
226 2131566
}
227
228
static const struct vfp v1f_chunked = {
229
        .name = "V1F_CHUNKED",
230
        .pull = v1f_chunked_pull,
231
};
232
233
234
/*--------------------------------------------------------------------*/
235
236
static enum vfp_status v_matchproto_(vfp_pull_f)
237 95322
v1f_straight_pull(struct vfp_ctx *vc, struct vfp_entry *vfe, void *p,
238
    ssize_t *lp)
239
{
240
        ssize_t l, lr;
241
        struct http_conn *htc;
242
243 95322
        CHECK_OBJ_NOTNULL(vc, VFP_CTX_MAGIC);
244 95322
        CHECK_OBJ_NOTNULL(vfe, VFP_ENTRY_MAGIC);
245 95322
        CAST_OBJ_NOTNULL(htc, vfe->priv1, HTTP_CONN_MAGIC);
246 95322
        AN(p);
247 95322
        AN(lp);
248
249 95322
        l = *lp;
250 95322
        *lp = 0;
251
252 95322
        if (vfe->priv2 == 0) // XXX: Optimize Content-Len: 0 out earlier
253 0
                return (VFP_END);
254 95322
        l = vmin(l, vfe->priv2);
255 95322
        lr = v1f_read(vc, htc, p, l);
256 95322
        if (lr <= 0)
257 920
                return (VFP_Error(vc, "straight insufficient bytes"));
258 94402
        *lp = lr;
259 94402
        vfe->priv2 -= lr;
260 94402
        if (vfe->priv2 == 0)
261 39636
                return (VFP_END);
262 54766
        return (VFP_OK);
263 95322
}
264
265
static const struct vfp v1f_straight = {
266
        .name = "V1F_STRAIGHT",
267
        .pull = v1f_straight_pull,
268
};
269
270
/*--------------------------------------------------------------------*/
271
272
static enum vfp_status v_matchproto_(vfp_pull_f)
273 2760
v1f_eof_pull(struct vfp_ctx *vc, struct vfp_entry *vfe, void *p, ssize_t *lp)
274
{
275
        ssize_t l, lr;
276
        struct http_conn *htc;
277
278 2760
        CHECK_OBJ_NOTNULL(vc, VFP_CTX_MAGIC);
279 2760
        CHECK_OBJ_NOTNULL(vfe, VFP_ENTRY_MAGIC);
280 2760
        CAST_OBJ_NOTNULL(htc, vfe->priv1, HTTP_CONN_MAGIC);
281 2760
        AN(p);
282
283 2760
        AN(lp);
284
285 2760
        l = *lp;
286 2760
        *lp = 0;
287 2760
        lr = v1f_read(vc, htc, p, l);
288 2760
        if (lr < 0)
289 120
                return (VFP_Error(vc, "eof socket fail"));
290 2640
        if (lr == 0)
291 800
                return (VFP_END);
292 1840
        *lp = lr;
293 1840
        return (VFP_OK);
294 2760
}
295
296
static const struct vfp v1f_eof = {
297
        .name = "V1F_EOF",
298
        .pull = v1f_eof_pull,
299
};
300
301
/*--------------------------------------------------------------------
302
 */
303
304
int
305 52238
V1F_Setup_Fetch(struct vfp_ctx *vfc, struct http_conn *htc)
306
{
307
        struct vfp_entry *vfe;
308
309 52238
        CHECK_OBJ_NOTNULL(vfc, VFP_CTX_MAGIC);
310 52238
        CHECK_OBJ_NOTNULL(htc, HTTP_CONN_MAGIC);
311
312 52238
        if (htc->body_status == BS_EOF) {
313 920
                assert(htc->content_length == -1);
314 920
                vfe = VFP_Push(vfc, &v1f_eof);
315 920
                if (vfe == NULL)
316 0
                        return (ENOSPC);
317 920
                vfe->priv2 = 0;
318 52238
        } else if (htc->body_status == BS_LENGTH) {
319 44918
                assert(htc->content_length > 0);
320 44918
                vfe = VFP_Push(vfc, &v1f_straight);
321 44918
                if (vfe == NULL)
322 0
                        return (ENOSPC);
323 44918
                vfe->priv2 = htc->content_length;
324 51318
        } else if (htc->body_status == BS_CHUNKED) {
325 6400
                assert(htc->content_length == -1);
326 6400
                vfe = VFP_Push(vfc, &v1f_chunked);
327 6400
                if (vfe == NULL)
328 640
                        return (ENOSPC);
329 5760
                vfe->priv2 = -1;
330 5760
        } else {
331 0
                WRONG("Wrong body_status");
332
        }
333 51598
        vfe->priv1 = htc;
334 51598
        return (0);
335 52238
}