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
 * Copyright 2026 UPLEX - Nils Goroll Systemoptimierung
4
 * All rights reserved.
5
 *
6
 * Author: Poul-Henning Kamp <phk@phk.freebsd.dk>
7
 *
8
 * SPDX-License-Identifier: BSD-2-Clause
9
 *
10
 * Redistribution and use in source and binary forms, with or without
11
 * modification, are permitted provided that the following conditions
12
 * are met:
13
 * 1. Redistributions of source code must retain the above copyright
14
 *    notice, this list of conditions and the following disclaimer.
15
 * 2. Redistributions in binary form must reproduce the above copyright
16
 *    notice, this list of conditions and the following disclaimer in the
17
 *    documentation and/or other materials provided with the distribution.
18
 *
19
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
20
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22
 * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
23
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29
 * SUCH DAMAGE.
30 131494
 *
31 15015
 * HTTP request storage and manipulation
32 12369
 */
33 7182
34 1596
#include "config.h"
35 1491
36 1365
#include "cache_int.h"
37 1365
#include <stdio.h>
38 1365
#include <stdlib.h>
39 1302
40 1302
#include "common/heritage.h"
41
42
#include "vct.h"
43
#include "vend.h"
44
#include "vnum.h"
45
#include "vtim.h"
46
47
#define BODYSTATUS(U, l, n, a, k)                               \
48
        const struct body_status BS_##U[1] = {{                 \
49
                .name = #l,                                     \
50
                .nbr = n,                                       \
51
                .avail = a,                                     \
52
                .length_known = k                               \
53
        }};
54
#include "tbl/body_status.h"
55
56
57
#define HTTPH(a, b, c) hdr_t b = HDR(a);
58
#include "tbl/http_headers.h"
59
60
hdr_t H__Status = HDR(":status");
61
hdr_t H__Proto  = HDR(":proto");
62
hdr_t H__Reason = HDR(":reason");
63
64
static char * via_hdr;
65
66
/*--------------------------------------------------------------------
67
 * Perfect hash to rapidly recognize headers from tbl/http_headers.h
68
 * which have non-zero flags.
69
 *
70
 * A suitable algorithm can be found with `gperf`:
71
 *
72
 *      tr '" ,' '   ' < include/tbl/http_headers.h |
73
 *              awk '$1 == "H(" {print $2}' |
74
 *              gperf --ignore-case
75
 *
76
 */
77
78
#define GPERF_MIN_WORD_LENGTH 2
79
#define GPERF_MAX_WORD_LENGTH 19
80
#define GPERF_MAX_HASH_VALUE 79
81
82
static const unsigned char http_asso_values[256] = {
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, 80, 80, 80, 80, 80, 80, 80,
88
        80, 80, 80,  0, 80, 80, 80, 80, 80, 80,
89
        80, 80, 80, 80, 80,  5, 80, 20,  0,  0,
90
        5, 10,  5,  5, 80,  0, 15,  0, 20, 80,
91
        40, 80,  0, 35, 10, 20, 55, 45,  0,  0,
92
        80, 80, 80, 80, 80, 80, 80,  5, 80, 20,
93
        0,  0,  5, 10,  5,  5, 80,  0, 15,  0,
94
        20, 80, 40, 80,  0, 35, 10, 20, 55, 45,
95
        0,  0, 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, 80, 80, 80, 80,
108
        80, 80, 80, 80, 80, 80
109
};
110
111
static struct http_hdrflg {
112
        hdr_t           *hdr;
113
        unsigned        flag;
114
} http_hdrflg[GPERF_MAX_HASH_VALUE + 1] = {
115
        { NULL }, { NULL }, { NULL }, { NULL },
116
        { &H_Date },
117
        { &H_Range },
118
        { NULL },
119
        { &H_Referer },
120
        { &H_Age },
121
        { &H_From },
122
        { &H_Keep_Alive },
123
        { &H_Retry_After },
124
        { &H_TE },
125
        { &H_If_Range },
126
        { &H_ETag },
127
        { &H_X_Forwarded_For },
128
        { &H_Expect },
129
        { &H_Trailer },
130
        { &H_If_Match },
131
        { &H_Host },
132
        { &H_Accept_Language },
133
        { &H_Accept },
134
        { &H_If_Modified_Since },
135
        { &H_If_None_Match },
136
        { &H_If_Unmodified_Since },
137
        { NULL },
138
        { &H_Cookie },
139
        { &H_Upgrade },
140
        { &H_Last_Modified },
141
        { &H_Accept_Charset },
142
        { &H_Accept_Encoding },
143
        { &H_Content_MD5 },
144
        { &H_Content_Type },
145
        { &H_Content_Range },
146
        { NULL }, { NULL },
147
        { &H_Content_Language },
148
        { &H_Transfer_Encoding },
149
        { &H_Authorization },
150
        { &H_Content_Length },
151
        { &H_User_Agent },
152
        { &H_Server },
153
        { &H_Expires },
154
        { &H_Location },
155
        { NULL },
156
        { &H_Set_Cookie },
157
        { &H_Content_Encoding },
158
        { &H_Max_Forwards },
159
        { &H_Cache_Control },
160
        { NULL },
161
        { &H_Connection },
162
        { &H_Pragma },
163
        { NULL },
164
        { &H_Accept_Ranges },
165
        { &H_HTTP2_Settings },
166
        { &H_Allow },
167
        { &H_Content_Location },
168
        { NULL },
169
        { &H_Proxy_Authenticate },
170
        { &H_Vary },
171
        { NULL },
172
        { &H_WWW_Authenticate },
173
        { &H_Warning },
174
        { &H_Via },
175
        { NULL }, { NULL }, { NULL }, { NULL },
176
        { NULL }, { NULL }, { NULL }, { NULL },
177
        { NULL }, { NULL }, { NULL }, { NULL },
178
        { NULL }, { NULL }, { NULL },
179
        { &H_Proxy_Authorization }
180
};
181
182
static struct http_hdrflg *
183 1690303
http_hdr_flags(const char *b, const char *e)
184
{
185
        unsigned u;
186
        struct http_hdrflg *retval;
187
188 1690303
        if (b == NULL || e == NULL)
189 172
                return (NULL);
190 1690297
        u = pdiff(b, e);
191 1690297
        if (u < GPERF_MIN_WORD_LENGTH || u > GPERF_MAX_WORD_LENGTH)
192 777
                return (NULL);
193 3379040
        u += http_asso_values[(uint8_t)(e[-1])] +
194 1689520
             http_asso_values[(uint8_t)(b[0])];
195 1689520
        if (u > GPERF_MAX_HASH_VALUE)
196 25563
                return (NULL);
197 1663957
        retval = &http_hdrflg[u];
198 1663957
        if (retval->hdr == NULL)
199 6611
                return (NULL);
200 1657346
        AN(*retval->hdr);
201 1657346
        if (!http_hdr_at(*retval->hdr + 1, b, e - b))
202 22910
                return (NULL);
203 1634436
        return (retval);
204 1690297
}
205
206
/*--------------------------------------------------------------------*/
207
208
static void
209 1086176
http_init_hdr(hdr_t hdr, int flg)
210
{
211
        struct http_hdrflg *f;
212
213 1086176
        f = http_hdr_flags(hdr->str, hdr->str + hdr->len - 1);
214 1086176
        AN(f);
215 1086176
        assert(*f->hdr == hdr);
216 1086176
        f->flag = flg;
217 1086176
}
218
219
void
220 20888
HTTP_Init(void)
221
{
222
        struct vsb *vsb;
223
224
#define HTTPH(a, b, c) http_init_hdr(b, c);
225
#include "tbl/http_headers.h"
226
227
        vsb = VSB_new_auto();
228 20888
        AN(vsb);
229
        VSB_printf(vsb, "1.1 %s (Vinyl-Cache/" PACKAGE_BRANCH ")",
230
            heritage.identity);
231 20888
        AZ(VSB_finish(vsb));
232 20888
        REPLACE(via_hdr, VSB_data(vsb));
233
        VSB_destroy(&vsb);
234
}
235
236
/*--------------------------------------------------------------------
237
 * These two functions are in an incestuous relationship with the
238
 * order of macros in include/tbl/vsl_tags_http.h
239
 *
240
 * The http->logtag is the SLT_*Method enum, and we add to that, to
241
 * get the SLT_ to use.
242
 */
