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 56571
http_VSLH(const struct http *hp, unsigned hdr)
58
{
59
        int i;
60
61 56571
        if (hp->vsl != NULL) {
62 56572
                AN(hp->vsl->wid & (VSL_CLIENTMARKER|VSL_BACKENDMARKER));
63 56572
                i = hdr;
64 56572
                if (i > HTTP_HDR_FIRST)
65 23584
                        i = HTTP_HDR_FIRST;
66 56572
                i += hp->logtag;
67 56572
                VSLbt(hp->vsl, (enum VSL_tag_e)i, hp->hd[hdr]);
68
        }
69 56567
}
70
71
static void
72 468
http_VSLH_del(const struct http *hp, unsigned hdr)
73
{
74
        int i;
75
76 468
        if (hp->vsl != NULL) {
77
                /* We don't support unsetting stuff in the first line */
78 468
                assert (hdr >= HTTP_HDR_FIRST);
79 468
                AN(hp->vsl->wid & (VSL_CLIENTMARKER|VSL_BACKENDMARKER));
80 468
                i = (HTTP_HDR_UNSET - HTTP_HDR_METHOD);
81 468
                i += hp->logtag;
82 468
                VSLbt(hp->vsl, (enum VSL_tag_e)i, hp->hd[hdr]);
83
        }
84 468
}
85
86
/*--------------------------------------------------------------------*/
87
88
void
89 3246
http_VSL_log(const struct http *hp)
90
{
91
        unsigned u;
92
93 22192
        for (u = 0; u < hp->nhd; u++)
94 18946
                if (hp->hd[u].b != NULL)
95 12454
                        http_VSLH(hp, u);
96 3246
}
97
98
/*--------------------------------------------------------------------*/
99
100
static void
101 26
http_fail(const struct http *hp)
102
{
103
104 26
        VSC_C_main->losthdr++;
105 26
        VSLb(hp->vsl, SLT_Error, "out of workspace (%s)", hp->ws->id);
106 26
        WS_MarkOverflow(hp->ws);
107 26
}
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 510
http_Status2Reason(unsigned status, const char **sstr)
124
{
125
        struct http_msg *mp;
126
127 510
        status %= 1000;
128 510
        assert(status >= 100);
129 12707
        for (mp = http_msg; mp->nbr != 0 && mp->nbr <= status; mp++)
130 12673
                if (mp->nbr == status) {
131 476
                        if (sstr)
132 375
                                *sstr = mp->status;
133 476
                        return (mp->txt);
134
                }
135 34
        return ("Unknown HTTP Status");
136
}
137
138
/*--------------------------------------------------------------------*/
139
140
unsigned
141 2876
HTTP_estimate(unsigned nhttp)
142
{
143
144
        /* XXX: We trust the structs to size-aligned as necessary */
145 2876
        return (PRNDUP(sizeof (struct http) + sizeof(txt) * nhttp + nhttp));
146
}
147
148
struct http *
149 8674
HTTP_create(void *p, uint16_t nhttp, unsigned len)
150
{
151
        struct http *hp;
152
153 8674
        hp = p;
154 8674
        hp->magic = HTTP_MAGIC;
155 8674
        hp->hd = (void*)(hp + 1);
156 8674
        hp->shd = nhttp;
157 8674
        hp->hdf = (void*)(hp->hd + nhttp);
158 8674
        assert((unsigned char*)p + len == hp->hdf + nhttp);
159 8674
        return (hp);
160
}
161
162
/*--------------------------------------------------------------------*/
163
164
void
165 7832
HTTP_Setup(struct http *hp, struct ws *ws, struct vsl_log *vsl,
166
    enum VSL_tag_e  whence)
