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