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