varnish-cache/bin/varnishd/cache/cache_http.c
1
/*-
2
 * Copyright (c) 2006 Verdens Gang AS
3
 * Copyright (c) 2006-2017 Varnish Software AS
4
 * All rights reserved.
5
 *
6
 * Author: Poul-Henning Kamp <phk@phk.freebsd.dk>
7
 *
8
 * Redistribution and use in source and binary forms, with or without
9
 * modification, are permitted provided that the following conditions
10
 * are met:
11
 * 1. Redistributions of source code must retain the above copyright
12
 *    notice, this list of conditions and the following disclaimer.
13
 * 2. Redistributions in binary form must reproduce the above copyright
14
 *    notice, this list of conditions and the following disclaimer in the
15
 *    documentation and/or other materials provided with the distribution.
16
 *
17
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20
 * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
21
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27
 * SUCH DAMAGE.
28
 *
29
 * HTTP request storage and manipulation
30
 */
31
32
#include "config.h"
33
34
#include "cache_varnishd.h"
35
#include <stdio.h>
36
37
#include "vend.h"
38
#include "vct.h"
39
#include "vtim.h"
40
41
#define HTTPH(a, b, c) char b[] = "*" a ":";
42
#include "tbl/http_headers.h"
43
44
const char H__Status[]  = "\010:status:";
45
const char H__Proto[]   = "\007:proto:";
46
const char H__Reason[]  = "\010:reason:";
47
48
/*--------------------------------------------------------------------
49
 * These two functions are in an incestous relationship with the
50
 * order of macros in include/tbl/vsl_tags_http.h
51
 *
52
 * The http->logtag is the SLT_*Method enum, and we add to that, to
53
 * get the SLT_ to use.
54
 */
55
56
static void
57 143669
http_VSLH(const struct http *hp, unsigned hdr)
58
{
59
        int i;
60
61 143669
        if (hp->vsl != NULL) {
62 143669
                AN(hp->vsl->wid & (VSL_CLIENTMARKER|VSL_BACKENDMARKER));
63 143669
                i = hdr;
64 143669
                if (i > HTTP_HDR_FIRST)
65 62664
                        i = HTTP_HDR_FIRST;
66 143669
                i += hp->logtag;
67 143669
                VSLbt(hp->vsl, (enum VSL_tag_e)i, hp->hd[hdr]);
68
        }
69 143668
}
70
71
static void
72 1000
http_VSLH_del(const struct http *hp, unsigned hdr)
73
{
74
        int i;
75
76 1000
        if (hp->vsl != NULL) {
77
                /* We don't support unsetting stuff in the first line */
78 1000
                assert (hdr >= HTTP_HDR_FIRST);
79 1000
                AN(hp->vsl->wid & (VSL_CLIENTMARKER|VSL_BACKENDMARKER));
80 1000
                i = (HTTP_HDR_UNSET - HTTP_HDR_METHOD);
81 1000
                i += hp->logtag;
82 1000
                VSLbt(hp->vsl, (enum VSL_tag_e)i, hp->hd[hdr]);
83
        }
84 1000
}
85
86
/*--------------------------------------------------------------------*/
87
88
void
89 7994
http_VSL_log(const struct http *hp)
90
{
91
        unsigned u;
92
93 58833
        for (u = 0; u < hp->nhd; u++)
94 50839
                if (hp->hd[u].b != NULL)
95 34853
                        http_VSLH(hp, u);
96 7994
}
97
98
/*--------------------------------------------------------------------*/
99
100
static void
101 132
http_fail(const struct http *hp)
102
{
103
104 132
        VSC_C_main->losthdr++;
105 132
        VSLb(hp->vsl, SLT_Error, "out of workspace (%s)", hp->ws->id);
106 132
        WS_MarkOverflow(hp->ws);
107 132
}
108
109
/*--------------------------------------------------------------------*/
110
/* List of canonical HTTP response code names from RFC2616 */
111
112
static struct http_msg {
113
        unsigned        nbr;
114
        const char      *status;
115
        const char      *txt;
116
} http_msg[] = {
117
#define HTTP_RESP(n, t) { n, #n, t},
118
#include "tbl/http_response.h"
119
        { 0, "0", NULL }
120
};
121
122
const char *
123 1236
http_Status2Reason(unsigned status, const char **sstr)
124
{
125
        struct http_msg *mp;
126
127 1236
        status %= 1000;
128 1236
        assert(status >= 100);
129 30346
        for (mp = http_msg; mp->nbr != 0 && mp->nbr <= status; mp++)
130 30278
                if (mp->nbr == status) {
131 1168
                        if (sstr)
132 918
                                *sstr = mp->status;
133 1168
                        return (mp->txt);
134
                }
135 68
        return ("Unknown HTTP Status");
136
}
137
138
/*--------------------------------------------------------------------*/
139
140
unsigned
141 7210
HTTP_estimate(unsigned nhttp)
142
{
143
144
        /* XXX: We trust the structs to size-aligned as necessary */
145 7210
        return (PRNDUP(sizeof (struct http) + sizeof(txt) * nhttp + nhttp));
146
}
147
148
struct http *
149 21646
HTTP_create(void *p, uint16_t nhttp, unsigned len)
150
{
151
        struct http *hp;
152
153 21646
        hp = p;
154 21646
        hp->magic = HTTP_MAGIC;
155 21646
        hp->hd = (void*)(hp + 1);
156 21646
        hp->shd = nhttp;
157 21646
        hp->hdf = (void*)(hp->hd + nhttp);
158 21646
        assert((unsigned char*)p + len == hp->hdf + PRNDUP(nhttp));
159 21646
        return (hp);
160
}
161
162
/*--------------------------------------------------------------------*/
163
164
void
165 19490
HTTP_Setup(struct http *hp, struct ws *ws, struct vsl_log *vsl,
166
    enum VSL_tag_e  whence)
