Return to http_mime.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 <syslog.h> 51: #include <pthread.h> 52: #include <errno.h> 53: #include <limits.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 "io/boundary_fp.h" 62: #include "io/string_fp.h" 63: #include "util/typed_mem.h" 64: #include "http/http_defs.h" 65: #include "http/http_server.h" 66: #include "http/http_internal.h" 67: 68: #define CR '\r' 69: #define LF '\n' 70: 71: #define MIME_MEM_TYPE "mime_multipart" 72: 73: struct mime_multipart { 74: u_int nparts; 75: u_int nalloc; 76: struct mime_part *parts; 77: }; 78: 79: struct mime_part { 80: struct http_head *head; /* mime headers */ 81: u_char *data; /* part's data */ 82: u_int dlen; /* length of data */ 83: }; 84: 85: /* Internal functions */ 86: static http_mime_handler_t _http_request_read_mime_handler; 87: 88: /* 89: * Read in multi-part MIME data all at once into memory. 90: */ 91: struct mime_multipart * 92: http_request_read_mime_multipart(struct http_request *req) 93: { 94: struct mime_multipart *mp; 95: 96: /* Allocate multipart structure */ 97: if ((mp = MALLOC(MIME_MEM_TYPE, sizeof(*mp))) == NULL) 98: return (NULL); 99: memset(mp, 0, sizeof(*mp)); 100: 101: /* Read in parts */ 102: if (http_request_get_mime_multiparts(req, 103: _http_request_read_mime_handler, mp) < 0) { 104: http_mime_multipart_free(&mp); 105: return (NULL); 106: } 107: 108: /* Done */ 109: return (mp); 110: } 111: 112: /* 113: * Handler used by http_request_read_mime_multipart(). 114: */ 115: static int 116: _http_request_read_mime_handler(void *arg, struct mime_part *part0, FILE *fp) 117: { 118: struct mime_multipart *const mp = arg; 119: struct mime_part *part; 120: FILE *sb = NULL; 121: char buf[256]; 1.1.1.2 ! misho 122: size_t nr; 1.1 misho 123: 124: /* Allocate new part structure */ 125: if (mp->nalloc < mp->nparts + 1) { 126: const u_int new_alloc = (mp->nalloc + 1) * 2; 127: struct mime_part *new_parts; 128: 129: if ((new_parts = REALLOC(MIME_MEM_TYPE, 130: mp->parts, new_alloc * sizeof(*mp->parts))) == NULL) 131: return (-1); 132: mp->parts = new_parts; 133: mp->nalloc = new_alloc; 134: } 135: part = &mp->parts[mp->nparts++]; 136: memset(part, 0, sizeof(*part)); 137: 138: /* Copy headers for this part */ 139: if ((part->head = _http_head_copy(part0->head)) == NULL) 140: return (-1); 141: 142: /* Slurp part's data into memory buffer */ 143: if ((sb = string_buf_output(MIME_MEM_TYPE)) == NULL) 144: return (-1); 145: while ((nr = fread(buf, 1, sizeof(buf), fp)) != 0) { 146: if (fwrite(buf, 1, nr, sb) != nr) { 147: fclose(sb); 148: return (-1); 149: } 150: } 151: if (ferror(fp)) { 152: fclose(sb); 153: return (-1); 154: } 155: 156: /* Extract data from string buffer stream */ 157: part->dlen = string_buf_length(sb); 158: if ((part->data = (u_char *)string_buf_content(sb, 1)) == NULL) { 159: part->dlen = 0; 160: fclose(sb); 161: return (-1); 162: } 163: fclose(sb); 164: 165: /* Done */ 166: return (0); 167: } 168: 169: /* 170: * Read in multi-part MIME data, and call the handler for each part. 171: * 172: * Returns the number of parts successfully read, or the ones 173: * complement of that number if the handler aborted. 174: */ 175: int 176: http_request_get_mime_multiparts(struct http_request *req, 177: http_mime_handler_t *handler, void *arg) 178: { 179: const char *hval; 180: FILE *fp = NULL; 181: char boundary[256]; 182: char buf[256]; 183: char *tokctx; 184: FILE *input; 185: int nparts; 186: char *s; 187: 188: /* Get POST input stream */ 189: if ((input = http_request_get_input(req)) == NULL) 190: return (~0); 191: 192: /* Get boundary string */ 193: if ((hval = http_request_get_header(req, 194: HTTP_HEADER_CONTENT_TYPE)) == NULL 195: || strlen(hval) > sizeof(buf) - 1) 196: goto bogus; 197: strlcpy(buf, hval, sizeof(buf)); 198: if ((s = strchr(buf, ';')) == NULL) 199: goto bogus; 200: *s++ = '\0'; 201: if (strcasecmp(buf, HTTP_CTYPE_MULTIPART_FORMDATA) != 0) 202: goto bogus; 203: if ((s = strtok_r(s, " \t;=", &tokctx)) == NULL 204: || strcasecmp(s, "boundary") != 0 205: || (s = strtok_r(NULL, " \t;=", &tokctx)) == NULL) { 206: bogus: errno = EINVAL; 207: return (~0); 208: } 209: snprintf(boundary, sizeof(boundary), "\r\n--%s", s); 210: 211: /* Read up through the initial boundary string */ 212: if ((fp = boundary_fopen(input, boundary + 2, 0)) == NULL) 213: return (~0); 214: while (fgets(buf, sizeof(buf), fp) != NULL) 215: ; 216: if (ferror(fp)) { 217: fclose(fp); 218: return (~0); 219: } 220: fclose(fp); 221: 222: /* Read in each part */ 223: for (nparts = 0; 1; nparts++) { 224: struct mime_part part; 225: int ch; 226: int r; 227: 228: /* We just saw a boundary; see if it was the last one */ 229: if ((ch = getc(input)) == '-') 230: return (nparts); 231: if (ch != '\r' || getc(input) != '\n') { 232: errno = EFTYPE; 233: break; 234: } 235: 236: /* Get stream for the next part only */ 237: if ((fp = boundary_fopen(input, boundary, 0)) == NULL) 238: break; 239: 240: /* Read in the next part's headers */ 241: memset(&part, 0, sizeof(part)); 242: if ((part.head = _http_head_new()) == NULL) { 243: fclose(fp); 244: break; 245: } 246: if (_http_head_read_headers(part.head, fp) == -1) { 247: _http_head_free(&part.head); 248: fclose(fp); 249: break; 250: } 251: 252: /* Invoke the handler */ 253: r = (*handler)(arg, &part, fp); 254: 255: /* Read any data not read by handler */ 256: while (fgets(buf, sizeof(buf), fp) != NULL) 257: ; 258: 259: /* Clean up */ 260: _http_head_free(&part.head); 261: fclose(fp); 262: 263: /* If handler aborted, stop */ 264: if (r != 0) 265: break; 266: } 267: 268: /* There was an error */ 269: return (~nparts); 270: } 271: 272: u_int 273: http_mime_multipart_get_count(struct mime_multipart *mp) 274: { 275: return (mp->nparts); 276: } 277: 278: struct mime_part * 279: http_mime_multipart_get_part(struct mime_multipart *mp, u_int index) 280: { 281: if (index >= mp->nparts) { 282: errno = EINVAL; 283: return (NULL); 284: } 285: return (&mp->parts[index]); 286: } 287: 288: void 289: http_mime_multipart_free(struct mime_multipart **mpp) 290: { 291: struct mime_multipart *const mp = *mpp; 1.1.1.2 ! misho 292: unsigned i; 1.1 misho 293: 294: if (mp == NULL) 295: return; 296: for (i = 0; i < mp->nparts; i++) { 297: struct mime_part *const part = &mp->parts[i]; 298: 299: _http_head_free(&part->head); 300: FREE(MIME_MEM_TYPE, part->data); 301: } 302: FREE(MIME_MEM_TYPE, mp->parts); 303: FREE(MIME_MEM_TYPE, mp); 304: *mpp = NULL; 305: } 306: 307: const char * 308: http_mime_part_get_header(struct mime_part *part, const char *name) 309: { 310: return (_http_head_get(part->head, name)); 311: } 312: 313: u_int 314: http_mime_part_get_length(struct mime_part *part) 315: { 316: return (part->dlen); 317: } 318: 319: u_char * 320: http_mime_part_get_data(struct mime_part *part) 321: { 322: return (part->data); 323: } 324: 325: