GNU libmicrohttpd 0.9.73
Loading...
Searching...
No Matches
connection.c
Go to the documentation of this file.
1/*
2 This file is part of libmicrohttpd
3 Copyright (C) 2007-2020 Daniel Pittman and Christian Grothoff
4
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
117
121#define MHD_SENFILE_CHUNK_ (0x20000)
122
126#define MHD_SENFILE_CHUNK_THR_P_C_ (0x200000)
127
128#ifdef HAVE_MESSAGES
134static const char *
135str_conn_error_ (ssize_t mhd_err_code)
136{
137 switch (mhd_err_code)
138 {
139 case MHD_ERR_AGAIN_:
140 return _ ("The operation would block, retry later");
142 return _ ("The connection was forcibly closed by remote peer");
143 case MHD_ERR_NOTCONN_:
144 return _ ("The socket is not connected");
145 case MHD_ERR_NOMEM_:
146 return _ ("Not enough system resources to serve the request");
147 case MHD_ERR_BADF_:
148 return _ ("Bad FD value");
149 case MHD_ERR_INVAL_:
150 return _ ("Argument value is invalid");
152 return _ ("Argument value is not supported");
153 case MHD_ERR_PIPE_:
154 return _ ("The socket is no longer available for sending");
155 case MHD_ERR_TLS_:
156 return _ ("TLS encryption or decryption error");
157 default:
158 break; /* Mute compiler warning */
159 }
160 if (0 <= mhd_err_code)
161 return _ ("Not an error code");
162
163 mhd_assert (0); /* Should never be reachable */
164 return _ ("Wrong error code value");
165}
166
167
168#endif /* HAVE_MESSAGES */
169
179static ssize_t
181 void *other,
182 size_t i)
183{
184 ssize_t ret;
185
186 if ( (MHD_INVALID_SOCKET == connection->socket_fd) ||
187 (MHD_CONNECTION_CLOSED == connection->state) )
188 {
189 return MHD_ERR_NOTCONN_;
190 }
192 i = MHD_SCKT_SEND_MAX_SIZE_; /* return value limit */
193
194 ret = MHD_recv_ (connection->socket_fd,
195 other,
196 i);
197 if (0 > ret)
198 {
199 const int err = MHD_socket_get_error_ ();
200 if (MHD_SCKT_ERR_IS_EAGAIN_ (err))
201 {
202#ifdef EPOLL_SUPPORT
203 /* Got EAGAIN --- no longer read-ready */
204 connection->epoll_state &= ~MHD_EPOLL_STATE_READ_READY;
205#endif /* EPOLL_SUPPORT */
206 return MHD_ERR_AGAIN_;
207 }
208 if (MHD_SCKT_ERR_IS_EINTR_ (err))
209 return MHD_ERR_AGAIN_;
211 return MHD_ERR_CONNRESET_;
213 return MHD_ERR_OPNOTSUPP_;
215 return MHD_ERR_NOTCONN_;
217 return MHD_ERR_INVAL_;
219 return MHD_ERR_NOMEM_;
221 return MHD_ERR_BADF_;
222 /* Treat any other error as a 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_NO == 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. */
671 if (0 != (daemon->options & MHD_USE_TLS))
672 {
673 if (! MHD_tls_connection_shutdown (connection))
674 shutdown (connection->socket_fd,
675 SHUT_WR);
676 }
677 else /* Combined with next 'shutdown()'. */
678#endif /* HTTPS_SUPPORT */
679 shutdown (connection->socket_fd,
680 SHUT_WR);
681 }
682}
683
684
694void
696 enum MHD_RequestTerminationCode termination_code)
697{
698 struct MHD_Daemon *daemon = connection->daemon;
699 struct MHD_Response *resp = connection->response;
700
701#ifdef MHD_USE_THREADS
702 mhd_assert ( (0 == (daemon->options & MHD_USE_INTERNAL_POLLING_THREAD)) || \
703 MHD_thread_ID_match_current_ (connection->pid) );
704#endif /* MHD_USE_THREADS */
705
706 MHD_connection_mark_closed_ (connection);
707 if (NULL != resp)
708 {
709 connection->response = NULL;
711 }
712 if ( (NULL != daemon->notify_completed) &&
713 (connection->client_aware) )
714 daemon->notify_completed (daemon->notify_completed_cls,
715 connection,
716 &connection->client_context,
717 termination_code);
718 connection->client_aware = false;
719}
720
721
722#if defined(HTTPS_SUPPORT) && defined(UPGRADE_SUPPORT)
733void
735{
736 struct MHD_Daemon *daemon = connection->daemon;
737 struct MHD_UpgradeResponseHandle *urh = connection->urh;
738
739#ifdef MHD_USE_THREADS
740 mhd_assert ( (0 == (daemon->options & MHD_USE_INTERNAL_POLLING_THREAD)) || \
741 (0 != (daemon->options & MHD_USE_THREAD_PER_CONNECTION)) || \
742 MHD_thread_ID_match_current_ (daemon->pid) );
743#endif /* MHD_USE_THREADS */
744
745 if (0 == (daemon->options & MHD_USE_TLS))
746 return; /* Nothing to do with non-TLS connection. */
747
748 if (0 == (daemon->options & MHD_USE_THREAD_PER_CONNECTION))
749 DLL_remove (daemon->urh_head,
750 daemon->urh_tail,
751 urh);
752#if EPOLL_SUPPORT
753 if ( (0 != (daemon->options & MHD_USE_EPOLL)) &&
754 (0 != epoll_ctl (daemon->epoll_upgrade_fd,
755 EPOLL_CTL_DEL,
756 connection->socket_fd,
757 NULL)) )
758 {
759 MHD_PANIC (_ ("Failed to remove FD from epoll set.\n"));
760 }
761 if (urh->in_eready_list)
762 {
763 EDLL_remove (daemon->eready_urh_head,
764 daemon->eready_urh_tail,
765 urh);
766 urh->in_eready_list = false;
767 }
768#endif /* EPOLL_SUPPORT */
769 if (MHD_INVALID_SOCKET != urh->mhd.socket)
770 {
771#if EPOLL_SUPPORT
772 if ( (0 != (daemon->options & MHD_USE_EPOLL)) &&
773 (0 != epoll_ctl (daemon->epoll_upgrade_fd,
774 EPOLL_CTL_DEL,
775 urh->mhd.socket,
776 NULL)) )
777 {
778 MHD_PANIC (_ ("Failed to remove FD from epoll set.\n"));
779 }
780#endif /* EPOLL_SUPPORT */
781 /* Reflect remote disconnect to application by breaking
782 * socketpair connection. */
783 shutdown (urh->mhd.socket, SHUT_RDWR);
784 }
785 /* Socketpair sockets will remain open as they will be
786 * used with MHD_UPGRADE_ACTION_CLOSE. They will be
787 * closed by cleanup_upgraded_connection() during
788 * connection's final cleanup.
789 */
790}
791
792
793#endif /* HTTPS_SUPPORT && UPGRADE_SUPPORT*/
794
795
803static void
805 const char *emsg)
806{
807#ifdef HAVE_MESSAGES
808 if (NULL != emsg)
809 MHD_DLOG (connection->daemon,
810 "%s\n",
811 emsg);
812#else /* ! HAVE_MESSAGES */
813 (void) emsg; /* Mute compiler warning. */
814#endif /* ! HAVE_MESSAGES */
815 MHD_connection_close_ (connection,
817}
818
819
824#ifdef HAVE_MESSAGES
825#define CONNECTION_CLOSE_ERROR(c, emsg) connection_close_error (c, emsg)
826#else
827#define CONNECTION_CLOSE_ERROR(c, emsg) connection_close_error (c, NULL)
828#endif
829
830
843static enum MHD_Result
845{
846 ssize_t ret;
847 struct MHD_Response *response;
848
849 response = connection->response;
850 if ( (0 == response->total_size) ||
851 (connection->response_write_position == response->total_size) )
852 return MHD_YES; /* 0-byte response is always ready */
853 if (NULL != response->data_iov)
854 {
855 size_t copy_size;
856
857 if (NULL != connection->resp_iov.iov)
858 return MHD_YES;
859 copy_size = response->data_iovcnt * sizeof(MHD_iovec_);
860 connection->resp_iov.iov = MHD_pool_allocate (connection->pool,
861 copy_size,
862 true);
863 if (NULL == connection->resp_iov.iov)
864 {
865 MHD_mutex_unlock_chk_ (&response->mutex);
866 /* not enough memory */
867 CONNECTION_CLOSE_ERROR (connection,
868 _ ("Closing connection (out of memory)."));
869 return MHD_NO;
870 }
871 memcpy (connection->resp_iov.iov,
872 response->data_iov,
873 copy_size);
874 connection->resp_iov.cnt = response->data_iovcnt;
875 connection->resp_iov.sent = 0;
876 return MHD_YES;
877 }
878 if (NULL == response->crc)
879 return MHD_YES;
880 if ( (response->data_start <=
881 connection->response_write_position) &&
882 (response->data_size + response->data_start >
883 connection->response_write_position) )
884 return MHD_YES; /* response already ready */
885#if defined(_MHD_HAVE_SENDFILE)
886 if (MHD_resp_sender_sendfile == connection->resp_sender)
887 {
888 /* will use sendfile, no need to bother response crc */
889 return MHD_YES;
890 }
891#endif /* _MHD_HAVE_SENDFILE */
892
893 ret = response->crc (response->crc_cls,
894 connection->response_write_position,
895 response->data,
896 (size_t) MHD_MIN ((uint64_t) response->data_buffer_size,
897 response->total_size
898 - connection->response_write_position));
899 if ( (((ssize_t) MHD_CONTENT_READER_END_OF_STREAM) == ret) ||
900 (((ssize_t) MHD_CONTENT_READER_END_WITH_ERROR) == ret) )
901 {
902 /* either error or http 1.0 transfer, close socket! */
903 response->total_size = connection->response_write_position;
904#if defined(MHD_USE_POSIX_THREADS) || defined(MHD_USE_W32_THREADS)
905 MHD_mutex_unlock_chk_ (&response->mutex);
906#endif
907 if ( ((ssize_t) MHD_CONTENT_READER_END_OF_STREAM) == ret)
908 MHD_connection_close_ (connection,
910 else
911 CONNECTION_CLOSE_ERROR (connection,
912 _ (
913 "Closing connection (application reported error generating data)."));
914 return MHD_NO;
915 }
916 response->data_start = connection->response_write_position;
917 response->data_size = ret;
918 if (0 == ret)
919 {
921#if defined(MHD_USE_POSIX_THREADS) || defined(MHD_USE_W32_THREADS)
922 MHD_mutex_unlock_chk_ (&response->mutex);
923#endif
924 return MHD_NO;
925 }
926 return MHD_YES;
927}
928
929
939static enum MHD_Result
941{
942 ssize_t ret;
943 struct MHD_Response *response;
944 char cbuf[10]; /* 10: max strlen of "%x\r\n" */
945 int cblen;
946
947 response = connection->response;
948 if (NULL == response->crc)
949 return MHD_YES;
950 if (0 == connection->write_buffer_size)
951 {
952 size_t size;
953
954 size = MHD_pool_get_free (connection->pool);
955 if (size < 128)
956 {
957#if defined(MHD_USE_POSIX_THREADS) || defined(MHD_USE_W32_THREADS)
958 MHD_mutex_unlock_chk_ (&response->mutex);
959#endif
960 /* not enough memory */
961 CONNECTION_CLOSE_ERROR (connection,
962 _ ("Closing connection (out of memory)."));
963 return MHD_NO;
964 }
965 if ( (2 * (0xFFFFFF + sizeof(cbuf) + 2)) < size)
966 size = 2 * (0xFFFFFF + sizeof(cbuf) + 2);
967 connection->write_buffer = MHD_pool_allocate (connection->pool,
968 size,
969 false);
970 mhd_assert (NULL != connection->write_buffer);
971 connection->write_buffer_size = size;
972 }
973
974 if (0 == response->total_size)
975 ret = 0; /* response must be empty, don't bother calling crc */
976 else if ( (response->data_start <=
977 connection->response_write_position) &&
978 (response->data_start + response->data_size >
979 connection->response_write_position) )
980 {
981 /* difference between response_write_position and data_start is less
982 than data_size which is size_t type, no need to check for overflow */
983 const size_t data_write_offset
984 = (size_t) (connection->response_write_position - response->data_start);
985 /* buffer already ready, use what is there for the chunk */
986 ret = response->data_size - data_write_offset;
987 if ( ((size_t) ret) > connection->write_buffer_size - sizeof (cbuf) - 2)
988 ret = connection->write_buffer_size - sizeof (cbuf) - 2;
989 memcpy (&connection->write_buffer[sizeof (cbuf)],
990 &response->data[data_write_offset],
991 ret);
992 }
993 else
994 {
995 /* buffer not in range, try to fill it */
996 ret = response->crc (response->crc_cls,
997 connection->response_write_position,
998 &connection->write_buffer[sizeof (cbuf)],
999 connection->write_buffer_size - sizeof (cbuf) - 2);
1000 }
1001 if ( ((ssize_t) MHD_CONTENT_READER_END_WITH_ERROR) == ret)
1002 {
1003 /* error, close socket! */
1004 response->total_size = connection->response_write_position;
1005#if defined(MHD_USE_POSIX_THREADS) || defined(MHD_USE_W32_THREADS)
1006 MHD_mutex_unlock_chk_ (&response->mutex);
1007#endif
1008 CONNECTION_CLOSE_ERROR (connection,
1009 _ (
1010 "Closing connection (application error generating response)."));
1011 return MHD_NO;
1012 }
1013 if ( (((ssize_t) MHD_CONTENT_READER_END_OF_STREAM) == ret) ||
1014 (0 == response->total_size) )
1015 {
1016 /* end of message, signal other side! */
1017 memcpy (connection->write_buffer,
1018 "0\r\n",
1019 3);
1020 connection->write_buffer_append_offset = 3;
1021 connection->write_buffer_send_offset = 0;
1022 response->total_size = connection->response_write_position;
1023 return MHD_YES;
1024 }
1025 if (0 == ret)
1026 {
1028#if defined(MHD_USE_POSIX_THREADS) || defined(MHD_USE_W32_THREADS)
1029 MHD_mutex_unlock_chk_ (&response->mutex);
1030#endif
1031 return MHD_NO;
1032 }
1033 if (ret > 0xFFFFFF)
1034 ret = 0xFFFFFF;
1035 cblen = MHD_snprintf_ (cbuf,
1036 sizeof (cbuf),
1037 "%X\r\n",
1038 (unsigned int) ret);
1039 mhd_assert (cblen > 0);
1040 mhd_assert ((size_t) cblen < sizeof(cbuf));
1041 memcpy (&connection->write_buffer[sizeof (cbuf) - cblen],
1042 cbuf,
1043 cblen);
1044 memcpy (&connection->write_buffer[sizeof (cbuf) + ret],
1045 "\r\n",
1046 2);
1047 connection->response_write_position += ret;
1048 connection->write_buffer_send_offset = sizeof (cbuf) - cblen;
1049 connection->write_buffer_append_offset = sizeof (cbuf) + ret + 2;
1050 return MHD_YES;
1051}
1052
1053
1070static enum MHD_Result
1072{
1073 if (MHD_CONN_MUST_CLOSE == connection->keepalive)
1074 return MHD_NO;
1075 if (NULL == connection->version)
1076 return MHD_NO;
1077 if ( (NULL != connection->response) &&
1078 (0 != (connection->response->flags & MHD_RF_HTTP_VERSION_1_0_ONLY) ) )
1079 return MHD_NO;
1080
1081 if (MHD_str_equal_caseless_ (connection->version,
1083 ( (NULL == connection->response) ||
1084 (0 == (connection->response->flags
1086 {
1087 if (MHD_lookup_header_s_token_ci (connection,
1089 "upgrade"))
1090 return MHD_NO;
1091
1092 if (MHD_lookup_header_s_token_ci (connection,
1094 "close"))
1095 return MHD_NO;
1096
1097 return MHD_YES;
1098 }
1099 if (MHD_str_equal_caseless_ (connection->version,
1101 {
1102 if (MHD_lookup_header_s_token_ci (connection,
1104 "Keep-Alive"))
1105 return MHD_YES;
1106
1107 return MHD_NO;
1108 }
1109 return MHD_NO;
1110}
1111
1112
1120static void
1122 size_t date_len)
1123{
1124 static const char *const days[] = {
1125 "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
1126 };
1127 static const char *const mons[] = {
1128 "Jan", "Feb", "Mar", "Apr", "May", "Jun",
1129 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
1130 };
1131 struct tm now;
1132 time_t t;
1133#if ! defined(HAVE_C11_GMTIME_S) && ! defined(HAVE_W32_GMTIME_S) && \
1134 ! defined(HAVE_GMTIME_R)
1135 struct tm*pNow;
1136#endif
1137
1138 date[0] = 0;
1139 time (&t);
1140#if defined(HAVE_C11_GMTIME_S)
1141 if (NULL == gmtime_s (&t,
1142 &now))
1143 return;
1144#elif defined(HAVE_W32_GMTIME_S)
1145 if (0 != gmtime_s (&now,
1146 &t))
1147 return;
1148#elif defined(HAVE_GMTIME_R)
1149 if (NULL == gmtime_r (&t,
1150 &now))
1151 return;
1152#else
1153 pNow = gmtime (&t);
1154 if (NULL == pNow)
1155 return;
1156 now = *pNow;
1157#endif
1158 MHD_snprintf_ (date,
1159 date_len,
1160 "Date: %3s, %02u %3s %04u %02u:%02u:%02u GMT\r\n",
1161 days[now.tm_wday % 7],
1162 (unsigned int) now.tm_mday,
1163 mons[now.tm_mon % 12],
1164 (unsigned int) (1900 + now.tm_year),
1165 (unsigned int) now.tm_hour,
1166 (unsigned int) now.tm_min,
1167 (unsigned int) now.tm_sec);
1168}
1169
1170
1183static bool
1185 bool required)
1186{
1187 size_t new_size;
1188 size_t avail_size;
1189 void *rb;
1190
1191 avail_size = MHD_pool_get_free (connection->pool);
1192 if (0 == avail_size)
1193 return false; /* No more space available */
1194 if (0 == connection->read_buffer_size)
1195 new_size = avail_size / 2; /* Use half of available buffer for reading */
1196 else
1197 {
1198 size_t grow_size;
1199
1200 grow_size = avail_size / 8;
1201 if (MHD_BUF_INC_SIZE > grow_size)
1202 { /* Shortage of space */
1203 if (! required)
1204 return false; /* Grow is not mandatory, leave some space in pool */
1205 else
1206 {
1207 /* Shortage of space, but grow is mandatory */
1208 static const size_t small_inc = MHD_BUF_INC_SIZE / 8;
1209 if (small_inc < avail_size)
1210 grow_size = small_inc;
1211 else
1212 grow_size = avail_size;
1213 }
1214 }
1215 new_size = connection->read_buffer_size + grow_size;
1216 }
1217 /* we can actually grow the buffer, do it! */
1218 rb = MHD_pool_reallocate (connection->pool,
1219 connection->read_buffer,
1220 connection->read_buffer_size,
1221 new_size);
1222 if (NULL == rb)
1223 {
1224 /* This should NOT be possible: we just computed 'new_size' so that
1225 it should fit. If it happens, somehow our read buffer is not in
1226 the right position in the pool, say because someone called
1227 MHD_pool_allocate() without 'from_end' set to 'true'? Anyway,
1228 should be investigated! (Ideally provide all data from
1229 *pool and connection->read_buffer and new_size for debugging). */
1230 mhd_assert (0);
1231 return false;
1232 }
1233 connection->read_buffer = rb;
1234 mhd_assert (NULL != connection->read_buffer);
1235 connection->read_buffer_size = new_size;
1236 return true;
1237}
1238
1239
1249static enum MHD_Result
1251{
1252 struct MHD_Response *response = connection->response;
1253 size_t size;
1254 size_t off;
1255 struct MHD_HTTP_Header *pos;
1256 char code[256];
1257 char date[128];
1258 size_t datelen;
1259 char content_length_buf[128];
1260 size_t content_length_len;
1261 char *data;
1262 enum MHD_ValueKind kind;
1263 const char *reason_phrase;
1264 uint32_t rc;
1265 bool client_requested_close;
1266 bool response_has_close;
1267 bool response_has_keepalive;
1268 const char *have_encoding;
1269 bool must_add_close;
1270 bool must_add_chunked_encoding;
1271 bool must_add_keep_alive;
1272 bool must_add_content_length;
1273 bool may_add_content_length;
1274
1275 mhd_assert (NULL != connection->version);
1276 if (0 == connection->version[0])
1277 {
1278 data = MHD_pool_allocate (connection->pool,
1279 0,
1280 true);
1281 connection->write_buffer = data;
1282 connection->write_buffer_append_offset = 0;
1283 connection->write_buffer_send_offset = 0;
1284 connection->write_buffer_size = 0;
1285 return MHD_YES;
1286 }
1287 rc = connection->responseCode & (~MHD_ICY_FLAG);
1288 if (MHD_CONNECTION_FOOTERS_RECEIVED == connection->state)
1289 {
1290 reason_phrase = MHD_get_reason_phrase_for (rc);
1291 off = MHD_snprintf_ (code,
1292 sizeof (code),
1293 "%s %u %s\r\n",
1294 (0 != (connection->responseCode & MHD_ICY_FLAG))
1295 ? "ICY"
1297 connection->version) ||
1298 (0 != (connection->response->flags
1302 rc,
1303 reason_phrase);
1304 /* estimate size */
1305 size = off + 2; /* +2 for extra "\r\n" at the end */
1307 if ( (0 == (connection->daemon->options
1309 (NULL == MHD_get_response_header (response,
1311 get_date_string (date,
1312 sizeof (date));
1313 else
1314 date[0] = '\0';
1315 datelen = strlen (date);
1316 size += datelen;
1317 }
1318 else
1319 {
1320 /* 2 bytes for final CRLF of a Chunked-Body */
1321 size = 2;
1323 off = 0;
1324 datelen = 0;
1325 }
1326
1327 /* calculate extra headers we need to add, such as 'Connection: close',
1328 first see what was explicitly requested by the application */
1329 must_add_close = false;
1330 must_add_chunked_encoding = false;
1331 must_add_keep_alive = false;
1332 must_add_content_length = false;
1333 content_length_len = 0; /* Mute compiler warning only */
1334 response_has_close = false;
1335 switch (connection->state)
1336 {
1338 response_has_close = MHD_check_response_header_s_token_ci (response,
1340 "close");
1341 response_has_keepalive = MHD_check_response_header_s_token_ci (response,
1343 "Keep-Alive");
1344 client_requested_close = MHD_lookup_header_s_token_ci (connection,
1346 "close");
1347
1348 if (0 != (response->flags & MHD_RF_HTTP_VERSION_1_0_ONLY))
1349 connection->keepalive = MHD_CONN_MUST_CLOSE;
1350#ifdef UPGRADE_SUPPORT
1351 else if (NULL != response->upgrade_handler)
1352 /* If this connection will not be "upgraded", it must be closed. */
1353 connection->keepalive = MHD_CONN_MUST_CLOSE;
1354#endif /* UPGRADE_SUPPORT */
1355
1356 /* now analyze chunked encoding situation */
1357 connection->have_chunked_upload = false;
1358 have_encoding = MHD_get_response_header (response,
1360 if (NULL == have_encoding)
1361 may_add_content_length = true;
1362 else
1363 may_add_content_length = false; /* RFC 7230, Section 3.3.2 forbids header */
1364 if ( (MHD_SIZE_UNKNOWN == response->total_size) &&
1365#ifdef UPGRADE_SUPPORT
1366 (NULL == response->upgrade_handler) &&
1367#endif /* UPGRADE_SUPPORT */
1368 (! response_has_close) &&
1369 (! client_requested_close) )
1370 {
1371 /* size is unknown, and close was not explicitly requested;
1372 need to either to HTTP 1.1 chunked encoding or
1373 close the connection */
1374 /* 'close' header doesn't exist yet, see if we need to add one;
1375 if the client asked for a close, no need to start chunk'ing */
1376 if ( (MHD_NO != keepalive_possible (connection)) &&
1378 connection->version) ) )
1379 {
1380 if (NULL == have_encoding)
1381 {
1382 must_add_chunked_encoding = true;
1383 connection->have_chunked_upload = true;
1384 }
1385 else
1386 {
1387 if (MHD_str_equal_caseless_ (have_encoding,
1388 "identity"))
1389 {
1390 /* application forced identity encoding, can't do 'chunked' */
1391 must_add_close = true;
1392 }
1393 else
1394 {
1395 connection->have_chunked_upload = true;
1396 }
1397 }
1398 }
1399 else
1400 {
1401 /* Keep alive or chunking not possible
1402 => set close header (we know response_has_close
1403 is false here) */
1404 must_add_close = true;
1405 }
1406 }
1407
1408 /* check for other reasons to add 'close' header */
1409 if ( ( (client_requested_close) ||
1410 (connection->read_closed) ||
1411 (MHD_CONN_MUST_CLOSE == connection->keepalive)) &&
1412 (! response_has_close) &&
1413#ifdef UPGRADE_SUPPORT
1414 (NULL == response->upgrade_handler) &&
1415#endif /* UPGRADE_SUPPORT */
1416 (0 == (response->flags & MHD_RF_HTTP_VERSION_1_0_ONLY) ) )
1417 must_add_close = true;
1418
1419 /* check if we must add 'close' header because we cannot add content-length
1420 because it is forbidden AND we don't have a 'chunked' encoding */
1421 if ( (! may_add_content_length) &&
1422 (! connection->have_chunked_upload) &&
1423 (! response_has_close) )
1424 must_add_close = true;
1425 /* #MHD_HTTP_NO_CONTENT, #MHD_HTTP_NOT_MODIFIED and 1xx-status
1426 codes SHOULD NOT have a Content-Length according to spec;
1427 also chunked encoding / unknown length or CONNECT... */
1428 if ( (MHD_SIZE_UNKNOWN != response->total_size) &&
1429 (MHD_HTTP_NO_CONTENT != rc) &&
1430 (MHD_HTTP_NOT_MODIFIED != rc) &&
1431 (MHD_HTTP_OK <= rc) &&
1432 (NULL == /* this COULD fail if the check in
1433 MHD_add_response_header() was bypassed
1434 via #MHD_RF_INSANITY_HEADER_CONTENT_LENGTH */
1435 MHD_get_response_header (response,
1437 (may_add_content_length) &&
1438 ( (NULL == connection->method) ||
1439 (! MHD_str_equal_caseless_ (connection->method,
1441 {
1442 /*
1443 Here we add a content-length if one is missing; however,
1444 for 'connect' methods, the responses MUST NOT include a
1445 content-length header *if* the response code is 2xx (in
1446 which case we expect there to be no body). Still,
1447 as we don't know the response code here in some cases, we
1448 simply only force adding a content-length header if this
1449 is not a 'connect' or if the response is not empty
1450 (which is kind of more sane, because if some crazy
1451 application did return content with a 2xx status code,
1452 then having a content-length might again be a good idea).
1453
1454 Note that the change from 'SHOULD NOT' to 'MUST NOT' is
1455 a recent development of the HTTP 1.1 specification.
1456 */
1457 content_length_len
1458 = MHD_snprintf_ (content_length_buf,
1459 sizeof (content_length_buf),
1463 must_add_content_length = true;
1464 }
1465
1466 /* check for adding keep alive */
1467 if ( (! response_has_keepalive) &&
1468 (! response_has_close) &&
1469 (! must_add_close) &&
1470 (MHD_CONN_MUST_CLOSE != connection->keepalive) &&
1471#ifdef UPGRADE_SUPPORT
1472 (NULL == response->upgrade_handler) &&
1473#endif /* UPGRADE_SUPPORT */
1474 (MHD_NO != keepalive_possible (connection)) )
1475 must_add_keep_alive = true;
1476 break;
1478 response_has_keepalive = false;
1479 break;
1480 default:
1481 mhd_assert (0);
1482 return MHD_NO;
1483 }
1484
1485 if (MHD_CONN_MUST_CLOSE != connection->keepalive)
1486 {
1487 if ( (must_add_close) || (response_has_close) )
1488 connection->keepalive = MHD_CONN_MUST_CLOSE;
1489 else if ( (must_add_keep_alive) || (response_has_keepalive) )
1490 connection->keepalive = MHD_CONN_USE_KEEPALIVE;
1491 }
1492
1493 if (must_add_close)
1494 size += MHD_STATICSTR_LEN_ ("Connection: close\r\n");
1495 if (must_add_keep_alive)
1496 size += MHD_STATICSTR_LEN_ ("Connection: Keep-Alive\r\n");
1497 if (must_add_chunked_encoding)
1498 size += MHD_STATICSTR_LEN_ ("Transfer-Encoding: chunked\r\n");
1499 if (must_add_content_length)
1500 size += content_length_len;
1501 mhd_assert (! (must_add_close && must_add_keep_alive) );
1502 mhd_assert (! (must_add_chunked_encoding && must_add_content_length) );
1503
1504 for (pos = response->first_header; NULL != pos; pos = pos->next)
1505 {
1506 /* TODO: add proper support for excluding "Keep-Alive" token. */
1507 if ( (pos->kind == kind) &&
1508 (! ( (must_add_close) &&
1509 (response_has_keepalive) &&
1517 "Keep-Alive")) ) ) )
1518 size += pos->header_size + pos->value_size + 4; /* colon, space, linefeeds */
1519 }
1520 /* produce data */
1521 data = MHD_pool_allocate (connection->pool,
1522 size + 1,
1523 false);
1524 if (NULL == data)
1525 {
1526#ifdef HAVE_MESSAGES
1527 MHD_DLOG (connection->daemon,
1528 "Not enough memory for write!\n");
1529#endif
1530 return MHD_NO;
1531 }
1532 if (MHD_CONNECTION_FOOTERS_RECEIVED == connection->state)
1533 {
1534 memcpy (data,
1535 code,
1536 off);
1537 }
1538 if (must_add_close)
1539 {
1540 /* we must add the 'Connection: close' header */
1541 memcpy (&data[off],
1542 "Connection: close\r\n",
1543 MHD_STATICSTR_LEN_ ("Connection: close\r\n"));
1544 off += MHD_STATICSTR_LEN_ ("Connection: close\r\n");
1545 }
1546 if (must_add_keep_alive)
1547 {
1548 /* we must add the 'Connection: Keep-Alive' header */
1549 memcpy (&data[off],
1550 "Connection: Keep-Alive\r\n",
1551 MHD_STATICSTR_LEN_ ("Connection: Keep-Alive\r\n"));
1552 off += MHD_STATICSTR_LEN_ ("Connection: Keep-Alive\r\n");
1553 }
1554 if (must_add_chunked_encoding)
1555 {
1556 /* we must add the 'Transfer-Encoding: chunked' header */
1557 memcpy (&data[off],
1558 "Transfer-Encoding: chunked\r\n",
1559 MHD_STATICSTR_LEN_ ("Transfer-Encoding: chunked\r\n"));
1560 off += MHD_STATICSTR_LEN_ ("Transfer-Encoding: chunked\r\n");
1561 }
1562 if (must_add_content_length)
1563 {
1564 /* we must add the 'Content-Length' header */
1565 memcpy (&data[off],
1566 content_length_buf,
1567 content_length_len);
1568 off += content_length_len;
1569 }
1570 for (pos = response->first_header; NULL != pos; pos = pos->next)
1571 {
1572 /* TODO: add proper support for excluding "Keep-Alive" token. */
1573 if ( (pos->kind == kind) &&
1574 (! ( (must_add_close) &&
1575 (response_has_keepalive) &&
1583 "Keep-Alive")) ) ) )
1584 off += MHD_snprintf_ (&data[off],
1585 size - off,
1586 "%s: %s\r\n",
1587 pos->header,
1588 pos->value);
1589 }
1590 if (MHD_CONNECTION_FOOTERS_RECEIVED == connection->state)
1591 {
1592 memcpy (&data[off],
1593 date,
1594 datelen);
1595 off += datelen;
1596 }
1597 memcpy (&data[off],
1598 "\r\n",
1599 2);
1600 off += 2;
1601
1602 if (off != size)
1604 __FILE__,
1605 __LINE__,
1606 NULL);
1607 connection->write_buffer = data;
1608 connection->write_buffer_append_offset = size;
1609 connection->write_buffer_send_offset = 0;
1610 connection->write_buffer_size = size + 1;
1611 return MHD_YES;
1612}
1613
1614
1624static void
1626 unsigned int status_code,
1627 const char *message)
1628{
1629 struct MHD_Response *response;
1630 enum MHD_Result iret;
1631
1632 if (NULL == connection->version)
1633 {
1634 /* we were unable to process the full header line, so we don't
1635 really know what version the client speaks; assume 1.0 */
1636 connection->version = MHD_HTTP_VERSION_1_0;
1637 }
1639 connection->read_closed = true;
1640 if (0 != connection->read_buffer_size)
1641 {
1642 /* Read buffer is not needed anymore, discard it
1643 * to free some space for error response. */
1644 connection->read_buffer = MHD_pool_reallocate (connection->pool,
1645 connection->read_buffer,
1646 connection->read_buffer_size,
1647 0);
1648 connection->read_buffer_size = 0;
1649 }
1650#ifdef HAVE_MESSAGES
1651 MHD_DLOG (connection->daemon,
1652 _ (
1653 "Error processing request (HTTP response code is %u (`%s')). Closing connection.\n"),
1655 message);
1656#endif
1657 if (NULL != connection->response)
1658 {
1659 MHD_destroy_response (connection->response);
1660 connection->response = NULL;
1661 }
1662 response = MHD_create_response_from_buffer (strlen (message),
1663 (void *) message,
1665 if (NULL == response)
1666 {
1667 /* can't even send a reply, at least close the connection */
1668 connection->state = MHD_CONNECTION_CLOSED;
1669 return;
1670 }
1671 iret = MHD_queue_response (connection,
1673 response);
1674 MHD_destroy_response (response);
1675 if (MHD_NO == iret)
1676 {
1677 /* can't even send a reply, at least close the connection */
1678 CONNECTION_CLOSE_ERROR (connection,
1679 _ (
1680 "Closing connection (failed to queue response)."));
1681 return;
1682 }
1683 mhd_assert (NULL != connection->response);
1684 /* Do not reuse this connection. */
1685 connection->keepalive = MHD_CONN_MUST_CLOSE;
1686 if (MHD_NO == build_header_response (connection))
1687 {
1688 /* oops - close! */
1689 CONNECTION_CLOSE_ERROR (connection,
1690 _ (
1691 "Closing connection (failed to create response header)."));
1692 }
1693 else
1694 {
1696 }
1697}
1698
1699
1708static void
1710{
1711 /* Do not update states of suspended connection */
1712 if (connection->suspended)
1713 return; /* States will be updated after resume. */
1714#ifdef HTTPS_SUPPORT
1715 if (MHD_TLS_CONN_NO_TLS != connection->tls_state)
1716 { /* HTTPS connection. */
1717 switch (connection->tls_state)
1718 {
1719 case MHD_TLS_CONN_INIT:
1721 return;
1723 if (0 == gnutls_record_get_direction (connection->tls_session))
1725 else
1727 return;
1728 default:
1729 break;
1730 }
1731 }
1732#endif /* HTTPS_SUPPORT */
1733 while (1)
1734 {
1735#if DEBUG_STATES
1736 MHD_DLOG (connection->daemon,
1737 _ ("In function %s handling connection at state: %s\n"),
1738 __FUNCTION__,
1739 MHD_state_to_string (connection->state));
1740#endif
1741 switch (connection->state)
1742 {
1746 /* while reading headers, we always grow the
1747 read buffer if needed, no size-check required */
1748 if ( (connection->read_buffer_offset == connection->read_buffer_size) &&
1749 (! try_grow_read_buffer (connection, true)) )
1750 {
1751 transmit_error_response (connection,
1752 (connection->url != NULL)
1756 continue;
1757 }
1758 if (! connection->read_closed)
1760 else
1762 break;
1764 mhd_assert (0);
1765 break;
1767 mhd_assert (0);
1768 break;
1771 break;
1773 if (connection->read_buffer_offset == connection->read_buffer_size)
1774 {
1775 const bool internal_poll = (0 != (connection->daemon->options
1777 if ( (! try_grow_read_buffer (connection, true)) &&
1778 internal_poll)
1779 {
1780 /* failed to grow the read buffer, and the
1781 client which is supposed to handle the
1782 received data in a *blocking* fashion
1783 (in this mode) did not handle the data as
1784 it was supposed to!
1785 => we would either have to do busy-waiting
1786 (on the client, which would likely fail),
1787 or if we do nothing, we would just timeout
1788 on the connection (if a timeout is even
1789 set!).
1790 Solution: we kill the connection with an error */
1791 transmit_error_response (connection,
1794 continue;
1795 }
1796 }
1797 if ( (connection->read_buffer_offset < connection->read_buffer_size) &&
1798 (! connection->read_closed) )
1800 else
1802 break;
1805 /* while reading footers, we always grow the
1806 read buffer if needed, no size-check required */
1807 if (connection->read_closed)
1808 {
1809 CONNECTION_CLOSE_ERROR (connection,
1810 NULL);
1811 continue;
1812 }
1814 /* transition to FOOTERS_RECEIVED
1815 happens in read handler */
1816 break;
1819 break;
1821 /* headers in buffer, keep writing */
1823 break;
1825 mhd_assert (0);
1826 break;
1829 break;
1832 break;
1835 break;
1838 break;
1840 mhd_assert (0);
1841 break;
1844 break;
1846 mhd_assert (0);
1847 break;
1850 return; /* do nothing, not even reading */
1851#ifdef UPGRADE_SUPPORT
1852 case MHD_CONNECTION_UPGRADE:
1853 mhd_assert (0);
1854 break;
1855#endif /* UPGRADE_SUPPORT */
1856 default:
1857 mhd_assert (0);
1858 }
1859 break;
1860 }
1861}
1862
1863
1877static char *
1879 size_t *line_len)
1880{
1881 char *rbuf;
1882 size_t pos;
1883
1884 if (0 == connection->read_buffer_offset)
1885 return NULL;
1886 pos = 0;
1887 rbuf = connection->read_buffer;
1888 while ( (pos < connection->read_buffer_offset - 1) &&
1889 ('\r' != rbuf[pos]) &&
1890 ('\n' != rbuf[pos]) )
1891 pos++;
1892 if ( (pos == connection->read_buffer_offset - 1) &&
1893 ('\n' != rbuf[pos]) )
1894 {
1895 /* not found, consider growing... */
1896 if ( (connection->read_buffer_offset == connection->read_buffer_size) &&
1897 (! try_grow_read_buffer (connection, true)) )
1898 {
1899 transmit_error_response (connection,
1900 (NULL != connection->url)
1904 }
1905 if (line_len)
1906 *line_len = 0;
1907 return NULL;
1908 }
1909
1910 if (line_len)
1911 *line_len = pos;
1912 /* found, check if we have proper LFCR */
1913 if ( ('\r' == rbuf[pos]) &&
1914 ('\n' == rbuf[pos + 1]) )
1915 rbuf[pos++] = '\0'; /* skip both r and n */
1916 rbuf[pos++] = '\0';
1917 connection->read_buffer += pos;
1918 connection->read_buffer_size -= pos;
1919 connection->read_buffer_offset -= pos;
1920 return rbuf;
1921}
1922
1923
1937static enum MHD_Result
1939 const char *key,
1940 size_t key_size,
1941 const char *value,
1942 size_t value_size,
1943 enum MHD_ValueKind kind)
1944{
1945 if (MHD_NO ==
1946 MHD_set_connection_value_n (connection,
1947 kind,
1948 key,
1949 key_size,
1950 value,
1951 value_size))
1952 {
1953#ifdef HAVE_MESSAGES
1954 MHD_DLOG (connection->daemon,
1955 _ ("Not enough memory in pool to allocate header record!\n"));
1956#endif
1957 transmit_error_response (connection,
1960 return MHD_NO;
1961 }
1962 return MHD_YES;
1963}
1964
1965
1972static enum MHD_Result
1974{
1975 const char *hdr;
1976 size_t hdr_len;
1977 char *cpy;
1978 char *pos;
1979 char *sce;
1980 char *semicolon;
1981 char *equals;
1982 char *ekill;
1983 char *end;
1984 char old;
1985 int quotes;
1986
1987 if (MHD_NO == MHD_lookup_connection_value_n (connection,
1992 &hdr,
1993 &hdr_len))
1994 return MHD_YES;
1995 cpy = MHD_pool_allocate (connection->pool,
1996 hdr_len + 1,
1997 true);
1998 if (NULL == cpy)
1999 {
2000#ifdef HAVE_MESSAGES
2001 MHD_DLOG (connection->daemon,
2002 _ ("Not enough memory in pool to parse cookies!\n"));
2003#endif
2004 transmit_error_response (connection,
2007 return MHD_NO;
2008 }
2009 memcpy (cpy,
2010 hdr,
2011 hdr_len);
2012 cpy[hdr_len] = '\0';
2013 pos = cpy;
2014 while (NULL != pos)
2015 {
2016 while (' ' == *pos)
2017 pos++; /* skip spaces */
2018
2019 sce = pos;
2020 while ( ((*sce) != '\0') &&
2021 ((*sce) != ',') &&
2022 ((*sce) != ';') &&
2023 ((*sce) != '=') )
2024 sce++;
2025 /* remove tailing whitespace (if any) from key */
2026 ekill = sce - 1;
2027 while ( (*ekill == ' ') &&
2028 (ekill >= pos) )
2029 *(ekill--) = '\0';
2030 old = *sce;
2031 *sce = '\0';
2032 if (old != '=')
2033 {
2034 /* value part omitted, use empty string... */
2035 if (MHD_NO ==
2036 connection_add_header (connection,
2037 pos,
2038 ekill - pos + 1,
2039 "",
2040 0,
2042 return MHD_NO;
2043 if (old == '\0')
2044 break;
2045 pos = sce + 1;
2046 continue;
2047 }
2048 equals = sce + 1;
2049 quotes = 0;
2050 semicolon = equals;
2051 while ( ('\0' != semicolon[0]) &&
2052 ( (0 != quotes) ||
2053 ( (';' != semicolon[0]) &&
2054 (',' != semicolon[0]) ) ) )
2055 {
2056 if ('"' == semicolon[0])
2057 quotes = (quotes + 1) & 1;
2058 semicolon++;
2059 }
2060 end = semicolon;
2061 if ('\0' == semicolon[0])
2062 semicolon = NULL;
2063 if (NULL != semicolon)
2064 {
2065 semicolon[0] = '\0';
2066 semicolon++;
2067 }
2068 /* remove quotes */
2069 if ( ('"' == equals[0]) &&
2070 ('"' == end[-1]) )
2071 {
2072 equals++;
2073 end--;
2074 *end = '\0';
2075 }
2076 if (MHD_NO ==
2077 connection_add_header (connection,
2078 pos,
2079 ekill - pos + 1,
2080 equals,
2081 end - equals,
2083 return MHD_NO;
2084 pos = semicolon;
2085 }
2086 return MHD_YES;
2087}
2088
2089
2098static enum MHD_Result
2100 char *line,
2101 size_t line_len)
2102{
2103 struct MHD_Daemon *daemon = connection->daemon;
2104 const char *curi;
2105 char *uri;
2106 char *http_version;
2107 char *args;
2108 unsigned int unused_num_headers;
2109
2110 if (NULL == (uri = memchr (line,
2111 ' ',
2112 line_len)))
2113 return MHD_NO; /* serious error */
2114 uri[0] = '\0';
2115 connection->method = line;
2116 uri++;
2117 /* Skip any spaces. Not required by standard but allow
2118 to be more tolerant. */
2119 while ( (' ' == uri[0]) &&
2120 ( (size_t) (uri - line) < line_len) )
2121 uri++;
2122 if ((size_t) (uri - line) == line_len)
2123 {
2124 /* No URI and no http version given */
2125 curi = "";
2126 uri = NULL;
2127 connection->version = "";
2128 args = NULL;
2129 }
2130 else
2131 {
2132 size_t uri_len;
2133 curi = uri;
2134 /* Search from back to accept malformed URI with space */
2135 http_version = line + line_len - 1;
2136 /* Skip any trailing spaces */
2137 while ( (' ' == http_version[0]) &&
2138 (http_version > uri) )
2139 http_version--;
2140 /* Find first space in reverse direction */
2141 while ( (' ' != http_version[0]) &&
2142 (http_version > uri) )
2143 http_version--;
2144 if (http_version > uri)
2145 {
2146 /* http_version points to character before HTTP version string */
2147 http_version[0] = '\0';
2148 connection->version = http_version + 1;
2149 uri_len = http_version - uri;
2150 }
2151 else
2152 {
2153 connection->version = "";
2154 uri_len = line_len - (uri - line);
2155 }
2156 /* check for spaces in URI if we are "strict" */
2157 if ( (1 <= daemon->strict_for_client) &&
2158 (NULL != memchr (uri,
2159 ' ',
2160 uri_len)) )
2161 {
2162 /* space exists in URI and we are supposed to be strict, reject */
2163 return MHD_NO;
2164 }
2165
2166 args = memchr (uri,
2167 '?',
2168 uri_len);
2169 }
2170
2171 /* log callback before we modify URI *or* args */
2172 if (NULL != daemon->uri_log_callback)
2173 {
2174 connection->client_aware = true;
2175 connection->client_context
2176 = daemon->uri_log_callback (daemon->uri_log_callback_cls,
2177 uri,
2178 connection);
2179 }
2180
2181 if (NULL != args)
2182 {
2183 args[0] = '\0';
2184 args++;
2185 /* note that this call clobbers 'args' */
2186 MHD_parse_arguments_ (connection,
2188 args,
2190 &unused_num_headers);
2191 }
2192
2193 /* unescape URI *after* searching for arguments and log callback */
2194 if (NULL != uri)
2196 connection,
2197 uri);
2198 connection->url = curi;
2199 return MHD_YES;
2200}
2201
2202
2210static void
2212{
2213 struct MHD_Daemon *daemon = connection->daemon;
2214 size_t processed;
2215
2216 if (NULL != connection->response)
2217 return; /* already queued a response */
2218 processed = 0;
2219 connection->client_aware = true;
2220 if (MHD_NO ==
2221 daemon->default_handler (daemon->default_handler_cls,
2222 connection,
2223 connection->url,
2224 connection->method,
2225 connection->version,
2226 NULL,
2227 &processed,
2228 &connection->client_context))
2229 {
2230 /* serious internal error, close connection */
2231 CONNECTION_CLOSE_ERROR (connection,
2232 _ (
2233 "Application reported internal error, closing connection."));
2234 return;
2235 }
2236}
2237
2238
2246static void
2248{
2249 struct MHD_Daemon *daemon = connection->daemon;
2250 size_t available;
2251 int instant_retry;
2252 char *buffer_head;
2253
2254 if (NULL != connection->response)
2255 {
2256 /* already queued a response, discard remaining upload
2257 (but not more, there might be another request after it) */
2258 size_t purge;
2259
2260 purge = (size_t) MHD_MIN (connection->remaining_upload_size,
2261 (uint64_t) connection->read_buffer_offset);
2262 connection->remaining_upload_size -= purge;
2263 if (connection->read_buffer_offset > purge)
2264 memmove (connection->read_buffer,
2265 &connection->read_buffer[purge],
2266 connection->read_buffer_offset - purge);
2267 connection->read_buffer_offset -= purge;
2268 return;
2269 }
2270
2271 buffer_head = connection->read_buffer;
2272 available = connection->read_buffer_offset;
2273 do
2274 {
2275 size_t to_be_processed;
2276 size_t left_unprocessed;
2277 size_t processed_size;
2278
2279 instant_retry = MHD_NO;
2280 if ( (connection->have_chunked_upload) &&
2281 (MHD_SIZE_UNKNOWN == connection->remaining_upload_size) )
2282 {
2283 if ( (connection->current_chunk_offset ==
2284 connection->current_chunk_size) &&
2285 (0LLU != connection->current_chunk_offset) &&
2286 (available >= 2) )
2287 {
2288 size_t i;
2289 /* skip new line at the *end* of a chunk */
2290 i = 0;
2291 if ( ('\r' == buffer_head[i]) ||
2292 ('\n' == buffer_head[i]) )
2293 i++; /* skip 1st part of line feed */
2294 if ( ('\r' == buffer_head[i]) ||
2295 ('\n' == buffer_head[i]) )
2296 i++; /* skip 2nd part of line feed */
2297 if (0 == i)
2298 {
2299 /* malformed encoding */
2300 CONNECTION_CLOSE_ERROR (connection,
2301 _ (
2302 "Received malformed HTTP request (bad chunked encoding). Closing connection."));
2303 return;
2304 }
2305 available -= i;
2306 buffer_head += i;
2307 connection->current_chunk_offset = 0;
2308 connection->current_chunk_size = 0;
2309 }
2310 if (connection->current_chunk_offset <
2311 connection->current_chunk_size)
2312 {
2313 uint64_t cur_chunk_left;
2314 /* we are in the middle of a chunk, give
2315 as much as possible to the client (without
2316 crossing chunk boundaries) */
2317 cur_chunk_left
2318 = connection->current_chunk_size - connection->current_chunk_offset;
2319 if (cur_chunk_left > available)
2320 to_be_processed = available;
2321 else
2322 { /* cur_chunk_left <= (size_t)available */
2323 to_be_processed = (size_t) cur_chunk_left;
2324 if (available > to_be_processed)
2325 instant_retry = MHD_YES;
2326 }
2327 }
2328 else
2329 {
2330 size_t i;
2331 size_t end_size;
2332 bool malformed;
2333
2334 /* we need to read chunk boundaries */
2335 i = 0;
2336 while (i < available)
2337 {
2338 if ( ('\r' == buffer_head[i]) ||
2339 ('\n' == buffer_head[i]) ||
2340 (';' == buffer_head[i]) )
2341 break;
2342 i++;
2343 if (i >= 16)
2344 break;
2345 }
2346 end_size = i;
2347 /* find beginning of CRLF (skip over chunk extensions) */
2348 if (';' == buffer_head[i])
2349 {
2350 while (i < available)
2351 {
2352 if ( ('\r' == buffer_head[i]) ||
2353 ('\n' == buffer_head[i]) )
2354 break;
2355 i++;
2356 }
2357 }
2358 /* take '\n' into account; if '\n' is the unavailable
2359 character, we will need to wait until we have it
2360 before going further */
2361 if ( (i + 1 >= available) &&
2362 ! ( (1 == i) &&
2363 (2 == available) &&
2364 ('0' == buffer_head[0]) ) )
2365 break; /* need more data... */
2366 i++;
2367 malformed = (end_size >= 16);
2368 if (! malformed)
2369 {
2370 size_t num_dig = MHD_strx_to_uint64_n_ (buffer_head,
2371 end_size,
2372 &connection->
2373 current_chunk_size);
2374 malformed = (end_size != num_dig);
2375 }
2376 if (malformed)
2377 {
2378 /* malformed encoding */
2379 CONNECTION_CLOSE_ERROR (connection,
2380 _ (
2381 "Received malformed HTTP request (bad chunked encoding). Closing connection."));
2382 return;
2383 }
2384 /* skip 2nd part of line feed */
2385 if ( (i < available) &&
2386 ( ('\r' == buffer_head[i]) ||
2387 ('\n' == buffer_head[i]) ) )
2388 i++;
2389
2390 buffer_head += i;
2391 available -= i;
2392 connection->current_chunk_offset = 0;
2393
2394 if (available > 0)
2395 instant_retry = MHD_YES;
2396 if (0LLU == connection->current_chunk_size)
2397 {
2398 connection->remaining_upload_size = 0;
2399 break;
2400 }
2401 continue;
2402 }
2403 }
2404 else
2405 {
2406 /* no chunked encoding, give all to the client */
2407 if ( (0 != connection->remaining_upload_size) &&
2408 (MHD_SIZE_UNKNOWN != connection->remaining_upload_size) &&
2409 (connection->remaining_upload_size < available) )
2410 {
2411 to_be_processed = (size_t) connection->remaining_upload_size;
2412 }
2413 else
2414 {
2419 to_be_processed = available;
2420 }
2421 }
2422 left_unprocessed = to_be_processed;
2423 connection->client_aware = true;
2424 if (MHD_NO ==
2425 daemon->default_handler (daemon->default_handler_cls,
2426 connection,
2427 connection->url,
2428 connection->method,
2429 connection->version,
2430 buffer_head,
2431 &left_unprocessed,
2432 &connection->client_context))
2433 {
2434 /* serious internal error, close connection */
2435 CONNECTION_CLOSE_ERROR (connection,
2436 _ (
2437 "Application reported internal error, closing connection."));
2438 return;
2439 }
2440 if (left_unprocessed > to_be_processed)
2442 __FILE__,
2443 __LINE__
2444#ifdef HAVE_MESSAGES
2445 , _ ("libmicrohttpd API violation.\n")
2446#else
2447 , NULL
2448#endif
2449 );
2450 if (0 != left_unprocessed)
2451 {
2452 instant_retry = MHD_NO; /* client did not process everything */
2453#ifdef HAVE_MESSAGES
2454 /* client did not process all upload data, complain if
2455 the setup was incorrect, which may prevent us from
2456 handling the rest of the request */
2457 if ( (0 != (daemon->options & MHD_USE_INTERNAL_POLLING_THREAD)) &&
2458 (! connection->suspended) )
2459 MHD_DLOG (daemon,
2460 _ (
2461 "WARNING: incomplete upload processing and connection not suspended may result in hung connection.\n"));
2462#endif
2463 }
2464 processed_size = to_be_processed - left_unprocessed;
2465 if (connection->have_chunked_upload)
2466 connection->current_chunk_offset += processed_size;
2467 /* dh left "processed" bytes in buffer for next time... */
2468 buffer_head += processed_size;
2469 available -= processed_size;
2470 if (MHD_SIZE_UNKNOWN != connection->remaining_upload_size)
2471 connection->remaining_upload_size -= processed_size;
2472 }
2473 while (MHD_NO != instant_retry);
2474 if ( (available > 0) &&
2475 (buffer_head != connection->read_buffer) )
2476 memmove (connection->read_buffer,
2477 buffer_head,
2478 available);
2479 connection->read_buffer_offset = available;
2480}
2481
2482
2491static enum MHD_Result
2493 enum MHD_CONNECTION_STATE next_state)
2494{
2495 if ( (connection->write_buffer_append_offset !=
2496 connection->write_buffer_send_offset)
2497 /* || data_in_tls_buffers == true */
2498 )
2499 return MHD_NO;
2500 connection->write_buffer_append_offset = 0;
2501 connection->write_buffer_send_offset = 0;
2502 connection->state = next_state;
2503 MHD_pool_reallocate (connection->pool,
2504 connection->write_buffer,
2505 connection->write_buffer_size,
2506 0);
2507 connection->write_buffer = NULL;
2508 connection->write_buffer_size = 0;
2509 return MHD_YES;
2510}
2511
2512
2522static enum MHD_Result
2524 char *line)
2525{
2526 char *colon;
2527
2528 /* line should be normal header line, find colon */
2529 colon = strchr (line, ':');
2530 if (NULL == colon)
2531 {
2532 /* error in header line, die hard */
2533 CONNECTION_CLOSE_ERROR (connection,
2534 _ (
2535 "Received malformed line (no colon). Closing connection."));
2536 return MHD_NO;
2537 }
2538 if (-1 >= connection->daemon->strict_for_client)
2539 {
2540 /* check for whitespace before colon, which is not allowed
2541 by RFC 7230 section 3.2.4; we count space ' ' and
2542 tab '\t', but not '\r\n' as those would have ended the line. */
2543 const char *white;
2544
2545 white = strchr (line, ' ');
2546 if ( (NULL != white) &&
2547 (white < colon) )
2548 return MHD_NO;
2549 white = strchr (line, '\t');
2550 if ( (NULL != white) &&
2551 (white < colon) )
2552 return MHD_NO;
2553 }
2554 /* zero-terminate header */
2555 colon[0] = '\0';
2556 colon++; /* advance to value */
2557 while ( ('\0' != colon[0]) &&
2558 ( (' ' == colon[0]) ||
2559 ('\t' == colon[0]) ) )
2560 colon++;
2561 /* we do the actual adding of the connection
2562 header at the beginning of the while
2563 loop since we need to be able to inspect
2564 the *next* header line (in case it starts
2565 with a space...) */
2566 connection->last = line;
2567 connection->colon = colon;
2568 return MHD_YES;
2569}
2570
2571
2582static enum MHD_Result
2584 char *line,
2585 enum MHD_ValueKind kind)
2586{
2587 char *last;
2588 char *tmp;
2589 size_t last_len;
2590 size_t tmp_len;
2591
2592 last = connection->last;
2593 if ( (' ' == line[0]) ||
2594 ('\t' == line[0]) )
2595 {
2596 /* value was continued on the next line, see
2597 http://www.jmarshall.com/easy/http/ */
2598 last_len = strlen (last);
2599 /* skip whitespace at start of 2nd line */
2600 tmp = line;
2601 while ( (' ' == tmp[0]) ||
2602 ('\t' == tmp[0]) )
2603 tmp++;
2604 tmp_len = strlen (tmp);
2605 /* FIXME: we might be able to do this better (faster!), as most
2606 likely 'last' and 'line' should already be adjacent in
2607 memory; however, doing this right gets tricky if we have a
2608 value continued over multiple lines (in which case we need to
2609 record how often we have done this so we can check for
2610 adjacency); also, in the case where these are not adjacent
2611 (not sure how it can happen!), we would want to allocate from
2612 the end of the pool, so as to not destroy the read-buffer's
2613 ability to grow nicely. */
2614 last = MHD_pool_reallocate (connection->pool,
2615 last,
2616 last_len + 1,
2617 last_len + tmp_len + 1);
2618 if (NULL == last)
2619 {
2620 transmit_error_response (connection,
2623 return MHD_NO;
2624 }
2625 memcpy (&last[last_len],
2626 tmp,
2627 tmp_len + 1);
2628 connection->last = last;
2629 return MHD_YES; /* possibly more than 2 lines... */
2630 }
2631 mhd_assert ( (NULL != last) &&
2632 (NULL != connection->colon) );
2633 if (MHD_NO ==
2634 connection_add_header (connection,
2635 last,
2636 strlen (last),
2637 connection->colon,
2638 strlen (connection->colon),
2639 kind))
2640 {
2641 transmit_error_response (connection,
2644 return MHD_NO;
2645 }
2646 /* we still have the current line to deal with... */
2647 if (0 != line[0])
2648 {
2649 if (MHD_NO == process_header_line (connection,
2650 line))
2651 {
2652 transmit_error_response (connection,
2655 return MHD_NO;
2656 }
2657 }
2658 return MHD_YES;
2659}
2660
2661
2669static void
2671{
2672 const char *clen;
2673 struct MHD_Response *response;
2674 const char *enc;
2675 const char *end;
2676
2677 parse_cookie_header (connection);
2678 if ( (1 <= connection->daemon->strict_for_client) &&
2679 (NULL != connection->version) &&
2681 connection->version)) &&
2682 (MHD_NO ==
2688 NULL,
2689 NULL)) )
2690 {
2691 enum MHD_Result iret;
2692
2693 /* die, http 1.1 request without host and we are pedantic */
2695 connection->read_closed = true;
2696#ifdef HAVE_MESSAGES
2697 MHD_DLOG (connection->daemon,
2698 _ ("Received HTTP 1.1 request without `Host' header.\n"));
2699#endif
2700 mhd_assert (NULL == connection->response);
2701 response =
2705 if (NULL == response)
2706 {
2707 /* can't even send a reply, at least close the connection */
2708 CONNECTION_CLOSE_ERROR (connection,
2709 _ (
2710 "Closing connection (failed to create response)."));
2711 return;
2712 }
2713 iret = MHD_queue_response (connection,
2715 response);
2716 MHD_destroy_response (response);
2717 if (MHD_NO == iret)
2718 {
2719 /* can't even send a reply, at least close the connection */
2720 CONNECTION_CLOSE_ERROR (connection,
2721 _ (
2722 "Closing connection (failed to queue response)."));
2723 }
2724 return;
2725 }
2726
2727 connection->remaining_upload_size = 0;
2728 if (MHD_NO != MHD_lookup_connection_value_n (connection,
2733 &enc,
2734 NULL))
2735 {
2737 if (MHD_str_equal_caseless_ (enc,
2738 "chunked"))
2739 connection->have_chunked_upload = true;
2740 }
2741 else
2742 {
2743 if (MHD_NO != MHD_lookup_connection_value_n (connection,
2748 &clen,
2749 NULL))
2750 {
2751 end = clen + MHD_str_to_uint64_ (clen,
2752 &connection->remaining_upload_size);
2753 if ( (clen == end) ||
2754 ('\0' != *end) )
2755 {
2756 connection->remaining_upload_size = 0;
2757#ifdef HAVE_MESSAGES
2758 MHD_DLOG (connection->daemon,
2759 _ (
2760 "Failed to parse `Content-Length' header. Closing connection.\n"));
2761#endif
2762 CONNECTION_CLOSE_ERROR (connection,
2763 NULL);
2764 return;
2765 }
2766 }
2767 }
2768}
2769
2770
2778void
2780{
2781 struct MHD_Daemon *daemon = connection->daemon;
2782
2783 if (0 == connection->connection_timeout)
2784 return; /* Skip update of activity for connections
2785 without timeout timer. */
2786 if (connection->suspended)
2787 return; /* no activity on suspended connections */
2788
2790 if (0 != (daemon->options & MHD_USE_THREAD_PER_CONNECTION))
2791 return; /* each connection has personal timeout */
2792
2793 if (connection->connection_timeout != daemon->connection_timeout)
2794 return; /* custom timeout, no need to move it in "normal" DLL */
2795#if defined(MHD_USE_POSIX_THREADS) || defined(MHD_USE_W32_THREADS)
2797#endif
2798 /* move connection to head of timeout list (by remove + add operation) */
2800 daemon->normal_timeout_tail,
2801 connection);
2803 daemon->normal_timeout_tail,
2804 connection);
2805#if defined(MHD_USE_POSIX_THREADS) || defined(MHD_USE_W32_THREADS)
2807#endif
2808}
2809
2810
2817void
2819{
2820 ssize_t bytes_read;
2821
2822 if ( (MHD_CONNECTION_CLOSED == connection->state) ||
2823 (connection->suspended) )
2824 return;
2825#ifdef HTTPS_SUPPORT
2826 if (MHD_TLS_CONN_NO_TLS != connection->tls_state)
2827 { /* HTTPS connection. */
2828 if (MHD_TLS_CONN_CONNECTED > connection->tls_state)
2829 {
2830 if (! MHD_run_tls_handshake_ (connection))
2831 return;
2832 }
2833 }
2834#endif /* HTTPS_SUPPORT */
2835
2836 /* make sure "read" has a reasonable number of bytes
2837 in buffer to use per system call (if possible) */
2838 if (connection->read_buffer_offset + connection->daemon->pool_increment >
2839 connection->read_buffer_size)
2840 try_grow_read_buffer (connection,
2841 (connection->read_buffer_size ==
2842 connection->read_buffer_offset));
2843
2844 if (connection->read_buffer_size == connection->read_buffer_offset)
2845 return; /* No space for receiving data. */
2846 bytes_read = connection->recv_cls (connection,
2847 &connection->read_buffer
2848 [connection->read_buffer_offset],
2849 connection->read_buffer_size
2850 - connection->read_buffer_offset);
2851 if (bytes_read < 0)
2852 {
2853 if (MHD_ERR_AGAIN_ == bytes_read)
2854 return; /* No new data to process. */
2855 if (MHD_ERR_CONNRESET_ == bytes_read)
2856 {
2857 CONNECTION_CLOSE_ERROR (connection,
2858 (MHD_CONNECTION_INIT == connection->state) ?
2859 NULL :
2860 _ (
2861 "Socket disconnected while reading request."));
2862 return;
2863 }
2864
2865#ifdef HAVE_MESSAGES
2866 if (MHD_CONNECTION_INIT != connection->state)
2867 MHD_DLOG (connection->daemon,
2868 _ ("Connection socket is closed when reading " \
2869 "request due to the error: %s\n"),
2870 str_conn_error_ (bytes_read));
2871#endif
2872 CONNECTION_CLOSE_ERROR (connection,
2873 NULL);
2874 return;
2875 }
2876
2877 if (0 == bytes_read)
2878 { /* Remote side closed connection. */
2879 connection->read_closed = true;
2880 MHD_connection_close_ (connection,
2882 return;
2883 }
2884 connection->read_buffer_offset += bytes_read;
2885 MHD_update_last_activity_ (connection);
2886#if DEBUG_STATES
2887 MHD_DLOG (connection->daemon,
2888 _ ("In function %s handling connection at state: %s\n"),
2889 __FUNCTION__,
2890 MHD_state_to_string (connection->state));
2891#endif
2892 switch (connection->state)
2893 {
2903 /* nothing to do but default action */
2904 if (connection->read_closed)
2905 {
2906 MHD_connection_close_ (connection,
2908 }
2909 return;
2911 return;
2912#ifdef UPGRADE_SUPPORT
2913 case MHD_CONNECTION_UPGRADE:
2914 mhd_assert (0);
2915 return;
2916#endif /* UPGRADE_SUPPORT */
2917 default:
2918 /* shrink read buffer to how much is actually used */
2919 MHD_pool_reallocate (connection->pool,
2920 connection->read_buffer,
2921 connection->read_buffer_size + 1,
2922 connection->read_buffer_offset);
2923 break;
2924 }
2925 return;
2926}
2927
2928
2935void
2937{
2938 struct MHD_Response *response;
2939 ssize_t ret;
2940 if (connection->suspended)
2941 return;
2942
2943#ifdef HTTPS_SUPPORT
2944 if (MHD_TLS_CONN_NO_TLS != connection->tls_state)
2945 { /* HTTPS connection. */
2946 if (MHD_TLS_CONN_CONNECTED > connection->tls_state)
2947 {
2948 if (! MHD_run_tls_handshake_ (connection))
2949 return;
2950 }
2951 }
2952#endif /* HTTPS_SUPPORT */
2953
2954#if DEBUG_STATES
2955 MHD_DLOG (connection->daemon,
2956 _ ("In function %s handling connection at state: %s\n"),
2957 __FUNCTION__,
2958 MHD_state_to_string (connection->state));
2959#endif
2960 switch (connection->state)
2961 {
2966 mhd_assert (0);
2967 return;
2969 return;
2971 ret = MHD_send_data_ (connection,
2973 [connection->continue_message_write_offset],
2975 - connection->continue_message_write_offset,
2976 true);
2977 if (ret < 0)
2978 {
2979 if (MHD_ERR_AGAIN_ == ret)
2980 return;
2981#ifdef HAVE_MESSAGES
2982 MHD_DLOG (connection->daemon,
2983 _ ("Failed to send data in request for %s.\n"),
2984 connection->url);
2985#endif
2986 CONNECTION_CLOSE_ERROR (connection,
2987 NULL);
2988 return;
2989 }
2990#if _MHD_DEBUG_SEND_DATA
2991 fprintf (stderr,
2992 _ ("Sent 100 continue response: `%.*s'\n"),
2993 (int) ret,
2995#endif
2996 connection->continue_message_write_offset += ret;
2997 MHD_update_last_activity_ (connection);
2998 return;
3003 mhd_assert (0);
3004 return;
3006 {
3007 struct MHD_Response *const resp = connection->response;
3008 const size_t wb_ready = connection->write_buffer_append_offset
3009 - connection->write_buffer_send_offset;
3010 mhd_assert (connection->write_buffer_append_offset >= \
3011 connection->write_buffer_send_offset);
3012 mhd_assert (NULL != resp);
3013 mhd_assert ( (0 == resp->data_size) || \
3014 (0 == resp->data_start) || \
3015 (NULL != resp->crc) );
3016 mhd_assert ( (0 == connection->response_write_position) || \
3017 (resp->total_size ==
3018 connection->response_write_position) || \
3020 connection->response_write_position) );
3021
3022 if ( (NULL == resp->crc) &&
3023 (NULL == resp->data_iov) &&
3024 (0 == connection->response_write_position) )
3025 {
3026 mhd_assert (resp->total_size >= resp->data_size);
3027 /* Send response headers alongside the response body, if the body
3028 * data is available. */
3029 ret = MHD_send_hdr_and_body_ (connection,
3030 &connection->write_buffer
3031 [connection->write_buffer_send_offset],
3032 wb_ready,
3033 false,
3034 resp->data,
3035 resp->data_size,
3036 (resp->total_size == resp->data_size));
3037 }
3038 else
3039 {
3040 /* This is response for HEAD request or reply body is not allowed
3041 * for any other reason or reply body is dynamically generated. */
3042 /* Do not send the body data even if it's available. */
3043 ret = MHD_send_hdr_and_body_ (connection,
3044 &connection->write_buffer
3045 [connection->write_buffer_send_offset],
3046 wb_ready,
3047 false,
3048 NULL,
3049 0,
3050 ((0 == resp->total_size) ||
3051 (resp->total_size ==
3052 connection->response_write_position) ||
3054 connection->response_write_position)));
3055 }
3056
3057 if (ret < 0)
3058 {
3059 if (MHD_ERR_AGAIN_ == ret)
3060 return;
3061#ifdef HAVE_MESSAGES
3062 MHD_DLOG (connection->daemon,
3063 _ ("Failed to send the response headers for the " \
3064 "request for `%s'. Error: %s\n"),
3065 connection->url,
3066 str_conn_error_ (ret));
3067#endif
3068 CONNECTION_CLOSE_ERROR (connection,
3069 NULL);
3070 return;
3071 }
3072 /* 'ret' is not negative, it's safe to cast it to 'size_t'. */
3073 if (((size_t) ret) > wb_ready)
3074 {
3075 /* The complete header and some response data have been sent,
3076 * update both offsets. */
3077 mhd_assert (0 == connection->response_write_position);
3078 mhd_assert (! connection->have_chunked_upload);
3079 connection->write_buffer_send_offset += wb_ready;
3080 connection->response_write_position = ret - wb_ready;
3081 }
3082 else
3083 connection->write_buffer_send_offset += ret;
3084 MHD_update_last_activity_ (connection);
3085 if (MHD_CONNECTION_HEADERS_SENDING != connection->state)
3086 return;
3087 check_write_done (connection,
3089 return;
3090 }
3092 return;
3094 response = connection->response;
3095 if (connection->response_write_position <
3096 connection->response->total_size)
3097 {
3098 uint64_t data_write_offset;
3099
3100#if defined(MHD_USE_POSIX_THREADS) || defined(MHD_USE_W32_THREADS)
3101 if (NULL != response->crc)
3102 MHD_mutex_lock_chk_ (&response->mutex);
3103#endif
3104 if (MHD_NO == try_ready_normal_body (connection))
3105 {
3106 /* mutex was already unlocked by try_ready_normal_body */
3107 return;
3108 }
3109#if defined(_MHD_HAVE_SENDFILE)
3110 if (MHD_resp_sender_sendfile == connection->resp_sender)
3111 {
3112 mhd_assert (NULL == response->data_iov);
3113 ret = MHD_send_sendfile_ (connection);
3114 }
3115 else /* combined with the next 'if' */
3116#endif /* _MHD_HAVE_SENDFILE */
3117 if (NULL != response->data_iov)
3118 {
3119 ret = MHD_send_iovec_ (connection,
3120 &connection->resp_iov,
3121 true);
3122 }
3123 else
3124 {
3125 data_write_offset = connection->response_write_position
3126 - response->data_start;
3127 if (data_write_offset > (uint64_t) SIZE_MAX)
3128 MHD_PANIC (_ ("Data offset exceeds limit.\n"));
3129 ret = MHD_send_data_ (connection,
3130 &response->data
3131 [(size_t) data_write_offset],
3132 response->data_size
3133 - (size_t) data_write_offset,
3134 true);
3135#if _MHD_DEBUG_SEND_DATA
3136 if (ret > 0)
3137 fprintf (stderr,
3138 _ ("Sent %d-byte DATA response: `%.*s'\n"),
3139 (int) ret,
3140 (int) ret,
3141 &response->data[connection->response_write_position
3142 - response->data_start]);
3143#endif
3144 }
3145#if defined(MHD_USE_POSIX_THREADS) || defined(MHD_USE_W32_THREADS)
3146 if (NULL != response->crc)
3147 MHD_mutex_unlock_chk_ (&response->mutex);
3148#endif
3149 if (ret < 0)
3150 {
3151 if (MHD_ERR_AGAIN_ == ret)
3152 return;
3153#ifdef HAVE_MESSAGES
3154 MHD_DLOG (connection->daemon,
3155 _ ("Failed to send the response body for the " \
3156 "request for `%s'. Error: %s\n"),
3157 connection->url,
3158 str_conn_error_ (ret));
3159#endif
3160 CONNECTION_CLOSE_ERROR (connection,
3161 NULL);
3162 return;
3163 }
3164 connection->response_write_position += ret;
3165 MHD_update_last_activity_ (connection);
3166 }
3167 if (connection->response_write_position ==
3168 connection->response->total_size)
3169 connection->state = MHD_CONNECTION_FOOTERS_SENT; /* have no footers */
3170 return;
3172 mhd_assert (0);
3173 return;
3175 ret = MHD_send_data_ (connection,
3176 &connection->write_buffer
3177 [connection->write_buffer_send_offset],
3178 connection->write_buffer_append_offset
3179 - connection->write_buffer_send_offset,
3180 true);
3181 if (ret < 0)
3182 {
3183 if (MHD_ERR_AGAIN_ == ret)
3184 return;
3185#ifdef HAVE_MESSAGES
3186 MHD_DLOG (connection->daemon,
3187 _ ("Failed to send the chunked response body for the " \
3188 "request for `%s'. Error: %s\n"),
3189 connection->url,
3190 str_conn_error_ (ret));
3191#endif
3192 CONNECTION_CLOSE_ERROR (connection,
3193 NULL);
3194 return;
3195 }
3196 connection->write_buffer_send_offset += ret;
3197 MHD_update_last_activity_ (connection);
3198 if (MHD_CONNECTION_CHUNKED_BODY_READY != connection->state)
3199 return;
3200 check_write_done (connection,
3201 (connection->response->total_size ==
3202 connection->response_write_position) ?
3205 return;
3208 mhd_assert (0);
3209 return;
3211 ret = MHD_send_data_ (connection,
3212 &connection->write_buffer
3213 [connection->write_buffer_send_offset],
3214 connection->write_buffer_append_offset
3215 - connection->write_buffer_send_offset,
3216 true);
3217 if (ret < 0)
3218 {
3219 if (MHD_ERR_AGAIN_ == ret)
3220 return;
3221#ifdef HAVE_MESSAGES
3222 MHD_DLOG (connection->daemon,
3223 _ ("Failed to send the footers for the " \
3224 "request for `%s'. Error: %s\n"),
3225 connection->url,
3226 str_conn_error_ (ret));
3227#endif
3228 CONNECTION_CLOSE_ERROR (connection,
3229 NULL);
3230 return;
3231 }
3232 connection->write_buffer_send_offset += ret;
3233 MHD_update_last_activity_ (connection);
3234 if (MHD_CONNECTION_FOOTERS_SENDING != connection->state)
3235 return;
3236 check_write_done (connection,
3238 return;
3240 mhd_assert (0);
3241 return;
3243 return;
3244#ifdef UPGRADE_SUPPORT
3245 case MHD_CONNECTION_UPGRADE:
3246 mhd_assert (0);
3247 return;
3248#endif /* UPGRADE_SUPPORT */
3249 default:
3250 mhd_assert (0);
3251 CONNECTION_CLOSE_ERROR (connection,
3252 _ ("Internal error.\n"));
3253 break;
3254 }
3255 return;
3256}
3257
3258
3267static void
3269{
3270 struct MHD_Daemon *daemon = connection->daemon;
3271#ifdef MHD_USE_THREADS
3272 mhd_assert ( (0 == (daemon->options & MHD_USE_INTERNAL_POLLING_THREAD)) || \
3273 MHD_thread_ID_match_current_ (connection->pid) );
3274#endif /* MHD_USE_THREADS */
3275
3276 if (connection->in_cleanup)
3277 return; /* Prevent double cleanup. */
3278 connection->in_cleanup = true;
3279 if (NULL != connection->response)
3280 {
3281 MHD_destroy_response (connection->response);
3282 connection->response = NULL;
3283 }
3284#if defined(MHD_USE_POSIX_THREADS) || defined(MHD_USE_W32_THREADS)
3286#endif
3287 if (connection->suspended)
3288 {
3291 connection);
3292 connection->suspended = false;
3293 }
3294 else
3295 {
3296 if (0 == (daemon->options & MHD_USE_THREAD_PER_CONNECTION))
3297 {
3298 if (connection->connection_timeout == daemon->connection_timeout)
3300 daemon->normal_timeout_tail,
3301 connection);
3302 else
3304 daemon->manual_timeout_tail,
3305 connection);
3306 }
3308 daemon->connections_tail,
3309 connection);
3310 }
3311 DLL_insert (daemon->cleanup_head,
3312 daemon->cleanup_tail,
3313 connection);
3314 connection->resuming = false;
3315 connection->in_idle = false;
3316#if defined(MHD_USE_POSIX_THREADS) || defined(MHD_USE_W32_THREADS)
3318#endif
3319 if (0 != (daemon->options & MHD_USE_THREAD_PER_CONNECTION))
3320 {
3321 /* if we were at the connection limit before and are in
3322 thread-per-connection mode, signal the main thread
3323 to resume accepting connections */
3324 if ( (MHD_ITC_IS_VALID_ (daemon->itc)) &&
3325 (! MHD_itc_activate_ (daemon->itc, "c")) )
3326 {
3327#ifdef HAVE_MESSAGES
3328 MHD_DLOG (daemon,
3329 _ (
3330 "Failed to signal end of connection via inter-thread communication channel.\n"));
3331#endif
3332 }
3333 }
3334}
3335
3336
3347enum MHD_Result
3349{
3350 struct MHD_Daemon *daemon = connection->daemon;
3351 char *line;
3352 size_t line_len;
3353 enum MHD_Result ret;
3354#ifdef MHD_USE_THREADS
3355 mhd_assert ( (0 == (daemon->options & MHD_USE_INTERNAL_POLLING_THREAD)) || \
3356 MHD_thread_ID_match_current_ (connection->pid) );
3357#endif /* MHD_USE_THREADS */
3358
3359 connection->in_idle = true;
3360 while (! connection->suspended)
3361 {
3362#ifdef HTTPS_SUPPORT
3363 if (MHD_TLS_CONN_NO_TLS != connection->tls_state)
3364 { /* HTTPS connection. */
3365 if ((MHD_TLS_CONN_INIT <= connection->tls_state) &&
3366 (MHD_TLS_CONN_CONNECTED > connection->tls_state))
3367 break;
3368 }
3369#endif /* HTTPS_SUPPORT */
3370#if DEBUG_STATES
3371 MHD_DLOG (daemon,
3372 _ ("In function %s handling connection at state: %s\n"),
3373 __FUNCTION__,
3374 MHD_state_to_string (connection->state));
3375#endif
3376 switch (connection->state)
3377 {
3379 line = get_next_header_line (connection,
3380 &line_len);
3381 /* Check for empty string, as we might want
3382 to tolerate 'spurious' empty lines; also
3383 NULL means we didn't get a full line yet;
3384 line is not 0-terminated here. */
3385 if ( (NULL == line) ||
3386 (0 == line[0]) )
3387 {
3388 if (MHD_CONNECTION_INIT != connection->state)
3389 continue;
3390 if (connection->read_closed)
3391 {
3392 CONNECTION_CLOSE_ERROR (connection,
3393 NULL);
3394 continue;
3395 }
3396 break;
3397 }
3398 if (MHD_NO == parse_initial_message_line (connection,
3399 line,
3400 line_len))
3401 CONNECTION_CLOSE_ERROR (connection,
3402 NULL);
3403 else
3404 connection->state = MHD_CONNECTION_URL_RECEIVED;
3405 continue;
3407 line = get_next_header_line (connection,
3408 NULL);
3409 if (NULL == line)
3410 {
3411 if (MHD_CONNECTION_URL_RECEIVED != connection->state)
3412 continue;
3413 if (connection->read_closed)
3414 {
3415 CONNECTION_CLOSE_ERROR (connection,
3416 NULL);
3417 continue;
3418 }
3419 break;
3420 }
3421 if (0 == line[0])
3422 {
3424 connection->header_size = (size_t) (line - connection->read_buffer);
3425 continue;
3426 }
3427 if (MHD_NO == process_header_line (connection,
3428 line))
3429 {
3430 transmit_error_response (connection,
3433 break;
3434 }
3436 continue;
3438 line = get_next_header_line (connection,
3439 NULL);
3440 if (NULL == line)
3441 {
3442 if (connection->state != MHD_CONNECTION_HEADER_PART_RECEIVED)
3443 continue;
3444 if (connection->read_closed)
3445 {
3446 CONNECTION_CLOSE_ERROR (connection,
3447 NULL);
3448 continue;
3449 }
3450 break;
3451 }
3452 if (MHD_NO ==
3453 process_broken_line (connection,
3454 line,
3456 continue;
3457 if (0 == line[0])
3458 {
3460 connection->header_size = (size_t) (line - connection->read_buffer);
3461 continue;
3462 }
3463 continue;
3465 parse_connection_headers (connection);
3466 if (MHD_CONNECTION_CLOSED == connection->state)
3467 continue;
3469 if (connection->suspended)
3470 break;
3471 continue;
3473 call_connection_handler (connection); /* first call */
3474 if (MHD_CONNECTION_CLOSED == connection->state)
3475 continue;
3476 if (connection->suspended)
3477 continue;
3478 if ( (NULL == connection->response) &&
3479 (need_100_continue (connection)) )
3480 {
3482 break;
3483 }
3484 if ( (NULL != connection->response) &&
3485 (0 != connection->remaining_upload_size) )
3486 {
3487 /* we refused (no upload allowed!) */
3488 connection->remaining_upload_size = 0;
3489 /* force close, in case client still tries to upload... */
3490 connection->read_closed = true;
3491 }
3492 connection->state = (0 == connection->remaining_upload_size)
3495 if (connection->suspended)
3496 break;
3497 continue;
3499 if (connection->continue_message_write_offset ==
3501 {
3502 connection->state = MHD_CONNECTION_CONTINUE_SENT;
3503 continue;
3504 }
3505 break;
3507 if (0 != connection->read_buffer_offset)
3508 {
3509 process_request_body (connection); /* loop call */
3510 if (MHD_CONNECTION_CLOSED == connection->state)
3511 continue;
3512 }
3513 if ( (0 == connection->remaining_upload_size) ||
3514 ( (MHD_SIZE_UNKNOWN == connection->remaining_upload_size) &&
3515 (0 == connection->read_buffer_offset) &&
3516 (connection->read_closed) ) )
3517 {
3518 if ( (connection->have_chunked_upload) &&
3519 (! connection->read_closed) )
3520 connection->state = MHD_CONNECTION_BODY_RECEIVED;
3521 else
3523 if (connection->suspended)
3524 break;
3525 continue;
3526 }
3527 break;
3529 line = get_next_header_line (connection,
3530 NULL);
3531 if (NULL == line)
3532 {
3533 if (connection->state != MHD_CONNECTION_BODY_RECEIVED)
3534 continue;
3535 if (connection->read_closed)
3536 {
3537 CONNECTION_CLOSE_ERROR (connection,
3538 NULL);
3539 continue;
3540 }
3541 break;
3542 }
3543 if (0 == line[0])
3544 {
3546 if (connection->suspended)
3547 break;
3548 continue;
3549 }
3550 if (MHD_NO == process_header_line (connection,
3551 line))
3552 {
3553 transmit_error_response (connection,
3556 break;
3557 }
3559 continue;
3561 line = get_next_header_line (connection,
3562 NULL);
3563 if (NULL == line)
3564 {
3565 if (connection->state != MHD_CONNECTION_FOOTER_PART_RECEIVED)
3566 continue;
3567 if (connection->read_closed)
3568 {
3569 CONNECTION_CLOSE_ERROR (connection,
3570 NULL);
3571 continue;
3572 }
3573 break;
3574 }
3575 if (MHD_NO ==
3576 process_broken_line (connection,
3577 line,
3579 continue;
3580 if (0 == line[0])
3581 {
3583 if (connection->suspended)
3584 break;
3585 continue;
3586 }
3587 continue;
3589 call_connection_handler (connection); /* "final" call */
3590 if (connection->state == MHD_CONNECTION_CLOSED)
3591 continue;
3592 if (NULL == connection->response)
3593 break; /* try again next time */
3594 if (MHD_NO == build_header_response (connection))
3595 {
3596 /* oops - close! */
3597 CONNECTION_CLOSE_ERROR (connection,
3598 _ (
3599 "Closing connection (failed to create response header).\n"));
3600 continue;
3601 }
3603 break;
3605 /* no default action */
3606 break;
3608 /* Some clients may take some actions right after header receive */
3609#ifdef UPGRADE_SUPPORT
3610 if (NULL != connection->response->upgrade_handler)
3611 {
3612 connection->state = MHD_CONNECTION_UPGRADE;
3613 /* This connection is "upgraded". Pass socket to application. */
3614 if (MHD_NO ==
3616 connection))
3617 {
3618 /* upgrade failed, fail hard */
3619 CONNECTION_CLOSE_ERROR (connection,
3620 NULL);
3621 continue;
3622 }
3623 /* Response is not required anymore for this connection. */
3624 {
3625 struct MHD_Response *const resp = connection->response;
3626
3627 connection->response = NULL;
3628 MHD_destroy_response (resp);
3629 }
3630 continue;
3631 }
3632#endif /* UPGRADE_SUPPORT */
3633
3634 if (connection->have_chunked_upload)
3636 else
3638 continue;
3640 /* nothing to do here */
3641 break;
3643#if defined(MHD_USE_POSIX_THREADS) || defined(MHD_USE_W32_THREADS)
3644 if (NULL != connection->response->crc)
3645 MHD_mutex_lock_chk_ (&connection->response->mutex);
3646#endif
3647 if (0 == connection->response->total_size)
3648 {
3649#if defined(MHD_USE_POSIX_THREADS) || defined(MHD_USE_W32_THREADS)
3650 if (NULL != connection->response->crc)
3651 MHD_mutex_unlock_chk_ (&connection->response->mutex);
3652#endif
3653 connection->state = MHD_CONNECTION_BODY_SENT;
3654 continue;
3655 }
3656 if (MHD_NO != try_ready_normal_body (connection))
3657 {
3658#if defined(MHD_USE_POSIX_THREADS) || defined(MHD_USE_W32_THREADS)
3659 if (NULL != connection->response->crc)
3660 MHD_mutex_unlock_chk_ (&connection->response->mutex);
3661#endif
3663 /* Buffering for flushable socket was already enabled*/
3664
3665 break;
3666 }
3667 /* mutex was already unlocked by "try_ready_normal_body */
3668 /* not ready, no socket action */
3669 break;
3671 /* nothing to do here */
3672 break;
3674#if defined(MHD_USE_POSIX_THREADS) || defined(MHD_USE_W32_THREADS)
3675 if (NULL != connection->response->crc)
3676 MHD_mutex_lock_chk_ (&connection->response->mutex);
3677#endif
3678 if ( (0 == connection->response->total_size) ||
3679 (connection->response_write_position ==
3680 connection->response->total_size) )
3681 {
3682#if defined(MHD_USE_POSIX_THREADS) || defined(MHD_USE_W32_THREADS)
3683 if (NULL != connection->response->crc)
3684 MHD_mutex_unlock_chk_ (&connection->response->mutex);
3685#endif
3686 connection->state = MHD_CONNECTION_BODY_SENT;
3687 continue;
3688 }
3689 if (MHD_NO != try_ready_chunked_body (connection))
3690 {
3691#if defined(MHD_USE_POSIX_THREADS) || defined(MHD_USE_W32_THREADS)
3692 if (NULL != connection->response->crc)
3693 MHD_mutex_unlock_chk_ (&connection->response->mutex);
3694#endif
3696 /* Buffering for flushable socket was already enabled */
3697
3698 continue;
3699 }
3700 /* mutex was already unlocked by try_ready_chunked_body */
3701 break;
3703 if (MHD_NO == build_header_response (connection))
3704 {
3705 /* oops - close! */
3706 CONNECTION_CLOSE_ERROR (connection,
3707 _ (
3708 "Closing connection (failed to create response header)."));
3709 continue;
3710 }
3711 if ( (! connection->have_chunked_upload) ||
3712 (connection->write_buffer_send_offset ==
3713 connection->write_buffer_append_offset) )
3714 connection->state = MHD_CONNECTION_FOOTERS_SENT;
3715 else
3717 continue;
3719 /* no default action */
3720 break;
3722 if (MHD_HTTP_PROCESSING == connection->responseCode)
3723 {
3724 /* After this type of response, we allow sending another! */
3726 MHD_destroy_response (connection->response);
3727 connection->response = NULL;
3728 /* FIXME: maybe partially reset memory pool? */
3729 continue;
3730 }
3731 MHD_destroy_response (connection->response);
3732 connection->response = NULL;
3733 if ( (NULL != daemon->notify_completed) &&
3734 (connection->client_aware) )
3735 {
3736 daemon->notify_completed (daemon->notify_completed_cls,
3737 connection,
3738 &connection->client_context,
3740 }
3741 connection->client_aware = false;
3742 if ( (MHD_CONN_USE_KEEPALIVE != connection->keepalive) ||
3743 (connection->read_closed) )
3744 {
3745 /* have to close for some reason */
3746 MHD_connection_close_ (connection,
3748 MHD_pool_destroy (connection->pool);
3749 connection->pool = NULL;
3750 connection->read_buffer = NULL;
3751 connection->read_buffer_size = 0;
3752 connection->read_buffer_offset = 0;
3753 }
3754 else
3755 {
3756 /* can try to keep-alive */
3757
3758 connection->version = NULL;
3759 connection->state = MHD_CONNECTION_INIT;
3760 connection->last = NULL;
3761 connection->colon = NULL;
3762 connection->header_size = 0;
3764 /* Reset the read buffer to the starting size,
3765 preserving the bytes we have already read. */
3766 connection->read_buffer
3767 = MHD_pool_reset (connection->pool,
3768 connection->read_buffer,
3769 connection->read_buffer_offset,
3770 connection->daemon->pool_size / 2);
3771 connection->read_buffer_size
3772 = connection->daemon->pool_size / 2;
3773 }
3774 connection->client_context = NULL;
3775 connection->continue_message_write_offset = 0;
3776 connection->responseCode = 0;
3777 connection->headers_received = NULL;
3778 connection->headers_received_tail = NULL;
3779 connection->response_write_position = 0;
3780 connection->have_chunked_upload = false;
3781 connection->current_chunk_size = 0;
3782 connection->current_chunk_offset = 0;
3783 connection->method = NULL;
3784 connection->url = NULL;
3785 connection->write_buffer = NULL;
3786 connection->write_buffer_size = 0;
3787 connection->write_buffer_send_offset = 0;
3788 connection->write_buffer_append_offset = 0;
3789 /* iov (if any) was deallocated by MHD_pool_reset */
3790 memset (&connection->resp_iov, 0, sizeof(connection->resp_iov));
3791 continue;
3793 cleanup_connection (connection);
3794 connection->in_idle = false;
3795 return MHD_NO;
3796#ifdef UPGRADE_SUPPORT
3797 case MHD_CONNECTION_UPGRADE:
3798 connection->in_idle = false;
3799 return MHD_YES; /* keep open */
3800#endif /* UPGRADE_SUPPORT */
3801 default:
3802 mhd_assert (0);
3803 break;
3804 }
3805 break;
3806 }
3807 if (! connection->suspended)
3808 {
3809 time_t timeout;
3810 timeout = connection->connection_timeout;
3811 if ( (0 != timeout) &&
3812 (timeout < (MHD_monotonic_sec_counter ()
3813 - connection->last_activity)) )
3814 {
3815 MHD_connection_close_ (connection,
3817 connection->in_idle = false;
3818 return MHD_YES;
3819 }
3820 }
3822 ret = MHD_YES;
3823#ifdef EPOLL_SUPPORT
3824 if ( (! connection->suspended) &&
3825 (0 != (daemon->options & MHD_USE_EPOLL)) )
3826 {
3827 ret = MHD_connection_epoll_update_ (connection);
3828 }
3829#endif /* EPOLL_SUPPORT */
3830 connection->in_idle = false;
3831 return ret;
3832}
3833
3834
3835#ifdef EPOLL_SUPPORT
3844enum MHD_Result
3845MHD_connection_epoll_update_ (struct MHD_Connection *connection)
3846{
3847 struct MHD_Daemon *daemon = connection->daemon;
3848
3849 if ( (0 != (daemon->options & MHD_USE_EPOLL)) &&
3850 (0 == (connection->epoll_state & MHD_EPOLL_STATE_IN_EPOLL_SET)) &&
3851 (0 == (connection->epoll_state & MHD_EPOLL_STATE_SUSPENDED)) &&
3852 ( ( (MHD_EVENT_LOOP_INFO_WRITE == connection->event_loop_info) &&
3853 (0 == (connection->epoll_state & MHD_EPOLL_STATE_WRITE_READY))) ||
3854 ( (MHD_EVENT_LOOP_INFO_READ == connection->event_loop_info) &&
3855 (0 == (connection->epoll_state & MHD_EPOLL_STATE_READ_READY)) ) ) )
3856 {
3857 /* add to epoll set */
3858 struct epoll_event event;
3859
3860 event.events = EPOLLIN | EPOLLOUT | EPOLLPRI | EPOLLET;
3861 event.data.ptr = connection;
3862 if (0 != epoll_ctl (daemon->epoll_fd,
3863 EPOLL_CTL_ADD,
3864 connection->socket_fd,
3865 &event))
3866 {
3867#ifdef HAVE_MESSAGES
3868 if (0 != (daemon->options & MHD_USE_ERROR_LOG))
3869 MHD_DLOG (daemon,
3870 _ ("Call to epoll_ctl failed: %s\n"),
3872#endif
3873 connection->state = MHD_CONNECTION_CLOSED;
3874 cleanup_connection (connection);
3875 return MHD_NO;
3876 }
3877 connection->epoll_state |= MHD_EPOLL_STATE_IN_EPOLL_SET;
3878 }
3879 return MHD_YES;
3880}
3881
3882
3883#endif
3884
3885
3891void
3893{
3894 connection->recv_cls = &recv_param_adapter;
3895}
3896
3897
3908const union MHD_ConnectionInfo *
3910 enum MHD_ConnectionInfoType info_type,
3911 ...)
3912{
3913 switch (info_type)
3914 {
3915#ifdef HTTPS_SUPPORT
3917 if (NULL == connection->tls_session)
3918 return NULL;
3919 connection->cipher = gnutls_cipher_get (connection->tls_session);
3920 return (const union MHD_ConnectionInfo *) &connection->cipher;
3922 if (NULL == connection->tls_session)
3923 return NULL;
3924 connection->protocol = gnutls_protocol_get_version (
3925 connection->tls_session);
3926 return (const union MHD_ConnectionInfo *) &connection->protocol;
3928 if (NULL == connection->tls_session)
3929 return NULL;
3930 return (const union MHD_ConnectionInfo *) &connection->tls_session;
3931#endif /* HTTPS_SUPPORT */
3933 return (const union MHD_ConnectionInfo *) &connection->addr;
3935 return (const union MHD_ConnectionInfo *) &connection->daemon;
3937 return (const union MHD_ConnectionInfo *) &connection->socket_fd;
3939 return (const union MHD_ConnectionInfo *) &connection->socket_context;
3941 connection->suspended_dummy = connection->suspended ? MHD_YES : MHD_NO;
3942 return (const union MHD_ConnectionInfo *) &connection->suspended_dummy;
3944 connection->connection_timeout_dummy = (unsigned
3945 int) connection->connection_timeout;
3946 return (const union MHD_ConnectionInfo *) &connection->
3947 connection_timeout_dummy;
3949 if ( (MHD_CONNECTION_HEADERS_RECEIVED > connection->state) ||
3950 (MHD_CONNECTION_CLOSED == connection->state) )
3951 return NULL; /* invalid, too early! */
3952 return (const union MHD_ConnectionInfo *) &connection->header_size;
3953 default:
3954 return NULL;
3955 }
3956}
3957
3958
3968enum MHD_Result
3970 enum MHD_CONNECTION_OPTION option,
3971 ...)
3972{
3973 va_list ap;
3974 struct MHD_Daemon *daemon;
3975
3976 daemon = connection->daemon;
3977 switch (option)
3978 {
3980 if (0 == connection->connection_timeout)
3982#if defined(MHD_USE_POSIX_THREADS) || defined(MHD_USE_W32_THREADS)
3984#endif
3985 if ( (0 == (daemon->options & MHD_USE_THREAD_PER_CONNECTION)) &&
3986 (! connection->suspended) )
3987 {
3988 if (connection->connection_timeout == daemon->connection_timeout)
3990 daemon->normal_timeout_tail,
3991 connection);
3992 else
3994 daemon->manual_timeout_tail,
3995 connection);
3996 }
3997 va_start (ap, option);
3998 connection->connection_timeout = va_arg (ap,
3999 unsigned int);
4000 va_end (ap);
4001 if ( (0 == (daemon->options & MHD_USE_THREAD_PER_CONNECTION)) &&
4002 (! connection->suspended) )
4003 {
4004 if (connection->connection_timeout == daemon->connection_timeout)
4006 daemon->normal_timeout_tail,
4007 connection);
4008 else
4010 daemon->manual_timeout_tail,
4011 connection);
4012 }
4013#if defined(MHD_USE_POSIX_THREADS) || defined(MHD_USE_W32_THREADS)
4015#endif
4016 return MHD_YES;
4017 default:
4018 return MHD_NO;
4019 }
4020}
4021
4022
4034enum MHD_Result
4036 unsigned int status_code,
4037 struct MHD_Response *response)
4038{
4039 struct MHD_Daemon *daemon;
4040
4041 if ( (NULL == connection) ||
4042 (NULL == response) ||
4043 (NULL != connection->response) ||
4044 ( (MHD_CONNECTION_HEADERS_PROCESSED != connection->state) &&
4045 (MHD_CONNECTION_FOOTERS_RECEIVED != connection->state) ) )
4046 return MHD_NO;
4047 daemon = connection->daemon;
4048
4049 if (daemon->shutdown)
4050 return MHD_YES; /* If daemon was shut down in parallel,
4051 * response will be aborted now or on later stage. */
4052
4053#if defined(MHD_USE_POSIX_THREADS) || defined(MHD_USE_W32_THREADS)
4054 if ( (! connection->suspended) &&
4055 (0 != (daemon->options & MHD_USE_INTERNAL_POLLING_THREAD)) &&
4056 (! MHD_thread_ID_match_current_ (connection->pid)) )
4057 {
4058#ifdef HAVE_MESSAGES
4059 MHD_DLOG (daemon,
4060 _ ("Attempted to queue response on wrong thread!\n"));
4061#endif
4062 return MHD_NO;
4063 }
4064#endif
4065#ifdef UPGRADE_SUPPORT
4066 if ( (NULL != response->upgrade_handler) &&
4067 (0 == (daemon->options & MHD_ALLOW_UPGRADE)) )
4068 {
4069#ifdef HAVE_MESSAGES
4070 MHD_DLOG (daemon,
4071 _ (
4072 "Attempted 'upgrade' connection on daemon without MHD_ALLOW_UPGRADE option!\n"));
4073#endif
4074 return MHD_NO;
4075 }
4076 if ( (MHD_HTTP_SWITCHING_PROTOCOLS != status_code) &&
4077 (NULL != response->upgrade_handler) )
4078 {
4079#ifdef HAVE_MESSAGES
4080 MHD_DLOG (daemon,
4081 _ (
4082 "Application used invalid status code for 'upgrade' response!\n"));
4083#endif
4084 return MHD_NO;
4085 }
4086#endif /* UPGRADE_SUPPORT */
4087 MHD_increment_response_rc (response);
4088 connection->response = response;
4089 connection->responseCode = status_code;
4090#if defined(_MHD_HAVE_SENDFILE)
4091 if ( (response->fd == -1) ||
4092 (response->is_pipe) ||
4093 (0 != (connection->daemon->options & MHD_USE_TLS))
4094#if defined(MHD_SEND_SPIPE_SUPPRESS_NEEDED) && \
4095 defined(MHD_SEND_SPIPE_SUPPRESS_POSSIBLE)
4096 || (! daemon->sigpipe_blocked && ! connection->sk_spipe_suppress)
4097#endif /* MHD_SEND_SPIPE_SUPPRESS_NEEDED &&
4098 MHD_SEND_SPIPE_SUPPRESS_POSSIBLE */
4099 )
4100 connection->resp_sender = MHD_resp_sender_std;
4101 else
4102 connection->resp_sender = MHD_resp_sender_sendfile;
4103#endif /* _MHD_HAVE_SENDFILE */
4104 /* FIXME: if 'is_pipe' is set, TLS is off, and we have *splice*, we could use splice()
4105 to avoid two user-space copies... */
4106
4107 if ( ( (NULL != connection->method) &&
4108 (MHD_str_equal_caseless_ (connection->method,
4110 (MHD_HTTP_OK > status_code) ||
4111 (MHD_HTTP_NO_CONTENT == status_code) ||
4112 (MHD_HTTP_NOT_MODIFIED == status_code) )
4113 {
4114 /* if this is a "HEAD" request, or a status code for
4115 which a body is not allowed, pretend that we
4116 have already sent the full message body. */
4117 connection->response_write_position = response->total_size;
4118 }
4119 if (MHD_CONNECTION_HEADERS_PROCESSED == connection->state)
4120 {
4121 /* response was queued "early", refuse to read body / footers or
4122 further requests! */
4123 connection->read_closed = true;
4125 connection->remaining_upload_size = 0;
4126 }
4127 if (! connection->in_idle)
4128 (void) MHD_connection_handle_idle (connection);
4129 MHD_update_last_activity_ (connection);
4130 return MHD_YES;
4131}
4132
4133
4134/* end of connection.c */
static ssize_t recv_param_adapter(struct MHD_Connection *connection, void *other, size_t i)
Definition: connection.c:180
static enum MHD_Result build_header_response(struct MHD_Connection *connection)
Definition: connection.c:1250
static void connection_close_error(struct MHD_Connection *connection, const char *emsg)
Definition: connection.c:804
static enum MHD_Result process_header_line(struct MHD_Connection *connection, char *line)
Definition: connection.c:2523
#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:2818
void MHD_connection_handle_write(struct MHD_Connection *connection)
Definition: connection.c:2936
#define INTERNAL_ERROR
Definition: connection.c:114
static void MHD_connection_update_event_loop_info(struct MHD_Connection *connection)
Definition: connection.c:1709
static enum MHD_Result try_ready_normal_body(struct MHD_Connection *connection)
Definition: connection.c:844
static void call_connection_handler(struct MHD_Connection *connection)
Definition: connection.c:2211
static void process_request_body(struct MHD_Connection *connection)
Definition: connection.c:2247
#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:1071
static enum MHD_Result parse_cookie_header(struct MHD_Connection *connection)
Definition: connection.c:1973
#define REQUEST_MALFORMED
Definition: connection.c:101
void MHD_set_http_callbacks_(struct MHD_Connection *connection)
Definition: connection.c:3892
#define REQUEST_LACKS_HOST
Definition: connection.c:87
static bool try_grow_read_buffer(struct MHD_Connection *connection, bool required)
Definition: connection.c:1184
static char * get_next_header_line(struct MHD_Connection *connection, size_t *line_len)
Definition: connection.c:1878
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:1625
enum MHD_Result MHD_connection_handle_idle(struct MHD_Connection *connection)
Definition: connection.c:3348
static void cleanup_connection(struct MHD_Connection *connection)
Definition: connection.c:3268
static enum MHD_Result try_ready_chunked_body(struct MHD_Connection *connection)
Definition: connection.c:940
static enum MHD_Result process_broken_line(struct MHD_Connection *connection, char *line, enum MHD_ValueKind kind)
Definition: connection.c:2583
static void parse_connection_headers(struct MHD_Connection *connection)
Definition: connection.c:2670
void MHD_update_last_activity_(struct MHD_Connection *connection)
Definition: connection.c:2779
static enum MHD_Result parse_initial_message_line(struct MHD_Connection *connection, char *line, size_t line_len)
Definition: connection.c:2099
static void get_date_string(char *date, size_t date_len)
Definition: connection.c:1121
void MHD_connection_close_(struct MHD_Connection *connection, enum MHD_RequestTerminationCode termination_code)
Definition: connection.c:695
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:1938
void MHD_connection_mark_closed_(struct MHD_Connection *connection)
Definition: connection.c:657
#define CONNECTION_CLOSE_ERROR(c, emsg)
Definition: connection.c:827
static enum MHD_Result check_write_done(struct MHD_Connection *connection, enum MHD_CONNECTION_STATE next_state)
Definition: connection.c:2492
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.
#define MHD_connection_finish_forward_(conn)
Definition: connection.h:163
#define MHD_ERR_TLS_
Definition: connection.h:77
#define MHD_ERR_OPNOTSUPP_
Definition: connection.h:67
#define MHD_ERR_PIPE_
Definition: connection.h:72
bool MHD_tls_connection_shutdown(struct MHD_Connection *connection)
bool MHD_run_tls_handshake_(struct MHD_Connection *connection)
Methods for managing connections.
#define MHD_HTTP_HEADER_CONTENT_LENGTH
Definition: microhttpd.h:572
#define MHD_HTTP_HEADER_CONNECTION
Definition: microhttpd.h:566
#define MHD_HTTP_HEADER_DATE
Definition: microhttpd.h:580
#define MHD_HTTP_HEADER_TRANSFER_ENCODING
Definition: microhttpd.h:628
#define MHD_HTTP_HEADER_COOKIE
Definition: microhttpd.h:706
#define MHD_HTTP_HEADER_EXPECT
Definition: microhttpd.h:584
#define MHD_HTTP_HEADER_HOST
Definition: microhttpd.h:590
#define MHD_HTTP_INTERNAL_SERVER_ERROR
Definition: microhttpd.h:443
#define MHD_HTTP_OK
Definition: microhttpd.h:341
#define MHD_HTTP_URI_TOO_LONG
Definition: microhttpd.h:410
#define MHD_HTTP_REQUEST_HEADER_FIELDS_TOO_LARGE
Definition: microhttpd.h:437
#define MHD_HTTP_PROCESSING
Definition: microhttpd.h:336
#define MHD_HTTP_SWITCHING_PROTOCOLS
Definition: microhttpd.h:334
#define MHD_HTTP_NOT_MODIFIED
Definition: microhttpd.h:371
#define MHD_HTTP_NO_CONTENT
Definition: microhttpd.h:349
#define MHD_HTTP_BAD_REQUEST
Definition: microhttpd.h:382
#define MHD_HTTP_METHOD_HEAD
Definition: microhttpd.h:920
#define MHD_HTTP_METHOD_CONNECT
Definition: microhttpd.h:914
enum MHD_Result(* MHD_KeyValueIterator)(void *cls, enum MHD_ValueKind kind, const char *key, const char *value)
Definition: microhttpd.h:2298
_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:2323
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:2017
_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:1851
@ MHD_CONNECTION_INFO_CONNECTION_TIMEOUT
Definition: microhttpd.h:2089
@ MHD_CONNECTION_INFO_SOCKET_CONTEXT
Definition: microhttpd.h:2077
@ MHD_CONNECTION_INFO_GNUTLS_SESSION
Definition: microhttpd.h:2045
@ MHD_CONNECTION_INFO_REQUEST_HEADER_SIZE
Definition: microhttpd.h:2095
@ MHD_CONNECTION_INFO_CIPHER_ALGO
Definition: microhttpd.h:2023
@ MHD_CONNECTION_INFO_CONNECTION_SUSPENDED
Definition: microhttpd.h:2083
@ MHD_CONNECTION_INFO_CLIENT_ADDRESS
Definition: microhttpd.h:2039
@ MHD_CONNECTION_INFO_DAEMON
Definition: microhttpd.h:2059
@ MHD_CONNECTION_INFO_CONNECTION_FD
Definition: microhttpd.h:2067
@ MHD_CONNECTION_INFO_PROTOCOL
Definition: microhttpd.h:2030
@ MHD_REQUEST_TERMINATED_TIMEOUT_REACHED
Definition: microhttpd.h:1873
@ MHD_REQUEST_TERMINATED_COMPLETED_OK
Definition: microhttpd.h:1857
@ MHD_REQUEST_TERMINATED_WITH_ERROR
Definition: microhttpd.h:1865
@ MHD_REQUEST_TERMINATED_READ_ERROR
Definition: microhttpd.h:1890
@ MHD_REQUEST_TERMINATED_CLIENT_ABORT
Definition: microhttpd.h:1898
_MHD_EXTERN struct MHD_Response * MHD_create_response_from_buffer(size_t size, void *buffer, enum MHD_ResponseMemoryMode mode)
Definition: response.c:810
_MHD_EXTERN enum MHD_Result MHD_queue_response(struct MHD_Connection *connection, unsigned int status_code, struct MHD_Response *response)
Definition: connection.c:4035
_MHD_EXTERN void MHD_destroy_response(struct MHD_Response *response)
Definition: response.c:1397
_MHD_EXTERN const char * MHD_get_response_header(struct MHD_Response *response, const char *key)
Definition: response.c:285
@ MHD_RESPMEM_PERSISTENT
Definition: microhttpd.h:3144
_MHD_EXTERN const union MHD_ConnectionInfo * MHD_get_connection_info(struct MHD_Connection *connection, enum MHD_ConnectionInfoType info_type,...)
Definition: connection.c:3909
#define MHD_ICY_FLAG
Definition: microhttpd.h:534
_MHD_EXTERN enum MHD_Result MHD_set_connection_option(struct MHD_Connection *connection, enum MHD_CONNECTION_OPTION option,...)
Definition: connection.c:3969
#define MHD_HTTP_VERSION_1_0
Definition: microhttpd.h:899
#define MHD_HTTP_VERSION_1_1
Definition: microhttpd.h:900
bool MHD_parse_arguments_(struct MHD_Request *request, enum MHD_ValueKind kind, char *args, MHD_ArgumentIterator_ cb, unsigned int *num_headers)
Definition: internal.c:190
#define MHD_ERR_INVAL_
Definition: internal.h:1889
#define MHD_ERR_CONNRESET_
Definition: internal.h:1868
#define XDLL_insert(head, tail, element)
Definition: internal.h:1786
#define MHD_ERR_NOMEM_
Definition: internal.h:1879
MHD_PanicCallback mhd_panic
Definition: panic.c:31
@ MHD_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_BADF_
Definition: internal.h:1884
#define MHD_ERR_NOTCONN_
Definition: internal.h:1874
void * MHD_pool_reallocate(struct MemoryPool *pool, void *old, size_t old_size, size_t new_size)
Definition: memorypool.c:248
void MHD_pool_destroy(struct MemoryPool *pool)
Definition: memorypool.c:157
size_t MHD_pool_get_free(struct MemoryPool *pool)
Definition: memorypool.c:185
void * MHD_pool_reset(struct MemoryPool *pool, void *keep, size_t copy_bytes, size_t new_size)
Definition: memorypool.c:314
void * MHD_pool_allocate(struct MemoryPool *pool, size_t size, int from_end)
Definition: memorypool.c:203
#define mhd_assert(CHK)
Definition: mhd_assert.h:39
#define 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_SCKT_ERR_IS_LOW_RESOURCES_(err)
Definition: mhd_sockets.h:656
#define MHD_socket_last_strerr_()
Definition: mhd_sockets.h:549
#define MHD_SCKT_EOPNOTSUPP_
Definition: mhd_sockets.h:484
#define MHD_SCKT_EBADF_
Definition: mhd_sockets.h:454
#define MHD_socket_get_error_()
Definition: mhd_sockets.h:523
#define MHD_SCKT_ERR_IS_REMOTE_DISCNN_(err)
Definition: mhd_sockets.h:688
#define MHD_SCKT_EINVAL_
Definition: mhd_sockets.h:464
#define MHD_SCKT_ERR_IS_EINTR_(err)
Definition: mhd_sockets.h:634
#define MHD_SCKT_SEND_MAX_SIZE_
Definition: mhd_sockets.h:222
#define MHD_SCKT_ENOTCONN_
Definition: mhd_sockets.h:429
#define MHD_recv_(s, b, l)
Definition: mhd_sockets.h:273
int MHD_str_equal_caseless_(const char *str1, const char *str2)
Definition: mhd_str.c:346
size_t MHD_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_hdr_and_body_(struct MHD_Connection *connection, const char *header, size_t header_size, bool never_push_hdr, const char *body, size_t body_size, bool complete_response)
Definition: mhd_send.c:892
ssize_t MHD_send_iovec_(struct MHD_Connection *connection, struct MHD_iovec_track_ *const r_iov, bool push_data)
Definition: mhd_send.c:1599
ssize_t MHD_send_data_(struct MHD_Connection *connection, const char *buffer, size_t buffer_size, bool push_data)
Definition: mhd_send.c:749
Declarations of send() wrappers.
internal shared structures
MHD_CONNECTION_STATE
Definition: internal.h:538
@ MHD_CONNECTION_BODY_RECEIVED
Definition: internal.h:578
@ MHD_CONNECTION_HEADER_PART_RECEIVED
Definition: internal.h:553
@ MHD_CONNECTION_HEADERS_SENDING
Definition: internal.h:596
@ MHD_CONNECTION_FOOTERS_SENDING
Definition: internal.h:632
@ MHD_CONNECTION_FOOTERS_RECEIVED
Definition: internal.h:590
@ MHD_CONNECTION_HEADERS_SENT
Definition: internal.h:601
@ MHD_CONNECTION_HEADERS_PROCESSED
Definition: internal.h:563
@ MHD_CONNECTION_INIT
Definition: internal.h:543
@ MHD_CONNECTION_CLOSED
Definition: internal.h:642
@ MHD_CONNECTION_NORMAL_BODY_UNREADY
Definition: internal.h:612
@ MHD_CONNECTION_HEADERS_RECEIVED
Definition: internal.h:558
@ MHD_CONNECTION_NORMAL_BODY_READY
Definition: internal.h:606
@ MHD_CONNECTION_CHUNKED_BODY_READY
Definition: internal.h:617
@ MHD_CONNECTION_FOOTER_PART_RECEIVED
Definition: internal.h:584
@ MHD_CONNECTION_CONTINUE_SENT
Definition: internal.h:573
@ MHD_CONNECTION_FOOTERS_SENT
Definition: internal.h:637
@ MHD_CONNECTION_CHUNKED_BODY_UNREADY
Definition: internal.h:622
@ MHD_CONNECTION_BODY_SENT
Definition: internal.h:627
@ MHD_CONNECTION_CONTINUE_SENDING
Definition: internal.h:568
@ MHD_CONNECTION_URL_RECEIVED
Definition: internal.h:548
#define MHD_check_response_header_s_token_ci(r, k, tkn)
Definition: internal.h:2180
@ MHD_TLS_CONN_NO_TLS
Definition: internal.h:660
@ MHD_TLS_CONN_INIT
Definition: internal.h:661
@ MHD_TLS_CONN_CONNECTED
Definition: internal.h:663
@ MHD_TLS_CONN_HANDSHAKING
Definition: internal.h:662
@ MHD_EVENT_LOOP_INFO_READ
Definition: internal.h:237
@ MHD_EVENT_LOOP_INFO_WRITE
Definition: internal.h:242
@ MHD_EVENT_LOOP_INFO_CLEANUP
Definition: internal.h:252
@ MHD_EVENT_LOOP_INFO_BLOCK
Definition: internal.h:247
struct MHD_IoVec MHD_iovec_
Definition: internal.h:374
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
#define MHD_SEND_SPIPE_SUPPRESS_NEEDED
Definition: mhd_sockets.h:929
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:1443
#define MHD_SIZE_UNKNOWN
Definition: microhttpd.h:165
MHD_Result
Definition: microhttpd.h:139
@ MHD_YES
Definition: microhttpd.h:148
@ MHD_NO
Definition: microhttpd.h:143
#define MHD_CONTENT_READER_END_OF_STREAM
Definition: microhttpd.h:172
#define MHD_UNSIGNED_LONG_LONG
Definition: microhttpd.h:296
#define MHD_UNSIGNED_LONG_LONG_PRINTF
Definition: microhttpd.h:310
void * data
Definition: microhttpd.h:3125
#define MHD_INVALID_SOCKET
Definition: microhttpd.h:194
_MHD_EXTERN const char * MHD_get_reason_phrase_for(unsigned int code)
#define MHD_CONTENT_READER_END_WITH_ERROR
Definition: microhttpd.h:173
MHD_ValueKind
Definition: microhttpd.h:1800
@ MHD_FOOTER_KIND
Definition: microhttpd.h:1841
@ MHD_COOKIE_KIND
Definition: microhttpd.h:1821
@ MHD_HEADER_KIND
Definition: microhttpd.h:1815
@ MHD_GET_ARGUMENT_KIND
Definition: microhttpd.h:1836
@ MHD_USE_EPOLL
Definition: microhttpd.h:1193
@ MHD_USE_THREAD_PER_CONNECTION
Definition: microhttpd.h:1087
@ MHD_USE_TURBO
Definition: microhttpd.h:1264
@ MHD_USE_SUPPRESS_DATE_NO_CLOCK
Definition: microhttpd.h:1166
@ MHD_USE_TLS
Definition: microhttpd.h:1072
@ MHD_ALLOW_UPGRADE
Definition: microhttpd.h:1302
@ MHD_USE_ERROR_LOG
Definition: microhttpd.h:1061
@ MHD_USE_INTERNAL_POLLING_THREAD
Definition: microhttpd.h:1098
@ MHD_RF_HTTP_VERSION_1_0_RESPONSE
Definition: microhttpd.h:3046
@ MHD_RF_HTTP_VERSION_1_0_ONLY
Definition: microhttpd.h:3039
MHD_CONNECTION_OPTION
Definition: microhttpd.h:3895
@ MHD_CONNECTION_OPTION_TIMEOUT
Definition: microhttpd.h:3904
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:910
size_t write_buffer_send_offset
Definition: internal.h:915
enum MHD_ConnectionEventLoopInfo event_loop_info
Definition: internal.h:1069
size_t write_buffer_append_offset
Definition: internal.h:921
char * last
Definition: internal.h:868
char * write_buffer
Definition: internal.h:860
uint64_t remaining_upload_size
Definition: internal.h:933
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:877
size_t header_size
Definition: internal.h:927
struct MHD_Response * response
Definition: internal.h:796
const char * url
Definition: internal.h:834
char * version
Definition: internal.h:840
enum MHD_ConnKeepAlive keepalive
Definition: internal.h:847
time_t connection_timeout
Definition: internal.h:745
struct MHD_HTTP_Header * headers_received
Definition: internal.h:786
size_t continue_message_write_offset
Definition: internal.h:963
uint64_t response_write_position
Definition: internal.h:940
struct sockaddr_storage addr
Definition: internal.h:728
struct MHD_HTTP_Header * headers_received_tail
Definition: internal.h:791
char * method
Definition: internal.h:828
uint64_t current_chunk_offset
Definition: internal.h:1098
struct MemoryPool * pool
Definition: internal.h:685
size_t read_buffer_offset
Definition: internal.h:905
uint64_t current_chunk_size
Definition: internal.h:1092
int suspended_dummy
Definition: internal.h:1152
bool client_aware
Definition: internal.h:992
struct MHD_iovec_track_ resp_iov
Definition: internal.h:948
unsigned int responseCode
Definition: internal.h:1075
MHD_thread_handle_ID_ pid
Definition: internal.h:723
bool have_chunked_upload
Definition: internal.h:1084
bool read_closed
Definition: internal.h:792
time_t last_activity
Definition: internal.h:739
void * client_context
Definition: internal.h:814
enum MHD_CONNECTION_STATE state
Definition: internal.h:1064
char * read_buffer
Definition: internal.h:854
struct MHD_Daemon * daemon
Definition: internal.h:675
unsigned int connection_timeout_dummy
Definition: internal.h:985
bool sk_spipe_suppress
Definition: internal.h:1015
size_t read_buffer_size
Definition: internal.h:899
size_t pool_size
Definition: internal.h:1662
MHD_AccessHandlerCallback default_handler
Definition: internal.h:1398
LogCallback uri_log_callback
Definition: internal.h:1588
void * unescape_callback_cls
Definition: internal.h:1603
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:1563
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:1411
bool sigpipe_blocked
Definition: internal.h:1794
UnescapeCallback unescape_callback
Definition: internal.h:1598
void * notify_completed_cls
Definition: internal.h:1568
struct MHD_Connection * cleanup_tail
Definition: internal.h:1182
MHD_thread_handle_ID_ pid
Definition: internal.h:1249
struct MHD_Connection * manual_timeout_head
Definition: internal.h:1143
void * default_handler_cls
Definition: internal.h:1403
struct MHD_Connection * suspended_connections_tail
Definition: internal.h:1172
time_t connection_timeout
Definition: internal.h:1778
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:1667
void * uri_log_callback_cls
Definition: internal.h:1593
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:1789
size_t value_size
Definition: internal.h:338
char * header
Definition: internal.h:347
enum MHD_ValueKind kind
Definition: internal.h:358
size_t header_size
Definition: internal.h:328
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
MHD_iovec_ * data_iov
Definition: internal.h:513
enum MHD_HTTP_StatusCode status_code
Definition: internal.h:1669
uint64_t data_start
Definition: internal.h:1648
MHD_ContentReaderCallback crc
Definition: internal.h:1600
bool is_pipe
Definition: internal.h:508
unsigned int data_iovcnt
Definition: internal.h:518
size_t data_size
Definition: internal.h:1659
enum MHD_ResponseFlags flags
Definition: internal.h:503
char * data
Definition: internal.h:1588
MHD_mutex_ mutex
Definition: internal.h:1637
uint64_t total_size
Definition: internal.h:1642
MHD_iovec_ * iov
Definition: internal.h:387