vinyl-cache/bin/vinyld/cache/cache_http.c
0
/*-
1
 * Copyright (c) 2006 Verdens Gang AS
2
 * Copyright (c) 2006-2017 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 23791
 * HTTP request storage and manipulation
31 1800
 */
32 1296
33 376
#include "config.h"
34 304
35 284
#include "cache_int.h"
36 260
#include <stdio.h>
37 260
#include <stdlib.h>
38 260
39 248
#include "common/heritage.h"
40 248
41
#include "vct.h"
42
#include "vend.h"
43
#include "vnum.h"
44
#include "vtim.h"
45
46
#define BODYSTATUS(U, l, n, a, k)                               \
47
        const struct body_status BS_##U[1] = {{                 \
48
                .name = #l,                                     \
49
                .nbr = n,                                       \
50
                .avail = a,                                     \
51
                .length_known = k                               \
52
        }};
53
#include "tbl/body_status.h"
54
55
56
#define HTTPH(a, b, c) hdr_t b = HDR(a);
57
#include "tbl/http_headers.h"
58
59
hdr_t H__Status = HDR(":status");
60
hdr_t H__Proto  = HDR(":proto");
61
hdr_t H__Reason = HDR(":reason");
62
63
static char * via_hdr;
64
65
/*--------------------------------------------------------------------
66
 * Perfect hash to rapidly recognize headers from tbl/http_headers.h
67
 * which have non-zero flags.
68
 *
69
 * A suitable algorithm can be found with `gperf`:
70
 *
71
 *      tr '" ,' '   ' < include/tbl/http_headers.h |
72
 *              awk '$1 == "H(" {print $2}' |
73
 *              gperf --ignore-case
74
 *
75
 */
76
77
#define GPERF_MIN_WORD_LENGTH 2
78
#define GPERF_MAX_WORD_LENGTH 19
79
#define GPERF_MAX_HASH_VALUE 79
80
81
static const unsigned char http_asso_values[256] = {
82
        80, 80, 80, 80, 80, 80, 80, 80, 80, 80,
83
        80, 80, 80, 80, 80, 80, 80, 80, 80, 80,
84
        80, 80, 80, 80, 80, 80, 80, 80, 80, 80,
85
        80, 80, 80, 80, 80, 80, 80, 80, 80, 80,
86
        80, 80, 80, 80, 80, 80, 80, 80, 80, 80,
87
        80, 80, 80,  0, 80, 80, 80, 80, 80, 80,
88
        80, 80, 80, 80, 80,  5, 80, 20,  0,  0,
89
        5, 10,  5,  5, 80,  0, 15,  0, 20, 80,
90
        40, 80,  0, 35, 10, 20, 55, 45,  0,  0,
91
        80, 80, 80, 80, 80, 80, 80,  5, 80, 20,
92
        0,  0,  5, 10,  5,  5, 80,  0, 15,  0,
93
        20, 80, 40, 80,  0, 35, 10, 20, 55, 45,
94
        0,  0, 80, 80, 80, 80, 80, 80, 80, 80,
95
        80, 80, 80, 80, 80, 80, 80, 80, 80, 80,
96
        80, 80, 80, 80, 80, 80, 80, 80, 80, 80,
97
        80, 80, 80, 80, 80, 80, 80, 80, 80, 80,
98
        80, 80, 80, 80, 80, 80, 80, 80, 80, 80,
99
        80, 80, 80, 80, 80, 80, 80, 80, 80, 80,
100
        80, 80, 80, 80, 80, 80, 80, 80, 80, 80,
101
        80, 80, 80, 80, 80, 80, 80, 80, 80, 80,
102
        80, 80, 80, 80, 80, 80, 80, 80, 80, 80,
103
        80, 80, 80, 80, 80, 80, 80, 80, 80, 80,
104
        80, 80, 80, 80, 80, 80, 80, 80, 80, 80,
105
        80, 80, 80, 80, 80, 80, 80, 80, 80, 80,
106
        80, 80, 80, 80, 80, 80, 80, 80, 80, 80,
107
        80, 80, 80, 80, 80, 80
108
};
109
110
static struct http_hdrflg {
111
        hdr_t           *hdr;
112
        unsigned        flag;
113
} http_hdrflg[GPERF_MAX_HASH_VALUE + 1] = {
114
        { NULL }, { NULL }, { NULL }, { NULL },
115
        { &H_Date },
116
        { &H_Range },
117
        { NULL },
118
        { &H_Referer },
119
        { &H_Age },
120
        { &H_From },
121
        { &H_Keep_Alive },
122
        { &H_Retry_After },
123
        { &H_TE },
124
        { &H_If_Range },
125
        { &H_ETag },
126
        { &H_X_Forwarded_For },
127
        { &H_Expect },
128
        { &H_Trailer },
129
        { &H_If_Match },
130
        { &H_Host },
131
        { &H_Accept_Language },
132
        { &H_Accept },
133
        { &H_If_Modified_Since },
134
        { &H_If_None_Match },
135
        { &H_If_Unmodified_Since },
136
        { NULL },
137
        { &H_Cookie },
138
        { &H_Upgrade },
139
        { &H_Last_Modified },
140
        { &H_Accept_Charset },
141
        { &H_Accept_Encoding },
142
        { &H_Content_MD5 },
143
        { &H_Content_Type },
144
        { &H_Content_Range },
145
        { NULL }, { NULL },
146
        { &H_Content_Language },
147
        { &H_Transfer_Encoding },
148
        { &H_Authorization },
149
        { &H_Content_Length },
150
        { &H_User_Agent },
151
        { &H_Server },
152
        { &H_Expires },
153
        { &H_Location },
154
        { NULL },
155
        { &H_Set_Cookie },
156
        { &H_Content_Encoding },
157
        { &H_Max_Forwards },
158
        { &H_Cache_Control },
159
        { NULL },
160
        { &H_Connection },
161
        { &H_Pragma },
162
        { NULL },
163
        { &H_Accept_Ranges },
164
        { &H_HTTP2_Settings },
165
        { &H_Allow },
166
        { &H_Content_Location },
167
        { NULL },
168
        { &H_Proxy_Authenticate },
169
        { &H_Vary },
170
        { NULL },
171
        { &H_WWW_Authenticate },
172
        { &H_Warning },
173
        { &H_Via },
174
        { NULL }, { NULL }, { NULL }, { NULL },
175
        { NULL }, { NULL }, { NULL }, { NULL },
176
        { NULL }, { NULL }, { NULL }, { NULL },
177
        { NULL }, { NULL }, { NULL },
178
        { &H_Proxy_Authorization }
179
};
180
181
static struct http_hdrflg *
182 314079
http_hdr_flags(const char *b, const char *e)
183
{
184
        unsigned u;
185
        struct http_hdrflg *retval;
186
187 314079
        if (b == NULL || e == NULL)
188 32
                return (NULL);
189 314077
        u = pdiff(b, e);
190 314077
        if (u < GPERF_MIN_WORD_LENGTH || u > GPERF_MAX_WORD_LENGTH)
191 140
                return (NULL);
192 627874
        u += http_asso_values[(uint8_t)(e[-1])] +
193 313937
             http_asso_values[(uint8_t)(b[0])];
194 313937
        if (u > GPERF_MAX_HASH_VALUE)
195 4316
                return (NULL);
196 309621
        retval = &http_hdrflg[u];
197 309621
        if (retval->hdr == NULL)
198 1232
                return (NULL);
199 308389
        AN(*retval->hdr);
200 308389
        if (!http_hdr_at(*retval->hdr + 1, b, e - b))
201 4328
                return (NULL);
202 304061
        return (retval);
203 314077
}
204
205
/*--------------------------------------------------------------------*/
206
207
static void
208 202384
http_init_hdr(hdr_t hdr, int flg)
209
{
210
        struct http_hdrflg *f;
211
212 202384
        f = http_hdr_flags(hdr->str, hdr->str + hdr->len - 1);
213 202384
        AN(f);
214 202384
        assert(*f->hdr == hdr);
215 202384
        f->flag = flg;
216 202384
}
217
218
void
219 3892
HTTP_Init(void)
220
{
221
        struct vsb *vsb;
222
223
#define HTTPH(a, b, c) http_init_hdr(b, c);
224
#include "tbl/http_headers.h"
225
226
        vsb = VSB_new_auto();
227 3892
        AN(vsb);
228
        VSB_printf(vsb, "1.1 %s (Vinyl-Cache/" PACKAGE_BRANCH ")",
229
            heritage.identity);
230 3892
        AZ(VSB_finish(vsb));
231 3892
        REPLACE(via_hdr, VSB_data(vsb));
232
        VSB_destroy(&vsb);
233
}
234
235
/*--------------------------------------------------------------------
236
 * These two functions are in an incestuous relationship with the
237
 * order of macros in include/tbl/vsl_tags_http.h
238
 *
239
 * The http->logtag is the SLT_*Method enum, and we add to that, to
240
 * get the SLT_ to use.
241
 */
