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 113525
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 113525
        ssize_t i = 0;
57
58 113525
        CHECK_OBJ_NOTNULL(vc, VFP_CTX_MAGIC);
59 113525
        CHECK_OBJ_NOTNULL(htc, HTTP_CONN_MAGIC);
60 113525
        assert(len > 0);
61 113525
        l = 0;
62 113525
        p = d;
63 113525
        if (htc->pipeline_b) {
64 5751
                l = htc->pipeline_e - htc->pipeline_b;
65 5751
                assert(l > 0);
66 5751
                if (l > len)
67 3980
                        l = len;
68 5751
                memcpy(p, htc->pipeline_b, l);
69 5751
                p += l;
70 5751
                len -= l;
71 5751
                htc->pipeline_b += l;
72 5751
                if (htc->pipeline_b == htc->pipeline_e)
73 1771
                        htc->pipeline_b = htc->pipeline_e = NULL;
74
        }
75 113525
        if (len > 0) {
76 107866
                i = read(*htc->rfd, p, len);
77 107866
                if (i < 0) {
78
                        // XXX: VTCP_Assert(i); // but also: EAGAIN
79 6
                        VSLb(vc->wrk->vsl, SLT_FetchError,
80 6
                            "%s", strerror(errno));
81 6
                        return (i);
82
                }
83
        }
84 113519
        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 106169
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 106169
        CHECK_OBJ_NOTNULL(vc, VFP_CTX_MAGIC);
106 106169
        CHECK_OBJ_NOTNULL(vfe, VFP_ENTRY_MAGIC);
107 106169
        CAST_OBJ_NOTNULL(htc, vfe->priv1, HTTP_CONN_MAGIC);
108 106169
        AN(ptr);
109 106169
        AN(lp);
110
111 106169
        l = *lp;
112 106169
        *lp = 0;
113 106169
        if (vfe->priv2 == -1) {
114
                /* Skip leading whitespace */
115
                do {
116 1098
                        lr = v1f_read(vc, htc, buf, 1);
117 1098
                        if (lr <= 0)
118 10
                                return (VFP_Error(vc, "chunked read err"));
119 1088
                } while (vct_islws(buf[0]));
120
121 496
                if (!vct_ishex(buf[0]))
122 0
                         return (VFP_Error(vc, "chunked header non-hex"));
123
124
                /* Collect hex digits, skipping leading zeros */
125 922
                for (u = 1; u < sizeof buf; u++) {
126
                        do {
127 2442
                                lr = v1f_read(vc, htc, buf + u, 1);
128 2442
                                if (lr <= 0)
129 0
                                        return (VFP_Error(vc,
130
                                            "chunked read err"));
131 2442
                        } while (u == 1 && buf[0] == '0' && buf[u] == '0');
132 920
                        if (!vct_ishex(buf[u]))
133 494
                                break;
134
                }
135
136 496
                if (u >= sizeof buf)
137 2
                        return (VFP_Error(vc, "chunked header too long"));
138
139
                /* Skip trailing white space */
140 1482
                while (vct_islws(buf[u]) && buf[u] != '\n') {
141 494
                        lr = v1f_read(vc, htc, buf + u, 1);
142 494
                        if (lr <= 0)
143 0
                                return (VFP_Error(vc, "chunked read err"));
144
                }
145
146 494
                if (buf[u] != '\n')
147 0
                        return (VFP_Error(vc, "chunked header no NL"));
148
149 494
                buf[u] = '\0';
150
151 494
                cll = strtoumax(buf, &q, 16);
152 494
                if (q == NULL || *q != '\0')
153 0
                        return (VFP_Error(vc, "chunked header number syntax"));
154 494
                cl = (ssize_t)cll;
155 494
                if (cl < 0 || (uintmax_t)cl != cll)
156 2
                        return (VFP_Error(vc, "bogusly large chunk size"));
157
158 492
                vfe->priv2 = cl;
159
        }
