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 369
v1f_rxbuf_init(struct http_conn *htc)
56
{
57
58 369
        AZ(htc->rxbuf_b);
59 369
        AZ(htc->rxbuf_e);
60
61 369
        htc->rxbuf_b = WS_Alloc(htc->ws, max_chunked_hdr);
62 369
        if (htc->rxbuf_b == NULL)
63 0
                return (-1);
64 369
        htc->rxbuf_e = htc->rxbuf_b + max_chunked_hdr;
65 369
        return (0);
66 369
}
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 723
v1f_rxbuf_read(struct http_conn *htc)
75
{
76
        ssize_t i;
77
        size_t av, sz;
78
        char *p;
79
80 723
        if (htc->pipeline_b)
81 149
                AN(htc->pipeline_e);
82
        else
83 574
                AZ(htc->pipeline_e);
84 723
        AN(htc->rxbuf_b);
85 723
        AN(htc->rxbuf_e);
86
87 723
        sz = pdiff(htc->rxbuf_b, htc->rxbuf_e);
88
89 723
        if (htc->pipeline_b == NULL)
90 574
                p = htc->pipeline_b = htc->rxbuf_b;
91
        else {
92 149
                AN(htc->pipeline_e);
93 149
                av = pdiff(htc->pipeline_b, htc->pipeline_e);
94 149
                if (av >= sz) {
95
                        // VTCP_Check(): can not originate from read()
96 8
                        errno = ENOBUFS;
97 8
                        return (-1);
98
                }
99 141
                assert(av < sz);
100 141
                memmove(htc->rxbuf_b, htc->pipeline_b, av);
101 141
                htc->pipeline_b = htc->rxbuf_b;
102 141
                htc->pipeline_e = htc->rxbuf_b + av;
103 141
                p = htc->pipeline_e;
104 141
                sz -= av;
105
        }
106 715
        do {
107 715
                errno = 0;
108 715
                i = read(*htc->rfd, p, sz);
109 715
        } while (i < 0 && errno == EINTR);
110 715
        if (i < 0) {
111 0
                VTCP_Assert(i);
112 0
                return (i);
113
        }
114 715
        htc->pipeline_e = p + i;
115 715
        if (htc->pipeline_b == htc->pipeline_e)
116 20
                 htc->pipeline_b = htc->pipeline_e = NULL;
117 715
        return (i);
118 723
}
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 10014
v1f_parse_chunked_tail(char *b, const char *e, void *unused, char **nextp)
131
{
132 10014
        AN(b);
133 10014
        AN(e);
134 10014
        (void)unused;
135 10014
        AN(nextp);
136
137 10014
        if (b == e)
138 16
                return (pct_more);
139 9998
        if (*b == '\r')
140 9798
                b++;
141 9998
        if (b == e)
142 12
                return (pct_more);
143 9986
        if (*b != '\n')
144 16
                return (pct_nonl);
145 9970
        b++;
146
147 9970
        *nextp = b;
148 9970
        return (NULL);
149 10014
}
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 31380
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 31380
        AN(b);
173 31380
        AN(e);
174 31380
        AN(szp);
175 31380
        AN(nextp);
176
177
        /* Skip leading whitespace - XXX rfc9112 does not specify this */
178 47084
        while (b < e && vct_isows(*b))
179 15704
                b++;
180 31380
        if (b == e)
181 4328
                return (pch_more);
182 27052
        if (!vct_ishex(*b))
183 24
                return (pch_nonhex);
184
        /* Skip leading zeros */
185 34740
        while (b < e - 1 && b[0] == '0' && b[1] == '0')
186 7712
                b++;
187 27028
        if (b == e)
188 0
                return (pch_more);
189 27028
        hb = b;
190
        /* Collect hex digits */
191 137384
        while (b < e && vct_ishex(*b))
192 110356
                b++;
193 27028
        if (b == e)
194 11480
                return (pch_more);
195 15548
        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 20348
        while (b < e && vct_isows(*b))
200 4800
                b++;
201 15544
        if (b == e)
202 1800
                return (pch_more);
203 13744
        if (*b == '\r')
204 12530
                b++;
205 13744
        if (b == e)
206 1342
                return (pch_more);
207 12402
        if (*b != '\n')
208 8
                return (pch_nonl);
209 12394
        b++;
210
211 12394
        errno = 0;
212 12394
        s = *he;
213 12394
        *he = '\0';
214 12394
        cll = strtoumax(hb, &q, 16);
215
        // restore original for debug-/testability
216 12394
        *he = s;
217
218 12394
        if (q == NULL || q != he)
219 6
                return (pch_syntax);
