GNU libmicrohttpd
0.9.5
|
00001 /* 00002 This file is part of libmicrohttpd 00003 (C) 2007, 2008, 2009, 2010 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 "connection.h" 00030 #include "memorypool.h" 00031 #include "response.h" 00032 #include "reason_phrase.h" 00033 00034 #if HAVE_NETINET_TCP_H 00035 /* for TCP_CORK */ 00036 #include <netinet/tcp.h> 00037 #endif 00038 00042 #define HTTP_100_CONTINUE "HTTP/1.1 100 Continue\r\n\r\n" 00043 00051 #if HAVE_MESSAGES 00052 #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>" 00053 #else 00054 #define REQUEST_TOO_BIG "" 00055 #endif 00056 00064 #if HAVE_MESSAGES 00065 #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>" 00066 #else 00067 #define REQUEST_LACKS_HOST "" 00068 #endif 00069 00077 #if HAVE_MESSAGES 00078 #define REQUEST_MALFORMED "<html><head><title>Request malformed</title></head><body>Your HTTP request was syntactically incorrect.</body></html>" 00079 #else 00080 #define REQUEST_MALFORMED "" 00081 #endif 00082 00089 #if HAVE_MESSAGES 00090 #define INTERNAL_ERROR "<html><head><title>Internal server error</title></head><body>Some programmer needs to study the manual more carefully.</body></html>" 00091 #else 00092 #define INTERNAL_ERROR "" 00093 #endif 00094 00099 #define DEBUG_CLOSE MHD_NO 00100 00104 #define DEBUG_SEND_DATA MHD_NO 00105 00114 int 00115 MHD_get_connection_values (struct MHD_Connection *connection, 00116 enum MHD_ValueKind kind, 00117 MHD_KeyValueIterator iterator, void *iterator_cls) 00118 { 00119 int ret; 00120 struct MHD_HTTP_Header *pos; 00121 00122 if (connection == NULL) 00123 return -1; 00124 ret = 0; 00125 pos = connection->headers_received; 00126 while (pos != NULL) 00127 { 00128 if (0 != (pos->kind & kind)) 00129 { 00130 ret++; 00131 if ((iterator != NULL) && 00132 (MHD_YES != iterator (iterator_cls, 00133 kind, pos->header, pos->value))) 00134 return ret; 00135 } 00136 pos = pos->next; 00137 } 00138 return ret; 00139 } 00140 00170 int 00171 MHD_set_connection_value (struct MHD_Connection *connection, 00172 enum MHD_ValueKind kind, 00173 const char *key, const char *value) 00174 { 00175 struct MHD_HTTP_Header *pos; 00176 00177 pos = MHD_pool_allocate (connection->pool, 00178 sizeof (struct MHD_HTTP_Header), MHD_NO); 00179 if (pos == NULL) 00180 return MHD_NO; 00181 pos->header = (char *) key; 00182 pos->value = (char *) value; 00183 pos->kind = kind; 00184 pos->next = connection->headers_received; 00185 connection->headers_received = pos; 00186 return MHD_YES; 00187 } 00188 00196 const char * 00197 MHD_lookup_connection_value (struct MHD_Connection *connection, 00198 enum MHD_ValueKind kind, const char *key) 00199 { 00200 struct MHD_HTTP_Header *pos; 00201 00202 if (connection == NULL) 00203 return NULL; 00204 pos = connection->headers_received; 00205 while (pos != NULL) 00206 { 00207 if ((0 != (pos->kind & kind)) && (0 == strcasecmp (key, pos->header))) 00208 return pos->value; 00209 pos = pos->next; 00210 } 00211 return NULL; 00212 } 00213 00224 int 00225 MHD_queue_response (struct MHD_Connection *connection, 00226 unsigned int status_code, struct MHD_Response *response) 00227 { 00228 if ((connection == NULL) || 00229 (response == NULL) || 00230 (connection->response != NULL) || 00231 ((connection->state != MHD_CONNECTION_HEADERS_PROCESSED) && 00232 (connection->state != MHD_CONNECTION_FOOTERS_RECEIVED))) 00233 return MHD_NO; 00234 MHD_increment_response_rc (response); 00235 connection->response = response; 00236 connection->responseCode = status_code; 00237 if ((connection->method != NULL) && 00238 (0 == strcasecmp (connection->method, MHD_HTTP_METHOD_HEAD))) 00239 { 00240 /* if this is a "HEAD" request, pretend that we 00241 have already sent the full message body */ 00242 connection->response_write_position = response->total_size; 00243 } 00244 if ((response->total_size == MHD_SIZE_UNKNOWN) && 00245 (0 == strcasecmp (connection->version, MHD_HTTP_VERSION_1_1))) 00246 connection->have_chunked_response = MHD_YES; 00247 else 00248 connection->have_chunked_response = MHD_NO; 00249 if (connection->state == MHD_CONNECTION_HEADERS_PROCESSED) 00250 { 00251 /* response was queued "early", 00252 refuse to read body / footers or further 00253 requests! */ 00254 SHUTDOWN (connection->socket_fd, SHUT_RD); 00255 connection->read_closed = MHD_YES; 00256 connection->state = MHD_CONNECTION_FOOTERS_RECEIVED; 00257 } 00258 return MHD_YES; 00259 } 00260 00265 static int 00266 need_100_continue (struct MHD_Connection *connection) 00267 { 00268 const char *expect; 00269 00270 return ((connection->response == NULL) && 00271 (connection->version != NULL) && 00272 (0 == strcasecmp (connection->version, 00273 MHD_HTTP_VERSION_1_1)) && 00274 (NULL != (expect = MHD_lookup_connection_value (connection, 00275 MHD_HEADER_KIND, 00276 MHD_HTTP_HEADER_EXPECT))) 00277 && (0 == strcasecmp (expect, "100-continue")) 00278 && (connection->continue_message_write_offset < 00279 strlen (HTTP_100_CONTINUE))); 00280 } 00281 00286 void 00287 MHD_connection_close (struct MHD_Connection *connection, 00288 enum MHD_RequestTerminationCode termination_code) 00289 { 00290 SHUTDOWN (connection->socket_fd, SHUT_RDWR); 00291 CLOSE (connection->socket_fd); 00292 connection->socket_fd = -1; 00293 connection->state = MHD_CONNECTION_CLOSED; 00294 if ( (NULL != connection->daemon->notify_completed) && 00295 (MHD_YES == connection->client_aware) ) 00296 connection->daemon->notify_completed (connection->daemon-> 00297 notify_completed_cls, connection, 00298 &connection->client_context, 00299 termination_code); 00300 connection->client_aware = MHD_NO; 00301 } 00302 00307 static void 00308 connection_close_error (struct MHD_Connection *connection) 00309 { 00310 MHD_connection_close (connection, MHD_REQUEST_TERMINATED_WITH_ERROR); 00311 } 00312 00313 00323 static int 00324 try_ready_normal_body (struct MHD_Connection *connection) 00325 { 00326 int ret; 00327 struct MHD_Response *response; 00328 00329 response = connection->response; 00330 if (response->crc == NULL) 00331 return MHD_YES; 00332 if ( (response->data_start <= 00333 connection->response_write_position) && 00334 (response->data_size + response->data_start > 00335 connection->response_write_position) ) 00336 return MHD_YES; /* response already ready */ 00337 #if LINUX 00338 if ( (response->fd != -1) && 00339 (0 == (connection->daemon->options & MHD_USE_SSL)) ) 00340 { 00341 /* will use sendfile, no need to bother response crc */ 00342 return MHD_YES; 00343 } 00344 #endif 00345 00346 ret = response->crc (response->crc_cls, 00347 connection->response_write_position, 00348 response->data, 00349 MHD_MIN (response->data_buffer_size, 00350 response->total_size - 00351 connection->response_write_position)); 00352 if ((ret == 0) && 00353 (0 != (connection->daemon->options & MHD_USE_SELECT_INTERNALLY))) 00354 mhd_panic (mhd_panic_cls, __FILE__, __LINE__, 00355 #if HAVE_MESSAGES 00356 "API violation" 00357 #else 00358 NULL 00359 #endif 00360 ); 00361 if ( (ret == MHD_CONTENT_READER_END_OF_STREAM) || 00362 (ret == MHD_CONTENT_READER_END_WITH_ERROR) ) 00363 { 00364 /* either error or http 1.0 transfer, close 00365 socket! */ 00366 #if DEBUG_CLOSE 00367 #if HAVE_MESSAGES 00368 MHD_DLOG (connection->daemon, 00369 "Closing connection (end of response or error)\n"); 00370 #endif 00371 #endif 00372 response->total_size = connection->response_write_position; 00373 connection_close_error (connection); 00374 return MHD_NO; 00375 } 00376 response->data_start = connection->response_write_position; 00377 response->data_size = ret; 00378 if (ret == 0) 00379 return MHD_NO; 00380 return MHD_YES; 00381 } 00382 00383 00392 static int 00393 try_ready_chunked_body (struct MHD_Connection *connection) 00394 { 00395 int ret; 00396 char *buf; 00397 struct MHD_Response *response; 00398 size_t size; 00399 char cbuf[10]; /* 10: max strlen of "%x\r\n" */ 00400 int cblen; 00401 00402 response = connection->response; 00403 if (connection->write_buffer_size == 0) 00404 { 00405 size = connection->daemon->pool_size; 00406 do 00407 { 00408 size /= 2; 00409 if (size < 128) 00410 { 00411 /* not enough memory */ 00412 #if DEBUG_CLOSE 00413 #if HAVE_MESSAGES 00414 MHD_DLOG (connection->daemon, 00415 "Closing connection (out of memory)\n"); 00416 #endif 00417 #endif 00418 connection_close_error (connection); 00419 return MHD_NO; 00420 } 00421 buf = MHD_pool_allocate (connection->pool, size, MHD_NO); 00422 } 00423 while (buf == NULL); 00424 connection->write_buffer_size = size; 00425 connection->write_buffer = buf; 00426 } 00427 00428 if ( (response->data_start <= 00429 connection->response_write_position) && 00430 (response->data_size + response->data_start > 00431 connection->response_write_position) ) 00432 { 00433 /* buffer already ready, use what is there for the chunk */ 00434 ret = response->data_size + response->data_start - connection->response_write_position; 00435 if (ret > connection->write_buffer_size - sizeof (cbuf) - 2) 00436 ret = connection->write_buffer_size - sizeof (cbuf) - 2; 00437 memcpy (&connection->write_buffer[sizeof (cbuf)], 00438 &response->data[connection->response_write_position - response->data_start], 00439 ret); 00440 } 00441 else 00442 { 00443 /* buffer not in range, try to fill it */ 00444 ret = response->crc (response->crc_cls, 00445 connection->response_write_position, 00446 &connection->write_buffer[sizeof (cbuf)], 00447 connection->write_buffer_size - sizeof (cbuf) - 2); 00448 } 00449 if (ret == MHD_CONTENT_READER_END_WITH_ERROR) 00450 { 00451 /* error, close socket! */ 00452 #if DEBUG_CLOSE 00453 #if HAVE_MESSAGES 00454 MHD_DLOG (connection->daemon, 00455 "Closing connection (error generating response)\n"); 00456 #endif 00457 #endif 00458 response->total_size = connection->response_write_position; 00459 connection_close_error (connection); 00460 return MHD_NO; 00461 } 00462 if (ret == MHD_CONTENT_READER_END_OF_STREAM) 00463 { 00464 /* end of message, signal other side! */ 00465 strcpy (connection->write_buffer, "0\r\n"); 00466 connection->write_buffer_append_offset = 3; 00467 connection->write_buffer_send_offset = 0; 00468 response->total_size = connection->response_write_position; 00469 return MHD_YES; 00470 } 00471 if (ret == 0) 00472 { 00473 connection->state = MHD_CONNECTION_CHUNKED_BODY_UNREADY; 00474 return MHD_NO; 00475 } 00476 if (ret > 0xFFFFFF) 00477 ret = 0xFFFFFF; 00478 snprintf (cbuf, 00479 sizeof (cbuf), 00480 "%X\r\n", ret); 00481 cblen = strlen (cbuf); 00482 EXTRA_CHECK (cblen <= sizeof (cbuf)); 00483 memcpy (&connection->write_buffer[sizeof (cbuf) - cblen], cbuf, cblen); 00484 memcpy (&connection->write_buffer[sizeof (cbuf) + ret], "\r\n", 2); 00485 connection->response_write_position += ret; 00486 connection->write_buffer_send_offset = sizeof (cbuf) - cblen; 00487 connection->write_buffer_append_offset = sizeof (cbuf) + ret + 2; 00488 return MHD_YES; 00489 } 00490 00495 static void 00496 add_extra_headers (struct MHD_Connection *connection) 00497 { 00498 const char *have; 00499 char buf[128]; 00500 00501 connection->have_chunked_upload = MHD_NO; 00502 if (connection->response->total_size == MHD_SIZE_UNKNOWN) 00503 { 00504 have = MHD_get_response_header (connection->response, 00505 MHD_HTTP_HEADER_CONNECTION); 00506 if ((have == NULL) || (0 != strcasecmp (have, "close"))) 00507 { 00508 if ((connection->version != NULL) && 00509 (0 == strcasecmp (connection->version, MHD_HTTP_VERSION_1_1))) 00510 { 00511 connection->have_chunked_upload = MHD_YES; 00512 have = MHD_get_response_header (connection->response, 00513 MHD_HTTP_HEADER_TRANSFER_ENCODING); 00514 if (have == NULL) 00515 MHD_add_response_header (connection->response, 00516 MHD_HTTP_HEADER_TRANSFER_ENCODING, 00517 "chunked"); 00518 } 00519 else 00520 { 00521 MHD_add_response_header (connection->response, 00522 MHD_HTTP_HEADER_CONNECTION, "close"); 00523 } 00524 } 00525 } 00526 else if (NULL == MHD_get_response_header (connection->response, 00527 MHD_HTTP_HEADER_CONTENT_LENGTH)) 00528 { 00529 SPRINTF (buf, 00530 "%" MHD_LONG_LONG_PRINTF "u", 00531 (unsigned MHD_LONG_LONG)connection->response->total_size); 00532 MHD_add_response_header (connection->response, 00533 MHD_HTTP_HEADER_CONTENT_LENGTH, buf); 00534 } 00535 } 00536 00543 static void 00544 get_date_string (char *date) 00545 { 00546 static const char *days[] = 00547 { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" }; 00548 static const char *mons[] = 00549 { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", 00550 "Nov", "Dec" 00551 }; 00552 struct tm now; 00553 time_t t; 00554 00555 time (&t); 00556 gmtime_r (&t, &now); 00557 SPRINTF (date, 00558 "Date: %3s, %02u %3s %04u %02u:%02u:%02u GMT\r\n", 00559 days[now.tm_wday % 7], 00560 now.tm_mday, 00561 mons[now.tm_mon % 12], 00562 1900 + now.tm_year, now.tm_hour, now.tm_min, now.tm_sec); 00563 } 00564 00570 static int 00571 try_grow_read_buffer (struct MHD_Connection *connection) 00572 { 00573 void *buf; 00574 00575 buf = MHD_pool_reallocate (connection->pool, 00576 connection->read_buffer, 00577 connection->read_buffer_size, 00578 connection->read_buffer_size * 2 + 00579 MHD_BUF_INC_SIZE + 1); 00580 if (buf == NULL) 00581 return MHD_NO; 00582 /* we can actually grow the buffer, do it! */ 00583 connection->read_buffer = buf; 00584 connection->read_buffer_size = 00585 connection->read_buffer_size * 2 + MHD_BUF_INC_SIZE; 00586 return MHD_YES; 00587 } 00588 00595 static int 00596 build_header_response (struct MHD_Connection *connection) 00597 { 00598 size_t size; 00599 size_t off; 00600 struct MHD_HTTP_Header *pos; 00601 char code[256]; 00602 char date[128]; 00603 char *data; 00604 enum MHD_ValueKind kind; 00605 const char *reason_phrase; 00606 uint32_t rc; 00607 00608 EXTRA_CHECK (NULL != connection->version); 00609 if (0 == strlen(connection->version)) 00610 { 00611 data = MHD_pool_allocate (connection->pool, 0, MHD_YES); 00612 connection->write_buffer = data; 00613 connection->write_buffer_append_offset = 0; 00614 connection->write_buffer_send_offset = 0; 00615 connection->write_buffer_size = 0; 00616 return MHD_YES; 00617 } 00618 if (connection->state == MHD_CONNECTION_FOOTERS_RECEIVED) 00619 { 00620 add_extra_headers (connection); 00621 rc = connection->responseCode & (~MHD_ICY_FLAG); 00622 reason_phrase = MHD_get_reason_phrase_for (rc); 00623 SPRINTF (code, 00624 "%s %u %s\r\n", 00625 (0 != (connection->responseCode & MHD_ICY_FLAG)) 00626 ? "ICY" 00627 : ( (0 == strcasecmp (MHD_HTTP_VERSION_1_0, 00628 connection->version)) 00629 ? MHD_HTTP_VERSION_1_0 00630 : MHD_HTTP_VERSION_1_1), 00631 rc, 00632 reason_phrase); 00633 off = strlen (code); 00634 /* estimate size */ 00635 size = off + 2; /* extra \r\n at the end */ 00636 kind = MHD_HEADER_KIND; 00637 if (NULL == MHD_get_response_header (connection->response, 00638 MHD_HTTP_HEADER_DATE)) 00639 get_date_string (date); 00640 else 00641 date[0] = '\0'; 00642 size += strlen (date); 00643 } 00644 else 00645 { 00646 size = 2; 00647 kind = MHD_FOOTER_KIND; 00648 off = 0; 00649 } 00650 pos = connection->response->first_header; 00651 while (pos != NULL) 00652 { 00653 if (pos->kind == kind) 00654 size += strlen (pos->header) + strlen (pos->value) + 4; /* colon, space, linefeeds */ 00655 pos = pos->next; 00656 } 00657 /* produce data */ 00658 data = MHD_pool_allocate (connection->pool, size + 1, MHD_YES); 00659 if (data == NULL) 00660 { 00661 #if HAVE_MESSAGES 00662 MHD_DLOG (connection->daemon, "Not enough memory for write!\n"); 00663 #endif 00664 return MHD_NO; 00665 } 00666 if (connection->state == MHD_CONNECTION_FOOTERS_RECEIVED) 00667 { 00668 memcpy (data, code, off); 00669 } 00670 pos = connection->response->first_header; 00671 while (pos != NULL) 00672 { 00673 if (pos->kind == kind) 00674 off += SPRINTF (&data[off], "%s: %s\r\n", pos->header, pos->value); 00675 pos = pos->next; 00676 } 00677 if (connection->state == MHD_CONNECTION_FOOTERS_RECEIVED) 00678 { 00679 strcpy (&data[off], date); 00680 off += strlen (date); 00681 } 00682 memcpy (&data[off], "\r\n", 2); 00683 off += 2; 00684 if (off != size) 00685 mhd_panic (mhd_panic_cls, __FILE__, __LINE__, NULL); 00686 connection->write_buffer = data; 00687 connection->write_buffer_append_offset = size; 00688 connection->write_buffer_send_offset = 0; 00689 connection->write_buffer_size = size + 1; 00690 return MHD_YES; 00691 } 00692 00700 static void 00701 transmit_error_response (struct MHD_Connection *connection, 00702 unsigned int status_code, const char *message) 00703 { 00704 struct MHD_Response *response; 00705 00706 if (connection->version == NULL) 00707 { 00708 /* we were unable to process the full header line, so we don't 00709 really know what version the client speaks; assume 1.0 */ 00710 connection->version = MHD_HTTP_VERSION_1_0; 00711 } 00712 connection->state = MHD_CONNECTION_FOOTERS_RECEIVED; 00713 connection->read_closed = MHD_YES; 00714 #if HAVE_MESSAGES 00715 MHD_DLOG (connection->daemon, 00716 "Error %u (`%s') processing request, closing connection.\n", 00717 status_code, message); 00718 #endif 00719 EXTRA_CHECK (connection->response == NULL); 00720 response = MHD_create_response_from_buffer (strlen (message), 00721 (void *) message, 00722 MHD_RESPMEM_PERSISTENT); 00723 MHD_queue_response (connection, status_code, response); 00724 EXTRA_CHECK (connection->response != NULL); 00725 MHD_destroy_response (response); 00726 if (MHD_NO == build_header_response (connection)) 00727 { 00728 /* oops - close! */ 00729 #if HAVE_MESSAGES 00730 MHD_DLOG (connection->daemon, 00731 "Closing connection (failed to create response header)\n"); 00732 #endif 00733 connection->state = MHD_CONNECTION_CLOSED; 00734 } 00735 else 00736 { 00737 connection->state = MHD_CONNECTION_HEADERS_SENDING; 00738 } 00739 } 00740 00745 static void 00746 do_fd_set (int fd, fd_set * set, int *max_fd) 00747 { 00748 FD_SET (fd, set); 00749 if ( (NULL != max_fd) && 00750 (fd > *max_fd) ) 00751 *max_fd = fd; 00752 } 00753 00759 int 00760 MHD_connection_get_fdset (struct MHD_Connection *connection, 00761 fd_set * read_fd_set, 00762 fd_set * write_fd_set, 00763 fd_set * except_fd_set, int *max_fd) 00764 { 00765 int ret; 00766 struct MHD_Pollfd p; 00767 00768 memset(&p, 0, sizeof(struct MHD_Pollfd)); 00769 ret = MHD_connection_get_pollfd(connection, &p); 00770 if ( (ret == MHD_YES) && (p.fd >= 0) ) { 00771 if (0 != (p.events & MHD_POLL_ACTION_IN)) 00772 do_fd_set(p.fd, read_fd_set, max_fd); 00773 if (0 != (p.events & MHD_POLL_ACTION_OUT)) 00774 do_fd_set(p.fd, write_fd_set, max_fd); 00775 } 00776 return ret; 00777 } 00778 00785 int 00786 MHD_connection_get_pollfd (struct MHD_Connection *connection, struct MHD_Pollfd *p) 00787 { 00788 int fd; 00789 00790 if (connection->pool == NULL) 00791 connection->pool = MHD_pool_create (connection->daemon->pool_size); 00792 if (connection->pool == NULL) 00793 { 00794 #if HAVE_MESSAGES 00795 MHD_DLOG (connection->daemon, "Failed to create memory pool!\n"); 00796 #endif 00797 connection_close_error (connection); 00798 return MHD_NO; 00799 } 00800 fd = connection->socket_fd; 00801 p->fd = fd; 00802 if (fd == -1) 00803 return MHD_YES; 00804 while (1) 00805 { 00806 #if DEBUG_STATES 00807 MHD_DLOG (connection->daemon, "%s: state: %s\n", 00808 __FUNCTION__, MHD_state_to_string (connection->state)); 00809 #endif 00810 switch (connection->state) 00811 { 00812 #if HTTPS_SUPPORT 00813 case MHD_TLS_CONNECTION_INIT: 00814 if (0 == gnutls_record_get_direction (connection->tls_session)) 00815 p->events |= MHD_POLL_ACTION_IN; 00816 else 00817 p->events |= MHD_POLL_ACTION_OUT; 00818 break; 00819 #endif 00820 case MHD_CONNECTION_INIT: 00821 case MHD_CONNECTION_URL_RECEIVED: 00822 case MHD_CONNECTION_HEADER_PART_RECEIVED: 00823 /* while reading headers, we always grow the 00824 read buffer if needed, no size-check required */ 00825 if ((connection->read_closed) && 00826 (connection->read_buffer_offset == 0)) 00827 { 00828 connection->state = MHD_CONNECTION_CLOSED; 00829 continue; 00830 } 00831 if ((connection->read_buffer_offset == connection->read_buffer_size) 00832 && (MHD_NO == try_grow_read_buffer (connection))) 00833 { 00834 transmit_error_response (connection, 00835 (connection->url != NULL) 00836 ? MHD_HTTP_REQUEST_ENTITY_TOO_LARGE 00837 : MHD_HTTP_REQUEST_URI_TOO_LONG, 00838 REQUEST_TOO_BIG); 00839 continue; 00840 } 00841 if (MHD_NO == connection->read_closed) 00842 p->events |= MHD_POLL_ACTION_IN; 00843 break; 00844 case MHD_CONNECTION_HEADERS_RECEIVED: 00845 /* we should never get here */ 00846 EXTRA_CHECK (0); 00847 break; 00848 case MHD_CONNECTION_HEADERS_PROCESSED: 00849 EXTRA_CHECK (0); 00850 break; 00851 case MHD_CONNECTION_CONTINUE_SENDING: 00852 p->events |= MHD_POLL_ACTION_OUT; 00853 break; 00854 case MHD_CONNECTION_CONTINUE_SENT: 00855 if (connection->read_buffer_offset == connection->read_buffer_size) 00856 { 00857 if ((MHD_YES != try_grow_read_buffer (connection)) && 00858 (0 != (connection->daemon->options & 00859 (MHD_USE_SELECT_INTERNALLY | 00860 MHD_USE_THREAD_PER_CONNECTION)))) 00861 { 00862 /* failed to grow the read buffer, and the 00863 client which is supposed to handle the 00864 received data in a *blocking* fashion 00865 (in this mode) did not handle the data as 00866 it was supposed to! 00867 => we would either have to do busy-waiting 00868 (on the client, which would likely fail), 00869 or if we do nothing, we would just timeout 00870 on the connection (if a timeout is even 00871 set!). 00872 Solution: we kill the connection with an error */ 00873 transmit_error_response (connection, 00874 MHD_HTTP_INTERNAL_SERVER_ERROR, 00875 INTERNAL_ERROR); 00876 continue; 00877 } 00878 } 00879 if ((connection->read_buffer_offset < connection->read_buffer_size) 00880 && (MHD_NO == connection->read_closed)) 00881 p->events |= MHD_POLL_ACTION_IN; 00882 break; 00883 case MHD_CONNECTION_BODY_RECEIVED: 00884 case MHD_CONNECTION_FOOTER_PART_RECEIVED: 00885 /* while reading footers, we always grow the 00886 read buffer if needed, no size-check required */ 00887 if (MHD_YES == connection->read_closed) 00888 { 00889 connection->state = MHD_CONNECTION_CLOSED; 00890 continue; 00891 } 00892 p->events |= MHD_POLL_ACTION_IN; 00893 /* transition to FOOTERS_RECEIVED 00894 happens in read handler */ 00895 break; 00896 case MHD_CONNECTION_FOOTERS_RECEIVED: 00897 /* no socket action, wait for client 00898 to provide response */ 00899 break; 00900 case MHD_CONNECTION_HEADERS_SENDING: 00901 /* headers in buffer, keep writing */ 00902 p->events |= MHD_POLL_ACTION_OUT; 00903 break; 00904 case MHD_CONNECTION_HEADERS_SENT: 00905 EXTRA_CHECK (0); 00906 break; 00907 case MHD_CONNECTION_NORMAL_BODY_READY: 00908 p->events |= MHD_POLL_ACTION_OUT; 00909 break; 00910 case MHD_CONNECTION_NORMAL_BODY_UNREADY: 00911 /* not ready, no socket action */ 00912 break; 00913 case MHD_CONNECTION_CHUNKED_BODY_READY: 00914 p->events |= MHD_POLL_ACTION_OUT; 00915 break; 00916 case MHD_CONNECTION_CHUNKED_BODY_UNREADY: 00917 /* not ready, no socket action */ 00918 break; 00919 case MHD_CONNECTION_BODY_SENT: 00920 EXTRA_CHECK (0); 00921 break; 00922 case MHD_CONNECTION_FOOTERS_SENDING: 00923 p->events |= MHD_POLL_ACTION_OUT; 00924 break; 00925 case MHD_CONNECTION_FOOTERS_SENT: 00926 EXTRA_CHECK (0); 00927 break; 00928 case MHD_CONNECTION_CLOSED: 00929 if (connection->socket_fd != -1) 00930 connection_close_error (connection); 00931 return MHD_YES; /* do nothing, not even reading */ 00932 00933 default: 00934 EXTRA_CHECK (0); 00935 } 00936 break; 00937 } 00938 return MHD_YES; 00939 } 00940 00949 static char * 00950 get_next_header_line (struct MHD_Connection *connection) 00951 { 00952 char *rbuf; 00953 size_t pos; 00954 00955 if (connection->read_buffer_offset == 0) 00956 return NULL; 00957 pos = 0; 00958 rbuf = connection->read_buffer; 00959 while ((pos < connection->read_buffer_offset - 1) && 00960 (rbuf[pos] != '\r') && (rbuf[pos] != '\n')) 00961 pos++; 00962 if (pos == connection->read_buffer_offset - 1) 00963 { 00964 /* not found, consider growing... */ 00965 if (connection->read_buffer_offset == connection->read_buffer_size) 00966 { 00967 rbuf = MHD_pool_reallocate (connection->pool, 00968 connection->read_buffer, 00969 connection->read_buffer_size, 00970 connection->read_buffer_size * 2 + 00971 MHD_BUF_INC_SIZE); 00972 if (rbuf == NULL) 00973 { 00974 transmit_error_response (connection, 00975 (connection->url != NULL) 00976 ? MHD_HTTP_REQUEST_ENTITY_TOO_LARGE 00977 : MHD_HTTP_REQUEST_URI_TOO_LONG, 00978 REQUEST_TOO_BIG); 00979 } 00980 else 00981 { 00982 connection->read_buffer_size = 00983 connection->read_buffer_size * 2 + MHD_BUF_INC_SIZE; 00984 connection->read_buffer = rbuf; 00985 } 00986 } 00987 return NULL; 00988 } 00989 /* found, check if we have proper CRLF */ 00990 if ((rbuf[pos] == '\r') && (rbuf[pos + 1] == '\n')) 00991 rbuf[pos++] = '\0'; /* skip both r and n */ 00992 rbuf[pos++] = '\0'; 00993 connection->read_buffer += pos; 00994 connection->read_buffer_size -= pos; 00995 connection->read_buffer_offset -= pos; 00996 return rbuf; 00997 } 00998 01002 static int 01003 connection_add_header (struct MHD_Connection *connection, 01004 char *key, char *value, enum MHD_ValueKind kind) 01005 { 01006 struct MHD_HTTP_Header *hdr; 01007 01008 hdr = MHD_pool_allocate (connection->pool, 01009 sizeof (struct MHD_HTTP_Header), MHD_YES); 01010 if (hdr == NULL) 01011 { 01012 #if HAVE_MESSAGES 01013 MHD_DLOG (connection->daemon, 01014 "Not enough memory to allocate header record!\n"); 01015 #endif 01016 transmit_error_response (connection, MHD_HTTP_REQUEST_ENTITY_TOO_LARGE, 01017 REQUEST_TOO_BIG); 01018 return MHD_NO; 01019 } 01020 hdr->next = connection->headers_received; 01021 hdr->header = key; 01022 hdr->value = value; 01023 hdr->kind = kind; 01024 connection->headers_received = hdr; 01025 return MHD_YES; 01026 } 01027 01031 static int 01032 parse_arguments (enum MHD_ValueKind kind, 01033 struct MHD_Connection *connection, char *args) 01034 { 01035 char *equals; 01036 char *amper; 01037 01038 while (args != NULL) 01039 { 01040 equals = strstr (args, "="); 01041 if (equals == NULL) 01042 return MHD_NO; /* invalid, ignore */ 01043 equals[0] = '\0'; 01044 equals++; 01045 amper = strstr (equals, "&"); 01046 if (amper != NULL) 01047 { 01048 amper[0] = '\0'; 01049 amper++; 01050 } 01051 connection->daemon->unescape_callback (connection->daemon->unescape_callback_cls, 01052 connection, 01053 args); 01054 connection->daemon->unescape_callback (connection->daemon->unescape_callback_cls, 01055 connection, 01056 equals); 01057 if (MHD_NO == connection_add_header (connection, args, equals, kind)) 01058 return MHD_NO; 01059 args = amper; 01060 } 01061 return MHD_YES; 01062 } 01063 01069 static int 01070 parse_cookie_header (struct MHD_Connection *connection) 01071 { 01072 const char *hdr; 01073 char *cpy; 01074 char *pos; 01075 char *sce; 01076 char *semicolon; 01077 char *equals; 01078 char *ekill; 01079 char old; 01080 int quotes; 01081 01082 hdr = MHD_lookup_connection_value (connection, 01083 MHD_HEADER_KIND, 01084 MHD_HTTP_HEADER_COOKIE); 01085 if (hdr == NULL) 01086 return MHD_YES; 01087 cpy = MHD_pool_allocate (connection->pool, strlen (hdr) + 1, MHD_YES); 01088 if (cpy == NULL) 01089 { 01090 #if HAVE_MESSAGES 01091 MHD_DLOG (connection->daemon, "Not enough memory to parse cookies!\n"); 01092 #endif 01093 transmit_error_response (connection, MHD_HTTP_REQUEST_ENTITY_TOO_LARGE, 01094 REQUEST_TOO_BIG); 01095 return MHD_NO; 01096 } 01097 memcpy (cpy, hdr, strlen (hdr) + 1); 01098 pos = cpy; 01099 while (pos != NULL) 01100 { 01101 while (*pos == ' ') 01102 pos++; /* skip spaces */ 01103 01104 sce = pos; 01105 while (((*sce) != '\0') && 01106 ((*sce) != ',') && ((*sce) != ';') && ((*sce) != '=')) 01107 sce++; 01108 /* remove tailing whitespace (if any) from key */ 01109 ekill = sce - 1; 01110 while ((*ekill == ' ') && (ekill >= pos)) 01111 *(ekill--) = '\0'; 01112 old = *sce; 01113 *sce = '\0'; 01114 if (old != '=') 01115 { 01116 /* value part omitted, use empty string... */ 01117 if (MHD_NO == 01118 connection_add_header (connection, pos, "", MHD_COOKIE_KIND)) 01119 return MHD_NO; 01120 if (old == '\0') 01121 break; 01122 pos = sce + 1; 01123 continue; 01124 } 01125 equals = sce + 1; 01126 quotes = 0; 01127 semicolon = equals; 01128 while ((semicolon[0] != '\0') && 01129 ((quotes != 0) || 01130 ((semicolon[0] != ';') && (semicolon[0] != ',')))) 01131 { 01132 if (semicolon[0] == '"') 01133 quotes = (quotes + 1) & 1; 01134 semicolon++; 01135 } 01136 if (semicolon[0] == '\0') 01137 semicolon = NULL; 01138 if (semicolon != NULL) 01139 { 01140 semicolon[0] = '\0'; 01141 semicolon++; 01142 } 01143 /* remove quotes */ 01144 if ((equals[0] == '"') && (equals[strlen (equals) - 1] == '"')) 01145 { 01146 equals[strlen (equals) - 1] = '\0'; 01147 equals++; 01148 } 01149 if (MHD_NO == connection_add_header (connection, 01150 pos, equals, MHD_COOKIE_KIND)) 01151 return MHD_NO; 01152 pos = semicolon; 01153 } 01154 return MHD_YES; 01155 } 01156 01164 static int 01165 parse_initial_message_line (struct MHD_Connection *connection, char *line) 01166 { 01167 char *uri; 01168 char *httpVersion; 01169 char *args; 01170 01171 uri = strstr (line, " "); 01172 if (uri == NULL) 01173 return MHD_NO; /* serious error */ 01174 uri[0] = '\0'; 01175 connection->method = line; 01176 uri++; 01177 while (uri[0] == ' ') 01178 uri++; 01179 httpVersion = strstr (uri, " "); 01180 if (httpVersion != NULL) 01181 { 01182 httpVersion[0] = '\0'; 01183 httpVersion++; 01184 } 01185 if (connection->daemon->uri_log_callback != NULL) 01186 connection->client_context 01187 = 01188 connection->daemon->uri_log_callback (connection->daemon-> 01189 uri_log_callback_cls, uri); 01190 args = strstr (uri, "?"); 01191 if (args != NULL) 01192 { 01193 args[0] = '\0'; 01194 args++; 01195 parse_arguments (MHD_GET_ARGUMENT_KIND, connection, args); 01196 } 01197 connection->daemon->unescape_callback (connection->daemon->unescape_callback_cls, 01198 connection, 01199 uri); 01200 connection->url = uri; 01201 if (httpVersion == NULL) 01202 connection->version = ""; 01203 else 01204 connection->version = httpVersion; 01205 return MHD_YES; 01206 } 01207 01208 01214 static void 01215 call_connection_handler (struct MHD_Connection *connection) 01216 { 01217 size_t processed; 01218 01219 if (connection->response != NULL) 01220 return; /* already queued a response */ 01221 processed = 0; 01222 connection->client_aware = MHD_YES; 01223 if (MHD_NO == 01224 connection->daemon->default_handler (connection->daemon-> 01225 default_handler_cls, 01226 connection, connection->url, 01227 connection->method, 01228 connection->version, 01229 NULL, &processed, 01230 &connection->client_context)) 01231 { 01232 /* serious internal error, close connection */ 01233 #if HAVE_MESSAGES 01234 MHD_DLOG (connection->daemon, 01235 "Internal application error, closing connection.\n"); 01236 #endif 01237 connection_close_error (connection); 01238 return; 01239 } 01240 } 01241 01242 01243 01249 static void 01250 process_request_body (struct MHD_Connection *connection) 01251 { 01252 size_t processed; 01253 size_t available; 01254 size_t used; 01255 size_t i; 01256 int instant_retry; 01257 int malformed; 01258 char *buffer_head; 01259 01260 if (connection->response != NULL) 01261 return; /* already queued a response */ 01262 01263 buffer_head = connection->read_buffer; 01264 available = connection->read_buffer_offset; 01265 do 01266 { 01267 instant_retry = MHD_NO; 01268 if ((connection->have_chunked_upload == MHD_YES) && 01269 (connection->remaining_upload_size == MHD_SIZE_UNKNOWN)) 01270 { 01271 if ((connection->current_chunk_offset == 01272 connection->current_chunk_size) 01273 && (connection->current_chunk_offset != 0) && (available >= 2)) 01274 { 01275 /* skip new line at the *end* of a chunk */ 01276 i = 0; 01277 if ((buffer_head[i] == '\r') || (buffer_head[i] == '\n')) 01278 i++; /* skip 1st part of line feed */ 01279 if ((buffer_head[i] == '\r') || (buffer_head[i] == '\n')) 01280 i++; /* skip 2nd part of line feed */ 01281 if (i == 0) 01282 { 01283 /* malformed encoding */ 01284 #if HAVE_MESSAGES 01285 MHD_DLOG (connection->daemon, 01286 "Received malformed HTTP request (bad chunked encoding), closing connection.\n"); 01287 #endif 01288 connection_close_error (connection); 01289 return; 01290 } 01291 available -= i; 01292 buffer_head += i; 01293 connection->current_chunk_offset = 0; 01294 connection->current_chunk_size = 0; 01295 } 01296 if (connection->current_chunk_offset < 01297 connection->current_chunk_size) 01298 { 01299 /* we are in the middle of a chunk, give 01300 as much as possible to the client (without 01301 crossing chunk boundaries) */ 01302 processed = 01303 connection->current_chunk_size - 01304 connection->current_chunk_offset; 01305 if (processed > available) 01306 processed = available; 01307 if (available > processed) 01308 instant_retry = MHD_YES; 01309 } 01310 else 01311 { 01312 /* we need to read chunk boundaries */ 01313 i = 0; 01314 while (i < available) 01315 { 01316 if ((buffer_head[i] == '\r') || (buffer_head[i] == '\n')) 01317 break; 01318 i++; 01319 if (i >= 6) 01320 break; 01321 } 01322 /* take '\n' into account; if '\n' 01323 is the unavailable character, we 01324 will need to wait until we have it 01325 before going further */ 01326 if ((i + 1 >= available) && 01327 !((i == 1) && (available == 2) && (buffer_head[0] == '0'))) 01328 break; /* need more data... */ 01329 malformed = (i >= 6); 01330 if (!malformed) 01331 { 01332 buffer_head[i] = '\0'; 01333 malformed = 01334 (1 != SSCANF (buffer_head, "%X", 01335 &connection->current_chunk_size)) && 01336 (1 != SSCANF (buffer_head, "%x", 01337 &connection->current_chunk_size)); 01338 } 01339 if (malformed) 01340 { 01341 /* malformed encoding */ 01342 #if HAVE_MESSAGES 01343 MHD_DLOG (connection->daemon, 01344 "Received malformed HTTP request (bad chunked encoding), closing connection.\n"); 01345 #endif 01346 connection_close_error (connection); 01347 return; 01348 } 01349 i++; 01350 if ((i < available) && 01351 ((buffer_head[i] == '\r') || (buffer_head[i] == '\n'))) 01352 i++; /* skip 2nd part of line feed */ 01353 01354 buffer_head += i; 01355 available -= i; 01356 connection->current_chunk_offset = 0; 01357 01358 if (available > 0) 01359 instant_retry = MHD_YES; 01360 if (connection->current_chunk_size == 0) 01361 { 01362 connection->remaining_upload_size = 0; 01363 break; 01364 } 01365 continue; 01366 } 01367 } 01368 else 01369 { 01370 /* no chunked encoding, give all to the client */ 01371 processed = available; 01372 } 01373 used = processed; 01374 connection->client_aware = MHD_YES; 01375 if (MHD_NO == 01376 connection->daemon->default_handler (connection->daemon-> 01377 default_handler_cls, 01378 connection, connection->url, 01379 connection->method, 01380 connection->version, 01381 buffer_head, &processed, 01382 &connection->client_context)) 01383 { 01384 /* serious internal error, close connection */ 01385 #if HAVE_MESSAGES 01386 MHD_DLOG (connection->daemon, 01387 "Internal application error, closing connection.\n"); 01388 #endif 01389 connection_close_error (connection); 01390 return; 01391 } 01392 if (processed > used) 01393 mhd_panic (mhd_panic_cls, __FILE__, __LINE__, 01394 #if HAVE_MESSAGES 01395 "API violation" 01396 #else 01397 NULL 01398 #endif 01399 ); 01400 if (processed != 0) 01401 instant_retry = MHD_NO; /* client did not process everything */ 01402 used -= processed; 01403 if (connection->have_chunked_upload == MHD_YES) 01404 connection->current_chunk_offset += used; 01405 /* dh left "processed" bytes in buffer for next time... */ 01406 buffer_head += used; 01407 available -= used; 01408 if (connection->remaining_upload_size != MHD_SIZE_UNKNOWN) 01409 connection->remaining_upload_size -= used; 01410 } 01411 while (instant_retry == MHD_YES); 01412 if (available > 0) 01413 memmove (connection->read_buffer, buffer_head, available); 01414 connection->read_buffer_offset = available; 01415 } 01416 01425 static int 01426 do_read (struct MHD_Connection *connection) 01427 { 01428 int bytes_read; 01429 01430 if (connection->read_buffer_size == connection->read_buffer_offset) 01431 return MHD_NO; 01432 01433 bytes_read = connection->recv_cls (connection, 01434 &connection->read_buffer 01435 [connection->read_buffer_offset], 01436 connection->read_buffer_size - 01437 connection->read_buffer_offset); 01438 if (bytes_read < 0) 01439 { 01440 if (errno == EINTR) 01441 return MHD_NO; 01442 #if HAVE_MESSAGES 01443 #if HTTPS_SUPPORT 01444 if (0 != (connection->daemon->options & MHD_USE_SSL)) 01445 MHD_DLOG (connection->daemon, 01446 "Failed to receive data: %s\n", 01447 gnutls_strerror (bytes_read)); 01448 else 01449 #endif 01450 MHD_DLOG (connection->daemon, 01451 "Failed to receive data: %s\n", STRERROR (errno)); 01452 #endif 01453 connection_close_error (connection); 01454 return MHD_YES; 01455 } 01456 if (bytes_read == 0) 01457 { 01458 /* other side closed connection */ 01459 connection->read_closed = MHD_YES; 01460 SHUTDOWN (connection->socket_fd, SHUT_RD); 01461 return MHD_YES; 01462 } 01463 connection->read_buffer_offset += bytes_read; 01464 return MHD_YES; 01465 } 01466 01474 static int 01475 do_write (struct MHD_Connection *connection) 01476 { 01477 int ret; 01478 01479 ret = connection->send_cls (connection, 01480 &connection->write_buffer 01481 [connection->write_buffer_send_offset], 01482 connection->write_buffer_append_offset 01483 - connection->write_buffer_send_offset); 01484 01485 if (ret < 0) 01486 { 01487 if (errno == EINTR) 01488 return MHD_NO; 01489 #if HAVE_MESSAGES 01490 #if HTTPS_SUPPORT 01491 if (0 != (connection->daemon->options & MHD_USE_SSL)) 01492 MHD_DLOG (connection->daemon, 01493 "Failed to send data: %s\n", 01494 gnutls_strerror (ret)); 01495 else 01496 #endif 01497 MHD_DLOG (connection->daemon, 01498 "Failed to send data: %s\n", STRERROR (errno)); 01499 #endif 01500 connection_close_error (connection); 01501 return MHD_YES; 01502 } 01503 #if DEBUG_SEND_DATA 01504 FPRINTF (stderr, 01505 "Sent response: `%.*s'\n", 01506 ret, 01507 &connection->write_buffer[connection->write_buffer_send_offset]); 01508 #endif 01509 connection->write_buffer_send_offset += ret; 01510 return MHD_YES; 01511 } 01512 01518 static int 01519 check_write_done (struct MHD_Connection *connection, 01520 enum MHD_CONNECTION_STATE next_state) 01521 { 01522 if (connection->write_buffer_append_offset != 01523 connection->write_buffer_send_offset) 01524 return MHD_NO; 01525 connection->write_buffer_append_offset = 0; 01526 connection->write_buffer_send_offset = 0; 01527 connection->state = next_state; 01528 MHD_pool_reallocate (connection->pool, connection->write_buffer, 01529 connection->write_buffer_size, 0); 01530 connection->write_buffer = NULL; 01531 connection->write_buffer_size = 0; 01532 return MHD_YES; 01533 } 01534 01540 static int 01541 process_header_line (struct MHD_Connection *connection, char *line) 01542 { 01543 char *colon; 01544 01545 /* line should be normal header line, find colon */ 01546 colon = strstr (line, ":"); 01547 if (colon == NULL) 01548 { 01549 /* error in header line, die hard */ 01550 #if HAVE_MESSAGES 01551 MHD_DLOG (connection->daemon, 01552 "Received malformed line (no colon), closing connection.\n"); 01553 #endif 01554 connection->state = MHD_CONNECTION_CLOSED; 01555 return MHD_NO; 01556 } 01557 /* zero-terminate header */ 01558 colon[0] = '\0'; 01559 colon++; /* advance to value */ 01560 while ((colon[0] != '\0') && ((colon[0] == ' ') || (colon[0] == '\t'))) 01561 colon++; 01562 /* we do the actual adding of the connection 01563 header at the beginning of the while 01564 loop since we need to be able to inspect 01565 the *next* header line (in case it starts 01566 with a space...) */ 01567 connection->last = line; 01568 connection->colon = colon; 01569 return MHD_YES; 01570 } 01571 01581 static int 01582 process_broken_line (struct MHD_Connection *connection, 01583 char *line, enum MHD_ValueKind kind) 01584 { 01585 char *last; 01586 char *tmp; 01587 size_t last_len; 01588 size_t tmp_len; 01589 01590 last = connection->last; 01591 if ((line[0] == ' ') || (line[0] == '\t')) 01592 { 01593 /* value was continued on the next line, see 01594 http://www.jmarshall.com/easy/http/ */ 01595 last_len = strlen (last); 01596 /* skip whitespace at start of 2nd line */ 01597 tmp = line; 01598 while ((tmp[0] == ' ') || (tmp[0] == '\t')) 01599 tmp++; 01600 tmp_len = strlen (tmp); 01601 last = MHD_pool_reallocate (connection->pool, 01602 last, 01603 last_len + 1, 01604 last_len + tmp_len + 1); 01605 if (last == NULL) 01606 { 01607 transmit_error_response (connection, 01608 MHD_HTTP_REQUEST_ENTITY_TOO_LARGE, 01609 REQUEST_TOO_BIG); 01610 return MHD_NO; 01611 } 01612 memcpy (&last[last_len], tmp, tmp_len + 1); 01613 connection->last = last; 01614 return MHD_YES; /* possibly more than 2 lines... */ 01615 } 01616 EXTRA_CHECK ((last != NULL) && (connection->colon != NULL)); 01617 if ((MHD_NO == connection_add_header (connection, 01618 last, connection->colon, kind))) 01619 { 01620 transmit_error_response (connection, MHD_HTTP_REQUEST_ENTITY_TOO_LARGE, 01621 REQUEST_TOO_BIG); 01622 return MHD_NO; 01623 } 01624 /* we still have the current line to deal with... */ 01625 if (strlen (line) != 0) 01626 { 01627 if (MHD_NO == process_header_line (connection, line)) 01628 { 01629 transmit_error_response (connection, 01630 MHD_HTTP_BAD_REQUEST, REQUEST_MALFORMED); 01631 return MHD_NO; 01632 } 01633 } 01634 return MHD_YES; 01635 } 01636 01642 static void 01643 parse_connection_headers (struct MHD_Connection *connection) 01644 { 01645 const char *clen; 01646 unsigned MHD_LONG_LONG cval; 01647 struct MHD_Response *response; 01648 const char *enc; 01649 01650 parse_cookie_header (connection); 01651 if ((0 != (MHD_USE_PEDANTIC_CHECKS & connection->daemon->options)) 01652 && (NULL != connection->version) 01653 && (0 == strcasecmp (MHD_HTTP_VERSION_1_1, connection->version)) 01654 && (NULL == 01655 MHD_lookup_connection_value (connection, MHD_HEADER_KIND, 01656 MHD_HTTP_HEADER_HOST))) 01657 { 01658 /* die, http 1.1 request without host and we are pedantic */ 01659 connection->state = MHD_CONNECTION_FOOTERS_RECEIVED; 01660 connection->read_closed = MHD_YES; 01661 #if HAVE_MESSAGES 01662 MHD_DLOG (connection->daemon, 01663 "Received `%s' request without `%s' header.\n", 01664 MHD_HTTP_VERSION_1_1, MHD_HTTP_HEADER_HOST); 01665 #endif 01666 EXTRA_CHECK (connection->response == NULL); 01667 response = 01668 MHD_create_response_from_buffer (strlen (REQUEST_LACKS_HOST), 01669 REQUEST_LACKS_HOST, 01670 MHD_RESPMEM_PERSISTENT); 01671 MHD_queue_response (connection, MHD_HTTP_BAD_REQUEST, response); 01672 MHD_destroy_response (response); 01673 return; 01674 } 01675 01676 clen = MHD_lookup_connection_value (connection, 01677 MHD_HEADER_KIND, 01678 MHD_HTTP_HEADER_CONTENT_LENGTH); 01679 if (clen != NULL) 01680 { 01681 if (1 != SSCANF (clen, "%" MHD_LONG_LONG_PRINTF "u", &cval)) 01682 { 01683 #if HAVE_MESSAGES 01684 MHD_DLOG (connection->daemon, 01685 "Failed to parse `%s' header `%s', closing connection.\n", 01686 MHD_HTTP_HEADER_CONTENT_LENGTH, clen); 01687 #endif 01688 connection->state = MHD_CONNECTION_CLOSED; 01689 return; 01690 } 01691 connection->remaining_upload_size = cval; 01692 } 01693 else 01694 { 01695 enc = MHD_lookup_connection_value (connection, 01696 MHD_HEADER_KIND, 01697 MHD_HTTP_HEADER_TRANSFER_ENCODING); 01698 if (NULL == enc) 01699 { 01700 /* this request (better) not have a body */ 01701 connection->remaining_upload_size = 0; 01702 } 01703 else 01704 { 01705 connection->remaining_upload_size = MHD_SIZE_UNKNOWN; 01706 if (0 == strcasecmp (enc, "chunked")) 01707 connection->have_chunked_upload = MHD_YES; 01708 } 01709 } 01710 } 01711 01721 int 01722 MHD_connection_handle_read (struct MHD_Connection *connection) 01723 { 01724 connection->last_activity = time (NULL); 01725 if (connection->state == MHD_CONNECTION_CLOSED) 01726 return MHD_NO; 01727 /* make sure "read" has a reasonable number of bytes 01728 in buffer to use per system call (if possible) */ 01729 if (connection->read_buffer_offset + MHD_BUF_INC_SIZE > 01730 connection->read_buffer_size) 01731 try_grow_read_buffer (connection); 01732 if (MHD_NO == do_read (connection)) 01733 return MHD_YES; 01734 while (1) 01735 { 01736 #if DEBUG_STATES 01737 MHD_DLOG (connection->daemon, "%s: state: %s\n", 01738 __FUNCTION__, MHD_state_to_string (connection->state)); 01739 #endif 01740 switch (connection->state) 01741 { 01742 case MHD_CONNECTION_INIT: 01743 case MHD_CONNECTION_URL_RECEIVED: 01744 case MHD_CONNECTION_HEADER_PART_RECEIVED: 01745 case MHD_CONNECTION_HEADERS_RECEIVED: 01746 case MHD_CONNECTION_HEADERS_PROCESSED: 01747 case MHD_CONNECTION_CONTINUE_SENDING: 01748 case MHD_CONNECTION_CONTINUE_SENT: 01749 case MHD_CONNECTION_BODY_RECEIVED: 01750 case MHD_CONNECTION_FOOTER_PART_RECEIVED: 01751 /* nothing to do but default action */ 01752 if (MHD_YES == connection->read_closed) 01753 { 01754 connection->state = MHD_CONNECTION_CLOSED; 01755 continue; 01756 } 01757 break; 01758 case MHD_CONNECTION_CLOSED: 01759 if (connection->socket_fd != -1) 01760 connection_close_error (connection); 01761 return MHD_NO; 01762 default: 01763 /* shrink read buffer to how much is actually used */ 01764 MHD_pool_reallocate (connection->pool, 01765 connection->read_buffer, 01766 connection->read_buffer_size + 1, 01767 connection->read_buffer_offset); 01768 break; 01769 } 01770 break; 01771 } 01772 return MHD_YES; 01773 } 01774 01784 int 01785 MHD_connection_handle_write (struct MHD_Connection *connection) 01786 { 01787 struct MHD_Response *response; 01788 int ret; 01789 connection->last_activity = time (NULL); 01790 while (1) 01791 { 01792 #if DEBUG_STATES 01793 MHD_DLOG (connection->daemon, "%s: state: %s\n", 01794 __FUNCTION__, MHD_state_to_string (connection->state)); 01795 #endif 01796 switch (connection->state) 01797 { 01798 case MHD_CONNECTION_INIT: 01799 case MHD_CONNECTION_URL_RECEIVED: 01800 case MHD_CONNECTION_HEADER_PART_RECEIVED: 01801 case MHD_CONNECTION_HEADERS_RECEIVED: 01802 EXTRA_CHECK (0); 01803 break; 01804 case MHD_CONNECTION_HEADERS_PROCESSED: 01805 break; 01806 case MHD_CONNECTION_CONTINUE_SENDING: 01807 ret = connection->send_cls (connection, 01808 &HTTP_100_CONTINUE 01809 [connection->continue_message_write_offset], 01810 strlen (HTTP_100_CONTINUE) - 01811 connection->continue_message_write_offset); 01812 if (ret < 0) 01813 { 01814 if (errno == EINTR) 01815 break; 01816 #if HAVE_MESSAGES 01817 MHD_DLOG (connection->daemon, 01818 "Failed to send data: %s\n", STRERROR (errno)); 01819 #endif 01820 connection_close_error (connection); 01821 return MHD_NO; 01822 } 01823 #if DEBUG_SEND_DATA 01824 FPRINTF (stderr, 01825 "Sent 100 continue response: `%.*s'\n", 01826 ret, 01827 &HTTP_100_CONTINUE 01828 [connection->continue_message_write_offset]); 01829 #endif 01830 connection->continue_message_write_offset += ret; 01831 break; 01832 case MHD_CONNECTION_CONTINUE_SENT: 01833 case MHD_CONNECTION_BODY_RECEIVED: 01834 case MHD_CONNECTION_FOOTER_PART_RECEIVED: 01835 case MHD_CONNECTION_FOOTERS_RECEIVED: 01836 EXTRA_CHECK (0); 01837 break; 01838 case MHD_CONNECTION_HEADERS_SENDING: 01839 do_write (connection); 01840 check_write_done (connection, MHD_CONNECTION_HEADERS_SENT); 01841 break; 01842 case MHD_CONNECTION_HEADERS_SENT: 01843 EXTRA_CHECK (0); 01844 break; 01845 case MHD_CONNECTION_NORMAL_BODY_READY: 01846 response = connection->response; 01847 if (response->crc != NULL) 01848 pthread_mutex_lock (&response->mutex); 01849 if (MHD_YES != try_ready_normal_body (connection)) 01850 { 01851 if (response->crc != NULL) 01852 pthread_mutex_unlock (&response->mutex); 01853 connection->state = MHD_CONNECTION_NORMAL_BODY_UNREADY; 01854 break; 01855 } 01856 ret = connection->send_cls (connection, 01857 &response->data 01858 [connection->response_write_position 01859 - response->data_start], 01860 response->data_size - 01861 (connection->response_write_position 01862 - response->data_start)); 01863 #if DEBUG_SEND_DATA 01864 if (ret > 0) 01865 FPRINTF (stderr, 01866 "Sent DATA response: `%.*s'\n", 01867 ret, 01868 &response->data[connection->response_write_position - 01869 response->data_start]); 01870 #endif 01871 if (response->crc != NULL) 01872 pthread_mutex_unlock (&response->mutex); 01873 if (ret < 0) 01874 { 01875 if (errno == EINTR) 01876 return MHD_YES; 01877 #if HAVE_MESSAGES 01878 MHD_DLOG (connection->daemon, 01879 "Failed to send data: %s\n", STRERROR (errno)); 01880 #endif 01881 connection_close_error (connection); 01882 return MHD_NO; 01883 } 01884 connection->response_write_position += ret; 01885 if (connection->response_write_position == 01886 connection->response->total_size) 01887 connection->state = MHD_CONNECTION_FOOTERS_SENT; /* have no footers... */ 01888 break; 01889 case MHD_CONNECTION_NORMAL_BODY_UNREADY: 01890 EXTRA_CHECK (0); 01891 break; 01892 case MHD_CONNECTION_CHUNKED_BODY_READY: 01893 do_write (connection); 01894 check_write_done (connection, 01895 (connection->response->total_size == 01896 connection->response_write_position) ? 01897 MHD_CONNECTION_BODY_SENT : 01898 MHD_CONNECTION_CHUNKED_BODY_UNREADY); 01899 break; 01900 case MHD_CONNECTION_CHUNKED_BODY_UNREADY: 01901 case MHD_CONNECTION_BODY_SENT: 01902 EXTRA_CHECK (0); 01903 break; 01904 case MHD_CONNECTION_FOOTERS_SENDING: 01905 do_write (connection); 01906 check_write_done (connection, MHD_CONNECTION_FOOTERS_SENT); 01907 break; 01908 case MHD_CONNECTION_FOOTERS_SENT: 01909 EXTRA_CHECK (0); 01910 break; 01911 case MHD_CONNECTION_CLOSED: 01912 if (connection->socket_fd != -1) 01913 connection_close_error (connection); 01914 return MHD_NO; 01915 case MHD_TLS_CONNECTION_INIT: 01916 EXTRA_CHECK (0); 01917 break; 01918 default: 01919 EXTRA_CHECK (0); 01920 connection_close_error (connection); 01921 return MHD_NO; 01922 } 01923 break; 01924 } 01925 return MHD_YES; 01926 } 01927 01937 int 01938 MHD_connection_handle_idle (struct MHD_Connection *connection) 01939 { 01940 unsigned int timeout; 01941 const char *end; 01942 char *line; 01943 01944 while (1) 01945 { 01946 #if DEBUG_STATES 01947 MHD_DLOG (connection->daemon, "%s: state: %s\n", 01948 __FUNCTION__, MHD_state_to_string (connection->state)); 01949 #endif 01950 switch (connection->state) 01951 { 01952 case MHD_CONNECTION_INIT: 01953 line = get_next_header_line (connection); 01954 if (line == NULL) 01955 { 01956 if (connection->state != MHD_CONNECTION_INIT) 01957 continue; 01958 if (connection->read_closed) 01959 { 01960 connection->state = MHD_CONNECTION_CLOSED; 01961 continue; 01962 } 01963 break; 01964 } 01965 if (MHD_NO == parse_initial_message_line (connection, line)) 01966 connection->state = MHD_CONNECTION_CLOSED; 01967 else 01968 connection->state = MHD_CONNECTION_URL_RECEIVED; 01969 continue; 01970 case MHD_CONNECTION_URL_RECEIVED: 01971 line = get_next_header_line (connection); 01972 if (line == NULL) 01973 { 01974 if (connection->state != MHD_CONNECTION_URL_RECEIVED) 01975 continue; 01976 if (connection->read_closed) 01977 { 01978 connection->state = MHD_CONNECTION_CLOSED; 01979 continue; 01980 } 01981 break; 01982 } 01983 if (strlen (line) == 0) 01984 { 01985 connection->state = MHD_CONNECTION_HEADERS_RECEIVED; 01986 continue; 01987 } 01988 if (MHD_NO == process_header_line (connection, line)) 01989 { 01990 transmit_error_response (connection, 01991 MHD_HTTP_BAD_REQUEST, 01992 REQUEST_MALFORMED); 01993 break; 01994 } 01995 connection->state = MHD_CONNECTION_HEADER_PART_RECEIVED; 01996 continue; 01997 case MHD_CONNECTION_HEADER_PART_RECEIVED: 01998 line = get_next_header_line (connection); 01999 if (line == NULL) 02000 { 02001 if (connection->state != MHD_CONNECTION_HEADER_PART_RECEIVED) 02002 continue; 02003 if (connection->read_closed) 02004 { 02005 connection->state = MHD_CONNECTION_CLOSED; 02006 continue; 02007 } 02008 break; 02009 } 02010 if (MHD_NO == 02011 process_broken_line (connection, line, MHD_HEADER_KIND)) 02012 continue; 02013 if (strlen (line) == 0) 02014 { 02015 connection->state = MHD_CONNECTION_HEADERS_RECEIVED; 02016 continue; 02017 } 02018 continue; 02019 case MHD_CONNECTION_HEADERS_RECEIVED: 02020 parse_connection_headers (connection); 02021 if (connection->state == MHD_CONNECTION_CLOSED) 02022 continue; 02023 connection->state = MHD_CONNECTION_HEADERS_PROCESSED; 02024 continue; 02025 case MHD_CONNECTION_HEADERS_PROCESSED: 02026 call_connection_handler (connection); /* first call */ 02027 if (connection->state == MHD_CONNECTION_CLOSED) 02028 continue; 02029 if (need_100_continue (connection)) 02030 { 02031 connection->state = MHD_CONNECTION_CONTINUE_SENDING; 02032 break; 02033 } 02034 if (connection->response != NULL) 02035 { 02036 /* we refused (no upload allowed!) */ 02037 connection->remaining_upload_size = 0; 02038 /* force close, in case client still tries to upload... */ 02039 connection->read_closed = MHD_YES; 02040 } 02041 connection->state = (connection->remaining_upload_size == 0) 02042 ? MHD_CONNECTION_FOOTERS_RECEIVED : MHD_CONNECTION_CONTINUE_SENT; 02043 continue; 02044 case MHD_CONNECTION_CONTINUE_SENDING: 02045 if (connection->continue_message_write_offset == 02046 strlen (HTTP_100_CONTINUE)) 02047 { 02048 connection->state = MHD_CONNECTION_CONTINUE_SENT; 02049 continue; 02050 } 02051 break; 02052 case MHD_CONNECTION_CONTINUE_SENT: 02053 if (connection->read_buffer_offset != 0) 02054 { 02055 process_request_body (connection); /* loop call */ 02056 if (connection->state == MHD_CONNECTION_CLOSED) 02057 continue; 02058 } 02059 if ((connection->remaining_upload_size == 0) || 02060 ((connection->remaining_upload_size == MHD_SIZE_UNKNOWN) && 02061 (connection->read_buffer_offset == 0) && 02062 (MHD_YES == connection->read_closed))) 02063 { 02064 if ((MHD_YES == connection->have_chunked_upload) && 02065 (MHD_NO == connection->read_closed)) 02066 connection->state = MHD_CONNECTION_BODY_RECEIVED; 02067 else 02068 connection->state = MHD_CONNECTION_FOOTERS_RECEIVED; 02069 continue; 02070 } 02071 break; 02072 case MHD_CONNECTION_BODY_RECEIVED: 02073 line = get_next_header_line (connection); 02074 if (line == NULL) 02075 { 02076 if (connection->state != MHD_CONNECTION_BODY_RECEIVED) 02077 continue; 02078 if (connection->read_closed) 02079 { 02080 connection->state = MHD_CONNECTION_CLOSED; 02081 continue; 02082 } 02083 break; 02084 } 02085 if (strlen (line) == 0) 02086 { 02087 connection->state = MHD_CONNECTION_FOOTERS_RECEIVED; 02088 continue; 02089 } 02090 if (MHD_NO == process_header_line (connection, line)) 02091 { 02092 transmit_error_response (connection, 02093 MHD_HTTP_BAD_REQUEST, 02094 REQUEST_MALFORMED); 02095 break; 02096 } 02097 connection->state = MHD_CONNECTION_FOOTER_PART_RECEIVED; 02098 continue; 02099 case MHD_CONNECTION_FOOTER_PART_RECEIVED: 02100 line = get_next_header_line (connection); 02101 if (line == NULL) 02102 { 02103 if (connection->state != MHD_CONNECTION_FOOTER_PART_RECEIVED) 02104 continue; 02105 if (connection->read_closed) 02106 { 02107 connection->state = MHD_CONNECTION_CLOSED; 02108 continue; 02109 } 02110 break; 02111 } 02112 if (MHD_NO == 02113 process_broken_line (connection, line, MHD_FOOTER_KIND)) 02114 continue; 02115 if (strlen (line) == 0) 02116 { 02117 connection->state = MHD_CONNECTION_FOOTERS_RECEIVED; 02118 continue; 02119 } 02120 continue; 02121 case MHD_CONNECTION_FOOTERS_RECEIVED: 02122 call_connection_handler (connection); /* "final" call */ 02123 if (connection->state == MHD_CONNECTION_CLOSED) 02124 continue; 02125 if (connection->response == NULL) 02126 break; /* try again next time */ 02127 if (MHD_NO == build_header_response (connection)) 02128 { 02129 /* oops - close! */ 02130 #if HAVE_MESSAGES 02131 MHD_DLOG (connection->daemon, 02132 "Closing connection (failed to create response header)\n"); 02133 #endif 02134 connection->state = MHD_CONNECTION_CLOSED; 02135 continue; 02136 } 02137 connection->state = MHD_CONNECTION_HEADERS_SENDING; 02138 02139 #if HAVE_DECL_TCP_CORK 02140 /* starting header send, set TCP cork */ 02141 { 02142 const int val = 1; 02143 setsockopt (connection->socket_fd, IPPROTO_TCP, TCP_CORK, &val, 02144 sizeof (val)); 02145 } 02146 #endif 02147 break; 02148 case MHD_CONNECTION_HEADERS_SENDING: 02149 /* no default action */ 02150 break; 02151 case MHD_CONNECTION_HEADERS_SENT: 02152 if (connection->have_chunked_upload) 02153 connection->state = MHD_CONNECTION_CHUNKED_BODY_UNREADY; 02154 else 02155 connection->state = MHD_CONNECTION_NORMAL_BODY_UNREADY; 02156 continue; 02157 case MHD_CONNECTION_NORMAL_BODY_READY: 02158 /* nothing to do here */ 02159 break; 02160 case MHD_CONNECTION_NORMAL_BODY_UNREADY: 02161 if (connection->response->crc != NULL) 02162 pthread_mutex_lock (&connection->response->mutex); 02163 if (MHD_YES == try_ready_normal_body (connection)) 02164 { 02165 if (connection->response->crc != NULL) 02166 pthread_mutex_unlock (&connection->response->mutex); 02167 connection->state = MHD_CONNECTION_NORMAL_BODY_READY; 02168 break; 02169 } 02170 if (connection->response->crc != NULL) 02171 pthread_mutex_unlock (&connection->response->mutex); 02172 /* not ready, no socket action */ 02173 break; 02174 case MHD_CONNECTION_CHUNKED_BODY_READY: 02175 /* nothing to do here */ 02176 break; 02177 case MHD_CONNECTION_CHUNKED_BODY_UNREADY: 02178 if (connection->response->crc != NULL) 02179 pthread_mutex_lock (&connection->response->mutex); 02180 if (MHD_YES == try_ready_chunked_body (connection)) 02181 { 02182 if (connection->response->crc != NULL) 02183 pthread_mutex_unlock (&connection->response->mutex); 02184 connection->state = MHD_CONNECTION_CHUNKED_BODY_READY; 02185 continue; 02186 } 02187 if (connection->response->crc != NULL) 02188 pthread_mutex_unlock (&connection->response->mutex); 02189 break; 02190 case MHD_CONNECTION_BODY_SENT: 02191 build_header_response (connection); 02192 if (connection->write_buffer_send_offset == 02193 connection->write_buffer_append_offset) 02194 connection->state = MHD_CONNECTION_FOOTERS_SENT; 02195 else 02196 connection->state = MHD_CONNECTION_FOOTERS_SENDING; 02197 continue; 02198 case MHD_CONNECTION_FOOTERS_SENDING: 02199 /* no default action */ 02200 break; 02201 case MHD_CONNECTION_FOOTERS_SENT: 02202 #if HAVE_DECL_TCP_CORK 02203 /* done sending, uncork */ 02204 { 02205 const int val = 0; 02206 setsockopt (connection->socket_fd, IPPROTO_TCP, TCP_CORK, &val, 02207 sizeof (val)); 02208 } 02209 #endif 02210 MHD_destroy_response (connection->response); 02211 connection->response = NULL; 02212 if (connection->daemon->notify_completed != NULL) 02213 connection->daemon->notify_completed (connection->daemon-> 02214 notify_completed_cls, 02215 connection, 02216 &connection->client_context, 02217 MHD_REQUEST_TERMINATED_COMPLETED_OK); 02218 connection->client_aware = MHD_NO; 02219 end = 02220 MHD_lookup_connection_value (connection, MHD_HEADER_KIND, 02221 MHD_HTTP_HEADER_CONNECTION); 02222 connection->client_context = NULL; 02223 connection->continue_message_write_offset = 0; 02224 connection->responseCode = 0; 02225 connection->headers_received = NULL; 02226 connection->response_write_position = 0; 02227 connection->have_chunked_upload = MHD_NO; 02228 connection->method = NULL; 02229 connection->url = NULL; 02230 connection->write_buffer = NULL; 02231 connection->write_buffer_size = 0; 02232 connection->write_buffer_send_offset = 0; 02233 connection->write_buffer_append_offset = 0; 02234 if ((end != NULL) && (0 == strcasecmp (end, "close"))) 02235 { 02236 connection->read_closed = MHD_YES; 02237 connection->read_buffer_offset = 0; 02238 } 02239 if (((MHD_YES == connection->read_closed) && 02240 (0 == connection->read_buffer_offset)) || 02241 (connection->version == NULL) || 02242 (0 != strcasecmp (MHD_HTTP_VERSION_1_1, connection->version))) 02243 { 02244 /* http 1.0, version-less requests cannot be pipelined */ 02245 connection->state = MHD_CONNECTION_CLOSED; 02246 MHD_pool_destroy (connection->pool); 02247 connection->pool = NULL; 02248 connection->read_buffer = NULL; 02249 connection->read_buffer_size = 0; 02250 connection->read_buffer_offset = 0; 02251 } 02252 else 02253 { 02254 connection->version = NULL; 02255 connection->state = MHD_CONNECTION_INIT; 02256 connection->read_buffer 02257 = MHD_pool_reset (connection->pool, 02258 connection->read_buffer, 02259 connection->read_buffer_size); 02260 } 02261 continue; 02262 case MHD_CONNECTION_CLOSED: 02263 if (connection->socket_fd != -1) 02264 connection_close_error (connection); 02265 break; 02266 default: 02267 EXTRA_CHECK (0); 02268 break; 02269 } 02270 break; 02271 } 02272 timeout = connection->daemon->connection_timeout; 02273 if ((connection->socket_fd != -1) && 02274 (timeout != 0) && 02275 (timeout < (time (NULL) - connection->last_activity)) ) 02276 { 02277 MHD_connection_close (connection, MHD_REQUEST_TERMINATED_TIMEOUT_REACHED); 02278 return MHD_NO; 02279 } 02280 return MHD_YES; 02281 } 02282 02283 02284 void 02285 MHD_set_http_callbacks_ (struct MHD_Connection *connection) 02286 { 02287 connection->read_handler = &MHD_connection_handle_read; 02288 connection->write_handler = &MHD_connection_handle_write; 02289 connection->idle_handler = &MHD_connection_handle_idle; 02290 } 02291 02292 02302 const union MHD_ConnectionInfo * 02303 MHD_get_connection_info (struct MHD_Connection *connection, 02304 enum MHD_ConnectionInfoType infoType, ...) 02305 { 02306 switch (infoType) 02307 { 02308 #if HTTPS_SUPPORT 02309 case MHD_CONNECTION_INFO_CIPHER_ALGO: 02310 if (connection->tls_session == NULL) 02311 return NULL; 02312 connection->cipher = gnutls_cipher_get (connection->tls_session); 02313 return (const union MHD_ConnectionInfo *) &connection->cipher; 02314 case MHD_CONNECTION_INFO_PROTOCOL: 02315 if (connection->tls_session == NULL) 02316 return NULL; 02317 connection->protocol = gnutls_protocol_get_version (connection->tls_session); 02318 return (const union MHD_ConnectionInfo *) &connection->protocol; 02319 case MHD_CONNECTION_INFO_GNUTLS_SESSION: 02320 if (connection->tls_session == NULL) 02321 return NULL; 02322 return (const union MHD_ConnectionInfo *) &connection->tls_session; 02323 #endif 02324 case MHD_CONNECTION_INFO_CLIENT_ADDRESS: 02325 return (const union MHD_ConnectionInfo *) &connection->addr; 02326 default: 02327 return NULL; 02328 }; 02329 } 02330 02331 02332 /* end of connection.c */