00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00028 #include "internal.h"
00029 #include "connection.h"
00030 #include "memorypool.h"
00031 #include "response.h"
00032 #include "reason_phrase.h"
00033
00034 #if HAVE_NETINET_TCP_H
00035
00036 #include <netinet/tcp.h>
00037 #endif
00038
00042 #define HTTP_100_CONTINUE "HTTP/1.1 100 Continue\r\n\r\n"
00043
00051 #if HAVE_MESSAGES
00052 #define REQUEST_TOO_BIG "<html><head><title>Request too big</title></head><body>Your HTTP header was too big for the memory constraints of this webserver.</body></html>"
00053 #else
00054 #define REQUEST_TOO_BIG ""
00055 #endif
00056
00064 #if HAVE_MESSAGES
00065 #define REQUEST_LACKS_HOST "<html><head><title>"Host:" header required</title></head><body>In HTTP 1.1, requests must include a "Host:" header, and your HTTP 1.1 request lacked such a header.</body></html>"
00066 #else
00067 #define REQUEST_LACKS_HOST ""
00068 #endif
00069
00077 #if HAVE_MESSAGES
00078 #define REQUEST_MALFORMED "<html><head><title>Request malformed</title></head><body>Your HTTP request was syntactically incorrect.</body></html>"
00079 #else
00080 #define REQUEST_MALFORMED ""
00081 #endif
00082
00089 #if HAVE_MESSAGES
00090 #define INTERNAL_ERROR "<html><head><title>Internal server error</title></head><body>Some programmer needs to study the manual more carefully.</body></html>"
00091 #else
00092 #define INTERNAL_ERROR ""
00093 #endif
00094
00099 #define DEBUG_CLOSE MHD_NO
00100
00104 #define DEBUG_SEND_DATA MHD_NO
00105
00114 int
00115 MHD_get_connection_values (struct MHD_Connection *connection,
00116 enum MHD_ValueKind kind,
00117 MHD_KeyValueIterator iterator, void *iterator_cls)
00118 {
00119 int ret;
00120 struct MHD_HTTP_Header *pos;
00121
00122 if (connection == NULL)
00123 return -1;
00124 ret = 0;
00125 pos = connection->headers_received;
00126 while (pos != NULL)
00127 {
00128 if (0 != (pos->kind & kind))
00129 {
00130 ret++;
00131 if ((iterator != NULL) &&
00132 (MHD_YES != iterator (iterator_cls,
00133 kind, pos->header, pos->value)))
00134 return ret;
00135 }
00136 pos = pos->next;
00137 }
00138 return ret;
00139 }
00140
00170 int
00171 MHD_set_connection_value (struct MHD_Connection *connection,
00172 enum MHD_ValueKind kind,
00173 const char *key, const char *value)
00174 {
00175 struct MHD_HTTP_Header *pos;
00176
00177 pos = MHD_pool_allocate (connection->pool,
00178 sizeof (struct MHD_HTTP_Header), MHD_NO);
00179 if (pos == NULL)
00180 return MHD_NO;
00181 pos->header = (char *) key;
00182 pos->value = (char *) value;
00183 pos->kind = kind;
00184 pos->next = connection->headers_received;
00185 connection->headers_received = pos;
00186 return MHD_YES;
00187 }
00188
00196 const char *
00197 MHD_lookup_connection_value (struct MHD_Connection *connection,
00198 enum MHD_ValueKind kind, const char *key)
00199 {
00200 struct MHD_HTTP_Header *pos;
00201
00202 if (connection == NULL)
00203 return NULL;
00204 pos = connection->headers_received;
00205 while (pos != NULL)
00206 {
00207 if ((0 != (pos->kind & kind)) && (0 == strcasecmp (key, pos->header)))
00208 return pos->value;
00209 pos = pos->next;
00210 }
00211 return NULL;
00212 }
00213
00224 int
00225 MHD_queue_response (struct MHD_Connection *connection,
00226 unsigned int status_code, struct MHD_Response *response)
00227 {
00228 if ((connection == NULL) ||
00229 (response == NULL) ||
00230 (connection->response != NULL) ||
00231 ((connection->state != MHD_CONNECTION_HEADERS_PROCESSED) &&
00232 (connection->state != MHD_CONNECTION_FOOTERS_RECEIVED)))
00233 return MHD_NO;
00234 MHD_increment_response_rc (response);
00235 connection->response = response;
00236 connection->responseCode = status_code;
00237 if ((connection->method != NULL) &&
00238 (0 == strcasecmp (connection->method, MHD_HTTP_METHOD_HEAD)))
00239 {
00240
00241
00242 connection->response_write_position = response->total_size;
00243 }
00244 if ((response->total_size == MHD_SIZE_UNKNOWN) &&
00245 (0 == strcasecmp (connection->version, MHD_HTTP_VERSION_1_1)))
00246 connection->have_chunked_response = MHD_YES;
00247 else
00248 connection->have_chunked_response = MHD_NO;
00249 if (connection->state == MHD_CONNECTION_HEADERS_PROCESSED)
00250 {
00251
00252
00253
00254 SHUTDOWN (connection->socket_fd, SHUT_RD);
00255 connection->read_closed = MHD_YES;
00256 connection->state = MHD_CONNECTION_FOOTERS_RECEIVED;
00257 }
00258 return MHD_YES;
00259 }
00260
00265 static int
00266 need_100_continue (struct MHD_Connection *connection)
00267 {
00268 const char *expect;
00269
00270 return ((connection->response == NULL) &&
00271 (connection->version != NULL) &&
00272 (0 == strcasecmp (connection->version,
00273 MHD_HTTP_VERSION_1_1)) &&
00274 (NULL != (expect = MHD_lookup_connection_value (connection,
00275 MHD_HEADER_KIND,
00276 MHD_HTTP_HEADER_EXPECT)))
00277 && (0 == strcasecmp (expect, "100-continue"))
00278 && (connection->continue_message_write_offset <
00279 strlen (HTTP_100_CONTINUE)));
00280 }
00281
00286 void
00287 MHD_connection_close (struct MHD_Connection *connection,
00288 enum MHD_RequestTerminationCode termination_code)
00289 {
00290 SHUTDOWN (connection->socket_fd, SHUT_RDWR);
00291 CLOSE (connection->socket_fd);
00292 connection->socket_fd = -1;
00293 connection->state = MHD_CONNECTION_CLOSED;
00294 if ( (NULL != connection->daemon->notify_completed) &&
00295 (MHD_YES == connection->client_aware) )
00296 connection->daemon->notify_completed (connection->daemon->
00297 notify_completed_cls, connection,
00298 &connection->client_context,
00299 termination_code);
00300 connection->client_aware = MHD_NO;
00301 }
00302
00307 static void
00308 connection_close_error (struct MHD_Connection *connection)
00309 {
00310 MHD_connection_close (connection, MHD_REQUEST_TERMINATED_WITH_ERROR);
00311 }
00312
00322 static int
00323 try_ready_normal_body (struct MHD_Connection *connection)
00324 {
00325 int ret;
00326 struct MHD_Response *response;
00327
00328 response = connection->response;
00329 if (response->crc == NULL)
00330 return MHD_YES;
00331 if ( (response->data_start <=
00332 connection->response_write_position) &&
00333 (response->data_size + response->data_start >
00334 connection->response_write_position) )
00335 return MHD_YES;
00336 ret = response->crc (response->crc_cls,
00337 connection->response_write_position,
00338 response->data,
00339 MHD_MIN (response->data_buffer_size,
00340 response->total_size -
00341 connection->response_write_position));
00342 if ((ret == 0) &&
00343 (0 != (connection->daemon->options & MHD_USE_SELECT_INTERNALLY)))
00344 mhd_panic (mhd_panic_cls, __FILE__, __LINE__,
00345 #if HAVE_MESSAGES
00346 "API violation"
00347 #else
00348 NULL
00349 #endif
00350 );
00351 if (ret == -1)
00352 {
00353
00354
00355 #if DEBUG_CLOSE
00356 #if HAVE_MESSAGES
00357 MHD_DLOG (connection->daemon, "Closing connection (end of response)\n");
00358 #endif
00359 #endif
00360 response->total_size = connection->response_write_position;
00361 connection_close_error (connection);
00362 return MHD_NO;
00363 }
00364 response->data_start = connection->response_write_position;
00365 response->data_size = ret;
00366 if (ret == 0)
00367 return MHD_NO;
00368 return MHD_YES;
00369 }
00370
00380 static int
00381 try_ready_chunked_body (struct MHD_Connection *connection)
00382 {
00383 int ret;
00384 char *buf;
00385 struct MHD_Response *response;
00386 size_t size;
00387 char cbuf[10];
00388 int cblen;
00389
00390 response = connection->response;
00391 if (connection->write_buffer_size == 0)
00392 {
00393 size = connection->daemon->pool_size;
00394 do
00395 {
00396 size /= 2;
00397 if (size < 128)
00398 {
00399
00400 #if DEBUG_CLOSE
00401 #if HAVE_MESSAGES
00402 MHD_DLOG (connection->daemon,
00403 "Closing connection (out of memory)\n");
00404 #endif
00405 #endif
00406 connection_close_error (connection);
00407 return MHD_NO;
00408 }
00409 buf = MHD_pool_allocate (connection->pool, size, MHD_NO);
00410 }
00411 while (buf == NULL);
00412 connection->write_buffer_size = size;
00413 connection->write_buffer = buf;
00414 }
00415
00416 if ( (response->data_start <=
00417 connection->response_write_position) &&
00418 (response->data_size + response->data_start >
00419 connection->response_write_position) )
00420 {
00421
00422 ret = response->data_size + response->data_start - connection->response_write_position;
00423 if (ret > connection->write_buffer_size - sizeof (cbuf) - 2)
00424 ret = connection->write_buffer_size - sizeof (cbuf) - 2;
00425 memcpy (&connection->write_buffer[sizeof (cbuf)],
00426 &response->data[connection->response_write_position - response->data_start],
00427 ret);
00428 }
00429 else
00430 {
00431
00432 ret = response->crc (response->crc_cls,
00433 connection->response_write_position,
00434 &connection->write_buffer[sizeof (cbuf)],
00435 connection->write_buffer_size - sizeof (cbuf) - 2);
00436 }
00437 if (ret == -1)
00438 {
00439
00440 strcpy (connection->write_buffer, "0\r\n");
00441 connection->write_buffer_append_offset = 3;
00442 connection->write_buffer_send_offset = 0;
00443 response->total_size = connection->response_write_position;
00444 return MHD_YES;
00445 }
00446 if (ret == 0)
00447 {
00448 connection->state = MHD_CONNECTION_CHUNKED_BODY_UNREADY;
00449 return MHD_NO;
00450 }
00451 if (ret > 0xFFFFFF)
00452 ret = 0xFFFFFF;
00453 SPRINTF (cbuf, "%X\r\n", ret);
00454 cblen = strlen (cbuf);
00455 EXTRA_CHECK (cblen <= sizeof (cbuf));
00456 memcpy (&connection->write_buffer[sizeof (cbuf) - cblen], cbuf, cblen);
00457 memcpy (&connection->write_buffer[sizeof (cbuf) + ret], "\r\n", 2);
00458 connection->response_write_position += ret;
00459 connection->write_buffer_send_offset = sizeof (cbuf) - cblen;
00460 connection->write_buffer_append_offset = sizeof (cbuf) + ret + 2;
00461 return MHD_YES;
00462 }
00463
00468 static void
00469 add_extra_headers (struct MHD_Connection *connection)
00470 {
00471 const char *have;
00472 char buf[128];
00473
00474 connection->have_chunked_upload = MHD_NO;
00475 if (connection->response->total_size == MHD_SIZE_UNKNOWN)
00476 {
00477 have = MHD_get_response_header (connection->response,
00478 MHD_HTTP_HEADER_CONNECTION);
00479 if ((have == NULL) || (0 != strcasecmp (have, "close")))
00480 {
00481 if ((connection->version != NULL) &&
00482 (0 == strcasecmp (connection->version, MHD_HTTP_VERSION_1_1)))
00483 {
00484 connection->have_chunked_upload = MHD_YES;
00485 have = MHD_get_response_header (connection->response,
00486 MHD_HTTP_HEADER_TRANSFER_ENCODING);
00487 if (have == NULL)
00488 MHD_add_response_header (connection->response,
00489 MHD_HTTP_HEADER_TRANSFER_ENCODING,
00490 "chunked");
00491 }
00492 else
00493 {
00494 MHD_add_response_header (connection->response,
00495 MHD_HTTP_HEADER_CONNECTION, "close");
00496 }
00497 }
00498 }
00499 else if (NULL == MHD_get_response_header (connection->response,
00500 MHD_HTTP_HEADER_CONTENT_LENGTH))
00501 {
00502 SPRINTF (buf,
00503 "%llu",
00504 (unsigned long long)connection->response->total_size);
00505 MHD_add_response_header (connection->response,
00506 MHD_HTTP_HEADER_CONTENT_LENGTH, buf);
00507 }
00508 }
00509
00516 static void
00517 get_date_string (char *date)
00518 {
00519 static const char *days[] =
00520 { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" };
00521 static const char *mons[] =
00522 { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct",
00523 "Nov", "Dec"
00524 };
00525 struct tm now;
00526 time_t t;
00527
00528 time (&t);
00529 gmtime_r (&t, &now);
00530 SPRINTF (date,
00531 "Date: %3s, %02u %3s %04u %02u:%02u:%02u GMT\r\n",
00532 days[now.tm_wday % 7],
00533 now.tm_mday,
00534 mons[now.tm_mon % 12],
00535 1900 + now.tm_year, now.tm_hour, now.tm_min, now.tm_sec);
00536 }
00537
00543 static int
00544 try_grow_read_buffer (struct MHD_Connection *connection)
00545 {
00546 void *buf;
00547
00548 buf = MHD_pool_reallocate (connection->pool,
00549 connection->read_buffer,
00550 connection->read_buffer_size,
00551 connection->read_buffer_size * 2 +
00552 MHD_BUF_INC_SIZE + 1);
00553 if (buf == NULL)
00554 return MHD_NO;
00555
00556 connection->read_buffer = buf;
00557 connection->read_buffer_size =
00558 connection->read_buffer_size * 2 + MHD_BUF_INC_SIZE;
00559 return MHD_YES;
00560 }
00561
00568 static int
00569 build_header_response (struct MHD_Connection *connection)
00570 {
00571 size_t size;
00572 size_t off;
00573 struct MHD_HTTP_Header *pos;
00574 char code[256];
00575 char date[128];
00576 char *data;
00577 enum MHD_ValueKind kind;
00578 const char *reason_phrase;
00579
00580 if (connection->state == MHD_CONNECTION_FOOTERS_RECEIVED)
00581 {
00582 add_extra_headers (connection);
00583 reason_phrase = MHD_get_reason_phrase_for (connection->responseCode);
00584 SPRINTF (code,
00585 "%s %u %s\r\n",
00586 MHD_HTTP_VERSION_1_1, connection->responseCode, reason_phrase);
00587 off = strlen (code);
00588
00589 size = off + 2;
00590 kind = MHD_HEADER_KIND;
00591 if (NULL == MHD_get_response_header (connection->response,
00592 MHD_HTTP_HEADER_DATE))
00593 get_date_string (date);
00594 else
00595 date[0] = '\0';
00596 size += strlen (date);
00597 }
00598 else
00599 {
00600 size = 2;
00601 kind = MHD_FOOTER_KIND;
00602 off = 0;
00603 }
00604 pos = connection->response->first_header;
00605 while (pos != NULL)
00606 {
00607 if (pos->kind == kind)
00608 size += strlen (pos->header) + strlen (pos->value) + 4;
00609 pos = pos->next;
00610 }
00611
00612 data = MHD_pool_allocate (connection->pool, size + 1, MHD_YES);
00613 if (data == NULL)
00614 {
00615 #if HAVE_MESSAGES
00616 MHD_DLOG (connection->daemon, "Not enough memory for write!\n");
00617 #endif
00618 return MHD_NO;
00619 }
00620 if (connection->state == MHD_CONNECTION_FOOTERS_RECEIVED)
00621 {
00622 memcpy (data, code, off);
00623 }
00624 pos = connection->response->first_header;
00625 while (pos != NULL)
00626 {
00627 if (pos->kind == kind)
00628 off += SPRINTF (&data[off], "%s: %s\r\n", pos->header, pos->value);
00629 pos = pos->next;
00630 }
00631 if (connection->state == MHD_CONNECTION_FOOTERS_RECEIVED)
00632 {
00633 strcpy (&data[off], date);
00634 off += strlen (date);
00635 }
00636 memcpy (&data[off], "\r\n", 2);
00637 off += 2;
00638 if (off != size)
00639 mhd_panic (mhd_panic_cls, __FILE__, __LINE__, NULL);
00640 connection->write_buffer = data;
00641 connection->write_buffer_append_offset = size;
00642 connection->write_buffer_send_offset = 0;
00643 connection->write_buffer_size = size + 1;
00644 return MHD_YES;
00645 }
00646
00654 static void
00655 transmit_error_response (struct MHD_Connection *connection,
00656 unsigned int status_code, const char *message)
00657 {
00658 struct MHD_Response *response;
00659
00660
00661 connection->state = MHD_CONNECTION_FOOTERS_RECEIVED;
00662 connection->read_closed = MHD_YES;
00663 #if HAVE_MESSAGES
00664 MHD_DLOG (connection->daemon,
00665 "Error %u (`%s') processing request, closing connection.\n",
00666 status_code, message);
00667 #endif
00668 response = MHD_create_response_from_data (strlen (message),
00669 (void *) message, MHD_NO, MHD_NO);
00670 MHD_queue_response (connection, status_code, response);
00671 EXTRA_CHECK (connection->response != NULL);
00672 MHD_destroy_response (response);
00673 if (MHD_NO == build_header_response (connection))
00674 {
00675
00676 #if HAVE_MESSAGES
00677 MHD_DLOG (connection->daemon,
00678 "Closing connection (failed to create response header)\n");
00679 #endif
00680 connection->state = MHD_CONNECTION_CLOSED;
00681 }
00682 else
00683 {
00684 connection->state = MHD_CONNECTION_HEADERS_SENDING;
00685 }
00686 }
00687
00692 static void
00693 do_fd_set (int fd, fd_set * set, int *max_fd)
00694 {
00695 FD_SET (fd, set);
00696 if (fd > *max_fd)
00697 *max_fd = fd;
00698 }
00699
00705 int
00706 MHD_connection_get_fdset (struct MHD_Connection *connection,
00707 fd_set * read_fd_set,
00708 fd_set * write_fd_set,
00709 fd_set * except_fd_set, int *max_fd)
00710 {
00711 int ret;
00712 struct MHD_Pollfd p;
00713
00714 memset(&p, 0, sizeof(struct MHD_Pollfd));
00715 ret = MHD_connection_get_pollfd(connection, &p);
00716 if ( (ret == MHD_YES) && (p.fd >= 0) ) {
00717 if (0 != (p.events & MHD_POLL_ACTION_IN))
00718 do_fd_set(p.fd, read_fd_set, max_fd);
00719 if (0 != (p.events & MHD_POLL_ACTION_OUT))
00720 do_fd_set(p.fd, write_fd_set, max_fd);
00721 }
00722 return ret;
00723 }
00724
00731 int
00732 MHD_connection_get_pollfd(struct MHD_Connection *connection, struct MHD_Pollfd *p)
00733 {
00734 int fd;
00735
00736 if (connection->pool == NULL)
00737 connection->pool = MHD_pool_create (connection->daemon->pool_size);
00738 if (connection->pool == NULL)
00739 {
00740 #if HAVE_MESSAGES
00741 MHD_DLOG (connection->daemon, "Failed to create memory pool!\n");
00742 #endif
00743 connection_close_error (connection);
00744 return MHD_NO;
00745 }
00746 fd = connection->socket_fd;
00747 p->fd = fd;
00748 if (fd == -1)
00749 return MHD_YES;
00750 while (1)
00751 {
00752 #if DEBUG_STATES
00753 MHD_DLOG (connection->daemon, "%s: state: %s\n",
00754 __FUNCTION__, MHD_state_to_string (connection->state));
00755 #endif
00756 switch (connection->state)
00757 {
00758 case MHD_CONNECTION_INIT:
00759 case MHD_CONNECTION_URL_RECEIVED:
00760 case MHD_CONNECTION_HEADER_PART_RECEIVED:
00761 #if HTTPS_SUPPORT
00762 case MHD_TLS_CONNECTION_INIT:
00763 #endif
00764
00765
00766 if ((connection->read_closed) &&
00767 (connection->read_buffer_offset == 0))
00768 {
00769 connection->state = MHD_CONNECTION_CLOSED;
00770 continue;
00771 }
00772 if ((connection->read_buffer_offset == connection->read_buffer_size)
00773 && (MHD_NO == try_grow_read_buffer (connection)))
00774 {
00775 transmit_error_response (connection,
00776 (connection->url != NULL)
00777 ? MHD_HTTP_REQUEST_ENTITY_TOO_LARGE
00778 : MHD_HTTP_REQUEST_URI_TOO_LONG,
00779 REQUEST_TOO_BIG);
00780 continue;
00781 }
00782 if (MHD_NO == connection->read_closed)
00783 p->events |= MHD_POLL_ACTION_IN;
00784 break;
00785 case MHD_CONNECTION_HEADERS_RECEIVED:
00786
00787 EXTRA_CHECK (0);
00788 break;
00789 case MHD_CONNECTION_HEADERS_PROCESSED:
00790 EXTRA_CHECK (0);
00791 break;
00792 case MHD_CONNECTION_CONTINUE_SENDING:
00793 p->events |= MHD_POLL_ACTION_OUT;
00794 break;
00795 case MHD_CONNECTION_CONTINUE_SENT:
00796 if (connection->read_buffer_offset == connection->read_buffer_size)
00797 {
00798 if ((MHD_YES != try_grow_read_buffer (connection)) &&
00799 (0 != (connection->daemon->options &
00800 (MHD_USE_SELECT_INTERNALLY |
00801 MHD_USE_THREAD_PER_CONNECTION))))
00802 {
00803
00804
00805
00806
00807
00808
00809
00810
00811
00812
00813
00814 transmit_error_response (connection,
00815 MHD_HTTP_INTERNAL_SERVER_ERROR,
00816 INTERNAL_ERROR);
00817 continue;
00818 }
00819 }
00820 if ((connection->read_buffer_offset < connection->read_buffer_size)
00821 && (MHD_NO == connection->read_closed))
00822 p->events |= MHD_POLL_ACTION_IN;
00823 break;
00824 case MHD_CONNECTION_BODY_RECEIVED:
00825 case MHD_CONNECTION_FOOTER_PART_RECEIVED:
00826
00827
00828 if (MHD_YES == connection->read_closed)
00829 {
00830 connection->state = MHD_CONNECTION_CLOSED;
00831 continue;
00832 }
00833 p->events |= MHD_POLL_ACTION_IN;
00834
00835
00836 break;
00837 case MHD_CONNECTION_FOOTERS_RECEIVED:
00838
00839
00840 break;
00841 case MHD_CONNECTION_HEADERS_SENDING:
00842
00843 p->events |= MHD_POLL_ACTION_OUT;
00844 break;
00845 case MHD_CONNECTION_HEADERS_SENT:
00846 EXTRA_CHECK (0);
00847 break;
00848 case MHD_CONNECTION_NORMAL_BODY_READY:
00849 p->events |= MHD_POLL_ACTION_OUT;
00850 break;
00851 case MHD_CONNECTION_NORMAL_BODY_UNREADY:
00852
00853 break;
00854 case MHD_CONNECTION_CHUNKED_BODY_READY:
00855 p->events |= MHD_POLL_ACTION_OUT;
00856 break;
00857 case MHD_CONNECTION_CHUNKED_BODY_UNREADY:
00858
00859 break;
00860 case MHD_CONNECTION_BODY_SENT:
00861 EXTRA_CHECK (0);
00862 break;
00863 case MHD_CONNECTION_FOOTERS_SENDING:
00864 p->events |= MHD_POLL_ACTION_OUT;
00865 break;
00866 case MHD_CONNECTION_FOOTERS_SENT:
00867 EXTRA_CHECK (0);
00868 break;
00869 case MHD_CONNECTION_CLOSED:
00870 if (connection->socket_fd != -1)
00871 connection_close_error (connection);
00872 return MHD_YES;
00873
00874 default:
00875 EXTRA_CHECK (0);
00876 }
00877 break;
00878 }
00879 return MHD_YES;
00880 }
00881
00890 static char *
00891 get_next_header_line (struct MHD_Connection *connection)
00892 {
00893 char *rbuf;
00894 size_t pos;
00895
00896 if (connection->read_buffer_offset == 0)
00897 return NULL;
00898 pos = 0;
00899 rbuf = connection->read_buffer;
00900 while ((pos < connection->read_buffer_offset - 1) &&
00901 (rbuf[pos] != '\r') && (rbuf[pos] != '\n'))
00902 pos++;
00903 if (pos == connection->read_buffer_offset - 1)
00904 {
00905
00906 if (connection->read_buffer_offset == connection->read_buffer_size)
00907 {
00908 rbuf = MHD_pool_reallocate (connection->pool,
00909 connection->read_buffer,
00910 connection->read_buffer_size,
00911 connection->read_buffer_size * 2 +
00912 MHD_BUF_INC_SIZE);
00913 if (rbuf == NULL)
00914 {
00915 transmit_error_response (connection,
00916 (connection->url != NULL)
00917 ? MHD_HTTP_REQUEST_ENTITY_TOO_LARGE
00918 : MHD_HTTP_REQUEST_URI_TOO_LONG,
00919 REQUEST_TOO_BIG);
00920 }
00921 else
00922 {
00923 connection->read_buffer_size =
00924 connection->read_buffer_size * 2 + MHD_BUF_INC_SIZE;
00925 connection->read_buffer = rbuf;
00926 }
00927 }
00928 return NULL;
00929 }
00930
00931 if ((rbuf[pos] == '\r') && (rbuf[pos + 1] == '\n'))
00932 rbuf[pos++] = '\0';
00933 rbuf[pos++] = '\0';
00934 connection->read_buffer += pos;
00935 connection->read_buffer_size -= pos;
00936 connection->read_buffer_offset -= pos;
00937 return rbuf;
00938 }
00939
00943 static int
00944 connection_add_header (struct MHD_Connection *connection,
00945 char *key, char *value, enum MHD_ValueKind kind)
00946 {
00947 struct MHD_HTTP_Header *hdr;
00948
00949 hdr = MHD_pool_allocate (connection->pool,
00950 sizeof (struct MHD_HTTP_Header), MHD_YES);
00951 if (hdr == NULL)
00952 {
00953 #if HAVE_MESSAGES
00954 MHD_DLOG (connection->daemon,
00955 "Not enough memory to allocate header record!\n");
00956 #endif
00957 transmit_error_response (connection, MHD_HTTP_REQUEST_ENTITY_TOO_LARGE,
00958 REQUEST_TOO_BIG);
00959 return MHD_NO;
00960 }
00961 hdr->next = connection->headers_received;
00962 hdr->header = key;
00963 hdr->value = value;
00964 hdr->kind = kind;
00965 connection->headers_received = hdr;
00966 return MHD_YES;
00967 }
00968
00972 static int
00973 parse_arguments (enum MHD_ValueKind kind,
00974 struct MHD_Connection *connection, char *args)
00975 {
00976 char *equals;
00977 char *amper;
00978
00979 while (args != NULL)
00980 {
00981 equals = strstr (args, "=");
00982 if (equals == NULL)
00983 return MHD_NO;
00984 equals[0] = '\0';
00985 equals++;
00986 amper = strstr (equals, "&");
00987 if (amper != NULL)
00988 {
00989 amper[0] = '\0';
00990 amper++;
00991 }
00992 MHD_http_unescape (args);
00993 MHD_http_unescape (equals);
00994 if (MHD_NO == connection_add_header (connection, args, equals, kind))
00995 return MHD_NO;
00996 args = amper;
00997 }
00998 return MHD_YES;
00999 }
01000
01006 static int
01007 parse_cookie_header (struct MHD_Connection *connection)
01008 {
01009 const char *hdr;
01010 char *cpy;
01011 char *pos;
01012 char *sce;
01013 char *semicolon;
01014 char *equals;
01015 char *ekill;
01016 char old;
01017 int quotes;
01018
01019 hdr = MHD_lookup_connection_value (connection,
01020 MHD_HEADER_KIND,
01021 MHD_HTTP_HEADER_COOKIE);
01022 if (hdr == NULL)
01023 return MHD_YES;
01024 cpy = MHD_pool_allocate (connection->pool, strlen (hdr) + 1, MHD_YES);
01025 if (cpy == NULL)
01026 {
01027 #if HAVE_MESSAGES
01028 MHD_DLOG (connection->daemon, "Not enough memory to parse cookies!\n");
01029 #endif
01030 transmit_error_response (connection, MHD_HTTP_REQUEST_ENTITY_TOO_LARGE,
01031 REQUEST_TOO_BIG);
01032 return MHD_NO;
01033 }
01034 memcpy (cpy, hdr, strlen (hdr) + 1);
01035 pos = cpy;
01036 while (pos != NULL)
01037 {
01038 while (*pos == ' ')
01039 pos++;
01040
01041 sce = pos;
01042 while (((*sce) != '\0') &&
01043 ((*sce) != ',') && ((*sce) != ';') && ((*sce) != '='))
01044 sce++;
01045
01046 ekill = sce - 1;
01047 while ((*ekill == ' ') && (ekill >= pos))
01048 *(ekill--) = '\0';
01049 old = *sce;
01050 *sce = '\0';
01051 if (old != '=')
01052 {
01053
01054 if (MHD_NO ==
01055 connection_add_header (connection, pos, "", MHD_COOKIE_KIND))
01056 return MHD_NO;
01057 if (old == '\0')
01058 break;
01059 pos = sce + 1;
01060 continue;
01061 }
01062 equals = sce + 1;
01063 quotes = 0;
01064 semicolon = equals;
01065 while ((semicolon[0] != '\0') &&
01066 ((quotes != 0) ||
01067 ((semicolon[0] != ';') && (semicolon[0] != ','))))
01068 {
01069 if (semicolon[0] == '"')
01070 quotes = (quotes + 1) & 1;
01071 semicolon++;
01072 }
01073 if (semicolon[0] == '\0')
01074 semicolon = NULL;
01075 if (semicolon != NULL)
01076 {
01077 semicolon[0] = '\0';
01078 semicolon++;
01079 }
01080
01081 if ((equals[0] == '"') && (equals[strlen (equals) - 1] == '"'))
01082 {
01083 equals[strlen (equals) - 1] = '\0';
01084 equals++;
01085 }
01086 if (MHD_NO == connection_add_header (connection,
01087 pos, equals, MHD_COOKIE_KIND))
01088 return MHD_NO;
01089 pos = semicolon;
01090 }
01091 return MHD_YES;
01092 }
01093
01101 static int
01102 parse_initial_message_line (struct MHD_Connection *connection, char *line)
01103 {
01104 char *uri;
01105 char *httpVersion;
01106 char *args;
01107
01108 uri = strstr (line, " ");
01109 if (uri == NULL)
01110 return MHD_NO;
01111 uri[0] = '\0';
01112 connection->method = line;
01113 uri++;
01114 while (uri[0] == ' ')
01115 uri++;
01116 httpVersion = strstr (uri, " ");
01117 if (httpVersion != NULL)
01118 {
01119 httpVersion[0] = '\0';
01120 httpVersion++;
01121 }
01122 if (connection->daemon->uri_log_callback != NULL)
01123 connection->client_context
01124 =
01125 connection->daemon->uri_log_callback (connection->daemon->
01126 uri_log_callback_cls, uri);
01127 args = strstr (uri, "?");
01128 if (args != NULL)
01129 {
01130 args[0] = '\0';
01131 args++;
01132 parse_arguments (MHD_GET_ARGUMENT_KIND, connection, args);
01133 }
01134 MHD_http_unescape (uri);
01135 connection->url = uri;
01136 if (httpVersion == NULL)
01137 connection->version = "";
01138 else
01139 connection->version = httpVersion;
01140 return MHD_YES;
01141 }
01142
01143
01149 static void
01150 call_connection_handler (struct MHD_Connection *connection)
01151 {
01152 size_t processed;
01153
01154 if (connection->response != NULL)
01155 return;
01156 processed = 0;
01157 connection->client_aware = MHD_YES;
01158 if (MHD_NO ==
01159 connection->daemon->default_handler (connection->daemon->
01160 default_handler_cls,
01161 connection, connection->url,
01162 connection->method,
01163 connection->version,
01164 NULL, &processed,
01165 &connection->client_context))
01166 {
01167
01168 #if HAVE_MESSAGES
01169 MHD_DLOG (connection->daemon,
01170 "Internal application error, closing connection.\n");
01171 #endif
01172 connection_close_error (connection);
01173 return;
01174 }
01175 }
01176
01177
01178
01184 static void
01185 process_request_body (struct MHD_Connection *connection)
01186 {
01187 size_t processed;
01188 size_t available;
01189 size_t used;
01190 size_t i;
01191 int instant_retry;
01192 int malformed;
01193 char *buffer_head;
01194
01195 if (connection->response != NULL)
01196 return;
01197
01198 buffer_head = connection->read_buffer;
01199 available = connection->read_buffer_offset;
01200 do
01201 {
01202 instant_retry = MHD_NO;
01203 if ((connection->have_chunked_upload == MHD_YES) &&
01204 (connection->remaining_upload_size == MHD_SIZE_UNKNOWN))
01205 {
01206 if ((connection->current_chunk_offset ==
01207 connection->current_chunk_size)
01208 && (connection->current_chunk_offset != 0) && (available >= 2))
01209 {
01210
01211 i = 0;
01212 if ((buffer_head[i] == '\r') || (buffer_head[i] == '\n'))
01213 i++;
01214 if ((buffer_head[i] == '\r') || (buffer_head[i] == '\n'))
01215 i++;
01216 if (i == 0)
01217 {
01218
01219 #if HAVE_MESSAGES
01220 MHD_DLOG (connection->daemon,
01221 "Received malformed HTTP request (bad chunked encoding), closing connection.\n");
01222 #endif
01223 connection_close_error (connection);
01224 return;
01225 }
01226 available -= i;
01227 buffer_head += i;
01228 connection->current_chunk_offset = 0;
01229 connection->current_chunk_size = 0;
01230 }
01231 if (connection->current_chunk_offset <
01232 connection->current_chunk_size)
01233 {
01234
01235
01236
01237 processed =
01238 connection->current_chunk_size -
01239 connection->current_chunk_offset;
01240 if (processed > available)
01241 processed = available;
01242 if (available > processed)
01243 instant_retry = MHD_YES;
01244 }
01245 else
01246 {
01247
01248 i = 0;
01249 while (i < available)
01250 {
01251 if ((buffer_head[i] == '\r') || (buffer_head[i] == '\n'))
01252 break;
01253 i++;
01254 if (i >= 6)
01255 break;
01256 }
01257
01258
01259
01260
01261 if ((i + 1 >= available) &&
01262 !((i == 1) && (available == 2) && (buffer_head[0] == '0')))
01263 break;
01264 malformed = (i >= 6);
01265 if (!malformed)
01266 {
01267 buffer_head[i] = '\0';
01268 malformed =
01269 (1 != SSCANF (buffer_head, "%X",
01270 &connection->current_chunk_size)) &&
01271 (1 != SSCANF (buffer_head, "%x",
01272 &connection->current_chunk_size));
01273 }
01274 if (malformed)
01275 {
01276
01277 #if HAVE_MESSAGES
01278 MHD_DLOG (connection->daemon,
01279 "Received malformed HTTP request (bad chunked encoding), closing connection.\n");
01280 #endif
01281 connection_close_error (connection);
01282 return;
01283 }
01284 i++;
01285 if ((i < available) &&
01286 ((buffer_head[i] == '\r') || (buffer_head[i] == '\n')))
01287 i++;
01288
01289 buffer_head += i;
01290 available -= i;
01291 connection->current_chunk_offset = 0;
01292
01293 if (available > 0)
01294 instant_retry = MHD_YES;
01295 if (connection->current_chunk_size == 0)
01296 {
01297 connection->remaining_upload_size = 0;
01298 break;
01299 }
01300 continue;
01301 }
01302 }
01303 else
01304 {
01305
01306 processed = available;
01307 }
01308 used = processed;
01309 connection->client_aware = MHD_YES;
01310 if (MHD_NO ==
01311 connection->daemon->default_handler (connection->daemon->
01312 default_handler_cls,
01313 connection, connection->url,
01314 connection->method,
01315 connection->version,
01316 buffer_head, &processed,
01317 &connection->client_context))
01318 {
01319
01320 #if HAVE_MESSAGES
01321 MHD_DLOG (connection->daemon,
01322 "Internal application error, closing connection.\n");
01323 #endif
01324 connection_close_error (connection);
01325 return;
01326 }
01327 if (processed > used)
01328 mhd_panic (mhd_panic_cls, __FILE__, __LINE__,
01329 #if HAVE_MESSAGES
01330 "API violation"
01331 #else
01332 NULL
01333 #endif
01334 );
01335 if (processed != 0)
01336 instant_retry = MHD_NO;
01337 used -= processed;
01338 if (connection->have_chunked_upload == MHD_YES)
01339 connection->current_chunk_offset += used;
01340
01341 buffer_head += used;
01342 available -= used;
01343 if (connection->remaining_upload_size != MHD_SIZE_UNKNOWN)
01344 connection->remaining_upload_size -= used;
01345 }
01346 while (instant_retry == MHD_YES);
01347 if (available > 0)
01348 memmove (connection->read_buffer, buffer_head, available);
01349 connection->read_buffer_offset = available;
01350 }
01351
01360 static int
01361 do_read (struct MHD_Connection *connection)
01362 {
01363 int bytes_read;
01364
01365 if (connection->read_buffer_size == connection->read_buffer_offset)
01366 return MHD_NO;
01367
01368 bytes_read = connection->recv_cls (connection,
01369 &connection->read_buffer
01370 [connection->read_buffer_offset],
01371 connection->read_buffer_size -
01372 connection->read_buffer_offset);
01373 if (bytes_read < 0)
01374 {
01375 if (errno == EINTR)
01376 return MHD_NO;
01377 #if HAVE_MESSAGES
01378 MHD_DLOG (connection->daemon,
01379 "Failed to receive data: %s\n", STRERROR (errno));
01380 #endif
01381 connection_close_error (connection);
01382 return MHD_YES;
01383 }
01384 if (bytes_read == 0)
01385 {
01386
01387 connection->read_closed = MHD_YES;
01388 SHUTDOWN (connection->socket_fd, SHUT_RD);
01389 return MHD_NO;
01390 }
01391 connection->read_buffer_offset += bytes_read;
01392 return MHD_YES;
01393 }
01394
01402 static int
01403 do_write (struct MHD_Connection *connection)
01404 {
01405 int ret;
01406
01407 ret = connection->send_cls (connection,
01408 &connection->write_buffer
01409 [connection->write_buffer_send_offset],
01410 connection->write_buffer_append_offset
01411 - connection->write_buffer_send_offset);
01412
01413 if (ret < 0)
01414 {
01415 if (errno == EINTR)
01416 return MHD_NO;
01417 #if HAVE_MESSAGES
01418 MHD_DLOG (connection->daemon,
01419 "Failed to send data: %s\n", STRERROR (errno));
01420 #endif
01421 connection_close_error (connection);
01422 return MHD_YES;
01423 }
01424 #if DEBUG_SEND_DATA
01425 FPRINTF (stderr,
01426 "Sent response: `%.*s'\n",
01427 ret,
01428 &connection->write_buffer[connection->write_buffer_send_offset]);
01429 #endif
01430 connection->write_buffer_send_offset += ret;
01431 return MHD_YES;
01432 }
01433
01439 static int
01440 check_write_done (struct MHD_Connection *connection,
01441 enum MHD_CONNECTION_STATE next_state)
01442 {
01443 if (connection->write_buffer_append_offset !=
01444 connection->write_buffer_send_offset)
01445 return MHD_NO;
01446 connection->write_buffer_append_offset = 0;
01447 connection->write_buffer_send_offset = 0;
01448 connection->state = next_state;
01449 MHD_pool_reallocate (connection->pool, connection->write_buffer,
01450 connection->write_buffer_size, 0);
01451 connection->write_buffer = NULL;
01452 connection->write_buffer_size = 0;
01453 return MHD_YES;
01454 }
01455
01461 static int
01462 process_header_line (struct MHD_Connection *connection, char *line)
01463 {
01464 char *colon;
01465
01466
01467 colon = strstr (line, ":");
01468 if (colon == NULL)
01469 {
01470
01471 #if HAVE_MESSAGES
01472 MHD_DLOG (connection->daemon,
01473 "Received malformed line (no colon), closing connection.\n");
01474 #endif
01475 connection->state = MHD_CONNECTION_CLOSED;
01476 return MHD_NO;
01477 }
01478
01479 colon[0] = '\0';
01480 colon++;
01481 while ((colon[0] != '\0') && ((colon[0] == ' ') || (colon[0] == '\t')))
01482 colon++;
01483
01484
01485
01486
01487
01488 connection->last = line;
01489 connection->colon = colon;
01490 return MHD_YES;
01491 }
01492
01502 static int
01503 process_broken_line (struct MHD_Connection *connection,
01504 char *line, enum MHD_ValueKind kind)
01505 {
01506 char *last;
01507 char *tmp;
01508
01509 last = connection->last;
01510 if ((line[0] == ' ') || (line[0] == '\t'))
01511 {
01512
01513
01514 last = MHD_pool_reallocate (connection->pool,
01515 last,
01516 strlen (last) + 1,
01517 strlen (line) + strlen (last) + 1);
01518 if (last == NULL)
01519 {
01520 transmit_error_response (connection,
01521 MHD_HTTP_REQUEST_ENTITY_TOO_LARGE,
01522 REQUEST_TOO_BIG);
01523 return MHD_NO;
01524 }
01525 tmp = line;
01526 while ((tmp[0] == ' ') || (tmp[0] == '\t'))
01527 tmp++;
01528 strcat (last, tmp);
01529 connection->last = last;
01530 return MHD_YES;
01531 }
01532 EXTRA_CHECK ((last != NULL) && (connection->colon != NULL));
01533 if ((MHD_NO == connection_add_header (connection,
01534 last, connection->colon, kind)))
01535 {
01536 transmit_error_response (connection, MHD_HTTP_REQUEST_ENTITY_TOO_LARGE,
01537 REQUEST_TOO_BIG);
01538 return MHD_NO;
01539 }
01540
01541 if (strlen (line) != 0)
01542 {
01543 if (MHD_NO == process_header_line (connection, line))
01544 {
01545 transmit_error_response (connection,
01546 MHD_HTTP_BAD_REQUEST, REQUEST_MALFORMED);
01547 return MHD_NO;
01548 }
01549 }
01550 return MHD_YES;
01551 }
01552
01558 static void
01559 parse_connection_headers (struct MHD_Connection *connection)
01560 {
01561 const char *clen;
01562 unsigned long long cval;
01563 struct MHD_Response *response;
01564
01565 parse_cookie_header (connection);
01566 if ((0 != (MHD_USE_PEDANTIC_CHECKS & connection->daemon->options))
01567 && (NULL != connection->version)
01568 && (0 == strcasecmp (MHD_HTTP_VERSION_1_1, connection->version))
01569 && (NULL ==
01570 MHD_lookup_connection_value (connection, MHD_HEADER_KIND,
01571 MHD_HTTP_HEADER_HOST)))
01572 {
01573
01574 connection->state = MHD_CONNECTION_FOOTERS_RECEIVED;
01575 connection->read_closed = MHD_YES;
01576 #if HAVE_MESSAGES
01577 MHD_DLOG (connection->daemon,
01578 "Received `%s' request without `%s' header.\n",
01579 MHD_HTTP_VERSION_1_1, MHD_HTTP_HEADER_HOST);
01580 #endif
01581 response =
01582 MHD_create_response_from_data (strlen (REQUEST_LACKS_HOST),
01583 REQUEST_LACKS_HOST, MHD_NO, MHD_NO);
01584 MHD_queue_response (connection, MHD_HTTP_BAD_REQUEST, response);
01585 MHD_destroy_response (response);
01586 return;
01587 }
01588
01589 clen = MHD_lookup_connection_value (connection,
01590 MHD_HEADER_KIND,
01591 MHD_HTTP_HEADER_CONTENT_LENGTH);
01592 if (clen != NULL)
01593 {
01594 if (1 != SSCANF (clen, "%llu", &cval))
01595 {
01596 #if HAVE_MESSAGES
01597 MHD_DLOG (connection->daemon,
01598 "Failed to parse `%s' header `%s', closing connection.\n",
01599 MHD_HTTP_HEADER_CONTENT_LENGTH, clen);
01600 #endif
01601 connection->state = MHD_CONNECTION_CLOSED;
01602 return;
01603 }
01604 connection->remaining_upload_size = cval;
01605 }
01606 else
01607 {
01608 if (NULL == MHD_lookup_connection_value (connection,
01609 MHD_HEADER_KIND,
01610 MHD_HTTP_HEADER_TRANSFER_ENCODING))
01611 {
01612
01613 connection->remaining_upload_size = 0;
01614 }
01615 else
01616 {
01617 connection->remaining_upload_size = MHD_SIZE_UNKNOWN;
01618 if (0 ==
01619 strcasecmp (MHD_lookup_connection_value
01620 (connection, MHD_HEADER_KIND,
01621 MHD_HTTP_HEADER_TRANSFER_ENCODING), "chunked"))
01622 connection->have_chunked_upload = MHD_YES;
01623 }
01624 }
01625 }
01626
01636 int
01637 MHD_connection_handle_read (struct MHD_Connection *connection)
01638 {
01639 connection->last_activity = time (NULL);
01640 if (connection->state == MHD_CONNECTION_CLOSED)
01641 return MHD_NO;
01642
01643
01644 if (connection->read_buffer_offset + MHD_BUF_INC_SIZE >
01645 connection->read_buffer_size)
01646 try_grow_read_buffer (connection);
01647 if (MHD_NO == do_read (connection))
01648 return MHD_YES;
01649 while (1)
01650 {
01651 #if DEBUG_STATES
01652 MHD_DLOG (connection->daemon, "%s: state: %s\n",
01653 __FUNCTION__, MHD_state_to_string (connection->state));
01654 #endif
01655 switch (connection->state)
01656 {
01657 case MHD_CONNECTION_INIT:
01658 case MHD_CONNECTION_URL_RECEIVED:
01659 case MHD_CONNECTION_HEADER_PART_RECEIVED:
01660 case MHD_CONNECTION_HEADERS_RECEIVED:
01661 case MHD_CONNECTION_HEADERS_PROCESSED:
01662 case MHD_CONNECTION_CONTINUE_SENDING:
01663 case MHD_CONNECTION_CONTINUE_SENT:
01664 case MHD_CONNECTION_BODY_RECEIVED:
01665 case MHD_CONNECTION_FOOTER_PART_RECEIVED:
01666
01667 if (MHD_YES == connection->read_closed)
01668 {
01669 connection->state = MHD_CONNECTION_CLOSED;
01670 continue;
01671 }
01672 break;
01673 case MHD_CONNECTION_CLOSED:
01674 if (connection->socket_fd != -1)
01675 connection_close_error (connection);
01676 return MHD_NO;
01677 default:
01678
01679 MHD_pool_reallocate (connection->pool,
01680 connection->read_buffer,
01681 connection->read_buffer_size + 1,
01682 connection->read_buffer_offset);
01683 break;
01684 }
01685 break;
01686 }
01687 return MHD_YES;
01688 }
01689
01699 int
01700 MHD_connection_handle_write (struct MHD_Connection *connection)
01701 {
01702 struct MHD_Response *response;
01703 int ret;
01704 connection->last_activity = time (NULL);
01705 while (1)
01706 {
01707 #if DEBUG_STATES
01708 MHD_DLOG (connection->daemon, "%s: state: %s\n",
01709 __FUNCTION__, MHD_state_to_string (connection->state));
01710 #endif
01711 switch (connection->state)
01712 {
01713 case MHD_CONNECTION_INIT:
01714 case MHD_CONNECTION_URL_RECEIVED:
01715 case MHD_CONNECTION_HEADER_PART_RECEIVED:
01716 case MHD_CONNECTION_HEADERS_RECEIVED:
01717 EXTRA_CHECK (0);
01718 break;
01719 case MHD_CONNECTION_HEADERS_PROCESSED:
01720 break;
01721 case MHD_CONNECTION_CONTINUE_SENDING:
01722 ret = connection->send_cls (connection,
01723 &HTTP_100_CONTINUE
01724 [connection->continue_message_write_offset],
01725 strlen (HTTP_100_CONTINUE) -
01726 connection->continue_message_write_offset);
01727 if (ret < 0)
01728 {
01729 if (errno == EINTR)
01730 break;
01731 #if HAVE_MESSAGES
01732 MHD_DLOG (connection->daemon,
01733 "Failed to send data: %s\n", STRERROR (errno));
01734 #endif
01735 connection_close_error (connection);
01736 return MHD_NO;
01737 }
01738 #if DEBUG_SEND_DATA
01739 FPRINTF (stderr,
01740 "Sent 100 continue response: `%.*s'\n",
01741 ret,
01742 &HTTP_100_CONTINUE
01743 [connection->continue_message_write_offset]);
01744 #endif
01745 connection->continue_message_write_offset += ret;
01746 break;
01747 case MHD_CONNECTION_CONTINUE_SENT:
01748 case MHD_CONNECTION_BODY_RECEIVED:
01749 case MHD_CONNECTION_FOOTER_PART_RECEIVED:
01750 case MHD_CONNECTION_FOOTERS_RECEIVED:
01751 EXTRA_CHECK (0);
01752 break;
01753 case MHD_CONNECTION_HEADERS_SENDING:
01754 do_write (connection);
01755 check_write_done (connection, MHD_CONNECTION_HEADERS_SENT);
01756 break;
01757 case MHD_CONNECTION_HEADERS_SENT:
01758 EXTRA_CHECK (0);
01759 break;
01760 case MHD_CONNECTION_NORMAL_BODY_READY:
01761 response = connection->response;
01762 if (response->crc != NULL)
01763 pthread_mutex_lock (&response->mutex);
01764 if (MHD_YES != try_ready_normal_body (connection))
01765 {
01766 if (response->crc != NULL)
01767 pthread_mutex_unlock (&response->mutex);
01768 connection->state = MHD_CONNECTION_NORMAL_BODY_UNREADY;
01769 break;
01770 }
01771 #if HTTPS_SUPPORT
01772 if (connection->daemon->options & MHD_USE_SSL)
01773 {
01774 ret = MHD__gnutls_record_send (connection->tls_session,
01775 &connection->response->data
01776 [connection->
01777 response_write_position -
01778 response->data_start],
01779 response->data_size -
01780 (connection->response_write_position
01781 - response->data_start));
01782 }
01783 else
01784 #endif
01785 {
01786 ret = connection->send_cls (connection,
01787 &response->data
01788 [connection->response_write_position
01789 - response->data_start],
01790 response->data_size -
01791 (connection->response_write_position
01792 - response->data_start));
01793 }
01794 #if DEBUG_SEND_DATA
01795 if (ret > 0)
01796 FPRINTF (stderr,
01797 "Sent DATA response: `%.*s'\n",
01798 ret,
01799 &response->data[connection->response_write_position -
01800 response->data_start]);
01801 #endif
01802 if (response->crc != NULL)
01803 pthread_mutex_unlock (&response->mutex);
01804 if (ret < 0)
01805 {
01806 if (errno == EINTR)
01807 return MHD_YES;
01808 #if HAVE_MESSAGES
01809 MHD_DLOG (connection->daemon,
01810 "Failed to send data: %s\n", STRERROR (errno));
01811 #endif
01812 connection_close_error (connection);
01813 return MHD_NO;
01814 }
01815 connection->response_write_position += ret;
01816 if (connection->response_write_position ==
01817 connection->response->total_size)
01818 connection->state = MHD_CONNECTION_FOOTERS_SENT;
01819 break;
01820 case MHD_CONNECTION_NORMAL_BODY_UNREADY:
01821 EXTRA_CHECK (0);
01822 break;
01823 case MHD_CONNECTION_CHUNKED_BODY_READY:
01824 do_write (connection);
01825 check_write_done (connection,
01826 (connection->response->total_size ==
01827 connection->response_write_position) ?
01828 MHD_CONNECTION_BODY_SENT :
01829 MHD_CONNECTION_CHUNKED_BODY_UNREADY);
01830 break;
01831 case MHD_CONNECTION_CHUNKED_BODY_UNREADY:
01832 case MHD_CONNECTION_BODY_SENT:
01833 EXTRA_CHECK (0);
01834 break;
01835 case MHD_CONNECTION_FOOTERS_SENDING:
01836 do_write (connection);
01837 check_write_done (connection, MHD_CONNECTION_FOOTERS_SENT);
01838 break;
01839 case MHD_CONNECTION_FOOTERS_SENT:
01840 EXTRA_CHECK (0);
01841 break;
01842 case MHD_CONNECTION_CLOSED:
01843 if (connection->socket_fd != -1)
01844 connection_close_error (connection);
01845 return MHD_NO;
01846 case MHD_TLS_CONNECTION_INIT:
01847 case MHD_TLS_HELLO_REQUEST:
01848 case MHD_TLS_HANDSHAKE_FAILED:
01849 EXTRA_CHECK (0);
01850 break;
01851 default:
01852 EXTRA_CHECK (0);
01853 connection_close_error (connection);
01854 return MHD_NO;
01855 }
01856 break;
01857 }
01858 return MHD_YES;
01859 }
01860
01870 int
01871 MHD_connection_handle_idle (struct MHD_Connection *connection)
01872 {
01873 unsigned int timeout;
01874 const char *end;
01875 char *line;
01876
01877 while (1)
01878 {
01879 #if DEBUG_STATES
01880 MHD_DLOG (connection->daemon, "%s: state: %s\n",
01881 __FUNCTION__, MHD_state_to_string (connection->state));
01882 #endif
01883 switch (connection->state)
01884 {
01885 case MHD_CONNECTION_INIT:
01886 line = get_next_header_line (connection);
01887 if (line == NULL)
01888 {
01889 if (connection->state != MHD_CONNECTION_INIT)
01890 continue;
01891 if (connection->read_closed)
01892 {
01893 connection->state = MHD_CONNECTION_CLOSED;
01894 continue;
01895 }
01896 break;
01897 }
01898 if (MHD_NO == parse_initial_message_line (connection, line))
01899 connection->state = MHD_CONNECTION_CLOSED;
01900 else
01901 connection->state = MHD_CONNECTION_URL_RECEIVED;
01902 continue;
01903 case MHD_CONNECTION_URL_RECEIVED:
01904 line = get_next_header_line (connection);
01905 if (line == NULL)
01906 {
01907 if (connection->state != MHD_CONNECTION_URL_RECEIVED)
01908 continue;
01909 if (connection->read_closed)
01910 {
01911 connection->state = MHD_CONNECTION_CLOSED;
01912 continue;
01913 }
01914 break;
01915 }
01916 if (strlen (line) == 0)
01917 {
01918 connection->state = MHD_CONNECTION_HEADERS_RECEIVED;
01919 continue;
01920 }
01921 if (MHD_NO == process_header_line (connection, line))
01922 {
01923 transmit_error_response (connection,
01924 MHD_HTTP_BAD_REQUEST,
01925 REQUEST_MALFORMED);
01926 break;
01927 }
01928 connection->state = MHD_CONNECTION_HEADER_PART_RECEIVED;
01929 continue;
01930 case MHD_CONNECTION_HEADER_PART_RECEIVED:
01931 line = get_next_header_line (connection);
01932 if (line == NULL)
01933 {
01934 if (connection->state != MHD_CONNECTION_HEADER_PART_RECEIVED)
01935 continue;
01936 if (connection->read_closed)
01937 {
01938 connection->state = MHD_CONNECTION_CLOSED;
01939 continue;
01940 }
01941 break;
01942 }
01943 if (MHD_NO ==
01944 process_broken_line (connection, line, MHD_HEADER_KIND))
01945 continue;
01946 if (strlen (line) == 0)
01947 {
01948 connection->state = MHD_CONNECTION_HEADERS_RECEIVED;
01949 continue;
01950 }
01951 continue;
01952 case MHD_CONNECTION_HEADERS_RECEIVED:
01953 parse_connection_headers (connection);
01954 if (connection->state == MHD_CONNECTION_CLOSED)
01955 continue;
01956 connection->state = MHD_CONNECTION_HEADERS_PROCESSED;
01957 continue;
01958 case MHD_CONNECTION_HEADERS_PROCESSED:
01959 call_connection_handler (connection);
01960 if (connection->state == MHD_CONNECTION_CLOSED)
01961 continue;
01962 if (need_100_continue (connection))
01963 {
01964 connection->state = MHD_CONNECTION_CONTINUE_SENDING;
01965 break;
01966 }
01967 if (connection->response != NULL)
01968 {
01969
01970 connection->remaining_upload_size = 0;
01971
01972 connection->read_closed = MHD_YES;
01973 }
01974 connection->state = (connection->remaining_upload_size == 0)
01975 ? MHD_CONNECTION_FOOTERS_RECEIVED : MHD_CONNECTION_CONTINUE_SENT;
01976 continue;
01977 case MHD_CONNECTION_CONTINUE_SENDING:
01978 if (connection->continue_message_write_offset ==
01979 strlen (HTTP_100_CONTINUE))
01980 {
01981 connection->state = MHD_CONNECTION_CONTINUE_SENT;
01982 continue;
01983 }
01984 break;
01985 case MHD_CONNECTION_CONTINUE_SENT:
01986 if (connection->read_buffer_offset != 0)
01987 {
01988 process_request_body (connection);
01989 if (connection->state == MHD_CONNECTION_CLOSED)
01990 continue;
01991 }
01992 if ((connection->remaining_upload_size == 0) ||
01993 ((connection->remaining_upload_size == MHD_SIZE_UNKNOWN) &&
01994 (connection->read_buffer_offset == 0) &&
01995 (MHD_YES == connection->read_closed)))
01996 {
01997 if ((MHD_YES == connection->have_chunked_upload) &&
01998 (MHD_NO == connection->read_closed))
01999 connection->state = MHD_CONNECTION_BODY_RECEIVED;
02000 else
02001 connection->state = MHD_CONNECTION_FOOTERS_RECEIVED;
02002 continue;
02003 }
02004 break;
02005 case MHD_CONNECTION_BODY_RECEIVED:
02006 line = get_next_header_line (connection);
02007 if (line == NULL)
02008 {
02009 if (connection->state != MHD_CONNECTION_BODY_RECEIVED)
02010 continue;
02011 if (connection->read_closed)
02012 {
02013 connection->state = MHD_CONNECTION_CLOSED;
02014 continue;
02015 }
02016 break;
02017 }
02018 if (strlen (line) == 0)
02019 {
02020 connection->state = MHD_CONNECTION_FOOTERS_RECEIVED;
02021 continue;
02022 }
02023 if (MHD_NO == process_header_line (connection, line))
02024 {
02025 transmit_error_response (connection,
02026 MHD_HTTP_BAD_REQUEST,
02027 REQUEST_MALFORMED);
02028 break;
02029 }
02030 connection->state = MHD_CONNECTION_FOOTER_PART_RECEIVED;
02031 continue;
02032 case MHD_CONNECTION_FOOTER_PART_RECEIVED:
02033 line = get_next_header_line (connection);
02034 if (line == NULL)
02035 {
02036 if (connection->state != MHD_CONNECTION_FOOTER_PART_RECEIVED)
02037 continue;
02038 if (connection->read_closed)
02039 {
02040 connection->state = MHD_CONNECTION_CLOSED;
02041 continue;
02042 }
02043 break;
02044 }
02045 if (MHD_NO ==
02046 process_broken_line (connection, line, MHD_FOOTER_KIND))
02047 continue;
02048 if (strlen (line) == 0)
02049 {
02050 connection->state = MHD_CONNECTION_FOOTERS_RECEIVED;
02051 continue;
02052 }
02053 continue;
02054 case MHD_CONNECTION_FOOTERS_RECEIVED:
02055 call_connection_handler (connection);
02056 if (connection->state == MHD_CONNECTION_CLOSED)
02057 continue;
02058 if (connection->response == NULL)
02059 break;
02060 if (MHD_NO == build_header_response (connection))
02061 {
02062
02063 #if HAVE_MESSAGES
02064 MHD_DLOG (connection->daemon,
02065 "Closing connection (failed to create response header)\n");
02066 #endif
02067 connection->state = MHD_CONNECTION_CLOSED;
02068 continue;
02069 }
02070 connection->state = MHD_CONNECTION_HEADERS_SENDING;
02071
02072 #if HAVE_DECL_TCP_CORK
02073
02074 {
02075 const int val = 1;
02076 setsockopt (connection->socket_fd, IPPROTO_TCP, TCP_CORK, &val,
02077 sizeof (val));
02078 }
02079 #endif
02080 break;
02081 case MHD_CONNECTION_HEADERS_SENDING:
02082
02083 break;
02084 case MHD_CONNECTION_HEADERS_SENT:
02085 if (connection->have_chunked_upload)
02086 connection->state = MHD_CONNECTION_CHUNKED_BODY_UNREADY;
02087 else
02088 connection->state = MHD_CONNECTION_NORMAL_BODY_UNREADY;
02089 continue;
02090 case MHD_CONNECTION_NORMAL_BODY_READY:
02091
02092 break;
02093 case MHD_CONNECTION_NORMAL_BODY_UNREADY:
02094 if (connection->response->crc != NULL)
02095 pthread_mutex_lock (&connection->response->mutex);
02096 if (MHD_YES == try_ready_normal_body (connection))
02097 {
02098 if (connection->response->crc != NULL)
02099 pthread_mutex_unlock (&connection->response->mutex);
02100 connection->state = MHD_CONNECTION_NORMAL_BODY_READY;
02101 break;
02102 }
02103 if (connection->response->crc != NULL)
02104 pthread_mutex_unlock (&connection->response->mutex);
02105
02106 break;
02107 case MHD_CONNECTION_CHUNKED_BODY_READY:
02108
02109 break;
02110 case MHD_CONNECTION_CHUNKED_BODY_UNREADY:
02111 if (connection->response->crc != NULL)
02112 pthread_mutex_lock (&connection->response->mutex);
02113 if (MHD_YES == try_ready_chunked_body (connection))
02114 {
02115 if (connection->response->crc != NULL)
02116 pthread_mutex_unlock (&connection->response->mutex);
02117 connection->state = MHD_CONNECTION_CHUNKED_BODY_READY;
02118 continue;
02119 }
02120 if (connection->response->crc != NULL)
02121 pthread_mutex_unlock (&connection->response->mutex);
02122 break;
02123 case MHD_CONNECTION_BODY_SENT:
02124 build_header_response (connection);
02125 if (connection->write_buffer_send_offset ==
02126 connection->write_buffer_append_offset)
02127 connection->state = MHD_CONNECTION_FOOTERS_SENT;
02128 else
02129 connection->state = MHD_CONNECTION_FOOTERS_SENDING;
02130 continue;
02131 case MHD_CONNECTION_FOOTERS_SENDING:
02132
02133 break;
02134 case MHD_CONNECTION_FOOTERS_SENT:
02135 #if HAVE_DECL_TCP_CORK
02136
02137 {
02138 const int val = 0;
02139 setsockopt (connection->socket_fd, IPPROTO_TCP, TCP_CORK, &val,
02140 sizeof (val));
02141 }
02142 #endif
02143 MHD_destroy_response (connection->response);
02144 if (connection->daemon->notify_completed != NULL)
02145 {
02146 connection->daemon->notify_completed (connection->daemon->
02147 notify_completed_cls,
02148 connection,
02149 &connection->client_context,
02150 MHD_REQUEST_TERMINATED_COMPLETED_OK);
02151 }
02152 connection->client_aware = MHD_NO;
02153 end =
02154 MHD_lookup_connection_value (connection, MHD_HEADER_KIND,
02155 MHD_HTTP_HEADER_CONNECTION);
02156 connection->client_context = NULL;
02157 connection->continue_message_write_offset = 0;
02158 connection->responseCode = 0;
02159 connection->response = NULL;
02160 connection->headers_received = NULL;
02161 connection->response_write_position = 0;
02162 connection->have_chunked_upload = MHD_NO;
02163 connection->method = NULL;
02164 connection->url = NULL;
02165 connection->write_buffer = NULL;
02166 connection->write_buffer_size = 0;
02167 connection->write_buffer_send_offset = 0;
02168 connection->write_buffer_append_offset = 0;
02169 if ((end != NULL) && (0 == strcasecmp (end, "close")))
02170 {
02171 connection->read_closed = MHD_YES;
02172 connection->read_buffer_offset = 0;
02173 }
02174 if (((MHD_YES == connection->read_closed) &&
02175 (0 == connection->read_buffer_offset)) ||
02176 (connection->version == NULL) ||
02177 (0 != strcasecmp (MHD_HTTP_VERSION_1_1, connection->version)))
02178 {
02179
02180 connection->state = MHD_CONNECTION_CLOSED;
02181 MHD_pool_destroy (connection->pool);
02182 connection->pool = NULL;
02183 connection->read_buffer = NULL;
02184 connection->read_buffer_size = 0;
02185 connection->read_buffer_offset = 0;
02186 }
02187 else
02188 {
02189 connection->version = NULL;
02190 connection->state = MHD_CONNECTION_INIT;
02191 connection->read_buffer
02192 = MHD_pool_reset (connection->pool,
02193 connection->read_buffer,
02194 connection->read_buffer_size);
02195 }
02196 continue;
02197 case MHD_CONNECTION_CLOSED:
02198 if (connection->socket_fd != -1)
02199 connection_close_error (connection);
02200 break;
02201 default:
02202 EXTRA_CHECK (0);
02203 break;
02204 }
02205 break;
02206 }
02207 timeout = connection->daemon->connection_timeout;
02208 if ((connection->socket_fd != -1) &&
02209 (timeout != 0) && (time (NULL) - timeout > connection->last_activity))
02210 {
02211 MHD_connection_close (connection, MHD_REQUEST_TERMINATED_TIMEOUT_REACHED);
02212 return MHD_NO;
02213 }
02214 return MHD_YES;
02215
02216 }
02217
02218 void
02219 MHD_set_http_calbacks (struct MHD_Connection *connection)
02220 {
02221 connection->read_handler = &MHD_connection_handle_read;
02222 connection->write_handler = &MHD_connection_handle_write;
02223 connection->idle_handler = &MHD_connection_handle_idle;
02224 }
02225
02226 #if HTTPS_SUPPORT
02227 #include "gnutls_int.h"
02228 #include "gnutls_record.h"
02229 #endif
02230
02240 const union MHD_ConnectionInfo *
02241 MHD_get_connection_info (struct MHD_Connection *connection,
02242 enum MHD_ConnectionInfoType infoType, ...)
02243 {
02244 switch (infoType)
02245 {
02246 #if HTTPS_SUPPORT
02247 case MHD_CONNECTION_INFO_CIPHER_ALGO:
02248 if (connection->tls_session == NULL)
02249 return NULL;
02250 return (const union MHD_ConnectionInfo *) &connection->
02251 tls_session->security_parameters.read_bulk_cipher_algorithm;
02252 case MHD_CONNECTION_INFO_PROTOCOL:
02253 if (connection->tls_session == NULL)
02254 return NULL;
02255 return (const union MHD_ConnectionInfo *) &connection->
02256 tls_session->security_parameters.version;
02257 #endif
02258 case MHD_CONNECTION_INFO_CLIENT_ADDRESS:
02259 return (const union MHD_ConnectionInfo *) &connection->addr;
02260 default:
02261 return NULL;
02262 };
02263 }
02264
02265
02266