xref: /plan9/sys/src/libhttpd/parse.c (revision 282e677fa45fb578cdb8bc2c412ac084c367776e)
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 	alarm(timeout);
202 	if(!hgethead(c, 1))
203 		return -1;
204 	alarm(0);
205 	h.hstart = c->hpos;
206 
207 	if(setjmp(h.jmp) == -1)
208 		return -1;
209 
210 	h.eol = 0;
211 	h.eoh = 0;
212 	h.tok = '\n';
213 	while(lex(&h) != '\n'){
214 		if(h.tok == Word && lex(&h) == ':')
215 			parsejump(&h, hstrdup(c, h.wordval));
216 		while(h.tok != '\n')
217 			lex(&h);
218 		h.eol = h.eoh;
219 	}
220 
221 	if(http11(c)){
222 		/*
223 		 * according to the http/1.1 spec,
224 		 * these rules must be followed
225 		 */
226 		if(c->head.host == nil){
227 			hfail(c, HBadReq, nil);
228 			return -1;
229 		}
230 		if(c->req.urihost != nil)
231 			c->head.host = c->req.urihost;
232 		/*
233 		 * also need to check host is actually this one
234 		 */
235 	}else if(c->head.host == nil)
236 		c->head.host = hmydomain;
237 	return 1;
238 }
239 
240 /*
241  * mimeparams	: | mimeparams ";" mimepara
242  * mimeparam	: token "=" token | token "=" qstring
243  */
244 static HSPairs*
245 mimeparams(Hlex *h)
246 {
247 	HSPairs *p;
248 	char *s;
249 
250 	p = nil;
251 	for(;;){
252 		if(lex(h) != Word)
253 			break;
254 		s = hstrdup(h->c, h->wordval);
255 		if(lex(h) != Word && h->tok != QString)
256 			break;
257 		p = hmkspairs(h->c, s, hstrdup(h->c, h->wordval), p);
258 	}
259 	return hrevspairs(p);
260 }
261 
262 /*
263  * mimehfields	: mimehfield | mimehfields commas mimehfield
264  * mimehfield	: token mimeparams
265  * commas	: "," | commas ","
266  */
267 static HFields*
268 mimehfields(Hlex *h)
269 {
270 	HFields *f;
271 
272 	f = nil;
273 	for(;;){
274 		while(lex(h) != Word)
275 			if(h->tok != ',')
276 				goto breakout;
277 
278 		f = hmkhfields(h->c, hstrdup(h->c, h->wordval), nil, f);
279 
280 		if(lex(h) == ';')
281 			f->params = mimeparams(h);
282 		if(h->tok != ',')
283 			break;
284 	}
285 breakout:;
286 	return hrevhfields(f);
287 }
288 
289 /*
290  * parse a list of acceptable types, encodings, languages, etc.
291  */
292 static HContent*
293 mimeok(Hlex *h, char *name, int multipart, HContent *head)
294 {
295 	char *generic, *specific, *s;
296 	float v;
297 
298 	/*
299 	 * each type is separated by one or more commas
300 	 */
301 	while(lex(h) != Word)
302 		if(h->tok != ',')
303 			return head;
304 
305 	generic = hstrdup(h->c, h->wordval);
306 	lex(h);
307 	if(h->tok == '/' || multipart){
308 		/*
309 		 * at one time, IE5 improperly said '*' for single types
310 		 */
311 		if(h->tok != '/')
312 			return nil;
313 		if(lex(h) != Word)
314 			return head;
315 		specific = hstrdup(h->c, h->wordval);
316 		if(!multipart && strcmp(specific, "*") != 0)
317 			return head;
318 		lex(h);
319 	}else
320 		specific = nil;
321 	head = hmkcontent(h->c, generic, specific, head);
322 
323 	for(;;){
324 		switch(h->tok){
325 		case ';':
326 			/*
327 			 * should make a list of these params
328 			 * for accept, they fall into two classes:
329 			 *	up to a q=..., they modify the media type.
330 			 *	afterwards, they acceptance criteria
331 			 */
332 			if(lex(h) == Word){
333 				s = hstrdup(h->c, h->wordval);
334 				if(lex(h) != '=' || lex(h) != Word && h->tok != QString)
335 					return head;
336 				v = strtod(h->wordval, nil);
337 				if(strcmp(s, "q") == 0)
338 					head->q = v;
339 				else if(strcmp(s, "mxb") == 0)
340 					head->mxb = v;
341 				else{
342 					/* cope with accept: application/xhtml+xml; profile=http://www.wapforum.org/xhtml, */
343 					while(lex(h) == Word || (h->tok != ',' && h->eol == 0) )
344 						;
345 					return mimeok(h, name, multipart, head);
346 				}
347 			}
348 			break;
349 		case ',':
350 			return  mimeok(h, name, multipart, head);
351 		default:
352 			return head;
353 		}
354 		lex(h);
355 	}
356 	return head;
357 }
358 
359 /*
360  * parse a list of entity tags
361  * 1#entity-tag
362  * entity-tag = [weak] opaque-tag
363  * weak = "W/"
364  * opaque-tag = quoted-string
365  */
366 static HETag*
367 mimeetag(Hlex *h, HETag *head)
368 {
369 	HETag *e;
370 	int weak;
371 
372 	for(;;){
373 		while(lex(h) != Word && h->tok != QString)
374 			if(h->tok != ',')
375 				return head;
376 
377 		weak = 0;
378 		if(h->tok == Word && strcmp(h->wordval, "*") != 0){
379 			if(strcmp(h->wordval, "W") != 0)
380 				return head;
381 			if(lex(h) != '/' || lex(h) != QString)
382 				return head;
383 			weak = 1;
384 		}
385 
386 		e = halloc(h->c, sizeof(HETag));
387 		e->etag = hstrdup(h->c, h->wordval);
388 		e->weak = weak;
389 		e->next = head;
390 		head = e;
391 
392 		if(lex(h) != ',')
393 			return head;
394 	}
395 	return head;
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 	goto top;
849 	return 0;
850 }
851 
852 /*
853  * return the rest of an rfc 822, including \n
854  * do not map to lower case
855  */
856 static void
857 lexhead(Hlex *h)
858 {
859 	int c, n;
860 
861 	n = 0;
862 	while((c = getc(h)) >= 0){
863 		if(c == '\r')
864 			c = wordcr(h);
865 		else if(c == '\n')
866 			c = wordnl(h);
867 		if(c == '\n')
868 			break;
869 		if(c == '\\'){
870 			c = getc(h);
871 			if(c < 0)
872 				break;
873 		}
874 
875 		if(n < HMaxWord-1)
876 			h->wordval[n++] = c;
877 	}
878 	h->tok = '\n';
879 	h->eol = 1;
880 	h->wordval[n] = '\0';
881 }
882 
883 static void
884 word(Hlex *h, char *stop)
885 {
886 	int c, n;
887 
888 	n = 0;
889 	while((c = getc(h)) >= 0){
890 		if(c == '\r')
891 			c = wordcr(h);
892 		else if(c == '\n')
893 			c = wordnl(h);
894 		if(c == '\\'){
895 			c = getc(h);
896 			if(c < 0)
897 				break;
898 		}else if(c < 32 || strchr(stop, c) != nil){
899 			ungetc(h);
900 			break;
901 		}
902 
903 		if(n < HMaxWord-1)
904 			h->wordval[n++] = c;
905 	}
906 	h->wordval[n] = '\0';
907 }
908 
909 static int
910 wordcr(Hlex *h)
911 {
912 	int c;
913 
914 	c = getc(h);
915 	if(c == '\n')
916 		return wordnl(h);
917 	ungetc(h);
918 	return ' ';
919 }
920 
921 static int
922 wordnl(Hlex *h)
923 {
924 	int c;
925 
926 	c = getc(h);
927 	if(c == ' ' || c == '\t')
928 		return c;
929 	ungetc(h);
930 
931 	return '\n';
932 }
933 
934 static int
935 getc(Hlex *h)
936 {
937 	if(h->eoh)
938 		return -1;
939 	if(h->c->hpos < h->c->hstop)
940 		return *h->c->hpos++;
941 	h->eoh = 1;
942 	h->eol = 1;
943 	return -1;
944 }
945 
946 static void
947 ungetc(Hlex *h)
948 {
949 	if(h->eoh)
950 		return;
951 	h->c->hpos--;
952 }
953 
954 static ulong
955 digtoul(char *s, char **e)
956 {
957 	ulong v;
958 	int c, ovfl;
959 
960 	v = 0;
961 	ovfl = 0;
962 	for(;;){
963 		c = *s;
964 		if(c < '0' || c > '9')
965 			break;
966 		s++;
967 		c -= '0';
968 		if(v > UlongMax/10 || v == UlongMax/10 && c >= UlongMax%10)
969 			ovfl = 1;
970 		v = v * 10 + c;
971 	}
972 
973 	if(e)
974 		*e = s;
975 	if(ovfl)
976 		return UlongMax;
977 	return v;
978 }
979 
980 int
981 http11(HConnect *c)
982 {
983 	return c->req.vermaj > 1 || c->req.vermaj == 1 && c->req.vermin > 0;
984 }
985 
986 char*
987 hmkmimeboundary(HConnect *c)
988 {
989 	char buf[32];
990 	int i;
991 
992 	srand((time(0)<<16)|getpid());
993 	strcpy(buf, "upas-");
994 	for(i = 5; i < sizeof(buf)-1; i++)
995 		buf[i] = 'a' + nrand(26);
996 	buf[i] = 0;
997 	return hstrdup(c, buf);
998 }
999 
1000 HSPairs*
1001 hmkspairs(HConnect *c, char *s, char *t, HSPairs *next)
1002 {
1003 	HSPairs *sp;
1004 
1005 	sp = halloc(c, sizeof *sp);
1006 	sp->s = s;
1007 	sp->t = t;
1008 	sp->next = next;
1009 	return sp;
1010 }
1011 
1012 HSPairs*
1013 hrevspairs(HSPairs *sp)
1014 {
1015 	HSPairs *last, *next;
1016 
1017 	last = nil;
1018 	for(; sp != nil; sp = next){
1019 		next = sp->next;
1020 		sp->next = last;
1021 		last = sp;
1022 	}
1023 	return last;
1024 }
1025 
1026 HFields*
1027 hmkhfields(HConnect *c, char *s, HSPairs *p, HFields *next)
1028 {
1029 	HFields *hf;
1030 
1031 	hf = halloc(c, sizeof *hf);
1032 	hf->s = s;
1033 	hf->params = p;
1034 	hf->next = next;
1035 	return hf;
1036 }
1037 
1038 HFields*
1039 hrevhfields(HFields *hf)
1040 {
1041 	HFields *last, *next;
1042 
1043 	last = nil;
1044 	for(; hf != nil; hf = next){
1045 		next = hf->next;
1046 		hf->next = last;
1047 		last = hf;
1048 	}
1049 	return last;
1050 }
1051 
1052 HContent*
1053 hmkcontent(HConnect *c, char *generic, char *specific, HContent *next)
1054 {
1055 	HContent *ct;
1056 
1057 	ct = halloc(c, sizeof(HContent));
1058 	ct->generic = generic;
1059 	ct->specific = specific;
1060 	ct->next = next;
1061 	ct->q = 1;
1062 	ct->mxb = 0;
1063 	return ct;
1064 }
1065