vinyl-cache/bin/vinyld/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
#include <poll.h>
41
42
#include "cache/cache_int.h"
43
#ifndef TEST_DRIVER
44
# include "cache/cache_filter.h"
45
#endif
46
#include "cache_http1.h"
47
48
#include "vct.h"
49
#include "vtcp.h"
50
51
static const unsigned max_chunked_hdr = 32;     // adjust b00007.vtc if changed
52
53
#ifndef TEST_DRIVER
54
static ssize_t
55 2346
v1f_rxbuf_init(struct http_conn *htc)
56
{
57
58 2346
        AZ(htc->rxbuf_b);
59 2346
        AZ(htc->rxbuf_e);
60
61 2346
        htc->rxbuf_b = WS_Alloc(htc->ws, max_chunked_hdr);
62 2346
        if (htc->rxbuf_b == NULL)
63 0
                return (-1);
64 2346
        htc->rxbuf_e = htc->rxbuf_b + max_chunked_hdr;
65 2346
        return (0);
66 2346
}
67
#endif
68
69
/*
70
 * fill up rxbuf. If there is pipelined data, move it to the beginning and
71
 * continue reading after it
72
 */
73
static ssize_t
74 4149
v1f_rxbuf_read(struct http_conn *htc)
75
{
76
        ssize_t i;
77
        size_t av, sz;
78
        char *p;
79
80 4149
        if (htc->pipeline_b)
81 989
                AN(htc->pipeline_e);
82
        else
83 3160
                AZ(htc->pipeline_e);
84 4149
        AN(htc->rxbuf_b);
85 4149
        AN(htc->rxbuf_e);
86
87 4149
        sz = pdiff(htc->rxbuf_b, htc->rxbuf_e);
88
89 4149
        if (htc->pipeline_b == NULL)
90 3160
                p = htc->pipeline_b = htc->rxbuf_b;
91
        else {
92 989
                AN(htc->pipeline_e);
93 989
                av = pdiff(htc->pipeline_b, htc->pipeline_e);
94 989
                if (av >= sz) {
95
                        // VTCP_Check(): can not originate from read()
96 42
                        errno = ENOBUFS;
97 42
                        return (-1);
98
                }
99 947
                assert(av < sz);
100 947
                vmemmove(htc->rxbuf_b, htc->pipeline_b, av);
101 947
                htc->pipeline_b = htc->rxbuf_b;
102 947
                htc->pipeline_e = htc->rxbuf_b + av;
103 947
                p = htc->pipeline_e;
104 947
                sz -= av;
105
        }
106 4107
        do {
107 4107
                errno = 0;
108 4107
                i = read(*htc->rfd, p, sz);
109 4107
        } while (i < 0 && errno == EINTR);
110 4107
        if (i < 0) {
111 0
                VTCP_Assert(i);
112 0
                return (i);
113
        }
114 4107
        htc->pipeline_e = p + i;
115 4107
        if (htc->pipeline_b == htc->pipeline_e)
116 105
                 htc->pipeline_b = htc->pipeline_e = NULL;
117 4107
        return (i);
118 4149
}
119
120
/*--------------------------------------------------------------------
121
 * Parse a chunk tail in the pipeline and return status as appropriate
122
 */
123
struct pct { const char *msg; };
124
125
static struct pct pct_more[]    = {{"tail more"}};
126
static struct pct pct_nonl[]    = {{"chunked tail no NL"}};
127
128
// the unused parameter is to simplify the macro calling different parsers
129
static struct pct *
130 57403
v1f_parse_chunked_tail(char *b, const char *e, void *unused, char **nextp)
131
{
132 57403
        AN(b);
133 57403
        AN(e);
134 57403
        (void)unused;
135 57403
        AN(nextp);
136
137 57403
        if (b == e)
138 105
                return (pct_more);
139 57298
        if (*b == '\r')
140 56248
                b++;
141 57298
        if (b == e)
142 126
                return (pct_more);
143 57172
        if (*b != '\n')
144 84
                return (pct_nonl);
145 57088
        b++;
146
147 57088
        *nextp = b;
148 57088
        return (NULL);
149 57403
}
150
151
152
/*--------------------------------------------------------------------
153
 * Parse a chunk header in the pipeline and return status as appropriate
154
 */
