Return to http_request.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 <ctype.h> 53: #include <syslog.h> 54: #include <errno.h> 55: #include <assert.h> 56: 57: #include <openssl/ssl.h> 58: 59: #include "structs/structs.h" 60: #include "structs/type/array.h" 61: 62: #include "http/http_defs.h" 63: #include "http/http_server.h" 64: #include "http/http_internal.h" 65: #include "util/typed_mem.h" 66: 67: #define MAX_NVP_LEN (8 * 1024) 68: #define MAX_NVP_DATA (64 * 1024) 69: 70: /* 71: * Error strings 72: */ 73: #define PARSE_REQUST_MSG "Error parsing request header" 74: #define REQUEST_TIMEOUT_MSG "Press reload to reestablish a connection" 75: 76: /* 77: * Internal functions 78: */ 79: static int http_request_decode_query(struct http_request *req); 80: static int nvp_cmp(const void *v1, const void *v2); 81: static char *read_string_until(const char *mtype, 82: FILE *fp, const char *term); 83: static int http_request_add_nvp(struct http_request *req, int encoded, 84: const char *ename, const char *evalue); 85: static void http_request_decode_auth(struct http_request *req); 86: 87: /* 88: * Internal variables 89: */ 90: static const char base64[65] 91: = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; 92: 93: /********************************************************************* 94: MAIN ROUTINES 95: *********************************************************************/ 96: 97: /* 98: * Create a new request structure. 99: */ 100: int 101: _http_request_new(struct http_connection *conn) 102: { 103: struct http_request *req; 104: 105: /* Create request structure */ 106: assert(conn->req == NULL); 107: if ((req = MALLOC("http_request", sizeof(*req))) == NULL) { 108: (*conn->logger)(LOG_ERR, "%s: %s", "malloc", strerror(errno)); 109: return (-1); 110: } 111: memset(req, 0, sizeof(*req)); 112: 113: /* Attach message structure */ 114: if ((req->msg = _http_message_new()) == NULL) { 115: (*conn->logger)(LOG_ERR, "%s: %s", "malloc", strerror(errno)); 116: FREE("http_request", req); 117: return (-1); 118: } 119: 120: /* Link it up */ 121: req->msg->conn = conn; 122: conn->req = req; 123: return (0); 124: } 125: 126: /* 127: * Read in, validate, and prep an HTTP request from a connection. 128: * 129: * If there is a problem, load an error response page if appropriate. 130: */ 131: int 132: _http_request_read(struct http_connection *conn) 133: { 134: struct http_request *const req = conn->req; 135: struct http_response *const resp = conn->resp; 136: struct http_message *const msg = req->msg; 137: const char *path = NULL; 138: const char *method; 139: const char *colon; 140: const char *slash; 141: const char *proto; 142: const char *uri; 143: const char *s; 144: char scheme[32]; 145: int plen = -1; 146: int hlen; 147: 148: /* Load in message from HTTP connection */ 149: if (_http_message_read(msg, 1) == -1) { 150: const int errno_save = errno; 151: 152: /* If nothing read, the peer must have closed the connection */ 153: if (!_http_message_has_anything(msg)) { 154: errno = ENOTCONN; 155: return (-1); 156: } 157: 158: /* Return an appropriate error message */ 159: switch (errno) { 160: case EINVAL: 161: http_response_send_error(resp, HTTP_STATUS_BAD_REQUEST, 162: PARSE_REQUST_MSG); 163: break; 164: 165: case ETIMEDOUT: 166: http_response_send_error(resp, 167: HTTP_STATUS_REQUEST_TIME_OUT, REQUEST_TIMEOUT_MSG); 168: break; 169: 170: default: 171: http_response_send_error(resp, 172: HTTP_STATUS_INTERNAL_SERVER_ERROR, 173: "%s", strerror(errno)); 174: break; 175: } 176: 177: /* in all cases return -1 */ 178: errno = errno_save; 179: return (-1); 180: } 181: 182: /* Get method, URI, and protocol */ 183: method = _http_head_get(msg->head, HDR_REQUEST_METHOD); 184: uri = _http_head_get(msg->head, HDR_REQUEST_URI); 185: proto = _http_head_get(msg->head, HDR_REQUEST_VERSION); 186: 187: /* Check method and reset input length if not POST */ 188: if (strcmp(method, HTTP_METHOD_GET) == 0 189: || strcmp(method, HTTP_METHOD_HEAD) == 0 190: || strcmp(method, HTTP_METHOD_POST) == 0 191: || strcmp(method, HTTP_METHOD_CONNECT) == 0) 192: ; /* ok */ 193: else if (strcmp(method, HTTP_METHOD_OPTIONS) == 0 194: || strcmp(method, HTTP_METHOD_PUT) == 0 195: || strcmp(method, HTTP_METHOD_DELETE) == 0 196: || strcmp(method, HTTP_METHOD_TRACE) == 0) { 197: http_response_send_error(resp, 198: HTTP_STATUS_METHOD_NOT_ALLOWED, NULL); 199: return (-1); 200: } else { 201: http_response_send_error(resp, 202: HTTP_STATUS_NOT_IMPLEMENTED, NULL); 203: return (-1); 204: } 205: 206: /* If request was HEAD, omit sending the body */ 207: if (strcasecmp(method, HTTP_METHOD_HEAD) == 0) 208: resp->msg->skip_body = 1; 209: 210: /* Check protocol is known */ 211: if (strcmp(proto, HTTP_PROTO_0_9) != 0 212: && strcmp(proto, HTTP_PROTO_1_0) != 0 213: && strcmp(proto, HTTP_PROTO_1_1) != 0) { 214: http_response_send_error(resp, 215: HTTP_STATUS_HTTP_VERSION_NOT_SUPPORTED, NULL); 216: return (-1); 217: } 218: 219: /* If protocol is HTTP/0.9, don't send back any headers */ 220: if (strcmp(proto, HTTP_PROTO_0_9) == 0) 221: resp->msg->no_headers = 1; 222: 223: /* Check for CONNECT method */ 224: if (strcmp(method, HTTP_METHOD_CONNECT) == 0) { 225: if ((msg->host = STRDUP("http_message.host", uri)) == NULL) 226: goto malloc_fail; 227: conn->proxy = 1; 228: goto no_path; 229: } 230: 231: /* Get explicit scheme, if any */ 232: colon = strchr(uri, ':'); 233: slash = strchr(uri, '/'); 234: if (colon != NULL && slash != NULL && colon < slash) { 235: char *c; 236: 237: strlcpy(scheme, uri, sizeof(scheme)); 238: if ((c = strchr(scheme, ':')) != NULL) 239: *c = '\0'; 240: conn->proxy = 1; /* explicit scheme => proxy request */ 241: } else 242: strlcpy(scheme, "http", sizeof(scheme)); 243: 244: /* We only support HTTP */ 245: if (strcasecmp(scheme, "http") != 0) { 246: http_response_send_error(resp, HTTP_STATUS_BAD_REQUEST, 247: "Unsupported scheme \"%s\"", scheme); 248: return (-1); 249: } 250: 251: /* Separate out host, path and query parts from URI */ 252: if (strncasecmp(uri, "http://", 7) == 0) { 253: if ((path = strchr(uri + 7, '/')) == NULL) { 254: http_response_send_error(resp, HTTP_STATUS_BAD_REQUEST, 255: "Request URI has no path component"); 256: return (-1); 257: } 258: hlen = path - (uri + 7); 259: if ((msg->host = MALLOC("http_message.host", hlen + 1)) == NULL) 260: goto malloc_fail; 261: memcpy(msg->host, uri + 7, hlen); 262: msg->host[hlen] = '\0'; 263: conn->proxy = 1; 264: } else if (*uri != '/') { 265: http_response_send_error(resp, 266: HTTP_STATUS_BAD_REQUEST, "Bogus non-absolute URI"); 267: return (-1); 268: } else 269: path = uri; 270: if ((s = strchr(path, '?')) == NULL) 271: plen = strlen(path); 272: else { 273: plen = s - path; 274: if ((msg->query = STRDUP("http_message.query", s + 1)) == NULL) 275: goto malloc_fail; 276: } 277: 278: no_path: 279: /* Check body input length for POST, all others have no input body */ 280: if (strcmp(method, HTTP_METHOD_POST) == 0) { 281: if (msg->input_len == UINT_MAX 282: && _http_head_want_keepalive(req->msg->head)) { 283: http_response_send_error(resp, HTTP_STATUS_BAD_REQUEST, 284: "Keep-Alive requires %s", 285: HTTP_HEADER_CONTENT_LENGTH); 286: return (-1); 287: } 288: } else 289: msg->input_len = 0; /* ignore C-L header */ 290: 291: /* Decode URL path part */ 292: if (path == NULL) 293: goto no_path2; 294: if ((msg->path = MALLOC("http_message.path", plen + 1)) == NULL) { 295: malloc_fail: 296: (*conn->logger)(LOG_ERR, "%s: %s", "malloc", strerror(errno)); 297: http_response_send_error(resp, 298: HTTP_STATUS_INTERNAL_SERVER_ERROR, "%s", strerror(errno)); 299: return (-1); 300: } 301: memcpy(msg->path, path, plen); 302: msg->path[plen] = '\0'; 303: http_request_url_decode(msg->path, msg->path); 304: 305: no_path2: 306: /* Check Host: header specified in a HTTP/1.1 request */ 307: if (strcmp(proto, HTTP_PROTO_1_1) == 0 308: && msg->host == NULL 309: && _http_head_get(msg->head, HTTP_HEADER_HOST) == NULL) { 310: http_response_send_error(resp, 311: HTTP_STATUS_BAD_REQUEST, "No host specified"); 312: return (-1); 313: } 314: 315: /* Decode name, value pairs from query string */ 316: if (msg->query != NULL) 317: http_request_decode_query(req); 318: 319: /* Done */ 320: return (0); 321: } 322: 323: /* 324: * Free a request structure. 325: */ 326: void 327: _http_request_free(struct http_request **reqp) 328: { 329: struct http_request *const req = *reqp; 330: int i; 331: 332: if (req == NULL) 333: return; 334: _http_message_free(&req->msg); 335: FREE("http_request.username", req->username); 336: FREE("http_request.password", req->password); 337: for (i = 0; i < req->num_nvp; i++) { 338: struct http_nvp *const nvp = &req->nvp[i]; 339: 340: FREE("http_request.nvp.name", nvp->name); 341: FREE("http_request.nvp.value", nvp->value); 342: } 343: FREE("http_request.nvp", req->nvp); 344: FREE("http_request", req); 345: *reqp = NULL; 346: } 347: 348: /********************************************************************* 349: MESSAGE WRAPPER ROUTINES 350: *********************************************************************/ 351: 352: /* 353: * Get a request header. 354: * 355: * For headers listed multiple times, this only gets the first instance. 356: */ 357: const char * 358: http_request_get_header(struct http_request *req, const char *name) 359: { 360: return (_http_head_get(req->msg->head, name)); 361: } 362: 363: /* 364: * Get the number of headers 365: */ 366: int 367: http_request_num_headers(struct http_request *req) 368: { 369: return (_http_head_num_headers(req->msg->head)); 370: } 371: 372: /* 373: * Get header by index. 374: */ 375: int 376: http_request_get_header_by_index(struct http_request *req, 377: u_int index, const char **namep, const char **valuep) 378: { 379: return (_http_head_get_by_index(req->msg->head, index, namep, valuep)); 380: } 381: 382: /* 383: * Set a request header. 384: */ 385: int 386: http_request_set_header(struct http_request *req, int append, 387: const char *name, const char *valfmt, ...) 388: { 389: va_list args; 390: int ret; 391: 392: /* Set header */ 393: va_start(args, valfmt); 394: ret = _http_message_vset_header(req->msg, append, name, valfmt, args); 395: va_end(args); 396: return (ret); 397: } 398: 399: /* 400: * Remove a header. 401: */ 402: int 403: http_request_remove_header(struct http_request *req, const char *name) 404: { 405: return (_http_message_remove_header(req->msg, name)); 406: } 407: 408: /* 409: * Send request headers to peer. 410: */ 411: int 412: http_request_send_headers(struct http_request *req) 413: { 414: const char *const method = http_request_get_method(req); 415: const char *const path = http_request_get_path(req); 416: const char *const uri = http_request_get_uri(req); 417: char *epath; 418: 419: /* Sanity checks */ 420: if (req->msg->hdrs_sent) 421: return (0); 422: if (method == NULL || (path == NULL && uri == NULL)) { 423: errno = EINVAL; 424: return (-1); 425: } 426: 427: /* If request is GET, put name, value pairs in the query string */ 428: if (strcmp(method, HTTP_METHOD_GET) == 0 429: && http_request_set_query_from_values(req) == -1) 430: return (-1); 431: 432: /* Set request URI */ 433: if (uri == NULL) { 434: if ((epath = http_request_url_encode( 435: TYPED_MEM_TEMP, path)) == NULL) 436: return (-1); 437: if (http_request_set_header(req, 0, 438: HDR_REQUEST_URI, "%s%s%s", epath, 439: req->msg->query != NULL ? "?" : "", 440: req->msg->query != NULL ? req->msg->query : "") == -1) { 441: FREE(TYPED_MEM_TEMP, epath); 442: return (-1); 443: } 444: FREE(TYPED_MEM_TEMP, epath); 445: } 446: 447: /* Set other headers */ 448: if (http_request_set_header(req, 0, HDR_REQUEST_METHOD, 449: "%s", http_request_get_method(req)) == -1) 450: return (-1); 451: if (http_request_set_header(req, 0, HDR_REQUEST_VERSION, 452: "%s", HTTP_PROTO_1_0) == -1) 453: return (-1); 454: if (http_request_set_header(req, 0, 455: _http_message_connection_header(req->msg), "%s", 456: req->msg->conn->keep_alive ? "Keep-Alive" : "Close") == -1) 457: return (-1); 458: 459: /* Send headers */ 460: _http_message_send_headers(req->msg, 0); 461: return (0); 462: } 463: 464: /* 465: * Get the encoded query string. 466: */ 467: const char * 468: http_request_get_query_string(struct http_request *req) 469: { 470: return (req->msg->query == NULL ? "" : req->msg->query); 471: } 472: 473: /* 474: * Get specified host, if any. 475: */ 476: const char * 477: http_request_get_host(struct http_request *req) 478: { 479: struct http_connection *const conn = req->msg->conn; 480: const char *host; 481: 482: if (!conn->proxy 483: && (host = http_request_get_header(req, HTTP_HEADER_HOST)) != NULL) 484: return (host); 485: return (req->msg->host); 486: } 487: 488: /* 489: * Get query method. 490: */ 491: const char * 492: http_request_get_method(struct http_request *req) 493: { 494: return (http_request_get_header(req, HDR_REQUEST_METHOD)); 495: } 496: 497: /* 498: * Get query URI. 499: */ 500: const char * 501: http_request_get_uri(struct http_request *req) 502: { 503: return (http_request_get_header(req, HDR_REQUEST_URI)); 504: } 505: 506: /* 507: * Get query version. 508: */ 509: const char * 510: http_request_get_version(struct http_request *req) 511: { 512: return (http_request_get_header(req, HDR_REQUEST_VERSION)); 513: } 514: 515: /* 516: * Set query method. 517: */ 518: int 519: http_request_set_method(struct http_request *req, const char *method) 520: { 521: /* Must be GET, POST, or HEAD for now */ 522: if (strcmp(method, HTTP_METHOD_GET) != 0 523: && strcmp(method, HTTP_METHOD_POST) != 0 524: && strcmp(method, HTTP_METHOD_HEAD) != 0) { 525: errno = EINVAL; 526: return (-1); 527: } 528: 529: /* Set method */ 530: if (http_request_set_header(req, 0, 531: HDR_REQUEST_METHOD, "%s", method) == -1) 532: return (-1); 533: 534: /* Only POST is allowed to have a body */ 535: req->msg->no_body = (strcmp(method, HTTP_METHOD_POST) != 0); 536: return (0); 537: } 538: 539: /* 540: * Set proxy request bit. 541: */ 542: void 543: http_request_set_proxy(struct http_request *req, int whether) 544: { 545: struct http_connection *const conn = req->msg->conn; 546: 547: conn->proxy = !!whether; 548: } 549: 550: /* 551: * Get the URL path. 552: */ 553: const char * 554: http_request_get_path(struct http_request *req) 555: { 556: return (req->msg->path); 557: } 558: 559: /* 560: * Set the URL path. 561: */ 562: int 563: http_request_set_path(struct http_request *req, const char *path) 564: { 565: char *copy; 566: 567: if (path == NULL || *path != '/') { 568: errno = EINVAL; 569: return (-1); 570: } 571: if ((copy = STRDUP("http_message.path", path)) == NULL) 572: return (-1); 573: FREE("http_message.path", req->msg->path); 574: req->msg->path = copy; 575: return (0); 576: } 577: 578: /* 579: * Get SSL context. 580: */ 581: SSL_CTX * 582: http_request_get_ssl(struct http_request *req) 583: { 584: return (req->msg->conn->ssl); 585: } 586: 587: /* 588: * Get request input stream. 589: */ 590: FILE * 591: http_request_get_input(struct http_request *req) 592: { 593: if (!req->msg->conn->server) { 594: errno = EINVAL; 595: return (NULL); 596: } 597: return (req->msg->input); 598: } 599: 600: /* 601: * Get raw i/o stream as a file descriptor. 602: */ 603: int 604: http_request_get_raw_socket(struct http_request *req) 605: { 606: return (_http_message_get_raw_socket(req->msg)); 607: } 608: 609: /* 610: * Get request output stream. 611: * 612: * If "buffer" is true, the entire output will be buffered unless 613: * the headers have already been sent. 614: */ 615: FILE * 616: http_request_get_output(struct http_request *req, int buffer) 617: { 618: if (req->msg->conn->server) { 619: errno = EINVAL; 620: return (NULL); 621: } 622: return (_http_message_get_output(req->msg, buffer)); 623: } 624: 625: /* 626: * Get remote IP address. 627: */ 628: struct in_addr 629: http_request_get_remote_ip(struct http_request *req) 630: { 631: return (_http_message_get_remote_ip(req->msg)); 632: } 633: 634: /* 635: * Get remote port. 636: */ 637: u_int16_t 638: http_request_get_remote_port(struct http_request *req) 639: { 640: return (_http_message_get_remote_port(req->msg)); 641: } 642: 643: /********************************************************************* 644: AUTHORIZATION ROUTINES 645: *********************************************************************/ 646: 647: /* 648: * Get request remote username. 649: * 650: * Returns NULL if none specified. 651: */ 652: const char * 653: http_request_get_username(struct http_request *req) 654: { 655: if (req->username == NULL) 656: http_request_decode_auth(req); 657: return (req->username); 658: } 659: 660: /* 661: * Get request remote password 662: * 663: * Returns NULL if none specified. 664: */ 665: const char * 666: http_request_get_password(struct http_request *req) 667: { 668: if (req->password == NULL) 669: http_request_decode_auth(req); 670: return (req->password); 671: } 672: 673: /* 674: * Compute base64 encoded username and password, suitable for 675: * passing in a basic authentication header. 676: */ 677: char * 678: http_request_encode_basic_auth(const char *mtype, 679: const char *username, const char *password) 680: { 681: char *buf; 682: char *auth; 683: int len; 684: int i, j; 685: 686: /* Get raw data buffer */ 687: len = strlen(username) + 1 + strlen(password) + 1; 688: if ((buf = MALLOC(TYPED_MEM_TEMP, len)) == NULL) 689: return (NULL); 690: strcpy(buf, username); 691: strcat(buf, ":"); 692: strcat(buf, password); 693: 694: /* Get encoded buffer */ 695: len = (4 * len) / 3 + 32; 696: if ((auth = MALLOC(mtype, len)) == NULL) { 697: FREE(TYPED_MEM_TEMP, buf); 698: return (NULL); 699: } 700: 701: /* Encode bits */ 702: len = strlen(buf); 703: for (j = i = 0; i < len; i += 3) { 704: const u_char b0 = ((u_char *)buf)[i]; 705: const u_char b1 = (i < len - 1) ? ((u_char *)buf)[i + 1] : 0; 706: const u_char b2 = (i < len - 2) ? ((u_char *)buf)[i + 2] : 0; 707: 708: auth[j++] = base64[(b0 >> 2) & 0x3f]; 709: auth[j++] = base64[((b0 << 4) & 0x30) | ((b1 >> 4) & 0x0f)]; 710: if (i == len - 1) 711: break; 712: auth[j++] = base64[((b1 << 2) & 0x3c) | ((b2 >> 6) & 0x03)]; 713: if (i == len - 2) 714: break; 715: auth[j++] = base64[b2 & 0x3f]; 716: } 717: FREE(TYPED_MEM_TEMP, buf); 718: 719: /* Pad encoding to an even multiple with equals signs */ 720: switch (len % 3) { 721: case 1: auth[j++] = '='; /* fall through */ 722: case 2: auth[j++] = '='; 723: case 0: break; 724: } 725: auth[j] = '\0'; 726: 727: /* Done */ 728: return (auth); 729: } 730: 731: /* 732: * Decode basic Authorization: header. 733: */ 734: static void 735: http_request_decode_auth(struct http_request *req) 736: { 737: static u_char table[256]; 738: u_int val, pval = 0; 739: const char *s; 740: char buf[128]; 741: char *pw; 742: int step; 743: int len; 744: 745: /* Initialize table (first time only) */ 746: if (table[0] == 0) { 747: for (val = 0; val < 0x100; val++) { 748: table[val] = ((s = strchr(base64, (char)val)) != NULL) ? 749: s - base64 : 0xff; 750: } 751: } 752: 753: /* Get basic authentication header */ 754: if ((s = http_request_get_header(req, 755: HTTP_HEADER_AUTHORIZATION)) == NULL 756: || strncmp(s, "Basic ", 6) != 0) 757: return; 758: 759: /* Decode it */ 760: for (len = step = 0, s += 6; len < sizeof(buf) - 1 && *s != '\0'; s++) { 761: 762: /* Decode character */ 763: if ((val = table[(u_char)*s]) == 0xff) 764: continue; 765: 766: /* Glom on bits */ 767: switch (step % 4) { 768: case 1: 769: buf[len++] = (pval << 2) | ((val & 0x30) >> 4); 770: break; 771: case 2: 772: buf[len++] = ((pval & 0x0f) << 4) | ((val & 0x3c) >> 2); 773: break; 774: case 3: 775: buf[len++] = ((pval & 0x03) << 6) | val; 776: break; 777: } 778: pval = val; 779: step++; 780: } 781: buf[len] = '\0'; 782: 783: /* Find password */ 784: if ((pw = strchr(buf, ':')) == NULL) 785: return; 786: *pw++ = '\0'; 787: 788: /* Allocate strings */ 789: if ((req->username = STRDUP("http_request.username", buf)) == NULL) 790: return; 791: if ((req->password = STRDUP("http_request.password", pw)) == NULL) { 792: FREE("http_request.username", req->username); 793: req->username = NULL; 794: return; 795: } 796: } 797: 798: /********************************************************************* 799: FORM FILE UPLOAD 800: *********************************************************************/ 801: 802: #define WHITESPACE " \t\r\n\f\v" 803: 804: struct upload_info { 805: const char *field; 806: FILE *fp; 807: int error; 808: size_t max; 809: }; 810: 811: static http_mime_handler_t http_request_file_upload_handler; 812: 813: /* 814: * Read an HTTP POST containing MIME multipart data and write 815: * the contents of the named field into the supplied stream. 816: * The stream is NOT closed. 817: * 818: * If "max" is non-zero and more than "max" bytes are read, 819: * an error is returned with errno = EFBIG. 820: * 821: * Returns zero if successful, otherwise -1 and sets errno. 822: */ 823: int 824: http_request_file_upload(struct http_request *req, 825: const char *field, FILE *fp, size_t max) 826: { 827: struct upload_info info; 828: const char *hval; 829: char *s; 830: 831: /* Verify proper submit was done */ 832: if ((hval = http_request_get_header(req, 833: HTTP_HEADER_CONTENT_TYPE)) == NULL) { 834: errno = EINVAL; 835: return (-1); 836: } 837: if ((s = strchr(hval, ';')) == NULL 838: || strncasecmp(hval, 839: HTTP_CTYPE_MULTIPART_FORMDATA, s - hval) != 0) { 840: errno = EINVAL; 841: return (-1); 842: } 843: 844: /* Read form data into file */ 845: memset(&info, 0, sizeof(info)); 846: info.field = field; 847: info.fp = fp; 848: info.max = max; 849: if (http_request_get_mime_multiparts(req, 850: http_request_file_upload_handler, &info) < 0) { 851: if (info.error == 0) 852: info.error = errno; 853: } 854: if (info.error != 0) { 855: errno = info.error; 856: return (-1); 857: } 858: 859: /* Done */ 860: return (0); 861: } 862: 863: static int 864: http_request_file_upload_handler(void *arg, struct mime_part *part, FILE *fp) 865: { 866: struct upload_info *const info = arg; 867: const char *hval = http_mime_part_get_header(part, 868: HTTP_HEADER_CONTENT_DISPOSITION); 869: char buf[256]; 870: char *tokctx; 871: char *s, *t; 872: size_t len; 873: size_t nr; 874: 875: /* Parse content dispostion to get the field name */ 876: strlcpy(buf, hval, sizeof(buf)); 877: for (s = strtok_r(buf, WHITESPACE ";", &tokctx); 878: s != NULL; 879: s = strtok_r(NULL, WHITESPACE ";", &tokctx)) { 880: if (strncmp(s, "name=\"", 6) != 0) 881: continue; 882: s += 6; 883: if ((t = strchr(s, '"')) == NULL) 884: continue; 885: *t = '\0'; 886: if (strcmp(s, info->field) == 0) /* is this the field? */ 887: break; 888: } 889: if (s == NULL) /* wrong field */ 890: return (0); 891: 892: /* Read data and write it to caller-supplied stream */ 893: for (len = 0; (nr = fread(buf, 1, sizeof(buf), fp)) != 0; len += nr) { 894: if (info->max != 0 && len + nr > info->max) { 895: errno = EFBIG; 896: goto fail; 897: } 898: if (fwrite(buf, 1, nr, info->fp) != nr) 899: goto fail; 900: } 901: if (ferror(fp)) { 902: fail: info->error = errno; 903: return (-1); 904: } 905: 906: /* Done */ 907: return (0); 908: } 909: 910: /********************************************************************* 911: NAME VALUE PAIR ROUTINES 912: *********************************************************************/ 913: 914: /* 915: * Get a value from a request. 916: */ 917: const char * 918: http_request_get_value(struct http_request *req, const char *name, int instance) 919: { 920: struct http_nvp key; 921: struct http_nvp *nvp; 922: 923: key.name = (char *)name; 924: if ((nvp = bsearch(&key, 925: req->nvp, req->num_nvp, sizeof(*req->nvp), nvp_cmp)) == NULL) 926: return (NULL); 927: while (instance-- > 0) { 928: if (++nvp - req->nvp >= req->num_nvp 929: || strcmp(nvp->name, name) != 0) 930: return (NULL); 931: } 932: return (nvp->value); 933: } 934: 935: /* 936: * Set a value associated with a query. 937: */ 938: int 939: http_request_set_value(struct http_request *req, 940: const char *name, const char *value) 941: { 942: int ret; 943: 944: if ((ret = http_request_add_nvp(req, 0, name, value)) == -1) 945: return (-1); 946: mergesort(req->nvp, req->num_nvp, sizeof(*req->nvp), nvp_cmp); 947: return (0); 948: } 949: 950: /* 951: * Get the number of NVP's. 952: */ 953: int 954: http_request_get_num_values(struct http_request *req) 955: { 956: return (req->num_nvp); 957: } 958: 959: /* 960: * Get the name of an NVP by index. 961: */ 962: int 963: http_request_get_value_by_index(struct http_request *req, int i, 964: const char **name, const char **value) 965: { 966: if (i < 0 || i >= req->num_nvp) { 967: errno = EINVAL; 968: return (-1); 969: } 970: if (name != NULL) 971: *name = req->nvp[i].name; 972: if (value != NULL) 973: *value = req->nvp[i].value; 974: return (0); 975: } 976: 977: /* 978: * Reset the query string from the list of name, value pairs. 979: */ 980: int 981: http_request_set_query_from_values(struct http_request *req) 982: { 983: char *buf; 984: int qlen; 985: int i; 986: 987: /* If no values, no query string */ 988: if (req->num_nvp == 0) { 989: buf = NULL; 990: goto done; 991: } 992: 993: /* Get bound on encoded query string length */ 994: for (qlen = i = 0; i < req->num_nvp; i++) { 995: const struct http_nvp *const nvp = &req->nvp[i]; 996: 997: qlen += strlen(nvp->name) * 3 + 1 + strlen(nvp->value) * 3; 998: } 999: 1000: /* Allocate new buffer */ 1001: if ((buf = MALLOC("http_message.query", qlen + 1)) == NULL) 1002: return (-1); 1003: 1004: /* Encode name, value pairs into buffer */ 1005: for (qlen = i = 0; i < req->num_nvp; i++) { 1006: const struct http_nvp *const nvp = &req->nvp[i]; 1007: char *ename; 1008: char *evalue; 1009: 1010: if ((ename = http_request_url_encode(TYPED_MEM_TEMP, 1011: nvp->name)) == NULL) { 1012: FREE("http_message.query", buf); 1013: return (-1); 1014: } 1015: if ((evalue = http_request_url_encode(TYPED_MEM_TEMP, 1016: nvp->value)) == NULL) { 1017: FREE(TYPED_MEM_TEMP, ename); 1018: FREE("http_message.query", buf); 1019: return (-1); 1020: } 1021: qlen += sprintf(buf + qlen, "%s%s=%s", 1022: i > 0 ? "&" : "", ename, evalue); 1023: FREE(TYPED_MEM_TEMP, ename); 1024: FREE(TYPED_MEM_TEMP, evalue); 1025: } 1026: 1027: done: 1028: /* Set new query string */ 1029: FREE("http_message.query", req->msg->query); 1030: req->msg->query = buf; 1031: return (0); 1032: } 1033: 1034: /* 1035: * Read in name, value pairs as URL-encoded form data. 1036: * Typically this is used for receiving POST requests. 1037: */ 1038: int 1039: http_request_read_url_encoded_values(struct http_request *req) 1040: { 1041: FILE *input; 1042: char *name; 1043: char *value; 1044: int count; 1045: int totlen; 1046: int ret; 1047: int ch; 1048: 1049: /* Get input stream */ 1050: if ((input = http_request_get_input(req)) == NULL) 1051: return (-1); 1052: 1053: /* Read in URL-encoded name, value pairs */ 1054: for (count = totlen = 0; totlen < MAX_NVP_DATA; totlen++) { 1055: 1056: /* Read name */ 1057: if ((name = read_string_until(TYPED_MEM_TEMP, 1058: req->msg->input, "&=")) == NULL) 1059: return (-1); 1060: 1061: /* Read value, if any */ 1062: if ((ch = getc(req->msg->input)) == '=') { 1063: if ((value = read_string_until(TYPED_MEM_TEMP, 1064: req->msg->input, "&")) == NULL) { 1065: FREE(TYPED_MEM_TEMP, name); 1066: return (-1); 1067: } 1068: } else 1069: value = NULL; 1070: 1071: /* Slurp next char */ 1072: (void)getc(req->msg->input); 1073: 1074: /* Add name, value pair */ 1075: ret = 0; 1076: if (*name != '\0') { 1077: ret = http_request_add_nvp(req, 1, 1078: name, (value != NULL) ? value : ""); 1079: count++; 1080: } 1081: FREE(TYPED_MEM_TEMP, name); 1082: FREE(TYPED_MEM_TEMP, value); 1083: if (ret == -1) 1084: return (-1); 1085: } 1086: 1087: /* Sort name using mergesort() which preserves order of duplicates */ 1088: if (mergesort(req->nvp, req->num_nvp, sizeof(*req->nvp), nvp_cmp) == -1) 1089: return (-1); 1090: 1091: /* Done */ 1092: return (count); 1093: } 1094: 1095: /* 1096: * Write out name, value pairs as URL-encoded form data. 1097: * Typically this is used for sending POST requests. 1098: */ 1099: int 1100: http_request_write_url_encoded_values(struct http_request *req) 1101: { 1102: int i; 1103: 1104: /* Get output stream */ 1105: if (req->msg->output == NULL) { 1106: errno = EINVAL; 1107: return (-1); 1108: } 1109: 1110: /* Encode name, value pairs into buffer */ 1111: for (i = 0; i < req->num_nvp; i++) { 1112: const struct http_nvp *const nvp = &req->nvp[i]; 1113: char *ename; 1114: char *evalue; 1115: 1116: if ((ename = http_request_url_encode(TYPED_MEM_TEMP, 1117: nvp->name)) == NULL) 1118: return (-1); 1119: if ((evalue = http_request_url_encode(TYPED_MEM_TEMP, 1120: nvp->value)) == NULL) { 1121: FREE(TYPED_MEM_TEMP, ename); 1122: return (-1); 1123: } 1124: fprintf(req->msg->output, "%s%s=%s", 1125: i > 0 ? "&" : "", ename, evalue); 1126: FREE(TYPED_MEM_TEMP, ename); 1127: FREE(TYPED_MEM_TEMP, evalue); 1128: } 1129: return (0); 1130: } 1131: 1132: /* 1133: * Parse out query string into name, value pairs. 1134: */ 1135: static int 1136: http_request_decode_query(struct http_request *req) 1137: { 1138: char *tokctx; 1139: char *qbuf; 1140: char *name; 1141: char *value; 1142: 1143: /* Sanity */ 1144: if (req->msg->query == NULL) 1145: return (0); 1146: 1147: /* Copy original encoded query string */ 1148: if ((qbuf = STRDUP(TYPED_MEM_TEMP, req->msg->query)) == NULL) 1149: return (-1); 1150: 1151: /* Separate out and decode name, value pairs */ 1152: for (name = strtok_r(qbuf, "&", &tokctx); 1153: name != NULL; 1154: name = strtok_r(NULL, "&", &tokctx)) { 1155: 1156: /* Find value */ 1157: if ((value = strchr(name, '=')) == NULL) 1158: continue; 1159: *value++ = '\0'; 1160: 1161: /* Add name, value pair */ 1162: if (http_request_add_nvp(req, 1, name, value) == -1) { 1163: FREE(TYPED_MEM_TEMP, qbuf); 1164: return (-1); 1165: } 1166: } 1167: FREE(TYPED_MEM_TEMP, qbuf); 1168: 1169: /* Sort name using mergesort() which preserves order of duplicates */ 1170: if (mergesort(req->nvp, req->num_nvp, sizeof(*req->nvp), nvp_cmp) == -1) 1171: return (-1); 1172: return (0); 1173: } 1174: 1175: /* 1176: * Add an (optionally URL-encoded) name, value pair. 1177: * 1178: * Array must be sorted again by caller. 1179: */ 1180: static int 1181: http_request_add_nvp(struct http_request *req, int encoded, 1182: const char *ename, const char *evalue) 1183: { 1184: char *name; 1185: char *value; 1186: void *mem; 1187: 1188: /* Create buffers */ 1189: if ((name = MALLOC("http_request.nvp.name", strlen(ename) + 1)) == NULL) 1190: return (-1); 1191: if ((value = MALLOC("http_request.nvp.value", 1192: strlen(evalue) + 1)) == NULL) { 1193: FREE("http_request.nvp.name", name); 1194: return (-1); 1195: } 1196: 1197: /* URL-decode name and value */ 1198: if (encoded) { 1199: http_request_url_decode(ename, name); 1200: http_request_url_decode(evalue, value); 1201: } else { 1202: strcpy(name, ename); 1203: strcpy(value, evalue); 1204: } 1205: 1206: /* Add new pointer struct */ 1207: if ((mem = REALLOC("http_request.nvp", req->nvp, 1208: (req->num_nvp + 1) * sizeof(*req->nvp))) == NULL) { 1209: FREE("http_request.nvp.name", name); 1210: FREE("http_request.nvp.value", value); 1211: return (-1); 1212: } 1213: req->nvp = mem; 1214: req->nvp[req->num_nvp].name = name; 1215: req->nvp[req->num_nvp].value = value; 1216: req->num_nvp++; 1217: return (0); 1218: } 1219: 1220: /* 1221: * Comparator for name, value pairs 1222: */ 1223: static int 1224: nvp_cmp(const void *v1, const void *v2) 1225: { 1226: const struct http_nvp *const q1 = v1; 1227: const struct http_nvp *const q2 = v2; 1228: 1229: return (strcmp(q1->name, q2->name)); 1230: } 1231: 1232: /* 1233: * Read a string until a terminating character or EOF is seen. 1234: */ 1235: static char * 1236: read_string_until(const char *mtype, FILE *fp, const char *term) 1237: { 1238: size_t alloc = 32; 1239: void *mem; 1240: char *s; 1241: int len = 0; 1242: int ch; 1243: 1244: if ((s = MALLOC(mtype, alloc)) == NULL) 1245: return (NULL); 1246: while (len < MAX_NVP_LEN) { 1247: if ((ch = getc(fp)) == EOF) { 1248: s[len] = '\0'; 1249: return (s); 1250: } 1251: if (strchr(term, ch) != NULL && ch != '\0') { 1252: ungetc(ch, fp); 1253: s[len] = '\0'; 1254: return (s); 1255: } 1256: s[len++] = ch; 1257: if (len == alloc) { 1258: alloc <<= 1; 1259: if ((mem = REALLOC(mtype, s, alloc)) == NULL) 1260: goto fail; 1261: s = mem; 1262: } 1263: } 1264: errno = E2BIG; 1265: fail: 1266: FREE(mtype, s); 1267: return (NULL); 1268: } 1269: 1270: /********************************************************************* 1271: MISC ROUTINES 1272: *********************************************************************/ 1273: 1274: /* 1275: * URL-encode a string. 1276: */ 1277: char * 1278: http_request_url_encode(const char *mtype, const char *s) 1279: { 1280: char *enc; 1281: char *t; 1282: 1283: if ((enc = MALLOC(mtype, (strlen(s) * 3) + 1)) == NULL) 1284: return (NULL); 1285: for (t = enc; *s != '\0'; s++) { 1286: if (!isalnum((u_char)*s) && strchr("-_.!~*'()/:", *s) == NULL) 1287: t += sprintf(t, "%%%02x", (u_char)*s); 1288: else 1289: *t++ = *s; 1290: } 1291: *t = '\0'; 1292: return (enc); 1293: } 1294: 1295: /* 1296: * URL-decode a string. 1297: */ 1298: void 1299: http_request_url_decode(const char *s, char *t) 1300: { 1301: for (; *s != '\0'; s++, t++) { 1302: switch (s[0]) { 1303: case '+': 1304: *t = ' '; 1305: break; 1306: case '%': 1307: if (isxdigit((u_char)s[1]) && isxdigit((u_char)s[2])) { 1308: *t = isdigit((u_char)s[1]) ? 1309: s[1] - '0' : tolower(s[1]) - 'a' + 10; 1310: *t <<= 4; 1311: *t |= isdigit((u_char)s[2]) ? 1312: s[2] - '0' : tolower(s[2]) - 'a' + 10; 1313: s += 2; 1314: break; 1315: } 1316: /* fall through */ 1317: default: 1318: *t = *s; 1319: break; 1320: } 1321: } 1322: *t = '\0'; 1323: } 1324: 1325: /* 1326: * Parse an HTTP time string. 1327: * 1328: * Returns (time_t)-1 if there was an error. 1329: */ 1330: time_t 1331: http_request_parse_time(const char *string) 1332: { 1333: static const char *fmts[] = { 1334: HTTP_TIME_FMT_RFC1123, 1335: HTTP_TIME_FMT_RFC850, 1336: HTTP_TIME_FMT_CTIME, 1337: }; 1338: struct tm whentm; 1339: time_t when; 1340: int i; 1341: 1342: for (i = 0; i < sizeof(fmts) / sizeof(*fmts); i++) { 1343: memset(&whentm, 0, sizeof(whentm)); 1344: if (strptime(string, fmts[i], &whentm) != NULL 1345: && (when = timegm(&whentm)) != (time_t)-1) 1346: return (when); 1347: } 1348: return ((time_t)-1); 1349: } 1350: