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 ret = response->crc (response->crc_cls,
00332 connection->response_write_position,
00333 response->data,
00334 MHD_MIN (response->data_buffer_size,
00335 response->total_size -
00336 connection->response_write_position));
00337 if ((ret == 0) &&
00338 (0 != (connection->daemon->options & MHD_USE_SELECT_INTERNALLY)))
00339 abort ();
00340 if (ret == -1)
00341 {
00342
00343
00344 #if DEBUG_CLOSE
00345 #if HAVE_MESSAGES
00346 MHD_DLOG (connection->daemon, "Closing connection (end of response)\n");
00347 #endif
00348 #endif
00349 response->total_size = connection->response_write_position;
00350 connection_close_error (connection);
00351 return MHD_NO;
00352 }
00353 response->data_start = connection->response_write_position;
00354 response->data_size = ret;
00355 if (ret == 0)
00356 return MHD_NO;
00357 return MHD_YES;
00358 }
00359
00369 static int
00370 try_ready_chunked_body (struct MHD_Connection *connection)
00371 {
00372 int ret;
00373 char *buf;
00374 struct MHD_Response *response;
00375 size_t size;
00376 char cbuf[10];
00377 int cblen;
00378
00379 response = connection->response;
00380 if (connection->write_buffer_size == 0)
00381 {
00382 size = connection->daemon->pool_size;
00383 do
00384 {
00385 size /= 2;
00386 if (size < 128)
00387 {
00388
00389 #if DEBUG_CLOSE
00390 #if HAVE_MESSAGES
00391 MHD_DLOG (connection->daemon,
00392 "Closing connection (out of memory)\n");
00393 #endif
00394 #endif
00395 connection_close_error (connection);
00396 return MHD_NO;
00397 }
00398 buf = MHD_pool_allocate (connection->pool, size, MHD_NO);
00399 }
00400 while (buf == NULL);
00401 connection->write_buffer_size = size;
00402 connection->write_buffer = buf;
00403 }
00404
00405 ret = response->crc (response->crc_cls,
00406 connection->response_write_position,
00407 &connection->write_buffer[sizeof (cbuf)],
00408 connection->write_buffer_size - sizeof (cbuf) - 2);
00409 if (ret == -1)
00410 {
00411
00412 strcpy (connection->write_buffer, "0\r\n");
00413 connection->write_buffer_append_offset = 3;
00414 connection->write_buffer_send_offset = 0;
00415 response->total_size = connection->response_write_position;
00416 return MHD_YES;
00417 }
00418 if (ret == 0)
00419 {
00420 connection->state = MHD_CONNECTION_CHUNKED_BODY_UNREADY;
00421 return MHD_NO;
00422 }
00423 if (ret > 0xFFFFFF)
00424 ret = 0xFFFFFF;
00425 SPRINTF (cbuf, "%X\r\n", ret);
00426 cblen = strlen (cbuf);
00427 EXTRA_CHECK (cblen <= sizeof (cbuf));
00428 memcpy (&connection->write_buffer[sizeof (cbuf) - cblen], cbuf, cblen);
00429 memcpy (&connection->write_buffer[sizeof (cbuf) + ret], "\r\n", 2);
00430 connection->response_write_position += ret;
00431 connection->write_buffer_send_offset = sizeof (cbuf) - cblen;
00432 connection->write_buffer_append_offset = sizeof (cbuf) + ret + 2;
00433 return MHD_YES;
00434 }
00435
00440 static void
00441 add_extra_headers (struct MHD_Connection *connection)
00442 {
00443 const char *have;
00444 char buf[128];
00445
00446 connection->have_chunked_upload = MHD_NO;
00447 if (connection->response->total_size == MHD_SIZE_UNKNOWN)
00448 {
00449 have = MHD_get_response_header (connection->response,
00450 MHD_HTTP_HEADER_CONNECTION);
00451 if ((have == NULL) || (0 != strcasecmp (have, "close")))
00452 {
00453 if ((connection->version != NULL) &&
00454 (0 == strcasecmp (connection->version, MHD_HTTP_VERSION_1_1)))
00455 {
00456 connection->have_chunked_upload = MHD_YES;
00457 have = MHD_get_response_header (connection->response,
00458 MHD_HTTP_HEADER_TRANSFER_ENCODING);
00459 if (have == NULL)
00460 MHD_add_response_header (connection->response,
00461 MHD_HTTP_HEADER_TRANSFER_ENCODING,
00462 "chunked");
00463 }
00464 else
00465 {
00466 MHD_add_response_header (connection->response,
00467 MHD_HTTP_HEADER_CONNECTION, "close");
00468 }
00469 }
00470 }
00471 else if (NULL == MHD_get_response_header (connection->response,
00472 MHD_HTTP_HEADER_CONTENT_LENGTH))
00473 {
00474 SPRINTF (buf,
00475 "%llu",
00476 (unsigned long long)connection->response->total_size);
00477 MHD_add_response_header (connection->response,
00478 MHD_HTTP_HEADER_CONTENT_LENGTH, buf);
00479 }
00480 }
00481
00488 static void
00489 get_date_string (char *date)
00490 {
00491 static const char *days[] =
00492 { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" };
00493 static const char *mons[] =
00494 { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct",
00495 "Nov", "Dec"
00496 };
00497 struct tm now;
00498 time_t t;
00499
00500 time (&t);
00501 gmtime_r (&t, &now);
00502 SPRINTF (date,
00503 "Date: %3s, %02u %3s %04u %02u:%02u:%02u GMT\r\n",
00504 days[now.tm_wday % 7],
00505 now.tm_mday,
00506 mons[now.tm_mon % 12],
00507 1900 + now.tm_year, now.tm_hour, now.tm_min, now.tm_sec);
00508 }
00509
00515 static int
00516 try_grow_read_buffer (struct MHD_Connection *connection)
00517 {
00518 void *buf;
00519
00520 buf = MHD_pool_reallocate (connection->pool,
00521 connection->read_buffer,
00522 connection->read_buffer_size,
00523 connection->read_buffer_size * 2 +
00524 MHD_BUF_INC_SIZE + 1);
00525 if (buf == NULL)
00526 return MHD_NO;
00527
00528 connection->read_buffer = buf;
00529 connection->read_buffer_size =
00530 connection->read_buffer_size * 2 + MHD_BUF_INC_SIZE;
00531 return MHD_YES;
00532 }
00533
00540 static int
00541 build_header_response (struct MHD_Connection *connection)
00542 {
00543 size_t size;
00544 size_t off;
00545 struct MHD_HTTP_Header *pos;
00546 char code[256];
00547 char date[128];
00548 char *data;
00549 enum MHD_ValueKind kind;
00550 const char *reason_phrase;
00551
00552 if (connection->state == MHD_CONNECTION_FOOTERS_RECEIVED)
00553 {
00554 add_extra_headers (connection);
00555 reason_phrase = MHD_get_reason_phrase_for (connection->responseCode);
00556 SPRINTF (code,
00557 "%s %u %s\r\n",
00558 MHD_HTTP_VERSION_1_1, connection->responseCode, reason_phrase);
00559 off = strlen (code);
00560
00561 size = off + 2;
00562 kind = MHD_HEADER_KIND;
00563 if (NULL == MHD_get_response_header (connection->response,
00564 MHD_HTTP_HEADER_DATE))
00565 get_date_string (date);
00566 else
00567 date[0] = '\0';
00568 size += strlen (date);
00569 }
00570 else
00571 {
00572 size = 2;
00573 kind = MHD_FOOTER_KIND;
00574 off = 0;
00575 }
00576 pos = connection->response->first_header;
00577 while (pos != NULL)
00578 {
00579 if (pos->kind == kind)
00580 size += strlen (pos->header) + strlen (pos->value) + 4;
00581 pos = pos->next;
00582 }
00583
00584 data = MHD_pool_allocate (connection->pool, size + 1, MHD_YES);
00585 if (data == NULL)
00586 {
00587 #if HAVE_MESSAGES
00588 MHD_DLOG (connection->daemon, "Not enough memory for write!\n");
00589 #endif
00590 return MHD_NO;
00591 }
00592 if (connection->state == MHD_CONNECTION_FOOTERS_RECEIVED)
00593 {
00594 memcpy (data, code, off);
00595 }
00596 pos = connection->response->first_header;
00597 while (pos != NULL)
00598 {
00599 if (pos->kind == kind)
00600 off += SPRINTF (&data[off], "%s: %s\r\n", pos->header, pos->value);
00601 pos = pos->next;
00602 }
00603 if (connection->state == MHD_CONNECTION_FOOTERS_RECEIVED)
00604 {
00605 strcpy (&data[off], date);
00606 off += strlen (date);
00607 }
00608 memcpy (&data[off], "\r\n", 2);
00609 off += 2;
00610 if (off != size)
00611 abort ();
00612 connection->write_buffer = data;
00613 connection->write_buffer_append_offset = size;
00614 connection->write_buffer_send_offset = 0;
00615 connection->write_buffer_size = size + 1;
00616 return MHD_YES;
00617 }
00618
00626 static void
00627 transmit_error_response (struct MHD_Connection *connection,
00628 unsigned int status_code, const char *message)
00629 {
00630 struct MHD_Response *response;
00631
00632
00633 connection->state = MHD_CONNECTION_FOOTERS_RECEIVED;
00634 connection->read_closed = MHD_YES;
00635 #if HAVE_MESSAGES
00636 MHD_DLOG (connection->daemon,
00637 "Error %u (`%s') processing request, closing connection.\n",
00638 status_code, message);
00639 #endif
00640 response = MHD_create_response_from_data (strlen (message),
00641 (void *) message, MHD_NO, MHD_NO);
00642 MHD_queue_response (connection, status_code, response);
00643 EXTRA_CHECK (connection->response != NULL);
00644 MHD_destroy_response (response);
00645 if (MHD_NO == build_header_response (connection))
00646 {
00647
00648 #if HAVE_MESSAGES
00649 MHD_DLOG (connection->daemon,
00650 "Closing connection (failed to create response header)\n");
00651 #endif
00652 connection->state = MHD_CONNECTION_CLOSED;
00653 }
00654 else
00655 {
00656 connection->state = MHD_CONNECTION_HEADERS_SENDING;
00657 }
00658 }
00659
00664 static void
00665 do_fd_set (int fd, fd_set * set, int *max_fd)
00666 {
00667 FD_SET (fd, set);
00668 if (fd > *max_fd)
00669 *max_fd = fd;
00670 }
00671
00677 int
00678 MHD_connection_get_fdset (struct MHD_Connection *connection,
00679 fd_set * read_fd_set,
00680 fd_set * write_fd_set,
00681 fd_set * except_fd_set, int *max_fd)
00682 {
00683 int fd;
00684
00685 if (connection->pool == NULL)
00686 connection->pool = MHD_pool_create (connection->daemon->pool_size);
00687 if (connection->pool == NULL)
00688 {
00689 #if HAVE_MESSAGES
00690 MHD_DLOG (connection->daemon, "Failed to create memory pool!\n");
00691 #endif
00692 connection_close_error (connection);
00693 return MHD_NO;
00694 }
00695 fd = connection->socket_fd;
00696 if (fd == -1)
00697 return MHD_YES;
00698 while (1)
00699 {
00700 #if DEBUG_STATES
00701 MHD_DLOG (connection->daemon, "%s: state: %s\n",
00702 __FUNCTION__, MHD_state_to_string (connection->state));
00703 #endif
00704 switch (connection->state)
00705 {
00706 case MHD_CONNECTION_INIT:
00707 case MHD_CONNECTION_URL_RECEIVED:
00708 case MHD_CONNECTION_HEADER_PART_RECEIVED:
00709 #if HTTPS_SUPPORT
00710 case MHD_TLS_CONNECTION_INIT:
00711 #endif
00712
00713
00714 if ((connection->read_closed) &&
00715 (connection->read_buffer_offset == 0))
00716 {
00717 connection->state = MHD_CONNECTION_CLOSED;
00718 continue;
00719 }
00720 if ((connection->read_buffer_offset == connection->read_buffer_size)
00721 && (MHD_NO == try_grow_read_buffer (connection)))
00722 {
00723 transmit_error_response (connection,
00724 (connection->url != NULL)
00725 ? MHD_HTTP_REQUEST_ENTITY_TOO_LARGE
00726 : MHD_HTTP_REQUEST_URI_TOO_LONG,
00727 REQUEST_TOO_BIG);
00728 continue;
00729 }
00730 if (MHD_NO == connection->read_closed)
00731 do_fd_set (fd, read_fd_set, max_fd);
00732 break;
00733 case MHD_CONNECTION_HEADERS_RECEIVED:
00734
00735 EXTRA_CHECK (0);
00736 break;
00737 case MHD_CONNECTION_HEADERS_PROCESSED:
00738 EXTRA_CHECK (0);
00739 break;
00740 case MHD_CONNECTION_CONTINUE_SENDING:
00741 do_fd_set (fd, write_fd_set, max_fd);
00742 break;
00743 case MHD_CONNECTION_CONTINUE_SENT:
00744 if (connection->read_buffer_offset == connection->read_buffer_size)
00745 {
00746 if ((MHD_YES != try_grow_read_buffer (connection)) &&
00747 (0 != (connection->daemon->options &
00748 (MHD_USE_SELECT_INTERNALLY |
00749 MHD_USE_THREAD_PER_CONNECTION))))
00750 {
00751
00752
00753
00754
00755
00756
00757
00758
00759
00760
00761
00762 transmit_error_response (connection,
00763 MHD_HTTP_INTERNAL_SERVER_ERROR,
00764 INTERNAL_ERROR);
00765 continue;
00766 }
00767 }
00768 if ((connection->read_buffer_offset < connection->read_buffer_size)
00769 && (MHD_NO == connection->read_closed))
00770 do_fd_set (fd, read_fd_set, max_fd);
00771 break;
00772 case MHD_CONNECTION_BODY_RECEIVED:
00773 case MHD_CONNECTION_FOOTER_PART_RECEIVED:
00774
00775
00776 if (MHD_YES == connection->read_closed)
00777 {
00778 connection->state = MHD_CONNECTION_CLOSED;
00779 continue;
00780 }
00781 do_fd_set (fd, read_fd_set, max_fd);
00782
00783
00784 break;
00785 case MHD_CONNECTION_FOOTERS_RECEIVED:
00786
00787
00788 break;
00789 case MHD_CONNECTION_HEADERS_SENDING:
00790
00791 do_fd_set (fd, write_fd_set, max_fd);
00792 break;
00793 case MHD_CONNECTION_HEADERS_SENT:
00794 EXTRA_CHECK (0);
00795 break;
00796 case MHD_CONNECTION_NORMAL_BODY_READY:
00797 do_fd_set (fd, write_fd_set, max_fd);
00798 break;
00799 case MHD_CONNECTION_NORMAL_BODY_UNREADY:
00800
00801 break;
00802 case MHD_CONNECTION_CHUNKED_BODY_READY:
00803 do_fd_set (fd, write_fd_set, max_fd);
00804 break;
00805 case MHD_CONNECTION_CHUNKED_BODY_UNREADY:
00806
00807 break;
00808 case MHD_CONNECTION_BODY_SENT:
00809 EXTRA_CHECK (0);
00810 break;
00811 case MHD_CONNECTION_FOOTERS_SENDING:
00812 do_fd_set (fd, write_fd_set, max_fd);
00813 break;
00814 case MHD_CONNECTION_FOOTERS_SENT:
00815 EXTRA_CHECK (0);
00816 break;
00817 case MHD_CONNECTION_CLOSED:
00818 if (connection->socket_fd != -1)
00819 connection_close_error (connection);
00820 return MHD_YES;
00821
00822 default:
00823 EXTRA_CHECK (0);
00824 }
00825 break;
00826 }
00827 return MHD_YES;
00828 }
00829
00838 static char *
00839 get_next_header_line (struct MHD_Connection *connection)
00840 {
00841 char *rbuf;
00842 size_t pos;
00843
00844 if (connection->read_buffer_offset == 0)
00845 return NULL;
00846 pos = 0;
00847 rbuf = connection->read_buffer;
00848 while ((pos < connection->read_buffer_offset - 1) &&
00849 (rbuf[pos] != '\r') && (rbuf[pos] != '\n'))
00850 pos++;
00851 if (pos == connection->read_buffer_offset - 1)
00852 {
00853
00854 if (connection->read_buffer_offset == connection->read_buffer_size)
00855 {
00856 rbuf = MHD_pool_reallocate (connection->pool,
00857 connection->read_buffer,
00858 connection->read_buffer_size,
00859 connection->read_buffer_size * 2 +
00860 MHD_BUF_INC_SIZE);
00861 if (rbuf == NULL)
00862 {
00863 transmit_error_response (connection,
00864 (connection->url != NULL)
00865 ? MHD_HTTP_REQUEST_ENTITY_TOO_LARGE
00866 : MHD_HTTP_REQUEST_URI_TOO_LONG,
00867 REQUEST_TOO_BIG);
00868 }
00869 else
00870 {
00871 connection->read_buffer_size =
00872 connection->read_buffer_size * 2 + MHD_BUF_INC_SIZE;
00873 connection->read_buffer = rbuf;
00874 }
00875 }
00876 return NULL;
00877 }
00878
00879 if ((rbuf[pos] == '\r') && (rbuf[pos + 1] == '\n'))
00880 rbuf[pos++] = '\0';
00881 rbuf[pos++] = '\0';
00882 connection->read_buffer += pos;
00883 connection->read_buffer_size -= pos;
00884 connection->read_buffer_offset -= pos;
00885 return rbuf;
00886 }
00887
00891 static int
00892 connection_add_header (struct MHD_Connection *connection,
00893 char *key, char *value, enum MHD_ValueKind kind)
00894 {
00895 struct MHD_HTTP_Header *hdr;
00896
00897 hdr = MHD_pool_allocate (connection->pool,
00898 sizeof (struct MHD_HTTP_Header), MHD_YES);
00899 if (hdr == NULL)
00900 {
00901 #if HAVE_MESSAGES
00902 MHD_DLOG (connection->daemon,
00903 "Not enough memory to allocate header record!\n");
00904 #endif
00905 transmit_error_response (connection, MHD_HTTP_REQUEST_ENTITY_TOO_LARGE,
00906 REQUEST_TOO_BIG);
00907 return MHD_NO;
00908 }
00909 hdr->next = connection->headers_received;
00910 hdr->header = key;
00911 hdr->value = value;
00912 hdr->kind = kind;
00913 connection->headers_received = hdr;
00914 return MHD_YES;
00915 }
00916
00920 static int
00921 parse_arguments (enum MHD_ValueKind kind,
00922 struct MHD_Connection *connection, char *args)
00923 {
00924 char *equals;
00925 char *amper;
00926
00927 while (args != NULL)
00928 {
00929 equals = strstr (args, "=");
00930 if (equals == NULL)
00931 return MHD_NO;
00932 equals[0] = '\0';
00933 equals++;
00934 amper = strstr (equals, "&");
00935 if (amper != NULL)
00936 {
00937 amper[0] = '\0';
00938 amper++;
00939 }
00940 MHD_http_unescape (args);
00941 MHD_http_unescape (equals);
00942 if (MHD_NO == connection_add_header (connection, args, equals, kind))
00943 return MHD_NO;
00944 args = amper;
00945 }
00946 return MHD_YES;
00947 }
00948
00954 static int
00955 parse_cookie_header (struct MHD_Connection *connection)
00956 {
00957 const char *hdr;
00958 char *cpy;
00959 char *pos;
00960 char *sce;
00961 char *semicolon;
00962 char *equals;
00963 char *ekill;
00964 char old;
00965 int quotes;
00966
00967 hdr = MHD_lookup_connection_value (connection, MHD_HEADER_KIND, "Cookie");
00968 if (hdr == NULL)
00969 return MHD_YES;
00970 cpy = MHD_pool_allocate (connection->pool, strlen (hdr) + 1, MHD_YES);
00971 if (cpy == NULL)
00972 {
00973 #if HAVE_MESSAGES
00974 MHD_DLOG (connection->daemon, "Not enough memory to parse cookies!\n");
00975 #endif
00976 transmit_error_response (connection, MHD_HTTP_REQUEST_ENTITY_TOO_LARGE,
00977 REQUEST_TOO_BIG);
00978 return MHD_NO;
00979 }
00980 memcpy (cpy, hdr, strlen (hdr) + 1);
00981 pos = cpy;
00982 while (pos != NULL)
00983 {
00984 while (*pos == ' ')
00985 pos++;
00986
00987 sce = pos;
00988 while (((*sce) != '\0') &&
00989 ((*sce) != ',') && ((*sce) != ';') && ((*sce) != '='))
00990 sce++;
00991
00992 ekill = sce - 1;
00993 while ((*ekill == ' ') && (ekill >= pos))
00994 *(ekill--) = '\0';
00995 old = *sce;
00996 *sce = '\0';
00997 if (old != '=')
00998 {
00999
01000 if (MHD_NO ==
01001 connection_add_header (connection, pos, "", MHD_COOKIE_KIND))
01002 return MHD_NO;
01003 if (old == '\0')
01004 break;
01005 pos = sce + 1;
01006 continue;
01007 }
01008 equals = sce + 1;
01009 quotes = 0;
01010 semicolon = equals;
01011 while ((semicolon[0] != '\0') &&
01012 ((quotes != 0) ||
01013 ((semicolon[0] != ';') && (semicolon[0] != ','))))
01014 {
01015 if (semicolon[0] == '"')
01016 quotes = (quotes + 1) & 1;
01017 semicolon++;
01018 }
01019 if (semicolon[0] == '\0')
01020 semicolon = NULL;
01021 if (semicolon != NULL)
01022 {
01023 semicolon[0] = '\0';
01024 semicolon++;
01025 }
01026
01027 if ((equals[0] == '"') && (equals[strlen (equals) - 1] == '"'))
01028 {
01029 equals[strlen (equals) - 1] = '\0';
01030 equals++;
01031 }
01032 if (MHD_NO == connection_add_header (connection,
01033 pos, equals, MHD_COOKIE_KIND))
01034 return MHD_NO;
01035 pos = semicolon;
01036 }
01037 return MHD_YES;
01038 }
01039
01047 static int
01048 parse_initial_message_line (struct MHD_Connection *connection, char *line)
01049 {
01050 char *uri;
01051 char *httpVersion;
01052 char *args;
01053
01054 uri = strstr (line, " ");
01055 if (uri == NULL)
01056 return MHD_NO;
01057 uri[0] = '\0';
01058 connection->method = line;
01059 uri++;
01060 while (uri[0] == ' ')
01061 uri++;
01062 httpVersion = strstr (uri, " ");
01063 if (httpVersion != NULL)
01064 {
01065 httpVersion[0] = '\0';
01066 httpVersion++;
01067 }
01068 if (connection->daemon->uri_log_callback != NULL)
01069 connection->client_context
01070 =
01071 connection->daemon->uri_log_callback (connection->daemon->
01072 uri_log_callback_cls, uri);
01073 args = strstr (uri, "?");
01074 if (args != NULL)
01075 {
01076 args[0] = '\0';
01077 args++;
01078 parse_arguments (MHD_GET_ARGUMENT_KIND, connection, args);
01079 }
01080 MHD_http_unescape (uri);
01081 connection->url = uri;
01082 if (httpVersion == NULL)
01083 connection->version = "";
01084 else
01085 connection->version = httpVersion;
01086 return MHD_YES;
01087 }
01088
01094 static void
01095 call_connection_handler (struct MHD_Connection *connection)
01096 {
01097 size_t processed;
01098 size_t available;
01099 size_t used;
01100 size_t i;
01101 int instant_retry;
01102 int malformed;
01103 char *buffer_head;
01104
01105 if (connection->response != NULL)
01106 return;
01107
01108 buffer_head = connection->read_buffer;
01109 available = connection->read_buffer_offset;
01110 do
01111 {
01112 instant_retry = MHD_NO;
01113 if ((connection->have_chunked_upload == MHD_YES) &&
01114 (connection->remaining_upload_size == MHD_SIZE_UNKNOWN))
01115 {
01116 if ((connection->current_chunk_offset ==
01117 connection->current_chunk_size)
01118 && (connection->current_chunk_offset != 0) && (available >= 2))
01119 {
01120
01121 i = 0;
01122 if ((buffer_head[i] == '\r') || (buffer_head[i] == '\n'))
01123 i++;
01124 if ((buffer_head[i] == '\r') || (buffer_head[i] == '\n'))
01125 i++;
01126 if (i == 0)
01127 {
01128
01129 #if HAVE_MESSAGES
01130 MHD_DLOG (connection->daemon,
01131 "Received malformed HTTP request (bad chunked encoding), closing connection.\n");
01132 #endif
01133 connection_close_error (connection);
01134 return;
01135 }
01136 available -= i;
01137 buffer_head += i;
01138 connection->current_chunk_offset = 0;
01139 connection->current_chunk_size = 0;
01140 }
01141 if (connection->current_chunk_offset <
01142 connection->current_chunk_size)
01143 {
01144
01145
01146
01147 processed =
01148 connection->current_chunk_size -
01149 connection->current_chunk_offset;
01150 if (processed > available)
01151 processed = available;
01152 if (available > processed)
01153 instant_retry = MHD_YES;
01154 }
01155 else
01156 {
01157
01158 i = 0;
01159 while (i < available)
01160 {
01161 if ((buffer_head[i] == '\r') || (buffer_head[i] == '\n'))
01162 break;
01163 i++;
01164 if (i >= 6)
01165 break;
01166 }
01167
01168
01169
01170
01171 if ((i + 1 >= available) &&
01172 !((i == 1) && (available == 2) && (buffer_head[0] == '0')))
01173 break;
01174 malformed = (i >= 6);
01175 if (!malformed)
01176 {
01177 buffer_head[i] = '\0';
01178 malformed =
01179 (1 != SSCANF (buffer_head, "%X",
01180 &connection->current_chunk_size)) &&
01181 (1 != SSCANF (buffer_head, "%x",
01182 &connection->current_chunk_size));
01183 }
01184 if (malformed)
01185 {
01186
01187 #if HAVE_MESSAGES
01188 MHD_DLOG (connection->daemon,
01189 "Received malformed HTTP request (bad chunked encoding), closing connection.\n");
01190 #endif
01191 connection_close_error (connection);
01192 return;
01193 }
01194 i++;
01195 if ((i < available) &&
01196 ((buffer_head[i] == '\r') || (buffer_head[i] == '\n')))
01197 i++;
01198
01199 buffer_head += i;
01200 available -= i;
01201 connection->current_chunk_offset = 0;
01202
01203 if (available > 0)
01204 instant_retry = MHD_YES;
01205 if (connection->current_chunk_size == 0)
01206 {
01207 connection->remaining_upload_size = 0;
01208 break;
01209 }
01210 continue;
01211 }
01212 }
01213 else
01214 {
01215
01216 processed = available;
01217 }
01218 used = processed;
01219 connection->client_aware = MHD_YES;
01220 if (MHD_NO ==
01221 connection->daemon->default_handler (connection->daemon->
01222 default_handler_cls,
01223 connection, connection->url,
01224 connection->method,
01225 connection->version,
01226 buffer_head, &processed,
01227 &connection->client_context))
01228 {
01229
01230 #if HAVE_MESSAGES
01231 MHD_DLOG (connection->daemon,
01232 "Internal application error, closing connection.\n");
01233 #endif
01234 connection_close_error (connection);
01235 return;
01236 }
01237 if (processed > used)
01238 abort ();
01239 if (processed != 0)
01240 instant_retry = MHD_NO;
01241 used -= processed;
01242 if (connection->have_chunked_upload == MHD_YES)
01243 connection->current_chunk_offset += used;
01244
01245 buffer_head += used;
01246 available -= used;
01247 if (connection->remaining_upload_size != MHD_SIZE_UNKNOWN)
01248 connection->remaining_upload_size -= used;
01249 }
01250 while (instant_retry == MHD_YES);
01251 if (available > 0)
01252 memmove (connection->read_buffer, buffer_head, available);
01253 connection->read_buffer_offset = available;
01254 }
01255
01264 static int
01265 do_read (struct MHD_Connection *connection)
01266 {
01267 int bytes_read;
01268
01269 if (connection->read_buffer_size == connection->read_buffer_offset)
01270 return MHD_NO;
01271
01272 bytes_read = connection->recv_cls (connection,
01273 &connection->read_buffer
01274 [connection->read_buffer_offset],
01275 connection->read_buffer_size -
01276 connection->read_buffer_offset);
01277 if (bytes_read < 0)
01278 {
01279 if (errno == EINTR)
01280 return MHD_NO;
01281 #if HAVE_MESSAGES
01282 MHD_DLOG (connection->daemon,
01283 "Failed to receive data: %s\n", STRERROR (errno));
01284 #endif
01285 connection_close_error (connection);
01286 return MHD_YES;
01287 }
01288 if (bytes_read == 0)
01289 {
01290
01291 connection->read_closed = MHD_YES;
01292 SHUTDOWN (connection->socket_fd, SHUT_RD);
01293 return MHD_NO;
01294 }
01295 connection->read_buffer_offset += bytes_read;
01296 return MHD_YES;
01297 }
01298
01306 static int
01307 do_write (struct MHD_Connection *connection)
01308 {
01309 int ret;
01310
01311 ret = connection->send_cls (connection,
01312 &connection->write_buffer
01313 [connection->write_buffer_send_offset],
01314 connection->write_buffer_append_offset
01315 - connection->write_buffer_send_offset);
01316
01317 if (ret < 0)
01318 {
01319 if (errno == EINTR)
01320 return MHD_NO;
01321 #if HAVE_MESSAGES
01322 MHD_DLOG (connection->daemon,
01323 "Failed to send data: %s\n", STRERROR (errno));
01324 #endif
01325 connection_close_error (connection);
01326 return MHD_YES;
01327 }
01328 #if DEBUG_SEND_DATA
01329 FPRINTF (stderr,
01330 "Sent response: `%.*s'\n",
01331 ret,
01332 &connection->write_buffer[connection->write_buffer_send_offset]);
01333 #endif
01334 connection->write_buffer_send_offset += ret;
01335 return MHD_YES;
01336 }
01337
01343 static int
01344 check_write_done (struct MHD_Connection *connection,
01345 enum MHD_CONNECTION_STATE next_state)
01346 {
01347 if (connection->write_buffer_append_offset !=
01348 connection->write_buffer_send_offset)
01349 return MHD_NO;
01350 connection->write_buffer_append_offset = 0;
01351 connection->write_buffer_send_offset = 0;
01352 connection->state = next_state;
01353 MHD_pool_reallocate (connection->pool, connection->write_buffer,
01354 connection->write_buffer_size, 0);
01355 connection->write_buffer = NULL;
01356 connection->write_buffer_size = 0;
01357 return MHD_YES;
01358 }
01359
01365 static int
01366 process_header_line (struct MHD_Connection *connection, char *line)
01367 {
01368 char *colon;
01369
01370
01371 colon = strstr (line, ":");
01372 if (colon == NULL)
01373 {
01374
01375 #if HAVE_MESSAGES
01376 MHD_DLOG (connection->daemon,
01377 "Received malformed line (no colon), closing connection.\n");
01378 #endif
01379 connection->state = MHD_CONNECTION_CLOSED;
01380 return MHD_NO;
01381 }
01382
01383 colon[0] = '\0';
01384 colon++;
01385 while ((colon[0] != '\0') && ((colon[0] == ' ') || (colon[0] == '\t')))
01386 colon++;
01387
01388
01389
01390
01391
01392 connection->last = line;
01393 connection->colon = colon;
01394 return MHD_YES;
01395 }
01396
01406 static int
01407 process_broken_line (struct MHD_Connection *connection,
01408 char *line, enum MHD_ValueKind kind)
01409 {
01410 char *last;
01411 char *tmp;
01412
01413 last = connection->last;
01414 if ((line[0] == ' ') || (line[0] == '\t'))
01415 {
01416
01417
01418 last = MHD_pool_reallocate (connection->pool,
01419 last,
01420 strlen (last) + 1,
01421 strlen (line) + strlen (last) + 1);
01422 if (last == NULL)
01423 {
01424 transmit_error_response (connection,
01425 MHD_HTTP_REQUEST_ENTITY_TOO_LARGE,
01426 REQUEST_TOO_BIG);
01427 return MHD_NO;
01428 }
01429 tmp = line;
01430 while ((tmp[0] == ' ') || (tmp[0] == '\t'))
01431 tmp++;
01432 strcat (last, tmp);
01433 connection->last = last;
01434 return MHD_YES;
01435 }
01436 EXTRA_CHECK ((last != NULL) && (connection->colon != NULL));
01437 if ((MHD_NO == connection_add_header (connection,
01438 last, connection->colon, kind)))
01439 {
01440 transmit_error_response (connection, MHD_HTTP_REQUEST_ENTITY_TOO_LARGE,
01441 REQUEST_TOO_BIG);
01442 return MHD_NO;
01443 }
01444
01445 if (strlen (line) != 0)
01446 {
01447 if (MHD_NO == process_header_line (connection, line))
01448 {
01449 transmit_error_response (connection,
01450 MHD_HTTP_BAD_REQUEST, REQUEST_MALFORMED);
01451 return MHD_NO;
01452 }
01453 }
01454 return MHD_YES;
01455 }
01456
01462 static void
01463 parse_connection_headers (struct MHD_Connection *connection)
01464 {
01465 const char *clen;
01466 unsigned long long cval;
01467 struct MHD_Response *response;
01468
01469 parse_cookie_header (connection);
01470 if ((0 != (MHD_USE_PEDANTIC_CHECKS & connection->daemon->options))
01471 && (NULL != connection->version)
01472 && (0 == strcasecmp (MHD_HTTP_VERSION_1_1, connection->version))
01473 && (NULL ==
01474 MHD_lookup_connection_value (connection, MHD_HEADER_KIND,
01475 MHD_HTTP_HEADER_HOST)))
01476 {
01477
01478 connection->state = MHD_CONNECTION_FOOTERS_RECEIVED;
01479 connection->read_closed = MHD_YES;
01480 #if HAVE_MESSAGES
01481 MHD_DLOG (connection->daemon,
01482 "Received `%s' request without `%s' header.\n",
01483 MHD_HTTP_VERSION_1_1, MHD_HTTP_HEADER_HOST);
01484 #endif
01485 response =
01486 MHD_create_response_from_data (strlen (REQUEST_LACKS_HOST),
01487 REQUEST_LACKS_HOST, MHD_NO, MHD_NO);
01488 MHD_queue_response (connection, MHD_HTTP_BAD_REQUEST, response);
01489 MHD_destroy_response (response);
01490 return;
01491 }
01492
01493 clen = MHD_lookup_connection_value (connection,
01494 MHD_HEADER_KIND,
01495 MHD_HTTP_HEADER_CONTENT_LENGTH);
01496 if (clen != NULL)
01497 {
01498 if (1 != SSCANF (clen, "%llu", &cval))
01499 {
01500 #if HAVE_MESSAGES
01501 MHD_DLOG (connection->daemon,
01502 "Failed to parse `%s' header `%s', closing connection.\n",
01503 MHD_HTTP_HEADER_CONTENT_LENGTH, clen);
01504 #endif
01505 connection->state = MHD_CONNECTION_CLOSED;
01506 return;
01507 }
01508 connection->remaining_upload_size = cval;
01509 }
01510 else
01511 {
01512 if (NULL == MHD_lookup_connection_value (connection,
01513 MHD_HEADER_KIND,
01514 MHD_HTTP_HEADER_TRANSFER_ENCODING))
01515 {
01516
01517 connection->remaining_upload_size = 0;
01518 }
01519 else
01520 {
01521 connection->remaining_upload_size = MHD_SIZE_UNKNOWN;
01522 if (0 ==
01523 strcasecmp (MHD_lookup_connection_value
01524 (connection, MHD_HEADER_KIND,
01525 MHD_HTTP_HEADER_TRANSFER_ENCODING), "chunked"))
01526 connection->have_chunked_upload = MHD_YES;
01527 }
01528 }
01529 }
01530
01540 int
01541 MHD_connection_handle_read (struct MHD_Connection *connection)
01542 {
01543 connection->last_activity = time (NULL);
01544 if (connection->state == MHD_CONNECTION_CLOSED)
01545 return MHD_NO;
01546
01547
01548 if (connection->read_buffer_offset + MHD_BUF_INC_SIZE >
01549 connection->read_buffer_size)
01550 try_grow_read_buffer (connection);
01551 if (MHD_NO == do_read (connection))
01552 return MHD_YES;
01553 while (1)
01554 {
01555 #if DEBUG_STATES
01556 MHD_DLOG (connection->daemon, "%s: state: %s\n",
01557 __FUNCTION__, MHD_state_to_string (connection->state));
01558 #endif
01559 switch (connection->state)
01560 {
01561 case MHD_CONNECTION_INIT:
01562 case MHD_CONNECTION_URL_RECEIVED:
01563 case MHD_CONNECTION_HEADER_PART_RECEIVED:
01564 case MHD_CONNECTION_HEADERS_RECEIVED:
01565 case MHD_CONNECTION_HEADERS_PROCESSED:
01566 case MHD_CONNECTION_CONTINUE_SENDING:
01567 case MHD_CONNECTION_CONTINUE_SENT:
01568 case MHD_CONNECTION_BODY_RECEIVED:
01569 case MHD_CONNECTION_FOOTER_PART_RECEIVED:
01570
01571 if (MHD_YES == connection->read_closed)
01572 {
01573 connection->state = MHD_CONNECTION_CLOSED;
01574 continue;
01575 }
01576 break;
01577 case MHD_CONNECTION_CLOSED:
01578 if (connection->socket_fd != -1)
01579 connection_close_error (connection);
01580 return MHD_NO;
01581 default:
01582
01583 MHD_pool_reallocate (connection->pool,
01584 connection->read_buffer,
01585 connection->read_buffer_size + 1,
01586 connection->read_buffer_offset);
01587 break;
01588 }
01589 break;
01590 }
01591 return MHD_YES;
01592 }
01593
01603 int
01604 MHD_connection_handle_write (struct MHD_Connection *connection)
01605 {
01606 struct MHD_Response *response;
01607 int ret;
01608 connection->last_activity = time (NULL);
01609 while (1)
01610 {
01611 #if DEBUG_STATES
01612 MHD_DLOG (connection->daemon, "%s: state: %s\n",
01613 __FUNCTION__, MHD_state_to_string (connection->state));
01614 #endif
01615 switch (connection->state)
01616 {
01617 case MHD_CONNECTION_INIT:
01618 case MHD_CONNECTION_URL_RECEIVED:
01619 case MHD_CONNECTION_HEADER_PART_RECEIVED:
01620 case MHD_CONNECTION_HEADERS_RECEIVED:
01621 EXTRA_CHECK (0);
01622 break;
01623 case MHD_CONNECTION_HEADERS_PROCESSED:
01624 break;
01625 case MHD_CONNECTION_CONTINUE_SENDING:
01626 ret = connection->send_cls (connection,
01627 &HTTP_100_CONTINUE
01628 [connection->continue_message_write_offset],
01629 strlen (HTTP_100_CONTINUE) -
01630 connection->continue_message_write_offset);
01631 if (ret < 0)
01632 {
01633 if (errno == EINTR)
01634 break;
01635 #if HAVE_MESSAGES
01636 MHD_DLOG (connection->daemon,
01637 "Failed to send data: %s\n", STRERROR (errno));
01638 #endif
01639 connection_close_error (connection);
01640 return MHD_NO;
01641 }
01642 #if DEBUG_SEND_DATA
01643 FPRINTF (stderr,
01644 "Sent 100 continue response: `%.*s'\n",
01645 ret,
01646 &HTTP_100_CONTINUE
01647 [connection->continue_message_write_offset]);
01648 #endif
01649 connection->continue_message_write_offset += ret;
01650 break;
01651 case MHD_CONNECTION_CONTINUE_SENT:
01652 case MHD_CONNECTION_BODY_RECEIVED:
01653 case MHD_CONNECTION_FOOTER_PART_RECEIVED:
01654 case MHD_CONNECTION_FOOTERS_RECEIVED:
01655 EXTRA_CHECK (0);
01656 break;
01657 case MHD_CONNECTION_HEADERS_SENDING:
01658 do_write (connection);
01659 check_write_done (connection, MHD_CONNECTION_HEADERS_SENT);
01660 break;
01661 case MHD_CONNECTION_HEADERS_SENT:
01662 EXTRA_CHECK (0);
01663 break;
01664 case MHD_CONNECTION_NORMAL_BODY_READY:
01665 response = connection->response;
01666 if (response->crc != NULL)
01667 pthread_mutex_lock (&response->mutex);
01668 if (MHD_YES != try_ready_normal_body (connection))
01669 {
01670 if (response->crc != NULL)
01671 pthread_mutex_unlock (&response->mutex);
01672 connection->state = MHD_CONNECTION_NORMAL_BODY_UNREADY;
01673 break;
01674 }
01675 #if HTTPS_SUPPORT
01676 if (connection->daemon->options & MHD_USE_SSL)
01677 {
01678 ret = MHD__gnutls_record_send (connection->tls_session,
01679 &connection->response->data
01680 [connection->
01681 response_write_position -
01682 response->data_start],
01683 response->data_size -
01684 (connection->response_write_position
01685 - response->data_start));
01686 }
01687 else
01688 #endif
01689 {
01690 ret = connection->send_cls (connection,
01691 &response->data
01692 [connection->response_write_position
01693 - response->data_start],
01694 response->data_size -
01695 (connection->response_write_position
01696 - response->data_start));
01697 }
01698 #if DEBUG_SEND_DATA
01699 if (ret > 0)
01700 FPRINTF (stderr,
01701 "Sent DATA response: `%.*s'\n",
01702 ret,
01703 &response->data[connection->response_write_position -
01704 response->data_start]);
01705 #endif
01706 if (response->crc != NULL)
01707 pthread_mutex_unlock (&response->mutex);
01708 if (ret < 0)
01709 {
01710 if (errno == EINTR)
01711 return MHD_YES;
01712 #if HAVE_MESSAGES
01713 MHD_DLOG (connection->daemon,
01714 "Failed to send data: %s\n", STRERROR (errno));
01715 #endif
01716 connection_close_error (connection);
01717 return MHD_NO;
01718 }
01719 connection->response_write_position += ret;
01720 if (connection->response_write_position ==
01721 connection->response->total_size)
01722 connection->state = MHD_CONNECTION_FOOTERS_SENT;
01723 break;
01724 case MHD_CONNECTION_NORMAL_BODY_UNREADY:
01725 EXTRA_CHECK (0);
01726 break;
01727 case MHD_CONNECTION_CHUNKED_BODY_READY:
01728 do_write (connection);
01729 check_write_done (connection,
01730 (connection->response->total_size ==
01731 connection->response_write_position) ?
01732 MHD_CONNECTION_BODY_SENT :
01733 MHD_CONNECTION_CHUNKED_BODY_UNREADY);
01734 break;
01735 case MHD_CONNECTION_CHUNKED_BODY_UNREADY:
01736 case MHD_CONNECTION_BODY_SENT:
01737 EXTRA_CHECK (0);
01738 break;
01739 case MHD_CONNECTION_FOOTERS_SENDING:
01740 do_write (connection);
01741 check_write_done (connection, MHD_CONNECTION_FOOTERS_SENT);
01742 break;
01743 case MHD_CONNECTION_FOOTERS_SENT:
01744 EXTRA_CHECK (0);
01745 break;
01746 case MHD_CONNECTION_CLOSED:
01747 if (connection->socket_fd != -1)
01748 connection_close_error (connection);
01749 return MHD_NO;
01750 case MHD_TLS_CONNECTION_INIT:
01751 case MHD_TLS_HELLO_REQUEST:
01752 case MHD_TLS_HANDSHAKE_FAILED:
01753 EXTRA_CHECK (0);
01754 break;
01755 default:
01756 EXTRA_CHECK (0);
01757 connection_close_error (connection);
01758 return MHD_NO;
01759 }
01760 break;
01761 }
01762 return MHD_YES;
01763 }
01764
01774 int
01775 MHD_connection_handle_idle (struct MHD_Connection *connection)
01776 {
01777 unsigned int timeout;
01778 const char *end;
01779 char *line;
01780
01781 while (1)
01782 {
01783 #if DEBUG_STATES
01784 MHD_DLOG (connection->daemon, "%s: state: %s\n",
01785 __FUNCTION__, MHD_state_to_string (connection->state));
01786 #endif
01787 switch (connection->state)
01788 {
01789 case MHD_CONNECTION_INIT:
01790 line = get_next_header_line (connection);
01791 if (line == NULL)
01792 {
01793 if (connection->state != MHD_CONNECTION_INIT)
01794 continue;
01795 if (connection->read_closed)
01796 {
01797 connection->state = MHD_CONNECTION_CLOSED;
01798 continue;
01799 }
01800 break;
01801 }
01802 if (MHD_NO == parse_initial_message_line (connection, line))
01803 connection->state = MHD_CONNECTION_CLOSED;
01804 else
01805 connection->state = MHD_CONNECTION_URL_RECEIVED;
01806 continue;
01807 case MHD_CONNECTION_URL_RECEIVED:
01808 line = get_next_header_line (connection);
01809 if (line == NULL)
01810 {
01811 if (connection->state != MHD_CONNECTION_URL_RECEIVED)
01812 continue;
01813 if (connection->read_closed)
01814 {
01815 connection->state = MHD_CONNECTION_CLOSED;
01816 continue;
01817 }
01818 break;
01819 }
01820 if (strlen (line) == 0)
01821 {
01822 connection->state = MHD_CONNECTION_HEADERS_RECEIVED;
01823 continue;
01824 }
01825 if (MHD_NO == process_header_line (connection, line))
01826 {
01827 transmit_error_response (connection,
01828 MHD_HTTP_BAD_REQUEST,
01829 REQUEST_MALFORMED);
01830 break;
01831 }
01832 connection->state = MHD_CONNECTION_HEADER_PART_RECEIVED;
01833 continue;
01834 case MHD_CONNECTION_HEADER_PART_RECEIVED:
01835 line = get_next_header_line (connection);
01836 if (line == NULL)
01837 {
01838 if (connection->state != MHD_CONNECTION_HEADER_PART_RECEIVED)
01839 continue;
01840 if (connection->read_closed)
01841 {
01842 connection->state = MHD_CONNECTION_CLOSED;
01843 continue;
01844 }
01845 break;
01846 }
01847 if (MHD_NO ==
01848 process_broken_line (connection, line, MHD_HEADER_KIND))
01849 continue;
01850 if (strlen (line) == 0)
01851 {
01852 connection->state = MHD_CONNECTION_HEADERS_RECEIVED;
01853 continue;
01854 }
01855 continue;
01856 case MHD_CONNECTION_HEADERS_RECEIVED:
01857 parse_connection_headers (connection);
01858 if (connection->state == MHD_CONNECTION_CLOSED)
01859 continue;
01860 connection->state = MHD_CONNECTION_HEADERS_PROCESSED;
01861 continue;
01862 case MHD_CONNECTION_HEADERS_PROCESSED:
01863 call_connection_handler (connection);
01864 if (connection->state == MHD_CONNECTION_CLOSED)
01865 continue;
01866 if (need_100_continue (connection))
01867 {
01868 connection->state = MHD_CONNECTION_CONTINUE_SENDING;
01869 break;
01870 }
01871 if (connection->response != NULL)
01872 {
01873
01874 connection->remaining_upload_size = 0;
01875
01876 connection->read_closed = MHD_YES;
01877 }
01878 connection->state = (connection->remaining_upload_size == 0)
01879 ? MHD_CONNECTION_FOOTERS_RECEIVED : MHD_CONNECTION_CONTINUE_SENT;
01880 continue;
01881 case MHD_CONNECTION_CONTINUE_SENDING:
01882 if (connection->continue_message_write_offset ==
01883 strlen (HTTP_100_CONTINUE))
01884 {
01885 connection->state = MHD_CONNECTION_CONTINUE_SENT;
01886 continue;
01887 }
01888 break;
01889 case MHD_CONNECTION_CONTINUE_SENT:
01890 if (connection->read_buffer_offset != 0)
01891 {
01892 call_connection_handler (connection);
01893 if (connection->state == MHD_CONNECTION_CLOSED)
01894 continue;
01895 }
01896 if ((connection->remaining_upload_size == 0) ||
01897 ((connection->remaining_upload_size == MHD_SIZE_UNKNOWN) &&
01898 (connection->read_buffer_offset == 0) &&
01899 (MHD_YES == connection->read_closed)))
01900 {
01901 if ((MHD_YES == connection->have_chunked_upload) &&
01902 (MHD_NO == connection->read_closed))
01903 connection->state = MHD_CONNECTION_BODY_RECEIVED;
01904 else
01905 connection->state = MHD_CONNECTION_FOOTERS_RECEIVED;
01906 continue;
01907 }
01908 break;
01909 case MHD_CONNECTION_BODY_RECEIVED:
01910 line = get_next_header_line (connection);
01911 if (line == NULL)
01912 {
01913 if (connection->state != MHD_CONNECTION_BODY_RECEIVED)
01914 continue;
01915 if (connection->read_closed)
01916 {
01917 connection->state = MHD_CONNECTION_CLOSED;
01918 continue;
01919 }
01920 break;
01921 }
01922 if (strlen (line) == 0)
01923 {
01924 connection->state = MHD_CONNECTION_FOOTERS_RECEIVED;
01925 continue;
01926 }
01927 if (MHD_NO == process_header_line (connection, line))
01928 {
01929 transmit_error_response (connection,
01930 MHD_HTTP_BAD_REQUEST,
01931 REQUEST_MALFORMED);
01932 break;
01933 }
01934 connection->state = MHD_CONNECTION_FOOTER_PART_RECEIVED;
01935 continue;
01936 case MHD_CONNECTION_FOOTER_PART_RECEIVED:
01937 line = get_next_header_line (connection);
01938 if (line == NULL)
01939 {
01940 if (connection->state != MHD_CONNECTION_FOOTER_PART_RECEIVED)
01941 continue;
01942 if (connection->read_closed)
01943 {
01944 connection->state = MHD_CONNECTION_CLOSED;
01945 continue;
01946 }
01947 break;
01948 }
01949 if (MHD_NO ==
01950 process_broken_line (connection, line, MHD_FOOTER_KIND))
01951 continue;
01952 if (strlen (line) == 0)
01953 {
01954 connection->state = MHD_CONNECTION_FOOTERS_RECEIVED;
01955 continue;
01956 }
01957 continue;
01958 case MHD_CONNECTION_FOOTERS_RECEIVED:
01959 call_connection_handler (connection);
01960 if (connection->state == MHD_CONNECTION_CLOSED)
01961 continue;
01962 if (connection->response == NULL)
01963 break;
01964 if (MHD_NO == build_header_response (connection))
01965 {
01966
01967 #if HAVE_MESSAGES
01968 MHD_DLOG (connection->daemon,
01969 "Closing connection (failed to create response header)\n");
01970 #endif
01971 connection->state = MHD_CONNECTION_CLOSED;
01972 continue;
01973 }
01974 connection->state = MHD_CONNECTION_HEADERS_SENDING;
01975
01976 #if HAVE_DECL_TCP_CORK
01977
01978 {
01979 const int val = 1;
01980 setsockopt (connection->socket_fd, IPPROTO_TCP, TCP_CORK, &val,
01981 sizeof (val));
01982 }
01983 #endif
01984 break;
01985 case MHD_CONNECTION_HEADERS_SENDING:
01986
01987 break;
01988 case MHD_CONNECTION_HEADERS_SENT:
01989 if (connection->have_chunked_upload)
01990 connection->state = MHD_CONNECTION_CHUNKED_BODY_UNREADY;
01991 else
01992 connection->state = MHD_CONNECTION_NORMAL_BODY_UNREADY;
01993 continue;
01994 case MHD_CONNECTION_NORMAL_BODY_READY:
01995
01996 break;
01997 case MHD_CONNECTION_NORMAL_BODY_UNREADY:
01998 if (connection->response->crc != NULL)
01999 pthread_mutex_lock (&connection->response->mutex);
02000 if (MHD_YES == try_ready_normal_body (connection))
02001 {
02002 if (connection->response->crc != NULL)
02003 pthread_mutex_unlock (&connection->response->mutex);
02004 connection->state = MHD_CONNECTION_NORMAL_BODY_READY;
02005 break;
02006 }
02007 if (connection->response->crc != NULL)
02008 pthread_mutex_unlock (&connection->response->mutex);
02009
02010 break;
02011 case MHD_CONNECTION_CHUNKED_BODY_READY:
02012
02013 break;
02014 case MHD_CONNECTION_CHUNKED_BODY_UNREADY:
02015 if (connection->response->crc != NULL)
02016 pthread_mutex_lock (&connection->response->mutex);
02017 if (MHD_YES == try_ready_chunked_body (connection))
02018 {
02019 if (connection->response->crc != NULL)
02020 pthread_mutex_unlock (&connection->response->mutex);
02021 connection->state = MHD_CONNECTION_CHUNKED_BODY_READY;
02022 continue;
02023 }
02024 if (connection->response->crc != NULL)
02025 pthread_mutex_unlock (&connection->response->mutex);
02026 break;
02027 case MHD_CONNECTION_BODY_SENT:
02028 build_header_response (connection);
02029 if (connection->write_buffer_send_offset ==
02030 connection->write_buffer_append_offset)
02031 connection->state = MHD_CONNECTION_FOOTERS_SENT;
02032 else
02033 connection->state = MHD_CONNECTION_FOOTERS_SENDING;
02034 continue;
02035 case MHD_CONNECTION_FOOTERS_SENDING:
02036
02037 break;
02038 case MHD_CONNECTION_FOOTERS_SENT:
02039 #if HAVE_DECL_TCP_CORK
02040
02041 {
02042 const int val = 0;
02043 setsockopt (connection->socket_fd, IPPROTO_TCP, TCP_CORK, &val,
02044 sizeof (val));
02045 }
02046 #endif
02047 MHD_destroy_response (connection->response);
02048 if (connection->daemon->notify_completed != NULL)
02049 {
02050 connection->daemon->notify_completed (connection->daemon->
02051 notify_completed_cls,
02052 connection,
02053 &connection->client_context,
02054 MHD_REQUEST_TERMINATED_COMPLETED_OK);
02055 }
02056 connection->client_aware = MHD_NO;
02057 end =
02058 MHD_lookup_connection_value (connection, MHD_HEADER_KIND,
02059 MHD_HTTP_HEADER_CONNECTION);
02060 connection->client_context = NULL;
02061 connection->continue_message_write_offset = 0;
02062 connection->responseCode = 0;
02063 connection->response = NULL;
02064 connection->headers_received = NULL;
02065 connection->response_write_position = 0;
02066 connection->have_chunked_upload = MHD_NO;
02067 connection->method = NULL;
02068 connection->url = NULL;
02069 connection->write_buffer = NULL;
02070 connection->write_buffer_size = 0;
02071 connection->write_buffer_send_offset = 0;
02072 connection->write_buffer_append_offset = 0;
02073 if ((end != NULL) && (0 == strcasecmp (end, "close")))
02074 {
02075 connection->read_closed = MHD_YES;
02076 connection->read_buffer_offset = 0;
02077 }
02078 if (((MHD_YES == connection->read_closed) &&
02079 (0 == connection->read_buffer_offset)) ||
02080 (connection->version == NULL) ||
02081 (0 != strcasecmp (MHD_HTTP_VERSION_1_1, connection->version)))
02082 {
02083
02084 connection->state = MHD_CONNECTION_CLOSED;
02085 MHD_pool_destroy (connection->pool);
02086 connection->pool = NULL;
02087 connection->read_buffer = NULL;
02088 connection->read_buffer_size = 0;
02089 connection->read_buffer_offset = 0;
02090 }
02091 else
02092 {
02093 connection->version = NULL;
02094 connection->state = MHD_CONNECTION_INIT;
02095 connection->read_buffer
02096 = MHD_pool_reset (connection->pool,
02097 connection->read_buffer,
02098 connection->read_buffer_size);
02099 }
02100 continue;
02101 case MHD_CONNECTION_CLOSED:
02102 if (connection->socket_fd != -1)
02103 connection_close_error (connection);
02104 break;
02105 default:
02106 EXTRA_CHECK (0);
02107 break;
02108 }
02109 break;
02110 }
02111 timeout = connection->daemon->connection_timeout;
02112 if ((connection->socket_fd != -1) &&
02113 (timeout != 0) && (time (NULL) - timeout > connection->last_activity))
02114 {
02115 MHD_connection_close (connection, MHD_REQUEST_TERMINATED_TIMEOUT_REACHED);
02116 return MHD_NO;
02117 }
02118 return MHD_YES;
02119
02120 }
02121
02122 void
02123 MHD_set_http_calbacks (struct MHD_Connection *connection)
02124 {
02125 connection->read_handler = &MHD_connection_handle_read;
02126 connection->write_handler = &MHD_connection_handle_write;
02127 connection->idle_handler = &MHD_connection_handle_idle;
02128 }
02129
02130 #if HTTPS_SUPPORT
02131 #include "gnutls_int.h"
02132 #include "gnutls_record.h"
02133 #endif
02134
02144 const union MHD_ConnectionInfo *
02145 MHD_get_connection_info (struct MHD_Connection *connection,
02146 enum MHD_ConnectionInfoType infoType, ...)
02147 {
02148 switch (infoType)
02149 {
02150 #if HTTPS_SUPPORT
02151 case MHD_CONNECTION_INFO_CIPHER_ALGO:
02152 if (connection->tls_session == NULL)
02153 return NULL;
02154 return (const union MHD_ConnectionInfo *) &connection->
02155 tls_session->security_parameters.read_bulk_cipher_algorithm;
02156 case MHD_CONNECTION_INFO_PROTOCOL:
02157 if (connection->tls_session == NULL)
02158 return NULL;
02159 return (const union MHD_ConnectionInfo *) &connection->
02160 tls_session->security_parameters.version;
02161 #endif
02162 case MHD_CONNECTION_INFO_CLIENT_ADDRESS:
02163 return (const union MHD_ConnectionInfo *) &connection->addr;
02164 default:
02165 return NULL;
02166 };
02167 }
02168
02169
02170