243
244
static void
245 2840649
http_VSLH(const struct http *hp, unsigned hdr)
246
{
247
        int i;
248
249 2840649
        if (hp->vsl != NULL) {
250 2840732
                assert(VXID_TAG(hp->vsl->wid));
251 2840732
                i = hdr;
252 2840732
                if (i > HTTP_HDR_FIRST)
253 1489291
                        i = HTTP_HDR_FIRST;
254 2840732
                i += hp->logtag;
255 2840732
                VSLbt(hp->vsl, (enum VSL_tag_e)i, hp->hd[hdr]);
256 2840732
        }
257 2840817
}
258
259
static void
260 23541
http_VSLH_del(const struct http *hp, unsigned hdr)
261
{
262
        int i;
263
264 23541
        if (hp->vsl != NULL) {
265
                /* We don't support unsetting stuff in the first line */
266 23541
                assert (hdr >= HTTP_HDR_FIRST);
267 23541
                assert(VXID_TAG(hp->vsl->wid));
268 23541
                i = (HTTP_HDR_UNSET - HTTP_HDR_METHOD);
269 23541
                i += hp->logtag;
270 23541
                VSLbt(hp->vsl, (enum VSL_tag_e)i, hp->hd[hdr]);
271 23541
        }
272 23541
}
273
274
/*--------------------------------------------------------------------*/
275
276
void
277 133864
http_VSL_log(const struct http *hp)
278
{
279
        unsigned u;
280
281 1167980
        for (u = 0; u < hp->nhd; u++)
282 1800592
                if (hp->hd[u].b != NULL)
283 766476
                        http_VSLH(hp, u);
284 133864
}
285
286
/*--------------------------------------------------------------------*/
287
288
static void
289 2289
http_fail(const struct http *hp)
290
{
291
        char id[WS_ID_SIZE];
292
293 2289
        VSC_C_main->losthdr++;
294 2289
        WS_Id(hp->ws, id);
295 2289
        VSLb(hp->vsl, SLT_Error, "out of workspace (%s)", id);
296 2289
        WS_MarkOverflow(hp->ws);
297 2289
}
298
299
/*--------------------------------------------------------------------
300
 * List of canonical HTTP response code names from RFC2616
301
 */
302
303
static struct http_msg {
304
        unsigned        nbr;
305
        const char      *status;
306
        const char      *txt;
307
} http_msg[] = {
308
#define HTTP_RESP(n, t) { n, #n, t},
309
#include "tbl/http_response.h"
310
        { 0, "0", NULL }
311
};
312
313
const char *
314 38977
http_Status2Reason(unsigned status, const char **sstr)
315
{
316
        struct http_msg *mp;
317
318 38977
        status %= 1000;
319 38977
        assert(status >= 100);
320 1031132
        for (mp = http_msg; mp->nbr != 0 && mp->nbr <= status; mp++)
321 1030133
                if (mp->nbr == status) {
322 37978
                        if (sstr)
323 25909
                                *sstr = mp->status;
324 37978
                        return (mp->txt);
325
                }
326 987
        return ("Unknown HTTP Status");
327 38965
}
328
329
/*--------------------------------------------------------------------*/
330
331
unsigned
332 120215
HTTP_estimate(unsigned nhttp)
333
{
334
335
        /* XXX: We trust the structs to size-aligned as necessary */
336 120215
        return (PRNDUP(sizeof(struct http) + sizeof(txt) * nhttp + nhttp));
337
}
338
339
struct http *
340 360647
HTTP_create(void *p, uint16_t nhttp, unsigned len)
341
{
342
        struct http *hp;
343
344 360647
        hp = p;
345 360647
        hp->magic = HTTP_MAGIC;
346 360647
        hp->hd = (void*)(hp + 1);
347 360647
        hp->shd = nhttp;
348 360647
        hp->hdf = (void*)(hp->hd + nhttp);
349 360647
        assert((unsigned char*)p + len == hp->hdf + PRNDUP(nhttp));
350 360647
        return (hp);
351
}
352
353
/*--------------------------------------------------------------------*/
354
355
void
356 339267
HTTP_Setup(struct http *hp, struct ws *ws, struct vsl_log *vsl,
357
    enum VSL_tag_e  whence)
358
{
359 339267
        http_Teardown(hp);
360 339267
        hp->nhd = HTTP_HDR_FIRST;
361 339267
        hp->logtag = whence;
362 339267
        hp->ws = ws;
363 339267
        hp->vsl = vsl;
364 339267
        hp->wkm = WKM_UNKNOWN;
365 339267
}
366
367
/*--------------------------------------------------------------------
368
 * http_Teardown() is a safety feature, we use it to zap all http
369
 * structs once we're done with them, to minimize the risk that
370
 * old stale pointers exist to no longer valid stuff.
371
 */
372
373
void
374 528987
http_Teardown(struct http *hp)
375
{
376
377 528987
        CHECK_OBJ_NOTNULL(hp, HTTP_MAGIC);
378 528987
        AN(hp->shd);
379 528987
        memset(&hp->nhd, 0, sizeof *hp - offsetof(struct http, nhd));
380 528987
        memset(hp->hd, 0, sizeof *hp->hd * hp->shd);
381 528987
        memset(hp->hdf, 0, sizeof *hp->hdf * hp->shd);
382 528987
}
383
384
/*--------------------------------------------------------------------
385
 * Duplicate the http content into another http
386
 * We cannot just memcpy the struct because the hd & hdf are private
387
 * storage to the struct http.
388
 */
389
390
void
391 148086
HTTP_Dup(struct http *to, const struct http * fm)
392
{
393
394 148086
        assert(fm->nhd <= to->shd);
395 148086
        vmemcpy(to->hd, fm->hd, fm->nhd * sizeof *to->hd);
396 148086
        vmemcpy(to->hdf, fm->hdf, fm->nhd * sizeof *to->hdf);
397 148086
        to->nhd = fm->nhd;
398 148086
        to->logtag = fm->logtag;
399 148086
        to->status = fm->status;
400 148086
        to->protover = fm->protover;
401 148086
        to->wkm = fm->wkm;
402 148086
}
403
404
405
/*--------------------------------------------------------------------
406
 * Clone the entire http structure, including vsl & ws
407
 */
408
409
void
410 140310
HTTP_Clone(struct http *to, const struct http * const fm)
411
{
412
413 140310
        HTTP_Dup(to, fm);
414 140310
        to->vsl = fm->vsl;
415 140310
        to->ws = fm->ws;
416 140310
}
417
418
/*--------------------------------------------------------------------*/
419
420
void
421 154475
http_Proto(struct http *to)
422
{
423
        const char *fm;
424
425 154475
        fm = to->hd[HTTP_HDR_PROTO].b;
426
427 308765
        if (fm != NULL &&
428 154311
            (fm[0] == 'H' || fm[0] == 'h') &&
429 154291
            (fm[1] == 'T' || fm[1] == 't') &&
430 154291
            (fm[2] == 'T' || fm[2] == 't') &&
431 154291
            (fm[3] == 'P' || fm[3] == 'p') &&
432 154291
            fm[4] == '/' &&
433 154291
            vct_isdigit(fm[5]) &&
434 154288
            fm[6] == '.' &&
435 154288
            vct_isdigit(fm[7]) &&
436 154290
            fm[8] == '\0') {
437 154290
                to->protover = 10 * (fm[5] - '0') + (fm[7] - '0');
438 154290
        } else {
439 189
                to->protover = 0;
440
        }
441 154479
}
442
443
/*--------------------------------------------------------------------*/
444
445
void
446 902141
http_SetH(struct http *to, unsigned n, const char *header)
447
{
448
449 902141
        assert(n < to->nhd);
450 902141
        AN(header);
451 902141
        to->hd[n].b = TRUST_ME(header);
452 902141
        to->hd[n].e = strchr(to->hd[n].b, '\0');
453 902141
        to->hdf[n] = 0;
454 902141
        http_VSLH(to, n);
455 902141
        if (n == HTTP_HDR_PROTO)
456 31535
                http_Proto(to);
457 902141
        if (n == HTTP_HDR_METHOD)
458 819
                http_SetWellKnownMethod(to);
459 902141
}
460
461
/*--------------------------------------------------------------------*/
462
463
static void
464 735
http_PutField(struct http *to, int field, const char *string)
465
{
466
        const char *p;
467
468 735
        CHECK_OBJ_NOTNULL(to, HTTP_MAGIC);
469 735
        p = WS_Copy(to->ws, string, -1);
470 735
        if (p == NULL) {
471 21
                http_fail(to);
472 21
                VSLbs(to->vsl, SLT_LostHeader, TOSTRAND(string));
473 21
                return;
474
        }
475 714
        http_SetH(to, field, p);
476 735
}
477
478
/*--------------------------------------------------------------------*/
479
480
int
481 4089210
http_IsHdr(const txt *hh, hdr_t hdr)
482
{
483
484 4089210
        Tcheck(*hh);
485 4089210
        CHECK_HDR(hdr);
486 4089210
        return (http_hdr_at(hdr->str, hh->b, hdr->len));
487
}
488
489
/*--------------------------------------------------------------------*/
490
491
static unsigned
492 3453014
http_findhdr(const struct http *hp, unsigned l, const char *hdr)
493
{
494
        unsigned u;
495
496 15991322
        for (u = HTTP_HDR_FIRST; u < hp->nhd; u++) {
497 13120656
                Tcheck(hp->hd[u]);
498 13120656
                if (hp->hd[u].e < hp->hd[u].b + l + 1)
499 2714819
                        continue;
500 10405837
                if (hp->hd[u].b[l] != ':')
501 8843878
                        continue;
502 1561959
                if (!http_hdr_at(hdr, hp->hd[u].b, l))
503 979611
                        continue;
504 582348
                return (u);
505
        }
506 2870666
        return (0);
507 3453014
}
508
509
/*--------------------------------------------------------------------
510
 * Count how many instances we have of this header
511
 */