167
{
168 19490
        http_Teardown(hp);
169 19491
        hp->nhd = HTTP_HDR_FIRST;
170 19491
        hp->logtag = whence;
171 19491
        hp->ws = ws;
172 19491
        hp->vsl = vsl;
173 19491
}
174
175
/*--------------------------------------------------------------------
176
 * http_Teardown() is a safety feature, we use it to zap all http
177
 * structs once we're done with them, to minimize the risk that
178
 * old stale pointers exist to no longer valid stuff.
179
 */
180
181
void
182 30943
http_Teardown(struct http *hp)
183
{
184
185 30943
        CHECK_OBJ_NOTNULL(hp, HTTP_MAGIC);
186 30943
        AN(hp->shd);
187 30943
        memset(&hp->nhd, 0, sizeof *hp - offsetof(struct http, nhd));
188 30943
        memset(hp->hd, 0, sizeof *hp->hd * hp->shd);
189 30943
        memset(hp->hdf, 0, sizeof *hp->hdf * hp->shd);
190 30943
}
191
192
/*--------------------------------------------------------------------*/
193
194
void
195 8722
HTTP_Copy(struct http *to, const struct http * const fm)
196
{
197
198 8722
        assert(fm->nhd <= to->shd);
199 8722
        memcpy(&to->nhd, &fm->nhd, sizeof *to - offsetof(struct http, nhd));
200 8722
        memcpy(to->hd, fm->hd, fm->nhd * sizeof *to->hd);
201 8722
        memcpy(to->hdf, fm->hdf, fm->nhd * sizeof *to->hdf);
202 8722
        to->protover = fm->protover;
203 8722
}
204
205
/*--------------------------------------------------------------------*/
206
207
void
208 8617
http_Proto(struct http *to)
209
{
210
        const char *fm;
211
212 8617
        fm = to->hd[HTTP_HDR_PROTO].b;
213
214 17230
        if ((fm[0] == 'H' || fm[0] == 'h') &&
215 17226
            (fm[1] == 'T' || fm[1] == 't') &&
216 17226
            (fm[2] == 'T' || fm[2] == 't') &&
217 17226
            (fm[3] == 'P' || fm[3] == 'p') &&
218 17226
            fm[4] == '/' &&
219 17226
            vct_isdigit(fm[5]) &&
220 17226
            fm[6] == '.' &&
221 17226
            vct_isdigit(fm[7]) &&
222 8613
            fm[8] == '\0') {
223 8613
                to->protover = 10 * (fm[5] - '0') + (fm[7] - '0');
224
        } else {
225 4
                to->protover = 0;
226
        }
227 8617
}
228
229
/*--------------------------------------------------------------------*/
230
231
void
232 20067
http_SetH(struct http *to, unsigned n, const char *fm)
233
{
234
235 20067
        assert(n < to->nhd);
236 20067
        AN(fm);
237 20067
        to->hd[n].b = TRUST_ME(fm);
238 20067
        to->hd[n].e = strchr(to->hd[n].b, '\0');
239 20067
        to->hdf[n] = 0;
240 20067
        http_VSLH(to, n);
241 20067
        if (n == HTTP_HDR_PROTO)
242 1230
                http_Proto(to);
243 20067
}
244
245
/*--------------------------------------------------------------------*/
246
247
static void
248 60
http_PutField(struct http *to, int field, const char *string)
249
{
250
        char *p;
251
252 60
        CHECK_OBJ_NOTNULL(to, HTTP_MAGIC);
253 60
        p = WS_Copy(to->ws, string, -1);
254 60
        if (p == NULL) {
255 2
                http_fail(to);
256 2
                VSLb(to->vsl, SLT_LostHeader, "%s", string);
257 2
                return;
258
        }
259 58
        to->hd[field].b = p;
260 58
        to->hd[field].e = strchr(p, '\0');
261 58
        to->hdf[field] = 0;
262 58
        http_VSLH(to, field);
263 58
        if (field == HTTP_HDR_PROTO)
264 0
                http_Proto(to);
265
}
266
267
/*--------------------------------------------------------------------*/
268
269
static int
270 610245
http_IsHdr(const txt *hh, const char *hdr)
271
{
272
        unsigned l;
273
274 610245
        Tcheck(*hh);
275 610245
        AN(hdr);
276 610245
        l = hdr[0];
277 610245
        assert(l == strlen(hdr + 1));
278 610245
        assert(hdr[l] == ':');
279 610245
        hdr++;
280 610245
        return (!strncasecmp(hdr, hh->b, l));
281
}
282
283
/*--------------------------------------------------------------------*/
284
285
static unsigned
286 159458
http_findhdr(const struct http *hp, unsigned l, const char *hdr)
287
{
288
        unsigned u;
289
290 498041
        for (u = HTTP_HDR_FIRST; u < hp->nhd; u++) {
291 374137
                Tcheck(hp->hd[u]);
292 374155
                if (hp->hd[u].e < hp->hd[u].b + l + 1)
293 46342
                        continue;
294 327813
                if (hp->hd[u].b[l] != ':')
295 267064
                        continue;
296 60749
                if (strncasecmp(hdr, hp->hd[u].b, l))
297 25177
                        continue;
298 35572
                return (u);
299
        }
300 123904
        return (0);
301
}
302
303
/*--------------------------------------------------------------------
304
 * Count how many instances we have of this header
305
 */
306
307
unsigned
308 8434
http_CountHdr(const struct http *hp, const char *hdr)
309
{
310 8434
        unsigned retval = 0;
311
        unsigned u;
312
313 8434
        CHECK_OBJ_NOTNULL(hp, HTTP_MAGIC);
314
315 19462
        for (u = HTTP_HDR_FIRST; u < hp->nhd; u++) {
316 11028
                Tcheck(hp->hd[u]);
317 11028
                if (http_IsHdr(&hp->hd[u], hdr))
318 4268
                        retval++;
319
        }
320 8434
        return (retval);
321
}
322
323
/*--------------------------------------------------------------------
324
 * This function collapses multiple headerlines of the same name.
325
 * The lines are joined with a comma, according to [rfc2616, 4.2bot, p32]
326
 */
