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 } 1127