512
513
unsigned
514 92702
http_CountHdr(const struct http *hp, hdr_t hdr)
515
{
516 92702
        unsigned retval = 0;
517
        unsigned u;
518
519 92702
        CHECK_OBJ_NOTNULL(hp, HTTP_MAGIC);
520
521 308567
        for (u = HTTP_HDR_FIRST; u < hp->nhd; u++) {
522 215865
                Tcheck(hp->hd[u]);
523 215865
                if (http_IsHdr(&hp->hd[u], hdr))
524 86998
                        retval++;
525 215865
        }
526 92702
        return (retval);
527
}
528
529
/*--------------------------------------------------------------------
530
 * This function collapses multiple header lines of the same name.
531
 * The lines are joined with a comma, according to [rfc2616, 4.2bot, p32]
532
 *
533
 * XXX Collection of issues / open questions with the CollectHdr family of
534
 * functions
535
 * - should know which header is list-type, attempting collect on singleton
536
 *   should fail (in particular Host)
537
 *   - For list type, consider "value, containing, comma" vs v1, v2
538
 *   - but no complete list exists
539
 * - should offer to keep uniqe values only (Content-Length)
540
 * - should skip h2 pseudo headers (starting with :)
541
 * - check for empty elements (",   ,")
542
 *
543
 * Worthwile historic reading: 653d3912245c4010a3e0fb4c3c376fb2cd816c04
544
 */
545
546
void
547 807897
http_CollectHdr(struct http *hp, hdr_t hdr)
548
{
549
550 807897
        http_CollectHdrSep(hp, hdr, NULL);
551 807897
}
552
553
/*--------------------------------------------------------------------
554
 * You may prefer to collapse header fields using a different separator.
555
 * For Cookie headers, the separator is "; " for example. That's probably
556
 * the only example too.
557
 */
558
559
static int
560
http_CollectHdrSepFrom(struct http *hp, unsigned char hdl, const char *hds,
561
    const char *sep, unsigned lsep, unsigned f);
562
563
void
564 811115
http_CollectHdrSep(struct http *hp, hdr_t hdr, const char *sep)
565
{
566
        unsigned lsep, f;
567
568 811115
        CHECK_OBJ_NOTNULL(hp, HTTP_MAGIC);
569 811115
        CHECK_HDR(hdr);
570
571 811115
        if (WS_Overflowed(hp->ws))
572 2520
                return;
573
574 808595
        if (sep == NULL || *sep == '\0')
575 805384
                sep = ", ";
576 808631
        lsep = vstrlen(sep);
577
578 808631
        f = http_findhdr(hp, hdr->len - 1, hdr->str);
579 808631
        if (f == 0)
580 798283
                return;
581
582 10348
        (void)http_CollectHdrSepFrom(hp, hdr->len, hdr->str, sep, lsep, f);
583 811151
}
584
585
/*
586
 * implements the actual collection from header index f
587
 *
588
 * returns 1 if collected, 0 if not and -1 for error
589
 */
590
591
static int
592 10682
http_CollectHdrSepFrom(struct http *hp, unsigned char hdl, const char *hds,
593
    const char *sep, unsigned lsep, unsigned f)
594
{
595
        unsigned u, ml, x, d;
596 10682
        char *b = NULL, *e = NULL;
597
        const char *v;
598 38905
        for (d = u = f + 1; u < hp->nhd; u++) {
599 28223
                Tcheck(hp->hd[u]);
600 28223
                if (! http_hdr_at(hds, hp->hd[u].b, hdl)) {
601 27593
                        if (d != u) {
602 2394
                                hp->hd[d] = hp->hd[u];
603 2394
                                hp->hdf[d] = hp->hdf[u];
604 2394
                        }
605 27593
                        d++;
606 27593
                        continue;
607
                }
608 630
                if (b == NULL) {
609 441
                        http_VSLH_del(hp, f);
610
                        /* Found second header, start our collection */
611 441
                        ml = WS_ReserveAll(hp->ws);
612 441
                        b = WS_Reservation(hp->ws);
613 441
                        e = b + ml;
614 441
                        x = Tlen(hp->hd[f]);
615 441
                        if (b + x >= e) {
616 0
                                http_fail(hp);
617 0
                                VSLbs(hp->vsl, SLT_LostHeader,
618 0
                                    TOSTRAND(hds));
619 0
                                WS_Release(hp->ws, 0);
620 0
                                return (-1);
621
                        }
622 441
                        vmemcpy(b, hp->hd[f].b, x);
623 441
                        b += x;
624 441
                }
625 630
                http_VSLH_del(hp, u);
626
627 630
                AN(b);
628 630
                AN(e);
629
630
                /* Append the Nth header we found */
631 630
                x = Tlen(hp->hd[u]) - hdl;
632
633 630
                v = hp->hd[u].b + hdl;
634 1260
                while (vct_issp(*v)) {
635 630
                        v++;
636 630
                        x--;
637
                }
638
639 630
                if (b + lsep + x >= e) {
640 0
                        http_fail(hp);
641 0
                        VSLbs(hp->vsl, SLT_LostHeader, TOSTRAND(hds));
642 0
                        WS_Release(hp->ws, 0);
643 0
                        return (-1);
644
                }
645 630
                vmemcpy(b, sep, lsep);
646 630
                b += lsep;
647 630
                vmemcpy(b, v, x);
648 630
                b += x;
649 630
        }
650 10682
        if (b == NULL)
651 10241
                return (0);
652 441
        hp->nhd = (uint16_t)d;
653 441
        AN(e);
654 441
        *b = '\0';
655 441
        hp->hd[f].b = WS_Reservation(hp->ws);
656 441
        hp->hd[f].e = b;
657 441
        http_VSLH(hp, f);
658 441
        WS_ReleaseP(hp->ws, b + 1);
659 441
        return (1);
660 10682
}
661
662
/*
663
 * this respects the two exceptions for combining field values: Cookie, which
664
 * uses "; ", and Set-Cookie, which can not be combined.
665
 *
666
 * All other cases need to be catered for in VCL (e.g. by copying again from
667
 * req0)
668
 */
669
void
670 42
http_CollectAllHdrs(struct http *hp)
671
{
672 42
        const unsigned lsep = 2;
673
        unsigned f;
674
675 42
        CHECK_OBJ_NOTNULL(hp, HTTP_MAGIC);
676
677 420
        for (f = HTTP_HDR_FIRST; f < hp->nhd; f++) {
678 378
                Tcheck(hp->hd[f]);
679 378
                if (http_IsHdr(&hp->hd[f], H_Set_Cookie))
680 42
                        continue;
681 336
                const char *sep = http_IsHdr(&hp->hd[f], H_Cookie) ?
682
                        "; " : ", ";
683 336
                assert(vstrlen(sep) == lsep);
684
685 336
                const char *e = strchr(hp->hd[f].b, ':');
686
                // XXX bad, how to handle?
687 336
                if (e == NULL)
688 0
                        continue;
689
690 336
                e++;
691 336
                size_t l = e - hp->hd[f].b;
692 336
                assert(l <= UCHAR_MAX);
693
694 672
                int i = http_CollectHdrSepFrom(hp, (unsigned char)l,
695 336
                    hp->hd[f].b, sep, lsep, f);
696 336
                if (i < 0)
697 0
                        return;
698 336
        }
699 42
}
700
701
/*--------------------------------------------------------------------*/
702
703
int
704 2641379
http_GetHdr(const struct http *hp, hdr_t hdr, const char **ptr)
705
{
706
        unsigned u;
707
        const char *p;
708
709 2641379
        CHECK_HDR(hdr);
710 2641379
        u = http_findhdr(hp, hdr->len - 1, hdr->str);
711 2641379
        if (u == 0) {
712 2071162
                if (ptr != NULL)
713 1965299
                        *ptr = NULL;
714 2071162
                return (0);
715
        }
716 570217
        if (ptr != NULL) {
717 439857
                p = hp->hd[u].b + hdr->len;
718 877987
                while (vct_issp(*p))
719 438130
                        p++;
720 439857
                *ptr = p;
721 439857
        }
722 570217
        return (1);
723 2641379
}
724
725
/*-----------------------------------------------------------------------------
726
 * Split source string at any of the separators, return pointer to first
727
 * and last+1 char of substrings, with whitespace trimmed at both ends.
728
 * If sep being an empty string is shorthand for VCT::SP
729
 * If stop is NULL, src is NUL terminated.
730
 */
731
732
static int
733 56456
http_split(const char **src, const char *stop, const char *sep,
734
    const char **b, const char **e)
735
{
736
        const char *p, *q;
737
738 56456
        AN(src);
739 56456
        AN(*src);
740 56456
        AN(sep);
741 56456
        AN(b);
742 56456
        AN(e);
743
744 56456
        if (stop == NULL)
745 56293
                stop = strchr(*src, '\0');
746
747 98792
        for (p = *src; p < stop && (vct_issp(*p) || strchr(sep, *p)); p++)
748 3127
                continue;
749
750 56456
        if (p >= stop) {
751 20362
                *b = NULL;
752 20362
                *e = NULL;
753 20362
                return (0);
754
        }
755
756 36094
        *b = p;
757 36094
        if (*sep == '\0') {
758 0
                for (q = p + 1; q < stop && !vct_issp(*q); q++)
759 0
                        continue;
760 0
                *e = q;
761 0
                *src = q;
762 0
                return (1);
763
        }
764 180308
        for (q = p + 1; q < stop && !strchr(sep, *q); q++)
765 144214
                continue;
766 36094
        *src = q;
767 36094
        while (q > p && vct_issp(q[-1]))
768 0
                q--;
769 36084
        *e = q;
770 36084
        return (1);
771 56446
}
772
773
/*-----------------------------------------------------------------------------
774
 * Comparison rule for tokens:
775
 *      if target string starts with '"', we use memcmp() and expect closing
776
 *      double quote as well
777
 *      otherwise we use http_tok_at()
778
 *
779
 * On match we increment *bp past the token name.
780
 */
781
782
static int
783 30071
http_istoken(const char **bp, const char *e, const char *token)
784
{
785 30071
        int fl = vstrlen(token);
786
        const char *b;
787
788 30071
        AN(bp);
789 30071
        AN(e);
790 30071
        AN(token);
791
792 30071
        b = *bp;
793
794 30071
        if (b + fl + 2 <= e && *b == '"' &&
795 0
            !vmemcmp(b + 1, token, fl) && b[fl + 1] == '"') {
796 0
                *bp += fl + 2;
797 0
                return (1);
798
        }
799 31079
        if (b + fl <= e && http_tok_at(b, token, fl) &&
800 14028
            (b + fl == e || !vct_istchar(b[fl]))) {
801 14028
                *bp += fl;
802 14028
                return (1);
803
        }
804 16043
        return (0);
805 30071
}
806
807
/*-----------------------------------------------------------------------------
808
 * Find a given data element (token) in a header according to RFC2616's #rule
809
 * (section 2.1, p15)
810
 *
811
 * On case sensitivity:
812
 *
813
 * Section 4.2 (Messages Headers) defines field (header) name as case
814
 * insensitive, but the field (header) value/content may be case-sensitive.
815
 *
816
 * http_GetHdrToken looks up a token in a header value and the rfc does not say
817
 * explicitly if tokens are to be compared with or without respect to case.
818
 *
819
 * But all examples and specific statements regarding tokens follow the rule
820
 * that unquoted tokens are to be matched case-insensitively and quoted tokens
821
 * case-sensitively.
822
 *
823
 * The optional pb and pe arguments will point to the token content start and
824
 * end+1, white space trimmed on both sides.
825
 */
826
827
int
828 329519
http_GetHdrToken(const struct http *hp, hdr_t hdr,
829
    const char *token, const char **pb, const char **pe)
830
{
831
        const char *h, *b, *e;
832
833 329519
        if (pb != NULL)
834 248444
                *pb = NULL;
835 329519
        if (pe != NULL)
836 78475
                *pe = NULL;
837 329519
        if (!http_GetHdr(hp, hdr, &h))
838 300371
                return (0);
839 29148
        AN(h);
840
841 45192
        while (http_split(&h, NULL, ",", &b, &e))
842 30072
                if (http_istoken(&b, e, token))
843 14028
                        break;
844 29148
        if (b == NULL)
845 15120
                return (0);
846 14028
        if (pb != NULL) {
847 13944
                for (; vct_islws(*b); b++)
848 105
                        continue;
849 13839
                if (b == e) {
850 12852
                        b = NULL;
851 12852
                        e = NULL;
852 12852
                }
853 13839
                *pb = b;
854 13839
                if (pe != NULL)
855 12705
                        *pe = e;
856 13839
        }
857 14028
        return (1);
858 329519
}
859
860
/*--------------------------------------------------------------------
861
 * Find a given header field's quality value (qvalue).
862
 */
863
864
double
865 78473
http_GetHdrQ(const struct http *hp, hdr_t hdr, const char *field)
866
{
867
        const char *hb, *he, *b, *e;
868
        int i;
869
        double a, f;
870
871 78473
        i = http_GetHdrToken(hp, hdr, field, &hb, &he);
872 78473
        if (!i)
873 65768
                return (0.);
874
875 12705
        if (hb == NULL)
876 12558
                return (1.);
877 147
        while (http_split(&hb, he, ";", &b, &e)) {
878 147
                if (*b != 'q')
879 0
                        continue;
880 147
                for (b++; b < e && vct_issp(*b); b++)
881 0
                        continue;
882 147
                if (b == e || *b != '=')
883 0
                        continue;
884 147
                break;
885
        }
886 147
        if (b == NULL)
887 0
                return (1.);
888 147
        for (b++; b < e && vct_issp(*b); b++)
889 0
                continue;
890 147
        if (b == e || (*b != '.' && !vct_isdigit(*b)))
891 21
                return (0.);
892 126
        a = 0;
893 252
        while (b < e && vct_isdigit(*b)) {
894 126
                a *= 10.;
895 126
                a += *b - '0';
896 126
                b++;
897
        }
898 126
        if (b == e || *b++ != '.')
899 21
                return (a);
900 105
        f = .1;
901 336
        while (b < e && vct_isdigit(*b)) {
902 231
                a += f * (*b - '0');
903 231
                f *= .1;
904 231
                b++;
905
        }
906 105
        return (a);
907 78473
}
908
909
/*--------------------------------------------------------------------
910
 * Find a given header field's value.
911
 */
912
913
int
914 169975
http_GetHdrField(const struct http *hp, hdr_t hdr,
915
    const char *field, const char **ptr)
916
{
917
        const char *h;
918
        int i;
919
920 169975
        if (ptr != NULL)
921 83307
                *ptr = NULL;
922
923 169975
        h = NULL;
924 169975
        i = http_GetHdrToken(hp, hdr, field, &h, NULL);
925 169975
        if (!i)
926 168841
                return (i);
927
928 1134
        if (ptr != NULL && h != NULL) {
929
                /* Skip whitespace, looking for '=' */
930 840
                while (*h && vct_issp(*h))
931 0
                        h++;
932 840
                if (*h == '=') {
933 840
                        h++;
934 924
                        while (*h && vct_issp(*h))
935 84
                                h++;
936 840
                        *ptr = h;
937 840
                }
938 840
        }
939 1134
        return (i);
940 169975
}
941
942
/*--------------------------------------------------------------------
943
 * Return the content length if all Content-Length headers are well formed and
944
 * agree. Remove agreeing duplicates. Normalize to no leading zeroes.
945
 *
946
 * Returns -1 for no content length, -2 for malformed.
947
 *
948
 * The surviving C-L header is normalized to not contain leading zeroes in order
949
 * to support vcl like if (req.http.Content-Length ~ "^\d{3}"). If all headers
950
 * had leading zeroes or list values, we generate a new one
951
 */