155
156
struct pch { const char *msg; };
157
158
static struct pch pch_more[]    = {{"more"}};
159
static struct pch pch_nonhex[]  = {{"chunked header non-hex"}};
160
static struct pch pch_nonl[]    = {{"chunked header no NL"}};
161
static struct pch pch_syntax[]  = {{"chunked header number syntax"}}; // can't happen?
162
static struct pch pch_large[]   = {{"bogusly large chunk size"}};
163
static struct pch pch_toolong[] = {{"chunked header too long"}};
164
165
static struct pch *
166 169665
v1f_parse_chunked_hdr_i(char *b, const char *e, ssize_t *szp, char **nextp)
167
{
168
        char *hb, *he, *q, s;
169
        uintmax_t cll;
170
        ssize_t cl;
171
172 169665
        AN(b);
173 169665
        AN(e);
174 169665
        AN(szp);
175 169665
        AN(nextp);
176
177
        /* Skip leading whitespace - XXX rfc9112 does not specify this */
178 252111
        while (b < e && vct_isows(*b))
179 82446
                b++;
180 169661
        if (b == e)
181 22722
                return (pch_more);
182 146939
        if (!vct_ishex(*b))
183 126
                return (pch_nonhex);
184
        /* Skip leading zeros */
185 187301
        while (b < e - 1 && b[0] == '0' && b[1] == '0')
186 40488
                b++;
187 146813
        if (b == e)
188 0
                return (pch_more);
189 146813
        hb = b;
190
        /* Collect hex digits */
191 731069
        while (b < e && vct_ishex(*b))
192 584256
                b++;
193 146813
        if (b == e)
194 60375
                return (pch_more);
195 86438
        he = b;
196
        /* Skip trailing whitespace. XXX rfc9112 does not specify this
197
         * XXX extension support missing https://httpwg.org/specs/rfc9112.html#chunked.extension
198
         */
199 111638
        while (b < e && vct_isows(*b))
200 25200
                b++;
201 86438
        if (b == e)
202 9450
                return (pch_more);
203 76988
        if (*b == '\r')
204 70618
                b++;
205 76988
        if (b == e)
206 7142
                return (pch_more);
207 69846
        if (*b != '\n')
208 42
                return (pch_nonl);
209 69804
        b++;
210
211 69804
        errno = 0;
212 69804
        s = *he;
213 69804
        *he = '\0';
214 69804
        cll = strtoumax(hb, &q, 16);
215
        // restore original for debug-/testability
216 69804
        *he = s;
217
218 69804
        if (q == NULL || q != he)
219 14
                return (pch_syntax);
220
221 69790
        cl = (ssize_t)cll;
222 69790
        if (cl < 0 || (uintmax_t)cl != cll)
223 84
                return (pch_large);
224
225
        // for a number larger than ULLONG_MAX, strtoumax() returns
226
        // ULLONG_MAX and sets errno to ERANGE. We catch this with the above
227
        // check already, but assert that we really do
228 69712
        AZ(errno);
229
230 69712
        *szp = cl;
231 69712
        *nextp = b;
232 69712
        return (NULL);
233 169653
}
234
235
// length check outside the actual parser for clarity
236
static struct pch *
237 169654
v1f_parse_chunked_hdr(char *b, const char *e, ssize_t *szp, char **nextp)
238
{
239
        struct pch *r;
240
        const char *ee;
241
242 169654
        ee = vmin_t(const char *, e, b + max_chunked_hdr);
243
244 169654
        r = v1f_parse_chunked_hdr_i(b, ee, szp, nextp);
245
246 169654
        if (r == pch_more && e != ee)
247 21
                return (pch_toolong);
248
249 169633
        return (r);
250 169654
}
251
252
#ifdef TEST_DRIVER
253
254
#include <stdlib.h>
255
#include <stdio.h>
256
257
// positive test cases have three constituents, we permutate all of them
258
static const char *t_ok_pre[] = {
259
        "",
260
        " ",
261
        "\t",
262
        " \t0",
263
        "00"
264
};
265
266
static const uintmax_t t_ok_sz[] = {
267
        0,
268
        1,
269
        0xa,
270
        0x10,
271
        0xaffe,
272
        SSIZE_MAX
273
};
274
275
static const char *t_ok_post[] = {
276
        "\r\n",
277
        "\n",
278
        " \r\n",
279
        " \t\n",
280
};
281
282
static const char *t_ok_next[] = {
283
        "",
284
        "\r\n",
285
        "\n",
286
        "GET",
287
        "\r\n01234567",
288
};
289
290
struct pch_neg {
291
        struct pch *r;
292
        const char *hdr;
293
};
294
295
// negative tests
296
static struct pch_neg t_neg[] = {
297
        {pch_more, ""},
298
        {pch_more, "\t "},
299
300
        {pch_nonhex, "x"},
301
        {pch_nonhex, " x"},
302
        {pch_nonhex, "\n"},
303
        {pch_nonhex, "\r"},
304
305
        {pch_more, "000"},
306
        {pch_more, "affe"},
307
        {pch_more, " a\r"},
308
309
        {pch_nonl, " a\rx"},
310
        {pch_nonl, " ax"},
311
312
        {pch_large, "8000000000000000\r\n"},
313
        {pch_large, "800000000000000000000000\r\n"},
314
};
315
316
// tail
317
static const char *t_ok_tail[] = {
318
        "\r\n",
319
        "\n",
320
};
321
322
static const char *t_ok_tail_next[] = {
323
        "",
324
        "0123",
325
};
326
327
struct pct_neg {
328
        struct pct *r;
329
        const char *hdr;
330
};
331
332
static struct pct_neg t_neg_tail[] = {
333
        {pct_more, "\r"},
334
        {pct_nonl, "\rx"},
335
};
336
337
338
static void
339 111363
t_parse_chunked_hdr(char *b, char *e,
340
    const struct pch *r_exp, ssize_t sz_exp, const char *next_exp)
