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