diff options
author | Christian Grothoff <christian@grothoff.org> | 2019-09-15 12:52:14 +0200 |
---|---|---|
committer | Christian Grothoff <christian@grothoff.org> | 2019-09-15 12:52:14 +0200 |
commit | 2133a6d6b4c35b11a485404b84fcd946dcc96a19 (patch) | |
tree | 1a0e0c45ccab02e0ebbb8ceb236366b48d17c30e | |
parent | d44a18700cc184027d4a283dc212982c6c112679 (diff) | |
download | libmicrohttpd-2133a6d6b4c35b11a485404b84fcd946dcc96a19.tar.gz libmicrohttpd-2133a6d6b4c35b11a485404b84fcd946dcc96a19.zip |
fix-warnings
-rw-r--r-- | src/microhttpd/connection.c | 4273 |
1 files changed, 2156 insertions, 2117 deletions
diff --git a/src/microhttpd/connection.c b/src/microhttpd/connection.c index ab760e4a..77fcd849 100644 --- a/src/microhttpd/connection.c +++ b/src/microhttpd/connection.c | |||
@@ -68,7 +68,8 @@ | |||
68 | * minimal. | 68 | * minimal. |
69 | */ | 69 | */ |
70 | #ifdef HAVE_MESSAGES | 70 | #ifdef HAVE_MESSAGES |
71 | #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>" | 71 | #define REQUEST_TOO_BIG \ |
72 | "<html><head><title>Request too big</title></head><body>Your HTTP header was too big for the memory constraints of this webserver.</body></html>" | ||
72 | #else | 73 | #else |
73 | #define REQUEST_TOO_BIG "" | 74 | #define REQUEST_TOO_BIG "" |
74 | #endif | 75 | #endif |
@@ -81,7 +82,8 @@ | |||
81 | * minimal. | 82 | * minimal. |
82 | */ | 83 | */ |
83 | #ifdef HAVE_MESSAGES | 84 | #ifdef HAVE_MESSAGES |
84 | #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>" | 85 | #define REQUEST_LACKS_HOST \ |
86 | "<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>" | ||
85 | #else | 87 | #else |
86 | #define REQUEST_LACKS_HOST "" | 88 | #define REQUEST_LACKS_HOST "" |
87 | #endif | 89 | #endif |
@@ -94,7 +96,8 @@ | |||
94 | * minimal. | 96 | * minimal. |
95 | */ | 97 | */ |
96 | #ifdef HAVE_MESSAGES | 98 | #ifdef HAVE_MESSAGES |
97 | #define REQUEST_MALFORMED "<html><head><title>Request malformed</title></head><body>Your HTTP request was syntactically incorrect.</body></html>" | 99 | #define REQUEST_MALFORMED \ |
100 | "<html><head><title>Request malformed</title></head><body>Your HTTP request was syntactically incorrect.</body></html>" | ||
98 | #else | 101 | #else |
99 | #define REQUEST_MALFORMED "" | 102 | #define REQUEST_MALFORMED "" |
100 | #endif | 103 | #endif |
@@ -106,7 +109,8 @@ | |||
106 | * minimal. | 109 | * minimal. |
107 | */ | 110 | */ |
108 | #ifdef HAVE_MESSAGES | 111 | #ifdef HAVE_MESSAGES |
109 | #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>" | 112 | #define INTERNAL_ERROR \ |
113 | "<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>" | ||
110 | #else | 114 | #else |
111 | #define INTERNAL_ERROR "" | 115 | #define INTERNAL_ERROR "" |
112 | #endif | 116 | #endif |
@@ -157,17 +161,18 @@ MHD_conn_init_static_ (void) | |||
157 | #ifdef SF_FLAGS | 161 | #ifdef SF_FLAGS |
158 | long sys_page_size = sysconf (_SC_PAGESIZE); | 162 | long sys_page_size = sysconf (_SC_PAGESIZE); |
159 | if (0 > sys_page_size) | 163 | if (0 > sys_page_size) |
160 | { /* Failed to get page size. */ | 164 | { /* Failed to get page size. */ |
161 | freebsd_sendfile_flags_ = SF_NODISKIO; | 165 | freebsd_sendfile_flags_ = SF_NODISKIO; |
162 | freebsd_sendfile_flags_thd_p_c_ = SF_NODISKIO; | 166 | freebsd_sendfile_flags_thd_p_c_ = SF_NODISKIO; |
163 | } | 167 | } |
164 | else | 168 | else |
165 | { | 169 | { |
166 | freebsd_sendfile_flags_ = | 170 | freebsd_sendfile_flags_ = |
167 | SF_FLAGS((uint16_t)(MHD_SENFILE_CHUNK_ / sys_page_size), SF_NODISKIO); | 171 | SF_FLAGS ((uint16_t) (MHD_SENFILE_CHUNK_ / sys_page_size), SF_NODISKIO); |
168 | freebsd_sendfile_flags_thd_p_c_ = | 172 | freebsd_sendfile_flags_thd_p_c_ = |
169 | SF_FLAGS((uint16_t)(MHD_SENFILE_CHUNK_THR_P_C_ / sys_page_size), SF_NODISKIO); | 173 | SF_FLAGS ((uint16_t) (MHD_SENFILE_CHUNK_THR_P_C_ / sys_page_size), |
170 | } | 174 | SF_NODISKIO); |
175 | } | ||
171 | #endif /* SF_FLAGS */ | 176 | #endif /* SF_FLAGS */ |
172 | } | 177 | } |
173 | #endif /* HAVE_FREEBSD_SENDFILE */ | 178 | #endif /* HAVE_FREEBSD_SENDFILE */ |
@@ -189,9 +194,9 @@ recv_param_adapter (struct MHD_Connection *connection, | |||
189 | 194 | ||
190 | if ( (MHD_INVALID_SOCKET == connection->socket_fd) || | 195 | if ( (MHD_INVALID_SOCKET == connection->socket_fd) || |
191 | (MHD_CONNECTION_CLOSED == connection->state) ) | 196 | (MHD_CONNECTION_CLOSED == connection->state) ) |
192 | { | 197 | { |
193 | return MHD_ERR_NOTCONN_; | 198 | return MHD_ERR_NOTCONN_; |
194 | } | 199 | } |
195 | if (i > MHD_SCKT_SEND_MAX_SIZE_) | 200 | if (i > MHD_SCKT_SEND_MAX_SIZE_) |
196 | i = MHD_SCKT_SEND_MAX_SIZE_; /* return value limit */ | 201 | i = MHD_SCKT_SEND_MAX_SIZE_; /* return value limit */ |
197 | 202 | ||
@@ -199,25 +204,25 @@ recv_param_adapter (struct MHD_Connection *connection, | |||
199 | other, | 204 | other, |
200 | i); | 205 | i); |
201 | if (0 > ret) | 206 | if (0 > ret) |
207 | { | ||
208 | const int err = MHD_socket_get_error_ (); | ||
209 | if (MHD_SCKT_ERR_IS_EAGAIN_ (err)) | ||
202 | { | 210 | { |
203 | const int err = MHD_socket_get_error_ (); | ||
204 | if (MHD_SCKT_ERR_IS_EAGAIN_ (err)) | ||
205 | { | ||
206 | #ifdef EPOLL_SUPPORT | 211 | #ifdef EPOLL_SUPPORT |
207 | /* Got EAGAIN --- no longer read-ready */ | 212 | /* Got EAGAIN --- no longer read-ready */ |
208 | connection->epoll_state &= ~MHD_EPOLL_STATE_READ_READY; | 213 | connection->epoll_state &= ~MHD_EPOLL_STATE_READ_READY; |
209 | #endif /* EPOLL_SUPPORT */ | 214 | #endif /* EPOLL_SUPPORT */ |
210 | return MHD_ERR_AGAIN_; | 215 | return MHD_ERR_AGAIN_; |
211 | } | ||
212 | if (MHD_SCKT_ERR_IS_EINTR_ (err)) | ||
213 | return MHD_ERR_AGAIN_; | ||
214 | if (MHD_SCKT_ERR_IS_ (err, MHD_SCKT_ECONNRESET_)) | ||
215 | return MHD_ERR_CONNRESET_; | ||
216 | /* Treat any other error as hard error. */ | ||
217 | return MHD_ERR_NOTCONN_; | ||
218 | } | 216 | } |
217 | if (MHD_SCKT_ERR_IS_EINTR_ (err)) | ||
218 | return MHD_ERR_AGAIN_; | ||
219 | if (MHD_SCKT_ERR_IS_ (err, MHD_SCKT_ECONNRESET_)) | ||
220 | return MHD_ERR_CONNRESET_; | ||
221 | /* Treat any other error as hard error. */ | ||
222 | return MHD_ERR_NOTCONN_; | ||
223 | } | ||
219 | #ifdef EPOLL_SUPPORT | 224 | #ifdef EPOLL_SUPPORT |
220 | else if (i > (size_t)ret) | 225 | else if (i > (size_t) ret) |
221 | connection->epoll_state &= ~MHD_EPOLL_STATE_READ_READY; | 226 | connection->epoll_state &= ~MHD_EPOLL_STATE_READ_READY; |
222 | #endif /* EPOLL_SUPPORT */ | 227 | #endif /* EPOLL_SUPPORT */ |
223 | return ret; | 228 | return ret; |
@@ -242,9 +247,9 @@ send_param_adapter (struct MHD_Connection *connection, | |||
242 | 247 | ||
243 | if ( (MHD_INVALID_SOCKET == connection->socket_fd) || | 248 | if ( (MHD_INVALID_SOCKET == connection->socket_fd) || |
244 | (MHD_CONNECTION_CLOSED == connection->state) ) | 249 | (MHD_CONNECTION_CLOSED == connection->state) ) |
245 | { | 250 | { |
246 | return MHD_ERR_NOTCONN_; | 251 | return MHD_ERR_NOTCONN_; |
247 | } | 252 | } |
248 | if (i > MHD_SCKT_SEND_MAX_SIZE_) | 253 | if (i > MHD_SCKT_SEND_MAX_SIZE_) |
249 | i = MHD_SCKT_SEND_MAX_SIZE_; /* return value limit */ | 254 | i = MHD_SCKT_SEND_MAX_SIZE_; /* return value limit */ |
250 | 255 | ||
@@ -252,26 +257,26 @@ send_param_adapter (struct MHD_Connection *connection, | |||
252 | other, | 257 | other, |
253 | i); | 258 | i); |
254 | if (0 > ret) | 259 | if (0 > ret) |
255 | { | 260 | { |
256 | const int err = MHD_socket_get_error_(); | 261 | const int err = MHD_socket_get_error_ (); |
257 | 262 | ||
258 | if (MHD_SCKT_ERR_IS_EAGAIN_(err)) | 263 | if (MHD_SCKT_ERR_IS_EAGAIN_ (err)) |
259 | { | 264 | { |
260 | #ifdef EPOLL_SUPPORT | 265 | #ifdef EPOLL_SUPPORT |
261 | /* EAGAIN --- no longer write-ready */ | 266 | /* EAGAIN --- no longer write-ready */ |
262 | connection->epoll_state &= ~MHD_EPOLL_STATE_WRITE_READY; | 267 | connection->epoll_state &= ~MHD_EPOLL_STATE_WRITE_READY; |
263 | #endif /* EPOLL_SUPPORT */ | 268 | #endif /* EPOLL_SUPPORT */ |
264 | return MHD_ERR_AGAIN_; | 269 | return MHD_ERR_AGAIN_; |
265 | } | ||
266 | if (MHD_SCKT_ERR_IS_EINTR_ (err)) | ||
267 | return MHD_ERR_AGAIN_; | ||
268 | if (MHD_SCKT_ERR_IS_ (err, MHD_SCKT_ECONNRESET_)) | ||
269 | return MHD_ERR_CONNRESET_; | ||
270 | /* Treat any other error as hard error. */ | ||
271 | return MHD_ERR_NOTCONN_; | ||
272 | } | 270 | } |
271 | if (MHD_SCKT_ERR_IS_EINTR_ (err)) | ||
272 | return MHD_ERR_AGAIN_; | ||
273 | if (MHD_SCKT_ERR_IS_ (err, MHD_SCKT_ECONNRESET_)) | ||
274 | return MHD_ERR_CONNRESET_; | ||
275 | /* Treat any other error as hard error. */ | ||
276 | return MHD_ERR_NOTCONN_; | ||
277 | } | ||
273 | #ifdef EPOLL_SUPPORT | 278 | #ifdef EPOLL_SUPPORT |
274 | else if (i > (size_t)ret) | 279 | else if (i > (size_t) ret) |
275 | connection->epoll_state &= ~MHD_EPOLL_STATE_WRITE_READY; | 280 | connection->epoll_state &= ~MHD_EPOLL_STATE_WRITE_READY; |
276 | #endif /* EPOLL_SUPPORT */ | 281 | #endif /* EPOLL_SUPPORT */ |
277 | return ret; | 282 | return ret; |
@@ -298,9 +303,9 @@ send_param_adapter (struct MHD_Connection *connection, | |||
298 | * @return true if force push is possible, false otherwise | 303 | * @return true if force push is possible, false otherwise |
299 | */ | 304 | */ |
300 | _MHD_static_inline bool | 305 | _MHD_static_inline bool |
301 | socket_flush_possible(struct MHD_Connection *connection) | 306 | socket_flush_possible (struct MHD_Connection *connection) |
302 | { | 307 | { |
303 | (void)connection; /* Mute compiler warning. */ | 308 | (void) connection; /* Mute compiler warning. */ |
304 | #if defined(TCP_CORK) || defined(TCP_PUSH) | 309 | #if defined(TCP_CORK) || defined(TCP_PUSH) |
305 | return true; | 310 | return true; |
306 | #else /* !TCP_CORK && !TCP_PUSH */ | 311 | #else /* !TCP_CORK && !TCP_PUSH */ |
@@ -310,20 +315,6 @@ socket_flush_possible(struct MHD_Connection *connection) | |||
310 | 315 | ||
311 | 316 | ||
312 | /** | 317 | /** |
313 | * Activate extra buffering mode on connection socket to prevent | ||
314 | * sending of partial packets. | ||
315 | * | ||
316 | * @param connection connection to be processed | ||
317 | * @return true on success, false otherwise | ||
318 | */ | ||
319 | _MHD_static_inline bool | ||
320 | socket_start_extra_buffering (struct MHD_Connection *connection) | ||
321 | { | ||
322 | mhd_assert(NULL != connection); | ||
323 | } | ||
324 | |||
325 | |||
326 | /** | ||
327 | * Activate no buffering mode (no delay sending) on connection socket | 318 | * Activate no buffering mode (no delay sending) on connection socket |
328 | * and push to client data pending in socket buffer. | 319 | * and push to client data pending in socket buffer. |
329 | * | 320 | * |
@@ -333,20 +324,20 @@ socket_start_extra_buffering (struct MHD_Connection *connection) | |||
333 | _MHD_static_inline bool | 324 | _MHD_static_inline bool |
334 | socket_start_no_buffering_flush (struct MHD_Connection *connection) | 325 | socket_start_no_buffering_flush (struct MHD_Connection *connection) |
335 | { | 326 | { |
336 | bool res; | 327 | bool res = false; |
337 | #if defined(TCP_NOPUSH) && !defined(TCP_CORK) | 328 | #if defined(TCP_NOPUSH) && ! defined(TCP_CORK) |
338 | const int dummy = 0; | 329 | const int dummy = 0; |
339 | #endif /* !TCP_CORK */ | 330 | #endif /* !TCP_CORK */ |
340 | 331 | ||
341 | #if defined(__FreeBSD__) && __FreeBSD__+0 >= 9 | 332 | #if defined(__FreeBSD__) && __FreeBSD__ + 0 >= 9 |
342 | /* FreeBSD do not need zero-send for flushing starting from version 9 */ | 333 | /* FreeBSD do not need zero-send for flushing starting from version 9 */ |
343 | #elif defined(TCP_NOPUSH) && !defined(TCP_CORK) | 334 | #elif defined(TCP_NOPUSH) && ! defined(TCP_CORK) |
344 | /* Force flush data with zero send otherwise Darwin and some BSD systems | 335 | /* Force flush data with zero send otherwise Darwin and some BSD systems |
345 | will add 5 seconds delay. Not required with TCP_CORK as switching off | 336 | will add 5 seconds delay. Not required with TCP_CORK as switching off |
346 | TCP_CORK always flushes socket buffer. */ | 337 | TCP_CORK always flushes socket buffer. */ |
347 | res = (0 <= MHD_send_ (connection->socket_fd, | 338 | res = (0 <= MHD_send_ (connection->socket_fd, |
348 | &dummy, | 339 | &dummy, |
349 | 0)) && res; | 340 | 0)) && res; |
350 | #endif /* TCP_NOPUSH && !TCP_CORK*/ | 341 | #endif /* TCP_NOPUSH && !TCP_CORK*/ |
351 | return res; | 342 | return res; |
352 | } | 343 | } |
@@ -378,15 +369,15 @@ MHD_get_connection_values (struct MHD_Connection *connection, | |||
378 | ret = 0; | 369 | ret = 0; |
379 | for (pos = connection->headers_received; NULL != pos; pos = pos->next) | 370 | for (pos = connection->headers_received; NULL != pos; pos = pos->next) |
380 | if (0 != (pos->kind & kind)) | 371 | if (0 != (pos->kind & kind)) |
381 | { | 372 | { |
382 | ret++; | 373 | ret++; |
383 | if ( (NULL != iterator) && | 374 | if ( (NULL != iterator) && |
384 | (MHD_YES != iterator (iterator_cls, | 375 | (MHD_YES != iterator (iterator_cls, |
385 | pos->kind, | 376 | pos->kind, |
386 | pos->header, | 377 | pos->header, |
387 | pos->value)) ) | 378 | pos->value)) ) |
388 | return ret; | 379 | return ret; |
389 | } | 380 | } |
390 | return ret; | 381 | return ret; |
391 | } | 382 | } |
392 | 383 | ||
@@ -418,23 +409,23 @@ MHD_get_connection_values_n (struct MHD_Connection *connection, | |||
418 | 409 | ||
419 | if (NULL == iterator) | 410 | if (NULL == iterator) |
420 | for (pos = connection->headers_received; NULL != pos; pos = pos->next) | 411 | for (pos = connection->headers_received; NULL != pos; pos = pos->next) |
421 | { | 412 | { |
422 | if (kind == pos->kind) | 413 | if (kind == pos->kind) |
423 | ret++; | 414 | ret++; |
424 | } | 415 | } |
425 | else | 416 | else |
426 | for (pos = connection->headers_received; NULL != pos; pos = pos->next) | 417 | for (pos = connection->headers_received; NULL != pos; pos = pos->next) |
427 | if (kind == pos->kind) | 418 | if (kind == pos->kind) |
428 | { | 419 | { |
429 | ret++; | 420 | ret++; |
430 | if (MHD_NO == iterator (iterator_cls, | 421 | if (MHD_NO == iterator (iterator_cls, |
431 | pos->kind, | 422 | pos->kind, |
432 | pos->header, | 423 | pos->header, |
433 | pos->header_size, | 424 | pos->header_size, |
434 | pos->value, | 425 | pos->value, |
435 | pos->value_size)) | 426 | pos->value_size)) |
436 | return ret; | 427 | return ret; |
437 | } | 428 | } |
438 | return ret; | 429 | return ret; |
439 | } | 430 | } |
440 | 431 | ||
@@ -479,15 +470,15 @@ MHD_set_connection_value_n_nocheck_ (struct MHD_Connection *connection, | |||
479 | pos->next = NULL; | 470 | pos->next = NULL; |
480 | /* append 'pos' to the linked list of headers */ | 471 | /* append 'pos' to the linked list of headers */ |
481 | if (NULL == connection->headers_received_tail) | 472 | if (NULL == connection->headers_received_tail) |
482 | { | 473 | { |
483 | connection->headers_received = pos; | 474 | connection->headers_received = pos; |
484 | connection->headers_received_tail = pos; | 475 | connection->headers_received_tail = pos; |
485 | } | 476 | } |
486 | else | 477 | else |
487 | { | 478 | { |
488 | connection->headers_received_tail->next = pos; | 479 | connection->headers_received_tail->next = pos; |
489 | connection->headers_received_tail = pos; | 480 | connection->headers_received_tail = pos; |
490 | } | 481 | } |
491 | return MHD_YES; | 482 | return MHD_YES; |
492 | } | 483 | } |
493 | 484 | ||
@@ -526,8 +517,8 @@ MHD_set_connection_value_n (struct MHD_Connection *connection, | |||
526 | size_t value_size) | 517 | size_t value_size) |
527 | { | 518 | { |
528 | if ( (MHD_GET_ARGUMENT_KIND != kind) && | 519 | if ( (MHD_GET_ARGUMENT_KIND != kind) && |
529 | ( ((key ? strlen(key) : 0) != key_size) || | 520 | ( ((key ? strlen (key) : 0) != key_size) || |
530 | ((value ? strlen(value) : 0) != value_size) ) ) | 521 | ((value ? strlen (value) : 0) != value_size) ) ) |
531 | return MHD_NO; /* binary zero is allowed only in GET arguments */ | 522 | return MHD_NO; /* binary zero is allowed only in GET arguments */ |
532 | 523 | ||
533 | return MHD_set_connection_value_n_nocheck_ (connection, | 524 | return MHD_set_connection_value_n_nocheck_ (connection, |
@@ -604,7 +595,7 @@ MHD_lookup_connection_value (struct MHD_Connection *connection, | |||
604 | (void) MHD_lookup_connection_value_n (connection, | 595 | (void) MHD_lookup_connection_value_n (connection, |
605 | kind, | 596 | kind, |
606 | key, | 597 | key, |
607 | (NULL == key) ? 0 : strlen(key), | 598 | (NULL == key) ? 0 : strlen (key), |
608 | &value, | 599 | &value, |
609 | NULL); | 600 | NULL); |
610 | return value; | 601 | return value; |
@@ -644,27 +635,27 @@ MHD_lookup_connection_value_n (struct MHD_Connection *connection, | |||
644 | return MHD_NO; | 635 | return MHD_NO; |
645 | 636 | ||
646 | if (NULL == key) | 637 | if (NULL == key) |
638 | { | ||
639 | for (pos = connection->headers_received; NULL != pos; pos = pos->next) | ||
647 | { | 640 | { |
648 | for (pos = connection->headers_received; NULL != pos; pos = pos->next) | 641 | if ( (0 != (kind & pos->kind)) && |
649 | { | 642 | (NULL == pos->header) ) |
650 | if ( (0 != (kind & pos->kind)) && | 643 | break; |
651 | (NULL == pos->header) ) | ||
652 | break; | ||
653 | } | ||
654 | } | 644 | } |
645 | } | ||
655 | else | 646 | else |
647 | { | ||
648 | for (pos = connection->headers_received; NULL != pos; pos = pos->next) | ||
656 | { | 649 | { |
657 | for (pos = connection->headers_received; NULL != pos; pos = pos->next) | 650 | if ( (0 != (kind & pos->kind)) && |
658 | { | 651 | (key_size == pos->header_size) && |
659 | if ( (0 != (kind & pos->kind)) && | 652 | ( (key == pos->header) || |
660 | (key_size == pos->header_size) && | 653 | (MHD_str_equal_caseless_bin_n_ (key, |
661 | ( (key == pos->header) || | 654 | pos->header, |
662 | (MHD_str_equal_caseless_bin_n_ (key, | 655 | key_size) ) ) ) |
663 | pos->header, | 656 | break; |
664 | key_size) ) ) ) | ||
665 | break; | ||
666 | } | ||
667 | } | 657 | } |
658 | } | ||
668 | 659 | ||
669 | if (NULL == pos) | 660 | if (NULL == pos) |
670 | return MHD_NO; | 661 | return MHD_NO; |
@@ -696,27 +687,30 @@ MHD_lookup_connection_value_n (struct MHD_Connection *connection, | |||
696 | */ | 687 | */ |
697 | static bool | 688 | static bool |
698 | MHD_lookup_header_token_ci (const struct MHD_Connection *connection, | 689 | MHD_lookup_header_token_ci (const struct MHD_Connection *connection, |
699 | const char *header, | 690 | const char *header, |
700 | size_t header_len, | 691 | size_t header_len, |
701 | const char *token, | 692 | const char *token, |
702 | size_t token_len) | 693 | size_t token_len) |
703 | { | 694 | { |
704 | struct MHD_HTTP_Header *pos; | 695 | struct MHD_HTTP_Header *pos; |
705 | 696 | ||
706 | if (NULL == connection || NULL == header || 0 == header[0] || NULL == token || 0 == token[0]) | 697 | if ((NULL == connection)||(NULL == header)||(0 == header[0])||(NULL == |
698 | token) ||(0 == | ||
699 | token | ||
700 | [0]) ) | ||
707 | return false; | 701 | return false; |
708 | 702 | ||
709 | for (pos = connection->headers_received; NULL != pos; pos = pos->next) | 703 | for (pos = connection->headers_received; NULL != pos; pos = pos->next) |
710 | { | 704 | { |
711 | if ((0 != (pos->kind & MHD_HEADER_KIND)) && | 705 | if ((0 != (pos->kind & MHD_HEADER_KIND)) && |
712 | (header_len == pos->header_size) && | 706 | (header_len == pos->header_size) && |
713 | ( (header == pos->header) || | 707 | ( (header == pos->header) || |
714 | (MHD_str_equal_caseless_bin_n_(header, | 708 | (MHD_str_equal_caseless_bin_n_ (header, |
715 | pos->header, | 709 | pos->header, |
716 | header_len)) ) && | 710 | header_len)) ) && |
717 | (MHD_str_has_token_caseless_ (pos->value, token, token_len))) | 711 | (MHD_str_has_token_caseless_ (pos->value, token, token_len))) |
718 | return true; | 712 | return true; |
719 | } | 713 | } |
720 | return false; | 714 | return false; |
721 | } | 715 | } |
722 | 716 | ||
@@ -733,8 +727,8 @@ MHD_lookup_header_token_ci (const struct MHD_Connection *connection, | |||
733 | * false otherwise | 727 | * false otherwise |
734 | */ | 728 | */ |
735 | #define MHD_lookup_header_s_token_ci(c,h,tkn) \ | 729 | #define MHD_lookup_header_s_token_ci(c,h,tkn) \ |
736 | MHD_lookup_header_token_ci((c),(h),MHD_STATICSTR_LEN_(h),\ | 730 | MHD_lookup_header_token_ci ((c),(h),MHD_STATICSTR_LEN_ (h), \ |
737 | (tkn),MHD_STATICSTR_LEN_(tkn)) | 731 | (tkn),MHD_STATICSTR_LEN_ (tkn)) |
738 | 732 | ||
739 | 733 | ||
740 | /** | 734 | /** |
@@ -750,19 +744,20 @@ need_100_continue (struct MHD_Connection *connection) | |||
750 | const char *expect; | 744 | const char *expect; |
751 | 745 | ||
752 | return ( (NULL == connection->response) && | 746 | return ( (NULL == connection->response) && |
753 | (NULL != connection->version) && | 747 | (NULL != connection->version) && |
754 | (MHD_str_equal_caseless_(connection->version, | 748 | (MHD_str_equal_caseless_ (connection->version, |
755 | MHD_HTTP_VERSION_1_1)) && | 749 | MHD_HTTP_VERSION_1_1)) && |
756 | (MHD_NO != MHD_lookup_connection_value_n (connection, | 750 | (MHD_NO != MHD_lookup_connection_value_n (connection, |
757 | MHD_HEADER_KIND, | 751 | MHD_HEADER_KIND, |
758 | MHD_HTTP_HEADER_EXPECT, | 752 | MHD_HTTP_HEADER_EXPECT, |
759 | MHD_STATICSTR_LEN_(MHD_HTTP_HEADER_EXPECT), | 753 | MHD_STATICSTR_LEN_ ( |
754 | MHD_HTTP_HEADER_EXPECT), | ||
760 | &expect, | 755 | &expect, |
761 | NULL)) && | 756 | NULL)) && |
762 | (MHD_str_equal_caseless_(expect, | 757 | (MHD_str_equal_caseless_ (expect, |
763 | "100-continue")) && | 758 | "100-continue")) && |
764 | (connection->continue_message_write_offset < | 759 | (connection->continue_message_write_offset < |
765 | MHD_STATICSTR_LEN_ (HTTP_100_CONTINUE)) ); | 760 | MHD_STATICSTR_LEN_ (HTTP_100_CONTINUE)) ); |
766 | } | 761 | } |
767 | 762 | ||
768 | 763 | ||
@@ -780,24 +775,24 @@ MHD_connection_mark_closed_ (struct MHD_Connection *connection) | |||
780 | connection->state = MHD_CONNECTION_CLOSED; | 775 | connection->state = MHD_CONNECTION_CLOSED; |
781 | connection->event_loop_info = MHD_EVENT_LOOP_INFO_CLEANUP; | 776 | connection->event_loop_info = MHD_EVENT_LOOP_INFO_CLEANUP; |
782 | if (0 == (daemon->options & MHD_USE_TURBO)) | 777 | if (0 == (daemon->options & MHD_USE_TURBO)) |
783 | { | 778 | { |
784 | #ifdef HTTPS_SUPPORT | 779 | #ifdef HTTPS_SUPPORT |
785 | /* For TLS connection use shutdown of TLS layer | 780 | /* For TLS connection use shutdown of TLS layer |
786 | * and do not shutdown TCP socket. This give more | 781 | * and do not shutdown TCP socket. This give more |
787 | * chances to send TLS closure data to remote side. | 782 | * chances to send TLS closure data to remote side. |
788 | * Closure of TLS layer will be interpreted by | 783 | * Closure of TLS layer will be interpreted by |
789 | * remote side as end of transmission. */ | 784 | * remote side as end of transmission. */ |
790 | if (0 != (daemon->options & MHD_USE_TLS)) | 785 | if (0 != (daemon->options & MHD_USE_TLS)) |
791 | { | 786 | { |
792 | if (! MHD_tls_connection_shutdown(connection)) | 787 | if (! MHD_tls_connection_shutdown (connection)) |
793 | shutdown (connection->socket_fd, | 788 | shutdown (connection->socket_fd, |
794 | SHUT_WR); | 789 | SHUT_WR); |
795 | } | ||
796 | else /* Combined with next 'shutdown()'. */ | ||
797 | #endif /* HTTPS_SUPPORT */ | ||
798 | shutdown (connection->socket_fd, | ||
799 | SHUT_WR); | ||
800 | } | 790 | } |
791 | else /* Combined with next 'shutdown()'. */ | ||
792 | #endif /* HTTPS_SUPPORT */ | ||
793 | shutdown (connection->socket_fd, | ||
794 | SHUT_WR); | ||
795 | } | ||
801 | } | 796 | } |
802 | 797 | ||
803 | 798 | ||
@@ -819,16 +814,16 @@ MHD_connection_close_ (struct MHD_Connection *connection, | |||
819 | 814 | ||
820 | MHD_connection_mark_closed_ (connection); | 815 | MHD_connection_mark_closed_ (connection); |
821 | if (NULL != resp) | 816 | if (NULL != resp) |
822 | { | 817 | { |
823 | connection->response = NULL; | 818 | connection->response = NULL; |
824 | MHD_destroy_response (resp); | 819 | MHD_destroy_response (resp); |
825 | } | 820 | } |
826 | if ( (NULL != daemon->notify_completed) && | 821 | if ( (NULL != daemon->notify_completed) && |
827 | (connection->client_aware) ) | 822 | (connection->client_aware) ) |
828 | daemon->notify_completed (daemon->notify_completed_cls, | 823 | daemon->notify_completed (daemon->notify_completed_cls, |
829 | connection, | 824 | connection, |
830 | &connection->client_context, | 825 | &connection->client_context, |
831 | termination_code); | 826 | termination_code); |
832 | connection->client_aware = false; | 827 | connection->client_aware = false; |
833 | } | 828 | } |
834 | 829 | ||
@@ -863,33 +858,33 @@ MHD_connection_finish_forward_ (struct MHD_Connection *connection) | |||
863 | EPOLL_CTL_DEL, | 858 | EPOLL_CTL_DEL, |
864 | connection->socket_fd, | 859 | connection->socket_fd, |
865 | NULL)) ) | 860 | NULL)) ) |
866 | { | 861 | { |
867 | MHD_PANIC (_("Failed to remove FD from epoll set\n")); | 862 | MHD_PANIC (_ ("Failed to remove FD from epoll set\n")); |
868 | } | 863 | } |
869 | if (urh->in_eready_list) | 864 | if (urh->in_eready_list) |
870 | { | 865 | { |
871 | EDLL_remove (daemon->eready_urh_head, | 866 | EDLL_remove (daemon->eready_urh_head, |
872 | daemon->eready_urh_tail, | 867 | daemon->eready_urh_tail, |
873 | urh); | 868 | urh); |
874 | urh->in_eready_list = false; | 869 | urh->in_eready_list = false; |
875 | } | 870 | } |
876 | #endif /* EPOLL_SUPPORT */ | 871 | #endif /* EPOLL_SUPPORT */ |
877 | if (MHD_INVALID_SOCKET != urh->mhd.socket) | 872 | if (MHD_INVALID_SOCKET != urh->mhd.socket) |
878 | { | 873 | { |
879 | #if EPOLL_SUPPORT | 874 | #if EPOLL_SUPPORT |
880 | if ( (0 != (daemon->options & MHD_USE_EPOLL)) && | 875 | if ( (0 != (daemon->options & MHD_USE_EPOLL)) && |
881 | (0 != epoll_ctl (daemon->epoll_upgrade_fd, | 876 | (0 != epoll_ctl (daemon->epoll_upgrade_fd, |
882 | EPOLL_CTL_DEL, | 877 | EPOLL_CTL_DEL, |
883 | urh->mhd.socket, | 878 | urh->mhd.socket, |
884 | NULL)) ) | 879 | NULL)) ) |
885 | { | 880 | { |
886 | MHD_PANIC (_("Failed to remove FD from epoll set\n")); | 881 | MHD_PANIC (_ ("Failed to remove FD from epoll set\n")); |
887 | } | ||
888 | #endif /* EPOLL_SUPPORT */ | ||
889 | /* Reflect remote disconnect to application by breaking | ||
890 | * socketpair connection. */ | ||
891 | shutdown (urh->mhd.socket, SHUT_RDWR); | ||
892 | } | 882 | } |
883 | #endif /* EPOLL_SUPPORT */ | ||
884 | /* Reflect remote disconnect to application by breaking | ||
885 | * socketpair connection. */ | ||
886 | shutdown (urh->mhd.socket, SHUT_RDWR); | ||
887 | } | ||
893 | /* Socketpair sockets will remain open as they will be | 888 | /* Socketpair sockets will remain open as they will be |
894 | * used with MHD_UPGRADE_ACTION_CLOSE. They will be | 889 | * used with MHD_UPGRADE_ACTION_CLOSE. They will be |
895 | * closed by MHD_cleanup_upgraded_connection_() during | 890 | * closed by MHD_cleanup_upgraded_connection_() during |
@@ -908,14 +903,14 @@ MHD_connection_finish_forward_ (struct MHD_Connection *connection) | |||
908 | */ | 903 | */ |
909 | static void | 904 | static void |
910 | connection_close_error (struct MHD_Connection *connection, | 905 | connection_close_error (struct MHD_Connection *connection, |
911 | const char *emsg) | 906 | const char *emsg) |
912 | { | 907 | { |
913 | #ifdef HAVE_MESSAGES | 908 | #ifdef HAVE_MESSAGES |
914 | if (NULL != emsg) | 909 | if (NULL != emsg) |
915 | MHD_DLOG (connection->daemon, | 910 | MHD_DLOG (connection->daemon, |
916 | emsg); | 911 | emsg); |
917 | #else /* ! HAVE_MESSAGES */ | 912 | #else /* ! HAVE_MESSAGES */ |
918 | (void)emsg; /* Mute compiler warning. */ | 913 | (void) emsg; /* Mute compiler warning. */ |
919 | #endif /* ! HAVE_MESSAGES */ | 914 | #endif /* ! HAVE_MESSAGES */ |
920 | MHD_connection_close_ (connection, | 915 | MHD_connection_close_ (connection, |
921 | MHD_REQUEST_TERMINATED_WITH_ERROR); | 916 | MHD_REQUEST_TERMINATED_WITH_ERROR); |
@@ -958,50 +953,51 @@ try_ready_normal_body (struct MHD_Connection *connection) | |||
958 | (connection->response_write_position == response->total_size) ) | 953 | (connection->response_write_position == response->total_size) ) |
959 | return MHD_YES; /* 0-byte response is always ready */ | 954 | return MHD_YES; /* 0-byte response is always ready */ |
960 | if ( (response->data_start <= | 955 | if ( (response->data_start <= |
961 | connection->response_write_position) && | 956 | connection->response_write_position) && |
962 | (response->data_size + response->data_start > | 957 | (response->data_size + response->data_start > |
963 | connection->response_write_position) ) | 958 | connection->response_write_position) ) |
964 | return MHD_YES; /* response already ready */ | 959 | return MHD_YES; /* response already ready */ |
965 | #if defined(_MHD_HAVE_SENDFILE) | 960 | #if defined(_MHD_HAVE_SENDFILE) |
966 | if (MHD_resp_sender_sendfile == connection->resp_sender) | 961 | if (MHD_resp_sender_sendfile == connection->resp_sender) |
967 | { | 962 | { |
968 | /* will use sendfile, no need to bother response crc */ | 963 | /* will use sendfile, no need to bother response crc */ |
969 | return MHD_YES; | 964 | return MHD_YES; |
970 | } | 965 | } |
971 | #endif /* _MHD_HAVE_SENDFILE */ | 966 | #endif /* _MHD_HAVE_SENDFILE */ |
972 | 967 | ||
973 | ret = response->crc (response->crc_cls, | 968 | ret = response->crc (response->crc_cls, |
974 | connection->response_write_position, | 969 | connection->response_write_position, |
975 | response->data, | 970 | response->data, |
976 | (size_t) MHD_MIN ((uint64_t)response->data_buffer_size, | 971 | (size_t) MHD_MIN ((uint64_t) response->data_buffer_size, |
977 | response->total_size - | 972 | response->total_size |
978 | connection->response_write_position)); | 973 | - connection->response_write_position)); |
979 | if ( (((ssize_t) MHD_CONTENT_READER_END_OF_STREAM) == ret) || | 974 | if ( (((ssize_t) MHD_CONTENT_READER_END_OF_STREAM) == ret) || |
980 | (((ssize_t) MHD_CONTENT_READER_END_WITH_ERROR) == ret) ) | 975 | (((ssize_t) MHD_CONTENT_READER_END_WITH_ERROR) == ret) ) |
981 | { | 976 | { |
982 | /* either error or http 1.0 transfer, close socket! */ | 977 | /* either error or http 1.0 transfer, close socket! */ |
983 | response->total_size = connection->response_write_position; | 978 | response->total_size = connection->response_write_position; |
984 | #if defined(MHD_USE_POSIX_THREADS) || defined(MHD_USE_W32_THREADS) | 979 | #if defined(MHD_USE_POSIX_THREADS) || defined(MHD_USE_W32_THREADS) |
985 | MHD_mutex_unlock_chk_ (&response->mutex); | 980 | MHD_mutex_unlock_chk_ (&response->mutex); |
986 | #endif | 981 | #endif |
987 | if ( ((ssize_t)MHD_CONTENT_READER_END_OF_STREAM) == ret) | 982 | if ( ((ssize_t) MHD_CONTENT_READER_END_OF_STREAM) == ret) |
988 | MHD_connection_close_ (connection, | 983 | MHD_connection_close_ (connection, |
989 | MHD_REQUEST_TERMINATED_COMPLETED_OK); | 984 | MHD_REQUEST_TERMINATED_COMPLETED_OK); |
990 | else | 985 | else |
991 | CONNECTION_CLOSE_ERROR (connection, | 986 | CONNECTION_CLOSE_ERROR (connection, |
992 | _("Closing connection (application reported error generating data)\n")); | 987 | _ ( |
993 | return MHD_NO; | 988 | "Closing connection (application reported error generating data)\n")); |
994 | } | 989 | return MHD_NO; |
990 | } | ||
995 | response->data_start = connection->response_write_position; | 991 | response->data_start = connection->response_write_position; |
996 | response->data_size = ret; | 992 | response->data_size = ret; |
997 | if (0 == ret) | 993 | if (0 == ret) |
998 | { | 994 | { |
999 | connection->state = MHD_CONNECTION_NORMAL_BODY_UNREADY; | 995 | connection->state = MHD_CONNECTION_NORMAL_BODY_UNREADY; |
1000 | #if defined(MHD_USE_POSIX_THREADS) || defined(MHD_USE_W32_THREADS) | 996 | #if defined(MHD_USE_POSIX_THREADS) || defined(MHD_USE_W32_THREADS) |
1001 | MHD_mutex_unlock_chk_ (&response->mutex); | 997 | MHD_mutex_unlock_chk_ (&response->mutex); |
1002 | #endif | 998 | #endif |
1003 | return MHD_NO; | 999 | return MHD_NO; |
1004 | } | 1000 | } |
1005 | return MHD_YES; | 1001 | return MHD_YES; |
1006 | } | 1002 | } |
1007 | 1003 | ||
@@ -1027,95 +1023,96 @@ try_ready_chunked_body (struct MHD_Connection *connection) | |||
1027 | if (NULL == response->crc) | 1023 | if (NULL == response->crc) |
1028 | return MHD_YES; | 1024 | return MHD_YES; |
1029 | if (0 == connection->write_buffer_size) | 1025 | if (0 == connection->write_buffer_size) |
1030 | { | 1026 | { |
1031 | size_t size; | 1027 | size_t size; |
1032 | 1028 | ||
1033 | size = MHD_pool_get_free (connection->pool); | 1029 | size = MHD_pool_get_free (connection->pool); |
1034 | if (size < 128) | 1030 | if (size < 128) |
1035 | { | 1031 | { |
1036 | #if defined(MHD_USE_POSIX_THREADS) || defined(MHD_USE_W32_THREADS) | 1032 | #if defined(MHD_USE_POSIX_THREADS) || defined(MHD_USE_W32_THREADS) |
1037 | MHD_mutex_unlock_chk_ (&response->mutex); | 1033 | MHD_mutex_unlock_chk_ (&response->mutex); |
1038 | #endif | 1034 | #endif |
1039 | /* not enough memory */ | 1035 | /* not enough memory */ |
1040 | CONNECTION_CLOSE_ERROR (connection, | 1036 | CONNECTION_CLOSE_ERROR (connection, |
1041 | _("Closing connection (out of memory)\n")); | 1037 | _ ("Closing connection (out of memory)\n")); |
1042 | return MHD_NO; | 1038 | return MHD_NO; |
1043 | } | ||
1044 | if ( (2 * (0xFFFFFF + sizeof(cbuf) + 2)) < size) | ||
1045 | size = 2 * (0xFFFFFF + sizeof(cbuf) + 2); | ||
1046 | connection->write_buffer = MHD_pool_allocate (connection->pool, | ||
1047 | size, | ||
1048 | false); | ||
1049 | mhd_assert (NULL != connection->write_buffer); | ||
1050 | connection->write_buffer_size = size; | ||
1051 | } | 1039 | } |
1040 | if ( (2 * (0xFFFFFF + sizeof(cbuf) + 2)) < size) | ||
1041 | size = 2 * (0xFFFFFF + sizeof(cbuf) + 2); | ||
1042 | connection->write_buffer = MHD_pool_allocate (connection->pool, | ||
1043 | size, | ||
1044 | false); | ||
1045 | mhd_assert (NULL != connection->write_buffer); | ||
1046 | connection->write_buffer_size = size; | ||
1047 | } | ||
1052 | 1048 | ||
1053 | if (0 == response->total_size) | 1049 | if (0 == response->total_size) |
1054 | ret = 0; /* response must be empty, don't bother calling crc */ | 1050 | ret = 0; /* response must be empty, don't bother calling crc */ |
1055 | else if ( (response->data_start <= | 1051 | else if ( (response->data_start <= |
1056 | connection->response_write_position) && | 1052 | connection->response_write_position) && |
1057 | (response->data_start + response->data_size > | 1053 | (response->data_start + response->data_size > |
1058 | connection->response_write_position) ) | 1054 | connection->response_write_position) ) |
1059 | { | 1055 | { |
1060 | /* difference between response_write_position and data_start is less | 1056 | /* difference between response_write_position and data_start is less |
1061 | than data_size which is size_t type, no need to check for overflow */ | 1057 | than data_size which is size_t type, no need to check for overflow */ |
1062 | const size_t data_write_offset | 1058 | const size_t data_write_offset |
1063 | = (size_t)(connection->response_write_position - response->data_start); | 1059 | = (size_t) (connection->response_write_position - response->data_start); |
1064 | /* buffer already ready, use what is there for the chunk */ | 1060 | /* buffer already ready, use what is there for the chunk */ |
1065 | ret = response->data_size - data_write_offset; | 1061 | ret = response->data_size - data_write_offset; |
1066 | if ( ((size_t) ret) > connection->write_buffer_size - sizeof (cbuf) - 2 ) | 1062 | if ( ((size_t) ret) > connection->write_buffer_size - sizeof (cbuf) - 2 ) |
1067 | ret = connection->write_buffer_size - sizeof (cbuf) - 2; | 1063 | ret = connection->write_buffer_size - sizeof (cbuf) - 2; |
1068 | memcpy (&connection->write_buffer[sizeof (cbuf)], | 1064 | memcpy (&connection->write_buffer[sizeof (cbuf)], |
1069 | &response->data[data_write_offset], | 1065 | &response->data[data_write_offset], |
1070 | ret); | 1066 | ret); |
1071 | } | 1067 | } |
1072 | else | 1068 | else |
1073 | { | 1069 | { |
1074 | /* buffer not in range, try to fill it */ | 1070 | /* buffer not in range, try to fill it */ |
1075 | ret = response->crc (response->crc_cls, | 1071 | ret = response->crc (response->crc_cls, |
1076 | connection->response_write_position, | 1072 | connection->response_write_position, |
1077 | &connection->write_buffer[sizeof (cbuf)], | 1073 | &connection->write_buffer[sizeof (cbuf)], |
1078 | connection->write_buffer_size - sizeof (cbuf) - 2); | 1074 | connection->write_buffer_size - sizeof (cbuf) - 2); |
1079 | } | 1075 | } |
1080 | if ( ((ssize_t) MHD_CONTENT_READER_END_WITH_ERROR) == ret) | 1076 | if ( ((ssize_t) MHD_CONTENT_READER_END_WITH_ERROR) == ret) |
1081 | { | 1077 | { |
1082 | /* error, close socket! */ | 1078 | /* error, close socket! */ |
1083 | response->total_size = connection->response_write_position; | 1079 | response->total_size = connection->response_write_position; |
1084 | #if defined(MHD_USE_POSIX_THREADS) || defined(MHD_USE_W32_THREADS) | 1080 | #if defined(MHD_USE_POSIX_THREADS) || defined(MHD_USE_W32_THREADS) |
1085 | MHD_mutex_unlock_chk_ (&response->mutex); | 1081 | MHD_mutex_unlock_chk_ (&response->mutex); |
1086 | #endif | 1082 | #endif |
1087 | CONNECTION_CLOSE_ERROR (connection, | 1083 | CONNECTION_CLOSE_ERROR (connection, |
1088 | _("Closing connection (application error generating response)\n")); | 1084 | _ ( |
1089 | return MHD_NO; | 1085 | "Closing connection (application error generating response)\n")); |
1090 | } | 1086 | return MHD_NO; |
1087 | } | ||
1091 | if ( (((ssize_t) MHD_CONTENT_READER_END_OF_STREAM) == ret) || | 1088 | if ( (((ssize_t) MHD_CONTENT_READER_END_OF_STREAM) == ret) || |
1092 | (0 == response->total_size) ) | 1089 | (0 == response->total_size) ) |
1093 | { | 1090 | { |
1094 | /* end of message, signal other side! */ | 1091 | /* end of message, signal other side! */ |
1095 | memcpy (connection->write_buffer, | 1092 | memcpy (connection->write_buffer, |
1096 | "0\r\n", | 1093 | "0\r\n", |
1097 | 3); | 1094 | 3); |
1098 | connection->write_buffer_append_offset = 3; | 1095 | connection->write_buffer_append_offset = 3; |
1099 | connection->write_buffer_send_offset = 0; | 1096 | connection->write_buffer_send_offset = 0; |
1100 | response->total_size = connection->response_write_position; | 1097 | response->total_size = connection->response_write_position; |
1101 | return MHD_YES; | 1098 | return MHD_YES; |
1102 | } | 1099 | } |
1103 | if (0 == ret) | 1100 | if (0 == ret) |
1104 | { | 1101 | { |
1105 | connection->state = MHD_CONNECTION_CHUNKED_BODY_UNREADY; | 1102 | connection->state = MHD_CONNECTION_CHUNKED_BODY_UNREADY; |
1106 | #if defined(MHD_USE_POSIX_THREADS) || defined(MHD_USE_W32_THREADS) | 1103 | #if defined(MHD_USE_POSIX_THREADS) || defined(MHD_USE_W32_THREADS) |
1107 | MHD_mutex_unlock_chk_ (&response->mutex); | 1104 | MHD_mutex_unlock_chk_ (&response->mutex); |
1108 | #endif | 1105 | #endif |
1109 | return MHD_NO; | 1106 | return MHD_NO; |
1110 | } | 1107 | } |
1111 | if (ret > 0xFFFFFF) | 1108 | if (ret > 0xFFFFFF) |
1112 | ret = 0xFFFFFF; | 1109 | ret = 0xFFFFFF; |
1113 | cblen = MHD_snprintf_(cbuf, | 1110 | cblen = MHD_snprintf_ (cbuf, |
1114 | sizeof (cbuf), | 1111 | sizeof (cbuf), |
1115 | "%X\r\n", | 1112 | "%X\r\n", |
1116 | (unsigned int) ret); | 1113 | (unsigned int) ret); |
1117 | mhd_assert(cblen > 0); | 1114 | mhd_assert (cblen > 0); |
1118 | mhd_assert((size_t)cblen < sizeof(cbuf)); | 1115 | mhd_assert ((size_t) cblen < sizeof(cbuf)); |
1119 | memcpy (&connection->write_buffer[sizeof (cbuf) - cblen], | 1116 | memcpy (&connection->write_buffer[sizeof (cbuf) - cblen], |
1120 | cbuf, | 1117 | cbuf, |
1121 | cblen); | 1118 | cblen); |
@@ -1156,33 +1153,34 @@ keepalive_possible (struct MHD_Connection *connection) | |||
1156 | (0 != (connection->response->flags & MHD_RF_HTTP_VERSION_1_0_ONLY) ) ) | 1153 | (0 != (connection->response->flags & MHD_RF_HTTP_VERSION_1_0_ONLY) ) ) |
1157 | return MHD_NO; | 1154 | return MHD_NO; |
1158 | 1155 | ||
1159 | if (MHD_str_equal_caseless_(connection->version, | 1156 | if (MHD_str_equal_caseless_ (connection->version, |
1160 | MHD_HTTP_VERSION_1_1) && | 1157 | MHD_HTTP_VERSION_1_1) && |
1161 | ( (NULL == connection->response) || | 1158 | ( (NULL == connection->response) || |
1162 | (0 == (connection->response->flags & MHD_RF_HTTP_VERSION_1_0_RESPONSE) ) ) ) | 1159 | (0 == (connection->response->flags |
1163 | { | 1160 | & MHD_RF_HTTP_VERSION_1_0_RESPONSE) ) ) ) |
1164 | if (MHD_lookup_header_s_token_ci (connection, | 1161 | { |
1165 | MHD_HTTP_HEADER_CONNECTION, | 1162 | if (MHD_lookup_header_s_token_ci (connection, |
1166 | "upgrade")) | 1163 | MHD_HTTP_HEADER_CONNECTION, |
1167 | return MHD_NO; | 1164 | "upgrade")) |
1165 | return MHD_NO; | ||
1168 | 1166 | ||
1169 | if (MHD_lookup_header_s_token_ci (connection, | 1167 | if (MHD_lookup_header_s_token_ci (connection, |
1170 | MHD_HTTP_HEADER_CONNECTION, | 1168 | MHD_HTTP_HEADER_CONNECTION, |
1171 | "close")) | 1169 | "close")) |
1172 | return MHD_NO; | 1170 | return MHD_NO; |
1173 | 1171 | ||
1172 | return MHD_YES; | ||
1173 | } | ||
1174 | if (MHD_str_equal_caseless_ (connection->version, | ||
1175 | MHD_HTTP_VERSION_1_0)) | ||
1176 | { | ||
1177 | if (MHD_lookup_header_s_token_ci (connection, | ||
1178 | MHD_HTTP_HEADER_CONNECTION, | ||
1179 | "Keep-Alive")) | ||
1174 | return MHD_YES; | 1180 | return MHD_YES; |
1175 | } | ||
1176 | if (MHD_str_equal_caseless_(connection->version, | ||
1177 | MHD_HTTP_VERSION_1_0)) | ||
1178 | { | ||
1179 | if (MHD_lookup_header_s_token_ci (connection, | ||
1180 | MHD_HTTP_HEADER_CONNECTION, | ||
1181 | "Keep-Alive")) | ||
1182 | return MHD_YES; | ||
1183 | 1181 | ||
1184 | return MHD_NO; | 1182 | return MHD_NO; |
1185 | } | 1183 | } |
1186 | return MHD_NO; | 1184 | return MHD_NO; |
1187 | } | 1185 | } |
1188 | 1186 | ||
@@ -1196,7 +1194,7 @@ keepalive_possible (struct MHD_Connection *connection) | |||
1196 | */ | 1194 | */ |
1197 | static void | 1195 | static void |
1198 | get_date_string (char *date, | 1196 | get_date_string (char *date, |
1199 | size_t date_len) | 1197 | size_t date_len) |
1200 | { | 1198 | { |
1201 | static const char *const days[] = { | 1199 | static const char *const days[] = { |
1202 | "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" | 1200 | "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" |
@@ -1207,8 +1205,9 @@ get_date_string (char *date, | |||
1207 | }; | 1205 | }; |
1208 | struct tm now; | 1206 | struct tm now; |
1209 | time_t t; | 1207 | time_t t; |
1210 | #if !defined(HAVE_C11_GMTIME_S) && !defined(HAVE_W32_GMTIME_S) && !defined(HAVE_GMTIME_R) | 1208 | #if ! defined(HAVE_C11_GMTIME_S) && ! defined(HAVE_W32_GMTIME_S) && \ |
1211 | struct tm* pNow; | 1209 | ! defined(HAVE_GMTIME_R) |
1210 | struct tm*pNow; | ||
1212 | #endif | 1211 | #endif |
1213 | 1212 | ||
1214 | date[0] = 0; | 1213 | date[0] = 0; |
@@ -1222,25 +1221,25 @@ get_date_string (char *date, | |||
1222 | &t)) | 1221 | &t)) |
1223 | return; | 1222 | return; |
1224 | #elif defined(HAVE_GMTIME_R) | 1223 | #elif defined(HAVE_GMTIME_R) |
1225 | if (NULL == gmtime_r(&t, | 1224 | if (NULL == gmtime_r (&t, |
1226 | &now)) | 1225 | &now)) |
1227 | return; | 1226 | return; |
1228 | #else | 1227 | #else |
1229 | pNow = gmtime(&t); | 1228 | pNow = gmtime (&t); |
1230 | if (NULL == pNow) | 1229 | if (NULL == pNow) |
1231 | return; | 1230 | return; |
1232 | now = *pNow; | 1231 | now = *pNow; |
1233 | #endif | 1232 | #endif |
1234 | MHD_snprintf_ (date, | 1233 | MHD_snprintf_ (date, |
1235 | date_len, | 1234 | date_len, |
1236 | "Date: %3s, %02u %3s %04u %02u:%02u:%02u GMT\r\n", | 1235 | "Date: %3s, %02u %3s %04u %02u:%02u:%02u GMT\r\n", |
1237 | days[now.tm_wday % 7], | 1236 | days[now.tm_wday % 7], |
1238 | (unsigned int) now.tm_mday, | 1237 | (unsigned int) now.tm_mday, |
1239 | mons[now.tm_mon % 12], | 1238 | mons[now.tm_mon % 12], |
1240 | (unsigned int) (1900 + now.tm_year), | 1239 | (unsigned int) (1900 + now.tm_year), |
1241 | (unsigned int) now.tm_hour, | 1240 | (unsigned int) now.tm_hour, |
1242 | (unsigned int) now.tm_min, | 1241 | (unsigned int) now.tm_min, |
1243 | (unsigned int) now.tm_sec); | 1242 | (unsigned int) now.tm_sec); |
1244 | } | 1243 | } |
1245 | 1244 | ||
1246 | 1245 | ||
@@ -1269,26 +1268,26 @@ try_grow_read_buffer (struct MHD_Connection *connection, | |||
1269 | if (0 == connection->read_buffer_size) | 1268 | if (0 == connection->read_buffer_size) |
1270 | new_size = avail_size / 2; /* Use half of available buffer for reading */ | 1269 | new_size = avail_size / 2; /* Use half of available buffer for reading */ |
1271 | else | 1270 | else |
1272 | { | 1271 | { |
1273 | size_t grow_size; | 1272 | size_t grow_size; |
1274 | 1273 | ||
1275 | grow_size = avail_size / 8; | 1274 | grow_size = avail_size / 8; |
1276 | if (MHD_BUF_INC_SIZE > grow_size) | 1275 | if (MHD_BUF_INC_SIZE > grow_size) |
1277 | { /* Shortage of space */ | 1276 | { /* Shortage of space */ |
1278 | if (!required) | 1277 | if (! required) |
1279 | return false; /* Grow is not mandatory, leave some space in pool */ | 1278 | return false; /* Grow is not mandatory, leave some space in pool */ |
1280 | else | 1279 | else |
1281 | { | 1280 | { |
1282 | /* Shortage of space, but grow is mandatory */ | 1281 | /* Shortage of space, but grow is mandatory */ |
1283 | static const size_t small_inc = MHD_BUF_INC_SIZE / 8; | 1282 | static const size_t small_inc = MHD_BUF_INC_SIZE / 8; |
1284 | if (small_inc < avail_size) | 1283 | if (small_inc < avail_size) |
1285 | grow_size = small_inc; | 1284 | grow_size = small_inc; |
1286 | else | 1285 | else |
1287 | grow_size = avail_size; | 1286 | grow_size = avail_size; |
1288 | } | 1287 | } |
1289 | } | ||
1290 | new_size = connection->read_buffer_size + grow_size; | ||
1291 | } | 1288 | } |
1289 | new_size = connection->read_buffer_size + grow_size; | ||
1290 | } | ||
1292 | /* we can actually grow the buffer, do it! */ | 1291 | /* we can actually grow the buffer, do it! */ |
1293 | connection->read_buffer = MHD_pool_reallocate (connection->pool, | 1292 | connection->read_buffer = MHD_pool_reallocate (connection->pool, |
1294 | connection->read_buffer, | 1293 | connection->read_buffer, |
@@ -1337,53 +1336,55 @@ build_header_response (struct MHD_Connection *connection) | |||
1337 | 1336 | ||
1338 | mhd_assert (NULL != connection->version); | 1337 | mhd_assert (NULL != connection->version); |
1339 | if (0 == connection->version[0]) | 1338 | if (0 == connection->version[0]) |
1340 | { | 1339 | { |
1341 | data = MHD_pool_allocate (connection->pool, | 1340 | data = MHD_pool_allocate (connection->pool, |
1342 | 0, | 1341 | 0, |
1343 | true); | 1342 | true); |
1344 | connection->write_buffer = data; | 1343 | connection->write_buffer = data; |
1345 | connection->write_buffer_append_offset = 0; | 1344 | connection->write_buffer_append_offset = 0; |
1346 | connection->write_buffer_send_offset = 0; | 1345 | connection->write_buffer_send_offset = 0; |
1347 | connection->write_buffer_size = 0; | 1346 | connection->write_buffer_size = 0; |
1348 | return MHD_YES; | 1347 | return MHD_YES; |
1349 | } | 1348 | } |
1350 | rc = connection->responseCode & (~MHD_ICY_FLAG); | 1349 | rc = connection->responseCode & (~MHD_ICY_FLAG); |
1351 | if (MHD_CONNECTION_FOOTERS_RECEIVED == connection->state) | 1350 | if (MHD_CONNECTION_FOOTERS_RECEIVED == connection->state) |
1352 | { | 1351 | { |
1353 | reason_phrase = MHD_get_reason_phrase_for (rc); | 1352 | reason_phrase = MHD_get_reason_phrase_for (rc); |
1354 | off = MHD_snprintf_ (code, | 1353 | off = MHD_snprintf_ (code, |
1355 | sizeof (code), | 1354 | sizeof (code), |
1356 | "%s %u %s\r\n", | 1355 | "%s %u %s\r\n", |
1357 | (0 != (connection->responseCode & MHD_ICY_FLAG)) | 1356 | (0 != (connection->responseCode & MHD_ICY_FLAG)) |
1358 | ? "ICY" | 1357 | ? "ICY" |
1359 | : ( (MHD_str_equal_caseless_ (MHD_HTTP_VERSION_1_0, | 1358 | : ( (MHD_str_equal_caseless_ (MHD_HTTP_VERSION_1_0, |
1360 | connection->version) || | 1359 | connection->version) || |
1361 | (0 != (connection->response->flags & MHD_RF_HTTP_VERSION_1_0_RESPONSE)) ) | 1360 | (0 != (connection->response->flags |
1362 | ? MHD_HTTP_VERSION_1_0 | 1361 | & MHD_RF_HTTP_VERSION_1_0_RESPONSE)) ) |
1363 | : MHD_HTTP_VERSION_1_1), | 1362 | ? MHD_HTTP_VERSION_1_0 |
1364 | rc, | 1363 | : MHD_HTTP_VERSION_1_1), |
1365 | reason_phrase); | 1364 | rc, |
1366 | /* estimate size */ | 1365 | reason_phrase); |
1367 | size = off + 2; /* +2 for extra "\r\n" at the end */ | 1366 | /* estimate size */ |
1368 | kind = MHD_HEADER_KIND; | 1367 | size = off + 2; /* +2 for extra "\r\n" at the end */ |
1369 | if ( (0 == (connection->daemon->options & MHD_USE_SUPPRESS_DATE_NO_CLOCK)) && | 1368 | kind = MHD_HEADER_KIND; |
1370 | (NULL == MHD_get_response_header (response, | 1369 | if ( (0 == (connection->daemon->options |
1371 | MHD_HTTP_HEADER_DATE)) ) | 1370 | & MHD_USE_SUPPRESS_DATE_NO_CLOCK)) && |
1372 | get_date_string (date, | 1371 | (NULL == MHD_get_response_header (response, |
1373 | sizeof (date)); | 1372 | MHD_HTTP_HEADER_DATE)) ) |
1374 | else | 1373 | get_date_string (date, |
1375 | date[0] = '\0'; | 1374 | sizeof (date)); |
1376 | datelen = strlen (date); | 1375 | else |
1377 | size += datelen; | 1376 | date[0] = '\0'; |
1378 | } | 1377 | datelen = strlen (date); |
1378 | size += datelen; | ||
1379 | } | ||
1379 | else | 1380 | else |
1380 | { | 1381 | { |
1381 | /* 2 bytes for final CRLF of a Chunked-Body */ | 1382 | /* 2 bytes for final CRLF of a Chunked-Body */ |
1382 | size = 2; | 1383 | size = 2; |
1383 | kind = MHD_FOOTER_KIND; | 1384 | kind = MHD_FOOTER_KIND; |
1384 | off = 0; | 1385 | off = 0; |
1385 | datelen = 0; | 1386 | datelen = 0; |
1386 | } | 1387 | } |
1387 | 1388 | ||
1388 | /* calculate extra headers we need to add, such as 'Connection: close', | 1389 | /* calculate extra headers we need to add, such as 'Connection: close', |
1389 | first see what was explicitly requested by the application */ | 1390 | first see what was explicitly requested by the application */ |
@@ -1393,160 +1394,161 @@ build_header_response (struct MHD_Connection *connection) | |||
1393 | must_add_content_length = MHD_NO; | 1394 | must_add_content_length = MHD_NO; |
1394 | response_has_close = false; | 1395 | response_has_close = false; |
1395 | switch (connection->state) | 1396 | switch (connection->state) |
1396 | { | 1397 | { |
1397 | case MHD_CONNECTION_FOOTERS_RECEIVED: | 1398 | case MHD_CONNECTION_FOOTERS_RECEIVED: |
1398 | response_has_close = MHD_check_response_header_s_token_ci (response, | 1399 | response_has_close = MHD_check_response_header_s_token_ci (response, |
1399 | MHD_HTTP_HEADER_CONNECTION, | 1400 | MHD_HTTP_HEADER_CONNECTION, |
1400 | "close"); | 1401 | "close"); |
1401 | response_has_keepalive = MHD_check_response_header_s_token_ci (response, | 1402 | response_has_keepalive = MHD_check_response_header_s_token_ci (response, |
1402 | MHD_HTTP_HEADER_CONNECTION, | 1403 | MHD_HTTP_HEADER_CONNECTION, |
1403 | "Keep-Alive"); | 1404 | "Keep-Alive"); |
1404 | client_requested_close = MHD_lookup_header_s_token_ci (connection, | 1405 | client_requested_close = MHD_lookup_header_s_token_ci (connection, |
1405 | MHD_HTTP_HEADER_CONNECTION, | 1406 | MHD_HTTP_HEADER_CONNECTION, |
1406 | "close"); | 1407 | "close"); |
1407 | 1408 | ||
1408 | if (0 != (response->flags & MHD_RF_HTTP_VERSION_1_0_ONLY)) | 1409 | if (0 != (response->flags & MHD_RF_HTTP_VERSION_1_0_ONLY)) |
1409 | connection->keepalive = MHD_CONN_MUST_CLOSE; | 1410 | connection->keepalive = MHD_CONN_MUST_CLOSE; |
1410 | #ifdef UPGRADE_SUPPORT | 1411 | #ifdef UPGRADE_SUPPORT |
1411 | else if (NULL != response->upgrade_handler) | 1412 | else if (NULL != response->upgrade_handler) |
1412 | /* If this connection will not be "upgraded", it must be closed. */ | 1413 | /* If this connection will not be "upgraded", it must be closed. */ |
1413 | connection->keepalive = MHD_CONN_MUST_CLOSE; | 1414 | connection->keepalive = MHD_CONN_MUST_CLOSE; |
1414 | #endif /* UPGRADE_SUPPORT */ | 1415 | #endif /* UPGRADE_SUPPORT */ |
1415 | 1416 | ||
1416 | /* now analyze chunked encoding situation */ | 1417 | /* now analyze chunked encoding situation */ |
1417 | connection->have_chunked_upload = false; | 1418 | connection->have_chunked_upload = false; |
1418 | have_encoding = MHD_get_response_header (response, | 1419 | have_encoding = MHD_get_response_header (response, |
1419 | MHD_HTTP_HEADER_TRANSFER_ENCODING); | 1420 | MHD_HTTP_HEADER_TRANSFER_ENCODING); |
1420 | if (NULL == have_encoding) | 1421 | if (NULL == have_encoding) |
1421 | may_add_content_length = MHD_YES; | 1422 | may_add_content_length = MHD_YES; |
1422 | else | 1423 | else |
1423 | may_add_content_length = MHD_NO; /* RFC 7230, Section 3.3.2 forbids header */ | 1424 | may_add_content_length = MHD_NO; /* RFC 7230, Section 3.3.2 forbids header */ |
1424 | if ( (MHD_SIZE_UNKNOWN == response->total_size) && | 1425 | if ( (MHD_SIZE_UNKNOWN == response->total_size) && |
1425 | #ifdef UPGRADE_SUPPORT | 1426 | #ifdef UPGRADE_SUPPORT |
1426 | (NULL == response->upgrade_handler) && | 1427 | (NULL == response->upgrade_handler) && |
1427 | #endif /* UPGRADE_SUPPORT */ | 1428 | #endif /* UPGRADE_SUPPORT */ |
1428 | (! response_has_close) && | 1429 | (! response_has_close) && |
1429 | (! client_requested_close) ) | 1430 | (! client_requested_close) ) |
1431 | { | ||
1432 | /* size is unknown, and close was not explicitly requested; | ||
1433 | need to either to HTTP 1.1 chunked encoding or | ||
1434 | close the connection */ | ||
1435 | /* 'close' header doesn't exist yet, see if we need to add one; | ||
1436 | if the client asked for a close, no need to start chunk'ing */ | ||
1437 | if ( (MHD_YES == keepalive_possible (connection)) && | ||
1438 | (MHD_str_equal_caseless_ (MHD_HTTP_VERSION_1_1, | ||
1439 | connection->version) ) ) | ||
1440 | { | ||
1441 | if (NULL == have_encoding) | ||
1442 | { | ||
1443 | must_add_chunked_encoding = MHD_YES; | ||
1444 | connection->have_chunked_upload = true; | ||
1445 | } | ||
1446 | else | ||
1430 | { | 1447 | { |
1431 | /* size is unknown, and close was not explicitly requested; | 1448 | if (MHD_str_equal_caseless_ (have_encoding, |
1432 | need to either to HTTP 1.1 chunked encoding or | 1449 | "identity")) |
1433 | close the connection */ | 1450 | { |
1434 | /* 'close' header doesn't exist yet, see if we need to add one; | 1451 | /* application forced identity encoding, can't do 'chunked' */ |
1435 | if the client asked for a close, no need to start chunk'ing */ | 1452 | must_add_close = MHD_YES; |
1436 | if ( (MHD_YES == keepalive_possible (connection)) && | 1453 | } |
1437 | (MHD_str_equal_caseless_ (MHD_HTTP_VERSION_1_1, | ||
1438 | connection->version) ) ) | ||
1439 | { | ||
1440 | if (NULL == have_encoding) | ||
1441 | { | ||
1442 | must_add_chunked_encoding = MHD_YES; | ||
1443 | connection->have_chunked_upload = true; | ||
1444 | } | ||
1445 | else | ||
1446 | { | ||
1447 | if (MHD_str_equal_caseless_ (have_encoding, | ||
1448 | "identity")) | ||
1449 | { | ||
1450 | /* application forced identity encoding, can't do 'chunked' */ | ||
1451 | must_add_close = MHD_YES; | ||
1452 | } | ||
1453 | else | ||
1454 | { | ||
1455 | connection->have_chunked_upload = true; | ||
1456 | } | ||
1457 | } | ||
1458 | } | ||
1459 | else | 1454 | else |
1460 | { | 1455 | { |
1461 | /* Keep alive or chunking not possible | 1456 | connection->have_chunked_upload = true; |
1462 | => set close header if not present */ | 1457 | } |
1463 | if (! response_has_close) | ||
1464 | must_add_close = MHD_YES; | ||
1465 | } | ||
1466 | } | 1458 | } |
1459 | } | ||
1460 | else | ||
1461 | { | ||
1462 | /* Keep alive or chunking not possible | ||
1463 | => set close header if not present */ | ||
1464 | if (! response_has_close) | ||
1465 | must_add_close = MHD_YES; | ||
1466 | } | ||
1467 | } | ||
1467 | 1468 | ||
1468 | /* check for other reasons to add 'close' header */ | 1469 | /* check for other reasons to add 'close' header */ |
1469 | if ( ( (client_requested_close) || | 1470 | if ( ( (client_requested_close) || |
1470 | (connection->read_closed) || | 1471 | (connection->read_closed) || |
1471 | (MHD_CONN_MUST_CLOSE == connection->keepalive)) && | 1472 | (MHD_CONN_MUST_CLOSE == connection->keepalive)) && |
1472 | (! response_has_close) && | 1473 | (! response_has_close) && |
1473 | #ifdef UPGRADE_SUPPORT | 1474 | #ifdef UPGRADE_SUPPORT |
1474 | (NULL == response->upgrade_handler) && | 1475 | (NULL == response->upgrade_handler) && |
1475 | #endif /* UPGRADE_SUPPORT */ | 1476 | #endif /* UPGRADE_SUPPORT */ |
1476 | (0 == (response->flags & MHD_RF_HTTP_VERSION_1_0_ONLY) ) ) | 1477 | (0 == (response->flags & MHD_RF_HTTP_VERSION_1_0_ONLY) ) ) |
1477 | must_add_close = MHD_YES; | 1478 | must_add_close = MHD_YES; |
1478 | 1479 | ||
1479 | /* check if we must add 'close' header because we cannot add content-length | 1480 | /* check if we must add 'close' header because we cannot add content-length |
1480 | because it is forbidden AND we don't have a 'chunked' encoding */ | 1481 | because it is forbidden AND we don't have a 'chunked' encoding */ |
1481 | if ( (! may_add_content_length) && | 1482 | if ( (! may_add_content_length) && |
1482 | (! connection->have_chunked_upload) && | 1483 | (! connection->have_chunked_upload) && |
1483 | (! response_has_close) ) | 1484 | (! response_has_close) ) |
1484 | must_add_close = MHD_YES; | 1485 | must_add_close = MHD_YES; |
1485 | /* #MHD_HTTP_NO_CONTENT, #MHD_HTTP_NOT_MODIFIED and 1xx-status | 1486 | /* #MHD_HTTP_NO_CONTENT, #MHD_HTTP_NOT_MODIFIED and 1xx-status |
1486 | codes SHOULD NOT have a Content-Length according to spec; | 1487 | codes SHOULD NOT have a Content-Length according to spec; |
1487 | also chunked encoding / unknown length or CONNECT... */ | 1488 | also chunked encoding / unknown length or CONNECT... */ |
1488 | if ( (MHD_SIZE_UNKNOWN != response->total_size) && | 1489 | if ( (MHD_SIZE_UNKNOWN != response->total_size) && |
1489 | (MHD_HTTP_NO_CONTENT != rc) && | 1490 | (MHD_HTTP_NO_CONTENT != rc) && |
1490 | (MHD_HTTP_NOT_MODIFIED != rc) && | 1491 | (MHD_HTTP_NOT_MODIFIED != rc) && |
1491 | (MHD_HTTP_OK <= rc) && | 1492 | (MHD_HTTP_OK <= rc) && |
1492 | (NULL == /* this should always succeed due to check in | 1493 | (NULL == /* this should always succeed due to check in |
1493 | MHD_add_response_header() */ | 1494 | MHD_add_response_header() */ |
1494 | MHD_get_response_header (response, | 1495 | MHD_get_response_header (response, |
1495 | MHD_HTTP_HEADER_CONTENT_LENGTH)) && | 1496 | MHD_HTTP_HEADER_CONTENT_LENGTH)) && |
1496 | (may_add_content_length) && | 1497 | (may_add_content_length) && |
1497 | ( (NULL == connection->method) || | 1498 | ( (NULL == connection->method) || |
1498 | (! MHD_str_equal_caseless_ (connection->method, | 1499 | (! MHD_str_equal_caseless_ (connection->method, |
1499 | MHD_HTTP_METHOD_CONNECT)) ) ) | 1500 | MHD_HTTP_METHOD_CONNECT)) ) ) |
1500 | { | 1501 | { |
1501 | /* | 1502 | /* |
1502 | Here we add a content-length if one is missing; however, | 1503 | Here we add a content-length if one is missing; however, |
1503 | for 'connect' methods, the responses MUST NOT include a | 1504 | for 'connect' methods, the responses MUST NOT include a |
1504 | content-length header *if* the response code is 2xx (in | 1505 | content-length header *if* the response code is 2xx (in |
1505 | which case we expect there to be no body). Still, | 1506 | which case we expect there to be no body). Still, |
1506 | as we don't know the response code here in some cases, we | 1507 | as we don't know the response code here in some cases, we |
1507 | simply only force adding a content-length header if this | 1508 | simply only force adding a content-length header if this |
1508 | is not a 'connect' or if the response is not empty | 1509 | is not a 'connect' or if the response is not empty |
1509 | (which is kind of more sane, because if some crazy | 1510 | (which is kind of more sane, because if some crazy |
1510 | application did return content with a 2xx status code, | 1511 | application did return content with a 2xx status code, |
1511 | then having a content-length might again be a good idea). | 1512 | then having a content-length might again be a good idea). |
1512 | 1513 | ||
1513 | Note that the change from 'SHOULD NOT' to 'MUST NOT' is | 1514 | Note that the change from 'SHOULD NOT' to 'MUST NOT' is |
1514 | a recent development of the HTTP 1.1 specification. | 1515 | a recent development of the HTTP 1.1 specification. |
1515 | */ | 1516 | */ |
1516 | content_length_len | 1517 | content_length_len |
1517 | = MHD_snprintf_ (content_length_buf, | 1518 | = MHD_snprintf_ (content_length_buf, |
1518 | sizeof (content_length_buf), | 1519 | sizeof (content_length_buf), |
1519 | MHD_HTTP_HEADER_CONTENT_LENGTH ": " MHD_UNSIGNED_LONG_LONG_PRINTF "\r\n", | 1520 | MHD_HTTP_HEADER_CONTENT_LENGTH ": " |
1520 | (MHD_UNSIGNED_LONG_LONG) response->total_size); | 1521 | MHD_UNSIGNED_LONG_LONG_PRINTF "\r\n", |
1521 | must_add_content_length = MHD_YES; | 1522 | (MHD_UNSIGNED_LONG_LONG) response->total_size); |
1522 | } | 1523 | must_add_content_length = MHD_YES; |
1524 | } | ||
1523 | 1525 | ||
1524 | /* check for adding keep alive */ | 1526 | /* check for adding keep alive */ |
1525 | if ( (! response_has_keepalive) && | 1527 | if ( (! response_has_keepalive) && |
1526 | (! response_has_close) && | 1528 | (! response_has_close) && |
1527 | (MHD_NO == must_add_close) && | 1529 | (MHD_NO == must_add_close) && |
1528 | (MHD_CONN_MUST_CLOSE != connection->keepalive) && | 1530 | (MHD_CONN_MUST_CLOSE != connection->keepalive) && |
1529 | #ifdef UPGRADE_SUPPORT | 1531 | #ifdef UPGRADE_SUPPORT |
1530 | (NULL == response->upgrade_handler) && | 1532 | (NULL == response->upgrade_handler) && |
1531 | #endif /* UPGRADE_SUPPORT */ | 1533 | #endif /* UPGRADE_SUPPORT */ |
1532 | (MHD_YES == keepalive_possible (connection)) ) | 1534 | (MHD_YES == keepalive_possible (connection)) ) |
1533 | must_add_keep_alive = MHD_YES; | 1535 | must_add_keep_alive = MHD_YES; |
1534 | break; | 1536 | break; |
1535 | case MHD_CONNECTION_BODY_SENT: | 1537 | case MHD_CONNECTION_BODY_SENT: |
1536 | response_has_keepalive = false; | 1538 | response_has_keepalive = false; |
1537 | break; | 1539 | break; |
1538 | default: | 1540 | default: |
1539 | mhd_assert (0); | 1541 | mhd_assert (0); |
1540 | return MHD_NO; | 1542 | return MHD_NO; |
1541 | } | 1543 | } |
1542 | 1544 | ||
1543 | if (MHD_CONN_MUST_CLOSE != connection->keepalive) | 1545 | if (MHD_CONN_MUST_CLOSE != connection->keepalive) |
1544 | { | 1546 | { |
1545 | if ( (must_add_close) || (response_has_close) ) | 1547 | if ( (must_add_close) || (response_has_close) ) |
1546 | connection->keepalive = MHD_CONN_MUST_CLOSE; | 1548 | connection->keepalive = MHD_CONN_MUST_CLOSE; |
1547 | else if ( (must_add_keep_alive) || (response_has_keepalive) ) | 1549 | else if ( (must_add_keep_alive) || (response_has_keepalive) ) |
1548 | connection->keepalive = MHD_CONN_USE_KEEPALIVE; | 1550 | connection->keepalive = MHD_CONN_USE_KEEPALIVE; |
1549 | } | 1551 | } |
1550 | 1552 | ||
1551 | if (must_add_close) | 1553 | if (must_add_close) |
1552 | size += MHD_STATICSTR_LEN_ ("Connection: close\r\n"); | 1554 | size += MHD_STATICSTR_LEN_ ("Connection: close\r\n"); |
@@ -1560,94 +1562,98 @@ build_header_response (struct MHD_Connection *connection) | |||
1560 | mhd_assert (! (must_add_chunked_encoding && must_add_content_length) ); | 1562 | mhd_assert (! (must_add_chunked_encoding && must_add_content_length) ); |
1561 | 1563 | ||
1562 | for (pos = response->first_header; NULL != pos; pos = pos->next) | 1564 | for (pos = response->first_header; NULL != pos; pos = pos->next) |
1563 | { | 1565 | { |
1564 | /* TODO: add proper support for excluding "Keep-Alive" token. */ | 1566 | /* TODO: add proper support for excluding "Keep-Alive" token. */ |
1565 | if ( (pos->kind == kind) && | 1567 | if ( (pos->kind == kind) && |
1566 | (! ( (MHD_YES == must_add_close) && | 1568 | (! ( (MHD_YES == must_add_close) && |
1567 | (response_has_keepalive) && | 1569 | (response_has_keepalive) && |
1568 | (pos->header_size == MHD_STATICSTR_LEN_(MHD_HTTP_HEADER_CONNECTION)) && | 1570 | (pos->header_size == MHD_STATICSTR_LEN_ ( |
1569 | (MHD_str_equal_caseless_bin_n_(pos->header, | 1571 | MHD_HTTP_HEADER_CONNECTION)) && |
1570 | MHD_HTTP_HEADER_CONNECTION, | 1572 | (MHD_str_equal_caseless_bin_n_ (pos->header, |
1571 | MHD_STATICSTR_LEN_(MHD_HTTP_HEADER_CONNECTION))) && | 1573 | MHD_HTTP_HEADER_CONNECTION, |
1572 | (MHD_str_equal_caseless_(pos->value, | 1574 | MHD_STATICSTR_LEN_ ( |
1573 | "Keep-Alive")) ) ) ) | 1575 | MHD_HTTP_HEADER_CONNECTION))) && |
1574 | size += pos->header_size + pos->value_size + 4; /* colon, space, linefeeds */ | 1576 | (MHD_str_equal_caseless_ (pos->value, |
1575 | } | 1577 | "Keep-Alive")) ) ) ) |
1578 | size += pos->header_size + pos->value_size + 4; /* colon, space, linefeeds */ | ||
1579 | } | ||
1576 | /* produce data */ | 1580 | /* produce data */ |
1577 | data = MHD_pool_allocate (connection->pool, | 1581 | data = MHD_pool_allocate (connection->pool, |
1578 | size + 1, | 1582 | size + 1, |
1579 | false); | 1583 | false); |
1580 | if (NULL == data) | 1584 | if (NULL == data) |
1581 | { | 1585 | { |
1582 | #ifdef HAVE_MESSAGES | 1586 | #ifdef HAVE_MESSAGES |
1583 | MHD_DLOG (connection->daemon, | 1587 | MHD_DLOG (connection->daemon, |
1584 | "Not enough memory for write!\n"); | 1588 | "Not enough memory for write!\n"); |
1585 | #endif | 1589 | #endif |
1586 | return MHD_NO; | 1590 | return MHD_NO; |
1587 | } | 1591 | } |
1588 | if (MHD_CONNECTION_FOOTERS_RECEIVED == connection->state) | 1592 | if (MHD_CONNECTION_FOOTERS_RECEIVED == connection->state) |
1589 | { | 1593 | { |
1590 | memcpy (data, | 1594 | memcpy (data, |
1591 | code, | 1595 | code, |
1592 | off); | 1596 | off); |
1593 | } | 1597 | } |
1594 | if (must_add_close) | 1598 | if (must_add_close) |
1595 | { | 1599 | { |
1596 | /* we must add the 'Connection: close' header */ | 1600 | /* we must add the 'Connection: close' header */ |
1597 | memcpy (&data[off], | 1601 | memcpy (&data[off], |
1598 | "Connection: close\r\n", | 1602 | "Connection: close\r\n", |
1599 | MHD_STATICSTR_LEN_ ("Connection: close\r\n")); | 1603 | MHD_STATICSTR_LEN_ ("Connection: close\r\n")); |
1600 | off += MHD_STATICSTR_LEN_ ("Connection: close\r\n"); | 1604 | off += MHD_STATICSTR_LEN_ ("Connection: close\r\n"); |
1601 | } | 1605 | } |
1602 | if (must_add_keep_alive) | 1606 | if (must_add_keep_alive) |
1603 | { | 1607 | { |
1604 | /* we must add the 'Connection: Keep-Alive' header */ | 1608 | /* we must add the 'Connection: Keep-Alive' header */ |
1605 | memcpy (&data[off], | 1609 | memcpy (&data[off], |
1606 | "Connection: Keep-Alive\r\n", | 1610 | "Connection: Keep-Alive\r\n", |
1607 | MHD_STATICSTR_LEN_ ("Connection: Keep-Alive\r\n")); | 1611 | MHD_STATICSTR_LEN_ ("Connection: Keep-Alive\r\n")); |
1608 | off += MHD_STATICSTR_LEN_ ("Connection: Keep-Alive\r\n"); | 1612 | off += MHD_STATICSTR_LEN_ ("Connection: Keep-Alive\r\n"); |
1609 | } | 1613 | } |
1610 | if (must_add_chunked_encoding) | 1614 | if (must_add_chunked_encoding) |
1611 | { | 1615 | { |
1612 | /* we must add the 'Transfer-Encoding: chunked' header */ | 1616 | /* we must add the 'Transfer-Encoding: chunked' header */ |
1613 | memcpy (&data[off], | 1617 | memcpy (&data[off], |
1614 | "Transfer-Encoding: chunked\r\n", | 1618 | "Transfer-Encoding: chunked\r\n", |
1615 | MHD_STATICSTR_LEN_ ("Transfer-Encoding: chunked\r\n")); | 1619 | MHD_STATICSTR_LEN_ ("Transfer-Encoding: chunked\r\n")); |
1616 | off += MHD_STATICSTR_LEN_ ("Transfer-Encoding: chunked\r\n"); | 1620 | off += MHD_STATICSTR_LEN_ ("Transfer-Encoding: chunked\r\n"); |
1617 | } | 1621 | } |
1618 | if (must_add_content_length) | 1622 | if (must_add_content_length) |
1619 | { | 1623 | { |
1620 | /* we must add the 'Content-Length' header */ | 1624 | /* we must add the 'Content-Length' header */ |
1621 | memcpy (&data[off], | 1625 | memcpy (&data[off], |
1622 | content_length_buf, | 1626 | content_length_buf, |
1623 | content_length_len); | 1627 | content_length_len); |
1624 | off += content_length_len; | 1628 | off += content_length_len; |
1625 | } | 1629 | } |
1626 | for (pos = response->first_header; NULL != pos; pos = pos->next) | 1630 | for (pos = response->first_header; NULL != pos; pos = pos->next) |
1627 | { | 1631 | { |
1628 | /* TODO: add proper support for excluding "Keep-Alive" token. */ | 1632 | /* TODO: add proper support for excluding "Keep-Alive" token. */ |
1629 | if ( (pos->kind == kind) && | 1633 | if ( (pos->kind == kind) && |
1630 | (! ( (MHD_YES == must_add_close) && | 1634 | (! ( (MHD_YES == must_add_close) && |
1631 | (response_has_keepalive) && | 1635 | (response_has_keepalive) && |
1632 | (pos->header_size == MHD_STATICSTR_LEN_(MHD_HTTP_HEADER_CONNECTION)) && | 1636 | (pos->header_size == MHD_STATICSTR_LEN_ ( |
1633 | (MHD_str_equal_caseless_bin_n_(pos->header, | 1637 | MHD_HTTP_HEADER_CONNECTION)) && |
1634 | MHD_HTTP_HEADER_CONNECTION, | 1638 | (MHD_str_equal_caseless_bin_n_ (pos->header, |
1635 | MHD_STATICSTR_LEN_(MHD_HTTP_HEADER_CONNECTION))) && | 1639 | MHD_HTTP_HEADER_CONNECTION, |
1636 | (MHD_str_equal_caseless_(pos->value, | 1640 | MHD_STATICSTR_LEN_ ( |
1637 | "Keep-Alive")) ) ) ) | 1641 | MHD_HTTP_HEADER_CONNECTION))) && |
1638 | off += MHD_snprintf_ (&data[off], | 1642 | (MHD_str_equal_caseless_ (pos->value, |
1639 | size - off, | 1643 | "Keep-Alive")) ) ) ) |
1640 | "%s: %s\r\n", | 1644 | off += MHD_snprintf_ (&data[off], |
1641 | pos->header, | 1645 | size - off, |
1642 | pos->value); | 1646 | "%s: %s\r\n", |
1643 | } | 1647 | pos->header, |
1648 | pos->value); | ||
1649 | } | ||
1644 | if (MHD_CONNECTION_FOOTERS_RECEIVED == connection->state) | 1650 | if (MHD_CONNECTION_FOOTERS_RECEIVED == connection->state) |
1645 | { | 1651 | { |
1646 | memcpy (&data[off], | 1652 | memcpy (&data[off], |
1647 | date, | 1653 | date, |
1648 | datelen); | 1654 | datelen); |
1649 | off += datelen; | 1655 | off += datelen; |
1650 | } | 1656 | } |
1651 | memcpy (&data[off], | 1657 | memcpy (&data[off], |
1652 | "\r\n", | 1658 | "\r\n", |
1653 | 2); | 1659 | 2); |
@@ -1678,73 +1684,76 @@ build_header_response (struct MHD_Connection *connection) | |||
1678 | static void | 1684 | static void |
1679 | transmit_error_response (struct MHD_Connection *connection, | 1685 | transmit_error_response (struct MHD_Connection *connection, |
1680 | unsigned int status_code, | 1686 | unsigned int status_code, |
1681 | const char *message) | 1687 | const char *message) |
1682 | { | 1688 | { |
1683 | struct MHD_Response *response; | 1689 | struct MHD_Response *response; |
1684 | int iret; | 1690 | int iret; |
1685 | 1691 | ||
1686 | if (NULL == connection->version) | 1692 | if (NULL == connection->version) |
1687 | { | 1693 | { |
1688 | /* we were unable to process the full header line, so we don't | 1694 | /* we were unable to process the full header line, so we don't |
1689 | really know what version the client speaks; assume 1.0 */ | 1695 | really know what version the client speaks; assume 1.0 */ |
1690 | connection->version = MHD_HTTP_VERSION_1_0; | 1696 | connection->version = MHD_HTTP_VERSION_1_0; |
1691 | } | 1697 | } |
1692 | connection->state = MHD_CONNECTION_FOOTERS_RECEIVED; | 1698 | connection->state = MHD_CONNECTION_FOOTERS_RECEIVED; |
1693 | connection->read_closed = true; | 1699 | connection->read_closed = true; |
1694 | if (0 != connection->read_buffer_size) | 1700 | if (0 != connection->read_buffer_size) |
1695 | { | 1701 | { |
1696 | /* Read buffer is not needed anymore, discard it | 1702 | /* Read buffer is not needed anymore, discard it |
1697 | * to free some space for error response. */ | 1703 | * to free some space for error response. */ |
1698 | connection->read_buffer = MHD_pool_reallocate(connection->pool, | 1704 | connection->read_buffer = MHD_pool_reallocate (connection->pool, |
1699 | connection->read_buffer, | 1705 | connection->read_buffer, |
1700 | connection->read_buffer_size, | 1706 | connection->read_buffer_size, |
1701 | 0); | 1707 | 0); |
1702 | connection->read_buffer_size = 0; | 1708 | connection->read_buffer_size = 0; |
1703 | } | 1709 | } |
1704 | #ifdef HAVE_MESSAGES | 1710 | #ifdef HAVE_MESSAGES |
1705 | MHD_DLOG (connection->daemon, | 1711 | MHD_DLOG (connection->daemon, |
1706 | _("Error processing request (HTTP response code is %u (`%s')). Closing connection.\n"), | 1712 | _ ( |
1713 | "Error processing request (HTTP response code is %u (`%s')). Closing connection.\n"), | ||
1707 | status_code, | 1714 | status_code, |
1708 | message); | 1715 | message); |
1709 | #endif | 1716 | #endif |
1710 | if (NULL != connection->response) | 1717 | if (NULL != connection->response) |
1711 | { | 1718 | { |
1712 | MHD_destroy_response (connection->response); | 1719 | MHD_destroy_response (connection->response); |
1713 | connection->response = NULL; | 1720 | connection->response = NULL; |
1714 | } | 1721 | } |
1715 | response = MHD_create_response_from_buffer (strlen (message), | 1722 | response = MHD_create_response_from_buffer (strlen (message), |
1716 | (void *) message, | 1723 | (void *) message, |
1717 | MHD_RESPMEM_PERSISTENT); | 1724 | MHD_RESPMEM_PERSISTENT); |
1718 | if (NULL == response) | 1725 | if (NULL == response) |
1719 | { | 1726 | { |
1720 | /* can't even send a reply, at least close the connection */ | 1727 | /* can't even send a reply, at least close the connection */ |
1721 | connection->state = MHD_CONNECTION_CLOSED; | 1728 | connection->state = MHD_CONNECTION_CLOSED; |
1722 | return; | 1729 | return; |
1723 | } | 1730 | } |
1724 | iret = MHD_queue_response (connection, | 1731 | iret = MHD_queue_response (connection, |
1725 | status_code, | 1732 | status_code, |
1726 | response); | 1733 | response); |
1727 | MHD_destroy_response (response); | 1734 | MHD_destroy_response (response); |
1728 | if (MHD_YES != iret) | 1735 | if (MHD_YES != iret) |
1729 | { | 1736 | { |
1730 | /* can't even send a reply, at least close the connection */ | 1737 | /* can't even send a reply, at least close the connection */ |
1731 | CONNECTION_CLOSE_ERROR (connection, | 1738 | CONNECTION_CLOSE_ERROR (connection, |
1732 | _("Closing connection (failed to queue response)\n")); | 1739 | _ ( |
1733 | return; | 1740 | "Closing connection (failed to queue response)\n")); |
1734 | } | 1741 | return; |
1742 | } | ||
1735 | mhd_assert (NULL != connection->response); | 1743 | mhd_assert (NULL != connection->response); |
1736 | /* Do not reuse this connection. */ | 1744 | /* Do not reuse this connection. */ |
1737 | connection->keepalive = MHD_CONN_MUST_CLOSE; | 1745 | connection->keepalive = MHD_CONN_MUST_CLOSE; |
1738 | if (MHD_NO == build_header_response (connection)) | 1746 | if (MHD_NO == build_header_response (connection)) |
1739 | { | 1747 | { |
1740 | /* oops - close! */ | 1748 | /* oops - close! */ |
1741 | CONNECTION_CLOSE_ERROR (connection, | 1749 | CONNECTION_CLOSE_ERROR (connection, |
1742 | _("Closing connection (failed to create response header)\n")); | 1750 | _ ( |
1743 | } | 1751 | "Closing connection (failed to create response header)\n")); |
1752 | } | ||
1744 | else | 1753 | else |
1745 | { | 1754 | { |
1746 | connection->state = MHD_CONNECTION_HEADERS_SENDING; | 1755 | connection->state = MHD_CONNECTION_HEADERS_SENDING; |
1747 | } | 1756 | } |
1748 | } | 1757 | } |
1749 | 1758 | ||
1750 | 1759 | ||
@@ -1764,151 +1773,151 @@ MHD_connection_update_event_loop_info (struct MHD_Connection *connection) | |||
1764 | return; /* States will be updated after resume. */ | 1773 | return; /* States will be updated after resume. */ |
1765 | #ifdef HTTPS_SUPPORT | 1774 | #ifdef HTTPS_SUPPORT |
1766 | if (MHD_TLS_CONN_NO_TLS != connection->tls_state) | 1775 | if (MHD_TLS_CONN_NO_TLS != connection->tls_state) |
1767 | { /* HTTPS connection. */ | 1776 | { /* HTTPS connection. */ |
1768 | switch (connection->tls_state) | 1777 | switch (connection->tls_state) |
1769 | { | 1778 | { |
1770 | case MHD_TLS_CONN_INIT: | 1779 | case MHD_TLS_CONN_INIT: |
1771 | connection->event_loop_info = MHD_EVENT_LOOP_INFO_READ; | 1780 | connection->event_loop_info = MHD_EVENT_LOOP_INFO_READ; |
1772 | return; | 1781 | return; |
1773 | case MHD_TLS_CONN_HANDSHAKING: | 1782 | case MHD_TLS_CONN_HANDSHAKING: |
1774 | if (0 == gnutls_record_get_direction (connection->tls_session)) | 1783 | if (0 == gnutls_record_get_direction (connection->tls_session)) |
1775 | connection->event_loop_info = MHD_EVENT_LOOP_INFO_READ; | 1784 | connection->event_loop_info = MHD_EVENT_LOOP_INFO_READ; |
1776 | else | 1785 | else |
1777 | connection->event_loop_info = MHD_EVENT_LOOP_INFO_WRITE; | 1786 | connection->event_loop_info = MHD_EVENT_LOOP_INFO_WRITE; |
1778 | return; | 1787 | return; |
1779 | default: | 1788 | default: |
1780 | break; | 1789 | break; |
1781 | } | ||
1782 | } | 1790 | } |
1791 | } | ||
1783 | #endif /* HTTPS_SUPPORT */ | 1792 | #endif /* HTTPS_SUPPORT */ |
1784 | while (1) | 1793 | while (1) |
1785 | { | 1794 | { |
1786 | #if DEBUG_STATES | 1795 | #if DEBUG_STATES |
1787 | MHD_DLOG (connection->daemon, | 1796 | MHD_DLOG (connection->daemon, |
1788 | _("In function %s handling connection at state: %s\n"), | 1797 | _ ("In function %s handling connection at state: %s\n"), |
1789 | __FUNCTION__, | 1798 | __FUNCTION__, |
1790 | MHD_state_to_string (connection->state)); | 1799 | MHD_state_to_string (connection->state)); |
1791 | #endif | 1800 | #endif |
1792 | switch (connection->state) | 1801 | switch (connection->state) |
1802 | { | ||
1803 | case MHD_CONNECTION_INIT: | ||
1804 | case MHD_CONNECTION_URL_RECEIVED: | ||
1805 | case MHD_CONNECTION_HEADER_PART_RECEIVED: | ||
1806 | /* while reading headers, we always grow the | ||
1807 | read buffer if needed, no size-check required */ | ||
1808 | if ( (connection->read_buffer_offset == connection->read_buffer_size) && | ||
1809 | (! try_grow_read_buffer (connection, true)) ) | ||
1810 | { | ||
1811 | transmit_error_response (connection, | ||
1812 | (connection->url != NULL) | ||
1813 | ? MHD_HTTP_REQUEST_HEADER_FIELDS_TOO_LARGE | ||
1814 | : MHD_HTTP_URI_TOO_LONG, | ||
1815 | REQUEST_TOO_BIG); | ||
1816 | continue; | ||
1817 | } | ||
1818 | if (! connection->read_closed) | ||
1819 | connection->event_loop_info = MHD_EVENT_LOOP_INFO_READ; | ||
1820 | else | ||
1821 | connection->event_loop_info = MHD_EVENT_LOOP_INFO_BLOCK; | ||
1822 | break; | ||
1823 | case MHD_CONNECTION_HEADERS_RECEIVED: | ||
1824 | mhd_assert (0); | ||
1825 | break; | ||
1826 | case MHD_CONNECTION_HEADERS_PROCESSED: | ||
1827 | mhd_assert (0); | ||
1828 | break; | ||
1829 | case MHD_CONNECTION_CONTINUE_SENDING: | ||
1830 | connection->event_loop_info = MHD_EVENT_LOOP_INFO_WRITE; | ||
1831 | break; | ||
1832 | case MHD_CONNECTION_CONTINUE_SENT: | ||
1833 | if (connection->read_buffer_offset == connection->read_buffer_size) | ||
1834 | { | ||
1835 | const bool internal_poll = (0 != (connection->daemon->options | ||
1836 | & MHD_USE_INTERNAL_POLLING_THREAD)); | ||
1837 | if ( (! try_grow_read_buffer (connection, true)) && | ||
1838 | internal_poll) | ||
1793 | { | 1839 | { |
1794 | case MHD_CONNECTION_INIT: | 1840 | /* failed to grow the read buffer, and the |
1795 | case MHD_CONNECTION_URL_RECEIVED: | 1841 | client which is supposed to handle the |
1796 | case MHD_CONNECTION_HEADER_PART_RECEIVED: | 1842 | received data in a *blocking* fashion |
1797 | /* while reading headers, we always grow the | 1843 | (in this mode) did not handle the data as |
1798 | read buffer if needed, no size-check required */ | 1844 | it was supposed to! |
1799 | if ( (connection->read_buffer_offset == connection->read_buffer_size) && | 1845 | => we would either have to do busy-waiting |
1800 | (!try_grow_read_buffer (connection, true)) ) | 1846 | (on the client, which would likely fail), |
1801 | { | 1847 | or if we do nothing, we would just timeout |
1802 | transmit_error_response (connection, | 1848 | on the connection (if a timeout is even |
1803 | (connection->url != NULL) | 1849 | set!). |
1804 | ? MHD_HTTP_REQUEST_HEADER_FIELDS_TOO_LARGE | 1850 | Solution: we kill the connection with an error */ |
1805 | : MHD_HTTP_URI_TOO_LONG, | 1851 | transmit_error_response (connection, |
1806 | REQUEST_TOO_BIG); | 1852 | MHD_HTTP_INTERNAL_SERVER_ERROR, |
1807 | continue; | 1853 | INTERNAL_ERROR); |
1808 | } | 1854 | continue; |
1809 | if (! connection->read_closed) | ||
1810 | connection->event_loop_info = MHD_EVENT_LOOP_INFO_READ; | ||
1811 | else | ||
1812 | connection->event_loop_info = MHD_EVENT_LOOP_INFO_BLOCK; | ||
1813 | break; | ||
1814 | case MHD_CONNECTION_HEADERS_RECEIVED: | ||
1815 | mhd_assert (0); | ||
1816 | break; | ||
1817 | case MHD_CONNECTION_HEADERS_PROCESSED: | ||
1818 | mhd_assert (0); | ||
1819 | break; | ||
1820 | case MHD_CONNECTION_CONTINUE_SENDING: | ||
1821 | connection->event_loop_info = MHD_EVENT_LOOP_INFO_WRITE; | ||
1822 | break; | ||
1823 | case MHD_CONNECTION_CONTINUE_SENT: | ||
1824 | if (connection->read_buffer_offset == connection->read_buffer_size) | ||
1825 | { | ||
1826 | const bool internal_poll = (0 != (connection->daemon->options & | ||
1827 | MHD_USE_INTERNAL_POLLING_THREAD)); | ||
1828 | if ( (!try_grow_read_buffer (connection, true)) && | ||
1829 | internal_poll) | ||
1830 | { | ||
1831 | /* failed to grow the read buffer, and the | ||
1832 | client which is supposed to handle the | ||
1833 | received data in a *blocking* fashion | ||
1834 | (in this mode) did not handle the data as | ||
1835 | it was supposed to! | ||
1836 | => we would either have to do busy-waiting | ||
1837 | (on the client, which would likely fail), | ||
1838 | or if we do nothing, we would just timeout | ||
1839 | on the connection (if a timeout is even | ||
1840 | set!). | ||
1841 | Solution: we kill the connection with an error */ | ||
1842 | transmit_error_response (connection, | ||
1843 | MHD_HTTP_INTERNAL_SERVER_ERROR, | ||
1844 | INTERNAL_ERROR); | ||
1845 | continue; | ||
1846 | } | ||
1847 | } | ||
1848 | if ( (connection->read_buffer_offset < connection->read_buffer_size) && | ||
1849 | (! connection->read_closed) ) | ||
1850 | connection->event_loop_info = MHD_EVENT_LOOP_INFO_READ; | ||
1851 | else | ||
1852 | connection->event_loop_info = MHD_EVENT_LOOP_INFO_BLOCK; | ||
1853 | break; | ||
1854 | case MHD_CONNECTION_BODY_RECEIVED: | ||
1855 | case MHD_CONNECTION_FOOTER_PART_RECEIVED: | ||
1856 | /* while reading footers, we always grow the | ||
1857 | read buffer if needed, no size-check required */ | ||
1858 | if (connection->read_closed) | ||
1859 | { | ||
1860 | CONNECTION_CLOSE_ERROR (connection, | ||
1861 | NULL); | ||
1862 | continue; | ||
1863 | } | ||
1864 | connection->event_loop_info = MHD_EVENT_LOOP_INFO_READ; | ||
1865 | /* transition to FOOTERS_RECEIVED | ||
1866 | happens in read handler */ | ||
1867 | break; | ||
1868 | case MHD_CONNECTION_FOOTERS_RECEIVED: | ||
1869 | connection->event_loop_info = MHD_EVENT_LOOP_INFO_BLOCK; | ||
1870 | break; | ||
1871 | case MHD_CONNECTION_HEADERS_SENDING: | ||
1872 | /* headers in buffer, keep writing */ | ||
1873 | connection->event_loop_info = MHD_EVENT_LOOP_INFO_WRITE; | ||
1874 | break; | ||
1875 | case MHD_CONNECTION_HEADERS_SENT: | ||
1876 | mhd_assert (0); | ||
1877 | break; | ||
1878 | case MHD_CONNECTION_NORMAL_BODY_READY: | ||
1879 | connection->event_loop_info = MHD_EVENT_LOOP_INFO_WRITE; | ||
1880 | break; | ||
1881 | case MHD_CONNECTION_NORMAL_BODY_UNREADY: | ||
1882 | connection->event_loop_info = MHD_EVENT_LOOP_INFO_BLOCK; | ||
1883 | break; | ||
1884 | case MHD_CONNECTION_CHUNKED_BODY_READY: | ||
1885 | connection->event_loop_info = MHD_EVENT_LOOP_INFO_WRITE; | ||
1886 | break; | ||
1887 | case MHD_CONNECTION_CHUNKED_BODY_UNREADY: | ||
1888 | connection->event_loop_info = MHD_EVENT_LOOP_INFO_BLOCK; | ||
1889 | break; | ||
1890 | case MHD_CONNECTION_BODY_SENT: | ||
1891 | mhd_assert (0); | ||
1892 | break; | ||
1893 | case MHD_CONNECTION_FOOTERS_SENDING: | ||
1894 | connection->event_loop_info = MHD_EVENT_LOOP_INFO_WRITE; | ||
1895 | break; | ||
1896 | case MHD_CONNECTION_FOOTERS_SENT: | ||
1897 | mhd_assert (0); | ||
1898 | break; | ||
1899 | case MHD_CONNECTION_CLOSED: | ||
1900 | connection->event_loop_info = MHD_EVENT_LOOP_INFO_CLEANUP; | ||
1901 | return; /* do nothing, not even reading */ | ||
1902 | #ifdef UPGRADE_SUPPORT | ||
1903 | case MHD_CONNECTION_UPGRADE: | ||
1904 | mhd_assert (0); | ||
1905 | break; | ||
1906 | #endif /* UPGRADE_SUPPORT */ | ||
1907 | default: | ||
1908 | mhd_assert (0); | ||
1909 | } | 1855 | } |
1856 | } | ||
1857 | if ( (connection->read_buffer_offset < connection->read_buffer_size) && | ||
1858 | (! connection->read_closed) ) | ||
1859 | connection->event_loop_info = MHD_EVENT_LOOP_INFO_READ; | ||
1860 | else | ||
1861 | connection->event_loop_info = MHD_EVENT_LOOP_INFO_BLOCK; | ||
1910 | break; | 1862 | break; |
1863 | case MHD_CONNECTION_BODY_RECEIVED: | ||
1864 | case MHD_CONNECTION_FOOTER_PART_RECEIVED: | ||
1865 | /* while reading footers, we always grow the | ||
1866 | read buffer if needed, no size-check required */ | ||
1867 | if (connection->read_closed) | ||
1868 | { | ||
1869 | CONNECTION_CLOSE_ERROR (connection, | ||
1870 | NULL); | ||
1871 | continue; | ||
1872 | } | ||
1873 | connection->event_loop_info = MHD_EVENT_LOOP_INFO_READ; | ||
1874 | /* transition to FOOTERS_RECEIVED | ||
1875 | happens in read handler */ | ||
1876 | break; | ||
1877 | case MHD_CONNECTION_FOOTERS_RECEIVED: | ||
1878 | connection->event_loop_info = MHD_EVENT_LOOP_INFO_BLOCK; | ||
1879 | break; | ||
1880 | case MHD_CONNECTION_HEADERS_SENDING: | ||
1881 | /* headers in buffer, keep writing */ | ||
1882 | connection->event_loop_info = MHD_EVENT_LOOP_INFO_WRITE; | ||
1883 | break; | ||
1884 | case MHD_CONNECTION_HEADERS_SENT: | ||
1885 | mhd_assert (0); | ||
1886 | break; | ||
1887 | case MHD_CONNECTION_NORMAL_BODY_READY: | ||
1888 | connection->event_loop_info = MHD_EVENT_LOOP_INFO_WRITE; | ||
1889 | break; | ||
1890 | case MHD_CONNECTION_NORMAL_BODY_UNREADY: | ||
1891 | connection->event_loop_info = MHD_EVENT_LOOP_INFO_BLOCK; | ||
1892 | break; | ||
1893 | case MHD_CONNECTION_CHUNKED_BODY_READY: | ||
1894 | connection->event_loop_info = MHD_EVENT_LOOP_INFO_WRITE; | ||
1895 | break; | ||
1896 | case MHD_CONNECTION_CHUNKED_BODY_UNREADY: | ||
1897 | connection->event_loop_info = MHD_EVENT_LOOP_INFO_BLOCK; | ||
1898 | break; | ||
1899 | case MHD_CONNECTION_BODY_SENT: | ||
1900 | mhd_assert (0); | ||
1901 | break; | ||
1902 | case MHD_CONNECTION_FOOTERS_SENDING: | ||
1903 | connection->event_loop_info = MHD_EVENT_LOOP_INFO_WRITE; | ||
1904 | break; | ||
1905 | case MHD_CONNECTION_FOOTERS_SENT: | ||
1906 | mhd_assert (0); | ||
1907 | break; | ||
1908 | case MHD_CONNECTION_CLOSED: | ||
1909 | connection->event_loop_info = MHD_EVENT_LOOP_INFO_CLEANUP; | ||
1910 | return; /* do nothing, not even reading */ | ||
1911 | #ifdef UPGRADE_SUPPORT | ||
1912 | case MHD_CONNECTION_UPGRADE: | ||
1913 | mhd_assert (0); | ||
1914 | break; | ||
1915 | #endif /* UPGRADE_SUPPORT */ | ||
1916 | default: | ||
1917 | mhd_assert (0); | ||
1911 | } | 1918 | } |
1919 | break; | ||
1920 | } | ||
1912 | } | 1921 | } |
1913 | 1922 | ||
1914 | 1923 | ||
@@ -1942,21 +1951,21 @@ get_next_header_line (struct MHD_Connection *connection, | |||
1942 | pos++; | 1951 | pos++; |
1943 | if ( (pos == connection->read_buffer_offset - 1) && | 1952 | if ( (pos == connection->read_buffer_offset - 1) && |
1944 | ('\n' != rbuf[pos]) ) | 1953 | ('\n' != rbuf[pos]) ) |
1954 | { | ||
1955 | /* not found, consider growing... */ | ||
1956 | if ( (connection->read_buffer_offset == connection->read_buffer_size) && | ||
1957 | (! try_grow_read_buffer (connection, true)) ) | ||
1945 | { | 1958 | { |
1946 | /* not found, consider growing... */ | 1959 | transmit_error_response (connection, |
1947 | if ( (connection->read_buffer_offset == connection->read_buffer_size) && | 1960 | (NULL != connection->url) |
1948 | (!try_grow_read_buffer (connection, true)) ) | 1961 | ? MHD_HTTP_REQUEST_HEADER_FIELDS_TOO_LARGE |
1949 | { | 1962 | : MHD_HTTP_URI_TOO_LONG, |
1950 | transmit_error_response (connection, | 1963 | REQUEST_TOO_BIG); |
1951 | (NULL != connection->url) | ||
1952 | ? MHD_HTTP_REQUEST_HEADER_FIELDS_TOO_LARGE | ||
1953 | : MHD_HTTP_URI_TOO_LONG, | ||
1954 | REQUEST_TOO_BIG); | ||
1955 | } | ||
1956 | if (line_len) | ||
1957 | *line_len = 0; | ||
1958 | return NULL; | ||
1959 | } | 1964 | } |
1965 | if (line_len) | ||
1966 | *line_len = 0; | ||
1967 | return NULL; | ||
1968 | } | ||
1960 | 1969 | ||
1961 | if (line_len) | 1970 | if (line_len) |
1962 | *line_len = pos; | 1971 | *line_len = pos; |
@@ -1989,27 +1998,27 @@ static int | |||
1989 | connection_add_header (struct MHD_Connection *connection, | 1998 | connection_add_header (struct MHD_Connection *connection, |
1990 | const char *key, | 1999 | const char *key, |
1991 | size_t key_size, | 2000 | size_t key_size, |
1992 | const char *value, | 2001 | const char *value, |
1993 | size_t value_size, | 2002 | size_t value_size, |
1994 | enum MHD_ValueKind kind) | 2003 | enum MHD_ValueKind kind) |
1995 | { | 2004 | { |
1996 | if (MHD_NO == | 2005 | if (MHD_NO == |
1997 | MHD_set_connection_value_n (connection, | 2006 | MHD_set_connection_value_n (connection, |
1998 | kind, | 2007 | kind, |
1999 | key, | 2008 | key, |
2000 | key_size, | 2009 | key_size, |
2001 | value, | 2010 | value, |
2002 | value_size)) | 2011 | value_size)) |
2003 | { | 2012 | { |
2004 | #ifdef HAVE_MESSAGES | 2013 | #ifdef HAVE_MESSAGES |
2005 | MHD_DLOG (connection->daemon, | 2014 | MHD_DLOG (connection->daemon, |
2006 | _("Not enough memory in pool to allocate header record!\n")); | 2015 | _ ("Not enough memory in pool to allocate header record!\n")); |
2007 | #endif | 2016 | #endif |
2008 | transmit_error_response (connection, | 2017 | transmit_error_response (connection, |
2009 | MHD_HTTP_REQUEST_HEADER_FIELDS_TOO_LARGE, | 2018 | MHD_HTTP_REQUEST_HEADER_FIELDS_TOO_LARGE, |
2010 | REQUEST_TOO_BIG); | 2019 | REQUEST_TOO_BIG); |
2011 | return MHD_NO; | 2020 | return MHD_NO; |
2012 | } | 2021 | } |
2013 | return MHD_YES; | 2022 | return MHD_YES; |
2014 | } | 2023 | } |
2015 | 2024 | ||
@@ -2038,7 +2047,8 @@ parse_cookie_header (struct MHD_Connection *connection) | |||
2038 | if (MHD_NO == MHD_lookup_connection_value_n (connection, | 2047 | if (MHD_NO == MHD_lookup_connection_value_n (connection, |
2039 | MHD_HEADER_KIND, | 2048 | MHD_HEADER_KIND, |
2040 | MHD_HTTP_HEADER_COOKIE, | 2049 | MHD_HTTP_HEADER_COOKIE, |
2041 | MHD_STATICSTR_LEN_(MHD_HTTP_HEADER_COOKIE), | 2050 | MHD_STATICSTR_LEN_ ( |
2051 | MHD_HTTP_HEADER_COOKIE), | ||
2042 | &hdr, | 2052 | &hdr, |
2043 | &hdr_len)) | 2053 | &hdr_len)) |
2044 | return MHD_YES; | 2054 | return MHD_YES; |
@@ -2046,93 +2056,93 @@ parse_cookie_header (struct MHD_Connection *connection) | |||
2046 | hdr_len + 1, | 2056 | hdr_len + 1, |
2047 | true); | 2057 | true); |
2048 | if (NULL == cpy) | 2058 | if (NULL == cpy) |
2049 | { | 2059 | { |
2050 | #ifdef HAVE_MESSAGES | 2060 | #ifdef HAVE_MESSAGES |
2051 | MHD_DLOG (connection->daemon, | 2061 | MHD_DLOG (connection->daemon, |
2052 | _("Not enough memory in pool to parse cookies!\n")); | 2062 | _ ("Not enough memory in pool to parse cookies!\n")); |
2053 | #endif | 2063 | #endif |
2054 | transmit_error_response (connection, | 2064 | transmit_error_response (connection, |
2055 | MHD_HTTP_REQUEST_HEADER_FIELDS_TOO_LARGE, | 2065 | MHD_HTTP_REQUEST_HEADER_FIELDS_TOO_LARGE, |
2056 | REQUEST_TOO_BIG); | 2066 | REQUEST_TOO_BIG); |
2057 | return MHD_NO; | 2067 | return MHD_NO; |
2058 | } | 2068 | } |
2059 | memcpy (cpy, | 2069 | memcpy (cpy, |
2060 | hdr, | 2070 | hdr, |
2061 | hdr_len); | 2071 | hdr_len); |
2062 | cpy[hdr_len] = '\0'; | 2072 | cpy[hdr_len] = '\0'; |
2063 | pos = cpy; | 2073 | pos = cpy; |
2064 | while (NULL != pos) | 2074 | while (NULL != pos) |
2075 | { | ||
2076 | while (' ' == *pos) | ||
2077 | pos++; /* skip spaces */ | ||
2078 | |||
2079 | sce = pos; | ||
2080 | while ( ((*sce) != '\0') && | ||
2081 | ((*sce) != ',') && | ||
2082 | ((*sce) != ';') && | ||
2083 | ((*sce) != '=') ) | ||
2084 | sce++; | ||
2085 | /* remove tailing whitespace (if any) from key */ | ||
2086 | ekill = sce - 1; | ||
2087 | while ( (*ekill == ' ') && | ||
2088 | (ekill >= pos) ) | ||
2089 | *(ekill--) = '\0'; | ||
2090 | old = *sce; | ||
2091 | *sce = '\0'; | ||
2092 | if (old != '=') | ||
2065 | { | 2093 | { |
2066 | while (' ' == *pos) | 2094 | /* value part omitted, use empty string... */ |
2067 | pos++; /* skip spaces */ | ||
2068 | |||
2069 | sce = pos; | ||
2070 | while ( ((*sce) != '\0') && | ||
2071 | ((*sce) != ',') && | ||
2072 | ((*sce) != ';') && | ||
2073 | ((*sce) != '=') ) | ||
2074 | sce++; | ||
2075 | /* remove tailing whitespace (if any) from key */ | ||
2076 | ekill = sce - 1; | ||
2077 | while ( (*ekill == ' ') && | ||
2078 | (ekill >= pos) ) | ||
2079 | *(ekill--) = '\0'; | ||
2080 | old = *sce; | ||
2081 | *sce = '\0'; | ||
2082 | if (old != '=') | ||
2083 | { | ||
2084 | /* value part omitted, use empty string... */ | ||
2085 | if (MHD_NO == | ||
2086 | connection_add_header (connection, | ||
2087 | pos, | ||
2088 | ekill - pos + 1, | ||
2089 | "", | ||
2090 | 0, | ||
2091 | MHD_COOKIE_KIND)) | ||
2092 | return MHD_NO; | ||
2093 | if (old == '\0') | ||
2094 | break; | ||
2095 | pos = sce + 1; | ||
2096 | continue; | ||
2097 | } | ||
2098 | equals = sce + 1; | ||
2099 | quotes = 0; | ||
2100 | semicolon = equals; | ||
2101 | while ( ('\0' != semicolon[0]) && | ||
2102 | ( (0 != quotes) || | ||
2103 | ( (';' != semicolon[0]) && | ||
2104 | (',' != semicolon[0]) ) ) ) | ||
2105 | { | ||
2106 | if ('"' == semicolon[0]) | ||
2107 | quotes = (quotes + 1) & 1; | ||
2108 | semicolon++; | ||
2109 | } | ||
2110 | end = semicolon; | ||
2111 | if ('\0' == semicolon[0]) | ||
2112 | semicolon = NULL; | ||
2113 | if (NULL != semicolon) | ||
2114 | { | ||
2115 | semicolon[0] = '\0'; | ||
2116 | semicolon++; | ||
2117 | } | ||
2118 | /* remove quotes */ | ||
2119 | if ( ('"' == equals[0]) && | ||
2120 | ('"' == end[-1]) ) | ||
2121 | { | ||
2122 | equals++; | ||
2123 | end--; | ||
2124 | *end = '\0'; | ||
2125 | } | ||
2126 | if (MHD_NO == | 2095 | if (MHD_NO == |
2127 | connection_add_header (connection, | 2096 | connection_add_header (connection, |
2128 | pos, | 2097 | pos, |
2129 | ekill - pos + 1, | 2098 | ekill - pos + 1, |
2130 | equals, | 2099 | "", |
2131 | end - equals, | 2100 | 0, |
2132 | MHD_COOKIE_KIND)) | 2101 | MHD_COOKIE_KIND)) |
2133 | return MHD_NO; | 2102 | return MHD_NO; |
2134 | pos = semicolon; | 2103 | if (old == '\0') |
2104 | break; | ||
2105 | pos = sce + 1; | ||
2106 | continue; | ||
2107 | } | ||
2108 | equals = sce + 1; | ||
2109 | quotes = 0; | ||
2110 | semicolon = equals; | ||
2111 | while ( ('\0' != semicolon[0]) && | ||
2112 | ( (0 != quotes) || | ||
2113 | ( (';' != semicolon[0]) && | ||
2114 | (',' != semicolon[0]) ) ) ) | ||
2115 | { | ||
2116 | if ('"' == semicolon[0]) | ||
2117 | quotes = (quotes + 1) & 1; | ||
2118 | semicolon++; | ||
2119 | } | ||
2120 | end = semicolon; | ||
2121 | if ('\0' == semicolon[0]) | ||
2122 | semicolon = NULL; | ||
2123 | if (NULL != semicolon) | ||
2124 | { | ||
2125 | semicolon[0] = '\0'; | ||
2126 | semicolon++; | ||
2127 | } | ||
2128 | /* remove quotes */ | ||
2129 | if ( ('"' == equals[0]) && | ||
2130 | ('"' == end[-1]) ) | ||
2131 | { | ||
2132 | equals++; | ||
2133 | end--; | ||
2134 | *end = '\0'; | ||
2135 | } | 2135 | } |
2136 | if (MHD_NO == | ||
2137 | connection_add_header (connection, | ||
2138 | pos, | ||
2139 | ekill - pos + 1, | ||
2140 | equals, | ||
2141 | end - equals, | ||
2142 | MHD_COOKIE_KIND)) | ||
2143 | return MHD_NO; | ||
2144 | pos = semicolon; | ||
2145 | } | ||
2136 | return MHD_YES; | 2146 | return MHD_YES; |
2137 | } | 2147 | } |
2138 | 2148 | ||
@@ -2167,84 +2177,84 @@ parse_initial_message_line (struct MHD_Connection *connection, | |||
2167 | /* Skip any spaces. Not required by standard but allow | 2177 | /* Skip any spaces. Not required by standard but allow |
2168 | to be more tolerant. */ | 2178 | to be more tolerant. */ |
2169 | while ( (' ' == uri[0]) && | 2179 | while ( (' ' == uri[0]) && |
2170 | ( (size_t)(uri - line) < line_len) ) | 2180 | ( (size_t) (uri - line) < line_len) ) |
2171 | uri++; | 2181 | uri++; |
2172 | if ((size_t)(uri - line) == line_len) | 2182 | if ((size_t) (uri - line) == line_len) |
2183 | { | ||
2184 | /* No URI and no http version given */ | ||
2185 | curi = ""; | ||
2186 | uri = NULL; | ||
2187 | connection->version = ""; | ||
2188 | args = NULL; | ||
2189 | } | ||
2190 | else | ||
2191 | { | ||
2192 | size_t uri_len; | ||
2193 | curi = uri; | ||
2194 | /* Search from back to accept misformed URI with space */ | ||
2195 | http_version = line + line_len - 1; | ||
2196 | /* Skip any trailing spaces */ | ||
2197 | while ( (' ' == http_version[0]) && | ||
2198 | (http_version > uri) ) | ||
2199 | http_version--; | ||
2200 | /* Find first space in reverse direction */ | ||
2201 | while ( (' ' != http_version[0]) && | ||
2202 | (http_version > uri) ) | ||
2203 | http_version--; | ||
2204 | if (http_version > uri) | ||
2205 | { | ||
2206 | /* http_version points to character before HTTP version string */ | ||
2207 | http_version[0] = '\0'; | ||
2208 | connection->version = http_version + 1; | ||
2209 | uri_len = http_version - uri; | ||
2210 | } | ||
2211 | else | ||
2173 | { | 2212 | { |
2174 | /* No URI and no http version given */ | ||
2175 | curi = ""; | ||
2176 | uri = NULL; | ||
2177 | connection->version = ""; | 2213 | connection->version = ""; |
2178 | args = NULL; | 2214 | uri_len = line_len - (uri - line); |
2179 | } | 2215 | } |
2180 | else | 2216 | /* check for spaces in URI if we are "strict" */ |
2217 | if ( (1 <= daemon->strict_for_client) && | ||
2218 | (NULL != memchr (uri, | ||
2219 | ' ', | ||
2220 | uri_len)) ) | ||
2181 | { | 2221 | { |
2182 | size_t uri_len; | 2222 | /* space exists in URI and we are supposed to be strict, reject */ |
2183 | curi = uri; | 2223 | return MHD_NO; |
2184 | /* Search from back to accept misformed URI with space */ | ||
2185 | http_version = line + line_len - 1; | ||
2186 | /* Skip any trailing spaces */ | ||
2187 | while ( (' ' == http_version[0]) && | ||
2188 | (http_version > uri) ) | ||
2189 | http_version--; | ||
2190 | /* Find first space in reverse direction */ | ||
2191 | while ( (' ' != http_version[0]) && | ||
2192 | (http_version > uri) ) | ||
2193 | http_version--; | ||
2194 | if (http_version > uri) | ||
2195 | { | ||
2196 | /* http_version points to character before HTTP version string */ | ||
2197 | http_version[0] = '\0'; | ||
2198 | connection->version = http_version + 1; | ||
2199 | uri_len = http_version - uri; | ||
2200 | } | ||
2201 | else | ||
2202 | { | ||
2203 | connection->version = ""; | ||
2204 | uri_len = line_len - (uri - line); | ||
2205 | } | ||
2206 | /* check for spaces in URI if we are "strict" */ | ||
2207 | if ( (1 <= daemon->strict_for_client) && | ||
2208 | (NULL != memchr (uri, | ||
2209 | ' ', | ||
2210 | uri_len)) ) | ||
2211 | { | ||
2212 | /* space exists in URI and we are supposed to be strict, reject */ | ||
2213 | return MHD_NO; | ||
2214 | } | ||
2215 | |||
2216 | args = memchr (uri, | ||
2217 | '?', | ||
2218 | uri_len); | ||
2219 | } | 2224 | } |
2220 | 2225 | ||
2226 | args = memchr (uri, | ||
2227 | '?', | ||
2228 | uri_len); | ||
2229 | } | ||
2230 | |||
2221 | /* log callback before we modify URI *or* args */ | 2231 | /* log callback before we modify URI *or* args */ |
2222 | if (NULL != daemon->uri_log_callback) | 2232 | if (NULL != daemon->uri_log_callback) |
2223 | { | 2233 | { |
2224 | connection->client_aware = true; | 2234 | connection->client_aware = true; |
2225 | connection->client_context | 2235 | connection->client_context |
2226 | = daemon->uri_log_callback (daemon->uri_log_callback_cls, | 2236 | = daemon->uri_log_callback (daemon->uri_log_callback_cls, |
2227 | uri, | 2237 | uri, |
2228 | connection); | 2238 | connection); |
2229 | } | 2239 | } |
2230 | 2240 | ||
2231 | if (NULL != args) | 2241 | if (NULL != args) |
2232 | { | 2242 | { |
2233 | args[0] = '\0'; | 2243 | args[0] = '\0'; |
2234 | args++; | 2244 | args++; |
2235 | /* note that this call clobbers 'args' */ | 2245 | /* note that this call clobbers 'args' */ |
2236 | MHD_parse_arguments_ (connection, | 2246 | MHD_parse_arguments_ (connection, |
2237 | MHD_GET_ARGUMENT_KIND, | 2247 | MHD_GET_ARGUMENT_KIND, |
2238 | args, | 2248 | args, |
2239 | &connection_add_header, | 2249 | &connection_add_header, |
2240 | &unused_num_headers); | 2250 | &unused_num_headers); |
2241 | } | 2251 | } |
2242 | 2252 | ||
2243 | /* unescape URI *after* searching for arguments and log callback */ | 2253 | /* unescape URI *after* searching for arguments and log callback */ |
2244 | if (NULL != uri) | 2254 | if (NULL != uri) |
2245 | daemon->unescape_callback (daemon->unescape_callback_cls, | 2255 | daemon->unescape_callback (daemon->unescape_callback_cls, |
2246 | connection, | 2256 | connection, |
2247 | uri); | 2257 | uri); |
2248 | connection->url = curi; | 2258 | connection->url = curi; |
2249 | return MHD_YES; | 2259 | return MHD_YES; |
2250 | } | 2260 | } |
@@ -2276,12 +2286,13 @@ call_connection_handler (struct MHD_Connection *connection) | |||
2276 | NULL, | 2286 | NULL, |
2277 | &processed, | 2287 | &processed, |
2278 | &connection->client_context)) | 2288 | &connection->client_context)) |
2279 | { | 2289 | { |
2280 | /* serious internal error, close connection */ | 2290 | /* serious internal error, close connection */ |
2281 | CONNECTION_CLOSE_ERROR (connection, | 2291 | CONNECTION_CLOSE_ERROR (connection, |
2282 | _("Application reported internal error, closing connection.\n")); | 2292 | _ ( |
2283 | return; | 2293 | "Application reported internal error, closing connection.\n")); |
2284 | } | 2294 | return; |
2295 | } | ||
2285 | } | 2296 | } |
2286 | 2297 | ||
2287 | 2298 | ||
@@ -2318,199 +2329,205 @@ process_request_body (struct MHD_Connection *connection) | |||
2318 | buffer_head = connection->read_buffer; | 2329 | buffer_head = connection->read_buffer; |
2319 | available = connection->read_buffer_offset; | 2330 | available = connection->read_buffer_offset; |
2320 | do | 2331 | do |
2321 | { | 2332 | { |
2322 | size_t to_be_processed; | 2333 | size_t to_be_processed; |
2323 | size_t left_unprocessed; | 2334 | size_t left_unprocessed; |
2324 | size_t processed_size; | 2335 | size_t processed_size; |
2325 | 2336 | ||
2326 | instant_retry = MHD_NO; | 2337 | instant_retry = MHD_NO; |
2327 | if ( (connection->have_chunked_upload) && | 2338 | if ( (connection->have_chunked_upload) && |
2328 | (MHD_SIZE_UNKNOWN == connection->remaining_upload_size) ) | 2339 | (MHD_SIZE_UNKNOWN == connection->remaining_upload_size) ) |
2340 | { | ||
2341 | if ( (connection->current_chunk_offset == | ||
2342 | connection->current_chunk_size) && | ||
2343 | (0LLU != connection->current_chunk_offset) && | ||
2344 | (available >= 2) ) | ||
2345 | { | ||
2346 | size_t i; | ||
2347 | /* skip new line at the *end* of a chunk */ | ||
2348 | i = 0; | ||
2349 | if ( ('\r' == buffer_head[i]) || | ||
2350 | ('\n' == buffer_head[i]) ) | ||
2351 | i++; /* skip 1st part of line feed */ | ||
2352 | if ( ('\r' == buffer_head[i]) || | ||
2353 | ('\n' == buffer_head[i]) ) | ||
2354 | i++; /* skip 2nd part of line feed */ | ||
2355 | if (0 == i) | ||
2329 | { | 2356 | { |
2330 | if ( (connection->current_chunk_offset == connection->current_chunk_size) && | 2357 | /* malformed encoding */ |
2331 | (0LLU != connection->current_chunk_offset) && | 2358 | CONNECTION_CLOSE_ERROR (connection, |
2332 | (available >= 2) ) | 2359 | _ ( |
2333 | { | 2360 | "Received malformed HTTP request (bad chunked encoding). Closing connection.\n")); |
2334 | size_t i; | 2361 | return; |
2335 | /* skip new line at the *end* of a chunk */ | ||
2336 | i = 0; | ||
2337 | if ( ('\r' == buffer_head[i]) || | ||
2338 | ('\n' == buffer_head[i]) ) | ||
2339 | i++; /* skip 1st part of line feed */ | ||
2340 | if ( ('\r' == buffer_head[i]) || | ||
2341 | ('\n' == buffer_head[i]) ) | ||
2342 | i++; /* skip 2nd part of line feed */ | ||
2343 | if (0 == i) | ||
2344 | { | ||
2345 | /* malformed encoding */ | ||
2346 | CONNECTION_CLOSE_ERROR (connection, | ||
2347 | _("Received malformed HTTP request (bad chunked encoding). Closing connection.\n")); | ||
2348 | return; | ||
2349 | } | ||
2350 | available -= i; | ||
2351 | buffer_head += i; | ||
2352 | connection->current_chunk_offset = 0; | ||
2353 | connection->current_chunk_size = 0; | ||
2354 | } | ||
2355 | if (connection->current_chunk_offset < | ||
2356 | connection->current_chunk_size) | ||
2357 | { | ||
2358 | uint64_t cur_chunk_left; | ||
2359 | /* we are in the middle of a chunk, give | ||
2360 | as much as possible to the client (without | ||
2361 | crossing chunk boundaries) */ | ||
2362 | cur_chunk_left | ||
2363 | = connection->current_chunk_size - connection->current_chunk_offset; | ||
2364 | if (cur_chunk_left > available) | ||
2365 | to_be_processed = available; | ||
2366 | else | ||
2367 | { /* cur_chunk_left <= (size_t)available */ | ||
2368 | to_be_processed = (size_t)cur_chunk_left; | ||
2369 | if (available > to_be_processed) | ||
2370 | instant_retry = MHD_YES; | ||
2371 | } | ||
2372 | } | ||
2373 | else | ||
2374 | { | ||
2375 | size_t i; | ||
2376 | size_t end_size; | ||
2377 | bool malformed; | ||
2378 | |||
2379 | /* we need to read chunk boundaries */ | ||
2380 | i = 0; | ||
2381 | while (i < available) | ||
2382 | { | ||
2383 | if ( ('\r' == buffer_head[i]) || | ||
2384 | ('\n' == buffer_head[i]) || | ||
2385 | (';' == buffer_head[i]) ) | ||
2386 | break; | ||
2387 | i++; | ||
2388 | if (i >= 16) | ||
2389 | break; | ||
2390 | } | ||
2391 | end_size = i; | ||
2392 | /* find beginning of CRLF (skip over chunk extensions) */ | ||
2393 | if (';' == buffer_head[i]) | ||
2394 | { | ||
2395 | while (i < available) | ||
2396 | { | ||
2397 | if ( ('\r' == buffer_head[i]) || | ||
2398 | ('\n' == buffer_head[i]) ) | ||
2399 | break; | ||
2400 | i++; | ||
2401 | } | ||
2402 | } | ||
2403 | /* take '\n' into account; if '\n' is the unavailable | ||
2404 | character, we will need to wait until we have it | ||
2405 | before going further */ | ||
2406 | if ( (i + 1 >= available) && | ||
2407 | ! ( (1 == i) && | ||
2408 | (2 == available) && | ||
2409 | ('0' == buffer_head[0]) ) ) | ||
2410 | break; /* need more data... */ | ||
2411 | i++; | ||
2412 | malformed = (end_size >= 16); | ||
2413 | if (! malformed) | ||
2414 | { | ||
2415 | size_t num_dig = MHD_strx_to_uint64_n_ (buffer_head, | ||
2416 | end_size, | ||
2417 | &connection->current_chunk_size); | ||
2418 | malformed = (end_size != num_dig); | ||
2419 | } | ||
2420 | if (malformed) | ||
2421 | { | ||
2422 | /* malformed encoding */ | ||
2423 | CONNECTION_CLOSE_ERROR (connection, | ||
2424 | _("Received malformed HTTP request (bad chunked encoding). Closing connection.\n")); | ||
2425 | return; | ||
2426 | } | ||
2427 | /* skip 2nd part of line feed */ | ||
2428 | if ( (i < available) && | ||
2429 | ( ('\r' == buffer_head[i]) || | ||
2430 | ('\n' == buffer_head[i]) ) ) | ||
2431 | i++; | ||
2432 | |||
2433 | buffer_head += i; | ||
2434 | available -= i; | ||
2435 | connection->current_chunk_offset = 0; | ||
2436 | |||
2437 | if (available > 0) | ||
2438 | instant_retry = MHD_YES; | ||
2439 | if (0LLU == connection->current_chunk_size) | ||
2440 | { | ||
2441 | connection->remaining_upload_size = 0; | ||
2442 | break; | ||
2443 | } | ||
2444 | continue; | ||
2445 | } | ||
2446 | } | 2362 | } |
2363 | available -= i; | ||
2364 | buffer_head += i; | ||
2365 | connection->current_chunk_offset = 0; | ||
2366 | connection->current_chunk_size = 0; | ||
2367 | } | ||
2368 | if (connection->current_chunk_offset < | ||
2369 | connection->current_chunk_size) | ||
2370 | { | ||
2371 | uint64_t cur_chunk_left; | ||
2372 | /* we are in the middle of a chunk, give | ||
2373 | as much as possible to the client (without | ||
2374 | crossing chunk boundaries) */ | ||
2375 | cur_chunk_left | ||
2376 | = connection->current_chunk_size - connection->current_chunk_offset; | ||
2377 | if (cur_chunk_left > available) | ||
2378 | to_be_processed = available; | ||
2379 | else | ||
2380 | { /* cur_chunk_left <= (size_t)available */ | ||
2381 | to_be_processed = (size_t) cur_chunk_left; | ||
2382 | if (available > to_be_processed) | ||
2383 | instant_retry = MHD_YES; | ||
2384 | } | ||
2385 | } | ||
2447 | else | 2386 | else |
2387 | { | ||
2388 | size_t i; | ||
2389 | size_t end_size; | ||
2390 | bool malformed; | ||
2391 | |||
2392 | /* we need to read chunk boundaries */ | ||
2393 | i = 0; | ||
2394 | while (i < available) | ||
2448 | { | 2395 | { |
2449 | /* no chunked encoding, give all to the client */ | 2396 | if ( ('\r' == buffer_head[i]) || |
2450 | if ( (0 != connection->remaining_upload_size) && | 2397 | ('\n' == buffer_head[i]) || |
2451 | (MHD_SIZE_UNKNOWN != connection->remaining_upload_size) && | 2398 | (';' == buffer_head[i]) ) |
2452 | (connection->remaining_upload_size < available) ) | 2399 | break; |
2453 | { | 2400 | i++; |
2454 | to_be_processed = (size_t)connection->remaining_upload_size; | 2401 | if (i >= 16) |
2455 | } | 2402 | break; |
2456 | else | ||
2457 | { | ||
2458 | /** | ||
2459 | * 1. no chunked encoding, give all to the client | ||
2460 | * 2. client may send large chunked data, but only a smaller part is available at one time. | ||
2461 | */ | ||
2462 | to_be_processed = available; | ||
2463 | } | ||
2464 | } | 2403 | } |
2465 | left_unprocessed = to_be_processed; | 2404 | end_size = i; |
2466 | connection->client_aware = true; | 2405 | /* find beginning of CRLF (skip over chunk extensions) */ |
2467 | if (MHD_NO == | 2406 | if (';' == buffer_head[i]) |
2468 | daemon->default_handler (daemon->default_handler_cls, | ||
2469 | connection, | ||
2470 | connection->url, | ||
2471 | connection->method, | ||
2472 | connection->version, | ||
2473 | buffer_head, | ||
2474 | &left_unprocessed, | ||
2475 | &connection->client_context)) | ||
2476 | { | 2407 | { |
2477 | /* serious internal error, close connection */ | 2408 | while (i < available) |
2409 | { | ||
2410 | if ( ('\r' == buffer_head[i]) || | ||
2411 | ('\n' == buffer_head[i]) ) | ||
2412 | break; | ||
2413 | i++; | ||
2414 | } | ||
2415 | } | ||
2416 | /* take '\n' into account; if '\n' is the unavailable | ||
2417 | character, we will need to wait until we have it | ||
2418 | before going further */ | ||
2419 | if ( (i + 1 >= available) && | ||
2420 | ! ( (1 == i) && | ||
2421 | (2 == available) && | ||
2422 | ('0' == buffer_head[0]) ) ) | ||
2423 | break; /* need more data... */ | ||
2424 | i++; | ||
2425 | malformed = (end_size >= 16); | ||
2426 | if (! malformed) | ||
2427 | { | ||
2428 | size_t num_dig = MHD_strx_to_uint64_n_ (buffer_head, | ||
2429 | end_size, | ||
2430 | &connection-> | ||
2431 | current_chunk_size); | ||
2432 | malformed = (end_size != num_dig); | ||
2433 | } | ||
2434 | if (malformed) | ||
2435 | { | ||
2436 | /* malformed encoding */ | ||
2478 | CONNECTION_CLOSE_ERROR (connection, | 2437 | CONNECTION_CLOSE_ERROR (connection, |
2479 | _("Application reported internal error, closing connection.\n")); | 2438 | _ ( |
2439 | "Received malformed HTTP request (bad chunked encoding). Closing connection.\n")); | ||
2480 | return; | 2440 | return; |
2481 | } | 2441 | } |
2482 | if (left_unprocessed > to_be_processed) | 2442 | /* skip 2nd part of line feed */ |
2483 | mhd_panic (mhd_panic_cls, | 2443 | if ( (i < available) && |
2484 | __FILE__, | 2444 | ( ('\r' == buffer_head[i]) || |
2485 | __LINE__ | 2445 | ('\n' == buffer_head[i]) ) ) |
2446 | i++; | ||
2447 | |||
2448 | buffer_head += i; | ||
2449 | available -= i; | ||
2450 | connection->current_chunk_offset = 0; | ||
2451 | |||
2452 | if (available > 0) | ||
2453 | instant_retry = MHD_YES; | ||
2454 | if (0LLU == connection->current_chunk_size) | ||
2455 | { | ||
2456 | connection->remaining_upload_size = 0; | ||
2457 | break; | ||
2458 | } | ||
2459 | continue; | ||
2460 | } | ||
2461 | } | ||
2462 | else | ||
2463 | { | ||
2464 | /* no chunked encoding, give all to the client */ | ||
2465 | if ( (0 != connection->remaining_upload_size) && | ||
2466 | (MHD_SIZE_UNKNOWN != connection->remaining_upload_size) && | ||
2467 | (connection->remaining_upload_size < available) ) | ||
2468 | { | ||
2469 | to_be_processed = (size_t) connection->remaining_upload_size; | ||
2470 | } | ||
2471 | else | ||
2472 | { | ||
2473 | /** | ||
2474 | * 1. no chunked encoding, give all to the client | ||
2475 | * 2. client may send large chunked data, but only a smaller part is available at one time. | ||
2476 | */ | ||
2477 | to_be_processed = available; | ||
2478 | } | ||
2479 | } | ||
2480 | left_unprocessed = to_be_processed; | ||
2481 | connection->client_aware = true; | ||
2482 | if (MHD_NO == | ||
2483 | daemon->default_handler (daemon->default_handler_cls, | ||
2484 | connection, | ||
2485 | connection->url, | ||
2486 | connection->method, | ||
2487 | connection->version, | ||
2488 | buffer_head, | ||
2489 | &left_unprocessed, | ||
2490 | &connection->client_context)) | ||
2491 | { | ||
2492 | /* serious internal error, close connection */ | ||
2493 | CONNECTION_CLOSE_ERROR (connection, | ||
2494 | _ ( | ||
2495 | "Application reported internal error, closing connection.\n")); | ||
2496 | return; | ||
2497 | } | ||
2498 | if (left_unprocessed > to_be_processed) | ||
2499 | mhd_panic (mhd_panic_cls, | ||
2500 | __FILE__, | ||
2501 | __LINE__ | ||
2486 | #ifdef HAVE_MESSAGES | 2502 | #ifdef HAVE_MESSAGES |
2487 | , _("libmicrohttpd API violation") | 2503 | , _ ("libmicrohttpd API violation") |
2488 | #else | 2504 | #else |
2489 | , NULL | 2505 | , NULL |
2490 | #endif | 2506 | #endif |
2491 | ); | 2507 | ); |
2492 | if (0 != left_unprocessed) | 2508 | if (0 != left_unprocessed) |
2493 | { | 2509 | { |
2494 | instant_retry = MHD_NO; /* client did not process everything */ | 2510 | instant_retry = MHD_NO; /* client did not process everything */ |
2495 | #ifdef HAVE_MESSAGES | 2511 | #ifdef HAVE_MESSAGES |
2496 | /* client did not process all upload data, complain if | 2512 | /* client did not process all upload data, complain if |
2497 | the setup was incorrect, which may prevent us from | 2513 | the setup was incorrect, which may prevent us from |
2498 | handling the rest of the request */ | 2514 | handling the rest of the request */ |
2499 | if ( (0 != (daemon->options & MHD_USE_INTERNAL_POLLING_THREAD)) && | 2515 | if ( (0 != (daemon->options & MHD_USE_INTERNAL_POLLING_THREAD)) && |
2500 | (! connection->suspended) ) | 2516 | (! connection->suspended) ) |
2501 | MHD_DLOG (daemon, | 2517 | MHD_DLOG (daemon, |
2502 | _("WARNING: incomplete upload processing and connection not suspended may result in hung connection.\n")); | 2518 | _ ( |
2519 | "WARNING: incomplete upload processing and connection not suspended may result in hung connection.\n")); | ||
2503 | #endif | 2520 | #endif |
2504 | } | ||
2505 | processed_size = to_be_processed - left_unprocessed; | ||
2506 | if (connection->have_chunked_upload) | ||
2507 | connection->current_chunk_offset += processed_size; | ||
2508 | /* dh left "processed" bytes in buffer for next time... */ | ||
2509 | buffer_head += processed_size; | ||
2510 | available -= processed_size; | ||
2511 | if (MHD_SIZE_UNKNOWN != connection->remaining_upload_size) | ||
2512 | connection->remaining_upload_size -= processed_size; | ||
2513 | } | 2521 | } |
2522 | processed_size = to_be_processed - left_unprocessed; | ||
2523 | if (connection->have_chunked_upload) | ||
2524 | connection->current_chunk_offset += processed_size; | ||
2525 | /* dh left "processed" bytes in buffer for next time... */ | ||
2526 | buffer_head += processed_size; | ||
2527 | available -= processed_size; | ||
2528 | if (MHD_SIZE_UNKNOWN != connection->remaining_upload_size) | ||
2529 | connection->remaining_upload_size -= processed_size; | ||
2530 | } | ||
2514 | while (MHD_YES == instant_retry); | 2531 | while (MHD_YES == instant_retry); |
2515 | if ( (available > 0) && | 2532 | if ( (available > 0) && |
2516 | (buffer_head != connection->read_buffer) ) | 2533 | (buffer_head != connection->read_buffer) ) |
@@ -2540,7 +2557,7 @@ check_write_done (struct MHD_Connection *connection, | |||
2540 | connection->write_buffer_send_offset = 0; | 2557 | connection->write_buffer_send_offset = 0; |
2541 | connection->state = next_state; | 2558 | connection->state = next_state; |
2542 | MHD_pool_reallocate (connection->pool, | 2559 | MHD_pool_reallocate (connection->pool, |
2543 | connection->write_buffer, | 2560 | connection->write_buffer, |
2544 | connection->write_buffer_size, | 2561 | connection->write_buffer_size, |
2545 | 0); | 2562 | 0); |
2546 | connection->write_buffer = NULL; | 2563 | connection->write_buffer = NULL; |
@@ -2567,28 +2584,29 @@ process_header_line (struct MHD_Connection *connection, | |||
2567 | /* line should be normal header line, find colon */ | 2584 | /* line should be normal header line, find colon */ |
2568 | colon = strchr (line, ':'); | 2585 | colon = strchr (line, ':'); |
2569 | if (NULL == colon) | 2586 | if (NULL == colon) |
2570 | { | 2587 | { |
2571 | /* error in header line, die hard */ | 2588 | /* error in header line, die hard */ |
2572 | CONNECTION_CLOSE_ERROR (connection, | 2589 | CONNECTION_CLOSE_ERROR (connection, |
2573 | _("Received malformed line (no colon). Closing connection.\n")); | 2590 | _ ( |
2574 | return MHD_NO; | 2591 | "Received malformed line (no colon). Closing connection.\n")); |
2575 | } | 2592 | return MHD_NO; |
2593 | } | ||
2576 | if (-1 >= connection->daemon->strict_for_client) | 2594 | if (-1 >= connection->daemon->strict_for_client) |
2577 | { | 2595 | { |
2578 | /* check for whitespace before colon, which is not allowed | 2596 | /* check for whitespace before colon, which is not allowed |
2579 | by RFC 7230 section 3.2.4; we count space ' ' and | 2597 | by RFC 7230 section 3.2.4; we count space ' ' and |
2580 | tab '\t', but not '\r\n' as those would have ended the line. */ | 2598 | tab '\t', but not '\r\n' as those would have ended the line. */ |
2581 | const char *white; | 2599 | const char *white; |
2582 | 2600 | ||
2583 | white = strchr (line, ' '); | 2601 | white = strchr (line, ' '); |
2584 | if ( (NULL != white) && | 2602 | if ( (NULL != white) && |
2585 | (white < colon) ) | 2603 | (white < colon) ) |
2586 | return MHD_NO; | 2604 | return MHD_NO; |
2587 | white = strchr (line, '\t'); | 2605 | white = strchr (line, '\t'); |
2588 | if ( (NULL != white) && | 2606 | if ( (NULL != white) && |
2589 | (white < colon) ) | 2607 | (white < colon) ) |
2590 | return MHD_NO; | 2608 | return MHD_NO; |
2591 | } | 2609 | } |
2592 | /* zero-terminate header */ | 2610 | /* zero-terminate header */ |
2593 | colon[0] = '\0'; | 2611 | colon[0] = '\0'; |
2594 | colon++; /* advance to value */ | 2612 | colon++; /* advance to value */ |
@@ -2630,69 +2648,69 @@ process_broken_line (struct MHD_Connection *connection, | |||
2630 | last = connection->last; | 2648 | last = connection->last; |
2631 | if ( (' ' == line[0]) || | 2649 | if ( (' ' == line[0]) || |
2632 | ('\t' == line[0]) ) | 2650 | ('\t' == line[0]) ) |
2633 | { | 2651 | { |
2634 | /* value was continued on the next line, see | 2652 | /* value was continued on the next line, see |
2635 | http://www.jmarshall.com/easy/http/ */ | 2653 | http://www.jmarshall.com/easy/http/ */ |
2636 | last_len = strlen (last); | 2654 | last_len = strlen (last); |
2637 | /* skip whitespace at start of 2nd line */ | 2655 | /* skip whitespace at start of 2nd line */ |
2638 | tmp = line; | 2656 | tmp = line; |
2639 | while ( (' ' == tmp[0]) || | 2657 | while ( (' ' == tmp[0]) || |
2640 | ('\t' == tmp[0]) ) | 2658 | ('\t' == tmp[0]) ) |
2641 | tmp++; | 2659 | tmp++; |
2642 | tmp_len = strlen (tmp); | 2660 | tmp_len = strlen (tmp); |
2643 | /* FIXME: we might be able to do this better (faster!), as most | 2661 | /* FIXME: we might be able to do this better (faster!), as most |
2644 | likely 'last' and 'line' should already be adjacent in | 2662 | likely 'last' and 'line' should already be adjacent in |
2645 | memory; however, doing this right gets tricky if we have a | 2663 | memory; however, doing this right gets tricky if we have a |
2646 | value continued over multiple lines (in which case we need to | 2664 | value continued over multiple lines (in which case we need to |
2647 | record how often we have done this so we can check for | 2665 | record how often we have done this so we can check for |
2648 | adjacency); also, in the case where these are not adjacent | 2666 | adjacency); also, in the case where these are not adjacent |
2649 | (not sure how it can happen!), we would want to allocate from | 2667 | (not sure how it can happen!), we would want to allocate from |
2650 | the end of the pool, so as to not destroy the read-buffer's | 2668 | the end of the pool, so as to not destroy the read-buffer's |
2651 | ability to grow nicely. */ | 2669 | ability to grow nicely. */ |
2652 | last = MHD_pool_reallocate (connection->pool, | 2670 | last = MHD_pool_reallocate (connection->pool, |
2653 | last, | 2671 | last, |
2654 | last_len + 1, | 2672 | last_len + 1, |
2655 | last_len + tmp_len + 1); | 2673 | last_len + tmp_len + 1); |
2656 | if (NULL == last) | 2674 | if (NULL == last) |
2657 | { | ||
2658 | transmit_error_response (connection, | ||
2659 | MHD_HTTP_REQUEST_HEADER_FIELDS_TOO_LARGE, | ||
2660 | REQUEST_TOO_BIG); | ||
2661 | return MHD_NO; | ||
2662 | } | ||
2663 | memcpy (&last[last_len], | ||
2664 | tmp, | ||
2665 | tmp_len + 1); | ||
2666 | connection->last = last; | ||
2667 | return MHD_YES; /* possibly more than 2 lines... */ | ||
2668 | } | ||
2669 | mhd_assert ( (NULL != last) && | ||
2670 | (NULL != connection->colon) ); | ||
2671 | if (MHD_NO == | ||
2672 | connection_add_header (connection, | ||
2673 | last, | ||
2674 | strlen (last), | ||
2675 | connection->colon, | ||
2676 | strlen (connection->colon), | ||
2677 | kind)) | ||
2678 | { | 2675 | { |
2679 | transmit_error_response (connection, | 2676 | transmit_error_response (connection, |
2680 | MHD_HTTP_REQUEST_HEADER_FIELDS_TOO_LARGE, | 2677 | MHD_HTTP_REQUEST_HEADER_FIELDS_TOO_LARGE, |
2681 | REQUEST_TOO_BIG); | 2678 | REQUEST_TOO_BIG); |
2682 | return MHD_NO; | 2679 | return MHD_NO; |
2683 | } | 2680 | } |
2681 | memcpy (&last[last_len], | ||
2682 | tmp, | ||
2683 | tmp_len + 1); | ||
2684 | connection->last = last; | ||
2685 | return MHD_YES; /* possibly more than 2 lines... */ | ||
2686 | } | ||
2687 | mhd_assert ( (NULL != last) && | ||
2688 | (NULL != connection->colon) ); | ||
2689 | if (MHD_NO == | ||
2690 | connection_add_header (connection, | ||
2691 | last, | ||
2692 | strlen (last), | ||
2693 | connection->colon, | ||
2694 | strlen (connection->colon), | ||
2695 | kind)) | ||
2696 | { | ||
2697 | transmit_error_response (connection, | ||
2698 | MHD_HTTP_REQUEST_HEADER_FIELDS_TOO_LARGE, | ||
2699 | REQUEST_TOO_BIG); | ||
2700 | return MHD_NO; | ||
2701 | } | ||
2684 | /* we still have the current line to deal with... */ | 2702 | /* we still have the current line to deal with... */ |
2685 | if (0 != line[0]) | 2703 | if (0 != line[0]) |
2704 | { | ||
2705 | if (MHD_NO == process_header_line (connection, | ||
2706 | line)) | ||
2686 | { | 2707 | { |
2687 | if (MHD_NO == process_header_line (connection, | 2708 | transmit_error_response (connection, |
2688 | line)) | 2709 | MHD_HTTP_BAD_REQUEST, |
2689 | { | 2710 | REQUEST_MALFORMED); |
2690 | transmit_error_response (connection, | 2711 | return MHD_NO; |
2691 | MHD_HTTP_BAD_REQUEST, | ||
2692 | REQUEST_MALFORMED); | ||
2693 | return MHD_NO; | ||
2694 | } | ||
2695 | } | 2712 | } |
2713 | } | ||
2696 | return MHD_YES; | 2714 | return MHD_YES; |
2697 | } | 2715 | } |
2698 | 2716 | ||
@@ -2715,88 +2733,93 @@ parse_connection_headers (struct MHD_Connection *connection) | |||
2715 | parse_cookie_header (connection); | 2733 | parse_cookie_header (connection); |
2716 | if ( (1 <= connection->daemon->strict_for_client) && | 2734 | if ( (1 <= connection->daemon->strict_for_client) && |
2717 | (NULL != connection->version) && | 2735 | (NULL != connection->version) && |
2718 | (MHD_str_equal_caseless_(MHD_HTTP_VERSION_1_1, | 2736 | (MHD_str_equal_caseless_ (MHD_HTTP_VERSION_1_1, |
2719 | connection->version)) && | 2737 | connection->version)) && |
2720 | (MHD_NO == | 2738 | (MHD_NO == |
2721 | MHD_lookup_connection_value_n (connection, | 2739 | MHD_lookup_connection_value_n (connection, |
2722 | MHD_HEADER_KIND, | 2740 | MHD_HEADER_KIND, |
2723 | MHD_HTTP_HEADER_HOST, | 2741 | MHD_HTTP_HEADER_HOST, |
2724 | MHD_STATICSTR_LEN_(MHD_HTTP_HEADER_HOST), | 2742 | MHD_STATICSTR_LEN_ ( |
2743 | MHD_HTTP_HEADER_HOST), | ||
2725 | NULL, | 2744 | NULL, |
2726 | NULL)) ) | 2745 | NULL)) ) |
2727 | { | 2746 | { |
2728 | int iret; | 2747 | int iret; |
2729 | 2748 | ||
2730 | /* die, http 1.1 request without host and we are pedantic */ | 2749 | /* die, http 1.1 request without host and we are pedantic */ |
2731 | connection->state = MHD_CONNECTION_FOOTERS_RECEIVED; | 2750 | connection->state = MHD_CONNECTION_FOOTERS_RECEIVED; |
2732 | connection->read_closed = true; | 2751 | connection->read_closed = true; |
2733 | #ifdef HAVE_MESSAGES | 2752 | #ifdef HAVE_MESSAGES |
2734 | MHD_DLOG (connection->daemon, | 2753 | MHD_DLOG (connection->daemon, |
2735 | _("Received HTTP 1.1 request without `Host' header.\n")); | 2754 | _ ("Received HTTP 1.1 request without `Host' header.\n")); |
2736 | #endif | 2755 | #endif |
2737 | mhd_assert (NULL == connection->response); | 2756 | mhd_assert (NULL == connection->response); |
2738 | response = | 2757 | response = |
2739 | MHD_create_response_from_buffer (MHD_STATICSTR_LEN_ (REQUEST_LACKS_HOST), | 2758 | MHD_create_response_from_buffer (MHD_STATICSTR_LEN_ (REQUEST_LACKS_HOST), |
2740 | REQUEST_LACKS_HOST, | 2759 | REQUEST_LACKS_HOST, |
2741 | MHD_RESPMEM_PERSISTENT); | 2760 | MHD_RESPMEM_PERSISTENT); |
2742 | if (NULL == response) | 2761 | if (NULL == response) |
2743 | { | 2762 | { |
2744 | /* can't even send a reply, at least close the connection */ | 2763 | /* can't even send a reply, at least close the connection */ |
2745 | CONNECTION_CLOSE_ERROR (connection, | 2764 | CONNECTION_CLOSE_ERROR (connection, |
2746 | _("Closing connection (failed to create response)\n")); | 2765 | _ ( |
2747 | return; | 2766 | "Closing connection (failed to create response)\n")); |
2748 | } | ||
2749 | iret = MHD_queue_response (connection, | ||
2750 | MHD_HTTP_BAD_REQUEST, | ||
2751 | response); | ||
2752 | MHD_destroy_response (response); | ||
2753 | if (MHD_YES != iret) | ||
2754 | { | ||
2755 | /* can't even send a reply, at least close the connection */ | ||
2756 | CONNECTION_CLOSE_ERROR (connection, | ||
2757 | _("Closing connection (failed to queue response)\n")); | ||
2758 | } | ||
2759 | return; | 2767 | return; |
2760 | } | 2768 | } |
2769 | iret = MHD_queue_response (connection, | ||
2770 | MHD_HTTP_BAD_REQUEST, | ||
2771 | response); | ||
2772 | MHD_destroy_response (response); | ||
2773 | if (MHD_YES != iret) | ||
2774 | { | ||
2775 | /* can't even send a reply, at least close the connection */ | ||
2776 | CONNECTION_CLOSE_ERROR (connection, | ||
2777 | _ ( | ||
2778 | "Closing connection (failed to queue response)\n")); | ||
2779 | } | ||
2780 | return; | ||
2781 | } | ||
2761 | 2782 | ||
2762 | connection->remaining_upload_size = 0; | 2783 | connection->remaining_upload_size = 0; |
2763 | if (MHD_NO != MHD_lookup_connection_value_n (connection, | 2784 | if (MHD_NO != MHD_lookup_connection_value_n (connection, |
2764 | MHD_HEADER_KIND, | 2785 | MHD_HEADER_KIND, |
2765 | MHD_HTTP_HEADER_TRANSFER_ENCODING, | 2786 | MHD_HTTP_HEADER_TRANSFER_ENCODING, |
2766 | MHD_STATICSTR_LEN_(MHD_HTTP_HEADER_TRANSFER_ENCODING), | 2787 | MHD_STATICSTR_LEN_ ( |
2788 | MHD_HTTP_HEADER_TRANSFER_ENCODING), | ||
2767 | &enc, | 2789 | &enc, |
2768 | NULL)) | 2790 | NULL)) |
2769 | { | 2791 | { |
2770 | connection->remaining_upload_size = MHD_SIZE_UNKNOWN; | 2792 | connection->remaining_upload_size = MHD_SIZE_UNKNOWN; |
2771 | if (MHD_str_equal_caseless_(enc, | 2793 | if (MHD_str_equal_caseless_ (enc, |
2772 | "chunked")) | 2794 | "chunked")) |
2773 | connection->have_chunked_upload = true; | 2795 | connection->have_chunked_upload = true; |
2774 | } | 2796 | } |
2775 | else | 2797 | else |
2798 | { | ||
2799 | if (MHD_NO != MHD_lookup_connection_value_n (connection, | ||
2800 | MHD_HEADER_KIND, | ||
2801 | MHD_HTTP_HEADER_CONTENT_LENGTH, | ||
2802 | MHD_STATICSTR_LEN_ ( | ||
2803 | MHD_HTTP_HEADER_CONTENT_LENGTH), | ||
2804 | &clen, | ||
2805 | NULL)) | ||
2776 | { | 2806 | { |
2777 | if (MHD_NO != MHD_lookup_connection_value_n (connection, | 2807 | end = clen + MHD_str_to_uint64_ (clen, |
2778 | MHD_HEADER_KIND, | 2808 | &connection->remaining_upload_size); |
2779 | MHD_HTTP_HEADER_CONTENT_LENGTH, | 2809 | if ( (clen == end) || |
2780 | MHD_STATICSTR_LEN_(MHD_HTTP_HEADER_CONTENT_LENGTH), | 2810 | ('\0' != *end) ) |
2781 | &clen, | 2811 | { |
2782 | NULL)) | 2812 | connection->remaining_upload_size = 0; |
2783 | { | ||
2784 | end = clen + MHD_str_to_uint64_ (clen, | ||
2785 | &connection->remaining_upload_size); | ||
2786 | if ( (clen == end) || | ||
2787 | ('\0' != *end) ) | ||
2788 | { | ||
2789 | connection->remaining_upload_size = 0; | ||
2790 | #ifdef HAVE_MESSAGES | 2813 | #ifdef HAVE_MESSAGES |
2791 | MHD_DLOG (connection->daemon, | 2814 | MHD_DLOG (connection->daemon, |
2792 | "Failed to parse `Content-Length' header. Closing connection.\n"); | 2815 | "Failed to parse `Content-Length' header. Closing connection.\n"); |
2793 | #endif | 2816 | #endif |
2794 | CONNECTION_CLOSE_ERROR (connection, | 2817 | CONNECTION_CLOSE_ERROR (connection, |
2795 | NULL); | 2818 | NULL); |
2796 | return; | 2819 | return; |
2797 | } | 2820 | } |
2798 | } | ||
2799 | } | 2821 | } |
2822 | } | ||
2800 | } | 2823 | } |
2801 | 2824 | ||
2802 | 2825 | ||
@@ -2818,7 +2841,7 @@ MHD_update_last_activity_ (struct MHD_Connection *connection) | |||
2818 | if (connection->suspended) | 2841 | if (connection->suspended) |
2819 | return; /* no activity on suspended connections */ | 2842 | return; /* no activity on suspended connections */ |
2820 | 2843 | ||
2821 | connection->last_activity = MHD_monotonic_sec_counter(); | 2844 | connection->last_activity = MHD_monotonic_sec_counter (); |
2822 | if (0 != (daemon->options & MHD_USE_THREAD_PER_CONNECTION)) | 2845 | if (0 != (daemon->options & MHD_USE_THREAD_PER_CONNECTION)) |
2823 | return; /* each connection has personal timeout */ | 2846 | return; /* each connection has personal timeout */ |
2824 | 2847 | ||
@@ -2829,11 +2852,11 @@ MHD_update_last_activity_ (struct MHD_Connection *connection) | |||
2829 | #endif | 2852 | #endif |
2830 | /* move connection to head of timeout list (by remove + add operation) */ | 2853 | /* move connection to head of timeout list (by remove + add operation) */ |
2831 | XDLL_remove (daemon->normal_timeout_head, | 2854 | XDLL_remove (daemon->normal_timeout_head, |
2832 | daemon->normal_timeout_tail, | 2855 | daemon->normal_timeout_tail, |
2833 | connection); | 2856 | connection); |
2834 | XDLL_insert (daemon->normal_timeout_head, | 2857 | XDLL_insert (daemon->normal_timeout_head, |
2835 | daemon->normal_timeout_tail, | 2858 | daemon->normal_timeout_tail, |
2836 | connection); | 2859 | connection); |
2837 | #if defined(MHD_USE_POSIX_THREADS) || defined(MHD_USE_W32_THREADS) | 2860 | #if defined(MHD_USE_POSIX_THREADS) || defined(MHD_USE_W32_THREADS) |
2838 | MHD_mutex_unlock_chk_ (&daemon->cleanup_connection_mutex); | 2861 | MHD_mutex_unlock_chk_ (&daemon->cleanup_connection_mutex); |
2839 | #endif | 2862 | #endif |
@@ -2856,13 +2879,13 @@ MHD_connection_handle_read (struct MHD_Connection *connection) | |||
2856 | return; | 2879 | return; |
2857 | #ifdef HTTPS_SUPPORT | 2880 | #ifdef HTTPS_SUPPORT |
2858 | if (MHD_TLS_CONN_NO_TLS != connection->tls_state) | 2881 | if (MHD_TLS_CONN_NO_TLS != connection->tls_state) |
2859 | { /* HTTPS connection. */ | 2882 | { /* HTTPS connection. */ |
2860 | if (MHD_TLS_CONN_CONNECTED > connection->tls_state) | 2883 | if (MHD_TLS_CONN_CONNECTED > connection->tls_state) |
2861 | { | 2884 | { |
2862 | if (!MHD_run_tls_handshake_ (connection)) | 2885 | if (! MHD_run_tls_handshake_ (connection)) |
2863 | return; | 2886 | return; |
2864 | } | ||
2865 | } | 2887 | } |
2888 | } | ||
2866 | #endif /* HTTPS_SUPPORT */ | 2889 | #endif /* HTTPS_SUPPORT */ |
2867 | 2890 | ||
2868 | /* make sure "read" has a reasonable number of bytes | 2891 | /* make sure "read" has a reasonable number of bytes |
@@ -2870,82 +2893,85 @@ MHD_connection_handle_read (struct MHD_Connection *connection) | |||
2870 | if (connection->read_buffer_offset + connection->daemon->pool_increment > | 2893 | if (connection->read_buffer_offset + connection->daemon->pool_increment > |
2871 | connection->read_buffer_size) | 2894 | connection->read_buffer_size) |
2872 | try_grow_read_buffer (connection, | 2895 | try_grow_read_buffer (connection, |
2873 | (connection->read_buffer_size == connection->read_buffer_offset)); | 2896 | (connection->read_buffer_size == |
2897 | connection->read_buffer_offset)); | ||
2874 | 2898 | ||
2875 | if (connection->read_buffer_size == connection->read_buffer_offset) | 2899 | if (connection->read_buffer_size == connection->read_buffer_offset) |
2876 | return; /* No space for receiving data. */ | 2900 | return; /* No space for receiving data. */ |
2877 | bytes_read = connection->recv_cls (connection, | 2901 | bytes_read = connection->recv_cls (connection, |
2878 | &connection->read_buffer | 2902 | &connection->read_buffer |
2879 | [connection->read_buffer_offset], | 2903 | [connection->read_buffer_offset], |
2880 | connection->read_buffer_size - | 2904 | connection->read_buffer_size |
2881 | connection->read_buffer_offset); | 2905 | - connection->read_buffer_offset); |
2882 | if (bytes_read < 0) | 2906 | if (bytes_read < 0) |
2907 | { | ||
2908 | if (MHD_ERR_AGAIN_ == bytes_read) | ||
2909 | return; /* No new data to process. */ | ||
2910 | if (MHD_ERR_CONNRESET_ == bytes_read) | ||
2883 | { | 2911 | { |
2884 | if (MHD_ERR_AGAIN_ == bytes_read) | ||
2885 | return; /* No new data to process. */ | ||
2886 | if (MHD_ERR_CONNRESET_ == bytes_read) | ||
2887 | { | ||
2888 | CONNECTION_CLOSE_ERROR (connection, | ||
2889 | (MHD_CONNECTION_INIT == connection->state) ? | ||
2890 | NULL : | ||
2891 | _("Socket disconnected while reading request.\n")); | ||
2892 | return; | ||
2893 | } | ||
2894 | CONNECTION_CLOSE_ERROR (connection, | 2912 | CONNECTION_CLOSE_ERROR (connection, |
2895 | (MHD_CONNECTION_INIT == connection->state) ? | 2913 | (MHD_CONNECTION_INIT == connection->state) ? |
2896 | NULL : | 2914 | NULL : |
2897 | _("Connection socket is closed due to error when reading request.\n")); | 2915 | _ ( |
2916 | "Socket disconnected while reading request.\n")); | ||
2898 | return; | 2917 | return; |
2899 | } | 2918 | } |
2919 | CONNECTION_CLOSE_ERROR (connection, | ||
2920 | (MHD_CONNECTION_INIT == connection->state) ? | ||
2921 | NULL : | ||
2922 | _ ( | ||
2923 | "Connection socket is closed due to error when reading request.\n")); | ||
2924 | return; | ||
2925 | } | ||
2900 | 2926 | ||
2901 | if (0 == bytes_read) | 2927 | if (0 == bytes_read) |
2902 | { /* Remote side closed connection. */ | 2928 | { /* Remote side closed connection. */ |
2903 | connection->read_closed = true; | 2929 | connection->read_closed = true; |
2904 | MHD_connection_close_ (connection, | 2930 | MHD_connection_close_ (connection, |
2905 | MHD_REQUEST_TERMINATED_CLIENT_ABORT); | 2931 | MHD_REQUEST_TERMINATED_CLIENT_ABORT); |
2906 | return; | 2932 | return; |
2907 | } | 2933 | } |
2908 | connection->read_buffer_offset += bytes_read; | 2934 | connection->read_buffer_offset += bytes_read; |
2909 | MHD_update_last_activity_ (connection); | 2935 | MHD_update_last_activity_ (connection); |
2910 | #if DEBUG_STATES | 2936 | #if DEBUG_STATES |
2911 | MHD_DLOG (connection->daemon, | 2937 | MHD_DLOG (connection->daemon, |
2912 | _("In function %s handling connection at state: %s\n"), | 2938 | _ ("In function %s handling connection at state: %s\n"), |
2913 | __FUNCTION__, | 2939 | __FUNCTION__, |
2914 | MHD_state_to_string (connection->state)); | 2940 | MHD_state_to_string (connection->state)); |
2915 | #endif | 2941 | #endif |
2916 | switch (connection->state) | 2942 | switch (connection->state) |
2943 | { | ||
2944 | case MHD_CONNECTION_INIT: | ||
2945 | case MHD_CONNECTION_URL_RECEIVED: | ||
2946 | case MHD_CONNECTION_HEADER_PART_RECEIVED: | ||
2947 | case MHD_CONNECTION_HEADERS_RECEIVED: | ||
2948 | case MHD_CONNECTION_HEADERS_PROCESSED: | ||
2949 | case MHD_CONNECTION_CONTINUE_SENDING: | ||
2950 | case MHD_CONNECTION_CONTINUE_SENT: | ||
2951 | case MHD_CONNECTION_BODY_RECEIVED: | ||
2952 | case MHD_CONNECTION_FOOTER_PART_RECEIVED: | ||
2953 | /* nothing to do but default action */ | ||
2954 | if (connection->read_closed) | ||
2917 | { | 2955 | { |
2918 | case MHD_CONNECTION_INIT: | 2956 | MHD_connection_close_ (connection, |
2919 | case MHD_CONNECTION_URL_RECEIVED: | 2957 | MHD_REQUEST_TERMINATED_READ_ERROR); |
2920 | case MHD_CONNECTION_HEADER_PART_RECEIVED: | 2958 | } |
2921 | case MHD_CONNECTION_HEADERS_RECEIVED: | 2959 | return; |
2922 | case MHD_CONNECTION_HEADERS_PROCESSED: | 2960 | case MHD_CONNECTION_CLOSED: |
2923 | case MHD_CONNECTION_CONTINUE_SENDING: | 2961 | return; |
2924 | case MHD_CONNECTION_CONTINUE_SENT: | ||
2925 | case MHD_CONNECTION_BODY_RECEIVED: | ||
2926 | case MHD_CONNECTION_FOOTER_PART_RECEIVED: | ||
2927 | /* nothing to do but default action */ | ||
2928 | if (connection->read_closed) | ||
2929 | { | ||
2930 | MHD_connection_close_ (connection, | ||
2931 | MHD_REQUEST_TERMINATED_READ_ERROR); | ||
2932 | } | ||
2933 | return; | ||
2934 | case MHD_CONNECTION_CLOSED: | ||
2935 | return; | ||
2936 | #ifdef UPGRADE_SUPPORT | 2962 | #ifdef UPGRADE_SUPPORT |
2937 | case MHD_CONNECTION_UPGRADE: | 2963 | case MHD_CONNECTION_UPGRADE: |
2938 | mhd_assert (0); | 2964 | mhd_assert (0); |
2939 | return; | 2965 | return; |
2940 | #endif /* UPGRADE_SUPPORT */ | 2966 | #endif /* UPGRADE_SUPPORT */ |
2941 | default: | 2967 | default: |
2942 | /* shrink read buffer to how much is actually used */ | 2968 | /* shrink read buffer to how much is actually used */ |
2943 | MHD_pool_reallocate (connection->pool, | 2969 | MHD_pool_reallocate (connection->pool, |
2944 | connection->read_buffer, | 2970 | connection->read_buffer, |
2945 | connection->read_buffer_size + 1, | 2971 | connection->read_buffer_size + 1, |
2946 | connection->read_buffer_offset); | 2972 | connection->read_buffer_offset); |
2947 | break; | 2973 | break; |
2948 | } | 2974 | } |
2949 | return; | 2975 | return; |
2950 | } | 2976 | } |
2951 | 2977 | ||
@@ -2966,258 +2992,261 @@ MHD_connection_handle_write (struct MHD_Connection *connection) | |||
2966 | 2992 | ||
2967 | #ifdef HTTPS_SUPPORT | 2993 | #ifdef HTTPS_SUPPORT |
2968 | if (MHD_TLS_CONN_NO_TLS != connection->tls_state) | 2994 | if (MHD_TLS_CONN_NO_TLS != connection->tls_state) |
2969 | { /* HTTPS connection. */ | 2995 | { /* HTTPS connection. */ |
2970 | if (MHD_TLS_CONN_CONNECTED > connection->tls_state) | 2996 | if (MHD_TLS_CONN_CONNECTED > connection->tls_state) |
2971 | { | 2997 | { |
2972 | if (!MHD_run_tls_handshake_ (connection)) | 2998 | if (! MHD_run_tls_handshake_ (connection)) |
2973 | return; | 2999 | return; |
2974 | } | ||
2975 | } | 3000 | } |
3001 | } | ||
2976 | #endif /* HTTPS_SUPPORT */ | 3002 | #endif /* HTTPS_SUPPORT */ |
2977 | 3003 | ||
2978 | #if DEBUG_STATES | 3004 | #if DEBUG_STATES |
2979 | MHD_DLOG (connection->daemon, | 3005 | MHD_DLOG (connection->daemon, |
2980 | _("In function %s handling connection at state: %s\n"), | 3006 | _ ("In function %s handling connection at state: %s\n"), |
2981 | __FUNCTION__, | 3007 | __FUNCTION__, |
2982 | MHD_state_to_string (connection->state)); | 3008 | MHD_state_to_string (connection->state)); |
2983 | #endif | 3009 | #endif |
2984 | switch (connection->state) | 3010 | switch (connection->state) |
3011 | { | ||
3012 | case MHD_CONNECTION_INIT: | ||
3013 | case MHD_CONNECTION_URL_RECEIVED: | ||
3014 | case MHD_CONNECTION_HEADER_PART_RECEIVED: | ||
3015 | case MHD_CONNECTION_HEADERS_RECEIVED: | ||
3016 | mhd_assert (0); | ||
3017 | return; | ||
3018 | case MHD_CONNECTION_HEADERS_PROCESSED: | ||
3019 | return; | ||
3020 | case MHD_CONNECTION_CONTINUE_SENDING: | ||
3021 | ret = MHD_send_on_connection_ (connection, | ||
3022 | &HTTP_100_CONTINUE | ||
3023 | [connection->continue_message_write_offset], | ||
3024 | MHD_STATICSTR_LEN_ (HTTP_100_CONTINUE) | ||
3025 | - connection->continue_message_write_offset, | ||
3026 | MHD_SSO_NO_CORK); | ||
3027 | if (ret < 0) | ||
2985 | { | 3028 | { |
2986 | case MHD_CONNECTION_INIT: | 3029 | if (MHD_ERR_AGAIN_ == ret) |
2987 | case MHD_CONNECTION_URL_RECEIVED: | 3030 | return; |
2988 | case MHD_CONNECTION_HEADER_PART_RECEIVED: | ||
2989 | case MHD_CONNECTION_HEADERS_RECEIVED: | ||
2990 | mhd_assert (0); | ||
2991 | return; | ||
2992 | case MHD_CONNECTION_HEADERS_PROCESSED: | ||
2993 | return; | ||
2994 | case MHD_CONNECTION_CONTINUE_SENDING: | ||
2995 | ret = MHD_send_on_connection_ (connection, | ||
2996 | &HTTP_100_CONTINUE | ||
2997 | [connection->continue_message_write_offset], | ||
2998 | MHD_STATICSTR_LEN_ (HTTP_100_CONTINUE) - | ||
2999 | connection->continue_message_write_offset, | ||
3000 | MHD_SSO_NO_CORK); | ||
3001 | if (ret < 0) | ||
3002 | { | ||
3003 | if (MHD_ERR_AGAIN_ == ret) | ||
3004 | return; | ||
3005 | #ifdef HAVE_MESSAGES | 3031 | #ifdef HAVE_MESSAGES |
3006 | MHD_DLOG (connection->daemon, | 3032 | MHD_DLOG (connection->daemon, |
3007 | _("Failed to send data in request for %s.\n"), | 3033 | _ ("Failed to send data in request for %s.\n"), |
3008 | connection->url); | 3034 | connection->url); |
3009 | #endif | 3035 | #endif |
3010 | CONNECTION_CLOSE_ERROR (connection, | 3036 | CONNECTION_CLOSE_ERROR (connection, |
3011 | NULL); | 3037 | NULL); |
3012 | return; | 3038 | return; |
3013 | } | 3039 | } |
3014 | #if DEBUG_SEND_DATA | 3040 | #if DEBUG_SEND_DATA |
3015 | fprintf (stderr, | 3041 | fprintf (stderr, |
3016 | _("Sent 100 continue response: `%.*s'\n"), | 3042 | _ ("Sent 100 continue response: `%.*s'\n"), |
3017 | (int) ret, | 3043 | (int) ret, |
3018 | &HTTP_100_CONTINUE[connection->continue_message_write_offset]); | 3044 | &HTTP_100_CONTINUE[connection->continue_message_write_offset]); |
3019 | #endif | 3045 | #endif |
3020 | connection->continue_message_write_offset += ret; | 3046 | connection->continue_message_write_offset += ret; |
3021 | MHD_update_last_activity_ (connection); | 3047 | MHD_update_last_activity_ (connection); |
3022 | return; | 3048 | return; |
3023 | case MHD_CONNECTION_CONTINUE_SENT: | 3049 | case MHD_CONNECTION_CONTINUE_SENT: |
3024 | case MHD_CONNECTION_BODY_RECEIVED: | 3050 | case MHD_CONNECTION_BODY_RECEIVED: |
3025 | case MHD_CONNECTION_FOOTER_PART_RECEIVED: | 3051 | case MHD_CONNECTION_FOOTER_PART_RECEIVED: |
3026 | case MHD_CONNECTION_FOOTERS_RECEIVED: | 3052 | case MHD_CONNECTION_FOOTERS_RECEIVED: |
3027 | mhd_assert (0); | 3053 | mhd_assert (0); |
3028 | return; | 3054 | return; |
3029 | case MHD_CONNECTION_HEADERS_SENDING: | 3055 | case MHD_CONNECTION_HEADERS_SENDING: |
3030 | { | 3056 | { |
3031 | const size_t wb_ready = connection->write_buffer_append_offset - | 3057 | const size_t wb_ready = connection->write_buffer_append_offset |
3032 | connection->write_buffer_send_offset; | 3058 | - connection->write_buffer_send_offset; |
3033 | 3059 | ||
3034 | /* if the response body is not available, we use MHD_send_on_connection_() */ | 3060 | /* if the response body is not available, we use MHD_send_on_connection_() */ |
3035 | if (NULL != connection->response->crc) | 3061 | if (NULL != connection->response->crc) |
3036 | { | 3062 | { |
3037 | ret = MHD_send_on_connection_ (connection, | 3063 | ret = MHD_send_on_connection_ (connection, |
3038 | &connection->write_buffer | 3064 | &connection->write_buffer |
3039 | [connection->write_buffer_send_offset], | 3065 | [connection->write_buffer_send_offset], |
3040 | wb_ready, | 3066 | wb_ready, |
3041 | MHD_SSO_MAY_CORK); | 3067 | MHD_SSO_MAY_CORK); |
3042 | } | 3068 | } |
3043 | else | 3069 | else |
3044 | { | 3070 | { |
3045 | ret = MHD_send_on_connection2_ (connection, | 3071 | ret = MHD_send_on_connection2_ (connection, |
3046 | &connection->write_buffer | 3072 | &connection->write_buffer |
3047 | [connection->write_buffer_send_offset], | 3073 | [connection->write_buffer_send_offset], |
3048 | wb_ready, | 3074 | wb_ready, |
3049 | connection->response->data, | 3075 | connection->response->data, |
3050 | connection->response->data_buffer_size); | 3076 | connection->response->data_buffer_size); |
3051 | } | 3077 | } |
3052 | 3078 | ||
3053 | if (ret < 0) | 3079 | if (ret < 0) |
3054 | { | 3080 | { |
3055 | if (MHD_ERR_AGAIN_ == ret) | 3081 | if (MHD_ERR_AGAIN_ == ret) |
3056 | return; | ||
3057 | CONNECTION_CLOSE_ERROR (connection, | ||
3058 | _("Connection was closed while sending response headers.\n")); | ||
3059 | return; | ||
3060 | } | ||
3061 | if (ret > wb_ready) | ||
3062 | { | ||
3063 | mhd_assert (NULL == connection->repsonse->crc); | ||
3064 | /* We sent not just header data but also some response data, | ||
3065 | update both offsets! */ | ||
3066 | connection->write_buffer_send_offset += wb_ready; | ||
3067 | ret -= wb_ready; | ||
3068 | connection->response_write_position += ret; | ||
3069 | } | ||
3070 | else | ||
3071 | connection->write_buffer_send_offset += ret; | ||
3072 | MHD_update_last_activity_ (connection); | ||
3073 | if (MHD_CONNECTION_HEADERS_SENDING != connection->state) | ||
3074 | return; | 3082 | return; |
3075 | check_write_done (connection, | 3083 | CONNECTION_CLOSE_ERROR (connection, |
3076 | MHD_CONNECTION_HEADERS_SENT); | 3084 | _ ( |
3085 | "Connection was closed while sending response headers.\n")); | ||
3077 | return; | 3086 | return; |
3078 | } | 3087 | } |
3079 | case MHD_CONNECTION_HEADERS_SENT: | 3088 | if (ret > wb_ready) |
3089 | { | ||
3090 | mhd_assert (NULL == connection->repsonse->crc); | ||
3091 | /* We sent not just header data but also some response data, | ||
3092 | update both offsets! */ | ||
3093 | connection->write_buffer_send_offset += wb_ready; | ||
3094 | ret -= wb_ready; | ||
3095 | connection->response_write_position += ret; | ||
3096 | } | ||
3097 | else | ||
3098 | connection->write_buffer_send_offset += ret; | ||
3099 | MHD_update_last_activity_ (connection); | ||
3100 | if (MHD_CONNECTION_HEADERS_SENDING != connection->state) | ||
3101 | return; | ||
3102 | check_write_done (connection, | ||
3103 | MHD_CONNECTION_HEADERS_SENT); | ||
3080 | return; | 3104 | return; |
3081 | case MHD_CONNECTION_NORMAL_BODY_READY: | 3105 | } |
3082 | response = connection->response; | 3106 | case MHD_CONNECTION_HEADERS_SENT: |
3083 | if (connection->response_write_position < | 3107 | return; |
3084 | connection->response->total_size) | 3108 | case MHD_CONNECTION_NORMAL_BODY_READY: |
3085 | { | 3109 | response = connection->response; |
3086 | uint64_t data_write_offset; | 3110 | if (connection->response_write_position < |
3111 | connection->response->total_size) | ||
3112 | { | ||
3113 | uint64_t data_write_offset; | ||
3087 | 3114 | ||
3088 | #if defined(MHD_USE_POSIX_THREADS) || defined(MHD_USE_W32_THREADS) | 3115 | #if defined(MHD_USE_POSIX_THREADS) || defined(MHD_USE_W32_THREADS) |
3089 | if (NULL != response->crc) | 3116 | if (NULL != response->crc) |
3090 | MHD_mutex_lock_chk_ (&response->mutex); | 3117 | MHD_mutex_lock_chk_ (&response->mutex); |
3091 | #endif | 3118 | #endif |
3092 | if (MHD_YES != try_ready_normal_body (connection)) | 3119 | if (MHD_YES != try_ready_normal_body (connection)) |
3093 | { | 3120 | { |
3094 | /* mutex was already unlocked by try_ready_normal_body */ | 3121 | /* mutex was already unlocked by try_ready_normal_body */ |
3095 | return; | 3122 | return; |
3096 | } | 3123 | } |
3097 | #if defined(_MHD_HAVE_SENDFILE) | 3124 | #if defined(_MHD_HAVE_SENDFILE) |
3098 | if (MHD_resp_sender_sendfile == connection->resp_sender) | 3125 | if (MHD_resp_sender_sendfile == connection->resp_sender) |
3099 | { | 3126 | { |
3100 | ret = MHD_send_sendfile_ (connection); | 3127 | ret = MHD_send_sendfile_ (connection); |
3101 | } | 3128 | } |
3102 | else | 3129 | else |
3103 | #else /* ! _MHD_HAVE_SENDFILE */ | 3130 | #else /* ! _MHD_HAVE_SENDFILE */ |
3104 | if (1) | 3131 | if (1) |
3105 | #endif /* ! _MHD_HAVE_SENDFILE */ | 3132 | #endif /* ! _MHD_HAVE_SENDFILE */ |
3106 | { | 3133 | { |
3107 | data_write_offset = connection->response_write_position | 3134 | data_write_offset = connection->response_write_position |
3108 | - response->data_start; | 3135 | - response->data_start; |
3109 | if (data_write_offset > (uint64_t)SIZE_MAX) | 3136 | if (data_write_offset > (uint64_t) SIZE_MAX) |
3110 | MHD_PANIC (_("Data offset exceeds limit")); | 3137 | MHD_PANIC (_ ("Data offset exceeds limit")); |
3111 | ret = MHD_send_on_connection_ (connection, | 3138 | ret = MHD_send_on_connection_ (connection, |
3112 | &response->data | 3139 | &response->data |
3113 | [(size_t)data_write_offset], | 3140 | [(size_t) data_write_offset], |
3114 | response->data_size - | 3141 | response->data_size |
3115 | (size_t)data_write_offset, | 3142 | - (size_t) data_write_offset, |
3116 | MHD_SSO_NO_CORK); | 3143 | MHD_SSO_NO_CORK); |
3117 | #if DEBUG_SEND_DATA | 3144 | #if DEBUG_SEND_DATA |
3118 | if (ret > 0) | 3145 | if (ret > 0) |
3119 | fprintf (stderr, | 3146 | fprintf (stderr, |
3120 | _("Sent %d-byte DATA response: `%.*s'\n"), | 3147 | _ ("Sent %d-byte DATA response: `%.*s'\n"), |
3121 | (int) ret, | 3148 | (int) ret, |
3122 | (int) ret, | 3149 | (int) ret, |
3123 | &response->data[connection->response_write_position - | 3150 | &response->data[connection->response_write_position |
3124 | response->data_start]); | 3151 | - response->data_start]); |
3125 | #endif | 3152 | #endif |
3126 | } | 3153 | } |
3127 | #if defined(MHD_USE_POSIX_THREADS) || defined(MHD_USE_W32_THREADS) | 3154 | #if defined(MHD_USE_POSIX_THREADS) || defined(MHD_USE_W32_THREADS) |
3128 | if (NULL != response->crc) | 3155 | if (NULL != response->crc) |
3129 | MHD_mutex_unlock_chk_ (&response->mutex); | 3156 | MHD_mutex_unlock_chk_ (&response->mutex); |
3130 | #endif | ||
3131 | if (ret < 0) | ||
3132 | { | ||
3133 | if (MHD_ERR_AGAIN_ == ret) | ||
3134 | return; | ||
3135 | #ifdef HAVE_MESSAGES | ||
3136 | MHD_DLOG (connection->daemon, | ||
3137 | _("Failed to send data in request for `%s'.\n"), | ||
3138 | connection->url); | ||
3139 | #endif | 3157 | #endif |
3140 | CONNECTION_CLOSE_ERROR (connection, | ||
3141 | NULL); | ||
3142 | return; | ||
3143 | } | ||
3144 | connection->response_write_position += ret; | ||
3145 | MHD_update_last_activity_ (connection); | ||
3146 | } | ||
3147 | if (connection->response_write_position == | ||
3148 | connection->response->total_size) | ||
3149 | connection->state = MHD_CONNECTION_FOOTERS_SENT; /* have no footers */ | ||
3150 | return; | ||
3151 | case MHD_CONNECTION_NORMAL_BODY_UNREADY: | ||
3152 | mhd_assert (0); | ||
3153 | return; | ||
3154 | case MHD_CONNECTION_CHUNKED_BODY_READY: | ||
3155 | ret = MHD_send_on_connection_ (connection, | ||
3156 | &connection->write_buffer | ||
3157 | [connection->write_buffer_send_offset], | ||
3158 | connection->write_buffer_append_offset - | ||
3159 | connection->write_buffer_send_offset, | ||
3160 | MHD_SSO_NO_CORK); | ||
3161 | if (ret < 0) | 3158 | if (ret < 0) |
3162 | { | 3159 | { |
3163 | if (MHD_ERR_AGAIN_ == ret) | 3160 | if (MHD_ERR_AGAIN_ == ret) |
3164 | return; | ||
3165 | CONNECTION_CLOSE_ERROR (connection, | ||
3166 | _("Connection was closed while sending response body.\n")); | ||
3167 | return; | 3161 | return; |
3168 | } | 3162 | #ifdef HAVE_MESSAGES |
3169 | connection->write_buffer_send_offset += ret; | 3163 | MHD_DLOG (connection->daemon, |
3164 | _ ("Failed to send data in request for `%s'.\n"), | ||
3165 | connection->url); | ||
3166 | #endif | ||
3167 | CONNECTION_CLOSE_ERROR (connection, | ||
3168 | NULL); | ||
3169 | return; | ||
3170 | } | ||
3171 | connection->response_write_position += ret; | ||
3170 | MHD_update_last_activity_ (connection); | 3172 | MHD_update_last_activity_ (connection); |
3171 | if (MHD_CONNECTION_CHUNKED_BODY_READY != connection->state) | 3173 | } |
3174 | if (connection->response_write_position == | ||
3175 | connection->response->total_size) | ||
3176 | connection->state = MHD_CONNECTION_FOOTERS_SENT; /* have no footers */ | ||
3177 | return; | ||
3178 | case MHD_CONNECTION_NORMAL_BODY_UNREADY: | ||
3179 | mhd_assert (0); | ||
3180 | return; | ||
3181 | case MHD_CONNECTION_CHUNKED_BODY_READY: | ||
3182 | ret = MHD_send_on_connection_ (connection, | ||
3183 | &connection->write_buffer | ||
3184 | [connection->write_buffer_send_offset], | ||
3185 | connection->write_buffer_append_offset | ||
3186 | - connection->write_buffer_send_offset, | ||
3187 | MHD_SSO_NO_CORK); | ||
3188 | if (ret < 0) | ||
3189 | { | ||
3190 | if (MHD_ERR_AGAIN_ == ret) | ||
3172 | return; | 3191 | return; |
3173 | check_write_done (connection, | 3192 | CONNECTION_CLOSE_ERROR (connection, |
3174 | (connection->response->total_size == | 3193 | _ ( |
3175 | connection->response_write_position) ? | 3194 | "Connection was closed while sending response body.\n")); |
3176 | MHD_CONNECTION_BODY_SENT : | ||
3177 | MHD_CONNECTION_CHUNKED_BODY_UNREADY); | ||
3178 | return; | 3195 | return; |
3179 | case MHD_CONNECTION_CHUNKED_BODY_UNREADY: | 3196 | } |
3180 | case MHD_CONNECTION_BODY_SENT: | 3197 | connection->write_buffer_send_offset += ret; |
3181 | mhd_assert (0); | 3198 | MHD_update_last_activity_ (connection); |
3199 | if (MHD_CONNECTION_CHUNKED_BODY_READY != connection->state) | ||
3182 | return; | 3200 | return; |
3183 | case MHD_CONNECTION_FOOTERS_SENDING: | 3201 | check_write_done (connection, |
3184 | ret = MHD_send_on_connection_ (connection, | 3202 | (connection->response->total_size == |
3185 | &connection->write_buffer | 3203 | connection->response_write_position) ? |
3186 | [connection->write_buffer_send_offset], | 3204 | MHD_CONNECTION_BODY_SENT : |
3187 | connection->write_buffer_append_offset - | 3205 | MHD_CONNECTION_CHUNKED_BODY_UNREADY); |
3188 | connection->write_buffer_send_offset, | 3206 | return; |
3189 | MHD_SSO_HDR_CORK); | 3207 | case MHD_CONNECTION_CHUNKED_BODY_UNREADY: |
3190 | if (ret < 0) | 3208 | case MHD_CONNECTION_BODY_SENT: |
3191 | { | 3209 | mhd_assert (0); |
3192 | if (MHD_ERR_AGAIN_ == ret) | 3210 | return; |
3193 | return; | 3211 | case MHD_CONNECTION_FOOTERS_SENDING: |
3194 | CONNECTION_CLOSE_ERROR (connection, | 3212 | ret = MHD_send_on_connection_ (connection, |
3195 | _("Connection was closed while sending response body.\n")); | 3213 | &connection->write_buffer |
3196 | return; | 3214 | [connection->write_buffer_send_offset], |
3197 | } | 3215 | connection->write_buffer_append_offset |
3198 | connection->write_buffer_send_offset += ret; | 3216 | - connection->write_buffer_send_offset, |
3199 | MHD_update_last_activity_ (connection); | 3217 | MHD_SSO_HDR_CORK); |
3200 | if (MHD_CONNECTION_FOOTERS_SENDING != connection->state) | 3218 | if (ret < 0) |
3219 | { | ||
3220 | if (MHD_ERR_AGAIN_ == ret) | ||
3201 | return; | 3221 | return; |
3202 | check_write_done (connection, | 3222 | CONNECTION_CLOSE_ERROR (connection, |
3203 | MHD_CONNECTION_FOOTERS_SENT); | 3223 | _ ( |
3204 | return; | 3224 | "Connection was closed while sending response body.\n")); |
3205 | case MHD_CONNECTION_FOOTERS_SENT: | ||
3206 | mhd_assert (0); | ||
3207 | return; | 3225 | return; |
3208 | case MHD_CONNECTION_CLOSED: | 3226 | } |
3227 | connection->write_buffer_send_offset += ret; | ||
3228 | MHD_update_last_activity_ (connection); | ||
3229 | if (MHD_CONNECTION_FOOTERS_SENDING != connection->state) | ||
3209 | return; | 3230 | return; |
3231 | check_write_done (connection, | ||
3232 | MHD_CONNECTION_FOOTERS_SENT); | ||
3233 | return; | ||
3234 | case MHD_CONNECTION_FOOTERS_SENT: | ||
3235 | mhd_assert (0); | ||
3236 | return; | ||
3237 | case MHD_CONNECTION_CLOSED: | ||
3238 | return; | ||
3210 | #ifdef UPGRADE_SUPPORT | 3239 | #ifdef UPGRADE_SUPPORT |
3211 | case MHD_CONNECTION_UPGRADE: | 3240 | case MHD_CONNECTION_UPGRADE: |
3212 | mhd_assert (0); | 3241 | mhd_assert (0); |
3213 | return; | 3242 | return; |
3214 | #endif /* UPGRADE_SUPPORT */ | 3243 | #endif /* UPGRADE_SUPPORT */ |
3215 | default: | 3244 | default: |
3216 | mhd_assert (0); | 3245 | mhd_assert (0); |
3217 | CONNECTION_CLOSE_ERROR (connection, | 3246 | CONNECTION_CLOSE_ERROR (connection, |
3218 | _("Internal error\n")); | 3247 | _ ("Internal error\n")); |
3219 | break; | 3248 | break; |
3220 | } | 3249 | } |
3221 | return; | 3250 | return; |
3222 | } | 3251 | } |
3223 | 3252 | ||
@@ -3239,59 +3268,60 @@ cleanup_connection (struct MHD_Connection *connection) | |||
3239 | return; /* Prevent double cleanup. */ | 3268 | return; /* Prevent double cleanup. */ |
3240 | connection->in_cleanup = true; | 3269 | connection->in_cleanup = true; |
3241 | if (NULL != connection->response) | 3270 | if (NULL != connection->response) |
3242 | { | 3271 | { |
3243 | MHD_destroy_response (connection->response); | 3272 | MHD_destroy_response (connection->response); |
3244 | connection->response = NULL; | 3273 | connection->response = NULL; |
3245 | } | 3274 | } |
3246 | #if defined(MHD_USE_POSIX_THREADS) || defined(MHD_USE_W32_THREADS) | 3275 | #if defined(MHD_USE_POSIX_THREADS) || defined(MHD_USE_W32_THREADS) |
3247 | MHD_mutex_lock_chk_ (&daemon->cleanup_connection_mutex); | 3276 | MHD_mutex_lock_chk_ (&daemon->cleanup_connection_mutex); |
3248 | #endif | 3277 | #endif |
3249 | if (connection->suspended) | 3278 | if (connection->suspended) |
3250 | { | 3279 | { |
3251 | DLL_remove (daemon->suspended_connections_head, | 3280 | DLL_remove (daemon->suspended_connections_head, |
3252 | daemon->suspended_connections_tail, | 3281 | daemon->suspended_connections_tail, |
3253 | connection); | 3282 | connection); |
3254 | connection->suspended = false; | 3283 | connection->suspended = false; |
3255 | } | 3284 | } |
3256 | else | 3285 | else |
3286 | { | ||
3287 | if (0 == (daemon->options & MHD_USE_THREAD_PER_CONNECTION)) | ||
3257 | { | 3288 | { |
3258 | if (0 == (daemon->options & MHD_USE_THREAD_PER_CONNECTION)) | 3289 | if (connection->connection_timeout == daemon->connection_timeout) |
3259 | { | 3290 | XDLL_remove (daemon->normal_timeout_head, |
3260 | if (connection->connection_timeout == daemon->connection_timeout) | 3291 | daemon->normal_timeout_tail, |
3261 | XDLL_remove (daemon->normal_timeout_head, | 3292 | connection); |
3262 | daemon->normal_timeout_tail, | 3293 | else |
3263 | connection); | 3294 | XDLL_remove (daemon->manual_timeout_head, |
3264 | else | 3295 | daemon->manual_timeout_tail, |
3265 | XDLL_remove (daemon->manual_timeout_head, | 3296 | connection); |
3266 | daemon->manual_timeout_tail, | ||
3267 | connection); | ||
3268 | } | ||
3269 | DLL_remove (daemon->connections_head, | ||
3270 | daemon->connections_tail, | ||
3271 | connection); | ||
3272 | } | 3297 | } |
3298 | DLL_remove (daemon->connections_head, | ||
3299 | daemon->connections_tail, | ||
3300 | connection); | ||
3301 | } | ||
3273 | DLL_insert (daemon->cleanup_head, | 3302 | DLL_insert (daemon->cleanup_head, |
3274 | daemon->cleanup_tail, | 3303 | daemon->cleanup_tail, |
3275 | connection); | 3304 | connection); |
3276 | connection->resuming = false; | 3305 | connection->resuming = false; |
3277 | connection->in_idle = false; | 3306 | connection->in_idle = false; |
3278 | #if defined(MHD_USE_POSIX_THREADS) || defined(MHD_USE_W32_THREADS) | 3307 | #if defined(MHD_USE_POSIX_THREADS) || defined(MHD_USE_W32_THREADS) |
3279 | MHD_mutex_unlock_chk_(&daemon->cleanup_connection_mutex); | 3308 | MHD_mutex_unlock_chk_ (&daemon->cleanup_connection_mutex); |
3280 | #endif | 3309 | #endif |
3281 | if (0 != (daemon->options & MHD_USE_THREAD_PER_CONNECTION)) | 3310 | if (0 != (daemon->options & MHD_USE_THREAD_PER_CONNECTION)) |
3311 | { | ||
3312 | /* if we were at the connection limit before and are in | ||
3313 | thread-per-connection mode, signal the main thread | ||
3314 | to resume accepting connections */ | ||
3315 | if ( (MHD_ITC_IS_VALID_ (daemon->itc)) && | ||
3316 | (! MHD_itc_activate_ (daemon->itc, "c")) ) | ||
3282 | { | 3317 | { |
3283 | /* if we were at the connection limit before and are in | ||
3284 | thread-per-connection mode, signal the main thread | ||
3285 | to resume accepting connections */ | ||
3286 | if ( (MHD_ITC_IS_VALID_ (daemon->itc)) && | ||
3287 | (! MHD_itc_activate_ (daemon->itc, "c")) ) | ||
3288 | { | ||
3289 | #ifdef HAVE_MESSAGES | 3318 | #ifdef HAVE_MESSAGES |
3290 | MHD_DLOG (daemon, | 3319 | MHD_DLOG (daemon, |
3291 | _("Failed to signal end of connection via inter-thread communication channel")); | 3320 | _ ( |
3321 | "Failed to signal end of connection via inter-thread communication channel")); | ||
3292 | #endif | 3322 | #endif |
3293 | } | ||
3294 | } | 3323 | } |
3324 | } | ||
3295 | } | 3325 | } |
3296 | 3326 | ||
3297 | 3327 | ||
@@ -3315,471 +3345,475 @@ MHD_connection_handle_idle (struct MHD_Connection *connection) | |||
3315 | 3345 | ||
3316 | connection->in_idle = true; | 3346 | connection->in_idle = true; |
3317 | while (! connection->suspended) | 3347 | while (! connection->suspended) |
3318 | { | 3348 | { |
3319 | #ifdef HTTPS_SUPPORT | 3349 | #ifdef HTTPS_SUPPORT |
3320 | if (MHD_TLS_CONN_NO_TLS != connection->tls_state) | 3350 | if (MHD_TLS_CONN_NO_TLS != connection->tls_state) |
3321 | { /* HTTPS connection. */ | 3351 | { /* HTTPS connection. */ |
3322 | if ((MHD_TLS_CONN_INIT <= connection->tls_state) && | 3352 | if ((MHD_TLS_CONN_INIT <= connection->tls_state) && |
3323 | (MHD_TLS_CONN_CONNECTED > connection->tls_state)) | 3353 | (MHD_TLS_CONN_CONNECTED > connection->tls_state)) |
3324 | break; | 3354 | break; |
3325 | } | 3355 | } |
3326 | #endif /* HTTPS_SUPPORT */ | 3356 | #endif /* HTTPS_SUPPORT */ |
3327 | #if DEBUG_STATES | 3357 | #if DEBUG_STATES |
3328 | MHD_DLOG (daemon, | 3358 | MHD_DLOG (daemon, |
3329 | _("In function %s handling connection at state: %s\n"), | 3359 | _ ("In function %s handling connection at state: %s\n"), |
3330 | __FUNCTION__, | 3360 | __FUNCTION__, |
3331 | MHD_state_to_string (connection->state)); | 3361 | MHD_state_to_string (connection->state)); |
3332 | #endif | 3362 | #endif |
3333 | switch (connection->state) | 3363 | switch (connection->state) |
3364 | { | ||
3365 | case MHD_CONNECTION_INIT: | ||
3366 | line = get_next_header_line (connection, | ||
3367 | &line_len); | ||
3368 | /* Check for empty string, as we might want | ||
3369 | to tolerate 'spurious' empty lines; also | ||
3370 | NULL means we didn't get a full line yet; | ||
3371 | line is not 0-terminated here. */ | ||
3372 | if ( (NULL == line) || | ||
3373 | (0 == line[0]) ) | ||
3374 | { | ||
3375 | if (MHD_CONNECTION_INIT != connection->state) | ||
3376 | continue; | ||
3377 | if (connection->read_closed) | ||
3334 | { | 3378 |