341
{
342
        const struct pch *r;
343 111363
        char *next = NULL;
344 111363
        ssize_t sz = -1;
345 111363
        r = v1f_parse_chunked_hdr(b, e, &sz, &next);
346
#ifdef DEBUG
347
        printf("r = %s, sz = 0x%zx, n = %s\n", r ? r->msg : "NULL", sz,
348
            next ? next : "NULL");
349
#endif
350 111363
        assert(r == r_exp);
351 111363
        assert(sz == sz_exp);
352 111363
        assert(next == next_exp);
353 111363
}
354
355
static void
356 98763
t_parse_chunked_hdr_err(char *b, char *e, const struct pch *err)
357
{
358 98763
        t_parse_chunked_hdr(b, e, err, -1, NULL);
359 98763
}
360
361
static void
362 12600
t_parse_chunked_hdr_ok(char *b, char *e,
363
    ssize_t sz_exp, const char *next_exp)
364
{
365 12600
        t_parse_chunked_hdr(b, e, NULL, sz_exp, next_exp);
366 12600
}
367
368
static void
369 252
t_parse_chunked_tail(char *b, char *e,
370
    const struct pct *r_exp, const char *next_exp)
371
{
372
        const struct pct *r;
373 252
        char *next = NULL;
374 252
        r = v1f_parse_chunked_tail(b, e, NULL, &next);
375
#ifdef DEBUG
376
        printf("r = %s, n = %s\n", r ? r->msg : "NULL",
377
            next ? next : "NULL");
378
#endif
379 252
        assert(r == r_exp);
380 252
        assert(next == next_exp);
381 252
}
382
383
void
384 0
VSLbs(struct vsl_log *vsl, enum VSL_tag_e tag, const struct strands *s)
385
{
386 0
        (void)vsl;
387 0
        (void)tag;
388 0
        (void)s;
389 0
}
390
/*
391
static ssize_t
392
v1f_rxbuf_read(struct http_conn *htc);
393
*/
394
static void
395 21
t_rxbuf_read(void) {
396
        struct http_conn htc[1];
397 21
        const char *data = "0123456789abcdef";
398
        char rxbuf[16];
399
        int fd[2], i, r;
400
401 21
        assert(vstrlen(data) == sizeof rxbuf);
402
403 21
        INIT_OBJ(htc, HTTP_CONN_MAGIC);
404
        // v1f_rxbuf_init without the workspace
405 21
        htc->rxbuf_b = rxbuf;
406 21
        htc->rxbuf_e = htc->rxbuf_b + sizeof rxbuf;
407
408 21
        AZ(pipe(fd));
409 21
        htc->rfd = &fd[0];
410
411 357
        for (i = 0; i < vstrlen(data); i++) {
412 336
                r = write(fd[1], data + i, 1);
413 336
                assert(r == 1);
414 336
                r = v1f_rxbuf_read(htc);
415 336
                assert(r == 1);
416 336
                size_t av = pdiff(htc->pipeline_b, htc->pipeline_e);
417 336
                assert(av == i + 1);
418 336
                AZ(vmemcmp(htc->pipeline_b, data, av));
419 336
                if (i % 2 == 0) {
420
                        // v1f_rxbuf_read moves pipelined data to the beginning
421 168
                        assert(htc->pipeline_b == htc->rxbuf_b);
422 168
                        vmemmove(htc->pipeline_b + 1, htc->pipeline_b, av);
423 168
                        htc->pipeline_b++;
424 168
                        htc->pipeline_e++;
425 168
                }
426
427 336
        }
428
        // buffer is now full
429 21
        r = v1f_rxbuf_read(htc);
430 21
        assert(r == -1);
431 21
        assert(errno == ENOBUFS);
432
433 21
        close(fd[0]);
434 21
        close(fd[1]);
435 21
}
436
437
int
438 21
main(int argc, char *argv[])
439
{
440 21
        (void) argc;
441 21
        (void) argv;
442
443 21
        printf("-- rxbuf_read\n");
444 21
        t_rxbuf_read();
445
446 21
        printf("-- head postitive test permutations\n");
447
        // avoid nested loops
448 21
        unsigned n_ok = vcountof(t_ok_pre) * vcountof(t_ok_sz) *
449
            vcountof(t_ok_post) * vcountof(t_ok_next);
450
        char buf[80];
451 12621
        for (unsigned n = 0; n < n_ok; n++) {
452 12600
                unsigned n_pre = n % vcountof(t_ok_pre);
453 12600
                unsigned n_sz = n / vcountof(t_ok_pre);
454 12600
                unsigned n_post = n_sz / vcountof(t_ok_sz);
455 12600
                unsigned n_next = n_post / vcountof(t_ok_post);
456 12600
                n_sz %= vcountof(t_ok_sz);
457 12600
                n_post %= vcountof(t_ok_post);
458 12600
                assert(n_next < vcountof(t_ok_next));
459
460
#ifdef DEBUG
461
                printf("n_next=%u n_post=%u n_sz=%u n_pre=%u\n",
462
                    n_next, n_post, n_sz, n_pre);
463
#endif
464 12600
                bprintf(buf, "%s%jx%s%s", t_ok_pre[n_pre], t_ok_sz[n_sz],
465
                    t_ok_post[n_post], t_ok_next[n_next]);
466
467 12600
                char *ee = buf + vstrlen(buf) - vstrlen(t_ok_next[n_next]);
468
469 111090
                for (char *e = buf; e < ee; e++)
470 98490
                        t_parse_chunked_hdr_err(buf, e, pch_more);
471
472 12600
                t_parse_chunked_hdr_ok(buf, ee, t_ok_sz[n_sz], ee);
473 12600
        }
474
475 21
        printf("-- head negative tests\n");
476 294
        for (struct pch_neg *neg = t_neg; neg < t_neg + vcountof(t_neg); neg++) {
477 273
                size_t l = vstrlen(neg->hdr);
478 273
                assert(l < sizeof buf);
479
480 273
                vmemcpy(buf, neg->hdr, l + 1);
481 273
                char *e = buf + l;
482
483 273
                t_parse_chunked_hdr_err(buf, e, neg->r);
484 273
        }
485
486 21
        printf("-- tail postitive test permutations\n");
487 21
        n_ok = vcountof(t_ok_tail) * vcountof(t_ok_tail_next);
488 105
        for (unsigned n = 0; n < n_ok; n++) {
489 84
                unsigned n_tail = n % vcountof(t_ok_tail);
490 84
                unsigned n_next = n / vcountof(t_ok_tail_next);
491 84
                assert(n_next < vcountof(t_ok_tail_next));
492
493 84
                bprintf(buf, "%s%s", t_ok_tail[n_tail], t_ok_tail_next[n_next]);
494 84
                char *ee = buf + vstrlen(buf) - vstrlen(t_ok_tail_next[n_next]);
495
496 210
                for (char *e = buf; e < ee; e++)
497 126
                        t_parse_chunked_tail(buf, e, pct_more, NULL);
498
499 84
                t_parse_chunked_tail(buf, ee, NULL, ee);
500 84
        }
501
502 21
        printf("-- tail negative tests\n");
503 63
        for (struct pct_neg *neg = t_neg_tail; neg < t_neg_tail + vcountof(t_neg_tail); neg++) {
504 42
                size_t l = vstrlen(neg->hdr);
505 42
                assert(l < sizeof buf);
506
507 42
                vmemcpy(buf, neg->hdr, l + 1);
508 42
                char *e = buf + l;
509
510 42
                t_parse_chunked_tail(buf, e, neg->r, NULL);
511 42
        }
512
513 21
        printf("OK\n");
514 21
        return (0);
515
}
516
#else
517
518
/*--------------------------------------------------------------------
519
 * Read up to len bytes, returning pipelined data first.
520
 */
