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
00322 static int
00323 try_ready_normal_body (struct MHD_Connection *connection)
00324 {
00325 int ret;
00326 struct MHD_Response *response;
00327
00328 response = connection->response;
00329 if (response->crc == NULL)
00330 return MHD_YES;
00331 if ( (response->data_start <=
00332 connection->response_write_position) &&
00333 (response->data_size + response->data_start >
00334 connection->response_write_position) )
00335 return MHD_YES;
00336 #if LINUX
00337 if ( (response->fd != -1) &&
00338 (0 == (connection->daemon->options & MHD_USE_SSL)) )
00339 {
00340
00341 return MHD_YES;
00342 }
00343 #endif
00344
00345 ret = response->crc (response->crc_cls,
00346 connection->response_write_position,
00347 response->data,
00348 MHD_MIN (response->data_buffer_size,
00349 response->total_size -
00350 connection->response_write_position));
00351 if ((ret == 0) &&
00352 (0 != (connection->daemon->options & MHD_USE_SELECT_INTERNALLY)))
00353 mhd_panic (mhd_panic_cls, __FILE__, __LINE__,
00354 #if HAVE_MESSAGES
00355 "API violation"
00356 #else
00357 NULL
00358 #endif
00359 );
00360 if (ret == -1)
00361 {
00362
00363
00364 #if DEBUG_CLOSE
00365 #if HAVE_MESSAGES
00366 MHD_DLOG (connection->daemon,
00367 "Closing connection (end of response)\n");
00368 #endif
00369 #endif
00370 response->total_size = connection->response_write_position;
00371 connection_close_error (connection);
00372 return MHD_NO;
00373 }
00374 response->data_start = connection->response_write_position;
00375 response->data_size = ret;
00376 if (ret == 0)
00377 return MHD_NO;
00378 return MHD_YES;
00379 }
00380
00390 static int
00391 try_ready_chunked_body (struct MHD_Connection *connection)
00392 {
00393 int ret;
00394 char *buf;
00395 struct MHD_Response *response;
00396 size_t size;
00397 char cbuf[10];
00398 int cblen;
00399
00400 response = connection->response;
00401 if (connection->write_buffer_size == 0)
00402 {
00403 size = connection->daemon->pool_size;
00404 do
00405 {
00406 size /= 2;
00407 if (size < 128)
00408 {
00409
00410 #if DEBUG_CLOSE
00411 #if HAVE_MESSAGES
00412 MHD_DLOG (connection->daemon,
00413 "Closing connection (out of memory)\n");
00414 #endif
00415 #endif
00416 connection_close_error (connection);
00417 return MHD_NO;
00418 }
00419 buf = MHD_pool_allocate (connection->pool, size, MHD_NO);
00420 }
00421 while (buf == NULL);
00422 connection->write_buffer_size = size;
00423 connection->write_buffer = buf;
00424 }
00425
00426 if ( (response->data_start <=
00427 connection->response_write_position) &&
00428 (response->data_size + response->data_start >
00429 connection->response_write_position) )
00430 {
00431
00432 ret = response->data_size + response->data_start - connection->response_write_position;
00433 if (ret > connection->write_buffer_size - sizeof (cbuf) - 2)
00434 ret = connection->write_buffer_size - sizeof (cbuf) - 2;
00435 memcpy (&connection->write_buffer[sizeof (cbuf)],
00436 &response->data[connection->response_write_position - response->data_start],
00437 ret);
00438 }
00439 else
00440 {
00441
00442 ret = response->crc (response->crc_cls,
00443 connection->response_write_position,
00444 &connection->write_buffer[sizeof (cbuf)],
00445 connection->write_buffer_size - sizeof (cbuf) - 2);
00446 }
00447 if (ret == -1)
00448 {
00449
00450 strcpy (connection->write_buffer, "0\r\n");
00451 connection->write_buffer_append_offset = 3;
00452 connection->write_buffer_send_offset = 0;
00453 response->total_size = connection->response_write_position;
00454 return MHD_YES;
00455 }
00456 if (ret == 0)
00457 {
00458 connection->state = MHD_CONNECTION_CHUNKED_BODY_UNREADY;
00459 return MHD_NO;
00460 }
00461 if (ret > 0xFFFFFF)
00462 ret = 0xFFFFFF;
00463 snprintf (cbuf,
00464 sizeof (cbuf),
00465 "%X\r\n", ret);
00466 cblen = strlen (cbuf);
00467 EXTRA_CHECK (cblen <= sizeof (cbuf));
00468 memcpy (&connection->write_buffer[sizeof (cbuf) - cblen], cbuf, cblen);
00469 memcpy (&connection->write_buffer[sizeof (cbuf) + ret], "\r\n", 2);
00470 connection->response_write_position += ret;
00471 connection->write_buffer_send_offset = sizeof (cbuf) - cblen;
00472 connection->write_buffer_append_offset = sizeof (cbuf) + ret + 2;
00473 return MHD_YES;
00474 }
00475
00480 static void
00481 add_extra_headers (struct MHD_Connection *connection)
00482 {
00483 const char *have;
00484 char buf[128];
00485
00486 connection->have_chunked_upload = MHD_NO;
00487 if (connection->response->total_size == MHD_SIZE_UNKNOWN)
00488 {
00489 have = MHD_get_response_header (connection->response,
00490 MHD_HTTP_HEADER_CONNECTION);
00491 if ((have == NULL) || (0 != strcasecmp (have, "close")))
00492 {
00493 if ((connection->version != NULL) &&
00494 (0 == strcasecmp (connection->version, MHD_HTTP_VERSION_1_1)))
00495 {
00496 connection->have_chunked_upload = MHD_YES;
00497 have = MHD_get_response_header (connection->response,
00498 MHD_HTTP_HEADER_TRANSFER_ENCODING);
00499 if (have == NULL)
00500 MHD_add_response_header (connection->response,
00501 MHD_HTTP_HEADER_TRANSFER_ENCODING,
00502 "chunked");
00503 }
00504 else
00505 {
00506 MHD_add_response_header (connection->response,
00507 MHD_HTTP_HEADER_CONNECTION, "close");
00508 }
00509 }
00510 }
00511 else if (NULL == MHD_get_response_header (connection->response,
00512 MHD_HTTP_HEADER_CONTENT_LENGTH))
00513 {
00514 SPRINTF (buf,
00515 "%llu",
00516 (unsigned long long)connection->response->total_size);
00517 MHD_add_response_header (connection->response,
00518 MHD_HTTP_HEADER_CONTENT_LENGTH, buf);
00519 }
00520 }
00521
00528 static void
00529 get_date_string (char *date)
00530 {
00531 static const char *days[] =
00532 { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" };
00533 static const char *mons[] =
00534 { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct",
00535 "Nov", "Dec"
00536 };
00537 struct tm now;
00538 time_t t;
00539
00540 time (&t);
00541 gmtime_r (&t, &now);
00542 SPRINTF (date,
00543 "Date: %3s, %02u %3s %04u %02u:%02u:%02u GMT\r\n",
00544 days[now.tm_wday % 7],
00545 now.tm_mday,
00546 mons[now.tm_mon % 12],
00547 1900 + now.tm_year, now.tm_hour, now.tm_min, now.tm_sec);
00548 }
00549
00555 static int
00556 try_grow_read_buffer (struct MHD_Connection *connection)
00557 {
00558 void *buf;
00559
00560 buf = MHD_pool_reallocate (connection->pool,
00561 connection->read_buffer,
00562 connection->read_buffer_size,
00563 connection->read_buffer_size * 2 +
00564 MHD_BUF_INC_SIZE + 1);
00565 if (buf == NULL)
00566 return MHD_NO;
00567
00568 connection->read_buffer = buf;
00569 connection->read_buffer_size =
00570 connection->read_buffer_size * 2 + MHD_BUF_INC_SIZE;
00571 return MHD_YES;
00572 }
00573
00580 static int
00581 build_header_response (struct MHD_Connection *connection)
00582 {
00583 size_t size;
00584 size_t off;
00585 struct MHD_HTTP_Header *pos;
00586 char code[256];
00587 char date[128];
00588 char *data;
00589 enum MHD_ValueKind kind;
00590 const char *reason_phrase;
00591 uint32_t rc;
00592
00593 EXTRA_CHECK (NULL != connection->version);
00594 if (0 == strlen(connection->version))
00595 {
00596 data = MHD_pool_allocate (connection->pool, 0, MHD_YES);
00597 connection->write_buffer = data;
00598 connection->write_buffer_append_offset = 0;
00599 connection->write_buffer_send_offset = 0;
00600 connection->write_buffer_size = 0;
00601 return MHD_YES;
00602 }
00603 if (connection->state == MHD_CONNECTION_FOOTERS_RECEIVED)
00604 {
00605 add_extra_headers (connection);
00606 rc = connection->responseCode & (~MHD_ICY_FLAG);
00607 reason_phrase = MHD_get_reason_phrase_for (rc);
00608 SPRINTF (code,
00609 "%s %u %s\r\n",
00610 (0 != (connection->responseCode & MHD_ICY_FLAG))
00611 ? "ICY"
00612 : ( (0 == strcasecmp (MHD_HTTP_VERSION_1_0,
00613 connection->version))
00614 ? MHD_HTTP_VERSION_1_0
00615 : MHD_HTTP_VERSION_1_1),
00616 rc,
00617 reason_phrase);
00618 off = strlen (code);
00619
00620 size = off + 2;
00621 kind = MHD_HEADER_KIND;
00622 if (NULL == MHD_get_response_header (connection->response,
00623 MHD_HTTP_HEADER_DATE))
00624 get_date_string (date);
00625 else
00626 date[0] = '\0';
00627 size += strlen (date);
00628 }
00629 else
00630 {
00631 size = 2;
00632 kind = MHD_FOOTER_KIND;
00633 off = 0;
00634 }
00635 pos = connection->response->first_header;
00636 while (pos != NULL)
00637 {
00638 if (pos->kind == kind)
00639 size += strlen (pos->header) + strlen (pos->value) + 4;
00640 pos = pos->next;
00641 }
00642
00643 data = MHD_pool_allocate (connection->pool, size + 1, MHD_YES);
00644 if (data == NULL)
00645 {
00646 #if HAVE_MESSAGES
00647 MHD_DLOG (connection->daemon, "Not enough memory for write!\n");
00648 #endif
00649 return MHD_NO;
00650 }
00651 if (connection->state == MHD_CONNECTION_FOOTERS_RECEIVED)
00652 {
00653 memcpy (data, code, off);
00654 }
00655 pos = connection->response->first_header;
00656 while (pos != NULL)
00657 {
00658 if (pos->kind == kind)
00659 off += SPRINTF (&data[off], "%s: %s\r\n", pos->header, pos->value);
00660 pos = pos->next;
00661 }
00662 if (connection->state == MHD_CONNECTION_FOOTERS_RECEIVED)
00663 {
00664 strcpy (&data[off], date);
00665 off += strlen (date);
00666 }
00667 memcpy (&data[off], "\r\n", 2);
00668 off += 2;
00669 if (off != size)
00670 mhd_panic (mhd_panic_cls, __FILE__, __LINE__, NULL);
00671 connection->write_buffer = data;
00672 connection->write_buffer_append_offset = size;
00673 connection->write_buffer_send_offset = 0;
00674 connection->write_buffer_size = size + 1;
00675 return MHD_YES;
00676 }
00677
00685 static void
00686 transmit_error_response (struct MHD_Connection *connection,
00687 unsigned int status_code, const char *message)
00688 {
00689 struct MHD_Response *response;
00690
00691 if (connection->version == NULL)
00692 {
00693
00694
00695 connection->version = MHD_HTTP_VERSION_1_0;
00696 }
00697 connection->state = MHD_CONNECTION_FOOTERS_RECEIVED;
00698 connection->read_closed = MHD_YES;
00699 #if HAVE_MESSAGES
00700 MHD_DLOG (connection->daemon,
00701 "Error %u (`%s') processing request, closing connection.\n",
00702 status_code, message);
00703 #endif
00704 EXTRA_CHECK (connection->response == NULL);
00705 response = MHD_create_response_from_data (strlen (message),
00706 (void *) message, MHD_NO, MHD_NO);
00707 MHD_queue_response (connection, status_code, response);
00708 EXTRA_CHECK (connection->response != NULL);
00709 MHD_destroy_response (response);
00710 if (MHD_NO == build_header_response (connection))
00711 {
00712
00713 #if HAVE_MESSAGES
00714 MHD_DLOG (connection->daemon,
00715 "Closing connection (failed to create response header)\n");
00716 #endif
00717 connection->state = MHD_CONNECTION_CLOSED;
00718 }
00719 else
00720 {
00721 connection->state = MHD_CONNECTION_HEADERS_SENDING;
00722 }
00723 }
00724
00729 static void
00730 do_fd_set (int fd, fd_set * set, int *max_fd)
00731 {
00732 FD_SET (fd, set);
00733 if ( (NULL != max_fd) &&
00734 (fd > *max_fd) )
00735 *max_fd = fd;
00736 }
00737
00743 int
00744 MHD_connection_get_fdset (struct MHD_Connection *connection,
00745 fd_set * read_fd_set,
00746 fd_set * write_fd_set,
00747 fd_set * except_fd_set, int *max_fd)
00748 {
00749 int ret;
00750 struct MHD_Pollfd p;
00751
00752 memset(&p, 0, sizeof(struct MHD_Pollfd));
00753 ret = MHD_connection_get_pollfd(connection, &p);
00754 if ( (ret == MHD_YES) && (p.fd >= 0) ) {
00755 if (0 != (p.events & MHD_POLL_ACTION_IN))
00756 do_fd_set(p.fd, read_fd_set, max_fd);
00757 if (0 != (p.events & MHD_POLL_ACTION_OUT))
00758 do_fd_set(p.fd, write_fd_set, max_fd);
00759 }
00760 return ret;
00761 }
00762
00769 int
00770 MHD_connection_get_pollfd (struct MHD_Connection *connection, struct MHD_Pollfd *p)
00771 {
00772 int fd;
00773
00774 if (connection->pool == NULL)
00775 connection->pool = MHD_pool_create (connection->daemon->pool_size);
00776 if (connection->pool == NULL)
00777 {
00778 #if HAVE_MESSAGES
00779 MHD_DLOG (connection->daemon, "Failed to create memory pool!\n");
00780 #endif
00781 connection_close_error (connection);
00782 return MHD_NO;
00783 }
00784 fd = connection->socket_fd;
00785 p->fd = fd;
00786 if (fd == -1)
00787 return MHD_YES;
00788 while (1)
00789 {
00790 #if DEBUG_STATES
00791 MHD_DLOG (connection->daemon, "%s: state: %s\n",
00792 __FUNCTION__, MHD_state_to_string (connection->state));
00793 #endif
00794 switch (connection->state)
00795 {
00796 #if HTTPS_SUPPORT
00797 case MHD_TLS_CONNECTION_INIT:
00798 if (0 == gnutls_record_get_direction (connection->tls_session))
00799 p->events |= MHD_POLL_ACTION_IN;
00800 else
00801 p->events |= MHD_POLL_ACTION_OUT;
00802 break;
00803 #endif
00804 case MHD_CONNECTION_INIT:
00805 case MHD_CONNECTION_URL_RECEIVED:
00806 case MHD_CONNECTION_HEADER_PART_RECEIVED:
00807
00808
00809 if ((connection->read_closed) &&
00810 (connection->read_buffer_offset == 0))
00811 {
00812 connection->state = MHD_CONNECTION_CLOSED;
00813 continue;
00814 }
00815 if ((connection->read_buffer_offset == connection->read_buffer_size)
00816 && (MHD_NO == try_grow_read_buffer (connection)))
00817 {
00818 transmit_error_response (connection,
00819 (connection->url != NULL)
00820 ? MHD_HTTP_REQUEST_ENTITY_TOO_LARGE
00821 : MHD_HTTP_REQUEST_URI_TOO_LONG,
00822 REQUEST_TOO_BIG);
00823 continue;
00824 }
00825 if (MHD_NO == connection->read_closed)
00826 p->events |= MHD_POLL_ACTION_IN;
00827 break;
00828 case MHD_CONNECTION_HEADERS_RECEIVED:
00829
00830 EXTRA_CHECK (0);
00831 break;
00832 case MHD_CONNECTION_HEADERS_PROCESSED:
00833 EXTRA_CHECK (0);
00834 break;
00835 case MHD_CONNECTION_CONTINUE_SENDING:
00836 p->events |= MHD_POLL_ACTION_OUT;
00837 break;
00838 case MHD_CONNECTION_CONTINUE_SENT:
00839 if (connection->read_buffer_offset == connection->read_buffer_size)
00840 {
00841 if ((MHD_YES != try_grow_read_buffer (connection)) &&
00842 (0 != (connection->daemon->options &
00843 (MHD_USE_SELECT_INTERNALLY |
00844 MHD_USE_THREAD_PER_CONNECTION))))
00845 {
00846
00847
00848
00849
00850
00851
00852
00853
00854
00855
00856
00857 transmit_error_response (connection,
00858 MHD_HTTP_INTERNAL_SERVER_ERROR,
00859 INTERNAL_ERROR);
00860 continue;
00861 }
00862 }
00863 if ((connection->read_buffer_offset < connection->read_buffer_size)
00864 && (MHD_NO == connection->read_closed))
00865 p->events |= MHD_POLL_ACTION_IN;
00866 break;
00867 case MHD_CONNECTION_BODY_RECEIVED:
00868 case MHD_CONNECTION_FOOTER_PART_RECEIVED:
00869
00870
00871 if (MHD_YES == connection->read_closed)
00872 {
00873 connection->state = MHD_CONNECTION_CLOSED;
00874 continue;
00875 }
00876 p->events |= MHD_POLL_ACTION_IN;
00877
00878
00879 break;
00880 case MHD_CONNECTION_FOOTERS_RECEIVED:
00881
00882
00883 break;
00884 case MHD_CONNECTION_HEADERS_SENDING:
00885
00886 p->events |= MHD_POLL_ACTION_OUT;
00887 break;
00888 case MHD_CONNECTION_HEADERS_SENT:
00889 EXTRA_CHECK (0);
00890 break;
00891 case MHD_CONNECTION_NORMAL_BODY_READY:
00892 p->events |= MHD_POLL_ACTION_OUT;
00893 break;
00894 case MHD_CONNECTION_NORMAL_BODY_UNREADY:
00895
00896 break;
00897 case MHD_CONNECTION_CHUNKED_BODY_READY:
00898 p->events |= MHD_POLL_ACTION_OUT;
00899 break;
00900 case MHD_CONNECTION_CHUNKED_BODY_UNREADY:
00901
00902 break;
00903 case MHD_CONNECTION_BODY_SENT:
00904 EXTRA_CHECK (0);
00905 break;
00906 case MHD_CONNECTION_FOOTERS_SENDING:
00907 p->events |= MHD_POLL_ACTION_OUT;
00908 break;
00909 case MHD_CONNECTION_FOOTERS_SENT:
00910 EXTRA_CHECK (0);
00911 break;
00912 case MHD_CONNECTION_CLOSED:
00913 if (connection->socket_fd != -1)
00914 connection_close_error (connection);
00915 return MHD_YES;
00916
00917 default:
00918 EXTRA_CHECK (0);
00919 }
00920 break;
00921 }
00922 return MHD_YES;
00923 }
00924
00933 static char *
00934 get_next_header_line (struct MHD_Connection *connection)
00935 {
00936 char *rbuf;
00937 size_t pos;
00938
00939 if (connection->read_buffer_offset == 0)
00940 return NULL;
00941 pos = 0;
00942 rbuf = connection->read_buffer;
00943 while ((pos < connection->read_buffer_offset - 1) &&
00944 (rbuf[pos] != '\r') && (rbuf[pos] != '\n'))
00945 pos++;
00946 if (pos == connection->read_buffer_offset - 1)
00947 {
00948
00949 if (connection->read_buffer_offset == connection->read_buffer_size)
00950 {
00951 rbuf = MHD_pool_reallocate (connection->pool,
00952 connection->read_buffer,
00953 connection->read_buffer_size,
00954 connection->read_buffer_size * 2 +
00955 MHD_BUF_INC_SIZE);
00956 if (rbuf == NULL)
00957 {
00958 transmit_error_response (connection,
00959 (connection->url != NULL)
00960 ? MHD_HTTP_REQUEST_ENTITY_TOO_LARGE
00961 : MHD_HTTP_REQUEST_URI_TOO_LONG,
00962 REQUEST_TOO_BIG);
00963 }
00964 else
00965 {
00966 connection->read_buffer_size =
00967 connection->read_buffer_size * 2 + MHD_BUF_INC_SIZE;
00968 connection->read_buffer = rbuf;
00969 }
00970 }
00971 return NULL;
00972 }
00973
00974 if ((rbuf[pos] == '\r') && (rbuf[pos + 1] == '\n'))
00975 rbuf[pos++] = '\0';
00976 rbuf[pos++] = '\0';
00977 connection->read_buffer += pos;
00978 connection->read_buffer_size -= pos;
00979 connection->read_buffer_offset -= pos;
00980 return rbuf;
00981 }
00982
00986 static int
00987 connection_add_header (struct MHD_Connection *connection,
00988 char *key, char *value, enum MHD_ValueKind kind)
00989 {
00990 struct MHD_HTTP_Header *hdr;
00991
00992 hdr = MHD_pool_allocate (connection->pool,
00993 sizeof (struct MHD_HTTP_Header), MHD_YES);
00994 if (hdr == NULL)
00995 {
00996 #if HAVE_MESSAGES
00997 MHD_DLOG (connection->daemon,
00998 "Not enough memory to allocate header record!\n");
00999 #endif
01000 transmit_error_response (connection, MHD_HTTP_REQUEST_ENTITY_TOO_LARGE,
01001 REQUEST_TOO_BIG);
01002 return MHD_NO;
01003 }
01004 hdr->next = connection->headers_received;
01005 hdr->header = key;
01006 hdr->value = value;
01007 hdr->kind = kind;
01008 connection->headers_received = hdr;
01009 return MHD_YES;
01010 }
01011
01015 static int
01016 parse_arguments (enum MHD_ValueKind kind,
01017 struct MHD_Connection *connection, char *args)
01018 {
01019 char *equals;
01020 char *amper;
01021
01022 while (args != NULL)
01023 {
01024 equals = strstr (args, "=");
01025 if (equals == NULL)
01026 return MHD_NO;
01027 equals[0] = '\0';
01028 equals++;
01029 amper = strstr (equals, "&");
01030 if (amper != NULL)
01031 {
01032 amper[0] = '\0';
01033 amper++;
01034 }
01035 connection->daemon->unescape_callback (connection->daemon->unescape_callback_cls,
01036 connection,
01037 args);
01038 connection->daemon->unescape_callback (connection->daemon->unescape_callback_cls,
01039 connection,
01040 equals);
01041 if (MHD_NO == connection_add_header (connection, args, equals, kind))
01042 return MHD_NO;
01043 args = amper;
01044 }
01045 return MHD_YES;
01046 }
01047
01053 static int
01054 parse_cookie_header (struct MHD_Connection *connection)
01055 {
01056 const char *hdr;
01057 char *cpy;
01058 char *pos;
01059 char *sce;
01060 char *semicolon;
01061 char *equals;
01062 char *ekill;
01063 char old;
01064 int quotes;
01065
01066 hdr = MHD_lookup_connection_value (connection,
01067 MHD_HEADER_KIND,
01068 MHD_HTTP_HEADER_COOKIE);
01069 if (hdr == NULL)
01070 return MHD_YES;
01071 cpy = MHD_pool_allocate (connection->pool, strlen (hdr) + 1, MHD_YES);
01072 if (cpy == NULL)
01073 {
01074 #if HAVE_MESSAGES
01075 MHD_DLOG (connection->daemon, "Not enough memory to parse cookies!\n");
01076 #endif
01077 transmit_error_response (connection, MHD_HTTP_REQUEST_ENTITY_TOO_LARGE,
01078 REQUEST_TOO_BIG);
01079 return MHD_NO;
01080 }
01081 memcpy (cpy, hdr, strlen (hdr) + 1);
01082 pos = cpy;
01083 while (pos != NULL)
01084 {
01085 while (*pos == ' ')
01086 pos++;
01087
01088 sce = pos;
01089 while (((*sce) != '\0') &&
01090 ((*sce) != ',') && ((*sce) != ';') && ((*sce) != '='))
01091 sce++;
01092
01093 ekill = sce - 1;
01094 while ((*ekill == ' ') && (ekill >= pos))
01095 *(ekill--) = '\0';
01096 old = *sce;
01097 *sce = '\0';
01098 if (old != '=')
01099 {
01100
01101 if (MHD_NO ==
01102 connection_add_header (connection, pos, "", MHD_COOKIE_KIND))
01103 return MHD_NO;
01104 if (old == '\0')
01105 break;
01106 pos = sce + 1;
01107 continue;
01108 }
01109 equals = sce + 1;
01110 quotes = 0;
01111 semicolon = equals;
01112 while ((semicolon[0] != '\0') &&
01113 ((quotes != 0) ||
01114 ((semicolon[0] != ';') && (semicolon[0] != ','))))
01115 {
01116 if (semicolon[0] == '"')
01117 quotes = (quotes + 1) & 1;
01118 semicolon++;
01119 }
01120 if (semicolon[0] == '\0')
01121 semicolon = NULL;
01122 if (semicolon != NULL)
01123 {
01124 semicolon[0] = '\0';
01125 semicolon++;
01126 }
01127
01128 if ((equals[0] == '"') && (equals[strlen (equals) - 1] == '"'))
01129 {
01130 equals[strlen (equals) - 1] = '\0';
01131 equals++;
01132 }
01133 if (MHD_NO == connection_add_header (connection,
01134 pos, equals, MHD_COOKIE_KIND))
01135 return MHD_NO;
01136 pos = semicolon;
01137 }
01138 return MHD_YES;
01139 }
01140
01148 static int
01149 parse_initial_message_line (struct MHD_Connection *connection, char *line)
01150 {
01151 char *uri;
01152 char *httpVersion;
01153 char *args;
01154
01155 uri = strstr (line, " ");
01156 if (uri == NULL)
01157 return MHD_NO;
01158 uri[0] = '\0';
01159 connection->method = line;
01160 uri++;
01161 while (uri[0] == ' ')
01162 uri++;
01163 httpVersion = strstr (uri, " ");
01164 if (httpVersion != NULL)
01165 {
01166 httpVersion[0] = '\0';
01167 httpVersion++;
01168 }
01169 if (connection->daemon->uri_log_callback != NULL)
01170 connection->client_context
01171 =
01172 connection->daemon->uri_log_callback (connection->daemon->
01173 uri_log_callback_cls, uri);
01174 args = strstr (uri, "?");
01175 if (args != NULL)
01176 {
01177 args[0] = '\0';
01178 args++;
01179 parse_arguments (MHD_GET_ARGUMENT_KIND, connection, args);
01180 }
01181 connection->daemon->unescape_callback (connection->daemon->unescape_callback_cls,
01182 connection,
01183 uri);
01184 connection->url = uri;
01185 if (httpVersion == NULL)
01186 connection->version = "";
01187 else
01188 connection->version = httpVersion;
01189 return MHD_YES;
01190 }
01191
01192
01198 static void
01199 call_connection_handler (struct MHD_Connection *connection)
01200 {
01201 size_t processed;
01202
01203 if (connection->response != NULL)
01204 return;
01205 processed = 0;
01206 connection->client_aware = MHD_YES;
01207 if (MHD_NO ==
01208 connection->daemon->default_handler (connection->daemon->
01209 default_handler_cls,
01210 connection, connection->url,
01211 connection->method,
01212 connection->version,
01213 NULL, &processed,
01214 &connection->client_context))
01215 {
01216
01217 #if HAVE_MESSAGES
01218 MHD_DLOG (connection->daemon,
01219 "Internal application error, closing connection.\n");
01220 #endif
01221 connection_close_error (connection);
01222 return;
01223 }
01224 }
01225
01226
01227
01233 static void
01234 process_request_body (struct MHD_Connection *connection)
01235 {
01236 size_t processed;
01237 size_t available;
01238 size_t used;
01239 size_t i;
01240 int instant_retry;
01241 int malformed;
01242 char *buffer_head;
01243
01244 if (connection->response != NULL)
01245 return;
01246
01247 buffer_head = connection->read_buffer;
01248 available = connection->read_buffer_offset;
01249 do
01250 {
01251 instant_retry = MHD_NO;
01252 if ((connection->have_chunked_upload == MHD_YES) &&
01253 (connection->remaining_upload_size == MHD_SIZE_UNKNOWN))
01254 {
01255 if ((connection->current_chunk_offset ==
01256 connection->current_chunk_size)
01257 && (connection->current_chunk_offset != 0) && (available >= 2))
01258 {
01259
01260 i = 0;
01261 if ((buffer_head[i] == '\r') || (buffer_head[i] == '\n'))
01262 i++;
01263 if ((buffer_head[i] == '\r') || (buffer_head[i] == '\n'))
01264 i++;
01265 if (i == 0)
01266 {
01267
01268 #if HAVE_MESSAGES
01269 MHD_DLOG (connection->daemon,
01270 "Received malformed HTTP request (bad chunked encoding), closing connection.\n");
01271 #endif
01272 connection_close_error (connection);
01273 return;
01274 }
01275 available -= i;
01276 buffer_head += i;
01277 connection->current_chunk_offset = 0;
01278 connection->current_chunk_size = 0;
01279 }
01280 if (connection->current_chunk_offset <
01281 connection->current_chunk_size)
01282 {
01283
01284
01285
01286 processed =
01287 connection->current_chunk_size -
01288 connection->current_chunk_offset;
01289 if (processed > available)
01290 processed = available;
01291 if (available > processed)
01292 instant_retry = MHD_YES;
01293 }
01294 else
01295 {
01296
01297 i = 0;
01298 while (i < available)
01299 {
01300 if ((buffer_head[i] == '\r') || (buffer_head[i] == '\n'))
01301 break;
01302 i++;
01303 if (i >= 6)
01304 break;
01305 }
01306
01307
01308
01309
01310 if ((i + 1 >= available) &&
01311 !((i == 1) && (available == 2) && (buffer_head[0] == '0')))
01312 break;
01313 malformed = (i >= 6);
01314 if (!malformed)
01315 {
01316 buffer_head[i] = '\0';
01317 malformed =
01318 (1 != SSCANF (buffer_head, "%X",
01319 &connection->current_chunk_size)) &&
01320 (1 != SSCANF (buffer_head, "%x",
01321 &connection->current_chunk_size));
01322 }
01323 if (malformed)
01324 {
01325
01326 #if HAVE_MESSAGES
01327 MHD_DLOG (connection->daemon,
01328 "Received malformed HTTP request (bad chunked encoding), closing connection.\n");
01329 #endif
01330 connection_close_error (connection);
01331 return;
01332 }
01333 i++;
01334 if ((i < available) &&
01335 ((buffer_head[i] == '\r') || (buffer_head[i] == '\n')))
01336 i++;
01337
01338 buffer_head += i;
01339 available -= i;
01340 connection->current_chunk_offset = 0;
01341
01342 if (available > 0)
01343 instant_retry = MHD_YES;
01344 if (connection->current_chunk_size == 0)
01345 {
01346 connection->remaining_upload_size = 0;
01347 break;
01348 }
01349 continue;
01350 }
01351 }
01352 else
01353 {
01354
01355 processed = available;
01356 }
01357 used = processed;
01358 connection->client_aware = MHD_YES;
01359 if (MHD_NO ==
01360 connection->daemon->default_handler (connection->daemon->
01361 default_handler_cls,
01362 connection, connection->url,
01363 connection->method,
01364 connection->version,
01365 buffer_head, &processed,
01366 &connection->client_context))
01367 {
01368
01369 #if HAVE_MESSAGES
01370 MHD_DLOG (connection->daemon,
01371 "Internal application error, closing connection.\n");
01372 #endif
01373 connection_close_error (connection);
01374 return;
01375 }
01376 if (processed > used)
01377 mhd_panic (mhd_panic_cls, __FILE__, __LINE__,
01378 #if HAVE_MESSAGES
01379 "API violation"
01380 #else
01381 NULL
01382 #endif
01383 );
01384 if (processed != 0)
01385 instant_retry = MHD_NO;
01386 used -= processed;
01387 if (connection->have_chunked_upload == MHD_YES)
01388 connection->current_chunk_offset += used;
01389
01390 buffer_head += used;
01391 available -= used;
01392 if (connection->remaining_upload_size != MHD_SIZE_UNKNOWN)
01393 connection->remaining_upload_size -= used;
01394 }
01395 while (instant_retry == MHD_YES);
01396 if (available > 0)
01397 memmove (connection->read_buffer, buffer_head, available);
01398 connection->read_buffer_offset = available;
01399 }
01400
01409 static int
01410 do_read (struct MHD_Connection *connection)
01411 {
01412 int bytes_read;
01413
01414 if (connection->read_buffer_size == connection->read_buffer_offset)
01415 return MHD_NO;
01416
01417 bytes_read = connection->recv_cls (connection,
01418 &connection->read_buffer
01419 [connection->read_buffer_offset],
01420 connection->read_buffer_size -
01421 connection->read_buffer_offset);
01422 if (bytes_read < 0)
01423 {
01424 if (errno == EINTR)
01425 return MHD_NO;
01426 #if HAVE_MESSAGES
01427 #if HTTPS_SUPPORT
01428 if (0 != (connection->daemon->options & MHD_USE_SSL))
01429 MHD_DLOG (connection->daemon,
01430 "Failed to receive data: %s\n",
01431 gnutls_strerror (bytes_read));
01432 else
01433 #endif
01434 MHD_DLOG (connection->daemon,
01435 "Failed to receive data: %s\n", STRERROR (errno));
01436 #endif
01437 connection_close_error (connection);
01438 return MHD_YES;
01439 }
01440 if (bytes_read == 0)
01441 {
01442
01443 connection->read_closed = MHD_YES;
01444 SHUTDOWN (connection->socket_fd, SHUT_RD);
01445 return MHD_NO;
01446 }
01447 connection->read_buffer_offset += bytes_read;
01448 return MHD_YES;
01449 }
01450
01458 static int
01459 do_write (struct MHD_Connection *connection)
01460 {
01461 int ret;
01462
01463 ret = connection->send_cls (connection,
01464 &connection->write_buffer
01465 [connection->write_buffer_send_offset],
01466 connection->write_buffer_append_offset
01467 - connection->write_buffer_send_offset);
01468
01469 if (ret < 0)
01470 {
01471 if (errno == EINTR)
01472 return MHD_NO;
01473 #if HAVE_MESSAGES
01474 #if HTTPS_SUPPORT
01475 if (0 != (connection->daemon->options & MHD_USE_SSL))
01476 MHD_DLOG (connection->daemon,
01477 "Failed to send data: %s\n",
01478 gnutls_strerror (ret));
01479 else
01480 #endif
01481 MHD_DLOG (connection->daemon,
01482 "Failed to send data: %s\n", STRERROR (errno));
01483 #endif
01484 connection_close_error (connection);
01485 return MHD_YES;
01486 }
01487 #if DEBUG_SEND_DATA
01488 FPRINTF (stderr,
01489 "Sent response: `%.*s'\n",
01490 ret,
01491 &connection->write_buffer[connection->write_buffer_send_offset]);
01492 #endif
01493 connection->write_buffer_send_offset += ret;
01494 return MHD_YES;
01495 }
01496
01502 static int
01503 check_write_done (struct MHD_Connection *connection,
01504 enum MHD_CONNECTION_STATE next_state)
01505 {
01506 if (connection->write_buffer_append_offset !=
01507 connection->write_buffer_send_offset)
01508 return MHD_NO;
01509 connection->write_buffer_append_offset = 0;
01510 connection->write_buffer_send_offset = 0;
01511 connection->state = next_state;
01512 MHD_pool_reallocate (connection->pool, connection->write_buffer,
01513 connection->write_buffer_size, 0);
01514 connection->write_buffer = NULL;
01515 connection->write_buffer_size = 0;
01516 return MHD_YES;
01517 }
01518
01524 static int
01525 process_header_line (struct MHD_Connection *connection, char *line)
01526 {
01527 char *colon;
01528
01529
01530 colon = strstr (line, ":");
01531 if (colon == NULL)
01532 {
01533
01534 #if HAVE_MESSAGES
01535 MHD_DLOG (connection->daemon,
01536 "Received malformed line (no colon), closing connection.\n");
01537 #endif
01538 connection->state = MHD_CONNECTION_CLOSED;
01539 return MHD_NO;
01540 }
01541
01542 colon[0] = '\0';
01543 colon++;
01544 while ((colon[0] != '\0') && ((colon[0] == ' ') || (colon[0] == '\t')))
01545 colon++;
01546
01547
01548
01549
01550
01551 connection->last = line;
01552 connection->colon = colon;
01553 return MHD_YES;
01554 }
01555
01565 static int
01566 process_broken_line (struct MHD_Connection *connection,
01567 char *line, enum MHD_ValueKind kind)
01568 {
01569 char *last;
01570 char *tmp;
01571 size_t last_len;
01572 size_t tmp_len;
01573
01574 last = connection->last;
01575 if ((line[0] == ' ') || (line[0] == '\t'))
01576 {
01577
01578
01579 last_len = strlen (last);
01580
01581 tmp = line;
01582 while ((tmp[0] == ' ') || (tmp[0] == '\t'))
01583 tmp++;
01584 tmp_len = strlen (tmp);
01585 last = MHD_pool_reallocate (connection->pool,
01586 last,
01587 last_len + 1,
01588 last_len + tmp_len + 1);
01589 if (last == NULL)
01590 {
01591 transmit_error_response (connection,
01592 MHD_HTTP_REQUEST_ENTITY_TOO_LARGE,
01593 REQUEST_TOO_BIG);
01594 return MHD_NO;
01595 }
01596 memcpy (&last[last_len], tmp, tmp_len + 1);
01597 connection->last = last;
01598 return MHD_YES;
01599 }
01600 EXTRA_CHECK ((last != NULL) && (connection->colon != NULL));
01601 if ((MHD_NO == connection_add_header (connection,
01602 last, connection->colon, kind)))
01603 {
01604 transmit_error_response (connection, MHD_HTTP_REQUEST_ENTITY_TOO_LARGE,
01605 REQUEST_TOO_BIG);
01606 return MHD_NO;
01607 }
01608
01609 if (strlen (line) != 0)
01610 {
01611 if (MHD_NO == process_header_line (connection, line))
01612 {
01613 transmit_error_response (connection,
01614 MHD_HTTP_BAD_REQUEST, REQUEST_MALFORMED);
01615 return MHD_NO;
01616 }
01617 }
01618 return MHD_YES;
01619 }
01620
01626 static void
01627 parse_connection_headers (struct MHD_Connection *connection)
01628 {
01629 const char *clen;
01630 unsigned long long cval;
01631 struct MHD_Response *response;
01632 const char *enc;
01633
01634 parse_cookie_header (connection);
01635 if ((0 != (MHD_USE_PEDANTIC_CHECKS & connection->daemon->options))
01636 && (NULL != connection->version)
01637 && (0 == strcasecmp (MHD_HTTP_VERSION_1_1, connection->version))
01638 && (NULL ==
01639 MHD_lookup_connection_value (connection, MHD_HEADER_KIND,
01640 MHD_HTTP_HEADER_HOST)))
01641 {
01642
01643 connection->state = MHD_CONNECTION_FOOTERS_RECEIVED;
01644 connection->read_closed = MHD_YES;
01645 #if HAVE_MESSAGES
01646 MHD_DLOG (connection->daemon,
01647 "Received `%s' request without `%s' header.\n",
01648 MHD_HTTP_VERSION_1_1, MHD_HTTP_HEADER_HOST);
01649 #endif
01650 EXTRA_CHECK (connection->response == NULL);
01651 response =
01652 MHD_create_response_from_data (strlen (REQUEST_LACKS_HOST),
01653 REQUEST_LACKS_HOST, MHD_NO, MHD_NO);
01654 MHD_queue_response (connection, MHD_HTTP_BAD_REQUEST, response);
01655 MHD_destroy_response (response);
01656 return;
01657 }
01658
01659 clen = MHD_lookup_connection_value (connection,
01660 MHD_HEADER_KIND,
01661 MHD_HTTP_HEADER_CONTENT_LENGTH);
01662 if (clen != NULL)
01663 {
01664 if (1 != SSCANF (clen, "%llu", &cval))
01665 {
01666 #if HAVE_MESSAGES
01667 MHD_DLOG (connection->daemon,
01668 "Failed to parse `%s' header `%s', closing connection.\n",
01669 MHD_HTTP_HEADER_CONTENT_LENGTH, clen);
01670 #endif
01671 connection->state = MHD_CONNECTION_CLOSED;
01672 return;
01673 }
01674 connection->remaining_upload_size = cval;
01675 }
01676 else
01677 {
01678 enc = MHD_lookup_connection_value (connection,
01679 MHD_HEADER_KIND,
01680 MHD_HTTP_HEADER_TRANSFER_ENCODING);
01681 if (NULL == enc)
01682 {
01683
01684 connection->remaining_upload_size = 0;
01685 }
01686 else
01687 {
01688 connection->remaining_upload_size = MHD_SIZE_UNKNOWN;
01689 if (0 == strcasecmp (enc, "chunked"))
01690 connection->have_chunked_upload = MHD_YES;
01691 }
01692 }
01693 }
01694
01704 int
01705 MHD_connection_handle_read (struct MHD_Connection *connection)
01706 {
01707 connection->last_activity = time (NULL);
01708 if (connection->state == MHD_CONNECTION_CLOSED)
01709 return MHD_NO;
01710
01711
01712 if (connection->read_buffer_offset + MHD_BUF_INC_SIZE >
01713 connection->read_buffer_size)
01714 try_grow_read_buffer (connection);
01715 if (MHD_NO == do_read (connection))
01716 return MHD_YES;
01717 while (1)
01718 {
01719 #if DEBUG_STATES
01720 MHD_DLOG (connection->daemon, "%s: state: %s\n",
01721 __FUNCTION__, MHD_state_to_string (connection->state));
01722 #endif
01723 switch (connection->state)
01724 {
01725 case MHD_CONNECTION_INIT:
01726 case MHD_CONNECTION_URL_RECEIVED:
01727 case MHD_CONNECTION_HEADER_PART_RECEIVED:
01728 case MHD_CONNECTION_HEADERS_RECEIVED:
01729 case MHD_CONNECTION_HEADERS_PROCESSED:
01730 case MHD_CONNECTION_CONTINUE_SENDING:
01731 case MHD_CONNECTION_CONTINUE_SENT:
01732 case MHD_CONNECTION_BODY_RECEIVED:
01733 case MHD_CONNECTION_FOOTER_PART_RECEIVED:
01734
01735 if (MHD_YES == connection->read_closed)
01736 {
01737 connection->state = MHD_CONNECTION_CLOSED;
01738 continue;
01739 }
01740 break;
01741 case MHD_CONNECTION_CLOSED:
01742 if (connection->socket_fd != -1)
01743 connection_close_error (connection);
01744 return MHD_NO;
01745 default:
01746
01747 MHD_pool_reallocate (connection->pool,
01748 connection->read_buffer,
01749 connection->read_buffer_size + 1,
01750 connection->read_buffer_offset);
01751 break;
01752 }
01753 break;
01754 }
01755 return MHD_YES;
01756 }
01757
01767 int
01768 MHD_connection_handle_write (struct MHD_Connection *connection)
01769 {
01770 struct MHD_Response *response;
01771 int ret;
01772 connection->last_activity = time (NULL);
01773 while (1)
01774 {
01775 #if DEBUG_STATES
01776 MHD_DLOG (connection->daemon, "%s: state: %s\n",
01777 __FUNCTION__, MHD_state_to_string (connection->state));
01778 #endif
01779 switch (connection->state)
01780 {
01781 case MHD_CONNECTION_INIT:
01782 case MHD_CONNECTION_URL_RECEIVED:
01783 case MHD_CONNECTION_HEADER_PART_RECEIVED:
01784 case MHD_CONNECTION_HEADERS_RECEIVED:
01785 EXTRA_CHECK (0);
01786 break;
01787 case MHD_CONNECTION_HEADERS_PROCESSED:
01788 break;
01789 case MHD_CONNECTION_CONTINUE_SENDING:
01790 ret = connection->send_cls (connection,
01791 &HTTP_100_CONTINUE
01792 [connection->continue_message_write_offset],
01793 strlen (HTTP_100_CONTINUE) -
01794 connection->continue_message_write_offset);
01795 if (ret < 0)
01796 {
01797 if (errno == EINTR)
01798 break;
01799 #if HAVE_MESSAGES
01800 MHD_DLOG (connection->daemon,
01801 "Failed to send data: %s\n", STRERROR (errno));
01802 #endif
01803 connection_close_error (connection);
01804 return MHD_NO;
01805 }
01806 #if DEBUG_SEND_DATA
01807 FPRINTF (stderr,
01808 "Sent 100 continue response: `%.*s'\n",
01809 ret,
01810 &HTTP_100_CONTINUE
01811 [connection->continue_message_write_offset]);
01812 #endif
01813 connection->continue_message_write_offset += ret;
01814 break;
01815 case MHD_CONNECTION_CONTINUE_SENT:
01816 case MHD_CONNECTION_BODY_RECEIVED:
01817 case MHD_CONNECTION_FOOTER_PART_RECEIVED:
01818 case MHD_CONNECTION_FOOTERS_RECEIVED:
01819 EXTRA_CHECK (0);
01820 break;
01821 case MHD_CONNECTION_HEADERS_SENDING:
01822 do_write (connection);
01823 check_write_done (connection, MHD_CONNECTION_HEADERS_SENT);
01824 break;
01825 case MHD_CONNECTION_HEADERS_SENT:
01826 EXTRA_CHECK (0);
01827 break;
01828 case MHD_CONNECTION_NORMAL_BODY_READY:
01829 response = connection->response;
01830 if (response->crc != NULL)
01831 pthread_mutex_lock (&response->mutex);
01832 if (MHD_YES != try_ready_normal_body (connection))
01833 {
01834 if (response->crc != NULL)
01835 pthread_mutex_unlock (&response->mutex);
01836 connection->state = MHD_CONNECTION_NORMAL_BODY_UNREADY;
01837 break;
01838 }
01839 ret = connection->send_cls (connection,
01840 &response->data
01841 [connection->response_write_position
01842 - response->data_start],
01843 response->data_size -
01844 (connection->response_write_position
01845 - response->data_start));
01846 #if DEBUG_SEND_DATA
01847 if (ret > 0)
01848 FPRINTF (stderr,
01849 "Sent DATA response: `%.*s'\n",
01850 ret,
01851 &response->data[connection->response_write_position -
01852 response->data_start]);
01853 #endif
01854 if (response->crc != NULL)
01855 pthread_mutex_unlock (&response->mutex);
01856 if (ret < 0)
01857 {
01858 if (errno == EINTR)
01859 return MHD_YES;
01860 #if HAVE_MESSAGES
01861 MHD_DLOG (connection->daemon,
01862 "Failed to send data: %s\n", STRERROR (errno));
01863 #endif
01864 connection_close_error (connection);
01865 return MHD_NO;
01866 }
01867 connection->response_write_position += ret;
01868 if (connection->response_write_position ==
01869 connection->response->total_size)
01870 connection->state = MHD_CONNECTION_FOOTERS_SENT;
01871 break;
01872 case MHD_CONNECTION_NORMAL_BODY_UNREADY:
01873 EXTRA_CHECK (0);
01874 break;
01875 case MHD_CONNECTION_CHUNKED_BODY_READY:
01876 do_write (connection);
01877 check_write_done (connection,
01878 (connection->response->total_size ==
01879 connection->response_write_position) ?
01880 MHD_CONNECTION_BODY_SENT :
01881 MHD_CONNECTION_CHUNKED_BODY_UNREADY);
01882 break;
01883 case MHD_CONNECTION_CHUNKED_BODY_UNREADY:
01884 case MHD_CONNECTION_BODY_SENT:
01885 EXTRA_CHECK (0);
01886 break;
01887 case MHD_CONNECTION_FOOTERS_SENDING:
01888 do_write (connection);
01889 check_write_done (connection, MHD_CONNECTION_FOOTERS_SENT);
01890 break;
01891 case MHD_CONNECTION_FOOTERS_SENT:
01892 EXTRA_CHECK (0);
01893 break;
01894 case MHD_CONNECTION_CLOSED:
01895 if (connection->socket_fd != -1)
01896 connection_close_error (connection);
01897 return MHD_NO;
01898 case MHD_TLS_CONNECTION_INIT:
01899 EXTRA_CHECK (0);
01900 break;
01901 default:
01902 EXTRA_CHECK (0);
01903 connection_close_error (connection);
01904 return MHD_NO;
01905 }
01906 break;
01907 }
01908 return MHD_YES;
01909 }
01910
01920 int
01921 MHD_connection_handle_idle (struct MHD_Connection *connection)
01922 {
01923 unsigned int timeout;
01924 const char *end;
01925 char *line;
01926
01927 while (1)
01928 {
01929 #if DEBUG_STATES
01930 MHD_DLOG (connection->daemon, "%s: state: %s\n",
01931 __FUNCTION__, MHD_state_to_string (connection->state));
01932 #endif
01933 switch (connection->state)
01934 {
01935 case MHD_CONNECTION_INIT:
01936 line = get_next_header_line (connection);
01937 if (line == NULL)
01938 {
01939 if (connection->state != MHD_CONNECTION_INIT)
01940 continue;
01941 if (connection->read_closed)
01942 {
01943 connection->state = MHD_CONNECTION_CLOSED;
01944 continue;
01945 }
01946 break;
01947 }
01948 if (MHD_NO == parse_initial_message_line (connection, line))
01949 connection->state = MHD_CONNECTION_CLOSED;
01950 else
01951 connection->state = MHD_CONNECTION_URL_RECEIVED;
01952 continue;
01953 case MHD_CONNECTION_URL_RECEIVED:
01954 line = get_next_header_line (connection);
01955 if (line == NULL)
01956 {
01957 if (connection->state != MHD_CONNECTION_URL_RECEIVED)
01958 continue;
01959 if (connection->read_closed)
01960 {
01961 connection->state = MHD_CONNECTION_CLOSED;
01962 continue;
01963 }
01964 break;
01965 }
01966 if (strlen (line) == 0)
01967 {
01968 connection->state = MHD_CONNECTION_HEADERS_RECEIVED;
01969 continue;
01970 }
01971 if (MHD_NO == process_header_line (connection, line))
01972 {
01973 transmit_error_response (connection,
01974 MHD_HTTP_BAD_REQUEST,
01975 REQUEST_MALFORMED);
01976 break;
01977 }
01978 connection->state = MHD_CONNECTION_HEADER_PART_RECEIVED;
01979 continue;
01980 case MHD_CONNECTION_HEADER_PART_RECEIVED:
01981 line = get_next_header_line (connection);
01982 if (line == NULL)
01983 {
01984 if (connection->state != MHD_CONNECTION_HEADER_PART_RECEIVED)
01985 continue;
01986 if (connection->read_closed)
01987 {
01988 connection->state = MHD_CONNECTION_CLOSED;
01989 continue;
01990 }
01991 break;
01992 }
01993 if (MHD_NO ==
01994 process_broken_line (connection, line, MHD_HEADER_KIND))
01995 continue;
01996 if (strlen (line) == 0)
01997 {
01998 connection->state = MHD_CONNECTION_HEADERS_RECEIVED;
01999 continue;
02000 }
02001 continue;
02002 case MHD_CONNECTION_HEADERS_RECEIVED:
02003 parse_connection_headers (connection);
02004 if (connection->state == MHD_CONNECTION_CLOSED)
02005 continue;
02006 connection->state = MHD_CONNECTION_HEADERS_PROCESSED;
02007 continue;
02008 case MHD_CONNECTION_HEADERS_PROCESSED:
02009 call_connection_handler (connection);
02010 if (connection->state == MHD_CONNECTION_CLOSED)
02011 continue;
02012 if (need_100_continue (connection))
02013 {
02014 connection->state = MHD_CONNECTION_CONTINUE_SENDING;
02015 break;
02016 }
02017 if (connection->response != NULL)
02018 {
02019
02020 connection->remaining_upload_size = 0;
02021
02022 connection->read_closed = MHD_YES;
02023 }
02024 connection->state = (connection->remaining_upload_size == 0)
02025 ? MHD_CONNECTION_FOOTERS_RECEIVED : MHD_CONNECTION_CONTINUE_SENT;
02026 continue;
02027 case MHD_CONNECTION_CONTINUE_SENDING:
02028 if (connection->continue_message_write_offset ==
02029 strlen (HTTP_100_CONTINUE))
02030 {
02031 connection->state = MHD_CONNECTION_CONTINUE_SENT;
02032 continue;
02033 }
02034 break;
02035 case MHD_CONNECTION_CONTINUE_SENT:
02036 if (connection->read_buffer_offset != 0)
02037 {
02038 process_request_body (connection);
02039 if (connection->state == MHD_CONNECTION_CLOSED)
02040 continue;
02041 }
02042 if ((connection->remaining_upload_size == 0) ||
02043 ((connection->remaining_upload_size == MHD_SIZE_UNKNOWN) &&
02044 (connection->read_buffer_offset == 0) &&
02045 (MHD_YES == connection->read_closed)))
02046 {
02047 if ((MHD_YES == connection->have_chunked_upload) &&
02048 (MHD_NO == connection->read_closed))
02049 connection->state = MHD_CONNECTION_BODY_RECEIVED;
02050 else
02051 connection->state = MHD_CONNECTION_FOOTERS_RECEIVED;
02052 continue;
02053 }
02054 break;
02055 case MHD_CONNECTION_BODY_RECEIVED:
02056 line = get_next_header_line (connection);
02057 if (line == NULL)
02058 {
02059 if (connection->state != MHD_CONNECTION_BODY_RECEIVED)
02060 continue;
02061 if (connection->read_closed)
02062 {
02063 connection->state = MHD_CONNECTION_CLOSED;
02064 continue;
02065 }
02066 break;
02067 }
02068 if (strlen (line) == 0)
02069 {
02070 connection->state = MHD_CONNECTION_FOOTERS_RECEIVED;
02071 continue;
02072 }
02073 if (MHD_NO == process_header_line (connection, line))
02074 {
02075 transmit_error_response (connection,
02076 MHD_HTTP_BAD_REQUEST,
02077 REQUEST_MALFORMED);
02078 break;
02079 }
02080 connection->state = MHD_CONNECTION_FOOTER_PART_RECEIVED;
02081 continue;
02082 case MHD_CONNECTION_FOOTER_PART_RECEIVED:
02083 line = get_next_header_line (connection);
02084 if (line == NULL)
02085 {
02086 if (connection->state != MHD_CONNECTION_FOOTER_PART_RECEIVED)
02087 continue;
02088 if (connection->read_closed)
02089 {
02090 connection->state = MHD_CONNECTION_CLOSED;
02091 continue;
02092 }
02093 break;
02094 }
02095 if (MHD_NO ==
02096 process_broken_line (connection, line, MHD_FOOTER_KIND))
02097 continue;
02098 if (strlen (line) == 0)
02099 {
02100 connection->state = MHD_CONNECTION_FOOTERS_RECEIVED;
02101 continue;
02102 }
02103 continue;
02104 case MHD_CONNECTION_FOOTERS_RECEIVED:
02105 call_connection_handler (connection);
02106 if (connection->state == MHD_CONNECTION_CLOSED)
02107 continue;
02108 if (connection->response == NULL)
02109 break;
02110 if (MHD_NO == build_header_response (connection))
02111 {
02112
02113 #if HAVE_MESSAGES
02114 MHD_DLOG (connection->daemon,
02115 "Closing connection (failed to create response header)\n");
02116 #endif
02117 connection->state = MHD_CONNECTION_CLOSED;
02118 continue;
02119 }
02120 connection->state = MHD_CONNECTION_HEADERS_SENDING;
02121
02122 #if HAVE_DECL_TCP_CORK
02123
02124 {
02125 const int val = 1;
02126 setsockopt (connection->socket_fd, IPPROTO_TCP, TCP_CORK, &val,
02127 sizeof (val));
02128 }
02129 #endif
02130 break;
02131 case MHD_CONNECTION_HEADERS_SENDING:
02132
02133 break;
02134 case MHD_CONNECTION_HEADERS_SENT:
02135 if (connection->have_chunked_upload)
02136 connection->state = MHD_CONNECTION_CHUNKED_BODY_UNREADY;
02137 else
02138 connection->state = MHD_CONNECTION_NORMAL_BODY_UNREADY;
02139 continue;
02140 case MHD_CONNECTION_NORMAL_BODY_READY:
02141
02142 break;
02143 case MHD_CONNECTION_NORMAL_BODY_UNREADY:
02144 if (connection->response->crc != NULL)
02145 pthread_mutex_lock (&connection->response->mutex);
02146 if (MHD_YES == try_ready_normal_body (connection))
02147 {
02148 if (connection->response->crc != NULL)
02149 pthread_mutex_unlock (&connection->response->mutex);
02150 connection->state = MHD_CONNECTION_NORMAL_BODY_READY;
02151 break;
02152 }
02153 if (connection->response->crc != NULL)
02154 pthread_mutex_unlock (&connection->response->mutex);
02155
02156 break;
02157 case MHD_CONNECTION_CHUNKED_BODY_READY:
02158
02159 break;
02160 case MHD_CONNECTION_CHUNKED_BODY_UNREADY:
02161 if (connection->response->crc != NULL)
02162 pthread_mutex_lock (&connection->response->mutex);
02163 if (MHD_YES == try_ready_chunked_body (connection))
02164 {
02165 if (connection->response->crc != NULL)
02166 pthread_mutex_unlock (&connection->response->mutex);
02167 connection->state = MHD_CONNECTION_CHUNKED_BODY_READY;
02168 continue;
02169 }
02170 if (connection->response->crc != NULL)
02171 pthread_mutex_unlock (&connection->response->mutex);
02172 break;
02173 case MHD_CONNECTION_BODY_SENT:
02174 build_header_response (connection);
02175 if (connection->write_buffer_send_offset ==
02176 connection->write_buffer_append_offset)
02177 connection->state = MHD_CONNECTION_FOOTERS_SENT;
02178 else
02179 connection->state = MHD_CONNECTION_FOOTERS_SENDING;
02180 continue;
02181 case MHD_CONNECTION_FOOTERS_SENDING:
02182
02183 break;
02184 case MHD_CONNECTION_FOOTERS_SENT:
02185 #if HAVE_DECL_TCP_CORK
02186
02187 {
02188 const int val = 0;
02189 setsockopt (connection->socket_fd, IPPROTO_TCP, TCP_CORK, &val,
02190 sizeof (val));
02191 }
02192 #endif
02193 MHD_destroy_response (connection->response);
02194 connection->response = NULL;
02195 if (connection->daemon->notify_completed != NULL)
02196 connection->daemon->notify_completed (connection->daemon->
02197 notify_completed_cls,
02198 connection,
02199 &connection->client_context,
02200 MHD_REQUEST_TERMINATED_COMPLETED_OK);
02201 connection->client_aware = MHD_NO;
02202 end =
02203 MHD_lookup_connection_value (connection, MHD_HEADER_KIND,
02204 MHD_HTTP_HEADER_CONNECTION);
02205 connection->client_context = NULL;
02206 connection->continue_message_write_offset = 0;
02207 connection->responseCode = 0;
02208 connection->headers_received = NULL;
02209 connection->response_write_position = 0;
02210 connection->have_chunked_upload = MHD_NO;
02211 connection->method = NULL;
02212 connection->url = NULL;
02213 connection->write_buffer = NULL;
02214 connection->write_buffer_size = 0;
02215 connection->write_buffer_send_offset = 0;
02216 connection->write_buffer_append_offset = 0;
02217 if ((end != NULL) && (0 == strcasecmp (end, "close")))
02218 {
02219 connection->read_closed = MHD_YES;
02220 connection->read_buffer_offset = 0;
02221 }
02222 if (((MHD_YES == connection->read_closed) &&
02223 (0 == connection->read_buffer_offset)) ||
02224 (connection->version == NULL) ||
02225 (0 != strcasecmp (MHD_HTTP_VERSION_1_1, connection->version)))
02226 {
02227
02228 connection->state = MHD_CONNECTION_CLOSED;
02229 MHD_pool_destroy (connection->pool);
02230 connection->pool = NULL;
02231 connection->read_buffer = NULL;
02232 connection->read_buffer_size = 0;
02233 connection->read_buffer_offset = 0;
02234 }
02235 else
02236 {
02237 connection->version = NULL;
02238 connection->state = MHD_CONNECTION_INIT;
02239 connection->read_buffer
02240 = MHD_pool_reset (connection->pool,
02241 connection->read_buffer,
02242 connection->read_buffer_size);
02243 }
02244 continue;
02245 case MHD_CONNECTION_CLOSED:
02246 if (connection->socket_fd != -1)
02247 connection_close_error (connection);
02248 break;
02249 default:
02250 EXTRA_CHECK (0);
02251 break;
02252 }
02253 break;
02254 }
02255 timeout = connection->daemon->connection_timeout;
02256 if ((connection->socket_fd != -1) &&
02257 (timeout != 0) &&
02258 (timeout < (time (NULL) - connection->last_activity)) )
02259 {
02260 MHD_connection_close (connection, MHD_REQUEST_TERMINATED_TIMEOUT_REACHED);
02261 return MHD_NO;
02262 }
02263 return MHD_YES;
02264 }
02265
02266 void
02267 MHD_set_http_callbacks_ (struct MHD_Connection *connection)
02268 {
02269 connection->read_handler = &MHD_connection_handle_read;
02270 connection->write_handler = &MHD_connection_handle_write;
02271 connection->idle_handler = &MHD_connection_handle_idle;
02272 }
02273
02274
02284 const union MHD_ConnectionInfo *
02285 MHD_get_connection_info (struct MHD_Connection *connection,
02286 enum MHD_ConnectionInfoType infoType, ...)
02287 {
02288 switch (infoType)
02289 {
02290 #if HTTPS_SUPPORT
02291 case MHD_CONNECTION_INFO_CIPHER_ALGO:
02292 if (connection->tls_session == NULL)
02293 return NULL;
02294 connection->cipher = gnutls_cipher_get (connection->tls_session);
02295 return (const union MHD_ConnectionInfo *) &connection->cipher;
02296 case MHD_CONNECTION_INFO_PROTOCOL:
02297 if (connection->tls_session == NULL)
02298 return NULL;
02299 connection->protocol = gnutls_protocol_get_version (connection->tls_session);
02300 return (const union MHD_ConnectionInfo *) &connection->protocol;
02301 case MHD_CONNECTION_INFO_GNUTLS_SESSION:
02302 if (connection->tls_session == NULL)
02303 return NULL;
02304 return (const union MHD_ConnectionInfo *) &connection->tls_session;
02305 #endif
02306 case MHD_CONNECTION_INFO_CLIENT_ADDRESS:
02307 return (const union MHD_ConnectionInfo *) &connection->addr;
02308 default:
02309 return NULL;
02310 };
02311 }
02312
02313
02314