aboutsummaryrefslogtreecommitdiff
path: root/src/lib
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2018-02-17 04:02:42 +0100
committerChristian Grothoff <christian@grothoff.org>2018-02-17 04:02:42 +0100
commita5fa8a08ef2cf017444cfa476cb3d932c1f6ba74 (patch)
treeeea7f8d5d151b8e5113b93890a597de60e5b4c48 /src/lib
parentc0ac86b069fac3460fd2e4c7997245c5a1281536 (diff)
downloadlibmicrohttpd-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.c6
-rw-r--r--src/lib/connection_call_handlers.c1433
-rw-r--r--src/lib/connection_cleanup.c2
-rw-r--r--src/lib/internal.h27
-rw-r--r--src/lib/request.c2
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 */
54static int freebsd_sendfile_flags_;
55
56/**
57 * FreeBSD sendfile() flags for thread-per-connection
58 */
59static 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 */
68void
69MHD_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 */
108static void
109connection_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 */
148static bool
149try_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 */
179static void
180MHD_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 */
299static ssize_t
300sendfile_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 */
485static bool
486check_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 */
515static bool
516try_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 */
581static bool
582try_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 */
701static void
702MHD_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 */
951int
952MHD_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 */
213enum MHD_REQUEST_STATE 213enum 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)