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