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