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 * note: netscape and ie through versions 4.7 and 4 571 * support only basic authorization, so that is all that is supported here 572 * 573 * "Authorization" ":" "Basic" base64-user-pass 574 * where base64-user-pass is the base64 encoding of 575 * username ":" password 576 */ 577 static void 578 mimeauthorization(Hlex *h, char *) 579 { 580 char *up, *p; 581 int n; 582 583 if(lex(h) != Word || cistrcmp(h->wordval, "basic") != 0) 584 return; 585 586 n = lexbase64(h); 587 if(!n) 588 return; 589 590 /* 591 * wipe out source for password, so it won't be logged. 592 * it is replaced by a single =, 593 * which is valid base64, but not ok for an auth reponse. 594 * therefore future parses of the header field will not overwrite 595 * authuser and authpass. 596 */ 597 memmove(h->c->hpos - (n - 1), h->c->hpos, h->c->hstop - h->c->hpos); 598 h->c->hstop -= n - 1; 599 *h->c->hstop = '\0'; 600 h->c->hpos -= n - 1; 601 h->c->hpos[-1] = '='; 602 603 up = halloc(h->c, n + 1); 604 n = dec64((uchar*)up, n, h->wordval, n); 605 up[n] = '\0'; 606 p = strchr(up, ':'); 607 if(p != nil){ 608 *p++ = '\0'; 609 h->c->head.authuser = hstrdup(h->c, up); 610 h->c->head.authpass = hstrdup(h->c, p); 611 } 612 } 613 614 static void 615 mimeagent(Hlex *h, char *) 616 { 617 lexhead(h); 618 h->c->head.client = hstrdup(h->c, h->wordval); 619 } 620 621 static void 622 mimefrom(Hlex *h, char *) 623 { 624 lexhead(h); 625 } 626 627 static void 628 mimehost(Hlex *h, char *) 629 { 630 char *hd; 631 632 lexhead(h); 633 for(hd = h->wordval; *hd == ' ' || *hd == '\t'; hd++) 634 ; 635 h->c->head.host = hlower(hstrdup(h->c, hd)); 636 } 637 638 /* 639 * if present, implies that a message body follows the headers 640 * "content-length" ":" digits 641 */ 642 static void 643 mimecontlen(Hlex *h, char *) 644 { 645 char *e; 646 ulong v; 647 648 if(lex(h) != Word) 649 return; 650 e = h->wordval; 651 v = digtoul(e, &e); 652 if(v == ~0UL || *e != '\0') 653 return; 654 h->c->head.contlen = v; 655 } 656 657 /* 658 * mimexpect : "expect" ":" expects 659 * expects : | expects "," expect 660 * expect : "100-continue" | token | token "=" token expectparams | token "=" qstring expectparams 661 * expectparams : ";" token | ";" token "=" token | token "=" qstring 662 * for now, we merely parse "100-continue" or anything else. 663 */ 664 static void 665 mimeexpect(Hlex *h, char *) 666 { 667 if(lex(h) != Word || cistrcmp(h->wordval, "100-continue") != 0 || lex(h) != '\n') 668 h->c->head.expectother = 1; 669 h->c->head.expectcont = 1; 670 } 671 672 static void 673 mimetransenc(Hlex *h, char *) 674 { 675 h->c->head.transenc = mimehfields(h); 676 } 677 678 static void 679 mimecookie(Hlex *h, char *) 680 { 681 char *s; 682 HSPairs *p; 683 684 p = nil; 685 for(;;){ 686 while(lex(h) != Word) 687 if(h->tok != ';' && h->tok != ',') 688 goto breakout; 689 s = hstrdup(h->c, h->wordval); 690 while (lex(h) != Word && h->tok != QString) 691 if (h->tok != '=') 692 goto breakout; 693 p = hmkspairs(h->c, s, hstrdup(h->c, h->wordval), p); 694 } 695 breakout: 696 h->c->head.cookie = hrevspairs(p); 697 } 698 699 static void 700 mimefresh(Hlex *h, char *) 701 { 702 char *s; 703 704 lexhead(h); 705 for(s = h->wordval; *s && (*s==' ' || *s=='\t'); s++) 706 ; 707 if(strncmp(s, "pathstat/", 9) == 0) 708 h->c->head.fresh_thresh = atoi(s+9); 709 else if(strncmp(s, "have/", 5) == 0) 710 h->c->head.fresh_have = atoi(s+5); 711 } 712 713 static void 714 mimeignore(Hlex *h, char *) 715 { 716 lexhead(h); 717 } 718 719 static void 720 parsejump(Hlex *h, char *k) 721 { 722 int l, r, m; 723 724 l = 1; 725 r = nelem(mimehead) - 1; 726 while(l <= r){ 727 m = (r + l) >> 1; 728 if(cistrcmp(mimehead[m].name, k) <= 0) 729 l = m + 1; 730 else 731 r = m - 1; 732 } 733 m = l - 1; 734 if(cistrcmp(mimehead[m].name, k) == 0 && !mimehead[m].ignore){ 735 mimehead[m].seen = 1; 736 (*mimehead[m].parse)(h, k); 737 }else 738 mimeignore(h, k); 739 } 740 741 static int 742 lex(Hlex *h) 743 { 744 return h->tok = lex1(h, 0); 745 } 746 747 static int 748 lexbase64(Hlex *h) 749 { 750 int c, n; 751 752 n = 0; 753 lex1(h, 1); 754 755 while((c = getc(h)) >= 0){ 756 if(!isalnum(c) && c != '+' && c != '/'){ 757 ungetc(h); 758 break; 759 } 760 if(n < HMaxWord-1) 761 h->wordval[n++] = c; 762 } 763 h->wordval[n] = '\0'; 764 return n; 765 } 766 767 /* 768 * rfc 822/rfc 1521 lexical analyzer 769 */ 770 static int 771 lex1(Hlex *h, int skipwhite) 772 { 773 int level, c; 774 775 if(h->eol) 776 return '\n'; 777 778 top: 779 c = getc(h); 780 switch(c){ 781 case '(': 782 level = 1; 783 while((c = getc(h)) >= 0){ 784 if(c == '\\'){ 785 c = getc(h); 786 if(c < 0) 787 return '\n'; 788 continue; 789 } 790 if(c == '(') 791 level++; 792 else if(c == ')' && --level == 0) 793 break; 794 else if(c == '\n'){ 795 c = getc(h); 796 if(c < 0) 797 return '\n'; 798 if(c == ')' && --level == 0) 799 break; 800 if(c != ' ' && c != '\t'){ 801 ungetc(h); 802 return '\n'; 803 } 804 } 805 } 806 goto top; 807 808 case ' ': case '\t': 809 goto top; 810 811 case '\r': 812 c = getc(h); 813 if(c != '\n'){ 814 ungetc(h); 815 goto top; 816 } 817 818 case '\n': 819 if(h->tok == '\n'){ 820 h->eol = 1; 821 h->eoh = 1; 822 return '\n'; 823 } 824 c = getc(h); 825 if(c < 0){ 826 h->eol = 1; 827 return '\n'; 828 } 829 if(c != ' ' && c != '\t'){ 830 ungetc(h); 831 h->eol = 1; 832 return '\n'; 833 } 834 goto top; 835 836 case ')': 837 case '<': case '>': 838 case '[': case ']': 839 case '@': case '/': 840 case ',': case ';': case ':': case '?': case '=': 841 if(skipwhite){ 842 ungetc(h); 843 return c; 844 } 845 return c; 846 847 case '"': 848 if(skipwhite){ 849 ungetc(h); 850 return c; 851 } 852 word(h, "\""); 853 getc(h); /* skip the closing quote */ 854 return QString; 855 856 default: 857 ungetc(h); 858 if(skipwhite) 859 return c; 860 word(h, "\"(){}<>@,;:/[]?=\r\n \t"); 861 if(h->wordval[0] == '\0'){ 862 h->c->head.closeit = 1; 863 hfail(h->c, HSyntax); 864 longjmp(h->jmp, -1); 865 } 866 return Word; 867 } 868 /* not reached */ 869 } 870 871 /* 872 * return the rest of an rfc 822, including \n 873 * do not map to lower case 874 */ 875 static void 876 lexhead(Hlex *h) 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 == '\n') 887 break; 888 if(c == '\\'){ 889 c = getc(h); 890 if(c < 0) 891 break; 892 } 893 894 if(n < HMaxWord-1) 895 h->wordval[n++] = c; 896 } 897 h->tok = '\n'; 898 h->eol = 1; 899 h->wordval[n] = '\0'; 900 } 901 902 static void 903 word(Hlex *h, char *stop) 904 { 905 int c, n; 906 907 n = 0; 908 while((c = getc(h)) >= 0){ 909 if(c == '\r') 910 c = wordcr(h); 911 else if(c == '\n') 912 c = wordnl(h); 913 if(c == '\\'){ 914 c = getc(h); 915 if(c < 0) 916 break; 917 }else if(c < 32 || strchr(stop, c) != nil){ 918 ungetc(h); 919 break; 920 } 921 922 if(n < HMaxWord-1) 923 h->wordval[n++] = c; 924 } 925 h->wordval[n] = '\0'; 926 } 927 928 static int 929 wordcr(Hlex *h) 930 { 931 int c; 932 933 c = getc(h); 934 if(c == '\n') 935 return wordnl(h); 936 ungetc(h); 937 return ' '; 938 } 939 940 static int 941 wordnl(Hlex *h) 942 { 943 int c; 944 945 c = getc(h); 946 if(c == ' ' || c == '\t') 947 return c; 948 ungetc(h); 949 950 return '\n'; 951 } 952 953 static int 954 getc(Hlex *h) 955 { 956 if(h->eoh) 957 return -1; 958 if(h->c->hpos < h->c->hstop) 959 return *h->c->hpos++; 960 h->eoh = 1; 961 h->eol = 1; 962 return -1; 963 } 964 965 static void 966 ungetc(Hlex *h) 967 { 968 if(h->eoh) 969 return; 970 h->c->hpos--; 971 } 972 973 static ulong 974 digtoul(char *s, char **e) 975 { 976 ulong v; 977 int c, ovfl; 978 979 v = 0; 980 ovfl = 0; 981 for(;;){ 982 c = *s; 983 if(c < '0' || c > '9') 984 break; 985 s++; 986 c -= '0'; 987 if(v > UlongMax/10 || v == UlongMax/10 && c >= UlongMax%10) 988 ovfl = 1; 989 v = v * 10 + c; 990 } 991 992 if(e) 993 *e = s; 994 if(ovfl) 995 return UlongMax; 996 return v; 997 } 998 999 int 1000 http11(HConnect *c) 1001 { 1002 return c->req.vermaj > 1 || c->req.vermaj == 1 && c->req.vermin > 0; 1003 } 1004 1005 char* 1006 hmkmimeboundary(HConnect *c) 1007 { 1008 char buf[32]; 1009 int i; 1010 1011 srand((time(0)<<16)|getpid()); 1012 strcpy(buf, "upas-"); 1013 for(i = 5; i < sizeof(buf)-1; i++) 1014 buf[i] = 'a' + nrand(26); 1015 buf[i] = 0; 1016 return hstrdup(c, buf); 1017 } 1018 1019 HSPairs* 1020 hmkspairs(HConnect *c, char *s, char *t, HSPairs *next) 1021 { 1022 HSPairs *sp; 1023 1024 sp = halloc(c, sizeof *sp); 1025 sp->s = s; 1026 sp->t = t; 1027 sp->next = next; 1028 return sp; 1029 } 1030 1031 HSPairs* 1032 hrevspairs(HSPairs *sp) 1033 { 1034 HSPairs *last, *next; 1035 1036 last = nil; 1037 for(; sp != nil; sp = next){ 1038 next = sp->next; 1039 sp->next = last; 1040 last = sp; 1041 } 1042 return last; 1043 } 1044 1045 HFields* 1046 hmkhfields(HConnect *c, char *s, HSPairs *p, HFields *next) 1047 { 1048 HFields *hf; 1049 1050 hf = halloc(c, sizeof *hf); 1051 hf->s = s; 1052 hf->params = p; 1053 hf->next = next; 1054 return hf; 1055 } 1056 1057 HFields* 1058 hrevhfields(HFields *hf) 1059 { 1060 HFields *last, *next; 1061 1062 last = nil; 1063 for(; hf != nil; hf = next){ 1064 next = hf->next; 1065 hf->next = last; 1066 last = hf; 1067 } 1068 return last; 1069 } 1070 1071 HContent* 1072 hmkcontent(HConnect *c, char *generic, char *specific, HContent *next) 1073 { 1074 HContent *ct; 1075 1076 ct = halloc(c, sizeof(HContent)); 1077 ct->generic = generic; 1078 ct->specific = specific; 1079 ct->next = next; 1080 ct->q = 1; 1081 ct->mxb = 0; 1082 return ct; 1083 } 1084