1 #include <u.h>
2 #include <libc.h>
3 #include <bin.h>
4 #include <httpd.h>
5 #include "escape.h"
6 
7 typedef struct Hlex	Hlex;
8 typedef struct MimeHead	MimeHead;
9 
10 enum
11 {
12 	/*
13 	 * tokens
14 	 */
15 	Word	= 1,
16 	QString
17 };
18 
19 #define UlongMax	4294967295UL
20 
21 struct Hlex
22 {
23 	int	tok;
24 	int	eoh;
25 	int	eol;			/* end of header line encountered? */
26 	uchar	*hstart;		/* start of header */
27 	jmp_buf	jmp;			/* jmp here to parse header */
28 	char	wordval[HMaxWord];
29 	HConnect *c;
30 };
31 
32 struct MimeHead
33 {
34 	char	*name;
35 	void	(*parse)(Hlex*, char*);
36 	uchar	seen;
37 	uchar	ignore;
38 };
39 
40 static void	mimeaccept(Hlex*, char*);
41 static void	mimeacceptchar(Hlex*, char*);
42 static void	mimeacceptenc(Hlex*, char*);
43 static void	mimeacceptlang(Hlex*, char*);
44 static void	mimeagent(Hlex*, char*);
45 static void	mimeauthorization(Hlex*, char*);
46 static void	mimeconnection(Hlex*, char*);
47 static void	mimecontlen(Hlex*, char*);
48 static void	mimeexpect(Hlex*, char*);
49 static void	mimefresh(Hlex*, char*);
50 static void	mimefrom(Hlex*, char*);
51 static void	mimehost(Hlex*, char*);
52 static void	mimeifrange(Hlex*, char*);
53 static void	mimeignore(Hlex*, char*);
54 static void	mimematch(Hlex*, char*);
55 static void	mimemodified(Hlex*, char*);
56 static void	mimenomatch(Hlex*, char*);
57 static void	mimerange(Hlex*, char*);
58 static void	mimetransenc(Hlex*, char*);
59 static void	mimeunmodified(Hlex*, char*);
60 
61 /*
62  * headers seen also include
63  * allow  cache-control chargeto
64  * content-encoding content-language content-location content-md5 content-range content-type
65  * date etag expires forwarded last-modified max-forwards pragma
66  * proxy-agent proxy-authorization proxy-connection
67  * ua-color ua-cpu ua-os ua-pixels
68  * upgrade via x-afs-tokens x-serial-number
69  */
70 static MimeHead	mimehead[] =
71 {
72 	{"accept",		mimeaccept},
73 	{"accept-charset",	mimeacceptchar},
74 	{"accept-encoding",	mimeacceptenc},
75 	{"accept-language",	mimeacceptlang},
76 	{"authorization",	mimeauthorization},
77 	{"connection",		mimeconnection},
78 	{"content-length",	mimecontlen},
79 	{"expect",		mimeexpect},
80 	{"fresh",		mimefresh},
81 	{"from",		mimefrom},
82 	{"host",		mimehost},
83 	{"if-match",		mimematch},
84 	{"if-modified-since",	mimemodified},
85 	{"if-none-match",	mimenomatch},
86 	{"if-range",		mimeifrange},
87 	{"if-unmodified-since",	mimeunmodified},
88 	{"range",		mimerange},
89 	{"transfer-encoding",	mimetransenc},
90 	{"user-agent",		mimeagent},
91 };
92 
93 char*		hmydomain;
94 char*		hversion = "HTTP/1.1";
95 
96 static	void	lexhead(Hlex*);
97 static	void	parsejump(Hlex*, char*);
98 static	int	getc(Hlex*);
99 static	void	ungetc(Hlex*);
100 static	int	wordcr(Hlex*);
101 static	int	wordnl(Hlex*);
102 static	void	word(Hlex*, char*);
103 static	int	lex1(Hlex*, int);
104 static	int	lex(Hlex*);
105 static	int	lexbase64(Hlex*);
106 static	ulong	digtoul(char *s, char **e);
107 
108 /*
109  * flush an clean up junk from a request
110  */
111 void
hreqcleanup(HConnect * c)112 hreqcleanup(HConnect *c)
113 {
114 	int i;
115 
116 	hxferenc(&c->hout, 0);
117 	memset(&c->req, 0, sizeof(c->req));
118 	memset(&c->head, 0, sizeof(c->head));
119 	c->hpos = c->header;
120 	c->hstop = c->header;
121 	binfree(&c->bin);
122 	for(i = 0; i < nelem(mimehead); i++){
123 		mimehead[i].seen = 0;
124 		mimehead[i].ignore = 0;
125 	}
126 }
127 
128 /*
129  * list of tokens
130  * if the client is HTTP/1.0,
131  * ignore headers which match one of the tokens.
132  * restarts parsing if necessary.
133  */
134 static void
mimeconnection(Hlex * h,char * unused)135 mimeconnection(Hlex *h, char *unused)
136 {
137 	char *u, *p;
138 	int reparse, i;
139 
140 	reparse = 0;
141 	for(;;){
142 		while(lex(h) != Word)
143 			if(h->tok != ',')
144 				goto breakout;
145 
146 		if(cistrcmp(h->wordval, "keep-alive") == 0)
147 			h->c->head.persist = 1;
148 		else if(cistrcmp(h->wordval, "close") == 0)
149 			h->c->head.closeit = 1;
150 		else if(!http11(h->c)){
151 			for(i = 0; i < nelem(mimehead); i++){
152 				if(cistrcmp(mimehead[i].name, h->wordval) == 0){
153 					reparse = mimehead[i].seen && !mimehead[i].ignore;
154 					mimehead[i].ignore = 1;
155 					if(cistrcmp(mimehead[i].name, "authorization") == 0){
156 						h->c->head.authuser = nil;
157 						h->c->head.authpass = nil;
158 					}
159 				}
160 			}
161 		}
162 
163 		if(lex(h) != ',')
164 			break;
165 	}
166 
167 breakout:;
168 	/*
169 	 * if need to ignore headers we've already parsed,
170 	 * reset & start over.  need to save authorization
171 	 * info because it's written over when parsed.
172 	 */
173 	if(reparse){
174 		u = h->c->head.authuser;
175 		p = h->c->head.authpass;
176 		memset(&h->c->head, 0, sizeof(h->c->head));
177 		h->c->head.authuser = u;
178 		h->c->head.authpass = p;
179 
180 		h->c->hpos = h->hstart;
181 		longjmp(h->jmp, 1);
182 	}
183 }
184 
185 int
hparseheaders(HConnect * c,int timeout)186 hparseheaders(HConnect *c, int timeout)
187 {
188 	Hlex h;
189 
190 	c->head.fresh_thresh = 0;
191 	c->head.fresh_have = 0;
192 	c->head.persist = 0;
193 	if(c->req.vermaj == 0){
194 		c->head.host = hmydomain;
195 		return 1;
196 	}
197 
198 	memset(&h, 0, sizeof(h));
199 	h.c = c;
200 	if(timeout)
201 		alarm(timeout);
202 	if(hgethead(c, 1) < 0)
203 		return -1;
204 	if(timeout)
205 		alarm(0);
206 	h.hstart = c->hpos;
207 
208 	if(setjmp(h.jmp) == -1)
209 		return -1;
210 
211 	h.eol = 0;
212 	h.eoh = 0;
213 	h.tok = '\n';
214 	while(lex(&h) != '\n'){
215 		if(h.tok == Word && lex(&h) == ':')
216 			parsejump(&h, hstrdup(c, h.wordval));
217 		while(h.tok != '\n')
218 			lex(&h);
219 		h.eol = h.eoh;
220 	}
221 
222 	if(http11(c)){
223 		/*
224 		 * according to the http/1.1 spec,
225 		 * these rules must be followed
226 		 */
227 		if(c->head.host == nil){
228 			hfail(c, HBadReq, nil);
229 			return -1;
230 		}
231 		if(c->req.urihost != nil)
232 			c->head.host = c->req.urihost;
233 		/*
234 		 * also need to check host is actually this one
235 		 */
236 	}else if(c->head.host == nil)
237 		c->head.host = hmydomain;
238 	return 1;
239 }
240 
241 /*
242  * mimeparams	: | mimeparams ";" mimepara
243  * mimeparam	: token "=" token | token "=" qstring
244  */
245 static HSPairs*
mimeparams(Hlex * h)246 mimeparams(Hlex *h)
247 {
248 	HSPairs *p;
249 	char *s;
250 
251 	p = nil;
252 	for(;;){
253 		if(lex(h) != Word)
254 			break;
255 		s = hstrdup(h->c, h->wordval);
256 		if(lex(h) != Word && h->tok != QString)
257 			break;
258 		p = hmkspairs(h->c, s, hstrdup(h->c, h->wordval), p);
259 	}
260 	return hrevspairs(p);
261 }
262 
263 /*
264  * mimehfields	: mimehfield | mimehfields commas mimehfield
265  * mimehfield	: token mimeparams
266  * commas	: "," | commas ","
267  */
268 static HFields*
mimehfields(Hlex * h)269 mimehfields(Hlex *h)
270 {
271 	HFields *f;
272 
273 	f = nil;
274 	for(;;){
275 		while(lex(h) != Word)
276 			if(h->tok != ',')
277 				goto breakout;
278 
279 		f = hmkhfields(h->c, hstrdup(h->c, h->wordval), nil, f);
280 
281 		if(lex(h) == ';')
282 			f->params = mimeparams(h);
283 		if(h->tok != ',')
284 			break;
285 	}
286 breakout:;
287 	return hrevhfields(f);
288 }
289 
290 /*
291  * parse a list of acceptable types, encodings, languages, etc.
292  */
293 static HContent*
mimeok(Hlex * h,char * name,int multipart,HContent * head)294 mimeok(Hlex *h, char *name, int multipart, HContent *head)
295 {
296 	char *generic, *specific, *s;
297 	float v;
298 
299 	/*
300 	 * each type is separated by one or more commas
301 	 */
302 	while(lex(h) != Word)
303 		if(h->tok != ',')
304 			return head;
305 
306 	generic = hstrdup(h->c, h->wordval);
307 	lex(h);
308 	if(h->tok == '/' || multipart){
309 		/*
310 		 * at one time, IE5 improperly said '*' for single types
311 		 */
312 		if(h->tok != '/')
313 			return nil;
314 		if(lex(h) != Word)
315 			return head;
316 		specific = hstrdup(h->c, h->wordval);
317 		if(!multipart && strcmp(specific, "*") != 0)
318 			return head;
319 		lex(h);
320 	}else
321 		specific = nil;
322 	head = hmkcontent(h->c, generic, specific, head);
323 
324 	for(;;){
325 		switch(h->tok){
326 		case ';':
327 			/*
328 			 * should make a list of these params
329 			 * for accept, they fall into two classes:
330 			 *	up to a q=..., they modify the media type.
331 			 *	afterwards, they acceptance criteria
332 			 */
333 			if(lex(h) == Word){
334 				s = hstrdup(h->c, h->wordval);
335 				if(lex(h) != '=' || lex(h) != Word && h->tok != QString)
336 					return head;
337 				v = strtod(h->wordval, nil);
338 				if(strcmp(s, "q") == 0)
339 					head->q = v;
340 				else if(strcmp(s, "mxb") == 0)
341 					head->mxb = v;
342 			}
343 			break;
344 		case ',':
345 			return  mimeok(h, name, multipart, head);
346 		default:
347 			return head;
348 		}
349 		lex(h);
350 	}
351 }
352 
353 /*
354  * parse a list of entity tags
355  * 1#entity-tag
356  * entity-tag = [weak] opaque-tag
357  * weak = "W/"
358  * opaque-tag = quoted-string
359  */
360 static HETag*
mimeetag(Hlex * h,HETag * head)361 mimeetag(Hlex *h, HETag *head)
362 {
363 	HETag *e;
364 	int weak;
365 
366 	for(;;){
367 		while(lex(h) != Word && h->tok != QString)
368 			if(h->tok != ',')
369 				return head;
370 
371 		weak = 0;
372 		if(h->tok == Word && strcmp(h->wordval, "*") != 0){
373 			if(strcmp(h->wordval, "W") != 0)
374 				return head;
375 			if(lex(h) != '/' || lex(h) != QString)
376 				return head;
377 			weak = 1;
378 		}
379 
380 		e = halloc(h->c, sizeof(HETag));
381 		e->etag = hstrdup(h->c, h->wordval);
382 		e->weak = weak;
383 		e->next = head;
384 		head = e;
385 
386 		if(lex(h) != ',')
387 			return head;
388 	}
389 }
390 
391 /*
392  * ranges-specifier = byte-ranges-specifier
393  * byte-ranges-specifier = "bytes" "=" byte-range-set
394  * byte-range-set = 1#(byte-range-spec|suffix-byte-range-spec)
395  * byte-range-spec = byte-pos "-" [byte-pos]
396  * byte-pos = 1*DIGIT
397  * suffix-byte-range-spec = "-" suffix-length
398  * suffix-length = 1*DIGIT
399  *
400  * syntactically invalid range specifiers cause the
401  * entire header field to be ignored.
402  * it is syntactically incorrect for the second byte pos
403  * to be smaller than the first byte pos
404  */
405 static HRange*
mimeranges(Hlex * h,HRange * head)406 mimeranges(Hlex *h, HRange *head)
407 {
408 	HRange *r, *rh, *tail;
409 	char *w;
410 	ulong start, stop;
411 	int suf;
412 
413 	if(lex(h) != Word || strcmp(h->wordval, "bytes") != 0 || lex(h) != '=')
414 		return head;
415 
416 	rh = nil;
417 	tail = nil;
418 	for(;;){
419 		while(lex(h) != Word){
420 			if(h->tok != ','){
421 				if(h->tok == '\n')
422 					goto breakout;
423 				return head;
424 			}
425 		}
426 
427 		w = h->wordval;
428 		start = 0;
429 		suf = 1;
430 		if(w[0] != '-'){
431 			suf = 0;
432 			start = digtoul(w, &w);
433 			if(w[0] != '-')
434 				return head;
435 		}
436 		w++;
437 		stop = ~0UL;
438 		if(w[0] != '\0'){
439 			stop = digtoul(w, &w);
440 			if(w[0] != '\0')
441 				return head;
442 			if(!suf && stop < start)
443 				return head;
444 		}
445 
446 		r = halloc(h->c, sizeof(HRange));
447 		r->suffix = suf;
448 		r->start = start;
449 		r->stop = stop;
450 		r->next = nil;
451 		if(rh == nil)
452 			rh = r;
453 		else
454 			tail->next = r;
455 		tail = r;
456 
457 		if(lex(h) != ','){
458 			if(h->tok == '\n')
459 				break;
460 			return head;
461 		}
462 	}
463 breakout:;
464 
465 	if(head == nil)
466 		return rh;
467 
468 	for(tail = head; tail->next != nil; tail = tail->next)
469 		;
470 	tail->next = rh;
471 	return head;
472 }
473 
474 static void
mimeaccept(Hlex * h,char * name)475 mimeaccept(Hlex *h, char *name)
476 {
477 	h->c->head.oktype = mimeok(h, name, 1, h->c->head.oktype);
478 }
479 
480 static void
mimeacceptchar(Hlex * h,char * name)481 mimeacceptchar(Hlex *h, char *name)
482 {
483 	h->c->head.okchar = mimeok(h, name, 0, h->c->head.okchar);
484 }
485 
486 static void
mimeacceptenc(Hlex * h,char * name)487 mimeacceptenc(Hlex *h, char *name)
488 {
489 	h->c->head.okencode = mimeok(h, name, 0, h->c->head.okencode);
490 }
491 
492 static void
mimeacceptlang(Hlex * h,char * name)493 mimeacceptlang(Hlex *h, char *name)
494 {
495 	h->c->head.oklang = mimeok(h, name, 0, h->c->head.oklang);
496 }
497 
498 static void
mimemodified(Hlex * h,char * unused)499 mimemodified(Hlex *h, char *unused)
500 {
501 	lexhead(h);
502 	h->c->head.ifmodsince = hdate2sec(h->wordval);
503 }
504 
505 static void
mimeunmodified(Hlex * h,char * unused)506 mimeunmodified(Hlex *h, char *unused)
507 {
508 	lexhead(h);
509 	h->c->head.ifunmodsince = hdate2sec(h->wordval);
510 }
511 
512 static void
mimematch(Hlex * h,char * unused)513 mimematch(Hlex *h, char *unused)
514 {
515 	h->c->head.ifmatch = mimeetag(h, h->c->head.ifmatch);
516 }
517 
518 static void
mimenomatch(Hlex * h,char * unused)519 mimenomatch(Hlex *h, char *unused)
520 {
521 	h->c->head.ifnomatch = mimeetag(h, h->c->head.ifnomatch);
522 }
523 
524 /*
525  * argument is either etag or date
526  */
527 static void
mimeifrange(Hlex * h,char * unused)528 mimeifrange(Hlex *h, char *unused)
529 {
530 	int c, d, et;
531 
532 	et = 0;
533 	c = getc(h);
534 	while(c == ' ' || c == '\t')
535 		c = getc(h);
536 	if(c == '"')
537 		et = 1;
538 	else if(c == 'W'){
539 		d = getc(h);
540 		if(d == '/')
541 			et = 1;
542 		ungetc(h);
543 	}
544 	ungetc(h);
545 	if(et){
546 		h->c->head.ifrangeetag = mimeetag(h, h->c->head.ifrangeetag);
547 	}else{
548 		lexhead(h);
549 		h->c->head.ifrangedate = hdate2sec(h->wordval);
550 	}
551 }
552 
553 static void
mimerange(Hlex * h,char * unused)554 mimerange(Hlex *h, char *unused)
555 {
556 	h->c->head.range = mimeranges(h, h->c->head.range);
557 }
558 
559 /*
560  * note: netscape and ie through versions 4.7 and 4
561  * support only basic authorization, so that is all that is supported here
562  *
563  * "Authorization" ":" "Basic" base64-user-pass
564  * where base64-user-pass is the base64 encoding of
565  * username ":" password
566  */
567 static void
mimeauthorization(Hlex * h,char * unused)568 mimeauthorization(Hlex *h, char *unused)
569 {
570 	char *up, *p;
571 	int n;
572 
573 	if(lex(h) != Word || cistrcmp(h->wordval, "basic") != 0)
574 		return;
575 
576 	n = lexbase64(h);
577 	if(!n)
578 		return;
579 
580 	/*
581 	 * wipe out source for password, so it won't be logged.
582 	 * it is replaced by a single =,
583 	 * which is valid base64, but not ok for an auth reponse.
584 	 * therefore future parses of the header field will not overwrite
585 	 * authuser and authpass.
586 	 */
587 	memmove(h->c->hpos - (n - 1), h->c->hpos, h->c->hstop - h->c->hpos);
588 	h->c->hstop -= n - 1;
589 	*h->c->hstop = '\0';
590 	h->c->hpos -= n - 1;
591 	h->c->hpos[-1] = '=';
592 
593 	up = halloc(h->c, n + 1);
594 	n = dec64((uchar*)up, n, h->wordval, n);
595 	up[n] = '\0';
596 	p = strchr(up, ':');
597 	if(p != nil){
598 		*p++ = '\0';
599 		h->c->head.authuser = hstrdup(h->c, up);
600 		h->c->head.authpass = hstrdup(h->c, p);
601 	}
602 }
603 
604 static void
mimeagent(Hlex * h,char * unused)605 mimeagent(Hlex *h, char *unused)
606 {
607 	lexhead(h);
608 	h->c->head.client = hstrdup(h->c, h->wordval);
609 }
610 
611 static void
mimefrom(Hlex * h,char * unused)612 mimefrom(Hlex *h, char *unused)
613 {
614 	lexhead(h);
615 }
616 
617 static void
mimehost(Hlex * h,char * unused)618 mimehost(Hlex *h, char *unused)
619 {
620 	char *hd;
621 
622 	lexhead(h);
623 	for(hd = h->wordval; *hd == ' ' || *hd == '\t'; hd++)
624 		;
625 	h->c->head.host = hlower(hstrdup(h->c, hd));
626 }
627 
628 /*
629  * if present, implies that a message body follows the headers
630  * "content-length" ":" digits
631  */
632 static void
mimecontlen(Hlex * h,char * unused)633 mimecontlen(Hlex *h, char *unused)
634 {
635 	char *e;
636 	ulong v;
637 
638 	if(lex(h) != Word)
639 		return;
640 	e = h->wordval;
641 	v = digtoul(e, &e);
642 	if(v == ~0UL || *e != '\0')
643 		return;
644 	h->c->head.contlen = v;
645 }
646 
647 /*
648  * mimexpect	: "expect" ":" expects
649  * expects	: | expects "," expect
650  * expect	: "100-continue" | token | token "=" token expectparams | token "=" qstring expectparams
651  * expectparams	: ";" token | ";" token "=" token | token "=" qstring
652  * for now, we merely parse "100-continue" or anything else.
653  */
654 static void
mimeexpect(Hlex * h,char * unused)655 mimeexpect(Hlex *h, char *unused)
656 {
657 	if(lex(h) != Word || cistrcmp(h->wordval, "100-continue") != 0 || lex(h) != '\n')
658 		h->c->head.expectother = 1;
659 	h->c->head.expectcont = 1;
660 }
661 
662 static void
mimetransenc(Hlex * h,char * unused)663 mimetransenc(Hlex *h, char *unused)
664 {
665 	h->c->head.transenc = mimehfields(h);
666 }
667 
668 static void
mimefresh(Hlex * h,char * unused)669 mimefresh(Hlex *h, char *unused)
670 {
671 	char *s;
672 
673 	lexhead(h);
674 	for(s = h->wordval; *s && (*s==' ' || *s=='\t'); s++)
675 		;
676 	if(strncmp(s, "pathstat/", 9) == 0)
677 		h->c->head.fresh_thresh = atoi(s+9);
678 	else if(strncmp(s, "have/", 5) == 0)
679 		h->c->head.fresh_have = atoi(s+5);
680 }
681 
682 static void
mimeignore(Hlex * h,char * unused)683 mimeignore(Hlex *h, char *unused)
684 {
685 	lexhead(h);
686 }
687 
688 static void
parsejump(Hlex * h,char * k)689 parsejump(Hlex *h, char *k)
690 {
691 	int l, r, m;
692 
693 	l = 1;
694 	r = nelem(mimehead) - 1;
695 	while(l <= r){
696 		m = (r + l) >> 1;
697 		if(cistrcmp(mimehead[m].name, k) <= 0)
698 			l = m + 1;
699 		else
700 			r = m - 1;
701 	}
702 	m = l - 1;
703 	if(cistrcmp(mimehead[m].name, k) == 0 && !mimehead[m].ignore){
704 		mimehead[m].seen = 1;
705 		(*mimehead[m].parse)(h, k);
706 	}else
707 		mimeignore(h, k);
708 }
709 
710 static int
lex(Hlex * h)711 lex(Hlex *h)
712 {
713 	return h->tok = lex1(h, 0);
714 }
715 
716 static int
lexbase64(Hlex * h)717 lexbase64(Hlex *h)
718 {
719 	int c, n;
720 
721 	n = 0;
722 	lex1(h, 1);
723 
724 	while((c = getc(h)) >= 0){
725 		if(!(c >= 'A' && c <= 'Z'
726 		|| c >= 'a' && c <= 'z'
727 		|| c >= '0' && c <= '9'
728 		|| c == '+' || c == '/')){
729 			ungetc(h);
730 			break;
731 		}
732 
733 		if(n < HMaxWord-1)
734 			h->wordval[n++] = c;
735 	}
736 	h->wordval[n] = '\0';
737 	return n;
738 }
739 
740 /*
741  * rfc 822/rfc 1521 lexical analyzer
742  */
743 static int
lex1(Hlex * h,int skipwhite)744 lex1(Hlex *h, int skipwhite)
745 {
746 	int level, c;
747 
748 	if(h->eol)
749 		return '\n';
750 
751 top:
752 	c = getc(h);
753 	switch(c){
754 	case '(':
755 		level = 1;
756 		while((c = getc(h)) >= 0){
757 			if(c == '\\'){
758 				c = getc(h);
759 				if(c < 0)
760 					return '\n';
761 				continue;
762 			}
763 			if(c == '(')
764 				level++;
765 			else if(c == ')' && --level == 0)
766 				break;
767 			else if(c == '\n'){
768 				c = getc(h);
769 				if(c < 0)
770 					return '\n';
771 				if(c == ')' && --level == 0)
772 					break;
773 				if(c != ' ' && c != '\t'){
774 					ungetc(h);
775 					return '\n';
776 				}
777 			}
778 		}
779 		goto top;
780 
781 	case ' ': case '\t':
782 		goto top;
783 
784 	case '\r':
785 		c = getc(h);
786 		if(c != '\n'){
787 			ungetc(h);
788 			goto top;
789 		}
790 
791 	case '\n':
792 		if(h->tok == '\n'){
793 			h->eol = 1;
794 			h->eoh = 1;
795 			return '\n';
796 		}
797 		c = getc(h);
798 		if(c < 0){
799 			h->eol = 1;
800 			return '\n';
801 		}
802 		if(c != ' ' && c != '\t'){
803 			ungetc(h);
804 			h->eol = 1;
805 			return '\n';
806 		}
807 		goto top;
808 
809 	case ')':
810 	case '<': case '>':
811 	case '[': case ']':
812 	case '@': case '/':
813 	case ',': case ';': case ':': case '?': case '=':
814 		if(skipwhite){
815 			ungetc(h);
816 			return c;
817 		}
818 		return c;
819 
820 	case '"':
821 		if(skipwhite){
822 			ungetc(h);
823 			return c;
824 		}
825 		word(h, "\"");
826 		getc(h);		/* skip the closing quote */
827 		return QString;
828 
829 	default:
830 		ungetc(h);
831 		if(skipwhite)
832 			return c;
833 		word(h, "\"(){}<>@,;:/[]?=\r\n \t");
834 		if(h->wordval[0] == '\0'){
835 			h->c->head.closeit = 1;
836 			hfail(h->c, HSyntax);
837 			longjmp(h->jmp, -1);
838 		}
839 		return Word;
840 	}
841 	/* not reached */
842 }
843 
844 /*
845  * return the rest of an rfc 822, including \n
846  * do not map to lower case
847  */
848 static void
lexhead(Hlex * h)849 lexhead(Hlex *h)
850 {
851 	int c, n;
852 
853 	n = 0;
854 	while((c = getc(h)) >= 0){
855 		if(c == '\r')
856 			c = wordcr(h);
857 		else if(c == '\n')
858 			c = wordnl(h);
859 		if(c == '\n')
860 			break;
861 		if(c == '\\'){
862 			c = getc(h);
863 			if(c < 0)
864 				break;
865 		}
866 
867 		if(n < HMaxWord-1)
868 			h->wordval[n++] = c;
869 	}
870 	h->tok = '\n';
871 	h->eol = 1;
872 	h->wordval[n] = '\0';
873 }
874 
875 static void
word(Hlex * h,char * stop)876 word(Hlex *h, char *stop)
877 {
878 	int c, n;
879 
880 	n = 0;
881 	while((c = getc(h)) >= 0){
882 		if(c == '\r')
883 			c = wordcr(h);
884 		else if(c == '\n')
885 			c = wordnl(h);
886 		if(c == '\\'){
887 			c = getc(h);
888 			if(c < 0)
889 				break;
890 		}else if(c < 32 || strchr(stop, c) != nil){
891 			ungetc(h);
892 			break;
893 		}
894 
895 		if(n < HMaxWord-1)
896 			h->wordval[n++] = c;
897 	}
898 	h->wordval[n] = '\0';
899 }
900 
901 static int
wordcr(Hlex * h)902 wordcr(Hlex *h)
903 {
904 	int c;
905 
906 	c = getc(h);
907 	if(c == '\n')
908 		return wordnl(h);
909 	ungetc(h);
910 	return ' ';
911 }
912 
913 static int
wordnl(Hlex * h)914 wordnl(Hlex *h)
915 {
916 	int c;
917 
918 	c = getc(h);
919 	if(c == ' ' || c == '\t')
920 		return c;
921 	ungetc(h);
922 
923 	return '\n';
924 }
925 
926 static int
getc(Hlex * h)927 getc(Hlex *h)
928 {
929 	if(h->eoh)
930 		return -1;
931 	if(h->c->hpos < h->c->hstop)
932 		return *h->c->hpos++;
933 	h->eoh = 1;
934 	h->eol = 1;
935 	return -1;
936 }
937 
938 static void
ungetc(Hlex * h)939 ungetc(Hlex *h)
940 {
941 	if(h->eoh)
942 		return;
943 	h->c->hpos--;
944 }
945 
946 static ulong
digtoul(char * s,char ** e)947 digtoul(char *s, char **e)
948 {
949 	ulong v;
950 	int c, ovfl;
951 
952 	v = 0;
953 	ovfl = 0;
954 	for(;;){
955 		c = *s;
956 		if(c < '0' || c > '9')
957 			break;
958 		s++;
959 		c -= '0';
960 		if(v > UlongMax/10 || v == UlongMax/10 && c >= UlongMax%10)
961 			ovfl = 1;
962 		v = v * 10 + c;
963 	}
964 
965 	if(e)
966 		*e = s;
967 	if(ovfl)
968 		return UlongMax;
969 	return v;
970 }
971 
972 int
http11(HConnect * c)973 http11(HConnect *c)
974 {
975 	return c->req.vermaj > 1 || c->req.vermaj == 1 && c->req.vermin > 0;
976 }
977 
978 char*
hmkmimeboundary(HConnect * c)979 hmkmimeboundary(HConnect *c)
980 {
981 	char buf[32];
982 	int i;
983 
984 	srand((time(0)<<16)|getpid());
985 	strcpy(buf, "upas-");
986 	for(i = 5; i < sizeof(buf)-1; i++)
987 		buf[i] = 'a' + nrand(26);
988 	buf[i] = 0;
989 	return hstrdup(c, buf);
990 }
991 
992 HSPairs*
hmkspairs(HConnect * c,char * s,char * t,HSPairs * next)993 hmkspairs(HConnect *c, char *s, char *t, HSPairs *next)
994 {
995 	HSPairs *sp;
996 
997 	sp = halloc(c, sizeof *sp);
998 	sp->s = s;
999 	sp->t = t;
1000 	sp->next = next;
1001 	return sp;
1002 }
1003 
1004 HSPairs*
hrevspairs(HSPairs * sp)1005 hrevspairs(HSPairs *sp)
1006 {
1007 	HSPairs *last, *next;
1008 
1009 	last = nil;
1010 	for(; sp != nil; sp = next){
1011 		next = sp->next;
1012 		sp->next = last;
1013 		last = sp;
1014 	}
1015 	return last;
1016 }
1017 
1018 HFields*
hmkhfields(HConnect * c,char * s,HSPairs * p,HFields * next)1019 hmkhfields(HConnect *c, char *s, HSPairs *p, HFields *next)
1020 {
1021 	HFields *hf;
1022 
1023 	hf = halloc(c, sizeof *hf);
1024 	hf->s = s;
1025 	hf->params = p;
1026 	hf->next = next;
1027 	return hf;
1028 }
1029 
1030 HFields*
hrevhfields(HFields * hf)1031 hrevhfields(HFields *hf)
1032 {
1033 	HFields *last, *next;
1034 
1035 	last = nil;
1036 	for(; hf != nil; hf = next){
1037 		next = hf->next;
1038 		hf->next = last;
1039 		last = hf;
1040 	}
1041 	return last;
1042 }
1043 
1044 HContent*
hmkcontent(HConnect * c,char * generic,char * specific,HContent * next)1045 hmkcontent(HConnect *c, char *generic, char *specific, HContent *next)
1046 {
1047 	HContent *ct;
1048 
1049 	ct = halloc(c, sizeof(HContent));
1050 	ct->generic = generic;
1051 	ct->specific = specific;
1052 	ct->next = next;
1053 	ct->q = 1;
1054 	ct->mxb = 0;
1055 	return ct;
1056 }
1057