327
328
void
329 23113
http_CollectHdr(struct http *hp, const char *hdr)
330
{
331
332 23113
        http_CollectHdrSep(hp, hdr, NULL);
333 23113
}
334
335
/*--------------------------------------------------------------------
336
 * You may prefer to collapse header fields using a different separator.
337
 * For Cookie headers, the separator is "; " for example. That's probably
338
 * the only example too.
339
 */
340
341
void
342 23243
http_CollectHdrSep(struct http *hp, const char *hdr, const char *sep)
343
{
344
        unsigned u, l, lsep, ml, f, x, d;
345 23243
        char *b = NULL, *e = NULL;
346
        const char *v;
347
348 23243
        CHECK_OBJ_NOTNULL(hp, HTTP_MAGIC);
349 23243
        if (WS_Overflowed(hp->ws))
350 48
                return;
351
352 23195
        if (sep == NULL || *sep == '\0')
353 23064
                sep = ", ";
354 23195
        lsep = strlen(sep);
355
356 23195
        l = hdr[0];
357 23195
        assert(l == strlen(hdr + 1));
358 23195
        assert(hdr[l] == ':');
359 23195
        f = http_findhdr(hp, l - 1, hdr + 1);
360 23195
        if (f == 0)
361 22678
                return;
362
363 1418
        for (d = u = f + 1; u < hp->nhd; u++) {
364 901
                Tcheck(hp->hd[u]);
365 901
                if (!http_IsHdr(&hp->hd[u], hdr)) {
366 869
                        if (d != u) {
367 92
                                hp->hd[d] = hp->hd[u];
368 92
                                hp->hdf[d] = hp->hdf[u];
369
                        }
370 869
                        d++;
371 869
                        continue;
372
                }
373 32
                if (b == NULL) {
374
                        /* Found second header, start our collection */
375 28
                        ml = WS_Reserve(hp->ws, 0);
376 28
                        b = hp->ws->f;
377 28
                        e = b + ml;
378 28
                        x = Tlen(hp->hd[f]);
379 28
                        if (b + x >= e) {
380 0
                                http_fail(hp);
381 0
                                VSLb(hp->vsl, SLT_LostHeader, "%s", hdr + 1);
382 0
                                WS_MarkOverflow(hp->ws);
383 0
                                WS_Release(hp->ws, 0);
384 0
                                return;
385
                        }
386 28
                        memcpy(b, hp->hd[f].b, x);
387 28
                        b += x;
388
                }
389
390 32
                AN(b);
391 32
                AN(e);
392
393
                /* Append the Nth header we found */
394 32
                x = Tlen(hp->hd[u]) - l;
395
396 32
                v = hp->hd[u].b + *hdr;
397 96
                while (vct_issp(*v)) {
398 32
                        v++;
399 32
                        x--;
400
                }
401
402 32
                if (b + lsep + x >= e) {
403 0
                        http_fail(hp);
404 0
                        VSLb(hp->vsl, SLT_LostHeader, "%s", hdr + 1);
405 0
                        WS_Release(hp->ws, 0);
406 0
                        return;
407
                }
408 32
                memcpy(b, sep, lsep);
409 32
                b += lsep;
410 32
                memcpy(b, v, x);
411 32
                b += x;
412
        }
413 517
        if (b == NULL)
414 489
                return;
415 28
        hp->nhd = (uint16_t)d;
416 28
        AN(e);
417 28
        *b = '\0';
418 28
        hp->hd[f].b = hp->ws->f;
419 28
        hp->hd[f].e = b;
420 28
        WS_ReleaseP(hp->ws, b + 1);
421
}
422
423
/*--------------------------------------------------------------------*/
424
425
int
426 135952
http_GetHdr(const struct http *hp, const char *hdr, const char **ptr)
427
{
428
        unsigned u, l;
429
        const char *p;
430
431 135952
        l = hdr[0];
432 135952
        assert(l == strlen(hdr + 1));
433 135952
        assert(hdr[l] == ':');
434 135952
        hdr++;
435 135952
        u = http_findhdr(hp, l - 1, hdr);
436 135954
        if (u == 0) {
437 100967
                if (ptr != NULL)
438 93502
                        *ptr = NULL;
439 100967
                return (0);
440
        }
441 34987
        if (ptr != NULL) {
442 28062
                p = hp->hd[u].b + l;
443 84079
                while (vct_issp(*p))
444 27955
                        p++;
445 28061
                *ptr = p;
446
        }
447 34986
        return (1);
448
}
449
450
/*-----------------------------------------------------------------------------
451
 * Split source string at any of the separators, return pointer to first
452
 * and last+1 char of substrings, with whitespace trimed at both ends.
453
 * If sep being an empty string is shorthand for VCT::SP
454
 * If stop is NULL, src is NUL terminated.
455
 */
456
457
static int
458 2266
http_split(const char **src, const char *stop, const char *sep,
459
    const char **b, const char **e)
460
{
461
        const char *p, *q;
462
463 2266
        AN(src);
464 2266
        AN(*src);
465 2266
        AN(sep);
466 2266
        AN(b);
467 2266
        AN(e);
468
469 2266
        if (stop == NULL)
470 2252
                stop = strchr(*src, '\0');
471
472 2400
        for (p = *src; p < stop && (vct_issp(*p) || strchr(sep, *p)); p++)
473 134
                continue;
474
475 2266
        if (p >= stop) {
476 805
                *b = NULL;
477 805
                *e = NULL;
478 805
                return (0);
479
        }
480
481 1461
        *b = p;
482 1461
        if (*sep == '\0') {
483 0
                for (q = p + 1; q < stop && !vct_issp(*q); q++)
484 0
                        continue;
485 0
                *e = q;
486 0
                *src = q;
487 0
                return (1);
488
        }
489 7313
        for (q = p + 1; q < stop && !strchr(sep, *q); q++)
490 5852
                continue;
491 1461
        *src = q;
492 2922
        while (q > p && vct_issp(q[-1]))
493 0
                q--;
494 1461
        *e = q;
495 1461
        return (1);
496
}
497
498
/*-----------------------------------------------------------------------------
499
 * Comparison rule for tokens:
500
 *      if target string starts with '"', we use memcmp() and expect closing
501
 *      double quote as well
502
 *      otherwise we use strncascmp()
503
 *
504
 * On match we increment *bp past the token name.
505
 */
