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