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 <inttypes.h>
39
40
#include "cache/cache_varnishd.h"
41
#include "cache/cache_filter.h"
42
#include "cache_http1.h"
43
44
#include "vct.h"
45
46
/*--------------------------------------------------------------------
47
 * Read up to len bytes, returning pipelined data first.
48
 */
49
50
static ssize_t
51 456831
v1f_read(const struct vfp_ctx *vc, struct http_conn *htc, void *d, ssize_t len)
52
{
53
        ssize_t l;
54
        unsigned char *p;
55 456831
        ssize_t i = 0;
56
57 456831
        CHECK_OBJ_NOTNULL(vc, VFP_CTX_MAGIC);
58 456835
        CHECK_OBJ_NOTNULL(htc, HTTP_CONN_MAGIC);
59 456834
        assert(len > 0);
60 456835
        l = 0;
61 456835
        p = d;
62 456835
        if (htc->pipeline_b) {
63 23208
                l = htc->pipeline_e - htc->pipeline_b;
64 23208
                assert(l > 0);
65 23208
                if (l > len)
66 15901
                        l = len;
67 23208
                memcpy(p, htc->pipeline_b, l);
68 23208
                p += l;
69 23208
                len -= l;
70 23208
                htc->pipeline_b += l;
71 23208
                if (htc->pipeline_b == htc->pipeline_e)
72 7307
                        htc->pipeline_b = htc->pipeline_e = NULL;
73 23208
        }
74 456835
        if (len > 0) {
75 434043
                i = read(*htc->rfd, p, len);
76 434043
                if (i < 0) {
77
                        // XXX: VTCP_Assert(i); // but also: EAGAIN
78 48
                        VSLb(vc->wrk->vsl, SLT_FetchError,
79 24
                            "%s", vstrerror(errno));
80 24
                        return (i);
81
                }
82 434018
        }
83 456807
        return (i + l);
84 456831
}
85
86
87
/*--------------------------------------------------------------------
88
 * Read a chunked HTTP object.
89
 *
90
 * XXX: Reading one byte at a time is pretty pessimal.
91
 */
92
93
static enum vfp_status v_matchproto_(vfp_pull_f)
94 425074
v1f_pull_chunked(struct vfp_ctx *vc, struct vfp_entry *vfe, void *ptr,
95
    ssize_t *lp)
96
{
97
        struct http_conn *htc;
98
        char buf[20];           /* XXX: 20 is arbitrary */
99
        char *q;
100
        unsigned u;
101
        uintmax_t cll;
102
        ssize_t cl, l, lr;
103
104 425074
        CHECK_OBJ_NOTNULL(vc, VFP_CTX_MAGIC);
105 425074
        CHECK_OBJ_NOTNULL(vfe, VFP_ENTRY_MAGIC);
106 425074
        CAST_OBJ_NOTNULL(htc, vfe->priv1, HTTP_CONN_MAGIC);
107 425074
        AN(ptr);
108 425073
        AN(lp);
109
110 425073
        l = *lp;
111 425073
        *lp = 0;
112 425073
        if (vfe->priv2 == -1) {
113
                /* Skip leading whitespace */
114 2416
                do {
115 5313
                        lr = v1f_read(vc, htc, buf, 1);
116 5313
                        if (lr <= 0)
117 40
                                return (VFP_Error(vc, "chunked read err"));
118 5274
                } while (vct_islws(buf[0]));
119
120 2377
                if (!vct_ishex(buf[0]))
121 0
                         return (VFP_Error(vc, "chunked header non-hex"));
122
123
                /* Collect hex digits, skipping leading zeros */
124 4241
                for (u = 1; u < sizeof buf; u++) {
125 4233
                        do {
126 10321
                                lr = v1f_read(vc, htc, buf + u, 1);
127 10321
                                if (lr <= 0)
128 0
                                        return (VFP_Error(vc,
129
                                            "chunked read err"));
130 10321
                        } while (u == 1 && buf[0] == '0' && buf[u] == '0');
131 4233
                        if (!vct_ishex(buf[u]))
132 2369
                                break;
133 1864
                }
134
135 2377
                if (u >= sizeof buf)
136 8
                        return (VFP_Error(vc, "chunked header too long"));
137
138
                /* Skip trailing white space */
139 4737
                while (vct_islws(buf[u]) && buf[u] != '\n') {
140 2368
                        lr = v1f_read(vc, htc, buf + u, 1);
141 2368
                        if (lr <= 0)
142 0
                                return (VFP_Error(vc, "chunked read err"));
143
                }
144
145 2369
                if (buf[u] != '\n')
146 0
                        return (VFP_Error(vc, "chunked header no NL"));
147
148 2369
                buf[u] = '\0';
149
150 2369
                cll = strtoumax(buf, &q, 16);
151 2369
                if (q == NULL || *q != '\0')
152 0
                        return (VFP_Error(vc, "chunked header number syntax"));
153 2369
                cl = (ssize_t)cll;
154 2369
                if (cl < 0 || (uintmax_t)cl != cll)
155 8
                        return (VFP_Error(vc, "bogusly large chunk size"));
156
157 2361
                vfe->priv2 = cl;
158 2361
        }
159 425018
        if (vfe->priv2 > 0) {
160 424193
                if (vfe->priv2 < l)
161 1359
                        l = vfe->priv2;
162 424193
                lr = v1f_read(vc, htc, ptr, l);
163 424193
                if (lr <= 0)
164 8
                        return (VFP_Error(vc, "chunked insufficient bytes"));
165 424185
                *lp = lr;
166 424185
                vfe->priv2 -= lr;
167 424185
                if (vfe->priv2 == 0)
168 1520
                        vfe->priv2 = -1;
169 424185
                return (VFP_OK);
170
        }
171 825
        AZ(vfe->priv2);
172 825
        if (v1f_read(vc, htc, buf, 1) <= 0)
173 0
                return (VFP_Error(vc, "chunked read err"));
174 825
        if (buf[0] == '\r' && v1f_read(vc, htc, buf, 1) <= 0)
175 0
                return (VFP_Error(vc, "chunked read err"));
176 825
        if (buf[0] != '\n')
177 0
                return (VFP_Error(vc, "chunked tail no NL"));
178 825
        return (VFP_END);
179 425074
}
180
181
static const struct vfp v1f_chunked = {
182
        .name = "V1F_CHUNKED",
183
        .pull = v1f_pull_chunked,
184
};
185
186
187
/*--------------------------------------------------------------------*/
188
189
static enum vfp_status v_matchproto_(vfp_pull_f)
190 12476
v1f_pull_straight(struct vfp_ctx *vc, struct vfp_entry *vfe, void *p,
191
    ssize_t *lp)