242
243
static void
244 521765
http_VSLH(const struct http *hp, unsigned hdr)
245
{
246
        int i;
247
248 521765
        if (hp->vsl != NULL) {
249 521795
                assert(VXID_TAG(hp->vsl->wid));
250 521795
                i = hdr;
251 521795
                if (i > HTTP_HDR_FIRST)
252 274784
                        i = HTTP_HDR_FIRST;
253 521795
                i += hp->logtag;
254 521795
                VSLbt(hp->vsl, (enum VSL_tag_e)i, hp->hd[hdr]);
255 521795
        }
256 521825
}
257
258
static void
259 4199
http_VSLH_del(const struct http *hp, unsigned hdr)
260
{
261
        int i;
262
263 4199
        if (hp->vsl != NULL) {
264
                /* We don't support unsetting stuff in the first line */
265 4199
                assert (hdr >= HTTP_HDR_FIRST);
266 4199
                assert(VXID_TAG(hp->vsl->wid));
267 4199
                i = (HTTP_HDR_UNSET - HTTP_HDR_METHOD);
268 4199
                i += hp->logtag;
269 4199
                VSLbt(hp->vsl, (enum VSL_tag_e)i, hp->hd[hdr]);
270 4199
        }
271 4199
}
272
273
/*--------------------------------------------------------------------*/
274
275
void
276 24286
http_VSL_log(const struct http *hp)
277
{
278
        unsigned u;
279
280 212261
        for (u = 0; u < hp->nhd; u++)
281 327393
                if (hp->hd[u].b != NULL)
282 139418
                        http_VSLH(hp, u);
283 24286
}
284
285
/*--------------------------------------------------------------------*/
286
287
static void
288 440
http_fail(const struct http *hp)
289
{
290
        char id[WS_ID_SIZE];
291
292 440
        VSC_C_main->losthdr++;
293 440
        WS_Id(hp->ws, id);
294 440
        VSLb(hp->vsl, SLT_Error, "out of workspace (%s)", id);
295 440
        WS_MarkOverflow(hp->ws);
296 440
}
297
298
/*--------------------------------------------------------------------
299
 * List of canonical HTTP response code names from RFC2616
300
 */
301
302
static struct http_msg {
303
        unsigned        nbr;
304
        const char      *status;
305
        const char      *txt;
306
} http_msg[] = {
307
#define HTTP_RESP(n, t) { n, #n, t},
308
#include "tbl/http_response.h"
309
        { 0, "0", NULL }
310
};
311
312
const char *
313 6148
http_Status2Reason(unsigned status, const char **sstr)
314
{
315
        struct http_msg *mp;
316
317 6148
        status %= 1000;
318 6148
        assert(status >= 100);
319 185999
        for (mp = http_msg; mp->nbr != 0 && mp->nbr <= status; mp++)
320 185819
                if (mp->nbr == status) {
321 5968
                        if (sstr)
322 4524
                                *sstr = mp->status;
323 5968
                        return (mp->txt);
324
                }
325 180
        return ("Unknown HTTP Status");
326 6148
}
327
328
/*--------------------------------------------------------------------*/
329
330
unsigned
331 22129
HTTP_estimate(unsigned nhttp)
332
{
333
334
        /* XXX: We trust the structs to size-aligned as necessary */
335 22129
        return (PRNDUP(sizeof(struct http) + sizeof(txt) * nhttp + nhttp));
336
}
337
338
struct http *
339 66388
HTTP_create(void *p, uint16_t nhttp, unsigned len)
340
{
341
        struct http *hp;
342
343 66388
        hp = p;
344 66388
        hp->magic = HTTP_MAGIC;
345 66388
        hp->hd = (void*)(hp + 1);
346 66388
        hp->shd = nhttp;
347 66388
        hp->hdf = (void*)(hp->hd + nhttp);
348 66388
        assert((unsigned char*)p + len == hp->hdf + PRNDUP(nhttp));
349 66388
        return (hp);
350
}
351
352
/*--------------------------------------------------------------------*/
353
354
void
355 61992
HTTP_Setup(struct http *hp, struct ws *ws, struct vsl_log *vsl,
356
    enum VSL_tag_e  whence)
357
{
358 61992
        http_Teardown(hp);
359 61992
        hp->nhd = HTTP_HDR_FIRST;
360 61992
        hp->logtag = whence;
361 61992
        hp->ws = ws;
362 61992
        hp->vsl = vsl;
363 61992
        hp->wkm = WKM_UNKNOWN;
364 61992
}
365
366
/*--------------------------------------------------------------------
367
 * http_Teardown() is a safety feature, we use it to zap all http
368
 * structs once we're done with them, to minimize the risk that
369
 * old stale pointers exist to no longer valid stuff.
370
 */
371
372
void
373 96792
http_Teardown(struct http *hp)
374
{
375
376 96792
        CHECK_OBJ_NOTNULL(hp, HTTP_MAGIC);
377 96792
        AN(hp->shd);
378 96792
        memset(&hp->nhd, 0, sizeof *hp - offsetof(struct http, nhd));
379 96792
        memset(hp->hd, 0, sizeof *hp->hd * hp->shd);
380 96792
        memset(hp->hdf, 0, sizeof *hp->hdf * hp->shd);
381 96792
}
382
383
/*--------------------------------------------------------------------
384
 * Duplicate the http content into another http
385
 * We cannot just memcpy the struct because the hd & hdf are private
386
 * storage to the struct http.
387
 */
388
389
void
390 27151
HTTP_Dup(struct http *to, const struct http * fm)
391
{
392
393 27151
        assert(fm->nhd <= to->shd);
394 27151
        memcpy(to->hd, fm->hd, fm->nhd * sizeof *to->hd);
395 27151
        memcpy(to->hdf, fm->hdf, fm->nhd * sizeof *to->hdf);
396 27151
        to->nhd = fm->nhd;
397 27151
        to->logtag = fm->logtag;
398 27151
        to->status = fm->status;
399 27151
        to->protover = fm->protover;
400 27151
        to->wkm = fm->wkm;
401 27151
}
402
403
404
/*--------------------------------------------------------------------
405
 * Clone the entire http structure, including vsl & ws
406
 */
407
408
void
409 25683
HTTP_Clone(struct http *to, const struct http * const fm)
410
{
411
412 25683
        HTTP_Dup(to, fm);
413 25683
        to->vsl = fm->vsl;
414 25683
        to->ws = fm->ws;
415 25683
}
416
417
/*--------------------------------------------------------------------*/
418
419
void
420 27766
http_Proto(struct http *to)
421
{
422
        const char *fm;
423
424 27766
        fm = to->hd[HTTP_HDR_PROTO].b;
425
426 55496
        if (fm != NULL &&
427 27734
            (fm[0] == 'H' || fm[0] == 'h') &&
428 27731
            (fm[1] == 'T' || fm[1] == 't') &&
429 27729
            (fm[2] == 'T' || fm[2] == 't') &&
430 27729
            (fm[3] == 'P' || fm[3] == 'p') &&
431 27729
            fm[4] == '/' &&
432 27729
            vct_isdigit(fm[5]) &&
433 27729
            fm[6] == '.' &&
434 27729
            vct_isdigit(fm[7]) &&
435 27730
            fm[8] == '\0') {
436 27730
                to->protover = 10 * (fm[5] - '0') + (fm[7] - '0');
437 27730
        } else {
438 36
                to->protover = 0;
439
        }
440 27766
}
441
442
/*--------------------------------------------------------------------*/
443
444
void
445 165114
http_SetH(struct http *to, unsigned n, const char *header)
446
{
447
448 165114
        assert(n < to->nhd);
449 165114
        AN(header);
450 165114
        to->hd[n].b = TRUST_ME(header);
451 165114
        to->hd[n].e = strchr(to->hd[n].b, '\0');
452 165114
        to->hdf[n] = 0;
453 165114
        http_VSLH(to, n);
454 165114
        if (n == HTTP_HDR_PROTO)
455 5608
                http_Proto(to);
456 165114
        if (n == HTTP_HDR_METHOD)
457 156
                http_SetWellKnownMethod(to);
458 165114
}
459
460
/*--------------------------------------------------------------------*/
461
462
static void
463 136
http_PutField(struct http *to, int field, const char *string)
464
{
465
        const char *p;
466
467 136
        CHECK_OBJ_NOTNULL(to, HTTP_MAGIC);
468 136
        p = WS_Copy(to->ws, string, -1);
469 136
        if (p == NULL) {
470 4
                http_fail(to);
471 4
                VSLbs(to->vsl, SLT_LostHeader, TOSTRAND(string));
472 4
                return;
473
        }
474 132
        http_SetH(to, field, p);
475 136
}
476
477
/*--------------------------------------------------------------------*/
478
479
int
480 604288
http_IsHdr(const txt *hh, hdr_t hdr)
481
{
482
483 604288
        Tcheck(*hh);
484 604288
        CHECK_HDR(hdr);
485 604288
        return (http_hdr_at(hdr->str, hh->b, hdr->len));
486
}
487
488
/*--------------------------------------------------------------------*/
489
490
static unsigned
491 682938
http_findhdr(const struct http *hp, unsigned l, const char *hdr)
492
{
493
        unsigned u;
494
495 3122958
        for (u = HTTP_HDR_FIRST; u < hp->nhd; u++) {
496 2576273
                Tcheck(hp->hd[u]);
497 2576273
                if (hp->hd[u].e < hp->hd[u].b + l + 1)
498 560541
                        continue;
499 2015732
                if (hp->hd[u].b[l] != ':')
500 1697256
                        continue;
501 318476
                if (!http_hdr_at(hdr, hp->hd[u].b, l))
502 182223
                        continue;
503 136253
                return (u);
504
        }
505 546685
        return (0);
506 682938
}
507
508
/*--------------------------------------------------------------------
509
 * Count how many instances we have of this header
510
 */
511
512
unsigned
513 31435
http_CountHdr(const struct http *hp, hdr_t hdr)
514
{
515 31435
        unsigned retval = 0;
516
        unsigned u;
517
518 31435
        CHECK_OBJ_NOTNULL(hp, HTTP_MAGIC);
519
520 104956
        for (u = HTTP_HDR_FIRST; u < hp->nhd; u++) {
521 73521
                Tcheck(hp->hd[u]);
522 73521
                if (http_IsHdr(&hp->hd[u], hdr))
523 15565
                        retval++;
524 73521
        }
525 31435
        return (retval);
526
}
527
528
/*--------------------------------------------------------------------
529
 * This function collapses multiple header lines of the same name.
530
 * The lines are joined with a comma, according to [rfc2616, 4.2bot, p32]
531
 */
532
533
void
534 132921
http_CollectHdr(struct http *hp, hdr_t hdr)
535
{
536
537 132921
        http_CollectHdrSep(hp, hdr, NULL);
538 132921
}
539
540
/*--------------------------------------------------------------------
541
 * You may prefer to collapse header fields using a different separator.
542
 * For Cookie headers, the separator is "; " for example. That's probably
543
 * the only example too.
544
 */
545
546
void
547 133526
http_CollectHdrSep(struct http *hp, hdr_t hdr, const char *sep)
548
{
549
        unsigned u, lsep, ml, f, x, d;
550 133526
        char *b = NULL, *e = NULL;
551
        const char *v;
552
553 133526
        CHECK_OBJ_NOTNULL(hp, HTTP_MAGIC);
554 133526
        CHECK_HDR(hdr);
555
556 133526
        if (WS_Overflowed(hp->ws))
557 184
                return;
558
559 133342
        if (sep == NULL || *sep == '\0')
560 132740
                sep = ", ";
561 133342
        lsep = vstrlen(sep);
562
563 133342
        f = http_findhdr(hp, hdr->len - 1, hdr->str);
564 133342
        if (f == 0)
565 131514
                return;
566
567 6672
        for (d = u = f + 1; u < hp->nhd; u++) {
568 4844
                Tcheck(hp->hd[u]);
569 4844
                if (!http_IsHdr(&hp->hd[u], hdr)) {
570 4772
                        if (d != u) {
571 284
                                hp->hd[d] = hp->hd[u];
572 284
                                hp->hdf[d] = hp->hdf[u];
573 284
                        }
574 4772
                        d++;
575 4772
                        continue;
576
                }
577 72
                if (b == NULL) {
578
                        /* Found second header, start our collection */
579 64
                        ml = WS_ReserveAll(hp->ws);
580 64
                        b = WS_Reservation(hp->ws);
581 64
                        e = b + ml;
582 64
                        x = Tlen(hp->hd[f]);
583 64
                        if (b + x >= e) {
584 0
                                http_fail(hp);
585 0
                                VSLbs(hp->vsl, SLT_LostHeader,
586 0
                                    TOSTRAND(hdr->str));
587 0
                                WS_Release(hp->ws, 0);
588 0
                                return;
589
                        }
590 64
                        memcpy(b, hp->hd[f].b, x);
591 64
                        b += x;
592 64
                }
593
594 72
                AN(b);
595 72
                AN(e);
596
597
                /* Append the Nth header we found */
598 72
                x = Tlen(hp->hd[u]) - hdr->len;
599
600 72
                v = hp->hd[u].b + hdr->len;
601 144
                while (vct_issp(*v)) {
602 72
                        v++;
603 72
                        x--;
604
                }
605
606 72
                if (b + lsep + x >= e) {
607 0
                        http_fail(hp);
608 0
                        VSLbs(hp->vsl, SLT_LostHeader, TOSTRAND(hdr->str));
609 0
                        WS_Release(hp->ws, 0);
610 0
                        return;
611
                }
612 72
                memcpy(b, sep, lsep);
613 72
                b += lsep;
614 72
                memcpy(b, v, x);
615 72
                b += x;
616 72
        }
617 1828
        if (b == NULL)
618 1764
                return;
619 64
        hp->nhd = (uint16_t)d;
620 64
        AN(e);
621 64
        *b = '\0';
622 64
        hp->hd[f].b = WS_Reservation(hp->ws);
623 64
        hp->hd[f].e = b;
624 64
        WS_ReleaseP(hp->ws, b + 1);
625 133526
}
626
627
/*--------------------------------------------------------------------*/
628
629
int
630 549101
http_GetHdr(const struct http *hp, hdr_t hdr, const char **ptr)
631
{
632
        unsigned u;
633
        const char *p;
634
635 549101
        CHECK_HDR(hdr);
636 549101
        u = http_findhdr(hp, hdr->len - 1, hdr->str);
637 549101
        if (u == 0) {
638 415016
                if (ptr != NULL)
639 383993
                        *ptr = NULL;
640 415016
                return (0);
641
        }
642 134085
        if (ptr != NULL) {
643 109232
                p = hp->hd[u].b + hdr->len;
644 218285
                while (vct_issp(*p))
645 109053
                        p++;
646 109232
                *ptr = p;
647 109232
        }
648 134085
        return (1);
649 549101
}
650
651
/*-----------------------------------------------------------------------------
652
 * Split source string at any of the separators, return pointer to first
653
 * and last+1 char of substrings, with whitespace trimmed at both ends.
654
 * If sep being an empty string is shorthand for VCT::SP
655
 * If stop is NULL, src is NUL terminated.
656
 */
