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
hreqcleanup(HConnect * c)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
mimeconnection(Hlex * h,char *)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
hparseheaders(HConnect * c,int timeout)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*
mimeparams(Hlex * h)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*
mimehfields(Hlex * h)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*
mimeok(Hlex * h,char * name,int multipart,HContent * head)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*
mimeetag(Hlex * h,HETag * head)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*
mimeranges(Hlex * h,HRange * head)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
mimeaccept(Hlex * h,char * name)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
mimeacceptchar(Hlex * h,char * name)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
mimeacceptenc(Hlex * h,char * name)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
mimeacceptlang(Hlex * h,char * name)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
mimemodified(Hlex * h,char *)509 mimemodified(Hlex *h, char *)
510 {
511 lexhead(h);
512 h->c->head.ifmodsince = hdate2sec(h->wordval);
513 }
514
515 static void
mimeunmodified(Hlex * h,char *)516 mimeunmodified(Hlex *h, char *)
517 {
518 lexhead(h);
519 h->c->head.ifunmodsince = hdate2sec(h->wordval);
520 }
521
522 static void
mimematch(Hlex * h,char *)523 mimematch(Hlex *h, char *)
524 {
525 h->c->head.ifmatch = mimeetag(h, h->c->head.ifmatch);
526 }
527
528 static void
mimenomatch(Hlex * h,char *)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
mimeifrange(Hlex * h,char *)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
mimerange(Hlex * h,char *)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
authdigest(Hlex * h,char *)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
authbasic(Hlex * h,char *)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
mimeauthorization(Hlex * h,char *)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
mimeagent(Hlex * h,char *)658 mimeagent(Hlex *h, char *)
659 {
660 lexhead(h);
661 h->c->head.client = hstrdup(h->c, h->wordval);
662 }
663
664 static void
mimefrom(Hlex * h,char *)665 mimefrom(Hlex *h, char *)
666 {
667 lexhead(h);
668 }
669
670 static void
mimehost(Hlex * h,char *)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
mimecontlen(Hlex * h,char *)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
mimeexpect(Hlex * h,char *)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
mimetransenc(Hlex * h,char *)716 mimetransenc(Hlex *h, char *)
717 {
718 h->c->head.transenc = mimehfields(h);
719 }
720
721 static void
mimecookie(Hlex * h,char *)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
mimefresh(Hlex * h,char *)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
mimeignore(Hlex * h,char *)757 mimeignore(Hlex *h, char *)
758 {
759 lexhead(h);
760 }
761
762 static void
parsejump(Hlex * h,char * k)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
lex(Hlex * h)785 lex(Hlex *h)
786 {
787 return h->tok = lex1(h, 0);
788 }
789
790 static int
lexbase64(Hlex * h)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
lex1(Hlex * h,int skipwhite)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
lexhead(Hlex * h)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
word(Hlex * h,char * stop)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
wordcr(Hlex * h)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
wordnl(Hlex * h)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
getc(Hlex * h)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
ungetc(Hlex * h)1009 ungetc(Hlex *h)
1010 {
1011 if(h->eoh)
1012 return;
1013 h->c->hpos--;
1014 }
1015
1016 static ulong
digtoul(char * s,char ** e)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
http11(HConnect * c)1043 http11(HConnect *c)
1044 {
1045 return c->req.vermaj > 1 || c->req.vermaj == 1 && c->req.vermin > 0;
1046 }
1047
1048 char*
hmkmimeboundary(HConnect * c)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*
hmkspairs(HConnect * c,char * s,char * t,HSPairs * next)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*
hrevspairs(HSPairs * sp)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*
hmkhfields(HConnect * c,char * s,HSPairs * p,HFields * next)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*
hrevhfields(HFields * hf)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*
hmkcontent(HConnect * c,char * generic,char * specific,HContent * next)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 }
1127