220
221 12388
        cl = (ssize_t)cll;
222 12388
        if (cl < 0 || (uintmax_t)cl != cll)
223 16
                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 12372
        AZ(errno);
229
230 12372
        *szp = cl;
231 12372
        *nextp = b;
232 12372
        return (NULL);
233 31370
}
234
235
// length check outside the actual parser for clarity
236
static struct pch *
237 31374
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 31374
        ee = vmin_t(const char *, e, b + max_chunked_hdr);
243
244 31374
        r = v1f_parse_chunked_hdr_i(b, ee, szp, nextp);
245
246 31374
        if (r == pch_more && e != ee)
247 4
                return (pch_toolong);
248
249 31370
        return (r);
250 31374
}
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 21212
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 21212
        char *next = NULL;
344 21212
        ssize_t sz = -1;
345 21212
        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 21212
        assert(r == r_exp);
351 21212
        assert(sz == sz_exp);
352 21212
        assert(next == next_exp);
353 21212
}
354
355
static void
356 18812
t_parse_chunked_hdr_err(char *b, char *e, const struct pch *err)
357
{
358 18812
        t_parse_chunked_hdr(b, e, err, -1, NULL);
359 18812
}
360
361
static void
362 2400
t_parse_chunked_hdr_ok(char *b, char *e,
363
    ssize_t sz_exp, const char *next_exp)
364
{
365 2400
        t_parse_chunked_hdr(b, e, NULL, sz_exp, next_exp);
366 2400
}
367
368
static void
369 48
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 48
        char *next = NULL;
374 48
        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 48
        assert(r == r_exp);
380 48
        assert(next == next_exp);