167
{
168 7832
        http_Teardown(hp);
169 7831
        hp->nhd = HTTP_HDR_FIRST;
170 7831
        hp->logtag = whence;
171 7831
        hp->ws = ws;
172 7831
        hp->vsl = vsl;
173 7831
}
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 12477
http_Teardown(struct http *hp)
183
{
184
185 12477
        CHECK_OBJ_NOTNULL(hp, HTTP_MAGIC);
186 12477
        AN(hp->shd);
187 12477
        memset(&hp->nhd, 0, sizeof *hp - offsetof(struct http, nhd));
188 12477
        memset(hp->hd, 0, sizeof *hp->hd * hp->shd);
189 12477
        memset(hp->hdf, 0, sizeof *hp->hdf * hp->shd);
190 12477
}
191
192
/*--------------------------------------------------------------------*/
193
194
void
195 3575
HTTP_Copy(struct http *to, const struct http * const fm)
196
{
197
198 3575
        assert(fm->nhd <= to->shd);
199 3575
        memcpy(&to->nhd, &fm->nhd, sizeof *to - offsetof(struct http, nhd));
200 3575
        memcpy(to->hd, fm->hd, fm->nhd * sizeof *to->hd);
201 3575
        memcpy(to->hdf, fm->hdf, fm->nhd * sizeof *to->hdf);
202 3575
        to->protover = fm->protover;
203 3575
}
204
205
/*--------------------------------------------------------------------*/
206
207
void
208 3442
http_Proto(struct http *to)
209
{
210
        const char *fm;
211
212 3442
        fm = to->hd[HTTP_HDR_PROTO].b;
213
214 6882
        if ((fm[0] == 'H' || fm[0] == 'h') &&
215 6880
            (fm[1] == 'T' || fm[1] == 't') &&
216 6880
            (fm[2] == 'T' || fm[2] == 't') &&
217 6880
            (fm[3] == 'P' || fm[3] == 'p') &&
218 6880
            fm[4] == '/' &&
219 6880
            vct_isdigit(fm[5]) &&
220 6880
            fm[6] == '.' &&
221 6880
            vct_isdigit(fm[7]) &&
222 3440
            fm[8] == '\0') {
223 3440
                to->protover = 10 * (fm[5] - '0') + (fm[7] - '0');
224
        } else {
225 2
                to->protover = 0;
226
        }
227 3442
}
228
229
/*--------------------------------------------------------------------*/
230
231
void
232 8131
http_SetH(struct http *to, unsigned n, const char *fm)
233
{
234
235 8131
        assert(n < to->nhd);
236 8131
        AN(fm);
237 8131
        to->hd[n].b = TRUST_ME(fm);
238 8131
        to->hd[n].e = strchr(to->hd[n].b, '\0');
239 8131
        to->hdf[n] = 0;
240 8131
        http_VSLH(to, n);
241 8131
        if (n == HTTP_HDR_PROTO)
242 491
                http_Proto(to);
243 8131
}
244
245
/*--------------------------------------------------------------------*/
246
247
static void
248 30
http_PutField(struct http *to, int field, const char *string)
249
{
250
        char *p;
251
252 30
        CHECK_OBJ_NOTNULL(to, HTTP_MAGIC);
253 30
        p = WS_Copy(to->ws, string, -1);
254 30
        if (p == NULL) {
255 1
                http_fail(to);
256 1
                VSLb(to->vsl, SLT_LostHeader, "%s", string);
257 31
                return;
258
        }
259 29
        to->hd[field].b = p;
260 29
        to->hd[field].e = strchr(p, '\0');
261 29
        to->hdf[field] = 0;
262 29
        http_VSLH(to, field);
263 29
        if (field == HTTP_HDR_PROTO)
264 0
                http_Proto(to);
265
}
266
267
/*--------------------------------------------------------------------*/
268
269
static int
270 230406
http_IsHdr(const txt *hh, const char *hdr)
271
{
272
        unsigned l;
273
274 230406
        Tcheck(*hh);
275 230406
        AN(hdr);
276 230406
        l = hdr[0];
277 230406
        assert(l == strlen(hdr + 1));
278 230406
        assert(hdr[l] == ':');
279 230406
        hdr++;
280 230406
        return (!strncasecmp(hdr, hh->b, l));
281
}
282
283
/*--------------------------------------------------------------------*/
284
285
static unsigned
286 64213
http_findhdr(const struct http *hp, unsigned l, const char *hdr)
287
{
288
        unsigned u;
289
290 189494
        for (u = HTTP_HDR_FIRST; u < hp->nhd; u++) {
291 134092
                Tcheck(hp->hd[u]);
292 134095
                if (hp->hd[u].e < hp->hd[u].b + l + 1)
293 19997
                        continue;
294 114098
                if (hp->hd[u].b[l] != ':')
295 94225
                        continue;
296 19873
                if (strncasecmp(hdr, hp->hd[u].b, l))
297 11059
                        continue;
298 8814
                return (u);
299
        }
300 55402
        return (0);
301
}
302
303
/*--------------------------------------------------------------------
304
 * Count how many instances we have of this header
305
 */
