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