GNU libmicrohttpd 0.9.77
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 mhd_assert (! connection->suspended);
837#ifdef MHD_USE_THREADS
838 mhd_assert ( (0 == (daemon->options & MHD_USE_INTERNAL_POLLING_THREAD)) || \
839 MHD_thread_ID_match_current_ (connection->pid) );
840#endif /* MHD_USE_THREADS */
841 if ( (NULL != daemon->notify_completed) &&
842 (connection->client_aware) )
843 daemon->notify_completed (daemon->notify_completed_cls,
844 connection,
845 &connection->client_context,
846 termination_code);
847 connection->client_aware = false;
848 if (NULL != resp)
849 {
850 connection->response = NULL;
852 }
853 if (NULL != connection->pool)
854 {
855 MHD_pool_destroy (connection->pool);
856 connection->pool = NULL;
857 }
858
859 MHD_connection_mark_closed_ (connection);
860}
861
862
863#if defined(HTTPS_SUPPORT) && defined(UPGRADE_SUPPORT)
874void
876{
877 struct MHD_Daemon *daemon = connection->daemon;
878 struct MHD_UpgradeResponseHandle *urh = connection->urh;
879
880#ifdef MHD_USE_THREADS
881 mhd_assert ( (0 == (daemon->options & MHD_USE_INTERNAL_POLLING_THREAD)) || \
882 (0 != (daemon->options & MHD_USE_THREAD_PER_CONNECTION)) || \
883 MHD_thread_ID_match_current_ (daemon->pid) );
884#endif /* MHD_USE_THREADS */
885
886 if (0 == (daemon->options & MHD_USE_TLS))
887 return; /* Nothing to do with non-TLS connection. */
888
889 if (0 == (daemon->options & MHD_USE_THREAD_PER_CONNECTION))
890 DLL_remove (daemon->urh_head,
891 daemon->urh_tail,
892 urh);
893#if EPOLL_SUPPORT
894 if ( (0 != (daemon->options & MHD_USE_EPOLL)) &&
895 (0 != epoll_ctl (daemon->epoll_upgrade_fd,
896 EPOLL_CTL_DEL,
897 connection->socket_fd,
898 NULL)) )
899 {
900 MHD_PANIC (_ ("Failed to remove FD from epoll set.\n"));
901 }
902 if (urh->in_eready_list)
903 {
904 EDLL_remove (daemon->eready_urh_head,
905 daemon->eready_urh_tail,
906 urh);
907 urh->in_eready_list = false;
908 }
909#endif /* EPOLL_SUPPORT */
910 if (MHD_INVALID_SOCKET != urh->mhd.socket)
911 {
912#if EPOLL_SUPPORT
913 if ( (0 != (daemon->options & MHD_USE_EPOLL)) &&
914 (0 != epoll_ctl (daemon->epoll_upgrade_fd,
915 EPOLL_CTL_DEL,
916 urh->mhd.socket,
917 NULL)) )
918 {
919 MHD_PANIC (_ ("Failed to remove FD from epoll set.\n"));
920 }
921#endif /* EPOLL_SUPPORT */
922 /* Reflect remote disconnect to application by breaking
923 * socketpair connection. */
924 shutdown (urh->mhd.socket, SHUT_RDWR);
925 }
926 /* Socketpair sockets will remain open as they will be
927 * used with MHD_UPGRADE_ACTION_CLOSE. They will be
928 * closed by cleanup_upgraded_connection() during
929 * connection's final cleanup.
930 */
931}
932
933
934#endif /* HTTPS_SUPPORT && UPGRADE_SUPPORT*/
935
936
944static void
946 const char *emsg)
947{
948 connection->stop_with_error = true;
949 connection->discard_request = true;
950#ifdef HAVE_MESSAGES
951 if (NULL != emsg)
952 MHD_DLOG (connection->daemon,
953 "%s\n",
954 emsg);
955#else /* ! HAVE_MESSAGES */
956 (void) emsg; /* Mute compiler warning. */
957#endif /* ! HAVE_MESSAGES */
958 MHD_connection_close_ (connection,
960}
961
962
967#ifdef HAVE_MESSAGES
968#define CONNECTION_CLOSE_ERROR(c, emsg) connection_close_error (c, emsg)
969#else
970#define CONNECTION_CLOSE_ERROR(c, emsg) connection_close_error (c, NULL)
971#endif
972
973
981static void
983 const char *emsg)
984{
985 if ( (NULL != connection->response) &&
986 (400 <= connection->responseCode) &&
987 (NULL == connection->response->crc) && /* Static response only! */
988 (connection->stop_with_error) &&
989 (MHD_CONNECTION_HEADERS_SENDING == connection->state) )
990 return; /* An error response was already queued */
991
992 connection_close_error (connection, emsg);
993}
994
995
1000#ifdef HAVE_MESSAGES
1001#define CONNECTION_CLOSE_ERROR_CHECK(c, emsg) \
1002 connection_close_error_check (c, emsg)
1003#else
1004#define CONNECTION_CLOSE_ERROR_CHECK(c, emsg) \
1005 connection_close_error_check (c, NULL)
1006#endif
1007
1008
1021static enum MHD_Result
1023{
1024 ssize_t ret;
1025 struct MHD_Response *response;
1026
1027 response = connection->response;
1028 mhd_assert (connection->rp_props.send_reply_body);
1029
1030 if ( (0 == response->total_size) ||
1031 /* TODO: replace the next check with assert */
1032 (connection->response_write_position == response->total_size) )
1033 return MHD_YES; /* 0-byte response is always ready */
1034 if (NULL != response->data_iov)
1035 {
1036 size_t copy_size;
1037
1038 if (NULL != connection->resp_iov.iov)
1039 return MHD_YES;
1040 copy_size = response->data_iovcnt * sizeof(MHD_iovec_);
1041 connection->resp_iov.iov = connection_alloc_memory (connection,
1042 copy_size);
1043 if (NULL == connection->resp_iov.iov)
1044 {
1045 MHD_mutex_unlock_chk_ (&response->mutex);
1046 /* not enough memory */
1047 CONNECTION_CLOSE_ERROR (connection,
1048 _ ("Closing connection (out of memory)."));
1049 return MHD_NO;
1050 }
1051 memcpy (connection->resp_iov.iov,
1052 response->data_iov,
1053 copy_size);
1054 connection->resp_iov.cnt = response->data_iovcnt;
1055 connection->resp_iov.sent = 0;
1056 return MHD_YES;
1057 }
1058 if (NULL == response->crc)
1059 return MHD_YES;
1060 if ( (response->data_start <=
1061 connection->response_write_position) &&
1062 (response->data_size + response->data_start >
1063 connection->response_write_position) )
1064 return MHD_YES; /* response already ready */
1065#if defined(_MHD_HAVE_SENDFILE)
1066 if (MHD_resp_sender_sendfile == connection->resp_sender)
1067 {
1068 /* will use sendfile, no need to bother response crc */
1069 return MHD_YES;
1070 }
1071#endif /* _MHD_HAVE_SENDFILE */
1072
1073 ret = response->crc (response->crc_cls,
1074 connection->response_write_position,
1075 response->data,
1076 (size_t) MHD_MIN ((uint64_t) response->data_buffer_size,
1077 response->total_size
1078 - connection->response_write_position));
1079 if (0 > 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 MHD_FUNC_,
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 *const last_value = connection->colon;
3473 const size_t last_value_len = strlen (last_value);
3474 mhd_assert (NULL != connection->last);
3475 mhd_assert (NULL != connection->colon);
3476
3477 if ( (' ' == line[0]) ||
3478 ('\t' == line[0]) )
3479 {
3480 /* This line is a continuation of the previous line */
3481 /* NOTE: this is a simplified implementation only for v0.9.77 */
3482 size_t num_to_replace = ((size_t) (line - last_value)) - last_value_len;
3483
3484 /* Only CRLF or LF should be between lines */
3485 mhd_assert ((2 == num_to_replace) || (1 == num_to_replace));
3486 /* Replace CRLF with spaces */
3487 last_value[last_value_len] = ' ';
3488 if (0 != --num_to_replace)
3489 last_value[last_value_len + 1] = ' ';
3490 return MHD_NO; /* possibly more than 2 lines... */
3491 }
3492 if (MHD_NO ==
3493 connection_add_header (connection,
3494 connection->last,
3495 strlen (connection->last),
3496 last_value,
3497 last_value_len,
3498 kind))
3499 {
3500 /* Error has been queued by connection_add_header() */
3501 return MHD_NO;
3502 }
3503 /* we still have the current line to deal with... */
3504 if (0 != line[0])
3505 {
3506 if (MHD_NO == process_header_line (connection,
3507 line))
3508 {
3512 return MHD_NO;
3513 }
3514 }
3515 return MHD_YES;
3516}
3517
3518
3526static void
3528{
3529 const char *clen;
3530 const char *enc;
3531 size_t val_len;
3532
3533 parse_cookie_header (connection);
3534 if ( (1 <= connection->daemon->strict_for_client) &&
3535 (MHD_IS_HTTP_VER_1_1_COMPAT (connection->http_ver)) &&
3536 (MHD_NO ==
3542 NULL,
3543 NULL)) )
3544 {
3545#ifdef HAVE_MESSAGES
3546 MHD_DLOG (connection->daemon,
3547 _ ("Received HTTP/1.1 request without `Host' header.\n"));
3548#endif
3552 return;
3553 }
3554
3555 connection->remaining_upload_size = 0;
3556 if (MHD_NO != MHD_lookup_connection_value_n (connection,
3561 &enc,
3562 NULL))
3563 {
3565 if (MHD_str_equal_caseless_ (enc,
3566 "chunked"))
3567 connection->have_chunked_upload = true;
3568 }
3569 else
3570 {
3571 if (MHD_NO != MHD_lookup_connection_value_n (connection,
3576 &clen,
3577 &val_len))
3578 {
3579 size_t num_digits;
3580
3581 num_digits = MHD_str_to_uint64_n_ (clen,
3582 val_len,
3583 &connection->remaining_upload_size);
3584 if ( (val_len != num_digits) ||
3585 (0 == num_digits) )
3586 {
3587 connection->remaining_upload_size = 0;
3588 if ((0 == num_digits) &&
3589 (0 != val_len) &&
3590 ('0' <= clen[0]) && ('9' >= clen[0]))
3591 {
3592#ifdef HAVE_MESSAGES
3593 MHD_DLOG (connection->daemon,
3594 _ ("Too large value of 'Content-Length' header. " \
3595 "Closing connection.\n"));
3596#endif
3600 }
3601 else
3602 {
3603#ifdef HAVE_MESSAGES
3604 MHD_DLOG (connection->daemon,
3605 _ ("Failed to parse `Content-Length' header. " \
3606 "Closing connection.\n"));
3607#endif
3611 }
3612 }
3613 }
3614 }
3615}
3616
3617
3625void
3627{
3628 struct MHD_Daemon *daemon = connection->daemon;
3629
3630 if (0 == connection->connection_timeout_ms)
3631 return; /* Skip update of activity for connections
3632 without timeout timer. */
3633 if (connection->suspended)
3634 return; /* no activity on suspended connections */
3635
3637 if (0 != (daemon->options & MHD_USE_THREAD_PER_CONNECTION))
3638 return; /* each connection has personal timeout */
3639
3640 if (connection->connection_timeout_ms != daemon->connection_timeout_ms)
3641 return; /* custom timeout, no need to move it in "normal" DLL */
3642#if defined(MHD_USE_POSIX_THREADS) || defined(MHD_USE_W32_THREADS)
3644#endif
3645 /* move connection to head of timeout list (by remove + add operation) */
3647 daemon->normal_timeout_tail,
3648 connection);
3650 daemon->normal_timeout_tail,
3651 connection);
3652#if defined(MHD_USE_POSIX_THREADS) || defined(MHD_USE_W32_THREADS)
3654#endif
3655}
3656
3657
3667void
3669 bool socket_error)
3670{
3671 ssize_t bytes_read;
3672
3673 if ( (MHD_CONNECTION_CLOSED == connection->state) ||
3674 (connection->suspended) )
3675 return;
3676#ifdef HTTPS_SUPPORT
3677 if (MHD_TLS_CONN_NO_TLS != connection->tls_state)
3678 { /* HTTPS connection. */
3679 if (MHD_TLS_CONN_CONNECTED > connection->tls_state)
3680 {
3681 if (! MHD_run_tls_handshake_ (connection))
3682 return;
3683 }
3684 }
3685#endif /* HTTPS_SUPPORT */
3686
3687 /* make sure "read" has a reasonable number of bytes
3688 in buffer to use per system call (if possible) */
3689 if (connection->read_buffer_offset + connection->daemon->pool_increment >
3690 connection->read_buffer_size)
3691 try_grow_read_buffer (connection,
3692 (connection->read_buffer_size ==
3693 connection->read_buffer_offset));
3694
3695 if (connection->read_buffer_size == connection->read_buffer_offset)
3696 return; /* No space for receiving data. */
3697 bytes_read = connection->recv_cls (connection,
3698 &connection->read_buffer
3699 [connection->read_buffer_offset],
3700 connection->read_buffer_size
3701 - connection->read_buffer_offset);
3702 if ((bytes_read < 0) || socket_error)
3703 {
3704 if ((MHD_ERR_AGAIN_ == bytes_read) && ! socket_error)
3705 return; /* No new data to process. */
3706 if ((bytes_read > 0) && connection->sk_nonblck)
3707 { /* Try to detect the socket error */
3708 int dummy;
3709 bytes_read = connection->recv_cls (connection, &dummy, sizeof (dummy));
3710 }
3711 if (MHD_ERR_CONNRESET_ == bytes_read)
3712 {
3713 if ( (MHD_CONNECTION_INIT < connection->state) &&
3714 (MHD_CONNECTION_FULL_REQ_RECEIVED > connection->state) )
3715 {
3716#ifdef HAVE_MESSAGES
3717 MHD_DLOG (connection->daemon,
3718 _ ("Socket has been disconnected when reading request.\n"));
3719#endif
3720 connection->discard_request = true;
3721 }
3722 MHD_connection_close_ (connection,
3724 return;
3725 }
3726
3727#ifdef HAVE_MESSAGES
3728 if (MHD_CONNECTION_INIT != connection->state)
3729 MHD_DLOG (connection->daemon,
3730 _ ("Connection socket is closed when reading " \
3731 "request due to the error: %s\n"),
3732 (bytes_read < 0) ? str_conn_error_ (bytes_read) :
3733 "detected connection closure");
3734#endif
3735 CONNECTION_CLOSE_ERROR (connection,
3736 NULL);
3737 return;
3738 }
3739
3740 if (0 == bytes_read)
3741 { /* Remote side closed connection. */
3742 connection->read_closed = true;
3743 if ( (MHD_CONNECTION_INIT < connection->state) &&
3744 (MHD_CONNECTION_FULL_REQ_RECEIVED > connection->state) )
3745 {
3746#ifdef HAVE_MESSAGES
3747 MHD_DLOG (connection->daemon,
3748 _ ("Connection was closed by remote side with incomplete "
3749 "request.\n"));
3750#endif
3751 connection->discard_request = true;
3752 MHD_connection_close_ (connection,
3754 }
3755 else if (MHD_CONNECTION_INIT == connection->state)
3756 /* This termination code cannot be reported to the application
3757 * because application has not been informed yet about this request */
3758 MHD_connection_close_ (connection,
3760 else
3761 MHD_connection_close_ (connection,
3763 return;
3764 }
3765 connection->read_buffer_offset += bytes_read;
3766 MHD_update_last_activity_ (connection);
3767#if DEBUG_STATES
3768 MHD_DLOG (connection->daemon,
3769 _ ("In function %s handling connection at state: %s\n"),
3770 MHD_FUNC_,
3771 MHD_state_to_string (connection->state));
3772#endif
3773 switch (connection->state)
3774 {
3785 /* nothing to do but default action */
3786 if (connection->read_closed)
3787 {
3788 /* TODO: check whether this really needed */
3789 MHD_connection_close_ (connection,
3791 }
3792 return;
3794 return;
3795#ifdef UPGRADE_SUPPORT
3796 case MHD_CONNECTION_UPGRADE:
3797 mhd_assert (0);
3798 return;
3799#endif /* UPGRADE_SUPPORT */
3800 default:
3801 /* shrink read buffer to how much is actually used */
3802 if ((0 != connection->read_buffer_size) &&
3803 (connection->read_buffer_size != connection->read_buffer_offset))
3804 {
3805 mhd_assert (NULL != connection->read_buffer);
3806 connection->read_buffer =
3807 MHD_pool_reallocate (connection->pool,
3808 connection->read_buffer,
3809 connection->read_buffer_size,
3810 connection->read_buffer_offset);
3811 connection->read_buffer_size = connection->read_buffer_offset;
3812 }
3813 break;
3814 }
3815 return;
3816}
3817
3818
3825void
3827{
3828 struct MHD_Response *response;
3829 ssize_t ret;
3830 if (connection->suspended)
3831 return;
3832
3833#ifdef HTTPS_SUPPORT
3834 if (MHD_TLS_CONN_NO_TLS != connection->tls_state)
3835 { /* HTTPS connection. */
3836 if (MHD_TLS_CONN_CONNECTED > connection->tls_state)
3837 {
3838 if (! MHD_run_tls_handshake_ (connection))
3839 return;
3840 }
3841 }
3842#endif /* HTTPS_SUPPORT */
3843
3844#if DEBUG_STATES
3845 MHD_DLOG (connection->daemon,
3846 _ ("In function %s handling connection at state: %s\n"),
3847 MHD_FUNC_,
3848 MHD_state_to_string (connection->state));
3849#endif
3850 switch (connection->state)
3851 {
3857 mhd_assert (0);
3858 return;
3860 return;
3862 ret = MHD_send_data_ (connection,
3864 [connection->continue_message_write_offset],
3866 - connection->continue_message_write_offset,
3867 true);
3868 if (ret < 0)
3869 {
3870 if (MHD_ERR_AGAIN_ == ret)
3871 return;
3872#ifdef HAVE_MESSAGES
3873 MHD_DLOG (connection->daemon,
3874 _ ("Failed to send data in request for %s.\n"),
3875 connection->url);
3876#endif
3877 CONNECTION_CLOSE_ERROR (connection,
3878 NULL);
3879 return;
3880 }
3881#if _MHD_DEBUG_SEND_DATA
3882 fprintf (stderr,
3883 _ ("Sent 100 continue response: `%.*s'\n"),
3884 (int) ret,
3886#endif
3887 connection->continue_message_write_offset += ret;
3888 MHD_update_last_activity_ (connection);
3889 return;
3896 mhd_assert (0);
3897 return;
3899 {
3900 struct MHD_Response *const resp = connection->response;
3901 const size_t wb_ready = connection->write_buffer_append_offset
3902 - connection->write_buffer_send_offset;
3903 mhd_assert (connection->write_buffer_append_offset >= \
3904 connection->write_buffer_send_offset);
3905 mhd_assert (NULL != resp);
3906 mhd_assert ( (0 == resp->data_size) || \
3907 (0 == resp->data_start) || \
3908 (NULL != resp->crc) );
3909 mhd_assert ( (0 == connection->response_write_position) || \
3910 (resp->total_size ==
3911 connection->response_write_position) || \
3913 connection->response_write_position) );
3914 mhd_assert ((MHD_CONN_MUST_UPGRADE != connection->keepalive) || \
3915 (! connection->rp_props.send_reply_body));
3916
3917 if ( (connection->rp_props.send_reply_body) &&
3918 (NULL == resp->crc) &&
3919 (NULL == resp->data_iov) &&
3920 /* TODO: remove the next check as 'send_reply_body' is used */
3921 (0 == connection->response_write_position) &&
3922 (! connection->rp_props.chunked) )
3923 {
3924 mhd_assert (resp->total_size >= resp->data_size);
3925 mhd_assert (0 == resp->data_start);
3926 /* Send response headers alongside the response body, if the body
3927 * data is available. */
3928 ret = MHD_send_hdr_and_body_ (connection,
3929 &connection->write_buffer
3930 [connection->write_buffer_send_offset],
3931 wb_ready,
3932 false,
3933 resp->data,
3934 resp->data_size,
3935 (resp->total_size == resp->data_size));
3936 }
3937 else
3938 {
3939 /* This is response for HEAD request or reply body is not allowed
3940 * for any other reason or reply body is dynamically generated. */
3941 /* Do not send the body data even if it's available. */
3942 ret = MHD_send_hdr_and_body_ (connection,
3943 &connection->write_buffer
3944 [connection->write_buffer_send_offset],
3945 wb_ready,
3946 false,
3947 NULL,
3948 0,
3949 ((0 == resp->total_size) ||
3950 (! connection->rp_props.send_reply_body)
3951 ));
3952 }
3953
3954 if (ret < 0)
3955 {
3956 if (MHD_ERR_AGAIN_ == ret)
3957 return;
3958#ifdef HAVE_MESSAGES
3959 MHD_DLOG (connection->daemon,
3960 _ ("Failed to send the response headers for the " \
3961 "request for `%s'. Error: %s\n"),
3962 connection->url,
3963 str_conn_error_ (ret));
3964#endif
3965 CONNECTION_CLOSE_ERROR (connection,
3966 NULL);
3967 return;
3968 }
3969 /* 'ret' is not negative, it's safe to cast it to 'size_t'. */
3970 if (((size_t) ret) > wb_ready)
3971 {
3972 /* The complete header and some response data have been sent,
3973 * update both offsets. */
3974 mhd_assert (0 == connection->response_write_position);
3975 mhd_assert (! connection->rp_props.chunked);
3976 mhd_assert (connection->rp_props.send_reply_body);
3977 connection->write_buffer_send_offset += wb_ready;
3978 connection->response_write_position = ret - wb_ready;
3979 }
3980 else
3981 connection->write_buffer_send_offset += ret;
3982 MHD_update_last_activity_ (connection);
3983 if (MHD_CONNECTION_HEADERS_SENDING != connection->state)
3984 return;
3985 check_write_done (connection,
3987 return;
3988 }
3990 return;
3992 response = connection->response;
3993 if (connection->response_write_position <
3994 connection->response->total_size)
3995 {
3996 uint64_t data_write_offset;
3997
3998#if defined(MHD_USE_POSIX_THREADS) || defined(MHD_USE_W32_THREADS)
3999 if (NULL != response->crc)
4000 MHD_mutex_lock_chk_ (&response->mutex);
4001#endif
4002 if (MHD_NO == try_ready_normal_body (connection))
4003 {
4004 /* mutex was already unlocked by try_ready_normal_body */
4005 return;
4006 }
4007#if defined(_MHD_HAVE_SENDFILE)
4008 if (MHD_resp_sender_sendfile == connection->resp_sender)
4009 {
4010 mhd_assert (NULL == response->data_iov);
4011 ret = MHD_send_sendfile_ (connection);
4012 }
4013 else /* combined with the next 'if' */
4014#endif /* _MHD_HAVE_SENDFILE */
4015 if (NULL != response->data_iov)
4016 {
4017 ret = MHD_send_iovec_ (connection,
4018 &connection->resp_iov,
4019 true);
4020 }
4021 else
4022 {
4023 data_write_offset = connection->response_write_position
4024 - response->data_start;
4025 if (data_write_offset > (uint64_t) SIZE_MAX)
4026 MHD_PANIC (_ ("Data offset exceeds limit.\n"));
4027 ret = MHD_send_data_ (connection,
4028 &response->data
4029 [(size_t) data_write_offset],
4030 response->data_size
4031 - (size_t) data_write_offset,
4032 true);
4033#if _MHD_DEBUG_SEND_DATA
4034 if (ret > 0)
4035 fprintf (stderr,
4036 _ ("Sent %d-byte DATA response: `%.*s'\n"),
4037 (int) ret,
4038 (int) ret,
4039 &response->data[connection->response_write_position
4040 - response->data_start]);
4041#endif
4042 }
4043#if defined(MHD_USE_POSIX_THREADS) || defined(MHD_USE_W32_THREADS)
4044 if (NULL != response->crc)
4045 MHD_mutex_unlock_chk_ (&response->mutex);
4046#endif
4047 if (ret < 0)
4048 {
4049 if (MHD_ERR_AGAIN_ == ret)
4050 return;
4051#ifdef HAVE_MESSAGES
4052 MHD_DLOG (connection->daemon,
4053 _ ("Failed to send the response body for the " \
4054 "request for `%s'. Error: %s\n"),
4055 connection->url,
4056 str_conn_error_ (ret));
4057#endif
4058 CONNECTION_CLOSE_ERROR (connection,
4059 NULL);
4060 return;
4061 }
4062 connection->response_write_position += ret;
4063 MHD_update_last_activity_ (connection);
4064 }
4065 if (connection->response_write_position ==
4066 connection->response->total_size)
4067 connection->state = MHD_CONNECTION_FOOTERS_SENT; /* have no footers */
4068 return;
4070 mhd_assert (0);
4071 return;
4073 ret = MHD_send_data_ (connection,
4074 &connection->write_buffer
4075 [connection->write_buffer_send_offset],
4076 connection->write_buffer_append_offset
4077 - connection->write_buffer_send_offset,
4078 true);
4079 if (ret < 0)
4080 {
4081 if (MHD_ERR_AGAIN_ == ret)
4082 return;
4083#ifdef HAVE_MESSAGES
4084 MHD_DLOG (connection->daemon,
4085 _ ("Failed to send the chunked response body for the " \
4086 "request for `%s'. Error: %s\n"),
4087 connection->url,
4088 str_conn_error_ (ret));
4089#endif
4090 CONNECTION_CLOSE_ERROR (connection,
4091 NULL);
4092 return;
4093 }
4094 connection->write_buffer_send_offset += ret;
4095 MHD_update_last_activity_ (connection);
4096 if (MHD_CONNECTION_CHUNKED_BODY_READY != connection->state)
4097 return;
4098 check_write_done (connection,
4099 (connection->response->total_size ==
4100 connection->response_write_position) ?
4103 return;
4106 mhd_assert (0);
4107 return;
4109 ret = MHD_send_data_ (connection,
4110 &connection->write_buffer
4111 [connection->write_buffer_send_offset],
4112 connection->write_buffer_append_offset
4113 - connection->write_buffer_send_offset,
4114 true);
4115 if (ret < 0)
4116 {
4117 if (MHD_ERR_AGAIN_ == ret)
4118 return;
4119#ifdef HAVE_MESSAGES
4120 MHD_DLOG (connection->daemon,
4121 _ ("Failed to send the footers for the " \
4122 "request for `%s'. Error: %s\n"),
4123 connection->url,
4124 str_conn_error_ (ret));
4125#endif
4126 CONNECTION_CLOSE_ERROR (connection,
4127 NULL);
4128 return;
4129 }
4130 connection->write_buffer_send_offset += ret;
4131 MHD_update_last_activity_ (connection);
4132 if (MHD_CONNECTION_FOOTERS_SENDING != connection->state)
4133 return;
4134 check_write_done (connection,
4136 return;
4138 mhd_assert (0);
4139 return;
4141 return;
4142#ifdef UPGRADE_SUPPORT
4143 case MHD_CONNECTION_UPGRADE:
4144 mhd_assert (0);
4145 return;
4146#endif /* UPGRADE_SUPPORT */
4147 default:
4148 mhd_assert (0);
4149 CONNECTION_CLOSE_ERROR (connection,
4150 _ ("Internal error.\n"));
4151 break;
4152 }
4153 return;
4154}
4155
4156
4163static bool
4165{
4166 const uint64_t timeout = c->connection_timeout_ms;
4167 uint64_t now;
4168 uint64_t since_actv;
4169
4170 if (c->suspended)
4171 return false;
4172 if (0 == timeout)
4173 return false;
4175 since_actv = now - c->last_activity;
4176 /* Keep the next lines in sync with #connection_get_wait() to avoid
4177 * undesired side-effects like busy-waiting. */
4178 if (timeout < since_actv)
4179 {
4180 if (UINT64_MAX / 2 < since_actv)
4181 {
4182 const uint64_t jump_back = c->last_activity - now;
4183 /* Very unlikely that it is more than quarter-million years pause.
4184 * More likely that system clock jumps back. */
4185 if (5000 >= jump_back)
4186 {
4187#ifdef HAVE_MESSAGES
4188 MHD_DLOG (c->daemon,
4189 _ ("Detected system clock %u milliseconds jump back.\n"),
4190 (unsigned int) jump_back);
4191#endif
4192 return false;
4193 }
4194#ifdef HAVE_MESSAGES
4195 MHD_DLOG (c->daemon,
4196 _ ("Detected too large system clock %" PRIu64 " milliseconds "
4197 "jump back.\n"),
4198 jump_back);
4199#endif
4200 }
4201 return true;
4202 }
4203 return false;
4204}
4205
4206
4215static void
4217{
4218 struct MHD_Daemon *daemon = connection->daemon;
4219#ifdef MHD_USE_THREADS
4220 mhd_assert ( (0 == (daemon->options & MHD_USE_INTERNAL_POLLING_THREAD)) || \
4221 MHD_thread_ID_match_current_ (connection->pid) );
4222#endif /* MHD_USE_THREADS */
4223
4224 if (connection->in_cleanup)
4225 return; /* Prevent double cleanup. */
4226 connection->in_cleanup = true;
4227 if (NULL != connection->response)
4228 {
4229 MHD_destroy_response (connection->response);
4230 connection->response = NULL;
4231 }
4232#if defined(MHD_USE_POSIX_THREADS) || defined(MHD_USE_W32_THREADS)
4234#endif
4235 if (connection->suspended)
4236 {
4239 connection);
4240 connection->suspended = false;
4241 }
4242 else
4243 {
4244 if (0 == (daemon->options & MHD_USE_THREAD_PER_CONNECTION))
4245 {
4246 if (connection->connection_timeout_ms == daemon->connection_timeout_ms)
4248 daemon->normal_timeout_tail,
4249 connection);
4250 else
4252 daemon->manual_timeout_tail,
4253 connection);
4254 }
4256 daemon->connections_tail,
4257 connection);
4258 }
4259 DLL_insert (daemon->cleanup_head,
4260 daemon->cleanup_tail,
4261 connection);
4262 connection->resuming = false;
4263 connection->in_idle = false;
4264#if defined(MHD_USE_POSIX_THREADS) || defined(MHD_USE_W32_THREADS)
4266#endif
4267 if (0 != (daemon->options & MHD_USE_THREAD_PER_CONNECTION))
4268 {
4269 /* if we were at the connection limit before and are in
4270 thread-per-connection mode, signal the main thread
4271 to resume accepting connections */
4272 if ( (MHD_ITC_IS_VALID_ (daemon->itc)) &&
4273 (! MHD_itc_activate_ (daemon->itc, "c")) )
4274 {
4275#ifdef HAVE_MESSAGES
4276 MHD_DLOG (daemon,
4277 _ (
4278 "Failed to signal end of connection via inter-thread communication channel.\n"));
4279#endif
4280 }
4281 }
4282}
4283
4284
4291static void
4293 bool reuse)
4294{
4295 struct MHD_Connection *const c = connection;
4296 struct MHD_Daemon *const d = connection->daemon;
4297
4298 if (! reuse)
4299 {
4300 /* Next function will destroy response, notify client,
4301 * destroy memory pool, and set connection state to "CLOSED" */
4302 MHD_connection_close_ (connection,
4303 c->stop_with_error ?
4306 c->read_buffer = NULL;
4307 c->read_buffer_size = 0;
4308 c->read_buffer_offset = 0;
4309 c->write_buffer = NULL;
4310 c->write_buffer_size = 0;
4313 }
4314 else
4315 {
4316 /* Reset connection to process the next request */
4317 size_t new_read_buf_size;
4320
4321 if ( (NULL != d->notify_completed) &&
4322 (c->client_aware) )
4324 c,
4325 &c->client_context,
4327 c->client_aware = false;
4328
4329 if (NULL != c->response)
4331 c->response = NULL;
4332 c->version = NULL;
4334 c->last = NULL;
4335 c->colon = NULL;
4336 c->header_size = 0;
4338 /* Reset the read buffer to the starting size,
4339 preserving the bytes we have already read. */
4340 new_read_buf_size = c->daemon->pool_size / 2;
4341 if (c->read_buffer_offset > new_read_buf_size)
4342 new_read_buf_size = c->read_buffer_offset;
4343
4344 connection->read_buffer
4345 = MHD_pool_reset (c->pool,
4346 c->read_buffer,
4348 new_read_buf_size);
4349 c->read_buffer_size = new_read_buf_size;
4353 c->have_chunked_upload = false;
4354 c->current_chunk_size = 0;
4355 c->current_chunk_offset = 0;
4356 c->responseCode = 0;
4358 c->method = NULL;
4360 c->url = NULL;
4361 memset (&c->rp_props, 0, sizeof(c->rp_props));
4362 c->write_buffer = NULL;
4363 c->write_buffer_size = 0;
4366 /* iov (if any) was deallocated by MHD_pool_reset */
4367 memset (&connection->resp_iov, 0, sizeof(connection->resp_iov));
4369 }
4370 connection->client_context = NULL;
4371}
4372
4373
4384enum MHD_Result
4386{
4387 struct MHD_Daemon *daemon = connection->daemon;
4388 char *line;
4389 size_t line_len;
4390 enum MHD_Result ret;
4391#ifdef MHD_USE_THREADS
4392 mhd_assert ( (0 == (daemon->options & MHD_USE_INTERNAL_POLLING_THREAD)) || \
4393 MHD_thread_ID_match_current_ (connection->pid) );
4394#endif /* MHD_USE_THREADS */
4395 /* 'daemon' is not used if epoll is not available and asserts are disabled */
4396 (void) daemon; /* Mute compiler warning */
4397
4398 connection->in_idle = true;
4399 while (! connection->suspended)
4400 {
4401#ifdef HTTPS_SUPPORT
4402 if (MHD_TLS_CONN_NO_TLS != connection->tls_state)
4403 { /* HTTPS connection. */
4404 if ((MHD_TLS_CONN_INIT <= connection->tls_state) &&
4405 (MHD_TLS_CONN_CONNECTED > connection->tls_state))
4406 break;
4407 }
4408#endif /* HTTPS_SUPPORT */
4409#if DEBUG_STATES
4410 MHD_DLOG (daemon,
4411 _ ("In function %s handling connection at state: %s\n"),
4412 MHD_FUNC_,
4413 MHD_state_to_string (connection->state));
4414#endif
4415 switch (connection->state)
4416 {
4419 line = get_next_header_line (connection,
4420 &line_len);
4421 if (NULL != line)
4422 {
4423 /* Check for empty string, as we might want
4424 to tolerate 'spurious' empty lines */
4425 if (0 == line[0])
4426 {
4427 /* TODO: Add MHD option to not tolerate it */
4428 connection->state = MHD_CONNECTION_INIT;
4429 continue; /* Process the next line */
4430 }
4431 if (MHD_NO == parse_initial_message_line (connection,
4432 line,
4433 line_len))
4434 CONNECTION_CLOSE_ERROR_CHECK (connection,
4435 NULL);
4436 else
4437 {
4439 connection->state = MHD_CONNECTION_URL_RECEIVED;
4440 }
4441 continue;
4442 }
4443 /* NULL means we didn't get a full line yet */
4444 if (connection->discard_request)
4445 {
4446 mhd_assert (MHD_CONNECTION_INIT != connection->state);
4447 continue;
4448 }
4449 if (0 < connection->read_buffer_offset)
4451 break;
4453 line = get_next_header_line (connection,
4454 NULL);
4455 if (NULL == line)
4456 {
4457 if (MHD_CONNECTION_URL_RECEIVED != connection->state)
4458 continue;
4459 if (connection->read_closed)
4460 {
4461 CONNECTION_CLOSE_ERROR (connection,
4462 NULL);
4463 continue;
4464 }
4465 break;
4466 }
4467 if (0 == line[0])
4468 {
4470 connection->header_size = (size_t) (connection->read_buffer
4471 - connection->method);
4472 continue;
4473 }
4474 if (MHD_NO == process_header_line (connection,
4475 line))
4476 {
4480 break;
4481 }
4483 continue;
4485 line = get_next_header_line (connection,
4486 NULL);
4487 if (NULL == line)
4488 {
4489 if (connection->state != MHD_CONNECTION_HEADER_PART_RECEIVED)
4490 continue;
4491 if (connection->read_closed)
4492 {
4493 CONNECTION_CLOSE_ERROR (connection,
4494 NULL);
4495 continue;
4496 }
4497 break;
4498 }
4499 if (MHD_NO ==
4500 process_broken_line (connection,
4501 line,
4503 continue;
4504 if (0 == line[0])
4505 {
4507 connection->header_size = (size_t) (connection->read_buffer
4508 - connection->method);
4509 continue;
4510 }
4511 continue;
4513 parse_connection_headers (connection);
4514 if (MHD_CONNECTION_CLOSED == connection->state)
4515 continue;
4517 if (connection->suspended)
4518 break;
4519 continue;
4521 call_connection_handler (connection); /* first call */
4522 if (MHD_CONNECTION_CLOSED == connection->state)
4523 continue;
4524 if (connection->suspended)
4525 continue;
4526 if ( (NULL == connection->response) &&
4527 (need_100_continue (connection)) )
4528 {
4530 break;
4531 }
4532 if ( (NULL != connection->response) &&
4533 (0 != connection->remaining_upload_size) )
4534 {
4535 /* we refused (no upload allowed!) */
4536 connection->remaining_upload_size = 0;
4537 /* force close, in case client still tries to upload... */
4538 connection->discard_request = true;
4539 }
4540 connection->state = (0 == connection->remaining_upload_size)
4543 if (connection->suspended)
4544 break;
4545 continue;
4547 if (connection->continue_message_write_offset ==
4549 {
4550 connection->state = MHD_CONNECTION_CONTINUE_SENT;
4551 continue;
4552 }
4553 break;
4555 if (0 != connection->read_buffer_offset)
4556 {
4557 process_request_body (connection); /* loop call */
4558 if (connection->discard_request)
4559 {
4561 continue;
4562 }
4563 }
4564 if ( (0 == connection->remaining_upload_size) ||
4565 ( (MHD_SIZE_UNKNOWN == connection->remaining_upload_size) &&
4566 (0 == connection->read_buffer_offset) &&
4567 (connection->discard_request) ) )
4568 {
4569 if ( (connection->have_chunked_upload) &&
4570 (! connection->discard_request) )
4571 connection->state = MHD_CONNECTION_BODY_RECEIVED;
4572 else
4574 if (connection->suspended)
4575 break;
4576 continue;
4577 }
4578 break;
4580 line = get_next_header_line (connection,
4581 NULL);
4582 if (NULL == line)
4583 {
4584 if (connection->state != MHD_CONNECTION_BODY_RECEIVED)
4585 continue;
4586 if (connection->read_closed)
4587 {
4588 CONNECTION_CLOSE_ERROR (connection,
4589 NULL);
4590 continue;
4591 }
4592 if (0 < connection->read_buffer_offset)
4594 break;
4595 }
4596 if (0 == line[0])
4597 {
4599 if (connection->suspended)
4600 break;
4601 continue;
4602 }
4603 if (MHD_NO == process_header_line (connection,
4604 line))
4605 {
4609 break;
4610 }
4612 continue;
4614 line = get_next_header_line (connection,
4615 NULL);
4616 if (NULL == line)
4617 {
4618 if (connection->state != MHD_CONNECTION_FOOTER_PART_RECEIVED)
4619 continue;
4620 if (connection->read_closed)
4621 {
4622 CONNECTION_CLOSE_ERROR (connection,
4623 NULL);
4624 continue;
4625 }
4626 break;
4627 }
4628 if (MHD_NO ==
4629 process_broken_line (connection,
4630 line,
4632 continue;
4633 if (0 == line[0])
4634 {
4636 if (connection->suspended)
4637 break;
4638 continue;
4639 }
4640 continue;
4642 /* The header, the body, and the footers of the request has been received,
4643 * switch to the final processing of the request. */
4645 continue;
4647 call_connection_handler (connection); /* "final" call */
4648 if (connection->state == MHD_CONNECTION_CLOSED)
4649 continue;
4650 if (NULL == connection->response)
4651 break; /* try again next time */
4652 /* Response is ready, start reply */
4653 connection->state = MHD_CONNECTION_START_REPLY;
4654 continue;
4656 mhd_assert (NULL != connection->response);
4658 if (MHD_NO == build_header_response (connection))
4659 {
4660 /* oops - close! */
4661 CONNECTION_CLOSE_ERROR (connection,
4662 _ ("Closing connection (failed to create "
4663 "response header).\n"));
4664 continue;
4665 }
4667 break;
4668
4670 /* no default action */
4671 break;
4673 /* Some clients may take some actions right after header receive */
4674#ifdef UPGRADE_SUPPORT
4675 if (NULL != connection->response->upgrade_handler)
4676 {
4677 connection->state = MHD_CONNECTION_UPGRADE;
4678 /* This connection is "upgraded". Pass socket to application. */
4679 if (MHD_NO ==
4681 connection))
4682 {
4683 /* upgrade failed, fail hard */
4684 CONNECTION_CLOSE_ERROR (connection,
4685 NULL);
4686 continue;
4687 }
4688 /* Response is not required anymore for this connection. */
4689 {
4690 struct MHD_Response *const resp = connection->response;
4691
4692 connection->response = NULL;
4693 MHD_destroy_response (resp);
4694 }
4695 continue;
4696 }
4697#endif /* UPGRADE_SUPPORT */
4698
4699 if (connection->rp_props.send_reply_body)
4700 {
4701 if (connection->rp_props.chunked)
4703 else
4705 }
4706 else
4707 connection->state = MHD_CONNECTION_FOOTERS_SENT;
4708 continue;
4710 /* nothing to do here */
4711 break;
4713#if defined(MHD_USE_POSIX_THREADS) || defined(MHD_USE_W32_THREADS)
4714 if (NULL != connection->response->crc)
4715 MHD_mutex_lock_chk_ (&connection->response->mutex);
4716#endif
4717 if (0 == connection->response->total_size)
4718 {
4719#if defined(MHD_USE_POSIX_THREADS) || defined(MHD_USE_W32_THREADS)
4720 if (NULL != connection->response->crc)
4721 MHD_mutex_unlock_chk_ (&connection->response->mutex);
4722#endif
4723 if (connection->rp_props.chunked)
4724 connection->state = MHD_CONNECTION_BODY_SENT;
4725 else
4726 connection->state = MHD_CONNECTION_FOOTERS_SENT;
4727 continue;
4728 }
4729 if (MHD_NO != try_ready_normal_body (connection))
4730 {
4731#if defined(MHD_USE_POSIX_THREADS) || defined(MHD_USE_W32_THREADS)
4732 if (NULL != connection->response->crc)
4733 MHD_mutex_unlock_chk_ (&connection->response->mutex);
4734#endif
4736 /* Buffering for flushable socket was already enabled*/
4737
4738 break;
4739 }
4740 /* mutex was already unlocked by "try_ready_normal_body */
4741 /* not ready, no socket action */
4742 break;
4744 /* nothing to do here */
4745 break;
4747#if defined(MHD_USE_POSIX_THREADS) || defined(MHD_USE_W32_THREADS)
4748 if (NULL != connection->response->crc)
4749 MHD_mutex_lock_chk_ (&connection->response->mutex);
4750#endif
4751 if ( (0 == connection->response->total_size) ||
4752 (connection->response_write_position ==
4753 connection->response->total_size) )
4754 {
4755#if defined(MHD_USE_POSIX_THREADS) || defined(MHD_USE_W32_THREADS)
4756 if (NULL != connection->response->crc)
4757 MHD_mutex_unlock_chk_ (&connection->response->mutex);
4758#endif
4759 connection->state = MHD_CONNECTION_BODY_SENT;
4760 continue;
4761 }
4762 if (1)
4763 { /* pseudo-branch for local variables scope */
4764 bool finished;
4765 if (MHD_NO != try_ready_chunked_body (connection, &finished))
4766 {
4767#if defined(MHD_USE_POSIX_THREADS) || defined(MHD_USE_W32_THREADS)
4768 if (NULL != connection->response->crc)
4769 MHD_mutex_unlock_chk_ (&connection->response->mutex);
4770#endif
4771 connection->state = finished ? MHD_CONNECTION_BODY_SENT :
4773 continue;
4774 }
4775 /* mutex was already unlocked by try_ready_chunked_body */
4776 }
4777 break;
4779 mhd_assert (connection->rp_props.chunked);
4780
4782 {
4783 /* oops - close! */
4784 CONNECTION_CLOSE_ERROR (connection,
4785 _ (
4786 "Closing connection (failed to create response footer)."));
4787 continue;
4788 }
4789 /* TODO: remove next 'if' */
4790 if ( (! connection->rp_props.chunked) ||
4791 (connection->write_buffer_send_offset ==
4792 connection->write_buffer_append_offset) )
4793 connection->state = MHD_CONNECTION_FOOTERS_SENT;
4794 else
4796 continue;
4798 /* no default action */
4799 break;
4801 if (MHD_HTTP_PROCESSING == connection->responseCode)
4802 {
4803 /* After this type of response, we allow sending another! */
4805 MHD_destroy_response (connection->response);
4806 connection->response = NULL;
4807 /* FIXME: maybe partially reset memory pool? */
4808 continue;
4809 }
4810 /* Reset connection after complete reply */
4811 connection_reset (connection,
4812 MHD_CONN_USE_KEEPALIVE == connection->keepalive &&
4813 ! connection->read_closed &&
4814 ! connection->discard_request);
4815 continue;
4817 cleanup_connection (connection);
4818 connection->in_idle = false;
4819 return MHD_NO;
4820#ifdef UPGRADE_SUPPORT
4821 case MHD_CONNECTION_UPGRADE:
4822 connection->in_idle = false;
4823 return MHD_YES; /* keep open */
4824#endif /* UPGRADE_SUPPORT */
4825 default:
4826 mhd_assert (0);
4827 break;
4828 }
4829 break;
4830 }
4831 if (connection_check_timedout (connection))
4832 {
4833 MHD_connection_close_ (connection,
4835 connection->in_idle = false;
4836 return MHD_YES;
4837 }
4839 ret = MHD_YES;
4840#ifdef EPOLL_SUPPORT
4841 if ( (! connection->suspended) &&
4842 (0 != (daemon->options & MHD_USE_EPOLL)) )
4843 {
4844 ret = MHD_connection_epoll_update_ (connection);
4845 }
4846#endif /* EPOLL_SUPPORT */
4847 connection->in_idle = false;
4848 return ret;
4849}
4850
4851
4852#ifdef EPOLL_SUPPORT
4861enum MHD_Result
4862MHD_connection_epoll_update_ (struct MHD_Connection *connection)
4863{
4864 struct MHD_Daemon *daemon = connection->daemon;
4865
4866 if ( (0 != (daemon->options & MHD_USE_EPOLL)) &&
4867 (0 == (connection->epoll_state & MHD_EPOLL_STATE_IN_EPOLL_SET)) &&
4868 (0 == (connection->epoll_state & MHD_EPOLL_STATE_SUSPENDED)) &&
4869 ( ( (MHD_EVENT_LOOP_INFO_WRITE == connection->event_loop_info) &&
4870 (0 == (connection->epoll_state & MHD_EPOLL_STATE_WRITE_READY))) ||
4871 ( (MHD_EVENT_LOOP_INFO_READ == connection->event_loop_info) &&
4872 (0 == (connection->epoll_state & MHD_EPOLL_STATE_READ_READY)) ) ) )
4873 {
4874 /* add to epoll set */
4875 struct epoll_event event;
4876
4877 event.events = EPOLLIN | EPOLLOUT | EPOLLPRI | EPOLLET;
4878 event.data.ptr = connection;
4879 if (0 != epoll_ctl (daemon->epoll_fd,
4880 EPOLL_CTL_ADD,
4881 connection->socket_fd,
4882 &event))
4883 {
4884#ifdef HAVE_MESSAGES
4885 if (0 != (daemon->options & MHD_USE_ERROR_LOG))
4886 MHD_DLOG (daemon,
4887 _ ("Call to epoll_ctl failed: %s\n"),
4889#endif
4890 connection->state = MHD_CONNECTION_CLOSED;
4891 cleanup_connection (connection);
4892 return MHD_NO;
4893 }
4894 connection->epoll_state |= MHD_EPOLL_STATE_IN_EPOLL_SET;
4895 }
4896 return MHD_YES;
4897}
4898
4899
4900#endif
4901
4902
4908void
4910{
4911 connection->recv_cls = &recv_param_adapter;
4912}
4913
4914
4925const union MHD_ConnectionInfo *
4927 enum MHD_ConnectionInfoType info_type,
4928 ...)
4929{
4930 switch (info_type)
4931 {
4932#ifdef HTTPS_SUPPORT
4934 if (NULL == connection->tls_session)
4935 return NULL;
4936 connection->cipher = gnutls_cipher_get (connection->tls_session);
4937 return (const union MHD_ConnectionInfo *) &connection->cipher;
4939 if (NULL == connection->tls_session)
4940 return NULL;
4941 connection->protocol = gnutls_protocol_get_version (
4942 connection->tls_session);
4943 return (const union MHD_ConnectionInfo *) &connection->protocol;
4945 if (NULL == connection->tls_session)
4946 return NULL;
4947 return (const union MHD_ConnectionInfo *) &connection->tls_session;
4948#endif /* HTTPS_SUPPORT */
4950 return (const union MHD_ConnectionInfo *) &connection->addr;
4952 return (const union MHD_ConnectionInfo *) &connection->daemon;
4954 return (const union MHD_ConnectionInfo *) &connection->socket_fd;
4956 return (const union MHD_ConnectionInfo *) &connection->socket_context;
4958 connection->suspended_dummy = connection->suspended ? MHD_YES : MHD_NO;
4959 return (const union MHD_ConnectionInfo *) &connection->suspended_dummy;
4961 connection->connection_timeout_dummy =
4962 (unsigned int) connection->connection_timeout_ms / 1000;
4963 return (const union MHD_ConnectionInfo *) &connection->
4964 connection_timeout_dummy;
4966 if ( (MHD_CONNECTION_HEADERS_RECEIVED > connection->state) ||
4967 (MHD_CONNECTION_CLOSED == connection->state) )
4968 return NULL; /* invalid, too early! */
4969 return (const union MHD_ConnectionInfo *) &connection->header_size;
4971 if (NULL == connection->response)
4972 return NULL;
4973 return (const union MHD_ConnectionInfo *) &connection->responseCode;
4974 default:
4975 return NULL;
4976 }
4977}
4978
4979
4989enum MHD_Result
4991 enum MHD_CONNECTION_OPTION option,
4992 ...)
4993{
4994 va_list ap;
4995 struct MHD_Daemon *daemon;
4996 unsigned int ui_val;
4997
4998 daemon = connection->daemon;
4999 switch (option)
5000 {
5002 if (0 == connection->connection_timeout_ms)
5004#if defined(MHD_USE_POSIX_THREADS) || defined(MHD_USE_W32_THREADS)
5006#endif
5007 if ( (0 == (daemon->options & MHD_USE_THREAD_PER_CONNECTION)) &&
5008 (! connection->suspended) )
5009 {
5010 if (connection->connection_timeout_ms == daemon->connection_timeout_ms)
5012 daemon->normal_timeout_tail,
5013 connection);
5014 else
5016 daemon->manual_timeout_tail,
5017 connection);
5018 }
5019 va_start (ap, option);
5020 ui_val = va_arg (ap, unsigned int);
5021 va_end (ap);
5022#if (SIZEOF_UINT64_T - 2) <= SIZEOF_UNSIGNED_INT
5023 if ((UINT64_MAX / 4000 - 1) < ui_val)
5024 {
5025#ifdef HAVE_MESSAGES
5026 MHD_DLOG (connection->daemon,
5027 _ ("The specified connection timeout (%u) is too " \
5028 "large. Maximum allowed value (%" PRIu64 ") will be used " \
5029 "instead.\n"),
5030 ui_val,
5031 (UINT64_MAX / 4000 - 1));
5032#endif
5033 ui_val = UINT64_MAX / 4000 - 1;
5034 }
5035 else
5036#endif /* (SIZEOF_UINT64_T - 2) <= SIZEOF_UNSIGNED_INT */
5037 connection->connection_timeout_ms = ui_val * 1000;
5038 if ( (0 == (daemon->options & MHD_USE_THREAD_PER_CONNECTION)) &&
5039 (! connection->suspended) )
5040 {
5041 if (connection->connection_timeout_ms == daemon->connection_timeout_ms)
5043 daemon->normal_timeout_tail,
5044 connection);
5045 else
5047 daemon->manual_timeout_tail,
5048 connection);
5049 }
5050#if defined(MHD_USE_POSIX_THREADS) || defined(MHD_USE_W32_THREADS)
5052#endif
5053 return MHD_YES;
5054 default:
5055 return MHD_NO;
5056 }
5057}
5058
5059
5077enum MHD_Result
5079 unsigned int status_code,
5080 struct MHD_Response *response)
5081{
5082 struct MHD_Daemon *daemon;
5083
5084 if ((NULL == connection) || (NULL == response))
5085 return MHD_NO;
5086
5087 daemon = connection->daemon;
5088
5089#if defined(MHD_USE_POSIX_THREADS) || defined(MHD_USE_W32_THREADS)
5090 if ( (! connection->suspended) &&
5091 (0 != (daemon->options & MHD_USE_INTERNAL_POLLING_THREAD)) &&
5092 (! MHD_thread_ID_match_current_ (connection->pid)) )
5093 {
5094#ifdef HAVE_MESSAGES
5095 MHD_DLOG (daemon,
5096 _ ("Attempted to queue response on wrong thread!\n"));
5097#endif
5098 return MHD_NO;
5099 }
5100#endif
5101
5102 if (daemon->shutdown)
5103 return MHD_YES; /* If daemon was shut down in parallel,
5104 * response will be aborted now or on later stage. */
5105
5106 if ( (NULL != connection->response) ||
5107 ( (MHD_CONNECTION_HEADERS_PROCESSED != connection->state) &&
5108 (MHD_CONNECTION_FULL_REQ_RECEIVED != connection->state) ) )
5109 return MHD_NO;
5110
5111#ifdef UPGRADE_SUPPORT
5112 if (NULL != response->upgrade_handler)
5113 {
5114 struct MHD_HTTP_Header *conn_header;
5115 if (0 == (daemon->options & MHD_ALLOW_UPGRADE))
5116 {
5117#ifdef HAVE_MESSAGES
5118 MHD_DLOG (daemon,
5119 _ ("Attempted 'upgrade' connection on daemon without" \
5120 " MHD_ALLOW_UPGRADE option!\n"));
5121#endif
5122 return MHD_NO;
5123 }
5124 if (MHD_HTTP_SWITCHING_PROTOCOLS != status_code)
5125 {
5126#ifdef HAVE_MESSAGES
5127 MHD_DLOG (daemon,
5128 _ ("Application used invalid status code for" \
5129 " 'upgrade' response!\n"));
5130#endif
5131 return MHD_NO;
5132 }
5133 if (0 == (response->flags_auto & MHD_RAF_HAS_CONNECTION_HDR))
5134 {
5135#ifdef HAVE_MESSAGES
5136 MHD_DLOG (daemon,
5137 _ ("Application used invalid response" \
5138 " without \"Connection\" header!\n"));
5139#endif
5140 return MHD_NO;
5141 }
5142 conn_header = response->first_header;
5143 mhd_assert (NULL != conn_header);
5146 if (! MHD_str_has_s_token_caseless_ (conn_header->value,
5147 "upgrade"))
5148 {
5149#ifdef HAVE_MESSAGES
5150 MHD_DLOG (daemon,
5151 _ ("Application used invalid response" \
5152 " without \"upgrade\" token in" \
5153 " \"Connection\" header!\n"));
5154#endif
5155 return MHD_NO;
5156 }
5157 if (! MHD_IS_HTTP_VER_1_1_COMPAT (connection->http_ver))
5158 {
5159#ifdef HAVE_MESSAGES
5160 MHD_DLOG (daemon,
5161 _ ("Connection \"Upgrade\" can be used " \
5162 "with HTTP/1.1 connections!\n"));
5163#endif
5164 return MHD_NO;
5165 }
5166 }
5167#endif /* UPGRADE_SUPPORT */
5168 if ( (100 > (status_code & (~MHD_ICY_FLAG))) ||
5169 (999 < (status_code & (~MHD_ICY_FLAG))) )
5170 {
5171#ifdef HAVE_MESSAGES
5172 MHD_DLOG (daemon,
5173 _ ("Refused wrong status code (%u). " \
5174 "HTTP requires three digits status code!\n"),
5175 (status_code & (~MHD_ICY_FLAG)));
5176#endif
5177 return MHD_NO;
5178 }
5179 if (200 > (status_code & (~MHD_ICY_FLAG)))
5180 {
5181 if (MHD_HTTP_VER_1_0 == connection->http_ver)
5182 {
5183#ifdef HAVE_MESSAGES
5184 MHD_DLOG (daemon,
5185 _ ("Wrong status code (%u) refused. " \
5186 "HTTP/1.0 clients do not support 1xx status codes!\n"),
5187 (status_code & (~MHD_ICY_FLAG)));
5188#endif
5189 return MHD_NO;
5190 }
5191 if (0 != (response->flags & (MHD_RF_HTTP_1_0_COMPATIBLE_STRICT
5193 {
5194#ifdef HAVE_MESSAGES
5195 MHD_DLOG (daemon,
5196 _ ("Wrong status code (%u) refused. " \
5197 "HTTP/1.0 reply mode does not support 1xx status codes!\n"),
5198 (status_code & (~MHD_ICY_FLAG)));
5199#endif
5200 return MHD_NO;
5201 }
5202 }
5203
5204 MHD_increment_response_rc (response);
5205 connection->response = response;
5206 connection->responseCode = status_code;
5207#if defined(_MHD_HAVE_SENDFILE)
5208 if ( (response->fd == -1) ||
5209 (response->is_pipe) ||
5210 (0 != (connection->daemon->options & MHD_USE_TLS))
5211#if defined(MHD_SEND_SPIPE_SUPPRESS_NEEDED) && \
5212 defined(MHD_SEND_SPIPE_SUPPRESS_POSSIBLE)
5213 || (! daemon->sigpipe_blocked && ! connection->sk_spipe_suppress)
5214#endif /* MHD_SEND_SPIPE_SUPPRESS_NEEDED &&
5215 MHD_SEND_SPIPE_SUPPRESS_POSSIBLE */
5216 )
5217 connection->resp_sender = MHD_resp_sender_std;
5218 else
5219 connection->resp_sender = MHD_resp_sender_sendfile;
5220#endif /* _MHD_HAVE_SENDFILE */
5221 /* FIXME: if 'is_pipe' is set, TLS is off, and we have *splice*, we could use splice()
5222 to avoid two user-space copies... */
5223
5224 if ( (MHD_HTTP_MTHD_HEAD == connection->http_mthd) ||
5225 (MHD_HTTP_OK > status_code) ||
5226 (MHD_HTTP_NO_CONTENT == status_code) ||
5227 (MHD_HTTP_NOT_MODIFIED == status_code) )
5228 {
5229 /* if this is a "HEAD" request, or a status code for
5230 which a body is not allowed, pretend that we
5231 have already sent the full message body. */
5232 /* TODO: remove the next assignment, use 'rp_props.send_reply_body' in
5233 * checks */
5234 connection->response_write_position = response->total_size;
5235 }
5236 if (MHD_CONNECTION_HEADERS_PROCESSED == connection->state)
5237 {
5238 /* response was queued "early", refuse to read body / footers or
5239 further requests! */
5240 connection->discard_request = true;
5241 connection->state = MHD_CONNECTION_START_REPLY;
5242 connection->remaining_upload_size = 0;
5243 }
5244 if (! connection->in_idle)
5245 (void) MHD_connection_handle_idle (connection);
5246 MHD_update_last_activity_ (connection);
5247 return MHD_YES;
5248}
5249
5250
5251/* 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:982
static enum MHD_Result build_connection_chunked_response_footer(struct MHD_Connection *connection)
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)
static enum MHD_Result build_header_response(struct MHD_Connection *connection)
static void connection_close_error(struct MHD_Connection *connection, const char *emsg)
Definition connection.c:945
static enum MHD_Result process_header_line(struct MHD_Connection *connection, char *line)
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)
#define INTERNAL_ERROR
Definition connection.c:160
static void MHD_connection_update_event_loop_info(struct MHD_Connection *connection)
#define buffer_append_s(buf, ppos, buf_size, str)
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)
static enum MHD_Result try_ready_normal_body(struct MHD_Connection *connection)
#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)
static void process_request_body(struct MHD_Connection *connection)
#define REQUEST_TOO_BIG
Definition connection.c:75
static void setup_reply_properties(struct MHD_Connection *connection)
#define HTTP_100_CONTINUE
Definition connection.c:62
static enum MHD_Result parse_cookie_header(struct MHD_Connection *connection)
#define transmit_error_response_static(c, code, msg)
#define REQUEST_MALFORMED
Definition connection.c:103
static void connection_shrink_read_buffer(struct MHD_Connection *connection)
void MHD_set_http_callbacks_(struct MHD_Connection *connection)
#define REQ_HTTP_VER_IS_TOO_OLD
Definition connection.c:170
static bool connection_check_timedout(struct MHD_Connection *c)
static enum MHD_ConnKeepAlive keepalive_possible(struct MHD_Connection *connection)
#define REQUEST_LACKS_HOST
Definition connection.c:89
static bool try_grow_read_buffer(struct MHD_Connection *connection, bool required)
static char * get_next_header_line(struct MHD_Connection *connection, size_t *line_len)
static enum MHD_Result parse_http_std_method(struct MHD_Connection *connection, const char *method, size_t len)
static bool need_100_continue(struct MHD_Connection *connection)
Definition connection.c:768
enum MHD_Result MHD_connection_handle_idle(struct MHD_Connection *connection)
#define CONNECTION_CLOSE_ERROR_CHECK(c, emsg)
static void cleanup_connection(struct MHD_Connection *connection)
static bool is_reply_body_needed(struct MHD_Connection *connection)
static enum MHD_Result process_broken_line(struct MHD_Connection *connection, char *line, enum MHD_ValueKind kind)
static enum MHD_Result try_ready_chunked_body(struct MHD_Connection *connection, bool *p_finished)
static bool get_date_str(char *date)
static void connection_reset(struct MHD_Connection *connection, bool reuse)
void MHD_connection_handle_read(struct MHD_Connection *connection, bool socket_error)
static void transmit_error_response_len(struct MHD_Connection *connection, unsigned int status_code, const char *message, size_t message_len)
static void connection_switch_from_recv_to_send(struct MHD_Connection *connection)
static void parse_connection_headers(struct MHD_Connection *connection)
void MHD_update_last_activity_(struct MHD_Connection *connection)
#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)
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)
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)
void MHD_connection_mark_closed_(struct MHD_Connection *connection)
Definition connection.c:792
#define CONNECTION_CLOSE_ERROR(c, emsg)
Definition connection.c:970
static bool buffer_append(char *buf, size_t *ppos, size_t buf_size, const char *append, size_t append_size)
static enum MHD_Result check_write_done(struct MHD_Connection *connection, enum MHD_CONNECTION_STATE next_state)
static enum MHD_Result parse_http_version(struct MHD_Connection *connection, const char *http_string, size_t len)
static bool get_date_header(char *header)
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
#define MHD_HTTP_METHOD_OPTIONS
#define MHD_HTTP_METHOD_GET
#define MHD_HTTP_METHOD_HEAD
#define MHD_HTTP_METHOD_POST
#define MHD_HTTP_METHOD_PUT
#define MHD_HTTP_METHOD_CONNECT
#define MHD_HTTP_METHOD_DELETE
enum MHD_Result(* MHD_KeyValueIterator)(void *cls, enum MHD_ValueKind kind, const char *key, const char *value)
_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)
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
_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
@ MHD_CONNECTION_INFO_CONNECTION_TIMEOUT
@ MHD_CONNECTION_INFO_SOCKET_CONTEXT
@ MHD_CONNECTION_INFO_GNUTLS_SESSION
@ MHD_CONNECTION_INFO_REQUEST_HEADER_SIZE
@ MHD_CONNECTION_INFO_CIPHER_ALGO
@ MHD_CONNECTION_INFO_CONNECTION_SUSPENDED
@ MHD_CONNECTION_INFO_CLIENT_ADDRESS
@ MHD_CONNECTION_INFO_DAEMON
@ MHD_CONNECTION_INFO_HTTP_STATUS
@ MHD_CONNECTION_INFO_CONNECTION_FD
@ MHD_CONNECTION_INFO_PROTOCOL
@ MHD_REQUEST_TERMINATED_TIMEOUT_REACHED
@ MHD_REQUEST_TERMINATED_COMPLETED_OK
@ MHD_REQUEST_TERMINATED_WITH_ERROR
@ MHD_REQUEST_TERMINATED_READ_ERROR
@ MHD_REQUEST_TERMINATED_CLIENT_ABORT
_MHD_EXTERN struct MHD_Response * MHD_create_response_from_buffer(size_t size, void *buffer, enum MHD_ResponseMemoryMode mode)
Definition response.c:1312
_MHD_EXTERN enum MHD_Result MHD_queue_response(struct MHD_Connection *connection, unsigned int status_code, struct MHD_Response *response)
_MHD_EXTERN void MHD_destroy_response(struct MHD_Response *response)
Definition response.c:1966
@ MHD_RESPMEM_PERSISTENT
_MHD_EXTERN const union MHD_ConnectionInfo * MHD_get_connection_info(struct MHD_Connection *connection, enum MHD_ConnectionInfoType info_type,...)
#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,...)
#define MHD_HTTP_VERSION_1_0
#define MHD_HTTP_VERSION_1_1
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)
#define MHD_SCKT_ERR_IS_EAGAIN_(err)
#define MHD_SCKT_ERR_IS_LOW_RESOURCES_(err)
#define MHD_socket_last_strerr_()
#define MHD_SCKT_EOPNOTSUPP_
#define MHD_SCKT_EBADF_
#define MHD_socket_get_error_()
#define MHD_SCKT_ERR_IS_REMOTE_DISCNN_(err)
#define MHD_SCKT_EINVAL_
#define MHD_SCKT_ERR_IS_EINTR_(err)
#define MHD_SCKT_SEND_MAX_SIZE_
#define MHD_SCKT_ENOTCONN_
#define MHD_recv_(s, b, l)
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
#define _(String)
Definition mhd_options.h:42
#define _MHD_EXTERN
Definition mhd_options.h:50
#define MHD_FUNC_
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:901
ssize_t MHD_send_iovec_(struct MHD_Connection *connection, struct MHD_iovec_track_ *const r_iov, bool push_data)
Definition mhd_send.c:1614
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
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:2012
#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
@ MHD_FOOTER_KIND
@ MHD_COOKIE_KIND
@ MHD_HEADER_KIND
@ MHD_GET_ARGUMENT_KIND
@ MHD_USE_EPOLL
@ MHD_USE_THREAD_PER_CONNECTION
@ MHD_USE_TURBO
@ MHD_USE_SUPPRESS_DATE_NO_CLOCK
@ MHD_USE_TLS
@ MHD_ALLOW_UPGRADE
@ MHD_USE_ERROR_LOG
@ MHD_USE_INTERNAL_POLLING_THREAD
@ MHD_RF_SEND_KEEP_ALIVE_HEADER
@ MHD_RF_HTTP_1_0_COMPATIBLE_STRICT
@ MHD_RF_HTTP_1_0_SERVER
MHD_CONNECTION_OPTION
@ MHD_CONNECTION_OPTION_TIMEOUT
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
ReceiveCallback recv_cls
Definition internal.h:706
size_t header_size
Definition internal.h:1108
struct MHD_Response * response
Definition internal.h:968
const char * url
Definition internal.h:1011
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
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
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
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
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
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
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