657
658
static int
659 10392
http_split(const char **src, const char *stop, const char *sep,
660
    const char **b, const char **e)
661
{
662
        const char *p, *q;
663
664 10392
        AN(src);
665 10392
        AN(*src);
666 10392
        AN(sep);
667 10392
        AN(b);
668 10392
        AN(e);
669
670 10392
        if (stop == NULL)
671 10364
                stop = strchr(*src, '\0');
672
673 17936
        for (p = *src; p < stop && (vct_issp(*p) || strchr(sep, *p)); p++)
674 444
                continue;
675
676 10392
        if (p >= stop) {
677 3736
                *b = NULL;
678 3736
                *e = NULL;
679 3736
                return (0);
680
        }
681
682 6656
        *b = p;
683 6656
        if (*sep == '\0') {
684 0
                for (q = p + 1; q < stop && !vct_issp(*q); q++)
685 0
                        continue;
686 0
                *e = q;
687 0
                *src = q;
688 0
                return (1);
689
        }
690 33256
        for (q = p + 1; q < stop && !strchr(sep, *q); q++)
691 26600
                continue;
692 6656
        *src = q;
693 6656
        while (q > p && vct_issp(q[-1]))
694 0
                q--;
695 6656
        *e = q;
696 6656
        return (1);
697 10392
}
698
699
/*-----------------------------------------------------------------------------
700
 * Comparison rule for tokens:
701
 *      if target string starts with '"', we use memcmp() and expect closing
702
 *      double quote as well
703
 *      otherwise we use http_tok_at()
704
 *
705
 * On match we increment *bp past the token name.
706
 */
707
708
static int
709 5728
http_istoken(const char **bp, const char *e, const char *token)
710
{
711 5728
        int fl = vstrlen(token);
712
        const char *b;
713
714 5728
        AN(bp);
715 5728
        AN(e);
716 5728
        AN(token);
717
718 5728
        b = *bp;
719
720 5728
        if (b + fl + 2 <= e && *b == '"' &&
721 0
            !memcmp(b + 1, token, fl) && b[fl + 1] == '"') {
722 0
                *bp += fl + 2;
723 0
                return (1);
724
        }
725 5920
        if (b + fl <= e && http_tok_at(b, token, fl) &&
726 2672
            (b + fl == e || !vct_istchar(b[fl]))) {
727 2672
                *bp += fl;
728 2672
                return (1);
729
        }
730 3056
        return (0);
731 5728
}
732
733
/*-----------------------------------------------------------------------------
734
 * Find a given data element (token) in a header according to RFC2616's #rule
735
 * (section 2.1, p15)
736
 *
737
 * On case sensitivity:
738
 *
739
 * Section 4.2 (Messages Headers) defines field (header) name as case
740
 * insensitive, but the field (header) value/content may be case-sensitive.
741
 *
742
 * http_GetHdrToken looks up a token in a header value and the rfc does not say
743
 * explicitly if tokens are to be compared with or without respect to case.
744
 *
745
 * But all examples and specific statements regarding tokens follow the rule
746
 * that unquoted tokens are to be matched case-insensitively and quoted tokens
747
 * case-sensitively.
748
 *
749
 * The optional pb and pe arguments will point to the token content start and
750
 * end+1, white space trimmed on both sides.
751
 */
752
753
int
754 61978
http_GetHdrToken(const struct http *hp, hdr_t hdr,
755
    const char *token, const char **pb, const char **pe)
756
{
757
        const char *h, *b, *e;
758
759 61978
        if (pb != NULL)
760 46932
                *pb = NULL;
761 61978
        if (pe != NULL)
762 14552
                *pe = NULL;
763 61978
        if (!http_GetHdr(hp, hdr, &h))
764 56426
                return (0);
765 5552
        AN(h);
766
767 8608
        while (http_split(&h, NULL, ",", &b, &e))
768 5728
                if (http_istoken(&b, e, token))
769 2672
                        break;
770 5552
        if (b == NULL)
771 2880
                return (0);
772 2672
        if (pb != NULL) {
773 2656
                for (; vct_islws(*b); b++)
774 20
                        continue;
775 2636
                if (b == e) {
776 2448
                        b = NULL;
777 2448
                        e = NULL;
778 2448
                }
779 2636
                *pb = b;
780 2636
                if (pe != NULL)
781 2420
                        *pe = e;
782 2636
        }
783 2672
        return (1);
784 61978
}
785
786
/*--------------------------------------------------------------------
787
 * Find a given header field's quality value (qvalue).
788
 */
789
790
double
791 14552
http_GetHdrQ(const struct http *hp, hdr_t hdr, const char *field)
792
{
793
        const char *hb, *he, *b, *e;
794
        int i;
795
        double a, f;
796
797 14552
        i = http_GetHdrToken(hp, hdr, field, &hb, &he);
798 14552
        if (!i)
799 12132
                return (0.);
800
801 2420
        if (hb == NULL)
802 2392
                return (1.);
803 28
        while (http_split(&hb, he, ";", &b, &e)) {
804 28
                if (*b != 'q')
805 0
                        continue;
806 28
                for (b++; b < e && vct_issp(*b); b++)
807 0
                        continue;
808 28
                if (b == e || *b != '=')
809 0
                        continue;
810 28
                break;
811
        }
812 28
        if (b == NULL)
813 0
                return (1.);
814 28
        for (b++; b < e && vct_issp(*b); b++)
815 0
                continue;
816 28
        if (b == e || (*b != '.' && !vct_isdigit(*b)))
817 4
                return (0.);
818 24
        a = 0;
819 48
        while (b < e && vct_isdigit(*b)) {
820 24
                a *= 10.;
821 24
                a += *b - '0';
822 24
                b++;
823
        }
824 24
        if (b == e || *b++ != '.')
825 4
                return (a);
826 20
        f = .1;
827 64
        while (b < e && vct_isdigit(*b)) {
828 44
                a += f * (*b - '0');
829 44
                f *= .1;
830 44
                b++;
831
        }
832 20
        return (a);
833 14552
}
834
835
/*--------------------------------------------------------------------
836
 * Find a given header field's value.
837
 */
838
839
int
840 32378
http_GetHdrField(const struct http *hp, hdr_t hdr,
841
    const char *field, const char **ptr)
