Annotation of embedaddon/libpdel/http/http_mime.c, revision 1.1
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];
! 122: int nr;
! 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;
! 292: int i;
! 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:
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>