521
522
enum ahead {
523
        NO_READ_AHEAD,
524
        READ_AHEAD
525
};
526
527
static ssize_t
528 45753
v1f_readahead(struct http_conn *htc, char *p, ssize_t len)
529
{
530
        struct iovec iov[2];
531
        ssize_t i;
532
533 45753
        AZ(htc->pipeline_b);
534 45753
        if (htc->rxbuf_b == NULL && v1f_rxbuf_init(htc)) {
535 0
                errno = ENOMEM;
536 0
                return (-ENOMEM);
537
        }
538 45753
        AN(htc->rxbuf_b);
539
540 45753
        iov[0].iov_base = p;
541 45753
        iov[0].iov_len = len;
542 45753
        iov[1].iov_base = htc->rxbuf_b;
543 45753
        iov[1].iov_len = pdiff(htc->rxbuf_b, htc->rxbuf_e);
544
545 45753
        i = readv(*htc->rfd, iov, vcountof(iov));
546 45753
        if (i <= len)
547 147
                return (i);
548 45606
        i -= len;
549 45606
        htc->pipeline_b = htc->rxbuf_b;
550 45606
        htc->pipeline_e = htc->rxbuf_b + i;
551
552 45606
        return (len);
553 45753
}
554
555
static ssize_t
556 1214982
v1f_read(const struct vfp_ctx *vc, struct http_conn *htc, void *d, ssize_t len,
557
    enum ahead ahead)
