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 23608
 * 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 313109
http_hdr_flags(const char *b, const char *e)
183
{
184
        unsigned u;
185
        struct http_hdrflg *retval;
186
187 313109
        if (b == NULL || e == NULL)
188 20
                return (NULL);
189 313109
        u = pdiff(b, e);
190 313109
        if (u < GPERF_MIN_WORD_LENGTH || u > GPERF_MAX_WORD_LENGTH)
191 140
                return (NULL);
192 625938
        u += http_asso_values[(uint8_t)(e[-1])] +
193 312969
             http_asso_values[(uint8_t)(b[0])];
194 312969
        if (u > GPERF_MAX_HASH_VALUE)
195 4318
                return (NULL);
196 308651
        retval = &http_hdrflg[u];
197 308651
        if (retval->hdr == NULL)
198 1236
                return (NULL);
199 307415
        AN(*retval->hdr);
200 307415
        if (!http_hdr_at(*retval->hdr + 1, b, e - b))
201 4328
                return (NULL);
202 303087
        return (retval);
203 313109
}
204
205
/*--------------------------------------------------------------------*/
206
207
static void
208 203632
http_init_hdr(hdr_t hdr, int flg)
209
{
210
        struct http_hdrflg *f;
211
212 203632
        f = http_hdr_flags(hdr->str, hdr->str + hdr->len - 1);
213 203632
        AN(f);
214 203632
        assert(*f->hdr == hdr);
215 203632
        f->flag = flg;
216 203632
}
217
218
void
219 3916
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 3916
        AN(vsb);
228
        VSB_printf(vsb, "1.1 %s (Vinyl-Cache/" PACKAGE_BRANCH ")",
229
            heritage.identity);
230 3916
        AZ(VSB_finish(vsb));
231 3916
        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 514871
http_VSLH(const struct http *hp, unsigned hdr)
245
{
246
        int i;
247
248 514871
        if (hp->vsl != NULL) {
249 514899
                assert(VXID_TAG(hp->vsl->wid));
250 514899
                i = hdr;
251 514899
                if (i > HTTP_HDR_FIRST)
252 270995
                        i = HTTP_HDR_FIRST;
253 514899
                i += hp->logtag;
254 514899
                VSLbt(hp->vsl, (enum VSL_tag_e)i, hp->hd[hdr]);
255 514899
        }
256 514927
}
257
258
static void
259 4200
http_VSLH_del(const struct http *hp, unsigned hdr)
260
{
261
        int i;
262
263 4200
        if (hp->vsl != NULL) {
264
                /* We don't support unsetting stuff in the first line */
265 4200
                assert (hdr >= HTTP_HDR_FIRST);
266 4200
                assert(VXID_TAG(hp->vsl->wid));
267 4200
                i = (HTTP_HDR_UNSET - HTTP_HDR_METHOD);
268 4200
                i += hp->logtag;
269 4200
                VSLbt(hp->vsl, (enum VSL_tag_e)i, hp->hd[hdr]);
270 4200
        }
271 4200
}
272
273
/*--------------------------------------------------------------------*/
274
275
void
276 24103
http_VSL_log(const struct http *hp)
277
{
278
        unsigned u;
279
280 210605
        for (u = 0; u < hp->nhd; u++)
281 324806
                if (hp->hd[u].b != NULL)
282 138304
                        http_VSLH(hp, u);
283 24103
}
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 6675
http_Status2Reason(unsigned status, const char **sstr)
314
{
315
        struct http_msg *mp;
316
317 6675
        status %= 1000;
318 6675
        assert(status >= 100);
319 189118
        for (mp = http_msg; mp->nbr != 0 && mp->nbr <= status; mp++)
320 188938
                if (mp->nbr == status) {
321 6495
                        if (sstr)
322 4571
                                *sstr = mp->status;
323 6495
                        return (mp->txt);
324
                }
325 180
        return ("Unknown HTTP Status");
326 6675
}
327
328
/*--------------------------------------------------------------------*/
329
330
unsigned
331 21961
HTTP_estimate(unsigned nhttp)
332
{
333
334
        /* XXX: We trust the structs to size-aligned as necessary */
335 21961
        return (PRNDUP(sizeof(struct http) + sizeof(txt) * nhttp + nhttp));
336
}
337
338
struct http *
339 65885
HTTP_create(void *p, uint16_t nhttp, unsigned len)
340
{
341
        struct http *hp;
342
343 65885
        hp = p;
344 65885
        hp->magic = HTTP_MAGIC;
345 65885
        hp->hd = (void*)(hp + 1);
346 65885
        hp->shd = nhttp;
347 65885
        hp->hdf = (void*)(hp->hd + nhttp);
348 65885
        assert((unsigned char*)p + len == hp->hdf + PRNDUP(nhttp));
349 65885
        return (hp);
350
}
351
352
/*--------------------------------------------------------------------*/
353
354
void
355 61197
HTTP_Setup(struct http *hp, struct ws *ws, struct vsl_log *vsl,
356
    enum VSL_tag_e  whence)
