Return to http_response.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/param.h> 43: #include <sys/queue.h> 44: 45: #include <netinet/in.h> 46: 47: #include <stdio.h> 48: #include <stdlib.h> 49: #include <stdarg.h> 50: #include <string.h> 51: #include <pthread.h> 52: #include <limits.h> 53: #include <ctype.h> 54: #include <syslog.h> 55: #include <errno.h> 56: #include <assert.h> 57: 58: #include <openssl/ssl.h> 59: 60: #include "structs/structs.h" 61: #include "structs/type/array.h" 62: 63: #include "http/http_defs.h" 64: #include "http/http_server.h" 65: #include "http/http_internal.h" 66: #include "util/typed_mem.h" 67: 68: struct suffix_map { 69: const char *suffix; 70: const char *mime; 71: }; 72: 73: /* error responses */ 74: #define MALFORMED_RESPONSE_MSG "Malformed response" 75: #define TIMEOUT_RESPONSE_MSG "Server timed out" 76: 77: /* 78: * Internal functions 79: */ 80: static int suffix_cmp(const void *v1, const void *v2); 81: 82: /* Filename suffix -> MIME encoding (list is sorted case insensitively) */ 83: static const struct suffix_map mime_encodings[] = { 84: { "gz", "gzip" }, 85: { "uu", "x-uuencode" }, 86: { "Z", "compress" }, 87: }; 88: static const int num_mime_encodings 89: = sizeof(mime_encodings) / sizeof(*mime_encodings); 90: 91: /* Filename suffix -> MIME type (list is sorted case insensitively) */ 92: static const struct suffix_map mime_types[] = { 93: { "a", "application/octet-stream" }, 94: { "aab", "application/x-authorware-bin" }, 95: { "aam", "application/x-authorware-map" }, 96: { "aas", "application/x-authorware-seg" }, 97: { "ai", "application/postscript" }, 98: { "aif", "audio/x-aiff" }, 99: { "aifc", "audio/x-aiff" }, 100: { "aiff", "audio/x-aiff" }, 101: { "au", "audio/basic" }, 102: { "avi", "video/x-msvideo" }, 103: { "bcpio", "application/x-bcpio" }, 104: { "bin", "application/octet-stream" }, 105: { "cdf", "application/x-netcdf" }, 106: { "class", "application/java" }, 107: { "cpio", "application/x-cpio" }, 108: { "css", "text/css" }, 109: { "dcr", "application/x-director" }, 110: { "dir", "application/x-director" }, 111: { "doc", "application/msword" }, 112: { "dtd", "text/xml" }, 113: { "dump", "application/octet-stream" }, 114: { "dvi", "application/x-dvi" }, 115: { "dxr", "application/x-director" }, 116: { "eps", "application/postscript" }, 117: { "etx", "text/x-setext" }, 118: { "exe", "application/octet-stream" }, 119: { "fgd", "application/x-director" }, 120: { "fh", "image/x-freehand" }, 121: { "fh4", "image/x-freehand" }, 122: { "fh5", "image/x-freehand" }, 123: { "fh7", "image/x-freehand" }, 124: { "fhc", "image/x-freehand" }, 125: { "gif", "image/gif" }, 126: { "gtar", "application/x-gtar" }, 127: { "hdf", "application/x-hdf" }, 128: { "hqx", "application/mac-binhex40" }, 129: { "htm", "text/html" }, 130: { "html", "text/html" }, 131: { "ief", "image/ief" }, 132: { "iv", "application/x-inventor" }, 133: { "jfif", "image/jpeg" }, 134: { "jpe", "image/jpeg" }, 135: { "jpeg", "image/jpeg" }, 136: { "jpg", "image/jpeg" }, 137: { "js", "application/x-javascript" }, 138: { "kar", "audio/midi" }, 139: { "latex", "application/x-latex" }, 140: { "man", "application/x-troff-man" }, 141: { "man", "application/x-troff-man" }, 142: { "me", "application/x-troff-me" }, 143: { "me", "application/x-troff-me" }, 144: { "mid", "audio/midi" }, 145: { "midi", "audio/midi" }, 146: { "mif", "application/x-mif" }, 147: { "mime", "message/rfc822" }, 148: { "mmf", "application/x-www-urlformencoded" }, 149: { "mov", "video/quicktime" }, 150: { "movie", "video/x-sgi-movie" }, 151: { "mp2", "audio/mpeg" }, 152: { "mp3", "audio/mpeg" }, 153: { "mpe", "video/mpeg" }, 154: { "mpeg", "video/mpeg" }, 155: { "mpg", "video/mpeg" }, 156: { "mpga", "audio/mpeg" }, 157: { "ms", "application/x-troff-ms" }, 158: { "ms", "application/x-troff-ms" }, 159: { "mv", "video/x-sgi-movie" }, 160: { "nc", "application/x-netcdf" }, 161: { "o", "application/octet-stream" }, 162: { "oda", "application/oda" }, 163: { "pac", "application/x-ns-proxy-autoconfig" }, 164: { "pbm", "image/x-portable-bitmap" }, 165: { "pdf", "application/pdf" }, 166: { "pgm", "image/x-portable-graymap" }, 167: { "png", "image/png" }, 168: { "pnm", "image/x-portable-anymap" }, 169: { "ppm", "image/x-portable-pixmap" }, 170: { "ppt", "application/powerpoint" }, 171: { "ps", "application/postscript" }, 172: { "qt", "video/quicktime" }, 173: { "ra", "audio/x-pn-realaudio" }, 174: { "ram", "audio/x-pn-realaudio" }, 175: { "rm", "audio/x-pn-realaudio" }, 176: { "roff", "application/x-troff" }, 177: { "rpm", "audio/x-pn-realaudio-plugin" }, 178: { "rtf", "application/rtf" }, 179: { "rtx", "text/richtext" }, 180: { "sh", "application/x-shar" }, 181: { "shar", "application/x-shar" }, 182: { "sit", "application/x-stuffit" }, 183: { "snd", "audio/basic" }, 184: { "spl", "application/futuresplash" }, 185: { "sv4cpio", "application/x-sv4cpio" }, 186: { "sv4crc", "application/x-sv4crc" }, 187: { "swf", "application/x-shockwave-flash" }, 188: { "tar", "application/x-tar" }, 189: { "tex", "application/x-tex" }, 190: { "texi", "application/x-texinfo" }, 191: { "texinfo", "application/x-texinfo" }, 192: { "tif", "image/tiff" }, 193: { "tiff", "image/tiff" }, 194: { "tmpl", "text/plain" }, /* template file input */ 195: { "tr", "application/x-troff" }, 196: { "tsp", "application/dsptype" }, 197: { "tsv", "text/tab-separated-values" }, 198: { "txt", "text/plain" }, 199: { "ustar", "application/x-ustar" }, 200: { "vrml", "model/vrml" }, 201: { "vx", "video/x-rad-screenplay" }, 202: { "wav", "audio/wav" }, 203: { "wbmp", "image/vnd.wap.wbmp" }, 204: { "wml", "text/vnd.wap.wml" }, 205: { "wmlc", "application/vnd.wap.wmlc" }, 206: { "wmls", "text/vnd.wap.wmlscript" }, 207: { "wmlsc", "application/vnd.wap.wmlscriptc" }, 208: { "wrl", "model/vrml" }, 209: { "wsrc", "application/x-wais-source" }, 210: { "xbm", "image/x-xbitmap" }, 211: { "xml", "text/xml" }, 212: { "xpm", "image/x-xpixmap" }, 213: { "xwd", "image/x-xwindowdump" }, 214: { "zip", "application/x-zip-compressed" }, 215: }; 216: static const int num_mime_types = sizeof(mime_types) / sizeof(*mime_types); 217: 218: /********************************************************************* 219: MAIN ROUTINES 220: *********************************************************************/ 221: 222: /* 223: * Create a new response structure. 224: */ 225: int 226: _http_response_new(struct http_connection *conn) 227: { 228: struct http_response *resp; 229: 230: /* Create response structure */ 231: assert(conn->resp == NULL); 232: if ((resp = MALLOC("http_response", sizeof(*resp))) == NULL) { 233: (*conn->logger)(LOG_ERR, "%s: %s", "malloc", strerror(errno)); 234: return (-1); 235: } 236: memset(resp, 0, sizeof(*resp)); 237: 238: /* Attach message structure */ 239: if ((resp->msg = _http_message_new()) == NULL) { 240: (*conn->logger)(LOG_ERR, "%s: %s", "malloc", strerror(errno)); 241: FREE("http_response", resp); 242: return (-1); 243: } 244: 245: /* Link it up */ 246: resp->msg->conn = conn; 247: conn->resp = resp; 248: return (0); 249: } 250: 251: /* 252: * Read in, validate, and prep an HTTP response from a connection. 253: * 254: * In all cases, fill in the error message buffer. 255: */ 256: int 257: _http_response_read(struct http_connection *conn, char *errbuf, int size) 258: { 259: struct http_response *const resp = conn->resp; 260: const char *hval; 261: 262: /* Load in message from HTTP connection */ 263: if (_http_message_read(resp->msg, 0) == -1) { 264: switch (errno) { 265: case EINVAL: 266: strlcpy(errbuf, MALFORMED_RESPONSE_MSG, size); 267: break; 268: 269: case ETIMEDOUT: 270: strlcpy(errbuf, TIMEOUT_RESPONSE_MSG, size); 271: break; 272: 273: default: 274: strlcpy(errbuf, strerror(errno), size); 275: break; 276: } 277: 278: /* fix errno now that we've used it */ 279: conn->keep_alive = 0; 280: errno = EINVAL; 281: return (-1); 282: } 283: 284: /* Set code */ 285: hval = http_response_get_header(resp, HDR_REPLY_STATUS); 286: if (sscanf(hval, "%u", &resp->code) != 1) { 287: snprintf(errbuf, size, "Invalid response code ``%s''", hval); 288: conn->keep_alive = 0; 289: errno = EINVAL; 290: return (-1); 291: } 292: 293: /* Expect no body from certain responses */ 294: if (http_response_no_body(resp->code)) { 295: resp->msg->input_len = 0; 296: resp->msg->no_body = 1; 297: } else if (resp->msg->input_len == UINT_MAX 298: && _http_head_want_keepalive(resp->msg->head)) { 299: snprintf(errbuf, size, 300: "Keep-Alive requres %s", HTTP_HEADER_CONTENT_LENGTH); 301: conn->keep_alive = 0; 302: errno = EINVAL; 303: return (-1); 304: } 305: 306: /* Turn off keep alive if not specified by remote side */ 307: if (!_http_head_want_keepalive(resp->msg->head)) 308: conn->keep_alive = 0; 309: 310: /* Done */ 311: strlcpy(errbuf, http_response_get_header(resp, HDR_REPLY_REASON), size); 312: return (0); 313: } 314: 315: /* 316: * Free a response 317: */ 318: void 319: _http_response_free(struct http_response **respp) 320: { 321: struct http_response *const resp = *respp; 322: 323: if (resp == NULL) 324: return; 325: _http_message_free(&resp->msg); 326: FREE("http_response", resp); 327: *respp = NULL; 328: } 329: 330: /* 331: * Get response code. 332: */ 333: int 334: http_response_get_code(struct http_response *resp) 335: { 336: return (resp->code); 337: } 338: 339: /********************************************************************* 340: MESSAGE WRAPPERS 341: *********************************************************************/ 342: 343: /* 344: * Set a response header. 345: */ 346: int 347: http_response_set_header(struct http_response *resp, int append, 348: const char *name, const char *valfmt, ...) 349: { 350: va_list args; 351: int ret; 352: 353: /* Set header */ 354: va_start(args, valfmt); 355: ret = _http_message_vset_header(resp->msg, append, name, valfmt, args); 356: va_end(args); 357: if (ret == -1) 358: return (-1); 359: 360: /* Remember response code */ 361: if (name == HDR_REPLY_STATUS) { 362: resp->code = atoi(http_response_get_header(resp, name)); 363: resp->msg->no_body = http_response_no_body(resp->code); 364: } 365: 366: /* Done */ 367: return (0); 368: } 369: 370: /* 371: * Get a response header. 372: * 373: * For headers listed multiple times, this only gets the first instance. 374: */ 375: const char * 376: http_response_get_header(struct http_response *resp, const char *name) 377: { 378: return (_http_head_get(resp->msg->head, name)); 379: } 380: 381: /* 382: * Get the number of headers 383: */ 384: int 385: http_response_num_headers(struct http_response *resp) 386: { 387: return (_http_head_num_headers(resp->msg->head)); 388: } 389: 390: /* 391: * Get header by index. 392: */ 393: int 394: http_response_get_header_by_index(struct http_response *resp, 395: u_int index, const char **namep, const char **valuep) 396: { 397: return (_http_head_get_by_index(resp->msg->head, index, namep, valuep)); 398: } 399: 400: /* 401: * Remove a header. 402: */ 403: int 404: http_response_remove_header(struct http_response *resp, const char *name) 405: { 406: return (_http_message_remove_header(resp->msg, name)); 407: } 408: 409: /* 410: * Send response headers, if not sent already. 411: */ 412: int 413: http_response_send_headers(struct http_response *resp, int unbuffer) 414: { 415: _http_message_send_headers(resp->msg, unbuffer); 416: return (0); 417: } 418: 419: /* 420: * Get response input stream. 421: */ 422: FILE * 423: http_response_get_input(struct http_response *resp) 424: { 425: if (resp->msg->conn->server) { 426: errno = EINVAL; 427: return (NULL); 428: } 429: return (resp->msg->input); 430: } 431: 432: /* 433: * Get response output stream. 434: */ 435: FILE * 436: http_response_get_output(struct http_response *resp, int buffer) 437: { 438: if (!resp->msg->conn->server) { 439: errno = EINVAL; 440: return (NULL); 441: } 442: return (_http_message_get_output(resp->msg, buffer)); 443: } 444: 445: /* 446: * Get raw i/o stream as a file descriptor. 447: */ 448: int 449: http_response_get_raw_socket(struct http_response *resp) 450: { 451: return (_http_message_get_raw_socket(resp->msg)); 452: } 453: 454: /* 455: * Get remote IP address. 456: */ 457: struct in_addr 458: http_response_get_remote_ip(struct http_response *resp) 459: { 460: return (_http_message_get_remote_ip(resp->msg)); 461: } 462: 463: /* 464: * Get remote port. 465: */ 466: u_int16_t 467: http_response_get_remote_port(struct http_response *resp) 468: { 469: return (_http_message_get_remote_port(resp->msg)); 470: } 471: 472: /* 473: * Get SSL context. 474: */ 475: SSL_CTX * 476: http_response_get_ssl(struct http_response *resp) 477: { 478: return (resp->msg->conn->ssl); 479: } 480: 481: /********************************************************************* 482: SERVLET HELPERS 483: *********************************************************************/ 484: 485: /* 486: * Send an HTTP redirect. 487: */ 488: void 489: http_response_send_redirect(struct http_response *resp, const char *url) 490: { 491: const char *name; 492: const char *value; 493: 494: while (_http_head_get_by_index(resp->msg->head, 0, &name, &value) == 0) 495: _http_head_remove(resp->msg->head, name); 496: http_response_set_header(resp, 0, HDR_REPLY_STATUS, 497: "%d", HTTP_STATUS_MOVED_PERMANENTLY); 498: http_response_set_header(resp, 0, HDR_REPLY_REASON, 499: "%s", http_response_status_msg(HTTP_STATUS_MOVED_PERMANENTLY)); 500: http_response_set_header(resp, 0, "Location", "%s", url); 501: } 502: 503: /* 504: * Send an HTTP authorization failed response. 505: */ 506: void 507: http_response_send_basic_auth(struct http_response *resp, const char *realm) 508: { 509: http_response_set_header(resp, 0, HTTP_HEADER_WWW_AUTHENTICATE, 510: "Basic realm=\"%s\"", realm); 511: _http_head_remove(resp->msg->head, HTTP_HEADER_LAST_MODIFIED); 512: http_response_send_error(resp, HTTP_STATUS_UNAUTHORIZED, NULL); 513: } 514: 515: /* 516: * Convert 'errno' into an HTTP error response. 517: */ 518: void 519: http_response_send_errno_error(struct http_response *resp) 520: { 521: int code; 522: 523: switch (errno) { 524: case ENOENT: 525: case ENOTDIR: 526: code = HTTP_STATUS_NOT_FOUND; 527: break; 528: case EPERM: 529: case EACCES: 530: code = HTTP_STATUS_FORBIDDEN; 531: break; 532: default: 533: code = HTTP_STATUS_INTERNAL_SERVER_ERROR; 534: break; 535: } 536: http_response_send_error(resp, code, "%s", strerror(errno)); 537: } 538: 539: /* 540: * Send back a simple error page 541: */ 542: void 543: http_response_send_error(struct http_response *resp, 544: int code, const char *fmt, ...) 545: { 546: struct http_request *const req = resp->msg->conn->req; 547: const char *ua; 548: FILE *fp; 549: int i; 550: 551: /* Check headers already sent */ 552: if (resp->msg->hdrs_sent) 553: return; 554: 555: /* Set response line info */ 556: http_response_set_header(resp, 0, HDR_REPLY_STATUS, "%d", code); 557: http_response_set_header(resp, 0, HDR_REPLY_REASON, 558: "%s", http_response_status_msg(code)); 559: 560: /* Set additional headers */ 561: http_response_set_header(resp, 0, HTTP_HEADER_CONTENT_TYPE, 562: "text/html; charset=iso-8859-1"); 563: 564: /* Close connection for real errors */ 565: if (code >= 400) { 566: http_response_set_header(resp, 567: 0, _http_message_connection_header(resp->msg), "close"); 568: } 569: 570: /* Send error page body */ 571: if ((fp = http_response_get_output(resp, 1)) == NULL) 572: return; 573: fprintf(fp, "<HTML>\n<HEAD>\n<TITLE>%d %s</TITLE></HEAD>\n", 574: code, http_response_status_msg(code)); 575: fprintf(fp, "<BODY BGCOLOR=\"#FFFFFF\">\n<H3>%d %s</H3>\n", 576: code, http_response_status_msg(code)); 577: if (fmt != NULL) { 578: va_list args; 579: 580: fprintf(fp, "<B>"); 581: va_start(args, fmt); 582: vfprintf(fp, fmt, args); 583: va_end(args); 584: fprintf(fp, "</B>\n"); 585: } 586: #if 0 587: fprintf(fp, "<P></P>\n<HR>\n"); 588: fprintf(fp, "<FONT SIZE=\"-1\"><EM>%s</EM></FONT>\n", 589: serv->server_name); 590: #endif 591: 592: /* Add fillter for IE */ 593: if ((ua = http_request_get_header(req, HTTP_HEADER_USER_AGENT)) != NULL 594: && strstr(ua, "IE") != NULL) { 595: for (i = 0; i < 20; i++) { 596: fprintf(fp, "<!-- FILLER TO MAKE INTERNET EXPLORER SHOW" 597: " THIS PAGE INSTEAD OF ITS OWN PAGE -->\n"); 598: } 599: } 600: fprintf(fp, "</BODY>\n</HTML>\n"); 601: } 602: 603: /* 604: * Try to guess MIME type and encoding from filename suffix. 605: */ 606: void 607: http_response_guess_mime(const char *path, 608: const char **ctype, const char **cencs, int maxencs) 609: { 610: static char buf[MAXPATHLEN]; 611: struct suffix_map *mime; 612: int matched_ctype = -1; 613: struct suffix_map key; 614: const char *slash; 615: char *tokctx; 616: char *s; 617: int i; 618: 619: /* Set defaults */ 620: *ctype = "text/plain; charset=iso-8859-1"; 621: memset(cencs, 0, maxencs * sizeof(*cencs)); 622: 623: /* Strip directories */ 624: if ((slash = strrchr(path, '/')) != NULL) 625: path = slash + 1; 626: strlcpy(buf, path, sizeof(buf)); 627: 628: /* Search for suffixes matching MIME types table entry */ 629: for (i = 0, s = strtok_r(buf, ".", &tokctx); 630: s != NULL; i++, s = strtok_r(NULL, ".", &tokctx)) { 631: key.suffix = s; 632: if ((mime = bsearch(&key, mime_types, num_mime_types, 633: sizeof(*mime_types), suffix_cmp)) != NULL) { 634: *ctype = mime->mime; 635: matched_ctype = i; 636: } 637: } 638: if (matched_ctype == -1) 639: return; 640: 641: /* Skip to the suffix after the last MIME type suffix */ 642: for (i = 0, s = strtok_r(buf, ".", &tokctx); 643: i <= matched_ctype; i++, s = strtok_r(NULL, ".", &tokctx)); 644: 645: /* Get encoding(s) */ 646: for (i = 0; i < maxencs - 1 647: && (s = strtok_r(NULL, ".", &tokctx)) != NULL; i++) { 648: key.suffix = s; 649: if ((mime = bsearch(&key, mime_encodings, num_mime_encodings, 650: sizeof(*mime_encodings), suffix_cmp)) == NULL) 651: break; 652: cencs[i] = mime->mime; 653: } 654: } 655: 656: /* 657: * Compare two entries in MIME type/encoding array 658: */ 659: static int 660: suffix_cmp(const void *v1, const void *v2) 661: { 662: const struct suffix_map *const map1 = v1; 663: const struct suffix_map *const map2 = v2; 664: 665: return (strcasecmp(map1->suffix, map2->suffix)); 666: } 667: 668: /********************************************************************* 669: MISC ROUTINES 670: *********************************************************************/ 671: 672: /* 673: * Certain response codes are required to not have any body. 674: */ 675: int 676: http_response_no_body(int code) 677: { 678: switch (code) { 679: case HTTP_STATUS_NO_CONTENT: 680: case HTTP_STATUS_NOT_MODIFIED: 681: return (1); 682: } 683: return (0); 684: } 685: