varnish-cache/bin/varnishd/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
 * HTTP request storage and manipulation
31
 */
32
33
#include "config.h"
34
35
#include "cache_varnishd.h"
36
#include <stdio.h>
37
#include <stdlib.h>
38
39
#include "common/heritage.h"
40
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 152528
http_hdr_flags(const char *b, const char *e)
183
{
184
        unsigned u;
185
        struct http_hdrflg *retval;
186
187 152528
        if (b == NULL || e == NULL)
188 8
                return (NULL);
189 152528
        u = pdiff(b, e);
190 152528
        if (u < GPERF_MIN_WORD_LENGTH || u > GPERF_MAX_WORD_LENGTH)
191 70
                return (NULL);
192 304916
        u += http_asso_values[(uint8_t)(e[-1])] +
193 152458
             http_asso_values[(uint8_t)(b[0])];
194 152458
        if (u > GPERF_MAX_HASH_VALUE)
195 2084
                return (NULL);
196 150374
        retval = &http_hdrflg[u];
197 150374
        if (retval->hdr == NULL)
198 577
                return (NULL);
199 149797
        AN(*retval->hdr);
200 149797
        if (!http_hdr_at(*retval->hdr + 1, b, e - b))
201 2120
                return (NULL);
202 147677
        return (retval);
203 152528
}
204
205
/*--------------------------------------------------------------------*/
206
207
static void
208 98696
http_init_hdr(hdr_t hdr, int flg)
209
{
210
        struct http_hdrflg *f;
211
212 98696
        f = http_hdr_flags(hdr->str, hdr->str + hdr->len - 1);
213 98696
        AN(f);
214 98696
        assert(*f->hdr == hdr);
215 98696
        f->flag = flg;
216 98696
}
217
218
void
219 1898
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 1898
        AN(vsb);
228
        VSB_printf(vsb, "1.1 %s (Varnish/" PACKAGE_BRANCH ")",
229
            heritage.identity);
230 1898
        AZ(VSB_finish(vsb));
231 1898
        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 252547
http_VSLH(const struct http *hp, unsigned hdr)
245
{
246
        int i;
247
248 252547
        if (hp->vsl != NULL) {
249 252559
                assert(VXID_TAG(hp->vsl->wid));
250 252559
                i = hdr;
251 252559
                if (i > HTTP_HDR_FIRST)
252 132982
                        i = HTTP_HDR_FIRST;
253 252559
                i += hp->logtag;
254 252559
                VSLbt(hp->vsl, (enum VSL_tag_e)i, hp->hd[hdr]);
255 252559
        }
256 252571
}
257
258
static void
259 2066
http_VSLH_del(const struct http *hp, unsigned hdr)
260
{
261
        int i;
262
263 2066
        if (hp->vsl != NULL) {
264
                /* We don't support unsetting stuff in the first line */
265 2066
                assert (hdr >= HTTP_HDR_FIRST);
266 2066
                assert(VXID_TAG(hp->vsl->wid));
267 2066
                i = (HTTP_HDR_UNSET - HTTP_HDR_METHOD);
268 2066
                i += hp->logtag;
269 2066
                VSLbt(hp->vsl, (enum VSL_tag_e)i, hp->hd[hdr]);
270 2066
        }
271 2066
}
272
273
/*--------------------------------------------------------------------*/
274
275
void
276 11746
http_VSL_log(const struct http *hp)
277
{
278
        unsigned u;
279
280 102587
        for (u = 0; u < hp->nhd; u++)
281 158198
                if (hp->hd[u].b != NULL)
282 67357
                        http_VSLH(hp, u);
283 11746
}
284
285
/*--------------------------------------------------------------------*/
286
287
static void
288 208
http_fail(const struct http *hp)
289
{
290
        char id[WS_ID_SIZE];
291
292 208
        VSC_C_main->losthdr++;
293 208
        WS_Id(hp->ws, id);
294 208
        VSLb(hp->vsl, SLT_Error, "out of workspace (%s)", id);
295 208
        WS_MarkOverflow(hp->ws);
296 208
}
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 2984
http_Status2Reason(unsigned status, const char **sstr)
314
{
315
        struct http_msg *mp;
316
317 2984
        status %= 1000;
318 2984
        assert(status >= 100);
319 91024
        for (mp = http_msg; mp->nbr != 0 && mp->nbr <= status; mp++)
320 90934
                if (mp->nbr == status) {
321 2894
                        if (sstr)
322 2210
                                *sstr = mp->status;
323 2894
                        return (mp->txt);
324
                }
325 90
        return ("Unknown HTTP Status");
326 2984
}
327
328
/*--------------------------------------------------------------------*/
329
330
unsigned
331 10722
HTTP_estimate(unsigned nhttp)
332
{
333
334
        /* XXX: We trust the structs to size-aligned as necessary */
335 10722
        return (PRNDUP(sizeof(struct http) + sizeof(txt) * nhttp + nhttp));
336
}
337
338
struct http *
339 32169
HTTP_create(void *p, uint16_t nhttp, unsigned len)
340
{
341
        struct http *hp;
342
343 32169
        hp = p;
344 32169
        hp->magic = HTTP_MAGIC;
345 32169
        hp->hd = (void*)(hp + 1);
346 32169
        hp->shd = nhttp;
347 32169
        hp->hdf = (void*)(hp->hd + nhttp);
348 32169
        assert((unsigned char*)p + len == hp->hdf + PRNDUP(nhttp));
349 32169
        return (hp);
350
}
351
352
/*--------------------------------------------------------------------*/
353
354
void
355 29998
HTTP_Setup(struct http *hp, struct ws *ws, struct vsl_log *vsl,
356
    enum VSL_tag_e  whence)
357
{
358 29998
        http_Teardown(hp);
359 29998
        hp->nhd = HTTP_HDR_FIRST;
360 29998
        hp->logtag = whence;
361 29998
        hp->ws = ws;
362 29998
        hp->vsl = vsl;
363 29998
}
364
365
/*--------------------------------------------------------------------
366
 * http_Teardown() is a safety feature, we use it to zap all http
367
 * structs once we're done with them, to minimize the risk that
368
 * old stale pointers exist to no longer valid stuff.
369
 */
370
371
void
372 46828
http_Teardown(struct http *hp)
373
{
374
375 46828
        CHECK_OBJ_NOTNULL(hp, HTTP_MAGIC);
376 46828
        AN(hp->shd);
377 46828
        memset(&hp->nhd, 0, sizeof *hp - offsetof(struct http, nhd));
378 46828
        memset(hp->hd, 0, sizeof *hp->hd * hp->shd);
379 46828
        memset(hp->hdf, 0, sizeof *hp->hdf * hp->shd);
380 46828
}
381
382
/*--------------------------------------------------------------------
383
 * Duplicate the http content into another http
384
 * We cannot just memcpy the struct because the hd & hdf are private
385
 * storage to the struct http.
386
 */