558
{
559
        ssize_t l;
560
        char *p;
561
        ssize_t i;
562
563 1214982
        CHECK_OBJ_NOTNULL(vc, VFP_CTX_MAGIC);
564 1214982
        CHECK_OBJ_NOTNULL(htc, HTTP_CONN_MAGIC);
565 1214982
        assert(len > 0);
566 1214982
        l = 0;
567 1214982
        p = d;
568 1214982
        i = 0;
569 1214982
        if (htc->pipeline_b) {
570 88326
                l = htc->pipeline_e - htc->pipeline_b;
571 88326
                assert(l > 0);
572 88326
                l = vmin(l, len);
573 88326
                vmemcpy(p, htc->pipeline_b, l);
574 88326
                p += l;
575 88326
                len -= l;
576 88326
                htc->pipeline_b += l;
577 88326
                if (htc->pipeline_b == htc->pipeline_e)
578 68862
                        htc->pipeline_b = htc->pipeline_e = NULL;
579 88326
        }
580 1214982
        if (len > 0) {
581 1173693
                do {
582 1173696
                        errno = 0;
583 1173696
                        if (ahead == NO_READ_AHEAD)
584 1127941
                                i = read(*htc->rfd, p, len);
585 45755
                        else if (ahead == READ_AHEAD)
586 45755
                                i = v1f_readahead(htc, p, len);
587
                        else
588 0
                                WRONG("ahead");
589
590 1173696
                } while (i < 0 && errno == EINTR);
591 1173693
                if (i < 0) {
592 189
                        if (ahead == NO_READ_AHEAD || i != -ENOMEM)
593 189
                                VTCP_Assert(i);
594 378
                        VSLbs(vc->wrk->vsl, SLT_FetchError,
595 189
                            TOSTRAND(VAS_errtxt(errno)));
596 189
                        return (i);
597
                }
598 1173504
                assert(i <= len);
599 1173504
        }
600 1214793
        assert(i >= 0);
601 1214793
        assert(l >= 0);
602 1214793
        assert(i < SSIZE_MAX / 2);
603 1214793
        assert(l < SSIZE_MAX / 2);
604 1214793
        return (i + l);
605 1214982
}
606
607
static enum vfp_status
608 110977
v1f_ok(struct http_conn *htc)
609
{
610 110977
        if ((htc)->pipeline_b == (htc)->pipeline_e)
611 5942
                (htc)->pipeline_b = (htc)->pipeline_e = NULL;
612 110977
        return (VFP_OK);
613
}
614
615
616
/*--------------------------------------------------------------------
617
 * Call parser on pipeline:
618
 * - If pipeline filled, try to return a parse result without reading
619
 * - else read until either the rxbuf is filled, or we have a parse
620
 *
621
 * this is a macro because the code for calling the head and tail parser is
622
 * _almost_ (but not quite) identical
623
 */
