aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/daemon/Makefile.am13
-rw-r--r--src/daemon/connection.c1845
-rw-r--r--src/daemon/connection.h25
-rw-r--r--src/daemon/daemon.c169
-rw-r--r--src/daemon/daemontest_get.c20
-rw-r--r--src/daemon/daemontest_large_put.c37
-rw-r--r--src/daemon/daemontest_postform.c9
-rw-r--r--src/daemon/daemontest_put_chunked.c5
-rw-r--r--src/daemon/fileserver_example.c10
-rw-r--r--src/daemon/internal.h201
-rw-r--r--src/daemon/memorypool.c29
-rw-r--r--src/daemon/memorypool.h12
-rw-r--r--src/daemon/minimal_example.c10
-rw-r--r--src/include/microhttpd.h47
14 files changed, 1499 insertions, 933 deletions
diff --git a/src/daemon/Makefile.am b/src/daemon/Makefile.am
index 4902dc52..30ec59f1 100644
--- a/src/daemon/Makefile.am
+++ b/src/daemon/Makefile.am
@@ -12,7 +12,7 @@ lib_LTLIBRARIES = \
12 libmicrohttpd.la 12 libmicrohttpd.la
13 13
14libmicrohttpd_la_LDFLAGS = \ 14libmicrohttpd_la_LDFLAGS = \
15 -export-dynamic -version-info 2:1:1 $(retaincommand) 15 -export-dynamic -version-info 3:0:0 $(retaincommand)
16libmicrohttpd_la_SOURCES = \ 16libmicrohttpd_la_SOURCES = \
17 connection.c connection.h \ 17 connection.c connection.h \
18 reason_phrase.c reason_phrase.h \ 18 reason_phrase.c reason_phrase.h \
@@ -48,7 +48,6 @@ check_PROGRAMS = \
48 daemontest_postform \ 48 daemontest_postform \
49 daemontest_post_loop \ 49 daemontest_post_loop \
50 daemontest_put \ 50 daemontest_put \
51 daemontest_put_chunked \
52 daemontest_large_put \ 51 daemontest_large_put \
53 daemontest_get11 \ 52 daemontest_get11 \
54 daemontest_post11 \ 53 daemontest_post11 \
@@ -56,7 +55,9 @@ check_PROGRAMS = \
56 daemontest_post_loop11 \ 55 daemontest_post_loop11 \
57 daemontest_put11 \ 56 daemontest_put11 \
58 daemontest_large_put11 \ 57 daemontest_large_put11 \
59 daemontest_long_header 58 daemontest_long_header \
59 daemontest_get_chunked \
60 daemontest_put_chunked
60 61
61TESTS = $(check_PROGRAMS) 62TESTS = $(check_PROGRAMS)
62 63
@@ -71,6 +72,12 @@ daemontest_get_LDADD = \
71 $(top_builddir)/src/daemon/libmicrohttpd.la \ 72 $(top_builddir)/src/daemon/libmicrohttpd.la \
72 @LIBCURL@ 73 @LIBCURL@
73 74
75daemontest_get_chunked_SOURCES = \
76 daemontest_get_chunked.c
77daemontest_get_chunked_LDADD = \
78 $(top_builddir)/src/daemon/libmicrohttpd.la \
79 @LIBCURL@
80
74daemontest_post_SOURCES = \ 81daemontest_post_SOURCES = \
75 daemontest_post.c 82 daemontest_post.c
76daemontest_post_LDADD = \ 83daemontest_post_LDADD = \
diff --git a/src/daemon/connection.c b/src/daemon/connection.c
index 318439a8..d07a2544 100644
--- a/src/daemon/connection.c
+++ b/src/daemon/connection.c
@@ -2,7 +2,6 @@
2 This file is part of libmicrohttpd 2 This file is part of libmicrohttpd
3 (C) 2007 Daniel Pittman and Christian Grothoff 3 (C) 2007 Daniel Pittman and Christian Grothoff
4 4
5
6 This library is free software; you can redistribute it and/or 5 This library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Lesser General Public 6 modify it under the terms of the GNU Lesser General Public
8 License as published by the Free Software Foundation; either 7 License as published by the Free Software Foundation; either
@@ -62,6 +61,14 @@
62 */ 61 */
63#define REQUEST_LACKS_HOST "" 62#define REQUEST_LACKS_HOST ""
64 63
64#define EXTRA_CHECKS MHD_YES
65
66#if EXTRA_CHECKS
67#define EXTRA_CHECK(a) if (!(a)) abort();
68#else
69#define EXTRA_CHECK(a)
70#endif
71
65/** 72/**
66 * Add extra debug messages with reasons for closing connections 73 * Add extra debug messages with reasons for closing connections
67 * (non-error reasons). 74 * (non-error reasons).
@@ -73,6 +80,10 @@
73 */ 80 */
74#define DEBUG_SEND_DATA MHD_NO 81#define DEBUG_SEND_DATA MHD_NO
75 82
83/**
84 * Should all state transitions be printed to stderr?
85 */
86#define DEBUG_STATES MHD_NO
76 87
77/** 88/**
78 * Get all of the headers from the request. 89 * Get all of the headers from the request.
@@ -109,7 +120,6 @@ MHD_get_connection_values (struct MHD_Connection *connection,
109 return ret; 120 return ret;
110} 121}
111 122
112
113/** 123/**
114 * Get a particular header value. If multiple 124 * Get a particular header value. If multiple
115 * values match the kind, return any one of them. 125 * values match the kind, return any one of them.
@@ -149,11 +159,11 @@ int
149MHD_queue_response (struct MHD_Connection *connection, 159MHD_queue_response (struct MHD_Connection *connection,
150 unsigned int status_code, struct MHD_Response *response) 160 unsigned int status_code, struct MHD_Response *response)
151{ 161{
152 if ((connection == NULL) || 162 if ( (connection == NULL) ||
153 (response == NULL) || 163 (response == NULL) ||
154 (connection->response != NULL) || 164 (connection->response != NULL) ||
155 (connection->have_received_body == MHD_NO) 165 ( (connection->state != MHD_CONNECTION_HEADERS_PROCESSED) &&
156 || (connection->have_received_headers == MHD_NO)) 166 (connection->state != MHD_CONNECTION_FOOTERS_RECEIVED) ) )
157 return MHD_NO; 167 return MHD_NO;
158 MHD_increment_response_rc (response); 168 MHD_increment_response_rc (response);
159 connection->response = response; 169 connection->response = response;
@@ -165,6 +175,21 @@ MHD_queue_response (struct MHD_Connection *connection,
165 have already sent the full message body */ 175 have already sent the full message body */
166 connection->response_write_position = response->total_size; 176 connection->response_write_position = response->total_size;
167 } 177 }
178 if ( (response->total_size == -1) &&
179 (0 == strcasecmp(connection->version,
180 MHD_HTTP_VERSION_1_1)) )
181 connection->have_chunked_response = MHD_YES;
182 else
183 connection->have_chunked_response = MHD_NO;
184 if (connection->state == MHD_CONNECTION_HEADERS_PROCESSED)
185 {
186 /* response was queued "early",
187 refuse to read body / footers or further
188 requests! */
189 SHUTDOWN (connection->socket_fd, SHUT_RD);
190 connection->read_closed = MHD_YES;
191 connection->state = MHD_CONNECTION_FOOTERS_RECEIVED;
192 }
168 return MHD_YES; 193 return MHD_YES;
169} 194}
170 195
@@ -173,14 +198,14 @@ MHD_queue_response (struct MHD_Connection *connection,
173 * message for this connection? 198 * message for this connection?
174 */ 199 */
175static int 200static int
176MHD_need_100_continue (struct MHD_Connection *connection) 201need_100_continue (struct MHD_Connection *connection)
177{ 202{
178 const char *expect; 203 const char *expect;
179 204
180 return ((connection->version != NULL) && 205 return ((connection->response == NULL) &&
206 (connection->version != NULL) &&
181 (0 == strcasecmp (connection->version, 207 (0 == strcasecmp (connection->version,
182 MHD_HTTP_VERSION_1_1)) && 208 MHD_HTTP_VERSION_1_1)) &&
183 (connection->have_received_headers == MHD_YES) &&
184 (NULL != (expect = MHD_lookup_connection_value (connection, 209 (NULL != (expect = MHD_lookup_connection_value (connection,
185 MHD_HEADER_KIND, 210 MHD_HEADER_KIND,
186 MHD_HTTP_HEADER_EXPECT))) 211 MHD_HTTP_HEADER_EXPECT)))
@@ -199,6 +224,7 @@ connection_close_error (struct MHD_Connection *connection)
199 SHUTDOWN (connection->socket_fd, SHUT_RDWR); 224 SHUTDOWN (connection->socket_fd, SHUT_RDWR);
200 CLOSE (connection->socket_fd); 225 CLOSE (connection->socket_fd);
201 connection->socket_fd = -1; 226 connection->socket_fd = -1;
227 connection->state = MHD_CONNECTION_CLOSED;
202 if (connection->daemon->notify_completed != NULL) 228 if (connection->daemon->notify_completed != NULL)
203 connection->daemon->notify_completed (connection->daemon-> 229 connection->daemon->notify_completed (connection->daemon->
204 notify_completed_cls, connection, 230 notify_completed_cls, connection,
@@ -216,12 +242,14 @@ connection_close_error (struct MHD_Connection *connection)
216 * @return MHD_NO if readying the response failed 242 * @return MHD_NO if readying the response failed
217 */ 243 */
218static int 244static int
219ready_response (struct MHD_Connection *connection) 245try_ready_normal_body (struct MHD_Connection *connection)
220{ 246{
221 int ret; 247 int ret;
222 struct MHD_Response *response; 248 struct MHD_Response *response;
223 249
224 response = connection->response; 250 response = connection->response;
251 if (response->crc == NULL)
252 return MHD_YES;
225 ret = response->crc (response->crc_cls, 253 ret = response->crc (response->crc_cls,
226 connection->response_write_position, 254 connection->response_write_position,
227 response->data, 255 response->data,
@@ -230,7 +258,8 @@ ready_response (struct MHD_Connection *connection)
230 connection->response_write_position)); 258 connection->response_write_position));
231 if (ret == -1) 259 if (ret == -1)
232 { 260 {
233 /* end of message, signal other side by closing! */ 261 /* either error or http 1.0 transfer, close
262 socket! */
234#if DEBUG_CLOSE 263#if DEBUG_CLOSE
235#if HAVE_MESSAGES 264#if HAVE_MESSAGES
236 MHD_DLOG (connection->daemon, "Closing connection (end of response)\n"); 265 MHD_DLOG (connection->daemon, "Closing connection (end of response)\n");
@@ -239,94 +268,281 @@ ready_response (struct MHD_Connection *connection)
239 response->total_size = connection->response_write_position; 268 response->total_size = connection->response_write_position;
240 connection_close_error (connection); 269 connection_close_error (connection);
241 return MHD_NO; 270 return MHD_NO;
242 } 271 }
243 response->data_start = connection->response_write_position; 272 response->data_start = connection->response_write_position;
244 response->data_size = ret; 273 response->data_size = ret;
245 if (ret == 0) 274 if (ret == 0)
275 return MHD_NO;
276 return MHD_YES;
277}
278
279/**
280 * Prepare the response buffer of this connection for
281 * sending. Assumes that the response mutex is
282 * already held. If the transmission is complete,
283 * this function may close the socket (and return
284 * MHD_NO).
285 *
286 * @return MHD_NO if readying the response failed
287 */
288static int
289try_ready_chunked_body (struct MHD_Connection *connection)
290{
291 int ret;
292 char * buf;
293 struct MHD_Response *response;
294 unsigned int size;
295 char cbuf[9];
296
297 response = connection->response;
298 if (connection->write_buffer_size == 0)
246 { 299 {
247 /* avoid busy-waiting when using external select 300 size = connection->daemon->pool_size;
248 (we assume that the main application will 301 do
249 wake up the external select once more data 302 {
250 is ready). With internal selects, we 303 size /= 2;
251 have no choice; if the app uses a thread 304 if (size < 128)
252 per connection, ret==0 is likely a bug -- 305 {
253 the application should block until data 306 /* not enough memory */
254 is ready! */ 307#if DEBUG_CLOSE
255 if ((0 == 308#if HAVE_MESSAGES
256 (connection->daemon-> 309 MHD_DLOG (connection->daemon, "Closing connection (out of memory)\n");
257 options & (MHD_USE_SELECT_INTERNALLY | 310#endif
258 MHD_USE_THREAD_PER_CONNECTION)))) 311#endif
259 connection->response_unready = MHD_YES; 312 connection_close_error (connection);
313 return MHD_NO;
314 }
315 buf = MHD_pool_allocate (connection->pool,
316 size,
317 MHD_NO);
318 }
319 while (buf == NULL);
320 connection->write_buffer_size = size;
321 connection->write_buffer = buf;
322 }
323
324 ret = response->crc (response->crc_cls,
325 connection->response_write_position,
326 &connection->write_buffer[8],
327 connection->write_buffer_size - 8 - 2);
328 if (ret == -1)
329 {
330 /* end of message, signal other side! */
331 strcpy(connection->write_buffer,
332 "0\r\n");
333 connection->write_buffer_append_offset = 3;
334 connection->write_buffer_send_offset = 0;
335 response->total_size = connection->response_write_position;
336 return MHD_YES;
337 }
338 if (ret == 0)
339 {
340 connection->state = MHD_CONNECTION_CHUNKED_BODY_UNREADY;
260 return MHD_NO; 341 return MHD_NO;
261 } 342 }
262 connection->response_unready = MHD_NO; 343 if (ret > 0xFFFFFF)
344 ret = 0xFFFFFF;
345 snprintf(cbuf,
346 8,
347 "%X\r\n",
348 ret);
349 memcpy(&connection->write_buffer[8 - strlen(cbuf)],
350 cbuf,
351 strlen(cbuf));
352 memcpy(&connection->write_buffer[8 + ret],
353 "\r\n",
354 2);
355 connection->response_write_position += ret;
356 connection->write_buffer_send_offset = 8 - strlen(cbuf);
357 connection->write_buffer_append_offset = 8 + ret + 2;
263 return MHD_YES; 358 return MHD_YES;
264} 359}
265 360
266/** 361/**
267 * Obtain the select sets for this connection 362 * Check if we need to set some additional headers
268 * 363 * for http-compiliance.
269 * @return MHD_YES on success
270 */ 364 */
271int 365static void
272MHD_connection_get_fdset (struct MHD_Connection *connection, 366add_extra_headers (struct MHD_Connection *connection)
273 fd_set * read_fd_set,
274 fd_set * write_fd_set,
275 fd_set * except_fd_set, int *max_fd)
276{ 367{
277 int fd; 368 const char *have;
278 void *buf; 369 char buf[128];
279 370
280 fd = connection->socket_fd; 371 connection->have_chunked_upload = MHD_NO;
281 if (fd == -1) 372 if (connection->response->total_size == -1)
282 return MHD_YES; 373 {
283 if ((connection->read_close == MHD_NO) && 374 have = MHD_get_response_header (connection->response,
284 ((connection->have_received_headers == MHD_NO) || 375 MHD_HTTP_HEADER_CONNECTION);
285 (connection->read_buffer_offset < connection->read_buffer_size))) 376 if ( (have == NULL) ||
377 (0 != strcasecmp(have, "close")) )
378 {
379 if ( (connection->version != NULL) &&
380 (0 == strcasecmp(connection->version,
381 MHD_HTTP_VERSION_1_1)) )
382 {
383 connection->have_chunked_upload = MHD_YES;
384 have = MHD_get_response_header (connection->response,
385 MHD_HTTP_HEADER_TRANSFER_ENCODING);
386 if (have == NULL)
387 MHD_add_response_header (connection->response,
388 MHD_HTTP_HEADER_TRANSFER_ENCODING,
389 "chunked");
390 }
391 else
392 {
393 MHD_add_response_header (connection->response,
394 MHD_HTTP_HEADER_CONNECTION, "close");
395 }
396 }
397 }
398 else if (NULL == MHD_get_response_header (connection->response,
399 MHD_HTTP_HEADER_CONTENT_LENGTH))
286 { 400 {
287 FD_SET (fd, read_fd_set); 401 _REAL_SNPRINTF (buf,
288 if (fd > *max_fd) 402 128,
289 *max_fd = fd; 403 "%llu",
404 (unsigned long long) connection->response->total_size);
405 MHD_add_response_header (connection->response,
406 MHD_HTTP_HEADER_CONTENT_LENGTH, buf);
407 }
408}
409
410/**
411 * Produce HTTP "Date:" header.
412 * @param date where to write the header
413 * @param max maximum number of characters to write
414 */
415static void
416get_date_string (char *date, unsigned int max)
417{
418 static const char *days[] =
419 { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" };
420 static const char *mons[] =
421 { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct",
422 "Nov", "Dec"
423 };
424 struct tm now;
425 time_t t;
426
427 time (&t);
428 gmtime_r (&t, &now);
429 snprintf (date,
430 max - 1,
431 "Date: %3s, %02u %3s %04u %02u:%02u:%02u GMT\r\n",
432 days[now.tm_wday % 7],
433 now.tm_mday,
434 mons[now.tm_mon % 12],
435 now.tm_year, now.tm_hour, now.tm_min, now.tm_sec);
436}
437
438/**
439 * try growing the read buffer
440 * @return MHD_YES on success, MHD_NO on failure
441 */
442static int
443try_grow_read_buffer(struct MHD_Connection * connection)
444{
445 void * buf;
446
447 buf = MHD_pool_reallocate (connection->pool,
448 connection->read_buffer,
449 connection->read_buffer_size,
450 connection->read_buffer_size * 2 +
451 MHD_BUF_INC_SIZE + 1);
452 if (buf == NULL)
453 return MHD_NO;
454 /* we can actually grow the buffer, do it! */
455 connection->read_buffer = buf;
456 connection->read_buffer_size =
457 connection->read_buffer_size * 2 + MHD_BUF_INC_SIZE;
458 return MHD_YES;
459}
460
461/**
462 * Allocate the connection's write buffer and
463 * fill it with all of the headers (or footers,
464 * if we have already sent the body) from the
465 * HTTPd's response.
466 */
467static int
468build_header_response (struct MHD_Connection *connection)
469{
470 size_t size;
471 size_t off;
472 struct MHD_HTTP_Header *pos;
473 char code[128];
474 char date[128];
475 char *data;
476 enum MHD_ValueKind kind;
477 const char *reason_phrase;
478
479 if (connection->state == MHD_CONNECTION_FOOTERS_RECEIVED)
480 {
481 add_extra_headers (connection);
482 reason_phrase =
483 MHD_get_reason_phrase_for (connection->responseCode);
484 _REAL_SNPRINTF (code, 128, "%s %u %s\r\n", MHD_HTTP_VERSION_1_1,
485 connection->responseCode, reason_phrase);
486 off = strlen (code);
487 /* estimate size */
488 size = off + 2; /* extra \r\n at the end */
489 kind = MHD_HEADER_KIND;
490 if (NULL == MHD_get_response_header (connection->response,
491 MHD_HTTP_HEADER_DATE))
492 get_date_string (date, sizeof (date));
493 else
494 date[0] = '\0';
495 size += strlen (date);
290 } 496 }
291 else 497 else
292 { 498 {
293 if ((connection->read_close == MHD_NO) && 499 size = 2;
294 ((connection->have_received_headers == MHD_YES) && 500 kind = MHD_FOOTER_KIND;
295 (connection->read_buffer_offset == connection->read_buffer_size))) 501 off = 0;
296 { 502 }
297 /* try growing the read buffer, just in case */ 503 pos = connection->response->first_header;
298 buf = MHD_pool_reallocate (connection->pool, 504 while (pos != NULL)
299 connection->read_buffer, 505 {
300 connection->read_buffer_size, 506 if (pos->kind == kind)
301 connection->read_buffer_size * 2 + 507 size += strlen (pos->header) + strlen (pos->value) + 4; /* colon, space, linefeeds */
302 MHD_BUF_INC_SIZE); 508 pos = pos->next;
303 if (buf != NULL) 509 }
304 { 510 /* produce data */
305 /* we can actually grow the buffer, do it! */ 511 data = MHD_pool_allocate (connection->pool, size + 1, MHD_YES);
306 connection->read_buffer = buf; 512 if (data == NULL)
307 connection->read_buffer_size = 513 {
308 connection->read_buffer_size * 2 + MHD_BUF_INC_SIZE; 514#if HAVE_MESSAGES
309 FD_SET (fd, read_fd_set); 515 MHD_DLOG (connection->daemon, "Not enough memory for write!\n");
310 if (fd > *max_fd) 516#endif
311 *max_fd = fd; 517 return MHD_NO;
312 } 518 }
313 } 519 if (connection->state == MHD_CONNECTION_FOOTERS_RECEIVED)
520 {
521 memcpy (data, code, off);
314 } 522 }
315 if ((connection->response != NULL) && 523 pos = connection->response->first_header;
316 (connection->response_unready == MHD_YES)) 524 while (pos != NULL)
317 { 525 {
318 pthread_mutex_lock (&connection->response->mutex); 526 if (pos->kind == kind)
319 ready_response (connection); 527 {
320 pthread_mutex_unlock (&connection->response->mutex); 528 SPRINTF (&data[off], "%s: %s\r\n", pos->header, pos->value);
529 off += strlen (pos->header) + strlen (pos->value) + 4;
530 }
531 pos = pos->next;
321 } 532 }
322 if (((connection->response != NULL) && 533 if (connection->state == MHD_CONNECTION_FOOTERS_RECEIVED)
323 (connection->response_unready == MHD_NO)) ||
324 MHD_need_100_continue (connection))
325 { 534 {
326 FD_SET (fd, write_fd_set); 535 strcpy (&data[off], date);
327 if (fd > *max_fd) 536 off += strlen (date);
328 *max_fd = fd;
329 } 537 }
538 sprintf (&data[off], "\r\n");
539 off += 2;
540 if (off != size)
541 abort ();
542 connection->write_buffer = data;
543 connection->write_buffer_append_offset = size;
544 connection->write_buffer_send_offset = 0;
545 connection->write_buffer_size = size + 1;
330 return MHD_YES; 546 return MHD_YES;
331} 547}
332 548
@@ -338,15 +554,14 @@ MHD_connection_get_fdset (struct MHD_Connection *connection,
338 * @param status_code the response code to send (413 or 414) 554 * @param status_code the response code to send (413 or 414)
339 */ 555 */
340static void 556static void
341MHD_excessive_data_handler (struct MHD_Connection *connection, 557excessive_data_handler (struct MHD_Connection *connection,
342 unsigned int status_code) 558 unsigned int status_code)
343{ 559{
344 struct MHD_Response *response; 560 struct MHD_Response *response;
345 561
346 /* die, header far too long to be reasonable */ 562 /* die, header far too long to be reasonable */
347 connection->read_close = MHD_YES; 563 connection->state = MHD_CONNECTION_FOOTERS_RECEIVED;
348 connection->have_received_headers = MHD_YES; 564 connection->read_closed = MHD_YES;
349 connection->have_received_body = MHD_YES;
350#if HAVE_MESSAGES 565#if HAVE_MESSAGES
351 MHD_DLOG (connection->daemon, 566 MHD_DLOG (connection->daemon,
352 "Received excessively long header, closing connection.\n"); 567 "Received excessively long header, closing connection.\n");
@@ -354,7 +569,166 @@ MHD_excessive_data_handler (struct MHD_Connection *connection,
354 response = MHD_create_response_from_data (strlen (REQUEST_TOO_BIG), 569 response = MHD_create_response_from_data (strlen (REQUEST_TOO_BIG),
355 REQUEST_TOO_BIG, MHD_NO, MHD_NO); 570 REQUEST_TOO_BIG, MHD_NO, MHD_NO);
356 MHD_queue_response (connection, status_code, response); 571 MHD_queue_response (connection, status_code, response);
572 EXTRA_CHECK(connection->response != NULL);
357 MHD_destroy_response (response); 573 MHD_destroy_response (response);
574 if (MHD_NO == build_header_response (connection))
575 {
576 /* oops - close! */
577#if HAVE_MESSAGES
578 MHD_DLOG (connection->daemon,
579 "Closing connection (failed to create response header)\n");
580#endif
581 connection->state = MHD_CONNECTION_CLOSED;
582 }
583 else
584 {
585 connection->state = MHD_CONNECTION_HEADERS_SENDING;
586 }
587}
588
589/**
590 * Add "fd" to the "fd_set". If "fd" is
591 * greater than "*max", set "*max" to fd.
592 */
593static void
594do_fd_set(int fd,
595 fd_set * set,
596 int * max_fd)
597{
598 FD_SET (fd, set);
599 if (fd > *max_fd)
600 *max_fd = fd;
601}
602
603/**
604 * Obtain the select sets for this connection
605 *
606 * @return MHD_YES on success
607 */
608int
609MHD_connection_get_fdset (struct MHD_Connection *connection,
610 fd_set * read_fd_set,
611 fd_set * write_fd_set,
612 fd_set * except_fd_set, int *max_fd)
613{
614 int fd;
615
616 if (connection->pool == NULL)
617 connection->pool = MHD_pool_create (connection->daemon->pool_size);
618 if (connection->pool == NULL)
619 {
620#if HAVE_MESSAGES
621 MHD_DLOG (connection->daemon, "Failed to create memory pool!\n");
622#endif
623 connection_close_error (connection);
624 return MHD_NO;
625 }
626 fd = connection->socket_fd;
627 if (fd == -1)
628 return MHD_YES;
629 while (1) {
630#if DEBUG_STATES
631 fprintf(stderr,
632 "`%s' in state %u\n",
633 __FUNCTION__,
634 connection->state);
635#endif
636 switch (connection->state)
637 {
638 case MHD_CONNECTION_INIT:
639 case MHD_CONNECTION_URL_RECEIVED:
640 case MHD_CONNECTION_HEADER_PART_RECEIVED:
641 /* while reading headers, we always grow the
642 read buffer if needed, no size-check required */
643 if ( (connection->read_closed) &&
644 (connection->read_buffer_offset == 0) )
645 {
646 connection->state = MHD_CONNECTION_CLOSED;
647 continue;
648 }
649 if ( (connection->read_buffer_offset == connection->read_buffer_size) &&
650 (MHD_NO == try_grow_read_buffer(connection)) )
651 {
652 excessive_data_handler (connection,
653 (connection->url != NULL)
654 ? MHD_HTTP_REQUEST_ENTITY_TOO_LARGE
655 : MHD_HTTP_REQUEST_URI_TOO_LONG);
656 continue;
657 }
658 if (MHD_NO == connection->read_closed)
659 do_fd_set (fd, read_fd_set, max_fd);
660 break;
661 case MHD_CONNECTION_HEADERS_RECEIVED:
662 /* we should never get here */
663 EXTRA_CHECK(0);
664 break;
665 case MHD_CONNECTION_HEADERS_PROCESSED:
666 EXTRA_CHECK(0);
667 break;
668 case MHD_CONNECTION_CONTINUE_SENDING:
669 do_fd_set (fd, write_fd_set, max_fd);
670 break;
671 case MHD_CONNECTION_CONTINUE_SENT:
672 if (connection->read_buffer_offset == connection->read_buffer_size)
673 try_grow_read_buffer(connection);
674 if (connection->read_buffer_offset < connection->read_buffer_size)
675 do_fd_set (fd, read_fd_set, max_fd);
676 break;
677 case MHD_CONNECTION_BODY_RECEIVED:
678 case MHD_CONNECTION_FOOTER_PART_RECEIVED:
679 /* while reading footers, we always grow the
680 read buffer if needed, no size-check required */
681 if (MHD_YES == connection->read_closed)
682 {
683 connection->state = MHD_CONNECTION_CLOSED;
684 continue;
685 }
686 do_fd_set (fd, read_fd_set, max_fd);
687 /* transition to FOOTERS_RECEIVED
688 happens in read handler */
689 break;
690 case MHD_CONNECTION_FOOTERS_RECEIVED:
691 /* no socket action, wait for client
692 to provide response */
693 break;
694 case MHD_CONNECTION_HEADERS_SENDING:
695 /* headers in buffer, keep writing */
696 do_fd_set(fd, write_fd_set, max_fd);
697 break;
698 case MHD_CONNECTION_HEADERS_SENT:
699 EXTRA_CHECK(0);
700 break;
701 case MHD_CONNECTION_NORMAL_BODY_READY:
702 do_fd_set (fd, write_fd_set, max_fd);
703 break;
704 case MHD_CONNECTION_NORMAL_BODY_UNREADY:
705 /* not ready, no socket action */
706 break;
707 case MHD_CONNECTION_CHUNKED_BODY_READY:
708 do_fd_set (fd, write_fd_set, max_fd);
709 break;
710 case MHD_CONNECTION_CHUNKED_BODY_UNREADY:
711 /* not ready, no socket action */
712 break;
713 case MHD_CONNECTION_BODY_SENT:
714 EXTRA_CHECK(0);
715 break;
716 case MHD_CONNECTION_FOOTERS_SENDING:
717 do_fd_set (fd, write_fd_set, max_fd);
718 break;
719 case MHD_CONNECTION_FOOTERS_SENT:
720 EXTRA_CHECK(0);
721 break;
722 case MHD_CONNECTION_CLOSED:
723 if (connection->socket_fd != -1)
724 connection_close_error(connection);
725 return MHD_YES; /* do nothing, not even reading */
726 default:
727 EXTRA_CHECK(0);
728 }
729 break;
730 }
731 return MHD_YES;
358} 732}
359 733
360/** 734/**
@@ -366,7 +740,7 @@ MHD_excessive_data_handler (struct MHD_Connection *connection,
366 * return NULL. Otherwise return a pointer to the line. 740 * return NULL. Otherwise return a pointer to the line.
367 */ 741 */
368static char * 742static char *
369MHD_get_next_header_line (struct MHD_Connection *connection) 743get_next_header_line (struct MHD_Connection *connection)
370{ 744{
371 char *rbuf; 745 char *rbuf;
372 size_t pos; 746 size_t pos;
@@ -390,10 +764,10 @@ MHD_get_next_header_line (struct MHD_Connection *connection)
390 MHD_BUF_INC_SIZE); 764 MHD_BUF_INC_SIZE);
391 if (rbuf == NULL) 765 if (rbuf == NULL)
392 { 766 {
393 MHD_excessive_data_handler (connection, 767 excessive_data_handler (connection,
394 (connection->url != NULL) 768 (connection->url != NULL)
395 ? MHD_HTTP_REQUEST_ENTITY_TOO_LARGE 769 ? MHD_HTTP_REQUEST_ENTITY_TOO_LARGE
396 : MHD_HTTP_REQUEST_URI_TOO_LONG); 770 : MHD_HTTP_REQUEST_URI_TOO_LONG);
397 } 771 }
398 else 772 else
399 { 773 {
@@ -418,8 +792,8 @@ MHD_get_next_header_line (struct MHD_Connection *connection)
418 * @return MHD_NO on failure (out of memory), MHD_YES for success 792 * @return MHD_NO on failure (out of memory), MHD_YES for success
419 */ 793 */
420static int 794static int
421MHD_connection_add_header (struct MHD_Connection *connection, 795connection_add_header (struct MHD_Connection *connection,
422 char *key, char *value, enum MHD_ValueKind kind) 796 char *key, char *value, enum MHD_ValueKind kind)
423{ 797{
424 struct MHD_HTTP_Header *hdr; 798 struct MHD_HTTP_Header *hdr;
425 799
@@ -431,8 +805,8 @@ MHD_connection_add_header (struct MHD_Connection *connection,
431 MHD_DLOG (connection->daemon, 805 MHD_DLOG (connection->daemon,
432 "Not enough memory to allocate header record!\n"); 806 "Not enough memory to allocate header record!\n");
433#endif 807#endif
434 MHD_excessive_data_handler (connection, 808 excessive_data_handler (connection,
435 MHD_HTTP_REQUEST_ENTITY_TOO_LARGE); 809 MHD_HTTP_REQUEST_ENTITY_TOO_LARGE);
436 return MHD_NO; 810 return MHD_NO;
437 } 811 }
438 hdr->next = connection->headers_received; 812 hdr->next = connection->headers_received;
@@ -468,8 +842,8 @@ parse_arguments (enum MHD_ValueKind kind,
468 } 842 }
469 MHD_http_unescape (args); 843 MHD_http_unescape (args);
470 MHD_http_unescape (equals); 844 MHD_http_unescape (equals);
471 if (MHD_NO == MHD_connection_add_header (connection, 845 if (MHD_NO == connection_add_header (connection,
472 args, equals, kind)) 846 args, equals, kind))
473 return MHD_NO; 847 return MHD_NO;
474 args = amper; 848 args = amper;
475 } 849 }
@@ -482,7 +856,7 @@ parse_arguments (enum MHD_ValueKind kind,
482 * @return MHD_YES for success, MHD_NO for failure (malformed, out of memory) 856 * @return MHD_YES for success, MHD_NO for failure (malformed, out of memory)
483 */ 857 */
484static int 858static int
485MHD_parse_cookie_header (struct MHD_Connection *connection) 859parse_cookie_header (struct MHD_Connection *connection)
486{ 860{
487 const char *hdr; 861 const char *hdr;
488 char *cpy; 862 char *cpy;
@@ -500,8 +874,8 @@ MHD_parse_cookie_header (struct MHD_Connection *connection)
500#if HAVE_MESSAGES 874#if HAVE_MESSAGES
501 MHD_DLOG (connection->daemon, "Not enough memory to parse cookies!\n"); 875 MHD_DLOG (connection->daemon, "Not enough memory to parse cookies!\n");
502#endif 876#endif
503 MHD_excessive_data_handler (connection, 877 excessive_data_handler (connection,
504 MHD_HTTP_REQUEST_ENTITY_TOO_LARGE); 878 MHD_HTTP_REQUEST_ENTITY_TOO_LARGE);
505 return MHD_NO; 879 return MHD_NO;
506 } 880 }
507 memcpy (cpy, hdr, strlen (hdr) + 1); 881 memcpy (cpy, hdr, strlen (hdr) + 1);
@@ -536,8 +910,8 @@ MHD_parse_cookie_header (struct MHD_Connection *connection)
536 equals[strlen (equals) - 1] = '\0'; 910 equals[strlen (equals) - 1] = '\0';
537 equals++; 911 equals++;
538 } 912 }
539 if (MHD_NO == MHD_connection_add_header (connection, 913 if (MHD_NO == connection_add_header (connection,
540 pos, equals, MHD_COOKIE_KIND)) 914 pos, equals, MHD_COOKIE_KIND))
541 return MHD_NO; 915 return MHD_NO;
542 pos = semicolon; 916 pos = semicolon;
543 } 917 }
@@ -587,235 +961,29 @@ parse_initial_message_line (struct MHD_Connection *connection, char *line)
587 return MHD_YES; 961 return MHD_YES;
588} 962}
589 963
590
591/**
592 * This function is designed to parse the input buffer of a given
593 * connection for HTTP headers -- and in the case of chunked encoding,
594 * also for HTTP "footers".
595 *
596 * Once the header is complete, it should have set the
597 * headers_received, url and method values and set
598 * have_received_headers to MHD_YES. If no body is expected, it
599 * should also set "have_received_body" to MHD_YES. Otherwise, it
600 * should set "remaining_upload_size" to the expected size of the
601 * body. If the size of the body is unknown, it should be set to -1.
602 */
603static void
604MHD_parse_connection_headers (struct MHD_Connection *connection)
605{
606 char *last;
607 char *line;
608 char *colon;
609 char *tmp;
610 const char *clen;
611 unsigned long long cval;
612 struct MHD_Response *response;
613
614 if (((connection->have_received_body == MHD_YES) &&
615 (connection->have_chunked_upload == MHD_NO)) ||
616 (connection->have_received_headers == MHD_YES))
617 abort ();
618 colon = NULL; /* make gcc happy */
619 last = NULL;
620 while (NULL != (line = MHD_get_next_header_line (connection)))
621 {
622 if (last != NULL)
623 {
624 if ((line[0] == ' ') || (line[0] == '\t'))
625 {
626 /* value was continued on the next line, see
627 http://www.jmarshall.com/easy/http/ */
628 last = MHD_pool_reallocate (connection->pool,
629 last,
630 strlen (last) + 1,
631 strlen (line) + strlen (last) + 1);
632 if (last == NULL)
633 {
634 MHD_excessive_data_handler (connection,
635 MHD_HTTP_REQUEST_ENTITY_TOO_LARGE);
636 break;
637 }
638 tmp = line;
639 while ((tmp[0] == ' ') || (tmp[0] == '\t'))
640 tmp++; /* skip whitespace at start of 2nd line */
641 strcat (last, tmp);
642 continue; /* possibly more than 2 lines... */
643 }
644 else
645 {
646 if (MHD_NO == MHD_connection_add_header (connection,
647 last,
648 colon,
649 MHD_HEADER_KIND))
650 return;
651 last = NULL;
652 }
653 }
654 if (connection->url == NULL)
655 {
656 /* line must be request line (first line of header) */
657 if (MHD_NO == parse_initial_message_line (connection, line))
658 goto DIE;
659 continue;
660 }
661 /* check if this is the end of the header */
662 if (strlen (line) == 0)
663 {
664 /* end of header */
665 connection->have_received_headers = MHD_YES;
666 clen = MHD_lookup_connection_value (connection,
667 MHD_HEADER_KIND,
668 MHD_HTTP_HEADER_CONTENT_LENGTH);
669 if (clen != NULL)
670 {
671 if (1 != sscanf (clen, "%llu", &cval))
672 {
673#if HAVE_MESSAGES
674 MHD_DLOG (connection->daemon,
675 "Failed to parse `%s' header `%s', closing connection.\n",
676 MHD_HTTP_HEADER_CONTENT_LENGTH, clen);
677#endif
678 goto DIE;
679 }
680 connection->remaining_upload_size = cval;
681 connection->have_received_body = cval == 0 ? MHD_YES : MHD_NO;
682 }
683 else
684 {
685 if (NULL == MHD_lookup_connection_value (connection,
686 MHD_HEADER_KIND,
687 MHD_HTTP_HEADER_TRANSFER_ENCODING))
688 {
689 /* this request does not have a body */
690 connection->remaining_upload_size = 0;
691 connection->have_received_body = MHD_YES;
692 }
693 else
694 {
695 if (connection->have_chunked_upload == MHD_NO)
696 {
697 connection->remaining_upload_size = -1; /* unknown size */
698 if (0 ==
699 strcasecmp (MHD_lookup_connection_value
700 (connection, MHD_HEADER_KIND,
701 MHD_HTTP_HEADER_TRANSFER_ENCODING),
702 "chunked"))
703 connection->have_chunked_upload = MHD_YES;
704 }
705 else
706 {
707 /* we were actually processing the footers at the
708 END of a chunked encoding; give connection
709 handler an extra chance... */
710 connection->have_chunked_upload = MHD_NO; /* no more! */
711 MHD_call_connection_handler (connection);
712 }
713 }
714 }
715 if ((0 != (MHD_USE_PEDANTIC_CHECKS & connection->daemon->options))
716 && (NULL != connection->version)
717 && (0 == strcasecmp (MHD_HTTP_VERSION_1_1, connection->version))
718 && (NULL ==
719 MHD_lookup_connection_value (connection, MHD_HEADER_KIND,
720 MHD_HTTP_HEADER_HOST)))
721 {
722 /* die, http 1.1 request without host and we are pedantic */
723 connection->have_received_body = MHD_YES;
724 connection->read_close = MHD_YES;
725#if HAVE_MESSAGES
726 MHD_DLOG (connection->daemon,
727 "Received `%s' request without `%s' header.\n",
728 MHD_HTTP_VERSION_1_1, MHD_HTTP_HEADER_HOST);
729#endif
730 response =
731 MHD_create_response_from_data (strlen (REQUEST_LACKS_HOST),
732 REQUEST_LACKS_HOST, MHD_NO,
733 MHD_NO);
734 MHD_queue_response (connection, MHD_HTTP_BAD_REQUEST, response);
735 MHD_destroy_response (response);
736 }
737 break;
738 }
739 /* line should be normal header line, find colon */
740 colon = strstr (line, ":");
741 if (colon == NULL)
742 {
743 /* error in header line, die hard */
744#if HAVE_MESSAGES
745 MHD_DLOG (connection->daemon,
746 "Received malformed line (no colon), closing connection.\n");
747#endif
748 goto DIE;
749 }
750 /* zero-terminate header */
751 colon[0] = '\0';
752 colon++; /* advance to value */
753 while ((colon[0] != '\0') && ((colon[0] == ' ') || (colon[0] == '\t')))
754 colon++;
755 /* we do the actual adding of the connection
756 header at the beginning of the while
757 loop since we need to be able to inspect
758 the *next* header line (in case it starts
759 with a space...) */
760 last = line;
761 }
762 if ((last != NULL) &&
763 (MHD_NO == MHD_connection_add_header (connection,
764 last, colon, MHD_HEADER_KIND)))
765 return; /* error */
766 MHD_parse_cookie_header (connection);
767 return;
768DIE:
769#if HAVE_MESSAGES
770 MHD_DLOG (connection->daemon,
771 "Closing connection (problem parsing headers)\n");
772#endif
773 connection_close_error (connection);
774}
775
776
777/**
778 * Find the handler responsible for this request.
779 */
780static struct MHD_Access_Handler *
781MHD_find_access_handler (struct MHD_Connection *connection)
782{
783 struct MHD_Access_Handler *pos;
784
785 pos = connection->daemon->handlers;
786 while (pos != NULL)
787 {
788 if (0 == strcmp (connection->url, pos->uri_prefix))
789 return pos;
790 pos = pos->next;
791 }
792 return &connection->daemon->default_handler;
793}
794
795
796/** 964/**
797 * Call the handler of the application for this 965 * Call the handler of the application for this
798 * connection. 966 * connection. Handles chunking of the upload
967 * as well as normal uploads.
799 */ 968 */
800void 969static void
801MHD_call_connection_handler (struct MHD_Connection *connection) 970call_connection_handler (struct MHD_Connection *connection)
802{ 971{
803 struct MHD_Access_Handler *ah;
804 unsigned int processed; 972 unsigned int processed;
805 unsigned int available; 973 unsigned int available;
806 unsigned int used; 974 unsigned int used;
807 int instant_retry; 975 int instant_retry;
808 unsigned int i; 976 unsigned int i;
977 int malformed;
809 978
810 if (connection->response != NULL) 979 if (connection->response != NULL)
811 return; /* already queued a response */ 980 return; /* already queued a response */
812 if (connection->have_received_headers == MHD_NO)
813 abort (); /* bad timing... */
814 do 981 do
815 { 982 {
816 instant_retry = MHD_NO; 983 instant_retry = MHD_NO;
817 available = connection->read_buffer_offset; 984 available = connection->read_buffer_offset;
818 if (connection->have_chunked_upload == MHD_YES) 985 if ( (connection->have_chunked_upload == MHD_YES) &&
986 (connection->remaining_upload_size == -1) )
819 { 987 {
820 if ((connection->current_chunk_offset == 988 if ((connection->current_chunk_offset ==
821 connection->current_chunk_size) 989 connection->current_chunk_size)
@@ -876,18 +1044,17 @@ MHD_call_connection_handler (struct MHD_Connection *connection)
876 } 1044 }
877 if (i >= available) 1045 if (i >= available)
878 return; /* need more data... */ 1046 return; /* need more data... */
879 /* The following if-statement is a bit crazy -- we 1047 malformed = (i >= 6);
880 use the second clause only for the side-effect, 1048 if (! malformed)
881 0-terminating the buffer for the following sscanf 1049 {
882 attempts; yes, there should be only a single 1050 connection->read_buffer[i] = '\0';
883 "="-sign (assignment!) in the read_buffer[i]-line. */ 1051 malformed = (1 != sscanf (connection->read_buffer,
884 if ((i >= 6) || 1052 "%X",
885 ((connection->read_buffer[i] = '\0')) || 1053 &connection->current_chunk_size)) &&
886 ((1 != sscanf (connection->read_buffer, 1054 (1 != sscanf (connection->read_buffer,
887 "%X", 1055 "%x", &connection->current_chunk_size));
888 &connection->current_chunk_size)) && 1056 }
889 (1 != sscanf (connection->read_buffer, 1057 if (malformed)
890 "%x", &connection->current_chunk_size))))
891 { 1058 {
892 /* malformed encoding */ 1059 /* malformed encoding */
893#if HAVE_MESSAGES 1060#if HAVE_MESSAGES
@@ -908,11 +1075,7 @@ MHD_call_connection_handler (struct MHD_Connection *connection)
908 instant_retry = MHD_YES; 1075 instant_retry = MHD_YES;
909 if (connection->current_chunk_size == 0) 1076 if (connection->current_chunk_size == 0)
910 { 1077 {
911 /* we're back to reading HEADERS (footers!) */
912 connection->have_received_body = MHD_YES;
913 connection->remaining_upload_size = 0; 1078 connection->remaining_upload_size = 0;
914 connection->have_received_headers = MHD_NO;
915 MHD_parse_connection_headers (connection);
916 return; 1079 return;
917 } 1080 }
918 continue; 1081 continue;
@@ -925,8 +1088,7 @@ MHD_call_connection_handler (struct MHD_Connection *connection)
925 available = 0; 1088 available = 0;
926 } 1089 }
927 used = processed; 1090 used = processed;
928 ah = MHD_find_access_handler (connection); 1091 if (MHD_NO == connection->daemon->default_handler (connection->daemon->default_handler_cls,
929 if (MHD_NO == ah->dh (ah->dh_cls,
930 connection, 1092 connection,
931 connection->url, 1093 connection->url,
932 connection->method, 1094 connection->method,
@@ -942,6 +1104,8 @@ MHD_call_connection_handler (struct MHD_Connection *connection)
942 connection_close_error (connection); 1104 connection_close_error (connection);
943 return; 1105 return;
944 } 1106 }
1107 if (processed > used)
1108 abort(); /* fatal client API violation! */
945 if (processed != 0) 1109 if (processed != 0)
946 instant_retry = MHD_NO; /* client did not process everything */ 1110 instant_retry = MHD_NO; /* client did not process everything */
947 used -= processed; 1111 used -= processed;
@@ -953,79 +1117,26 @@ MHD_call_connection_handler (struct MHD_Connection *connection)
953 &connection->read_buffer[used], processed + available); 1117 &connection->read_buffer[used], processed + available);
954 if (connection->remaining_upload_size != -1) 1118 if (connection->remaining_upload_size != -1)
955 connection->remaining_upload_size -= used; 1119 connection->remaining_upload_size -= used;
956 connection->read_buffer_offset = processed + available; 1120 connection->read_buffer_offset = processed + available;
957 if ((connection->remaining_upload_size == 0) ||
958 ((connection->read_buffer_offset == 0) &&
959 (connection->remaining_upload_size == -1)
960 && (connection->socket_fd == -1)))
961 {
962 connection->have_received_body = MHD_YES;
963 if (connection->read_buffer != NULL)
964 MHD_pool_reallocate (connection->pool,
965 connection->read_buffer,
966 (connection->read_buffer ==
967 NULL) ? 0 : connection->read_buffer_size +
968 1, 0);
969 connection->read_buffer_offset = 0;
970 connection->read_buffer_size = 0;
971 connection->read_buffer = NULL;
972 }
973 } 1121 }
974 while (instant_retry == MHD_YES); 1122 while (instant_retry == MHD_YES);
975} 1123}
976 1124
977/** 1125/**
978 * This function handles a particular connection when it has been 1126 * Try reading data from the socket into the
979 * determined that there is data to be read off a socket. All implementations 1127 * read buffer of the connection.
980 * (multithreaded, external select, internal select) call this function 1128 *
981 * to handle reads. 1129 * @return MHD_YES if something changed,
1130 * MHD_NO if we were interrupted or if
1131 * no space was available
982 */ 1132 */
983int 1133static int
984MHD_connection_handle_read (struct MHD_Connection *connection) 1134do_read(struct MHD_Connection * connection)
985{ 1135{
986 int bytes_read; 1136 int bytes_read;
987 void *tmp; 1137
988 1138 if (connection->read_buffer_size == connection->read_buffer_offset)
989 if (connection->pool == NULL) 1139 return MHD_NO;
990 connection->pool = MHD_pool_create (connection->daemon->pool_size);
991 if (connection->pool == NULL)
992 {
993#if HAVE_MESSAGES
994 MHD_DLOG (connection->daemon, "Failed to create memory pool!\n");
995#endif
996 connection_close_error (connection);
997 return MHD_NO;
998 }
999 if ((connection->read_buffer_offset >= connection->read_buffer_size) &&
1000 (connection->have_received_headers == MHD_NO))
1001 {
1002 /* need to grow read buffer */
1003 tmp = MHD_pool_reallocate (connection->pool,
1004 connection->read_buffer,
1005 connection->read_buffer_size,
1006 connection->read_buffer_size * 2 +
1007 MHD_BUF_INC_SIZE + 1);
1008 if (tmp == NULL)
1009 {
1010#if HAVE_MESSAGES
1011 MHD_DLOG (connection->daemon,
1012 "Not enough memory for reading headers!\n");
1013#endif
1014 MHD_excessive_data_handler (connection,
1015 MHD_HTTP_REQUEST_ENTITY_TOO_LARGE);
1016 return MHD_NO;
1017 }
1018 connection->read_buffer = tmp;
1019 connection->read_buffer_size =
1020 connection->read_buffer_size * 2 + MHD_BUF_INC_SIZE;
1021 }
1022 if (connection->read_buffer_offset >= connection->read_buffer_size)
1023 {
1024#if HAVE_MESSAGES
1025 MHD_DLOG (connection->daemon, "Unexpected call to %s.\n", __FUNCTION__);
1026#endif
1027 return MHD_NO;
1028 }
1029 bytes_read = RECV (connection->socket_fd, 1140 bytes_read = RECV (connection->socket_fd,
1030 &connection->read_buffer[connection->read_buffer_offset], 1141 &connection->read_buffer[connection->read_buffer_offset],
1031 connection->read_buffer_size - 1142 connection->read_buffer_size -
@@ -1044,150 +1155,297 @@ MHD_connection_handle_read (struct MHD_Connection *connection)
1044 if (bytes_read == 0) 1155 if (bytes_read == 0)
1045 { 1156 {
1046 /* other side closed connection */ 1157 /* other side closed connection */
1047 connection->read_close = MHD_YES; 1158 connection->read_closed = MHD_YES;
1048 if ((connection->have_received_headers == MHD_YES) 1159 return MHD_NO;
1049 && (connection->read_buffer_offset > 0))
1050 MHD_call_connection_handler (connection);
1051#if DEBUG_CLOSE
1052#if HAVE_MESSAGES
1053 MHD_DLOG (connection->daemon,
1054 "Shutting down connection for reading (other side closed connection)\n");
1055#endif
1056#endif
1057 shutdown (connection->socket_fd, SHUT_RD);
1058 if ((connection->have_received_headers == MHD_NO) ||
1059 (connection->have_received_body == MHD_NO))
1060 {
1061 /* no request => no response! */
1062 CLOSE (connection->socket_fd);
1063 connection->socket_fd = -1;
1064 }
1065 return MHD_YES;
1066 } 1160 }
1067 connection->read_buffer_offset += bytes_read; 1161 connection->read_buffer_offset += bytes_read;
1068 if (connection->have_received_headers == MHD_NO)
1069 MHD_parse_connection_headers (connection);
1070 if ((connection->have_received_headers == MHD_YES)
1071 && (connection->method != NULL))
1072 MHD_call_connection_handler (connection);
1073 return MHD_YES; 1162 return MHD_YES;
1074} 1163}
1075 1164
1076/** 1165/**
1077 * Check if we need to set some additional headers 1166 * We have received (possibly the beginning of) a line in the
1078 * for http-compiliance. 1167 * header (or footer). Validate (check for ":") and prepare
1168 * to process.
1079 */ 1169 */
1080static void 1170static void
1081MHD_add_extra_headers (struct MHD_Connection *connection) 1171process_header_line(struct MHD_Connection * connection,
1172 char * line)
1082{ 1173{
1083 const char *have; 1174 char *colon;
1084 char buf[128];
1085 1175
1086 if (connection->response->total_size == -1) 1176 /* line should be normal header line, find colon */
1177 colon = strstr (line, ":");
1178 if (colon == NULL)
1087 { 1179 {
1088 have = MHD_get_response_header (connection->response, 1180 /* error in header line, die hard */
1089 MHD_HTTP_HEADER_CONNECTION); 1181#if HAVE_MESSAGES
1090 if (have == NULL) 1182 MHD_DLOG (connection->daemon,
1091 MHD_add_response_header (connection->response, 1183 "Received malformed line (no colon), closing connection.\n");
1092 MHD_HTTP_HEADER_CONNECTION, "close"); 1184#endif
1093 } 1185 connection->state = MHD_CONNECTION_CLOSED;
1094 else if (NULL == MHD_get_response_header (connection->response, 1186 return;
1095 MHD_HTTP_HEADER_CONTENT_LENGTH))
1096 {
1097 _REAL_SNPRINTF (buf,
1098 128,
1099 "%llu",
1100 (unsigned long long) connection->response->total_size);
1101 MHD_add_response_header (connection->response,
1102 MHD_HTTP_HEADER_CONTENT_LENGTH, buf);
1103 } 1187 }
1188 /* zero-terminate header */
1189 colon[0] = '\0';
1190 colon++; /* advance to value */
1191 while ((colon[0] != '\0') && ((colon[0] == ' ') || (colon[0] == '\t')))
1192 colon++;
1193 /* we do the actual adding of the connection
1194 header at the beginning of the while
1195 loop since we need to be able to inspect
1196 the *next* header line (in case it starts
1197 with a space...) */
1198 connection->last = line;
1199 connection->colon = colon;
1104} 1200}
1105 1201
1202/**
1203 * Process a header value that spans multiple lines.
1204 * The previous line(s) are in connection->last.
1205 *
1206 * @param line the current input line
1207 * @param kind if the line is complete, add a header
1208 * of the given kind
1209 */
1106static void 1210static void
1107get_date_string (char *date, unsigned int max) 1211process_broken_line(struct MHD_Connection * connection,
1212 char * line,
1213 enum MHD_ValueKind kind)
1108{ 1214{
1109 static const char *days[] = 1215 char * last;
1110 { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" }; 1216 char * tmp;
1111 static const char *mons[] =
1112 { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct",
1113 "Nov", "Dec"
1114 };
1115 struct tm now;
1116 time_t t;
1117 1217
1118 time (&t); 1218 last = connection->last;
1119 gmtime_r (&t, &now); 1219 if ((line[0] == ' ') || (line[0] == '\t'))
1120 snprintf (date, 1220 {
1121 max - 1, 1221 /* value was continued on the next line, see
1122 "Date: %3s, %02u %3s %04u %02u:%02u:%02u GMT\r\n", 1222 http://www.jmarshall.com/easy/http/ */
1123 days[now.tm_wday % 7], 1223 last = MHD_pool_reallocate (connection->pool,
1124 now.tm_mday, 1224 last,
1125 mons[now.tm_mon % 12], 1225 strlen (last) + 1,
1126 now.tm_year, now.tm_hour, now.tm_min, now.tm_sec); 1226 strlen (line) + strlen (last) + 1);
1227 if (last == NULL)
1228 {
1229 excessive_data_handler (connection,
1230 MHD_HTTP_REQUEST_ENTITY_TOO_LARGE);
1231 return;
1232 }
1233 tmp = line;
1234 while ((tmp[0] == ' ') || (tmp[0] == '\t'))
1235 tmp++; /* skip whitespace at start of 2nd line */
1236 strcat (last, tmp);
1237 connection->last = last;
1238 return; /* possibly more than 2 lines... */
1239 }
1240 if (MHD_NO == connection_add_header (connection,
1241 last,
1242 connection->colon,
1243 kind))
1244 {
1245 excessive_data_handler (connection,
1246 MHD_HTTP_REQUEST_ENTITY_TOO_LARGE);
1247 return;
1248 }
1249 /* we still have the current line to deal with... */
1250 if (strlen(line) != 0)
1251 process_header_line(connection,
1252 line);
1127} 1253}
1128 1254
1129/** 1255/**
1130 * Allocate the connection's write buffer and 1256 * Parse the various headers; figure out the size
1131 * fill it with all of the headers from the 1257 * of the upload and make sure the headers follow
1132 * HTTPd's response. 1258 * the protocol. Advance to the appropriate state.
1133 */ 1259 */
1134static int 1260static void
1135MHD_build_header_response (struct MHD_Connection *connection) 1261parse_connection_headers(struct MHD_Connection * connection)
1136{ 1262{
1137 size_t size; 1263 const char *clen;
1138 size_t off; 1264 unsigned long long cval;
1139 struct MHD_HTTP_Header *pos; 1265 struct MHD_Response *response;
1140 char code[128];
1141 char date[128];
1142 char *data;
1143 1266
1144 MHD_add_extra_headers (connection); 1267 parse_cookie_header (connection);
1145 const char *reason_phrase = 1268 if ((0 != (MHD_USE_PEDANTIC_CHECKS & connection->daemon->options))
1146 MHD_get_reason_phrase_for (connection->responseCode); 1269 && (NULL != connection->version)
1147 _REAL_SNPRINTF (code, 128, "%s %u %s\r\n", MHD_HTTP_VERSION_1_1, 1270 && (0 == strcasecmp (MHD_HTTP_VERSION_1_1, connection->version))
1148 connection->responseCode, reason_phrase); 1271 && (NULL ==
1149 off = strlen (code); 1272 MHD_lookup_connection_value (connection, MHD_HEADER_KIND,
1150 /* estimate size */ 1273 MHD_HTTP_HEADER_HOST)))
1151 size = off + 2; /* extra \r\n at the end */
1152 pos = connection->response->first_header;
1153 while (pos != NULL)
1154 { 1274 {
1155 size += strlen (pos->header) + strlen (pos->value) + 4; /* colon, space, linefeeds */ 1275 /* die, http 1.1 request without host and we are pedantic */
1156 pos = pos->next; 1276 connection->state = MHD_CONNECTION_FOOTERS_RECEIVED;
1277 connection->read_closed = MHD_YES;
1278#if HAVE_MESSAGES
1279 MHD_DLOG (connection->daemon,
1280 "Received `%s' request without `%s' header.\n",
1281 MHD_HTTP_VERSION_1_1, MHD_HTTP_HEADER_HOST);
1282#endif
1283 response =
1284 MHD_create_response_from_data (strlen (REQUEST_LACKS_HOST),
1285 REQUEST_LACKS_HOST, MHD_NO,
1286 MHD_NO);
1287 MHD_queue_response (connection, MHD_HTTP_BAD_REQUEST, response);
1288 MHD_destroy_response (response);
1289 return;
1157 } 1290 }
1158 if (NULL == MHD_get_response_header (connection->response, 1291
1159 MHD_HTTP_HEADER_DATE)) 1292 clen = MHD_lookup_connection_value (connection,
1160 get_date_string (date, sizeof (date)); 1293 MHD_HEADER_KIND,
1161 else 1294 MHD_HTTP_HEADER_CONTENT_LENGTH);
1162 date[0] = '\0'; 1295 if (clen != NULL)
1163 size += strlen (date);
1164 /* produce data */
1165 data = MHD_pool_allocate (connection->pool, size + 1, MHD_YES);
1166 if (data == NULL)
1167 { 1296 {
1297 if (1 != sscanf (clen, "%llu", &cval))
1298 {
1168#if HAVE_MESSAGES 1299#if HAVE_MESSAGES
1169 MHD_DLOG (connection->daemon, "Not enough memory for write!\n"); 1300 MHD_DLOG (connection->daemon,
1301 "Failed to parse `%s' header `%s', closing connection.\n",
1302 MHD_HTTP_HEADER_CONTENT_LENGTH, clen);
1170#endif 1303#endif
1171 return MHD_NO; 1304 connection->state = MHD_CONNECTION_CLOSED;
1305 return;
1306 }
1307 connection->remaining_upload_size = cval;
1172 } 1308 }
1173 memcpy (data, code, off); 1309 else
1174 pos = connection->response->first_header;
1175 while (pos != NULL)
1176 { 1310 {
1177 SPRINTF (&data[off], "%s: %s\r\n", pos->header, pos->value); 1311 if (NULL == MHD_lookup_connection_value (connection,
1178 off += strlen (pos->header) + strlen (pos->value) + 4; 1312 MHD_HEADER_KIND,
1179 pos = pos->next; 1313 MHD_HTTP_HEADER_TRANSFER_ENCODING))
1314 {
1315 /* this request does not have a body */
1316 connection->remaining_upload_size = 0;
1317 }
1318 else
1319 {
1320 connection->remaining_upload_size = -1; /* unknown size */
1321 if (0 ==
1322 strcasecmp (MHD_lookup_connection_value
1323 (connection, MHD_HEADER_KIND,
1324 MHD_HTTP_HEADER_TRANSFER_ENCODING),
1325 "chunked"))
1326 connection->have_chunked_upload = MHD_YES;
1327 }
1328 }
1329}
1330
1331/**
1332 * This function handles a particular connection when it has been
1333 * determined that there is data to be read off a socket. All
1334 * implementations (multithreaded, external select, internal select)
1335 * call this function to handle reads.
1336 *
1337 * @return MHD_YES if we should continue to process the
1338 * connection (not dead yet), MHD_NO if it died
1339 */
1340int
1341MHD_connection_handle_read (struct MHD_Connection *connection)
1342{
1343 connection->last_activity = time(NULL);
1344 if (connection->state == MHD_CONNECTION_CLOSED)
1345 return MHD_NO;
1346 if (MHD_NO == do_read(connection))
1347 return MHD_YES;
1348 while (1) {
1349#if DEBUG_STATES
1350 fprintf(stderr,
1351 "`%s' in state %u\n",
1352 __FUNCTION__,
1353 connection->state);
1354#endif
1355 switch (connection->state)
1356 {
1357 case MHD_CONNECTION_INIT:
1358 case MHD_CONNECTION_URL_RECEIVED:
1359 case MHD_CONNECTION_HEADER_PART_RECEIVED:
1360 case MHD_CONNECTION_HEADERS_RECEIVED:
1361 case MHD_CONNECTION_HEADERS_PROCESSED:
1362 case MHD_CONNECTION_CONTINUE_SENDING:
1363 case MHD_CONNECTION_CONTINUE_SENT:
1364 case MHD_CONNECTION_BODY_RECEIVED:
1365 case MHD_CONNECTION_FOOTER_PART_RECEIVED:
1366 /* nothing to do but default action */
1367 if (MHD_YES == connection->read_closed)
1368 {
1369 connection->state = MHD_CONNECTION_CLOSED;
1370 continue;
1371 }
1372 break;
1373 case MHD_CONNECTION_CLOSED:
1374 if (connection->socket_fd != -1)
1375 connection_close_error (connection);
1376 return MHD_NO;
1377 default:
1378 /* shrink read buffer to how much is actually used */
1379 MHD_pool_reallocate (connection->pool,
1380 connection->read_buffer,
1381 connection->read_buffer_size + 1,
1382 connection->read_buffer_offset);
1383 break;
1384 }
1385 break;
1386 }
1387 return MHD_YES;
1388}
1389
1390/**
1391 * Try writing data to the socket from the
1392 * write buffer of the connection.
1393 *
1394 * @return MHD_YES if something changed,
1395 * MHD_NO if we were interrupted
1396 */
1397static int
1398do_write(struct MHD_Connection * connection)
1399{
1400 int ret;
1401
1402 ret = SEND (connection->socket_fd,
1403 &connection->write_buffer[connection->
1404 write_buffer_send_offset],
1405 connection->write_buffer_append_offset -
1406 connection->write_buffer_send_offset, MSG_NOSIGNAL);
1407 if (ret < 0)
1408 {
1409 if (errno == EINTR)
1410 return MHD_NO;
1411#if HAVE_MESSAGES
1412 MHD_DLOG (connection->daemon,
1413 "Failed to send data: %s\n", STRERROR (errno));
1414#endif
1415 connection_close_error (connection);
1416 return MHD_YES;
1180 } 1417 }
1181 strcpy (&data[off], date); 1418#if DEBUG_SEND_DATA
1182 off += strlen (date); 1419 fprintf (stderr,
1183 sprintf (&data[off], "\r\n"); 1420 "Sent HEADER response: `%.*s'\n",
1184 off += 2; 1421 ret,
1185 if (off != size) 1422 &connection->write_buffer[connection->
1186 abort (); 1423 write_buffer_send_offset]);
1187 connection->write_buffer = data; 1424#endif
1188 connection->write_buffer_append_offset = size; 1425 connection->write_buffer_send_offset += ret;
1426 return MHD_YES;
1427}
1428
1429/**
1430 * Check if we are done sending the write-buffer.
1431 * If so, transition into "next_state".
1432 * @return MHY_NO if we are not done, MHD_YES if we are
1433 */
1434static int
1435check_write_done(struct MHD_Connection * connection,
1436 enum MHD_CONNECTION_STATE next_state)
1437{
1438 if (connection->write_buffer_append_offset !=
1439 connection->write_buffer_send_offset)
1440 return MHD_NO;
1441 connection->write_buffer_append_offset = 0;
1189 connection->write_buffer_send_offset = 0; 1442 connection->write_buffer_send_offset = 0;
1190 connection->write_buffer_size = size + 1; 1443 connection->state = next_state;
1444 MHD_pool_reallocate (connection->pool,
1445 connection->write_buffer,
1446 connection->write_buffer_size, 0);
1447 connection->write_buffer = NULL;
1448 connection->write_buffer_size = 0;
1191 return MHD_YES; 1449 return MHD_YES;
1192} 1450}
1193 1451
@@ -1196,207 +1454,414 @@ MHD_build_header_response (struct MHD_Connection *connection)
1196 * been determined that the socket can be written to. All 1454 * been determined that the socket can be written to. All
1197 * implementations (multithreaded, external select, internal select) 1455 * implementations (multithreaded, external select, internal select)
1198 * call this function 1456 * call this function
1457 *
1458 * @return MHD_YES if we should continue to process the
1459 * connection (not dead yet), MHD_NO if it died
1199 */ 1460 */
1200int 1461int
1201MHD_connection_handle_write (struct MHD_Connection *connection) 1462MHD_connection_handle_write (struct MHD_Connection *connection)
1202{ 1463{
1203 struct MHD_Response *response; 1464 struct MHD_Response *response;
1204 int ret; 1465 int ret;
1205 const char *end;
1206 1466
1207 if (MHD_need_100_continue (connection)) 1467 connection->last_activity = time(NULL);
1208 { 1468 while (1) {
1209 ret = SEND (connection->socket_fd, 1469#if DEBUG_STATES
1210 &HTTP_100_CONTINUE[connection-> 1470 fprintf(stderr,
1211 continue_message_write_offset], 1471 "`%s' in state %u\n",
1212 strlen (HTTP_100_CONTINUE) - 1472 __FUNCTION__,
1213 connection->continue_message_write_offset, MSG_NOSIGNAL); 1473 connection->state);
1214 if (ret < 0) 1474#endif
1215 { 1475 switch (connection->state)
1216 if (errno == EINTR) 1476 {
1217 return MHD_YES; 1477 case MHD_CONNECTION_INIT:
1478 case MHD_CONNECTION_URL_RECEIVED:
1479 case MHD_CONNECTION_HEADER_PART_RECEIVED:
1480 case MHD_CONNECTION_HEADERS_RECEIVED:
1481 EXTRA_CHECK(0);
1482 break;
1483 case MHD_CONNECTION_HEADERS_PROCESSED:
1484 break;
1485 case MHD_CONNECTION_CONTINUE_SENDING:
1486 ret = SEND (connection->socket_fd,
1487 &HTTP_100_CONTINUE[connection->
1488 continue_message_write_offset],
1489 strlen (HTTP_100_CONTINUE) -
1490 connection->continue_message_write_offset, MSG_NOSIGNAL);
1491 if (ret < 0)
1492 {
1493 if (errno == EINTR)
1494 break;
1218#if HAVE_MESSAGES 1495#if HAVE_MESSAGES
1219 MHD_DLOG (connection->daemon, 1496 MHD_DLOG (connection->daemon,
1220 "Failed to send data: %s\n", STRERROR (errno)); 1497 "Failed to send data: %s\n", STRERROR (errno));
1221#endif 1498#endif
1222 connection_close_error (connection); 1499 connection_close_error (connection);
1223 return MHD_YES; 1500 return MHD_NO;
1224 } 1501 }
1225#if DEBUG_SEND_DATA 1502#if DEBUG_SEND_DATA
1226 fprintf (stderr, 1503 fprintf (stderr,
1227 "Sent 100 continue response: `%.*s'\n", 1504 "Sent 100 continue response: `%.*s'\n",
1228 ret, 1505 ret,
1229 &HTTP_100_CONTINUE[connection->continue_message_write_offset]); 1506 &HTTP_100_CONTINUE[connection->continue_message_write_offset]);
1230#endif 1507#endif
1231 connection->continue_message_write_offset += ret; 1508 connection->continue_message_write_offset += ret;
1232 return MHD_YES; 1509 break;
1233 } 1510 case MHD_CONNECTION_CONTINUE_SENT:
1234 response = connection->response; 1511 case MHD_CONNECTION_BODY_RECEIVED:
1235 if (response == NULL) 1512 case MHD_CONNECTION_FOOTER_PART_RECEIVED:
1236 { 1513 case MHD_CONNECTION_FOOTERS_RECEIVED:
1237#if HAVE_MESSAGES 1514 EXTRA_CHECK(0);
1238 MHD_DLOG (connection->daemon, "Unexpected call to %s.\n", __FUNCTION__); 1515 break;
1239#endif 1516 case MHD_CONNECTION_HEADERS_SENDING:
1240 return MHD_NO; 1517 do_write(connection);
1241 } 1518 check_write_done(connection,
1242 if (MHD_NO == connection->have_sent_headers) 1519 MHD_CONNECTION_HEADERS_SENT);
1243 { 1520 break;
1244 if ((connection->write_buffer == NULL) && 1521 case MHD_CONNECTION_HEADERS_SENT:
1245 (MHD_NO == MHD_build_header_response (connection))) 1522 EXTRA_CHECK(0);
1246 { 1523 break;
1247 /* oops - close! */ 1524 case MHD_CONNECTION_NORMAL_BODY_READY:
1525 response = connection->response;
1526 if (response->crc != NULL)
1527 pthread_mutex_lock (&response->mutex);
1528 if (MHD_YES != try_ready_normal_body(connection))
1529 {
1530 if (response->crc != NULL)
1531 pthread_mutex_unlock (&response->mutex);
1532 connection->state = MHD_CONNECTION_NORMAL_BODY_UNREADY;
1533 break;
1534 }
1535 ret = SEND (connection->socket_fd,
1536 &response->data[connection->response_write_position -
1537 response->data_start],
1538 response->data_size - (connection->response_write_position -
1539 response->data_start), MSG_NOSIGNAL);
1540#if DEBUG_SEND_DATA
1541 if (ret > 0)
1542 fprintf (stderr,
1543 "Sent DATA response: `%.*s'\n",
1544 ret,
1545 &response->data[connection->response_write_position -
1546 response->data_start]);
1547#endif
1548 if (response->crc != NULL)
1549 pthread_mutex_unlock (&response->mutex);
1550 if (ret < 0)
1551 {
1552 if (errno == EINTR)
1553 return MHD_YES;
1248#if HAVE_MESSAGES 1554#if HAVE_MESSAGES
1249 MHD_DLOG (connection->daemon, 1555 MHD_DLOG (connection->daemon,
1250 "Closing connection (failed to create response header)\n"); 1556 "Failed to send data: %s\n", STRERROR (errno));
1251#endif 1557#endif
1252 connection_close_error (connection); 1558 connection_close_error (connection);
1253 return MHD_NO; 1559 return MHD_NO;
1254 } 1560 }
1255 ret = SEND (connection->socket_fd, 1561 connection->response_write_position += ret;
1256 &connection->write_buffer[connection-> 1562 if (connection->response_write_position == connection->response->total_size)
1257 write_buffer_send_offset], 1563 connection->state = MHD_CONNECTION_FOOTERS_SENT; /* have no footers... */
1258 connection->write_buffer_append_offset - 1564 break;
1259 connection->write_buffer_send_offset, MSG_NOSIGNAL); 1565 case MHD_CONNECTION_NORMAL_BODY_UNREADY:
1260 if (ret < 0) 1566 EXTRA_CHECK(0);
1261 { 1567 break;
1262 if (errno == EINTR) 1568 case MHD_CONNECTION_CHUNKED_BODY_READY:
1263 return MHD_YES; 1569 do_write(connection);
1570 check_write_done(connection,
1571 (connection->response->total_size == connection->response_write_position)
1572 ? MHD_CONNECTION_BODY_SENT
1573 : MHD_CONNECTION_CHUNKED_BODY_UNREADY);
1574 break;
1575 case MHD_CONNECTION_CHUNKED_BODY_UNREADY:
1576 case MHD_CONNECTION_BODY_SENT:
1577 EXTRA_CHECK(0);
1578 break;
1579 case MHD_CONNECTION_FOOTERS_SENDING:
1580 do_write(connection);
1581 check_write_done(connection,
1582 MHD_CONNECTION_FOOTERS_SENT);
1583 break;
1584 case MHD_CONNECTION_FOOTERS_SENT:
1585 EXTRA_CHECK(0);
1586 break;
1587 case MHD_CONNECTION_CLOSED:
1588 if (connection->socket_fd != -1)
1589 connection_close_error(connection);
1590 return MHD_NO;
1591 }
1592 break;
1593 }
1594 return MHD_YES;
1595}
1596
1597/**
1598 * This function was created to handle per-connection processing that
1599 * has to happen even if the socket cannot be read or written to. All
1600 * implementations (multithreaded, external select, internal select)
1601 * call this function.
1602 *
1603 * @return MHD_YES if we should continue to process the
1604 * connection (not dead yet), MHD_NO if it died
1605 */
1606int
1607MHD_connection_handle_idle (struct MHD_Connection *connection)
1608{
1609 unsigned int timeout;
1610 const char * end;
1611 char * line;
1612
1613 while (1) {
1614#if DEBUG_STATES
1615 fprintf(stderr,
1616 "`%s' in state %u\n",
1617 __FUNCTION__,
1618 connection->state);
1619#endif
1620 switch (connection->state)
1621 {
1622 case MHD_CONNECTION_INIT:
1623 line = get_next_header_line(connection);
1624 if (line == NULL)
1625 break;
1626 if (MHD_NO == parse_initial_message_line (connection, line))
1627 connection->state = MHD_CONNECTION_CLOSED;
1628 else
1629 connection->state = MHD_CONNECTION_URL_RECEIVED;
1630 continue;
1631 case MHD_CONNECTION_URL_RECEIVED:
1632 line = get_next_header_line(connection);
1633 if (line == NULL)
1634 break;
1635 if (strlen(line) == 0)
1636 {
1637 connection->state = MHD_CONNECTION_HEADERS_RECEIVED;
1638 continue;
1639 }
1640 process_header_line(connection, line);
1641 connection->state = MHD_CONNECTION_HEADER_PART_RECEIVED;
1642 continue;
1643 case MHD_CONNECTION_HEADER_PART_RECEIVED:
1644 line = get_next_header_line(connection);
1645 if (line == NULL)
1646 break;
1647 process_broken_line(connection,
1648 line,
1649 MHD_HEADER_KIND);
1650 if (strlen(line) == 0)
1651 {
1652 connection->state = MHD_CONNECTION_HEADERS_RECEIVED;
1653 continue;
1654 }
1655 continue;
1656 case MHD_CONNECTION_HEADERS_RECEIVED:
1657 parse_connection_headers (connection);
1658 if (connection->state == MHD_CONNECTION_CLOSED)
1659 continue;
1660 connection->state = MHD_CONNECTION_HEADERS_PROCESSED;
1661 continue;
1662 case MHD_CONNECTION_HEADERS_PROCESSED:
1663 call_connection_handler (connection); /* first call */
1664 if (need_100_continue(connection))
1665 {
1666 connection->state = MHD_CONNECTION_CONTINUE_SENDING;
1667 break;
1668 }
1669 connection->state = (connection->remaining_upload_size == 0)
1670 ? MHD_CONNECTION_FOOTERS_RECEIVED
1671 : MHD_CONNECTION_CONTINUE_SENT;
1672 continue;
1673 case MHD_CONNECTION_CONTINUE_SENDING:
1674 if (connection->continue_message_write_offset ==
1675 strlen (HTTP_100_CONTINUE))
1676 {
1677 connection->state = MHD_CONNECTION_CONTINUE_SENT;
1678 continue;
1679 }
1680 break;
1681 case MHD_CONNECTION_CONTINUE_SENT:
1682 if (connection->read_buffer_offset != 0) {
1683 call_connection_handler(connection); /* loop call */
1684 if (connection->state == MHD_CONNECTION_CLOSED)
1685 continue;
1686 }
1687 if ( (connection->remaining_upload_size == 0) ||
1688 ( (connection->remaining_upload_size == -1) &&
1689 (connection->read_buffer_offset == 0) &&
1690 (MHD_YES == connection->read_closed) ) )
1691 {
1692 if ( (MHD_YES == connection->have_chunked_upload) &&
1693 (MHD_NO == connection->read_closed) )
1694 connection->state = MHD_CONNECTION_BODY_RECEIVED;
1695 else
1696 connection->state = MHD_CONNECTION_FOOTERS_RECEIVED;
1697 continue;
1698 }
1699 break;
1700 case MHD_CONNECTION_BODY_RECEIVED:
1701 line = get_next_header_line(connection);
1702 if (line == NULL)
1703 break;
1704 if (strlen(line) == 0)
1705 {
1706 connection->state = MHD_CONNECTION_FOOTERS_RECEIVED;
1707 continue;
1708 }
1709 process_header_line(connection, line);
1710 connection->state = MHD_CONNECTION_FOOTER_PART_RECEIVED;
1711 continue;
1712 case MHD_CONNECTION_FOOTER_PART_RECEIVED:
1713 line = get_next_header_line(connection);
1714 if (line == NULL)
1715 break;
1716 process_broken_line(connection,
1717 line,
1718 MHD_FOOTER_KIND);
1719 if (strlen(line) == 0)
1720 {
1721 connection->state = MHD_CONNECTION_FOOTERS_RECEIVED;
1722 continue;
1723 }
1724 continue;
1725 case MHD_CONNECTION_FOOTERS_RECEIVED:
1726 call_connection_handler (connection); /* "final" call */
1727 if (connection->state == MHD_CONNECTION_CLOSED)
1728 continue;
1729 if (connection->response == NULL)
1730 break; /* try again next time */
1731 if (MHD_NO == build_header_response (connection))
1732 {
1733 /* oops - close! */
1264#if HAVE_MESSAGES 1734#if HAVE_MESSAGES
1265 MHD_DLOG (connection->daemon, 1735 MHD_DLOG (connection->daemon,
1266 "Failed to send data: %s\n", STRERROR (errno)); 1736 "Closing connection (failed to create response header)\n");
1267#endif 1737#endif
1268 connection_close_error (connection); 1738 connection->state = MHD_CONNECTION_CLOSED;
1269 return MHD_YES; 1739 continue;
1270 } 1740 }
1271#if DEBUG_SEND_DATA 1741 connection->state = MHD_CONNECTION_HEADERS_SENDING;
1272 fprintf (stderr, 1742 break;
1273 "Sent HEADER response: `%.*s'\n", 1743 case MHD_CONNECTION_HEADERS_SENDING:
1274 ret, 1744 /* no default action */
1275 &connection->write_buffer[connection-> 1745 break;
1276 write_buffer_send_offset]); 1746 case MHD_CONNECTION_HEADERS_SENT:
1277#endif 1747 if (connection->have_chunked_upload)
1278 connection->write_buffer_send_offset += ret; 1748 connection->state = MHD_CONNECTION_CHUNKED_BODY_UNREADY;
1279 if (connection->write_buffer_append_offset == 1749 else
1280 connection->write_buffer_send_offset) 1750 connection->state = MHD_CONNECTION_NORMAL_BODY_UNREADY;
1281 { 1751 continue;
1282 connection->write_buffer_append_offset = 0; 1752 case MHD_CONNECTION_NORMAL_BODY_READY:
1283 connection->write_buffer_send_offset = 0; 1753 /* nothing to do here */
1284 connection->have_sent_headers = MHD_YES; 1754 break;
1285 MHD_pool_reallocate (connection->pool, 1755 case MHD_CONNECTION_NORMAL_BODY_UNREADY:
1286 connection->write_buffer, 1756 if (connection->response->crc != NULL)
1287 connection->write_buffer_size, 0); 1757 pthread_mutex_lock (&connection->response->mutex);
1288 connection->write_buffer = NULL; 1758 if (MHD_YES == try_ready_normal_body(connection))
1289 connection->write_buffer_size = 0; 1759 {
1290 } 1760 if (connection->response->crc != NULL)
1291 return MHD_YES; 1761 pthread_mutex_unlock (&connection->response->mutex);
1292 } 1762 connection->state = MHD_CONNECTION_NORMAL_BODY_READY;
1293 if (response->total_size < connection->response_write_position) 1763 break;
1294 abort (); /* internal error */ 1764 }
1295 if (response->crc != NULL) 1765 if (connection->response->crc != NULL)
1296 pthread_mutex_lock (&response->mutex); 1766 pthread_mutex_unlock (&connection->response->mutex);
1297 1767 /* not ready, no socket action */
1298 /* prepare send buffer */ 1768 break;
1299 if ((response->crc != NULL) && 1769 case MHD_CONNECTION_CHUNKED_BODY_READY:
1300 ((response->data_start > connection->response_write_position) || 1770 /* nothing to do here */
1301 (response->data_start + response->data_size <= 1771 break;
1302 connection->response_write_position)) 1772 case MHD_CONNECTION_CHUNKED_BODY_UNREADY:
1303 && (MHD_YES != ready_response (connection))) 1773 if (connection->response->crc != NULL)
1304 { 1774 pthread_mutex_lock (&connection->response->mutex);
1305 pthread_mutex_unlock (&response->mutex); 1775 if (MHD_YES == try_ready_chunked_body(connection))
1306 return MHD_YES; 1776 {
1307 } 1777 if (connection->response->crc != NULL)
1308 /* transmit */ 1778 pthread_mutex_unlock (&connection->response->mutex);
1309 ret = SEND (connection->socket_fd, 1779 connection->state = MHD_CONNECTION_CHUNKED_BODY_READY;
1310 &response->data[connection->response_write_position - 1780 continue;
1311 response->data_start], 1781 }
1312 response->data_size - (connection->response_write_position - 1782 if (connection->response->crc != NULL)
1313 response->data_start), MSG_NOSIGNAL); 1783 pthread_mutex_unlock (&connection->response->mutex);
1314 if (response->crc != NULL) 1784 break;
1315 pthread_mutex_unlock (&response->mutex); 1785 case MHD_CONNECTION_BODY_SENT:
1316 if (ret < 0) 1786 build_header_response(connection);
1787 if (connection->write_buffer_send_offset == connection->write_buffer_append_offset)
1788 connection->state = MHD_CONNECTION_FOOTERS_SENT;
1789 else
1790 connection->state = MHD_CONNECTION_FOOTERS_SENDING;
1791 continue;
1792 case MHD_CONNECTION_FOOTERS_SENDING:
1793 /* no default action */
1794 break;
1795 case MHD_CONNECTION_FOOTERS_SENT:
1796 MHD_destroy_response (connection->response);
1797 if (connection->daemon->notify_completed != NULL)
1798 connection->daemon->notify_completed (connection->daemon->
1799 notify_completed_cls,
1800 connection,
1801 &connection->client_context,
1802 MHD_REQUEST_TERMINATED_COMPLETED_OK);
1803 end = MHD_lookup_connection_value (connection,
1804 MHD_HEADER_KIND,
1805 MHD_HTTP_HEADER_CONNECTION);
1806 connection->client_context = NULL;
1807 connection->continue_message_write_offset = 0;
1808 connection->responseCode = 0;
1809 connection->response = NULL;
1810 connection->headers_received = NULL;
1811 connection->response_write_position = 0;
1812 connection->have_chunked_upload = MHD_NO;
1813 connection->method = NULL;
1814 connection->url = NULL;
1815 connection->write_buffer = NULL;
1816 connection->write_buffer_size = 0;
1817 connection->write_buffer_send_offset = 0;
1818 connection->write_buffer_append_offset = 0;
1819 if ((end != NULL) && (0 == strcasecmp (end, "close")))
1820 {
1821 connection->read_closed = MHD_YES;
1822 connection->read_buffer_offset = 0;
1823 }
1824 if ( ( (MHD_YES == connection->read_closed) &&
1825 (0 == connection->read_buffer_offset) ) ||
1826 (connection->version == NULL) ||
1827 (0 != strcasecmp (MHD_HTTP_VERSION_1_1, connection->version)) )
1828 {
1829 connection->state = MHD_CONNECTION_CLOSED;
1830 MHD_pool_destroy (connection->pool);
1831 connection->pool = NULL;
1832 connection->read_buffer = NULL;
1833 connection->read_buffer_size = 0;
1834 connection->read_buffer_offset = 0;
1835 }
1836 else
1837 {
1838 connection->version = NULL;
1839 connection->state = MHD_CONNECTION_INIT;
1840 connection->read_buffer
1841 = MHD_pool_reset(connection->pool,
1842 connection->read_buffer,
1843 connection->read_buffer_size);
1844 }
1845 continue;
1846 case MHD_CONNECTION_CLOSED:
1847 if (connection->socket_fd != -1)
1848 connection_close_error (connection);
1849 break;
1850 default:
1851 EXTRA_CHECK(0);
1852 break;
1853 }
1854 break;
1855 }
1856 timeout = connection->daemon->connection_timeout;
1857 if ( (timeout != 0) &&
1858 (time(NULL) - timeout > connection->last_activity) )
1317 { 1859 {
1318 if (errno == EINTR)
1319 return MHD_YES;
1320#if HAVE_MESSAGES
1321 MHD_DLOG (connection->daemon,
1322 "Failed to send data: %s\n", STRERROR (errno));
1323#endif
1324 connection_close_error (connection); 1860 connection_close_error (connection);
1325 return MHD_YES; 1861 return MHD_NO;
1326 }
1327#if DEBUG_SEND_DATA
1328 fprintf (stderr,
1329 "Sent DATA response: `%.*s'\n",
1330 ret,
1331 &response->data[connection->response_write_position -
1332 response->data_start]);
1333#endif
1334 connection->response_write_position += ret;
1335 if (connection->response_write_position > response->total_size)
1336 abort (); /* internal error */
1337 if (connection->response_write_position == response->total_size)
1338 {
1339 if ((connection->have_received_body == MHD_NO) ||
1340 (connection->have_received_headers == MHD_NO))
1341 abort (); /* internal error */
1342 MHD_destroy_response (response);
1343 if (connection->daemon->notify_completed != NULL)
1344 connection->daemon->notify_completed (connection->daemon->
1345 notify_completed_cls,
1346 connection,
1347 &connection->client_context,
1348 MHD_REQUEST_TERMINATED_COMPLETED_OK);
1349 end = MHD_lookup_connection_value (connection,
1350 MHD_HEADER_KIND,
1351 MHD_HTTP_HEADER_CONNECTION);
1352 connection->client_context = NULL;
1353 connection->continue_message_write_offset = 0;
1354 connection->responseCode = 0;
1355 connection->response = NULL;
1356 connection->headers_received = NULL;
1357 connection->have_received_headers = MHD_NO;
1358 connection->have_sent_headers = MHD_NO;
1359 connection->have_received_body = MHD_NO;
1360 connection->response_write_position = 0;
1361 connection->have_chunked_upload = MHD_NO;
1362 connection->method = NULL;
1363 connection->url = NULL;
1364 if ((end != NULL) && (0 == strcasecmp (end, "close")))
1365 {
1366 /* other side explicitly requested
1367 that we close the connection after
1368 this request */
1369 connection->read_close = MHD_YES;
1370 }
1371 if ((connection->read_close == MHD_YES) ||
1372 (0 != strcasecmp (MHD_HTTP_VERSION_1_1, connection->version)))
1373 {
1374 /* closed for reading => close for good! */
1375 if (connection->socket_fd != -1)
1376 {
1377#if DEBUG_CLOSE
1378#if HAVE_MESSAGES
1379 MHD_DLOG (connection->daemon,
1380 "Closing connection (http 1.0 or end-of-stream for unknown content length)\n");
1381#endif
1382#endif
1383 SHUTDOWN (connection->socket_fd, SHUT_RDWR);
1384 CLOSE (connection->socket_fd);
1385 }
1386 connection->socket_fd = -1;
1387 }
1388 connection->version = NULL;
1389 connection->read_buffer = NULL;
1390 connection->write_buffer = NULL;
1391 connection->read_buffer_size = 0;
1392 connection->read_buffer_offset = 0;
1393 connection->write_buffer_size = 0;
1394 connection->write_buffer_send_offset = 0;
1395 connection->write_buffer_append_offset = 0;
1396 MHD_pool_destroy (connection->pool);
1397 connection->pool = NULL;
1398 } 1862 }
1399 return MHD_YES; 1863 return MHD_YES;
1864
1400} 1865}
1401 1866
1402/* end of connection.c */ 1867/* end of connection.c */
diff --git a/src/daemon/connection.h b/src/daemon/connection.h
index e00a83e1..a1763b55 100644
--- a/src/daemon/connection.h
+++ b/src/daemon/connection.h
@@ -39,18 +39,14 @@ MHD_connection_get_fdset (struct MHD_Connection *connection,
39 fd_set * write_fd_set, 39 fd_set * write_fd_set,
40 fd_set * except_fd_set, int *max_fd); 40 fd_set * except_fd_set, int *max_fd);
41 41
42
43/**
44 * Call the handler of the application for this
45 * connection.
46 */
47void MHD_call_connection_handler (struct MHD_Connection *connection);
48
49/** 42/**
50 * This function handles a particular connection when it has been 43 * This function handles a particular connection when it has been
51 * determined that there is data to be read off a socket. All implementations 44 * determined that there is data to be read off a socket. All implementations
52 * (multithreaded, external select, internal select) call this function 45 * (multithreaded, external select, internal select) call this function
53 * to handle reads. 46 * to handle reads.
47 *
48 * @return MHD_YES if we should continue to process the
49 * connection (not dead yet), MHD_NO if it died
54 */ 50 */
55int MHD_connection_handle_read (struct MHD_Connection *connection); 51int MHD_connection_handle_read (struct MHD_Connection *connection);
56 52
@@ -60,8 +56,23 @@ int MHD_connection_handle_read (struct MHD_Connection *connection);
60 * determined that the socket can be written to. If there is no data 56 * determined that the socket can be written to. If there is no data
61 * to be written, however, the function call does nothing. All implementations 57 * to be written, however, the function call does nothing. All implementations
62 * (multithreaded, external select, internal select) call this function 58 * (multithreaded, external select, internal select) call this function
59 *
60 * @return MHD_YES if we should continue to process the
61 * connection (not dead yet), MHD_NO if it died
63 */ 62 */
64int MHD_connection_handle_write (struct MHD_Connection *connection); 63int MHD_connection_handle_write (struct MHD_Connection *connection);
65 64
66 65
66/**
67 * This function was created to handle per-connection processing that
68 * has to happen even if the socket cannot be read or written to. All
69 * implementations (multithreaded, external select, internal select)
70 * call this function.
71 *
72 * @return MHD_YES if we should continue to process the
73 * connection (not dead yet), MHD_NO if it died
74 */
75int
76MHD_connection_handle_idle (struct MHD_Connection *connection);
77
67#endif 78#endif
diff --git a/src/daemon/daemon.c b/src/daemon/daemon.c
index 19c614a1..b6f1e9f3 100644
--- a/src/daemon/daemon.c
+++ b/src/daemon/daemon.c
@@ -52,85 +52,6 @@
52 */ 52 */
53#define DEBUG_CONNECT MHD_NO 53#define DEBUG_CONNECT MHD_NO
54 54
55/**
56 * Register an access handler for all URIs beginning with uri_prefix.
57 *
58 * @param uri_prefix
59 * @return MRI_NO if a handler for this exact prefix
60 * already exists
61 */
62int
63MHD_register_handler (struct MHD_Daemon *daemon,
64 const char *uri_prefix,
65 MHD_AccessHandlerCallback dh, void *dh_cls)
66{
67 struct MHD_Access_Handler *ah;
68
69 if ((daemon == NULL) || (uri_prefix == NULL) || (dh == NULL))
70 return MHD_NO;
71 ah = daemon->handlers;
72 while (ah != NULL)
73 {
74 if (0 == strcmp (uri_prefix, ah->uri_prefix))
75 return MHD_NO;
76 ah = ah->next;
77 }
78 ah = malloc (sizeof (struct MHD_Access_Handler));
79 if (ah == NULL)
80 {
81#if HAVE_MESSAGES
82 MHD_DLOG (daemon, "Error allocating memory: %s\n", STRERROR (errno));
83#endif
84 return MHD_NO;
85 }
86
87 ah->next = daemon->handlers;
88 ah->uri_prefix = strdup (uri_prefix);
89 ah->dh = dh;
90 ah->dh_cls = dh_cls;
91 daemon->handlers = ah;
92 return MHD_YES;
93}
94
95
96/**
97 * Unregister an access handler for the URIs beginning with
98 * uri_prefix.
99 *
100 * @param uri_prefix
101 * @return MHD_NO if a handler for this exact prefix
102 * is not known for this daemon
103 */
104int
105MHD_unregister_handler (struct MHD_Daemon *daemon,
106 const char *uri_prefix,
107 MHD_AccessHandlerCallback dh, void *dh_cls)
108{
109 struct MHD_Access_Handler *prev;
110 struct MHD_Access_Handler *pos;
111
112 if ((daemon == NULL) || (uri_prefix == NULL) || (dh == NULL))
113 return MHD_NO;
114 pos = daemon->handlers;
115 prev = NULL;
116 while (pos != NULL)
117 {
118 if ((dh == pos->dh) &&
119 (dh_cls == pos->dh_cls) &&
120 (0 == strcmp (uri_prefix, pos->uri_prefix)))
121 {
122 if (prev == NULL)
123 daemon->handlers = pos->next;
124 else
125 prev->next = pos->next;
126 free (pos);
127 return MHD_YES;
128 }
129 prev = pos;
130 pos = pos->next;
131 }
132 return MHD_NO;
133}
134 55
135/** 56/**
136 * Obtain the select sets for this daemon. 57 * Obtain the select sets for this daemon.
@@ -175,7 +96,6 @@ MHD_get_fdset (struct MHD_Daemon *daemon,
175 return MHD_YES; 96 return MHD_YES;
176} 97}
177 98
178
179/** 99/**
180 * Main function of the thread that handles an individual 100 * Main function of the thread that handles an individual
181 * connection. 101 * connection.
@@ -191,26 +111,27 @@ MHD_handle_connection (void *data)
191 int max; 111 int max;
192 struct timeval tv; 112 struct timeval tv;
193 unsigned int timeout; 113 unsigned int timeout;
194 time_t now; 114 unsigned int now;
195 115
196 if (con == NULL) 116 if (con == NULL)
197 abort (); 117 abort ();
198 timeout = con->daemon->connection_timeout; 118 timeout = con->daemon->connection_timeout;
199 now = time (NULL); 119 while ( (!con->daemon->shutdown) &&
200 while ((!con->daemon->shutdown) && 120 (con->socket_fd != -1) )
201 (con->socket_fd != -1) &&
202 ((timeout == 0) || (now - timeout > con->last_activity)))
203 { 121 {
204 FD_ZERO (&rs); 122 FD_ZERO (&rs);
205 FD_ZERO (&ws); 123 FD_ZERO (&ws);
206 FD_ZERO (&es); 124 FD_ZERO (&es);
207 max = 0; 125 max = 0;
208 MHD_connection_get_fdset (con, &rs, &ws, &es, &max); 126 MHD_connection_get_fdset (con, &rs, &ws, &es, &max);
127 now = time(NULL);
209 tv.tv_usec = 0; 128 tv.tv_usec = 0;
210 tv.tv_sec = timeout - (now - con->last_activity); 129 if ( timeout > (now - con->last_activity) )
130 tv.tv_sec = timeout - (now - con->last_activity);
131 else
132 tv.tv_sec = 0;
211 num_ready = SELECT (max + 1, 133 num_ready = SELECT (max + 1,
212 &rs, &ws, &es, (timeout != 0) ? &tv : NULL); 134 &rs, &ws, &es, (timeout != 0) ? &tv : NULL);
213 now = time (NULL);
214 if (num_ready < 0) 135 if (num_ready < 0)
215 { 136 {
216 if (errno == EINTR) 137 if (errno == EINTR)
@@ -221,18 +142,13 @@ MHD_handle_connection (void *data)
221#endif 142#endif
222 break; 143 break;
223 } 144 }
224 if (((FD_ISSET (con->socket_fd, &rs)) && 145 if (FD_ISSET (con->socket_fd, &rs))
225 (MHD_YES != MHD_connection_handle_read (con))) || 146 MHD_connection_handle_read (con);
226 ((con->socket_fd != -1) &&
227 (FD_ISSET (con->socket_fd, &ws)) &&
228 (MHD_YES != MHD_connection_handle_write (con))))
229 break;
230 if ((con->have_received_headers == MHD_YES) && (con->response == NULL))
231 MHD_call_connection_handler (con);
232 if ((con->socket_fd != -1) && 147 if ((con->socket_fd != -1) &&
233 ((FD_ISSET (con->socket_fd, &rs)) || 148 (FD_ISSET (con->socket_fd, &ws)) )
234 (FD_ISSET (con->socket_fd, &ws)))) 149 MHD_connection_handle_write (con);
235 con->last_activity = now; 150 if (con->socket_fd != -1)
151 MHD_connection_handle_idle (con);
236 } 152 }
237 if (con->socket_fd != -1) 153 if (con->socket_fd != -1)
238 { 154 {
@@ -370,11 +286,6 @@ MHD_accept_connection (struct MHD_Daemon *daemon)
370 * Free resources associated with all closed connections. 286 * Free resources associated with all closed connections.
371 * (destroy responses, free buffers, etc.). A connection 287 * (destroy responses, free buffers, etc.). A connection
372 * is known to be closed if the socket_fd is -1. 288 * is known to be closed if the socket_fd is -1.
373 *
374 * Also performs connection actions that need to be run
375 * even if the connection is not selectable (such as
376 * calling the application again with upload data when
377 * the upload data buffer is full).
378 */ 289 */
379static void 290static void
380MHD_cleanup_connections (struct MHD_Daemon *daemon) 291MHD_cleanup_connections (struct MHD_Daemon *daemon)
@@ -382,33 +293,11 @@ MHD_cleanup_connections (struct MHD_Daemon *daemon)
382 struct MHD_Connection *pos; 293 struct MHD_Connection *pos;
383 struct MHD_Connection *prev; 294 struct MHD_Connection *prev;
384 void *unused; 295 void *unused;
385 time_t timeout;
386 296
387 timeout = time (NULL);
388 if (daemon->connection_timeout != 0)
389 timeout -= daemon->connection_timeout;
390 else
391 timeout = 0;
392 pos = daemon->connections; 297 pos = daemon->connections;
393 prev = NULL; 298 prev = NULL;
394 while (pos != NULL) 299 while (pos != NULL)
395 { 300 {
396 if ((pos->last_activity < timeout) && (pos->socket_fd != -1))
397 {
398#if DEBUG_CLOSE
399#if HAVE_MESSAGES
400 MHD_DLOG (daemon, "Connection timed out, closing connection\n");
401#endif
402#endif
403 SHUTDOWN (pos->socket_fd, SHUT_RDWR);
404 CLOSE (pos->socket_fd);
405 pos->socket_fd = -1;
406 if (pos->daemon->notify_completed != NULL)
407 pos->daemon->notify_completed (pos->daemon->notify_completed_cls,
408 pos,
409 &pos->client_context,
410 MHD_REQUEST_TERMINATED_TIMEOUT_REACHED);
411 }
412 if (pos->socket_fd == -1) 301 if (pos->socket_fd == -1)
413 { 302 {
414 if (prev == NULL) 303 if (prev == NULL)
@@ -420,8 +309,7 @@ MHD_cleanup_connections (struct MHD_Daemon *daemon)
420 pthread_kill (pos->pid, SIGALRM); 309 pthread_kill (pos->pid, SIGALRM);
421 pthread_join (pos->pid, &unused); 310 pthread_join (pos->pid, &unused);
422 } 311 }
423 if (pos->response != NULL) 312 MHD_destroy_response (pos->response);
424 MHD_destroy_response (pos->response);
425 MHD_pool_destroy (pos->pool); 313 MHD_pool_destroy (pos->pool);
426 free (pos->addr); 314 free (pos->addr);
427 free (pos); 315 free (pos);
@@ -432,12 +320,6 @@ MHD_cleanup_connections (struct MHD_Daemon *daemon)
432 pos = prev->next; 320 pos = prev->next;
433 continue; 321 continue;
434 } 322 }
435
436 if ((0 == (daemon->options & MHD_USE_THREAD_PER_CONNECTION)) &&
437 ((pos->have_received_headers == MHD_YES)
438 && (pos->response == NULL)))
439 MHD_call_connection_handler (pos);
440
441 prev = pos; 323 prev = pos;
442 pos = pos->next; 324 pos = pos->next;
443 } 325 }
@@ -573,15 +455,12 @@ MHD_select (struct MHD_Daemon *daemon, int may_block)
573 if (ds != -1) 455 if (ds != -1)
574 { 456 {
575 if (FD_ISSET (ds, &rs)) 457 if (FD_ISSET (ds, &rs))
576 { 458 MHD_connection_handle_read (pos);
577 pos->last_activity = now; 459 if ( (pos->socket_fd != -1) &&
578 MHD_connection_handle_read (pos); 460 (FD_ISSET (ds, &ws)) )
579 } 461 MHD_connection_handle_write (pos);
580 if (FD_ISSET (ds, &ws)) 462 if (pos->socket_fd != -1)
581 { 463 MHD_connection_handle_idle(pos);
582 pos->last_activity = now;
583 MHD_connection_handle_write (pos);
584 }
585 } 464 }
586 pos = pos->next; 465 pos = pos->next;
587 } 466 }
@@ -726,10 +605,8 @@ MHD_start_daemon (unsigned int options,
726 retVal->apc = apc; 605 retVal->apc = apc;
727 retVal->apc_cls = apc_cls; 606 retVal->apc_cls = apc_cls;
728 retVal->socket_fd = socket_fd; 607 retVal->socket_fd = socket_fd;
729 retVal->default_handler.dh = dh; 608 retVal->default_handler = dh;
730 retVal->default_handler.dh_cls = dh_cls; 609 retVal->default_handler_cls = dh_cls;
731 retVal->default_handler.uri_prefix = "";
732 retVal->default_handler.next = NULL;
733 retVal->max_connections = MHD_MAX_CONNECTIONS_DEFAULT; 610 retVal->max_connections = MHD_MAX_CONNECTIONS_DEFAULT;
734 retVal->pool_size = MHD_POOL_SIZE_DEFAULT; 611 retVal->pool_size = MHD_POOL_SIZE_DEFAULT;
735 retVal->connection_timeout = 0; /* no timeout */ 612 retVal->connection_timeout = 0; /* no timeout */
diff --git a/src/daemon/daemontest_get.c b/src/daemon/daemontest_get.c
index c6c63fd8..1a6ca12a 100644
--- a/src/daemon/daemontest_get.c
+++ b/src/daemon/daemontest_get.c
@@ -66,16 +66,24 @@ ahc_echo (void *cls,
66 const char *upload_data, unsigned int *upload_data_size, 66 const char *upload_data, unsigned int *upload_data_size,
67 void **unused) 67 void **unused)
68{ 68{
69 static int ptr;
69 const char *me = cls; 70 const char *me = cls;
70 struct MHD_Response *response; 71 struct MHD_Response *response;
71 int ret; 72 int ret;
72 73
73 if (0 != strcmp (me, method)) 74 if (0 != strcmp (me, method))
74 return MHD_NO; /* unexpected method */ 75 return MHD_NO; /* unexpected method */
76 if (&ptr != *unused) {
77 *unused = &ptr;
78 return MHD_YES;
79 }
80 *unused = NULL;
75 response = MHD_create_response_from_data (strlen (url), 81 response = MHD_create_response_from_data (strlen (url),
76 (void *) url, MHD_NO, MHD_YES); 82 (void *) url, MHD_NO, MHD_YES);
77 ret = MHD_queue_response (connection, MHD_HTTP_OK, response); 83 ret = MHD_queue_response (connection, MHD_HTTP_OK, response);
78 MHD_destroy_response (response); 84 MHD_destroy_response (response);
85 if (ret == MHD_NO)
86 abort();
79 return ret; 87 return ret;
80} 88}
81 89
@@ -93,11 +101,11 @@ testInternalGet ()
93 cbc.size = 2048; 101 cbc.size = 2048;
94 cbc.pos = 0; 102 cbc.pos = 0;
95 d = MHD_start_daemon (MHD_USE_SELECT_INTERNALLY | MHD_USE_DEBUG, 103 d = MHD_start_daemon (MHD_USE_SELECT_INTERNALLY | MHD_USE_DEBUG,
96 1080, NULL, NULL, &ahc_echo, "GET", MHD_OPTION_END); 104 11080, NULL, NULL, &ahc_echo, "GET", MHD_OPTION_END);
97 if (d == NULL) 105 if (d == NULL)
98 return 1; 106 return 1;
99 c = curl_easy_init (); 107 c = curl_easy_init ();
100 curl_easy_setopt (c, CURLOPT_URL, "http://localhost:1080/hello_world"); 108 curl_easy_setopt (c, CURLOPT_URL, "http://localhost:11080/hello_world");
101 curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, &copyBuffer); 109 curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, &copyBuffer);
102 curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc); 110 curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc);
103 curl_easy_setopt (c, CURLOPT_FAILONERROR, 1); 111 curl_easy_setopt (c, CURLOPT_FAILONERROR, 1);
@@ -150,12 +158,12 @@ testMultithreadedGet ()
150 curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, &copyBuffer); 158 curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, &copyBuffer);
151 curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc); 159 curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc);
152 curl_easy_setopt (c, CURLOPT_FAILONERROR, 1); 160 curl_easy_setopt (c, CURLOPT_FAILONERROR, 1);
153 curl_easy_setopt (c, CURLOPT_TIMEOUT, 2L); 161 curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L);
154 if (oneone) 162 if (oneone)
155 curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1); 163 curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
156 else 164 else
157 curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0); 165 curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
158 curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 2L); 166 curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 15L);
159 // NOTE: use of CONNECTTIMEOUT without also 167 // NOTE: use of CONNECTTIMEOUT without also
160 // setting NOSIGNAL results in really weird 168 // setting NOSIGNAL results in really weird
161 // crashes on my system! 169 // crashes on my system!
@@ -214,8 +222,8 @@ testExternalGet ()
214 curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1); 222 curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
215 else 223 else
216 curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0); 224 curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
217 curl_easy_setopt (c, CURLOPT_TIMEOUT, 5L); 225 curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L);
218 curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 5L); 226 curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 15L);
219 // NOTE: use of CONNECTTIMEOUT without also 227 // NOTE: use of CONNECTTIMEOUT without also
220 // setting NOSIGNAL results in really weird 228 // setting NOSIGNAL results in really weird
221 // crashes on my system! 229 // crashes on my system!
diff --git a/src/daemon/daemontest_large_put.c b/src/daemon/daemontest_large_put.c
index 2a9ad4fa..3bbf707e 100644
--- a/src/daemon/daemontest_large_put.c
+++ b/src/daemon/daemontest_large_put.c
@@ -96,8 +96,16 @@ ahc_echo (void *cls,
96 return MHD_NO; /* unexpected method */ 96 return MHD_NO; /* unexpected method */
97 if ((*done) == 0) 97 if ((*done) == 0)
98 { 98 {
99 if (*upload_data_size != PUT_SIZE) 99 if (*upload_data_size != PUT_SIZE)
100 return MHD_YES; /* not yet ready */ 100 {
101#if 0
102 fprintf(stderr,
103 "Waiting for more data (%u/%u)...\n",
104 *upload_data_size,
105 PUT_SIZE);
106#endif
107 return MHD_YES; /* not yet ready */
108 }
101 if (0 == memcmp (upload_data, put_buffer, PUT_SIZE)) 109 if (0 == memcmp (upload_data, put_buffer, PUT_SIZE))
102 { 110 {
103 *upload_data_size = 0; 111 *upload_data_size = 0;
@@ -227,7 +235,13 @@ testMultithreadedPut ()
227 curl_easy_cleanup (c); 235 curl_easy_cleanup (c);
228 MHD_stop_daemon (d); 236 MHD_stop_daemon (d);
229 if (cbc.pos != strlen ("/hello_world")) 237 if (cbc.pos != strlen ("/hello_world"))
230 return 64; 238 {
239 fprintf(stderr,
240 "Got invalid response `%.*s'\n",
241 cbc.pos,
242 cbc.buf);
243 return 64;
244 }
231 if (0 != strncmp ("/hello_world", cbc.buf, strlen ("/hello_world"))) 245 if (0 != strncmp ("/hello_world", cbc.buf, strlen ("/hello_world")))
232 return 128; 246 return 128;
233 return 0; 247 return 0;
@@ -260,7 +274,10 @@ testExternalPut ()
260 multi = NULL; 274 multi = NULL;
261 d = MHD_start_daemon (MHD_USE_DEBUG, 275 d = MHD_start_daemon (MHD_USE_DEBUG,
262 1082, 276 1082,
263 NULL, NULL, &ahc_echo, &done_flag, MHD_OPTION_END); 277 NULL, NULL, &ahc_echo, &done_flag,
278 MHD_OPTION_CONNECTION_MEMORY_LIMIT,
279 PUT_SIZE * 4,
280 MHD_OPTION_END);
264 if (d == NULL) 281 if (d == NULL)
265 return 256; 282 return 256;
266 c = curl_easy_init (); 283 c = curl_easy_init ();
@@ -357,9 +374,15 @@ testExternalPut ()
357 } 374 }
358 MHD_stop_daemon (d); 375 MHD_stop_daemon (d);
359 if (cbc.pos != strlen ("/hello_world")) 376 if (cbc.pos != strlen ("/hello_world"))
360 return 64; 377 {
378 fprintf(stderr,
379 "Got invalid response `%.*s'\n",
380 cbc.pos,
381 cbc.buf);
382 return 8192;
383 }
361 if (0 != strncmp ("/hello_world", cbc.buf, strlen ("/hello_world"))) 384 if (0 != strncmp ("/hello_world", cbc.buf, strlen ("/hello_world")))
362 return 128; 385 return 16384;
363 return 0; 386 return 0;
364} 387}
365 388
@@ -380,7 +403,7 @@ main (int argc, char *const *argv)
380 errorCount += testInternalPut (); 403 errorCount += testInternalPut ();
381 errorCount += testMultithreadedPut (); 404 errorCount += testMultithreadedPut ();
382 } 405 }
383 errorCount += testExternalPut (); 406 errorCount += testExternalPut ();
384 free (put_buffer); 407 free (put_buffer);
385 if (errorCount != 0) 408 if (errorCount != 0)
386 fprintf (stderr, "Error (code: %u)\n", errorCount); 409 fprintf (stderr, "Error (code: %u)\n", errorCount);
diff --git a/src/daemon/daemontest_postform.c b/src/daemon/daemontest_postform.c
index 75df1eb0..00734df6 100644
--- a/src/daemon/daemontest_postform.c
+++ b/src/daemon/daemontest_postform.c
@@ -72,6 +72,13 @@ post_iterator (void *cls,
72{ 72{
73 int *eok = cls; 73 int *eok = cls;
74 74
75#if 0
76 fprintf(stderr,
77 "PI sees %s-%.*s\n",
78 key,
79 size,
80 value);
81#endif
75 if ((0 == strcmp (key, "name")) && 82 if ((0 == strcmp (key, "name")) &&
76 (size == strlen ("daniel")) && (0 == strncmp (value, "daniel", size))) 83 (size == strlen ("daniel")) && (0 == strncmp (value, "daniel", size)))
77 (*eok) |= 1; 84 (*eok) |= 1;
@@ -95,7 +102,7 @@ ahc_echo (void *cls,
95 struct MHD_PostProcessor *pp; 102 struct MHD_PostProcessor *pp;
96 int ret; 103 int ret;
97 104
98 if (0 != strcmp ("POST", method)) 105 if (0 != strcmp ("POST", method))
99 { 106 {
100 printf ("METHOD: %s\n", method); 107 printf ("METHOD: %s\n", method);
101 return MHD_NO; /* unexpected method */ 108 return MHD_NO; /* unexpected method */
diff --git a/src/daemon/daemontest_put_chunked.c b/src/daemon/daemontest_put_chunked.c
index 9f00dbb3..84afc444 100644
--- a/src/daemon/daemontest_put_chunked.c
+++ b/src/daemon/daemontest_put_chunked.c
@@ -105,6 +105,11 @@ ahc_echo (void *cls,
105 printf ("Invalid upload data `%8s'!\n", upload_data); 105 printf ("Invalid upload data `%8s'!\n", upload_data);
106 return MHD_NO; 106 return MHD_NO;
107 } 107 }
108#if 0
109 fprintf(stderr,
110 "Not ready for response: %u/%u\n",
111 *done, 8);
112#endif
108 return MHD_YES; 113 return MHD_YES;
109 } 114 }
110 response = MHD_create_response_from_data (strlen (url), 115 response = MHD_create_response_from_data (strlen (url),
diff --git a/src/daemon/fileserver_example.c b/src/daemon/fileserver_example.c
index c5bf762b..9f86fd2c 100644
--- a/src/daemon/fileserver_example.c
+++ b/src/daemon/fileserver_example.c
@@ -52,8 +52,9 @@ ahc_echo (void *cls,
52 const char *url, 52 const char *url,
53 const char *method, 53 const char *method,
54 const char *upload_data, 54 const char *upload_data,
55 const char *version, unsigned int *upload_data_size, void **unused) 55 const char *version, unsigned int *upload_data_size, void **ptr)
56{ 56{
57 static int aptr;
57 struct MHD_Response *response; 58 struct MHD_Response *response;
58 int ret; 59 int ret;
59 FILE *file; 60 FILE *file;
@@ -61,6 +62,13 @@ ahc_echo (void *cls,
61 62
62 if (0 != strcmp (method, "GET")) 63 if (0 != strcmp (method, "GET"))
63 return MHD_NO; /* unexpected method */ 64 return MHD_NO; /* unexpected method */
65 if (&aptr != *ptr)
66 {
67 /* do never respond on first call */
68 *ptr = &aptr;
69 return MHD_YES;
70 }
71 *ptr = NULL; /* reset when done */
64 file = fopen (&url[1], "r"); 72 file = fopen (&url[1], "r");
65 if (file == NULL) 73 if (file == NULL)
66 { 74 {
diff --git a/src/daemon/internal.h b/src/daemon/internal.h
index de4ae725..4749d10d 100644
--- a/src/daemon/internal.h
+++ b/src/daemon/internal.h
@@ -85,21 +85,9 @@ struct MHD_HTTP_Header
85 char *value; 85 char *value;
86 86
87 enum MHD_ValueKind kind; 87 enum MHD_ValueKind kind;
88};
89
90
91struct MHD_Access_Handler
92{
93 struct MHD_Access_Handler *next;
94
95 char *uri_prefix;
96
97 MHD_AccessHandlerCallback dh;
98 88
99 void *dh_cls;
100}; 89};
101 90
102
103/** 91/**
104 * Representation of a response. 92 * Representation of a response.
105 */ 93 */
@@ -172,7 +160,129 @@ struct MHD_Response
172 160
173}; 161};
174 162
163/**
164 * States in a state machine for a connection.
165 *
166 * Transitions are any-state to CLOSED, any state to state+1,
167 * FOOTERS_SENT to INIT. CLOSED is the terminal state and
168 * INIT the initial state.
169 *
170 * Note that transitions for *reading* happen only after
171 * the input has been processed; transitions for
172 * *writing* happen after the respective data has been
173 * put into the write buffer (the write does not have
174 * to be completed yet). A transition to CLOSED or INIT
175 * requires the write to be complete.
176 */
177enum MHD_CONNECTION_STATE
178{
179 /**
180 * Connection just started (no headers received).
181 * Waiting for the line with the request type, URL and version.
182 */
183 MHD_CONNECTION_INIT = 0,
184
185 /**
186 * 1: We got the URL (and request type and version). Wait for a header line.
187 */
188 MHD_CONNECTION_URL_RECEIVED = MHD_CONNECTION_INIT + 1,
189
190 /**
191 * 2: We got part of a multi-line request header. Wait for the rest.
192 */
193 MHD_CONNECTION_HEADER_PART_RECEIVED = MHD_CONNECTION_URL_RECEIVED + 1,
194
195 /**
196 * 3: We got the request headers. Process them.
197 */
198 MHD_CONNECTION_HEADERS_RECEIVED = MHD_CONNECTION_HEADER_PART_RECEIVED + 1,
199
200 /**
201 * 4: We have processed the request headers. Send 100 continue.
202 */
203 MHD_CONNECTION_HEADERS_PROCESSED = MHD_CONNECTION_HEADERS_RECEIVED + 1,
204
205 /**
206 * 5: We have processed the headers and need to send 100 CONTINUE.
207 */
208 MHD_CONNECTION_CONTINUE_SENDING = MHD_CONNECTION_HEADERS_PROCESSED + 1,
209
210 /**
211 * 6: We have sent 100 CONTINUE (or do not need to). Read the message body.
212 */
213 MHD_CONNECTION_CONTINUE_SENT = MHD_CONNECTION_CONTINUE_SENDING + 1,
214
215 /**
216 * 7: We got the request body. Wait for a line of the footer.
217 */
218 MHD_CONNECTION_BODY_RECEIVED = MHD_CONNECTION_CONTINUE_SENT + 1,
175 219
220 /**
221 * 8: We got part of a line of the footer. Wait for the
222 * rest.
223 */
224 MHD_CONNECTION_FOOTER_PART_RECEIVED = MHD_CONNECTION_BODY_RECEIVED + 1,
225
226 /**
227 * 9: We received the entire footer. Wait for a response to be queued
228 * and prepare the response headers.
229 */
230 MHD_CONNECTION_FOOTERS_RECEIVED = MHD_CONNECTION_FOOTER_PART_RECEIVED + 1,
231
232 /**
233 * 10: We have prepared the response headers in the writ buffer.
234 * Send the response headers.
235 */
236 MHD_CONNECTION_HEADERS_SENDING = MHD_CONNECTION_FOOTERS_RECEIVED + 1,
237
238 /**
239 * 11: We have sent the response headers. Get ready to send the body.
240 */
241 MHD_CONNECTION_HEADERS_SENT = MHD_CONNECTION_HEADERS_SENDING + 1,
242
243 /**
244 * 12: We are ready to send a part of a non-chunked body. Send it.
245 */
246 MHD_CONNECTION_NORMAL_BODY_READY = MHD_CONNECTION_HEADERS_SENT + 1,
247
248 /**
249 * 13: We are waiting for the client to provide more
250 * data of a non-chunked body.
251 */
252 MHD_CONNECTION_NORMAL_BODY_UNREADY = MHD_CONNECTION_NORMAL_BODY_READY + 1,
253
254 /**
255 * 14: We are ready to send a chunk.
256 */
257 MHD_CONNECTION_CHUNKED_BODY_READY = MHD_CONNECTION_NORMAL_BODY_UNREADY + 1,
258
259 /**
260 * 15: We are waiting for the client to provide a chunk of the body.
261 */
262 MHD_CONNECTION_CHUNKED_BODY_UNREADY = MHD_CONNECTION_CHUNKED_BODY_READY + 1,
263
264 /**
265 * 16: We have sent the response body. Prepare the footers.
266 */
267 MHD_CONNECTION_BODY_SENT = MHD_CONNECTION_CHUNKED_BODY_UNREADY + 1,
268
269 /**
270 * 17: We have prepared the response footer. Send it.
271 */
272 MHD_CONNECTION_FOOTERS_SENDING = MHD_CONNECTION_BODY_SENT + 1,
273
274 /**
275 * 18: We have sent the response footer. Shutdown or restart.
276 */
277 MHD_CONNECTION_FOOTERS_SENT = MHD_CONNECTION_FOOTERS_SENDING + 1,
278
279 /**
280 * 19: This connection is closed (no more activity
281 * allowed).
282 */
283 MHD_CONNECTION_CLOSED = MHD_CONNECTION_FOOTERS_SENT + 1,
284
285};
176 286
177struct MHD_Connection 287struct MHD_Connection
178{ 288{
@@ -250,6 +360,21 @@ struct MHD_Connection
250 char *write_buffer; 360 char *write_buffer;
251 361
252 /** 362 /**
363 * Last incomplete header line during parsing of headers.
364 * Allocated in pool. Only valid if state is
365 * either HEADER_PART_RECEIVED or FOOTER_PART_RECEIVED.
366 */
367 char *last;
368
369 /**
370 * Position after the colon on the last incomplete header
371 * line during parsing of headers.
372 * Allocated in pool. Only valid if state is
373 * either HEADER_PART_RECEIVED or FOOTER_PART_RECEIVED.
374 */
375 char *colon;
376
377 /**
253 * Foreign address (of length addr_len). MALLOCED (not 378 * Foreign address (of length addr_len). MALLOCED (not
254 * in pool!). 379 * in pool!).
255 */ 380 */
@@ -292,6 +417,12 @@ struct MHD_Connection
292 size_t write_buffer_append_offset; 417 size_t write_buffer_append_offset;
293 418
294 /** 419 /**
420 * How many more bytes of the body do we expect
421 * to read? "-1" for unknown.
422 */
423 size_t remaining_upload_size;
424
425 /**
295 * Current write position in the actual response 426 * Current write position in the actual response
296 * (excluding headers, content only; should be 0 427 * (excluding headers, content only; should be 0
297 * while sending headers). 428 * while sending headers).
@@ -299,13 +430,6 @@ struct MHD_Connection
299 size_t response_write_position; 430 size_t response_write_position;
300 431
301 /** 432 /**
302 * Remaining (!) number of bytes in the upload.
303 * Set to -1 for unknown (connection will close
304 * to indicate end of upload).
305 */
306 size_t remaining_upload_size;
307
308 /**
309 * Position in the 100 CONTINUE message that 433 * Position in the 100 CONTINUE message that
310 * we need to send when receiving http 1.1 requests. 434 * we need to send when receiving http 1.1 requests.
311 */ 435 */
@@ -333,29 +457,15 @@ struct MHD_Connection
333 * Has this socket been closed for reading (i.e. 457 * Has this socket been closed for reading (i.e.
334 * other side closed the connection)? If so, 458 * other side closed the connection)? If so,
335 * we must completely close the connection once 459 * we must completely close the connection once
336 * we are done sending our response. 460 * we are done sending our response (and stop
337 */ 461 * trying to read from this socket).
338 int read_close;
339
340 /**
341 * Have we finished receiving all of the headers yet?
342 * Set to 1 once we are done processing all of the
343 * headers. Note that due to pipelining, it is
344 * possible that the NEXT request is already
345 * (partially) waiting in the read buffer.
346 */
347 int have_received_headers;
348
349 /**
350 * Have we finished receiving the data from a
351 * potential file-upload?
352 */ 462 */
353 int have_received_body; 463 int read_closed;
354 464
355 /** 465 /**
356 * Have we finished sending all of the headers yet? 466 * State in the FSM for this connection.
357 */ 467 */
358 int have_sent_headers; 468 enum MHD_CONNECTION_STATE state;
359 469
360 /** 470 /**
361 * HTTP response code. Only valid if response object 471 * HTTP response code. Only valid if response object
@@ -373,6 +483,11 @@ struct MHD_Connection
373 int response_unready; 483 int response_unready;
374 484
375 /** 485 /**
486 * Are we sending with chunked encoding?
487 */
488 int have_chunked_response;
489
490 /**
376 * Are we receiving with chunked encoding? This will be set to 491 * Are we receiving with chunked encoding? This will be set to
377 * MHD_YES after we parse the headers and are processing the body 492 * MHD_YES after we parse the headers and are processing the body
378 * with chunks. After we are done with the body and we are 493 * with chunks. After we are done with the body and we are
@@ -402,9 +517,15 @@ struct MHD_Connection
402struct MHD_Daemon 517struct MHD_Daemon
403{ 518{
404 519
405 struct MHD_Access_Handler *handlers; 520 /**
521 * Callback function for all requests.
522 */
523 MHD_AccessHandlerCallback default_handler;
406 524
407 struct MHD_Access_Handler default_handler; 525 /**
526 * Closure argument to default_handler.
527 */
528 void * default_handler_cls;
408 529
409 /** 530 /**
410 * Linked list of our current connections. 531 * Linked list of our current connections.
diff --git a/src/daemon/memorypool.c b/src/daemon/memorypool.c
index 6310d7d7..1bb12bae 100644
--- a/src/daemon/memorypool.c
+++ b/src/daemon/memorypool.c
@@ -188,4 +188,33 @@ MHD_pool_reallocate (struct MemoryPool *pool,
188 return NULL; 188 return NULL;
189} 189}
190 190
191/**
192 * Clear all entries from the memory pool except
193 * for "keep" of the given "size".
194 *
195 * @param keep pointer to the entry to keep (maybe NULL)
196 * @param size how many bytes need to be kept at this address
197 * @return addr new address of "keep" (if it had to change)
198 */
199void *MHD_pool_reset(struct MemoryPool * pool,
200 void * keep,
201 unsigned int size)
202{
203 if (keep != NULL)
204 {
205 if (keep != pool->memory)
206 {
207 memmove(pool->memory,
208 keep,
209 size);
210 keep = pool->memory;
211 }
212 pool->pos = size;
213 }
214 pool->end = pool->size;
215 return keep;
216}
217
218
219
191/* end of memorypool.c */ 220/* end of memorypool.c */
diff --git a/src/daemon/memorypool.h b/src/daemon/memorypool.h
index 7f53cba5..1d8ffb32 100644
--- a/src/daemon/memorypool.h
+++ b/src/daemon/memorypool.h
@@ -81,4 +81,16 @@ void *MHD_pool_reallocate (struct MemoryPool *pool,
81 void *old, 81 void *old,
82 unsigned int old_size, unsigned int new_size); 82 unsigned int old_size, unsigned int new_size);
83 83
84/**
85 * Clear all entries from the memory pool except
86 * for "keep" of the given "size".
87 *
88 * @param keep pointer to the entry to keep (maybe NULL)
89 * @param size how many bytes need to be kept at this address
90 * @return addr new address of "keep" (if it had to change)
91 */
92void *MHD_pool_reset(struct MemoryPool * pool,
93 void * keep,
94 unsigned int size);
95
84#endif 96#endif
diff --git a/src/daemon/minimal_example.c b/src/daemon/minimal_example.c
index 62ee5ae5..badff7a2 100644
--- a/src/daemon/minimal_example.c
+++ b/src/daemon/minimal_example.c
@@ -41,14 +41,22 @@ ahc_echo (void *cls,
41 const char *url, 41 const char *url,
42 const char *method, 42 const char *method,
43 const char *upload_data, 43 const char *upload_data,
44 const char *version, unsigned int *upload_data_size, void **unused) 44 const char *version, unsigned int *upload_data_size, void **ptr)
45{ 45{
46 static int aptr;
46 const char *me = cls; 47 const char *me = cls;
47 struct MHD_Response *response; 48 struct MHD_Response *response;
48 int ret; 49 int ret;
49 50
50 if (0 != strcmp (method, "GET")) 51 if (0 != strcmp (method, "GET"))
51 return MHD_NO; /* unexpected method */ 52 return MHD_NO; /* unexpected method */
53 if (&aptr != *ptr)
54 {
55 /* do never respond on first call */
56 *ptr = &aptr;
57 return MHD_YES;
58 }
59 *ptr = NULL; /* reset when done */
52 response = MHD_create_response_from_data (strlen (me), 60 response = MHD_create_response_from_data (strlen (me),
53 (void *) me, MHD_NO, MHD_NO); 61 (void *) me, MHD_NO, MHD_NO);
54 ret = MHD_queue_response (connection, MHD_HTTP_OK, response); 62 ret = MHD_queue_response (connection, MHD_HTTP_OK, response);
diff --git a/src/include/microhttpd.h b/src/include/microhttpd.h
index 680e6d23..2197d9d9 100644
--- a/src/include/microhttpd.h
+++ b/src/include/microhttpd.h
@@ -84,7 +84,7 @@ extern "C"
84/** 84/**
85 * Current version of the library. 85 * Current version of the library.
86 */ 86 */
87#define MHD_VERSION 0x00000100 87#define MHD_VERSION 0x00000200
88 88
89/** 89/**
90 * MHD-internal return codes. 90 * MHD-internal return codes.
@@ -373,6 +373,11 @@ enum MHD_ValueKind
373 */ 373 */
374 MHD_GET_ARGUMENT_KIND = 8, 374 MHD_GET_ARGUMENT_KIND = 8,
375 375
376 /**
377 * HTTP footer (only for http 1.1 chunked encodings).
378 */
379 MHD_FOOTER_KIND = 16,
380
376}; 381};
377 382
378/** 383/**
@@ -544,9 +549,15 @@ typedef int
544 * libmicrohttpd guarantees that "pos" will be 549 * libmicrohttpd guarantees that "pos" will be
545 * the sum of all non-negative return values 550 * the sum of all non-negative return values
546 * obtained from the content reader so far. 551 * obtained from the content reader so far.
547 * @return -1 on error (libmicrohttpd will no longer 552 * @return -1 for the end of transmission (or on error);
548 * try to read content and instead close the connection 553 * if a content transfer size was pre-set and the callback
549 * with the client). 554 * has provided fewer than that amount of data,
555 * MHD will close the connection with the client;
556 * if no content size was specified and this is an
557 * http 1.1 connection using chunked encoding, MHD will
558 * interpret "-1" as the normal end of the transfer
559 * (possibly allowing the client to perform additional
560 * requests using the same TCP connection).
550 */ 561 */
551typedef int 562typedef int
552 (*MHD_ContentReaderCallback) (void *cls, size_t pos, char *buf, int max); 563 (*MHD_ContentReaderCallback) (void *cls, size_t pos, char *buf, int max);
@@ -596,7 +607,7 @@ typedef int
596 * in which case connections from any IP will be 607 * in which case connections from any IP will be
597 * accepted 608 * accepted
598 * @param apc_cls extra argument to apc 609 * @param apc_cls extra argument to apc
599 * @param dh default handler for all URIs 610 * @param dh handler called for all requests (repeatedly)
600 * @param dh_cls extra argument to dh 611 * @param dh_cls extra argument to dh
601 * @param ... list of options (type-value pairs, 612 * @param ... list of options (type-value pairs,
602 * terminated with MHD_OPTION_END). 613 * terminated with MHD_OPTION_END).
@@ -655,32 +666,6 @@ int MHD_get_timeout (struct MHD_Daemon *daemon, unsigned long long *timeout);
655 */ 666 */
656int MHD_run (struct MHD_Daemon *daemon); 667int MHD_run (struct MHD_Daemon *daemon);
657 668
658
659/**
660 * Register an access handler for all URIs beginning with uri_prefix.
661 *
662 * @param uri_prefix
663 * @return MRI_NO if a handler for this exact prefix
664 * already exists
665 */
666int
667MHD_register_handler (struct MHD_Daemon *daemon,
668 const char *uri_prefix,
669 MHD_AccessHandlerCallback dh, void *dh_cls);
670
671/**
672 * Unregister an access handler for the URIs beginning with
673 * uri_prefix.
674 *
675 * @param uri_prefix
676 * @return MHD_NO if a handler for this exact prefix
677 * is not known for this daemon
678 */
679int
680MHD_unregister_handler (struct MHD_Daemon *daemon,
681 const char *uri_prefix,
682 MHD_AccessHandlerCallback dh, void *dh_cls);
683
684/** 669/**
685 * Get all of the headers from the request. 670 * Get all of the headers from the request.
686 * 671 *