[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[GNUnet-SVN] r5422 - in libmicrohttpd: . src/daemon src/include
From: |
gnunet |
Subject: |
[GNUnet-SVN] r5422 - in libmicrohttpd: . src/daemon src/include |
Date: |
Wed, 8 Aug 2007 02:07:59 -0600 (MDT) |
Author: grothoff
Date: 2007-08-08 02:07:49 -0600 (Wed, 08 Aug 2007)
New Revision: 5422
Added:
libmicrohttpd/src/daemon/memorypool.c
libmicrohttpd/src/daemon/memorypool.h
Modified:
libmicrohttpd/ChangeLog
libmicrohttpd/README
libmicrohttpd/src/daemon/Makefile.am
libmicrohttpd/src/daemon/connection.c
libmicrohttpd/src/daemon/daemon.c
libmicrohttpd/src/daemon/daemontest_post.c
libmicrohttpd/src/daemon/daemontest_put.c
libmicrohttpd/src/daemon/internal.h
libmicrohttpd/src/include/microhttpd.h
Log:
updates
Modified: libmicrohttpd/ChangeLog
===================================================================
--- libmicrohttpd/ChangeLog 2007-08-07 15:57:09 UTC (rev 5421)
+++ libmicrohttpd/ChangeLog 2007-08-08 08:07:49 UTC (rev 5422)
@@ -1,2 +1,6 @@
+Wed Aug 8 01:46:06 MDT 2007
+ Added pool allocation and connection limitations (total
+ number and memory size).
+
Tue Jan 9 20:52:48 MST 2007
Created project build files and updated API. - CG
Modified: libmicrohttpd/README
===================================================================
--- libmicrohttpd/README 2007-08-07 15:57:09 UTC (rev 5421)
+++ libmicrohttpd/README 2007-08-08 08:07:49 UTC (rev 5422)
@@ -1,46 +1,34 @@
-Run "autoreconf -f -i" to create configure.
+Run "autoreconf -fi" to create configure.
-This is still pre-alpha software. The following
-things need to be implemented (in list of importance)
-before certain features can be used at all:
+This is still pre-alpha software. The following things should be
+implemented (in order of importance) before we can claim to be
+reasonably complete:
-For POST:
-=========
-- Decoding of POST data, testing thereof
-- POST testcase currently fails (blocks!)
-
-For http-compliance:
-====================
-session.c:
+For http/1.1-compliance:
+========================
+connection.c:
+- support responding immediately with "100 CONTINUE" (http 1.1)!
- send proper error code back if headers are too long
- (investigate what we should do with those headers,
- read? give user control?)
- ALSO: should this limit be per-line or for the
- entire header? (currently, we enforce per-line,
- but the entire header might make more sense!)
-- http 1.0 compatibility (if 1.0, force connection
- close at the end!)
+ (currently, we just close the connection)
+- support chunked requests from clients
+- send proper error code back if client forgot the "Host" header (?)
+- automatically add MHD_HTTP_HEADER_DATE if client "forgot" to add one (?)
+- automatically drop body from responses to "HEAD" requests?
-For IPv6:
+For POST:
=========
-daemon.c:
-- fix start daemon and accept handlers
+- find better way to handle POST data that does not fit into memory
+- add support to decode multipart/form-data
-
For SSL:
========
microhttpd.h:
- define appropriate MHD_OPTIONs
- actual implementation
-
-Other:
-======
-- allow client to control size of input/output
- buffers (add MHD_OPTION)
-- allow client to limit total number of connections
- (add MHD_OPTION)
-
-
-
+Missing Testcases:
+==================
+- add testcases for http/1.1 pipelining (need
+ to figure out how to ensure curl pipelines)
+- add testcases for resource limit enforcement
Modified: libmicrohttpd/src/daemon/Makefile.am
===================================================================
--- libmicrohttpd/src/daemon/Makefile.am 2007-08-07 15:57:09 UTC (rev
5421)
+++ libmicrohttpd/src/daemon/Makefile.am 2007-08-08 08:07:49 UTC (rev
5422)
@@ -11,6 +11,7 @@
connection.c connection.h \
daemon.c \
internal.c internal.h \
+ memorypool.c memorypool.h \
plibc.h \
response.c response.h
@@ -31,7 +32,9 @@
daemontest \
daemontest_get \
daemontest_post \
- daemontest_put
+ daemontest_put \
+ daemontest_post11 \
+ daemontest_put11
TESTS = $(check_PROGRAMS)
@@ -46,18 +49,29 @@
$(top_builddir)/src/daemon/libmicrohttpd.la \
@LIBCURL@
-
daemontest_post_SOURCES = \
daemontest_post.c
daemontest_post_LDADD = \
$(top_builddir)/src/daemon/libmicrohttpd.la \
@LIBCURL@
-
daemontest_put_SOURCES = \
daemontest_put.c
daemontest_put_LDADD = \
$(top_builddir)/src/daemon/libmicrohttpd.la \
@LIBCURL@
+daemontest_post11_SOURCES = \
+ daemontest_post.c
+daemontest_post11_LDADD = \
+ $(top_builddir)/src/daemon/libmicrohttpd.la \
+ @LIBCURL@
+
+
+daemontest_put11_SOURCES = \
+ daemontest_put.c
+daemontest_put11_LDADD = \
+ $(top_builddir)/src/daemon/libmicrohttpd.la \
+ @LIBCURL@
+
endif
\ No newline at end of file
Modified: libmicrohttpd/src/daemon/connection.c
===================================================================
--- libmicrohttpd/src/daemon/connection.c 2007-08-07 15:57:09 UTC (rev
5421)
+++ libmicrohttpd/src/daemon/connection.c 2007-08-08 08:07:49 UTC (rev
5422)
@@ -27,9 +27,15 @@
#include "internal.h"
#include "connection.h"
+#include "memorypool.h"
#include "response.h"
+/**
+ * Size by which MHD usually tries to increment read/write buffers.
+ */
+#define MHD_BUF_INC_SIZE 2048
+
/**
* Get all of the headers from the request.
*
@@ -40,9 +46,9 @@
*/
int
MHD_get_connection_values(struct MHD_Connection * connection,
- enum MHD_ValueKind kind,
- MHD_KeyValueIterator iterator,
- void * iterator_cls) {
+ enum MHD_ValueKind kind,
+ MHD_KeyValueIterator iterator,
+ void * iterator_cls) {
int ret;
struct MHD_HTTP_Header * pos;
@@ -131,41 +137,77 @@
fd_set * except_fd_set,
int * max_fd) {
int fd;
+ void * buf;
fd = connection->socket_fd;
if (fd == -1)
return MHD_YES;
if ( (connection->read_close == 0) &&
( (connection->headersReceived == 0) ||
- (connection->readLoc < connection->read_buffer_size) ) )
+ (connection->readLoc < connection->read_buffer_size) ) ) {
FD_SET(fd, read_fd_set);
- if (connection->response != NULL)
+ if (fd > *max_fd)
+ *max_fd = fd;
+ } else {
+
+
+ if ( (connection->read_close == 0) &&
+ ( (connection->headersReceived == 1) &&
+ (connection->post_processed == MHD_NO) &&
+ (connection->readLoc == connection->read_buffer_size) ) ) {
+ /* try growing the read buffer, just in case */
+ buf = MHD_pool_reallocate(connection->pool,
+ connection->read_buffer,
+ connection->read_buffer_size,
+ connection->read_buffer_size * 2 +
MHD_BUF_INC_SIZE);
+ if (buf != NULL) {
+ /* we can actually grow the buffer, do it! */
+ connection->read_buffer = buf;
+ connection->read_buffer_size = connection->read_buffer_size * 2 +
MHD_BUF_INC_SIZE;
+ FD_SET(fd, read_fd_set);
+ if (fd > *max_fd)
+ *max_fd = fd;
+ }
+ }
+ }
+ if (connection->response != NULL) {
FD_SET(fd, write_fd_set);
- if ( (fd > *max_fd) &&
- ( (connection->headersReceived == 0) ||
- (connection->readLoc < connection->read_buffer_size) ||
- (connection->response != NULL) ) )
- *max_fd = fd;
+ if (fd > *max_fd)
+ *max_fd = fd;
+ }
return MHD_YES;
}
/**
- * Parse a single line of the HTTP header. Remove it
- * from the read buffer. If the current line does not
+ * We ran out of memory processing the
+ * header. Handle it properly.
+ */
+static void
+MHD_excessive_header_handler(struct MHD_Connection * connection) {
+ /* die, header far too long to be reasonable;
+ FIXME: send proper response to client
+ (stop reading, queue proper response) */
+ MHD_DLOG(connection->daemon,
+ "Received excessively long header line, closing connection.\n");
+ CLOSE(connection->socket_fd);
+ connection->socket_fd = -1;
+}
+
+/**
+ * Parse a single line of the HTTP header. Advance
+ * read_buffer (!) appropriately. If the current line does not
* fit, consider growing the buffer. If the line is
* far too long, close the connection. If no line is
* found (incomplete, buffer too small, line too long),
- * return NULL. Otherwise return a copy of the line.
+ * return NULL. Otherwise return a pointer to the line.
*/
static char *
MHD_get_next_header_line(struct MHD_Connection * connection) {
char * rbuf;
size_t pos;
- size_t start;
if (connection->readLoc == 0)
return NULL;
- start = 0;
pos = 0;
rbuf = connection->read_buffer;
while ( (pos < connection->readLoc - 1) &&
@@ -175,56 +217,55 @@
if (pos == connection->readLoc - 1) {
/* not found, consider growing... */
if (connection->readLoc == connection->read_buffer_size) {
- /* grow buffer to read larger header or die... */
- if (connection->read_buffer_size < 4 * MHD_MAX_BUF_SIZE) {
- rbuf = malloc(connection->read_buffer_size * 2);
- memcpy(rbuf,
- connection->read_buffer,
- connection->readLoc);
- free(connection->read_buffer);
+ rbuf = MHD_pool_reallocate(connection->pool,
+ connection->read_buffer,
+ connection->read_buffer_size,
+ connection->read_buffer_size * 2 +
MHD_BUF_INC_SIZE);
+ if (rbuf == NULL) {
+ MHD_excessive_header_handler(connection);
+ } else {
+ connection->read_buffer_size = connection->read_buffer_size * 2 +
MHD_BUF_INC_SIZE;
connection->read_buffer = rbuf;
- connection->read_buffer_size *= 2;
- } else {
- /* die, header far too long to be reasonable */
- MHD_DLOG(connection->daemon,
- "Received excessively long header line (>%u), closing
connection.\n",
- 4 * MHD_MAX_BUF_SIZE);
- CLOSE(connection->socket_fd);
- connection->socket_fd = -1;
}
}
return NULL;
}
/* found, check if we have proper CRLF */
- rbuf = malloc(pos + 1);
- memcpy(rbuf,
- connection->read_buffer,
- pos);
- rbuf[pos] = '\0';
- if ( (connection->read_buffer[pos] == '\r') &&
- (connection->read_buffer[pos+1] == '\n') )
- pos++; /* skip both r and n */
- pos++;
- memmove(connection->read_buffer,
- &connection->read_buffer[pos],
- connection->readLoc - pos);
+ if ( (rbuf[pos] == '\r') &&
+ (rbuf[pos+1] == '\n') )
+ rbuf[pos++] = '\0'; /* skip both r and n */
+ rbuf[pos++] = '\0';
+ connection->read_buffer += pos;
+ connection->read_buffer_size -= pos;
connection->readLoc -= pos;
return rbuf;
}
-static void
+/**
+ * @return MHD_NO on failure (out of memory), MHD_YES for success
+ */
+static int
MHD_connection_add_header(struct MHD_Connection * connection,
- const char * key,
- const char * value,
- enum MHD_ValueKind kind) {
+ char * key,
+ char * value,
+ enum MHD_ValueKind kind) {
struct MHD_HTTP_Header * hdr;
- hdr = malloc(sizeof(struct MHD_HTTP_Header));
+ hdr = MHD_pool_allocate(connection->pool,
+ sizeof(struct MHD_HTTP_Header),
+ MHD_YES);
+ if (hdr == NULL) {
+ MHD_DLOG(connection->daemon,
+ "Not enough memory to allocate header record!\n");
+ MHD_excessive_header_handler(connection);
+ return MHD_NO;
+ }
hdr->next = connection->headers_received;
- hdr->header = strdup(key);
- hdr->value = strdup(value);
+ hdr->header = key;
+ hdr->value = value;
hdr->kind = kind;
connection->headers_received = hdr;
+ return MHD_YES;
}
/**
@@ -253,7 +294,10 @@
}
}
-static void
+/**
+ * @return MHD_NO on failure (out of memory), MHD_YES for success
+ */
+static int
parse_arguments(enum MHD_ValueKind kind,
struct MHD_Connection * connection,
char * args) {
@@ -263,7 +307,7 @@
while (args != NULL) {
equals = strstr(args, "=");
if (equals == NULL)
- return; /* invalid, ignore */
+ return MHD_NO; /* invalid, ignore */
equals[0] = '\0';
equals++;
amper = strstr(equals, "&");
@@ -273,18 +317,22 @@
}
MHD_http_unescape(args);
MHD_http_unescape(equals);
- MHD_connection_add_header(connection,
- args,
- equals,
- kind);
+ if (MHD_NO == MHD_connection_add_header(connection,
+ args,
+ equals,
+ kind))
+ return MHD_NO;
args = amper;
}
+ return MHD_YES;
}
/**
* Parse the cookie header (see RFC 2109).
+ *
+ * @return MHD_YES for success, MHD_NO for failure (malformed, out of memory)
*/
-static void
+static int
MHD_parse_cookie_header(struct MHD_Connection * connection) {
const char * hdr;
char * cpy;
@@ -294,11 +342,22 @@
int quotes;
hdr = MHD_lookup_connection_value(connection,
- MHD_HEADER_KIND,
- "Cookie");
+ MHD_HEADER_KIND,
+ "Cookie");
if (hdr == NULL)
- return;
- cpy = strdup(hdr);
+ return MHD_YES;
+ cpy = MHD_pool_allocate(connection->pool,
+ strlen(hdr)+1,
+ MHD_YES);
+ if (cpy == NULL) {
+ MHD_DLOG(connection->daemon,
+ "Not enough memory to parse cookies!\n");
+ MHD_excessive_header_handler(connection);
+ return MHD_NO;
+ }
+ memcpy(cpy,
+ hdr,
+ strlen(hdr)+1);
pos = cpy;
while (pos != NULL) {
equals = strstr(pos, "=");
@@ -328,13 +387,14 @@
equals[strlen(equals)-1] = '\0';
equals++;
}
- MHD_connection_add_header(connection,
- pos,
- equals,
- MHD_COOKIE_KIND);
+ if (MHD_NO == MHD_connection_add_header(connection,
+ pos,
+ equals,
+ MHD_COOKIE_KIND))
+ return MHD_NO;
pos = semicolon;
}
- free(cpy);
+ return MHD_YES;
}
/**
@@ -355,7 +415,7 @@
if (uri == NULL)
return MHD_NO; /* serious error */
uri[0] = '\0';
- connection->method = strdup(line);
+ connection->method = line;
uri++;
while (uri[0] == ' ')
uri++;
@@ -372,11 +432,11 @@
connection,
args);
}
- connection->url = strdup(uri);
+ connection->url = uri;
if (httpVersion == NULL)
- connection->version = strdup("");
+ connection->version = "";
else
- connection->version = strdup(httpVersion);
+ connection->version = httpVersion;
return MHD_YES;
}
@@ -398,6 +458,7 @@
char * colon;
char * tmp;
const char * clen;
+ const char * end;
unsigned long long cval;
if (connection->bodyReceived == 1)
@@ -409,51 +470,38 @@
(line[0] == '\t') ) {
/* value was continued on the next line, see
http://www.jmarshall.com/easy/http/ */
- if ( (strlen(line) + strlen(last) >
- 4 * MHD_MAX_BUF_SIZE) ) {
- free(line);
- free(last);
- last = NULL;
- MHD_DLOG(connection->daemon,
- "Received excessively long header line (>%u), closing
connection.\n",
- 4 * MHD_MAX_BUF_SIZE);
- CLOSE(connection->socket_fd);
- connection->socket_fd = -1;
+ last = MHD_pool_reallocate(connection->pool,
+ last,
+ strlen(last)+1,
+ strlen(line) + strlen(last) + 1);
+ if (last == NULL) {
+ MHD_excessive_header_handler(connection);
break;
}
- tmp = malloc(strlen(line) + strlen(last) + 1);
- strcpy(tmp, last);
- free(last);
- last = tmp;
tmp = line;
while ( (tmp[0] == ' ') ||
(tmp[0] == '\t') )
tmp++; /* skip whitespace at start of 2nd line */
- strcat(last, tmp);
- free(line);
+ strcat(last, tmp);
continue; /* possibly more than 2 lines... */
} else {
- MHD_connection_add_header(connection,
- last,
- colon,
- MHD_HEADER_KIND);
- free(last);
+ if (MHD_NO == MHD_connection_add_header(connection,
+ last,
+ colon,
+ MHD_HEADER_KIND))
+ return;
last = NULL;
}
}
if (connection->url == NULL) {
/* line must be request line (first line of header) */
if (MHD_NO == parse_initial_message_line(connection,
- line)) {
- free(line);
- goto DIE;
- }
- free(line);
+ line))
+ goto DIE;
continue;
}
/* check if this is the end of the header */
if (strlen(line) == 0) {
- free(line);
/* end of header */
connection->headersReceived = 1;
clen = MHD_lookup_connection_value(connection,
@@ -483,6 +531,17 @@
connection->bodyReceived = 0;
}
}
+ end = MHD_lookup_connection_value(connection,
+ MHD_HEADER_KIND,
+ MHD_HTTP_HEADER_CONNECTION);
+ if ( (end != NULL) &&
+ (0 == strcasecmp(end,
+ "close")) ) {
+ /* other side explicitly requested
+ that we close the connection after
+ this request */
+ connection->read_close = MHD_YES;
+ }
break;
}
/* line should be normal header line, find colon */
@@ -507,13 +566,12 @@
with a space...) */
last = line;
}
- if (last != NULL) {
- MHD_connection_add_header(connection,
- last,
- colon,
- MHD_HEADER_KIND);
- free(last);
- }
+ if ( (last != NULL) &&
+ (MHD_NO == MHD_connection_add_header(connection,
+ last,
+ colon,
+ MHD_HEADER_KIND)) )
+ return; /* error */
MHD_parse_cookie_header(connection);
return;
DIE:
@@ -540,6 +598,103 @@
}
/**
+ * Test if we are able to process the POST data.
+ * This depends on available memory (enough to load
+ * all of the POST data into the pool) and the
+ * content encoding of the POST data. And of course,
+ * this requires that the request is actually a
+ * POST request.
+ *
+ * @return MHD_YES if so
+ */
+static int
+MHD_test_post_data(struct MHD_Connection * connection) {
+ const char * encoding;
+ void * buf;
+
+ if (0 != strcasecmp(connection->method,
+ MHD_HTTP_METHOD_POST))
+ return MHD_NO;
+ encoding = MHD_lookup_connection_value(connection,
+ MHD_HEADER_KIND,
+ MHD_HTTP_HEADER_CONTENT_TYPE);
+ if (encoding == NULL)
+ return MHD_NO;
+ if ( (0 == strcasecmp(MHD_HTTP_POST_ENCODING_FORM_URLENCODED,
+ encoding)) &&
+ (connection->uploadSize != -1) ) {
+ buf = MHD_pool_reallocate(connection->pool,
+ connection->read_buffer,
+ connection->read_buffer_size,
+ connection->uploadSize + 1);
+ if (buf == NULL)
+ return MHD_NO;
+ connection->read_buffer_size = connection->uploadSize + 1;
+ connection->read_buffer = buf;
+ return MHD_YES;
+ }
+ return MHD_NO;
+}
+
+/**
+ * Process the POST data here (adding to headers).
+ *
+ * Needs to first check POST encoding and then do
+ * the right thing (TM). The POST data is in the
+ * connection's post_data buffer between the postPos
+ * and postLoc offsets. The POST message maybe
+ * incomplete. The existing buffer (allocated from
+ * the pool) can be used and modified but must then
+ * be properly removed from the struct.
+ *
+ * @return MHD_YES on success, MHD_NO on error (i.e. out of
+ * memory).
+ */
+static int
+MHD_parse_post_data(struct MHD_Connection * connection) {
+ const char * encoding;
+ int ret;
+
+ encoding = MHD_lookup_connection_value(connection,
+ MHD_HEADER_KIND,
+ MHD_HTTP_HEADER_CONTENT_TYPE);
+ if (encoding == NULL)
+ return MHD_NO;
+ if (0 == strcasecmp(MHD_HTTP_POST_ENCODING_FORM_URLENCODED,
+ encoding)) {
+ ret = parse_arguments(MHD_POSTDATA_KIND,
+ connection,
+ connection->read_buffer);
+ /* invalidate read buffer for other uses --
+ in particular, do not give it to the
+ client; if this were to be needed, we would
+ have to make a copy, which would double memory
+ requirements */
+ connection->read_buffer_size = 0;
+ connection->readLoc = 0;
+ connection->uploadSize = 0;
+ connection->read_buffer = NULL;
+ return ret;
+ }
+ if (0 == strcasecmp(MHD_HTTP_POST_ENCODING_MULTIPART_FORMDATA,
+ encoding)) {
+ /* this code should never been reached right now,
+ since the test_post_data function would already
+ return MHD_NO; code is here only for future
+ extensions... */
+ /* see http://www.w3.org/TR/html4/interact/forms.html#h-17.13.4 */
+ MHD_DLOG(connection->daemon,
+ "Unsupported multipart encoding of POST data specified, not
processing POST data.\n");
+ return MHD_NO;
+ }
+ /* this should never be reached, just here for
+ error checking */
+ MHD_DLOG(connection->daemon,
+ "Unknown encoding of POST data specified, not processing POST
data.\n");
+ return MHD_NO;
+}
+
+/**
* Call the handler of the application for this
* connection.
*/
@@ -552,9 +707,6 @@
abort(); /* bad timing... */
ah = MHD_find_access_handler(connection);
processed = connection->readLoc;
- /* FIXME: in case of POST, we need to
- process the POST data here as well
- (adding to the header list! */
if (MHD_NO == ah->dh(ah->dh_cls,
connection,
connection->url,
@@ -564,7 +716,7 @@
&processed)) {
/* serios internal error, close connection */
MHD_DLOG(connection->daemon,
- "Internal application error, closing connection.");
+ "Internal application error, closing connection.\n");
CLOSE(connection->socket_fd);
connection->socket_fd = -1;
return;
@@ -583,7 +735,6 @@
connection->bodyReceived = 1;
connection->readLoc = 0;
connection->read_buffer_size = 0;
- free(connection->read_buffer);
connection->read_buffer = NULL;
}
}
@@ -600,17 +751,30 @@
int bytes_read;
void * tmp;
+ if (connection->pool == NULL)
+ connection->pool = MHD_pool_create(connection->daemon->pool_size);
+ if (connection->pool == NULL) {
+ MHD_DLOG(connection->daemon,
+ "Failed to create memory pool!\n");
+ CLOSE(connection->socket_fd);
+ connection->socket_fd = -1;
+ return MHD_NO;
+ }
if ( (connection->readLoc >= connection->read_buffer_size) &&
(connection->headersReceived == 0) ) {
/* need to grow read buffer */
- tmp = malloc(connection->read_buffer_size * 2 + MHD_MAX_BUF_SIZE);
- memcpy(tmp,
- connection->read_buffer,
- connection->read_buffer_size);
- connection->read_buffer_size = connection->read_buffer_size * 2 +
MHD_MAX_BUF_SIZE;
- if (connection->read_buffer != NULL)
- free(connection->read_buffer);
+ tmp = MHD_pool_reallocate(connection->pool,
+ connection->read_buffer,
+ connection->read_buffer_size,
+ connection->read_buffer_size * 2 +
MHD_BUF_INC_SIZE);
+ if (tmp == NULL) {
+ MHD_DLOG(connection->daemon,
+ "Not enough memory for reading headers!\n");
+ MHD_excessive_header_handler(connection);
+ return MHD_NO;
+ }
connection->read_buffer = tmp;
+ connection->read_buffer_size = connection->read_buffer_size * 2 +
MHD_BUF_INC_SIZE;
}
if (connection->readLoc >= connection->read_buffer_size) {
MHD_DLOG(connection->daemon,
@@ -634,16 +798,28 @@
}
if (bytes_read == 0) {
/* other side closed connection */
+ connection->read_close = MHD_YES;
if (connection->readLoc > 0)
MHD_call_connection_handler(connection);
shutdown(connection->socket_fd, SHUT_RD);
return MHD_YES;
}
connection->readLoc += bytes_read;
- if (connection->headersReceived == 0)
+ if (connection->headersReceived == 0) {
MHD_parse_connection_headers(connection);
- if (connection->headersReceived == 1)
- MHD_call_connection_handler(connection);
+ if (connection->headersReceived == 1) {
+ connection->post_processed = MHD_test_post_data(connection);
+ }
+ }
+ if (connection->headersReceived == 1) {
+ if ( (connection->post_processed == MHD_YES) &&
+ (connection->uploadSize == connection->readLoc) )
+ if (MHD_NO == MHD_parse_post_data(connection))
+ connection->post_processed = MHD_NO;
+ if ( (connection->post_processed == MHD_NO) ||
+ (connection->read_buffer_size == connection->readLoc) )
+ MHD_call_connection_handler(connection);
+ }
return MHD_YES;
}
@@ -666,9 +842,9 @@
} else if (NULL == MHD_get_response_header(connection->response,
MHD_HTTP_HEADER_CONTENT_LENGTH)) {
_REAL_SNPRINTF(buf,
- 128,
- "%llu",
- (unsigned long long) connection->response->total_size);
+ 128,
+ "%llu",
+ (unsigned long long) connection->response->total_size);
MHD_add_response_header(connection->response,
MHD_HTTP_HEADER_CONTENT_LENGTH,
buf);
@@ -680,7 +856,7 @@
* fill it with all of the headers from the
* HTTPd's response.
*/
-static void
+static int
MHD_build_header_response(struct MHD_Connection * connection) {
size_t size;
size_t off;
@@ -702,7 +878,14 @@
pos = pos->next;
}
/* produce data */
- data = malloc(size + 1);
+ data = MHD_pool_allocate(connection->pool,
+ size + 1,
+ MHD_YES);
+ if (data == NULL) {
+ MHD_DLOG(connection->daemon,
+ "Not enough memory for write!\n");
+ return MHD_NO;
+ }
memcpy(data,
code,
off);
@@ -721,7 +904,10 @@
if (off != size)
abort();
connection->write_buffer = data;
- connection->write_buffer_size = size;
+ connection->writeLoc = size;
+ connection->writePos = 0;
+ connection->write_buffer_size = size + 1;
+ return MHD_YES;
}
/**
@@ -743,11 +929,16 @@
return MHD_NO;
}
if (! connection->headersSent) {
- if (connection->write_buffer == NULL)
- MHD_build_header_response(connection);
+ if ( (connection->write_buffer == NULL) &&
+ (MHD_NO == MHD_build_header_response(connection)) ) {
+ /* oops - close! */
+ CLOSE(connection->socket_fd);
+ connection->socket_fd = -1;
+ return MHD_NO;
+ }
ret = SEND(connection->socket_fd,
- &connection->write_buffer[connection->writeLoc],
- connection->write_buffer_size - connection->writeLoc,
+ &connection->write_buffer[connection->writePos],
+ connection->writeLoc - connection->writePos,
0);
if (ret < 0) {
if (errno == EINTR)
@@ -759,13 +950,17 @@
connection->socket_fd = -1;
return MHD_YES;
}
- connection->writeLoc += ret;
- if (connection->writeLoc == connection->write_buffer_size) {
+ connection->writePos += ret;
+ if (connection->writeLoc == connection->writePos) {
connection->writeLoc = 0;
- free(connection->write_buffer);
+ connection->writePos = 0;
+ connection->headersSent = 1;
+ MHD_pool_reallocate(connection->pool,
+ connection->write_buffer,
+ connection->write_buffer_size,
+ 0);
connection->write_buffer = NULL;
connection->write_buffer_size = 0;
- connection->headersSent = 1;
}
return MHD_YES;
}
@@ -781,13 +976,13 @@
if (response->data_size == 0) {
if (response->data != NULL)
free(response->data);
- response->data = malloc(MHD_MAX_BUF_SIZE);
- response->data_size = MHD_MAX_BUF_SIZE;
+ response->data = malloc(MHD_BUF_INC_SIZE);
+ response->data_size = MHD_BUF_INC_SIZE;
}
ret = response->crc(response->crc_cls,
connection->messagePos,
response->data,
- MAX(MHD_MAX_BUF_SIZE,
+ MAX(MHD_BUF_INC_SIZE,
response->data_size - connection->messagePos));
if (ret == -1) {
/* end of message, signal other side by closing! */
@@ -838,22 +1033,26 @@
connection->headersSent = 0;
connection->bodyReceived = 0;
connection->messagePos = 0;
- free(connection->method);
connection->method = NULL;
- free(connection->url);
connection->url = NULL;
- free(connection->write_buffer);
- connection->write_buffer = NULL;
- connection->write_buffer_size = 0;
if ( (connection->read_close != 0) ||
(0 != strcasecmp(MHD_HTTP_VERSION_1_1,
connection->version)) ) {
/* closed for reading => close for good! */
- CLOSE(connection->socket_fd);
+ if (connection->socket_fd != -1)
+ CLOSE(connection->socket_fd);
connection->socket_fd = -1;
}
- free(connection->version);
connection->version = NULL;
+ connection->read_buffer = NULL;
+ connection->write_buffer = NULL;
+ connection->read_buffer_size = 0;
+ connection->readLoc = 0;
+ connection->write_buffer_size = 0;
+ connection->writePos = 0;
+ connection->writeLoc = 0;
+ MHD_pool_destroy(connection->pool);
+ connection->pool = NULL;
}
return MHD_YES;
}
Modified: libmicrohttpd/src/daemon/daemon.c
===================================================================
--- libmicrohttpd/src/daemon/daemon.c 2007-08-07 15:57:09 UTC (rev 5421)
+++ libmicrohttpd/src/daemon/daemon.c 2007-08-08 08:07:49 UTC (rev 5422)
@@ -28,9 +28,17 @@
#include "internal.h"
#include "response.h"
#include "connection.h"
+#include "memorypool.h"
-#define MHD_MAX_CONNECTIONS FD_SETSIZE -4
+/**
+ * Default connection limit.
+ */
+#define MHD_MAX_CONNECTIONS_DEFAULT FD_SETSIZE -4
+/**
+ * Default memory allowed per connection.
+ */
+#define MHD_POOL_SIZE_DEFAULT (1024 * 1024)
/**
* Register an access handler for all URIs beginning with uri_prefix.
@@ -229,8 +237,15 @@
MHD_DLOG(daemon,
"Error accepting connection: %s\n",
STRERROR(errno));
+ if (s != -1)
+ CLOSE(s); /* just in case */
return MHD_NO;
}
+ if (daemon->max_connections == 0) {
+ /* above connection limit - reject */
+ CLOSE(s);
+ return MHD_NO;
+ }
if (MHD_NO == daemon->apc(daemon->apc_cls,
addr,
addrlen)) {
@@ -241,7 +256,13 @@
memset(connection,
0,
sizeof(struct MHD_Connection));
+ connection->pool = NULL;
connection->addr = malloc(addrlen);
+ if (connection->addr == NULL) {
+ CLOSE(s);
+ free(connection);
+ return MHD_NO;
+ }
memcpy(connection->addr,
addr,
addrlen);
@@ -258,11 +279,13 @@
STRERROR(errno));
free(connection->addr);
CLOSE(s);
+ free(connection->addr);
free(connection);
return MHD_NO;
}
connection->next = daemon->connections;
daemon->connections = connection;
+ daemon->max_connections--;
return MHD_YES;
}
@@ -281,7 +304,6 @@
MHD_cleanup_connections(struct MHD_Daemon * daemon) {
struct MHD_Connection * pos;
struct MHD_Connection * prev;
- struct MHD_HTTP_Header * hpos;
void * unused;
pos = daemon->connections;
@@ -296,25 +318,12 @@
pthread_kill(pos->pid, SIGALRM);
pthread_join(pos->pid, &unused);
}
- free(pos->addr);
- if (pos->url != NULL)
- free(pos->url);
- if (pos->method != NULL)
- free(pos->method);
- if (pos->write_buffer != NULL)
- free(pos->write_buffer);
- if (pos->read_buffer != NULL)
- free(pos->read_buffer);
- while (pos->headers_received != NULL) {
- hpos = pos->headers_received;
- pos->headers_received = hpos->next;
- free(hpos->header);
- free(hpos->value);
- free(hpos);
- }
if (pos->response != NULL)
MHD_destroy_response(pos->response);
+ MHD_pool_destroy(pos->pool);
+ free(pos->addr);
free(pos);
+ daemon->max_connections++;
if (prev == NULL)
pos = daemon->connections;
else
@@ -474,6 +483,8 @@
struct sockaddr_in6 servaddr6;
const struct sockaddr * servaddr;
socklen_t addrlen;
+ va_list ap;
+ enum MHD_OPTION opt;
if ((options & MHD_USE_SSL) != 0)
return NULL;
@@ -549,6 +560,24 @@
retVal->default_handler.dh_cls = dh_cls;
retVal->default_handler.uri_prefix = "";
retVal->default_handler.next = NULL;
+ retVal->max_connections = MHD_MAX_CONNECTIONS_DEFAULT;
+ retVal->pool_size = MHD_POOL_SIZE_DEFAULT;
+ va_start(ap, dh_cls);
+ while (MHD_OPTION_END != (opt = va_arg(ap, enum MHD_OPTION))) {
+ switch (opt) {
+ case MHD_OPTION_CONNECTION_MEMORY_LIMIT:
+ retVal->pool_size = va_arg(ap, unsigned int);
+ break;
+ case MHD_OPTION_CONNECTION_LIMIT:
+ retVal->max_connections = va_arg(ap, unsigned int);
+ break;
+ default:
+ fprintf(stderr,
+ "Invalid MHD_OPTION argument! (Did you terminate the list with
MHD_OPTION_END?)\n");
+ abort();
+ }
+ }
+ va_end(ap);
if ( ( (0 != (options & MHD_USE_THREAD_PER_CONNECTION)) ||
(0 != (options & MHD_USE_SELECT_INTERNALLY)) ) &&
(0 != pthread_create(&retVal->pid,
Modified: libmicrohttpd/src/daemon/daemontest_post.c
===================================================================
--- libmicrohttpd/src/daemon/daemontest_post.c 2007-08-07 15:57:09 UTC (rev
5421)
+++ libmicrohttpd/src/daemon/daemontest_post.c 2007-08-08 08:07:49 UTC (rev
5422)
@@ -39,6 +39,7 @@
#define POST_DATA "name=daniel&project=curl"
+static int oneone;
static int apc_all(void * cls,
const struct sockaddr * addr,
@@ -76,40 +77,36 @@
unsigned int * upload_data_size) {
struct MHD_Response * response;
int ret;
+ const char * r1;
+ const char * r2;
if (0 != strcmp("POST", method)) {
printf("METHOD: %s\n", method);
return MHD_NO; /* unexpected method */
}
- if ( (*upload_data_size < 24) &&
- (*upload_data_size > 0) )
- return MHD_YES; /* continue */
- if (*upload_data_size == 24) {
- *upload_data_size = 0;
- if ( (0 != strcmp("daniel",
- MHD_lookup_connection_value(connection,
- MHD_POSTDATA_KIND,
- "name"))) ||
- (0 != strcmp("curl",
- MHD_lookup_connection_value(connection,
- MHD_POSTDATA_KIND,
- "project"))) ) {
- printf("POST DATA not processed correctly!\n");
- return MHD_NO;
- }
-
- return MHD_YES; /* continue */
+ r1 = MHD_lookup_connection_value(connection,
+ MHD_POSTDATA_KIND,
+ "name");
+ r2 = MHD_lookup_connection_value(connection,
+ MHD_POSTDATA_KIND,
+ "project");
+ if ( (r1 != NULL) &&
+ (r2 != NULL) &&
+ (0 == strcmp("daniel",
+ r1)) &&
+ (0 == strcmp("curl",
+ r2)) ) {
+ response = MHD_create_response_from_data(strlen(url),
+ (void*) url,
+ MHD_NO,
+ MHD_YES);
+ ret = MHD_queue_response(connection,
+ MHD_HTTP_OK,
+ response);
+ MHD_destroy_response(response);
+ return MHD_YES; /* done */
}
- /* FIXME: check connection headers... */
- response = MHD_create_response_from_data(strlen(url),
- (void*) url,
- MHD_NO,
- MHD_YES);
- ret = MHD_queue_response(connection,
- MHD_HTTP_OK,
- response);
- MHD_destroy_response(response);
- return ret;
+ return MHD_YES;
}
@@ -118,7 +115,7 @@
CURL * c;
char buf[2048];
struct CBC cbc;
-
+
cbc.buf = buf;
cbc.size = 2048;
cbc.pos = 0;
@@ -156,10 +153,15 @@
curl_easy_setopt(c,
CURLOPT_TIMEOUT,
2L);
+ if (oneone)
+ curl_easy_setopt(c,
+ CURLOPT_HTTP_VERSION,
+ CURL_HTTP_VERSION_1_1);
+ else
+ curl_easy_setopt(c,
+ CURLOPT_HTTP_VERSION,
+ CURL_HTTP_VERSION_1_0);
curl_easy_setopt(c,
- CURLOPT_HTTP_VERSION,
- CURL_HTTP_VERSION_1_0);
- curl_easy_setopt(c,
CURLOPT_CONNECTTIMEOUT,
2L);
// NOTE: use of CONNECTTIMEOUT without also
@@ -233,10 +235,15 @@
curl_easy_setopt(c,
CURLOPT_TIMEOUT,
2L);
+ if (oneone)
+ curl_easy_setopt(c,
+ CURLOPT_HTTP_VERSION,
+ CURL_HTTP_VERSION_1_1);
+ else
+ curl_easy_setopt(c,
+ CURLOPT_HTTP_VERSION,
+ CURL_HTTP_VERSION_1_0);
curl_easy_setopt(c,
- CURLOPT_HTTP_VERSION,
- CURL_HTTP_VERSION_1_0);
- curl_easy_setopt(c,
CURLOPT_CONNECTTIMEOUT,
2L);
// NOTE: use of CONNECTTIMEOUT without also
@@ -321,10 +328,15 @@
curl_easy_setopt(c,
CURLOPT_TIMEOUT,
5L);
+ if (oneone)
+ curl_easy_setopt(c,
+ CURLOPT_HTTP_VERSION,
+ CURL_HTTP_VERSION_1_1);
+ else
+ curl_easy_setopt(c,
+ CURLOPT_HTTP_VERSION,
+ CURL_HTTP_VERSION_1_0);
curl_easy_setopt(c,
- CURLOPT_HTTP_VERSION,
- CURL_HTTP_VERSION_1_0);
- curl_easy_setopt(c,
CURLOPT_CONNECTTIMEOUT,
5L);
// NOTE: use of CONNECTTIMEOUT without also
@@ -429,11 +441,12 @@
char * const * argv) {
unsigned int errorCount = 0;
+ oneone = NULL != strstr(argv[0], "11");
if (0 != curl_global_init(CURL_GLOBAL_WIN32))
return 2;
errorCount += testInternalPost();
errorCount += testMultithreadedPost();
- errorCount += testExternalPost();
+ errorCount += testExternalPost();
if (errorCount != 0)
fprintf(stderr,
"Error (code: %u)\n",
Modified: libmicrohttpd/src/daemon/daemontest_put.c
===================================================================
--- libmicrohttpd/src/daemon/daemontest_put.c 2007-08-07 15:57:09 UTC (rev
5421)
+++ libmicrohttpd/src/daemon/daemontest_put.c 2007-08-08 08:07:49 UTC (rev
5422)
@@ -32,6 +32,8 @@
#include <string.h>
#include <time.h>
+static int oneone;
+
static int apc_all(void * cls,
const struct sockaddr * addr,
socklen_t addrlen) {
@@ -164,10 +166,15 @@
curl_easy_setopt(c,
CURLOPT_TIMEOUT,
15L);
+ if (oneone)
+ curl_easy_setopt(c,
+ CURLOPT_HTTP_VERSION,
+ CURL_HTTP_VERSION_1_1);
+ else
+ curl_easy_setopt(c,
+ CURLOPT_HTTP_VERSION,
+ CURL_HTTP_VERSION_1_0);
curl_easy_setopt(c,
- CURLOPT_HTTP_VERSION,
- CURL_HTTP_VERSION_1_0);
- curl_easy_setopt(c,
CURLOPT_CONNECTTIMEOUT,
15L);
// NOTE: use of CONNECTTIMEOUT without also
@@ -246,10 +253,15 @@
curl_easy_setopt(c,
CURLOPT_TIMEOUT,
15L);
+ if (oneone)
+ curl_easy_setopt(c,
+ CURLOPT_HTTP_VERSION,
+ CURL_HTTP_VERSION_1_1);
+ else
+ curl_easy_setopt(c,
+ CURLOPT_HTTP_VERSION,
+ CURL_HTTP_VERSION_1_0);
curl_easy_setopt(c,
- CURLOPT_HTTP_VERSION,
- CURL_HTTP_VERSION_1_0);
- curl_easy_setopt(c,
CURLOPT_CONNECTTIMEOUT,
15L);
// NOTE: use of CONNECTTIMEOUT without also
@@ -339,10 +351,15 @@
curl_easy_setopt(c,
CURLOPT_TIMEOUT,
15L);
+ if (oneone)
+ curl_easy_setopt(c,
+ CURLOPT_HTTP_VERSION,
+ CURL_HTTP_VERSION_1_1);
+ else
+ curl_easy_setopt(c,
+ CURLOPT_HTTP_VERSION,
+ CURL_HTTP_VERSION_1_0);
curl_easy_setopt(c,
- CURLOPT_HTTP_VERSION,
- CURL_HTTP_VERSION_1_0);
- curl_easy_setopt(c,
CURLOPT_CONNECTTIMEOUT,
15L);
// NOTE: use of CONNECTTIMEOUT without also
@@ -447,6 +464,7 @@
char * const * argv) {
unsigned int errorCount = 0;
+ oneone = NULL != strstr(argv[0], "11");
if (0 != curl_global_init(CURL_GLOBAL_WIN32))
return 2;
errorCount += testInternalPut();
Modified: libmicrohttpd/src/daemon/internal.h
===================================================================
--- libmicrohttpd/src/daemon/internal.h 2007-08-07 15:57:09 UTC (rev 5421)
+++ libmicrohttpd/src/daemon/internal.h 2007-08-08 08:07:49 UTC (rev 5422)
@@ -37,6 +37,7 @@
#include <errno.h>
#include <fcntl.h>
#include <signal.h>
+#include <sys/mman.h>
#include "config.h"
#include "plibc.h"
@@ -49,8 +50,6 @@
#include <pthread.h>
-#define MHD_MAX_BUF_SIZE 2048
-
#define MAX(a,b) ((a)<(b)) ? (b) : (a)
@@ -157,41 +156,72 @@
struct MHD_Connection {
+
+ /**
+ * This is a linked list.
+ */
struct MHD_Connection * next;
+ /**
+ * Reference to the MHD_Daemon struct.
+ */
struct MHD_Daemon * daemon;
+ /**
+ * Linked list of parsed headers.
+ */
struct MHD_HTTP_Header * headers_received;
+ /**
+ * Response to transmit (initially NULL).
+ */
struct MHD_Response * response;
/**
- * Request method. Should be GET/POST/etc.
+ * The memory pool is created whenever we first read
+ * from the TCP stream and destroyed at the end of
+ * each request (and re-created for the next request).
+ * In the meantime, this pointer is NULL. The
+ * pool is used for all connection-related data
+ * except for the response (which maybe shared between
+ * connections) and the IP address (which persists
+ * across individual requests).
*/
+ struct MemoryPool * pool;
+
+ /**
+ * Request method. Should be GET/POST/etc. Allocated
+ * in pool.
+ */
char * method;
/**
- * Requested URL (everything after "GET" only).
+ * Requested URL (everything after "GET" only). Allocated
+ * in pool.
*/
char * url;
/**
- * HTTP version string (i.e. http/1.1)
+ * HTTP version string (i.e. http/1.1). Allocated
+ * in pool.
*/
char * version;
/**
- * Buffer for reading requests.
+ * Buffer for reading requests. Allocated
+ * in pool.
*/
char * read_buffer;
/**
- * Buffer for writing response.
+ * Buffer for writing response (headers only). Allocated
+ * in pool.
*/
char * write_buffer;
/**
- * Foreign address (of length addr_len).
+ * Foreign address (of length addr_len). MALLOCED (not
+ * in pool!).
*/
struct sockaddr_in * addr;
@@ -201,12 +231,30 @@
*/
pthread_t pid;
+ /**
+ * Size of read_buffer (in bytes).
+ */
size_t read_buffer_size;
+ /**
+ * Position where we currently append data in
+ * read_buffer (last valid position).
+ */
size_t readLoc;
+ /**
+ * Size of write_buffer (in bytes).
+ */
size_t write_buffer_size;
+ /**
+ * Offset where we are with sending from write_buffer.
+ */
+ size_t writePos;
+
+ /**
+ * Last valid location in write_buffer.
+ */
size_t writeLoc;
/**
@@ -264,6 +312,11 @@
int headersSent;
/**
+ * Are we processing the POST data?
+ */
+ int post_processed;
+
+ /**
* HTTP response code. Only valid if response object
* is already set.
*/
@@ -279,6 +332,9 @@
struct MHD_Access_Handler default_handler;
+ /**
+ * Linked list of our current connections.
+ */
struct MHD_Connection * connections;
MHD_AcceptPolicyCallback apc;
@@ -301,11 +357,24 @@
int shutdown;
/**
+ * Size of the per-connection memory pools.
+ */
+ unsigned int pool_size;
+
+ /**
+ * Limit on the number of parallel connections.
+ */
+ unsigned int max_connections;
+
+ /**
* Daemon's options.
*/
enum MHD_OPTION options;
- unsigned short port;
+ /**
+ * Listen port.
+ */
+ unsigned short port;
};
Added: libmicrohttpd/src/daemon/memorypool.c
===================================================================
--- libmicrohttpd/src/daemon/memorypool.c (rev 0)
+++ libmicrohttpd/src/daemon/memorypool.c 2007-08-08 08:07:49 UTC (rev
5422)
@@ -0,0 +1,180 @@
+/*
+ This file is part of libmicrohttpd
+ (C) 2007 Daniel Pittman
+
+ libmicrohttpd is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 2, or (at your
+ option) any later version.
+
+ libmicrohttpd 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
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with libmicrohttpd; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+/**
+ * @file memorypool.c
+ * @brief memory pool
+ * @author Christian Grothoff
+ */
+
+#include "memorypool.h"
+
+struct MemoryPool {
+
+ /**
+ * Pointer to the pool's memory
+ */
+ char * memory;
+
+ /**
+ * Size of the pool.
+ */
+ unsigned int size;
+
+ /**
+ * Offset of the first unallocated byte.
+ */
+ unsigned int pos;
+
+ /**
+ * Offset of the last unallocated byte.
+ */
+ unsigned int end;
+
+ /**
+ * 0 if pool was malloc'ed, 1 if mmapped.
+ */
+ int is_mmap;
+};
+
+/**
+ * Create a memory pool.
+ *
+ * @param max maximum size of the pool
+ */
+struct MemoryPool * MHD_pool_create(unsigned int max) {
+ struct MemoryPool * pool;
+
+ pool = malloc(sizeof(struct MemoryPool));
+ if (pool == NULL)
+ return NULL;
+ pool->memory = MMAP(NULL, max, PROT_READ | PROT_WRITE,
+ MAP_ANONYMOUS, -1, 0);
+ if ( (pool->memory == MAP_FAILED) ||
+ (pool->memory == NULL) ) {
+ pool->memory = malloc(max);
+ if (pool->memory == NULL) {
+ free(pool);
+ return NULL;
+ }
+ pool->is_mmap = 0;
+ } else {
+ pool->is_mmap = 1;
+ }
+ pool->pos = 0;
+ pool->end = max;
+ pool->size = max;
+ return pool;
+}
+
+/**
+ * Destroy a memory pool.
+ */
+void MHD_pool_destroy(struct MemoryPool * pool) {
+ if (pool == NULL)
+ return;
+ if (pool->is_mmap == 0)
+ free(pool->memory);
+ else
+ MUNMAP(pool->memory, pool->size);
+ free(pool);
+}
+
+/**
+ * Allocate size bytes from the pool.
+ * @return NULL if the pool cannot support size more
+ * bytes
+ */
+void * MHD_pool_allocate(struct MemoryPool * pool,
+ unsigned int size,
+ int from_end) {
+ void * ret;
+
+ if ( (pool->pos + size > pool->end) ||
+ (pool->pos + size < pool->pos) )
+ return NULL;
+ if (from_end == MHD_YES) {
+ ret = &pool->memory[pool->end - size];
+ pool->end -= size;
+ } else {
+ ret = &pool->memory[pool->pos];
+ pool->pos += size;
+ }
+ return ret;
+}
+
+/**
+ * Reallocate a block of memory obtained from the pool.
+ * This is particularly efficient when growing or
+ * shrinking the block that was last (re)allocated.
+ * If the given block is not the most recenlty
+ * (re)allocated block, the memory of the previous
+ * allocation may be leaked until the pool is
+ * destroyed (and copying the data maybe required).
+ *
+ * @param old the existing block
+ * @param old_size the size of the existing block
+ * @param new_size the new size of the block
+ * @return new address of the block, or
+ * NULL if the pool cannot support new_size
+ * bytes (old continues to be valid for old_size)
+ */
+void * MHD_pool_reallocate(struct MemoryPool * pool,
+ void * old,
+ unsigned int old_size,
+ unsigned int new_size) {
+ void * ret;
+
+ if ( (pool->end < old_size) ||
+ (pool->end < new_size) )
+ return NULL; /* unsatisfiable or bogus request */
+
+ if ( (pool->pos >= old_size) &&
+ (&pool->memory[pool->pos - old_size] == old) ) {
+ /* was the previous allocation - optimize! */
+ if (pool->pos + new_size - old_size <= pool->end) {
+ /* fits */
+ pool->pos += new_size - old_size;
+ if (new_size < old_size) /* shrinking - zero again! */
+ memset(&pool->memory[pool->pos],
+ 0,
+ old_size - new_size);
+ return old;
+ }
+ /* does not fit */
+ return NULL;
+ }
+ if (new_size <= old_size)
+ return old; /* cannot shrink, no need to move */
+ if ( (pool->pos + new_size >= pool->pos) &&
+ (pool->pos + new_size <= pool->end) ) {
+ /* fits */
+ ret = &pool->memory[pool->pos];
+ memcpy(ret,
+ old,
+ old_size);
+ pool->pos += new_size;
+ return ret;
+ }
+ /* does not fit */
+ return NULL;
+}
+
+/* end of memorypool.c */
Property changes on: libmicrohttpd/src/daemon/memorypool.c
___________________________________________________________________
Name: svn:eol-style
+ native
Added: libmicrohttpd/src/daemon/memorypool.h
===================================================================
--- libmicrohttpd/src/daemon/memorypool.h (rev 0)
+++ libmicrohttpd/src/daemon/memorypool.h 2007-08-08 08:07:49 UTC (rev
5422)
@@ -0,0 +1,87 @@
+/*
+ This file is part of libmicrohttpd
+ (C) 2007 Daniel Pittman
+
+ libmicrohttpd is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 2, or (at your
+ option) any later version.
+
+ libmicrohttpd 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
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with libmicrohttpd; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+/**
+ * @file memorypool.h
+ * @brief memory pool; mostly used for efficient (de)allocation
+ * for each connection and bounding memory use for each
+ * request
+ * @author Christian Grothoff
+ */
+
+#ifndef MEMORYPOOL_H
+#define MEMORYPOOL_H
+
+#include "internal.h"
+
+/**
+ * Opaque handle for a memory pool.
+ * Pools are not reentrant and must not be used
+ * by multiple threads.
+ */
+struct MemoryPool;
+
+/**
+ * Create a memory pool.
+ *
+ * @param max maximum size of the pool
+ */
+struct MemoryPool * MHD_pool_create(unsigned int max);
+
+/**
+ * Destroy a memory pool.
+ */
+void MHD_pool_destroy(struct MemoryPool * pool);
+
+/**
+ * Allocate size bytes from the pool.
+ *
+ * @param from_end allocate from end of pool (set to MHD_YES);
+ * use this for small, persistent allocations that
+ * will never be reallocated
+ * @return NULL if the pool cannot support size more
+ * bytes
+ */
+void * MHD_pool_allocate(struct MemoryPool * pool,
+ unsigned int size,
+ int from_end);
+
+/**
+ * Reallocate a block of memory obtained from the pool.
+ * This is particularly efficient when growing or
+ * shrinking the block that was last (re)allocated.
+ * If the given block is not the most recenlty
+ * (re)allocated block, the memory of the previous
+ * allocation may be leaked until the pool is
+ * destroyed (and copying the data maybe required).
+ *
+ * @param old the existing block
+ * @param old_size the size of the existing block
+ * @param new_size the new size of the block
+ * @return new address of the block, or
+ * NULL if the pool cannot support new_size
+ * bytes (old continues to be valid for old_size)
+ */
+void * MHD_pool_reallocate(struct MemoryPool * pool,
+ void * old,
+ unsigned int old_size,
+ unsigned int new_size);
+
+#endif
Property changes on: libmicrohttpd/src/daemon/memorypool.h
___________________________________________________________________
Name: svn:eol-style
+ native
Modified: libmicrohttpd/src/include/microhttpd.h
===================================================================
--- libmicrohttpd/src/include/microhttpd.h 2007-08-07 15:57:09 UTC (rev
5421)
+++ libmicrohttpd/src/include/microhttpd.h 2007-08-08 08:07:49 UTC (rev
5422)
@@ -187,7 +187,24 @@
#define MHD_HTTP_VERSION_1_0 "HTTP/1.0"
#define MHD_HTTP_VERSION_1_1 "HTTP/1.1"
+/**
+ * HTTP methods
+ */
+#define MHD_HTTP_METHOD_CONNECT "CONNECT"
+#define MHD_HTTP_METHOD_DELETE "DELETE"
+#define MHD_HTTP_METHOD_GET "GET"
+#define MHD_HTTP_METHOD_HEAD "HEAD"
+#define MHD_HTTP_METHOD_OPTIONS "OPTIONS"
+#define MHD_HTTP_METHOD_POST "POST"
+#define MHD_HTTP_METHOD_PUT "PUT"
+#define MHD_HTTP_METHOD_TRACE "TRACE"
+/**
+ * HTTP POST encodings, see also
+ * http://www.w3.org/TR/html4/interact/forms.html#h-17.13.4
+ */
+#define MHD_HTTP_POST_ENCODING_FORM_URLENCODED
"application/x-www-form-urlencoded"
+#define MHD_HTTP_POST_ENCODING_MULTIPART_FORMDATA "multipart/form-data"
/**
* Options for the MHD daemon. Note that if neither
@@ -248,9 +265,17 @@
MHD_OPTION_END = 0,
/**
- * FIXME: add options for buffer sizes here...
+ * Maximum memory size per connection (followed by an
+ * unsigned int).
*/
+ MHD_OPTION_CONNECTION_MEMORY_LIMIT = 1,
+ /**
+ * Maximum number of concurrenct connections to
+ * accept (followed by an unsigned int).
+ */
+ MHD_OPTION_CONNECTION_LIMIT = 2,
+
};
/**
@@ -265,22 +290,28 @@
MHD_RESPONSE_HEADER_KIND = 0,
/**
- * HTTP header
+ * HTTP header.
*/
MHD_HEADER_KIND = 1,
/**
- * Cookies
+ * Cookies. Note that the original HTTP header containing
+ * the cookie(s) will still be available and intact.
*/
MHD_COOKIE_KIND = 2,
/**
- * POST data
+ * POST data. This is available only if a content encoding
+ * supported by MHD is used (currently only URL encoding),
+ * and only if the posted content fits within the available
+ * memory pool. Note that in that case, the upload data
+ * given to the MHD_AccessHandlerCallback will be
+ * empty (since it has already been processed).
*/
MHD_POSTDATA_KIND = 4,
/**
- * GET (URI) arguments
+ * GET (URI) arguments.
*/
MHD_GET_ARGUMENT_KIND = 8,
@@ -326,9 +357,16 @@
* @param url the requested url
* @param method the HTTP method used ("GET", "PUT", etc.)
* @param version the HTTP version string (i.e. "HTTP/1.1")
+ * @param upload_data the data being uploaded (excluding HEADERS,
+ * for a POST that fits into memory and that is encoded
+ * with a supported encoding, the POST data will NOT be
+ * given in upload_data and is instead available as
+ * part of MHD_get_connection_values; very large POST
+ * data *will* be made available incrementally in
+ * upload_data)
* @param upload_data_size set initially to the size of the
* upload_data provided; the method must update this
- * value to the number of bytes NOT processed
+ * value to the number of bytes NOT processed;
* @return MHS_YES if the connection was handled successfully,
* MHS_NO if the socket must be closed due to a serios
* error while handling the request
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- [GNUnet-SVN] r5422 - in libmicrohttpd: . src/daemon src/include,
gnunet <=