506
507
static int
508 1248
http_istoken(const char **bp, const char *e, const char *token)
509
{
510 1248
        int fl = strlen(token);
511
        const char *b;
512
513 1248
        AN(bp);
514 1248
        AN(e);
515 1248
        AN(token);
516
517 1248
        b = *bp;
518
519 1248
        if (b + fl + 2 <= e && *b == '"' &&
520 0
            !memcmp(b + 1, token, fl) && b[fl + 1] == '"') {
521 0
                *bp += fl + 2;
522 0
                return (1);
523
        }
524 1826
        if (b + fl <= e && !strncasecmp(b, token, fl) &&
525 630
            (b + fl == e || !vct_istchar(b[fl]))) {
526 578
                *bp += fl;
527 578
                return (1);
528
        }
529 670
        return (0);
530
}
531
532
/*-----------------------------------------------------------------------------
533
 * Find a given data element (token) in a header according to RFC2616's #rule
534
 * (section 2.1, p15)
535
 *
536
 * On case sensitivity:
537
 *
538
 * Section 4.2 (Messages Headers) defines field (header) name as case
539
 * insensitive, but the field (header) value/content may be case-sensitive.
540
 *
541
 * http_GetHdrToken looks up a token in a header value and the rfc does not say
542
 * explicitly if tokens are to be compared with or without respect to case.
543
 *
544
 * But all examples and specific statements regarding tokens follow the rule
545
 * that unquoted tokens are to be matched case-insensitively and quoted tokens
546
 * case-sensitively.
547
 *
548
 * The optional pb and pe arguments will point to the token content start and
549
 * end+1, white space trimmed on both sides.
550
 */
551
552
int
553 14800
http_GetHdrToken(const struct http *hp, const char *hdr,
554
    const char *token, const char **pb, const char **pe)
555
{
556
        const char *h, *b, *e;
557
558 14800
        if (pb != NULL)
559 10436
                *pb = NULL;
560 14800
        if (pe != NULL)
561 4198
                *pe = NULL;
562 14800
        if (!http_GetHdr(hp, hdr, &h))
563 13608
                return (0);
564 1192
        AN(h);
565
566 3054
        while (http_split(&h, NULL, ",", &b, &e))
567 1248
                if (http_istoken(&b, e, token))
568 578
                        break;
569 1192
        if (b == NULL)
570 614
                return (0);
571 578
        if (pb != NULL) {
572 572
                for (; vct_islws(*b); b++)
573 10
                        continue;
574 562
                if (b == e) {
575 512
                        b = NULL;
576 512
                        e = NULL;
577
                }
578 562
                *pb = b;
579 562
                if (pe != NULL)
580 526
                        *pe = e;
581
        }
582 578
        return (1);
583
}
584
585
/*--------------------------------------------------------------------
586
 * Find a given headerfields Q value.
587
 */
588
589
double
590 4198
http_GetHdrQ(const struct http *hp, const char *hdr, const char *field)
591
{
592
        const char *hb, *he, *b, *e;
593
        int i;
594
        double a, f;
595
596 4198
        i = http_GetHdrToken(hp, hdr, field, &hb, &he);
597 4198
        if (!i)
598 3672
                return (0.);
599
600 526
        if (hb == NULL)
601 512
                return (1.);
602 28
        while (http_split(&hb, he, ";", &b, &e)) {
603 14
                if (*b != 'q')
604 0
                        continue;
605 14
                for (b++; b < e && vct_issp(*b); b++)
606 0
                        continue;
607 14
                if (b == e || *b != '=')
608 0
                        continue;
609 14
                break;
610
        }
611 14
        if (b == NULL)
612 0
                return (1.);
613 14
        for (b++; b < e && vct_issp(*b); b++)
614 0
                continue;
615 14
        if (b == e || (*b != '.' && !vct_isdigit(*b)))
616 2
                return (0.);
617 12
        a = 0;
618 36
        while (b < e && vct_isdigit(*b)) {
619 12
                a *= 10.;
620 12
                a += *b - '0';
621 12
                b++;
622
        }
623 12
        if (b == e || *b++ != '.')
624 2
                return (a);
625 10
        f = .1;
626 42
        while (b < e && vct_isdigit(*b)) {
627 22
                a += f * (*b - '0');
628 22
                f *= .1;
629 22
                b++;
630
        }
631 10
        return (a);
632
}
633
634
/*--------------------------------------------------------------------
635
 * Find a given headerfields value.
636
 */
637
638
int
639 6238
http_GetHdrField(const struct http *hp, const char *hdr,
640
    const char *field, const char **ptr)
641
{
642
        const char *h;
643
        int i;
644
645 6238
        if (ptr != NULL)
646 6238
                *ptr = NULL;
647
648 6238
        h = NULL;
649 6238
        i = http_GetHdrToken(hp, hdr, field, &h, NULL);
650 6238
        if (!i)
651 6202
                return (i);
652
653 36
        if (ptr != NULL && h != NULL) {
654
                /* Skip whitespace, looking for '=' */
655 72
                while (*h && vct_issp(*h))
656 0
                        h++;
657 36
                if (*h == '=') {
658 36
                        h++;
659 80
                        while (*h && vct_issp(*h))
660 8
                                h++;
661 36
                        *ptr = h;
662
                }
663
        }
664 36
        return (i);
665
}
666
667
/*--------------------------------------------------------------------*/
668
669
ssize_t
670 12172
http_GetContentLength(const struct http *hp)
671
{
672
        ssize_t cl;
673
        const char *b;
674
        unsigned n;
675
676 12172
        CHECK_OBJ_NOTNULL(hp, HTTP_MAGIC);
677
678 12172
        if (!http_GetHdr(hp, H_Content_Length, &b))
679 5199
                return (-1);
680 6972
        cl = 0;
681 6972
        if (!vct_isdigit(*b))
682 6
                return (-2);
683 17305
        for (; vct_isdigit(*b); b++) {
684 10340
                if (cl > (SSIZE_MAX / 10))
685 -1
                        return (-2);
686 10341
                cl *= 10;
687 10341
                n = *b - '0';
688 10341
                if (cl > (SSIZE_MAX - n))
689 2
                        return (-2);
690 10339
                cl += n;
691
        }
692 13930
        while (vct_islws(*b))
693 0
                b++;
694 6964
        if (*b != '\0')
695 0
                return (-2);
696 6964
        return (cl);
697
}
698
699
/*--------------------------------------------------------------------
700
 */
