aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2007-08-08 08:07:49 +0000
committerChristian Grothoff <christian@grothoff.org>2007-08-08 08:07:49 +0000
commit0cacf72380222e704cff8c05b329ba6bac41f631 (patch)
tree5fb26264b53a285aece3bb0912645da2275a4715
parent5b7eec5d2d858dd33aa7f65a7655de1410154f0a (diff)
downloadlibmicrohttpd-0cacf72380222e704cff8c05b329ba6bac41f631.tar.gz
libmicrohttpd-0cacf72380222e704cff8c05b329ba6bac41f631.zip
updates
-rw-r--r--ChangeLog4
-rw-r--r--README54
-rw-r--r--src/daemon/Makefile.am20
-rw-r--r--src/daemon/connection.c483
-rw-r--r--src/daemon/daemon.c65
-rw-r--r--src/daemon/daemontest_post.c91
-rw-r--r--src/daemon/daemontest_put.c36
-rw-r--r--src/daemon/internal.h87
-rw-r--r--src/daemon/memorypool.c180
-rw-r--r--src/daemon/memorypool.h87
-rw-r--r--src/include/microhttpd.h50
11 files changed, 898 insertions, 259 deletions
diff --git a/ChangeLog b/ChangeLog
index d9e63f27..ee123097 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,2 +1,6 @@
1Wed Aug 8 01:46:06 MDT 2007
2 Added pool allocation and connection limitations (total
3 number and memory size).
4
1Tue Jan 9 20:52:48 MST 2007 5Tue Jan 9 20:52:48 MST 2007
2 Created project build files and updated API. - CG 6 Created project build files and updated API. - CG
diff --git a/README b/README
index afa4467e..bb7e8a31 100644
--- a/README
+++ b/README
@@ -1,32 +1,25 @@
1Run "autoreconf -f -i" to create configure. 1Run "autoreconf -fi" to create configure.
2 2
3This is still pre-alpha software. The following 3This is still pre-alpha software. The following things should be
4things need to be implemented (in list of importance) 4implemented (in order of importance) before we can claim to be
5before certain features can be used at all: 5reasonably complete:
6 6
7 7
8For POST: 8For http/1.1-compliance:
9========= 9========================
10- Decoding of POST data, testing thereof 10connection.c:
11- POST testcase currently fails (blocks!) 11- support responding immediately with "100 CONTINUE" (http 1.1)!
12
13For http-compliance:
14====================
15session.c:
16- send proper error code back if headers are too long 12- send proper error code back if headers are too long
17 (investigate what we should do with those headers, 13 (currently, we just close the connection)
18 read? give user control?) 14- support chunked requests from clients
19 ALSO: should this limit be per-line or for the 15- send proper error code back if client forgot the "Host" header (?)
20 entire header? (currently, we enforce per-line, 16- automatically add MHD_HTTP_HEADER_DATE if client "forgot" to add one (?)
21 but the entire header might make more sense!) 17- automatically drop body from responses to "HEAD" requests?
22- http 1.0 compatibility (if 1.0, force connection
23 close at the end!)
24 18
25For IPv6: 19For POST:
26========= 20=========
27daemon.c: 21- find better way to handle POST data that does not fit into memory
28- fix start daemon and accept handlers 22- add support to decode multipart/form-data
29
30 23
31For SSL: 24For SSL:
32======== 25========
@@ -34,13 +27,8 @@ microhttpd.h:
34- define appropriate MHD_OPTIONs 27- define appropriate MHD_OPTIONs
35- actual implementation 28- actual implementation
36 29
37 30Missing Testcases:
38Other: 31==================
39====== 32- add testcases for http/1.1 pipelining (need
40- allow client to control size of input/output 33 to figure out how to ensure curl pipelines)
41 buffers (add MHD_OPTION) 34- add testcases for resource limit enforcement
42- allow client to limit total number of connections
43 (add MHD_OPTION)
44
45
46
diff --git a/src/daemon/Makefile.am b/src/daemon/Makefile.am
index 5ce824cc..e0174f40 100644
--- a/src/daemon/Makefile.am
+++ b/src/daemon/Makefile.am
@@ -11,6 +11,7 @@ libmicrohttpd_la_SOURCES = \
11 connection.c connection.h \ 11 connection.c connection.h \
12 daemon.c \ 12 daemon.c \
13 internal.c internal.h \ 13 internal.c internal.h \
14 memorypool.c memorypool.h \
14 plibc.h \ 15 plibc.h \
15 response.c response.h 16 response.c response.h
16 17
@@ -31,7 +32,9 @@ check_PROGRAMS = \
31 daemontest \ 32 daemontest \
32 daemontest_get \ 33 daemontest_get \
33 daemontest_post \ 34 daemontest_post \
34 daemontest_put 35 daemontest_put \
36 daemontest_post11 \
37 daemontest_put11
35 38
36TESTS = $(check_PROGRAMS) 39TESTS = $(check_PROGRAMS)
37 40
@@ -46,18 +49,29 @@ daemontest_get_LDADD = \
46 $(top_builddir)/src/daemon/libmicrohttpd.la \ 49 $(top_builddir)/src/daemon/libmicrohttpd.la \
47 @LIBCURL@ 50 @LIBCURL@
48 51
49
50daemontest_post_SOURCES = \ 52daemontest_post_SOURCES = \
51 daemontest_post.c 53 daemontest_post.c
52daemontest_post_LDADD = \ 54daemontest_post_LDADD = \
53 $(top_builddir)/src/daemon/libmicrohttpd.la \ 55 $(top_builddir)/src/daemon/libmicrohttpd.la \
54 @LIBCURL@ 56 @LIBCURL@
55 57
56
57daemontest_put_SOURCES = \ 58daemontest_put_SOURCES = \
58 daemontest_put.c 59 daemontest_put.c
59daemontest_put_LDADD = \ 60daemontest_put_LDADD = \
60 $(top_builddir)/src/daemon/libmicrohttpd.la \ 61 $(top_builddir)/src/daemon/libmicrohttpd.la \
61 @LIBCURL@ 62 @LIBCURL@
62 63
64daemontest_post11_SOURCES = \
65 daemontest_post.c
66daemontest_post11_LDADD = \
67 $(top_builddir)/src/daemon/libmicrohttpd.la \
68 @LIBCURL@
69
70
71daemontest_put11_SOURCES = \
72 daemontest_put.c
73daemontest_put11_LDADD = \
74 $(top_builddir)/src/daemon/libmicrohttpd.la \
75 @LIBCURL@
76
63endif \ No newline at end of file 77endif \ No newline at end of file
diff --git a/src/daemon/connection.c b/src/daemon/connection.c
index 21b7872c..bb3d8990 100644
--- a/src/daemon/connection.c
+++ b/src/daemon/connection.c
@@ -27,8 +27,14 @@
27 27
28#include "internal.h" 28#include "internal.h"
29#include "connection.h" 29#include "connection.h"
30#include "memorypool.h"
30#include "response.h" 31#include "response.h"
31 32
33/**
34 * Size by which MHD usually tries to increment read/write buffers.
35 */
36#define MHD_BUF_INC_SIZE 2048
37
32 38
33/** 39/**
34 * Get all of the headers from the request. 40 * Get all of the headers from the request.
@@ -40,9 +46,9 @@
40 */ 46 */
41int 47int
42MHD_get_connection_values(struct MHD_Connection * connection, 48MHD_get_connection_values(struct MHD_Connection * connection,
43 enum MHD_ValueKind kind, 49 enum MHD_ValueKind kind,
44 MHD_KeyValueIterator iterator, 50 MHD_KeyValueIterator iterator,
45 void * iterator_cls) { 51 void * iterator_cls) {
46 int ret; 52 int ret;
47 struct MHD_HTTP_Header * pos; 53 struct MHD_HTTP_Header * pos;
48 54
@@ -131,41 +137,77 @@ MHD_connection_get_fdset(struct MHD_Connection * connection,
131 fd_set * except_fd_set, 137 fd_set * except_fd_set,
132 int * max_fd) { 138 int * max_fd) {
133 int fd; 139 int fd;
140 void * buf;
134 141
135 fd = connection->socket_fd; 142 fd = connection->socket_fd;
136 if (fd == -1) 143 if (fd == -1)
137 return MHD_YES; 144 return MHD_YES;
138 if ( (connection->read_close == 0) && 145 if ( (connection->read_close == 0) &&
139 ( (connection->headersReceived == 0) || 146 ( (connection->headersReceived == 0) ||
140 (connection->readLoc < connection->read_buffer_size) ) ) 147 (connection->readLoc < connection->read_buffer_size) ) ) {
141 FD_SET(fd, read_fd_set); 148 FD_SET(fd, read_fd_set);
142 if (connection->response != NULL) 149 if (fd > *max_fd)
150 *max_fd = fd;
151 } else {
152
153
154 if ( (connection->read_close == 0) &&
155 ( (connection->headersReceived == 1) &&
156 (connection->post_processed == MHD_NO) &&
157 (connection->readLoc == connection->read_buffer_size) ) ) {
158 /* try growing the read buffer, just in case */
159 buf = MHD_pool_reallocate(connection->pool,
160 connection->read_buffer,
161 connection->read_buffer_size,
162 connection->read_buffer_size * 2 + MHD_BUF_INC_SIZE);
163 if (buf != NULL) {
164 /* we can actually grow the buffer, do it! */
165 connection->read_buffer = buf;
166 connection->read_buffer_size = connection->read_buffer_size * 2 + MHD_BUF_INC_SIZE;
167 FD_SET(fd, read_fd_set);
168 if (fd > *max_fd)
169 *max_fd = fd;
170 }
171 }
172 }
173 if (connection->response != NULL) {
143 FD_SET(fd, write_fd_set); 174 FD_SET(fd, write_fd_set);
144 if ( (fd > *max_fd) && 175 if (fd > *max_fd)
145 ( (connection->headersReceived == 0) || 176 *max_fd = fd;
146 (connection->readLoc < connection->read_buffer_size) || 177 }
147 (connection->response != NULL) ) )
148 *max_fd = fd;
149 return MHD_YES; 178 return MHD_YES;
150} 179}
151 180
152/** 181/**
153 * Parse a single line of the HTTP header. Remove it 182 * We ran out of memory processing the
154 * from the read buffer. If the current line does not 183 * header. Handle it properly.
184 */
185static void
186MHD_excessive_header_handler(struct MHD_Connection * connection) {
187 /* die, header far too long to be reasonable;
188 FIXME: send proper response to client
189 (stop reading, queue proper response) */
190 MHD_DLOG(connection->daemon,
191 "Received excessively long header line, closing connection.\n");
192 CLOSE(connection->socket_fd);
193 connection->socket_fd = -1;
194}
195
196/**
197 * Parse a single line of the HTTP header. Advance
198 * read_buffer (!) appropriately. If the current line does not
155 * fit, consider growing the buffer. If the line is 199 * fit, consider growing the buffer. If the line is
156 * far too long, close the connection. If no line is 200 * far too long, close the connection. If no line is
157 * found (incomplete, buffer too small, line too long), 201 * found (incomplete, buffer too small, line too long),
158 * return NULL. Otherwise return a copy of the line. 202 * return NULL. Otherwise return a pointer to the line.
159 */ 203 */
160static char * 204static char *
161MHD_get_next_header_line(struct MHD_Connection * connection) { 205MHD_get_next_header_line(struct MHD_Connection * connection) {
162 char * rbuf; 206 char * rbuf;
163 size_t pos; 207 size_t pos;
164 size_t start;
165 208
166 if (connection->readLoc == 0) 209 if (connection->readLoc == 0)
167 return NULL; 210 return NULL;
168 start = 0;
169 pos = 0; 211 pos = 0;
170 rbuf = connection->read_buffer; 212 rbuf = connection->read_buffer;
171 while ( (pos < connection->readLoc - 1) && 213 while ( (pos < connection->readLoc - 1) &&
@@ -175,56 +217,55 @@ MHD_get_next_header_line(struct MHD_Connection * connection) {
175 if (pos == connection->readLoc - 1) { 217 if (pos == connection->readLoc - 1) {
176 /* not found, consider growing... */ 218 /* not found, consider growing... */
177 if (connection->readLoc == connection->read_buffer_size) { 219 if (connection->readLoc == connection->read_buffer_size) {
178 /* grow buffer to read larger header or die... */ 220 rbuf = MHD_pool_reallocate(connection->pool,
179 if (connection->read_buffer_size < 4 * MHD_MAX_BUF_SIZE) { 221 connection->read_buffer,
180 rbuf = malloc(connection->read_buffer_size * 2); 222 connection->read_buffer_size,
181 memcpy(rbuf, 223 connection->read_buffer_size * 2 + MHD_BUF_INC_SIZE);
182 connection->read_buffer, 224 if (rbuf == NULL) {
183 connection->readLoc); 225 MHD_excessive_header_handler(connection);
184 free(connection->read_buffer);
185 connection->read_buffer = rbuf;
186 connection->read_buffer_size *= 2;
187 } else { 226 } else {
188 /* die, header far too long to be reasonable */ 227 connection->read_buffer_size = connection->read_buffer_size * 2 + MHD_BUF_INC_SIZE;
189 MHD_DLOG(connection->daemon, 228 connection->read_buffer = rbuf;
190 "Received excessively long header line (>%u), closing connection.\n",
191 4 * MHD_MAX_BUF_SIZE);
192 CLOSE(connection->socket_fd);
193 connection->socket_fd = -1;
194 } 229 }
195 } 230 }
196 return NULL; 231 return NULL;
197 } 232 }
198 /* found, check if we have proper CRLF */ 233 /* found, check if we have proper CRLF */
199 rbuf = malloc(pos + 1); 234 if ( (rbuf[pos] == '\r') &&
200 memcpy(rbuf, 235 (rbuf[pos+1] == '\n') )
201 connection->read_buffer, 236 rbuf[pos++] = '\0'; /* skip both r and n */
202 pos); 237 rbuf[pos++] = '\0';
203 rbuf[pos] = '\0'; 238 connection->read_buffer += pos;
204 if ( (connection->read_buffer[pos] == '\r') && 239 connection->read_buffer_size -= pos;
205 (connection->read_buffer[pos+1] == '\n') )
206 pos++; /* skip both r and n */
207 pos++;
208 memmove(connection->read_buffer,
209 &connection->read_buffer[pos],
210 connection->readLoc - pos);
211 connection->readLoc -= pos; 240 connection->readLoc -= pos;
212 return rbuf; 241 return rbuf;
213} 242}
214 243
215static void 244/**
245 * @return MHD_NO on failure (out of memory), MHD_YES for success
246 */
247static int
216MHD_connection_add_header(struct MHD_Connection * connection, 248MHD_connection_add_header(struct MHD_Connection * connection,
217 const char * key, 249 char * key,
218 const char * value, 250 char * value,
219 enum MHD_ValueKind kind) { 251 enum MHD_ValueKind kind) {
220 struct MHD_HTTP_Header * hdr; 252 struct MHD_HTTP_Header * hdr;
221 253
222 hdr = malloc(sizeof(struct MHD_HTTP_Header)); 254 hdr = MHD_pool_allocate(connection->pool,
255 sizeof(struct MHD_HTTP_Header),
256 MHD_YES);
257 if (hdr == NULL) {
258 MHD_DLOG(connection->daemon,
259 "Not enough memory to allocate header record!\n");
260 MHD_excessive_header_handler(connection);
261 return MHD_NO;
262 }
223 hdr->next = connection->headers_received; 263 hdr->next = connection->headers_received;
224 hdr->header = strdup(key); 264 hdr->header = key;
225 hdr->value = strdup(value); 265 hdr->value = value;
226 hdr->kind = kind; 266 hdr->kind = kind;
227 connection->headers_received = hdr; 267 connection->headers_received = hdr;
268 return MHD_YES;
228} 269}
229 270
230/** 271/**
@@ -253,7 +294,10 @@ MHD_http_unescape(char * val) {
253 } 294 }
254} 295}
255 296
256static void 297/**
298 * @return MHD_NO on failure (out of memory), MHD_YES for success
299 */
300static int
257parse_arguments(enum MHD_ValueKind kind, 301parse_arguments(enum MHD_ValueKind kind,
258 struct MHD_Connection * connection, 302 struct MHD_Connection * connection,
259 char * args) { 303 char * args) {
@@ -263,7 +307,7 @@ parse_arguments(enum MHD_ValueKind kind,
263 while (args != NULL) { 307 while (args != NULL) {
264 equals = strstr(args, "="); 308 equals = strstr(args, "=");
265 if (equals == NULL) 309 if (equals == NULL)
266 return; /* invalid, ignore */ 310 return MHD_NO; /* invalid, ignore */
267 equals[0] = '\0'; 311 equals[0] = '\0';
268 equals++; 312 equals++;
269 amper = strstr(equals, "&"); 313 amper = strstr(equals, "&");
@@ -273,18 +317,22 @@ parse_arguments(enum MHD_ValueKind kind,
273 } 317 }
274 MHD_http_unescape(args); 318 MHD_http_unescape(args);
275 MHD_http_unescape(equals); 319 MHD_http_unescape(equals);
276 MHD_connection_add_header(connection, 320 if (MHD_NO == MHD_connection_add_header(connection,
277 args, 321 args,
278 equals, 322 equals,
279 kind); 323 kind))
324 return MHD_NO;
280 args = amper; 325 args = amper;
281 } 326 }
327 return MHD_YES;
282} 328}
283 329
284/** 330/**
285 * Parse the cookie header (see RFC 2109). 331 * Parse the cookie header (see RFC 2109).
332 *
333 * @return MHD_YES for success, MHD_NO for failure (malformed, out of memory)
286 */ 334 */
287static void 335static int
288MHD_parse_cookie_header(struct MHD_Connection * connection) { 336MHD_parse_cookie_header(struct MHD_Connection * connection) {
289 const char * hdr; 337 const char * hdr;
290 char * cpy; 338 char * cpy;
@@ -294,11 +342,22 @@ MHD_parse_cookie_header(struct MHD_Connection * connection) {
294 int quotes; 342 int quotes;
295 343
296 hdr = MHD_lookup_connection_value(connection, 344 hdr = MHD_lookup_connection_value(connection,
297 MHD_HEADER_KIND, 345 MHD_HEADER_KIND,
298 "Cookie"); 346 "Cookie");
299 if (hdr == NULL) 347 if (hdr == NULL)
300 return; 348 return MHD_YES;
301 cpy = strdup(hdr); 349 cpy = MHD_pool_allocate(connection->pool,
350 strlen(hdr)+1,
351 MHD_YES);
352 if (cpy == NULL) {
353 MHD_DLOG(connection->daemon,
354 "Not enough memory to parse cookies!\n");
355 MHD_excessive_header_handler(connection);
356 return MHD_NO;
357 }
358 memcpy(cpy,
359 hdr,
360 strlen(hdr)+1);
302 pos = cpy; 361 pos = cpy;
303 while (pos != NULL) { 362 while (pos != NULL) {
304 equals = strstr(pos, "="); 363 equals = strstr(pos, "=");
@@ -328,13 +387,14 @@ MHD_parse_cookie_header(struct MHD_Connection * connection) {
328 equals[strlen(equals)-1] = '\0'; 387 equals[strlen(equals)-1] = '\0';
329 equals++; 388 equals++;
330 } 389 }
331 MHD_connection_add_header(connection, 390 if (MHD_NO == MHD_connection_add_header(connection,
332 pos, 391 pos,
333 equals, 392 equals,
334 MHD_COOKIE_KIND); 393 MHD_COOKIE_KIND))
394 return MHD_NO;
335 pos = semicolon; 395 pos = semicolon;
336 } 396 }
337 free(cpy); 397 return MHD_YES;
338} 398}
339 399
340/** 400/**
@@ -355,7 +415,7 @@ parse_initial_message_line(struct MHD_Connection * connection,
355 if (uri == NULL) 415 if (uri == NULL)
356 return MHD_NO; /* serious error */ 416 return MHD_NO; /* serious error */
357 uri[0] = '\0'; 417 uri[0] = '\0';
358 connection->method = strdup(line); 418 connection->method = line;
359 uri++; 419 uri++;
360 while (uri[0] == ' ') 420 while (uri[0] == ' ')
361 uri++; 421 uri++;
@@ -372,11 +432,11 @@ parse_initial_message_line(struct MHD_Connection * connection,
372 connection, 432 connection,
373 args); 433 args);
374 } 434 }
375 connection->url = strdup(uri); 435 connection->url = uri;
376 if (httpVersion == NULL) 436 if (httpVersion == NULL)
377 connection->version = strdup(""); 437 connection->version = "";
378 else 438 else
379 connection->version = strdup(httpVersion); 439 connection->version = httpVersion;
380 return MHD_YES; 440 return MHD_YES;
381} 441}
382 442
@@ -398,6 +458,7 @@ MHD_parse_connection_headers(struct MHD_Connection * connection) {
398 char * colon; 458 char * colon;
399 char * tmp; 459 char * tmp;
400 const char * clen; 460 const char * clen;
461 const char * end;
401 unsigned long long cval; 462 unsigned long long cval;
402 463
403 if (connection->bodyReceived == 1) 464 if (connection->bodyReceived == 1)
@@ -409,51 +470,38 @@ MHD_parse_connection_headers(struct MHD_Connection * connection) {
409 (line[0] == '\t') ) { 470 (line[0] == '\t') ) {
410 /* value was continued on the next line, see 471 /* value was continued on the next line, see
411 http://www.jmarshall.com/easy/http/ */ 472 http://www.jmarshall.com/easy/http/ */
412 if ( (strlen(line) + strlen(last) > 473 last = MHD_pool_reallocate(connection->pool,
413 4 * MHD_MAX_BUF_SIZE) ) { 474 last,
414 free(line); 475 strlen(last)+1,
415 free(last); 476 strlen(line) + strlen(last) + 1);
416 last = NULL; 477 if (last == NULL) {
417 MHD_DLOG(connection->daemon, 478 MHD_excessive_header_handler(connection);
418 "Received excessively long header line (>%u), closing connection.\n",
419 4 * MHD_MAX_BUF_SIZE);
420 CLOSE(connection->socket_fd);
421 connection->socket_fd = -1;
422 break; 479 break;
423 } 480 }
424 tmp = malloc(strlen(line) + strlen(last) + 1);
425 strcpy(tmp, last);
426 free(last);
427 last = tmp;
428 tmp = line; 481 tmp = line;
429 while ( (tmp[0] == ' ') || 482 while ( (tmp[0] == ' ') ||
430 (tmp[0] == '\t') ) 483 (tmp[0] == '\t') )
431 tmp++; /* skip whitespace at start of 2nd line */ 484 tmp++; /* skip whitespace at start of 2nd line */
432 strcat(last, tmp); 485 strcat(last, tmp);
433 free(line);
434 continue; /* possibly more than 2 lines... */ 486 continue; /* possibly more than 2 lines... */
435 } else { 487 } else {
436 MHD_connection_add_header(connection, 488 if (MHD_NO == MHD_connection_add_header(connection,
437 last, 489 last,
438 colon, 490 colon,
439 MHD_HEADER_KIND); 491 MHD_HEADER_KIND))
440 free(last); 492 return;
441 last = NULL; 493 last = NULL;
442 } 494 }
443 } 495 }
444 if (connection->url == NULL) { 496 if (connection->url == NULL) {
445 /* line must be request line (first line of header) */ 497 /* line must be request line (first line of header) */
446 if (MHD_NO == parse_initial_message_line(connection, 498 if (MHD_NO == parse_initial_message_line(connection,
447 line)) { 499 line))
448 free(line); 500 goto DIE;
449 goto DIE;
450 }
451 free(line);
452 continue; 501 continue;
453 } 502 }
454 /* check if this is the end of the header */ 503 /* check if this is the end of the header */
455 if (strlen(line) == 0) { 504 if (strlen(line) == 0) {
456 free(line);
457 /* end of header */ 505 /* end of header */
458 connection->headersReceived = 1; 506 connection->headersReceived = 1;
459 clen = MHD_lookup_connection_value(connection, 507 clen = MHD_lookup_connection_value(connection,
@@ -483,6 +531,17 @@ MHD_parse_connection_headers(struct MHD_Connection * connection) {
483 connection->bodyReceived = 0; 531 connection->bodyReceived = 0;
484 } 532 }
485 } 533 }
534 end = MHD_lookup_connection_value(connection,
535 MHD_HEADER_KIND,
536 MHD_HTTP_HEADER_CONNECTION);
537 if ( (end != NULL) &&
538 (0 == strcasecmp(end,
539 "close")) ) {
540 /* other side explicitly requested
541 that we close the connection after
542 this request */
543 connection->read_close = MHD_YES;
544 }
486 break; 545 break;
487 } 546 }
488 /* line should be normal header line, find colon */ 547 /* line should be normal header line, find colon */
@@ -507,13 +566,12 @@ MHD_parse_connection_headers(struct MHD_Connection * connection) {
507 with a space...) */ 566 with a space...) */
508 last = line; 567 last = line;
509 } 568 }
510 if (last != NULL) { 569 if ( (last != NULL) &&
511 MHD_connection_add_header(connection, 570 (MHD_NO == MHD_connection_add_header(connection,
512 last, 571 last,
513 colon, 572 colon,
514 MHD_HEADER_KIND); 573 MHD_HEADER_KIND)) )
515 free(last); 574 return; /* error */
516 }
517 MHD_parse_cookie_header(connection); 575 MHD_parse_cookie_header(connection);
518 return; 576 return;
519 DIE: 577 DIE:
@@ -540,6 +598,103 @@ MHD_find_access_handler(struct MHD_Connection * connection) {
540} 598}
541 599
542/** 600/**
601 * Test if we are able to process the POST data.
602 * This depends on available memory (enough to load
603 * all of the POST data into the pool) and the
604 * content encoding of the POST data. And of course,
605 * this requires that the request is actually a
606 * POST request.
607 *
608 * @return MHD_YES if so
609 */
610static int
611MHD_test_post_data(struct MHD_Connection * connection) {
612 const char * encoding;
613 void * buf;
614
615 if (0 != strcasecmp(connection->method,
616 MHD_HTTP_METHOD_POST))
617 return MHD_NO;
618 encoding = MHD_lookup_connection_value(connection,
619 MHD_HEADER_KIND,
620 MHD_HTTP_HEADER_CONTENT_TYPE);
621 if (encoding == NULL)
622 return MHD_NO;
623 if ( (0 == strcasecmp(MHD_HTTP_POST_ENCODING_FORM_URLENCODED,
624 encoding)) &&
625 (connection->uploadSize != -1) ) {
626 buf = MHD_pool_reallocate(connection->pool,
627 connection->read_buffer,
628 connection->read_buffer_size,
629 connection->uploadSize + 1);
630 if (buf == NULL)
631 return MHD_NO;
632 connection->read_buffer_size = connection->uploadSize + 1;
633 connection->read_buffer = buf;
634 return MHD_YES;
635 }
636 return MHD_NO;
637}
638
639/**
640 * Process the POST data here (adding to headers).
641 *
642 * Needs to first check POST encoding and then do
643 * the right thing (TM). The POST data is in the
644 * connection's post_data buffer between the postPos
645 * and postLoc offsets. The POST message maybe
646 * incomplete. The existing buffer (allocated from
647 * the pool) can be used and modified but must then
648 * be properly removed from the struct.
649 *
650 * @return MHD_YES on success, MHD_NO on error (i.e. out of
651 * memory).
652 */
653static int
654MHD_parse_post_data(struct MHD_Connection * connection) {
655 const char * encoding;
656 int ret;
657
658 encoding = MHD_lookup_connection_value(connection,
659 MHD_HEADER_KIND,
660 MHD_HTTP_HEADER_CONTENT_TYPE);
661 if (encoding == NULL)
662 return MHD_NO;
663 if (0 == strcasecmp(MHD_HTTP_POST_ENCODING_FORM_URLENCODED,
664 encoding)) {
665 ret = parse_arguments(MHD_POSTDATA_KIND,
666 connection,
667 connection->read_buffer);
668 /* invalidate read buffer for other uses --
669 in particular, do not give it to the
670 client; if this were to be needed, we would
671 have to make a copy, which would double memory
672 requirements */
673 connection->read_buffer_size = 0;
674 connection->readLoc = 0;
675 connection->uploadSize = 0;
676 connection->read_buffer = NULL;
677 return ret;
678 }
679 if (0 == strcasecmp(MHD_HTTP_POST_ENCODING_MULTIPART_FORMDATA,
680 encoding)) {
681 /* this code should never been reached right now,
682 since the test_post_data function would already
683 return MHD_NO; code is here only for future
684 extensions... */
685 /* see http://www.w3.org/TR/html4/interact/forms.html#h-17.13.4 */
686 MHD_DLOG(connection->daemon,
687 "Unsupported multipart encoding of POST data specified, not processing POST data.\n");
688 return MHD_NO;
689 }
690 /* this should never be reached, just here for
691 error checking */
692 MHD_DLOG(connection->daemon,
693 "Unknown encoding of POST data specified, not processing POST data.\n");
694 return MHD_NO;
695}
696
697/**
543 * Call the handler of the application for this 698 * Call the handler of the application for this
544 * connection. 699 * connection.
545 */ 700 */
@@ -552,9 +707,6 @@ MHD_call_connection_handler(struct MHD_Connection * connection) {
552 abort(); /* bad timing... */ 707 abort(); /* bad timing... */
553 ah = MHD_find_access_handler(connection); 708 ah = MHD_find_access_handler(connection);
554 processed = connection->readLoc; 709 processed = connection->readLoc;
555 /* FIXME: in case of POST, we need to
556 process the POST data here as well
557 (adding to the header list! */
558 if (MHD_NO == ah->dh(ah->dh_cls, 710 if (MHD_NO == ah->dh(ah->dh_cls,
559 connection, 711 connection,
560 connection->url, 712 connection->url,
@@ -564,7 +716,7 @@ MHD_call_connection_handler(struct MHD_Connection * connection) {
564 &processed)) { 716 &processed)) {
565 /* serios internal error, close connection */ 717 /* serios internal error, close connection */
566 MHD_DLOG(connection->daemon, 718 MHD_DLOG(connection->daemon,
567 "Internal application error, closing connection."); 719 "Internal application error, closing connection.\n");
568 CLOSE(connection->socket_fd); 720 CLOSE(connection->socket_fd);
569 connection->socket_fd = -1; 721 connection->socket_fd = -1;
570 return; 722 return;
@@ -583,7 +735,6 @@ MHD_call_connection_handler(struct MHD_Connection * connection) {
583 connection->bodyReceived = 1; 735 connection->bodyReceived = 1;
584 connection->readLoc = 0; 736 connection->readLoc = 0;
585 connection->read_buffer_size = 0; 737 connection->read_buffer_size = 0;
586 free(connection->read_buffer);
587 connection->read_buffer = NULL; 738 connection->read_buffer = NULL;
588 } 739 }
589} 740}
@@ -600,17 +751,30 @@ MHD_connection_handle_read(struct MHD_Connection * connection) {
600 int bytes_read; 751 int bytes_read;
601 void * tmp; 752 void * tmp;
602 753
754 if (connection->pool == NULL)
755 connection->pool = MHD_pool_create(connection->daemon->pool_size);
756 if (connection->pool == NULL) {
757 MHD_DLOG(connection->daemon,
758 "Failed to create memory pool!\n");
759 CLOSE(connection->socket_fd);
760 connection->socket_fd = -1;
761 return MHD_NO;
762 }
603 if ( (connection->readLoc >= connection->read_buffer_size) && 763 if ( (connection->readLoc >= connection->read_buffer_size) &&
604 (connection->headersReceived == 0) ) { 764 (connection->headersReceived == 0) ) {
605 /* need to grow read buffer */ 765 /* need to grow read buffer */
606 tmp = malloc(connection->read_buffer_size * 2 + MHD_MAX_BUF_SIZE); 766 tmp = MHD_pool_reallocate(connection->pool,
607 memcpy(tmp, 767 connection->read_buffer,
608 connection->read_buffer, 768 connection->read_buffer_size,
609 connection->read_buffer_size); 769 connection->read_buffer_size * 2 + MHD_BUF_INC_SIZE);
610 connection->read_buffer_size = connection->read_buffer_size * 2 + MHD_MAX_BUF_SIZE; 770 if (tmp == NULL) {
611 if (connection->read_buffer != NULL) 771 MHD_DLOG(connection->daemon,
612 free(connection->read_buffer); 772 "Not enough memory for reading headers!\n");
773 MHD_excessive_header_handler(connection);
774 return MHD_NO;
775 }
613 connection->read_buffer = tmp; 776 connection->read_buffer = tmp;
777 connection->read_buffer_size = connection->read_buffer_size * 2 + MHD_BUF_INC_SIZE;
614 } 778 }
615 if (connection->readLoc >= connection->read_buffer_size) { 779 if (connection->readLoc >= connection->read_buffer_size) {
616 MHD_DLOG(connection->daemon, 780 MHD_DLOG(connection->daemon,
@@ -634,16 +798,28 @@ MHD_connection_handle_read(struct MHD_Connection * connection) {
634 } 798 }
635 if (bytes_read == 0) { 799 if (bytes_read == 0) {
636 /* other side closed connection */ 800 /* other side closed connection */
801 connection->read_close = MHD_YES;
637 if (connection->readLoc > 0) 802 if (connection->readLoc > 0)
638 MHD_call_connection_handler(connection); 803 MHD_call_connection_handler(connection);
639 shutdown(connection->socket_fd, SHUT_RD); 804 shutdown(connection->socket_fd, SHUT_RD);
640 return MHD_YES; 805 return MHD_YES;
641 } 806 }
642 connection->readLoc += bytes_read; 807 connection->readLoc += bytes_read;
643 if (connection->headersReceived == 0) 808 if (connection->headersReceived == 0) {
644 MHD_parse_connection_headers(connection); 809 MHD_parse_connection_headers(connection);
645 if (connection->headersReceived == 1) 810 if (connection->headersReceived == 1) {
646 MHD_call_connection_handler(connection); 811 connection->post_processed = MHD_test_post_data(connection);
812 }
813 }
814 if (connection->headersReceived == 1) {
815 if ( (connection->post_processed == MHD_YES) &&
816 (connection->uploadSize == connection->readLoc) )
817 if (MHD_NO == MHD_parse_post_data(connection))
818 connection->post_processed = MHD_NO;
819 if ( (connection->post_processed == MHD_NO) ||
820 (connection->read_buffer_size == connection->readLoc) )
821 MHD_call_connection_handler(connection);
822 }
647 return MHD_YES; 823 return MHD_YES;
648} 824}
649 825
@@ -666,9 +842,9 @@ MHD_add_extra_headers(struct MHD_Connection * connection) {
666 } else if (NULL == MHD_get_response_header(connection->response, 842 } else if (NULL == MHD_get_response_header(connection->response,
667 MHD_HTTP_HEADER_CONTENT_LENGTH)) { 843 MHD_HTTP_HEADER_CONTENT_LENGTH)) {
668 _REAL_SNPRINTF(buf, 844 _REAL_SNPRINTF(buf,
669 128, 845 128,
670 "%llu", 846 "%llu",
671 (unsigned long long) connection->response->total_size); 847 (unsigned long long) connection->response->total_size);
672 MHD_add_response_header(connection->response, 848 MHD_add_response_header(connection->response,
673 MHD_HTTP_HEADER_CONTENT_LENGTH, 849 MHD_HTTP_HEADER_CONTENT_LENGTH,
674 buf); 850 buf);
@@ -680,7 +856,7 @@ MHD_add_extra_headers(struct MHD_Connection * connection) {
680 * fill it with all of the headers from the 856 * fill it with all of the headers from the
681 * HTTPd's response. 857 * HTTPd's response.
682 */ 858 */
683static void 859static int
684MHD_build_header_response(struct MHD_Connection * connection) { 860MHD_build_header_response(struct MHD_Connection * connection) {
685 size_t size; 861 size_t size;
686 size_t off; 862 size_t off;
@@ -702,7 +878,14 @@ MHD_build_header_response(struct MHD_Connection * connection) {
702 pos = pos->next; 878 pos = pos->next;
703 } 879 }
704 /* produce data */ 880 /* produce data */
705 data = malloc(size + 1); 881 data = MHD_pool_allocate(connection->pool,
882 size + 1,
883 MHD_YES);
884 if (data == NULL) {
885 MHD_DLOG(connection->daemon,
886 "Not enough memory for write!\n");
887 return MHD_NO;
888 }
706 memcpy(data, 889 memcpy(data,
707 code, 890 code,
708 off); 891 off);
@@ -721,7 +904,10 @@ MHD_build_header_response(struct MHD_Connection * connection) {
721 if (off != size) 904 if (off != size)
722 abort(); 905 abort();
723 connection->write_buffer = data; 906 connection->write_buffer = data;
724 connection->write_buffer_size = size; 907 connection->writeLoc = size;
908 connection->writePos = 0;
909 connection->write_buffer_size = size + 1;
910 return MHD_YES;
725} 911}
726 912
727/** 913/**
@@ -743,11 +929,16 @@ MHD_connection_handle_write(struct MHD_Connection * connection) {
743 return MHD_NO; 929 return MHD_NO;
744 } 930 }
745 if (! connection->headersSent) { 931 if (! connection->headersSent) {
746 if (connection->write_buffer == NULL) 932 if ( (connection->write_buffer == NULL) &&
747 MHD_build_header_response(connection); 933 (MHD_NO == MHD_build_header_response(connection)) ) {
934 /* oops - close! */
935 CLOSE(connection->socket_fd);
936 connection->socket_fd = -1;
937 return MHD_NO;
938 }
748 ret = SEND(connection->socket_fd, 939 ret = SEND(connection->socket_fd,
749 &connection->write_buffer[connection->writeLoc], 940 &connection->write_buffer[connection->writePos],
750 connection->write_buffer_size - connection->writeLoc, 941 connection->writeLoc - connection->writePos,
751 0); 942 0);
752 if (ret < 0) { 943 if (ret < 0) {
753 if (errno == EINTR) 944 if (errno == EINTR)
@@ -759,13 +950,17 @@ MHD_connection_handle_write(struct MHD_Connection * connection) {
759 connection->socket_fd = -1; 950 connection->socket_fd = -1;
760 return MHD_YES; 951 return MHD_YES;
761 } 952 }
762 connection->writeLoc += ret; 953 connection->writePos += ret;
763 if (connection->writeLoc == connection->write_buffer_size) { 954 if (connection->writeLoc == connection->writePos) {
764 connection->writeLoc = 0; 955 connection->writeLoc = 0;
765 free(connection->write_buffer); 956 connection->writePos = 0;
957 connection->headersSent = 1;
958 MHD_pool_reallocate(connection->pool,
959 connection->write_buffer,
960 connection->write_buffer_size,
961 0);
766 connection->write_buffer = NULL; 962 connection->write_buffer = NULL;
767 connection->write_buffer_size = 0; 963 connection->write_buffer_size = 0;
768 connection->headersSent = 1;
769 } 964 }
770 return MHD_YES; 965 return MHD_YES;
771 } 966 }
@@ -781,13 +976,13 @@ MHD_connection_handle_write(struct MHD_Connection * connection) {
781 if (response->data_size == 0) { 976 if (response->data_size == 0) {
782 if (response->data != NULL) 977 if (response->data != NULL)
783 free(response->data); 978 free(response->data);
784 response->data = malloc(MHD_MAX_BUF_SIZE); 979 response->data = malloc(MHD_BUF_INC_SIZE);
785 response->data_size = MHD_MAX_BUF_SIZE; 980 response->data_size = MHD_BUF_INC_SIZE;
786 } 981 }
787 ret = response->crc(response->crc_cls, 982 ret = response->crc(response->crc_cls,
788 connection->messagePos, 983 connection->messagePos,
789 response->data, 984 response->data,
790 MAX(MHD_MAX_BUF_SIZE, 985 MAX(MHD_BUF_INC_SIZE,
791 response->data_size - connection->messagePos)); 986 response->data_size - connection->messagePos));
792 if (ret == -1) { 987 if (ret == -1) {
793 /* end of message, signal other side by closing! */ 988 /* end of message, signal other side by closing! */
@@ -838,22 +1033,26 @@ MHD_connection_handle_write(struct MHD_Connection * connection) {
838 connection->headersSent = 0; 1033 connection->headersSent = 0;
839 connection->bodyReceived = 0; 1034 connection->bodyReceived = 0;
840 connection->messagePos = 0; 1035 connection->messagePos = 0;
841 free(connection->method);
842 connection->method = NULL; 1036 connection->method = NULL;
843 free(connection->url);
844 connection->url = NULL; 1037 connection->url = NULL;
845 free(connection->write_buffer);
846 connection->write_buffer = NULL;
847 connection->write_buffer_size = 0;
848 if ( (connection->read_close != 0) || 1038 if ( (connection->read_close != 0) ||
849 (0 != strcasecmp(MHD_HTTP_VERSION_1_1, 1039 (0 != strcasecmp(MHD_HTTP_VERSION_1_1,
850 connection->version)) ) { 1040 connection->version)) ) {
851 /* closed for reading => close for good! */ 1041 /* closed for reading => close for good! */
852 CLOSE(connection->socket_fd); 1042 if (connection->socket_fd != -1)
1043 CLOSE(connection->socket_fd);
853 connection->socket_fd = -1; 1044 connection->socket_fd = -1;
854 } 1045 }
855 free(connection->version);
856 connection->version = NULL; 1046 connection->version = NULL;
1047 connection->read_buffer = NULL;
1048 connection->write_buffer = NULL;
1049 connection->read_buffer_size = 0;
1050 connection->readLoc = 0;
1051 connection->write_buffer_size = 0;
1052 connection->writePos = 0;
1053 connection->writeLoc = 0;
1054 MHD_pool_destroy(connection->pool);
1055 connection->pool = NULL;
857 } 1056 }
858 return MHD_YES; 1057 return MHD_YES;
859} 1058}
diff --git a/src/daemon/daemon.c b/src/daemon/daemon.c
index 39abee6a..48ec9219 100644
--- a/src/daemon/daemon.c
+++ b/src/daemon/daemon.c
@@ -28,9 +28,17 @@
28#include "internal.h" 28#include "internal.h"
29#include "response.h" 29#include "response.h"
30#include "connection.h" 30#include "connection.h"
31#include "memorypool.h"
31 32
32#define MHD_MAX_CONNECTIONS FD_SETSIZE -4 33/**
34 * Default connection limit.
35 */
36#define MHD_MAX_CONNECTIONS_DEFAULT FD_SETSIZE -4
33 37
38/**
39 * Default memory allowed per connection.
40 */
41#define MHD_POOL_SIZE_DEFAULT (1024 * 1024)
34 42
35/** 43/**
36 * Register an access handler for all URIs beginning with uri_prefix. 44 * Register an access handler for all URIs beginning with uri_prefix.
@@ -229,6 +237,13 @@ MHD_accept_connection(struct MHD_Daemon * daemon) {
229 MHD_DLOG(daemon, 237 MHD_DLOG(daemon,
230 "Error accepting connection: %s\n", 238 "Error accepting connection: %s\n",
231 STRERROR(errno)); 239 STRERROR(errno));
240 if (s != -1)
241 CLOSE(s); /* just in case */
242 return MHD_NO;
243 }
244 if (daemon->max_connections == 0) {
245 /* above connection limit - reject */
246 CLOSE(s);
232 return MHD_NO; 247 return MHD_NO;
233 } 248 }
234 if (MHD_NO == daemon->apc(daemon->apc_cls, 249 if (MHD_NO == daemon->apc(daemon->apc_cls,
@@ -241,7 +256,13 @@ MHD_accept_connection(struct MHD_Daemon * daemon) {
241 memset(connection, 256 memset(connection,
242 0, 257 0,
243 sizeof(struct MHD_Connection)); 258 sizeof(struct MHD_Connection));
259 connection->pool = NULL;
244 connection->addr = malloc(addrlen); 260 connection->addr = malloc(addrlen);
261 if (connection->addr == NULL) {
262 CLOSE(s);
263 free(connection);
264 return MHD_NO;
265 }
245 memcpy(connection->addr, 266 memcpy(connection->addr,
246 addr, 267 addr,
247 addrlen); 268 addrlen);
@@ -258,11 +279,13 @@ MHD_accept_connection(struct MHD_Daemon * daemon) {
258 STRERROR(errno)); 279 STRERROR(errno));
259 free(connection->addr); 280 free(connection->addr);
260 CLOSE(s); 281 CLOSE(s);
282 free(connection->addr);
261 free(connection); 283 free(connection);
262 return MHD_NO; 284 return MHD_NO;
263 } 285 }
264 connection->next = daemon->connections; 286 connection->next = daemon->connections;
265 daemon->connections = connection; 287 daemon->connections = connection;
288 daemon->max_connections--;
266 return MHD_YES; 289 return MHD_YES;
267} 290}
268 291
@@ -281,7 +304,6 @@ static void
281MHD_cleanup_connections(struct MHD_Daemon * daemon) { 304MHD_cleanup_connections(struct MHD_Daemon * daemon) {
282 struct MHD_Connection * pos; 305 struct MHD_Connection * pos;
283 struct MHD_Connection * prev; 306 struct MHD_Connection * prev;
284 struct MHD_HTTP_Header * hpos;
285 void * unused; 307 void * unused;
286 308
287 pos = daemon->connections; 309 pos = daemon->connections;
@@ -296,25 +318,12 @@ MHD_cleanup_connections(struct MHD_Daemon * daemon) {
296 pthread_kill(pos->pid, SIGALRM); 318 pthread_kill(pos->pid, SIGALRM);
297 pthread_join(pos->pid, &unused); 319 pthread_join(pos->pid, &unused);
298 } 320 }
299 free(pos->addr);
300 if (pos->url != NULL)
301 free(pos->url);
302 if (pos->method != NULL)
303 free(pos->method);
304 if (pos->write_buffer != NULL)
305 free(pos->write_buffer);
306 if (pos->read_buffer != NULL)
307 free(pos->read_buffer);
308 while (pos->headers_received != NULL) {
309 hpos = pos->headers_received;
310 pos->headers_received = hpos->next;
311 free(hpos->header);
312 free(hpos->value);
313 free(hpos);
314 }
315 if (pos->response != NULL) 321 if (pos->response != NULL)
316 MHD_destroy_response(pos->response); 322 MHD_destroy_response(pos->response);
323 MHD_pool_destroy(pos->pool);
324 free(pos->addr);
317 free(pos); 325 free(pos);
326 daemon->max_connections++;
318 if (prev == NULL) 327 if (prev == NULL)
319 pos = daemon->connections; 328 pos = daemon->connections;
320 else 329 else
@@ -474,6 +483,8 @@ MHD_start_daemon(unsigned int options,
474 struct sockaddr_in6 servaddr6; 483 struct sockaddr_in6 servaddr6;
475 const struct sockaddr * servaddr; 484 const struct sockaddr * servaddr;
476 socklen_t addrlen; 485 socklen_t addrlen;
486 va_list ap;
487 enum MHD_OPTION opt;
477 488
478 if ((options & MHD_USE_SSL) != 0) 489 if ((options & MHD_USE_SSL) != 0)
479 return NULL; 490 return NULL;
@@ -549,6 +560,24 @@ MHD_start_daemon(unsigned int options,
549 retVal->default_handler.dh_cls = dh_cls; 560 retVal->default_handler.dh_cls = dh_cls;
550 retVal->default_handler.uri_prefix = ""; 561 retVal->default_handler.uri_prefix = "";
551 retVal->default_handler.next = NULL; 562 retVal->default_handler.next = NULL;
563 retVal->max_connections = MHD_MAX_CONNECTIONS_DEFAULT;
564 retVal->pool_size = MHD_POOL_SIZE_DEFAULT;
565 va_start(ap, dh_cls);
566 while (MHD_OPTION_END != (opt = va_arg(ap, enum MHD_OPTION))) {
567 switch (opt) {
568 case MHD_OPTION_CONNECTION_MEMORY_LIMIT:
569 retVal->pool_size = va_arg(ap, unsigned int);
570 break;
571 case MHD_OPTION_CONNECTION_LIMIT:
572 retVal->max_connections = va_arg(ap, unsigned int);
573 break;
574 default:
575 fprintf(stderr,
576 "Invalid MHD_OPTION argument! (Did you terminate the list with MHD_OPTION_END?)\n");
577 abort();
578 }
579 }
580 va_end(ap);
552 if ( ( (0 != (options & MHD_USE_THREAD_PER_CONNECTION)) || 581 if ( ( (0 != (options & MHD_USE_THREAD_PER_CONNECTION)) ||
553 (0 != (options & MHD_USE_SELECT_INTERNALLY)) ) && 582 (0 != (options & MHD_USE_SELECT_INTERNALLY)) ) &&
554 (0 != pthread_create(&retVal->pid, 583 (0 != pthread_create(&retVal->pid,
diff --git a/src/daemon/daemontest_post.c b/src/daemon/daemontest_post.c
index 9f5f6c6f..3c69dadc 100644
--- a/src/daemon/daemontest_post.c
+++ b/src/daemon/daemontest_post.c
@@ -39,6 +39,7 @@
39 39
40#define POST_DATA "name=daniel&project=curl" 40#define POST_DATA "name=daniel&project=curl"
41 41
42static int oneone;
42 43
43static int apc_all(void * cls, 44static int apc_all(void * cls,
44 const struct sockaddr * addr, 45 const struct sockaddr * addr,
@@ -76,40 +77,36 @@ static int ahc_echo(void * cls,
76 unsigned int * upload_data_size) { 77 unsigned int * upload_data_size) {
77 struct MHD_Response * response; 78 struct MHD_Response * response;
78 int ret; 79 int ret;
80 const char * r1;
81 const char * r2;
79 82
80 if (0 != strcmp("POST", method)) { 83 if (0 != strcmp("POST", method)) {
81 printf("METHOD: %s\n", method); 84 printf("METHOD: %s\n", method);
82 return MHD_NO; /* unexpected method */ 85 return MHD_NO; /* unexpected method */
83 } 86 }
84 if ( (*upload_data_size < 24) && 87 r1 = MHD_lookup_connection_value(connection,
85 (*upload_data_size > 0) ) 88 MHD_POSTDATA_KIND,
86 return MHD_YES; /* continue */ 89 "name");
87 if (*upload_data_size == 24) { 90 r2 = MHD_lookup_connection_value(connection,
88 *upload_data_size = 0; 91 MHD_POSTDATA_KIND,
89 if ( (0 != strcmp("daniel", 92 "project");
90 MHD_lookup_connection_value(connection, 93 if ( (r1 != NULL) &&
91 MHD_POSTDATA_KIND, 94 (r2 != NULL) &&
92 "name"))) || 95 (0 == strcmp("daniel",
93 (0 != strcmp("curl", 96 r1)) &&
94 MHD_lookup_connection_value(connection, 97 (0 == strcmp("curl",
95 MHD_POSTDATA_KIND, 98 r2)) ) {
96 "project"))) ) { 99 response = MHD_create_response_from_data(strlen(url),
97 printf("POST DATA not processed correctly!\n"); 100 (void*) url,
98 return MHD_NO; 101 MHD_NO,
99 } 102 MHD_YES);
100 103 ret = MHD_queue_response(connection,
101 return MHD_YES; /* continue */ 104 MHD_HTTP_OK,
105 response);
106 MHD_destroy_response(response);
107 return MHD_YES; /* done */
102 } 108 }
103 /* FIXME: check connection headers... */ 109 return MHD_YES;
104 response = MHD_create_response_from_data(strlen(url),
105 (void*) url,
106 MHD_NO,
107 MHD_YES);
108 ret = MHD_queue_response(connection,
109 MHD_HTTP_OK,
110 response);
111 MHD_destroy_response(response);
112 return ret;
113} 110}
114 111
115 112
@@ -118,7 +115,7 @@ static int testInternalPost() {
118 CURL * c; 115 CURL * c;
119 char buf[2048]; 116 char buf[2048];
120 struct CBC cbc; 117 struct CBC cbc;
121 118
122 cbc.buf = buf; 119 cbc.buf = buf;
123 cbc.size = 2048; 120 cbc.size = 2048;
124 cbc.pos = 0; 121 cbc.pos = 0;
@@ -156,9 +153,14 @@ static int testInternalPost() {
156 curl_easy_setopt(c, 153 curl_easy_setopt(c,
157 CURLOPT_TIMEOUT, 154 CURLOPT_TIMEOUT,
158 2L); 155 2L);
159 curl_easy_setopt(c, 156 if (oneone)
160 CURLOPT_HTTP_VERSION, 157 curl_easy_setopt(c,
161 CURL_HTTP_VERSION_1_0); 158 CURLOPT_HTTP_VERSION,
159 CURL_HTTP_VERSION_1_1);
160 else
161 curl_easy_setopt(c,
162 CURLOPT_HTTP_VERSION,
163 CURL_HTTP_VERSION_1_0);
162 curl_easy_setopt(c, 164 curl_easy_setopt(c,
163 CURLOPT_CONNECTTIMEOUT, 165 CURLOPT_CONNECTTIMEOUT,
164 2L); 166 2L);
@@ -233,9 +235,14 @@ static int testMultithreadedPost() {
233 curl_easy_setopt(c, 235 curl_easy_setopt(c,
234 CURLOPT_TIMEOUT, 236 CURLOPT_TIMEOUT,
235 2L); 237 2L);
236 curl_easy_setopt(c, 238 if (oneone)
237 CURLOPT_HTTP_VERSION, 239 curl_easy_setopt(c,
238 CURL_HTTP_VERSION_1_0); 240 CURLOPT_HTTP_VERSION,
241 CURL_HTTP_VERSION_1_1);
242 else
243 curl_easy_setopt(c,
244 CURLOPT_HTTP_VERSION,
245 CURL_HTTP_VERSION_1_0);
239 curl_easy_setopt(c, 246 curl_easy_setopt(c,
240 CURLOPT_CONNECTTIMEOUT, 247 CURLOPT_CONNECTTIMEOUT,
241 2L); 248 2L);
@@ -321,9 +328,14 @@ static int testExternalPost() {
321 curl_easy_setopt(c, 328 curl_easy_setopt(c,
322 CURLOPT_TIMEOUT, 329 CURLOPT_TIMEOUT,
323 5L); 330 5L);
324 curl_easy_setopt(c, 331 if (oneone)
325 CURLOPT_HTTP_VERSION, 332 curl_easy_setopt(c,
326 CURL_HTTP_VERSION_1_0); 333 CURLOPT_HTTP_VERSION,
334 CURL_HTTP_VERSION_1_1);
335 else
336 curl_easy_setopt(c,
337 CURLOPT_HTTP_VERSION,
338 CURL_HTTP_VERSION_1_0);
327 curl_easy_setopt(c, 339 curl_easy_setopt(c,
328 CURLOPT_CONNECTTIMEOUT, 340 CURLOPT_CONNECTTIMEOUT,
329 5L); 341 5L);
@@ -429,11 +441,12 @@ int main(int argc,
429 char * const * argv) { 441 char * const * argv) {
430 unsigned int errorCount = 0; 442 unsigned int errorCount = 0;
431 443
444 oneone = NULL != strstr(argv[0], "11");
432 if (0 != curl_global_init(CURL_GLOBAL_WIN32)) 445 if (0 != curl_global_init(CURL_GLOBAL_WIN32))
433 return 2; 446 return 2;
434 errorCount += testInternalPost(); 447 errorCount += testInternalPost();
435 errorCount += testMultithreadedPost(); 448 errorCount += testMultithreadedPost();
436 errorCount += testExternalPost(); 449 errorCount += testExternalPost();
437 if (errorCount != 0) 450 if (errorCount != 0)
438 fprintf(stderr, 451 fprintf(stderr,
439 "Error (code: %u)\n", 452 "Error (code: %u)\n",
diff --git a/src/daemon/daemontest_put.c b/src/daemon/daemontest_put.c
index ca64688b..dfcccb0a 100644
--- a/src/daemon/daemontest_put.c
+++ b/src/daemon/daemontest_put.c
@@ -32,6 +32,8 @@
32#include <string.h> 32#include <string.h>
33#include <time.h> 33#include <time.h>
34 34
35static int oneone;
36
35static int apc_all(void * cls, 37static int apc_all(void * cls,
36 const struct sockaddr * addr, 38 const struct sockaddr * addr,
37 socklen_t addrlen) { 39 socklen_t addrlen) {
@@ -164,9 +166,14 @@ static int testInternalPut() {
164 curl_easy_setopt(c, 166 curl_easy_setopt(c,
165 CURLOPT_TIMEOUT, 167 CURLOPT_TIMEOUT,
166 15L); 168 15L);
167 curl_easy_setopt(c, 169 if (oneone)
168 CURLOPT_HTTP_VERSION, 170 curl_easy_setopt(c,
169 CURL_HTTP_VERSION_1_0); 171 CURLOPT_HTTP_VERSION,
172 CURL_HTTP_VERSION_1_1);
173 else
174 curl_easy_setopt(c,
175 CURLOPT_HTTP_VERSION,
176 CURL_HTTP_VERSION_1_0);
170 curl_easy_setopt(c, 177 curl_easy_setopt(c,
171 CURLOPT_CONNECTTIMEOUT, 178 CURLOPT_CONNECTTIMEOUT,
172 15L); 179 15L);
@@ -246,9 +253,14 @@ static int testMultithreadedPut() {
246 curl_easy_setopt(c, 253 curl_easy_setopt(c,
247 CURLOPT_TIMEOUT, 254 CURLOPT_TIMEOUT,
248 15L); 255 15L);
249 curl_easy_setopt(c, 256 if (oneone)
250 CURLOPT_HTTP_VERSION, 257 curl_easy_setopt(c,
251 CURL_HTTP_VERSION_1_0); 258 CURLOPT_HTTP_VERSION,
259 CURL_HTTP_VERSION_1_1);
260 else
261 curl_easy_setopt(c,
262 CURLOPT_HTTP_VERSION,
263 CURL_HTTP_VERSION_1_0);
252 curl_easy_setopt(c, 264 curl_easy_setopt(c,
253 CURLOPT_CONNECTTIMEOUT, 265 CURLOPT_CONNECTTIMEOUT,
254 15L); 266 15L);
@@ -339,9 +351,14 @@ static int testExternalPut() {
339 curl_easy_setopt(c, 351 curl_easy_setopt(c,
340 CURLOPT_TIMEOUT, 352 CURLOPT_TIMEOUT,
341 15L); 353 15L);
342 curl_easy_setopt(c, 354 if (oneone)
343 CURLOPT_HTTP_VERSION, 355 curl_easy_setopt(c,
344 CURL_HTTP_VERSION_1_0); 356 CURLOPT_HTTP_VERSION,
357 CURL_HTTP_VERSION_1_1);
358 else
359 curl_easy_setopt(c,
360 CURLOPT_HTTP_VERSION,
361 CURL_HTTP_VERSION_1_0);
345 curl_easy_setopt(c, 362 curl_easy_setopt(c,
346 CURLOPT_CONNECTTIMEOUT, 363 CURLOPT_CONNECTTIMEOUT,
347 15L); 364 15L);
@@ -447,6 +464,7 @@ int main(int argc,
447 char * const * argv) { 464 char * const * argv) {
448 unsigned int errorCount = 0; 465 unsigned int errorCount = 0;
449 466
467 oneone = NULL != strstr(argv[0], "11");
450 if (0 != curl_global_init(CURL_GLOBAL_WIN32)) 468 if (0 != curl_global_init(CURL_GLOBAL_WIN32))
451 return 2; 469 return 2;
452 errorCount += testInternalPut(); 470 errorCount += testInternalPut();
diff --git a/src/daemon/internal.h b/src/daemon/internal.h
index 101acfdd..efadb33a 100644
--- a/src/daemon/internal.h
+++ b/src/daemon/internal.h
@@ -37,6 +37,7 @@
37#include <errno.h> 37#include <errno.h>
38#include <fcntl.h> 38#include <fcntl.h>
39#include <signal.h> 39#include <signal.h>
40#include <sys/mman.h>
40 41
41#include "config.h" 42#include "config.h"
42#include "plibc.h" 43#include "plibc.h"
@@ -49,8 +50,6 @@
49 50
50#include <pthread.h> 51#include <pthread.h>
51 52
52#define MHD_MAX_BUF_SIZE 2048
53
54#define MAX(a,b) ((a)<(b)) ? (b) : (a) 53#define MAX(a,b) ((a)<(b)) ? (b) : (a)
55 54
56 55
@@ -157,41 +156,72 @@ struct MHD_Response {
157 156
158 157
159struct MHD_Connection { 158struct MHD_Connection {
159
160 /**
161 * This is a linked list.
162 */
160 struct MHD_Connection * next; 163 struct MHD_Connection * next;
161 164
165 /**
166 * Reference to the MHD_Daemon struct.
167 */
162 struct MHD_Daemon * daemon; 168 struct MHD_Daemon * daemon;
163 169
170 /**
171 * Linked list of parsed headers.
172 */
164 struct MHD_HTTP_Header * headers_received; 173 struct MHD_HTTP_Header * headers_received;
165 174
175 /**
176 * Response to transmit (initially NULL).
177 */
166 struct MHD_Response * response; 178 struct MHD_Response * response;
167 179
168 /** 180 /**
169 * Request method. Should be GET/POST/etc. 181 * The memory pool is created whenever we first read
182 * from the TCP stream and destroyed at the end of
183 * each request (and re-created for the next request).
184 * In the meantime, this pointer is NULL. The
185 * pool is used for all connection-related data
186 * except for the response (which maybe shared between
187 * connections) and the IP address (which persists
188 * across individual requests).
189 */
190 struct MemoryPool * pool;
191
192 /**
193 * Request method. Should be GET/POST/etc. Allocated
194 * in pool.
170 */ 195 */
171 char * method; 196 char * method;
172 197
173 /** 198 /**
174 * Requested URL (everything after "GET" only). 199 * Requested URL (everything after "GET" only). Allocated
200 * in pool.
175 */ 201 */
176 char * url; 202 char * url;
177 203
178 /** 204 /**
179 * HTTP version string (i.e. http/1.1) 205 * HTTP version string (i.e. http/1.1). Allocated
206 * in pool.
180 */ 207 */
181 char * version; 208 char * version;
182 209
183 /** 210 /**
184 * Buffer for reading requests. 211 * Buffer for reading requests. Allocated
212 * in pool.
185 */ 213 */
186 char * read_buffer; 214 char * read_buffer;
187 215
188 /** 216 /**
189 * Buffer for writing response. 217 * Buffer for writing response (headers only). Allocated
218 * in pool.
190 */ 219 */
191 char * write_buffer; 220 char * write_buffer;
192 221
193 /** 222 /**
194 * Foreign address (of length addr_len). 223 * Foreign address (of length addr_len). MALLOCED (not
224 * in pool!).
195 */ 225 */
196 struct sockaddr_in * addr; 226 struct sockaddr_in * addr;
197 227
@@ -201,12 +231,30 @@ struct MHD_Connection {
201 */ 231 */
202 pthread_t pid; 232 pthread_t pid;
203 233
234 /**
235 * Size of read_buffer (in bytes).
236 */
204 size_t read_buffer_size; 237 size_t read_buffer_size;
205 238
239 /**
240 * Position where we currently append data in
241 * read_buffer (last valid position).
242 */
206 size_t readLoc; 243 size_t readLoc;
207 244
245 /**
246 * Size of write_buffer (in bytes).
247 */
208 size_t write_buffer_size; 248 size_t write_buffer_size;
209 249
250 /**
251 * Offset where we are with sending from write_buffer.
252 */
253 size_t writePos;
254
255 /**
256 * Last valid location in write_buffer.
257 */
210 size_t writeLoc; 258 size_t writeLoc;
211 259
212 /** 260 /**
@@ -264,6 +312,11 @@ struct MHD_Connection {
264 int headersSent; 312 int headersSent;
265 313
266 /** 314 /**
315 * Are we processing the POST data?
316 */
317 int post_processed;
318
319 /**
267 * HTTP response code. Only valid if response object 320 * HTTP response code. Only valid if response object
268 * is already set. 321 * is already set.
269 */ 322 */
@@ -279,6 +332,9 @@ struct MHD_Daemon {
279 332
280 struct MHD_Access_Handler default_handler; 333 struct MHD_Access_Handler default_handler;
281 334
335 /**
336 * Linked list of our current connections.
337 */
282 struct MHD_Connection * connections; 338 struct MHD_Connection * connections;
283 339
284 MHD_AcceptPolicyCallback apc; 340 MHD_AcceptPolicyCallback apc;
@@ -301,11 +357,24 @@ struct MHD_Daemon {
301 int shutdown; 357 int shutdown;
302 358
303 /** 359 /**
360 * Size of the per-connection memory pools.
361 */
362 unsigned int pool_size;
363
364 /**
365 * Limit on the number of parallel connections.
366 */
367 unsigned int max_connections;
368
369 /**
304 * Daemon's options. 370 * Daemon's options.
305 */ 371 */
306 enum MHD_OPTION options; 372 enum MHD_OPTION options;
307 373
308 unsigned short port; 374 /**
375 * Listen port.
376 */
377 unsigned short port;
309 378
310}; 379};
311 380
diff --git a/src/daemon/memorypool.c b/src/daemon/memorypool.c
new file mode 100644
index 00000000..5b54cd2e
--- /dev/null
+++ b/src/daemon/memorypool.c
@@ -0,0 +1,180 @@
1/*
2 This file is part of libmicrohttpd
3 (C) 2007 Daniel Pittman
4
5 libmicrohttpd is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 2, or (at your
8 option) any later version.
9
10 libmicrohttpd is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with libmicrohttpd; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA.
19*/
20
21/**
22 * @file memorypool.c
23 * @brief memory pool
24 * @author Christian Grothoff
25 */
26
27#include "memorypool.h"
28
29struct MemoryPool {
30
31 /**
32 * Pointer to the pool's memory
33 */
34 char * memory;
35
36 /**
37 * Size of the pool.
38 */
39 unsigned int size;
40
41 /**
42 * Offset of the first unallocated byte.
43 */
44 unsigned int pos;
45
46 /**
47 * Offset of the last unallocated byte.
48 */
49 unsigned int end;
50
51 /**
52 * 0 if pool was malloc'ed, 1 if mmapped.
53 */
54 int is_mmap;
55};
56
57/**
58 * Create a memory pool.
59 *
60 * @param max maximum size of the pool
61 */
62struct MemoryPool * MHD_pool_create(unsigned int max) {
63 struct MemoryPool * pool;
64
65 pool = malloc(sizeof(struct MemoryPool));
66 if (pool == NULL)
67 return NULL;
68 pool->memory = MMAP(NULL, max, PROT_READ | PROT_WRITE,
69 MAP_ANONYMOUS, -1, 0);
70 if ( (pool->memory == MAP_FAILED) ||
71 (pool->memory == NULL) ) {
72 pool->memory = malloc(max);
73 if (pool->memory == NULL) {
74 free(pool);
75 return NULL;
76 }
77 pool->is_mmap = 0;
78 } else {
79 pool->is_mmap = 1;
80 }
81 pool->pos = 0;
82 pool->end = max;
83 pool->size = max;
84 return pool;
85}
86
87/**
88 * Destroy a memory pool.
89 */
90void MHD_pool_destroy(struct MemoryPool * pool) {
91 if (pool == NULL)
92 return;
93 if (pool->is_mmap == 0)
94 free(pool->memory);
95 else
96 MUNMAP(pool->memory, pool->size);
97 free(pool);
98}
99
100/**
101 * Allocate size bytes from the pool.
102 * @return NULL if the pool cannot support size more
103 * bytes
104 */
105void * MHD_pool_allocate(struct MemoryPool * pool,
106 unsigned int size,
107 int from_end) {
108 void * ret;
109
110 if ( (pool->pos + size > pool->end) ||
111 (pool->pos + size < pool->pos) )
112 return NULL;
113 if (from_end == MHD_YES) {
114 ret = &pool->memory[pool->end - size];
115 pool->end -= size;
116 } else {
117 ret = &pool->memory[pool->pos];
118 pool->pos += size;
119 }
120 return ret;
121}
122
123/**
124 * Reallocate a block of memory obtained from the pool.
125 * This is particularly efficient when growing or
126 * shrinking the block that was last (re)allocated.
127 * If the given block is not the most recenlty
128 * (re)allocated block, the memory of the previous
129 * allocation may be leaked until the pool is
130 * destroyed (and copying the data maybe required).
131 *
132 * @param old the existing block
133 * @param old_size the size of the existing block
134 * @param new_size the new size of the block
135 * @return new address of the block, or
136 * NULL if the pool cannot support new_size
137 * bytes (old continues to be valid for old_size)
138 */
139void * MHD_pool_reallocate(struct MemoryPool * pool,
140 void * old,
141 unsigned int old_size,
142 unsigned int new_size) {
143 void * ret;
144
145 if ( (pool->end < old_size) ||
146 (pool->end < new_size) )
147 return NULL; /* unsatisfiable or bogus request */
148
149 if ( (pool->pos >= old_size) &&
150 (&pool->memory[pool->pos - old_size] == old) ) {
151 /* was the previous allocation - optimize! */
152 if (pool->pos + new_size - old_size <= pool->end) {
153 /* fits */
154 pool->pos += new_size - old_size;
155 if (new_size < old_size) /* shrinking - zero again! */
156 memset(&pool->memory[pool->pos],
157 0,
158 old_size - new_size);
159 return old;
160 }
161 /* does not fit */
162 return NULL;
163 }
164 if (new_size <= old_size)
165 return old; /* cannot shrink, no need to move */
166 if ( (pool->pos + new_size >= pool->pos) &&
167 (pool->pos + new_size <= pool->end) ) {
168 /* fits */
169 ret = &pool->memory[pool->pos];
170 memcpy(ret,
171 old,
172 old_size);
173 pool->pos += new_size;
174 return ret;
175 }
176 /* does not fit */
177 return NULL;
178}
179
180/* end of memorypool.c */
diff --git a/src/daemon/memorypool.h b/src/daemon/memorypool.h
new file mode 100644
index 00000000..c49e0d8e
--- /dev/null
+++ b/src/daemon/memorypool.h
@@ -0,0 +1,87 @@
1/*
2 This file is part of libmicrohttpd
3 (C) 2007 Daniel Pittman
4
5 libmicrohttpd is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 2, or (at your
8 option) any later version.
9
10 libmicrohttpd is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with libmicrohttpd; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA.
19*/
20
21/**
22 * @file memorypool.h
23 * @brief memory pool; mostly used for efficient (de)allocation
24 * for each connection and bounding memory use for each
25 * request
26 * @author Christian Grothoff
27 */
28
29#ifndef MEMORYPOOL_H
30#define MEMORYPOOL_H
31
32#include "internal.h"
33
34/**
35 * Opaque handle for a memory pool.
36 * Pools are not reentrant and must not be used
37 * by multiple threads.
38 */
39struct MemoryPool;
40
41/**
42 * Create a memory pool.
43 *
44 * @param max maximum size of the pool
45 */
46struct MemoryPool * MHD_pool_create(unsigned int max);
47
48/**
49 * Destroy a memory pool.
50 */
51void MHD_pool_destroy(struct MemoryPool * pool);
52
53/**
54 * Allocate size bytes from the pool.
55 *
56 * @param from_end allocate from end of pool (set to MHD_YES);
57 * use this for small, persistent allocations that
58 * will never be reallocated
59 * @return NULL if the pool cannot support size more
60 * bytes
61 */
62void * MHD_pool_allocate(struct MemoryPool * pool,
63 unsigned int size,
64 int from_end);
65
66/**
67 * Reallocate a block of memory obtained from the pool.
68 * This is particularly efficient when growing or
69 * shrinking the block that was last (re)allocated.
70 * If the given block is not the most recenlty
71 * (re)allocated block, the memory of the previous
72 * allocation may be leaked until the pool is
73 * destroyed (and copying the data maybe required).
74 *
75 * @param old the existing block
76 * @param old_size the size of the existing block
77 * @param new_size the new size of the block
78 * @return new address of the block, or
79 * NULL if the pool cannot support new_size
80 * bytes (old continues to be valid for old_size)
81 */
82void * MHD_pool_reallocate(struct MemoryPool * pool,
83 void * old,
84 unsigned int old_size,
85 unsigned int new_size);
86
87#endif
diff --git a/src/include/microhttpd.h b/src/include/microhttpd.h
index 01f31ca2..5efaca09 100644
--- a/src/include/microhttpd.h
+++ b/src/include/microhttpd.h
@@ -187,7 +187,24 @@ extern "C" {
187#define MHD_HTTP_VERSION_1_0 "HTTP/1.0" 187#define MHD_HTTP_VERSION_1_0 "HTTP/1.0"
188#define MHD_HTTP_VERSION_1_1 "HTTP/1.1" 188#define MHD_HTTP_VERSION_1_1 "HTTP/1.1"
189 189
190/**
191 * HTTP methods
192 */
193#define MHD_HTTP_METHOD_CONNECT "CONNECT"
194#define MHD_HTTP_METHOD_DELETE "DELETE"
195#define MHD_HTTP_METHOD_GET "GET"
196#define MHD_HTTP_METHOD_HEAD "HEAD"
197#define MHD_HTTP_METHOD_OPTIONS "OPTIONS"
198#define MHD_HTTP_METHOD_POST "POST"
199#define MHD_HTTP_METHOD_PUT "PUT"
200#define MHD_HTTP_METHOD_TRACE "TRACE"
190 201
202/**
203 * HTTP POST encodings, see also
204 * http://www.w3.org/TR/html4/interact/forms.html#h-17.13.4
205 */
206#define MHD_HTTP_POST_ENCODING_FORM_URLENCODED "application/x-www-form-urlencoded"
207#define MHD_HTTP_POST_ENCODING_MULTIPART_FORMDATA "multipart/form-data"
191 208
192/** 209/**
193 * Options for the MHD daemon. Note that if neither 210 * Options for the MHD daemon. Note that if neither
@@ -248,8 +265,16 @@ enum MHD_OPTION {
248 MHD_OPTION_END = 0, 265 MHD_OPTION_END = 0,
249 266
250 /** 267 /**
251 * FIXME: add options for buffer sizes here... 268 * Maximum memory size per connection (followed by an
269 * unsigned int).
270 */
271 MHD_OPTION_CONNECTION_MEMORY_LIMIT = 1,
272
273 /**
274 * Maximum number of concurrenct connections to
275 * accept (followed by an unsigned int).
252 */ 276 */
277 MHD_OPTION_CONNECTION_LIMIT = 2,
253 278
254}; 279};
255 280
@@ -265,22 +290,28 @@ enum MHD_ValueKind {
265 MHD_RESPONSE_HEADER_KIND = 0, 290 MHD_RESPONSE_HEADER_KIND = 0,
266 291
267 /** 292 /**
268 * HTTP header 293 * HTTP header.
269 */ 294 */
270 MHD_HEADER_KIND = 1, 295 MHD_HEADER_KIND = 1,
271 296
272 /** 297 /**
273 * Cookies 298 * Cookies. Note that the original HTTP header containing
299 * the cookie(s) will still be available and intact.
274 */ 300 */
275 MHD_COOKIE_KIND = 2, 301 MHD_COOKIE_KIND = 2,
276 302
277 /** 303 /**
278 * POST data 304 * POST data. This is available only if a content encoding
305 * supported by MHD is used (currently only URL encoding),
306 * and only if the posted content fits within the available
307 * memory pool. Note that in that case, the upload data
308 * given to the MHD_AccessHandlerCallback will be
309 * empty (since it has already been processed).
279 */ 310 */
280 MHD_POSTDATA_KIND = 4, 311 MHD_POSTDATA_KIND = 4,
281 312
282 /** 313 /**
283 * GET (URI) arguments 314 * GET (URI) arguments.
284 */ 315 */
285 MHD_GET_ARGUMENT_KIND = 8, 316 MHD_GET_ARGUMENT_KIND = 8,
286 317
@@ -326,9 +357,16 @@ typedef int
326 * @param url the requested url 357 * @param url the requested url
327 * @param method the HTTP method used ("GET", "PUT", etc.) 358 * @param method the HTTP method used ("GET", "PUT", etc.)
328 * @param version the HTTP version string (i.e. "HTTP/1.1") 359 * @param version the HTTP version string (i.e. "HTTP/1.1")
360 * @param upload_data the data being uploaded (excluding HEADERS,
361 * for a POST that fits into memory and that is encoded
362 * with a supported encoding, the POST data will NOT be
363 * given in upload_data and is instead available as
364 * part of MHD_get_connection_values; very large POST
365 * data *will* be made available incrementally in
366 * upload_data)
329 * @param upload_data_size set initially to the size of the 367 * @param upload_data_size set initially to the size of the
330 * upload_data provided; the method must update this 368 * upload_data provided; the method must update this
331 * value to the number of bytes NOT processed 369 * value to the number of bytes NOT processed;
332 * @return MHS_YES if the connection was handled successfully, 370 * @return MHS_YES if the connection was handled successfully,
333 * MHS_NO if the socket must be closed due to a serios 371 * MHS_NO if the socket must be closed due to a serios
334 * error while handling the request 372 * error while handling the request