387
388
void
389 13177
HTTP_Dup(struct http *to, const struct http * fm)
390
{
391
392 13177
        assert(fm->nhd <= to->shd);
393 13177
        memcpy(to->hd, fm->hd, fm->nhd * sizeof *to->hd);
394 13177
        memcpy(to->hdf, fm->hdf, fm->nhd * sizeof *to->hdf);
395 13177
        to->nhd = fm->nhd;
396 13177
        to->logtag = fm->logtag;
397 13177
        to->status = fm->status;
398 13177
        to->protover = fm->protover;
399 13177
}
400
401
402
/*--------------------------------------------------------------------
403
 * Clone the entire http structure, including vsl & ws
404
 */
405
406
void
407 12446
HTTP_Clone(struct http *to, const struct http * const fm)
408
{
409
410 12446
        HTTP_Dup(to, fm);
411 12446
        to->vsl = fm->vsl;
412 12446
        to->ws = fm->ws;
413 12446
}
414
415
/*--------------------------------------------------------------------*/
416
417
void
418 13438
http_Proto(struct http *to)
419
{
420
        const char *fm;
421
422 13438
        fm = to->hd[HTTP_HDR_PROTO].b;
423
424 26858
        if (fm != NULL &&
425 13422
            (fm[0] == 'H' || fm[0] == 'h') &&
426 13421
            (fm[1] == 'T' || fm[1] == 't') &&
427 13421
            (fm[2] == 'T' || fm[2] == 't') &&
428 13421
            (fm[3] == 'P' || fm[3] == 'p') &&
429 13421
            fm[4] == '/' &&
430 13421
            vct_isdigit(fm[5]) &&
431 13421
            fm[6] == '.' &&
432 13421
            vct_isdigit(fm[7]) &&
433 13420
            fm[8] == '\0') {
434 13420
                to->protover = 10 * (fm[5] - '0') + (fm[7] - '0');
435 13420
        } else {
436 18
                to->protover = 0;
437
        }
438 13438
}
439
440
/*--------------------------------------------------------------------*/
441
442
void
443 80139
http_SetH(struct http *to, unsigned n, const char *header)
444
{
445
446 80139
        assert(n < to->nhd);
447 80139
        AN(header);
448 80139
        to->hd[n].b = TRUST_ME(header);
449 80139
        to->hd[n].e = strchr(to->hd[n].b, '\0');
450 80139
        to->hdf[n] = 0;
451 80139
        http_VSLH(to, n);
452 80139
        if (n == HTTP_HDR_PROTO)
453 2750
                http_Proto(to);
454 80139
}
455
456
/*--------------------------------------------------------------------*/
457
458
static void
459 72
http_PutField(struct http *to, int field, const char *string)
460
{
461
        const char *p;
462
463 72
        CHECK_OBJ_NOTNULL(to, HTTP_MAGIC);
464 72
        p = WS_Copy(to->ws, string, -1);
465 72
        if (p == NULL) {
466 2
                http_fail(to);
467 2
                VSLbs(to->vsl, SLT_LostHeader, TOSTRAND(string));
468 2
                return;
469
        }
470 70
        http_SetH(to, field, p);
471 72
}
472
473
/*--------------------------------------------------------------------*/
474
475
int
476 292601
http_IsHdr(const txt *hh, hdr_t hdr)
477
{
478
479 292601
        Tcheck(*hh);
480 292601
        CHECK_HDR(hdr);
481 292601
        return (http_hdr_at(hdr->str, hh->b, hdr->len));
482
}
483
484
/*--------------------------------------------------------------------*/
485
486
static unsigned
487 301520
http_findhdr(const struct http *hp, unsigned l, const char *hdr)
488
{
489
        unsigned u;
490
491 1309783
        for (u = HTTP_HDR_FIRST; u < hp->nhd; u++) {
492 1075105
                Tcheck(hp->hd[u]);
493 1075105
                if (hp->hd[u].e < hp->hd[u].b + l + 1)
494 193848
                        continue;
495 881257
                if (hp->hd[u].b[l] != ':')
496 740948
                        continue;
497 140309
                if (!http_hdr_at(hdr, hp->hd[u].b, l))
498 73467
                        continue;
499 66842
                return (u);
500
        }
501 234678
        return (0);
502 301520
}
503
504
/*--------------------------------------------------------------------
505
 * Count how many instances we have of this header
506
 */
507
508
unsigned
509 15254
http_CountHdr(const struct http *hp, hdr_t hdr)
510
{
511 15254
        unsigned retval = 0;
512
        unsigned u;
513
514 15254
        CHECK_OBJ_NOTNULL(hp, HTTP_MAGIC);
515
516 50862
        for (u = HTTP_HDR_FIRST; u < hp->nhd; u++) {
517 35608
                Tcheck(hp->hd[u]);
518 35608
                if (http_IsHdr(&hp->hd[u], hdr))
519 7536
                        retval++;
520 35608
        }
521 15254
        return (retval);
522
}
523
524
/*--------------------------------------------------------------------
525
 * This function collapses multiple header lines of the same name.
526
 * The lines are joined with a comma, according to [rfc2616, 4.2bot, p32]
527
 */
528
529
void
530 49053
http_CollectHdr(struct http *hp, hdr_t hdr)
531
{
532
533 49053
        http_CollectHdrSep(hp, hdr, NULL);
534 49053
}
535
536
/*--------------------------------------------------------------------
537
 * You may prefer to collapse header fields using a different separator.
538
 * For Cookie headers, the separator is "; " for example. That's probably
539
 * the only example too.
540
 */
