aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2007-12-20 04:23:00 +0000
committerChristian Grothoff <christian@grothoff.org>2007-12-20 04:23:00 +0000
commitc490e64780fd1c45592f5528bf755956f0f2eddb (patch)
treeaa34ac04246134cb8e32a2d81573c73079c0d764
parente787fde83a61e3f9290c589139b657c7c414201c (diff)
downloadlibmicrohttpd-c490e64780fd1c45592f5528bf755956f0f2eddb.tar.gz
libmicrohttpd-c490e64780fd1c45592f5528bf755956f0f2eddb.zip
new MHD with support for chunked encoding
-rw-r--r--ChangeLog9
-rw-r--r--README11
-rw-r--r--configure.ac4
-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
17 files changed, 1515 insertions, 941 deletions
diff --git a/ChangeLog b/ChangeLog
index e784f5b5..14bc69e6 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,12 @@
1Wed Dec 19 21:12:04 MST 2007
2 Implemented chunked (HTTP 1.1) downloads (including
3 sending of HTTP footers). Also allowed queuing of
4 a response early to suppress the otherwise automatic
5 "100 CONTINUE" response. Removed the mostly useless
6 "(un)register handler" methods from the API. Changed
7 the internal implementation to use a finite state
8 machine (cleaner code, slightly less memory consumption). - CG
9
1Sun Dec 16 03:24:13 MST 2007 10Sun Dec 16 03:24:13 MST 2007
2 Implemented handling of chunked (HTTP 1.1) uploads. 11 Implemented handling of chunked (HTTP 1.1) uploads.
3 Note that the upload callback must be able to 12 Note that the upload callback must be able to
diff --git a/README b/README
index 4fd9edbe..cf941c2e 100644
--- a/README
+++ b/README
@@ -24,7 +24,7 @@ reporting (and use MHD_USE_DEBUG). Error reporting is not enabled by
24default to reduce the size of the library (error messages take 24default to reduce the size of the library (error messages take
25space!). If you are concerned about space, you should set "CFLAGS" to 25space!). If you are concerned about space, you should set "CFLAGS" to
26"-Os --fomit-frame-pointer" to have gcc generate tight code. The 26"-Os --fomit-frame-pointer" to have gcc generate tight code. The
27resulting binary should be less than 25k (on x86). 27resulting binary should be about 25k (on x86).
28 28
29 29
30Portability 30Portability
@@ -50,11 +50,6 @@ indicates that a testcase should be written before implementing the
50feature. 50feature.
51 51
52 52
53For http/1.1-compliance:
54========================
55connection.c:
56- support sending of chunked responses (#1302, TEST, ARCH)
57
58For POST: 53For POST:
59========= 54=========
60- add support to decode multipart/form-data with 55- add support to decode multipart/form-data with
@@ -71,6 +66,10 @@ Missing Testcases:
71- add testcases for http/1.1 pipelining (need 66- add testcases for http/1.1 pipelining (need
72 to figure out how to ensure curl pipelines) 67 to figure out how to ensure curl pipelines)
73- add testcases for resource limit enforcement 68- add testcases for resource limit enforcement
69- add testcases for client queuing early response,
70 suppressing 100 CONTINUE
71- extend testcase for chunked encoding to validate
72 handling of footers
74 73
75Documentation: 74Documentation:
76============== 75==============
diff --git a/configure.ac b/configure.ac
index adc1e3ca..09860619 100644
--- a/configure.ac
+++ b/configure.ac
@@ -21,8 +21,8 @@
21# 21#
22# 22#
23AC_PREREQ(2.57) 23AC_PREREQ(2.57)
24AC_INIT([libmicrohttpd], [0.1.2],[libmicrohttpd@gnunet.org]) 24AC_INIT([libmicrohttpd], [0.2.0],[libmicrohttpd@gnunet.org])
25AM_INIT_AUTOMAKE([libmicrohttpd], [0.1.2]) 25AM_INIT_AUTOMAKE([libmicrohttpd], [0.2.0])
26AM_CONFIG_HEADER([config.h]) 26AM_CONFIG_HEADER([config.h])
27 27
28AH_TOP([#define _GNU_SOURCE 1]) 28AH_TOP([#define _GNU_SOURCE 1])
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 *