306
307
unsigned
308 3301
http_CountHdr(const struct http *hp, const char *hdr)
309
{
310 3301
        unsigned retval = 0;
311
        unsigned u;
312
313 3301
        CHECK_OBJ_NOTNULL(hp, HTTP_MAGIC);
314
315 4593
        for (u = HTTP_HDR_FIRST; u < hp->nhd; u++) {
316 1292
                Tcheck(hp->hd[u]);
317 1292
                if (http_IsHdr(&hp->hd[u], hdr))
318 72
                        retval++;
319
        }
320 3301
        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 9320
http_CollectHdr(struct http *hp, const char *hdr)
330
{
331
332 9320
        http_CollectHdrSep(hp, hdr, NULL);
333 9319
}
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 9366
http_CollectHdrSep(struct http *hp, const char *hdr, const char *sep)
343
{
344
        unsigned u, l, lsep, ml, f, x, d;
345 9366
        char *b = NULL, *e = NULL;
346
        const char *v;
347
348 9366
        CHECK_OBJ_NOTNULL(hp, HTTP_MAGIC);
349 9366
        if (WS_Overflowed(hp->ws))
350 10
                return;
351
352 9356
        if (sep == NULL || *sep == '\0')
353 9310
                sep = ", ";
354 9356
        lsep = strlen(sep);
355
356 9356
        l = hdr[0];
357 9356
        assert(l == strlen(hdr + 1));
358 9356
        assert(hdr[l] == ':');
359 9356
        f = http_findhdr(hp, l - 1, hdr + 1);
360 9355
        if (f == 0)
361 9113
                return;
362
363 675
        for (d = u = f + 1; u < hp->nhd; u++) {
364 433
                Tcheck(hp->hd[u]);
365 433
                if (!http_IsHdr(&hp->hd[u], hdr)) {
366 417
                        if (d != u) {
367 42
                                hp->hd[d] = hp->hd[u];
368 42
                                hp->hdf[d] = hp->hdf[u];
369
                        }
370 417
                        d++;
371 417
                        continue;
372
                }
373 16
                if (b == NULL) {
374
                        /* Found second header, start our collection */
375 14
                        ml = WS_Reserve(hp->ws, 0);
376 14
                        b = hp->ws->f;
377 14
                        e = b + ml;
378 14
                        x = Tlen(hp->hd[f]);
379 14
                        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 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 242
        if (b == NULL)
414 228
                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 54719
http_GetHdr(const struct http *hp, const char *hdr, const char **ptr)
427
{
428
        unsigned u, l;
429
        const char *p;
430
431 54719
        l = hdr[0];
432 54719
        assert(l == strlen(hdr + 1));
433 54719
        assert(hdr[l] == ':');
434 54719
        hdr++;
435 54719
        u = http_findhdr(hp, l - 1, hdr);
436 54726
        if (u == 0) {
437 46183
                if (ptr != NULL)
438 41259
                        *ptr = NULL;
439 46183
                return (0);
440
        }
441 8543
        if (ptr != NULL) {
442 6982
                p = hp->hd[u].b + l;
443 20894
                while (vct_issp(*p))
444 6930
                        p++;
445 6982
                *ptr = p;
446
        }
447 8543
        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 1080
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 1080
        AN(src);
464 1080
        AN(*src);
465 1080
        AN(sep);
466 1080
        AN(b);
467 1080
        AN(e);
468
469 1080
        if (stop == NULL)
470 1073
                stop = strchr(*src, '\0');
471
472 1145
        for (p = *src; p < stop && (vct_issp(*p) || strchr(sep, *p)); p++)
473 65
                continue;
474
475 1080
        if (p >= stop) {
476 381
                *b = NULL;
477 381
                *e = NULL;
478 381
                return (0);
479
        }
480
481 699
        *b = p;
482 699
        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 3463
        for (q = p + 1; q < stop && !strchr(sep, *q); q++)
490 2764
                continue;
491 699
        *src = q;
492 1398
        while (q > p && vct_issp(q[-1]))
493 0
                q--;
494 699
        *e = q;
495 699
        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 606
http_istoken(const char **bp, const char *e, const char *token)
509
{
510 606
        int fl = strlen(token);
511
        const char *b;
512
513 606
        AN(bp);
514 606
        AN(e);
515 606
        AN(token);
516
517 606
        b = *bp;
518
519 606
        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 886
        if (b + fl <= e && !strncasecmp(b, token, fl) &&
525 306
            (b + fl == e || !vct_istchar(b[fl]))) {
526 280
                *bp += fl;
527 280
                return (1);
528
        }
529 326
        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 6603
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 6603
        if (pb != NULL)
559 4695
                *pb = NULL;
560 6603
        if (pe != NULL)
561 1835
                *pe = NULL;
562 6603
        if (!http_GetHdr(hp, hdr, &h))
563 6026
                return (0);
564 578
        AN(h);
565
566 1482
        while (http_split(&h, NULL, ",", &b, &e))
567 606
                if (http_istoken(&b, e, token))
568 280
                        break;
569 578
        if (b == NULL)
570 298
                return (0);
571 280
        if (pb != NULL) {
572 280
                for (; vct_islws(*b); b++)
573 5
                        continue;
574 275
                if (b == e) {
575 250
                        b = NULL;
576 250
                        e = NULL;
577
                }
578 275
                *pb = b;
579 275
                if (pe != NULL)
580 257
                        *pe = e;
581
        }
582 280
        return (1);
583
}
584
585
/*--------------------------------------------------------------------
586
 * Find a given headerfields Q value.
587
 */
588
589
double
590 1834
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 1834
        i = http_GetHdrToken(hp, hdr, field, &hb, &he);
597 1834
        if (!i)
598 1577
                return (0.);
599
600 257
        if (hb == NULL)
601 250
                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 2861
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 2861
        if (ptr != NULL)
646 2861
                *ptr = NULL;
647
648 2861
        h = NULL;
649 2861
        i = http_GetHdrToken(hp, hdr, field, &h, NULL);
650 2861
        if (!i)
651 2843
                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 4859
http_GetContentLength(const struct http *hp)
671
{
672
        ssize_t cl, cll;
673
        const char *b;
674
675 4859
        CHECK_OBJ_NOTNULL(hp, HTTP_MAGIC);
676
677 4859
        if (!http_GetHdr(hp, H_Content_Length, &b))
678 1931
                return (-1);
679 2927
        cl = 0;
680 2927
        if (!vct_isdigit(*b))
681 3
                return (-2);
682 7104
        for (; vct_isdigit(*b); b++) {
683 4180
                cll = cl;
684 4180
                cl *= 10;
685 4180
                cl += *b - '0';
686 4180
                if (cll != cl / 10)
687 0
                        return (-2);
688
        }
689 5848
        while (vct_islws(*b))
690 0
                b++;
691 2924
        if (*b != '\0')
692 0
                return (-2);
693 2924
        return (cl);
694
}
695
696
/*--------------------------------------------------------------------
697
 */
698
699
enum sess_close
700 2944
http_DoConnection(struct http *hp)
701
{
702
        const char *h, *b, *e;
703
        enum sess_close retval;
704
        unsigned u, v;
705
706 2944
        if (hp->protover == 10)
707 31
                retval = SC_REQ_HTTP10;
708
        else
709 2913
                retval = SC_NULL;
710
711 2944
        http_CollectHdr(hp, H_Connection);
712 2944
        if (!http_GetHdr(hp, H_Connection, &h))
713 2860
                return (retval);
714 84
        AN(h);
715 253
        while (http_split(&h, NULL, ",", &b, &e)) {
716 86
                u = pdiff(b, e);
717 86
                if (u == 5 && !strncasecmp(b, "close", u))
718 71
                        retval = SC_REQ_CLOSE;
719 86
                if (u == 10 && !strncasecmp(b, "keep-alive", u))
720 9
                        retval = SC_NULL;
721
722
                /* Refuse removal of well-known-headers if they would pass. */
723
/*lint -save -e506 [constant value boolean] */
724
#define HTTPH(a, x, c)                                          \
725
                if (!((c) & HTTPH_R_PASS) &&                    \
726
                    strlen(a) == u && !strncasecmp(a, b, u))    \
727
                        return (SC_RX_BAD);
728
#include "tbl/http_headers.h"
729
/*lint -restore */
730
731 85
                v = http_findhdr(hp, u, b);
732 85
                if (v > 0)
733 3
                        hp->hdf[v] |= HDF_FILTER;
734
        }
735 83
        return (retval);
736
}
737
738
/*--------------------------------------------------------------------*/
739
740
int
741 6993
http_HdrIs(const struct http *hp, const char *hdr, const char *val)
742
{
743
        const char *p;
744
745 6993
        if (!http_GetHdr(hp, hdr, &p))
746 6665
                return (0);
747 331
        AN(p);
748 331
        if (!strcasecmp(p, val))
749 304
                return (1);
750 27
        return (0);
751
}
752
753
/*--------------------------------------------------------------------*/
754
755
uint16_t
756 4134
http_GetStatus(const struct http *hp)
757
{
758
759 4134
        CHECK_OBJ_NOTNULL(hp, HTTP_MAGIC);
760 4134
        return (hp->status);
761
}
762
763
int
764 8079
http_IsStatus(const struct http *hp, int val)
765
{
766
767 8079
        CHECK_OBJ_NOTNULL(hp, HTTP_MAGIC);
768 8079
        assert(val >= 100 && val <= 999);
769 8079
        return (val == (hp->status % 1000));
770
}
771
772
/*--------------------------------------------------------------------
773
 * Setting the status will also set the Reason appropriately
774
 */
775
776
void
777 405
http_SetStatus(struct http *to, uint16_t status)
778
{
779
        char buf[4];
780
        const char *reason;
781 405
        const char *sstr = NULL;
782
783 405
        CHECK_OBJ_NOTNULL(to, HTTP_MAGIC);
784
        /*
785
         * We allow people to use top digits for internal VCL
786
         * signalling, but strip them from the ASCII version.
787
         */
788 405
        to->status = status;
789 405
        status %= 1000;
790 405
        assert(status >= 100);
791
792 405
        reason = http_Status2Reason(status, &sstr);
793 405
        if (sstr) {
794 375
                http_SetH(to, HTTP_HDR_STATUS, sstr);
795
        } else {
796 30
                bprintf(buf, "%03d", status);
797 30
                http_PutField(to, HTTP_HDR_STATUS, buf);
798
        }
799 405
        http_SetH(to, HTTP_HDR_REASON, reason);
800 405
}
801
802
/*--------------------------------------------------------------------*/
803
804
const char *
805 2916
http_GetMethod(const struct http *hp)
806
{
807
808 2916
        CHECK_OBJ_NOTNULL(hp, HTTP_MAGIC);
809 2916
        Tcheck(hp->hd[HTTP_HDR_METHOD]);
810 2916
        return (hp->hd[HTTP_HDR_METHOD].b);
811
}
812
813
/*--------------------------------------------------------------------
814
 * Force a particular header field to a particular value
815
 */
816
817
void
818 4303
http_ForceField(struct http *to, unsigned n, const char *t)
819
{
820
        int i;
821
822 4303
        CHECK_OBJ_NOTNULL(to, HTTP_MAGIC);
823 4303
        assert(n < HTTP_HDR_FIRST);
824 4303
        AN(t);
825 4303
        if (to->hd[n].b == NULL || strcmp(to->hd[n].b, t)) {
826 63
                i = (HTTP_HDR_UNSET - HTTP_HDR_METHOD);
827 63
                i += to->logtag;
828 63
                if (n >= HTTP_HDR_FIRST)
829 0
                        VSLbt(to->vsl, (enum VSL_tag_e)i, to->hd[n]);
830 63
                http_SetH(to, n, t);
831
        }
832 4303
}
833
834
/*--------------------------------------------------------------------*/
835
836
void
837 365
http_PutResponse(struct http *to, const char *proto, uint16_t status,
838
    const char *reason)
839
{
840
841 365
        CHECK_OBJ_NOTNULL(to, HTTP_MAGIC);
842 365
        if (proto != NULL)
843 365
                http_SetH(to, HTTP_HDR_PROTO, proto);
844 365
        http_SetStatus(to, status);
845 365
        if (reason != NULL)
846 281
                http_SetH(to, HTTP_HDR_REASON, reason);
847 365
}
848
849
/*--------------------------------------------------------------------
850
 * Estimate how much workspace we need to Filter this header according
851
 * to 'how'.
852
 */
853
854
unsigned
855 1335
http_EstimateWS(const struct http *fm, unsigned how)
856
{
857
        unsigned u, l;
858
859 1335
        l = 4;
860 1335
        CHECK_OBJ_NOTNULL(fm, HTTP_MAGIC);
861 11496
        for (u = 0; u < fm->nhd; u++) {
862 10160
                if (u == HTTP_HDR_METHOD || u == HTTP_HDR_URL)
863 2672
                        continue;
864 7488
                Tcheck(fm->hd[u]);
865 7489
                if (fm->hdf[u] & HDF_FILTER)
866 1
                        continue;
867
#define HTTPH(a, b, c) \
868
                if (((c) & how) && http_IsHdr(&fm->hd[u], (b))) \
869
                        continue;
870
#include "tbl/http_headers.h"
871 7366
                l += Tlen(fm->hd[u]) + 1L;
872
        }
873 1336
        return (PRNDUP(l + 1L));
874
}
875
876
/*--------------------------------------------------------------------
877
 * Encode http struct as byte string.
878
 *
879
 * XXX: We could save considerable special-casing below by encoding also
880
 * XXX: H__Status, H__Reason and H__Proto into the string, but it would
881
 * XXX: add 26-30 bytes to all encoded objects to save a little code.
882
 * XXX: It could possibly be a good idea for later HTTP versions.
883
 */
884
885
void
886 1333
HTTP_Encode(const struct http *fm, uint8_t *p0, unsigned l, unsigned how)
887
{
888
        unsigned u, w;
889
        uint16_t n;
890
        uint8_t *p, *e;
891
892 1333
        AN(p0);
893 1333
        AN(l);
894 1333
        p = p0;
895 1333
        e = p + l;
896 1333
        assert(p + 5 <= e);
897 1333
        assert(fm->nhd <= fm->shd);
898 1333
        n = HTTP_HDR_FIRST - 3;
899 1333
        vbe16enc(p + 2, fm->status);
900 1333
        p += 4;
901 1333
        CHECK_OBJ_NOTNULL(fm, HTTP_MAGIC);
902 11469
        for (u = 0; u < fm->nhd; u++) {
903 10136
                if (u == HTTP_HDR_METHOD || u == HTTP_HDR_URL)
904 2666
                        continue;
905 7470
                Tcheck(fm->hd[u]);
906 7470
                if (fm->hdf[u] & HDF_FILTER)
907 1
                        continue;
908
#define HTTPH(a, b, c) \
909
                if (((c) & how) && http_IsHdr(&fm->hd[u], (b))) \
910
                        continue;
911
#include "tbl/http_headers.h"
912 7352
                http_VSLH(fm, u);
913 7350
                w = Tlen(fm->hd[u]) + 1L;
914 7350
                assert(p + w + 1 <= e);
915 7350
                memcpy(p, fm->hd[u].b, w);
916 7350
                p += w;
917 7350
                n++;
918
        }
919 1333
        *p++ = '\0';
920 1333
        assert(p <= e);
921 1333
        vbe16enc(p0, n + 1);
922 1333
}
923
924
/*--------------------------------------------------------------------
925
 * Decode byte string into http struct
926
 */
927
928
int
929 1786
HTTP_Decode(struct http *to, const uint8_t *fm)
930
{
931
932 1786
        CHECK_OBJ_NOTNULL(to, HTTP_MAGIC);
933 1786
        AN(to->vsl);
934 1786
        AN(fm);
935 1786
        if (vbe16dec(fm) <= to->shd) {
936 1785
                to->status = vbe16dec(fm + 2);
937 1785
                fm += 4;
938 15172
                for (to->nhd = 0; to->nhd < to->shd; to->nhd++) {
939 28559
                        if (to->nhd == HTTP_HDR_METHOD ||
940 13387
                            to->nhd == HTTP_HDR_URL) {
941 3570
                                to->hd[to->nhd].b = NULL;
942 3570
                                to->hd[to->nhd].e = NULL;
943 3570
                                continue;
944
                        }
945 11602
                        if (*fm == '\0')
946 1785
                                return (0);
947 9817
                        to->hd[to->nhd].b = (const void*)fm;
948 9817
                        fm = (const void*)strchr((const void*)fm, '\0');
949 9817
                        to->hd[to->nhd].e = (const void*)fm;
950 9817
                        fm++;
951 9817
                        http_VSLH(to, to->nhd);
952
                }
953
        }
954 2
        VSLb(to->vsl, SLT_Error,
955
            "Too many headers to Decode object (%u vs. %u)",
956 2
            vbe16dec(fm), to->shd);
957 1
        return (-1);
958
}
959
960
/*--------------------------------------------------------------------*/
961
962
uint16_t
963 1
HTTP_GetStatusPack(struct worker *wrk, struct objcore *oc)
964
{
965
        const char *ptr;
966 1
        ptr = ObjGetAttr(wrk, oc, OA_HEADERS, NULL);
967 1
        AN(ptr);
968
969 1
        return(vbe16dec(ptr + 2));
970
}
971
972
/*--------------------------------------------------------------------*/
973
974
/* Get the first packed header */
975
int
976 142
HTTP_IterHdrPack(struct worker *wrk, struct objcore *oc, const char **p)
977
{
978
        const char *ptr;
979
980 142
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
981 142
        CHECK_OBJ_NOTNULL(oc, OBJCORE_MAGIC);
982 142
        AN(p);
983
984 142
        if (*p == NULL) {
985 67
                ptr = ObjGetAttr(wrk, oc, OA_HEADERS, NULL);
986 67
                AN(ptr);
987 67
                ptr += 4;       /* Skip nhd and status */
988 67
                ptr = strchr(ptr, '\0') + 1;    /* Skip :proto: */
989 67
                ptr = strchr(ptr, '\0') + 1;    /* Skip :status: */
990 67
                ptr = strchr(ptr, '\0') + 1;    /* Skip :reason: */
991 67
                *p = ptr;
992
        } else {
993 75
                *p = strchr(*p, '\0') + 1;      /* Skip to next header */
994
        }
995 142
        if (**p == '\0')
996 16
                return (0);
997 126
        return (1);
998
}
999
1000
const char *
1001 70
HTTP_GetHdrPack(struct worker *wrk, struct objcore *oc, const char *hdr)
1002
{
1003
        const char *ptr;
1004
        unsigned l;
1005
1006 70
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
1007 70
        CHECK_OBJ_NOTNULL(oc, OBJCORE_MAGIC);
1008 70
        AN(hdr);
1009
1010 70
        l = hdr[0];
1011 70
        assert(l > 0);
1012 70
        assert(l == strlen(hdr + 1));
1013 70
        assert(hdr[l] == ':');
1014 70
        hdr++;
1015
1016 70
        if (hdr[0] == ':') {
1017
                /* Special cases */
1018 3
                ptr = ObjGetAttr(wrk, oc, OA_HEADERS, NULL);
1019 3
                AN(ptr);
1020 3
                ptr += 4;       /* Skip nhd and status */
1021
1022 3
                if (!strcmp(hdr, ":proto:"))
1023 1
                        return (ptr);
1024 2
                ptr = strchr(ptr, '\0') + 1;
1025 2
                if (!strcmp(hdr, ":status:"))
1026 1
                        return (ptr);
1027 1
                ptr = strchr(ptr, '\0') + 1;
1028 1
                if (!strcmp(hdr, ":reason:"))
1029 1
                        return (ptr);
1030 0
                WRONG("Unknown magic packed header");
1031
        }
1032
1033 209
        HTTP_FOREACH_PACK(wrk, oc, ptr) {
1034 126
                if (!strncasecmp(ptr, hdr, l)) {
1035 51
                        ptr += l;
1036 152
                        while (vct_islws(*ptr))
1037 50
                                ptr++;
1038 51
                        return (ptr);
1039
                }
1040
        }
1041
1042 16
        return (NULL);
1043
}
1044
1045
/*--------------------------------------------------------------------
1046
 * Merge any headers in the oc->OA_HEADER into the struct http if they
1047
 * are not there already.
1048
 */
1049
1050
void
1051 13
HTTP_Merge(struct worker *wrk, struct objcore *oc, struct http *to)
1052
{
1053
        const char *ptr;
1054
        unsigned u;
1055
        const char *p;
1056
        unsigned nhd_before_merge;
1057
1058 13
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
1059 13
        CHECK_OBJ_NOTNULL(oc, OBJCORE_MAGIC);
1060 13
        CHECK_OBJ_NOTNULL(to, HTTP_MAGIC);
1061
1062 13
        ptr = ObjGetAttr(wrk, oc, OA_HEADERS, NULL);
1063 13
        AN(ptr);
1064
1065 13
        to->status = vbe16dec(ptr + 2);
1066 13
        ptr += 4;
1067
1068 78
        for (u = 0; u < HTTP_HDR_FIRST; u++) {
1069 65
                if (u == HTTP_HDR_METHOD || u == HTTP_HDR_URL)
1070 26
                        continue;
1071 39
                http_SetH(to, u, ptr);
1072 39
                ptr = strchr(ptr, '\0') + 1;
1073
        }
1074 13
        nhd_before_merge = to->nhd;
1075 77
        while (*ptr != '\0') {
1076 51
                p = strchr(ptr, ':');
1077 51
                AN(p);
1078 51
                u = http_findhdr(to, p - ptr, ptr);
1079 51
                if (u == 0 || u >= nhd_before_merge)
1080 26
                        http_SetHeader(to, ptr);
1081 51
                ptr = strchr(ptr, '\0') + 1;
1082
        }
1083 13
}
1084
1085
/*--------------------------------------------------------------------*/
1086
1087
static void
1088 1342
http_filterfields(struct http *to, const struct http *fm, unsigned how)
1089
{
1090
        unsigned u;
1091
1092 1342
        CHECK_OBJ_NOTNULL(fm, HTTP_MAGIC);
1093 1342
        CHECK_OBJ_NOTNULL(to, HTTP_MAGIC);
1094 1342
        to->nhd = HTTP_HDR_FIRST;
1095 1342
        to->status = fm->status;
1096 3215
        for (u = HTTP_HDR_FIRST; u < fm->nhd; u++) {
1097 1873
                Tcheck(fm->hd[u]);
1098 1873
                if (fm->hdf[u] & HDF_FILTER)
1099 2
                        continue;
1100 1871
                Tcheck(fm->hd[u]);
1101
#define HTTPH(a, b, c) \
1102
                if (((c) & how) && http_IsHdr(&fm->hd[u], (b))) \
1103
                        continue;
1104
#include "tbl/http_headers.h"
1105 1834
                assert (to->nhd < to->shd);
1106 1834
                to->hd[to->nhd] = fm->hd[u];
1107 1834
                to->hdf[to->nhd] = 0;
1108 1834
                http_VSLH(to, to->nhd);
1109 1834
                to->nhd++;
1110
        }
1111 1342
}
1112
1113
/*--------------------------------------------------------------------*/
1114
1115
static void
1116 4026
http_linkh(const struct http *to, const struct http *fm, unsigned n)
1117
{
1118
1119 4026
        assert(n < HTTP_HDR_FIRST);
1120 4026
        Tcheck(fm->hd[n]);
1121 4026
        to->hd[n] = fm->hd[n];
1122 4026
        to->hdf[n] = fm->hdf[n];
1123 4026
        http_VSLH(to, n);
1124 4026
}
1125
1126
/*--------------------------------------------------------------------*/
1127
1128
void
1129 1342
http_FilterReq(struct http *to, const struct http *fm, unsigned how)
1130
{
1131 1342
        CHECK_OBJ_NOTNULL(to, HTTP_MAGIC);
1132 1342
        CHECK_OBJ_NOTNULL(fm, HTTP_MAGIC);
1133
1134 1342
        http_linkh(to, fm, HTTP_HDR_METHOD);
1135 1342
        http_linkh(to, fm, HTTP_HDR_URL);
1136 1342
        http_linkh(to, fm, HTTP_HDR_PROTO);
1137 1342
        to->protover = fm->protover;
1138 1342
        http_filterfields(to, fm, how);
1139 1342
}
1140
1141
/*--------------------------------------------------------------------
1142
 * This function copies any header fields which reference foreign
1143
 * storage into our own WS.
1144
 */
1145
1146
void
1147 1330
http_CopyHome(const struct http *hp)
1148
{
1149
        unsigned u, l;
1150
        char *p;
1151
1152 10738
        for (u = 0; u < hp->nhd; u++) {
1153 9408
                if (hp->hd[u].b == NULL) {
1154 2660
                        assert(u < HTTP_HDR_FIRST);
1155 2660
                        continue;
1156
                }
1157 6748
                if (WS_Inside(hp->ws, hp->hd[u].b, hp->hd[u].e))
1158 944
                        continue;
1159
1160 5804
                l = Tlen(hp->hd[u]);
1161 5804
                p = WS_Copy(hp->ws, hp->hd[u].b, l + 1L);
1162 5804
                if (p == NULL) {
1163 0
                        http_fail(hp);
1164 0
                        VSLb(hp->vsl, SLT_LostHeader, "%s", hp->hd[u].b);
1165 1330
                        return;
1166
                }
1167 5804
                hp->hd[u].b = p;
1168 5804
                hp->hd[u].e = p + l;
1169
        }
1170
}
1171
1172
/*--------------------------------------------------------------------*/
1173
1174
void
1175 6269
http_SetHeader(struct http *to, const char *hdr)
1176
{
1177
1178 6269
        CHECK_OBJ_NOTNULL(to, HTTP_MAGIC);
1179 6269
        if (to->nhd >= to->shd) {
1180 0
                VSLb(to->vsl, SLT_LostHeader, "%s", hdr);
1181 0
                http_fail(to);
1182 6269
                return;
1183
        }
1184 6269
        http_SetH(to, to->nhd++, hdr);
1185
}
1186
1187
/*--------------------------------------------------------------------*/
1188
1189
void
1190 2771
http_ForceHeader(struct http *to, const char *hdr, const char *val)
1191
{
1192
1193 2771
        CHECK_OBJ_NOTNULL(to, HTTP_MAGIC);
1194 2771
        if (http_HdrIs(to, hdr, val))
1195 2935
                return;
1196 2609
        http_Unset(to, hdr);
1197 2609
        http_PrintfHeader(to, "%s %s", hdr + 1, val);
1198
}
1199
1200
void
1201 11395
http_PrintfHeader(struct http *to, const char *fmt, ...)
1202
{
1203
        va_list ap;
1204
        unsigned l, n;
1205
1206 11395
        CHECK_OBJ_NOTNULL(to, HTTP_MAGIC);
1207 11395
        l = WS_Reserve(to->ws, 0);
1208 11395
        va_start(ap, fmt);
1209 11395
        n = vsnprintf(to->ws->f, l, fmt, ap);
1210 11395
        va_end(ap);
1211 11395
        if (n + 1 >= l || to->nhd >= to->shd) {
1212 6
                http_fail(to);
1213 6
                va_start(ap, fmt);
1214 6
                VSLbv(to->vsl, SLT_LostHeader, fmt, ap);
1215 6
                va_end(ap);
1216 6
                WS_Release(to->ws, 0);
1217 11400
                return;
1218
        }
1219 11389
        to->hd[to->nhd].b = to->ws->f;
1220 11389
        to->hd[to->nhd].e = to->ws->f + n;
1221 11389
        to->hdf[to->nhd] = 0;
1222 11389
        WS_Release(to->ws, n + 1);
1223 11389
        http_VSLH(to, to->nhd);
1224 11388
        to->nhd++;
1225
}
1226
1227
void
1228 1561
http_TimeHeader(struct http *to, const char *fmt, double now)
1229
{
1230
        char *p;
1231
1232 1561
        CHECK_OBJ_NOTNULL(to, HTTP_MAGIC);
1233 1561
        p = WS_Alloc(to->ws, strlen(fmt) + VTIM_FORMAT_SIZE);
1234 1561
        if (p == NULL) {
1235 19
                http_fail(to);
1236 19
                VSLb(to->vsl, SLT_LostHeader, "%s", fmt);
1237 1581
                return;
1238
        }
1239 1542
        strcpy(p, fmt);
1240 1542
        VTIM_format(now, strchr(p, '\0'));
1241 1542
        to->hd[to->nhd].b = p;
1242 1542
        to->hd[to->nhd].e = strchr(p, '\0');
1243 1542
        to->hdf[to->nhd] = 0;
1244 1542
        http_VSLH(to, to->nhd);
1245 1543
        to->nhd++;
1246
}
1247
1248
/*--------------------------------------------------------------------*/
1249
1250
void
1251 9112
http_Unset(struct http *hp, const char *hdr)
1252
{
1253
        uint16_t u, v;
1254
1255 47675
        for (v = u = HTTP_HDR_FIRST; u < hp->nhd; u++) {
1256 38562
                Tcheck(hp->hd[u]);
1257 38562
                if (http_IsHdr(&hp->hd[u], hdr)) {
1258 468
                        http_VSLH_del(hp, u);
1259 468
                        continue;
1260
                }
1261 38095
                if (v != u) {
1262 1217
                        memcpy(&hp->hd[v], &hp->hd[u], sizeof *hp->hd);
1263 1217
                        memcpy(&hp->hdf[v], &hp->hdf[u], sizeof *hp->hdf);
1264
                }
1265 38095
                v++;
1266
        }
1267 9113
        hp->nhd = v;
1268 9113
}
1269
1270
/*--------------------------------------------------------------------*/
1271
1272
void
1273 614
HTTP_Init(void)
1274
{
1275
1276
#define HTTPH(a, b, c) b[0] = (char)strlen(b + 1);
1277
#include "tbl/http_headers.h"
1278 614
}