541
542
void
543 49353
http_CollectHdrSep(struct http *hp, hdr_t hdr, const char *sep)
544
{
545
        unsigned u, lsep, ml, f, x, d;
546 49353
        char *b = NULL, *e = NULL;
547
        const char *v;
548
549 49353
        CHECK_OBJ_NOTNULL(hp, HTTP_MAGIC);
550 49353
        CHECK_HDR(hdr);
551
552 49353
        if (WS_Overflowed(hp->ws))
553 40
                return;
554
555 49313
        if (sep == NULL || *sep == '\0')
556 49012
                sep = ", ";
557 49313
        lsep = strlen(sep);
558
559 49313
        f = http_findhdr(hp, hdr->len - 1, hdr->str);
560 49313
        if (f == 0)
561 48484
                return;
562
563 3054
        for (d = u = f + 1; u < hp->nhd; u++) {
564 2225
                Tcheck(hp->hd[u]);
565 2225
                if (!http_IsHdr(&hp->hd[u], hdr)) {
566 2189
                        if (d != u) {
567 142
                                hp->hd[d] = hp->hd[u];
568 142
                                hp->hdf[d] = hp->hdf[u];
569 142
                        }
570 2189
                        d++;
571 2189
                        continue;
572
                }
573 36
                if (b == NULL) {
574
                        /* Found second header, start our collection */
575 32
                        ml = WS_ReserveAll(hp->ws);
576 32
                        b = WS_Reservation(hp->ws);
577 32
                        e = b + ml;
578 32
                        x = Tlen(hp->hd[f]);
579 32
                        if (b + x >= e) {
580 0
                                http_fail(hp);
581 0
                                VSLbs(hp->vsl, SLT_LostHeader,
582 0
                                    TOSTRAND(hdr->str));
583 0
                                WS_Release(hp->ws, 0);
584 0
                                return;
585
                        }
586 32
                        memcpy(b, hp->hd[f].b, x);
587 32
                        b += x;
588 32
                }
589
590 36
                AN(b);
591 36
                AN(e);
592
593
                /* Append the Nth header we found */
594 36
                x = Tlen(hp->hd[u]) - hdr->len;
595
596 36
                v = hp->hd[u].b + hdr->len;
597 72
                while (vct_issp(*v)) {
598 36
                        v++;
599 36
                        x--;
600
                }
601
602 36
                if (b + lsep + x >= e) {
603 0
                        http_fail(hp);
604 0
                        VSLbs(hp->vsl, SLT_LostHeader, TOSTRAND(hdr->str));
605 0
                        WS_Release(hp->ws, 0);
606 0
                        return;
607
                }
608 36
                memcpy(b, sep, lsep);
609 36
                b += lsep;
610 36
                memcpy(b, v, x);
611 36
                b += x;
612 36
        }
613 829
        if (b == NULL)
614 797
                return;
615 32
        hp->nhd = (uint16_t)d;
616 32
        AN(e);
617 32
        *b = '\0';
618 32
        hp->hd[f].b = WS_Reservation(hp->ws);
619 32
        hp->hd[f].e = b;
620 32
        WS_ReleaseP(hp->ws, b + 1);
621 49353
}
622
623
/*--------------------------------------------------------------------*/
624
625
int
626 251908
http_GetHdr(const struct http *hp, hdr_t hdr, const char **ptr)
627
{
628
        unsigned u;
629
        const char *p;
630
631 251908
        CHECK_HDR(hdr);
632 251908
        u = http_findhdr(hp, hdr->len - 1, hdr->str);
633 251908
        if (u == 0) {
634 186056
                if (ptr != NULL)
635 171007
                        *ptr = NULL;
636 186056
                return (0);
637
        }
638 65852
        if (ptr != NULL) {
639 53909
                p = hp->hd[u].b + hdr->len;
640 107729
                while (vct_issp(*p))
641 53820
                        p++;
642 53909
                *ptr = p;
643 53909
        }
644 65852
        return (1);
645 251908
}
646
647
/*-----------------------------------------------------------------------------
648
 * Split source string at any of the separators, return pointer to first
649
 * and last+1 char of substrings, with whitespace trimmed at both ends.
650
 * If sep being an empty string is shorthand for VCT::SP
651
 * If stop is NULL, src is NUL terminated.
652
 */
653
654
static int
655 4968
http_split(const char **src, const char *stop, const char *sep,
656
    const char **b, const char **e)
657
{
658
        const char *p, *q;
659
660 4968
        AN(src);
661 4968
        AN(*src);
662 4968
        AN(sep);
663 4968
        AN(b);
664 4968
        AN(e);
665
666 4968
        if (stop == NULL)
667 4954
                stop = strchr(*src, '\0');
668
669 8511
        for (p = *src; p < stop && (vct_issp(*p) || strchr(sep, *p)); p++)
670 174
                continue;
671
672 4968
        if (p >= stop) {
673 1773
                *b = NULL;
674 1773
                *e = NULL;
675 1773
                return (0);
676
        }
677
678 3195
        *b = p;
679 3195
        if (*sep == '\0') {
680 0
                for (q = p + 1; q < stop && !vct_issp(*q); q++)
681 0
                        continue;
682 0
                *e = q;
683 0
                *src = q;
684 0
                return (1);
685
        }
686 15553
        for (q = p + 1; q < stop && !strchr(sep, *q); q++)
687 12358
                continue;
688 3195
        *src = q;
689 3195
        while (q > p && vct_issp(q[-1]))
690 0
                q--;
691 3195
        *e = q;
692 3195
        return (1);
693 4968
}
694
695
/*-----------------------------------------------------------------------------
696
 * Comparison rule for tokens:
697
 *      if target string starts with '"', we use memcmp() and expect closing
698
 *      double quote as well
699
 *      otherwise we use http_tok_at()
700
 *
701
 * On match we increment *bp past the token name.
702
 */
703
704
static int
705 2820
http_istoken(const char **bp, const char *e, const char *token)
706
{
707 2820
        int fl = strlen(token);
708
        const char *b;
709
710 2820
        AN(bp);
711 2820
        AN(e);
712 2820
        AN(token);
713
714 2820
        b = *bp;
715
716 2820
        if (b + fl + 2 <= e && *b == '"' &&
717 0
            !memcmp(b + 1, token, fl) && b[fl + 1] == '"') {
718 0
                *bp += fl + 2;
719 0
                return (1);
720
        }
721 2902
        if (b + fl <= e && http_tok_at(b, token, fl) &&
722 1322
            (b + fl == e || !vct_istchar(b[fl]))) {
723 1322
                *bp += fl;
724 1322
                return (1);
725
        }
726 1498
        return (0);
727 2820
}
728
729
/*-----------------------------------------------------------------------------
730
 * Find a given data element (token) in a header according to RFC2616's #rule
731
 * (section 2.1, p15)
732
 *
733
 * On case sensitivity:
734
 *
735
 * Section 4.2 (Messages Headers) defines field (header) name as case
736
 * insensitive, but the field (header) value/content may be case-sensitive.
737
 *
738
 * http_GetHdrToken looks up a token in a header value and the rfc does not say
739
 * explicitly if tokens are to be compared with or without respect to case.
740
 *
741
 * But all examples and specific statements regarding tokens follow the rule
742
 * that unquoted tokens are to be matched case-insensitively and quoted tokens
743
 * case-sensitively.
744
 *
745
 * The optional pb and pe arguments will point to the token content start and
746
 * end+1, white space trimmed on both sides.
747
 */
748
749
int
750 30060
http_GetHdrToken(const struct http *hp, hdr_t hdr,
751
    const char *token, const char **pb, const char **pe)
