00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00028 #include "internal.h"
00029 #include <limits.h>
00030 #include "connection.h"
00031 #include "memorypool.h"
00032 #include "response.h"
00033 #include "reason_phrase.h"
00034
00035 #if HAVE_NETINET_TCP_H
00036
00037 #include <netinet/tcp.h>
00038 #endif
00039
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
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
00256
00257 connection->response_write_position = response->total_size;
00258 }
00259 if (MHD_CONNECTION_HEADERS_PROCESSED == connection->state)
00260 {
00261
00262
00263
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;
00378 #if LINUX
00379 if ( (-1 != response->fd) &&
00380 (0 == (connection->daemon->options & MHD_USE_SSL)) )
00381 {
00382
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
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];
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
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
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
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
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
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
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
00675 size = off + 2;
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;
00702
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
00718
00719
00720
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
00768
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
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
00841
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
00900
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
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
00940
00941
00942
00943
00944
00945
00946
00947
00948
00949
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
00963
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
00972
00973 break;
00974 case MHD_CONNECTION_FOOTERS_RECEIVED:
00975
00976
00977 break;
00978 case MHD_CONNECTION_HEADERS_SENDING:
00979
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
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
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;
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
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
01066 if (('\r' == rbuf[pos]) && ('\n' == rbuf[pos + 1]))
01067 rbuf[pos++] = '\0';
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
01131 if (NULL == equals)
01132 {
01133
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
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
01154 amper[0] = '\0';
01155 amper++;
01156 if ( (NULL == equals) ||
01157 (equals >= amper) )
01158 {
01159
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
01170 args = amper;
01171 continue;
01172
01173 }
01174
01175
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++;
01231
01232 sce = pos;
01233 while (((*sce) != '\0') &&
01234 ((*sce) != ',') && ((*sce) != ';') && ((*sce) != '='))
01235 sce++;
01236
01237 ekill = sce - 1;
01238 while ((*ekill == ' ') && (ekill >= pos))
01239 *(ekill--) = '\0';
01240 old = *sce;
01241 *sce = '\0';
01242 if (old != '=')
01243 {
01244
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
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;
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;
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
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;
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
01402 i = 0;
01403 if ((buffer_head[i] == '\r') || (buffer_head[i] == '\n'))
01404 i++;
01405 if ((buffer_head[i] == '\r') || (buffer_head[i] == '\n'))
01406 i++;
01407 if (i == 0)
01408 {
01409
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
01423
01424
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
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
01446
01447
01448
01449 if ((i + 1 >= available) &&
01450 !((i == 1) && (available == 2) && (buffer_head[0] == '0')))
01451 break;
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
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++;
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
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
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;
01529 used -= processed;
01530 if (connection->have_chunked_upload == MHD_YES)
01531 connection->current_chunk_offset += used;
01532
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
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
01673 colon = strchr (line, ':');
01674 if (colon == NULL)
01675 {
01676
01677 CONNECTION_CLOSE_ERROR (connection,
01678 "Received malformed line (no colon), closing connection.\n");
01679 return MHD_NO;
01680 }
01681
01682 colon[0] = '\0';
01683 colon++;
01684 while ((colon[0] != '\0') && ((colon[0] == ' ') || (colon[0] == '\t')))
01685 colon++;
01686
01687
01688
01689
01690
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
01719
01720 last_len = strlen (last);
01721
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;
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
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
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
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
01859
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
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
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;
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);
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
02179 connection->remaining_upload_size = 0;
02180
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);
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);
02267 if (connection->state == MHD_CONNECTION_CLOSED)
02268 continue;
02269 if (connection->response == NULL)
02270 break;
02271 if (MHD_NO == build_header_response (connection))
02272 {
02273
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
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
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
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
02314 break;
02315 case MHD_CONNECTION_CHUNKED_BODY_READY:
02316
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
02341 break;
02342 case MHD_CONNECTION_FOOTERS_SENT:
02343 #if HAVE_DECL_TCP_CORK
02344
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
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