952
953
ssize_t
954 256473
http_GetContentLength(struct http *hp)
955
{
956 256473
        txt first = { NULL, NULL };
957 256473
        ssize_t cl = -1;        // default no length
958
        uint16_t u, v;
959 256473
        int need = 1;
960
961 256473
        CHECK_OBJ_NOTNULL(hp, HTTP_MAGIC);
962
963
        // basically the same outer loop as http_Unset
964 1383968
        for (v = u = HTTP_HDR_FIRST; u < hp->nhd; u++) {
965 1127642
                Tcheck(hp->hd[u]);
966 1127642
                if (http_IsHdr(&hp->hd[u], H_Content_Length)) {
967 145818
                        const char *b = hp->hd[u].b + H_Content_Length->len;
968
969 292436
                        while (vct_issp(*b))
970 146618
                                b++;
971
972
                        // leading zeroes are not canonical
973 145818
                        int noncanon = (pdiff(b, hp->hd[u].e) > 1 && b[0] == '0');
974
975 145818
                        ssize_t l = VNUM_uint(b, NULL, &b);
976 145818
                        ssize_t ll = l;
977
978 145902
                        for (;;) {
979
                                // malformed numbers and mismatches to previous
980
                                // are hard errors
981 145902
                                if (l < 0 || ll != l) {
982 147
                                        l = -2;
983 147
                                        break;
984
                                }
985
986 145755
                                while (vct_isows(*b))
987 0
                                        b++;
988 145755
                                if (*b == '\0')
989 145650
                                        break;
990 105
                                if (*b != ',') {
991 0
                                        l = -2;
992 0
                                        break;
993
                                }
994 105
                                b++;
995
996
                                // list values are not canonical
997 105
                                noncanon = 1;
998 168
                                while (vct_issp(*b))
999 63
                                        b++;
1000 105
                                if (*b == '\0')
1001 21
                                        break;
1002 84
                                ll = l;
1003 84
                                l = VNUM_uint(b, NULL, &b);
1004
                        }
1005
1006 145818
                        assert(l == -2 || l >= 0);
1007 145818
                        assert(cl >= -2);
1008
1009
                        // note good cl or log errors
1010 145818
                        if (l == -2) {
1011 148
                                cl = -2;
1012 296
                                VSLb(hp->vsl, SLT_HttpGarbage, "%.*s",
1013 148
                                    (int)pdiff(hp->hd[u].b, hp->hd[u].e), hp->hd[u].b);
1014 145818
                        } else if (cl == -1)
1015 145439
                                cl = l;
1016 231
                        else if (l != cl) {
1017 63
                                cl = -2;
1018
1019 63
                                AN(first.b);
1020 126
                                VSLb(hp->vsl, SLT_HttpGarbage, "mismatch: %.*s",
1021 63
                                    (int)pdiff(hp->hd[u].b, hp->hd[u].e), hp->hd[u].b);
1022 126
                                VSLb(hp->vsl, SLT_HttpGarbage, "first   : %.*s",
1023 63
                                    (int)pdiff(first.b, first.e), first.b);
1024 63
                        }
1025
1026
                        // Return early if wrong and all headers kept
1027 145818
                        if (cl == -2 && v == u)
1028 147
                                return (cl);
1029
1030
                        // track for logging, by value because the
1031
                        // compaction below can move this slot
1032 145671
                        if (first.b == NULL)
1033 145436
                                first = hp->hd[u];
1034
1035
                        // decide if to keep header
1036 145671
                        if (cl >= 0 && need && !noncanon) {
1037 145374
                                need = 0;
1038 145671
                        } else if (cl >= 0) {
1039 234
                                http_VSLH_del(hp, u);
1040 234
                                continue;
1041
                        }
1042 145437
                }
1043
1044 1127261
                if (v != u) {
1045 546
                        vmemcpy(&hp->hd[v], &hp->hd[u], sizeof *hp->hd);
1046 546
                        vmemcpy(&hp->hdf[v], &hp->hdf[u], sizeof *hp->hdf);
1047 546
                }
1048 1127261
                v++;
1049 1127261
        }
1050 256326
        hp->nhd = v;
1051
1052 256326
        if (cl >= 0 && need) {
1053
                // we have deleted all headers above
1054 42
                http_PrintfHeader(hp, "Content-Length: %zd", cl);
1055 42
        }
1056
1057 256326
        return (cl);
1058 256473
}
1059
1060
ssize_t
1061 45591
http_GetContentRange(const struct http *hp, ssize_t *lo, ssize_t *hi)
1062
{
1063
        ssize_t tmp, cl;
1064
        const char *b, *t;
1065
1066 45591
        CHECK_OBJ_NOTNULL(hp, HTTP_MAGIC);
1067
1068 45591
        if (lo == NULL)
1069 0
                lo = &tmp;
1070 45591
        if (hi == NULL)
1071 0
                hi = &tmp;
1072
1073 45591
        *lo = *hi = -1;
1074
1075 45591
        if (!http_GetHdr(hp, H_Content_Range, &b))
1076 45381
                return (-1);
1077
1078 210
        t = strchr(b, ' ');
1079 210
        if (t == NULL)
1080 21
                return (-2);            // Missing space after range unit
1081
1082 189
        if (!http_range_at(b, bytes, t - b))
1083 21
                return (-1);            // Unknown range unit, ignore
1084 168
        b = t + 1;
1085
1086 168
        if (*b == '*') {                // Content-Range: bytes */123
1087 63
                *lo = *hi = -1;
1088 63
                b++;
1089 63
        } else {                        // Content-Range: bytes 1-2/3
1090 105
                *lo = VNUM_uint(b, NULL, &b);
1091 105
                if (*lo < 0)
1092 0
                        return (-2);
1093 105
                if (*b != '-')
1094 0
                        return (-2);
1095 105
                *hi = VNUM_uint(b + 1, NULL, &b);
1096 105
                if (*hi < 0)
1097 0
                        return (-2);
1098
        }
1099 168
        if (*b != '/')
1100 0
                return (-2);
1101 168
        if (b[1] == '*') {              // Content-Range: bytes 1-2/*
1102 21
                cl = -1;
1103 21
                b += 2;
1104 21
        } else {
1105 147
                cl = VNUM_uint(b + 1, NULL, &b);
1106 147
                if (cl <= 0)
1107 0
                        return (-2);
1108
        }
1109 168
        while (vct_isows(*b))
1110 0
                b++;
1111 168
        if (*b != '\0')
1112 0
                return (-2);
1113 168
        if (*lo > *hi)
1114 0
                return (-2);
1115 168
        assert(cl >= -1);
1116 168
        if (*lo >= cl || *hi >= cl)
1117 21
                return (-2);
1118 147
        AN(cl);
1119 147
        return (cl);
1120 45591
}
1121
1122
const char *
1123 46641
http_GetRange(const struct http *hp, ssize_t *lo, ssize_t *hi, ssize_t len)
1124
{
1125
        ssize_t tmp_lo, tmp_hi;
1126
        const char *b, *t;
1127
1128 46641
        CHECK_OBJ_NOTNULL(hp, HTTP_MAGIC);
1129
1130 46641
        if (lo == NULL)
1131 0
                lo = &tmp_lo;
1132 46641
        if (hi == NULL)
1133 0
                hi = &tmp_hi;
1134
1135 46641
        *lo = *hi = -1;
1136
1137 46641
        if (!http_GetHdr(hp, H_Range, &b))
1138 45444
                return (NULL);
1139
1140
        // rfc9110,l,6481,6484
1141 1197
        if (!http_method_eq(hp->wkm, WKM_GET))
1142 21
                return (NULL);
1143
1144 1176
        t = strchr(b, '=');
1145 1176
        if (t == NULL)
1146 42
                return ("Missing '='");
1147
1148 1134
        if (!http_range_at(b, bytes, t - b))
1149 84
                return ("Not Bytes");
1150 1050
        b = t + 1;
1151
1152 1050
        *lo = VNUM_uint(b, NULL, &b);
1153 1050
        if (*lo == -2)
1154 0
                return ("Low number too big");
1155 1050
        if (*b++ != '-')
1156 0
                return ("Missing hyphen");
1157
1158 1050
        *hi = VNUM_uint(b, NULL, &b);
1159 1050
        if (*hi == -2)
1160 0
                return ("High number too big");
1161 1050
        if (*lo == -1 && *hi == -1)
1162 21
                return ("Neither high nor low");
1163 1029
        if (*lo == -1 && *hi == 0)
1164 21
                return ("No low, high is zero");
1165 1008
        if (*hi >= 0 && *hi < *lo)
1166 21
                return ("high smaller than low");
1167
1168 1008
        while (vct_isows(*b))
1169 21
                b++;
1170 987
        if (*b != '\0')
1171 21
                return ("Trailing stuff");
1172
1173 966
        assert(*lo >= -1);
1174 966
        assert(*hi >= -1);
1175
1176 966
        if (*lo < 0) {
1177 84
                assert(*hi > 0);
1178 84
                *lo = len - *hi;
1179 84
                if (*lo < 0)
1180 42
                        *lo = 0;
1181 84
                *hi = len - 1;
1182 966
        } else if (len >= 0 && (*hi >= len || *hi < 0)) {
1183 189
                *hi = len - 1;
1184 189
        }
1185
1186 966
        if (len <= 0)
1187 378
                return (NULL);                  // Allow 200 response
1188
1189 588
        if (*lo >= len)
1190 21
                return ("low range beyond object");
1191
1192 567
        return (NULL);
1193 46641
}
1194
1195
/*--------------------------------------------------------------------
1196
 */
