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 232944
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 232944
        ssize_t i = 0;
58
59 232944
        CHECK_OBJ_NOTNULL(vc, VFP_CTX_MAGIC);
60 232944
        CHECK_OBJ_NOTNULL(htc, HTTP_CONN_MAGIC);
61 232944
        assert(len > 0);
62 232944
        l = 0;
63 232944
        p = d;
64 232944
        if (htc->pipeline_b) {
65 11646
                l = htc->pipeline_e - htc->pipeline_b;
66 11646
                assert(l > 0);
67 11646
                l = vmin(l, len);
68 11646
                memcpy(p, htc->pipeline_b, l);
69 11646
                p += l;
70 11646
                len -= l;
71 11646
                htc->pipeline_b += l;
72 11646
                if (htc->pipeline_b == htc->pipeline_e)
73 4171
                        htc->pipeline_b = htc->pipeline_e = NULL;
74 11646
        }
75 232944
        if (len > 0) {
76 221587
                i = read(*htc->rfd, p, len);
77 221587
                if (i < 0) {
78 36
                        VTCP_Assert(i);
79 72
                        VSLbs(vc->wrk->vsl, SLT_FetchError,
80 36
                            TOSTRAND(VAS_errtxt(errno)));
81 36
                        return (i);
82
                }
83 221551
                assert(i <= len);
84 221551
                if (i == 0)
85 236
                        htc->doclose = SC_RESP_CLOSE;
86 221551
        }
87 232908
        return (i + l);
88 232944
}
89
90
91
/*--------------------------------------------------------------------
92
 * Read a chunked HTTP object.
93
 *
94
 * XXX: Reading one byte at a time is pretty pessimal.
95
 */
96
97
static enum vfp_status v_matchproto_(vfp_pull_f)
98 212618
v1f_chunked_pull(struct vfp_ctx *vc, struct vfp_entry *vfe, void *ptr,
99
    ssize_t *lp)
100
{
101
        struct http_conn *htc;
102
        char buf[20];           /* XXX: 20 is arbitrary */
103
        char *q;
104
        unsigned u;
105
        uintmax_t cll;
106
        ssize_t cl, l, lr;
107
108 212618
        CHECK_OBJ_NOTNULL(vc, VFP_CTX_MAGIC);
109 212618
        CHECK_OBJ_NOTNULL(vfe, VFP_ENTRY_MAGIC);
110 212618
        CAST_OBJ_NOTNULL(htc, vfe->priv1, HTTP_CONN_MAGIC);
111 212618
        AN(ptr);
112 212618
        AN(lp);
113
114 212618
        l = *lp;
115 212618
        *lp = 0;
116 212618
        if (vfe->priv2 == -1) {
117
                /* Skip leading whitespace */
118 1541
                do {
119 3215
                        lr = v1f_read(vc, htc, buf, 1);
120 3215
                        if (lr <= 0)
121 20
                                return (VFP_Error(vc, "chunked read err"));
122 3195
                } while (vct_islws(buf[0]));
123
124 1521
                if (!vct_ishex(buf[0]))
125 0
                         return (VFP_Error(vc, "chunked header non-hex"));
126
127
                /* Collect hex digits, skipping leading zeros */
128 2753
                for (u = 1; u < sizeof buf; u++) {
129 2749
                        do {
130 5429
                                lr = v1f_read(vc, htc, buf + u, 1);
131 5429
                                if (lr <= 0)
132 0
                                        return (VFP_Error(vc, "chunked read err"));
133 5429
                        } while (u == 1 && buf[0] == '0' && buf[u] == '0');
134 2749
                        if (!vct_ishex(buf[u]))
135 1517
                                break;
136 1232
                }
137
138 1521
                if (u >= sizeof buf)
139 4
                        return (VFP_Error(vc, "chunked header too long"));
140
141
                /* Skip trailing white space */
142 3034
                while (vct_islws(buf[u]) && buf[u] != '\n') {
143 1517
                        lr = v1f_read(vc, htc, buf + u, 1);
144 1517
                        if (lr <= 0)
145 0
                                return (VFP_Error(vc, "chunked read err"));
146
                }
147
148 1517
                if (buf[u] != '\n')
149 0
                        return (VFP_Error(vc, "chunked header no NL"));
150
151 1517
                buf[u] = '\0';
152
153 1517
                cll = strtoumax(buf, &q, 16);
154 1517
                if (q == NULL || *q != '\0')
155 0
                        return (VFP_Error(vc, "chunked header number syntax"));
156 1517
                cl = (ssize_t)cll;
157 1517
                if (cl < 0 || (uintmax_t)cl != cll)
158 4
                        return (VFP_Error(vc, "bogusly large chunk size"));
159
160 1513
                vfe->priv2 = cl;
161 1513
        }
162 212590
        if (vfe->priv2 > 0) {
163 212117
                if (vfe->priv2 < l)
164 951
                        l = vfe->priv2;
165 212117
                lr = v1f_read(vc, htc, ptr, l);
166 212117
                if (lr <= 0)
167 4
                        return (VFP_Error(vc, "chunked insufficient bytes"));
168 212113
                *lp = lr;
169 212113
                vfe->priv2 -= lr;
170 212113
                if (vfe->priv2 == 0)
171 1032
                        vfe->priv2 = -1;
172 212113
                return (VFP_OK);
173
        }
174 473
        AZ(vfe->priv2);
175 473
        if (v1f_read(vc, htc, buf, 1) <= 0)
176 0
                return (VFP_Error(vc, "chunked read err"));
177 473
        if (buf[0] == '\r' && v1f_read(vc, htc, buf, 1) <= 0)
178 0
                return (VFP_Error(vc, "chunked read err"));
179 473
        if (buf[0] != '\n')
180 0
                return (VFP_Error(vc, "chunked tail no NL"));
181 473
        return (VFP_END);
182 212618
}
183
184
static const struct vfp v1f_chunked = {
185
        .name = "V1F_CHUNKED",
186
        .pull = v1f_chunked_pull,
187
};
188
189
190
/*--------------------------------------------------------------------*/
191
192
static enum vfp_status v_matchproto_(vfp_pull_f)
193 9445
v1f_straight_pull(struct vfp_ctx *vc, struct vfp_entry *vfe, void *p,
194
    ssize_t *lp)
