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 72955
http_VSLH(const struct http *hp, unsigned hdr)
58
{
59
        int i;
60
61 72955
        if (hp->vsl != NULL) {
62 72956
                AN(hp->vsl->wid & (VSL_CLIENTMARKER|VSL_BACKENDMARKER));
63 72956
                i = hdr;
64 72956
                if (i > HTTP_HDR_FIRST)
65 31901
                        i = HTTP_HDR_FIRST;
66 72956
                i += hp->logtag;
67 72956
                VSLbt(hp->vsl, (enum VSL_tag_e)i, hp->hd[hdr]);
68
        }
69 72944
}
70
71
static void
72 500
http_VSLH_del(const struct http *hp, unsigned hdr)
73
{
74
        int i;
75
76 500
        if (hp->vsl != NULL) {
77
                /* We don't support unsetting stuff in the first line */
78 500
                assert (hdr >= HTTP_HDR_FIRST);
79 500
                AN(hp->vsl->wid & (VSL_CLIENTMARKER|VSL_BACKENDMARKER));
80 500
                i = (HTTP_HDR_UNSET - HTTP_HDR_METHOD);
81 500
                i += hp->logtag;
82 500
                VSLbt(hp->vsl, (enum VSL_tag_e)i, hp->hd[hdr]);
83
        }
84 500
}
85
86
/*--------------------------------------------------------------------*/
87
88
void
89 4051
http_VSL_log(const struct http *hp)
90
{
91
        unsigned u;
92
93 29830
        for (u = 0; u < hp->nhd; u++)
94 25779
                if (hp->hd[u].b != NULL)
95 17677
                        http_VSLH(hp, u);
96 4051
}
97
98
/*--------------------------------------------------------------------*/
99
100
static void
101 68
http_fail(const struct http *hp)
102
{
103
104 68
        VSC_C_main->losthdr++;
105 68
        hp->ws->id[0] |= 0x20;          // cheesy tolower()
106 68
        VSLb(hp->vsl, SLT_Error, "out of workspace (%s)", hp->ws->id);
107 68
        WS_MarkOverflow(hp->ws);
108 68
}
109
110
/*--------------------------------------------------------------------*/
111
/* List of canonical HTTP response code names from RFC2616 */
112
113
static struct http_msg {
114
        unsigned        nbr;
115
        const char      *status;
116
        const char      *txt;
117
} http_msg[] = {
118
#define HTTP_RESP(n, t) { n, #n, t},
119
#include "tbl/http_response.h"
120
        { 0, "0", NULL }
121
};
122
123
const char *
124 671
http_Status2Reason(unsigned status, const char **sstr)
125
{
126
        struct http_msg *mp;
127
128 671
        status %= 1000;
129 671
        assert(status >= 100);
130 16088
        for (mp = http_msg; mp->nbr != 0 && mp->nbr <= status; mp++)
131 16054
                if (mp->nbr == status) {
132 637
                        if (sstr)
133 496
                                *sstr = mp->status;
134 637
                        return (mp->txt);
135
                }
136 34
        return ("Unknown HTTP Status");
137
}
138
139
/*--------------------------------------------------------------------*/
140
141
unsigned
142 3570
HTTP_estimate(unsigned nhttp)
143
{
144
145
        /* XXX: We trust the structs to size-aligned as necessary */
146 3570
        return (PRNDUP(sizeof (struct http) + sizeof(txt) * nhttp + nhttp));
147
}
148
149
struct http *
150 10716
HTTP_create(void *p, uint16_t nhttp, unsigned len)
151
{
152
        struct http *hp;
153
154 10716
        hp = p;
155 10716
        hp->magic = HTTP_MAGIC;
156 10716
        hp->hd = (void*)(hp + 1);
157 10716
        hp->shd = nhttp;
158 10716
        hp->hdf = (void*)(hp->hd + nhttp);
159 10716
        assert((unsigned char*)p + len == hp->hdf + PRNDUP(nhttp));
160 10716
        return (hp);
161
}
162
163
/*--------------------------------------------------------------------*/
164
165
void
166 9869
HTTP_Setup(struct http *hp, struct ws *ws, struct vsl_log *vsl,
167
    enum VSL_tag_e  whence)
168
{
169 9869
        http_Teardown(hp);
170 9869
        hp->nhd = HTTP_HDR_FIRST;
171 9869
        hp->logtag = whence;
172 9869
        hp->ws = ws;
173 9869
        hp->vsl = vsl;
174 9869
}
175
176
/*--------------------------------------------------------------------
177
 * http_Teardown() is a safety feature, we use it to zap all http
178
 * structs once we're done with them, to minimize the risk that
179
 * old stale pointers exist to no longer valid stuff.
180
 */