701
702
enum sess_close
703 7400
http_DoConnection(struct http *hp)
704
{
705
        const char *h, *b, *e;
706
        enum sess_close retval;
707
        unsigned u, v;
708
709 7400
        if (hp->protover == 10)
710 82
                retval = SC_REQ_HTTP10;
711
        else
712 7318
                retval = SC_NULL;
713
714 7400
        http_CollectHdr(hp, H_Connection);
715 7400
        if (!http_GetHdr(hp, H_Connection, &h))
716 7207
                return (retval);
717 193
        AN(h);
718 583
        while (http_split(&h, NULL, ",", &b, &e)) {
719 199
                u = pdiff(b, e);
720 199
                if (u == 5 && !strncasecmp(b, "close", u))
721 169
                        retval = SC_REQ_CLOSE;
722 199
                if (u == 10 && !strncasecmp(b, "keep-alive", u))
723 16
                        retval = SC_NULL;
724
725
                /* Refuse removal of well-known-headers if they would pass. */
726
/*lint -save -e506 [constant value boolean] */
727
#define HTTPH(a, x, c)                                          \
728
                if (!((c) & HTTPH_R_PASS) &&                    \
729
                    strlen(a) == u && !strncasecmp(a, b, u))    \
730
                        return (SC_RX_BAD);
731
#include "tbl/http_headers.h"
732
/*lint -restore */
733
734 197
                v = http_findhdr(hp, u, b);
735 197
                if (v > 0)
736 6
                        hp->hdf[v] |= HDF_FILTER;
737
        }
738 191
        return (retval);
739
}
740
741
/*--------------------------------------------------------------------*/
742
743
int
744 15402
http_HdrIs(const struct http *hp, const char *hdr, const char *val)
745
{
746
        const char *p;
747
748 15402
        if (!http_GetHdr(hp, hdr, &p))
749 14834
                return (0);
750 568
        AN(p);
751 568
        if (!strcasecmp(p, val))
752 512
                return (1);
753 56
        return (0);
754
}
755
756
/*--------------------------------------------------------------------*/
757
758
uint16_t
759 10440
http_GetStatus(const struct http *hp)
760
{
761
762 10440
        CHECK_OBJ_NOTNULL(hp, HTTP_MAGIC);
763 10440
        return (hp->status);
764
}
765
766
int
767 19809
http_IsStatus(const struct http *hp, int val)
768
{
769
770 19809
        CHECK_OBJ_NOTNULL(hp, HTTP_MAGIC);
771 19809
        assert(val >= 100 && val <= 999);
772 19809
        return (val == (hp->status % 1000));
773
}
774
775
/*--------------------------------------------------------------------
776
 * Setting the status will also set the Reason appropriately
777
 */
778
779
void
780 978
http_SetStatus(struct http *to, uint16_t status)
781
{
782
        char buf[4];
783
        const char *reason;
784 978
        const char *sstr = NULL;
785
786 978
        CHECK_OBJ_NOTNULL(to, HTTP_MAGIC);
787
        /*
788
         * We allow people to use top digits for internal VCL
789
         * signalling, but strip them from the ASCII version.
790
         */
791 978
        to->status = status;
792 978
        status %= 1000;
793 978
        assert(status >= 100);
794
795 978
        reason = http_Status2Reason(status, &sstr);
796 978
        if (sstr) {
797 918
                http_SetH(to, HTTP_HDR_STATUS, sstr);
798
        } else {
799 60
                bprintf(buf, "%03d", status);
800 60
                http_PutField(to, HTTP_HDR_STATUS, buf);
801
        }
802 978
        http_SetH(to, HTTP_HDR_REASON, reason);
803 978
}
804
805
/*--------------------------------------------------------------------*/
806
807
const char *
808 7314
http_GetMethod(const struct http *hp)
809
{
810
811 7314
        CHECK_OBJ_NOTNULL(hp, HTTP_MAGIC);
812 7314
        Tcheck(hp->hd[HTTP_HDR_METHOD]);
813 7314
        return (hp->hd[HTTP_HDR_METHOD].b);
814
}
815
816
/*--------------------------------------------------------------------
817
 * Force a particular header field to a particular value
818
 */
819
820
void
821 10894
http_ForceField(struct http *to, unsigned n, const char *t)
822
{
823
        int i;
824
825 10894
        CHECK_OBJ_NOTNULL(to, HTTP_MAGIC);
826 10894
        assert(n < HTTP_HDR_FIRST);
827 10894
        AN(t);
828 10894
        if (to->hd[n].b == NULL || strcmp(to->hd[n].b, t)) {
829 162
                i = (HTTP_HDR_UNSET - HTTP_HDR_METHOD);
830 162
                i += to->logtag;
831 162
                if (n >= HTTP_HDR_FIRST)
832 0
                        VSLbt(to->vsl, (enum VSL_tag_e)i, to->hd[n]);
833 162
                http_SetH(to, n, t);
834
        }
835 10894
}
836
837
/*--------------------------------------------------------------------*/
838
839
void
840 890
http_PutResponse(struct http *to, const char *proto, uint16_t status,
841
    const char *reason)
842
{
843
844 890
        CHECK_OBJ_NOTNULL(to, HTTP_MAGIC);
845 890
        if (proto != NULL)
846 890
                http_SetH(to, HTTP_HDR_PROTO, proto);
847 890
        http_SetStatus(to, status);
848 890
        if (reason != NULL)
849 710
                http_SetH(to, HTTP_HDR_REASON, reason);
850 890
}
851
852
/*--------------------------------------------------------------------
853
 * Estimate how much workspace we need to Filter this header according
854
 * to 'how'.
855
 */