357
{
358 61197
        http_Teardown(hp);
359 61197
        hp->nhd = HTTP_HDR_FIRST;
360 61197
        hp->logtag = whence;
361 61197
        hp->ws = ws;
362 61197
        hp->vsl = vsl;
363 61197
        hp->wkm = WKM_UNKNOWN;
364 61197
}
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 95374
http_Teardown(struct http *hp)
374
{
375
376 95374
        CHECK_OBJ_NOTNULL(hp, HTTP_MAGIC);
377 95374
        AN(hp->shd);
378 95374
        memset(&hp->nhd, 0, sizeof *hp - offsetof(struct http, nhd));
379 95374
        memset(hp->hd, 0, sizeof *hp->hd * hp->shd);
380 95374
        memset(hp->hdf, 0, sizeof *hp->hdf * hp->shd);
381 95374
}
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 26764
HTTP_Dup(struct http *to, const struct http * fm)
391
{
392
393 26764
        assert(fm->nhd <= to->shd);
394 26764
        vmemcpy(to->hd, fm->hd, fm->nhd * sizeof *to->hd);
395 26764
        vmemcpy(to->hdf, fm->hdf, fm->nhd * sizeof *to->hdf);
396 26764
        to->nhd = fm->nhd;
397 26764
        to->logtag = fm->logtag;
398 26764
        to->status = fm->status;
399 26764
        to->protover = fm->protover;
400 26764
        to->wkm = fm->wkm;
401 26764
}
402
403
404
/*--------------------------------------------------------------------
405
 * Clone the entire http structure, including vsl & ws
406
 */
407
408
void
409 25297
HTTP_Clone(struct http *to, const struct http * const fm)
410
{
411
412 25297
        HTTP_Dup(to, fm);
413 25297
        to->vsl = fm->vsl;
414 25297
        to->ws = fm->ws;
415 25297
}
416
417
/*--------------------------------------------------------------------*/
418
419
void
420 27634
http_Proto(struct http *to)
421
{
422
        const char *fm;
423
424 27634
        fm = to->hd[HTTP_HDR_PROTO].b;
425
426 55230
        if (fm != NULL &&
427 27601
            (fm[0] == 'H' || fm[0] == 'h') &&
428 27598
            (fm[1] == 'T' || fm[1] == 't') &&
429 27596
            (fm[2] == 'T' || fm[2] == 't') &&
430 27596
            (fm[3] == 'P' || fm[3] == 'p') &&
431 27596
            fm[4] == '/' &&
432 27596
            vct_isdigit(fm[5]) &&
433 27596
            fm[6] == '.' &&
434 27596
            vct_isdigit(fm[7]) &&
435 27596
            fm[8] == '\0') {
436 27596
                to->protover = 10 * (fm[5] - '0') + (fm[7] - '0');
437 27596
        } else {
438 36
                to->protover = 0;
439
        }
440 27632
}
441
442
/*--------------------------------------------------------------------*/
443
444
void
445 163478
http_SetH(struct http *to, unsigned n, const char *header)
446
{
447
448 163478
        assert(n < to->nhd);
449 163478
        AN(header);
450 163478
        to->hd[n].b = TRUST_ME(header);
451 163478
        to->hd[n].e = strchr(to->hd[n].b, '\0');
452 163478
        to->hdf[n] = 0;
453 163478
        http_VSLH(to, n);
454 163478
        if (n == HTTP_HDR_PROTO)
455 5656
                http_Proto(to);
456 163478
        if (n == HTTP_HDR_METHOD)
457 156
                http_SetWellKnownMethod(to);
458 163478
}
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 594207
http_IsHdr(const txt *hh, hdr_t hdr)
481
{
482
483 594207
        Tcheck(*hh);
484 594207
        CHECK_HDR(hdr);
485 594207
        return (http_hdr_at(hdr->str, hh->b, hdr->len));
486
}
487
488
/*--------------------------------------------------------------------*/
489
490
static unsigned
491 675009
http_findhdr(const struct http *hp, unsigned l, const char *hdr)
492
{
493
        unsigned u;
494
495 3091050
        for (u = HTTP_HDR_FIRST; u < hp->nhd; u++) {
496 2550498
                Tcheck(hp->hd[u]);
497 2550498
                if (hp->hd[u].e < hp->hd[u].b + l + 1)
498 554640
                        continue;
499 1995858
                if (hp->hd[u].b[l] != ':')
500 1680557
                        continue;
501 315301
                if (!http_hdr_at(hdr, hp->hd[u].b, l))
502 180844
                        continue;
503 134457
                return (u);
504
        }
505 540552
        return (0);
506 675009
}
507
508
/*--------------------------------------------------------------------
509
 * Count how many instances we have of this header
510
 */
511
512
unsigned
513 31516
http_CountHdr(const struct http *hp, hdr_t hdr)
514
{
515 31516
        unsigned retval = 0;
516
        unsigned u;
517
518 31516
        CHECK_OBJ_NOTNULL(hp, HTTP_MAGIC);
519
520 105206
        for (u = HTTP_HDR_FIRST; u < hp->nhd; u++) {
521 73690
                Tcheck(hp->hd[u]);
522 73690
                if (http_IsHdr(&hp->hd[u], hdr))
523 15606
                        retval++;
524 73690
        }
525 31516
        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 132267
http_CollectHdr(struct http *hp, hdr_t hdr)
535
{
536
537 132267
        http_CollectHdrSep(hp, hdr, NULL);
538 132267
}
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 132879
http_CollectHdrSep(struct http *hp, hdr_t hdr, const char *sep)
548
{
549
        unsigned u, lsep, ml, f, x, d;
550 132879
        char *b = NULL, *e = NULL;
551
        const char *v;
552
553 132879
        CHECK_OBJ_NOTNULL(hp, HTTP_MAGIC);
554 132879
        CHECK_HDR(hdr);
555
556 132879
        if (WS_Overflowed(hp->ws))
557 184
                return;
558
559 132695
        if (sep == NULL || *sep == '\0')
560 132086
                sep = ", ";
561 132701
        lsep = vstrlen(sep);
562
563 132701
        f = http_findhdr(hp, hdr->len - 1, hdr->str);
564 132701
        if (f == 0)
565 130868
                return;
566
567 6689
        for (d = u = f + 1; u < hp->nhd; u++) {
568 4856
                Tcheck(hp->hd[u]);
569 4856
                if (!http_IsHdr(&hp->hd[u], hdr)) {
570 4784
                        if (d != u) {
571 284
                                hp->hd[d] = hp->hd[u];
572 284
                                hp->hdf[d] = hp->hdf[u];
573 284
                        }
574 4784
                        d++;
575 4784
                        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
                        vmemcpy(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
                vmemcpy(b, sep, lsep);
613 72
                b += lsep;
614 72
                vmemcpy(b, v, x);
615 72
                b += x;
616 72
        }
617 1833
        if (b == NULL)
618 1769
                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 132885
}
626
627
/*--------------------------------------------------------------------*/
628
629
int
630 541785
http_GetHdr(const struct http *hp, hdr_t hdr, const char **ptr)
631
{
632
        unsigned u;
633
        const char *p;
634
635 541785
        CHECK_HDR(hdr);
636 541785
        u = http_findhdr(hp, hdr->len - 1, hdr->str);
637 541785
        if (u == 0) {
638 409501
                if (ptr != NULL)
639 378665
                        *ptr = NULL;
640 409501
                return (0);
641
        }
642 132284
        if (ptr != NULL) {
643 108055
                p = hp->hd[u].b + hdr->len;
644 215932
                while (vct_issp(*p))
645 107877
                        p++;
646 108055
                *ptr = p;
647 108055
        }
648 132284
        return (1);
649 541785
}
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 10402
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 10402
        AN(src);
665 10402
        AN(*src);
666 10402
        AN(sep);
667 10402
        AN(b);
668 10402
        AN(e);
669
670 10402
        if (stop == NULL)
671 10373
                stop = strchr(*src, '\0');
672
673 17950
        for (p = *src; p < stop && (vct_issp(*p) || strchr(sep, *p)); p++)
674 444
                continue;
675
676 10402
        if (p >= stop) {
677 3741
                *b = NULL;
678 3741
                *e = NULL;
679 3741
                return (0);
680
        }
681
682 6661
        *b = p;
683 6661
        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 33277
        for (q = p + 1; q < stop && !strchr(sep, *q); q++)
691 26616
                continue;
692 6661
        *src = q;
693 6661
        while (q > p && vct_issp(q[-1]))
694 0
                q--;
695 6661
        *e = q;
696 6661
        return (1);
697 10402
}
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
            !vmemcmp(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 60911
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 60911
        if (pb != NULL)
760 45836
                *pb = NULL;
761 60911
        if (pe != NULL)
762 14579
                *pe = NULL;
763 60911
        if (!http_GetHdr(hp, hdr, &h))
764 55359
                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 60911
}
785
786
/*--------------------------------------------------------------------
787
 * Find a given header field's quality value (qvalue).
788
 */
789
790
double
791 14580
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 14580
        i = http_GetHdrToken(hp, hdr, field, &hb, &he);
798 14580
        if (!i)
799 12160
                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 14580
}
834
835
/*--------------------------------------------------------------------
836
 * Find a given header field's value.
837
 */
838
839
int
840 31256
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 31256
        if (ptr != NULL)
847 15799
                *ptr = NULL;
848
849 31256
        h = NULL;
850 31256
        i = http_GetHdrToken(hp, hdr, field, &h, NULL);
851 31256
        if (!i)
852 31040
                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 31256
}
867
868
/*--------------------------------------------------------------------*/
869
870
ssize_t
871 45877
http_GetContentLength(const struct http *hp)
872
{
873
        ssize_t cl;
874
        const char *b;
875
876 45877
        CHECK_OBJ_NOTNULL(hp, HTTP_MAGIC);
877
878 45877
        if (!http_GetHdr(hp, H_Content_Length, &b))
879 20160
                return (-1);
880 25717
        cl = VNUM_uint(b, NULL, &b);
881 25717
        if (cl < 0)
882 16
                return (-2);
883 25701
        while (vct_islws(*b))
884 0
                b++;
885 25701
        if (*b != '\0')
886 0
                return (-2);
887 25701
        return (cl);
888 45877
}
889
890
ssize_t
891 8149
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 8149
        CHECK_OBJ_NOTNULL(hp, HTTP_MAGIC);
897
898 8149
        if (lo == NULL)
899 0
                lo = &tmp;
900 8149
        if (hi == NULL)
901 0
                hi = &tmp;
902
903 8149
        *lo = *hi = -1;
904
905 8149
        if (!http_GetHdr(hp, H_Content_Range, &b))
906 8109
                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 8149
}
951
952
const char *
953 8349
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 8349
        CHECK_OBJ_NOTNULL(hp, HTTP_MAGIC);
959
960 8349
        if (lo == NULL)
961 0
                lo = &tmp_lo;
962 8349
        if (hi == NULL)
963 0
                hi = &tmp_hi;
964
965 8349
        *lo = *hi = -1;
966
967 8349
        if (!http_GetHdr(hp, H_Range, &b))
968 8125
                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 8349
}
1024
1025
/*--------------------------------------------------------------------
1026
 */
1027
1028
stream_close_t
1029 55906
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 55906
        CHECK_OBJ_NOTNULL(hp, HTTP_MAGIC);
1037 55906
        assert(sc_close == SC_REQ_CLOSE || sc_close == SC_RESP_CLOSE);
1038
1039 55906
        if (hp->protover == 10)
1040 165
                retval = SC_REQ_HTTP10;
1041
        else
1042 55741
                retval = SC_NULL;
1043
1044 55906
        http_CollectHdr(hp, H_Connection);
1045 55906
        if (!http_GetHdr(hp, H_Connection, &h))
1046 55033
                return (retval);
1047 873
        AN(h);
