varnish-cache/bin/varnishd/http1/cache_http1_vfp.c
1
/*-
2
 * Copyright (c) 2006 Verdens Gang AS
3
 * Copyright (c) 2006-2015 Varnish Software AS
4
 * All rights reserved.
5
 *
6
 * Author: Poul-Henning Kamp <phk@phk.freebsd.dk>
7
 *
8
 * Redistribution and use in source and binary forms, with or without
9
 * modification, are permitted provided that the following conditions
10
 * are met:
11
 * 1. Redistributions of source code must retain the above copyright
12
 *    notice, this list of conditions and the following disclaimer.
13
 * 2. Redistributions in binary form must reproduce the above copyright
14
 *    notice, this list of conditions and the following disclaimer in the
15
 *    documentation and/or other materials provided with the distribution.
16
 *
17
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20
 * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
21
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27
 * SUCH DAMAGE.
28
 *
29
 * HTTP1 Fetch Filters
30
 *
31
 * These filters are used for both req.body and beresp.body to handle
32
 * the HTTP/1 aspects (C-L/Chunked/EOF)
33
 *
34
 */
35
36
#include "config.h"
37
38
#include <errno.h>
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
47
/*--------------------------------------------------------------------
48
 * Read up to len bytes, returning pipelined data first.
49
 */
50
51
static ssize_t
52 55286
v1f_read(const struct vfp_ctx *vc, struct http_conn *htc, void *d, ssize_t len)
53
{
54
        ssize_t l;
55
        unsigned char *p;
56 55286
        ssize_t i = 0;
57
58 55286
        CHECK_OBJ_NOTNULL(vc, VFP_CTX_MAGIC);
59 55286
        CHECK_OBJ_NOTNULL(htc, HTTP_CONN_MAGIC);
60 55286
        assert(len > 0);
61 55286
        l = 0;
62 55286
        p = d;
63 55286
        if (htc->pipeline_b) {
64 1362
                l = htc->pipeline_e - htc->pipeline_b;
65 1362
                assert(l > 0);
66 1362
                if (l > len)
67 640
                        l = len;
68 1362
                memcpy(p, htc->pipeline_b, l);
69 1362
                p += l;
70 1362
                len -= l;
71 1362
                htc->pipeline_b += l;
72 1362
                if (htc->pipeline_b == htc->pipeline_e)
73 722
                        htc->pipeline_b = htc->pipeline_e = NULL;
74
        }
75 55286
        if (len > 0) {
76 53967
                i = read(*htc->rfd, p, len);
77 53967
                if (i < 0) {
78
                        // XXX: VTCP_Assert(i); // but also: EAGAIN
79 3
                        VSLb(vc->wrk->vsl, SLT_FetchError,
80 3
                            "%s", strerror(errno));
81 3
                        return (i);
82
                }
83
        }
84 55283
        return (i + l);
85
}
86
87
88
/*--------------------------------------------------------------------
89
 * Read a chunked HTTP object.
90
 *
91
 * XXX: Reading one byte at a time is pretty pessimal.
92
 */
93
94
static enum vfp_status v_matchproto_(vfp_pull_f)
95 52999
v1f_pull_chunked(struct vfp_ctx *vc, struct vfp_entry *vfe, void *ptr,
96
    ssize_t *lp)
