aboutsummaryrefslogtreecommitdiff
path: root/src/lib/connection_call_handlers.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/connection_call_handlers.c')
-rw-r--r--src/lib/connection_call_handlers.c146
1 files changed, 146 insertions, 0 deletions
diff --git a/src/lib/connection_call_handlers.c b/src/lib/connection_call_handlers.c
new file mode 100644
index 00000000..3ded0ebd
--- /dev/null
+++ b/src/lib/connection_call_handlers.c
@@ -0,0 +1,146 @@
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*/
19/**
20 * @file lib/connection_call_handlers.c
21 * @brief call the connection's handlers based on the event trigger
22 * @author Christian Grothoff
23 */
24#include "internal.h"
25#include "connection_call_handlers.h"
26#include "connection_close.h"
27
28
29/**
30 * Call the handlers for a connection in the appropriate order based
31 * on the readiness as detected by the event loop.
32 *
33 * @param con connection to handle
34 * @param read_ready set if the socket is ready for reading
35 * @param write_ready set if the socket is ready for writing
36 * @param force_close set if a hard error was detected on the socket;
37 * if this information is not available, simply pass #MHD_NO
38 * @return #MHD_YES to continue normally,
39 * #MHD_NO if a serious error was encountered and the
40 * connection is to be closed.
41 */
42// FIXME: rename connection->request?
43int
44MHD_connection_call_handlers_ (struct MHD_Connection *con,
45 bool read_ready,
46 bool write_ready,
47 bool force_close)
48{
49 struct MHD_Daemon *daemon = con->daemon;
50 int ret;
51 bool states_info_processed = false;
52 /* Fast track flag */
53 bool on_fasttrack = (con->request.state == MHD_REQUEST_INIT);
54
55#ifdef HTTPS_SUPPORT
56 if (con->tls_read_ready)
57 read_ready = true;
58#endif /* HTTPS_SUPPORT */
59 if (!force_close)
60 {
61 if ( (MHD_EVENT_LOOP_INFO_READ ==
62 con->request.event_loop_info) &&
63 read_ready)
64 {
65 MHD_connection_handle_read (con);
66 ret = MHD_connection_handle_idle (con);
67 states_info_processed = true;
68 }
69 /* No need to check value of 'ret' here as closed connection
70 * cannot be in MHD_EVENT_LOOP_INFO_WRITE state. */
71 if ( (MHD_EVENT_LOOP_INFO_WRITE ==
72 con->request.event_loop_info) &&
73 write_ready)
74 {
75 MHD_connection_handle_write (con);
76 ret = MHD_connection_handle_idle (con);
77 states_info_processed = true;
78 }
79 }
80 else
81 {
82 MHD_connection_close_ (con,
83 MHD_REQUEST_TERMINATED_WITH_ERROR);
84 return MHD_connection_handle_idle (con);
85 }
86
87 if (! states_info_processed)
88 { /* Connection is not read or write ready, but external conditions
89 * may be changed and need to be processed. */
90 ret = MHD_connection_handle_idle (con);
91 }
92 /* Fast track for fast connections. */
93 /* If full request was read by single read_handler() invocation
94 and headers were completely prepared by single MHD_connection_handle_idle()
95 then try not to wait for next sockets polling and send response
96 immediately.
97 As writeability of socket was not checked and it may have
98 some data pending in system buffers, use this optimization
99 only for non-blocking sockets. */
100 /* No need to check 'ret' as connection is always in
101 * MHD_CONNECTION_CLOSED state if 'ret' is equal 'MHD_NO'. */
102 else if (on_fasttrack &&
103 con->sk_nonblck)
104 {
105 if (MHD_REQUEST_HEADERS_SENDING == con->request.state)
106 {
107 MHD_connection_handle_write (con);
108 /* Always call 'MHD_connection_handle_idle()' after each read/write. */
109 ret = MHD_connection_handle_idle (con);
110 }
111 /* If all headers were sent by single write_handler() and
112 * response body is prepared by single MHD_connection_handle_idle()
113 * call - continue. */
114 if ((MHD_REQUEST_NORMAL_BODY_READY == con->request.state) ||
115 (MHD_REQUEST_CHUNKED_BODY_READY == con->request.state))
116 {
117 MHD_connection_handle_write (con);
118 ret = MHD_connection_handle_idle (con);
119 }
120 }
121
122 /* All connection's data and states are processed for this turn.
123 * If connection already has more data to be processed - use
124 * zero timeout for next select()/poll(). */
125 /* Thread-per-connection do not need global zero timeout as
126 * connections are processed individually. */
127 /* Note: no need to check for read buffer availability for
128 * TLS read-ready connection in 'read info' state as connection
129 * without space in read buffer will be market as 'info block'. */
130 if ( (! daemon->data_already_pending) &&
131 (MHD_TM_THREAD_PER_CONNECTION != daemon->threading_model) )
132 {
133 if (MHD_EVENT_LOOP_INFO_BLOCK ==
134 con->request.event_loop_info)
135 daemon->data_already_pending = true;
136#ifdef HTTPS_SUPPORT
137 else if ( (con->tls_read_ready) &&
138 (MHD_EVENT_LOOP_INFO_READ ==
139 con->request.event_loop_info) )
140 daemon->data_already_pending = true;
141#endif /* HTTPS_SUPPORT */
142 }
143 return ret;
144}
145
146/* end of connection_call_handlers.c */