Return to http_message.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 <pthread.h> 51: #include <limits.h> 52: #include <syslog.h> 53: #include <errno.h> 54: #include <ctype.h> 55: 56: #include <openssl/ssl.h> 57: 58: #include "structs/structs.h" 59: #include "structs/type/array.h" 60: 61: #include "util/typed_mem.h" 62: #include "http/http_defs.h" 63: #include "http/http_server.h" 64: #include "http/http_internal.h" 65: 66: /* 67: * Internal functions 68: */ 69: static int http_message_input_read(void *cookie, char *buf, int len); 70: static int http_message_input_close(void *cookie); 71: static int http_message_output_write(void *cookie, 72: const char *buf, int len); 73: static int http_message_output_close(void *cookie); 74: 75: /********************************************************************* 76: MAIN ROUTINES 77: *********************************************************************/ 78: 79: /* 80: * Create a new message structure. 81: */ 82: struct http_message * 83: _http_message_new(void) 84: { 85: struct http_message *msg; 86: 87: if ((msg = MALLOC("http_message", sizeof(*msg))) == NULL) 88: return (NULL); 89: memset(msg, 0, sizeof(*msg)); 90: if ((msg->head = _http_head_new()) == NULL) { 91: FREE("http_message", msg); 92: return (NULL); 93: } 94: return (msg); 95: } 96: 97: /* 98: * Initialize a message by loading in HTTP headers from a stream, 99: * and set msg->input to be the entity input stream. 100: * 101: * This reads any Content-Length header and sets msg->input_len 102: * accordingly, or UINT_MAX if none found. Messages that by definition 103: * have no body must reset msg->input_len to zero. 104: */ 105: int 106: _http_message_read(struct http_message *msg, int req) 107: { 108: struct http_connection *const conn = msg->conn; 109: const char *s; 110: 111: /* Slurp in HTTP headers */ 112: if (_http_head_read(msg->head, conn->fp, req) == -1) 113: return (-1); 114: 115: /* Get content length, if any */ 116: msg->input_len = UINT_MAX; 117: if ((s = _http_head_get(msg->head, 118: HTTP_HEADER_CONTENT_LENGTH)) != NULL) { 119: if (sscanf(s, "%u", &msg->input_len) != 1) { 120: errno = EINVAL; 121: return (-1); 122: } 123: } 124: 125: /* Create input stream */ 126: if ((msg->input = funopen(msg, http_message_input_read, 127: NULL, NULL, http_message_input_close)) == NULL) 128: return (-1); 129: 130: /* Debugging */ 131: if (PDEL_DEBUG_ENABLED(HTTP_HDRS)) { 132: DBG(HTTP_HDRS, "dumping %s headers:", 133: msg->conn->server ? "REQUEST" : "RESPONSE"); 134: _http_head_write(msg->head, stdout); 135: } 136: 137: /* Done */ 138: return (0); 139: } 140: 141: /* 142: * Free a message structure. 143: */ 144: void 145: _http_message_free(struct http_message **msgp) 146: { 147: struct http_message *const msg = *msgp; 148: 149: if (msg == NULL) 150: return; 151: _http_head_free(&msg->head); 152: if (msg->input != NULL) 153: fclose(msg->input); 154: if (msg->output != NULL) 155: fclose(msg->output); 156: if (msg->output_buf != NULL) 157: FREE("http_message.output_buf", msg->output_buf); 158: FREE("http_message.query", msg->query); 159: FREE("http_message.host", msg->host); 160: FREE("http_message.path", msg->path); 161: FREE("http_message", msg); 162: *msgp = NULL; 163: } 164: 165: /* 166: * Get message output stream. 167: * 168: * If "buffer" is true, the entire output will be buffered unless 169: * the headers have already been sent. 170: */ 171: FILE * 172: _http_message_get_output(struct http_message *msg, int buffer) 173: { 174: if (msg->output == NULL) { 175: if ((msg->output = funopen(msg, NULL, 176: http_message_output_write, NULL, 177: http_message_output_close)) == NULL) 178: return (NULL); 179: msg->buffered = buffer; 180: } 181: return (msg->output); 182: } 183: 184: /* 185: * Get raw i/o stream as a file descriptor. 186: */ 187: int 188: _http_message_get_raw_socket(struct http_message *msg) 189: { 190: if (msg->conn->ssl != NULL) { 191: errno = EPROTOTYPE; 192: return (-1); 193: } 194: return (msg->conn->sock); 195: } 196: 197: /* 198: * Send message headers, if not sent already. 199: */ 200: void 201: _http_message_send_headers(struct http_message *msg, int unbuffer) 202: { 203: /* Do nothing if nothing to do */ 204: if (msg->hdrs_sent) 205: return; 206: 207: /* If we're unbuffering message, turn off buffered flag */ 208: if (!msg->buffered) 209: unbuffer = 0; 210: else if (unbuffer) { 211: if (msg->output != NULL) 212: fflush(msg->output); 213: msg->buffered = 0; 214: } 215: 216: /* In buffered mode, set Content-Length header from buffer length. 217: In non-buffed mode, turn off connection keep-alive. If no body, 218: remove content related headers. */ 219: if (msg->no_body) { 220: _http_head_remove(msg->head, HTTP_HEADER_CONTENT_ENCODING); 221: _http_head_remove(msg->head, HTTP_HEADER_CONTENT_LENGTH); 222: _http_head_remove(msg->head, HTTP_HEADER_CONTENT_TYPE); 223: _http_head_remove(msg->head, HTTP_HEADER_LAST_MODIFIED); 224: } else if (msg->buffered) { 225: if (msg->output != NULL) 226: fflush(msg->output); 227: _http_head_set(msg->head, 0, HTTP_HEADER_CONTENT_LENGTH, 228: "%u", msg->output_len); 229: } else if (_http_head_get(msg->head, 230: HTTP_HEADER_CONTENT_LENGTH) == NULL) { 231: _http_head_set(msg->head, 0, 232: _http_message_connection_header(msg), "Close"); 233: } 234: 235: /* Debugging */ 236: if (PDEL_DEBUG_ENABLED(HTTP_HDRS)) { 237: DBG(HTTP_HDRS, "dumping %s headers:", 238: msg->conn->server ? "RESPONSE" : "REQUEST"); 239: _http_head_write(msg->head, stdout); 240: } 241: 242: /* Send headers */ 243: if (!msg->no_headers) 244: _http_head_write(msg->head, msg->conn->fp); 245: msg->hdrs_sent = 1; 246: 247: /* If unbuffering, send and release any output buffered so far */ 248: if (unbuffer) { 249: _http_message_send_body(msg); 250: FREE("http_message.output_buf", msg->output_buf); 251: msg->output_buf = NULL; 252: msg->output_len = 0; 253: } 254: } 255: 256: /* 257: * Send message body. 258: */ 259: void 260: _http_message_send_body(struct http_message *msg) 261: { 262: struct http_connection *const conn = msg->conn; 263: 264: /* Flush output stream data */ 265: if (msg->output != NULL) 266: fflush(msg->output); 267: 268: /* Send buffered output (if it was buffered) */ 269: if (msg->output_buf != NULL) { 270: if (!msg->skip_body) 271: fwrite(msg->output_buf, 1, msg->output_len, conn->fp); 272: fflush(conn->fp); 273: } 274: } 275: 276: /* 277: * Set a message header. 278: */ 279: int 280: _http_message_vset_header(struct http_message *msg, int append, 281: const char *name, const char *valfmt, va_list args) 282: { 283: 284: /* Check if we already sent the headers */ 285: if (msg->hdrs_sent) { 286: errno = EALREADY; 287: return (-1); 288: } 289: 290: /* Set header */ 291: return (_http_head_vset(msg->head, append, name, valfmt, args)); 292: } 293: 294: /* 295: * Remove a message header. 296: */ 297: int 298: _http_message_remove_header(struct http_message *msg, const char *name) 299: { 300: return (_http_head_remove(msg->head, name)); 301: } 302: 303: /* 304: * Get the "Connection" header name, which will be either "Connection" 305: * or "Proxy-Connection". 306: */ 307: const char * 308: _http_message_connection_header(struct http_message *msg) 309: { 310: struct http_connection *const conn = msg->conn; 311: const char *hval; 312: 313: if (!conn->proxy 314: || (hval = _http_head_get(msg->head, conn->server ? 315: HDR_REQUEST_VERSION : HDR_REPLY_VERSION)) == NULL 316: || strcmp(hval, HTTP_PROTO_1_1) >= 0) 317: return (HTTP_HEADER_CONNECTION); 318: return (HTTP_HEADER_PROXY_CONNECTION); 319: } 320: 321: /* 322: * Get remote IP address. 323: */ 324: struct in_addr 325: _http_message_get_remote_ip(struct http_message *msg) 326: { 327: return (msg->conn->remote_ip); 328: } 329: 330: /* 331: * Get remote port. 332: */ 333: u_int16_t 334: _http_message_get_remote_port(struct http_message *msg) 335: { 336: return (msg->conn->remote_port); 337: } 338: 339: /* 340: * Figure out whether anything is in the message at all. 341: */ 342: int 343: _http_message_has_anything(struct http_message *msg) 344: { 345: return (_http_head_has_anything(msg->head)); 346: } 347: 348: /********************************************************************* 349: INPUT STREAM METHODS 350: *********************************************************************/ 351: 352: /* 353: * Read message input stream. 354: */ 355: static int 356: http_message_input_read(void *cookie, char *buf, int len) 357: { 358: struct http_message *const msg = cookie; 359: int ret; 360: 361: if (msg->input_read == msg->input_len || len < 0) 362: return (0); 363: if (len > msg->input_len - msg->input_read) 364: len = msg->input_len - msg->input_read; 365: if ((ret = fread(buf, 1, len, msg->conn->fp)) != len) { 366: if (ferror(msg->conn->fp)) 367: return (-1); 368: } 369: msg->input_read += ret; 370: return (ret); 371: } 372: 373: /* 374: * Close message input stream. 375: */ 376: static int 377: http_message_input_close(void *cookie) 378: { 379: struct http_message *const msg = cookie; 380: 381: msg->input = NULL; 382: return (0); 383: } 384: 385: /********************************************************************* 386: OUTPUT STREAM METHODS 387: *********************************************************************/ 388: 389: /* 390: * Write to message output stream. 391: */ 392: static int 393: http_message_output_write(void *cookie, const char *buf, int len) 394: { 395: struct http_message *const msg = cookie; 396: struct http_connection *const conn = msg->conn; 397: int totlen; 398: int ret; 399: void *mem; 400: 401: /* Ignore zero length writes */ 402: if (len == 0) 403: return (0); 404: 405: /* Check whether to allow an entity body at all */ 406: if (msg->no_body) { 407: errno = EINVAL; 408: return (-1); 409: } 410: 411: /* If not buffered, check if headers have been sent then write data */ 412: if (!msg->buffered) { 413: if (!msg->hdrs_sent) 414: _http_message_send_headers(msg, 0); 415: if (msg->skip_body) 416: return (len); 417: if ((ret = fwrite(buf, 1, len, conn->fp)) != len) 418: return (-1); 419: return (ret); 420: } 421: 422: /* Expand buffer and write data into it */ 423: totlen = msg->output_len + len; 424: if ((mem = REALLOC("http_message.output_buf", 425: msg->output_buf, totlen)) == NULL) { 426: (*conn->logger)(LOG_ERR, "%s: %s", "realloc", strerror(errno)); 427: return (-1); 428: } 429: msg->output_buf = mem; 430: memcpy(msg->output_buf + msg->output_len, buf, len); 431: msg->output_len += len; 432: return (len); 433: } 434: 435: /* 436: * Close message output stream. 437: */ 438: static int 439: http_message_output_close(void *cookie) 440: { 441: struct http_message *const msg = cookie; 442: 443: msg->output = NULL; 444: return (0); 445: } 446: