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 1462161
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 1462161
        ssize_t i = 0;
58
59 1462161
        CHECK_OBJ_NOTNULL(vc, VFP_CTX_MAGIC);
60 1462161
        CHECK_OBJ_NOTNULL(htc, HTTP_CONN_MAGIC);
61 1462161
        assert(len > 0);
62 1462161
        l = 0;
63 1462161
        p = d;
64 1462161
        if (htc->pipeline_b) {
65 77717
                l = htc->pipeline_e - htc->pipeline_b;
66 77717
                assert(l > 0);
67 77717
                l = vmin(l, len);
68 77717
                memcpy(p, htc->pipeline_b, l);
69 77717
                p += l;
70 77717
                len -= l;
71 77717
                htc->pipeline_b += l;
72 77717
                if (htc->pipeline_b == htc->pipeline_e)
73 25366
                        htc->pipeline_b = htc->pipeline_e = NULL;
74 77717
        }
75 1462161
        if (len > 0) {
76 1386221
                i = read(*htc->rfd, p, len);
77 1386221
                if (i < 0) {
78 225
                        VTCP_Assert(i);
79 450
                        VSLbs(vc->wrk->vsl, SLT_FetchError,
80 225
                            TOSTRAND(VAS_errtxt(errno)));
81 225
                        return (i);
82
                }
83 1385996
                if (i == 0)
84 1475
                        htc->doclose = SC_RESP_CLOSE;
85
86 1385996
        }
87 1461936
        return (i + l);
88 1462161
}
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 1331851
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 1331851
        CHECK_OBJ_NOTNULL(vc, VFP_CTX_MAGIC);
109 1331851
        CHECK_OBJ_NOTNULL(vfe, VFP_ENTRY_MAGIC);
110 1331851
        CAST_OBJ_NOTNULL(htc, vfe->priv1, HTTP_CONN_MAGIC);
111 1331851
        AN(ptr);
112 1331851
        AN(lp);
113
114 1331851
        l = *lp;
115 1331851
        *lp = 0;
116 1331851
        if (vfe->priv2 == -1) {
117
                /* Skip leading whitespace */
118 9878
                do {
119 20579
                        lr = v1f_read(vc, htc, buf, 1);
120 20579
                        if (lr <= 0)
121 125
                                return (VFP_Error(vc, "chunked read err"));
122 20454
                } while (vct_islws(buf[0]));
123
124 9753
                if (!vct_ishex(buf[0]))
125 0
                         return (VFP_Error(vc, "chunked header non-hex"));
126
127
                /* Collect hex digits, skipping leading zeros */
128 17678
                for (u = 1; u < sizeof buf; u++) {
129 17652
                        do {
130 37327
                                lr = v1f_read(vc, htc, buf + u, 1);
131 37327
                                if (lr <= 0)
132 0
                                        return (VFP_Error(vc, "chunked read err"));
133 37327
                        } while (u == 1 && buf[0] == '0' && buf[u] == '0');
134 17652
                        if (!vct_ishex(buf[u]))
135 9727
                                break;
136 7925
                }
137
138 9753
                if (u >= sizeof buf)
139 25
                        return (VFP_Error(vc, "chunked header too long"));
140
141
                /* Skip trailing white space */
142 19454
                while (vct_islws(buf[u]) && buf[u] != '\n') {
143 9726
                        lr = v1f_read(vc, htc, buf + u, 1);
144 9726
                        if (lr <= 0)
145 0
                                return (VFP_Error(vc, "chunked read err"));
146
                }
147
148 9728
                if (buf[u] != '\n')
149 0
                        return (VFP_Error(vc, "chunked header no NL"));
150
151 9728
                buf[u] = '\0';
152
153 9728
                cll = strtoumax(buf, &q, 16);
154 9728
                if (q == NULL || *q != '\0')
155 4
                        return (VFP_Error(vc, "chunked header number syntax"));
156 9726
                cl = (ssize_t)cll;
157 9726
                if (cl < 0 || (uintmax_t)cl != cll)
158 25
                        return (VFP_Error(vc, "bogusly large chunk size"));
159
160 9701
                vfe->priv2 = cl;
161 9701
        }