1197
1198
stream_close_t
1199 312873
http_DoConnection(struct http *hp, stream_close_t sc_close)
1200
{
1201
        const char *h, *b, *e;
1202
        stream_close_t retval;
1203
        unsigned u, v;
1204
        struct http_hdrflg *f;
1205
1206 312873
        CHECK_OBJ_NOTNULL(hp, HTTP_MAGIC);
1207 312873
        assert(sc_close == SC_REQ_CLOSE || sc_close == SC_RESP_CLOSE);
1208
1209 312873
        if (hp->protover == 10)
1210 1054
                retval = SC_REQ_HTTP10;
1211
        else
1212 311819
                retval = SC_NULL;
1213
1214 312873
        http_CollectHdr(hp, H_Connection);
1215 312873
        if (!http_GetHdr(hp, H_Connection, &h))
1216 307946
                return (retval);
1217 4927
        AN(h);
1218 10168
        while (http_split(&h, NULL, ",", &b, &e)) {
1219 5304
                u = pdiff(b, e);
1220 5304
                if (u == 5 && http_hdr_at(b, "close", u))
1221 3712
                        retval = sc_close;
1222 5304
                if (u == 10 && http_hdr_at(b, "keep-alive", u))
1223 924
                        retval = SC_NULL;
1224
1225
                /* Refuse removal of well-known-headers if they would pass. */
1226 5304
                f = http_hdr_flags(b, e);
1227 5304
                if (f != NULL && !(f->flag & HTTPH_R_PASS))
1228 63
                        return (SC_RX_BAD);
1229
1230 27574
                for (v = HTTP_HDR_FIRST; v < hp->nhd; v++) {
1231 22333
                        Tcheck(hp->hd[v]);
1232 22333
                        if (hp->hd[v].e < hp->hd[v].b + u + 1)
1233 840
                                continue;
1234 21493
                        if (hp->hd[v].b[u] != ':')
1235 19330
                                continue;
1236 2163
                        if (!http_hdr_at(b, hp->hd[v].b, u))
1237 1785
                                continue;
1238 378
                        hp->hdf[v] |= HDF_FILTER;
1239 378
                }
1240
        }
1241 4864
        CHECK_OBJ_NOTNULL(retval, STREAM_CLOSE_MAGIC);
1242 4864
        return (retval);
1243 312873
}
1244
1245
// Set the correct Connection header for closing or not
1246
// Existing Connection: close has precedence
1247
stream_close_t
1248 71836
http_EnsureConnection(struct http *hp, stream_close_t sc_close)
1249
{
1250
        const char *h, *b, *e;
1251
        struct vsb vsb[1];
1252 71836
        unsigned has_keep = 0, has_close = 0;
1253 71836
        unsigned u, n = 0;
1254
1255 71836
        CHECK_OBJ_NOTNULL(hp, HTTP_MAGIC);
1256 71836
        http_CollectHdr(hp, H_Connection);
1257 71836
        if (!http_GetHdr(hp, H_Connection, &h)) {
1258 71458
                if (sc_close == SC_NULL)
1259 67690
                        http_SetHeader(hp, "Connection: keep-alive");
1260
                else
1261 3768
                        http_SetHeader(hp, "Connection: close");
1262 71458
                return (sc_close);
1263
        }
1264
1265 378
        WS_VSB_new(vsb, hp->ws);
1266 378
        AN(h);
1267 945
        while (http_split(&h, NULL, ",", &b, &e)) {
1268 567
                u = pdiff(b, e);
1269 567
                if (u == 5 && http_hdr_at(b, "close", u)) {
1270 315
                        has_close = 1;
1271 315
                        continue;
1272
                }
1273 252
                if (u == 10 && http_hdr_at(b, "keep-alive", u)) {
1274 42
                        has_keep = 1;
1275 42
                        continue;
1276
                }
1277 210
                if (n++ == 0)
1278 126
                        VSB_cat(vsb, "Connection: ");
1279
                else
1280 84
                        VSB_cat(vsb, ", ");
1281 210
                VSB_bcat(vsb, b, u);
1282
        }
1283 378
        if (sc_close == SC_NULL && has_close)
1284 21
                sc_close = SC_RESP_CLOSE;
1285
        //lint -e{731} Boolean argument to equal/not equal
1286 378
        if (has_keep ^ has_close && (sc_close == SC_NULL) == (has_keep == 1)) {
1287
                // already correct
1288 315
                WS_Release(hp->ws, 0);
1289 315
                return (sc_close);
1290
        }
1291 63
        http_Unset(hp, H_Connection);
1292 63
        if (n == 0 && sc_close == SC_NULL) {
1293 0
                WS_Release(hp->ws, 0);
1294 0
                http_SetHeader(hp, "Connection: keep-alive");
1295 0
                return (sc_close);
1296
        }
1297 63
        if (n == 0) {
1298 21
                WS_Release(hp->ws, 0);
1299 21
                http_SetHeader(hp, "Connection: close");
1300 21
                return (sc_close);
1301
        }
1302 42
        if (sc_close == SC_NULL)
1303 21
                VSB_cat(vsb, ", keep-alive");
1304
        else
1305 21
                VSB_cat(vsb, ", close");
1306 42
        h = WS_VSB_finish(vsb, hp->ws, NULL);
1307 42
        if (h == NULL)
1308 0
                return (SC_OVERLOAD);
1309 42
        http_SetHeader(hp, h);
1310 42
        return (sc_close);
1311 71836
}
1312
1313
/*--------------------------------------------------------------------*/
1314
1315
int
1316 171787
http_HdrIs(const struct http *hp, hdr_t hdr, const char *val)
1317
{
1318
        const char *p;
1319
1320 171787
        if (!http_GetHdr(hp, hdr, &p))
1321 159516
                return (0);
1322 12271
        AN(p);
1323 12271
        if (http_tok_eq(p, val))
1324 11704
                return (1);
1325 567
        return (0);
1326 171787
}
1327
1328
/*--------------------------------------------------------------------*/
1329
1330
uint16_t
1331 324097
http_GetStatus(const struct http *hp)
1332
{
1333
1334 324097
        CHECK_OBJ_NOTNULL(hp, HTTP_MAGIC);
1335 324097
        return (hp->status);
1336
}
1337
1338
int
1339 225647
http_IsStatus(const struct http *hp, int val)
1340
{
1341
1342 225647
        CHECK_OBJ_NOTNULL(hp, HTTP_MAGIC);
1343 225647
        assert(val >= 100 && val <= 999);
1344 225647
        return (val == (hp->status % 1000));
1345
}
1346
1347
/*--------------------------------------------------------------------
1348
 * Setting the status will also set the Reason appropriately
1349
 */
1350
1351
void
1352 26644
http_SetStatus(struct http *to, uint16_t status, const char *reason)
1353
{
1354
        char buf[4];
1355 26644
        const char *sstr = NULL;
1356
1357 26644
        CHECK_OBJ_NOTNULL(to, HTTP_MAGIC);
1358
        /*
1359
         * We allow people to use top digits for internal VCL
1360
         * signalling, but strip them from the ASCII version.
1361
         */
1362 26644
        to->status = status;
1363 26644
        status %= 1000;
1364 26644
        assert(status >= 100);
1365
1366 26644
        if (reason == NULL)
1367 5061
                reason = http_Status2Reason(status, &sstr);
1368
        else
1369 21583
                (void)http_Status2Reason(status, &sstr);
1370
1371 26644
        if (sstr) {
1372 25909
                http_SetH(to, HTTP_HDR_STATUS, sstr);
1373 25909
        } else {
1374 735
                bprintf(buf, "%03d", status);
1375 735
                http_PutField(to, HTTP_HDR_STATUS, buf);
1376
        }
1377 26644
        http_SetH(to, HTTP_HDR_REASON, reason);
1378 26644
}
1379
1380
/*--------------------------------------------------------------------*/
1381
1382
const char *
1383 131496
http_GetMethod(const struct http *hp)
1384
{
1385
1386 131496
        CHECK_OBJ_NOTNULL(hp, HTTP_MAGIC);
1387 131496
        Tcheck(hp->hd[HTTP_HDR_METHOD]);
1388 131496
        return (hp->hd[HTTP_HDR_METHOD].b);
1389
}
1390
1391
/*--------------------------------------------------------------------
1392
 * Force a particular header field to a particular value
1393
 */
1394
1395
void
1396 171250
http_ForceField(struct http *to, unsigned n, const char *t)
1397
{
1398
        int i;
1399
1400 171250
        CHECK_OBJ_NOTNULL(to, HTTP_MAGIC);
1401 171250
        assert(n < HTTP_HDR_FIRST);
1402 171250
        assert(n == HTTP_HDR_METHOD || n == HTTP_HDR_PROTO);
1403 171250
        AN(t);
1404
1405
        /* NB: method names and protocol versions are case-sensitive. */
1406 171250
        if (to->hd[n].b == NULL || vstrcmp(to->hd[n].b, t)) {
1407 2625
                i = (HTTP_HDR_UNSET - HTTP_HDR_METHOD);
1408 2625
                i += to->logtag;
1409
                /* XXX: this is a dead branch */
1410 2625
                if (n >= HTTP_HDR_FIRST)
1411 0
                        VSLbt(to->vsl, (enum VSL_tag_e)i, to->hd[n]);
1412 2625
                http_SetH(to, n, t);
1413 2625
        }
1414 171250
}
1415
1416
/*--------------------------------------------------------------------*/
1417
1418
void
1419 24394
http_PutResponse(struct http *to, const char *proto, uint16_t status,
1420
    const char *reason)
1421
{
1422
1423 24394
        CHECK_OBJ_NOTNULL(to, HTTP_MAGIC);
1424 24394
        if (proto != NULL)
1425 24394
                http_SetH(to, HTTP_HDR_PROTO, proto);
1426 24394
        http_SetStatus(to, status, reason);
1427 24394
}
1428
1429
/*--------------------------------------------------------------------
1430
 * check if header is filtered by the dynamic marker or the static
1431
 * definitions in http_headers.h
1432
 */
1433
1434
static inline int
1435 902876
http_isfiltered(const struct http *fm, unsigned u, unsigned how)
1436
{
1437
        const char *e;
1438
        const struct http_hdrflg *f;
1439
1440 902876
        if (fm->hdf[u] & HDF_FILTER)
1441 357
                return (1);
1442 902519
        if (u < HTTP_HDR_FIRST)
1443 303705
                return (0);
1444 598814
        e = strchr(fm->hd[u].b, ':');
1445 598814
        if (e == NULL)
1446 0
                return (0);
1447 598814
        f = http_hdr_flags(fm->hd[u].b, e);
1448 598814
        return (f != NULL && f->flag & how);
1449 902876
}
1450
1451
int
1452 17753
http_IsFiltered(const struct http *fm, unsigned u, unsigned how)
1453
{
1454
1455 17753
        return (http_isfiltered(fm, u, how));
1456
}
1457
1458
/*--------------------------------------------------------------------
1459
 * Estimate how much workspace we need to Filter this header according
1460
 * to 'how'.
1461
 */
