[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[libmicrohttpd] 231/335: WIP more
From: |
gnunet |
Subject: |
[libmicrohttpd] 231/335: WIP more |
Date: |
Sat, 27 Jul 2024 22:02:07 +0200 |
This is an automated email from the git hooks/post-receive script.
grothoff pushed a commit to tag stf-m2
in repository libmicrohttpd.
commit 189805ef3e7c24966f8299c080e8247cd6354c76
Author: Evgeny Grin (Karlson2k) <k2k@narod.ru>
AuthorDate: Sun Jul 14 07:37:42 2024 +0200
WIP more
---
src/include/microhttpd2.h | 109 +-
src/mhd2/Makefile.am | 37 +-
src/mhd2/action.c | 16 +-
src/mhd2/conn_data_process.c | 7 +-
src/mhd2/conn_data_process.h | 17 +-
src/mhd2/conn_data_recv.c | 21 +-
src/mhd2/conn_data_recv.h | 2 +-
src/mhd2/conn_data_send.c | 24 +-
src/mhd2/conn_data_send.h | 2 +-
src/mhd2/daemon_add_conn.c | 8 +-
src/mhd2/daemon_add_conn.h | 11 +
src/mhd2/daemon_funcs.c | 135 +-
src/mhd2/daemon_funcs.h | 85 +-
src/mhd2/daemon_options.h | 6 +
src/mhd2/daemon_start.c | 164 +-
src/mhd2/http_prot_ver.h | 13 +
src/mhd2/http_status_str.c | 10 +-
src/mhd2/http_status_str.h | 2 +-
src/mhd2/mhd_action.h | 45 +-
src/mhd2/mhd_atomic_counter.c | 17 +-
src/mhd2/mhd_atomic_counter.h | 18 +-
src/mhd2/{http_status_str.h => mhd_buffer.h} | 37 +-
src/mhd2/mhd_connection.h | 62 +-
src/mhd2/mhd_daemon.h | 43 +
src/mhd2/mhd_mempool.c | 54 +-
src/mhd2/mhd_mempool.h | 52 +-
src/mhd2/mhd_recv.c | 15 +-
src/mhd2/mhd_reply.h | 6 -
src/mhd2/mhd_request.h | 42 +-
src/mhd2/mhd_response.h | 2 +-
src/mhd2/mhd_send.c | 190 ++-
src/mhd2/mhd_socket_error.c | 7 +-
src/mhd2/mhd_str.h | 24 +-
src/mhd2/request_funcs.c | 13 +-
src/mhd2/request_get_value.c | 32 +-
src/mhd2/request_get_value.h | 32 +-
src/mhd2/respond_with_error.h | 86 +
src/mhd2/response_add_header.c | 35 +-
src/mhd2/response_destroy.c | 14 +-
src/mhd2/response_funcs.c | 23 +-
src/mhd2/response_set_options.c | 1 +
src/mhd2/stream_funcs.c | 117 +-
src/mhd2/stream_funcs.h | 85 +-
.../{http_status_str.h => stream_process_reply.h} | 24 +-
src/mhd2/stream_process_request.c | 1735 ++++++++++++++++----
src/mhd2/stream_process_request.h | 125 +-
src/mhd2/stream_process_states.c | 149 +-
47 files changed, 2874 insertions(+), 880 deletions(-)
diff --git a/src/include/microhttpd2.h b/src/include/microhttpd2.h
index b1e1b2b2..4c304c5e 100644
--- a/src/include/microhttpd2.h
+++ b/src/include/microhttpd2.h
@@ -481,6 +481,17 @@ enum MHD_FIXED_ENUM_MHD_SET_ MHD_StatusCode
*/
MHD_SC_CONNECTION_POOL_MALLOC_FAILURE_REQ = 30130
,
+ /**
+ * Failed to allocate memory from our memory pool to store GET parameter.
+ * Likely the request URI or header fields are too large to leave enough
room.
+ */
+ MHD_SC_CONNECTION_POOL_NO_MEM_GET_PARAM = 30131
+ ,
+ /**
+ * Failed to allocate memory from our memory pool to store parsed cookie.
+ */
+ MHD_SC_CONNECTION_POOL_NO_MEM_COOKIE = 30132
+ ,
/* 40000-level errors are caused by the HTTP client
(or the network) */
@@ -497,42 +508,57 @@ enum MHD_FIXED_ENUM_MHD_SET_ MHD_StatusCode
MHD_SC_CONNECTION_RESET_CLOSED = 40001
,
/**
- * MHD is closing a connection because reading the
+ * MHD is closing a connection because receiving the
* request failed.
*/
- MHD_SC_CONNECTION_READ_FAIL_CLOSED = 40002
+ MHD_SC_CONNECTION_RECV_FAIL_CLOSED = 40002
,
/**
- * MHD is closing a connection because writing the response failed.
+ * MHD is closing a connection because sending the response failed.
*/
- MHD_SC_CONNECTION_WRITE_FAIL_CLOSED = 40003
+ MHD_SC_CONNECTION_SEND_FAIL_CLOSED = 40003
,
/**
* MHD is returning an error because the header provided
* by the client is too big.
*/
- MHD_SC_CLIENT_HEADER_TOO_BIG = 40004
+ MHD_SC_CLIENT_HEADER_TOO_BIG = 40020
,
/**
* An HTTP/1.1 request was sent without the "Host:" header.
*/
- MHD_SC_HOST_HEADER_MISSING = 40005
+ MHD_SC_HOST_HEADER_MISSING = 40060
,
/**
* The given content length was not a number.
*/
- MHD_SC_CONTENT_LENGTH_MALFORMED = 40006
+ MHD_SC_CONTENT_LENGTH_MALFORMED = 40061
+ ,
+ /**
+ * The BOTH Content-Length and Transfer-Encoding headers are used.
+ */
+ MHD_SC_CONTENT_LENGTH_AND_TR_ENC = 40062
+ ,
+ /**
+ * The Content-Length is too large to be handled.
+ */
+ MHD_SC_CONTENT_LENGTH_TOO_LARGE = 40062
,
/**
* The given uploaded, chunked-encoded body was malformed.
*/
- MHD_SC_CHUNKED_ENCODING_MALFORMED = 40007
+ MHD_SC_CHUNKED_ENCODING_MALFORMED = 40080
,
/**
* The first header line has whitespace at the start
*/
MHD_SC_REQ_FIRST_HEADER_LINE_SPACE_PREFIXED = 40100
,
+ /**
+ * The request target (URI) has whitespace character
+ */
+ MHD_SC_REQ_TARGET_HAS_WHITESPACE = 40101
+ ,
/**
* Wrong bare CR characters has been replaced with space.
*/
@@ -553,6 +579,28 @@ enum MHD_FIXED_ENUM_MHD_SET_ MHD_StatusCode
*/
MHD_SC_REQ_FOOTER_LINE_NO_COLON = 40141
,
+ /**
+ * The cookie string has been parsed, but it is not fully compliant with
+ * specifications
+ */
+ MHD_SC_REQ_COOKIE_PARSED_NOT_COMPLIANT = 40142
+ ,
+ /**
+ * The cookie string has been parsed only partially
+ */
+ MHD_SC_REQ_COOKIE_PARSED_PARTIALLY = 40142
+ ,
+ /**
+ * The cookie string is ignored, as it is not fully compliant with
+ * specifications
+ */
+ MHD_SC_REQ_COOKIE_IGNORED_NOT_COMPLIANT = 40143
+ ,
+ /**
+ * The cookie string has been ignored as it is invalid
+ */
+ MHD_SC_REQ_COOKIE_INVALID = 40143
+ ,
/* 50000-level errors are because of an error internal
to the MHD logic, possibly including our interaction
@@ -785,6 +833,11 @@ enum MHD_FIXED_ENUM_MHD_SET_ MHD_StatusCode
*/
MHD_SC_LISTEN_PORT_INTROSPECTION_UNKNOWN_AF = 50081
,
+ /**
+ * Failed to initialise mutex.
+ */
+ MHD_SC_MUTEX_INIT_FAILURE = 50085
+ ,
/**
* Failed to allocate memory for the thread pool.
*/
@@ -1163,6 +1216,16 @@ enum MHD_FIXED_ENUM_MHD_SET_ MHD_StatusCode
* The response header value has forbidden characters
*/
MHD_SC_RESP_HEADER_VALUE_INVALID = 60051
+ ,
+ /**
+ * The the provided MHD_Action is invalid
+ */
+ MHD_SC_ACTION_INVALID = 60080
+ ,
+ /**
+ * The the provided MHD_UploadAction is invalid
+ */
+ MHD_SC_UPLOAD_ACTION_INVALID = 60081
};
@@ -1997,7 +2060,7 @@ MHD_FN_CONST_;
* #MHD_SIZE_UNKNOWN for chunked uploads (if the
* final chunk has not been processed yet)
* @return action how to proceed, NULL
- * if the request must be closed due to a serious
+ * if the request must be aborted due to a serious
* error while handling the request (implies closure
* of underling data stream, for HTTP/1.1 it means
* socket closure).
@@ -2259,7 +2322,7 @@ struct MHD_EventUpdateContext;
* NULL if @a fd socket was not registered before
* @param ecb_cntx the context handle to be used
* with #MHD_daemon_event_update()
- * @return NULL if error (to connection will be closed),
+ * @return NULL if error (to connection will be aborted),
* or the new socket context
* @ingroup event
*/
@@ -3238,13 +3301,13 @@ typedef void
enum MHD_FIXED_ENUM_MHD_SET_ MHD_StreamNotificationCode
{
/**
- * A new connection has been started.
+ * A new stream has been started.
* @ingroup request
*/
MHD_STREAM_NOTIFY_STARTED = 0
,
/**
- * A connection is closed.
+ * A stream is closed.
* @ingroup request
*/
MHD_STREAM_NOTIFY_CLOSED = 1
@@ -4723,7 +4786,7 @@ MHD_FN_PAR_NONNULL_ (4) MHD_FN_PAR_OUT_SIZE_ (4,3);
* @return NULL if no such item was found
* @ingroup request
*/
-MHD_EXTERN_ const struct MHD_String *
+MHD_EXTERN_ const struct MHD_StringNullable *
MHD_request_get_value (struct MHD_Request *MHD_RESTRICT request,
enum MHD_ValueKind kind,
const char *MHD_RESTRICT key)
@@ -5122,7 +5185,7 @@ MHD_FN_PAR_NONNULL_ALL_;
* @param request the request to create the action for
* @param[in] response the response to convert,
* if NULL then this function is equivalent to
- * #MHD_action_close_connection() call
+ * #MHD_action_abort_connection() call
* @return pointer to the action, the action must be consumed
* otherwise response object may leak;
* NULL if failed (no memory) or if any action has been already
@@ -5145,7 +5208,7 @@ MHD_FN_PAR_NONNULL_(1);
* @return action operation, always NULL
* @ingroup action
*/
-#define MHD_action_close_connection(req) \
+#define MHD_action_abort_request(req) \
MHD_STATIC_CAST_ (const struct MHD_Action *, NULL)
@@ -5674,7 +5737,7 @@ MHD_FN_RETURNS_NONNULL_ MHD_FN_PAR_NONNULL_ALL_;
* @param request the request to create the action for
* @param[in] response the response to convert,
* if NULL then this function is equivalent to
- * #MHD_upload_action_close_connection() call
+ * #MHD_upload_action_abort_request() call
* @return pointer to the action, the action must be consumed
* otherwise response object may leak;
* NULL if failed (no memory) or if any action has been already
@@ -5690,6 +5753,9 @@ MHD_FN_PAR_NONNULL_(1);
/**
* Action telling MHD to continue processing the upload.
+ * Valid only for incremental upload processing.
+ * Works as #MHD_upload_action_abort_request() if used for full upload callback
+ * or for the final (with zero data) incremental callback.
*
* @param request the request to make an action
* @return action operation,
@@ -5709,7 +5775,7 @@ MHD_FN_RETURNS_NONNULL_;
* @return action operation, always NULL
* @ingroup action
*/
-#define MHD_upload_action_close_connection(req) \
+#define MHD_upload_action_abort_request(req) \
MHD_STATIC_CAST_ (const struct MHD_UploadAction *, NULL)
#ifndef MHD_UPLOADCALLBACK_DEFINED
@@ -5727,10 +5793,11 @@ MHD_FN_RETURNS_NONNULL_;
* valid only until return from the callback,
* NULL when all data have been processed
* @return action specifying how to proceed:
- * #MHD_upload_action_continue() if all is well,
+ * #MHD_upload_action_continue() to continue upload (for incremental
+ * upload processing only),
* #MHD_upload_action_suspend() to stop reading the upload until
* the request is resumed,
- * #MHD_upload_action_close_connection() to close the socket,
+ * #MHD_upload_action_abort_request() to close the socket,
* or a response to discard the rest of the upload and transmit
* the response
* @ingroup action
@@ -5833,7 +5900,7 @@ MHD_FN_PAR_NONNULL_ (1);
* #MHD_upload_action_continue() if all is well,
* #MHD_upload_action_suspend() to stop reading the upload until
* the request is resumed,
- * #MHD_upload_action_close_connection() to close the socket,
+ * #MHD_upload_action_abort_request() to close the socket,
* or a response to discard the rest of the upload and transmit
* the response
* @ingroup action
@@ -5890,7 +5957,7 @@ typedef const struct MHD_UploadAction *
* @sa #MHD_D_OPTION_LARGE_POOL_SIZE()
* @ingroup action
*/
-MHD_EXTERN_ struct MHD_Action *
+MHD_EXTERN_ const struct MHD_Action *
MHD_action_post_processor (struct MHD_Request *request,
size_t pp_buffer_size,
size_t pp_stream_limit, // FIXME: Remove?
Duplicated with pp_buffer_size
diff --git a/src/mhd2/Makefile.am b/src/mhd2/Makefile.am
index 1c569739..fa855adc 100644
--- a/src/mhd2/Makefile.am
+++ b/src/mhd2/Makefile.am
@@ -26,25 +26,38 @@ libmicrohttpd2_la_SOURCES = \
autoinit_funcs.h \
sys_null_macro.h sys_base_types.h sys_bool_type.h \
sys_sockets_types.h sys_sockets_headers.h sys_ip_headers.h \
- sys_errno.h sys_malloc.h \
+ sys_errno.h sys_file_fd.h sys_malloc.h \
sys_poll.h \
sys_sendfile.h \
compat_calloc.h \
mhd_assert.h \
mhd_tristate.h \
- mhd_socket_types.h mhd_sockets_macros.h \
+ mhd_socket_type.h mhd_sockets_macros.h \
mhd_sockets_funcs.c mhd_sockets_funcs.h \
+ mhd_socket_error.c mhd_socket_error.h \
+ mhd_atomic_counter.c mhd_atomic_counter.h \
+ mhd_str.c mhd_str.h \
+ mhd_str_macros.h mhd_str_types.h \
+ mhd_buffer.h \
+ mhd_limits.h \
mhd_iovec.h \
mhd_panic.c mhd_panic.h \
mhd_lib_init.c mhd_lib_init_impl.h mhd_lib_init.h \
mhd_dlinked_list.h \
+ mhd_connection.h \
mhd_locks.h \
mhd_itc.c mhd_itc.h mhd_itc_types.h \
mhd_threads.c mhd_threads.h sys_thread_entry_type.h \
mhd_mono_clock.c mhd_mono_clock.h \
mhd_mempool.c mhd_mempool.h \
- mhd_daemon.h daemon_funcs.c daemon_funcs.h \
+ mhd_recv.c mhd_recv.h \
+ mhd_send.c mhd_send.h \
+ mhd_daemon.h \
mhd_public_api.h \
+ mhd_request.h mhd_reply.h mhd_response.h \
+ http_method.h http_prot_ver.h \
+ http_status_str.c http_status_str.h \
+ action.c mhd_action.h \
events_process.c events_process.h \
daemon_logger.c daemon_logger.h \
daemon_logger_default.c daemon_logger_default.h \
@@ -52,9 +65,21 @@ libmicrohttpd2_la_SOURCES = \
daemon_create.c \
daemon_start.c \
daemon_add_conn.c daemon_add_conn.h \
- mhd_connection.h mhd_request.h mhd_reply.h \
- response_from.c response_from.h
-
+ daemon_funcs.c daemon_funcs.h \
+ conn_data_process.c conn_data_process.h \
+ conn_data_recv.c conn_data_recv.h \
+ request_funcs.c request_funcs.h \
+ request_get_value.c request_get_value.h \
+ respond_with_error.h \
+ response_from.c response_from.h \
+ response_add_header.c response_add_header.h \
+ response_destroy.c response_destroy.h \
+ response_funcs.c response_funcs.h \
+ response_set_options.c response_set_options.h response_options.h \
+ stream_funcs.c stream_funcs.h \
+ stream_process_states.c stream_process_states.h \
+ stream_process_request.c stream_process_request.h \
+ stream_process_reply.h
if ! HAVE_SYS_CALLOC
libmicrohttpd2_la_SOURCES += \
diff --git a/src/mhd2/action.c b/src/mhd2/action.c
index 9f37cf12..0971832a 100644
--- a/src/mhd2/action.c
+++ b/src/mhd2/action.c
@@ -37,7 +37,7 @@ const struct MHD_Action *
MHD_action_suspend (struct MHD_Request *request)
{
struct MHD_Action *const restrict head_act = &(request->app_act.head_act);
- if (mhd_UPLOAD_ACTION_NO_ACTION != head_act->act)
+ if (mhd_ACTION_NO_ACTION != head_act->act)
return (const struct MHD_Action *) NULL;
head_act->act = mhd_ACTION_SUSPEND;
@@ -100,7 +100,7 @@ MHD_action_process_upload (struct MHD_Request *request,
MHD_EXTERN_
-MHD_FN_PAR_NONNULL_ (1) struct MHD_Action *
+MHD_FN_PAR_NONNULL_ (1) const struct MHD_Action *
MHD_action_post_processor (struct MHD_Request *request,
size_t pp_buffer_size,
size_t pp_stream_limit,
@@ -110,7 +110,8 @@ MHD_action_post_processor (struct MHD_Request *request,
MHD_PostDataFinished done_cb,
void *done_cb_cls)
{
- struct MHD_Action *const restrict head_act = &(request->app_act.head_act);
+ struct MHD_Action *const restrict head_act =
+ &(request->app_act.head_act);
if (mhd_ACTION_NO_ACTION != head_act->act)
return (const struct MHD_Action *) NULL;
if (NULL == done_cb)
@@ -133,7 +134,8 @@ MHD_EXTERN_ MHD_FN_RETURNS_NONNULL_ MHD_FN_PAR_NONNULL_ALL_
const struct MHD_UploadAction *
MHD_upload_action_suspend (struct MHD_Request *request)
{
- struct MHD_Action *const restrict upl_act = &(request->app_act.upl_act);
+ struct MHD_UploadAction *const restrict upl_act =
+ &(request->app_act.upl_act);
if (mhd_UPLOAD_ACTION_NO_ACTION != upl_act->act)
return (const struct MHD_UploadAction *) NULL;
@@ -148,7 +150,8 @@ MHD_FN_PAR_NONNULL_ (1) const struct MHD_UploadAction *
MHD_upload_action_from_response (struct MHD_Request *request,
struct MHD_Response *response)
{
- struct MHD_Action *const restrict upl_act = &(request->app_act.upl_act);
+ struct MHD_UploadAction *const restrict upl_act =
+ &(request->app_act.upl_act);
if (mhd_UPLOAD_ACTION_NO_ACTION != upl_act->act)
return (const struct MHD_UploadAction *) NULL;
@@ -162,7 +165,8 @@ MHD_upload_action_from_response (struct MHD_Request
*request,
MHD_EXTERN_ MHD_FN_RETURNS_NONNULL_ const struct MHD_UploadAction *
MHD_upload_action_continue (struct MHD_Request *request)
{
- struct MHD_Action *const restrict upl_act = &(request->app_act.upl_act);
+ struct MHD_UploadAction *const restrict upl_act =
+ &(request->app_act.upl_act);
if (mhd_UPLOAD_ACTION_NO_ACTION != upl_act->act)
return (const struct MHD_UploadAction *) NULL;
diff --git a/src/mhd2/conn_data_process.c b/src/mhd2/conn_data_process.c
index 0b364d2b..c1a3b6bb 100644
--- a/src/mhd2/conn_data_process.c
+++ b/src/mhd2/conn_data_process.c
@@ -44,6 +44,7 @@
#include "conn_data_recv.h"
#include "conn_data_send.h"
+#include "stream_process_states.h"
MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_ bool
mhd_conn_process_recv_send_data (struct MHD_Connection *restrict c)
@@ -62,7 +63,7 @@ mhd_conn_process_recv_send_data (struct MHD_Connection
*restrict c)
bool use_recv;
use_recv = (0 != (mhd_SOCKET_NET_STATE_RECV_READY & c->sk_ready));
use_recv = use_recv ||
- (has_sock_err && c->sk_nonblck);
+ (has_sock_err && c->sk_nonblck);
if (use_recv)
{
@@ -86,9 +87,9 @@ mhd_conn_process_recv_send_data (struct MHD_Connection
*restrict c)
or has not been performed yet. */
use_send = (0 != (mhd_SOCKET_NET_STATE_SEND_READY & c->sk_ready));
use_send = use_send ||
- (data_processed && (! send_ready_state_known) && c->sk_nonblck);
+ (data_processed && (! send_ready_state_known) && c->sk_nonblck);
use_send = use_send ||
- (has_sock_err && c->sk_nonblck);
+ (has_sock_err && c->sk_nonblck);
if (use_send)
{
diff --git a/src/mhd2/conn_data_process.h b/src/mhd2/conn_data_process.h
index 1ad1dee2..5667bbfc 100644
--- a/src/mhd2/conn_data_process.h
+++ b/src/mhd2/conn_data_process.h
@@ -40,16 +40,17 @@ struct MHD_Connection; /* forward declaration */
*/
MHD_INTERNAL bool
mhd_conn_process_recv_send_data (struct MHD_Connection *restrict c)
-MHD_FN_PAR_NONNULL_ALL_ ;
+MHD_FN_PAR_NONNULL_ALL_;
/**
- * Finally close and clean-up connection.
- * Must be performed only when connection thread (for thread-per-connection)
- * has stopped.
- * @param c the connection to close
+ * Update "active" state, move to the activity lists if necessary.
+ * Update "event loop info"
+ * @param c the connection to use
+ * @return true if data processed successfully,
+ * false if connection needs to be closed
*/
-MHD_INTERNAL void
-mhd_conn_close_final (struct MHD_Connection *restrict c)
-MHD_FN_PAR_NONNULL_ALL_ ;
+MHD_INTERNAL bool
+mhd_conn_update_active_state (struct MHD_Connection *restrict c)
+MHD_FN_PAR_NONNULL_ALL_;
#endif /* ! MHD_DATA_PROCESS_H */
diff --git a/src/mhd2/conn_data_recv.c b/src/mhd2/conn_data_recv.c
index bf0bc3ec..15ae732d 100644
--- a/src/mhd2/conn_data_recv.c
+++ b/src/mhd2/conn_data_recv.c
@@ -1,7 +1,6 @@
/*
This file is part of GNU libmicrohttpd
- Copyright (C) 2015-2024 Evgeny Grin (Karlson2k)
- Copyright (C) 2007-2020 Daniel Pittman and Christian Grothoff
+ Copyright (C) 2024 Evgeny Grin (Karlson2k)
GNU libmicrohttpd is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
@@ -23,9 +22,6 @@
* @file src/mhd2/conn_data_recv.c
* @brief The implementation of data receiving functions for connection
* @author Karlson2k (Evgeny Grin)
- *
- * Based on the MHD v0.x code by Daniel Pittman, Christian Grothoff, Evgeny
Grin
- * and other contributors.
*/
#include "conn_data_recv.h"
@@ -40,13 +36,12 @@
#include "mhd_connection.h"
#include "mhd_recv.h"
+#include "stream_funcs.h"
MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_ void
-mhd_conn_data_recv (struct MHD_Connection restrict *c,
- bool has_err)
+mhd_conn_data_recv (struct MHD_Connection *restrict c,
+ bool has_err)
{
- ssize_t bytes_read;
- uint_fast64_t dummy_buf;
void *buf;
size_t buf_size;
size_t received;
@@ -74,7 +69,7 @@ mhd_conn_data_recv (struct MHD_Connection restrict *c,
{
/* Re-try last time to detect the error */
uint_fast64_t dummy_buf;
- res = mhd_recv (c, &dummy_buf, sizeof(dummy_buf), &received);
+ res = mhd_recv (c, sizeof(dummy_buf), (char *) &dummy_buf, &received);
}
if (mhd_SOCKET_ERR_IS_HARD (res))
{
@@ -86,11 +81,11 @@ mhd_conn_data_recv (struct MHD_Connection restrict *c,
return;
}
- if (0 == bytes_read)
+ if (0 == received)
c->sk_rmt_shut_wr = true;
- c->read_buffer_offset += (size_t) bytes_read;
- MHD_update_last_activity_ (c); // TODO: centralise activity update
+ c->read_buffer_offset += received;
+ mhd_stream_update_activity_mark (c); // TODO: centralise activity update
return;
}
diff --git a/src/mhd2/conn_data_recv.h b/src/mhd2/conn_data_recv.h
index 927f103a..9edc4aeb 100644
--- a/src/mhd2/conn_data_recv.h
+++ b/src/mhd2/conn_data_recv.h
@@ -42,7 +42,7 @@ struct MHD_Connection; /* forward declarations */
* type is performed
*/
MHD_INTERNAL void
-mhd_conn_data_recv (struct MHD_Connection restrict *c,
+mhd_conn_data_recv (struct MHD_Connection *restrict c,
bool has_err)
MHD_FN_PAR_NONNULL_ALL_;
diff --git a/src/mhd2/conn_data_send.c b/src/mhd2/conn_data_send.c
index 2f4cd6e0..fa15f344 100644
--- a/src/mhd2/conn_data_send.c
+++ b/src/mhd2/conn_data_send.c
@@ -69,13 +69,13 @@ check_write_done (struct MHD_Connection *restrict
connection,
MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_ void
-mhd_conn_data_send (struct MHD_Connection restrict *c,
+mhd_conn_data_send (struct MHD_Connection *restrict c,
bool has_err)
{
static const char http_100_continue_msg[] =
mdh_HTTP_1_1_100_CONTINUE_REPLY;
static const size_t http_100_continue_msg_len =
- mhd_SSTR_LEN(mdh_HTTP_1_1_100_CONTINUE_REPLY);
+ mhd_SSTR_LEN (mdh_HTTP_1_1_100_CONTINUE_REPLY);
enum mhd_SocketError res;
size_t sent;
@@ -121,8 +121,8 @@ mhd_conn_data_send (struct MHD_Connection restrict *c,
mhd_assert (mhd_RESPONSE_CONTENT_DATA_BUFFER == resp->cntn_dtype);
res = mhd_send_hdr_and_body (c,
- c->write_buffer +
- c->write_buffer_send_offset,
+ c->write_buffer
+ + c->write_buffer_send_offset,
wb_ready,
false,
(const char *) resp->cntn.buf,
@@ -136,8 +136,8 @@ mhd_conn_data_send (struct MHD_Connection restrict *c,
* for any other reason or reply body is dynamically generated. */
/* Do not send the body data even if it's available. */
res = mhd_send_hdr_and_body (c,
- c->write_buffer +
- c->write_buffer_send_offset,
+ c->write_buffer
+ + c->write_buffer_send_offset,
wb_ready,
false,
NULL,
@@ -183,8 +183,8 @@ mhd_conn_data_send (struct MHD_Connection restrict *c,
mhd_assert (mhd_RESPONSE_CONTENT_DATA_BUFFER == resp->cntn_dtype);
res = mhd_send_data (c,
- (const char *) resp->cntn.buf +
- c->rp.rsp_cntn_read_pos,
+ (const char *) resp->cntn.buf
+ + c->rp.rsp_cntn_read_pos,
c->rp.rsp_cntn_read_pos - resp->cntn_size,
true,
&sent);
@@ -245,8 +245,8 @@ mhd_conn_data_send (struct MHD_Connection restrict *c,
else if (MHD_CONNECTION_FOOTERS_SENDING == c->state)
{
res = mhd_send_data (c,
- c->write_buffer +
- c->write_buffer_send_offset,
+ c->write_buffer
+ + c->write_buffer_send_offset,
c->write_buffer_append_offset
- c->write_buffer_send_offset,
true,
@@ -267,9 +267,9 @@ mhd_conn_data_send (struct MHD_Connection restrict *c,
if (mhd_SOCKET_ERR_NO_ERROR != res)
{
- MHD_update_last_activity_ (c); // TODO: centralise activity mark updates
+ mhd_stream_update_activity_mark (c); // TODO: centralise activity mark
updates
}
- else if (mhd_SOCKET_ERR_IS_HARD(res))
+ else if (mhd_SOCKET_ERR_IS_HARD (res))
{
c->sk_discnt_err = res;
c->sk_ready =
diff --git a/src/mhd2/conn_data_send.h b/src/mhd2/conn_data_send.h
index d3d88190..bce642a6 100644
--- a/src/mhd2/conn_data_send.h
+++ b/src/mhd2/conn_data_send.h
@@ -42,7 +42,7 @@ struct MHD_Connection; /* forward declarations */
* type is performed
*/
MHD_INTERNAL void
-mhd_conn_data_send (struct MHD_Connection restrict *c,
+mhd_conn_data_send (struct MHD_Connection *restrict c,
bool has_err)
MHD_FN_PAR_NONNULL_ALL_;
diff --git a/src/mhd2/daemon_add_conn.c b/src/mhd2/daemon_add_conn.c
index 22a0a592..21c3d241 100644
--- a/src/mhd2/daemon_add_conn.c
+++ b/src/mhd2/daemon_add_conn.c
@@ -99,7 +99,7 @@ connection_set_initial_state (struct MHD_Connection *restrict
c)
c->read_buffer_offset = 0;
read_buf_size = c->daemon->conns.cfg.mem_pool_size / 2;
c->read_buffer
- = MHD_pool_allocate (c->pool,
+ = mhd_pool_allocate (c->pool,
read_buf_size,
false);
c->read_buffer_size = read_buf_size;
@@ -131,7 +131,7 @@ connection_clean_destroy (struct MHD_Connection *restrict c,
// TODO: upgrade support
- MHD_pool_destroy (c->pool);
+ mhd_pool_destroy (c->pool);
// TODO: TLS deinit
@@ -314,7 +314,7 @@ new_connection_process_ (struct MHD_Daemon *restrict daemon,
* intensively used memory area is allocated in "good"
* (for the thread) memory region. It is important with
* NUMA and/or complex cache hierarchy. */
- connection->pool = MHD_pool_create (daemon->conns.cfg.mem_pool_size);
+ connection->pool = mdh_pool_create (daemon->conns.cfg.mem_pool_size);
if (NULL == connection->pool)
{ /* 'pool' creation failed */
MHD_LOG_MSG (daemon, MHD_SC_POOL_MALLOC_FAILURE, \
@@ -430,7 +430,7 @@ new_connection_process_ (struct MHD_Daemon *restrict daemon,
daemon->conns.count--;
daemon->conns.block_new = false;
}
- MHD_pool_destroy (connection->pool);
+ mhd_pool_destroy (connection->pool);
}
/* Free resources allocated before the call of this functions */
diff --git a/src/mhd2/daemon_add_conn.h b/src/mhd2/daemon_add_conn.h
index 3238d02f..dacac27a 100644
--- a/src/mhd2/daemon_add_conn.h
+++ b/src/mhd2/daemon_add_conn.h
@@ -35,6 +35,7 @@
#include "sys_bool_type.h"
struct MHD_Daemon; /* Forward declaration */
+struct MHD_Connection; /* Forward declaration */
/**
* The result of the accepting of the new connection
@@ -79,5 +80,15 @@ enum mhd_DaemonAcceptResult
MHD_INTERNAL enum mhd_DaemonAcceptResult
mhd_daemon_accept_connection (struct MHD_Daemon *restrict daemon);
+/**
+ * Finally close and clean-up connection.
+ * Must be performed only when connection thread (for thread-per-connection)
+ * has stopped.
+ * @param c the connection to close
+ */
+MHD_INTERNAL void
+mhd_conn_close_final (struct MHD_Connection *restrict c)
+MHD_FN_PAR_NONNULL_ALL_;
+
#endif /* ! MHD_DAEMON_ADD_CONN */
diff --git a/src/mhd2/daemon_funcs.c b/src/mhd2/daemon_funcs.c
index 6640ef43..ae6e6f74 100644
--- a/src/mhd2/daemon_funcs.c
+++ b/src/mhd2/daemon_funcs.c
@@ -26,14 +26,31 @@
#include "mhd_sys_options.h"
-#ifdef MHD_USE_THREADS
-
#include "daemon_funcs.h"
+#include "sys_base_types.h"
+#include "sys_malloc.h"
+
+#include "mhd_assert.h"
#include "mhd_itc.h"
#include "mhd_daemon.h"
#include "daemon_logger.h"
+
+MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_
+MHD_FN_MUST_CHECK_RESULT_ struct MHD_Daemon *
+mhd_daemon_get_master_daemon (struct MHD_Daemon *restrict d)
+{
+#ifdef MHD_USE_THREADS
+ if (mhd_D_TYPE_HAS_MASTER_DAEMON (d->threading.d_type))
+ return d->threading.hier.master;
+#endif /* MHD_USE_THREADS */
+ return d;
+}
+
+
+#ifdef MHD_USE_THREADS
+
MHD_INTERNAL bool
mhd_daemon_trigger_itc (struct MHD_Daemon *restrict d)
{
@@ -49,3 +66,117 @@ mhd_daemon_trigger_itc (struct MHD_Daemon *restrict d)
#endif /* MHD_USE_THREADS */
+
+
+MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_ void
+mhd_daemon_resume_conns (struct MHD_Daemon *restrict d)
+{
+ (void) d;
+ mhd_assert (0 && "Not implemented yet");
+}
+
+
+MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_
+MHD_FN_MUST_CHECK_RESULT_ bool
+mhd_daemon_claim_lbuf (struct MHD_Daemon *d,
+ size_t requested_size)
+{
+ bool ret;
+ struct MHD_Daemon *const masterd = mhd_daemon_get_master_daemon (d);
+ mhd_assert (0 != requested_size);
+ if (0 == masterd->req_cfg.large_buf.space_left)
+ return false; /* Shortcut for typical use without large buffer */
+
+ ret = false;
+ mhd_mutex_lock_chk (&(masterd->req_cfg.large_buf.lock));
+ if (masterd->req_cfg.large_buf.space_left >= requested_size)
+ {
+ masterd->req_cfg.large_buf.space_left -= requested_size;
+ ret = true;
+ }
+ mhd_mutex_unlock_chk (&(masterd->req_cfg.large_buf.lock));
+ return ret;
+}
+
+
+MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_ void
+mhd_daemon_reclaim_lbuf (struct MHD_Daemon *d,
+ size_t reclaimed_size)
+{
+ struct MHD_Daemon *const masterd = mhd_daemon_get_master_daemon (d);
+ mhd_assert (0 != reclaimed_size);
+ mhd_mutex_lock_chk (&(masterd->req_cfg.large_buf.lock));
+ masterd->req_cfg.large_buf.space_left += reclaimed_size;
+ mhd_mutex_unlock_chk (&(masterd->req_cfg.large_buf.lock));
+}
+
+
+MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_ MHD_FN_MUST_CHECK_RESULT_
+MHD_FN_PAR_OUT_ (3) bool
+mhd_daemon_get_lbuf (struct MHD_Daemon *restrict d,
+ size_t requested_size,
+ struct mhd_Buffer *restrict buf)
+{
+ if (! mhd_daemon_claim_lbuf (d, requested_size))
+ {
+ buf->size = 0;
+ buf->buf = NULL;
+ return false;
+ }
+ buf->buf = (char *) malloc (requested_size);
+ if (NULL == buf->buf)
+ {
+ buf->size = 0;
+ mhd_daemon_reclaim_lbuf (d, requested_size);
+ return false;
+ }
+ buf->size = requested_size;
+ return true;
+}
+
+
+MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_ MHD_FN_MUST_CHECK_RESULT_
+MHD_FN_PAR_INOUT_ (3) bool
+mhd_daemon_grow_lbuf (struct MHD_Daemon *restrict d,
+ size_t grow_size,
+ struct mhd_Buffer *restrict buf)
+{
+ void *new_alloc;
+ mhd_assert (NULL != buf->buf || 0 == buf->size);
+ mhd_assert (0 != buf->size || NULL == buf->buf);
+
+ if (! mhd_daemon_claim_lbuf (d, grow_size))
+ return false;
+
+ if (NULL == buf->buf)
+ new_alloc = malloc (grow_size);
+ else
+ new_alloc = realloc (buf->buf, buf->size + grow_size);
+ if (NULL == new_alloc)
+ {
+ mhd_daemon_reclaim_lbuf (d, grow_size);
+ return false;
+ }
+
+ buf->buf = (char *) new_alloc;
+ buf->size += grow_size;
+
+ return true;
+}
+
+
+MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_
+MHD_FN_PAR_INOUT_ (2) void
+mhd_daemon_free_lbuf (struct MHD_Daemon *restrict d,
+ struct mhd_Buffer *restrict buf)
+{
+ if (0 == buf->size)
+ {
+ mhd_assert (NULL == buf->buf);
+ return;
+ }
+ free (buf->buf);
+ buf->buf = NULL;
+ mhd_daemon_reclaim_lbuf (d, buf->size);
+ buf->size = 0;
+}
diff --git a/src/mhd2/daemon_funcs.h b/src/mhd2/daemon_funcs.h
index e5acd8aa..73cc3a79 100644
--- a/src/mhd2/daemon_funcs.h
+++ b/src/mhd2/daemon_funcs.h
@@ -29,13 +29,24 @@
#include "mhd_sys_options.h"
-#ifdef MHD_USE_THREADS
-
#include "sys_bool_type.h"
+#include "mhd_buffer.h"
+
struct MHD_Daemon; /* forward declaration */
+/**
+ * Get controlling daemon
+ * @param d the daemon to get controlling daemon
+ * @return the master daemon (possible the same as the @a d)
+ */
+MHD_INTERNAL struct MHD_Daemon *
+mhd_daemon_get_master_daemon (struct MHD_Daemon *restrict d)
+MHD_FN_PAR_NONNULL_ALL_ MHD_FN_MUST_CHECK_RESULT_;
+
+#ifdef MHD_USE_THREADS
+
/**
* Trigger daemon ITC.
* This should cause daemon's thread to stop waiting for the network events
@@ -46,6 +57,7 @@ struct MHD_Daemon; /* forward declaration */
MHD_INTERNAL bool
mhd_daemon_trigger_itc (struct MHD_Daemon *restrict d);
+#endif /* MHD_USE_THREADS */
/**
@@ -54,8 +66,73 @@ mhd_daemon_trigger_itc (struct MHD_Daemon *restrict d);
*/
MHD_INTERNAL void
mhd_daemon_resume_conns (struct MHD_Daemon *restrict d)
-MHD_FN_PAR_NONNULL_ALL_ ;
+MHD_FN_PAR_NONNULL_ALL_;
+
+
+/**
+ * Request allocation of the large buffer
+ * @param d the daemon to use
+ * @param requested_size the requested size of allocation
+ * @return true if allocation allowed and counted,
+ * false otherwise
+ */
+MHD_INTERNAL bool
+mhd_daemon_claim_lbuf (struct MHD_Daemon *restrict d,
+ size_t requested_size)
+MHD_FN_PAR_NONNULL_ALL_ MHD_FN_MUST_CHECK_RESULT_;
+
+
+/**
+ * Reclaim the large buffer allocation.
+ * Must be called when the allocation has been already freed.
+ * @param d the daemon to use
+ * @param reclaimed_size the deallocated size
+ */
+MHD_INTERNAL void
+mhd_daemon_reclaim_lbuf (struct MHD_Daemon *restrict d,
+ size_t reclaimed_size)
+MHD_FN_PAR_NONNULL_ALL_;
+
+/**
+ * Allocate the large buffer
+ * @param d the daemon to use
+ * @param requested_size the requested size of allocation
+ * @param[out] buf the buffer to allocate
+ * @return true if buffer is allocated,
+ * false otherwise
+ */
+MHD_INTERNAL bool
+mhd_daemon_get_lbuf (struct MHD_Daemon *restrict d,
+ size_t requested_size,
+ struct mhd_Buffer *restrict buf)
+MHD_FN_PAR_NONNULL_ALL_ MHD_FN_MUST_CHECK_RESULT_
+ MHD_FN_PAR_OUT_ (3);
+
+/**
+ * Grow the large buffer, which previously was allocated
+ * @param d the daemon to use
+ * @param grow_size the requested size of grow
+ * @param[in,out] buf the buffer to grow
+ * @return true if buffer has been grown,
+ * false otherwise
+ */
+MHD_INTERNAL bool
+mhd_daemon_grow_lbuf (struct MHD_Daemon *restrict d,
+ size_t grow_size,
+ struct mhd_Buffer *restrict buf)
+MHD_FN_PAR_NONNULL_ALL_ MHD_FN_MUST_CHECK_RESULT_
+ MHD_FN_PAR_INOUT_ (3);
+
+
+/**
+ * Free large buffer.
+ * @param d the daemon to use
+ * @param[in,out] buf the buffer to free
+ */
+MHD_INTERNAL void
+mhd_daemon_free_lbuf (struct MHD_Daemon *restrict d,
+ struct mhd_Buffer *restrict buf)
+MHD_FN_PAR_NONNULL_ALL_ MHD_FN_PAR_INOUT_ (2);
-#endif /* MHD_USE_THREADS */
#endif /* ! MHD_DAEMON_FUNCS_H */
diff --git a/src/mhd2/daemon_options.h b/src/mhd2/daemon_options.h
index 5cad1b28..973f5ab4 100644
--- a/src/mhd2/daemon_options.h
+++ b/src/mhd2/daemon_options.h
@@ -137,6 +137,12 @@ struct DaemonOptions {
unsigned int global_connection_limit;
+ /**
+ * // TODO: add settings
+ */
+ size_t global_large_buffer_size;
+
+
/**
* Value for #MHD_D_O_PER_IP_LIMIT.
* FIXME
diff --git a/src/mhd2/daemon_start.c b/src/mhd2/daemon_start.c
index 52aa11e3..e98e0c2a 100644
--- a/src/mhd2/daemon_start.c
+++ b/src/mhd2/daemon_start.c
@@ -107,8 +107,8 @@ dsettings_release (struct DaemonOptions *s)
* @return MHD_SC_OK on success,
* the error code otherwise
*/
-MHD_FN_PAR_NONNULL_ (1) MHD_FN_PAR_NONNULL_ (2)
-MHD_FN_MUST_CHECK_RESULT_ static enum MHD_StatusCode
+static MHD_FN_PAR_NONNULL_ (1) MHD_FN_PAR_NONNULL_ (2)
+MHD_FN_MUST_CHECK_RESULT_ enum MHD_StatusCode
daemon_set_work_mode (struct MHD_Daemon *restrict d,
struct DaemonOptions *restrict s)
{
@@ -982,7 +982,7 @@ create_bind_listen_stream_socket (struct MHD_Daemon
*restrict d,
* Detect and set the type and port of the listening socket
* @param d the daemon to use
*/
-MHD_FN_PAR_NONNULL_ (1) static void
+static MHD_FN_PAR_NONNULL_ (1) void
detect_listen_type_and_port (struct MHD_Daemon *restrict d)
{
union mhd_SockaddrAny sa_all;
@@ -1053,7 +1053,7 @@ detect_listen_type_and_port (struct MHD_Daemon *restrict
d)
/**
* Initialise daemon's epoll FD
*/
-MHD_FN_PAR_NONNULL_ (1) static enum MHD_StatusCode
+static MHD_FN_PAR_NONNULL_ (1) enum MHD_StatusCode
init_epoll (struct MHD_Daemon *restrict d)
{
int e_fd;
@@ -1129,8 +1129,8 @@ deinit_epoll (struct MHD_Daemon *restrict d)
* @return #MHD_SC_OK on success,
* the error code otherwise
*/
-MHD_FN_PAR_NONNULL_ (1) MHD_FN_PAR_NONNULL_ (2) \
- MHD_FN_MUST_CHECK_RESULT_ static enum MHD_StatusCode
+static MHD_FN_PAR_NONNULL_ (1) MHD_FN_PAR_NONNULL_ (2) \
+ MHD_FN_MUST_CHECK_RESULT_ enum MHD_StatusCode
daemon_choose_and_preinit_events (struct MHD_Daemon *restrict d,
struct DaemonOptions *restrict s)
{
@@ -1318,8 +1318,8 @@ daemon_choose_and_preinit_events (struct MHD_Daemon
*restrict d,
* @return #MHD_SC_OK on success,
* the error code otherwise
*/
-MHD_FN_PAR_NONNULL_ (1) MHD_FN_PAR_NONNULL_ (2) \
- MHD_FN_MUST_CHECK_RESULT_ static enum MHD_StatusCode
+static MHD_FN_PAR_NONNULL_ (1) MHD_FN_PAR_NONNULL_ (2) \
+ MHD_FN_MUST_CHECK_RESULT_ enum MHD_StatusCode
daemon_init_net (struct MHD_Daemon *restrict d,
struct DaemonOptions *restrict s)
{
@@ -1433,6 +1433,42 @@ dauth_init (struct MHD_Daemon *restrict d,
#endif
+/**
+ * Initialise large buffer tracking.
+ * @param d the daemon object
+ * @param s the user settings
+ * @return #MHD_SC_OK on success,
+ * the error code otherwise
+ */
+static MHD_FN_PAR_NONNULL_ (1) MHD_FN_PAR_NONNULL_ (2) \
+ MHD_FN_MUST_CHECK_RESULT_ enum MHD_StatusCode
+daemon_init_large_buf (struct MHD_Daemon *restrict d,
+ struct DaemonOptions *restrict s)
+{
+ d->req_cfg.large_buf.space_left = s->global_large_buffer_size;
+ if (! mhd_mutex_init_short (&(d->req_cfg.large_buf.lock)))
+ {
+ MHD_LOG_MSG (d, MHD_SC_MUTEX_INIT_FAILURE, \
+ "Failed to initialise mutex for the global large buffer.");
+ return MHD_SC_MUTEX_INIT_FAILURE;
+ }
+ return MHD_SC_OK;
+}
+
+
+/**
+ * Initialise large buffer tracking.
+ * @param d the daemon object
+ * @param s the user settings
+ * @return #MHD_SC_OK on success,
+ * the error code otherwise
+ */
+static MHD_FN_PAR_NONNULL_ (1) void
+daemon_deinit_large_buf (struct MHD_Daemon *restrict d)
+{
+ mhd_mutex_destroy_chk (&(d->req_cfg.large_buf.lock));
+}
+
/**
* Finish initialisation of events processing
@@ -1440,8 +1476,8 @@ dauth_init (struct MHD_Daemon *restrict d,
* @return #MHD_SC_OK on success,
* the error code otherwise
*/
-MHD_FN_PAR_NONNULL_ (1) \
- MHD_FN_MUST_CHECK_RESULT_ static enum MHD_StatusCode
+static MHD_FN_PAR_NONNULL_ (1)
+MHD_FN_MUST_CHECK_RESULT_ enum MHD_StatusCode
allocate_events (struct MHD_Daemon *restrict d)
{
mhd_assert (0 != d->conns.cfg.count_limit);
@@ -1586,7 +1622,7 @@ allocate_events (struct MHD_Daemon *restrict d)
* @return #MHD_SC_OK on success,
* the error code otherwise
*/
-MHD_FN_PAR_NONNULL_ (1) static void
+static MHD_FN_PAR_NONNULL_ (1) void
deallocate_events (struct MHD_Daemon *restrict d)
{
mhd_assert (0 != d->conns.cfg.count_limit);
@@ -1638,8 +1674,8 @@ deallocate_events (struct MHD_Daemon *restrict d)
* @return #MHD_SC_OK on success,
* the error code otherwise
*/
-MHD_FN_PAR_NONNULL_ (1) \
- MHD_FN_MUST_CHECK_RESULT_ static enum MHD_StatusCode
+static MHD_FN_PAR_NONNULL_ (1)
+MHD_FN_MUST_CHECK_RESULT_ enum MHD_StatusCode
init_itc (struct MHD_Daemon *restrict d)
{
mhd_assert (mhd_D_TYPE_IS_VALID (d->threading.d_type));
@@ -1679,7 +1715,7 @@ init_itc (struct MHD_Daemon *restrict d)
* @return #MHD_SC_OK on success,
* the error code otherwise
*/
-MHD_FN_PAR_NONNULL_ (1) static void
+static MHD_FN_PAR_NONNULL_ (1) void
deinit_itc (struct MHD_Daemon *restrict d)
{
mhd_assert (mhd_D_TYPE_IS_VALID (d->threading.d_type));
@@ -1699,8 +1735,8 @@ deinit_itc (struct MHD_Daemon *restrict d)
* @return #MHD_SC_OK on success,
* the error code otherwise
*/
-MHD_FN_PAR_NONNULL_ (1)
-MHD_FN_MUST_CHECK_RESULT_ static enum MHD_StatusCode
+static MHD_FN_PAR_NONNULL_ (1)
+MHD_FN_MUST_CHECK_RESULT_ enum MHD_StatusCode
add_itc_and_listen_to_monitoring (struct MHD_Daemon *restrict d)
{
mhd_assert (d->dbg.net_inited);
@@ -1813,8 +1849,8 @@ add_itc_and_listen_to_monitoring (struct MHD_Daemon
*restrict d)
* @return #MHD_SC_OK on success,
* the error code otherwise
*/
-MHD_FN_PAR_NONNULL_ (1) MHD_FN_PAR_NONNULL_ (2) \
- MHD_FN_MUST_CHECK_RESULT_ static enum MHD_StatusCode
+static MHD_FN_PAR_NONNULL_ (1) MHD_FN_PAR_NONNULL_ (2)
+MHD_FN_MUST_CHECK_RESULT_ enum MHD_StatusCode
init_individual_conns (struct MHD_Daemon *restrict d,
struct DaemonOptions *restrict s)
{
@@ -1849,8 +1885,8 @@ init_individual_conns (struct MHD_Daemon *restrict d,
* @return #MHD_SC_OK on success,
* the error code otherwise
*/
-MHD_FN_PAR_NONNULL_ (1) MHD_FN_PAR_NONNULL_ (2) \
- MHD_FN_MUST_CHECK_RESULT_ static enum MHD_StatusCode
+static MHD_FN_PAR_NONNULL_ (1) MHD_FN_PAR_NONNULL_ (2)
+MHD_FN_MUST_CHECK_RESULT_ enum MHD_StatusCode
init_individual_thread_data_events_conns (struct MHD_Daemon *restrict d,
struct DaemonOptions *restrict s)
{
@@ -1903,7 +1939,7 @@ init_individual_thread_data_events_conns (struct
MHD_Daemon *restrict d,
* @return #MHD_SC_OK on success,
* the error code otherwise
*/
-MHD_FN_PAR_NONNULL_ (1) static void
+static MHD_FN_PAR_NONNULL_ (1) void
deinit_individual_thread_data_events_conns (struct MHD_Daemon *restrict d)
{
deinit_itc (d);
@@ -1924,8 +1960,8 @@ deinit_individual_thread_data_events_conns (struct
MHD_Daemon *restrict d)
* @return #MHD_SC_OK on success,
* the error code otherwise
*/
-MHD_FN_PAR_NONNULL_ (1) MHD_FN_PAR_NONNULL_ (2) \
- MHD_FN_MUST_CHECK_RESULT_ static enum MHD_StatusCode
+static MHD_FN_PAR_NONNULL_ (1) MHD_FN_PAR_NONNULL_ (2)
+MHD_FN_MUST_CHECK_RESULT_ enum MHD_StatusCode
set_connections_total_limits (struct MHD_Daemon *restrict d,
struct DaemonOptions *restrict s)
{
@@ -2157,7 +2193,7 @@ set_d_threading_type (struct MHD_Daemon *restrict d)
* @return #MHD_SC_OK on success,
* the error code otherwise
*/
-MHD_FN_PAR_NONNULL_ (1) static void
+static MHD_FN_PAR_NONNULL_ (1) void
deinit_workers_pool (struct MHD_Daemon *restrict d,
unsigned int num_workers)
{
@@ -2188,6 +2224,17 @@ deinit_workers_pool (struct MHD_Daemon *restrict d,
}
+/**
+ * Nullify worker daemon member that should be set only in master daemon
+ * @param d
+ */
+static MHD_FN_PAR_NONNULL_ (1) void
+reset_master_only_areas (struct MHD_Daemon *restrict d)
+{
+ memset (&(d->req_cfg.large_buf), 0, sizeof(d->req_cfg.large_buf));
+}
+
+
/**
* Initialise workers pool, including workers daemons.
* Do not start the threads.
@@ -2196,8 +2243,8 @@ deinit_workers_pool (struct MHD_Daemon *restrict d,
* @return #MHD_SC_OK on success,
* the error code otherwise
*/
-MHD_FN_PAR_NONNULL_ (1) MHD_FN_PAR_NONNULL_ (2) \
- MHD_FN_MUST_CHECK_RESULT_ static enum MHD_StatusCode
+static MHD_FN_PAR_NONNULL_ (1) MHD_FN_PAR_NONNULL_ (2)
+MHD_FN_MUST_CHECK_RESULT_ enum MHD_StatusCode
init_workers_pool (struct MHD_Daemon *restrict d,
struct DaemonOptions *restrict s)
{
@@ -2252,6 +2299,8 @@ init_workers_pool (struct MHD_Daemon *restrict d,
struct MHD_Daemon *restrict const worker =
d->threading.hier.pool.workers + i;
memcpy (worker, d, sizeof(struct MHD_Daemon));
+ reset_master_only_areas (d);
+
worker->threading.d_type = mhd_DAEMON_TYPE_WORKER;
worker->threading.hier.master = d;
worker->conns.cfg.count_limit = conn_per_daemon;
@@ -2318,8 +2367,8 @@ init_workers_pool (struct MHD_Daemon *restrict d,
* @return #MHD_SC_OK on success,
* the error code otherwise
*/
-MHD_FN_PAR_NONNULL_ (1) MHD_FN_PAR_NONNULL_ (2) \
- MHD_FN_MUST_CHECK_RESULT_ static enum MHD_StatusCode
+static MHD_FN_PAR_NONNULL_ (1) MHD_FN_PAR_NONNULL_ (2)
+MHD_FN_MUST_CHECK_RESULT_ enum MHD_StatusCode
daemon_init_threading_and_conn (struct MHD_Daemon *restrict d,
struct DaemonOptions *restrict s)
{
@@ -2375,7 +2424,7 @@ daemon_init_threading_and_conn (struct MHD_Daemon
*restrict d,
* @return #MHD_SC_OK on success,
* the error code otherwise
*/
-MHD_FN_PAR_NONNULL_ (1) static void
+static MHD_FN_PAR_NONNULL_ (1) void
daemon_deinit_threading_and_conn (struct MHD_Daemon *restrict d)
{
mhd_assert (d->dbg.net_inited);
@@ -2418,8 +2467,8 @@ daemon_deinit_threading_and_conn (struct MHD_Daemon
*restrict d)
* @return #MHD_SC_OK on success,
* the error code otherwise
*/
-MHD_FN_PAR_NONNULL_ (1)
-MHD_FN_MUST_CHECK_RESULT_ static enum MHD_StatusCode
+static MHD_FN_PAR_NONNULL_ (1)
+MHD_FN_MUST_CHECK_RESULT_ enum MHD_StatusCode
start_individual_daemon_thread (struct MHD_Daemon *restrict d)
{
mhd_assert (d->dbg.threading_inited);
@@ -2513,7 +2562,7 @@ stop_individual_daemon_thread (struct MHD_Daemon
*restrict d)
* @param d the daemon object, the workers threads must be running
* @param num_workers the number of threads to stop
*/
-MHD_FN_PAR_NONNULL_ (1) static void
+static MHD_FN_PAR_NONNULL_ (1) void
stop_worker_pool_threads (struct MHD_Daemon *restrict d,
unsigned int num_workers)
{
@@ -2560,8 +2609,8 @@ stop_worker_pool_threads (struct MHD_Daemon *restrict d,
* @return #MHD_SC_OK on success,
* the error code otherwise
*/
-MHD_FN_PAR_NONNULL_ (1)
-MHD_FN_MUST_CHECK_RESULT_ static enum MHD_StatusCode
+static MHD_FN_PAR_NONNULL_ (1)
+MHD_FN_MUST_CHECK_RESULT_ enum MHD_StatusCode
start_worker_pool_threads (struct MHD_Daemon *restrict d)
{
enum MHD_StatusCode res;
@@ -2602,8 +2651,8 @@ start_worker_pool_threads (struct MHD_Daemon *restrict d)
* @return #MHD_SC_OK on success,
* the error code otherwise
*/
-MHD_FN_PAR_NONNULL_ (1)
-MHD_FN_MUST_CHECK_RESULT_ static enum MHD_StatusCode
+static MHD_FN_PAR_NONNULL_ (1)
+MHD_FN_MUST_CHECK_RESULT_ enum MHD_StatusCode
daemon_start_threads (struct MHD_Daemon *restrict d)
{
mhd_assert (d->dbg.net_inited);
@@ -2641,7 +2690,7 @@ daemon_start_threads (struct MHD_Daemon *restrict d)
* @return #MHD_SC_OK on success,
* the error code otherwise
*/
-MHD_FN_PAR_NONNULL_ (1) static void
+static MHD_FN_PAR_NONNULL_ (1) void
daemon_stop_threads (struct MHD_Daemon *restrict d)
{
mhd_assert (d->dbg.net_inited);
@@ -2681,8 +2730,8 @@ daemon_stop_threads (struct MHD_Daemon *restrict d)
* @return #MHD_SC_OK on success,
* the error code otherwise
*/
-MHD_FN_PAR_NONNULL_ (1) MHD_FN_PAR_NONNULL_ (2)
-MHD_FN_MUST_CHECK_RESULT_ static enum MHD_StatusCode
+static MHD_FN_PAR_NONNULL_ (1) MHD_FN_PAR_NONNULL_ (2)
+MHD_FN_MUST_CHECK_RESULT_ enum MHD_StatusCode
daemon_start_internal (struct MHD_Daemon *restrict d,
struct DaemonOptions *restrict s)
{
@@ -2696,33 +2745,38 @@ daemon_start_internal (struct MHD_Daemon *restrict d,
if (MHD_SC_OK != res)
return res;
- // TODO: Other init
-
- res = daemon_init_threading_and_conn (d, s);
+ res = daemon_init_large_buf (d, s);
if (MHD_SC_OK == res)
{
- mhd_assert (d->dbg.net_inited);
- mhd_assert (d->dbg.threading_inited);
- mhd_assert (! mhd_D_TYPE_IS_INTERNAL_ONLY (d->threading.d_type));
- res = daemon_start_threads (d);
+ // TODO: Other init
+
+ res = daemon_init_threading_and_conn (d, s);
if (MHD_SC_OK == res)
{
- return MHD_SC_OK;
- }
+ mhd_assert (d->dbg.net_inited);
+ mhd_assert (d->dbg.threading_inited);
+ mhd_assert (! mhd_D_TYPE_IS_INTERNAL_ONLY (d->threading.d_type));
- /* Below is a clean-up path */
- daemon_deinit_threading_and_conn (d);
- }
+ res = daemon_start_threads (d);
+ if (MHD_SC_OK == res)
+ {
+ return MHD_SC_OK;
+ }
+ /* Below is a clean-up path */
+ daemon_deinit_threading_and_conn (d);
+ }
+ daemon_deinit_large_buf (d);
+ }
daemon_deinit_net (d);
mhd_assert (MHD_SC_OK != res);
return res;
}
-MHD_FN_PAR_NONNULL_ (1) MHD_FN_MUST_CHECK_RESULT_ \
- MHD_EXTERN_ enum MHD_StatusCode
+MHD_EXTERN_
+MHD_FN_PAR_NONNULL_ (1) MHD_FN_MUST_CHECK_RESULT_ enum MHD_StatusCode
MHD_daemon_start (struct MHD_Daemon *daemon)
{
struct MHD_Daemon *const d = daemon; /* a short alias */
@@ -2747,7 +2801,7 @@ MHD_daemon_start (struct MHD_Daemon *daemon)
}
-MHD_FN_PAR_NONNULL_ALL_ MHD_EXTERN_ void
+MHD_EXTERN_ MHD_FN_PAR_NONNULL_ALL_ void
MHD_daemon_destroy (struct MHD_Daemon *daemon)
{
bool not_yet_started = (mhd_DAEMON_STATE_NOT_STARTED == daemon->state);
@@ -2771,6 +2825,8 @@ MHD_daemon_destroy (struct MHD_Daemon *daemon)
daemon_deinit_threading_and_conn (daemon);
+ daemon_deinit_large_buf (daemon);
+
daemon_deinit_net (daemon);
}
daemon->state = mhd_DAEMON_STATE_STOPPED; /* Useful only for debugging */
diff --git a/src/mhd2/http_prot_ver.h b/src/mhd2/http_prot_ver.h
index 70cac271..b9a3ce29 100644
--- a/src/mhd2/http_prot_ver.h
+++ b/src/mhd2/http_prot_ver.h
@@ -55,4 +55,17 @@ enum MHD_FIXED_ENUM_MHD_SET_ MHD_HTTP_ProtocolVersion
#define MHD_HTTP_PROTOCOL_VER_DEFINED 1
#endif /* ! MHD_HTTP_PROTOCOL_VER_DEFINED */
+/**
+ * Check whether version of HTTP protocol is supported
+ */
+#define MHD_HTTP_VERSION_IS_SUPPORTED(v) \
+ ((MHD_HTTP_VERSION_1_0 <= (v)) && (MHD_HTTP_VERSION_1_1 >= (v)))
+
+/**
+ * Check whether version of HTTP protocol is valid
+ */
+#define MHD_HTTP_VERSION_IS_VALID(v) \
+ (((MHD_HTTP_VERSION_1_0 <= (v)) && (MHD_HTTP_VERSION_3 >= (v))) || \
+ (MHD_HTTP_VERSION_FUTURE == (v)))
+
#endif /* ! MHD_HTTP_PROT_VER_H */
diff --git a/src/mhd2/http_status_str.c b/src/mhd2/http_status_str.c
index d946ff03..5d5154cc 100644
--- a/src/mhd2/http_status_str.c
+++ b/src/mhd2/http_status_str.c
@@ -27,6 +27,8 @@
*/
#include "mhd_sys_options.h"
+#include "http_status_str.h"
+
#include "sys_base_types.h"
#include "mhd_public_api.h"
#include "mhd_str_macros.h"
@@ -177,7 +179,7 @@ static const struct mhd_HttpStatusesBlock statuses[] = {
MHD_EXTERN_ MHD_FN_CONST_ const struct MHD_String *
MHD_HTTP_status_code_to_string (enum MHD_HTTP_StatusCode code)
{
- struct MHD_String *res;
+ const struct MHD_String *res;
const unsigned int code_i = (unsigned int) code;
if (100 > code_i)
return NULL;
@@ -185,7 +187,7 @@ MHD_HTTP_status_code_to_string (enum MHD_HTTP_StatusCode
code)
return NULL;
if (statuses[code_i / 100].max > (code_i % 100))
return NULL;
- res = statuses[code_i / 100] + (code_i % 100);
+ res = statuses[code_i / 100].data + (code_i % 100);
if (NULL == res->cstr)
return NULL;
return res;
@@ -193,13 +195,13 @@ MHD_HTTP_status_code_to_string (enum MHD_HTTP_StatusCode
code)
MHD_INTERNAL MHD_FN_CONST_ const struct MHD_String *
-mhd_HTTP_status_code_to_string_int (enum MHD_HTTP_StatusCode code)
+mhd_HTTP_status_code_to_string_int (unsigned int code)
{
static const struct MHD_String no_status =
mhd_MSTR_INIT ("Nonstandard Status");
const struct MHD_String *res;
- res = MHD_status_code_to_string (code);
+ res = MHD_HTTP_status_code_to_string ((enum MHD_HTTP_StatusCode) code);
if (NULL != res)
return res;
diff --git a/src/mhd2/http_status_str.h b/src/mhd2/http_status_str.h
index 4906943b..3eef398e 100644
--- a/src/mhd2/http_status_str.h
+++ b/src/mhd2/http_status_str.h
@@ -39,7 +39,7 @@
* @return pointer to MHD_String, never NULL.
*/
MHD_INTERNAL const struct MHD_String *
-mhd_HTTP_status_code_to_string_int (enum MHD_HTTP_StatusCode code)
+mhd_HTTP_status_code_to_string_int (unsigned int code)
MHD_FN_CONST_;
diff --git a/src/mhd2/mhd_action.h b/src/mhd2/mhd_action.h
index a56fbf32..25289710 100644
--- a/src/mhd2/mhd_action.h
+++ b/src/mhd2/mhd_action.h
@@ -33,6 +33,7 @@
#include "mhd_str_types.h"
+
/**
* The type of the action requested by application
*/
@@ -49,29 +50,35 @@ enum mhd_ActionType
mhd_ACTION_RESPONSE
,
/**
- * Suspend requests (connection)
+ * Process clients upload by application callback
*/
- mhd_ACTION_SUSPEND
+ mhd_ACTION_UPLOAD
,
/**
- * Hard close request with no response
+ * Process clients upload by POST processor
*/
- mhd_ACTION_CLOSE
+ mhd_ACTION_POST_PROCESS
,
/**
- * Process clients upload by application callback
+ * Suspend requests (connection)
*/
- mhd_ACTION_UPLOAD
+ mhd_ACTION_SUSPEND
,
/**
- * Process clients upload by POST processor
+ * Hard close request with no response
*/
- mhd_ACTION_POST_PROCESS
+ mhd_ACTION_ABORT
};
+/**
+ * Check whether provided mhd_ActionType value is valid
+ */
+#define mhd_ACTION_IS_VALID(act) \
+ ((mhd_ACTION_RESPONSE <= (act)) && (mhd_ACTION_ABORT >= (act)))
-struct MHD_Response; /* forward declaration */
+struct MHD_Response; /* forward declaration */
+struct MHD_Request; /* forward declaration */
#ifndef MHD_UPLOADCALLBACK_DEFINED
@@ -242,6 +249,11 @@ enum mhd_UploadActionType
*/
mhd_UPLOAD_ACTION_NO_ACTION = 0
,
+ /**
+ * Continue processing the upload
+ */
+ mhd_UPLOAD_ACTION_CONTINUE
+ ,
/**
* Start replying with the response
*/
@@ -255,14 +267,17 @@ enum mhd_UploadActionType
/**
* Hard close request with no response
*/
- mhd_UPLOAD_ACTION_CLOSE
- ,
- /**
- * Continue processing the upload
- */
- mhd_UPLOAD_ACTION_CONTINUE
+ mhd_UPLOAD_ACTION_ABORT
};
+/**
+ * Check whether provided mhd_UploadActionType value is valid
+ */
+#define mhd_UPLOAD_ACTION_IS_VALID(act) \
+ ((mhd_UPLOAD_ACTION_CONTINUE <= (act)) && \
+ (mhd_UPLOAD_ACTION_ABORT >= (act)))
+
+
/**
* The data for the application action
*/
diff --git a/src/mhd2/mhd_atomic_counter.c b/src/mhd2/mhd_atomic_counter.c
index c6edc896..02fb93d7 100644
--- a/src/mhd2/mhd_atomic_counter.c
+++ b/src/mhd2/mhd_atomic_counter.c
@@ -30,44 +30,49 @@
#if defined(mhd_ATOMIC_BY_LOCKS)
+#include "mhd_assert.h"
+
MHD_INTERNAL mhd_ATOMIC_COUNTER_TYPE
mhd_atomic_counter_inc_get (struct mhd_AtomicCounter *pcnt)
{
mhd_ATOMIC_COUNTER_TYPE ret;
- mhd_mutex_lock_chk(&(pcnt->lock));
+ mhd_mutex_lock_chk (&(pcnt->lock));
ret = ++(pcnt->count);
- mhd_mutex_unlock_chk(&(pcnt->lock));
+ mhd_mutex_unlock_chk (&(pcnt->lock));
mhd_assert (0 != ret); /* check for overflow */
return ret;
}
+
MHD_INTERNAL mhd_ATOMIC_COUNTER_TYPE
mhd_atomic_counter_dec_get (struct mhd_AtomicCounter *pcnt)
{
mhd_ATOMIC_COUNTER_TYPE ret;
- mhd_mutex_lock_chk(&(pcnt->lock));
+ mhd_mutex_lock_chk (&(pcnt->lock));
ret = --(pcnt->count);
- mhd_mutex_unlock_chk(&(pcnt->lock));
+ mhd_mutex_unlock_chk (&(pcnt->lock));
mhd_assert (mhd_ATOMIC_COUNTER_MAX != ret); /* check for underflow */
return ret;
}
+
MHD_INTERNAL mhd_ATOMIC_COUNTER_TYPE
mhd_atomic_counter_get (struct mhd_AtomicCounter *pcnt)
{
mhd_ATOMIC_COUNTER_TYPE ret;
- mhd_mutex_lock_chk(&(pcnt->lock));
+ mhd_mutex_lock_chk (&(pcnt->lock));
ret = pcnt->count;
- mhd_mutex_unlock_chk(&(pcnt->lock));
+ mhd_mutex_unlock_chk (&(pcnt->lock));
return ret;
}
+
#endif /* mhd_ATOMIC_BY_LOCKS */
diff --git a/src/mhd2/mhd_atomic_counter.h b/src/mhd2/mhd_atomic_counter.h
index 2410a3e5..d42962ad 100644
--- a/src/mhd2/mhd_atomic_counter.h
+++ b/src/mhd2/mhd_atomic_counter.h
@@ -44,7 +44,7 @@
* The maximum counter value
*/
#define mhd_ATOMIC_COUNTER_MAX \
- ((mhd_ATOMIC_COUNTER_TYPE)(~((mhd_ATOMIC_COUNTER_TYPE)0)))
+ ((mhd_ATOMIC_COUNTER_TYPE) (~((mhd_ATOMIC_COUNTER_TYPE) 0)))
#ifdef MHD_USE_THREADS
@@ -109,23 +109,25 @@ struct mhd_AtomicCounter
* already.
*/
# define mhd_atomic_counter_init(pcnt,initial_value) \
- ((pcnt)->count=(initial_value), mhd_mutex_init_short(&(pcnt->lock)))
+ ((pcnt)->count = (initial_value), \
+ mhd_mutex_init_short (&((pcnt)->lock)))
/**
* Deinitialise the counter.
* @param pcnt the pointer to the counter to deinitialise
* @warning Must be called only for the counters that has been initialised.
*/
-# define mhd_atomic_counter_deinit(pcnt)
mhd_mutex_destroy_chk(&((pcnt)->lock))
+# define mhd_atomic_counter_deinit(pcnt) \
+ mhd_mutex_destroy_chk (&((pcnt)->lock))
/**
* Atomically increment the value of the counter
* @param pcnt the pointer to the counter to increment
*/
# define mhd_atomic_counter_inc(pcnt) do { \
- mhd_mutex_lock_chk(&(pcnt->lock)); \
- ++(pcnt->count); \
- mhd_mutex_unlock_chk(&(pcnt->lock)); } while (0)
+ mhd_mutex_lock_chk (&((pcnt)->lock)); \
+ ++(pcnt->count); \
+ mhd_mutex_unlock_chk (&((pcnt)->lock)); } while (0)
/**
* Atomically increment the value of the counter and return the result
@@ -162,14 +164,14 @@ mhd_atomic_counter_get (struct mhd_AtomicCounter *pcnt);
* already.
*/
# define mhd_atomic_counter_init(pcnt,initial_value) \
- ((pcnt)->count=(initial_value), (! 0))
+ ((pcnt)->count = (initial_value), (! 0))
/**
* Deinitialise the counter.
* @param pcnt the pointer to the counter to deinitialise
* @warning Must be called only for the counters that has been initialised.
*/
-# define mhd_atomic_counter_deinit(pcnt) ((void)0)
+# define mhd_atomic_counter_deinit(pcnt) ((void) 0)
/**
* Atomically increment the value of the counter
diff --git a/src/mhd2/http_status_str.h b/src/mhd2/mhd_buffer.h
similarity index 63%
copy from src/mhd2/http_status_str.h
copy to src/mhd2/mhd_buffer.h
index 4906943b..1e282b2c 100644
--- a/src/mhd2/http_status_str.h
+++ b/src/mhd2/mhd_buffer.h
@@ -19,28 +19,31 @@
*/
/**
- * @file src/mhd2/http_status_str.h
- * @brief The declaration for internal HTTP status string functions
+ * @file src/mhd2/mhd_buffer.h
+ * @brief The definition of the MHD_Buffer type
* @author Karlson2k (Evgeny Grin)
*/
-#ifndef MHD_HTTP_STATUS_STR_H
-#define MHD_HTTP_STATUS_STR_H 1
+#ifndef MHD_BUFFER_H
+#define MHD_BUFFER_H 1
#include "mhd_sys_options.h"
-
-#include "mhd_str_types.h"
+#include "sys_base_types.h"
/**
- * Get string for provided HTTP status code.
- * Substitute a replacement string for unknown codes.
- *
- * @param code the HTTP status code
- * @return pointer to MHD_String, never NULL.
+ * The buffer with size
*/
-MHD_INTERNAL const struct MHD_String *
-mhd_HTTP_status_code_to_string_int (enum MHD_HTTP_StatusCode code)
-MHD_FN_CONST_;
-
-
-#endif /* ! MHD_HTTP_STATUS_STR_H */
+struct mhd_Buffer
+{
+ /**
+ * The size of the allocated @a buf buffer
+ */
+ size_t size;
+
+ /**
+ * The pointer to the allocation
+ */
+ char *buf;
+};
+
+#endif /* ! MHD_BUFFER_H */
diff --git a/src/mhd2/mhd_connection.h b/src/mhd2/mhd_connection.h
index 19978980..45fdf92c 100644
--- a/src/mhd2/mhd_connection.h
+++ b/src/mhd2/mhd_connection.h
@@ -207,124 +207,131 @@ enum MHD_FIXED_ENUM_ MHD_CONNECTION_STATE
* Part of the request line was received.
* Wait for complete line.
*/
- MHD_CONNECTION_REQ_LINE_RECEIVING = MHD_CONNECTION_INIT + 1,
+ MHD_CONNECTION_REQ_LINE_RECEIVING,
/**
* We got the URL (and request type and version). Wait for a header line.
*
* A milestone state. No received data is processed in this state.
*/
- MHD_CONNECTION_REQ_LINE_RECEIVED = MHD_CONNECTION_REQ_LINE_RECEIVING + 1,
+ MHD_CONNECTION_REQ_LINE_RECEIVED,
/**
* Receiving request headers. Wait for the rest of the headers.
*/
- MHD_CONNECTION_REQ_HEADERS_RECEIVING = MHD_CONNECTION_REQ_LINE_RECEIVED + 1,
+ MHD_CONNECTION_REQ_HEADERS_RECEIVING,
/**
* We got the request headers. Process them.
*/
- MHD_CONNECTION_HEADERS_RECEIVED = MHD_CONNECTION_REQ_HEADERS_RECEIVING + 1,
+ MHD_CONNECTION_HEADERS_RECEIVED,
/**
* We have processed the request headers. Call application callback.
*/
- MHD_CONNECTION_HEADERS_PROCESSED = MHD_CONNECTION_HEADERS_RECEIVED + 1,
+ MHD_CONNECTION_HEADERS_PROCESSED,
/**
* We have processed the headers and need to send 100 CONTINUE.
*/
- MHD_CONNECTION_CONTINUE_SENDING = MHD_CONNECTION_HEADERS_PROCESSED + 1,
+ MHD_CONNECTION_CONTINUE_SENDING,
/**
* We have sent 100 CONTINUE (or do not need to). Read the message body.
*/
- MHD_CONNECTION_BODY_RECEIVING = MHD_CONNECTION_CONTINUE_SENDING + 1,
+ MHD_CONNECTION_BODY_RECEIVING,
/**
* We got the request body.
*
* A milestone state. No received data is processed in this state.
*/
- MHD_CONNECTION_BODY_RECEIVED = MHD_CONNECTION_BODY_RECEIVING + 1,
+ MHD_CONNECTION_BODY_RECEIVED,
/**
* We are reading the request footers.
*/
- MHD_CONNECTION_FOOTERS_RECEIVING = MHD_CONNECTION_BODY_RECEIVED + 1,
+ MHD_CONNECTION_FOOTERS_RECEIVING,
/**
* We received the entire footer.
*
- * A milestone state. No received data is processed in this state.
+ * A milestone state. No data is receiving in this state.
*/
- MHD_CONNECTION_FOOTERS_RECEIVED = MHD_CONNECTION_FOOTERS_RECEIVING + 1,
+ MHD_CONNECTION_FOOTERS_RECEIVED,
/**
* We received the entire request.
- * Wait for a response to be queued.
+ *
+ * A milestone state. No data is receiving in this state.
+ */
+ MHD_CONNECTION_FULL_REQ_RECEIVED,
+
+ /**
+ * Finished receiving request data: either complete request received or
+ * MHD is going to send reply early, without getting full request.
*/
- MHD_CONNECTION_FULL_REQ_RECEIVED = MHD_CONNECTION_FOOTERS_RECEIVED + 1,
+ MHD_CONNECTION_REQ_RECV_FINISHED,
/**
* Finished reading of the request and the response is ready.
* Switch internal logic from receiving to sending, prepare connection
* sending the reply and build the reply header.
*/
- MHD_CONNECTION_START_REPLY = MHD_CONNECTION_FULL_REQ_RECEIVED + 1,
+ MHD_CONNECTION_START_REPLY,
/**
* We have prepared the response headers in the write buffer.
* Send the response headers.
*/
- MHD_CONNECTION_HEADERS_SENDING = MHD_CONNECTION_START_REPLY + 1,
+ MHD_CONNECTION_HEADERS_SENDING,
/**
* We have sent the response headers. Get ready to send the body.
*/
- MHD_CONNECTION_HEADERS_SENT = MHD_CONNECTION_HEADERS_SENDING + 1,
+ MHD_CONNECTION_HEADERS_SENT,
/**
* We are waiting for the client to provide more
* data of a non-chunked body.
*/
- MHD_CONNECTION_NORMAL_BODY_UNREADY = MHD_CONNECTION_HEADERS_SENT + 1,
+ MHD_CONNECTION_NORMAL_BODY_UNREADY,
/**
* We are ready to send a part of a non-chunked body. Send it.
*/
- MHD_CONNECTION_NORMAL_BODY_READY = MHD_CONNECTION_NORMAL_BODY_UNREADY + 1,
+ MHD_CONNECTION_NORMAL_BODY_READY,
/**
* We are waiting for the client to provide a chunk of the body.
*/
- MHD_CONNECTION_CHUNKED_BODY_UNREADY = MHD_CONNECTION_NORMAL_BODY_READY + 1,
+ MHD_CONNECTION_CHUNKED_BODY_UNREADY,
/**
* We are ready to send a chunk.
*/
- MHD_CONNECTION_CHUNKED_BODY_READY = MHD_CONNECTION_CHUNKED_BODY_UNREADY + 1,
+ MHD_CONNECTION_CHUNKED_BODY_READY,
/**
* We have sent the chunked response body. Prepare the footers.
*/
- MHD_CONNECTION_CHUNKED_BODY_SENT = MHD_CONNECTION_CHUNKED_BODY_READY + 1,
+ MHD_CONNECTION_CHUNKED_BODY_SENT,
/**
* We have prepared the response footer. Send it.
*/
- MHD_CONNECTION_FOOTERS_SENDING = MHD_CONNECTION_CHUNKED_BODY_SENT + 1,
+ MHD_CONNECTION_FOOTERS_SENDING,
/**
* We have sent the entire reply.
* Shutdown connection or restart processing to get a new request.
*/
- MHD_CONNECTION_FULL_REPLY_SENT = MHD_CONNECTION_FOOTERS_SENDING + 1,
+ MHD_CONNECTION_FULL_REPLY_SENT,
/**
* This connection is to be closed.
*/
- MHD_CONNECTION_CLOSED = MHD_CONNECTION_FULL_REPLY_SENT + 1
+ MHD_CONNECTION_CLOSED
};
@@ -360,7 +367,6 @@ enum MHD_FIXED_ENUM_ MHD_ConnKeepAlive
*/
mhd_DLINKEDL_LINKS_DEF (MHD_Connection);
-
/**
* State kept for HTTP network connection.
*/
@@ -431,7 +437,7 @@ struct MHD_Connection
* response (which maybe shared between connections) and the IP
* address (which persists across individual requests).
*/
- struct MemoryPool *pool;
+ struct mhd_MemoryPool *pool;
/**
* We allow the main application to associate some pointer with the
@@ -551,12 +557,12 @@ struct MHD_Connection
*/
bool sk_spipe_suppress;
-//#ifndef MHD_WINSOCK_SOCKETS // TODO: conditionally use in the code
+// #ifndef MHD_WINSOCK_SOCKETS // TODO: conditionally use in the code
/**
* Tracks TCP_CORK / TCP_NOPUSH of the connection socket.
*/
enum mhd_Tristate sk_corked;
-//#endif
+// #endif
/**
* Tracks TCP_NODELAY state of the connection socket.
diff --git a/src/mhd2/mhd_daemon.h b/src/mhd2/mhd_daemon.h
index 23f2e062..317a9b9a 100644
--- a/src/mhd2/mhd_daemon.h
+++ b/src/mhd2/mhd_daemon.h
@@ -38,6 +38,7 @@
#ifdef MHD_USE_THREADS
# include "mhd_threads.h"
# include "mhd_itc_types.h"
+# include "mhd_locks.h"
#endif
#if defined(MHD_USE_SELECT) && defined(MHD_POSIX_SOCKETS)
@@ -769,6 +770,38 @@ struct mhd_DaemonConnections
struct mhd_DaemonConnectionsSettings cfg;
};
+/**
+ * Early URI callback
+ */
+struct mhd_DaemonRequestUriCB
+{
+ /**
+ * The callback
+ */
+ MHD_EarlyUriLogCallback cb;
+ /**
+ * The callback closure
+ */
+ void *cls;
+};
+
+/**
+ * Shared large buffer data
+ */
+struct mhd_DeamonLargeBuffer
+{
+ /**
+ * The amount of memory left allowed to be allocated for the large buffer
+ */
+ size_t space_left;
+
+#ifdef MHD_USE_THREADS
+ /**
+ * The mutex to change or check the @a space_left value
+ */
+ mhd_mutex lock;
+#endif
+};
/**
* Settings for requests processing
@@ -790,6 +823,16 @@ struct mhd_DaemonRequestProcessingSettings
* Protocol strictness enforced by MHD on clients.
*/
enum MHD_ProtocolStrictLevel strictnees;
+
+ /**
+ * Early URI callback
+ */
+ struct mhd_DaemonRequestUriCB uri_cb; // TODO: set from settings
+
+ /**
+ * Shared large buffer data
+ */
+ struct mhd_DeamonLargeBuffer large_buf; // TODO: set from settings
};
diff --git a/src/mhd2/mhd_mempool.c b/src/mhd2/mhd_mempool.c
index 85dc36c3..97d1f07d 100644
--- a/src/mhd2/mhd_mempool.c
+++ b/src/mhd2/mhd_mempool.c
@@ -214,7 +214,7 @@ static size_t MHD_sys_page_size_ = (size_t)
* Initialise values for memory pools
*/
void
-MHD_init_mem_pools_ (void)
+mhd_init_mem_pools (void)
{
#ifdef MHD_SC_PAGESIZE
long result;
@@ -238,7 +238,7 @@ MHD_init_mem_pools_ (void)
* Handle for a memory pool. Pools are not reentrant and must not be
* used by multiple threads.
*/
-struct MemoryPool
+struct mhd_MemoryPool
{
/**
@@ -274,15 +274,15 @@ struct MemoryPool
* @param max maximum size of the pool
* @return NULL on error
*/
-struct MemoryPool *
-MHD_pool_create (size_t max)
+MHD_INTERNAL struct mhd_MemoryPool *
+mdh_pool_create (size_t max)
{
- struct MemoryPool *pool;
+ struct mhd_MemoryPool *pool;
size_t alloc_size;
mhd_assert (max > 0);
alloc_size = 0;
- pool = malloc (sizeof (struct MemoryPool));
+ pool = malloc (sizeof (struct mhd_MemoryPool));
if (NULL == pool)
return NULL;
#if defined(MAP_ANONYMOUS) || defined(_WIN32)
@@ -345,8 +345,8 @@ MHD_pool_create (size_t max)
*
* @param pool memory pool to destroy
*/
-void
-MHD_pool_destroy (struct MemoryPool *pool)
+MHD_INTERNAL void
+mhd_pool_destroy (struct mhd_MemoryPool *restrict pool)
{
if (NULL == pool)
return;
@@ -378,8 +378,8 @@ MHD_pool_destroy (struct MemoryPool *pool)
* @param pool pool to check
* @return number of bytes still available in @a pool
*/
-size_t
-MHD_pool_get_free (struct MemoryPool *pool)
+MHD_INTERNAL size_t
+mhd_pool_get_free (struct mhd_MemoryPool *restrict pool)
{
mhd_assert (pool->end >= pool->pos);
mhd_assert (pool->size >= pool->end - pool->pos);
@@ -403,8 +403,8 @@ MHD_pool_get_free (struct MemoryPool *pool)
* @return NULL if the pool cannot support size more
* bytes
*/
-void *
-MHD_pool_allocate (struct MemoryPool *pool,
+MHD_INTERNAL void *
+mhd_pool_allocate (struct mhd_MemoryPool *restrict pool,
size_t size,
bool from_end)
{
@@ -444,9 +444,9 @@ MHD_pool_allocate (struct MemoryPool *pool,
* @return true if block can be resized in-place in the optimal way,
* false otherwise
*/
-bool
-MHD_pool_is_resizable_inplace (struct MemoryPool *pool,
- void *block,
+MHD_INTERNAL bool
+mhd_pool_is_resizable_inplace (struct mhd_MemoryPool *restrict pool,
+ void *restrict block,
size_t block_size)
{
mhd_assert (pool->end >= pool->pos);
@@ -485,10 +485,10 @@ MHD_pool_is_resizable_inplace (struct MemoryPool *pool,
* with amount of space needed to be freed in rellocatable area or
* set to SIZE_MAX if requested size is too large for the pool.
*/
-void *
-MHD_pool_try_alloc (struct MemoryPool *pool,
+MHD_INTERNAL void *
+mhd_pool_try_alloc (struct mhd_MemoryPool *restrict pool,
size_t size,
- size_t *required_bytes)
+ size_t *restrict required_bytes)
{
void *ret;
size_t asize;
@@ -537,9 +537,9 @@ MHD_pool_try_alloc (struct MemoryPool *pool,
* NULL if the pool cannot support @a new_size
* bytes (old continues to be valid for @a old_size)
*/
-void *
-MHD_pool_reallocate (struct MemoryPool *pool,
- void *old,
+MHD_INTERNAL void *
+mhd_pool_reallocate (struct mhd_MemoryPool *pool,
+ void *restrict old,
size_t old_size,
size_t new_size)
{
@@ -629,9 +629,9 @@ MHD_pool_reallocate (struct MemoryPool *pool,
* @param block the allocated block, the NULL is tolerated
* @param block_size the size of the allocated block
*/
-void
-MHD_pool_deallocate (struct MemoryPool *pool,
- void *block,
+MHD_INTERNAL void
+mhd_pool_deallocate (struct mhd_MemoryPool *restrict pool,
+ void *restrict block,
size_t block_size)
{
mhd_assert (pool->end >= pool->pos);
@@ -733,9 +733,9 @@ MHD_pool_deallocate (struct MemoryPool *pool,
* (should be larger or equal to @a copy_bytes)
* @return addr new address of @a keep (if it had to change)
*/
-void *
-MHD_pool_reset (struct MemoryPool *pool,
- void *keep,
+MHD_INTERNAL void *
+mhd_pool_reset (struct mhd_MemoryPool *restrict pool,
+ void *restrict keep,
size_t copy_bytes,
size_t new_size)
{
diff --git a/src/mhd2/mhd_mempool.h b/src/mhd2/mhd_mempool.h
index 73ec1030..bc7dac46 100644
--- a/src/mhd2/mhd_mempool.h
+++ b/src/mhd2/mhd_mempool.h
@@ -25,8 +25,6 @@
* request
* @author Christian Grothoff
* @author Karlson2k (Evgeny Grin)
- *
- * TODO: Update code style
*/
#ifndef MHD_MEMPOOL_H
@@ -41,13 +39,13 @@
* Pools are not reentrant and must not be used
* by multiple threads.
*/
-struct MemoryPool;
+struct mhd_MemoryPool;
/**
* Initialize values for memory pools
*/
void
-MHD_init_mem_pools_ (void);
+mhd_init_mem_pools (void);
/**
@@ -56,8 +54,8 @@ MHD_init_mem_pools_ (void);
* @param max maximum size of the pool
* @return NULL on error
*/
-struct MemoryPool *
-MHD_pool_create (size_t max);
+MHD_INTERNAL struct mhd_MemoryPool *
+mdh_pool_create (size_t max);
/**
@@ -65,8 +63,8 @@ MHD_pool_create (size_t max);
*
* @param pool memory pool to destroy
*/
-void
-MHD_pool_destroy (struct MemoryPool *pool);
+MHD_INTERNAL void
+mhd_pool_destroy (struct mhd_MemoryPool *restrict pool);
/**
@@ -80,8 +78,8 @@ MHD_pool_destroy (struct MemoryPool *pool);
* @return NULL if the pool cannot support size more
* bytes
*/
-void *
-MHD_pool_allocate (struct MemoryPool *pool,
+MHD_INTERNAL void *
+mhd_pool_allocate (struct mhd_MemoryPool *restrict pool,
size_t size,
bool from_end);
@@ -95,9 +93,9 @@ MHD_pool_allocate (struct MemoryPool *pool,
* @return true if block can be resized in-place in the optimal way,
* false otherwise
*/
-bool
-MHD_pool_is_resizable_inplace (struct MemoryPool *pool,
- void *block,
+MHD_INTERNAL bool
+mhd_pool_is_resizable_inplace (struct mhd_MemoryPool *restrict pool,
+ void *restrict block,
size_t block_size);
/**
@@ -119,10 +117,10 @@ MHD_pool_is_resizable_inplace (struct MemoryPool *pool,
* with amount of space needed to be freed in rellocatable area or
* set to SIZE_MAX if requested size is too large for the pool.
*/
-void *
-MHD_pool_try_alloc (struct MemoryPool *pool,
+MHD_INTERNAL void *
+mhd_pool_try_alloc (struct mhd_MemoryPool *restrict pool,
size_t size,
- size_t *required_bytes);
+ size_t *restrict required_bytes);
/**
@@ -142,9 +140,9 @@ MHD_pool_try_alloc (struct MemoryPool *pool,
* NULL if the pool cannot support @a new_size
* bytes (old continues to be valid for @a old_size)
*/
-void *
-MHD_pool_reallocate (struct MemoryPool *pool,
- void *old,
+MHD_INTERNAL void *
+mhd_pool_reallocate (struct mhd_MemoryPool *restrict pool,
+ void *restrict old,
size_t old_size,
size_t new_size);
@@ -155,8 +153,8 @@ MHD_pool_reallocate (struct MemoryPool *pool,
* @param pool pool to check
* @return number of bytes still available in @a pool
*/
-size_t
-MHD_pool_get_free (struct MemoryPool *pool);
+MHD_INTERNAL size_t
+mhd_pool_get_free (struct mhd_MemoryPool *restrict pool);
/**
@@ -171,9 +169,9 @@ MHD_pool_get_free (struct MemoryPool *pool);
* @param block the allocated block, the NULL is tolerated
* @param block_size the size of the allocated block
*/
-void
-MHD_pool_deallocate (struct MemoryPool *pool,
- void *block,
+MHD_INTERNAL void
+mhd_pool_deallocate (struct mhd_MemoryPool *restrict pool,
+ void *restrict block,
size_t block_size);
@@ -190,9 +188,9 @@ MHD_pool_deallocate (struct MemoryPool *pool,
* (should be larger or equal to @a copy_bytes)
* @return addr new address of @a keep (if it had to change)
*/
-void *
-MHD_pool_reset (struct MemoryPool *pool,
- void *keep,
+MHD_INTERNAL void *
+mhd_pool_reset (struct mhd_MemoryPool *restrict pool,
+ void *restrict keep,
size_t copy_bytes,
size_t new_size);
diff --git a/src/mhd2/mhd_recv.c b/src/mhd2/mhd_recv.c
index b909d510..979e4b53 100644
--- a/src/mhd2/mhd_recv.c
+++ b/src/mhd2/mhd_recv.c
@@ -42,7 +42,7 @@ static MHD_FN_PAR_NONNULL_ALL_
MHD_FN_PAR_OUT_SIZE_ (3,2) MHD_FN_PAR_OUT_ (4) enum mhd_SocketError
mhd_plain_recv (struct MHD_Connection *restrict c,
size_t buf_size,
- char buf[MHD_FN_PAR_DYN_ARR_SIZE_(buf_size)],
+ char buf[MHD_FN_PAR_DYN_ARR_SIZE_ (buf_size)],
size_t *restrict received)
{
/* Plain TCP connection */
@@ -59,25 +59,28 @@ mhd_plain_recv (struct MHD_Connection *restrict c,
if (buf_size > (size_t) res)
c->sk_ready = (enum mhd_SocketNetState) /* Clear 'recv-ready' */
(((unsigned int) c->sk_ready)
- & (~mhd_SOCKET_NET_STATE_RECV_READY));
+ & (~(enum mhd_SocketNetState)
+ mhd_SOCKET_NET_STATE_RECV_READY));
return mhd_SOCKET_ERR_NO_ERROR; /* Success exit point */
}
- err = mhd_socket_error_get_from_sys_err(mhd_SCKT_GET_LERR ());
+ err = mhd_socket_error_get_from_sys_err (mhd_SCKT_GET_LERR ());
if (mhd_SOCKET_ERR_AGAIN == err)
c->sk_ready = (enum mhd_SocketNetState) /* Clear 'recv-ready' */
(((unsigned int) c->sk_ready)
- & (~mhd_SOCKET_NET_STATE_RECV_READY));
+ & (~(enum mhd_SocketNetState)
+ mhd_SOCKET_NET_STATE_RECV_READY));
return err; /* Failure exit point */
}
+
MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_
MHD_FN_PAR_OUT_SIZE_ (3,2) MHD_FN_PAR_OUT_ (4) enum mhd_SocketError
mhd_recv (struct MHD_Connection *restrict c,
size_t buf_size,
- char buf[MHD_FN_PAR_DYN_ARR_SIZE_(buf_size)],
+ char buf[MHD_FN_PAR_DYN_ARR_SIZE_ (buf_size)],
size_t *restrict received)
{
mhd_assert (MHD_INVALID_SOCKET != c->socket_fd);
@@ -85,5 +88,5 @@ mhd_recv (struct MHD_Connection *restrict c,
// TODO: implement TLS support
- return mhd_plain_recv(c, buf_size, buf, received);
+ return mhd_plain_recv (c, buf_size, buf, received);
}
diff --git a/src/mhd2/mhd_reply.h b/src/mhd2/mhd_reply.h
index 3caf6384..e92a5530 100644
--- a/src/mhd2/mhd_reply.h
+++ b/src/mhd2/mhd_reply.h
@@ -99,12 +99,6 @@ struct MHD_Reply
*/
struct MHD_Response *response;
- /**
- * HTTP response code. Only valid if response object
- * is already set.
- */
- unsigned int responseCode;
-
/**
* The "ICY" response.
* Reply begins with the SHOUTcast "ICY" line instead of "HTTP".
diff --git a/src/mhd2/mhd_request.h b/src/mhd2/mhd_request.h
index a9e0f341..445e32b2 100644
--- a/src/mhd2/mhd_request.h
+++ b/src/mhd2/mhd_request.h
@@ -39,6 +39,7 @@
#include "http_prot_ver.h"
#include "http_method.h"
#include "mhd_action.h"
+#include "mhd_buffer.h"
/**
@@ -199,6 +200,36 @@ struct mhd_RequestField
mhd_DLINKEDL_LIST_DEF (mhd_RequestField);
+
+/**
+ * The request content data
+ */
+struct mhd_ReqContentData
+{
+ /**
+ * The pointer to the large buffer
+ * Must be NULL if large buffer is not allocated.
+ */
+ struct mhd_Buffer lbuf;
+
+ /**
+ * The total size of the request content.
+ * #MHD_SIZE_UNKNOWN if the size is not yet known (chunked upload).
+ */
+ uint_fast64_t cntn_size;
+
+ /**
+ * The size of the received content
+ */
+ uint_fast64_t recv_size;
+
+ /**
+ * The size of the processed content
+ */
+ uint_fast64_t proc_size;
+};
+
+
/**
* Request-specific values.
*
@@ -216,6 +247,11 @@ struct MHD_Request
*/
struct mhd_ApplicationAction app_act;
+ /**
+ * The request content data
+ */
+ struct mhd_ReqContentData cntn;
+
/**
* HTTP version string (i.e. http/1.1). Allocated
* in pool.
@@ -271,12 +307,6 @@ struct MHD_Request
*/
union MHD_StartOrSize field_lines;
- /**
- * How many more bytes of the body do we expect
- * to read? #MHD_SIZE_UNKNOWN for unknown.
- */
- uint_fast64_t remaining_upload_size;
-
/**
* Are we receiving with chunked encoding?
* This will be set to #MHD_YES after we parse the headers and
diff --git a/src/mhd2/mhd_response.h b/src/mhd2/mhd_response.h
index 0dd8c9b8..b89caf90 100644
--- a/src/mhd2/mhd_response.h
+++ b/src/mhd2/mhd_response.h
@@ -263,7 +263,7 @@ mhd_DLINKEDL_LIST_DEF (mhd_ResponseHeader);
struct MHD_Response
{
/**
- * The response status code
+ * The response HTTP status code
*/
enum MHD_HTTP_StatusCode sc;
diff --git a/src/mhd2/mhd_send.c b/src/mhd2/mhd_send.c
index ce1c5591..5283960f 100644
--- a/src/mhd2/mhd_send.c
+++ b/src/mhd2/mhd_send.c
@@ -37,13 +37,16 @@
#include "mhd_sys_options.h"
+#include <string.h>
+
#include "mhd_send.h"
#include "sys_sockets_headers.h"
#include "sys_ip_headers.h"
#include "mhd_sockets_macros.h"
#include "daemon_logger.h"
-#include <string.h>
+#include "mhd_connection.h"
+#include "mhd_response.h"
#include "mhd_iovec.h"
#ifdef HAVE_LINUX_SENDFILE
@@ -74,8 +77,8 @@
#ifdef mhd_USE_VECT_SEND
# if (! defined(HAVE_SENDMSG) || ! defined(MSG_NOSIGNAL)) && \
- defined(mhd_SEND_SPIPE_SUPPRESS_POSSIBLE) && \
- defined(mhd_SEND_SPIPE_SUPPRESS_NEEDED)
+ defined(mhd_SEND_SPIPE_SUPPRESS_POSSIBLE) && \
+ defined(mhd_SEND_SPIPE_SUPPRESS_NEEDED)
# define mhd_VECT_SEND_NEEDS_SPIPE_SUPPRESSED 1
# endif /* (!HAVE_SENDMSG || !MSG_NOSIGNAL) &&
mhd_SEND_SPIPE_SUPPRESS_POSSIBLE && mhd_SEND_SPIPE_SUPPRESS_NEEDED
*/
@@ -124,13 +127,13 @@ freebsd_sendfile_init_ (void)
freebsd_sendfile_flags_thd_p_c_ =
SF_FLAGS ((uint_fast16_t) \
((mhd_SENFILE_CHUNK_SIZE_FOR_THR_P_C + sys_page_size - 1) \
- / sys_page_size) & 0xFFFFU, SF_NODISKIO);
+ / sys_page_size) & 0xFFFFU, SF_NODISKIO);
}
}
#else /* ! HAVE_FREEBSD_SENDFILE || ! SF_FLAGS */
-# define freebsd_sendfile_init_() (void)0
+# define freebsd_sendfile_init_() (void) 0
#endif /* HAVE_FREEBSD_SENDFILE */
@@ -162,7 +165,7 @@ iov_max_init_ (void)
*/
# define mhd_IOV_MAX mhd_iov_max_
#else /* ! HAVE_SYSCONF || ! _SC_IOV_MAX */
-# define iov_max_init_() (void)0
+# define iov_max_init_() (void) 0
# if defined(IOV_MAX)
/**
@@ -197,7 +200,7 @@ mhd_connection_set_nodelay_state (struct MHD_Connection
*connection,
static const mhd_SCKT_OPT_BOOL on_val = 1;
int err_code;
- if (mhd_T_IS_YES(connection->is_nonip))
+ if (mhd_T_IS_YES (connection->is_nonip))
return false;
if (0 == setsockopt (connection->socket_fd,
@@ -211,10 +214,10 @@ mhd_connection_set_nodelay_state (struct MHD_Connection
*connection,
}
err_code = mhd_SCKT_GET_LERR ();
- if ((mhd_T_IS_NOT_YES(connection->is_nonip)) &&
- (mhd_SCKT_ERR_IS_EINVAL (err_code) ||
- mhd_SCKT_ERR_IS_NOPROTOOPT (err_code) ||
- mhd_SCKT_ERR_IS_NOTSOCK (err_code)))
+ if ((mhd_T_IS_NOT_YES (connection->is_nonip)) &&
+ (mhd_SCKT_ERR_IS_EINVAL (err_code) ||
+ mhd_SCKT_ERR_IS_NOPROTOOPT (err_code) ||
+ mhd_SCKT_ERR_IS_NOTSOCK (err_code)))
{
connection->is_nonip = mhd_T_YES;
}
@@ -240,7 +243,7 @@ mhd_connection_set_cork_state (struct MHD_Connection
*connection,
static const mhd_SCKT_OPT_BOOL on_val = 1;
int err_code;
- if (mhd_T_IS_YES(connection->is_nonip))
+ if (mhd_T_IS_YES (connection->is_nonip))
return false;
if (0 == setsockopt (connection->socket_fd,
@@ -254,10 +257,10 @@ mhd_connection_set_cork_state (struct MHD_Connection
*connection,
}
err_code = mhd_SCKT_GET_LERR ();
- if ((mhd_T_IS_NOT_YES(connection->is_nonip)) &&
- (mhd_SCKT_ERR_IS_EINVAL (err_code) ||
- mhd_SCKT_ERR_IS_NOPROTOOPT (err_code) ||
- mhd_SCKT_ERR_IS_NOTSOCK (err_code)))
+ if ((mhd_T_IS_NOT_YES (connection->is_nonip)) &&
+ (mhd_SCKT_ERR_IS_EINVAL (err_code) ||
+ mhd_SCKT_ERR_IS_NOPROTOOPT (err_code) ||
+ mhd_SCKT_ERR_IS_NOTSOCK (err_code)))
{
connection->is_nonip = mhd_T_YES;
}
@@ -299,7 +302,7 @@ pre_send_setopt (struct MHD_Connection *connection,
* Final piece is indicated by push_data == true. */
const bool buffer_data = (! push_data);
- if (mhd_T_IS_YES(connection->is_nonip))
+ if (mhd_T_IS_YES (connection->is_nonip))
return;
// TODO: support inheriting of TCP_NODELAY and TCP_NOPUSH
@@ -321,7 +324,7 @@ pre_send_setopt (struct MHD_Connection *connection,
#endif /* ! mhd_USE_MSG_MORE */
#ifdef mhd_TCP_CORK_NOPUSH
- if (mhd_T_IS_YES(connection->sk_corked))
+ if (mhd_T_IS_YES (connection->sk_corked))
return; /* The connection was already corked. */
/* Prefer 'cork' over 'no delay' as the 'cork' buffers better, regardless
@@ -332,7 +335,7 @@ pre_send_setopt (struct MHD_Connection *connection,
/* Failed to cork the connection.
* Really unlikely to happen on TCP connections. */
#endif /* mhd_TCP_CORK_NOPUSH */
- if (mhd_T_IS_NO(connection->sk_nodelay))
+ if (mhd_T_IS_NO (connection->sk_nodelay))
return; /* TCP_NODELAY was not set for the socket.
* Nagle's algorithm will buffer some data. */
@@ -396,17 +399,17 @@ pre_send_setopt (struct MHD_Connection *connection,
/* This is typical modern FreeBSD and OpenBSD behaviour. */
# endif /* ! mhd_NODELAY_SET_PUSH_DATA */
- if (mhd_T_IS_YES(connection->sk_corked))
+ if (mhd_T_IS_YES (connection->sk_corked))
return; /* Socket is corked. Data can be pushed by resetting of
* TCP_CORK / TCP_NOPUSH after send() */
- else if (mhd_T_IS_NO(connection->sk_corked))
+ else if (mhd_T_IS_NO (connection->sk_corked))
{
/* The socket is not corked. */
- if (mhd_T_IS_YES(connection->sk_nodelay))
+ if (mhd_T_IS_YES (connection->sk_nodelay))
return; /* TCP_NODELAY was already set,
* data will be pushed automatically by the next send() */
# ifdef mhd_NODELAY_SET_PUSH_DATA
- else if (mhd_T_IS_MAYBE(connection->sk_nodelay))
+ else if (mhd_T_IS_MAYBE (connection->sk_nodelay))
{
/* Setting TCP_NODELAY may push data NOW.
* Cork socket here and uncork after send(). */
@@ -469,7 +472,7 @@ pre_send_setopt (struct MHD_Connection *connection,
* TCP_CORK / TCP_NOPUSH after send() */
/* The socket cannot be corked.
* Really unlikely to happen on TCP connections */
- if (mhd_T_IS_YES(connection->sk_nodelay))
+ if (mhd_T_IS_YES (connection->sk_nodelay))
return; /* TCP_NODELAY was already set,
* data will be pushed by the next send() */
@@ -498,11 +501,11 @@ pre_send_setopt (struct MHD_Connection *connection,
/* This is old FreeBSD and Darwin behaviour. */
/* Uncork socket if socket wasn't uncorked. */
- if (mhd_T_IS_NOT_NO(connection->sk_corked))
+ if (mhd_T_IS_NOT_NO (connection->sk_corked))
mhd_connection_set_cork_state (connection, false);
/* Set TCP_NODELAY if it wasn't set. */
- if (mhd_T_IS_NOT_YES(connection->sk_nodelay))
+ if (mhd_T_IS_NOT_YES (connection->sk_nodelay))
mhd_connection_set_nodelay_state (connection, true);
return;
@@ -524,7 +527,7 @@ pre_send_setopt (struct MHD_Connection *connection,
/* Buffering of data is controlled only by
* Nagel's algorithm. */
/* Set TCP_NODELAY if it wasn't set. */
- if (mhd_T_IS_NOT_YES(connection->sk_nodelay))
+ if (mhd_T_IS_NOT_YES (connection->sk_nodelay))
mhd_connection_set_nodelay_state (connection, true);
#endif /* ! mhd_TCP_CORK_NOPUSH */
}
@@ -545,13 +548,12 @@ pre_send_setopt (struct MHD_Connection *connection,
static bool
zero_send (struct MHD_Connection *connection)
{
- static const int dummy;
+ static const int dummy = 0;
- if (mhd_T_IS_YES(connection->is_nonip))
+ if (mhd_T_IS_YES (connection->is_nonip))
return false;
- mhd_assert (mhd_T_IS_NO(connection->sk_corked));
- mhd_assert (mhd_T_IS_YES(connection->sk_nodelay));
- dummy = 0; /* Mute compiler and analyzer warnings */
+ mhd_assert (mhd_T_IS_NO (connection->sk_corked));
+ mhd_assert (mhd_T_IS_YES (connection->sk_nodelay));
if (0 == mhd_sys_send (connection->socket_fd, &dummy, 0))
return true;
MHD_LOG_MSG (connection->daemon, MHD_SC_SOCKET_ZERO_SEND_FAILED, \
@@ -581,7 +583,7 @@ post_send_setopt (struct MHD_Connection *connection,
* Final piece is indicated by push_data == true. */
const bool buffer_data = (! push_data);
- if (mhd_T_IS_YES(connection->is_nonip))
+ if (mhd_T_IS_YES (connection->is_nonip))
return;
if (buffer_data)
return; /* Nothing to do after the send(). */
@@ -592,8 +594,8 @@ post_send_setopt (struct MHD_Connection *connection,
/* Need to push data. */
#ifdef mhd_TCP_CORK_NOPUSH
- if (mhd_T_IS_YES(connection->sk_nodelay) && \
- mhd_T_IS_NO(connection->sk_corked))
+ if (mhd_T_IS_YES (connection->sk_nodelay) && \
+ mhd_T_IS_NO (connection->sk_corked))
return; /* Data has been already pushed by last send(). */
# ifdef mhd_CORK_RESET_PUSH_DATA_ALWAYS
@@ -620,7 +622,7 @@ post_send_setopt (struct MHD_Connection *connection,
* resetting of TCP_CORK so next final send without MSG_MORE will push
* data to the network (without additional sys-call to push data). */
- if (mhd_T_IS_NOT_YES(connection->sk_nodelay) ||
+ if (mhd_T_IS_NOT_YES (connection->sk_nodelay) ||
(! plain_send_next))
{
if (mhd_connection_set_nodelay_state (connection, true))
@@ -672,9 +674,9 @@ post_send_setopt (struct MHD_Connection *connection,
# else /* ! mhd_CORK_RESET_PUSH_DATA_ALWAYS */
/* This is old FreeBSD or Darwin kernel. */
- if (mhd_T_IS_NO(connection->sk_corked))
+ if (mhd_T_IS_NO (connection->sk_corked))
{
- mhd_assert(mhd_T_IS_NOT_YES(connection->sk_nodelay));
+ mhd_assert (mhd_T_IS_NOT_YES (connection->sk_nodelay));
/* Unlikely to reach this code.
* TCP_NODELAY should be turned on before send(). */
@@ -700,14 +702,14 @@ post_send_setopt (struct MHD_Connection *connection,
{
#ifdef mhd_CORK_RESET_PUSH_DATA
/* Modern FreeBSD or OpenBSD kernel */
- if (mhd_T_IS_YES(old_cork_state))
+ if (mhd_T_IS_YES (old_cork_state))
return; /* Data has been pushed by uncorking the socket. */
#endif /* mhd_CORK_RESET_PUSH_DATA */
/* Unlikely to reach this code.
* The data should be pushed by uncorking (FreeBSD) or
* the socket should be uncorked before send(). */
- if (mhd_T_IS_YES(connection->sk_nodelay) ||
+ if (mhd_T_IS_YES (connection->sk_nodelay) ||
(mhd_connection_set_nodelay_state (connection, true)))
{
/* TCP_NODELAY is turned ON on uncorked socket.
@@ -722,8 +724,8 @@ post_send_setopt (struct MHD_Connection *connection,
#else /* ! mhd_TCP_CORK_NOPUSH */
/* Corking is not supported. Buffering is controlled
* by TCP_NODELAY only. */
- mhd_assert (mhd_T_IS_NOT_YES(connection->sk_corked));
- if (mhd_T_IS_YES(connection->sk_nodelay))
+ mhd_assert (mhd_T_IS_NOT_YES (connection->sk_corked));
+ if (mhd_T_IS_YES (connection->sk_nodelay))
return; /* Data was already pushed by send(). */
/* Unlikely to reach this code.
@@ -746,11 +748,13 @@ post_send_setopt (struct MHD_Connection *connection,
return;
}
-static MHD_FN_PAR_NONNULL_ALL_ MHD_FN_PAR_IN_SIZE_ (3,2)
+
+static MHD_FN_PAR_NONNULL_ALL_
+MHD_FN_PAR_IN_SIZE_ (3,2)
MHD_FN_PAR_OUT_ (5) enum mhd_SocketError
mhd_plain_send (struct MHD_Connection *restrict c,
size_t buf_size,
- const char buf[MHD_FN_PAR_DYN_ARR_SIZE_(buf_size)],
+ const char buf[MHD_FN_PAR_DYN_ARR_SIZE_ (buf_size)],
bool push_data,
size_t *restrict sent)
{
@@ -766,12 +770,12 @@ mhd_plain_send (struct MHD_Connection *restrict c,
pre_send_setopt (c, true, push_data);
#ifdef mhd_USE_MSG_MORE
- res = mhd_sys_send4 (s,
- buffer,
- buffer_size,
- push_data ? 0 : MSG_MORE);
+ res = mhd_sys_send4 (c->socket_fd,
+ buffer,
+ buffer_size,
+ push_data ? 0 : MSG_MORE);
#else
- res = mhd_sys_send4 (c,
+ res = mhd_sys_send4 (c->socket_fd,
buf,
buf_size,
0);
@@ -781,12 +785,13 @@ mhd_plain_send (struct MHD_Connection *restrict c,
{
enum mhd_SocketError err;
- err = mhd_socket_error_get_from_sys_err(mhd_SCKT_GET_LERR ());
+ err = mhd_socket_error_get_from_sys_err (mhd_SCKT_GET_LERR ());
if (mhd_SOCKET_ERR_AGAIN == err)
c->sk_ready = (enum mhd_SocketNetState) /* Clear 'send-ready' */
(((unsigned int) c->sk_ready)
- & (~mhd_SOCKET_NET_STATE_SEND_READY));
+ & (~(enum mhd_SocketNetState)
+ mhd_SOCKET_NET_STATE_SEND_READY));
return err;
}
@@ -797,31 +802,32 @@ mhd_plain_send (struct MHD_Connection *restrict c,
if (! full_buf_sent)
c->sk_ready = (enum mhd_SocketNetState) /* Clear 'send-ready' */
(((unsigned int) c->sk_ready)
- & (~mhd_SOCKET_NET_STATE_SEND_READY));
+ & (~(enum mhd_SocketNetState)
+ mhd_SOCKET_NET_STATE_SEND_READY));
/* If there is a need to push the data from network buffers
* call post_send_setopt(). */
/* It's unknown whether sendfile() (or other send function without
* MSG_MORE support) will be used for the next reply so assume
* that next sending will be the same, like this call. */
- if ( push_data && full_buf_sent)
+ if (push_data && full_buf_sent)
post_send_setopt (c, false, push_data);
return mhd_SOCKET_ERR_NO_ERROR;
}
-MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_ MHD_FN_PAR_IN_SIZE_ (3,2)
+MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_
+MHD_FN_PAR_IN_SIZE_ (3,2)
MHD_FN_PAR_OUT_ (5) enum mhd_SocketError
mhd_send_data (struct MHD_Connection *restrict connection,
size_t buf_size,
- const char buf[MHD_FN_PAR_DYN_ARR_SIZE_(buf_size)],
+ const char buf[MHD_FN_PAR_DYN_ARR_SIZE_ (buf_size)],
bool push_data,
size_t *restrict sent)
{
MHD_Socket s = connection->socket_fd;
- enum mhd_SocketError ret;
const bool tls_conn = false; // TODO: TLS support
mhd_assert (MHD_INVALID_SOCKET != s);
@@ -838,10 +844,12 @@ mhd_send_data (struct MHD_Connection *restrict connection,
return mhd_SOCKET_ERR_OTHER;
}
- return mhd_plain_send(connection, buf_size, buf, push_data, sent);
+ return mhd_plain_send (connection, buf_size, buf, push_data, sent);
}
-MHD_INTERNAL MHD_FN_PAR_NONNULL_(1) MHD_FN_PAR_NONNULL_(3)
+
+MHD_INTERNAL
+MHD_FN_PAR_NONNULL_ (1) MHD_FN_PAR_NONNULL_ (3)
MHD_FN_PAR_IN_SIZE_ (3,2) MHD_FN_PAR_IN_SIZE_ (6,5) enum mhd_SocketError
mhd_send_hdr_and_body (struct MHD_Connection *restrict connection,
size_t header_size,
@@ -920,17 +928,16 @@ mhd_send_hdr_and_body (struct MHD_Connection *restrict
connection,
#else /* mhd_USE_VECT_SEND */
no_vec = (no_vec || (0 == body_size));
no_vec = (no_vec || ((sizeof(mhd_iov_elmn_size) <= sizeof(size_t)) &&
- (((size_t) mhd_IOV_ELMN_MAX_SIZE) < header_size)));
+ (((size_t) mhd_IOV_ELMN_MAX_SIZE) < header_size)));
#endif /* mhd_USE_VECT_SEND */
-
if (no_vec)
{
enum mhd_SocketError ret;
ret = mhd_send_data (connection,
- header,
header_size,
+ header,
push_hdr,
sent);
@@ -947,14 +954,14 @@ mhd_send_hdr_and_body (struct MHD_Connection *restrict
connection,
* the next round. */
ret = mhd_send_data (connection,
- body,
body_size,
+ body,
push_body,
&sent_b);
if (mhd_SOCKET_ERR_NO_ERROR == ret)
*sent += sent_b;
- else if (mhd_SOCKET_ERR_IS_HARD(ret))
+ else if (mhd_SOCKET_ERR_IS_HARD (ret))
return ret; /* Unrecoverable error */
return mhd_SOCKET_ERR_NO_ERROR; /* The header has been sent successfully
*/
@@ -971,8 +978,8 @@ mhd_send_hdr_and_body (struct MHD_Connection *restrict
connection,
push_body = complete_response;
}
if (((mhd_iov_ret_type) (header_size + body_size)) < 0 ||
- ((size_t)(mhd_iov_ret_type) (header_size + body_size)) !=
- (header_size + body_size))
+ ((size_t) (mhd_iov_ret_type) (header_size + body_size)) !=
+ (header_size + body_size))
{
/* Send sys-call total amount limit */
body_size = mhd_IOV_RET_MAX_SIZE - header_size;
@@ -1004,8 +1011,8 @@ mhd_send_hdr_and_body (struct MHD_Connection *restrict
connection,
msg.msg_controllen = 0;
msg.msg_flags = 0;
- res = sendmsg (s, &msg, mhd_MSG_NOSIGNAL |
- ((push_hdr || push_body) ? 0 : mhd_MSG_MORE));
+ res = sendmsg (s, &msg, mhd_MSG_NOSIGNAL
+ | ((push_hdr || push_body) ? 0 : mhd_MSG_MORE));
#elif defined(HAVE_WRITEV)
res = writev (s, vector, 2);
#endif /* HAVE_WRITEV */
@@ -1038,19 +1045,21 @@ mhd_send_hdr_and_body (struct MHD_Connection *restrict
connection,
{
enum mhd_SocketError err;
- err = mhd_socket_error_get_from_sys_err(mhd_SCKT_GET_LERR ());
+ err = mhd_socket_error_get_from_sys_err (mhd_SCKT_GET_LERR ());
if (mhd_SOCKET_ERR_AGAIN == err)
connection->sk_ready = (enum mhd_SocketNetState) /* Clear 'send-ready' */
(((unsigned int) connection->sk_ready)
- & (~mhd_SOCKET_NET_STATE_SEND_READY));
+ & (~(enum mhd_SocketNetState)
+ mhd_SOCKET_NET_STATE_SEND_READY));
return err;
}
if ((header_size + body_size) > *sent)
connection->sk_ready = (enum mhd_SocketNetState) /* Clear 'send-ready' */
(((unsigned int) connection->sk_ready)
- & (~mhd_SOCKET_NET_STATE_SEND_READY));
+ & (~(enum mhd_SocketNetState)
+ mhd_SOCKET_NET_STATE_SEND_READY));
/* If there is a need to push the data from network buffers
* call post_send_setopt(). */
@@ -1091,7 +1100,8 @@ mhd_send_hdr_and_body (struct MHD_Connection *restrict
connection,
#if defined(MHD_USE_SENDFILE) // TODO: adapt, update
-MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_ MHD_FN_PAR_OUT_ (2) enum mhd_SocketError
+MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_
+MHD_FN_PAR_OUT_ (2) enum mhd_SocketError
mhd_send_sendfile (struct MHD_Connection *restrict connection,
size_t *restrict sent)
{
@@ -1324,13 +1334,13 @@ mhd_send_sendfile (struct MHD_Connection *restrict
connection,
* @return mhd_SOCKET_ERR_NO_ERROR if send succeed (the @a sent gets
* the sent size) or socket error
*/
-static MHD_FN_PAR_NONNULL_ALL_ MHD_FN_PAR_OUT_ (4) enum mhd_SocketError
+static MHD_FN_PAR_NONNULL_ALL_
+MHD_FN_PAR_OUT_ (4) enum mhd_SocketError
send_iov_nontls (struct MHD_Connection *restrict connection,
struct mhd_iovec_track *const restrict r_iov,
bool push_data,
size_t *restrict sent)
{
- ssize_t res;
bool send_error;
size_t items_to_send;
#ifdef HAVE_SENDMSG
@@ -1410,12 +1420,13 @@ send_iov_nontls (struct MHD_Connection *restrict
connection,
{
enum mhd_SocketError err;
- err = mhd_socket_error_get_from_sys_err(mhd_SCKT_GET_LERR ());
+ err = mhd_socket_error_get_from_sys_err (mhd_SCKT_GET_LERR ());
if (mhd_SOCKET_ERR_AGAIN == err)
connection->sk_ready = (enum mhd_SocketNetState) /* Clear 'send-ready' */
(((unsigned int) connection->sk_ready)
- & (~mhd_SOCKET_NET_STATE_SEND_READY));
+ & (~(enum mhd_SocketNetState)
+ mhd_SOCKET_NET_STATE_SEND_READY));
return err;
}
@@ -1439,7 +1450,8 @@ send_iov_nontls (struct MHD_Connection *restrict
connection,
{
connection->sk_ready = (enum mhd_SocketNetState) /* Clear 'send-ready' */
(((unsigned int) connection->sk_ready)
- & (~mhd_SOCKET_NET_STATE_SEND_READY));
+ & (~(enum mhd_SocketNetState)
+ mhd_SOCKET_NET_STATE_SEND_READY));
if (0 != track_sent)
{
mhd_assert (r_iov->cnt > r_iov->sent);
@@ -1477,7 +1489,8 @@ send_iov_nontls (struct MHD_Connection *restrict
connection,
* @return mhd_SOCKET_ERR_NO_ERROR if send succeed (the @a sent gets
* the sent size) or socket error
*/
-static MHD_FN_PAR_NONNULL_ALL_ MHD_FN_PAR_OUT_ (4) enum mhd_SocketError
+static MHD_FN_PAR_NONNULL_ALL_
+MHD_FN_PAR_OUT_ (4) enum mhd_SocketError
send_iov_emu (struct MHD_Connection *restrict connection,
struct mhd_iovec_track *const restrict r_iov,
bool push_data,
@@ -1485,33 +1498,31 @@ send_iov_emu (struct MHD_Connection *restrict
connection,
{
const bool non_blk = connection->sk_nonblck;
size_t total_sent;
- size_t sent_elements;
size_t max_elelements_to_sent;
mhd_assert (NULL != r_iov->iov);
total_sent = 0;
- sent_elements = 0;
max_elelements_to_sent = 8; /* Do not make too many sys-calls for just one
connection */
do
{
enum mhd_SocketError res;
size_t sent_el_size;
- if (total_sent > (size_t)(r_iov->iov[r_iov->sent].iov_len + total_sent))
+ if (total_sent > (size_t) (r_iov->iov[r_iov->sent].iov_len + total_sent))
break; /* return value would overflow */
res = mhd_send_data (connection,
- r_iov->iov[r_iov->sent].iov_base,
- r_iov->iov[r_iov->sent].iov_len,
- push_data && (r_iov->cnt == r_iov->sent + 1),
- &sent_el_size);
+ r_iov->iov[r_iov->sent].iov_len,
+ r_iov->iov[r_iov->sent].iov_base,
+ push_data && (r_iov->cnt == r_iov->sent + 1),
+ &sent_el_size);
if (mhd_SOCKET_ERR_NO_ERROR == res)
{
/* Result is an error */
if (0 == total_sent)
return res; /* Nothing was sent, return error as is */
- if (mhd_SOCKET_ERR_IS_HARD(res))
+ if (mhd_SOCKET_ERR_IS_HARD (res))
return res; /* Any kind of a hard error */
break; /* Return the amount of the sent data */
@@ -1543,7 +1554,8 @@ send_iov_emu (struct MHD_Connection *restrict connection,
#endif /* !mhd_USE_VECT_SEND || HTTPS_SUPPORT
|| mhd_VECT_SEND_NEEDS_SPIPE_SUPPRESSED */
-MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_ MHD_FN_PAR_OUT_ (4) enum mhd_SocketError
+MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_
+MHD_FN_PAR_OUT_ (4) enum mhd_SocketError
mhd_send_iovec (struct MHD_Connection *restrict connection,
struct mhd_iovec_track *const restrict r_iov,
bool push_data,
@@ -1564,7 +1576,7 @@ mhd_send_iovec (struct MHD_Connection *restrict
connection,
#if defined(HTTPS_SUPPORT) || \
defined(mhd_VECT_SEND_NEEDS_SPIPE_SUPPRESSED)
#ifdef HTTPS_SUPPORT
- use_iov_send = use_iov_send &
+ use_iov_send = use_iov_send &&
(true); // TODO: TLS support
#endif /* HTTPS_SUPPORT */
#ifdef mhd_VECT_SEND_NEEDS_SPIPE_SUPPRESSED
@@ -1573,12 +1585,12 @@ mhd_send_iovec (struct MHD_Connection *restrict
connection,
#endif /* mhd_VECT_SEND_NEEDS_SPIPE_SUPPRESSED */
if (use_iov_send)
#endif /* HTTPS_SUPPORT || mhd_VECT_SEND_NEEDS_SPIPE_SUPPRESSED */
- return send_iov_nontls (connection, r_iov, push_data);
+ return send_iov_nontls (connection, r_iov, push_data, sent);
#endif /* mhd_USE_VECT_SEND */
#if ! defined(mhd_USE_VECT_SEND) || defined(HTTPS_SUPPORT) || \
defined(mhd_VECT_SEND_NEEDS_SPIPE_SUPPRESSED)
- return send_iov_emu (connection, r_iov, push_data);
+ return send_iov_emu (connection, r_iov, push_data, sent);
#endif /* !mhd_USE_VECT_SEND || HTTPS_SUPPORT
|| mhd_VECT_SEND_NEEDS_SPIPE_SUPPRESSED */
}
diff --git a/src/mhd2/mhd_socket_error.c b/src/mhd2/mhd_socket_error.c
index 449a9e1e..0c14e560 100644
--- a/src/mhd2/mhd_socket_error.c
+++ b/src/mhd2/mhd_socket_error.c
@@ -65,11 +65,12 @@ mhd_socket_error_get_from_socket (MHD_Socket fd)
#if defined(SOL_SOCKET) && defined(SO_ERROR)
enum mhd_SocketError err;
int sock_err;
- if (0 == setsockopt(fd, SOL_SOCKET, SOCKET_ERROR,
- (void *) &sock_err, sizeof(sock_err)))
+ sock_err = 0;
+ if (0 == setsockopt (fd, SOL_SOCKET, SOCKET_ERROR,
+ (void *) &sock_err, sizeof(sock_err)))
return mhd_socket_error_get_from_sys_err (sock_err);
- err = mhd_socket_error_get_from_sys_err(mhd_SCKT_GET_LERR());
+ err = mhd_socket_error_get_from_sys_err (mhd_SCKT_GET_LERR ());
if ((mhd_SOCKET_ERR_NOTSOCK == err) ||
(mhd_SOCKET_ERR_BADF == err))
return err;
diff --git a/src/mhd2/mhd_str.h b/src/mhd2/mhd_str.h
index 0139233a..15678208 100644
--- a/src/mhd2/mhd_str.h
+++ b/src/mhd2/mhd_str.h
@@ -100,10 +100,10 @@ mhd_str_equal_caseless_bin_n (const char *const str1,
* Comparison stops at first unmatched byte.
* @param a the statically allocated string to compare
* @param s the string to compare
- * @param len number of characters to compare
+ * @param l the number of characters in the @a s string
* @return 'true' if two strings are equal, 'false' otherwise.
*/
-#define mhd_str_equal_caseless_s_bin_n(a,s,l) \
+#define mhd_str_equal_caseless_n_st(a,s,l) \
((mhd_SSTR_LEN (a) == (l)) \
&& mhd_str_equal_caseless_bin_n (a,s,l))
@@ -517,10 +517,10 @@ mhd_hex_to_bin (const char *restrict hex,
* small to hold the result
*/
MHD_INTERNAL size_t
-mhd_str_pct_decode_strict_n_ (const char *pct_encoded,
- size_t pct_encoded_len,
- char *decoded,
- size_t buf_size);
+mhd_str_pct_decode_strict_n (const char *pct_encoded,
+ size_t pct_encoded_len,
+ char *decoded,
+ size_t buf_size);
/**
* Decode string with percent-encoded characters as defined by
@@ -545,11 +545,11 @@ mhd_str_pct_decode_strict_n_ (const char *pct_encoded,
* zero if output buffer is too small to hold the result
*/
MHD_INTERNAL size_t
-mhd_str_pct_decode_lenient_n_ (const char *pct_encoded,
- size_t pct_encoded_len,
- char *decoded,
- size_t buf_size,
- bool *broken_encoding);
+mhd_str_pct_decode_lenient_n (const char *pct_encoded,
+ size_t pct_encoded_len,
+ char *decoded,
+ size_t buf_size,
+ bool *broken_encoding);
/**
@@ -589,7 +589,7 @@ mhd_str_pct_decode_in_place_strict (char *str);
*/
MHD_INTERNAL size_t
mhd_str_pct_decode_in_place_lenient (char *str,
- bool *broken_encoding);
+ bool *broken_encoding);
#ifdef DAUTH_SUPPORT
/**
diff --git a/src/mhd2/request_funcs.c b/src/mhd2/request_funcs.c
index 6b3519f9..271a1add 100644
--- a/src/mhd2/request_funcs.c
+++ b/src/mhd2/request_funcs.c
@@ -41,20 +41,21 @@ mhd_stream_add_field_nullable (struct MHD_Connection
*restrict c,
struct mhd_RequestField *f;
f = (struct mhd_RequestField *)
- mhd_stream_alloc_memory (sizeof(struct mhd_RequestField));
+ mhd_stream_alloc_memory (c, sizeof(struct mhd_RequestField));
if (NULL == f)
return false;
- f->field.nv.name = name;
- f->field.nv.value = value;
+ f->field.nv.name = *name;
+ f->field.nv.value = *value;
f->field.kind = kind;
- mhd_DLINKEDL_INIT_LINKS(f, fields);
+ mhd_DLINKEDL_INIT_LINKS (f, fields);
- mhd_DLINKEDL_INS_LAST(&(c->rq),f,fields);
+ mhd_DLINKEDL_INS_LAST (&(c->rq),f,fields);
return true;
}
+
MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_ bool
mhd_stream_add_field (struct MHD_Connection *restrict c,
enum MHD_ValueKind kind,
@@ -66,5 +67,5 @@ mhd_stream_add_field (struct MHD_Connection *restrict c,
value2.len = value->len;
value2.cstr = value->cstr;
- return mhd_stream_add_field_nullable(c, kind, name, &value2);
+ return mhd_stream_add_field_nullable (c, kind, name, &value2);
}
diff --git a/src/mhd2/request_get_value.c b/src/mhd2/request_get_value.c
index ca7a2b0b..7f3a5b32 100644
--- a/src/mhd2/request_get_value.c
+++ b/src/mhd2/request_get_value.c
@@ -34,35 +34,41 @@
#include "mhd_public_api.h"
#include "mhd_dlinked_list.h"
+#include "mhd_assert.h"
-MHD_INTERNAL MHD_FN_PAR_NONNULL_ (1)
-MHD_FN_PAR_NONNULL_ (3) MHD_FN_PAR_CSTR_ (3) const struct MHD_String *
-mhd_request_get_value_len (struct MHD_Request *MHD_RESTRICT request,
- enum MHD_ValueKind kind,
- size_t key_len,
- const char *restrict key)
+MHD_INTERNAL
+MHD_FN_PAR_NONNULL_ (1)
+MHD_FN_PAR_NONNULL_ (4) MHD_FN_PAR_CSTR_ (4) const struct MHD_StringNullable *
+mhd_request_get_value_n (struct MHD_Request *MHD_RESTRICT request,
+ enum MHD_ValueKind kind,
+ size_t key_len,
+ const char *restrict key)
{
struct mhd_RequestField *f;
- for (f = mhd_DLINKEDL_GET_FIRST(request, fields); NULL != f;
- f = mhd_DLINKEDL_GET_NEXT(f, fields))
+ mhd_assert (strlen (key) == key_len);
+
+ for (f = mhd_DLINKEDL_GET_FIRST (request, fields); NULL != f;
+ f = mhd_DLINKEDL_GET_NEXT (f, fields))
{
if ((key_len == f->field.nv.name.len) &&
(kind == f->field.kind) &&
- (0 == memcmp(key, f->field.nv.name.cstr)))
+ (0 == memcmp (key, f->field.nv.name.cstr, key_len)))
return &(f->field.nv.value);
}
return NULL;
}
-MHD_EXTERN_ MHD_FN_PAR_NONNULL_ (1)
-MHD_FN_PAR_NONNULL_ (3) MHD_FN_PAR_CSTR_ (3) const struct MHD_String *
+
+MHD_EXTERN_
+MHD_FN_PAR_NONNULL_ (1)
+MHD_FN_PAR_NONNULL_ (3) MHD_FN_PAR_CSTR_ (3) const struct MHD_StringNullable *
MHD_request_get_value (struct MHD_Request *MHD_RESTRICT request,
enum MHD_ValueKind kind,
const char *MHD_RESTRICT key)
{
size_t len;
- len = strlen(key);
- return mhd_request_get_value_len(request, kind, len, key);
+ len = strlen (key);
+ return mhd_request_get_value_n (request, kind, len, key);
}
diff --git a/src/mhd2/request_get_value.h b/src/mhd2/request_get_value.h
index 950bb523..a549972f 100644
--- a/src/mhd2/request_get_value.h
+++ b/src/mhd2/request_get_value.h
@@ -31,8 +31,10 @@
#include "sys_base_types.h"
#include "mhd_public_api.h"
+#include "mhd_str_macros.h"
+
/**
- * Get a particular header (or other kind of request data) value.
+ * Get specified field value from request
* If multiple values match the kind, return any one of them.
*
* The returned pointer is valid until the response is queued.
@@ -40,17 +42,35 @@
*
* @param request request to get values from
* @param kind what kind of value are we looking for
+ * @param key_len the length of the @a key string
* @param key the header to look for, empty to lookup 'trailing' value
* without a key
* @return NULL if no such item was found
* @ingroup request
*/
-MHD_INTERNAL const struct MHD_String *
-mhd_request_get_value_len (struct MHD_Request *restrict request,
- enum MHD_ValueKind kind,
- size_t key_len,
- const char *restrict key)
+MHD_INTERNAL const struct MHD_StringNullable *
+mhd_request_get_value_n (struct MHD_Request *restrict request,
+ enum MHD_ValueKind kind,
+ size_t key_len,
+ const char *restrict key)
MHD_FN_PAR_NONNULL_ (1)
MHD_FN_PAR_NONNULL_ (4) MHD_FN_PAR_CSTR_ (4);
+/**
+ * Get specified field value from request
+ * If multiple values match the kind, return any one of them.
+ *
+ * The returned pointer is valid until the response is queued.
+ * If the data is needed beyond this point, it should be copied.
+ *
+ * @param request request to get values from
+ * @param kind what kind of value are we looking for
+ * @param key the header to look for, empty to lookup 'trailing' value
+ * without a key; must be a static string or array
+ * @return NULL if no such item was found
+ * @ingroup request
+ */
+#define mhd_request_get_value_st(r,k,str) \
+ mhd_request_get_value_n ((r),(k),mhd_SSTR_LEN (str),(str))
+
#endif /* ! MHD_REQUEST_GET_VALUE_H */
diff --git a/src/mhd2/respond_with_error.h b/src/mhd2/respond_with_error.h
new file mode 100644
index 00000000..3dc8930b
--- /dev/null
+++ b/src/mhd2/respond_with_error.h
@@ -0,0 +1,86 @@
+/*
+ This file is part of GNU libmicrohttpd
+ Copyright (C) 2024 Evgeny Grin (Karlson2k)
+
+ GNU libmicrohttpd is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ GNU libmicrohttpd is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
USA
+
+*/
+
+/**
+ * @file src/mhd2/respond_with_error.h
+ * @brief The declaration of error response functions and helper macros
+ * @author Karlson2k (Evgeny Grin)
+ */
+
+#ifndef MHD_RESPOND_WITH_ERROR_H
+#define MHD_RESPOND_WITH_ERROR_H 1
+
+#include "mhd_sys_options.h"
+#include "sys_base_types.h"
+#include "sys_null_macro.h"
+#include "mhd_str_macros.h"
+
+struct MHD_Connection; /* forward declaration */
+
+MHD_INTERNAL void
+respond_with_error_len (struct MHD_Connection *c,
+ unsigned int http_code,
+ size_t msg_len,
+ const char *msg,
+ size_t add_hdr_name_len,
+ const char *add_hdr_name,
+ size_t add_hdr_value_len,
+ const char *add_hdr_value)
+MHD_FN_PAR_NONNULL_ (1)
+MHD_FN_PAR_CSTR_ (4) MHD_FN_PAR_CSTR_ (6) MHD_FN_PAR_CSTR_ (8);
+
+#ifdef HAVE_HTTP_AUTO_MESSAGES_BODIES
+/**
+ * Transmit static string as error response
+ */
+# define mhd_RESPOND_WITH_ERROR_STATIC(c, code, msg) \
+ respond_with_error_len ((c), (code), \
+ mhd_SSTR_LEN (msg), (msg), \
+ 0, NULL, 0, NULL)
+
+/**
+ * Transmit static string as error response and add specified header
+ */
+# define mhd_RESPOND_WITH_ERROR_HEADER(c,code,m,hd_n_l,hd_n,hd_v_l,hd_v) \
+ respond_with_error_len ((c), (code), \
+ mhd_SSTR_LEN (m), (m), \
+ (hd_n_l), (hd_n), \
+ (hd_v_l), (hd_v))
+
+#else
+/**
+ * Transmit static string as error response
+ */
+# define mhd_RESPOND_WITH_ERROR_STATIC(c, code, msg) \
+ respond_with_error_len ((c), (code), \
+ 0, NULL, \
+ 0, NULL, 0, NULL)
+
+/**
+ * Transmit static string as error response and add specified header
+ */
+# define mhd_RESPOND_WITH_ERROR_HEADER(c,code,m,hd_n_l,hd_n,hd_v_l,hd_v) \
+ respond_with_error_len ((c), (code), \
+ 0, NULL, \
+ (hd_n_l), (hd_n), \
+ (hd_v_l), (hd_v))
+#endif
+
+#endif /* ! MHD_RESPOND_WITH_ERROR_H */
diff --git a/src/mhd2/response_add_header.c b/src/mhd2/response_add_header.c
index e563239c..b8751ba3 100644
--- a/src/mhd2/response_add_header.c
+++ b/src/mhd2/response_add_header.c
@@ -26,6 +26,7 @@
#include "mhd_sys_options.h"
+#include "response_add_header.h"
#include "mhd_response.h"
#include "mhd_locks.h"
@@ -34,26 +35,27 @@
#include "mhd_public_api.h"
-MHD_INTERNAL
+static
MHD_FN_PAR_NONNULL_ (1)
-MHD_FN_PAR_NONNULL_ (3) MHD_FN_PAR_CSTR_ (3) MHD_FN_PAR_IN_SIZE_(3,2)
-MHD_FN_PAR_NONNULL_ (5) MHD_FN_PAR_CSTR_ (5) MHD_FN_PAR_IN_SIZE_(5,4) bool
+MHD_FN_PAR_NONNULL_ (3) MHD_FN_PAR_CSTR_ (3) MHD_FN_PAR_IN_SIZE_ (3,2)
+MHD_FN_PAR_NONNULL_ (5) MHD_FN_PAR_CSTR_ (5) MHD_FN_PAR_IN_SIZE_ (5,4) bool
response_add_header_no_check (
struct MHD_Response *response,
size_t name_len,
- const char name[MHD_FN_PAR_DYN_ARR_SIZE_(name_len)],
+ const char name[MHD_FN_PAR_DYN_ARR_SIZE_ (name_len)],
size_t value_len,
- const char value[MHD_FN_PAR_DYN_ARR_SIZE_(value_len)])
+ const char value[MHD_FN_PAR_DYN_ARR_SIZE_ (value_len)])
{
char *buf;
struct mhd_ResponseHeader *new_hdr;
- buf = malloc (sizeof(struct mhd_ResponseHeader) + name_len + value_len + 2);
- if (NULL == buf)
+ new_hdr = (struct mhd_ResponseHeader *)
+ malloc (sizeof(struct mhd_ResponseHeader) + name_len
+ + value_len + 2);
+ if (NULL == new_hdr)
return false;
- new_hdr = (struct mhd_ResponseHeader *) buf;
- buf += sizeof(struct mhd_ResponseHeader);
+ buf = ((char *) new_hdr) + sizeof(struct mhd_ResponseHeader);
memcpy (buf, name, name_len);
buf[name_len] = 0;
new_hdr->name.cstr = buf;
@@ -68,15 +70,17 @@ response_add_header_no_check (
return true;
}
-MHD_INTERNAL MHD_FN_PAR_NONNULL_ (1) void
+
+MHD_INTERNAL
+MHD_FN_PAR_NONNULL_ (1) void
mhd_response_remove_all_headers (struct MHD_Response *restrict r)
{
struct mhd_ResponseHeader *hdr;
- for (hdr = mhd_DLINKEDL_GET_LAST(r, headers); NULL != hdr;
- hdr = mhd_DLINKEDL_GET_LAST(r, headers))
+ for (hdr = mhd_DLINKEDL_GET_LAST (r, headers); NULL != hdr;
+ hdr = mhd_DLINKEDL_GET_LAST (r, headers))
{
- mhd_DLINKEDL_DEL(r, hdr, headers);
+ mhd_DLINKEDL_DEL (r, hdr, headers);
free (hdr);
}
}
@@ -103,7 +107,8 @@ response_add_header_int (struct MHD_Response *response,
(NULL != memchr (value, '\r', value_len)))
return MHD_SC_RESP_HEADER_VALUE_INVALID;
- if (!response_add_header_no_check(response, name_len, name, value_len,
value))
+ if (! response_add_header_no_check (response, name_len, name,
+ value_len, value))
return MHD_SC_RESPONSE_HEADER_MALLOC_FAILED;
return MHD_SC_OK;
@@ -129,7 +134,7 @@ MHD_response_add_header (struct MHD_Response *response,
need_unlock = true;
if (! mhd_mutex_lock (&(response->reuse.settings_lock)))
return MHD_SC_RESPONSE_MUTEX_LOCK_FAILED;
- mhd_assert (1 == mhd_atomic_counter_get(&(response->reuse.counter)));
+ mhd_assert (1 == mhd_atomic_counter_get (&(response->reuse.counter)));
}
else
need_unlock = false;
diff --git a/src/mhd2/response_destroy.c b/src/mhd2/response_destroy.c
index 95bfaf02..defde693 100644
--- a/src/mhd2/response_destroy.c
+++ b/src/mhd2/response_destroy.c
@@ -35,6 +35,7 @@
#include "response_add_header.h"
#include "response_funcs.h"
+#include "response_from.h"
/**
* Perform full response de-initialisation, with cleaning-up / freeing
@@ -47,8 +48,8 @@ response_full_detinit (struct MHD_Response *restrict r)
{
mhd_response_remove_all_headers (r);
if (r->reuse.reusable)
- mhd_response_deinit_reusable(r);
- mhd_response_deinit_content_data(r);
+ mhd_response_deinit_reusable (r);
+ mhd_response_deinit_content_data (r);
free (r);
}
@@ -56,11 +57,11 @@ response_full_detinit (struct MHD_Response *restrict r)
MHD_INTERNAL void
mhd_response_dec_use_count (struct MHD_Response *restrict r)
{
- mhd_assert(r->frozen);
+ mhd_assert (r->frozen);
if (r->reuse.reusable)
{
- if (0 != mhd_atomic_counter_dec_get(&(r->reuse.counter)))
+ if (0 != mhd_atomic_counter_dec_get (&(r->reuse.counter)))
return; /* The response is still used somewhere */
}
@@ -68,7 +69,8 @@ mhd_response_dec_use_count (struct MHD_Response *restrict r)
}
-MHD_EXTERN_ MHD_FN_PAR_NONNULL_ (1) void
+MHD_EXTERN_
+MHD_FN_PAR_NONNULL_ (1) void
MHD_response_destroy (struct MHD_Response *response)
{
if (! response->frozen)
@@ -78,7 +80,7 @@ MHD_response_destroy (struct MHD_Response *response)
free (response->settings);
#ifndef NDEBUG
/* Decrement counter to avoid triggering assert in deinit function */
- mhd_assert (0 == mhd_atomic_counter_dec_get(&(response->reuse.counter)));
+ mhd_assert (0 == mhd_atomic_counter_dec_get (&(response->reuse.counter)));
#endif
response_full_detinit (response);
return;
diff --git a/src/mhd2/response_funcs.c b/src/mhd2/response_funcs.c
index a4b27312..6853592f 100644
--- a/src/mhd2/response_funcs.c
+++ b/src/mhd2/response_funcs.c
@@ -32,39 +32,42 @@
#include "mhd_response.h"
#include "response_funcs.h"
#include "mhd_locks.h"
+#include "response_options.h"
#include "mhd_atomic_counter.h"
-MHD_INTERNAL MHD_FN_PAR_NONNULL_ (1) bool
+MHD_INTERNAL
+MHD_FN_PAR_NONNULL_ (1) bool
response_make_reusable (struct MHD_Response *restrict r)
{
mhd_assert (! r->reuse.reusable);
mhd_assert (! r->frozen);
mhd_assert (NULL != r->settings);
- if (mhd_mutex_init(&(r->reuse.settings_lock)))
+ if (mhd_mutex_init (&(r->reuse.settings_lock)))
{
- if (mhd_atomic_counter_init(&(r->reuse.counter), 1))
+ if (mhd_atomic_counter_init (&(r->reuse.counter), 1))
{
r->reuse.reusable = true;
return true;
}
- (void) mhd_mutex_destroy(&(r->reuse.settings_lock));
+ (void) mhd_mutex_destroy (&(r->reuse.settings_lock));
}
return false;
}
-MHD_INTERNAL MHD_FN_PAR_NONNULL_ (1) void
+MHD_INTERNAL
+MHD_FN_PAR_NONNULL_ (1) void
mhd_response_deinit_reusable (struct MHD_Response *restrict r)
{
- mhd_assert(r->reuse.reusable);
- mhd_assert(0 == mhd_atomic_counter_get(&(r->reuse.counter)));
+ mhd_assert (r->reuse.reusable);
+ mhd_assert (0 == mhd_atomic_counter_get (&(r->reuse.counter)));
- mhd_atomic_counter_deinit(&(r->reuse.counter));
- mhd_mutex_destroy_chk(&(r->reuse.settings_lock));
+ mhd_atomic_counter_deinit (&(r->reuse.counter));
+ mhd_mutex_destroy_chk (&(r->reuse.settings_lock));
}
@@ -110,7 +113,7 @@ mhd_response_check_frozen_freeze (struct MHD_Response
*restrict response)
{
need_unlock = true;
mhd_mutex_lock_chk (&(response->reuse.settings_lock));
- mhd_assert (1 == mhd_atomic_counter_get(&(response->reuse.counter)));
+ mhd_assert (1 == mhd_atomic_counter_get (&(response->reuse.counter)));
}
else
need_unlock = false;
diff --git a/src/mhd2/response_set_options.c b/src/mhd2/response_set_options.c
index cd56338f..ec4682ef 100644
--- a/src/mhd2/response_set_options.c
+++ b/src/mhd2/response_set_options.c
@@ -18,6 +18,7 @@
#include "mhd_public_api.h"
#include "mhd_locks.h"
#include "mhd_assert.h"
+#include "response_funcs.h"
/**
* Internal version of the #MHD_response_set_options()
diff --git a/src/mhd2/stream_funcs.c b/src/mhd2/stream_funcs.c
index 51260411..580dbafc 100644
--- a/src/mhd2/stream_funcs.c
+++ b/src/mhd2/stream_funcs.c
@@ -39,17 +39,17 @@ MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_ void *
mhd_stream_alloc_memory (struct MHD_Connection *restrict c,
size_t size)
{
- struct MemoryPool *const restrict pool = c->pool; /* a short alias */
+ struct mhd_MemoryPool *const restrict pool = c->pool; /* a short alias */
size_t need_to_be_freed = 0; /**< The required amount of additional free
memory */
void *res;
- res = MHD_pool_try_alloc (pool,
+ res = mhd_pool_try_alloc (pool,
size,
&need_to_be_freed);
if (NULL != res)
return res;
- if (MHD_pool_is_resizable_inplace (pool,
+ if (mhd_pool_is_resizable_inplace (pool,
c->write_buffer,
c->write_buffer_size))
{
@@ -58,7 +58,7 @@ mhd_stream_alloc_memory (struct MHD_Connection *restrict c,
{
char *buf;
const size_t new_buf_size = c->write_buffer_size - need_to_be_freed;
- buf = MHD_pool_reallocate (pool,
+ buf = mhd_pool_reallocate (pool,
c->write_buffer,
c->write_buffer_size,
new_buf_size);
@@ -71,7 +71,7 @@ mhd_stream_alloc_memory (struct MHD_Connection *restrict c,
else
return NULL;
}
- else if (MHD_pool_is_resizable_inplace (pool,
+ else if (mhd_pool_is_resizable_inplace (pool,
c->read_buffer,
c->read_buffer_size))
{
@@ -79,7 +79,7 @@ mhd_stream_alloc_memory (struct MHD_Connection *restrict c,
{
char *buf;
const size_t new_buf_size = c->read_buffer_size - need_to_be_freed;
- buf = MHD_pool_reallocate (pool,
+ buf = mhd_pool_reallocate (pool,
c->read_buffer,
c->read_buffer_size,
new_buf_size);
@@ -93,12 +93,90 @@ mhd_stream_alloc_memory (struct MHD_Connection *restrict c,
}
else
return NULL;
- res = MHD_pool_allocate (pool, size, true);
+ res = mhd_pool_allocate (pool, size, true);
mhd_assert (NULL != res); /* It has been checked that pool has enough space
*/
return res;
}
+/**
+ * Shrink stream read buffer to the zero size of free space in the buffer
+ * @param c the connection whose read buffer is being manipulated
+ */
+MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_ void
+mhd_stream_shrink_read_buffer (struct MHD_Connection *restrict c)
+{
+ void *new_buf;
+
+ if ((NULL == c->read_buffer) || (0 == c->read_buffer_size))
+ {
+ mhd_assert (0 == c->read_buffer_size);
+ mhd_assert (0 == c->read_buffer_offset);
+ return;
+ }
+
+ mhd_assert (c->read_buffer_offset <= c->read_buffer_size);
+ if (0 == c->read_buffer_offset)
+ {
+ mhd_pool_deallocate (c->pool, c->read_buffer, c->read_buffer_size);
+ c->read_buffer = NULL;
+ c->read_buffer_size = 0;
+ }
+ else
+ {
+ mhd_assert (mhd_pool_is_resizable_inplace (c->pool, c->read_buffer, \
+ c->read_buffer_size));
+ new_buf = mhd_pool_reallocate (c->pool, c->read_buffer,
c->read_buffer_size,
+ c->read_buffer_offset);
+ mhd_assert (c->read_buffer == new_buf);
+ c->read_buffer = new_buf;
+ c->read_buffer_size = c->read_buffer_offset;
+ }
+}
+
+
+MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_ size_t
+mhd_stream_maximize_write_buffer (struct MHD_Connection *restrict c)
+{
+ struct mhd_MemoryPool *const restrict pool = c->pool;
+ void *new_buf;
+ size_t new_size;
+ size_t free_size;
+
+ mhd_assert ((NULL != c->write_buffer) || (0 == c->write_buffer_size));
+ mhd_assert (c->write_buffer_append_offset >= c->write_buffer_send_offset);
+ mhd_assert (c->write_buffer_size >= c->write_buffer_append_offset);
+
+ free_size = mhd_pool_get_free (pool);
+ if (0 != free_size)
+ {
+ new_size = c->write_buffer_size + free_size;
+ /* This function must not move the buffer position.
+ * mhd_pool_reallocate () may return the new position only if buffer was
+ * allocated 'from_end' or is not the last allocation,
+ * which should not happen. */
+ mhd_assert ((NULL == c->write_buffer) || \
+ mhd_pool_is_resizable_inplace (pool, c->write_buffer, \
+ c->write_buffer_size));
+ new_buf = mhd_pool_reallocate (pool,
+ c->write_buffer,
+ c->write_buffer_size,
+ new_size);
+ mhd_assert ((c->write_buffer == new_buf) || (NULL == c->write_buffer));
+ c->write_buffer = new_buf;
+ c->write_buffer_size = new_size;
+ if (c->write_buffer_send_offset == c->write_buffer_append_offset)
+ {
+ /* All data have been sent, reset offsets to zero. */
+ c->write_buffer_send_offset = 0;
+ c->write_buffer_append_offset = 0;
+ }
+ }
+
+ return c->write_buffer_size - c->write_buffer_append_offset;
+}
+
+
#ifndef MHD_MAX_REASONABLE_HEADERS_SIZE_
/**
* A reasonable headers size (excluding request line) that should be sufficient
@@ -169,7 +247,8 @@ mhd_stream_alloc_memory (struct MHD_Connection *restrict c,
#endif /* ! MHD_MIN_REASONABLE_REQ_CHUNK_LINE_LENGTH_ */
-MHD_INTERNAL MHD_FN_PAR_NONNULL_(1) MHD_FN_PAR_IN_SIZE_(4,3) unsigned int
+MHD_INTERNAL
+MHD_FN_PAR_NONNULL_ (1) MHD_FN_PAR_IN_SIZE_ (4,3) unsigned int
mhd_stream_get_no_space_err_status_code (struct MHD_Connection *restrict c,
enum MHD_ProcRecvDataStage stage,
size_t add_element_size,
@@ -220,8 +299,8 @@ mhd_stream_get_no_space_err_status_code (struct
MHD_Connection *restrict c,
&& ( (0 == add_element[header_host_key_len])
|| (':' == add_element[header_host_key_len]) )
&& mhd_str_equal_caseless_bin_n (MHD_HTTP_HEADER_HOST,
- add_element,
- header_host_key_len);
+ add_element,
+ header_host_key_len);
if (is_host_header)
{
const bool is_parsed = ! (
@@ -249,11 +328,11 @@ mhd_stream_get_no_space_err_status_code (struct
MHD_Connection *restrict c,
{
static const size_t host_field_name_len =
mhd_SSTR_LEN (MHD_HTTP_HEADER_HOST);
- struct MHD_String *host_value;
- host_value = mhd_request_get_value_len(&(c->rq),
- MHD_VK_HEADER,
- MHD_HTTP_HEADER_HOST,
- host_field_name_len);
+ const struct MHD_StringNullable *host_value;
+ host_value = mhd_request_get_value_n (&(c->rq),
+ MHD_VK_HEADER,
+ host_field_name_len,
+ MHD_HTTP_HEADER_HOST);
if (NULL != host_value)
{
/* Calculate the minimal size of the field line: no space between
@@ -369,3 +448,11 @@ mhd_stream_get_no_space_err_status_code (struct
MHD_Connection *restrict c,
return MHD_HTTP_STATUS_URI_TOO_LONG;
}
+
+
+MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_ void
+mhd_stream_switch_from_recv_to_send (struct MHD_Connection *c)
+{
+ /* Read buffer is not needed for this request, shrink it.*/
+ mhd_stream_shrink_read_buffer (c);
+}
diff --git a/src/mhd2/stream_funcs.h b/src/mhd2/stream_funcs.h
index 0e775dbe..697fde5e 100644
--- a/src/mhd2/stream_funcs.h
+++ b/src/mhd2/stream_funcs.h
@@ -30,6 +30,7 @@
#include "mhd_sys_options.h"
#include "sys_base_types.h"
+
struct MHD_Connection; /* forward declaration */
@@ -64,6 +65,25 @@ mhd_stream_alloc_memory (struct MHD_Connection *restrict
connection,
size_t size)
MHD_FN_PAR_NONNULL_ALL_;
+/**
+ * Shrink stream read buffer to the zero size of free space in the buffer
+ * @param c the connection whose read buffer is being manipulated
+ */
+MHD_INTERNAL void
+mhd_stream_shrink_read_buffer (struct MHD_Connection *restrict c)
+MHD_FN_PAR_NONNULL_ALL_;
+
+/**
+ * Allocate the maximum available amount of memory from MemoryPool
+ * for write buffer.
+ * @param c the connection whose write buffer is being manipulated
+ * @return the size of the free space in the write buffer
+ */
+MHD_INTERNAL size_t
+mhd_stream_maximize_write_buffer (struct MHD_Connection *restrict c)
+MHD_FN_PAR_NONNULL_ALL_;
+
+
/**
* Select the HTTP error status code for "out of receive buffer space" error.
* @param c the connection to process
@@ -81,6 +101,69 @@ mhd_stream_get_no_space_err_status_code (struct
MHD_Connection *restrict c,
enum MHD_ProcRecvDataStage stage,
size_t add_element_size,
const char *restrict add_element)
-MHD_FN_PAR_NONNULL_(1) MHD_FN_PAR_IN_SIZE_(4,3);
+MHD_FN_PAR_NONNULL_ (1) MHD_FN_PAR_IN_SIZE_ (4,3);
+
+/**
+ * Switch connection from recv mode to send mode.
+ *
+ * Current request header or body will not be read anymore,
+ * response must be assigned to connection.
+ * @param c the connection to prepare for sending.
+ */
+MHD_INTERNAL void
+mhd_stream_switch_from_recv_to_send (struct MHD_Connection *c)
+MHD_FN_PAR_NONNULL_ALL_;
+
+
+enum mhd_StreamAbortReason
+{
+ mhd_STREAM_ABORT_CLIENT_HTTP_ERR
+};
+
+/**
+ * Close stream with error
+ *
+ * @param c the connection to close.
+ */
+MHD_INTERNAL void
+mhd_stream_abort (struct MHD_Connection *c,
+ enum mhd_StreamAbortReason reason,
+ const char *log_msg)
+MHD_FN_PAR_NONNULL_ (1) MHD_FN_PAR_CSTR_ (3);
+
+#ifdef HAVE_LOG_FUNCTIONALITY
+# define mhd_STREAM_ABORT(c,r,m) (mhd_stream_abort ((c),(r),(m)))
+#else /* ! HAVE_LOG_FUNCTIONALITY */
+# define mhd_STREAM_ABORT(c,r,m) (mhd_stream_abort ((c),(r),NULL))
+#endif /* ! HAVE_LOG_FUNCTIONALITY */
+
+/**
+ * Update last activity mark to the current time..
+ * @param c the connection to update
+ */
+MHD_INTERNAL void
+mhd_stream_update_activity_mark (struct MHD_Connection *restrict c)
+MHD_FN_PAR_NONNULL_ALL_;
+
+
+/**
+ * Perform initial clean-up and mark for closing.
+ * Set the reason to "aborted by application"
+ * @param c to make
+ */
+MHD_INTERNAL void
+mhd_conn_pre_close_app_abort (struct MHD_Connection *restrict c)
+MHD_FN_PAR_NONNULL_ALL_;
+
+
+/**
+ * Perform initial clean-up and mark for closing.
+ * Set the reason to "socket error"
+ * @param c to make
+ */
+MHD_INTERNAL void
+mhd_conn_pre_close_skt_err (struct MHD_Connection *restrict c)
+MHD_FN_PAR_NONNULL_ALL_;
+
#endif /* ! MHD_STREAM_FUNCS_H */
diff --git a/src/mhd2/http_status_str.h b/src/mhd2/stream_process_reply.h
similarity index 62%
copy from src/mhd2/http_status_str.h
copy to src/mhd2/stream_process_reply.h
index 4906943b..2531fce6 100644
--- a/src/mhd2/http_status_str.h
+++ b/src/mhd2/stream_process_reply.h
@@ -19,28 +19,20 @@
*/
/**
- * @file src/mhd2/http_status_str.h
- * @brief The declaration for internal HTTP status string functions
+ * @file src/mhd2/stream_process_reply.h
+ * @brief The declarations of internal functions for forming and sending
+ * replies for requests
* @author Karlson2k (Evgeny Grin)
*/
-#ifndef MHD_HTTP_STATUS_STR_H
-#define MHD_HTTP_STATUS_STR_H 1
+#ifndef MHD_STREAM_PROCESS_REPLY_H
+#define MHD_STREAM_PROCESS_REPLY_H 1
#include "mhd_sys_options.h"
-#include "mhd_str_types.h"
+#include "sys_bool_type.h"
-/**
- * Get string for provided HTTP status code.
- * Substitute a replacement string for unknown codes.
- *
- * @param code the HTTP status code
- * @return pointer to MHD_String, never NULL.
- */
-MHD_INTERNAL const struct MHD_String *
-mhd_HTTP_status_code_to_string_int (enum MHD_HTTP_StatusCode code)
-MHD_FN_CONST_;
+struct MHD_Connection; /* forward declaration */
-#endif /* ! MHD_HTTP_STATUS_STR_H */
+#endif /* ! MHD_STREAM_PROCESS_REPLY_H */
diff --git a/src/mhd2/stream_process_request.c
b/src/mhd2/stream_process_request.c
index 5250559a..19bf5e11 100644
--- a/src/mhd2/stream_process_request.c
+++ b/src/mhd2/stream_process_request.c
@@ -1,6 +1,7 @@
/*
This file is part of GNU libmicrohttpd
- Copyright (C) 2024 Evgeny Grin (Karlson2k)
+ Copyright (C) 2014-2024 Evgeny Grin (Karlson2k)
+ Copyright (C) 2007-2020 Daniel Pittman and Christian Grothoff
GNU libmicrohttpd is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
@@ -23,23 +24,36 @@
* @brief The implementation of internal functions for requests parsing
* and processing
* @author Karlson2k (Evgeny Grin)
+ *
+ * Based on the MHD v0.x code by Daniel Pittman, Christian Grothoff and other
+ * contributors.
*/
#include "mhd_sys_options.h"
+#include "stream_process_request.h"
#include "sys_bool_type.h"
#include "sys_base_types.h"
+#include "mhd_str_types.h"
#include "mhd_str_macros.h"
+#include "mhd_str.h"
#include <string.h>
+#include "mhd_daemon.h"
#include "mhd_connection.h"
+#include "mhd_public_api.h"
-#include "mhd_str_types.h"
#include "daemon_logger.h"
+#include "mhd_assert.h"
+#include "mhd_panic.h"
#include "request_funcs.h"
+#include "request_get_value.h"
+#include "respond_with_error.h"
+#include "stream_funcs.h"
+#include "daemon_funcs.h"
/**
* Response text used when the request (http header) is
@@ -254,6 +268,95 @@
"request target or a shorter request method token.</p></body>" \
"</html>"
+/**
+ * Response text used when the request header is too big to be processed.
+ */
+#define ERR_RSP_REQUEST_FOOTER_TOO_BIG \
+ "<html>" \
+ "<head><title>Request too big</title></head>" \
+ "<body><p>The total size of the request headers, which includes the " \
+ "request target, the request field lines and the chunked trailer " \
+ "section exceeds the memory constraints of this web server.</p>" \
+ "<p>The request could be re-tried with a shorter chunked trailer " \
+ "section, shorter field lines, a shorter request target or " \
+ "a shorter request method token.</p></body>" \
+ "</html>"
+
+/**
+ * Response text used when the request (http header) is too big to
+ * be processed.
+ */
+#define ERR_RSP_MSG_REQUEST_TOO_BIG \
+ "<html>" \
+ "<head><title>Request too big</title></head>" \
+ "<body>Request HTTP header is too big for the memory constraints " \
+ "of this webserver.</body>" \
+ "</html>"
+
+/**
+ * Response text used when the request (http header) does not
+ * contain a "Host:" header and still claims to be HTTP 1.1.
+ */
+#define ERR_RSP_REQUEST_LACKS_HOST \
+ "<html>" \
+ "<head><title>"Host:" header required</title></head>" \
+ "<body>HTTP/1.1 request without <b>"Host:"</b>.</body>" \
+ "</html>"
+
+/**
+ * Response text used when the request has unsupported "Transfer-Encoding:".
+ */
+#define ERR_RSP_UNSUPPORTED_TR_ENCODING \
+ "<html>" \
+ "<head><title>Unsupported Transfer-Encoding</title></head>" \
+ "<body>The Transfer-Encoding used in request is not supported.</body>"
\
+ "</html>"
+
+/**
+ * Response text used when the request has unsupported both headers:
+ * "Transfer-Encoding:" and "Content-Length:"
+ */
+#define ERR_RSP_REQUEST_CNTNLENGTH_WITH_TR_ENCODING \
+ "<html>" \
+ "<head><title>Malformed request</title></head>" \
+ "<body>Wrong combination of the request headers: both
Transfer-Encoding " \
+ "and Content-Length headers are used at the same time.</body>" \
+ "</html>"
+
+/**
+ * Response text used when the request HTTP content is too large.
+ */
+#define ERR_RSP_REQUEST_CONTENTLENGTH_TOOLARGE \
+ "<html><head><title>Request content too large</title></head>" \
+ "<body>HTTP request has too large value for " \
+ "<b>Content-Length</b> header.</body></html>"
+
+/**
+ * Response text used when the request HTTP chunked encoding is
+ * malformed.
+ */
+#define ERR_RSP_REQUEST_CONTENTLENGTH_MALFORMED \
+ "<html><head><title>Request malformed</title></head>" \
+ "<body>HTTP request has wrong value for " \
+ "<b>Content-Length</b> header.</body></html>"
+
+
+/**
+ * Response text used when the request HTTP chunked encoding is
+ * malformed.
+ */
+#define ERR_RSP_REQUEST_CHUNKED_MALFORMED \
+ "<html><head><title>Request malformed</title></head>" \
+ "<body>HTTP chunked encoding is syntactically incorrect.</body></html>"
+
+/**
+ * Response text used when the request HTTP chunk is too large.
+ */
+#define ERR_RSP_REQUEST_CHUNK_TOO_LARGE \
+ "<html><head><title>Request content too large</title></head>" \
+ "<body>The chunk size used in HTTP chunked encoded " \
+ "request is too large.</body></html>"
+
/**
* Get whether bare LF in HTTP header and other protocol elements
* should be treated as the line termination depending on the configured
@@ -265,7 +368,57 @@
/**
* The valid length of any HTTP version string
*/
-#define HTTP_VER_LEN (mhd_SSTR_LEN(MHD_HTTP_VERSION_1_1_STR))
+#define HTTP_VER_LEN (mhd_SSTR_LEN (MHD_HTTP_VERSION_1_1_STR))
+
+
+/**
+ * Detect standard HTTP request method
+ *
+ * @param connection the connection
+ * @param method the pointer to HTTP request method string
+ * @param len the length of @a method in bytes
+ */
+static MHD_FN_PAR_NONNULL_ALL_
+MHD_FN_PAR_IN_SIZE_ (3,2) void
+parse_http_std_method (struct MHD_Connection *restrict connection,
+ size_t len,
+ const char *restrict method)
+{
+ const char *const m = method; /**< short alias */
+ mhd_assert (NULL != m);
+ mhd_assert (0 != len);
+
+ if ((mhd_SSTR_LEN (MHD_HTTP_METHOD_STR_GET) == len) &&
+ (0 == memcmp (m, MHD_HTTP_METHOD_STR_GET, len)))
+ connection->rq.http_mthd = mhd_HTTP_METHOD_GET;
+ else if ((mhd_SSTR_LEN (MHD_HTTP_METHOD_STR_HEAD) == len) &&
+ (0 == memcmp (m, MHD_HTTP_METHOD_STR_HEAD, len)))
+ connection->rq.http_mthd = mhd_HTTP_METHOD_HEAD;
+ else if ((mhd_SSTR_LEN (MHD_HTTP_METHOD_STR_POST) == len) &&
+ (0 == memcmp (m, MHD_HTTP_METHOD_STR_POST, len)))
+ connection->rq.http_mthd = mhd_HTTP_METHOD_POST;
+ else if ((mhd_SSTR_LEN (MHD_HTTP_METHOD_STR_PUT) == len) &&
+ (0 == memcmp (m, MHD_HTTP_METHOD_STR_PUT, len)))
+ connection->rq.http_mthd = mhd_HTTP_METHOD_PUT;
+ else if ((mhd_SSTR_LEN (MHD_HTTP_METHOD_STR_DELETE) == len) &&
+ (0 == memcmp (m, MHD_HTTP_METHOD_STR_DELETE, len)))
+ connection->rq.http_mthd = mhd_HTTP_METHOD_DELETE;
+ else if ((mhd_SSTR_LEN (MHD_HTTP_METHOD_STR_CONNECT) == len) &&
+ (0 == memcmp (m, MHD_HTTP_METHOD_STR_CONNECT, len)))
+ connection->rq.http_mthd = mhd_HTTP_METHOD_CONNECT;
+ else if ((mhd_SSTR_LEN (MHD_HTTP_METHOD_STR_OPTIONS) == len) &&
+ (0 == memcmp (m, MHD_HTTP_METHOD_STR_OPTIONS, len)))
+ connection->rq.http_mthd = mhd_HTTP_METHOD_OPTIONS;
+ else if ((mhd_SSTR_LEN (MHD_HTTP_METHOD_STR_TRACE) == len) &&
+ (0 == memcmp (m, MHD_HTTP_METHOD_STR_TRACE, len)))
+ connection->rq.http_mthd = mhd_HTTP_METHOD_TRACE;
+ else if ((mhd_SSTR_LEN (MHD_HTTP_METHOD_STR_ASTERISK) == len) &&
+ (0 == memcmp (m, MHD_HTTP_METHOD_STR_ASTERISK, len)))
+ connection->rq.http_mthd = mhd_HTTP_METHOD_ASTERISK;
+ else
+ connection->rq.http_mthd = mhd_HTTP_METHOD_OTHER;
+}
+
/**
* Detect HTTP version, send error response if version is not supported
@@ -292,9 +445,9 @@ parse_http_version (struct MHD_Connection *restrict
connection,
|| ('.' != h[6]))
{
connection->rq.http_ver = MHD_HTTP_VERSION_INVALID;
- transmit_error_response_static (connection,
- MHD_HTTP_STATUS_BAD_REQUEST,
- ERR_RSP_REQUEST_MALFORMED);
+ mhd_RESPOND_WITH_ERROR_STATIC (connection,
+ MHD_HTTP_STATUS_BAD_REQUEST,
+ ERR_RSP_REQUEST_MALFORMED);
return false;
}
if (1 == h[5] - '0')
@@ -318,20 +471,19 @@ parse_http_version (struct MHD_Connection *restrict
connection,
{
/* Too old major version */
connection->rq.http_ver = MHD_HTTP_VERSION_INVALID;
- transmit_error_response_static (connection,
- MHD_HTTP_STATUS_HTTP_VERSION_NOT_SUPPORTED,
- ERR_RSP_REQ_HTTP_VER_IS_TOO_OLD);
+ mhd_RESPOND_WITH_ERROR_STATIC (connection,
+ MHD_HTTP_STATUS_HTTP_VERSION_NOT_SUPPORTED,
+ ERR_RSP_REQ_HTTP_VER_IS_TOO_OLD);
return false;
}
- else if ((2 == h[5] - '0') &&
- (('0' > h[7]) || ('9' < h[7])))
+ else if ((2 == h[5] - '0') && ('0' == h[7] - '0'))
connection->rq.http_ver = MHD_HTTP_VERSION_2;
else
connection->rq.http_ver = MHD_HTTP_VERSION_INVALID;
- transmit_error_response_static (connection,
- MHD_HTTP_STATUS_HTTP_VERSION_NOT_SUPPORTED,
- ERR_RSP_REQ_HTTP_VER_IS_NOT_SUPPORTED);
+ mhd_RESPOND_WITH_ERROR_STATIC (connection,
+ MHD_HTTP_STATUS_HTTP_VERSION_NOT_SUPPORTED,
+ ERR_RSP_REQ_HTTP_VER_IS_NOT_SUPPORTED);
return false;
}
@@ -341,7 +493,7 @@ parse_http_version (struct MHD_Connection *restrict
connection,
* The maximum number of ignored empty line before the request line
* at default "strictness" level.
*/
-#define MHD_MAX_EMPTY_LINES_SKIP 1024
+# define MHD_MAX_EMPTY_LINES_SKIP 1024
#endif /* ! MHD_MAX_EMPTY_LINES_SKIP */
@@ -353,7 +505,7 @@ parse_http_version (struct MHD_Connection *restrict
connection,
* false if not enough data yet in the receive buffer
*/
static MHD_FN_PAR_NONNULL_ALL_ bool
-mhd_get_request_line_inner (struct MHD_Connection *restrict c)
+get_request_line_inner (struct MHD_Connection *restrict c)
{
size_t p; /**< The current processing position */
const int discp_lvl = c->daemon->req_cfg.strictnees;
@@ -457,9 +609,9 @@ mhd_get_request_line_inner (struct MHD_Connection *restrict
c)
MHD_MAX_EMPTY_LINES_SKIP : 1)) <
c->rq.hdrs.rq_line.skipped_empty_lines))
{
- connection_close_error (c,
- _ ("Too many meaningless extra empty lines "
\
- "received before the request"));
+ mhd_STREAM_ABORT (c, mhd_STREAM_ABORT_CLIENT_HTTP_ERR,
+ "Too many meaningless extra empty lines " \
+ "received before the request.");
return true; /* Process connection closure */
}
if (0 == c->read_buffer_offset)
@@ -528,14 +680,15 @@ mhd_get_request_line_inner (struct MHD_Connection
*restrict c)
if ((mhd_HTTP_METHOD_GET <= c->rq.http_mthd) &&
(mhd_HTTP_METHOD_DELETE >= c->rq.http_mthd))
{
- transmit_error_response_static (c,
- MHD_HTTP_STATUS_BAD_REQUEST,
- ERR_RSP_BARE_CR_IN_HEADER);
+ mhd_RESPOND_WITH_ERROR_STATIC (c,
+ MHD_HTTP_STATUS_BAD_REQUEST,
+ ERR_RSP_BARE_CR_IN_HEADER);
}
else
- connection_close_error (c,
- _ ("Bare CR characters are not allowed " \
- "in the request line.\n"));
+ mhd_STREAM_ABORT (c, mhd_STREAM_ABORT_CLIENT_HTTP_ERR,
+ "Bare CR characters are not allowed " \
+ "in the request line.");
+
return true; /* Error in the request */
}
}
@@ -555,14 +708,14 @@ mhd_get_request_line_inner (struct MHD_Connection
*restrict c)
if ((mhd_HTTP_METHOD_GET <= c->rq.http_mthd) &&
(mhd_HTTP_METHOD_DELETE >= c->rq.http_mthd))
{
- transmit_error_response_static (c,
- MHD_HTTP_STATUS_BAD_REQUEST,
- ERR_RSP_BARE_LF_IN_HEADER);
+ mhd_RESPOND_WITH_ERROR_STATIC (c,
+ MHD_HTTP_STATUS_BAD_REQUEST,
+ ERR_RSP_BARE_LF_IN_HEADER);
}
else
- connection_close_error (c,
- _ ("Bare LF characters are not allowed " \
- "in the request line.\n"));
+ mhd_STREAM_ABORT (c, mhd_STREAM_ABORT_CLIENT_HTTP_ERR,
+ "Bare LF characters are not allowed " \
+ "in the request line.");
return true; /* Error in the request */
}
}
@@ -620,8 +773,8 @@ mhd_get_request_line_inner (struct MHD_Connection *restrict
c)
&& (HTTP_VER_LEN == p - (size_t) (c->rq.hdrs.rq_line.rq_tgt
- read_buffer))
&& (0 != read_buffer[(size_t)
- (c->rq.hdrs.rq_line.rq_tgt
- - read_buffer) - 1]))
+ (c->rq.hdrs.rq_line.rq_tgt
+ - read_buffer) - 1]))
{
/* Found only HTTP method and HTTP version and more than one
whitespace between them. Assume zero-length URI. */
@@ -680,13 +833,13 @@ mhd_get_request_line_inner (struct MHD_Connection
*restrict c)
if ((mhd_HTTP_METHOD_GET <= c->rq.http_mthd) &&
(mhd_HTTP_METHOD_DELETE >= c->rq.http_mthd))
{
- transmit_error_response_static (c,
- MHD_HTTP_STATUS_BAD_REQUEST,
- ERR_RSP_REQUEST_MALFORMED);
+ mhd_RESPOND_WITH_ERROR_STATIC (c,
+ MHD_HTTP_STATUS_BAD_REQUEST,
+ ERR_RSP_REQUEST_MALFORMED);
}
else
- connection_close_error (c,
- _ ("The request line is malformed.\n"));
+ mhd_STREAM_ABORT (c, mhd_STREAM_ABORT_CLIENT_HTTP_ERR,
+ "The request line is malformed.");
return true;
}
@@ -748,14 +901,13 @@ mhd_get_request_line_inner (struct MHD_Connection
*restrict c)
mhd_assert (NULL == c->rq.version);
if (0 == p)
{
- connection_close_error (c,
- _ ("The request line starts with "
- "a whitespace.\n"));
+ mhd_STREAM_ABORT (c, mhd_STREAM_ABORT_CLIENT_HTTP_ERR,
+ "The request line starts with a whitespace.");
return true; /* Error in the request */
}
read_buffer[p] = 0; /* Zero-terminate the request method string */
c->rq.method = read_buffer;
- parse_http_std_method (c, c->rq.method, p);
+ parse_http_std_method (c, p, c->rq.method);
}
else
{
@@ -781,14 +933,14 @@ mhd_get_request_line_inner (struct MHD_Connection
*restrict c)
if ((mhd_HTTP_METHOD_GET <= c->rq.http_mthd) &&
(mhd_HTTP_METHOD_DELETE >= c->rq.http_mthd))
{
- transmit_error_response_static (c,
- MHD_HTTP_STATUS_BAD_REQUEST,
- ERR_RSP_RQ_LINE_TOO_MANY_WSP);
+ mhd_RESPOND_WITH_ERROR_STATIC (c,
+ MHD_HTTP_STATUS_BAD_REQUEST,
+ ERR_RSP_RQ_LINE_TOO_MANY_WSP);
}
else
- connection_close_error (c,
- _ ("The request line has more than "
- "two whitespaces.\n"));
+ mhd_STREAM_ABORT (c, mhd_STREAM_ABORT_CLIENT_HTTP_ERR,
+ "The request line has more than "
+ "two whitespaces.");
return true; /* Error in the request */
}
}
@@ -875,18 +1027,16 @@ mhd_get_request_line_inner (struct MHD_Connection
*restrict c)
}
else
{
- connection_close_error (c,
- _ ("Invalid character is in the "
- "request line.\n"));
+ mhd_STREAM_ABORT (c, mhd_STREAM_ABORT_CLIENT_HTTP_ERR,
+ "Invalid character is in the request line.");
return true; /* Error in the request */
}
}
else if (0 == chr)
{
/* NUL character */
- connection_close_error (c,
- _ ("The NUL character is in the "
- "request line.\n"));
+ mhd_STREAM_ABORT (c, mhd_STREAM_ABORT_CLIENT_HTTP_ERR,
+ "The NUL character is in the request line.");
return true; /* Error in the request */
}
}
@@ -898,8 +1048,294 @@ mhd_get_request_line_inner (struct MHD_Connection
*restrict c)
return false; /* Not enough data yet */
}
+
+/**
+ * Callback for iterating over GET parameters
+ * @param cls the iterator metadata
+ * @param name the name of the parameter
+ * @param value the value of the parameter
+ * @return bool to continue iterations,
+ * false to stop the iteration
+ */
+static MHD_FN_PAR_NONNULL_ (2) MHD_FN_PAR_NONNULL_ (3) bool
+request_add_get_arg (void *restrict cls,
+ const struct MHD_String *restrict name,
+ const struct MHD_StringNullable *restrict value)
+{
+ struct MHD_Connection *c = (struct MHD_Connection *) cls;
+
+ return mhd_stream_add_field_nullable (c, MHD_VK_GET_ARGUMENT, name, value);
+}
+
+
+MHD_INTERNAL
+MHD_FN_PAR_NONNULL_ (2) MHD_FN_PAR_CSTR_ (2)
+MHD_FN_PAR_INOUT_ (2) bool
+// TODO: detect and report errors
+mhd_parse_get_args (size_t args_len,
+ char *restrict args,
+ mhd_GetArgumentInter cb,
+ void *restrict cls)
+{
+ size_t i;
+
+ mhd_assert (args_len < (size_t) (args_len + 1)); /* Does not work when
args_len == SIZE_MAX */
+
+ for (i = 0; i < args_len; ++i) /* Looking for names of the parameters */
+ {
+ size_t name_start;
+ size_t name_len;
+ size_t value_start;
+ size_t value_len;
+ struct MHD_String name;
+ struct MHD_StringNullable value;
+
+ /* Found start of the name */
+
+ value_start = 0;
+ for (name_start = i; i < args_len; ++i) /* Processing parameter */
+ {
+ if ('+' == args[i])
+ args[i] = ' ';
+ else if ('=' == args[i])
+ {
+ /* Found start of the value */
+ args[i] = 0; /* zero-terminate the name */
+ for (value_start = ++i; i < args_len; ++i) /* Processing parameter
value */
+ {
+ if ('+' == args[i])
+ args[i] = ' ';
+ else if ('&' == args[i]) /* delimiter for the next parameter */
+ break;
+ }
+ if (i < args_len)
+ args[i] = 0;
+ mhd_assert (0 == args[i]);
+ break; /* End if the parameter */
+ }
+ }
+
+ /* Store found parameter */
+
+ if (0 != value_start) /* Value cannot start at zero position */
+ { /* Name with value */
+ mhd_assert (name_start + 2 <= value_start);
+ name_len = value_start - name_start - 2;
+
+ value_len = mhd_str_pct_decode_lenient_n (args + value_start, value_len,
+ args + value_start, value_len,
+ NULL); // TODO: add support
for broken encoding detection
+ value.cstr = args + value_start;
+ value.len = value_len;
+ }
+ else
+ { /* Name without value */
+ name_len = i - name_start;
+
+ value.cstr = NULL;
+ value.len = 0;
+ }
+ name_len = mhd_str_pct_decode_lenient_n (args + name_start, name_len,
+ args + name_start, name_len,
+ NULL); // TODO: add support for
broken encoding detection
+ name.cstr = args + name_start;
+ name.len = name_len;
+ if (! cb (cls, &name, &value))
+ return false;
+ }
+ return true;
+}
+
+
+/**
+ * Process request-target string, form URI and URI parameters
+ * @param c the connection to process
+ * @return true if request-target successfully processed,
+ * false if error encountered
+ */
+static MHD_FN_PAR_NONNULL_ALL_ bool
+process_request_target (struct MHD_Connection *c)
+{
+#ifdef _DEBUG
+ size_t params_len;
+#endif /* _DEBUG */
+ mhd_assert (MHD_CONNECTION_REQ_LINE_RECEIVING == c->state);
+ mhd_assert (NULL == c->rq.url);
+ mhd_assert (0 == c->rq.url_len);
+ mhd_assert (NULL != c->rq.hdrs.rq_line.rq_tgt);
+ mhd_assert ((NULL == c->rq.hdrs.rq_line.rq_tgt_qmark) || \
+ (c->rq.hdrs.rq_line.rq_tgt <= c->rq.hdrs.rq_line.rq_tgt_qmark));
+ mhd_assert ((NULL == c->rq.hdrs.rq_line.rq_tgt_qmark) || \
+ (c->rq.req_target_len > \
+ (size_t) (c->rq.hdrs.rq_line.rq_tgt_qmark \
+ - c->rq.hdrs.rq_line.rq_tgt)));
+
+ /* Log callback before the request-target is modified/decoded */
+ if (NULL != c->daemon->req_cfg.uri_cb.cb)
+ {
+ struct MHD_String full_uri;
+ full_uri.cstr = c->rq.hdrs.rq_line.rq_tgt;
+ full_uri.len = c->rq.req_target_len;
+ c->rq.client_aware = true;
+ c->daemon->req_cfg.uri_cb.cb (c->daemon->req_cfg.uri_cb.cls,
+ &(c->rq),
+ &full_uri);
+ }
+
+ if (NULL != c->rq.hdrs.rq_line.rq_tgt_qmark)
+ {
+ params_len =
+ c->rq.req_target_len
+ - (size_t) (c->rq.hdrs.rq_line.rq_tgt_qmark - c->rq.hdrs.rq_line.rq_tgt);
+
+ mhd_assert (1 <= params_len);
+
+ c->rq.hdrs.rq_line.rq_tgt_qmark[0] = 0; /* Replace '?' with zero
termination */
+
+ // TODO: support detection of decoding errors
+ if (! mhd_parse_get_args (params_len - 1,
+ c->rq.hdrs.rq_line.rq_tgt_qmark + 1,
+ &request_add_get_arg,
+ c))
+ {
+ MHD_LOG_MSG (c->daemon, MHD_SC_CONNECTION_POOL_NO_MEM_GET_PARAM,
+ "Not enough memory in the pool to store GET parameter");
+
+ mhd_RESPOND_WITH_ERROR_STATIC (
+ c,
+ mhd_stream_get_no_space_err_status_code (c,MHD_PROC_RECV_URI, 0, NULL),
+ ERR_RSP_MSG_REQUEST_TOO_BIG);
+ mhd_assert (MHD_CONNECTION_REQ_LINE_RECEIVING != c->state);
+ return false;
+
+ }
+ }
+ else
+ params_len = 0;
+
+ mhd_assert (strlen (c->rq.hdrs.rq_line.rq_tgt) == \
+ c->rq.req_target_len - params_len);
+
+ /* Finally unescape URI itself */
+ // TODO: support detection of decoding errors
+ c->rq.url_len =
+ mhd_str_pct_decode_lenient_n (c->rq.hdrs.rq_line.rq_tgt,
+ c->rq.req_target_len - params_len,
+ c->rq.hdrs.rq_line.rq_tgt,
+ c->rq.req_target_len - params_len,
+ NULL);
+ c->rq.url = c->rq.hdrs.rq_line.rq_tgt;
+
+ return true;
+}
+
+
+#ifndef MHD_MAX_FIXED_URI_LEN
+/**
+ * The maximum size of the fixed URI for automatic redirection
+ */
+#define MHD_MAX_FIXED_URI_LEN (64 * 1024)
+#endif /* ! MHD_MAX_FIXED_URI_LEN */
+
+/**
+ * Send the automatic redirection to fixed URI when received URI with
+ * whitespaces.
+ * If URI is too large, close connection with error.
+ *
+ * @param c the connection to process
+ */
+static void
+send_redirect_fixed_rq_target (struct MHD_Connection *restrict c)
+{
+ char *b;
+ size_t fixed_uri_len;
+ size_t i;
+ size_t o;
+ char *hdr_name;
+ size_t hdr_name_len;
+
+ mhd_assert (MHD_CONNECTION_REQ_LINE_RECEIVING == c->state);
+ mhd_assert (0 != c->rq.hdrs.rq_line.num_ws_in_uri);
+ mhd_assert (c->rq.hdrs.rq_line.num_ws_in_uri <= \
+ c->rq.req_target_len);
+ fixed_uri_len = c->rq.req_target_len
+ + 2 * c->rq.hdrs.rq_line.num_ws_in_uri;
+ if ( (fixed_uri_len + 200 > c->daemon->conns.cfg.mem_pool_size) ||
+ (fixed_uri_len > MHD_MAX_FIXED_URI_LEN) ||
+ (NULL == (b = malloc (fixed_uri_len + 1))) )
+ {
+ mhd_STREAM_ABORT (c, mhd_STREAM_ABORT_CLIENT_HTTP_ERR, \
+ "The request has whitespace character is " \
+ "in the URI and the URI is too large to " \
+ "send automatic redirect to fixed URI.");
+ return;
+ }
+ i = 0;
+ o = 0;
+
+ do
+ {
+ const char chr = c->rq.hdrs.rq_line.rq_tgt[i++];
+
+ mhd_assert ('\r' != chr); /* Replaced during request line parsing */
+ mhd_assert ('\n' != chr); /* Rejected during request line parsing */
+ mhd_assert (0 != chr); /* Rejected during request line parsing */
+ switch (chr)
+ {
+ case ' ':
+ b[o++] = '%';
+ b[o++] = '2';
+ b[o++] = '0';
+ break;
+ case '\t':
+ b[o++] = '%';
+ b[o++] = '0';
+ b[o++] = '9';
+ break;
+ case 0x0B: /* VT (vertical tab) */
+ b[o++] = '%';
+ b[o++] = '0';
+ b[o++] = 'B';
+ break;
+ case 0x0C: /* FF (form feed) */
+ b[o++] = '%';
+ b[o++] = '0';
+ b[o++] = 'C';
+ break;
+ default:
+ b[o++] = chr;
+ break;
+ }
+ } while (i < c->rq.req_target_len);
+ mhd_assert (fixed_uri_len == o);
+ b[o] = 0; /* Zero-terminate the result */
+
+ hdr_name_len = mhd_SSTR_LEN (MHD_HTTP_HEADER_LOCATION);
+ hdr_name = malloc (hdr_name_len + 1);
+ if (NULL != hdr_name)
+ {
+ memcpy (hdr_name,
+ MHD_HTTP_HEADER_LOCATION,
+ hdr_name_len + 1);
+ /* hdr_name and b are free()d within this call */
+ mhd_RESPOND_WITH_ERROR_HEADER (c,
+ MHD_HTTP_STATUS_MOVED_PERMANENTLY,
+ ERR_RSP_RQ_TARGET_INVALID_CHAR,
+ hdr_name_len,
+ hdr_name,
+ o,
+ b);
+ return;
+ }
+ free (b);
+ mhd_STREAM_ABORT (c, mhd_STREAM_ABORT_CLIENT_HTTP_ERR,
+ "The request has whitespace character is in the URI.");
+ return;
+}
+
+
MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_ bool
-mhd_get_request_line (struct MHD_Connection *restrict c)
+mhd_stream_get_request_line (struct MHD_Connection *restrict c)
{
const int discp_lvl = c->daemon->req_cfg.strictnees;
/* Parse whitespace in URI, special parsing of the request line */
@@ -918,9 +1354,9 @@ mhd_get_request_line (struct MHD_Connection *restrict c)
- (size_t) (c->rq.version - c->read_buffer))))
{
c->rq.http_ver = MHD_HTTP_VERSION_INVALID;
- transmit_error_response_static (c,
- MHD_HTTP_STATUS_BAD_REQUEST,
- ERR_RSP_REQUEST_MALFORMED);
+ mhd_RESPOND_WITH_ERROR_STATIC (c,
+ MHD_HTTP_STATUS_BAD_REQUEST,
+ ERR_RSP_REQUEST_MALFORMED);
return true; /* Error in the request */
}
return false;
@@ -936,9 +1372,9 @@ mhd_get_request_line (struct MHD_Connection *restrict c)
{
if (! wsp_in_uri)
{
- transmit_error_response_static (c,
- MHD_HTTP_STATUS_BAD_REQUEST,
- ERR_RSP_RQ_TARGET_INVALID_CHAR);
+ mhd_RESPOND_WITH_ERROR_STATIC (c,
+ MHD_HTTP_STATUS_BAD_REQUEST,
+ ERR_RSP_RQ_TARGET_INVALID_CHAR);
return true; /* Error in the request */
}
if (! wsp_in_uri_keep)
@@ -956,13 +1392,14 @@ mhd_get_request_line (struct MHD_Connection *restrict c)
MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_ void
-mhd_switch_to_rq_headers_processing (struct MHD_Connection *restrict c)
+mhd_stream_switch_to_rq_headers_proc (struct MHD_Connection *restrict c)
{
c->rq.field_lines.start = c->read_buffer;
- memset (&c->rq.hdrs.hdr, 0, sizeof(c->rq.hdrs.hdr));
+ mhd_stream_reset_rq_hdr_proc_state (c);
c->state = MHD_CONNECTION_REQ_HEADERS_RECEIVING;
}
+
/**
* Send error reply when receive buffer space exhausted while receiving or
* storing the request headers
@@ -973,27 +1410,55 @@ mhd_switch_to_rq_headers_processing (struct
MHD_Connection *restrict c)
* Can be NULL.
* @param add_header_size the size of the @a add_header
*/
-static void
+MHD_static_inline_
+MHD_FN_PAR_NONNULL_ (1) void
handle_req_headers_no_space (struct MHD_Connection *restrict c,
const char *restrict add_header,
size_t add_header_size)
{
unsigned int err_code;
- err_code = get_no_space_err_status_code (c,
- MHD_PROC_RECV_HEADERS,
- add_header,
- add_header_size);
- transmit_error_response_static (c,
- err_code,
- ERR_RSP_REQUEST_HEADER_TOO_BIG);
+ err_code = mhd_stream_get_no_space_err_status_code (c,
+ MHD_PROC_RECV_HEADERS,
+ add_header_size,
+ add_header);
+ mhd_RESPOND_WITH_ERROR_STATIC (c,
+ err_code,
+ ERR_RSP_REQUEST_HEADER_TOO_BIG);
+}
+
+
+/**
+ * Send error reply when receive buffer space exhausted while receiving or
+ * storing the request footers (for chunked requests).
+ * @param c the connection to handle
+ * @param add_footer the optional pointer to the current footer string being
+ * processed or the footer failed to be added.
+ * Could be not zero-terminated and can contain binary zeros.
+ * Can be NULL.
+ * @param add_footer_size the size of the @a add_footer
+ */
+MHD_static_inline_
+MHD_FN_PAR_NONNULL_ (1) void
+handle_req_footers_no_space (struct MHD_Connection *restrict c,
+ const char *restrict add_footer,
+ size_t add_footer_size)
+{
+ (void) add_footer; (void) add_footer_size; /* Unused */
+ mhd_assert (c->rq.have_chunked_upload);
+
+ /* Footers should be optional */
+ mhd_RESPOND_WITH_ERROR_STATIC (
+ c,
+ MHD_HTTP_STATUS_REQUEST_HEADER_FIELDS_TOO_LARGE,
+ ERR_RSP_REQUEST_FOOTER_TOO_BIG);
}
/**
* Results of header line reading
*/
-enum mhd_HdrLineReadRes
+enum MHD_FIXED_ENUM_ mhd_HdrLineReadRes
{
/**
* Not enough data yet
@@ -1011,7 +1476,7 @@ enum mhd_HdrLineReadRes
* Found the end of the request header (end of field lines)
*/
MHD_HDR_LINE_READING_GOT_END_OF_HEADER
-} _MHD_FIXED_ENUM;
+};
/**
@@ -1022,10 +1487,9 @@ enum mhd_HdrLineReadRes
* if false then headers are processed
* @param[out] hdr_name the name of the parsed header (field)
* @param[out] hdr_name the value of the parsed header (field)
- * @return true if request header line completely processed,
- * false if not enough data yet in the receive buffer
+ * @return mhd_HdrLineReadRes value
*/
-static enum MHD_HdrLineReadRes_
+static enum mhd_HdrLineReadRes
get_req_header (struct MHD_Connection *restrict c,
bool process_footers,
struct MHD_String *restrict hdr_name,
@@ -1133,13 +1597,13 @@ get_req_header (struct MHD_Connection *restrict c,
else if (! bare_cr_keep)
{
if (! process_footers)
- transmit_error_response_static (c,
- MHD_HTTP_STATUS_BAD_REQUEST,
- ERR_RSP_BARE_CR_IN_HEADER);
+ mhd_RESPOND_WITH_ERROR_STATIC (c,
+ MHD_HTTP_STATUS_BAD_REQUEST,
+ ERR_RSP_BARE_CR_IN_HEADER);
else
- transmit_error_response_static (c,
- MHD_HTTP_STATUS_BAD_REQUEST,
- ERR_RSP_BARE_CR_IN_FOOTER);
+ mhd_RESPOND_WITH_ERROR_STATIC (c,
+ MHD_HTTP_STATUS_BAD_REQUEST,
+ ERR_RSP_BARE_CR_IN_FOOTER);
return MHD_HDR_LINE_READING_DATA_ERROR; /* Error in the request */
}
end_of_line = false;
@@ -1162,13 +1626,13 @@ get_req_header (struct MHD_Connection *restrict c,
else
{
if (! process_footers)
- transmit_error_response_static (c,
- MHD_HTTP_STATUS_BAD_REQUEST,
- ERR_RSP_BARE_LF_IN_HEADER);
+ mhd_RESPOND_WITH_ERROR_STATIC (c,
+ MHD_HTTP_STATUS_BAD_REQUEST,
+ ERR_RSP_BARE_LF_IN_HEADER);
else
- transmit_error_response_static (c,
- MHD_HTTP_STATUS_BAD_REQUEST,
- ERR_RSP_BARE_LF_IN_FOOTER);
+ mhd_RESPOND_WITH_ERROR_STATIC (c,
+ MHD_HTTP_STATUS_BAD_REQUEST,
+ ERR_RSP_BARE_LF_IN_FOOTER);
return MHD_HDR_LINE_READING_DATA_ERROR; /* Error in the request */
}
}
@@ -1213,13 +1677,13 @@ get_req_header (struct MHD_Connection *restrict c,
if (! allow_folded)
{
if (! process_footers)
- transmit_error_response_static (c,
- MHD_HTTP_STATUS_BAD_REQUEST,
- ERR_RSP_OBS_FOLD);
+ mhd_RESPOND_WITH_ERROR_STATIC (c,
+ MHD_HTTP_STATUS_BAD_REQUEST,
+ ERR_RSP_OBS_FOLD);
else
- transmit_error_response_static (c,
- MHD_HTTP_STATUS_BAD_REQUEST,
- ERR_RSP_OBS_FOLD_FOOTER);
+ mhd_RESPOND_WITH_ERROR_STATIC (c,
+ MHD_HTTP_STATUS_BAD_REQUEST,
+ ERR_RSP_OBS_FOLD_FOOTER);
return MHD_HDR_LINE_READING_DATA_ERROR; /* Error in the request */
}
@@ -1252,13 +1716,13 @@ get_req_header (struct MHD_Connection *restrict c,
if (! allow_line_without_colon)
{
if (! process_footers)
- transmit_error_response_static (c,
- MHD_HTTP_STATUS_BAD_REQUEST,
- ERR_RSP_HEADER_WITHOUT_COLON);
+ mhd_RESPOND_WITH_ERROR_STATIC (c,
+ MHD_HTTP_STATUS_BAD_REQUEST,
+ ERR_RSP_HEADER_WITHOUT_COLON);
else
- transmit_error_response_static (c,
- MHD_HTTP_STATUS_BAD_REQUEST,
- ERR_RSP_FOOTER_WITHOUT_COLON);
+ mhd_RESPOND_WITH_ERROR_STATIC (c,
+ MHD_HTTP_STATUS_BAD_REQUEST,
+ ERR_RSP_FOOTER_WITHOUT_COLON);
return MHD_HDR_LINE_READING_DATA_ERROR; /* Error in the request */
}
@@ -1325,13 +1789,13 @@ get_req_header (struct MHD_Connection *restrict c,
if (! allow_wsp_at_start)
{
if (! process_footers)
- transmit_error_response_static (c,
- MHD_HTTP_STATUS_BAD_REQUEST,
- ERR_RSP_WSP_BEFORE_HEADER);
+ mhd_RESPOND_WITH_ERROR_STATIC (c,
+ MHD_HTTP_STATUS_BAD_REQUEST,
+ ERR_RSP_WSP_BEFORE_HEADER);
else
- transmit_error_response_static (c,
- MHD_HTTP_STATUS_BAD_REQUEST,
- ERR_RSP_WSP_BEFORE_FOOTER);
+ mhd_RESPOND_WITH_ERROR_STATIC (c,
+ MHD_HTTP_STATUS_BAD_REQUEST,
+ ERR_RSP_WSP_BEFORE_FOOTER);
return MHD_HDR_LINE_READING_DATA_ERROR; /* Error in the request */
}
c->rq.hdrs.hdr.starts_with_ws = true;
@@ -1348,13 +1812,13 @@ get_req_header (struct MHD_Connection *restrict c,
else
{
if (! process_footers)
- transmit_error_response_static (c,
- MHD_HTTP_STATUS_BAD_REQUEST,
- ERR_RSP_WSP_IN_HEADER_NAME);
+ mhd_RESPOND_WITH_ERROR_STATIC (c,
+ MHD_HTTP_STATUS_BAD_REQUEST,
+ ERR_RSP_WSP_IN_HEADER_NAME);
else
- transmit_error_response_static (c,
- MHD_HTTP_STATUS_BAD_REQUEST,
- ERR_RSP_WSP_IN_FOOTER_NAME);
+ mhd_RESPOND_WITH_ERROR_STATIC (c,
+ MHD_HTTP_STATUS_BAD_REQUEST,
+ ERR_RSP_WSP_IN_FOOTER_NAME);
return MHD_HDR_LINE_READING_DATA_ERROR; /* Error in the request */
}
@@ -1371,13 +1835,13 @@ get_req_header (struct MHD_Connection *restrict c,
if (! nul_as_sp)
{
if (! process_footers)
- transmit_error_response_static (c,
- MHD_HTTP_STATUS_BAD_REQUEST,
- ERR_RSP_INVALID_CHR_IN_HEADER);
+ mhd_RESPOND_WITH_ERROR_STATIC (c,
+ MHD_HTTP_STATUS_BAD_REQUEST,
+ ERR_RSP_INVALID_CHR_IN_HEADER);
else
- transmit_error_response_static (c,
- MHD_HTTP_STATUS_BAD_REQUEST,
- ERR_RSP_INVALID_CHR_IN_FOOTER);
+ mhd_RESPOND_WITH_ERROR_STATIC (c,
+ MHD_HTTP_STATUS_BAD_REQUEST,
+ ERR_RSP_INVALID_CHR_IN_FOOTER);
return MHD_HDR_LINE_READING_DATA_ERROR; /* Error in the request */
}
@@ -1404,13 +1868,13 @@ get_req_header (struct MHD_Connection *restrict c,
if (! allow_wsp_before_colon)
{
if (! process_footers)
- transmit_error_response_static (c,
- MHD_HTTP_STATUS_BAD_REQUEST,
- ERR_RSP_WSP_IN_HEADER_NAME);
+ mhd_RESPOND_WITH_ERROR_STATIC (c,
+ MHD_HTTP_STATUS_BAD_REQUEST,
+ ERR_RSP_WSP_IN_HEADER_NAME);
else
- transmit_error_response_static (c,
- MHD_HTTP_STATUS_BAD_REQUEST,
- ERR_RSP_WSP_IN_FOOTER_NAME);
+ mhd_RESPOND_WITH_ERROR_STATIC (c,
+ MHD_HTTP_STATUS_BAD_REQUEST,
+ ERR_RSP_WSP_IN_FOOTER_NAME);
return MHD_HDR_LINE_READING_DATA_ERROR; /* Error in the request
*/
}
c->rq.hdrs.hdr.name_len = c->rq.hdrs.hdr.ws_start;
@@ -1421,13 +1885,13 @@ get_req_header (struct MHD_Connection *restrict c,
if ((0 == c->rq.hdrs.hdr.name_len) && ! allow_empty_name)
{
if (! process_footers)
- transmit_error_response_static (c,
- MHD_HTTP_STATUS_BAD_REQUEST,
- ERR_RSP_EMPTY_HEADER_NAME);
+ mhd_RESPOND_WITH_ERROR_STATIC (c,
+ MHD_HTTP_STATUS_BAD_REQUEST,
+ ERR_RSP_EMPTY_HEADER_NAME);
else
- transmit_error_response_static (c,
- MHD_HTTP_STATUS_BAD_REQUEST,
- ERR_RSP_EMPTY_FOOTER_NAME);
+ mhd_RESPOND_WITH_ERROR_STATIC (c,
+ MHD_HTTP_STATUS_BAD_REQUEST,
+ ERR_RSP_EMPTY_FOOTER_NAME);
return MHD_HDR_LINE_READING_DATA_ERROR; /* Error in the request */
}
c->rq.hdrs.hdr.name_end_found = true;
@@ -1442,13 +1906,13 @@ get_req_header (struct MHD_Connection *restrict c,
if (! allow_wsp_in_name)
{
if (! process_footers)
- transmit_error_response_static (c,
- MHD_HTTP_STATUS_BAD_REQUEST,
- ERR_RSP_WSP_IN_HEADER_NAME);
+ mhd_RESPOND_WITH_ERROR_STATIC (c,
+ MHD_HTTP_STATUS_BAD_REQUEST,
+ ERR_RSP_WSP_IN_HEADER_NAME);
else
- transmit_error_response_static (c,
- MHD_HTTP_STATUS_BAD_REQUEST,
- ERR_RSP_WSP_IN_FOOTER_NAME);
+ mhd_RESPOND_WITH_ERROR_STATIC (c,
+ MHD_HTTP_STATUS_BAD_REQUEST,
+ ERR_RSP_WSP_IN_FOOTER_NAME);
return MHD_HDR_LINE_READING_DATA_ERROR; /* Error in the request
*/
}
@@ -1478,8 +1942,23 @@ get_req_header (struct MHD_Connection *restrict c,
}
+/**
+ * Reset request header processing state.
+ *
+ * This function resets the processing state before processing the next header
+ * (or footer) line.
+ * @param c the connection to process
+ */
+MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_ void
+mhd_stream_reset_rq_hdr_proc_state (struct MHD_Connection *c)
+{
+ memset (&c->rq.hdrs.hdr, 0, sizeof(c->rq.hdrs.hdr));
+}
+
+
MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_ bool
-mhd_get_req_headers (struct MHD_Connection *restrict c, bool process_footers)
+mhd_stream_get_request_headers (struct MHD_Connection *restrict c,
+ bool process_footers)
{
do
{
@@ -1530,7 +2009,7 @@ mhd_get_req_headers (struct MHD_Connection *restrict c,
bool process_footers)
mhd_assert (hdr_name.cstr < hdr_value.cstr);
- if (!process_footers)
+ if (! process_footers)
MHD_LOG_MSG (c->daemon, MHD_SC_CONNECTION_POOL_MALLOC_FAILURE_REQ, \
"Failed to allocate memory in the connection memory " \
"pool to store header.");
@@ -1551,7 +2030,7 @@ mhd_get_req_headers (struct MHD_Connection *restrict c,
bool process_footers)
return true;
}
/* Reset processing state */
- reset_rq_header_processing_state (c);
+ mhd_stream_reset_rq_hdr_proc_state (c);
mhd_assert ((process_footers ? MHD_CONNECTION_FOOTERS_RECEIVING : \
MHD_CONNECTION_REQ_HEADERS_RECEIVING) == \
c->state);
@@ -1593,15 +2072,15 @@ mhd_get_req_headers (struct MHD_Connection *restrict c,
bool process_footers)
{
if (! process_footers)
MHD_LOG_PRINT (c->daemon, MHD_SC_REQ_HEADER_CR_REPLACED, \
- MHD_LOG_FMT("%" PRIuFAST64 " bare CR characters have " \
- "been replaced with spaces in the request " \
- "line and/or in the request headers."), \
+ MHD_LOG_FMT ("%" PRIuFAST64 " bare CR characters have " \
+ "been replaced with spaces in the request " \
+ "line and/or in the request headers."), \
(uint_fast64_t) c->rq.num_cr_sp_replaced);
else
MHD_LOG_PRINT (c->daemon, MHD_SC_REQ_HEADER_CR_REPLACED, \
- MHD_LOG_FMT("%" PRIuFAST64 " bare CR characters have " \
- "been replaced with spaces in the request " \
- "footers."), \
+ MHD_LOG_FMT ("%" PRIuFAST64 " bare CR characters have " \
+ "been replaced with spaces in the request " \
+ "footers."), \
(uint_fast64_t) c->rq.num_cr_sp_replaced);
@@ -1619,13 +2098,13 @@ mhd_get_req_headers (struct MHD_Connection *restrict c,
bool process_footers)
{
if (! process_footers)
MHD_LOG_PRINT (c->daemon, MHD_SC_REQ_HEADER_CR_REPLACED, \
- MHD_LOG_FMT("%" PRIu64 " header lines without colons "
- "have been skipped."),
+ MHD_LOG_FMT ("%" PRIu64 " header lines without colons "
+ "have been skipped."),
(uint_fast64_t) c->rq.skipped_broken_lines);
else
MHD_LOG_PRINT (c->daemon, MHD_SC_REQ_HEADER_CR_REPLACED, \
- MHD_LOG_FMT("%" PRIu64 " footer lines without colons "
- "have been skipped."),
+ MHD_LOG_FMT ("%" PRIu64 " footer lines without colons "
+ "have been skipped."),
(uint_fast64_t) c->rq.skipped_broken_lines);
}
@@ -1652,7 +2131,7 @@ mhd_get_req_headers (struct MHD_Connection *restrict c,
bool process_footers)
const char *last_elmnt_end;
size_t shift_back_size;
struct mhd_RequestField *header;
- header = mhd_DLINKEDL_GET_LAST(&(c->rq), fields);
+ header = mhd_DLINKEDL_GET_LAST (&(c->rq), fields);
if (NULL != header)
last_elmnt_end =
header->field.nv.value.cstr + header->field.nv.value.len;
@@ -1701,8 +2180,9 @@ enum _MHD_ParseCookie
* @param connection the connection to add parsed cookies
* @return #MHD_PARSE_COOKIE_OK for success, error code otherwise
*/
-static MHD_FN_PAR_NONNULL_ALL_ MHD_FN_PAR_CSTR_(2)
-MHD_FN_PAR_INOUT_SIZE_(2,1) enum _MHD_ParseCookie
+static MHD_FN_PAR_NONNULL_ALL_
+MHD_FN_PAR_CSTR_ (2)
+MHD_FN_PAR_INOUT_SIZE_ (2,1) enum _MHD_ParseCookie
parse_cookies_string (const size_t str_len,
char *restrict str,
struct MHD_Connection *restrict connection)
@@ -1848,10 +2328,10 @@ parse_cookies_string (const size_t str_len,
str[value_start + value_len] = 0; /* Zero-terminate the value */
value.cstr = str + value_start;
value.len = value_len;
- if (! mhd_stream_add_field(connection,
- MHD_VK_COOKIE,
- &name,
- &value))
+ if (! mhd_stream_add_field (connection,
+ MHD_VK_COOKIE,
+ &name,
+ &value))
return MHD_PARSE_COOKIE_NO_MEMORY;
}
else
@@ -1860,12 +2340,12 @@ parse_cookies_string (const size_t str_len,
struct MHD_String value;
name.cstr = str + name_start;
name.len = name_len;
- value.cstr = ""
+ value.cstr = "";
value.len = 0;
- if (! mhd_stream_add_field(connection,
- MHD_VK_COOKIE,
- &name,
- &value))
+ if (! mhd_stream_add_field (connection,
+ MHD_VK_COOKIE,
+ &name,
+ &value))
return MHD_PARSE_COOKIE_NO_MEMORY;
}
if (str_len > i)
@@ -1911,20 +2391,19 @@ parse_cookies_string (const size_t str_len,
* @return #MHD_PARSE_COOKIE_OK for success, error code otherwise
*/
static enum _MHD_ParseCookie
-parse_cookie_header (struct MHD_Connection *connection)
+parse_cookie_header (struct MHD_Connection *restrict connection)
{
- struct MHD_String *hvalue;
+ const struct MHD_StringNullable *hvalue;
char *cpy;
size_t i;
enum _MHD_ParseCookie parse_res;
struct mhd_RequestField *const saved_tail =
- connection->rq.fields.last;
+ connection->rq.fields.last; // FIXME: a better way?
const bool allow_partially_correct_cookie =
(1 >= connection->daemon->req_cfg.strictnees);
- hvalue = mhd_request_get_value_len(&(connection->rq),
+ hvalue = mhd_request_get_value_st (&(connection->rq),
MHD_VK_HEADER,
- mhd_SSTR_LEN (MHD_HTTP_HEADER_COOKIE),
MHD_HTTP_HEADER_COOKIE);
if (NULL == hvalue)
return MHD_PARSE_COOKIE_OK;
@@ -1938,16 +2417,16 @@ parse_cookie_header (struct MHD_Connection *connection)
else
{
memcpy (cpy,
- hdr,
- hdr_len);
- cpy[hdr_len] = '\0';
+ hvalue->cstr,
+ hvalue->len + 1);
+ mhd_assert (0 == cpy[hvalue->len]);
- i = 0;
- /* Skip all initial whitespaces */
- while (i < hdr_len && (' ' == cpy[i] || '\t' == cpy[i]))
- i++;
+ /* Must not have initial whitespaces */
+ mhd_assert (' ' != cpy[0]);
+ mhd_assert ('\t' != cpy[0]);
- parse_res = parse_cookies_string (cpy + i, hdr_len - i, connection);
+ i = 0;
+ parse_res = parse_cookies_string (hvalue->len - i, cpy + i, connection);
}
switch (parse_res)
@@ -1955,96 +2434,101 @@ parse_cookie_header (struct MHD_Connection *connection)
case MHD_PARSE_COOKIE_OK:
break;
case MHD_PARSE_COOKIE_OK_LAX:
-#ifdef HAVE_MESSAGES
- if (saved_tail != connection->rq.headers_received_tail)
- MHD_DLOG (connection->daemon,
- _ ("The Cookie header has been parsed, but it is not fully "
- "compliant with the standard.\n"));
-#endif /* HAVE_MESSAGES */
+ if (saved_tail != connection->rq.fields.last)
+ MHD_LOG_MSG (connection->daemon, MHD_SC_REQ_COOKIE_PARSED_NOT_COMPLIANT,
\
+ "The Cookie header has been parsed, but it is not "
+ "fully compliant with specifications.");
break;
case MHD_PARSE_COOKIE_MALFORMED:
- if (saved_tail != connection->rq.headers_received_tail)
+ if (saved_tail != connection->rq.fields.last) // FIXME: a better way?
{
if (! allow_partially_correct_cookie)
{
/* Remove extracted values from partially broken cookie */
/* Memory remains allocated until the end of the request processing */
- connection->rq.headers_received_tail = saved_tail;
- saved_tail->next = NULL;
-#ifdef HAVE_MESSAGES
- MHD_DLOG (connection->daemon,
- _ ("The Cookie header has been ignored as it contains "
- "malformed data.\n"));
-#endif /* HAVE_MESSAGES */
+ connection->rq.fields.last = saved_tail; // FIXME: a better way?
+ saved_tail->fields.next = NULL; // FIXME: a better way?
+ MHD_LOG_MSG ( \
+ connection->daemon, MHD_SC_REQ_COOKIE_IGNORED_NOT_COMPLIANT, \
+ "The Cookie header is ignored as it contains malformed data.");
}
-#ifdef HAVE_MESSAGES
else
- MHD_DLOG (connection->daemon,
- _ ("The Cookie header has been only partially parsed as it "
- "contains malformed data.\n"));
-#endif /* HAVE_MESSAGES */
+ MHD_LOG_MSG (connection->daemon, MHD_SC_REQ_COOKIE_PARSED_PARTIALLY, \
+ "The Cookie header has been only partially parsed " \
+ "as it contains malformed data.");
}
-#ifdef HAVE_MESSAGES
else
- MHD_DLOG (connection->daemon,
- _ ("The Cookie header has malformed data.\n"));
-#endif /* HAVE_MESSAGES */
+ MHD_LOG_MSG (connection->daemon, MHD_SC_REQ_COOKIE_INVALID,
+ "The Cookie header has malformed data.");
break;
case MHD_PARSE_COOKIE_NO_MEMORY:
-#ifdef HAVE_MESSAGES
- MHD_DLOG (connection->daemon,
- _ ("Not enough memory in the connection pool to "
- "parse client cookies!\n"));
-#endif /* HAVE_MESSAGES */
+ MHD_LOG_MSG (connection->daemon, MHD_SC_CONNECTION_POOL_NO_MEM_COOKIE,
+ "Not enough memory in the connection pool to "
+ "parse client cookies!\n");
break;
default:
- mhd_assert (0);
+ mhd_assert (0 && "Impossible value");
+ MHD_UNREACHABLE_;
break;
}
-#ifndef HAVE_MESSAGES
- (void) saved_tail; /* Mute compiler warning */
-#endif /* ! HAVE_MESSAGES */
return parse_res;
}
-#endif /* COOKIE_SUPPORT */
+/**
+ * Send error reply when receive buffer space exhausted while receiving or
+ * storing the request headers
+ * @param c the connection to handle
+ * @param add_header the optional pointer to the current header string being
+ * processed or the header failed to be added.
+ * Could be not zero-terminated and can contain binary zeros.
+ * Can be NULL.
+ * @param add_header_size the size of the @a add_header
+ */
+MHD_static_inline_ void
+handle_req_cookie_no_space (struct MHD_Connection *restrict c)
+{
+ unsigned int err_code;
+ err_code = mhd_stream_get_no_space_err_status_code (c,
+ MHD_PROC_RECV_COOKIE,
+ 0,
+ NULL);
+ mhd_RESPOND_WITH_ERROR_STATIC (c,
+ err_code,
+ ERR_RSP_REQUEST_HEADER_TOO_BIG);
+}
+
+
+#endif /* COOKIE_SUPPORT */
MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_ void
-mhd_parse_connection_headers (struct MHD_Connection *restrict c)
+mhd_stream_parse_connection_headers (struct MHD_Connection *restrict c)
{
- const char *clen;
- const char *enc;
- size_t val_len;
+ const struct MHD_StringNullable *hcntnlen;
+ const struct MHD_StringNullable *htrenc;
#ifdef COOKIE_SUPPORT
- if (MHD_PARSE_COOKIE_NO_MEMORY == parse_cookie_header (connection))
+ if (MHD_PARSE_COOKIE_NO_MEMORY == parse_cookie_header (c))
{
- handle_req_cookie_no_space (connection);
+ handle_req_cookie_no_space (c);
return;
}
#endif /* COOKIE_SUPPORT */
- if ( (-3 < connection->daemon->client_discipline) &&
- (MHD_IS_HTTP_VER_1_1_COMPAT (connection->rq.http_ver)) &&
- (MHD_NO ==
- MHD_lookup_connection_value_n (connection,
- MHD_VK_HEADER,
- MHD_HTTP_HEADER_HOST,
- mhd_SSTR_LEN (
- MHD_HTTP_HEADER_HOST),
- NULL,
- NULL)) )
+
+ if ( (-3 < c->daemon->req_cfg.strictnees) &&
+ (MHD_HTTP_VERSION_1_1 == c->rq.http_ver) &&
+ (NULL == mhd_request_get_value_st (&(c->rq),
+ MHD_VK_HEADER,
+ MHD_HTTP_HEADER_HOST)))
{
-#ifdef HAVE_MESSAGES
- MHD_DLOG (connection->daemon,
- _ ("Received HTTP/1.1 request without `Host' header.\n"));
-#endif
- transmit_error_response_static (connection,
- MHD_HTTP_STATUS_BAD_REQUEST,
- REQUEST_LACKS_HOST);
+ MHD_LOG_MSG (c->daemon, MHD_SC_HOST_HEADER_MISSING, \
+ "Received HTTP/1.1 request without 'Host' header.");
+ mhd_RESPOND_WITH_ERROR_STATIC (c,
+ MHD_HTTP_STATUS_BAD_REQUEST,
+ ERR_RSP_REQUEST_LACKS_HOST);
return;
}
@@ -2052,98 +2536,741 @@ mhd_parse_connection_headers (struct MHD_Connection
*restrict c)
"Transfer-Encoding:" request headers.
Unless one of these two headers is used, the request has no request body.
See RFC9112, Section 6, paragraph 4. */
- connection->rq.remaining_upload_size = 0;
- if (MHD_NO !=
- MHD_lookup_connection_value_n (connection,
+ c->rq.cntn.cntn_size = 0;
+ htrenc = mhd_request_get_value_st (&(c->rq),
MHD_VK_HEADER,
- MHD_HTTP_HEADER_TRANSFER_ENCODING,
- mhd_SSTR_LEN (
- MHD_HTTP_HEADER_TRANSFER_ENCODING),
- &enc,
- NULL))
+ MHD_HTTP_HEADER_TRANSFER_ENCODING);
+
+ if (NULL != htrenc)
{
- if (! MHD_str_equal_caseless_ (enc,
- "chunked"))
+ if (! mhd_str_equal_caseless_n_st ("chunked", htrenc->cstr, htrenc->len))
{
- transmit_error_response_static (connection,
- MHD_HTTP_STATUS_BAD_REQUEST,
- REQUEST_UNSUPPORTED_TR_ENCODING);
+ mhd_RESPOND_WITH_ERROR_STATIC (c,
+ MHD_HTTP_STATUS_BAD_REQUEST,
+ ERR_RSP_UNSUPPORTED_TR_ENCODING);
return;
}
- else if (MHD_NO !=
- MHD_lookup_connection_value_n (connection,
- MHD_VK_HEADER,
- MHD_HTTP_HEADER_CONTENT_LENGTH,
- mhd_SSTR_LEN ( \
- MHD_HTTP_HEADER_CONTENT_LENGTH),
- NULL,
- NULL))
+
+ c->rq.have_chunked_upload = true;
+ c->rq.cntn.cntn_size = MHD_SIZE_UNKNOWN;
+
+ if (MHD_HTTP_VERSION_1_1 != c->rq.http_ver)
+ c->keepalive = MHD_CONN_MUST_CLOSE; /* Framing could in incorrect */
+ }
+
+ hcntnlen = mhd_request_get_value_st (&(c->rq),
+ MHD_VK_HEADER,
+ MHD_HTTP_HEADER_CONTENT_LENGTH);
+
+ if ((NULL != hcntnlen) && (NULL != htrenc))
+ {
+ /* TODO: add individual settings */
+ if (1 <= c->daemon->req_cfg.strictnees)
{
- /* TODO: add individual settings */
- if (1 <= connection->daemon->client_discipline)
- {
- transmit_error_response_static (connection,
- MHD_HTTP_STATUS_BAD_REQUEST,
- REQUEST_LENGTH_WITH_TR_ENCODING);
- return;
- }
- else
- {
- /* Must close connection after reply to prevent potential attack */
- connection->keepalive = MHD_CONN_MUST_CLOSE;
-#ifdef HAVE_MESSAGES
- MHD_DLOG (connection->daemon,
- _ ("The 'Content-Length' request header is ignored "
- "as chunked Transfer-Encoding is used "
- "for this request.\n"));
-#endif /* HAVE_MESSAGES */
- }
+ mhd_RESPOND_WITH_ERROR_STATIC (c,
+ MHD_HTTP_STATUS_BAD_REQUEST,
+
ERR_RSP_REQUEST_CNTNLENGTH_WITH_TR_ENCODING);
+ return;
+ }
+ else
+ {
+ /* Must close connection after reply to prevent potential attack */
+ c->keepalive = MHD_CONN_MUST_CLOSE;
+ MHD_LOG_MSG (c->daemon, MHD_SC_CONTENT_LENGTH_AND_TR_ENC, \
+ "The 'Content-Length' request header is ignored " \
+ "as chunked Transfer-Encoding is used " \
+ "for this request.");
}
- connection->rq.have_chunked_upload = true;
- connection->rq.remaining_upload_size = MHD_SIZE_UNKNOWN;
}
- else if (MHD_NO !=
- MHD_lookup_connection_value_n (connection,
- MHD_VK_HEADER,
- MHD_HTTP_HEADER_CONTENT_LENGTH,
- mhd_SSTR_LEN (
- MHD_HTTP_HEADER_CONTENT_LENGTH),
- &clen,
- &val_len))
+ else if (NULL != hcntnlen)
{
size_t num_digits;
- num_digits = MHD_str_to_uint64_n_ (clen,
- val_len,
- &connection->rq.remaining_upload_size);
+ num_digits = mhd_str_to_uint64_n (hcntnlen->cstr,
+ hcntnlen->len,
+ &c->rq.cntn.cntn_size);
if (((0 == num_digits) &&
- (0 != val_len) &&
- ('0' <= clen[0]) && ('9' >= clen[0]))
- || (MHD_SIZE_UNKNOWN == connection->rq.remaining_upload_size))
+ (0 != hcntnlen->len) &&
+ ('0' <= hcntnlen->cstr[0]) && ('9' >= hcntnlen->cstr[0]))
+ || (MHD_SIZE_UNKNOWN == c->rq.cntn.cntn_size))
{
- connection->rq.remaining_upload_size = 0;
-#ifdef HAVE_MESSAGES
- MHD_DLOG (connection->daemon,
- _ ("Too large value of 'Content-Length' header. " \
- "Closing connection.\n"));
-#endif
- transmit_error_response_static (connection,
- MHD_HTTP_STATUS_CONTENT_TOO_LARGE,
- REQUEST_CONTENTLENGTH_TOOLARGE);
+ c->rq.cntn.cntn_size = 0;
+ MHD_LOG_MSG (c->daemon, MHD_SC_CONTENT_LENGTH_TOO_LARGE, \
+ "Too large value of 'Content-Length' header. " \
+ "Closing connection.");
+ mhd_RESPOND_WITH_ERROR_STATIC (c,
+ MHD_HTTP_STATUS_CONTENT_TOO_LARGE,
+ ERR_RSP_REQUEST_CONTENTLENGTH_TOOLARGE);
+ return;
}
- else if ((val_len != num_digits) ||
+ else if ((hcntnlen->len != num_digits) ||
(0 == num_digits))
{
- connection->rq.remaining_upload_size = 0;
-#ifdef HAVE_MESSAGES
- MHD_DLOG (connection->daemon,
- _ ("Failed to parse 'Content-Length' header. " \
- "Closing connection.\n"));
+ c->rq.cntn.cntn_size = 0;
+ MHD_LOG_MSG (c->daemon, MHD_SC_CONTENT_LENGTH_MALFORMED, \
+ "Failed to parse 'Content-Length' header. " \
+ "Closing connection.");
+ mhd_RESPOND_WITH_ERROR_STATIC (c,
+ MHD_HTTP_STATUS_BAD_REQUEST,
+ ERR_RSP_REQUEST_CONTENTLENGTH_MALFORMED);
+ return;
+ }
+ }
+ c->state = MHD_CONNECTION_HEADERS_PROCESSED;
+ return;
+}
+
+
+/**
+ * Is "100 CONTINUE" needed to be sent for current request?
+ *
+ * @param c the connection to check
+ * @return false 100 CONTINUE is not needed,
+ * true otherwise
+ */
+static MHD_FN_PAR_NONNULL_ALL_ bool
+need_100_continue (struct MHD_Connection *restrict c)
+{
+ const struct MHD_StringNullable *hvalue;
+
+ mhd_assert (MHD_HTTP_VERSION_IS_SUPPORTED (c->rq.http_ver));
+ mhd_assert (MHD_CONNECTION_BODY_RECEIVING > c->state);
+
+ if (MHD_HTTP_VERSION_1_0 == c->rq.http_ver)
+ return false;
+
+ if (0 != c->read_buffer_offset)
+ return false; /* Part of the content has been received already */
+
+ hvalue = mhd_request_get_value_st (&(c->rq),
+ MHD_VK_HEADER,
+ MHD_HTTP_HEADER_EXPECT);
+ if (NULL == hvalue)
+ return false;
+
+ if (! mhd_str_equal_caseless_n_st ("100-continue", \
+ hvalue->cstr, hvalue->len))
+ return false;
+
+ return true;
+}
+
+
+/**
+ * Check whether special buffer is required to handle the upload content and
+ * try to allocate if necessary.
+ * Respond with error to the client if buffer cannot be allocated
+ * @param c the connection to
+ * @return true if succeed,
+ * false if error response is set
+ */
+static MHD_FN_PAR_NONNULL_ALL_ bool
+check_and_alloc_buf_for_upload_processing (struct MHD_Connection *restrict c)
+{
+ mhd_assert ((mhd_ACTION_UPLOAD == c->rq.app_act.head_act.act) || \
+ (mhd_ACTION_POST_PROCESS == c->rq.app_act.head_act.act));
+
+ if (c->rq.have_chunked_upload)
+ return true; /* The size is unknown, buffers will be dynamically allocated
+ and re-allocated */
+ mhd_assert (c->read_buffer_size > c->read_buffer_offset);
+#if 0 // TODO: support processing full response in the connection buffer
+ if ((c->read_buffer_size - c->read_buffer_offset) >=
+ c->rq.cntn.cntn_size)
+ return true; /* No additional buffer needed */
#endif
- transmit_error_response_static (connection,
- MHD_HTTP_STATUS_BAD_REQUEST,
- REQUEST_CONTENTLENGTH_MALFORMED);
+
+ if ((mhd_ACTION_UPLOAD == c->rq.app_act.head_act.act) &&
+ (NULL == c->rq.app_act.head_act.data.upload.full.cb))
+ return true; /* data will be processed only incrementally */
+
+ if (mhd_ACTION_UPLOAD != c->rq.app_act.head_act.act)
+ {
+ // TODO: add check for intermental-only POST processing */
+ mhd_assert (0 && "Not implemented yet");
+ return false;
+ }
+
+ if ((c->rq.cntn.cntn_size >
+ c->rq.app_act.head_act.data.upload.large_buffer_size) ||
+ ! mhd_daemon_get_lbuf (c->daemon, c->rq.cntn.cntn_size,
+ &(c->rq.cntn.lbuf)))
+ {
+ if (NULL != c->rq.app_act.head_act.data.upload.inc.cb)
+ {
+ c->rq.app_act.head_act.data.upload.full.cb = NULL;
+ return true; /* Data can be processed incrementally */
}
+
+ mhd_RESPOND_WITH_ERROR_STATIC (c,
+ MHD_HTTP_STATUS_CONTENT_TOO_LARGE,
+ ERR_RSP_REQUEST_CONTENTLENGTH_TOOLARGE);
+ return false;
}
+
+ return true;
+}
+
+
+MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_ bool
+mhd_stream_call_app_request_cb (struct MHD_Connection *restrict c)
+{
+ struct MHD_Daemon *restrict d = c->daemon;
+ struct MHD_String path;
+ const struct MHD_Action *a;
+
+ mhd_assert (mhd_HTTP_METHOD_NO_METHOD != c->rq.http_mthd);
+ mhd_assert (NULL == c->rp.response);
+
+ if (mhd_ACTION_NO_ACTION != c->rq.app_act.head_act.act)
+ MHD_PANIC ("MHD_Action has been set already");
+
+ path.cstr = c->rq.url;
+ path.len = c->rq.url_len;
+
+ c->rq.client_aware = true;
+ a = d->req_cfg.cb (d->req_cfg.cb_cls,
+ &(c->rq),
+ &path,
+ (enum MHD_HTTP_Method) c->rq.http_mthd,
+ c->rq.cntn.cntn_size);
+
+ if (((NULL != a) && (&(c->rq.app_act.head_act) != a)) ||
+ ! mhd_ACTION_IS_VALID (c->rq.app_act.head_act.act))
+ {
+ MHD_LOG_MSG (d, MHD_SC_ACTION_INVALID, \
+ "Provided action is not a correct action generated " \
+ "for the current request.");
+ a = NULL;
+ }
+ if (NULL == a)
+ c->rq.app_act.head_act.act = mhd_ACTION_ABORT;
+
+ switch (c->rq.app_act.head_act.act)
+ {
+ case mhd_ACTION_RESPONSE:
+ c->rp.response = c->rq.app_act.head_act.data.response;
+ c->state = MHD_CONNECTION_REQ_RECV_FINISHED;
+ return true;
+ case mhd_ACTION_UPLOAD:
+ if (0 != c->rq.cntn.cntn_size)
+ {
+ if (! check_and_alloc_buf_for_upload_processing (c))
+ return true;
+ if (need_100_continue (c))
+ {
+ c->state = MHD_CONNECTION_CONTINUE_SENDING;
+ return true;
+ }
+ c->state = MHD_CONNECTION_BODY_RECEIVING;
+ return (0 != c->read_buffer_offset);
+ }
+ c->state = MHD_CONNECTION_FULL_REQ_RECEIVED;
+ return true;
+ case mhd_ACTION_POST_PROCESS:
+ mhd_assert (0 && "Not implemented yet");
+ return true;
+ case mhd_ACTION_SUSPEND:
+ c->suspended = true;
+ return false;
+ case mhd_ACTION_ABORT:
+ mhd_conn_pre_close_app_abort (c);
+ return false;
+ case mhd_ACTION_NO_ACTION:
+ default:
+ mhd_assert (0 && "Impossible value");
+ break;
+ }
+ MHD_UNREACHABLE_;
+ return false;
+}
+
+
+/**
+ * React on provided action for upload
+ * @param c the stream to use
+ * @param act the action provided by application
+ * @param final set to 'true' if this is final upload callback
+ * @return true if connection state has been changed,
+ * false otherwise
+ */
+static MHD_FN_PAR_NONNULL_ (1) bool
+process_upload_action (struct MHD_Connection *restrict c,
+ const struct MHD_UploadAction *act,
+ bool final)
+{
+ if (((NULL != act) && (&(c->rq.app_act.upl_act) != act)) ||
+ ! mhd_UPLOAD_ACTION_IS_VALID (c->rq.app_act.upl_act.act) ||
+ (final &&
+ (mhd_UPLOAD_ACTION_CONTINUE == c->rq.app_act.upl_act.act)))
+ {
+ MHD_LOG_MSG (c->daemon, MHD_SC_UPLOAD_ACTION_INVALID, \
+ "Provided action is not a correct action generated " \
+ "for the current request.");
+ act = NULL;
+ }
+ if (NULL == act)
+ c->rq.app_act.upl_act.act = mhd_UPLOAD_ACTION_ABORT;
+
+ switch (c->rq.app_act.upl_act.act)
+ {
+ case mhd_UPLOAD_ACTION_RESPONSE:
+ c->rp.response = c->rq.app_act.upl_act.data.response;
+ c->state = MHD_CONNECTION_REQ_RECV_FINISHED;
+ return true;
+ case mhd_UPLOAD_ACTION_CONTINUE:
+ memset (&(c->rq.app_act.upl_act), 0, sizeof(c->rq.app_act.upl_act));
+ return false;
+ case mhd_UPLOAD_ACTION_SUSPEND:
+ c->suspended = true;
+ return false;
+ case mhd_UPLOAD_ACTION_ABORT:
+ mhd_conn_pre_close_app_abort (c);
+ return false;
+ case mhd_UPLOAD_ACTION_NO_ACTION:
+ default:
+ mhd_assert (0 && "Impossible value");
+ break;
+ }
+ MHD_UNREACHABLE_;
+ return false;
+}
+
+
+static MHD_FN_PAR_NONNULL_ALL_ bool
+process_request_chunked_body (struct MHD_Connection *restrict c)
+{
+ struct MHD_Daemon *restrict d = c->daemon;
+ size_t available;
+ bool has_more_data;
+ char *restrict buffer_head;
+ const int discp_lvl = d->req_cfg.strictnees;
+ /* Treat bare LF as the end of the line.
+ RFC 9112, section 2.2-3
+ Note: MHD never replaces bare LF with space (RFC 9110, section 5.5-5).
+ Bare LF is processed as end of the line or rejected as broken request. */
+ const bool bare_lf_as_crlf = MHD_ALLOW_BARE_LF_AS_CRLF_ (discp_lvl);
+ /* Allow "Bad WhiteSpace" in chunk extension.
+ RFC 9112, Section 7.1.1, Paragraph 2 */
+ const bool allow_bws = (2 < discp_lvl);
+ bool state_updated;
+
+ mhd_assert (NULL == c->rp.response);
+ mhd_assert (c->rq.have_chunked_upload);
+ mhd_assert (MHD_SIZE_UNKNOWN == c->rq.cntn.cntn_size);
+
+ buffer_head = c->read_buffer;
+ available = c->read_buffer_offset;
+ state_updated = false;
+ do
+ {
+ size_t cntn_data_ready;
+ bool need_inc_proc;
+
+ has_more_data = false;
+
+ if ( (c->rq.current_chunk_offset ==
+ c->rq.current_chunk_size) &&
+ (0 != c->rq.current_chunk_size) )
+ {
+ size_t i;
+ mhd_assert (0 != available);
+ /* skip new line at the *end* of a chunk */
+ i = 0;
+ if ( (2 <= available) &&
+ ('\r' == buffer_head[0]) &&
+ ('\n' == buffer_head[1]) )
+ i += 2; /* skip CRLF */
+ else if (bare_lf_as_crlf && ('\n' == buffer_head[0]))
+ i++; /* skip bare LF */
+ else if (2 > available)
+ break; /* need more upload data */
+ if (0 == i)
+ {
+ /* malformed encoding */
+ mhd_RESPOND_WITH_ERROR_STATIC (c,
+ MHD_HTTP_STATUS_BAD_REQUEST,
+ ERR_RSP_REQUEST_CHUNKED_MALFORMED);
+ return true;
+ }
+ available -= i;
+ buffer_head += i;
+ c->rq.current_chunk_offset = 0;
+ c->rq.current_chunk_size = 0;
+ if (0 == available)
+ break;
+ }
+ if (0 != c->rq.current_chunk_size)
+ {
+ uint_fast64_t cur_chunk_left;
+ mhd_assert (c->rq.current_chunk_offset < \
+ c->rq.current_chunk_size);
+ /* we are in the middle of a chunk, give
+ as much as possible to the client (without
+ crossing chunk boundaries) */
+ cur_chunk_left
+ = c->rq.current_chunk_size
+ - c->rq.current_chunk_offset;
+ if (cur_chunk_left > available)
+ cntn_data_ready = available;
+ else
+ { /* cur_chunk_left <= (size_t)available */
+ cntn_data_ready = (size_t) cur_chunk_left;
+ if (available > cntn_data_ready)
+ has_more_data = true;
+ }
+ }
+ else
+ { /* Need the parse the chunk size line */
+ /** The number of found digits in the chunk size number */
+ size_t num_dig;
+ uint_fast64_t chunk_size;
+ bool broken;
+ bool overflow;
+
+ mhd_assert (0 != available);
+
+ overflow = false;
+ chunk_size = 0; /* Mute possible compiler warning.
+ The real value will be set later. */
+
+ num_dig = mhd_strx_to_uint64_n (buffer_head,
+ available,
+ &chunk_size);
+ mhd_assert (num_dig <= available);
+ if (num_dig == available)
+ continue; /* Need line delimiter */
+
+ broken = (0 == num_dig);
+ if (broken)
+ /* Check whether result is invalid due to uint64_t overflow */
+ overflow = ((('0' <= buffer_head[0]) && ('9' >= buffer_head[0])) ||
+ (('A' <= buffer_head[0]) && ('F' >= buffer_head[0])) ||
+ (('a' <= buffer_head[0]) && ('f' >= buffer_head[0])));
+ else
+ {
+ /**
+ * The length of the string with the number of the chunk size,
+ * including chunk extension
+ */
+ size_t chunk_size_line_len;
+
+ chunk_size_line_len = 0;
+ if ((';' == buffer_head[num_dig]) ||
+ (allow_bws &&
+ ((' ' == buffer_head[num_dig]) ||
+ ('\t' == buffer_head[num_dig]))))
+ { /* Chunk extension */
+ size_t i;
+
+ /* Skip bad whitespaces (if any) */
+ for (i = num_dig; i < available; ++i)
+ {
+ if ((' ' != buffer_head[i]) && ('\t' != buffer_head[i]))
+ break;
+ }
+ if (i == available)
+ break; /* need more data */
+ if (';' == buffer_head[i])
+ {
+ for (++i; i < available; ++i)
+ {
+ if ('\n' == buffer_head[i])
+ break;
+ }
+ if (i == available)
+ break; /* need more data */
+ mhd_assert (i > num_dig);
+ mhd_assert (1 <= i);
+ /* Found LF position */
+ if (bare_lf_as_crlf)
+ chunk_size_line_len = i; /* Don't care about CR before LF */
+ else if ('\r' == buffer_head[i - 1])
+ chunk_size_line_len = i;
+ }
+ else
+ { /* No ';' after "bad whitespace" */
+ mhd_assert (allow_bws);
+ mhd_assert (0 == chunk_size_line_len);
+ }
+ }
+ else
+ {
+ mhd_assert (available >= num_dig);
+ if ((2 <= (available - num_dig)) &&
+ ('\r' == buffer_head[num_dig]) &&
+ ('\n' == buffer_head[num_dig + 1]))
+ chunk_size_line_len = num_dig + 2;
+ else if (bare_lf_as_crlf &&
+ ('\n' == buffer_head[num_dig]))
+ chunk_size_line_len = num_dig + 1;
+ else if (2 > (available - num_dig))
+ break; /* need more data */
+ }
+
+ if (0 != chunk_size_line_len)
+ { /* Valid termination of the chunk size line */
+ mhd_assert (chunk_size_line_len <= available);
+ /* Start reading payload data of the chunk */
+ c->rq.current_chunk_offset = 0;
+ c->rq.current_chunk_size = chunk_size;
+
+ available -= chunk_size_line_len;
+ buffer_head += chunk_size_line_len;
+
+ if (0 == chunk_size)
+ { /* The final (termination) chunk */
+ c->rq.cntn.cntn_size = c->rq.cntn.recv_size;
+ c->state = MHD_CONNECTION_BODY_RECEIVED;
+ state_updated = true;
+ break;
+ }
+ if (available > 0)
+ has_more_data = true;
+ continue;
+ }
+ /* Invalid chunk size line */
+ }
+
+ if (! overflow)
+ mhd_RESPOND_WITH_ERROR_STATIC (c,
+ MHD_HTTP_STATUS_BAD_REQUEST,
+ ERR_RSP_REQUEST_CHUNKED_MALFORMED);
+ else
+ mhd_RESPOND_WITH_ERROR_STATIC (c,
+ MHD_HTTP_STATUS_CONTENT_TOO_LARGE,
+ ERR_RSP_REQUEST_CHUNK_TOO_LARGE);
+ return true;
+ }
+ mhd_assert (c->rq.client_aware);
+
+ if (mhd_ACTION_POST_PROCESS == c->rq.app_act.head_act.act)
+ {
+ mhd_assert (0 && "Not implemented yet"); // TODO: implement POST
+ return false;
+ }
+
+ if (NULL != c->rq.app_act.head_act.data.upload.full.cb)
+ {
+ need_inc_proc = false;
+
+ mhd_assert (0 == c->rq.cntn.proc_size);
+ if ((uint_fast64_t) c->rq.cntn.lbuf.size <
+ c->rq.cntn.recv_size + cntn_data_ready)
+ {
+ size_t grow_size;
+
+ grow_size = (size_t) (c->rq.cntn.recv_size + cntn_data_ready
+ - c->rq.cntn.lbuf.size);
+ if (((size_t) (c->rq.cntn.recv_size + cntn_data_ready) <
+ cntn_data_ready) || (! mhd_daemon_grow_lbuf (d,
+ grow_size,
+ &(c->rq.cntn.lbuf))))
+ {
+ /* Failed to grow the buffer, no space to put the new data */
+ const struct MHD_UploadAction *act;
+ if (NULL != c->rq.app_act.head_act.data.upload.inc.cb)
+ {
+ mhd_RESPOND_WITH_ERROR_STATIC (
+ c,
+ MHD_HTTP_STATUS_CONTENT_TOO_LARGE,
+ ERR_RSP_MSG_REQUEST_TOO_BIG);
+ return true;
+ }
+ c->rq.app_act.head_act.data.upload.full.cb = NULL; /* Cannot process
"full" content */
+ /* Process previously buffered data */
+ mhd_assert (c->rq.cntn.recv_size <= c->rq.cntn.lbuf.size);
+ act = c->rq.app_act.head_act.data.upload.inc.cb (
+ c->rq.app_act.head_act.data.upload.inc.cls,
+ &(c->rq),
+ c->rq.cntn.recv_size,
+ c->rq.cntn.lbuf.buf);
+ c->rq.cntn.proc_size = c->rq.cntn.recv_size;
+ mhd_daemon_free_lbuf (d, &(c->rq.cntn.lbuf));
+ if (process_upload_action (c, act, false))
+ return true;
+ need_inc_proc = true;
+ }
+ }
+ if (! need_inc_proc)
+ {
+ memcpy (c->rq.cntn.lbuf.buf + c->rq.cntn.recv_size,
+ buffer_head, cntn_data_ready);
+ c->rq.cntn.recv_size += cntn_data_ready;
+ }
+ }
+ else
+ need_inc_proc = true;
+
+ if (need_inc_proc)
+ {
+ const struct MHD_UploadAction *act;
+ mhd_assert (NULL != c->rq.app_act.head_act.data.upload.inc.cb);
+
+ c->rq.cntn.recv_size += cntn_data_ready;
+ act = c->rq.app_act.head_act.data.upload.inc.cb (
+ c->rq.app_act.head_act.data.upload.inc.cls,
+ &(c->rq),
+ cntn_data_ready,
+ buffer_head);
+ c->rq.cntn.proc_size += cntn_data_ready;
+ state_updated = process_upload_action (c, act, false);
+ }
+
+ /* dh left "processed" bytes in buffer for next time... */
+ buffer_head += cntn_data_ready;
+ available -= cntn_data_ready;
+ mhd_assert (MHD_SIZE_UNKNOWN == c->rq.cntn.cntn_size);
+ c->rq.current_chunk_offset += cntn_data_ready;
+ } while (has_more_data && ! state_updated);
+ /* TODO: optionally? zero out reused memory region */
+ if ( (available > 0) &&
+ (buffer_head != c->read_buffer) )
+ memmove (c->read_buffer,
+ buffer_head,
+ available);
+ else
+ mhd_assert ((0 == available) || \
+ (c->read_buffer_offset == available));
+ c->read_buffer_offset = available;
+
+ return state_updated;
+}
+
+
+static MHD_FN_PAR_NONNULL_ALL_ bool
+process_request_nonchunked_body (struct MHD_Connection *restrict c)
+{
+ size_t cntn_data_ready;
+ bool read_buf_reuse;
+ bool state_updated;
+
+ mhd_assert (NULL == c->rp.response);
+ mhd_assert (! c->rq.have_chunked_upload);
+ mhd_assert (MHD_SIZE_UNKNOWN != c->rq.cntn.cntn_size);
+ mhd_assert (c->rq.cntn.recv_size < c->rq.cntn.cntn_size);
+ mhd_assert (c->rq.client_aware);
+
+ if ((c->rq.cntn.cntn_size - c->rq.cntn.recv_size) < c->read_buffer_offset)
+ cntn_data_ready = (size_t) (c->rq.cntn.cntn_size - c->rq.cntn.recv_size);
+ else
+ cntn_data_ready = c->read_buffer_offset;
+
+ if (mhd_ACTION_POST_PROCESS == c->rq.app_act.head_act.act)
+ {
+ mhd_assert (0 && "Not implemented yet"); // TODO: implement POST
+ return false;
+ }
+
+ mhd_assert (mhd_ACTION_UPLOAD == c->rq.app_act.head_act.act);
+ read_buf_reuse = false;
+ state_updated = false;
+ if (NULL != c->rq.app_act.head_act.data.upload.full.cb)
+ {
+ // TODO: implement processing in pool memory if buffer is large enough
+ mhd_assert ((c->rq.cntn.recv_size + cntn_data_ready) <=
+ (uint_fast64_t) c->rq.cntn.lbuf.size);
+ memcpy (c->rq.cntn.lbuf.buf + c->rq.cntn.recv_size,
+ c->read_buffer, cntn_data_ready);
+ c->rq.cntn.recv_size += cntn_data_ready;
+ read_buf_reuse = true;
+ if (c->rq.cntn.recv_size == c->rq.cntn.cntn_size)
+ {
+ c->state = MHD_CONNECTION_FULL_REQ_RECEIVED;
+ state_updated = true;
+ }
+ }
+ else
+ {
+ const struct MHD_UploadAction *act;
+ mhd_assert (NULL != c->rq.app_act.head_act.data.upload.inc.cb);
+
+ c->rq.cntn.recv_size += cntn_data_ready;
+ act = c->rq.app_act.head_act.data.upload.inc.cb (
+ c->rq.app_act.head_act.data.upload.inc.cls,
+ &(c->rq),
+ cntn_data_ready,
+ c->read_buffer);
+ c->rq.cntn.proc_size += cntn_data_ready;
+ read_buf_reuse = true;
+ state_updated = process_upload_action (c, act, false);
+ }
+
+ if (read_buf_reuse)
+ {
+ size_t data_left_size;
+ mhd_assert (c->read_buffer_offset >= cntn_data_ready);
+ data_left_size = c->read_buffer_offset - cntn_data_ready;
+ if (0 != data_left_size)
+ memmove (c->read_buffer, c->read_buffer + cntn_data_ready,
data_left_size)
+ ;
+ c->read_buffer_offset = data_left_size;
+ }
+
+ return state_updated;
+}
+
+
+MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_ bool
+mhd_stream_process_request_body (struct MHD_Connection *restrict c)
+{
+ if (c->rq.have_chunked_upload)
+ return process_request_chunked_body (c);
+
+ return process_request_nonchunked_body (c);
+}
+
+
+MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_ bool
+mhd_stream_call_app_final_upload_cb (struct MHD_Connection *restrict c)
+{
+ const struct MHD_UploadAction *act;
+ mhd_assert (mhd_ACTION_POST_PROCESS == c->rq.app_act.head_act.act || \
+ mhd_ACTION_UPLOAD == c->rq.app_act.head_act.act);
+
+ if (mhd_ACTION_POST_PROCESS == c->rq.app_act.head_act.act)
+ {
+ mhd_assert (0 && "Not implemented yet"); // TODO: implement POST
+ return false;
+ }
+
+ if (NULL != c->rq.app_act.head_act.data.upload.full.cb)
+ {
+ mhd_assert (c->rq.cntn.recv_size == c->rq.cntn.cntn_size);
+ mhd_assert (0 == c->rq.cntn.proc_size);
+ mhd_assert (NULL != c->rq.cntn.lbuf.buf);
+ mhd_assert (c->rq.cntn.recv_size <= c->rq.cntn.lbuf.size);
+ // TODO: implement processing in pool memory if it is large enough
+ act = c->rq.app_act.head_act.data.upload.full.cb (
+ c->rq.app_act.head_act.data.upload.full.cls,
+ &(c->rq),
+ c->rq.cntn.recv_size,
+ c->rq.cntn.lbuf.buf);
+ c->rq.cntn.proc_size = c->rq.cntn.recv_size;
+ }
+ else
+ {
+ mhd_assert (NULL != c->rq.app_act.head_act.data.upload.inc.cb);
+ mhd_assert (c->rq.cntn.cntn_size == c->rq.cntn.proc_size);
+ act = c->rq.app_act.head_act.data.upload.inc.cb (
+ c->rq.app_act.head_act.data.upload.inc.cls,
+ &(c->rq),
+ 0,
+ NULL);
+ }
+ return process_upload_action (c, act, true);
+}
+
+
+MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_ bool
+mhd_stream_process_req_recv_finished (struct MHD_Connection *restrict c)
+{
+ if (NULL != c->rq.cntn.lbuf.buf)
+ mhd_daemon_free_lbuf (c->daemon, &(c->rq.cntn.lbuf));
+ if (c->rq.cntn.cntn_size != c->rq.cntn.proc_size)
+ c->discard_request = true;
+ mhd_assert (NULL != c->rp.response);
+ c->state = MHD_CONNECTION_START_REPLY;
+ return true;
}
diff --git a/src/mhd2/stream_process_request.h
b/src/mhd2/stream_process_request.h
index e71a39b7..810fafd9 100644
--- a/src/mhd2/stream_process_request.h
+++ b/src/mhd2/stream_process_request.h
@@ -1,6 +1,7 @@
/*
This file is part of GNU libmicrohttpd
- Copyright (C) 2024 Evgeny Grin (Karlson2k)
+ Copyright (C) 2014-2024 Evgeny Grin (Karlson2k)
+ Copyright (C) 2007-2020 Daniel Pittman and Christian Grothoff
GNU libmicrohttpd is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
@@ -23,17 +24,58 @@
* @brief The declarations of internal functions for requests parsing
* and processing
* @author Karlson2k (Evgeny Grin)
+ *
+ * Based on the MHD v0.x code by Daniel Pittman, Christian Grothoff and other
+ * contributors.
*/
#ifndef MHD_STREAM_PROCESS_REQUEST_H
-#define MHD_STREAM_PROCESS_STATES_H 1
+#define MHD_STREAM_PROCESS_REQUEST_H 1
#include "mhd_sys_options.h"
#include "sys_bool_type.h"
+#include "sys_base_types.h"
+
+#include "mhd_str_types.h"
struct MHD_Connection; /* forward declaration */
+/**
+ * Callback for iterating over GET parameters
+ * @param cls the iterator metadata
+ * @param name the name of the parameter
+ * @param value the value of the parameter
+ * @return bool to continue iterations,
+ * false to stop the iteration
+ */
+typedef bool
+(MHD_FN_PAR_NONNULL_ (2) MHD_FN_PAR_NONNULL_ (3)
+ *mhd_GetArgumentInter)(void *restrict cls,
+ const struct MHD_String *restrict name,
+ const struct MHD_StringNullable *restrict value);
+
+/**
+ * Parse and unescape the arguments given by the client
+ * as part of the HTTP request URI.
+ *
+ * @param args_len the function to call on each key-value pair found
+ * @param[in,out] args argument URI string (after "?" in URI),
+ * clobbered in the process!
+ * @param cb function to call on each key-value pair found
+ * @param cls the iterator context
+ * @param[out] enc_broken the pointer to get
+ * @return false on failure
+ * true on success (parsing succeeded, @a cb always returned true)
+ */
+MHD_INTERNAL bool
+mhd_parse_get_args (size_t args_len,
+ char *restrict args,
+ mhd_GetArgumentInter cb,
+ void *restrict cls)
+MHD_FN_PAR_NONNULL_ (2) MHD_FN_PAR_CSTR_ (2) MHD_FN_PAR_INOUT_ (2);
+
+
/**
* Find and parse the request line.
* @param c the connection to process
@@ -42,7 +84,7 @@ struct MHD_Connection; /* forward declaration */
* false if not enough data yet in the receive buffer
*/
MHD_INTERNAL bool
-mhd_get_request_line (struct MHD_Connection *restrict c)
+mhd_stream_get_request_line (struct MHD_Connection *restrict c)
MHD_FN_PAR_NONNULL_ALL_;
/**
@@ -50,11 +92,22 @@ MHD_FN_PAR_NONNULL_ALL_;
* @param c the connection to process
*/
MHD_INTERNAL void
-mhd_switch_to_rq_headers_processing (struct MHD_Connection *restrict c)
+mhd_stream_switch_to_rq_headers_proc (struct MHD_Connection *restrict c)
MHD_FN_PAR_NONNULL_ALL_;
/**
- * Find the end of the request headers and make basic header parsing.
+ * Reset request header processing state.
+ *
+ * This function resets the processing state before processing the header
+ * (or footer) line.
+ * @param c the connection to process
+ */
+MHD_INTERNAL void
+mhd_stream_reset_rq_hdr_proc_state (struct MHD_Connection *c)
+MHD_FN_PAR_NONNULL_ALL_;
+
+/**
+ * Find the end of the request GET parameters.
* Advance to the next state when done, handle errors.
* @param c the connection to process
* @param process_footers if true then footers are processed,
@@ -64,18 +117,68 @@ MHD_FN_PAR_NONNULL_ALL_;
* false if not enough data yet in the receive buffer
*/
MHD_INTERNAL bool
-mhd_get_req_headers (struct MHD_Connection *restrict c, bool process_footers)
+mhd_stream_get_request_headers (struct MHD_Connection *restrict c,
+ bool process_footers)
MHD_FN_PAR_NONNULL_ALL_;
/**
- * Parse the various headers; figure out the size
- * of the upload and make sure the headers follow
- * the protocol. Advance to the appropriate state.
+ * Parse the various request headers; figure out the size of the upload and
+ * make sure the headers follow the protocol.
+ * Advance to the appropriate state.
*
* @param c the connection to process
*/
MHD_INTERNAL void
-mhd_parse_connection_headers (struct MHD_Connection *restrict c)
+mhd_stream_parse_connection_headers (struct MHD_Connection *restrict c)
+MHD_FN_PAR_NONNULL_ALL_;
+
+/**
+ * Call application request handling callback, process action given by app.
+ * Advance to the next state when done, handle errors.
+ * @param c the connection to process
+ * @return true if advanced to the next state and the next state could
+ * be processes right now,
+ * false if connection is suspended or aborted or more data needed
+ * to process the next state
+ */
+MHD_INTERNAL bool
+mhd_stream_call_app_request_cb (struct MHD_Connection *restrict c)
+MHD_FN_PAR_NONNULL_ALL_;
+
+/**
+ * Process non-chunked request body or upload chunking encoding.
+ * Call the upload handler of the application.
+ * Advance to the next state when done, handle errors.
+ *
+ * @param c the connection to process
+ * @return true if advanced to the next state,
+ * false if more data needed or connection is suspended or aborted
+ */
+MHD_INTERNAL bool
+mhd_stream_process_request_body (struct MHD_Connection *restrict c)
MHD_FN_PAR_NONNULL_ALL_;
-#endif /* ! MHD_STREAM_PROCESS_STATES_H */
+/**
+ * Call application final upload callback, process action given by app.
+ * Advance to the next state, handle errors.
+ * @param c the connection to process
+ * @return true if advanced to the next state,
+ * false if connection is suspended or aborted
+ */
+MHD_INTERNAL bool
+mhd_stream_call_app_final_upload_cb (struct MHD_Connection *restrict c)
+MHD_FN_PAR_NONNULL_ALL_;
+
+/**
+ * Process finalisation of request receiving.
+ * Advance to the next state, handle errors.
+ * @param c the connection to process
+ * @return true if advanced to the next state,
+ * false if connection is suspended or aborted
+ */
+MHD_INTERNAL bool
+mhd_stream_process_req_recv_finished (struct MHD_Connection *restrict c)
+MHD_FN_PAR_NONNULL_ALL_;
+
+
+#endif /* ! MHD_STREAM_PROCESS_REQUEST_H */
diff --git a/src/mhd2/stream_process_states.c b/src/mhd2/stream_process_states.c
index 32b3d22e..d933490f 100644
--- a/src/mhd2/stream_process_states.c
+++ b/src/mhd2/stream_process_states.c
@@ -1,6 +1,7 @@
/*
This file is part of GNU libmicrohttpd
- Copyright (C) 2024 Evgeny Grin (Karlson2k)
+ Copyright (C) 2014-2024 Evgeny Grin (Karlson2k)
+ Copyright (C) 2007-2020 Daniel Pittman and Christian Grothoff
GNU libmicrohttpd is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
@@ -23,13 +24,20 @@
* @brief The definitions of internal functions for processing
* stream states
* @author Karlson2k (Evgeny Grin)
+ *
+ * Based on the MHD v0.x code by Daniel Pittman, Christian Grothoff and other
+ * contributors.
*/
#include "mhd_sys_options.h"
#include "sys_bool_type.h"
+#include "mhd_str_macros.h"
+
#include "mhd_connection.h"
#include "stream_process_states.h"
+#include "stream_funcs.h"
+#include "stream_process_request.h"
MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_ bool
@@ -37,19 +45,24 @@ mhd_conn_process_data (struct MHD_Connection *restrict c)
{
struct MHD_Daemon *const restrict d = c->daemon;
- enum MHD_Result ret;
-
/* 'daemon' is not used if epoll is not available and asserts are disabled */
(void) d; /* Mute compiler warning */
+ mhd_assert (c->resuming || ! c->suspended);
+ if (c->resuming)
+ {
+ // TODO: finish resuming, update activity mark
+ // TODO: move to special function
+ }
+
if ((mhd_SOCKET_ERR_NO_ERROR != c->sk_discnt_err) ||
(0 != (c->sk_ready & mhd_SOCKET_NET_STATE_ERROR_READY)))
{
mhd_assert ((mhd_SOCKET_ERR_NO_ERROR != c->sk_discnt_err) || \
- mhd_SOCKET_ERR_IS_HARD(c->sk_discnt_err));
+ mhd_SOCKET_ERR_IS_HARD (c->sk_discnt_err));
if ((mhd_SOCKET_ERR_NO_ERROR == c->sk_discnt_err) ||
(mhd_SOCKET_ERR_NOT_CHECKED == c->sk_discnt_err))
- c->sk_discnt_err = mhd_socket_error_get_from_socket(c->socket_fd);
+ c->sk_discnt_err = mhd_socket_error_get_from_socket (c->socket_fd);
mhd_conn_pre_close_skt_err (c);
return false;
}
@@ -63,21 +76,21 @@ mhd_conn_process_data (struct MHD_Connection *restrict c)
{
case MHD_CONNECTION_INIT:
case MHD_CONNECTION_REQ_LINE_RECEIVING:
- if (mhd_get_request_line (c))
+ if (mhd_stream_get_request_line (c))
{
mhd_assert (MHD_CONNECTION_REQ_LINE_RECEIVING < c->state);
- mhd_assert ((MHD_IS_HTTP_VER_SUPPORTED (c->rq.http_ver)) \
+ mhd_assert ((MHD_HTTP_VERSION_IS_SUPPORTED (c->rq.http_ver)) \
|| (c->discard_request));
continue;
}
mhd_assert (MHD_CONNECTION_REQ_LINE_RECEIVING >= c->state);
break;
case MHD_CONNECTION_REQ_LINE_RECEIVED:
- mhd_switch_to_rq_headers_processing (c);
+ mhd_stream_switch_to_rq_headers_proc (c);
mhd_assert (MHD_CONNECTION_REQ_LINE_RECEIVED != c->state);
continue;
case MHD_CONNECTION_REQ_HEADERS_RECEIVING:
- if (mhd_get_req_headers (c, false))
+ if (mhd_stream_get_request_headers (c, false))
{
mhd_assert (MHD_CONNECTION_REQ_HEADERS_RECEIVING < c->state);
mhd_assert ((MHD_CONNECTION_HEADERS_RECEIVED == c->state) || \
@@ -87,91 +100,49 @@ mhd_conn_process_data (struct MHD_Connection *restrict c)
mhd_assert (MHD_CONNECTION_REQ_HEADERS_RECEIVING == c->state);
break;
case MHD_CONNECTION_HEADERS_RECEIVED:
- mhd_parse_connection_headers (c);
- if (MHD_CONNECTION_HEADERS_RECEIVED != c->state)
- continue;
- c->state = MHD_CONNECTION_HEADERS_PROCESSED;
- if (c->suspended)
- break;
+ mhd_stream_parse_connection_headers (c);
+ mhd_assert (c->state != MHD_CONNECTION_HEADERS_RECEIVED);
continue;
case MHD_CONNECTION_HEADERS_PROCESSED:
- call_connection_handler (c);
- if (MHD_CONNECTION_HEADERS_PROCESSED != c->state)
- continue;
- if (c->suspended)
- continue;
-
- if ( (NULL == c->rp.response) &&
- (need_100_continue (c)) &&
- /* If the client is already sending the payload (body)
- there is no need to send "100 Continue" */
- (0 == c->read_buffer_offset) )
- {
- c->state = MHD_CONNECTION_CONTINUE_SENDING;
- break;
- }
- if ( (NULL != c->rp.response) &&
- (0 != c->rq.remaining_upload_size) )
+ if (mhd_stream_call_app_request_cb (c))
{
- /* we refused (no upload allowed!) */
- c->rq.remaining_upload_size = 0;
- /* force close, in case client still tries to upload... */
- c->discard_request = true;
+ mhd_assert (MHD_CONNECTION_HEADERS_PROCESSED < c->state);
+ continue;
}
- c->state = (0 == c->rq.remaining_upload_size)
- ? MHD_CONNECTION_FULL_REQ_RECEIVED
- : MHD_CONNECTION_BODY_RECEIVING;
- if (c->suspended)
- break;
- continue;
+ // TODO: add assert
+ break;
case MHD_CONNECTION_CONTINUE_SENDING:
if (c->continue_message_write_offset ==
- mhd_SSTR_LEN (HTTP_100_CONTINUE))
+ mhd_SSTR_LEN (mdh_HTTP_1_1_100_CONTINUE_REPLY))
{
c->state = MHD_CONNECTION_BODY_RECEIVING;
continue;
}
break;
case MHD_CONNECTION_BODY_RECEIVING:
- mhd_assert (0 != c->rq.remaining_upload_size);
+ mhd_assert (c->rq.cntn.recv_size < c->rq.cntn.cntn_size);
mhd_assert (! c->discard_request);
mhd_assert (NULL == c->rp.response);
- if (0 != c->read_buffer_offset)
- {
- process_request_body (c); /* loop call */
- if (MHD_CONNECTION_BODY_RECEIVING != c->state)
- continue;
- }
- /* Modify here when queueing of the response during data processing
- will be supported */
+ if (0 == c->read_buffer_offset)
+ break; /* Need more data to process */
+
+ if (mhd_stream_process_request_body (c))
+ continue;
mhd_assert (! c->discard_request);
mhd_assert (NULL == c->rp.response);
- if (0 == c->rq.remaining_upload_size)
- {
- c->state = MHD_CONNECTION_BODY_RECEIVED;
- continue;
- }
break;
case MHD_CONNECTION_BODY_RECEIVED:
mhd_assert (! c->discard_request);
mhd_assert (NULL == c->rp.response);
- if (0 == c->rq.remaining_upload_size)
- {
- if (c->rq.have_chunked_upload)
- {
- /* Reset counter variables reused for footers */
- c->rq.num_cr_sp_replaced = 0;
- c->rq.skipped_broken_lines = 0;
- reset_rq_header_processing_state (c);
- c->state = MHD_CONNECTION_FOOTERS_RECEIVING;
- }
- else
- c->state = MHD_CONNECTION_FULL_REQ_RECEIVED;
- continue;
- }
- break;
+ mhd_assert (c->rq.have_chunked_upload);
+ /* Reset counter variables reused for footers */
+ c->rq.num_cr_sp_replaced = 0;
+ c->rq.skipped_broken_lines = 0;
+ mhd_stream_reset_rq_hdr_proc_state (c);
+ c->state = MHD_CONNECTION_FOOTERS_RECEIVING;
+ continue;
case MHD_CONNECTION_FOOTERS_RECEIVING:
- if (get_req_headers (c, true))
+ if (mhd_stream_get_request_headers (c, true))
{
mhd_assert (MHD_CONNECTION_FOOTERS_RECEIVING < c->state);
mhd_assert ((MHD_CONNECTION_FOOTERS_RECEIVED == c->state) || \
@@ -181,22 +152,22 @@ mhd_conn_process_data (struct MHD_Connection *restrict c)
mhd_assert (MHD_CONNECTION_FOOTERS_RECEIVING == c->state);
break;
case MHD_CONNECTION_FOOTERS_RECEIVED:
- /* The header, the body, and the footers of the request has been
received,
- * switch to the final processing of the request. */
c->state = MHD_CONNECTION_FULL_REQ_RECEIVED;
continue;
case MHD_CONNECTION_FULL_REQ_RECEIVED:
- call_connection_handler (c); /* "final" call */
- if (c->state != MHD_CONNECTION_FULL_REQ_RECEIVED)
+ if (mhd_stream_call_app_final_upload_cb (c))
+ {
+ mhd_assert (MHD_CONNECTION_FOOTERS_RECEIVING != c->state);
continue;
- if (NULL == c->rp.response)
- break; /* try again next time */
- /* Response is ready, start reply */
- c->state = MHD_CONNECTION_START_REPLY;
- continue;
+ }
+ break;
+ case MHD_CONNECTION_REQ_RECV_FINISHED:
+ if (mhd_stream_process_req_recv_finished (c))
+ continue;
+ break;
case MHD_CONNECTION_START_REPLY:
mhd_assert (NULL != c->rp.response);
- connection_switch_from_recv_to_send (c);
+ mhd_stream_switch_from_recv_to_send (c);
if (MHD_NO == build_header_response (c))
{
/* oops - close! */
@@ -213,7 +184,7 @@ mhd_conn_process_data (struct MHD_Connection *restrict c)
break;
case MHD_CONNECTION_HEADERS_SENT:
mhd_assert (0 && "Not implemented yet");
-#if 0 //def UPGRADE_SUPPORT // TODO: upgrade support
+#if 0 // def UPGRADE_SUPPORT // TODO: upgrade support
if (NULL != c->rp.response->upgrade_handler)
{
c->state = MHD_CONNECTION_UPGRADE;
@@ -296,7 +267,7 @@ mhd_conn_process_data (struct MHD_Connection *restrict c)
if (MHD_NO != try_ready_chunked_body (c, &finished))
{
c->state = finished ? MHD_CONNECTION_CHUNKED_BODY_SENT :
- MHD_CONNECTION_CHUNKED_BODY_READY;
+ MHD_CONNECTION_CHUNKED_BODY_READY;
continue;
}
/* mutex was already unlocked by try_ready_chunked_body */
@@ -346,7 +317,13 @@ mhd_conn_process_data (struct MHD_Connection *restrict c)
}
break;
}
- if (connection_check_timedout (c))
+
+ if (c->suspended)
+ {
+ // TODO: process
+ }
+
+ if (connection_check_timedout (c)) // TODO: centralise timeout checks
{
MHD_connection_close_ (c,
MHD_REQUEST_TERMINATED_TIMEOUT_REACHED);
--
To stop receiving notification emails like this one, please contact
gnunet@gnunet.org.
- [libmicrohttpd] 228/335: -fix typo, (continued)
- [libmicrohttpd] 228/335: -fix typo, gnunet, 2024/07/27
- [libmicrohttpd] 207/335: Renamed sys_socket_types.h -> sys_sockets_types.h, gnunet, 2024/07/27
- [libmicrohttpd] 234/335: Follow-up for 631d550d6ed81be0ebd5a06e107868e5153da430, gnunet, 2024/07/27
- [libmicrohttpd] 238/335: More portability, gnunet, 2024/07/27
- [libmicrohttpd] 212/335: configure: check for uintptr_t type, gnunet, 2024/07/27
- [libmicrohttpd] 214/335: configure: added check for various levels of compound literals support, gnunet, 2024/07/27
- [libmicrohttpd] 243/335: Copy-paste fixes, gnunet, 2024/07/27
- [libmicrohttpd] 225/335: Still WIP, gnunet, 2024/07/27
- [libmicrohttpd] 242/335: Fixes, gnunet, 2024/07/27
- [libmicrohttpd] 245/335: WIP-4, gnunet, 2024/07/27
- [libmicrohttpd] 231/335: WIP more,
gnunet <=
- [libmicrohttpd] 235/335: GNU/Linux fixes, gnunet, 2024/07/27
- [libmicrohttpd] 237/335: GNU/Linux fixes-3, gnunet, 2024/07/27
- [libmicrohttpd] 236/335: More GNU/Linux fixes, gnunet, 2024/07/27
- [libmicrohttpd] 251/335: Implemented MHD_daemon_get_info_fixed_sz(), gnunet, 2024/07/27
- [libmicrohttpd] 246/335: WIP-5, gnunet, 2024/07/27
- [libmicrohttpd] 224/335: Minor update, gnunet, 2024/07/27
- [libmicrohttpd] 253/335: fix issues in test logic, gnunet, 2024/07/27
- [libmicrohttpd] 240/335: more example test code, gnunet, 2024/07/27
- [libmicrohttpd] 254/335: Fixed GET parameters parsing, gnunet, 2024/07/27
- [libmicrohttpd] 239/335: first test against test framework, gnunet, 2024/07/27