162 1331674
        if (vfe->priv2 > 0) {
163 1328597
                if (vfe->priv2 < l)
164 6110
                        l = vfe->priv2;
165 1328597
                lr = v1f_read(vc, htc, ptr, l);
166 1328597
                if (lr <= 0)
167 25
                        return (VFP_Error(vc, "chunked insufficient bytes"));
168 1328572
                *lp = lr;
169 1328572
                vfe->priv2 -= lr;
170 1328572
                if (vfe->priv2 == 0)
171 6575
                        vfe->priv2 = -1;
172 1328572
                return (VFP_OK);
173
        }
174 3077
        AZ(vfe->priv2);
175 3077
        if (v1f_read(vc, htc, buf, 1) <= 0)
176 0
                return (VFP_Error(vc, "chunked read err"));
177 3077
        if (buf[0] == '\r' && v1f_read(vc, htc, buf, 1) <= 0)
178 0
                return (VFP_Error(vc, "chunked read err"));
179 3077
        if (buf[0] != '\n')
180 0
                return (VFP_Error(vc, "chunked tail no NL"));
181 3077
        return (VFP_END);
182 1331849
}
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 58038
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 58038
        CHECK_OBJ_NOTNULL(vc, VFP_CTX_MAGIC);
200 58038
        CHECK_OBJ_NOTNULL(vfe, VFP_ENTRY_MAGIC);
201 58038
        CAST_OBJ_NOTNULL(htc, vfe->priv1, HTTP_CONN_MAGIC);
202 58038
        AN(p);
203 58038
        AN(lp);
204
205 58038
        l = *lp;
206 58038
        *lp = 0;
207
208 58038
        if (vfe->priv2 == 0) // XXX: Optimize Content-Len: 0 out earlier
209 0
                return (VFP_END);
210 58038
        l = vmin(l, vfe->priv2);
211 58038
        lr = v1f_read(vc, htc, p, l);
212 58038
        if (lr <= 0)
213 575
                return (VFP_Error(vc, "straight insufficient bytes"));
214 57463
        *lp = lr;
215 57463
        vfe->priv2 -= lr;
216 57463
        if (vfe->priv2 == 0)
217 23522
                return (VFP_END);
218 33941
        return (VFP_OK);
219 58038
}
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 1725
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 1725
        CHECK_OBJ_NOTNULL(vc, VFP_CTX_MAGIC);
235 1725
        CHECK_OBJ_NOTNULL(vfe, VFP_ENTRY_MAGIC);
236 1725
        CAST_OBJ_NOTNULL(htc, vfe->priv1, HTTP_CONN_MAGIC);
237 1725
        AN(p);
238
239 1725
        AN(lp);
240
241 1725
        l = *lp;
242 1725
        *lp = 0;
243 1725
        lr = v1f_read(vc, htc, p, l);
244 1725
        if (lr < 0)
245 75
                return (VFP_Error(vc, "eof socket fail"));
246 1650
        if (lr == 0)
247 500
                return (VFP_END);
248 1150
        *lp = lr;
249 1150
        return (VFP_OK);
250 1725
}
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 31348
V1F_Setup_Fetch(struct vfp_ctx *vfc, struct http_conn *htc)
262
{
263
        struct vfp_entry *vfe;
264
265 31348
        CHECK_OBJ_NOTNULL(vfc, VFP_CTX_MAGIC);
266 31348
        CHECK_OBJ_NOTNULL(htc, HTTP_CONN_MAGIC);
267
268 31348
        if (htc->body_status == BS_EOF) {
269 575
                assert(htc->content_length == -1);
270 575
                vfe = VFP_Push(vfc, &v1f_eof);
271 575
                if (vfe == NULL)
272 0
                        return (ENOSPC);
273 575
                vfe->priv2 = 0;
274 31348
        } else if (htc->body_status == BS_LENGTH) {
275 26799
                assert(htc->content_length > 0);
276 26799
                vfe = VFP_Push(vfc, &v1f_straight);
277 26799
                if (vfe == NULL)
278 0
                        return (ENOSPC);
279 26799
                vfe->priv2 = htc->content_length;
280 30773
        } else if (htc->body_status == BS_CHUNKED) {
281 3974
                assert(htc->content_length == -1);
282 3974
                vfe = VFP_Push(vfc, &v1f_chunked);
283 3974
                if (vfe == NULL)
284 400
                        return (ENOSPC);
285 3574
                vfe->priv2 = -1;
286 3574
        } else {
287 0
                WRONG("Wrong body_status");
288
        }
289 30948
        vfe->priv1 = htc;
290 30948
        return (0);
291 31348
}