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 } 342 break; 343 case ',': 344 return mimeok(h, name, multipart, head); 345 default: 346 return head; 347 } 348 lex(h); 349 } 350 return head; 351 } 352 353 /* 354 * parse a list of entity tags 355 * 1#entity-tag 356 * entity-tag = [weak] opaque-tag 357 * weak = "W/" 358 * opaque-tag = quoted-string 359 */ 360 static HETag* 361 mimeetag(Hlex *h, HETag *head) 362 { 363 HETag *e; 364 int weak; 365 366 for(;;){ 367 while(lex(h) != Word && h->tok != QString) 368 if(h->tok != ',') 369 return head; 370 371 weak = 0; 372 if(h->tok == Word && strcmp(h->wordval, "*") != 0){ 373 if(strcmp(h->wordval, "W") != 0) 374 return head; 375 if(lex(h) != '/' || lex(h) != QString) 376 return head; 377 weak = 1; 378 } 379 380 e = halloc(h->c, sizeof(HETag)); 381 e->etag = hstrdup(h->c, h->wordval); 382 e->weak = weak; 383 e->next = head; 384 head = e; 385 386 if(lex(h) != ',') 387 return head; 388 } 389 return head; 390 } 391 392 /* 393 * ranges-specifier = byte-ranges-specifier 394 * byte-ranges-specifier = "bytes" "=" byte-range-set 395 * byte-range-set = 1#(byte-range-spec|suffix-byte-range-spec) 396 * byte-range-spec = byte-pos "-" [byte-pos] 397 * byte-pos = 1*DIGIT 398 * suffix-byte-range-spec = "-" suffix-length 399 * suffix-length = 1*DIGIT 400 * 401 * syntactically invalid range specifiers cause the 402 * entire header field to be ignored. 403 * it is syntactically incorrect for the second byte pos 404 * to be smaller than the first byte pos 405 */ 406 static HRange* 407 mimeranges(Hlex *h, HRange *head) 408 { 409 HRange *r, *rh, *tail; 410 char *w; 411 ulong start, stop; 412 int suf; 413 414 if(lex(h) != Word || strcmp(h->wordval, "bytes") != 0 || lex(h) != '=') 415 return head; 416 417 rh = nil; 418 tail = nil; 419 for(;;){ 420 while(lex(h) != Word){ 421 if(h->tok != ','){ 422 if(h->tok == '\n') 423 goto breakout; 424 return head; 425 } 426 } 427 428 w = h->wordval; 429 start = 0; 430 suf = 1; 431 if(w[0] != '-'){ 432 suf = 0; 433 start = digtoul(w, &w); 434 if(w[0] != '-') 435 return head; 436 } 437 w++; 438 stop = ~0UL; 439 if(w[0] != '\0'){ 440 stop = digtoul(w, &w); 441 if(w[0] != '\0') 442 return head; 443 if(!suf && stop < start) 444 return head; 445 } 446 447 r = halloc(h->c, sizeof(HRange)); 448 r->suffix = suf; 449 r->start = start; 450 r->stop = stop; 451 r->next = nil; 452 if(rh == nil) 453 rh = r; 454 else 455 tail->next = r; 456 tail = r; 457 458 if(lex(h) != ','){ 459 if(h->tok == '\n') 460 break; 461 return head; 462 } 463 } 464 breakout:; 465 466 if(head == nil) 467 return rh; 468 469 for(tail = head; tail->next != nil; tail = tail->next) 470 ; 471 tail->next = rh; 472 return head; 473 } 474 475 static void 476 mimeaccept(Hlex *h, char *name) 477 { 478 h->c->head.oktype = mimeok(h, name, 1, h->c->head.oktype); 479 } 480 481 static void 482 mimeacceptchar(Hlex *h, char *name) 483 { 484 h->c->head.okchar = mimeok(h, name, 0, h->c->head.okchar); 485 } 486 487 static void 488 mimeacceptenc(Hlex *h, char *name) 489 { 490 h->c->head.okencode = mimeok(h, name, 0, h->c->head.okencode); 491 } 492 493 static void 494 mimeacceptlang(Hlex *h, char *name) 495 { 496 h->c->head.oklang = mimeok(h, name, 0, h->c->head.oklang); 497 } 498 499 static void 500 mimemodified(Hlex *h, char *) 501 { 502 lexhead(h); 503 h->c->head.ifmodsince = hdate2sec(h->wordval); 504 } 505 506 static void 507 mimeunmodified(Hlex *h, char *) 508 { 509 lexhead(h); 510 h->c->head.ifunmodsince = hdate2sec(h->wordval); 511 } 512 513 static void 514 mimematch(Hlex *h, char *) 515 { 516 h->c->head.ifmatch = mimeetag(h, h->c->head.ifmatch); 517 } 518 519 static void 520 mimenomatch(Hlex *h, char *) 521 { 522 h->c->head.ifnomatch = mimeetag(h, h->c->head.ifnomatch); 523 } 524 525 /* 526 * argument is either etag or date 527 */ 528 static void 529 mimeifrange(Hlex *h, char *) 530 { 531 int c, d, et; 532 533 et = 0; 534 c = getc(h); 535 while(c == ' ' || c == '\t') 536 c = getc(h); 537 if(c == '"') 538 et = 1; 539 else if(c == 'W'){ 540 d = getc(h); 541 if(d == '/') 542 et = 1; 543 ungetc(h); 544 } 545 ungetc(h); 546 if(et){ 547 h->c->head.ifrangeetag = mimeetag(h, h->c->head.ifrangeetag); 548 }else{ 549 lexhead(h); 550 h->c->head.ifrangedate = hdate2sec(h->wordval); 551 } 552 } 553 554 static void 555 mimerange(Hlex *h, char *) 556 { 557 h->c->head.range = mimeranges(h, h->c->head.range); 558 } 559 560 /* 561 * note: netscape and ie through versions 4.7 and 4 562 * support only basic authorization, so that is all that is supported here 563 * 564 * "Authorization" ":" "Basic" base64-user-pass 565 * where base64-user-pass is the base64 encoding of 566 * username ":" password 567 */ 568 static void 569 mimeauthorization(Hlex *h, char *) 570 { 571 char *up, *p; 572 int n; 573 574 if(lex(h) != Word || cistrcmp(h->wordval, "basic") != 0) 575 return; 576 577 n = lexbase64(h); 578 if(!n) 579 return; 580 581 /* 582 * wipe out source for password, so it won't be logged. 583 * it is replaced by a single =, 584 * which is valid base64, but not ok for an auth reponse. 585 * therefore future parses of the header field will not overwrite 586 * authuser and authpass. 587 */ 588 memmove(h->c->hpos - (n - 1), h->c->hpos, h->c->hstop - h->c->hpos); 589 h->c->hstop -= n - 1; 590 *h->c->hstop = '\0'; 591 h->c->hpos -= n - 1; 592 h->c->hpos[-1] = '='; 593 594 up = halloc(h->c, n + 1); 595 n = dec64((uchar*)up, n, h->wordval, n); 596 up[n] = '\0'; 597 p = strchr(up, ':'); 598 if(p != nil){ 599 *p++ = '\0'; 600 h->c->head.authuser = hstrdup(h->c, up); 601 h->c->head.authpass = hstrdup(h->c, p); 602 } 603 } 604 605 static void 606 mimeagent(Hlex *h, char *) 607 { 608 lexhead(h); 609 h->c->head.client = hstrdup(h->c, h->wordval); 610 } 611 612 static void 613 mimefrom(Hlex *h, char *) 614 { 615 lexhead(h); 616 } 617 618 static void 619 mimehost(Hlex *h, char *) 620 { 621 char *hd; 622 623 lexhead(h); 624 for(hd = h->wordval; *hd == ' ' || *hd == '\t'; hd++) 625 ; 626 h->c->head.host = hlower(hstrdup(h->c, hd)); 627 } 628 629 /* 630 * if present, implies that a message body follows the headers 631 * "content-length" ":" digits 632 */ 633 static void 634 mimecontlen(Hlex *h, char *) 635 { 636 char *e; 637 ulong v; 638 639 if(lex(h) != Word) 640 return; 641 e = h->wordval; 642 v = digtoul(e, &e); 643 if(v == ~0UL || *e != '\0') 644 return; 645 h->c->head.contlen = v; 646 } 647 648 /* 649 * mimexpect : "expect" ":" expects 650 * expects : | expects "," expect 651 * expect : "100-continue" | token | token "=" token expectparams | token "=" qstring expectparams 652 * expectparams : ";" token | ";" token "=" token | token "=" qstring 653 * for now, we merely parse "100-continue" or anything else. 654 */ 655 static void 656 mimeexpect(Hlex *h, char *) 657 { 658 if(lex(h) != Word || cistrcmp(h->wordval, "100-continue") != 0 || lex(h) != '\n') 659 h->c->head.expectother = 1; 660 h->c->head.expectcont = 1; 661 } 662 663 static void 664 mimetransenc(Hlex *h, char *) 665 { 666 h->c->head.transenc = mimehfields(h); 667 } 668 669 static void 670 mimefresh(Hlex *h, char *) 671 { 672 char *s; 673 674 lexhead(h); 675 for(s = h->wordval; *s && (*s==' ' || *s=='\t'); s++) 676 ; 677 if(strncmp(s, "pathstat/", 9) == 0) 678 h->c->head.fresh_thresh = atoi(s+9); 679 else if(strncmp(s, "have/", 5) == 0) 680 h->c->head.fresh_have = atoi(s+5); 681 } 682 683 static void 684 mimeignore(Hlex *h, char *) 685 { 686 lexhead(h); 687 } 688 689 static void 690 parsejump(Hlex *h, char *k) 691 { 692 int l, r, m; 693 694 l = 1; 695 r = nelem(mimehead) - 1; 696 while(l <= r){ 697 m = (r + l) >> 1; 698 if(cistrcmp(mimehead[m].name, k) <= 0) 699 l = m + 1; 700 else 701 r = m - 1; 702 } 703 m = l - 1; 704 if(cistrcmp(mimehead[m].name, k) == 0 && !mimehead[m].ignore){ 705 mimehead[m].seen = 1; 706 (*mimehead[m].parse)(h, k); 707 }else 708 mimeignore(h, k); 709 } 710 711 static int 712 lex(Hlex *h) 713 { 714 return h->tok = lex1(h, 0); 715 } 716 717 static int 718 lexbase64(Hlex *h) 719 { 720 int c, n; 721 722 n = 0; 723 lex1(h, 1); 724 725 while((c = getc(h)) >= 0){ 726 if(!(c >= 'A' && c <= 'Z' 727 || c >= 'a' && c <= 'z' 728 || c >= '0' && c <= '9' 729 || c == '+' || c == '/')){ 730 ungetc(h); 731 break; 732 } 733 734 if(n < HMaxWord-1) 735 h->wordval[n++] = c; 736 } 737 h->wordval[n] = '\0'; 738 return n; 739 } 740 741 /* 742 * rfc 822/rfc 1521 lexical analyzer 743 */ 744 static int 745 lex1(Hlex *h, int skipwhite) 746 { 747 int level, c; 748 749 if(h->eol) 750 return '\n'; 751 752 top: 753 c = getc(h); 754 switch(c){ 755 case '(': 756 level = 1; 757 while((c = getc(h)) >= 0){ 758 if(c == '\\'){ 759 c = getc(h); 760 if(c < 0) 761 return '\n'; 762 continue; 763 } 764 if(c == '(') 765 level++; 766 else if(c == ')' && --level == 0) 767 break; 768 else if(c == '\n'){ 769 c = getc(h); 770 if(c < 0) 771 return '\n'; 772 if(c == ')' && --level == 0) 773 break; 774 if(c != ' ' && c != '\t'){ 775 ungetc(h); 776 return '\n'; 777 } 778 } 779 } 780 goto top; 781 782 case ' ': case '\t': 783 goto top; 784 785 case '\r': 786 c = getc(h); 787 if(c != '\n'){ 788 ungetc(h); 789 goto top; 790 } 791 792 case '\n': 793 if(h->tok == '\n'){ 794 h->eol = 1; 795 h->eoh = 1; 796 return '\n'; 797 } 798 c = getc(h); 799 if(c < 0){ 800 h->eol = 1; 801 return '\n'; 802 } 803 if(c != ' ' && c != '\t'){ 804 ungetc(h); 805 h->eol = 1; 806 return '\n'; 807 } 808 goto top; 809 810 case ')': 811 case '<': case '>': 812 case '[': case ']': 813 case '@': case '/': 814 case ',': case ';': case ':': case '?': case '=': 815 if(skipwhite){ 816 ungetc(h); 817 return c; 818 } 819 return c; 820 821 case '"': 822 if(skipwhite){ 823 ungetc(h); 824 return c; 825 } 826 word(h, "\""); 827 getc(h); /* skip the closing quote */ 828 return QString; 829 830 default: 831 ungetc(h); 832 if(skipwhite) 833 return c; 834 word(h, "\"(){}<>@,;:/[]?=\r\n \t"); 835 if(h->wordval[0] == '\0'){ 836 h->c->head.closeit = 1; 837 hfail(h->c, HSyntax); 838 longjmp(h->jmp, -1); 839 } 840 return Word; 841 } 842 goto top; 843 return 0; 844 } 845 846 /* 847 * return the rest of an rfc 822, including \n 848 * do not map to lower case 849 */ 850 static void 851 lexhead(Hlex *h) 852 { 853 int c, n; 854 855 n = 0; 856 while((c = getc(h)) >= 0){ 857 if(c == '\r') 858 c = wordcr(h); 859 else if(c == '\n') 860 c = wordnl(h); 861 if(c == '\n') 862 break; 863 if(c == '\\'){ 864 c = getc(h); 865 if(c < 0) 866 break; 867 } 868 869 if(n < HMaxWord-1) 870 h->wordval[n++] = c; 871 } 872 h->tok = '\n'; 873 h->eol = 1; 874 h->wordval[n] = '\0'; 875 } 876 877 static void 878 word(Hlex *h, char *stop) 879 { 880 int c, n; 881 882 n = 0; 883 while((c = getc(h)) >= 0){ 884 if(c == '\r') 885 c = wordcr(h); 886 else if(c == '\n') 887 c = wordnl(h); 888 if(c == '\\'){ 889 c = getc(h); 890 if(c < 0) 891 break; 892 }else if(c < 32 || strchr(stop, c) != nil){ 893 ungetc(h); 894 break; 895 } 896 897 if(n < HMaxWord-1) 898 h->wordval[n++] = c; 899 } 900 h->wordval[n] = '\0'; 901 } 902 903 static int 904 wordcr(Hlex *h) 905 { 906 int c; 907 908 c = getc(h); 909 if(c == '\n') 910 return wordnl(h); 911 ungetc(h); 912 return ' '; 913 } 914 915 static int 916 wordnl(Hlex *h) 917 { 918 int c; 919 920 c = getc(h); 921 if(c == ' ' || c == '\t') 922 return c; 923 ungetc(h); 924 925 return '\n'; 926 } 927 928 static int 929 getc(Hlex *h) 930 { 931 if(h->eoh) 932 return -1; 933 if(h->c->hpos < h->c->hstop) 934 return *h->c->hpos++; 935 h->eoh = 1; 936 h->eol = 1; 937 return -1; 938 } 939 940 static void 941 ungetc(Hlex *h) 942 { 943 if(h->eoh) 944 return; 945 h->c->hpos--; 946 } 947 948 static ulong 949 digtoul(char *s, char **e) 950 { 951 ulong v; 952 int c, ovfl; 953 954 v = 0; 955 ovfl = 0; 956 for(;;){ 957 c = *s; 958 if(c < '0' || c > '9') 959 break; 960 s++; 961 c -= '0'; 962 if(v > UlongMax/10 || v == UlongMax/10 && c >= UlongMax%10) 963 ovfl = 1; 964 v = v * 10 + c; 965 } 966 967 if(e) 968 *e = s; 969 if(ovfl) 970 return UlongMax; 971 return v; 972 } 973 974 int 975 http11(HConnect *c) 976 { 977 return c->req.vermaj > 1 || c->req.vermaj == 1 && c->req.vermin > 0; 978 } 979 980 char* 981 hmkmimeboundary(HConnect *c) 982 { 983 char buf[32]; 984 int i; 985 986 srand((time(0)<<16)|getpid()); 987 strcpy(buf, "upas-"); 988 for(i = 5; i < sizeof(buf)-1; i++) 989 buf[i] = 'a' + nrand(26); 990 buf[i] = 0; 991 return hstrdup(c, buf); 992 } 993 994 HSPairs* 995 hmkspairs(HConnect *c, char *s, char *t, HSPairs *next) 996 { 997 HSPairs *sp; 998 999 sp = halloc(c, sizeof *sp); 1000 sp->s = s; 1001 sp->t = t; 1002 sp->next = next; 1003 return sp; 1004 } 1005 1006 HSPairs* 1007 hrevspairs(HSPairs *sp) 1008 { 1009 HSPairs *last, *next; 1010 1011 last = nil; 1012 for(; sp != nil; sp = next){ 1013 next = sp->next; 1014 sp->next = last; 1015 last = sp; 1016 } 1017 return last; 1018 } 1019 1020 HFields* 1021 hmkhfields(HConnect *c, char *s, HSPairs *p, HFields *next) 1022 { 1023 HFields *hf; 1024 1025 hf = halloc(c, sizeof *hf); 1026 hf->s = s; 1027 hf->params = p; 1028 hf->next = next; 1029 return hf; 1030 } 1031 1032 HFields* 1033 hrevhfields(HFields *hf) 1034 { 1035 HFields *last, *next; 1036 1037 last = nil; 1038 for(; hf != nil; hf = next){ 1039 next = hf->next; 1040 hf->next = last; 1041 last = hf; 1042 } 1043 return last; 1044 } 1045 1046 HContent* 1047 hmkcontent(HConnect *c, char *generic, char *specific, HContent *next) 1048 { 1049 HContent *ct; 1050 1051 ct = halloc(c, sizeof(HContent)); 1052 ct->generic = generic; 1053 ct->specific = specific; 1054 ct->next = next; 1055 ct->q = 1; 1056 ct->mxb = 0; 1057 return ct; 1058 } 1059