856
857
unsigned
858 3277
http_EstimateWS(const struct http *fm, unsigned how)
859
{
860
        unsigned u, l;
861
862 3277
        l = 4;
863 3277
        CHECK_OBJ_NOTNULL(fm, HTTP_MAGIC);
864 28372
        for (u = 0; u < fm->nhd; u++) {
865 25097
                if (u == HTTP_HDR_METHOD || u == HTTP_HDR_URL)
866 6552
                        continue;
867 18545
                Tcheck(fm->hd[u]);
868 18544
                if (fm->hdf[u] & HDF_FILTER)
869 2
                        continue;
870
#define HTTPH(a, b, c) \
871
                if (((c) & how) && http_IsHdr(&fm->hd[u], (b))) \
872
                        continue;
873
#include "tbl/http_headers.h"
874 18177
                l += Tlen(fm->hd[u]) + 1L;
875
        }
876 3275
        return (PRNDUP(l + 1L));
877
}
878
879
/*--------------------------------------------------------------------
880
 * Encode http struct as byte string.
881
 *
882
 * XXX: We could save considerable special-casing below by encoding also
883
 * XXX: H__Status, H__Reason and H__Proto into the string, but it would
884
 * XXX: add 26-30 bytes to all encoded objects to save a little code.
885
 * XXX: It could possibly be a good idea for later HTTP versions.
886
 */
887
888
void
889 3270
HTTP_Encode(const struct http *fm, uint8_t *p0, unsigned l, unsigned how)
890
{
891
        unsigned u, w;
892
        uint16_t n;
893
        uint8_t *p, *e;
894
895 3270
        AN(p0);
896 3270
        AN(l);
897 3270
        p = p0;
898 3270
        e = p + l;
899 3270
        assert(p + 5 <= e);
900 3270
        assert(fm->nhd <= fm->shd);
901 3270
        n = HTTP_HDR_FIRST - 3;
902 3270
        vbe16enc(p + 2, fm->status);
903 3270
        p += 4;
904 3270
        CHECK_OBJ_NOTNULL(fm, HTTP_MAGIC);
905 28313
        for (u = 0; u < fm->nhd; u++) {
906 25043
                if (u == HTTP_HDR_METHOD || u == HTTP_HDR_URL)
907 6539
                        continue;
908 18504
                Tcheck(fm->hd[u]);
909 18503
                if (fm->hdf[u] & HDF_FILTER)
910 2
                        continue;
911
#define HTTPH(a, b, c) \
912
                if (((c) & how) && http_IsHdr(&fm->hd[u], (b))) \
913
                        continue;
914
#include "tbl/http_headers.h"
915 18133
                http_VSLH(fm, u);
916 18136
                w = Tlen(fm->hd[u]) + 1L;
917 18137
                assert(p + w + 1 <= e);
918 18137
                memcpy(p, fm->hd[u].b, w);
919 18137
                p += w;
920 18137
                n++;
921
        }
922 3270
        *p++ = '\0';
923 3270
        assert(p <= e);
924 3270
        vbe16enc(p0, n + 1);
925 3270
}
926
927
/*--------------------------------------------------------------------
928
 * Decode byte string into http struct
929
 */
930
931
int
932 4446
HTTP_Decode(struct http *to, const uint8_t *fm)
933
{
934
935 4446
        CHECK_OBJ_NOTNULL(to, HTTP_MAGIC);
936 4446
        AN(to->vsl);
937 4446
        AN(fm);
938 4446
        if (vbe16dec(fm) <= to->shd) {
939 4444
                to->status = vbe16dec(fm + 2);
940 4444
                fm += 4;
941 37985
                for (to->nhd = 0; to->nhd < to->shd; to->nhd++) {
942 71526
                        if (to->nhd == HTTP_HDR_METHOD ||
943 33541
                            to->nhd == HTTP_HDR_URL) {
944 8887
                                to->hd[to->nhd].b = NULL;
945 8887
                                to->hd[to->nhd].e = NULL;
946 8887
                                continue;
947
                        }
948 29098
                        if (*fm == '\0')
949 4444
                                return (0);
950 24654
                        to->hd[to->nhd].b = (const void*)fm;
951 24654
                        fm = (const void*)strchr((const void*)fm, '\0');
952 24654
                        to->hd[to->nhd].e = (const void*)fm;
953 24654
                        fm++;
954 24654
                        http_VSLH(to, to->nhd);
955
                }
956
        }
957 4
        VSLb(to->vsl, SLT_Error,
958
            "Too many headers to Decode object (%u vs. %u)",
959 4
            vbe16dec(fm), to->shd);
960 2
        return (-1);
961
}
962
963
/*--------------------------------------------------------------------*/
964
965
uint16_t
966 2
HTTP_GetStatusPack(struct worker *wrk, struct objcore *oc)
967
{
968
        const char *ptr;
969 2
        ptr = ObjGetAttr(wrk, oc, OA_HEADERS, NULL);
970 2
        AN(ptr);
971
972 2
        return(vbe16dec(ptr + 2));
973
}
974
975
/*--------------------------------------------------------------------*/
976
977
/* Get the first packed header */
978
int
979 318
HTTP_IterHdrPack(struct worker *wrk, struct objcore *oc, const char **p)
980
{
981
        const char *ptr;
982
983 318
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
984 318
        CHECK_OBJ_NOTNULL(oc, OBJCORE_MAGIC);
985 318
        AN(p);
986
987 318
        if (*p == NULL) {
988 146
                ptr = ObjGetAttr(wrk, oc, OA_HEADERS, NULL);
989 146
                AN(ptr);
990 146
                ptr += 4;       /* Skip nhd and status */
991 146
                ptr = strchr(ptr, '\0') + 1;    /* Skip :proto: */
992 146
                ptr = strchr(ptr, '\0') + 1;    /* Skip :status: */
993 146
                ptr = strchr(ptr, '\0') + 1;    /* Skip :reason: */
994 146
                *p = ptr;
995
        } else {
996 172
                *p = strchr(*p, '\0') + 1;      /* Skip to next header */
997
        }
998 318
        if (**p == '\0')
999 38
                return (0);
1000 280
        return (1);
1001
}
1002
1003
const char *
1004 152
HTTP_GetHdrPack(struct worker *wrk, struct objcore *oc, const char *hdr)
1005
{
1006
        const char *ptr;
1007
        unsigned l;
1008
1009 152
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
1010 152
        CHECK_OBJ_NOTNULL(oc, OBJCORE_MAGIC);
1011 152
        AN(hdr);
1012
1013 152
        l = hdr[0];
1014 152
        assert(l > 0);
1015 152
        assert(l == strlen(hdr + 1));
1016 152
        assert(hdr[l] == ':');
1017 152
        hdr++;
1018
1019 152
        if (hdr[0] == ':') {
1020
                /* Special cases */
1021 6
                ptr = ObjGetAttr(wrk, oc, OA_HEADERS, NULL);
1022 6
                AN(ptr);
1023 6
                ptr += 4;       /* Skip nhd and status */
1024
1025 6
                if (!strcmp(hdr, ":proto:"))
1026 2
                        return (ptr);
1027 4
                ptr = strchr(ptr, '\0') + 1;
1028 4
                if (!strcmp(hdr, ":status:"))
1029 2
                        return (ptr);
1030 2
                ptr = strchr(ptr, '\0') + 1;
1031 2
                if (!strcmp(hdr, ":reason:"))
1032 2
                        return (ptr);
1033 0
                WRONG("Unknown magic packed header");
1034
        }
1035
1036 464
        HTTP_FOREACH_PACK(wrk, oc, ptr) {
1037 280
                if (!strncasecmp(ptr, hdr, l)) {
1038 108
                        ptr += l;
1039 322
                        while (vct_islws(*ptr))
1040 106
                                ptr++;
1041 108
                        return (ptr);
1042
                }
1043
        }
1044
1045 38
        return (NULL);
1046
}
1047
1048
/*--------------------------------------------------------------------
1049
 * Merge any headers in the oc->OA_HEADER into the struct http if they
1050
 * are not there already.
1051
 */
