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
00037 #define HTTP_100_CONTINUE "HTTP/1.1 100 Continue\r\n\r\n"
00038
00046 #if HAVE_MESSAGES
00047 #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>"
00048 #else
00049 #define REQUEST_TOO_BIG ""
00050 #endif
00051
00059 #if HAVE_MESSAGES
00060 #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>"
00061 #else
00062 #define REQUEST_LACKS_HOST ""
00063 #endif
00064
00072 #if HAVE_MESSAGES
00073 #define REQUEST_MALFORMED "<html><head><title>Request malformed</title></head><body>Your HTTP request was syntactically incorrect.</body></html>"
00074 #else
00075 #define REQUEST_MALFORMED ""
00076 #endif
00077
00084 #if HAVE_MESSAGES
00085 #define INTERNAL_ERROR "<html><head><title>Internal server error</title></head><body>Some programmer needs to study the manual more carefully.</body></html>"
00086 #else
00087 #define INTERNAL_ERROR ""
00088 #endif
00089
00094 #define DEBUG_CLOSE MHD_NO
00095
00099 #define DEBUG_SEND_DATA MHD_NO
00100
00109 int
00110 MHD_get_connection_values (struct MHD_Connection *connection,
00111 enum MHD_ValueKind kind,
00112 MHD_KeyValueIterator iterator, void *iterator_cls)
00113 {
00114 int ret;
00115 struct MHD_HTTP_Header *pos;
00116
00117 if (connection == NULL)
00118 return -1;
00119 ret = 0;
00120 pos = connection->headers_received;
00121 while (pos != NULL)
00122 {
00123 if (0 != (pos->kind & kind))
00124 {
00125 ret++;
00126 if ((iterator != NULL) &&
00127 (MHD_YES != iterator (iterator_cls,
00128 kind, pos->header, pos->value)))
00129 return ret;
00130 }
00131 pos = pos->next;
00132 }
00133 return ret;
00134 }
00135
00165 int
00166 MHD_set_connection_value (struct MHD_Connection *connection,
00167 enum MHD_ValueKind kind,
00168 const char *key, const char *value)
00169 {
00170 struct MHD_HTTP_Header *pos;
00171
00172 pos = MHD_pool_allocate (connection->pool,
00173 sizeof (struct MHD_HTTP_Header), MHD_NO);
00174 if (pos == NULL)
00175 return MHD_NO;
00176 pos->header = (char *) key;
00177 pos->value = (char *) value;
00178 pos->kind = kind;
00179 pos->next = connection->headers_received;
00180 connection->headers_received = pos;
00181 return MHD_YES;
00182 }
00183
00191 const char *
00192 MHD_lookup_connection_value (struct MHD_Connection *connection,
00193 enum MHD_ValueKind kind, const char *key)
00194 {
00195 struct MHD_HTTP_Header *pos;
00196
00197 if (connection == NULL)
00198 return NULL;
00199 pos = connection->headers_received;
00200 while (pos != NULL)
00201 {
00202 if ((0 != (pos->kind & kind)) && (0 == strcasecmp (key, pos->header)))
00203 return pos->value;
00204 pos = pos->next;
00205 }
00206 return NULL;
00207 }
00208
00219 int
00220 MHD_queue_response (struct MHD_Connection *connection,
00221 unsigned int status_code, struct MHD_Response *response)
00222 {
00223 if ((connection == NULL) ||
00224 (response == NULL) ||
00225 (connection->response != NULL) ||
00226 ((connection->state != MHD_CONNECTION_HEADERS_PROCESSED) &&
00227 (connection->state != MHD_CONNECTION_FOOTERS_RECEIVED)))
00228 return MHD_NO;
00229 MHD_increment_response_rc (response);
00230 connection->response = response;
00231 connection->responseCode = status_code;
00232 if ((connection->method != NULL) &&
00233 (0 == strcasecmp (connection->method, MHD_HTTP_METHOD_HEAD)))
00234 {
00235
00236
00237 connection->response_write_position = response->total_size;
00238 }
00239 if ((response->total_size == -1) &&
00240 (0 == strcasecmp (connection->version, MHD_HTTP_VERSION_1_1)))
00241 connection->have_chunked_response = MHD_YES;
00242 else
00243 connection->have_chunked_response = MHD_NO;
00244 if (connection->state == MHD_CONNECTION_HEADERS_PROCESSED)
00245 {
00246
00247
00248
00249 SHUTDOWN (connection->socket_fd, SHUT_RD);
00250 connection->read_closed = MHD_YES;
00251 connection->state = MHD_CONNECTION_FOOTERS_RECEIVED;
00252 }
00253 return MHD_YES;
00254 }
00255
00260 static int
00261 need_100_continue (struct MHD_Connection *connection)
00262 {
00263 const char *expect;
00264
00265 return ((connection->response == NULL) &&
00266 (connection->version != NULL) &&
00267 (0 == strcasecmp (connection->version,
00268 MHD_HTTP_VERSION_1_1)) &&
00269 (NULL != (expect = MHD_lookup_connection_value (connection,
00270 MHD_HEADER_KIND,
00271 MHD_HTTP_HEADER_EXPECT)))
00272 && (0 == strcasecmp (expect, "100-continue"))
00273 && (connection->continue_message_write_offset <
00274 strlen (HTTP_100_CONTINUE)));
00275 }
00276
00281 void
00282 MHD_connection_close (struct MHD_Connection *connection,
00283 enum MHD_RequestTerminationCode termination_code)
00284 {
00285
00286 SHUTDOWN (connection->socket_fd, SHUT_RDWR);
00287 CLOSE (connection->socket_fd);
00288 connection->socket_fd = -1;
00289 connection->state = MHD_CONNECTION_CLOSED;
00290 if (connection->daemon->notify_completed != NULL)
00291 connection->daemon->notify_completed (connection->daemon->
00292 notify_completed_cls, connection,
00293 &connection->client_context,
00294 termination_code);
00295 }
00296
00301 static void
00302 connection_close_error (struct MHD_Connection *connection)
00303 {
00304 MHD_connection_close (connection, MHD_REQUEST_TERMINATED_WITH_ERROR);
00305 }
00306
00316 static int
00317 try_ready_normal_body (struct MHD_Connection *connection)
00318 {
00319 int ret;
00320 struct MHD_Response *response;
00321
00322 response = connection->response;
00323 if (response->crc == NULL)
00324 return MHD_YES;
00325 ret = response->crc (response->crc_cls,
00326 connection->response_write_position,
00327 response->data,
00328 MHD_MIN (response->data_buffer_size,
00329 response->total_size -
00330 connection->response_write_position));
00331 if ((ret == 0) &&
00332 (0 != (connection->daemon->options & MHD_USE_SELECT_INTERNALLY)))
00333 abort ();
00334 if (ret == -1)
00335 {
00336
00337
00338 #if DEBUG_CLOSE
00339 #if HAVE_MESSAGES
00340 MHD_DLOG (connection->daemon, "Closing connection (end of response)\n");
00341 #endif
00342 #endif
00343 response->total_size = connection->response_write_position;
00344 connection_close_error (connection);
00345 return MHD_NO;
00346 }
00347 response->data_start = connection->response_write_position;
00348 response->data_size = ret;
00349 if (ret == 0)
00350 return MHD_NO;
00351 return MHD_YES;
00352 }
00353
00363 static int
00364 try_ready_chunked_body (struct MHD_Connection *connection)
00365 {
00366 int ret;
00367 char *buf;
00368 struct MHD_Response *response;
00369 size_t size;
00370 char cbuf[10];
00371 int cblen;
00372
00373 response = connection->response;
00374 if (connection->write_buffer_size == 0)
00375 {
00376 size = connection->daemon->pool_size;
00377 do
00378 {
00379 size /= 2;
00380 if (size < 128)
00381 {
00382
00383 #if DEBUG_CLOSE
00384 #if HAVE_MESSAGES
00385 MHD_DLOG (connection->daemon,
00386 "Closing connection (out of memory)\n");
00387 #endif
00388 #endif
00389 connection_close_error (connection);
00390 return MHD_NO;
00391 }
00392 buf = MHD_pool_allocate (connection->pool, size, MHD_NO);
00393 }
00394 while (buf == NULL);
00395 connection->write_buffer_size = size;
00396 connection->write_buffer = buf;
00397 }
00398
00399 ret = response->crc (response->crc_cls,
00400 connection->response_write_position,
00401 &connection->write_buffer[sizeof (cbuf)],
00402 connection->write_buffer_size - sizeof (cbuf) - 2);
00403 if (ret == -1)
00404 {
00405
00406 strcpy (connection->write_buffer, "0\r\n");
00407 connection->write_buffer_append_offset = 3;
00408 connection->write_buffer_send_offset = 0;
00409 response->total_size = connection->response_write_position;
00410 return MHD_YES;
00411 }
00412 if (ret == 0)
00413 {
00414 connection->state = MHD_CONNECTION_CHUNKED_BODY_UNREADY;
00415 return MHD_NO;
00416 }
00417 if (ret > 0xFFFFFF)
00418 ret = 0xFFFFFF;
00419 SPRINTF (cbuf, "%X\r\n", ret);
00420 cblen = strlen (cbuf);
00421 EXTRA_CHECK (cblen <= sizeof (cbuf));
00422 memcpy (&connection->write_buffer[sizeof (cbuf) - cblen], cbuf, cblen);
00423 memcpy (&connection->write_buffer[sizeof (cbuf) + ret], "\r\n", 2);
00424 connection->response_write_position += ret;
00425 connection->write_buffer_send_offset = sizeof (cbuf) - cblen;
00426 connection->write_buffer_append_offset = sizeof (cbuf) + ret + 2;
00427 return MHD_YES;
00428 }
00429
00434 static void
00435 add_extra_headers (struct MHD_Connection *connection)
00436 {
00437 const char *have;
00438 char buf[128];
00439
00440 connection->have_chunked_upload = MHD_NO;
00441 if (connection->response->total_size == -1)
00442 {
00443 have = MHD_get_response_header (connection->response,
00444 MHD_HTTP_HEADER_CONNECTION);
00445 if ((have == NULL) || (0 != strcasecmp (have, "close")))
00446 {
00447 if ((connection->version != NULL) &&
00448 (0 == strcasecmp (connection->version, MHD_HTTP_VERSION_1_1)))
00449 {
00450 connection->have_chunked_upload = MHD_YES;
00451 have = MHD_get_response_header (connection->response,
00452 MHD_HTTP_HEADER_TRANSFER_ENCODING);
00453 if (have == NULL)
00454 MHD_add_response_header (connection->response,
00455 MHD_HTTP_HEADER_TRANSFER_ENCODING,
00456 "chunked");
00457 }
00458 else
00459 {
00460 MHD_add_response_header (connection->response,
00461 MHD_HTTP_HEADER_CONNECTION, "close");
00462 }
00463 }
00464 }
00465 else if (NULL == MHD_get_response_header (connection->response,
00466 MHD_HTTP_HEADER_CONTENT_LENGTH))
00467 {
00468 SPRINTF (buf,
00469 "%llu",
00470 connection->response->total_size);
00471 MHD_add_response_header (connection->response,
00472 MHD_HTTP_HEADER_CONTENT_LENGTH, buf);
00473 }
00474 }
00475
00482 static void
00483 get_date_string (char *date)
00484 {
00485 static const char *days[] =
00486 { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" };
00487 static const char *mons[] =
00488 { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct",
00489 "Nov", "Dec"
00490 };
00491 struct tm now;
00492 time_t t;
00493
00494 time (&t);
00495 gmtime_r (&t, &now);
00496 SPRINTF (date,
00497 "Date: %3s, %02u %3s %04u %02u:%02u:%02u GMT\r\n",
00498 days[now.tm_wday % 7],
00499 now.tm_mday,
00500 mons[now.tm_mon % 12],
00501 1900 + now.tm_year, now.tm_hour, now.tm_min, now.tm_sec);
00502 }
00503
00509 static int
00510 try_grow_read_buffer (struct MHD_Connection *connection)
00511 {
00512 void *buf;
00513
00514 buf = MHD_pool_reallocate (connection->pool,
00515 connection->read_buffer,
00516 connection->read_buffer_size,
00517 connection->read_buffer_size * 2 +
00518 MHD_BUF_INC_SIZE + 1);
00519 if (buf == NULL)
00520 return MHD_NO;
00521
00522 connection->read_buffer = buf;
00523 connection->read_buffer_size =
00524 connection->read_buffer_size * 2 + MHD_BUF_INC_SIZE;
00525 return MHD_YES;
00526 }
00527
00534 static int
00535 build_header_response (struct MHD_Connection *connection)
00536 {
00537 size_t size;
00538 size_t off;
00539 struct MHD_HTTP_Header *pos;
00540 char code[256];
00541 char date[128];
00542 char *data;
00543 enum MHD_ValueKind kind;
00544 const char *reason_phrase;
00545
00546 if (connection->state == MHD_CONNECTION_FOOTERS_RECEIVED)
00547 {
00548 add_extra_headers (connection);
00549 reason_phrase = MHD_get_reason_phrase_for (connection->responseCode);
00550 SPRINTF (code,
00551 "%s %u %s\r\n",
00552 MHD_HTTP_VERSION_1_1, connection->responseCode, reason_phrase);
00553 off = strlen (code);
00554
00555 size = off + 2;
00556 kind = MHD_HEADER_KIND;
00557 if (NULL == MHD_get_response_header (connection->response,
00558 MHD_HTTP_HEADER_DATE))
00559 get_date_string (date);
00560 else
00561 date[0] = '\0';
00562 size += strlen (date);
00563 }
00564 else
00565 {
00566 size = 2;
00567 kind = MHD_FOOTER_KIND;
00568 off = 0;
00569 }
00570 pos = connection->response->first_header;
00571 while (pos != NULL)
00572 {
00573 if (pos->kind == kind)
00574 size += strlen (pos->header) + strlen (pos->value) + 4;
00575 pos = pos->next;
00576 }
00577
00578 data = MHD_pool_allocate (connection->pool, size + 1, MHD_YES);
00579 if (data == NULL)
00580 {
00581 #if HAVE_MESSAGES
00582 MHD_DLOG (connection->daemon, "Not enough memory for write!\n");
00583 #endif
00584 return MHD_NO;
00585 }
00586 if (connection->state == MHD_CONNECTION_FOOTERS_RECEIVED)
00587 {
00588 memcpy (data, code, off);
00589 }
00590 pos = connection->response->first_header;
00591 while (pos != NULL)
00592 {
00593 if (pos->kind == kind)
00594 off += SPRINTF (&data[off], "%s: %s\r\n", pos->header, pos->value);
00595 pos = pos->next;
00596 }
00597 if (connection->state == MHD_CONNECTION_FOOTERS_RECEIVED)
00598 {
00599 strcpy (&data[off], date);
00600 off += strlen (date);
00601 }
00602 memcpy (&data[off], "\r\n", 2);
00603 off += 2;
00604 if (off != size)
00605 abort ();
00606 connection->write_buffer = data;
00607 connection->write_buffer_append_offset = size;
00608 connection->write_buffer_send_offset = 0;
00609 connection->write_buffer_size = size + 1;
00610 return MHD_YES;
00611 }
00612
00620 static void
00621 transmit_error_response (struct MHD_Connection *connection,
00622 unsigned int status_code, const char *message)
00623 {
00624 struct MHD_Response *response;
00625
00626
00627 connection->state = MHD_CONNECTION_FOOTERS_RECEIVED;
00628 connection->read_closed = MHD_YES;
00629 #if HAVE_MESSAGES
00630 MHD_DLOG (connection->daemon,
00631 "Error %u (`%s') processing request, closing connection.\n",
00632 status_code, message);
00633 #endif
00634 response = MHD_create_response_from_data (strlen (message),
00635 (void *) message, MHD_NO, MHD_NO);
00636 MHD_queue_response (connection, status_code, response);
00637 EXTRA_CHECK (connection->response != NULL);
00638 MHD_destroy_response (response);
00639 if (MHD_NO == build_header_response (connection))
00640 {
00641
00642 #if HAVE_MESSAGES
00643 MHD_DLOG (connection->daemon,
00644 "Closing connection (failed to create response header)\n");
00645 #endif
00646 connection->state = MHD_CONNECTION_CLOSED;
00647 }
00648 else
00649 {
00650 connection->state = MHD_CONNECTION_HEADERS_SENDING;
00651 }
00652 }
00653
00658 static void
00659 do_fd_set (int fd, fd_set * set, int *max_fd)
00660 {
00661 FD_SET (fd, set);
00662 if (fd > *max_fd)
00663 *max_fd = fd;
00664 }
00665
00671 int
00672 MHD_connection_get_fdset (struct MHD_Connection *connection,
00673 fd_set * read_fd_set,
00674 fd_set * write_fd_set,
00675 fd_set * except_fd_set, int *max_fd)
00676 {
00677 int fd;
00678
00679 if (connection->pool == NULL)
00680 connection->pool = MHD_pool_create (connection->daemon->pool_size);
00681 if (connection->pool == NULL)
00682 {
00683 #if HAVE_MESSAGES
00684 MHD_DLOG (connection->daemon, "Failed to create memory pool!\n");
00685 #endif
00686 connection_close_error (connection);
00687 return MHD_NO;
00688 }
00689 fd = connection->socket_fd;
00690 if (fd == -1)
00691 return MHD_YES;
00692 while (1)
00693 {
00694 #if DEBUG_STATES
00695 MHD_DLOG (connection->daemon, "%s: state: %s\n",
00696 __FUNCTION__, MHD_state_to_string (connection->state));
00697 #endif
00698 switch (connection->state)
00699 {
00700 case MHD_CONNECTION_INIT:
00701 case MHD_CONNECTION_URL_RECEIVED:
00702 case MHD_CONNECTION_HEADER_PART_RECEIVED:
00703 #if HTTPS_SUPPORT
00704 case MHD_TLS_CONNECTION_INIT:
00705 #endif
00706
00707
00708 if ((connection->read_closed) &&
00709 (connection->read_buffer_offset == 0))
00710 {
00711 connection->state = MHD_CONNECTION_CLOSED;
00712 continue;
00713 }
00714 if ((connection->read_buffer_offset == connection->read_buffer_size)
00715 && (MHD_NO == try_grow_read_buffer (connection)))
00716 {
00717 transmit_error_response (connection,
00718 (connection->url != NULL)
00719 ? MHD_HTTP_REQUEST_ENTITY_TOO_LARGE
00720 : MHD_HTTP_REQUEST_URI_TOO_LONG,
00721 REQUEST_TOO_BIG);
00722 continue;
00723 }
00724 if (MHD_NO == connection->read_closed)
00725 do_fd_set (fd, read_fd_set, max_fd);
00726 break;
00727 case MHD_CONNECTION_HEADERS_RECEIVED:
00728
00729 EXTRA_CHECK (0);
00730 break;
00731 case MHD_CONNECTION_HEADERS_PROCESSED:
00732 EXTRA_CHECK (0);
00733 break;
00734 case MHD_CONNECTION_CONTINUE_SENDING:
00735 do_fd_set (fd, write_fd_set, max_fd);
00736 break;
00737 case MHD_CONNECTION_CONTINUE_SENT:
00738 if (connection->read_buffer_offset == connection->read_buffer_size)
00739 {
00740 if ((MHD_YES != try_grow_read_buffer (connection)) &&
00741 (0 != (connection->daemon->options &
00742 (MHD_USE_SELECT_INTERNALLY |
00743 MHD_USE_THREAD_PER_CONNECTION))))
00744 {
00745
00746
00747
00748
00749
00750
00751
00752
00753
00754
00755
00756 transmit_error_response (connection,
00757 MHD_HTTP_INTERNAL_SERVER_ERROR,
00758 INTERNAL_ERROR);
00759 continue;
00760 }
00761 }
00762 if ((connection->read_buffer_offset < connection->read_buffer_size)
00763 && (MHD_NO == connection->read_closed))
00764 do_fd_set (fd, read_fd_set, max_fd);
00765 break;
00766 case MHD_CONNECTION_BODY_RECEIVED:
00767 case MHD_CONNECTION_FOOTER_PART_RECEIVED:
00768
00769
00770 if (MHD_YES == connection->read_closed)
00771 {
00772 connection->state = MHD_CONNECTION_CLOSED;
00773 continue;
00774 }
00775 do_fd_set (fd, read_fd_set, max_fd);
00776
00777
00778 break;
00779 case MHD_CONNECTION_FOOTERS_RECEIVED:
00780
00781
00782 break;
00783 case MHD_CONNECTION_HEADERS_SENDING:
00784
00785 do_fd_set (fd, write_fd_set, max_fd);
00786 break;
00787 case MHD_CONNECTION_HEADERS_SENT:
00788 EXTRA_CHECK (0);
00789 break;
00790 case MHD_CONNECTION_NORMAL_BODY_READY:
00791 do_fd_set (fd, write_fd_set, max_fd);
00792 break;
00793 case MHD_CONNECTION_NORMAL_BODY_UNREADY:
00794
00795 break;
00796 case MHD_CONNECTION_CHUNKED_BODY_READY:
00797 do_fd_set (fd, write_fd_set, max_fd);
00798 break;
00799 case MHD_CONNECTION_CHUNKED_BODY_UNREADY:
00800
00801 break;
00802 case MHD_CONNECTION_BODY_SENT:
00803 EXTRA_CHECK (0);
00804 break;
00805 case MHD_CONNECTION_FOOTERS_SENDING:
00806 do_fd_set (fd, write_fd_set, max_fd);
00807 break;
00808 case MHD_CONNECTION_FOOTERS_SENT:
00809 EXTRA_CHECK (0);
00810 break;
00811 case MHD_CONNECTION_CLOSED:
00812 if (connection->socket_fd != -1)
00813 connection_close_error (connection);
00814 return MHD_YES;
00815
00816 default:
00817 EXTRA_CHECK (0);
00818 }
00819 break;
00820 }
00821 return MHD_YES;
00822 }
00823
00832 static char *
00833 get_next_header_line (struct MHD_Connection *connection)
00834 {
00835 char *rbuf;
00836 size_t pos;
00837
00838 if (connection->read_buffer_offset == 0)
00839 return NULL;
00840 pos = 0;
00841 rbuf = connection->read_buffer;
00842 while ((pos < connection->read_buffer_offset - 1) &&
00843 (rbuf[pos] != '\r') && (rbuf[pos] != '\n'))
00844 pos++;
00845 if (pos == connection->read_buffer_offset - 1)
00846 {
00847
00848 if (connection->read_buffer_offset == connection->read_buffer_size)
00849 {
00850 rbuf = MHD_pool_reallocate (connection->pool,
00851 connection->read_buffer,
00852 connection->read_buffer_size,
00853 connection->read_buffer_size * 2 +
00854 MHD_BUF_INC_SIZE);
00855 if (rbuf == NULL)
00856 {
00857 transmit_error_response (connection,
00858 (connection->url != NULL)
00859 ? MHD_HTTP_REQUEST_ENTITY_TOO_LARGE
00860 : MHD_HTTP_REQUEST_URI_TOO_LONG,
00861 REQUEST_TOO_BIG);
00862 }
00863 else
00864 {
00865 connection->read_buffer_size =
00866 connection->read_buffer_size * 2 + MHD_BUF_INC_SIZE;
00867 connection->read_buffer = rbuf;
00868 }
00869 }
00870 return NULL;
00871 }
00872
00873 if ((rbuf[pos] == '\r') && (rbuf[pos + 1] == '\n'))
00874 rbuf[pos++] = '\0';
00875 rbuf[pos++] = '\0';
00876 connection->read_buffer += pos;
00877 connection->read_buffer_size -= pos;
00878 connection->read_buffer_offset -= pos;
00879 return rbuf;
00880 }
00881
00885 static int
00886 connection_add_header (struct MHD_Connection *connection,
00887 char *key, char *value, enum MHD_ValueKind kind)
00888 {
00889 struct MHD_HTTP_Header *hdr;
00890
00891 hdr = MHD_pool_allocate (connection->pool,
00892 sizeof (struct MHD_HTTP_Header), MHD_YES);
00893 if (hdr == NULL)
00894 {
00895 #if HAVE_MESSAGES
00896 MHD_DLOG (connection->daemon,
00897 "Not enough memory to allocate header record!\n");
00898 #endif
00899 transmit_error_response (connection, MHD_HTTP_REQUEST_ENTITY_TOO_LARGE,
00900 REQUEST_TOO_BIG);
00901 return MHD_NO;
00902 }
00903 hdr->next = connection->headers_received;
00904 hdr->header = key;
00905 hdr->value = value;
00906 hdr->kind = kind;
00907 connection->headers_received = hdr;
00908 return MHD_YES;
00909 }
00910
00914 static int
00915 parse_arguments (enum MHD_ValueKind kind,
00916 struct MHD_Connection *connection, char *args)
00917 {
00918 char *equals;
00919 char *amper;
00920
00921 while (args != NULL)
00922 {
00923 equals = strstr (args, "=");
00924 if (equals == NULL)
00925 return MHD_NO;
00926 equals[0] = '\0';
00927 equals++;
00928 amper = strstr (equals, "&");
00929 if (amper != NULL)
00930 {
00931 amper[0] = '\0';
00932 amper++;
00933 }
00934 MHD_http_unescape (args);
00935 MHD_http_unescape (equals);
00936 if (MHD_NO == connection_add_header (connection, args, equals, kind))
00937 return MHD_NO;
00938 args = amper;
00939 }
00940 return MHD_YES;
00941 }
00942
00948 static int
00949 parse_cookie_header (struct MHD_Connection *connection)
00950 {
00951 const char *hdr;
00952 char *cpy;
00953 char *pos;
00954 char *sce;
00955 char *semicolon;
00956 char *equals;
00957 char *ekill;
00958 char old;
00959 int quotes;
00960
00961 hdr = MHD_lookup_connection_value (connection, MHD_HEADER_KIND, "Cookie");
00962 if (hdr == NULL)
00963 return MHD_YES;
00964 cpy = MHD_pool_allocate (connection->pool, strlen (hdr) + 1, MHD_YES);
00965 if (cpy == NULL)
00966 {
00967 #if HAVE_MESSAGES
00968 MHD_DLOG (connection->daemon, "Not enough memory to parse cookies!\n");
00969 #endif
00970 transmit_error_response (connection, MHD_HTTP_REQUEST_ENTITY_TOO_LARGE,
00971 REQUEST_TOO_BIG);
00972 return MHD_NO;
00973 }
00974 memcpy (cpy, hdr, strlen (hdr) + 1);
00975 pos = cpy;
00976 while (pos != NULL)
00977 {
00978 while (*pos == ' ')
00979 pos++;
00980
00981 sce = pos;
00982 while (((*sce) != '\0') &&
00983 ((*sce) != ',') && ((*sce) != ';') && ((*sce) != '='))
00984 sce++;
00985
00986 ekill = sce - 1;
00987 while ((*ekill == ' ') && (ekill >= pos))
00988 *(ekill--) = '\0';
00989 old = *sce;
00990 *sce = '\0';
00991 if (old != '=')
00992 {
00993
00994 if (MHD_NO ==
00995 connection_add_header (connection, pos, "", MHD_COOKIE_KIND))
00996 return MHD_NO;
00997 if (old == '\0')
00998 break;
00999 pos = sce + 1;
01000 continue;
01001 }
01002 equals = sce + 1;
01003 quotes = 0;
01004 semicolon = equals;
01005 while ((semicolon[0] != '\0') &&
01006 ((quotes != 0) ||
01007 ((semicolon[0] != ';') && (semicolon[0] != ','))))
01008 {
01009 if (semicolon[0] == '"')
01010 quotes = (quotes + 1) & 1;
01011 semicolon++;
01012 }
01013 if (semicolon[0] == '\0')
01014 semicolon = NULL;
01015 if (semicolon != NULL)
01016 {
01017 semicolon[0] = '\0';
01018 semicolon++;
01019 }
01020
01021 if ((equals[0] == '"') && (equals[strlen (equals) - 1] == '"'))
01022 {
01023 equals[strlen (equals) - 1] = '\0';
01024 equals++;
01025 }
01026 if (MHD_NO == connection_add_header (connection,
01027 pos, equals, MHD_COOKIE_KIND))
01028 return MHD_NO;
01029 pos = semicolon;
01030 }
01031 return MHD_YES;
01032 }
01033
01041 static int
01042 parse_initial_message_line (struct MHD_Connection *connection, char *line)
01043 {
01044 char *uri;
01045 char *httpVersion;
01046 char *args;
01047
01048 uri = strstr (line, " ");
01049 if (uri == NULL)
01050 return MHD_NO;
01051 uri[0] = '\0';
01052 connection->method = line;
01053 uri++;
01054 while (uri[0] == ' ')
01055 uri++;
01056 httpVersion = strstr (uri, " ");
01057 if (httpVersion != NULL)
01058 {
01059 httpVersion[0] = '\0';
01060 httpVersion++;
01061 }
01062 if (connection->daemon->uri_log_callback != NULL)
01063 connection->client_context
01064 =
01065 connection->daemon->uri_log_callback (connection->daemon->
01066 uri_log_callback_cls, uri);
01067 args = strstr (uri, "?");
01068 if (args != NULL)
01069 {
01070 args[0] = '\0';
01071 args++;
01072 parse_arguments (MHD_GET_ARGUMENT_KIND, connection, args);
01073 }
01074 MHD_http_unescape (uri);
01075 connection->url = uri;
01076 if (httpVersion == NULL)
01077 connection->version = "";
01078 else
01079 connection->version = httpVersion;
01080 return MHD_YES;
01081 }
01082
01088 static void
01089 call_connection_handler (struct MHD_Connection *connection)
01090 {
01091 size_t processed;
01092 size_t available;
01093 size_t used;
01094 size_t i;
01095 int instant_retry;
01096 int malformed;
01097 char *buffer_head;
01098
01099 if (connection->response != NULL)
01100 return;
01101
01102 buffer_head = connection->read_buffer;
01103 available = connection->read_buffer_offset;
01104 do
01105 {
01106 instant_retry = MHD_NO;
01107 if ((connection->have_chunked_upload == MHD_YES) &&
01108 (connection->remaining_upload_size == -1))
01109 {
01110 if ((connection->current_chunk_offset ==
01111 connection->current_chunk_size)
01112 && (connection->current_chunk_offset != 0) && (available >= 2))
01113 {
01114
01115 i = 0;
01116 if ((buffer_head[i] == '\r') || (buffer_head[i] == '\n'))
01117 i++;
01118 if ((buffer_head[i] == '\r') || (buffer_head[i] == '\n'))
01119 i++;
01120 if (i == 0)
01121 {
01122
01123 #if HAVE_MESSAGES
01124 MHD_DLOG (connection->daemon,
01125 "Received malformed HTTP request (bad chunked encoding), closing connection.\n");
01126 #endif
01127 connection_close_error (connection);
01128 return;
01129 }
01130 available -= i;
01131 buffer_head += i;
01132 connection->current_chunk_offset = 0;
01133 connection->current_chunk_size = 0;
01134 }
01135 if (connection->current_chunk_offset <
01136 connection->current_chunk_size)
01137 {
01138
01139
01140
01141 processed =
01142 connection->current_chunk_size -
01143 connection->current_chunk_offset;
01144 if (processed > available)
01145 processed = available;
01146 if (available > processed)
01147 instant_retry = MHD_YES;
01148 }
01149 else
01150 {
01151
01152 i = 0;
01153 while (i < available)
01154 {
01155 if ((buffer_head[i] == '\r') || (buffer_head[i] == '\n'))
01156 break;
01157 i++;
01158 if (i >= 6)
01159 break;
01160 }
01161
01162
01163
01164
01165 if ((i + 1 >= available) &&
01166 !((i == 1) && (available == 2) && (buffer_head[0] == '0')))
01167 break;
01168 malformed = (i >= 6);
01169 if (!malformed)
01170 {
01171 buffer_head[i] = '\0';
01172 malformed =
01173 (1 != SSCANF (buffer_head, "%X",
01174 &connection->current_chunk_size)) &&
01175 (1 != SSCANF (buffer_head, "%x",
01176 &connection->current_chunk_size));
01177 }
01178 if (malformed)
01179 {
01180
01181 #if HAVE_MESSAGES
01182 MHD_DLOG (connection->daemon,
01183 "Received malformed HTTP request (bad chunked encoding), closing connection.\n");
01184 #endif
01185 connection_close_error (connection);
01186 return;
01187 }
01188 i++;
01189 if ((i < available) &&
01190 ((buffer_head[i] == '\r') || (buffer_head[i] == '\n')))
01191 i++;
01192
01193 buffer_head += i;
01194 available -= i;
01195 connection->current_chunk_offset = 0;
01196
01197 if (available > 0)
01198 instant_retry = MHD_YES;
01199 if (connection->current_chunk_size == 0)
01200 {
01201 connection->remaining_upload_size = 0;
01202 break;
01203 }
01204 continue;
01205 }
01206 }
01207 else
01208 {
01209
01210 processed = available;
01211 }
01212 used = processed;
01213 if (MHD_NO ==
01214 connection->daemon->default_handler (connection->daemon->
01215 default_handler_cls,
01216 connection, connection->url,
01217 connection->method,
01218 connection->version,
01219 buffer_head, &processed,
01220 &connection->client_context))
01221 {
01222
01223 #if HAVE_MESSAGES
01224 MHD_DLOG (connection->daemon,
01225 "Internal application error, closing connection.\n");
01226 #endif
01227 connection_close_error (connection);
01228 return;
01229 }
01230 if (processed > used)
01231 abort ();
01232 if (processed != 0)
01233 instant_retry = MHD_NO;
01234 used -= processed;
01235 if (connection->have_chunked_upload == MHD_YES)
01236 connection->current_chunk_offset += used;
01237
01238 buffer_head += used;
01239 available -= used;
01240 if (connection->remaining_upload_size != -1)
01241 connection->remaining_upload_size -= used;
01242 }
01243 while (instant_retry == MHD_YES);
01244 if (available > 0)
01245 memmove (connection->read_buffer, buffer_head, available);
01246 connection->read_buffer_offset = available;
01247 }
01248
01257 static int
01258 do_read (struct MHD_Connection *connection)
01259 {
01260 int bytes_read;
01261
01262 if (connection->read_buffer_size == connection->read_buffer_offset)
01263 return MHD_NO;
01264
01265 bytes_read = connection->recv_cls (connection,
01266 &connection->read_buffer
01267 [connection->read_buffer_offset],
01268 connection->read_buffer_size -
01269 connection->read_buffer_offset);
01270 if (bytes_read < 0)
01271 {
01272 if (errno == EINTR)
01273 return MHD_NO;
01274 #if HAVE_MESSAGES
01275 MHD_DLOG (connection->daemon,
01276 "Failed to receive data: %s\n", STRERROR (errno));
01277 #endif
01278 connection_close_error (connection);
01279 return MHD_YES;
01280 }
01281 if (bytes_read == 0)
01282 {
01283
01284 connection->read_closed = MHD_YES;
01285 SHUTDOWN (connection->socket_fd, SHUT_RD);
01286 return MHD_NO;
01287 }
01288 connection->read_buffer_offset += bytes_read;
01289 return MHD_YES;
01290 }
01291
01299 static int
01300 do_write (struct MHD_Connection *connection)
01301 {
01302 int ret;
01303
01304 ret = connection->send_cls (connection,
01305 &connection->write_buffer
01306 [connection->write_buffer_send_offset],
01307 connection->write_buffer_append_offset
01308 - connection->write_buffer_send_offset);
01309
01310 if (ret < 0)
01311 {
01312 if (errno == EINTR)
01313 return MHD_NO;
01314 #if HAVE_MESSAGES
01315 MHD_DLOG (connection->daemon,
01316 "Failed to send data: %s\n", STRERROR (errno));
01317 #endif
01318 connection_close_error (connection);
01319 return MHD_YES;
01320 }
01321 #if DEBUG_SEND_DATA
01322 FPRINTF (stderr,
01323 "Sent response: `%.*s'\n",
01324 ret,
01325 &connection->write_buffer[connection->write_buffer_send_offset]);
01326 #endif
01327 connection->write_buffer_send_offset += ret;
01328 return MHD_YES;
01329 }
01330
01336 static int
01337 check_write_done (struct MHD_Connection *connection,
01338 enum MHD_CONNECTION_STATE next_state)
01339 {
01340 if (connection->write_buffer_append_offset !=
01341 connection->write_buffer_send_offset)
01342 return MHD_NO;
01343 connection->write_buffer_append_offset = 0;
01344 connection->write_buffer_send_offset = 0;
01345 connection->state = next_state;
01346 MHD_pool_reallocate (connection->pool, connection->write_buffer,
01347 connection->write_buffer_size, 0);
01348 connection->write_buffer = NULL;
01349 connection->write_buffer_size = 0;
01350 return MHD_YES;
01351 }
01352
01358 static int
01359 process_header_line (struct MHD_Connection *connection, char *line)
01360 {
01361 char *colon;
01362
01363
01364 colon = strstr (line, ":");
01365 if (colon == NULL)
01366 {
01367
01368 #if HAVE_MESSAGES
01369 MHD_DLOG (connection->daemon,
01370 "Received malformed line (no colon), closing connection.\n");
01371 #endif
01372 connection->state = MHD_CONNECTION_CLOSED;
01373 return MHD_NO;
01374 }
01375
01376 colon[0] = '\0';
01377 colon++;
01378 while ((colon[0] != '\0') && ((colon[0] == ' ') || (colon[0] == '\t')))
01379 colon++;
01380
01381
01382
01383
01384
01385 connection->last = line;
01386 connection->colon = colon;
01387 return MHD_YES;
01388 }
01389
01399 static int
01400 process_broken_line (struct MHD_Connection *connection,
01401 char *line, enum MHD_ValueKind kind)
01402 {
01403 char *last;
01404 char *tmp;
01405
01406 last = connection->last;
01407 if ((line[0] == ' ') || (line[0] == '\t'))
01408 {
01409
01410
01411 last = MHD_pool_reallocate (connection->pool,
01412 last,
01413 strlen (last) + 1,
01414 strlen (line) + strlen (last) + 1);
01415 if (last == NULL)
01416 {
01417 transmit_error_response (connection,
01418 MHD_HTTP_REQUEST_ENTITY_TOO_LARGE,
01419 REQUEST_TOO_BIG);
01420 return MHD_NO;
01421 }
01422 tmp = line;
01423 while ((tmp[0] == ' ') || (tmp[0] == '\t'))
01424 tmp++;
01425 strcat (last, tmp);
01426 connection->last = last;
01427 return MHD_YES;
01428 }
01429 EXTRA_CHECK ((last != NULL) && (connection->colon != NULL));
01430 if ((MHD_NO == connection_add_header (connection,
01431 last, connection->colon, kind)))
01432 {
01433 transmit_error_response (connection, MHD_HTTP_REQUEST_ENTITY_TOO_LARGE,
01434 REQUEST_TOO_BIG);
01435 return MHD_NO;
01436 }
01437
01438 if (strlen (line) != 0)
01439 {
01440 if (MHD_NO == process_header_line (connection, line))
01441 {
01442 transmit_error_response (connection,
01443 MHD_HTTP_BAD_REQUEST, REQUEST_MALFORMED);
01444 return MHD_NO;
01445 }
01446 }
01447 return MHD_YES;
01448 }
01449
01455 static void
01456 parse_connection_headers (struct MHD_Connection *connection)
01457 {
01458 const char *clen;
01459 unsigned long long cval;
01460 struct MHD_Response *response;
01461
01462 parse_cookie_header (connection);
01463 if ((0 != (MHD_USE_PEDANTIC_CHECKS & connection->daemon->options))
01464 && (NULL != connection->version)
01465 && (0 == strcasecmp (MHD_HTTP_VERSION_1_1, connection->version))
01466 && (NULL ==
01467 MHD_lookup_connection_value (connection, MHD_HEADER_KIND,
01468 MHD_HTTP_HEADER_HOST)))
01469 {
01470
01471 connection->state = MHD_CONNECTION_FOOTERS_RECEIVED;
01472 connection->read_closed = MHD_YES;
01473 #if HAVE_MESSAGES
01474 MHD_DLOG (connection->daemon,
01475 "Received `%s' request without `%s' header.\n",
01476 MHD_HTTP_VERSION_1_1, MHD_HTTP_HEADER_HOST);
01477 #endif
01478 response =
01479 MHD_create_response_from_data (strlen (REQUEST_LACKS_HOST),
01480 REQUEST_LACKS_HOST, MHD_NO, MHD_NO);
01481 MHD_queue_response (connection, MHD_HTTP_BAD_REQUEST, response);
01482 MHD_destroy_response (response);
01483 return;
01484 }
01485
01486 clen = MHD_lookup_connection_value (connection,
01487 MHD_HEADER_KIND,
01488 MHD_HTTP_HEADER_CONTENT_LENGTH);
01489 if (clen != NULL)
01490 {
01491 if (1 != SSCANF (clen, "%llu", &cval))
01492 {
01493 #if HAVE_MESSAGES
01494 MHD_DLOG (connection->daemon,
01495 "Failed to parse `%s' header `%s', closing connection.\n",
01496 MHD_HTTP_HEADER_CONTENT_LENGTH, clen);
01497 #endif
01498 connection->state = MHD_CONNECTION_CLOSED;
01499 return;
01500 }
01501 connection->remaining_upload_size = cval;
01502 }
01503 else
01504 {
01505 if (NULL == MHD_lookup_connection_value (connection,
01506 MHD_HEADER_KIND,
01507 MHD_HTTP_HEADER_TRANSFER_ENCODING))
01508 {
01509
01510 connection->remaining_upload_size = 0;
01511 }
01512 else
01513 {
01514 connection->remaining_upload_size = -1;
01515 if (0 ==
01516 strcasecmp (MHD_lookup_connection_value
01517 (connection, MHD_HEADER_KIND,
01518 MHD_HTTP_HEADER_TRANSFER_ENCODING), "chunked"))
01519 connection->have_chunked_upload = MHD_YES;
01520 }
01521 }
01522 }
01523
01533 int
01534 MHD_connection_handle_read (struct MHD_Connection *connection)
01535 {
01536 connection->last_activity = time (NULL);
01537 if (connection->state == MHD_CONNECTION_CLOSED)
01538 return MHD_NO;
01539 if (MHD_NO == do_read (connection))
01540 return MHD_YES;
01541 while (1)
01542 {
01543 #if DEBUG_STATES
01544 MHD_DLOG (connection->daemon, "%s: state: %s\n",
01545 __FUNCTION__, MHD_state_to_string (connection->state));
01546 #endif
01547 switch (connection->state)
01548 {
01549 case MHD_CONNECTION_INIT:
01550 case MHD_CONNECTION_URL_RECEIVED:
01551 case MHD_CONNECTION_HEADER_PART_RECEIVED:
01552 case MHD_CONNECTION_HEADERS_RECEIVED:
01553 case MHD_CONNECTION_HEADERS_PROCESSED:
01554 case MHD_CONNECTION_CONTINUE_SENDING:
01555 case MHD_CONNECTION_CONTINUE_SENT:
01556 case MHD_CONNECTION_BODY_RECEIVED:
01557 case MHD_CONNECTION_FOOTER_PART_RECEIVED:
01558
01559 if (MHD_YES == connection->read_closed)
01560 {
01561 connection->state = MHD_CONNECTION_CLOSED;
01562 continue;
01563 }
01564 break;
01565 case MHD_CONNECTION_CLOSED:
01566 if (connection->socket_fd != -1)
01567 connection_close_error (connection);
01568 return MHD_NO;
01569 default:
01570
01571 MHD_pool_reallocate (connection->pool,
01572 connection->read_buffer,
01573 connection->read_buffer_size + 1,
01574 connection->read_buffer_offset);
01575 break;
01576 }
01577 break;
01578 }
01579 return MHD_YES;
01580 }
01581
01591 int
01592 MHD_connection_handle_write (struct MHD_Connection *connection)
01593 {
01594 struct MHD_Response *response;
01595 int ret;
01596 connection->last_activity = time (NULL);
01597 while (1)
01598 {
01599 #if DEBUG_STATES
01600 MHD_DLOG (connection->daemon, "%s: state: %s\n",
01601 __FUNCTION__, MHD_state_to_string (connection->state));
01602 #endif
01603 switch (connection->state)
01604 {
01605 case MHD_CONNECTION_INIT:
01606 case MHD_CONNECTION_URL_RECEIVED:
01607 case MHD_CONNECTION_HEADER_PART_RECEIVED:
01608 case MHD_CONNECTION_HEADERS_RECEIVED:
01609 EXTRA_CHECK (0);
01610 break;
01611 case MHD_CONNECTION_HEADERS_PROCESSED:
01612 break;
01613 case MHD_CONNECTION_CONTINUE_SENDING:
01614 ret = connection->send_cls (connection,
01615 &HTTP_100_CONTINUE
01616 [connection->continue_message_write_offset],
01617 strlen (HTTP_100_CONTINUE) -
01618 connection->continue_message_write_offset);
01619 if (ret < 0)
01620 {
01621 if (errno == EINTR)
01622 break;
01623 #if HAVE_MESSAGES
01624 MHD_DLOG (connection->daemon,
01625 "Failed to send data: %s\n", STRERROR (errno));
01626 #endif
01627 connection_close_error (connection);
01628 return MHD_NO;
01629 }
01630 #if DEBUG_SEND_DATA
01631 FPRINTF (stderr,
01632 "Sent 100 continue response: `%.*s'\n",
01633 ret,
01634 &HTTP_100_CONTINUE
01635 [connection->continue_message_write_offset]);
01636 #endif
01637 connection->continue_message_write_offset += ret;
01638 break;
01639 case MHD_CONNECTION_CONTINUE_SENT:
01640 case MHD_CONNECTION_BODY_RECEIVED:
01641 case MHD_CONNECTION_FOOTER_PART_RECEIVED:
01642 case MHD_CONNECTION_FOOTERS_RECEIVED:
01643 EXTRA_CHECK (0);
01644 break;
01645 case MHD_CONNECTION_HEADERS_SENDING:
01646 do_write (connection);
01647 check_write_done (connection, MHD_CONNECTION_HEADERS_SENT);
01648 break;
01649 case MHD_CONNECTION_HEADERS_SENT:
01650 EXTRA_CHECK (0);
01651 break;
01652 case MHD_CONNECTION_NORMAL_BODY_READY:
01653 response = connection->response;
01654 if (response->crc != NULL)
01655 pthread_mutex_lock (&response->mutex);
01656 if (MHD_YES != try_ready_normal_body (connection))
01657 {
01658 if (response->crc != NULL)
01659 pthread_mutex_unlock (&response->mutex);
01660 connection->state = MHD_CONNECTION_NORMAL_BODY_UNREADY;
01661 break;
01662 }
01663 #if HTTPS_SUPPORT
01664 if (connection->daemon->options & MHD_USE_SSL)
01665 {
01666 ret = MHD__gnutls_record_send (connection->tls_session,
01667 &connection->response->data
01668 [connection->
01669 response_write_position -
01670 response->data_start],
01671 response->data_size -
01672 (connection->response_write_position
01673 - response->data_start));
01674 }
01675 else
01676 #endif
01677 {
01678 ret = connection->send_cls (connection,
01679 &response->data
01680 [connection->response_write_position
01681 - response->data_start],
01682 response->data_size -
01683 (connection->response_write_position
01684 - response->data_start));
01685 }
01686 #if DEBUG_SEND_DATA
01687 if (ret > 0)
01688 FPRINTF (stderr,
01689 "Sent DATA response: `%.*s'\n",
01690 ret,
01691 &response->data[connection->response_write_position -
01692 response->data_start]);
01693 #endif
01694 if (response->crc != NULL)
01695 pthread_mutex_unlock (&response->mutex);
01696 if (ret < 0)
01697 {
01698 if (errno == EINTR)
01699 return MHD_YES;
01700 #if HAVE_MESSAGES
01701 MHD_DLOG (connection->daemon,
01702 "Failed to send data: %s\n", STRERROR (errno));
01703 #endif
01704 connection_close_error (connection);
01705 return MHD_NO;
01706 }
01707 connection->response_write_position += ret;
01708 if (connection->response_write_position ==
01709 connection->response->total_size)
01710 connection->state = MHD_CONNECTION_FOOTERS_SENT;
01711 break;
01712 case MHD_CONNECTION_NORMAL_BODY_UNREADY:
01713 EXTRA_CHECK (0);
01714 break;
01715 case MHD_CONNECTION_CHUNKED_BODY_READY:
01716 do_write (connection);
01717 check_write_done (connection,
01718 (connection->response->total_size ==
01719 connection->response_write_position) ?
01720 MHD_CONNECTION_BODY_SENT :
01721 MHD_CONNECTION_CHUNKED_BODY_UNREADY);
01722 break;
01723 case MHD_CONNECTION_CHUNKED_BODY_UNREADY:
01724 case MHD_CONNECTION_BODY_SENT:
01725 EXTRA_CHECK (0);
01726 break;
01727 case MHD_CONNECTION_FOOTERS_SENDING:
01728 do_write (connection);
01729 check_write_done (connection, MHD_CONNECTION_FOOTERS_SENT);
01730 break;
01731 case MHD_CONNECTION_FOOTERS_SENT:
01732 EXTRA_CHECK (0);
01733 break;
01734 case MHD_CONNECTION_CLOSED:
01735 if (connection->socket_fd != -1)
01736 connection_close_error (connection);
01737 return MHD_NO;
01738 case MHD_TLS_CONNECTION_INIT:
01739 case MHD_TLS_HELLO_REQUEST:
01740 case MHD_TLS_HANDSHAKE_FAILED:
01741 EXTRA_CHECK (0);
01742 break;
01743 default:
01744 EXTRA_CHECK (0);
01745 connection_close_error (connection);
01746 return MHD_NO;
01747 }
01748 break;
01749 }
01750 return MHD_YES;
01751 }
01752
01762 int
01763 MHD_connection_handle_idle (struct MHD_Connection *connection)
01764 {
01765 unsigned int timeout;
01766 const char *end;
01767 char *line;
01768
01769 while (1)
01770 {
01771 #if DEBUG_STATES
01772 MHD_DLOG (connection->daemon, "%s: state: %s\n",
01773 __FUNCTION__, MHD_state_to_string (connection->state));
01774 #endif
01775 switch (connection->state)
01776 {
01777 case MHD_CONNECTION_INIT:
01778 line = get_next_header_line (connection);
01779 if (line == NULL)
01780 {
01781 if (connection->state != MHD_CONNECTION_INIT)
01782 continue;
01783 if (connection->read_closed)
01784 {
01785 connection->state = MHD_CONNECTION_CLOSED;
01786 continue;
01787 }
01788 break;
01789 }
01790 if (MHD_NO == parse_initial_message_line (connection, line))
01791 connection->state = MHD_CONNECTION_CLOSED;
01792 else
01793 connection->state = MHD_CONNECTION_URL_RECEIVED;
01794 continue;
01795 case MHD_CONNECTION_URL_RECEIVED:
01796 line = get_next_header_line (connection);
01797 if (line == NULL)
01798 {
01799 if (connection->state != MHD_CONNECTION_URL_RECEIVED)
01800 continue;
01801 if (connection->read_closed)
01802 {
01803 connection->state = MHD_CONNECTION_CLOSED;
01804 continue;
01805 }
01806 break;
01807 }
01808 if (strlen (line) == 0)
01809 {
01810 connection->state = MHD_CONNECTION_HEADERS_RECEIVED;
01811 continue;
01812 }
01813 if (MHD_NO == process_header_line (connection, line))
01814 {
01815 transmit_error_response (connection,
01816 MHD_HTTP_BAD_REQUEST,
01817 REQUEST_MALFORMED);
01818 break;
01819 }
01820 connection->state = MHD_CONNECTION_HEADER_PART_RECEIVED;
01821 continue;
01822 case MHD_CONNECTION_HEADER_PART_RECEIVED:
01823 line = get_next_header_line (connection);
01824 if (line == NULL)
01825 {
01826 if (connection->state != MHD_CONNECTION_HEADER_PART_RECEIVED)
01827 continue;
01828 if (connection->read_closed)
01829 {
01830 connection->state = MHD_CONNECTION_CLOSED;
01831 continue;
01832 }
01833 break;
01834 }
01835 if (MHD_NO ==
01836 process_broken_line (connection, line, MHD_HEADER_KIND))
01837 continue;
01838 if (strlen (line) == 0)
01839 {
01840 connection->state = MHD_CONNECTION_HEADERS_RECEIVED;
01841 continue;
01842 }
01843 continue;
01844 case MHD_CONNECTION_HEADERS_RECEIVED:
01845 parse_connection_headers (connection);
01846 if (connection->state == MHD_CONNECTION_CLOSED)
01847 continue;
01848 connection->state = MHD_CONNECTION_HEADERS_PROCESSED;
01849 continue;
01850 case MHD_CONNECTION_HEADERS_PROCESSED:
01851 call_connection_handler (connection);
01852 if (connection->state == MHD_CONNECTION_CLOSED)
01853 continue;
01854 if (need_100_continue (connection))
01855 {
01856 connection->state = MHD_CONNECTION_CONTINUE_SENDING;
01857 break;
01858 }
01859 if (connection->response != NULL)
01860 {
01861
01862 connection->remaining_upload_size = 0;
01863
01864 connection->read_closed = MHD_YES;
01865 }
01866 connection->state = (connection->remaining_upload_size == 0)
01867 ? MHD_CONNECTION_FOOTERS_RECEIVED : MHD_CONNECTION_CONTINUE_SENT;
01868 continue;
01869 case MHD_CONNECTION_CONTINUE_SENDING:
01870 if (connection->continue_message_write_offset ==
01871 strlen (HTTP_100_CONTINUE))
01872 {
01873 connection->state = MHD_CONNECTION_CONTINUE_SENT;
01874 continue;
01875 }
01876 break;
01877 case MHD_CONNECTION_CONTINUE_SENT:
01878 if (connection->read_buffer_offset != 0)
01879 {
01880 call_connection_handler (connection);
01881 if (connection->state == MHD_CONNECTION_CLOSED)
01882 continue;
01883 }
01884 if ((connection->remaining_upload_size == 0) ||
01885 ((connection->remaining_upload_size == -1) &&
01886 (connection->read_buffer_offset == 0) &&
01887 (MHD_YES == connection->read_closed)))
01888 {
01889 if ((MHD_YES == connection->have_chunked_upload) &&
01890 (MHD_NO == connection->read_closed))
01891 connection->state = MHD_CONNECTION_BODY_RECEIVED;
01892 else
01893 connection->state = MHD_CONNECTION_FOOTERS_RECEIVED;
01894 continue;
01895 }
01896 break;
01897 case MHD_CONNECTION_BODY_RECEIVED:
01898 line = get_next_header_line (connection);
01899 if (line == NULL)
01900 {
01901 if (connection->state != MHD_CONNECTION_BODY_RECEIVED)
01902 continue;
01903 if (connection->read_closed)
01904 {
01905 connection->state = MHD_CONNECTION_CLOSED;
01906 continue;
01907 }
01908 break;
01909 }
01910 if (strlen (line) == 0)
01911 {
01912 connection->state = MHD_CONNECTION_FOOTERS_RECEIVED;
01913 continue;
01914 }
01915 if (MHD_NO == process_header_line (connection, line))
01916 {
01917 transmit_error_response (connection,
01918 MHD_HTTP_BAD_REQUEST,
01919 REQUEST_MALFORMED);
01920 break;
01921 }
01922 connection->state = MHD_CONNECTION_FOOTER_PART_RECEIVED;
01923 continue;
01924 case MHD_CONNECTION_FOOTER_PART_RECEIVED:
01925 line = get_next_header_line (connection);
01926 if (line == NULL)
01927 {
01928 if (connection->state != MHD_CONNECTION_FOOTER_PART_RECEIVED)
01929 continue;
01930 if (connection->read_closed)
01931 {
01932 connection->state = MHD_CONNECTION_CLOSED;
01933 continue;
01934 }
01935 break;
01936 }
01937 if (MHD_NO ==
01938 process_broken_line (connection, line, MHD_FOOTER_KIND))
01939 continue;
01940 if (strlen (line) == 0)
01941 {
01942 connection->state = MHD_CONNECTION_FOOTERS_RECEIVED;
01943 continue;
01944 }
01945 continue;
01946 case MHD_CONNECTION_FOOTERS_RECEIVED:
01947 call_connection_handler (connection);
01948 if (connection->state == MHD_CONNECTION_CLOSED)
01949 continue;
01950 if (connection->response == NULL)
01951 break;
01952 if (MHD_NO == build_header_response (connection))
01953 {
01954
01955 #if HAVE_MESSAGES
01956 MHD_DLOG (connection->daemon,
01957 "Closing connection (failed to create response header)\n");
01958 #endif
01959 connection->state = MHD_CONNECTION_CLOSED;
01960 continue;
01961 }
01962 connection->state = MHD_CONNECTION_HEADERS_SENDING;
01963
01964 #if HAVE_TCP_CORK
01965
01966 {
01967 const int val = 1;
01968 setsockopt (connection->socket_fd, IPPROTO_TCP, TCP_CORK, &val,
01969 sizeof (val));
01970 }
01971 #endif
01972 break;
01973 case MHD_CONNECTION_HEADERS_SENDING:
01974
01975 break;
01976 case MHD_CONNECTION_HEADERS_SENT:
01977 if (connection->have_chunked_upload)
01978 connection->state = MHD_CONNECTION_CHUNKED_BODY_UNREADY;
01979 else
01980 connection->state = MHD_CONNECTION_NORMAL_BODY_UNREADY;
01981 continue;
01982 case MHD_CONNECTION_NORMAL_BODY_READY:
01983
01984 break;
01985 case MHD_CONNECTION_NORMAL_BODY_UNREADY:
01986 if (connection->response->crc != NULL)
01987 pthread_mutex_lock (&connection->response->mutex);
01988 if (MHD_YES == try_ready_normal_body (connection))
01989 {
01990 if (connection->response->crc != NULL)
01991 pthread_mutex_unlock (&connection->response->mutex);
01992 connection->state = MHD_CONNECTION_NORMAL_BODY_READY;
01993 break;
01994 }
01995 if (connection->response->crc != NULL)
01996 pthread_mutex_unlock (&connection->response->mutex);
01997
01998 break;
01999 case MHD_CONNECTION_CHUNKED_BODY_READY:
02000
02001 break;
02002 case MHD_CONNECTION_CHUNKED_BODY_UNREADY:
02003 if (connection->response->crc != NULL)
02004 pthread_mutex_lock (&connection->response->mutex);
02005 if (MHD_YES == try_ready_chunked_body (connection))
02006 {
02007 if (connection->response->crc != NULL)
02008 pthread_mutex_unlock (&connection->response->mutex);
02009 connection->state = MHD_CONNECTION_CHUNKED_BODY_READY;
02010 continue;
02011 }
02012 if (connection->response->crc != NULL)
02013 pthread_mutex_unlock (&connection->response->mutex);
02014 break;
02015 case MHD_CONNECTION_BODY_SENT:
02016 build_header_response (connection);
02017 if (connection->write_buffer_send_offset ==
02018 connection->write_buffer_append_offset)
02019 connection->state = MHD_CONNECTION_FOOTERS_SENT;
02020 else
02021 connection->state = MHD_CONNECTION_FOOTERS_SENDING;
02022 continue;
02023 case MHD_CONNECTION_FOOTERS_SENDING:
02024
02025 break;
02026 case MHD_CONNECTION_FOOTERS_SENT:
02027 #if HAVE_TCP_CORK
02028
02029 {
02030 const int val = 0;
02031 setsockopt (connection->socket_fd, IPPROTO_TCP, TCP_CORK, &val,
02032 sizeof (val));
02033 }
02034 #endif
02035 MHD_destroy_response (connection->response);
02036 if (connection->daemon->notify_completed != NULL)
02037 connection->daemon->notify_completed (connection->daemon->
02038 notify_completed_cls,
02039 connection,
02040 &connection->client_context,
02041 MHD_REQUEST_TERMINATED_COMPLETED_OK);
02042 end =
02043 MHD_lookup_connection_value (connection, MHD_HEADER_KIND,
02044 MHD_HTTP_HEADER_CONNECTION);
02045 connection->client_context = NULL;
02046 connection->continue_message_write_offset = 0;
02047 connection->responseCode = 0;
02048 connection->response = NULL;
02049 connection->headers_received = NULL;
02050 connection->response_write_position = 0;
02051 connection->have_chunked_upload = MHD_NO;
02052 connection->method = NULL;
02053 connection->url = NULL;
02054 connection->write_buffer = NULL;
02055 connection->write_buffer_size = 0;
02056 connection->write_buffer_send_offset = 0;
02057 connection->write_buffer_append_offset = 0;
02058 if ((end != NULL) && (0 == strcasecmp (end, "close")))
02059 {
02060 connection->read_closed = MHD_YES;
02061 connection->read_buffer_offset = 0;
02062 }
02063 if (((MHD_YES == connection->read_closed) &&
02064 (0 == connection->read_buffer_offset)) ||
02065 (connection->version == NULL) ||
02066 (0 != strcasecmp (MHD_HTTP_VERSION_1_1, connection->version)))
02067 {
02068
02069 connection->state = MHD_CONNECTION_CLOSED;
02070 MHD_pool_destroy (connection->pool);
02071 connection->pool = NULL;
02072 connection->read_buffer = NULL;
02073 connection->read_buffer_size = 0;
02074 connection->read_buffer_offset = 0;
02075 }
02076 else
02077 {
02078 connection->version = NULL;
02079 connection->state = MHD_CONNECTION_INIT;
02080 connection->read_buffer
02081 = MHD_pool_reset (connection->pool,
02082 connection->read_buffer,
02083 connection->read_buffer_size);
02084 }
02085 continue;
02086 case MHD_CONNECTION_CLOSED:
02087 if (connection->socket_fd != -1)
02088 connection_close_error (connection);
02089 break;
02090 default:
02091 EXTRA_CHECK (0);
02092 break;
02093 }
02094 break;
02095 }
02096 timeout = connection->daemon->connection_timeout;
02097 if ((connection->socket_fd != -1) &&
02098 (timeout != 0) && (time (NULL) - timeout > connection->last_activity))
02099 {
02100 connection_close_error (connection);
02101 return MHD_NO;
02102 }
02103 return MHD_YES;
02104
02105 }
02106
02107 void
02108 MHD_set_http_calbacks (struct MHD_Connection *connection)
02109 {
02110 connection->read_handler = &MHD_connection_handle_read;
02111 connection->write_handler = &MHD_connection_handle_write;
02112 connection->idle_handler = &MHD_connection_handle_idle;
02113 }
02114
02115 #if HTTPS_SUPPORT
02116 #include "gnutls_int.h"
02117 #include "gnutls_record.h"
02118 #endif
02119
02129 const union MHD_ConnectionInfo *
02130 MHD_get_connection_info (struct MHD_Connection *connection,
02131 enum MHD_ConnectionInfoType infoType, ...)
02132 {
02133 switch (infoType)
02134 {
02135 #if HTTPS_SUPPORT
02136 case MHD_CONNECTION_INFO_CIPHER_ALGO:
02137 if (connection->tls_session == NULL)
02138 return NULL;
02139 return (const union MHD_ConnectionInfo *) &connection->
02140 tls_session->security_parameters.read_bulk_cipher_algorithm;
02141 case MHD_CONNECTION_INFO_PROTOCOL:
02142 if (connection->tls_session == NULL)
02143 return NULL;
02144 return (const union MHD_ConnectionInfo *) &connection->
02145 tls_session->security_parameters.version;
02146 #endif
02147 case MHD_CONNECTION_INFO_CLIENT_ADDRESS:
02148 return (const union MHD_ConnectionInfo *) &connection->addr;
02149 default:
02150 return NULL;
02151 };
02152 }
02153
02154
02155