1048 1766
        while (http_split(&h, NULL, ",", &b, &e)) {
1049 905
                u = pdiff(b, e);
1050 905
                if (u == 5 && http_hdr_at(b, "close", u))
1051 684
                        retval = sc_close;
1052 905
                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 905
                f = http_hdr_flags(b, e);
1057 905
                if (f != NULL && !(f->flag & HTTPH_R_PASS))
1058 12
                        return (SC_RX_BAD);
1059
1060 4757
                for (v = HTTP_HDR_FIRST; v < hp->nhd; v++) {
1061 3864
                        Tcheck(hp->hd[v]);
1062 3864
                        if (hp->hd[v].e < hp->hd[v].b + u + 1)
1063 160
                                continue;
1064 3704
                        if (hp->hd[v].b[u] != ':')
1065 3356
                                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 861
        CHECK_OBJ_NOTNULL(retval, STREAM_CLOSE_MAGIC);
1072 861
        return (retval);
1073 55906
}
1074
1075
/*--------------------------------------------------------------------*/
1076
1077
int
1078 44344
http_HdrIs(const struct http *hp, hdr_t hdr, const char *val)
1079
{
1080
        const char *p;
1081
1082 44344
        if (!http_GetHdr(hp, hdr, &p))
1083 41965
                return (0);
1084 2379
        AN(p);
1085 2379
        if (http_tok_eq(p, val))
1086 2267
                return (1);
1087 112
        return (0);
1088 44344
}
1089
1090
/*--------------------------------------------------------------------*/
1091
1092
uint16_t
1093 58907
http_GetStatus(const struct http *hp)
1094
{
1095
1096 58907
        CHECK_OBJ_NOTNULL(hp, HTTP_MAGIC);
1097 58907
        return (hp->status);
1098
}
1099
1100
int
1101 40863
http_IsStatus(const struct http *hp, int val)
1102
{
1103
1104 40863
        CHECK_OBJ_NOTNULL(hp, HTTP_MAGIC);
1105 40863
        assert(val >= 100 && val <= 999);
1106 40863
        return (val == (hp->status % 1000));
1107
}
1108
1109
/*--------------------------------------------------------------------
1110
 * Setting the status will also set the Reason appropriately
1111
 */
1112
1113
void
1114 4707
http_SetStatus(struct http *to, uint16_t status, const char *reason)
1115
{
1116
        char buf[4];
1117 4707
        const char *sstr = NULL;
1118
1119 4707
        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 4707
        to->status = status;
1125 4707
        status %= 1000;
1126 4707
        assert(status >= 100);
1127
1128 4707
        if (reason == NULL)
1129 940
                reason = http_Status2Reason(status, &sstr);
1130
        else
1131 3767
                (void)http_Status2Reason(status, &sstr);
1132
1133 4707
        if (sstr) {
1134 4571
                http_SetH(to, HTTP_HDR_STATUS, sstr);
1135 4571
        } else {
1136 136
                bprintf(buf, "%03d", status);
1137 136
                http_PutField(to, HTTP_HDR_STATUS, buf);
1138
        }
1139 4707
        http_SetH(to, HTTP_HDR_REASON, reason);
1140 4707
}
1141
1142
/*--------------------------------------------------------------------*/
1143
1144
const char *
1145 23608
http_GetMethod(const struct http *hp)
1146
{
1147
1148 23608
        CHECK_OBJ_NOTNULL(hp, HTTP_MAGIC);
1149 23608
        Tcheck(hp->hd[HTTP_HDR_METHOD]);
1150 23608
        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 31481
http_ForceField(struct http *to, unsigned n, const char *t)
1159
{
1160
        int i;
1161
1162 31481
        CHECK_OBJ_NOTNULL(to, HTTP_MAGIC);
1163 31481
        assert(n < HTTP_HDR_FIRST);
1164 31481
        assert(n == HTTP_HDR_METHOD || n == HTTP_HDR_PROTO);
1165 31481
        AN(t);
1166
1167
        /* NB: method names and protocol versions are case-sensitive. */
1168 31481
        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 31481
}
1177
1178
/*--------------------------------------------------------------------*/
1179
1180
void
1181 4299
http_PutResponse(struct http *to, const char *proto, uint16_t status,
1182
    const char *reason)
1183
{
1184
1185 4299
        CHECK_OBJ_NOTNULL(to, HTTP_MAGIC);
1186 4299
        if (proto != NULL)
1187 4299
                http_SetH(to, HTTP_HDR_PROTO, proto);
1188 4299
        http_SetStatus(to, status, reason);
1189 4299
}
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 163272
http_isfiltered(const struct http *fm, unsigned u, unsigned how)
1198
{
1199
        const char *e;
1200
        const struct http_hdrflg *f;
1201
1202 163272
        if (fm->hdf[u] & HDF_FILTER)
1203 68
                return (1);
1204 163204
        if (u < HTTP_HDR_FIRST)
1205 54634
                return (0);
1206 108570
        e = strchr(fm->hd[u].b, ':');
1207 108570
        if (e == NULL)
1208 0
                return (0);
1209 108570
        f = http_hdr_flags(fm->hd[u].b, e);
1210 108570
        return (f != NULL && f->flag & how);
1211 163272
}
1212
1213
int
1214 3382
http_IsFiltered(const struct http *fm, unsigned u, unsigned how)
1215
{
1216
1217 3382
        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 9120
http_EstimateWS(const struct http *fm, unsigned how)
1227
{
1228
        unsigned u, l;
1229
1230 9120
        l = 4;
1231 9120
        CHECK_OBJ_NOTNULL(fm, HTTP_MAGIC);
1232 87339
        for (u = 0; u < fm->nhd; u++) {
1233 78219
                if (u == HTTP_HDR_METHOD || u == HTTP_HDR_URL)
1234 18240
                        continue;
1235 59979
                Tcheck(fm->hd[u]);
1236 59979
                if (http_isfiltered(fm, u, how))
1237 1136
                        continue;
1238 58843
                l += Tlen(fm->hd[u]) + 1L;
1239 58843
        }
1240 9120
        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 9097
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 9097
        AN(p0);
1260 9097
        AN(l);
1261 9097
        p = p0;
1262 9097
        e = p + l;
1263 9097
        assert(p + 5 <= e);
1264 9097
        assert(fm->nhd <= fm->shd);
1265 9097
        n = HTTP_HDR_FIRST - 3;
1266 9097
        vbe16enc(p + 2, fm->status);
1267 9097
        p += 4;
1268 9097
        CHECK_OBJ_NOTNULL(fm, HTTP_MAGIC);
1269 87101
        for (u = 0; u < fm->nhd; u++) {
1270 78004
                if (u == HTTP_HDR_METHOD || u == HTTP_HDR_URL)
1271 18192
                        continue;
1272 59812
                Tcheck(fm->hd[u]);
1273 59812
                if (http_isfiltered(fm, u, how))
1274 1136
                        continue;
1275 58676
                http_VSLH(fm, u);
1276 58676
                w = Tlen(fm->hd[u]) + 1L;
1277 58676
                assert(p + w + 1 <= e);
1278 58676
                vmemcpy(p, fm->hd[u].b, w);
1279 58676
                p += w;
1280 58676
                n++;
1281 58676
        }
1282 9097
        *p++ = '\0';
1283 9097
        assert(p <= e);
1284 9097
        vbe16enc(p0, n + 1);
1285 9097
}
1286
1287
/*--------------------------------------------------------------------
1288
 * Decode byte string into http struct
1289
 */
1290
1291
int
1292 13413
HTTP_Decode(struct http *to, const uint8_t *fm)
1293
{
1294
1295 13413
        CHECK_OBJ_NOTNULL(to, HTTP_MAGIC);
1296 13413
        AN(to->vsl);
1297 13413
        AN(fm);
1298 13413
        if (vbe16dec(fm) <= to->shd) {
1299 13409
                to->status = vbe16dec(fm + 2);
1300 13409
                fm += 4;
1301 127158
                for (to->nhd = 0; to->nhd < to->shd; to->nhd++) {
1302 127158
                        if (to->nhd == HTTP_HDR_METHOD ||
1303 113743
                            to->nhd == HTTP_HDR_URL) {
1304 26804
                                to->hd[to->nhd].b = NULL;
1305 26804
                                to->hd[to->nhd].e = NULL;
1306 26804
                                continue;
1307
                        }
1308 100354
                        if (*fm == '\0')
1309 13409
                                return (0);
1310 86945
                        to->hd[to->nhd].b = (const void*)fm;
1311 86945
                        fm = (const void*)strchr((const void*)fm, '\0');
1312 86945
                        to->hd[to->nhd].e = (const void*)fm;
1313 86945
                        fm++;
1314 86945
                        http_VSLH(to, to->nhd);
1315 86945
                }
1316 0
        }
1317 8
        VSLb(to->vsl, SLT_Error,
1318
            "Too many headers to Decode object (%u vs. %u)",
1319 4
            vbe16dec(fm), to->shd);
1320 4
        return (-1);
1321 13413
}
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 3777
HTTP_IterHdrPack(struct worker *wrk, struct objcore *oc, const char **p)
1340
{
1341
        const char *ptr;
1342
1343 3777
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
1344 3777
        CHECK_OBJ_NOTNULL(oc, OBJCORE_MAGIC);
1345 3777
        AN(p);
1346
1347 3777
        if (*p == NULL) {
1348 1162
                ptr = ObjGetAttr(wrk, oc, OA_HEADERS, NULL);
1349 1162
                AN(ptr);
1350 1162
                ptr += 4;       /* Skip nhd and status */
1351 1162
                ptr = strchr(ptr, '\0') + 1;    /* Skip :proto: */
1352 1162
                ptr = strchr(ptr, '\0') + 1;    /* Skip :status: */
1353 1162
                ptr = strchr(ptr, '\0') + 1;    /* Skip :reason: */
1354 1162
                *p = ptr;
1355 1162
        } else {
1356 2615
                *p = strchr(*p, '\0') + 1;      /* Skip to next header */
1357
        }
1358 3777
        if (**p == '\0')
1359 248
                return (0);
1360 3529
        return (1);
1361 3777
}
1362
1363
const char *
1364 1235
HTTP_GetHdrPack(struct worker *wrk, struct objcore *oc, hdr_t hdr)
1365
{
1366
        const char *ptr;
1367
1368 1235
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
1369 1235
        CHECK_OBJ_NOTNULL(oc, OBJCORE_MAGIC);
1370 1235
        CHECK_HDR(hdr);
1371
1372 1235
        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 3780
        HTTP_FOREACH_PACK(wrk, oc, ptr) {
1391 3532
                if (http_hdr_at(ptr, hdr->str, hdr->len)) {
1392 915
                        ptr += hdr->len;
1393 1826
                        while (vct_islws(*ptr))
1394 911
                                ptr++;
1395 915
                        return (ptr);
1396
                }
1397
        }
1398
1399 248
        return (NULL);
1400 1235
}
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 27969
http_linkh(const struct http *to, const struct http *fm, unsigned n)
1446
{
1447
1448 27969
        assert(n < HTTP_HDR_FIRST);
1449 27969
        Tcheck(fm->hd[n]);
1450 27969
        to->hd[n] = fm->hd[n];
1451 27969
        to->hdf[n] = fm->hdf[n];
1452 27969
        http_VSLH(to, n);
1453 27969
}
1454
1455
/*--------------------------------------------------------------------*/
1456
1457
void
1458 9325
http_FilterReq(struct http *to, const struct http *fm, unsigned how)
1459
{
1460
        unsigned u;
1461
1462 9325
        CHECK_OBJ_NOTNULL(to, HTTP_MAGIC);
1463 9325
        CHECK_OBJ_NOTNULL(fm, HTTP_MAGIC);
1464
1465 9325
        http_linkh(to, fm, HTTP_HDR_METHOD);
1466 9325
        http_SetWellKnownMethod(to);
1467 9325
        http_linkh(to, fm, HTTP_HDR_URL);
1468 9325
        http_linkh(to, fm, HTTP_HDR_PROTO);
1469 9325
        to->protover = fm->protover;
1470 9325
        to->status = fm->status;
1471
1472 9325
        to->nhd = HTTP_HDR_FIRST;
1473 49437
        for (u = HTTP_HDR_FIRST; u < fm->nhd; u++) {
1474 40112
                Tcheck(fm->hd[u]);
1475 40112
                if (http_isfiltered(fm, u, how))
1476 486
                        continue;
1477 39626
                assert (to->nhd < to->shd);
1478 39626
                to->hd[to->nhd] = fm->hd[u];
1479 39626
                to->hdf[to->nhd] = 0;
1480 39626
                http_VSLH(to, to->nhd);
1481 39626
                to->nhd++;
1482 39626
        }
1483 9325
}
1484
1485
/*--------------------------------------------------------------------
1486
 * This function copies any header fields which reference foreign
1487
 * storage into our own WS.
1488
 */
1489
1490
void
1491 9204
http_CopyHome(const struct http *hp)
1492
{
1493
        unsigned u, l;
1494
        const char *p;
1495
1496 100077
        for (u = 0; u < hp->nhd; u++) {
1497 90873
                if (hp->hd[u].b == NULL) {
1498 18406
                        assert(u < HTTP_HDR_FIRST);
1499 18406
                        continue;
1500
                }
1501
1502 72467
                l = Tlen(hp->hd[u]);
1503 72467
                if (WS_Allocated(hp->ws, hp->hd[u].b, l))
1504 5758
                        continue;
1505
1506 66709
                p = WS_Copy(hp->ws, hp->hd[u].b, l + 1L);
1507 66709
                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 66709
                hp->hd[u].b = p;
1513 66709
                hp->hd[u].e = p + l;
1514 66709
        }
1515 9204
}
1516
1517
/*--------------------------------------------------------------------*/
1518
1519
void
1520 38802
http_SetHeader(struct http *to, const char *header)
1521
{
1522
1523 38802
        CHECK_OBJ_NOTNULL(to, HTTP_MAGIC);
1524 38802
        if (to->nhd >= to->shd) {
1525 4
                VSLbs(to->vsl, SLT_LostHeader, TOSTRAND(header));
1526 4
                http_fail(to);
1527 4
                return;
1528
        }
1529 38798
        http_SetH(to, to->nhd++, header);
1530 38802
}
1531
1532
/*--------------------------------------------------------------------*/
1533
1534
void
1535 17136
http_ForceHeader(struct http *to, hdr_t hdr, const char *val)
1536
{
1537
1538 17136
        CHECK_OBJ_NOTNULL(to, HTTP_MAGIC);
1539 17136
        if (http_HdrIs(to, hdr, val))
1540 1555
                return;
1541 15581
        http_Unset(to, hdr);
1542 15581
        http_PrintfHeader(to, "%s %s", hdr->str, val);
1543 17136
}
1544
1545
void
1546 44490
http_AppendHeader(struct http *to, hdr_t hdr, const char *val)
1547
{
1548
        const char *old;
1549
1550 44490
        http_CollectHdr(to, hdr);
1551 44490
        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 44298
                http_PrintfHeader(to, "%s %s", hdr->str, val);
1556
        }
1557 44490
}
1558
1559
void
1560 103659
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 103659
        CHECK_OBJ_NOTNULL(to, HTTP_MAGIC);
1568
1569 103659
        va_start(ap, fmt);
1570 103659
        va_copy(ap2, ap);
1571
1572 103659
        WS_VSB_new(vsb, to->ws);
1573 103659
        VSB_vprintf(vsb, fmt, ap);
1574 103659
        p = WS_VSB_finish(vsb, to->ws, &sz);
1575
1576 103659
        if (p == NULL || to->nhd >= to->shd) {
1577 132
                http_fail(to);
1578 132
                VSLbv(to->vsl, SLT_LostHeader, fmt, ap2);
1579 132
        } else {
1580 103527
                http_SetH(to, to->nhd++, p);
1581
        }
1582 103659
        va_end(ap);
1583 103659
        va_end(ap2);
1584 103659
}
1585
1586
void
1587 4348
http_TimeHeader(struct http *to, const char *fmt, vtim_real now)
1588
{
1589
        unsigned l;
1590
        char *p;
1591
1592 4348
        CHECK_OBJ_NOTNULL(to, HTTP_MAGIC);
1593 4348
        if (to->nhd >= to->shd) {
1594 0
                VSLbs(to->vsl, SLT_LostHeader, TOSTRAND(fmt));
1595 0
                http_fail(to);
1596 0
                return;
1597
        }
1598 4348
        l = (unsigned)vstrlen(fmt);
1599 4348
        p = WS_Alloc(to->ws, l + VTIM_FORMAT_SIZE);
1600 4348
        if (p == NULL) {
1601 308
                http_fail(to);
1602 308
                VSLbs(to->vsl, SLT_LostHeader, TOSTRAND(fmt));
1603 308
                return;
1604
        }
1605 4040
        strcpy(p, fmt);
1606 4040
        VTIM_format(now, p + l);
1607 4040
        http_SetH(to, to->nhd++, p);
1608 4348
}
1609
1610
const char *
1611 28950
http_ViaHeader(void)
1612
{
1613
1614 28950
        return (via_hdr);
1615
}
1616
1617
/*--------------------------------------------------------------------*/
1618
1619
void
1620 93555
http_Unset(struct http *hp, hdr_t hdr)
1621
{
1622
        uint16_t u, v;
1623
1624 609217
        for (v = u = HTTP_HDR_FIRST; u < hp->nhd; u++) {
1625 515662
                Tcheck(hp->hd[u]);
1626 515662
                if (http_IsHdr(&hp->hd[u], hdr)) {
1627 4200
                        http_VSLH_del(hp, u);
1628 4200
                        continue;
1629
                }
1630 511462
                if (v != u) {
1631 12095
                        vmemcpy(&hp->hd[v], &hp->hd[u], sizeof *hp->hd);
1632 12095
                        vmemcpy(&hp->hdf[v], &hp->hdf[u], sizeof *hp->hdf);
1633 12095
                }
1634 511462
                v++;
1635 511462
        }
1636 93555
        hp->nhd = v;
1637 93555
}
1638
1639
void
1640 23608
http_SetWellKnownMethod(struct http *hp)
1641
{
1642
        size_t l;
1643
        const char *method;
1644
1645 23608
        CHECK_OBJ_NOTNULL(hp, HTTP_MAGIC);
1646
1647 23608
        method = http_GetMethod(hp);
1648 23608
        AN(method);
1649 23608
        l = vstrlen(method);
1650 23608
        hp->wkm = WKM_UNKNOWN;
1651
#define WKM(wk, bit)                                                    \
1652
        do {                                                            \
1653
                if (l == vstrlen(#wk) && !vmemcmp(#wk, method, l)) {    \
1654
                        hp->wkm = WKM_##wk;                             \
1655
                        return;                                         \
1656
                }                                                       \
1657
        } while (0);
1658
#include "tbl/well_known_methods.h"
1659
#undef WKM
1660
}