842
{
843
        const char *h;
844
        int i;
845
846 32378
        if (ptr != NULL)
847 16468
                *ptr = NULL;
848
849 32378
        h = NULL;
850 32378
        i = http_GetHdrToken(hp, hdr, field, &h, NULL);
851 32378
        if (!i)
852 32162
                return (i);
853
854 216
        if (ptr != NULL && h != NULL) {
855
                /* Skip whitespace, looking for '=' */
856 160
                while (*h && vct_issp(*h))
857 0
                        h++;
858 160
                if (*h == '=') {
859 160
                        h++;
860 176
                        while (*h && vct_issp(*h))
861 16
                                h++;
862 160
                        *ptr = h;
863 160
                }
864 160
        }
865 216
        return (i);
866 32378
}
867
868
/*--------------------------------------------------------------------*/
869
870
ssize_t
871 46469
http_GetContentLength(const struct http *hp)
872
{
873
        ssize_t cl;
874
        const char *b;
875
876 46469
        CHECK_OBJ_NOTNULL(hp, HTTP_MAGIC);
877
878 46469
        if (!http_GetHdr(hp, H_Content_Length, &b))
879 20302
                return (-1);
880 26167
        cl = VNUM_uint(b, NULL, &b);
881 26167
        if (cl < 0)
882 16
                return (-2);
883 26151
        while (vct_islws(*b))
884 0
                b++;
885 26151
        if (*b != '\0')
886 0
                return (-2);
887 26151
        return (cl);
888 46469
}
889
890
ssize_t
891 8372
http_GetContentRange(const struct http *hp, ssize_t *lo, ssize_t *hi)
892
{
893
        ssize_t tmp, cl;
894
        const char *b, *t;
895
896 8372
        CHECK_OBJ_NOTNULL(hp, HTTP_MAGIC);
897
898 8372
        if (lo == NULL)
899 0
                lo = &tmp;
900 8372
        if (hi == NULL)
901 0
                hi = &tmp;
902
903 8372
        *lo = *hi = -1;
904
905 8372
        if (!http_GetHdr(hp, H_Content_Range, &b))
906 8332
                return (-1);
907
908 40
        t = strchr(b, ' ');
909 40
        if (t == NULL)
910 4
                return (-2);            // Missing space after range unit
911
912 36
        if (!http_range_at(b, bytes, t - b))
913 4
                return (-1);            // Unknown range unit, ignore
914 32
        b = t + 1;
915
916 32
        if (*b == '*') {                // Content-Range: bytes */123
917 12
                *lo = *hi = -1;
918 12
                b++;
919 12
        } else {                        // Content-Range: bytes 1-2/3
920 20
                *lo = VNUM_uint(b, NULL, &b);
921 20
                if (*lo < 0)
922 0
                        return (-2);
923 20
                if (*b != '-')
924 0
                        return (-2);
925 20
                *hi = VNUM_uint(b + 1, NULL, &b);
926 20
                if (*hi < 0)
927 0
                        return (-2);
928
        }
929 32
        if (*b != '/')
930 0
                return (-2);
931 32
        if (b[1] == '*') {              // Content-Range: bytes 1-2/*
932 4
                cl = -1;
933 4
                b += 2;
934 4
        } else {
935 28
                cl = VNUM_uint(b + 1, NULL, &b);
936 28
                if (cl <= 0)
937 0
                        return (-2);
938
        }
939 32
        while (vct_islws(*b))
940 0
                b++;
941 32
        if (*b != '\0')
942 0
                return (-2);
943 32
        if (*lo > *hi)
944 0
                return (-2);
945 32
        assert(cl >= -1);
946 32
        if (*lo >= cl || *hi >= cl)
947 4
                return (-2);
948 28
        AN(cl);
949 28
        return (cl);
950 8372
}
951
952
const char *
953 8572
http_GetRange(const struct http *hp, ssize_t *lo, ssize_t *hi, ssize_t len)
954
{
955
        ssize_t tmp_lo, tmp_hi;
956
        const char *b, *t;
957
958 8572
        CHECK_OBJ_NOTNULL(hp, HTTP_MAGIC);
959
960 8572
        if (lo == NULL)
961 0
                lo = &tmp_lo;
962 8572
        if (hi == NULL)
963 0
                hi = &tmp_hi;
964
965 8572
        *lo = *hi = -1;
966
967 8572
        if (!http_GetHdr(hp, H_Range, &b))
968 8348
                return (NULL);
969
970
        // rfc9110,l,6481,6484
971 224
        if (!http_method_eq(hp->wkm, WKM_GET))
972 4
                return (NULL);
973
974 220
        t = strchr(b, '=');
975 220
        if (t == NULL)
976 8
                return ("Missing '='");
977
978 212
        if (!http_range_at(b, bytes, t - b))
979 12
                return ("Not Bytes");
980 200
        b = t + 1;
981
982 200
        *lo = VNUM_uint(b, NULL, &b);
983 200
        if (*lo == -2)
984 0
                return ("Low number too big");
985 200
        if (*b++ != '-')
986 0
                return ("Missing hyphen");
987
988 200
        *hi = VNUM_uint(b, NULL, &b);
989 200
        if (*hi == -2)
990 0
                return ("High number too big");
991 200
        if (*lo == -1 && *hi == -1)
992 4
                return ("Neither high nor low");
993 196
        if (*lo == -1 && *hi == 0)
994 4
                return ("No low, high is zero");
995 192
        if (*hi >= 0 && *hi < *lo)
996 4
                return ("high smaller than low");
997
998 192
        while (vct_islws(*b))
999 4
                b++;
1000 188
        if (*b != '\0')
1001 4
                return ("Trailing stuff");
1002
1003 184
        assert(*lo >= -1);
1004 184
        assert(*hi >= -1);
1005
1006 184
        if (*lo < 0) {
1007 16
                assert(*hi > 0);
1008 16
                *lo = len - *hi;
1009 16
                if (*lo < 0)
1010 8
                        *lo = 0;
1011 16
                *hi = len - 1;
1012 184
        } else if (len >= 0 && (*hi >= len || *hi < 0)) {
1013 36
                *hi = len - 1;
1014 36
        }
1015
1016 184
        if (len <= 0)
1017 72
                return (NULL);                  // Allow 200 response
1018
1019 112
        if (*lo >= len)
1020 4
                return ("low range beyond object");
1021
1022 108
        return (NULL);
1023 8572
}
1024
1025
/*--------------------------------------------------------------------
1026
 */
1027
1028
stream_close_t
1029 56020
http_DoConnection(struct http *hp, stream_close_t sc_close)
1030
{
1031
        const char *h, *b, *e;
1032
        stream_close_t retval;
1033
        unsigned u, v;
1034
        struct http_hdrflg *f;
1035
1036 56020
        CHECK_OBJ_NOTNULL(hp, HTTP_MAGIC);
1037 56020
        assert(sc_close == SC_REQ_CLOSE || sc_close == SC_RESP_CLOSE);
1038
1039 56020
        if (hp->protover == 10)
1040 161
                retval = SC_REQ_HTTP10;
1041
        else
1042 55859
                retval = SC_NULL;
1043
1044 56020
        http_CollectHdr(hp, H_Connection);
1045 56020
        if (!http_GetHdr(hp, H_Connection, &h))
1046 55152
                return (retval);
1047 868
        AN(h);
1048 1756
        while (http_split(&h, NULL, ",", &b, &e)) {
1049 900
                u = pdiff(b, e);
1050 900
                if (u == 5 && http_hdr_at(b, "close", u))
1051 680
                        retval = sc_close;
1052 900
                if (u == 10 && http_hdr_at(b, "keep-alive", u))
1053 136
                        retval = SC_NULL;
1054
1055
                /* Refuse removal of well-known-headers if they would pass. */
1056 900
                f = http_hdr_flags(b, e);
1057 900
                if (f != NULL && !(f->flag & HTTPH_R_PASS))
1058 12
                        return (SC_RX_BAD);
1059
1060 4740
                for (v = HTTP_HDR_FIRST; v < hp->nhd; v++) {
1061 3852
                        Tcheck(hp->hd[v]);
1062 3852
                        if (hp->hd[v].e < hp->hd[v].b + u + 1)
1063 160
                                continue;
1064 3692
                        if (hp->hd[v].b[u] != ':')
1065 3344
                                continue;
1066 348
                        if (!http_hdr_at(b, hp->hd[v].b, u))
1067 276
                                continue;
1068 72
                        hp->hdf[v] |= HDF_FILTER;
1069 72
                }
1070
        }
1071 856
        CHECK_OBJ_NOTNULL(retval, STREAM_CLOSE_MAGIC);
1072 856
        return (retval);
1073 56020
}
1074
1075
/*--------------------------------------------------------------------*/
1076
1077
int
1078 44941
http_HdrIs(const struct http *hp, hdr_t hdr, const char *val)
1079
{
1080
        const char *p;
1081
1082 44941
        if (!http_GetHdr(hp, hdr, &p))
1083 42562
                return (0);
1084 2379
        AN(p);
1085 2379
        if (http_tok_eq(p, val))
1086 2267
                return (1);
1087 112
        return (0);
1088 44941
}
1089
1090
/*--------------------------------------------------------------------*/
1091
1092
uint16_t
1093 59941
http_GetStatus(const struct http *hp)
1094
{
1095
1096 59941
        CHECK_OBJ_NOTNULL(hp, HTTP_MAGIC);
1097 59941
        return (hp->status);
1098
}
1099
1100
int
1101 41762
http_IsStatus(const struct http *hp, int val)
1102
{
1103
1104 41762
        CHECK_OBJ_NOTNULL(hp, HTTP_MAGIC);
1105 41762
        assert(val >= 100 && val <= 999);
1106 41762
        return (val == (hp->status % 1000));
1107
}
1108
1109
/*--------------------------------------------------------------------
1110
 * Setting the status will also set the Reason appropriately
1111
 */