97
{
98
        struct http_conn *htc;
99
        char buf[20];           /* XXX: 20 is arbitrary */
100
        char *q;
101
        unsigned u;
102
        uintmax_t cll;
103
        ssize_t cl, l, lr;
104
105 52999
        CHECK_OBJ_NOTNULL(vc, VFP_CTX_MAGIC);
106 52999
        CHECK_OBJ_NOTNULL(vfe, VFP_ENTRY_MAGIC);
107 52999
        CAST_OBJ_NOTNULL(htc, vfe->priv1, HTTP_CONN_MAGIC);
108 52999
        AN(ptr);
109 52999
        AN(lp);
110
111 52999
        l = *lp;
112 52999
        *lp = 0;
113 52999
        if (vfe->priv2 == -1) {
114
                /* Skip leading whitespace */
115
                do {
116 306
                        lr = v1f_read(vc, htc, buf, 1);
117 306
                        if (lr <= 0)
118 4
                                return (VFP_Error(vc, "chunked read err"));
119 302
                } while (vct_islws(buf[0]));
120
121 128
                if (!vct_ishex(buf[0]))
122 0
                         return (VFP_Error(vc, "chunked header non-hex"));
123
124
                /* Collect hex digits, skipping leading zeros */
125 276
                for (u = 1; u < sizeof buf; u++) {
126
                        do {
127 314
                                lr = v1f_read(vc, htc, buf + u, 1);
128 314
                                if (lr <= 0)
129 0
                                        return (VFP_Error(vc,
130
                                            "chunked read err"));
131 314
                        } while (u == 1 && buf[0] == '0' && buf[u] == '0');
132 275
                        if (!vct_ishex(buf[u]))
133 127
                                break;
134
                }
135
136 128
                if (u >= sizeof buf)
137 1
                        return (VFP_Error(vc, "chunked header too long"));
138
139
                /* Skip trailing white space */
140 381
                while (vct_islws(buf[u]) && buf[u] != '\n') {
141 127
                        lr = v1f_read(vc, htc, buf + u, 1);
142 127
                        if (lr <= 0)
143 0
                                return (VFP_Error(vc, "chunked read err"));
144
                }
145
146 127
                if (buf[u] != '\n')
147 0
                        return (VFP_Error(vc, "chunked header no NL"));
148
149 127
                buf[u] = '\0';
150
151 127
                cll = strtoumax(buf, &q, 16);
152 127
                if (q == NULL || *q != '\0')
153 0
                        return (VFP_Error(vc, "chunked header number syntax"));
154 127
                cl = (ssize_t)cll;
155 127
                if (cl < 0 || (uintmax_t)cl != cll)
156 1
                        return (VFP_Error(vc, "bogusly large chunk size"));
157
158 126
                vfe->priv2 = cl;
159
        }
160 52993
        if (vfe->priv2 > 0) {
161 52965
                if (vfe->priv2 < l)
162 85
                        l = vfe->priv2;
163 52965
                lr = v1f_read(vc, htc, ptr, l);
164 52965
                if (lr <= 0)
165 1
                        return (VFP_Error(vc, "straight insufficient bytes"));
166 52964
                *lp = lr;
167 52964
                vfe->priv2 -= lr;
168 52964
                if (vfe->priv2 == 0)
169 96
                        vfe->priv2 = -1;
170 52964
                return (VFP_OK);
171
        }
172 28
        AZ(vfe->priv2);
173 28
        if (v1f_read(vc, htc, buf, 1) <= 0)
174 0
                return (VFP_Error(vc, "chunked read err"));
175 28
        if (buf[0] == '\r' && v1f_read(vc, htc, buf, 1) <= 0)
176 0
                return (VFP_Error(vc, "chunked read err"));
177 28
        if (buf[0] != '\n')
178 0
                return (VFP_Error(vc, "chunked tail no NL"));
179 28
        return (VFP_END);
180
}
181
182
static const struct vfp v1f_chunked = {
183
        .name = "V1F_CHUNKED",
184
        .pull = v1f_pull_chunked,
185
};
186
187
188
/*--------------------------------------------------------------------*/
189
190
static enum vfp_status v_matchproto_(vfp_pull_f)
191 1456
v1f_pull_straight(struct vfp_ctx *vc, struct vfp_entry *vfe, void *p,
192
    ssize_t *lp)
