aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2018-02-17 09:43:09 +0100
committerChristian Grothoff <christian@grothoff.org>2018-02-17 09:43:09 +0100
commit25385c3c76cd81613761031f6f87c4087c2975eb (patch)
tree02493d62a8f96cec60347a40fb5341bb5d041caa
parented7d85d6a835bc3528cb66a324dac93af1d3e8bc (diff)
downloadlibmicrohttpd-25385c3c76cd81613761031f6f87c4087c2975eb.tar.gz
libmicrohttpd-25385c3c76cd81613761031f6f87c4087c2975eb.zip
more work on connection_call_handlers.c
-rw-r--r--src/gnutls/idle_ready.c12
-rw-r--r--src/include/microhttpd2.h66
-rw-r--r--src/lib/action_continue.c2
-rw-r--r--src/lib/action_from_response.c2
-rw-r--r--src/lib/action_parse_post.c2
-rw-r--r--src/lib/action_process_upload.c2
-rw-r--r--src/lib/action_suspend.c4
-rw-r--r--src/lib/connection_call_handlers.c1708
-rw-r--r--src/lib/connection_close.c4
-rw-r--r--src/lib/internal.c48
-rw-r--r--src/lib/internal.h27
11 files changed, 1704 insertions, 173 deletions
diff --git a/src/gnutls/idle_ready.c b/src/gnutls/idle_ready.c
new file mode 100644
index 00000000..0e315950
--- /dev/null
+++ b/src/gnutls/idle_ready.c
@@ -0,0 +1,12 @@
1 enum MHD_Bool
2 (*idle_ready)(void *cls,
3 struct MHD_TLS_ConnectionState *cs);
4
5
6 if (MHD_TLS_CONN_NO_TLS != connection->tls_state)
7 { /* HTTPS connection. */
8 if ((MHD_TLS_CONN_INIT <= connection->tls_state) &&
9 (MHD_TLS_CONN_CONNECTED > connection->tls_state))
10 return false;
11 }
12return true;
diff --git a/src/include/microhttpd2.h b/src/include/microhttpd2.h
index f54d16b2..05fa58e9 100644
--- a/src/include/microhttpd2.h
+++ b/src/include/microhttpd2.h
@@ -493,6 +493,27 @@ enum MHD_StatusCode
493 */ 493 */
494 MHD_SC_CONNECTION_WRITE_FAIL_CLOSED = 40003, 494 MHD_SC_CONNECTION_WRITE_FAIL_CLOSED = 40003,
495 495
496 /**
497 * MHD is returning an error because the header provided
498 * by the client is too big.
499 */
500 MHD_SC_CLIENT_HEADER_TOO_BIG = 40004,
501
502 /**
503 * An HTTP/1.1 request was sent without the "Host:" header.
504 */
505 MHD_SC_HOST_HEADER_MISSING = 40005,
506
507 /**
508 * The given content length was not a number.
509 */
510 MHD_SC_CONTENT_LENGTH_MALFORMED = 40006,
511
512 /**
513 * The given uploaded, chunked-encoded body was malformed.
514 */
515 MHD_SC_CHUNKED_ENCODING_MALFORMED = 40007,
516
496 517
497 518
498 /* 50000-level errors are because of an error internal 519 /* 50000-level errors are because of an error internal
@@ -782,6 +803,18 @@ enum MHD_StatusCode
782 */ 803 */
783 MHD_SC_STATEMACHINE_FAILURE_CONNECTION_CLOSED = 50054, 804 MHD_SC_STATEMACHINE_FAILURE_CONNECTION_CLOSED = 50054,
784 805
806 /**
807 * Failed to allocate memory in connection's pool
808 * to parse the cookie header.
809 */
810 MHD_SC_COOKIE_POOL_ALLOCATION_FAILURE = 50055,
811
812 /**
813 * MHD failed to build the response header.
814 */
815 MHD_SC_FAILED_RESPONSE_HEADER_GENERATION = 50056,
816
817
785 818
786 /* 60000-level errors are because the application 819 /* 60000-level errors are because the application
787 logic did something wrong or generated an error. */ 820 logic did something wrong or generated an error. */
@@ -820,6 +853,19 @@ enum MHD_StatusCode
820 */ 853 */
821 MHD_SC_APPLICATION_DATA_GENERATION_FAILURE_CLOSED = 60005, 854 MHD_SC_APPLICATION_DATA_GENERATION_FAILURE_CLOSED = 60005,
822 855
856 /**
857 * MHD is closing a connection because the application
858 * callback told it to do so.
859 */
860 MHD_SC_APPLICATION_CALLBACK_FAILURE_CLOSED = 60006,
861
862 /**
863 * Application only partially processed upload and did
864 * not suspend connection. This may result in a hung
865 * connection.
866 */
867 MHD_SC_APPLICATION_HUNG_CONNECTION = 60007,
868
823 869
824}; 870};
825 871
@@ -1409,7 +1455,7 @@ enum MHD_Method
1409 * if the socket must be closed due to a serios 1455 * if the socket must be closed due to a serios
1410 * error while handling the request 1456 * error while handling the request
1411 */ 1457 */
1412typedef struct MHD_Action * 1458typedef const struct MHD_Action *
1413(*MHD_RequestCallback) (void *cls, 1459(*MHD_RequestCallback) (void *cls,
1414 struct MHD_Request *request, 1460 struct MHD_Request *request,
1415 const char *url, 1461 const char *url,
@@ -2791,7 +2837,7 @@ MHD_get_reason_phrase_for (enum MHD_HTTP_StatusCode code);
2791 * 2837 *
2792 * @return action to cause a request to be suspended. 2838 * @return action to cause a request to be suspended.
2793 */ 2839 */
2794_MHD_EXTERN struct MHD_Action * 2840_MHD_EXTERN const struct MHD_Action *
2795MHD_action_suspend (void); 2841MHD_action_suspend (void);
2796 2842
2797 2843
@@ -2826,10 +2872,10 @@ struct MHD_Response;
2826 2872
2827 2873
2828/** 2874/**
2829 * Converts a @a response to an action. If @a consume 2875 * Converts a @a response to an action. If @a destroy_after_use
2830 * is set, the reference to the @a response is consumed 2876 * is set, the reference to the @a response is consumed
2831 * by the conversion. If @a consume is #MHD_NO, then 2877 * by the conversion. If @a consume is #MHD_NO, then
2832 * the response can be converted to actions in the future. 2878 * the @a response can be converted to actions in the future.
2833 * However, the @a response is frozen by this step and 2879 * However, the @a response is frozen by this step and
2834 * must no longer be modified (i.e. by setting headers). 2880 * must no longer be modified (i.e. by setting headers).
2835 * 2881 *
@@ -2842,7 +2888,7 @@ struct MHD_Response;
2842 * as a response *is* an action. As no memory is 2888 * as a response *is* an action. As no memory is
2843 * allocated, this operation cannot fail. 2889 * allocated, this operation cannot fail.
2844 */ 2890 */
2845_MHD_EXTERN struct MHD_Action * 2891_MHD_EXTERN const struct MHD_Action *
2846MHD_action_from_response (struct MHD_Response *response, 2892MHD_action_from_response (struct MHD_Response *response,
2847 enum MHD_Bool destroy_after_use) 2893 enum MHD_Bool destroy_after_use)
2848 MHD_NONNULL(1); 2894 MHD_NONNULL(1);
@@ -3364,7 +3410,7 @@ MHD_response_get_header (struct MHD_Response *response,
3364 * 3410 *
3365 * @return action operation, never NULL 3411 * @return action operation, never NULL
3366 */ 3412 */
3367_MHD_EXTERN struct MHD_Action * 3413_MHD_EXTERN const struct MHD_Action *
3368MHD_action_continue (void); 3414MHD_action_continue (void);
3369 3415
3370 3416
@@ -3386,7 +3432,7 @@ MHD_action_continue (void);
3386 * NULL to close the socket, or a response 3432 * NULL to close the socket, or a response
3387 * to discard the rest of the upload and return the data given 3433 * to discard the rest of the upload and return the data given
3388 */ 3434 */
3389typedef struct MHD_Action * 3435typedef const struct MHD_Action *
3390(*MHD_UploadCallback) (void *cls, 3436(*MHD_UploadCallback) (void *cls,
3391 const char *upload_data, 3437 const char *upload_data,
3392 size_t *upload_data_size); 3438 size_t *upload_data_size);
@@ -3400,7 +3446,7 @@ typedef struct MHD_Action *
3400 * @return NULL on error (out of memory) 3446 * @return NULL on error (out of memory)
3401 * @ingroup action 3447 * @ingroup action
3402 */ 3448 */
3403_MHD_EXTERN struct MHD_Action * 3449_MHD_EXTERN const struct MHD_Action *
3404MHD_action_process_upload (MHD_UploadCallback uc, 3450MHD_action_process_upload (MHD_UploadCallback uc,
3405 void *uc_cls) 3451 void *uc_cls)
3406 MHD_NONNULL(1); 3452 MHD_NONNULL(1);
@@ -3429,7 +3475,7 @@ MHD_action_process_upload (MHD_UploadCallback uc,
3429 * NULL to close the socket, or a response 3475 * NULL to close the socket, or a response
3430 * to discard the rest of the upload and return the data given 3476 * to discard the rest of the upload and return the data given
3431 */ 3477 */
3432typedef struct MHD_Action * 3478typedef const struct MHD_Action *
3433(*MHD_PostDataIterator) (void *cls, 3479(*MHD_PostDataIterator) (void *cls,
3434 enum MHD_ValueKind kind, 3480 enum MHD_ValueKind kind,
3435 const char *key, 3481 const char *key,
@@ -3465,7 +3511,7 @@ typedef struct MHD_Action *
3465 * otherwise a PP handle 3511 * otherwise a PP handle
3466 * @ingroup request 3512 * @ingroup request
3467 */ 3513 */
3468_MHD_EXTERN struct MHD_Action * 3514_MHD_EXTERN const struct MHD_Action *
3469MHD_action_parse_post (size_t buffer_size, 3515MHD_action_parse_post (size_t buffer_size,
3470 MHD_PostDataIterator iter, 3516 MHD_PostDataIterator iter,
3471 void *iter_cls) 3517 void *iter_cls)
diff --git a/src/lib/action_continue.c b/src/lib/action_continue.c
index 40cb4a12..20c351ad 100644
--- a/src/lib/action_continue.c
+++ b/src/lib/action_continue.c
@@ -50,7 +50,7 @@ cont_action (void *cls,
50 * 50 *
51 * @return action operation, never NULL 51 * @return action operation, never NULL
52 */ 52 */
53struct MHD_Action * 53const struct MHD_Action *
54MHD_action_continue (void) 54MHD_action_continue (void)
55{ 55{
56 static struct MHD_Action acont = { 56 static struct MHD_Action acont = {
diff --git a/src/lib/action_from_response.c b/src/lib/action_from_response.c
index 9c303e0c..d3dccc5f 100644
--- a/src/lib/action_from_response.c
+++ b/src/lib/action_from_response.c
@@ -111,7 +111,7 @@ response_action (void *cls,
111 * as a response *is* an action. As no memory is 111 * as a response *is* an action. As no memory is
112 * allocated, this operation cannot fail. 112 * allocated, this operation cannot fail.
113 */ 113 */
114_MHD_EXTERN struct MHD_Action * 114_MHD_EXTERN const struct MHD_Action *
115MHD_action_from_response (struct MHD_Response *response, 115MHD_action_from_response (struct MHD_Response *response,
116 enum MHD_Bool destroy_after_use) 116 enum MHD_Bool destroy_after_use)
117{ 117{
diff --git a/src/lib/action_parse_post.c b/src/lib/action_parse_post.c
index 202e52f1..c60e793d 100644
--- a/src/lib/action_parse_post.c
+++ b/src/lib/action_parse_post.c
@@ -50,7 +50,7 @@
50 * otherwise a PP handle 50 * otherwise a PP handle
51 * @ingroup request 51 * @ingroup request
52 */ 52 */
53struct MHD_Action * 53const struct MHD_Action *
54MHD_action_parse_post (size_t buffer_size, 54MHD_action_parse_post (size_t buffer_size,
55 MHD_PostDataIterator iter, 55 MHD_PostDataIterator iter,
56 void *iter_cls) 56 void *iter_cls)
diff --git a/src/lib/action_process_upload.c b/src/lib/action_process_upload.c
index 33221486..cafd5d3c 100644
--- a/src/lib/action_process_upload.c
+++ b/src/lib/action_process_upload.c
@@ -73,7 +73,7 @@ upload_action (void *cls,
73 * @return NULL on error (out of memory) 73 * @return NULL on error (out of memory)
74 * @ingroup action 74 * @ingroup action
75 */ 75 */
76struct MHD_Action * 76const struct MHD_Action *
77MHD_action_process_upload (MHD_UploadCallback uc, 77MHD_action_process_upload (MHD_UploadCallback uc,
78 void *uc_cls) 78 void *uc_cls)
79{ 79{
diff --git a/src/lib/action_suspend.c b/src/lib/action_suspend.c
index 9e5e1301..da27f124 100644
--- a/src/lib/action_suspend.c
+++ b/src/lib/action_suspend.c
@@ -123,10 +123,10 @@ suspend_action (void *cls,
123 * 123 *
124 * @return action to cause a request to be suspended. 124 * @return action to cause a request to be suspended.
125 */ 125 */
126struct MHD_Action * 126const struct MHD_Action *
127MHD_action_suspend (void) 127MHD_action_suspend (void)
128{ 128{
129 static struct MHD_Action suspend = { 129 static const struct MHD_Action suspend = {
130 .action = &suspend_action, 130 .action = &suspend_action,
131 .action_cls = NULL 131 .action_cls = NULL
132 }; 132 };
diff --git a/src/lib/connection_call_handlers.c b/src/lib/connection_call_handlers.c
index 346089a2..9e6276eb 100644
--- a/src/lib/connection_call_handlers.c
+++ b/src/lib/connection_call_handlers.c
@@ -26,6 +26,7 @@
26#include "connection_update_last_activity.h" 26#include "connection_update_last_activity.h"
27#include "connection_close.h" 27#include "connection_close.h"
28 28
29
29#ifdef MHD_LINUX_SOLARIS_SENDFILE 30#ifdef MHD_LINUX_SOLARIS_SENDFILE
30#include <sys/sendfile.h> 31#include <sys/sendfile.h>
31#endif /* MHD_LINUX_SOLARIS_SENDFILE */ 32#endif /* MHD_LINUX_SOLARIS_SENDFILE */
@@ -46,6 +47,59 @@
46 */ 47 */
47#define MHD_SENFILE_CHUNK_THR_P_C_ (0x200000) 48#define MHD_SENFILE_CHUNK_THR_P_C_ (0x200000)
48 49
50
51/**
52 * Response text used when the request (http header) is too big to
53 * be processed.
54 *
55 * Intentionally empty here to keep our memory footprint
56 * minimal.
57 */
58#ifdef HAVE_MESSAGES
59#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>"
60#else
61#define REQUEST_TOO_BIG ""
62#endif
63
64/**
65 * Response text used when the request (http header) does not
66 * contain a "Host:" header and still claims to be HTTP 1.1.
67 *
68 * Intentionally empty here to keep our memory footprint
69 * minimal.
70 */
71#ifdef HAVE_MESSAGES
72#define REQUEST_LACKS_HOST "<html><head><title>&quot;Host:&quot; header required</title></head><body>In HTTP 1.1, requests must include a &quot;Host:&quot; header, and your HTTP 1.1 request lacked such a header.</body></html>"
73#else
74#define REQUEST_LACKS_HOST ""
75#endif
76
77/**
78 * Response text used when the request (http header) is
79 * malformed.
80 *
81 * Intentionally empty here to keep our memory footprint
82 * minimal.
83 */
84#ifdef HAVE_MESSAGES
85#define REQUEST_MALFORMED "<html><head><title>Request malformed</title></head><body>Your HTTP request was syntactically incorrect.</body></html>"
86#else
87#define REQUEST_MALFORMED ""
88#endif
89
90/**
91 * Response text used when there is an internal server error.
92 *
93 * Intentionally empty here to keep our memory footprint
94 * minimal.
95 */
96#ifdef HAVE_MESSAGES
97#define INTERNAL_ERROR "<html><head><title>Internal server error</title></head><body>Please ask the developer of this Web server to carefully read the GNU libmicrohttpd documentation about connection management and blocking.</body></html>"
98#else
99#define INTERNAL_ERROR ""
100#endif
101
102
49#ifdef HAVE_FREEBSD_SENDFILE 103#ifdef HAVE_FREEBSD_SENDFILE
50#ifdef SF_FLAGS 104#ifdef SF_FLAGS
51/** 105/**
@@ -931,7 +985,647 @@ MHD_request_handle_write_ (struct MHD_Request *request)
931 _("Internal error\n")); 985 _("Internal error\n"));
932 break; 986 break;
933 } 987 }
934 return; 988}
989
990
991/**
992 * Check whether request header contains particular token.
993 *
994 * Token could be surrounded by spaces and tabs and delimited by comma.
995 * Case-insensitive match used for header names and tokens.
996 * @param request the request to get values from
997 * @param header the header name
998 * @param token the token to find
999 * @param token_len the length of token, not including optional
1000 * terminating null-character.
1001 * @return true if token is found in specified header,
1002 * false otherwise
1003 */
1004static bool
1005MHD_lookup_header_token_ci (const struct MHD_Request *request,
1006 const char *header,
1007 const char *token,
1008 size_t token_len)
1009{
1010 struct MHD_HTTP_Header *pos;
1011
1012 if ( (NULL == request) || /* FIXME: require non-null? */
1013 (NULL == header) || /* FIXME: require non-null? */
1014 (0 == header[0]) ||
1015 (NULL == token) ||
1016 (0 == token[0]) )
1017 return false;
1018 for (pos = request->headers_received; NULL != pos; pos = pos->next)
1019 {
1020 if ( (0 != (pos->kind & MHD_HEADER_KIND)) &&
1021 ( (header == pos->header) ||
1022 (MHD_str_equal_caseless_(header,
1023 pos->header)) ) &&
1024 (MHD_str_has_token_caseless_ (pos->value,
1025 token,
1026 token_len)) )
1027 return true;
1028 }
1029 return false;
1030}
1031
1032
1033/**
1034 * Check whether request header contains particular static @a tkn.
1035 *
1036 * Token could be surrounded by spaces and tabs and delimited by comma.
1037 * Case-insensitive match used for header names and tokens.
1038 * @param r the request to get values from
1039 * @param h the header name
1040 * @param tkn the static string of token to find
1041 * @return true if token is found in specified header,
1042 * false otherwise
1043 */
1044#define MHD_lookup_header_s_token_ci(r,h,tkn) \
1045 MHD_lookup_header_token_ci((r),(h),(tkn),MHD_STATICSTR_LEN_(tkn))
1046
1047
1048/**
1049 * Are we allowed to keep the given connection alive? We can use the
1050 * TCP stream for a second request if the connection is HTTP 1.1 and
1051 * the "Connection" header either does not exist or is not set to
1052 * "close", or if the connection is HTTP 1.0 and the "Connection"
1053 * header is explicitly set to "keep-alive". If no HTTP version is
1054 * specified (or if it is not 1.0 or 1.1), we definitively close the
1055 * connection. If the "Connection" header is not exactly "close" or
1056 * "keep-alive", we proceed to use the default for the respective HTTP
1057 * version (which is conservative for HTTP 1.0, but might be a bit
1058 * optimistic for HTTP 1.1).
1059 *
1060 * @param request the request to check for keepalive
1061 * @return #MHD_YES if (based on the request), a keepalive is
1062 * legal
1063 */
1064static bool
1065keepalive_possible (struct MHD_Request *request)
1066{
1067 if (MHD_CONN_MUST_CLOSE == request->keepalive)
1068 return false;
1069 if (NULL == request->version_s)
1070 return false;
1071 if ( (NULL != request->response) &&
1072 (request->response->v10_only) )
1073 return false;
1074
1075 if (MHD_str_equal_caseless_ (request->version_s,
1076 MHD_HTTP_VERSION_1_1))
1077 {
1078 if (MHD_lookup_header_s_token_ci (request,
1079 MHD_HTTP_HEADER_CONNECTION,
1080 "upgrade"))
1081 return false;
1082 if (MHD_lookup_header_s_token_ci (request,
1083 MHD_HTTP_HEADER_CONNECTION,
1084 "close"))
1085 return false;
1086 return true;
1087 }
1088 if (MHD_str_equal_caseless_ (request->version_s,
1089 MHD_HTTP_VERSION_1_0))
1090 {
1091 if (MHD_lookup_header_s_token_ci (request,
1092 MHD_HTTP_HEADER_CONNECTION,
1093 "Keep-Alive"))
1094 return true;
1095 return false;
1096 }
1097 return false;
1098}
1099
1100
1101/**
1102 * Produce HTTP time stamp.
1103 *
1104 * @param date where to write the header, with
1105 * at least 128 bytes available space.
1106 * @param date_len number of bytes in @a date
1107 */
1108static void
1109get_date_string (char *date,
1110 size_t date_len)
1111{
1112 static const char *const days[] = {
1113 "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
1114 };
1115 static const char *const mons[] = {
1116 "Jan", "Feb", "Mar", "Apr", "May", "Jun",
1117 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
1118 };
1119 struct tm now;
1120 time_t t;
1121#if !defined(HAVE_C11_GMTIME_S) && !defined(HAVE_W32_GMTIME_S) && !defined(HAVE_GMTIME_R)
1122 struct tm* pNow;
1123#endif
1124
1125 date[0] = 0;
1126 time (&t);
1127#if defined(HAVE_C11_GMTIME_S)
1128 if (NULL == gmtime_s (&t,
1129 &now))
1130 return;
1131#elif defined(HAVE_W32_GMTIME_S)
1132 if (0 != gmtime_s (&now,
1133 &t))
1134 return;
1135#elif defined(HAVE_GMTIME_R)
1136 if (NULL == gmtime_r(&t,
1137 &now))
1138 return;
1139#else
1140 pNow = gmtime(&t);
1141 if (NULL == pNow)
1142 return;
1143 now = *pNow;
1144#endif
1145 MHD_snprintf_ (date,
1146 date_len,
1147 "Date: %3s, %02u %3s %04u %02u:%02u:%02u GMT\r\n",
1148 days[now.tm_wday % 7],
1149 (unsigned int) now.tm_mday,
1150 mons[now.tm_mon % 12],
1151 (unsigned int) (1900 + now.tm_year),
1152 (unsigned int) now.tm_hour,
1153 (unsigned int) now.tm_min,
1154 (unsigned int) now.tm_sec);
1155}
1156
1157
1158/**
1159 * Check whether response header contains particular @a token.
1160 *
1161 * Token could be surrounded by spaces and tabs and delimited by comma.
1162 * Case-insensitive match used for header names and tokens.
1163 * @param response the response to query
1164 * @param key header name
1165 * @param token the token to find
1166 * @param token_len the length of token, not including optional
1167 * terminating null-character.
1168 * @return true if token is found in specified header,
1169 * false otherwise
1170 */
1171static bool
1172check_response_header_token_ci (const struct MHD_Response *response,
1173 const char *key,
1174 const char *token,
1175 size_t token_len)
1176{
1177 struct MHD_HTTP_Header *pos;
1178
1179 if ( (NULL == key) ||
1180 ('\0' == key[0]) ||
1181 (NULL == token) ||
1182 ('\0' == token[0]) )
1183 return false;
1184
1185 for (pos = response->first_header;
1186 NULL != pos;
1187 pos = pos->next)
1188 {
1189 if ( (pos->kind == MHD_HEADER_KIND) &&
1190 MHD_str_equal_caseless_ (pos->header,
1191 key) &&
1192 MHD_str_has_token_caseless_ (pos->value,
1193 token,
1194 token_len) )
1195 return true;
1196 }
1197 return false;
1198}
1199
1200
1201/**
1202 * Check whether response header contains particular static @a tkn.
1203 *
1204 * Token could be surrounded by spaces and tabs and delimited by comma.
1205 * Case-insensitive match used for header names and tokens.
1206 * @param r the response to query
1207 * @param k header name
1208 * @param tkn the static string of token to find
1209 * @return true if token is found in specified header,
1210 * false otherwise
1211 */
1212#define check_response_header_s_token_ci(r,k,tkn) \
1213 check_response_header_token_ci((r),(k),(tkn),MHD_STATICSTR_LEN_(tkn))
1214
1215
1216/**
1217 * Allocate the connection's write buffer and fill it with all of the
1218 * headers (or footers, if we have already sent the body) from the
1219 * HTTPd's response. If headers are missing in the response supplied
1220 * by the application, additional headers may be added here.
1221 *
1222 * @param request the request for which to build the response header
1223 * @return true on success, false on failure (out of memory)
1224 */
1225static bool
1226build_header_response (struct MHD_Request *request)
1227{
1228 struct MHD_Connection *connection = request->connection;
1229 struct MHD_Daemon *daemon = request->daemon;
1230 struct MHD_Response *response = request->response;
1231 size_t size;
1232 size_t off;
1233 struct MHD_HTTP_Header *pos;
1234 char code[256];
1235 char date[128];
1236 char content_length_buf[128];
1237 size_t content_length_len;
1238 char *data;
1239 enum MHD_ValueKind kind;
1240 bool client_requested_close;
1241 bool response_has_close;
1242 bool response_has_keepalive;
1243 const char *have_encoding;
1244 const char *have_content_length;
1245 bool must_add_close;
1246 bool must_add_chunked_encoding;
1247 bool must_add_keep_alive;
1248 bool must_add_content_length;
1249
1250 mhd_assert (NULL != request->version_s);
1251 if (0 == request->version_s[0])
1252 {
1253 data = MHD_pool_allocate (connection->pool,
1254 0,
1255 MHD_YES);
1256 request->write_buffer = data;
1257 request->write_buffer_append_offset = 0;
1258 request->write_buffer_send_offset = 0;
1259 request->write_buffer_size = 0;
1260 return true;
1261 }
1262 if (MHD_REQUEST_FOOTERS_RECEIVED == request->state)
1263 {
1264 const char *reason_phrase;
1265 const char *version;
1266
1267 reason_phrase
1268 = MHD_get_reason_phrase_for (response->status_code);
1269 version
1270 = (response->icy)
1271 ? "ICY"
1272 : ( (MHD_str_equal_caseless_ (MHD_HTTP_VERSION_1_0,
1273 request->version_s))
1274 ? MHD_HTTP_VERSION_1_0
1275 : MHD_HTTP_VERSION_1_1);
1276 MHD_snprintf_ (code,
1277 sizeof (code),
1278 "%s %u %s\r\n",
1279 version,
1280 response->status_code,
1281 reason_phrase);
1282 off = strlen (code);
1283 /* estimate size */
1284 size = off + 2; /* +2 for extra "\r\n" at the end */
1285 kind = MHD_HEADER_KIND;
1286 if ( (! daemon->suppress_date) &&
1287 (NULL == MHD_response_get_header (response,
1288 MHD_HTTP_HEADER_DATE)) )
1289 get_date_string (date,
1290 sizeof (date));
1291 else
1292 date[0] = '\0';
1293 size += strlen (date);
1294 }
1295 else
1296 {
1297 /* 2 bytes for final CRLF of a Chunked-Body */
1298 size = 2;
1299 kind = MHD_FOOTER_KIND;
1300 off = 0;
1301 }
1302
1303 /* calculate extra headers we need to add, such as 'Connection: close',
1304 first see what was explicitly requested by the application */
1305 must_add_close = false;
1306 must_add_chunked_encoding = false;
1307 must_add_keep_alive = false;
1308 must_add_content_length = false;
1309 response_has_close = false;
1310 response_has_keepalive = false;
1311 switch (request->state)
1312 {
1313 case MHD_REQUEST_FOOTERS_RECEIVED:
1314 response_has_close
1315 = check_response_header_s_token_ci (response,
1316 MHD_HTTP_HEADER_CONNECTION,
1317 "close");
1318 response_has_keepalive
1319 = check_response_header_s_token_ci (response,
1320 MHD_HTTP_HEADER_CONNECTION,
1321 "Keep-Alive");
1322 client_requested_close
1323 = MHD_lookup_header_s_token_ci (request,
1324 MHD_HTTP_HEADER_CONNECTION,
1325 "close");
1326
1327 if (response->v10_only)
1328 request->keepalive = MHD_CONN_MUST_CLOSE;
1329#ifdef UPGRADE_SUPPORT
1330 else if (NULL != response->upgrade_handler)
1331 /* If this connection will not be "upgraded", it must be closed. */
1332 request->keepalive = MHD_CONN_MUST_CLOSE;
1333#endif /* UPGRADE_SUPPORT */
1334
1335 /* now analyze chunked encoding situation */
1336 request->have_chunked_upload = false;
1337
1338 if ( (MHD_SIZE_UNKNOWN == response->total_size) &&
1339#ifdef UPGRADE_SUPPORT
1340 (NULL == response->upgrade_handler) &&
1341#endif /* UPGRADE_SUPPORT */
1342 (! response_has_close) &&
1343 (! client_requested_close) )
1344 {
1345 /* size is unknown, and close was not explicitly requested;
1346 need to either to HTTP 1.1 chunked encoding or
1347 close the connection */
1348 /* 'close' header doesn't exist yet, see if we need to add one;
1349 if the client asked for a close, no need to start chunk'ing */
1350 if ( (keepalive_possible (request)) &&
1351 (MHD_str_equal_caseless_ (MHD_HTTP_VERSION_1_1,
1352 request->version_s)) )
1353 {
1354 have_encoding
1355 = MHD_response_get_header (response,
1356 MHD_HTTP_HEADER_TRANSFER_ENCODING);
1357 if (NULL == have_encoding)
1358 {
1359 must_add_chunked_encoding = true;
1360 request->have_chunked_upload = true;
1361 }
1362 else if (MHD_str_equal_caseless_ (have_encoding,
1363 "identity"))
1364 {
1365 /* application forced identity encoding, can't do 'chunked' */
1366 must_add_close = true;
1367 }
1368 else
1369 {
1370 request->have_chunked_upload = true;
1371 }
1372 }
1373 else
1374 {
1375 /* Keep alive or chunking not possible
1376 => set close header if not present */
1377 if (! response_has_close)
1378 must_add_close = true;
1379 }
1380 }
1381
1382 /* check for other reasons to add 'close' header */
1383 if ( ( (client_requested_close) ||
1384 (connection->read_closed) ||
1385 (MHD_CONN_MUST_CLOSE == request->keepalive)) &&
1386 (! response_has_close) &&
1387#ifdef UPGRADE_SUPPORT
1388 (NULL == response->upgrade_handler) &&
1389#endif /* UPGRADE_SUPPORT */
1390 (! response->v10_only) )
1391 must_add_close = true;
1392
1393 /* check if we should add a 'content length' header */
1394 have_content_length
1395 = MHD_response_get_header (response,
1396 MHD_HTTP_HEADER_CONTENT_LENGTH);
1397
1398 /* MHD_HTTP_NO_CONTENT, MHD_HTTP_NOT_MODIFIED and 1xx-status
1399 codes SHOULD NOT have a Content-Length according to spec;
1400 also chunked encoding / unknown length or CONNECT... */
1401 if ( (MHD_SIZE_UNKNOWN != response->total_size) &&
1402 (MHD_HTTP_NO_CONTENT != response->status_code) &&
1403 (MHD_HTTP_NOT_MODIFIED != response->status_code) &&
1404 (MHD_HTTP_OK <= response->status_code) &&
1405 (NULL == have_content_length) &&
1406 (request->method != MHD_METHOD_CONNECT) )
1407 {
1408 /*
1409 Here we add a content-length if one is missing; however,
1410 for 'connect' methods, the responses MUST NOT include a
1411 content-length header *if* the response code is 2xx (in
1412 which case we expect there to be no body). Still,
1413 as we don't know the response code here in some cases, we
1414 simply only force adding a content-length header if this
1415 is not a 'connect' or if the response is not empty
1416 (which is kind of more sane, because if some crazy
1417 application did return content with a 2xx status code,
1418 then having a content-length might again be a good idea).
1419
1420 Note that the change from 'SHOULD NOT' to 'MUST NOT' is
1421 a recent development of the HTTP 1.1 specification.
1422 */
1423 content_length_len
1424 = MHD_snprintf_ (content_length_buf,
1425 sizeof (content_length_buf),
1426 MHD_HTTP_HEADER_CONTENT_LENGTH ": " MHD_UNSIGNED_LONG_LONG_PRINTF "\r\n",
1427 (MHD_UNSIGNED_LONG_LONG) response->total_size);
1428 must_add_content_length = true;
1429 }
1430
1431 /* check for adding keep alive */
1432 if ( (! response_has_keepalive) &&
1433 (! response_has_close) &&
1434 (! must_add_close) &&
1435 (MHD_CONN_MUST_CLOSE != request->keepalive) &&
1436#ifdef UPGRADE_SUPPORT
1437 (NULL == response->upgrade_handler) &&
1438#endif /* UPGRADE_SUPPORT */
1439 (keepalive_possible (request)) )
1440 must_add_keep_alive = true;
1441 break;
1442 case MHD_REQUEST_BODY_SENT:
1443 response_has_keepalive = false;
1444 break;
1445 default:
1446 mhd_assert (0);
1447 }
1448
1449 if (MHD_CONN_MUST_CLOSE != request->keepalive)
1450 {
1451 if ( (must_add_close) ||
1452 (response_has_close) )
1453 request->keepalive = MHD_CONN_MUST_CLOSE;
1454 else if ( (must_add_keep_alive) ||
1455 (response_has_keepalive) )
1456 request->keepalive = MHD_CONN_USE_KEEPALIVE;
1457 }
1458
1459 if (must_add_close)
1460 size += MHD_STATICSTR_LEN_ ("Connection: close\r\n");
1461 if (must_add_keep_alive)
1462 size += MHD_STATICSTR_LEN_ ("Connection: Keep-Alive\r\n");
1463 if (must_add_chunked_encoding)
1464 size += MHD_STATICSTR_LEN_ ("Transfer-Encoding: chunked\r\n");
1465 if (must_add_content_length)
1466 size += content_length_len;
1467 mhd_assert (! (must_add_close && must_add_keep_alive) );
1468 mhd_assert (! (must_add_chunked_encoding && must_add_content_length) );
1469
1470 for (pos = response->first_header; NULL != pos; pos = pos->next)
1471 {
1472 /* TODO: add proper support for excluding "Keep-Alive" token. */
1473 if ( (pos->kind == kind) &&
1474 (! ( (must_add_close) &&
1475 (response_has_keepalive) &&
1476 (MHD_str_equal_caseless_(pos->header,
1477 MHD_HTTP_HEADER_CONNECTION)) &&
1478 (MHD_str_equal_caseless_(pos->value,
1479 "Keep-Alive")) ) ) )
1480 size += strlen (pos->header) + strlen (pos->value) + 4; /* colon, space, linefeeds */
1481 }
1482 /* produce data */
1483 data = MHD_pool_allocate (connection->pool,
1484 size + 1,
1485 MHD_NO);
1486 if (NULL == data)
1487 {
1488#ifdef HAVE_MESSAGES
1489 MHD_DLOG (daemon,
1490 MHD_SC_CONNECTION_POOL_MALLOC_FAILURE,
1491 "Not enough memory for write!\n");
1492#endif
1493 return false;
1494 }
1495 if (MHD_REQUEST_FOOTERS_RECEIVED == request->state)
1496 {
1497 memcpy (data,
1498 code,
1499 off);
1500 }
1501 if (must_add_close)
1502 {
1503 /* we must add the 'Connection: close' header */
1504 memcpy (&data[off],
1505 "Connection: close\r\n",
1506 MHD_STATICSTR_LEN_ ("Connection: close\r\n"));
1507 off += MHD_STATICSTR_LEN_ ("Connection: close\r\n");
1508 }
1509 if (must_add_keep_alive)
1510 {
1511 /* we must add the 'Connection: Keep-Alive' header */
1512 memcpy (&data[off],
1513 "Connection: Keep-Alive\r\n",
1514 MHD_STATICSTR_LEN_ ("Connection: Keep-Alive\r\n"));
1515 off += MHD_STATICSTR_LEN_ ("Connection: Keep-Alive\r\n");
1516 }
1517 if (must_add_chunked_encoding)
1518 {
1519 /* we must add the 'Transfer-Encoding: chunked' header */
1520 memcpy (&data[off],
1521 "Transfer-Encoding: chunked\r\n",
1522 MHD_STATICSTR_LEN_ ("Transfer-Encoding: chunked\r\n"));
1523 off += MHD_STATICSTR_LEN_ ("Transfer-Encoding: chunked\r\n");
1524 }
1525 if (must_add_content_length)
1526 {
1527 /* we must add the 'Content-Length' header */
1528 memcpy (&data[off],
1529 content_length_buf,
1530 content_length_len);
1531 off += content_length_len;
1532 }
1533 for (pos = response->first_header; NULL != pos; pos = pos->next)
1534 {
1535 /* TODO: add proper support for excluding "Keep-Alive" token. */
1536 if ( (pos->kind == kind) &&
1537 (! ( (must_add_close) &&
1538 (response_has_keepalive) &&
1539 (MHD_str_equal_caseless_(pos->header,
1540 MHD_HTTP_HEADER_CONNECTION)) &&
1541 (MHD_str_equal_caseless_(pos->value,
1542 "Keep-Alive")) ) ) )
1543 off += MHD_snprintf_ (&data[off],
1544 size - off,
1545 "%s: %s\r\n",
1546 pos->header,
1547 pos->value);
1548 }
1549 if (MHD_REQUEST_FOOTERS_RECEIVED == request->state)
1550 {
1551 strcpy (&data[off],
1552 date);
1553 off += strlen (date);
1554 }
1555 memcpy (&data[off],
1556 "\r\n",
1557 2);
1558 off += 2;
1559
1560 if (off != size)
1561 mhd_panic (mhd_panic_cls,
1562 __FILE__,
1563 __LINE__,
1564 NULL);
1565 request->write_buffer = data;
1566 request->write_buffer_append_offset = size;
1567 request->write_buffer_send_offset = 0;
1568 request->write_buffer_size = size + 1;
1569 return true;
1570}
1571
1572
1573/**
1574 * We encountered an error processing the request. Handle it properly
1575 * by stopping to read data and sending the indicated response code
1576 * and message.
1577 *
1578 * @param request the request
1579 * @param ec error code for MHD
1580 * @param status_code the response code to send (400, 413 or 414)
1581 * @param message the error message to send
1582 */
1583static void
1584transmit_error_response (struct MHD_Request *request,
1585 enum MHD_StatusCode ec,
1586 enum MHD_HTTP_StatusCode status_code,
1587 const char *message)
1588{
1589 struct MHD_Response *response;
1590
1591 if (NULL == request->version_s)
1592 {
1593 /* we were unable to process the full header line, so we don't
1594 really know what version the client speaks; assume 1.0 */
1595 request->version_s = MHD_HTTP_VERSION_1_0;
1596 }
1597 request->state = MHD_REQUEST_FOOTERS_RECEIVED;
1598 request->connection->read_closed = true;
1599#ifdef HAVE_MESSAGES
1600 MHD_DLOG (request->daemon,
1601 ec,
1602 _("Error processing request (HTTP response code is %u (`%s')). Closing connection.\n"),
1603 status_code,
1604 message);
1605#endif
1606 if (NULL != request->response)
1607 {
1608 MHD_response_queue_for_destroy (request->response);
1609 request->response = NULL;
1610 }
1611 response = MHD_response_from_buffer (status_code,
1612 strlen (message),
1613 (void *) message,
1614 MHD_RESPMEM_PERSISTENT);
1615 request->response = response;
1616 /* Do not reuse this connection. */
1617 request->keepalive = MHD_CONN_MUST_CLOSE;
1618 if (! build_header_response (request))
1619 {
1620 /* oops - close! */
1621 CONNECTION_CLOSE_ERROR (request->connection,
1622 ec,
1623 _("Closing connection (failed to create response header)\n"));
1624 }
1625 else
1626 {
1627 request->state = MHD_REQUEST_HEADERS_SENDING;
1628 }
935} 1629}
936 1630
937 1631
@@ -999,6 +1693,43 @@ method_string_to_enum (const char *method)
999 1693
1000 1694
1001/** 1695/**
1696 * Add an entry to the HTTP headers of a request. If this fails,
1697 * transmit an error response (request too big).
1698 *
1699 * @param request the request for which a value should be set
1700 * @param kind kind of the value
1701 * @param key key for the value
1702 * @param value the value itself
1703 * @return false on failure (out of memory), true for success
1704 */
1705static bool
1706request_add_header (struct MHD_Request *request,
1707 const char *key,
1708 const char *value,
1709 enum MHD_ValueKind kind)
1710{
1711 if (MHD_NO ==
1712 MHD_request_set_value (request,
1713 kind,
1714 key,
1715 value))
1716 {
1717#ifdef HAVE_MESSAGES
1718 MHD_DLOG (request->daemon,
1719 MHD_SC_CONNECTION_POOL_MALLOC_FAILURE,
1720 _("Not enough memory in pool to allocate header record!\n"));
1721#endif
1722 transmit_error_response (request,
1723 MHD_SC_CLIENT_HEADER_TOO_BIG,
1724 MHD_HTTP_REQUEST_HEADER_FIELDS_TOO_LARGE,
1725 REQUEST_TOO_BIG);
1726 return false;
1727 }
1728 return true;
1729}
1730
1731
1732/**
1002 * Parse the first line of the HTTP HEADER. 1733 * Parse the first line of the HTTP HEADER.
1003 * 1734 *
1004 * @param connection the connection (updated) 1735 * @param connection the connection (updated)
@@ -1011,7 +1742,6 @@ parse_initial_message_line (struct MHD_Request *request,
1011 char *line, 1742 char *line,
1012 size_t line_len) 1743 size_t line_len)
1013{ 1744{
1014 struct MHD_Connection *connection = request->connection;
1015 struct MHD_Daemon *daemon = request->daemon; 1745 struct MHD_Daemon *daemon = request->daemon;
1016 const char *curi; 1746 const char *curi;
1017 char *uri; 1747 char *uri;
@@ -1036,7 +1766,7 @@ parse_initial_message_line (struct MHD_Request *request,
1036 { 1766 {
1037 curi = ""; 1767 curi = "";
1038 uri = NULL; 1768 uri = NULL;
1039 request->version = ""; 1769 request->version_s = "";
1040 args = NULL; 1770 args = NULL;
1041 } 1771 }
1042 else 1772 else
@@ -1055,22 +1785,21 @@ parse_initial_message_line (struct MHD_Request *request,
1055 if (http_version > uri) 1785 if (http_version > uri)
1056 { 1786 {
1057 http_version[0] = '\0'; 1787 http_version[0] = '\0';
1058 request->version = http_version + 1; 1788 request->version_s = http_version + 1;
1059 args = memchr (uri, 1789 args = memchr (uri,
1060 '?', 1790 '?',
1061 http_version - uri); 1791 http_version - uri);
1062 } 1792 }
1063 else 1793 else
1064 { 1794 {
1065 request->version = ""; 1795 request->version_s = "";
1066 args = memchr (uri, 1796 args = memchr (uri,
1067 '?', 1797 '?',
1068 line_len - (uri - line)); 1798 line_len - (uri - line));
1069 } 1799 }
1070 } 1800 }
1071 if (NULL != daemon->uri_log_callback) 1801 if (NULL != daemon->early_uri_logger_cb)
1072 { 1802 {
1073 request->client_aware = true;
1074 request->client_context 1803 request->client_context
1075 = daemon->early_uri_logger_cb (daemon->early_uri_logger_cb_cls, 1804 = daemon->early_uri_logger_cb (daemon->early_uri_logger_cb_cls,
1076 curi, 1805 curi,
@@ -1081,10 +1810,10 @@ parse_initial_message_line (struct MHD_Request *request,
1081 args[0] = '\0'; 1810 args[0] = '\0';
1082 args++; 1811 args++;
1083 /* note that this call clobbers 'args' */ 1812 /* note that this call clobbers 'args' */
1084 MHD_parse_arguments_ (connection, 1813 MHD_parse_arguments_ (request,
1085 MHD_GET_ARGUMENT_KIND, 1814 MHD_GET_ARGUMENT_KIND,
1086 args, 1815 args,
1087 &connection_add_header, 1816 &request_add_header,
1088 &unused_num_headers); 1817 &unused_num_headers);
1089 } 1818 }
1090 if (NULL != uri) 1819 if (NULL != uri)
@@ -1092,41 +1821,6 @@ parse_initial_message_line (struct MHD_Request *request,
1092 request, 1821 request,
1093 uri); 1822 uri);
1094 request->url = curi; 1823 request->url = curi;
1095 return MHD_YES;
1096}
1097
1098
1099/**
1100 * Add an entry to the HTTP headers of a request. If this fails,
1101 * transmit an error response (request too big).
1102 *
1103 * @param request the request for which a value should be set
1104 * @param kind kind of the value
1105 * @param key key for the value
1106 * @param value the value itself
1107 * @return false on failure (out of memory), true for success
1108 */
1109static bool
1110connection_add_header (struct MHD_Request *request,
1111 const char *key,
1112 const char *value,
1113 enum MHD_ValueKind kind)
1114{
1115 if (MHD_NO ==
1116 MHD_request_set_value (request,
1117 kind,
1118 key,
1119 value))
1120 {
1121#ifdef HAVE_MESSAGES
1122 MHD_DLOG (request->daemon,
1123 _("Not enough memory in pool to allocate header record!\n"));
1124#endif
1125 transmit_error_response (request->connection,
1126 MHD_HTTP_REQUEST_HEADER_FIELDS_TOO_LARGE,
1127 REQUEST_TOO_BIG);
1128 return false;
1129 }
1130 return true; 1824 return true;
1131} 1825}
1132 1826
@@ -1148,7 +1842,8 @@ process_header_line (struct MHD_Request *request,
1148 char *colon; 1842 char *colon;
1149 1843
1150 /* line should be normal header line, find colon */ 1844 /* line should be normal header line, find colon */
1151 colon = strchr (line, ':'); 1845 colon = strchr (line,
1846 ':');
1152 if (NULL == colon) 1847 if (NULL == colon)
1153 { 1848 {
1154 /* error in header line, die hard */ 1849 /* error in header line, die hard */
@@ -1157,7 +1852,7 @@ process_header_line (struct MHD_Request *request,
1157 _("Received malformed line (no colon). Closing connection.\n")); 1852 _("Received malformed line (no colon). Closing connection.\n"));
1158 return false; 1853 return false;
1159 } 1854 }
1160 if (-1 >= request->daemon->strict_for_client) 1855 if (MHD_PSL_PERMISSIVE != request->daemon->protocol_strict_level)
1161 { 1856 {
1162 /* check for whitespace before colon, which is not allowed 1857 /* check for whitespace before colon, which is not allowed
1163 by RFC 7230 section 3.2.4; we count space ' ' and 1858 by RFC 7230 section 3.2.4; we count space ' ' and
@@ -1252,7 +1947,8 @@ process_broken_line (struct MHD_Request *request,
1252 last_len + tmp_len + 1); 1947 last_len + tmp_len + 1);
1253 if (NULL == last) 1948 if (NULL == last)
1254 { 1949 {
1255 transmit_error_response (connection, 1950 transmit_error_response (request,
1951 MHD_SC_CLIENT_HEADER_TOO_BIG,
1256 MHD_HTTP_REQUEST_HEADER_FIELDS_TOO_LARGE, 1952 MHD_HTTP_REQUEST_HEADER_FIELDS_TOO_LARGE,
1257 REQUEST_TOO_BIG); 1953 REQUEST_TOO_BIG);
1258 return MHD_NO; 1954 return MHD_NO;
@@ -1270,7 +1966,8 @@ process_broken_line (struct MHD_Request *request,
1270 request->colon, 1966 request->colon,
1271 kind)) 1967 kind))
1272 { 1968 {
1273 transmit_error_response (connection, 1969 transmit_error_response (request,
1970 MHD_SC_CLIENT_HEADER_TOO_BIG,
1274 MHD_HTTP_REQUEST_HEADER_FIELDS_TOO_LARGE, 1971 MHD_HTTP_REQUEST_HEADER_FIELDS_TOO_LARGE,
1275 REQUEST_TOO_BIG); 1972 REQUEST_TOO_BIG);
1276 return false; 1973 return false;
@@ -1281,7 +1978,8 @@ process_broken_line (struct MHD_Request *request,
1281 if (! process_header_line (request, 1978 if (! process_header_line (request,
1282 line)) 1979 line))
1283 { 1980 {
1284 transmit_error_response (connection, 1981 transmit_error_response (request,
1982 MHD_SC_CONNECTION_PARSE_FAIL_CLOSED,
1285 MHD_HTTP_BAD_REQUEST, 1983 MHD_HTTP_BAD_REQUEST,
1286 REQUEST_MALFORMED); 1984 REQUEST_MALFORMED);
1287 return false; 1985 return false;
@@ -1291,7 +1989,782 @@ process_broken_line (struct MHD_Request *request,
1291} 1989}
1292 1990
1293 1991
1294#ifdef REWRITE_IN_PROGRESS 1992/**
1993 * Parse a single line of the HTTP header. Advance read_buffer (!)
1994 * appropriately. If the current line does not fit, consider growing
1995 * the buffer. If the line is far too long, close the connection. If
1996 * no line is found (incomplete, buffer too small, line too long),
1997 * return NULL. Otherwise return a pointer to the line.
1998 *
1999 * @param request request we're processing
2000 * @param[out] line_len pointer to variable that receive
2001 * length of line or NULL
2002 * @return NULL if no full line is available; note that the returned
2003 * string will not be 0-termianted
2004 */
2005static char *
2006get_next_header_line (struct MHD_Request *request,
2007 size_t *line_len)
2008{
2009 char *rbuf;
2010 size_t pos;
2011
2012 if (0 == request->read_buffer_offset)
2013 return NULL;
2014 pos = 0;
2015 rbuf = request->read_buffer;
2016 while ( (pos < request->read_buffer_offset - 1) &&
2017 ('\r' != rbuf[pos]) &&
2018 ('\n' != rbuf[pos]) )
2019 pos++;
2020 if ( (pos == request->read_buffer_offset - 1) &&
2021 ('\n' != rbuf[pos]) )
2022 {
2023 /* not found, consider growing... */
2024 if ( (request->read_buffer_offset == request->read_buffer_size) &&
2025 (! try_grow_read_buffer (request)) )
2026 {
2027 transmit_error_response (request,
2028 MHD_SC_CLIENT_HEADER_TOO_BIG,
2029 (NULL != request->url)
2030 ? MHD_HTTP_REQUEST_HEADER_FIELDS_TOO_LARGE
2031 : MHD_HTTP_URI_TOO_LONG,
2032 REQUEST_TOO_BIG);
2033 }
2034 if (line_len)
2035 *line_len = 0;
2036 return NULL;
2037 }
2038
2039 if (line_len)
2040 *line_len = pos;
2041 /* found, check if we have proper LFCR */
2042 if ( ('\r' == rbuf[pos]) &&
2043 ('\n' == rbuf[pos + 1]) )
2044 rbuf[pos++] = '\0'; /* skip both r and n */
2045 rbuf[pos++] = '\0';
2046 request->read_buffer += pos;
2047 request->read_buffer_size -= pos;
2048 request->read_buffer_offset -= pos;
2049 return rbuf;
2050}
2051
2052
2053/**
2054 * Check whether is possible to force push socket buffer content as
2055 * partial packet.
2056 * MHD use different buffering logic depending on whether flushing of
2057 * socket buffer is possible or not.
2058 * If flushing IS possible than MHD activates extra buffering before
2059 * sending data to prevent sending partial packets and flush pending
2060 * data in socket buffer to push last partial packet to client after
2061 * sending logical completed part of data (for example: after sending
2062 * full response header or full response message).
2063 * If flushing IS NOT possible than MHD activates no buffering (no
2064 * delay sending) when it going to send formed fully completed logical
2065 * part of data and activate normal buffering after sending.
2066 * For idled keep-alive connection MHD always activate normal
2067 * buffering.
2068 *
2069 * @param connection connection to check
2070 * @return true if force push is possible, false otherwise
2071 */
2072static bool
2073socket_flush_possible(struct MHD_Connection *connection)
2074{
2075 (void) connection; /* Mute compiler warning. */
2076#if defined(TCP_CORK) || defined(TCP_PUSH)
2077 return true;
2078#else /* !TCP_CORK && !TCP_PUSH */
2079 return false;
2080#endif /* !TCP_CORK && !TCP_PUSH */
2081}
2082
2083
2084/**
2085 * Activate extra buffering mode on connection socket to prevent
2086 * sending of partial packets.
2087 *
2088 * @param connection connection to be processed
2089 * @return true on success, false otherwise
2090 */
2091static bool
2092socket_start_extra_buffering (struct MHD_Connection *connection)
2093{
2094 bool res = false;
2095 (void)connection; /* Mute compiler warning. */
2096#if defined(TCP_CORK) || defined(TCP_NOPUSH)
2097 const MHD_SCKT_OPT_BOOL_ on_val = 1;
2098#if defined(TCP_NODELAY)
2099 const MHD_SCKT_OPT_BOOL_ off_val = 0;
2100#endif /* TCP_NODELAY */
2101 mhd_assert(NULL != connection);
2102#if defined(TCP_NOPUSH) && !defined(TCP_CORK)
2103 /* Buffer data before sending */
2104 res = (0 == setsockopt (connection->socket_fd,
2105 IPPROTO_TCP,
2106 TCP_NOPUSH,
2107 (const void *) &on_val,
2108 sizeof (on_val)))
2109 ? true : false;
2110#if defined(TCP_NODELAY)
2111 /* Enable Nagle's algorithm */
2112 /* TCP_NODELAY may interfere with TCP_NOPUSH */
2113 res &= (0 == setsockopt (connection->socket_fd,
2114 IPPROTO_TCP,
2115 TCP_NODELAY,
2116 (const void *) &off_val,
2117 sizeof (off_val)))
2118 ? true : false;
2119#endif /* TCP_NODELAY */
2120#else /* TCP_CORK */
2121#if defined(TCP_NODELAY)
2122 /* Enable Nagle's algorithm */
2123 /* TCP_NODELAY may prevent enabling TCP_CORK. Resulting buffering mode depends
2124 solely on TCP_CORK result, so ignoring return code here. */
2125 (void) setsockopt (connection->socket_fd,
2126 IPPROTO_TCP,
2127 TCP_NODELAY,
2128 (const void *) &off_val,
2129 sizeof (off_val));
2130#endif /* TCP_NODELAY */
2131 /* Send only full packets */
2132 res = (0 == setsockopt (connection->socket_fd,
2133 IPPROTO_TCP,
2134 TCP_CORK,
2135 (const void *) &on_val,
2136 sizeof (on_val)))
2137 ? true : false;
2138#endif /* TCP_CORK */
2139#endif /* TCP_CORK || TCP_NOPUSH */
2140 return res;
2141}
2142
2143
2144/**
2145 * Activate no buffering mode (no delay sending) on connection socket.
2146 *
2147 * @param connection connection to be processed
2148 * @return true on success, false otherwise
2149 */
2150static bool
2151socket_start_no_buffering (struct MHD_Connection *connection)
2152{
2153#if defined(TCP_NODELAY)
2154 bool res = true;
2155 const MHD_SCKT_OPT_BOOL_ on_val = 1;
2156#if defined(TCP_CORK) || defined(TCP_NOPUSH)
2157 const MHD_SCKT_OPT_BOOL_ off_val = 0;
2158#endif /* TCP_CORK || TCP_NOPUSH */
2159
2160 (void)connection; /* Mute compiler warning. */
2161 mhd_assert(NULL != connection);
2162#if defined(TCP_CORK)
2163 /* Allow partial packets */
2164 res &= (0 == setsockopt (connection->socket_fd,
2165 IPPROTO_TCP,
2166 TCP_CORK,
2167 (const void *) &off_val,
2168 sizeof (off_val)))
2169 ? true : false;
2170#endif /* TCP_CORK */
2171#if defined(TCP_NODELAY)
2172 /* Disable Nagle's algorithm for sending packets without delay */
2173 res &= (0 == setsockopt (connection->socket_fd,
2174 IPPROTO_TCP,
2175 TCP_NODELAY,
2176 (const void *) &on_val,
2177 sizeof (on_val)))
2178 ? true : false;
2179#endif /* TCP_NODELAY */
2180#if defined(TCP_NOPUSH) && !defined(TCP_CORK)
2181 /* Disable extra buffering */
2182 res &= (0 == setsockopt (connection->socket_fd,
2183 IPPROTO_TCP,
2184 TCP_NOPUSH,
2185 (const void *) &off_val,
2186 sizeof (off_val)))
2187 ? true : false;
2188#endif /* TCP_NOPUSH && !TCP_CORK */
2189 return res;
2190#else /* !TCP_NODELAY */
2191 return false;
2192#endif /* !TCP_NODELAY */
2193}
2194
2195
2196/**
2197 * Activate no buffering mode (no delay sending) on connection socket
2198 * and push to client data pending in socket buffer.
2199 *
2200 * @param connection connection to be processed
2201 * @return true on success, false otherwise
2202 */
2203static bool
2204socket_start_no_buffering_flush (struct MHD_Connection *connection)
2205{
2206 bool res = true;
2207#if defined(TCP_NOPUSH) && !defined(TCP_CORK)
2208 const int dummy = 0;
2209#endif /* !TCP_CORK */
2210
2211 if (NULL == connection)
2212 return false; /* FIXME: use MHD_NONNULL? */
2213 res = socket_start_no_buffering (connection);
2214#if defined(TCP_NOPUSH) && !defined(TCP_CORK)
2215 /* Force flush data with zero send otherwise Darwin and some BSD systems
2216 will add 5 seconds delay. Not required with TCP_CORK as switching off
2217 TCP_CORK always flushes socket buffer. */
2218 res &= (0 <= MHD_send_ (connection->socket_fd,
2219 &dummy,
2220 0))
2221 ? true : false;
2222#endif /* TCP_NOPUSH && !TCP_CORK*/
2223 return res;
2224}
2225
2226
2227/**
2228 * Activate normal buffering mode on connection socket.
2229 *
2230 * @param connection connection to be processed
2231 * @return true on success, false otherwise
2232 */
2233static bool
2234socket_start_normal_buffering (struct MHD_Connection *connection)
2235{
2236#if defined(TCP_NODELAY)
2237 bool res = true;
2238 const MHD_SCKT_OPT_BOOL_ off_val = 0;
2239#if defined(TCP_CORK)
2240 MHD_SCKT_OPT_BOOL_ cork_val = 0;
2241 socklen_t param_size = sizeof (cork_val);
2242#endif /* TCP_CORK */
2243
2244 mhd_assert(NULL != connection);
2245#if defined(TCP_CORK)
2246 /* Allow partial packets */
2247 /* Disabling TCP_CORK will flush partial packet even if TCP_CORK wasn't enabled before
2248 so try to check current value of TCP_CORK to prevent unrequested flushing */
2249 if ( (0 != getsockopt (connection->socket_fd,
2250 IPPROTO_TCP,
2251 TCP_CORK,
2252 (void*)&cork_val,
2253 &param_size)) ||
2254 (0 != cork_val))
2255 res &= (0 == setsockopt (connection->socket_fd,
2256 IPPROTO_TCP,
2257 TCP_CORK,
2258 (const void *) &off_val,
2259 sizeof (off_val)))
2260 ? true : false;
2261#elif defined(TCP_NOPUSH)
2262 /* Disable extra buffering */
2263 /* No need to check current value as disabling TCP_NOPUSH will not flush partial
2264 packet if TCP_NOPUSH wasn't enabled before */
2265 res &= (0 == setsockopt (connection->socket_fd,
2266 IPPROTO_TCP,
2267 TCP_NOPUSH,
2268 (const void *) &off_val,
2269 sizeof (off_val)))
2270 ? true : false;
2271#endif /* TCP_NOPUSH && !TCP_CORK */
2272 /* Enable Nagle's algorithm for normal buffering */
2273 res &= (0 == setsockopt (connection->socket_fd,
2274 IPPROTO_TCP,
2275 TCP_NODELAY,
2276 (const void *) &off_val,
2277 sizeof (off_val)))
2278 ? true : false;
2279 return res;
2280#else /* !TCP_NODELAY */
2281 return false;
2282#endif /* !TCP_NODELAY */
2283}
2284
2285
2286/**
2287 * Do we (still) need to send a 100 continue
2288 * message for this request?
2289 *
2290 * @param request the request to test
2291 * @return false if we don't need 100 CONTINUE, true if we do
2292 */
2293static bool
2294need_100_continue (struct MHD_Request *request)
2295{
2296 const char *expect;
2297
2298 return ( (NULL == request->response) &&
2299 (NULL != request->version_s) &&
2300 (MHD_str_equal_caseless_(request->version_s,
2301 MHD_HTTP_VERSION_1_1)) &&
2302 (NULL != (expect = MHD_request_lookup_value (request,
2303 MHD_HEADER_KIND,
2304 MHD_HTTP_HEADER_EXPECT))) &&
2305 (MHD_str_equal_caseless_(expect,
2306 "100-continue")) &&
2307 (request->continue_message_write_offset <
2308 MHD_STATICSTR_LEN_ (HTTP_100_CONTINUE)) );
2309}
2310
2311
2312/**
2313 * Parse the cookie header (see RFC 2109).
2314 *
2315 * @param request request to parse header of
2316 * @return true for success, false for failure (malformed, out of memory)
2317 */
2318static int
2319parse_cookie_header (struct MHD_Request *request)
2320{
2321 const char *hdr;
2322 char *cpy;
2323 char *pos;
2324 char *sce;
2325 char *semicolon;
2326 char *equals;
2327 char *ekill;
2328 char old;
2329 int quotes;
2330
2331 hdr = MHD_request_lookup_value (request,
2332 MHD_HEADER_KIND,
2333 MHD_HTTP_HEADER_COOKIE);
2334 if (NULL == hdr)
2335 return true;
2336 cpy = MHD_pool_allocate (request->connection->pool,
2337 strlen (hdr) + 1,
2338 MHD_YES);
2339 if (NULL == cpy)
2340 {
2341#ifdef HAVE_MESSAGES
2342 MHD_DLOG (request->daemon,
2343 MHD_SC_COOKIE_POOL_ALLOCATION_FAILURE,
2344 _("Not enough memory in pool to parse cookies!\n"));
2345#endif
2346 transmit_error_response (request,
2347 MHD_SC_COOKIE_POOL_ALLOCATION_FAILURE,
2348 MHD_HTTP_REQUEST_HEADER_FIELDS_TOO_LARGE,
2349 REQUEST_TOO_BIG);
2350 return false;
2351 }
2352 memcpy (cpy,
2353 hdr,
2354 strlen (hdr) + 1);
2355 pos = cpy;
2356 while (NULL != pos)
2357 {
2358 while (' ' == *pos)
2359 pos++; /* skip spaces */
2360
2361 sce = pos;
2362 while ( ((*sce) != '\0') &&
2363 ((*sce) != ',') &&
2364 ((*sce) != ';') &&
2365 ((*sce) != '=') )
2366 sce++;
2367 /* remove tailing whitespace (if any) from key */
2368 ekill = sce - 1;
2369 while ( (*ekill == ' ') &&
2370 (ekill >= pos) )
2371 *(ekill--) = '\0';
2372 old = *sce;
2373 *sce = '\0';
2374 if (old != '=')
2375 {
2376 /* value part omitted, use empty string... */
2377 if (! request_add_header (request,
2378 pos,
2379 "",
2380 MHD_COOKIE_KIND))
2381 return false;
2382 if (old == '\0')
2383 break;
2384 pos = sce + 1;
2385 continue;
2386 }
2387 equals = sce + 1;
2388 quotes = 0;
2389 semicolon = equals;
2390 while ( ('\0' != semicolon[0]) &&
2391 ( (0 != quotes) ||
2392 ( (';' != semicolon[0]) &&
2393 (',' != semicolon[0]) ) ) )
2394 {
2395 if ('"' == semicolon[0])
2396 quotes = (quotes + 1) & 1;
2397 semicolon++;
2398 }
2399 if ('\0' == semicolon[0])
2400 semicolon = NULL;
2401 if (NULL != semicolon)
2402 {
2403 semicolon[0] = '\0';
2404 semicolon++;
2405 }
2406 /* remove quotes */
2407 if ( ('"' == equals[0]) &&
2408 ('"' == equals[strlen (equals) - 1]) )
2409 {
2410 equals[strlen (equals) - 1] = '\0';
2411 equals++;
2412 }
2413 if (! request_add_header (request,
2414 pos,
2415 equals,
2416 MHD_COOKIE_KIND))
2417 return false;
2418 pos = semicolon;
2419 }
2420 return true;
2421}
2422
2423
2424/**
2425 * Parse the various headers; figure out the size
2426 * of the upload and make sure the headers follow
2427 * the protocol. Advance to the appropriate state.
2428 *
2429 * @param request request we're processing
2430 */
2431static void
2432parse_request_headers (struct MHD_Request *request)
2433{
2434 struct MHD_Daemon *daemon = request->daemon;
2435 struct MHD_Connection *connection = request->connection;
2436 const char *clen;
2437 struct MHD_Response *response;
2438 const char *enc;
2439 const char *end;
2440
2441 parse_cookie_header (request); /* FIXME: return value ignored! */
2442 if ( (MHD_PSL_STRICT == daemon->protocol_strict_level) &&
2443 (NULL != request->version_s) &&
2444 (MHD_str_equal_caseless_(MHD_HTTP_VERSION_1_1,
2445 request->version_s)) &&
2446 (NULL ==
2447 MHD_request_lookup_value (request,
2448 MHD_HEADER_KIND,
2449 MHD_HTTP_HEADER_HOST)) )
2450 {
2451 /* die, http 1.1 request without host and we are pedantic */
2452 request->state = MHD_REQUEST_FOOTERS_RECEIVED;
2453 connection->read_closed = true;
2454#ifdef HAVE_MESSAGES
2455 MHD_DLOG (daemon,
2456 MHD_SC_HOST_HEADER_MISSING,
2457 _("Received HTTP 1.1 request without `Host' header.\n"));
2458#endif
2459 mhd_assert (NULL == request->response);
2460 response =
2461 MHD_response_from_buffer (MHD_HTTP_BAD_REQUEST,
2462 MHD_STATICSTR_LEN_ (REQUEST_LACKS_HOST),
2463 REQUEST_LACKS_HOST,
2464 MHD_RESPMEM_PERSISTENT);
2465 request->response = response;
2466 // FIXME: state machine advance?
2467 return;
2468 }
2469
2470 request->remaining_upload_size = 0;
2471 enc = MHD_request_lookup_value (request,
2472 MHD_HEADER_KIND,
2473 MHD_HTTP_HEADER_TRANSFER_ENCODING);
2474 if (NULL != enc)
2475 {
2476 request->remaining_upload_size = MHD_SIZE_UNKNOWN;
2477 if (MHD_str_equal_caseless_ (enc,
2478 "chunked"))
2479 request->have_chunked_upload = true;
2480 return;
2481 }
2482 clen = MHD_request_lookup_value (request,
2483 MHD_HEADER_KIND,
2484 MHD_HTTP_HEADER_CONTENT_LENGTH);
2485 if (NULL == clen)
2486 return;
2487 end = clen + MHD_str_to_uint64_ (clen,
2488 &request->remaining_upload_size);
2489 if ( (clen == end) ||
2490 ('\0' != *end) )
2491 {
2492 request->remaining_upload_size = 0;
2493#ifdef HAVE_MESSAGES
2494 MHD_DLOG (request->daemon,
2495 MHD_SC_CONTENT_LENGTH_MALFORMED,
2496 "Failed to parse `Content-Length' header. Closing connection.\n");
2497#endif
2498 CONNECTION_CLOSE_ERROR (connection,
2499 MHD_SC_CONTENT_LENGTH_MALFORMED,
2500 NULL);
2501 }
2502}
2503
2504
2505/**
2506 * Call the handler of the application for this
2507 * request.
2508 *
2509 * @param request request we're processing
2510 */
2511static void
2512call_request_handler (struct MHD_Request *request)
2513{
2514 struct MHD_Daemon *daemon = request->daemon;
2515 struct MHD_Connection *connection = request->connection;
2516 const struct MHD_Action *action;
2517
2518 if (NULL != request->response)
2519 return; /* already queued a response */
2520 if (NULL == (action =
2521 daemon->rc (daemon->rc_cls,
2522 request,
2523 request->url,
2524 request->method)))
2525 {
2526 /* serious internal error, close connection */
2527 CONNECTION_CLOSE_ERROR (connection,
2528 MHD_SC_APPLICATION_CALLBACK_FAILURE_CLOSED,
2529 _("Application reported internal error, closing connection.\n"));
2530 return;
2531 }
2532 action->action (action->action_cls,
2533 request);
2534}
2535
2536
2537/**
2538 * Call the handler of the application for this request. Handles
2539 * chunking of the upload as well as normal uploads.
2540 *
2541 * @param request request we're processing
2542 */
2543static void
2544process_request_body (struct MHD_Request *request)
2545{
2546 struct MHD_Daemon *daemon = request->daemon;
2547 struct MHD_Connection *connection = request->connection;
2548 size_t available;
2549 bool instant_retry;
2550 char *buffer_head;
2551
2552 if (NULL != request->response)
2553 return; /* already queued a response */
2554
2555 buffer_head = request->read_buffer;
2556 available = request->read_buffer_offset;
2557 do
2558 {
2559 size_t to_be_processed;
2560 size_t left_unprocessed;
2561 size_t processed_size;
2562
2563 instant_retry = false;
2564 if ( (request->have_chunked_upload) &&
2565 (MHD_SIZE_UNKNOWN == request->remaining_upload_size) )
2566 {
2567 if ( (request->current_chunk_offset == request->current_chunk_size) &&
2568 (0LLU != request->current_chunk_offset) &&
2569 (available >= 2) )
2570 {
2571 size_t i;
2572
2573 /* skip new line at the *end* of a chunk */
2574 i = 0;
2575 if ( ('\r' == buffer_head[i]) ||
2576 ('\n' == buffer_head[i]) )
2577 i++; /* skip 1st part of line feed */
2578 if ( ('\r' == buffer_head[i]) ||
2579 ('\n' == buffer_head[i]) )
2580 i++; /* skip 2nd part of line feed */
2581 if (0 == i)
2582 {
2583 /* malformed encoding */
2584 CONNECTION_CLOSE_ERROR (connection,
2585 MHD_SC_CHUNKED_ENCODING_MALFORMED,
2586 _("Received malformed HTTP request (bad chunked encoding). Closing connection.\n"));
2587 return;
2588 }
2589 available -= i;
2590 buffer_head += i;
2591 request->current_chunk_offset = 0;
2592 request->current_chunk_size = 0;
2593 }
2594 if (request->current_chunk_offset <
2595 request->current_chunk_size)
2596 {
2597 uint64_t cur_chunk_left;
2598
2599 /* we are in the middle of a chunk, give
2600 as much as possible to the client (without
2601 crossing chunk boundaries) */
2602 cur_chunk_left
2603 = request->current_chunk_size - request->current_chunk_offset;
2604 if (cur_chunk_left > available)
2605 {
2606 to_be_processed = available;
2607 }
2608 else
2609 { /* cur_chunk_left <= (size_t)available */
2610 to_be_processed = (size_t)cur_chunk_left;
2611 if (available > to_be_processed)
2612 instant_retry = true;
2613 }
2614 }
2615 else
2616 {
2617 size_t i;
2618 size_t end_size;
2619 bool malformed;
2620
2621 /* we need to read chunk boundaries */
2622 i = 0;
2623 while (i < available)
2624 {
2625 if ( ('\r' == buffer_head[i]) ||
2626 ('\n' == buffer_head[i]) ||
2627 (';' == buffer_head[i]) )
2628 break;
2629 i++;
2630 if (i >= 16)
2631 break;
2632 }
2633 end_size = i;
2634 /* find beginning of CRLF (skip over chunk extensions) */
2635 if (';' == buffer_head[i])
2636 {
2637 while (i < available)
2638 {
2639 if ( ('\r' == buffer_head[i]) ||
2640 ('\n' == buffer_head[i]) )
2641 break;
2642 i++;
2643 }
2644 }
2645 /* take '\n' into account; if '\n' is the unavailable
2646 character, we will need to wait until we have it
2647 before going further */
2648 if ( (i + 1 >= available) &&
2649 ! ( (1 == i) &&
2650 (2 == available) &&
2651 ('0' == buffer_head[0]) ) )
2652 break; /* need more data... */
2653 i++;
2654 malformed = (end_size >= 16);
2655 if (! malformed)
2656 {
2657 size_t num_dig = MHD_strx_to_uint64_n_ (buffer_head,
2658 end_size,
2659 &request->current_chunk_size);
2660 malformed = (end_size != num_dig);
2661 }
2662 if (malformed)
2663 {
2664 /* malformed encoding */
2665 CONNECTION_CLOSE_ERROR (connection,
2666 MHD_SC_CHUNKED_ENCODING_MALFORMED,
2667 _("Received malformed HTTP request (bad chunked encoding). Closing connection.\n"));
2668 return;
2669 }
2670 /* skip 2nd part of line feed */
2671 if ( (i < available) &&
2672 ( ('\r' == buffer_head[i]) ||
2673 ('\n' == buffer_head[i]) ) )
2674 i++;
2675
2676 buffer_head += i;
2677 available -= i;
2678 request->current_chunk_offset = 0;
2679
2680 if (available > 0)
2681 instant_retry = true;
2682 if (0LLU == request->current_chunk_size)
2683 {
2684 request->remaining_upload_size = 0;
2685 break;
2686 }
2687 continue;
2688 }
2689 }
2690 else
2691 {
2692 /* no chunked encoding, give all to the client */
2693 if ( (0 != request->remaining_upload_size) &&
2694 (MHD_SIZE_UNKNOWN != request->remaining_upload_size) &&
2695 (request->remaining_upload_size < available) )
2696 {
2697 to_be_processed = (size_t)request->remaining_upload_size;
2698 }
2699 else
2700 {
2701 /**
2702 * 1. no chunked encoding, give all to the client
2703 * 2. client may send large chunked data, but only a smaller part is available at one time.
2704 */
2705 to_be_processed = available;
2706 }
2707 }
2708 left_unprocessed = to_be_processed;
2709#if FIXME_OLD_STYLE
2710 if (MHD_NO ==
2711 daemon->rc (daemon->rc_cls,
2712 request,
2713 request->url,
2714 request->method,
2715 request->version,
2716 buffer_head,
2717 &left_unprocessed,
2718 &request->client_context))
2719 {
2720 /* serious internal error, close connection */
2721 CONNECTION_CLOSE_ERROR (connection,
2722 MHD_SC_APPLICATION_CALLBACK_FAILURE_CLOSED,
2723 _("Application reported internal error, closing connection.\n"));
2724 return;
2725 }
2726#endif
2727 if (left_unprocessed > to_be_processed)
2728 mhd_panic (mhd_panic_cls,
2729 __FILE__,
2730 __LINE__
2731#ifdef HAVE_MESSAGES
2732 , _("libmicrohttpd API violation")
2733#else
2734 , NULL
2735#endif
2736 );
2737 if (0 != left_unprocessed)
2738 {
2739 instant_retry = false; /* client did not process everything */
2740#ifdef HAVE_MESSAGES
2741 /* client did not process all upload data, complain if
2742 the setup was incorrect, which may prevent us from
2743 handling the rest of the request */
2744 if ( (MHD_TM_EXTERNAL_EVENT_LOOP == daemon->threading_model) &&
2745 (! connection->suspended) )
2746 MHD_DLOG (daemon,
2747 MHD_SC_APPLICATION_HUNG_CONNECTION,
2748 _("WARNING: incomplete upload processing and connection not suspended may result in hung connection.\n"));
2749#endif
2750 }
2751 processed_size = to_be_processed - left_unprocessed;
2752 if (request->have_chunked_upload)
2753 request->current_chunk_offset += processed_size;
2754 /* dh left "processed" bytes in buffer for next time... */
2755 buffer_head += processed_size;
2756 available -= processed_size;
2757 if (MHD_SIZE_UNKNOWN != request->remaining_upload_size)
2758 request->remaining_upload_size -= processed_size;
2759 }
2760 while (instant_retry);
2761 if (available > 0)
2762 memmove (request->read_buffer,
2763 buffer_head,
2764 available);
2765 request->read_buffer_offset = available;
2766}
2767
1295 2768
1296/** 2769/**
1297 * This function was created to handle per-request processing that 2770 * This function was created to handle per-request processing that
@@ -1304,13 +2777,13 @@ process_broken_line (struct MHD_Request *request,
1304 * request (not dead yet), false if it died 2777 * request (not dead yet), false if it died
1305 */ 2778 */
1306bool 2779bool
1307MHD_request_handle_idle (struct MHD_Request *request) 2780MHD_request_handle_idle_ (struct MHD_Request *request)
1308{ 2781{
1309 struct MHD_Daemon *daemon = request->daemon; 2782 struct MHD_Daemon *daemon = request->daemon;
1310 struct MHD_Connection *connection = request->connection; 2783 struct MHD_Connection *connection = request->connection;
1311 char *line; 2784 char *line;
1312 size_t line_len; 2785 size_t line_len;
1313 int ret; 2786 bool ret;
1314 2787
1315 request->in_idle = true; 2788 request->in_idle = true;
1316 while (! connection->suspended) 2789 while (! connection->suspended)
@@ -1358,6 +2831,7 @@ MHD_request_handle_idle (struct MHD_Request *request)
1358 line, 2831 line,
1359 line_len)) 2832 line_len))
1360 CONNECTION_CLOSE_ERROR (connection, 2833 CONNECTION_CLOSE_ERROR (connection,
2834 MHD_SC_CONNECTION_CLOSED,
1361 NULL); 2835 NULL);
1362 else 2836 else
1363 request->state = MHD_REQUEST_URL_RECEIVED; 2837 request->state = MHD_REQUEST_URL_RECEIVED;
@@ -1387,7 +2861,8 @@ MHD_request_handle_idle (struct MHD_Request *request)
1387 if (! process_header_line (request, 2861 if (! process_header_line (request,
1388 line)) 2862 line))
1389 { 2863 {
1390 transmit_error_response (connection, 2864 transmit_error_response (request,
2865 MHD_SC_CONNECTION_PARSE_FAIL_CLOSED,
1391 MHD_HTTP_BAD_REQUEST, 2866 MHD_HTTP_BAD_REQUEST,
1392 REQUEST_MALFORMED); 2867 REQUEST_MALFORMED);
1393 break; 2868 break;
@@ -1444,10 +2919,8 @@ MHD_request_handle_idle (struct MHD_Request *request)
1444 break; 2919 break;
1445 } 2920 }
1446 if ( (NULL != request->response) && 2921 if ( (NULL != request->response) &&
1447 ( (MHD_str_equal_caseless_ (request->method, 2922 ( (MHD_METHOD_POST == request->method) ||
1448 MHD_HTTP_METHOD_POST)) || 2923 (MHD_METHOD_PUT == request->method) ) )
1449 (MHD_str_equal_caseless_ (request->method,
1450 MHD_HTTP_METHOD_PUT))) )
1451 { 2924 {
1452 /* we refused (no upload allowed!) */ 2925 /* we refused (no upload allowed!) */
1453 request->remaining_upload_size = 0; 2926 request->remaining_upload_size = 0;
@@ -1455,7 +2928,8 @@ MHD_request_handle_idle (struct MHD_Request *request)
1455 connection->read_closed = true; 2928 connection->read_closed = true;
1456 } 2929 }
1457 request->state = (0 == request->remaining_upload_size) 2930 request->state = (0 == request->remaining_upload_size)
1458 ? MHD_REQUEST_FOOTERS_RECEIVED : MHD_REQUEST_CONTINUE_SENT; 2931 ? MHD_REQUEST_FOOTERS_RECEIVED
2932 : MHD_REQUEST_CONTINUE_SENT;
1459 if (connection->suspended) 2933 if (connection->suspended)
1460 break; 2934 break;
1461 continue; 2935 continue;
@@ -1464,11 +2938,10 @@ MHD_request_handle_idle (struct MHD_Request *request)
1464 MHD_STATICSTR_LEN_ (HTTP_100_CONTINUE)) 2938 MHD_STATICSTR_LEN_ (HTTP_100_CONTINUE))
1465 { 2939 {
1466 request->state = MHD_REQUEST_CONTINUE_SENT; 2940 request->state = MHD_REQUEST_CONTINUE_SENT;
1467 if (MHD_NO != socket_flush_possible (request)) 2941 if (! socket_flush_possible (connection))
1468 socket_start_no_buffering_flush (request); 2942 socket_start_no_buffering_flush (connection);
1469 else 2943 else
1470 socket_start_normal_buffering (request); 2944 socket_start_normal_buffering (connection);
1471
1472 continue; 2945 continue;
1473 } 2946 }
1474 break; 2947 break;
@@ -1482,10 +2955,10 @@ MHD_request_handle_idle (struct MHD_Request *request)
1482 if ( (0 == request->remaining_upload_size) || 2955 if ( (0 == request->remaining_upload_size) ||
1483 ( (MHD_SIZE_UNKNOWN == request->remaining_upload_size) && 2956 ( (MHD_SIZE_UNKNOWN == request->remaining_upload_size) &&
1484 (0 == request->read_buffer_offset) && 2957 (0 == request->read_buffer_offset) &&
1485 (request->read_closed) ) ) 2958 (connection->read_closed) ) )
1486 { 2959 {
1487 if ( (request->have_chunked_upload) && 2960 if ( (request->have_chunked_upload) &&
1488 (! request->read_closed) ) 2961 (! connection->read_closed) )
1489 request->state = MHD_REQUEST_BODY_RECEIVED; 2962 request->state = MHD_REQUEST_BODY_RECEIVED;
1490 else 2963 else
1491 request->state = MHD_REQUEST_FOOTERS_RECEIVED; 2964 request->state = MHD_REQUEST_FOOTERS_RECEIVED;
@@ -1504,6 +2977,7 @@ MHD_request_handle_idle (struct MHD_Request *request)
1504 if (connection->read_closed) 2977 if (connection->read_closed)
1505 { 2978 {
1506 CONNECTION_CLOSE_ERROR (connection, 2979 CONNECTION_CLOSE_ERROR (connection,
2980 MHD_SC_CONNECTION_CLOSED,
1507 NULL); 2981 NULL);
1508 continue; 2982 continue;
1509 } 2983 }
@@ -1519,7 +2993,8 @@ MHD_request_handle_idle (struct MHD_Request *request)
1519 if (MHD_NO == process_header_line (request, 2993 if (MHD_NO == process_header_line (request,
1520 line)) 2994 line))
1521 { 2995 {
1522 transmit_error_response (connection, 2996 transmit_error_response (request,
2997 MHD_SC_CONNECTION_PARSE_FAIL_CLOSED,
1523 MHD_HTTP_BAD_REQUEST, 2998 MHD_HTTP_BAD_REQUEST,
1524 REQUEST_MALFORMED); 2999 REQUEST_MALFORMED);
1525 break; 3000 break;
@@ -1536,6 +3011,7 @@ MHD_request_handle_idle (struct MHD_Request *request)
1536 if (connection->read_closed) 3011 if (connection->read_closed)
1537 { 3012 {
1538 CONNECTION_CLOSE_ERROR (connection, 3013 CONNECTION_CLOSE_ERROR (connection,
3014 MHD_SC_CONNECTION_CLOSED,
1539 NULL); 3015 NULL);
1540 continue; 3016 continue;
1541 } 3017 }
@@ -1560,10 +3036,11 @@ MHD_request_handle_idle (struct MHD_Request *request)
1560 continue; 3036 continue;
1561 if (NULL == request->response) 3037 if (NULL == request->response)
1562 break; /* try again next time */ 3038 break; /* try again next time */
1563 if (MHD_NO == build_header_response (request)) 3039 if (! build_header_response (request))
1564 { 3040 {
1565 /* oops - close! */ 3041 /* oops - close! */
1566 CONNECTION_CLOSE_ERROR (connection, 3042 CONNECTION_CLOSE_ERROR (connection,
3043 MHD_SC_FAILED_RESPONSE_HEADER_GENERATION,
1567 _("Closing connection (failed to create response header)\n")); 3044 _("Closing connection (failed to create response header)\n"));
1568 continue; 3045 continue;
1569 } 3046 }
@@ -1588,12 +3065,12 @@ MHD_request_handle_idle (struct MHD_Request *request)
1588 socket_start_normal_buffering (connection); 3065 socket_start_normal_buffering (connection);
1589 request->state = MHD_REQUEST_UPGRADE; 3066 request->state = MHD_REQUEST_UPGRADE;
1590 /* This request is "upgraded". Pass socket to application. */ 3067 /* This request is "upgraded". Pass socket to application. */
1591 if (MHD_YES != 3068 if (! MHD_response_execute_upgrade_ (request->response,
1592 MHD_response_execute_upgrade_ (request->response, 3069 request))
1593 request))
1594 { 3070 {
1595 /* upgrade failed, fail hard */ 3071 /* upgrade failed, fail hard */
1596 CONNECTION_CLOSE_ERROR (connection, 3072 CONNECTION_CLOSE_ERROR (connection,
3073 MHD_SC_CONNECTION_CLOSED,
1597 NULL); 3074 NULL);
1598 continue; 3075 continue;
1599 } 3076 }
@@ -1602,7 +3079,7 @@ MHD_request_handle_idle (struct MHD_Request *request)
1602 { 3079 {
1603 struct MHD_Response * const resp = request->response; 3080 struct MHD_Response * const resp = request->response;
1604 request->response = NULL; 3081 request->response = NULL;
1605 MHD_destroy_response (resp); 3082 MHD_response_queue_for_destroy (resp);
1606 } 3083 }
1607 continue; 3084 continue;
1608 } 3085 }
@@ -1671,10 +3148,11 @@ MHD_request_handle_idle (struct MHD_Request *request)
1671 /* mutex was already unlocked by try_ready_chunked_body */ 3148 /* mutex was already unlocked by try_ready_chunked_body */
1672 break; 3149 break;
1673 case MHD_REQUEST_BODY_SENT: 3150 case MHD_REQUEST_BODY_SENT:
1674 if (MHD_NO == build_header_response (request)) 3151 if (! build_header_response (request))
1675 { 3152 {
1676 /* oops - close! */ 3153 /* oops - close! */
1677 CONNECTION_CLOSE_ERROR (connection, 3154 CONNECTION_CLOSE_ERROR (connection,
3155 MHD_SC_FAILED_RESPONSE_HEADER_GENERATION,
1678 _("Closing connection (failed to create response header)\n")); 3156 _("Closing connection (failed to create response header)\n"));
1679 continue; 3157 continue;
1680 } 3158 }
@@ -1689,32 +3167,33 @@ MHD_request_handle_idle (struct MHD_Request *request)
1689 /* no default action */ 3167 /* no default action */
1690 break; 3168 break;
1691 case MHD_REQUEST_FOOTERS_SENT: 3169 case MHD_REQUEST_FOOTERS_SENT:
1692 if (MHD_HTTP_PROCESSING == request->responseCode)
1693 { 3170 {
1694 /* After this type of response, we allow sending another! */ 3171 struct MHD_Response *response = request->response;
1695 request->state = MHD_REQUEST_HEADERS_PROCESSED; 3172
1696 MHD_destroy_response (request->response); 3173 if (MHD_HTTP_PROCESSING == response->status_code)
3174 {
3175 /* After this type of response, we allow sending another! */
3176 request->state = MHD_REQUEST_HEADERS_PROCESSED;
3177 MHD_response_queue_for_destroy (response);
3178 request->response = NULL;
3179 /* FIXME: maybe partially reset memory pool? */
3180 continue;
3181 }
3182 if (socket_flush_possible (connection))
3183 socket_start_no_buffering_flush (connection);
3184 else
3185 socket_start_normal_buffering (connection);
3186
3187 if (NULL != response->termination_cb)
3188 {
3189 response->termination_cb (response->termination_cb_cls,
3190 MHD_REQUEST_TERMINATED_COMPLETED_OK,
3191 request->client_context);
3192 }
3193 MHD_response_queue_for_destroy (response);
1697 request->response = NULL; 3194 request->response = NULL;
1698 /* FIXME: maybe partially reset memory pool? */
1699 continue;
1700 } 3195 }
1701 if (MHD_NO != socket_flush_possible (connection)) 3196 if ( (MHD_CONN_USE_KEEPALIVE != request->keepalive) ||
1702 socket_start_no_buffering_flush (connection);
1703 else
1704 socket_start_normal_buffering (connection);
1705
1706 MHD_destroy_response (request->response);
1707 connection->response = NULL;
1708 if ( (NULL != daemon->notify_completed) &&
1709 (connection->client_aware) )
1710 {
1711 connection->client_aware = false;
1712 daemon->notify_completed (daemon->notify_completed_cls,
1713 connection,
1714 &connection->client_context,
1715 MHD_REQUEST_TERMINATED_COMPLETED_OK);
1716 }
1717 if ( (MHD_CONN_USE_KEEPALIVE != request->keepalive) ||
1718 (connection->read_closed) ) 3197 (connection->read_closed) )
1719 { 3198 {
1720 /* have to close for some reason */ 3199 /* have to close for some reason */
@@ -1729,9 +3208,9 @@ MHD_request_handle_idle (struct MHD_Request *request)
1729 else 3208 else
1730 { 3209 {
1731 /* can try to keep-alive */ 3210 /* can try to keep-alive */
1732 if (MHD_NO != socket_flush_possible (connection)) 3211 if (socket_flush_possible (connection))
1733 socket_start_normal_buffering (connection); 3212 socket_start_normal_buffering (connection);
1734 request->version = NULL; 3213 request->version_s = NULL;
1735 request->state = MHD_REQUEST_INIT; 3214 request->state = MHD_REQUEST_INIT;
1736 request->last = NULL; 3215 request->last = NULL;
1737 request->colon = NULL; 3216 request->colon = NULL;
@@ -1743,10 +3222,12 @@ MHD_request_handle_idle (struct MHD_Request *request)
1743 = MHD_pool_reset (connection->pool, 3222 = MHD_pool_reset (connection->pool,
1744 request->read_buffer, 3223 request->read_buffer,
1745 request->read_buffer_offset, 3224 request->read_buffer_offset,
1746 daemon->pool_size / 2); 3225 daemon->connection_memory_limit_b / 2);
1747 request->read_buffer_size 3226 request->read_buffer_size
1748 = daemon->pool_size / 2; 3227 = daemon->connection_memory_limit_b / 2;
1749 } 3228 }
3229 // FIXME: this is too much, NULLs out some of the things
3230 // initialized above...
1750 memset (&request, 3231 memset (&request,
1751 0, 3232 0,
1752 sizeof (struct MHD_Request)); 3233 sizeof (struct MHD_Request));
@@ -1756,11 +3237,11 @@ MHD_request_handle_idle (struct MHD_Request *request)
1756 case MHD_REQUEST_CLOSED: 3237 case MHD_REQUEST_CLOSED:
1757 cleanup_connection (connection); 3238 cleanup_connection (connection);
1758 request->in_idle = false; 3239 request->in_idle = false;
1759 return MHD_NO; 3240 return false;
1760#ifdef UPGRADE_SUPPORT 3241#ifdef UPGRADE_SUPPORT
1761 case MHD_REQUEST_UPGRADE: 3242 case MHD_REQUEST_UPGRADE:
1762 request->in_idle = false; 3243 request->in_idle = false;
1763 return MHD_YES; /* keep open */ 3244 return true; /* keep open */
1764#endif /* UPGRADE_SUPPORT */ 3245#endif /* UPGRADE_SUPPORT */
1765 default: 3246 default:
1766 mhd_assert (0); 3247 mhd_assert (0);
@@ -1778,14 +3259,14 @@ MHD_request_handle_idle (struct MHD_Request *request)
1778 MHD_connection_close_ (connection, 3259 MHD_connection_close_ (connection,
1779 MHD_REQUEST_TERMINATED_TIMEOUT_REACHED); 3260 MHD_REQUEST_TERMINATED_TIMEOUT_REACHED);
1780 request->in_idle = false; 3261 request->in_idle = false;
1781 return MHD_YES; 3262 return true;
1782 } 3263 }
1783 } 3264 }
1784 MHD_connection_update_event_loop_info (connection); 3265 MHD_connection_update_event_loop_info (connection);
1785 ret = MHD_YES; 3266 ret = true;
1786#ifdef EPOLL_SUPPORT 3267#ifdef EPOLL_SUPPORT
1787 if ( (! connection->suspended) && 3268 if ( (! connection->suspended) &&
1788 (0 != (daemon->options & MHD_USE_EPOLL)) ) 3269 (MHD_ELS_EPOLL == daemon->event_loop_syscall) )
1789 { 3270 {
1790 ret = MHD_connection_epoll_update_ (connection); 3271 ret = MHD_connection_epoll_update_ (connection);
1791 } 3272 }
@@ -1794,9 +3275,6 @@ MHD_request_handle_idle (struct MHD_Request *request)
1794 return ret; 3275 return ret;
1795} 3276}
1796 3277
1797// rewrite commented out
1798#endif
1799
1800 3278
1801/** 3279/**
1802 * Call the handlers for a connection in the appropriate order based 3280 * Call the handlers for a connection in the appropriate order based
@@ -1835,7 +3313,7 @@ MHD_connection_call_handlers_ (struct MHD_Connection *con,
1835 read_ready) 3313 read_ready)
1836 { 3314 {
1837 MHD_request_handle_read_ (&con->request); 3315 MHD_request_handle_read_ (&con->request);
1838 ret = MHD_connection_handle_idle (con); 3316 ret = MHD_request_handle_idle_ (&con->request);
1839 states_info_processed = true; 3317 states_info_processed = true;
1840 } 3318 }
1841 /* No need to check value of 'ret' here as closed connection 3319 /* No need to check value of 'ret' here as closed connection
@@ -1845,7 +3323,7 @@ MHD_connection_call_handlers_ (struct MHD_Connection *con,
1845 write_ready) 3323 write_ready)
1846 { 3324 {
1847 MHD_request_handle_write_ (&con->request); 3325 MHD_request_handle_write_ (&con->request);
1848 ret = MHD_connection_handle_idle (con); 3326 ret = MHD_request_handle_idle_ (&con->request);
1849 states_info_processed = true; 3327 states_info_processed = true;
1850 } 3328 }
1851 } 3329 }
@@ -1853,17 +3331,17 @@ MHD_connection_call_handlers_ (struct MHD_Connection *con,
1853 { 3331 {
1854 MHD_connection_close_ (con, 3332 MHD_connection_close_ (con,
1855 MHD_REQUEST_TERMINATED_WITH_ERROR); 3333 MHD_REQUEST_TERMINATED_WITH_ERROR);
1856 return MHD_connection_handle_idle (con); 3334 return MHD_request_handle_idle_ (&con->request);
1857 } 3335 }
1858 3336
1859 if (! states_info_processed) 3337 if (! states_info_processed)
1860 { /* Connection is not read or write ready, but external conditions 3338 { /* Connection is not read or write ready, but external conditions
1861 * may be changed and need to be processed. */ 3339 * may be changed and need to be processed. */
1862 ret = MHD_connection_handle_idle (con); 3340 ret = MHD_request_handle_idle_ (&con->request);
1863 } 3341 }
1864 /* Fast track for fast connections. */ 3342 /* Fast track for fast connections. */
1865 /* If full request was read by single read_handler() invocation 3343 /* If full request was read by single read_handler() invocation
1866 and headers were completely prepared by single MHD_connection_handle_idle() 3344 and headers were completely prepared by single MHD_request_handle_idle_()
1867 then try not to wait for next sockets polling and send response 3345 then try not to wait for next sockets polling and send response
1868 immediately. 3346 immediately.
1869 As writeability of socket was not checked and it may have 3347 As writeability of socket was not checked and it may have
@@ -1877,17 +3355,17 @@ MHD_connection_call_handlers_ (struct MHD_Connection *con,
1877 if (MHD_REQUEST_HEADERS_SENDING == con->request.state) 3355 if (MHD_REQUEST_HEADERS_SENDING == con->request.state)
1878 { 3356 {
1879 MHD_request_handle_write_ (&con->request); 3357 MHD_request_handle_write_ (&con->request);
1880 /* Always call 'MHD_connection_handle_idle()' after each read/write. */ 3358 /* Always call 'MHD_request_handle_idle_()' after each read/write. */
1881 ret = MHD_connection_handle_idle (con); 3359 ret = MHD_request_handle_idle_ (&con->request);
1882 } 3360 }
1883 /* If all headers were sent by single write_handler() and 3361 /* If all headers were sent by single write_handler() and
1884 * response body is prepared by single MHD_connection_handle_idle() 3362 * response body is prepared by single MHD_request_handle_idle_()
1885 * call - continue. */ 3363 * call - continue. */
1886 if ((MHD_REQUEST_NORMAL_BODY_READY == con->request.state) || 3364 if ((MHD_REQUEST_NORMAL_BODY_READY == con->request.state) ||
1887 (MHD_REQUEST_CHUNKED_BODY_READY == con->request.state)) 3365 (MHD_REQUEST_CHUNKED_BODY_READY == con->request.state))
1888 { 3366 {
1889 MHD_request_handle_write_ (&con->request); 3367 MHD_request_handle_write_ (&con->request);
1890 ret = MHD_connection_handle_idle (con); 3368 ret = MHD_request_handle_idle_ (&con->request);
1891 } 3369 }
1892 } 3370 }
1893 3371
diff --git a/src/lib/connection_close.c b/src/lib/connection_close.c
index 39045e9f..ad15ce7a 100644
--- a/src/lib/connection_close.c
+++ b/src/lib/connection_close.c
@@ -93,12 +93,10 @@ MHD_connection_close_ (struct MHD_Connection *connection,
93 connection->request.response = NULL; 93 connection->request.response = NULL;
94 MHD_response_queue_for_destroy (resp); 94 MHD_response_queue_for_destroy (resp);
95 } 95 }
96 if ( (NULL != daemon->notify_connection_cb) && 96 if (NULL != daemon->notify_connection_cb)
97 (connection->client_aware) )
98 daemon->notify_connection_cb (daemon->notify_connection_cb_cls, 97 daemon->notify_connection_cb (daemon->notify_connection_cb_cls,
99 connection, 98 connection,
100 cnc); 99 cnc);
101 connection->client_aware = false;
102} 100}
103 101
104/* end of connection_close.c */ 102/* end of connection_close.c */
diff --git a/src/lib/internal.c b/src/lib/internal.c
index ea7600c3..75eae8a4 100644
--- a/src/lib/internal.c
+++ b/src/lib/internal.c
@@ -178,11 +178,11 @@ MHD_http_unescape (char *val)
178 * clobbered in the process! 178 * clobbered in the process!
179 * @param cb function to call on each key-value pair found 179 * @param cb function to call on each key-value pair found
180 * @param[out] num_headers set to the number of headers found 180 * @param[out] num_headers set to the number of headers found
181 * @return #MHD_NO on failure (@a cb returned #MHD_NO), 181 * @return false on failure (@a cb returned false),
182 * #MHD_YES for success (parsing succeeded, @a cb always 182 * true for success (parsing succeeded, @a cb always
183 * returned #MHD_YES) 183 * returned true)
184 */ 184 */
185int 185bool
186MHD_parse_arguments_ (struct MHD_Request *request, 186MHD_parse_arguments_ (struct MHD_Request *request,
187 enum MHD_ValueKind kind, 187 enum MHD_ValueKind kind,
188 char *args, 188 char *args,
@@ -209,11 +209,11 @@ MHD_parse_arguments_ (struct MHD_Request *request,
209 daemon->unescape_cb (daemon->unescape_cb_cls, 209 daemon->unescape_cb (daemon->unescape_cb_cls,
210 request, 210 request,
211 args); 211 args);
212 if (MHD_YES != cb (request, 212 if (! cb (request,
213 args, 213 args,
214 NULL, 214 NULL,
215 kind)) 215 kind))
216 return MHD_NO; 216 return false;
217 (*num_headers)++; 217 (*num_headers)++;
218 break; 218 break;
219 } 219 }
@@ -228,11 +228,11 @@ MHD_parse_arguments_ (struct MHD_Request *request,
228 daemon->unescape_cb (daemon->unescape_cb_cls, 228 daemon->unescape_cb (daemon->unescape_cb_cls,
229 request, 229 request,
230 equals); 230 equals);
231 if (MHD_YES != cb (request, 231 if (! cb (request,
232 args, 232 args,
233 equals, 233 equals,
234 kind)) 234 kind))
235 return MHD_NO; 235 return false;
236 (*num_headers)++; 236 (*num_headers)++;
237 break; 237 break;
238 } 238 }
@@ -247,11 +247,11 @@ MHD_parse_arguments_ (struct MHD_Request *request,
247 daemon->unescape_cb (daemon->unescape_cb_cls, 247 daemon->unescape_cb (daemon->unescape_cb_cls,
248 request, 248 request,
249 args); 249 args);
250 if (MHD_YES != cb (request, 250 if (! cb (request,
251 args, 251 args,
252 NULL, 252 NULL,
253 kind)) 253 kind))
254 return MHD_NO; 254 return false;
255 /* continue with 'bar' */ 255 /* continue with 'bar' */
256 (*num_headers)++; 256 (*num_headers)++;
257 args = amper; 257 args = amper;
@@ -269,15 +269,15 @@ MHD_parse_arguments_ (struct MHD_Request *request,
269 daemon->unescape_cb (daemon->unescape_cb_cls, 269 daemon->unescape_cb (daemon->unescape_cb_cls,
270 request, 270 request,
271 equals); 271 equals);
272 if (MHD_YES != cb (request, 272 if (! cb (request,
273 args, 273 args,
274 equals, 274 equals,
275 kind)) 275 kind))
276 return MHD_NO; 276 return false;
277 (*num_headers)++; 277 (*num_headers)++;
278 args = amper; 278 args = amper;
279 } 279 }
280 return MHD_YES; 280 return true;
281} 281}
282 282
283/* end of internal.c */ 283/* end of internal.c */
diff --git a/src/lib/internal.h b/src/lib/internal.h
index b4c471dd..c90fdd2d 100644
--- a/src/lib/internal.h
+++ b/src/lib/internal.h
@@ -795,14 +795,6 @@ struct MHD_Connection
795 bool suspended; 795 bool suspended;
796 796
797 /** 797 /**
798 * Did we ever call the "default_handler" on this request? (this
799 * flag will determine if we call the
800 * #MHD_daemon_set_notify_connection() handler when the connection
801 * closes down).
802 */
803 bool client_aware;
804
805 /**
806 * Are we ready to read from TLS for this connection? 798 * Are we ready to read from TLS for this connection?
807 */ 799 */
808 bool tls_read_ready; 800 bool tls_read_ready;
@@ -1722,6 +1714,11 @@ struct MHD_Response
1722 * Only respond in HTTP 1.0 mode. 1714 * Only respond in HTTP 1.0 mode.
1723 */ 1715 */
1724 bool v10_only; 1716 bool v10_only;
1717
1718 /**
1719 * Use ShoutCAST format.
1720 */
1721 bool icy;
1725 1722
1726}; 1723};
1727 1724
@@ -1735,10 +1732,10 @@ struct MHD_Response
1735 * @param key 0-terminated key string, never NULL 1732 * @param key 0-terminated key string, never NULL
1736 * @param value 0-terminated value string, may be NULL 1733 * @param value 0-terminated value string, may be NULL
1737 * @param kind origin of the key-value pair 1734 * @param kind origin of the key-value pair
1738 * @return #MHD_YES on success (continue to iterate) 1735 * @return true on success (continue to iterate)
1739 * #MHD_NO to signal failure (and abort iteration) 1736 * false to signal failure (and abort iteration)
1740 */ 1737 */
1741typedef int 1738typedef bool
1742(*MHD_ArgumentIterator_)(struct MHD_Request *request, 1739(*MHD_ArgumentIterator_)(struct MHD_Request *request,
1743 const char *key, 1740 const char *key,
1744 const char *value, 1741 const char *value,
@@ -1755,11 +1752,11 @@ typedef int
1755 * clobbered in the process! 1752 * clobbered in the process!
1756 * @param cb function to call on each key-value pair found 1753 * @param cb function to call on each key-value pair found
1757 * @param[out] num_headers set to the number of headers found 1754 * @param[out] num_headers set to the number of headers found
1758 * @return #MHD_NO on failure (@a cb returned #MHD_NO), 1755 * @return false on failure (@a cb returned false),
1759 * #MHD_YES for success (parsing succeeded, @a cb always 1756 * true for success (parsing succeeded, @a cb always
1760 * returned #MHD_YES) 1757 * returned true)
1761 */ 1758 */
1762int 1759bool
1763MHD_parse_arguments_ (struct MHD_Request *request, 1760MHD_parse_arguments_ (struct MHD_Request *request,
1764 enum MHD_ValueKind kind, 1761 enum MHD_ValueKind kind,
1765 char *args, 1762 char *args,