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 "connection.h"
00030 #include "memorypool.h"
00031 #include "response.h"
00032 #include "reason_phrase.h"
00033
00034 #if HAVE_NETINET_TCP_H
00035
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
00241
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
00252
00253
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;
00337 #if LINUX
00338 if ( (response->fd != -1) &&
00339 (0 == (connection->daemon->options & MHD_USE_SSL)) )
00340 {
00341
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
00365
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];
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
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
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
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
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
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
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
00635 size = off + 2;
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;
00655 pos = pos->next;
00656 }
00657
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
00709
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
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
00824
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
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
00863
00864
00865
00866
00867
00868
00869
00870
00871
00872
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
00886
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
00894
00895 break;
00896 case MHD_CONNECTION_FOOTERS_RECEIVED:
00897
00898
00899 break;
00900 case MHD_CONNECTION_HEADERS_SENDING:
00901
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
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
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;
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
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
00990 if ((rbuf[pos] == '\r') && (rbuf[pos + 1] == '\n'))
00991 rbuf[pos++] = '\0';
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;
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++;
01103
01104 sce = pos;
01105 while (((*sce) != '\0') &&
01106 ((*sce) != ',') && ((*sce) != ';') && ((*sce) != '='))
01107 sce++;
01108
01109 ekill = sce - 1;
01110 while ((*ekill == ' ') && (ekill >= pos))
01111 *(ekill--) = '\0';
01112 old = *sce;
01113 *sce = '\0';
01114 if (old != '=')
01115 {
01116
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
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;
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;
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
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;
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
01276 i = 0;
01277 if ((buffer_head[i] == '\r') || (buffer_head[i] == '\n'))
01278 i++;
01279 if ((buffer_head[i] == '\r') || (buffer_head[i] == '\n'))
01280 i++;
01281 if (i == 0)
01282 {
01283
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
01300
01301
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
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
01323
01324
01325
01326 if ((i + 1 >= available) &&
01327 !((i == 1) && (available == 2) && (buffer_head[0] == '0')))
01328 break;
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
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++;
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
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
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;
01402 used -= processed;
01403 if (connection->have_chunked_upload == MHD_YES)
01404 connection->current_chunk_offset += used;
01405
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
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
01546 colon = strstr (line, ":");
01547 if (colon == NULL)
01548 {
01549
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
01558 colon[0] = '\0';
01559 colon++;
01560 while ((colon[0] != '\0') && ((colon[0] == ' ') || (colon[0] == '\t')))
01561 colon++;
01562
01563
01564
01565
01566
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
01594
01595 last_len = strlen (last);
01596
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;
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
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
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
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
01728
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
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
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;
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);
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
02037 connection->remaining_upload_size = 0;
02038
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);
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);
02123 if (connection->state == MHD_CONNECTION_CLOSED)
02124 continue;
02125 if (connection->response == NULL)
02126 break;
02127 if (MHD_NO == build_header_response (connection))
02128 {
02129
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
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
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
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
02173 break;
02174 case MHD_CONNECTION_CHUNKED_BODY_READY:
02175
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
02200 break;
02201 case MHD_CONNECTION_FOOTERS_SENT:
02202 #if HAVE_DECL_TCP_CORK
02203
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
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