diff options
author | Christian Grothoff <christian@grothoff.org> | 2018-02-17 04:02:42 +0100 |
---|---|---|
committer | Christian Grothoff <christian@grothoff.org> | 2018-02-17 04:02:42 +0100 |
commit | a5fa8a08ef2cf017444cfa476cb3d932c1f6ba74 (patch) | |
tree | eea7f8d5d151b8e5113b93890a597de60e5b4c48 /src/lib | |
parent | c0ac86b069fac3460fd2e4c7997245c5a1281536 (diff) | |
download | libmicrohttpd-a5fa8a08ef2cf017444cfa476cb3d932c1f6ba74.tar.gz libmicrohttpd-a5fa8a08ef2cf017444cfa476cb3d932c1f6ba74.zip |
more work on connnection_call_handlers.c
Diffstat (limited to 'src/lib')
-rw-r--r-- | src/lib/connection_add.c | 6 | ||||
-rw-r--r-- | src/lib/connection_call_handlers.c | 1433 | ||||
-rw-r--r-- | src/lib/connection_cleanup.c | 2 | ||||
-rw-r--r-- | src/lib/internal.h | 27 | ||||
-rw-r--r-- | src/lib/request.c | 2 |
5 files changed, 1447 insertions, 23 deletions
diff --git a/src/lib/connection_add.c b/src/lib/connection_add.c index c4150b1e..b2b6a9af 100644 --- a/src/lib/connection_add.c +++ b/src/lib/connection_add.c | |||
@@ -732,9 +732,9 @@ internal_add_connection (struct MHD_Daemon *daemon, | |||
732 | errno = eno; | 732 | errno = eno; |
733 | return MHD_SC_CONNECTION_MALLOC_FAILURE; | 733 | return MHD_SC_CONNECTION_MALLOC_FAILURE; |
734 | } | 734 | } |
735 | connection->request.pool | 735 | connection->pool |
736 | = MHD_pool_create (daemon->connection_memory_limit_b); | 736 | = MHD_pool_create (daemon->connection_memory_limit_b); |
737 | if (NULL == connection->request.pool) | 737 | if (NULL == connection->pool) |
738 | { | 738 | { |
739 | #ifdef HAVE_MESSAGES | 739 | #ifdef HAVE_MESSAGES |
740 | MHD_DLOG (daemon, | 740 | MHD_DLOG (daemon, |
@@ -919,7 +919,7 @@ internal_add_connection (struct MHD_Daemon *daemon, | |||
919 | daemon->connections_tail, | 919 | daemon->connections_tail, |
920 | connection); | 920 | connection); |
921 | MHD_mutex_unlock_chk_ (&daemon->cleanup_connection_mutex); | 921 | MHD_mutex_unlock_chk_ (&daemon->cleanup_connection_mutex); |
922 | MHD_pool_destroy (connection->request.pool); | 922 | MHD_pool_destroy (connection->pool); |
923 | free (connection); | 923 | free (connection); |
924 | if (0 != eno) | 924 | if (0 != eno) |
925 | errno = eno; | 925 | errno = eno; |
diff --git a/src/lib/connection_call_handlers.c b/src/lib/connection_call_handlers.c index 3ded0ebd..1eac9c10 100644 --- a/src/lib/connection_call_handlers.c +++ b/src/lib/connection_call_handlers.c | |||
@@ -23,8 +23,1431 @@ | |||
23 | */ | 23 | */ |
24 | #include "internal.h" | 24 | #include "internal.h" |
25 | #include "connection_call_handlers.h" | 25 | #include "connection_call_handlers.h" |
26 | #include "connection_update_last_activity.h" | ||
26 | #include "connection_close.h" | 27 | #include "connection_close.h" |
27 | 28 | ||
29 | #ifdef MHD_LINUX_SOLARIS_SENDFILE | ||
30 | #include <sys/sendfile.h> | ||
31 | #endif /* MHD_LINUX_SOLARIS_SENDFILE */ | ||
32 | #if defined(HAVE_FREEBSD_SENDFILE) || defined(HAVE_DARWIN_SENDFILE) | ||
33 | #include <sys/types.h> | ||
34 | #include <sys/socket.h> | ||
35 | #include <sys/uio.h> | ||
36 | #endif /* HAVE_FREEBSD_SENDFILE || HAVE_DARWIN_SENDFILE */ | ||
37 | |||
38 | |||
39 | /** | ||
40 | * sendfile() chuck size | ||
41 | */ | ||
42 | #define MHD_SENFILE_CHUNK_ (0x20000) | ||
43 | |||
44 | /** | ||
45 | * sendfile() chuck size for thread-per-connection | ||
46 | */ | ||
47 | #define MHD_SENFILE_CHUNK_THR_P_C_ (0x200000) | ||
48 | |||
49 | #ifdef HAVE_FREEBSD_SENDFILE | ||
50 | #ifdef SF_FLAGS | ||
51 | /** | ||
52 | * FreeBSD sendfile() flags | ||
53 | */ | ||
54 | static int freebsd_sendfile_flags_; | ||
55 | |||
56 | /** | ||
57 | * FreeBSD sendfile() flags for thread-per-connection | ||
58 | */ | ||
59 | static int freebsd_sendfile_flags_thd_p_c_; | ||
60 | #endif /* SF_FLAGS */ | ||
61 | |||
62 | |||
63 | /** | ||
64 | * Initialises static variables. | ||
65 | * | ||
66 | * FIXME: make sure its actually called! | ||
67 | */ | ||
68 | void | ||
69 | MHD_conn_init_static_ (void) | ||
70 | { | ||
71 | /* FreeBSD 11 and later allow to specify read-ahead size | ||
72 | * and handles SF_NODISKIO differently. | ||
73 | * SF_FLAGS defined only on FreeBSD 11 and later. */ | ||
74 | #ifdef SF_FLAGS | ||
75 | long sys_page_size = sysconf (_SC_PAGESIZE); | ||
76 | if (0 > sys_page_size) | ||
77 | { /* Failed to get page size. */ | ||
78 | freebsd_sendfile_flags_ = SF_NODISKIO; | ||
79 | freebsd_sendfile_flags_thd_p_c_ = SF_NODISKIO; | ||
80 | } | ||
81 | else | ||
82 | { | ||
83 | freebsd_sendfile_flags_ = | ||
84 | SF_FLAGS((uint16_t)(MHD_SENFILE_CHUNK_ / sys_page_size), SF_NODISKIO); | ||
85 | freebsd_sendfile_flags_thd_p_c_ = | ||
86 | SF_FLAGS((uint16_t)(MHD_SENFILE_CHUNK_THR_P_C_ / sys_page_size), SF_NODISKIO); | ||
87 | } | ||
88 | #endif /* SF_FLAGS */ | ||
89 | } | ||
90 | #endif /* HAVE_FREEBSD_SENDFILE */ | ||
91 | |||
92 | |||
93 | |||
94 | /** | ||
95 | * Message to transmit when http 1.1 request is received | ||
96 | */ | ||
97 | #define HTTP_100_CONTINUE "HTTP/1.1 100 Continue\r\n\r\n" | ||
98 | |||
99 | |||
100 | /** | ||
101 | * A serious error occured, close the | ||
102 | * connection (and notify the application). | ||
103 | * | ||
104 | * @param connection connection to close with error | ||
105 | * @param sc the reason for closing the connection | ||
106 | * @param emsg error message (can be NULL) | ||
107 | */ | ||
108 | static void | ||
109 | connection_close_error (struct MHD_Connection *connection, | ||
110 | enum MHD_StatusCode sc, | ||
111 | const char *emsg) | ||
112 | { | ||
113 | #ifdef HAVE_MESSAGES | ||
114 | if (NULL != emsg) | ||
115 | MHD_DLOG (connection->daemon, | ||
116 | sc, | ||
117 | emsg); | ||
118 | #else /* ! HAVE_MESSAGES */ | ||
119 | (void) emsg; /* Mute compiler warning. */ | ||
120 | (void) sc; | ||
121 | #endif /* ! HAVE_MESSAGES */ | ||
122 | MHD_connection_close_ (connection, | ||
123 | MHD_REQUEST_TERMINATED_WITH_ERROR); | ||
124 | } | ||
125 | |||
126 | |||
127 | /** | ||
128 | * Macro to only include error message in call to | ||
129 | * #connection_close_error() if we have HAVE_MESSAGES. | ||
130 | */ | ||
131 | #ifdef HAVE_MESSAGES | ||
132 | #define CONNECTION_CLOSE_ERROR(c, sc, emsg) connection_close_error (c, sc, emsg) | ||
133 | #else | ||
134 | #define CONNECTION_CLOSE_ERROR(c, sc, emsg) connection_close_error (c, sc, NULL) | ||
135 | #endif | ||
136 | |||
137 | |||
138 | /** | ||
139 | * Try growing the read buffer. We initially claim half the available | ||
140 | * buffer space for the read buffer (the other half being left for | ||
141 | * management data structures; the write buffer can in the end take | ||
142 | * virtually everything as the read buffer can be reduced to the | ||
143 | * minimum necessary at that point. | ||
144 | * | ||
145 | * @param request the request for which to grow the buffer | ||
146 | * @return true on success, false on failure | ||
147 | */ | ||
148 | static bool | ||
149 | try_grow_read_buffer (struct MHD_Request *request) | ||
150 | { | ||
151 | struct MHD_Daemon *daemon = request->daemon; | ||
152 | void *buf; | ||
153 | size_t new_size; | ||
154 | |||
155 | if (0 == request->read_buffer_size) | ||
156 | new_size = daemon->connection_memory_limit_b / 2; | ||
157 | else | ||
158 | new_size = request->read_buffer_size + | ||
159 | daemon->connection_memory_increment_b; | ||
160 | buf = MHD_pool_reallocate (request->connection->pool, | ||
161 | request->read_buffer, | ||
162 | request->read_buffer_size, | ||
163 | new_size); | ||
164 | if (NULL == buf) | ||
165 | return false; | ||
166 | /* we can actually grow the buffer, do it! */ | ||
167 | request->read_buffer = buf; | ||
168 | request->read_buffer_size = new_size; | ||
169 | return true; | ||
170 | } | ||
171 | |||
172 | |||
173 | /** | ||
174 | * This function handles a particular request when it has been | ||
175 | * determined that there is data to be read off a socket. | ||
176 | * | ||
177 | * @param request request to handle | ||
178 | */ | ||
179 | static void | ||
180 | MHD_request_handle_read_ (struct MHD_Request *request) | ||
181 | { | ||
182 | struct MHD_Daemon *daemon = request->daemon; | ||
183 | struct MHD_Connection *connection = request->connection; | ||
184 | ssize_t bytes_read; | ||
185 | |||
186 | if ( (MHD_REQUEST_CLOSED == request->state) || | ||
187 | (connection->suspended) ) | ||
188 | return; | ||
189 | #ifdef HTTPS_SUPPORT | ||
190 | { | ||
191 | struct MHD_TLS_Plugin *tls; | ||
192 | |||
193 | if ( (NULL != (tls = daemon->tls_api)) && | ||
194 | (! tls->handshake (tls->cls, | ||
195 | connection->tls_cs)) ) | ||
196 | return; | ||
197 | } | ||
198 | #endif /* HTTPS_SUPPORT */ | ||
199 | |||
200 | /* make sure "read" has a reasonable number of bytes | ||
201 | in buffer to use per system call (if possible) */ | ||
202 | if (request->read_buffer_offset + | ||
203 | daemon->connection_memory_increment_b > | ||
204 | request->read_buffer_size) | ||
205 | try_grow_read_buffer (request); | ||
206 | |||
207 | if (request->read_buffer_size == request->read_buffer_offset) | ||
208 | return; /* No space for receiving data. */ | ||
209 | bytes_read = connection->recv_cls (connection, | ||
210 | &request->read_buffer | ||
211 | [request->read_buffer_offset], | ||
212 | request->read_buffer_size - | ||
213 | request->read_buffer_offset); | ||
214 | if (bytes_read < 0) | ||
215 | { | ||
216 | if (MHD_ERR_AGAIN_ == bytes_read) | ||
217 | return; /* No new data to process. */ | ||
218 | if (MHD_ERR_CONNRESET_ == bytes_read) | ||
219 | { | ||
220 | CONNECTION_CLOSE_ERROR (connection, | ||
221 | (MHD_REQUEST_INIT == request->state) | ||
222 | ? MHD_SC_CONNECTION_CLOSED | ||
223 | : MHD_SC_CONNECTION_RESET_CLOSED, | ||
224 | (MHD_REQUEST_INIT == request->state) | ||
225 | ? NULL | ||
226 | : _("Socket disconnected while reading request.\n")); | ||
227 | return; | ||
228 | } | ||
229 | CONNECTION_CLOSE_ERROR (connection, | ||
230 | (MHD_REQUEST_INIT == request->state) | ||
231 | ? MHD_SC_CONNECTION_CLOSED | ||
232 | : MHD_SC_CONNECTION_READ_FAIL_CLOSED, | ||
233 | (MHD_REQUEST_INIT == request->state) | ||
234 | ? NULL | ||
235 | : _("Connection socket is closed due to error when reading request.\n")); | ||
236 | return; | ||
237 | } | ||
238 | |||
239 | if (0 == bytes_read) | ||
240 | { /* Remote side closed connection. */ | ||
241 | connection->read_closed = true; | ||
242 | MHD_connection_close_ (connection, | ||
243 | MHD_REQUEST_TERMINATED_CLIENT_ABORT); | ||
244 | return; | ||
245 | } | ||
246 | request->read_buffer_offset += bytes_read; | ||
247 | MHD_connection_update_last_activity_ (connection); | ||
248 | #if DEBUG_STATES | ||
249 | MHD_DLOG (daemon, | ||
250 | MHD_SC_STATE_MACHINE_STATUS_REPORT, | ||
251 | _("In function %s handling connection at state: %s\n"), | ||
252 | __FUNCTION__, | ||
253 | MHD_state_to_string (request->state)); | ||
254 | #endif | ||
255 | switch (request->state) | ||
256 | { | ||
257 | case MHD_REQUEST_INIT: | ||
258 | case MHD_REQUEST_URL_RECEIVED: | ||
259 | case MHD_REQUEST_HEADER_PART_RECEIVED: | ||
260 | case MHD_REQUEST_HEADERS_RECEIVED: | ||
261 | case MHD_REQUEST_HEADERS_PROCESSED: | ||
262 | case MHD_REQUEST_CONTINUE_SENDING: | ||
263 | case MHD_REQUEST_CONTINUE_SENT: | ||
264 | case MHD_REQUEST_BODY_RECEIVED: | ||
265 | case MHD_REQUEST_FOOTER_PART_RECEIVED: | ||
266 | /* nothing to do but default action */ | ||
267 | if (connection->read_closed) | ||
268 | { | ||
269 | MHD_connection_close_ (connection, | ||
270 | MHD_REQUEST_TERMINATED_READ_ERROR); | ||
271 | } | ||
272 | return; | ||
273 | case MHD_REQUEST_CLOSED: | ||
274 | return; | ||
275 | #ifdef UPGRADE_SUPPORT | ||
276 | case MHD_REQUEST_UPGRADE: | ||
277 | mhd_assert (0); | ||
278 | return; | ||
279 | #endif /* UPGRADE_SUPPORT */ | ||
280 | default: | ||
281 | /* shrink read buffer to how much is actually used */ | ||
282 | MHD_pool_reallocate (connection->pool, | ||
283 | request->read_buffer, | ||
284 | request->read_buffer_size + 1, | ||
285 | request->read_buffer_offset); | ||
286 | break; | ||
287 | } | ||
288 | return; | ||
289 | } | ||
290 | |||
291 | |||
292 | #if defined(_MHD_HAVE_SENDFILE) | ||
293 | /** | ||
294 | * Function for sending responses backed by file FD. | ||
295 | * | ||
296 | * @param connection the MHD connection structure | ||
297 | * @return actual number of bytes sent | ||
298 | */ | ||
299 | static ssize_t | ||
300 | sendfile_adapter (struct MHD_Connection *connection) | ||
301 | { | ||
302 | struct MHD_Daemon *daemon = connection->daemon; | ||
303 | struct MHD_Request *request = &connection->request; | ||
304 | struct MHD_Response *response = request->response; | ||
305 | ssize_t ret; | ||
306 | const int file_fd = response->fd; | ||
307 | uint64_t left; | ||
308 | uint64_t offsetu64; | ||
309 | #ifndef HAVE_SENDFILE64 | ||
310 | const uint64_t max_off_t = (uint64_t)OFF_T_MAX; | ||
311 | #else /* HAVE_SENDFILE64 */ | ||
312 | const uint64_t max_off_t = (uint64_t)OFF64_T_MAX; | ||
313 | #endif /* HAVE_SENDFILE64 */ | ||
314 | #ifdef MHD_LINUX_SOLARIS_SENDFILE | ||
315 | #ifndef HAVE_SENDFILE64 | ||
316 | off_t offset; | ||
317 | #else /* HAVE_SENDFILE64 */ | ||
318 | off64_t offset; | ||
319 | #endif /* HAVE_SENDFILE64 */ | ||
320 | #endif /* MHD_LINUX_SOLARIS_SENDFILE */ | ||
321 | #ifdef HAVE_FREEBSD_SENDFILE | ||
322 | off_t sent_bytes; | ||
323 | int flags = 0; | ||
324 | #endif | ||
325 | #ifdef HAVE_DARWIN_SENDFILE | ||
326 | off_t len; | ||
327 | #endif /* HAVE_DARWIN_SENDFILE */ | ||
328 | const bool used_thr_p_c = (MHD_TM_THREAD_PER_CONNECTION == daemon->threading_model); | ||
329 | const size_t chunk_size = used_thr_p_c ? MHD_SENFILE_CHUNK_THR_P_C_ : MHD_SENFILE_CHUNK_; | ||
330 | size_t send_size = 0; | ||
331 | |||
332 | mhd_assert (MHD_resp_sender_sendfile == request->resp_sender); | ||
333 | offsetu64 = request->response_write_position + response->fd_off; | ||
334 | left = response->total_size - request->response_write_position; | ||
335 | /* Do not allow system to stick sending on single fast connection: | ||
336 | * use 128KiB chunks (2MiB for thread-per-connection). */ | ||
337 | send_size = (left > chunk_size) ? chunk_size : (size_t) left; | ||
338 | if (max_off_t < offsetu64) | ||
339 | { /* Retry to send with standard 'send()'. */ | ||
340 | request->resp_sender = MHD_resp_sender_std; | ||
341 | return MHD_ERR_AGAIN_; | ||
342 | } | ||
343 | #ifdef MHD_LINUX_SOLARIS_SENDFILE | ||
344 | #ifndef HAVE_SENDFILE64 | ||
345 | offset = (off_t) offsetu64; | ||
346 | ret = sendfile (connection->socket_fd, | ||
347 | file_fd, | ||
348 | &offset, | ||
349 | send_size); | ||
350 | #else /* HAVE_SENDFILE64 */ | ||
351 | offset = (off64_t) offsetu64; | ||
352 | ret = sendfile64 (connection->socket_fd, | ||
353 | file_fd, | ||
354 | &offset, | ||
355 | send_size); | ||
356 | #endif /* HAVE_SENDFILE64 */ | ||
357 | if (0 > ret) | ||
358 | { | ||
359 | const int err = MHD_socket_get_error_(); | ||
360 | |||
361 | if (MHD_SCKT_ERR_IS_EAGAIN_(err)) | ||
362 | { | ||
363 | #ifdef EPOLL_SUPPORT | ||
364 | /* EAGAIN --- no longer write-ready */ | ||
365 | connection->epoll_state &= ~MHD_EPOLL_STATE_WRITE_READY; | ||
366 | #endif /* EPOLL_SUPPORT */ | ||
367 | return MHD_ERR_AGAIN_; | ||
368 | } | ||
369 | if (MHD_SCKT_ERR_IS_EINTR_ (err)) | ||
370 | return MHD_ERR_AGAIN_; | ||
371 | #ifdef HAVE_LINUX_SENDFILE | ||
372 | if (MHD_SCKT_ERR_IS_(err, | ||
373 | MHD_SCKT_EBADF_)) | ||
374 | return MHD_ERR_BADF_; | ||
375 | /* sendfile() failed with EINVAL if mmap()-like operations are not | ||
376 | supported for FD or other 'unusual' errors occurred, so we should try | ||
377 | to fall back to 'SEND'; see also this thread for info on | ||
378 | odd libc/Linux behavior with sendfile: | ||
379 | http://lists.gnu.org/archive/html/libmicrohttpd/2011-02/msg00015.html */ | ||
380 | request->resp_sender = MHD_resp_sender_std; | ||
381 | return MHD_ERR_AGAIN_; | ||
382 | #else /* HAVE_SOLARIS_SENDFILE */ | ||
383 | if ( (EAFNOSUPPORT == err) || | ||
384 | (EINVAL == err) || | ||
385 | (EOPNOTSUPP == err) ) | ||
386 | { /* Retry with standard file reader. */ | ||
387 | request->resp_sender = MHD_resp_sender_std; | ||
388 | return MHD_ERR_AGAIN_; | ||
389 | } | ||
390 | if ( (ENOTCONN == err) || | ||
391 | (EPIPE == err) ) | ||
392 | { | ||
393 | return MHD_ERR_CONNRESET_; | ||
394 | } | ||
395 | return MHD_ERR_BADF_; /* Fail hard */ | ||
396 | #endif /* HAVE_SOLARIS_SENDFILE */ | ||
397 | } | ||
398 | #ifdef EPOLL_SUPPORT | ||
399 | else if (send_size > (size_t)ret) | ||
400 | connection->epoll_state &= ~MHD_EPOLL_STATE_WRITE_READY; | ||
401 | #endif /* EPOLL_SUPPORT */ | ||
402 | #elif defined(HAVE_FREEBSD_SENDFILE) | ||
403 | #ifdef SF_FLAGS | ||
404 | flags = used_thr_p_c ? | ||
405 | freebsd_sendfile_flags_thd_p_c_ : freebsd_sendfile_flags_; | ||
406 | #endif /* SF_FLAGS */ | ||
407 | if (0 != sendfile (file_fd, | ||
408 | connection->socket_fd, | ||
409 | (off_t) offsetu64, | ||
410 | send_size, | ||
411 | NULL, | ||
412 | &sent_bytes, | ||
413 | flags)) | ||
414 | { | ||
415 | const int err = MHD_socket_get_error_(); | ||
416 | if (MHD_SCKT_ERR_IS_EAGAIN_(err) || | ||
417 | MHD_SCKT_ERR_IS_EINTR_(err) || | ||
418 | EBUSY == err) | ||
419 | { | ||
420 | mhd_assert (SSIZE_MAX >= sent_bytes); | ||
421 | if (0 != sent_bytes) | ||
422 | return (ssize_t)sent_bytes; | ||
423 | |||
424 | return MHD_ERR_AGAIN_; | ||
425 | } | ||
426 | /* Some unrecoverable error. Possibly file FD is not suitable | ||
427 | * for sendfile(). Retry with standard send(). */ | ||
428 | request->resp_sender = MHD_resp_sender_std; | ||
429 | return MHD_ERR_AGAIN_; | ||
430 | } | ||
431 | mhd_assert (0 < sent_bytes); | ||
432 | mhd_assert (SSIZE_MAX >= sent_bytes); | ||
433 | ret = (ssize_t)sent_bytes; | ||
434 | #elif defined(HAVE_DARWIN_SENDFILE) | ||
435 | len = (off_t) send_size; /* chunk always fit */ | ||
436 | if (0 != sendfile (file_fd, | ||
437 | connection->socket_fd, | ||
438 | (off_t) offsetu64, | ||
439 | &len, | ||
440 | NULL, | ||
441 | 0)) | ||
442 | { | ||
443 | const int err = MHD_socket_get_error_(); | ||
444 | if (MHD_SCKT_ERR_IS_EAGAIN_(err) || | ||
445 | MHD_SCKT_ERR_IS_EINTR_(err)) | ||
446 | { | ||
447 | mhd_assert (0 <= len); | ||
448 | mhd_assert (SSIZE_MAX >= len); | ||
449 | mhd_assert (send_size >= (size_t)len); | ||
450 | if (0 != len) | ||
451 | return (ssize_t)len; | ||
452 | |||
453 | return MHD_ERR_AGAIN_; | ||
454 | } | ||
455 | if (ENOTCONN == err || | ||
456 | EPIPE == err) | ||
457 | return MHD_ERR_CONNRESET_; | ||
458 | if (ENOTSUP == err || | ||
459 | EOPNOTSUPP == err) | ||
460 | { /* This file FD is not suitable for sendfile(). | ||
461 | * Retry with standard send(). */ | ||
462 | request->resp_sender = MHD_resp_sender_std; | ||
463 | return MHD_ERR_AGAIN_; | ||
464 | } | ||
465 | return MHD_ERR_BADF_; /* Return hard error. */ | ||
466 | } | ||
467 | mhd_assert (0 <= len); | ||
468 | mhd_assert (SSIZE_MAX >= len); | ||
469 | mhd_assert (send_size >= (size_t)len); | ||
470 | ret = (ssize_t)len; | ||
471 | #endif /* HAVE_FREEBSD_SENDFILE */ | ||
472 | return ret; | ||
473 | } | ||
474 | #endif /* _MHD_HAVE_SENDFILE */ | ||
475 | |||
476 | |||
477 | /** | ||
478 | * Check if we are done sending the write-buffer. If so, transition | ||
479 | * into "next_state". | ||
480 | * | ||
481 | * @param connection connection to check write status for | ||
482 | * @param next_state the next state to transition to | ||
483 | * @return false if we are not done, true if we are | ||
484 | */ | ||
485 | static bool | ||
486 | check_write_done (struct MHD_Request *request, | ||
487 | enum MHD_REQUEST_STATE next_state) | ||
488 | { | ||
489 | if (request->write_buffer_append_offset != | ||
490 | request->write_buffer_send_offset) | ||
491 | return false; | ||
492 | request->write_buffer_append_offset = 0; | ||
493 | request->write_buffer_send_offset = 0; | ||
494 | request->state = next_state; | ||
495 | MHD_pool_reallocate (request->connection->pool, | ||
496 | request->write_buffer, | ||
497 | request->write_buffer_size, | ||
498 | 0); | ||
499 | request->write_buffer = NULL; | ||
500 | request->write_buffer_size = 0; | ||
501 | return true; | ||
502 | } | ||
503 | |||
504 | |||
505 | /** | ||
506 | * Prepare the response buffer of this request for sending. Assumes | ||
507 | * that the response mutex is already held. If the transmission is | ||
508 | * complete, this function may close the socket (and return false). | ||
509 | * | ||
510 | * @param request the request handle | ||
511 | * @return false if readying the response failed (the | ||
512 | * lock on the response will have been released already | ||
513 | * in this case). | ||
514 | */ | ||
515 | static bool | ||
516 | try_ready_normal_body (struct MHD_Request *request) | ||
517 | { | ||
518 | struct MHD_Response *response = request->response; | ||
519 | struct MHD_Connection *connection = request->connection; | ||
520 | ssize_t ret; | ||
521 | |||
522 | if (NULL == response->crc) | ||
523 | return true; | ||
524 | if ( (0 == response->total_size) || | ||
525 | (request->response_write_position == response->total_size) ) | ||
526 | return true; /* 0-byte response is always ready */ | ||
527 | if ( (response->data_start <= | ||
528 | request->response_write_position) && | ||
529 | (response->data_size + response->data_start > | ||
530 | request->response_write_position) ) | ||
531 | return true; /* response already ready */ | ||
532 | #if defined(_MHD_HAVE_SENDFILE) | ||
533 | if (MHD_resp_sender_sendfile == request->resp_sender) | ||
534 | { | ||
535 | /* will use sendfile, no need to bother response crc */ | ||
536 | return true; | ||
537 | } | ||
538 | #endif /* _MHD_HAVE_SENDFILE */ | ||
539 | |||
540 | ret = response->crc (response->crc_cls, | ||
541 | request->response_write_position, | ||
542 | response->data, | ||
543 | (size_t) MHD_MIN ((uint64_t) response->data_buffer_size, | ||
544 | response->total_size - | ||
545 | request->response_write_position)); | ||
546 | if ( (((ssize_t) MHD_CONTENT_READER_END_OF_STREAM) == ret) || | ||
547 | (((ssize_t) MHD_CONTENT_READER_END_WITH_ERROR) == ret) ) | ||
548 | { | ||
549 | /* either error or http 1.0 transfer, close socket! */ | ||
550 | response->total_size = request->response_write_position; | ||
551 | MHD_mutex_unlock_chk_ (&response->mutex); | ||
552 | if ( ((ssize_t)MHD_CONTENT_READER_END_OF_STREAM) == ret) | ||
553 | MHD_connection_close_ (connection, | ||
554 | MHD_REQUEST_TERMINATED_COMPLETED_OK); | ||
555 | else | ||
556 | CONNECTION_CLOSE_ERROR (connection, | ||
557 | MHD_SC_APPLICATION_DATA_GENERATION_FAILURE_CLOSED, | ||
558 | _("Closing connection (application reported error generating data)\n")); | ||
559 | return false; | ||
560 | } | ||
561 | response->data_start = request->response_write_position; | ||
562 | response->data_size = ret; | ||
563 | if (0 == ret) | ||
564 | { | ||
565 | request->state = MHD_REQUEST_NORMAL_BODY_UNREADY; | ||
566 | MHD_mutex_unlock_chk_ (&response->mutex); | ||
567 | return false; | ||
568 | } | ||
569 | return true; | ||
570 | } | ||
571 | |||
572 | |||
573 | /** | ||
574 | * Prepare the response buffer of this request for sending. Assumes | ||
575 | * that the response mutex is already held. If the transmission is | ||
576 | * complete, this function may close the socket (and return false). | ||
577 | * | ||
578 | * @param connection the connection | ||
579 | * @return false if readying the response failed | ||
580 | */ | ||
581 | static bool | ||
582 | try_ready_chunked_body (struct MHD_Request *request) | ||
583 | { | ||
584 | struct MHD_Connection *connection = request->connection; | ||
585 | struct MHD_Response *response = request->response; | ||
586 | struct MHD_Daemon *daemon = request->daemon; | ||
587 | ssize_t ret; | ||
588 | char *buf; | ||
589 | size_t size; | ||
590 | char cbuf[10]; /* 10: max strlen of "%x\r\n" */ | ||
591 | int cblen; | ||
592 | |||
593 | if (NULL == response->crc) | ||
594 | return true; | ||
595 | if (0 == request->write_buffer_size) | ||
596 | { | ||
597 | size = MHD_MIN (daemon->connection_memory_limit_b, | ||
598 | 2 * (0xFFFFFF + sizeof(cbuf) + 2)); | ||
599 | do | ||
600 | { | ||
601 | size /= 2; | ||
602 | if (size < 128) | ||
603 | { | ||
604 | MHD_mutex_unlock_chk_ (&response->mutex); | ||
605 | /* not enough memory */ | ||
606 | CONNECTION_CLOSE_ERROR (connection, | ||
607 | MHD_SC_CONNECTION_POOL_MALLOC_FAILURE, | ||
608 | _("Closing connection (out of memory)\n")); | ||
609 | return false; | ||
610 | } | ||
611 | buf = MHD_pool_allocate (connection->pool, | ||
612 | size, | ||
613 | MHD_NO); | ||
614 | } | ||
615 | while (NULL == buf); | ||
616 | request->write_buffer_size = size; | ||
617 | request->write_buffer = buf; | ||
618 | } | ||
619 | |||
620 | if (0 == response->total_size) | ||
621 | ret = 0; /* response must be empty, don't bother calling crc */ | ||
622 | else if ( (response->data_start <= | ||
623 | request->response_write_position) && | ||
624 | (response->data_start + response->data_size > | ||
625 | request->response_write_position) ) | ||
626 | { | ||
627 | /* difference between response_write_position and data_start is less | ||
628 | than data_size which is size_t type, no need to check for overflow */ | ||
629 | const size_t data_write_offset | ||
630 | = (size_t)(request->response_write_position - response->data_start); | ||
631 | /* buffer already ready, use what is there for the chunk */ | ||
632 | ret = response->data_size - data_write_offset; | ||
633 | if ( ((size_t) ret) > request->write_buffer_size - sizeof (cbuf) - 2 ) | ||
634 | ret = request->write_buffer_size - sizeof (cbuf) - 2; | ||
635 | memcpy (&request->write_buffer[sizeof (cbuf)], | ||
636 | &response->data[data_write_offset], | ||
637 | ret); | ||
638 | } | ||
639 | else | ||
640 | { | ||
641 | /* buffer not in range, try to fill it */ | ||
642 | ret = response->crc (response->crc_cls, | ||
643 | request->response_write_position, | ||
644 | &request->write_buffer[sizeof (cbuf)], | ||
645 | request->write_buffer_size - sizeof (cbuf) - 2); | ||
646 | } | ||
647 | if ( ((ssize_t) MHD_CONTENT_READER_END_WITH_ERROR) == ret) | ||
648 | { | ||
649 | /* error, close socket! */ | ||
650 | response->total_size = request->response_write_position; | ||
651 | MHD_mutex_unlock_chk_ (&response->mutex); | ||
652 | CONNECTION_CLOSE_ERROR (connection, | ||
653 | MHD_SC_APPLICATION_DATA_GENERATION_FAILURE_CLOSED, | ||
654 | _("Closing connection (application error generating response)\n")); | ||
655 | return false; | ||
656 | } | ||
657 | if ( (((ssize_t) MHD_CONTENT_READER_END_OF_STREAM) == ret) || | ||
658 | (0 == response->total_size) ) | ||
659 | { | ||
660 | /* end of message, signal other side! */ | ||
661 | strcpy (request->write_buffer, | ||
662 | "0\r\n"); | ||
663 | request->write_buffer_append_offset = 3; | ||
664 | request->write_buffer_send_offset = 0; | ||
665 | response->total_size = request->response_write_position; | ||
666 | return true; | ||
667 | } | ||
668 | if (0 == ret) | ||
669 | { | ||
670 | request->state = MHD_REQUEST_CHUNKED_BODY_UNREADY; | ||
671 | MHD_mutex_unlock_chk_ (&response->mutex); | ||
672 | return false; | ||
673 | } | ||
674 | if (ret > 0xFFFFFF) | ||
675 | ret = 0xFFFFFF; | ||
676 | cblen = MHD_snprintf_(cbuf, | ||
677 | sizeof (cbuf), | ||
678 | "%X\r\n", | ||
679 | (unsigned int) ret); | ||
680 | mhd_assert(cblen > 0); | ||
681 | mhd_assert((size_t)cblen < sizeof(cbuf)); | ||
682 | memcpy (&request->write_buffer[sizeof (cbuf) - cblen], | ||
683 | cbuf, | ||
684 | cblen); | ||
685 | memcpy (&request->write_buffer[sizeof (cbuf) + ret], | ||
686 | "\r\n", | ||
687 | 2); | ||
688 | request->response_write_position += ret; | ||
689 | request->write_buffer_send_offset = sizeof (cbuf) - cblen; | ||
690 | request->write_buffer_append_offset = sizeof (cbuf) + ret + 2; | ||
691 | return true; | ||
692 | } | ||
693 | |||
694 | |||
695 | /** | ||
696 | * This function was created to handle writes to sockets when it has | ||
697 | * been determined that the socket can be written to. | ||
698 | * | ||
699 | * @param request the request to handle | ||
700 | */ | ||
701 | static void | ||
702 | MHD_request_handle_write_ (struct MHD_Request *request) | ||
703 | { | ||
704 | struct MHD_Daemon *daemon = request->daemon; | ||
705 | struct MHD_Connection *connection = request->connection; | ||
706 | struct MHD_Response *response; | ||
707 | ssize_t ret; | ||
708 | |||
709 | if (connection->suspended) | ||
710 | return; | ||
711 | #ifdef HTTPS_SUPPORT | ||
712 | { | ||
713 | struct MHD_TLS_Plugin *tls; | ||
714 | |||
715 | if ( (NULL != (tls = daemon->tls_api)) && | ||
716 | (! tls->handshake (tls->cls, | ||
717 | connection->tls_cs)) ) | ||
718 | return; | ||
719 | } | ||
720 | #endif /* HTTPS_SUPPORT */ | ||
721 | |||
722 | #if DEBUG_STATES | ||
723 | MHD_DLOG (daemon, | ||
724 | MHD_SC_STATE_MACHINE_STATUS_REPORT, | ||
725 | _("In function %s handling connection at state: %s\n"), | ||
726 | __FUNCTION__, | ||
727 | MHD_state_to_string (request->state)); | ||
728 | #endif | ||
729 | switch (request->state) | ||
730 | { | ||
731 | case MHD_REQUEST_INIT: | ||
732 | case MHD_REQUEST_URL_RECEIVED: | ||
733 | case MHD_REQUEST_HEADER_PART_RECEIVED: | ||
734 | case MHD_REQUEST_HEADERS_RECEIVED: | ||
735 | mhd_assert (0); | ||
736 | return; | ||
737 | case MHD_REQUEST_HEADERS_PROCESSED: | ||
738 | return; | ||
739 | case MHD_REQUEST_CONTINUE_SENDING: | ||
740 | ret = connection->send_cls (connection, | ||
741 | &HTTP_100_CONTINUE | ||
742 | [request->continue_message_write_offset], | ||
743 | MHD_STATICSTR_LEN_ (HTTP_100_CONTINUE) - | ||
744 | request->continue_message_write_offset); | ||
745 | if (ret < 0) | ||
746 | { | ||
747 | if (MHD_ERR_AGAIN_ == ret) | ||
748 | return; | ||
749 | #ifdef HAVE_MESSAGES | ||
750 | MHD_DLOG (daemon, | ||
751 | MHD_SC_CONNECTION_WRITE_FAIL_CLOSED, | ||
752 | _("Failed to send data in request for %s.\n"), | ||
753 | request->url); | ||
754 | #endif | ||
755 | CONNECTION_CLOSE_ERROR (connection, | ||
756 | MHD_SC_CONNECTION_WRITE_FAIL_CLOSED, | ||
757 | NULL); | ||
758 | return; | ||
759 | } | ||
760 | request->continue_message_write_offset += ret; | ||
761 | MHD_connection_update_last_activity_ (connection); | ||
762 | return; | ||
763 | case MHD_REQUEST_CONTINUE_SENT: | ||
764 | case MHD_REQUEST_BODY_RECEIVED: | ||
765 | case MHD_REQUEST_FOOTER_PART_RECEIVED: | ||
766 | case MHD_REQUEST_FOOTERS_RECEIVED: | ||
767 | mhd_assert (0); | ||
768 | return; | ||
769 | case MHD_REQUEST_HEADERS_SENDING: | ||
770 | ret = connection->send_cls (connection, | ||
771 | &request->write_buffer | ||
772 | [request->write_buffer_send_offset], | ||
773 | request->write_buffer_append_offset - | ||
774 | request->write_buffer_send_offset); | ||
775 | if (ret < 0) | ||
776 | { | ||
777 | if (MHD_ERR_AGAIN_ == ret) | ||
778 | return; | ||
779 | CONNECTION_CLOSE_ERROR (connection, | ||
780 | MHD_SC_CONNECTION_WRITE_FAIL_CLOSED, | ||
781 | _("Connection was closed while sending response headers.\n")); | ||
782 | return; | ||
783 | } | ||
784 | request->write_buffer_send_offset += ret; | ||
785 | MHD_connection_update_last_activity_ (connection); | ||
786 | if (MHD_REQUEST_HEADERS_SENDING != request->state) | ||
787 | return; | ||
788 | check_write_done (request, | ||
789 | MHD_REQUEST_HEADERS_SENT); | ||
790 | return; | ||
791 | case MHD_REQUEST_HEADERS_SENT: | ||
792 | return; | ||
793 | case MHD_REQUEST_NORMAL_BODY_READY: | ||
794 | response = request->response; | ||
795 | if (request->response_write_position < | ||
796 | request->response->total_size) | ||
797 | { | ||
798 | uint64_t data_write_offset; | ||
799 | |||
800 | if (NULL != response->crc) | ||
801 | MHD_mutex_lock_chk_ (&response->mutex); | ||
802 | if (! try_ready_normal_body (request)) | ||
803 | { | ||
804 | /* mutex was already unlocked by try_ready_normal_body */ | ||
805 | return; | ||
806 | } | ||
807 | #if defined(_MHD_HAVE_SENDFILE) | ||
808 | if (MHD_resp_sender_sendfile == request->resp_sender) | ||
809 | { | ||
810 | ret = sendfile_adapter (connection); | ||
811 | } | ||
812 | else | ||
813 | #else /* ! _MHD_HAVE_SENDFILE */ | ||
814 | if (1) | ||
815 | #endif /* ! _MHD_HAVE_SENDFILE */ | ||
816 | { | ||
817 | data_write_offset = request->response_write_position | ||
818 | - response->data_start; | ||
819 | if (data_write_offset > (uint64_t)SIZE_MAX) | ||
820 | MHD_PANIC (_("Data offset exceeds limit")); | ||
821 | ret = connection->send_cls (connection, | ||
822 | &response->data | ||
823 | [(size_t)data_write_offset], | ||
824 | response->data_size - | ||
825 | (size_t)data_write_offset); | ||
826 | #if DEBUG_SEND_DATA | ||
827 | if (ret > 0) | ||
828 | fprintf (stderr, | ||
829 | _("Sent %d-byte DATA response: `%.*s'\n"), | ||
830 | (int) ret, | ||
831 | (int) ret, | ||
832 | &response->data[request->response_write_position - | ||
833 | response->data_start]); | ||
834 | #endif | ||
835 | } | ||
836 | if (NULL != response->crc) | ||
837 | MHD_mutex_unlock_chk_ (&response->mutex); | ||
838 | if (ret < 0) | ||
839 | { | ||
840 | if (MHD_ERR_AGAIN_ == ret) | ||
841 | return; | ||
842 | #ifdef HAVE_MESSAGES | ||
843 | MHD_DLOG (daemon, | ||
844 | MHD_SC_CONNECTION_WRITE_FAIL_CLOSED, | ||
845 | _("Failed to send data in request for `%s'.\n"), | ||
846 | request->url); | ||
847 | #endif | ||
848 | CONNECTION_CLOSE_ERROR (connection, | ||
849 | MHD_SC_CONNECTION_WRITE_FAIL_CLOSED, | ||
850 | NULL); | ||
851 | return; | ||
852 | } | ||
853 | request->response_write_position += ret; | ||
854 | MHD_connection_update_last_activity_ (connection); | ||
855 | } | ||
856 | if (request->response_write_position == | ||
857 | request->response->total_size) | ||
858 | request->state = MHD_REQUEST_FOOTERS_SENT; /* have no footers */ | ||
859 | return; | ||
860 | case MHD_REQUEST_NORMAL_BODY_UNREADY: | ||
861 | mhd_assert (0); | ||
862 | return; | ||
863 | case MHD_REQUEST_CHUNKED_BODY_READY: | ||
864 | ret = connection->send_cls (connection, | ||
865 | &request->write_buffer | ||
866 | [request->write_buffer_send_offset], | ||
867 | request->write_buffer_append_offset - | ||
868 | request->write_buffer_send_offset); | ||
869 | if (ret < 0) | ||
870 | { | ||
871 | if (MHD_ERR_AGAIN_ == ret) | ||
872 | return; | ||
873 | CONNECTION_CLOSE_ERROR (connection, | ||
874 | MHD_SC_CONNECTION_WRITE_FAIL_CLOSED, | ||
875 | _("Connection was closed while sending response body.\n")); | ||
876 | return; | ||
877 | } | ||
878 | request->write_buffer_send_offset += ret; | ||
879 | MHD_connection_update_last_activity_ (connection); | ||
880 | if (MHD_REQUEST_CHUNKED_BODY_READY != request->state) | ||
881 | return; | ||
882 | check_write_done (request, | ||
883 | (request->response->total_size == | ||
884 | request->response_write_position) ? | ||
885 | MHD_REQUEST_BODY_SENT : | ||
886 | MHD_REQUEST_CHUNKED_BODY_UNREADY); | ||
887 | return; | ||
888 | case MHD_REQUEST_CHUNKED_BODY_UNREADY: | ||
889 | case MHD_REQUEST_BODY_SENT: | ||
890 | mhd_assert (0); | ||
891 | return; | ||
892 | case MHD_REQUEST_FOOTERS_SENDING: | ||
893 | ret = connection->send_cls (connection, | ||
894 | &request->write_buffer | ||
895 | [request->write_buffer_send_offset], | ||
896 | request->write_buffer_append_offset - | ||
897 | request->write_buffer_send_offset); | ||
898 | if (ret < 0) | ||
899 | { | ||
900 | if (MHD_ERR_AGAIN_ == ret) | ||
901 | return; | ||
902 | CONNECTION_CLOSE_ERROR (connection, | ||
903 | MHD_SC_CONNECTION_WRITE_FAIL_CLOSED, | ||
904 | _("Connection was closed while sending response body.\n")); | ||
905 | return; | ||
906 | } | ||
907 | request->write_buffer_send_offset += ret; | ||
908 | MHD_connection_update_last_activity_ (connection); | ||
909 | if (MHD_REQUEST_FOOTERS_SENDING != request->state) | ||
910 | return; | ||
911 | check_write_done (request, | ||
912 | MHD_REQUEST_FOOTERS_SENT); | ||
913 | return; | ||
914 | case MHD_REQUEST_FOOTERS_SENT: | ||
915 | mhd_assert (0); | ||
916 | return; | ||
917 | case MHD_REQUEST_CLOSED: | ||
918 | return; | ||
919 | case MHD_REQUEST_IN_CLEANUP: | ||
920 | mhd_assert (0); | ||
921 | return; | ||
922 | #ifdef UPGRADE_SUPPORT | ||
923 | case MHD_REQUEST_UPGRADE: | ||
924 | mhd_assert (0); | ||
925 | return; | ||
926 | #endif /* UPGRADE_SUPPORT */ | ||
927 | default: | ||
928 | mhd_assert (0); | ||
929 | CONNECTION_CLOSE_ERROR (connection, | ||
930 | MHD_SC_STATEMACHINE_FAILURE_CONNECTION_CLOSED, | ||
931 | _("Internal error\n")); | ||
932 | break; | ||
933 | } | ||
934 | return; | ||
935 | } | ||
936 | |||
937 | |||
938 | #if COMMENTED_OUT_FOR_REWRITE | ||
939 | |||
940 | |||
941 | /** | ||
942 | * This function was created to handle per-connection processing that | ||
943 | * has to happen even if the socket cannot be read or written to. | ||
944 | * @remark To be called only from thread that process connection's | ||
945 | * recv(), send() and response. | ||
946 | * | ||
947 | * @param connection connection to handle | ||
948 | * @return #MHD_YES if we should continue to process the | ||
949 | * connection (not dead yet), #MHD_NO if it died | ||
950 | */ | ||
951 | int | ||
952 | MHD_connection_handle_idle (struct MHD_Connection *connection) | ||
953 | { | ||
954 | struct MHD_Daemon *daemon = connection->daemon; | ||
955 | char *line; | ||
956 | size_t line_len; | ||
957 | int ret; | ||
958 | |||
959 | connection->in_idle = true; | ||
960 | while (! connection->suspended) | ||
961 | { | ||
962 | #ifdef HTTPS_SUPPORT | ||
963 | if (MHD_TLS_CONN_NO_TLS != connection->tls_state) | ||
964 | { /* HTTPS connection. */ | ||
965 | if ((MHD_TLS_CONN_INIT <= connection->tls_state) && | ||
966 | (MHD_TLS_CONN_CONNECTED > connection->tls_state)) | ||
967 | break; | ||
968 | } | ||
969 | #endif /* HTTPS_SUPPORT */ | ||
970 | #if DEBUG_STATES | ||
971 | MHD_DLOG (daemon, | ||
972 | _("In function %s handling connection at state: %s\n"), | ||
973 | __FUNCTION__, | ||
974 | MHD_state_to_string (connection->state)); | ||
975 | #endif | ||
976 | switch (connection->state) | ||
977 | { | ||
978 | case MHD_CONNECTION_INIT: | ||
979 | line = get_next_header_line (connection, | ||
980 | &line_len); | ||
981 | /* Check for empty string, as we might want | ||
982 | to tolerate 'spurious' empty lines; also | ||
983 | NULL means we didn't get a full line yet; | ||
984 | line is not 0-terminated here. */ | ||
985 | if ( (NULL == line) || | ||
986 | (0 == line[0]) ) | ||
987 | { | ||
988 | if (MHD_CONNECTION_INIT != connection->state) | ||
989 | continue; | ||
990 | if (connection->read_closed) | ||
991 | { | ||
992 | CONNECTION_CLOSE_ERROR (connection, | ||
993 | NULL); | ||
994 | continue; | ||
995 | } | ||
996 | break; | ||
997 | } | ||
998 | if (MHD_NO == parse_initial_message_line (connection, | ||
999 | line, | ||
1000 | line_len)) | ||
1001 | CONNECTION_CLOSE_ERROR (connection, | ||
1002 | NULL); | ||
1003 | else | ||
1004 | connection->state = MHD_CONNECTION_URL_RECEIVED; | ||
1005 | continue; | ||
1006 | case MHD_CONNECTION_URL_RECEIVED: | ||
1007 | line = get_next_header_line (connection, | ||
1008 | NULL); | ||
1009 | if (NULL == line) | ||
1010 | { | ||
1011 | if (MHD_CONNECTION_URL_RECEIVED != connection->state) | ||
1012 | continue; | ||
1013 | if (connection->read_closed) | ||
1014 | { | ||
1015 | CONNECTION_CLOSE_ERROR (connection, | ||
1016 | NULL); | ||
1017 | continue; | ||
1018 | } | ||
1019 | break; | ||
1020 | } | ||
1021 | if (0 == line[0]) | ||
1022 | { | ||
1023 | connection->state = MHD_CONNECTION_HEADERS_RECEIVED; | ||
1024 | connection->header_size = (size_t) (line - connection->read_buffer); | ||
1025 | continue; | ||
1026 | } | ||
1027 | if (MHD_NO == process_header_line (connection, | ||
1028 | line)) | ||
1029 | { | ||
1030 | transmit_error_response (connection, | ||
1031 | MHD_HTTP_BAD_REQUEST, | ||
1032 | REQUEST_MALFORMED); | ||
1033 | break; | ||
1034 | } | ||
1035 | connection->state = MHD_CONNECTION_HEADER_PART_RECEIVED; | ||
1036 | continue; | ||
1037 | case MHD_CONNECTION_HEADER_PART_RECEIVED: | ||
1038 | line = get_next_header_line (connection, | ||
1039 | NULL); | ||
1040 | if (NULL == line) | ||
1041 | { | ||
1042 | if (connection->state != MHD_CONNECTION_HEADER_PART_RECEIVED) | ||
1043 | continue; | ||
1044 | if (connection->read_closed) | ||
1045 | { | ||
1046 | CONNECTION_CLOSE_ERROR (connection, | ||
1047 | NULL); | ||
1048 | continue; | ||
1049 | } | ||
1050 | break; | ||
1051 | } | ||
1052 | if (MHD_NO == | ||
1053 | process_broken_line (connection, | ||
1054 | line, | ||
1055 | MHD_HEADER_KIND)) | ||
1056 | continue; | ||
1057 | if (0 == line[0]) | ||
1058 | { | ||
1059 | connection->state = MHD_CONNECTION_HEADERS_RECEIVED; | ||
1060 | connection->header_size = (size_t) (line - connection->read_buffer); | ||
1061 | continue; | ||
1062 | } | ||
1063 | continue; | ||
1064 | case MHD_CONNECTION_HEADERS_RECEIVED: | ||
1065 | parse_connection_headers (connection); | ||
1066 | if (MHD_CONNECTION_CLOSED == connection->state) | ||
1067 | continue; | ||
1068 | connection->state = MHD_CONNECTION_HEADERS_PROCESSED; | ||
1069 | if (connection->suspended) | ||
1070 | break; | ||
1071 | continue; | ||
1072 | case MHD_CONNECTION_HEADERS_PROCESSED: | ||
1073 | call_connection_handler (connection); /* first call */ | ||
1074 | if (MHD_CONNECTION_CLOSED == connection->state) | ||
1075 | continue; | ||
1076 | if (need_100_continue (connection)) | ||
1077 | { | ||
1078 | connection->state = MHD_CONNECTION_CONTINUE_SENDING; | ||
1079 | if (MHD_NO != socket_flush_possible (connection)) | ||
1080 | socket_start_extra_buffering (connection); | ||
1081 | else | ||
1082 | socket_start_no_buffering (connection); | ||
1083 | |||
1084 | break; | ||
1085 | } | ||
1086 | if ( (NULL != connection->response) && | ||
1087 | ( (MHD_str_equal_caseless_ (connection->method, | ||
1088 | MHD_HTTP_METHOD_POST)) || | ||
1089 | (MHD_str_equal_caseless_ (connection->method, | ||
1090 | MHD_HTTP_METHOD_PUT))) ) | ||
1091 | { | ||
1092 | /* we refused (no upload allowed!) */ | ||
1093 | connection->remaining_upload_size = 0; | ||
1094 | /* force close, in case client still tries to upload... */ | ||
1095 | connection->read_closed = true; | ||
1096 | } | ||
1097 | connection->state = (0 == connection->remaining_upload_size) | ||
1098 | ? MHD_CONNECTION_FOOTERS_RECEIVED : MHD_CONNECTION_CONTINUE_SENT; | ||
1099 | if (connection->suspended) | ||
1100 | break; | ||
1101 | continue; | ||
1102 | case MHD_CONNECTION_CONTINUE_SENDING: | ||
1103 | if (connection->continue_message_write_offset == | ||
1104 | MHD_STATICSTR_LEN_ (HTTP_100_CONTINUE)) | ||
1105 | { | ||
1106 | connection->state = MHD_CONNECTION_CONTINUE_SENT; | ||
1107 | if (MHD_NO != socket_flush_possible (connection)) | ||
1108 | socket_start_no_buffering_flush (connection); | ||
1109 | else | ||
1110 | socket_start_normal_buffering (connection); | ||
1111 | |||
1112 | continue; | ||
1113 | } | ||
1114 | break; | ||
1115 | case MHD_CONNECTION_CONTINUE_SENT: | ||
1116 | if (0 != connection->read_buffer_offset) | ||
1117 | { | ||
1118 | process_request_body (connection); /* loop call */ | ||
1119 | if (MHD_CONNECTION_CLOSED == connection->state) | ||
1120 | continue; | ||
1121 | } | ||
1122 | if ( (0 == connection->remaining_upload_size) || | ||
1123 | ( (MHD_SIZE_UNKNOWN == connection->remaining_upload_size) && | ||
1124 | (0 == connection->read_buffer_offset) && | ||
1125 | (connection->read_closed) ) ) | ||
1126 | { | ||
1127 | if ( (connection->have_chunked_upload) && | ||
1128 | (! connection->read_closed) ) | ||
1129 | connection->state = MHD_CONNECTION_BODY_RECEIVED; | ||
1130 | else | ||
1131 | connection->state = MHD_CONNECTION_FOOTERS_RECEIVED; | ||
1132 | if (connection->suspended) | ||
1133 | break; | ||
1134 | continue; | ||
1135 | } | ||
1136 | break; | ||
1137 | case MHD_CONNECTION_BODY_RECEIVED: | ||
1138 | line = get_next_header_line (connection, | ||
1139 | NULL); | ||
1140 | if (NULL == line) | ||
1141 | { | ||
1142 | if (connection->state != MHD_CONNECTION_BODY_RECEIVED) | ||
1143 | continue; | ||
1144 | if (connection->read_closed) | ||
1145 | { | ||
1146 | CONNECTION_CLOSE_ERROR (connection, | ||
1147 | NULL); | ||
1148 | continue; | ||
1149 | } | ||
1150 | break; | ||
1151 | } | ||
1152 | if (0 == line[0]) | ||
1153 | { | ||
1154 | connection->state = MHD_CONNECTION_FOOTERS_RECEIVED; | ||
1155 | if (connection->suspended) | ||
1156 | break; | ||
1157 | continue; | ||
1158 | } | ||
1159 | if (MHD_NO == process_header_line (connection, | ||
1160 | line)) | ||
1161 | { | ||
1162 | transmit_error_response (connection, | ||
1163 | MHD_HTTP_BAD_REQUEST, | ||
1164 | REQUEST_MALFORMED); | ||
1165 | break; | ||
1166 | } | ||
1167 | connection->state = MHD_CONNECTION_FOOTER_PART_RECEIVED; | ||
1168 | continue; | ||
1169 | case MHD_CONNECTION_FOOTER_PART_RECEIVED: | ||
1170 | line = get_next_header_line (connection, | ||
1171 | NULL); | ||
1172 | if (NULL == line) | ||
1173 | { | ||
1174 | if (connection->state != MHD_CONNECTION_FOOTER_PART_RECEIVED) | ||
1175 | continue; | ||
1176 | if (connection->read_closed) | ||
1177 | { | ||
1178 | CONNECTION_CLOSE_ERROR (connection, | ||
1179 | NULL); | ||
1180 | continue; | ||
1181 | } | ||
1182 | break; | ||
1183 | } | ||
1184 | if (MHD_NO == | ||
1185 | process_broken_line (connection, | ||
1186 | line, | ||
1187 | MHD_FOOTER_KIND)) | ||
1188 | continue; | ||
1189 | if (0 == line[0]) | ||
1190 | { | ||
1191 | connection->state = MHD_CONNECTION_FOOTERS_RECEIVED; | ||
1192 | if (connection->suspended) | ||
1193 | break; | ||
1194 | continue; | ||
1195 | } | ||
1196 | continue; | ||
1197 | case MHD_CONNECTION_FOOTERS_RECEIVED: | ||
1198 | call_connection_handler (connection); /* "final" call */ | ||
1199 | if (connection->state == MHD_CONNECTION_CLOSED) | ||
1200 | continue; | ||
1201 | if (NULL == connection->response) | ||
1202 | break; /* try again next time */ | ||
1203 | if (MHD_NO == build_header_response (connection)) | ||
1204 | { | ||
1205 | /* oops - close! */ | ||
1206 | CONNECTION_CLOSE_ERROR (connection, | ||
1207 | _("Closing connection (failed to create response header)\n")); | ||
1208 | continue; | ||
1209 | } | ||
1210 | connection->state = MHD_CONNECTION_HEADERS_SENDING; | ||
1211 | if (MHD_NO != socket_flush_possible (connection)) | ||
1212 | socket_start_extra_buffering (connection); | ||
1213 | else | ||
1214 | socket_start_no_buffering (connection); | ||
1215 | |||
1216 | break; | ||
1217 | case MHD_CONNECTION_HEADERS_SENDING: | ||
1218 | /* no default action */ | ||
1219 | break; | ||
1220 | case MHD_CONNECTION_HEADERS_SENT: | ||
1221 | /* Some clients may take some actions right after header receive */ | ||
1222 | if (MHD_NO != socket_flush_possible (connection)) | ||
1223 | socket_start_no_buffering_flush (connection); | ||
1224 | |||
1225 | #ifdef UPGRADE_SUPPORT | ||
1226 | if (NULL != connection->response->upgrade_handler) | ||
1227 | { | ||
1228 | socket_start_normal_buffering (connection); | ||
1229 | connection->state = MHD_CONNECTION_UPGRADE; | ||
1230 | /* This connection is "upgraded". Pass socket to application. */ | ||
1231 | if (MHD_YES != | ||
1232 | MHD_response_execute_upgrade_ (connection->response, | ||
1233 | connection)) | ||
1234 | { | ||
1235 | /* upgrade failed, fail hard */ | ||
1236 | CONNECTION_CLOSE_ERROR (connection, | ||
1237 | NULL); | ||
1238 | continue; | ||
1239 | } | ||
1240 | /* Response is not required anymore for this connection. */ | ||
1241 | if (NULL != connection->response) | ||
1242 | { | ||
1243 | struct MHD_Response * const resp = connection->response; | ||
1244 | connection->response = NULL; | ||
1245 | MHD_destroy_response (resp); | ||
1246 | } | ||
1247 | continue; | ||
1248 | } | ||
1249 | #endif /* UPGRADE_SUPPORT */ | ||
1250 | if (MHD_NO != socket_flush_possible (connection)) | ||
1251 | socket_start_extra_buffering (connection); | ||
1252 | else | ||
1253 | socket_start_normal_buffering (connection); | ||
1254 | |||
1255 | if (connection->have_chunked_upload) | ||
1256 | connection->state = MHD_CONNECTION_CHUNKED_BODY_UNREADY; | ||
1257 | else | ||
1258 | connection->state = MHD_CONNECTION_NORMAL_BODY_UNREADY; | ||
1259 | continue; | ||
1260 | case MHD_CONNECTION_NORMAL_BODY_READY: | ||
1261 | /* nothing to do here */ | ||
1262 | break; | ||
1263 | case MHD_CONNECTION_NORMAL_BODY_UNREADY: | ||
1264 | if (NULL != connection->response->crc) | ||
1265 | MHD_mutex_lock_chk_ (&connection->response->mutex); | ||
1266 | if (0 == connection->response->total_size) | ||
1267 | { | ||
1268 | if (NULL != connection->response->crc) | ||
1269 | MHD_mutex_unlock_chk_ (&connection->response->mutex); | ||
1270 | connection->state = MHD_CONNECTION_BODY_SENT; | ||
1271 | continue; | ||
1272 | } | ||
1273 | if (try_ready_normal_body (connection)) | ||
1274 | { | ||
1275 | if (NULL != connection->response->crc) | ||
1276 | MHD_mutex_unlock_chk_ (&connection->response->mutex); | ||
1277 | connection->state = MHD_CONNECTION_NORMAL_BODY_READY; | ||
1278 | /* Buffering for flushable socket was already enabled*/ | ||
1279 | if (MHD_NO == socket_flush_possible (connection)) | ||
1280 | socket_start_no_buffering (connection); | ||
1281 | break; | ||
1282 | } | ||
1283 | /* mutex was already unlocked by "try_ready_normal_body */ | ||
1284 | /* not ready, no socket action */ | ||
1285 | break; | ||
1286 | case MHD_CONNECTION_CHUNKED_BODY_READY: | ||
1287 | /* nothing to do here */ | ||
1288 | break; | ||
1289 | case MHD_CONNECTION_CHUNKED_BODY_UNREADY: | ||
1290 | if (NULL != connection->response->crc) | ||
1291 | MHD_mutex_lock_chk_ (&connection->response->mutex); | ||
1292 | if ( (0 == connection->response->total_size) || | ||
1293 | (connection->response_write_position == | ||
1294 | connection->response->total_size) ) | ||
1295 | { | ||
1296 | if (NULL != connection->response->crc) | ||
1297 | MHD_mutex_unlock_chk_ (&connection->response->mutex); | ||
1298 | connection->state = MHD_CONNECTION_BODY_SENT; | ||
1299 | continue; | ||
1300 | } | ||
1301 | if (try_ready_chunked_body (connection)) | ||
1302 | { | ||
1303 | if (NULL != connection->response->crc) | ||
1304 | MHD_mutex_unlock_chk_ (&connection->response->mutex); | ||
1305 | connection->state = MHD_CONNECTION_CHUNKED_BODY_READY; | ||
1306 | /* Buffering for flushable socket was already enabled */ | ||
1307 | if (MHD_NO == socket_flush_possible (connection)) | ||
1308 | socket_start_no_buffering (connection); | ||
1309 | continue; | ||
1310 | } | ||
1311 | /* mutex was already unlocked by try_ready_chunked_body */ | ||
1312 | break; | ||
1313 | case MHD_CONNECTION_BODY_SENT: | ||
1314 | if (MHD_NO == build_header_response (connection)) | ||
1315 | { | ||
1316 | /* oops - close! */ | ||
1317 | CONNECTION_CLOSE_ERROR (connection, | ||
1318 | _("Closing connection (failed to create response header)\n")); | ||
1319 | continue; | ||
1320 | } | ||
1321 | if ( (! connection->have_chunked_upload) || | ||
1322 | (connection->write_buffer_send_offset == | ||
1323 | connection->write_buffer_append_offset) ) | ||
1324 | connection->state = MHD_CONNECTION_FOOTERS_SENT; | ||
1325 | else | ||
1326 | connection->state = MHD_CONNECTION_FOOTERS_SENDING; | ||
1327 | continue; | ||
1328 | case MHD_CONNECTION_FOOTERS_SENDING: | ||
1329 | /* no default action */ | ||
1330 | break; | ||
1331 | case MHD_CONNECTION_FOOTERS_SENT: | ||
1332 | if (MHD_HTTP_PROCESSING == connection->responseCode) | ||
1333 | { | ||
1334 | /* After this type of response, we allow sending another! */ | ||
1335 | connection->state = MHD_CONNECTION_HEADERS_PROCESSED; | ||
1336 | MHD_destroy_response (connection->response); | ||
1337 | connection->response = NULL; | ||
1338 | /* FIXME: maybe partially reset memory pool? */ | ||
1339 | continue; | ||
1340 | } | ||
1341 | if (MHD_NO != socket_flush_possible (connection)) | ||
1342 | socket_start_no_buffering_flush (connection); | ||
1343 | else | ||
1344 | socket_start_normal_buffering (connection); | ||
1345 | |||
1346 | MHD_destroy_response (connection->response); | ||
1347 | connection->response = NULL; | ||
1348 | if ( (NULL != daemon->notify_completed) && | ||
1349 | (connection->client_aware) ) | ||
1350 | { | ||
1351 | connection->client_aware = false; | ||
1352 | daemon->notify_completed (daemon->notify_completed_cls, | ||
1353 | connection, | ||
1354 | &connection->client_context, | ||
1355 | MHD_REQUEST_TERMINATED_COMPLETED_OK); | ||
1356 | } | ||
1357 | if ( (MHD_CONN_USE_KEEPALIVE != connection->keepalive) || | ||
1358 | (connection->read_closed) ) | ||
1359 | { | ||
1360 | /* have to close for some reason */ | ||
1361 | MHD_connection_close_ (connection, | ||
1362 | MHD_REQUEST_TERMINATED_COMPLETED_OK); | ||
1363 | MHD_pool_destroy (connection->pool); | ||
1364 | connection->pool = NULL; | ||
1365 | connection->read_buffer = NULL; | ||
1366 | connection->read_buffer_size = 0; | ||
1367 | connection->read_buffer_offset = 0; | ||
1368 | } | ||
1369 | else | ||
1370 | { | ||
1371 | /* can try to keep-alive */ | ||
1372 | if (MHD_NO != socket_flush_possible (connection)) | ||
1373 | socket_start_normal_buffering (connection); | ||
1374 | connection->version = NULL; | ||
1375 | connection->state = MHD_CONNECTION_INIT; | ||
1376 | connection->last = NULL; | ||
1377 | connection->colon = NULL; | ||
1378 | connection->header_size = 0; | ||
1379 | connection->keepalive = MHD_CONN_KEEPALIVE_UNKOWN; | ||
1380 | /* Reset the read buffer to the starting size, | ||
1381 | preserving the bytes we have already read. */ | ||
1382 | connection->read_buffer | ||
1383 | = MHD_pool_reset (connection->pool, | ||
1384 | connection->read_buffer, | ||
1385 | connection->read_buffer_offset, | ||
1386 | connection->daemon->pool_size / 2); | ||
1387 | connection->read_buffer_size | ||
1388 | = connection->daemon->pool_size / 2; | ||
1389 | } | ||
1390 | connection->client_aware = false; | ||
1391 | connection->client_context = NULL; | ||
1392 | connection->continue_message_write_offset = 0; | ||
1393 | connection->responseCode = 0; | ||
1394 | connection->headers_received = NULL; | ||
1395 | connection->headers_received_tail = NULL; | ||
1396 | connection->response_write_position = 0; | ||
1397 | connection->have_chunked_upload = false; | ||
1398 | connection->current_chunk_size = 0; | ||
1399 | connection->current_chunk_offset = 0; | ||
1400 | connection->method = NULL; | ||
1401 | connection->url = NULL; | ||
1402 | connection->write_buffer = NULL; | ||
1403 | connection->write_buffer_size = 0; | ||
1404 | connection->write_buffer_send_offset = 0; | ||
1405 | connection->write_buffer_append_offset = 0; | ||
1406 | continue; | ||
1407 | case MHD_CONNECTION_CLOSED: | ||
1408 | cleanup_connection (connection); | ||
1409 | connection->in_idle = false; | ||
1410 | return MHD_NO; | ||
1411 | #ifdef UPGRADE_SUPPORT | ||
1412 | case MHD_CONNECTION_UPGRADE: | ||
1413 | connection->in_idle = false; | ||
1414 | return MHD_YES; /* keep open */ | ||
1415 | #endif /* UPGRADE_SUPPORT */ | ||
1416 | default: | ||
1417 | mhd_assert (0); | ||
1418 | break; | ||
1419 | } | ||
1420 | break; | ||
1421 | } | ||
1422 | if (! connection->suspended) | ||
1423 | { | ||
1424 | time_t timeout; | ||
1425 | timeout = connection->connection_timeout; | ||
1426 | if ( (0 != timeout) && | ||
1427 | (timeout < (MHD_monotonic_sec_counter() - connection->last_activity)) ) | ||
1428 | { | ||
1429 | MHD_connection_close_ (connection, | ||
1430 | MHD_REQUEST_TERMINATED_TIMEOUT_REACHED); | ||
1431 | connection->in_idle = false; | ||
1432 | return MHD_YES; | ||
1433 | } | ||
1434 | } | ||
1435 | MHD_connection_update_event_loop_info (connection); | ||
1436 | ret = MHD_YES; | ||
1437 | #ifdef EPOLL_SUPPORT | ||
1438 | if ( (! connection->suspended) && | ||
1439 | (0 != (daemon->options & MHD_USE_EPOLL)) ) | ||
1440 | { | ||
1441 | ret = MHD_connection_epoll_update_ (connection); | ||
1442 | } | ||
1443 | #endif /* EPOLL_SUPPORT */ | ||
1444 | connection->in_idle = false; | ||
1445 | return ret; | ||
1446 | } | ||
1447 | |||
1448 | // rewrite commented out | ||
1449 | #endif | ||
1450 | |||
28 | 1451 | ||
29 | /** | 1452 | /** |
30 | * Call the handlers for a connection in the appropriate order based | 1453 | * Call the handlers for a connection in the appropriate order based |
@@ -56,13 +1479,13 @@ MHD_connection_call_handlers_ (struct MHD_Connection *con, | |||
56 | if (con->tls_read_ready) | 1479 | if (con->tls_read_ready) |
57 | read_ready = true; | 1480 | read_ready = true; |
58 | #endif /* HTTPS_SUPPORT */ | 1481 | #endif /* HTTPS_SUPPORT */ |
59 | if (!force_close) | 1482 | if (! force_close) |
60 | { | 1483 | { |
61 | if ( (MHD_EVENT_LOOP_INFO_READ == | 1484 | if ( (MHD_EVENT_LOOP_INFO_READ == |
62 | con->request.event_loop_info) && | 1485 | con->request.event_loop_info) && |
63 | read_ready) | 1486 | read_ready) |
64 | { | 1487 | { |
65 | MHD_connection_handle_read (con); | 1488 | MHD_request_handle_read_ (&con->request); |
66 | ret = MHD_connection_handle_idle (con); | 1489 | ret = MHD_connection_handle_idle (con); |
67 | states_info_processed = true; | 1490 | states_info_processed = true; |
68 | } | 1491 | } |
@@ -72,7 +1495,7 @@ MHD_connection_call_handlers_ (struct MHD_Connection *con, | |||
72 | con->request.event_loop_info) && | 1495 | con->request.event_loop_info) && |
73 | write_ready) | 1496 | write_ready) |
74 | { | 1497 | { |
75 | MHD_connection_handle_write (con); | 1498 | MHD_request_handle_write_ (&con->request); |
76 | ret = MHD_connection_handle_idle (con); | 1499 | ret = MHD_connection_handle_idle (con); |
77 | states_info_processed = true; | 1500 | states_info_processed = true; |
78 | } | 1501 | } |
@@ -104,7 +1527,7 @@ MHD_connection_call_handlers_ (struct MHD_Connection *con, | |||
104 | { | 1527 | { |
105 | if (MHD_REQUEST_HEADERS_SENDING == con->request.state) | 1528 | if (MHD_REQUEST_HEADERS_SENDING == con->request.state) |
106 | { | 1529 | { |
107 | MHD_connection_handle_write (con); | 1530 | MHD_request_handle_write_ (&con->request); |
108 | /* Always call 'MHD_connection_handle_idle()' after each read/write. */ | 1531 | /* Always call 'MHD_connection_handle_idle()' after each read/write. */ |
109 | ret = MHD_connection_handle_idle (con); | 1532 | ret = MHD_connection_handle_idle (con); |
110 | } | 1533 | } |
@@ -114,7 +1537,7 @@ MHD_connection_call_handlers_ (struct MHD_Connection *con, | |||
114 | if ((MHD_REQUEST_NORMAL_BODY_READY == con->request.state) || | 1537 | if ((MHD_REQUEST_NORMAL_BODY_READY == con->request.state) || |
115 | (MHD_REQUEST_CHUNKED_BODY_READY == con->request.state)) | 1538 | (MHD_REQUEST_CHUNKED_BODY_READY == con->request.state)) |
116 | { | 1539 | { |
117 | MHD_connection_handle_write (con); | 1540 | MHD_request_handle_write_ (&con->request); |
118 | ret = MHD_connection_handle_idle (con); | 1541 | ret = MHD_connection_handle_idle (con); |
119 | } | 1542 | } |
120 | } | 1543 | } |
diff --git a/src/lib/connection_cleanup.c b/src/lib/connection_cleanup.c index cf0b9d45..8af313ad 100644 --- a/src/lib/connection_cleanup.c +++ b/src/lib/connection_cleanup.c | |||
@@ -92,7 +92,7 @@ MHD_connection_cleanup_ (struct MHD_Daemon *daemon) | |||
92 | #ifdef UPGRADE_SUPPORT | 92 | #ifdef UPGRADE_SUPPORT |
93 | cleanup_upgraded_connection (pos); | 93 | cleanup_upgraded_connection (pos); |
94 | #endif /* UPGRADE_SUPPORT */ | 94 | #endif /* UPGRADE_SUPPORT */ |
95 | MHD_pool_destroy (pos->request.pool); | 95 | MHD_pool_destroy (pos->pool); |
96 | #ifdef HTTPS_SUPPORT | 96 | #ifdef HTTPS_SUPPORT |
97 | { | 97 | { |
98 | struct MHD_TLS_Plugin *tls; | 98 | struct MHD_TLS_Plugin *tls; |
diff --git a/src/lib/internal.h b/src/lib/internal.h index f03e101e..b4c471dd 100644 --- a/src/lib/internal.h +++ b/src/lib/internal.h | |||
@@ -209,8 +209,8 @@ typedef ssize_t | |||
209 | * not have to be completed yet). A transition to | 209 | * not have to be completed yet). A transition to |
210 | * #MHD_REQUEST_CLOSED or #MHD_REQUEST_INIT requires the write | 210 | * #MHD_REQUEST_CLOSED or #MHD_REQUEST_INIT requires the write |
211 | * to be complete. | 211 | * to be complete. |
212 | */ | 212 | */ |
213 | enum MHD_REQUEST_STATE | 213 | enum MHD_REQUEST_STATE // FIXME: fix capitalization! |
214 | { | 214 | { |
215 | /** | 215 | /** |
216 | * Request just started (no headers received). | 216 | * Request just started (no headers received). |
@@ -422,16 +422,6 @@ struct MHD_Request | |||
422 | struct MHD_HTTP_Header *headers_received_tail; | 422 | struct MHD_HTTP_Header *headers_received_tail; |
423 | 423 | ||
424 | /** | 424 | /** |
425 | * The memory pool is created whenever we first read from the TCP | ||
426 | * stream and destroyed at the end of each request (and re-created | ||
427 | * for the next request). In the meantime, this pointer is NULL. | ||
428 | * The pool is used for all request-related data except for the | ||
429 | * response (which maybe shared between requests) and the IP | ||
430 | * address (which persists across individual requests). | ||
431 | */ | ||
432 | struct MemoryPool *pool; // FIXME: keep with connnection! | ||
433 | |||
434 | /** | ||
435 | * We allow the main application to associate some pointer with the | 425 | * We allow the main application to associate some pointer with the |
436 | * HTTP request, which is passed to each #MHD_AccessHandlerCallback | 426 | * HTTP request, which is passed to each #MHD_AccessHandlerCallback |
437 | * and some other API calls. Here is where we store it. (MHD does | 427 | * and some other API calls. Here is where we store it. (MHD does |
@@ -567,7 +557,8 @@ struct MHD_Request | |||
567 | */ | 557 | */ |
568 | uint64_t response_write_position; | 558 | uint64_t response_write_position; |
569 | 559 | ||
570 | #if defined(_MHD_HAVE_SENDFILE) | 560 | #if defined(_MHD_HAVE_SENDFILE) |
561 | // FIXME: document, fix capitalization! | ||
571 | enum MHD_resp_sender_ | 562 | enum MHD_resp_sender_ |
572 | { | 563 | { |
573 | MHD_resp_sender_std = 0, | 564 | MHD_resp_sender_std = 0, |
@@ -713,6 +704,16 @@ struct MHD_Connection | |||
713 | * Reference to the MHD_Daemon struct. | 704 | * Reference to the MHD_Daemon struct. |
714 | */ | 705 | */ |
715 | struct MHD_Daemon *daemon; | 706 | struct MHD_Daemon *daemon; |
707 | |||
708 | /** | ||
709 | * The memory pool is created whenever we first read from the TCP | ||
710 | * stream and destroyed at the end of each request (and re-created | ||
711 | * for the next request). In the meantime, this pointer is NULL. | ||
712 | * The pool is used for all request-related data except for the | ||
713 | * response (which maybe shared between requests) and the IP | ||
714 | * address (which persists across individual requests). | ||
715 | */ | ||
716 | struct MemoryPool *pool; | ||
716 | 717 | ||
717 | /** | 718 | /** |
718 | * We allow the main application to associate some pointer with the | 719 | * We allow the main application to associate some pointer with the |
diff --git a/src/lib/request.c b/src/lib/request.c index 6264111e..02cce55c 100644 --- a/src/lib/request.c +++ b/src/lib/request.c | |||
@@ -100,7 +100,7 @@ MHD_request_set_value (struct MHD_Request *request, | |||
100 | { | 100 | { |
101 | struct MHD_HTTP_Header *pos; | 101 | struct MHD_HTTP_Header *pos; |
102 | 102 | ||
103 | pos = MHD_pool_allocate (request->pool, | 103 | pos = MHD_pool_allocate (request->connection->pool, |
104 | sizeof (struct MHD_HTTP_Header), | 104 | sizeof (struct MHD_HTTP_Header), |
105 | MHD_YES); | 105 | MHD_YES); |
106 | if (NULL == pos) | 106 | if (NULL == pos) |