diff options
Diffstat (limited to 'src/daemon/connection.c')
-rw-r--r-- | src/daemon/connection.c | 1845 |
1 files changed, 1155 insertions, 690 deletions
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 | |||
149 | MHD_queue_response (struct MHD_Connection *connection, | 159 | MHD_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 | */ |
175 | static int | 200 | static int |
176 | MHD_need_100_continue (struct MHD_Connection *connection) | 201 | need_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 | */ |
218 | static int | 244 | static int |
219 | ready_response (struct MHD_Connection *connection) | 245 | try_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 | */ | ||
288 | static int | ||
289 | try_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 | */ |
271 | int | 365 | static void |
272 | MHD_connection_get_fdset (struct MHD_Connection *connection, | 366 | add_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 | */ | ||
415 | static void | ||
416 | get_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 | */ | ||
442 | static int | ||
443 | try_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 | */ | ||
467 | static int | ||
468 | build_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 | */ |
340 | static void | 556 | static void |
341 | MHD_excessive_data_handler (struct MHD_Connection *connection, | 557 | excessive_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 | */ | ||
593 | static void | ||
594 | do_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 | */ | ||
608 | int | ||
609 | MHD_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 | */ |
368 | static char * | 742 | static char * |
369 | MHD_get_next_header_line (struct MHD_Connection *connection) | 743 | get_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 | */ |
420 | static int | 794 | static int |
421 | MHD_connection_add_header (struct MHD_Connection *connection, | 795 | connection_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 | */ |
484 | static int | 858 | static int |
485 | MHD_parse_cookie_header (struct MHD_Connection *connection) | 859 | parse_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 | */ | ||
603 | static void | ||
604 | MHD_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; | ||
768 | DIE: | ||
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 | */ | ||
780 | static struct MHD_Access_Handler * | ||
781 | MHD_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 | */ |
800 | void | 969 | static void |
801 | MHD_call_connection_handler (struct MHD_Connection *connection) | 970 | call_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 | */ |
983 | int | 1133 | static int |
984 | MHD_connection_handle_read (struct MHD_Connection *connection) | 1134 | do_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 | */ |
1080 | static void | 1170 | static void |
1081 | MHD_add_extra_headers (struct MHD_Connection *connection) | 1171 | process_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 | */ | ||
1106 | static void | 1210 | static void |
1107 | get_date_string (char *date, unsigned int max) | 1211 | process_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 | */ |
1134 | static int | 1260 | static void |
1135 | MHD_build_header_response (struct MHD_Connection *connection) | 1261 | parse_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 | */ | ||
1340 | int | ||
1341 | MHD_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 | */ | ||
1397 | static int | ||
1398 | do_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 | */ | ||
1434 | static int | ||
1435 | check_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 | */ |
1200 | int | 1461 | int |
1201 | MHD_connection_handle_write (struct MHD_Connection *connection) | 1462 | MHD_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 | */ | ||
1606 | int | ||
1607 | MHD_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 */ |