GNU libmicrohttpd 0.9.71
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
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public
16 License along with this library; if not, write to the Free Software
17 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18
19*/
27#include "internal.h"
28#include "mhd_limits.h"
29#include "connection.h"
30#include "memorypool.h"
31#include "response.h"
32#include "mhd_mono_clock.h"
33#include "mhd_str.h"
34#if defined(MHD_USE_POSIX_THREADS) || defined(MHD_USE_W32_THREADS)
35#include "mhd_locks.h"
36#endif
37#include "mhd_sockets.h"
38#include "mhd_compat.h"
39#include "mhd_itc.h"
40#ifdef MHD_LINUX_SOLARIS_SENDFILE
41#include <sys/sendfile.h>
42#endif /* MHD_LINUX_SOLARIS_SENDFILE */
43#if defined(HAVE_FREEBSD_SENDFILE) || defined(HAVE_DARWIN_SENDFILE)
44#include <sys/types.h>
45#include <sys/socket.h>
46#include <sys/uio.h>
47#endif /* HAVE_FREEBSD_SENDFILE || HAVE_DARWIN_SENDFILE */
48#ifdef HTTPS_SUPPORT
49#include "connection_https.h"
50#endif /* HTTPS_SUPPORT */
51#ifdef HAVE_SYS_PARAM_H
52/* For FreeBSD version identification */
53#include <sys/param.h>
54#endif /* HAVE_SYS_PARAM_H */
55#include "mhd_send.h"
56
60#define HTTP_100_CONTINUE "HTTP/1.1 100 Continue\r\n\r\n"
61
69#ifdef HAVE_MESSAGES
70#define REQUEST_TOO_BIG \
71 "<html><head><title>Request too big</title></head><body>Your HTTP header was too big for the memory constraints of this webserver.</body></html>"
72#else
73#define REQUEST_TOO_BIG ""
74#endif
75
83#ifdef HAVE_MESSAGES
84#define REQUEST_LACKS_HOST \
85 "<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>"
86#else
87#define REQUEST_LACKS_HOST ""
88#endif
89
97#ifdef HAVE_MESSAGES
98#define REQUEST_MALFORMED \
99 "<html><head><title>Request malformed</title></head><body>Your HTTP request was syntactically incorrect.</body></html>"
100#else
101#define REQUEST_MALFORMED ""
102#endif
103
110#ifdef HAVE_MESSAGES
111#define INTERNAL_ERROR \
112 "<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>"
113#else
114#define INTERNAL_ERROR ""
115#endif
116
121#define DEBUG_CLOSE MHD_NO
122
126#define DEBUG_SEND_DATA MHD_NO
127
128
132#define MHD_SENFILE_CHUNK_ (0x20000)
133
137#define MHD_SENFILE_CHUNK_THR_P_C_ (0x200000)
138
139#ifdef HAVE_FREEBSD_SENDFILE
140#ifdef SF_FLAGS
144static int freebsd_sendfile_flags_;
145
149static int freebsd_sendfile_flags_thd_p_c_;
150#endif /* SF_FLAGS */
154void
155MHD_conn_init_static_ (void)
156{
157/* FreeBSD 11 and later allow to specify read-ahead size
158 * and handles SF_NODISKIO differently.
159 * SF_FLAGS defined only on FreeBSD 11 and later. */
160#ifdef SF_FLAGS
161 long sys_page_size = sysconf (_SC_PAGESIZE);
162 if (0 > sys_page_size)
163 { /* Failed to get page size. */
164 freebsd_sendfile_flags_ = SF_NODISKIO;
165 freebsd_sendfile_flags_thd_p_c_ = SF_NODISKIO;
166 }
167 else
168 {
169 freebsd_sendfile_flags_ =
170 SF_FLAGS ((uint16_t) (MHD_SENFILE_CHUNK_ / sys_page_size), SF_NODISKIO);
171 freebsd_sendfile_flags_thd_p_c_ =
172 SF_FLAGS ((uint16_t) (MHD_SENFILE_CHUNK_THR_P_C_ / sys_page_size),
173 SF_NODISKIO);
174 }
175#endif /* SF_FLAGS */
176}
177
178
179#endif /* HAVE_FREEBSD_SENDFILE */
189static ssize_t
191 void *other,
192 size_t i)
193{
194 ssize_t ret;
195
196 if ( (MHD_INVALID_SOCKET == connection->socket_fd) ||
197 (MHD_CONNECTION_CLOSED == connection->state) )
198 {
199 return MHD_ERR_NOTCONN_;
200 }
202 i = MHD_SCKT_SEND_MAX_SIZE_; /* return value limit */
203
204 ret = MHD_recv_ (connection->socket_fd,
205 other,
206 i);
207 if (0 > ret)
208 {
209 const int err = MHD_socket_get_error_ ();
210 if (MHD_SCKT_ERR_IS_EAGAIN_ (err))
211 {
212#ifdef EPOLL_SUPPORT
213 /* Got EAGAIN --- no longer read-ready */
214 connection->epoll_state &= ~MHD_EPOLL_STATE_READ_READY;
215#endif /* EPOLL_SUPPORT */
216 return MHD_ERR_AGAIN_;
217 }
218 if (MHD_SCKT_ERR_IS_EINTR_ (err))
219 return MHD_ERR_AGAIN_;
221 return MHD_ERR_CONNRESET_;
222 /* Treat any other error as hard error. */
223 return MHD_ERR_NOTCONN_;
224 }
225#ifdef EPOLL_SUPPORT
226 else if (i > (size_t) ret)
227 connection->epoll_state &= ~MHD_EPOLL_STATE_READ_READY;
228#endif /* EPOLL_SUPPORT */
229 return ret;
230}
231
232
245int
247 enum MHD_ValueKind kind,
248 MHD_KeyValueIterator iterator,
249 void *iterator_cls)
250{
251 int ret;
252 struct MHD_HTTP_Header *pos;
253
254 if (NULL == connection)
255 return -1;
256 ret = 0;
257 for (pos = connection->headers_received; NULL != pos; pos = pos->next)
258 if (0 != (pos->kind & kind))
259 {
260 ret++;
261 if ( (NULL != iterator) &&
262 (MHD_YES != iterator (iterator_cls,
263 pos->kind,
264 pos->header,
265 pos->value)) )
266 return ret;
267 }
268 return ret;
269}
270
271
284int
286 enum MHD_ValueKind kind,
287 MHD_KeyValueIteratorN iterator,
288 void *iterator_cls)
289{
290 int ret;
291 struct MHD_HTTP_Header *pos;
292
293 if (NULL == connection)
294 return -1;
295 ret = 0;
296
297 if (NULL == iterator)
298 for (pos = connection->headers_received; NULL != pos; pos = pos->next)
299 {
300 if (0 != (kind & pos->kind))
301 ret++;
302 }
303 else
304 for (pos = connection->headers_received; NULL != pos; pos = pos->next)
305 if (0 != (kind & pos->kind))
306 {
307 ret++;
308 if (MHD_NO == iterator (iterator_cls,
309 pos->kind,
310 pos->header,
311 pos->header_size,
312 pos->value,
313 pos->value_size))
314 return ret;
315 }
316 return ret;
317}
318
319
337static enum MHD_Result
339 enum MHD_ValueKind kind,
340 const char *key,
341 size_t key_size,
342 const char *value,
343 size_t value_size)
344{
345 struct MHD_HTTP_Header *pos;
346
347 pos = MHD_pool_allocate (connection->pool,
348 sizeof (struct MHD_HTTP_Header),
349 true);
350 if (NULL == pos)
351 return MHD_NO;
352 pos->header = (char *) key;
353 pos->header_size = key_size;
354 pos->value = (char *) value;
355 pos->value_size = value_size;
356 pos->kind = kind;
357 pos->next = NULL;
358 /* append 'pos' to the linked list of headers */
359 if (NULL == connection->headers_received_tail)
360 {
361 connection->headers_received = pos;
362 connection->headers_received_tail = pos;
363 }
364 else
365 {
366 connection->headers_received_tail->next = pos;
367 connection->headers_received_tail = pos;
368 }
369 return MHD_YES;
370}
371
372
398enum MHD_Result
400 enum MHD_ValueKind kind,
401 const char *key,
402 size_t key_size,
403 const char *value,
404 size_t value_size)
405{
406 if ( (MHD_GET_ARGUMENT_KIND != kind) &&
407 ( ((key ? strlen (key) : 0) != key_size) ||
408 ((value ? strlen (value) : 0) != value_size) ) )
409 return MHD_NO; /* binary zero is allowed only in GET arguments */
410
411 return MHD_set_connection_value_n_nocheck_ (connection,
412 kind,
413 key,
414 key_size,
415 value,
416 value_size);
417}
418
419
445enum MHD_Result
447 enum MHD_ValueKind kind,
448 const char *key,
449 const char *value)
450{
451 return MHD_set_connection_value_n_nocheck_ (connection,
452 kind,
453 key,
454 NULL != key
455 ? strlen (key)
456 : 0,
457 value,
458 NULL != value
459 ? strlen (value)
460 : 0);
461}
462
463
474const char *
476 enum MHD_ValueKind kind,
477 const char *key)
478{
479 const char *value;
480
481 value = NULL;
482 (void) MHD_lookup_connection_value_n (connection,
483 kind,
484 key,
485 (NULL == key) ? 0 : strlen (key),
486 &value,
487 NULL);
488 return value;
489}
490
491
513 enum MHD_ValueKind kind,
514 const char *key,
515 size_t key_size,
516 const char **value_ptr,
517 size_t *value_size_ptr)
518{
519 struct MHD_HTTP_Header *pos;
520
521 if (NULL == connection)
522 return MHD_NO;
523
524 if (NULL == key)
525 {
526 for (pos = connection->headers_received; NULL != pos; pos = pos->next)
527 {
528 if ( (0 != (kind & pos->kind)) &&
529 (NULL == pos->header) )
530 break;
531 }
532 }
533 else
534 {
535 for (pos = connection->headers_received; NULL != pos; pos = pos->next)
536 {
537 if ( (0 != (kind & pos->kind)) &&
538 (key_size == pos->header_size) &&
539 ( (key == pos->header) ||
541 pos->header,
542 key_size) ) ) )
543 break;
544 }
545 }
546
547 if (NULL == pos)
548 return MHD_NO;
549
550 if (NULL != value_ptr)
551 *value_ptr = pos->value;
552
553 if (NULL != value_size_ptr)
554 *value_size_ptr = pos->value_size;
555
556 return MHD_YES;
557}
558
559
575static bool
577 const char *header,
578 size_t header_len,
579 const char *token,
580 size_t token_len)
581{
582 struct MHD_HTTP_Header *pos;
583
584 if ((NULL == connection) || (NULL == header) || (0 == header[0]) || (NULL ==
585 token) ||
586 (0 ==
587 token
588 [
589 0]) )
590 return false;
591
592 for (pos = connection->headers_received; NULL != pos; pos = pos->next)
593 {
594 if ((0 != (pos->kind & MHD_HEADER_KIND)) &&
595 (header_len == pos->header_size) &&
596 ( (header == pos->header) ||
598 pos->header,
599 header_len)) ) &&
600 (MHD_str_has_token_caseless_ (pos->value, token, token_len)))
601 return true;
602 }
603 return false;
604}
605
606
618#define MHD_lookup_header_s_token_ci(c,h,tkn) \
619 MHD_lookup_header_token_ci ((c),(h),MHD_STATICSTR_LEN_ (h), \
620 (tkn),MHD_STATICSTR_LEN_ (tkn))
621
622
630static bool
632{
633 const char *expect;
634
635 return ( (NULL != connection->version) &&
636 (MHD_str_equal_caseless_ (connection->version,
643 &expect,
644 NULL)) &&
646 "100-continue")) );
647}
648
649
656void
658{
659 const struct MHD_Daemon *daemon = connection->daemon;
660
661 connection->state = MHD_CONNECTION_CLOSED;
663 if (0 == (daemon->options & MHD_USE_TURBO))
664 {
665#ifdef HTTPS_SUPPORT
666 /* For TLS connection use shutdown of TLS layer
667 * and do not shutdown TCP socket. This give more
668 * chances to send TLS closure data to remote side.
669 * Closure of TLS layer will be interpreted by
670 * remote side as end of transmission. */if (0 != (daemon->options & MHD_USE_TLS))
671 {
672 if (! MHD_tls_connection_shutdown (connection))
673 shutdown (connection->socket_fd,
674 SHUT_WR);
675 }
676 else /* Combined with next 'shutdown()'. */
677#endif /* HTTPS_SUPPORT */
678 shutdown (connection->socket_fd,
679 SHUT_WR);
680 }
681}
682
683
693void
695 enum MHD_RequestTerminationCode termination_code)
696{
697 struct MHD_Daemon *daemon = connection->daemon;
698 struct MHD_Response *resp = connection->response;
699
700 MHD_connection_mark_closed_ (connection);
701 if (NULL != resp)
702 {
703 connection->response = NULL;
705 }
706 if ( (NULL != daemon->notify_completed) &&
707 (connection->client_aware) )
708 daemon->notify_completed (daemon->notify_completed_cls,
709 connection,
710 &connection->client_context,
711 termination_code);
712 connection->client_aware = false;
713}
714
715
716#if defined(HTTPS_SUPPORT) && defined(UPGRADE_SUPPORT)
727void
729{
730 struct MHD_Daemon *daemon = connection->daemon;
731 struct MHD_UpgradeResponseHandle *urh = connection->urh;
732
733 if (0 == (daemon->options & MHD_USE_TLS))
734 return; /* Nothing to do with non-TLS connection. */
735
736 if (0 == (daemon->options & MHD_USE_THREAD_PER_CONNECTION))
737 DLL_remove (daemon->urh_head,
738 daemon->urh_tail,
739 urh);
740#if EPOLL_SUPPORT
741 if ( (0 != (daemon->options & MHD_USE_EPOLL)) &&
742 (0 != epoll_ctl (daemon->epoll_upgrade_fd,
743 EPOLL_CTL_DEL,
744 connection->socket_fd,
745 NULL)) )
746 {
747 MHD_PANIC (_ ("Failed to remove FD from epoll set.\n"));
748 }
749 if (urh->in_eready_list)
750 {
751 EDLL_remove (daemon->eready_urh_head,
752 daemon->eready_urh_tail,
753 urh);
754 urh->in_eready_list = false;
755 }
756#endif /* EPOLL_SUPPORT */
757 if (MHD_INVALID_SOCKET != urh->mhd.socket)
758 {
759#if EPOLL_SUPPORT
760 if ( (0 != (daemon->options & MHD_USE_EPOLL)) &&
761 (0 != epoll_ctl (daemon->epoll_upgrade_fd,
762 EPOLL_CTL_DEL,
763 urh->mhd.socket,
764 NULL)) )
765 {
766 MHD_PANIC (_ ("Failed to remove FD from epoll set.\n"));
767 }
768#endif /* EPOLL_SUPPORT */
769 /* Reflect remote disconnect to application by breaking
770 * socketpair connection. */
771 shutdown (urh->mhd.socket, SHUT_RDWR);
772 }
773 /* Socketpair sockets will remain open as they will be
774 * used with MHD_UPGRADE_ACTION_CLOSE. They will be
775 * closed by MHD_cleanup_upgraded_connection_() during
776 * connection's final cleanup.
777 */}
778
779
780#endif /* HTTPS_SUPPORT && UPGRADE_SUPPORT*/
781
782
790static void
792 const char *emsg)
793{
794#ifdef HAVE_MESSAGES
795 if (NULL != emsg)
796 MHD_DLOG (connection->daemon,
797 emsg);
798#else /* ! HAVE_MESSAGES */
799 (void) emsg; /* Mute compiler warning. */
800#endif /* ! HAVE_MESSAGES */
801 MHD_connection_close_ (connection,
803}
804
805
810#ifdef HAVE_MESSAGES
811#define CONNECTION_CLOSE_ERROR(c, emsg) connection_close_error (c, emsg)
812#else
813#define CONNECTION_CLOSE_ERROR(c, emsg) connection_close_error (c, NULL)
814#endif
815
816
829static enum MHD_Result
831{
832 ssize_t ret;
833 struct MHD_Response *response;
834
835 response = connection->response;
836 if (NULL == response->crc)
837 return MHD_YES;
838 if ( (0 == response->total_size) ||
839 (connection->response_write_position == response->total_size) )
840 return MHD_YES; /* 0-byte response is always ready */
841 if ( (response->data_start <=
842 connection->response_write_position) &&
843 (response->data_size + response->data_start >
844 connection->response_write_position) )
845 return MHD_YES; /* response already ready */
846#if defined(_MHD_HAVE_SENDFILE)
847 if (MHD_resp_sender_sendfile == connection->resp_sender)
848 {
849 /* will use sendfile, no need to bother response crc */
850 return MHD_YES;
851 }
852#endif /* _MHD_HAVE_SENDFILE */
853
854 ret = response->crc (response->crc_cls,
855 connection->response_write_position,
856 response->data,
857 (size_t) MHD_MIN ((uint64_t) response->data_buffer_size,
858 response->total_size
859 - connection->response_write_position));
860 if ( (((ssize_t) MHD_CONTENT_READER_END_OF_STREAM) == ret) ||
861 (((ssize_t) MHD_CONTENT_READER_END_WITH_ERROR) == ret) )
862 {
863 /* either error or http 1.0 transfer, close socket! */
864 response->total_size = connection->response_write_position;
865#if defined(MHD_USE_POSIX_THREADS) || defined(MHD_USE_W32_THREADS)
866 MHD_mutex_unlock_chk_ (&response->mutex);
867#endif
868 if ( ((ssize_t) MHD_CONTENT_READER_END_OF_STREAM) == ret)
869 MHD_connection_close_ (connection,
871 else
872 CONNECTION_CLOSE_ERROR (connection,
873 _ (
874 "Closing connection (application reported error generating data).\n"));
875 return MHD_NO;
876 }
877 response->data_start = connection->response_write_position;
878 response->data_size = ret;
879 if (0 == ret)
880 {
882#if defined(MHD_USE_POSIX_THREADS) || defined(MHD_USE_W32_THREADS)
883 MHD_mutex_unlock_chk_ (&response->mutex);
884#endif
885 return MHD_NO;
886 }
887 return MHD_YES;
888}
889
890
900static enum MHD_Result
902{
903 ssize_t ret;
904 struct MHD_Response *response;
905 char cbuf[10]; /* 10: max strlen of "%x\r\n" */
906 int cblen;
907
908 response = connection->response;
909 if (NULL == response->crc)
910 return MHD_YES;
911 if (0 == connection->write_buffer_size)
912 {
913 size_t size;
914
915 size = MHD_pool_get_free (connection->pool);
916 if (size < 128)
917 {
918#if defined(MHD_USE_POSIX_THREADS) || defined(MHD_USE_W32_THREADS)
919 MHD_mutex_unlock_chk_ (&response->mutex);
920#endif
921 /* not enough memory */
922 CONNECTION_CLOSE_ERROR (connection,
923 _ ("Closing connection (out of memory).\n"));
924 return MHD_NO;
925 }
926 if ( (2 * (0xFFFFFF + sizeof(cbuf) + 2)) < size)
927 size = 2 * (0xFFFFFF + sizeof(cbuf) + 2);
928 connection->write_buffer = MHD_pool_allocate (connection->pool,
929 size,
930 false);
931 mhd_assert (NULL != connection->write_buffer);
932 connection->write_buffer_size = size;
933 }
934
935 if (0 == response->total_size)
936 ret = 0; /* response must be empty, don't bother calling crc */
937 else if ( (response->data_start <=
938 connection->response_write_position) &&
939 (response->data_start + response->data_size >
940 connection->response_write_position) )
941 {
942 /* difference between response_write_position and data_start is less
943 than data_size which is size_t type, no need to check for overflow */
944 const size_t data_write_offset
945 = (size_t) (connection->response_write_position - response->data_start);
946 /* buffer already ready, use what is there for the chunk */
947 ret = response->data_size - data_write_offset;
948 if ( ((size_t) ret) > connection->write_buffer_size - sizeof (cbuf) - 2)
949 ret = connection->write_buffer_size - sizeof (cbuf) - 2;
950 memcpy (&connection->write_buffer[sizeof (cbuf)],
951 &response->data[data_write_offset],
952 ret);
953 }
954 else
955 {
956 /* buffer not in range, try to fill it */
957 ret = response->crc (response->crc_cls,
958 connection->response_write_position,
959 &connection->write_buffer[sizeof (cbuf)],
960 connection->write_buffer_size - sizeof (cbuf) - 2);
961 }
962 if ( ((ssize_t) MHD_CONTENT_READER_END_WITH_ERROR) == ret)
963 {
964 /* error, close socket! */
965 response->total_size = connection->response_write_position;
966#if defined(MHD_USE_POSIX_THREADS) || defined(MHD_USE_W32_THREADS)
967 MHD_mutex_unlock_chk_ (&response->mutex);
968#endif
969 CONNECTION_CLOSE_ERROR (connection,
970 _ (
971 "Closing connection (application error generating response).\n"));
972 return MHD_NO;
973 }
974 if ( (((ssize_t) MHD_CONTENT_READER_END_OF_STREAM) == ret) ||
975 (0 == response->total_size) )
976 {
977 /* end of message, signal other side! */
978 memcpy (connection->write_buffer,
979 "0\r\n",
980 3);
981 connection->write_buffer_append_offset = 3;
982 connection->write_buffer_send_offset = 0;
983 response->total_size = connection->response_write_position;
984 return MHD_YES;
985 }
986 if (0 == ret)
987 {
989#if defined(MHD_USE_POSIX_THREADS) || defined(MHD_USE_W32_THREADS)
990 MHD_mutex_unlock_chk_ (&response->mutex);
991#endif
992 return MHD_NO;
993 }
994 if (ret > 0xFFFFFF)
995 ret = 0xFFFFFF;
996 cblen = MHD_snprintf_ (cbuf,
997 sizeof (cbuf),
998 "%X\r\n",
999 (unsigned int) ret);
1000 mhd_assert (cblen > 0);
1001 mhd_assert ((size_t) cblen < sizeof(cbuf));
1002 memcpy (&connection->write_buffer[sizeof (cbuf) - cblen],
1003 cbuf,
1004 cblen);
1005 memcpy (&connection->write_buffer[sizeof (cbuf) + ret],
1006 "\r\n",
1007 2);
1008 connection->response_write_position += ret;
1009 connection->write_buffer_send_offset = sizeof (cbuf) - cblen;
1010 connection->write_buffer_append_offset = sizeof (cbuf) + ret + 2;
1011 return MHD_YES;
1012}
1013
1014
1031static enum MHD_Result
1033{
1034 if (MHD_CONN_MUST_CLOSE == connection->keepalive)
1035 return MHD_NO;
1036 if (NULL == connection->version)
1037 return MHD_NO;
1038 if ( (NULL != connection->response) &&
1039 (0 != (connection->response->flags & MHD_RF_HTTP_VERSION_1_0_ONLY) ) )
1040 return MHD_NO;
1041
1042 if (MHD_str_equal_caseless_ (connection->version,
1044 ( (NULL == connection->response) ||
1045 (0 == (connection->response->flags
1047 {
1048 if (MHD_lookup_header_s_token_ci (connection,
1050 "upgrade"))
1051 return MHD_NO;
1052
1053 if (MHD_lookup_header_s_token_ci (connection,
1055 "close"))
1056 return MHD_NO;
1057
1058 return MHD_YES;
1059 }
1060 if (MHD_str_equal_caseless_ (connection->version,
1062 {
1063 if (MHD_lookup_header_s_token_ci (connection,
1065 "Keep-Alive"))
1066 return MHD_YES;
1067
1068 return MHD_NO;
1069 }
1070 return MHD_NO;
1071}
1072
1073
1081static void
1083 size_t date_len)
1084{
1085 static const char *const days[] = {
1086 "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
1087 };
1088 static const char *const mons[] = {
1089 "Jan", "Feb", "Mar", "Apr", "May", "Jun",
1090 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
1091 };
1092 struct tm now;
1093 time_t t;
1094#if ! defined(HAVE_C11_GMTIME_S) && ! defined(HAVE_W32_GMTIME_S) && \
1095 ! defined(HAVE_GMTIME_R)
1096 struct tm*pNow;
1097#endif
1098
1099 date[0] = 0;
1100 time (&t);
1101#if defined(HAVE_C11_GMTIME_S)
1102 if (NULL == gmtime_s (&t,
1103 &now))
1104 return;
1105#elif defined(HAVE_W32_GMTIME_S)
1106 if (0 != gmtime_s (&now,
1107 &t))
1108 return;
1109#elif defined(HAVE_GMTIME_R)
1110 if (NULL == gmtime_r (&t,
1111 &now))
1112 return;
1113#else
1114 pNow = gmtime (&t);
1115 if (NULL == pNow)
1116 return;
1117 now = *pNow;
1118#endif
1119 MHD_snprintf_ (date,
1120 date_len,
1121 "Date: %3s, %02u %3s %04u %02u:%02u:%02u GMT\r\n",
1122 days[now.tm_wday % 7],
1123 (unsigned int) now.tm_mday,
1124 mons[now.tm_mon % 12],
1125 (unsigned int) (1900 + now.tm_year),
1126 (unsigned int) now.tm_hour,
1127 (unsigned int) now.tm_min,
1128 (unsigned int) now.tm_sec);
1129}
1130
1131
1144static bool
1146 bool required)
1147{
1148 size_t new_size;
1149 size_t avail_size;
1150
1151 avail_size = MHD_pool_get_free (connection->pool);
1152 if (0 == avail_size)
1153 return false; /* No more space available */
1154 if (0 == connection->read_buffer_size)
1155 new_size = avail_size / 2; /* Use half of available buffer for reading */
1156 else
1157 {
1158 size_t grow_size;
1159
1160 grow_size = avail_size / 8;
1161 if (MHD_BUF_INC_SIZE > grow_size)
1162 { /* Shortage of space */
1163 if (! required)
1164 return false; /* Grow is not mandatory, leave some space in pool */
1165 else
1166 {
1167 /* Shortage of space, but grow is mandatory */
1168 static const size_t small_inc = MHD_BUF_INC_SIZE / 8;
1169 if (small_inc < avail_size)
1170 grow_size = small_inc;
1171 else
1172 grow_size = avail_size;
1173 }
1174 }
1175 new_size = connection->read_buffer_size + grow_size;
1176 }
1177 /* we can actually grow the buffer, do it! */
1178 connection->read_buffer = MHD_pool_reallocate (connection->pool,
1179 connection->read_buffer,
1180 connection->read_buffer_size,
1181 new_size);
1182 mhd_assert (NULL != connection->read_buffer);
1183 connection->read_buffer_size = new_size;
1184 return true;
1185}
1186
1187
1197static enum MHD_Result
1199{
1200 struct MHD_Response *response = connection->response;
1201 size_t size;
1202 size_t off;
1203 struct MHD_HTTP_Header *pos;
1204 char code[256];
1205 char date[128];
1206 size_t datelen;
1207 char content_length_buf[128];
1208 size_t content_length_len;
1209 char *data;
1210 enum MHD_ValueKind kind;
1211 const char *reason_phrase;
1212 uint32_t rc;
1213 bool client_requested_close;
1214 bool response_has_close;
1215 bool response_has_keepalive;
1216 const char *have_encoding;
1217 bool must_add_close;
1218 bool must_add_chunked_encoding;
1219 bool must_add_keep_alive;
1220 bool must_add_content_length;
1221 bool may_add_content_length;
1222
1223 mhd_assert (NULL != connection->version);
1224 if (0 == connection->version[0])
1225 {
1226 data = MHD_pool_allocate (connection->pool,
1227 0,
1228 true);
1229 connection->write_buffer = data;
1230 connection->write_buffer_append_offset = 0;
1231 connection->write_buffer_send_offset = 0;
1232 connection->write_buffer_size = 0;
1233 return MHD_YES;
1234 }
1235 rc = connection->responseCode & (~MHD_ICY_FLAG);
1236 if (MHD_CONNECTION_FOOTERS_RECEIVED == connection->state)
1237 {
1238 reason_phrase = MHD_get_reason_phrase_for (rc);
1239 off = MHD_snprintf_ (code,
1240 sizeof (code),
1241 "%s %u %s\r\n",
1242 (0 != (connection->responseCode & MHD_ICY_FLAG))
1243 ? "ICY"
1245 connection->version) ||
1246 (0 != (connection->response->flags
1250 rc,
1251 reason_phrase);
1252 /* estimate size */
1253 size = off + 2; /* +2 for extra "\r\n" at the end */
1255 if ( (0 == (connection->daemon->options
1257 (NULL == MHD_get_response_header (response,
1259 get_date_string (date,
1260 sizeof (date));
1261 else
1262 date[0] = '\0';
1263 datelen = strlen (date);
1264 size += datelen;
1265 }
1266 else
1267 {
1268 /* 2 bytes for final CRLF of a Chunked-Body */
1269 size = 2;
1271 off = 0;
1272 datelen = 0;
1273 }
1274
1275 /* calculate extra headers we need to add, such as 'Connection: close',
1276 first see what was explicitly requested by the application */
1277 must_add_close = false;
1278 must_add_chunked_encoding = false;
1279 must_add_keep_alive = false;
1280 must_add_content_length = false;
1281 response_has_close = false;
1282 switch (connection->state)
1283 {
1285 response_has_close = MHD_check_response_header_s_token_ci (response,
1287 "close");
1288 response_has_keepalive = MHD_check_response_header_s_token_ci (response,
1290 "Keep-Alive");
1291 client_requested_close = MHD_lookup_header_s_token_ci (connection,
1293 "close");
1294
1295 if (0 != (response->flags & MHD_RF_HTTP_VERSION_1_0_ONLY))
1296 connection->keepalive = MHD_CONN_MUST_CLOSE;
1297#ifdef UPGRADE_SUPPORT
1298 else if (NULL != response->upgrade_handler)
1299 /* If this connection will not be "upgraded", it must be closed. */
1300 connection->keepalive = MHD_CONN_MUST_CLOSE;
1301#endif /* UPGRADE_SUPPORT */
1302
1303 /* now analyze chunked encoding situation */
1304 connection->have_chunked_upload = false;
1305 have_encoding = MHD_get_response_header (response,
1307 if (NULL == have_encoding)
1308 may_add_content_length = true;
1309 else
1310 may_add_content_length = false; /* RFC 7230, Section 3.3.2 forbids header */
1311 if ( (MHD_SIZE_UNKNOWN == response->total_size) &&
1312#ifdef UPGRADE_SUPPORT
1313 (NULL == response->upgrade_handler) &&
1314#endif /* UPGRADE_SUPPORT */
1315 (! response_has_close) &&
1316 (! client_requested_close) )
1317 {
1318 /* size is unknown, and close was not explicitly requested;
1319 need to either to HTTP 1.1 chunked encoding or
1320 close the connection */
1321 /* 'close' header doesn't exist yet, see if we need to add one;
1322 if the client asked for a close, no need to start chunk'ing */
1323 if ( (MHD_YES == keepalive_possible (connection)) &&
1325 connection->version) ) )
1326 {
1327 if (NULL == have_encoding)
1328 {
1329 must_add_chunked_encoding = true;
1330 connection->have_chunked_upload = true;
1331 }
1332 else
1333 {
1334 if (MHD_str_equal_caseless_ (have_encoding,
1335 "identity"))
1336 {
1337 /* application forced identity encoding, can't do 'chunked' */
1338 must_add_close = true;
1339 }
1340 else
1341 {
1342 connection->have_chunked_upload = true;
1343 }
1344 }
1345 }
1346 else
1347 {
1348 /* Keep alive or chunking not possible
1349 => set close header (we know response_has_close
1350 is false here) */
1351 must_add_close = true;
1352 }
1353 }
1354
1355 /* check for other reasons to add 'close' header */
1356 if ( ( (client_requested_close) ||
1357 (connection->read_closed) ||
1358 (MHD_CONN_MUST_CLOSE == connection->keepalive)) &&
1359 (! response_has_close) &&
1360#ifdef UPGRADE_SUPPORT
1361 (NULL == response->upgrade_handler) &&
1362#endif /* UPGRADE_SUPPORT */
1363 (0 == (response->flags & MHD_RF_HTTP_VERSION_1_0_ONLY) ) )
1364 must_add_close = true;
1365
1366 /* check if we must add 'close' header because we cannot add content-length
1367 because it is forbidden AND we don't have a 'chunked' encoding */
1368 if ( (! may_add_content_length) &&
1369 (! connection->have_chunked_upload) &&
1370 (! response_has_close) )
1371 must_add_close = true;
1372 /* #MHD_HTTP_NO_CONTENT, #MHD_HTTP_NOT_MODIFIED and 1xx-status
1373 codes SHOULD NOT have a Content-Length according to spec;
1374 also chunked encoding / unknown length or CONNECT... */
1375 if ( (MHD_SIZE_UNKNOWN != response->total_size) &&
1376 (MHD_HTTP_NO_CONTENT != rc) &&
1377 (MHD_HTTP_NOT_MODIFIED != rc) &&
1378 (MHD_HTTP_OK <= rc) &&
1379 (NULL == /* this COULD fail if the check in
1380 MHD_add_response_header() was bypassed
1381 via #MHD_RF_INSANITY_HEADER_CONTENT_LENGTH */
1382 MHD_get_response_header (response,
1384 (may_add_content_length) &&
1385 ( (NULL == connection->method) ||
1386 (! MHD_str_equal_caseless_ (connection->method,
1388 {
1389 /*
1390 Here we add a content-length if one is missing; however,
1391 for 'connect' methods, the responses MUST NOT include a
1392 content-length header *if* the response code is 2xx (in
1393 which case we expect there to be no body). Still,
1394 as we don't know the response code here in some cases, we
1395 simply only force adding a content-length header if this
1396 is not a 'connect' or if the response is not empty
1397 (which is kind of more sane, because if some crazy
1398 application did return content with a 2xx status code,
1399 then having a content-length might again be a good idea).
1400
1401 Note that the change from 'SHOULD NOT' to 'MUST NOT' is
1402 a recent development of the HTTP 1.1 specification.
1403 */content_length_len
1404 = MHD_snprintf_ (content_length_buf,
1405 sizeof (content_length_buf),
1409 must_add_content_length = true;
1410 }
1411
1412 /* check for adding keep alive */
1413 if ( (! response_has_keepalive) &&
1414 (! response_has_close) &&
1415 (! must_add_close) &&
1416 (MHD_CONN_MUST_CLOSE != connection->keepalive) &&
1417#ifdef UPGRADE_SUPPORT
1418 (NULL == response->upgrade_handler) &&
1419#endif /* UPGRADE_SUPPORT */
1420 (MHD_YES == keepalive_possible (connection)) )
1421 must_add_keep_alive = true;
1422 break;
1424 response_has_keepalive = false;
1425 break;
1426 default:
1427 mhd_assert (0);
1428 return MHD_NO;
1429 }
1430
1431 if (MHD_CONN_MUST_CLOSE != connection->keepalive)
1432 {
1433 if ( (must_add_close) || (response_has_close) )
1434 connection->keepalive = MHD_CONN_MUST_CLOSE;
1435 else if ( (must_add_keep_alive) || (response_has_keepalive) )
1436 connection->keepalive = MHD_CONN_USE_KEEPALIVE;
1437 }
1438
1439 if (must_add_close)
1440 size += MHD_STATICSTR_LEN_ ("Connection: close\r\n");
1441 if (must_add_keep_alive)
1442 size += MHD_STATICSTR_LEN_ ("Connection: Keep-Alive\r\n");
1443 if (must_add_chunked_encoding)
1444 size += MHD_STATICSTR_LEN_ ("Transfer-Encoding: chunked\r\n");
1445 if (must_add_content_length)
1446 size += content_length_len;
1447 mhd_assert (! (must_add_close && must_add_keep_alive) );
1448 mhd_assert (! (must_add_chunked_encoding && must_add_content_length) );
1449
1450 for (pos = response->first_header; NULL != pos; pos = pos->next)
1451 {
1452 /* TODO: add proper support for excluding "Keep-Alive" token. */
1453 if ( (pos->kind == kind) &&
1454 (! ( (must_add_close) &&
1455 (response_has_keepalive) &&
1463 "Keep-Alive")) ) ) )
1464 size += pos->header_size + pos->value_size + 4; /* colon, space, linefeeds */
1465 }
1466 /* produce data */
1467 data = MHD_pool_allocate (connection->pool,
1468 size + 1,
1469 false);
1470 if (NULL == data)
1471 {
1472#ifdef HAVE_MESSAGES
1473 MHD_DLOG (connection->daemon,
1474 "Not enough memory for write!\n");
1475#endif
1476 return MHD_NO;
1477 }
1478 if (MHD_CONNECTION_FOOTERS_RECEIVED == connection->state)
1479 {
1480 memcpy (data,
1481 code,
1482 off);
1483 }
1484 if (must_add_close)
1485 {
1486 /* we must add the 'Connection: close' header */
1487 memcpy (&data[off],
1488 "Connection: close\r\n",
1489 MHD_STATICSTR_LEN_ ("Connection: close\r\n"));
1490 off += MHD_STATICSTR_LEN_ ("Connection: close\r\n");
1491 }
1492 if (must_add_keep_alive)
1493 {
1494 /* we must add the 'Connection: Keep-Alive' header */
1495 memcpy (&data[off],
1496 "Connection: Keep-Alive\r\n",
1497 MHD_STATICSTR_LEN_ ("Connection: Keep-Alive\r\n"));
1498 off += MHD_STATICSTR_LEN_ ("Connection: Keep-Alive\r\n");
1499 }
1500 if (must_add_chunked_encoding)
1501 {
1502 /* we must add the 'Transfer-Encoding: chunked' header */
1503 memcpy (&data[off],
1504 "Transfer-Encoding: chunked\r\n",
1505 MHD_STATICSTR_LEN_ ("Transfer-Encoding: chunked\r\n"));
1506 off += MHD_STATICSTR_LEN_ ("Transfer-Encoding: chunked\r\n");
1507 }
1508 if (must_add_content_length)
1509 {
1510 /* we must add the 'Content-Length' header */
1511 memcpy (&data[off],
1512 content_length_buf,
1513 content_length_len);
1514 off += content_length_len;
1515 }
1516 for (pos = response->first_header; NULL != pos; pos = pos->next)
1517 {
1518 /* TODO: add proper support for excluding "Keep-Alive" token. */
1519 if ( (pos->kind == kind) &&
1520 (! ( (must_add_close) &&
1521 (response_has_keepalive) &&
1529 "Keep-Alive")) ) ) )
1530 off += MHD_snprintf_ (&data[off],
1531 size - off,
1532 "%s: %s\r\n",
1533 pos->header,
1534 pos->value);
1535 }
1536 if (MHD_CONNECTION_FOOTERS_RECEIVED == connection->state)
1537 {
1538 memcpy (&data[off],
1539 date,
1540 datelen);
1541 off += datelen;
1542 }
1543 memcpy (&data[off],
1544 "\r\n",
1545 2);
1546 off += 2;
1547
1548 if (off != size)
1550 __FILE__,
1551 __LINE__,
1552 NULL);
1553 connection->write_buffer = data;
1554 connection->write_buffer_append_offset = size;
1555 connection->write_buffer_send_offset = 0;
1556 connection->write_buffer_size = size + 1;
1557 return MHD_YES;
1558}
1559
1560
1570static void
1572 unsigned int status_code,
1573 const char *message)
1574{
1575 struct MHD_Response *response;
1576 enum MHD_Result iret;
1577
1578 if (NULL == connection->version)
1579 {
1580 /* we were unable to process the full header line, so we don't
1581 really know what version the client speaks; assume 1.0 */
1582 connection->version = MHD_HTTP_VERSION_1_0;
1583 }
1585 connection->read_closed = true;
1586 if (0 != connection->read_buffer_size)
1587 {
1588 /* Read buffer is not needed anymore, discard it
1589 * to free some space for error response. */
1590 connection->read_buffer = MHD_pool_reallocate (connection->pool,
1591 connection->read_buffer,
1592 connection->read_buffer_size,
1593 0);
1594 connection->read_buffer_size = 0;
1595 }
1596#ifdef HAVE_MESSAGES
1597 MHD_DLOG (connection->daemon,
1598 _ (
1599 "Error processing request (HTTP response code is %u (`%s')). Closing connection.\n"),
1601 message);
1602#endif
1603 if (NULL != connection->response)
1604 {
1605 MHD_destroy_response (connection->response);
1606 connection->response = NULL;
1607 }
1608 response = MHD_create_response_from_buffer (strlen (message),
1609 (void *) message,
1611 if (NULL == response)
1612 {
1613 /* can't even send a reply, at least close the connection */
1614 connection->state = MHD_CONNECTION_CLOSED;
1615 return;
1616 }
1617 iret = MHD_queue_response (connection,
1619 response);
1620 MHD_destroy_response (response);
1621 if (MHD_YES != iret)
1622 {
1623 /* can't even send a reply, at least close the connection */
1624 CONNECTION_CLOSE_ERROR (connection,
1625 _ (
1626 "Closing connection (failed to queue response).\n"));
1627 return;
1628 }
1629 mhd_assert (NULL != connection->response);
1630 /* Do not reuse this connection. */
1631 connection->keepalive = MHD_CONN_MUST_CLOSE;
1632 if (MHD_NO == build_header_response (connection))
1633 {
1634 /* oops - close! */
1635 CONNECTION_CLOSE_ERROR (connection,
1636 _ (
1637 "Closing connection (failed to create response header).\n"));
1638 }
1639 else
1640 {
1642 }
1643}
1644
1645
1654static void
1656{
1657 /* Do not update states of suspended connection */
1658 if (connection->suspended)
1659 return; /* States will be updated after resume. */
1660#ifdef HTTPS_SUPPORT
1661 if (MHD_TLS_CONN_NO_TLS != connection->tls_state)
1662 { /* HTTPS connection. */
1663 switch (connection->tls_state)
1664 {
1665 case MHD_TLS_CONN_INIT:
1667 return;
1669 if (0 == gnutls_record_get_direction (connection->tls_session))
1671 else
1673 return;
1674 default:
1675 break;
1676 }
1677 }
1678#endif /* HTTPS_SUPPORT */
1679 while (1)
1680 {
1681#if DEBUG_STATES
1682 MHD_DLOG (connection->daemon,
1683 _ ("In function %s handling connection at state: %s\n"),
1684 __FUNCTION__,
1685 MHD_state_to_string (connection->state));
1686#endif
1687 switch (connection->state)
1688 {
1692 /* while reading headers, we always grow the
1693 read buffer if needed, no size-check required */
1694 if ( (connection->read_buffer_offset == connection->read_buffer_size) &&
1695 (! try_grow_read_buffer (connection, true)) )
1696 {
1697 transmit_error_response (connection,
1698 (connection->url != NULL)
1702 continue;
1703 }
1704 if (! connection->read_closed)
1706 else
1708 break;
1710 mhd_assert (0);
1711 break;
1713 mhd_assert (0);
1714 break;
1717 break;
1719 if (connection->read_buffer_offset == connection->read_buffer_size)
1720 {
1721 const bool internal_poll = (0 != (connection->daemon->options
1723 if ( (! try_grow_read_buffer (connection, true)) &&
1724 internal_poll)
1725 {
1726 /* failed to grow the read buffer, and the
1727 client which is supposed to handle the
1728 received data in a *blocking* fashion
1729 (in this mode) did not handle the data as
1730 it was supposed to!
1731 => we would either have to do busy-waiting
1732 (on the client, which would likely fail),
1733 or if we do nothing, we would just timeout
1734 on the connection (if a timeout is even
1735 set!).
1736 Solution: we kill the connection with an error */transmit_error_response (connection,
1739 continue;
1740 }
1741 }
1742 if ( (connection->read_buffer_offset < connection->read_buffer_size) &&
1743 (! connection->read_closed) )
1745 else
1747 break;
1750 /* while reading footers, we always grow the
1751 read buffer if needed, no size-check required */
1752 if (connection->read_closed)
1753 {
1754 CONNECTION_CLOSE_ERROR (connection,
1755 NULL);
1756 continue;
1757 }
1759 /* transition to FOOTERS_RECEIVED
1760 happens in read handler */
1761 break;
1764 break;
1766 /* headers in buffer, keep writing */
1768 break;
1770 mhd_assert (0);
1771 break;
1774 break;
1777 break;
1780 break;
1783 break;
1785 mhd_assert (0);
1786 break;
1789 break;
1791 mhd_assert (0);
1792 break;
1795 return; /* do nothing, not even reading */
1796#ifdef UPGRADE_SUPPORT
1797 case MHD_CONNECTION_UPGRADE:
1798 mhd_assert (0);
1799 break;
1800#endif /* UPGRADE_SUPPORT */
1801 default:
1802 mhd_assert (0);
1803 }
1804 break;
1805 }
1806}
1807
1808
1822static char *
1824 size_t *line_len)
1825{
1826 char *rbuf;
1827 size_t pos;
1828
1829 if (0 == connection->read_buffer_offset)
1830 return NULL;
1831 pos = 0;
1832 rbuf = connection->read_buffer;
1833 while ( (pos < connection->read_buffer_offset - 1) &&
1834 ('\r' != rbuf[pos]) &&
1835 ('\n' != rbuf[pos]) )
1836 pos++;
1837 if ( (pos == connection->read_buffer_offset - 1) &&
1838 ('\n' != rbuf[pos]) )
1839 {
1840 /* not found, consider growing... */
1841 if ( (connection->read_buffer_offset == connection->read_buffer_size) &&
1842 (! try_grow_read_buffer (connection, true)) )
1843 {
1844 transmit_error_response (connection,
1845 (NULL != connection->url)
1849 }
1850 if (line_len)
1851 *line_len = 0;
1852 return NULL;
1853 }
1854
1855 if (line_len)
1856 *line_len = pos;
1857 /* found, check if we have proper LFCR */
1858 if ( ('\r' == rbuf[pos]) &&
1859 ('\n' == rbuf[pos + 1]) )
1860 rbuf[pos++] = '\0'; /* skip both r and n */
1861 rbuf[pos++] = '\0';
1862 connection->read_buffer += pos;
1863 connection->read_buffer_size -= pos;
1864 connection->read_buffer_offset -= pos;
1865 return rbuf;
1866}
1867
1868
1882static enum MHD_Result
1884 const char *key,
1885 size_t key_size,
1886 const char *value,
1887 size_t value_size,
1888 enum MHD_ValueKind kind)
1889{
1890 if (MHD_NO ==
1891 MHD_set_connection_value_n (connection,
1892 kind,
1893 key,
1894 key_size,
1895 value,
1896 value_size))
1897 {
1898#ifdef HAVE_MESSAGES
1899 MHD_DLOG (connection->daemon,
1900 _ ("Not enough memory in pool to allocate header record!\n"));
1901#endif
1902 transmit_error_response (connection,
1905 return MHD_NO;
1906 }
1907 return MHD_YES;
1908}
1909
1910
1917static enum MHD_Result
1919{
1920 const char *hdr;
1921 size_t hdr_len;
1922 char *cpy;
1923 char *pos;
1924 char *sce;
1925 char *semicolon;
1926 char *equals;
1927 char *ekill;
1928 char *end;
1929 char old;
1930 int quotes;
1931
1932 if (MHD_NO == MHD_lookup_connection_value_n (connection,
1937 &hdr,
1938 &hdr_len))
1939 return MHD_YES;
1940 cpy = MHD_pool_allocate (connection->pool,
1941 hdr_len + 1,
1942 true);
1943 if (NULL == cpy)
1944 {
1945#ifdef HAVE_MESSAGES
1946 MHD_DLOG (connection->daemon,
1947 _ ("Not enough memory in pool to parse cookies!\n"));
1948#endif
1949 transmit_error_response (connection,
1952 return MHD_NO;
1953 }
1954 memcpy (cpy,
1955 hdr,
1956 hdr_len);
1957 cpy[hdr_len] = '\0';
1958 pos = cpy;
1959 while (NULL != pos)
1960 {
1961 while (' ' == *pos)
1962 pos++; /* skip spaces */
1963
1964 sce = pos;
1965 while ( ((*sce) != '\0') &&
1966 ((*sce) != ',') &&
1967 ((*sce) != ';') &&
1968 ((*sce) != '=') )
1969 sce++;
1970 /* remove tailing whitespace (if any) from key */
1971 ekill = sce - 1;
1972 while ( (*ekill == ' ') &&
1973 (ekill >= pos) )
1974 *(ekill--) = '\0';
1975 old = *sce;
1976 *sce = '\0';
1977 if (old != '=')
1978 {
1979 /* value part omitted, use empty string... */
1980 if (MHD_NO ==
1981 connection_add_header (connection,
1982 pos,
1983 ekill - pos + 1,
1984 "",
1985 0,
1987 return MHD_NO;
1988 if (old == '\0')
1989 break;
1990 pos = sce + 1;
1991 continue;
1992 }
1993 equals = sce + 1;
1994 quotes = 0;
1995 semicolon = equals;
1996 while ( ('\0' != semicolon[0]) &&
1997 ( (0 != quotes) ||
1998 ( (';' != semicolon[0]) &&
1999 (',' != semicolon[0]) ) ) )
2000 {
2001 if ('"' == semicolon[0])
2002 quotes = (quotes + 1) & 1;
2003 semicolon++;
2004 }
2005 end = semicolon;
2006 if ('\0' == semicolon[0])
2007 semicolon = NULL;
2008 if (NULL != semicolon)
2009 {
2010 semicolon[0] = '\0';
2011 semicolon++;
2012 }
2013 /* remove quotes */
2014 if ( ('"' == equals[0]) &&
2015 ('"' == end[-1]) )
2016 {
2017 equals++;
2018 end--;
2019 *end = '\0';
2020 }
2021 if (MHD_NO ==
2022 connection_add_header (connection,
2023 pos,
2024 ekill - pos + 1,
2025 equals,
2026 end - equals,
2028 return MHD_NO;
2029 pos = semicolon;
2030 }
2031 return MHD_YES;
2032}
2033
2034
2043static enum MHD_Result
2045 char *line,
2046 size_t line_len)
2047{
2048 struct MHD_Daemon *daemon = connection->daemon;
2049 const char *curi;
2050 char *uri;
2051 char *http_version;
2052 char *args;
2053 unsigned int unused_num_headers;
2054
2055 if (NULL == (uri = memchr (line,
2056 ' ',
2057 line_len)))
2058 return MHD_NO; /* serious error */
2059 uri[0] = '\0';
2060 connection->method = line;
2061 uri++;
2062 /* Skip any spaces. Not required by standard but allow
2063 to be more tolerant. */
2064 while ( (' ' == uri[0]) &&
2065 ( (size_t) (uri - line) < line_len) )
2066 uri++;
2067 if ((size_t) (uri - line) == line_len)
2068 {
2069 /* No URI and no http version given */
2070 curi = "";
2071 uri = NULL;
2072 connection->version = "";
2073 args = NULL;
2074 }
2075 else
2076 {
2077 size_t uri_len;
2078 curi = uri;
2079 /* Search from back to accept misformed URI with space */
2080 http_version = line + line_len - 1;
2081 /* Skip any trailing spaces */
2082 while ( (' ' == http_version[0]) &&
2083 (http_version > uri) )
2084 http_version--;
2085 /* Find first space in reverse direction */
2086 while ( (' ' != http_version[0]) &&
2087 (http_version > uri) )
2088 http_version--;
2089 if (http_version > uri)
2090 {
2091 /* http_version points to character before HTTP version string */
2092 http_version[0] = '\0';
2093 connection->version = http_version + 1;
2094 uri_len = http_version - uri;
2095 }
2096 else
2097 {
2098 connection->version = "";
2099 uri_len = line_len - (uri - line);
2100 }
2101 /* check for spaces in URI if we are "strict" */
2102 if ( (1 <= daemon->strict_for_client) &&
2103 (NULL != memchr (uri,
2104 ' ',
2105 uri_len)) )
2106 {
2107 /* space exists in URI and we are supposed to be strict, reject */
2108 return MHD_NO;
2109 }
2110
2111 args = memchr (uri,
2112 '?',
2113 uri_len);
2114 }
2115
2116 /* log callback before we modify URI *or* args */
2117 if (NULL != daemon->uri_log_callback)
2118 {
2119 connection->client_aware = true;
2120 connection->client_context
2121 = daemon->uri_log_callback (daemon->uri_log_callback_cls,
2122 uri,
2123 connection);
2124 }
2125
2126 if (NULL != args)
2127 {
2128 args[0] = '\0';
2129 args++;
2130 /* note that this call clobbers 'args' */
2131 MHD_parse_arguments_ (connection,
2133 args,
2135 &unused_num_headers);
2136 }
2137
2138 /* unescape URI *after* searching for arguments and log callback */
2139 if (NULL != uri)
2141 connection,
2142 uri);
2143 connection->url = curi;
2144 return MHD_YES;
2145}
2146
2147
2155static void
2157{
2158 struct MHD_Daemon *daemon = connection->daemon;
2159 size_t processed;
2160
2161 if (NULL != connection->response)
2162 return; /* already queued a response */
2163 processed = 0;
2164 connection->client_aware = true;
2165 if (MHD_NO ==
2166 daemon->default_handler (daemon->default_handler_cls,
2167 connection,
2168 connection->url,
2169 connection->method,
2170 connection->version,
2171 NULL,
2172 &processed,
2173 &connection->client_context))
2174 {
2175 /* serious internal error, close connection */
2176 CONNECTION_CLOSE_ERROR (connection,
2177 _ (
2178 "Application reported internal error, closing connection.\n"));
2179 return;
2180 }
2181}
2182
2183
2191static void
2193{
2194 struct MHD_Daemon *daemon = connection->daemon;
2195 size_t available;
2196 int instant_retry;
2197 char *buffer_head;
2198
2199 if (NULL != connection->response)
2200 {
2201 /* already queued a response, discard remaining upload
2202 (but not more, there might be another request after it) */
2203 uint64_t purge = MHD_MIN (connection->remaining_upload_size,
2204 connection->read_buffer_offset);
2205 connection->remaining_upload_size -= purge;
2206 if (connection->read_buffer_offset > purge)
2207 memmove (connection->read_buffer,
2208 &connection->read_buffer[purge],
2209 connection->read_buffer_offset - purge);
2210 connection->read_buffer_offset -= purge;
2211 return;
2212 }
2213
2214 buffer_head = connection->read_buffer;
2215 available = connection->read_buffer_offset;
2216 do
2217 {
2218 size_t to_be_processed;
2219 size_t left_unprocessed;
2220 size_t processed_size;
2221
2222 instant_retry = MHD_NO;
2223 if ( (connection->have_chunked_upload) &&
2224 (MHD_SIZE_UNKNOWN == connection->remaining_upload_size) )
2225 {
2226 if ( (connection->current_chunk_offset ==
2227 connection->current_chunk_size) &&
2228 (0LLU != connection->current_chunk_offset) &&
2229 (available >= 2) )
2230 {
2231 size_t i;
2232 /* skip new line at the *end* of a chunk */
2233 i = 0;
2234 if ( ('\r' == buffer_head[i]) ||
2235 ('\n' == buffer_head[i]) )
2236 i++; /* skip 1st part of line feed */
2237 if ( ('\r' == buffer_head[i]) ||
2238 ('\n' == buffer_head[i]) )
2239 i++; /* skip 2nd part of line feed */
2240 if (0 == i)
2241 {
2242 /* malformed encoding */
2243 CONNECTION_CLOSE_ERROR (connection,
2244 _ (
2245 "Received malformed HTTP request (bad chunked encoding). Closing connection.\n"));
2246 return;
2247 }
2248 available -= i;
2249 buffer_head += i;
2250 connection->current_chunk_offset = 0;
2251 connection->current_chunk_size = 0;
2252 }
2253 if (connection->current_chunk_offset <
2254 connection->current_chunk_size)
2255 {
2256 uint64_t cur_chunk_left;
2257 /* we are in the middle of a chunk, give
2258 as much as possible to the client (without
2259 crossing chunk boundaries) */
2260 cur_chunk_left
2261 = connection->current_chunk_size - connection->current_chunk_offset;
2262 if (cur_chunk_left > available)
2263 to_be_processed = available;
2264 else
2265 { /* cur_chunk_left <= (size_t)available */
2266 to_be_processed = (size_t) cur_chunk_left;
2267 if (available > to_be_processed)
2268 instant_retry = MHD_YES;
2269 }
2270 }
2271 else
2272 {
2273 size_t i;
2274 size_t end_size;
2275 bool malformed;
2276
2277 /* we need to read chunk boundaries */
2278 i = 0;
2279 while (i < available)
2280 {
2281 if ( ('\r' == buffer_head[i]) ||
2282 ('\n' == buffer_head[i]) ||
2283 (';' == buffer_head[i]) )
2284 break;
2285 i++;
2286 if (i >= 16)
2287 break;
2288 }
2289 end_size = i;
2290 /* find beginning of CRLF (skip over chunk extensions) */
2291 if (';' == buffer_head[i])
2292 {
2293 while (i < available)
2294 {
2295 if ( ('\r' == buffer_head[i]) ||
2296 ('\n' == buffer_head[i]) )
2297 break;
2298 i++;
2299 }
2300 }
2301 /* take '\n' into account; if '\n' is the unavailable
2302 character, we will need to wait until we have it
2303 before going further */
2304 if ( (i + 1 >= available) &&
2305 ! ( (1 == i) &&
2306 (2 == available) &&
2307 ('0' == buffer_head[0]) ) )
2308 break; /* need more data... */
2309 i++;
2310 malformed = (end_size >= 16);
2311 if (! malformed)
2312 {
2313 size_t num_dig = MHD_strx_to_uint64_n_ (buffer_head,
2314 end_size,
2315 &connection->
2316 current_chunk_size);
2317 malformed = (end_size != num_dig);
2318 }
2319 if (malformed)
2320 {
2321 /* malformed encoding */
2322 CONNECTION_CLOSE_ERROR (connection,
2323 _ (
2324 "Received malformed HTTP request (bad chunked encoding). Closing connection.\n"));
2325 return;
2326 }
2327 /* skip 2nd part of line feed */
2328 if ( (i < available) &&
2329 ( ('\r' == buffer_head[i]) ||
2330 ('\n' == buffer_head[i]) ) )
2331 i++;
2332
2333 buffer_head += i;
2334 available -= i;
2335 connection->current_chunk_offset = 0;
2336
2337 if (available > 0)
2338 instant_retry = MHD_YES;
2339 if (0LLU == connection->current_chunk_size)
2340 {
2341 connection->remaining_upload_size = 0;
2342 break;
2343 }
2344 continue;
2345 }
2346 }
2347 else
2348 {
2349 /* no chunked encoding, give all to the client */
2350 if ( (0 != connection->remaining_upload_size) &&
2351 (MHD_SIZE_UNKNOWN != connection->remaining_upload_size) &&
2352 (connection->remaining_upload_size < available) )
2353 {
2354 to_be_processed = (size_t) connection->remaining_upload_size;
2355 }
2356 else
2357 {
2362 to_be_processed = available;
2363 }
2364 }
2365 left_unprocessed = to_be_processed;
2366 connection->client_aware = true;
2367 if (MHD_NO ==
2368 daemon->default_handler (daemon->default_handler_cls,
2369 connection,
2370 connection->url,
2371 connection->method,
2372 connection->version,
2373 buffer_head,
2374 &left_unprocessed,
2375 &connection->client_context))
2376 {
2377 /* serious internal error, close connection */
2378 CONNECTION_CLOSE_ERROR (connection,
2379 _ (
2380 "Application reported internal error, closing connection.\n"));
2381 return;
2382 }
2383 if (left_unprocessed > to_be_processed)
2385 __FILE__,
2386 __LINE__
2387#ifdef HAVE_MESSAGES
2388 , _ ("libmicrohttpd API violation.\n")
2389#else
2390 , NULL
2391#endif
2392 );
2393 if (0 != left_unprocessed)
2394 {
2395 instant_retry = MHD_NO; /* client did not process everything */
2396#ifdef HAVE_MESSAGES
2397 /* client did not process all upload data, complain if
2398 the setup was incorrect, which may prevent us from
2399 handling the rest of the request */
2400 if ( (0 != (daemon->options & MHD_USE_INTERNAL_POLLING_THREAD)) &&
2401 (! connection->suspended) )
2402 MHD_DLOG (daemon,
2403 _ (
2404 "WARNING: incomplete upload processing and connection not suspended may result in hung connection.\n"));
2405#endif
2406 }
2407 processed_size = to_be_processed - left_unprocessed;
2408 if (connection->have_chunked_upload)
2409 connection->current_chunk_offset += processed_size;
2410 /* dh left "processed" bytes in buffer for next time... */
2411 buffer_head += processed_size;
2412 available -= processed_size;
2413 if (MHD_SIZE_UNKNOWN != connection->remaining_upload_size)
2414 connection->remaining_upload_size -= processed_size;
2415 }
2416 while (MHD_YES == instant_retry);
2417 if ( (available > 0) &&
2418 (buffer_head != connection->read_buffer) )
2419 memmove (connection->read_buffer,
2420 buffer_head,
2421 available);
2422 connection->read_buffer_offset = available;
2423}
2424
2425
2434static enum MHD_Result
2436 enum MHD_CONNECTION_STATE next_state)
2437{
2438 if (connection->write_buffer_append_offset !=
2439 connection->write_buffer_send_offset)
2440 return MHD_NO;
2441 connection->write_buffer_append_offset = 0;
2442 connection->write_buffer_send_offset = 0;
2443 connection->state = next_state;
2444 MHD_pool_reallocate (connection->pool,
2445 connection->write_buffer,
2446 connection->write_buffer_size,
2447 0);
2448 connection->write_buffer = NULL;
2449 connection->write_buffer_size = 0;
2450 return MHD_YES;
2451}
2452
2453
2463static enum MHD_Result
2465 char *line)
2466{
2467 char *colon;
2468
2469 /* line should be normal header line, find colon */
2470 colon = strchr (line, ':');
2471 if (NULL == colon)
2472 {
2473 /* error in header line, die hard */
2474 CONNECTION_CLOSE_ERROR (connection,
2475 _ (
2476 "Received malformed line (no colon). Closing connection.\n"));
2477 return MHD_NO;
2478 }
2479 if (-1 >= connection->daemon->strict_for_client)
2480 {
2481 /* check for whitespace before colon, which is not allowed
2482 by RFC 7230 section 3.2.4; we count space ' ' and
2483 tab '\t', but not '\r\n' as those would have ended the line. */
2484 const char *white;
2485
2486 white = strchr (line, ' ');
2487 if ( (NULL != white) &&
2488 (white < colon) )
2489 return MHD_NO;
2490 white = strchr (line, '\t');
2491 if ( (NULL != white) &&
2492 (white < colon) )
2493 return MHD_NO;
2494 }
2495 /* zero-terminate header */
2496 colon[0] = '\0';
2497 colon++; /* advance to value */
2498 while ( ('\0' != colon[0]) &&
2499 ( (' ' == colon[0]) ||
2500 ('\t' == colon[0]) ) )
2501 colon++;
2502 /* we do the actual adding of the connection
2503 header at the beginning of the while
2504 loop since we need to be able to inspect
2505 the *next* header line (in case it starts
2506 with a space...) */connection->last = line;
2507 connection->colon = colon;
2508 return MHD_YES;
2509}
2510
2511
2522static enum MHD_Result
2524 char *line,
2525 enum MHD_ValueKind kind)
2526{
2527 char *last;
2528 char *tmp;
2529 size_t last_len;
2530 size_t tmp_len;
2531
2532 last = connection->last;
2533 if ( (' ' == line[0]) ||
2534 ('\t' == line[0]) )
2535 {
2536 /* value was continued on the next line, see
2537 http://www.jmarshall.com/easy/http/ */
2538 last_len = strlen (last);
2539 /* skip whitespace at start of 2nd line */
2540 tmp = line;
2541 while ( (' ' == tmp[0]) ||
2542 ('\t' == tmp[0]) )
2543 tmp++;
2544 tmp_len = strlen (tmp);
2545 /* FIXME: we might be able to do this better (faster!), as most
2546 likely 'last' and 'line' should already be adjacent in
2547 memory; however, doing this right gets tricky if we have a
2548 value continued over multiple lines (in which case we need to
2549 record how often we have done this so we can check for
2550 adjacency); also, in the case where these are not adjacent
2551 (not sure how it can happen!), we would want to allocate from
2552 the end of the pool, so as to not destroy the read-buffer's
2553 ability to grow nicely. */last = MHD_pool_reallocate (connection->pool,
2554 last,
2555 last_len + 1,
2556 last_len + tmp_len + 1);
2557 if (NULL == last)
2558 {
2559 transmit_error_response (connection,
2562 return MHD_NO;
2563 }
2564 memcpy (&last[last_len],
2565 tmp,
2566 tmp_len + 1);
2567 connection->last = last;
2568 return MHD_YES; /* possibly more than 2 lines... */
2569 }
2570 mhd_assert ( (NULL != last) &&
2571 (NULL != connection->colon) );
2572 if (MHD_NO ==
2573 connection_add_header (connection,
2574 last,
2575 strlen (last),
2576 connection->colon,
2577 strlen (connection->colon),
2578 kind))
2579 {
2580 transmit_error_response (connection,
2583 return MHD_NO;
2584 }
2585 /* we still have the current line to deal with... */
2586 if (0 != line[0])
2587 {
2588 if (MHD_NO == process_header_line (connection,
2589 line))
2590 {
2591 transmit_error_response (connection,
2594 return MHD_NO;
2595 }
2596 }
2597 return MHD_YES;
2598}
2599
2600
2608static void
2610{
2611 const char *clen;
2612 struct MHD_Response *response;
2613 const char *enc;
2614 const char *end;
2615
2616 parse_cookie_header (connection);
2617 if ( (1 <= connection->daemon->strict_for_client) &&
2618 (NULL != connection->version) &&
2620 connection->version)) &&
2621 (MHD_NO ==
2627 NULL,
2628 NULL)) )
2629 {
2630 enum MHD_Result iret;
2631
2632 /* die, http 1.1 request without host and we are pedantic */
2634 connection->read_closed = true;
2635#ifdef HAVE_MESSAGES
2636 MHD_DLOG (connection->daemon,
2637 _ ("Received HTTP 1.1 request without `Host' header.\n"));
2638#endif
2639 mhd_assert (NULL == connection->response);
2640 response =
2644 if (NULL == response)
2645 {
2646 /* can't even send a reply, at least close the connection */
2647 CONNECTION_CLOSE_ERROR (connection,
2648 _ (
2649 "Closing connection (failed to create response).\n"));
2650 return;
2651 }
2652 iret = MHD_queue_response (connection,
2654 response);
2655 MHD_destroy_response (response);
2656 if (MHD_YES != iret)
2657 {
2658 /* can't even send a reply, at least close the connection */
2659 CONNECTION_CLOSE_ERROR (connection,
2660 _ (
2661 "Closing connection (failed to queue response).\n"));
2662 }
2663 return;
2664 }
2665
2666 connection->remaining_upload_size = 0;
2667 if (MHD_NO != MHD_lookup_connection_value_n (connection,
2672 &enc,
2673 NULL))
2674 {
2676 if (MHD_str_equal_caseless_ (enc,
2677 "chunked"))
2678 connection->have_chunked_upload = true;
2679 }
2680 else
2681 {
2682 if (MHD_NO != MHD_lookup_connection_value_n (connection,
2687 &clen,
2688 NULL))
2689 {
2690 end = clen + MHD_str_to_uint64_ (clen,
2691 &connection->remaining_upload_size);
2692 if ( (clen == end) ||
2693 ('\0' != *end) )
2694 {
2695 connection->remaining_upload_size = 0;
2696#ifdef HAVE_MESSAGES
2697 MHD_DLOG (connection->daemon,
2698 "Failed to parse `Content-Length' header. Closing connection.\n");
2699#endif
2700 CONNECTION_CLOSE_ERROR (connection,
2701 NULL);
2702 return;
2703 }
2704 }
2705 }
2706}
2707
2708
2716void
2718{
2719 struct MHD_Daemon *daemon = connection->daemon;
2720
2721 if (0 == connection->connection_timeout)
2722 return; /* Skip update of activity for connections
2723 without timeout timer. */
2724 if (connection->suspended)
2725 return; /* no activity on suspended connections */
2726
2728 if (0 != (daemon->options & MHD_USE_THREAD_PER_CONNECTION))
2729 return; /* each connection has personal timeout */
2730
2731 if (connection->connection_timeout != daemon->connection_timeout)
2732 return; /* custom timeout, no need to move it in "normal" DLL */
2733#if defined(MHD_USE_POSIX_THREADS) || defined(MHD_USE_W32_THREADS)
2735#endif
2736 /* move connection to head of timeout list (by remove + add operation) */
2738 daemon->normal_timeout_tail,
2739 connection);
2741 daemon->normal_timeout_tail,
2742 connection);
2743#if defined(MHD_USE_POSIX_THREADS) || defined(MHD_USE_W32_THREADS)
2745#endif
2746}
2747
2748
2755void
2757{
2758 ssize_t bytes_read;
2759
2760 if ( (MHD_CONNECTION_CLOSED == connection->state) ||
2761 (connection->suspended) )
2762 return;
2763#ifdef HTTPS_SUPPORT
2764 if (MHD_TLS_CONN_NO_TLS != connection->tls_state)
2765 { /* HTTPS connection. */
2766 if (MHD_TLS_CONN_CONNECTED > connection->tls_state)
2767 {
2768 if (! MHD_run_tls_handshake_ (connection))
2769 return;
2770 }
2771 }
2772#endif /* HTTPS_SUPPORT */
2773
2774 /* make sure "read" has a reasonable number of bytes
2775 in buffer to use per system call (if possible) */
2776 if (connection->read_buffer_offset + connection->daemon->pool_increment >
2777 connection->read_buffer_size)
2778 try_grow_read_buffer (connection,
2779 (connection->read_buffer_size ==
2780 connection->read_buffer_offset));
2781
2782 if (connection->read_buffer_size == connection->read_buffer_offset)
2783 return; /* No space for receiving data. */
2784 bytes_read = connection->recv_cls (connection,
2785 &connection->read_buffer
2786 [connection->read_buffer_offset],
2787 connection->read_buffer_size
2788 - connection->read_buffer_offset);
2789 if (bytes_read < 0)
2790 {
2791 if (MHD_ERR_AGAIN_ == bytes_read)
2792 return; /* No new data to process. */
2793 if (MHD_ERR_CONNRESET_ == bytes_read)
2794 {
2795 CONNECTION_CLOSE_ERROR (connection,
2796 (MHD_CONNECTION_INIT == connection->state) ?
2797 NULL :
2798 _ (
2799 "Socket disconnected while reading request.\n"));
2800 return;
2801 }
2802 CONNECTION_CLOSE_ERROR (connection,
2803 (MHD_CONNECTION_INIT == connection->state) ?
2804 NULL :
2805 _ (
2806 "Connection socket is closed due to error when reading request.\n"));
2807 return;
2808 }
2809
2810 if (0 == bytes_read)
2811 { /* Remote side closed connection. */
2812 connection->read_closed = true;
2813 MHD_connection_close_ (connection,
2815 return;
2816 }
2817 connection->read_buffer_offset += bytes_read;
2818 MHD_update_last_activity_ (connection);
2819#if DEBUG_STATES
2820 MHD_DLOG (connection->daemon,
2821 _ ("In function %s handling connection at state: %s\n"),
2822 __FUNCTION__,
2823 MHD_state_to_string (connection->state));
2824#endif
2825 switch (connection->state)
2826 {
2836 /* nothing to do but default action */
2837 if (connection->read_closed)
2838 {
2839 MHD_connection_close_ (connection,
2841 }
2842 return;
2844 return;
2845#ifdef UPGRADE_SUPPORT
2846 case MHD_CONNECTION_UPGRADE:
2847 mhd_assert (0);
2848 return;
2849#endif /* UPGRADE_SUPPORT */
2850 default:
2851 /* shrink read buffer to how much is actually used */
2852 MHD_pool_reallocate (connection->pool,
2853 connection->read_buffer,
2854 connection->read_buffer_size + 1,
2855 connection->read_buffer_offset);
2856 break;
2857 }
2858 return;
2859}
2860
2861
2868void
2870{
2871 struct MHD_Response *response;
2872 ssize_t ret;
2873 if (connection->suspended)
2874 return;
2875
2876#ifdef HTTPS_SUPPORT
2877 if (MHD_TLS_CONN_NO_TLS != connection->tls_state)
2878 { /* HTTPS connection. */
2879 if (MHD_TLS_CONN_CONNECTED > connection->tls_state)
2880 {
2881 if (! MHD_run_tls_handshake_ (connection))
2882 return;
2883 }
2884 }
2885#endif /* HTTPS_SUPPORT */
2886
2887#if DEBUG_STATES
2888 MHD_DLOG (connection->daemon,
2889 _ ("In function %s handling connection at state: %s\n"),
2890 __FUNCTION__,
2891 MHD_state_to_string (connection->state));
2892#endif
2893 switch (connection->state)
2894 {
2899 mhd_assert (0);
2900 return;
2902 return;
2904 ret = MHD_send_on_connection_ (connection,
2906 [connection->continue_message_write_offset],
2908 - connection->continue_message_write_offset,
2910 if (ret < 0)
2911 {
2912 if (MHD_ERR_AGAIN_ == ret)
2913 return;
2914#ifdef HAVE_MESSAGES
2915 MHD_DLOG (connection->daemon,
2916 _ ("Failed to send data in request for %s.\n"),
2917 connection->url);
2918#endif
2919 CONNECTION_CLOSE_ERROR (connection,
2920 NULL);
2921 return;
2922 }
2923#if DEBUG_SEND_DATA
2924 fprintf (stderr,
2925 _ ("Sent 100 continue response: `%.*s'\n"),
2926 (int) ret,
2928#endif
2929 connection->continue_message_write_offset += ret;
2930 MHD_update_last_activity_ (connection);
2931 return;
2936 mhd_assert (0);
2937 return;
2939 {
2940 const size_t wb_ready = connection->write_buffer_append_offset
2941 - connection->write_buffer_send_offset;
2942
2943 /* if the response body is not available, we use MHD_send_on_connection_() */
2944 if (NULL != connection->response->crc)
2945 {
2946 ret = MHD_send_on_connection_ (connection,
2947 &connection->write_buffer
2948 [connection->write_buffer_send_offset],
2949 wb_ready,
2951 }
2952 else
2953 {
2954 ret = MHD_send_on_connection2_ (connection,
2955 &connection->write_buffer
2956 [connection->write_buffer_send_offset],
2957 wb_ready,
2958 connection->response->data,
2959 connection->response->data_buffer_size);
2960 }
2961
2962 if (ret < 0)
2963 {
2964 if (MHD_ERR_AGAIN_ == ret)
2965 return;
2966 CONNECTION_CLOSE_ERROR (connection,
2967 _ (
2968 "Connection was closed while sending response headers.\n"));
2969 return;
2970 }
2971 if (ret > wb_ready)
2972 {
2973 mhd_assert (NULL == connection->response->crc);
2974 /* We sent not just header data but also some response data,
2975 update both offsets! */
2976 connection->write_buffer_send_offset += wb_ready;
2977 ret -= wb_ready;
2978 connection->response_write_position += ret;
2979 }
2980 else
2981 connection->write_buffer_send_offset += ret;
2982 MHD_update_last_activity_ (connection);
2983 if (MHD_CONNECTION_HEADERS_SENDING != connection->state)
2984 return;
2985 check_write_done (connection,
2987 return;
2988 }
2990 return;
2992 response = connection->response;
2993 if (connection->response_write_position <
2994 connection->response->total_size)
2995 {
2996 uint64_t data_write_offset;
2997
2998#if defined(MHD_USE_POSIX_THREADS) || defined(MHD_USE_W32_THREADS)
2999 if (NULL != response->crc)
3000 MHD_mutex_lock_chk_ (&response->mutex);
3001#endif
3002 if (MHD_YES != try_ready_normal_body (connection))
3003 {
3004 /* mutex was already unlocked by try_ready_normal_body */
3005 return;
3006 }
3007#if defined(_MHD_HAVE_SENDFILE)
3008 if (MHD_resp_sender_sendfile == connection->resp_sender)
3009 {
3010 ret = MHD_send_sendfile_ (connection);
3011 }
3012 else
3013#else /* ! _MHD_HAVE_SENDFILE */
3014 if (1)
3015#endif /* ! _MHD_HAVE_SENDFILE */
3016 {
3017 data_write_offset = connection->response_write_position
3018 - response->data_start;
3019 if (data_write_offset > (uint64_t) SIZE_MAX)
3020 MHD_PANIC (_ ("Data offset exceeds limit.\n"));
3021 ret = MHD_send_on_connection_ (connection,
3022 &response->data
3023 [(size_t) data_write_offset],
3024 response->data_size
3025 - (size_t) data_write_offset,
3027#if DEBUG_SEND_DATA
3028 if (ret > 0)
3029 fprintf (stderr,
3030 _ ("Sent %d-byte DATA response: `%.*s'\n"),
3031 (int) ret,
3032 (int) ret,
3033 &response->data[connection->response_write_position
3034 - response->data_start]);
3035#endif
3036 }
3037#if defined(MHD_USE_POSIX_THREADS) || defined(MHD_USE_W32_THREADS)
3038 if (NULL != response->crc)
3039 MHD_mutex_unlock_chk_ (&response->mutex);
3040#endif
3041 if (ret < 0)
3042 {
3043 if (MHD_ERR_AGAIN_ == ret)
3044 return;
3045#ifdef HAVE_MESSAGES
3046 MHD_DLOG (connection->daemon,
3047 _ ("Failed to send data in request for `%s'.\n"),
3048 connection->url);
3049#endif
3050 CONNECTION_CLOSE_ERROR (connection,
3051 NULL);
3052 return;
3053 }
3054 connection->response_write_position += ret;
3055 MHD_update_last_activity_ (connection);
3056 }
3057 if (connection->response_write_position ==
3058 connection->response->total_size)
3059 connection->state = MHD_CONNECTION_FOOTERS_SENT; /* have no footers */
3060 return;
3062 mhd_assert (0);
3063 return;
3065 ret = MHD_send_on_connection_ (connection,
3066 &connection->write_buffer
3067 [connection->write_buffer_send_offset],
3068 connection->write_buffer_append_offset
3069 - connection->write_buffer_send_offset,
3071 if (ret < 0)
3072 {
3073 if (MHD_ERR_AGAIN_ == ret)
3074 return;
3075 CONNECTION_CLOSE_ERROR (connection,
3076 _ (
3077 "Connection was closed while sending response body.\n"));
3078 return;
3079 }
3080 connection->write_buffer_send_offset += ret;
3081 MHD_update_last_activity_ (connection);
3082 if (MHD_CONNECTION_CHUNKED_BODY_READY != connection->state)
3083 return;
3084 check_write_done (connection,
3085 (connection->response->total_size ==
3086 connection->response_write_position) ?
3089 return;
3092 mhd_assert (0);
3093 return;
3095 ret = MHD_send_on_connection_ (connection,
3096 &connection->write_buffer
3097 [connection->write_buffer_send_offset],
3098 connection->write_buffer_append_offset
3099 - connection->write_buffer_send_offset,
3101 if (ret < 0)
3102 {
3103 if (MHD_ERR_AGAIN_ == ret)
3104 return;
3105 CONNECTION_CLOSE_ERROR (connection,
3106 _ (
3107 "Connection was closed while sending response body.\n"));
3108 return;
3109 }
3110 connection->write_buffer_send_offset += ret;
3111 MHD_update_last_activity_ (connection);
3112 if (MHD_CONNECTION_FOOTERS_SENDING != connection->state)
3113 return;
3114 check_write_done (connection,
3116 return;
3118 mhd_assert (0);
3119 return;
3121 return;
3122#ifdef UPGRADE_SUPPORT
3123 case MHD_CONNECTION_UPGRADE:
3124 mhd_assert (0);
3125 return;
3126#endif /* UPGRADE_SUPPORT */
3127 default:
3128 mhd_assert (0);
3129 CONNECTION_CLOSE_ERROR (connection,
3130 _ ("Internal error.\n"));
3131 break;
3132 }
3133 return;
3134}
3135
3136
3145static void
3147{
3148 struct MHD_Daemon *daemon = connection->daemon;
3149
3150 if (connection->in_cleanup)
3151 return; /* Prevent double cleanup. */
3152 connection->in_cleanup = true;
3153 if (NULL != connection->response)
3154 {
3155 MHD_destroy_response (connection->response);
3156 connection->response = NULL;
3157 }
3158#if defined(MHD_USE_POSIX_THREADS) || defined(MHD_USE_W32_THREADS)
3160#endif
3161 if (connection->suspended)
3162 {
3165 connection);
3166 connection->suspended = false;
3167 }
3168 else
3169 {
3170 if (0 == (daemon->options & MHD_USE_THREAD_PER_CONNECTION))
3171 {
3172 if (connection->connection_timeout == daemon->connection_timeout)
3174 daemon->normal_timeout_tail,
3175 connection);
3176 else
3178 daemon->manual_timeout_tail,
3179 connection);
3180 }
3182 daemon->connections_tail,
3183 connection);
3184 }
3185 DLL_insert (daemon->cleanup_head,
3186 daemon->cleanup_tail,
3187 connection);
3188 connection->resuming = false;
3189 connection->in_idle = false;
3190#if defined(MHD_USE_POSIX_THREADS) || defined(MHD_USE_W32_THREADS)
3192#endif
3193 if (0 != (daemon->options & MHD_USE_THREAD_PER_CONNECTION))
3194 {
3195 /* if we were at the connection limit before and are in
3196 thread-per-connection mode, signal the main thread
3197 to resume accepting connections */
3198 if ( (MHD_ITC_IS_VALID_ (daemon->itc)) &&
3199 (! MHD_itc_activate_ (daemon->itc, "c")) )
3200 {
3201#ifdef HAVE_MESSAGES
3202 MHD_DLOG (daemon,
3203 _ (
3204 "Failed to signal end of connection via inter-thread communication channel.\n"));
3205#endif
3206 }
3207 }
3208}
3209
3210
3221enum MHD_Result
3223{
3224 struct MHD_Daemon *daemon = connection->daemon;
3225 char *line;
3226 size_t line_len;
3227 enum MHD_Result ret;
3228
3229 connection->in_idle = true;
3230 while (! connection->suspended)
3231 {
3232#ifdef HTTPS_SUPPORT
3233 if (MHD_TLS_CONN_NO_TLS != connection->tls_state)
3234 { /* HTTPS connection. */
3235 if ((MHD_TLS_CONN_INIT <= connection->tls_state) &&
3236 (MHD_TLS_CONN_CONNECTED > connection->tls_state))
3237 break;
3238 }
3239#endif /* HTTPS_SUPPORT */
3240#if DEBUG_STATES
3241 MHD_DLOG (daemon,
3242 _ ("In function %s handling connection at state: %s\n"),
3243 __FUNCTION__,
3244 MHD_state_to_string (connection->state));
3245#endif
3246 switch (connection->state)
3247 {
3249 line = get_next_header_line (connection,
3250 &line_len);
3251 /* Check for empty string, as we might want
3252 to tolerate 'spurious' empty lines; also
3253 NULL means we didn't get a full line yet;
3254 line is not 0-terminated here. */
3255 if ( (NULL == line) ||
3256 (0 == line[0]) )
3257 {
3258 if (MHD_CONNECTION_INIT != connection->state)
3259 continue;
3260 if (connection->read_closed)
3261 {
3262 CONNECTION_CLOSE_ERROR (connection,
3263 NULL);
3264 continue;
3265 }
3266 break;
3267 }
3268 if (MHD_NO == parse_initial_message_line (connection,
3269 line,
3270 line_len))
3271 CONNECTION_CLOSE_ERROR (connection,
3272 NULL);
3273 else
3274 connection->state = MHD_CONNECTION_URL_RECEIVED;
3275 continue;
3277 line = get_next_header_line (connection,
3278 NULL);
3279 if (NULL == line)
3280 {
3281 if (MHD_CONNECTION_URL_RECEIVED != connection->state)
3282 continue;
3283 if (connection->read_closed)
3284 {
3285 CONNECTION_CLOSE_ERROR (connection,
3286 NULL);
3287 continue;
3288 }
3289 break;
3290 }
3291 if (0 == line[0])
3292 {
3294 connection->header_size = (size_t) (line - connection->read_buffer);
3295 continue;
3296 }
3297 if (MHD_NO == process_header_line (connection,
3298 line))
3299 {
3300 transmit_error_response (connection,
3303 break;
3304 }
3306 continue;
3308 line = get_next_header_line (connection,
3309 NULL);
3310 if (NULL == line)
3311 {
3312 if (connection->state != MHD_CONNECTION_HEADER_PART_RECEIVED)
3313 continue;
3314 if (connection->read_closed)
3315 {
3316 CONNECTION_CLOSE_ERROR (connection,
3317 NULL);
3318 continue;
3319 }
3320 break;
3321 }
3322 if (MHD_NO ==
3323 process_broken_line (connection,
3324 line,
3326 continue;
3327 if (0 == line[0])
3328 {
3330 connection->header_size = (size_t) (line - connection->read_buffer);
3331 continue;
3332 }
3333 continue;
3335 parse_connection_headers (connection);
3336 if (MHD_CONNECTION_CLOSED == connection->state)
3337 continue;
3339 if (connection->suspended)
3340 break;
3341 continue;
3343 call_connection_handler (connection); /* first call */
3344 if (MHD_CONNECTION_CLOSED == connection->state)
3345 continue;
3346 if (connection->suspended)
3347 continue;
3348 if ( (NULL == connection->response) &&
3349 (need_100_continue (connection)) )
3350 {
3352 break;
3353 }
3354 if ( (NULL != connection->response) &&
3355 (0 != connection->remaining_upload_size) )
3356 {
3357 /* we refused (no upload allowed!) */
3358 connection->remaining_upload_size = 0;
3359 /* force close, in case client still tries to upload... */
3360 connection->read_closed = true;
3361 }
3362 connection->state = (0 == connection->remaining_upload_size)
3365 if (connection->suspended)
3366 break;
3367 continue;
3369 if (connection->continue_message_write_offset ==
3371 {
3372 connection->state = MHD_CONNECTION_CONTINUE_SENT;
3373 continue;
3374 }
3375 break;
3377 if (0 != connection->read_buffer_offset)
3378 {
3379 process_request_body (connection); /* loop call */
3380 if (MHD_CONNECTION_CLOSED == connection->state)
3381 continue;
3382 }
3383 if ( (0 == connection->remaining_upload_size) ||
3384 ( (MHD_SIZE_UNKNOWN == connection->remaining_upload_size) &&
3385 (0 == connection->read_buffer_offset) &&
3386 (connection->read_closed) ) )
3387 {
3388 if ( (connection->have_chunked_upload) &&
3389 (! connection->read_closed) )
3390 connection->state = MHD_CONNECTION_BODY_RECEIVED;
3391 else
3393 if (connection->suspended)
3394 break;
3395 continue;
3396 }
3397 break;
3399 line = get_next_header_line (connection,
3400 NULL);
3401 if (NULL == line)
3402 {
3403 if (connection->state != MHD_CONNECTION_BODY_RECEIVED)
3404 continue;
3405 if (connection->read_closed)
3406 {
3407 CONNECTION_CLOSE_ERROR (connection,
3408 NULL);
3409 continue;
3410 }
3411 break;
3412 }
3413 if (0 == line[0])
3414 {
3416 if (connection->suspended)
3417 break;
3418 continue;
3419 }
3420 if (MHD_NO == process_header_line (connection,
3421 line))
3422 {
3423 transmit_error_response (connection,
3426 break;
3427 }
3429 continue;
3431 line = get_next_header_line (connection,
3432 NULL);
3433 if (NULL == line)
3434 {
3435 if (connection->state != MHD_CONNECTION_FOOTER_PART_RECEIVED)
3436 continue;
3437 if (connection->read_closed)
3438 {
3439 CONNECTION_CLOSE_ERROR (connection,
3440 NULL);
3441 continue;
3442 }
3443 break;
3444 }
3445 if (MHD_NO ==
3446 process_broken_line (connection,
3447 line,
3449 continue;
3450 if (0 == line[0])
3451 {
3453 if (connection->suspended)
3454 break;
3455 continue;
3456 }
3457 continue;
3459 call_connection_handler (connection); /* "final" call */
3460 if (connection->state == MHD_CONNECTION_CLOSED)
3461 continue;
3462 if (NULL == connection->response)
3463 break; /* try again next time */
3464 if (MHD_NO == build_header_response (connection))
3465 {
3466 /* oops - close! */
3467 CONNECTION_CLOSE_ERROR (connection,
3468 _ (
3469 "Closing connection (failed to create response header).\n"));
3470 continue;
3471 }
3473 break;
3475 /* no default action */
3476 break;
3478 /* Some clients may take some actions right after header receive */
3479#ifdef UPGRADE_SUPPORT
3480 if (NULL != connection->response->upgrade_handler)
3481 {
3482 connection->state = MHD_CONNECTION_UPGRADE;
3483 /* This connection is "upgraded". Pass socket to application. */
3484 if (MHD_YES !=
3486 connection))
3487 {
3488 /* upgrade failed, fail hard */
3489 CONNECTION_CLOSE_ERROR (connection,
3490 NULL);
3491 continue;
3492 }
3493 /* Response is not required anymore for this connection. */
3494 {
3495 struct MHD_Response *const resp = connection->response;
3496
3497 connection->response = NULL;
3498 MHD_destroy_response (resp);
3499 }
3500 continue;
3501 }
3502#endif /* UPGRADE_SUPPORT */
3503
3504 if (connection->have_chunked_upload)
3506 else
3508 continue;
3510 /* nothing to do here */
3511 break;
3513#if defined(MHD_USE_POSIX_THREADS) || defined(MHD_USE_W32_THREADS)
3514 if (NULL != connection->response->crc)
3515 MHD_mutex_lock_chk_ (&connection->response->mutex);
3516#endif
3517 if (0 == connection->response->total_size)
3518 {
3519#if defined(MHD_USE_POSIX_THREADS) || defined(MHD_USE_W32_THREADS)
3520 if (NULL != connection->response->crc)
3521 MHD_mutex_unlock_chk_ (&connection->response->mutex);
3522#endif
3523 connection->state = MHD_CONNECTION_BODY_SENT;
3524 continue;
3525 }
3526 if (MHD_YES == try_ready_normal_body (connection))
3527 {
3528#if defined(MHD_USE_POSIX_THREADS) || defined(MHD_USE_W32_THREADS)
3529 if (NULL != connection->response->crc)
3530 MHD_mutex_unlock_chk_ (&connection->response->mutex);
3531#endif
3533 /* Buffering for flushable socket was already enabled*/
3534
3535 break;
3536 }
3537 /* mutex was already unlocked by "try_ready_normal_body */
3538 /* not ready, no socket action */
3539 break;
3541 /* nothing to do here */
3542 break;
3544#if defined(MHD_USE_POSIX_THREADS) || defined(MHD_USE_W32_THREADS)
3545 if (NULL != connection->response->crc)
3546 MHD_mutex_lock_chk_ (&connection->response->mutex);
3547#endif
3548 if ( (0 == connection->response->total_size) ||
3549 (connection->response_write_position ==
3550 connection->response->total_size) )
3551 {
3552#if defined(MHD_USE_POSIX_THREADS) || defined(MHD_USE_W32_THREADS)
3553 if (NULL != connection->response->crc)
3554 MHD_mutex_unlock_chk_ (&connection->response->mutex);
3555#endif
3556 connection->state = MHD_CONNECTION_BODY_SENT;
3557 continue;
3558 }
3559 if (MHD_YES == try_ready_chunked_body (connection))
3560 {
3561#if defined(MHD_USE_POSIX_THREADS) || defined(MHD_USE_W32_THREADS)
3562 if (NULL != connection->response->crc)
3563 MHD_mutex_unlock_chk_ (&connection->response->mutex);
3564#endif
3566 /* Buffering for flushable socket was already enabled */
3567
3568 continue;
3569 }
3570 /* mutex was already unlocked by try_ready_chunked_body */
3571 break;
3573 if (MHD_NO == build_header_response (connection))
3574 {
3575 /* oops - close! */
3576 CONNECTION_CLOSE_ERROR (connection,
3577 _ (
3578 "Closing connection (failed to create response header).\n"));
3579 continue;
3580 }
3581 if ( (! connection->have_chunked_upload) ||
3582 (connection->write_buffer_send_offset ==
3583 connection->write_buffer_append_offset) )
3584 connection->state = MHD_CONNECTION_FOOTERS_SENT;
3585 else
3587 continue;
3589 /* no default action */
3590 break;
3592 if (MHD_HTTP_PROCESSING == connection->responseCode)
3593 {
3594 /* After this type of response, we allow sending another! */
3596 MHD_destroy_response (connection->response);
3597 connection->response = NULL;
3598 /* FIXME: maybe partially reset memory pool? */
3599 continue;
3600 }
3601 MHD_destroy_response (connection->response);
3602 connection->response = NULL;
3603 if ( (NULL != daemon->notify_completed) &&
3604 (connection->client_aware) )
3605 {
3606 daemon->notify_completed (daemon->notify_completed_cls,
3607 connection,
3608 &connection->client_context,
3610 }
3611 connection->client_aware = false;
3612 if ( (MHD_CONN_USE_KEEPALIVE != connection->keepalive) ||
3613 (connection->read_closed) )
3614 {
3615 /* have to close for some reason */
3616 MHD_connection_close_ (connection,
3618 MHD_pool_destroy (connection->pool);
3619 connection->pool = NULL;
3620 connection->read_buffer = NULL;
3621 connection->read_buffer_size = 0;
3622 connection->read_buffer_offset = 0;
3623 }
3624 else
3625 {
3626 /* can try to keep-alive */
3627
3628 connection->version = NULL;
3629 connection->state = MHD_CONNECTION_INIT;
3630 connection->last = NULL;
3631 connection->colon = NULL;
3632 connection->header_size = 0;
3634 /* Reset the read buffer to the starting size,
3635 preserving the bytes we have already read. */
3636 connection->read_buffer
3637 = MHD_pool_reset (connection->pool,
3638 connection->read_buffer,
3639 connection->read_buffer_offset,
3640 connection->daemon->pool_size / 2);
3641 connection->read_buffer_size
3642 = connection->daemon->pool_size / 2;
3643 }
3644 connection->client_context = NULL;
3645 connection->continue_message_write_offset = 0;
3646 connection->responseCode = 0;
3647 connection->headers_received = NULL;
3648 connection->headers_received_tail = NULL;
3649 connection->response_write_position = 0;
3650 connection->have_chunked_upload = false;
3651 connection->current_chunk_size = 0;
3652 connection->current_chunk_offset = 0;
3653 connection->method = NULL;
3654 connection->url = NULL;
3655 connection->write_buffer = NULL;
3656 connection->write_buffer_size = 0;
3657 connection->write_buffer_send_offset = 0;
3658 connection->write_buffer_append_offset = 0;
3659 continue;
3661 cleanup_connection (connection);
3662 connection->in_idle = false;
3663 return MHD_NO;
3664#ifdef UPGRADE_SUPPORT
3665 case MHD_CONNECTION_UPGRADE:
3666 connection->in_idle = false;
3667 return MHD_YES; /* keep open */
3668#endif /* UPGRADE_SUPPORT */
3669 default:
3670 mhd_assert (0);
3671 break;
3672 }
3673 break;
3674 }
3675 if (! connection->suspended)
3676 {
3677 time_t timeout;
3678 timeout = connection->connection_timeout;
3679 if ( (0 != timeout) &&
3680 (timeout < (MHD_monotonic_sec_counter ()
3681 - connection->last_activity)) )
3682 {
3683 MHD_connection_close_ (connection,
3685 connection->in_idle = false;
3686 return MHD_YES;
3687 }
3688 }
3690 ret = MHD_YES;
3691#ifdef EPOLL_SUPPORT
3692 if ( (! connection->suspended) &&
3693 (0 != (daemon->options & MHD_USE_EPOLL)) )
3694 {
3695 ret = MHD_connection_epoll_update_ (connection);
3696 }
3697#endif /* EPOLL_SUPPORT */
3698 connection->in_idle = false;
3699 return ret;
3700}
3701
3702
3703#ifdef EPOLL_SUPPORT
3712enum MHD_Result
3713MHD_connection_epoll_update_ (struct MHD_Connection *connection)
3714{
3715 struct MHD_Daemon *daemon = connection->daemon;
3716
3717 if ( (0 != (daemon->options & MHD_USE_EPOLL)) &&
3718 (0 == (connection->epoll_state & MHD_EPOLL_STATE_IN_EPOLL_SET)) &&
3719 (0 == (connection->epoll_state & MHD_EPOLL_STATE_SUSPENDED)) &&
3720 ( ( (MHD_EVENT_LOOP_INFO_WRITE == connection->event_loop_info) &&
3721 (0 == (connection->epoll_state & MHD_EPOLL_STATE_WRITE_READY))) ||
3722 ( (MHD_EVENT_LOOP_INFO_READ == connection->event_loop_info) &&
3723 (0 == (connection->epoll_state & MHD_EPOLL_STATE_READ_READY)) ) ) )
3724 {
3725 /* add to epoll set */
3726 struct epoll_event event;
3727
3728 event.events = EPOLLIN | EPOLLOUT | EPOLLPRI | EPOLLET;
3729 event.data.ptr = connection;
3730 if (0 != epoll_ctl (daemon->epoll_fd,
3731 EPOLL_CTL_ADD,
3732 connection->socket_fd,
3733 &event))
3734 {
3735#ifdef HAVE_MESSAGES
3736 if (0 != (daemon->options & MHD_USE_ERROR_LOG))
3737 MHD_DLOG (daemon,
3738 _ ("Call to epoll_ctl failed: %s\n"),
3740#endif
3741 connection->state = MHD_CONNECTION_CLOSED;
3742 cleanup_connection (connection);
3743 return MHD_NO;
3744 }
3745 connection->epoll_state |= MHD_EPOLL_STATE_IN_EPOLL_SET;
3746 }
3747 return MHD_YES;
3748}
3749
3750
3751#endif
3752
3753
3759void
3761{
3762 connection->recv_cls = &recv_param_adapter;
3763}
3764
3765
3776const union MHD_ConnectionInfo *
3778 enum MHD_ConnectionInfoType info_type,
3779 ...)
3780{
3781 switch (info_type)
3782 {
3783#ifdef HTTPS_SUPPORT
3785 if (NULL == connection->tls_session)
3786 return NULL;
3787 connection->cipher = gnutls_cipher_get (connection->tls_session);
3788 return (const union MHD_ConnectionInfo *) &connection->cipher;
3790 if (NULL == connection->tls_session)
3791 return NULL;
3792 connection->protocol = gnutls_protocol_get_version (
3793 connection->tls_session);
3794 return (const union MHD_ConnectionInfo *) &connection->protocol;
3796 if (NULL == connection->tls_session)
3797 return NULL;
3798 return (const union MHD_ConnectionInfo *) &connection->tls_session;
3799#endif /* HTTPS_SUPPORT */
3801 return (const union MHD_ConnectionInfo *) &connection->addr;
3803 return (const union MHD_ConnectionInfo *) &connection->daemon;
3805 return (const union MHD_ConnectionInfo *) &connection->socket_fd;
3807 return (const union MHD_ConnectionInfo *) &connection->socket_context;
3809 connection->suspended_dummy = connection->suspended ? MHD_YES : MHD_NO;
3810 return (const union MHD_ConnectionInfo *) &connection->suspended_dummy;
3812 connection->connection_timeout_dummy = (unsigned
3813 int) connection->connection_timeout;
3814 return (const union MHD_ConnectionInfo *) &connection->
3815 connection_timeout_dummy;
3817 if ( (MHD_CONNECTION_HEADERS_RECEIVED > connection->state) ||
3818 (MHD_CONNECTION_CLOSED == connection->state) )
3819 return NULL; /* invalid, too early! */
3820 return (const union MHD_ConnectionInfo *) &connection->header_size;
3821 default:
3822 return NULL;
3823 }
3824}
3825
3826
3836enum MHD_Result
3838 enum MHD_CONNECTION_OPTION option,
3839 ...)
3840{
3841 va_list ap;
3842 struct MHD_Daemon *daemon;
3843
3844 daemon = connection->daemon;
3845 switch (option)
3846 {
3848 if (0 == connection->connection_timeout)
3850#if defined(MHD_USE_POSIX_THREADS) || defined(MHD_USE_W32_THREADS)
3852#endif
3853 if ( (0 == (daemon->options & MHD_USE_THREAD_PER_CONNECTION)) &&
3854 (! connection->suspended) )
3855 {
3856 if (connection->connection_timeout == daemon->connection_timeout)
3858 daemon->normal_timeout_tail,
3859 connection);
3860 else
3862 daemon->manual_timeout_tail,
3863 connection);
3864 }
3865 va_start (ap, option);
3866 connection->connection_timeout = va_arg (ap,
3867 unsigned int);
3868 va_end (ap);
3869 if ( (0 == (daemon->options & MHD_USE_THREAD_PER_CONNECTION)) &&
3870 (! connection->suspended) )
3871 {
3872 if (connection->connection_timeout == daemon->connection_timeout)
3874 daemon->normal_timeout_tail,
3875 connection);
3876 else
3878 daemon->manual_timeout_tail,
3879 connection);
3880 }
3881#if defined(MHD_USE_POSIX_THREADS) || defined(MHD_USE_W32_THREADS)
3883#endif
3884 return MHD_YES;
3885 default:
3886 return MHD_NO;
3887 }
3888}
3889
3890
3902enum MHD_Result
3904 unsigned int status_code,
3905 struct MHD_Response *response)
3906{
3907 struct MHD_Daemon *daemon;
3908
3909 if ( (NULL == connection) ||
3910 (NULL == response) ||
3911 (NULL != connection->response) ||
3912 ( (MHD_CONNECTION_HEADERS_PROCESSED != connection->state) &&
3913 (MHD_CONNECTION_FOOTERS_RECEIVED != connection->state) ) )
3914 return MHD_NO;
3915 daemon = connection->daemon;
3916
3917 if (daemon->shutdown)
3918 return MHD_YES; /* If daemon was shut down in parallel,
3919 * response will be aborted now or on later stage. */
3920
3921#if defined(MHD_USE_POSIX_THREADS) || defined(MHD_USE_W32_THREADS)
3922 if ( (! connection->suspended) &&
3923 (0 != (daemon->options & MHD_USE_INTERNAL_POLLING_THREAD)) &&
3924 (! MHD_thread_ID_match_current_ (connection->pid.ID)) )
3925 {
3926#ifdef HAVE_MESSAGES
3927 MHD_DLOG (daemon,
3928 _ ("Attempted to queue response on wrong thread!\n"));
3929#endif
3930 return MHD_NO;
3931 }
3932#endif
3933#ifdef UPGRADE_SUPPORT
3934 if ( (NULL != response->upgrade_handler) &&
3935 (0 == (daemon->options & MHD_ALLOW_UPGRADE)) )
3936 {
3937#ifdef HAVE_MESSAGES
3938 MHD_DLOG (daemon,
3939 _ (
3940 "Attempted 'upgrade' connection on daemon without MHD_ALLOW_UPGRADE option!\n"));
3941#endif
3942 return MHD_NO;
3943 }
3944 if ( (MHD_HTTP_SWITCHING_PROTOCOLS != status_code) &&
3945 (NULL != response->upgrade_handler) )
3946 {
3947#ifdef HAVE_MESSAGES
3948 MHD_DLOG (daemon,
3949 _ (
3950 "Application used invalid status code for 'upgrade' response!\n"));
3951#endif
3952 return MHD_NO;
3953 }
3954#endif /* UPGRADE_SUPPORT */
3955 MHD_increment_response_rc (response);
3956 connection->response = response;
3957 connection->responseCode = status_code;
3958#if defined(_MHD_HAVE_SENDFILE)
3959 if ( (response->fd == -1) ||
3960 (0 != (connection->daemon->options & MHD_USE_TLS)) )
3961 connection->resp_sender = MHD_resp_sender_std;
3962 else
3963 connection->resp_sender = MHD_resp_sender_sendfile;
3964#endif /* _MHD_HAVE_SENDFILE */
3965
3966 if ( ( (NULL != connection->method) &&
3967 (MHD_str_equal_caseless_ (connection->method,
3969 (MHD_HTTP_OK > status_code) ||
3970 (MHD_HTTP_NO_CONTENT == status_code) ||
3971 (MHD_HTTP_NOT_MODIFIED == status_code) )
3972 {
3973 /* if this is a "HEAD" request, or a status code for
3974 which a body is not allowed, pretend that we
3975 have already sent the full message body. */
3976 connection->response_write_position = response->total_size;
3977 }
3978 if (MHD_CONNECTION_HEADERS_PROCESSED == connection->state)
3979 {
3980 /* response was queued "early", refuse to read body / footers or
3981 further requests! */
3982 connection->read_closed = true;
3984 connection->remaining_upload_size = 0;
3985 }
3986 if (! connection->in_idle)
3987 (void) MHD_connection_handle_idle (connection);
3988 MHD_update_last_activity_ (connection);
3989 return MHD_YES;
3990}
3991
3992
3993/* end of connection.c */
#define MHD_SENFILE_CHUNK_THR_P_C_
Definition: connection.c:137
static ssize_t recv_param_adapter(struct MHD_Connection *connection, void *other, size_t i)
Definition: connection.c:190
static enum MHD_Result build_header_response(struct MHD_Connection *connection)
Definition: connection.c:1198
static void connection_close_error(struct MHD_Connection *connection, const char *emsg)
Definition: connection.c:791
static enum MHD_Result process_header_line(struct MHD_Connection *connection, char *line)
Definition: connection.c:2464
#define MHD_lookup_header_s_token_ci(c, h, tkn)
Definition: connection.c:618
void MHD_connection_handle_read(struct MHD_Connection *connection)
Definition: connection.c:2756
void MHD_connection_handle_write(struct MHD_Connection *connection)
Definition: connection.c:2869
#define INTERNAL_ERROR
Definition: connection.c:114
static void MHD_connection_update_event_loop_info(struct MHD_Connection *connection)
Definition: connection.c:1655
static enum MHD_Result try_ready_normal_body(struct MHD_Connection *connection)
Definition: connection.c:830
static void call_connection_handler(struct MHD_Connection *connection)
Definition: connection.c:2156
static void process_request_body(struct MHD_Connection *connection)
Definition: connection.c:2192
#define REQUEST_TOO_BIG
Definition: connection.c:73
#define HTTP_100_CONTINUE
Definition: connection.c:60
static enum MHD_Result keepalive_possible(struct MHD_Connection *connection)
Definition: connection.c:1032
static enum MHD_Result parse_cookie_header(struct MHD_Connection *connection)
Definition: connection.c:1918
#define REQUEST_MALFORMED
Definition: connection.c:101
void MHD_set_http_callbacks_(struct MHD_Connection *connection)
Definition: connection.c:3760
#define REQUEST_LACKS_HOST
Definition: connection.c:87
static bool try_grow_read_buffer(struct MHD_Connection *connection, bool required)
Definition: connection.c:1145
static char * get_next_header_line(struct MHD_Connection *connection, size_t *line_len)
Definition: connection.c:1823
static bool need_100_continue(struct MHD_Connection *connection)
Definition: connection.c:631
static void transmit_error_response(struct MHD_Connection *connection, unsigned int status_code, const char *message)
Definition: connection.c:1571
enum MHD_Result MHD_connection_handle_idle(struct MHD_Connection *connection)
Definition: connection.c:3222
static void cleanup_connection(struct MHD_Connection *connection)
Definition: connection.c:3146
static enum MHD_Result try_ready_chunked_body(struct MHD_Connection *connection)
Definition: connection.c:901
static enum MHD_Result process_broken_line(struct MHD_Connection *connection, char *line, enum MHD_ValueKind kind)
Definition: connection.c:2523
static void parse_connection_headers(struct MHD_Connection *connection)
Definition: connection.c:2609
void MHD_update_last_activity_(struct MHD_Connection *connection)
Definition: connection.c:2717
static enum MHD_Result parse_initial_message_line(struct MHD_Connection *connection, char *line, size_t line_len)
Definition: connection.c:2044
static void get_date_string(char *date, size_t date_len)
Definition: connection.c:1082
void MHD_connection_close_(struct MHD_Connection *connection, enum MHD_RequestTerminationCode termination_code)
Definition: connection.c:694
static enum MHD_Result connection_add_header(struct MHD_Connection *connection, const char *key, size_t key_size, const char *value, size_t value_size, enum MHD_ValueKind kind)
Definition: connection.c:1883
void MHD_connection_mark_closed_(struct MHD_Connection *connection)
Definition: connection.c:657
#define CONNECTION_CLOSE_ERROR(c, emsg)
Definition: connection.c:813
static enum MHD_Result check_write_done(struct MHD_Connection *connection, enum MHD_CONNECTION_STATE next_state)
Definition: connection.c:2435
#define MHD_SENFILE_CHUNK_
Definition: connection.c:132
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:576
Methods for managing connections.
void MHD_connection_finish_forward_(struct MHD_Connection *connection) MHD_NONNULL(1)
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:574
#define MHD_HTTP_HEADER_CONNECTION
Definition: microhttpd.h:568
#define MHD_HTTP_HEADER_DATE
Definition: microhttpd.h:582
#define MHD_HTTP_HEADER_TRANSFER_ENCODING
Definition: microhttpd.h:630
#define MHD_HTTP_HEADER_COOKIE
Definition: microhttpd.h:702
#define MHD_HTTP_HEADER_EXPECT
Definition: microhttpd.h:586
#define MHD_HTTP_HEADER_HOST
Definition: microhttpd.h:592
#define MHD_HTTP_INTERNAL_SERVER_ERROR
Definition: microhttpd.h:445
#define MHD_HTTP_OK
Definition: microhttpd.h:343
#define MHD_HTTP_URI_TOO_LONG
Definition: microhttpd.h:412
#define MHD_HTTP_REQUEST_HEADER_FIELDS_TOO_LARGE
Definition: microhttpd.h:439
#define MHD_HTTP_PROCESSING
Definition: microhttpd.h:338
#define MHD_HTTP_SWITCHING_PROTOCOLS
Definition: microhttpd.h:336
#define MHD_HTTP_NOT_MODIFIED
Definition: microhttpd.h:373
#define MHD_HTTP_NO_CONTENT
Definition: microhttpd.h:351
#define MHD_HTTP_BAD_REQUEST
Definition: microhttpd.h:384
#define MHD_HTTP_METHOD_HEAD
Definition: microhttpd.h:908
#define MHD_HTTP_METHOD_CONNECT
Definition: microhttpd.h:902
enum MHD_Result(* MHD_KeyValueIterator)(void *cls, enum MHD_ValueKind kind, const char *key, const char *value)
Definition: microhttpd.h:2246
_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:285
_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:399
enum MHD_Result(* MHD_KeyValueIteratorN)(void *cls, enum MHD_ValueKind kind, const char *key, size_t key_size, const char *value, size_t value_size)
Definition: microhttpd.h:2271
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:338
_MHD_EXTERN const char * MHD_lookup_connection_value(struct MHD_Connection *connection, enum MHD_ValueKind kind, const char *key)
Definition: connection.c:475
_MHD_EXTERN int MHD_get_connection_values(struct MHD_Connection *connection, enum MHD_ValueKind kind, MHD_KeyValueIterator iterator, void *iterator_cls)
Definition: connection.c:246
MHD_ConnectionInfoType
Definition: microhttpd.h:1965
_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:446
_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:512
MHD_RequestTerminationCode
Definition: microhttpd.h:1817
@ MHD_CONNECTION_INFO_CONNECTION_TIMEOUT
Definition: microhttpd.h:2037
@ MHD_CONNECTION_INFO_SOCKET_CONTEXT
Definition: microhttpd.h:2025
@ MHD_CONNECTION_INFO_GNUTLS_SESSION
Definition: microhttpd.h:1993
@ MHD_CONNECTION_INFO_REQUEST_HEADER_SIZE
Definition: microhttpd.h:2043
@ MHD_CONNECTION_INFO_CIPHER_ALGO
Definition: microhttpd.h:1971
@ MHD_CONNECTION_INFO_CONNECTION_SUSPENDED
Definition: microhttpd.h:2031
@ MHD_CONNECTION_INFO_CLIENT_ADDRESS
Definition: microhttpd.h:1987
@ MHD_CONNECTION_INFO_DAEMON
Definition: microhttpd.h:2007
@ MHD_CONNECTION_INFO_CONNECTION_FD
Definition: microhttpd.h:2015
@ MHD_CONNECTION_INFO_PROTOCOL
Definition: microhttpd.h:1978
@ MHD_REQUEST_TERMINATED_TIMEOUT_REACHED
Definition: microhttpd.h:1839
@ MHD_REQUEST_TERMINATED_COMPLETED_OK
Definition: microhttpd.h:1823
@ MHD_REQUEST_TERMINATED_WITH_ERROR
Definition: microhttpd.h:1831
@ MHD_REQUEST_TERMINATED_READ_ERROR
Definition: microhttpd.h:1856
@ MHD_REQUEST_TERMINATED_CLIENT_ABORT
Definition: microhttpd.h:1864
_MHD_EXTERN struct MHD_Response * MHD_create_response_from_buffer(size_t size, void *buffer, enum MHD_ResponseMemoryMode mode)
Definition: response.c:738
_MHD_EXTERN enum MHD_Result MHD_queue_response(struct MHD_Connection *connection, unsigned int status_code, struct MHD_Response *response)
Definition: connection.c:3903
_MHD_EXTERN void MHD_destroy_response(struct MHD_Response *response)
Definition: response.c:1214
_MHD_EXTERN const char * MHD_get_response_header(struct MHD_Response *response, const char *key)
Definition: response.c:284
@ MHD_RESPMEM_PERSISTENT
Definition: microhttpd.h:3057
_MHD_EXTERN const union MHD_ConnectionInfo * MHD_get_connection_info(struct MHD_Connection *connection, enum MHD_ConnectionInfoType info_type,...)
Definition: connection.c:3777
#define MHD_ICY_FLAG
Definition: microhttpd.h:536
_MHD_EXTERN enum MHD_Result MHD_set_connection_option(struct MHD_Connection *connection, enum MHD_CONNECTION_OPTION option,...)
Definition: connection.c:3837
#define MHD_HTTP_VERSION_1_0
Definition: microhttpd.h:887
#define MHD_HTTP_VERSION_1_1
Definition: microhttpd.h:888
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_CONNRESET_
Definition: internal.h:1868
#define XDLL_insert(head, tail, element)
Definition: internal.h:1786
MHD_PanicCallback mhd_panic
Definition: panic.c:31
@ 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_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_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 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
time_t MHD_monotonic_sec_counter(void)
#define MHD_SCKT_ERR_IS_(err, code)
Definition: mhd_sockets.h:611
#define MHD_SCKT_ERR_IS_EAGAIN_(err)
Definition: mhd_sockets.h:643
#define MHD_socket_last_strerr_()
Definition: mhd_sockets.h:549
#define MHD_socket_get_error_()
Definition: mhd_sockets.h:523
#define MHD_SCKT_ERR_IS_EINTR_(err)
Definition: mhd_sockets.h:634
#define MHD_SCKT_SEND_MAX_SIZE_
Definition: mhd_sockets.h:222
#define MHD_recv_(s, b, l)
Definition: mhd_sockets.h:273
#define MHD_SCKT_ECONNRESET_
Definition: mhd_sockets.h:419
int MHD_str_equal_caseless_(const char *str1, const char *str2)
Definition: mhd_str.c:346
size_t MHD_strx_to_uint64_n_(const char *str, size_t maxlen, uint64_t *out_val)
Definition: mhd_str.c:692
size_t MHD_str_to_uint64_(const char *str, uint64_t *out_val)
Definition: mhd_str.c:473
bool MHD_str_has_token_caseless_(const char *str, const char *const token, size_t token_len)
Definition: mhd_str.c:412
#define MHD_STATICSTR_LEN_(macro)
Definition: mhd_str.h:45
#define NULL
Definition: reason_phrase.c:30
#define _(String)
Definition: mhd_options.h:42
#define _MHD_EXTERN
Definition: mhd_options.h:50
ssize_t MHD_send_on_connection_(struct MHD_Connection *connection, const char *buffer, size_t buffer_size, enum MHD_SendSocketOptions options)
Definition: mhd_send.c:241
ssize_t MHD_send_on_connection2_(struct MHD_Connection *connection, const char *header, size_t header_size, const char *buffer, size_t buffer_size)
Definition: mhd_send.c:389
Implementation of send() wrappers.
@ MHD_SSO_HDR_CORK
Definition: mhd_send.h:77
@ MHD_SSO_NO_CORK
Definition: mhd_send.h:64
@ MHD_SSO_MAY_CORK
Definition: mhd_send.h:68
internal shared structures
MHD_CONNECTION_STATE
Definition: internal.h:422
@ MHD_CONNECTION_BODY_RECEIVED
Definition: internal.h:462
@ MHD_CONNECTION_HEADER_PART_RECEIVED
Definition: internal.h:437
@ MHD_CONNECTION_HEADERS_SENDING
Definition: internal.h:480
@ MHD_CONNECTION_FOOTERS_SENDING
Definition: internal.h:516
@ MHD_CONNECTION_FOOTERS_RECEIVED
Definition: internal.h:474
@ MHD_CONNECTION_HEADERS_SENT
Definition: internal.h:485
@ MHD_CONNECTION_HEADERS_PROCESSED
Definition: internal.h:447
@ MHD_CONNECTION_INIT
Definition: internal.h:427
@ MHD_CONNECTION_CLOSED
Definition: internal.h:526
@ MHD_CONNECTION_NORMAL_BODY_UNREADY
Definition: internal.h:496
@ MHD_CONNECTION_HEADERS_RECEIVED
Definition: internal.h:442
@ MHD_CONNECTION_NORMAL_BODY_READY
Definition: internal.h:490
@ MHD_CONNECTION_CHUNKED_BODY_READY
Definition: internal.h:501
@ MHD_CONNECTION_FOOTER_PART_RECEIVED
Definition: internal.h:468
@ MHD_CONNECTION_CONTINUE_SENT
Definition: internal.h:457
@ MHD_CONNECTION_FOOTERS_SENT
Definition: internal.h:521
@ MHD_CONNECTION_CHUNKED_BODY_UNREADY
Definition: internal.h:506
@ MHD_CONNECTION_BODY_SENT
Definition: internal.h:511
@ MHD_CONNECTION_CONTINUE_SENDING
Definition: internal.h:452
@ MHD_CONNECTION_URL_RECEIVED
Definition: internal.h:432
#define MHD_check_response_header_s_token_ci(r, k, tkn)
Definition: internal.h:1973
@ MHD_TLS_CONN_NO_TLS
Definition: internal.h:544
@ MHD_TLS_CONN_INIT
Definition: internal.h:545
@ MHD_TLS_CONN_CONNECTED
Definition: internal.h:547
@ MHD_TLS_CONN_HANDSHAKING
Definition: internal.h:546
@ MHD_EVENT_LOOP_INFO_READ
Definition: internal.h:189
@ MHD_EVENT_LOOP_INFO_WRITE
Definition: internal.h:194
@ MHD_EVENT_LOOP_INFO_CLEANUP
Definition: internal.h:204
@ MHD_EVENT_LOOP_INFO_BLOCK
Definition: internal.h:199
memory pool; mostly used for efficient (de)allocation for each connection and bounding memory use for...
Header for platform missing functions.
Header for platform-independent inter-thread communication.
limits values definitions
internal monotonic clock functions implementations
bool MHD_str_equal_caseless_bin_n_(const char *const str1, const char *const str2, size_t len)
Definition: mhd_str.c:408
Header for string manipulating helpers.
void MHD_increment_response_rc(struct MHD_Response *response)
Definition: response.c:1254
#define MHD_SIZE_UNKNOWN
Definition: microhttpd.h:167
MHD_Result
Definition: microhttpd.h:141
@ MHD_YES
Definition: microhttpd.h:150
@ MHD_NO
Definition: microhttpd.h:145
#define MHD_CONTENT_READER_END_OF_STREAM
Definition: microhttpd.h:174
#define MHD_UNSIGNED_LONG_LONG
Definition: microhttpd.h:298
#define MHD_UNSIGNED_LONG_LONG_PRINTF
Definition: microhttpd.h:312
void * data
Definition: microhttpd.h:3038
#define MHD_INVALID_SOCKET
Definition: microhttpd.h:196
_MHD_EXTERN const char * MHD_get_reason_phrase_for(unsigned int code)
#define MHD_CONTENT_READER_END_WITH_ERROR
Definition: microhttpd.h:175
MHD_ValueKind
Definition: microhttpd.h:1766
@ MHD_FOOTER_KIND
Definition: microhttpd.h:1807
@ MHD_COOKIE_KIND
Definition: microhttpd.h:1787
@ MHD_HEADER_KIND
Definition: microhttpd.h:1781
@ MHD_GET_ARGUMENT_KIND
Definition: microhttpd.h:1802
@ MHD_USE_EPOLL
Definition: microhttpd.h:1181
@ MHD_USE_THREAD_PER_CONNECTION
Definition: microhttpd.h:1075
@ MHD_USE_TURBO
Definition: microhttpd.h:1252
@ MHD_USE_SUPPRESS_DATE_NO_CLOCK
Definition: microhttpd.h:1154
@ MHD_USE_TLS
Definition: microhttpd.h:1060
@ MHD_ALLOW_UPGRADE
Definition: microhttpd.h:1290
@ MHD_USE_ERROR_LOG
Definition: microhttpd.h:1049
@ MHD_USE_INTERNAL_POLLING_THREAD
Definition: microhttpd.h:1086
@ MHD_RF_HTTP_VERSION_1_0_RESPONSE
Definition: microhttpd.h:2959
@ MHD_RF_HTTP_VERSION_1_0_ONLY
Definition: microhttpd.h:2952
MHD_CONNECTION_OPTION
Definition: microhttpd.h:3765
@ MHD_CONNECTION_OPTION_TIMEOUT
Definition: microhttpd.h:3774
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
size_t write_buffer_size
Definition: internal.h:794
size_t write_buffer_send_offset
Definition: internal.h:799
enum MHD_ConnectionEventLoopInfo event_loop_info
Definition: internal.h:929
size_t write_buffer_append_offset
Definition: internal.h:805
char * last
Definition: internal.h:752
char * write_buffer
Definition: internal.h:744
uint64_t remaining_upload_size
Definition: internal.h:817
void * socket_context
Definition: internal.h:694
bool suspended
Definition: internal.h:764
ReceiveCallback recv_cls
Definition: internal.h:706
char * colon
Definition: internal.h:761
size_t header_size
Definition: internal.h:811
struct MHD_Response * response
Definition: internal.h:680
const char * url
Definition: internal.h:718
char * version
Definition: internal.h:724
enum MHD_ConnKeepAlive keepalive
Definition: internal.h:731
time_t connection_timeout
Definition: internal.h:745
struct MHD_HTTP_Header * headers_received
Definition: internal.h:670
size_t continue_message_write_offset
Definition: internal.h:838
uint64_t response_write_position
Definition: internal.h:824
struct sockaddr_storage addr
Definition: internal.h:728
struct MHD_HTTP_Header * headers_received_tail
Definition: internal.h:675
char * method
Definition: internal.h:712
uint64_t current_chunk_offset
Definition: internal.h:958
struct MemoryPool * pool
Definition: internal.h:685
size_t read_buffer_offset
Definition: internal.h:789
uint64_t current_chunk_size
Definition: internal.h:952
int suspended_dummy
Definition: internal.h:1012
bool client_aware
Definition: internal.h:867
unsigned int responseCode
Definition: internal.h:935
MHD_thread_handle_ID_ pid
Definition: internal.h:723
bool have_chunked_upload
Definition: internal.h:944
bool read_closed
Definition: internal.h:792
time_t last_activity
Definition: internal.h:739
bool in_cleanup
Definition: internal.h:912
void * client_context
Definition: internal.h:698
enum MHD_CONNECTION_STATE state
Definition: internal.h:924
char * read_buffer
Definition: internal.h:738
struct MHD_Daemon * daemon
Definition: internal.h:675
unsigned int connection_timeout_dummy
Definition: internal.h:860
size_t read_buffer_size
Definition: internal.h:783
size_t pool_size
Definition: internal.h:1447
MHD_AccessHandlerCallback default_handler
Definition: internal.h:1258
LogCallback uri_log_callback
Definition: internal.h:1397
void * unescape_callback_cls
Definition: internal.h:1412
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:1372
struct MHD_itc_ itc
Definition: internal.h:1410
struct MHD_Connection * manual_timeout_tail
Definition: internal.h:1150
volatile bool shutdown
Definition: internal.h:1526
enum MHD_FLAG options
Definition: internal.h:1600
UnescapeCallback unescape_callback
Definition: internal.h:1407
void * notify_completed_cls
Definition: internal.h:1377
struct MHD_Connection * cleanup_tail
Definition: internal.h:1182
struct MHD_Connection * manual_timeout_head
Definition: internal.h:1143
void * default_handler_cls
Definition: internal.h:1263
struct MHD_Connection * suspended_connections_tail
Definition: internal.h:1172
time_t connection_timeout
Definition: internal.h:1589
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:1452
void * uri_log_callback_cls
Definition: internal.h:1402
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:1610
size_t value_size
Definition: internal.h:290
char * header
Definition: internal.h:347
enum MHD_ValueKind kind
Definition: internal.h:358
size_t header_size
Definition: internal.h:280
struct MHD_HTTP_Header * next
Definition: internal.h:342
char * value
Definition: internal.h:352
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
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
size_t data_size
Definition: internal.h:1659
enum MHD_ResponseFlags flags
Definition: internal.h:401
char * data
Definition: internal.h:1588
MHD_mutex_ mutex
Definition: internal.h:1637
uint64_t total_size
Definition: internal.h:1642