File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / libpdel / http / http_mime.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Tue Feb 21 23:25:53 2012 UTC (12 years, 4 months ago) by misho
Branches: libpdel, MAIN
CVS tags: v0_5_3, HEAD
libpdel


/*
 * Copyright (c) 2001-2002 Packet Design, LLC.
 * All rights reserved.
 * 
 * Subject to the following obligations and disclaimer of warranty,
 * use and redistribution of this software, in source or object code
 * forms, with or without modifications are expressly permitted by
 * Packet Design; provided, however, that:
 * 
 *    (i)  Any and all reproductions of the source or object code
 *         must include the copyright notice above and the following
 *         disclaimer of warranties; and
 *    (ii) No rights are granted, in any manner or form, to use
 *         Packet Design trademarks, including the mark "PACKET DESIGN"
 *         on advertising, endorsements, or otherwise except as such
 *         appears in the above copyright notice or in the software.
 * 
 * THIS SOFTWARE IS BEING PROVIDED BY PACKET DESIGN "AS IS", AND
 * TO THE MAXIMUM EXTENT PERMITTED BY LAW, PACKET DESIGN MAKES NO
 * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING
 * THIS SOFTWARE, INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED
 * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE,
 * OR NON-INFRINGEMENT.  PACKET DESIGN DOES NOT WARRANT, GUARANTEE,
 * OR MAKE ANY REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS
 * OF THE USE OF THIS SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY,
 * RELIABILITY OR OTHERWISE.  IN NO EVENT SHALL PACKET DESIGN BE
 * LIABLE FOR ANY DAMAGES RESULTING FROM OR ARISING OUT OF ANY USE
 * OF THIS SOFTWARE, INCLUDING WITHOUT LIMITATION, ANY DIRECT,
 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, PUNITIVE, OR CONSEQUENTIAL
 * DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, LOSS OF
 * USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
 * THE USE OF THIS SOFTWARE, EVEN IF PACKET DESIGN IS ADVISED OF
 * THE POSSIBILITY OF SUCH DAMAGE.
 *
 * Author: Archie Cobbs <archie@freebsd.org>
 */

#include <sys/types.h>
#include <sys/queue.h>

#include <netinet/in.h>

#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <syslog.h>
#include <pthread.h>
#include <errno.h>
#include <limits.h>
#include <ctype.h>

#include <openssl/ssl.h>

#include "structs/structs.h"
#include "structs/type/array.h"

#include "io/boundary_fp.h"
#include "io/string_fp.h"
#include "util/typed_mem.h"
#include "http/http_defs.h"
#include "http/http_server.h"
#include "http/http_internal.h"

#define CR		'\r'
#define LF		'\n'

#define MIME_MEM_TYPE		"mime_multipart"

struct mime_multipart {
	u_int			nparts;
	u_int			nalloc;
	struct mime_part	*parts;
};

struct mime_part {
	struct http_head	*head;			/* mime headers */
	u_char			*data;			/* part's data */
	u_int			dlen;			/* length of data */
};

/* Internal functions */
static http_mime_handler_t _http_request_read_mime_handler;

/*
 * Read in multi-part MIME data all at once into memory.
 */
struct mime_multipart *
http_request_read_mime_multipart(struct http_request *req)
{
	struct mime_multipart *mp;

	/* Allocate multipart structure */
	if ((mp = MALLOC(MIME_MEM_TYPE, sizeof(*mp))) == NULL)
		return (NULL);
	memset(mp, 0, sizeof(*mp));

	/* Read in parts */
	if (http_request_get_mime_multiparts(req,
	    _http_request_read_mime_handler, mp) < 0) {
		http_mime_multipart_free(&mp);
		return (NULL);
	}

	/* Done */
	return (mp);
}

/*
 * Handler used by http_request_read_mime_multipart().
 */
static int
_http_request_read_mime_handler(void *arg, struct mime_part *part0, FILE *fp)
{
	struct mime_multipart *const mp = arg;
	struct mime_part *part;
	FILE *sb = NULL;
	char buf[256];
	int nr;

	/* Allocate new part structure */
	if (mp->nalloc < mp->nparts + 1) {
		const u_int new_alloc = (mp->nalloc + 1) * 2;
		struct mime_part *new_parts;

		if ((new_parts = REALLOC(MIME_MEM_TYPE,
		    mp->parts, new_alloc * sizeof(*mp->parts))) == NULL)
			return (-1);
		mp->parts = new_parts;
		mp->nalloc = new_alloc;
	}
	part = &mp->parts[mp->nparts++];
	memset(part, 0, sizeof(*part));

	/* Copy headers for this part */
	if ((part->head = _http_head_copy(part0->head)) == NULL)
		return (-1);

	/* Slurp part's data into memory buffer */
	if ((sb = string_buf_output(MIME_MEM_TYPE)) == NULL)
		return (-1);
	while ((nr = fread(buf, 1, sizeof(buf), fp)) != 0) {
		if (fwrite(buf, 1, nr, sb) != nr) {
			fclose(sb);
			return (-1);
		}
	}
	if (ferror(fp)) {
		fclose(sb);
		return (-1);
	}

	/* Extract data from string buffer stream */
	part->dlen = string_buf_length(sb);
	if ((part->data = (u_char *)string_buf_content(sb, 1)) == NULL) {
		part->dlen = 0;
		fclose(sb);
		return (-1);
	}
	fclose(sb);

	/* Done */
	return (0);
}