1462
1463
unsigned
1464 50692
http_EstimateWS(const struct http *fm, unsigned how)
1465
{
1466
        unsigned u, l;
1467
1468 50692
        l = 4;
1469 50692
        CHECK_OBJ_NOTNULL(fm, HTTP_MAGIC);
1470 484020
        for (u = 0; u < fm->nhd; u++) {
1471 433328
                if (u == HTTP_HDR_METHOD || u == HTTP_HDR_URL)
1472 101384
                        continue;
1473 331944
                Tcheck(fm->hd[u]);
1474 331944
                if (http_isfiltered(fm, u, how))
1475 5971
                        continue;
1476 325973
                l += Tlen(fm->hd[u]) + 1L;
1477 325973
        }
1478 50692
        return (PRNDUP(l + 1L));
1479
}
1480
1481
/*--------------------------------------------------------------------
1482
 * Encode http struct as byte string.
1483
 *
1484
 * XXX: We could save considerable special-casing below by encoding also
1485
 * XXX: H__Status, H__Reason and H__Proto into the string, but it would
1486
 * XXX: add 26-30 bytes to all encoded objects to save a little code.
1487
 * XXX: It could possibly be a good idea for later HTTP versions.
1488
 */
1489
1490
void
1491 50567
HTTP_Encode(const struct http *fm, uint8_t *p0, unsigned l, unsigned how)
1492
{
1493
        unsigned u, w;
1494
        uint16_t n;
1495
        uint8_t *p, *e;
1496
1497 50567
        AN(p0);
1498 50567
        AN(l);
1499 50567
        p = p0;
1500 50567
        e = p + l;
1501 50567
        assert(p + 5 <= e);
1502 50567
        assert(fm->nhd <= fm->shd);
1503 50567
        n = HTTP_HDR_FIRST - 3;
1504 50567
        vbe16enc(p + 2, fm->status);
1505 50567
        p += 4;
1506 50567
        CHECK_OBJ_NOTNULL(fm, HTTP_MAGIC);
1507 482683
        for (u = 0; u < fm->nhd; u++) {
1508 432116
                if (u == HTTP_HDR_METHOD || u == HTTP_HDR_URL)
1509 101126
                        continue;
1510 330990
                Tcheck(fm->hd[u]);
1511 330990
                if (http_isfiltered(fm, u, how))
1512 5971
                        continue;
1513 325019
                http_VSLH(fm, u);
1514 325019
                w = Tlen(fm->hd[u]) + 1L;
1515 325019
                assert(p + w + 1 <= e);
1516 325019
                vmemcpy(p, fm->hd[u].b, w);
1517 325019
                p += w;
1518 325019
                n++;
1519 325019
        }
1520 50567
        *p++ = '\0';
1521 50567
        assert(p <= e);
1522 50567
        vbe16enc(p0, n + 1);
1523 50567
}
1524
1525
/*--------------------------------------------------------------------
1526
 * Decode byte string into http struct
1527
 */
1528
1529
int
1530 73292
HTTP_Decode(struct http *to, const uint8_t *fm)
1531
{
1532
1533 73292
        CHECK_OBJ_NOTNULL(to, HTTP_MAGIC);
1534 73292
        AN(to->vsl);
1535 73292
        AN(fm);
1536 73292
        if (vbe16dec(fm) <= to->shd) {
1537 73243
                to->status = vbe16dec(fm + 2);
1538 73243
                fm += 4;
1539 693546
                for (to->nhd = 0; to->nhd < to->shd; to->nhd++) {
1540 693546
                        if (to->nhd == HTTP_HDR_METHOD ||
1541 620223
                            to->nhd == HTTP_HDR_URL) {
1542 146485
                                to->hd[to->nhd].b = NULL;
1543 146485
                                to->hd[to->nhd].e = NULL;
1544 146485
                                continue;
1545
                        }
1546 547061
                        if (*fm == '\0')
1547 73243
                                return (0);
1548 473818
                        to->hd[to->nhd].b = (const void*)fm;
1549 473818
                        fm = (const void*)strchr((const void*)fm, '\0');
1550 473818
                        to->hd[to->nhd].e = (const void*)fm;
1551 473818
                        fm++;
1552 473818
                        http_VSLH(to, to->nhd);
1553 473818
                }
1554 0
        }
1555 98
        VSLb(to->vsl, SLT_Error,
1556
            "Too many headers to Decode object (%u vs. %u)",
1557 49
            vbe16dec(fm), to->shd);
1558 49
        return (-1);
1559 73292
}
1560
1561
/*--------------------------------------------------------------------*/
1562
1563
uint16_t
1564 714
HTTP_GetStatusPack(struct worker *wrk, struct objcore *oc)
1565
{
1566
        const char *ptr;
1567 714
        ptr = ObjGetAttr(wrk, oc, OA_HEADERS, NULL);
1568 714
        AN(ptr);
1569
1570 714
        return (vbe16dec(ptr + 2));
1571
}
1572
1573
/*--------------------------------------------------------------------*/
1574
1575
/* Get the first packed header */
1576
int
1577 19394
HTTP_IterHdrPack(struct worker *wrk, struct objcore *oc, const char **p)
1578
{
1579
        const char *ptr;
1580
1581 19394
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
1582 19394
        CHECK_OBJ_NOTNULL(oc, OBJCORE_MAGIC);
1583 19394
        AN(p);
1584
1585 19394
        if (*p == NULL) {
1586 5996
                ptr = ObjGetAttr(wrk, oc, OA_HEADERS, NULL);
1587 5996
                AN(ptr);
1588 5996
                ptr += 4;       /* Skip nhd and status */
1589 5996
                ptr = strchr(ptr, '\0') + 1;    /* Skip :proto: */
1590 5996
                ptr = strchr(ptr, '\0') + 1;    /* Skip :status: */
1591 5996
                ptr = strchr(ptr, '\0') + 1;    /* Skip :reason: */
1592 5996
                *p = ptr;
1593 5996
        } else {
1594 13398
                *p = strchr(*p, '\0') + 1;      /* Skip to next header */
1595
        }
1596 19394
        if (**p == '\0')
1597 1261
                return (0);
1598 18133
        return (1);
1599 19394
}
1600
1601
const char *
1602 6373
HTTP_GetHdrPack(struct worker *wrk, struct objcore *oc, hdr_t hdr)
1603
{
1604
        const char *ptr;
1605
1606 6373
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
1607 6373
        CHECK_OBJ_NOTNULL(oc, OBJCORE_MAGIC);
1608 6373
        CHECK_HDR(hdr);
1609
1610 6373
        if (hdr->str[0] == ':') {
1611
                /* Special cases */
1612 378
                ptr = ObjGetAttr(wrk, oc, OA_HEADERS, NULL);
1613 378
                AN(ptr);
1614 378
                ptr += 4;       /* Skip nhd and status */
1615
1616
                /* XXX: should we also have h2_hdr_eq() ? */
1617 378
                if (!vstrcmp(hdr->str, ":proto:"))
1618 42
                        return (ptr);
1619 336
                ptr = strchr(ptr, '\0') + 1;
1620 336
                if (!vstrcmp(hdr->str, ":status:"))
1621 294
                        return (ptr);
1622 42
                ptr = strchr(ptr, '\0') + 1;
1623 42
                if (!vstrcmp(hdr->str, ":reason:"))
1624 42
                        return (ptr);
1625 0
                WRONG("Unknown magic packed header");
1626 0
        }
1627
1628 19393
        HTTP_FOREACH_PACK(wrk, oc, ptr) {
1629 18132
                if (http_hdr_at(ptr, hdr->str, hdr->len)) {
1630 4734
                        ptr += hdr->len;
1631 9447
                        while (vct_islws(*ptr))
1632 4713
                                ptr++;
1633 4734
                        return (ptr);
1634
                }
1635
        }
1636
1637 1261
        return (NULL);
1638 6373
}
1639
1640
/*--------------------------------------------------------------------
1641
 * Merge any headers in the oc->OA_HEADER into the struct http if they
1642
 * are not there already.
1643
 */