193
{
194
        ssize_t l, lr;
195
        struct http_conn *htc;
196
197 1456
        CHECK_OBJ_NOTNULL(vc, VFP_CTX_MAGIC);
198 1456
        CHECK_OBJ_NOTNULL(vfe, VFP_ENTRY_MAGIC);
199 1456
        CAST_OBJ_NOTNULL(htc, vfe->priv1, HTTP_CONN_MAGIC);
200 1456
        AN(p);
201 1456
        AN(lp);
202
203 1456
        l = *lp;
204 1456
        *lp = 0;
205
206 1456
        if (vfe->priv2 == 0) // XXX: Optimize Content-Len: 0 out earlier
207 0
                return (VFP_END);
208 1456
        if (vfe->priv2 < l)
209 54
                l = vfe->priv2;
210 1456
        lr = v1f_read(vc, htc, p, l);
211 1456
        if (lr <= 0)
212 11
                return (VFP_Error(vc, "straight insufficient bytes"));
213 1445
        *lp = lr;
214 1445
        vfe->priv2 -= lr;
215 1445
        if (vfe->priv2 == 0)
216 707
                return (VFP_END);
217 738
        return (VFP_OK);
218
}
219
220
static const struct vfp v1f_straight = {
221
        .name = "V1F_STRAIGHT",
222
        .pull = v1f_pull_straight,
223
};
224
225
/*--------------------------------------------------------------------*/
226
227
static enum vfp_status v_matchproto_(vfp_pull_f)
228 62
v1f_pull_eof(struct vfp_ctx *vc, struct vfp_entry *vfe, void *p, ssize_t *lp)
229
{
230
        ssize_t l, lr;
231
        struct http_conn *htc;
232
233 62
        CHECK_OBJ_NOTNULL(vc, VFP_CTX_MAGIC);
234 62
        CHECK_OBJ_NOTNULL(vfe, VFP_ENTRY_MAGIC);
235 62
        CAST_OBJ_NOTNULL(htc, vfe->priv1, HTTP_CONN_MAGIC);
236 62
        AN(p);
237
238 62
        AN(lp);
239
240 62
        l = *lp;
241 62
        *lp = 0;
242 62
        lr = v1f_read(vc, htc, p, l);
243 62
        if (lr < 0)
244 3
                return (VFP_Error(vc, "eof socket fail"));
245 59
        if (lr == 0)
246 16
                return (VFP_END);
247 43
        *lp = lr;
248 43
        return (VFP_OK);
249
}
250
251
static const struct vfp v1f_eof = {
252
        .name = "V1F_EOF",
253
        .pull = v1f_pull_eof,
254
};
255
256
/*--------------------------------------------------------------------
257
 */
258
259
int
260 800
V1F_Setup_Fetch(struct vfp_ctx *vfc, struct http_conn *htc)
261
{
262
        struct vfp_entry *vfe;
263
264 800
        CHECK_OBJ_NOTNULL(vfc, VFP_CTX_MAGIC);
265 800
        CHECK_OBJ_NOTNULL(htc, HTTP_CONN_MAGIC);
266
267 800
        switch (htc->body_status) {
268
        case BS_EOF:
269 19
                assert(htc->content_length == -1);
270 19
                vfe = VFP_Push(vfc, &v1f_eof);
271 19
                if (vfe == NULL)
272 0
                        return (ENOSPC);
273 19
                vfe->priv2 = 0;
274 19
                break;
275
        case BS_LENGTH:
276 735
                assert(htc->content_length > 0);
277 735
                vfe = VFP_Push(vfc, &v1f_straight);
278 735
                if (vfe == NULL)
279 0
                        return (ENOSPC);
280 735
                vfe->priv2 = htc->content_length;
281 735
                break;
282
        case BS_CHUNKED:
283 46
                assert(htc->content_length == -1);
284 46
                vfe = VFP_Push(vfc, &v1f_chunked);
285 46
                if (vfe == NULL)
286 0
                        return (ENOSPC);
287 46
                vfe->priv2 = -1;
288 46
                break;
289
        default:
290 0
                WRONG("Wrong body_status");
291
                break;
292
        }
293 800
        vfe->priv1 = htc;
294 800
        return 0;
295
}