195
{
196
        ssize_t l, lr;
197
        struct http_conn *htc;
198
199 9445
        CHECK_OBJ_NOTNULL(vc, VFP_CTX_MAGIC);
200 9445
        CHECK_OBJ_NOTNULL(vfe, VFP_ENTRY_MAGIC);
201 9445
        CAST_OBJ_NOTNULL(htc, vfe->priv1, HTTP_CONN_MAGIC);
202 9445
        AN(p);
203 9445
        AN(lp);
204
205 9445
        l = *lp;
206 9445
        *lp = 0;
207
208 9445
        if (vfe->priv2 == 0) // XXX: Optimize Content-Len: 0 out earlier
209 0
                return (VFP_END);
210 9445
        l = vmin(l, vfe->priv2);
211 9445
        lr = v1f_read(vc, htc, p, l);
212 9445
        if (lr <= 0)
213 92
                return (VFP_Error(vc, "straight insufficient bytes"));
214 9353
        *lp = lr;
215 9353
        vfe->priv2 -= lr;
216 9353
        if (vfe->priv2 == 0)
217 3916
                return (VFP_END);
218 5437
        return (VFP_OK);
219 9445
}
220
221
static const struct vfp v1f_straight = {
222
        .name = "V1F_STRAIGHT",
223
        .pull = v1f_straight_pull,
224
};
225
226
/*--------------------------------------------------------------------*/
227
228
static enum vfp_status v_matchproto_(vfp_pull_f)
229 276
v1f_eof_pull(struct vfp_ctx *vc, struct vfp_entry *vfe, void *p, ssize_t *lp)
230
{
231
        ssize_t l, lr;
232
        struct http_conn *htc;
233
234 276
        CHECK_OBJ_NOTNULL(vc, VFP_CTX_MAGIC);
235 276
        CHECK_OBJ_NOTNULL(vfe, VFP_ENTRY_MAGIC);
236 276
        CAST_OBJ_NOTNULL(htc, vfe->priv1, HTTP_CONN_MAGIC);
237 276
        AN(p);
238
239 276
        AN(lp);
240
241 276
        l = *lp;
242 276
        *lp = 0;
243 276
        lr = v1f_read(vc, htc, p, l);
244 276
        if (lr < 0)
245 12
                return (VFP_Error(vc, "eof socket fail"));
246 264
        if (lr == 0)
247 80
                return (VFP_END);
248 184
        *lp = lr;
249 184
        return (VFP_OK);
250 276
}
251
252
static const struct vfp v1f_eof = {
253
        .name = "V1F_EOF",
254
        .pull = v1f_eof_pull,
255
};
256
257
/*--------------------------------------------------------------------
258
 */
259
260
int
261 5143
V1F_Setup_Fetch(struct vfp_ctx *vfc, struct http_conn *htc)
262
{
263
        struct vfp_entry *vfe;
264
265 5143
        CHECK_OBJ_NOTNULL(vfc, VFP_CTX_MAGIC);
266 5143
        CHECK_OBJ_NOTNULL(htc, HTTP_CONN_MAGIC);
267
268 5143
        if (htc->body_status == BS_EOF) {
269 92
                assert(htc->content_length == -1);
270 92
                vfe = VFP_Push(vfc, &v1f_eof);
271 92
                if (vfe == NULL)
272 0
                        return (ENOSPC);
273 92
                vfe->priv2 = 0;
274 5143
        } else if (htc->body_status == BS_LENGTH) {
275 4439
                assert(htc->content_length > 0);
276 4439
                vfe = VFP_Push(vfc, &v1f_straight);
277 4439
                if (vfe == NULL)
278 0
                        return (ENOSPC);
279 4439
                vfe->priv2 = htc->content_length;
280 5051
        } else if (htc->body_status == BS_CHUNKED) {
281 612
                assert(htc->content_length == -1);
282 612
                vfe = VFP_Push(vfc, &v1f_chunked);
283 612
                if (vfe == NULL)
284 64
                        return (ENOSPC);
285 548
                vfe->priv2 = -1;
286 548
        } else {
287 0
                WRONG("Wrong body_status");
288
        }
289 5079
        vfe->priv1 = htc;
290 5079
        return (0);
291 5143
}