624
625
#define CHUNKED_PARSER(vc, htc, func, func_arg, more, what)                     \
626
                                                                                \
627
        ssize_t sz;                                                             \
628
                                                                                \
629
        if ((htc)->pipeline_b) {                                                \
630
                r = func((htc)->pipeline_b, (htc)->pipeline_e,                  \
631
                        func_arg, &(htc)->pipeline_b);                          \
632
                if (r == NULL)                                                  \
633
                        return (v1f_ok(htc));                                   \
634
                if (r != more)                                                  \
635
                        return (VFP_Error(vc, "%s", r->msg));                   \
636
        }                                                                       \
637
        if ((htc)->rxbuf_b == NULL && v1f_rxbuf_init(htc) != 0)                 \
638
                return (VFP_Error(vc, "No workspace for rxbuf"));               \
639
        while ((sz = v1f_rxbuf_read(htc)) > 0) {                                \
640
                r = func((htc)->pipeline_b, (htc)->pipeline_e,                  \
641
                    func_arg, &(htc)->pipeline_b);                              \
642
                if (r == NULL)                                                  \
643
                        return (v1f_ok(htc));                                   \
644
                if (r == more)                                                  \
645
                        continue;                                               \
646
                VSLb((vc)->wrk->vsl, SLT_Debug, "%.*s",                         \
647
                    (int)pdiff((htc)->pipeline_b, (htc)->pipeline_e),           \
648
                    (htc)->pipeline_b);                                         \
649
                return (VFP_Error(vc, "%s", r->msg));                           \
650
        }                                                                       \
651
        if (sz == 0)                                                            \
652
                return (VFP_Error(vc, "chunked " what " EOF"));                 \
653
        assert(sz < 0);                                                         \
654
        VSLbs(vc->wrk->vsl, SLT_FetchError, TOSTRAND(VAS_errtxt(errno)));       \
655
        return (VFP_Error(vc, "^^^ error reading chunk " what));
656
657
/*--------------------------------------------------------------------
658
 * read (CR)?LF at the end of a chunk
659
 */
660
661
static enum vfp_status
662 57069
v1f_chunk_end(struct vfp_ctx *vc, struct http_conn *htc)
663
{
664
        const struct pct *r;
665 57069
        CHUNKED_PARSER(vc, htc, v1f_parse_chunked_tail, NULL, pct_more, "tail")
666 57069
}
667
668
/*--------------------------------------------------------------------
669
 * Parse a chunk header and, for VFP_OK, return size in a pointer
670
 */
671
672
static enum vfp_status
673 6741
v1f_chunked_hdr(struct vfp_ctx *vc, struct http_conn *htc, ssize_t *szp)
674
{
675
        const struct pch *r;
676 6762
        CHUNKED_PARSER(vc, htc, v1f_parse_chunked_hdr, szp, pch_more, "header")
677 6741
}
678
679
#undef CHUNKED_PARSER
680
681
/*--------------------------------------------------------------------
682
 * Read a chunked HTTP object.
683
 *
684
 */