181
182
void
183 15660
http_Teardown(struct http *hp)
184
{
185
186 15660
        CHECK_OBJ_NOTNULL(hp, HTTP_MAGIC);
187 15660
        AN(hp->shd);
188 15660
        memset(&hp->nhd, 0, sizeof *hp - offsetof(struct http, nhd));
189 15660
        memset(hp->hd, 0, sizeof *hp->hd * hp->shd);
190 15660
        memset(hp->hdf, 0, sizeof *hp->hdf * hp->shd);
191 15660
}
192
193
/*--------------------------------------------------------------------*/
194
195
void
196 4434
HTTP_Copy(struct http *to, const struct http * const fm)
197
{
198
199 4434
        assert(fm->nhd <= to->shd);
200 4434
        memcpy(&to->nhd, &fm->nhd, sizeof *to - offsetof(struct http, nhd));
201 4434
        memcpy(to->hd, fm->hd, fm->nhd * sizeof *to->hd);
202 4434
        memcpy(to->hdf, fm->hdf, fm->nhd * sizeof *to->hdf);
203 4434
        to->protover = fm->protover;
204 4434
}
205
206
/*--------------------------------------------------------------------*/
207
208
void
209 4402
http_Proto(struct http *to)
210
{
211
        const char *fm;
212
213 4402
        fm = to->hd[HTTP_HDR_PROTO].b;
214
215 8802
        if ((fm[0] == 'H' || fm[0] == 'h') &&
216 8800
            (fm[1] == 'T' || fm[1] == 't') &&
217 8800
            (fm[2] == 'T' || fm[2] == 't') &&
218 8800
            (fm[3] == 'P' || fm[3] == 'p') &&
219 8800
            fm[4] == '/' &&
220 8800
            vct_isdigit(fm[5]) &&
221 8800
            fm[6] == '.' &&
222 8800
            vct_isdigit(fm[7]) &&
223 4400
            fm[8] == '\0') {
224 4400
                to->protover = 10 * (fm[5] - '0') + (fm[7] - '0');
225
        } else {
226 2
                to->protover = 0;
227
        }
228 4402
}
229
230
/*--------------------------------------------------------------------*/
231
232
void
233 10481
http_SetH(struct http *to, unsigned n, const char *fm)
234
{
235
236 10481
        assert(n < to->nhd);
237 10481
        AN(fm);
238 10481
        to->hd[n].b = TRUST_ME(fm);
239 10481
        to->hd[n].e = strchr(to->hd[n].b, '\0');
240 10481
        to->hdf[n] = 0;
241 10481
        http_VSLH(to, n);
242 10481
        if (n == HTTP_HDR_PROTO)
243 662
                http_Proto(to);
244 10481
}
245
246
/*--------------------------------------------------------------------*/
247
248
static void
249 30
http_PutField(struct http *to, int field, const char *string)
250
{
251
        char *p;
252
253 30
        CHECK_OBJ_NOTNULL(to, HTTP_MAGIC);
254 30
        p = WS_Copy(to->ws, string, -1);
255 30
        if (p == NULL) {
256 1
                http_fail(to);
257 1
                VSLb(to->vsl, SLT_LostHeader, "%s", string);
258 1
                return;
259
        }
260 29
        to->hd[field].b = p;
261 29
        to->hd[field].e = strchr(p, '\0');
262 29
        to->hdf[field] = 0;
263 29
        http_VSLH(to, field);
264 29
        if (field == HTTP_HDR_PROTO)
265 0
                http_Proto(to);
266
}
267
268
/*--------------------------------------------------------------------*/
269
270
static int
271 308451
http_IsHdr(const txt *hh, const char *hdr)
272
{
273
        unsigned l;
274
275 308451
        Tcheck(*hh);
276 308451
        AN(hdr);
277 308451
        l = hdr[0];
278 308451
        assert(l == strlen(hdr + 1));
279 308451
        assert(hdr[l] == ':');
280 308451
        hdr++;
281 308451
        return (!strncasecmp(hdr, hh->b, l));
282
}
283
284
/*--------------------------------------------------------------------*/
285
286
static unsigned
287 80297
http_findhdr(const struct http *hp, unsigned l, const char *hdr)
288
{
289
        unsigned u;
290
291 252528
        for (u = HTTP_HDR_FIRST; u < hp->nhd; u++) {
292 189735
                Tcheck(hp->hd[u]);
293 189743
                if (hp->hd[u].e < hp->hd[u].b + l + 1)
294 23410
                        continue;
295 166333
                if (hp->hd[u].b[l] != ':')
296 135926
                        continue;
297 30407
                if (strncasecmp(hdr, hp->hd[u].b, l))
298 12895
                        continue;
299 17512
                return (u);
300
        }
301 62793
        return (0);
302
}
303
304
/*--------------------------------------------------------------------
305
 * Count how many instances we have of this header
306
 */
307
308
unsigned
309 4295
http_CountHdr(const struct http *hp, const char *hdr)
310
{
311 4295
        unsigned retval = 0;
312
        unsigned u;
313
314 4295
        CHECK_OBJ_NOTNULL(hp, HTTP_MAGIC);
315
316 9949
        for (u = HTTP_HDR_FIRST; u < hp->nhd; u++) {
317 5654
                Tcheck(hp->hd[u]);
318 5654
                if (http_IsHdr(&hp->hd[u], hdr))
319 2172
                        retval++;
320
        }
321 4295
        return (retval);
322
}
323
324
/*--------------------------------------------------------------------
325
 * This function collapses multiple headerlines of the same name.
326
 * The lines are joined with a comma, according to [rfc2616, 4.2bot, p32]
327
 */
