35 #if HAVE_NETINET_TCP_H
37 #include <netinet/tcp.h>
40 #if defined(_WIN32) && defined(MHD_W32_MUTEX_)
41 #ifndef WIN32_LEAN_AND_MEAN
42 #define WIN32_LEAN_AND_MEAN 1
51 #define HTTP_100_CONTINUE "HTTP/1.1 100 Continue\r\n\r\n"
61 #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>"
63 #define REQUEST_TOO_BIG ""
74 #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>"
76 #define REQUEST_LACKS_HOST ""
87 #define REQUEST_MALFORMED "<html><head><title>Request malformed</title></head><body>Your HTTP request was syntactically incorrect.</body></html>"
89 #define REQUEST_MALFORMED ""
99 #define INTERNAL_ERROR "<html><head><title>Internal server error</title></head><body>Some programmer needs to study the manual more carefully.</body></html>"
101 #define INTERNAL_ERROR ""
108 #define DEBUG_CLOSE MHD_NO
113 #define DEBUG_SEND_DATA MHD_NO
135 if (
NULL == connection)
139 if (0 != (pos->
kind & kind))
142 if ((
NULL != iterator) &&
143 (
MHD_YES != iterator (iterator_cls,
179 const char *key,
const char *
value)
187 pos->
header = (
char *) key;
188 pos->
value = (
char *) value;
222 if (
NULL == connection)
225 if ((0 != (pos->
kind & kind)) &&
273 daemon = connection->
daemon;
302 MHD_DLOG (connection->
daemon, emsg);
313 #define CONNECTION_CLOSE_ERROR(c, emsg) connection_close_error (c, emsg)
315 #define CONNECTION_CLOSE_ERROR(c, emsg) connection_close_error (c, NULL)
368 (void) MHD_mutex_unlock_ (&response->
mutex);
369 if ( ((ssize_t)MHD_CONTENT_READER_END_OF_STREAM) == ret)
373 "Closing connection (stream error)\n");
382 (void) MHD_mutex_unlock_ (&response->
mutex);
419 "Closing connection (out of memory)\n");
459 "Closing connection (error generating response)\n");
481 "%X\r\n", (
unsigned int) ret);
482 cblen = strlen (cbuf);
484 memcpy (&connection->
write_buffer[sizeof (cbuf) - cblen], cbuf, cblen);
485 memcpy (&connection->
write_buffer[sizeof (cbuf) + ret],
"\r\n", 2);
554 static const char *
const days[] =
555 {
"Sun",
"Mon",
"Tue",
"Wed",
"Thu",
"Fri",
"Sat" };
556 static const char *
const mons[] =
557 {
"Jan",
"Feb",
"Mar",
"Apr",
"May",
"Jun",
"Jul",
"Aug",
"Sep",
"Oct",
562 #if defined(_WIN32) && !defined(HAVE_GMTIME_S) && !defined(__CYGWIN__)
569 if (
NULL != gmtime_r (&t, &now))
571 #elif defined(HAVE_GMTIME_S)
572 if (0 == gmtime_s (&now, &t))
574 #elif defined(__CYGWIN__)
575 if (
NULL != gmtime_r (&t, &now))
584 "Date: %3s, %02u %3s %04u %02u:%02u:%02u GMT\r\n",
585 days[now.tm_wday % 7],
586 (
unsigned int) now.tm_mday,
587 mons[now.tm_mon % 12],
588 (
unsigned int) (1900 + now.tm_year),
589 (
unsigned int) now.tm_hour,
590 (
unsigned int) now.tm_min,
591 (
unsigned int) now.tm_sec);
647 char content_length_buf[128];
648 size_t content_length_len;
651 const char *reason_phrase;
653 const char *client_requested_close;
654 const char *response_has_close;
655 const char *response_has_keepalive;
656 const char *have_encoding;
657 const char *have_content_length;
659 int must_add_chunked_encoding;
660 int must_add_keep_alive;
661 int must_add_content_length;
664 if (0 == strlen (connection->
version))
697 size += strlen (date);
710 must_add_chunked_encoding =
MHD_NO;
711 must_add_keep_alive =
MHD_NO;
712 must_add_content_length =
MHD_NO;
713 switch (connection->
state)
718 response_has_keepalive = response_has_close;
719 if ( (
NULL != response_has_close) &&
721 response_has_close =
NULL;
722 if ( (
NULL != response_has_keepalive) &&
724 response_has_keepalive =
NULL;
728 if ( (
NULL != client_requested_close) &&
730 client_requested_close =
NULL;
736 (
NULL == response_has_close) &&
737 (
NULL == client_requested_close) )
748 if (
NULL == have_encoding)
750 must_add_chunked_encoding =
MHD_YES;
766 if (
NULL == response_has_close)
772 if ( ( (
NULL != client_requested_close) ||
774 (
NULL == response_has_close) &&
783 (
NULL == have_content_length) &&
804 = sprintf (content_length_buf,
807 must_add_content_length =
MHD_YES;
811 if ( (
NULL == response_has_keepalive) &&
812 (
NULL == response_has_close) &&
813 (
MHD_NO == must_add_close) &&
825 size += strlen (
"Connection: close\r\n");
826 if (must_add_keep_alive)
827 size += strlen (
"Connection: Keep-Alive\r\n");
828 if (must_add_chunked_encoding)
829 size += strlen (
"Transfer-Encoding: chunked\r\n");
830 if (must_add_content_length)
831 size += content_length_len;
832 EXTRA_CHECK (! (must_add_close && must_add_keep_alive) );
833 EXTRA_CHECK (! (must_add_chunked_encoding && must_add_content_length) );
836 if ( (pos->
kind == kind) &&
837 (! ( (
MHD_YES == must_add_close) &&
838 (pos->
value == response_has_keepalive) &&
841 size += strlen (pos->
header) + strlen (pos->
value) + 4;
847 MHD_DLOG (connection->
daemon,
848 "Not enough memory for write!\n");
854 memcpy (data, code, off);
860 "Connection: close\r\n",
861 strlen (
"Connection: close\r\n"));
862 off += strlen (
"Connection: close\r\n");
864 if (must_add_keep_alive)
868 "Connection: Keep-Alive\r\n",
869 strlen (
"Connection: Keep-Alive\r\n"));
870 off += strlen (
"Connection: Keep-Alive\r\n");
872 if (must_add_chunked_encoding)
876 "Transfer-Encoding: chunked\r\n",
877 strlen (
"Transfer-Encoding: chunked\r\n"));
878 off += strlen (
"Transfer-Encoding: chunked\r\n");
880 if (must_add_content_length)
886 off += content_length_len;
889 if ( (pos->
kind == kind) &&
890 (! ( (pos->
value == response_has_keepalive) &&
894 off += sprintf (&data[off],
900 strcpy (&data[off], date);
901 off += strlen (date);
903 memcpy (&data[off],
"\r\n", 2);
927 unsigned int status_code,
941 MHD_DLOG (connection->
daemon,
942 "Error %u (`%s') processing request, closing connection.\n",
943 status_code, message);
956 "Closing connection (failed to create response header)\n");
979 MHD_DLOG (connection->
daemon,
982 MHD_state_to_string (connection->
state));
984 switch (connection->
state)
988 if (0 == gnutls_record_get_direction (connection->tls_session))
1131 while ((pos < connection->read_buffer_offset - 1) &&
1132 (
'\r' != rbuf[pos]) && (
'\n' != rbuf[pos]))
1135 (
'\n' != rbuf[pos]) )
1151 if ((
'\r' == rbuf[pos]) && (
'\n' == rbuf[pos + 1]))
1181 MHD_DLOG (connection->
daemon,
1182 "Not enough memory to allocate header record!\n");
1209 while (
NULL != args)
1211 equals = strchr (args,
'=');
1212 amper = strchr (args,
'&');
1244 if ( (
NULL == equals) ||
1310 MHD_DLOG (connection->
daemon,
1311 "Not enough memory to parse cookies!\n");
1317 memcpy (cpy, hdr, strlen (hdr) + 1);
1325 while (((*sce) !=
'\0') &&
1326 ((*sce) !=
',') && ((*sce) !=
';') && ((*sce) !=
'='))
1330 while ((*ekill ==
' ') && (ekill >= pos))
1348 while ( (
'\0' != semicolon[0]) &&
1350 ( (
';' != semicolon[0]) &&
1351 (
',' != semicolon[0]) ) ) )
1353 if (
'"' == semicolon[0])
1354 quotes = (quotes + 1) & 1;
1357 if (
'\0' == semicolon[0])
1359 if (
NULL != semicolon)
1361 semicolon[0] =
'\0';
1365 if ( (
'"' == equals[0]) &&
1366 (
'"' == equals[strlen (equals) - 1]) )
1368 equals[strlen (equals) - 1] =
'\0';
1395 if (
NULL == (uri = strchr (line,
' ')))
1398 connection->
method = line;
1400 while (
' ' == uri[0])
1402 http_version = strchr (uri,
' ');
1403 if (
NULL != http_version)
1405 http_version[0] =
'\0';
1413 args = strchr (uri,
'?');
1423 connection->
url = uri;
1424 if (
NULL == http_version)
1427 connection->
version = http_version;
1459 "Internal application error, closing connection.\n");
1502 if ((buffer_head[i] ==
'\r') || (buffer_head[i] ==
'\n'))
1504 if ((buffer_head[i] ==
'\r') || (buffer_head[i] ==
'\n'))
1510 "Received malformed HTTP request (bad chunked encoding), closing connection.\n");
1527 if (processed > available)
1528 processed = available;
1529 if (available > processed)
1536 while (i < available)
1538 if ((buffer_head[i] ==
'\r') || (buffer_head[i] ==
'\n'))
1548 if ((i + 1 >= available) &&
1549 !((i == 1) && (available == 2) && (buffer_head[0] ==
'0')))
1551 malformed = (i >= 6);
1554 buffer_head[i] =
'\0';
1556 malformed = (
'\0' != *end);
1562 "Received malformed HTTP request (bad chunked encoding), closing connection.\n");
1566 if ((i < available) &&
1567 ((buffer_head[i] ==
'\r') || (buffer_head[i] ==
'\n')))
1599 processed = available;
1616 "Internal application error, closing connection.\n");
1619 if (processed > used)
1633 buffer_head += used;
1638 while (
MHD_YES == instant_retry);
1640 memmove (connection->
read_buffer, buffer_head, available);
1661 bytes_read = connection->
recv_cls (connection,
1669 if ((EINTR == err) || (EAGAIN == err) || (
EWOULDBLOCK == err))
1679 MHD_DLOG (connection->
daemon,
1680 "Failed to receive data: %s\n",
1681 gnutls_strerror (bytes_read));
1684 MHD_DLOG (connection->
daemon,
1685 "Failed to receive data: %s\n",
1691 if (0 == bytes_read)
1720 ret = connection->
send_cls (connection,
1728 if ((EINTR == err) || (EAGAIN == err) || (
EWOULDBLOCK == err))
1733 MHD_DLOG (connection->
daemon,
1734 "Failed to send data: %s\n",
1735 gnutls_strerror ((
int) ret));
1738 MHD_DLOG (connection->
daemon,
1746 "Sent response: `%.*s'\n",
1775 connection->
state = next_state;
1800 colon = strchr (line,
':');
1805 "Received malformed line (no colon), closing connection.\n");
1811 while ((colon[0] !=
'\0') && ((colon[0] ==
' ') || (colon[0] ==
'\t')))
1818 connection->
last = line;
1819 connection->
colon = colon;
1843 last = connection->
last;
1844 if ((line[0] ==
' ') || (line[0] ==
'\t'))
1848 last_len = strlen (last);
1851 while ((tmp[0] ==
' ') || (tmp[0] ==
'\t'))
1853 tmp_len = strlen (tmp);
1866 last_len + tmp_len + 1);
1874 memcpy (&last[last_len], tmp, tmp_len + 1);
1875 connection->
last = last;
1880 last, connection->
colon, kind)))
1887 if (0 != strlen (line))
1929 MHD_DLOG (connection->
daemon,
1930 "Received `%s' request without `%s' header.\n",
1960 cval = strtoul (clen, &end, 10);
1961 if ( (
'\0' != *end) ||
1962 ( (LONG_MAX == cval) && (errno == ERANGE) ) )
1965 MHD_DLOG (connection->
daemon,
1966 "Failed to parse `%s' header `%s', closing connection.\n",
1998 MHD_PANIC (
"Failed to acquire cleanup mutex\n");
2007 MHD_PANIC (
"Failed to release cleanup mutex\n");
2035 MHD_DLOG (connection->
daemon,
"%s: state: %s\n",
2037 MHD_state_to_string (connection->
state));
2039 switch (connection->
state)
2092 MHD_DLOG (connection->
daemon,
"%s: state: %s\n",
2094 MHD_state_to_string (connection->
state));
2096 switch (connection->
state)
2107 ret = connection->
send_cls (connection,
2115 if ((err == EINTR) || (err == EAGAIN) || (
EWOULDBLOCK == err))
2118 MHD_DLOG (connection->
daemon,
2119 "Failed to send data: %s\n",
2127 "Sent 100 continue response: `%.*s'\n",
2151 (void) MHD_mutex_lock_ (&response->
mutex);
2154 ret = connection->
send_cls (connection,
2165 "Sent DATA response: `%.*s'\n",
2171 (void) MHD_mutex_unlock_ (&response->
mutex);
2174 if ((err == EINTR) || (err == EAGAIN) || (
EWOULDBLOCK == err))
2177 MHD_DLOG (connection->
daemon,
2178 "Failed to send data: %s\n",
2202 case MHD_CONNECTION_CHUNKED_BODY_UNREADY:
2223 "Internal error\n");
2250 MHD_PANIC (
"Failed to acquire cleanup mutex\n");
2275 MHD_PANIC (
"Failed to release cleanup mutex\n");
2291 unsigned int timeout;
2303 MHD_state_to_string (connection->
state));
2305 switch (connection->
state)
2340 if (strlen (line) == 0)
2371 if (0 == strlen (line))
2448 if (0 == strlen (line))
2479 if (0 == strlen (line))
2495 "Closing connection (failed to create response header)\n");
2500 #if HAVE_DECL_TCP_CORK
2504 setsockopt (connection->
socket_fd, IPPROTO_TCP, TCP_CORK, &val,
2568 "Closing connection (failed to create response header)\n");
2582 #if HAVE_DECL_TCP_CORK
2586 setsockopt (connection->
socket_fd, IPPROTO_TCP, TCP_CORK, &val,
2593 client_close = ((
NULL != end) && (0 == strcasecmp (end,
"close")));
2663 if ( (0 != timeout) &&
2680 daemon->eready_tail,
2692 daemon->eready_tail,
2701 daemon->eready_tail,
2713 daemon->eready_tail,
2722 return MHD_connection_epoll_update_ (connection);
2753 struct epoll_event event;
2755 event.events = EPOLLIN | EPOLLOUT | EPOLLET;
2756 event.data.ptr = connection;
2757 if (0 != epoll_ctl (daemon->epoll_fd,
2765 "Call to epoll_ctl failed: %s\n",
2812 if (connection->tls_session ==
NULL)
2814 connection->cipher = gnutls_cipher_get (connection->tls_session);
2817 if (connection->tls_session ==
NULL)
2819 connection->protocol = gnutls_protocol_get_version (connection->tls_session);
2822 if (connection->tls_session ==
NULL)
2855 daemon = connection->
daemon;
2861 MHD_PANIC (
"Failed to acquire cleanup mutex\n");
2872 va_start (ap, option);
2887 MHD_PANIC (
"Failed to release cleanup mutex\n");
2908 unsigned int status_code,
2911 if ( (
NULL == connection) ||
2912 (
NULL == response) ||
static int process_header_line(struct MHD_Connection *connection, char *line)
#define MHD_HTTP_REQUEST_ENTITY_TOO_LARGE
int(* MHD_KeyValueIterator)(void *cls, enum MHD_ValueKind kind, const char *key, const char *value)
static int parse_cookie_header(struct MHD_Connection *connection)
void * unescape_callback_cls
void MHD_unescape_plus(char *arg)
#define XDLL_insert(head, tail, element)
static int try_ready_normal_body(struct MHD_Connection *connection)
_MHD_EXTERN const char * MHD_lookup_connection_value(struct MHD_Connection *connection, enum MHD_ValueKind kind, const char *key)
#define MHD_HTTP_METHOD_CONNECT
int(* write_handler)(struct MHD_Connection *connection)
static void MHD_connection_update_event_loop_info(struct MHD_Connection *connection)
enum MHD_CONNECTION_STATE state
int(* idle_handler)(struct MHD_Connection *connection)
static int try_ready_chunked_body(struct MHD_Connection *connection)
uint64_t response_write_position
void MHD_pool_destroy(struct MemoryPool *pool)
#define HTTP_100_CONTINUE
enum MHD_ConnectionEventLoopInfo event_loop_info
size_t current_chunk_size
int MHD_connection_handle_write(struct MHD_Connection *connection)
#define DLL_remove(head, tail, element)
Methods for managing connections.
static int connection_add_header(struct MHD_Connection *connection, char *key, char *value, enum MHD_ValueKind kind)
struct MHD_Response * response
#define REQUEST_LACKS_HOST
struct MHD_Connection * normal_timeout_tail
MHD_RequestTerminationCode
static int do_read(struct MHD_Connection *connection)
struct MHD_HTTP_Header * first_header
static void transmit_error_response(struct MHD_Connection *connection, unsigned int status_code, const char *message)
MHD_AccessHandlerCallback default_handler
void * MHD_pool_allocate(struct MemoryPool *pool, size_t size, int from_end)
size_t current_chunk_offset
static void call_connection_handler(struct MHD_Connection *connection)
uint64_t remaining_upload_size
unsigned int responseCode
Methods for managing response objects.
static void cleanup_connection(struct MHD_Connection *connection)
#define MHD_UNSIGNED_LONG_LONG
void * uri_log_callback_cls
int(* read_handler)(struct MHD_Connection *connection)
struct MHD_Daemon * daemon
struct MHD_Connection * manual_timeout_head
struct MHD_Connection * cleanup_head
static void connection_close_error(struct MHD_Connection *connection, const char *emsg)
_MHD_EXTERN const union MHD_ConnectionInfo * MHD_get_connection_info(struct MHD_Connection *connection, enum MHD_ConnectionInfoType info_type,...)
static int keepalive_possible(struct MHD_Connection *connection)
struct MHD_Connection * cleanup_tail
int MHD_connection_handle_read(struct MHD_Connection *connection)
size_t write_buffer_send_offset
void * MHD_pool_reallocate(struct MemoryPool *pool, void *old, size_t old_size, size_t new_size)
static void get_date_string(char *date)
struct MHD_Connection * manual_timeout_tail
size_t continue_message_write_offset
#define REQUEST_MALFORMED
#define MHD_INVALID_SOCKET
internal shared structures
time_t MHD_monotonic_time(void)
LogCallback uri_log_callback
_MHD_EXTERN void MHD_destroy_response(struct MHD_Response *response)
_MHD_EXTERN int MHD_set_connection_option(struct MHD_Connection *connection, enum MHD_CONNECTION_OPTION option,...)
void MHD_increment_response_rc(struct MHD_Response *response)
#define MHD_CONTENT_READER_END_OF_STREAM
struct MHD_Connection * normal_timeout_head
static void update_last_activity(struct MHD_Connection *connection)
static int need_100_continue(struct MHD_Connection *connection)
static char * get_next_header_line(struct MHD_Connection *connection)
const char * MHD_get_reason_phrase_for(unsigned int code)
#define MHD_HTTP_VERSION_1_1
UnescapeCallback unescape_callback
static int try_grow_read_buffer(struct MHD_Connection *connection)
_MHD_EXTERN int MHD_queue_response(struct MHD_Connection *connection, unsigned int status_code, struct MHD_Response *response)
void * MHD_pool_reset(struct MemoryPool *pool, void *keep, size_t size)
#define MHD_HTTP_BAD_REQUEST
static int parse_initial_message_line(struct MHD_Connection *connection, char *line)
_MHD_EXTERN struct MHD_Response * MHD_create_response_from_buffer(size_t size, void *buffer, enum MHD_ResponseMemoryMode mode)
struct MHD_Connection * connections_head
static int check_write_done(struct MHD_Connection *connection, enum MHD_CONNECTION_STATE next_state)
int MHD_connection_handle_idle(struct MHD_Connection *connection)
unsigned int connection_timeout
static int process_broken_line(struct MHD_Connection *connection, char *line, enum MHD_ValueKind kind)
enum MHD_ResponseFlags flags
#define MHD_HTTP_METHOD_HEAD
static void parse_connection_headers(struct MHD_Connection *connection)
size_t write_buffer_append_offset
MHD_RequestCompletedCallback notify_completed
void MHD_set_http_callbacks_(struct MHD_Connection *connection)
#define MHD_HTTP_METHOD_PUT
void * notify_completed_cls
static void process_request_body(struct MHD_Connection *connection)
#define MHD_HTTP_VERSION_1_0
TransmitCallback send_cls
_MHD_EXTERN int MHD_get_connection_values(struct MHD_Connection *connection, enum MHD_ValueKind kind, MHD_KeyValueIterator iterator, void *iterator_cls)
#define XDLL_remove(head, tail, element)
#define DLL_insert(head, tail, element)
#define MHD_HTTP_INTERNAL_SERVER_ERROR
#define MHD_CONTENT_READER_END_WITH_ERROR
MHD_ContentReaderCallback crc
struct MHD_Connection * suspended_connections_tail
MHD_PanicCallback mhd_panic
#define MHD_UNSIGNED_LONG_LONG_PRINTF
static int parse_arguments(enum MHD_ValueKind kind, struct MHD_Connection *connection, char *args)
static int do_write(struct MHD_Connection *connection)
size_t read_buffer_offset
void * default_handler_cls
unsigned int connection_timeout
_MHD_EXTERN const char * MHD_get_response_header(struct MHD_Response *response, const char *key)
#define MHD_HTTP_REQUEST_URI_TOO_LONG
MHD_mutex_ cleanup_connection_mutex
#define CONNECTION_CLOSE_ERROR(c, emsg)
struct MHD_HTTP_Header * headers_received
struct MHD_Connection * connections_tail
#define EDLL_insert(head, tail, element)
void MHD_connection_close(struct MHD_Connection *connection, enum MHD_RequestTerminationCode termination_code)
_MHD_EXTERN int MHD_set_connection_value(struct MHD_Connection *connection, enum MHD_ValueKind kind, const char *key, const char *value)
struct MHD_HTTP_Header * headers_received_tail
static int build_header_response(struct MHD_Connection *connection)
#define MHD_HTTP_METHOD_POST
struct MHD_Connection * suspended_connections_head
memory pool; mostly used for efficient (de)allocation for each connection and bounding memory use for...