685
686
static enum vfp_status v_matchproto_(vfp_pull_f)
687 1163528
v1f_chunked_pull(struct vfp_ctx *vc, struct vfp_entry *vfe, void *ptr,
688
    ssize_t *lp)
689
{
690
        enum vfp_status vfps;
691
        struct http_conn *htc;
692
        ssize_t l, lr;
693
694 1163528
        CHECK_OBJ_NOTNULL(vc, VFP_CTX_MAGIC);
695 1163528
        CHECK_OBJ_NOTNULL(vfe, VFP_ENTRY_MAGIC);
696 1163528
        CAST_OBJ_NOTNULL(htc, vfe->priv1, HTTP_CONN_MAGIC);
697 1163528
        AN(ptr);
698 1163528
        AN(lp);
699
700 1163528
        l = *lp;
701 1163528
        *lp = 0;
702 1163528
        if (vfe->priv2 == -1) {
703 6741
                vfps = v1f_chunked_hdr(vc, htc, &vfe->priv2);
704 6741
                if (vfps != VFP_OK)
705 189
                        return (vfps);
706 6552
        }
707 1163339
        if (vfe->priv2 > 0) {
708 1162474
                if (vfe->priv2 <= l) {
709 52722
                        l = vfe->priv2;
710 52722
                        lr = v1f_read(vc, htc, ptr, l, READ_AHEAD);
711 52722
                } else
712 1109752
                        lr = v1f_read(vc, htc, ptr, l, NO_READ_AHEAD);
713 1162474
                if (lr <= 0)
714 21
                        return (VFP_Error(vc, "chunked insufficient bytes"));
715 1162453
                *lp = lr;
716 1162453
                vfe->priv2 -= lr;
717 1162453
                if (vfe->priv2 != 0)
718 1109878
                        return (VFP_OK);
719
720 52575
                vfe->priv2 = -1;
721
722 52575
                vfps = v1f_chunk_end(vc, htc);
723 52575
                if (vfps != VFP_OK)
724 63
                        return (vfps);
725
726
                /* opportunistically check for next chunk header read ahead */
727 52512
                if (! htc->pipeline_b)
728 1408
                        return (VFP_OK);
729
730 51104
                const struct pch *r = v1f_parse_chunked_hdr(
731 51104
                    htc->pipeline_b, htc->pipeline_e,
732 51104
                    &vfe->priv2, &htc->pipeline_b);
733 51104
                if (r == pch_more)
734 504
                        return (v1f_ok(htc));
735 50600
                if (r != NULL)
736 42
                        return (VFP_Error(vc, "%s", r->msg));
737 50558
                if (vfe->priv2 != 0)
738 46931
                        return (v1f_ok(htc));
739 3627
        }
740 4492
        AZ(vfe->priv2);
741 4492
        vfps = v1f_chunk_end(vc, htc);
742 4492
        if (vfps != VFP_OK)
743 0
                return (vfps);
744
        /* the tail is the last CRLF, we do not accept a trailer section */
745 4492
        htc->body_status = BS_TAKEN;
746 4492
        return (VFP_END);
747 1163528
}
748
749
static const struct vfp v1f_chunked = {
750
        .name = "V1F_CHUNKED",
751
        .pull = v1f_chunked_pull,
752
};
753
754
755
/*--------------------------------------------------------------------*/
756
757
static enum vfp_status v_matchproto_(vfp_pull_f)
758 51058
v1f_straight_pull(struct vfp_ctx *vc, struct vfp_entry *vfe, void *p,
759
    ssize_t *lp)