192
{
193
        ssize_t l, lr;
194
        struct http_conn *htc;
195
196 12476
        CHECK_OBJ_NOTNULL(vc, VFP_CTX_MAGIC);
197 12476
        CHECK_OBJ_NOTNULL(vfe, VFP_ENTRY_MAGIC);
198 12476
        CAST_OBJ_NOTNULL(htc, vfe->priv1, HTTP_CONN_MAGIC);
199 12476
        AN(p);
200 12476
        AN(lp);
201
202 12476
        l = *lp;
203 12476
        *lp = 0;
204
205 12476
        if (vfe->priv2 == 0) // XXX: Optimize Content-Len: 0 out earlier
206 0
                return (VFP_END);
207 12476
        if (vfe->priv2 < l)
208 519
                l = vfe->priv2;
209 12476
        lr = v1f_read(vc, htc, p, l);
210 12476
        if (lr <= 0)
211 88
                return (VFP_Error(vc, "straight insufficient bytes"));
212 12388
        *lp = lr;
213 12388
        vfe->priv2 -= lr;
214 12388
        if (vfe->priv2 == 0)
215 6745
                return (VFP_END);
216 5643
        return (VFP_OK);
217 12476
}
218
219
static const struct vfp v1f_straight = {
220
        .name = "V1F_STRAIGHT",
221
        .pull = v1f_pull_straight,
222
};
223
224
/*--------------------------------------------------------------------*/
225
226
static enum vfp_status v_matchproto_(vfp_pull_f)
227 512
v1f_pull_eof(struct vfp_ctx *vc, struct vfp_entry *vfe, void *p, ssize_t *lp)
228
{
229
        ssize_t l, lr;
230
        struct http_conn *htc;
231
232 512
        CHECK_OBJ_NOTNULL(vc, VFP_CTX_MAGIC);
233 512
        CHECK_OBJ_NOTNULL(vfe, VFP_ENTRY_MAGIC);
234 512
        CAST_OBJ_NOTNULL(htc, vfe->priv1, HTTP_CONN_MAGIC);
235 512
        AN(p);
236
237 512
        AN(lp);
238
239 512
        l = *lp;
240 512
        *lp = 0;
241 512
        lr = v1f_read(vc, htc, p, l);
242 512
        if (lr < 0)
243 24
                return (VFP_Error(vc, "eof socket fail"));
244 488
        if (lr == 0)
245 136
                return (VFP_END);
246 352
        *lp = lr;
247 352
        return (VFP_OK);
248 512
}
249
250
static const struct vfp v1f_eof = {
251
        .name = "V1F_EOF",
252
        .pull = v1f_pull_eof,
253
};
254
255
/*--------------------------------------------------------------------
256
 */
257
258
int
259 8304
V1F_Setup_Fetch(struct vfp_ctx *vfc, struct http_conn *htc)
260
{
261
        struct vfp_entry *vfe;
262
263 8304
        CHECK_OBJ_NOTNULL(vfc, VFP_CTX_MAGIC);
264 8304
        CHECK_OBJ_NOTNULL(htc, HTTP_CONN_MAGIC);
265
266 8304
        switch (htc->body_status) {
267
        case BS_EOF:
268 160
                assert(htc->content_length == -1);
269 160
                vfe = VFP_Push(vfc, &v1f_eof);
270 160
                if (vfe == NULL)
271 0
                        return (ENOSPC);
272 160
                vfe->priv2 = 0;
273 160
                break;
274
        case BS_LENGTH:
275 7016
                assert(htc->content_length > 0);
276 7016
                vfe = VFP_Push(vfc, &v1f_straight);
277 7016
                if (vfe == NULL)
278 0
                        return (ENOSPC);
279 7016
                vfe->priv2 = htc->content_length;
280 7016
                break;
281
        case BS_CHUNKED:
282 1128
                assert(htc->content_length == -1);
283 1128
                vfe = VFP_Push(vfc, &v1f_chunked);
284 1128
                if (vfe == NULL)
285 136
                        return (ENOSPC);
286 992
                vfe->priv2 = -1;
287 992
                break;
288
        default:
289 0
                WRONG("Wrong body_status");
290 0
                break;
291
        }
292 8168
        vfe->priv1 = htc;
293 8168
        return (0);
294 8304
}