1052
1053
void
1054 34
HTTP_Merge(struct worker *wrk, struct objcore *oc, struct http *to)
1055
{
1056
        const char *ptr;
1057
        unsigned u;
1058
        const char *p;
1059
        unsigned nhd_before_merge;
1060
1061 34
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
1062 34
        CHECK_OBJ_NOTNULL(oc, OBJCORE_MAGIC);
1063 34
        CHECK_OBJ_NOTNULL(to, HTTP_MAGIC);
1064
1065 34
        ptr = ObjGetAttr(wrk, oc, OA_HEADERS, NULL);
1066 34
        AN(ptr);
1067
1068 34
        to->status = vbe16dec(ptr + 2);
1069 34
        ptr += 4;
1070
1071 204
        for (u = 0; u < HTTP_HDR_FIRST; u++) {
1072 170
                if (u == HTTP_HDR_METHOD || u == HTTP_HDR_URL)
1073 68
                        continue;
1074 102
                http_SetH(to, u, ptr);
1075 102
                ptr = strchr(ptr, '\0') + 1;
1076
        }
1077 34
        nhd_before_merge = to->nhd;
1078 200
        while (*ptr != '\0') {
1079 132
                p = strchr(ptr, ':');
1080 132
                AN(p);
1081 132
                u = http_findhdr(to, p - ptr, ptr);
1082 132
                if (u == 0 || u >= nhd_before_merge)
1083 74
                        http_SetHeader(to, ptr);
1084 132
                ptr = strchr(ptr, '\0') + 1;
1085
        }
1086 34
}
1087
1088
/*--------------------------------------------------------------------*/
1089
1090
static void
1091 3296
http_filterfields(struct http *to, const struct http *fm, unsigned how)
1092
{
1093
        unsigned u;
1094
1095 3296
        CHECK_OBJ_NOTNULL(fm, HTTP_MAGIC);
1096 3296
        CHECK_OBJ_NOTNULL(to, HTTP_MAGIC);
1097 3296
        to->nhd = HTTP_HDR_FIRST;
1098 3296
        to->status = fm->status;
1099 10916
        for (u = HTTP_HDR_FIRST; u < fm->nhd; u++) {
1100 7620
                Tcheck(fm->hd[u]);
1101 7621
                if (fm->hdf[u] & HDF_FILTER)
1102 4
                        continue;
1103 7617
                Tcheck(fm->hd[u]);
1104
#define HTTPH(a, b, c) \
1105
                if (((c) & how) && http_IsHdr(&fm->hd[u], (b))) \
1106
                        continue;
1107
#include "tbl/http_headers.h"
1108 7528
                assert (to->nhd < to->shd);
1109 7528
                to->hd[to->nhd] = fm->hd[u];
1110 7528
                to->hdf[to->nhd] = 0;
1111 7528
                http_VSLH(to, to->nhd);
1112 7528
                to->nhd++;
1113
        }
1114 3296
}
1115
1116
/*--------------------------------------------------------------------*/
1117
1118
static void
1119 9888
http_linkh(const struct http *to, const struct http *fm, unsigned n)
1120
{
1121
1122 9888
        assert(n < HTTP_HDR_FIRST);
1123 9888
        Tcheck(fm->hd[n]);
1124 9888
        to->hd[n] = fm->hd[n];
1125 9888
        to->hdf[n] = fm->hdf[n];
1126 9888
        http_VSLH(to, n);
1127 9888
}
1128
1129
/*--------------------------------------------------------------------*/
1130
1131
void
1132 3296
http_FilterReq(struct http *to, const struct http *fm, unsigned how)
1133
{
1134 3296
        CHECK_OBJ_NOTNULL(to, HTTP_MAGIC);
1135 3296
        CHECK_OBJ_NOTNULL(fm, HTTP_MAGIC);
1136
1137 3296
        http_linkh(to, fm, HTTP_HDR_METHOD);
1138 3296
        http_linkh(to, fm, HTTP_HDR_URL);
1139 3296
        http_linkh(to, fm, HTTP_HDR_PROTO);
1140 3296
        to->protover = fm->protover;
1141 3296
        http_filterfields(to, fm, how);
1142 3296
}
1143
1144
/*--------------------------------------------------------------------
1145
 * This function copies any header fields which reference foreign
1146
 * storage into our own WS.
1147
 */