328
329
void
330 11720
http_CollectHdr(struct http *hp, const char *hdr)
331
{
332
333 11720
        http_CollectHdrSep(hp, hdr, NULL);
334 11719
}
335
336
/*--------------------------------------------------------------------
337
 * You may prefer to collapse header fields using a different separator.
338
 * For Cookie headers, the separator is "; " for example. That's probably
339
 * the only example too.
340
 */
341
342
void
343 11795
http_CollectHdrSep(struct http *hp, const char *hdr, const char *sep)
344
{
345
        unsigned u, l, lsep, ml, f, x, d;
346 11795
        char *b = NULL, *e = NULL;
347
        const char *v;
348
349 11795
        CHECK_OBJ_NOTNULL(hp, HTTP_MAGIC);
350 11795
        if (WS_Overflowed(hp->ws))
351 24
                return;
352
353 11770
        if (sep == NULL || *sep == '\0')
354 11695
                sep = ", ";
355 11770
        lsep = strlen(sep);
356
357 11770
        l = hdr[0];
358 11770
        assert(l == strlen(hdr + 1));
359 11770
        assert(hdr[l] == ':');
360 11770
        f = http_findhdr(hp, l - 1, hdr + 1);
361 11770
        if (f == 0)
362 11512
                return;
363
364 710
        for (d = u = f + 1; u < hp->nhd; u++) {
365 452
                Tcheck(hp->hd[u]);
366 452
                if (!http_IsHdr(&hp->hd[u], hdr)) {
367 436
                        if (d != u) {
368 46
                                hp->hd[d] = hp->hd[u];
369 46
                                hp->hdf[d] = hp->hdf[u];
370
                        }
371 436
                        d++;
372 436
                        continue;
373
                }
374 16
                if (b == NULL) {
375
                        /* Found second header, start our collection */
376 14
                        ml = WS_Reserve(hp->ws, 0);
377 14
                        b = hp->ws->f;
378 14
                        e = b + ml;
379 14
                        x = Tlen(hp->hd[f]);
380 14
                        if (b + x >= e) {
381 0
                                http_fail(hp);
382 0
                                VSLb(hp->vsl, SLT_LostHeader, "%s", hdr + 1);
383 0
                                WS_Release(hp->ws, 0);
384 0
                                return;
385
                        }
386 14
                        memcpy(b, hp->hd[f].b, x);
387 14
                        b += x;
388
                }
389
390 16
                AN(b);
391 16
                AN(e);
392
393
                /* Append the Nth header we found */
394 16
                x = Tlen(hp->hd[u]) - l;
395
396 16
                v = hp->hd[u].b + *hdr;
397 48
                while (vct_issp(*v)) {
398 16
                        v++;
399 16
                        x--;
400
                }
401
402 16
                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 16
                memcpy(b, sep, lsep);
409 16
                b += lsep;
410 16
                memcpy(b, v, x);
411 16
                b += x;
412
        }
413 258
        if (b == NULL)
414 244
                return;
415 14
        hp->nhd = (uint16_t)d;
416 14
        AN(e);
417 14
        *b = '\0';
418 14
        hp->hd[f].b = hp->ws->f;
419 14
        hp->hd[f].e = b;
420 14
        WS_ReleaseP(hp->ws, b + 1);
421
}
422
423
/*--------------------------------------------------------------------*/
424
425
int
426 68371
http_GetHdr(const struct http *hp, const char *hdr, const char **ptr)
427
{
428
        unsigned u, l;
429
        const char *p;
430
431 68371
        l = hdr[0];
432 68371
        assert(l == strlen(hdr + 1));
433 68371
        assert(hdr[l] == ':');
434 68371
        hdr++;
435 68371
        u = http_findhdr(hp, l - 1, hdr);
436 68373
        if (u == 0) {
437 51154
                if (ptr != NULL)
438 47392
                        *ptr = NULL;
439 51154
                return (0);
440
        }
441 17219
        if (ptr != NULL) {
442 14358
                p = hp->hd[u].b + l;
443 43021
                while (vct_issp(*p))
444 14305
                        p++;
445 14358
                *ptr = p;
446
        }
447 17219
        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 1132
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 1132
        AN(src);
464 1132
        AN(*src);
465 1132
        AN(sep);
466 1132
        AN(b);
467 1132
        AN(e);
468
469 1132
        if (stop == NULL)
470 1125
                stop = strchr(*src, '\0');
471
472 1199
        for (p = *src; p < stop && (vct_issp(*p) || strchr(sep, *p)); p++)
473 67
                continue;
474
475 1132
        if (p >= stop) {
476 402
                *b = NULL;
477 402
                *e = NULL;
478 402
                return (0);
479
        }
480
481 730
        *b = p;
482 730
        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 3654
        for (q = p + 1; q < stop && !strchr(sep, *q); q++)
490 2924
                continue;
491 730
        *src = q;
492 1460
        while (q > p && vct_issp(q[-1]))
493 0
                q--;
494 730
        *e = q;
495 730
        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 624
http_istoken(const char **bp, const char *e, const char *token)
509
{
510 624
        int fl = strlen(token);
511
        const char *b;
512
513 624
        AN(bp);
514 624
        AN(e);
515 624
        AN(token);
516
517 624
        b = *bp;
518
519 624
        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 913
        if (b + fl <= e && !strncasecmp(b, token, fl) &&
525 315
            (b + fl == e || !vct_istchar(b[fl]))) {
526 289
                *bp += fl;
527 289
                return (1);
528
        }
529 335
        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 7505
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 7505
        if (pb != NULL)
559 5278
                *pb = NULL;
560 7505
        if (pe != NULL)
561 2144
                *pe = NULL;
562 7505
        if (!http_GetHdr(hp, hdr, &h))
563 6909
                return (0);
564 596
        AN(h);
565
566 1527
        while (http_split(&h, NULL, ",", &b, &e))
567 624
                if (http_istoken(&b, e, token))
568 289
                        break;
569 596
        if (b == NULL)
570 307
                return (0);
571 289
        if (pb != NULL) {
572 286
                for (; vct_islws(*b); b++)
573 5
                        continue;
574 281
                if (b == e) {
575 256
                        b = NULL;
576 256
                        e = NULL;
577
                }
578 281
                *pb = b;
579 281
                if (pe != NULL)
580 263
                        *pe = e;
581
        }
582 289
        return (1);
583
}
584
585
/*--------------------------------------------------------------------
586
 * Find a given headerfields Q value.
587
 */
588
589
double
590 2144
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 2144
        i = http_GetHdrToken(hp, hdr, field, &hb, &he);
597 2144
        if (!i)
598 1881
                return (0.);
599
600 263
        if (hb == NULL)
601 256
                return (1.);
602 14
        while (http_split(&hb, he, ";", &b, &e)) {
603 7
                if (*b != 'q')
604 0
                        continue;
605 7
                for (b++; b < e && vct_issp(*b); b++)
606 0
                        continue;
607 7
                if (b == e || *b != '=')
608 0
                        continue;
609 7
                break;
610
        }
611 7
        if (b == NULL)
612 0
                return (1.);
613 7
        for (b++; b < e && vct_issp(*b); b++)
614 0
                continue;
615 7
        if (b == e || (*b != '.' && !vct_isdigit(*b)))
616 1
                return (0.);
617 6
        a = 0;
618 18
        while (b < e && vct_isdigit(*b)) {
619 6
                a *= 10.;
620 6
                a += *b - '0';
621 6
                b++;
622
        }
623 6
        if (b == e || *b++ != '.')
624 1
                return (a);
625 5
        f = .1;
626 21
        while (b < e && vct_isdigit(*b)) {
627 11
                a += f * (*b - '0');
628 11
                f *= .1;
629 11
                b++;
630
        }
631 5
        return (a);
632
}
633
634
/*--------------------------------------------------------------------
635
 * Find a given headerfields value.
636
 */
