GNU libmicrohttpd 0.9.75
Loading...
Searching...
No Matches
connection.c
Go to the documentation of this file.
1/*
2 This file is part of libmicrohttpd
3 Copyright (C) 2007-2020 Daniel Pittman and Christian Grothoff
4 Copyright (C) 2015-2021 Evgeny Grin (Karlson2k)
5
6 This library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Lesser General Public
8 License as published by the Free Software Foundation; either
9 version 2.1 of the License, or (at your option) any later version.
10
11 This library is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
15
16 You should have received a copy of the GNU Lesser General Public
17 License along with this library; if not, write to the Free Software
18 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19
20*/
28#include "internal.h"
29#include "mhd_limits.h"
30#include "connection.h"
31#include "memorypool.h"
32#include "response.h"
33#include "mhd_mono_clock.h"
34#include "mhd_str.h"
35#if defined(MHD_USE_POSIX_THREADS) || defined(MHD_USE_W32_THREADS)
36#include "mhd_locks.h"
37#endif
38#include "mhd_sockets.h"
39#include "mhd_compat.h"
40#include "mhd_itc.h"
41#ifdef MHD_LINUX_SOLARIS_SENDFILE
42#include <sys/sendfile.h>
43#endif /* MHD_LINUX_SOLARIS_SENDFILE */
44#if defined(HAVE_FREEBSD_SENDFILE) || defined(HAVE_DARWIN_SENDFILE)
45#include <sys/types.h>
46#include <sys/socket.h>
47#include <sys/uio.h>
48#endif /* HAVE_FREEBSD_SENDFILE || HAVE_DARWIN_SENDFILE */
49#ifdef HTTPS_SUPPORT
50#include "connection_https.h"
51#endif /* HTTPS_SUPPORT */
52#ifdef HAVE_SYS_PARAM_H
53/* For FreeBSD version identification */
54#include <sys/param.h>
55#endif /* HAVE_SYS_PARAM_H */
56#include "mhd_send.h"
57#include "mhd_assert.h"
58
62#define HTTP_100_CONTINUE "HTTP/1.1 100 Continue\r\n\r\n"
63
71#ifdef HAVE_MESSAGES
72#define REQUEST_TOO_BIG \
73 "<html><head><title>Request too big</title></head><body>Your HTTP header was too big for the memory constraints of this webserver.</body></html>"
74#else
75#define REQUEST_TOO_BIG ""
76#endif
77
85#ifdef HAVE_MESSAGES
86#define REQUEST_LACKS_HOST \
87 "<html><head><title>&quot;Host:&quot; header required</title></head><body>In HTTP 1.1, requests must include a &quot;Host:&quot; header, and your HTTP 1.1 request lacked such a header.</body></html>"
88#else
89#define REQUEST_LACKS_HOST ""
90#endif
91
99#ifdef HAVE_MESSAGES
100#define REQUEST_MALFORMED \
101 "<html><head><title>Request malformed</title></head><body>Your HTTP request was syntactically incorrect.</body></html>"
102#else
103#define REQUEST_MALFORMED ""
104#endif
105
110#ifdef HAVE_MESSAGES
111#define REQUEST_CHUNKED_MALFORMED \
112 "<html><head><title>Request malformed</title></head><body>Your HTTP chunked encoding was syntactically incorrect.</body></html>"
113#else
114#define REQUEST_CHUNKED_MALFORMED ""
115#endif
116
120#ifdef HAVE_MESSAGES
121#define REQUEST_CHUNK_TOO_LARGE \
122 "<html><head><title>Request content too large</title></head><body>The chunk size used in your HTTP chunked encoded request is too large.</body></html>"
123#else
124#define REQUEST_CHUNK_TOO_LARGE ""
125#endif
126
130#ifdef HAVE_MESSAGES
131#define REQUEST_CONTENTLENGTH_TOOLARGE \
132 "<html><head><title>Request content too large</title></head>" \
133 "<body>Your HTTP request has too large value for <b>Content-Length</b> header.</body></html>"
134#else
135#define REQUEST_CONTENTLENGTH_TOOLARGE ""
136#endif
137
142#ifdef HAVE_MESSAGES
143#define REQUEST_CONTENTLENGTH_MALFORMED \
144 "<html><head><title>Request malformed</title></head>" \
145 "<body>Your HTTP request has wrong value for <b>Content-Length</b> header.</body></html>"
146#else
147#define REQUEST_CONTENTLENGTH_MALFORMED ""
148#endif
149
156#ifdef HAVE_MESSAGES
157#define INTERNAL_ERROR \
158 "<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>"
159#else
160#define INTERNAL_ERROR ""
161#endif
162
166#ifdef HAVE_MESSAGES
167#define REQ_HTTP_VER_IS_TOO_OLD \
168 "<html><head><title>Requested HTTP version is not supported</title></head><body>Requested HTTP version is too old and not supported.</body></html>"
169#else
170#define REQ_HTTP_VER_IS_TOO_OLD ""
171#endif
172
176#ifdef HAVE_MESSAGES
177#define REQ_HTTP_VER_IS_NOT_SUPPORTED \
178 "<html><head><title>Requested HTTP version is not supported</title></head><body>Requested HTTP version is not supported.</body></html>"
179#else
180#define REQ_HTTP_VER_IS_NOT_SUPPORTED ""
181#endif
182
183
187#define MHD_SENFILE_CHUNK_ (0x20000)
188
192#define MHD_SENFILE_CHUNK_THR_P_C_ (0x200000)
193
194#ifdef HAVE_MESSAGES
200static const char *
201str_conn_error_ (ssize_t mhd_err_code)
202{
203 switch (mhd_err_code)
204 {
205 case MHD_ERR_AGAIN_:
206 return _ ("The operation would block, retry later");
208 return _ ("The connection was forcibly closed by remote peer");
209 case MHD_ERR_NOTCONN_:
210 return _ ("The socket is not connected");
211 case MHD_ERR_NOMEM_:
212 return _ ("Not enough system resources to serve the request");
213 case MHD_ERR_BADF_:
214 return _ ("Bad FD value");
215 case MHD_ERR_INVAL_:
216 return _ ("Argument value is invalid");
218 return _ ("Argument value is not supported");
219 case MHD_ERR_PIPE_:
220 return _ ("The socket is no longer available for sending");
221 case MHD_ERR_TLS_:
222 return _ ("TLS encryption or decryption error");
223 default:
224 break; /* Mute compiler warning */
225 }
226 if (0 <= mhd_err_code)
227 return _ ("Not an error code");
228
229 mhd_assert (0); /* Should never be reachable */
230 return _ ("Wrong error code value");
231}
232
233
234#endif /* HAVE_MESSAGES */
235
245static void *
247 size_t size)
248{
249 struct MHD_Connection *const c = connection; /* a short alias */
250 struct MemoryPool *const pool = c->pool; /* a short alias */
251 size_t need_to_free;
252 void *res;
253
254 res = MHD_pool_try_alloc (pool, size, &need_to_free);
255 if (NULL == res)
256 {
257 if (NULL != c->write_buffer)
258 {
259 /* The connection is in the sending phase */
260 mhd_assert (MHD_CONNECTION_START_REPLY <= c->state);
261 if (c->write_buffer_size - c->write_buffer_append_offset >= need_to_free)
262 {
263 char *buf;
264 const size_t new_buf_size = c->write_buffer_size - need_to_free;
265 buf = MHD_pool_reallocate (pool,
266 c->write_buffer,
268 new_buf_size);
269 mhd_assert (c->write_buffer == buf);
270 mhd_assert (c->write_buffer_append_offset <= new_buf_size);
271 mhd_assert (c->write_buffer_send_offset <= new_buf_size);
272 c->write_buffer_size = new_buf_size;
273 c->write_buffer = buf;
274 }
275 else
276 return NULL;
277 }
278 else if (NULL != c->read_buffer)
279 {
280 /* The connection is in the receiving phase */
281 if (c->read_buffer_size - c->read_buffer_offset >= need_to_free)
282 {
283 char *buf;
284 const size_t new_buf_size = c->read_buffer_size - need_to_free;
285 buf = MHD_pool_reallocate (pool,
286 c->read_buffer,
288 new_buf_size);
289 mhd_assert (c->read_buffer == buf);
290 mhd_assert (c->read_buffer_offset <= new_buf_size);
291 c->read_buffer_size = new_buf_size;
292 c->read_buffer = buf;
293 }
294 else
295 return NULL;
296 }
297 else
298 return NULL;
299 res = MHD_pool_allocate (pool, size, true);
300 mhd_assert (NULL != res); /* It has been checked that pool has enough space */
301 }
302 return res;
303}
304
305
315static ssize_t
317 void *other,
318 size_t i)
319{
320 ssize_t ret;
321
322 if ( (MHD_INVALID_SOCKET == connection->socket_fd) ||
323 (MHD_CONNECTION_CLOSED == connection->state) )
324 {
325 return MHD_ERR_NOTCONN_;
326 }
328 i = MHD_SCKT_SEND_MAX_SIZE_; /* return value limit */
329
330 ret = MHD_recv_ (connection->socket_fd,
331 other,
332 i);
333 if (0 > ret)
334 {
335 const int err = MHD_socket_get_error_ ();
336 if (MHD_SCKT_ERR_IS_EAGAIN_ (err))
337 {
338#ifdef EPOLL_SUPPORT
339 /* Got EAGAIN --- no longer read-ready */
340 connection->epoll_state &=
342#endif /* EPOLL_SUPPORT */
343 return MHD_ERR_AGAIN_;
344 }
345 if (MHD_SCKT_ERR_IS_EINTR_ (err))
346 return MHD_ERR_AGAIN_;
348 return MHD_ERR_CONNRESET_;
350 return MHD_ERR_OPNOTSUPP_;
352 return MHD_ERR_NOTCONN_;
354 return MHD_ERR_INVAL_;
356 return MHD_ERR_NOMEM_;
358 return MHD_ERR_BADF_;
359 /* Treat any other error as a hard error. */
360 return MHD_ERR_NOTCONN_;
361 }
362#ifdef EPOLL_SUPPORT
363 else if (i > (size_t) ret)
364 connection->epoll_state &=
366#endif /* EPOLL_SUPPORT */
367 return ret;
368}
369
370
383int
385 enum MHD_ValueKind kind,
386 MHD_KeyValueIterator iterator,
387 void *iterator_cls)
388{
389 int ret;
390 struct MHD_HTTP_Header *pos;
391
392 if (NULL == connection)
393 return -1;
394 ret = 0;
395 for (pos = connection->headers_received; NULL != pos; pos = pos->next)
396 if (0 != (pos->kind & kind))
397 {
398 ret++;
399 if ( (NULL != iterator) &&
400 (MHD_NO == iterator (iterator_cls,
401 pos->kind,
402 pos->header,
403 pos->value)) )
404 return ret;
405 }
406 return ret;
407}
408
409
422int
424 enum MHD_ValueKind kind,
425 MHD_KeyValueIteratorN iterator,
426 void *iterator_cls)
427{
428 int ret;
429 struct MHD_HTTP_Header *pos;
430
431 if (NULL == connection)
432 return -1;
433 ret = 0;
434
435 if (NULL == iterator)
436 for (pos = connection->headers_received; NULL != pos; pos = pos->next)
437 {
438 if (0 != (kind & pos->kind))
439 ret++;
440 }
441 else
442 for (pos = connection->headers_received; NULL != pos; pos = pos->next)
443 if (0 != (kind & pos->kind))
444 {
445 ret++;
446 if (MHD_NO == iterator (iterator_cls,
447 pos->kind,
448 pos->header,
449 pos->header_size,
450 pos->value,
451 pos->value_size))
452 return ret;
453 }
454 return ret;
455}
456
457
475static enum MHD_Result
477 enum MHD_ValueKind kind,
478 const char *key,
479 size_t key_size,
480 const char *value,
481 size_t value_size)
482{
483 struct MHD_HTTP_Header *pos;
484
485 pos = connection_alloc_memory (connection,
486 sizeof (struct MHD_HTTP_Header));
487 if (NULL == pos)
488 return MHD_NO;
489 pos->header = (char *) key;
490 pos->header_size = key_size;
491 pos->value = (char *) value;
492 pos->value_size = value_size;
493 pos->kind = kind;
494 pos->next = NULL;
495 /* append 'pos' to the linked list of headers */
496 if (NULL == connection->headers_received_tail)
497 {
498 connection->headers_received = pos;
499 connection->headers_received_tail = pos;
500 }
501 else
502 {
503 connection->headers_received_tail->next = pos;
504 connection->headers_received_tail = pos;
505 }
506 return MHD_YES;
507}
508
509
535enum MHD_Result
537 enum MHD_ValueKind kind,
538 const char *key,
539 size_t key_size,
540 const char *value,
541 size_t value_size)
542{
543 if ( (MHD_GET_ARGUMENT_KIND != kind) &&
544 ( ((key ? strlen (key) : 0) != key_size) ||
545 ((value ? strlen (value) : 0) != value_size) ) )
546 return MHD_NO; /* binary zero is allowed only in GET arguments */
547
548 return MHD_set_connection_value_n_nocheck_ (connection,
549 kind,
550 key,
551 key_size,
552 value,
553 value_size);
554}
555
556
582enum MHD_Result
584 enum MHD_ValueKind kind,
585 const char *key,
586 const char *value)
587{
588 return MHD_set_connection_value_n_nocheck_ (connection,
589 kind,
590 key,
591 NULL != key
592 ? strlen (key)
593 : 0,
594 value,
595 NULL != value
596 ? strlen (value)
597 : 0);
598}
599
600
611const char *
613 enum MHD_ValueKind kind,
614 const char *key)
615{
616 const char *value;
617
618 value = NULL;
619 (void) MHD_lookup_connection_value_n (connection,
620 kind,
621 key,
622 (NULL == key) ? 0 : strlen (key),
623 &value,
624 NULL);
625 return value;
626}
627
628
650 enum MHD_ValueKind kind,
651 const char *key,
652 size_t key_size,
653 const char **value_ptr,
654 size_t *value_size_ptr)
655{
656 struct MHD_HTTP_Header *pos;
657
658 if (NULL == connection)
659 return MHD_NO;
660
661 if (NULL == key)
662 {
663 for (pos = connection->headers_received; NULL != pos; pos = pos->next)
664 {
665 if ( (0 != (kind & pos->kind)) &&
666 (NULL == pos->header) )
667 break;
668 }
669 }
670 else
671 {
672 for (pos = connection->headers_received; NULL != pos; pos = pos->next)
673 {
674 if ( (0 != (kind & pos->kind)) &&
675 (key_size == pos->header_size) &&
676 ( (key == pos->header) ||
678 pos->header,
679 key_size) ) ) )
680 break;
681 }
682 }
683
684 if (NULL == pos)
685 return MHD_NO;
686
687 if (NULL != value_ptr)
688 *value_ptr = pos->value;
689
690 if (NULL != value_size_ptr)
691 *value_size_ptr = pos->value_size;
692
693 return MHD_YES;
694}
695
696
712static bool
714 const char *header,
715 size_t header_len,
716 const char *token,
717 size_t token_len)
718{
719 struct MHD_HTTP_Header *pos;
720
721 if ((NULL == connection) || (NULL == header) || (0 == header[0]) || (NULL ==
722 token) ||
723 (0 ==
724 token
725 [
726 0]) )
727 return false;
728
729 for (pos = connection->headers_received; NULL != pos; pos = pos->next)
730 {
731 if ((0 != (pos->kind & MHD_HEADER_KIND)) &&
732 (header_len == pos->header_size) &&
733 ( (header == pos->header) ||
735 pos->header,
736 header_len)) ) &&
737 (MHD_str_has_token_caseless_ (pos->value, token, token_len)))
738 return true;
739 }
740 return false;
741}
742
743
755#define MHD_lookup_header_s_token_ci(c,h,tkn) \
756 MHD_lookup_header_token_ci ((c),(h),MHD_STATICSTR_LEN_ (h), \
757 (tkn),MHD_STATICSTR_LEN_ (tkn))
758
759
767static bool
769{
770 const char *expect;
771
772 return (MHD_IS_HTTP_VER_1_1_COMPAT (connection->http_ver) &&
778 &expect,
779 NULL)) &&
781 "100-continue")) );
782}
783
784
791void
793{
794 const struct MHD_Daemon *daemon = connection->daemon;
795
796 if (0 == (daemon->options & MHD_USE_TURBO))
797 {
798#ifdef HTTPS_SUPPORT
799 /* For TLS connection use shutdown of TLS layer
800 * and do not shutdown TCP socket. This give more
801 * chances to send TLS closure data to remote side.
802 * Closure of TLS layer will be interpreted by
803 * remote side as end of transmission. */
804 if (0 != (daemon->options & MHD_USE_TLS))
805 {
806 if (! MHD_tls_connection_shutdown (connection))
807 shutdown (connection->socket_fd,
808 SHUT_WR);
809 }
810 else /* Combined with next 'shutdown()'. */
811#endif /* HTTPS_SUPPORT */
812 shutdown (connection->socket_fd,
813 SHUT_WR);
814 }
815 connection->state = MHD_CONNECTION_CLOSED;
817}
818
819
829void
831 enum MHD_RequestTerminationCode termination_code)
832{
833 struct MHD_Daemon *daemon = connection->daemon;
834 struct MHD_Response *resp = connection->response;
835
836#ifdef MHD_USE_THREADS
837 mhd_assert ( (0 == (daemon->options & MHD_USE_INTERNAL_POLLING_THREAD)) || \
838 MHD_thread_ID_match_current_ (connection->pid) );
839#endif /* MHD_USE_THREADS */
840 if ( (NULL != daemon->notify_completed) &&
841 (connection->client_aware) )
842 daemon->notify_completed (daemon->notify_completed_cls,
843 connection,
844 &connection->client_context,
845 termination_code);
846 connection->client_aware = false;
847 if (NULL != resp)
848 {
849 connection->response = NULL;
851 }
852 if (NULL != connection->pool)
853 {
854 MHD_pool_destroy (connection->pool);
855 connection->pool = NULL;
856 }
857
858 MHD_connection_mark_closed_ (connection);
859}
860
861
862#if defined(HTTPS_SUPPORT) && defined(UPGRADE_SUPPORT)
873void
875{
876 struct MHD_Daemon *daemon = connection->daemon;
877 struct MHD_UpgradeResponseHandle *urh = connection->urh;
878
879#ifdef MHD_USE_THREADS
880 mhd_assert ( (0 == (daemon->options & MHD_USE_INTERNAL_POLLING_THREAD)) || \
881 (0 != (daemon->options & MHD_USE_THREAD_PER_CONNECTION)) || \
882 MHD_thread_ID_match_current_ (daemon->pid) );
883#endif /* MHD_USE_THREADS */
884
885 if (0 == (daemon->options & MHD_USE_TLS))
886 return; /* Nothing to do with non-TLS connection. */
887
888 if (0 == (daemon->options & MHD_USE_THREAD_PER_CONNECTION))
889 DLL_remove (daemon->urh_head,
890 daemon->urh_tail,
891 urh);
892#if EPOLL_SUPPORT
893 if ( (0 != (daemon->options & MHD_USE_EPOLL)) &&
894 (0 != epoll_ctl (daemon->epoll_upgrade_fd,
895 EPOLL_CTL_DEL,
896 connection->socket_fd,
897 NULL)) )
898 {
899 MHD_PANIC (_ ("Failed to remove FD from epoll set.\n"));
900 }
901 if (urh->in_eready_list)
902 {
903 EDLL_remove (daemon->eready_urh_head,
904 daemon->eready_urh_tail,
905 urh);
906 urh->in_eready_list = false;
907 }
908#endif /* EPOLL_SUPPORT */
909 if (MHD_INVALID_SOCKET != urh->mhd.socket)
910 {
911#if EPOLL_SUPPORT
912 if ( (0 != (daemon->options & MHD_USE_EPOLL)) &&
913 (0 != epoll_ctl (daemon->epoll_upgrade_fd,
914 EPOLL_CTL_DEL,
915 urh->mhd.socket,
916 NULL)) )
917 {
918 MHD_PANIC (_ ("Failed to remove FD from epoll set.\n"));
919 }
920#endif /* EPOLL_SUPPORT */
921 /* Reflect remote disconnect to application by breaking
922 * socketpair connection. */
923 shutdown (urh->mhd.socket, SHUT_RDWR);
924 }
925 /* Socketpair sockets will remain open as they will be
926 * used with MHD_UPGRADE_ACTION_CLOSE. They will be
927 * closed by cleanup_upgraded_connection() during
928 * connection's final cleanup.
929 */
930}
931
932
933#endif /* HTTPS_SUPPORT && UPGRADE_SUPPORT*/
934
935
943static void
945 const char *emsg)
946{
947 connection->stop_with_error = true;
948 connection->discard_request = true;
949#ifdef HAVE_MESSAGES
950 if (NULL != emsg)
951 MHD_DLOG (connection->daemon,
952 "%s\n",
953 emsg);
954#else /* ! HAVE_MESSAGES */
955 (void) emsg; /* Mute compiler warning. */
956#endif /* ! HAVE_MESSAGES */
957 MHD_connection_close_ (connection,
959}
960
961
966#ifdef HAVE_MESSAGES
967#define CONNECTION_CLOSE_ERROR(c, emsg) connection_close_error (c, emsg)
968#else
969#define CONNECTION_CLOSE_ERROR(c, emsg) connection_close_error (c, NULL)
970#endif
971
972
980static void
982 const char *emsg)
983{
984 if ( (NULL != connection->response) &&
985 (400 <= connection->responseCode) &&
986 (NULL == connection->response->crc) && /* Static response only! */
987 (connection->stop_with_error) &&
988 (MHD_CONNECTION_HEADERS_SENDING == connection->state) )
989 return; /* An error response was already queued */
990
991 connection_close_error (connection, emsg);
992}
993
994
999#ifdef HAVE_MESSAGES
1000#define CONNECTION_CLOSE_ERROR_CHECK(c, emsg) \
1001 connection_close_error_check (c, emsg)
1002#else
1003#define CONNECTION_CLOSE_ERROR_CHECK(c, emsg) \
1004 connection_close_error_check (c, NULL)
1005#endif
1006
1007
1020static enum MHD_Result
1022{
1023 ssize_t ret;
1024 struct MHD_Response *response;
1025
1026 response = connection->response;
1027 mhd_assert (connection->rp_props.send_reply_body);
1028
1029 if ( (0 == response->total_size) ||
1030 /* TODO: replace the next check with assert */
1031 (connection->response_write_position == response->total_size) )
1032 return MHD_YES; /* 0-byte response is always ready */
1033 if (NULL != response->data_iov)
1034 {
1035 size_t copy_size;
1036
1037 if (NULL != connection->resp_iov.iov)
1038 return MHD_YES;
1039 copy_size = response->data_iovcnt * sizeof(MHD_iovec_);
1040 connection->resp_iov.iov = connection_alloc_memory (connection,
1041 copy_size);
1042 if (NULL == connection->resp_iov.iov)
1043 {
1044 MHD_mutex_unlock_chk_ (&response->mutex);
1045 /* not enough memory */
1046 CONNECTION_CLOSE_ERROR (connection,
1047 _ ("Closing connection (out of memory)."));
1048 return MHD_NO;
1049 }
1050 memcpy (connection->resp_iov.iov,
1051 response->data_iov,
1052 copy_size);
1053 connection->resp_iov.cnt = response->data_iovcnt;
1054 connection->resp_iov.sent = 0;
1055 return MHD_YES;
1056 }
1057 if (NULL == response->crc)
1058 return MHD_YES;
1059 if ( (response->data_start <=
1060 connection->response_write_position) &&
1061 (response->data_size + response->data_start >
1062 connection->response_write_position) )
1063 return MHD_YES; /* response already ready */
1064#if defined(_MHD_HAVE_SENDFILE)
1065 if (MHD_resp_sender_sendfile == connection->resp_sender)
1066 {
1067 /* will use sendfile, no need to bother response crc */
1068 return MHD_YES;
1069 }
1070#endif /* _MHD_HAVE_SENDFILE */
1071
1072 ret = response->crc (response->crc_cls,
1073 connection->response_write_position,
1074 response->data,
1075 (size_t) MHD_MIN ((uint64_t) response->data_buffer_size,
1076 response->total_size
1077 - connection->response_write_position));
1078 if ( (MHD_CONTENT_READER_END_OF_STREAM == ret) ||
1080 {
1081 /* either error or http 1.0 transfer, close socket! */
1082 /* TODO: do not update total size, check whether response
1083 * was really with unknown size */
1084 response->total_size = connection->response_write_position;
1085#if defined(MHD_USE_POSIX_THREADS) || defined(MHD_USE_W32_THREADS)
1086 MHD_mutex_unlock_chk_ (&response->mutex);
1087#endif
1089 MHD_connection_close_ (connection,
1091 else
1092 CONNECTION_CLOSE_ERROR (connection,
1093 _ (
1094 "Closing connection (application reported error generating data)."));
1095 return MHD_NO;
1096 }
1097 response->data_start = connection->response_write_position;
1098 response->data_size = ret;
1099 if (0 == ret)
1100 {
1102#if defined(MHD_USE_POSIX_THREADS) || defined(MHD_USE_W32_THREADS)
1103 MHD_mutex_unlock_chk_ (&response->mutex);
1104#endif
1105 return MHD_NO;
1106 }
1107 return MHD_YES;
1108}
1109
1110
1123static enum MHD_Result
1125 bool *p_finished)
1126{
1127 ssize_t ret;
1128 struct MHD_Response *response;
1129 static const size_t max_chunk = 0xFFFFFF;
1130 char chunk_hdr[6]; /* 6: max strlen of "FFFFFF" */
1131 /* "FFFFFF" + "\r\n" */
1132 static const size_t max_chunk_hdr_len = sizeof(chunk_hdr) + 2;
1133 /* "FFFFFF" + "\r\n" + "\r\n" (chunk termination) */
1134 static const size_t max_chunk_overhead = sizeof(chunk_hdr) + 2 + 2;
1135 size_t chunk_hdr_len;
1136 uint64_t left_to_send;
1137 size_t size_to_fill;
1138
1139 response = connection->response;
1140 mhd_assert (NULL != response->crc || NULL != response->data);
1141
1142 mhd_assert (0 == connection->write_buffer_append_offset);
1143
1144 /* The buffer must be reasonably large enough */
1145 if (128 > connection->write_buffer_size)
1146 {
1147 size_t size;
1148
1149 size = connection->write_buffer_size + MHD_pool_get_free (connection->pool);
1150 if (128 > size)
1151 {
1152#if defined(MHD_USE_POSIX_THREADS) || defined(MHD_USE_W32_THREADS)
1153 MHD_mutex_unlock_chk_ (&response->mutex);
1154#endif
1155 /* not enough memory */
1156 CONNECTION_CLOSE_ERROR (connection,
1157 _ ("Closing connection (out of memory)."));
1158 return MHD_NO;
1159 }
1160 /* Limit the buffer size to the largest usable size for chunks */
1161 if ( (max_chunk + max_chunk_overhead) < size)
1162 size = max_chunk + max_chunk_overhead;
1163 connection->write_buffer = MHD_pool_reallocate (connection->pool,
1164 connection->write_buffer,
1165 connection->
1166 write_buffer_size, size);
1167 mhd_assert (NULL != connection->write_buffer);
1168 connection->write_buffer_size = size;
1169 }
1170 mhd_assert (max_chunk_overhead < connection->write_buffer_size);
1171
1172 if (MHD_SIZE_UNKNOWN == response->total_size)
1173 left_to_send = MHD_SIZE_UNKNOWN;
1174 else
1175 left_to_send = response->total_size - connection->response_write_position;
1176
1177 size_to_fill = connection->write_buffer_size - max_chunk_overhead;
1178 /* Limit size for the callback to the max usable size */
1179 if (max_chunk < size_to_fill)
1180 size_to_fill = max_chunk;
1181 if (left_to_send < size_to_fill)
1182 size_to_fill = (size_t) left_to_send;
1183
1184 if (0 == left_to_send)
1185 /* nothing to send, don't bother calling crc */
1187 else if ( (response->data_start <=
1188 connection->response_write_position) &&
1189 (response->data_start + response->data_size >
1190 connection->response_write_position) )
1191 {
1192 /* difference between response_write_position and data_start is less
1193 than data_size which is size_t type, no need to check for overflow */
1194 const size_t data_write_offset
1195 = (size_t) (connection->response_write_position - response->data_start);
1196 /* buffer already ready, use what is there for the chunk */
1197 ret = response->data_size - data_write_offset;
1198 if ( ((size_t) ret) > size_to_fill)
1199 ret = (ssize_t) size_to_fill;
1200 memcpy (&connection->write_buffer[max_chunk_hdr_len],
1201 &response->data[data_write_offset],
1202 ret);
1203 }
1204 else
1205 {
1206 if (NULL == response->crc)
1207 { /* There is no way to reach this code */
1208#if defined(MHD_USE_THREADS)
1209 MHD_mutex_unlock_chk_ (&response->mutex);
1210#endif
1211 CONNECTION_CLOSE_ERROR (connection,
1212 _ ("No callback for the chunked data."));
1213 return MHD_NO;
1214 }
1215 ret = response->crc (response->crc_cls,
1216 connection->response_write_position,
1217 &connection->write_buffer[max_chunk_hdr_len],
1218 size_to_fill);
1219 }
1221 {
1222 /* error, close socket! */
1223 /* TODO: remove update of the response size */
1224 response->total_size = connection->response_write_position;
1225#if defined(MHD_USE_POSIX_THREADS) || defined(MHD_USE_W32_THREADS)
1226 MHD_mutex_unlock_chk_ (&response->mutex);
1227#endif
1228 CONNECTION_CLOSE_ERROR (connection,
1229 _ (
1230 "Closing connection (application error generating response)."));
1231 return MHD_NO;
1232 }
1234 {
1235 *p_finished = true;
1236 /* TODO: remove update of the response size */
1237 response->total_size = connection->response_write_position;
1238 return MHD_YES;
1239 }
1240 if (0 == ret)
1241 {
1243#if defined(MHD_USE_POSIX_THREADS) || defined(MHD_USE_W32_THREADS)
1244 MHD_mutex_unlock_chk_ (&response->mutex);
1245#endif
1246 return MHD_NO;
1247 }
1248 if (size_to_fill < (size_t) ret)
1249 {
1250#if defined(MHD_USE_THREADS)
1251 MHD_mutex_unlock_chk_ (&response->mutex);
1252#endif
1253 CONNECTION_CLOSE_ERROR (connection,
1254 _ ("Closing connection (application returned " \
1255 "more data than requested)."));
1256 return MHD_NO;
1257 }
1258 chunk_hdr_len = MHD_uint32_to_strx ((uint32_t) ret, chunk_hdr,
1259 sizeof(chunk_hdr));
1260 mhd_assert (chunk_hdr_len != 0);
1261 mhd_assert (chunk_hdr_len < sizeof(chunk_hdr));
1262 *p_finished = false;
1263 connection->write_buffer_send_offset =
1264 (max_chunk_hdr_len - (chunk_hdr_len + 2));
1265 memcpy (connection->write_buffer + connection->write_buffer_send_offset,
1266 chunk_hdr,
1267 chunk_hdr_len);
1268 connection->write_buffer[max_chunk_hdr_len - 2] = '\r';
1269 connection->write_buffer[max_chunk_hdr_len - 1] = '\n';
1270 connection->write_buffer[max_chunk_hdr_len + ret] = '\r';
1271 connection->write_buffer[max_chunk_hdr_len + ret + 1] = '\n';
1272 connection->response_write_position += ret;
1273 connection->write_buffer_append_offset = max_chunk_hdr_len + ret + 2;
1274 return MHD_YES;
1275}
1276
1277
1300static enum MHD_ConnKeepAlive
1302{
1303 struct MHD_Connection *const c = connection;
1304 struct MHD_Response *const r = c->response;
1306 mhd_assert (NULL != r);
1308 return MHD_CONN_MUST_CLOSE;
1309
1310#ifdef UPGRADE_SUPPORT
1311 /* TODO: Move below the next check when MHD stops closing connections
1312 * when response is queued in first callback */
1313 if (NULL != r->upgrade_handler)
1314 {
1315 /* No "close" token is enforced by 'add_response_header_connection()' */
1317 /* Valid HTTP version is enforced by 'MHD_queue_response()' */
1320 return MHD_CONN_MUST_UPGRADE;
1321 }
1322#endif /* UPGRADE_SUPPORT */
1323
1324 mhd_assert ( (! c->stop_with_error) || (c->discard_request));
1325 if ((c->read_closed) || (c->discard_request))
1326 return MHD_CONN_MUST_CLOSE;
1327
1329 return MHD_CONN_MUST_CLOSE;
1331 return MHD_CONN_MUST_CLOSE;
1332
1334 return MHD_CONN_MUST_CLOSE;
1335
1338 "close"))
1339 return MHD_CONN_MUST_CLOSE;
1340
1341 if ((MHD_HTTP_VER_1_0 == connection->http_ver) ||
1342 (0 != (connection->response->flags & MHD_RF_HTTP_1_0_SERVER)))
1343 {
1344 if (MHD_lookup_header_s_token_ci (connection,
1346 "Keep-Alive"))
1348
1349 return MHD_CONN_MUST_CLOSE;
1350 }
1351
1354
1355 return MHD_CONN_MUST_CLOSE;
1356}
1357
1358
1368static bool
1369get_date_str (char *date)
1370{
1371 static const char *const days[] = {
1372 "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
1373 };
1374 static const char *const mons[] = {
1375 "Jan", "Feb", "Mar", "Apr", "May", "Jun",
1376 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
1377 };
1378 static const size_t buf_len = 29;
1379 struct tm now;
1380 time_t t;
1381 const char *src;
1382#if ! defined(HAVE_C11_GMTIME_S) && ! defined(HAVE_W32_GMTIME_S) && \
1383 ! defined(HAVE_GMTIME_R)
1384 struct tm *pNow;
1385#endif
1386
1387 if ((time_t) -1 == time (&t))
1388 return false;
1389#if defined(HAVE_C11_GMTIME_S)
1390 if (NULL == gmtime_s (&t,
1391 &now))
1392 return false;
1393#elif defined(HAVE_W32_GMTIME_S)
1394 if (0 != gmtime_s (&now,
1395 &t))
1396 return false;
1397#elif defined(HAVE_GMTIME_R)
1398 if (NULL == gmtime_r (&t,
1399 &now))
1400 return false;
1401#else
1402 pNow = gmtime (&t);
1403 if (NULL == pNow)
1404 return false;
1405 now = *pNow;
1406#endif
1407
1408 /* Day of the week */
1409 src = days[now.tm_wday % 7];
1410 date[0] = src[0];
1411 date[1] = src[1];
1412 date[2] = src[2];
1413 date[3] = ',';
1414 date[4] = ' ';
1415 /* Day of the month */
1416 if (2 != MHD_uint8_to_str_pad ((uint8_t) now.tm_mday, 2,
1417 date + 5, buf_len - 5))
1418 return false;
1419 date[7] = ' ';
1420 /* Month */
1421 src = mons[now.tm_mon % 12];
1422 date[8] = src[0];
1423 date[9] = src[1];
1424 date[10] = src[2];
1425 date[11] = ' ';
1426 /* Year */
1427 if (4 != MHD_uint16_to_str ((uint16_t) (1900 + now.tm_year), date + 12,
1428 buf_len - 12))
1429 return false;
1430 date[16] = ' ';
1431 /* Time */
1432 MHD_uint8_to_str_pad ((uint8_t) now.tm_hour, 2, date + 17, buf_len - 17);
1433 date[19] = ':';
1434 MHD_uint8_to_str_pad ((uint8_t) now.tm_min, 2, date + 20, buf_len - 20);
1435 date[22] = ':';
1436 MHD_uint8_to_str_pad ((uint8_t) now.tm_sec, 2, date + 23, buf_len - 23);
1437 date[25] = ' ';
1438 date[26] = 'G';
1439 date[27] = 'M';
1440 date[28] = 'T';
1441
1442 return true;
1443}
1444
1445
1453static bool
1454get_date_header (char *header)
1455{
1456 if (! get_date_str (header + 6))
1457 {
1458 header[0] = 0;
1459 return false;
1460 }
1461 header[0] = 'D';
1462 header[1] = 'a';
1463 header[2] = 't';
1464 header[3] = 'e';
1465 header[4] = ':';
1466 header[5] = ' ';
1467 header[35] = '\r';
1468 header[36] = '\n';
1469 header[37] = 0;
1470 return true;
1471}
1472
1473
1486static bool
1488 bool required)
1489{
1490 size_t new_size;
1491 size_t avail_size;
1492 void *rb;
1493
1494 avail_size = MHD_pool_get_free (connection->pool);
1495 if (0 == avail_size)
1496 return false; /* No more space available */
1497 if (0 == connection->read_buffer_size)
1498 new_size = avail_size / 2; /* Use half of available buffer for reading */
1499 else
1500 {
1501 size_t grow_size;
1502
1503 grow_size = avail_size / 8;
1504 if (MHD_BUF_INC_SIZE > grow_size)
1505 { /* Shortage of space */
1506 if (! required)
1507 return false; /* Grow is not mandatory, leave some space in pool */
1508 else
1509 {
1510 /* Shortage of space, but grow is mandatory */
1511 static const size_t small_inc = MHD_BUF_INC_SIZE / 8;
1512 if (small_inc < avail_size)
1513 grow_size = small_inc;
1514 else
1515 grow_size = avail_size;
1516 }
1517 }
1518 new_size = connection->read_buffer_size + grow_size;
1519 }
1520 /* we can actually grow the buffer, do it! */
1521 rb = MHD_pool_reallocate (connection->pool,
1522 connection->read_buffer,
1523 connection->read_buffer_size,
1524 new_size);
1525 if (NULL == rb)
1526 {
1527 /* This should NOT be possible: we just computed 'new_size' so that
1528 it should fit. If it happens, somehow our read buffer is not in
1529 the right position in the pool, say because someone called
1530 MHD_pool_allocate() without 'from_end' set to 'true'? Anyway,
1531 should be investigated! (Ideally provide all data from
1532 *pool and connection->read_buffer and new_size for debugging). */
1533 mhd_assert (0);
1534 return false;
1535 }
1536 connection->read_buffer = rb;
1537 mhd_assert (NULL != connection->read_buffer);
1538 connection->read_buffer_size = new_size;
1539 return true;
1540}
1541
1542
1547static void
1549{
1550 struct MHD_Connection *const c = connection;
1551 void *new_buf;
1552
1553 if ((NULL == c->read_buffer) || (0 == c->read_buffer_size))
1554 {
1555 mhd_assert (0 == c->read_buffer_size);
1557 return;
1558 }
1559
1563 mhd_assert (c->read_buffer == new_buf);
1564 c->read_buffer = new_buf;
1566}
1567
1568
1576static size_t
1578{
1579 struct MHD_Connection *const c = connection;
1580 struct MemoryPool *const pool = connection->pool;
1581 void *new_buf;
1582 size_t new_size;
1583 size_t free_size;
1584
1585 mhd_assert ((NULL != c->write_buffer) || (0 == c->write_buffer_size));
1588
1589 free_size = MHD_pool_get_free (pool);
1590 if (0 != free_size)
1591 {
1592 new_size = c->write_buffer_size + free_size;
1593 /* This function must not move the buffer position.
1594 * MHD_pool_reallocate () may return the new position only if buffer was
1595 * allocated 'from_end' or is not the last allocation,
1596 * which should not happen. */
1597 new_buf = MHD_pool_reallocate (pool,
1598 c->write_buffer,
1600 new_size);
1601 mhd_assert ((c->write_buffer == new_buf) || (NULL == c->write_buffer));
1602 c->write_buffer = new_buf;
1603 c->write_buffer_size = new_size;
1605 {
1606 /* All data have been sent, reset offsets to zero. */
1609 }
1610 }
1611
1613}
1614
1615
1616#if 0 /* disable unused function */
1625static void
1626connection_shrink_write_buffer (struct MHD_Connection *connection)
1627{
1628 struct MHD_Connection *const c = connection;
1629 struct MemoryPool *const pool = connection->pool;
1630 void *new_buf;
1631
1632 mhd_assert ((NULL != c->write_buffer) || (0 == c->write_buffer_size));
1635
1636 if ( (NULL == c->write_buffer) || (0 == c->write_buffer_size))
1637 {
1640 c->write_buffer = NULL;
1641 return;
1642 }
1644 return;
1645
1646 new_buf = MHD_pool_reallocate (pool, c->write_buffer, c->write_buffer_size,
1648 mhd_assert ((c->write_buffer == new_buf) || \
1649 (0 == c->write_buffer_append_offset));
1651 if (0 == c->write_buffer_size)
1652 c->write_buffer = NULL;
1653 else
1654 c->write_buffer = new_buf;
1655}
1656
1657
1658#endif /* unused function */
1659
1660
1668static void
1670{
1671 /* Read buffer is not needed for this request, shrink it.*/
1672 connection_shrink_read_buffer (connection);
1673}
1674
1675
1690static bool
1692{
1693 struct MHD_Connection *const c = connection;
1694 unsigned rcode;
1696 mhd_assert (100 <= (c->responseCode & (~MHD_ICY_FLAG)) && \
1697 999 >= (c->responseCode & (~MHD_ICY_FLAG)));
1698
1699 rcode = (unsigned) (c->responseCode & (~MHD_ICY_FLAG));
1700
1701 if (199 >= rcode)
1702 return false;
1703
1704 if (MHD_HTTP_NO_CONTENT == rcode)
1705 return false;
1706
1707#ifdef UPGRADE_SUPPORT
1708 if (NULL != c->response->upgrade_handler)
1709 return false;
1710#endif /* UPGRADE_SUPPORT */
1711
1712 if ( (MHD_HTTP_MTHD_CONNECT == c->http_mthd) &&
1713 (2 == rcode / 100) )
1714 return false; /* Actually pass-through CONNECT is not supported by MHD */
1715
1716 return true;
1717}
1718
1719
1730static bool
1732{
1733 struct MHD_Connection *const c = connection;
1734 unsigned rcode;
1736 mhd_assert (100 <= (c->responseCode & (~MHD_ICY_FLAG)) && \
1737 999 >= (c->responseCode & (~MHD_ICY_FLAG)));
1738
1740 return false;
1741
1742 if (MHD_HTTP_MTHD_HEAD == c->http_mthd)
1743 return false;
1744
1745 rcode = (unsigned) (c->responseCode & (~MHD_ICY_FLAG));
1746 if (MHD_HTTP_NOT_MODIFIED == rcode)
1747 return false;
1748
1749 return true;
1750}
1751
1752
1762static void
1764{
1765 struct MHD_Connection *const c = connection;
1766 struct MHD_Response *const r = c->response;
1767 bool use_chunked;
1768
1769 mhd_assert (NULL != r);
1770
1771 /* ** Adjust reply properties ** */
1772
1777 else
1778 c->rp_props.send_reply_body = false;
1779
1781 {
1782 if ((MHD_SIZE_UNKNOWN == r->total_size) ||
1784 { /* Use chunked reply encoding if possible */
1785
1786 /* Check whether chunked encoding is supported by the client */
1788 use_chunked = false;
1789 /* Check whether chunked encoding is allowed for the reply */
1790 else if (0 != (r->flags & (MHD_RF_HTTP_1_0_COMPATIBLE_STRICT
1792 use_chunked = false;
1793 else
1794 /* If chunked encoding is supported and allowed, and response size
1795 * is unknown, use chunked even for non-Keep-Alive connections.
1796 * See https://datatracker.ietf.org/doc/html/rfc7230#section-3.3.3
1797 * Also use chunked if it is enforced by application and supported by
1798 * the client. */
1799 use_chunked = true;
1800 }
1801 else
1802 use_chunked = false;
1803
1804 if ( (MHD_SIZE_UNKNOWN == r->total_size) && ! use_chunked)
1805 {
1806 /* End of the stream is indicated by closure */
1808 }
1809 }
1810 else
1811 use_chunked = false; /* chunked encoding cannot be used without body */
1812
1813 c->rp_props.chunked = use_chunked;
1814 c->rp_props.set = true;
1815}
1816
1817
1829static bool
1830buffer_append (char *buf,
1831 size_t *ppos,
1832 size_t buf_size,
1833 const char *append,
1834 size_t append_size)
1835{
1836 mhd_assert (NULL != buf); /* Mute static analyzer */
1837 if (buf_size < *ppos + append_size)
1838 return false;
1839 memcpy (buf + *ppos, append, append_size);
1840 *ppos += append_size;
1841 return true;
1842}
1843
1844
1855#define buffer_append_s(buf,ppos,buf_size,str) \
1856 buffer_append(buf,ppos,buf_size,str, MHD_STATICSTR_LEN_(str))
1857
1858
1878static bool
1880 size_t *ppos,
1881 size_t buf_size,
1882 struct MHD_Response *response,
1883 enum MHD_ValueKind kind,
1884 bool filter_transf_enc,
1885 bool add_close,
1886 bool add_keep_alive)
1887{
1888 struct MHD_Response *const r = response;
1889 struct MHD_HTTP_Header *hdr;
1890 size_t el_size;
1892 mhd_assert ((! filter_transf_enc) || MHD_HEADER_KIND == kind);
1893 mhd_assert ((! add_close) || MHD_HEADER_KIND == kind);
1894 mhd_assert ((! add_keep_alive) || MHD_HEADER_KIND == kind);
1895 mhd_assert (! add_close || ! add_keep_alive);
1896
1898 filter_transf_enc = false; /* No such header */
1899 if (0 == (r->flags_auto & MHD_RAF_HAS_CONNECTION_HDR))
1900 {
1901 add_close = false; /* No such header */
1902 add_keep_alive = false; /* No such header */
1903 }
1904 else if (0 != (r->flags_auto & MHD_RAF_HAS_CONNECTION_CLOSE))
1905 add_close = false; /* "close" token was already set */
1906
1907 for (hdr = r->first_header; NULL != hdr; hdr = hdr->next)
1908 {
1909 size_t initial_pos = *ppos;
1910 if (kind != hdr->kind)
1911 continue;
1912 if (filter_transf_enc)
1913 { /* Need to filter-out "Transfer-Encoding" */
1915 hdr->header_size) &&
1917 hdr->header, hdr->header_size)) )
1918 {
1919 filter_transf_enc = false; /* There is the only one such header */
1920 continue; /* Skip "Transfer-Encoding" header */
1921 }
1922 }
1923
1924 /* Add user header */
1925 el_size = hdr->header_size + 2 + hdr->value_size + 2;
1926 if (buf_size < *ppos + el_size)
1927 return false;
1928 memcpy (buf + *ppos, hdr->header, hdr->header_size);
1929 (*ppos) += hdr->header_size;
1930 buf[(*ppos)++] = ':';
1931 buf[(*ppos)++] = ' ';
1932 if (add_close || add_keep_alive)
1933 {
1934 /* "Connection:" header must be always the first one */
1937 hdr->header_size));
1938
1939 if (add_close)
1940 {
1941 el_size += MHD_STATICSTR_LEN_ ("close, ");
1942 if (buf_size < initial_pos + el_size)
1943 return false;
1944 memcpy (buf + *ppos, "close, ",
1945 MHD_STATICSTR_LEN_ ("close, "));
1946 *ppos += MHD_STATICSTR_LEN_ ("close, ");
1947 }
1948 else
1949 {
1950 el_size += MHD_STATICSTR_LEN_ ("Keep-Alive, ");
1951 if (buf_size < initial_pos + el_size)
1952 return false;
1953 memcpy (buf + *ppos, "Keep-Alive, ",
1954 MHD_STATICSTR_LEN_ ("Keep-Alive, "));
1955 *ppos += MHD_STATICSTR_LEN_ ("Keep-Alive, ");
1956 }
1957 add_close = false;
1958 add_keep_alive = false;
1959 }
1960 if (0 != hdr->value_size)
1961 memcpy (buf + *ppos, hdr->value, hdr->value_size);
1962 *ppos += hdr->value_size;
1963 buf[(*ppos)++] = '\r';
1964 buf[(*ppos)++] = '\n';
1965 mhd_assert (initial_pos + el_size == (*ppos));
1966 }
1967 return true;
1968}
1969
1970
1979static enum MHD_Result
1981{
1982 struct MHD_Connection *const c = connection;
1983 struct MHD_Response *const r = c->response;
1984 char *buf;
1985 size_t pos;
1986 size_t buf_size;
1987 size_t el_size;
1988 unsigned rcode;
1989 bool use_conn_close;
1990 bool use_conn_k_alive;
1992 mhd_assert (NULL != r);
1993
1994 /* ** Adjust response properties ** */
1995
1997
1998 mhd_assert (c->rp_props.set);
2002#ifdef UPGRADE_SUPPORT
2003 mhd_assert ((NULL == r->upgrade_handler) || \
2005#else /* ! UPGRADE_SUPPORT */
2007#endif /* ! UPGRADE_SUPPORT */
2011#ifdef UPGRADE_SUPPORT
2012 mhd_assert (NULL == r->upgrade_handler || \
2014#endif /* UPGRADE_SUPPORT */
2015
2016 rcode = (unsigned) (c->responseCode & (~MHD_ICY_FLAG));
2018 {
2019 /* The closure of connection must be always indicated by header
2020 * to avoid hung connections */
2021 use_conn_close = true;
2022 use_conn_k_alive = false;
2023 }
2024 else if (MHD_CONN_USE_KEEPALIVE == c->keepalive)
2025 {
2026 use_conn_close = false;
2027 /* Add "Connection: keep-alive" if request is HTTP/1.0 or
2028 * if reply is HTTP/1.0
2029 * For HTTP/1.1 add header only if explicitly requested by app
2030 * (by response flag), as "Keep-Alive" is default for HTTP/1.1. */
2031 if ((0 != (r->flags & MHD_RF_SEND_KEEP_ALIVE_HEADER)) ||
2032 (MHD_HTTP_VER_1_0 == c->http_ver) ||
2033 (0 != (r->flags & MHD_RF_HTTP_1_0_SERVER)))
2034 use_conn_k_alive = true;
2035 else
2036 use_conn_k_alive = false;
2037 }
2038 else
2039 {
2040 use_conn_close = false;
2041 use_conn_k_alive = false;
2042 }
2043
2044 /* ** Actually build the response header ** */
2045
2046 /* Get all space available */
2048 buf = c->write_buffer;
2050 buf_size = c->write_buffer_size;
2051 if (0 == buf_size)
2052 return MHD_NO;
2053 mhd_assert (NULL != buf);
2054
2055 /* * The status line * */
2056
2057 /* The HTTP version */
2058 if (0 == (c->responseCode & MHD_ICY_FLAG))
2059 { /* HTTP reply */
2060 if (0 == (r->flags & MHD_RF_HTTP_1_0_SERVER))
2061 { /* HTTP/1.1 reply */
2062 /* Use HTTP/1.1 responses for HTTP/1.0 clients.
2063 * See https://datatracker.ietf.org/doc/html/rfc7230#section-2.6 */
2064 if (! buffer_append_s (buf, &pos, buf_size, MHD_HTTP_VERSION_1_1))
2065 return MHD_NO;
2066 }
2067 else
2068 { /* HTTP/1.0 reply */
2069 if (! buffer_append_s (buf, &pos, buf_size, MHD_HTTP_VERSION_1_0))
2070 return MHD_NO;
2071 }
2072 }
2073 else
2074 { /* ICY reply */
2075 if (! buffer_append_s (buf, &pos, buf_size, "ICY"))
2076 return MHD_NO;
2077 }
2078
2079 /* The response code */
2080 if (buf_size < pos + 5) /* space + code + space */
2081 return MHD_NO;
2082 buf[pos++] = ' ';
2083 pos += MHD_uint16_to_str (rcode, buf + pos,
2084 buf_size - pos);
2085 buf[pos++] = ' ';
2086
2087 /* The reason phrase */
2088 el_size = MHD_get_reason_phrase_len_for (rcode);
2089 if (0 == el_size)
2090 {
2091 if (! buffer_append_s (buf, &pos, buf_size, "Non-Standard Status"))
2092 return MHD_NO;
2093 }
2094 else if (! buffer_append (buf, &pos, buf_size,
2096 el_size))
2097 return MHD_NO;
2098
2099 /* The linefeed */
2100 if (buf_size < pos + 2)
2101 return MHD_NO;
2102 buf[pos++] = '\r';
2103 buf[pos++] = '\n';
2104
2105 /* * The headers * */
2106
2107 /* Main automatic headers */
2108
2109 /* The "Date:" header */
2110 if ( (0 == (r->flags_auto & MHD_RAF_HAS_DATE_HDR)) &&
2112 {
2113 /* Additional byte for unused zero-termination */
2114 if (buf_size < pos + 38)
2115 return MHD_NO;
2116 if (get_date_header (buf + pos))
2117 pos += 37;
2118 }
2119 /* The "Connection:" header */
2120 mhd_assert (! use_conn_close || ! use_conn_k_alive);
2121 mhd_assert (! use_conn_k_alive || ! use_conn_close);
2122 if (0 == (r->flags_auto & MHD_RAF_HAS_CONNECTION_HDR))
2123 {
2124 if (use_conn_close)
2125 {
2126 if (! buffer_append_s (buf, &pos, buf_size,
2127 MHD_HTTP_HEADER_CONNECTION ": close\r\n"))
2128 return MHD_NO;
2129 }
2130 else if (use_conn_k_alive)
2131 {
2132 if (! buffer_append_s (buf, &pos, buf_size,
2133 MHD_HTTP_HEADER_CONNECTION ": Keep-Alive\r\n"))
2134 return MHD_NO;
2135 }
2136 }
2137
2138 /* User-defined headers */
2139
2140 if (! add_user_headers (buf, &pos, buf_size, r, MHD_HEADER_KIND,
2141 ! c->rp_props.chunked,
2142 use_conn_close,
2143 use_conn_k_alive))
2144 return MHD_NO;
2145
2146 /* Other automatic headers */
2147
2149 {
2150 /* Body-specific headers */
2151 if (c->rp_props.chunked)
2152 { /* Chunked encoding is used */
2154 { /* No chunked encoding header set by user */
2155 if (! buffer_append_s (buf, &pos, buf_size,
2157 "chunked\r\n"))
2158 return MHD_NO;
2159 }
2160 }
2161 else
2162 { /* Chunked encoding is not used */
2163 if (MHD_SIZE_UNKNOWN != r->total_size)
2164 {
2165 if (! buffer_append_s (buf, &pos, buf_size,
2167 return MHD_NO;
2168 el_size = MHD_uint64_to_str (r->total_size, buf + pos,
2169 buf_size - pos);
2170 if (0 == el_size)
2171 return MHD_NO;
2172 pos += el_size;
2173
2174 if (buf_size < pos + 2)
2175 return MHD_NO;
2176 buf[pos++] = '\r';
2177 buf[pos++] = '\n';
2178 }
2179 }
2180 }
2181
2182 /* * Header termination * */
2183 if (buf_size < pos + 2)
2184 return MHD_NO;
2185 buf[pos++] = '\r';
2186 buf[pos++] = '\n';
2187
2189 return MHD_YES;
2190}
2191
2192
2202static enum MHD_Result
2204{
2205 char *buf;
2206 size_t buf_size;
2207 size_t used_size;
2208 struct MHD_Connection *const c = connection;
2209 struct MHD_HTTP_Header *pos;
2210
2211 mhd_assert (connection->rp_props.chunked);
2212 /* TODO: allow combining of the final footer with the last chunk,
2213 * modify the next assert. */
2214 mhd_assert (MHD_CONNECTION_BODY_SENT == connection->state);
2215 mhd_assert (NULL != c->response);
2216
2217 buf_size = connection_maximize_write_buffer (c);
2218 /* '5' is the minimal size of chunked footer ("0\r\n\r\n") */
2219 if (buf_size < 5)
2220 return MHD_NO;
2223 mhd_assert (NULL != buf);
2224 used_size = 0;
2225 buf[used_size++] = '0';
2226 buf[used_size++] = '\r';
2227 buf[used_size++] = '\n';
2228
2229 for (pos = c->response->first_header; NULL != pos; pos = pos->next)
2230 {
2231 if (MHD_FOOTER_KIND == pos->kind)
2232 {
2233 size_t new_used_size; /* resulting size with this header */
2234 /* '4' is colon, space, linefeeds */
2235 new_used_size = used_size + pos->header_size + pos->value_size + 4;
2236 if (new_used_size > buf_size)
2237 return MHD_NO;
2238 memcpy (buf + used_size, pos->header, pos->header_size);
2239 used_size += pos->header_size;
2240 buf[used_size++] = ':';
2241 buf[used_size++] = ' ';
2242 memcpy (buf + used_size, pos->value, pos->value_size);
2243 used_size += pos->value_size;
2244 buf[used_size++] = '\r';
2245 buf[used_size++] = '\n';
2246 mhd_assert (used_size == new_used_size);
2247 }
2248 }
2249 if (used_size + 2 > buf_size)
2250 return MHD_NO;
2251 buf[used_size++] = '\r';
2252 buf[used_size++] = '\n';
2253
2254 c->write_buffer_append_offset += used_size;
2256
2257 return MHD_YES;
2258}
2259
2260
2271static void
2273 unsigned int status_code,
2274 const char *message,
2275 size_t message_len)
2276{
2277 struct MHD_Response *response;
2278 enum MHD_Result iret;
2279
2280 mhd_assert (! connection->stop_with_error); /* Do not send error twice */
2281 if (connection->stop_with_error)
2282 { /* Should not happen */
2283 if (MHD_CONNECTION_CLOSED > connection->state)
2284 connection->state = MHD_CONNECTION_CLOSED;
2285
2286 return;
2287 }
2288 connection->stop_with_error = true;
2289 connection->discard_request = true;
2290#ifdef HAVE_MESSAGES
2291 MHD_DLOG (connection->daemon,
2292 _ ("Error processing request (HTTP response code is %u ('%s')). " \
2293 "Closing connection.\n"),
2295 message);
2296#endif
2297 if (MHD_CONNECTION_START_REPLY < connection->state)
2298 {
2299#ifdef HAVE_MESSAGES
2300 MHD_DLOG (connection->daemon,
2301 _ ("Too late to send an error response, " \
2302 "response is being sent already.\n"),
2304 message);
2305#endif
2306 CONNECTION_CLOSE_ERROR (connection,
2307 _ ("Too late for error response."));
2308 return;
2309 }
2310 /* TODO: remove when special error queue function is implemented */
2312 if (0 != connection->read_buffer_size)
2313 {
2314 /* Read buffer is not needed anymore, discard it
2315 * to free some space for error response. */
2316 connection->read_buffer = MHD_pool_reallocate (connection->pool,
2317 connection->read_buffer,
2318 connection->read_buffer_size,
2319 0);
2320 connection->read_buffer_size = 0;
2321 connection->read_buffer_offset = 0;
2322 }
2323 if (NULL != connection->response)
2324 {
2325 MHD_destroy_response (connection->response);
2326 connection->response = NULL;
2327 }
2328 response = MHD_create_response_from_buffer (message_len,
2329 (void *) message,
2331 if (NULL == response)
2332 {
2333#ifdef HAVE_MESSAGES
2334 MHD_DLOG (connection->daemon,
2335 _ ("Failed to create error response.\n"),
2337 message);
2338#endif
2339 /* can't even send a reply, at least close the connection */
2340 connection->state = MHD_CONNECTION_CLOSED;
2341 return;
2342 }
2343 iret = MHD_queue_response (connection,
2345 response);
2346 MHD_destroy_response (response);
2347 if (MHD_NO == iret)
2348 {
2349 /* can't even send a reply, at least close the connection */
2350 CONNECTION_CLOSE_ERROR (connection,
2351 _ ("Closing connection " \
2352 "(failed to queue error response)."));
2353 return;
2354 }
2355 mhd_assert (NULL != connection->response);
2356 /* Do not reuse this connection. */
2357 connection->keepalive = MHD_CONN_MUST_CLOSE;
2358 if (MHD_NO == build_header_response (connection))
2359 {
2360 /* No memory. Release everything. */
2361 connection->version = NULL;
2362 connection->method = NULL;
2363 connection->url = NULL;
2364 connection->last = NULL;
2365 connection->colon = NULL;
2366 connection->headers_received = NULL;
2367 connection->headers_received_tail = NULL;
2368 connection->write_buffer = NULL;
2369 connection->write_buffer_size = 0;
2370 connection->write_buffer_send_offset = 0;
2371 connection->write_buffer_append_offset = 0;
2372 connection->read_buffer
2373 = MHD_pool_reset (connection->pool,
2374 NULL,
2375 0,
2376 0);
2377 connection->read_buffer_size = 0;
2378
2379 /* Retry with empty buffer */
2380 if (MHD_NO == build_header_response (connection))
2381 {
2382 CONNECTION_CLOSE_ERROR (connection,
2383 _ ("Closing connection " \
2384 "(failed to create error response header)."));
2385 return;
2386 }
2387 }
2389}
2390
2391
2395#define transmit_error_response_static(c, code, msg) \
2396 transmit_error_response_len (c, code, msg, MHD_STATICSTR_LEN_ (msg))
2397
2406static void
2408{
2409 /* Do not update states of suspended connection */
2410 if (connection->suspended)
2411 return; /* States will be updated after resume. */
2412#ifdef HTTPS_SUPPORT
2413 if (MHD_TLS_CONN_NO_TLS != connection->tls_state)
2414 { /* HTTPS connection. */
2415 switch (connection->tls_state)
2416 {
2417 case MHD_TLS_CONN_INIT:
2419 return;
2421 if (0 == gnutls_record_get_direction (connection->tls_session))
2423 else
2425 return;
2426 default:
2427 break;
2428 }
2429 }
2430#endif /* HTTPS_SUPPORT */
2431 while (1)
2432 {
2433#if DEBUG_STATES
2434 MHD_DLOG (connection->daemon,
2435 _ ("In function %s handling connection at state: %s\n"),
2436 __FUNCTION__,
2437 MHD_state_to_string (connection->state));
2438#endif
2439 switch (connection->state)
2440 {
2445 /* while reading headers, we always grow the
2446 read buffer if needed, no size-check required */
2447 if ( (connection->read_buffer_offset == connection->read_buffer_size) &&
2448 (! try_grow_read_buffer (connection, true)) )
2449 {
2450 if (connection->url != NULL)
2454 else
2458 continue;
2459 }
2460 if (! connection->discard_request)
2462 else
2464 break;
2466 mhd_assert (0);
2467 break;
2469 mhd_assert (0);
2470 break;
2473 break;
2475 if (connection->read_buffer_offset == connection->read_buffer_size)
2476 {
2477 const bool internal_poll = (0 != (connection->daemon->options
2479 if ( (! try_grow_read_buffer (connection, true)) &&
2480 internal_poll)
2481 {
2482 /* failed to grow the read buffer, and the
2483 client which is supposed to handle the
2484 received data in a *blocking* fashion
2485 (in this mode) did not handle the data as
2486 it was supposed to!
2487 => we would either have to do busy-waiting
2488 (on the client, which would likely fail),
2489 or if we do nothing, we would just timeout
2490 on the connection (if a timeout is even
2491 set!).
2492 Solution: we kill the connection with an error */
2496 continue;
2497 }
2498 }
2499 if ( (connection->read_buffer_offset < connection->read_buffer_size) &&
2500 (! connection->discard_request) )
2502 else
2504 break;
2507 /* while reading footers, we always grow the
2508 read buffer if needed, no size-check required */
2509 if (connection->read_closed)
2510 {
2511 CONNECTION_CLOSE_ERROR (connection,
2512 NULL);
2513 continue;
2514 }
2516 /* transition to FOOTERS_RECEIVED
2517 happens in read handler */
2518 break;
2520 mhd_assert (0);
2521 break;
2524 break;
2526 mhd_assert (0);
2527 break;
2529 /* headers in buffer, keep writing */
2531 break;
2533 mhd_assert (0);
2534 break;
2537 break;
2540 break;
2543 break;
2546 break;
2548 mhd_assert (0);
2549 break;
2552 break;
2554 mhd_assert (0);
2555 break;
2558 return; /* do nothing, not even reading */
2559#ifdef UPGRADE_SUPPORT
2560 case MHD_CONNECTION_UPGRADE:
2561 mhd_assert (0);
2562 break;
2563#endif /* UPGRADE_SUPPORT */
2564 default:
2565 mhd_assert (0);
2566 }
2567 break;
2568 }
2569}
2570
2571
2585static char *
2587 size_t *line_len)
2588{
2589 char *rbuf;
2590 size_t pos;
2591
2592 if (0 == connection->read_buffer_offset)
2593 return NULL;
2594 pos = 0;
2595 rbuf = connection->read_buffer;
2596 mhd_assert (NULL != rbuf);
2597
2598 do
2599 {
2600 const char c = rbuf[pos];
2601 bool found;
2602 found = false;
2603 if ( ('\r' == c) && (pos < connection->read_buffer_offset - 1) &&
2604 ('\n' == rbuf[pos + 1]) )
2605 { /* Found CRLF */
2606 found = true;
2607 if (line_len)
2608 *line_len = pos;
2609 rbuf[pos++] = 0; /* Replace CR with zero */
2610 rbuf[pos++] = 0; /* Replace LF with zero */
2611 }
2612 else if ('\n' == c) /* TODO: Add MHD option to disallow */
2613 { /* Found bare LF */
2614 found = true;
2615 if (line_len)
2616 *line_len = pos;
2617 rbuf[pos++] = 0; /* Replace LF with zero */
2618 }
2619 if (found)
2620 {
2621 connection->read_buffer += pos;
2622 connection->read_buffer_size -= pos;
2623 connection->read_buffer_offset -= pos;
2624 return rbuf;
2625 }
2626 } while (++pos < connection->read_buffer_offset);
2627
2628 /* not found, consider growing... */
2629 if ( (connection->read_buffer_offset == connection->read_buffer_size) &&
2630 (! try_grow_read_buffer (connection, true)) )
2631 {
2632 if (NULL != connection->url)
2636 else
2640 }
2641 if (line_len)
2642 *line_len = 0;
2643 return NULL;
2644}
2645
2646
2660static enum MHD_Result
2662 const char *key,
2663 size_t key_size,
2664 const char *value,
2665 size_t value_size,
2666 enum MHD_ValueKind kind)
2667{
2668 if (MHD_NO ==
2669 MHD_set_connection_value_n (connection,
2670 kind,
2671 key,
2672 key_size,
2673 value,
2674 value_size))
2675 {
2676#ifdef HAVE_MESSAGES
2677 MHD_DLOG (connection->daemon,
2678 _ ("Not enough memory in pool to allocate header record!\n"));
2679#endif
2683 return MHD_NO;
2684 }
2685 return MHD_YES;
2686}
2687
2688
2695static enum MHD_Result
2697{
2698 const char *hdr;
2699 size_t hdr_len;
2700 char *cpy;
2701 char *pos;
2702 char *sce;
2703 char *semicolon;
2704 char *equals;
2705 char *ekill;
2706 char *end;
2707 char old;
2708 int quotes;
2709
2710 if (MHD_NO == MHD_lookup_connection_value_n (connection,
2715 &hdr,
2716 &hdr_len))
2717 return MHD_YES;
2718 cpy = connection_alloc_memory (connection,
2719 hdr_len + 1);
2720 if (NULL == cpy)
2721 {
2722#ifdef HAVE_MESSAGES
2723 MHD_DLOG (connection->daemon,
2724 _ ("Not enough memory in pool to parse cookies!\n"));
2725#endif
2729 return MHD_NO;
2730 }
2731 memcpy (cpy,
2732 hdr,
2733 hdr_len);
2734 cpy[hdr_len] = '\0';
2735 pos = cpy;
2736 while (NULL != pos)
2737 {
2738 while (' ' == *pos)
2739 pos++; /* skip spaces */
2740
2741 sce = pos;
2742 while ( ((*sce) != '\0') &&
2743 ((*sce) != ',') &&
2744 ((*sce) != ';') &&
2745 ((*sce) != '=') )
2746 sce++;
2747 /* remove tailing whitespace (if any) from key */
2748 ekill = sce - 1;
2749 while ( (*ekill == ' ') &&
2750 (ekill >= pos) )
2751 *(ekill--) = '\0';
2752 old = *sce;
2753 *sce = '\0';
2754 if (old != '=')
2755 {
2756 /* value part omitted, use empty string... */
2757 if (MHD_NO ==
2758 connection_add_header (connection,
2759 pos,
2760 ekill - pos + 1,
2761 "",
2762 0,
2764 return MHD_NO;
2765 if (old == '\0')
2766 break;
2767 pos = sce + 1;
2768 continue;
2769 }
2770 equals = sce + 1;
2771 quotes = 0;
2772 semicolon = equals;
2773 while ( ('\0' != semicolon[0]) &&
2774 ( (0 != quotes) ||
2775 ( (';' != semicolon[0]) &&
2776 (',' != semicolon[0]) ) ) )
2777 {
2778 if ('"' == semicolon[0])
2779 quotes = (quotes + 1) & 1;
2780 semicolon++;
2781 }
2782 end = semicolon;
2783 if ('\0' == semicolon[0])
2784 semicolon = NULL;
2785 if (NULL != semicolon)
2786 {
2787 semicolon[0] = '\0';
2788 semicolon++;
2789 }
2790 /* remove quotes */
2791 if ( ('"' == equals[0]) &&
2792 ('"' == end[-1]) )
2793 {
2794 equals++;
2795 end--;
2796 *end = '\0';
2797 }
2798 if (MHD_NO ==
2799 connection_add_header (connection,
2800 pos,
2801 ekill - pos + 1,
2802 equals,
2803 end - equals,
2805 return MHD_NO;
2806 pos = semicolon;
2807 }
2808 return MHD_YES;
2809}
2810
2811
2821static enum MHD_Result
2823 const char *http_string,
2824 size_t len)
2825{
2826 const char *const h = http_string;
2827 mhd_assert (NULL != http_string);
2828
2829 /* String must starts with 'HTTP/d.d', case-sensetive match.
2830 * See https://datatracker.ietf.org/doc/html/rfc7230#section-2.6 */
2831 if ((len != 8) ||
2832 (h[0] != 'H') || (h[1] != 'T') || (h[2] != 'T') || (h[3] != 'P') ||
2833 (h[4] != '/')
2834 || (h[6] != '.') ||
2835 ((h[5] < '0') || (h[5] > '9')) ||
2836 ((h[7] < '0') || (h[7] > '9')))
2837 {
2838 connection->http_ver = MHD_HTTP_VER_INVALID;
2842 return MHD_NO;
2843 }
2844 if (1 == h[5] - '0')
2845 {
2846 /* HTTP/1.x */
2847 if (1 == h[7] - '0')
2848 connection->http_ver = MHD_HTTP_VER_1_1;
2849 else if (0 == h[7] - '0')
2850 connection->http_ver = MHD_HTTP_VER_1_0;
2851 else
2852 connection->http_ver = MHD_HTTP_VER_1_2__1_9;
2853
2854 return MHD_YES;
2855 }
2856
2857 if (0 == h[5] - '0')
2858 {
2859 /* Too old major version */
2860 connection->http_ver = MHD_HTTP_VER_TOO_OLD;
2864 return MHD_NO;
2865 }
2866
2867 connection->http_ver = MHD_HTTP_VER_FUTURE;
2871 return MHD_NO;
2872}
2873
2874
2884static enum MHD_Result
2886 const char *method,
2887 size_t len)
2888{
2889 const char *const m = method;
2890 mhd_assert (NULL != m);
2891
2892 if (0 == len)
2893 return MHD_NO;
2894
2895 if ((MHD_STATICSTR_LEN_ (MHD_HTTP_METHOD_GET) == len) &&
2896 (0 == memcmp (m, MHD_HTTP_METHOD_GET, len)))
2897 connection->http_mthd = MHD_HTTP_MTHD_GET;
2898 else if ((MHD_STATICSTR_LEN_ (MHD_HTTP_METHOD_HEAD) == len) &&
2899 (0 == memcmp (m, MHD_HTTP_METHOD_HEAD, len)))
2900 connection->http_mthd = MHD_HTTP_MTHD_HEAD;
2901 else if ((MHD_STATICSTR_LEN_ (MHD_HTTP_METHOD_POST) == len) &&
2902 (0 == memcmp (m, MHD_HTTP_METHOD_POST, len)))
2903 connection->http_mthd = MHD_HTTP_MTHD_POST;
2904 else if ((MHD_STATICSTR_LEN_ (MHD_HTTP_METHOD_PUT) == len) &&
2905 (0 == memcmp (m, MHD_HTTP_METHOD_PUT, len)))
2906 connection->http_mthd = MHD_HTTP_MTHD_PUT;
2907 else if ((MHD_STATICSTR_LEN_ (MHD_HTTP_METHOD_DELETE) == len) &&
2908 (0 == memcmp (m, MHD_HTTP_METHOD_DELETE, len)))
2909 connection->http_mthd = MHD_HTTP_MTHD_DELETE;
2910 else if ((MHD_STATICSTR_LEN_ (MHD_HTTP_METHOD_CONNECT) == len) &&
2911 (0 == memcmp (m, MHD_HTTP_METHOD_CONNECT, len)))
2912 connection->http_mthd = MHD_HTTP_MTHD_CONNECT;
2913 else if ((MHD_STATICSTR_LEN_ (MHD_HTTP_METHOD_OPTIONS) == len) &&
2914 (0 == memcmp (m, MHD_HTTP_METHOD_OPTIONS, len)))
2915 connection->http_mthd = MHD_HTTP_MTHD_OPTIONS;
2916 else if ((MHD_STATICSTR_LEN_ (MHD_HTTP_METHOD_TRACE) == len) &&
2917 (0 == memcmp (m, MHD_HTTP_METHOD_TRACE, len)))
2918 connection->http_mthd = MHD_HTTP_MTHD_TRACE;
2919 else
2920 connection->http_mthd = MHD_HTTP_MTHD_OTHER;
2921
2922 /* Any method string with non-zero length is valid */
2923 return MHD_YES;
2924}
2925
2926
2935static enum MHD_Result
2937 char *line,
2938 size_t line_len)
2939{
2940 struct MHD_Daemon *daemon = connection->daemon;
2941 const char *curi;
2942 char *uri;
2943 char *http_version;
2944 char *args;
2945 unsigned int unused_num_headers;
2946
2947 if (NULL == (uri = memchr (line,
2948 ' ',
2949 line_len)))
2950 return MHD_NO; /* serious error */
2951 uri[0] = '\0';
2952 connection->method = line;
2953 if (MHD_NO == parse_http_std_method (connection, connection->method,
2954 (size_t) (uri - line)))
2955 return MHD_NO;
2956 uri++;
2957 /* Skip any spaces. Not required by standard but allow
2958 to be more tolerant. */
2959 /* TODO: do not skip them in standard mode */
2960 while ( (' ' == uri[0]) &&
2961 ( (size_t) (uri - line) < line_len) )
2962 uri++;
2963 if ((size_t) (uri - line) == line_len)
2964 {
2965 /* No URI and no http version given */
2966 curi = "";
2967 uri = NULL;
2968 connection->version = "";
2969 args = NULL;
2970 if (MHD_NO == parse_http_version (connection, connection->version, 0))
2971 return MHD_NO;
2972 }
2973 else
2974 {
2975 size_t uri_len;
2976 curi = uri;
2977 /* Search from back to accept malformed URI with space */
2978 http_version = line + line_len - 1;
2979 /* Skip any trailing spaces */
2980 /* TODO: do not skip them in standard mode */
2981 while ( (' ' == http_version[0]) &&
2982 (http_version > uri) )
2983 http_version--;
2984 /* Find first space in reverse direction */
2985 while ( (' ' != http_version[0]) &&
2986 (http_version > uri) )
2987 http_version--;
2988 if (http_version > uri)
2989 {
2990 /* http_version points to character before HTTP version string */
2991 http_version[0] = '\0';
2992 connection->version = http_version + 1;
2993 if (MHD_NO == parse_http_version (connection, connection->version,
2994 line_len
2995 - (connection->version - line)))
2996 return MHD_NO;
2997 uri_len = http_version - uri;
2998 }
2999 else
3000 {
3001 connection->version = "";
3002 if (MHD_NO == parse_http_version (connection, connection->version, 0))
3003 return MHD_NO;
3004 uri_len = line_len - (uri - line);
3005 }
3006 /* check for spaces in URI if we are "strict" */
3007 if ( (1 <= daemon->strict_for_client) &&
3008 (NULL != memchr (uri,
3009 ' ',
3010 uri_len)) )
3011 {
3012 /* space exists in URI and we are supposed to be strict, reject */
3013 return MHD_NO;
3014 }
3015
3016 args = memchr (uri,
3017 '?',
3018 uri_len);
3019 }
3020
3021 /* log callback before we modify URI *or* args */
3022 if (NULL != daemon->uri_log_callback)
3023 {
3024 connection->client_aware = true;
3025 connection->client_context
3026 = daemon->uri_log_callback (daemon->uri_log_callback_cls,
3027 uri,
3028 connection);
3029 }
3030
3031 if (NULL != args)
3032 {
3033 args[0] = '\0';
3034 args++;
3035 /* note that this call clobbers 'args' */
3036 MHD_parse_arguments_ (connection,
3038 args,
3040 &unused_num_headers);
3041 }
3042
3043 /* unescape URI *after* searching for arguments and log callback */
3044 if (NULL != uri)
3046 connection,
3047 uri);
3048 connection->url = curi;
3049 return MHD_YES;
3050}
3051
3052
3060static void
3062{
3063 struct MHD_Daemon *daemon = connection->daemon;
3064 size_t processed;
3065
3066 if (NULL != connection->response)
3067 return; /* already queued a response */
3068 processed = 0;
3069 connection->client_aware = true;
3070 if (MHD_NO ==
3071 daemon->default_handler (daemon->default_handler_cls,
3072 connection,
3073 connection->url,
3074 connection->method,
3075 connection->version,
3076 NULL,
3077 &processed,
3078 &connection->client_context))
3079 {
3080 /* serious internal error, close connection */
3081 CONNECTION_CLOSE_ERROR (connection,
3082 _ (
3083 "Application reported internal error, closing connection."));
3084 return;
3085 }
3086}
3087
3088
3096static void
3098{
3099 struct MHD_Daemon *daemon = connection->daemon;
3100 size_t available;
3101 bool instant_retry;
3102 char *buffer_head;
3103
3104 if (NULL != connection->response)
3105 {
3106 /* TODO: discard all read buffer as early response
3107 * means that connection have to be closed. */
3108 /* already queued a response, discard remaining upload
3109 (but not more, there might be another request after it) */
3110 size_t purge;
3111
3112 purge = (size_t) MHD_MIN (connection->remaining_upload_size,
3113 (uint64_t) connection->read_buffer_offset);
3114 connection->remaining_upload_size -= purge;
3115 if (connection->read_buffer_offset > purge)
3116 memmove (connection->read_buffer,
3117 &connection->read_buffer[purge],
3118 connection->read_buffer_offset - purge);
3119 connection->read_buffer_offset -= purge;
3120 return;
3121 }
3122
3123 buffer_head = connection->read_buffer;
3124 available = connection->read_buffer_offset;
3125 do
3126 {
3127 size_t to_be_processed;
3128 size_t left_unprocessed;
3129 size_t processed_size;
3130
3131 instant_retry = false;
3132 if (connection->have_chunked_upload)
3133 {
3135 if ( (connection->current_chunk_offset ==
3136 connection->current_chunk_size) &&
3137 (0 != connection->current_chunk_size) )
3138 {
3139 size_t i;
3140 mhd_assert (0 != available);
3141 /* skip new line at the *end* of a chunk */
3142 i = 0;
3143 if ( (2 <= available) &&
3144 ('\r' == buffer_head[0]) &&
3145 ('\n' == buffer_head[1]) )
3146 i += 2; /* skip CRLF */
3147 else if ('\n' == buffer_head[0]) /* TODO: Add MHD option to disallow */
3148 i++; /* skip bare LF */
3149 else if (2 > available)
3150 break; /* need more upload data */
3151 if (0 == i)
3152 {
3153 /* malformed encoding */
3157 return;
3158 }
3159 available -= i;
3160 buffer_head += i;
3161 connection->current_chunk_offset = 0;
3162 connection->current_chunk_size = 0;
3163 if (0 == available)
3164 break;
3165 }
3166 if (0 != connection->current_chunk_size)
3167 {
3168 uint64_t cur_chunk_left;
3169 mhd_assert (connection->current_chunk_offset < \
3170 connection->current_chunk_size);
3171 /* we are in the middle of a chunk, give
3172 as much as possible to the client (without
3173 crossing chunk boundaries) */
3174 cur_chunk_left
3175 = connection->current_chunk_size - connection->current_chunk_offset;
3176 if (cur_chunk_left > available)
3177 to_be_processed = available;
3178 else
3179 { /* cur_chunk_left <= (size_t)available */
3180 to_be_processed = (size_t) cur_chunk_left;
3181 if (available > to_be_processed)
3182 instant_retry = true;
3183 }
3184 }
3185 else
3186 {
3187 size_t i;
3189 size_t chunk_size_len;
3190 bool found_chunk_size_str;
3191 bool malformed;
3192
3193 /* we need to read chunk boundaries */
3194 i = 0;
3195 found_chunk_size_str = false;
3196 chunk_size_len = 0;
3197 mhd_assert (0 != available);
3198 do
3199 {
3200 if ('\n' == buffer_head[i])
3201 {
3202 if ((0 < i) && ('\r' == buffer_head[i - 1]))
3203 { /* CRLF */
3204 if (! found_chunk_size_str)
3205 chunk_size_len = i - 1;
3206 }
3207 else
3208 { /* bare LF */
3209 /* TODO: Add an option to disallow bare LF */
3210 if (! found_chunk_size_str)
3211 chunk_size_len = i;
3212 }
3213 found_chunk_size_str = true;
3214 break; /* Found the end of the string */
3215 }
3216 else if (! found_chunk_size_str && (';' == buffer_head[i]))
3217 { /* Found chunk extension */
3218 chunk_size_len = i;
3219 found_chunk_size_str = true;
3220 }
3221 } while (available > ++i);
3222 mhd_assert ((i == available) || found_chunk_size_str);
3223 mhd_assert ((0 == chunk_size_len) || found_chunk_size_str);
3224 malformed = ((0 == chunk_size_len) && found_chunk_size_str);
3225 if (! malformed)
3226 {
3227 /* Check whether size is valid hexadecimal number
3228 * even if end of the string is not found yet. */
3229 size_t num_dig;
3230 uint64_t chunk_size;
3231 mhd_assert (0 < i);
3232 if (! found_chunk_size_str)
3233 {
3234 mhd_assert (i == available);
3235 /* Check already available part of the size string for valid
3236 * hexadecimal digits. */
3237 chunk_size_len = i;
3238 if ('\r' == buffer_head[i - 1])
3239 {
3240 chunk_size_len--;
3241 malformed = (0 == chunk_size_len);
3242 }
3243 }
3244 num_dig = MHD_strx_to_uint64_n_ (buffer_head,
3245 chunk_size_len,
3246 &chunk_size);
3247 malformed = malformed || (chunk_size_len != num_dig);
3248
3249 if ((available != i) && ! malformed)
3250 {
3251 /* Found end of the string and the size of the chunk is valid */
3252
3253 mhd_assert (found_chunk_size_str);
3254 /* Start reading payload data of the chunk */
3255 connection->current_chunk_offset = 0;
3256 connection->current_chunk_size = chunk_size;
3257 i++; /* Consume the last checked char */
3258 available -= i;
3259 buffer_head += i;
3260
3261 if (0 == connection->current_chunk_size)
3262 { /* The final (termination) chunk */
3263 connection->remaining_upload_size = 0;
3264 break;
3265 }
3266 if (available > 0)
3267 instant_retry = true;
3268 continue;
3269 }
3270
3271 if ((0 == num_dig) && (0 != chunk_size_len))
3272 { /* Check whether result is invalid due to uint64_t overflow */
3273 /* At least one byte is always available
3274 * in the input buffer here. */
3275 const char d = buffer_head[0];
3276 if ((('0' <= d) && ('9' >= d)) ||
3277 (('A' <= d) && ('F' >= d)) ||
3278 (('a' <= d) && ('f' >= d)))
3279 { /* The first char is a valid hexadecimal digit */
3283 return;
3284 }
3285 }
3286 }
3287 if (malformed)
3288 {
3292 return;
3293 }
3294 mhd_assert (available == i);
3295 break; /* The end of the string not found, need more upload data */
3296 }
3297 }
3298 else
3299 {
3300 /* no chunked encoding, give all to the client */
3302 mhd_assert (0 != connection->remaining_upload_size);
3303 if (connection->remaining_upload_size < available)
3304 to_be_processed = (size_t) connection->remaining_upload_size;
3305 else
3306 to_be_processed = available;
3307 }
3308 left_unprocessed = to_be_processed;
3309 connection->client_aware = true;
3310 if (MHD_NO ==
3311 daemon->default_handler (daemon->default_handler_cls,
3312 connection,
3313 connection->url,
3314 connection->method,
3315 connection->version,
3316 buffer_head,
3317 &left_unprocessed,
3318 &connection->client_context))
3319 {
3320 /* serious internal error, close connection */
3321 CONNECTION_CLOSE_ERROR (connection,
3322 _ ("Application reported internal error, " \
3323 "closing connection."));
3324 return;
3325 }
3326 if (left_unprocessed > to_be_processed)
3328 __FILE__,
3329 __LINE__
3330#ifdef HAVE_MESSAGES
3331 , _ ("libmicrohttpd API violation.\n")
3332#else
3333 , NULL
3334#endif
3335 );
3336 if (0 != left_unprocessed)
3337 {
3338 instant_retry = false; /* client did not process everything */
3339#ifdef HAVE_MESSAGES
3340 /* client did not process all upload data, complain if
3341 the setup was incorrect, which may prevent us from
3342 handling the rest of the request */
3343 if ( (0 != (daemon->options & MHD_USE_INTERNAL_POLLING_THREAD)) &&
3344 (! connection->suspended) )
3345 MHD_DLOG (daemon,
3346 _ ("WARNING: incomplete upload processing and connection " \
3347 "not suspended may result in hung connection.\n"));
3348#endif
3349 }
3350 processed_size = to_be_processed - left_unprocessed;
3351 if (connection->have_chunked_upload)
3352 connection->current_chunk_offset += processed_size;
3353 /* dh left "processed" bytes in buffer for next time... */
3354 buffer_head += processed_size;
3355 available -= processed_size;
3356 if (! connection->have_chunked_upload)
3357 {
3359 connection->remaining_upload_size -= processed_size;
3360 }
3361 else
3363 } while (instant_retry);
3364 /* TODO: zero out reused memory region */
3365 if ( (available > 0) &&
3366 (buffer_head != connection->read_buffer) )
3367 memmove (connection->read_buffer,
3368 buffer_head,
3369 available);
3370 else
3371 mhd_assert ((0 == available) || \
3372 (connection->read_buffer_offset == available));
3373 connection->read_buffer_offset = available;
3374}
3375
3376
3385static enum MHD_Result
3387 enum MHD_CONNECTION_STATE next_state)
3388{
3389 if ( (connection->write_buffer_append_offset !=
3390 connection->write_buffer_send_offset)
3391 /* || data_in_tls_buffers == true */
3392 )
3393 return MHD_NO;
3394 connection->write_buffer_append_offset = 0;
3395 connection->write_buffer_send_offset = 0;
3396 connection->state = next_state;
3397 return MHD_YES;
3398}
3399
3400
3410static enum MHD_Result
3412 char *line)
3413{
3414 char *colon;
3415
3416 /* line should be normal header line, find colon */
3417 colon = strchr (line, ':');
3418 if (NULL == colon)
3419 {
3420 /* error in header line, die hard */
3421 return MHD_NO;
3422 }
3423 if (-1 >= connection->daemon->strict_for_client)
3424 {
3425 /* check for whitespace before colon, which is not allowed
3426 by RFC 7230 section 3.2.4; we count space ' ' and
3427 tab '\t', but not '\r\n' as those would have ended the line. */
3428 const char *white;
3429
3430 white = strchr (line, ' ');
3431 if ( (NULL != white) &&
3432 (white < colon) )
3433 return MHD_NO;
3434 white = strchr (line, '\t');
3435 if ( (NULL != white) &&
3436 (white < colon) )
3437 return MHD_NO;
3438 }
3439 /* zero-terminate header */
3440 colon[0] = '\0';
3441 colon++; /* advance to value */
3442 while ( ('\0' != colon[0]) &&
3443 ( (' ' == colon[0]) ||
3444 ('\t' == colon[0]) ) )
3445 colon++;
3446 /* we do the actual adding of the connection
3447 header at the beginning of the while
3448 loop since we need to be able to inspect
3449 the *next* header line (in case it starts
3450 with a space...) */
3451 connection->last = line;
3452 connection->colon = colon;
3453 return MHD_YES;
3454}
3455
3456
3467static enum MHD_Result
3469 char *line,
3470 enum MHD_ValueKind kind)
3471{
3472 char *last;
3473 char *tmp;
3474 size_t last_len;
3475 size_t tmp_len;
3476
3477 last = connection->last;
3478 if ( (' ' == line[0]) ||
3479 ('\t' == line[0]) )
3480 {
3481 /* value was continued on the next line, see
3482 http://www.jmarshall.com/easy/http/ */
3483 last_len = strlen (last);
3484 /* skip whitespace at start of 2nd line */
3485 tmp = line;
3486 while ( (' ' == tmp[0]) ||
3487 ('\t' == tmp[0]) )
3488 tmp++;
3489 tmp_len = strlen (tmp);
3490 /* FIXME: we might be able to do this better (faster!), as most
3491 likely 'last' and 'line' should already be adjacent in
3492 memory; however, doing this right gets tricky if we have a
3493 value continued over multiple lines (in which case we need to
3494 record how often we have done this so we can check for
3495 adjacency); also, in the case where these are not adjacent
3496 (not sure how it can happen!), we would want to allocate from
3497 the end of the pool, so as to not destroy the read-buffer's
3498 ability to grow nicely. */
3499 last = MHD_pool_reallocate (connection->pool,
3500 last,
3501 last_len + 1,
3502 last_len + tmp_len + 1);
3503 if (NULL == last)
3504 {
3508 return MHD_NO;
3509 }
3510 memcpy (&last[last_len],
3511 tmp,
3512 tmp_len + 1);
3513 connection->last = last;
3514 return MHD_YES; /* possibly more than 2 lines... */
3515 }
3516 mhd_assert ( (NULL != last) &&
3517 (NULL != connection->colon) );
3518 if (MHD_NO ==
3519 connection_add_header (connection,
3520 last,
3521 strlen (last),
3522 connection->colon,
3523 strlen (connection->colon),
3524 kind))
3525 {
3526 /* Error has been queued by connection_add_header() */
3527 return MHD_NO;
3528 }
3529 /* we still have the current line to deal with... */
3530 if (0 != line[0])
3531 {
3532 if (MHD_NO == process_header_line (connection,
3533 line))
3534 {
3538 return MHD_NO;
3539 }
3540 }
3541 return MHD_YES;
3542}
3543
3544
3552static void
3554{
3555 const char *clen;
3556 const char *enc;
3557 size_t val_len;
3558
3559 parse_cookie_header (connection);
3560 if ( (1 <= connection->daemon->strict_for_client) &&
3561 (MHD_IS_HTTP_VER_1_1_COMPAT (connection->http_ver)) &&
3562 (MHD_NO ==
3568 NULL,
3569 NULL)) )
3570 {
3571#ifdef HAVE_MESSAGES
3572 MHD_DLOG (connection->daemon,
3573 _ ("Received HTTP/1.1 request without `Host' header.\n"));
3574#endif
3578 return;
3579 }
3580
3581 connection->remaining_upload_size = 0;
3582 if (MHD_NO != MHD_lookup_connection_value_n (connection,
3587 &enc,
3588 NULL))
3589 {
3591 if (MHD_str_equal_caseless_ (enc,
3592 "chunked"))
3593 connection->have_chunked_upload = true;
3594 }
3595 else
3596 {
3597 if (MHD_NO != MHD_lookup_connection_value_n (connection,
3602 &clen,
3603 &val_len))
3604 {
3605 size_t num_digits;
3606
3607 num_digits = MHD_str_to_uint64_n_ (clen,
3608 val_len,
3609 &connection->remaining_upload_size);
3610 if ( (val_len != num_digits) ||
3611 (0 == num_digits) )
3612 {
3613 connection->remaining_upload_size = 0;
3614 if ((0 == num_digits) &&
3615 (0 != val_len) &&
3616 ('0' <= clen[0]) && ('9' >= clen[0]))
3617 {
3618#ifdef HAVE_MESSAGES
3619 MHD_DLOG (connection->daemon,
3620 _ ("Too large value of 'Content-Length' header. " \
3621 "Closing connection.\n"));
3622#endif
3626 }
3627 else
3628 {
3629#ifdef HAVE_MESSAGES
3630 MHD_DLOG (connection->daemon,
3631 _ ("Failed to parse `Content-Length' header. " \
3632 "Closing connection.\n"));
3633#endif
3637 }
3638 }
3639 }
3640 }
3641}
3642
3643
3651void
3653{
3654 struct MHD_Daemon *daemon = connection->daemon;
3655
3656 if (0 == connection->connection_timeout_ms)
3657 return; /* Skip update of activity for connections
3658 without timeout timer. */
3659 if (connection->suspended)
3660 return; /* no activity on suspended connections */
3661
3663 if (0 != (daemon->options & MHD_USE_THREAD_PER_CONNECTION))
3664 return; /* each connection has personal timeout */
3665
3666 if (connection->connection_timeout_ms != daemon->connection_timeout_ms)
3667 return; /* custom timeout, no need to move it in "normal" DLL */
3668#if defined(MHD_USE_POSIX_THREADS) || defined(MHD_USE_W32_THREADS)
3670#endif
3671 /* move connection to head of timeout list (by remove + add operation) */
3673 daemon->normal_timeout_tail,
3674 connection);
3676 daemon->normal_timeout_tail,
3677 connection);
3678#if defined(MHD_USE_POSIX_THREADS) || defined(MHD_USE_W32_THREADS)
3680#endif
3681}
3682
3683
3693void
3695 bool socket_error)
3696{
3697 ssize_t bytes_read;
3698
3699 if ( (MHD_CONNECTION_CLOSED == connection->state) ||
3700 (connection->suspended) )
3701 return;
3702#ifdef HTTPS_SUPPORT
3703 if (MHD_TLS_CONN_NO_TLS != connection->tls_state)
3704 { /* HTTPS connection. */
3705 if (MHD_TLS_CONN_CONNECTED > connection->tls_state)
3706 {
3707 if (! MHD_run_tls_handshake_ (connection))
3708 return;
3709 }
3710 }
3711#endif /* HTTPS_SUPPORT */
3712
3713 /* make sure "read" has a reasonable number of bytes
3714 in buffer to use per system call (if possible) */
3715 if (connection->read_buffer_offset + connection->daemon->pool_increment >
3716 connection->read_buffer_size)
3717 try_grow_read_buffer (connection,
3718 (connection->read_buffer_size ==
3719 connection->read_buffer_offset));
3720
3721 if (connection->read_buffer_size == connection->read_buffer_offset)
3722 return; /* No space for receiving data. */
3723 bytes_read = connection->recv_cls (connection,
3724 &connection->read_buffer
3725 [connection->read_buffer_offset],
3726 connection->read_buffer_size
3727 - connection->read_buffer_offset);
3728 if ((bytes_read < 0) || socket_error)
3729 {
3730 if ((MHD_ERR_AGAIN_ == bytes_read) && ! socket_error)
3731 return; /* No new data to process. */
3732 if ((bytes_read > 0) && connection->sk_nonblck)
3733 { /* Try to detect the socket error */
3734 int dummy;
3735 bytes_read = connection->recv_cls (connection, &dummy, sizeof (dummy));
3736 }
3737 if (MHD_ERR_CONNRESET_ == bytes_read)
3738 {
3739 if ( (MHD_CONNECTION_INIT < connection->state) &&
3740 (MHD_CONNECTION_FULL_REQ_RECEIVED > connection->state) )
3741 {
3742#ifdef HAVE_MESSAGES
3743 MHD_DLOG (connection->daemon,
3744 _ ("Socket has been disconnected when reading request.\n"));
3745#endif
3746 connection->discard_request = true;
3747 }
3748 MHD_connection_close_ (connection,
3750 return;
3751 }
3752
3753#ifdef HAVE_MESSAGES
3754 if (MHD_CONNECTION_INIT != connection->state)
3755 MHD_DLOG (connection->daemon,
3756 _ ("Connection socket is closed when reading " \
3757 "request due to the error: %s\n"),
3758 (bytes_read < 0) ? str_conn_error_ (bytes_read) :
3759 "detected connection closure");
3760#endif
3761 CONNECTION_CLOSE_ERROR (connection,
3762 NULL);
3763 return;
3764 }
3765
3766 if (0 == bytes_read)
3767 { /* Remote side closed connection. */
3768 connection->read_closed = true;
3769 if ( (MHD_CONNECTION_INIT < connection->state) &&
3770 (MHD_CONNECTION_FULL_REQ_RECEIVED > connection->state) )
3771 {
3772#ifdef HAVE_MESSAGES
3773 MHD_DLOG (connection->daemon,
3774 _ ("Connection was closed by remote side with incomplete "
3775 "request.\n"));
3776#endif
3777 connection->discard_request = true;
3778 MHD_connection_close_ (connection,
3780 }
3781 else if (MHD_CONNECTION_INIT == connection->state)
3782 /* This termination code cannot be reported to the application
3783 * because application has not been informed yet about this request */
3784 MHD_connection_close_ (connection,
3786 else
3787 MHD_connection_close_ (connection,
3789 return;
3790 }
3791 connection->read_buffer_offset += bytes_read;
3792 MHD_update_last_activity_ (connection);
3793#if DEBUG_STATES
3794 MHD_DLOG (connection->daemon,
3795 _ ("In function %s handling connection at state: %s\n"),
3796 __FUNCTION__,
3797 MHD_state_to_string (connection->state));
3798#endif
3799 switch (connection->state)
3800 {
3811 /* nothing to do but default action */
3812 if (connection->read_closed)
3813 {
3814 /* TODO: check whether this really needed */
3815 MHD_connection_close_ (connection,
3817 }
3818 return;
3820 return;
3821#ifdef UPGRADE_SUPPORT
3822 case MHD_CONNECTION_UPGRADE:
3823 mhd_assert (0);
3824 return;
3825#endif /* UPGRADE_SUPPORT */
3826 default:
3827 /* shrink read buffer to how much is actually used */
3828 if ((0 != connection->read_buffer_size) &&
3829 (connection->read_buffer_size != connection->read_buffer_offset))
3830 {
3831 mhd_assert (NULL != connection->read_buffer);
3832 connection->read_buffer =
3833 MHD_pool_reallocate (connection->pool,
3834 connection->read_buffer,
3835 connection->read_buffer_size,
3836 connection->read_buffer_offset);
3837 connection->read_buffer_size = connection->read_buffer_offset;
3838 }
3839 break;
3840 }
3841 return;
3842}
3843
3844
3851void
3853{
3854 struct MHD_Response *response;
3855 ssize_t ret;
3856 if (connection->suspended)
3857 return;
3858
3859#ifdef HTTPS_SUPPORT
3860 if (MHD_TLS_CONN_NO_TLS != connection->tls_state)
3861 { /* HTTPS connection. */
3862 if (MHD_TLS_CONN_CONNECTED > connection->tls_state)
3863 {
3864 if (! MHD_run_tls_handshake_ (connection))
3865 return;
3866 }
3867 }
3868#endif /* HTTPS_SUPPORT */
3869
3870#if DEBUG_STATES
3871 MHD_DLOG (connection->daemon,
3872 _ ("In function %s handling connection at state: %s\n"),
3873 __FUNCTION__,
3874 MHD_state_to_string (connection->state));
3875#endif
3876 switch (connection->state)
3877 {
3883 mhd_assert (0);
3884 return;
3886 return;
3888 ret = MHD_send_data_ (connection,
3890 [connection->continue_message_write_offset],
3892 - connection->continue_message_write_offset,
3893 true);
3894 if (ret < 0)
3895 {
3896 if (MHD_ERR_AGAIN_ == ret)
3897 return;
3898#ifdef HAVE_MESSAGES
3899 MHD_DLOG (connection->daemon,
3900 _ ("Failed to send data in request for %s.\n"),
3901 connection->url);
3902#endif
3903 CONNECTION_CLOSE_ERROR (connection,
3904 NULL);
3905 return;
3906 }
3907#if _MHD_DEBUG_SEND_DATA
3908 fprintf (stderr,
3909 _ ("Sent 100 continue response: `%.*s'\n"),
3910 (int) ret,
3912#endif
3913 connection->continue_message_write_offset += ret;
3914 MHD_update_last_activity_ (connection);
3915 return;
3922 mhd_assert (0);
3923 return;
3925 {
3926 struct MHD_Response *const resp = connection->response;
3927 const size_t wb_ready = connection->write_buffer_append_offset
3928 - connection->write_buffer_send_offset;
3929 mhd_assert (connection->write_buffer_append_offset >= \
3930 connection->write_buffer_send_offset);
3931 mhd_assert (NULL != resp);
3932 mhd_assert ( (0 == resp->data_size) || \
3933 (0 == resp->data_start) || \
3934 (NULL != resp->crc) );
3935 mhd_assert ( (0 == connection->response_write_position) || \
3936 (resp->total_size ==
3937 connection->response_write_position) || \
3939 connection->response_write_position) );
3940 mhd_assert ((MHD_CONN_MUST_UPGRADE != connection->keepalive) || \
3941 (! connection->rp_props.send_reply_body));
3942
3943 if ( (connection->rp_props.send_reply_body) &&
3944 (NULL == resp->crc) &&
3945 (NULL == resp->data_iov) &&
3946 /* TODO: remove the next check as 'send_reply_body' is used */
3947 (0 == connection->response_write_position) &&
3948 (! connection->rp_props.chunked) )
3949 {
3950 mhd_assert (resp->total_size >= resp->data_size);
3951 mhd_assert (0 == resp->data_start);
3952 /* Send response headers alongside the response body, if the body
3953 * data is available. */
3954 ret = MHD_send_hdr_and_body_ (connection,
3955 &connection->write_buffer
3956 [connection->write_buffer_send_offset],
3957 wb_ready,
3958 false,
3959 resp->data,
3960 resp->data_size,
3961 (resp->total_size == resp->data_size));
3962 }
3963 else
3964 {
3965 /* This is response for HEAD request or reply body is not allowed
3966 * for any other reason or reply body is dynamically generated. */
3967 /* Do not send the body data even if it's available. */
3968 ret = MHD_send_hdr_and_body_ (connection,
3969 &connection->write_buffer
3970 [connection->write_buffer_send_offset],
3971 wb_ready,
3972 false,
3973 NULL,
3974 0,
3975 ((0 == resp->total_size) ||
3976 (! connection->rp_props.send_reply_body)
3977 ));
3978 }
3979
3980 if (ret < 0)
3981 {
3982 if (MHD_ERR_AGAIN_ == ret)
3983 return;
3984#ifdef HAVE_MESSAGES
3985 MHD_DLOG (connection->daemon,
3986 _ ("Failed to send the response headers for the " \
3987 "request for `%s'. Error: %s\n"),
3988 connection->url,
3989 str_conn_error_ (ret));
3990#endif
3991 CONNECTION_CLOSE_ERROR (connection,
3992 NULL);
3993 return;
3994 }
3995 /* 'ret' is not negative, it's safe to cast it to 'size_t'. */
3996 if (((size_t) ret) > wb_ready)
3997 {
3998 /* The complete header and some response data have been sent,
3999 * update both offsets. */
4000 mhd_assert (0 == connection->response_write_position);
4001 mhd_assert (! connection->rp_props.chunked);
4002 mhd_assert (connection->rp_props.send_reply_body);
4003 connection->write_buffer_send_offset += wb_ready;
4004 connection->response_write_position = ret - wb_ready;
4005 }
4006 else
4007 connection->write_buffer_send_offset += ret;
4008 MHD_update_last_activity_ (connection);
4009 if (MHD_CONNECTION_HEADERS_SENDING != connection->state)
4010 return;
4011 check_write_done (connection,
4013 return;
4014 }
4016 return;
4018 response = connection->response;
4019 if (connection->response_write_position <
4020 connection->response->total_size)
4021 {
4022 uint64_t data_write_offset;
4023
4024#if defined(MHD_USE_POSIX_THREADS) || defined(MHD_USE_W32_THREADS)
4025 if (NULL != response->crc)
4026 MHD_mutex_lock_chk_ (&response->mutex);
4027#endif
4028 if (MHD_NO == try_ready_normal_body (connection))
4029 {
4030 /* mutex was already unlocked by try_ready_normal_body */
4031 return;
4032 }
4033#if defined(_MHD_HAVE_SENDFILE)
4034 if (MHD_resp_sender_sendfile == connection->resp_sender)
4035 {
4036 mhd_assert (NULL == response->data_iov);
4037 ret = MHD_send_sendfile_ (connection);
4038 }
4039 else /* combined with the next 'if' */
4040#endif /* _MHD_HAVE_SENDFILE */
4041 if (NULL != response->data_iov)
4042 {
4043 ret = MHD_send_iovec_ (connection,
4044 &connection->resp_iov,
4045 true);
4046 }
4047 else
4048 {
4049 data_write_offset = connection->response_write_position
4050 - response->data_start;
4051 if (data_write_offset > (uint64_t) SIZE_MAX)
4052 MHD_PANIC (_ ("Data offset exceeds limit.\n"));
4053 ret = MHD_send_data_ (connection,
4054 &response->data
4055 [(size_t) data_write_offset],
4056 response->data_size
4057 - (size_t) data_write_offset,
4058 true);
4059#if _MHD_DEBUG_SEND_DATA
4060 if (ret > 0)
4061 fprintf (stderr,
4062 _ ("Sent %d-byte DATA response: `%.*s'\n"),
4063 (int) ret,
4064 (int) ret,
4065 &response->data[connection->response_write_position
4066 - response->data_start]);
4067#endif
4068 }
4069#if defined(MHD_USE_POSIX_THREADS) || defined(MHD_USE_W32_THREADS)
4070 if (NULL != response->crc)
4071 MHD_mutex_unlock_chk_ (&response->mutex);
4072#endif
4073 if (ret < 0)
4074 {
4075 if (MHD_ERR_AGAIN_ == ret)
4076 return;
4077#ifdef HAVE_MESSAGES
4078 MHD_DLOG (connection->daemon,
4079 _ ("Failed to send the response body for the " \
4080 "request for `%s'. Error: %s\n"),
4081 connection->url,
4082 str_conn_error_ (ret));
4083#endif
4084 CONNECTION_CLOSE_ERROR (connection,
4085 NULL);
4086 return;
4087 }
4088 connection->response_write_position += ret;
4089 MHD_update_last_activity_ (connection);
4090 }
4091 if (connection->response_write_position ==
4092 connection->response->total_size)
4093 connection->state = MHD_CONNECTION_FOOTERS_SENT; /* have no footers */
4094 return;
4096 mhd_assert (0);
4097 return;
4099 ret = MHD_send_data_ (connection,
4100 &connection->write_buffer
4101 [connection->write_buffer_send_offset],
4102 connection->write_buffer_append_offset
4103 - connection->write_buffer_send_offset,
4104 true);
4105 if (ret < 0)
4106 {
4107 if (MHD_ERR_AGAIN_ == ret)
4108 return;
4109#ifdef HAVE_MESSAGES
4110 MHD_DLOG (connection->daemon,
4111 _ ("Failed to send the chunked response body for the " \
4112 "request for `%s'. Error: %s\n"),
4113 connection->url,
4114 str_conn_error_ (ret));
4115#endif
4116 CONNECTION_CLOSE_ERROR (connection,
4117 NULL);
4118 return;
4119 }
4120 connection->write_buffer_send_offset += ret;
4121 MHD_update_last_activity_ (connection);
4122 if (MHD_CONNECTION_CHUNKED_BODY_READY != connection->state)
4123 return;
4124 check_write_done (connection,
4125 (connection->response->total_size ==
4126 connection->response_write_position) ?
4129 return;
4132 mhd_assert (0);
4133 return;
4135 ret = MHD_send_data_ (connection,
4136 &connection->write_buffer
4137 [connection->write_buffer_send_offset],
4138 connection->write_buffer_append_offset
4139 - connection->write_buffer_send_offset,
4140 true);
4141 if (ret < 0)
4142 {
4143 if (MHD_ERR_AGAIN_ == ret)
4144 return;
4145#ifdef HAVE_MESSAGES
4146 MHD_DLOG (connection->daemon,
4147 _ ("Failed to send the footers for the " \
4148 "request for `%s'. Error: %s\n"),
4149 connection->url,
4150 str_conn_error_ (ret));
4151#endif
4152 CONNECTION_CLOSE_ERROR (connection,
4153 NULL);
4154 return;
4155 }
4156 connection->write_buffer_send_offset += ret;
4157 MHD_update_last_activity_ (connection);
4158 if (MHD_CONNECTION_FOOTERS_SENDING != connection->state)
4159 return;
4160 check_write_done (connection,
4162 return;
4164 mhd_assert (0);
4165 return;
4167 return;
4168#ifdef UPGRADE_SUPPORT
4169 case MHD_CONNECTION_UPGRADE:
4170 mhd_assert (0);
4171 return;
4172#endif /* UPGRADE_SUPPORT */
4173 default:
4174 mhd_assert (0);
4175 CONNECTION_CLOSE_ERROR (connection,
4176 _ ("Internal error.\n"));
4177 break;
4178 }
4179 return;
4180}
4181
4182
4189static bool
4191{
4192 const uint64_t timeout = c->connection_timeout_ms;
4193 uint64_t now;
4194 uint64_t since_actv;
4195
4196 if (c->suspended)
4197 return false;
4198 if (0 == timeout)
4199 return false;
4201 since_actv = now - c->last_activity;
4202 /* Keep the next lines in sync with #connection_get_wait() to avoid
4203 * undesired side-effects like busy-waiting. */
4204 if (timeout < since_actv)
4205 {
4206 if (UINT64_MAX / 2 < since_actv)
4207 {
4208 const uint64_t jump_back = c->last_activity - now;
4209 /* Very unlikely that it is more than quarter-million years pause.
4210 * More likely that system clock jumps back. */
4211 if (5000 >= jump_back)
4212 {
4213#ifdef HAVE_MESSAGES
4214 MHD_DLOG (c->daemon,
4215 _ ("Detected system clock %u milliseconds jump back.\n"),
4216 (unsigned int) jump_back);
4217#endif
4218 return false;
4219 }
4220#ifdef HAVE_MESSAGES
4221 MHD_DLOG (c->daemon,
4222 _ ("Detected too large system clock %" PRIu64 " milliseconds "
4223 "jump back.\n"),
4224 jump_back);
4225#endif
4226 }
4227 return true;
4228 }
4229 return false;
4230}
4231
4232
4241static void
4243{
4244 struct MHD_Daemon *daemon = connection->daemon;
4245#ifdef MHD_USE_THREADS
4246 mhd_assert ( (0 == (daemon->options & MHD_USE_INTERNAL_POLLING_THREAD)) || \
4247 MHD_thread_ID_match_current_ (connection->pid) );
4248#endif /* MHD_USE_THREADS */
4249
4250 if (connection->in_cleanup)
4251 return; /* Prevent double cleanup. */
4252 connection->in_cleanup = true;
4253 if (NULL != connection->response)
4254 {
4255 MHD_destroy_response (connection->response);
4256 connection->response = NULL;
4257 }
4258#if defined(MHD_USE_POSIX_THREADS) || defined(MHD_USE_W32_THREADS)
4260#endif
4261 if (connection->suspended)
4262 {
4265 connection);
4266 connection->suspended = false;
4267 }
4268 else
4269 {
4270 if (0 == (daemon->options & MHD_USE_THREAD_PER_CONNECTION))
4271 {
4272 if (connection->connection_timeout_ms == daemon->connection_timeout_ms)
4274 daemon->normal_timeout_tail,
4275 connection);
4276 else
4278 daemon->manual_timeout_tail,
4279 connection);
4280 }
4282 daemon->connections_tail,
4283 connection);
4284 }
4285 DLL_insert (daemon->cleanup_head,
4286 daemon->cleanup_tail,
4287 connection);
4288 connection->resuming = false;
4289 connection->in_idle = false;
4290#if defined(MHD_USE_POSIX_THREADS) || defined(MHD_USE_W32_THREADS)
4292#endif
4293 if (0 != (daemon->options & MHD_USE_THREAD_PER_CONNECTION))
4294 {
4295 /* if we were at the connection limit before and are in
4296 thread-per-connection mode, signal the main thread
4297 to resume accepting connections */
4298 if ( (MHD_ITC_IS_VALID_ (daemon->itc)) &&
4299 (! MHD_itc_activate_ (daemon->itc, "c")) )
4300 {
4301#ifdef HAVE_MESSAGES
4302 MHD_DLOG (daemon,
4303 _ (
4304 "Failed to signal end of connection via inter-thread communication channel.\n"));
4305#endif
4306 }
4307 }
4308}
4309
4310
4317static void
4319 bool reuse)
4320{
4321 struct MHD_Connection *const c = connection;
4322 struct MHD_Daemon *const d = connection->daemon;
4323
4324 if (! reuse)
4325 {
4326 /* Next function will destroy response, notify client,
4327 * destroy memory pool, and set connection state to "CLOSED" */
4328 MHD_connection_close_ (connection,
4329 c->stop_with_error ?
4332 c->read_buffer = NULL;
4333 c->read_buffer_size = 0;
4334 c->read_buffer_offset = 0;
4335 c->write_buffer = NULL;
4336 c->write_buffer_size = 0;
4339 }
4340 else
4341 {
4342 /* Reset connection to process the next request */
4343 size_t new_read_buf_size;
4346
4347 if ( (NULL != d->notify_completed) &&
4348 (c->client_aware) )
4350 c,
4351 &c->client_context,
4353 c->client_aware = false;
4354
4355 if (NULL != c->response)
4357 c->response = NULL;
4358 c->version = NULL;
4360 c->last = NULL;
4361 c->colon = NULL;
4362 c->header_size = 0;
4364 /* Reset the read buffer to the starting size,
4365 preserving the bytes we have already read. */
4366 new_read_buf_size = c->daemon->pool_size / 2;
4367 if (c->read_buffer_offset > new_read_buf_size)
4368 new_read_buf_size = c->read_buffer_offset;
4369
4370 connection->read_buffer
4371 = MHD_pool_reset (c->pool,
4372 c->read_buffer,
4374 new_read_buf_size);
4375 c->read_buffer_size = new_read_buf_size;
4379 c->have_chunked_upload = false;
4380 c->current_chunk_size = 0;
4381 c->current_chunk_offset = 0;
4382 c->responseCode = 0;
4384 c->method = NULL;
4386 c->url = NULL;
4387 memset (&c->rp_props, 0, sizeof(c->rp_props));
4388 c->write_buffer = NULL;
4389 c->write_buffer_size = 0;
4392 /* iov (if any) was deallocated by MHD_pool_reset */
4393 memset (&connection->resp_iov, 0, sizeof(connection->resp_iov));
4395 }
4396 connection->client_context = NULL;
4397}
4398
4399
4410enum MHD_Result
4412{
4413 struct MHD_Daemon *daemon = connection->daemon;
4414 char *line;
4415 size_t line_len;
4416 enum MHD_Result ret;
4417#ifdef MHD_USE_THREADS
4418 mhd_assert ( (0 == (daemon->options & MHD_USE_INTERNAL_POLLING_THREAD)) || \
4419 MHD_thread_ID_match_current_ (connection->pid) );
4420#endif /* MHD_USE_THREADS */
4421 /* 'daemon' is not used if epoll is not available and asserts are disabled */
4422 (void) daemon; /* Mute compiler warning */
4423
4424 connection->in_idle = true;
4425 while (! connection->suspended)
4426 {
4427#ifdef HTTPS_SUPPORT
4428 if (MHD_TLS_CONN_NO_TLS != connection->tls_state)
4429 { /* HTTPS connection. */
4430 if ((MHD_TLS_CONN_INIT <= connection->tls_state) &&
4431 (MHD_TLS_CONN_CONNECTED > connection->tls_state))
4432 break;
4433 }
4434#endif /* HTTPS_SUPPORT */
4435#if DEBUG_STATES
4436 MHD_DLOG (daemon,
4437 _ ("In function %s handling connection at state: %s\n"),
4438 __FUNCTION__,
4439 MHD_state_to_string (connection->state));
4440#endif
4441 switch (connection->state)
4442 {
4445 line = get_next_header_line (connection,
4446 &line_len);
4447 if (NULL != line)
4448 {
4449 /* Check for empty string, as we might want
4450 to tolerate 'spurious' empty lines */
4451 if (0 == line[0])
4452 {
4453 /* TODO: Add MHD option to not tolerate it */
4454 connection->state = MHD_CONNECTION_INIT;
4455 continue; /* Process the next line */
4456 }
4457 if (MHD_NO == parse_initial_message_line (connection,
4458 line,
4459 line_len))
4460 CONNECTION_CLOSE_ERROR_CHECK (connection,
4461 NULL);
4462 else
4463 {
4465 connection->state = MHD_CONNECTION_URL_RECEIVED;
4466 }
4467 continue;
4468 }
4469 /* NULL means we didn't get a full line yet */
4470 if (connection->discard_request)
4471 {
4472 mhd_assert (MHD_CONNECTION_INIT != connection->state);
4473 continue;
4474 }
4475 if (0 < connection->read_buffer_offset)
4477 break;
4479 line = get_next_header_line (connection,
4480 NULL);
4481 if (NULL == line)
4482 {
4483 if (MHD_CONNECTION_URL_RECEIVED != connection->state)
4484 continue;
4485 if (connection->read_closed)
4486 {
4487 CONNECTION_CLOSE_ERROR (connection,
4488 NULL);
4489 continue;
4490 }
4491 break;
4492 }
4493 if (0 == line[0])
4494 {
4496 connection->header_size = (size_t) (connection->read_buffer
4497 - connection->method);
4498 continue;
4499 }
4500 if (MHD_NO == process_header_line (connection,
4501 line))
4502 {
4506 break;
4507 }
4509 continue;
4511 line = get_next_header_line (connection,
4512 NULL);
4513 if (NULL == line)
4514 {
4515 if (connection->state != MHD_CONNECTION_HEADER_PART_RECEIVED)
4516 continue;
4517 if (connection->read_closed)
4518 {
4519 CONNECTION_CLOSE_ERROR (connection,
4520 NULL);
4521 continue;
4522 }
4523 break;
4524 }
4525 if (MHD_NO ==
4526 process_broken_line (connection,
4527 line,
4529 continue;
4530 if (0 == line[0])
4531 {
4533 connection->header_size = (size_t) (connection->read_buffer
4534 - connection->method);
4535 continue;
4536 }
4537 continue;
4539 parse_connection_headers (connection);
4540 if (MHD_CONNECTION_CLOSED == connection->state)
4541 continue;
4543 if (connection->suspended)
4544 break;
4545 continue;
4547 call_connection_handler (connection); /* first call */
4548 if (MHD_CONNECTION_CLOSED == connection->state)
4549 continue;
4550 if (connection->suspended)
4551 continue;
4552 if ( (NULL == connection->response) &&
4553 (need_100_continue (connection)) )
4554 {
4556 break;
4557 }
4558 if ( (NULL != connection->response) &&
4559 (0 != connection->remaining_upload_size) )
4560 {
4561 /* we refused (no upload allowed!) */
4562 connection->remaining_upload_size = 0;
4563 /* force close, in case client still tries to upload... */
4564 connection->discard_request = true;
4565 }
4566 connection->state = (0 == connection->remaining_upload_size)
4569 if (connection->suspended)
4570 break;
4571 continue;
4573 if (connection->continue_message_write_offset ==
4575 {
4576 connection->state = MHD_CONNECTION_CONTINUE_SENT;
4577 continue;
4578 }
4579 break;
4581 if (0 != connection->read_buffer_offset)
4582 {
4583 process_request_body (connection); /* loop call */
4584 if (connection->discard_request)
4585 {
4587 continue;
4588 }
4589 }
4590 if ( (0 == connection->remaining_upload_size) ||
4591 ( (MHD_SIZE_UNKNOWN == connection->remaining_upload_size) &&
4592 (0 == connection->read_buffer_offset) &&
4593 (connection->discard_request) ) )
4594 {
4595 if ( (connection->have_chunked_upload) &&
4596 (! connection->discard_request) )
4597 connection->state = MHD_CONNECTION_BODY_RECEIVED;
4598 else
4600 if (connection->suspended)
4601 break;
4602 continue;
4603 }
4604 break;
4606 line = get_next_header_line (connection,
4607 NULL);
4608 if (NULL == line)
4609 {
4610 if (connection->state != MHD_CONNECTION_BODY_RECEIVED)
4611 continue;
4612 if (connection->read_closed)
4613 {
4614 CONNECTION_CLOSE_ERROR (connection,
4615 NULL);
4616 continue;
4617 }
4618 if (0 < connection->read_buffer_offset)
4620 break;
4621 }
4622 if (0 == line[0])
4623 {
4625 if (connection->suspended)
4626 break;
4627 continue;
4628 }
4629 if (MHD_NO == process_header_line (connection,
4630 line))
4631 {
4635 break;
4636 }
4638 continue;
4640 line = get_next_header_line (connection,
4641 NULL);
4642 if (NULL == line)
4643 {
4644 if (connection->state != MHD_CONNECTION_FOOTER_PART_RECEIVED)
4645 continue;
4646 if (connection->read_closed)
4647 {
4648 CONNECTION_CLOSE_ERROR (connection,
4649 NULL);
4650 continue;
4651 }
4652 break;
4653 }
4654 if (MHD_NO ==
4655 process_broken_line (connection,
4656 line,
4658 continue;
4659 if (0 == line[0])
4660 {
4662 if (connection->suspended)
4663 break;
4664 continue;
4665 }
4666 continue;
4668 /* The header, the body, and the footers of the request has been received,
4669 * switch to the final processing of the request. */
4671 continue;
4673 call_connection_handler (connection); /* "final" call */
4674 if (connection->state == MHD_CONNECTION_CLOSED)
4675 continue;
4676 if (NULL == connection->response)
4677 break; /* try again next time */
4678 /* Response is ready, start reply */
4679 connection->state = MHD_CONNECTION_START_REPLY;
4680 continue;
4682 mhd_assert (NULL != connection->response);
4684 if (MHD_NO == build_header_response (connection))
4685 {
4686 /* oops - close! */
4687 CONNECTION_CLOSE_ERROR (connection,
4688 _ ("Closing connection (failed to create "
4689 "response header).\n"));
4690 continue;
4691 }
4693 break;
4694
4696 /* no default action */
4697 break;
4699 /* Some clients may take some actions right after header receive */
4700#ifdef UPGRADE_SUPPORT
4701 if (NULL != connection->response->upgrade_handler)
4702 {
4703 connection->state = MHD_CONNECTION_UPGRADE;
4704 /* This connection is "upgraded". Pass socket to application. */
4705 if (MHD_NO ==
4707 connection))
4708 {
4709 /* upgrade failed, fail hard */
4710 CONNECTION_CLOSE_ERROR (connection,
4711 NULL);
4712 continue;
4713 }
4714 /* Response is not required anymore for this connection. */
4715 {
4716 struct MHD_Response *const resp = connection->response;
4717
4718 connection->response = NULL;
4719 MHD_destroy_response (resp);
4720 }
4721 continue;
4722 }
4723#endif /* UPGRADE_SUPPORT */
4724
4725 if (connection->rp_props.chunked)
4727 else
4729 continue;
4731 /* nothing to do here */
4732 break;
4734#if defined(MHD_USE_POSIX_THREADS) || defined(MHD_USE_W32_THREADS)
4735 if (NULL != connection->response->crc)
4736 MHD_mutex_lock_chk_ (&connection->response->mutex);
4737#endif
4738 if (0 == connection->response->total_size)
4739 {
4740#if defined(MHD_USE_POSIX_THREADS) || defined(MHD_USE_W32_THREADS)
4741 if (NULL != connection->response->crc)
4742 MHD_mutex_unlock_chk_ (&connection->response->mutex);
4743#endif
4744 if (connection->rp_props.chunked)
4745 connection->state = MHD_CONNECTION_BODY_SENT;
4746 else
4747 connection->state = MHD_CONNECTION_FOOTERS_SENT;
4748 continue;
4749 }
4750 if (MHD_NO != try_ready_normal_body (connection))
4751 {
4752#if defined(MHD_USE_POSIX_THREADS) || defined(MHD_USE_W32_THREADS)
4753 if (NULL != connection->response->crc)
4754 MHD_mutex_unlock_chk_ (&connection->response->mutex);
4755#endif
4757 /* Buffering for flushable socket was already enabled*/
4758
4759 break;
4760 }
4761 /* mutex was already unlocked by "try_ready_normal_body */
4762 /* not ready, no socket action */
4763 break;
4765 /* nothing to do here */
4766 break;
4768#if defined(MHD_USE_POSIX_THREADS) || defined(MHD_USE_W32_THREADS)
4769 if (NULL != connection->response->crc)
4770 MHD_mutex_lock_chk_ (&connection->response->mutex);
4771#endif
4772 if ( (0 == connection->response->total_size) ||
4773 (connection->response_write_position ==
4774 connection->response->total_size) )
4775 {
4776#if defined(MHD_USE_POSIX_THREADS) || defined(MHD_USE_W32_THREADS)
4777 if (NULL != connection->response->crc)
4778 MHD_mutex_unlock_chk_ (&connection->response->mutex);
4779#endif
4780 connection->state = MHD_CONNECTION_BODY_SENT;
4781 continue;
4782 }
4783 if (1)
4784 { /* pseudo-branch for local variables scope */
4785 bool finished;
4786 if (MHD_NO != try_ready_chunked_body (connection, &finished))
4787 {
4788#if defined(MHD_USE_POSIX_THREADS) || defined(MHD_USE_W32_THREADS)
4789 if (NULL != connection->response->crc)
4790 MHD_mutex_unlock_chk_ (&connection->response->mutex);
4791#endif
4792 connection->state = finished ? MHD_CONNECTION_BODY_SENT :
4794 continue;
4795 }
4796 /* mutex was already unlocked by try_ready_chunked_body */
4797 }
4798 break;
4800 mhd_assert (connection->rp_props.chunked);
4801
4803 {
4804 /* oops - close! */
4805 CONNECTION_CLOSE_ERROR (connection,
4806 _ (
4807 "Closing connection (failed to create response footer)."));
4808 continue;
4809 }
4810 /* TODO: remove next 'if' */
4811 if ( (! connection->rp_props.chunked) ||
4812 (connection->write_buffer_send_offset ==
4813 connection->write_buffer_append_offset) )
4814 connection->state = MHD_CONNECTION_FOOTERS_SENT;
4815 else
4817 continue;
4819 /* no default action */
4820 break;
4822 if (MHD_HTTP_PROCESSING == connection->responseCode)
4823 {
4824 /* After this type of response, we allow sending another! */
4826 MHD_destroy_response (connection->response);
4827 connection->response = NULL;
4828 /* FIXME: maybe partially reset memory pool? */
4829 continue;
4830 }
4831 /* Reset connection after complete reply */
4832 connection_reset (connection,
4833 MHD_CONN_USE_KEEPALIVE == connection->keepalive &&
4834 ! connection->read_closed &&
4835 ! connection->discard_request);
4836 continue;
4838 cleanup_connection (connection);
4839 connection->in_idle = false;
4840 return MHD_NO;
4841#ifdef UPGRADE_SUPPORT
4842 case MHD_CONNECTION_UPGRADE:
4843 connection->in_idle = false;
4844 return MHD_YES; /* keep open */
4845#endif /* UPGRADE_SUPPORT */
4846 default:
4847 mhd_assert (0);
4848 break;
4849 }
4850 break;
4851 }
4852 if (connection_check_timedout (connection))
4853 {
4854 MHD_connection_close_ (connection,
4856 connection->in_idle = false;
4857 return MHD_YES;
4858 }
4860 ret = MHD_YES;
4861#ifdef EPOLL_SUPPORT
4862 if ( (! connection->suspended) &&
4863 (0 != (daemon->options & MHD_USE_EPOLL)) )
4864 {
4865 ret = MHD_connection_epoll_update_ (connection);
4866 }
4867#endif /* EPOLL_SUPPORT */
4868 connection->in_idle = false;
4869 return ret;
4870}
4871
4872
4873#ifdef EPOLL_SUPPORT
4882enum MHD_Result
4883MHD_connection_epoll_update_ (struct MHD_Connection *connection)
4884{
4885 struct MHD_Daemon *daemon = connection->daemon;
4886
4887 if ( (0 != (daemon->options & MHD_USE_EPOLL)) &&
4888 (0 == (connection->epoll_state & MHD_EPOLL_STATE_IN_EPOLL_SET)) &&
4889 (0 == (connection->epoll_state & MHD_EPOLL_STATE_SUSPENDED)) &&
4890 ( ( (MHD_EVENT_LOOP_INFO_WRITE == connection->event_loop_info) &&
4891 (0 == (connection->epoll_state & MHD_EPOLL_STATE_WRITE_READY))) ||
4892 ( (MHD_EVENT_LOOP_INFO_READ == connection->event_loop_info) &&
4893 (0 == (connection->epoll_state & MHD_EPOLL_STATE_READ_READY)) ) ) )
4894 {
4895 /* add to epoll set */
4896 struct epoll_event event;
4897
4898 event.events = EPOLLIN | EPOLLOUT | EPOLLPRI | EPOLLET;
4899 event.data.ptr = connection;
4900 if (0 != epoll_ctl (daemon->epoll_fd,
4901 EPOLL_CTL_ADD,
4902 connection->socket_fd,
4903 &event))
4904 {
4905#ifdef HAVE_MESSAGES
4906 if (0 != (daemon->options & MHD_USE_ERROR_LOG))
4907 MHD_DLOG (daemon,
4908 _ ("Call to epoll_ctl failed: %s\n"),
4910#endif
4911 connection->state = MHD_CONNECTION_CLOSED;
4912 cleanup_connection (connection);
4913 return MHD_NO;
4914 }
4915 connection->epoll_state |= MHD_EPOLL_STATE_IN_EPOLL_SET;
4916 }
4917 return MHD_YES;
4918}
4919
4920
4921#endif
4922
4923
4929void
4931{
4932 connection->recv_cls = &recv_param_adapter;
4933}
4934
4935
4946const union MHD_ConnectionInfo *
4948 enum MHD_ConnectionInfoType info_type,
4949 ...)
4950{
4951 switch (info_type)
4952 {
4953#ifdef HTTPS_SUPPORT
4955 if (NULL == connection->tls_session)
4956 return NULL;
4957 connection->cipher = gnutls_cipher_get (connection->tls_session);
4958 return (const union MHD_ConnectionInfo *) &connection->cipher;
4960 if (NULL == connection->tls_session)
4961 return NULL;
4962 connection->protocol = gnutls_protocol_get_version (
4963 connection->tls_session);
4964 return (const union MHD_ConnectionInfo *) &connection->protocol;
4966 if (NULL == connection->tls_session)
4967 return NULL;
4968 return (const union MHD_ConnectionInfo *) &connection->tls_session;
4969#endif /* HTTPS_SUPPORT */
4971 return (const union MHD_ConnectionInfo *) &connection->addr;
4973 return (const union MHD_ConnectionInfo *) &connection->daemon;
4975 return (const union MHD_ConnectionInfo *) &connection->socket_fd;
4977 return (const union MHD_ConnectionInfo *) &connection->socket_context;
4979 connection->suspended_dummy = connection->suspended ? MHD_YES : MHD_NO;
4980 return (const union MHD_ConnectionInfo *) &connection->suspended_dummy;
4982 connection->connection_timeout_dummy =
4983 (unsigned int) connection->connection_timeout_ms / 1000;
4984 return (const union MHD_ConnectionInfo *) &connection->
4985 connection_timeout_dummy;
4987 if ( (MHD_CONNECTION_HEADERS_RECEIVED > connection->state) ||
4988 (MHD_CONNECTION_CLOSED == connection->state) )
4989 return NULL; /* invalid, too early! */
4990 return (const union MHD_ConnectionInfo *) &connection->header_size;
4992 if (NULL == connection->response)
4993 return NULL;
4994 return (const union MHD_ConnectionInfo *) &connection->responseCode;
4995 default:
4996 return NULL;
4997 }
4998}
4999
5000
5010enum MHD_Result
5012 enum MHD_CONNECTION_OPTION option,
5013 ...)
5014{
5015 va_list ap;
5016 struct MHD_Daemon *daemon;
5017 unsigned int ui_val;
5018
5019 daemon = connection->daemon;
5020 switch (option)
5021 {
5023 if (0 == connection->connection_timeout_ms)
5025#if defined(MHD_USE_POSIX_THREADS) || defined(MHD_USE_W32_THREADS)
5027#endif
5028 if ( (0 == (daemon->options & MHD_USE_THREAD_PER_CONNECTION)) &&
5029 (! connection->suspended) )
5030 {
5031 if (connection->connection_timeout_ms == daemon->connection_timeout_ms)
5033 daemon->normal_timeout_tail,
5034 connection);
5035 else
5037 daemon->manual_timeout_tail,
5038 connection);
5039 }
5040 va_start (ap, option);
5041 ui_val = va_arg (ap, unsigned int);
5042 va_end (ap);
5043#if (SIZEOF_UINT64_T - 2) <= SIZEOF_UNSIGNED_INT
5044 if ((UINT64_MAX / 4000 - 1) < ui_val)
5045 {
5046#ifdef HAVE_MESSAGES
5047 MHD_DLOG (connection->daemon,
5048 _ ("The specified connection timeout (%u) is too " \
5049 "large. Maximum allowed value (%" PRIu64 ") will be used " \
5050 "instead.\n"),
5051 ui_val,
5052 (UINT64_MAX / 4000 - 1));
5053#endif
5054 ui_val = UINT64_MAX / 4000 - 1;
5055 }
5056 else
5057#endif /* (SIZEOF_UINT64_T - 2) <= SIZEOF_UNSIGNED_INT */
5058 connection->connection_timeout_ms = ui_val * 1000;
5059 if ( (0 == (daemon->options & MHD_USE_THREAD_PER_CONNECTION)) &&
5060 (! connection->suspended) )
5061 {
5062 if (connection->connection_timeout_ms == daemon->connection_timeout_ms)
5064 daemon->normal_timeout_tail,
5065 connection);
5066 else
5068 daemon->manual_timeout_tail,
5069 connection);
5070 }
5071#if defined(MHD_USE_POSIX_THREADS) || defined(MHD_USE_W32_THREADS)
5073#endif
5074 return MHD_YES;
5075 default:
5076 return MHD_NO;
5077 }
5078}
5079
5080
5098enum MHD_Result
5100 unsigned int status_code,
5101 struct MHD_Response *response)
5102{
5103 struct MHD_Daemon *daemon;
5104
5105 if ((NULL == connection) || (NULL == response))
5106 return MHD_NO;
5107
5108 daemon = connection->daemon;
5109
5110#if defined(MHD_USE_POSIX_THREADS) || defined(MHD_USE_W32_THREADS)
5111 if ( (! connection->suspended) &&
5112 (0 != (daemon->options & MHD_USE_INTERNAL_POLLING_THREAD)) &&
5113 (! MHD_thread_ID_match_current_ (connection->pid)) )
5114 {
5115#ifdef HAVE_MESSAGES
5116 MHD_DLOG (daemon,
5117 _ ("Attempted to queue response on wrong thread!\n"));
5118#endif
5119 return MHD_NO;
5120 }
5121#endif
5122
5123 if (daemon->shutdown)
5124 return MHD_YES; /* If daemon was shut down in parallel,
5125 * response will be aborted now or on later stage. */
5126
5127 if ( (NULL != connection->response) ||
5128 ( (MHD_CONNECTION_HEADERS_PROCESSED != connection->state) &&
5129 (MHD_CONNECTION_FULL_REQ_RECEIVED != connection->state) ) )
5130 return MHD_NO;
5131
5132#ifdef UPGRADE_SUPPORT
5133 if (NULL != response->upgrade_handler)
5134 {
5135 struct MHD_HTTP_Header *conn_header;
5136 if (0 == (daemon->options & MHD_ALLOW_UPGRADE))
5137 {
5138#ifdef HAVE_MESSAGES
5139 MHD_DLOG (daemon,
5140 _ ("Attempted 'upgrade' connection on daemon without" \
5141 " MHD_ALLOW_UPGRADE option!\n"));
5142#endif
5143 return MHD_NO;
5144 }
5145 if (MHD_HTTP_SWITCHING_PROTOCOLS != status_code)
5146 {
5147#ifdef HAVE_MESSAGES
5148 MHD_DLOG (daemon,
5149 _ ("Application used invalid status code for" \
5150 " 'upgrade' response!\n"));
5151#endif
5152 return MHD_NO;
5153 }
5154 if (0 == (response->flags_auto & MHD_RAF_HAS_CONNECTION_HDR))
5155 {
5156#ifdef HAVE_MESSAGES
5157 MHD_DLOG (daemon,
5158 _ ("Application used invalid response" \
5159 " without \"Connection\" header!\n"));
5160#endif
5161 return MHD_NO;
5162 }
5163 conn_header = response->first_header;
5164 mhd_assert (NULL != conn_header);
5167 if (! MHD_str_has_s_token_caseless_ (conn_header->value,
5168 "upgrade"))
5169 {
5170#ifdef HAVE_MESSAGES
5171 MHD_DLOG (daemon,
5172 _ ("Application used invalid response" \
5173 " without \"upgrade\" token in" \
5174 " \"Connection\" header!\n"));
5175#endif
5176 return MHD_NO;
5177 }
5178 if (! MHD_IS_HTTP_VER_1_1_COMPAT (connection->http_ver))
5179 {
5180#ifdef HAVE_MESSAGES
5181 MHD_DLOG (daemon,
5182 _ ("Connection \"Upgrade\" can be used " \
5183 "with HTTP/1.1 connections!\n"));
5184#endif
5185 return MHD_NO;
5186 }
5187 }
5188#endif /* UPGRADE_SUPPORT */
5189 if ( (100 > (status_code & (~MHD_ICY_FLAG))) ||
5190 (999 < (status_code & (~MHD_ICY_FLAG))) )
5191 {
5192#ifdef HAVE_MESSAGES
5193 MHD_DLOG (daemon,
5194 _ ("Refused wrong status code (%u). " \
5195 "HTTP requires three digits status code!\n"),
5196 (status_code & (~MHD_ICY_FLAG)));
5197#endif
5198 return MHD_NO;
5199 }
5200 if (200 > (status_code & (~MHD_ICY_FLAG)))
5201 {
5202 if (MHD_HTTP_VER_1_0 == connection->http_ver)
5203 {
5204#ifdef HAVE_MESSAGES
5205 MHD_DLOG (daemon,
5206 _ ("Wrong status code (%u) refused. " \
5207 "HTTP/1.0 clients do not support 1xx status codes!\n"),
5208 (status_code & (~MHD_ICY_FLAG)));
5209#endif
5210 return MHD_NO;
5211 }
5212 if (0 != (response->flags & (MHD_RF_HTTP_1_0_COMPATIBLE_STRICT
5214 {
5215#ifdef HAVE_MESSAGES
5216 MHD_DLOG (daemon,
5217 _ ("Wrong status code (%u) refused. " \
5218 "HTTP/1.0 reply mode does not support 1xx status codes!\n"),
5219 (status_code & (~MHD_ICY_FLAG)));
5220#endif
5221 return MHD_NO;
5222 }
5223 }
5224
5225 MHD_increment_response_rc (response);
5226 connection->response = response;
5227 connection->responseCode = status_code;
5228#if defined(_MHD_HAVE_SENDFILE)
5229 if ( (response->fd == -1) ||
5230 (response->is_pipe) ||
5231 (0 != (connection->daemon->options & MHD_USE_TLS))
5232#if defined(MHD_SEND_SPIPE_SUPPRESS_NEEDED) && \
5233 defined(MHD_SEND_SPIPE_SUPPRESS_POSSIBLE)
5234 || (! daemon->sigpipe_blocked && ! connection->sk_spipe_suppress)
5235#endif /* MHD_SEND_SPIPE_SUPPRESS_NEEDED &&
5236 MHD_SEND_SPIPE_SUPPRESS_POSSIBLE */
5237 )
5238 connection->resp_sender = MHD_resp_sender_std;
5239 else
5240 connection->resp_sender = MHD_resp_sender_sendfile;
5241#endif /* _MHD_HAVE_SENDFILE */
5242 /* FIXME: if 'is_pipe' is set, TLS is off, and we have *splice*, we could use splice()
5243 to avoid two user-space copies... */
5244
5245 if ( (MHD_HTTP_MTHD_HEAD == connection->http_mthd) ||
5246 (MHD_HTTP_OK > status_code) ||
5247 (MHD_HTTP_NO_CONTENT == status_code) ||
5248 (MHD_HTTP_NOT_MODIFIED == status_code) )
5249 {
5250 /* if this is a "HEAD" request, or a status code for
5251 which a body is not allowed, pretend that we
5252 have already sent the full message body. */
5253 /* TODO: remove the next assignment, use 'rp_props.send_reply_body' in
5254 * checks */
5255 connection->response_write_position = response->total_size;
5256 }
5257 if (MHD_CONNECTION_HEADERS_PROCESSED == connection->state)
5258 {
5259 /* response was queued "early", refuse to read body / footers or
5260 further requests! */
5261 connection->discard_request = true;
5262 connection->state = MHD_CONNECTION_START_REPLY;
5263 connection->remaining_upload_size = 0;
5264 }
5265 if (! connection->in_idle)
5266 (void) MHD_connection_handle_idle (connection);
5267 MHD_update_last_activity_ (connection);
5268 return MHD_YES;
5269}
5270
5271
5272/* end of connection.c */
#define REQUEST_CONTENTLENGTH_TOOLARGE
Definition: connection.c:135
static void connection_close_error_check(struct MHD_Connection *connection, const char *emsg)
Definition: connection.c:981
static enum MHD_Result build_connection_chunked_response_footer(struct MHD_Connection *connection)
Definition: connection.c:2203
static ssize_t recv_param_adapter(struct MHD_Connection *connection, void *other, size_t i)
Definition: connection.c:316
static bool is_reply_body_headers_needed(struct MHD_Connection *connection)
Definition: connection.c:1691
static enum MHD_Result build_header_response(struct MHD_Connection *connection)
Definition: connection.c:1980
static void connection_close_error(struct MHD_Connection *connection, const char *emsg)
Definition: connection.c:944
static enum MHD_Result process_header_line(struct MHD_Connection *connection, char *line)
Definition: connection.c:3411
static void * connection_alloc_memory(struct MHD_Connection *connection, size_t size)
Definition: connection.c:246
#define MHD_lookup_header_s_token_ci(c, h, tkn)
Definition: connection.c:755
#define REQUEST_CHUNK_TOO_LARGE
Definition: connection.c:124
void MHD_connection_handle_write(struct MHD_Connection *connection)
Definition: connection.c:3852
#define INTERNAL_ERROR
Definition: connection.c:160
static void MHD_connection_update_event_loop_info(struct MHD_Connection *connection)
Definition: connection.c:2407
#define buffer_append_s(buf, ppos, buf_size, str)
Definition: connection.c:1855
static bool add_user_headers(char *buf, size_t *ppos, size_t buf_size, struct MHD_Response *response, enum MHD_ValueKind kind, bool filter_transf_enc, bool add_close, bool add_keep_alive)
Definition: connection.c:1879
static enum MHD_Result try_ready_normal_body(struct MHD_Connection *connection)
Definition: connection.c:1021
#define REQUEST_CHUNKED_MALFORMED
Definition: connection.c:114
#define REQ_HTTP_VER_IS_NOT_SUPPORTED
Definition: connection.c:180
static void call_connection_handler(struct MHD_Connection *connection)
Definition: connection.c:3061
static void process_request_body(struct MHD_Connection *connection)
Definition: connection.c:3097
#define REQUEST_TOO_BIG
Definition: connection.c:75
static void setup_reply_properties(struct MHD_Connection *connection)
Definition: connection.c:1763
#define HTTP_100_CONTINUE
Definition: connection.c:62
static enum MHD_Result parse_cookie_header(struct MHD_Connection *connection)
Definition: connection.c:2696
#define transmit_error_response_static(c, code, msg)
Definition: connection.c:2395
#define REQUEST_MALFORMED
Definition: connection.c:103
static void connection_shrink_read_buffer(struct MHD_Connection *connection)
Definition: connection.c:1548
void MHD_set_http_callbacks_(struct MHD_Connection *connection)
Definition: connection.c:4930
#define REQ_HTTP_VER_IS_TOO_OLD
Definition: connection.c:170
static bool connection_check_timedout(struct MHD_Connection *c)
Definition: connection.c:4190
static enum MHD_ConnKeepAlive keepalive_possible(struct MHD_Connection *connection)
Definition: connection.c:1301
#define REQUEST_LACKS_HOST
Definition: connection.c:89
static bool try_grow_read_buffer(struct MHD_Connection *connection, bool required)
Definition: connection.c:1487
static char * get_next_header_line(struct MHD_Connection *connection, size_t *line_len)
Definition: connection.c:2586
static enum MHD_Result parse_http_std_method(struct MHD_Connection *connection, const char *method, size_t len)
Definition: connection.c:2885
static bool need_100_continue(struct MHD_Connection *connection)
Definition: connection.c:768
enum MHD_Result MHD_connection_handle_idle(struct MHD_Connection *connection)
Definition: connection.c:4411
#define CONNECTION_CLOSE_ERROR_CHECK(c, emsg)
Definition: connection.c:1003
static void cleanup_connection(struct MHD_Connection *connection)
Definition: connection.c:4242
static bool is_reply_body_needed(struct MHD_Connection *connection)
Definition: connection.c:1731
static enum MHD_Result process_broken_line(struct MHD_Connection *connection, char *line, enum MHD_ValueKind kind)
Definition: connection.c:3468
static enum MHD_Result try_ready_chunked_body(struct MHD_Connection *connection, bool *p_finished)
Definition: connection.c:1124
static bool get_date_str(char *date)
Definition: connection.c:1369
static void connection_reset(struct MHD_Connection *connection, bool reuse)
Definition: connection.c:4318
void MHD_connection_handle_read(struct MHD_Connection *connection, bool socket_error)
Definition: connection.c:3694
static void transmit_error_response_len(struct MHD_Connection *connection, unsigned int status_code, const char *message, size_t message_len)
Definition: connection.c:2272
static void connection_switch_from_recv_to_send(struct MHD_Connection *connection)
Definition: connection.c:1669
static void parse_connection_headers(struct MHD_Connection *connection)
Definition: connection.c:3553
void MHD_update_last_activity_(struct MHD_Connection *connection)
Definition: connection.c:3652
#define REQUEST_CONTENTLENGTH_MALFORMED
Definition: connection.c:147
static enum MHD_Result parse_initial_message_line(struct MHD_Connection *connection, char *line, size_t line_len)
Definition: connection.c:2936
void MHD_connection_close_(struct MHD_Connection *connection, enum MHD_RequestTerminationCode termination_code)
Definition: connection.c:830
static size_t connection_maximize_write_buffer(struct MHD_Connection *connection)
Definition: connection.c:1577
static enum MHD_Result connection_add_header(struct MHD_Connection *connection, const char *key, size_t key_size, const char *value, size_t value_size, enum MHD_ValueKind kind)
Definition: connection.c:2661
void MHD_connection_mark_closed_(struct MHD_Connection *connection)
Definition: connection.c:792
#define CONNECTION_CLOSE_ERROR(c, emsg)
Definition: connection.c:969
static bool buffer_append(char *buf, size_t *ppos, size_t buf_size, const char *append, size_t append_size)
Definition: connection.c:1830
static enum MHD_Result check_write_done(struct MHD_Connection *connection, enum MHD_CONNECTION_STATE next_state)
Definition: connection.c:3386
static enum MHD_Result parse_http_version(struct MHD_Connection *connection, const char *http_string, size_t len)
Definition: connection.c:2822
static bool get_date_header(char *header)
Definition: connection.c:1454
static bool MHD_lookup_header_token_ci(const struct MHD_Connection *connection, const char *header, size_t header_len, const char *token, size_t token_len)
Definition: connection.c:713
Methods for managing connections.
#define MHD_connection_finish_forward_(conn)
Definition: connection.h:165
#define MHD_ERR_TLS_
Definition: connection.h:77
#define MHD_ERR_OPNOTSUPP_
Definition: connection.h:67
#define MHD_ERR_PIPE_
Definition: connection.h:72
bool MHD_tls_connection_shutdown(struct MHD_Connection *connection)
bool MHD_run_tls_handshake_(struct MHD_Connection *connection)
Methods for managing connections.
#define MHD_HTTP_HEADER_CONTENT_LENGTH
Definition: microhttpd.h:612
#define MHD_HTTP_HEADER_CONNECTION
Definition: microhttpd.h:606
#define MHD_HTTP_HEADER_TRANSFER_ENCODING
Definition: microhttpd.h:674
#define MHD_HTTP_HEADER_COOKIE
Definition: microhttpd.h:772
#define MHD_HTTP_HEADER_EXPECT
Definition: microhttpd.h:624
#define MHD_HTTP_HEADER_HOST
Definition: microhttpd.h:632
#define MHD_HTTP_INTERNAL_SERVER_ERROR
Definition: microhttpd.h:459
#define MHD_HTTP_OK
Definition: microhttpd.h:356
#define MHD_HTTP_URI_TOO_LONG
Definition: microhttpd.h:425
#define MHD_HTTP_REQUEST_HEADER_FIELDS_TOO_LARGE
Definition: microhttpd.h:453
#define MHD_HTTP_PROCESSING
Definition: microhttpd.h:351
#define MHD_HTTP_SWITCHING_PROTOCOLS
Definition: microhttpd.h:349
#define MHD_HTTP_HTTP_VERSION_NOT_SUPPORTED
Definition: microhttpd.h:469
#define MHD_HTTP_CONTENT_TOO_LARGE
Definition: microhttpd.h:423
#define MHD_HTTP_NOT_MODIFIED
Definition: microhttpd.h:386
#define MHD_HTTP_NO_CONTENT
Definition: microhttpd.h:364
#define MHD_HTTP_BAD_REQUEST
Definition: microhttpd.h:397
#define MHD_HTTP_METHOD_TRACE
Definition: microhttpd.h:1100
#define MHD_HTTP_METHOD_OPTIONS
Definition: microhttpd.h:1094
#define MHD_HTTP_METHOD_GET
Definition: microhttpd.h:1090
#define MHD_HTTP_METHOD_HEAD
Definition: microhttpd.h:1092
#define MHD_HTTP_METHOD_POST
Definition: microhttpd.h:1096
#define MHD_HTTP_METHOD_PUT
Definition: microhttpd.h:1098
#define MHD_HTTP_METHOD_CONNECT
Definition: microhttpd.h:1086
#define MHD_HTTP_METHOD_DELETE
Definition: microhttpd.h:1088
enum MHD_Result(* MHD_KeyValueIterator)(void *cls, enum MHD_ValueKind kind, const char *key, const char *value)
Definition: microhttpd.h:2518
_MHD_EXTERN int MHD_get_connection_values_n(struct MHD_Connection *connection, enum MHD_ValueKind kind, MHD_KeyValueIteratorN iterator, void *iterator_cls)
Definition: connection.c:423
_MHD_EXTERN enum MHD_Result MHD_set_connection_value_n(struct MHD_Connection *connection, enum MHD_ValueKind kind, const char *key, size_t key_size, const char *value, size_t value_size)
Definition: connection.c:536
enum MHD_Result(* MHD_KeyValueIteratorN)(void *cls, enum MHD_ValueKind kind, const char *key, size_t key_size, const char *value, size_t value_size)
Definition: microhttpd.h:2543
static enum MHD_Result MHD_set_connection_value_n_nocheck_(struct MHD_Connection *connection, enum MHD_ValueKind kind, const char *key, size_t key_size, const char *value, size_t value_size)
Definition: connection.c:476
_MHD_EXTERN const char * MHD_lookup_connection_value(struct MHD_Connection *connection, enum MHD_ValueKind kind, const char *key)
Definition: connection.c:612
_MHD_EXTERN int MHD_get_connection_values(struct MHD_Connection *connection, enum MHD_ValueKind kind, MHD_KeyValueIterator iterator, void *iterator_cls)
Definition: connection.c:384
MHD_ConnectionInfoType
Definition: microhttpd.h:2200
_MHD_EXTERN enum MHD_Result MHD_set_connection_value(struct MHD_Connection *connection, enum MHD_ValueKind kind, const char *key, const char *value)
Definition: connection.c:583
_MHD_EXTERN enum MHD_Result MHD_lookup_connection_value_n(struct MHD_Connection *connection, enum MHD_ValueKind kind, const char *key, size_t key_size, const char **value_ptr, size_t *value_size_ptr)
Definition: connection.c:649
MHD_RequestTerminationCode
Definition: microhttpd.h:2029
@ MHD_CONNECTION_INFO_CONNECTION_TIMEOUT
Definition: microhttpd.h:2272
@ MHD_CONNECTION_INFO_SOCKET_CONTEXT
Definition: microhttpd.h:2260
@ MHD_CONNECTION_INFO_GNUTLS_SESSION
Definition: microhttpd.h:2228
@ MHD_CONNECTION_INFO_REQUEST_HEADER_SIZE
Definition: microhttpd.h:2278
@ MHD_CONNECTION_INFO_CIPHER_ALGO
Definition: microhttpd.h:2206
@ MHD_CONNECTION_INFO_CONNECTION_SUSPENDED
Definition: microhttpd.h:2266
@ MHD_CONNECTION_INFO_CLIENT_ADDRESS
Definition: microhttpd.h:2222
@ MHD_CONNECTION_INFO_DAEMON
Definition: microhttpd.h:2242
@ MHD_CONNECTION_INFO_HTTP_STATUS
Definition: microhttpd.h:2284
@ MHD_CONNECTION_INFO_CONNECTION_FD
Definition: microhttpd.h:2250
@ MHD_CONNECTION_INFO_PROTOCOL
Definition: microhttpd.h:2213
@ MHD_REQUEST_TERMINATED_TIMEOUT_REACHED
Definition: microhttpd.h:2052
@ MHD_REQUEST_TERMINATED_COMPLETED_OK
Definition: microhttpd.h:2035
@ MHD_REQUEST_TERMINATED_WITH_ERROR
Definition: microhttpd.h:2044
@ MHD_REQUEST_TERMINATED_READ_ERROR
Definition: microhttpd.h:2069
@ MHD_REQUEST_TERMINATED_CLIENT_ABORT
Definition: microhttpd.h:2076
_MHD_EXTERN struct MHD_Response * MHD_create_response_from_buffer(size_t size, void *buffer, enum MHD_ResponseMemoryMode mode)
Definition: response.c:1308
_MHD_EXTERN enum MHD_Result MHD_queue_response(struct MHD_Connection *connection, unsigned int status_code, struct MHD_Response *response)
Definition: connection.c:5099
_MHD_EXTERN void MHD_destroy_response(struct MHD_Response *response)
Definition: response.c:1948
@ MHD_RESPMEM_PERSISTENT
Definition: microhttpd.h:3447
_MHD_EXTERN const union MHD_ConnectionInfo * MHD_get_connection_info(struct MHD_Connection *connection, enum MHD_ConnectionInfoType info_type,...)
Definition: connection.c:4947
#define MHD_ICY_FLAG
Definition: microhttpd.h:570
_MHD_EXTERN enum MHD_Result MHD_set_connection_option(struct MHD_Connection *connection, enum MHD_CONNECTION_OPTION option,...)
Definition: connection.c:5011
#define MHD_HTTP_VERSION_1_0
Definition: microhttpd.h:1071
#define MHD_HTTP_VERSION_1_1
Definition: microhttpd.h:1072
bool MHD_parse_arguments_(struct MHD_Request *request, enum MHD_ValueKind kind, char *args, MHD_ArgumentIterator_ cb, unsigned int *num_headers)
Definition: internal.c:190
#define MHD_ERR_INVAL_
Definition: internal.h:1889
#define MHD_ERR_CONNRESET_
Definition: internal.h:1868
#define XDLL_insert(head, tail, element)
Definition: internal.h:1786
#define MHD_ERR_NOMEM_
Definition: internal.h:1879
MHD_PanicCallback mhd_panic
Definition: panic.c:31
MHD_EpollState
Definition: internal.h:588
@ MHD_EPOLL_STATE_SUSPENDED
Definition: internal.h:621
@ MHD_EPOLL_STATE_READ_READY
Definition: internal.h:600
@ MHD_EPOLL_STATE_IN_EPOLL_SET
Definition: internal.h:616
@ MHD_EPOLL_STATE_WRITE_READY
Definition: internal.h:606
#define DLL_insert(head, tail, element)
Definition: internal.h:1743
#define MHD_PANIC(msg)
Definition: internal.h:69
#define MHD_MIN(a, b)
Definition: internal.h:110
MHD_ConnKeepAlive
Definition: internal.h:155
@ MHD_CONN_USE_KEEPALIVE
Definition: internal.h:169
@ MHD_CONN_MUST_CLOSE
Definition: internal.h:159
@ MHD_CONN_KEEPALIVE_UNKOWN
Definition: internal.h:164
#define MHD_ERR_AGAIN_
Definition: internal.h:1863
#define MHD_BUF_INC_SIZE
Definition: internal.h:120
#define EDLL_remove(head, tail, element)
Definition: internal.h:1847
#define XDLL_remove(head, tail, element)
Definition: internal.h:1806
#define DLL_remove(head, tail, element)
Definition: internal.h:1763
void * mhd_panic_cls
Definition: panic.c:36
#define MHD_ERR_BADF_
Definition: internal.h:1884
#define MHD_ERR_NOTCONN_
Definition: internal.h:1874
void * MHD_pool_reallocate(struct MemoryPool *pool, void *old, size_t old_size, size_t new_size)
Definition: memorypool.c:248
void MHD_pool_destroy(struct MemoryPool *pool)
Definition: memorypool.c:157
size_t MHD_pool_get_free(struct MemoryPool *pool)
Definition: memorypool.c:185
void * MHD_pool_reset(struct MemoryPool *pool, void *keep, size_t copy_bytes, size_t new_size)
Definition: memorypool.c:314
void * MHD_pool_allocate(struct MemoryPool *pool, size_t size, int from_end)
Definition: memorypool.c:203
#define mhd_assert(CHK)
Definition: mhd_assert.h:39
#define UINT64_MAX
Definition: mhd_limits.h:81
#define SIZE_MAX
Definition: mhd_limits.h:99
#define MHD_mutex_unlock_chk_(pmutex)
Definition: mhd_locks.h:180
#define MHD_mutex_lock_chk_(pmutex)
Definition: mhd_locks.h:154
#define MHD_SCKT_ERR_IS_(err, code)
Definition: mhd_sockets.h:611
#define MHD_SCKT_ERR_IS_EAGAIN_(err)
Definition: mhd_sockets.h:643
#define MHD_SCKT_ERR_IS_LOW_RESOURCES_(err)
Definition: mhd_sockets.h:656
#define MHD_socket_last_strerr_()
Definition: mhd_sockets.h:549
#define MHD_SCKT_EOPNOTSUPP_
Definition: mhd_sockets.h:484
#define MHD_SCKT_EBADF_
Definition: mhd_sockets.h:454
#define MHD_socket_get_error_()
Definition: mhd_sockets.h:523
#define MHD_SCKT_ERR_IS_REMOTE_DISCNN_(err)
Definition: mhd_sockets.h:688
#define MHD_SCKT_EINVAL_
Definition: mhd_sockets.h:464
#define MHD_SCKT_ERR_IS_EINTR_(err)
Definition: mhd_sockets.h:634
#define MHD_SCKT_SEND_MAX_SIZE_
Definition: mhd_sockets.h:222
#define MHD_SCKT_ENOTCONN_
Definition: mhd_sockets.h:429
#define MHD_recv_(s, b, l)
Definition: mhd_sockets.h:273
int MHD_str_equal_caseless_(const char *str1, const char *str2)
Definition: mhd_str.c:346
size_t MHD_str_to_uint64_n_(const char *str, size_t maxlen, uint64_t *out_val)
Definition: mhd_str.c:515
size_t MHD_strx_to_uint64_n_(const char *str, size_t maxlen, uint64_t *out_val)
Definition: mhd_str.c:692
int MHD_str_equal_caseless_n_(const char *const str1, const char *const str2, size_t maxlen)
Definition: mhd_str.c:378
bool MHD_str_has_token_caseless_(const char *str, const char *const token, size_t token_len)
Definition: mhd_str.c:412
#define MHD_str_has_s_token_caseless_(str, tkn)
Definition: mhd_str.h:115
#define MHD_STATICSTR_LEN_(macro)
Definition: mhd_str.h:45
#define NULL
Definition: reason_phrase.c:30
#define _(String)
Definition: mhd_options.h:42
#define _MHD_EXTERN
Definition: mhd_options.h:50
ssize_t MHD_send_hdr_and_body_(struct MHD_Connection *connection, const char *header, size_t header_size, bool never_push_hdr, const char *body, size_t body_size, bool complete_response)
Definition: mhd_send.c:900
ssize_t MHD_send_iovec_(struct MHD_Connection *connection, struct MHD_iovec_track_ *const r_iov, bool push_data)
Definition: mhd_send.c:1613
ssize_t MHD_send_data_(struct MHD_Connection *connection, const char *buffer, size_t buffer_size, bool push_data)
Definition: mhd_send.c:749
Declarations of send() wrappers.
MHD internal shared structures.
MHD_CONNECTION_STATE
Definition: internal.h:574
@ MHD_CONNECTION_BODY_RECEIVED
Definition: internal.h:620
@ MHD_CONNECTION_HEADER_PART_RECEIVED
Definition: internal.h:595
@ MHD_CONNECTION_HEADERS_SENDING
Definition: internal.h:650
@ MHD_CONNECTION_FOOTERS_SENDING
Definition: internal.h:686
@ MHD_CONNECTION_FOOTERS_RECEIVED
Definition: internal.h:631
@ MHD_CONNECTION_HEADERS_SENT
Definition: internal.h:655
@ MHD_CONNECTION_HEADERS_PROCESSED
Definition: internal.h:605
@ MHD_CONNECTION_INIT
Definition: internal.h:579
@ MHD_CONNECTION_CLOSED
Definition: internal.h:696
@ MHD_CONNECTION_NORMAL_BODY_UNREADY
Definition: internal.h:661
@ MHD_CONNECTION_HEADERS_RECEIVED
Definition: internal.h:600
@ MHD_CONNECTION_NORMAL_BODY_READY
Definition: internal.h:666
@ MHD_CONNECTION_START_REPLY
Definition: internal.h:644
@ MHD_CONNECTION_CHUNKED_BODY_READY
Definition: internal.h:676
@ MHD_CONNECTION_FOOTER_PART_RECEIVED
Definition: internal.h:626
@ MHD_CONNECTION_CONTINUE_SENT
Definition: internal.h:615
@ MHD_CONNECTION_FOOTERS_SENT
Definition: internal.h:691
@ MHD_CONNECTION_FULL_REQ_RECEIVED
Definition: internal.h:637
@ MHD_CONNECTION_CHUNKED_BODY_UNREADY
Definition: internal.h:671
@ MHD_CONNECTION_BODY_SENT
Definition: internal.h:681
@ MHD_CONNECTION_CONTINUE_SENDING
Definition: internal.h:610
@ MHD_CONNECTION_URL_RECEIVED
Definition: internal.h:590
@ MHD_CONNECTION_REQ_LINE_RECEIVING
Definition: internal.h:585
@ MHD_TLS_CONN_NO_TLS
Definition: internal.h:714
@ MHD_TLS_CONN_INIT
Definition: internal.h:715
@ MHD_TLS_CONN_CONNECTED
Definition: internal.h:717
@ MHD_TLS_CONN_HANDSHAKING
Definition: internal.h:716
@ MHD_EVENT_LOOP_INFO_READ
Definition: internal.h:246
@ MHD_EVENT_LOOP_INFO_WRITE
Definition: internal.h:251
@ MHD_EVENT_LOOP_INFO_CLEANUP
Definition: internal.h:261
@ MHD_EVENT_LOOP_INFO_BLOCK
Definition: internal.h:256
struct MHD_IoVec MHD_iovec_
Definition: internal.h:401
#define MHD_IS_HTTP_VER_SUPPORTED(ver)
Definition: internal.h:835
@ MHD_RAF_HAS_DATE_HDR
Definition: internal.h:372
@ MHD_RAF_HAS_CONNECTION_CLOSE
Definition: internal.h:370
@ MHD_RAF_HAS_TRANS_ENC_CHUNKED
Definition: internal.h:371
@ MHD_RAF_HAS_CONNECTION_HDR
Definition: internal.h:369
@ MHD_HTTP_VER_1_0
Definition: internal.h:814
@ MHD_HTTP_VER_1_1
Definition: internal.h:819
@ MHD_HTTP_VER_TOO_OLD
Definition: internal.h:809
@ MHD_HTTP_VER_INVALID
Definition: internal.h:799
@ MHD_HTTP_VER_UNKNOWN
Definition: internal.h:804
@ MHD_HTTP_VER_1_2__1_9
Definition: internal.h:824
@ MHD_HTTP_VER_FUTURE
Definition: internal.h:829
@ MHD_CONN_MUST_UPGRADE
Definition: internal.h:791
#define MHD_IS_HTTP_VER_1_1_COMPAT(ver)
Definition: internal.h:844
@ MHD_HTTP_MTHD_GET
Definition: internal.h:861
@ MHD_HTTP_MTHD_CONNECT
Definition: internal.h:881
@ MHD_HTTP_MTHD_DELETE
Definition: internal.h:877
@ MHD_HTTP_MTHD_OPTIONS
Definition: internal.h:885
@ MHD_HTTP_MTHD_TRACE
Definition: internal.h:889
@ MHD_HTTP_MTHD_HEAD
Definition: internal.h:865
@ MHD_HTTP_MTHD_POST
Definition: internal.h:869
@ MHD_HTTP_MTHD_OTHER
Definition: internal.h:893
@ MHD_HTTP_MTHD_NO_METHOD
Definition: internal.h:857
@ MHD_HTTP_MTHD_PUT
Definition: internal.h:873
#define PRIu64
Definition: internal.h:53
void * MHD_pool_try_alloc(struct MemoryPool *pool, size_t size, size_t *required_bytes)
Definition: memorypool.c:373
memory pool; mostly used for efficient (de)allocation for each connection and bounding memory use for...
macros for mhd_assert()
Header for platform missing functions.
Header for platform-independent inter-thread communication.
limits values definitions
uint64_t MHD_monotonic_msec_counter(void)
internal monotonic clock functions implementations
#define MHD_SEND_SPIPE_SUPPRESS_NEEDED
Definition: mhd_sockets.h:942
size_t MHD_uint8_to_str_pad(uint8_t val, uint8_t min_digits, char *buf, size_t buf_size)
Definition: mhd_str.c:1313
size_t MHD_uint16_to_str(uint16_t val, char *buf, size_t buf_size)
Definition: mhd_str.c:1234
size_t MHD_uint64_to_str(uint64_t val, char *buf, size_t buf_size)
Definition: mhd_str.c:1275
bool MHD_str_equal_caseless_bin_n_(const char *const str1, const char *const str2, size_t len)
Definition: mhd_str.c:445
size_t MHD_uint32_to_strx(uint32_t val, char *buf, size_t buf_size)
Definition: mhd_str.c:1202
Header for string manipulating helpers.
void MHD_increment_response_rc(struct MHD_Response *response)
Definition: response.c:1994
#define MHD_SIZE_UNKNOWN
Definition: microhttpd.h:184
MHD_Result
Definition: microhttpd.h:158
@ MHD_YES
Definition: microhttpd.h:167
@ MHD_NO
Definition: microhttpd.h:162
#define MHD_CONTENT_READER_END_OF_STREAM
Definition: microhttpd.h:187
_MHD_EXTERN size_t MHD_get_reason_phrase_len_for(unsigned int code)
#define MHD_INVALID_SOCKET
Definition: microhttpd.h:208
_MHD_EXTERN const char * MHD_get_reason_phrase_for(unsigned int code)
#define MHD_CONTENT_READER_END_WITH_ERROR
Definition: microhttpd.h:188
MHD_ValueKind
Definition: microhttpd.h:1978
@ MHD_FOOTER_KIND
Definition: microhttpd.h:2019
@ MHD_COOKIE_KIND
Definition: microhttpd.h:1999
@ MHD_HEADER_KIND
Definition: microhttpd.h:1993
@ MHD_GET_ARGUMENT_KIND
Definition: microhttpd.h:2014
@ MHD_USE_EPOLL
Definition: microhttpd.h:1369
@ MHD_USE_THREAD_PER_CONNECTION
Definition: microhttpd.h:1261
@ MHD_USE_TURBO
Definition: microhttpd.h:1440
@ MHD_USE_SUPPRESS_DATE_NO_CLOCK
Definition: microhttpd.h:1342
@ MHD_USE_TLS
Definition: microhttpd.h:1246
@ MHD_ALLOW_UPGRADE
Definition: microhttpd.h:1478
@ MHD_USE_ERROR_LOG
Definition: microhttpd.h:1235
@ MHD_USE_INTERNAL_POLLING_THREAD
Definition: microhttpd.h:1273
@ MHD_RF_SEND_KEEP_ALIVE_HEADER
Definition: microhttpd.h:3357
@ MHD_RF_HTTP_1_0_COMPATIBLE_STRICT
Definition: microhttpd.h:3316
@ MHD_RF_HTTP_1_0_SERVER
Definition: microhttpd.h:3337
MHD_CONNECTION_OPTION
Definition: microhttpd.h:4325
@ MHD_CONNECTION_OPTION_TIMEOUT
Definition: microhttpd.h:4336
Methods for managing response objects.
enum MHD_Result MHD_response_execute_upgrade_(struct MHD_Response *response, struct MHD_Connection *connection)
MHD_socket socket_fd
Definition: internal.h:752
enum MHD_HTTP_Method http_mthd
Definition: internal.h:1005
size_t write_buffer_size
Definition: internal.h:1091
size_t write_buffer_send_offset
Definition: internal.h:1096
struct MHD_Reply_Properties rp_props
Definition: internal.h:1279
enum MHD_HTTP_Version http_ver
Definition: internal.h:1022
enum MHD_ConnectionEventLoopInfo event_loop_info
Definition: internal.h:1268
size_t write_buffer_append_offset
Definition: internal.h:1102
char * write_buffer
Definition: internal.h:1042
bool stop_with_error
Definition: internal.h:1224
uint64_t remaining_upload_size
Definition: internal.h:1114
void * socket_context
Definition: internal.h:694
bool discard_request
Definition: internal.h:1233
bool suspended
Definition: internal.h:764
ReceiveCallback recv_cls
Definition: internal.h:706
char * colon
Definition: internal.h:1059
size_t header_size
Definition: internal.h:1108
struct MHD_Response * response
Definition: internal.h:968
const char * url
Definition: internal.h:1011
char * version
Definition: internal.h:1017
bool sk_nonblck
Definition: internal.h:784
enum MHD_ConnKeepAlive keepalive
Definition: internal.h:1029
struct MHD_HTTP_Header * headers_received
Definition: internal.h:958
size_t continue_message_write_offset
Definition: internal.h:1144
uint64_t response_write_position
Definition: internal.h:1121
struct sockaddr_storage addr
Definition: internal.h:728
struct MHD_HTTP_Header * headers_received_tail
Definition: internal.h:963
char * method
Definition: internal.h:1000
uint64_t current_chunk_offset
Definition: internal.h:1306
struct MemoryPool * pool
Definition: internal.h:685
size_t read_buffer_offset
Definition: internal.h:1086
uint64_t current_chunk_size
Definition: internal.h:1300
int suspended_dummy
Definition: internal.h:1360
bool client_aware
Definition: internal.h:1174
struct MHD_iovec_track_ resp_iov
Definition: internal.h:1129
unsigned int responseCode
Definition: internal.h:1274
MHD_thread_handle_ID_ pid
Definition: internal.h:723
bool have_chunked_upload
Definition: internal.h:1291
bool read_closed
Definition: internal.h:792
time_t last_activity
Definition: internal.h:739
void * client_context
Definition: internal.h:986
enum MHD_CONNECTION_STATE state
Definition: internal.h:1263
char * read_buffer
Definition: internal.h:1036
struct MHD_Daemon * daemon
Definition: internal.h:675
unsigned int connection_timeout_dummy
Definition: internal.h:1167
bool sk_spipe_suppress
Definition: internal.h:1197
uint64_t connection_timeout_ms
Definition: internal.h:1162
size_t read_buffer_size
Definition: internal.h:1080
size_t pool_size
Definition: internal.h:1875
MHD_AccessHandlerCallback default_handler
Definition: internal.h:1606
LogCallback uri_log_callback
Definition: internal.h:1796
void * unescape_callback_cls
Definition: internal.h:1811
MHD_mutex_ cleanup_connection_mutex
Definition: internal.h:1265
struct MHD_Connection * connections_head
Definition: internal.h:1155
MHD_RequestCompletedCallback notify_completed
Definition: internal.h:1771
struct MHD_itc_ itc
Definition: internal.h:1410
uint64_t connection_timeout_ms
Definition: internal.h:1992
struct MHD_Connection * manual_timeout_tail
Definition: internal.h:1150
volatile bool shutdown
Definition: internal.h:1526
enum MHD_FLAG options
Definition: internal.h:1619
bool sigpipe_blocked
Definition: internal.h:2008
UnescapeCallback unescape_callback
Definition: internal.h:1806
void * notify_completed_cls
Definition: internal.h:1776
struct MHD_Connection * cleanup_tail
Definition: internal.h:1182
MHD_thread_handle_ID_ pid
Definition: internal.h:1249
struct MHD_Connection * manual_timeout_head
Definition: internal.h:1143
void * default_handler_cls
Definition: internal.h:1611
struct MHD_Connection * suspended_connections_tail
Definition: internal.h:1172
struct MHD_Connection * cleanup_head
Definition: internal.h:1177
struct MHD_Connection * normal_timeout_head
Definition: internal.h:1128
struct MHD_Connection * normal_timeout_tail
Definition: internal.h:1135
size_t pool_increment
Definition: internal.h:1880
void * uri_log_callback_cls
Definition: internal.h:1801
struct MHD_Connection * suspended_connections_head
Definition: internal.h:1166
struct MHD_Connection * connections_tail
Definition: internal.h:1160
int strict_for_client
Definition: internal.h:2003
size_t value_size
Definition: internal.h:352
char * header
Definition: internal.h:347
enum MHD_ValueKind kind
Definition: internal.h:358
size_t header_size
Definition: internal.h:342
struct MHD_HTTP_Header * next
Definition: internal.h:342
char * value
Definition: internal.h:352
bool use_reply_body_headers
Definition: internal.h:903
struct MHD_HTTP_Header * first_header
Definition: internal.h:1582
void * crc_cls
Definition: internal.h:1594
size_t data_buffer_size
Definition: internal.h:1664
MHD_iovec_ * data_iov
Definition: internal.h:549
enum MHD_HTTP_StatusCode status_code
Definition: internal.h:1669
uint64_t data_start
Definition: internal.h:1648
MHD_ContentReaderCallback crc
Definition: internal.h:1600
bool is_pipe
Definition: internal.h:544
enum MHD_ResponseAutoFlags flags_auto
Definition: internal.h:539
unsigned int data_iovcnt
Definition: internal.h:554
size_t data_size
Definition: internal.h:1659
enum MHD_ResponseFlags flags
Definition: internal.h:534
char * data
Definition: internal.h:1588
MHD_mutex_ mutex
Definition: internal.h:1637
uint64_t total_size
Definition: internal.h:1642
MHD_iovec_ * iov
Definition: internal.h:414