381 48
}
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 4
t_rxbuf_read(void) {
396
        struct http_conn htc[1];
397 4
        const char *data = "0123456789abcdef";
398
        char rxbuf[16];
399
        int fd[2], i, r;
400
401 4
        assert(strlen(data) == sizeof rxbuf);
402
403 4
        INIT_OBJ(htc, HTTP_CONN_MAGIC);
404
        // v1f_rxbuf_init without the workspace
405 4
        htc->rxbuf_b = rxbuf;
406 4
        htc->rxbuf_e = htc->rxbuf_b + sizeof rxbuf;
407
408 4
        AZ(pipe(fd));
409 4
        htc->rfd = &fd[0];
410
411 68
        for (i = 0; i < strlen(data); i++) {
412 64
                r = write(fd[1], data + i, 1);
413 64
                assert(r == 1);
414 64
                r = v1f_rxbuf_read(htc);
415 64
                assert(r == 1);
416 64
                size_t av = pdiff(htc->pipeline_b, htc->pipeline_e);
417 64
                assert(av == i + 1);
418 64
                AZ(memcmp(htc->pipeline_b, data, av));
419 64
                if (i % 2 == 0) {
420
                        // v1f_rxbuf_read moves pipelined data to the beginning
421 32
                        assert(htc->pipeline_b == htc->rxbuf_b);
422 32
                        memmove(htc->pipeline_b + 1, htc->pipeline_b, av);
423 32
                        htc->pipeline_b++;
424 32
                        htc->pipeline_e++;
425 32
                }
426
427 64
        }
428
        // buffer is now full
429 4
        r = v1f_rxbuf_read(htc);
430 4
        assert(r == -1);
431 4
        assert(errno == ENOBUFS);
432
433 4
        close(fd[0]);
434 4
        close(fd[1]);
435 4
}
436
437
int
438 4
main(int argc, char *argv[])
439
{
440 4
        (void) argc;
441 4
        (void) argv;
442
443 4
        printf("-- rxbuf_read\n");
444 4
        t_rxbuf_read();
445
446 4
        printf("-- head postitive test permutations\n");
447
        // avoid nested loops
448 4
        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 2404
        for (unsigned n = 0; n < n_ok; n++) {
452 2400
                unsigned n_pre = n % vcountof(t_ok_pre);
453 2400
                unsigned n_sz = n / vcountof(t_ok_pre);
454 2400
                unsigned n_post = n_sz / vcountof(t_ok_sz);
455 2400
                unsigned n_next = n_post / vcountof(t_ok_post);
456 2400
                n_sz %= vcountof(t_ok_sz);
457 2400
                n_post %= vcountof(t_ok_post);
458 2400
                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 2400
                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 2400
                char *ee = buf + strlen(buf) - strlen(t_ok_next[n_next]);
468
469 21160
                for (char *e = buf; e < ee; e++)
470 18760
                        t_parse_chunked_hdr_err(buf, e, pch_more);
471
472 2400
                t_parse_chunked_hdr_ok(buf, ee, t_ok_sz[n_sz], ee);
473 2400
        }
474
475 4
        printf("-- head negative tests\n");
476 56
        for (struct pch_neg *neg = t_neg; neg < t_neg + vcountof(t_neg); neg++) {
477 52
                size_t l = strlen(neg->hdr);
478 52
                assert(l < sizeof buf);
479
480 52
                memcpy(buf, neg->hdr, l + 1);
481 52
                char *e = buf + l;
482
483 52
                t_parse_chunked_hdr_err(buf, e, neg->r);
484 52
        }
485
486 4
        printf("-- tail postitive test permutations\n");
487 4
        n_ok = vcountof(t_ok_tail) * vcountof(t_ok_tail_next);
488 20
        for (unsigned n = 0; n < n_ok; n++) {
489 16
                unsigned n_tail = n % vcountof(t_ok_tail);
490 16
                unsigned n_next = n / vcountof(t_ok_tail_next);
491 16
                assert(n_next < vcountof(t_ok_tail_next));
492
493 16
                bprintf(buf, "%s%s", t_ok_tail[n_tail], t_ok_tail_next[n_next]);
494 16
                char *ee = buf + strlen(buf) - strlen(t_ok_tail_next[n_next]);
495
496 40
                for (char *e = buf; e < ee; e++)
497 24
                        t_parse_chunked_tail(buf, e, pct_more, NULL);
498
499 16
                t_parse_chunked_tail(buf, ee, NULL, ee);
500 16
        }
501
502 4
        printf("-- tail negative tests\n");
503 12
        for (struct pct_neg *neg = t_neg_tail; neg < t_neg_tail + vcountof(t_neg_tail); neg++) {
504 8
                size_t l = strlen(neg->hdr);
505 8
                assert(l < sizeof buf);
506
507 8
                memcpy(buf, neg->hdr, l + 1);
508 8
                char *e = buf + l;
509
510 8
                t_parse_chunked_tail(buf, e, neg->r, NULL);
511 8
        }
512
513 4
        printf("OK\n");
514 4
        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 8706
v1f_readahead(struct http_conn *htc, char *p, ssize_t len)
529
{
530
        struct iovec iov[2];
531
        ssize_t i;
532
533 8706
        AZ(htc->pipeline_b);
534 8706
        if (htc->rxbuf_b == NULL && v1f_rxbuf_init(htc)) {
535 0
                errno = ENOMEM;
536 0
                return (-ENOMEM);
537
        }
538 8706
        AN(htc->rxbuf_b);
539
540 8706
        iov[0].iov_base = p;
541 8706
        iov[0].iov_len = len;
542 8706
        iov[1].iov_base = htc->rxbuf_b;
543 8706
        iov[1].iov_len = pdiff(htc->rxbuf_b, htc->rxbuf_e);
544
545 8706
        i = readv(*htc->rfd, iov, vcountof(iov));
546 8706
        if (i <= len)
547 28
                return (i);
548 8678
        i -= len;
549 8678
        htc->pipeline_b = htc->rxbuf_b;
550 8678
        htc->pipeline_e = htc->rxbuf_b + i;
551
552 8678
        return (len);
553 8706
}
554
555
static ssize_t
556 230751
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 230751
        CHECK_OBJ_NOTNULL(vc, VFP_CTX_MAGIC);
564 230751
        CHECK_OBJ_NOTNULL(htc, HTTP_CONN_MAGIC);
565 230751
        assert(len > 0);
566 230751
        l = 0;
567 230751
        p = d;
568 230751
        i = 0;
569 230751
        if (htc->pipeline_b) {
570 15961
                l = htc->pipeline_e - htc->pipeline_b;
571 15961
                assert(l > 0);
572 15961
                l = vmin(l, len);
573 15961
                memcpy(p, htc->pipeline_b, l);
574 15961
                p += l;
575 15961
                len -= l;
576 15961
                htc->pipeline_b += l;
577 15961
                if (htc->pipeline_b == htc->pipeline_e)
578 12868
                        htc->pipeline_b = htc->pipeline_e = NULL;
579 15961
        }
580 230751
        if (len > 0) {
581 223749
                do {
582 223751
                        errno = 0;
583 223751
                        if (ahead == NO_READ_AHEAD)
584 215045
                                i = read(*htc->rfd, p, len);
585 8706
                        else if (ahead == READ_AHEAD)
586 8706
                                i = v1f_readahead(htc, p, len);
587
                        else
588 0
                                WRONG("ahead");
589
590 223751
                } while (i < 0 && errno == EINTR);
591 223749
                if (i < 0) {
592 36
                        if (ahead == NO_READ_AHEAD || i != -ENOMEM)
593 36
                                VTCP_Assert(i);
594 72
                        VSLbs(vc->wrk->vsl, SLT_FetchError,
595 36
                            TOSTRAND(VAS_errtxt(errno)));
596 36
                        return (i);
597
                }
598 223713
                assert(i <= len);
599 223713
        }
600 230715
        assert(i >= 0);
601 230715
        assert(l >= 0);
602 230715
        assert(i < SSIZE_MAX / 2);
603 230715
        assert(l < SSIZE_MAX / 2);
604 230715
        return (i + l);
605 230751
}
606
607
static enum vfp_status
608 10871
v1f_ok(struct http_conn *htc)
609
{
610 10871
        if ((htc)->pipeline_b == (htc)->pipeline_e)
611 810
                (htc)->pipeline_b = (htc)->pipeline_e = NULL;
612 10871
        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 9965
v1f_chunk_end(struct vfp_ctx *vc, struct http_conn *htc)
663
{
664
        const struct pct *r;
665 9965
        CHUNKED_PARSER(vc, htc, v1f_parse_chunked_tail, NULL, pct_more, "tail")
666 9965
}
667
668
/*--------------------------------------------------------------------
669
 * Parse a chunk header and, for VFP_OK, return size in a pointer
670
 */
671
672
static enum vfp_status
673 955
v1f_chunked_hdr(struct vfp_ctx *vc, struct http_conn *htc, ssize_t *szp)
674
{
675
        const struct pch *r;
676 959
        CHUNKED_PARSER(vc, htc, v1f_parse_chunked_hdr, szp, pch_more, "header")
677 955
}
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 221192
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 221192
        CHECK_OBJ_NOTNULL(vc, VFP_CTX_MAGIC);
695 221192
        CHECK_OBJ_NOTNULL(vfe, VFP_ENTRY_MAGIC);
696 221192
        CAST_OBJ_NOTNULL(htc, vfe->priv1, HTTP_CONN_MAGIC);
697 221192
        AN(ptr);
698 221192
        AN(lp);
699
700 221192
        l = *lp;
701 221192
        *lp = 0;
702 221192
        if (vfe->priv2 == -1) {
703 955
                vfps = v1f_chunked_hdr(vc, htc, &vfe->priv2);
704 955
                if (vfps != VFP_OK)
705 36
                        return (vfps);
706 919
        }
707 221156
        if (vfe->priv2 > 0) {
708 221007
                if (vfe->priv2 <= l) {
709 9439
                        l = vfe->priv2;
710 9439
                        lr = v1f_read(vc, htc, ptr, l, READ_AHEAD);
711 9439
                } else
712 211568
                        lr = v1f_read(vc, htc, ptr, l, NO_READ_AHEAD);
713 221007
                if (lr <= 0)
714 4
                        return (VFP_Error(vc, "chunked insufficient bytes"));
715 221003
                *lp = lr;
716 221003
                vfe->priv2 -= lr;
717 221003
                if (vfe->priv2 != 0)
718 211592
                        return (VFP_OK);
719
720 9411
                vfe->priv2 = -1;
721
722 9411
                vfps = v1f_chunk_end(vc, htc);
723 9411
                if (vfps != VFP_OK)
724 12
                        return (vfps);
725
726
                /* opportunistically check for next chunk header read ahead */
727 9399
                if (! htc->pipeline_b)
728 258
                        return (VFP_OK);
729
730 9141
                const struct pch *r = v1f_parse_chunked_hdr(
731 9141
                    htc->pipeline_b, htc->pipeline_e,
732 9141
                    &vfe->priv2, &htc->pipeline_b);
733 9141
                if (r == pch_more)
734 81
                        return (VFP_OK);
735 9060
                if (r != NULL)
736 8
                        return (VFP_Error(vc, "%s", r->msg));
737 9052
                if (vfe->priv2 != 0)
738 8649
                        return (VFP_OK);
739 403
        }
740 552
        AZ(vfe->priv2);
741 552
        vfps = v1f_chunk_end(vc, htc);
742 552
        return (vfps == VFP_OK ? VFP_END : vfps);
743 221192
}
744
745
static const struct vfp v1f_chunked = {
746
        .name = "V1F_CHUNKED",
747
        .pull = v1f_chunked_pull,
748
};
749
750
751
/*--------------------------------------------------------------------*/
752
753
static enum vfp_status v_matchproto_(vfp_pull_f)
754 9464
v1f_straight_pull(struct vfp_ctx *vc, struct vfp_entry *vfe, void *p,
755
    ssize_t *lp)
