summaryrefslogtreecommitdiffstats
path: root/nanohttp
diff options
context:
space:
mode:
Diffstat (limited to 'nanohttp')
-rwxr-xr-xnanohttp/nanohttp-mime.c937
-rwxr-xr-xnanohttp/nanohttp-mime.h59
-rwxr-xr-xnanohttp/nanohttp-request.c284
-rwxr-xr-xnanohttp/nanohttp-request.h57
-rwxr-xr-xnanohttp/nanohttp-response.c213
-rwxr-xr-xnanohttp/nanohttp-response.h57
-rwxr-xr-xnanohttp/todo.txt19
7 files changed, 1626 insertions, 0 deletions
diff --git a/nanohttp/nanohttp-mime.c b/nanohttp/nanohttp-mime.c
new file mode 100755
index 0000000..51f3219
--- /dev/null
+++ b/nanohttp/nanohttp-mime.c
@@ -0,0 +1,937 @@
+/******************************************************************
+* _ _ _ _ _ __
+* | \/ | | | | \/ | | _/
+* |_''_| |_| |_''_| |_'/ PARSER
+*
+* $Id: nanohttp-mime.c,v 1.1 2004/10/15 13:30:42 snowdrop Exp $
+*
+* CSOAP Project: A http client/server library in C
+* Copyright (C) 2003-2004 Ferhat Ayaz
+*
+* This library is free software; you can redistribute it and/or
+* modify it under the terms of the GNU Library General Public
+* License as published by the Free Software Foundation; either
+* version 2 of the License, or (at your option) any later version.
+*
+* This library is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+* Library General Public License for more details.
+*
+* You should have received a copy of the GNU Library General Public
+* License along with this library; if not, write to the
+* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+* Boston, MA 02111-1307, USA.
+*
+* Email: ferhatayaz@yahoo.com
+******************************************************************/
+
+
+
+#include <nanohttp/nanohttp-mime.h>
+#include <stdio.h>
+
+/*----------------------------------------------------------------
+Buffered Reader. A helper object to read bytes from a source
+----------------------------------------------------------------*/
+
+#ifdef MEM_DEBUG
+#include <utils/alloc.h>
+#endif
+
+
+
+/* ------------------------------------------------------------------
+ MIME Parser
+ ------------------------------------------------------------------*/
+typedef void (*MIME_part_begin) (void*);
+typedef void (*MIME_part_end) (void*);
+typedef void (*MIME_parse_begin) (void*);
+typedef void (*MIME_parse_end) (void*);
+typedef void (*MIME_ERROR_bytes) (void*,
+ const unsigned char*, size_t);
+
+typedef enum _MIME_parser_status
+{
+ MIME_PARSER_INCOMPLETE_MESSAGE,
+ MIME_PARSER_READ_ERROR,
+ MIME_PARSER_OK
+}MIME_parser_status;
+
+typedef enum _MIME_read_status
+{
+ MIME_READ_OK,
+ MIME_READ_EOF,
+ MIME_READ_ERROR
+}MIME_read_status;
+
+#define MIME_READER_MAX_BUFFER_SIZE 1054
+#define MIME_PARSER_BUFFER_SIZE 1054
+
+
+typedef MIME_read_status (*MIME_read_function) (void*, unsigned char*, int*);
+
+
+/**
+ Reader structure. This will be use
+ by the parser
+*/
+typedef struct _MIME_reader
+{
+ int size;
+ int marker;
+ int current;
+ MIME_read_function read_function;
+ char buffer[MIME_READER_MAX_BUFFER_SIZE];
+ void *userdata;
+}MIME_reader;
+
+
+MIME_read_status MIME_filereader_function(void* userdata,
+ unsigned char* dest, int* size);
+
+typedef struct _MIME_callbacks
+{
+ MIME_part_begin part_begin_cb;
+ MIME_part_end part_end_cb;
+ MIME_parse_begin parse_begin_cb;
+ MIME_parse_end parse_end_cb;
+ MIME_ERROR_bytes received_bytes_cb;
+}MIME_callbacks;
+
+
+MIME_parser_status MIME_parse(
+ MIME_read_function reader_function,
+ void *reader_userdata,
+ const char* user_boundary,
+ const MIME_callbacks* callbacks,
+ void *callbacks_userdata
+);
+
+
+/**
+ Initialize a reader
+*/
+void MIME_reader_init(MIME_reader *reader,
+ MIME_read_function reader_function,void *userdata)
+{
+ reader->size = 0;
+ reader->marker = -1;
+ reader->current = 0;
+ reader->userdata = userdata;
+ reader->read_function = reader_function;
+
+}
+
+/**
+ Read data from a reader source.
+*/
+MIME_read_status MIME_reader_read(MIME_reader *reader,
+ unsigned char *buffer, size_t size)
+{
+ MIME_read_status status;
+ size_t readed_size;
+ unsigned char tempBuffer[MIME_READER_MAX_BUFFER_SIZE];
+ int rest_size;
+
+ /* Check if buffer is full */
+ if (reader->size == reader->current)
+ {
+ /* Yes, so read some data */
+
+ /* First handle marker */
+ if (reader->marker > -1)
+ {
+ if (reader->marker != 0)
+ {
+ memcpy(tempBuffer, reader->buffer + reader->marker,
+ reader->size - reader->marker);
+ memcpy(reader->buffer, tempBuffer,
+ reader->size - reader->marker);
+ reader->current = reader->size - reader->marker;
+ }
+ else if (reader->current == MIME_READER_MAX_BUFFER_SIZE-1)
+ {
+ fprintf(stderr, "Marker error");
+ return MIME_READ_ERROR;
+ }
+ reader->marker = 0;
+ }
+ else
+ reader->current = 0;
+
+ readed_size = MIME_READER_MAX_BUFFER_SIZE - reader->current -1;
+ status = reader->read_function(reader->userdata,
+ reader->buffer + reader->current, &readed_size);
+
+ if (status == MIME_READ_OK)
+ {
+ reader->size = readed_size + reader->current;
+ }
+ else
+ return status;
+ }
+
+ if (size <= reader->size - reader->current)
+ {
+ memcpy(buffer, reader->buffer + reader->current, size);
+ reader->current += size;
+ return MIME_READ_OK;
+ }
+ else
+ {
+ /* Fill rest data */
+ rest_size = reader->size - reader->current;
+ memcpy(buffer, reader->buffer + reader->current, rest_size);
+
+ reader->current = reader->size;
+ return MIME_reader_read(reader, buffer + rest_size,
+ size - rest_size);
+ }
+}
+
+
+void MIME_reader_set_marker(MIME_reader *reader)
+{
+ reader->marker = reader->current;
+}
+
+void MIME_reader_unset_marker(MIME_reader *reader)
+{
+ reader->marker = -1;
+}
+
+void MIME_reader_jump_marker(MIME_reader *reader)
+{
+ reader->current = reader->marker;
+}
+
+
+
+typedef struct _MIME_buffer
+{
+ unsigned char data[MIME_PARSER_BUFFER_SIZE];
+ int size;
+}MIME_buffer;
+
+
+void MIME_buffer_init(MIME_buffer *buffer)
+{
+ buffer->size = 0;
+}
+
+void MIME_buffer_add(MIME_buffer *buffer, unsigned char ch)
+{
+ buffer->data[buffer->size++] = ch;
+}
+
+void MIME_buffer_add_bytes(MIME_buffer *buffer, unsigned char *bytes, int size)
+{
+ memcpy(buffer->data, bytes, size);
+ buffer->size += size;
+}
+
+int MIME_buffer_is_full(MIME_buffer *buffer)
+{
+ return buffer->size + 150 >= MIME_PARSER_BUFFER_SIZE;
+}
+
+int MIME_buffer_is_empty(MIME_buffer *buffer)
+{
+ return buffer->size == 0;
+}
+
+int MIME_buffer_clear(MIME_buffer *buffer)
+{
+ buffer->size = 0;
+}
+
+
+MIME_parser_status MIME_parse(
+ MIME_read_function reader_function,
+ void *reader_userdata,
+ const char* user_boundary,
+ const MIME_callbacks* callbacks,
+ void *callbacks_userdata
+)
+{
+ char boundary[150];
+ unsigned char ch[153];
+ int boundary_length, n, ignore = 0;
+ MIME_reader reader;
+ MIME_buffer buffer;
+ MIME_read_status status;
+
+ /* Init reader */
+ MIME_reader_init(&reader, reader_function, reader_userdata);
+
+ /* Init buffer */
+ MIME_buffer_init(&buffer);
+
+ /* Set boundary related stuff */
+ sprintf(boundary, "\n--%s", user_boundary);
+ boundary_length = strlen(boundary);
+
+ /* Call parse begin callback */
+ callbacks->parse_begin_cb(callbacks_userdata);
+
+ while (1)
+ {
+set_marker:
+
+ /* Set marker */
+ MIME_reader_set_marker(&reader);
+
+read_byte:
+
+ /* Read 1 byte */
+ status = MIME_reader_read(&reader, ch, 1);
+ _log_str("buffer.log", ch,1);
+ if (status == MIME_READ_EOF)
+ return MIME_PARSER_INCOMPLETE_MESSAGE;
+ else if (status == MIME_READ_ERROR)
+ return MIME_PARSER_READ_ERROR;
+
+ if (ch[0] == '\r' && !ignore)
+ {
+ n = 0;
+ while (n < boundary_length)
+ {
+ /* Read 1 byte */
+ status = MIME_reader_read(&reader, ch, 1);
+ _log_str("buffer.log", ch,1);
+ if (status == MIME_READ_EOF)
+ return MIME_PARSER_INCOMPLETE_MESSAGE;
+ else if (status == MIME_READ_ERROR)
+ return MIME_PARSER_READ_ERROR;
+
+ /* Check if byte is in boundary */
+ if (ch[0] == boundary[n])
+ {
+ n = n + 1;
+ continue;
+ }
+ else
+ {
+ MIME_reader_jump_marker(&reader);
+ ignore = 1;
+ goto read_byte;
+ }
+
+ } /* while n < boundary_length*/
+
+ /* Read 1 byte */
+ status = MIME_reader_read(&reader, ch, 1);
+ _log_str("buffer.log", ch,1);
+
+
+ if (status == MIME_READ_EOF)
+ return MIME_PARSER_INCOMPLETE_MESSAGE;
+ else if (status == MIME_READ_ERROR)
+ return MIME_PARSER_READ_ERROR;
+
+ /* Show if byte is '\r' */
+ if (ch[0] == '\r')
+ {
+ /* Read 1 byte */
+ status = MIME_reader_read(&reader, ch, 1);
+ _log_str("buffer.log", ch,1);
+
+
+ if (status == MIME_READ_EOF)
+ return MIME_PARSER_INCOMPLETE_MESSAGE;
+ else if (status == MIME_READ_ERROR)
+ return MIME_PARSER_READ_ERROR;
+
+ /* Check if byte is '\n' */
+ if (ch[0] == '\n')
+ {
+ if (!MIME_buffer_is_empty(&buffer))
+ {
+ /* Invoke callback */
+ callbacks->received_bytes_cb(
+ callbacks_userdata, buffer.data, buffer.size);
+
+ /* Empty the buffer */
+ MIME_buffer_clear(&buffer);
+
+ /* Invoke End Part */
+ callbacks->part_end_cb(callbacks_userdata);
+ }
+
+ /* Invoke start new Part */
+ callbacks->part_begin_cb(callbacks_userdata);
+ goto set_marker;
+
+ } /* if (ch[0] == '\n') */
+ else
+ {
+ /* Jump to marker and read bytes */
+ MIME_reader_jump_marker(&reader);
+ MIME_reader_read(&reader, ch, boundary_length+2);
+ _log_str("buffer.log", ch,1);
+
+ MIME_buffer_add_bytes(&buffer, ch, boundary_length+2);
+
+ if (MIME_buffer_is_full(&buffer))
+ {
+ /* Invoke callback */
+ callbacks->received_bytes_cb(
+ callbacks_userdata, buffer.data, buffer.size);
+
+
+ /* Empty the buffer */
+ MIME_buffer_clear(&buffer);
+ }
+ } /* else of if (ch[0] == '\n') */
+
+ } /* if (ch[0] == '\r') */
+ else
+ {
+ if (ch[0] == '-')
+ {
+ /* Read 1 byte */
+ status = MIME_reader_read(&reader, ch, 1);
+ _log_str("buffer.log", ch,1);
+
+ if (status == MIME_READ_EOF)
+ return MIME_PARSER_INCOMPLETE_MESSAGE;
+ else if (status == MIME_READ_ERROR)
+ return MIME_PARSER_READ_ERROR;
+
+ if (ch[0] == '-')
+ {
+ if (!MIME_buffer_is_empty(&buffer))
+ {
+ /* Invoke callback */
+ callbacks->received_bytes_cb(
+ callbacks_userdata, buffer.data, buffer.size);
+
+ /* Empty the buffer */
+ MIME_buffer_clear(&buffer);
+
+ /* Invoke End Part */
+ callbacks->part_end_cb(callbacks_userdata);
+ }
+
+ /* Invoke start new Part */
+ callbacks->parse_end_cb(callbacks_userdata);
+
+ /* Finish parsing*/
+ /* TODO (#1#): We assume that after -- comes \r\n
+ This is not always correct */
+
+ return MIME_PARSER_OK;
+
+ } /* if (ch[0] == '-') */
+ else
+ {
+ MIME_reader_jump_marker(&reader);
+ ignore = 1;
+ goto read_byte;
+ } /* else of if (ch[0] == '-') */
+
+ } /* if (ch[0] == '-') */
+ else
+ {
+ MIME_reader_jump_marker(&reader);
+ ignore = 1;
+ goto read_byte;
+ } /* else of if (ch[0] == '-') */
+
+ } /* else of if (ch[0] == '\r') */
+
+ } /* if ch[0] == '\r' && !ignore */
+ else
+ {
+ ignore = 0;
+ MIME_buffer_add(&buffer, ch[0]);
+
+ /* Chec if buffer is full*/
+ if (MIME_buffer_is_full(&buffer))
+ {
+ /* Invoke callback */
+ callbacks->received_bytes_cb(
+ callbacks_userdata, buffer.data, buffer.size);
+
+ /* Empty the buffer */
+ MIME_buffer_clear(&buffer);
+ }
+ } /* else of if ch[0] == '\r' && !ignore */
+ } /* while (1) */
+}
+
+
+
+
+MIME_read_status MIME_filereader_function(void* userdata,
+ unsigned char* dest, int* size)
+{
+ FILE *f = (FILE*)userdata;
+
+ if (feof(f))
+ return MIME_READ_EOF;
+
+ *size = fread(dest, 1, *size, f);
+ return MIME_READ_OK;
+}
+
+
+/* ------------------------------------------------------------------
+ "multipart/related" MIME Message Builder
+ ------------------------------------------------------------------*/
+
+/*
+ Callback data to use internally
+*/
+typedef struct _mime_callback_data
+{
+ int part_id;
+ attachments_t *message;
+ part_t *current_part;
+ int buffer_capacity;
+ char header[4064];
+ char root_id[256];
+ int header_index;
+ int header_search;
+ FILE *current_fd;
+ char root_dir[512];
+}mime_callback_data_t;
+
+
+
+MIME_read_status mime_streamreader_function(void* userdata,
+ unsigned char* dest, int* size)
+{
+ int readed=0;
+ http_input_stream_t *in = (http_input_stream_t*)userdata;
+
+ if (!http_input_stream_is_ready(in))
+ return MIME_READ_EOF;
+
+ readed = http_input_stream_read(in, dest, *size);
+ *size = readed;
+ if (*size!=-1) {
+ _log_str("reader.log", dest, *size);
+ return MIME_READ_OK;
+ }
+
+ return MIME_READ_ERROR;
+}
+
+
+/*
+ Start Callback functions
+*/
+static
+void _mime_parse_begin(void *data)
+{
+/* Nothing to do
+ mime_callback_data_t *cbdata = (mime_callback_data_t)data;
+ */
+ log_verbose2("Begin parse (%p)", data);
+}
+
+
+static
+void _mime_parse_end(void *data)
+{
+/* Nothing to do
+ mime_callback_data_t *cbdata = (mime_callback_data_t)data;
+ */
+ log_verbose2("End parse (%p)", data);
+}
+
+
+static
+void _mime_part_begin(void *data)
+{
+ char buffer[1054];
+ mime_callback_data_t *cbdata = (mime_callback_data_t*)data;
+ part_t *part;
+
+ log_verbose2("Begin Part (%p)", data);
+ part = (part_t *)malloc(sizeof(part_t));
+ part->next = NULL;
+
+
+ if (cbdata->current_part)
+ cbdata->current_part->next = part;
+
+ cbdata->current_part = part;
+
+ if (!cbdata->message->parts)
+ cbdata->message->parts = part;
+
+ cbdata->header[0] = '\0';
+ cbdata->header_index = 0;
+ cbdata->header_search = 0;
+
+#ifdef WIN32
+ sprintf(buffer, "%s\\mime_%p_%d.part", cbdata->root_dir,
+ cbdata, cbdata->part_id++);
+#else
+ sprintf(buffer, "%s/mime_%p_%d.part", cbdata->root_dir,
+ cbdata, cbdata->part_id++);
+#endif
+
+ cbdata->current_fd = fopen(buffer, "wb");
+ if (cbdata->current_fd)
+ strcpy(cbdata->current_part->filename, buffer);
+ else
+ log_error2("Can not open file for write '%s'", buffer);
+}
+
+
+static
+void _mime_part_end(void *data)
+{
+ mime_callback_data_t *cbdata = (mime_callback_data_t*)data;
+ log_verbose2("End Part (%p)", data);
+ if (cbdata->current_fd)
+ {
+ fclose(cbdata->current_fd);
+ cbdata->current_fd = NULL;
+ }
+}
+
+
+static
+hpair_t *_mime_process_header(char *buffer)
+{
+ int i=0, c=0, proc_key, begin=0;
+ hpair_t *first = NULL, *last = NULL;
+ char key[1054], value[1054];
+
+ key[0] = '\0';
+ value[0] = '\0';
+ proc_key = 1;
+
+ while (buffer[i] != '\0')
+ {
+ if (buffer[i] == '\r' && buffer[i+1] == '\n')
+ {
+ value[c] = '\0';
+ if (last)
+ {
+ last->next = hpairnode_new(key, value, NULL);
+ last = last->next;
+ }
+ else
+ {
+ first = last = hpairnode_new(key, value, NULL);
+ }
+ proc_key = 1;
+ c = 0;
+ i++;
+ }
+ else if (buffer[i] == ':')
+ {
+ key[c] = '\0';
+ c = 0;
+ begin = 0;
+ proc_key = 0;
+ }
+ else
+ {
+ if (proc_key)
+ key[c++] = buffer[i];
+ else
+ {
+ if (buffer[i] != ' ')
+ begin = 1;
+ if (begin)
+ value[c++] = buffer[i];
+ }
+ }
+ i++;
+ }
+ return first;
+}
+
+
+static
+void _mime_received_bytes(void *data, const unsigned char* bytes, size_t size)
+{
+ int i=0;
+ char *id;
+ mime_callback_data_t *cbdata = (mime_callback_data_t*)data;
+
+ if (!cbdata ) {
+ log_error1("MIME transport error Called <received bytes> without initializing\n");
+ return;
+ }
+ if (!cbdata->current_part) {
+ log_error1("MIME transport error Called <received bytes> without initializing\n");
+ return;
+ }
+/* log_verbose4("Received %d bytes (%p), header_search = %d",
+ size, data, cbdata->header_search);
+*/
+ if (cbdata->header_search < 4)
+ {
+ /* Find \r\n\r\n in bytes */
+ for (i=0;i<size;i++)
+ {
+ if (cbdata->header_search == 0)
+ {
+ if (bytes[i] == '\r')
+ cbdata->header_search++;
+ else
+ {
+ cbdata->header[cbdata->header_index++] = bytes[i];
+ cbdata->header_search = 0;
+ }
+ }
+
+ else if (cbdata->header_search == 1)
+ {
+ if (bytes[i] == '\n')
+ cbdata->header_search++;
+ else
+ {
+ cbdata->header[cbdata->header_index++] = '\r';
+ cbdata->header[cbdata->header_index++] = bytes[i];
+ cbdata->header_search = 0;
+ }
+ }
+
+ else if (cbdata->header_search == 2)
+ {
+ if (bytes[i] == '\r')
+ cbdata->header_search++;
+ else
+ {
+ cbdata->header[cbdata->header_index++] = '\r';
+ cbdata->header[cbdata->header_index++] = '\n';
+ cbdata->header[cbdata->header_index++] = bytes[i];
+ cbdata->header_search = 0;
+ }
+ }
+
+ else if (cbdata->header_search == 3)
+ {
+ if (bytes[i] == '\n')
+ {
+ cbdata->header[cbdata->header_index++] = '\r';
+ cbdata->header[cbdata->header_index++] = '\n';
+ cbdata->header[cbdata->header_index++] = '\0';
+ cbdata->header_search = 4;
+ cbdata->current_part->header = _mime_process_header(cbdata->header);
+ hpairnode_dump_deep(cbdata->current_part->header);
+ /* set id */
+ id = hpairnode_get(cbdata->current_part->header, HEADER_CONTENT_ID);
+ if (id != NULL)
+ {
+ strcpy(cbdata->current_part->id, id);
+ if (!strcmp(id, cbdata->root_id))
+ cbdata->message->root_part = cbdata->current_part;
+ }
+ i++;
+ break;
+ }
+ else
+ {
+ cbdata->header[cbdata->header_index++] = '\r';
+ cbdata->header[cbdata->header_index++] = '\n';
+ cbdata->header[cbdata->header_index++] = '\r';
+ cbdata->header[cbdata->header_index++] = bytes[i];
+ cbdata->header_search = 0;
+ }
+ }
+ /* TODO (#1#): Check for cbdata->header overflow */
+
+ } /* for (i=0;i<size;i++) */
+ } /* if (cbdata->header_search < 4) */
+
+ if (i >= size-1)
+ return;
+
+ /* Write remaining bytes into the file or buffer (if root)
+ (buffer is disabled in this version) */
+ if (cbdata->current_fd)
+ fwrite(&(bytes[i]), 1, size - i, cbdata->current_fd);
+}
+
+
+/*
+ The mime message parser
+*/
+
+attachments_t *
+mime_message_parse(http_input_stream_t *in, const char* root_id,
+ const char* boundary, const char* dest_dir)
+{
+ MIME_parser_status status;
+ MIME_callbacks callbacks;
+ attachments_t* message;
+
+ mime_callback_data_t *cbdata = (mime_callback_data_t*)
+ malloc(sizeof(mime_callback_data_t));
+
+ cbdata->part_id = 100;
+ cbdata->buffer_capacity = 0;
+ cbdata-> current_fd = NULL;
+ cbdata->current_part = NULL;
+ cbdata->header_index = 0;
+ cbdata->header_search = 0;
+ strcpy(cbdata->root_id, root_id);
+ strcpy(cbdata->root_dir, dest_dir);
+ message = (attachments_t*)malloc(sizeof(attachments_t));
+ cbdata->message = message;
+ cbdata->message->parts = NULL;
+ cbdata->message->root_part = NULL;
+
+ callbacks.parse_begin_cb = _mime_parse_begin;
+ callbacks.parse_end_cb = _mime_parse_end;
+ callbacks.part_begin_cb = _mime_part_begin;
+ callbacks.part_end_cb = _mime_part_end;
+ callbacks.received_bytes_cb = _mime_received_bytes;
+
+ status = MIME_parse(mime_streamreader_function,
+ in, boundary, &callbacks, cbdata);
+
+ if (status == MIME_PARSER_OK)
+ {
+ free(cbdata);
+ return message;
+ }
+ else
+ {
+ log_error2("MIME parser error '%s'!",
+ status == MIME_PARSER_READ_ERROR ? "read error" : "Incomplete message");
+ return NULL;
+ }
+}
+
+attachments_t *
+mime_message_parse_from_file(FILE *in, const char* root_id,
+ const char* boundary, const char* dest_dir)
+{
+ MIME_parser_status status;
+ MIME_callbacks callbacks;
+ attachments_t* message;
+
+ mime_callback_data_t *cbdata = (mime_callback_data_t*)
+ malloc(sizeof(mime_callback_data_t));
+
+ cbdata->part_id = 100;
+ cbdata->buffer_capacity = 0;
+ cbdata-> current_fd = NULL;
+ cbdata->current_part = NULL;
+ cbdata->header_index = 0;
+ cbdata->header_search = 0;
+ strcpy(cbdata->root_id, root_id);
+ strcpy(cbdata->root_dir, dest_dir);
+ message = (attachments_t*)malloc(sizeof(attachments_t));
+ cbdata->message = message;
+ cbdata->message->parts = NULL;
+ cbdata->message->root_part = NULL;
+
+ callbacks.parse_begin_cb = _mime_parse_begin;
+ callbacks.parse_end_cb = _mime_parse_end;
+ callbacks.part_begin_cb = _mime_part_begin;
+ callbacks.part_end_cb = _mime_part_end;
+ callbacks.received_bytes_cb = _mime_received_bytes;
+
+ status = MIME_parse(MIME_filereader_function,
+ in, boundary, &callbacks, cbdata);
+
+ if (status == MIME_PARSER_OK)
+ {
+ free(cbdata);
+ return message;
+ }
+ else
+ {
+ /* TODO (#1#): Free objects */
+
+ log_error2("MIME parser error '%s'!",
+ status == MIME_PARSER_READ_ERROR ? "general error" : "Incomplete message");
+ return NULL;
+ }
+}
+
+/*
+ Free a mime part
+*/
+void
+mime_part_free(part_t *part)
+{
+ if (part == NULL)
+ return;
+
+ hpairnode_free_deep(part->header);
+
+ free(part);
+}
+
+
+
+
+hstatus_t mime_get_attachments(content_type_t *ctype, http_input_stream_t *in, attachments_t **dest)
+{
+ /* MIME variables */
+ attachments_t *mimeMessage;
+ part_t *part, *tmp_part=NULL;
+ char *boundary, *root_id;
+
+ /* Check for MIME message */
+ if (!(ctype &&
+ !strcmp(ctype->type, "multipart/related")))
+ return MIME_ERROR_NOT_MIME_MESSAGE;
+
+ boundary = hpairnode_get(ctype->params, "boundary");
+ root_id = hpairnode_get(ctype->params, "start");
+ if (boundary == NULL)
+ {
+ /* TODO (#1#): Handle Error in http form */
+ log_error1("'boundary' not set for multipart/related");
+ return MIME_ERROR_NO_BOUNDARY_PARAM;
+ }
+
+ if (root_id == NULL)
+ {
+ /* TODO (#1#): Handle Error in http form */
+ log_error1("'start' not set for multipart/related");
+ return MIME_ERROR_NO_START_PARAM;
+ }
+
+ /* TODO (#1#): Set this not to working directory
+ This must be configured */
+
+ mimeMessage = mime_message_parse(in, root_id, boundary, ".");
+ if (mimeMessage == NULL)
+ {
+ /* TODO (#1#): Handle Error in http form */
+ log_error1("MIME Parse Error");
+ return MIME_ERROR_PARSE_ERROR;
+ }
+
+ /* Find root */
+ if (!mimeMessage->root_part)
+ {
+ attachments_free(mimeMessage);
+ return MIME_ERROR_NO_ROOT_PART;
+ }
+
+ /* delete root_part from list */
+ part = mimeMessage->parts;
+ while (part) {
+ if (part == mimeMessage->root_part)
+ {
+ if (tmp_part)
+ tmp_part->next = part->next;
+ else
+ mimeMessage->parts = part->next;
+
+ break;
+ }
+ tmp_part = part;
+ part = part->next;
+ }
+ *dest = mimeMessage;
+ return H_OK;
+}
+
+
diff --git a/nanohttp/nanohttp-mime.h b/nanohttp/nanohttp-mime.h
new file mode 100755
index 0000000..e863488
--- /dev/null
+++ b/nanohttp/nanohttp-mime.h
@@ -0,0 +1,59 @@
+/******************************************************************
+* _ _ _ _ _ __
+* | \/ | | | | \/ | | _/
+* |_''_| |_| |_''_| |_'/ PARSER
+*
+* $Id: nanohttp-mime.h,v 1.1 2004/10/15 13:30:42 snowdrop Exp $
+*
+* CSOAP Project: A http client/server library in C
+* Copyright (C) 2003-2004 Ferhat Ayaz
+*
+* This library is free software; you can redistribute it and/or
+* modify it under the terms of the GNU Library General Public
+* License as published by the Free Software Foundation; either
+* version 2 of the License, or (at your option) any later version.
+*
+* This library is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+* Library General Public License for more details.
+*
+* You should have received a copy of the GNU Library General Public
+* License along with this library; if not, write to the
+* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+* Boston, MA 02111-1307, USA.
+*
+* Email: ferhatayaz@yahoo.com
+******************************************************************/
+
+#ifndef NANO_HTTP_MIME_PARSER_H
+#define NANO_HTTP_MIME_PARSER_H
+
+#include <stdlib.h>
+
+#include <nanohttp/nanohttp-stream.h>
+#include <nanohttp/nanohttp-common.h>
+
+/* ------------------------------------------------------------------
+ "multipart/related" MIME Message Builder
+ ------------------------------------------------------------------*/
+
+
+
+hstatus_t mime_get_attachments(content_type_t *ctype,
+ http_input_stream_t *in, attachments_t **dest);
+
+
+#endif
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/nanohttp/nanohttp-request.c b/nanohttp/nanohttp-request.c
new file mode 100755
index 0000000..bed59f2
--- /dev/null
+++ b/nanohttp/nanohttp-request.c
@@ -0,0 +1,284 @@
+/******************************************************************
+* $Id: nanohttp-request.c,v 1.1 2004/10/15 13:30:42 snowdrop Exp $
+*
+* CSOAP Project: A http client/server library in C
+* Copyright (C) 2003 Ferhat Ayaz
+*
+* This library is free software; you can redistribute it and/or
+* modify it under the terms of the GNU Library General Public
+* License as published by the Free Software Foundation; either
+* version 2 of the License, or (at your option) any later version.
+*
+* This library is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+* Library General Public License for more details.
+*
+* You should have received a copy of the GNU Library General Public
+* License along with this library; if not, write to the
+* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+* Boston, MA 02111-1307, USA.
+*
+* Email: ayaz@jprogrammer.net
+******************************************************************/
+
+#include <nanohttp/nanohttp-common.h>
+#include <nanohttp/nanohttp-request.h>
+
+#ifdef MEM_DEBUG
+#include <utils/alloc.h>
+#endif
+
+/* request stuff */
+
+
+static
+hrequest_t *hrequest_new()
+{
+ hrequest_t * req = (hrequest_t *) malloc(sizeof(hrequest_t));
+
+ req->method = HTTP_REQUEST_GET;
+ req->version = HTTP_1_1;
+ req->query = NULL;
+ req->header = NULL;
+ req->in = NULL;
+ req->attachments = NULL;
+ req->content_type = NULL;
+
+}
+
+static
+hrequest_t *
+_hrequest_parse_header(char *data)
+{
+ hrequest_t *req;
+ hpair_t *hpair = NULL, *qpair = NULL, *tmppair = NULL;
+
+ char *tmp;
+ char *tmp2;
+ char *saveptr;
+ char *saveptr2;
+ char *saveptr3;
+ char *result;
+ char *key;
+ char *value;
+ char *opt_key;
+ char *opt_value;
+ int firstline = 1;
+
+ req = hrequest_new();
+ tmp = data;
+
+ for (;;) {
+ result = (char *) strtok_r(tmp, "\r\n", &saveptr);
+ tmp = saveptr;
+
+ if (result == NULL)
+ break;
+
+ if (firstline) {
+ firstline = 0;
+ tmp2 = result;
+
+ /* parse [GET|POST] [PATH] [SPEC] */
+ key = (char *) strtok_r(tmp2, " ", &saveptr2);
+
+ /* save method (get or post) */
+ tmp2 = saveptr2;
+ if (key != NULL) {
+ if (!strcmp(key, "POST"))
+ req->method = HTTP_REQUEST_POST;
+ else
+ req->method = HTTP_REQUEST_GET;
+ }
+ /* below is key the path and tmp2 the spec */
+ key = (char *) strtok_r(tmp2, " ", &saveptr2);
+
+ /* save version */
+ tmp2 = saveptr2;
+ if (tmp2 != NULL) {
+ /*req->spec = (char *) malloc(strlen(tmp2) + 1);
+ strcpy(req->spec, tmp2);
+ */
+ if (!strcmp(tmp2, "HTTP/1.0"))
+ req-> version = HTTP_1_0;
+ else
+ req-> version = HTTP_1_1;
+ }
+ /*
+ * parse and save path+query parse:
+ * /path/of/target?key1=value1&key2=value2...
+ */
+
+ if (key != NULL) {
+ tmp2 = key;
+ key = (char *) strtok_r(tmp2, "?", &saveptr2);
+ tmp2 = saveptr2;
+
+ /* save path */
+ /*req->path = (char *) malloc(strlen(key) + 1);*/
+ strncpy(req->path, key, REQUEST_MAX_PATH_SIZE);
+
+ /* parse options */
+ for (;;) {
+ key = (char *) strtok_r(tmp2, "&", &saveptr2);
+ tmp2 = saveptr2;
+
+ if (key == NULL)
+ break;
+
+ opt_key = (char *) strtok_r(key, "=", &saveptr3);
+ opt_value = saveptr3;
+
+ if (opt_value == NULL)
+ opt_value = "";
+
+ /* create option pair */
+ if (opt_key != NULL) {
+ tmppair = (hpair_t *) malloc(sizeof(hpair_t));
+
+ if (req->query == NULL) {
+ req->query = qpair = tmppair;
+ } else {
+ qpair->next = tmppair;
+ qpair = tmppair;
+ }
+
+ /* fill hpairnode_t struct */
+ qpair->next = NULL;
+ qpair->key = (char *) malloc(strlen(opt_key) + 1);
+ qpair->value = (char *) malloc(strlen(opt_value) + 1);
+
+ strcpy(qpair->key, opt_key);
+ strcpy(qpair->value, opt_value);
+
+ }
+ }
+ }
+ } else {
+
+ /* parse "key: value" */
+ /* tmp2 = result;
+ key = (char *) strtok_r(tmp2, ": ", &saveptr2);
+ value = saveptr2;*/
+
+ /* create pair */
+/* tmppair = (hpair_t *) malloc(sizeof(hpair_t));*/
+ tmppair = hpairnode_parse(result, ":", NULL);
+
+ if (req->header == NULL) {
+ req->header = hpair = tmppair;
+ } else {
+ hpair->next = tmppair;
+ hpair = tmppair;
+ }
+
+ /* fill pairnode_t struct */
+ /*
+ hpair->next = NULL;
+ hpair->key = (char *) malloc(strlen(key) + 1);
+ hpair->value = (char *) malloc(strlen(value) + 1);
+
+ strcpy(hpair->key, key);
+ strcpy(hpair->value, value);
+ */
+ }
+ }
+
+ /* Check Content-type */
+ tmp = hpairnode_get(req->header, HEADER_CONTENT_TYPE);
+ if (tmp != NULL)
+ req->content_type = content_type_new(tmp);
+
+ return req;
+}
+
+
+void
+hrequest_free(hrequest_t * req)
+{
+ if (req == NULL)
+ return;
+
+
+ hpairnode_free_deep(req->header);
+ hpairnode_free_deep(req->query);
+
+ if (req->in)
+ http_input_stream_free(req->in);
+
+ if (req->content_type)
+ content_type_free(req->content_type);
+
+ if (req->attachments)
+ attachments_free(req->attachments);
+
+ free(req);
+}
+
+
+hrequest_t *
+hrequest_new_from_socket(hsocket_t sock)
+{
+ int i=0, status;
+ hrequest_t *req;
+ char buffer[MAX_HEADER_SIZE+1];
+ attachments_t *mimeMessage;
+
+ /* Read header */
+ while (i<MAX_HEADER_SIZE)
+ {
+ status = hsocket_read(sock, &(buffer[i]), 1, 1);
+ if (status == -1)
+ {
+ log_error1("Socket read error");
+ return NULL;
+ }
+
+ buffer[i+1] = '\0'; /* for strmp */
+
+ if (i > 3)
+ {
+ if (!strcmp(&(buffer[i-1]), "\n\n") ||
+ !strcmp(&(buffer[i-2]), "\n\r\n"))
+ break;
+ }
+ i++;
+ }
+
+ /* Create response */
+ req = _hrequest_parse_header(buffer);
+ if (req == NULL)
+ {
+ log_error1("Header parse error");
+ return NULL;
+ }
+
+ /* Create input stream */
+ req->in = http_input_stream_new(sock, req->header);
+
+ /* Check for MIME message */
+ if ((req->content_type &&
+ !strcmp(req->content_type->type, "multipart/related")))
+ {
+ status = mime_get_attachments(req->content_type, req->in, &mimeMessage);
+ if (status != H_OK)
+ {
+ /* TODO (#1#): Handle error */
+ hrequest_free(req);
+ return NULL;
+ }
+ else
+ {
+ req->attachments = mimeMessage;
+ req->in = http_input_stream_new_from_file(mimeMessage->root_part->filename);
+ }
+ }
+
+
+ return req;
+}
+
+
+
+
diff --git a/nanohttp/nanohttp-request.h b/nanohttp/nanohttp-request.h
new file mode 100755
index 0000000..c445596
--- /dev/null
+++ b/nanohttp/nanohttp-request.h
@@ -0,0 +1,57 @@
+/******************************************************************
+ * $Id: nanohttp-request.h,v 1.1 2004/10/15 13:30:42 snowdrop Exp $
+ *
+ * CSOAP Project: A http client/server library in C
+ * Copyright (C) 2003-2004 Ferhat Ayaz
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Email: ferhatayaz@yahoo.com
+ ******************************************************************/
+#ifndef NANO_HTTP_REQUEST_H
+#define NANO_HTTP_REQUEST_H
+
+#include <nanohttp/nanohttp-stream.h>
+#include <nanohttp/nanohttp-mime.h>
+
+/*
+ request object
+ */
+typedef struct hrequest
+{
+ hreq_method_t method;
+ http_version_t version;
+ char path[REQUEST_MAX_PATH_SIZE];
+
+ hpair_t *query;
+ hpair_t *header;
+
+ http_input_stream_t *in;
+ content_type_t *content_type;
+ attachments_t *attachments;
+ char root_part_id[150];
+}hrequest_t;
+
+hrequest_t *hrequest_new_from_socket(hsocket_t sock);
+void hrequest_free(hrequest_t *req);
+
+#endif
+
+
+
+
+
+
diff --git a/nanohttp/nanohttp-response.c b/nanohttp/nanohttp-response.c
new file mode 100755
index 0000000..8f55856
--- /dev/null
+++ b/nanohttp/nanohttp-response.c
@@ -0,0 +1,213 @@
+/******************************************************************
+* $Id: nanohttp-response.c,v 1.1 2004/10/15 13:30:42 snowdrop Exp $
+*
+* CSOAP Project: A http client/server library in C
+* Copyright (C) 2003-2004 Ferhat Ayaz
+*
+* This library is free software; you can redistribute it and/or
+* modify it under the terms of the GNU Library General Public
+* License as published by the Free Software Foundation; either
+* version 2 of the License, or (at your option) any later version.
+*
+* This library is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+* Library General Public License for more details.
+*
+* You should have received a copy of the GNU Library General Public
+* License along with this library; if not, write to the
+* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+* Boston, MA 02111-1307, USA.
+*
+* Email: ferhatayaz@yahoo.com
+******************************************************************/
+
+#include <nanohttp/nanohttp-common.h>
+#include <nanohttp/nanohttp-response.h>
+
+
+#ifdef MEM_DEBUG
+#include <utils/alloc.h>
+#endif
+
+static
+hresponse_t*
+hresponse_new()
+{
+ hresponse_t *res;
+
+ /* create response object */
+ res = (hresponse_t *) malloc(sizeof(hresponse_t));
+ res->version = HTTP_1_1;
+ res->errcode = -1;
+ res->desc[0] = '\0';
+ res->header = NULL;
+ res->in = NULL;
+ res->content_type = NULL;
+ res->attachments = NULL;
+ return res;
+}
+
+static
+hresponse_t*
+_hresponse_parse_header(const char *buffer)
+{
+ hresponse_t *res;
+ char *s1, *s2, *str;
+
+ /* create response object */
+ res = hresponse_new();
+
+ /* *** parse spec *** */
+ /* [HTTP/1.1 | 1.2] [CODE] [DESC] */
+
+ /* stage 1: HTTP spec */
+ str = (char *) strtok_r((char *) buffer, " ", &s2);
+ s1 = s2;
+ if (str == NULL) {
+ log_error1("Parse error reading HTTP spec");
+ return NULL;
+ }
+
+ if (!strcmp(str, "HTTP/1.0"))
+ res->version = HTTP_1_0;
+ else
+ res->version = HTTP_1_1;
+
+ /* stage 2: http code */
+ str = (char *) strtok_r(s1, " ", &s2);
+ s1 = s2;
+ if (str == NULL) {
+ log_error1("Parse error reading HTTP code");
+ return NULL;
+ }
+ res->errcode = atoi(str);
+
+ /* stage 3: description text */
+ str = (char *) strtok_r(s1, "\r\n", &s2);
+ s1 = s2;
+ if (str == NULL) {
+ log_error1("Parse error reading HTTP description");
+ return NULL;
+ }
+/* res->desc = (char *) malloc(strlen(str) + 1);*/
+ strncpy(res->desc, str, RESPONSE_MAX_DESC_SIZE);
+ res->desc[strlen(str)] = '\0';
+
+ /* *** parse header *** */
+ /* [key]: [value] */
+ for (;;) {
+ str = strtok_r(s1, "\n", &s2);
+ s1 = s2;
+
+ /* check if header ends without body */
+ if (str == NULL) {
+ return res;
+ }
+ /* check also for end of header */
+ if (!strcmp(str, "\r")) {
+ break;
+ }
+ str[strlen(str) - 1] = '\0';
+ res->header = hpairnode_parse(str, ":", res->header);
+ }
+
+ /* Check Content-type */
+ str = hpairnode_get(res->header, HEADER_CONTENT_TYPE);
+ if (str != NULL)
+ res->content_type = content_type_new(str);
+
+ /* return response object */
+ return res;
+}
+
+hresponse_t *
+hresponse_new_from_socket(hsocket_t sock)
+{
+ int i=0, status;
+ hresponse_t *res;
+ attachments_t *mimeMessage;
+ char buffer[MAX_HEADER_SIZE+1];
+
+read_header: /* for errorcode: 100 (continue) */
+ /* Read header */
+ while (i<MAX_HEADER_SIZE)
+ {
+ status = hsocket_read(sock, &(buffer[i]), 1, 1);
+ if (status == -1)
+ {
+ log_error1("Socket read error");
+ return NULL;
+ }
+
+ buffer[i+1] = '\0'; /* for strmp */
+
+ if (i > 3)
+ {
+ if (!strcmp(&(buffer[i-1]), "\n\n") ||
+ !strcmp(&(buffer[i-2]), "\n\r\n"))
+ break;
+ }
+ i++;
+ }
+
+ /* Create response */
+ res = _hresponse_parse_header(buffer);
+ if (res == NULL)
+ {
+ log_error1("Header parse error");
+ return NULL;
+ }
+
+ /* Chec for Errorcode: 100 (continue) */
+ if (res->errcode == 100) {
+ hresponse_free(res);
+ i=0;
+ goto read_header;
+ }
+
+ /* Create input stream */
+ res->in = http_input_stream_new(sock, res->header);
+
+
+ /* Check for MIME message */
+ if ((res->content_type &&
+ !strcmp(res->content_type->type, "multipart/related")))
+ {
+ status = mime_get_attachments(res->content_type, res->in, &mimeMessage);
+ if (status != H_OK)
+ {
+ /* TODO (#1#): Handle error */
+ hresponse_free(res);
+ return NULL;
+ }
+ else
+ {
+ res->attachments = mimeMessage;
+ res->in = http_input_stream_new_from_file(mimeMessage->root_part->filename);
+ }
+ }
+
+ return res;
+}
+
+
+
+void
+hresponse_free(hresponse_t * res)
+{
+ if (res == NULL)
+ return;
+
+ if (res->header)
+ hpairnode_free_deep(res->header);
+
+ if (res->in)
+ http_input_stream_free(res->in);
+
+ if (res->content_type)
+ content_type_free(res->content_type);
+
+ free(res);
+}
+
diff --git a/nanohttp/nanohttp-response.h b/nanohttp/nanohttp-response.h
new file mode 100755
index 0000000..7607eb7
--- /dev/null
+++ b/nanohttp/nanohttp-response.h
@@ -0,0 +1,57 @@
+/******************************************************************
+ * $Id: nanohttp-response.h,v 1.1 2004/10/15 13:30:42 snowdrop Exp $
+ *
+ * CSOAP Project: A http client/server library in C
+ * Copyright (C) 2003-2004 Ferhat Ayaz
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Email: ferhatayaz@yahoo.com
+ ******************************************************************/
+#ifndef NANO_HTTP_RESPONSE_H
+#define NANO_HTTP_RESPONSE_H
+
+#include <nanohttp/nanohttp-stream.h>
+#include <nanohttp/nanohttp-common.h>
+#include <nanohttp/nanohttp-mime.h>
+
+/* response object */
+typedef struct hresponse
+{
+ http_version_t version;
+ int errcode;
+ char desc[RESPONSE_MAX_DESC_SIZE];
+
+ hpair_t *header;
+
+ http_input_stream_t *in;
+ content_type_t *content_type;
+ attachments_t *attachments;
+ char root_part_id[150];
+}hresponse_t;
+
+hresponse_t *hresponse_new_from_socket(hsocket_t sock);
+void hresponse_free(hresponse_t *res);
+
+
+
+#endif
+
+
+
+
+
+
diff --git a/nanohttp/todo.txt b/nanohttp/todo.txt
new file mode 100755
index 0000000..3cf9981
--- /dev/null
+++ b/nanohttp/todo.txt
@@ -0,0 +1,19 @@
+
+------------------------------------------------------------
+ERROR HANDLING !!!!
+------------------------------------------------------------
+
+Merge
+
+
+mime_message_t *
+mime_message_parse(http_input_stream_t *in,
+ const char* root_id, const char* boundary,
+ const char* dest_dir);
+
+and try to optimize mime API
+
+------------------------------------------------------------
+check socket API again
+
+