|
GNU libmicrohttpd
0.9.5
|
00001 /* 00002 This file is part of libmicrohttpd 00003 (C) 2007, 2008, 2009, 2010, 2011, 2012 Daniel Pittman and Christian Grothoff 00004 00005 This library is free software; you can redistribute it and/or 00006 modify it under the terms of the GNU Lesser General Public 00007 License as published by the Free Software Foundation; either 00008 version 2.1 of the License, or (at your option) any later version. 00009 00010 This library is distributed in the hope that it will be useful, 00011 but WITHOUT ANY WARRANTY; without even the implied warranty of 00012 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00013 Lesser General Public License for more details. 00014 00015 You should have received a copy of the GNU Lesser General Public 00016 License along with this library; if not, write to the Free Software 00017 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 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 /* for TCP_CORK */ 00037 #include <netinet/tcp.h> 00038 #endif 00039 00043 #define HTTP_100_CONTINUE "HTTP/1.1 100 Continue\r\n\r\n" 00044 00052 #if HAVE_MESSAGES 00053 #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>" 00054 #else 00055 #define REQUEST_TOO_BIG "" 00056 #endif 00057 00065 #if HAVE_MESSAGES 00066 #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>" 00067 #else 00068 #define REQUEST_LACKS_HOST "" 00069 #endif 00070 00078 #if HAVE_MESSAGES 00079 #define REQUEST_MALFORMED "<html><head><title>Request malformed</title></head><body>Your HTTP request was syntactically incorrect.</body></html>" 00080 #else 00081 #define REQUEST_MALFORMED "" 00082 #endif 00083 00090 #if HAVE_MESSAGES 00091 #define INTERNAL_ERROR "<html><head><title>Internal server error</title></head><body>Some programmer needs to study the manual more carefully.</body></html>" 00092 #else 00093 #define INTERNAL_ERROR "" 00094 #endif 00095 00100 #define DEBUG_CLOSE MHD_NO 00101 00105 #define DEBUG_SEND_DATA MHD_NO 00106 00107 00118 int 00119 MHD_get_connection_values (struct MHD_Connection *connection, 00120 enum MHD_ValueKind kind, 00121 MHD_KeyValueIterator iterator, void *iterator_cls) 00122 { 00123 int ret; 00124 struct MHD_HTTP_Header *pos; 00125 00126 if (NULL == connection) 00127 return -1; 00128 ret = 0; 00129 for (pos = connection->headers_received; NULL != pos; pos = pos->next) 00130 if (0 != (pos->kind & kind)) 00131 { 00132 ret++; 00133 if ((NULL != iterator) && 00134 (MHD_YES != iterator (iterator_cls, 00135 kind, pos->header, pos->value))) 00136 return ret; 00137 } 00138 return ret; 00139 } 00140 00141 00171 int 00172 MHD_set_connection_value (struct MHD_Connection *connection, 00173 enum MHD_ValueKind kind, 00174 const char *key, const char *value) 00175 { 00176 struct MHD_HTTP_Header *pos; 00177 00178 pos = MHD_pool_allocate (connection->pool, 00179 sizeof (struct MHD_HTTP_Header), MHD_NO); 00180 if (NULL == pos) 00181 return MHD_NO; 00182 pos->header = (char *) key; 00183 pos->value = (char *) value; 00184 pos->kind = kind; 00185 pos->next = NULL; 00186 /* append 'pos' to the linked list of headers */ 00187 if (NULL == connection->headers_received_tail) 00188 { 00189 connection->headers_received = pos; 00190 connection->headers_received_tail = pos; 00191 } 00192 else 00193 { 00194 connection->headers_received_tail->next = pos; 00195 connection->headers_received_tail = pos; 00196 } 00197 return MHD_YES; 00198 } 00199 00200 00210 const char * 00211 MHD_lookup_connection_value (struct MHD_Connection *connection, 00212 enum MHD_ValueKind kind, const char *key) 00213 { 00214 struct MHD_HTTP_Header *pos; 00215 00216 if (NULL == connection) 00217 return NULL; 00218 for (pos = connection->headers_received; NULL != pos; pos = pos->next) 00219 if ((0 != (pos->kind & kind)) && 00220 ( (key == pos->header) || 00221 ( (NULL != pos->header) && 00222 (NULL != key) && 00223 (0 == strcasecmp (key, pos->header))) )) 00224 return pos->value; 00225 return NULL; 00226 } 00227 00228 00239 int 00240 MHD_queue_response (struct MHD_Connection *connection, 00241 unsigned int status_code, struct MHD_Response *response) 00242 { 00243 if ( (NULL == connection) || 00244 (NULL == response) || 00245 (NULL != connection->response) || 00246 ( (MHD_CONNECTION_HEADERS_PROCESSED != connection->state) && 00247 (MHD_CONNECTION_FOOTERS_RECEIVED != connection->state) ) ) 00248 return MHD_NO; 00249 MHD_increment_response_rc (response); 00250 connection->response = response; 00251 connection->responseCode = status_code; 00252 if ( (NULL != connection->method) && 00253 (0 == strcasecmp (connection->method, MHD_HTTP_METHOD_HEAD)) ) 00254 { 00255 /* if this is a "HEAD" request, pretend that we 00256 have already sent the full message body */ 00257 connection->response_write_position = response->total_size; 00258 } 00259 if (MHD_CONNECTION_HEADERS_PROCESSED == connection->state) 00260 { 00261 /* response was queued "early", 00262 refuse to read body / footers or further 00263 requests! */ 00264 (void) SHUTDOWN (connection->socket_fd, SHUT_RD); 00265 connection->read_closed = MHD_YES; 00266 connection->state = MHD_CONNECTION_FOOTERS_RECEIVED; 00267 } 00268 return MHD_YES; 00269 } 00270 00271 00279 static int 00280 need_100_continue (struct MHD_Connection *connection) 00281 { 00282 const char *expect; 00283 00284 return ( (NULL == connection->response) && 00285 (NULL != connection->version) && 00286 (0 == strcasecmp (connection->version, 00287 MHD_HTTP_VERSION_1_1)) && 00288 (NULL != (expect = MHD_lookup_connection_value (connection, 00289 MHD_HEADER_KIND, 00290 MHD_HTTP_HEADER_EXPECT))) && 00291 (0 == strcasecmp (expect, "100-continue")) && 00292 (connection->continue_message_write_offset < 00293 strlen (HTTP_100_CONTINUE)) ); 00294 } 00295 00296 00304 void 00305 MHD_connection_close (struct MHD_Connection *connection, 00306 enum MHD_RequestTerminationCode termination_code) 00307 { 00308 struct MHD_Daemon *daemon; 00309 00310 daemon = connection->daemon; 00311 SHUTDOWN (connection->socket_fd, 00312 (connection->read_closed == MHD_YES) ? SHUT_WR : SHUT_RDWR); 00313 connection->state = MHD_CONNECTION_CLOSED; 00314 if ( (NULL != daemon->notify_completed) && 00315 (MHD_YES == connection->client_aware) ) 00316 daemon->notify_completed (daemon->notify_completed_cls, 00317 connection, 00318 &connection->client_context, 00319 termination_code); 00320 connection->client_aware = MHD_NO; 00321 } 00322 00323 00331 static void 00332 connection_close_error (struct MHD_Connection *connection, 00333 const char *emsg) 00334 { 00335 #if HAVE_MESSAGES 00336 if (NULL != emsg) 00337 MHD_DLOG (connection->daemon, emsg); 00338 #endif 00339 MHD_connection_close (connection, MHD_REQUEST_TERMINATED_WITH_ERROR); 00340 } 00341 00342 00347 #if HAVE_MESSAGES 00348 #define CONNECTION_CLOSE_ERROR(c, emsg) connection_close_error (c, emsg) 00349 #else 00350 #define CONNECTION_CLOSE_ERROR(c, emsg) connection_close_error (c, NULL) 00351 #endif 00352 00353 00364 static int 00365 try_ready_normal_body (struct MHD_Connection *connection) 00366 { 00367 int ret; 00368 struct MHD_Response *response; 00369 00370 response = connection->response; 00371 if (NULL == response->crc) 00372 return MHD_YES; 00373 if ( (response->data_start <= 00374 connection->response_write_position) && 00375 (response->data_size + response->data_start > 00376 connection->response_write_position) ) 00377 return MHD_YES; /* response already ready */ 00378 #if LINUX 00379 if ( (-1 != response->fd) && 00380 (0 == (connection->daemon->options & MHD_USE_SSL)) ) 00381 { 00382 /* will use sendfile, no need to bother response crc */ 00383 return MHD_YES; 00384 } 00385 #endif 00386 00387 ret = response->crc (response->crc_cls, 00388 connection->response_write_position, 00389 response->data, 00390 MHD_MIN (response->data_buffer_size, 00391 response->total_size - 00392 connection->response_write_position)); 00393 if ((0 == ret) && 00394 (0 != (connection->daemon->options & MHD_USE_SELECT_INTERNALLY))) 00395 mhd_panic (mhd_panic_cls, __FILE__, __LINE__, 00396 #if HAVE_MESSAGES 00397 "API violation" 00398 #else 00399 NULL 00400 #endif 00401 ); 00402 if ( (MHD_CONTENT_READER_END_OF_STREAM == ret) || 00403 (MHD_CONTENT_READER_END_WITH_ERROR == ret) ) 00404 { 00405 /* either error or http 1.0 transfer, close socket! */ 00406 response->total_size = connection->response_write_position; 00407 CONNECTION_CLOSE_ERROR (connection, 00408 (ret == MHD_CONTENT_READER_END_OF_STREAM) 00409 ? "Closing connection (end of response)\n" 00410 : "Closing connection (stream error)\n"); 00411 return MHD_NO; 00412 } 00413 response->data_start = connection->response_write_position; 00414 response->data_size = ret; 00415 if (0 == ret) 00416 { 00417 connection->state = MHD_CONNECTION_NORMAL_BODY_UNREADY; 00418 return MHD_NO; 00419 } 00420 return MHD_YES; 00421 } 00422 00423 00433 static int 00434 try_ready_chunked_body (struct MHD_Connection *connection) 00435 { 00436 int ret; 00437 char *buf; 00438 struct MHD_Response *response; 00439 size_t size; 00440 char cbuf[10]; /* 10: max strlen of "%x\r\n" */ 00441 int cblen; 00442 00443 response = connection->response; 00444 if (0 == connection->write_buffer_size) 00445 { 00446 size = connection->daemon->pool_size; 00447 do 00448 { 00449 size /= 2; 00450 if (size < 128) 00451 { 00452 /* not enough memory */ 00453 CONNECTION_CLOSE_ERROR (connection, 00454 "Closing connection (out of memory)\n"); 00455 return MHD_NO; 00456 } 00457 buf = MHD_pool_allocate (connection->pool, size, MHD_NO); 00458 } 00459 while (NULL == buf); 00460 connection->write_buffer_size = size; 00461 connection->write_buffer = buf; 00462 } 00463 00464 if ( (response->data_start <= 00465 connection->response_write_position) && 00466 (response->data_size + response->data_start > 00467 connection->response_write_position) ) 00468 { 00469 /* buffer already ready, use what is there for the chunk */ 00470 ret = response->data_size + response->data_start - connection->response_write_position; 00471 if (ret > connection->write_buffer_size - sizeof (cbuf) - 2) 00472 ret = connection->write_buffer_size - sizeof (cbuf) - 2; 00473 memcpy (&connection->write_buffer[sizeof (cbuf)], 00474 &response->data[connection->response_write_position - response->data_start], 00475 ret); 00476 } 00477 else 00478 { 00479 /* buffer not in range, try to fill it */ 00480 ret = response->crc (response->crc_cls, 00481 connection->response_write_position, 00482 &connection->write_buffer[sizeof (cbuf)], 00483 connection->write_buffer_size - sizeof (cbuf) - 2); 00484 } 00485 if (MHD_CONTENT_READER_END_WITH_ERROR == ret) 00486 { 00487 /* error, close socket! */ 00488 response->total_size = connection->response_write_position; 00489 CONNECTION_CLOSE_ERROR (connection, 00490 "Closing connection (error generating response)\n"); 00491 return MHD_NO; 00492 } 00493 if (MHD_CONTENT_READER_END_OF_STREAM == ret) 00494 { 00495 /* end of message, signal other side! */ 00496 strcpy (connection->write_buffer, "0\r\n"); 00497 connection->write_buffer_append_offset = 3; 00498 connection->write_buffer_send_offset = 0; 00499 response->total_size = connection->response_write_position; 00500 return MHD_YES; 00501 } 00502 if (0 == ret) 00503 { 00504 connection->state = MHD_CONNECTION_CHUNKED_BODY_UNREADY; 00505 return MHD_NO; 00506 } 00507 if (ret > 0xFFFFFF) 00508 ret = 0xFFFFFF; 00509 snprintf (cbuf, 00510 sizeof (cbuf), 00511 "%X\r\n", ret); 00512 cblen = strlen (cbuf); 00513 EXTRA_CHECK (cblen <= sizeof (cbuf)); 00514 memcpy (&connection->write_buffer[sizeof (cbuf) - cblen], cbuf, cblen); 00515 memcpy (&connection->write_buffer[sizeof (cbuf) + ret], "\r\n", 2); 00516 connection->response_write_position += ret; 00517 connection->write_buffer_send_offset = sizeof (cbuf) - cblen; 00518 connection->write_buffer_append_offset = sizeof (cbuf) + ret + 2; 00519 return MHD_YES; 00520 } 00521 00522 00529 static void 00530 add_extra_headers (struct MHD_Connection *connection) 00531 { 00532 const char *have; 00533 char buf[128]; 00534 00535 connection->have_chunked_upload = MHD_NO; 00536 if (MHD_SIZE_UNKNOWN == connection->response->total_size) 00537 { 00538 have = MHD_get_response_header (connection->response, 00539 MHD_HTTP_HEADER_CONNECTION); 00540 if ((NULL == have) || (0 != strcasecmp (have, "close"))) 00541 { 00542 if ((NULL != connection->version) && 00543 (0 == strcasecmp (connection->version, MHD_HTTP_VERSION_1_1))) 00544 { 00545 connection->have_chunked_upload = MHD_YES; 00546 have = MHD_get_response_header (connection->response, 00547 MHD_HTTP_HEADER_TRANSFER_ENCODING); 00548 if (NULL == have) 00549 MHD_add_response_header (connection->response, 00550 MHD_HTTP_HEADER_TRANSFER_ENCODING, 00551 "chunked"); 00552 } 00553 else 00554 { 00555 MHD_add_response_header (connection->response, 00556 MHD_HTTP_HEADER_CONNECTION, "close"); 00557 } 00558 } 00559 } 00560 else if (NULL == MHD_get_response_header (connection->response, 00561 MHD_HTTP_HEADER_CONTENT_LENGTH)) 00562 { 00563 SPRINTF (buf, 00564 "%" MHD_LONG_LONG_PRINTF "u", 00565 (unsigned MHD_LONG_LONG) connection->response->total_size); 00566 MHD_add_response_header (connection->response, 00567 MHD_HTTP_HEADER_CONTENT_LENGTH, buf); 00568 } 00569 } 00570 00571 00578 static void 00579 get_date_string (char *date) 00580 { 00581 static const char *days[] = 00582 { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" }; 00583 static const char *mons[] = 00584 { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", 00585 "Nov", "Dec" 00586 }; 00587 struct tm now; 00588 time_t t; 00589 00590 time (&t); 00591 gmtime_r (&t, &now); 00592 SPRINTF (date, 00593 "Date: %3s, %02u %3s %04u %02u:%02u:%02u GMT\r\n", 00594 days[now.tm_wday % 7], 00595 now.tm_mday, 00596 mons[now.tm_mon % 12], 00597 1900 + now.tm_year, now.tm_hour, now.tm_min, now.tm_sec); 00598 } 00599 00600 00607 static int 00608 try_grow_read_buffer (struct MHD_Connection *connection) 00609 { 00610 void *buf; 00611 00612 buf = MHD_pool_reallocate (connection->pool, 00613 connection->read_buffer, 00614 connection->read_buffer_size, 00615 connection->read_buffer_size * 2 + 00616 MHD_BUF_INC_SIZE + 1); 00617 if (NULL == buf) 00618 return MHD_NO; 00619 /* we can actually grow the buffer, do it! */ 00620 connection->read_buffer = buf; 00621 connection->read_buffer_size = 00622 connection->read_buffer_size * 2 + MHD_BUF_INC_SIZE; 00623 return MHD_YES; 00624 } 00625 00626 00634 static int 00635 build_header_response (struct MHD_Connection *connection) 00636 { 00637 size_t size; 00638 size_t off; 00639 struct MHD_HTTP_Header *pos; 00640 char code[256]; 00641 char date[128]; 00642 char *data; 00643 enum MHD_ValueKind kind; 00644 const char *reason_phrase; 00645 uint32_t rc; 00646 int must_add_close; 00647 00648 EXTRA_CHECK (NULL != connection->version); 00649 if (0 == strlen(connection->version)) 00650 { 00651 data = MHD_pool_allocate (connection->pool, 0, MHD_YES); 00652 connection->write_buffer = data; 00653 connection->write_buffer_append_offset = 0; 00654 connection->write_buffer_send_offset = 0; 00655 connection->write_buffer_size = 0; 00656 return MHD_YES; 00657 } 00658 if (MHD_CONNECTION_FOOTERS_RECEIVED == connection->state) 00659 { 00660 add_extra_headers (connection); 00661 rc = connection->responseCode & (~MHD_ICY_FLAG); 00662 reason_phrase = MHD_get_reason_phrase_for (rc); 00663 SPRINTF (code, 00664 "%s %u %s\r\n", 00665 (0 != (connection->responseCode & MHD_ICY_FLAG)) 00666 ? "ICY" 00667 : ( (0 == strcasecmp (MHD_HTTP_VERSION_1_0, 00668 connection->version)) 00669 ? MHD_HTTP_VERSION_1_0 00670 : MHD_HTTP_VERSION_1_1), 00671 rc, 00672 reason_phrase); 00673 off = strlen (code); 00674 /* estimate size */ 00675 size = off + 2; /* extra \r\n at the end */ 00676 kind = MHD_HEADER_KIND; 00677 if ( (0 == (connection->daemon->options & MHD_SUPPRESS_DATE_NO_CLOCK)) && 00678 (NULL == MHD_get_response_header (connection->response, 00679 MHD_HTTP_HEADER_DATE)) ) 00680 get_date_string (date); 00681 else 00682 date[0] = '\0'; 00683 size += strlen (date); 00684 } 00685 else 00686 { 00687 size = 2; 00688 kind = MHD_FOOTER_KIND; 00689 off = 0; 00690 } 00691 must_add_close = ( (connection->state == MHD_CONNECTION_FOOTERS_RECEIVED) && 00692 (connection->read_closed == MHD_YES) && 00693 (0 == strcasecmp (connection->version, 00694 MHD_HTTP_VERSION_1_1)) && 00695 (NULL == MHD_get_response_header (connection->response, 00696 MHD_HTTP_HEADER_CONNECTION)) ); 00697 if (must_add_close) 00698 size += strlen ("Connection: close\r\n"); 00699 for (pos = connection->response->first_header; NULL != pos; pos = pos->next) 00700 if (pos->kind == kind) 00701 size += strlen (pos->header) + strlen (pos->value) + 4; /* colon, space, linefeeds */ 00702 /* produce data */ 00703 data = MHD_pool_allocate (connection->pool, size + 1, MHD_YES); 00704 if (NULL == data) 00705 { 00706 #if HAVE_MESSAGES 00707 MHD_DLOG (connection->daemon, "Not enough memory for write!\n"); 00708 #endif 00709 return MHD_NO; 00710 } 00711 if (MHD_CONNECTION_FOOTERS_RECEIVED == connection->state) 00712 { 00713 memcpy (data, code, off); 00714 } 00715 if (must_add_close) 00716 { 00717 /* we must add the 'close' header because circumstances forced us to 00718 stop reading from the socket; however, we are not adding the header 00719 to the response as the response may be used in a different context 00720 as well */ 00721 memcpy (&data[off], "Connection: close\r\n", 00722 strlen ("Connection: close\r\n")); 00723 off += strlen ("Connection: close\r\n"); 00724 } 00725 for (pos = connection->response->first_header; NULL != pos; pos = pos->next) 00726 if (pos->kind == kind) 00727 off += SPRINTF (&data[off], 00728 "%s: %s\r\n", 00729 pos->header, 00730 pos->value); 00731 if (connection->state == MHD_CONNECTION_FOOTERS_RECEIVED) 00732 { 00733 strcpy (&data[off], date); 00734 off += strlen (date); 00735 } 00736 memcpy (&data[off], "\r\n", 2); 00737 off += 2; 00738 00739 if (off != size) 00740 mhd_panic (mhd_panic_cls, __FILE__, __LINE__, NULL); 00741 connection->write_buffer = data; 00742 connection->write_buffer_append_offset = size; 00743 connection->write_buffer_send_offset = 0; 00744 connection->write_buffer_size = size + 1; 00745 return MHD_YES; 00746 } 00747 00748 00758 static void 00759 transmit_error_response (struct MHD_Connection *connection, 00760 unsigned int status_code, 00761 const char *message) 00762 { 00763 struct MHD_Response *response; 00764 00765 if (NULL == connection->version) 00766 { 00767 /* we were unable to process the full header line, so we don't 00768 really know what version the client speaks; assume 1.0 */ 00769 connection->version = MHD_HTTP_VERSION_1_0; 00770 } 00771 connection->state = MHD_CONNECTION_FOOTERS_RECEIVED; 00772 connection->read_closed = MHD_YES; 00773 #if HAVE_MESSAGES 00774 MHD_DLOG (connection->daemon, 00775 "Error %u (`%s') processing request, closing connection.\n", 00776 status_code, message); 00777 #endif 00778 EXTRA_CHECK (connection->response == NULL); 00779 response = MHD_create_response_from_buffer (strlen (message), 00780 (void *) message, 00781 MHD_RESPMEM_PERSISTENT); 00782 MHD_queue_response (connection, status_code, response); 00783 EXTRA_CHECK (connection->response != NULL); 00784 MHD_destroy_response (response); 00785 if (MHD_NO == build_header_response (connection)) 00786 { 00787 /* oops - close! */ 00788 CONNECTION_CLOSE_ERROR (connection, 00789 "Closing connection (failed to create response header)\n"); 00790 } 00791 else 00792 { 00793 connection->state = MHD_CONNECTION_HEADERS_SENDING; 00794 } 00795 } 00796 00797 00806 static void 00807 add_to_fd_set (int fd, 00808 fd_set *set, 00809 int *max_fd) 00810 { 00811 FD_SET (fd, set); 00812 if ( (NULL != max_fd) && 00813 (fd > *max_fd) ) 00814 *max_fd = fd; 00815 } 00816 00817 00830 int 00831 MHD_connection_get_fdset (struct MHD_Connection *connection, 00832 fd_set *read_fd_set, 00833 fd_set *write_fd_set, 00834 fd_set *except_fd_set, 00835 int *max_fd) 00836 { 00837 int ret; 00838 struct MHD_Pollfd p; 00839 00840 /* we use the 'poll fd' as a convenient way to re-use code 00841 when determining the select sets */ 00842 memset (&p, 0, sizeof(struct MHD_Pollfd)); 00843 ret = MHD_connection_get_pollfd (connection, &p); 00844 if ( (MHD_YES == ret) && (p.fd >= 0) ) { 00845 if (0 != (p.events & MHD_POLL_ACTION_IN)) 00846 add_to_fd_set(p.fd, read_fd_set, max_fd); 00847 if (0 != (p.events & MHD_POLL_ACTION_OUT)) 00848 add_to_fd_set(p.fd, write_fd_set, max_fd); 00849 } 00850 return ret; 00851 } 00852 00853 00862 int 00863 MHD_connection_get_pollfd (struct MHD_Connection *connection, 00864 struct MHD_Pollfd *p) 00865 { 00866 int fd; 00867 00868 if (NULL == connection->pool) 00869 connection->pool = MHD_pool_create (connection->daemon->pool_size); 00870 if (NULL == connection->pool) 00871 { 00872 CONNECTION_CLOSE_ERROR (connection, 00873 "Failed to create memory pool!\n"); 00874 return MHD_YES; 00875 } 00876 fd = connection->socket_fd; 00877 p->fd = fd; 00878 if (-1 == fd) 00879 return MHD_YES; 00880 while (1) 00881 { 00882 #if DEBUG_STATES 00883 MHD_DLOG (connection->daemon, "%s: state: %s\n", 00884 __FUNCTION__, MHD_state_to_string (connection->state)); 00885 #endif 00886 switch (connection->state) 00887 { 00888 #if HTTPS_SUPPORT 00889 case MHD_TLS_CONNECTION_INIT: 00890 if (0 == gnutls_record_get_direction (connection->tls_session)) 00891 p->events |= MHD_POLL_ACTION_IN; 00892 else 00893 p->events |= MHD_POLL_ACTION_OUT; 00894 break; 00895 #endif 00896 case MHD_CONNECTION_INIT: 00897 case MHD_CONNECTION_URL_RECEIVED: 00898 case MHD_CONNECTION_HEADER_PART_RECEIVED: 00899 /* while reading headers, we always grow the 00900 read buffer if needed, no size-check required */ 00901 if ((connection->read_closed) && 00902 (0 == connection->read_buffer_offset)) 00903 { 00904 CONNECTION_CLOSE_ERROR (connection, 00905 "Connection buffer to small for request\n"); 00906 continue; 00907 } 00908 if ((connection->read_buffer_offset == connection->read_buffer_size) 00909 && (MHD_NO == try_grow_read_buffer (connection))) 00910 { 00911 transmit_error_response (connection, 00912 (connection->url != NULL) 00913 ? MHD_HTTP_REQUEST_ENTITY_TOO_LARGE 00914 : MHD_HTTP_REQUEST_URI_TOO_LONG, 00915 REQUEST_TOO_BIG); 00916 continue; 00917 } 00918 if (MHD_NO == connection->read_closed) 00919 p->events |= MHD_POLL_ACTION_IN; 00920 break; 00921 case MHD_CONNECTION_HEADERS_RECEIVED: 00922 /* we should never get here */ 00923 EXTRA_CHECK (0); 00924 break; 00925 case MHD_CONNECTION_HEADERS_PROCESSED: 00926 EXTRA_CHECK (0); 00927 break; 00928 case MHD_CONNECTION_CONTINUE_SENDING: 00929 p->events |= MHD_POLL_ACTION_OUT; 00930 break; 00931 case MHD_CONNECTION_CONTINUE_SENT: 00932 if (connection->read_buffer_offset == connection->read_buffer_size) 00933 { 00934 if ((MHD_YES != try_grow_read_buffer (connection)) && 00935 (0 != (connection->daemon->options & 00936 (MHD_USE_SELECT_INTERNALLY | 00937 MHD_USE_THREAD_PER_CONNECTION)))) 00938 { 00939 /* failed to grow the read buffer, and the 00940 client which is supposed to handle the 00941 received data in a *blocking* fashion 00942 (in this mode) did not handle the data as 00943 it was supposed to! 00944 => we would either have to do busy-waiting 00945 (on the client, which would likely fail), 00946 or if we do nothing, we would just timeout 00947 on the connection (if a timeout is even 00948 set!). 00949 Solution: we kill the connection with an error */ 00950 transmit_error_response (connection, 00951 MHD_HTTP_INTERNAL_SERVER_ERROR, 00952 INTERNAL_ERROR); 00953 continue; 00954 } 00955 } 00956 if ((connection->read_buffer_offset < connection->read_buffer_size) 00957 && (MHD_NO == connection->read_closed)) 00958 p->events |= MHD_POLL_ACTION_IN; 00959 break; 00960 case MHD_CONNECTION_BODY_RECEIVED: 00961 case MHD_CONNECTION_FOOTER_PART_RECEIVED: 00962 /* while reading footers, we always grow the 00963 read buffer if needed, no size-check required */ 00964 if (MHD_YES == connection->read_closed) 00965 { 00966 CONNECTION_CLOSE_ERROR (connection, 00967 NULL); 00968 continue; 00969 } 00970 p->events |= MHD_POLL_ACTION_IN; 00971 /* transition to FOOTERS_RECEIVED 00972 happens in read handler */ 00973 break; 00974 case MHD_CONNECTION_FOOTERS_RECEIVED: 00975 /* no socket action, wait for client 00976 to provide response */ 00977 break; 00978 case MHD_CONNECTION_HEADERS_SENDING: 00979 /* headers in buffer, keep writing */ 00980 p->events |= MHD_POLL_ACTION_OUT; 00981 break; 00982 case MHD_CONNECTION_HEADERS_SENT: 00983 EXTRA_CHECK (0); 00984 break; 00985 case MHD_CONNECTION_NORMAL_BODY_READY: 00986 p->events |= MHD_POLL_ACTION_OUT; 00987 break; 00988 case MHD_CONNECTION_NORMAL_BODY_UNREADY: 00989 /* not ready, no socket action */ 00990 break; 00991 case MHD_CONNECTION_CHUNKED_BODY_READY: 00992 p->events |= MHD_POLL_ACTION_OUT; 00993 break; 00994 case MHD_CONNECTION_CHUNKED_BODY_UNREADY: 00995 /* not ready, no socket action */ 00996 break; 00997 case MHD_CONNECTION_BODY_SENT: 00998 EXTRA_CHECK (0); 00999 break; 01000 case MHD_CONNECTION_FOOTERS_SENDING: 01001 p->events |= MHD_POLL_ACTION_OUT; 01002 break; 01003 case MHD_CONNECTION_FOOTERS_SENT: 01004 EXTRA_CHECK (0); 01005 break; 01006 case MHD_CONNECTION_CLOSED: 01007 return MHD_YES; /* do nothing, not even reading */ 01008 default: 01009 EXTRA_CHECK (0); 01010 } 01011 break; 01012 } 01013 return MHD_YES; 01014 } 01015 01016 01025 static char * 01026 get_next_header_line (struct MHD_Connection *connection) 01027 { 01028 char *rbuf; 01029 size_t pos; 01030 01031 if (0 == connection->read_buffer_offset) 01032 return NULL; 01033 pos = 0; 01034 rbuf = connection->read_buffer; 01035 while ((pos < connection->read_buffer_offset - 1) && 01036 ('\r' != rbuf[pos]) && ('\n' != rbuf[pos])) 01037 pos++; 01038 if (pos == connection->read_buffer_offset - 1) 01039 { 01040 /* not found, consider growing... */ 01041 if (connection->read_buffer_offset == connection->read_buffer_size) 01042 { 01043 rbuf = MHD_pool_reallocate (connection->pool, 01044 connection->read_buffer, 01045 connection->read_buffer_size, 01046 connection->read_buffer_size * 2 + 01047 MHD_BUF_INC_SIZE); 01048 if (NULL == rbuf) 01049 { 01050 transmit_error_response (connection, 01051 (NULL != connection->url) 01052 ? MHD_HTTP_REQUEST_ENTITY_TOO_LARGE 01053 : MHD_HTTP_REQUEST_URI_TOO_LONG, 01054 REQUEST_TOO_BIG); 01055 } 01056 else 01057 { 01058 connection->read_buffer_size = 01059 connection->read_buffer_size * 2 + MHD_BUF_INC_SIZE; 01060 connection->read_buffer = rbuf; 01061 } 01062 } 01063 return NULL; 01064 } 01065 /* found, check if we have proper CRLF */ 01066 if (('\r' == rbuf[pos]) && ('\n' == rbuf[pos + 1])) 01067 rbuf[pos++] = '\0'; /* skip both r and n */ 01068 rbuf[pos++] = '\0'; 01069 connection->read_buffer += pos; 01070 connection->read_buffer_size -= pos; 01071 connection->read_buffer_offset -= pos; 01072 return rbuf; 01073 } 01074 01075 01087 static int 01088 connection_add_header (struct MHD_Connection *connection, 01089 char *key, char *value, enum MHD_ValueKind kind) 01090 { 01091 if (MHD_NO == MHD_set_connection_value (connection, 01092 kind, 01093 key, value)) 01094 { 01095 #if HAVE_MESSAGES 01096 MHD_DLOG (connection->daemon, 01097 "Not enough memory to allocate header record!\n"); 01098 #endif 01099 transmit_error_response (connection, MHD_HTTP_REQUEST_ENTITY_TOO_LARGE, 01100 REQUEST_TOO_BIG); 01101 return MHD_NO; 01102 } 01103 return MHD_YES; 01104 } 01105 01106 01116 static int 01117 parse_arguments (enum MHD_ValueKind kind, 01118 struct MHD_Connection *connection, 01119 char *args) 01120 { 01121 char *equals; 01122 char *amper; 01123 01124 while (NULL != args) 01125 { 01126 equals = strchr (args, '='); 01127 amper = strchr (args, '&'); 01128 if (NULL == amper) 01129 { 01130 /* last argument */ 01131 if (NULL == equals) 01132 { 01133 /* got 'foo', add key 'foo' with NULL for value */ 01134 connection->daemon->unescape_callback (connection->daemon->unescape_callback_cls, 01135 connection, 01136 args); 01137 return connection_add_header (connection, 01138 args, 01139 NULL, 01140 kind); 01141 } 01142 /* got 'foo=bar' */ 01143 equals[0] = '\0'; 01144 equals++; 01145 connection->daemon->unescape_callback (connection->daemon->unescape_callback_cls, 01146 connection, 01147 args); 01148 connection->daemon->unescape_callback (connection->daemon->unescape_callback_cls, 01149 connection, 01150 equals); 01151 return connection_add_header (connection, args, equals, kind); 01152 } 01153 /* amper is non-NULL here */ 01154 amper[0] = '\0'; 01155 amper++; 01156 if ( (NULL == equals) || 01157 (equals >= amper) ) 01158 { 01159 /* got 'foo&bar' or 'foo&bar=val', add key 'foo' with NULL for value */ 01160 connection->daemon->unescape_callback (connection->daemon->unescape_callback_cls, 01161 connection, 01162 args); 01163 if (MHD_NO == 01164 connection_add_header (connection, 01165 args, 01166 NULL, 01167 kind)) 01168 return MHD_NO; 01169 /* continue with 'bar' */ 01170 args = amper; 01171 continue; 01172 01173 } 01174 /* equals and amper are non-NULL here, and equals < amper, 01175 so we got regular 'foo=value&bar...'-kind of argument */ 01176 equals[0] = '\0'; 01177 equals++; 01178 connection->daemon->unescape_callback (connection->daemon->unescape_callback_cls, 01179 connection, 01180 args); 01181 connection->daemon->unescape_callback (connection->daemon->unescape_callback_cls, 01182 connection, 01183 equals); 01184 if (MHD_NO == connection_add_header (connection, args, equals, kind)) 01185 return MHD_NO; 01186 args = amper; 01187 } 01188 return MHD_YES; 01189 } 01190 01191 01197 static int 01198 parse_cookie_header (struct MHD_Connection *connection) 01199 { 01200 const char *hdr; 01201 char *cpy; 01202 char *pos; 01203 char *sce; 01204 char *semicolon; 01205 char *equals; 01206 char *ekill; 01207 char old; 01208 int quotes; 01209 01210 hdr = MHD_lookup_connection_value (connection, 01211 MHD_HEADER_KIND, 01212 MHD_HTTP_HEADER_COOKIE); 01213 if (hdr == NULL) 01214 return MHD_YES; 01215 cpy = MHD_pool_allocate (connection->pool, strlen (hdr) + 1, MHD_YES); 01216 if (cpy == NULL) 01217 { 01218 #if HAVE_MESSAGES 01219 MHD_DLOG (connection->daemon, "Not enough memory to parse cookies!\n"); 01220 #endif 01221 transmit_error_response (connection, MHD_HTTP_REQUEST_ENTITY_TOO_LARGE, 01222 REQUEST_TOO_BIG); 01223 return MHD_NO; 01224 } 01225 memcpy (cpy, hdr, strlen (hdr) + 1); 01226 pos = cpy; 01227 while (pos != NULL) 01228 { 01229 while (*pos == ' ') 01230 pos++; /* skip spaces */ 01231 01232 sce = pos; 01233 while (((*sce) != '\0') && 01234 ((*sce) != ',') && ((*sce) != ';') && ((*sce) != '=')) 01235 sce++; 01236 /* remove tailing whitespace (if any) from key */ 01237 ekill = sce - 1; 01238 while ((*ekill == ' ') && (ekill >= pos)) 01239 *(ekill--) = '\0'; 01240 old = *sce; 01241 *sce = '\0'; 01242 if (old != '=') 01243 { 01244 /* value part omitted, use empty string... */ 01245 if (MHD_NO == 01246 connection_add_header (connection, pos, "", MHD_COOKIE_KIND)) 01247 return MHD_NO; 01248 if (old == '\0') 01249 break; 01250 pos = sce + 1; 01251 continue; 01252 } 01253 equals = sce + 1; 01254 quotes = 0; 01255 semicolon = equals; 01256 while ((semicolon[0] != '\0') && 01257 ((quotes != 0) || 01258 ((semicolon[0] != ';') && (semicolon[0] != ',')))) 01259 { 01260 if (semicolon[0] == '"') 01261 quotes = (quotes + 1) & 1; 01262 semicolon++; 01263 } 01264 if (semicolon[0] == '\0') 01265 semicolon = NULL; 01266 if (semicolon != NULL) 01267 { 01268 semicolon[0] = '\0'; 01269 semicolon++; 01270 } 01271 /* remove quotes */ 01272 if ((equals[0] == '"') && (equals[strlen (equals) - 1] == '"')) 01273 { 01274 equals[strlen (equals) - 1] = '\0'; 01275 equals++; 01276 } 01277 if (MHD_NO == connection_add_header (connection, 01278 pos, equals, MHD_COOKIE_KIND)) 01279 return MHD_NO; 01280 pos = semicolon; 01281 } 01282 return MHD_YES; 01283 } 01284 01285 01293 static int 01294 parse_initial_message_line (struct MHD_Connection *connection, char *line) 01295 { 01296 char *uri; 01297 char *httpVersion; 01298 char *args; 01299 01300 if (NULL == (uri = strchr (line, ' '))) 01301 return MHD_NO; /* serious error */ 01302 uri[0] = '\0'; 01303 connection->method = line; 01304 uri++; 01305 while (uri[0] == ' ') 01306 uri++; 01307 httpVersion = strchr (uri, ' '); 01308 if (httpVersion != NULL) 01309 { 01310 httpVersion[0] = '\0'; 01311 httpVersion++; 01312 } 01313 if (connection->daemon->uri_log_callback != NULL) 01314 connection->client_context 01315 = 01316 connection->daemon->uri_log_callback (connection->daemon-> 01317 uri_log_callback_cls, uri); 01318 args = strchr (uri, '?'); 01319 if (NULL != args) 01320 { 01321 args[0] = '\0'; 01322 args++; 01323 parse_arguments (MHD_GET_ARGUMENT_KIND, connection, args); 01324 } 01325 connection->daemon->unescape_callback (connection->daemon->unescape_callback_cls, 01326 connection, 01327 uri); 01328 connection->url = uri; 01329 if (NULL == httpVersion) 01330 connection->version = ""; 01331 else 01332 connection->version = httpVersion; 01333 return MHD_YES; 01334 } 01335 01336 01342 static void 01343 call_connection_handler (struct MHD_Connection *connection) 01344 { 01345 size_t processed; 01346 01347 if (NULL != connection->response) 01348 return; /* already queued a response */ 01349 processed = 0; 01350 connection->client_aware = MHD_YES; 01351 if (MHD_NO == 01352 connection->daemon->default_handler (connection->daemon-> 01353 default_handler_cls, 01354 connection, connection->url, 01355 connection->method, 01356 connection->version, 01357 NULL, &processed, 01358 &connection->client_context)) 01359 { 01360 /* serious internal error, close connection */ 01361 CONNECTION_CLOSE_ERROR (connection, 01362 "Internal application error, closing connection.\n"); 01363 return; 01364 } 01365 } 01366 01367 01368 01374 static void 01375 process_request_body (struct MHD_Connection *connection) 01376 { 01377 size_t processed; 01378 size_t available; 01379 size_t used; 01380 size_t i; 01381 int instant_retry; 01382 int malformed; 01383 char *buffer_head; 01384 char *end; 01385 01386 if (NULL != connection->response) 01387 return; /* already queued a response */ 01388 01389 buffer_head = connection->read_buffer; 01390 available = connection->read_buffer_offset; 01391 do 01392 { 01393 instant_retry = MHD_NO; 01394 if ((connection->have_chunked_upload == MHD_YES) && 01395 (connection->remaining_upload_size == MHD_SIZE_UNKNOWN)) 01396 { 01397 if ((connection->current_chunk_offset == 01398 connection->current_chunk_size) 01399 && (connection->current_chunk_offset != 0) && (available >= 2)) 01400 { 01401 /* skip new line at the *end* of a chunk */ 01402 i = 0; 01403 if ((buffer_head[i] == '\r') || (buffer_head[i] == '\n')) 01404 i++; /* skip 1st part of line feed */ 01405 if ((buffer_head[i] == '\r') || (buffer_head[i] == '\n')) 01406 i++; /* skip 2nd part of line feed */ 01407 if (i == 0) 01408 { 01409 /* malformed encoding */ 01410 CONNECTION_CLOSE_ERROR (connection, 01411 "Received malformed HTTP request (bad chunked encoding), closing connection.\n"); 01412 return; 01413 } 01414 available -= i; 01415 buffer_head += i; 01416 connection->current_chunk_offset = 0; 01417 connection->current_chunk_size = 0; 01418 } 01419 if (connection->current_chunk_offset < 01420 connection->current_chunk_size) 01421 { 01422 /* we are in the middle of a chunk, give 01423 as much as possible to the client (without 01424 crossing chunk boundaries) */ 01425 processed = 01426 connection->current_chunk_size - 01427 connection->current_chunk_offset; 01428 if (processed > available) 01429 processed = available; 01430 if (available > processed) 01431 instant_retry = MHD_YES; 01432 } 01433 else 01434 { 01435 /* we need to read chunk boundaries */ 01436 i = 0; 01437 while (i < available) 01438 { 01439 if ((buffer_head[i] == '\r') || (buffer_head[i] == '\n')) 01440 break; 01441 i++; 01442 if (i >= 6) 01443 break; 01444 } 01445 /* take '\n' into account; if '\n' 01446 is the unavailable character, we 01447 will need to wait until we have it 01448 before going further */ 01449 if ((i + 1 >= available) && 01450 !((i == 1) && (available == 2) && (buffer_head[0] == '0'))) 01451 break; /* need more data... */ 01452 malformed = (i >= 6); 01453 if (!malformed) 01454 { 01455 buffer_head[i] = '\0'; 01456 connection->current_chunk_size = strtoul (buffer_head, &end, 16); 01457 malformed = ('\0' != *end); 01458 } 01459 if (malformed) 01460 { 01461 /* malformed encoding */ 01462 CONNECTION_CLOSE_ERROR (connection, 01463 "Received malformed HTTP request (bad chunked encoding), closing connection.\n"); 01464 return; 01465 } 01466 i++; 01467 if ((i < available) && 01468 ((buffer_head[i] == '\r') || (buffer_head[i] == '\n'))) 01469 i++; /* skip 2nd part of line feed */ 01470 01471 buffer_head += i; 01472 available -= i; 01473 connection->current_chunk_offset = 0; 01474 01475 if (available > 0) 01476 instant_retry = MHD_YES; 01477 if (connection->current_chunk_size == 0) 01478 { 01479 connection->remaining_upload_size = 0; 01480 break; 01481 } 01482 continue; 01483 } 01484 } 01485 else 01486 { 01487 /* no chunked encoding, give all to the client */ 01488 if ( (0 != connection->remaining_upload_size) && 01489 (MHD_SIZE_UNKNOWN != connection->remaining_upload_size) && 01490 (connection->remaining_upload_size < available) ) 01491 { 01492 processed = connection->remaining_upload_size; 01493 } 01494 else 01495 { 01500 processed = available; 01501 } 01502 } 01503 used = processed; 01504 connection->client_aware = MHD_YES; 01505 if (MHD_NO == 01506 connection->daemon->default_handler (connection->daemon-> 01507 default_handler_cls, 01508 connection, connection->url, 01509 connection->method, 01510 connection->version, 01511 buffer_head, &processed, 01512 &connection->client_context)) 01513 { 01514 /* serious internal error, close connection */ 01515 CONNECTION_CLOSE_ERROR (connection, 01516 "Internal application error, closing connection.\n"); 01517 return; 01518 } 01519 if (processed > used) 01520 mhd_panic (mhd_panic_cls, __FILE__, __LINE__, 01521 #if HAVE_MESSAGES 01522 "API violation" 01523 #else 01524 NULL 01525 #endif 01526 ); 01527 if (processed != 0) 01528 instant_retry = MHD_NO; /* client did not process everything */ 01529 used -= processed; 01530 if (connection->have_chunked_upload == MHD_YES) 01531 connection->current_chunk_offset += used; 01532 /* dh left "processed" bytes in buffer for next time... */ 01533 buffer_head += used; 01534 available -= used; 01535 if (connection->remaining_upload_size != MHD_SIZE_UNKNOWN) 01536 connection->remaining_upload_size -= used; 01537 } 01538 while (MHD_YES == instant_retry); 01539 if (available > 0) 01540 memmove (connection->read_buffer, buffer_head, available); 01541 connection->read_buffer_offset = available; 01542 } 01543 01552 static int 01553 do_read (struct MHD_Connection *connection) 01554 { 01555 int bytes_read; 01556 01557 if (connection->read_buffer_size == connection->read_buffer_offset) 01558 return MHD_NO; 01559 01560 bytes_read = connection->recv_cls (connection, 01561 &connection->read_buffer 01562 [connection->read_buffer_offset], 01563 connection->read_buffer_size - 01564 connection->read_buffer_offset); 01565 if (bytes_read < 0) 01566 { 01567 if ((EINTR == errno) || (EAGAIN == errno)) 01568 return MHD_NO; 01569 #if HAVE_MESSAGES 01570 #if HTTPS_SUPPORT 01571 if (0 != (connection->daemon->options & MHD_USE_SSL)) 01572 MHD_DLOG (connection->daemon, 01573 "Failed to receive data: %s\n", 01574 gnutls_strerror (bytes_read)); 01575 else 01576 #endif 01577 MHD_DLOG (connection->daemon, 01578 "Failed to receive data: %s\n", STRERROR (errno)); 01579 #endif 01580 CONNECTION_CLOSE_ERROR (connection, NULL); 01581 return MHD_YES; 01582 } 01583 if (0 == bytes_read) 01584 { 01585 /* other side closed connection */ 01586 connection->read_closed = MHD_YES; 01587 SHUTDOWN (connection->socket_fd, SHUT_RD); 01588 return MHD_YES; 01589 } 01590 connection->read_buffer_offset += bytes_read; 01591 return MHD_YES; 01592 } 01593 01601 static int 01602 do_write (struct MHD_Connection *connection) 01603 { 01604 int ret; 01605 01606 ret = connection->send_cls (connection, 01607 &connection->write_buffer 01608 [connection->write_buffer_send_offset], 01609 connection->write_buffer_append_offset 01610 - connection->write_buffer_send_offset); 01611 01612 if (ret < 0) 01613 { 01614 if ((EINTR == errno) || (EAGAIN == errno)) 01615 return MHD_NO; 01616 #if HAVE_MESSAGES 01617 #if HTTPS_SUPPORT 01618 if (0 != (connection->daemon->options & MHD_USE_SSL)) 01619 MHD_DLOG (connection->daemon, 01620 "Failed to send data: %s\n", 01621 gnutls_strerror (ret)); 01622 else 01623 #endif 01624 MHD_DLOG (connection->daemon, 01625 "Failed to send data: %s\n", STRERROR (errno)); 01626 #endif 01627 CONNECTION_CLOSE_ERROR (connection, NULL); 01628 return MHD_YES; 01629 } 01630 #if DEBUG_SEND_DATA 01631 FPRINTF (stderr, 01632 "Sent response: `%.*s'\n", 01633 ret, 01634 &connection->write_buffer[connection->write_buffer_send_offset]); 01635 #endif 01636 connection->write_buffer_send_offset += ret; 01637 return MHD_YES; 01638 } 01639 01645 static int 01646 check_write_done (struct MHD_Connection *connection, 01647 enum MHD_CONNECTION_STATE next_state) 01648 { 01649 if (connection->write_buffer_append_offset != 01650 connection->write_buffer_send_offset) 01651 return MHD_NO; 01652 connection->write_buffer_append_offset = 0; 01653 connection->write_buffer_send_offset = 0; 01654 connection->state = next_state; 01655 MHD_pool_reallocate (connection->pool, connection->write_buffer, 01656 connection->write_buffer_size, 0); 01657 connection->write_buffer = NULL; 01658 connection->write_buffer_size = 0; 01659 return MHD_YES; 01660 } 01661 01667 static int 01668 process_header_line (struct MHD_Connection *connection, char *line) 01669 { 01670 char *colon; 01671 01672 /* line should be normal header line, find colon */ 01673 colon = strchr (line, ':'); 01674 if (colon == NULL) 01675 { 01676 /* error in header line, die hard */ 01677 CONNECTION_CLOSE_ERROR (connection, 01678 "Received malformed line (no colon), closing connection.\n"); 01679 return MHD_NO; 01680 } 01681 /* zero-terminate header */ 01682 colon[0] = '\0'; 01683 colon++; /* advance to value */ 01684 while ((colon[0] != '\0') && ((colon[0] == ' ') || (colon[0] == '\t'))) 01685 colon++; 01686 /* we do the actual adding of the connection 01687 header at the beginning of the while 01688 loop since we need to be able to inspect 01689 the *next* header line (in case it starts 01690 with a space...) */ 01691 connection->last = line; 01692 connection->colon = colon; 01693 return MHD_YES; 01694 } 01695 01696 01706 static int 01707 process_broken_line (struct MHD_Connection *connection, 01708 char *line, enum MHD_ValueKind kind) 01709 { 01710 char *last; 01711 char *tmp; 01712 size_t last_len; 01713 size_t tmp_len; 01714 01715 last = connection->last; 01716 if ((line[0] == ' ') || (line[0] == '\t')) 01717 { 01718 /* value was continued on the next line, see 01719 http://www.jmarshall.com/easy/http/ */ 01720 last_len = strlen (last); 01721 /* skip whitespace at start of 2nd line */ 01722 tmp = line; 01723 while ((tmp[0] == ' ') || (tmp[0] == '\t')) 01724 tmp++; 01725 tmp_len = strlen (tmp); 01726 last = MHD_pool_reallocate (connection->pool, 01727 last, 01728 last_len + 1, 01729 last_len + tmp_len + 1); 01730 if (last == NULL) 01731 { 01732 transmit_error_response (connection, 01733 MHD_HTTP_REQUEST_ENTITY_TOO_LARGE, 01734 REQUEST_TOO_BIG); 01735 return MHD_NO; 01736 } 01737 memcpy (&last[last_len], tmp, tmp_len + 1); 01738 connection->last = last; 01739 return MHD_YES; /* possibly more than 2 lines... */ 01740 } 01741 EXTRA_CHECK ((last != NULL) && (connection->colon != NULL)); 01742 if ((MHD_NO == connection_add_header (connection, 01743 last, connection->colon, kind))) 01744 { 01745 transmit_error_response (connection, MHD_HTTP_REQUEST_ENTITY_TOO_LARGE, 01746 REQUEST_TOO_BIG); 01747 return MHD_NO; 01748 } 01749 /* we still have the current line to deal with... */ 01750 if (strlen (line) != 0) 01751 { 01752 if (MHD_NO == process_header_line (connection, line)) 01753 { 01754 transmit_error_response (connection, 01755 MHD_HTTP_BAD_REQUEST, REQUEST_MALFORMED); 01756 return MHD_NO; 01757 } 01758 } 01759 return MHD_YES; 01760 } 01761 01762 01768 static void 01769 parse_connection_headers (struct MHD_Connection *connection) 01770 { 01771 const char *clen; 01772 unsigned MHD_LONG_LONG cval; 01773 struct MHD_Response *response; 01774 const char *enc; 01775 char *end; 01776 01777 parse_cookie_header (connection); 01778 if ((0 != (MHD_USE_PEDANTIC_CHECKS & connection->daemon->options)) 01779 && (NULL != connection->version) 01780 && (0 == strcasecmp (MHD_HTTP_VERSION_1_1, connection->version)) 01781 && (NULL == 01782 MHD_lookup_connection_value (connection, MHD_HEADER_KIND, 01783 MHD_HTTP_HEADER_HOST))) 01784 { 01785 /* die, http 1.1 request without host and we are pedantic */ 01786 connection->state = MHD_CONNECTION_FOOTERS_RECEIVED; 01787 connection->read_closed = MHD_YES; 01788 #if HAVE_MESSAGES 01789 MHD_DLOG (connection->daemon, 01790 "Received `%s' request without `%s' header.\n", 01791 MHD_HTTP_VERSION_1_1, MHD_HTTP_HEADER_HOST); 01792 #endif 01793 EXTRA_CHECK (connection->response == NULL); 01794 response = 01795 MHD_create_response_from_buffer (strlen (REQUEST_LACKS_HOST), 01796 REQUEST_LACKS_HOST, 01797 MHD_RESPMEM_PERSISTENT); 01798 MHD_queue_response (connection, MHD_HTTP_BAD_REQUEST, response); 01799 MHD_destroy_response (response); 01800 return; 01801 } 01802 01803 clen = MHD_lookup_connection_value (connection, 01804 MHD_HEADER_KIND, 01805 MHD_HTTP_HEADER_CONTENT_LENGTH); 01806 if (clen != NULL) 01807 { 01808 cval = strtoul (clen, &end, 10); 01809 if ( ('\0' != *end) || 01810 ( (LONG_MAX == cval) && (errno == ERANGE) ) ) 01811 { 01812 #if HAVE_MESSAGES 01813 MHD_DLOG (connection->daemon, 01814 "Failed to parse `%s' header `%s', closing connection.\n", 01815 MHD_HTTP_HEADER_CONTENT_LENGTH, clen); 01816 #endif 01817 CONNECTION_CLOSE_ERROR (connection, NULL); 01818 return; 01819 } 01820 connection->remaining_upload_size = cval; 01821 } 01822 else 01823 { 01824 enc = MHD_lookup_connection_value (connection, 01825 MHD_HEADER_KIND, 01826 MHD_HTTP_HEADER_TRANSFER_ENCODING); 01827 if (NULL == enc) 01828 { 01829 /* this request (better) not have a body */ 01830 connection->remaining_upload_size = 0; 01831 } 01832 else 01833 { 01834 connection->remaining_upload_size = MHD_SIZE_UNKNOWN; 01835 if (0 == strcasecmp (enc, "chunked")) 01836 connection->have_chunked_upload = MHD_YES; 01837 } 01838 } 01839 } 01840 01841 01852 int 01853 MHD_connection_handle_read (struct MHD_Connection *connection) 01854 { 01855 connection->last_activity = MHD_monotonic_time(); 01856 if (connection->state == MHD_CONNECTION_CLOSED) 01857 return MHD_YES; 01858 /* make sure "read" has a reasonable number of bytes 01859 in buffer to use per system call (if possible) */ 01860 if (connection->read_buffer_offset + MHD_BUF_INC_SIZE > 01861 connection->read_buffer_size) 01862 try_grow_read_buffer (connection); 01863 if (MHD_NO == do_read (connection)) 01864 return MHD_YES; 01865 while (1) 01866 { 01867 #if DEBUG_STATES 01868 MHD_DLOG (connection->daemon, "%s: state: %s\n", 01869 __FUNCTION__, MHD_state_to_string (connection->state)); 01870 #endif 01871 switch (connection->state) 01872 { 01873 case MHD_CONNECTION_INIT: 01874 case MHD_CONNECTION_URL_RECEIVED: 01875 case MHD_CONNECTION_HEADER_PART_RECEIVED: 01876 case MHD_CONNECTION_HEADERS_RECEIVED: 01877 case MHD_CONNECTION_HEADERS_PROCESSED: 01878 case MHD_CONNECTION_CONTINUE_SENDING: 01879 case MHD_CONNECTION_CONTINUE_SENT: 01880 case MHD_CONNECTION_BODY_RECEIVED: 01881 case MHD_CONNECTION_FOOTER_PART_RECEIVED: 01882 /* nothing to do but default action */ 01883 if (MHD_YES == connection->read_closed) 01884 { 01885 MHD_connection_close (connection, 01886 MHD_REQUEST_TERMINATED_READ_ERROR); 01887 continue; 01888 } 01889 break; 01890 case MHD_CONNECTION_CLOSED: 01891 return MHD_YES; 01892 default: 01893 /* shrink read buffer to how much is actually used */ 01894 MHD_pool_reallocate (connection->pool, 01895 connection->read_buffer, 01896 connection->read_buffer_size + 1, 01897 connection->read_buffer_offset); 01898 break; 01899 } 01900 break; 01901 } 01902 return MHD_YES; 01903 } 01904 01905 01916 int 01917 MHD_connection_handle_write (struct MHD_Connection *connection) 01918 { 01919 struct MHD_Response *response; 01920 int ret; 01921 connection->last_activity = MHD_monotonic_time(); 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 (response->crc != NULL) 01982 pthread_mutex_lock (&response->mutex); 01983 if (MHD_YES != try_ready_normal_body (connection)) 01984 { 01985 if (response->crc != NULL) 01986 pthread_mutex_unlock (&response->mutex); 01987 break; 01988 } 01989 ret = connection->send_cls (connection, 01990 &response->data 01991 [connection->response_write_position 01992 - response->data_start], 01993 response->data_size - 01994 (connection->response_write_position 01995 - response->data_start)); 01996 #if DEBUG_SEND_DATA 01997 if (ret > 0) 01998 FPRINTF (stderr, 01999 "Sent DATA response: `%.*s'\n", 02000 ret, 02001 &response->data[connection->response_write_position - 02002 response->data_start]); 02003 #endif 02004 if (response->crc != NULL) 02005 pthread_mutex_unlock (&response->mutex); 02006 if (ret < 0) 02007 { 02008 if ((errno == EINTR) || (errno == EAGAIN)) 02009 return MHD_YES; 02010 #if HAVE_MESSAGES 02011 MHD_DLOG (connection->daemon, 02012 "Failed to send data: %s\n", STRERROR (errno)); 02013 #endif 02014 CONNECTION_CLOSE_ERROR (connection, NULL); 02015 return MHD_YES; 02016 } 02017 connection->response_write_position += ret; 02018 if (connection->response_write_position == 02019 connection->response->total_size) 02020 connection->state = MHD_CONNECTION_FOOTERS_SENT; /* have no footers... */ 02021 break; 02022 case MHD_CONNECTION_NORMAL_BODY_UNREADY: 02023 EXTRA_CHECK (0); 02024 break; 02025 case MHD_CONNECTION_CHUNKED_BODY_READY: 02026 do_write (connection); 02027 if (connection->state != MHD_CONNECTION_CHUNKED_BODY_READY) 02028 break; 02029 check_write_done (connection, 02030 (connection->response->total_size == 02031 connection->response_write_position) ? 02032 MHD_CONNECTION_BODY_SENT : 02033 MHD_CONNECTION_CHUNKED_BODY_UNREADY); 02034 break; 02035 case MHD_CONNECTION_CHUNKED_BODY_UNREADY: 02036 case MHD_CONNECTION_BODY_SENT: 02037 EXTRA_CHECK (0); 02038 break; 02039 case MHD_CONNECTION_FOOTERS_SENDING: 02040 do_write (connection); 02041 if (connection->state != MHD_CONNECTION_FOOTERS_SENDING) 02042 break; 02043 check_write_done (connection, MHD_CONNECTION_FOOTERS_SENT); 02044 break; 02045 case MHD_CONNECTION_FOOTERS_SENT: 02046 EXTRA_CHECK (0); 02047 break; 02048 case MHD_CONNECTION_CLOSED: 02049 return MHD_YES; 02050 case MHD_TLS_CONNECTION_INIT: 02051 EXTRA_CHECK (0); 02052 break; 02053 default: 02054 EXTRA_CHECK (0); 02055 CONNECTION_CLOSE_ERROR (connection, "Internal error\n"); 02056 return MHD_YES; 02057 } 02058 break; 02059 } 02060 return MHD_YES; 02061 } 02062 02063 02074 int 02075 MHD_connection_handle_idle (struct MHD_Connection *connection) 02076 { 02077 struct MHD_Daemon *daemon; 02078 unsigned int timeout; 02079 const char *end; 02080 int rend; 02081 char *line; 02082 02083 while (1) 02084 { 02085 #if DEBUG_STATES 02086 MHD_DLOG (connection->daemon, "%s: state: %s\n", 02087 __FUNCTION__, MHD_state_to_string (connection->state)); 02088 #endif 02089 switch (connection->state) 02090 { 02091 case MHD_CONNECTION_INIT: 02092 line = get_next_header_line (connection); 02093 if (line == NULL) 02094 { 02095 if (connection->state != MHD_CONNECTION_INIT) 02096 continue; 02097 if (connection->read_closed) 02098 { 02099 CONNECTION_CLOSE_ERROR (connection, 02100 NULL); 02101 continue; 02102 } 02103 break; 02104 } 02105 if (MHD_NO == parse_initial_message_line (connection, line)) 02106 CONNECTION_CLOSE_ERROR (connection, NULL); 02107 else 02108 connection->state = MHD_CONNECTION_URL_RECEIVED; 02109 continue; 02110 case MHD_CONNECTION_URL_RECEIVED: 02111 line = get_next_header_line (connection); 02112 if (line == NULL) 02113 { 02114 if (connection->state != MHD_CONNECTION_URL_RECEIVED) 02115 continue; 02116 if (connection->read_closed) 02117 { 02118 CONNECTION_CLOSE_ERROR (connection, 02119 NULL); 02120 continue; 02121 } 02122 break; 02123 } 02124 if (strlen (line) == 0) 02125 { 02126 connection->state = MHD_CONNECTION_HEADERS_RECEIVED; 02127 continue; 02128 } 02129 if (MHD_NO == process_header_line (connection, line)) 02130 { 02131 transmit_error_response (connection, 02132 MHD_HTTP_BAD_REQUEST, 02133 REQUEST_MALFORMED); 02134 break; 02135 } 02136 connection->state = MHD_CONNECTION_HEADER_PART_RECEIVED; 02137 continue; 02138 case MHD_CONNECTION_HEADER_PART_RECEIVED: 02139 line = get_next_header_line (connection); 02140 if (line == NULL) 02141 { 02142 if (connection->state != MHD_CONNECTION_HEADER_PART_RECEIVED) 02143 continue; 02144 if (connection->read_closed) 02145 { 02146 CONNECTION_CLOSE_ERROR (connection, 02147 NULL); 02148 continue; 02149 } 02150 break; 02151 } 02152 if (MHD_NO == 02153 process_broken_line (connection, line, MHD_HEADER_KIND)) 02154 continue; 02155 if (strlen (line) == 0) 02156 { 02157 connection->state = MHD_CONNECTION_HEADERS_RECEIVED; 02158 continue; 02159 } 02160 continue; 02161 case MHD_CONNECTION_HEADERS_RECEIVED: 02162 parse_connection_headers (connection); 02163 if (connection->state == MHD_CONNECTION_CLOSED) 02164 continue; 02165 connection->state = MHD_CONNECTION_HEADERS_PROCESSED; 02166 continue; 02167 case MHD_CONNECTION_HEADERS_PROCESSED: 02168 call_connection_handler (connection); /* first call */ 02169 if (connection->state == MHD_CONNECTION_CLOSED) 02170 continue; 02171 if (need_100_continue (connection)) 02172 { 02173 connection->state = MHD_CONNECTION_CONTINUE_SENDING; 02174 break; 02175 } 02176 if (connection->response != NULL) 02177 { 02178 /* we refused (no upload allowed!) */ 02179 connection->remaining_upload_size = 0; 02180 /* force close, in case client still tries to upload... */ 02181 connection->read_closed = MHD_YES; 02182 } 02183 connection->state = (connection->remaining_upload_size == 0) 02184 ? MHD_CONNECTION_FOOTERS_RECEIVED : MHD_CONNECTION_CONTINUE_SENT; 02185 continue; 02186 case MHD_CONNECTION_CONTINUE_SENDING: 02187 if (connection->continue_message_write_offset == 02188 strlen (HTTP_100_CONTINUE)) 02189 { 02190 connection->state = MHD_CONNECTION_CONTINUE_SENT; 02191 continue; 02192 } 02193 break; 02194 case MHD_CONNECTION_CONTINUE_SENT: 02195 if (connection->read_buffer_offset != 0) 02196 { 02197 process_request_body (connection); /* loop call */ 02198 if (connection->state == MHD_CONNECTION_CLOSED) 02199 continue; 02200 } 02201 if ((connection->remaining_upload_size == 0) || 02202 ((connection->remaining_upload_size == MHD_SIZE_UNKNOWN) && 02203 (connection->read_buffer_offset == 0) && 02204 (MHD_YES == connection->read_closed))) 02205 { 02206 if ((MHD_YES == connection->have_chunked_upload) && 02207 (MHD_NO == connection->read_closed)) 02208 connection->state = MHD_CONNECTION_BODY_RECEIVED; 02209 else 02210 connection->state = MHD_CONNECTION_FOOTERS_RECEIVED; 02211 continue; 02212 } 02213 break; 02214 case MHD_CONNECTION_BODY_RECEIVED: 02215 line = get_next_header_line (connection); 02216 if (line == NULL) 02217 { 02218 if (connection->state != MHD_CONNECTION_BODY_RECEIVED) 02219 continue; 02220 if (connection->read_closed) 02221 { 02222 CONNECTION_CLOSE_ERROR (connection, 02223 NULL); 02224 continue; 02225 } 02226 break; 02227 } 02228 if (strlen (line) == 0) 02229 { 02230 connection->state = MHD_CONNECTION_FOOTERS_RECEIVED; 02231 continue; 02232 } 02233 if (MHD_NO == process_header_line (connection, line)) 02234 { 02235 transmit_error_response (connection, 02236 MHD_HTTP_BAD_REQUEST, 02237 REQUEST_MALFORMED); 02238 break; 02239 } 02240 connection->state = MHD_CONNECTION_FOOTER_PART_RECEIVED; 02241 continue; 02242 case MHD_CONNECTION_FOOTER_PART_RECEIVED: 02243 line = get_next_header_line (connection); 02244 if (line == NULL) 02245 { 02246 if (connection->state != MHD_CONNECTION_FOOTER_PART_RECEIVED) 02247 continue; 02248 if (connection->read_closed) 02249 { 02250 CONNECTION_CLOSE_ERROR (connection, 02251 NULL); 02252 continue; 02253 } 02254 break; 02255 } 02256 if (MHD_NO == 02257 process_broken_line (connection, line, MHD_FOOTER_KIND)) 02258 continue; 02259 if (strlen (line) == 0) 02260 { 02261 connection->state = MHD_CONNECTION_FOOTERS_RECEIVED; 02262 continue; 02263 } 02264 continue; 02265 case MHD_CONNECTION_FOOTERS_RECEIVED: 02266 call_connection_handler (connection); /* "final" call */ 02267 if (connection->state == MHD_CONNECTION_CLOSED) 02268 continue; 02269 if (connection->response == NULL) 02270 break; /* try again next time */ 02271 if (MHD_NO == build_header_response (connection)) 02272 { 02273 /* oops - close! */ 02274 CONNECTION_CLOSE_ERROR (connection, 02275 "Closing connection (failed to create response header)\n"); 02276 continue; 02277 } 02278 connection->state = MHD_CONNECTION_HEADERS_SENDING; 02279 02280 #if HAVE_DECL_TCP_CORK 02281 /* starting header send, set TCP cork */ 02282 { 02283 const int val = 1; 02284 setsockopt (connection->socket_fd, IPPROTO_TCP, TCP_CORK, &val, 02285 sizeof (val)); 02286 } 02287 #endif 02288 break; 02289 case MHD_CONNECTION_HEADERS_SENDING: 02290 /* no default action */ 02291 break; 02292 case MHD_CONNECTION_HEADERS_SENT: 02293 if (connection->have_chunked_upload) 02294 connection->state = MHD_CONNECTION_CHUNKED_BODY_UNREADY; 02295 else 02296 connection->state = MHD_CONNECTION_NORMAL_BODY_UNREADY; 02297 continue; 02298 case MHD_CONNECTION_NORMAL_BODY_READY: 02299 /* nothing to do here */ 02300 break; 02301 case MHD_CONNECTION_NORMAL_BODY_UNREADY: 02302 if (connection->response->crc != NULL) 02303 pthread_mutex_lock (&connection->response->mutex); 02304 if (MHD_YES == try_ready_normal_body (connection)) 02305 { 02306 if (connection->response->crc != NULL) 02307 pthread_mutex_unlock (&connection->response->mutex); 02308 connection->state = MHD_CONNECTION_NORMAL_BODY_READY; 02309 break; 02310 } 02311 if (connection->response->crc != NULL) 02312 pthread_mutex_unlock (&connection->response->mutex); 02313 /* not ready, no socket action */ 02314 break; 02315 case MHD_CONNECTION_CHUNKED_BODY_READY: 02316 /* nothing to do here */ 02317 break; 02318 case MHD_CONNECTION_CHUNKED_BODY_UNREADY: 02319 if (connection->response->crc != NULL) 02320 pthread_mutex_lock (&connection->response->mutex); 02321 if (MHD_YES == try_ready_chunked_body (connection)) 02322 { 02323 if (connection->response->crc != NULL) 02324 pthread_mutex_unlock (&connection->response->mutex); 02325 connection->state = MHD_CONNECTION_CHUNKED_BODY_READY; 02326 continue; 02327 } 02328 if (connection->response->crc != NULL) 02329 pthread_mutex_unlock (&connection->response->mutex); 02330 break; 02331 case MHD_CONNECTION_BODY_SENT: 02332 build_header_response (connection); 02333 if (connection->write_buffer_send_offset == 02334 connection->write_buffer_append_offset) 02335 connection->state = MHD_CONNECTION_FOOTERS_SENT; 02336 else 02337 connection->state = MHD_CONNECTION_FOOTERS_SENDING; 02338 continue; 02339 case MHD_CONNECTION_FOOTERS_SENDING: 02340 /* no default action */ 02341 break; 02342 case MHD_CONNECTION_FOOTERS_SENT: 02343 #if HAVE_DECL_TCP_CORK 02344 /* done sending, uncork */ 02345 { 02346 const int val = 0; 02347 setsockopt (connection->socket_fd, IPPROTO_TCP, TCP_CORK, &val, 02348 sizeof (val)); 02349 } 02350 #endif 02351 end = 02352 MHD_get_response_header (connection->response, 02353 MHD_HTTP_HEADER_CONNECTION); 02354 rend = ( (end != NULL) && (0 == strcasecmp (end, "close")) ); 02355 MHD_destroy_response (connection->response); 02356 connection->response = NULL; 02357 if (connection->daemon->notify_completed != NULL) 02358 connection->daemon->notify_completed (connection->daemon-> 02359 notify_completed_cls, 02360 connection, 02361 &connection->client_context, 02362 MHD_REQUEST_TERMINATED_COMPLETED_OK); 02363 connection->client_aware = MHD_NO; 02364 end = 02365 MHD_lookup_connection_value (connection, MHD_HEADER_KIND, 02366 MHD_HTTP_HEADER_CONNECTION); 02367 connection->client_context = NULL; 02368 connection->continue_message_write_offset = 0; 02369 connection->responseCode = 0; 02370 connection->headers_received = NULL; 02371 connection->headers_received_tail = NULL; 02372 connection->response_write_position = 0; 02373 connection->have_chunked_upload = MHD_NO; 02374 connection->method = NULL; 02375 connection->url = NULL; 02376 connection->write_buffer = NULL; 02377 connection->write_buffer_size = 0; 02378 connection->write_buffer_send_offset = 0; 02379 connection->write_buffer_append_offset = 0; 02380 if ( (rend) || ((end != NULL) && (0 == strcasecmp (end, "close"))) ) 02381 { 02382 connection->read_closed = MHD_YES; 02383 connection->read_buffer_offset = 0; 02384 } 02385 if (((MHD_YES == connection->read_closed) && 02386 (0 == connection->read_buffer_offset)) || 02387 (connection->version == NULL) || 02388 (0 != strcasecmp (MHD_HTTP_VERSION_1_1, connection->version))) 02389 { 02390 /* http 1.0, version-less requests cannot be pipelined */ 02391 MHD_connection_close (connection, MHD_REQUEST_TERMINATED_COMPLETED_OK); 02392 MHD_pool_destroy (connection->pool); 02393 connection->pool = NULL; 02394 connection->read_buffer = NULL; 02395 connection->read_buffer_size = 0; 02396 connection->read_buffer_offset = 0; 02397 } 02398 else 02399 { 02400 connection->version = NULL; 02401 connection->state = MHD_CONNECTION_INIT; 02402 connection->read_buffer 02403 = MHD_pool_reset (connection->pool, 02404 connection->read_buffer, 02405 connection->read_buffer_size); 02406 } 02407 continue; 02408 case MHD_CONNECTION_CLOSED: 02409 if (connection->response != NULL) 02410 { 02411 MHD_destroy_response (connection->response); 02412 connection->response = NULL; 02413 } 02414 daemon = connection->daemon; 02415 if (0 != pthread_mutex_lock(&daemon->cleanup_connection_mutex)) 02416 { 02417 MHD_PANIC ("Failed to acquire cleanup mutex\n"); 02418 } 02419 DLL_remove (daemon->connections_head, 02420 daemon->connections_tail, 02421 connection); 02422 DLL_insert (daemon->cleanup_head, 02423 daemon->cleanup_tail, 02424 connection); 02425 if (0 != pthread_mutex_unlock(&daemon->cleanup_connection_mutex)) 02426 { 02427 MHD_PANIC ("Failed to release cleanup mutex\n"); 02428 } 02429 return MHD_NO; 02430 default: 02431 EXTRA_CHECK (0); 02432 break; 02433 } 02434 break; 02435 } 02436 timeout = connection->connection_timeout; 02437 if ( (timeout != 0) && 02438 (timeout <= (MHD_monotonic_time() - connection->last_activity)) ) 02439 { 02440 MHD_connection_close (connection, MHD_REQUEST_TERMINATED_TIMEOUT_REACHED); 02441 return MHD_YES; 02442 } 02443 return MHD_YES; 02444 } 02445 02446 02452 void 02453 MHD_set_http_callbacks_ (struct MHD_Connection *connection) 02454 { 02455 connection->read_handler = &MHD_connection_handle_read; 02456 connection->write_handler = &MHD_connection_handle_write; 02457 connection->idle_handler = &MHD_connection_handle_idle; 02458 } 02459 02460 02470 const union MHD_ConnectionInfo * 02471 MHD_get_connection_info (struct MHD_Connection *connection, 02472 enum MHD_ConnectionInfoType infoType, ...) 02473 { 02474 switch (infoType) 02475 { 02476 #if HTTPS_SUPPORT 02477 case MHD_CONNECTION_INFO_CIPHER_ALGO: 02478 if (connection->tls_session == NULL) 02479 return NULL; 02480 connection->cipher = gnutls_cipher_get (connection->tls_session); 02481 return (const union MHD_ConnectionInfo *) &connection->cipher; 02482 case MHD_CONNECTION_INFO_PROTOCOL: 02483 if (connection->tls_session == NULL) 02484 return NULL; 02485 connection->protocol = gnutls_protocol_get_version (connection->tls_session); 02486 return (const union MHD_ConnectionInfo *) &connection->protocol; 02487 case MHD_CONNECTION_INFO_GNUTLS_SESSION: 02488 if (connection->tls_session == NULL) 02489 return NULL; 02490 return (const union MHD_ConnectionInfo *) &connection->tls_session; 02491 #endif 02492 case MHD_CONNECTION_INFO_CLIENT_ADDRESS: 02493 return (const union MHD_ConnectionInfo *) &connection->addr; 02494 case MHD_CONNECTION_INFO_DAEMON: 02495 return (const union MHD_ConnectionInfo *) &connection->daemon; 02496 default: 02497 return NULL; 02498 }; 02499 } 02500 02501 02510 int 02511 MHD_set_connection_option (struct MHD_Connection *connection, 02512 enum MHD_CONNECTION_OPTION option, 02513 ...) 02514 { 02515 va_list ap; 02516 02517 switch (option) 02518 { 02519 case MHD_CONNECTION_OPTION_TIMEOUT: 02520 va_start (ap, option); 02521 connection->connection_timeout = va_arg (ap, unsigned int); 02522 va_end (ap); 02523 return MHD_YES; 02524 default: 02525 return MHD_NO; 02526 } 02527 } 02528 02529 02530 /* end of connection.c */