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