1112
1113
void
1114 4660
http_SetStatus(struct http *to, uint16_t status, const char *reason)
1115
{
1116
        char buf[4];
1117 4660
        const char *sstr = NULL;
1118
1119 4660
        CHECK_OBJ_NOTNULL(to, HTTP_MAGIC);
1120
        /*
1121
         * We allow people to use top digits for internal VCL
1122
         * signalling, but strip them from the ASCII version.
1123
         */
1124 4660
        to->status = status;
1125 4660
        status %= 1000;
1126 4660
        assert(status >= 100);
1127
1128 4660
        if (reason == NULL)
1129 940
                reason = http_Status2Reason(status, &sstr);
1130
        else
1131 3720
                (void)http_Status2Reason(status, &sstr);
1132
1133 4660
        if (sstr) {
1134 4524
                http_SetH(to, HTTP_HDR_STATUS, sstr);
1135 4524
        } else {
1136 136
                bprintf(buf, "%03d", status);
1137 136
                http_PutField(to, HTTP_HDR_STATUS, buf);
1138
        }
1139 4660
        http_SetH(to, HTTP_HDR_REASON, reason);
1140 4660
}
1141
1142
/*--------------------------------------------------------------------*/
1143
1144
const char *
1145 23792
http_GetMethod(const struct http *hp)
1146
{
1147
1148 23792
        CHECK_OBJ_NOTNULL(hp, HTTP_MAGIC);
1149 23792
        Tcheck(hp->hd[HTTP_HDR_METHOD]);
1150 23792
        return (hp->hd[HTTP_HDR_METHOD].b);
1151
}
1152
1153
/*--------------------------------------------------------------------
1154
 * Force a particular header field to a particular value
1155
 */
1156
1157
void
1158 32146
http_ForceField(struct http *to, unsigned n, const char *t)
1159
{
1160
        int i;
1161
1162 32146
        CHECK_OBJ_NOTNULL(to, HTTP_MAGIC);
1163 32146
        assert(n < HTTP_HDR_FIRST);
1164 32146
        assert(n == HTTP_HDR_METHOD || n == HTTP_HDR_PROTO);
1165 32146
        AN(t);
1166
1167
        /* NB: method names and protocol versions are case-sensitive. */
1168 32146
        if (to->hd[n].b == NULL || vstrcmp(to->hd[n].b, t)) {
1169 496
                i = (HTTP_HDR_UNSET - HTTP_HDR_METHOD);
1170 496
                i += to->logtag;
1171
                /* XXX: this is a dead branch */
1172 496
                if (n >= HTTP_HDR_FIRST)
1173 0
                        VSLbt(to->vsl, (enum VSL_tag_e)i, to->hd[n]);
1174 496
                http_SetH(to, n, t);
1175 496
        }
1176 32146
}
1177
1178
/*--------------------------------------------------------------------*/
1179
1180
void
1181 4250
http_PutResponse(struct http *to, const char *proto, uint16_t status,
1182
    const char *reason)
1183
{
1184
1185 4250
        CHECK_OBJ_NOTNULL(to, HTTP_MAGIC);
1186 4250
        if (proto != NULL)
1187 4250
                http_SetH(to, HTTP_HDR_PROTO, proto);
1188 4250
        http_SetStatus(to, status, reason);
1189 4250
}
1190
1191
/*--------------------------------------------------------------------
1192
 * check if header is filtered by the dynamic marker or the static
1193
 * definitions in http_headers.h
1194
 */
1195
1196
static inline int
1197 166837
http_isfiltered(const struct http *fm, unsigned u, unsigned how)
1198
{
1199
        const char *e;
1200
        const struct http_hdrflg *f;
1201
1202 166837
        if (fm->hdf[u] & HDF_FILTER)
1203 68
                return (1);
1204 166769
        if (u < HTTP_HDR_FIRST)
1205 55978
                return (0);
1206 110791
        e = strchr(fm->hd[u].b, ':');
1207 110791
        if (e == NULL)
1208 0
                return (0);
1209 110791
        f = http_hdr_flags(fm->hd[u].b, e);
1210 110791
        return (f != NULL && f->flag & how);
1211 166837
}
1212
1213
int
1214 3381
http_IsFiltered(const struct http *fm, unsigned u, unsigned how)
1215
{
1216
1217 3381
        return (http_isfiltered(fm, u, how));
1218
}
1219
1220
/*--------------------------------------------------------------------
1221
 * Estimate how much workspace we need to Filter this header according
1222
 * to 'how'.
1223
 */
1224
1225
unsigned
1226 9344
http_EstimateWS(const struct http *fm, unsigned how)
1227
{
1228
        unsigned u, l;
1229
1230 9344
        l = 4;
1231 9344
        CHECK_OBJ_NOTNULL(fm, HTTP_MAGIC);
1232 89337
        for (u = 0; u < fm->nhd; u++) {
1233 79993
                if (u == HTTP_HDR_METHOD || u == HTTP_HDR_URL)
1234 18688
                        continue;
1235 61305
                Tcheck(fm->hd[u]);
1236 61305
                if (http_isfiltered(fm, u, how))
1237 1132
                        continue;
1238 60173
                l += Tlen(fm->hd[u]) + 1L;
1239 60173
        }
1240 9344
        return (PRNDUP(l + 1L));
1241
}
1242
1243
/*--------------------------------------------------------------------
1244
 * Encode http struct as byte string.
1245
 *
1246
 * XXX: We could save considerable special-casing below by encoding also
1247
 * XXX: H__Status, H__Reason and H__Proto into the string, but it would
1248
 * XXX: add 26-30 bytes to all encoded objects to save a little code.
1249
 * XXX: It could possibly be a good idea for later HTTP versions.
1250
 */
1251
1252
void
1253 9320
HTTP_Encode(const struct http *fm, uint8_t *p0, unsigned l, unsigned how)
1254
{
1255
        unsigned u, w;
1256
        uint16_t n;
1257
        uint8_t *p, *e;
1258
1259 9320
        AN(p0);
1260 9320
        AN(l);
1261 9320
        p = p0;
1262 9320
        e = p + l;
1263 9320
        assert(p + 5 <= e);
1264 9320
        assert(fm->nhd <= fm->shd);
1265 9320
        n = HTTP_HDR_FIRST - 3;
1266 9320
        vbe16enc(p + 2, fm->status);
1267 9320
        p += 4;
1268 9320
        CHECK_OBJ_NOTNULL(fm, HTTP_MAGIC);
1269 89084
        for (u = 0; u < fm->nhd; u++) {
1270 79764
                if (u == HTTP_HDR_METHOD || u == HTTP_HDR_URL)
1271 18636
                        continue;
1272 61128
                Tcheck(fm->hd[u]);
1273 61128
                if (http_isfiltered(fm, u, how))
1274 1132
                        continue;
1275 59996
                http_VSLH(fm, u);
1276 59996
                w = Tlen(fm->hd[u]) + 1L;
1277 59996
                assert(p + w + 1 <= e);
1278 59996
                memcpy(p, fm->hd[u].b, w);
1279 59996
                p += w;
1280 59996
                n++;
1281 59996
        }
1282 9320
        *p++ = '\0';
1283 9320
        assert(p <= e);
1284 9320
        vbe16enc(p0, n + 1);
1285 9320
}
1286
1287
/*--------------------------------------------------------------------
1288
 * Decode byte string into http struct
1289
 */