1644
1645
void
1646 672
HTTP_Merge(struct worker *wrk, struct objcore *oc, struct http *to)
1647
{
1648
        const char *ptr;
1649
        unsigned u;
1650
        const char *p;
1651
        unsigned nhd_before_merge;
1652
1653 672
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
1654 672
        CHECK_OBJ_NOTNULL(oc, OBJCORE_MAGIC);
1655 672
        CHECK_OBJ_NOTNULL(to, HTTP_MAGIC);
1656
1657 672
        ptr = ObjGetAttr(wrk, oc, OA_HEADERS, NULL);
1658 672
        AN(ptr);
1659
1660 672
        to->status = vbe16dec(ptr + 2);
1661 672
        ptr += 4;
1662
1663 4032
        for (u = 0; u < HTTP_HDR_FIRST; u++) {
1664 3360
                if (u == HTTP_HDR_METHOD || u == HTTP_HDR_URL)
1665 1344
                        continue;
1666 2016
                http_SetH(to, u, ptr);
1667 2016
                ptr = strchr(ptr, '\0') + 1;
1668 2016
        }
1669 672
        nhd_before_merge = to->nhd;
1670 4011
        while (*ptr != '\0') {
1671 3339
                p = strchr(ptr, ':');
1672 3339
                AN(p);
1673 3339
                u = http_findhdr(to, p - ptr, ptr);
1674 3339
                if (u == 0 || u >= nhd_before_merge)
1675 1575
                        http_SetHeader(to, ptr);
1676 3339
                ptr = strchr(ptr, '\0') + 1;
1677
        }
1678 672
}
1679
1680
/*--------------------------------------------------------------------*/
1681
1682
static void
1683 155346
http_linkh(const struct http *to, const struct http *fm, unsigned n)
1684
{
1685
1686 155346
        assert(n < HTTP_HDR_FIRST);
1687 155346
        Tcheck(fm->hd[n]);
1688 155346
        to->hd[n] = fm->hd[n];
1689 155346
        to->hdf[n] = fm->hdf[n];
1690 155346
        http_VSLH(to, n);
1691 155346
}
1692
1693
/*--------------------------------------------------------------------*/
1694
1695
void
1696 51784
http_FilterReq(struct http *to, const struct http *fm, unsigned how)
1697
{
1698
        unsigned u;
1699
1700 51784
        CHECK_OBJ_NOTNULL(to, HTTP_MAGIC);
1701 51784
        CHECK_OBJ_NOTNULL(fm, HTTP_MAGIC);
1702
1703 51784
        http_linkh(to, fm, HTTP_HDR_METHOD);
1704 51784
        http_SetWellKnownMethod(to);
1705 51784
        http_linkh(to, fm, HTTP_HDR_URL);
1706 51784
        http_linkh(to, fm, HTTP_HDR_PROTO);
1707 51784
        to->protover = fm->protover;
1708 51784
        to->status = fm->status;
1709
1710 51784
        to->nhd = HTTP_HDR_FIRST;
1711 273981
        for (u = HTTP_HDR_FIRST; u < fm->nhd; u++) {
1712 222197
                Tcheck(fm->hd[u]);
1713 222197
                if (http_isfiltered(fm, u, how))
1714 4122
                        continue;
1715 218075
                assert (to->nhd < to->shd);
1716 218075
                to->hd[to->nhd] = fm->hd[u];
1717 218075
                to->hdf[to->nhd] = 0;
1718 218075
                http_VSLH(to, to->nhd);
1719 218075
                to->nhd++;
1720 218075
        }
1721 51784
}
1722
1723
/*--------------------------------------------------------------------
1724
 * This function copies any header fields which reference foreign
1725
 * storage into our own WS.
1726
 */
1727
1728
void
1729 51153
http_CopyHome(const struct http *hp)
1730
{
1731
        unsigned u, l;
1732
        const char *p;
1733
1734 552546
        for (u = 0; u < hp->nhd; u++) {
1735 501393
                if (hp->hd[u].b == NULL) {
1736 102302
                        assert(u < HTTP_HDR_FIRST);
1737 102302
                        continue;
1738
                }
1739
1740 399091
                l = Tlen(hp->hd[u]);
1741 399091
                if (WS_Allocated(hp->ws, hp->hd[u].b, l))
1742 30400
                        continue;
1743
1744 368691
                p = WS_Copy(hp->ws, hp->hd[u].b, l + 1L);
1745 368691
                if (p == NULL) {
1746 0
                        http_fail(hp);
1747 0
                        VSLbs(hp->vsl, SLT_LostHeader, TOSTRAND(hp->hd[u].b));
1748 0
                        return;
1749
                }
1750 368691
                hp->hd[u].b = p;
1751 368691
                hp->hd[u].e = p + l;
1752 368691
        }
1753 51153
}
1754
1755
/*--------------------------------------------------------------------*/
1756
1757
void
1758 211320
http_SetHeader(struct http *to, const char *header)
1759
{
1760
1761 211320
        CHECK_OBJ_NOTNULL(to, HTTP_MAGIC);
1762 211320
        if (to->nhd >= to->shd) {
1763 21
                VSLbs(to->vsl, SLT_LostHeader, TOSTRAND(header));
1764 21
                http_fail(to);
1765 21
                return;
1766
        }
1767 211299
        http_SetH(to, to->nhd++, header);
1768 211320
}
1769
1770
/*--------------------------------------------------------------------*/
1771
1772
void
1773 91863
http_ForceHeader(struct http *to, hdr_t hdr, const char *val)
1774
{
1775
1776 91863
        CHECK_OBJ_NOTNULL(to, HTTP_MAGIC);
1777 91863
        if (http_HdrIs(to, hdr, val))
1778 8155
                return;
1779 83708
        http_Unset(to, hdr);
1780 83708
        http_PrintfHeader(to, "%s %s", hdr->str, val);
1781 91863
}
1782
1783
void
1784 245669
http_AppendHeader(struct http *to, hdr_t hdr, const char *val)
1785
{
1786
        const char *old;
1787
1788 245669
        http_CollectHdr(to, hdr);
1789 245669
        if (http_GetHdr(to, hdr, &old)) {
1790 1008
                http_Unset(to, hdr);
1791 1008
                http_PrintfHeader(to, "%s %s, %s", hdr->str, old, val);
1792 1008
        } else {
1793 244661
                http_PrintfHeader(to, "%s %s", hdr->str, val);
1794
        }
1795 245669
}
1796
1797
void
1798 572823
http_PrintfHeader(struct http *to, const char *fmt, ...)
1799
{
1800
        va_list ap, ap2;
1801
        struct vsb vsb[1];
1802
        size_t sz;
1803
        char *p;
1804
1805 572823
        CHECK_OBJ_NOTNULL(to, HTTP_MAGIC);
1806
1807 572823
        va_start(ap, fmt);
1808 572823
        va_copy(ap2, ap);
1809
1810 572823
        WS_VSB_new(vsb, to->ws);
1811 572823
        VSB_vprintf(vsb, fmt, ap);
1812 572823
        p = WS_VSB_finish(vsb, to->ws, &sz);
1813
1814 572823
        if (p == NULL || to->nhd >= to->shd) {
1815 711
                http_fail(to);
1816 711
                VSLbv(to->vsl, SLT_LostHeader, fmt, ap2);
1817 711
        } else {
1818 572128
                http_SetH(to, to->nhd++, p);
1819
        }
1820 572839
        va_end(ap);
1821 572839
        va_end(ap2);
1822 572839
}
1823
1824
void
1825 24669
http_TimeHeader(struct http *to, const char *fmt, vtim_real now)
1826
{
1827
        unsigned l;
1828
        char *p;
1829
1830 24669
        CHECK_OBJ_NOTNULL(to, HTTP_MAGIC);
1831 24669
        if (to->nhd >= to->shd) {
1832 0
                VSLbs(to->vsl, SLT_LostHeader, TOSTRAND(fmt));
1833 0
                http_fail(to);
1834 0
                return;
1835
        }
1836 24669
        l = (unsigned)vstrlen(fmt);
1837 24669
        p = WS_Alloc(to->ws, l + VTIM_FORMAT_SIZE);
1838 24669
        if (p == NULL) {
1839 1596
                http_fail(to);
1840 1596
                VSLbs(to->vsl, SLT_LostHeader, TOSTRAND(fmt));
1841 1596
                return;
1842
        }
1843 23073
        strcpy(p, fmt);
1844 23073
        VTIM_format(now, p + l);
1845 23073
        http_SetH(to, to->nhd++, p);
1846 24669
}
1847
1848
const char *
1849 159453
http_ViaHeader(void)
1850
{
1851
1852 159453
        return (via_hdr);
1853
}
1854
1855
/*--------------------------------------------------------------------*/
1856
1857
void
1858 502302
http_Unset(struct http *hp, hdr_t hdr)
1859
{
1860
        uint16_t u, v;
1861
1862 3247514
        for (v = u = HTTP_HDR_FIRST; u < hp->nhd; u++) {
1863 2745212
                Tcheck(hp->hd[u]);
1864 2745212
                if (http_IsHdr(&hp->hd[u], hdr)) {
1865 22239
                        http_VSLH_del(hp, u);
1866 22239
                        continue;
1867
                }
1868 2722973
                if (v != u) {
1869 64494
                        vmemcpy(&hp->hd[v], &hp->hd[u], sizeof *hp->hd);
1870 64494
                        vmemcpy(&hp->hdf[v], &hp->hdf[u], sizeof *hp->hdf);
1871 64494
                }
1872 2722973
                v++;
1873 2722973
        }
1874 502302
        hp->nhd = v;
1875 502302
}
1876
1877
void
1878 131494
http_SetWellKnownMethod(struct http *hp)
1879
{
1880
        size_t l;
1881
        const char *method;
1882
1883 131494
        CHECK_OBJ_NOTNULL(hp, HTTP_MAGIC);
1884
1885 131494
        method = http_GetMethod(hp);
1886 131494
        AN(method);
1887 131494
        l = vstrlen(method);
1888 131494
        hp->wkm = WKM_UNKNOWN;
1889
#define WKM(wk, bit)                                                    \
1890
        do {                                                            \
1891
                if (l == vstrlen(#wk) && !vmemcmp(#wk, method, l)) {    \
1892
                        hp->wkm = WKM_##wk;                             \
1893
                        return;                                         \
1894
                }                                                       \
1895
        } while (0);
1896
#include "tbl/well_known_methods.h"
1897
#undef WKM
1898
}