GNU libmicrohttpd  0.9.72
connection_call_handlers.c
Go to the documentation of this file.
1 /*
2  This file is part of libmicrohttpd
3  Copyright (C) 2007-2018 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 */
24 #include "internal.h"
27 #include "connection_close.h"
28 
29 
30 #ifdef MHD_LINUX_SOLARIS_SENDFILE
31 #include <sys/sendfile.h>
32 #endif /* MHD_LINUX_SOLARIS_SENDFILE */
33 #if defined(HAVE_FREEBSD_SENDFILE) || defined(HAVE_DARWIN_SENDFILE)
34 #include <sys/types.h>
35 #include <sys/socket.h>
36 #include <sys/uio.h>
37 #endif /* HAVE_FREEBSD_SENDFILE || HAVE_DARWIN_SENDFILE */
38 
39 
43 #define MHD_SENFILE_CHUNK_ (0x20000)
44 
48 #define MHD_SENFILE_CHUNK_THR_P_C_ (0x200000)
49 
50 
58 #ifdef HAVE_MESSAGES
59 #define REQUEST_TOO_BIG \
60  "<html><head><title>Request too big</title></head><body>Your HTTP header was too big for the memory constraints of this webserver.</body></html>"
61 #else
62 #define REQUEST_TOO_BIG ""
63 #endif
64 
72 #ifdef HAVE_MESSAGES
73 #define REQUEST_LACKS_HOST \
74  "<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>"
75 #else
76 #define REQUEST_LACKS_HOST ""
77 #endif
78 
86 #ifdef HAVE_MESSAGES
87 #define REQUEST_MALFORMED \
88  "<html><head><title>Request malformed</title></head><body>Your HTTP request was syntactically incorrect.</body></html>"
89 #else
90 #define REQUEST_MALFORMED ""
91 #endif
92 
99 #ifdef HAVE_MESSAGES
100 #define INTERNAL_ERROR \
101  "<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>"
102 #else
103 #define INTERNAL_ERROR ""
104 #endif
105 
106 
107 #ifdef HAVE_FREEBSD_SENDFILE
108 #ifdef SF_FLAGS
112 static int freebsd_sendfile_flags_;
113 
117 static int freebsd_sendfile_flags_thd_p_c_;
118 #endif /* SF_FLAGS */
119 
120 
126 void
127 MHD_conn_init_static_ (void)
128 {
129 /* FreeBSD 11 and later allow to specify read-ahead size
130  * and handles SF_NODISKIO differently.
131  * SF_FLAGS defined only on FreeBSD 11 and later. */
132 #ifdef SF_FLAGS
133  long sys_page_size = sysconf (_SC_PAGESIZE);
134  if (0 > sys_page_size)
135  { /* Failed to get page size. */
136  freebsd_sendfile_flags_ = SF_NODISKIO;
137  freebsd_sendfile_flags_thd_p_c_ = SF_NODISKIO;
138  }
139  else
140  {
141  freebsd_sendfile_flags_ =
142  SF_FLAGS ((uint16_t) (MHD_SENFILE_CHUNK_ / sys_page_size), SF_NODISKIO);
143  freebsd_sendfile_flags_thd_p_c_ =
144  SF_FLAGS ((uint16_t) (MHD_SENFILE_CHUNK_THR_P_C_ / sys_page_size),
145  SF_NODISKIO);
146  }
147 #endif /* SF_FLAGS */
148 }
149 
150 
151 #endif /* HAVE_FREEBSD_SENDFILE */
152 
153 
157 #define HTTP_100_CONTINUE "HTTP/1.1 100 Continue\r\n\r\n"
158 
159 
168 static void
170  enum MHD_StatusCode sc,
171  const char *emsg)
172 {
173 #ifdef HAVE_MESSAGES
174  if (NULL != emsg)
175  MHD_DLOG (connection->daemon,
176  sc,
177  emsg);
178 #else /* ! HAVE_MESSAGES */
179  (void) emsg; /* Mute compiler warning. */
180  (void) sc;
181 #endif /* ! HAVE_MESSAGES */
182  MHD_connection_close_ (connection,
184 }
185 
186 
191 #ifdef HAVE_MESSAGES
192 #define CONNECTION_CLOSE_ERROR(c, sc, emsg) connection_close_error (c, sc, emsg)
193 #else
194 #define CONNECTION_CLOSE_ERROR(c, sc, emsg) connection_close_error (c, sc, NULL)
195 #endif
196 
197 
208 static bool
210 {
211  struct MHD_Daemon *daemon = request->daemon;
212  void *buf;
213  size_t new_size;
214 
215  if (0 == request->read_buffer_size)
216  new_size = daemon->connection_memory_limit_b / 2;
217  else
218  new_size = request->read_buffer_size
220  buf = MHD_pool_reallocate (request->connection->pool,
221  request->read_buffer,
222  request->read_buffer_size,
223  new_size);
224  if (NULL == buf)
225  return false;
226  /* we can actually grow the buffer, do it! */
227  request->read_buffer = buf;
228  request->read_buffer_size = new_size;
229  return true;
230 }
231 
232 
239 static void
241 {
242  struct MHD_Daemon *daemon = request->daemon;
243  struct MHD_Connection *connection = request->connection;
244  ssize_t bytes_read;
245 
246  if ( (MHD_REQUEST_CLOSED == request->state) ||
247  (connection->suspended) )
248  return;
249 #ifdef HTTPS_SUPPORT
250  {
251  struct MHD_TLS_Plugin *tls;
252 
253  if ( (NULL != (tls = daemon->tls_api)) &&
254  (! tls->handshake (tls->cls,
255  connection->tls_cs)) )
256  return;
257  }
258 #endif /* HTTPS_SUPPORT */
259 
260  /* make sure "read" has a reasonable number of bytes
261  in buffer to use per system call (if possible) */
262  if (request->read_buffer_offset
264  request->read_buffer_size)
265  try_grow_read_buffer (request);
266 
267  if (request->read_buffer_size == request->read_buffer_offset)
268  return; /* No space for receiving data. */
269  bytes_read = connection->recv_cls (connection,
270  &request->read_buffer
271  [request->read_buffer_offset],
272  request->read_buffer_size
273  - request->read_buffer_offset);
274  if (bytes_read < 0)
275  {
276  if (MHD_ERR_AGAIN_ == bytes_read)
277  return; /* No new data to process. */
278  if (MHD_ERR_CONNRESET_ == bytes_read)
279  {
280  CONNECTION_CLOSE_ERROR (connection,
281  (MHD_REQUEST_INIT == request->state)
282  ? MHD_SC_CONNECTION_CLOSED
283  : MHD_SC_CONNECTION_RESET_CLOSED,
284  (MHD_REQUEST_INIT == request->state)
285  ? NULL
286  : _ (
287  "Socket disconnected while reading request.\n"));
288  return;
289  }
290  CONNECTION_CLOSE_ERROR (connection,
291  (MHD_REQUEST_INIT == request->state)
292  ? MHD_SC_CONNECTION_CLOSED
293  : MHD_SC_CONNECTION_READ_FAIL_CLOSED,
294  (MHD_REQUEST_INIT == request->state)
295  ? NULL
296  : _ (
297  "Connection socket is closed due to error when reading request.\n"));
298  return;
299  }
300 
301  if (0 == bytes_read)
302  { /* Remote side closed connection. */
303  connection->read_closed = true;
304  MHD_connection_close_ (connection,
306  return;
307  }
308  request->read_buffer_offset += bytes_read;
310 #if DEBUG_STATES
311  MHD_DLOG (daemon,
312  MHD_SC_STATE_MACHINE_STATUS_REPORT,
313  _ ("In function %s handling connection at state: %s\n"),
314  __FUNCTION__,
315  MHD_state_to_string (request->state));
316 #endif
317  switch (request->state)
318  {
319  case MHD_REQUEST_INIT:
328  /* nothing to do but default action */
329  if (connection->read_closed)
330  {
331  MHD_connection_close_ (connection,
333  }
334  return;
335  case MHD_REQUEST_CLOSED:
336  return;
337 #ifdef UPGRADE_SUPPORT
338  case MHD_REQUEST_UPGRADE:
339  mhd_assert (0);
340  return;
341 #endif /* UPGRADE_SUPPORT */
342  default:
343  /* shrink read buffer to how much is actually used */
344  MHD_pool_reallocate (connection->pool,
345  request->read_buffer,
346  request->read_buffer_size + 1,
347  request->read_buffer_offset);
348  break;
349  }
350  return;
351 }
352 
353 
354 #if defined(_MHD_HAVE_SENDFILE)
361 static ssize_t
362 sendfile_adapter (struct MHD_Connection *connection)
363 {
364  struct MHD_Daemon *daemon = connection->daemon;
365  struct MHD_Request *request = &connection->request;
366  struct MHD_Response *response = request->response;
367  ssize_t ret;
368  const int file_fd = response->fd;
369  uint64_t left;
370  uint64_t offsetu64;
371 #ifndef HAVE_SENDFILE64
372  const uint64_t max_off_t = (uint64_t) OFF_T_MAX;
373 #else /* HAVE_SENDFILE64 */
374  const uint64_t max_off_t = (uint64_t) OFF64_T_MAX;
375 #endif /* HAVE_SENDFILE64 */
376 #ifdef MHD_LINUX_SOLARIS_SENDFILE
377 #ifndef HAVE_SENDFILE64
378  off_t offset;
379 #else /* HAVE_SENDFILE64 */
380  off64_t offset;
381 #endif /* HAVE_SENDFILE64 */
382 #endif /* MHD_LINUX_SOLARIS_SENDFILE */
383 #ifdef HAVE_FREEBSD_SENDFILE
384  off_t sent_bytes;
385  int flags = 0;
386 #endif
387 #ifdef HAVE_DARWIN_SENDFILE
388  off_t len;
389 #endif /* HAVE_DARWIN_SENDFILE */
390  const bool used_thr_p_c = (MHD_TM_THREAD_PER_CONNECTION ==
391  daemon->threading_mode);
392  const size_t chunk_size = used_thr_p_c ? MHD_SENFILE_CHUNK_THR_P_C_ :
394  size_t send_size = 0;
395 
396  mhd_assert (MHD_resp_sender_sendfile == request->resp_sender);
397  offsetu64 = request->response_write_position + response->fd_off;
398  left = response->total_size - request->response_write_position;
399  /* Do not allow system to stick sending on single fast connection:
400  * use 128KiB chunks (2MiB for thread-per-connection). */
401  send_size = (left > chunk_size) ? chunk_size : (size_t) left;
402  if (max_off_t < offsetu64)
403  { /* Retry to send with standard 'send()'. */
404  request->resp_sender = MHD_resp_sender_std;
405  return MHD_ERR_AGAIN_;
406  }
407 #ifdef MHD_LINUX_SOLARIS_SENDFILE
408 #ifndef HAVE_SENDFILE64
409  offset = (off_t) offsetu64;
410  ret = sendfile (connection->socket_fd,
411  file_fd,
412  &offset,
413  send_size);
414 #else /* HAVE_SENDFILE64 */
415  offset = (off64_t) offsetu64;
416  ret = sendfile64 (connection->socket_fd,
417  file_fd,
418  &offset,
419  send_size);
420 #endif /* HAVE_SENDFILE64 */
421  if (0 > ret)
422  {
423  const int err = MHD_socket_get_error_ ();
424 
425  if (MHD_SCKT_ERR_IS_EAGAIN_ (err))
426  {
427 #ifdef EPOLL_SUPPORT
428  /* EAGAIN --- no longer write-ready */
429  connection->epoll_state &= ~MHD_EPOLL_STATE_WRITE_READY;
430 #endif /* EPOLL_SUPPORT */
431  return MHD_ERR_AGAIN_;
432  }
433  if (MHD_SCKT_ERR_IS_EINTR_ (err))
434  return MHD_ERR_AGAIN_;
435 #ifdef HAVE_LINUX_SENDFILE
436  if (MHD_SCKT_ERR_IS_ (err,
438  return MHD_ERR_BADF_;
439  /* sendfile() failed with EINVAL if mmap()-like operations are not
440  supported for FD or other 'unusual' errors occurred, so we should try
441  to fall back to 'SEND'; see also this thread for info on
442  odd libc/Linux behavior with sendfile:
443  http://lists.gnu.org/archive/html/libmicrohttpd/2011-02/msg00015.html */request->resp_sender = MHD_resp_sender_std;
444  return MHD_ERR_AGAIN_;
445 #else /* HAVE_SOLARIS_SENDFILE */
446  if ( (EAFNOSUPPORT == err) ||
447  (EINVAL == err) ||
448  (EOPNOTSUPP == err) )
449  { /* Retry with standard file reader. */
450  request->resp_sender = MHD_resp_sender_std;
451  return MHD_ERR_AGAIN_;
452  }
453  if ( (ENOTCONN == err) ||
454  (EPIPE == err) )
455  {
456  return MHD_ERR_CONNRESET_;
457  }
458  return MHD_ERR_BADF_; /* Fail hard */
459 #endif /* HAVE_SOLARIS_SENDFILE */
460  }
461 #ifdef EPOLL_SUPPORT
462  else if (send_size > (size_t) ret)
463  connection->epoll_state &= ~MHD_EPOLL_STATE_WRITE_READY;
464 #endif /* EPOLL_SUPPORT */
465 #elif defined(HAVE_FREEBSD_SENDFILE)
466 #ifdef SF_FLAGS
467  flags = used_thr_p_c ?
468  freebsd_sendfile_flags_thd_p_c_ : freebsd_sendfile_flags_;
469 #endif /* SF_FLAGS */
470  if (0 != sendfile (file_fd,
471  connection->socket_fd,
472  (off_t) offsetu64,
473  send_size,
474  NULL,
475  &sent_bytes,
476  flags))
477  {
478  const int err = MHD_socket_get_error_ ();
479  if (MHD_SCKT_ERR_IS_EAGAIN_ (err) ||
480  MHD_SCKT_ERR_IS_EINTR_ (err) ||
481  (EBUSY == err) )
482  {
483  mhd_assert (SSIZE_MAX >= sent_bytes);
484  if (0 != sent_bytes)
485  return (ssize_t) sent_bytes;
486 
487  return MHD_ERR_AGAIN_;
488  }
489  /* Some unrecoverable error. Possibly file FD is not suitable
490  * for sendfile(). Retry with standard send(). */
491  request->resp_sender = MHD_resp_sender_std;
492  return MHD_ERR_AGAIN_;
493  }
494  mhd_assert (0 < sent_bytes);
495  mhd_assert (SSIZE_MAX >= sent_bytes);
496  ret = (ssize_t) sent_bytes;
497 #elif defined(HAVE_DARWIN_SENDFILE)
498  len = (off_t) send_size; /* chunk always fit */
499  if (0 != sendfile (file_fd,
500  connection->socket_fd,
501  (off_t) offsetu64,
502  &len,
503  NULL,
504  0))
505  {
506  const int err = MHD_socket_get_error_ ();
507  if (MHD_SCKT_ERR_IS_EAGAIN_ (err) ||
509  {
510  mhd_assert (0 <= len);
511  mhd_assert (SSIZE_MAX >= len);
512  mhd_assert (send_size >= (size_t) len);
513  if (0 != len)
514  return (ssize_t) len;
515 
516  return MHD_ERR_AGAIN_;
517  }
518  if ((ENOTCONN == err) ||
519  (EPIPE == err) )
520  return MHD_ERR_CONNRESET_;
521  if ((ENOTSUP == err) ||
522  (EOPNOTSUPP == err) )
523  { /* This file FD is not suitable for sendfile().
524  * Retry with standard send(). */
525  request->resp_sender = MHD_resp_sender_std;
526  return MHD_ERR_AGAIN_;
527  }
528  return MHD_ERR_BADF_; /* Return hard error. */
529  }
530  mhd_assert (0 <= len);
531  mhd_assert (SSIZE_MAX >= len);
532  mhd_assert (send_size >= (size_t) len);
533  ret = (ssize_t) len;
534 #endif /* HAVE_FREEBSD_SENDFILE */
535  return ret;
536 }
537 
538 
539 #endif /* _MHD_HAVE_SENDFILE */
540 
541 
550 static bool
551 check_write_done (struct MHD_Request *request,
552  enum MHD_REQUEST_STATE next_state)
553 {
554  if (request->write_buffer_append_offset !=
555  request->write_buffer_send_offset)
556  return false;
557  request->write_buffer_append_offset = 0;
558  request->write_buffer_send_offset = 0;
559  request->state = next_state;
561  request->write_buffer,
562  request->write_buffer_size,
563  0);
564  request->write_buffer = NULL;
565  request->write_buffer_size = 0;
566  return true;
567 }
568 
569 
580 static bool
582 {
583  struct MHD_Response *response = request->response;
584  struct MHD_Connection *connection = request->connection;
585  ssize_t ret;
586 
587  if (NULL == response->crc)
588  return true;
589  if ( (0 == response->total_size) ||
591  return true; /* 0-byte response is always ready */
592  if ( (response->data_start <=
596  return true; /* response already ready */
597 #if defined(_MHD_HAVE_SENDFILE)
598  if (MHD_resp_sender_sendfile == request->resp_sender)
599  {
600  /* will use sendfile, no need to bother response crc */
601  return true;
602  }
603 #endif /* _MHD_HAVE_SENDFILE */
604 
605  ret = response->crc (response->crc_cls,
607  response->data,
608  (size_t) MHD_MIN ((uint64_t) response->data_buffer_size,
611  if ( (((ssize_t) MHD_CONTENT_READER_END_OF_STREAM) == ret) ||
612  (((ssize_t) MHD_CONTENT_READER_END_WITH_ERROR) == ret) )
613  {
614  /* either error or http 1.0 transfer, close socket! */
617  if ( ((ssize_t) MHD_CONTENT_READER_END_OF_STREAM) == ret)
618  MHD_connection_close_ (connection,
620  else
621  CONNECTION_CLOSE_ERROR (connection,
622  MHD_SC_APPLICATION_DATA_GENERATION_FAILURE_CLOSED,
623  _ (
624  "Closing connection (application reported error generating data).\n"));
625  return false;
626  }
628  response->data_size = ret;
629  if (0 == ret)
630  {
633  return false;
634  }
635  return true;
636 }
637 
638 
647 static bool
649 {
650  struct MHD_Connection *connection = request->connection;
651  struct MHD_Response *response = request->response;
652  struct MHD_Daemon *daemon = request->daemon;
653  ssize_t ret;
654  char *buf;
655  size_t size;
656  char cbuf[10]; /* 10: max strlen of "%x\r\n" */
657  int cblen;
658 
659  if (NULL == response->crc)
660  return true;
661  if (0 == request->write_buffer_size)
662  {
663  size = MHD_MIN (daemon->connection_memory_limit_b,
664  2 * (0xFFFFFF + sizeof(cbuf) + 2));
665  do
666  {
667  size /= 2;
668  if (size < 128)
669  {
670  MHD_mutex_unlock_chk_ (&response->mutex);
671  /* not enough memory */
672  CONNECTION_CLOSE_ERROR (connection,
673  MHD_SC_CONNECTION_POOL_MALLOC_FAILURE,
674  _ ("Closing connection (out of memory).\n"));
675  return false;
676  }
677  buf = MHD_pool_allocate (connection->pool,
678  size,
679  MHD_NO);
680  }
681  while (NULL == buf);
682  request->write_buffer_size = size;
683  request->write_buffer = buf;
684  }
685 
686  if (0 == response->total_size)
687  ret = 0; /* response must be empty, don't bother calling crc */
688  else if ( (response->data_start <=
689  request->response_write_position) &&
690  (response->data_start + response->data_size >
691  request->response_write_position) )
692  {
693  /* difference between response_write_position and data_start is less
694  than data_size which is size_t type, no need to check for overflow */
695  const size_t data_write_offset
696  = (size_t) (request->response_write_position - response->data_start);
697  /* buffer already ready, use what is there for the chunk */
698  ret = response->data_size - data_write_offset;
699  if ( ((size_t) ret) > request->write_buffer_size - sizeof (cbuf) - 2)
700  ret = request->write_buffer_size - sizeof (cbuf) - 2;
701  memcpy (&request->write_buffer[sizeof (cbuf)],
702  &response->data[data_write_offset],
703  ret);
704  }
705  else
706  {
707  /* buffer not in range, try to fill it */
708  ret = response->crc (response->crc_cls,
709  request->response_write_position,
710  &request->write_buffer[sizeof (cbuf)],
711  request->write_buffer_size - sizeof (cbuf) - 2);
712  }
713  if ( ((ssize_t) MHD_CONTENT_READER_END_WITH_ERROR) == ret)
714  {
715  /* error, close socket! */
716  response->total_size = request->response_write_position;
717  MHD_mutex_unlock_chk_ (&response->mutex);
718  CONNECTION_CLOSE_ERROR (connection,
719  MHD_SC_APPLICATION_DATA_GENERATION_FAILURE_CLOSED,
720  _ (
721  "Closing connection (application error generating response).\n"));
722  return false;
723  }
724  if ( (((ssize_t) MHD_CONTENT_READER_END_OF_STREAM) == ret) ||
725  (0 == response->total_size) )
726  {
727  /* end of message, signal other side! */
728  memcpy (request->write_buffer,
729  "0\r\n",
730  3);
731  request->write_buffer_append_offset = 3;
732  request->write_buffer_send_offset = 0;
733  response->total_size = request->response_write_position;
734  return true;
735  }
736  if (0 == ret)
737  {
739  MHD_mutex_unlock_chk_ (&response->mutex);
740  return false;
741  }
742  if (ret > 0xFFFFFF)
743  ret = 0xFFFFFF;
744  cblen = MHD_snprintf_ (cbuf,
745  sizeof (cbuf),
746  "%X\r\n",
747  (unsigned int) ret);
748  mhd_assert (cblen > 0);
749  mhd_assert ((size_t) cblen < sizeof(cbuf));
750  memcpy (&request->write_buffer[sizeof (cbuf) - cblen],
751  cbuf,
752  cblen);
753  memcpy (&request->write_buffer[sizeof (cbuf) + ret],
754  "\r\n",
755  2);
756  request->response_write_position += ret;
757  request->write_buffer_send_offset = sizeof (cbuf) - cblen;
758  request->write_buffer_append_offset = sizeof (cbuf) + ret + 2;
759  return true;
760 }
761 
762 
769 static void
771 {
772  struct MHD_Daemon *daemon = request->daemon;
773  struct MHD_Connection *connection = request->connection;
774  struct MHD_Response *response;
775  ssize_t ret;
776 
777  if (connection->suspended)
778  return;
779 #ifdef HTTPS_SUPPORT
780  {
781  struct MHD_TLS_Plugin *tls;
782 
783  if ( (NULL != (tls = daemon->tls_api)) &&
784  (! tls->handshake (tls->cls,
785  connection->tls_cs)) )
786  return;
787  }
788 #endif /* HTTPS_SUPPORT */
789 
790 #if DEBUG_STATES
791  MHD_DLOG (daemon,
792  MHD_SC_STATE_MACHINE_STATUS_REPORT,
793  _ ("In function %s handling connection at state: %s\n"),
794  __FUNCTION__,
795  MHD_state_to_string (request->state));
796 #endif
797  switch (request->state)
798  {
799  case MHD_REQUEST_INIT:
803  mhd_assert (0);
804  return;
806  return;
808  ret = connection->send_cls (connection,
812  - request->continue_message_write_offset);
813  if (ret < 0)
814  {
815  if (MHD_ERR_AGAIN_ == ret)
816  return;
817 #ifdef HAVE_MESSAGES
818  MHD_DLOG (daemon,
819  MHD_SC_CONNECTION_WRITE_FAIL_CLOSED,
820  _ ("Failed to send data in request for %s.\n"),
821  request->url);
822 #endif
823  CONNECTION_CLOSE_ERROR (connection,
824  MHD_SC_CONNECTION_WRITE_FAIL_CLOSED,
825  NULL);
826  return;
827  }
828  request->continue_message_write_offset += ret;
830  return;
835  mhd_assert (0);
836  return;
838  ret = connection->send_cls (connection,
839  &request->write_buffer
840  [request->write_buffer_send_offset],
842  - request->write_buffer_send_offset);
843  if (ret < 0)
844  {
845  if (MHD_ERR_AGAIN_ == ret)
846  return;
847  CONNECTION_CLOSE_ERROR (connection,
848  MHD_SC_CONNECTION_WRITE_FAIL_CLOSED,
849  _ (
850  "Connection was closed while sending response headers.\n"));
851  return;
852  }
853  request->write_buffer_send_offset += ret;
855  if (MHD_REQUEST_HEADERS_SENDING != request->state)
856  return;
857  check_write_done (request,
859  return;
861  return;
863  response = request->response;
864  if (request->response_write_position <
865  request->response->total_size)
866  {
867  uint64_t data_write_offset;
868 
869  if (NULL != response->crc)
870  MHD_mutex_lock_chk_ (&response->mutex);
871  if (! try_ready_normal_body (request))
872  {
873  /* mutex was already unlocked by try_ready_normal_body */
874  return;
875  }
876 #if defined(_MHD_HAVE_SENDFILE)
877  if (MHD_resp_sender_sendfile == request->resp_sender)
878  {
879  ret = sendfile_adapter (connection);
880  }
881  else
882 #else /* ! _MHD_HAVE_SENDFILE */
883  if (1)
884 #endif /* ! _MHD_HAVE_SENDFILE */
885  {
886  data_write_offset = request->response_write_position
887  - response->data_start;
888  if (data_write_offset > (uint64_t) SIZE_MAX)
889  MHD_PANIC (_ ("Data offset exceeds limit.\n"));
890  ret = connection->send_cls (connection,
891  &response->data
892  [(size_t) data_write_offset],
893  response->data_size
894  - (size_t) data_write_offset);
895 #if DEBUG_SEND_DATA
896  if (ret > 0)
897  fprintf (stderr,
898  _ ("Sent %d-byte DATA response: `%.*s'\n"),
899  (int) ret,
900  (int) ret,
901  &response->data[request->response_write_position
902  - response->data_start]);
903 #endif
904  }
905  if (NULL != response->crc)
906  MHD_mutex_unlock_chk_ (&response->mutex);
907  if (ret < 0)
908  {
909  if (MHD_ERR_AGAIN_ == ret)
910  return;
911 #ifdef HAVE_MESSAGES
912  MHD_DLOG (daemon,
913  MHD_SC_CONNECTION_WRITE_FAIL_CLOSED,
914  _ ("Failed to send data in request for `%s'.\n"),
915  request->url);
916 #endif
917  CONNECTION_CLOSE_ERROR (connection,
918  MHD_SC_CONNECTION_WRITE_FAIL_CLOSED,
919  NULL);
920  return;
921  }
922  request->response_write_position += ret;
924  }
925  if (request->response_write_position ==
926  request->response->total_size)
927  request->state = MHD_REQUEST_FOOTERS_SENT; /* have no footers */
928  return;
930  mhd_assert (0);
931  return;
933  ret = connection->send_cls (connection,
934  &request->write_buffer
935  [request->write_buffer_send_offset],
937  - request->write_buffer_send_offset);
938  if (ret < 0)
939  {
940  if (MHD_ERR_AGAIN_ == ret)
941  return;
942  CONNECTION_CLOSE_ERROR (connection,
943  MHD_SC_CONNECTION_WRITE_FAIL_CLOSED,
944  _ (
945  "Connection was closed while sending response body.\n"));
946  return;
947  }
948  request->write_buffer_send_offset += ret;
950  if (MHD_REQUEST_CHUNKED_BODY_READY != request->state)
951  return;
952  check_write_done (request,
953  (request->response->total_size ==
954  request->response_write_position) ?
957  return;
960  mhd_assert (0);
961  return;
963  ret = connection->send_cls (connection,
964  &request->write_buffer
965  [request->write_buffer_send_offset],
967  - request->write_buffer_send_offset);
968  if (ret < 0)
969  {
970  if (MHD_ERR_AGAIN_ == ret)
971  return;
972  CONNECTION_CLOSE_ERROR (connection,
973  MHD_SC_CONNECTION_WRITE_FAIL_CLOSED,
974  _ (
975  "Connection was closed while sending response body.\n"));
976  return;
977  }
978  request->write_buffer_send_offset += ret;
980  if (MHD_REQUEST_FOOTERS_SENDING != request->state)
981  return;
982  check_write_done (request,
984  return;
986  mhd_assert (0);
987  return;
988  case MHD_REQUEST_CLOSED:
989  return;
990 #ifdef UPGRADE_SUPPORT
991  case MHD_REQUEST_UPGRADE:
992  mhd_assert (0);
993  return;
994 #endif /* UPGRADE_SUPPORT */
995  default:
996  mhd_assert (0);
997  CONNECTION_CLOSE_ERROR (connection,
998  MHD_SC_STATEMACHINE_FAILURE_CONNECTION_CLOSED,
999  _ ("Internal error.\n"));
1000  break;
1001  }
1002 }
1003 
1004 
1018 static bool
1020  const char *header,
1021  const char *token,
1022  size_t token_len)
1023 {
1024  struct MHD_HTTP_Header *pos;
1025 
1026  if ( (NULL == request) || /* FIXME: require non-null? */
1027  (NULL == header) || /* FIXME: require non-null? */
1028  (0 == header[0]) ||
1029  (NULL == token) ||
1030  (0 == token[0]) )
1031  return false;
1032  for (pos = request->headers_received; NULL != pos; pos = pos->next)
1033  {
1034  if ( (0 != (pos->kind & MHD_HEADER_KIND)) &&
1035  ( (header == pos->header) ||
1037  pos->header)) ) &&
1039  token,
1040  token_len)) )
1041  return true;
1042  }
1043  return false;
1044 }
1045 
1046 
1058 #define MHD_lookup_header_s_token_ci(r,h,tkn) \
1059  MHD_lookup_header_token_ci ((r),(h),(tkn),MHD_STATICSTR_LEN_ (tkn))
1060 
1061 
1078 static bool
1080 {
1081  if (MHD_CONN_MUST_CLOSE == request->keepalive)
1082  return false;
1083  if (NULL == request->version_s)
1084  return false;
1085  if ( (NULL != request->response) &&
1086  (request->response->v10_only) )
1087  return false;
1088 
1089  if (MHD_str_equal_caseless_ (request->version_s,
1091  {
1092  if (MHD_lookup_header_s_token_ci (request,
1094  "upgrade"))
1095  return false;
1096  if (MHD_lookup_header_s_token_ci (request,
1098  "close"))
1099  return false;
1100  return true;
1101  }
1102  if (MHD_str_equal_caseless_ (request->version_s,
1104  {
1105  if (MHD_lookup_header_s_token_ci (request,
1107  "Keep-Alive"))
1108  return true;
1109  return false;
1110  }
1111  return false;
1112 }
1113 
1114 
1122 static void
1123 get_date_string (char *date,
1124  size_t date_len)
1125 {
1126  static const char *const days[] = {
1127  "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
1128  };
1129  static const char *const mons[] = {
1130  "Jan", "Feb", "Mar", "Apr", "May", "Jun",
1131  "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
1132  };
1133  struct tm now;
1134  time_t t;
1135 #if ! defined(HAVE_C11_GMTIME_S) && ! defined(HAVE_W32_GMTIME_S) && \
1136  ! defined(HAVE_GMTIME_R)
1137  struct tm*pNow;
1138 #endif
1139 
1140  date[0] = 0;
1141  time (&t);
1142 #if defined(HAVE_C11_GMTIME_S)
1143  if (NULL == gmtime_s (&t,
1144  &now))
1145  return;
1146 #elif defined(HAVE_W32_GMTIME_S)
1147  if (0 != gmtime_s (&now,
1148  &t))
1149  return;
1150 #elif defined(HAVE_GMTIME_R)
1151  if (NULL == gmtime_r (&t,
1152  &now))
1153  return;
1154 #else
1155  pNow = gmtime (&t);
1156  if (NULL == pNow)
1157  return;
1158  now = *pNow;
1159 #endif
1160  MHD_snprintf_ (date,
1161  date_len,
1162  "Date: %3s, %02u %3s %04u %02u:%02u:%02u GMT\r\n",
1163  days[now.tm_wday % 7],
1164  (unsigned int) now.tm_mday,
1165  mons[now.tm_mon % 12],
1166  (unsigned int) (1900 + now.tm_year),
1167  (unsigned int) now.tm_hour,
1168  (unsigned int) now.tm_min,
1169  (unsigned int) now.tm_sec);
1170 }
1171 
1172 
1186 static bool
1188  const char *key,
1189  const char *token,
1190  size_t token_len)
1191 {
1192  struct MHD_HTTP_Header *pos;
1193 
1194  if ( (NULL == key) ||
1195  ('\0' == key[0]) ||
1196  (NULL == token) ||
1197  ('\0' == token[0]) )
1198  return false;
1199 
1200  for (pos = response->first_header;
1201  NULL != pos;
1202  pos = pos->next)
1203  {
1204  if ( (pos->kind == MHD_HEADER_KIND) &&
1206  key) &&
1208  token,
1209  token_len) )
1210  return true;
1211  }
1212  return false;
1213 }
1214 
1215 
1227 #define check_response_header_s_token_ci(r,k,tkn) \
1228  check_response_header_token_ci ((r),(k),(tkn),MHD_STATICSTR_LEN_ (tkn))
1229 
1230 
1240 static bool
1242 {
1243  struct MHD_Connection *connection = request->connection;
1244  struct MHD_Daemon *daemon = request->daemon;
1245  struct MHD_Response *response = request->response;
1246  size_t size;
1247  size_t off;
1248  struct MHD_HTTP_Header *pos;
1249  char code[256];
1250  char date[128];
1251  size_t datelen;
1252  char content_length_buf[128];
1253  size_t content_length_len;
1254  char *data;
1255  enum MHD_ValueKind kind;
1256  bool client_requested_close;
1257  bool response_has_close;
1258  bool response_has_keepalive;
1259  const char *have_encoding;
1260  const char *have_content_length;
1261  bool must_add_close;
1262  bool must_add_chunked_encoding;
1263  bool must_add_keep_alive;
1264  bool must_add_content_length;
1265 
1266  mhd_assert (NULL != request->version_s);
1267  if (0 == request->version_s[0])
1268  {
1269  data = MHD_pool_allocate (connection->pool,
1270  0,
1271  MHD_YES);
1272  request->write_buffer = data;
1273  request->write_buffer_append_offset = 0;
1274  request->write_buffer_send_offset = 0;
1275  request->write_buffer_size = 0;
1276  return true;
1277  }
1278  if (MHD_REQUEST_FOOTERS_RECEIVED == request->state)
1279  {
1280  const char *reason_phrase;
1281  const char *version;
1282 
1283  reason_phrase
1284  = MHD_get_reason_phrase_for (response->status_code);
1285  version
1286  = (response->icy)
1287  ? "ICY"
1289  request->version_s))
1292  MHD_snprintf_ (code,
1293  sizeof (code),
1294  "%s %u %s\r\n",
1295  version,
1296  response->status_code,
1297  reason_phrase);
1298  off = strlen (code);
1299  /* estimate size */
1300  size = off + 2; /* +2 for extra "\r\n" at the end */
1302  if ( (! daemon->suppress_date) &&
1303  (NULL == MHD_response_get_header (response,
1305  get_date_string (date,
1306  sizeof (date));
1307  else
1308  date[0] = '\0';
1309  datelen = strlen (date);
1310  size += datelen;
1311  }
1312  else
1313  {
1314  /* 2 bytes for final CRLF of a Chunked-Body */
1315  size = 2;
1317  off = 0;
1318  datelen = 0;
1319  }
1320 
1321  /* calculate extra headers we need to add, such as 'Connection: close',
1322  first see what was explicitly requested by the application */
1323  must_add_close = false;
1324  must_add_chunked_encoding = false;
1325  must_add_keep_alive = false;
1326  must_add_content_length = false;
1327  response_has_close = false;
1328  switch (request->state)
1329  {
1331  response_has_close
1334  "close");
1335  response_has_keepalive
1338  "Keep-Alive");
1339  client_requested_close
1340  = MHD_lookup_header_s_token_ci (request,
1342  "close");
1343 
1344  if (response->v10_only)
1345  request->keepalive = MHD_CONN_MUST_CLOSE;
1346 #ifdef UPGRADE_SUPPORT
1347  else if (NULL != response->upgrade_handler)
1348  /* If this connection will not be "upgraded", it must be closed. */
1349  request->keepalive = MHD_CONN_MUST_CLOSE;
1350 #endif /* UPGRADE_SUPPORT */
1351 
1352  /* now analyze chunked encoding situation */
1353  request->have_chunked_upload = false;
1354 
1355  if ( (MHD_SIZE_UNKNOWN == response->total_size) &&
1356 #ifdef UPGRADE_SUPPORT
1357  (NULL == response->upgrade_handler) &&
1358 #endif /* UPGRADE_SUPPORT */
1359  (! response_has_close) &&
1360  (! client_requested_close) )
1361  {
1362  /* size is unknown, and close was not explicitly requested;
1363  need to either to HTTP 1.1 chunked encoding or
1364  close the connection */
1365  /* 'close' header doesn't exist yet, see if we need to add one;
1366  if the client asked for a close, no need to start chunk'ing */
1367  if ( (keepalive_possible (request)) &&
1369  request->version_s)) )
1370  {
1371  have_encoding
1372  = MHD_response_get_header (response,
1374  if (NULL == have_encoding)
1375  {
1376  must_add_chunked_encoding = true;
1377  request->have_chunked_upload = true;
1378  }
1379  else if (MHD_str_equal_caseless_ (have_encoding,
1380  "identity"))
1381  {
1382  /* application forced identity encoding, can't do 'chunked' */
1383  must_add_close = true;
1384  }
1385  else
1386  {
1387  request->have_chunked_upload = true;
1388  }
1389  }
1390  else
1391  {
1392  /* Keep alive or chunking not possible
1393  => set close header if not present */
1394  if (! response_has_close)
1395  must_add_close = true;
1396  }
1397  }
1398 
1399  /* check for other reasons to add 'close' header */
1400  if ( ( (client_requested_close) ||
1401  (connection->read_closed) ||
1402  (MHD_CONN_MUST_CLOSE == request->keepalive)) &&
1403  (! response_has_close) &&
1404 #ifdef UPGRADE_SUPPORT
1405  (NULL == response->upgrade_handler) &&
1406 #endif /* UPGRADE_SUPPORT */
1407  (! response->v10_only) )
1408  must_add_close = true;
1409 
1410  /* check if we should add a 'content length' header */
1411  have_content_length
1412  = MHD_response_get_header (response,
1414 
1415  /* MHD_HTTP_NO_CONTENT, MHD_HTTP_NOT_MODIFIED and 1xx-status
1416  codes SHOULD NOT have a Content-Length according to spec;
1417  also chunked encoding / unknown length or CONNECT... */
1418  if ( (MHD_SIZE_UNKNOWN != response->total_size) &&
1419  (MHD_HTTP_NO_CONTENT != response->status_code) &&
1420  (MHD_HTTP_NOT_MODIFIED != response->status_code) &&
1421  (MHD_HTTP_OK <= response->status_code) &&
1422  (NULL == have_content_length) &&
1423  (request->method != MHD_METHOD_CONNECT) )
1424  {
1425  /*
1426  Here we add a content-length if one is missing; however,
1427  for 'connect' methods, the responses MUST NOT include a
1428  content-length header *if* the response code is 2xx (in
1429  which case we expect there to be no body). Still,
1430  as we don't know the response code here in some cases, we
1431  simply only force adding a content-length header if this
1432  is not a 'connect' or if the response is not empty
1433  (which is kind of more sane, because if some crazy
1434  application did return content with a 2xx status code,
1435  then having a content-length might again be a good idea).
1436 
1437  Note that the change from 'SHOULD NOT' to 'MUST NOT' is
1438  a recent development of the HTTP 1.1 specification.
1439  */content_length_len
1440  = MHD_snprintf_ (content_length_buf,
1441  sizeof (content_length_buf),
1444  (MHD_UNSIGNED_LONG_LONG) response->total_size);
1445  must_add_content_length = true;
1446  }
1447 
1448  /* check for adding keep alive */
1449  if ( (! response_has_keepalive) &&
1450  (! response_has_close) &&
1451  (! must_add_close) &&
1452  (MHD_CONN_MUST_CLOSE != request->keepalive) &&
1453 #ifdef UPGRADE_SUPPORT
1454  (NULL == response->upgrade_handler) &&
1455 #endif /* UPGRADE_SUPPORT */
1456  (keepalive_possible (request)) )
1457  must_add_keep_alive = true;
1458  break;
1459  case MHD_REQUEST_BODY_SENT:
1460  response_has_keepalive = false;
1461  break;
1462  default:
1463  mhd_assert (0);
1464  return MHD_NO;
1465  }
1466 
1467  if (MHD_CONN_MUST_CLOSE != request->keepalive)
1468  {
1469  if ( (must_add_close) ||
1470  (response_has_close) )
1471  request->keepalive = MHD_CONN_MUST_CLOSE;
1472  else if ( (must_add_keep_alive) ||
1473  (response_has_keepalive) )
1474  request->keepalive = MHD_CONN_USE_KEEPALIVE;
1475  }
1476 
1477  if (must_add_close)
1478  size += MHD_STATICSTR_LEN_ ("Connection: close\r\n");
1479  if (must_add_keep_alive)
1480  size += MHD_STATICSTR_LEN_ ("Connection: Keep-Alive\r\n");
1481  if (must_add_chunked_encoding)
1482  size += MHD_STATICSTR_LEN_ ("Transfer-Encoding: chunked\r\n");
1483  if (must_add_content_length)
1484  size += content_length_len;
1485  mhd_assert (! (must_add_close && must_add_keep_alive) );
1486  mhd_assert (! (must_add_chunked_encoding && must_add_content_length) );
1487 
1488  for (pos = response->first_header; NULL != pos; pos = pos->next)
1489  {
1490  /* TODO: add proper support for excluding "Keep-Alive" token. */
1491  if ( (pos->kind == kind) &&
1492  (! ( (must_add_close) &&
1493  (response_has_keepalive) &&
1497  "Keep-Alive")) ) ) )
1498  size += strlen (pos->header) + strlen (pos->value) + 4; /* colon, space, linefeeds */
1499  }
1500  /* produce data */
1501  data = MHD_pool_allocate (connection->pool,
1502  size + 1,
1503  MHD_NO);
1504  if (NULL == data)
1505  {
1506 #ifdef HAVE_MESSAGES
1507  MHD_DLOG (daemon,
1508  MHD_SC_CONNECTION_POOL_MALLOC_FAILURE,
1509  "Not enough memory for write!\n");
1510 #endif
1511  return false;
1512  }
1513  if (MHD_REQUEST_FOOTERS_RECEIVED == request->state)
1514  {
1515  memcpy (data,
1516  code,
1517  off);
1518  }
1519  if (must_add_close)
1520  {
1521  /* we must add the 'Connection: close' header */
1522  memcpy (&data[off],
1523  "Connection: close\r\n",
1524  MHD_STATICSTR_LEN_ ("Connection: close\r\n"));
1525  off += MHD_STATICSTR_LEN_ ("Connection: close\r\n");
1526  }
1527  if (must_add_keep_alive)
1528  {
1529  /* we must add the 'Connection: Keep-Alive' header */
1530  memcpy (&data[off],
1531  "Connection: Keep-Alive\r\n",
1532  MHD_STATICSTR_LEN_ ("Connection: Keep-Alive\r\n"));
1533  off += MHD_STATICSTR_LEN_ ("Connection: Keep-Alive\r\n");
1534  }
1535  if (must_add_chunked_encoding)
1536  {
1537  /* we must add the 'Transfer-Encoding: chunked' header */
1538  memcpy (&data[off],
1539  "Transfer-Encoding: chunked\r\n",
1540  MHD_STATICSTR_LEN_ ("Transfer-Encoding: chunked\r\n"));
1541  off += MHD_STATICSTR_LEN_ ("Transfer-Encoding: chunked\r\n");
1542  }
1543  if (must_add_content_length)
1544  {
1545  /* we must add the 'Content-Length' header */
1546  memcpy (&data[off],
1547  content_length_buf,
1548  content_length_len);
1549  off += content_length_len;
1550  }
1551  for (pos = response->first_header; NULL != pos; pos = pos->next)
1552  {
1553  /* TODO: add proper support for excluding "Keep-Alive" token. */
1554  if ( (pos->kind == kind) &&
1555  (! ( (must_add_close) &&
1556  (response_has_keepalive) &&
1560  "Keep-Alive")) ) ) )
1561  off += MHD_snprintf_ (&data[off],
1562  size - off,
1563  "%s: %s\r\n",
1564  pos->header,
1565  pos->value);
1566  }
1567  if (MHD_REQUEST_FOOTERS_RECEIVED == request->state)
1568  {
1569  memcpy (&data[off],
1570  date,
1571  datelen);
1572  off += datelen;
1573  }
1574  memcpy (&data[off],
1575  "\r\n",
1576  2);
1577  off += 2;
1578 
1579  if (off != size)
1581  __FILE__,
1582  __LINE__,
1583  NULL);
1584  request->write_buffer = data;
1585  request->write_buffer_append_offset = size;
1586  request->write_buffer_send_offset = 0;
1587  request->write_buffer_size = size + 1;
1588  return true;
1589 }
1590 
1591 
1602 static void
1604  enum MHD_StatusCode ec,
1605  enum MHD_HTTP_StatusCode status_code,
1606  const char *message)
1607 {
1608  struct MHD_Response *response;
1609 
1610  if (NULL == request->version_s)
1611  {
1612  /* we were unable to process the full header line, so we don't
1613  really know what version the client speaks; assume 1.0 */
1614  request->version_s = MHD_HTTP_VERSION_1_0;
1615  }
1617  request->connection->read_closed = true;
1618 #ifdef HAVE_MESSAGES
1619  MHD_DLOG (request->daemon,
1620  ec,
1621  _ (
1622  "Error processing request (HTTP response code is %u (`%s')). Closing connection.\n"),
1623  status_code,
1624  message);
1625 #endif
1626  if (NULL != request->response)
1627  {
1629  request->response = NULL;
1630  }
1632  strlen (message),
1633  (void *) message,
1635  request->response = response;
1636  /* Do not reuse this connection. */
1637  request->keepalive = MHD_CONN_MUST_CLOSE;
1638  if (! build_header_response (request))
1639  {
1640  /* oops - close! */
1642  ec,
1643  _ (
1644  "Closing connection (failed to create response header).\n"));
1645  }
1646  else
1647  {
1649  }
1650 }
1651 
1652 
1659 static enum MHD_Method
1660 method_string_to_enum (const char *method)
1661 {
1662  static const struct
1663  {
1664  const char *key;
1665  enum MHD_Method value;
1666  } methods[] = {
1667  { "OPTIONS", MHD_METHOD_OPTIONS },
1668  { "GET", MHD_METHOD_GET },
1669  { "HEAD", MHD_METHOD_HEAD },
1670  { "POST", MHD_METHOD_POST },
1671  { "PUT", MHD_METHOD_PUT },
1672  { "DELETE", MHD_METHOD_DELETE },
1673  { "TRACE", MHD_METHOD_TRACE },
1674  { "CONNECT", MHD_METHOD_CONNECT },
1675  { "ACL", MHD_METHOD_ACL },
1676  { "BASELINE_CONTROL", MHD_METHOD_BASELINE_CONTROL },
1677  { "BIND", MHD_METHOD_BIND },
1678  { "CHECKIN", MHD_METHOD_CHECKIN },
1679  { "CHECKOUT", MHD_METHOD_CHECKOUT },
1680  { "COPY", MHD_METHOD_COPY },
1681  { "LABEL", MHD_METHOD_LABEL },
1682  { "LINK", MHD_METHOD_LINK },
1683  { "LOCK", MHD_METHOD_LOCK },
1684  { "MERGE", MHD_METHOD_MERGE },
1685  { "MKACTIVITY", MHD_METHOD_MKACTIVITY },
1686  { "MKCOL", MHD_METHOD_MKCOL },
1687  { "MKREDIRECTREF", MHD_METHOD_MKREDIRECTREF },
1688  { "MKWORKSPACE", MHD_METHOD_MKWORKSPACE },
1689  { "MOVE", MHD_METHOD_MOVE },
1690  { "ORDERPATCH", MHD_METHOD_ORDERPATCH },
1691  { "PRI", MHD_METHOD_PRI },
1692  { "PROPFIND", MHD_METHOD_PROPFIND },
1693  { "PROPPATCH", MHD_METHOD_PROPPATCH },
1694  { "REBIND", MHD_METHOD_REBIND },
1695  { "REPORT", MHD_METHOD_REPORT },
1696  { "SEARCH", MHD_METHOD_SEARCH },
1697  { "UNBIND", MHD_METHOD_UNBIND },
1698  { "UNCHECKOUT", MHD_METHOD_UNCHECKOUT },
1699  { "UNLINK", MHD_METHOD_UNLINK },
1700  { "UNLOCK", MHD_METHOD_UNLOCK },
1701  { "UPDATE", MHD_METHOD_UPDATE },
1702  { "UPDATEDIRECTREF", MHD_METHOD_UPDATEDIRECTREF },
1703  { "VERSION-CONTROL", MHD_METHOD_VERSION_CONTROL },
1704  { NULL, MHD_METHOD_UNKNOWN } /* must be last! */
1705  };
1706  unsigned int i;
1707 
1708  for (i = 0; NULL != methods[i].key; i++)
1709  if (0 ==
1710  MHD_str_equal_caseless_ (method,
1711  methods[i].key))
1712  return methods[i].value;
1713  return MHD_METHOD_UNKNOWN;
1714 }
1715 
1716 
1727 static bool
1729  const char *key,
1730  const char *value,
1731  enum MHD_ValueKind kind)
1732 {
1733  if (MHD_NO ==
1734  MHD_request_set_value (request,
1735  kind,
1736  key,
1737  value))
1738  {
1739 #ifdef HAVE_MESSAGES
1740  MHD_DLOG (request->daemon,
1741  MHD_SC_CONNECTION_POOL_MALLOC_FAILURE,
1742  _ ("Not enough memory in pool to allocate header record!\n"));
1743 #endif
1744  transmit_error_response (request,
1745  MHD_SC_CLIENT_HEADER_TOO_BIG,
1747  REQUEST_TOO_BIG);
1748  return false;
1749  }
1750  return true;
1751 }
1752 
1753 
1762 static bool
1764  char *line,
1765  size_t line_len)
1766 {
1767  struct MHD_Daemon *daemon = request->daemon;
1768  const char *curi;
1769  char *uri;
1770  char *http_version;
1771  char *args;
1772  unsigned int unused_num_headers;
1773  size_t url_end;
1774 
1775  if (NULL == (uri = memchr (line,
1776  ' ',
1777  line_len)))
1778  return false; /* serious error */
1779  uri[0] = '\0';
1780  request->method_s = line;
1781  request->method = method_string_to_enum (line);
1782  uri++;
1783  /* Skip any spaces. Not required by standard but allow
1784  to be more tolerant. */
1785  while ( (' ' == uri[0]) &&
1786  ( (size_t) (uri - line) < line_len) )
1787  uri++;
1788  if ((size_t) (uri - line) == line_len)
1789  {
1790  curi = "";
1791  uri = NULL;
1792  request->version_s = "";
1793  args = NULL;
1794  url_end = line_len - (line - uri); // EH, this is garbage. FIXME!
1795  }
1796  else
1797  {
1798  curi = uri;
1799  /* Search from back to accept malformed URI with space */
1800  http_version = line + line_len - 1;
1801  /* Skip any trailing spaces */
1802  while ( (' ' == http_version[0]) &&
1803  (http_version > uri) )
1804  http_version--;
1805  /* Find first space in reverse direction */
1806  while ( (' ' != http_version[0]) &&
1807  (http_version > uri) )
1808  http_version--;
1809  if (http_version > uri)
1810  {
1811  http_version[0] = '\0';
1812  request->version_s = http_version + 1;
1813  args = memchr (uri,
1814  '?',
1815  http_version - uri);
1816  }
1817  else
1818  {
1819  request->version_s = "";
1820  args = memchr (uri,
1821  '?',
1822  line_len - (uri - line));
1823  }
1824  url_end = http_version - uri;
1825  }
1826  if ( (MHD_PSL_STRICT == daemon->protocol_strict_level) &&
1827  (NULL != memchr (curi,
1828  ' ',
1829  url_end)) )
1830  {
1831  /* space exists in URI and we are supposed to be strict, reject */
1832  return MHD_NO;
1833  }
1834  if (NULL != daemon->early_uri_logger_cb)
1835  {
1836  request->client_context
1837  = daemon->early_uri_logger_cb (daemon->early_uri_logger_cb_cls,
1838  curi,
1839  request);
1840  }
1841  if (NULL != args)
1842  {
1843  args[0] = '\0';
1844  args++;
1845  /* note that this call clobbers 'args' */
1846  MHD_parse_arguments_ (request,
1848  args,
1850  &unused_num_headers);
1851  }
1852  if (NULL != uri)
1853  daemon->unescape_cb (daemon->unescape_cb_cls,
1854  request,
1855  uri);
1856  request->url = curi;
1857  return true;
1858 }
1859 
1860 
1870 static bool
1872  char *line)
1873 {
1874  struct MHD_Connection *connection = request->connection;
1875  char *colon;
1876 
1877  /* line should be normal header line, find colon */
1878  colon = strchr (line,
1879  ':');
1880  if (NULL == colon)
1881  {
1882  /* error in header line, die hard */
1883  CONNECTION_CLOSE_ERROR (connection,
1884  MHD_SC_CONNECTION_PARSE_FAIL_CLOSED,
1885  _ (
1886  "Received malformed line (no colon). Closing connection.\n"));
1887  return false;
1888  }
1889  if (MHD_PSL_PERMISSIVE != request->daemon->protocol_strict_level)
1890  {
1891  /* check for whitespace before colon, which is not allowed
1892  by RFC 7230 section 3.2.4; we count space ' ' and
1893  tab '\t', but not '\r\n' as those would have ended the line. */
1894  const char *white;
1895 
1896  white = strchr (line,
1897  (unsigned char) ' ');
1898  if ( (NULL != white) &&
1899  (white < colon) )
1900  {
1901  CONNECTION_CLOSE_ERROR (connection,
1902  MHD_SC_CONNECTION_PARSE_FAIL_CLOSED,
1903  _ (
1904  "Whitespace before colon forbidden by RFC 7230. Closing connection.\n"));
1905  return false;
1906  }
1907  white = strchr (line,
1908  (unsigned char) '\t');
1909  if ( (NULL != white) &&
1910  (white < colon) )
1911  {
1912  CONNECTION_CLOSE_ERROR (connection,
1913  MHD_SC_CONNECTION_PARSE_FAIL_CLOSED,
1914  _ (
1915  "Tab before colon forbidden by RFC 7230. Closing connection.\n"));
1916  return false;
1917  }
1918  }
1919  /* zero-terminate header */
1920  colon[0] = '\0';
1921  colon++; /* advance to value */
1922  while ( ('\0' != colon[0]) &&
1923  ( (' ' == colon[0]) ||
1924  ('\t' == colon[0]) ) )
1925  colon++;
1926  /* we do the actual adding of the connection
1927  header at the beginning of the while
1928  loop since we need to be able to inspect
1929  the *next* header line (in case it starts
1930  with a space...) */request->last = line;
1931  request->colon = colon;
1932  return true;
1933 }
1934 
1935 
1946 static bool
1948  char *line,
1949  enum MHD_ValueKind kind)
1950 {
1951  struct MHD_Connection *connection = request->connection;
1952  char *last;
1953  char *tmp;
1954  size_t last_len;
1955  size_t tmp_len;
1956 
1957  last = request->last;
1958  if ( (' ' == line[0]) ||
1959  ('\t' == line[0]) )
1960  {
1961  /* value was continued on the next line, see
1962  http://www.jmarshall.com/easy/http/ */
1963  last_len = strlen (last);
1964  /* skip whitespace at start of 2nd line */
1965  tmp = line;
1966  while ( (' ' == tmp[0]) ||
1967  ('\t' == tmp[0]) )
1968  tmp++;
1969  tmp_len = strlen (tmp);
1970  /* FIXME: we might be able to do this better (faster!), as most
1971  likely 'last' and 'line' should already be adjacent in
1972  memory; however, doing this right gets tricky if we have a
1973  value continued over multiple lines (in which case we need to
1974  record how often we have done this so we can check for
1975  adjacency); also, in the case where these are not adjacent
1976  (not sure how it can happen!), we would want to allocate from
1977  the end of the pool, so as to not destroy the read-buffer's
1978  ability to grow nicely. */last = MHD_pool_reallocate (connection->pool,
1979  last,
1980  last_len + 1,
1981  last_len + tmp_len + 1);
1982  if (NULL == last)
1983  {
1985  MHD_SC_CLIENT_HEADER_TOO_BIG,
1987  REQUEST_TOO_BIG);
1988  return MHD_NO;
1989  }
1990  memcpy (&last[last_len],
1991  tmp,
1992  tmp_len + 1);
1993  request->last = last;
1994  return MHD_YES; /* possibly more than 2 lines... */
1995  }
1996  mhd_assert ( (NULL != last) &&
1997  (NULL != request->colon) );
1998  if (! request_add_header (request,
1999  last,
2000  request->colon,
2001  kind))
2002  {
2004  MHD_SC_CLIENT_HEADER_TOO_BIG,
2006  REQUEST_TOO_BIG);
2007  return false;
2008  }
2009  /* we still have the current line to deal with... */
2010  if ('\0' != line[0])
2011  {
2013  line))
2014  {
2016  MHD_SC_CONNECTION_PARSE_FAIL_CLOSED,
2019  return false;
2020  }
2021  }
2022  return true;
2023 }
2024 
2025 
2039 static char *
2041  size_t *line_len)
2042 {
2043  char *rbuf;
2044  size_t pos;
2045 
2046  if (0 == request->read_buffer_offset)
2047  return NULL;
2048  pos = 0;
2049  rbuf = request->read_buffer;
2050  while ( (pos < request->read_buffer_offset - 1) &&
2051  ('\r' != rbuf[pos]) &&
2052  ('\n' != rbuf[pos]) )
2053  pos++;
2054  if ( (pos == request->read_buffer_offset - 1) &&
2055  ('\n' != rbuf[pos]) )
2056  {
2057  /* not found, consider growing... */
2060  {
2062  MHD_SC_CLIENT_HEADER_TOO_BIG,
2063  (NULL != request->url)
2066  REQUEST_TOO_BIG);
2067  }
2068  if (line_len)
2069  *line_len = 0;
2070  return NULL;
2071  }
2072 
2073  if (line_len)
2074  *line_len = pos;
2075  /* found, check if we have proper LFCR */
2076  if ( ('\r' == rbuf[pos]) &&
2077  ('\n' == rbuf[pos + 1]) )
2078  rbuf[pos++] = '\0'; /* skip both r and n */
2079  rbuf[pos++] = '\0';
2080  request->read_buffer += pos;
2081  request->read_buffer_size -= pos;
2082  request->read_buffer_offset -= pos;
2083  return rbuf;
2084 }
2085 
2086 
2106 static bool
2108 {
2109  (void) connection; /* Mute compiler warning. */
2110 #if defined(TCP_CORK) || defined(TCP_PUSH)
2111  return true;
2112 #else /* !TCP_CORK && !TCP_PUSH */
2113  return false;
2114 #endif /* !TCP_CORK && !TCP_PUSH */
2115 }
2116 
2117 
2125 static bool
2127 {
2128  bool res = false;
2129  (void) connection; /* Mute compiler warning. */
2130 #if defined(TCP_CORK) || defined(TCP_NOPUSH)
2131  const MHD_SCKT_OPT_BOOL_ on_val = 1;
2132 #if defined(TCP_NODELAY)
2133  const MHD_SCKT_OPT_BOOL_ off_val = 0;
2134 #endif /* TCP_NODELAY */
2135  mhd_assert (NULL != connection);
2136 #if defined(TCP_NOPUSH) && ! defined(TCP_CORK)
2137  /* Buffer data before sending */
2138  res = (0 == setsockopt (connection->socket_fd,
2139  IPPROTO_TCP,
2140  TCP_NOPUSH,
2141  (const void *) &on_val,
2142  sizeof (on_val)))
2143  ? true : false;
2144 #if defined(TCP_NODELAY)
2145  /* Enable Nagle's algorithm */
2146  /* TCP_NODELAY may interfere with TCP_NOPUSH */
2147  res &= (0 == setsockopt (connection->socket_fd,
2148  IPPROTO_TCP,
2149  TCP_NODELAY,
2150  (const void *) &off_val,
2151  sizeof (off_val)))
2152  ? true : false;
2153 #endif /* TCP_NODELAY */
2154 #else /* TCP_CORK */
2155 #if defined(TCP_NODELAY)
2156  /* Enable Nagle's algorithm */
2157  /* TCP_NODELAY may prevent enabling TCP_CORK. Resulting buffering mode depends
2158  solely on TCP_CORK result, so ignoring return code here. */
2159  (void) setsockopt (connection->socket_fd,
2160  IPPROTO_TCP,
2161  TCP_NODELAY,
2162  (const void *) &off_val,
2163  sizeof (off_val));
2164 #endif /* TCP_NODELAY */
2165  /* Send only full packets */
2166  res = (0 == setsockopt (connection->socket_fd,
2167  IPPROTO_TCP,
2168  TCP_CORK,
2169  (const void *) &on_val,
2170  sizeof (on_val)))
2171  ? true : false;
2172 #endif /* TCP_CORK */
2173 #endif /* TCP_CORK || TCP_NOPUSH */
2174  return res;
2175 }
2176 
2177 
2184 static bool
2186 {
2187 #if defined(TCP_NODELAY)
2188  bool res = true;
2189  const MHD_SCKT_OPT_BOOL_ on_val = 1;
2190 #if defined(TCP_CORK) || defined(TCP_NOPUSH)
2191  const MHD_SCKT_OPT_BOOL_ off_val = 0;
2192 #endif /* TCP_CORK || TCP_NOPUSH */
2193 
2194  (void) connection; /* Mute compiler warning. */
2195  mhd_assert (NULL != connection);
2196 #if defined(TCP_CORK)
2197  /* Allow partial packets */
2198  res &= (0 == setsockopt (connection->socket_fd,
2199  IPPROTO_TCP,
2200  TCP_CORK,
2201  (const void *) &off_val,
2202  sizeof (off_val)))
2203  ? true : false;
2204 #endif /* TCP_CORK */
2205 #if defined(TCP_NODELAY)
2206  /* Disable Nagle's algorithm for sending packets without delay */
2207  res &= (0 == setsockopt (connection->socket_fd,
2208  IPPROTO_TCP,
2209  TCP_NODELAY,
2210  (const void *) &on_val,
2211  sizeof (on_val)))
2212  ? true : false;
2213 #endif /* TCP_NODELAY */
2214 #if defined(TCP_NOPUSH) && ! defined(TCP_CORK)
2215  /* Disable extra buffering */
2216  res &= (0 == setsockopt (connection->socket_fd,
2217  IPPROTO_TCP,
2218  TCP_NOPUSH,
2219  (const void *) &off_val,
2220  sizeof (off_val)))
2221  ? true : false;
2222 #endif /* TCP_NOPUSH && !TCP_CORK */
2223  return res;
2224 #else /* !TCP_NODELAY */
2225  return false;
2226 #endif /* !TCP_NODELAY */
2227 }
2228 
2229 
2237 static bool
2239 {
2240  bool res = true;
2241 #if defined(TCP_NOPUSH) && ! defined(TCP_CORK)
2242  const int dummy = 0;
2243 #endif /* !TCP_CORK */
2244 
2245  if (NULL == connection)
2246  return false; /* FIXME: use MHD_NONNULL? */
2247  res = socket_start_no_buffering (connection);
2248 #if defined(TCP_NOPUSH) && ! defined(TCP_CORK)
2249  /* Force flush data with zero send otherwise Darwin and some BSD systems
2250  will add 5 seconds delay. Not required with TCP_CORK as switching off
2251  TCP_CORK always flushes socket buffer. */
2252  res &= (0 <= MHD_send_ (connection->socket_fd,
2253  &dummy,
2254  0))
2255  ? true : false;
2256 #endif /* TCP_NOPUSH && !TCP_CORK*/
2257  return res;
2258 }
2259 
2260 
2267 static bool
2269 {
2270 #if defined(TCP_NODELAY)
2271  bool res = true;
2272  const MHD_SCKT_OPT_BOOL_ off_val = 0;
2273 #if defined(TCP_CORK)
2274  MHD_SCKT_OPT_BOOL_ cork_val = 0;
2275  socklen_t param_size = sizeof (cork_val);
2276 #endif /* TCP_CORK */
2277 
2278  mhd_assert (NULL != connection);
2279 #if defined(TCP_CORK)
2280  /* Allow partial packets */
2281  /* Disabling TCP_CORK will flush partial packet even if TCP_CORK wasn't enabled before
2282  so try to check current value of TCP_CORK to prevent unrequested flushing */
2283  if ( (0 != getsockopt (connection->socket_fd,
2284  IPPROTO_TCP,
2285  TCP_CORK,
2286  (void*) &cork_val,
2287  &param_size)) ||
2288  (0 != cork_val))
2289  res &= (0 == setsockopt (connection->socket_fd,
2290  IPPROTO_TCP,
2291  TCP_CORK,
2292  (const void *) &off_val,
2293  sizeof (off_val)))
2294  ? true : false;
2295 #elif defined(TCP_NOPUSH)
2296  /* Disable extra buffering */
2297  /* No need to check current value as disabling TCP_NOPUSH will not flush partial
2298  packet if TCP_NOPUSH wasn't enabled before */
2299  res &= (0 == setsockopt (connection->socket_fd,
2300  IPPROTO_TCP,
2301  TCP_NOPUSH,
2302  (const void *) &off_val,
2303  sizeof (off_val)))
2304  ? true : false;
2305 #endif /* TCP_NOPUSH && !TCP_CORK */
2306  /* Enable Nagle's algorithm for normal buffering */
2307  res &= (0 == setsockopt (connection->socket_fd,
2308  IPPROTO_TCP,
2309  TCP_NODELAY,
2310  (const void *) &off_val,
2311  sizeof (off_val)))
2312  ? true : false;
2313  return res;
2314 #else /* !TCP_NODELAY */
2315  return false;
2316 #endif /* !TCP_NODELAY */
2317 }
2318 
2319 
2327 static bool
2329 {
2330  const char *expect;
2331 
2332  return ( (NULL == request->response) &&
2333  (NULL != request->version_s) &&
2336  (NULL != (expect = MHD_request_lookup_value (request,
2339  &&
2340  (MHD_str_equal_caseless_ (expect,
2341  "100-continue")) &&
2344 }
2345 
2346 
2353 static int
2355 {
2356  const char *hdr;
2357  char *cpy;
2358  char *pos;
2359  char *sce;
2360  char *semicolon;
2361  char *equals;
2362  char *ekill;
2363  char old;
2364  int quotes;
2365 
2369  if (NULL == hdr)
2370  return true;
2372  strlen (hdr) + 1,
2373  MHD_YES);
2374  if (NULL == cpy)
2375  {
2376 #ifdef HAVE_MESSAGES
2377  MHD_DLOG (request->daemon,
2378  MHD_SC_COOKIE_POOL_ALLOCATION_FAILURE,
2379  _ ("Not enough memory in pool to parse cookies!\n"));
2380 #endif
2382  MHD_SC_COOKIE_POOL_ALLOCATION_FAILURE,
2384  REQUEST_TOO_BIG);
2385  return false;
2386  }
2387  memcpy (cpy,
2388  hdr,
2389  strlen (hdr) + 1);
2390  pos = cpy;
2391  while (NULL != pos)
2392  {
2393  while (' ' == *pos)
2394  pos++; /* skip spaces */
2395 
2396  sce = pos;
2397  while ( ((*sce) != '\0') &&
2398  ((*sce) != ',') &&
2399  ((*sce) != ';') &&
2400  ((*sce) != '=') )
2401  sce++;
2402  /* remove tailing whitespace (if any) from key */
2403  ekill = sce - 1;
2404  while ( (*ekill == ' ') &&
2405  (ekill >= pos) )
2406  *(ekill--) = '\0';
2407  old = *sce;
2408  *sce = '\0';
2409  if (old != '=')
2410  {
2411  /* value part omitted, use empty string... */
2412  if (! request_add_header (request,
2413  pos,
2414  "",
2415  MHD_COOKIE_KIND))
2416  return false;
2417  if (old == '\0')
2418  break;
2419  pos = sce + 1;
2420  continue;
2421  }
2422  equals = sce + 1;
2423  quotes = 0;
2424  semicolon = equals;
2425  while ( ('\0' != semicolon[0]) &&
2426  ( (0 != quotes) ||
2427  ( (';' != semicolon[0]) &&
2428  (',' != semicolon[0]) ) ) )
2429  {
2430  if ('"' == semicolon[0])
2431  quotes = (quotes + 1) & 1;
2432  semicolon++;
2433  }
2434  if ('\0' == semicolon[0])
2435  semicolon = NULL;
2436  if (NULL != semicolon)
2437  {
2438  semicolon[0] = '\0';
2439  semicolon++;
2440  }
2441  /* remove quotes */
2442  if ( ('"' == equals[0]) &&
2443  ('"' == equals[strlen (equals) - 1]) )
2444  {
2445  equals[strlen (equals) - 1] = '\0';
2446  equals++;
2447  }
2448  if (! request_add_header (request,
2449  pos,
2450  equals,
2451  MHD_COOKIE_KIND))
2452  return false;
2453  pos = semicolon;
2454  }
2455  return true;
2456 }
2457 
2458 
2466 static void
2468 {
2469  struct MHD_Daemon *daemon = request->daemon;
2470  struct MHD_Connection *connection = request->connection;
2471  const char *clen;
2472  struct MHD_Response *response;
2473  const char *enc;
2474  const char *end;
2475 
2476  parse_cookie_header (request); /* FIXME: return value ignored! */
2477  if ( (MHD_PSL_STRICT == daemon->protocol_strict_level) &&
2478  (NULL != request->version_s) &&
2480  request->version_s)) &&
2481  (NULL ==
2482  MHD_request_lookup_value (request,
2485  {
2486  /* die, http 1.1 request without host and we are pedantic */
2488  connection->read_closed = true;
2489 #ifdef HAVE_MESSAGES
2490  MHD_DLOG (daemon,
2491  MHD_SC_HOST_HEADER_MISSING,
2492  _ ("Received HTTP 1.1 request without `Host' header.\n"));
2493 #endif
2494  mhd_assert (NULL == request->response);
2495  response =
2500  request->response = response;
2501  // FIXME: state machine advance?
2502  return;
2503  }
2504 
2505  request->remaining_upload_size = 0;
2506  enc = MHD_request_lookup_value (request,
2509  if (NULL != enc)
2510  {
2512  if (MHD_str_equal_caseless_ (enc,
2513  "chunked"))
2514  request->have_chunked_upload = true;
2515  return;
2516  }
2517  clen = MHD_request_lookup_value (request,
2520  if (NULL == clen)
2521  return;
2522  end = clen + MHD_str_to_uint64_ (clen,
2523  &request->remaining_upload_size);
2524  if ( (clen == end) ||
2525  ('\0' != *end) )
2526  {
2527  request->remaining_upload_size = 0;
2528 #ifdef HAVE_MESSAGES
2529  MHD_DLOG (request->daemon,
2530  MHD_SC_CONTENT_LENGTH_MALFORMED,
2531  "Failed to parse `Content-Length' header. Closing connection.\n");
2532 #endif
2533  CONNECTION_CLOSE_ERROR (connection,
2534  MHD_SC_CONTENT_LENGTH_MALFORMED,
2535  NULL);
2536  }
2537 }
2538 
2539 
2546 static void
2548 {
2549  struct MHD_Daemon *daemon = request->daemon;
2550  struct MHD_Connection *connection = request->connection;
2551  const struct MHD_Action *action;
2552 
2553  if (NULL != request->response)
2554  return; /* already queued a response */
2555  if (NULL == (action =
2556  daemon->rc (daemon->rc_cls,
2557  request,
2558  request->url,
2559  request->method)))
2560  {
2561  /* serious internal error, close connection */
2562  CONNECTION_CLOSE_ERROR (connection,
2563  MHD_SC_APPLICATION_CALLBACK_FAILURE_CLOSED,
2564  _ (
2565  "Application reported internal error, closing connection.\n"));
2566  return;
2567  }
2568  action->action (action->action_cls,
2569  request);
2570 }
2571 
2572 
2579 static void
2581 {
2582  struct MHD_Daemon *daemon = request->daemon;
2583  struct MHD_Connection *connection = request->connection;
2584  size_t available;
2585  bool instant_retry;
2586  char *buffer_head;
2587 
2588  if (NULL != request->response)
2589  return; /* already queued a response */
2590 
2591  buffer_head = request->read_buffer;
2592  available = request->read_buffer_offset;
2593  do
2594  {
2595  size_t to_be_processed;
2596  size_t left_unprocessed;
2597  size_t processed_size;
2598 
2599  instant_retry = false;
2600  if ( (request->have_chunked_upload) &&
2602  {
2604  (0LLU != request->current_chunk_offset) &&
2605  (available >= 2) )
2606  {
2607  size_t i;
2608 
2609  /* skip new line at the *end* of a chunk */
2610  i = 0;
2611  if ( ('\r' == buffer_head[i]) ||
2612  ('\n' == buffer_head[i]) )
2613  i++; /* skip 1st part of line feed */
2614  if ( ('\r' == buffer_head[i]) ||
2615  ('\n' == buffer_head[i]) )
2616  i++; /* skip 2nd part of line feed */
2617  if (0 == i)
2618  {
2619  /* malformed encoding */
2620  CONNECTION_CLOSE_ERROR (connection,
2621  MHD_SC_CHUNKED_ENCODING_MALFORMED,
2622  _ (
2623  "Received malformed HTTP request (bad chunked encoding). Closing connection.\n"));
2624  return;
2625  }
2626  available -= i;
2627  buffer_head += i;
2630  }
2633  {
2634  uint64_t cur_chunk_left;
2635 
2636  /* we are in the middle of a chunk, give
2637  as much as possible to the client (without
2638  crossing chunk boundaries) */
2639  cur_chunk_left
2641  if (cur_chunk_left > available)
2642  {
2643  to_be_processed = available;
2644  }
2645  else
2646  { /* cur_chunk_left <= (size_t)available */
2647  to_be_processed = (size_t) cur_chunk_left;
2648  if (available > to_be_processed)
2649  instant_retry = true;
2650  }
2651  }
2652  else
2653  {
2654  size_t i;
2655  size_t end_size;
2656  bool malformed;
2657 
2658  /* we need to read chunk boundaries */
2659  i = 0;
2660  while (i < available)
2661  {
2662  if ( ('\r' == buffer_head[i]) ||
2663  ('\n' == buffer_head[i]) ||
2664  (';' == buffer_head[i]) )
2665  break;
2666  i++;
2667  if (i >= 16)
2668  break;
2669  }
2670  end_size = i;
2671  /* find beginning of CRLF (skip over chunk extensions) */
2672  if (';' == buffer_head[i])
2673  {
2674  while (i < available)
2675  {
2676  if ( ('\r' == buffer_head[i]) ||
2677  ('\n' == buffer_head[i]) )
2678  break;
2679  i++;
2680  }
2681  }
2682  /* take '\n' into account; if '\n' is the unavailable
2683  character, we will need to wait until we have it
2684  before going further */
2685  if ( (i + 1 >= available) &&
2686  ! ( (1 == i) &&
2687  (2 == available) &&
2688  ('0' == buffer_head[0]) ) )
2689  break; /* need more data... */
2690  i++;
2691  malformed = (end_size >= 16);
2692  if (! malformed)
2693  {
2694  size_t num_dig = MHD_strx_to_uint64_n_ (buffer_head,
2695  end_size,
2697  malformed = (end_size != num_dig);
2698  }
2699  if (malformed)
2700  {
2701  /* malformed encoding */
2702  CONNECTION_CLOSE_ERROR (connection,
2703  MHD_SC_CHUNKED_ENCODING_MALFORMED,
2704  _ (
2705  "Received malformed HTTP request (bad chunked encoding). Closing connection.\n"));
2706  return;
2707  }
2708  /* skip 2nd part of line feed */
2709  if ( (i < available) &&
2710  ( ('\r' == buffer_head[i]) ||
2711  ('\n' == buffer_head[i]) ) )
2712  i++;
2713 
2714  buffer_head += i;
2715  available -= i;
2717 
2718  if (available > 0)
2719  instant_retry = true;
2720  if (0LLU == request->current_chunk_size)
2721  {
2723  break;
2724  }
2725  continue;
2726  }
2727  }
2728  else
2729  {
2730  /* no chunked encoding, give all to the client */
2731  if ( (0 != request->remaining_upload_size) &&
2733  (request->remaining_upload_size < available) )
2734  {
2735  to_be_processed = (size_t) request->remaining_upload_size;
2736  }
2737  else
2738  {
2743  to_be_processed = available;
2744  }
2745  }
2746  left_unprocessed = to_be_processed;
2747 #if FIXME_OLD_STYLE
2748  if (MHD_NO ==
2749  daemon->rc (daemon->rc_cls,
2750  request,
2751  request->url,
2752  request->method,
2753  request->version,
2754  buffer_head,
2755  &left_unprocessed,
2757  {
2758  /* serious internal error, close connection */
2759  CONNECTION_CLOSE_ERROR (connection,
2760  MHD_SC_APPLICATION_CALLBACK_FAILURE_CLOSED,
2761  _ (
2762  "Application reported internal error, closing connection.\n"));
2763  return;
2764  }
2765 #endif
2766  if (left_unprocessed > to_be_processed)
2768  __FILE__,
2769  __LINE__
2770 #ifdef HAVE_MESSAGES
2771  , _ ("libmicrohttpd API violation.\n")
2772 #else
2773  , NULL
2774 #endif
2775  );
2776  if (0 != left_unprocessed)
2777  {
2778  instant_retry = false; /* client did not process everything */
2779 #ifdef HAVE_MESSAGES
2780  /* client did not process all upload data, complain if
2781  the setup was incorrect, which may prevent us from
2782  handling the rest of the request */
2783  if ( (MHD_TM_EXTERNAL_EVENT_LOOP == daemon->threading_mode) &&
2784  (! connection->suspended) )
2785  MHD_DLOG (daemon,
2786  MHD_SC_APPLICATION_HUNG_CONNECTION,
2787  _ (
2788  "WARNING: incomplete upload processing and connection not suspended may result in hung connection.\n"));
2789 #endif
2790  }
2791  processed_size = to_be_processed - left_unprocessed;
2793  request->current_chunk_offset += processed_size;
2794  /* dh left "processed" bytes in buffer for next time... */
2795  buffer_head += processed_size;
2796  available -= processed_size;
2798  request->remaining_upload_size -= processed_size;
2799  }
2800  while (instant_retry);
2801  if (available > 0)
2802  memmove (request->read_buffer,
2803  buffer_head,
2804  available);
2805  request->read_buffer_offset = available;
2806 }
2807 
2808 
2817 static void
2819 {
2820  struct MHD_Daemon *daemon = connection->daemon;
2821 
2822  if (connection->request.in_cleanup)
2823  return; /* Prevent double cleanup. */
2824  connection->request.in_cleanup = true;
2825  if (NULL != connection->request.response)
2826  {
2828  connection->request.response = NULL;
2829  }
2831  if (connection->suspended)
2832  {
2835  connection);
2836  connection->suspended = false;
2837  }
2838  else
2839  {
2840  if (MHD_TM_THREAD_PER_CONNECTION != daemon->threading_mode)
2841  {
2842  if (connection->connection_timeout ==
2845  daemon->normal_timeout_tail,
2846  connection);
2847  else
2849  daemon->manual_timeout_tail,
2850  connection);
2851  }
2852  DLL_remove (daemon->connections_head,
2853  daemon->connections_tail,
2854  connection);
2855  }
2856  DLL_insert (daemon->cleanup_head,
2857  daemon->cleanup_tail,
2858  connection);
2859  connection->resuming = false;
2860  connection->request.in_idle = false;
2862  if (MHD_TM_THREAD_PER_CONNECTION == daemon->threading_mode)
2863  {
2864  /* if we were at the connection limit before and are in
2865  thread-per-connection mode, signal the main thread
2866  to resume accepting connections */
2867  if ( (MHD_ITC_IS_VALID_ (daemon->itc)) &&
2868  (! MHD_itc_activate_ (daemon->itc,
2869  "c")) )
2870  {
2871 #ifdef HAVE_MESSAGES
2872  MHD_DLOG (daemon,
2873  MHD_SC_ITC_USE_FAILED,
2874  _ (
2875  "Failed to signal end of connection via inter-thread communication channel.\n"));
2876 #endif
2877  }
2878  }
2879 }
2880 
2881 
2882 #ifdef EPOLL_SUPPORT
2891 static bool
2892 connection_epoll_update_ (struct MHD_Connection *connection)
2893 {
2894  struct MHD_Daemon *daemon = connection->daemon;
2895 
2896  if ( (MHD_ELS_EPOLL == daemon->event_loop_syscall) &&
2897  (0 == (connection->epoll_state & MHD_EPOLL_STATE_IN_EPOLL_SET)) &&
2898  (0 == (connection->epoll_state & MHD_EPOLL_STATE_SUSPENDED)) &&
2899  ( ( (MHD_EVENT_LOOP_INFO_WRITE == connection->request.event_loop_info) &&
2900  (0 == (connection->epoll_state & MHD_EPOLL_STATE_WRITE_READY))) ||
2901  ( (MHD_EVENT_LOOP_INFO_READ == connection->request.event_loop_info) &&
2902  (0 == (connection->epoll_state & MHD_EPOLL_STATE_READ_READY)) ) ) )
2903  {
2904  /* add to epoll set */
2905  struct epoll_event event;
2906 
2907  event.events = EPOLLIN | EPOLLOUT | EPOLLPRI | EPOLLET;
2908  event.data.ptr = connection;
2909  if (0 != epoll_ctl (daemon->epoll_fd,
2910  EPOLL_CTL_ADD,
2911  connection->socket_fd,
2912  &event))
2913  {
2914 #ifdef HAVE_MESSAGES
2915  MHD_DLOG (daemon,
2916  MHD_SC_EPOLL_CTL_ADD_FAILED,
2917  _ ("Call to epoll_ctl failed: %s\n"),
2919 #endif
2920  connection->request.state = MHD_REQUEST_CLOSED;
2921  cleanup_connection (connection);
2922  return false;
2923  }
2924  connection->epoll_state |= MHD_EPOLL_STATE_IN_EPOLL_SET;
2925  }
2926  return true;
2927 }
2928 
2929 
2930 #endif
2931 
2932 
2941 static void
2943 {
2944  struct MHD_Daemon *daemon = connection->daemon;
2945  struct MHD_Request *request = &connection->request;
2946 
2947  /* Do not update states of suspended connection */
2948  if (connection->suspended)
2949  return; /* States will be updated after resume. */
2950 #ifdef HTTPS_SUPPORT
2951  {
2952  struct MHD_TLS_Plugin *tls;
2953 
2954  if ( (NULL != (tls = daemon->tls_api)) &&
2955  (tls->update_event_loop_info (tls->cls,
2956  connection->tls_cs,
2957  &request->event_loop_info)) )
2958  return; /* TLS has decided what to do */
2959  }
2960 #endif /* HTTPS_SUPPORT */
2961  while (1)
2962  {
2963 #if DEBUG_STATES
2964  MHD_DLOG (daemon,
2965  MHD_SC_STATE_MACHINE_STATUS_REPORT,
2966  _ ("In function %s handling connection at state: %s\n"),
2967  __FUNCTION__,
2968  MHD_state_to_string (request->state));
2969 #endif
2970  switch (request->state)
2971  {
2972  case MHD_REQUEST_INIT:
2975  /* while reading headers, we always grow the
2976  read buffer if needed, no size-check required */
2977  if ( (request->read_buffer_offset == request->read_buffer_size) &&
2978  (! try_grow_read_buffer (request)) )
2979  {
2980  transmit_error_response (request,
2981  MHD_SC_CLIENT_HEADER_TOO_BIG,
2982  (NULL != request->url)
2985  REQUEST_TOO_BIG);
2986  continue;
2987  }
2988  if (! connection->read_closed)
2990  else
2992  break;
2994  mhd_assert (0);
2995  break;
2997  mhd_assert (0);
2998  break;
3001  break;
3003  if (request->read_buffer_offset == request->read_buffer_size)
3004  {
3005  if ( (! try_grow_read_buffer (request)) &&
3006  (MHD_TM_EXTERNAL_EVENT_LOOP != daemon->threading_mode) )
3007  {
3008  /* failed to grow the read buffer, and the client
3009  which is supposed to handle the received data in
3010  a *blocking* fashion (in this mode) did not
3011  handle the data as it was supposed to!
3012 
3013  => we would either have to do busy-waiting
3014  (on the client, which would likely fail),
3015  or if we do nothing, we would just timeout
3016  on the connection (if a timeout is even set!).
3017 
3018  Solution: we kill the connection with an error */transmit_error_response (request,
3019  MHD_SC_APPLICATION_HUNG_CONNECTION_CLOSED,
3021  INTERNAL_ERROR);
3022  continue;
3023  }
3024  }
3025  if ( (request->read_buffer_offset < request->read_buffer_size) &&
3026  (! connection->read_closed) )
3028  else
3030  break;
3033  /* while reading footers, we always grow the
3034  read buffer if needed, no size-check required */
3035  if (connection->read_closed)
3036  {
3037  CONNECTION_CLOSE_ERROR (connection,
3038  MHD_SC_CONNECTION_READ_FAIL_CLOSED,
3039  NULL);
3040  continue;
3041  }
3043  /* transition to FOOTERS_RECEIVED
3044  happens in read handler */
3045  break;
3048  break;
3050  /* headers in buffer, keep writing */
3052  break;
3054  mhd_assert (0);
3055  break;
3058  break;
3061  break;
3064  break;
3067  break;
3068  case MHD_REQUEST_BODY_SENT:
3069  mhd_assert (0);
3070  break;
3073  break;
3075  mhd_assert (0);
3076  break;
3077  case MHD_REQUEST_CLOSED:
3079  return; /* do nothing, not even reading */
3080 #ifdef UPGRADE_SUPPORT
3081  case MHD_REQUEST_UPGRADE:
3082  mhd_assert (0);
3083  break;
3084 #endif /* UPGRADE_SUPPORT */
3085  default:
3086  mhd_assert (0);
3087  }
3088  break;
3089  }
3090 }
3091 
3092 
3103 bool
3105 {
3106  struct MHD_Daemon *daemon = request->daemon;
3107  struct MHD_Connection *connection = request->connection;
3108  char *line;
3109  size_t line_len;
3110  bool ret;
3111 
3112  request->in_idle = true;
3113  while (! connection->suspended)
3114  {
3115 #ifdef HTTPS_SUPPORT
3116  struct MHD_TLS_Plugin *tls;
3117 
3118  if ( (NULL != (tls = daemon->tls_api)) &&
3119  (! tls->idle_ready (tls->cls,
3120  connection->tls_cs)) )
3121  break;
3122 #endif /* HTTPS_SUPPORT */
3123 #if DEBUG_STATES
3124  MHD_DLOG (daemon,
3125  MHD_SC_STATE_MACHINE_STATUS_REPORT,
3126  _ ("In function %s handling connection at state: %s\n"),
3127  __FUNCTION__,
3128  MHD_state_to_string (request->state));
3129 #endif
3130  switch (request->state)
3131  {
3132  case MHD_REQUEST_INIT:
3133  line = get_next_header_line (request,
3134  &line_len);
3135  /* Check for empty string, as we might want
3136  to tolerate 'spurious' empty lines; also
3137  NULL means we didn't get a full line yet;
3138  line is not 0-terminated here. */
3139  if ( (NULL == line) ||
3140  (0 == line[0]) )
3141  {
3142  if (MHD_REQUEST_INIT != request->state)
3143  continue;
3144  if (connection->read_closed)
3145  {
3146  CONNECTION_CLOSE_ERROR (connection,
3147  MHD_SC_CONNECTION_READ_FAIL_CLOSED,
3148  NULL);
3149  continue;
3150  }
3151  break;
3152  }
3153  if (MHD_NO ==
3154  parse_initial_message_line (request,
3155  line,
3156  line_len))
3157  CONNECTION_CLOSE_ERROR (connection,
3158  MHD_SC_CONNECTION_CLOSED,
3159  NULL);
3160  else
3161  request->state = MHD_REQUEST_URL_RECEIVED;
3162  continue;
3164  line = get_next_header_line (request,
3165  NULL);
3166  if (NULL == line)
3167  {
3168  if (MHD_REQUEST_URL_RECEIVED != request->state)
3169  continue;
3170  if (connection->read_closed)
3171  {
3172  CONNECTION_CLOSE_ERROR (connection,
3173  MHD_SC_CONNECTION_READ_FAIL_CLOSED,
3174  NULL);
3175  continue;
3176  }
3177  break;
3178  }
3179  if (0 == line[0])
3180  {
3182  request->header_size = (size_t) (line - request->read_buffer);
3183  continue;
3184  }
3185  if (! process_header_line (request,
3186  line))
3187  {
3188  transmit_error_response (request,
3189  MHD_SC_CONNECTION_PARSE_FAIL_CLOSED,
3192  break;
3193  }
3195  continue;
3197  line = get_next_header_line (request,
3198  NULL);
3199  if (NULL == line)
3200  {
3201  if (request->state != MHD_REQUEST_HEADER_PART_RECEIVED)
3202  continue;
3203  if (connection->read_closed)
3204  {
3205  CONNECTION_CLOSE_ERROR (connection,
3206  MHD_SC_CONNECTION_READ_FAIL_CLOSED,
3207  NULL);
3208  continue;
3209  }
3210  break;
3211  }
3212  if (MHD_NO ==
3213  process_broken_line (request,
3214  line,
3215  MHD_HEADER_KIND))
3216  continue;
3217  if (0 == line[0])
3218  {
3220  request->header_size = (size_t) (line - request->read_buffer);
3221  continue;
3222  }
3223  continue;
3225  parse_request_headers (request);
3226  if (MHD_REQUEST_CLOSED == request->state)
3227  continue;
3229  if (connection->suspended)
3230  break;
3231  continue;
3233  call_request_handler (request); /* first call */
3234  if (MHD_REQUEST_CLOSED == request->state)
3235  continue;
3236  if (need_100_continue (request))
3237  {
3239  if (socket_flush_possible (connection))
3240  socket_start_extra_buffering (connection);
3241  else
3242  socket_start_no_buffering (connection);
3243  break;
3244  }
3245  if ( (NULL != request->response) &&
3246  ( (MHD_METHOD_POST == request->method) ||
3247  (MHD_METHOD_PUT == request->method) ) )
3248  {
3249  /* we refused (no upload allowed!) */
3250  request->remaining_upload_size = 0;
3251  /* force close, in case client still tries to upload... */
3252  connection->read_closed = true;
3253  }
3254  request->state = (0 == request->remaining_upload_size)
3257  if (connection->suspended)
3258  break;
3259  continue;
3261  if (request->continue_message_write_offset ==
3263  {
3264  request->state = MHD_REQUEST_CONTINUE_SENT;
3265  if (! socket_flush_possible (connection))
3266  socket_start_no_buffering_flush (connection);
3267  else
3268  socket_start_normal_buffering (connection);
3269  continue;
3270  }
3271  break;
3273  if (0 != request->read_buffer_offset)
3274  {
3275  process_request_body (request); /* loop call */
3276  if (MHD_REQUEST_CLOSED == request->state)
3277  continue;
3278  }
3279  if ( (0 == request->remaining_upload_size) ||
3280  ( (MHD_SIZE_UNKNOWN == request->remaining_upload_size) &&
3281  (0 == request->read_buffer_offset) &&
3282  (connection->read_closed) ) )
3283  {
3284  if ( (request->have_chunked_upload) &&
3285  (! connection->read_closed) )
3286  request->state = MHD_REQUEST_BODY_RECEIVED;
3287  else
3289  if (connection->suspended)
3290  break;
3291  continue;
3292  }
3293  break;
3295  line = get_next_header_line (request,
3296  NULL);
3297  if (NULL == line)
3298  {
3299  if (request->state != MHD_REQUEST_BODY_RECEIVED)
3300  continue;
3301  if (connection->read_closed)
3302  {
3303  CONNECTION_CLOSE_ERROR (connection,
3304  MHD_SC_CONNECTION_CLOSED,
3305  NULL);
3306  continue;
3307  }
3308  break;
3309  }
3310  if (0 == line[0])
3311  {
3313  if (connection->suspended)
3314  break;
3315  continue;
3316  }
3317  if (MHD_NO == process_header_line (request,
3318  line))
3319  {
3320  transmit_error_response (request,
3321  MHD_SC_CONNECTION_PARSE_FAIL_CLOSED,
3324  break;
3325  }
3327  continue;
3329  line = get_next_header_line (request,
3330  NULL);
3331  if (NULL == line)
3332  {
3333  if (request->state != MHD_REQUEST_FOOTER_PART_RECEIVED)
3334  continue;
3335  if (connection->read_closed)
3336  {
3337  CONNECTION_CLOSE_ERROR (connection,
3338  MHD_SC_CONNECTION_CLOSED,
3339  NULL);
3340  continue;
3341  }
3342  break;
3343  }
3344  if (MHD_NO ==
3345  process_broken_line (request,
3346  line,
3347  MHD_FOOTER_KIND))
3348  continue;
3349  if (0 == line[0])
3350  {
3352  if (connection->suspended)
3353  break;
3354  continue;
3355  }
3356  continue;
3358  call_request_handler (request); /* "final" call */
3359  if (request->state == MHD_REQUEST_CLOSED)
3360  continue;
3361  if (NULL == request->response)
3362  break; /* try again next time */
3363  if (! build_header_response (request))
3364  {
3365  /* oops - close! */
3366  CONNECTION_CLOSE_ERROR (connection,
3367  MHD_SC_FAILED_RESPONSE_HEADER_GENERATION,
3368  _ (
3369  "Closing connection (failed to create response header).\n"));
3370  continue;
3371  }
3373  if (MHD_NO != socket_flush_possible (connection))
3374  socket_start_extra_buffering (connection);
3375  else
3376  socket_start_no_buffering (connection);
3377 
3378  break;
3380  /* no default action */
3381  break;
3383  /* Some clients may take some actions right after header receive */
3384  if (MHD_NO != socket_flush_possible (connection))
3385  socket_start_no_buffering_flush (connection);
3386 
3387 #ifdef UPGRADE_SUPPORT
3388  if (NULL != request->response->upgrade_handler)
3389  {
3390  socket_start_normal_buffering (connection);
3391  request->state = MHD_REQUEST_UPGRADE;
3392 #if FIXME_LEGACY_STYLE
3393  /* This request is "upgraded". Pass socket to application. */
3394  if (! MHD_response_execute_upgrade_ (request->response,
3395  request))
3396  {
3397  /* upgrade failed, fail hard */
3398  CONNECTION_CLOSE_ERROR (connection,
3399  MHD_SC_CONNECTION_CLOSED,
3400  NULL);
3401  continue;
3402  }
3403 #endif
3404  /* Response is not required anymore for this request. */
3405  {
3406  struct MHD_Response *const resp = request->response;
3407 
3408  request->response = NULL;
3410  }
3411  continue;
3412  }
3413 #endif /* UPGRADE_SUPPORT */
3414  if (MHD_NO != socket_flush_possible (connection))
3415  socket_start_extra_buffering (connection);
3416  else
3417  socket_start_normal_buffering (connection);
3418 
3419  if (request->have_chunked_upload)
3421  else
3423  continue;
3425  /* nothing to do here */
3426  break;
3428  if (NULL != request->response->crc)
3429  MHD_mutex_lock_chk_ (&request->response->mutex);
3430  if (0 == request->response->total_size)
3431  {
3432  if (NULL != request->response->crc)
3433  MHD_mutex_unlock_chk_ (&request->response->mutex);
3434  request->state = MHD_REQUEST_BODY_SENT;
3435  continue;
3436  }
3437  if (try_ready_normal_body (request))
3438  {
3439  if (NULL != request->response->crc)
3440  MHD_mutex_unlock_chk_ (&request->response->mutex);
3442  /* Buffering for flushable socket was already enabled*/
3443  if (MHD_NO == socket_flush_possible (connection))
3444  socket_start_no_buffering (connection);
3445  break;
3446  }
3447  /* mutex was already unlocked by "try_ready_normal_body */
3448  /* not ready, no socket action */
3449  break;
3451  /* nothing to do here */
3452  break;
3454  if (NULL != request->response->crc)
3455  MHD_mutex_lock_chk_ (&request->response->mutex);
3456  if ( (0 == request->response->total_size) ||
3457  (request->response_write_position ==
3458  request->response->total_size) )
3459  {
3460  if (NULL != request->response->crc)
3461  MHD_mutex_unlock_chk_ (&request->response->mutex);
3462  request->state = MHD_REQUEST_BODY_SENT;
3463  continue;
3464  }
3465  if (try_ready_chunked_body (request))
3466  {
3467  if (NULL != request->response->crc)
3468  MHD_mutex_unlock_chk_ (&request->response->mutex);
3470  /* Buffering for flushable socket was already enabled */
3471  if (MHD_NO == socket_flush_possible (connection))
3472  socket_start_no_buffering (connection);
3473  continue;
3474  }
3475  /* mutex was already unlocked by try_ready_chunked_body */
3476  break;
3477  case MHD_REQUEST_BODY_SENT:
3478  if (! build_header_response (request))
3479  {
3480  /* oops - close! */
3481  CONNECTION_CLOSE_ERROR (connection,
3482  MHD_SC_FAILED_RESPONSE_HEADER_GENERATION,
3483  _ (
3484  "Closing connection (failed to create response header).\n"));
3485  continue;
3486  }
3487  if ( (! request->have_chunked_upload) ||
3488  (request->write_buffer_send_offset ==
3489  request->write_buffer_append_offset) )
3490  request->state = MHD_REQUEST_FOOTERS_SENT;
3491  else
3493  continue;
3495  /* no default action */
3496  break;
3498  {
3499  struct MHD_Response *response = request->response;
3500 
3501  if (MHD_HTTP_PROCESSING == response->status_code)
3502  {
3503  /* After this type of response, we allow sending another! */
3505  MHD_response_queue_for_destroy (response);
3506  request->response = NULL;
3507  /* FIXME: maybe partially reset memory pool? */
3508  continue;
3509  }
3510  if (socket_flush_possible (connection))
3511  socket_start_no_buffering_flush (connection);
3512  else
3513  socket_start_normal_buffering (connection);
3514 
3515  if (NULL != response->termination_cb)
3516  {
3517  response->termination_cb (response->termination_cb_cls,
3519  request->client_context);
3520  }
3521  MHD_response_queue_for_destroy (response);
3522  request->response = NULL;
3523  }
3524  if ( (MHD_CONN_USE_KEEPALIVE != request->keepalive) ||
3525  (connection->read_closed) )
3526  {
3527  /* have to close for some reason */
3528  MHD_connection_close_ (connection,
3530  MHD_pool_destroy (connection->pool);
3531  connection->pool = NULL;
3532  request->read_buffer = NULL;
3533  request->read_buffer_size = 0;
3534  request->read_buffer_offset = 0;
3535  }
3536  else
3537  {
3538  /* can try to keep-alive */
3539  if (socket_flush_possible (connection))
3540  socket_start_normal_buffering (connection);
3541  request->version_s = NULL;
3542  request->state = MHD_REQUEST_INIT;
3543  request->last = NULL;
3544  request->colon = NULL;
3545  request->header_size = 0;
3547  /* Reset the read buffer to the starting size,
3548  preserving the bytes we have already read. */
3549  request->read_buffer
3550  = MHD_pool_reset (connection->pool,
3551  request->read_buffer,
3552  request->read_buffer_offset,
3553  daemon->connection_memory_limit_b / 2);
3554  request->read_buffer_size
3555  = daemon->connection_memory_limit_b / 2;
3556  }
3557  // FIXME: this is too much, NULLs out some of the things
3558  // initialized above...
3559  memset (request,
3560  0,
3561  sizeof (struct MHD_Request));
3562  request->daemon = daemon;
3563  request->connection = connection;
3564  continue;
3565  case MHD_REQUEST_CLOSED:
3566  cleanup_connection (connection);
3567  request->in_idle = false;
3568  return false;
3569 #ifdef UPGRADE_SUPPORT
3570  case MHD_REQUEST_UPGRADE:
3571  request->in_idle = false;
3572  return true; /* keep open */
3573 #endif /* UPGRADE_SUPPORT */
3574  default:
3575  mhd_assert (0);
3576  break;
3577  }
3578  break;
3579  }
3580  if (! connection->suspended)
3581  {
3582  time_t timeout;
3583  timeout = connection->connection_timeout;
3584  if ( (0 != timeout) &&
3585  (timeout < (MHD_monotonic_sec_counter ()
3586  - connection->last_activity)) )
3587  {
3588  MHD_connection_close_ (connection,
3590  request->in_idle = false;
3591  return true;
3592  }
3593  }
3594  connection_update_event_loop_info (connection);
3595  ret = true;
3596 #ifdef EPOLL_SUPPORT
3597  if ( (! connection->suspended) &&
3598  (MHD_ELS_EPOLL == daemon->event_loop_syscall) )
3599  {
3600  ret = connection_epoll_update_ (connection);
3601  }
3602 #endif /* EPOLL_SUPPORT */
3603  request->in_idle = false;
3604  return ret;
3605 }
3606 
3607 
3621 // FIXME: rename connection->request?
3622 int
3624  bool read_ready,
3625  bool write_ready,
3626  bool force_close)
3627 {
3628  struct MHD_Daemon *daemon = con->daemon;
3629  int ret;
3630  bool states_info_processed = false;
3631  /* Fast track flag */
3632  bool on_fasttrack = (con->request.state == MHD_REQUEST_INIT);
3633 
3634 #ifdef HTTPS_SUPPORT
3635  if (con->tls_read_ready)
3636  read_ready = true;
3637 #endif /* HTTPS_SUPPORT */
3638  if (! force_close)
3639  {
3640  if ( (MHD_EVENT_LOOP_INFO_READ ==
3641  con->request.event_loop_info) &&
3642  read_ready)
3643  {
3645  ret = MHD_request_handle_idle_ (&con->request);
3646  states_info_processed = true;
3647  }
3648  /* No need to check value of 'ret' here as closed connection
3649  * cannot be in MHD_EVENT_LOOP_INFO_WRITE state. */
3650  if ( (MHD_EVENT_LOOP_INFO_WRITE ==
3651  con->request.event_loop_info) &&
3652  write_ready)
3653  {
3655  ret = MHD_request_handle_idle_ (&con->request);
3656  states_info_processed = true;
3657  }
3658  }
3659  else
3660  {
3661  MHD_connection_close_ (con,
3663  return MHD_request_handle_idle_ (&con->request);
3664  }
3665 
3666  if (! states_info_processed)
3667  { /* Connection is not read or write ready, but external conditions
3668  * may be changed and need to be processed. */
3669  ret = MHD_request_handle_idle_ (&con->request);
3670  }
3671  /* Fast track for fast connections. */
3672  /* If full request was read by single read_handler() invocation
3673  and headers were completely prepared by single MHD_request_handle_idle_()
3674  then try not to wait for next sockets polling and send response
3675  immediately.
3676  As writeability of socket was not checked and it may have
3677  some data pending in system buffers, use this optimization
3678  only for non-blocking sockets. *//* No need to check 'ret' as connection is always in
3679  * MHD_CONNECTION_CLOSED state if 'ret' is equal 'MHD_NO'. */else if (on_fasttrack &&
3680  con->sk_nonblck)
3681  {
3683  {
3685  /* Always call 'MHD_request_handle_idle_()' after each read/write. */
3686  ret = MHD_request_handle_idle_ (&con->request);
3687  }
3688  /* If all headers were sent by single write_handler() and
3689  * response body is prepared by single MHD_request_handle_idle_()
3690  * call - continue. */
3693  {
3695  ret = MHD_request_handle_idle_ (&con->request);
3696  }
3697  }
3698 
3699  /* All connection's data and states are processed for this turn.
3700  * If connection already has more data to be processed - use
3701  * zero timeout for next select()/poll(). */
3702  /* Thread-per-connection do not need global zero timeout as
3703  * connections are processed individually. */
3704  /* Note: no need to check for read buffer availability for
3705  * TLS read-ready connection in 'read info' state as connection
3706  * without space in read buffer will be market as 'info block'. */
3707  if ( (! daemon->data_already_pending) &&
3708  (MHD_TM_THREAD_PER_CONNECTION != daemon->threading_mode) )
3709  {
3711  con->request.event_loop_info)
3712  daemon->data_already_pending = true;
3713 #ifdef HTTPS_SUPPORT
3714  else if ( (con->tls_read_ready) &&
3716  con->request.event_loop_info) )
3717  daemon->data_already_pending = true;
3718 #endif /* HTTPS_SUPPORT */
3719  }
3720  return ret;
3721 }
3722 
3723 
3724 /* end of connection_call_handlers.c */
#define MHD_SENFILE_CHUNK_THR_P_C_
static bool socket_flush_possible(struct MHD_Connection *connection)
static void process_request_body(struct MHD_Request *request)
static void connection_close_error(struct MHD_Connection *connection, enum MHD_StatusCode sc, const char *emsg)
static bool parse_initial_message_line(struct MHD_Request *request, char *line, size_t line_len)
static bool MHD_lookup_header_token_ci(const struct MHD_Request *request, const char *header, const char *token, size_t token_len)
#define INTERNAL_ERROR
static bool socket_start_normal_buffering(struct MHD_Connection *connection)
static void MHD_request_handle_write_(struct MHD_Request *request)
static char * get_next_header_line(struct MHD_Request *request, size_t *line_len)
int MHD_connection_call_handlers_(struct MHD_Connection *con, bool read_ready, bool write_ready, bool force_close)
#define REQUEST_TOO_BIG
static bool need_100_continue(struct MHD_Request *request)
#define HTTP_100_CONTINUE
bool MHD_request_handle_idle_(struct MHD_Request *request)
#define REQUEST_MALFORMED
static bool try_ready_chunked_body(struct MHD_Request *request)
static void connection_update_event_loop_info(struct MHD_Connection *connection)
#define MHD_lookup_header_s_token_ci(r, h, tkn)
static bool process_header_line(struct MHD_Request *request, char *line)
static bool check_write_done(struct MHD_Request *request, enum MHD_REQUEST_STATE next_state)
#define REQUEST_LACKS_HOST
static bool request_add_header(struct MHD_Request *request, const char *key, const char *value, enum MHD_ValueKind kind)
static void parse_request_headers(struct MHD_Request *request)
static bool keepalive_possible(struct MHD_Request *request)
static bool check_response_header_token_ci(const struct MHD_Response *response, const char *key, const char *token, size_t token_len)
static void cleanup_connection(struct MHD_Connection *connection)
static bool process_broken_line(struct MHD_Request *request, char *line, enum MHD_ValueKind kind)
#define CONNECTION_CLOSE_ERROR(c, sc, emsg)
static bool socket_start_extra_buffering(struct MHD_Connection *connection)
static bool socket_start_no_buffering_flush(struct MHD_Connection *connection)
static enum MHD_Method method_string_to_enum(const char *method)
static bool try_ready_normal_body(struct MHD_Request *request)
static bool build_header_response(struct MHD_Request *request)
static void get_date_string(char *date, size_t date_len)
static bool try_grow_read_buffer(struct MHD_Request *request)
static void call_request_handler(struct MHD_Request *request)
static void MHD_request_handle_read_(struct MHD_Request *request)
static void transmit_error_response(struct MHD_Request *request, enum MHD_StatusCode ec, enum MHD_HTTP_StatusCode status_code, const char *message)
static bool socket_start_no_buffering(struct MHD_Connection *connection)
#define check_response_header_s_token_ci(r, k, tkn)
#define MHD_SENFILE_CHUNK_
static int parse_cookie_header(struct MHD_Request *request)
function to call event handlers based on event mask
void MHD_connection_close_(struct MHD_Connection *connection, enum MHD_RequestTerminationCode rtc)
functions to close connection
void MHD_connection_update_last_activity_(struct MHD_Connection *connection)
function to update last activity of a connection
#define MHD_HTTP_HEADER_CONTENT_LENGTH
Definition: microhttpd.h:575
#define MHD_HTTP_HEADER_CONNECTION
Definition: microhttpd.h:569
#define MHD_HTTP_HEADER_DATE
Definition: microhttpd.h:583
#define MHD_HTTP_HEADER_TRANSFER_ENCODING
Definition: microhttpd.h:631
#define MHD_HTTP_HEADER_COOKIE
Definition: microhttpd.h:709
#define MHD_HTTP_HEADER_EXPECT
Definition: microhttpd.h:587
#define MHD_HTTP_HEADER_HOST
Definition: microhttpd.h:593
#define MHD_HTTP_INTERNAL_SERVER_ERROR
Definition: microhttpd.h:446
#define MHD_HTTP_URI_TOO_LONG
Definition: microhttpd.h:413
#define MHD_HTTP_REQUEST_HEADER_FIELDS_TOO_LARGE
Definition: microhttpd.h:440
#define MHD_HTTP_PROCESSING
Definition: microhttpd.h:339
#define MHD_HTTP_NOT_MODIFIED
Definition: microhttpd.h:374
#define MHD_HTTP_NO_CONTENT
Definition: microhttpd.h:352
#define MHD_HTTP_BAD_REQUEST
Definition: microhttpd.h:385
enum MHD_Bool MHD_request_set_value(struct MHD_Request *request, enum MHD_ValueKind kind, const char *key, const char *value)
Definition: request.c:96
const char * MHD_request_lookup_value(struct MHD_Request *request, enum MHD_ValueKind kind, const char *key)
Definition: request.c:138
@ MHD_REQUEST_TERMINATED_TIMEOUT_REACHED
Definition: microhttpd.h:1854
@ MHD_REQUEST_TERMINATED_COMPLETED_OK
Definition: microhttpd.h:1838
@ MHD_REQUEST_TERMINATED_WITH_ERROR
Definition: microhttpd.h:1846
@ MHD_REQUEST_TERMINATED_READ_ERROR
Definition: microhttpd.h:1871
@ MHD_REQUEST_TERMINATED_CLIENT_ABORT
Definition: microhttpd.h:1879
const char * MHD_response_get_header(struct MHD_Response *response, const char *key)
Definition: response.c:243
void MHD_response_queue_for_destroy(struct MHD_Response *response)
Definition: response.c:88
struct MHD_Response * MHD_response_from_buffer(enum MHD_HTTP_StatusCode sc, size_t size, void *buffer, enum MHD_ResponseMemoryMode mode)
@ MHD_RESPMEM_PERSISTENT
Definition: microhttpd.h:3072
#define MHD_HTTP_VERSION_1_0
Definition: microhttpd.h:902
#define MHD_HTTP_VERSION_1_1
Definition: microhttpd.h:903
bool MHD_parse_arguments_(struct MHD_Request *request, enum MHD_ValueKind kind, char *args, MHD_ArgumentIterator_ cb, unsigned int *num_headers)
Definition: internal.c:190
#define MHD_ERR_CONNRESET_
Definition: internal.h:1868
MHD_PanicCallback mhd_panic
Definition: panic.c:31
@ MHD_EPOLL_STATE_SUSPENDED
Definition: internal.h:621
@ MHD_EPOLL_STATE_READ_READY
Definition: internal.h:600
@ MHD_EPOLL_STATE_IN_EPOLL_SET
Definition: internal.h:616
@ MHD_EPOLL_STATE_WRITE_READY
Definition: internal.h:606
#define DLL_insert(head, tail, element)
Definition: internal.h:1743
#define MHD_PANIC(msg)
Definition: internal.h:69
#define MHD_MIN(a, b)
Definition: internal.h:110
@ MHD_CONN_USE_KEEPALIVE
Definition: internal.h:169
@ MHD_CONN_MUST_CLOSE
Definition: internal.h:159
@ MHD_CONN_KEEPALIVE_UNKOWN
Definition: internal.h:164
#define MHD_ERR_AGAIN_
Definition: internal.h:1863
MHD_REQUEST_STATE
Definition: internal.h:217
@ MHD_REQUEST_CHUNKED_BODY_UNREADY
Definition: internal.h:301
@ MHD_REQUEST_CLOSED
Definition: internal.h:321
@ MHD_REQUEST_CONTINUE_SENDING
Definition: internal.h:247
@ MHD_REQUEST_NORMAL_BODY_READY
Definition: internal.h:285
@ MHD_REQUEST_FOOTER_PART_RECEIVED
Definition: internal.h:263
@ MHD_REQUEST_HEADER_PART_RECEIVED
Definition: internal.h:232
@ MHD_REQUEST_FOOTERS_SENDING
Definition: internal.h:311
@ MHD_REQUEST_HEADERS_SENDING
Definition: internal.h:275
@ MHD_REQUEST_HEADERS_SENT
Definition: internal.h:280
@ MHD_REQUEST_BODY_RECEIVED
Definition: internal.h:257
@ MHD_REQUEST_INIT
Definition: internal.h:222
@ MHD_REQUEST_CHUNKED_BODY_READY
Definition: internal.h:296
@ MHD_REQUEST_HEADERS_RECEIVED
Definition: internal.h:237
@ MHD_REQUEST_FOOTERS_RECEIVED
Definition: internal.h:269
@ MHD_REQUEST_HEADERS_PROCESSED
Definition: internal.h:242
@ MHD_REQUEST_FOOTERS_SENT
Definition: internal.h:316
@ MHD_REQUEST_URL_RECEIVED
Definition: internal.h:227
@ MHD_REQUEST_BODY_SENT
Definition: internal.h:306
@ MHD_REQUEST_CONTINUE_SENT
Definition: internal.h:252
@ MHD_REQUEST_NORMAL_BODY_UNREADY
Definition: internal.h:291
#define XDLL_remove(head, tail, element)
Definition: internal.h:1806
#define DLL_remove(head, tail, element)
Definition: internal.h:1763
void * mhd_panic_cls
Definition: panic.c:36
#define MHD_ERR_BADF_
Definition: internal.h:1884
void MHD_pool_destroy(struct MemoryPool *pool)
Definition: memorypool.c:157
void * MHD_pool_reallocate(struct MemoryPool *pool, void *old, size_t old_size, size_t new_size)
Definition: memorypool.c:248
void * MHD_pool_reset(struct MemoryPool *pool, void *keep, size_t copy_bytes, size_t new_size)
Definition: memorypool.c:314
void * MHD_pool_allocate(struct MemoryPool *pool, size_t size, int from_end)
Definition: memorypool.c:203
#define mhd_assert(CHK)
Definition: mhd_assert.h:39
#define SIZE_MAX
Definition: mhd_limits.h:99
#define OFF_T_MAX
Definition: mhd_limits.h:123
#define MHD_mutex_unlock_chk_(pmutex)
Definition: mhd_locks.h:180
#define MHD_mutex_lock_chk_(pmutex)
Definition: mhd_locks.h:154
time_t MHD_monotonic_sec_counter(void)
#define MHD_SCKT_ERR_IS_(err, code)
Definition: mhd_sockets.h:611
int MHD_SCKT_OPT_BOOL_
Definition: mhd_sockets.h:203
#define MHD_SCKT_ERR_IS_EAGAIN_(err)
Definition: mhd_sockets.h:643
#define MHD_socket_last_strerr_()
Definition: mhd_sockets.h:549
#define MHD_SCKT_EBADF_
Definition: mhd_sockets.h:454
#define MHD_socket_get_error_()
Definition: mhd_sockets.h:523
#define MHD_SCKT_ERR_IS_EINTR_(err)
Definition: mhd_sockets.h:634
#define MHD_send_(s, b, l)
Definition: mhd_sockets.h:261
int MHD_str_equal_caseless_(const char *str1, const char *str2)
Definition: mhd_str.c:346
size_t MHD_strx_to_uint64_n_(const char *str, size_t maxlen, uint64_t *out_val)
Definition: mhd_str.c:692
size_t MHD_str_to_uint64_(const char *str, uint64_t *out_val)
Definition: mhd_str.c:473
bool MHD_str_has_token_caseless_(const char *str, const char *const token, size_t token_len)
Definition: mhd_str.c:412
#define MHD_STATICSTR_LEN_(macro)
Definition: mhd_str.h:45
#define NULL
Definition: reason_phrase.c:30
#define _(String)
Definition: mhd_options.h:42
internal shared structures
@ MHD_EVENT_LOOP_INFO_READ
Definition: internal.h:234
@ MHD_EVENT_LOOP_INFO_WRITE
Definition: internal.h:239
@ MHD_EVENT_LOOP_INFO_CLEANUP
Definition: internal.h:249
@ MHD_EVENT_LOOP_INFO_BLOCK
Definition: internal.h:244
#define SSIZE_MAX
Definition: mhd_limits.h:111
#define MHD_SIZE_UNKNOWN
Definition: microhttpd.h:168
@ MHD_YES
Definition: microhttpd.h:151
@ MHD_NO
Definition: microhttpd.h:146
int off_t offset
Definition: microhttpd.h:3196
#define MHD_CONTENT_READER_END_OF_STREAM
Definition: microhttpd.h:175
#define MHD_UNSIGNED_LONG_LONG
Definition: microhttpd.h:299
#define MHD_UNSIGNED_LONG_LONG_PRINTF
Definition: microhttpd.h:313
void * data
Definition: microhttpd.h:3053
#define MHD_CONTENT_READER_END_WITH_ERROR
Definition: microhttpd.h:176
MHD_ValueKind
Definition: microhttpd.h:1781
@ MHD_FOOTER_KIND
Definition: microhttpd.h:1822
@ MHD_COOKIE_KIND
Definition: microhttpd.h:1802
@ MHD_HEADER_KIND
Definition: microhttpd.h:1796
@ MHD_GET_ARGUMENT_KIND
Definition: microhttpd.h:1817
_MHD_EXTERN const char * MHD_get_reason_phrase_for(unsigned int code)
enum MHD_Result MHD_response_execute_upgrade_(struct MHD_Response *response, struct MHD_Connection *connection)
ActionCallback action
Definition: internal.h:1554
MHD_socket socket_fd
Definition: internal.h:752
char * last
Definition: internal.h:802
bool tls_read_ready
Definition: internal.h:769
bool suspended
Definition: internal.h:764
ReceiveCallback recv_cls
Definition: internal.h:706
char * colon
Definition: internal.h:811
struct MHD_Response * response
Definition: internal.h:730
bool sk_nonblck
Definition: internal.h:784
struct MHD_Request request
Definition: internal.h:717
time_t connection_timeout
Definition: internal.h:745
TransmitCallback send_cls
Definition: internal.h:711
struct MemoryPool * pool
Definition: internal.h:685
size_t read_buffer_offset
Definition: internal.h:839
bool read_closed
Definition: internal.h:792
time_t last_activity
Definition: internal.h:739
struct MHD_Daemon * daemon
Definition: internal.h:675
bool data_already_pending
Definition: internal.h:1500
MHD_EarlyUriLogCallback early_uri_logger_cb
Definition: internal.h:1036
MHD_mutex_ cleanup_connection_mutex
Definition: internal.h:1265
struct MHD_Connection * connections_head
Definition: internal.h:1155
void * early_uri_logger_cb_cls
Definition: internal.h:1041
struct MHD_itc_ itc
Definition: internal.h:1410
void * unescape_cb_cls
Definition: internal.h:1063
bool suppress_date
Definition: internal.h:1456
enum MHD_EventLoopSyscall event_loop_syscall
Definition: internal.h:1436
MHD_RequestCallback rc
Definition: internal.h:1005
struct MHD_Connection * manual_timeout_tail
Definition: internal.h:1150
size_t connection_memory_increment_b
Definition: internal.h:1296
void * rc_cls
Definition: internal.h:1010
struct MHD_Connection * cleanup_tail
Definition: internal.h:1182
enum MHD_ProtocolStrictLevel protocol_strict_level
Definition: internal.h:1442
time_t connection_default_timeout
Definition: internal.h:1371
struct MHD_Connection * manual_timeout_head
Definition: internal.h:1143
struct MHD_Connection * suspended_connections_tail
Definition: internal.h:1172
struct MHD_Connection * cleanup_head
Definition: internal.h:1177
struct MHD_Connection * normal_timeout_head
Definition: internal.h:1128
size_t connection_memory_limit_b
Definition: internal.h:1281
struct MHD_Connection * normal_timeout_tail
Definition: internal.h:1135
enum MHD_ThreadingMode threading_mode
Definition: internal.h:1417
MHD_UnescapeCallback unescape_cb
Definition: internal.h:1058
struct MHD_Connection * suspended_connections_head
Definition: internal.h:1166
struct MHD_Connection * connections_tail
Definition: internal.h:1160
char * header
Definition: internal.h:347
enum MHD_ValueKind kind
Definition: internal.h:358
struct MHD_HTTP_Header * next
Definition: internal.h:342
char * value
Definition: internal.h:352
size_t write_buffer_append_offset
Definition: internal.h:496
struct MHD_Response * response
Definition: internal.h:383
size_t read_buffer_size
Definition: internal.h:474
uint64_t current_chunk_size
Definition: internal.h:516
uint64_t current_chunk_offset
Definition: internal.h:522
struct MHD_HTTP_Header * headers_received
Definition: internal.h:388
size_t continue_message_write_offset
Definition: internal.h:544
void * client_context
Definition: internal.h:401
size_t write_buffer_size
Definition: internal.h:485
enum MHD_Method method
Definition: internal.h:554
const char * url
Definition: internal.h:413
char * read_buffer
Definition: internal.h:433
bool in_idle
Definition: internal.h:565
size_t write_buffer_send_offset
Definition: internal.h:490
size_t read_buffer_offset
Definition: internal.h:480
enum MHD_RequestEventLoopInfo event_loop_info
Definition: internal.h:559
uint64_t response_write_position
Definition: internal.h:529
char * colon
Definition: internal.h:456
struct MHD_Connection * connection
Definition: internal.h:377
char * write_buffer
Definition: internal.h:439
size_t header_size
Definition: internal.h:502
char * last
Definition: internal.h:447
struct MHD_Daemon * daemon
Definition: internal.h:372
bool in_cleanup
Definition: internal.h:571
char * version_s
Definition: internal.h:419
bool have_chunked_upload
Definition: internal.h:580
enum MHD_REQUEST_STATE state
Definition: internal.h:549
enum MHD_ConnKeepAlive keepalive
Definition: internal.h:426
uint64_t remaining_upload_size
Definition: internal.h:508
char * method_s
Definition: internal.h:407
void * termination_cb_cls
Definition: internal.h:1617
struct MHD_HTTP_Header * first_header
Definition: internal.h:1582
void * crc_cls
Definition: internal.h:1594
size_t data_buffer_size
Definition: internal.h:1664
bool v10_only
Definition: internal.h:1685
enum MHD_HTTP_StatusCode status_code
Definition: internal.h:1669
uint64_t data_start
Definition: internal.h:1648
MHD_ContentReaderCallback crc
Definition: internal.h:1600
MHD_RequestTerminationCallback termination_cb
Definition: internal.h:1612
size_t data_size
Definition: internal.h:1659
enum MHD_ResponseFlags flags
Definition: internal.h:446
char * data
Definition: internal.h:1588
MHD_mutex_ mutex
Definition: internal.h:1637
uint64_t total_size
Definition: internal.h:1642
uint64_t fd_off
Definition: internal.h:1653
enum MHD_Bool(* idle_ready)(void *cls, struct MHD_TLS_ConnectionState *cs)
enum MHD_Bool(* update_event_loop_info)(void *cls, struct MHD_TLS_ConnectionState *cs, enum MHD_RequestEventLoopInfo *eli)
enum MHD_Bool(* handshake)(void *cls, struct MHD_TLS_ConnectionState *cs)