1290
1291
int
1292 13636
HTTP_Decode(struct http *to, const uint8_t *fm)
1293
{
1294
1295 13636
        CHECK_OBJ_NOTNULL(to, HTTP_MAGIC);
1296 13636
        AN(to->vsl);
1297 13636
        AN(fm);
1298 13636
        if (vbe16dec(fm) <= to->shd) {
1299 13627
                to->status = vbe16dec(fm + 2);
1300 13627
                fm += 4;
1301 129156
                for (to->nhd = 0; to->nhd < to->shd; to->nhd++) {
1302 129156
                        if (to->nhd == HTTP_HDR_METHOD ||
1303 115516
                            to->nhd == HTTP_HDR_URL) {
1304 27252
                                to->hd[to->nhd].b = NULL;
1305 27252
                                to->hd[to->nhd].e = NULL;
1306 27252
                                continue;
1307
                        }
1308 101904
                        if (*fm == '\0')
1309 13627
                                return (0);
1310 88277
                        to->hd[to->nhd].b = (const void*)fm;
1311 88277
                        fm = (const void*)strchr((const void*)fm, '\0');
1312 88277
                        to->hd[to->nhd].e = (const void*)fm;
1313 88277
                        fm++;
1314 88277
                        http_VSLH(to, to->nhd);
1315 88277
                }
1316 0
        }
1317 18
        VSLb(to->vsl, SLT_Error,
1318
            "Too many headers to Decode object (%u vs. %u)",
1319 9
            vbe16dec(fm), to->shd);
1320 9
        return (-1);
1321 13636
}
1322
1323
/*--------------------------------------------------------------------*/
1324
1325
uint16_t
1326 136
HTTP_GetStatusPack(struct worker *wrk, struct objcore *oc)
1327
{
1328
        const char *ptr;
1329 136
        ptr = ObjGetAttr(wrk, oc, OA_HEADERS, NULL);
1330 136
        AN(ptr);
1331
1332 136
        return (vbe16dec(ptr + 2));
1333
}
1334
1335
/*--------------------------------------------------------------------*/
1336
1337
/* Get the first packed header */
1338
int
1339 3676
HTTP_IterHdrPack(struct worker *wrk, struct objcore *oc, const char **p)
1340
{
1341
        const char *ptr;
1342
1343 3676
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
1344 3676
        CHECK_OBJ_NOTNULL(oc, OBJCORE_MAGIC);
1345 3676
        AN(p);
1346
1347 3676
        if (*p == NULL) {
1348 1138
                ptr = ObjGetAttr(wrk, oc, OA_HEADERS, NULL);
1349 1138
                AN(ptr);
1350 1138
                ptr += 4;       /* Skip nhd and status */
1351 1138
                ptr = strchr(ptr, '\0') + 1;    /* Skip :proto: */
1352 1138
                ptr = strchr(ptr, '\0') + 1;    /* Skip :status: */
1353 1138
                ptr = strchr(ptr, '\0') + 1;    /* Skip :reason: */
1354 1138
                *p = ptr;
1355 1138
        } else {
1356 2538
                *p = strchr(*p, '\0') + 1;      /* Skip to next header */
1357
        }
1358 3676
        if (**p == '\0')
1359 235
                return (0);
1360 3441
        return (1);
1361 3676
}
1362
1363
const char *
1364 1210
HTTP_GetHdrPack(struct worker *wrk, struct objcore *oc, hdr_t hdr)
1365
{
1366
        const char *ptr;
1367
1368 1210
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
1369 1210
        CHECK_OBJ_NOTNULL(oc, OBJCORE_MAGIC);
1370 1210
        CHECK_HDR(hdr);
1371
1372 1210
        if (hdr->str[0] == ':') {
1373
                /* Special cases */
1374 72
                ptr = ObjGetAttr(wrk, oc, OA_HEADERS, NULL);
1375 72
                AN(ptr);
1376 72
                ptr += 4;       /* Skip nhd and status */
1377
1378
                /* XXX: should we also have h2_hdr_eq() ? */
1379 72
                if (!vstrcmp(hdr->str, ":proto:"))
1380 8
                        return (ptr);
1381 64
                ptr = strchr(ptr, '\0') + 1;
1382 64
                if (!vstrcmp(hdr->str, ":status:"))
1383 56
                        return (ptr);
1384 8
                ptr = strchr(ptr, '\0') + 1;
1385 8
                if (!vstrcmp(hdr->str, ":reason:"))
1386 8
                        return (ptr);
1387 0
                WRONG("Unknown magic packed header");
1388 0
        }
1389
1390 3676
        HTTP_FOREACH_PACK(wrk, oc, ptr) {
1391 3441
                if (http_hdr_at(ptr, hdr->str, hdr->len)) {
1392 903
                        ptr += hdr->len;
1393 1802
                        while (vct_islws(*ptr))
1394 899
                                ptr++;
1395 903
                        return (ptr);
1396
                }
1397
        }
1398
1399 235
        return (NULL);
1400 1210
}
1401
1402
/*--------------------------------------------------------------------
1403
 * Merge any headers in the oc->OA_HEADER into the struct http if they
1404
 * are not there already.
1405
 */
1406
1407
void
1408 128
HTTP_Merge(struct worker *wrk, struct objcore *oc, struct http *to)
1409
{
1410
        const char *ptr;
1411
        unsigned u;
1412
        const char *p;
1413
        unsigned nhd_before_merge;
1414
1415 128
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
1416 128
        CHECK_OBJ_NOTNULL(oc, OBJCORE_MAGIC);
1417 128
        CHECK_OBJ_NOTNULL(to, HTTP_MAGIC);
1418
1419 128
        ptr = ObjGetAttr(wrk, oc, OA_HEADERS, NULL);
1420 128
        AN(ptr);
1421
1422 128
        to->status = vbe16dec(ptr + 2);
1423 128
        ptr += 4;
1424
1425 768
        for (u = 0; u < HTTP_HDR_FIRST; u++) {
1426 640
                if (u == HTTP_HDR_METHOD || u == HTTP_HDR_URL)
1427 256
                        continue;
1428 384
                http_SetH(to, u, ptr);
1429 384
                ptr = strchr(ptr, '\0') + 1;
1430 384
        }
1431 128
        nhd_before_merge = to->nhd;
1432 764
        while (*ptr != '\0') {
1433 636
                p = strchr(ptr, ':');
1434 636
                AN(p);
1435 636
                u = http_findhdr(to, p - ptr, ptr);
1436 636
                if (u == 0 || u >= nhd_before_merge)
1437 300
                        http_SetHeader(to, ptr);
1438 636
                ptr = strchr(ptr, '\0') + 1;
1439
        }
1440 128
}
1441
1442
/*--------------------------------------------------------------------*/
1443
1444
static void
1445 28641
http_linkh(const struct http *to, const struct http *fm, unsigned n)
1446
{
1447
1448 28641
        assert(n < HTTP_HDR_FIRST);
1449 28641
        Tcheck(fm->hd[n]);
1450 28641
        to->hd[n] = fm->hd[n];
1451 28641
        to->hdf[n] = fm->hdf[n];
1452 28641
        http_VSLH(to, n);
1453 28641
}
1454
1455
/*--------------------------------------------------------------------*/
1456
1457
void
1458 9548
http_FilterReq(struct http *to, const struct http *fm, unsigned how)
1459
{
1460
        unsigned u;
1461
1462 9548
        CHECK_OBJ_NOTNULL(to, HTTP_MAGIC);
1463 9548
        CHECK_OBJ_NOTNULL(fm, HTTP_MAGIC);
1464
1465 9548
        http_linkh(to, fm, HTTP_HDR_METHOD);
1466 9548
        http_SetWellKnownMethod(to);
1467 9548
        http_linkh(to, fm, HTTP_HDR_URL);
1468 9548
        http_linkh(to, fm, HTTP_HDR_PROTO);
1469 9548
        to->protover = fm->protover;
1470 9548
        to->status = fm->status;
1471
1472 9548
        to->nhd = HTTP_HDR_FIRST;
1473 50548
        for (u = HTTP_HDR_FIRST; u < fm->nhd; u++) {
1474 41000
                Tcheck(fm->hd[u]);
1475 41000
                if (http_isfiltered(fm, u, how))
1476 484
                        continue;
1477 40516
                assert (to->nhd < to->shd);
1478 40516
                to->hd[to->nhd] = fm->hd[u];
1479 40516
                to->hdf[to->nhd] = 0;
1480 40516
                http_VSLH(to, to->nhd);
1481 40516
                to->nhd++;
1482 40516
        }
1483 9548
}
1484
1485
/*--------------------------------------------------------------------
1486
 * This function copies any header fields which reference foreign
1487
 * storage into our own WS.
1488
 */