637
638
int
639 3134
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 3134
        if (ptr != NULL)
646 3134
                *ptr = NULL;
647
648 3134
        h = NULL;
649 3134
        i = http_GetHdrToken(hp, hdr, field, &h, NULL);
650 3134
        if (!i)
651 3116
                return (i);
652
653 18
        if (ptr != NULL && h != NULL) {
654
                /* Skip whitespace, looking for '=' */
655 36
                while (*h && vct_issp(*h))
656 0
                        h++;
657 18
                if (*h == '=') {
658 18
                        h++;
659 40
                        while (*h && vct_issp(*h))
660 4
                                h++;
661 18
                        *ptr = h;
662
                }
663
        }
664 18
        return (i);
665
}
666
667
/*--------------------------------------------------------------------*/
668
669
ssize_t
670 6186
http_GetContentLength(const struct http *hp)
671
{
672
        ssize_t cl;
673
        const char *b;
674
        unsigned n;
675
676 6186
        CHECK_OBJ_NOTNULL(hp, HTTP_MAGIC);
677
678 6186
        if (!http_GetHdr(hp, H_Content_Length, &b))
679 2641
                return (-1);
680 3545
        cl = 0;
681 3545
        if (!vct_isdigit(*b))
682 3
                return (-2);
683 8855
        for (; vct_isdigit(*b); b++) {
684 5314
                if (cl > (SSIZE_MAX / 10))
685 0
                        return (-2);
686 5314
                cl *= 10;
687 5314
                n = *b - '0';
688 5314
                if (cl > (SSIZE_MAX - n))
689 1
                        return (-2);
690 5313
                cl += n;
691
        }
692 7082
        while (vct_islws(*b))
693 0
                b++;
694 3541
        if (*b != '\0')
695 0
                return (-2);
696 3541
        return (cl);
697
}
698
699
/*--------------------------------------------------------------------
700
 */