160 106155
        if (vfe->priv2 > 0) {
161 105981
                if (vfe->priv2 < l)
162 293
                        l = vfe->priv2;
163 105981
                lr = v1f_read(vc, htc, ptr, l);
164 105981
                if (lr <= 0)
165 2
                        return (VFP_Error(vc, "straight insufficient bytes"));
166 105979
                *lp = lr;
167 105979
                vfe->priv2 -= lr;
168 105979
                if (vfe->priv2 == 0)
169 314
                        vfe->priv2 = -1;
170 105979
                return (VFP_OK);
171
        }
172 174
        AZ(vfe->priv2);
173 174
        if (v1f_read(vc, htc, buf, 1) <= 0)
174 0
                return (VFP_Error(vc, "chunked read err"));
175 174
        if (buf[0] == '\r' && v1f_read(vc, htc, buf, 1) <= 0)
176 0
                return (VFP_Error(vc, "chunked read err"));
177 174
        if (buf[0] != '\n')
178 0
                return (VFP_Error(vc, "chunked tail no NL"));
179 174
        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 3038
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 3038
        CHECK_OBJ_NOTNULL(vc, VFP_CTX_MAGIC);
198 3038
        CHECK_OBJ_NOTNULL(vfe, VFP_ENTRY_MAGIC);
199 3038
        CAST_OBJ_NOTNULL(htc, vfe->priv1, HTTP_CONN_MAGIC);
200 3038
        AN(p);
201 3038
        AN(lp);
202
203 3038
        l = *lp;
204 3038
        *lp = 0;
205
206 3038
        if (vfe->priv2 == 0) // XXX: Optimize Content-Len: 0 out earlier
207 0
                return (VFP_END);
208 3038
        if (vfe->priv2 < l)
209 113
                l = vfe->priv2;
210 3038
        lr = v1f_read(vc, htc, p, l);
211 3038
        if (lr <= 0)
212 22
                return (VFP_Error(vc, "straight insufficient bytes"));
213 3016
        *lp = lr;
214 3016
        vfe->priv2 -= lr;
215 3016
        if (vfe->priv2 == 0)
216 1632
                return (VFP_END);
217 1384
        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 124
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 124
        CHECK_OBJ_NOTNULL(vc, VFP_CTX_MAGIC);
234 124
        CHECK_OBJ_NOTNULL(vfe, VFP_ENTRY_MAGIC);
235 124
        CAST_OBJ_NOTNULL(htc, vfe->priv1, HTTP_CONN_MAGIC);
236 124
        AN(p);
237
238 124
        AN(lp);
239
240 124
        l = *lp;
241 124
        *lp = 0;
242 124
        lr = v1f_read(vc, htc, p, l);
243 124
        if (lr < 0)
244 6
                return (VFP_Error(vc, "eof socket fail"));
245 118
        if (lr == 0)
246 32
                return (VFP_END);
247 86
        *lp = lr;
248 86
        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 1984
V1F_Setup_Fetch(struct vfp_ctx *vfc, struct http_conn *htc)
261
{
262
        struct vfp_entry *vfe;
263
264 1984
        CHECK_OBJ_NOTNULL(vfc, VFP_CTX_MAGIC);
265 1984
        CHECK_OBJ_NOTNULL(htc, HTTP_CONN_MAGIC);
266
267 1984
        switch (htc->body_status) {
268
        case BS_EOF:
269 38
                assert(htc->content_length == -1);
270 38
                vfe = VFP_Push(vfc, &v1f_eof);
271 38
                if (vfe == NULL)
272 0
                        return (ENOSPC);
273 38
                vfe->priv2 = 0;
274 38
                break;
275
        case BS_LENGTH:
276 1696
                assert(htc->content_length > 0);
277 1696
                vfe = VFP_Push(vfc, &v1f_straight);
278 1696
                if (vfe == NULL)
279 0
                        return (ENOSPC);
280 1696
                vfe->priv2 = htc->content_length;
281 1696
                break;
282
        case BS_CHUNKED:
283 250
                assert(htc->content_length == -1);
284 250
                vfe = VFP_Push(vfc, &v1f_chunked);
285 250
                if (vfe == NULL)
286 34
                        return (ENOSPC);
287 216
                vfe->priv2 = -1;
288 216
                break;
289
        default:
290 0
                WRONG("Wrong body_status");
291
                break;
292
        }
293 1950
        vfe->priv1 = htc;
294 1950
        return 0;
295
}