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