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