701
702
enum sess_close
703 3754
http_DoConnection(struct http *hp)
704
{
705
        const char *h, *b, *e;
706
        enum sess_close retval;
707
        unsigned u, v;
708
709 3754
        if (hp->protover == 10)
710 39
                retval = SC_REQ_HTTP10;
711
        else
712 3715
                retval = SC_NULL;
713
714 3754
        http_CollectHdr(hp, H_Connection);
715 3754
        if (!http_GetHdr(hp, H_Connection, &h))
716 3658
                return (retval);
717 96
        AN(h);
718 290
        while (http_split(&h, NULL, ",", &b, &e)) {
719 99
                u = pdiff(b, e);
720 99
                if (u == 5 && !strncasecmp(b, "close", u))
721 84
                        retval = SC_REQ_CLOSE;
722 99
                if (u == 10 && !strncasecmp(b, "keep-alive", u))
723 8
                        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 98
                v = http_findhdr(hp, u, b);
735 98
                if (v > 0)
736 3
                        hp->hdf[v] |= HDF_FILTER;
737
        }
738 95
        return (retval);
739
}
740
741
/*--------------------------------------------------------------------*/
742
743
int
744 7827
http_HdrIs(const struct http *hp, const char *hdr, const char *val)
745
{
746
        const char *p;
747
748 7827
        if (!http_GetHdr(hp, hdr, &p))
749 7545
                return (0);
750 282
        AN(p);
751 282
        if (!strcasecmp(p, val))
752 256
                return (1);
753 26
        return (0);
754
}
755
756
/*--------------------------------------------------------------------*/
757
758
uint16_t
759 5281
http_GetStatus(const struct http *hp)
760
{
761
762 5281
        CHECK_OBJ_NOTNULL(hp, HTTP_MAGIC);
763 5281
        return (hp->status);
764
}
765
766
int
767 9992
http_IsStatus(const struct http *hp, int val)
768
{
769
770 9992
        CHECK_OBJ_NOTNULL(hp, HTTP_MAGIC);
771 9992
        assert(val >= 100 && val <= 999);
772 9992
        return (val == (hp->status % 1000));
773
}
774
775
/*--------------------------------------------------------------------
776
 * Setting the status will also set the Reason appropriately
777
 */