/*
 * Read in multi-part MIME data, and call the handler for each part.
 *
 * Returns the number of parts successfully read, or the ones
 * complement of that number if the handler aborted.
 */
int
http_request_get_mime_multiparts(struct http_request *req,
	http_mime_handler_t *handler, void *arg)
{
	const char *hval;
	FILE *fp = NULL;
	char boundary[256];
	char buf[256];
	char *tokctx;
	FILE *input;
	int nparts;
	char *s;

	/* Get POST input stream */
	if ((input = http_request_get_input(req)) == NULL)
		return (~0);

	/* Get boundary string */
	if ((hval = http_request_get_header(req,
	      HTTP_HEADER_CONTENT_TYPE)) == NULL
	    || strlen(hval) > sizeof(buf) - 1)
		goto bogus;
	strlcpy(buf, hval, sizeof(buf));
	if ((s = strchr(buf, ';')) == NULL)
		goto bogus;
	*s++ = '\0';
	if (strcasecmp(buf, HTTP_CTYPE_MULTIPART_FORMDATA) != 0)
		goto bogus;
	if ((s = strtok_r(s, " \t;=", &tokctx)) == NULL
	    || strcasecmp(s, "boundary") != 0
	    || (s = strtok_r(NULL, " \t;=", &tokctx)) == NULL) {
bogus:		errno = EINVAL;
		return (~0);
	}
	snprintf(boundary, sizeof(boundary), "\r\n--%s", s);

	/* Read up through the initial boundary string */
	if ((fp = boundary_fopen(input, boundary + 2, 0)) == NULL)
		return (~0);
	while (fgets(buf, sizeof(buf), fp) != NULL)
		;
	if (ferror(fp)) {
		fclose(fp);
		return (~0);
	}
	fclose(fp);

	/* Read in each part */
	for (nparts = 0; 1; nparts++) {
		struct mime_part part;
		int ch;
		int r;

		/* We just saw a boundary; see if it was the last one */
		if ((ch = getc(input)) == '-')
			return (nparts);
		if (ch != '\r' || getc(input) != '\n') {
			errno = EFTYPE;
			break;
		}

		/* Get stream for the next part only */
		if ((fp = boundary_fopen(input, boundary, 0)) == NULL)
			break;

		/* Read in the next part's headers */
		memset(&part, 0, sizeof(part));
		if ((part.head = _http_head_new()) == NULL) {
			fclose(fp);
			break;
		}
		if (_http_head_read_headers(part.head, fp) == -1) {
			_http_head_free(&part.head);
			fclose(fp);
			break;
		}

		/* Invoke the handler */
		r = (*handler)(arg, &part, fp);

		/* Read any data not read by handler */
		while (fgets(buf, sizeof(buf), fp) != NULL)
			;

		/* Clean up */
		_http_head_free(&part.head);
		fclose(fp);

		/* If handler aborted, stop */
		if (r != 0)
			break;
	}

	/* There was an error */
	return (~nparts);
}

u_int
http_mime_multipart_get_count(struct mime_multipart *mp)
{
	return (mp->nparts);
}

struct mime_part *
http_mime_multipart_get_part(struct mime_multipart *mp, u_int index)
{
	if (index >= mp->nparts) {
		errno = EINVAL;
		return (NULL);
	}
	return (&mp->parts[index]);
}

void
http_mime_multipart_free(struct mime_multipart **mpp)
{
	struct mime_multipart *const mp = *mpp;
	int i;

	if (mp == NULL)
		return;
	for (i = 0; i < mp->nparts; i++) {
		struct mime_part *const part = &mp->parts[i];

		_http_head_free(&part->head);
		FREE(MIME_MEM_TYPE, part->data);
	}
	FREE(MIME_MEM_TYPE, mp->parts);
	FREE(MIME_MEM_TYPE, mp);
	*mpp = NULL;
}

const char *
http_mime_part_get_header(struct mime_part *part, const char *name)
{
	return (_http_head_get(part->head, name));
}

u_int
http_mime_part_get_length(struct mime_part *part)
{
	return (part->dlen);
}

u_char *
http_mime_part_get_data(struct mime_part *part)
{
	return (part->data);
}



FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>