1148
1149
void
1150 3268
http_CopyHome(const struct http *hp)
1151
{
1152
        unsigned u, l;
1153
        char *p;
1154
1155 29114
        for (u = 0; u < hp->nhd; u++) {
1156 25848
                if (hp->hd[u].b == NULL) {
1157 6534
                        assert(u < HTTP_HDR_FIRST);
1158 6534
                        continue;
1159
                }
1160 19314
                if (WS_Inside(hp->ws, hp->hd[u].b, hp->hd[u].e))
1161 2052
                        continue;
1162
1163 17261
                l = Tlen(hp->hd[u]);
1164 17261
                p = WS_Copy(hp->ws, hp->hd[u].b, l + 1L);
1165 17260
                if (p == NULL) {
1166 0
                        http_fail(hp);
1167 0
                        VSLb(hp->vsl, SLT_LostHeader, "%s", hp->hd[u].b);
1168 0
                        return;
1169
                }
1170 17260
                hp->hd[u].b = p;
1171 17260
                hp->hd[u].e = p + l;
1172
        }
1173
}
1174
1175
/*--------------------------------------------------------------------*/
1176
1177
void
1178 15585
http_SetHeader(struct http *to, const char *hdr)
1179
{
1180
1181 15585
        CHECK_OBJ_NOTNULL(to, HTTP_MAGIC);
1182 15585
        if (to->nhd >= to->shd) {
1183 0
                VSLb(to->vsl, SLT_LostHeader, "%s", hdr);
1184 0
                http_fail(to);
1185 0
                return;
1186
        }
1187 15585
        http_SetH(to, to->nhd++, hdr);
1188
}
1189
1190
/*--------------------------------------------------------------------*/
1191
1192
void
1193 6538
http_ForceHeader(struct http *to, const char *hdr, const char *val)
1194
{
1195
1196 6538
        CHECK_OBJ_NOTNULL(to, HTTP_MAGIC);
1197 6538
        if (http_HdrIs(to, hdr, val))
1198 334
                return;
1199 6204
        http_Unset(to, hdr);
1200 6204
        http_PrintfHeader(to, "%s %s", hdr + 1, val);
1201
}
1202
1203
void
1204 24833
http_PrintfHeader(struct http *to, const char *fmt, ...)
1205
{
1206
        va_list ap;
1207
        unsigned l, n;
1208
1209 24833
        CHECK_OBJ_NOTNULL(to, HTTP_MAGIC);
1210 24833
        l = WS_Reserve(to->ws, 0);
1211 24832
        va_start(ap, fmt);
1212 24832
        n = vsnprintf(to->ws->f, l, fmt, ap);
1213 24832
        va_end(ap);
1214 24832
        if (n + 1 >= l || to->nhd >= to->shd) {
1215 31
                http_fail(to);
1216 32
                va_start(ap, fmt);
1217 32
                VSLbv(to->vsl, SLT_LostHeader, fmt, ap);
1218 32
                va_end(ap);
1219 32
                WS_Release(to->ws, 0);
1220 32
                return;
1221
        }
1222 24801
        to->hd[to->nhd].b = to->ws->f;
1223 24801
        to->hd[to->nhd].e = to->ws->f + n;
1224 24801
        to->hdf[to->nhd] = 0;
1225 24801
        WS_Release(to->ws, n + 1);
1226 24800
        http_VSLH(to, to->nhd);
1227 24799
        to->nhd++;
1228
}
1229
1230
void
1231 3810
http_TimeHeader(struct http *to, const char *fmt, double now)
1232
{
1233
        char *p;
1234
1235 3810
        CHECK_OBJ_NOTNULL(to, HTTP_MAGIC);
1236 3810
        p = WS_Alloc(to->ws, strlen(fmt) + VTIM_FORMAT_SIZE);
1237 3810
        if (p == NULL) {
1238 98
                http_fail(to);
1239 98
                VSLb(to->vsl, SLT_LostHeader, "%s", fmt);
1240 98
                return;
1241
        }
1242 3712
        strcpy(p, fmt);
1243 3712
        VTIM_format(now, strchr(p, '\0'));
1244 3712
        to->hd[to->nhd].b = p;
1245 3712
        to->hd[to->nhd].e = strchr(p, '\0');
1246 3712
        to->hdf[to->nhd] = 0;
1247 3712
        http_VSLH(to, to->nhd);
1248 3712
        to->nhd++;
1249
}
1250
1251
/*--------------------------------------------------------------------*/
1252
1253
void
1254 21270
http_Unset(struct http *hp, const char *hdr)
1255
{
1256
        uint16_t u, v;
1257
1258 120618
        for (v = u = HTTP_HDR_FIRST; u < hp->nhd; u++) {
1259 99348
                Tcheck(hp->hd[u]);
1260 99348
                if (http_IsHdr(&hp->hd[u], hdr)) {
1261 1000
                        http_VSLH_del(hp, u);
1262 1000
                        continue;
1263
                }
1264 98348
                if (v != u) {
1265 2648
                        memcpy(&hp->hd[v], &hp->hd[u], sizeof *hp->hd);
1266 2648
                        memcpy(&hp->hdf[v], &hp->hdf[u], sizeof *hp->hdf);
1267
                }
1268 98348
                v++;
1269
        }
1270 21270
        hp->nhd = v;
1271 21270
}
1272
1273
/*--------------------------------------------------------------------*/
1274
1275
void
1276 1368
HTTP_Init(void)
1277
{
1278
1279
#define HTTPH(a, b, c) b[0] = (char)strlen(b + 1);
1280
#include "tbl/http_headers.h"
1281 1368
}