752
{
753
        const char *h, *b, *e;
754
755 30060
        if (pb != NULL)
756 22703
                *pb = NULL;
757 30060
        if (pe != NULL)
758 7109
                *pe = NULL;
759 30060
        if (!http_GetHdr(hp, hdr, &h))
760 27314
                return (0);
761 2746
        AN(h);
762
763 4244
        while (http_split(&h, NULL, ",", &b, &e))
764 2820
                if (http_istoken(&b, e, token))
765 1322
                        break;
766 2746
        if (b == NULL)
767 1424
                return (0);
768 1322
        if (pb != NULL) {
769 1314
                for (; vct_islws(*b); b++)
770 10
                        continue;
771 1304
                if (b == e) {
772 1224
                        b = NULL;
773 1224
                        e = NULL;
774 1224
                }
775 1304
                *pb = b;
776 1304
                if (pe != NULL)
777 1210
                        *pe = e;
778 1304
        }
779 1322
        return (1);
780 30060
}
781
782
/*--------------------------------------------------------------------
783
 * Find a given header field's quality value (qvalue).
784
 */
785
786
double
787 7109
http_GetHdrQ(const struct http *hp, hdr_t hdr, const char *field)
788
{
789
        const char *hb, *he, *b, *e;
790
        int i;
791
        double a, f;
792
793 7109
        i = http_GetHdrToken(hp, hdr, field, &hb, &he);
794 7109
        if (!i)
795 5899
                return (0.);
796
797 1210
        if (hb == NULL)
798 1196
                return (1.);
799 14
        while (http_split(&hb, he, ";", &b, &e)) {
800 14
                if (*b != 'q')
801 0
                        continue;
802 14
                for (b++; b < e && vct_issp(*b); b++)
803 0
                        continue;
804 14
                if (b == e || *b != '=')
805 0
                        continue;
806 14
                break;
807
        }
808 14
        if (b == NULL)
809 0
                return (1.);
810 14
        for (b++; b < e && vct_issp(*b); b++)
811 0
                continue;
812 14
        if (b == e || (*b != '.' && !vct_isdigit(*b)))
813 2
                return (0.);
814 12
        a = 0;
815 24
        while (b < e && vct_isdigit(*b)) {
816 12
                a *= 10.;
817 12
                a += *b - '0';
818 12
                b++;
819
        }
820 12
        if (b == e || *b++ != '.')
821 2
                return (a);
822 10
        f = .1;
823 32
        while (b < e && vct_isdigit(*b)) {
824 22
                a += f * (*b - '0');
825 22
                f *= .1;
826 22
                b++;
827
        }
828 10
        return (a);
829 7109
}
830
831
/*--------------------------------------------------------------------
832
 * Find a given header field's value.
833
 */
834
835
int
836 15595
http_GetHdrField(const struct http *hp, hdr_t hdr,
837
    const char *field, const char **ptr)
838
{
839
        const char *h;
840
        int i;
841
842 15595
        if (ptr != NULL)
843 7936
                *ptr = NULL;
844
845 15595
        h = NULL;
846 15595
        i = http_GetHdrToken(hp, hdr, field, &h, NULL);
847 15595
        if (!i)
848 15501
                return (i);
849
850 94
        if (ptr != NULL && h != NULL) {
851
                /* Skip whitespace, looking for '=' */
852 66
                while (*h && vct_issp(*h))
853 0
                        h++;
854 66
                if (*h == '=') {
855 66
                        h++;
856 74
                        while (*h && vct_issp(*h))
857 8
                                h++;
858 66
                        *ptr = h;
859 66
                }
860 66
        }
861 94
        return (i);
862 15595
}
863
864
/*--------------------------------------------------------------------*/
865
866
ssize_t
867 22455
http_GetContentLength(const struct http *hp)
868
{
869
        ssize_t cl;
870
        const char *b;
871
872 22455
        CHECK_OBJ_NOTNULL(hp, HTTP_MAGIC);
873
874 22455
        if (!http_GetHdr(hp, H_Content_Length, &b))
875 8829
                return (-1);
876 13626
        cl = VNUM_uint(b, NULL, &b);
877 13626
        if (cl < 0)
878 8
                return (-2);
879 13618
        while (vct_islws(*b))
880 0
                b++;
881 13618
        if (*b != '\0')
882 0
                return (-2);
883 13618
        return (cl);
884 22455
}
885
886
ssize_t
887 4025
http_GetContentRange(const struct http *hp, ssize_t *lo, ssize_t *hi)
888
{
889
        ssize_t tmp, cl;
890
        const char *b, *t;
891
892 4025
        CHECK_OBJ_NOTNULL(hp, HTTP_MAGIC);
893
894 4025
        if (lo == NULL)
895 0
                lo = &tmp;
896 4025
        if (hi == NULL)
897 0
                hi = &tmp;
898
899 4025
        *lo = *hi = -1;
900
901 4025
        if (!http_GetHdr(hp, H_Content_Range, &b))
902 4005
                return (-1);
903
904 20
        t = strchr(b, ' ');
905 20
        if (t == NULL)
906 2
                return (-2);            // Missing space after range unit
907
908 18
        if (!http_range_at(b, bytes, t - b))
909 2
                return (-1);            // Unknown range unit, ignore
910 16
        b = t + 1;
911
912 16
        if (*b == '*') {                // Content-Range: bytes */123
913 6
                *lo = *hi = -1;
914 6
                b++;
915 6
        } else {                        // Content-Range: bytes 1-2/3
916 10
                *lo = VNUM_uint(b, NULL, &b);
917 10
                if (*lo < 0)
918 0
                        return (-2);
919 10
                if (*b != '-')
920 0
                        return (-2);
921 10
                *hi = VNUM_uint(b + 1, NULL, &b);
922 10
                if (*hi < 0)
923 0
                        return (-2);
924
        }
925 16
        if (*b != '/')
926 0
                return (-2);
927 16
        if (b[1] == '*') {              // Content-Range: bytes 1-2/*
928 2
                cl = -1;
929 2
                b += 2;
930 2
        } else {
931 14
                cl = VNUM_uint(b + 1, NULL, &b);
932 14
                if (cl <= 0)
933 0
                        return (-2);
934
        }
935 16
        while (vct_islws(*b))
936 0
                b++;
937 16
        if (*b != '\0')
938 0
                return (-2);
939 16
        if (*lo > *hi)
940 0
                return (-2);
941 16
        assert(cl >= -1);
942 16
        if (*lo >= cl || *hi >= cl)
943 2
                return (-2);
944 14
        AN(cl);
945 14
        return (cl);
946 4025
}
947
948
const char *
949 4124
http_GetRange(const struct http *hp, ssize_t *lo, ssize_t *hi, ssize_t len)
950
{
951
        ssize_t tmp_lo, tmp_hi;
952
        const char *b, *t;
953
954 4124
        CHECK_OBJ_NOTNULL(hp, HTTP_MAGIC);
955
956 4124
        if (lo == NULL)
957 0
                lo = &tmp_lo;
958 4124
        if (hi == NULL)
959 0
                hi = &tmp_hi;
960
961 4124
        *lo = *hi = -1;
962
963 4124
        if (!http_GetHdr(hp, H_Range, &b))
964 4014
                return (NULL);
965
966 110
        t = strchr(b, '=');
967 110
        if (t == NULL)
968 4
                return ("Missing '='");
969
970 106
        if (!http_range_at(b, bytes, t - b))
971 6
                return ("Not Bytes");
972 100
        b = t + 1;
973
974 100
        *lo = VNUM_uint(b, NULL, &b);
975 100
        if (*lo == -2)
976 0
                return ("Low number too big");
977 100
        if (*b++ != '-')
978 0
                return ("Missing hyphen");
979
980 100
        *hi = VNUM_uint(b, NULL, &b);
981 100
        if (*hi == -2)
982 0
                return ("High number too big");
983 100
        if (*lo == -1 && *hi == -1)
984 2
                return ("Neither high nor low");
985 98
        if (*lo == -1 && *hi == 0)
986 2
                return ("No low, high is zero");
987 96
        if (*hi >= 0 && *hi < *lo)
988 2
                return ("high smaller than low");
989
990 96
        while (vct_islws(*b))
991 2
                b++;
992 94
        if (*b != '\0')
993 2
                return ("Trailing stuff");
994
995 92
        assert(*lo >= -1);
996 92
        assert(*hi >= -1);
997
998 92
        if (*lo < 0) {
999 8
                assert(*hi > 0);
1000 8
                *lo = len - *hi;
1001 8
                if (*lo < 0)
1002 4
                        *lo = 0;
1003 8
                *hi = len - 1;
1004 92
        } else if (len >= 0 && (*hi >= len || *hi < 0)) {
1005 18
                *hi = len - 1;
1006 18
        }
1007
1008 92
        if (len <= 0)
1009 36
                return (NULL);                  // Allow 200 response
1010
1011 56
        if (*lo >= len)
1012 2
                return ("low range beyond object");
1013
1014 54
        return (NULL);
1015 4124
}
1016
1017
/*--------------------------------------------------------------------
1018
 */
1019
1020
stream_close_t
1021 11808
http_DoConnection(struct http *hp, stream_close_t sc_close)
1022
{
1023
        const char *h, *b, *e;
1024
        stream_close_t retval;
1025
        unsigned u, v;
1026
        struct http_hdrflg *f;
1027
1028 11808
        CHECK_OBJ_NOTNULL(hp, HTTP_MAGIC);
1029 11808
        assert(sc_close == SC_REQ_CLOSE || sc_close == SC_RESP_CLOSE);
1030
1031 11808
        if (hp->protover == 10)
1032 78
                retval = SC_REQ_HTTP10;
1033
        else
1034 11730
                retval = SC_NULL;
1035
1036 11808
        http_CollectHdr(hp, H_Connection);
1037 11808
        if (!http_GetHdr(hp, H_Connection, &h))
1038 11453
                return (retval);
1039 355
        AN(h);
1040 710
        while (http_split(&h, NULL, ",", &b, &e)) {
1041 361
                u = pdiff(b, e);
1042 361
                if (u == 5 && http_hdr_at(b, "close", u))
1043 291
                        retval = sc_close;
1044 361
                if (u == 10 && http_hdr_at(b, "keep-alive", u))
1045 46
                        retval = SC_NULL;
1046
1047
                /* Refuse removal of well-known-headers if they would pass. */
1048 361
                f = http_hdr_flags(b, e);
1049 361
                if (f != NULL && !(f->flag & HTTPH_R_PASS))
1050 6
                        return (SC_RX_BAD);
1051
1052 1723
                for (v = HTTP_HDR_FIRST; v < hp->nhd; v++) {
1053 1368
                        Tcheck(hp->hd[v]);
1054 1368
                        if (hp->hd[v].e < hp->hd[v].b + u + 1)
1055 62
                                continue;
1056 1306
                        if (hp->hd[v].b[u] != ':')
1057 1206
                                continue;
1058 100
                        if (!http_hdr_at(b, hp->hd[v].b, u))
1059 76
                                continue;
1060 24
                        hp->hdf[v] |= HDF_FILTER;
1061 24
                }
1062
        }
1063 349
        CHECK_OBJ_NOTNULL(retval, STREAM_CLOSE_MAGIC);
1064 349
        return (retval);
1065 11808
}
1066
1067
/*--------------------------------------------------------------------*/
1068
1069
int
1070 23232
http_HdrIs(const struct http *hp, hdr_t hdr, const char *val)
1071
{
1072
        const char *p;
1073
1074 23232
        if (!http_GetHdr(hp, hdr, &p))
1075 22045
                return (0);
1076 1187
        AN(p);
1077 1187
        if (http_tok_eq(p, val))
1078 1135
                return (1);
1079 52
        return (0);
1080 23232
}
1081
1082
/*--------------------------------------------------------------------*/
1083
1084
uint16_t
1085 29048
http_GetStatus(const struct http *hp)
1086
{
1087
1088 29048
        CHECK_OBJ_NOTNULL(hp, HTTP_MAGIC);
1089 29048
        return (hp->status);
1090
}
1091
1092
int
1093 20126
http_IsStatus(const struct http *hp, int val)
1094
{
1095
1096 20126
        CHECK_OBJ_NOTNULL(hp, HTTP_MAGIC);
1097 20126
        assert(val >= 100 && val <= 999);
1098 20126
        return (val == (hp->status % 1000));
1099
}
1100
1101
/*--------------------------------------------------------------------
1102
 * Setting the status will also set the Reason appropriately
1103
 */
1104
1105
void
1106 2282
http_SetStatus(struct http *to, uint16_t status, const char *reason)
1107
{
1108
        char buf[4];
1109 2282
        const char *sstr = NULL;
1110
1111 2282
        CHECK_OBJ_NOTNULL(to, HTTP_MAGIC);
1112
        /*
1113
         * We allow people to use top digits for internal VCL
1114
         * signalling, but strip them from the ASCII version.
1115
         */
1116 2282
        to->status = status;
1117 2282
        status %= 1000;
1118 2282
        assert(status >= 100);
1119
1120 2282
        if (reason == NULL)
1121 466
                reason = http_Status2Reason(status, &sstr);
1122
        else
1123 1816
                (void)http_Status2Reason(status, &sstr);
1124
1125 2282
        if (sstr) {
1126 2210
                http_SetH(to, HTTP_HDR_STATUS, sstr);
1127 2210
        } else {
1128 72
                bprintf(buf, "%03d", status);
1129 72
                http_PutField(to, HTTP_HDR_STATUS, buf);
1130
        }
1131 2282
        http_SetH(to, HTTP_HDR_REASON, reason);
1132 2282
}
1133
1134
/*--------------------------------------------------------------------*/
1135
1136
const char *
1137 10603
http_GetMethod(const struct http *hp)
1138
{
1139
1140 10603
        CHECK_OBJ_NOTNULL(hp, HTTP_MAGIC);
1141 10603
        Tcheck(hp->hd[HTTP_HDR_METHOD]);
1142 10603
        return (hp->hd[HTTP_HDR_METHOD].b);
1143
}
1144
1145
/*--------------------------------------------------------------------
1146
 * Force a particular header field to a particular value
1147
 */
1148
1149
void
1150 15593
http_ForceField(struct http *to, unsigned n, const char *t)
1151
{
1152
        int i;
1153
1154 15593
        CHECK_OBJ_NOTNULL(to, HTTP_MAGIC);
1155 15593
        assert(n < HTTP_HDR_FIRST);
1156 15593
        assert(n == HTTP_HDR_METHOD || n == HTTP_HDR_PROTO);
1157 15593
        AN(t);
1158
1159
        /* NB: method names and protocol versions are case-sensitive. */
1160 15593
        if (to->hd[n].b == NULL || strcmp(to->hd[n].b, t)) {
1161 240
                i = (HTTP_HDR_UNSET - HTTP_HDR_METHOD);
1162 240
                i += to->logtag;
1163
                /* XXX: this is a dead branch */
1164 240
                if (n >= HTTP_HDR_FIRST)
1165 0
                        VSLbt(to->vsl, (enum VSL_tag_e)i, to->hd[n]);
1166 240
                http_SetH(to, n, t);
1167 240
        }
1168 15593
}
1169
1170
/*--------------------------------------------------------------------*/
1171
1172
void
1173 2082
http_PutResponse(struct http *to, const char *proto, uint16_t status,
1174
    const char *reason)
1175
{
1176
1177 2082
        CHECK_OBJ_NOTNULL(to, HTTP_MAGIC);
1178 2082
        if (proto != NULL)
1179 2082
                http_SetH(to, HTTP_HDR_PROTO, proto);
1180 2082
        http_SetStatus(to, status, reason);
1181 2082
}
1182
1183
/*--------------------------------------------------------------------
1184
 * check if header is filtered by the dynamic marker or the static
1185
 * definitions in http_headers.h
1186
 */
1187
1188
static inline int
1189 80459
http_isfiltered(const struct http *fm, unsigned u, unsigned how)
1190
{
1191
        const char *e;
1192
        const struct http_hdrflg *f;
1193
1194 80459
        if (fm->hdf[u] & HDF_FILTER)
1195 34
                return (1);
1196 80425
        if (u < HTTP_HDR_FIRST)
1197 26958
                return (0);
1198 53467
        e = strchr(fm->hd[u].b, ':');
1199 53467
        if (e == NULL)
1200 0
                return (0);
1201 53467
        f = http_hdr_flags(fm->hd[u].b, e);
1202 53467
        return (f != NULL && f->flag & how);
1203 80459
}
1204
1205
int
1206 1679
http_IsFiltered(const struct http *fm, unsigned u, unsigned how)
1207
{
1208
1209 1679
        return (http_isfiltered(fm, u, how));
1210
}
1211
1212
/*--------------------------------------------------------------------
1213
 * Estimate how much workspace we need to Filter this header according
1214
 * to 'how'.
1215
 */
1216
1217
unsigned
1218 4500
http_EstimateWS(const struct http *fm, unsigned how)
1219
{
1220
        unsigned u, l;
1221
1222 4500
        l = 4;
1223 4500
        CHECK_OBJ_NOTNULL(fm, HTTP_MAGIC);
1224 43056
        for (u = 0; u < fm->nhd; u++) {
1225 38556
                if (u == HTTP_HDR_METHOD || u == HTTP_HDR_URL)
1226 9000
                        continue;
1227 29556
                Tcheck(fm->hd[u]);
1228 29556
                if (http_isfiltered(fm, u, how))
1229 527
                        continue;
1230 29029
                l += Tlen(fm->hd[u]) + 1L;
1231 29029
        }
1232 4500
        return (PRNDUP(l + 1L));
1233
}
1234
1235
/*--------------------------------------------------------------------
1236
 * Encode http struct as byte string.
1237
 *
1238
 * XXX: We could save considerable special-casing below by encoding also
1239
 * XXX: H__Status, H__Reason and H__Proto into the string, but it would
1240
 * XXX: add 26-30 bytes to all encoded objects to save a little code.
1241
 * XXX: It could possibly be a good idea for later HTTP versions.
1242
 */
1243
1244
void
1245 4488
HTTP_Encode(const struct http *fm, uint8_t *p0, unsigned l, unsigned how)
1246
{
1247
        unsigned u, w;
1248
        uint16_t n;
1249
        uint8_t *p, *e;
1250
1251 4488
        AN(p0);
1252 4488
        AN(l);
1253 4488
        p = p0;
1254 4488
        e = p + l;
1255 4488
        assert(p + 5 <= e);
1256 4488
        assert(fm->nhd <= fm->shd);
1257 4488
        n = HTTP_HDR_FIRST - 3;
1258 4488
        vbe16enc(p + 2, fm->status);
1259 4488
        p += 4;
1260 4488
        CHECK_OBJ_NOTNULL(fm, HTTP_MAGIC);
1261 42929
        for (u = 0; u < fm->nhd; u++) {
1262 38441
                if (u == HTTP_HDR_METHOD || u == HTTP_HDR_URL)
1263 8976
                        continue;
1264 29465
                Tcheck(fm->hd[u]);
1265 29465
                if (http_isfiltered(fm, u, how))
1266 527
                        continue;
1267 28938
                http_VSLH(fm, u);
1268 28938
                w = Tlen(fm->hd[u]) + 1L;
1269 28938
                assert(p + w + 1 <= e);
1270 28938
                memcpy(p, fm->hd[u].b, w);
1271 28938
                p += w;
1272 28938
                n++;
1273 28938
        }
1274 4488
        *p++ = '\0';
1275 4488
        assert(p <= e);
1276 4488
        vbe16enc(p0, n + 1);
1277 4488
}
1278
1279
/*--------------------------------------------------------------------
1280
 * Decode byte string into http struct
1281
 */
1282
1283
int
1284 6611
HTTP_Decode(struct http *to, const uint8_t *fm)
1285
{
1286
1287 6611
        CHECK_OBJ_NOTNULL(to, HTTP_MAGIC);
1288 6611
        AN(to->vsl);
1289 6611
        AN(fm);
1290 6611
        if (vbe16dec(fm) <= to->shd) {
1291 6607
                to->status = vbe16dec(fm + 2);
1292 6607
                fm += 4;
1293 62663
                for (to->nhd = 0; to->nhd < to->shd; to->nhd++) {
1294 62663
                        if (to->nhd == HTTP_HDR_METHOD ||
1295 56052
                            to->nhd == HTTP_HDR_URL) {
1296 13210
                                to->hd[to->nhd].b = NULL;
1297 13210
                                to->hd[to->nhd].e = NULL;
1298 13210
                                continue;
1299
                        }
1300 49453
                        if (*fm == '\0')
1301 6607
                                return (0);
1302 42846
                        to->hd[to->nhd].b = (const void*)fm;
1303 42846
                        fm = (const void*)strchr((const void*)fm, '\0');
1304 42846
                        to->hd[to->nhd].e = (const void*)fm;
1305 42846
                        fm++;
1306 42846
                        http_VSLH(to, to->nhd);
1307 42846
                }
1308 0
        }
1309 8
        VSLb(to->vsl, SLT_Error,
1310
            "Too many headers to Decode object (%u vs. %u)",
1311 4
            vbe16dec(fm), to->shd);
1312 4
        return (-1);
1313 6611
}
1314
1315
/*--------------------------------------------------------------------*/
1316
1317
uint16_t
1318 66
HTTP_GetStatusPack(struct worker *wrk, struct objcore *oc)
1319
{
1320
        const char *ptr;
1321 66
        ptr = ObjGetAttr(wrk, oc, OA_HEADERS, NULL);
1322 66
        AN(ptr);
1323
1324 66
        return (vbe16dec(ptr + 2));
1325
}
1326
1327
/*--------------------------------------------------------------------*/
1328
1329
/* Get the first packed header */
1330
int
1331 1773
HTTP_IterHdrPack(struct worker *wrk, struct objcore *oc, const char **p)
1332
{
1333
        const char *ptr;
1334
1335 1773
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
1336 1773
        CHECK_OBJ_NOTNULL(oc, OBJCORE_MAGIC);
1337 1773
        AN(p);
1338
1339 1773
        if (*p == NULL) {
1340 544
                ptr = ObjGetAttr(wrk, oc, OA_HEADERS, NULL);
1341 544
                AN(ptr);
1342 544
                ptr += 4;       /* Skip nhd and status */
1343 544
                ptr = strchr(ptr, '\0') + 1;    /* Skip :proto: */
1344 544
                ptr = strchr(ptr, '\0') + 1;    /* Skip :status: */
1345 544
                ptr = strchr(ptr, '\0') + 1;    /* Skip :reason: */
1346 544
                *p = ptr;
1347 544
        } else {
1348 1229
                *p = strchr(*p, '\0') + 1;      /* Skip to next header */
1349
        }
1350 1773
        if (**p == '\0')
1351 117
                return (0);
1352 1656
        return (1);
1353 1773
}
1354
1355
const char *
1356 580
HTTP_GetHdrPack(struct worker *wrk, struct objcore *oc, hdr_t hdr)
1357
{
1358
        const char *ptr;
1359
1360 580
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
1361 580
        CHECK_OBJ_NOTNULL(oc, OBJCORE_MAGIC);
1362 580
        CHECK_HDR(hdr);
1363
1364 580
        if (hdr->str[0] == ':') {
1365
                /* Special cases */
1366 36
                ptr = ObjGetAttr(wrk, oc, OA_HEADERS, NULL);
1367 36
                AN(ptr);
1368 36
                ptr += 4;       /* Skip nhd and status */
1369
1370
                /* XXX: should we also have h2_hdr_eq() ? */
1371 36
                if (!strcmp(hdr->str, ":proto:"))
1372 4
                        return (ptr);
1373 32
                ptr = strchr(ptr, '\0') + 1;
1374 32
                if (!strcmp(hdr->str, ":status:"))
1375 28
                        return (ptr);
1376 4
                ptr = strchr(ptr, '\0') + 1;
1377 4
                if (!strcmp(hdr->str, ":reason:"))
1378 4
                        return (ptr);
1379 0
                WRONG("Unknown magic packed header");
1380 0
        }
1381
1382 1773
        HTTP_FOREACH_PACK(wrk, oc, ptr) {
1383 1656
                if (http_hdr_at(ptr, hdr->str, hdr->len)) {
1384 427
                        ptr += hdr->len;
1385 852
                        while (vct_islws(*ptr))
1386 425
                                ptr++;
1387 427
                        return (ptr);
1388
                }
1389
        }
1390
1391 117
        return (NULL);
1392 580
}
1393
1394
/*--------------------------------------------------------------------
1395
 * Merge any headers in the oc->OA_HEADER into the struct http if they
1396
 * are not there already.
1397
 */
1398
1399
void
1400 60
HTTP_Merge(struct worker *wrk, struct objcore *oc, struct http *to)
1401
{
1402
        const char *ptr;
1403
        unsigned u;
1404
        const char *p;
1405
        unsigned nhd_before_merge;
1406
1407 60
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
1408 60
        CHECK_OBJ_NOTNULL(oc, OBJCORE_MAGIC);
1409 60
        CHECK_OBJ_NOTNULL(to, HTTP_MAGIC);
1410
1411 60
        ptr = ObjGetAttr(wrk, oc, OA_HEADERS, NULL);
1412 60
        AN(ptr);
1413
1414 60
        to->status = vbe16dec(ptr + 2);
1415 60
        ptr += 4;
1416
1417 360
        for (u = 0; u < HTTP_HDR_FIRST; u++) {
1418 300
                if (u == HTTP_HDR_METHOD || u == HTTP_HDR_URL)
1419 120
                        continue;
1420 180
                http_SetH(to, u, ptr);
1421 180
                ptr = strchr(ptr, '\0') + 1;
1422 180
        }
1423 60
        nhd_before_merge = to->nhd;
1424 360
        while (*ptr != '\0') {
1425 300
                p = strchr(ptr, ':');
1426 300
                AN(p);
1427 300
                u = http_findhdr(to, p - ptr, ptr);
1428 300
                if (u == 0 || u >= nhd_before_merge)
1429 142
                        http_SetHeader(to, ptr);
1430 300
                ptr = strchr(ptr, '\0') + 1;
1431
        }
1432 60
}
1433
1434
/*--------------------------------------------------------------------*/
1435
1436
static void
1437 13817
http_linkh(const struct http *to, const struct http *fm, unsigned n)
1438
{
1439
1440 13817
        assert(n < HTTP_HDR_FIRST);
1441 13817
        Tcheck(fm->hd[n]);
1442 13817
        to->hd[n] = fm->hd[n];
1443 13817
        to->hdf[n] = fm->hdf[n];
1444 13817
        http_VSLH(to, n);
1445 13817
}
1446
1447
/*--------------------------------------------------------------------*/
1448
1449
void
1450 4606
http_FilterReq(struct http *to, const struct http *fm, unsigned how)
1451
{
1452
        unsigned u;
1453
1454 4606
        CHECK_OBJ_NOTNULL(to, HTTP_MAGIC);
1455 4606
        CHECK_OBJ_NOTNULL(fm, HTTP_MAGIC);
1456
1457 4606
        http_linkh(to, fm, HTTP_HDR_METHOD);
1458 4606
        http_linkh(to, fm, HTTP_HDR_URL);
1459 4606
        http_linkh(to, fm, HTTP_HDR_PROTO);
1460 4606
        to->protover = fm->protover;
1461 4606
        to->status = fm->status;
1462
1463 4606
        to->nhd = HTTP_HDR_FIRST;
1464 24365
        for (u = HTTP_HDR_FIRST; u < fm->nhd; u++) {
1465 19759
                Tcheck(fm->hd[u]);
1466 19759
                if (http_isfiltered(fm, u, how))
1467 230
                        continue;
1468 19529
                assert (to->nhd < to->shd);
1469 19529
                to->hd[to->nhd] = fm->hd[u];
1470 19529
                to->hdf[to->nhd] = 0;
1471 19529
                http_VSLH(to, to->nhd);
1472 19529
                to->nhd++;
1473 19529
        }
1474 4606
}
1475
1476
/*--------------------------------------------------------------------
1477
 * This function copies any header fields which reference foreign
1478
 * storage into our own WS.
1479
 */
1480
1481
void
1482 4546
http_CopyHome(const struct http *hp)
1483
{
1484
        unsigned u, l;
1485
        const char *p;
1486
1487 49413
        for (u = 0; u < hp->nhd; u++) {
1488 44867
                if (hp->hd[u].b == NULL) {
1489 9092
                        assert(u < HTTP_HDR_FIRST);
1490 9092
                        continue;
1491
                }
1492
1493 35775
                l = Tlen(hp->hd[u]);
1494 35775
                if (WS_Allocated(hp->ws, hp->hd[u].b, l))
1495 2885
                        continue;
1496
1497 32890
                p = WS_Copy(hp->ws, hp->hd[u].b, l + 1L);
1498 32890
                if (p == NULL) {
1499 0
                        http_fail(hp);
1500 0
                        VSLbs(hp->vsl, SLT_LostHeader, TOSTRAND(hp->hd[u].b));
1501 0
                        return;
1502
                }
1503 32890
                hp->hd[u].b = p;
1504 32890
                hp->hd[u].e = p + l;
1505 32890
        }
1506 4546
}
1507
1508
/*--------------------------------------------------------------------*/
1509
1510
void
1511 19017
http_SetHeader(struct http *to, const char *header)
1512
{
1513
1514 19017
        CHECK_OBJ_NOTNULL(to, HTTP_MAGIC);
1515 19017
        if (to->nhd >= to->shd) {
1516 2
                VSLbs(to->vsl, SLT_LostHeader, TOSTRAND(header));
1517 2
                http_fail(to);
1518 2
                return;
1519
        }
1520 19015
        http_SetH(to, to->nhd++, header);
1521 19017
}
1522
1523
/*--------------------------------------------------------------------*/
1524
1525
void
1526 8478
http_ForceHeader(struct http *to, hdr_t hdr, const char *val)
1527
{
1528
1529 8478
        CHECK_OBJ_NOTNULL(to, HTTP_MAGIC);
1530 8478
        if (http_HdrIs(to, hdr, val))
1531 773
                return;
1532 7705
        http_Unset(to, hdr);
1533 7705
        http_PrintfHeader(to, "%s %s", hdr->str, val);
1534 8478
}
1535
1536
void
1537 21649
http_AppendHeader(struct http *to, hdr_t hdr, const char *val)
1538
{
1539
        const char *old;
1540
1541 21649
        http_CollectHdr(to, hdr);
1542 21649
        if (http_GetHdr(to, hdr, &old)) {
1543 96
                http_Unset(to, hdr);
1544 96
                http_PrintfHeader(to, "%s %s, %s", hdr->str, old, val);
1545 96
        } else {
1546 21553
                http_PrintfHeader(to, "%s %s", hdr->str, val);
1547
        }
1548 21649
}
1549
1550
void
1551 50922
http_PrintfHeader(struct http *to, const char *fmt, ...)
1552
{
1553
        va_list ap, ap2;
1554
        struct vsb vsb[1];
1555
        size_t sz;
1556
        char *p;
1557
1558 50922
        CHECK_OBJ_NOTNULL(to, HTTP_MAGIC);
1559
1560 50922
        va_start(ap, fmt);
1561 50922
        va_copy(ap2, ap);
1562
1563 50922
        WS_VSB_new(vsb, to->ws);
1564 50922
        VSB_vprintf(vsb, fmt, ap);
1565 50922
        p = WS_VSB_finish(vsb, to->ws, &sz);
1566
1567 50922
        if (p == NULL || to->nhd >= to->shd) {
1568 53
                http_fail(to);
1569 53
                VSLbv(to->vsl, SLT_LostHeader, fmt, ap2);
1570 53
        } else {
1571 50869
                http_SetH(to, to->nhd++, p);
1572
        }
1573 50922
        va_end(ap);
1574 50922
        va_end(ap2);
1575 50922
}
1576
1577
void
1578 2098
http_TimeHeader(struct http *to, const char *fmt, vtim_real now)
1579
{
1580
        char *p;
1581
1582 2098
        CHECK_OBJ_NOTNULL(to, HTTP_MAGIC);
1583 2098
        if (to->nhd >= to->shd) {
1584 0
                VSLbs(to->vsl, SLT_LostHeader, TOSTRAND(fmt));
1585 0
                http_fail(to);
1586 0
                return;
1587
        }
1588 2098
        p = WS_Alloc(to->ws, strlen(fmt) + VTIM_FORMAT_SIZE);
1589 2098
        if (p == NULL) {
1590 154
                http_fail(to);
1591 154
                VSLbs(to->vsl, SLT_LostHeader, TOSTRAND(fmt));
1592 154
                return;
1593
        }
1594 1944
        strcpy(p, fmt);
1595 1944
        VTIM_format(now, strchr(p, '\0'));
1596 1944
        http_SetH(to, to->nhd++, p);
1597 2098
}
1598
1599
const char *
1600 14129
http_ViaHeader(void)
1601
{
1602
1603 14129
        return (via_hdr);
1604
}
1605
1606
/*--------------------------------------------------------------------*/
1607
1608
void
1609 46329
http_Unset(struct http *hp, hdr_t hdr)
1610
{
1611
        uint16_t u, v;
1612
1613 301106
        for (v = u = HTTP_HDR_FIRST; u < hp->nhd; u++) {
1614 254777
                Tcheck(hp->hd[u]);
1615 254777
                if (http_IsHdr(&hp->hd[u], hdr)) {
1616 2066
                        http_VSLH_del(hp, u);
1617 2066
                        continue;
1618
                }
1619 252711
                if (v != u) {
1620 5914
                        memcpy(&hp->hd[v], &hp->hd[u], sizeof *hp->hd);
1621 5914
                        memcpy(&hp->hdf[v], &hp->hdf[u], sizeof *hp->hdf);
1622 5914
                }
1623 252711
                v++;
1624 252711
        }
1625 46329
        hp->nhd = v;
1626 46329
}