00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00028 #include "internal.h"
00029 #include <limits.h>
00030 #include "connection.h"
00031 #include "memorypool.h"
00032 #include "response.h"
00033 #include "reason_phrase.h"
00034
00035 #if HAVE_NETINET_TCP_H
00036
00037 #include <netinet/tcp.h>
00038 #endif
00039
00040
00044 #define HTTP_100_CONTINUE "HTTP/1.1 100 Continue\r\n\r\n"
00045
00053 #if HAVE_MESSAGES
00054 #define REQUEST_TOO_BIG "<html><head><title>Request too big</title></head><body>Your HTTP header was too big for the memory constraints of this webserver.</body></html>"
00055 #else
00056 #define REQUEST_TOO_BIG ""
00057 #endif
00058
00066 #if HAVE_MESSAGES
00067 #define REQUEST_LACKS_HOST "<html><head><title>"Host:" header required</title></head><body>In HTTP 1.1, requests must include a "Host:" header, and your HTTP 1.1 request lacked such a header.</body></html>"
00068 #else
00069 #define REQUEST_LACKS_HOST ""
00070 #endif
00071
00079 #if HAVE_MESSAGES
00080 #define REQUEST_MALFORMED "<html><head><title>Request malformed</title></head><body>Your HTTP request was syntactically incorrect.</body></html>"
00081 #else
00082 #define REQUEST_MALFORMED ""
00083 #endif
00084
00091 #if HAVE_MESSAGES
00092 #define INTERNAL_ERROR "<html><head><title>Internal server error</title></head><body>Some programmer needs to study the manual more carefully.</body></html>"
00093 #else
00094 #define INTERNAL_ERROR ""
00095 #endif
00096
00101 #define DEBUG_CLOSE MHD_NO
00102
00106 #define DEBUG_SEND_DATA MHD_NO
00107
00108
00120 int
00121 MHD_get_connection_values (struct MHD_Connection *connection,
00122 enum MHD_ValueKind kind,
00123 MHD_KeyValueIterator iterator, void *iterator_cls)
00124 {
00125 int ret;
00126 struct MHD_HTTP_Header *pos;
00127
00128 if (NULL == connection)
00129 return -1;
00130 ret = 0;
00131 for (pos = connection->headers_received; NULL != pos; pos = pos->next)
00132 if (0 != (pos->kind & kind))
00133 {
00134 ret++;
00135 if ((NULL != iterator) &&
00136 (MHD_YES != iterator (iterator_cls,
00137 kind, pos->header, pos->value)))
00138 return ret;
00139 }
00140 return ret;
00141 }
00142
00143
00169 int
00170 MHD_set_connection_value (struct MHD_Connection *connection,
00171 enum MHD_ValueKind kind,
00172 const char *key, const char *value)
00173 {
00174 struct MHD_HTTP_Header *pos;
00175
00176 pos = MHD_pool_allocate (connection->pool,
00177 sizeof (struct MHD_HTTP_Header), MHD_YES);
00178 if (NULL == pos)
00179 return MHD_NO;
00180 pos->header = (char *) key;
00181 pos->value = (char *) value;
00182 pos->kind = kind;
00183 pos->next = NULL;
00184
00185 if (NULL == connection->headers_received_tail)
00186 {
00187 connection->headers_received = pos;
00188 connection->headers_received_tail = pos;
00189 }
00190 else
00191 {
00192 connection->headers_received_tail->next = pos;
00193 connection->headers_received_tail = pos;
00194 }
00195 return MHD_YES;
00196 }
00197
00198
00209 const char *
00210 MHD_lookup_connection_value (struct MHD_Connection *connection,
00211 enum MHD_ValueKind kind, const char *key)
00212 {
00213 struct MHD_HTTP_Header *pos;
00214
00215 if (NULL == connection)
00216 return NULL;
00217 for (pos = connection->headers_received; NULL != pos; pos = pos->next)
00218 if ((0 != (pos->kind & kind)) &&
00219 ( (key == pos->header) ||
00220 ( (NULL != pos->header) &&
00221 (NULL != key) &&
00222 (0 == strcasecmp (key, pos->header))) ))
00223 return pos->value;
00224 return NULL;
00225 }
00226
00227
00235 static int
00236 need_100_continue (struct MHD_Connection *connection)
00237 {
00238 const char *expect;
00239
00240 return ( (NULL == connection->response) &&
00241 (NULL != connection->version) &&
00242 (0 == strcasecmp (connection->version,
00243 MHD_HTTP_VERSION_1_1)) &&
00244 (NULL != (expect = MHD_lookup_connection_value (connection,
00245 MHD_HEADER_KIND,
00246 MHD_HTTP_HEADER_EXPECT))) &&
00247 (0 == strcasecmp (expect, "100-continue")) &&
00248 (connection->continue_message_write_offset <
00249 strlen (HTTP_100_CONTINUE)) );
00250 }
00251
00252
00260 void
00261 MHD_connection_close (struct MHD_Connection *connection,
00262 enum MHD_RequestTerminationCode termination_code)
00263 {
00264 struct MHD_Daemon *daemon;
00265
00266 daemon = connection->daemon;
00267 if (0 == (connection->daemon->options & MHD_USE_EPOLL_TURBO))
00268 SHUTDOWN (connection->socket_fd,
00269 (MHD_YES == connection->read_closed) ? SHUT_WR : SHUT_RDWR);
00270 connection->state = MHD_CONNECTION_CLOSED;
00271 connection->event_loop_info = MHD_EVENT_LOOP_INFO_CLEANUP;
00272 if ( (NULL != daemon->notify_completed) &&
00273 (MHD_YES == connection->client_aware) )
00274 daemon->notify_completed (daemon->notify_completed_cls,
00275 connection,
00276 &connection->client_context,
00277 termination_code);
00278 connection->client_aware = MHD_NO;
00279 }
00280
00281
00289 static void
00290 connection_close_error (struct MHD_Connection *connection,
00291 const char *emsg)
00292 {
00293 #if HAVE_MESSAGES
00294 if (NULL != emsg)
00295 MHD_DLOG (connection->daemon, emsg);
00296 #endif
00297 MHD_connection_close (connection, MHD_REQUEST_TERMINATED_WITH_ERROR);
00298 }
00299
00300
00305 #if HAVE_MESSAGES
00306 #define CONNECTION_CLOSE_ERROR(c, emsg) connection_close_error (c, emsg)
00307 #else
00308 #define CONNECTION_CLOSE_ERROR(c, emsg) connection_close_error (c, NULL)
00309 #endif
00310
00311
00324 static int
00325 try_ready_normal_body (struct MHD_Connection *connection)
00326 {
00327 ssize_t ret;
00328 struct MHD_Response *response;
00329
00330 response = connection->response;
00331 if (NULL == response->crc)
00332 return MHD_YES;
00333 if (0 == response->total_size)
00334 return MHD_YES;
00335 if ( (response->data_start <=
00336 connection->response_write_position) &&
00337 (response->data_size + response->data_start >
00338 connection->response_write_position) )
00339 return MHD_YES;
00340 #if LINUX
00341 if ( (-1 != response->fd) &&
00342 (0 == (connection->daemon->options & MHD_USE_SSL)) )
00343 {
00344
00345 return MHD_YES;
00346 }
00347 #endif
00348
00349 ret = response->crc (response->crc_cls,
00350 connection->response_write_position,
00351 response->data,
00352 MHD_MIN (response->data_buffer_size,
00353 response->total_size -
00354 connection->response_write_position));
00355 if ( (((ssize_t) MHD_CONTENT_READER_END_OF_STREAM) == ret) ||
00356 (((ssize_t) MHD_CONTENT_READER_END_WITH_ERROR) == ret) )
00357 {
00358
00359 response->total_size = connection->response_write_position;
00360 if (NULL != response->crc)
00361 pthread_mutex_unlock (&response->mutex);
00362 if ( ((ssize_t)MHD_CONTENT_READER_END_OF_STREAM) == ret)
00363 MHD_connection_close (connection, MHD_REQUEST_TERMINATED_COMPLETED_OK);
00364 else
00365 CONNECTION_CLOSE_ERROR (connection,
00366 "Closing connection (stream error)\n");
00367 return MHD_NO;
00368 }
00369 response->data_start = connection->response_write_position;
00370 response->data_size = ret;
00371 if (0 == ret)
00372 {
00373 connection->state = MHD_CONNECTION_NORMAL_BODY_UNREADY;
00374 if (NULL != response->crc)
00375 pthread_mutex_unlock (&response->mutex);
00376 return MHD_NO;
00377 }
00378 return MHD_YES;
00379 }
00380
00381
00391 static int
00392 try_ready_chunked_body (struct MHD_Connection *connection)
00393 {
00394 ssize_t ret;
00395 char *buf;
00396 struct MHD_Response *response;
00397 size_t size;
00398 char cbuf[10];
00399 int cblen;
00400
00401 response = connection->response;
00402 if (0 == connection->write_buffer_size)
00403 {
00404 size = connection->daemon->pool_size;
00405 do
00406 {
00407 size /= 2;
00408 if (size < 128)
00409 {
00410
00411 CONNECTION_CLOSE_ERROR (connection,
00412 "Closing connection (out of memory)\n");
00413 return MHD_NO;
00414 }
00415 buf = MHD_pool_allocate (connection->pool, size, MHD_NO);
00416 }
00417 while (NULL == buf);
00418 connection->write_buffer_size = size;
00419 connection->write_buffer = buf;
00420 }
00421
00422 if ( (response->data_start <=
00423 connection->response_write_position) &&
00424 (response->data_size + response->data_start >
00425 connection->response_write_position) )
00426 {
00427
00428 ret = response->data_size + response->data_start - connection->response_write_position;
00429 if ( (ret > 0) &&
00430 (((size_t) ret) > connection->write_buffer_size - sizeof (cbuf) - 2) )
00431 ret = connection->write_buffer_size - sizeof (cbuf) - 2;
00432 memcpy (&connection->write_buffer[sizeof (cbuf)],
00433 &response->data[connection->response_write_position - response->data_start],
00434 ret);
00435 }
00436 else
00437 {
00438
00439 if (0 == response->total_size)
00440 ret = 0;
00441 else
00442 ret = response->crc (response->crc_cls,
00443 connection->response_write_position,
00444 &connection->write_buffer[sizeof (cbuf)],
00445 connection->write_buffer_size - sizeof (cbuf) - 2);
00446 }
00447 if ( ((ssize_t) MHD_CONTENT_READER_END_WITH_ERROR) == ret)
00448 {
00449
00450 response->total_size = connection->response_write_position;
00451 CONNECTION_CLOSE_ERROR (connection,
00452 "Closing connection (error generating response)\n");
00453 return MHD_NO;
00454 }
00455 if ( (((ssize_t) MHD_CONTENT_READER_END_OF_STREAM) == ret) ||
00456 (0 == response->total_size) )
00457 {
00458
00459 strcpy (connection->write_buffer, "0\r\n");
00460 connection->write_buffer_append_offset = 3;
00461 connection->write_buffer_send_offset = 0;
00462 response->total_size = connection->response_write_position;
00463 return MHD_YES;
00464 }
00465 if (0 == ret)
00466 {
00467 connection->state = MHD_CONNECTION_CHUNKED_BODY_UNREADY;
00468 return MHD_NO;
00469 }
00470 if (ret > 0xFFFFFF)
00471 ret = 0xFFFFFF;
00472 snprintf (cbuf,
00473 sizeof (cbuf),
00474 "%X\r\n", (unsigned int) ret);
00475 cblen = strlen (cbuf);
00476 EXTRA_CHECK (cblen <= sizeof (cbuf));
00477 memcpy (&connection->write_buffer[sizeof (cbuf) - cblen], cbuf, cblen);
00478 memcpy (&connection->write_buffer[sizeof (cbuf) + ret], "\r\n", 2);
00479 connection->response_write_position += ret;
00480 connection->write_buffer_send_offset = sizeof (cbuf) - cblen;
00481 connection->write_buffer_append_offset = sizeof (cbuf) + ret + 2;
00482 return MHD_YES;
00483 }
00484
00485
00492 static void
00493 add_extra_headers (struct MHD_Connection *connection)
00494 {
00495 const char *have_close;
00496 const char *client_close;
00497 const char *have_encoding;
00498 char buf[128];
00499 int add_close;
00500
00501 client_close = MHD_lookup_connection_value (connection,
00502 MHD_HEADER_KIND,
00503 MHD_HTTP_HEADER_CONNECTION);
00504
00505 if ( (NULL != client_close) && (0 != strcasecmp (client_close, "close")) )
00506 client_close = NULL;
00507 have_close = MHD_get_response_header (connection->response,
00508 MHD_HTTP_HEADER_CONNECTION);
00509 if ( (NULL != have_close) && (0 != strcasecmp (have_close, "close")) )
00510 have_close = NULL;
00511 connection->have_chunked_upload = MHD_NO;
00512 add_close = MHD_NO;
00513 if (MHD_SIZE_UNKNOWN == connection->response->total_size)
00514 {
00515
00516
00517 if (NULL == have_close)
00518 {
00519
00520
00521 if ((NULL == client_close) &&
00522 (NULL != connection->version) &&
00523 (0 == strcasecmp (connection->version, MHD_HTTP_VERSION_1_1)))
00524 {
00525 connection->have_chunked_upload = MHD_YES;
00526 have_encoding = MHD_get_response_header (connection->response,
00527 MHD_HTTP_HEADER_TRANSFER_ENCODING);
00528 if (NULL == have_encoding)
00529 MHD_add_response_header (connection->response,
00530 MHD_HTTP_HEADER_TRANSFER_ENCODING,
00531 "chunked");
00532 else if (0 != strcasecmp (have_encoding, "chunked"))
00533 add_close = MHD_YES;
00534 }
00535 else
00536 {
00537
00538 add_close = MHD_YES;
00539 }
00540 }
00541 }
00542 else
00543 {
00544
00545 if ( (NULL != client_close) &&
00546 (NULL == have_close) )
00547 add_close = MHD_YES;
00548
00549
00550 if ( (NULL == MHD_get_response_header (connection->response,
00551 MHD_HTTP_HEADER_CONTENT_LENGTH)) &&
00552 ( (NULL == connection->method) ||
00553 (0 != strcasecmp (connection->method,
00554 MHD_HTTP_METHOD_CONNECT)) ||
00555 (0 != connection->response->total_size) ) )
00556 {
00557
00558
00559
00560
00561
00562
00563
00564
00565
00566
00567
00568
00569
00570
00571
00572 SPRINTF (buf,
00573 MHD_UNSIGNED_LONG_LONG_PRINTF,
00574 (MHD_UNSIGNED_LONG_LONG) connection->response->total_size);
00575 MHD_add_response_header (connection->response,
00576 MHD_HTTP_HEADER_CONTENT_LENGTH, buf);
00577 }
00578 }
00579 if (MHD_YES == add_close)
00580 MHD_add_response_header (connection->response,
00581 MHD_HTTP_HEADER_CONNECTION, "close");
00582 }
00583
00584
00591 static void
00592 get_date_string (char *date)
00593 {
00594 static const char *const days[] =
00595 { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" };
00596 static const char *const mons[] =
00597 { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct",
00598 "Nov", "Dec"
00599 };
00600 struct tm now;
00601 time_t t;
00602
00603 time (&t);
00604 gmtime_r (&t, &now);
00605 SPRINTF (date,
00606 "Date: %3s, %02u %3s %04u %02u:%02u:%02u GMT\r\n",
00607 days[now.tm_wday % 7],
00608 (unsigned int) now.tm_mday,
00609 mons[now.tm_mon % 12],
00610 (unsigned int) (1900 + now.tm_year),
00611 (unsigned int) now.tm_hour,
00612 (unsigned int) now.tm_min,
00613 (unsigned int) now.tm_sec);
00614 }
00615
00616
00628 static int
00629 try_grow_read_buffer (struct MHD_Connection *connection)
00630 {
00631 void *buf;
00632 size_t new_size;
00633
00634 if (0 == connection->read_buffer_size)
00635 new_size = connection->daemon->pool_size / 2;
00636 else
00637 new_size = connection->read_buffer_size + MHD_BUF_INC_SIZE;
00638 buf = MHD_pool_reallocate (connection->pool,
00639 connection->read_buffer,
00640 connection->read_buffer_size,
00641 new_size);
00642 if (NULL == buf)
00643 return MHD_NO;
00644
00645 connection->read_buffer = buf;
00646 connection->read_buffer_size = new_size;
00647 return MHD_YES;
00648 }
00649
00650
00659 static int
00660 build_header_response (struct MHD_Connection *connection)
00661 {
00662 size_t size;
00663 size_t off;
00664 struct MHD_HTTP_Header *pos;
00665 char code[256];
00666 char date[128];
00667 char *data;
00668 enum MHD_ValueKind kind;
00669 const char *reason_phrase;
00670 uint32_t rc;
00671 int must_add_close;
00672
00673 EXTRA_CHECK (NULL != connection->version);
00674 if (0 == strlen (connection->version))
00675 {
00676 data = MHD_pool_allocate (connection->pool, 0, MHD_YES);
00677 connection->write_buffer = data;
00678 connection->write_buffer_append_offset = 0;
00679 connection->write_buffer_send_offset = 0;
00680 connection->write_buffer_size = 0;
00681 return MHD_YES;
00682 }
00683 if (MHD_CONNECTION_FOOTERS_RECEIVED == connection->state)
00684 {
00685 add_extra_headers (connection);
00686 rc = connection->responseCode & (~MHD_ICY_FLAG);
00687 reason_phrase = MHD_get_reason_phrase_for (rc);
00688 SPRINTF (code,
00689 "%s %u %s\r\n",
00690 (0 != (connection->responseCode & MHD_ICY_FLAG))
00691 ? "ICY"
00692 : ( (0 == strcasecmp (MHD_HTTP_VERSION_1_0,
00693 connection->version))
00694 ? MHD_HTTP_VERSION_1_0
00695 : MHD_HTTP_VERSION_1_1),
00696 rc,
00697 reason_phrase);
00698 off = strlen (code);
00699
00700 size = off + 2;
00701 kind = MHD_HEADER_KIND;
00702 if ( (0 == (connection->daemon->options & MHD_SUPPRESS_DATE_NO_CLOCK)) &&
00703 (NULL == MHD_get_response_header (connection->response,
00704 MHD_HTTP_HEADER_DATE)) )
00705 get_date_string (date);
00706 else
00707 date[0] = '\0';
00708 size += strlen (date);
00709 }
00710 else
00711 {
00712 size = 2;
00713 kind = MHD_FOOTER_KIND;
00714 off = 0;
00715 }
00716 must_add_close = ( (MHD_CONNECTION_FOOTERS_RECEIVED == connection->state) &&
00717 (MHD_YES == connection->read_closed) &&
00718 (0 == strcasecmp (connection->version,
00719 MHD_HTTP_VERSION_1_1)) &&
00720 (NULL == MHD_get_response_header (connection->response,
00721 MHD_HTTP_HEADER_CONNECTION)) );
00722 if (must_add_close)
00723 size += strlen ("Connection: close\r\n");
00724 for (pos = connection->response->first_header; NULL != pos; pos = pos->next)
00725 if (pos->kind == kind)
00726 size += strlen (pos->header) + strlen (pos->value) + 4;
00727
00728 data = MHD_pool_allocate (connection->pool, size + 1, MHD_NO);
00729 if (NULL == data)
00730 {
00731 #if HAVE_MESSAGES
00732 MHD_DLOG (connection->daemon, "Not enough memory for write!\n");
00733 #endif
00734 return MHD_NO;
00735 }
00736 if (MHD_CONNECTION_FOOTERS_RECEIVED == connection->state)
00737 {
00738 memcpy (data, code, off);
00739 }
00740 if (must_add_close)
00741 {
00742
00743
00744
00745
00746 memcpy (&data[off], "Connection: close\r\n",
00747 strlen ("Connection: close\r\n"));
00748 off += strlen ("Connection: close\r\n");
00749 }
00750 for (pos = connection->response->first_header; NULL != pos; pos = pos->next)
00751 if (pos->kind == kind)
00752 off += SPRINTF (&data[off],
00753 "%s: %s\r\n",
00754 pos->header,
00755 pos->value);
00756 if (connection->state == MHD_CONNECTION_FOOTERS_RECEIVED)
00757 {
00758 strcpy (&data[off], date);
00759 off += strlen (date);
00760 }
00761 memcpy (&data[off], "\r\n", 2);
00762 off += 2;
00763
00764 if (off != size)
00765 mhd_panic (mhd_panic_cls, __FILE__, __LINE__, NULL);
00766 connection->write_buffer = data;
00767 connection->write_buffer_append_offset = size;
00768 connection->write_buffer_send_offset = 0;
00769 connection->write_buffer_size = size + 1;
00770 return MHD_YES;
00771 }
00772
00773
00783 static void
00784 transmit_error_response (struct MHD_Connection *connection,
00785 unsigned int status_code,
00786 const char *message)
00787 {
00788 struct MHD_Response *response;
00789
00790 if (NULL == connection->version)
00791 {
00792
00793
00794 connection->version = MHD_HTTP_VERSION_1_0;
00795 }
00796 connection->state = MHD_CONNECTION_FOOTERS_RECEIVED;
00797 connection->read_closed = MHD_YES;
00798 #if HAVE_MESSAGES
00799 MHD_DLOG (connection->daemon,
00800 "Error %u (`%s') processing request, closing connection.\n",
00801 status_code, message);
00802 #endif
00803 EXTRA_CHECK (NULL == connection->response);
00804 response = MHD_create_response_from_buffer (strlen (message),
00805 (void *) message,
00806 MHD_RESPMEM_PERSISTENT);
00807 MHD_queue_response (connection, status_code, response);
00808 EXTRA_CHECK (NULL != connection->response);
00809 MHD_destroy_response (response);
00810 if (MHD_NO == build_header_response (connection))
00811 {
00812
00813 CONNECTION_CLOSE_ERROR (connection,
00814 "Closing connection (failed to create response header)\n");
00815 }
00816 else
00817 {
00818 connection->state = MHD_CONNECTION_HEADERS_SENDING;
00819 }
00820 }
00821
00822
00831 static void
00832 MHD_connection_update_event_loop_info (struct MHD_Connection *connection)
00833 {
00834 while (1)
00835 {
00836 #if DEBUG_STATES
00837 MHD_DLOG (connection->daemon, "%s: state: %s\n",
00838 __FUNCTION__, MHD_state_to_string (connection->state));
00839 #endif
00840 switch (connection->state)
00841 {
00842 #if HTTPS_SUPPORT
00843 case MHD_TLS_CONNECTION_INIT:
00844 if (0 == gnutls_record_get_direction (connection->tls_session))
00845 connection->event_loop_info = MHD_EVENT_LOOP_INFO_READ;
00846 else
00847 connection->event_loop_info = MHD_EVENT_LOOP_INFO_WRITE;
00848 break;
00849 #endif
00850 case MHD_CONNECTION_INIT:
00851 case MHD_CONNECTION_URL_RECEIVED:
00852 case MHD_CONNECTION_HEADER_PART_RECEIVED:
00853
00854
00855 if ( (connection->read_buffer_offset == connection->read_buffer_size) &&
00856 (MHD_NO == try_grow_read_buffer (connection)) )
00857 {
00858 transmit_error_response (connection,
00859 (connection->url != NULL)
00860 ? MHD_HTTP_REQUEST_ENTITY_TOO_LARGE
00861 : MHD_HTTP_REQUEST_URI_TOO_LONG,
00862 REQUEST_TOO_BIG);
00863 continue;
00864 }
00865 if (MHD_NO == connection->read_closed)
00866 connection->event_loop_info = MHD_EVENT_LOOP_INFO_READ;
00867 else
00868 connection->event_loop_info = MHD_EVENT_LOOP_INFO_BLOCK;
00869 break;
00870 case MHD_CONNECTION_HEADERS_RECEIVED:
00871 EXTRA_CHECK (0);
00872 break;
00873 case MHD_CONNECTION_HEADERS_PROCESSED:
00874 EXTRA_CHECK (0);
00875 break;
00876 case MHD_CONNECTION_CONTINUE_SENDING:
00877 connection->event_loop_info = MHD_EVENT_LOOP_INFO_WRITE;
00878 break;
00879 case MHD_CONNECTION_CONTINUE_SENT:
00880 if (connection->read_buffer_offset == connection->read_buffer_size)
00881 {
00882 if ((MHD_YES != try_grow_read_buffer (connection)) &&
00883 (0 != (connection->daemon->options &
00884 (MHD_USE_SELECT_INTERNALLY |
00885 MHD_USE_THREAD_PER_CONNECTION))))
00886 {
00887
00888
00889
00890
00891
00892
00893
00894
00895
00896
00897
00898 transmit_error_response (connection,
00899 MHD_HTTP_INTERNAL_SERVER_ERROR,
00900 INTERNAL_ERROR);
00901 continue;
00902 }
00903 }
00904 if ( (connection->read_buffer_offset < connection->read_buffer_size) &&
00905 (MHD_NO == connection->read_closed) )
00906 connection->event_loop_info = MHD_EVENT_LOOP_INFO_READ;
00907 else
00908 connection->event_loop_info = MHD_EVENT_LOOP_INFO_BLOCK;
00909 break;
00910 case MHD_CONNECTION_BODY_RECEIVED:
00911 case MHD_CONNECTION_FOOTER_PART_RECEIVED:
00912
00913
00914 if (MHD_YES == connection->read_closed)
00915 {
00916 CONNECTION_CLOSE_ERROR (connection,
00917 NULL);
00918 continue;
00919 }
00920 connection->event_loop_info = MHD_EVENT_LOOP_INFO_READ;
00921
00922
00923 break;
00924 case MHD_CONNECTION_FOOTERS_RECEIVED:
00925 connection->event_loop_info = MHD_EVENT_LOOP_INFO_BLOCK;
00926 break;
00927 case MHD_CONNECTION_HEADERS_SENDING:
00928
00929 connection->event_loop_info = MHD_EVENT_LOOP_INFO_WRITE;
00930 break;
00931 case MHD_CONNECTION_HEADERS_SENT:
00932 EXTRA_CHECK (0);
00933 break;
00934 case MHD_CONNECTION_NORMAL_BODY_READY:
00935 connection->event_loop_info = MHD_EVENT_LOOP_INFO_WRITE;
00936 break;
00937 case MHD_CONNECTION_NORMAL_BODY_UNREADY:
00938 connection->event_loop_info = MHD_EVENT_LOOP_INFO_BLOCK;
00939 break;
00940 case MHD_CONNECTION_CHUNKED_BODY_READY:
00941 connection->event_loop_info = MHD_EVENT_LOOP_INFO_WRITE;
00942 break;
00943 case MHD_CONNECTION_CHUNKED_BODY_UNREADY:
00944 connection->event_loop_info = MHD_EVENT_LOOP_INFO_BLOCK;
00945 break;
00946 case MHD_CONNECTION_BODY_SENT:
00947 EXTRA_CHECK (0);
00948 break;
00949 case MHD_CONNECTION_FOOTERS_SENDING:
00950 connection->event_loop_info = MHD_EVENT_LOOP_INFO_WRITE;
00951 break;
00952 case MHD_CONNECTION_FOOTERS_SENT:
00953 EXTRA_CHECK (0);
00954 break;
00955 case MHD_CONNECTION_CLOSED:
00956 connection->event_loop_info = MHD_EVENT_LOOP_INFO_CLEANUP;
00957 return;
00958 default:
00959 EXTRA_CHECK (0);
00960 }
00961 break;
00962 }
00963 }
00964
00965
00977 static char *
00978 get_next_header_line (struct MHD_Connection *connection)
00979 {
00980 char *rbuf;
00981 size_t pos;
00982
00983 if (0 == connection->read_buffer_offset)
00984 return NULL;
00985 pos = 0;
00986 rbuf = connection->read_buffer;
00987 while ((pos < connection->read_buffer_offset - 1) &&
00988 ('\r' != rbuf[pos]) && ('\n' != rbuf[pos]))
00989 pos++;
00990 if ( (pos == connection->read_buffer_offset - 1) &&
00991 ('\n' != rbuf[pos]) )
00992 {
00993
00994 if ( (connection->read_buffer_offset == connection->read_buffer_size) &&
00995 (MHD_NO ==
00996 try_grow_read_buffer (connection)) )
00997 {
00998 transmit_error_response (connection,
00999 (NULL != connection->url)
01000 ? MHD_HTTP_REQUEST_ENTITY_TOO_LARGE
01001 : MHD_HTTP_REQUEST_URI_TOO_LONG,
01002 REQUEST_TOO_BIG);
01003 }
01004 return NULL;
01005 }
01006
01007 if (('\r' == rbuf[pos]) && ('\n' == rbuf[pos + 1]))
01008 rbuf[pos++] = '\0';
01009 rbuf[pos++] = '\0';
01010 connection->read_buffer += pos;
01011 connection->read_buffer_size -= pos;
01012 connection->read_buffer_offset -= pos;
01013 return rbuf;
01014 }
01015
01016
01028 static int
01029 connection_add_header (struct MHD_Connection *connection,
01030 char *key, char *value, enum MHD_ValueKind kind)
01031 {
01032 if (MHD_NO == MHD_set_connection_value (connection,
01033 kind,
01034 key, value))
01035 {
01036 #if HAVE_MESSAGES
01037 MHD_DLOG (connection->daemon,
01038 "Not enough memory to allocate header record!\n");
01039 #endif
01040 transmit_error_response (connection, MHD_HTTP_REQUEST_ENTITY_TOO_LARGE,
01041 REQUEST_TOO_BIG);
01042 return MHD_NO;
01043 }
01044 return MHD_YES;
01045 }
01046
01047
01057 static int
01058 parse_arguments (enum MHD_ValueKind kind,
01059 struct MHD_Connection *connection,
01060 char *args)
01061 {
01062 char *equals;
01063 char *amper;
01064
01065 while (NULL != args)
01066 {
01067 equals = strchr (args, '=');
01068 amper = strchr (args, '&');
01069 if (NULL == amper)
01070 {
01071
01072 if (NULL == equals)
01073 {
01074
01075 connection->daemon->unescape_callback (connection->daemon->unescape_callback_cls,
01076 connection,
01077 args);
01078 return connection_add_header (connection,
01079 args,
01080 NULL,
01081 kind);
01082 }
01083
01084 equals[0] = '\0';
01085 equals++;
01086 connection->daemon->unescape_callback (connection->daemon->unescape_callback_cls,
01087 connection,
01088 args);
01089 connection->daemon->unescape_callback (connection->daemon->unescape_callback_cls,
01090 connection,
01091 equals);
01092 return connection_add_header (connection, args, equals, kind);
01093 }
01094
01095 amper[0] = '\0';
01096 amper++;
01097 if ( (NULL == equals) ||
01098 (equals >= amper) )
01099 {
01100
01101 connection->daemon->unescape_callback (connection->daemon->unescape_callback_cls,
01102 connection,
01103 args);
01104 if (MHD_NO ==
01105 connection_add_header (connection,
01106 args,
01107 NULL,
01108 kind))
01109 return MHD_NO;
01110
01111 args = amper;
01112 continue;
01113
01114 }
01115
01116
01117 equals[0] = '\0';
01118 equals++;
01119 connection->daemon->unescape_callback (connection->daemon->unescape_callback_cls,
01120 connection,
01121 args);
01122 connection->daemon->unescape_callback (connection->daemon->unescape_callback_cls,
01123 connection,
01124 equals);
01125 if (MHD_NO == connection_add_header (connection, args, equals, kind))
01126 return MHD_NO;
01127 args = amper;
01128 }
01129 return MHD_YES;
01130 }
01131
01132
01138 static int
01139 parse_cookie_header (struct MHD_Connection *connection)
01140 {
01141 const char *hdr;
01142 char *cpy;
01143 char *pos;
01144 char *sce;
01145 char *semicolon;
01146 char *equals;
01147 char *ekill;
01148 char old;
01149 int quotes;
01150
01151 hdr = MHD_lookup_connection_value (connection,
01152 MHD_HEADER_KIND,
01153 MHD_HTTP_HEADER_COOKIE);
01154 if (NULL == hdr)
01155 return MHD_YES;
01156 cpy = MHD_pool_allocate (connection->pool, strlen (hdr) + 1, MHD_YES);
01157 if (NULL == cpy)
01158 {
01159 #if HAVE_MESSAGES
01160 MHD_DLOG (connection->daemon, "Not enough memory to parse cookies!\n");
01161 #endif
01162 transmit_error_response (connection, MHD_HTTP_REQUEST_ENTITY_TOO_LARGE,
01163 REQUEST_TOO_BIG);
01164 return MHD_NO;
01165 }
01166 memcpy (cpy, hdr, strlen (hdr) + 1);
01167 pos = cpy;
01168 while (NULL != pos)
01169 {
01170 while (' ' == *pos)
01171 pos++;
01172
01173 sce = pos;
01174 while (((*sce) != '\0') &&
01175 ((*sce) != ',') && ((*sce) != ';') && ((*sce) != '='))
01176 sce++;
01177
01178 ekill = sce - 1;
01179 while ((*ekill == ' ') && (ekill >= pos))
01180 *(ekill--) = '\0';
01181 old = *sce;
01182 *sce = '\0';
01183 if (old != '=')
01184 {
01185
01186 if (MHD_NO ==
01187 connection_add_header (connection, pos, "", MHD_COOKIE_KIND))
01188 return MHD_NO;
01189 if (old == '\0')
01190 break;
01191 pos = sce + 1;
01192 continue;
01193 }
01194 equals = sce + 1;
01195 quotes = 0;
01196 semicolon = equals;
01197 while ((semicolon[0] != '\0') &&
01198 ((quotes != 0) ||
01199 ((semicolon[0] != ';') && (semicolon[0] != ','))))
01200 {
01201 if (semicolon[0] == '"')
01202 quotes = (quotes + 1) & 1;
01203 semicolon++;
01204 }
01205 if (semicolon[0] == '\0')
01206 semicolon = NULL;
01207 if (NULL != semicolon)
01208 {
01209 semicolon[0] = '\0';
01210 semicolon++;
01211 }
01212
01213 if ((equals[0] == '"') && (equals[strlen (equals) - 1] == '"'))
01214 {
01215 equals[strlen (equals) - 1] = '\0';
01216 equals++;
01217 }
01218 if (MHD_NO == connection_add_header (connection,
01219 pos, equals, MHD_COOKIE_KIND))
01220 return MHD_NO;
01221 pos = semicolon;
01222 }
01223 return MHD_YES;
01224 }
01225
01226
01234 static int
01235 parse_initial_message_line (struct MHD_Connection *connection, char *line)
01236 {
01237 char *uri;
01238 char *http_version;
01239 char *args;
01240
01241 if (NULL == (uri = strchr (line, ' ')))
01242 return MHD_NO;
01243 uri[0] = '\0';
01244 connection->method = line;
01245 uri++;
01246 while (uri[0] == ' ')
01247 uri++;
01248 http_version = strchr (uri, ' ');
01249 if (NULL != http_version)
01250 {
01251 http_version[0] = '\0';
01252 http_version++;
01253 }
01254 if (NULL != connection->daemon->uri_log_callback)
01255 connection->client_context
01256 = connection->daemon->uri_log_callback (connection->daemon->uri_log_callback_cls,
01257 uri,
01258 connection);
01259 args = strchr (uri, '?');
01260 if (NULL != args)
01261 {
01262 args[0] = '\0';
01263 args++;
01264 parse_arguments (MHD_GET_ARGUMENT_KIND, connection, args);
01265 }
01266 connection->daemon->unescape_callback (connection->daemon->unescape_callback_cls,
01267 connection,
01268 uri);
01269 connection->url = uri;
01270 if (NULL == http_version)
01271 connection->version = "";
01272 else
01273 connection->version = http_version;
01274 return MHD_YES;
01275 }
01276
01277
01285 static void
01286 call_connection_handler (struct MHD_Connection *connection)
01287 {
01288 size_t processed;
01289
01290 if (NULL != connection->response)
01291 return;
01292 processed = 0;
01293 connection->client_aware = MHD_YES;
01294 if (MHD_NO ==
01295 connection->daemon->default_handler (connection->daemon->
01296 default_handler_cls,
01297 connection, connection->url,
01298 connection->method,
01299 connection->version,
01300 NULL, &processed,
01301 &connection->client_context))
01302 {
01303
01304 CONNECTION_CLOSE_ERROR (connection,
01305 "Internal application error, closing connection.\n");
01306 return;
01307 }
01308 }
01309
01310
01311
01319 static void
01320 process_request_body (struct MHD_Connection *connection)
01321 {
01322 size_t processed;
01323 size_t available;
01324 size_t used;
01325 size_t i;
01326 int instant_retry;
01327 int malformed;
01328 char *buffer_head;
01329 char *end;
01330
01331 if (NULL != connection->response)
01332 return;
01333
01334 buffer_head = connection->read_buffer;
01335 available = connection->read_buffer_offset;
01336 do
01337 {
01338 instant_retry = MHD_NO;
01339 if ((connection->have_chunked_upload == MHD_YES) &&
01340 (connection->remaining_upload_size == MHD_SIZE_UNKNOWN))
01341 {
01342 if ((connection->current_chunk_offset ==
01343 connection->current_chunk_size)
01344 && (connection->current_chunk_offset != 0) && (available >= 2))
01345 {
01346
01347 i = 0;
01348 if ((buffer_head[i] == '\r') || (buffer_head[i] == '\n'))
01349 i++;
01350 if ((buffer_head[i] == '\r') || (buffer_head[i] == '\n'))
01351 i++;
01352 if (i == 0)
01353 {
01354
01355 CONNECTION_CLOSE_ERROR (connection,
01356 "Received malformed HTTP request (bad chunked encoding), closing connection.\n");
01357 return;
01358 }
01359 available -= i;
01360 buffer_head += i;
01361 connection->current_chunk_offset = 0;
01362 connection->current_chunk_size = 0;
01363 }
01364 if (connection->current_chunk_offset <
01365 connection->current_chunk_size)
01366 {
01367
01368
01369
01370 processed =
01371 connection->current_chunk_size -
01372 connection->current_chunk_offset;
01373 if (processed > available)
01374 processed = available;
01375 if (available > processed)
01376 instant_retry = MHD_YES;
01377 }
01378 else
01379 {
01380
01381 i = 0;
01382 while (i < available)
01383 {
01384 if ((buffer_head[i] == '\r') || (buffer_head[i] == '\n'))
01385 break;
01386 i++;
01387 if (i >= 6)
01388 break;
01389 }
01390
01391
01392
01393
01394 if ((i + 1 >= available) &&
01395 !((i == 1) && (available == 2) && (buffer_head[0] == '0')))
01396 break;
01397 malformed = (i >= 6);
01398 if (!malformed)
01399 {
01400 buffer_head[i] = '\0';
01401 connection->current_chunk_size = strtoul (buffer_head, &end, 16);
01402 malformed = ('\0' != *end);
01403 }
01404 if (malformed)
01405 {
01406
01407 CONNECTION_CLOSE_ERROR (connection,
01408 "Received malformed HTTP request (bad chunked encoding), closing connection.\n");
01409 return;
01410 }
01411 i++;
01412 if ((i < available) &&
01413 ((buffer_head[i] == '\r') || (buffer_head[i] == '\n')))
01414 i++;
01415
01416 buffer_head += i;
01417 available -= i;
01418 connection->current_chunk_offset = 0;
01419
01420 if (available > 0)
01421 instant_retry = MHD_YES;
01422 if (connection->current_chunk_size == 0)
01423 {
01424 connection->remaining_upload_size = 0;
01425 break;
01426 }
01427 continue;
01428 }
01429 }
01430 else
01431 {
01432
01433 if ( (0 != connection->remaining_upload_size) &&
01434 (MHD_SIZE_UNKNOWN != connection->remaining_upload_size) &&
01435 (connection->remaining_upload_size < available) )
01436 {
01437 processed = connection->remaining_upload_size;
01438 }
01439 else
01440 {
01445 processed = available;
01446 }
01447 }
01448 used = processed;
01449 connection->client_aware = MHD_YES;
01450 if (MHD_NO ==
01451 connection->daemon->default_handler (connection->daemon->
01452 default_handler_cls,
01453 connection, connection->url,
01454 connection->method,
01455 connection->version,
01456 buffer_head, &processed,
01457 &connection->client_context))
01458 {
01459
01460 CONNECTION_CLOSE_ERROR (connection,
01461 "Internal application error, closing connection.\n");
01462 return;
01463 }
01464 if (processed > used)
01465 mhd_panic (mhd_panic_cls, __FILE__, __LINE__
01466 #if HAVE_MESSAGES
01467 , "API violation"
01468 #else
01469 , NULL
01470 #endif
01471 );
01472 if (0 != processed)
01473 instant_retry = MHD_NO;
01474 used -= processed;
01475 if (connection->have_chunked_upload == MHD_YES)
01476 connection->current_chunk_offset += used;
01477
01478 buffer_head += used;
01479 available -= used;
01480 if (connection->remaining_upload_size != MHD_SIZE_UNKNOWN)
01481 connection->remaining_upload_size -= used;
01482 }
01483 while (MHD_YES == instant_retry);
01484 if (available > 0)
01485 memmove (connection->read_buffer, buffer_head, available);
01486 connection->read_buffer_offset = available;
01487 }
01488
01489
01499 static int
01500 do_read (struct MHD_Connection *connection)
01501 {
01502 int bytes_read;
01503
01504 if (connection->read_buffer_size == connection->read_buffer_offset)
01505 return MHD_NO;
01506 bytes_read = connection->recv_cls (connection,
01507 &connection->read_buffer
01508 [connection->read_buffer_offset],
01509 connection->read_buffer_size -
01510 connection->read_buffer_offset);
01511 if (bytes_read < 0)
01512 {
01513 if ((EINTR == errno) || (EAGAIN == errno))
01514 return MHD_NO;
01515 #if HAVE_MESSAGES
01516 #if HTTPS_SUPPORT
01517 if (0 != (connection->daemon->options & MHD_USE_SSL))
01518 MHD_DLOG (connection->daemon,
01519 "Failed to receive data: %s\n",
01520 gnutls_strerror (bytes_read));
01521 else
01522 #endif
01523 MHD_DLOG (connection->daemon,
01524 "Failed to receive data: %s\n", STRERROR (errno));
01525 #endif
01526 CONNECTION_CLOSE_ERROR (connection, NULL);
01527 return MHD_YES;
01528 }
01529 if (0 == bytes_read)
01530 {
01531
01532
01533 connection->read_closed = MHD_YES;
01534 MHD_connection_close (connection,
01535 MHD_REQUEST_TERMINATED_CLIENT_ABORT);
01536 return MHD_YES;
01537 }
01538 connection->read_buffer_offset += bytes_read;
01539 return MHD_YES;
01540 }
01541
01550 static int
01551 do_write (struct MHD_Connection *connection)
01552 {
01553 int ret;
01554 size_t max;
01555
01556 max = connection->write_buffer_append_offset - connection->write_buffer_send_offset;
01557 ret = connection->send_cls (connection,
01558 &connection->write_buffer
01559 [connection->write_buffer_send_offset],
01560 max);
01561
01562 if (ret < 0)
01563 {
01564 if ((EINTR == errno) || (EAGAIN == errno))
01565 return MHD_NO;
01566 #if HAVE_MESSAGES
01567 #if HTTPS_SUPPORT
01568 if (0 != (connection->daemon->options & MHD_USE_SSL))
01569 MHD_DLOG (connection->daemon,
01570 "Failed to send data: %s\n",
01571 gnutls_strerror (ret));
01572 else
01573 #endif
01574 MHD_DLOG (connection->daemon,
01575 "Failed to send data: %s\n", STRERROR (errno));
01576 #endif
01577 CONNECTION_CLOSE_ERROR (connection, NULL);
01578 return MHD_YES;
01579 }
01580 #if DEBUG_SEND_DATA
01581 FPRINTF (stderr,
01582 "Sent response: `%.*s'\n",
01583 ret,
01584 &connection->write_buffer[connection->write_buffer_send_offset]);
01585 #endif
01586
01587
01588 if (0 != max)
01589 connection->write_buffer_send_offset += ret;
01590 return MHD_YES;
01591 }
01592
01593
01602 static int
01603 check_write_done (struct MHD_Connection *connection,
01604 enum MHD_CONNECTION_STATE next_state)
01605 {
01606 if (connection->write_buffer_append_offset !=
01607 connection->write_buffer_send_offset)
01608 return MHD_NO;
01609 connection->write_buffer_append_offset = 0;
01610 connection->write_buffer_send_offset = 0;
01611 connection->state = next_state;
01612 MHD_pool_reallocate (connection->pool,
01613 connection->write_buffer,
01614 connection->write_buffer_size, 0);
01615 connection->write_buffer = NULL;
01616 connection->write_buffer_size = 0;
01617 return MHD_YES;
01618 }
01619
01620
01630 static int
01631 process_header_line (struct MHD_Connection *connection, char *line)
01632 {
01633 char *colon;
01634
01635
01636 colon = strchr (line, ':');
01637 if (NULL == colon)
01638 {
01639
01640 CONNECTION_CLOSE_ERROR (connection,
01641 "Received malformed line (no colon), closing connection.\n");
01642 return MHD_NO;
01643 }
01644
01645 colon[0] = '\0';
01646 colon++;
01647 while ((colon[0] != '\0') && ((colon[0] == ' ') || (colon[0] == '\t')))
01648 colon++;
01649
01650
01651
01652
01653
01654 connection->last = line;
01655 connection->colon = colon;
01656 return MHD_YES;
01657 }
01658
01659
01670 static int
01671 process_broken_line (struct MHD_Connection *connection,
01672 char *line, enum MHD_ValueKind kind)
01673 {
01674 char *last;
01675 char *tmp;
01676 size_t last_len;
01677 size_t tmp_len;
01678
01679 last = connection->last;
01680 if ((line[0] == ' ') || (line[0] == '\t'))
01681 {
01682
01683
01684 last_len = strlen (last);
01685
01686 tmp = line;
01687 while ((tmp[0] == ' ') || (tmp[0] == '\t'))
01688 tmp++;
01689 tmp_len = strlen (tmp);
01690
01691
01692
01693
01694
01695
01696
01697
01698
01699 last = MHD_pool_reallocate (connection->pool,
01700 last,
01701 last_len + 1,
01702 last_len + tmp_len + 1);
01703 if (NULL == last)
01704 {
01705 transmit_error_response (connection,
01706 MHD_HTTP_REQUEST_ENTITY_TOO_LARGE,
01707 REQUEST_TOO_BIG);
01708 return MHD_NO;
01709 }
01710 memcpy (&last[last_len], tmp, tmp_len + 1);
01711 connection->last = last;
01712 return MHD_YES;
01713 }
01714 EXTRA_CHECK ((NULL != last) && (NULL != connection->colon));
01715 if ((MHD_NO == connection_add_header (connection,
01716 last, connection->colon, kind)))
01717 {
01718 transmit_error_response (connection, MHD_HTTP_REQUEST_ENTITY_TOO_LARGE,
01719 REQUEST_TOO_BIG);
01720 return MHD_NO;
01721 }
01722
01723 if (0 != strlen (line))
01724 {
01725 if (MHD_NO == process_header_line (connection, line))
01726 {
01727 transmit_error_response (connection,
01728 MHD_HTTP_BAD_REQUEST, REQUEST_MALFORMED);
01729 return MHD_NO;
01730 }
01731 }
01732 return MHD_YES;
01733 }
01734
01735
01743 static void
01744 parse_connection_headers (struct MHD_Connection *connection)
01745 {
01746 const char *clen;
01747 MHD_UNSIGNED_LONG_LONG cval;
01748 struct MHD_Response *response;
01749 const char *enc;
01750 char *end;
01751
01752 parse_cookie_header (connection);
01753 if ((0 != (MHD_USE_PEDANTIC_CHECKS & connection->daemon->options))
01754 && (NULL != connection->version)
01755 && (0 == strcasecmp (MHD_HTTP_VERSION_1_1, connection->version))
01756 && (NULL ==
01757 MHD_lookup_connection_value (connection, MHD_HEADER_KIND,
01758 MHD_HTTP_HEADER_HOST)))
01759 {
01760
01761 connection->state = MHD_CONNECTION_FOOTERS_RECEIVED;
01762 connection->read_closed = MHD_YES;
01763 #if HAVE_MESSAGES
01764 MHD_DLOG (connection->daemon,
01765 "Received `%s' request without `%s' header.\n",
01766 MHD_HTTP_VERSION_1_1, MHD_HTTP_HEADER_HOST);
01767 #endif
01768 EXTRA_CHECK (connection->response == NULL);
01769 response =
01770 MHD_create_response_from_buffer (strlen (REQUEST_LACKS_HOST),
01771 REQUEST_LACKS_HOST,
01772 MHD_RESPMEM_PERSISTENT);
01773 MHD_queue_response (connection, MHD_HTTP_BAD_REQUEST, response);
01774 MHD_destroy_response (response);
01775 return;
01776 }
01777
01778 connection->remaining_upload_size = 0;
01779 enc = MHD_lookup_connection_value (connection,
01780 MHD_HEADER_KIND,
01781 MHD_HTTP_HEADER_TRANSFER_ENCODING);
01782 if (enc != NULL)
01783 {
01784 connection->remaining_upload_size = MHD_SIZE_UNKNOWN;
01785 if (0 == strcasecmp (enc, "chunked"))
01786 connection->have_chunked_upload = MHD_YES;
01787 }
01788 else
01789 {
01790 clen = MHD_lookup_connection_value (connection,
01791 MHD_HEADER_KIND,
01792 MHD_HTTP_HEADER_CONTENT_LENGTH);
01793 if (clen != NULL)
01794 {
01795 cval = strtoul (clen, &end, 10);
01796 if ( ('\0' != *end) ||
01797 ( (LONG_MAX == cval) && (errno == ERANGE) ) )
01798 {
01799 #if HAVE_MESSAGES
01800 MHD_DLOG (connection->daemon,
01801 "Failed to parse `%s' header `%s', closing connection.\n",
01802 MHD_HTTP_HEADER_CONTENT_LENGTH, clen);
01803 #endif
01804 CONNECTION_CLOSE_ERROR (connection, NULL);
01805 return;
01806 }
01807 connection->remaining_upload_size = cval;
01808 }
01809 }
01810 }
01811
01812
01820 static void
01821 update_last_activity (struct MHD_Connection *connection)
01822 {
01823 struct MHD_Daemon *daemon = connection->daemon;
01824
01825 connection->last_activity = MHD_monotonic_time();
01826 if (connection->connection_timeout != daemon->connection_timeout)
01827 return;
01828
01829
01830 if ( (0 != (daemon->options & MHD_USE_THREAD_PER_CONNECTION)) &&
01831 (0 != pthread_mutex_lock (&daemon->cleanup_connection_mutex)) )
01832 MHD_PANIC ("Failed to acquire cleanup mutex\n");
01833 XDLL_remove (daemon->normal_timeout_head,
01834 daemon->normal_timeout_tail,
01835 connection);
01836 XDLL_insert (daemon->normal_timeout_head,
01837 daemon->normal_timeout_tail,
01838 connection);
01839 if ( (0 != (daemon->options & MHD_USE_THREAD_PER_CONNECTION)) &&
01840 (0 != pthread_mutex_unlock (&daemon->cleanup_connection_mutex)) )
01841 MHD_PANIC ("Failed to release cleanup mutex\n");
01842 }
01843
01844
01853 int
01854 MHD_connection_handle_read (struct MHD_Connection *connection)
01855 {
01856 update_last_activity (connection);
01857 if (MHD_CONNECTION_CLOSED == connection->state)
01858 return MHD_YES;
01859
01860
01861 if (connection->read_buffer_offset + connection->daemon->pool_increment >
01862 connection->read_buffer_size)
01863 try_grow_read_buffer (connection);
01864 if (MHD_NO == do_read (connection))
01865 return MHD_YES;
01866 while (1)
01867 {
01868 #if DEBUG_STATES
01869 MHD_DLOG (connection->daemon, "%s: state: %s\n",
01870 __FUNCTION__, MHD_state_to_string (connection->state));
01871 #endif
01872 switch (connection->state)
01873 {
01874 case MHD_CONNECTION_INIT:
01875 case MHD_CONNECTION_URL_RECEIVED:
01876 case MHD_CONNECTION_HEADER_PART_RECEIVED:
01877 case MHD_CONNECTION_HEADERS_RECEIVED:
01878 case MHD_CONNECTION_HEADERS_PROCESSED:
01879 case MHD_CONNECTION_CONTINUE_SENDING:
01880 case MHD_CONNECTION_CONTINUE_SENT:
01881 case MHD_CONNECTION_BODY_RECEIVED:
01882 case MHD_CONNECTION_FOOTER_PART_RECEIVED:
01883
01884 if (MHD_YES == connection->read_closed)
01885 {
01886 MHD_connection_close (connection,
01887 MHD_REQUEST_TERMINATED_READ_ERROR);
01888 continue;
01889 }
01890 break;
01891 case MHD_CONNECTION_CLOSED:
01892 return MHD_YES;
01893 default:
01894
01895 MHD_pool_reallocate (connection->pool,
01896 connection->read_buffer,
01897 connection->read_buffer_size + 1,
01898 connection->read_buffer_offset);
01899 break;
01900 }
01901 break;
01902 }
01903 return MHD_YES;
01904 }
01905
01906
01915 int
01916 MHD_connection_handle_write (struct MHD_Connection *connection)
01917 {
01918 struct MHD_Response *response;
01919 int ret;
01920
01921 update_last_activity (connection);
01922 while (1)
01923 {
01924 #if DEBUG_STATES
01925 MHD_DLOG (connection->daemon, "%s: state: %s\n",
01926 __FUNCTION__, MHD_state_to_string (connection->state));
01927 #endif
01928 switch (connection->state)
01929 {
01930 case MHD_CONNECTION_INIT:
01931 case MHD_CONNECTION_URL_RECEIVED:
01932 case MHD_CONNECTION_HEADER_PART_RECEIVED:
01933 case MHD_CONNECTION_HEADERS_RECEIVED:
01934 EXTRA_CHECK (0);
01935 break;
01936 case MHD_CONNECTION_HEADERS_PROCESSED:
01937 break;
01938 case MHD_CONNECTION_CONTINUE_SENDING:
01939 ret = connection->send_cls (connection,
01940 &HTTP_100_CONTINUE
01941 [connection->continue_message_write_offset],
01942 strlen (HTTP_100_CONTINUE) -
01943 connection->continue_message_write_offset);
01944 if (ret < 0)
01945 {
01946 if ((errno == EINTR) || (errno == EAGAIN))
01947 break;
01948 #if HAVE_MESSAGES
01949 MHD_DLOG (connection->daemon,
01950 "Failed to send data: %s\n", STRERROR (errno));
01951 #endif
01952 CONNECTION_CLOSE_ERROR (connection, NULL);
01953 return MHD_YES;
01954 }
01955 #if DEBUG_SEND_DATA
01956 FPRINTF (stderr,
01957 "Sent 100 continue response: `%.*s'\n",
01958 ret,
01959 &HTTP_100_CONTINUE
01960 [connection->continue_message_write_offset]);
01961 #endif
01962 connection->continue_message_write_offset += ret;
01963 break;
01964 case MHD_CONNECTION_CONTINUE_SENT:
01965 case MHD_CONNECTION_BODY_RECEIVED:
01966 case MHD_CONNECTION_FOOTER_PART_RECEIVED:
01967 case MHD_CONNECTION_FOOTERS_RECEIVED:
01968 EXTRA_CHECK (0);
01969 break;
01970 case MHD_CONNECTION_HEADERS_SENDING:
01971 do_write (connection);
01972 if (connection->state != MHD_CONNECTION_HEADERS_SENDING)
01973 break;
01974 check_write_done (connection, MHD_CONNECTION_HEADERS_SENT);
01975 break;
01976 case MHD_CONNECTION_HEADERS_SENT:
01977 EXTRA_CHECK (0);
01978 break;
01979 case MHD_CONNECTION_NORMAL_BODY_READY:
01980 response = connection->response;
01981 if (NULL != response->crc)
01982 pthread_mutex_lock (&response->mutex);
01983 if (MHD_YES != try_ready_normal_body (connection))
01984 break;
01985 ret = connection->send_cls (connection,
01986 &response->data
01987 [connection->response_write_position
01988 - response->data_start],
01989 response->data_size -
01990 (connection->response_write_position
01991 - response->data_start));
01992 #if DEBUG_SEND_DATA
01993 if (ret > 0)
01994 FPRINTF (stderr,
01995 "Sent DATA response: `%.*s'\n",
01996 ret,
01997 &response->data[connection->response_write_position -
01998 response->data_start]);
01999 #endif
02000 if (NULL != response->crc)
02001 pthread_mutex_unlock (&response->mutex);
02002 if (ret < 0)
02003 {
02004 if ((errno == EINTR) || (errno == EAGAIN))
02005 return MHD_YES;
02006 #if HAVE_MESSAGES
02007 MHD_DLOG (connection->daemon,
02008 "Failed to send data: %s\n", STRERROR (errno));
02009 #endif
02010 CONNECTION_CLOSE_ERROR (connection, NULL);
02011 return MHD_YES;
02012 }
02013 connection->response_write_position += ret;
02014 if (connection->response_write_position ==
02015 connection->response->total_size)
02016 connection->state = MHD_CONNECTION_FOOTERS_SENT;
02017 break;
02018 case MHD_CONNECTION_NORMAL_BODY_UNREADY:
02019 EXTRA_CHECK (0);
02020 break;
02021 case MHD_CONNECTION_CHUNKED_BODY_READY:
02022 do_write (connection);
02023 if (connection->state != MHD_CONNECTION_CHUNKED_BODY_READY)
02024 break;
02025 check_write_done (connection,
02026 (connection->response->total_size ==
02027 connection->response_write_position) ?
02028 MHD_CONNECTION_BODY_SENT :
02029 MHD_CONNECTION_CHUNKED_BODY_UNREADY);
02030 break;
02031 case MHD_CONNECTION_CHUNKED_BODY_UNREADY:
02032 case MHD_CONNECTION_BODY_SENT:
02033 EXTRA_CHECK (0);
02034 break;
02035 case MHD_CONNECTION_FOOTERS_SENDING:
02036 do_write (connection);
02037 if (connection->state != MHD_CONNECTION_FOOTERS_SENDING)
02038 break;
02039 check_write_done (connection, MHD_CONNECTION_FOOTERS_SENT);
02040 break;
02041 case MHD_CONNECTION_FOOTERS_SENT:
02042 EXTRA_CHECK (0);
02043 break;
02044 case MHD_CONNECTION_CLOSED:
02045 return MHD_YES;
02046 case MHD_TLS_CONNECTION_INIT:
02047 EXTRA_CHECK (0);
02048 break;
02049 default:
02050 EXTRA_CHECK (0);
02051 CONNECTION_CLOSE_ERROR (connection, "Internal error\n");
02052 return MHD_YES;
02053 }
02054 break;
02055 }
02056 return MHD_YES;
02057 }
02058
02059
02066 static void
02067 cleanup_connection (struct MHD_Connection *connection)
02068 {
02069 struct MHD_Daemon *daemon = connection->daemon;
02070
02071 if (NULL != connection->response)
02072 {
02073 MHD_destroy_response (connection->response);
02074 connection->response = NULL;
02075 }
02076 if ( (0 != (daemon->options & MHD_USE_THREAD_PER_CONNECTION)) &&
02077 (0 != pthread_mutex_lock (&daemon->cleanup_connection_mutex)) )
02078 MHD_PANIC ("Failed to acquire cleanup mutex\n");
02079 if (connection->connection_timeout == daemon->connection_timeout)
02080 XDLL_remove (daemon->normal_timeout_head,
02081 daemon->normal_timeout_tail,
02082 connection);
02083 else
02084 XDLL_remove (daemon->manual_timeout_head,
02085 daemon->manual_timeout_tail,
02086 connection);
02087 if (MHD_YES == connection->suspended)
02088 DLL_remove (daemon->suspended_connections_head,
02089 daemon->suspended_connections_tail,
02090 connection);
02091 else
02092 DLL_remove (daemon->connections_head,
02093 daemon->connections_tail,
02094 connection);
02095 DLL_insert (daemon->cleanup_head,
02096 daemon->cleanup_tail,
02097 connection);
02098 connection->suspended = MHD_NO;
02099 connection->resuming = MHD_NO;
02100 connection->in_idle = MHD_NO;
02101 if ( (0 != (daemon->options & MHD_USE_THREAD_PER_CONNECTION)) &&
02102 (0 != pthread_mutex_unlock(&daemon->cleanup_connection_mutex)) )
02103 MHD_PANIC ("Failed to release cleanup mutex\n");
02104 }
02105
02106
02115 int
02116 MHD_connection_handle_idle (struct MHD_Connection *connection)
02117 {
02118 struct MHD_Daemon *daemon = connection->daemon;
02119 unsigned int timeout;
02120 const char *end;
02121 int rend;
02122 char *line;
02123
02124 connection->in_idle = MHD_YES;
02125 while (1)
02126 {
02127 #if DEBUG_STATES
02128 MHD_DLOG (daemon, "%s: state: %s\n",
02129 __FUNCTION__, MHD_state_to_string (connection->state));
02130 #endif
02131 switch (connection->state)
02132 {
02133 case MHD_CONNECTION_INIT:
02134 line = get_next_header_line (connection);
02135 if (NULL == line)
02136 {
02137 if (MHD_CONNECTION_INIT != connection->state)
02138 continue;
02139 if (MHD_YES == connection->read_closed)
02140 {
02141 CONNECTION_CLOSE_ERROR (connection,
02142 NULL);
02143 continue;
02144 }
02145 break;
02146 }
02147 if (MHD_NO == parse_initial_message_line (connection, line))
02148 CONNECTION_CLOSE_ERROR (connection, NULL);
02149 else
02150 connection->state = MHD_CONNECTION_URL_RECEIVED;
02151 continue;
02152 case MHD_CONNECTION_URL_RECEIVED:
02153 line = get_next_header_line (connection);
02154 if (NULL == line)
02155 {
02156 if (MHD_CONNECTION_URL_RECEIVED != connection->state)
02157 continue;
02158 if (MHD_YES == connection->read_closed)
02159 {
02160 CONNECTION_CLOSE_ERROR (connection,
02161 NULL);
02162 continue;
02163 }
02164 break;
02165 }
02166 if (strlen (line) == 0)
02167 {
02168 connection->state = MHD_CONNECTION_HEADERS_RECEIVED;
02169 continue;
02170 }
02171 if (MHD_NO == process_header_line (connection, line))
02172 {
02173 transmit_error_response (connection,
02174 MHD_HTTP_BAD_REQUEST,
02175 REQUEST_MALFORMED);
02176 break;
02177 }
02178 connection->state = MHD_CONNECTION_HEADER_PART_RECEIVED;
02179 continue;
02180 case MHD_CONNECTION_HEADER_PART_RECEIVED:
02181 line = get_next_header_line (connection);
02182 if (NULL == line)
02183 {
02184 if (connection->state != MHD_CONNECTION_HEADER_PART_RECEIVED)
02185 continue;
02186 if (MHD_YES == connection->read_closed)
02187 {
02188 CONNECTION_CLOSE_ERROR (connection,
02189 NULL);
02190 continue;
02191 }
02192 break;
02193 }
02194 if (MHD_NO ==
02195 process_broken_line (connection, line, MHD_HEADER_KIND))
02196 continue;
02197 if (0 == strlen (line))
02198 {
02199 connection->state = MHD_CONNECTION_HEADERS_RECEIVED;
02200 continue;
02201 }
02202 continue;
02203 case MHD_CONNECTION_HEADERS_RECEIVED:
02204 parse_connection_headers (connection);
02205 if (MHD_CONNECTION_CLOSED == connection->state)
02206 continue;
02207 connection->state = MHD_CONNECTION_HEADERS_PROCESSED;
02208 continue;
02209 case MHD_CONNECTION_HEADERS_PROCESSED:
02210 call_connection_handler (connection);
02211 if (MHD_CONNECTION_CLOSED == connection->state)
02212 continue;
02213 if (need_100_continue (connection))
02214 {
02215 connection->state = MHD_CONNECTION_CONTINUE_SENDING;
02216 break;
02217 }
02218 if ( (NULL != connection->response) &&
02219 ( (0 == strcasecmp (connection->method,
02220 MHD_HTTP_METHOD_POST)) ||
02221 (0 == strcasecmp (connection->method,
02222 MHD_HTTP_METHOD_PUT))) )
02223 {
02224
02225 connection->remaining_upload_size = 0;
02226
02227 connection->read_closed = MHD_YES;
02228 }
02229 connection->state = (0 == connection->remaining_upload_size)
02230 ? MHD_CONNECTION_FOOTERS_RECEIVED : MHD_CONNECTION_CONTINUE_SENT;
02231 continue;
02232 case MHD_CONNECTION_CONTINUE_SENDING:
02233 if (connection->continue_message_write_offset ==
02234 strlen (HTTP_100_CONTINUE))
02235 {
02236 connection->state = MHD_CONNECTION_CONTINUE_SENT;
02237 continue;
02238 }
02239 break;
02240 case MHD_CONNECTION_CONTINUE_SENT:
02241 if (connection->read_buffer_offset != 0)
02242 {
02243 process_request_body (connection);
02244 if (MHD_CONNECTION_CLOSED == connection->state)
02245 continue;
02246 }
02247 if ((connection->remaining_upload_size == 0) ||
02248 ((connection->remaining_upload_size == MHD_SIZE_UNKNOWN) &&
02249 (connection->read_buffer_offset == 0) &&
02250 (MHD_YES == connection->read_closed)))
02251 {
02252 if ((MHD_YES == connection->have_chunked_upload) &&
02253 (MHD_NO == connection->read_closed))
02254 connection->state = MHD_CONNECTION_BODY_RECEIVED;
02255 else
02256 connection->state = MHD_CONNECTION_FOOTERS_RECEIVED;
02257 continue;
02258 }
02259 break;
02260 case MHD_CONNECTION_BODY_RECEIVED:
02261 line = get_next_header_line (connection);
02262 if (line == NULL)
02263 {
02264 if (connection->state != MHD_CONNECTION_BODY_RECEIVED)
02265 continue;
02266 if (MHD_YES == connection->read_closed)
02267 {
02268 CONNECTION_CLOSE_ERROR (connection,
02269 NULL);
02270 continue;
02271 }
02272 break;
02273 }
02274 if (strlen (line) == 0)
02275 {
02276 connection->state = MHD_CONNECTION_FOOTERS_RECEIVED;
02277 continue;
02278 }
02279 if (MHD_NO == process_header_line (connection, line))
02280 {
02281 transmit_error_response (connection,
02282 MHD_HTTP_BAD_REQUEST,
02283 REQUEST_MALFORMED);
02284 break;
02285 }
02286 connection->state = MHD_CONNECTION_FOOTER_PART_RECEIVED;
02287 continue;
02288 case MHD_CONNECTION_FOOTER_PART_RECEIVED:
02289 line = get_next_header_line (connection);
02290 if (line == NULL)
02291 {
02292 if (connection->state != MHD_CONNECTION_FOOTER_PART_RECEIVED)
02293 continue;
02294 if (MHD_YES == connection->read_closed)
02295 {
02296 CONNECTION_CLOSE_ERROR (connection,
02297 NULL);
02298 continue;
02299 }
02300 break;
02301 }
02302 if (MHD_NO ==
02303 process_broken_line (connection, line, MHD_FOOTER_KIND))
02304 continue;
02305 if (strlen (line) == 0)
02306 {
02307 connection->state = MHD_CONNECTION_FOOTERS_RECEIVED;
02308 continue;
02309 }
02310 continue;
02311 case MHD_CONNECTION_FOOTERS_RECEIVED:
02312 call_connection_handler (connection);
02313 if (connection->state == MHD_CONNECTION_CLOSED)
02314 continue;
02315 if (connection->response == NULL)
02316 break;
02317 if (MHD_NO == build_header_response (connection))
02318 {
02319
02320 CONNECTION_CLOSE_ERROR (connection,
02321 "Closing connection (failed to create response header)\n");
02322 continue;
02323 }
02324 connection->state = MHD_CONNECTION_HEADERS_SENDING;
02325
02326 #if HAVE_DECL_TCP_CORK
02327
02328 {
02329 const int val = 1;
02330 setsockopt (connection->socket_fd, IPPROTO_TCP, TCP_CORK, &val,
02331 sizeof (val));
02332 }
02333 #endif
02334 break;
02335 case MHD_CONNECTION_HEADERS_SENDING:
02336
02337 break;
02338 case MHD_CONNECTION_HEADERS_SENT:
02339 if (connection->have_chunked_upload)
02340 connection->state = MHD_CONNECTION_CHUNKED_BODY_UNREADY;
02341 else
02342 connection->state = MHD_CONNECTION_NORMAL_BODY_UNREADY;
02343 continue;
02344 case MHD_CONNECTION_NORMAL_BODY_READY:
02345
02346 break;
02347 case MHD_CONNECTION_NORMAL_BODY_UNREADY:
02348 if (NULL != connection->response->crc)
02349 pthread_mutex_lock (&connection->response->mutex);
02350 if (0 == connection->response->total_size)
02351 {
02352 if (NULL != connection->response->crc)
02353 pthread_mutex_unlock (&connection->response->mutex);
02354 connection->state = MHD_CONNECTION_BODY_SENT;
02355 continue;
02356 }
02357 if (MHD_YES == try_ready_normal_body (connection))
02358 {
02359 if (NULL != connection->response->crc)
02360 pthread_mutex_unlock (&connection->response->mutex);
02361 connection->state = MHD_CONNECTION_NORMAL_BODY_READY;
02362 break;
02363 }
02364
02365 break;
02366 case MHD_CONNECTION_CHUNKED_BODY_READY:
02367
02368 break;
02369 case MHD_CONNECTION_CHUNKED_BODY_UNREADY:
02370 if (NULL != connection->response->crc)
02371 pthread_mutex_lock (&connection->response->mutex);
02372 if (0 == connection->response->total_size)
02373 {
02374 if (NULL != connection->response->crc)
02375 pthread_mutex_unlock (&connection->response->mutex);
02376 connection->state = MHD_CONNECTION_BODY_SENT;
02377 continue;
02378 }
02379 if (MHD_YES == try_ready_chunked_body (connection))
02380 {
02381 if (NULL != connection->response->crc)
02382 pthread_mutex_unlock (&connection->response->mutex);
02383 connection->state = MHD_CONNECTION_CHUNKED_BODY_READY;
02384 continue;
02385 }
02386 if (NULL != connection->response->crc)
02387 pthread_mutex_unlock (&connection->response->mutex);
02388 break;
02389 case MHD_CONNECTION_BODY_SENT:
02390 build_header_response (connection);
02391 if (connection->write_buffer_send_offset ==
02392 connection->write_buffer_append_offset)
02393 connection->state = MHD_CONNECTION_FOOTERS_SENT;
02394 else
02395 connection->state = MHD_CONNECTION_FOOTERS_SENDING;
02396 continue;
02397 case MHD_CONNECTION_FOOTERS_SENDING:
02398
02399 break;
02400 case MHD_CONNECTION_FOOTERS_SENT:
02401 #if HAVE_DECL_TCP_CORK
02402
02403 {
02404 const int val = 0;
02405 setsockopt (connection->socket_fd, IPPROTO_TCP, TCP_CORK, &val,
02406 sizeof (val));
02407 }
02408 #endif
02409 end =
02410 MHD_get_response_header (connection->response,
02411 MHD_HTTP_HEADER_CONNECTION);
02412 rend = ( (MHD_YES == connection->read_closed) ||
02413 ( (end != NULL) && (0 == strcasecmp (end, "close")) ) );
02414 MHD_destroy_response (connection->response);
02415 connection->response = NULL;
02416 if (daemon->notify_completed != NULL)
02417 daemon->notify_completed (daemon->notify_completed_cls,
02418 connection,
02419 &connection->client_context,
02420 MHD_REQUEST_TERMINATED_COMPLETED_OK);
02421 connection->client_aware = MHD_NO;
02422 end =
02423 MHD_lookup_connection_value (connection, MHD_HEADER_KIND,
02424 MHD_HTTP_HEADER_CONNECTION);
02425 connection->client_context = NULL;
02426 connection->continue_message_write_offset = 0;
02427 connection->responseCode = 0;
02428 connection->headers_received = NULL;
02429 connection->headers_received_tail = NULL;
02430 connection->response_write_position = 0;
02431 connection->have_chunked_upload = MHD_NO;
02432 connection->method = NULL;
02433 connection->url = NULL;
02434 connection->write_buffer = NULL;
02435 connection->write_buffer_size = 0;
02436 connection->write_buffer_send_offset = 0;
02437 connection->write_buffer_append_offset = 0;
02438 if ( (rend) || ((end != NULL) && (0 == strcasecmp (end, "close"))) )
02439 {
02440 connection->read_closed = MHD_YES;
02441 connection->read_buffer_offset = 0;
02442 }
02443 if (((MHD_YES == connection->read_closed) &&
02444 (0 == connection->read_buffer_offset)) ||
02445 (connection->version == NULL) ||
02446 (0 != strcasecmp (MHD_HTTP_VERSION_1_1, connection->version)))
02447 {
02448
02449 MHD_connection_close (connection, MHD_REQUEST_TERMINATED_COMPLETED_OK);
02450 MHD_pool_destroy (connection->pool);
02451 connection->pool = NULL;
02452 connection->read_buffer = NULL;
02453 connection->read_buffer_size = 0;
02454 connection->read_buffer_offset = 0;
02455 }
02456 else
02457 {
02458 connection->version = NULL;
02459 connection->state = MHD_CONNECTION_INIT;
02460 connection->read_buffer
02461 = MHD_pool_reset (connection->pool,
02462 connection->read_buffer,
02463 connection->read_buffer_size);
02464 }
02465 continue;
02466 case MHD_CONNECTION_CLOSED:
02467 cleanup_connection (connection);
02468 return MHD_NO;
02469 default:
02470 EXTRA_CHECK (0);
02471 break;
02472 }
02473 break;
02474 }
02475 timeout = connection->connection_timeout;
02476 if ( (timeout != 0) &&
02477 (timeout <= (MHD_monotonic_time() - connection->last_activity)) )
02478 {
02479 MHD_connection_close (connection, MHD_REQUEST_TERMINATED_TIMEOUT_REACHED);
02480 connection->in_idle = MHD_NO;
02481 return MHD_YES;
02482 }
02483 MHD_connection_update_event_loop_info (connection);
02484 #if EPOLL_SUPPORT
02485 switch (connection->event_loop_info)
02486 {
02487 case MHD_EVENT_LOOP_INFO_READ:
02488 if ( (0 != (connection->epoll_state & MHD_EPOLL_STATE_READ_READY)) &&
02489 (0 == (connection->epoll_state & MHD_EPOLL_STATE_SUSPENDED)) &&
02490 (0 == (connection->epoll_state & MHD_EPOLL_STATE_IN_EREADY_EDLL)) )
02491 {
02492 EDLL_insert (daemon->eready_head,
02493 daemon->eready_tail,
02494 connection);
02495 connection->epoll_state |= MHD_EPOLL_STATE_IN_EREADY_EDLL;
02496 }
02497 break;
02498 case MHD_EVENT_LOOP_INFO_WRITE:
02499 if ( (connection->read_buffer_size > connection->read_buffer_offset) &&
02500 (0 != (connection->epoll_state & MHD_EPOLL_STATE_READ_READY)) &&
02501 (0 == (connection->epoll_state & MHD_EPOLL_STATE_SUSPENDED)) &&
02502 (0 == (connection->epoll_state & MHD_EPOLL_STATE_IN_EREADY_EDLL)) )
02503 {
02504 EDLL_insert (daemon->eready_head,
02505 daemon->eready_tail,
02506 connection);
02507 connection->epoll_state |= MHD_EPOLL_STATE_IN_EREADY_EDLL;
02508 }
02509 if ( (0 != (connection->epoll_state & MHD_EPOLL_STATE_WRITE_READY)) &&
02510 (0 == (connection->epoll_state & MHD_EPOLL_STATE_SUSPENDED)) &&
02511 (0 == (connection->epoll_state & MHD_EPOLL_STATE_IN_EREADY_EDLL)) )
02512 {
02513 EDLL_insert (daemon->eready_head,
02514 daemon->eready_tail,
02515 connection);
02516 connection->epoll_state |= MHD_EPOLL_STATE_IN_EREADY_EDLL;
02517 }
02518 break;
02519 case MHD_EVENT_LOOP_INFO_BLOCK:
02520
02521
02522 if ( (0 == (connection->epoll_state & MHD_EPOLL_STATE_IN_EREADY_EDLL) &&
02523 (0 == (connection->epoll_state & MHD_EPOLL_STATE_SUSPENDED))) )
02524 {
02525 EDLL_insert (daemon->eready_head,
02526 daemon->eready_tail,
02527 connection);
02528 connection->epoll_state |= MHD_EPOLL_STATE_IN_EREADY_EDLL;
02529 }
02530 break;
02531 case MHD_EVENT_LOOP_INFO_CLEANUP:
02532
02533 break;
02534 }
02535 return MHD_connection_epoll_update_ (connection);
02536 #else
02537 return MHD_YES;
02538 #endif
02539 }
02540
02541
02542 #if EPOLL_SUPPORT
02543
02551 int
02552 MHD_connection_epoll_update_ (struct MHD_Connection *connection)
02553 {
02554 struct MHD_Daemon *daemon = connection->daemon;
02555
02556 if ( (0 != (daemon->options & MHD_USE_EPOLL_LINUX_ONLY)) &&
02557 (0 == (connection->epoll_state & MHD_EPOLL_STATE_IN_EPOLL_SET)) &&
02558 (0 == (connection->epoll_state & MHD_EPOLL_STATE_SUSPENDED)) &&
02559 ( (0 == (connection->epoll_state & MHD_EPOLL_STATE_WRITE_READY)) ||
02560 ( (0 == (connection->epoll_state & MHD_EPOLL_STATE_READ_READY)) &&
02561 ( (MHD_EVENT_LOOP_INFO_READ == connection->event_loop_info) ||
02562 (connection->read_buffer_size > connection->read_buffer_offset) ) &&
02563 (MHD_NO == connection->read_closed) ) ) )
02564 {
02565
02566 struct epoll_event event;
02567
02568 event.events = EPOLLIN | EPOLLOUT | EPOLLET;
02569 event.data.ptr = connection;
02570 if (0 != epoll_ctl (daemon->epoll_fd,
02571 EPOLL_CTL_ADD,
02572 connection->socket_fd,
02573 &event))
02574 {
02575 #if HAVE_MESSAGES
02576 if (0 != (daemon->options & MHD_USE_DEBUG))
02577 MHD_DLOG (daemon,
02578 "Call to epoll_ctl failed: %s\n",
02579 STRERROR (errno));
02580 #endif
02581 connection->state = MHD_CONNECTION_CLOSED;
02582 cleanup_connection (connection);
02583 return MHD_NO;
02584 }
02585 connection->epoll_state |= MHD_EPOLL_STATE_IN_EPOLL_SET;
02586 }
02587 connection->in_idle = MHD_NO;
02588 return MHD_YES;
02589 }
02590 #endif
02591
02592
02598 void
02599 MHD_set_http_callbacks_ (struct MHD_Connection *connection)
02600 {
02601 connection->read_handler = &MHD_connection_handle_read;
02602 connection->write_handler = &MHD_connection_handle_write;
02603 connection->idle_handler = &MHD_connection_handle_idle;
02604 }
02605
02606
02617 const union MHD_ConnectionInfo *
02618 MHD_get_connection_info (struct MHD_Connection *connection,
02619 enum MHD_ConnectionInfoType info_type, ...)
02620 {
02621 switch (info_type)
02622 {
02623 #if HTTPS_SUPPORT
02624 case MHD_CONNECTION_INFO_CIPHER_ALGO:
02625 if (connection->tls_session == NULL)
02626 return NULL;
02627 connection->cipher = gnutls_cipher_get (connection->tls_session);
02628 return (const union MHD_ConnectionInfo *) &connection->cipher;
02629 case MHD_CONNECTION_INFO_PROTOCOL:
02630 if (connection->tls_session == NULL)
02631 return NULL;
02632 connection->protocol = gnutls_protocol_get_version (connection->tls_session);
02633 return (const union MHD_ConnectionInfo *) &connection->protocol;
02634 case MHD_CONNECTION_INFO_GNUTLS_SESSION:
02635 if (connection->tls_session == NULL)
02636 return NULL;
02637 return (const union MHD_ConnectionInfo *) &connection->tls_session;
02638 #endif
02639 case MHD_CONNECTION_INFO_CLIENT_ADDRESS:
02640 return (const union MHD_ConnectionInfo *) &connection->addr;
02641 case MHD_CONNECTION_INFO_DAEMON:
02642 return (const union MHD_ConnectionInfo *) &connection->daemon;
02643 case MHD_CONNECTION_INFO_CONNECTION_FD:
02644 return (const union MHD_ConnectionInfo *) &connection->socket_fd;
02645 default:
02646 return NULL;
02647 };
02648 }
02649
02650
02660 int
02661 MHD_set_connection_option (struct MHD_Connection *connection,
02662 enum MHD_CONNECTION_OPTION option,
02663 ...)
02664 {
02665 va_list ap;
02666 struct MHD_Daemon *daemon;
02667
02668 daemon = connection->daemon;
02669 switch (option)
02670 {
02671 case MHD_CONNECTION_OPTION_TIMEOUT:
02672 if ( (0 != (daemon->options & MHD_USE_THREAD_PER_CONNECTION)) &&
02673 (0 != pthread_mutex_lock (&daemon->cleanup_connection_mutex)) )
02674 MHD_PANIC ("Failed to acquire cleanup mutex\n");
02675 if (connection->connection_timeout == daemon->connection_timeout)
02676 XDLL_remove (daemon->normal_timeout_head,
02677 daemon->normal_timeout_tail,
02678 connection);
02679 else
02680 XDLL_remove (daemon->manual_timeout_head,
02681 daemon->manual_timeout_tail,
02682 connection);
02683 va_start (ap, option);
02684 connection->connection_timeout = va_arg (ap, unsigned int);
02685 va_end (ap);
02686 if (connection->connection_timeout == daemon->connection_timeout)
02687 XDLL_insert (daemon->normal_timeout_head,
02688 daemon->normal_timeout_tail,
02689 connection);
02690 else
02691 XDLL_insert (daemon->manual_timeout_head,
02692 daemon->manual_timeout_tail,
02693 connection);
02694 if ( (0 != (daemon->options & MHD_USE_THREAD_PER_CONNECTION)) &&
02695 (0 != pthread_mutex_unlock (&daemon->cleanup_connection_mutex)) )
02696 MHD_PANIC ("Failed to release cleanup mutex\n");
02697 return MHD_YES;
02698 default:
02699 return MHD_NO;
02700 }
02701 }
02702
02703
02715 int
02716 MHD_queue_response (struct MHD_Connection *connection,
02717 unsigned int status_code, struct MHD_Response *response)
02718 {
02719 if ( (NULL == connection) ||
02720 (NULL == response) ||
02721 (NULL != connection->response) ||
02722 ( (MHD_CONNECTION_HEADERS_PROCESSED != connection->state) &&
02723 (MHD_CONNECTION_FOOTERS_RECEIVED != connection->state) ) )
02724 return MHD_NO;
02725 MHD_increment_response_rc (response);
02726 connection->response = response;
02727 connection->responseCode = status_code;
02728 if ( (NULL != connection->method) &&
02729 (0 == strcasecmp (connection->method, MHD_HTTP_METHOD_HEAD)) )
02730 {
02731
02732
02733 connection->response_write_position = response->total_size;
02734 }
02735 if ( (MHD_CONNECTION_HEADERS_PROCESSED == connection->state) &&
02736 (NULL != connection->method) &&
02737 ( (0 == strcasecmp (connection->method,
02738 MHD_HTTP_METHOD_POST)) ||
02739 (0 == strcasecmp (connection->method,
02740 MHD_HTTP_METHOD_PUT))) )
02741 {
02742
02743
02744 connection->read_closed = MHD_YES;
02745 connection->state = MHD_CONNECTION_FOOTERS_RECEIVED;
02746 }
02747 if (MHD_NO == connection->in_idle)
02748 (void) MHD_connection_handle_idle (connection);
02749 return MHD_YES;
02750 }
02751
02752
02753