Return to http_head.c CVS log | Up to [ELWIX - Embedded LightWeight unIX -] / embedaddon / mpd / src / contrib / libpdel / http |
1.1 misho 1: 2: /* 3: * Copyright (c) 2001-2002 Packet Design, LLC. 4: * All rights reserved. 5: * 6: * Subject to the following obligations and disclaimer of warranty, 7: * use and redistribution of this software, in source or object code 8: * forms, with or without modifications are expressly permitted by 9: * Packet Design; provided, however, that: 10: * 11: * (i) Any and all reproductions of the source or object code 12: * must include the copyright notice above and the following 13: * disclaimer of warranties; and 14: * (ii) No rights are granted, in any manner or form, to use 15: * Packet Design trademarks, including the mark "PACKET DESIGN" 16: * on advertising, endorsements, or otherwise except as such 17: * appears in the above copyright notice or in the software. 18: * 19: * THIS SOFTWARE IS BEING PROVIDED BY PACKET DESIGN "AS IS", AND 20: * TO THE MAXIMUM EXTENT PERMITTED BY LAW, PACKET DESIGN MAKES NO 21: * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING 22: * THIS SOFTWARE, INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED 23: * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, 24: * OR NON-INFRINGEMENT. PACKET DESIGN DOES NOT WARRANT, GUARANTEE, 25: * OR MAKE ANY REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS 26: * OF THE USE OF THIS SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, 27: * RELIABILITY OR OTHERWISE. IN NO EVENT SHALL PACKET DESIGN BE 28: * LIABLE FOR ANY DAMAGES RESULTING FROM OR ARISING OUT OF ANY USE 29: * OF THIS SOFTWARE, INCLUDING WITHOUT LIMITATION, ANY DIRECT, 30: * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, PUNITIVE, OR CONSEQUENTIAL 31: * DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, LOSS OF 32: * USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY THEORY OF 33: * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 34: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 35: * THE USE OF THIS SOFTWARE, EVEN IF PACKET DESIGN IS ADVISED OF 36: * THE POSSIBILITY OF SUCH DAMAGE. 37: * 38: * Author: Archie Cobbs <archie@freebsd.org> 39: */ 40: 41: #include <sys/types.h> 42: #include <sys/queue.h> 43: 44: #include <netinet/in.h> 45: 46: #include <stdio.h> 47: #include <stdlib.h> 48: #include <stdarg.h> 49: #include <string.h> 50: #include <limits.h> 51: #include <pthread.h> 52: #include <errno.h> 53: #include <ctype.h> 54: 55: #include <openssl/ssl.h> 56: 57: #include "structs/structs.h" 58: #include "structs/type/array.h" 59: 60: #include "util/typed_mem.h" 61: #include "http/http_defs.h" 62: #include "http/http_server.h" 63: #include "http/http_internal.h" 64: 65: #define CR '\r' 66: #define LF '\n' 67: 68: #define MAX_STRING (64 * 1024) 69: 70: #define MEM_TYPE_HEAD "http_head" 71: #define MEM_TYPE_HDRS "http_head.hdrs" 72: #define MEM_TYPE_NAME "http_head.name" 73: #define MEM_TYPE_VALUE "http_head.value" 74: 75: #define issep(ch) (strchr("()<>@,;:\\\"/[]?={} \t", ch) != NULL) 76: 77: struct http_header { 78: char *name; 79: char *value; 80: }; 81: 82: struct http_head { 83: char *words[3]; /* first line stuff */ 84: int num_hdrs; /* number of headers */ 85: struct http_header *hdrs; /* headers, sorted */ 86: }; 87: 88: /* 89: * Internal variables 90: */ 91: static const char *header_sort[] = { 92: HTTP_HEADER_DATE, 93: HTTP_HEADER_SERVER, 94: HTTP_HEADER_CONNECTION, 95: HTTP_HEADER_PROXY_CONNECTION, 96: HTTP_HEADER_CACHE_CONTROL, 97: HTTP_HEADER_PRAGMA, 98: HTTP_HEADER_LAST_MODIFIED, 99: HTTP_HEADER_WWW_AUTHENTICATE, 100: HTTP_HEADER_CONTENT_TYPE, 101: HTTP_HEADER_CONTENT_LENGTH, 102: HTTP_HEADER_CONTENT_ENCODING, 103: }; 104: #define NUM_HEADER_SORT (sizeof(header_sort) / sizeof(*header_sort)) 105: 106: /* 107: * Internal functions 108: */ 109: static int http_head_special(const char *name); 110: static int http_header_cmp(const void *v1, const void *v2); 111: static char *read_hval(FILE *fp); 112: static char *read_line(FILE *fp, const char *mtype); 113: static char *read_token(FILE *fp, int liberal, const char *mtype); 114: static void read_whitespace(FILE *fp); 115: static int addch(char **sp, int *slen, int ch, const char *mtype); 116: 117: /* 118: * Create new header object. 119: */ 120: struct http_head * 121: _http_head_new(void) 122: { 123: struct http_head *head; 124: 125: /* Create structure */ 126: if ((head = MALLOC(MEM_TYPE_HEAD, sizeof(*head))) == NULL) 127: return (NULL); 128: memset(head, 0, sizeof(*head)); 129: return (head); 130: } 131: 132: /* 133: * Free a header object. 134: */ 135: void 136: _http_head_free(struct http_head **headp) 137: { 138: struct http_head *const head = *headp; 139: int i; 140: 141: if (head == NULL) 142: return; 143: for (i = 0; i < 3; i++) 144: FREE(MEM_TYPE_VALUE, head->words[i]); 145: for (i = 0; i < head->num_hdrs; i++) { 146: struct http_header *const hdr = &head->hdrs[i]; 147: 148: FREE(MEM_TYPE_NAME, hdr->name); 149: FREE(MEM_TYPE_VALUE, hdr->value); 150: } 151: FREE(MEM_TYPE_HDRS, head->hdrs); 152: FREE(MEM_TYPE_HEAD, head); 153: *headp = NULL; 154: } 155: 156: /* 157: * Copy headers 158: */ 159: struct http_head * 160: _http_head_copy(struct http_head *head0) 161: { 162: struct http_head *head; 163: int i; 164: 165: /* Get new header struct */ 166: if ((head = _http_head_new()) == NULL) 167: goto fail; 168: 169: /* Copy first line words */ 170: for (i = 0; i < 3; i++) { 171: if (head0->words[i] == NULL) 172: continue; 173: if ((head->words[i] = STRDUP(MEM_TYPE_VALUE, 174: head0->words[i])) == NULL) 175: goto fail; 176: } 177: 178: /* Copy other headers */ 179: for (i = 0; i < head0->num_hdrs; i++) { 180: const char *name; 181: const char *value; 182: 183: if (_http_head_get_by_index(head0, i, &name, &value) == -1) 184: goto fail; 185: if (_http_head_set(head, 0, name, "%s", value) == -1) 186: goto fail; 187: } 188: 189: /* Done */ 190: return (head); 191: 192: fail: 193: _http_head_free(&head); 194: return (NULL); 195: } 196: 197: /* 198: * Get a header field value. 199: * 200: * For headers listed multiple times, this only gets the first instance. 201: */ 202: const char * 203: _http_head_get(struct http_head *head, const char *name) 204: { 205: struct http_header key; 206: struct http_header *hdr; 207: int i; 208: 209: /* First line stuff */ 210: if ((i = http_head_special(name)) != -1) 211: return (head->words[i]); 212: 213: /* Normal headers */ 214: key.name = (char *)name; 215: if ((hdr = bsearch(&key, head->hdrs, head->num_hdrs, 216: sizeof(*head->hdrs), http_header_cmp)) == NULL) { 217: errno = ENOENT; 218: return (NULL); 219: } 220: return (hdr->value); 221: } 222: 223: /* 224: * Get the number of headers 225: */ 226: int 227: _http_head_num_headers(struct http_head *head) 228: { 229: return (head->num_hdrs); 230: } 231: 232: /* 233: * Get a header by index. 234: */ 235: int 236: _http_head_get_by_index(struct http_head *head, u_int index, 237: const char **namep, const char **valuep) 238: { 239: if (index >= head->num_hdrs) { 240: errno = EINVAL; 241: return (-1); 242: } 243: if (namep != NULL) 244: *namep = head->hdrs[index].name; 245: if (valuep != NULL) 246: *valuep = head->hdrs[index].value; 247: return (0); 248: } 249: 250: /* 251: * Get the names of all headers. 252: */ 253: int 254: _http_head_get_headers(struct http_head *head, 255: const char **names, size_t max_names) 256: { 257: int i; 258: 259: if (max_names > head->num_hdrs) 260: max_names = head->num_hdrs; 261: for (i = 0; i < max_names; i++) 262: names[i] = head->hdrs[i].name; 263: return (i); 264: } 265: 266: /* 267: * Set header value, in either append or replace mode. 268: */ 269: int 270: _http_head_set(struct http_head *head, int append, 271: const char *name, const char *valfmt, ...) 272: { 273: va_list args; 274: int ret; 275: 276: va_start(args, valfmt); 277: ret = _http_head_vset(head, append, name, valfmt, args); 278: va_end(args); 279: return (ret); 280: } 281: 282: /* 283: * Set header value, in either append or replace mode. 284: */ 285: int 286: _http_head_vset(struct http_head *head, int append, 287: const char *name, const char *valfmt, va_list args) 288: { 289: struct http_header key; 290: struct http_header *hdr; 291: char *value; 292: void *mem; 293: int i; 294: 295: /* Generate value */ 296: VASPRINTF(MEM_TYPE_VALUE, &value, valfmt, args); 297: if (value == NULL) 298: return (-1); 299: 300: /* First line stuff */ 301: if ((i = http_head_special(name)) != -1) { 302: FREE(MEM_TYPE_VALUE, head->words[i]); 303: head->words[i] = value; 304: return (0); 305: } 306: 307: /* If header doesn't already exist, add it (unless special) */ 308: key.name = (char *)name; 309: if (strcasecmp(name, HTTP_HEADER_SET_COOKIE) == 0 /* XXX blech */ 310: || (hdr = bsearch(&key, head->hdrs, head->num_hdrs, 311: sizeof(*head->hdrs), http_header_cmp)) == NULL) { 312: 313: /* Extend headers array */ 314: if ((mem = REALLOC(MEM_TYPE_HDRS, head->hdrs, 315: (head->num_hdrs + 1) * sizeof(*head->hdrs))) == NULL) { 316: FREE(MEM_TYPE_VALUE, value); 317: return (-1); 318: } 319: head->hdrs = mem; 320: hdr = &head->hdrs[head->num_hdrs]; 321: 322: /* Copy name */ 323: if ((hdr->name = STRDUP(MEM_TYPE_NAME, name)) == NULL) { 324: FREE(MEM_TYPE_VALUE, value); 325: return (-1); 326: } 327: 328: /* Add new header */ 329: hdr->value = value; 330: head->num_hdrs++; 331: 332: /* Keep array sorted */ 333: (void)mergesort(head->hdrs, head->num_hdrs, 334: sizeof(*head->hdrs), http_header_cmp); 335: return (0); 336: } 337: 338: /* Append or replace */ 339: if (append) { 340: const int plen = strlen(hdr->value); 341: 342: if ((mem = REALLOC(MEM_TYPE_VALUE, 343: hdr->value, plen + strlen(value) + 3)) == NULL) { 344: FREE(MEM_TYPE_VALUE, value); 345: return (-1); 346: } 347: hdr->value = mem; 348: sprintf(hdr->value + plen, ", %s", value); 349: FREE(MEM_TYPE_VALUE, value); 350: } else { 351: FREE(MEM_TYPE_VALUE, hdr->value); 352: hdr->value = value; 353: } 354: return (0); 355: } 356: 357: /* 358: * Remove a header. 359: */ 360: int 361: _http_head_remove(struct http_head *head, const char *name) 362: { 363: struct http_header key; 364: struct http_header *hdr; 365: int i; 366: 367: /* First line stuff */ 368: if ((i = http_head_special(name)) != -1) { 369: if (head->words[i] != NULL) { 370: FREE(MEM_TYPE_VALUE, head->words[i]); 371: head->words[i] = NULL; 372: return (1); 373: } 374: return (0); 375: } 376: 377: /* Does header exist? */ 378: key.name = (char *)name; 379: if ((hdr = bsearch(&key, head->hdrs, head->num_hdrs, 380: sizeof(*head->hdrs), http_header_cmp)) == NULL) 381: return (0); 382: 383: /* Remove header */ 384: i = hdr - head->hdrs; 385: FREE(MEM_TYPE_NAME, hdr->name); 386: FREE(MEM_TYPE_VALUE, hdr->value); 387: memmove(head->hdrs + i, head->hdrs + i + 1, 388: (--head->num_hdrs - i) * sizeof(*head->hdrs)); 389: return (1); 390: } 391: 392: /* 393: * Return index for one of the 'special' headers representing 394: * one of the three parts of the first line of the HTTP request 395: * or response. 396: */ 397: static int 398: http_head_special(const char *name) 399: { 400: if (name == HDR_REQUEST_METHOD) /* also HDR_REPLY_VERSION */ 401: return (0); 402: if (name == HDR_REQUEST_URI) /* also HDR_REPLY_STATUS */ 403: return (1); 404: if (name == HDR_REQUEST_VERSION) /* also HDR_REPLY_REASON */ 405: return (2); 406: return (-1); 407: } 408: 409: /* 410: * Compare two headers by name. 411: * 412: * XXX this could be faster 413: */ 414: static int 415: http_header_cmp(const void *v1, const void *v2) 416: { 417: const struct http_header *const hdrs[] = { v1, v2 }; 418: int sortval[2]; 419: int i, j; 420: 421: /* Check assigned ordering list */ 422: for (i = 0; i < 2; i++) { 423: const char *hdr = hdrs[i]->name; 424: 425: sortval[i] = INT_MAX; 426: for (j = 0; j < NUM_HEADER_SORT; j++) { 427: if (strcasecmp(hdr, header_sort[j]) == 0) { 428: sortval[i] = j; 429: break; 430: } 431: } 432: } 433: if (sortval[0] == INT_MAX && sortval[1] == INT_MAX) 434: return (strcasecmp(hdrs[0]->name, hdrs[1]->name)); 435: return (sortval[0] - sortval[1]); 436: } 437: 438: /* 439: * Read an entire HTTP request or response header. 440: */ 441: int 442: _http_head_read(struct http_head *head, FILE *fp, int req) 443: { 444: int ch; 445: 446: /* Read any initial whitespace including CR, LF */ 447: while ((ch = getc(fp)) != EOF) { 448: if (!isspace(ch)) { 449: ungetc(ch, fp); 450: break; 451: } 452: } 453: 454: /* Read first word */ 455: FREE(MEM_TYPE_VALUE, head->words[0]); 456: if ((head->words[0] = read_token(fp, 1, MEM_TYPE_VALUE)) == NULL) 457: return (-1); 458: 459: /* Get whitespace */ 460: read_whitespace(fp); 461: 462: /* Read second word */ 463: FREE(MEM_TYPE_VALUE, head->words[1]); 464: if ((head->words[1] = read_token(fp, 1, MEM_TYPE_VALUE)) == NULL) 465: return (-1); 466: 467: /* Get whitespace */ 468: read_whitespace(fp); 469: 470: /* Read third and remaining words on the line including CR-LF */ 471: FREE(MEM_TYPE_VALUE, head->words[2]); 472: if ((head->words[2] = read_line(fp, MEM_TYPE_VALUE)) == NULL) 473: return (-1); 474: 475: /* Special format for HTTP 0.9 request (no protocol or headers) */ 476: if (req && *head->words[2] == '\0') { 477: FREE(MEM_TYPE_VALUE, head->words[2]); 478: if ((head->words[2] = STRDUP(MEM_TYPE_VALUE, 479: HTTP_PROTO_0_9)) == NULL) 480: return (-1); 481: return (0); 482: } 483: 484: /* Read headers */ 485: if (_http_head_read_headers(head, fp) == -1) 486: return (-1); 487: 488: /* Done */ 489: return (0); 490: } 491: 492: /* 493: * Read HTTP headers 494: */ 495: int 496: _http_head_read_headers(struct http_head *head, FILE *fp) 497: { 498: char *name; 499: char *value; 500: int ret; 501: int ch; 502: 503: while (1) { 504: 505: /* Check for CR-LF */ 506: if ((ch = getc(fp)) == EOF) { 507: if (ferror(fp)) 508: goto fail; 509: goto fail_invalid; 510: } 511: if (ch == CR) { 512: if ((ch = getc(fp)) != LF) { 513: if (ch == EOF && ferror(fp)) 514: goto fail; 515: goto fail_invalid; 516: } 517: return (0); 518: } 519: ungetc(ch, fp); 520: 521: /* Get header name */ 522: if ((name = read_token(fp, 0, MEM_TYPE_NAME)) == NULL) 523: goto fail; 524: 525: /* Get separator */ 526: if ((ch = getc(fp)) != ':') { 527: FREE(MEM_TYPE_NAME, name); 528: goto fail_invalid; 529: } 530: 531: /* Get whitespace */ 532: read_whitespace(fp); 533: 534: /* Get header value including final CR-LF */ 535: if ((value = read_hval(fp)) == NULL) { 536: FREE(MEM_TYPE_NAME, name); 537: goto fail; 538: } 539: 540: /* Append to header value */ 541: ret = _http_head_set(head, 1, name, "%s", value); 542: FREE(MEM_TYPE_NAME, name); 543: FREE(MEM_TYPE_VALUE, value); 544: if (ret == -1) 545: goto fail; 546: } 547: 548: fail_invalid: 549: errno = EINVAL; 550: fail: 551: return (-1); 552: } 553: 554: /* 555: * Write out an HTTP header. 556: */ 557: int 558: _http_head_write(struct http_head *head, FILE *fp) 559: { 560: int i; 561: 562: for (i = 0; i < 3; i++) { 563: if (head->words[i] == NULL) { 564: errno = EINVAL; 565: return (-1); 566: } 567: } 568: fprintf(fp, "%s %s %s\r\n", 569: head->words[0], head->words[1], head->words[2]); 570: for (i = 0; i < head->num_hdrs; i++) { 571: struct http_header *const hdr = &head->hdrs[i]; 572: 573: fprintf(fp, "%s: %s\r\n", hdr->name, hdr->value); 574: } 575: fprintf(fp, "\r\n"); 576: #if 0 577: fflush(fp); 578: #endif 579: return (0); 580: } 581: 582: /* 583: * Figure out whether there is anything in the head or not. 584: */ 585: int 586: _http_head_has_anything(struct http_head *head) 587: { 588: return (head->words[0] != NULL); 589: } 590: 591: /* 592: * Determine if keep alive is requested. 593: */ 594: int 595: _http_head_want_keepalive(struct http_head *head) 596: { 597: const char *hval; 598: 599: return (((hval = _http_head_get(head, HTTP_HEADER_CONNECTION)) != NULL 600: || (hval = _http_head_get(head, 601: HTTP_HEADER_PROXY_CONNECTION)) != NULL) 602: && strcasecmp(hval, "Keep-Alive") == 0); 603: } 604: 605: /* 606: * Read an HTTP header value. 607: */ 608: static char * 609: read_hval(FILE *fp) 610: { 611: char *s = NULL; 612: int inquote = 0; 613: int bslash = 0; 614: int slen = 0; 615: int ch; 616: 617: /* Read characters */ 618: while (1) { 619: if ((ch = getc(fp)) == EOF) { 620: if (ferror(fp)) 621: goto fail; 622: goto fail_invalid; 623: } 624: if (bslash) { /* implies inquote */ 625: if (!addch(&s, &slen, ch, MEM_TYPE_VALUE)) 626: goto fail; 627: bslash = 0; 628: continue; 629: } 630: switch (ch) { 631: case '"': 632: inquote = !inquote; 633: break; 634: case '\\': 635: if (inquote) { 636: bslash = 1; 637: continue; 638: } 639: case CR: 640: if ((ch = getc(fp)) != LF) { /* read linefeed */ 641: if (ch == EOF && ferror(fp)) 642: goto fail; 643: goto fail_invalid; 644: } 645: if ((ch = getc(fp)) == EOF) { /* get next char */ 646: if (ferror(fp)) 647: goto fail; 648: goto fail_invalid; 649: } 650: if (ch == ' ' || ch == '\t') { /* line continuation */ 651: read_whitespace(fp); 652: ch = ' '; 653: break; 654: } 655: ungetc(ch, fp); 656: goto done; 657: default: 658: if (iscntrl(ch) && ch != ' ' && ch != '\t') 659: goto fail_invalid; 660: break; 661: } 662: if (!addch(&s, &slen, ch, MEM_TYPE_VALUE)) 663: goto fail; 664: } 665: 666: done: 667: /* Terminate and return string */ 668: if (!addch(&s, &slen, '\0', MEM_TYPE_VALUE)) 669: goto fail; 670: return (s); 671: 672: fail_invalid: 673: errno = EINVAL; 674: fail: 675: FREE(MEM_TYPE_VALUE, s); 676: return (NULL); 677: } 678: 679: /* 680: * Read up through end of line and return value, not including CR-LF. 681: */ 682: static char * 683: read_line(FILE *fp, const char *mtype) 684: { 685: char *s = NULL; 686: int slen = 0; 687: int ch; 688: 689: /* Read characters */ 690: while (1) { 691: if ((ch = getc(fp)) == EOF) { 692: if (ferror(fp)) 693: goto fail; 694: goto fail_invalid; 695: } 696: if (ch == CR) { 697: if ((ch = getc(fp)) != LF) { 698: if (ch == EOF && ferror(fp)) 699: goto fail; 700: goto fail_invalid; 701: } 702: goto done; 703: } 704: if (ch == LF) /* handle broken clients */ 705: break; 706: if (!addch(&s, &slen, ch, mtype)) 707: goto fail; 708: } 709: 710: done: 711: /* Terminate and return string */ 712: if (!addch(&s, &slen, '\0', mtype)) 713: goto fail; 714: return (s); 715: 716: fail_invalid: 717: errno = EINVAL; 718: fail: 719: FREE(mtype, s); 720: return (NULL); 721: } 722: 723: /* 724: * Read an HTTP header token. 725: */ 726: static char * 727: read_token(FILE *fp, int liberal, const char *mtype) 728: { 729: char *s = NULL; 730: int slen = 0; 731: int ch; 732: 733: /* Read characters */ 734: while (1) { 735: if ((ch = getc(fp)) == EOF) { 736: if (ferror(fp)) 737: goto fail; 738: goto fail_invalid; 739: } 740: if (!isprint(ch) 741: || (ch == ' ' || ch == '\t') 742: || (!liberal && issep(ch))) { 743: ungetc(ch, fp); 744: break; 745: } 746: if (!addch(&s, &slen, ch, mtype)) 747: goto fail; 748: } 749: 750: /* Terminate and return string */ 751: if (!addch(&s, &slen, '\0', mtype)) 752: goto fail; 753: return (s); 754: 755: fail_invalid: 756: errno = EINVAL; 757: fail: 758: FREE(mtype, s); 759: return (NULL); 760: } 761: 762: /* 763: * Read any amount of whitespace. 764: */ 765: static void 766: read_whitespace(FILE *fp) 767: { 768: int ch; 769: 770: while (1) { 771: if ((ch = getc(fp)) == EOF) 772: return; 773: if (ch != ' ' && ch != '\t') { 774: ungetc(ch, fp); 775: break; 776: } 777: } 778: } 779: 780: /* 781: * Add a character to a malloc'd string. 782: */ 783: static int 784: addch(char **sp, int *slen, int ch, const char *mtype) 785: { 786: void *mem; 787: 788: if (*slen >= MAX_STRING) { 789: errno = E2BIG; 790: return (0); 791: } 792: if (*slen % 128 == 0) { 793: if ((mem = REALLOC(mtype, *sp, *slen + 128)) == NULL) 794: return (0); 795: *sp = mem; 796: } 797: (*sp)[(*slen)++] = ch; 798: return (1); 799: } 800: