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