GNU libmicrohttpd  0.9.66
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 "<html><head><title>Request too big</title></head><body>Your HTTP header was too big for the memory constraints of this webserver.</body></html>"
60 #else
61 #define REQUEST_TOO_BIG ""
62 #endif
63 
71 #ifdef HAVE_MESSAGES
72 #define REQUEST_LACKS_HOST "<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>"
73 #else
74 #define REQUEST_LACKS_HOST ""
75 #endif
76 
84 #ifdef HAVE_MESSAGES
85 #define REQUEST_MALFORMED "<html><head><title>Request malformed</title></head><body>Your HTTP request was syntactically incorrect.</body></html>"
86 #else
87 #define REQUEST_MALFORMED ""
88 #endif
89 
96 #ifdef HAVE_MESSAGES
97 #define INTERNAL_ERROR "<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>"
98 #else
99 #define INTERNAL_ERROR ""
100 #endif
101 
102 
103 #ifdef HAVE_FREEBSD_SENDFILE
104 #ifdef SF_FLAGS
105 
108 static int freebsd_sendfile_flags_;
109 
113 static int freebsd_sendfile_flags_thd_p_c_;
114 #endif /* SF_FLAGS */
115 
116 
122 void
123 MHD_conn_init_static_ (void)
124 {
125 /* FreeBSD 11 and later allow to specify read-ahead size
126  * and handles SF_NODISKIO differently.
127  * SF_FLAGS defined only on FreeBSD 11 and later. */
128 #ifdef SF_FLAGS
129  long sys_page_size = sysconf (_SC_PAGESIZE);
130  if (0 > sys_page_size)
131  { /* Failed to get page size. */
132  freebsd_sendfile_flags_ = SF_NODISKIO;
133  freebsd_sendfile_flags_thd_p_c_ = SF_NODISKIO;
134  }
135  else
136  {
137  freebsd_sendfile_flags_ =
138  SF_FLAGS((uint16_t)(MHD_SENFILE_CHUNK_ / sys_page_size), SF_NODISKIO);
139  freebsd_sendfile_flags_thd_p_c_ =
140  SF_FLAGS((uint16_t)(MHD_SENFILE_CHUNK_THR_P_C_ / sys_page_size), SF_NODISKIO);
141  }
142 #endif /* SF_FLAGS */
143 }
144 #endif /* HAVE_FREEBSD_SENDFILE */
145 
146 
147 
151 #define HTTP_100_CONTINUE "HTTP/1.1 100 Continue\r\n\r\n"
152 
153 
162 static void
164  enum MHD_StatusCode sc,
165  const char *emsg)
166 {
167 #ifdef HAVE_MESSAGES
168  if (NULL != emsg)
169  MHD_DLOG (connection->daemon,
170  sc,
171  emsg);
172 #else /* ! HAVE_MESSAGES */
173  (void) emsg; /* Mute compiler warning. */
174  (void) sc;
175 #endif /* ! HAVE_MESSAGES */
176  MHD_connection_close_ (connection,
178 }
179 
180 
185 #ifdef HAVE_MESSAGES
186 #define CONNECTION_CLOSE_ERROR(c, sc, emsg) connection_close_error (c, sc, emsg)
187 #else
188 #define CONNECTION_CLOSE_ERROR(c, sc, emsg) connection_close_error (c, sc, NULL)
189 #endif
190 
191 
202 static bool
204 {
205  struct MHD_Daemon *daemon = request->daemon;
206  void *buf;
207  size_t new_size;
208 
209  if (0 == request->read_buffer_size)
210  new_size = daemon->connection_memory_limit_b / 2;
211  else
212  new_size = request->read_buffer_size +
214  buf = MHD_pool_reallocate (request->connection->pool,
215  request->read_buffer,
216  request->read_buffer_size,
217  new_size);
218  if (NULL == buf)
219  return false;
220  /* we can actually grow the buffer, do it! */
221  request->read_buffer = buf;
222  request->read_buffer_size = new_size;
223  return true;
224 }
225 
226 
233 static void
235 {
236  struct MHD_Daemon *daemon = request->daemon;
237  struct MHD_Connection *connection = request->connection;
238  ssize_t bytes_read;
239 
240  if ( (MHD_REQUEST_CLOSED == request->state) ||
241  (connection->suspended) )
242  return;
243 #ifdef HTTPS_SUPPORT
244  {
245  struct MHD_TLS_Plugin *tls;
246 
247  if ( (NULL != (tls = daemon->tls_api)) &&
248  (! tls->handshake (tls->cls,
249  connection->tls_cs)) )
250  return;
251  }
252 #endif /* HTTPS_SUPPORT */
253 
254  /* make sure "read" has a reasonable number of bytes
255  in buffer to use per system call (if possible) */
256  if (request->read_buffer_offset +
258  request->read_buffer_size)
259  try_grow_read_buffer (request);
260 
261  if (request->read_buffer_size == request->read_buffer_offset)
262  return; /* No space for receiving data. */
263  bytes_read = connection->recv_cls (connection,
264  &request->read_buffer
265  [request->read_buffer_offset],
266  request->read_buffer_size -
267  request->read_buffer_offset);
268  if (bytes_read < 0)
269  {
270  if (MHD_ERR_AGAIN_ == bytes_read)
271  return; /* No new data to process. */
272  if (MHD_ERR_CONNRESET_ == bytes_read)
273  {
274  CONNECTION_CLOSE_ERROR (connection,
275  (MHD_REQUEST_INIT == request->state)
276  ? MHD_SC_CONNECTION_CLOSED
277  : MHD_SC_CONNECTION_RESET_CLOSED,
278  (MHD_REQUEST_INIT == request->state)
279  ? NULL
280  : _("Socket disconnected while reading request.\n"));
281  return;
282  }
283  CONNECTION_CLOSE_ERROR (connection,
284  (MHD_REQUEST_INIT == request->state)
285  ? MHD_SC_CONNECTION_CLOSED
286  : MHD_SC_CONNECTION_READ_FAIL_CLOSED,
287  (MHD_REQUEST_INIT == request->state)
288  ? NULL
289  : _("Connection socket is closed due to error when reading request.\n"));
290  return;
291  }
292 
293  if (0 == bytes_read)
294  { /* Remote side closed connection. */
295  connection->read_closed = true;
296  MHD_connection_close_ (connection,
298  return;
299  }
300  request->read_buffer_offset += bytes_read;
302 #if DEBUG_STATES
303  MHD_DLOG (daemon,
304  MHD_SC_STATE_MACHINE_STATUS_REPORT,
305  _("In function %s handling connection at state: %s\n"),
306  __FUNCTION__,
307  MHD_state_to_string (request->state));
308 #endif
309  switch (request->state)
310  {
311  case MHD_REQUEST_INIT:
320  /* nothing to do but default action */
321  if (connection->read_closed)
322  {
323  MHD_connection_close_ (connection,
325  }
326  return;
327  case MHD_REQUEST_CLOSED:
328  return;
329 #ifdef UPGRADE_SUPPORT
330  case MHD_REQUEST_UPGRADE:
331  mhd_assert (0);
332  return;
333 #endif /* UPGRADE_SUPPORT */
334  default:
335  /* shrink read buffer to how much is actually used */
336  MHD_pool_reallocate (connection->pool,
337  request->read_buffer,
338  request->read_buffer_size + 1,
339  request->read_buffer_offset);
340  break;
341  }
342  return;
343 }
344 
345 
346 #if defined(_MHD_HAVE_SENDFILE)
347 
353 static ssize_t
354 sendfile_adapter (struct MHD_Connection *connection)
355 {
356  struct MHD_Daemon *daemon = connection->daemon;
357  struct MHD_Request *request = &connection->request;
358  struct MHD_Response *response = request->response;
359  ssize_t ret;
360  const int file_fd = response->fd;
361  uint64_t left;
362  uint64_t offsetu64;
363 #ifndef HAVE_SENDFILE64
364  const uint64_t max_off_t = (uint64_t)OFF_T_MAX;
365 #else /* HAVE_SENDFILE64 */
366  const uint64_t max_off_t = (uint64_t)OFF64_T_MAX;
367 #endif /* HAVE_SENDFILE64 */
368 #ifdef MHD_LINUX_SOLARIS_SENDFILE
369 #ifndef HAVE_SENDFILE64
370  off_t offset;
371 #else /* HAVE_SENDFILE64 */
372  off64_t offset;
373 #endif /* HAVE_SENDFILE64 */
374 #endif /* MHD_LINUX_SOLARIS_SENDFILE */
375 #ifdef HAVE_FREEBSD_SENDFILE
376  off_t sent_bytes;
377  int flags = 0;
378 #endif
379 #ifdef HAVE_DARWIN_SENDFILE
380  off_t len;
381 #endif /* HAVE_DARWIN_SENDFILE */
382  const bool used_thr_p_c = (MHD_TM_THREAD_PER_CONNECTION == daemon->threading_mode);
383  const size_t chunk_size = used_thr_p_c ? MHD_SENFILE_CHUNK_THR_P_C_ : MHD_SENFILE_CHUNK_;
384  size_t send_size = 0;
385 
386  mhd_assert (MHD_resp_sender_sendfile == request->resp_sender);
387  offsetu64 = request->response_write_position + response->fd_off;
388  left = response->total_size - request->response_write_position;
389  /* Do not allow system to stick sending on single fast connection:
390  * use 128KiB chunks (2MiB for thread-per-connection). */
391  send_size = (left > chunk_size) ? chunk_size : (size_t) left;
392  if (max_off_t < offsetu64)
393  { /* Retry to send with standard 'send()'. */
394  request->resp_sender = MHD_resp_sender_std;
395  return MHD_ERR_AGAIN_;
396  }
397 #ifdef MHD_LINUX_SOLARIS_SENDFILE
398 #ifndef HAVE_SENDFILE64
399  offset = (off_t) offsetu64;
400  ret = sendfile (connection->socket_fd,
401  file_fd,
402  &offset,
403  send_size);
404 #else /* HAVE_SENDFILE64 */
405  offset = (off64_t) offsetu64;
406  ret = sendfile64 (connection->socket_fd,
407  file_fd,
408  &offset,
409  send_size);
410 #endif /* HAVE_SENDFILE64 */
411  if (0 > ret)
412  {
413  const int err = MHD_socket_get_error_();
414 
415  if (MHD_SCKT_ERR_IS_EAGAIN_(err))
416  {
417 #ifdef EPOLL_SUPPORT
418  /* EAGAIN --- no longer write-ready */
419  connection->epoll_state &= ~MHD_EPOLL_STATE_WRITE_READY;
420 #endif /* EPOLL_SUPPORT */
421  return MHD_ERR_AGAIN_;
422  }
423  if (MHD_SCKT_ERR_IS_EINTR_ (err))
424  return MHD_ERR_AGAIN_;
425 #ifdef HAVE_LINUX_SENDFILE
426  if (MHD_SCKT_ERR_IS_(err,
428  return MHD_ERR_BADF_;
429  /* sendfile() failed with EINVAL if mmap()-like operations are not
430  supported for FD or other 'unusual' errors occurred, so we should try
431  to fall back to 'SEND'; see also this thread for info on
432  odd libc/Linux behavior with sendfile:
433  http://lists.gnu.org/archive/html/libmicrohttpd/2011-02/msg00015.html */
434  request->resp_sender = MHD_resp_sender_std;
435  return MHD_ERR_AGAIN_;
436 #else /* HAVE_SOLARIS_SENDFILE */
437  if ( (EAFNOSUPPORT == err) ||
438  (EINVAL == err) ||
439  (EOPNOTSUPP == err) )
440  { /* Retry with standard file reader. */
441  request->resp_sender = MHD_resp_sender_std;
442  return MHD_ERR_AGAIN_;
443  }
444  if ( (ENOTCONN == err) ||
445  (EPIPE == err) )
446  {
447  return MHD_ERR_CONNRESET_;
448  }
449  return MHD_ERR_BADF_; /* Fail hard */
450 #endif /* HAVE_SOLARIS_SENDFILE */
451  }
452 #ifdef EPOLL_SUPPORT
453  else if (send_size > (size_t)ret)
454  connection->epoll_state &= ~MHD_EPOLL_STATE_WRITE_READY;
455 #endif /* EPOLL_SUPPORT */
456 #elif defined(HAVE_FREEBSD_SENDFILE)
457 #ifdef SF_FLAGS
458  flags = used_thr_p_c ?
459  freebsd_sendfile_flags_thd_p_c_ : freebsd_sendfile_flags_;
460 #endif /* SF_FLAGS */
461  if (0 != sendfile (file_fd,
462  connection->socket_fd,
463  (off_t) offsetu64,
464  send_size,
465  NULL,
466  &sent_bytes,
467  flags))
468  {
469  const int err = MHD_socket_get_error_();
470  if (MHD_SCKT_ERR_IS_EAGAIN_(err) ||
471  MHD_SCKT_ERR_IS_EINTR_(err) ||
472  EBUSY == err)
473  {
474  mhd_assert (SSIZE_MAX >= sent_bytes);
475  if (0 != sent_bytes)
476  return (ssize_t)sent_bytes;
477 
478  return MHD_ERR_AGAIN_;
479  }
480  /* Some unrecoverable error. Possibly file FD is not suitable
481  * for sendfile(). Retry with standard send(). */
482  request->resp_sender = MHD_resp_sender_std;
483  return MHD_ERR_AGAIN_;
484  }
485  mhd_assert (0 < sent_bytes);
486  mhd_assert (SSIZE_MAX >= sent_bytes);
487  ret = (ssize_t)sent_bytes;
488 #elif defined(HAVE_DARWIN_SENDFILE)
489  len = (off_t) send_size; /* chunk always fit */
490  if (0 != sendfile (file_fd,
491  connection->socket_fd,
492  (off_t) offsetu64,
493  &len,
494  NULL,
495  0))
496  {
497  const int err = MHD_socket_get_error_();
498  if (MHD_SCKT_ERR_IS_EAGAIN_(err) ||
500  {
501  mhd_assert (0 <= len);
502  mhd_assert (SSIZE_MAX >= len);
503  mhd_assert (send_size >= (size_t)len);
504  if (0 != len)
505  return (ssize_t)len;
506 
507  return MHD_ERR_AGAIN_;
508  }
509  if (ENOTCONN == err ||
510  EPIPE == err)
511  return MHD_ERR_CONNRESET_;
512  if (ENOTSUP == err ||
513  EOPNOTSUPP == err)
514  { /* This file FD is not suitable for sendfile().
515  * Retry with standard send(). */
516  request->resp_sender = MHD_resp_sender_std;
517  return MHD_ERR_AGAIN_;
518  }
519  return MHD_ERR_BADF_; /* Return hard error. */
520  }
521  mhd_assert (0 <= len);
522  mhd_assert (SSIZE_MAX >= len);
523  mhd_assert (send_size >= (size_t)len);
524  ret = (ssize_t)len;
525 #endif /* HAVE_FREEBSD_SENDFILE */
526  return ret;
527 }
528 #endif /* _MHD_HAVE_SENDFILE */
529 
530 
539 static bool
540 check_write_done (struct MHD_Request *request,
541  enum MHD_REQUEST_STATE next_state)
542 {
543  if (request->write_buffer_append_offset !=
544  request->write_buffer_send_offset)
545  return false;
546  request->write_buffer_append_offset = 0;
547  request->write_buffer_send_offset = 0;
548  request->state = next_state;
550  request->write_buffer,
551  request->write_buffer_size,
552  0);
553  request->write_buffer = NULL;
554  request->write_buffer_size = 0;
555  return true;
556 }
557 
558 
569 static bool
571 {
572  struct MHD_Response *response = request->response;
573  struct MHD_Connection *connection = request->connection;
574  ssize_t ret;
575 
576  if (NULL == response->crc)
577  return true;
578  if ( (0 == response->total_size) ||
580  return true; /* 0-byte response is always ready */
581  if ( (response->data_start <=
585  return true; /* response already ready */
586 #if defined(_MHD_HAVE_SENDFILE)
587  if (MHD_resp_sender_sendfile == request->resp_sender)
588  {
589  /* will use sendfile, no need to bother response crc */
590  return true;
591  }
592 #endif /* _MHD_HAVE_SENDFILE */
593 
594  ret = response->crc (response->crc_cls,
596  response->data,
597  (size_t) MHD_MIN ((uint64_t) response->data_buffer_size,
600  if ( (((ssize_t) MHD_CONTENT_READER_END_OF_STREAM) == ret) ||
601  (((ssize_t) MHD_CONTENT_READER_END_WITH_ERROR) == ret) )
602  {
603  /* either error or http 1.0 transfer, close socket! */
606  if ( ((ssize_t)MHD_CONTENT_READER_END_OF_STREAM) == ret)
607  MHD_connection_close_ (connection,
609  else
610  CONNECTION_CLOSE_ERROR (connection,
611  MHD_SC_APPLICATION_DATA_GENERATION_FAILURE_CLOSED,
612  _("Closing connection (application reported error generating data)\n"));
613  return false;
614  }
616  response->data_size = ret;
617  if (0 == ret)
618  {
621  return false;
622  }
623  return true;
624 }
625 
626 
635 static bool
637 {
638  struct MHD_Connection *connection = request->connection;
639  struct MHD_Response *response = request->response;
640  struct MHD_Daemon *daemon = request->daemon;
641  ssize_t ret;
642  char *buf;
643  size_t size;
644  char cbuf[10]; /* 10: max strlen of "%x\r\n" */
645  int cblen;
646 
647  if (NULL == response->crc)
648  return true;
649  if (0 == request->write_buffer_size)
650  {
651  size = MHD_MIN (daemon->connection_memory_limit_b,
652  2 * (0xFFFFFF + sizeof(cbuf) + 2));
653  do
654  {
655  size /= 2;
656  if (size < 128)
657  {
658  MHD_mutex_unlock_chk_ (&response->mutex);
659  /* not enough memory */
660  CONNECTION_CLOSE_ERROR (connection,
661  MHD_SC_CONNECTION_POOL_MALLOC_FAILURE,
662  _("Closing connection (out of memory)\n"));
663  return false;
664  }
665  buf = MHD_pool_allocate (connection->pool,
666  size,
667  MHD_NO);
668  }
669  while (NULL == buf);
670  request->write_buffer_size = size;
671  request->write_buffer = buf;
672  }
673 
674  if (0 == response->total_size)
675  ret = 0; /* response must be empty, don't bother calling crc */
676  else if ( (response->data_start <=
677  request->response_write_position) &&
678  (response->data_start + response->data_size >
679  request->response_write_position) )
680  {
681  /* difference between response_write_position and data_start is less
682  than data_size which is size_t type, no need to check for overflow */
683  const size_t data_write_offset
684  = (size_t)(request->response_write_position - response->data_start);
685  /* buffer already ready, use what is there for the chunk */
686  ret = response->data_size - data_write_offset;
687  if ( ((size_t) ret) > request->write_buffer_size - sizeof (cbuf) - 2 )
688  ret = request->write_buffer_size - sizeof (cbuf) - 2;
689  memcpy (&request->write_buffer[sizeof (cbuf)],
690  &response->data[data_write_offset],
691  ret);
692  }
693  else
694  {
695  /* buffer not in range, try to fill it */
696  ret = response->crc (response->crc_cls,
697  request->response_write_position,
698  &request->write_buffer[sizeof (cbuf)],
699  request->write_buffer_size - sizeof (cbuf) - 2);
700  }
701  if ( ((ssize_t) MHD_CONTENT_READER_END_WITH_ERROR) == ret)
702  {
703  /* error, close socket! */
704  response->total_size = request->response_write_position;
705  MHD_mutex_unlock_chk_ (&response->mutex);
706  CONNECTION_CLOSE_ERROR (connection,
707  MHD_SC_APPLICATION_DATA_GENERATION_FAILURE_CLOSED,
708  _("Closing connection (application error generating response)\n"));
709  return false;
710  }
711  if ( (((ssize_t) MHD_CONTENT_READER_END_OF_STREAM) == ret) ||
712  (0 == response->total_size) )
713  {
714  /* end of message, signal other side! */
715  memcpy (request->write_buffer,
716  "0\r\n",
717  3);
718  request->write_buffer_append_offset = 3;
719  request->write_buffer_send_offset = 0;
720  response->total_size = request->response_write_position;
721  return true;
722  }
723  if (0 == ret)
724  {
726  MHD_mutex_unlock_chk_ (&response->mutex);
727  return false;
728  }
729  if (ret > 0xFFFFFF)
730  ret = 0xFFFFFF;
731  cblen = MHD_snprintf_(cbuf,
732  sizeof (cbuf),
733  "%X\r\n",
734  (unsigned int) ret);
735  mhd_assert(cblen > 0);
736  mhd_assert((size_t)cblen < sizeof(cbuf));
737  memcpy (&request->write_buffer[sizeof (cbuf) - cblen],
738  cbuf,
739  cblen);
740  memcpy (&request->write_buffer[sizeof (cbuf) + ret],
741  "\r\n",
742  2);
743  request->response_write_position += ret;
744  request->write_buffer_send_offset = sizeof (cbuf) - cblen;
745  request->write_buffer_append_offset = sizeof (cbuf) + ret + 2;
746  return true;
747 }
748 
749 
756 static void
758 {
759  struct MHD_Daemon *daemon = request->daemon;
760  struct MHD_Connection *connection = request->connection;
761  struct MHD_Response *response;
762  ssize_t ret;
763 
764  if (connection->suspended)
765  return;
766 #ifdef HTTPS_SUPPORT
767  {
768  struct MHD_TLS_Plugin *tls;
769 
770  if ( (NULL != (tls = daemon->tls_api)) &&
771  (! tls->handshake (tls->cls,
772  connection->tls_cs)) )
773  return;
774  }
775 #endif /* HTTPS_SUPPORT */
776 
777 #if DEBUG_STATES
778  MHD_DLOG (daemon,
779  MHD_SC_STATE_MACHINE_STATUS_REPORT,
780  _("In function %s handling connection at state: %s\n"),
781  __FUNCTION__,
782  MHD_state_to_string (request->state));
783 #endif
784  switch (request->state)
785  {
786  case MHD_REQUEST_INIT:
790  mhd_assert (0);
791  return;
793  return;
795  ret = connection->send_cls (connection,
800  if (ret < 0)
801  {
802  if (MHD_ERR_AGAIN_ == ret)
803  return;
804 #ifdef HAVE_MESSAGES
805  MHD_DLOG (daemon,
806  MHD_SC_CONNECTION_WRITE_FAIL_CLOSED,
807  _("Failed to send data in request for %s.\n"),
808  request->url);
809 #endif
810  CONNECTION_CLOSE_ERROR (connection,
811  MHD_SC_CONNECTION_WRITE_FAIL_CLOSED,
812  NULL);
813  return;
814  }
815  request->continue_message_write_offset += ret;
817  return;
822  mhd_assert (0);
823  return;
825  ret = connection->send_cls (connection,
826  &request->write_buffer
827  [request->write_buffer_send_offset],
828  request->write_buffer_append_offset -
829  request->write_buffer_send_offset);
830  if (ret < 0)
831  {
832  if (MHD_ERR_AGAIN_ == ret)
833  return;
834  CONNECTION_CLOSE_ERROR (connection,
835  MHD_SC_CONNECTION_WRITE_FAIL_CLOSED,
836  _("Connection was closed while sending response headers.\n"));
837  return;
838  }
839  request->write_buffer_send_offset += ret;
841  if (MHD_REQUEST_HEADERS_SENDING != request->state)
842  return;
843  check_write_done (request,
845  return;
847  return;
849  response = request->response;
850  if (request->response_write_position <
851  request->response->total_size)
852  {
853  uint64_t data_write_offset;
854 
855  if (NULL != response->crc)
856  MHD_mutex_lock_chk_ (&response->mutex);
857  if (! try_ready_normal_body (request))
858  {
859  /* mutex was already unlocked by try_ready_normal_body */
860  return;
861  }
862 #if defined(_MHD_HAVE_SENDFILE)
863  if (MHD_resp_sender_sendfile == request->resp_sender)
864  {
865  ret = sendfile_adapter (connection);
866  }
867  else
868 #else /* ! _MHD_HAVE_SENDFILE */
869  if (1)
870 #endif /* ! _MHD_HAVE_SENDFILE */
871  {
872  data_write_offset = request->response_write_position
873  - response->data_start;
874  if (data_write_offset > (uint64_t)SIZE_MAX)
875  MHD_PANIC (_("Data offset exceeds limit"));
876  ret = connection->send_cls (connection,
877  &response->data
878  [(size_t)data_write_offset],
879  response->data_size -
880  (size_t)data_write_offset);
881 #if DEBUG_SEND_DATA
882  if (ret > 0)
883  fprintf (stderr,
884  _("Sent %d-byte DATA response: `%.*s'\n"),
885  (int) ret,
886  (int) ret,
887  &response->data[request->response_write_position -
888  response->data_start]);
889 #endif
890  }
891  if (NULL != response->crc)
892  MHD_mutex_unlock_chk_ (&response->mutex);
893  if (ret < 0)
894  {
895  if (MHD_ERR_AGAIN_ == ret)
896  return;
897 #ifdef HAVE_MESSAGES
898  MHD_DLOG (daemon,
899  MHD_SC_CONNECTION_WRITE_FAIL_CLOSED,
900  _("Failed to send data in request for `%s'.\n"),
901  request->url);
902 #endif
903  CONNECTION_CLOSE_ERROR (connection,
904  MHD_SC_CONNECTION_WRITE_FAIL_CLOSED,
905  NULL);
906  return;
907  }
908  request->response_write_position += ret;
910  }
911  if (request->response_write_position ==
912  request->response->total_size)
913  request->state = MHD_REQUEST_FOOTERS_SENT; /* have no footers */
914  return;
916  mhd_assert (0);
917  return;
919  ret = connection->send_cls (connection,
920  &request->write_buffer
921  [request->write_buffer_send_offset],
922  request->write_buffer_append_offset -
923  request->write_buffer_send_offset);
924  if (ret < 0)
925  {
926  if (MHD_ERR_AGAIN_ == ret)
927  return;
928  CONNECTION_CLOSE_ERROR (connection,
929  MHD_SC_CONNECTION_WRITE_FAIL_CLOSED,
930  _("Connection was closed while sending response body.\n"));
931  return;
932  }
933  request->write_buffer_send_offset += ret;
935  if (MHD_REQUEST_CHUNKED_BODY_READY != request->state)
936  return;
937  check_write_done (request,
938  (request->response->total_size ==
939  request->response_write_position) ?
942  return;
945  mhd_assert (0);
946  return;
948  ret = connection->send_cls (connection,
949  &request->write_buffer
950  [request->write_buffer_send_offset],
951  request->write_buffer_append_offset -
952  request->write_buffer_send_offset);
953  if (ret < 0)
954  {
955  if (MHD_ERR_AGAIN_ == ret)
956  return;
957  CONNECTION_CLOSE_ERROR (connection,
958  MHD_SC_CONNECTION_WRITE_FAIL_CLOSED,
959  _("Connection was closed while sending response body.\n"));
960  return;
961  }
962  request->write_buffer_send_offset += ret;
964  if (MHD_REQUEST_FOOTERS_SENDING != request->state)
965  return;
966  check_write_done (request,
968  return;
970  mhd_assert (0);
971  return;
972  case MHD_REQUEST_CLOSED:
973  return;
974 #ifdef UPGRADE_SUPPORT
975  case MHD_REQUEST_UPGRADE:
976  mhd_assert (0);
977  return;
978 #endif /* UPGRADE_SUPPORT */
979  default:
980  mhd_assert (0);
981  CONNECTION_CLOSE_ERROR (connection,
982  MHD_SC_STATEMACHINE_FAILURE_CONNECTION_CLOSED,
983  _("Internal error\n"));
984  break;
985  }
986 }
987 
988 
1002 static bool
1004  const char *header,
1005  const char *token,
1006  size_t token_len)
1007 {
1008  struct MHD_HTTP_Header *pos;
1009 
1010  if ( (NULL == request) || /* FIXME: require non-null? */
1011  (NULL == header) || /* FIXME: require non-null? */
1012  (0 == header[0]) ||
1013  (NULL == token) ||
1014  (0 == token[0]) )
1015  return false;
1016  for (pos = request->headers_received; NULL != pos; pos = pos->next)
1017  {
1018  if ( (0 != (pos->kind & MHD_HEADER_KIND)) &&
1019  ( (header == pos->header) ||
1021  pos->header)) ) &&
1023  token,
1024  token_len)) )
1025  return true;
1026  }
1027  return false;
1028 }
1029 
1030 
1042 #define MHD_lookup_header_s_token_ci(r,h,tkn) \
1043  MHD_lookup_header_token_ci((r),(h),(tkn),MHD_STATICSTR_LEN_(tkn))
1044 
1045 
1062 static bool
1064 {
1065  if (MHD_CONN_MUST_CLOSE == request->keepalive)
1066  return false;
1067  if (NULL == request->version_s)
1068  return false;
1069  if ( (NULL != request->response) &&
1070  (request->response->v10_only) )
1071  return false;
1072 
1073  if (MHD_str_equal_caseless_ (request->version_s,
1075  {
1076  if (MHD_lookup_header_s_token_ci (request,
1078  "upgrade"))
1079  return false;
1080  if (MHD_lookup_header_s_token_ci (request,
1082  "close"))
1083  return false;
1084  return true;
1085  }
1086  if (MHD_str_equal_caseless_ (request->version_s,
1088  {
1089  if (MHD_lookup_header_s_token_ci (request,
1091  "Keep-Alive"))
1092  return true;
1093  return false;
1094  }
1095  return false;
1096 }
1097 
1098 
1106 static void
1107 get_date_string (char *date,
1108  size_t date_len)
1109 {
1110  static const char *const days[] = {
1111  "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
1112  };
1113  static const char *const mons[] = {
1114  "Jan", "Feb", "Mar", "Apr", "May", "Jun",
1115  "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
1116  };
1117  struct tm now;
1118  time_t t;
1119 #if !defined(HAVE_C11_GMTIME_S) && !defined(HAVE_W32_GMTIME_S) && !defined(HAVE_GMTIME_R)
1120  struct tm* pNow;
1121 #endif
1122 
1123  date[0] = 0;
1124  time (&t);
1125 #if defined(HAVE_C11_GMTIME_S)
1126  if (NULL == gmtime_s (&t,
1127  &now))
1128  return;
1129 #elif defined(HAVE_W32_GMTIME_S)
1130  if (0 != gmtime_s (&now,
1131  &t))
1132  return;
1133 #elif defined(HAVE_GMTIME_R)
1134  if (NULL == gmtime_r(&t,
1135  &now))
1136  return;
1137 #else
1138  pNow = gmtime(&t);
1139  if (NULL == pNow)
1140  return;
1141  now = *pNow;
1142 #endif
1143  MHD_snprintf_ (date,
1144  date_len,
1145  "Date: %3s, %02u %3s %04u %02u:%02u:%02u GMT\r\n",
1146  days[now.tm_wday % 7],
1147  (unsigned int) now.tm_mday,
1148  mons[now.tm_mon % 12],
1149  (unsigned int) (1900 + now.tm_year),
1150  (unsigned int) now.tm_hour,
1151  (unsigned int) now.tm_min,
1152  (unsigned int) now.tm_sec);
1153 }
1154 
1155 
1169 static bool
1171  const char *key,
1172  const char *token,
1173  size_t token_len)
1174 {
1175  struct MHD_HTTP_Header *pos;
1176 
1177  if ( (NULL == key) ||
1178  ('\0' == key[0]) ||
1179  (NULL == token) ||
1180  ('\0' == token[0]) )
1181  return false;
1182 
1183  for (pos = response->first_header;
1184  NULL != pos;
1185  pos = pos->next)
1186  {
1187  if ( (pos->kind == MHD_HEADER_KIND) &&
1189  key) &&
1191  token,
1192  token_len) )
1193  return true;
1194  }
1195  return false;
1196 }
1197 
1198 
1210 #define check_response_header_s_token_ci(r,k,tkn) \
1211  check_response_header_token_ci((r),(k),(tkn),MHD_STATICSTR_LEN_(tkn))
1212 
1213 
1223 static bool
1225 {
1226  struct MHD_Connection *connection = request->connection;
1227  struct MHD_Daemon *daemon = request->daemon;
1228  struct MHD_Response *response = request->response;
1229  size_t size;
1230  size_t off;
1231  struct MHD_HTTP_Header *pos;
1232  char code[256];
1233  char date[128];
1234  size_t datelen;
1235  char content_length_buf[128];
1236  size_t content_length_len;
1237  char *data;
1238  enum MHD_ValueKind kind;
1239  bool client_requested_close;
1240  bool response_has_close;
1241  bool response_has_keepalive;
1242  const char *have_encoding;
1243  const char *have_content_length;
1244  bool must_add_close;
1245  bool must_add_chunked_encoding;
1246  bool must_add_keep_alive;
1247  bool must_add_content_length;
1248 
1249  mhd_assert (NULL != request->version_s);
1250  if (0 == request->version_s[0])
1251  {
1252  data = MHD_pool_allocate (connection->pool,
1253  0,
1254  MHD_YES);
1255  request->write_buffer = data;
1256  request->write_buffer_append_offset = 0;
1257  request->write_buffer_send_offset = 0;
1258  request->write_buffer_size = 0;
1259  return true;
1260  }
1261  if (MHD_REQUEST_FOOTERS_RECEIVED == request->state)
1262  {
1263  const char *reason_phrase;
1264  const char *version;
1265 
1266  reason_phrase
1267  = MHD_get_reason_phrase_for (response->status_code);
1268  version
1269  = (response->icy)
1270  ? "ICY"
1272  request->version_s))
1275  MHD_snprintf_ (code,
1276  sizeof (code),
1277  "%s %u %s\r\n",
1278  version,
1279  response->status_code,
1280  reason_phrase);
1281  off = strlen (code);
1282  /* estimate size */
1283  size = off + 2; /* +2 for extra "\r\n" at the end */
1285  if ( (! daemon->suppress_date) &&
1286  (NULL == MHD_response_get_header (response,
1288  get_date_string (date,
1289  sizeof (date));
1290  else
1291  date[0] = '\0';
1292  datelen = strlen (date);
1293  size += datelen;
1294  }
1295  else
1296  {
1297  /* 2 bytes for final CRLF of a Chunked-Body */
1298  size = 2;
1300  off = 0;
1301  datelen = 0;
1302  }
1303 
1304  /* calculate extra headers we need to add, such as 'Connection: close',
1305  first see what was explicitly requested by the application */
1306  must_add_close = false;
1307  must_add_chunked_encoding = false;
1308  must_add_keep_alive = false;
1309  must_add_content_length = false;
1310  response_has_close = false;
1311  switch (request->state)
1312  {
1314  response_has_close
1317  "close");
1318  response_has_keepalive
1321  "Keep-Alive");
1322  client_requested_close
1323  = MHD_lookup_header_s_token_ci (request,
1325  "close");
1326 
1327  if (response->v10_only)
1328  request->keepalive = MHD_CONN_MUST_CLOSE;
1329 #ifdef UPGRADE_SUPPORT
1330  else if (NULL != response->upgrade_handler)
1331  /* If this connection will not be "upgraded", it must be closed. */
1332  request->keepalive = MHD_CONN_MUST_CLOSE;
1333 #endif /* UPGRADE_SUPPORT */
1334 
1335  /* now analyze chunked encoding situation */
1336  request->have_chunked_upload = false;
1337 
1338  if ( (MHD_SIZE_UNKNOWN == response->total_size) &&
1339 #ifdef UPGRADE_SUPPORT
1340  (NULL == response->upgrade_handler) &&
1341 #endif /* UPGRADE_SUPPORT */
1342  (! response_has_close) &&
1343  (! client_requested_close) )
1344  {
1345  /* size is unknown, and close was not explicitly requested;
1346  need to either to HTTP 1.1 chunked encoding or
1347  close the connection */
1348  /* 'close' header doesn't exist yet, see if we need to add one;
1349  if the client asked for a close, no need to start chunk'ing */
1350  if ( (keepalive_possible (request)) &&
1352  request->version_s)) )
1353  {
1354  have_encoding
1355  = MHD_response_get_header (response,
1357  if (NULL == have_encoding)
1358  {
1359  must_add_chunked_encoding = true;
1360  request->have_chunked_upload = true;
1361  }
1362  else if (MHD_str_equal_caseless_ (have_encoding,
1363  "identity"))
1364  {
1365  /* application forced identity encoding, can't do 'chunked' */
1366  must_add_close = true;
1367  }
1368  else
1369  {
1370  request->have_chunked_upload = true;
1371  }
1372  }
1373  else
1374  {
1375  /* Keep alive or chunking not possible
1376  => set close header if not present */
1377  if (! response_has_close)
1378  must_add_close = true;
1379  }
1380  }
1381 
1382  /* check for other reasons to add 'close' header */
1383  if ( ( (client_requested_close) ||
1384  (connection->read_closed) ||
1385  (MHD_CONN_MUST_CLOSE == request->keepalive)) &&
1386  (! response_has_close) &&
1387 #ifdef UPGRADE_SUPPORT
1388  (NULL == response->upgrade_handler) &&
1389 #endif /* UPGRADE_SUPPORT */
1390  (! response->v10_only) )
1391  must_add_close = true;
1392 
1393  /* check if we should add a 'content length' header */
1394  have_content_length
1395  = MHD_response_get_header (response,
1397 
1398  /* MHD_HTTP_NO_CONTENT, MHD_HTTP_NOT_MODIFIED and 1xx-status
1399  codes SHOULD NOT have a Content-Length according to spec;
1400  also chunked encoding / unknown length or CONNECT... */
1401  if ( (MHD_SIZE_UNKNOWN != response->total_size) &&
1402  (MHD_HTTP_NO_CONTENT != response->status_code) &&
1403  (MHD_HTTP_NOT_MODIFIED != response->status_code) &&
1404  (MHD_HTTP_OK <= response->status_code) &&
1405  (NULL == have_content_length) &&
1406  (request->method != MHD_METHOD_CONNECT) )
1407  {
1408  /*
1409  Here we add a content-length if one is missing; however,
1410  for 'connect' methods, the responses MUST NOT include a
1411  content-length header *if* the response code is 2xx (in
1412  which case we expect there to be no body). Still,
1413  as we don't know the response code here in some cases, we
1414  simply only force adding a content-length header if this
1415  is not a 'connect' or if the response is not empty
1416  (which is kind of more sane, because if some crazy
1417  application did return content with a 2xx status code,
1418  then having a content-length might again be a good idea).
1419 
1420  Note that the change from 'SHOULD NOT' to 'MUST NOT' is
1421  a recent development of the HTTP 1.1 specification.
1422  */
1423  content_length_len
1424  = MHD_snprintf_ (content_length_buf,
1425  sizeof (content_length_buf),
1427  (MHD_UNSIGNED_LONG_LONG) response->total_size);
1428  must_add_content_length = true;
1429  }
1430 
1431  /* check for adding keep alive */
1432  if ( (! response_has_keepalive) &&
1433  (! response_has_close) &&
1434  (! must_add_close) &&
1435  (MHD_CONN_MUST_CLOSE != request->keepalive) &&
1436 #ifdef UPGRADE_SUPPORT
1437  (NULL == response->upgrade_handler) &&
1438 #endif /* UPGRADE_SUPPORT */
1439  (keepalive_possible (request)) )
1440  must_add_keep_alive = true;
1441  break;
1442  case MHD_REQUEST_BODY_SENT:
1443  response_has_keepalive = false;
1444  break;
1445  default:
1446  mhd_assert (0);
1447  return MHD_NO;
1448  }
1449 
1450  if (MHD_CONN_MUST_CLOSE != request->keepalive)
1451  {
1452  if ( (must_add_close) ||
1453  (response_has_close) )
1454  request->keepalive = MHD_CONN_MUST_CLOSE;
1455  else if ( (must_add_keep_alive) ||
1456  (response_has_keepalive) )
1457  request->keepalive = MHD_CONN_USE_KEEPALIVE;
1458  }
1459 
1460  if (must_add_close)
1461  size += MHD_STATICSTR_LEN_ ("Connection: close\r\n");
1462  if (must_add_keep_alive)
1463  size += MHD_STATICSTR_LEN_ ("Connection: Keep-Alive\r\n");
1464  if (must_add_chunked_encoding)
1465  size += MHD_STATICSTR_LEN_ ("Transfer-Encoding: chunked\r\n");
1466  if (must_add_content_length)
1467  size += content_length_len;
1468  mhd_assert (! (must_add_close && must_add_keep_alive) );
1469  mhd_assert (! (must_add_chunked_encoding && must_add_content_length) );
1470 
1471  for (pos = response->first_header; NULL != pos; pos = pos->next)
1472  {
1473  /* TODO: add proper support for excluding "Keep-Alive" token. */
1474  if ( (pos->kind == kind) &&
1475  (! ( (must_add_close) &&
1476  (response_has_keepalive) &&
1480  "Keep-Alive")) ) ) )
1481  size += strlen (pos->header) + strlen (pos->value) + 4; /* colon, space, linefeeds */
1482  }
1483  /* produce data */
1484  data = MHD_pool_allocate (connection->pool,
1485  size + 1,
1486  MHD_NO);
1487  if (NULL == data)
1488  {
1489 #ifdef HAVE_MESSAGES
1490  MHD_DLOG (daemon,
1491  MHD_SC_CONNECTION_POOL_MALLOC_FAILURE,
1492  "Not enough memory for write!\n");
1493 #endif
1494  return false;
1495  }
1496  if (MHD_REQUEST_FOOTERS_RECEIVED == request->state)
1497  {
1498  memcpy (data,
1499  code,
1500  off);
1501  }
1502  if (must_add_close)
1503  {
1504  /* we must add the 'Connection: close' header */
1505  memcpy (&data[off],
1506  "Connection: close\r\n",
1507  MHD_STATICSTR_LEN_ ("Connection: close\r\n"));
1508  off += MHD_STATICSTR_LEN_ ("Connection: close\r\n");
1509  }
1510  if (must_add_keep_alive)
1511  {
1512  /* we must add the 'Connection: Keep-Alive' header */
1513  memcpy (&data[off],
1514  "Connection: Keep-Alive\r\n",
1515  MHD_STATICSTR_LEN_ ("Connection: Keep-Alive\r\n"));
1516  off += MHD_STATICSTR_LEN_ ("Connection: Keep-Alive\r\n");
1517  }
1518  if (must_add_chunked_encoding)
1519  {
1520  /* we must add the 'Transfer-Encoding: chunked' header */
1521  memcpy (&data[off],
1522  "Transfer-Encoding: chunked\r\n",
1523  MHD_STATICSTR_LEN_ ("Transfer-Encoding: chunked\r\n"));
1524  off += MHD_STATICSTR_LEN_ ("Transfer-Encoding: chunked\r\n");
1525  }
1526  if (must_add_content_length)
1527  {
1528  /* we must add the 'Content-Length' header */
1529  memcpy (&data[off],
1530  content_length_buf,
1531  content_length_len);
1532  off += content_length_len;
1533  }
1534  for (pos = response->first_header; NULL != pos; pos = pos->next)
1535  {
1536  /* TODO: add proper support for excluding "Keep-Alive" token. */
1537  if ( (pos->kind == kind) &&
1538  (! ( (must_add_close) &&
1539  (response_has_keepalive) &&
1543  "Keep-Alive")) ) ) )
1544  off += MHD_snprintf_ (&data[off],
1545  size - off,
1546  "%s: %s\r\n",
1547  pos->header,
1548  pos->value);
1549  }
1550  if (MHD_REQUEST_FOOTERS_RECEIVED == request->state)
1551  {
1552  memcpy (&data[off],
1553  date,
1554  datelen);
1555  off += datelen;
1556  }
1557  memcpy (&data[off],
1558  "\r\n",
1559  2);
1560  off += 2;
1561 
1562  if (off != size)
1564  __FILE__,
1565  __LINE__,
1566  NULL);
1567  request->write_buffer = data;
1568  request->write_buffer_append_offset = size;
1569  request->write_buffer_send_offset = 0;
1570  request->write_buffer_size = size + 1;
1571  return true;
1572 }
1573 
1574 
1585 static void
1587  enum MHD_StatusCode ec,
1588  enum MHD_HTTP_StatusCode status_code,
1589  const char *message)
1590 {
1591  struct MHD_Response *response;
1592 
1593  if (NULL == request->version_s)
1594  {
1595  /* we were unable to process the full header line, so we don't
1596  really know what version the client speaks; assume 1.0 */
1597  request->version_s = MHD_HTTP_VERSION_1_0;
1598  }
1600  request->connection->read_closed = true;
1601 #ifdef HAVE_MESSAGES
1602  MHD_DLOG (request->daemon,
1603  ec,
1604  _("Error processing request (HTTP response code is %u (`%s')). Closing connection.\n"),
1605  status_code,
1606  message);
1607 #endif
1608  if (NULL != request->response)
1609  {
1611  request->response = NULL;
1612  }
1614  strlen (message),
1615  (void *) message,
1617  request->response = response;
1618  /* Do not reuse this connection. */
1619  request->keepalive = MHD_CONN_MUST_CLOSE;
1620  if (! build_header_response (request))
1621  {
1622  /* oops - close! */
1624  ec,
1625  _("Closing connection (failed to create response header)\n"));
1626  }
1627  else
1628  {
1630  }
1631 }
1632 
1633 
1640 static enum MHD_Method
1641 method_string_to_enum (const char *method)
1642 {
1643  static const struct {
1644  const char *key;
1645  enum MHD_Method value;
1646  } methods[] = {
1647  { "OPTIONS", MHD_METHOD_OPTIONS },
1648  { "GET", MHD_METHOD_GET },
1649  { "HEAD", MHD_METHOD_HEAD },
1650  { "POST", MHD_METHOD_POST },
1651  { "PUT", MHD_METHOD_PUT },
1652  { "DELETE", MHD_METHOD_DELETE },
1653  { "TRACE", MHD_METHOD_TRACE },
1654  { "CONNECT", MHD_METHOD_CONNECT },
1655  { "ACL", MHD_METHOD_ACL },
1656  { "BASELINE_CONTROL", MHD_METHOD_BASELINE_CONTROL },
1657  { "BIND", MHD_METHOD_BIND },
1658  { "CHECKIN", MHD_METHOD_CHECKIN },
1659  { "CHECKOUT", MHD_METHOD_CHECKOUT },
1660  { "COPY", MHD_METHOD_COPY },
1661  { "LABEL", MHD_METHOD_LABEL },
1662  { "LINK", MHD_METHOD_LINK },
1663  { "LOCK", MHD_METHOD_LOCK },
1664  { "MERGE", MHD_METHOD_MERGE },
1665  { "MKACTIVITY", MHD_METHOD_MKACTIVITY },
1666  { "MKCOL", MHD_METHOD_MKCOL },
1667  { "MKREDIRECTREF", MHD_METHOD_MKREDIRECTREF },
1668  { "MKWORKSPACE", MHD_METHOD_MKWORKSPACE },
1669  { "MOVE", MHD_METHOD_MOVE },
1670  { "ORDERPATCH", MHD_METHOD_ORDERPATCH },
1671  { "PRI", MHD_METHOD_PRI },
1672  { "PROPFIND", MHD_METHOD_PROPFIND },
1673  { "PROPPATCH", MHD_METHOD_PROPPATCH },
1674  { "REBIND", MHD_METHOD_REBIND },
1675  { "REPORT", MHD_METHOD_REPORT },
1676  { "SEARCH", MHD_METHOD_SEARCH },
1677  { "UNBIND", MHD_METHOD_UNBIND },
1678  { "UNCHECKOUT", MHD_METHOD_UNCHECKOUT },
1679  { "UNLINK", MHD_METHOD_UNLINK },
1680  { "UNLOCK", MHD_METHOD_UNLOCK },
1681  { "UPDATE", MHD_METHOD_UPDATE },
1682  { "UPDATEDIRECTREF", MHD_METHOD_UPDATEDIRECTREF },
1683  { "VERSION-CONTROL", MHD_METHOD_VERSION_CONTROL },
1684  { NULL, MHD_METHOD_UNKNOWN } /* must be last! */
1685  };
1686  unsigned int i;
1687 
1688  for (i=0;NULL != methods[i].key;i++)
1689  if (0 ==
1690  MHD_str_equal_caseless_ (method,
1691  methods[i].key))
1692  return methods[i].value;
1693  return MHD_METHOD_UNKNOWN;
1694 }
1695 
1696 
1707 static bool
1709  const char *key,
1710  const char *value,
1711  enum MHD_ValueKind kind)
1712 {
1713  if (MHD_NO ==
1714  MHD_request_set_value (request,
1715  kind,
1716  key,
1717  value))
1718  {
1719 #ifdef HAVE_MESSAGES
1720  MHD_DLOG (request->daemon,
1721  MHD_SC_CONNECTION_POOL_MALLOC_FAILURE,
1722  _("Not enough memory in pool to allocate header record!\n"));
1723 #endif
1724  transmit_error_response (request,
1725  MHD_SC_CLIENT_HEADER_TOO_BIG,
1727  REQUEST_TOO_BIG);
1728  return false;
1729  }
1730  return true;
1731 }
1732 
1733 
1742 static bool
1744  char *line,
1745  size_t line_len)
1746 {
1747  struct MHD_Daemon *daemon = request->daemon;
1748  const char *curi;
1749  char *uri;
1750  char *http_version;
1751  char *args;
1752  unsigned int unused_num_headers;
1753  size_t url_end;
1754 
1755  if (NULL == (uri = memchr (line,
1756  ' ',
1757  line_len)))
1758  return false; /* serious error */
1759  uri[0] = '\0';
1760  request->method_s = line;
1761  request->method = method_string_to_enum (line);
1762  uri++;
1763  /* Skip any spaces. Not required by standard but allow
1764  to be more tolerant. */
1765  while ( (' ' == uri[0]) &&
1766  ( (size_t)(uri - line) < line_len) )
1767  uri++;
1768  if ((size_t)(uri - line) == line_len)
1769  {
1770  curi = "";
1771  uri = NULL;
1772  request->version_s = "";
1773  args = NULL;
1774  url_end = line_len - (line - uri); // EH, this is garbage. FIXME!
1775  }
1776  else
1777  {
1778  curi = uri;
1779  /* Search from back to accept misformed URI with space */
1780  http_version = line + line_len - 1;
1781  /* Skip any trailing spaces */
1782  while ( (' ' == http_version[0]) &&
1783  (http_version > uri) )
1784  http_version--;
1785  /* Find first space in reverse direction */
1786  while ( (' ' != http_version[0]) &&
1787  (http_version > uri) )
1788  http_version--;
1789  if (http_version > uri)
1790  {
1791  http_version[0] = '\0';
1792  request->version_s = http_version + 1;
1793  args = memchr (uri,
1794  '?',
1795  http_version - uri);
1796  }
1797  else
1798  {
1799  request->version_s = "";
1800  args = memchr (uri,
1801  '?',
1802  line_len - (uri - line));
1803  }
1804  url_end = http_version - uri;
1805  }
1806  if ( (MHD_PSL_STRICT == daemon->protocol_strict_level) &&
1807  (NULL != memchr (curi,
1808  ' ',
1809  url_end)) )
1810  {
1811  /* space exists in URI and we are supposed to be strict, reject */
1812  return MHD_NO;
1813  }
1814  if (NULL != daemon->early_uri_logger_cb)
1815  {
1816  request->client_context
1817  = daemon->early_uri_logger_cb (daemon->early_uri_logger_cb_cls,
1818  curi,
1819  request);
1820  }
1821  if (NULL != args)
1822  {
1823  args[0] = '\0';
1824  args++;
1825  /* note that this call clobbers 'args' */
1826  MHD_parse_arguments_ (request,
1828  args,
1830  &unused_num_headers);
1831  }
1832  if (NULL != uri)
1833  daemon->unescape_cb (daemon->unescape_cb_cls,
1834  request,
1835  uri);
1836  request->url = curi;
1837  return true;
1838 }
1839 
1840 
1850 static bool
1852  char *line)
1853 {
1854  struct MHD_Connection *connection = request->connection;
1855  char *colon;
1856 
1857  /* line should be normal header line, find colon */
1858  colon = strchr (line,
1859  ':');
1860  if (NULL == colon)
1861  {
1862  /* error in header line, die hard */
1863  CONNECTION_CLOSE_ERROR (connection,
1864  MHD_SC_CONNECTION_PARSE_FAIL_CLOSED,
1865  _("Received malformed line (no colon). Closing connection.\n"));
1866  return false;
1867  }
1868  if (MHD_PSL_PERMISSIVE != request->daemon->protocol_strict_level)
1869  {
1870  /* check for whitespace before colon, which is not allowed
1871  by RFC 7230 section 3.2.4; we count space ' ' and
1872  tab '\t', but not '\r\n' as those would have ended the line. */
1873  const char *white;
1874 
1875  white = strchr (line,
1876  (unsigned char) ' ');
1877  if ( (NULL != white) &&
1878  (white < colon) )
1879  {
1880  CONNECTION_CLOSE_ERROR (connection,
1881  MHD_SC_CONNECTION_PARSE_FAIL_CLOSED,
1882  _("Whitespace before colon forbidden by RFC 7230. Closing connection.\n"));
1883  return false;
1884  }
1885  white = strchr (line,
1886  (unsigned char) '\t');
1887  if ( (NULL != white) &&
1888  (white < colon) )
1889  {
1890  CONNECTION_CLOSE_ERROR (connection,
1891  MHD_SC_CONNECTION_PARSE_FAIL_CLOSED,
1892  _("Tab before colon forbidden by RFC 7230. Closing connection.\n"));
1893  return false;
1894  }
1895  }
1896  /* zero-terminate header */
1897  colon[0] = '\0';
1898  colon++; /* advance to value */
1899  while ( ('\0' != colon[0]) &&
1900  ( (' ' == colon[0]) ||
1901  ('\t' == colon[0]) ) )
1902  colon++;
1903  /* we do the actual adding of the connection
1904  header at the beginning of the while
1905  loop since we need to be able to inspect
1906  the *next* header line (in case it starts
1907  with a space...) */
1908  request->last = line;
1909  request->colon = colon;
1910  return true;
1911 }
1912 
1913 
1924 static bool
1926  char *line,
1927  enum MHD_ValueKind kind)
1928 {
1929  struct MHD_Connection *connection = request->connection;
1930  char *last;
1931  char *tmp;
1932  size_t last_len;
1933  size_t tmp_len;
1934 
1935  last = request->last;
1936  if ( (' ' == line[0]) ||
1937  ('\t' == line[0]) )
1938  {
1939  /* value was continued on the next line, see
1940  http://www.jmarshall.com/easy/http/ */
1941  last_len = strlen (last);
1942  /* skip whitespace at start of 2nd line */
1943  tmp = line;
1944  while ( (' ' == tmp[0]) ||
1945  ('\t' == tmp[0]) )
1946  tmp++;
1947  tmp_len = strlen (tmp);
1948  /* FIXME: we might be able to do this better (faster!), as most
1949  likely 'last' and 'line' should already be adjacent in
1950  memory; however, doing this right gets tricky if we have a
1951  value continued over multiple lines (in which case we need to
1952  record how often we have done this so we can check for
1953  adjacency); also, in the case where these are not adjacent
1954  (not sure how it can happen!), we would want to allocate from
1955  the end of the pool, so as to not destroy the read-buffer's
1956  ability to grow nicely. */
1957  last = MHD_pool_reallocate (connection->pool,
1958  last,
1959  last_len + 1,
1960  last_len + tmp_len + 1);
1961  if (NULL == last)
1962  {
1964  MHD_SC_CLIENT_HEADER_TOO_BIG,
1966  REQUEST_TOO_BIG);
1967  return MHD_NO;
1968  }
1969  memcpy (&last[last_len],
1970  tmp,
1971  tmp_len + 1);
1972  request->last = last;
1973  return MHD_YES; /* possibly more than 2 lines... */
1974  }
1975  mhd_assert ( (NULL != last) &&
1976  (NULL != request->colon) );
1977  if (! request_add_header (request,
1978  last,
1979  request->colon,
1980  kind))
1981  {
1983  MHD_SC_CLIENT_HEADER_TOO_BIG,
1985  REQUEST_TOO_BIG);
1986  return false;
1987  }
1988  /* we still have the current line to deal with... */
1989  if ('\0' != line[0])
1990  {
1992  line))
1993  {
1995  MHD_SC_CONNECTION_PARSE_FAIL_CLOSED,
1998  return false;
1999  }
2000  }
2001  return true;
2002 }
2003 
2004 
2018 static char *
2020  size_t *line_len)
2021 {
2022  char *rbuf;
2023  size_t pos;
2024 
2025  if (0 == request->read_buffer_offset)
2026  return NULL;
2027  pos = 0;
2028  rbuf = request->read_buffer;
2029  while ( (pos < request->read_buffer_offset - 1) &&
2030  ('\r' != rbuf[pos]) &&
2031  ('\n' != rbuf[pos]) )
2032  pos++;
2033  if ( (pos == request->read_buffer_offset - 1) &&
2034  ('\n' != rbuf[pos]) )
2035  {
2036  /* not found, consider growing... */
2039  {
2041  MHD_SC_CLIENT_HEADER_TOO_BIG,
2042  (NULL != request->url)
2045  REQUEST_TOO_BIG);
2046  }
2047  if (line_len)
2048  *line_len = 0;
2049  return NULL;
2050  }
2051 
2052  if (line_len)
2053  *line_len = pos;
2054  /* found, check if we have proper LFCR */
2055  if ( ('\r' == rbuf[pos]) &&
2056  ('\n' == rbuf[pos + 1]) )
2057  rbuf[pos++] = '\0'; /* skip both r and n */
2058  rbuf[pos++] = '\0';
2059  request->read_buffer += pos;
2060  request->read_buffer_size -= pos;
2061  request->read_buffer_offset -= pos;
2062  return rbuf;
2063 }
2064 
2065 
2085 static bool
2087 {
2088  (void) connection; /* Mute compiler warning. */
2089 #if defined(TCP_CORK) || defined(TCP_PUSH)
2090  return true;
2091 #else /* !TCP_CORK && !TCP_PUSH */
2092  return false;
2093 #endif /* !TCP_CORK && !TCP_PUSH */
2094 }
2095 
2096 
2104 static bool
2106 {
2107  bool res = false;
2108  (void)connection; /* Mute compiler warning. */
2109 #if defined(TCP_CORK) || defined(TCP_NOPUSH)
2110  const MHD_SCKT_OPT_BOOL_ on_val = 1;
2111 #if defined(TCP_NODELAY)
2112  const MHD_SCKT_OPT_BOOL_ off_val = 0;
2113 #endif /* TCP_NODELAY */
2114  mhd_assert(NULL != connection);
2115 #if defined(TCP_NOPUSH) && !defined(TCP_CORK)
2116  /* Buffer data before sending */
2117  res = (0 == setsockopt (connection->socket_fd,
2118  IPPROTO_TCP,
2119  TCP_NOPUSH,
2120  (const void *) &on_val,
2121  sizeof (on_val)))
2122  ? true : false;
2123 #if defined(TCP_NODELAY)
2124  /* Enable Nagle's algorithm */
2125  /* TCP_NODELAY may interfere with TCP_NOPUSH */
2126  res &= (0 == setsockopt (connection->socket_fd,
2127  IPPROTO_TCP,
2128  TCP_NODELAY,
2129  (const void *) &off_val,
2130  sizeof (off_val)))
2131  ? true : false;
2132 #endif /* TCP_NODELAY */
2133 #else /* TCP_CORK */
2134 #if defined(TCP_NODELAY)
2135  /* Enable Nagle's algorithm */
2136  /* TCP_NODELAY may prevent enabling TCP_CORK. Resulting buffering mode depends
2137  solely on TCP_CORK result, so ignoring return code here. */
2138  (void) setsockopt (connection->socket_fd,
2139  IPPROTO_TCP,
2140  TCP_NODELAY,
2141  (const void *) &off_val,
2142  sizeof (off_val));
2143 #endif /* TCP_NODELAY */
2144  /* Send only full packets */
2145  res = (0 == setsockopt (connection->socket_fd,
2146  IPPROTO_TCP,
2147  TCP_CORK,
2148  (const void *) &on_val,
2149  sizeof (on_val)))
2150  ? true : false;
2151 #endif /* TCP_CORK */
2152 #endif /* TCP_CORK || TCP_NOPUSH */
2153  return res;
2154 }
2155 
2156 
2163 static bool
2165 {
2166 #if defined(TCP_NODELAY)
2167  bool res = true;
2168  const MHD_SCKT_OPT_BOOL_ on_val = 1;
2169 #if defined(TCP_CORK) || defined(TCP_NOPUSH)
2170  const MHD_SCKT_OPT_BOOL_ off_val = 0;
2171 #endif /* TCP_CORK || TCP_NOPUSH */
2172 
2173  (void)connection; /* Mute compiler warning. */
2174  mhd_assert(NULL != connection);
2175 #if defined(TCP_CORK)
2176  /* Allow partial packets */
2177  res &= (0 == setsockopt (connection->socket_fd,
2178  IPPROTO_TCP,
2179  TCP_CORK,
2180  (const void *) &off_val,
2181  sizeof (off_val)))
2182  ? true : false;
2183 #endif /* TCP_CORK */
2184 #if defined(TCP_NODELAY)
2185  /* Disable Nagle's algorithm for sending packets without delay */
2186  res &= (0 == setsockopt (connection->socket_fd,
2187  IPPROTO_TCP,
2188  TCP_NODELAY,
2189  (const void *) &on_val,
2190  sizeof (on_val)))
2191  ? true : false;
2192 #endif /* TCP_NODELAY */
2193 #if defined(TCP_NOPUSH) && !defined(TCP_CORK)
2194  /* Disable extra buffering */
2195  res &= (0 == setsockopt (connection->socket_fd,
2196  IPPROTO_TCP,
2197  TCP_NOPUSH,
2198  (const void *) &off_val,
2199  sizeof (off_val)))
2200  ? true : false;
2201 #endif /* TCP_NOPUSH && !TCP_CORK */
2202  return res;
2203 #else /* !TCP_NODELAY */
2204  return false;
2205 #endif /* !TCP_NODELAY */
2206 }
2207 
2208 
2216 static bool
2218 {
2219  bool res = true;
2220 #if defined(TCP_NOPUSH) && !defined(TCP_CORK)
2221  const int dummy = 0;
2222 #endif /* !TCP_CORK */
2223 
2224  if (NULL == connection)
2225  return false; /* FIXME: use MHD_NONNULL? */
2226  res = socket_start_no_buffering (connection);
2227 #if defined(TCP_NOPUSH) && !defined(TCP_CORK)
2228  /* Force flush data with zero send otherwise Darwin and some BSD systems
2229  will add 5 seconds delay. Not required with TCP_CORK as switching off
2230  TCP_CORK always flushes socket buffer. */
2231  res &= (0 <= MHD_send_ (connection->socket_fd,
2232  &dummy,
2233  0))
2234  ? true : false;
2235 #endif /* TCP_NOPUSH && !TCP_CORK*/
2236  return res;
2237 }
2238 
2239 
2246 static bool
2248 {
2249 #if defined(TCP_NODELAY)
2250  bool res = true;
2251  const MHD_SCKT_OPT_BOOL_ off_val = 0;
2252 #if defined(TCP_CORK)
2253  MHD_SCKT_OPT_BOOL_ cork_val = 0;
2254  socklen_t param_size = sizeof (cork_val);
2255 #endif /* TCP_CORK */
2256 
2257  mhd_assert(NULL != connection);
2258 #if defined(TCP_CORK)
2259  /* Allow partial packets */
2260  /* Disabling TCP_CORK will flush partial packet even if TCP_CORK wasn't enabled before
2261  so try to check current value of TCP_CORK to prevent unrequested flushing */
2262  if ( (0 != getsockopt (connection->socket_fd,
2263  IPPROTO_TCP,
2264  TCP_CORK,
2265  (void*)&cork_val,
2266  &param_size)) ||
2267  (0 != cork_val))
2268  res &= (0 == setsockopt (connection->socket_fd,
2269  IPPROTO_TCP,
2270  TCP_CORK,
2271  (const void *) &off_val,
2272  sizeof (off_val)))
2273  ? true : false;
2274 #elif defined(TCP_NOPUSH)
2275  /* Disable extra buffering */
2276  /* No need to check current value as disabling TCP_NOPUSH will not flush partial
2277  packet if TCP_NOPUSH wasn't enabled before */
2278  res &= (0 == setsockopt (connection->socket_fd,
2279  IPPROTO_TCP,
2280  TCP_NOPUSH,
2281  (const void *) &off_val,
2282  sizeof (off_val)))
2283  ? true : false;
2284 #endif /* TCP_NOPUSH && !TCP_CORK */
2285  /* Enable Nagle's algorithm for normal buffering */
2286  res &= (0 == setsockopt (connection->socket_fd,
2287  IPPROTO_TCP,
2288  TCP_NODELAY,
2289  (const void *) &off_val,
2290  sizeof (off_val)))
2291  ? true : false;
2292  return res;
2293 #else /* !TCP_NODELAY */
2294  return false;
2295 #endif /* !TCP_NODELAY */
2296 }
2297 
2298 
2306 static bool
2308 {
2309  const char *expect;
2310 
2311  return ( (NULL == request->response) &&
2312  (NULL != request->version_s) &&
2315  (NULL != (expect = MHD_request_lookup_value (request,
2318  (MHD_str_equal_caseless_(expect,
2319  "100-continue")) &&
2322 }
2323 
2324 
2331 static int
2333 {
2334  const char *hdr;
2335  char *cpy;
2336  char *pos;
2337  char *sce;
2338  char *semicolon;
2339  char *equals;
2340  char *ekill;
2341  char old;
2342  int quotes;
2343 
2347  if (NULL == hdr)
2348  return true;
2350  strlen (hdr) + 1,
2351  MHD_YES);
2352  if (NULL == cpy)
2353  {
2354 #ifdef HAVE_MESSAGES
2355  MHD_DLOG (request->daemon,
2356  MHD_SC_COOKIE_POOL_ALLOCATION_FAILURE,
2357  _("Not enough memory in pool to parse cookies!\n"));
2358 #endif
2360  MHD_SC_COOKIE_POOL_ALLOCATION_FAILURE,
2362  REQUEST_TOO_BIG);
2363  return false;
2364  }
2365  memcpy (cpy,
2366  hdr,
2367  strlen (hdr) + 1);
2368  pos = cpy;
2369  while (NULL != pos)
2370  {
2371  while (' ' == *pos)
2372  pos++; /* skip spaces */
2373 
2374  sce = pos;
2375  while ( ((*sce) != '\0') &&
2376  ((*sce) != ',') &&
2377  ((*sce) != ';') &&
2378  ((*sce) != '=') )
2379  sce++;
2380  /* remove tailing whitespace (if any) from key */
2381  ekill = sce - 1;
2382  while ( (*ekill == ' ') &&
2383  (ekill >= pos) )
2384  *(ekill--) = '\0';
2385  old = *sce;
2386  *sce = '\0';
2387  if (old != '=')
2388  {
2389  /* value part omitted, use empty string... */
2390  if (! request_add_header (request,
2391  pos,
2392  "",
2393  MHD_COOKIE_KIND))
2394  return false;
2395  if (old == '\0')
2396  break;
2397  pos = sce + 1;
2398  continue;
2399  }
2400  equals = sce + 1;
2401  quotes = 0;
2402  semicolon = equals;
2403  while ( ('\0' != semicolon[0]) &&
2404  ( (0 != quotes) ||
2405  ( (';' != semicolon[0]) &&
2406  (',' != semicolon[0]) ) ) )
2407  {
2408  if ('"' == semicolon[0])
2409  quotes = (quotes + 1) & 1;
2410  semicolon++;
2411  }
2412  if ('\0' == semicolon[0])
2413  semicolon = NULL;
2414  if (NULL != semicolon)
2415  {
2416  semicolon[0] = '\0';
2417  semicolon++;
2418  }
2419  /* remove quotes */
2420  if ( ('"' == equals[0]) &&
2421  ('"' == equals[strlen (equals) - 1]) )
2422  {
2423  equals[strlen (equals) - 1] = '\0';
2424  equals++;
2425  }
2426  if (! request_add_header (request,
2427  pos,
2428  equals,
2429  MHD_COOKIE_KIND))
2430  return false;
2431  pos = semicolon;
2432  }
2433  return true;
2434 }
2435 
2436 
2444 static void
2446 {
2447  struct MHD_Daemon *daemon = request->daemon;
2448  struct MHD_Connection *connection = request->connection;
2449  const char *clen;
2450  struct MHD_Response *response;
2451  const char *enc;
2452  const char *end;
2453 
2454  parse_cookie_header (request); /* FIXME: return value ignored! */
2455  if ( (MHD_PSL_STRICT == daemon->protocol_strict_level) &&
2456  (NULL != request->version_s) &&
2458  request->version_s)) &&
2459  (NULL ==
2460  MHD_request_lookup_value (request,
2463  {
2464  /* die, http 1.1 request without host and we are pedantic */
2466  connection->read_closed = true;
2467 #ifdef HAVE_MESSAGES
2468  MHD_DLOG (daemon,
2469  MHD_SC_HOST_HEADER_MISSING,
2470  _("Received HTTP 1.1 request without `Host' header.\n"));
2471 #endif
2472  mhd_assert (NULL == request->response);
2473  response =
2478  request->response = response;
2479  // FIXME: state machine advance?
2480  return;
2481  }
2482 
2483  request->remaining_upload_size = 0;
2484  enc = MHD_request_lookup_value (request,
2487  if (NULL != enc)
2488  {
2490  if (MHD_str_equal_caseless_ (enc,
2491  "chunked"))
2492  request->have_chunked_upload = true;
2493  return;
2494  }
2495  clen = MHD_request_lookup_value (request,
2498  if (NULL == clen)
2499  return;
2500  end = clen + MHD_str_to_uint64_ (clen,
2501  &request->remaining_upload_size);
2502  if ( (clen == end) ||
2503  ('\0' != *end) )
2504  {
2505  request->remaining_upload_size = 0;
2506 #ifdef HAVE_MESSAGES
2507  MHD_DLOG (request->daemon,
2508  MHD_SC_CONTENT_LENGTH_MALFORMED,
2509  "Failed to parse `Content-Length' header. Closing connection.\n");
2510 #endif
2511  CONNECTION_CLOSE_ERROR (connection,
2512  MHD_SC_CONTENT_LENGTH_MALFORMED,
2513  NULL);
2514  }
2515 }
2516 
2517 
2524 static void
2526 {
2527  struct MHD_Daemon *daemon = request->daemon;
2528  struct MHD_Connection *connection = request->connection;
2529  const struct MHD_Action *action;
2530 
2531  if (NULL != request->response)
2532  return; /* already queued a response */
2533  if (NULL == (action =
2534  daemon->rc (daemon->rc_cls,
2535  request,
2536  request->url,
2537  request->method)))
2538  {
2539  /* serious internal error, close connection */
2540  CONNECTION_CLOSE_ERROR (connection,
2541  MHD_SC_APPLICATION_CALLBACK_FAILURE_CLOSED,
2542  _("Application reported internal error, closing connection.\n"));
2543  return;
2544  }
2545  action->action (action->action_cls,
2546  request);
2547 }
2548 
2549 
2556 static void
2558 {
2559  struct MHD_Daemon *daemon = request->daemon;
2560  struct MHD_Connection *connection = request->connection;
2561  size_t available;
2562  bool instant_retry;
2563  char *buffer_head;
2564 
2565  if (NULL != request->response)
2566  return; /* already queued a response */
2567 
2568  buffer_head = request->read_buffer;
2569  available = request->read_buffer_offset;
2570  do
2571  {
2572  size_t to_be_processed;
2573  size_t left_unprocessed;
2574  size_t processed_size;
2575 
2576  instant_retry = false;
2577  if ( (request->have_chunked_upload) &&
2579  {
2581  (0LLU != request->current_chunk_offset) &&
2582  (available >= 2) )
2583  {
2584  size_t i;
2585 
2586  /* skip new line at the *end* of a chunk */
2587  i = 0;
2588  if ( ('\r' == buffer_head[i]) ||
2589  ('\n' == buffer_head[i]) )
2590  i++; /* skip 1st part of line feed */
2591  if ( ('\r' == buffer_head[i]) ||
2592  ('\n' == buffer_head[i]) )
2593  i++; /* skip 2nd part of line feed */
2594  if (0 == i)
2595  {
2596  /* malformed encoding */
2597  CONNECTION_CLOSE_ERROR (connection,
2598  MHD_SC_CHUNKED_ENCODING_MALFORMED,
2599  _("Received malformed HTTP request (bad chunked encoding). Closing connection.\n"));
2600  return;
2601  }
2602  available -= i;
2603  buffer_head += i;
2606  }
2609  {
2610  uint64_t cur_chunk_left;
2611 
2612  /* we are in the middle of a chunk, give
2613  as much as possible to the client (without
2614  crossing chunk boundaries) */
2615  cur_chunk_left
2617  if (cur_chunk_left > available)
2618  {
2619  to_be_processed = available;
2620  }
2621  else
2622  { /* cur_chunk_left <= (size_t)available */
2623  to_be_processed = (size_t)cur_chunk_left;
2624  if (available > to_be_processed)
2625  instant_retry = true;
2626  }
2627  }
2628  else
2629  {
2630  size_t i;
2631  size_t end_size;
2632  bool malformed;
2633 
2634  /* we need to read chunk boundaries */
2635  i = 0;
2636  while (i < available)
2637  {
2638  if ( ('\r' == buffer_head[i]) ||
2639  ('\n' == buffer_head[i]) ||
2640  (';' == buffer_head[i]) )
2641  break;
2642  i++;
2643  if (i >= 16)
2644  break;
2645  }
2646  end_size = i;
2647  /* find beginning of CRLF (skip over chunk extensions) */
2648  if (';' == buffer_head[i])
2649  {
2650  while (i < available)
2651  {
2652  if ( ('\r' == buffer_head[i]) ||
2653  ('\n' == buffer_head[i]) )
2654  break;
2655  i++;
2656  }
2657  }
2658  /* take '\n' into account; if '\n' is the unavailable
2659  character, we will need to wait until we have it
2660  before going further */
2661  if ( (i + 1 >= available) &&
2662  ! ( (1 == i) &&
2663  (2 == available) &&
2664  ('0' == buffer_head[0]) ) )
2665  break; /* need more data... */
2666  i++;
2667  malformed = (end_size >= 16);
2668  if (! malformed)
2669  {
2670  size_t num_dig = MHD_strx_to_uint64_n_ (buffer_head,
2671  end_size,
2673  malformed = (end_size != num_dig);
2674  }
2675  if (malformed)
2676  {
2677  /* malformed encoding */
2678  CONNECTION_CLOSE_ERROR (connection,
2679  MHD_SC_CHUNKED_ENCODING_MALFORMED,
2680  _("Received malformed HTTP request (bad chunked encoding). Closing connection.\n"));
2681  return;
2682  }
2683  /* skip 2nd part of line feed */
2684  if ( (i < available) &&
2685  ( ('\r' == buffer_head[i]) ||
2686  ('\n' == buffer_head[i]) ) )
2687  i++;
2688 
2689  buffer_head += i;
2690  available -= i;
2692 
2693  if (available > 0)
2694  instant_retry = true;
2695  if (0LLU == request->current_chunk_size)
2696  {
2698  break;
2699  }
2700  continue;
2701  }
2702  }
2703  else
2704  {
2705  /* no chunked encoding, give all to the client */
2706  if ( (0 != request->remaining_upload_size) &&
2708  (request->remaining_upload_size < available) )
2709  {
2710  to_be_processed = (size_t)request->remaining_upload_size;
2711  }
2712  else
2713  {
2718  to_be_processed = available;
2719  }
2720  }
2721  left_unprocessed = to_be_processed;
2722 #if FIXME_OLD_STYLE
2723  if (MHD_NO ==
2724  daemon->rc (daemon->rc_cls,
2725  request,
2726  request->url,
2727  request->method,
2728  request->version,
2729  buffer_head,
2730  &left_unprocessed,
2732  {
2733  /* serious internal error, close connection */
2734  CONNECTION_CLOSE_ERROR (connection,
2735  MHD_SC_APPLICATION_CALLBACK_FAILURE_CLOSED,
2736  _("Application reported internal error, closing connection.\n"));
2737  return;
2738  }
2739 #endif
2740  if (left_unprocessed > to_be_processed)
2742  __FILE__,
2743  __LINE__
2744 #ifdef HAVE_MESSAGES
2745  , _("libmicrohttpd API violation")
2746 #else
2747  , NULL
2748 #endif
2749  );
2750  if (0 != left_unprocessed)
2751  {
2752  instant_retry = false; /* client did not process everything */
2753 #ifdef HAVE_MESSAGES
2754  /* client did not process all upload data, complain if
2755  the setup was incorrect, which may prevent us from
2756  handling the rest of the request */
2757  if ( (MHD_TM_EXTERNAL_EVENT_LOOP == daemon->threading_mode) &&
2758  (! connection->suspended) )
2759  MHD_DLOG (daemon,
2760  MHD_SC_APPLICATION_HUNG_CONNECTION,
2761  _("WARNING: incomplete upload processing and connection not suspended may result in hung connection.\n"));
2762 #endif
2763  }
2764  processed_size = to_be_processed - left_unprocessed;
2766  request->current_chunk_offset += processed_size;
2767  /* dh left "processed" bytes in buffer for next time... */
2768  buffer_head += processed_size;
2769  available -= processed_size;
2771  request->remaining_upload_size -= processed_size;
2772  }
2773  while (instant_retry);
2774  if (available > 0)
2775  memmove (request->read_buffer,
2776  buffer_head,
2777  available);
2778  request->read_buffer_offset = available;
2779 }
2780 
2781 
2790 static void
2792 {
2793  struct MHD_Daemon *daemon = connection->daemon;
2794 
2795  if (connection->request.in_cleanup)
2796  return; /* Prevent double cleanup. */
2797  connection->request.in_cleanup = true;
2798  if (NULL != connection->request.response)
2799  {
2801  connection->request.response = NULL;
2802  }
2804  if (connection->suspended)
2805  {
2808  connection);
2809  connection->suspended = false;
2810  }
2811  else
2812  {
2813  if (MHD_TM_THREAD_PER_CONNECTION != daemon->threading_mode)
2814  {
2815  if (connection->connection_timeout ==
2818  daemon->normal_timeout_tail,
2819  connection);
2820  else
2822  daemon->manual_timeout_tail,
2823  connection);
2824  }
2825  DLL_remove (daemon->connections_head,
2826  daemon->connections_tail,
2827  connection);
2828  }
2829  DLL_insert (daemon->cleanup_head,
2830  daemon->cleanup_tail,
2831  connection);
2832  connection->resuming = false;
2833  connection->request.in_idle = false;
2835  if (MHD_TM_THREAD_PER_CONNECTION == daemon->threading_mode)
2836  {
2837  /* if we were at the connection limit before and are in
2838  thread-per-connection mode, signal the main thread
2839  to resume accepting connections */
2840  if ( (MHD_ITC_IS_VALID_ (daemon->itc)) &&
2841  (! MHD_itc_activate_ (daemon->itc,
2842  "c")) )
2843  {
2844 #ifdef HAVE_MESSAGES
2845  MHD_DLOG (daemon,
2846  MHD_SC_ITC_USE_FAILED,
2847  _("Failed to signal end of connection via inter-thread communication channel"));
2848 #endif
2849  }
2850  }
2851 }
2852 
2853 
2854 #ifdef EPOLL_SUPPORT
2855 
2863 static bool
2864 connection_epoll_update_ (struct MHD_Connection *connection)
2865 {
2866  struct MHD_Daemon *daemon = connection->daemon;
2867 
2868  if ( (MHD_ELS_EPOLL == daemon->event_loop_syscall) &&
2869  (0 == (connection->epoll_state & MHD_EPOLL_STATE_IN_EPOLL_SET)) &&
2870  (0 == (connection->epoll_state & MHD_EPOLL_STATE_SUSPENDED)) &&
2871  ( ( (MHD_EVENT_LOOP_INFO_WRITE == connection->request.event_loop_info) &&
2872  (0 == (connection->epoll_state & MHD_EPOLL_STATE_WRITE_READY))) ||
2873  ( (MHD_EVENT_LOOP_INFO_READ == connection->request.event_loop_info) &&
2874  (0 == (connection->epoll_state & MHD_EPOLL_STATE_READ_READY)) ) ) )
2875  {
2876  /* add to epoll set */
2877  struct epoll_event event;
2878 
2879  event.events = EPOLLIN | EPOLLOUT | EPOLLPRI | EPOLLET;
2880  event.data.ptr = connection;
2881  if (0 != epoll_ctl (daemon->epoll_fd,
2882  EPOLL_CTL_ADD,
2883  connection->socket_fd,
2884  &event))
2885  {
2886 #ifdef HAVE_MESSAGES
2887  MHD_DLOG (daemon,
2888  MHD_SC_EPOLL_CTL_ADD_FAILED,
2889  _("Call to epoll_ctl failed: %s\n"),
2891 #endif
2892  connection->request.state = MHD_REQUEST_CLOSED;
2893  cleanup_connection (connection);
2894  return false;
2895  }
2896  connection->epoll_state |= MHD_EPOLL_STATE_IN_EPOLL_SET;
2897  }
2898  return true;
2899 }
2900 #endif
2901 
2902 
2911 static void
2913 {
2914  struct MHD_Daemon *daemon = connection->daemon;
2915  struct MHD_Request *request = &connection->request;
2916 
2917  /* Do not update states of suspended connection */
2918  if (connection->suspended)
2919  return; /* States will be updated after resume. */
2920 #ifdef HTTPS_SUPPORT
2921  {
2922  struct MHD_TLS_Plugin *tls;
2923 
2924  if ( (NULL != (tls = daemon->tls_api)) &&
2925  (tls->update_event_loop_info (tls->cls,
2926  connection->tls_cs,
2927  &request->event_loop_info)) )
2928  return; /* TLS has decided what to do */
2929  }
2930 #endif /* HTTPS_SUPPORT */
2931  while (1)
2932  {
2933 #if DEBUG_STATES
2934  MHD_DLOG (daemon,
2935  MHD_SC_STATE_MACHINE_STATUS_REPORT,
2936  _("In function %s handling connection at state: %s\n"),
2937  __FUNCTION__,
2938  MHD_state_to_string (request->state));
2939 #endif
2940  switch (request->state)
2941  {
2942  case MHD_REQUEST_INIT:
2945  /* while reading headers, we always grow the
2946  read buffer if needed, no size-check required */
2947  if ( (request->read_buffer_offset == request->read_buffer_size) &&
2948  (! try_grow_read_buffer (request)) )
2949  {
2950  transmit_error_response (request,
2951  MHD_SC_CLIENT_HEADER_TOO_BIG,
2952  (NULL != request->url)
2955  REQUEST_TOO_BIG);
2956  continue;
2957  }
2958  if (! connection->read_closed)
2960  else
2962  break;
2964  mhd_assert (0);
2965  break;
2967  mhd_assert (0);
2968  break;
2971  break;
2973  if (request->read_buffer_offset == request->read_buffer_size)
2974  {
2975  if ( (! try_grow_read_buffer (request)) &&
2976  (MHD_TM_EXTERNAL_EVENT_LOOP != daemon->threading_mode) )
2977  {
2978  /* failed to grow the read buffer, and the client
2979  which is supposed to handle the received data in
2980  a *blocking* fashion (in this mode) did not
2981  handle the data as it was supposed to!
2982 
2983  => we would either have to do busy-waiting
2984  (on the client, which would likely fail),
2985  or if we do nothing, we would just timeout
2986  on the connection (if a timeout is even set!).
2987 
2988  Solution: we kill the connection with an error */
2989  transmit_error_response (request,
2990  MHD_SC_APPLICATION_HUNG_CONNECTION_CLOSED,
2992  INTERNAL_ERROR);
2993  continue;
2994  }
2995  }
2996  if ( (request->read_buffer_offset < request->read_buffer_size) &&
2997  (! connection->read_closed) )
2999  else
3001  break;
3004  /* while reading footers, we always grow the
3005  read buffer if needed, no size-check required */
3006  if (connection->read_closed)
3007  {
3008  CONNECTION_CLOSE_ERROR (connection,
3009  MHD_SC_CONNECTION_READ_FAIL_CLOSED,
3010  NULL);
3011  continue;
3012  }
3014  /* transition to FOOTERS_RECEIVED
3015  happens in read handler */
3016  break;
3019  break;
3021  /* headers in buffer, keep writing */
3023  break;
3025  mhd_assert (0);
3026  break;
3029  break;
3032  break;
3035  break;
3038  break;
3039  case MHD_REQUEST_BODY_SENT:
3040  mhd_assert (0);
3041  break;
3044  break;
3046  mhd_assert (0);
3047  break;
3048  case MHD_REQUEST_CLOSED:
3050  return; /* do nothing, not even reading */
3051 #ifdef UPGRADE_SUPPORT
3052  case MHD_REQUEST_UPGRADE:
3053  mhd_assert (0);
3054  break;
3055 #endif /* UPGRADE_SUPPORT */
3056  default:
3057  mhd_assert (0);
3058  }
3059  break;
3060  }
3061 }
3062 
3063 
3074 bool
3076 {
3077  struct MHD_Daemon *daemon = request->daemon;
3078  struct MHD_Connection *connection = request->connection;
3079  char *line;
3080  size_t line_len;
3081  bool ret;
3082 
3083  request->in_idle = true;
3084  while (! connection->suspended)
3085  {
3086 #ifdef HTTPS_SUPPORT
3087  struct MHD_TLS_Plugin *tls;
3088 
3089  if ( (NULL != (tls = daemon->tls_api)) &&
3090  (! tls->idle_ready (tls->cls,
3091  connection->tls_cs)) )
3092  break;
3093 #endif /* HTTPS_SUPPORT */
3094 #if DEBUG_STATES
3095  MHD_DLOG (daemon,
3096  MHD_SC_STATE_MACHINE_STATUS_REPORT,
3097  _("In function %s handling connection at state: %s\n"),
3098  __FUNCTION__,
3099  MHD_state_to_string (request->state));
3100 #endif
3101  switch (request->state)
3102  {
3103  case MHD_REQUEST_INIT:
3104  line = get_next_header_line (request,
3105  &line_len);
3106  /* Check for empty string, as we might want
3107  to tolerate 'spurious' empty lines; also
3108  NULL means we didn't get a full line yet;
3109  line is not 0-terminated here. */
3110  if ( (NULL == line) ||
3111  (0 == line[0]) )
3112  {
3113  if (MHD_REQUEST_INIT != request->state)
3114  continue;
3115  if (connection->read_closed)
3116  {
3117  CONNECTION_CLOSE_ERROR (connection,
3118  MHD_SC_CONNECTION_READ_FAIL_CLOSED,
3119  NULL);
3120  continue;
3121  }
3122  break;
3123  }
3124  if (MHD_NO ==
3125  parse_initial_message_line (request,
3126  line,
3127  line_len))
3128  CONNECTION_CLOSE_ERROR (connection,
3129  MHD_SC_CONNECTION_CLOSED,
3130  NULL);
3131  else
3132  request->state = MHD_REQUEST_URL_RECEIVED;
3133  continue;
3135  line = get_next_header_line (request,
3136  NULL);
3137  if (NULL == line)
3138  {
3139  if (MHD_REQUEST_URL_RECEIVED != request->state)
3140  continue;
3141  if (connection->read_closed)
3142  {
3143  CONNECTION_CLOSE_ERROR (connection,
3144  MHD_SC_CONNECTION_READ_FAIL_CLOSED,
3145  NULL);
3146  continue;
3147  }
3148  break;
3149  }
3150  if (0 == line[0])
3151  {
3153  request->header_size = (size_t) (line - request->read_buffer);
3154  continue;
3155  }
3156  if (! process_header_line (request,
3157  line))
3158  {
3159  transmit_error_response (request,
3160  MHD_SC_CONNECTION_PARSE_FAIL_CLOSED,
3163  break;
3164  }
3166  continue;
3168  line = get_next_header_line (request,
3169  NULL);
3170  if (NULL == line)
3171  {
3172  if (request->state != MHD_REQUEST_HEADER_PART_RECEIVED)
3173  continue;
3174  if (connection->read_closed)
3175  {
3176  CONNECTION_CLOSE_ERROR (connection,
3177  MHD_SC_CONNECTION_READ_FAIL_CLOSED,
3178  NULL);
3179  continue;
3180  }
3181  break;
3182  }
3183  if (MHD_NO ==
3184  process_broken_line (request,
3185  line,
3186  MHD_HEADER_KIND))
3187  continue;
3188  if (0 == line[0])
3189  {
3191  request->header_size = (size_t) (line - request->read_buffer);
3192  continue;
3193  }
3194  continue;
3196  parse_request_headers (request);
3197  if (MHD_REQUEST_CLOSED == request->state)
3198  continue;
3200  if (connection->suspended)
3201  break;
3202  continue;
3204  call_request_handler (request); /* first call */
3205  if (MHD_REQUEST_CLOSED == request->state)
3206  continue;
3207  if (need_100_continue (request))
3208  {
3210  if (socket_flush_possible (connection))
3211  socket_start_extra_buffering (connection);
3212  else
3213  socket_start_no_buffering (connection);
3214  break;
3215  }
3216  if ( (NULL != request->response) &&
3217  ( (MHD_METHOD_POST == request->method) ||
3218  (MHD_METHOD_PUT == request->method) ) )
3219  {
3220  /* we refused (no upload allowed!) */
3221  request->remaining_upload_size = 0;
3222  /* force close, in case client still tries to upload... */
3223  connection->read_closed = true;
3224  }
3225  request->state = (0 == request->remaining_upload_size)
3228  if (connection->suspended)
3229  break;
3230  continue;
3232  if (request->continue_message_write_offset ==
3234  {
3235  request->state = MHD_REQUEST_CONTINUE_SENT;
3236  if (! socket_flush_possible (connection))
3237  socket_start_no_buffering_flush (connection);
3238  else
3239  socket_start_normal_buffering (connection);
3240  continue;
3241  }
3242  break;
3244  if (0 != request->read_buffer_offset)
3245  {
3246  process_request_body (request); /* loop call */
3247  if (MHD_REQUEST_CLOSED == request->state)
3248  continue;
3249  }
3250  if ( (0 == request->remaining_upload_size) ||
3251  ( (MHD_SIZE_UNKNOWN == request->remaining_upload_size) &&
3252  (0 == request->read_buffer_offset) &&
3253  (connection->read_closed) ) )
3254  {
3255  if ( (request->have_chunked_upload) &&
3256  (! connection->read_closed) )
3257  request->state = MHD_REQUEST_BODY_RECEIVED;
3258  else
3260  if (connection->suspended)
3261  break;
3262  continue;
3263  }
3264  break;
3266  line = get_next_header_line (request,
3267  NULL);
3268  if (NULL == line)
3269  {
3270  if (request->state != MHD_REQUEST_BODY_RECEIVED)
3271  continue;
3272  if (connection->read_closed)
3273  {
3274  CONNECTION_CLOSE_ERROR (connection,
3275  MHD_SC_CONNECTION_CLOSED,
3276  NULL);
3277  continue;
3278  }
3279  break;
3280  }
3281  if (0 == line[0])
3282  {
3284  if (connection->suspended)
3285  break;
3286  continue;
3287  }
3288  if (MHD_NO == process_header_line (request,
3289  line))
3290  {
3291  transmit_error_response (request,
3292  MHD_SC_CONNECTION_PARSE_FAIL_CLOSED,
3295  break;
3296  }
3298  continue;
3300  line = get_next_header_line (request,
3301  NULL);
3302  if (NULL == line)
3303  {
3304  if (request->state != MHD_REQUEST_FOOTER_PART_RECEIVED)
3305  continue;
3306  if (connection->read_closed)
3307  {
3308  CONNECTION_CLOSE_ERROR (connection,
3309  MHD_SC_CONNECTION_CLOSED,
3310  NULL);
3311  continue;
3312  }
3313  break;
3314  }
3315  if (MHD_NO ==
3316  process_broken_line (request,
3317  line,
3318  MHD_FOOTER_KIND))
3319  continue;
3320  if (0 == line[0])
3321  {
3323  if (connection->suspended)
3324  break;
3325  continue;
3326  }
3327  continue;
3329  call_request_handler (request); /* "final" call */
3330  if (request->state == MHD_REQUEST_CLOSED)
3331  continue;
3332  if (NULL == request->response)
3333  break; /* try again next time */
3334  if (! build_header_response (request))
3335  {
3336  /* oops - close! */
3337  CONNECTION_CLOSE_ERROR (connection,
3338  MHD_SC_FAILED_RESPONSE_HEADER_GENERATION,
3339  _("Closing connection (failed to create response header)\n"));
3340  continue;
3341  }
3343  if (MHD_NO != socket_flush_possible (connection))
3344  socket_start_extra_buffering (connection);
3345  else
3346  socket_start_no_buffering (connection);
3347 
3348  break;
3350  /* no default action */
3351  break;
3353  /* Some clients may take some actions right after header receive */
3354  if (MHD_NO != socket_flush_possible (connection))
3355  socket_start_no_buffering_flush (connection);
3356 
3357 #ifdef UPGRADE_SUPPORT
3358  if (NULL != request->response->upgrade_handler)
3359  {
3360  socket_start_normal_buffering (connection);
3361  request->state = MHD_REQUEST_UPGRADE;
3362 #if FIXME_LEGACY_STYLE
3363  /* This request is "upgraded". Pass socket to application. */
3364  if (! MHD_response_execute_upgrade_ (request->response,
3365  request))
3366  {
3367  /* upgrade failed, fail hard */
3368  CONNECTION_CLOSE_ERROR (connection,
3369  MHD_SC_CONNECTION_CLOSED,
3370  NULL);
3371  continue;
3372  }
3373 #endif
3374  /* Response is not required anymore for this request. */
3375  {
3376  struct MHD_Response * const resp = request->response;
3377 
3378  request->response = NULL;
3380  }
3381  continue;
3382  }
3383 #endif /* UPGRADE_SUPPORT */
3384  if (MHD_NO != socket_flush_possible (connection))
3385  socket_start_extra_buffering (connection);
3386  else
3387  socket_start_normal_buffering (connection);
3388 
3389  if (request->have_chunked_upload)
3391  else
3393  continue;
3395  /* nothing to do here */
3396  break;
3398  if (NULL != request->response->crc)
3399  MHD_mutex_lock_chk_ (&request->response->mutex);
3400  if (0 == request->response->total_size)
3401  {
3402  if (NULL != request->response->crc)
3403  MHD_mutex_unlock_chk_ (&request->response->mutex);
3404  request->state = MHD_REQUEST_BODY_SENT;
3405  continue;
3406  }
3407  if (try_ready_normal_body (request))
3408  {
3409  if (NULL != request->response->crc)
3410  MHD_mutex_unlock_chk_ (&request->response->mutex);
3412  /* Buffering for flushable socket was already enabled*/
3413  if (MHD_NO == socket_flush_possible (connection))
3414  socket_start_no_buffering (connection);
3415  break;
3416  }
3417  /* mutex was already unlocked by "try_ready_normal_body */
3418  /* not ready, no socket action */
3419  break;
3421  /* nothing to do here */
3422  break;
3424  if (NULL != request->response->crc)
3425  MHD_mutex_lock_chk_ (&request->response->mutex);
3426  if ( (0 == request->response->total_size) ||
3427  (request->response_write_position ==
3428  request->response->total_size) )
3429  {
3430  if (NULL != request->response->crc)
3431  MHD_mutex_unlock_chk_ (&request->response->mutex);
3432  request->state = MHD_REQUEST_BODY_SENT;
3433  continue;
3434  }
3435  if (try_ready_chunked_body (request))
3436  {
3437  if (NULL != request->response->crc)
3438  MHD_mutex_unlock_chk_ (&request->response->mutex);
3440  /* Buffering for flushable socket was already enabled */
3441  if (MHD_NO == socket_flush_possible (connection))
3442  socket_start_no_buffering (connection);
3443  continue;
3444  }
3445  /* mutex was already unlocked by try_ready_chunked_body */
3446  break;
3447  case MHD_REQUEST_BODY_SENT:
3448  if (! build_header_response (request))
3449  {
3450  /* oops - close! */
3451  CONNECTION_CLOSE_ERROR (connection,
3452  MHD_SC_FAILED_RESPONSE_HEADER_GENERATION,
3453  _("Closing connection (failed to create response header)\n"));
3454  continue;
3455  }
3456  if ( (! request->have_chunked_upload) ||
3457  (request->write_buffer_send_offset ==
3458  request->write_buffer_append_offset) )
3459  request->state = MHD_REQUEST_FOOTERS_SENT;
3460  else
3462  continue;
3464  /* no default action */
3465  break;
3467  {
3468  struct MHD_Response *response = request->response;
3469 
3470  if (MHD_HTTP_PROCESSING == response->status_code)
3471  {
3472  /* After this type of response, we allow sending another! */
3474  MHD_response_queue_for_destroy (response);
3475  request->response = NULL;
3476  /* FIXME: maybe partially reset memory pool? */
3477  continue;
3478  }
3479  if (socket_flush_possible (connection))
3480  socket_start_no_buffering_flush (connection);
3481  else
3482  socket_start_normal_buffering (connection);
3483 
3484  if (NULL != response->termination_cb)
3485  {
3486  response->termination_cb (response->termination_cb_cls,
3488  request->client_context);
3489  }
3490  MHD_response_queue_for_destroy (response);
3491  request->response = NULL;
3492  }
3493  if ( (MHD_CONN_USE_KEEPALIVE != request->keepalive) ||
3494  (connection->read_closed) )
3495  {
3496  /* have to close for some reason */
3497  MHD_connection_close_ (connection,
3499  MHD_pool_destroy (connection->pool);
3500  connection->pool = NULL;
3501  request->read_buffer = NULL;
3502  request->read_buffer_size = 0;
3503  request->read_buffer_offset = 0;
3504  }
3505  else
3506  {
3507  /* can try to keep-alive */
3508  if (socket_flush_possible (connection))
3509  socket_start_normal_buffering (connection);
3510  request->version_s = NULL;
3511  request->state = MHD_REQUEST_INIT;
3512  request->last = NULL;
3513  request->colon = NULL;
3514  request->header_size = 0;
3516  /* Reset the read buffer to the starting size,
3517  preserving the bytes we have already read. */
3518  request->read_buffer
3519  = MHD_pool_reset (connection->pool,
3520  request->read_buffer,
3521  request->read_buffer_offset,
3522  daemon->connection_memory_limit_b / 2);
3523  request->read_buffer_size
3524  = daemon->connection_memory_limit_b / 2;
3525  }
3526  // FIXME: this is too much, NULLs out some of the things
3527  // initialized above...
3528  memset (request,
3529  0,
3530  sizeof (struct MHD_Request));
3531  request->daemon = daemon;
3532  request->connection = connection;
3533  continue;
3534  case MHD_REQUEST_CLOSED:
3535  cleanup_connection (connection);
3536  request->in_idle = false;
3537  return false;
3538 #ifdef UPGRADE_SUPPORT
3539  case MHD_REQUEST_UPGRADE:
3540  request->in_idle = false;
3541  return true; /* keep open */
3542 #endif /* UPGRADE_SUPPORT */
3543  default:
3544  mhd_assert (0);
3545  break;
3546  }
3547  break;
3548  }
3549  if (! connection->suspended)
3550  {
3551  time_t timeout;
3552  timeout = connection->connection_timeout;
3553  if ( (0 != timeout) &&
3554  (timeout < (MHD_monotonic_sec_counter() - connection->last_activity)) )
3555  {
3556  MHD_connection_close_ (connection,
3558  request->in_idle = false;
3559  return true;
3560  }
3561  }
3562  connection_update_event_loop_info (connection);
3563  ret = true;
3564 #ifdef EPOLL_SUPPORT
3565  if ( (! connection->suspended) &&
3566  (MHD_ELS_EPOLL == daemon->event_loop_syscall) )
3567  {
3568  ret = connection_epoll_update_ (connection);
3569  }
3570 #endif /* EPOLL_SUPPORT */
3571  request->in_idle = false;
3572  return ret;
3573 }
3574 
3575 
3589 // FIXME: rename connection->request?
3590 int
3592  bool read_ready,
3593  bool write_ready,
3594  bool force_close)
3595 {
3596  struct MHD_Daemon *daemon = con->daemon;
3597  int ret;
3598  bool states_info_processed = false;
3599  /* Fast track flag */
3600  bool on_fasttrack = (con->request.state == MHD_REQUEST_INIT);
3601 
3602 #ifdef HTTPS_SUPPORT
3603  if (con->tls_read_ready)
3604  read_ready = true;
3605 #endif /* HTTPS_SUPPORT */
3606  if (! force_close)
3607  {
3608  if ( (MHD_EVENT_LOOP_INFO_READ ==
3609  con->request.event_loop_info) &&
3610  read_ready)
3611  {
3613  ret = MHD_request_handle_idle_ (&con->request);
3614  states_info_processed = true;
3615  }
3616  /* No need to check value of 'ret' here as closed connection
3617  * cannot be in MHD_EVENT_LOOP_INFO_WRITE state. */
3618  if ( (MHD_EVENT_LOOP_INFO_WRITE ==
3619  con->request.event_loop_info) &&
3620  write_ready)
3621  {
3623  ret = MHD_request_handle_idle_ (&con->request);
3624  states_info_processed = true;
3625  }
3626  }
3627  else
3628  {
3629  MHD_connection_close_ (con,
3631  return MHD_request_handle_idle_ (&con->request);
3632  }
3633 
3634  if (! states_info_processed)
3635  { /* Connection is not read or write ready, but external conditions
3636  * may be changed and need to be processed. */
3637  ret = MHD_request_handle_idle_ (&con->request);
3638  }
3639  /* Fast track for fast connections. */
3640  /* If full request was read by single read_handler() invocation
3641  and headers were completely prepared by single MHD_request_handle_idle_()
3642  then try not to wait for next sockets polling and send response
3643  immediately.
3644  As writeability of socket was not checked and it may have
3645  some data pending in system buffers, use this optimization
3646  only for non-blocking sockets. */
3647  /* No need to check 'ret' as connection is always in
3648  * MHD_CONNECTION_CLOSED state if 'ret' is equal 'MHD_NO'. */
3649  else if (on_fasttrack &&
3650  con->sk_nonblck)
3651  {
3653  {
3655  /* Always call 'MHD_request_handle_idle_()' after each read/write. */
3656  ret = MHD_request_handle_idle_ (&con->request);
3657  }
3658  /* If all headers were sent by single write_handler() and
3659  * response body is prepared by single MHD_request_handle_idle_()
3660  * call - continue. */
3663  {
3665  ret = MHD_request_handle_idle_ (&con->request);
3666  }
3667  }
3668 
3669  /* All connection's data and states are processed for this turn.
3670  * If connection already has more data to be processed - use
3671  * zero timeout for next select()/poll(). */
3672  /* Thread-per-connection do not need global zero timeout as
3673  * connections are processed individually. */
3674  /* Note: no need to check for read buffer availability for
3675  * TLS read-ready connection in 'read info' state as connection
3676  * without space in read buffer will be market as 'info block'. */
3677  if ( (! daemon->data_already_pending) &&
3678  (MHD_TM_THREAD_PER_CONNECTION != daemon->threading_mode) )
3679  {
3681  con->request.event_loop_info)
3682  daemon->data_already_pending = true;
3683 #ifdef HTTPS_SUPPORT
3684  else if ( (con->tls_read_ready) &&
3686  con->request.event_loop_info) )
3687  daemon->data_already_pending = true;
3688 #endif /* HTTPS_SUPPORT */
3689  }
3690  return ret;
3691 }
3692 
3693 /* end of connection_call_handlers.c */
#define check_response_header_s_token_ci(r, k, tkn)
#define SSIZE_MAX
Definition: mhd_limits.h:111
static void parse_request_headers(struct MHD_Request *request)
#define MHD_send_(s, b, l)
Definition: mhd_sockets.h:259
size_t continue_message_write_offset
Definition: internal.h:541
struct MHD_Request request
Definition: internal.h:714
enum MHD_EventLoopSyscall event_loop_syscall
Definition: internal.h:1433
#define MHD_HTTP_HEADER_DATE
Definition: microhttpd.h:553
#define MHD_PANIC(msg)
Definition: internal.h:68
#define REQUEST_LACKS_HOST
uint64_t total_size
Definition: internal.h:1639
#define HTTP_100_CONTINUE
uint64_t fd_off
Definition: internal.h:1650
bool data_already_pending
Definition: internal.h:1497
size_t connection_memory_limit_b
Definition: internal.h:1278
static void get_date_string(char *date, size_t date_len)
MHD_EarlyUriLogCallback early_uri_logger_cb
Definition: internal.h:1033
bool in_cleanup
Definition: internal.h:568
struct MHD_Connection * cleanup_head
Definition: internal.h:1174
void * data
Definition: microhttpd.h:2959
size_t MHD_str_to_uint64_(const char *str, uint64_t *out_val)
Definition: mhd_str.c:450
void * mhd_panic_cls
Definition: panic.c:36
#define OFF_T_MAX
Definition: mhd_limits.h:123
size_t header_size
Definition: internal.h:499
size_t read_buffer_offset
Definition: internal.h:477
#define MHD_mutex_unlock_chk_(pmutex)
Definition: mhd_locks.h:177
MHD_PanicCallback mhd_panic
Definition: panic.c:31
void * termination_cb_cls
Definition: internal.h:1614
#define INTERNAL_ERROR
#define MHD_socket_get_error_()
Definition: mhd_sockets.h:507
uint64_t current_chunk_size
Definition: internal.h:513
enum MHD_ProtocolStrictLevel protocol_strict_level
Definition: internal.h:1439
#define MHD_HTTP_HEADER_HOST
Definition: microhttpd.h:563
static bool check_response_header_token_ci(const struct MHD_Response *response, const char *key, const char *token, size_t token_len)
#define MHD_YES
Definition: microhttpd.h:140
#define SIZE_MAX
Definition: mhd_limits.h:99
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
struct MHD_Response * response
Definition: internal.h:675
char * data
Definition: internal.h:1585
char * colon
Definition: internal.h:756
MHD_RequestTerminationCallback termination_cb
Definition: internal.h:1609
#define REQUEST_MALFORMED
char * read_buffer
Definition: internal.h:430
#define MHD_HTTP_NOT_MODIFIED
Definition: microhttpd.h:356
char * colon
Definition: internal.h:453
const char * MHD_request_lookup_value(struct MHD_Request *request, enum MHD_ValueKind kind, const char *key)
Definition: request.c:138
static bool build_header_response(struct MHD_Request *request)
#define MHD_ERR_AGAIN_
Definition: internal.h:1864
bool MHD_str_has_token_caseless_(const char *str, const char *const token, size_t token_len)
Definition: mhd_str.c:393
bool MHD_parse_arguments_(struct MHD_Request *request, enum MHD_ValueKind kind, char *args, MHD_ArgumentIterator_ cb, unsigned int *num_headers)
Definition: internal.c:186
struct MHD_Connection * manual_timeout_head
Definition: internal.h:1140
MHD_REQUEST_STATE
Definition: internal.h:213
size_t data_size
Definition: internal.h:1656
int MHD_str_equal_caseless_(const char *str1, const char *str2)
Definition: mhd_str.c:329
time_t MHD_monotonic_sec_counter(void)
char * value
Definition: internal.h:349
static bool check_write_done(struct MHD_Request *request, enum MHD_REQUEST_STATE next_state)
enum MHD_ValueKind kind
Definition: internal.h:355
bool in_idle
Definition: internal.h:562
static void cleanup_connection(struct MHD_Connection *connection)
size_t write_buffer_size
Definition: internal.h:482
#define MHD_SCKT_ERR_IS_EAGAIN_(err)
Definition: mhd_sockets.h:622
static bool try_ready_chunked_body(struct MHD_Request *request)
#define MHD_lookup_header_s_token_ci(r, h, tkn)
uint64_t current_chunk_offset
Definition: internal.h:519
internal shared structures
static void transmit_error_response(struct MHD_Request *request, enum MHD_StatusCode ec, enum MHD_HTTP_StatusCode status_code, const char *message)
static enum MHD_Method method_string_to_enum(const char *method)
#define MHD_ERR_CONNRESET_
Definition: internal.h:1869
char * header
Definition: internal.h:344
static bool socket_start_extra_buffering(struct MHD_Connection *connection)
#define MHD_UNSIGNED_LONG_LONG
Definition: microhttpd.h:283
struct MHD_Daemon * daemon
Definition: internal.h:672
int MHD_response_execute_upgrade_(struct MHD_Response *response, struct MHD_Connection *connection)
static bool socket_start_normal_buffering(struct MHD_Connection *connection)
function to update last activity of a connection
time_t connection_default_timeout
Definition: internal.h:1368
#define MHD_HTTP_HEADER_COOKIE
Definition: microhttpd.h:673
enum MHD_REQUEST_STATE state
Definition: internal.h:546
enum MHD_ConnKeepAlive keepalive
Definition: internal.h:423
static bool MHD_lookup_header_token_ci(const struct MHD_Request *request, const char *header, const char *token, size_t token_len)
struct MHD_Daemon * daemon
Definition: internal.h:369
bool v10_only
Definition: internal.h:1682
void * MHD_pool_reset(struct MemoryPool *pool, void *keep, size_t copy_bytes, size_t new_size)
Definition: memorypool.c:314
#define DLL_insert(head, tail, element)
Definition: internal.h:1742
#define MHD_HTTP_URI_TOO_LONG
Definition: microhttpd.h:395
static bool process_header_line(struct MHD_Request *request, char *line)
static void MHD_request_handle_read_(struct MHD_Request *request)
struct MHD_HTTP_Header * first_header
Definition: internal.h:1579
#define MHD_socket_last_strerr_()
Definition: mhd_sockets.h:532
size_t data_buffer_size
Definition: internal.h:1661
void * unescape_cb_cls
Definition: internal.h:1060
void * crc_cls
Definition: internal.h:1591
struct MHD_Connection * connections_tail
Definition: internal.h:1157
#define MHD_SENFILE_CHUNK_THR_P_C_
void * MHD_pool_allocate(struct MemoryPool *pool, size_t size, int from_end)
Definition: memorypool.c:203
#define REQUEST_TOO_BIG
char * write_buffer
Definition: internal.h:436
#define MHD_SCKT_EBADF_
Definition: mhd_sockets.h:438
functions to close connection
struct MHD_Response * MHD_response_from_buffer(enum MHD_HTTP_StatusCode sc, size_t size, void *buffer, enum MHD_ResponseMemoryMode mode)
ActionCallback action
Definition: internal.h:1551
static bool socket_start_no_buffering(struct MHD_Connection *connection)
size_t read_buffer_size
Definition: internal.h:471
MHD_UnescapeCallback unescape_cb
Definition: internal.h:1055
static bool process_broken_line(struct MHD_Request *request, char *line, enum MHD_ValueKind kind)
MHD_socket socket_fd
Definition: internal.h:749
size_t MHD_strx_to_uint64_n_(const char *str, size_t maxlen, uint64_t *out_val)
Definition: mhd_str.c:666
enum MHD_HTTP_StatusCode status_code
Definition: internal.h:1666
size_t connection_memory_increment_b
Definition: internal.h:1293
void * MHD_pool_reallocate(struct MemoryPool *pool, void *old, size_t old_size, size_t new_size)
Definition: memorypool.c:248
struct MHD_Connection * connections_head
Definition: internal.h:1152
static bool socket_start_no_buffering_flush(struct MHD_Connection *connection)
#define MHD_HTTP_NO_CONTENT
Definition: microhttpd.h:334
void MHD_connection_close_(struct MHD_Connection *connection, enum MHD_RequestTerminationCode rtc)
uint64_t remaining_upload_size
Definition: internal.h:505
time_t connection_timeout
Definition: internal.h:742
#define MHD_SCKT_ERR_IS_(err, code)
Definition: mhd_sockets.h:591
enum MHD_RequestEventLoopInfo event_loop_info
Definition: internal.h:556
#define MHD_CONTENT_READER_END_OF_STREAM
Definition: microhttpd.h:166
struct MHD_Connection * manual_timeout_tail
Definition: internal.h:1147
function to call event handlers based on event mask
static bool need_100_continue(struct MHD_Request *request)
#define NULL
Definition: reason_phrase.c:30
char * last
Definition: internal.h:747
static bool socket_flush_possible(struct MHD_Connection *connection)
static int parse_cookie_header(struct MHD_Request *request)
MHD_RequestCallback rc
Definition: internal.h:1002
MHD_ValueKind
Definition: microhttpd.h:1695
char * version_s
Definition: internal.h:416
#define DLL_remove(head, tail, element)
Definition: internal.h:1762
static bool try_grow_read_buffer(struct MHD_Request *request)
ReceiveCallback recv_cls
Definition: internal.h:703
enum MHD_Method method
Definition: internal.h:551
#define MHD_STATICSTR_LEN_(macro)
Definition: mhd_str.h:45
uint64_t data_start
Definition: internal.h:1645
bool have_chunked_upload
Definition: internal.h:577
#define MHD_HTTP_VERSION_1_1
Definition: microhttpd.h:856
struct MHD_Connection * normal_timeout_head
Definition: internal.h:1125
int MHD_connection_call_handlers_(struct MHD_Connection *con, bool read_ready, bool write_ready, bool force_close)
void MHD_pool_destroy(struct MemoryPool *pool)
Definition: memorypool.c:157
#define MHD_HTTP_REQUEST_HEADER_FIELDS_TOO_LARGE
Definition: microhttpd.h:422
int off_t offset
Definition: microhttpd.h:3087
static void call_request_handler(struct MHD_Request *request)
#define XDLL_remove(head, tail, element)
Definition: internal.h:1806
#define MHD_HTTP_BAD_REQUEST
Definition: microhttpd.h:367
#define MHD_ERR_BADF_
Definition: internal.h:1885
static void connection_close_error(struct MHD_Connection *connection, enum MHD_StatusCode sc, const char *emsg)
struct MHD_Connection * suspended_connections_tail
Definition: internal.h:1169
int MHD_SCKT_OPT_BOOL_
Definition: mhd_sockets.h:201
bool tls_read_ready
Definition: internal.h:766
struct MHD_itc_ itc
Definition: internal.h:1407
#define mhd_assert(CHK)
Definition: mhd_assert.h:39
time_t last_activity
Definition: internal.h:736
struct MHD_Connection * cleanup_tail
Definition: internal.h:1179
struct MHD_HTTP_Header * headers_received
Definition: internal.h:385
static void process_request_body(struct MHD_Request *request)
char * method_s
Definition: internal.h:404
static bool try_ready_normal_body(struct MHD_Request *request)
bool sk_nonblck
Definition: internal.h:781
#define CONNECTION_CLOSE_ERROR(c, sc, emsg)
enum MHD_ResponseFlags flags
Definition: internal.h:397
#define MHD_HTTP_HEADER_EXPECT
Definition: microhttpd.h:557
size_t write_buffer_send_offset
Definition: internal.h:487
struct MHD_HTTP_Header * next
Definition: internal.h:339
struct MHD_Connection * normal_timeout_tail
Definition: internal.h:1132
struct MHD_Response * response
Definition: internal.h:380
#define MHD_mutex_lock_chk_(pmutex)
Definition: mhd_locks.h:151
void * early_uri_logger_cb_cls
Definition: internal.h:1038
#define MHD_HTTP_HEADER_CONNECTION
Definition: microhttpd.h:539
bool read_closed
Definition: internal.h:789
bool suppress_date
Definition: internal.h:1453
static bool request_add_header(struct MHD_Request *request, const char *key, const char *value, enum MHD_ValueKind kind)
#define MHD_HTTP_VERSION_1_0
Definition: microhttpd.h:855
struct MemoryPool * pool
Definition: internal.h:682
TransmitCallback send_cls
Definition: internal.h:708
void * rc_cls
Definition: internal.h:1007
static bool keepalive_possible(struct MHD_Request *request)
#define MHD_HTTP_INTERNAL_SERVER_ERROR
Definition: microhttpd.h:428
uint64_t response_write_position
Definition: internal.h:526
#define MHD_CONTENT_READER_END_WITH_ERROR
Definition: microhttpd.h:167
MHD_ContentReaderCallback crc
Definition: internal.h:1597
enum MHD_Bool(* handshake)(void *cls, struct MHD_TLS_ConnectionState *cs)
MHD_mutex_ mutex
Definition: internal.h:1634
static char * get_next_header_line(struct MHD_Request *request, size_t *line_len)
size_t write_buffer_append_offset
Definition: internal.h:493
static void MHD_request_handle_write_(struct MHD_Request *request)
#define _(String)
Definition: mhd_options.h:42
#define MHD_UNSIGNED_LONG_LONG_PRINTF
Definition: microhttpd.h:296
struct MHD_Connection * connection
Definition: internal.h:374
bool suspended
Definition: internal.h:761
#define MHD_HTTP_HEADER_CONTENT_LENGTH
Definition: microhttpd.h:545
#define MHD_HTTP_PROCESSING
Definition: microhttpd.h:321
const char * url
Definition: internal.h:410
#define MHD_SIZE_UNKNOWN
Definition: microhttpd.h:159
#define MHD_MIN(a, b)
Definition: internal.h:107
struct MHD_Connection * suspended_connections_head
Definition: internal.h:1163
size_t read_buffer_offset
Definition: internal.h:784
static void connection_update_event_loop_info(struct MHD_Connection *connection)
#define MHD_NO
Definition: microhttpd.h:145
enum MHD_ThreadingMode threading_mode
Definition: internal.h:1414
void * client_context
Definition: internal.h:398
char * last
Definition: internal.h:444
#define MHD_SCKT_ERR_IS_EINTR_(err)
Definition: mhd_sockets.h:613
#define MHD_SENFILE_CHUNK_
void MHD_connection_update_last_activity_(struct MHD_Connection *connection)
bool MHD_request_handle_idle_(struct MHD_Request *request)
enum MHD_Bool(* idle_ready)(void *cls, struct MHD_TLS_ConnectionState *cs)
MHD_mutex_ cleanup_connection_mutex
Definition: internal.h:1262
static bool parse_initial_message_line(struct MHD_Request *request, char *line, size_t line_len)
_MHD_EXTERN const char * MHD_get_reason_phrase_for(unsigned int code)
#define MHD_HTTP_HEADER_TRANSFER_ENCODING
Definition: microhttpd.h:601
const char * MHD_response_get_header(struct MHD_Response *response, const char *key)
Definition: response.c:243
enum MHD_Bool(* update_event_loop_info)(void *cls, struct MHD_TLS_ConnectionState *cs, enum MHD_RequestEventLoopInfo *eli)
void MHD_response_queue_for_destroy(struct MHD_Response *response)
Definition: response.c:88