778
779
void
780 526
http_SetStatus(struct http *to, uint16_t status)
781
{
782
        char buf[4];
783
        const char *reason;
784 526
        const char *sstr = NULL;
785
786 526
        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 526
        to->status = status;
792 526
        status %= 1000;
793 526
        assert(status >= 100);
794
795 526
        reason = http_Status2Reason(status, &sstr);
796 526
        if (sstr) {
797 496
                http_SetH(to, HTTP_HDR_STATUS, sstr);
798
        } else {
799 30
                bprintf(buf, "%03d", status);
800 30
                http_PutField(to, HTTP_HDR_STATUS, buf);
801
        }
802 526
        http_SetH(to, HTTP_HDR_REASON, reason);
803 526
}
804
805
/*--------------------------------------------------------------------*/
806
807
const char *
808 3703
http_GetMethod(const struct http *hp)
809
{
810
811 3703
        CHECK_OBJ_NOTNULL(hp, HTTP_MAGIC);
812 3703
        Tcheck(hp->hd[HTTP_HDR_METHOD]);
813 3703
        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 5475
http_ForceField(struct http *to, unsigned n, const char *t)
822
{
823
        int i;
824
825 5475
        CHECK_OBJ_NOTNULL(to, HTTP_MAGIC);
826 5475
        assert(n < HTTP_HDR_FIRST);
827 5475
        AN(t);
828 5475
        if (to->hd[n].b == NULL || strcmp(to->hd[n].b, t)) {
829 81
                i = (HTTP_HDR_UNSET - HTTP_HDR_METHOD);
830 81
                i += to->logtag;
831 81
                if (n >= HTTP_HDR_FIRST)
832 0
                        VSLbt(to->vsl, (enum VSL_tag_e)i, to->hd[n]);
833 81
                http_SetH(to, n, t);
834
        }
835 5475
}
836
837
/*--------------------------------------------------------------------*/
838
839
void
840 482
http_PutResponse(struct http *to, const char *proto, uint16_t status,
841
    const char *reason)
842
{
843
844 482
        CHECK_OBJ_NOTNULL(to, HTTP_MAGIC);
845 482
        if (proto != NULL)
846 482
                http_SetH(to, HTTP_HDR_PROTO, proto);
847 482
        http_SetStatus(to, status);
848 482
        if (reason != NULL)
849 392
                http_SetH(to, HTTP_HDR_REASON, reason);
850 482
}
851
852
/*--------------------------------------------------------------------
853
 * Estimate how much workspace we need to Filter this header according
854
 * to 'how'.
855
 */
856
857
unsigned
858 1645
http_EstimateWS(const struct http *fm, unsigned how)
859
{
860
        unsigned u, l;
861
862 1645
        l = 4;
863 1645
        CHECK_OBJ_NOTNULL(fm, HTTP_MAGIC);
864 14249
        for (u = 0; u < fm->nhd; u++) {
865 12604
                if (u == HTTP_HDR_METHOD || u == HTTP_HDR_URL)
866 3289
                        continue;
867 9315
                Tcheck(fm->hd[u]);
868 9315
                if (fm->hdf[u] & HDF_FILTER)
869 1
                        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 9133
                l += Tlen(fm->hd[u]) + 1L;
875
        }
876 1645
        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 1642
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 1642
        AN(p0);
896 1642
        AN(l);
897 1642
        p = p0;
898 1642
        e = p + l;
899 1642
        assert(p + 5 <= e);
900 1642
        assert(fm->nhd <= fm->shd);
901 1642
        n = HTTP_HDR_FIRST - 3;
902 1642
        vbe16enc(p + 2, fm->status);
903 1642
        p += 4;
904 1642
        CHECK_OBJ_NOTNULL(fm, HTTP_MAGIC);
905 14219
        for (u = 0; u < fm->nhd; u++) {
906 12577
                if (u == HTTP_HDR_METHOD || u == HTTP_HDR_URL)
907 3282
                        continue;
908 9295
                Tcheck(fm->hd[u]);
909 9294
                if (fm->hdf[u] & HDF_FILTER)
910 1
                        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 9112
                http_VSLH(fm, u);
916 9113
                w = Tlen(fm->hd[u]) + 1L;
917 9113
                assert(p + w + 1 <= e);
918 9113
                memcpy(p, fm->hd[u].b, w);
919 9113
                p += w;
920 9113
                n++;
921
        }
922 1642
        *p++ = '\0';
923 1642
        assert(p <= e);
924 1642
        vbe16enc(p0, n + 1);
925 1642
}
926
927
/*--------------------------------------------------------------------
928
 * Decode byte string into http struct
929
 */
930
931
int
932 2239
HTTP_Decode(struct http *to, const uint8_t *fm)
933
{
934
935 2239
        CHECK_OBJ_NOTNULL(to, HTTP_MAGIC);
936 2239
        AN(to->vsl);
937 2239
        AN(fm);
938 2239
        if (vbe16dec(fm) <= to->shd) {
939 2238
                to->status = vbe16dec(fm + 2);
940 2238
                fm += 4;
941 19131
                for (to->nhd = 0; to->nhd < to->shd; to->nhd++) {
942 36023
                        if (to->nhd == HTTP_HDR_METHOD ||
943 16893
                            to->nhd == HTTP_HDR_URL) {
944 4473
                                to->hd[to->nhd].b = NULL;
945 4473
                                to->hd[to->nhd].e = NULL;
946 4473
                                continue;
947
                        }
948 14657
                        if (*fm == '\0')
949 2238
                                return (0);
950 12419
                        to->hd[to->nhd].b = (const void*)fm;
951 12419
                        fm = (const void*)strchr((const void*)fm, '\0');
952 12419
                        to->hd[to->nhd].e = (const void*)fm;
953 12419
                        fm++;
954 12419
                        http_VSLH(to, to->nhd);
955
                }
956
        }
957 3
        VSLb(to->vsl, SLT_Error,
958
            "Too many headers to Decode object (%u vs. %u)",
959 4
            vbe16dec(fm), to->shd);
960 1
        return (-1);
961
}
962
963
/*--------------------------------------------------------------------*/
964
965
uint16_t
966 1
HTTP_GetStatusPack(struct worker *wrk, struct objcore *oc)
967
{
968
        const char *ptr;
969 1
        ptr = ObjGetAttr(wrk, oc, OA_HEADERS, NULL);
970 1
        AN(ptr);
971
972 1
        return(vbe16dec(ptr + 2));
973
}
974
975
/*--------------------------------------------------------------------*/
976
977
/* Get the first packed header */
978
int
979 157
HTTP_IterHdrPack(struct worker *wrk, struct objcore *oc, const char **p)
980
{
981
        const char *ptr;
982
983 157
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
984 157
        CHECK_OBJ_NOTNULL(oc, OBJCORE_MAGIC);
985 157
        AN(p);
986
987 157
        if (*p == NULL) {
988 73
                ptr = ObjGetAttr(wrk, oc, OA_HEADERS, NULL);
989 73
                AN(ptr);
990 73
                ptr += 4;       /* Skip nhd and status */
991 73
                ptr = strchr(ptr, '\0') + 1;    /* Skip :proto: */
992 73
                ptr = strchr(ptr, '\0') + 1;    /* Skip :status: */
993 73
                ptr = strchr(ptr, '\0') + 1;    /* Skip :reason: */
994 73
                *p = ptr;
995
        } else {
996 84
                *p = strchr(*p, '\0') + 1;      /* Skip to next header */
997
        }
998 157
        if (**p == '\0')
999 19
                return (0);
1000 138
        return (1);
1001
}
1002
1003
const char *
1004 76
HTTP_GetHdrPack(struct worker *wrk, struct objcore *oc, const char *hdr)
1005
{
1006
        const char *ptr;
1007
        unsigned l;
1008
1009 76
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
1010 76
        CHECK_OBJ_NOTNULL(oc, OBJCORE_MAGIC);
1011 76
        AN(hdr);
1012
1013 76
        l = hdr[0];
1014 76
        assert(l > 0);
1015 76
        assert(l == strlen(hdr + 1));
1016 76
        assert(hdr[l] == ':');
1017 76
        hdr++;
1018
1019 76
        if (hdr[0] == ':') {
1020
                /* Special cases */
1021 3
                ptr = ObjGetAttr(wrk, oc, OA_HEADERS, NULL);
1022 3
                AN(ptr);
1023 3
                ptr += 4;       /* Skip nhd and status */
1024
1025 3
                if (!strcmp(hdr, ":proto:"))
1026 1
                        return (ptr);
1027 2
                ptr = strchr(ptr, '\0') + 1;
1028 2
                if (!strcmp(hdr, ":status:"))
1029 1
                        return (ptr);
1030 1
                ptr = strchr(ptr, '\0') + 1;
1031 1
                if (!strcmp(hdr, ":reason:"))
1032 1
                        return (ptr);
1033 0
                WRONG("Unknown magic packed header");
1034
        }
1035
1036 230
        HTTP_FOREACH_PACK(wrk, oc, ptr) {
1037 138
                if (!strncasecmp(ptr, hdr, l)) {
1038 54
                        ptr += l;
1039 161
                        while (vct_islws(*ptr))
1040 53
                                ptr++;
1041 54
                        return (ptr);
1042
                }
1043
        }
1044
1045 19
        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 18
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 18
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
1062 18
        CHECK_OBJ_NOTNULL(oc, OBJCORE_MAGIC);
1063 18
        CHECK_OBJ_NOTNULL(to, HTTP_MAGIC);
1064
1065 18
        ptr = ObjGetAttr(wrk, oc, OA_HEADERS, NULL);
1066 18
        AN(ptr);
1067
1068 18
        to->status = vbe16dec(ptr + 2);
1069 18
        ptr += 4;
1070
1071 108
        for (u = 0; u < HTTP_HDR_FIRST; u++) {
1072 90
                if (u == HTTP_HDR_METHOD || u == HTTP_HDR_URL)
1073 36
                        continue;
1074 54
                http_SetH(to, u, ptr);
1075 54
                ptr = strchr(ptr, '\0') + 1;
1076
        }
1077 18
        nhd_before_merge = to->nhd;
1078 105
        while (*ptr != '\0') {
1079 69
                p = strchr(ptr, ':');
1080 69
                AN(p);
1081 69
                u = http_findhdr(to, p - ptr, ptr);
1082 69
                if (u == 0 || u >= nhd_before_merge)
1083 38
                        http_SetHeader(to, ptr);
1084 69
                ptr = strchr(ptr, '\0') + 1;
1085
        }
1086 18
}
1087
1088
/*--------------------------------------------------------------------*/
1089
1090
static void
1091 1655
http_filterfields(struct http *to, const struct http *fm, unsigned how)
1092
{
1093
        unsigned u;
1094
1095 1655
        CHECK_OBJ_NOTNULL(fm, HTTP_MAGIC);
1096 1655
        CHECK_OBJ_NOTNULL(to, HTTP_MAGIC);
1097 1655
        to->nhd = HTTP_HDR_FIRST;
1098 1655
        to->status = fm->status;
1099 5487
        for (u = HTTP_HDR_FIRST; u < fm->nhd; u++) {
1100 3832
                Tcheck(fm->hd[u]);
1101 3832
                if (fm->hdf[u] & HDF_FILTER)
1102 2
                        continue;
1103 3830
                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 3785
                assert (to->nhd < to->shd);
1109 3785
                to->hd[to->nhd] = fm->hd[u];
1110 3785
                to->hdf[to->nhd] = 0;
1111 3785
                http_VSLH(to, to->nhd);
1112 3785
                to->nhd++;
1113
        }
1114 1655
}
1115
1116
/*--------------------------------------------------------------------*/
1117
1118
static void
1119 4965
http_linkh(const struct http *to, const struct http *fm, unsigned n)
1120
{
1121
1122 4965
        assert(n < HTTP_HDR_FIRST);
1123 4965
        Tcheck(fm->hd[n]);
1124 4965
        to->hd[n] = fm->hd[n];
1125 4965
        to->hdf[n] = fm->hdf[n];
1126 4965
        http_VSLH(to, n);
1127 4965
}
1128
1129
/*--------------------------------------------------------------------*/
1130
1131
void
1132 1655
http_FilterReq(struct http *to, const struct http *fm, unsigned how)
1133
{
1134 1655
        CHECK_OBJ_NOTNULL(to, HTTP_MAGIC);
1135 1655
        CHECK_OBJ_NOTNULL(fm, HTTP_MAGIC);
1136
1137 1655
        http_linkh(to, fm, HTTP_HDR_METHOD);
1138 1655
        http_linkh(to, fm, HTTP_HDR_URL);
1139 1655
        http_linkh(to, fm, HTTP_HDR_PROTO);
1140 1655
        to->protover = fm->protover;
1141 1655
        http_filterfields(to, fm, how);
1142 1655
}
1143
1144
/*--------------------------------------------------------------------
1145
 * This function copies any header fields which reference foreign
1146
 * storage into our own WS.
1147
 */
1148
1149
void
1150 1641
http_CopyHome(const struct http *hp)
1151
{
1152
        unsigned u, l;
1153
        char *p;
1154
1155 14627
        for (u = 0; u < hp->nhd; u++) {
1156 12986
                if (hp->hd[u].b == NULL) {
1157 3282
                        assert(u < HTTP_HDR_FIRST);
1158 3282
                        continue;
1159
                }
1160 9704
                if (WS_Inside(hp->ws, hp->hd[u].b, hp->hd[u].e))
1161 1031
                        continue;
1162
1163 8673
                l = Tlen(hp->hd[u]);
1164 8673
                p = WS_Copy(hp->ws, hp->hd[u].b, l + 1L);
1165 8673
                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 8673
                hp->hd[u].b = p;
1171 8673
                hp->hd[u].e = p + l;
1172
        }
1173
}
1174
1175
/*--------------------------------------------------------------------*/
1176
1177
void
1178 8078
http_SetHeader(struct http *to, const char *hdr)
1179
{
1180
1181 8078
        CHECK_OBJ_NOTNULL(to, HTTP_MAGIC);
1182 8078
        if (to->nhd >= to->shd) {
1183 0
                VSLb(to->vsl, SLT_LostHeader, "%s", hdr);
1184 0
                http_fail(to);
1185 0
                return;
1186
        }
1187 8078
        http_SetH(to, to->nhd++, hdr);
1188
}
1189
1190
/*--------------------------------------------------------------------*/
1191
1192
void
1193 3302
http_ForceHeader(struct http *to, const char *hdr, const char *val)
1194
{
1195
1196 3302
        CHECK_OBJ_NOTNULL(to, HTTP_MAGIC);
1197 3302
        if (http_HdrIs(to, hdr, val))
1198 167
                return;
1199 3135
        http_Unset(to, hdr);
1200 3135
        http_PrintfHeader(to, "%s %s", hdr + 1, val);
1201
}
1202
1203
void
1204 12608
http_PrintfHeader(struct http *to, const char *fmt, ...)
1205
{
1206
        va_list ap;
1207
        unsigned l, n;
1208
1209 12608
        CHECK_OBJ_NOTNULL(to, HTTP_MAGIC);
1210 12608
        l = WS_Reserve(to->ws, 0);
1211 12608
        va_start(ap, fmt);
1212 12608
        n = vsnprintf(to->ws->f, l, fmt, ap);
1213 12608
        va_end(ap);
1214 12608
        if (n + 1 >= l || to->nhd >= to->shd) {
1215 18
                http_fail(to);
1216 18
                va_start(ap, fmt);
1217 18
                VSLbv(to->vsl, SLT_LostHeader, fmt, ap);
1218 18
                va_end(ap);
1219 18
                WS_Release(to->ws, 0);
1220 18
                return;
1221
        }
1222 12590
        to->hd[to->nhd].b = to->ws->f;
1223 12590
        to->hd[to->nhd].e = to->ws->f + n;
1224 12590
        to->hdf[to->nhd] = 0;
1225 12590
        WS_Release(to->ws, n + 1);
1226 12590
        http_VSLH(to, to->nhd);
1227 12590
        to->nhd++;
1228
}
1229
1230
void
1231 1949
http_TimeHeader(struct http *to, const char *fmt, double now)
1232
{
1233
        char *p;
1234
1235 1949
        CHECK_OBJ_NOTNULL(to, HTTP_MAGIC);
1236 1949
        if (to->nhd >= to->shd) {
1237 0
                VSLb(to->vsl, SLT_LostHeader, "%s", fmt);
1238 0
                http_fail(to);
1239 0
                return;
1240
        }
1241 1949
        p = WS_Alloc(to->ws, strlen(fmt) + VTIM_FORMAT_SIZE);
1242 1949
        if (p == NULL) {
1243 49
                http_fail(to);
1244 49
                VSLb(to->vsl, SLT_LostHeader, "%s", fmt);
1245 49
                return;
1246
        }
1247 1900
        strcpy(p, fmt);
1248 1900
        VTIM_format(now, strchr(p, '\0'));
1249 1900
        to->hd[to->nhd].b = p;
1250 1900
        to->hd[to->nhd].e = strchr(p, '\0');
1251 1900
        to->hdf[to->nhd] = 0;
1252 1900
        http_VSLH(to, to->nhd);
1253 1900
        to->nhd++;
1254
}
1255
1256
/*--------------------------------------------------------------------*/
1257
1258
void
1259 10962
http_Unset(struct http *hp, const char *hdr)
1260
{
1261
        uint16_t u, v;
1262
1263 62553
        for (v = u = HTTP_HDR_FIRST; u < hp->nhd; u++) {
1264 51591
                Tcheck(hp->hd[u]);
1265 51591
                if (http_IsHdr(&hp->hd[u], hdr)) {
1266 500
                        http_VSLH_del(hp, u);
1267 500
                        continue;
1268
                }
1269 51091
                if (v != u) {
1270 1319
                        memcpy(&hp->hd[v], &hp->hd[u], sizeof *hp->hd);
1271 1319
                        memcpy(&hp->hdf[v], &hp->hdf[u], sizeof *hp->hdf);
1272
                }
1273 51091
                v++;
1274
        }
1275 10962
        hp->nhd = v;
1276 10962
}
1277
1278
/*--------------------------------------------------------------------*/
1279
1280
void
1281 688
HTTP_Init(void)
1282
{
1283
1284
#define HTTPH(a, b, c) b[0] = (char)strlen(b + 1);
1285
#include "tbl/http_headers.h"
1286 688
}