760
{
761
        ssize_t l, lr;
762
        struct http_conn *htc;
763
764 51058
        CHECK_OBJ_NOTNULL(vc, VFP_CTX_MAGIC);
765 51058
        CHECK_OBJ_NOTNULL(vfe, VFP_ENTRY_MAGIC);
766 51058
        CAST_OBJ_NOTNULL(htc, vfe->priv1, HTTP_CONN_MAGIC);
767 51058
        AN(p);
768 51058
        AN(lp);
769
770 51058
        l = *lp;
771 51058
        *lp = 0;
772
773 51058
        if (vfe->priv2 == 0) { // XXX: Optimize Content-Len: 0 out earlier
774 0
                htc->body_status = BS_TAKEN;
775 0
                return (VFP_END);
776
        }
777 51058
        l = vmin(l, vfe->priv2);
778 51058
        lr = v1f_read(vc, htc, p, l, NO_READ_AHEAD);
779 51058
        if (lr <= 0)
780 504
                return (VFP_Error(vc, "straight insufficient bytes"));
781 50554
        *lp = lr;
782 50554
        vfe->priv2 -= lr;
783 50554
        if (vfe->priv2 == 0) {
784 23161
                htc->body_status = BS_TAKEN;
785 23161
                return (VFP_END);
786
        }
787 27393
        return (VFP_OK);
788 51058
}
789
790
static const struct vfp v1f_straight = {
791
        .name = "V1F_STRAIGHT",
792
        .pull = v1f_straight_pull,
793
};
794
795
/*--------------------------------------------------------------------*/
796
797
static enum vfp_status v_matchproto_(vfp_pull_f)
798 1449
v1f_eof_pull(struct vfp_ctx *vc, struct vfp_entry *vfe, void *p, ssize_t *lp)
799
{
800
        ssize_t l, lr;
801
        struct http_conn *htc;
802
803 1449
        CHECK_OBJ_NOTNULL(vc, VFP_CTX_MAGIC);
804 1449
        CHECK_OBJ_NOTNULL(vfe, VFP_ENTRY_MAGIC);
805 1449
        CAST_OBJ_NOTNULL(htc, vfe->priv1, HTTP_CONN_MAGIC);
806 1449
        AN(p);
807
808 1449
        AN(lp);
809
810 1449
        l = *lp;
811 1449
        *lp = 0;
812 1449
        lr = v1f_read(vc, htc, p, l, NO_READ_AHEAD);
813 1449
        if (lr < 0)
814 63
                return (VFP_Error(vc, "eof socket fail"));
815 1386
        if (lr == 0) {
816 420
                htc->doclose = SC_RESP_CLOSE;
817 420
                return (VFP_END);
818
        }
819 966
        *lp = lr;
820 966
        return (VFP_OK);
821 1449
}
822
823
static const struct vfp v1f_eof = {
824
        .name = "V1F_EOF",
825
        .pull = v1f_eof_pull,
826
};
827
828
/*--------------------------------------------------------------------
829
 */
830
831
int
832 31731
V1F_Setup_Fetch(struct vfp_ctx *vfc, struct http_conn *htc)
833
{
834
        struct vfp_entry *vfe;
835
836 31731
        CHECK_OBJ_NOTNULL(vfc, VFP_CTX_MAGIC);
837 31731
        CHECK_OBJ_NOTNULL(htc, HTTP_CONN_MAGIC);
838
839 31731
        AN(htc->ws);
840 31731
        AZ(htc->ws->r);
841
842 31731
        AZ(htc->rxbuf_b);
843 31731
        AZ(htc->rxbuf_e);
844
845 31731
        if (htc->body_status == BS_EOF) {
846 483
                assert(htc->content_length == -1);
847 483
                vfe = VFP_Push(vfc, &v1f_eof);
848 483
                if (vfe == NULL)
849 0
                        return (ENOSPC);
850 483
                vfe->priv2 = 0;
851 31731
        } else if (htc->body_status == BS_LENGTH) {
852 25956
                assert(htc->content_length > 0);
853 25956
                vfe = VFP_Push(vfc, &v1f_straight);
854 25956
                if (vfe == NULL)
855 0
                        return (ENOSPC);
856 25956
                vfe->priv2 = htc->content_length;
857 31248
        } else if (htc->body_status == BS_CHUNKED) {
858 5292
                assert(htc->content_length == -1);
859 5292
                vfe = VFP_Push(vfc, &v1f_chunked);
860 5292
                if (vfe == NULL)
861 336
                        return (ENOSPC);
862 4956
                vfe->priv2 = -1;
863 4956
        } else {
864 0
                WRONG("Wrong body_status");
865
        }
866 31395
        vfe->priv1 = htc;
867 31395
        return (0);
868 31731
}
869
#endif