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->
00292 daemon->notify_completed_cls,
00293 connection,
00294 &connection->client_context,
00295 termination_code);
00296 }
00297
00302 static void
00303 connection_close_error (struct MHD_Connection *connection)
00304 {
00305 MHD_connection_close(connection,
00306 MHD_REQUEST_TERMINATED_WITH_ERROR);
00307 }
00308
00318 static int
00319 try_ready_normal_body (struct MHD_Connection *connection)
00320 {
00321 int ret;
00322 struct MHD_Response *response;
00323
00324 response = connection->response;
00325 if (response->crc == NULL)
00326 return MHD_YES;
00327 ret = response->crc (response->crc_cls,
00328 connection->response_write_position,
00329 response->data,
00330 MHD_MIN (response->data_buffer_size,
00331 response->total_size -
00332 connection->response_write_position));
00333 if ((ret == 0) &&
00334 (0 != (connection->daemon->options & MHD_USE_SELECT_INTERNALLY)))
00335 abort ();
00336 if (ret == -1)
00337 {
00338
00339
00340 #if DEBUG_CLOSE
00341 #if HAVE_MESSAGES
00342 MHD_DLOG (connection->daemon, "Closing connection (end of response)\n");
00343 #endif
00344 #endif
00345 response->total_size = connection->response_write_position;
00346 connection_close_error (connection);
00347 return MHD_NO;
00348 }
00349 response->data_start = connection->response_write_position;
00350 response->data_size = ret;
00351 if (ret == 0)
00352 return MHD_NO;
00353 return MHD_YES;
00354 }
00355
00365 static int
00366 try_ready_chunked_body (struct MHD_Connection *connection)
00367 {
00368 int ret;
00369 char *buf;
00370 struct MHD_Response *response;
00371 unsigned int size;
00372 char cbuf[10];
00373 int cblen;
00374
00375 response = connection->response;
00376 if (connection->write_buffer_size == 0)
00377 {
00378 size = connection->daemon->pool_size;
00379 do
00380 {
00381 size /= 2;
00382 if (size < 128)
00383 {
00384
00385 #if DEBUG_CLOSE
00386 #if HAVE_MESSAGES
00387 MHD_DLOG (connection->daemon,
00388 "Closing connection (out of memory)\n");
00389 #endif
00390 #endif
00391 connection_close_error (connection);
00392 return MHD_NO;
00393 }
00394 buf = MHD_pool_allocate (connection->pool, size, MHD_NO);
00395 }
00396 while (buf == NULL);
00397 connection->write_buffer_size = size;
00398 connection->write_buffer = buf;
00399 }
00400
00401 ret = response->crc (response->crc_cls,
00402 connection->response_write_position,
00403 &connection->write_buffer[sizeof (cbuf)],
00404 connection->write_buffer_size - sizeof (cbuf) - 2);
00405 if (ret == -1)
00406 {
00407
00408 strcpy (connection->write_buffer, "0\r\n");
00409 connection->write_buffer_append_offset = 3;
00410 connection->write_buffer_send_offset = 0;
00411 response->total_size = connection->response_write_position;
00412 return MHD_YES;
00413 }
00414 if (ret == 0)
00415 {
00416 connection->state = MHD_CONNECTION_CHUNKED_BODY_UNREADY;
00417 return MHD_NO;
00418 }
00419 if (ret > 0xFFFFFF)
00420 ret = 0xFFFFFF;
00421 SPRINTF (cbuf, "%X\r\n", ret);
00422 cblen = strlen (cbuf);
00423 EXTRA_CHECK (cblen <= sizeof (cbuf));
00424 memcpy (&connection->write_buffer[sizeof (cbuf) - cblen], cbuf, cblen);
00425 memcpy (&connection->write_buffer[sizeof (cbuf) + ret], "\r\n", 2);
00426 connection->response_write_position += ret;
00427 connection->write_buffer_send_offset = sizeof (cbuf) - cblen;
00428 connection->write_buffer_append_offset = sizeof (cbuf) + ret + 2;
00429 return MHD_YES;
00430 }
00431
00436 static void
00437 add_extra_headers (struct MHD_Connection *connection)
00438 {
00439 const char *have;
00440 char buf[128];
00441
00442 connection->have_chunked_upload = MHD_NO;
00443 if (connection->response->total_size == -1)
00444 {
00445 have = MHD_get_response_header (connection->response,
00446 MHD_HTTP_HEADER_CONNECTION);
00447 if ((have == NULL) || (0 != strcasecmp (have, "close")))
00448 {
00449 if ((connection->version != NULL) &&
00450 (0 == strcasecmp (connection->version, MHD_HTTP_VERSION_1_1)))
00451 {
00452 connection->have_chunked_upload = MHD_YES;
00453 have = MHD_get_response_header (connection->response,
00454 MHD_HTTP_HEADER_TRANSFER_ENCODING);
00455 if (have == NULL)
00456 MHD_add_response_header (connection->response,
00457 MHD_HTTP_HEADER_TRANSFER_ENCODING,
00458 "chunked");
00459 }
00460 else
00461 {
00462 MHD_add_response_header (connection->response,
00463 MHD_HTTP_HEADER_CONNECTION, "close");
00464 }
00465 }
00466 }
00467 else if (NULL == MHD_get_response_header (connection->response,
00468 MHD_HTTP_HEADER_CONTENT_LENGTH))
00469 {
00470 SPRINTF (buf,
00471 "%llu", (unsigned long long) connection->response->total_size);
00472 MHD_add_response_header (connection->response,
00473 MHD_HTTP_HEADER_CONTENT_LENGTH, buf);
00474 }
00475 }
00476
00483 static void
00484 get_date_string (char *date)
00485 {
00486 static const char *days[] =
00487 { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" };
00488 static const char *mons[] =
00489 { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct",
00490 "Nov", "Dec"
00491 };
00492 struct tm now;
00493 time_t t;
00494
00495 time (&t);
00496 gmtime_r (&t, &now);
00497 SPRINTF (date,
00498 "Date: %3s, %02u %3s %04u %02u:%02u:%02u GMT\r\n",
00499 days[now.tm_wday % 7],
00500 now.tm_mday,
00501 mons[now.tm_mon % 12],
00502 1900 + now.tm_year, now.tm_hour, now.tm_min, now.tm_sec);
00503 }
00504
00510 static int
00511 try_grow_read_buffer (struct MHD_Connection *connection)
00512 {
00513 void *buf;
00514
00515 buf = MHD_pool_reallocate (connection->pool,
00516 connection->read_buffer,
00517 connection->read_buffer_size,
00518 connection->read_buffer_size * 2 +
00519 MHD_BUF_INC_SIZE + 1);
00520 if (buf == NULL)
00521 return MHD_NO;
00522
00523 connection->read_buffer = buf;
00524 connection->read_buffer_size =
00525 connection->read_buffer_size * 2 + MHD_BUF_INC_SIZE;
00526 return MHD_YES;
00527 }
00528
00535 static int
00536 build_header_response (struct MHD_Connection *connection)
00537 {
00538 size_t size;
00539 size_t off;
00540 struct MHD_HTTP_Header *pos;
00541 char code[256];
00542 char date[128];
00543 char *data;
00544 enum MHD_ValueKind kind;
00545 const char *reason_phrase;
00546
00547 if (connection->state == MHD_CONNECTION_FOOTERS_RECEIVED)
00548 {
00549 add_extra_headers (connection);
00550 reason_phrase = MHD_get_reason_phrase_for (connection->responseCode);
00551 SPRINTF (code,
00552 "%s %u %s\r\n",
00553 MHD_HTTP_VERSION_1_1, connection->responseCode, reason_phrase);
00554 off = strlen (code);
00555
00556 size = off + 2;
00557 kind = MHD_HEADER_KIND;
00558 if (NULL == MHD_get_response_header (connection->response,
00559 MHD_HTTP_HEADER_DATE))
00560 get_date_string (date);
00561 else
00562 date[0] = '\0';
00563 size += strlen (date);
00564 }
00565 else
00566 {
00567 size = 2;
00568 kind = MHD_FOOTER_KIND;
00569 off = 0;
00570 }
00571 pos = connection->response->first_header;
00572 while (pos != NULL)
00573 {
00574 if (pos->kind == kind)
00575 size += strlen (pos->header) + strlen (pos->value) + 4;
00576 pos = pos->next;
00577 }
00578
00579 data = MHD_pool_allocate (connection->pool, size + 1, MHD_YES);
00580 if (data == NULL)
00581 {
00582 #if HAVE_MESSAGES
00583 MHD_DLOG (connection->daemon, "Not enough memory for write!\n");
00584 #endif
00585 return MHD_NO;
00586 }
00587 if (connection->state == MHD_CONNECTION_FOOTERS_RECEIVED)
00588 {
00589 memcpy (data, code, off);
00590 }
00591 pos = connection->response->first_header;
00592 while (pos != NULL)
00593 {
00594 if (pos->kind == kind)
00595 off += SPRINTF (&data[off], "%s: %s\r\n", pos->header, pos->value);
00596 pos = pos->next;
00597 }
00598 if (connection->state == MHD_CONNECTION_FOOTERS_RECEIVED)
00599 {
00600 strcpy (&data[off], date);
00601 off += strlen (date);
00602 }
00603 memcpy (&data[off], "\r\n", 2);
00604 off += 2;
00605 if (off != size)
00606 abort ();
00607 connection->write_buffer = data;
00608 connection->write_buffer_append_offset = size;
00609 connection->write_buffer_send_offset = 0;
00610 connection->write_buffer_size = size + 1;
00611 return MHD_YES;
00612 }
00613
00621 static void
00622 transmit_error_response (struct MHD_Connection *connection,
00623 unsigned int status_code, const char *message)
00624 {
00625 struct MHD_Response *response;
00626
00627
00628 connection->state = MHD_CONNECTION_FOOTERS_RECEIVED;
00629 connection->read_closed = MHD_YES;
00630 #if HAVE_MESSAGES
00631 MHD_DLOG (connection->daemon,
00632 "Error %u (`%s') processing request, closing connection.\n",
00633 status_code, message);
00634 #endif
00635 response = MHD_create_response_from_data (strlen (message),
00636 (void *) message, MHD_NO, MHD_NO);
00637 MHD_queue_response (connection, status_code, response);
00638 EXTRA_CHECK (connection->response != NULL);
00639 MHD_destroy_response (response);
00640 if (MHD_NO == build_header_response (connection))
00641 {
00642
00643 #if HAVE_MESSAGES
00644 MHD_DLOG (connection->daemon,
00645 "Closing connection (failed to create response header)\n");
00646 #endif
00647 connection->state = MHD_CONNECTION_CLOSED;
00648 }
00649 else
00650 {
00651 connection->state = MHD_CONNECTION_HEADERS_SENDING;
00652 }
00653 }
00654
00659 static void
00660 do_fd_set (int fd, fd_set * set, int *max_fd)
00661 {
00662 FD_SET (fd, set);
00663 if (fd > *max_fd)
00664 *max_fd = fd;
00665 }
00666
00672 int
00673 MHD_connection_get_fdset (struct MHD_Connection *connection,
00674 fd_set * read_fd_set,
00675 fd_set * write_fd_set,
00676 fd_set * except_fd_set, int *max_fd)
00677 {
00678 int fd;
00679
00680 if (connection->pool == NULL)
00681 connection->pool = MHD_pool_create (connection->daemon->pool_size);
00682 if (connection->pool == NULL)
00683 {
00684 #if HAVE_MESSAGES
00685 MHD_DLOG (connection->daemon, "Failed to create memory pool!\n");
00686 #endif
00687 connection_close_error (connection);
00688 return MHD_NO;
00689 }
00690 fd = connection->socket_fd;
00691 if (fd == -1)
00692 return MHD_YES;
00693 while (1)
00694 {
00695 #if DEBUG_STATES
00696 MHD_DLOG (connection->daemon, "%s: state: %s\n",
00697 __FUNCTION__, MHD_state_to_string (connection->state));
00698 #endif
00699 switch (connection->state)
00700 {
00701 case MHD_CONNECTION_INIT:
00702 case MHD_CONNECTION_URL_RECEIVED:
00703 case MHD_CONNECTION_HEADER_PART_RECEIVED:
00704 #if HTTPS_SUPPORT
00705 case MHD_TLS_CONNECTION_INIT:
00706 #endif
00707
00708
00709 if ((connection->read_closed) &&
00710 (connection->read_buffer_offset == 0))
00711 {
00712 connection->state = MHD_CONNECTION_CLOSED;
00713 continue;
00714 }
00715 if ((connection->read_buffer_offset == connection->read_buffer_size)
00716 && (MHD_NO == try_grow_read_buffer (connection)))
00717 {
00718 transmit_error_response (connection,
00719 (connection->url != NULL)
00720 ? MHD_HTTP_REQUEST_ENTITY_TOO_LARGE
00721 : MHD_HTTP_REQUEST_URI_TOO_LONG,
00722 REQUEST_TOO_BIG);
00723 continue;
00724 }
00725 if (MHD_NO == connection->read_closed)
00726 do_fd_set (fd, read_fd_set, max_fd);
00727 break;
00728 case MHD_CONNECTION_HEADERS_RECEIVED:
00729
00730 EXTRA_CHECK (0);
00731 break;
00732 case MHD_CONNECTION_HEADERS_PROCESSED:
00733 EXTRA_CHECK (0);
00734 break;
00735 case MHD_CONNECTION_CONTINUE_SENDING:
00736 do_fd_set (fd, write_fd_set, max_fd);
00737 break;
00738 case MHD_CONNECTION_CONTINUE_SENT:
00739 if (connection->read_buffer_offset == connection->read_buffer_size)
00740 {
00741 if ((MHD_YES != try_grow_read_buffer (connection)) &&
00742 (0 != (connection->daemon->options &
00743 (MHD_USE_SELECT_INTERNALLY |
00744 MHD_USE_THREAD_PER_CONNECTION))))
00745 {
00746
00747
00748
00749
00750
00751
00752
00753
00754
00755
00756
00757 transmit_error_response (connection,
00758 MHD_HTTP_INTERNAL_SERVER_ERROR,
00759 INTERNAL_ERROR);
00760 continue;
00761 }
00762 }
00763 if ((connection->read_buffer_offset < connection->read_buffer_size)
00764 && (MHD_NO == connection->read_closed))
00765 do_fd_set (fd, read_fd_set, max_fd);
00766 break;
00767 case MHD_CONNECTION_BODY_RECEIVED:
00768 case MHD_CONNECTION_FOOTER_PART_RECEIVED:
00769
00770
00771 if (MHD_YES == connection->read_closed)
00772 {
00773 connection->state = MHD_CONNECTION_CLOSED;
00774 continue;
00775 }
00776 do_fd_set (fd, read_fd_set, max_fd);
00777
00778
00779 break;
00780 case MHD_CONNECTION_FOOTERS_RECEIVED:
00781
00782
00783 break;
00784 case MHD_CONNECTION_HEADERS_SENDING:
00785
00786 do_fd_set (fd, write_fd_set, max_fd);
00787 break;
00788 case MHD_CONNECTION_HEADERS_SENT:
00789 EXTRA_CHECK (0);
00790 break;
00791 case MHD_CONNECTION_NORMAL_BODY_READY:
00792 do_fd_set (fd, write_fd_set, max_fd);
00793 break;
00794 case MHD_CONNECTION_NORMAL_BODY_UNREADY:
00795
00796 break;
00797 case MHD_CONNECTION_CHUNKED_BODY_READY:
00798 do_fd_set (fd, write_fd_set, max_fd);
00799 break;
00800 case MHD_CONNECTION_CHUNKED_BODY_UNREADY:
00801
00802 break;
00803 case MHD_CONNECTION_BODY_SENT:
00804 EXTRA_CHECK (0);
00805 break;
00806 case MHD_CONNECTION_FOOTERS_SENDING:
00807 do_fd_set (fd, write_fd_set, max_fd);
00808 break;
00809 case MHD_CONNECTION_FOOTERS_SENT:
00810 EXTRA_CHECK (0);
00811 break;
00812 case MHD_CONNECTION_CLOSED:
00813 if (connection->socket_fd != -1)
00814 connection_close_error (connection);
00815 return MHD_YES;
00816
00817 default:
00818 EXTRA_CHECK (0);
00819 }
00820 break;
00821 }
00822 return MHD_YES;
00823 }
00824
00833 static char *
00834 get_next_header_line (struct MHD_Connection *connection)
00835 {
00836 char *rbuf;
00837 size_t pos;
00838
00839 if (connection->read_buffer_offset == 0)
00840 return NULL;
00841 pos = 0;
00842 rbuf = connection->read_buffer;
00843 while ((pos < connection->read_buffer_offset - 1) &&
00844 (rbuf[pos] != '\r') && (rbuf[pos] != '\n'))
00845 pos++;
00846 if (pos == connection->read_buffer_offset - 1)
00847 {
00848
00849 if (connection->read_buffer_offset == connection->read_buffer_size)
00850 {
00851 rbuf = MHD_pool_reallocate (connection->pool,
00852 connection->read_buffer,
00853 connection->read_buffer_size,
00854 connection->read_buffer_size * 2 +
00855 MHD_BUF_INC_SIZE);
00856 if (rbuf == NULL)
00857 {
00858 transmit_error_response (connection,
00859 (connection->url != NULL)
00860 ? MHD_HTTP_REQUEST_ENTITY_TOO_LARGE
00861 : MHD_HTTP_REQUEST_URI_TOO_LONG,
00862 REQUEST_TOO_BIG);
00863 }
00864 else
00865 {
00866 connection->read_buffer_size =
00867 connection->read_buffer_size * 2 + MHD_BUF_INC_SIZE;
00868 connection->read_buffer = rbuf;
00869 }
00870 }
00871 return NULL;
00872 }
00873
00874 if ((rbuf[pos] == '\r') && (rbuf[pos + 1] == '\n'))
00875 rbuf[pos++] = '\0';
00876 rbuf[pos++] = '\0';
00877 connection->read_buffer += pos;
00878 connection->read_buffer_size -= pos;
00879 connection->read_buffer_offset -= pos;
00880 return rbuf;
00881 }
00882
00886 static int
00887 connection_add_header (struct MHD_Connection *connection,
00888 char *key, char *value, enum MHD_ValueKind kind)
00889 {
00890 struct MHD_HTTP_Header *hdr;
00891
00892 hdr = MHD_pool_allocate (connection->pool,
00893 sizeof (struct MHD_HTTP_Header), MHD_YES);
00894 if (hdr == NULL)
00895 {
00896 #if HAVE_MESSAGES
00897 MHD_DLOG (connection->daemon,
00898 "Not enough memory to allocate header record!\n");
00899 #endif
00900 transmit_error_response (connection, MHD_HTTP_REQUEST_ENTITY_TOO_LARGE,
00901 REQUEST_TOO_BIG);
00902 return MHD_NO;
00903 }
00904 hdr->next = connection->headers_received;
00905 hdr->header = key;
00906 hdr->value = value;
00907 hdr->kind = kind;
00908 connection->headers_received = hdr;
00909 return MHD_YES;
00910 }
00911
00915 static int
00916 parse_arguments (enum MHD_ValueKind kind,
00917 struct MHD_Connection *connection, char *args)
00918 {
00919 char *equals;
00920 char *amper;
00921
00922 while (args != NULL)
00923 {
00924 equals = strstr (args, "=");
00925 if (equals == NULL)
00926 return MHD_NO;
00927 equals[0] = '\0';
00928 equals++;
00929 amper = strstr (equals, "&");
00930 if (amper != NULL)
00931 {
00932 amper[0] = '\0';
00933 amper++;
00934 }
00935 MHD_http_unescape (args);
00936 MHD_http_unescape (equals);
00937 if (MHD_NO == connection_add_header (connection, args, equals, kind))
00938 return MHD_NO;
00939 args = amper;
00940 }
00941 return MHD_YES;
00942 }
00943
00949 static int
00950 parse_cookie_header (struct MHD_Connection *connection)
00951 {
00952 const char *hdr;
00953 char *cpy;
00954 char *pos;
00955 char *semicolon;
00956 char *equals;
00957 int quotes;
00958
00959 hdr = MHD_lookup_connection_value (connection, MHD_HEADER_KIND, "Cookie");
00960 if (hdr == NULL)
00961 return MHD_YES;
00962 cpy = MHD_pool_allocate (connection->pool, strlen (hdr) + 1, MHD_YES);
00963 if (cpy == NULL)
00964 {
00965 #if HAVE_MESSAGES
00966 MHD_DLOG (connection->daemon, "Not enough memory to parse cookies!\n");
00967 #endif
00968 transmit_error_response (connection, MHD_HTTP_REQUEST_ENTITY_TOO_LARGE,
00969 REQUEST_TOO_BIG);
00970 return MHD_NO;
00971 }
00972 memcpy (cpy, hdr, strlen (hdr) + 1);
00973 pos = cpy;
00974 while (pos != NULL)
00975 {
00976 equals = strstr (pos, "=");
00977 if (equals == NULL)
00978 break;
00979 equals[0] = '\0';
00980 equals++;
00981 quotes = 0;
00982 semicolon = equals;
00983 while ((semicolon[0] != '\0') &&
00984 ((quotes != 0) ||
00985 ((semicolon[0] != ';') && (semicolon[0] != ','))))
00986 {
00987 if (semicolon[0] == '"')
00988 quotes = (quotes + 1) & 1;
00989 semicolon++;
00990 }
00991 if (semicolon[0] == '\0')
00992 semicolon = NULL;
00993 if (semicolon != NULL)
00994 {
00995 semicolon[0] = '\0';
00996 semicolon++;
00997 }
00998
00999 if ((equals[0] == '"') && (equals[strlen (equals) - 1] == '"'))
01000 {
01001 equals[strlen (equals) - 1] = '\0';
01002 equals++;
01003 }
01004 if (MHD_NO == connection_add_header (connection,
01005 pos, equals, MHD_COOKIE_KIND))
01006 return MHD_NO;
01007 pos = semicolon;
01008 }
01009 return MHD_YES;
01010 }
01011
01019 static int
01020 parse_initial_message_line (struct MHD_Connection *connection, char *line)
01021 {
01022 char *uri;
01023 char *httpVersion;
01024 char *args;
01025
01026 uri = strstr (line, " ");
01027 if (uri == NULL)
01028 return MHD_NO;
01029 uri[0] = '\0';
01030 connection->method = line;
01031 uri++;
01032 while (uri[0] == ' ')
01033 uri++;
01034 httpVersion = strstr (uri, " ");
01035 if (httpVersion != NULL)
01036 {
01037 httpVersion[0] = '\0';
01038 httpVersion++;
01039 }
01040 if (connection->daemon->uri_log_callback != NULL)
01041 connection->client_context
01042 = connection->daemon->uri_log_callback(connection->daemon->uri_log_callback_cls,
01043 uri);
01044 args = strstr (uri, "?");
01045 if (args != NULL)
01046 {
01047 args[0] = '\0';
01048 args++;
01049 parse_arguments (MHD_GET_ARGUMENT_KIND, connection, args);
01050 }
01051 MHD_http_unescape (uri);
01052 connection->url = uri;
01053 if (httpVersion == NULL)
01054 connection->version = "";
01055 else
01056 connection->version = httpVersion;
01057 return MHD_YES;
01058 }
01059
01065 static void
01066 call_connection_handler (struct MHD_Connection *connection)
01067 {
01068 unsigned int processed;
01069 unsigned int available;
01070 unsigned int used;
01071 int instant_retry;
01072 unsigned int i;
01073 int malformed;
01074 char *buffer_head;
01075
01076 if (connection->response != NULL)
01077 return;
01078
01079 buffer_head = connection->read_buffer;
01080 available = connection->read_buffer_offset;
01081 do
01082 {
01083 instant_retry = MHD_NO;
01084 if ((connection->have_chunked_upload == MHD_YES) &&
01085 (connection->remaining_upload_size == -1))
01086 {
01087 if ((connection->current_chunk_offset ==
01088 connection->current_chunk_size)
01089 && (connection->current_chunk_offset != 0) && (available >= 2))
01090 {
01091
01092 i = 0;
01093 if ((buffer_head[i] == '\r') || (buffer_head[i] == '\n'))
01094 i++;
01095 if ((buffer_head[i] == '\r') || (buffer_head[i] == '\n'))
01096 i++;
01097 if (i == 0)
01098 {
01099
01100 #if HAVE_MESSAGES
01101 MHD_DLOG (connection->daemon,
01102 "Received malformed HTTP request (bad chunked encoding), closing connection.\n");
01103 #endif
01104 connection_close_error (connection);
01105 return;
01106 }
01107 available -= i;
01108 buffer_head += i;
01109 connection->current_chunk_offset = 0;
01110 connection->current_chunk_size = 0;
01111 }
01112 if (connection->current_chunk_offset <
01113 connection->current_chunk_size)
01114 {
01115
01116
01117
01118 processed =
01119 connection->current_chunk_size -
01120 connection->current_chunk_offset;
01121 if (processed > available)
01122 processed = available;
01123 if (available > processed)
01124 instant_retry = MHD_YES;
01125 }
01126 else
01127 {
01128
01129 i = 0;
01130 while (i < available)
01131 {
01132 if ((buffer_head[i] == '\r') || (buffer_head[i] == '\n'))
01133 break;
01134 i++;
01135 if (i >= 6)
01136 break;
01137 }
01138
01139
01140
01141
01142 if ((i + 1 >= available) &&
01143 !((i == 1) && (available == 2) && (buffer_head[0] == '0')))
01144 break;
01145 malformed = (i >= 6);
01146 if (!malformed)
01147 {
01148 buffer_head[i] = '\0';
01149 malformed =
01150 (1 != SSCANF (buffer_head, "%X",
01151 &connection->current_chunk_size)) &&
01152 (1 != SSCANF (buffer_head, "%x",
01153 &connection->current_chunk_size));
01154 }
01155 if (malformed)
01156 {
01157
01158 #if HAVE_MESSAGES
01159 MHD_DLOG (connection->daemon,
01160 "Received malformed HTTP request (bad chunked encoding), closing connection.\n");
01161 #endif
01162 connection_close_error (connection);
01163 return;
01164 }
01165 i++;
01166 if ((i < available) &&
01167 ((buffer_head[i] == '\r') || (buffer_head[i] == '\n')))
01168 i++;
01169
01170 buffer_head += i;
01171 available -= i;
01172 connection->current_chunk_offset = 0;
01173
01174 if (available > 0)
01175 instant_retry = MHD_YES;