756
{
757
        ssize_t l, lr;
758
        struct http_conn *htc;
759
760 9464
        CHECK_OBJ_NOTNULL(vc, VFP_CTX_MAGIC);
761 9464
        CHECK_OBJ_NOTNULL(vfe, VFP_ENTRY_MAGIC);
762 9464
        CAST_OBJ_NOTNULL(htc, vfe->priv1, HTTP_CONN_MAGIC);
763 9464
        AN(p);
764 9464
        AN(lp);
765
766 9464
        l = *lp;
767 9464
        *lp = 0;
768
769 9464
        if (vfe->priv2 == 0) // XXX: Optimize Content-Len: 0 out earlier
770 0
                return (VFP_END);
771 9464
        l = vmin(l, vfe->priv2);
772 9464
        lr = v1f_read(vc, htc, p, l, NO_READ_AHEAD);
773 9464
        if (lr <= 0)
774 96
                return (VFP_Error(vc, "straight insufficient bytes"));
775 9368
        *lp = lr;
776 9368
        vfe->priv2 -= lr;
777 9368
        if (vfe->priv2 == 0)
778 4168
                return (VFP_END);
779 5200
        return (VFP_OK);
780 9464
}
781
782
static const struct vfp v1f_straight = {
783
        .name = "V1F_STRAIGHT",
784
        .pull = v1f_straight_pull,
785
};
786
787
/*--------------------------------------------------------------------*/
788
789
static enum vfp_status v_matchproto_(vfp_pull_f)
790 276
v1f_eof_pull(struct vfp_ctx *vc, struct vfp_entry *vfe, void *p, ssize_t *lp)
791
{
792
        ssize_t l, lr;
793
        struct http_conn *htc;
794
795 276
        CHECK_OBJ_NOTNULL(vc, VFP_CTX_MAGIC);
796 276
        CHECK_OBJ_NOTNULL(vfe, VFP_ENTRY_MAGIC);
797 276
        CAST_OBJ_NOTNULL(htc, vfe->priv1, HTTP_CONN_MAGIC);
798 276
        AN(p);
799
800 276
        AN(lp);
801
802 276
        l = *lp;
803 276
        *lp = 0;
804 276
        lr = v1f_read(vc, htc, p, l, NO_READ_AHEAD);
805 276
        if (lr < 0)
806 12
                return (VFP_Error(vc, "eof socket fail"));
807 264
        if (lr == 0) {
808 80
                htc->doclose = SC_RESP_CLOSE;
809 80
                return (VFP_END);
810
        }
811 184
        *lp = lr;
812 184
        return (VFP_OK);
813 276
}
814
815
static const struct vfp v1f_eof = {
816
        .name = "V1F_EOF",
817
        .pull = v1f_eof_pull,
818
};
819
820
/*--------------------------------------------------------------------
821
 */