1489
1490
void
1491 9426
http_CopyHome(const struct http *hp)
1492
{
1493
        unsigned u, l;
1494
        const char *p;
1495
1496 102527
        for (u = 0; u < hp->nhd; u++) {
1497 93101
                if (hp->hd[u].b == NULL) {
1498 18852
                        assert(u < HTTP_HDR_FIRST);
1499 18852
                        continue;
1500
                }
1501
1502 74249
                l = Tlen(hp->hd[u]);
1503 74249
                if (WS_Allocated(hp->ws, hp->hd[u].b, l))
1504 5981
                        continue;
1505
1506 68268
                p = WS_Copy(hp->ws, hp->hd[u].b, l + 1L);
1507 68268
                if (p == NULL) {
1508 0
                        http_fail(hp);
1509 0
                        VSLbs(hp->vsl, SLT_LostHeader, TOSTRAND(hp->hd[u].b));
1510 0
                        return;
1511
                }
1512 68268
                hp->hd[u].b = p;
1513 68268
                hp->hd[u].e = p + l;
1514 68268
        }
1515 9426
}
1516
1517
/*--------------------------------------------------------------------*/
1518
1519
void
1520 39265
http_SetHeader(struct http *to, const char *header)
1521
{
1522
1523 39265
        CHECK_OBJ_NOTNULL(to, HTTP_MAGIC);
1524 39265
        if (to->nhd >= to->shd) {
1525 4
                VSLbs(to->vsl, SLT_LostHeader, TOSTRAND(header));
1526 4
                http_fail(to);
1527 4
                return;
1528
        }
1529 39261
        http_SetH(to, to->nhd++, header);
1530 39265
}
1531
1532
/*--------------------------------------------------------------------*/
1533
1534
void
1535 17580
http_ForceHeader(struct http *to, hdr_t hdr, const char *val)
1536
{
1537
1538 17580
        CHECK_OBJ_NOTNULL(to, HTTP_MAGIC);
1539 17580
        if (http_HdrIs(to, hdr, val))
1540 1555
                return;
1541 16025
        http_Unset(to, hdr);
1542 16025
        http_PrintfHeader(to, "%s %s", hdr->str, val);
1543 17580
}
1544
1545
void
1546 44629
http_AppendHeader(struct http *to, hdr_t hdr, const char *val)
1547
{
1548
        const char *old;
1549
1550 44629
        http_CollectHdr(to, hdr);
1551 44629
        if (http_GetHdr(to, hdr, &old)) {
1552 192
                http_Unset(to, hdr);
1553 192
                http_PrintfHeader(to, "%s %s, %s", hdr->str, old, val);
1554 192
        } else {
1555 44437
                http_PrintfHeader(to, "%s %s", hdr->str, val);
1556
        }
1557 44629
}
1558
1559
void
1560 105033
http_PrintfHeader(struct http *to, const char *fmt, ...)
1561
{
1562
        va_list ap, ap2;
1563
        struct vsb vsb[1];
1564
        size_t sz;
1565
        char *p;
1566
1567 105033
        CHECK_OBJ_NOTNULL(to, HTTP_MAGIC);
1568
1569 105033
        va_start(ap, fmt);
1570 105033
        va_copy(ap2, ap);
1571
1572 105033
        WS_VSB_new(vsb, to->ws);
1573 105033
        VSB_vprintf(vsb, fmt, ap);
1574 105033
        p = WS_VSB_finish(vsb, to->ws, &sz);
1575
1576 105033
        if (p == NULL || to->nhd >= to->shd) {
1577 144
                http_fail(to);
1578 144
                VSLbv(to->vsl, SLT_LostHeader, fmt, ap2);
1579 144
        } else {
1580 104889
                http_SetH(to, to->nhd++, p);
1581
        }
1582 105033
        va_end(ap);
1583 105033
        va_end(ap2);
1584 105033
}
1585
1586
void
1587 4300
http_TimeHeader(struct http *to, const char *fmt, vtim_real now)
1588
{
1589
        char *p;
1590
1591 4300
        CHECK_OBJ_NOTNULL(to, HTTP_MAGIC);
1592 4300
        if (to->nhd >= to->shd) {
1593 0
                VSLbs(to->vsl, SLT_LostHeader, TOSTRAND(fmt));
1594 0
                http_fail(to);
1595 0
                return;
1596
        }
1597 4300
        p = WS_Alloc(to->ws, vstrlen(fmt) + VTIM_FORMAT_SIZE);
1598 4300
        if (p == NULL) {
1599 308
                http_fail(to);
1600 308
                VSLbs(to->vsl, SLT_LostHeader, TOSTRAND(fmt));
1601 308
                return;
1602
        }
1603 3992
        strcpy(p, fmt);
1604 3992
        VTIM_format(now, strchr(p, '\0'));
1605 3992
        http_SetH(to, to->nhd++, p);
1606 4300
}
1607
1608
const char *
1609 29128
http_ViaHeader(void)
1610
{
1611
1612 29128
        return (via_hdr);
1613
}
1614
1615
/*--------------------------------------------------------------------*/
1616
1617
void
1618 95583
http_Unset(struct http *hp, hdr_t hdr)
1619
{
1620
        uint16_t u, v;
1621
1622 621508
        for (v = u = HTTP_HDR_FIRST; u < hp->nhd; u++) {
1623 525925
                Tcheck(hp->hd[u]);
1624 525925
                if (http_IsHdr(&hp->hd[u], hdr)) {
1625 4199
                        http_VSLH_del(hp, u);
1626 4199
                        continue;
1627
                }
1628 521726
                if (v != u) {
1629 12104
                        memcpy(&hp->hd[v], &hp->hd[u], sizeof *hp->hd);
1630 12104
                        memcpy(&hp->hdf[v], &hp->hdf[u], sizeof *hp->hdf);
1631 12104
                }
1632 521726
                v++;
1633 521726
        }
1634 95583
        hp->nhd = v;
1635 95583
}
1636
1637
void
1638 23791
http_SetWellKnownMethod(struct http *hp)
1639
{
1640
        size_t l;
1641
        const char *method;
1642
1643 23791
        CHECK_OBJ_NOTNULL(hp, HTTP_MAGIC);
1644
1645 23791
        method = http_GetMethod(hp);
1646 23791
        AN(method);
1647 23791
        l = vstrlen(method);
1648 23791
        hp->wkm = WKM_UNKNOWN;
1649
#define WKM(wk, bit)                                                    \
1650
        do {                                                            \
1651
                if (l == vstrlen(#wk) && !vmemcmp(#wk, method, l)) {    \
1652
                        hp->wkm = WKM_##wk;                             \
1653
                        return;                                         \
1654
                }                                                       \
1655
        } while (0);
1656
#include "tbl/well_known_methods.h"
1657
#undef WKM
1658
}