822
823
int
824 5492
V1F_Setup_Fetch(struct vfp_ctx *vfc, struct http_conn *htc)
825
{
826
        struct vfp_entry *vfe;
827
828 5492
        CHECK_OBJ_NOTNULL(vfc, VFP_CTX_MAGIC);
829 5492
        CHECK_OBJ_NOTNULL(htc, HTTP_CONN_MAGIC);
830
831 5492
        AN(htc->ws);
832 5492
        AZ(htc->ws->r);
833
834 5492
        AZ(htc->rxbuf_b);
835 5492
        AZ(htc->rxbuf_e);
836
837 5492
        if (htc->body_status == BS_EOF) {
838 92
                assert(htc->content_length == -1);
839 92
                vfe = VFP_Push(vfc, &v1f_eof);
840 92
                if (vfe == NULL)
841 0
                        return (ENOSPC);
842 92
                vfe->priv2 = 0;
843 5492
        } else if (htc->body_status == BS_LENGTH) {
844 4700
                assert(htc->content_length > 0);
845 4700
                vfe = VFP_Push(vfc, &v1f_straight);
846 4700
                if (vfe == NULL)
847 0
                        return (ENOSPC);
848 4700
                vfe->priv2 = htc->content_length;
849 5400
        } else if (htc->body_status == BS_CHUNKED) {
850 700
                assert(htc->content_length == -1);
851 700
                vfe = VFP_Push(vfc, &v1f_chunked);
852 700
                if (vfe == NULL)
853 64
                        return (ENOSPC);
854 636
                vfe->priv2 = -1;
855 636
        } else {
856 0
                WRONG("Wrong body_status");
857
        }
858 5428
        vfe->priv1 = htc;
859 5428
        return (0);
860 5492
}
861
#endif