libmicrohttpd2

HTTP server C library (MHD 2.x, alpha)
Log | Files | Refs | README | LICENSE

commit c2c66985801044aadb376c8340dbb59802662e17
parent 16c70247864f464d40ad14c5d5fe0646dc43d1be
Author: Evgeny Grin (Karlson2k) <k2k@drgrin.dev>
Date:   Mon,  8 Apr 2024 02:13:45 +0100

Added header generator scripts, updated microhttpd2.h

Diffstat:
M.gitattributes | 1+
Ascripts/d_options.rec | 387+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ascripts/d_options.sh | 524+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ascripts/options_enum.template | 7+++++++
Ascripts/options_func.template | 17+++++++++++++++++
Ascripts/options_macro.template | 14++++++++++++++
Ascripts/options_struct.template | 7+++++++
Ascripts/options_union.template | 4++++
Ascripts/r_options.rec | 91+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ascripts/r_options.sh | 21+++++++++++++++++++++
Msrc/include/microhttpd2.h | 11493++++++++++++++++++++++++++++++++++++++++++++++++++++++-------------------------
11 files changed, 8893 insertions(+), 3673 deletions(-)

diff --git a/.gitattributes b/.gitattributes @@ -13,6 +13,7 @@ makefile.am text eol=lf *.pem text eol=lf *.yml text eol=lf *.rec text eol=lf +*.template text eol=lf uncrustify.cfg text eol=lf .editorconfig text eol=crlf *.props text eol=cflf diff --git a/scripts/d_options.rec b/scripts/d_options.rec @@ -0,0 +1,387 @@ +# *-* mode: rec -*- +# +# MHD option registry +# +%rec: D_Options +# recutils supports only signed 32 bit values +%typedef: enum_value range 1 0x7FFFFFFF +%key: Name +%singular: Value +%type: Value enum_value +%auto: Value +%mandatory: Value +%mandatory: Comment +%allowed: Type Argument1 Description1 Member1 Argument2 Description2 Member2 Argument3 Description3 Member3 +%type: Name,Type,Argument1,Member1,Argument2,Member2,Argument3,Member3 line +%unique: Type Value Argument1 Description1 Member1 Argument2 Description2 Member2 Argument3 Description3 Member3 + +# MHD behaviour + +Name: WORK_MODE +Value: 40 +Comment: Set MHD work (threading and polling) mode. ++ Consider use of #MHD_DAEMON_OPTION_WM_EXTERNAL_PERIODIC(), #MHD_DAEMON_OPTION_WM_EXTERNAL_EVENT_LOOP_CB_LEVEL(), #MHD_DAEMON_OPTION_WM_EXTERNAL_EVENT_LOOP_CB_EDGE(), #MHD_DAEMON_OPTION_WM_EXTERNAL_SINGLE_FD_WATCH(), #MHD_DAEMON_OPTION_WM_WORKER_THREADS() or #MHD_DAEMON_OPTION_WM_THREAD_PER_CONNECTION() instead of direct use of this parameter. +Argument1: struct MHD_WorkModeWithParam wmp +Description1: the object created by one of the next functions/macros: #MHD_WM_OPTION_EXTERNAL_PERIODIC(), #MHD_WM_OPTION_EXTERNAL_EVENT_LOOP_CB_LEVEL(), #MHD_WM_OPTION_EXTERNAL_EVENT_LOOP_CB_EDGE(), #MHD_WM_OPTION_EXTERNAL_SINGLE_FD_WATCH(), #MHD_WM_OPTION_WORKER_THREADS(), #MHD_WM_OPTION_THREAD_PER_CONNECTION() + +Name: poll_syscall +Value: 41 +Comment: Select a sockets watch system call used for internal polling. +Argument1: enum MHD_SockPollSyscall els + +Name: log_callback +Value: 60 +Comment: Set a callback to use for logging +Type: struct MHD_DaemonOptionValueLog +Argument1: MHD_LoggingCallback log_cb +Description1: the callback to use for logging, ++ NULL to disable logging +Argument2: void *lob_cb_cls +Description2: the closure for the logging callback + +# Listen socket + +Name: bind_port +Value: 80 +Type: struct MHD_DaemonOptionValueBind +Comment: Bind to the given TCP port and address family. ++ ++ Does not work with #MHD_DAEMON_OPTION_BIND_SA() or #MHD_DAEMON_OPTION_LISTEN_SOCKET(). ++ ++ If no listen socket optins (#MHD_DAEMON_OPTION_BIND_PORT(), #MHD_DAEMON_OPTION_BIND_SA(), #MHD_DAEMON_OPTION_LISTEN_SOCKET()) are used, MHD does not listen for incoming connection. +Argument1: enum MHD_AddressFamily af +Description1: the address family to use, ++ the #MHD_AF_NONE to disable listen socket (the same effect as if this option is not used) +Argument2: uint_fast16_t port +Description2: port to use, 0 to let system assign any free port, ++ ignored if @a af is #MHD_AF_NONE + +Name: bind_sa +Value: 81 +Type: struct MHD_DaemonOptionValueSA +Comment: Bind to the given socket address. ++ ++ Does not work with #MHD_DAEMON_OPTION_BIND_PORT() or #MHD_DAEMON_OPTION_LISTEN_SOCKET(). ++ ++ If no listen socket optins (#MHD_DAEMON_OPTION_BIND_PORT(), #MHD_DAEMON_OPTION_BIND_SA(), #MHD_DAEMON_OPTION_LISTEN_SOCKET()) are used, MHD does not listen for incoming connection. +Argument1: size_t sa_len +Description1: the size of the socket address pointed by @a sa. +Argument2: const struct sockaddr *sa +Description2: the address to bind to; can be IPv4 (AF_INET), IPv6 (AF_INET6) or even a UNIX domain socket (AF_UNIX) + +Name: listen_socket +Value: 82 +Comment: Accept connections from the given socket. Socket ++ must be a TCP or UNIX domain (SOCK_STREAM) socket. ++ ++ Does not work with #MHD_DAEMON_OPTION_BIND_PORT() or #MHD_DAEMON_OPTION_BIND_SA(). ++ ++ If no listen socket optins (#MHD_DAEMON_OPTION_BIND_PORT(), #MHD_DAEMON_OPTION_BIND_SA(), #MHD_DAEMON_OPTION_LISTEN_SOCKET()) are used, MHD does not listen for incoming connection. +Argument1: MHD_socket listen_fd +Description1: the listen socket to use, ignored if set to #MHD_INVALID_SOCKET + +Name: listen addr reuse +Value: 100 +Comment: Select mode of reusing address:port listen address. ++ ++ Works only when #MHD_DAEMON_OPTION_BIND_PORT() or #MHD_DAEMON_OPTION_BIND_SA() are used. +Argument1: enum MHD_DaemonOptionBindType reuse_type + +Name: tcp_fastopen +Value: 101 +Type: struct MHD_DaemonOptionValueTFO +Comment: Configure TCP_FASTOPEN option, including setting a ++ custom @a queue_length. ++ ++ Note that having a larger queue size can cause resource exhaustion ++ attack as the TCP stack has to now allocate resources for the SYN ++ packet along with its DATA. ++ ++ Works only when #MHD_DAEMON_OPTION_BIND_PORT() or #MHD_DAEMON_OPTION_BIND_SA() are used. +Argument1: enum MHD_TCPFastOpenType option +Description1: the type use of of TCP FastOpen +Argument2: unsigned int queue_length +Description2: the length of the queue, zero to use system or MHD default, ++ silently ignored on platforms without support for custom queue size + +Name: LISTEN_BACKLOG +Value: 102 +Comment: Use the given backlog for the listen() call. ++ ++ Works only when #MHD_DAEMON_OPTION_BIND_PORT() or #MHD_DAEMON_OPTION_BIND_SA() are used. +Argument1: unsigned int backlog_size + +Name: sigpipe suppressed +Value: 103 +Type: enum MHD_Bool +Comment: Inform that SIGPIPE is suppressed or handled by application. ++ If suppressed/handled, MHD uses network functions that could generate SIGPIPE, like `sendfile()`. ++ Silently ignored when MHD creates internal threads as for them SIGPIPE is suppressed automatically. + +# TLS settings + +Name: TLS +Value: 120 +Comment: Enable TLS (HTTPS) and select TLS backend +Argument1: enum MHD_TlsBackend backend +Description1: the TLS backend to use, ++ #MHD_TLS_BACKEND_NONE for non-TLS (plain TCP) connections + +Name: tls_key_cert +Value: 121 +Comment: Provide TLS key and certificate data in-memory. ++ Works only if TLS mode is enabled. +Type: struct MHD_DaemonOptionValueTlsCert +Argument1: const char *mem_key +Description1: the private key loaded into memory (not a filename) +Argument2: const char *mem_cert +Description2: the certificate loaded into memory (not a filename) +Argument3: const char *mem_cert +Description3: the option passphrase phrase to decrypt the private key, ++ could be NULL is private does not need a password + +Name: tls_client_ca +Value: 122 +Comment: Provide the certificate of the certificate authority (CA) to be used by the MHD daemon for client authentication. ++ Works only if TLS mode is enabled. +Argument1: const char *mem_client_ca +Description1: the CA certificate in memory (not a filename) + +Name: tls_psk_callback +Value: 130 +Type: struct MHD_DaemonOptionValueTlsPskCB +Comment: Configure PSK to use for the TLS key exchange. +Argument1: MHD_PskServerCredentialsCallback psk_cb +Description1: the function to call to obtain pre-shared key +Argument2: void *psk_cb_cls +Description2: the closure for @a psk_cb + +Name: no alpn +Value: 140 +Type: enum MHD_Bool +Comment: Control ALPN for TLS connection. ++ Silently ignored for non-TLS. ++ By default ALPN is automatically used for TLS connections. + +# Connection handling + +Name: DEFAULT_TIMEOUT +Value: 160 +Comment: Specify inactivity timeout for connection. ++ When no activity for specified time on connection, it is closed automatically. ++ Use zero for no timeout, which is also the (unsafe!) default. +Argument1: unsigned int timeout +Description1: the in seconds, zero for no timeout + +Name: GLOBAL_CONNECTION_LIMIT +Value: 161 +Comment: Maximum number of (concurrent) network connections served by daemon +Argument1: unsigned int glob_limit + +Name: PER_IP_LIMIT +Value: 162 +Comment: Limit on the number of (concurrent) network connections made to the server from the same IP address. ++ Can be used to prevent one IP from taking over all of the allowed connections. If the same IP tries to establish more than the specified number of connections, they will be immediately rejected. +Argument1: unsigned int per_ip_limit + +Name: accept_policy +Value: 163 +Type: struct MHD_DaemonOptionValueAcceptPol +Comment: Set a policy callback that accepts/rejects connections based on the client's IP address. The callbeck function will be called before servicing any new incoming connection. +Argument1: MHD_AcceptPolicyCallback apc +Description1: the accept policy callback +Argument2: void *apc_cls +Description2: the closure for the callback + +# Requests processing + +Name: protocol_strict_level +Value: 200 +Type: struct MHD_DaemonOptionValueStrctLvl +Comment: Set how strictly MHD will enforce the HTTP protocol. +Argument1: enum MHD_ProtocolStrictLevel sl +Description1: the level of strictness +Argument2: enum MHD_UseStictLevel how +Description2: the way how to use the requested level + +Name: early_uri_logger +Value: 201 +Type: struct MHD_DaemonOptionValueUriCB +Comment: Set a callback to be called first for every request when the request line is received (before any parsing of the header). ++ This callback is the only way to get raw (unmodified) request URI as URI is parsed and modified by MHD in-place. ++ Mandatory URI modification may apply before this call, like binary zero replacement, as required by RFCs. +Argument1: MHD_EarlyUriLogCallback cb +Description1: the early URI callback +Argument2: void *cls +Description2: the closure for the callback + +Name: DISABLE_URI_QUERY_PLUS_AS_SPACE +Value: 202 +Type: enum MHD_Bool +Comment: Disable converting plus ('+') character to space in GET parameters (URI part after '?'). ++ Plus conversion is not required by HTTP RFCs, however it required by HTML specifications, see https://url.spec.whatwg.org/#application/x-www-form-urlencoded for details. ++ By default plus is converted to space in the query part of URI. + +# Responses processing + +Name: SUPPRESS_DATE_HEADER +Value: 240 +Type: enum MHD_Bool +Comment: Suppresse use of "Date:" header. ++ According to RFC should be suppressed only if the system has no RTC. ++ The "Date:" is not suppressed (the header is enabled) by default. + +Name: ENABLE_SHOUTCAST +Value: 241 +Type: enum MHD_Bool +Comment: Use SHOUTcast for responses. ++ This will cause *all* responses to begin with the SHOUTcast "ICY" line instead of "HTTP". + +# MHD limits + +Name: conn memory limit +Value: 280 +Type: size_t +Comment: Maximum memory size per connection. ++ Default is 32kb. ++ Values above 128kb are unlikely to result in much performance benefit, as half of the memory will be typically used for IO, and TCP buffers are unlikely to support window sizes above 64k on most systems. ++ The size should be large enough to fit all request headers (together with internal parsing information). + +Name: large pool size +Value: 281 +Type: size_t +Comment: The size of the shared memory pool for accamulated upload processing. ++ The same "large" pool is shared for all connections server by MHD and used when application requests avoiding of incremental upload processing to accamulate complete content upload before giving it to the application. ++ Default is 8Mb. ++ Can be set to zero to disable share pool. + +Name: stack size +Value: 282 +Type: size_t +Comment: Desired size of the stack for the threads started by MHD. ++ Use 0 for system default, which is also MHD default. ++ Works only with ##MHD_DAEMON_OPTION_WORKER_THREADS() or #MHD_DAEMON_OPTION_THREAD_PER_CONNECTION(). + +Name: fd_number_limit +Value: 283 +Comment: The the maximum FD value. ++ The limit is applied to all sockets used by MHD. ++ If listen socket FD is equal or higher that specified value, the daemon fail to start. ++ If new connection FD is equal or higher that specified value, the connection is rejected. ++ Useful if application uses select() for polling the sockets, system FD_SETSIZE is good value for this option in such case. ++ Does not work with ##MHD_DAEMON_OPTION_WORKER_THREADS() or #MHD_DAEMON_OPTION_THREAD_PER_CONNECTION(). ++ Does not work on W32 (WinSock sockets). +Argument1: MHD_socket max_fd + +# MHD optimisations + +Name: TURBO +Value: 320 +Type: enum MHD_Bool +Comment: Enable `turbo`. ++ Disables certain calls to `shutdown()`, enables aggressive non-blocking optimistic reads and other potentially unsafe optimisations. ++ Most effects only happen with internal threads with epoll. ++ The 'turbo' mode is not enabled (mode is disabled) by default. + +Name: DISABLE_THREAD_SAFETY +Value: 321 +Type: enum MHD_Bool +Comment: Disable some internal thread safety. ++ Indicates that MHD daemon will be used by application in single-threaded mode only. When this flag is set then application must call any MHD function only within a single thread. ++ This flag turns off some internal thread-safety and allows MHD making some of the internal optimisations suitable only for single-threaded environment. ++ Not compatible with any internal threads modes. ++ If MHD is compiled with custom configuration for embedded projects without threads support, this option is mandatory. ++ Thread safety is not disabled (safety is enabled) by default. + +Name: DISALLOW_UPGRADE +Value: 322 +Type: enum MHD_Bool +Comment: You need to set this option if you want to disable use of HTTP "Upgrade". ++ "Upgrade" may require usage of additional internal resources, which we can avoid providing if they will not be used. ++ You should only use this option if you do not use "Upgrade" functionality and need a generally minor boost in performance and resources saving. ++ The "Upgrade" is not disallowed ("upgrade" is allowed) by default. + +Name: DISALLOW_SUSPEND_RESUME +Value: 323 +Type: enum MHD_Bool +Comment: Disable #MHD_action_suspend() functionality. ++ ++ You should only use this function if you do not use suspend functionality and need a generally minor boost in performance. ++ The suspend is not disallowed (suspend is allowed) by default. + +# Notification callbacks + +Name: daemon_ready_callback +Value: 360 +Type: struct MHD_DaemonOptionValueReadyCB +Comment: Set a callback to be called for pre-start finalisation. ++ ++ The specified callback will be called one time, after network initialisation, TLS pre-initialisation, but before the start of the internal threads (if allowed) +Argument1: MHD_DaemonReadyCallback cb +Description1: the pre-start callback +Argument2: void *cb_cls +Description2: the closure for the callback + +Name: notify_connection +Value: 361 +Type: struct MHD_DaemonOptionValueNotifConnCB +Comment: Set a function that should be called whenever a connection is started or closed. +Argument1: MHD_NotifyConnectionCallback ncc +Description1: the callback for notifications +Argument2: void *cls +Description2: the closure for the callback + +Name: notify_stream +Value: 362 +Type: struct MHD_DaemonOptionValueNotifStreamCB +Comment: Register a function that should be called whenever a stream is started or closed. ++ For HTTP/1.1 this callback is called one time for every connection. +Argument1: MHD_NotifyStreamCallback nsc +Description1: the callback for notifications +Argument2: void *cls +Description2: the closure for the callback + +# Digest Auth settings + +Name: random entropy +Value: 400 +Type: struct MHD_DaemonOptionValueRand +Comment: Set strong random data to be used by MHD. ++ Currently the data is only needed for Digest Auth module. ++ The recommended size is between 8 and 32 bytes. Security can be lower for sizes less or equal four. ++ Sizes larger then 32 (or, probably, larger than 16 - debatable) will not increase the security. +Argument1: size_t buf_size +Description1: the size of the buffer +Argument2: const void *buf +Description2: the buffer with strong random data, the content will be copied by MHD + +Name: dauth_map_size +Value: 401 +Comment: Specify the size of the internal hash map array that tracks generated digest nonces usage. ++ When the size of the map is too small then need to handle concurrent DAuth requests, a lot of "stale nonce" results will be produced. ++ By default the size is 8 bytes (very small). +Argument1: size_t size +Description1: the size of the map array + +Name: dauth_nonce_bind_type +Value: 402 +Type: enum MHD_DaemonOptionValueDAuthBindNonce +Comment: Control the scope of validity of MHD-generated nonces. ++ This regulates how "nonces" are generated and how "nonces" are checked by #MHD_digest_auth_check() and similar functions. ++ This option allows bitwise OR combination of #MHD_DaemonOptionValueDAuthBindNonce values. ++ When this option is not used then default value is #MHD_DAEMON_OPTION_VALUE_DAUTH_BIND_NONCE_NONE. +Argument1: bind_type + +Name: dauth_def_nonce_timeout +Value: 403 +Comment: Default nonce timeout value (in seconds) used for Digest Auth. ++ Silently ignored if followed by zero value. ++ @see #MHD_digest_auth_check(), MHD_digest_auth_check_digest() +Argument1: unsigned int timeout + +Name: dauth_def_max_nc +Value: 404 +Comment: Default maximum nc (nonce count) value used for Digest Auth. ++ Silently ignored if followed by zero value. ++ @see #MHD_digest_auth_check(), MHD_digest_auth_check_digest() +Argument1: uint_fast32_t max_nc diff --git a/scripts/d_options.sh b/scripts/d_options.sh @@ -0,0 +1,524 @@ +#!/bin/bash + +# This file is part of GNU libmicrohttpd +# Copyright (C) 2024 Karlson2k (Evgeny Grin), Christian Grothoff + +# This library 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. + +# This library 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 + + +export LC_ALL=C +export LANG=C + +if command -v recsel >/dev/null 2>&1 ; then : ; else + echo "Error: The command 'recsel' is missing. Please install recutils." >&2 + exit 1 +fi + +if command -v recset >/dev/null 2>&1 ; then : ; else + echo "Error: The command 'recset' is missing. Please install recutils." >&2 + exit 1 +fi + +if command -v recfmt >/dev/null 2>&1 ; then : ; else + echo "Error: The command 'recfmt' is missing. Please install recutils." >&2 + exit 1 +fi + +if (( 0 + 1 )) 2>/dev/null && test "$(( 2 + 2 ))" = "4" 2>/dev/null ; then : ; else + echo "Error: Built-in shell math is required" >&2 + exit 1 +fi + +if declare -a ARGS 2>/dev/null ; then : ; else + echo "Error: Indexed arrays support is required" >&2 + exit 1 +fi + +if [[ "false" ]] ; then : ; else + echo "Error: Compound command support is required" >&2 + exit 1 +fi + +if [[ $'\n' = ' +' ]] ; then : ; else + echo "Error: ANSI-C quoting support is required" >&2 + exit 1 +fi + +if [[ "abc" =~ 'b' ]] && [[ "xyz" =~ [x-z]{3} ]] ; then : ; else + echo "Error: Regular expression match support is required" >&2 + exit 1 +fi + +test_var="abc ABC Abc" +if test "${test_var^}" = "Abc ABC Abc" && test "${test_var^^}" = "ABC ABC ABC" && test "${test_var,,}" = "abc abc abc"; then : ; else + echo "Error: Shell upper- and lowercase variable conversion support required" >&2 + exit 1 +fi + +if test "${test_var// /_}" = "abc_ABC_Abc" ; then : ; else + echo "Error: Shell variable replacement conversion support required" >&2 + exit 1 +fi + +unset test_var + +if [[ "${0}" =~ (^|/|\\)'d_options.sh'$ ]]; then + options_type='daemon' +elif [[ "${0}" =~ (^|/|\\)'r_options.sh'$ ]]; then + options_type='response' +else + echo "Wrong name ('$0') of the script file" >&2 + exit 1 +fi + +# parameters +max_width=79 +if [[ "$options_type" = 'daemon' ]]; then + input_rec='d_options.rec' + rec_name='D_Options' + hdr_marker="Daemon" + one_char_opt_name='D' + short_opt_name="$options_type" +else + input_rec="r_options.rec" + rec_name='R_Options' + hdr_marker="Response" + one_char_opt_name='R' + short_opt_name="resp" +fi +tmp_rec_name="${rec_name}_preproc" +tmp_rec_file="${input_rec%.rec}_preproc.rec" + +# fixed strings +flat_arg_descr='the value of the parameter' + +err_exit() { + local msg="$1" + local err=$2 + + [[ -z $msg ]] && msg="Error!" + ( [[ -z $err ]] || (( err < 1 )) ) && err=2 + echo "$msg" >&2 + exit $err +} + +# cut string an newline character +cut_str_nl() { + local str="$1" + declare -g cut_str_nl_res='' + if [[ "$str" =~ $'\n' ]]; then + cut_str_nl_res="${str%%$'\n'*}" + return 0 + fi + return 1 +} + +# cut string to given length at word boundary if possible +# process embedded new line characters +cut_str_word () { + local str="$1" + local len=$2 + declare -g cut_str_word_res='' + [[ $len -le 0 ]] && return 1 + if cut_str_nl "${str:0:$(( len + 1 ))}"; then + cut_str_word_res="${cut_str_nl_res}" + cut_str_word_res="${cut_str_word_res% }" + return 0 + fi + if [[ ${#str} -le $len ]]; then + cut_str_word_res="${str}" + return 0 + fi + if [[ "${str:${len}:1}" = " " ]]; then + cut_str_word_res="${str:0:${len}}" + cut_str_word_res="${cut_str_word_res% }" + return 0 + fi + cut_str_word_res="${str:0:${len}}" + cut_str_word_res="${cut_str_word_res% *}" + cut_str_word_res="${cut_str_word_res% }" + return 0 +} + +format_doxy() { + local prefix1="$1" # first line prefix + local desc="$2" + local prefix2="$3" # prefix on all other lines + local width="$4" + local tmp_str + declare -g format_doxy_res='' + [[ -z $width ]] && width=$max_width + prefix1="${prefix1%"${prefix1##*[! ]}"} " # force single trailing space + [[ -z $prefix2 ]] && prefix2="$prefix1" + [[ ${#prefix1} -ge $width ]] && err_exit "Too long prefix ('${prefix1}') for width $width." + desc="${desc#"${desc%%[! ]*}"}" + desc="${desc%"${desc##*[! ]}"}" # trim desc + local width_r=$(( width - ${#prefix1} )) + local tmp_str="${prefix1//?/ }" # Space-only string with the same length + prefix2=" +${prefix2}${tmp_str:${#prefix2}}" + cut_str_word "$desc" $width_r || return 1 + format_doxy_res="${prefix1}${cut_str_word_res}" + format_doxy_res="${format_doxy_res% }" + desc="${desc:${#cut_str_word_res}}" + desc="${desc#"${desc%%[! ]*}"}" # trim leading spaces + desc="${desc#$'\n'}" # remove leading newline character + while [[ -n "$desc" ]]; do + cut_str_word "$desc" $width_r || return 1 + tmp_str="${prefix2}${cut_str_word_res}" + format_doxy_res+="${tmp_str% }" + desc="${desc:${#cut_str_word_res}}" + desc="${desc#"${desc%%[! ]*}"}" # trim leading spaces + desc="${desc#$'\n'}" # remove leading newline character + done + return 0 +} + +def_name_for_type() { + case $1 in + 'enum MHD_Bool') echo -n "bool_val";; + 'unsigned int') echo -n "uint_val";; + 'uint_fast64_t') echo -n "uint64_val";; + 'uint_fast32_t') echo -n "uint32_val";; + 'uint_fast16_t') echo -n "uint16_val";; + 'size_t') echo -n "sizet_val";; + *) local tp="${1,,}" && printf '%s' "${tp// /_}_val";; + esac +} + +capitalise_first() { + local first_char="${1:0:1}" + printf '%s' "${first_char^^}${1:1}" +} + +echo "Trimming lines in '$input_rec'..." +${SED-sed} -E -e 's/ +$//' -i "$input_rec" || err_exit +echo "OK" + +echo "Checking '$input_rec'..." +recfix --check "$input_rec" || exit 3 +echo "OK" + +cat << _EOF_ > "$tmp_rec_file" +%rec: ${tmp_rec_name} +%key: EName +%mandatory: Value +%mandatory: Name +%type: Value int +%sort: Value +%singular: EName UName SName Value + +_EOF_ + +echo "Processing input file..." +for N in $(recsel -t "${rec_name}" -R Value "$input_rec") +do + NAME=$(recsel -t "${rec_name}" -P Name -e "Value = $N" "$input_rec") + if [[ -z $NAME ]]; then + echo "The 'Name' field is empty for 'Value=$N'" >&2 + exit 2 + fi + echo -n '.' + COMMENT=$(recsel -t "${rec_name}" -P Comment -e "Value = $N" "$input_rec") + if [[ -z $COMMENT ]]; then + echo "The 'Comment' field is empty for '$NAME' ('Value=$N')" >&2 + exit 2 + fi + TYPE=$(recsel -t "${rec_name}" -P Type -e "Value = $N" "$input_rec") + EComment="" # The initial part of doxy comment for the enum value + EName="" # The name of the enum value + UName="" # The name of the union member + UType="" # The type of the union member + UTypeSp='' # The type of the union member with space at the end for non-pointers + SComment="" # The doxy comment for the set macro/function + SName="" # The name of the set macro/function + MArguments="" # The arguments for the macro + CLBody="" # The Compound Literal body (for the set macro) + SFArguments="" # The arguments for the static function + SFBody="" # The static function body + StBody='' # The data struct body (if any) + + nested='maybe' # The option has nested struct parameters ('yes'/'no'/'maybe') + + clean_name="${NAME//_/ }" + clean_name="${clean_name,,}" # Lowercase space-delimited + + echo -n "$N: ${clean_name// /_}" + + EName="${clean_name^^}" + EName="MHD_${one_char_opt_name^^}_O_${EName// /_}" # Uppercase '_'-joined + + UName="v_${clean_name// /_}" # lowercase '_'-joined + + SName="${clean_name^^}" + SName="MHD_${one_char_opt_name^^}_OPTION_${SName// /_}" # Uppercase '_'-joined + + format_doxy ' * ' "$COMMENT" || err_exit + EComment="$format_doxy_res" + + format_doxy ' * ' "$COMMENT" || err_exit + SComment="$format_doxy_res" + + # Read option parameters + ARGS=( ) + DESCRS=( ) + MEMBERS=( ) + M=1 + while + ARGM=$(recsel -t "${rec_name}" -P Argument${M} -e "Value = $N" "$input_rec") + [[ -n $ARGM ]] + do + ARGS[$M]="$ARGM" + DESCRS[$M]=$(recsel -t "${rec_name}" -P Description${M} -e "Value = $N" "$input_rec") + MEMBERS[$M]=$(recsel -t "${rec_name}" -P Member${M} -e "Value = $N" "$input_rec") + (( M++ )) + echo -n '.' + done + + # Basic data checks + (( M - 1 == ${#ARGS[@]} )) || err_exit + + if [[ ${#ARGS[@]} -eq 0 ]]; then + [[ -z $TYPE ]] && err_exit "No 'Argument1' is specified for '$NAME' ('Value=$N') without 'Type'" >&2 + nested='no' + ARGS[1]='' + DESCRS[1]="$flat_arg_descr" + MEMBERS[1]='' + elif [[ ${#ARGS[@]} -eq 1 ]]; then + nested='no' + else + nested='yes' + [[ -z $TYPE ]] && err_exit "No 'Type' is specified for non-flat (nested, with multiple parameters) '$NAME' ('Value=$N')" >&2 + fi + + # Process option parameters + for (( M=1 ; M <= ${#ARGS[@]} ; M++ )) ; do + + arg_name='' # The name of the current argument + arg_type='' # The type of the data of the current argument + arg_descr='' # The description of the current argument + nest_member='' # The name of the member of the nested structure + [[ "${ARGS[$M]}" =~ (^' '|' '$) ]] && err_exit "'Argument${M}' value '${ARGS[$M]}' for '$NAME' ('Value=$N') is not trimmed" + [[ "${DESCRS[$M]}" =~ (^' '|' '$) ]] && err_exit "'Description${M}' value '${DESCRS[$M]}' for '$NAME' ('Value=$N') is not trimmed" + [[ "${MEMBERS[$M]}" =~ (^' '|' '$) ]] && err_exit "'Member${M}' value '${MEMBERS[$M]}' for '$NAME' ('Value=$N') is not trimmed" + # Pre-process parameters data + if [[ -n ${ARGS[$M]} ]]; then + arg_name="${ARGS[$M]##* }" + arg_name="${arg_name#\*}" + arg_type="${ARGS[$M]%${arg_name}}" + arg_type="${arg_type% }" + else + if [[ $nested = 'yes' ]]; then + err_exit "Empty or no 'Argument${M}' ('$arg_type') for '$NAME' ('Value=$N')" + else + [[ -z $TYPE ]] && err_exit "No 'Argument1' is specified for '$NAME' ('Value=$N') without 'Type'" >&2 + arg_name="$(def_name_for_type "$TYPE")" + arg_type="$TYPE" + fi + fi + arg_descr="${DESCRS[$M]}" + nest_membr="${MEMBERS[$M]}" + + [[ -z $arg_name ]] && err_exit # Should not happen + if [[ $nested = 'yes' ]]; then + # non-flat, nested + [[ -z $arg_type ]] && err_exit "No argument type in 'Argument${M}' ('${ARGS[$M]}') for $NAME ('Value=$N')" + [[ $TYPE = $arg_type ]] && \ + err_exit "The same 'Type' and type for in 'Argument${M}' ('$arg_type') used for non-flat (nested) '$NAME' ('Value=$N')" + [[ -z $arg_descr ]] && \ + err_exit "Empty or no 'Description${M}' for argument '${ARGS[$M]}' for non-flat (nested) '$NAME' ('Value=$N')" + if [[ "$arg_name" = "$nest_membr" ]]; then + echo "The name for 'Argument${M}' ('${ARGS[$M]}') is the same as the 'Member${M}' ('$nest_membr') for non-flat (nested) '$NAME' ('Value=$N')" >&2 + nest_membr="v_${nest_membr}" + echo "Auto-correcting the struct member name to '$nest_membr' to avoid wrong macro expansion" >&2 + fi + else + # flat, non-nested + if [[ -z $arg_type ]]; then + if [[ -z $TYPE ]]; then + err_exit "Both 'Type' and type for in 'Argument${M}' ('${ARGS[$M]}') are empty for '$NAME' ('Value=$N')" + else + arg_type="$TYPE" + fi + else + if [[ -z $TYPE ]]; then + TYPE="$arg_type" + elif [[ $TYPE != $arg_type ]]; then + err_exit "Different 'Type' ('$TYPE') and type for in 'Argument${M}' ('$arg_type') used for '$NAME' ('Value=$N')" + fi + fi + [[ -z $arg_descr ]] && arg_descr="$flat_arg_descr" + [[ -n $nest_membr ]] && \ + err_exit "'Member${M}' is provided for non-nested (flat) '$NAME' ('Value=$N')" + fi + + [[ "$arg_type" =~ \*$ ]] || arg_type+=' ' # Position '*' correctly + [[ "$arg_name" = "${UName}" ]] && err_exit "The name ('$arg_name') of the argument 'Argument${M}' ('${ARGS[$M]}') for '$NAME' ('Value=$N') conflicts with the union member name ('${UName}'). Macro would not work." + [[ "$arg_name" = "opt" ]] && err_exit "The name ('$arg_name') of the argument 'Argument${M}' ('${ARGS[$M]}') for '$NAME' ('Value=$N') conflicts with the option struct member name ('opt'). Macro would not work." + [[ "$arg_name" = "val" ]] && err_exit "The name ('$arg_name') of the argument 'Argument${M}' ('${ARGS[$M]}') for '$NAME' ('Value=$N') conflicts with the option struct member name ('val'). Macro would not work." + [[ "${arg_name,,}" = "${arg_name}" ]] || err_exit "The name ('$arg_name') of the argument 'Argument${M}' ('${ARGS[$M]}') for '$NAME' ('Value=$N') has capital letter(s)" + [[ $nested = 'yes' ]] && [[ -z $nest_membr ]] && nest_membr="v_${arg_name}" + [[ "${#arg_name}" -ge 15 ]] && echo "Warning: too long (${#arg_name} chars) parameter name '${arg_name}'." >&2 + + [[ $M -gt 1 ]] && [[ $nested = 'no' ]] && err_exit + + # Use parameters data + + format_doxy ' * @param '"$arg_name " "$arg_descr" ' * '|| err_exit + SComment+=$'\n'"$format_doxy_res" + + [[ $M -gt 1 ]] && MArguments+=',' + MArguments+="$arg_name" + + if [[ $nested = 'yes' ]]; then + [[ $M -gt 1 ]] && SFArguments+=',' + SFArguments+=$'\n'" ${arg_type}$arg_name" + else + if (( ${#SName} + ${#arg_type} + ${#arg_name} <= $max_width )); then + SFArguments+="${arg_type}$arg_name" + else + SFArguments+=$'\n'" ${arg_type}$arg_name" + fi + fi + + #[[ $M -gt 1 ]] && CLBody+=', \'$'\n'" " + [[ $M -gt 1 ]] && CLBody+=', \##removeme##'$'\n'" " # '##removeme##' is a workaround for requtils bug + CLBody+=".val.${UName}" + [[ $nested = 'yes' ]] && CLBody+=".${nest_membr}" + CLBody+=" = ($arg_name)" + + [[ $M -gt 1 ]] && SFBody+=$'\n'" " + SFBody+="opt_val.val.${UName}" + [[ $nested = 'yes' ]] && SFBody+=".${nest_membr}" + SFBody+=" = ${arg_name};" + + if [[ $nested = 'yes' ]] && [[ "$TYPE" =~ ^'struct ' ]]; then + StBody+=$'\n' + StBody+=" /**"$'\n' + format_doxy ' * ' "$(capitalise_first "$arg_descr")" || err_exit + StBody+="$format_doxy_res"$'\n'" */"$'\n' + StBody+=" ${arg_type}$nest_membr;" + fi + echo -n '.' + done + + UType="$TYPE" + if [[ $nested = 'yes' ]] && [[ "$TYPE" =~ ^'struct ' ]]; then + need_struct_decl='yes' + else + need_struct_decl='no' + fi + [[ "$UType" =~ \*$ ]] && UTypeSp="$UType" || UTypeSp="$UType " # Position '*' correctly + + recins -t "${tmp_rec_name}" \ + -f Name -v "$NAME" \ + -f Value -v "$N" \ + -f hdr_marker -v "$hdr_marker" \ + -f EComment -v "$EComment" \ + -f EName -v "$EName" \ + -f UName -v "$UName" \ + -f UType -v "$UType" \ + -f UTypeSp -v "$UTypeSp" \ + -f SComment -v "$SComment" \ + -f SName -v "$SName" \ + -f MArguments -v "$MArguments" \ + -f CLBody -v "$CLBody" \ + -f SFArguments -v "$SFArguments" \ + -f SFBody -v "$SFBody" \ + -f StBody -v "$StBody" \ + --verbose "$tmp_rec_file" || err_exit + echo '.' +done +echo "finished." + +echo "Updating header file..." +header_name='microhttpd2.h' +start_of_marker=" = MHD ${hdr_marker} Option " +end_of_start_marker=' below are generated automatically = ' +end_of_end_marker=' above are generated automatically = ' +I=0 + +cp "../src/include/${header_name}" "./${header_name}" || err_exit + +middle_of_marker='enum values' +echo "${middle_of_marker}..." +in_file="${header_name}" +out_file="${header_name%.h}_tmp$((++I)).h" +recfmt -f options_enum.template < "$tmp_rec_file" > "header_insert${I}.h" || err_exit +middle_of_marker='enum values' +start_marker="${start_of_marker}${middle_of_marker}${end_of_start_marker}" && end_marker="${start_of_marker}${middle_of_marker}${end_of_end_marker}" || err_exit +${SED-sed} -e '/'"$start_marker"'/{p; r header_insert'"$I"'.h +} +/'"$end_marker"'/p +/'"$start_marker"'/,/'"$end_marker"'/d' "${in_file}" > "${out_file}" || err_exit + +middle_of_marker='structures' +echo "${middle_of_marker}..." +in_file="${out_file}" +out_file="${header_name%.h}_tmp$((++I)).h" +recsel -e "StBody != ''" "$tmp_rec_file" | recfmt -f options_struct.template > "header_insert${I}.h" || err_exit +start_marker="${start_of_marker}${middle_of_marker}${end_of_start_marker}" && end_marker="${start_of_marker}${middle_of_marker}${end_of_end_marker}" || err_exit +${SED-sed} -e '/'"$start_marker"'/{p; r header_insert'"$I"'.h +} +/'"$end_marker"'/p +/'"$start_marker"'/,/'"$end_marker"'/d' "${in_file}" > "${out_file}" || err_exit + +middle_of_marker='union members' +echo "${middle_of_marker}..." +in_file="${out_file}" +out_file="${header_name%.h}_tmp$((++I)).h" +recfmt -f options_union.template < "$tmp_rec_file" > "header_insert${I}.h" || err_exit +start_marker="${start_of_marker}${middle_of_marker}${end_of_start_marker}" && end_marker="${start_of_marker}${middle_of_marker}${end_of_end_marker}" || err_exit +${SED-sed} -e '/'"$start_marker"'/{p; r header_insert'"$I"'.h +} +/'"$end_marker"'/p +/'"$start_marker"'/,/'"$end_marker"'/d' "${in_file}" > "${out_file}" || err_exit + +middle_of_marker='macros' +echo "${middle_of_marker}..." +in_file="${out_file}" +out_file="${header_name%.h}_tmp$((++I)).h" +recfmt -f options_macro.template < "$tmp_rec_file" | ${SED-sed} -e 's/##removeme##//g' - > "header_insert${I}.h" || err_exit +start_marker="${start_of_marker}${middle_of_marker}${end_of_start_marker}" && end_marker="${start_of_marker}${middle_of_marker}${end_of_end_marker}" || err_exit +${SED-sed} -e '/'"$start_marker"'/{p; r header_insert'"$I"'.h +} +/'"$end_marker"'/p +/'"$start_marker"'/,/'"$end_marker"'/d' "${in_file}" > "${out_file}" || err_exit + +middle_of_marker='static functions' +echo "${middle_of_marker}..." +in_file="${out_file}" +out_file="${header_name%.h}_tmp$((++I)).h" +recfmt -f options_func.template < "$tmp_rec_file" > "header_insert${I}.h" || err_exit +start_marker="${start_of_marker}${middle_of_marker}${end_of_start_marker}" && end_marker="${start_of_marker}${middle_of_marker}${end_of_end_marker}" || err_exit +${SED-sed} -e '/'"$start_marker"'/{p; r header_insert'"$I"'.h +} +/'"$end_marker"'/p +/'"$start_marker"'/,/'"$end_marker"'/d' "${in_file}" > "${out_file}" || err_exit + +echo "finished." + +if diff "../src/include/${header_name}" "${out_file}" > /dev/null; then + echo "The updated header '${header_name}' content is equal to the previous content, the file remains the same." +else + mv "${out_file}" "../src/include/${header_name}" || err_exit + echo "The header '${header_name}' has been updated with the new content." +fi + +echo "Cleanup..." +rm -f "$tmp_rec_file" ${header_name%.h}_tmp?.h header_insert?.h +echo "completed." diff --git a/scripts/options_enum.template b/scripts/options_enum.template @@ -0,0 +1,7 @@ + /** +{{EComment}} + * The parameter value must be placed to the + * @a {{UName}} member. + */ + {{EName}} = {{Value}} + , diff --git a/scripts/options_func.template b/scripts/options_func.template @@ -0,0 +1,17 @@ +/** +{{SComment}} + * @return the object of struct MHD_{{hdr_marker}}OptionAndValue with the requested + * values + */ +static MHD_INLINE struct MHD_{{hdr_marker}}OptionAndValue +{{SName}} ({{SFArguments}}) +{ + struct MHD_{{hdr_marker}}OptionAndValue opt_val; + + opt_val.opt = {{EName}}; + {{SFBody}} + + return opt_val; +} + + diff --git a/scripts/options_macro.template b/scripts/options_macro.template @@ -0,0 +1,14 @@ +/** +{{SComment}} + * @return the object of struct MHD_{{hdr_marker}}OptionAndValue with the requested + * values + */ +# define {{SName}}({{MArguments}}) \ + MHD_NOWARN_COMPOUND_LITERALS_ \ + (const struct MHD_{{hdr_marker}}OptionAndValue) \ + { \ + .opt = ({{EName}}), \ + {{CLBody}} \ + } \ + MHD_RESTORE_WARN_COMPOUND_LITERALS_ + diff --git a/scripts/options_struct.template b/scripts/options_struct.template @@ -0,0 +1,7 @@ +/** + * Data for #MHD_D_O_{{EName}} + */ +{{UType}} v_{{UName}} +{{{StBody}} +}; + diff --git a/scripts/options_union.template b/scripts/options_union.template @@ -0,0 +1,4 @@ + /** + * Value for #{{EName}} + */ + {{UTypeSp}}{{UName}}; diff --git a/scripts/r_options.rec b/scripts/r_options.rec @@ -0,0 +1,91 @@ +# *-* mode: rec -*- +# +# response option registry +# +%rec: R_Options +# recutils supports only signed 32 bit values +%typedef: enum_value range 1 0x7FFFFFFF +%key: Name +%singular: Value +%type: Value enum_value +%auto: Value +%mandatory: Value +%mandatory: Comment +%allowed: Type Argument1 Description1 Member1 Argument2 Description2 Member2 Argument3 Description3 Member3 +%type: Name,Type,Argument1,Member1,Argument2,Member2,Argument3,Member3 line +%unique: Type Value Argument1 Description1 Member1 Argument2 Description2 Member2 Argument3 Description3 Member3 + +# General properties + +Name: REUSABLE +Value: 20 +Type: enum MHD_Bool +Comment: Make the response object re-usable. ++ The response will not be consumed by MHD_action_from_response() and must be destroyed by MHD_response_destroy(). ++ Useful if the same response is often used to reply. + +# Content control + +Name: HEAD_ONLY_RESPONSE +Value: 40 +Type: enum MHD_Bool +Comment: Enable special processing of the response as body-less (with undefined body size). No automatic "Content-Length" or "Transfer-Encoding: chunked" headers are added when the response is used with #MHD_HTTP_NOT_MODIFIED code or to respond to HEAD request. ++ The flag also allow to set arbitrary "Content-Length" by #MHD_response_add_header() function. ++ This flag value can be used only with responses created without body (zero-size body). ++ Responses with this flag enabled cannot be used in situations where reply body must be sent to the client. ++ This flag is primarily intended to be used when automatic "Content-Length" header is undesirable in response to HEAD requests. + +Name: CHUNKED_ENC +Value: 41 +Type: enum MHD_Bool +Comment: Force use of chunked encoding even if the response content size is known. ++ Ignored when the reply cannot have body/content. + +# Connection control + +Name: CONN_CLOSE +Value: 60 +Type: enum MHD_Bool +Comment: Force close connection after sending the response, prevents keep-alive connections and adds "Connection: close" header. + +# Compatibility settings + +Name: HTTP_1_0_COMPATIBLE_STRIC +Value: 80 +Type: enum MHD_Bool +Comment: Only respond in conservative (dumb) HTTP/1.0-compatible mode. ++ Response still use HTTP/1.1 version in header, but always close the connection after sending the response and do not use chunked encoding for the response. ++ You can also set the #MHD_R_O_HTTP_1_0_SERVER flag to force HTTP/1.0 version in the response. ++ Responses are still compatible with HTTP/1.1. ++ This option can be used to communicate with some broken client, which does not implement HTTP/1.1 features, but advertises HTTP/1.1 support. + +Name: HTTP_1_0_SERVER +Value: 81 +Type: enum MHD_Bool +Comment: Only respond in HTTP/1.0-mode. ++ Contrary to the #MHD_R_O_HTTP_1_0_COMPATIBLE_STRICT flag, the response's HTTP version will always be set to 1.0 and keep-alive connections will be used if explicitly requested by the client. ++ The "Connection:" header will be added for both "close" and "keep-alive" connections. ++ Chunked encoding will not be used for the response. ++ Due to backward compatibility, responses still can be used with HTTP/1.1 clients. ++ This option can be used to emulate HTTP/1.0 server (for response part only as chunked encoding in requests (if any) is processed by MHD). ++ With this option HTTP/1.0 server is emulated (with support for "keep-alive" connections). + +# Violate HTTP and/or RFCs + +Name: INSANITY_HEADER_CONTENT_LENGTH +Value: 100 +Type: enum MHD_Bool +Comment: Disable sanity check preventing clients from manually setting the HTTP content length option. ++ Allow to set several "Content-Length" headers. These headers will be used even with replies without body. + +# Callbacks + +Name: termination_callback +Value: 121 +Type: struct MHD_ResponeOptionValueTermCB +Comment: Set a function to be called once MHD is finished with the request. +Argument1: MHD_RequestTerminationCallback term_cb +Description1: the function to call, ++ NULL to not use the callback +Argument2: void *term_cb_cls +Description2: the closure for the callback diff --git a/scripts/r_options.sh b/scripts/r_options.sh @@ -0,0 +1,21 @@ +#!/bin/bash + +# This file is part of GNU libmicrohttpd +# Copyright (C) 2024 Karlson2k (Evgeny Grin) + +# This library 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. + +# This library 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 + +source ./d_options.sh diff --git a/src/include/microhttpd2.h b/src/include/microhttpd2.h @@ -59,7 +59,7 @@ * really optional, and where applicable avoid having options * where the default works if nothing is specified * - simplify API by moving rarely used http_version into - * MHD_request_get_information() + * MHD_request_get_info_fixed() * - avoid 'int' for MHD_YES/MHD_NO by introducing `enum MHD_Bool` * - improve terminology by eliminating confusion between * 'request' and 'connection' @@ -172,13 +172,13 @@ * TODO: * - varargs in upgrade is still there and ugly (and not even used!) * - migrate event loop apis (get fdset, timeout, MHD_run(), etc.) - * - * FIXME: Add to public API internal helpers, like Base64 decoder? - * Keep smaller API for now. Do not export. */ #ifndef MICROHTTPD2_H #define MICROHTTPD2_H +// TODO: finish daemon options with recutils +// TODO: finish response options with recutils + #ifdef __cplusplus extern "C" @@ -201,6 +201,7 @@ extern "C" includes won't be used (which might be a good idea, especially on platforms where they do not exist). */ +// TODO: review the list of includes, reduce it #ifndef MHD_PLATFORM_H #include <stdarg.h> #include <stdint.h> @@ -227,7 +228,7 @@ typedef intptr_t ssize_t; * Current version of the library. * 0x01093001 = 1.9.30-1. */ -#define MHD_VERSION 0x02000000 +#define MHD_VERSION 0x02000001 /** * Representation of 'bool' in the public API as stdbool.h may not @@ -243,8 +244,8 @@ enum MHD_Bool /** * MHD-internal return code for "NO". */ - MHD_NO = 0, - + MHD_NO = 0 + , /** * MHD-internal return code for "YES". All non-zero values * will be interpreted as "YES", but MHD will only ever @@ -256,6 +257,7 @@ enum MHD_Bool /** * String with length data. + * This type should always have valid @a cstr pointer. */ struct MHD_String { @@ -266,162 +268,597 @@ struct MHD_String /** * 0-terminated C-string. + * Must not be NULL. + */ + const char *cstr; +}; + +/** + * String with length data. + * This type of data may have NULL as the @a cstr pointer. + */ +struct MHD_StringNullable +{ + /** + * Number of characters in @e str, not counting 0-termination. + * If @a cstr is NULL, it must be zero. + */ + size_t len; + + /** + * 0-terminated C-string. + * In some cases it could be NULL. */ const char *cstr; }; +#ifndef __cplusplus +# define MHD_STATIC_CAST_(type,value) \ + ((type)(value)) +#else +# define MHD_STATIC_CAST_(type,value) \ + (static_cast<type>(value)) +#endif /** * Constant used to indicate unknown size (use when * creating a response). */ -#ifdef UINT_FAST64_MAX -# define MHD_SIZE_UNKNOWN UINT_FAST64_MAX +#ifdef UINT64_MAX +# define MHD_SIZE_UNKNOWN UINT64_MAX #else -# define MHD_SIZE_UNKNOWN ((uint_fast64_t) -1LL) +# define MHD_SIZE_UNKNOWN MHD_STATIC_CAST_(uint_fast64_t,0xffffffffffffffffU) #endif -// FIXME: Updated -#define MHD_DYNAMIC_CONTENT_END_OF_STREAM ((ssize_t) -1) -#define MHD_DYNAMIC_CONTENT_STOP_WITH_ERROR ((ssize_t) -2) -#define MHD_DYNAMIC_CONTENT_SUSPEND_REQUEST ((ssize_t) -3) -#ifndef _MHD_EXTERN -#if defined(_WIN32) && defined(MHD_W32LIB) -#define _MHD_EXTERN extern -#elif defined(_WIN32) && defined(MHD_W32DLL) -/* Define MHD_W32DLL when using MHD as W32 .DLL to speed up linker a little */ -#define _MHD_EXTERN extern __declspec(dllimport) +/** + * Constant used to indicate unlimited wait time. + */ +#ifdef UINT64_MAX +# define MHD_WAIT_INDEFINITELY UINT64_MAX #else -#define _MHD_EXTERN extern +# define MHD_WAIT_INDEFINITELY \ + MHD_STATIC_CAST_(uint_fast64_t,0xffffffffffffffffU) #endif + + +/** + * Constant used to indicate that options array is limited by zero-termination + */ +#define MHD_OPTIONS_ARRAY_MAX_SIZE \ + MHD_STATIC_CAST_(size_t,~ MHD_STATIC_CAST_(size_t, 0)) + + +#ifndef MHD_EXTERN_ +# if ! defined(_WIN32) +# define MHD_EXTERN_ extern +# else /* defined(_WIN32) */ +# if ! defined(MHD_W32LIB) +# define MHD_EXTERN_ extern +# else /* defined(_WIN32) && efined(MHD_W32LIB) */ +/* Define MHD_W32DLL when using MHD as W32 .DLL to speed up linker a little */ +# define MHD_EXTERN_ extern __declspec(dllimport) +# endif +# endif #endif #ifndef MHD_SOCKET_DEFINED /** * MHD_socket is type for socket FDs */ -#if ! defined(_WIN32) || defined(_SYS_TYPES_FD_SET) -#define MHD_POSIX_SOCKETS 1 +# if ! defined(_WIN32) || defined(_SYS_TYPES_FD_SET) +# define MHD_POSIX_SOCKETS 1 typedef int MHD_socket; -#define MHD_INVALID_SOCKET (-1) -#else /* !defined(_WIN32) || defined(_SYS_TYPES_FD_SET) */ -#define MHD_WINSOCK_SOCKETS 1 -#include <winsock2.h> +# define MHD_INVALID_SOCKET (-1) +# else /* !defined(_WIN32) || defined(_SYS_TYPES_FD_SET) */ +# define MHD_WINSOCK_SOCKETS 1 +# include <winsock2.h> typedef SOCKET MHD_socket; -#define MHD_INVALID_SOCKET (INVALID_SOCKET) -#endif /* !defined(_WIN32) || defined(_SYS_TYPES_FD_SET) */ -#define MHD_SOCKET_DEFINED 1 +# define MHD_INVALID_SOCKET (INVALID_SOCKET) +# endif /* !defined(_WIN32) || defined(_SYS_TYPES_FD_SET) */ +# define MHD_SOCKET_DEFINED 1 #endif /* MHD_SOCKET_DEFINED */ -// TODO: move compiler macros to separate header + +/* Compiler macros for internal needs */ + +/* Stringify macro parameter literally */ +#define MHD_MACRO_STR__(x) #x +/* Stringify macro parameter after expansion */ +#define MHD_MACRO_STR_(x) MHD_MACRO_STR__(x) + +/* Concatenate macro parameters literally */ +#define MHD_MACRO_CAT__(a,b) a ## b +/* Concatenate macro parameters after expansion */ +#define MHD_MACRO_CAT_(a,b) MHD_MACRO_CAT__(a,b) + +#ifdef __GNUC__ +# define MHD_GNUC_MINV(major,minor) \ + ((__GNUC__ > (major)) || \ + ((__GNUC__ == (major)) && (__GNUC_MINOR__ >= (minor+0)))) +#else /* ! __GNUC__ */ +# define MHD_GNUC_MINV(major,minor) (0) +#endif /* ! __GNUC__ */ + +#ifdef __clang__ +# define MHD_CLANG_MINV(major,minor) \ + ((__clang_major__ > (major)) || \ + ((__clang_major__ == (major)) && (__clang_minor__ >= (minor+0)))) +#else /* ! __GNUC__ */ +# define MHD_CLANG_MINV(major,minor) (0) +#endif /* ! __GNUC__ */ + +#if defined(_MSC_FULL_VER) +# define MHD_MSC_MINV(version) (_MSC_VER >= (version+0)) +# if defined(_MSC_FULL_VER) \ + && (! defined(__STDC__) || defined(_MSC_EXTENSIONS)) +/* Visual C with extensions */ +# define MHD_HAS_MSC_EXTENSION 1 +# endif +#else /* ! _MSC_FULL_VER */ +# define MHD_MSC_MINV(version) (0) +#endif /* ! _MSC_FULL_VER */ + +#if defined(__STDC_VERSION__) && ! defined(__cplusplus) +# define MHD_C_MINV(version) (__STDC_VERSION__ >= (version)) +#else +# define MHD_C_MINV(version) (0) +#endif + +#define MHD_C_MINV_99 MHD_C_MINV(199901) + + +#ifndef __cplusplus +# define MHD_CXX_MINV(version) (0) +#elif ! defined(_MSC_FULL_VER) || ! defined(_MSVC_LANG) +# define MHD_CXX_MINV(version) ((__cplusplus+0) >= version) +#else +# define MHD_CXX_MINV(version) \ + ((__cplusplus+0) >= version) || ((_MSVC_LANG+0) >= version) +#endif + +/* Use compound literals? */ +#if ! defined(MHD_NO_COMPOUND_LITERALS) +# if ! defined(MHD_USE_COMPOUND_LITERALS) +# if MHD_C_MINV_99 +# define MHD_USE_COMPOUND_LITERALS 1 +# elif MHD_GNUC_MINV (3,0) && ! defined(__STRICT_ANSI__) +/* This may warn in "pedantic" compilation mode */ +# define MHD_USE_COMPOUND_LITERALS 1 +/* Compound literals are an extension */ +# define MHD_USE_COMPOUND_LITERALS_EXT 1 +# elif defined(MHD_HAS_MSC_EXTENSION) && MHD_MSC_MINV (1800) \ + && ! defined(__cplusplus) +# define MHD_USE_COMPOUND_LITERALS 1 +/* Compound literals are an extension */ +# define MHD_USE_COMPOUND_LITERALS_EXT 1 +# else +/* Compound literals are not supported */ +# define MHD_NO_COMPOUND_LITERALS 1 +# endif +# endif /* !MHD_USE_COMPOUND_LITERALS */ +#elif defined(MHD_USE_COMPOUND_LITERALS) +#error MHD_USE_COMPOUND_LITERALS and MHD_NO_COMPOUND_LITERALS are both defined +#endif /* MHD_NO_COMPOUND_LITERALS */ + +/* Use compound literals array as function parameter? */ +#if defined(MHD_USE_COMPOUND_LITERALS) +# if ! defined(MHD_NO_COMP_LIT_FUNC_PARAMS) +# if ! defined(MHD_USE_COMP_LIT_FUNC_PARAMS) +# if ! defined(__cplusplus) +/* Compound literals are lvalues and their addresses can be taken */ +# define MHD_USE_COMP_LIT_FUNC_PARAMS 1 +# elif defined(__llvm__) +/* clang and LLVM-based compilers treat compound literals as lvalue */ +# define MHD_USE_COMP_LIT_FUNC_PARAMS 1 +# else +/* Compound literals array cannot be used as function parameter */ +# define MHD_NO_COMP_LIT_FUNC_PARAMS 1 +# endif +# endif +# elif defined(MHD_USE_COMP_LIT_FUNC_PARAMS) +#error MHD_USE_COMP_LIT_FUNC_PARAMS and MHD_USE_COMP_LIT_FUNC_PARAMS are both \ + defined +# endif +#else /* ! MHD_USE_COMPOUND_LITERALS */ +# ifndef MHD_NO_COMP_LIT_FUNC_PARAMS +/* Compound literals array cannot be used as function parameter */ +# define MHD_NO_COMP_LIT_FUNC_PARAMS 1 +# endif +# ifdef MHD_USE_COMP_LIT_FUNC_PARAMS +# undef MHD_USE_COMP_LIT_FUNC_PARAMS +# endif +#endif /* ! MHD_USE_COMPOUND_LITERALS */ + +/* Use designated initializers? */ +#if ! defined(MHD_NO_DESIGNATED_INIT) +# if ! defined(MHD_USE_DESIGNATED_INIT) +# if MHD_C_MINV_99 +# define MHD_USE_DESIGNATED_INIT 1 +# elif defined(__cplusplus) && defined(__cpp_designated_initializers) +# define MHD_USE_DESIGNATED_INIT 1 +# elif (MHD_GNUC_MINV (3,0) && ! defined(__STRICT_ANSI__) \ + && ! defined(__cplusplus)) \ + || (defined(__GNUG__) && MHD_GNUC_MINV (4,7)) +/* This may warn in "pedantic" compilation mode */ +# define MHD_USE_DESIGNATED_INIT 1 +/* Designated initializers are an extension */ +# define MHD_USE_DESIGNATED_INIT_EXT 1 +# elif defined(MHD_HAS_MSC_EXTENSION) && MHD_MSC_MINV (1800) +# define MHD_USE_DESIGNATED_INIT 1 +/* Designated initializers are an extension */ +# define MHD_USE_DESIGNATED_INIT_EXT 1 +# else +/* Designated initializers are not supported */ +# define MHD_NO_DESIGNATED_INIT 1 +# endif +# endif /* !MHD_USE_DESIGNATED_INIT */ +#elif defined(MHD_USE_DESIGNATED_INIT) +#error MHD_USE_DESIGNATED_INIT and MHD_NO_DESIGNATED_INIT are both defined +#endif /* MHD_NO_DESIGNATED_INIT */ + +/* Use nested designated initializers? */ +#if defined(MHD_USE_DESIGNATED_INIT) && ! defined(__cplusplus) +# ifdef MHD_NO_DESIG_NEST_INIT +# undef MHD_NO_DESIG_NEST_INIT +# endif +# ifndef MHD_USE_DESIG_NEST_INIT +# define MHD_USE_DESIG_NEST_INIT 1 +# endif +#else /* ! MHD_USE_DESIGNATED_INIT || __cplusplus */ +# ifdef MHD_USE_DESIG_NEST_INIT +# undef MHD_USE_DESIG_NEST_INIT +# endif +# ifndef MHD_NO_DESIG_NEST_INIT +/* Designated nested initializers are not supported */ +# define MHD_NO_DESIG_NEST_INIT 1 +# endif +#endif /* ! MHD_USE_DESIGNATED_INIT || __cplusplus */ + +/* Use C++ initializer lists? */ +#if ! defined(MHD_NO_CPP_INIT_LIST) +# if ! defined(MHD_USE_CPP_INIT_LIST) +# if defined(__cplusplus) && defined(__cpp_initializer_lists) +# define MHD_USE_CPP_INIT_LIST 1 +# else +# define MHD_NO_CPP_INIT_LIST 1 +# endif +# endif +#elif defined(MHD_USE_CPP_INIT_LIST) +#error MHD_USE_CPP_INIT_LIST and MHD_NO_CPP_INIT_LIST are both defined +#endif + +/* Use variadic arguments macros? */ +#if ! defined(MHD_NO_VARARG_MACROS) +# if ! defined(MHD_USE_VARARG_MACROS) +# if MHD_C_MINV_99 +# define MHD_USE_VARARG_MACROS 1 +# elif MHD_CXX_MINV (201103) +# define MHD_USE_VARARG_MACROS 1 +# elif MHD_GNUC_MINV (3,0) && ! defined(__STRICT_ANSI__) +/* This may warn in "pedantic" compilation mode */ +# define MHD_USE_VARARG_MACROS 1 +/* Variable arguments macros are an extension */ +# define MHD_USE_VARARG_MACROS_EXT 1 +# elif defined(MHD_HAS_MSC_EXTENSION) && MHD_MSC_MINV (1400) +# define MHD_USE_VARARG_MACROS 1 +/* Variable arguments macros are an extension */ +# define MHD_USE_VARARG_MACROS_EXT 1 +# else +/* Variable arguments macros are not supported */ +# define MHD_NO_VARARG_MACROS 1 +# endif +# endif /* !MHD_USE_VARARG_MACROS */ +#elif defined(MHD_USE_VARARG_MACROS) +#error MHD_USE_VARARG_MACROS and MHD_NO_VARARG_MACROS are both defined +#endif /* MHD_NO_VARARG_MACROS */ + + +/* Use variable-length arrays? */ +#if ! defined(MHD_NO_VLA) +# if ! defined(MHD_USE_VLA) +# if MHD_C_MINV_99 && \ + (! defined(__STDC_NO_VLA__) || __STDC_NO_VLA__ + 0 != 0) +# if defined(__GNUC__) || defined(__clang__) +# define MHD_USE_VLA 1 +# elif defined(_MSC_VER) +# define MHD_NO_VLA 1 +# else +/* Assume 'not supported' */ +# define MHD_NO_VLA 1 +# endif +# else +# define MHD_NO_VLA 1 +# endif +# endif +#elif defined(MHD_USE_VLA) +#error MHD_USE_VLA and MHD_NO_VLA are both defined +#endif /* MHD_NO_VARARG_MACROS */ + +#if ! defined(MHD_INLINE) +# if defined(inline) +/* Assume that proper value of 'inline' was already defined */ +# define MHD_INLINE inline +# elif MHD_C_MINV_99 +/* C99 (and later) supports 'inline' */ +# define MHD_INLINE inline +# elif defined(__cplusplus) +/* C++ always supports 'inline' */ +# define MHD_INLINE inline +# elif MHD_GNUC_MINV (3,0) && ! defined(__STRICT_ANSI__) +# define MHD_INLINE __inline__ +# elif defined(MHD_HAS_MSC_EXTENSION) && MHD_MSC_MINV (1400) +# define MHD_INLINE __inline +# else +# define MHD_INLINE /* empty */ +# endif +#endif /* MHD_INLINE */ + + +#if ! defined(MHD_NO__PRAGMA) +# if MHD_GNUC_MINV (4,6) && ! defined(__clang__) +/* '_Pragma()' support was added in GCC 3.0.0 + * 'pragma push/pop' support was added in GCC 4.6.0 */ +# define MHD_WARN_PUSH_ _Pragma("GCC diagnostic push") +# define MHD_WARN_POP_ _Pragma("GCC diagnostic pop") +# define MHD_WARN_INGORE_(warn) \ + _Pragma(MHD_MACRO_STR_(GCC diagnostic ignored MHD_MACRO_STR__(warn))) +# ifdef MHD_USE_VARARG_MACROS_EXT +# define MHD_NOWARN_VARIADIC_MACROS_ \ + MHD_WARN_PUSH_ MHD_WARN_INGORE_(-Wvariadic-macros) +# define MHD_RESTORE_WARN_VARIADIC_MACROS_ MHD_WARN_POP_ +# endif +# ifdef MHD_USE_COMPOUND_LITERALS_EXT +# define MHD_NOWARN_COMPOUND_LITERALS_ __extension__ +# define MHD_RESTORE_WARN_COMPOUND_LITERALS_ /* empty */ +# endif +# define MHD_NOWARN_UNUSED_FUNC_ \ + MHD_WARN_PUSH_ MHD_WARN_INGORE_(-Wunused-function) +# define MHD_RESTORE_WARN_UNUSED_FUNC_ MHD_WARN_POP_ +# elif MHD_CLANG_MINV (3,1) +# define MHD_WARN_PUSH_ _Pragma("clang diagnostic push") +# define MHD_WARN_POP_ _Pragma("clang diagnostic pop") +# define MHD_WARN_INGORE_(warn) \ + _Pragma(MHD_MACRO_STR_(clang diagnostic ignored MHD_MACRO_STR__(warn))) +# ifdef MHD_USE_VARARG_MACROS_EXT +# define MHD_NOWARN_VARIADIC_MACROS_ \ + MHD_WARN_PUSH_ \ + MHD_WARN_INGORE_(-Wvariadic-macros) \ + MHD_WARN_INGORE_(-Wc++98-compat-pedantic) +# define MHD_RESTORE_WARN_VARIADIC_MACROS_ MHD_WARN_POP_ +# else /* ! MHD_USE_VARARG_MACROS_EXT */ +# define MHD_NOWARN_VARIADIC_MACROS_ \ + MHD_WARN_PUSH_ MHD_WARN_INGORE_(-Wc++98-compat-pedantic) +# define MHD_RESTORE_WARN_VARIADIC_MACROS_ MHD_WARN_POP_ +# endif +# ifdef MHD_USE_CPP_INIT_LIST +# define MHD_NOWARN_CPP_INIT_LIST_ \ + MHD_WARN_PUSH_ MHD_WARN_INGORE_(-Wc++98-compat) +# define MHD_RESTORE_WARN_CPP_INIT_LIST_ MHD_WARN_POP_ +# endif +# ifdef MHD_USE_COMPOUND_LITERALS_EXT +# define MHD_NOWARN_COMPOUND_LITERALS_ \ + MHD_WARN_PUSH_ MHD_WARN_INGORE_(-Wc99-extensions) +# define MHD_RESTORE_WARN_COMPOUND_LITERALS_ MHD_WARN_POP_ +# endif +# define MHD_NOWARN_UNUSED_FUNC_ \ + MHD_WARN_PUSH_ MHD_WARN_INGORE_(-Wunused-function) +# define MHD_RESTORE_WARN_UNUSED_FUNC_ MHD_WARN_POP_ +# elif MHD_MSC_MINV (1500) +# define MHD_WARN_PUSH_ __pragma(warning(push)) +# define MHD_WARN_POP_ __pragma(warning(pop)) +# define MHD_WARN_INGORE_(warn) __pragma(warning(disable:warn)) +# define MHD_NOWARN_UNUSED_FUNC_ \ + MHD_WARN_PUSH_ MHD_WARN_INGORE_(4514) +# define MHD_RESTORE_WARN_UNUSED_FUNC_ MHD_WARN_POP_ +# endif +#endif /*! MHD_NO__PRAGMA */ + +#ifndef MHD_WARN_PUSH_ +# define MHD_WARN_PUSH_ /* empty */ +#endif +#ifndef MHD_WARN_POP_ +# define MHD_WARN_POP_ /* empty */ +#endif +#ifndef MHD_WARN_INGORE_ +# define MHD_WARN_INGORE_(ignored) /* empty */ +#endif +#ifndef MHD_NOWARN_VARIADIC_MACROS_ +# define MHD_NOWARN_VARIADIC_MACROS_ /* empty */ +#endif +#ifndef MHD_RESTORE_WARN_VARIADIC_MACROS_ +# define MHD_RESTORE_WARN_VARIADIC_MACROS_ /* empty */ +#endif +#ifndef MHD_NOWARN_CPP_INIT_LIST_ +# define MHD_NOWARN_CPP_INIT_LIST_ /* empty */ +#endif +#ifndef MHD_RESTORE_WARN_CPP_INIT_LIST_ +# define MHD_RESTORE_WARN_CPP_INIT_LIST_ /* empty */ +#endif +#ifndef MHD_NOWARN_COMPOUND_LITERALS_ +# define MHD_NOWARN_COMPOUND_LITERALS_ /* empty */ +#endif +#ifndef MHD_RESTORE_WARN_COMPOUND_LITERALS_ +# define MHD_RESTORE_WARN_COMPOUND_LITERALS_ /* empty */ +#endif +#ifndef MHD_NOWARN_UNUSED_FUNC_ +# define MHD_NOWARN_UNUSED_FUNC_ /* empty */ +#endif +#ifndef MHD_RESTORE_WARN_UNUSED_FUNC_ +# define MHD_RESTORE_WARN_UNUSED_FUNC_ /* empty */ +#endif /** - * Define MHD_NO_DEPRECATION before including "microhttpd.h" to disable deprecation messages + * Define MHD_NO_DEPRECATION before including "microhttpd2.h" to disable deprecation messages */ #ifdef MHD_NO_DEPRECATION -#define _MHD_DEPR_MACRO(msg) -#define _MHD_NO_DEPR_IN_MACRO 1 -#define _MHD_DEPR_IN_MACRO(msg) -#define _MHD_NO_DEPR_FUNC 1 -#define _MHD_DEPR_FUNC(msg) +# define MHD_DEPR_MACRO_(msg) +# define MHD_NO_DEPR_IN_MACRO_ 1 +# define MHD_DEPR_IN_MACRO_(msg) +# define MHD_NO_DEPR_FUNC_ 1 +# define MHD_DEPR_FUNC_(msg) #endif /* MHD_NO_DEPRECATION */ -#ifndef _MHD_DEPR_MACRO -#if defined(_MSC_FULL_VER) && _MSC_VER + 0 >= 1500 -/* VS 2008 or later */ -/* Stringify macros */ -#define _MHD_INSTRMACRO(a) #a -#define _MHD_STRMACRO(a) _MHD_INSTRMACRO (a) -/* deprecation message */ -#define _MHD_DEPR_MACRO(msg) __pragma(message (__FILE__ "(" _MHD_STRMACRO ( \ - __LINE__) "): warning: " msg)) -#define _MHD_DEPR_IN_MACRO(msg) _MHD_DEPR_MACRO (msg) -#elif defined(__clang__) || defined(__GNUC_PATCHLEVEL__) -/* clang or GCC since 3.0 */ -#define _MHD_GCC_PRAG(x) _Pragma(#x) -#if (defined(__clang__) && (__clang_major__ + 0 >= 5 || \ - (! defined(__apple_build_version__) && \ - (__clang_major__ + 0 > 3 || (__clang_major__ + 0 == 3 && __clang_minor__ >= \ - 3))))) || \ - __GNUC__ + 0 > 4 || (__GNUC__ + 0 == 4 && __GNUC_MINOR__ + 0 >= 8) -/* clang >= 3.3 (or XCode's clang >= 5.0) or - GCC >= 4.8 */ -#define _MHD_DEPR_MACRO(msg) _MHD_GCC_PRAG (GCC warning msg) -#define _MHD_DEPR_IN_MACRO(msg) _MHD_DEPR_MACRO (msg) -#else /* older clang or GCC */ -/* clang < 3.3, XCode's clang < 5.0, 3.0 <= GCC < 4.8 */ -#define _MHD_DEPR_MACRO(msg) _MHD_GCC_PRAG (message msg) -#if (defined(__clang__) && (__clang_major__ + 0 > 2 || (__clang_major__ + 0 == \ - 2 && __clang_minor__ >= \ - 9))) /* FIXME: clang >= 2.9, earlier versions not tested */ -/* clang handles inline pragmas better than GCC */ -#define _MHD_DEPR_IN_MACRO(msg) _MHD_DEPR_MACRO (msg) -#endif /* clang >= 2.9 */ -#endif /* older clang or GCC */ -/* #elif defined(SOMEMACRO) */ /* add compiler-specific macros here if required */ -#endif /* clang || GCC >= 3.0 */ -#endif /* !_MHD_DEPR_MACRO */ - -#ifndef _MHD_DEPR_MACRO -#define _MHD_DEPR_MACRO(msg) -#endif /* !_MHD_DEPR_MACRO */ - -#ifndef _MHD_DEPR_IN_MACRO -#define _MHD_NO_DEPR_IN_MACRO 1 -#define _MHD_DEPR_IN_MACRO(msg) -#endif /* !_MHD_DEPR_IN_MACRO */ - -#ifndef _MHD_DEPR_FUNC -#if defined(_MSC_FULL_VER) && _MSC_VER + 0 >= 1400 -/* VS 2005 or later */ -#define _MHD_DEPR_FUNC(msg) __declspec(deprecated (msg)) -#elif defined(_MSC_FULL_VER) && _MSC_VER + 0 >= 1310 -/* VS .NET 2003 deprecation do not support custom messages */ -#define _MHD_DEPR_FUNC(msg) __declspec(deprecated) -#elif (__GNUC__ + 0 >= 5) || (defined(__clang__) && \ - (__clang_major__ + 0 > 2 || (__clang_major__ + 0 == 2 && __clang_minor__ >= \ - 9))) /* FIXME: earlier versions not tested */ +#ifndef MHD_DEPR_MACRO_ +# if MHD_GNUC_MINV (4,8) && ! deifned (__clang__) /* GCC >= 4.8 */ +/* Print warning when the macro is processed (if not excluded from processing). + * To be used outside other macros */ +# define MHD_DEPR_MACRO_(msg) _Pragma(MHD_MACRO_STR_(GCC warning msg)) +/* Print warning message when another macro which includes this macro is used */ +# define MHD_DEPR_IN_MACRO_(msg) MHD_DEPR_MACRO_(msg) +# elif (MHD_CLANG_MINV (3,3) && ! defined(__apple_build_version__)) \ + || MHD_CLANG_MINV (5,0) +/* clang >= 3.3 (or XCode's clang >= 5.0) */ +/* Print warning when the macro is processed (if not excluded from processing). + * To be used outside other macros */ +# define MHD_DEPR_MACRO_(msg) _Pragma (MHD_MACRO_STR_(clang warning msg)) +/* Print warning message when another macro which includes this macro is used */ +# define MHD_DEPR_IN_MACRO_(msg) MHD_DEPR_MACRO_ (msg) +# elif MHD_MSC_MINV (1500) +/* Print warning when the macro is processed (if not excluded from processing). + * To be used outside other macros */ +# define MHD_DEPR_MACRO_(msg) \ + __pragma(message (__FILE__ "(" MHD_MACRO_STR_ ( __LINE__) ") : " \ + "warning MHDWARN01 : " msg)) +/* Print warning message when another macro which includes this macro is used */ +# define MHD_DEPR_IN_MACRO_(msg) MHD_DEPR_MACRO_ (msg) +# elif MHD_GNUC_MINV (3,0) /* 3.0 <= GCC < 4.8 */ +/* Print warning when the macro is processed (if not excluded from processing). + * To be used outside other macros */ +# define MHD_DEPR_MACRO_(msg) _Pragma (MHD_MACRO_STR_(message msg)) +# elif MHD_CLANG_MINV (2,9) +/* Print warning when the macro is processed (if not excluded from processing). + * To be used outside other macros */ +# define MHD_DEPR_MACRO_(msg) _Pragma (MHD_MACRO_STR_(message msg)) +/* Print warning message when another macro which includes this macro is used */ +# define MHD_DEPR_IN_MACRO_(msg) MHD_DEPR_MACRO_ (msg) +/* # elif defined(SOMEMACRO) */ /* add compiler-specific macros here if required */ +# endif +#endif /* !MHD_DEPR_MACRO_ */ + +#ifndef MHD_DEPR_FUNC_ +# if MHD_GNUC_MINV (5,0) || MHD_CLANG_MINV (2,9) /* GCC >= 5.0 or clang >= 2.9 */ -#define _MHD_DEPR_FUNC(msg) __attribute__((deprecated (msg))) -#elif defined(__clang__) || __GNUC__ + 0 > 3 || (__GNUC__ + 0 == 3 && \ - __GNUC_MINOR__ + 0 >= 1) +# define MHD_DEPR_FUNC_(msg) __attribute__((deprecated (msg))) +# elif MHD_GNUC_MINV (3,1) || defined(__clang__) /* 3.1 <= GCC < 5.0 or clang < 2.9 */ -/* old GCC-style deprecation do not support custom messages */ -#define _MHD_DEPR_FUNC(msg) __attribute__((__deprecated__)) -/* #elif defined(SOMEMACRO) */ /* add compiler-specific macros here if required */ -#endif /* clang < 2.9 || GCC >= 3.1 */ -#endif /* !_MHD_DEPR_FUNC */ +# define MHD_DEPR_FUNC_(msg) __attribute__((__deprecated__)) +# elif MHD_MSC_MINV (1400) +/* VS 2005 or later */ +# define MHD_DEPR_FUNC_(msg) __declspec(deprecated (msg)) +# elif MHD_MSC_MINV (1310) +# define MHD_DEPR_FUNC_(msg) __declspec(deprecated) +/* # elif defined(SOMEMACRO) */ /* add compiler-specific macros here if required */ +# endif +#endif /* ! MHD_DEPR_FUNC_ */ + +#ifndef MHD_DEPR_MACRO_ +# define MHD_DEPR_MACRO_(msg) +#endif /* !MHD_DEPR_MACRO_ */ + +#ifndef MHD_DEPR_IN_MACRO_ +# define MHD_NO_DEPR_IN_MACRO_ 1 +# define MHD_DEPR_IN_MACRO_(msg) +#endif /* !MHD_DEPR_IN_MACRO_ */ + +#ifndef MHD_DEPR_FUNC_ +# define MHD_NO_DEPR_FUNC_ 1 +# define MHD_DEPR_FUNC_(msg) +#endif /* !MHD_DEPR_FUNC_ */ + +#ifdef __has_attribute +# if __has_attribute (enum_extensibility) +/* Enum will not be extended */ +# define MHD_FIXED_ENUM_ __attribute__((enum_extensibility (closed))) +# endif /* enum_extensibility */ +# if __has_attribute (flag_enum) +/* Enum is a bitmap */ +# define MHD_FLAGS_ENUM_ __attribute__((flag_enum)) +# endif /* flag_enum */ +#endif /* __has_attribute */ + +#ifndef MHD_FIXED_ENUM_ +# define MHD_FIXED_ENUM_ /* empty */ +#endif /* MHD_FIXED_ENUM_ */ +#ifndef MHD_FLAGS_ENUM_ +# define MHD_FLAGS_ENUM_ /* empty */ +#endif /* MHD_FLAGS_ENUM_ */ + +#ifndef MHD_FIXED_FLAGS_ENUM_ +# define MHD_FIXED_FLAGS_ENUM_ MHD_FIXED_ENUM_ MHD_FLAGS_ENUM_ +#endif -#ifndef _MHD_DEPR_FUNC -#define _MHD_NO_DEPR_FUNC 1 -#define _MHD_DEPR_FUNC(msg) -#endif /* !_MHD_DEPR_FUNC */ +#ifndef MHD_FIXED_ENUM_APP_SET_ +/* The enum is set by an application to the fixed list of values */ +# define MHD_FIXED_ENUM_APP_SET_ MHD_FIXED_ENUM_ +#endif +#ifndef MHD_FLAGS_ENUM_APP_SET_ +/* The enum is set by an application, it is a bitmap */ +# define MHD_FLAGS_ENUM_APP_SET_ MHD_FLAGS_ENUM_ +#endif -/* Define MHD_FUNC_PARAM_NONNULL_ attribute */ +#ifndef MHD_FIXED_FLAGS_ENUM_APP_SET_ +/* The enum is set by an application to the fixed bitmap values */ +# define MHD_FIXED_FLAGS_ENUM_APP_SET_ MHD_FIXED_FLAGS_ENUM_ +#endif -/** - * Macro to indicate that certain parameters must be - * non-null. Todo: port to non-gcc platforms. - */ -#if defined(__CYGWIN__) || defined(_WIN32) || defined(MHD_W32LIB) || \ - defined(__clang__) || ! defined(__GNUC__) -// FIXME: vararg macros still not universally supported -// FIXME: discuss long list of attributes -#define MHD_FUNC_PARAM_NONNULL_(...) /* empty */ -#else -#define MHD_FUNC_PARAM_NONNULL_(...) __THROW __nonnull ((__VA_ARGS__)) +#ifndef MHD_FIXED_ENUM_MHD_SET_ +/* The enum is set by MHD to the fixed list of values */ +# define MHD_FIXED_ENUM_MHD_SET_ /* enum can be extended in next MHD versions */ +#endif + +#ifndef MHD_FLAGS_ENUM_MHD_SET_ +/* The enum is set by MHD, it is a bitmap */ +# define MHD_FLAGS_ENUM_MHD_SET_ MHD_FLAGS_ENUM_ #endif -// TODO: document +#ifndef MHD_FIXED_FLAGS_ENUM_MHD_SET_ +/* The enum is set by MHD to the fixed bitmap values */ +# define MHD_FIXED_FLAGS_ENUM_MHD_SET_ MHD_FLAGS_ENUM_ /* enum can be extended in next MHD versions */ +#endif + +#ifndef MHD_FIXED_ENUM_MHD_APP_SET_ +/* The enum is set by both MHD and app to the fixed list of values */ +# define MHD_FIXED_ENUM_MHD_APP_SET_ /* enum can be extended in next MHD versions */ +#endif + +#ifndef MHD_FLAGS_ENUM_MHD_APP_SET_ +/* The enum is set by both MHD and app, it is a bitmap */ +# define MHD_FLAGS_ENUM_MHD_APP_SET_ MHD_FLAGS_ENUM_ +#endif + +#ifndef MHD_FIXED_FLAGS_ENUM_MHD_APP_SET_ +/* The enum is set by both MHD and app to the fixed bitmap values */ +# define MHD_FIXED_FLAGS_ENUM_MHD_APP_SET_ MHD_FLAGS_ENUM_ /* enum can be extended in next MHD versions */ +#endif + + +/* Define MHD_NO_FUNC_ATTRIBUTES to avoid having function attributes */ #if ! defined(MHD_NO_FUNC_ATTRIBUTES) # if defined(__has_attribute) -// TODO: document -# if __has_attribute (const) && ! defined(MHD_FUNC_CONST_) +/* Override detected value of MHD_FN_PURE_ by defining it before including + * the header */ +# if __has_attribute (pure) && ! defined(MHD_FN_PURE_) +/** + * MHD_FN_PURE_ functions always return the same value for this same input + * if volatile memory content is not changed. + * In general, such functions must must not access any global variables that + * can be changed over the time. + * Typical examples: + * size_t strlen(const char *str); + * int memcmpconst void *ptr1, const void *ptr2, size_t _Size); + */ +# define MHD_FN_PURE_ __attribute__ ((pure)) +# endif /* pure && !MHD_FN_PURE_ */ + +/* Override detected value of MHD_FN_CONST_ by defining it before including + * the header */ +# if ! defined(MHD_FN_CONST_) +# if __has_attribute (const) /** - * MHD_FUNC_CONST_ functions always return the same value for this same + * MHD_FN_CONST_ functions always return the same value for this same * input value, even if any memory pointed by parameter is changed or * any global value changed. The functions do not change any global values. * In general, such functions must not dereference any pointers provided @@ -431,184 +868,239 @@ typedef SOCKET MHD_socket; * int square(int x); * int sum(int a, int b); */ -# define MHD_FUNC_CONST_ __attribute__ ((const)) -# endif /* const && !MHD_FUNC_CONST_ */ - -// TODO: document -# if __has_attribute (pure) && ! defined(MHD_FUNC_PURE_) -/** - * MHD_FUNC_PURE_ functions always return the same value for this same input - * if volatile memory content is not changed. - * In general, such functions must must not access any global variables that - * can be changed over the time. - * Typical examples: - * size_t strlen(const char *str); - * int memcmpconst void *ptr1, const void *ptr2, size_t _Size); - */ -# define MHD_FUNC_PURE_ __attribute__ ((pure)) -# endif /* pure && !MHD_FUNC_PURE_ */ +# define MHD_FN_CONST_ __attribute__ ((const)) +# elif defined(MHD_FN_PURE_) /* && ! __has_attribute (const) */ +# define MHD_FN_CONST_ MHD_FN_PURE_ +# endif +# endif /* const && !MHD_FN_CONST_ */ -// TODO: document +/* Override detected value of MHD_FN_MUST_CHECK_RESULT_ by defining it before + * including the header */ # if __has_attribute (warn_unused_result) && \ - ! defined(MHD_FUNC_MUST_CHECK_RESULT_) + ! defined(MHD_FN_MUST_CHECK_RESULT_) /** - * MHD_FUNC_MUST_CHECK_RESULT_ indicates that caller must check the value + * MHD_FN_MUST_CHECK_RESULT_ indicates that caller must check the value * returned by the function. */ -# define MHD_FUNC_MUST_CHECK_RESULT_ __attribute__ ((warn_unused_result)) -# endif /* warn_unused_result && !MHD_FUNC_MUST_CHECK_RESULT_ */ +# define MHD_FN_MUST_CHECK_RESULT_ __attribute__ ((warn_unused_result)) +# endif /* warn_unused_result && !MHD_FN_MUST_CHECK_RESULT_ */ +/* Override detected value of MHD_FN_PAR_NONNULL_ by defining it before + * including the header */ # if __has_attribute (nonnull) && \ - ! defined(MHD_FUNC_PARAM_NONNULL_) + ! defined(MHD_FN_PAR_NONNULL_) /** - * MHD_FUNC_PARAM_NONNULL_ indicates function parameter number @a param_num + * MHD_FN_PAR_NONNULL_ indicates function parameter number @a param_num * must never be NULL. */ -# define MHD_FUNC_PARAM_NONNULL_(param_num) \ +# define MHD_FN_PAR_NONNULL_(param_num) \ __attribute__ ((nonnull (param_num))) -# endif /* nonnull && !MHD_FUNC_PARAM_NONNULL_ */ +# endif /* nonnull && !MHD_FN_PAR_NONNULL_ */ +/* Override detected value of MHD_FN_PAR_NONNULL_ALL_ by defining it before + * including the header */ # if __has_attribute (nonnull) && \ - ! defined(MHD_FUNC_PARAM_NONNULL_ALL_) + ! defined(MHD_FN_PAR_NONNULL_ALL_) /** - * MHD_FUNC_PARAM_NONNULL_ALL_ indicates all function parameters must + * MHD_FN_PAR_NONNULL_ALL_ indicates all function parameters must * never be NULL. */ -# define MHD_FUNC_PARAM_NONNULL_ALL_ __attribute__ ((nonnull)) -# endif /* nonnull && !MHD_FUNC_PARAM_NONNULL_ALL_ */ +# define MHD_FN_PAR_NONNULL_ALL_ __attribute__ ((nonnull)) +# endif /* nonnull && !MHD_FN_PAR_NONNULL_ALL_ */ # if __has_attribute (access) -# if ! defined(MHD_FUNC_PARAM_IN_) +/* Override detected value of MHD_FN_PAR_IN_ by defining it before + * including the header */ +# if ! defined(MHD_FN_PAR_IN_) /** - * MHD_FUNC_PARAM_IN_ indicates function parameter points to data + * MHD_FN_PAR_IN_ indicates function parameter points to data * that must not be modified by the function */ -# define MHD_FUNC_PARAM_IN_(param_num) \ +# define MHD_FN_PAR_IN_(param_num) \ __attribute__ ((access (read_only,pram_num))) -# endif /* !MHD_FUNC_PARAM_IN_ */ +# endif /* !MHD_FN_PAR_IN_ */ -# if ! defined(MHD_FUNC_PARAM_IN_SIZE_) +/* Override detected value of MHD_FN_PAR_IN_SIZE_ by defining it before + * including the header */ +# if ! defined(MHD_FN_PAR_IN_SIZE_) /** - * MHD_FUNC_PARAM_IN_SIZE_ indicates function parameter points to data + * MHD_FN_PAR_IN_SIZE_ indicates function parameter points to data * which size is specified by @a size_num parameter and that must not be * modified by the function */ -# define MHD_FUNC_PARAM_IN_SIZE_(param_num,size_num) \ +# define MHD_FN_PAR_IN_SIZE_(param_num,size_num) \ __attribute__ ((access (read_only,pram_num,size_num))) -# endif /* !MHD_FUNC_PARAM_IN_SIZE_ */ +# endif /* !MHD_FN_PAR_IN_SIZE_ */ -# if ! defined(MHD_FUNC_PARAM_OUT_) +/* Override detected value of MHD_FN_PAR_OUT_ by defining it before + * including the header */ +# if ! defined(MHD_FN_PAR_OUT_) /** - * MHD_FUNC_PARAM_OUT_ indicates function parameter points to data + * MHD_FN_PAR_OUT_ indicates function parameter points to data * that could be written by the function, but not read. */ -# define MHD_FUNC_PARAM_OUT_(param_num) \ +# define MHD_FN_PAR_OUT_(param_num) \ __attribute__ ((access (write_only,pram_num))) -# endif /* !MHD_FUNC_PARAM_OUT_ */ +# endif /* !MHD_FN_PAR_OUT_ */ -# if ! defined(MHD_FUNC_PARAM_OUT_SIZE_) +/* Override detected value of MHD_FN_PAR_OUT_SIZE_ by defining it before + * including the header */ +# if ! defined(MHD_FN_PAR_OUT_SIZE_) /** - * MHD_FUNC_PARAM_OUT_SIZE_ indicates function parameter points to data + * MHD_FN_PAR_OUT_SIZE_ indicates function parameter points to data * which size is specified by @a size_num parameter and that could be * written by the function, but not read. */ -# define MHD_FUNC_PARAM_OUT_SIZE_(param_num,size_num) \ +# define MHD_FN_PAR_OUT_SIZE_(param_num,size_num) \ __attribute__ ((access (write_only,pram_num,size_num))) -# endif /* !MHD_FUNC_PARAM_OUT_SIZE_ */ +# endif /* !MHD_FN_PAR_OUT_SIZE_ */ -# if ! defined(MHD_FUNC_PARAM_INOUT_) +/* Override detected value of MHD_FN_PAR_INOUT_ by defining it before + * including the header */ +# if ! defined(MHD_FN_PAR_INOUT_) /** - * MHD_FUNC_PARAM_INOUT_ indicates function parameter points to data + * MHD_FN_PAR_INOUT_ indicates function parameter points to data * that could be both read and written by the function. */ -# define MHD_FUNC_PARAM_INOUT_(param_num) \ +# define MHD_FN_PAR_INOUT_(param_num) \ __attribute__ ((access (read_write,pram_num))) -# endif /* !MHD_FUNC_PARAM_INOUT_ */ +# endif /* !MHD_FN_PAR_INOUT_ */ -# if ! defined(MHD_FUNC_PARAM_INOUT_SIZE_) +/* Override detected value of MHD_FN_PAR_INOUT_SIZE_ by defining it before + * including the header */ +# if ! defined(MHD_FN_PAR_INOUT_SIZE_) /** - * MHD_FUNC_PARAM_INOUT_SIZE_ indicates function parameter points to data + * MHD_FN_PAR_INOUT_SIZE_ indicates function parameter points to data * which size is specified by @a size_num parameter and that could be * both read and written by the function. */ -# define MHD_FUNC_PARAM_INOUT_SIZE_(param_num,size_num) \ +# define MHD_FN_PAR_INOUT_SIZE_(param_num,size_num) \ __attribute__ ((access (read_write,pram_num,size_num))) -# endif /* !MHD_FUNC_PARAM_INOUT_SIZE_ */ +# endif /* !MHD_FN_PAR_INOUT_SIZE_ */ # endif /* access */ +/* Override detected value of MHD_FN_PAR_FD_READ_ by defining it before + * including the header */ +# if __has_attribute (fd_arg_read) && \ + ! defined(MHD_FN_PAR_FD_READ_) +/** + * MHD_FN_PAR_IN_ indicates function parameter is file descriptor that + * must be in open state and available for reading + */ +# define MHD_FN_PAR_FD_READ_(param_num) \ + __attribute__ ((fd_arg_read (param_num))) +# endif /* fd_arg_read && !MHD_FN_PAR_FD_READ_ */ + +/* Override detected value of MHD_FN_PAR_CSTR_ by defining it before + * including the header */ +# if __has_attribute (null_terminated_string_arg) && \ + ! defined(MHD_FN_PAR_CSTR_) +/** + * MHD_FN_PAR_IN_ indicates function parameter is file descriptor that + * must be in open state and available for reading + */ +# define MHD_FN_PAR_CSTR_(param_num) \ + __attribute__ ((null_terminated_string_arg (param_num))) +# endif /* null_terminated_string_arg && !MHD_FN_PAR_CSTR_ */ + +/* Override detected value of MHD_FN_RETURNS_NONNULL_ by defining it before + * including the header */ # if __has_attribute (returns_nonnull) && \ - ! defined(MHD_FUNC_RETURNS_NONNULL_) + ! defined(MHD_FN_RETURNS_NONNULL_) /** - * MHD_FUNC_RETURNS_NONNULL_ indicates that function never returns NULL. + * MHD_FN_RETURNS_NONNULL_ indicates that function never returns NULL. */ -# define MHD_FUNC_RETURNS_NONNULL_ __attribute__ ((returns_nonnull)) -# endif /* returns_nonnull && !MHD_FUNC_RETURNS_NONNULL_ */ +# define MHD_FN_RETURNS_NONNULL_ __attribute__ ((returns_nonnull)) +# endif /* returns_nonnull && !MHD_FN_RETURNS_NONNULL_ */ -# if __has_attribute (access) && \ - ! defined(MHD_FUNC_PARAM_IN_) +/* Override detected value of MHD_FN_WARN_UNUSED_RESULT_ by defining it before + * including the header */ +# if __has_attribute (warn_unused_result) && \ + ! defined(MHD_FN_WARN_UNUSED_RESULT_) /** - * MHD_FUNC_PARAM_IN_ indicates function parameter points to data - * that must not be modified by the function + * MHD_FN_WARN_UNUSED_RESULT_ that function return value should not be ignored */ -# define MHD_FUNC_PARAM_IN_(param_num) \ - __attribute__ ((access (read_only,pram_num))) -# endif /* returns_nonnull && !MHD_FUNC_RETURNS_NONNULL_ */ +# define MHD_FN_WARN_UNUSED_RESULT_ \ + __attribute__ ((warn_unused_result)) +# endif /* warn_unused_result && !MHD_FN_WARN_UNUSED_RESULT_ */ # endif /* __has_attribute */ #endif /* ! MHD_NO_FUNC_ATTRIBUTES */ -#ifndef MHD_C99_ -# if __STDC_VERSION__ >= 199901L -// FIXME: does not work with VLA on C11 on some compilers at least -// FIXME: whitelist supported compilers -// Probably problematic for typedefs for callbacks -# define MHD_C99_(x) x -# endif /* __STDC_VERSION__ >= 199901L */ -#endif /* MHD_C99_ */ - - -#ifndef MHD_FUNC_CONST_ -# define MHD_FUNC_CONST_ /* empty */ -#endif /* ! MHD_FUNC_CONST_ */ -#ifndef MHD_FUNC_PURE_ -# define MHD_FUNC_PURE_ /* empty */ -#endif /* ! MHD_FUNC_PURE_ */ -#ifndef MHD_FUNC_MUST_CHECK_RESULT_ -# define MHD_FUNC_MUST_CHECK_RESULT_ /* empty */ -#endif /* ! MHD_FUNC_MUST_CHECK_RESULT_ */ -#ifndef MHD_FUNC_PARAM_NONNULL_ -# define MHD_FUNC_PARAM_NONNULL_(ignored) /* empty */ -#endif /* ! MHD_FUNC_PARAM_NONNULL_ */ -#ifndef MHD_FUNC_PARAM_NONNULL_ALL_ -# define MHD_FUNC_PARAM_NONNULL_ALL_ /* empty */ -#endif /* ! MHD_FUNC_PARAM_NONNULL_ALL_ */ -#if ! defined(MHD_FUNC_PARAM_IN_) -# define MHD_FUNC_PARAM_IN_(param_num) /* empty */ -#endif /* !MHD_FUNC_PARAM_IN_ */ -#if ! defined(MHD_FUNC_PARAM_IN_SIZE_) -# define MHD_FUNC_PARAM_IN_SIZE_(param_num,size_num) /* empty */ -#endif /* !MHD_FUNC_PARAM_IN_SIZE_ */ -#if ! defined(MHD_FUNC_PARAM_OUT_) -# define MHD_FUNC_PARAM_OUT_(param_num) /* empty */ -#endif /* !MHD_FUNC_PARAM_OUT_ */ -#if ! defined(MHD_FUNC_PARAM_OUT_SIZE_) -# define MHD_FUNC_PARAM_OUT_SIZE_(param_num,size_num) /* empty */ -#endif /* !MHD_FUNC_PARAM_OUT_SIZE_ */ -#if ! defined(MHD_FUNC_PARAM_INOUT_) -# define MHD_FUNC_PARAM_INOUT_(param_num) /* empty */ -#endif /* !MHD_FUNC_PARAM_INOUT_ */ -#if ! defined(MHD_FUNC_PARAM_INOUT_SIZE_) -# define MHD_FUNC_PARAM_INOUT_SIZE_(param_num,size_num) /* empty */ -#endif /* !MHD_FUNC_PARAM_INOUT_SIZE_ */ -#ifndef MHD_FUNC_RETURNS_NONNULL_ -# define MHD_FUNC_RETURNS_NONNULL_ /* empty */ -#endif /* ! MHD_FUNC_RETURNS_NONNULL_ */ - -#ifndef MHD_C99_ -# define MHD_C99_(ignored) /* empty */ -#endif /* MHD_C99_ */ +/* Override detected value of MHD_FN_PAR_DYN_ARR_SIZE_() by defining it + * before including the header */ +#ifndef MHD_FN_PAR_DYN_ARR_SIZE_ +# if MHD_C_MINV_99 +# if MHD_USE_VLA +# define MHD_FN_PAR_DYN_ARR_SIZE_(size) static size +# else +# define MHD_FN_PAR_DYN_ARR_SIZE_(size) 1 +# endif +# else /* ! MHD_C_MINV_99 */ +# define MHD_FN_PAR_DYN_ARR_SIZE_(size) 1 +# endif /* ! MHD_C_MINV_99 */ +#endif /* MHD_FN_PAR_DYN_ARR_SIZE_ */ + +/* Override detected value of MHD_FN_PAR_FIX_ARR_SIZE_() by defining it + * before including the header */ +#ifndef MHD_FN_PAR_FIX_ARR_SIZE_ +# if MHD_C_MINV_99 +/* The size must be constant expression */ +# define MHD_FN_PAR_FIX_ARR_SIZE_(size) static size +# else +/* The size must be constant expression */ +# define MHD_FN_PAR_FIX_ARR_SIZE_(size) size +# endif /* MHD_C_MINV_99 */ +#endif /* MHD_FN_PAR_FIX_ARR_SIZE_ */ + + +#ifndef MHD_FN_CONST_ +# define MHD_FN_CONST_ /* empty */ +#endif /* ! MHD_FN_CONST_ */ +#ifndef MHD_FN_PURE_ +# define MHD_FN_PURE_ /* empty */ +#endif /* ! MHD_FN_PURE_ */ +#ifndef MHD_FN_MUST_CHECK_RESULT_ +# define MHD_FN_MUST_CHECK_RESULT_ /* empty */ +#endif /* ! MHD_FN_MUST_CHECK_RESULT_ */ +#ifndef MHD_FN_PAR_NONNULL_ +# define MHD_FN_PAR_NONNULL_(param_num) /* empty */ +#endif /* ! MHD_FN_PAR_NONNULL_ */ +#ifndef MHD_FN_PAR_NONNULL_ALL_ +# define MHD_FN_PAR_NONNULL_ALL_ /* empty */ +#endif /* ! MHD_FN_PAR_NONNULL_ALL_ */ +#ifndef MHD_FN_PAR_IN_ +# define MHD_FN_PAR_IN_(param_num) /* empty */ +#endif /* !MHD_FN_PAR_IN_ */ +#ifndef MHD_FN_PAR_IN_SIZE_ +# define MHD_FN_PAR_IN_SIZE_(param_num,size_num) /* empty */ +#endif /* !MHD_FN_PAR_IN_SIZE_ */ +#ifndef MHD_FN_PAR_OUT_ +# define MHD_FN_PAR_OUT_(param_num) /* empty */ +#endif /* !MHD_FN_PAR_OUT_ */ +#ifndef MHD_FN_PAR_OUT_SIZE_ +# define MHD_FN_PAR_OUT_SIZE_(param_num,size_num) /* empty */ +#endif /* !MHD_FN_PAR_OUT_SIZE_ */ +#ifndef MHD_FN_PAR_INOUT_ +# define MHD_FN_PAR_INOUT_(param_num) /* empty */ +#endif /* !MHD_FN_PAR_INOUT_ */ +#ifndef MHD_FN_PAR_INOUT_SIZE_ +# define MHD_FN_PAR_INOUT_SIZE_(param_num,size_num) /* empty */ +#endif /* !MHD_FN_PAR_INOUT_SIZE_ */ +#ifndef MHD_FN_PAR_FD_READ_ +# define MHD_FN_PAR_FD_READ_(param_num) /* empty */ +#endif /* !MHD_FN_PAR_FD_READ_ */ +#ifndef MHD_FN_PAR_CSTR_ +# define MHD_FN_PAR_CSTR_(param_num) /* empty */ +#endif /* ! MHD_FN_PAR_CSTR_ */ +#ifndef MHD_FN_RETURNS_NONNULL_ +# define MHD_FN_RETURNS_NONNULL_ /* empty */ +#endif /* ! MHD_FN_RETURNS_NONNULL_ */ +#ifndef MHD_FN_WARN_UNUSED_RESULT_ +# define MHD_FN_WARN_UNUSED_RESULT_ /* empty */ +#endif /* ! MHD_FN_WARN_UNUSED_RESULT_ */ /* ********** (a) Core HTTP Processing ************ */ @@ -651,9 +1143,9 @@ struct MHD_Stream; * stream. However, MHD will only show one request per data * stream to the client at any given time. * - * Replaces `struct MHD_Connection`, renamed to better reflect - * what this object truly represents to the application using - * MHD. + * Replaces `struct MHD_Connection` in the API prior to version 2.0.0, + * renamed to better reflect what this object truly represents to + * the application using MHD. * * @ingroup request */ @@ -679,7 +1171,7 @@ struct MHD_Action; * Values from 50000-59999 indicate MHD server errors. * Values from 60000-65535 indicate application errors. */ -enum MHD_StatusCode +enum MHD_FIXED_ENUM_MHD_SET_ MHD_StatusCode { /* 00000-level status codes indicate return values @@ -687,15 +1179,15 @@ enum MHD_StatusCode /** * Successful operation (not used for logging). + * The code is guaranteed to be always zero. */ - MHD_SC_OK = 0, - + MHD_SC_OK = 0 + , /** * We were asked to return a timeout, but, there is no timeout. - * FIXME: explain better? Remove? */ - MHD_SC_NO_TIMEOUT = 1, - + MHD_SC_NO_TIMEOUT = 1 + , /* 10000-level status codes indicate intermediate results of some kind. */ @@ -703,28 +1195,28 @@ enum MHD_StatusCode /** * Informational event, MHD started. */ - MHD_SC_DAEMON_STARTED = 10000, - + MHD_SC_DAEMON_STARTED = 10000 + , /** * Informational event, we accepted a connection. */ - MHD_SC_CONNECTION_ACCEPTED = 10001, - + MHD_SC_CONNECTION_ACCEPTED = 10001 + , /** * Informational event, thread processing connection terminates. */ - MHD_SC_THREAD_TERMINATING = 10002, - + MHD_SC_THREAD_TERMINATING = 10002 + , /** * Informational event, state machine status for a connection. */ - MHD_SC_STATE_MACHINE_STATUS_REPORT = 10003, - + MHD_SC_STATE_MACHINE_STATUS_REPORT = 10003 + , /** * accept() returned transient error. */ - MHD_SC_ACCEPT_FAILED_EAGAIN = 10004, - + MHD_SC_ACCEPT_FAILED_EAGAIN = 10004 + , /* 20000-level status codes indicate success of some kind. */ @@ -732,14 +1224,14 @@ enum MHD_StatusCode * MHD is closing a connection after the client closed it * (perfectly normal end). */ - MHD_SC_CONNECTION_CLOSED = 20000, - + MHD_SC_CONNECTION_CLOSED = 20000 + , /** * MHD is closing a connection because the application * logic to generate the response data completed. */ - MHD_SC_APPLICATION_DATA_GENERATION_FINISHED = 20001, - + MHD_SC_APPLICATION_DATA_GENERATION_FINISHED = 20001 + , /* 30000-level status codes indicate transient failures that might go away if the client tries again. */ @@ -749,74 +1241,74 @@ enum MHD_StatusCode * Resource limit in terms of number of parallel connections * hit. */ - MHD_SC_LIMIT_CONNECTIONS_REACHED = 30000, - + MHD_SC_LIMIT_CONNECTIONS_REACHED = 30000 + , /** * We failed to allocate memory for poll() syscall. * (May be transient.) */ - MHD_SC_POLL_MALLOC_FAILURE = 30001, - + MHD_SC_POLL_MALLOC_FAILURE = 30001 + , /** * The operation failed because the respective * daemon is already too deep inside of the shutdown * activity. */ - MHD_SC_DAEMON_ALREADY_SHUTDOWN = 30002, - + MHD_SC_DAEMON_ALREADY_SHUTDOWN = 30002 + , /** * We failed to start a thread. */ - MHD_SC_THREAD_LAUNCH_FAILURE = 30003, - + MHD_SC_THREAD_LAUNCH_FAILURE = 30003 + , /** * The operation failed because we either have no * listen socket or were already quiesced. */ - MHD_SC_DAEMON_ALREADY_QUIESCED = 30004, - + MHD_SC_DAEMON_ALREADY_QUIESCED = 30004 + , /** * The operation failed because client disconnected * faster than we could accept(). */ - MHD_SC_ACCEPT_FAST_DISCONNECT = 30005, - + MHD_SC_ACCEPT_FAST_DISCONNECT = 30005 + , /** * Operating resource limits hit on accept(). */ - MHD_SC_ACCEPT_SYSTEM_LIMIT_REACHED = 30006, - + MHD_SC_ACCEPT_SYSTEM_LIMIT_REACHED = 30006 + , /** * Connection was refused by accept policy callback. */ - MHD_SC_ACCEPT_POLICY_REJECTED = 30007, - + MHD_SC_ACCEPT_POLICY_REJECTED = 30007 + , /** * We failed to allocate memory for the connection. * (May be transient.) */ - MHD_SC_CONNECTION_MALLOC_FAILURE = 30008, - + MHD_SC_CONNECTION_MALLOC_FAILURE = 30008 + , /** * We failed to allocate memory for the connection's memory pool. * (May be transient.) */ - MHD_SC_POOL_MALLOC_FAILURE = 30009, - + MHD_SC_POOL_MALLOC_FAILURE = 30009 + , /** * We failed to forward data from a Web socket to the * application to the remote side due to the socket * being closed prematurely. (May be transient.) */ - MHD_SC_UPGRADE_FORWARD_INCOMPLETE = 30010, - + MHD_SC_UPGRADE_FORWARD_INCOMPLETE = 30010 + , /** * We failed to allocate memory for generating the response from our * memory pool. Likely the request header was too large to leave * enough room. */ - MHD_SC_CONNECTION_POOL_MALLOC_FAILURE = 30011, - + MHD_SC_CONNECTION_POOL_MALLOC_FAILURE = 30011 + , /* 40000-level errors are caused by the HTTP client (or the network) */ @@ -825,45 +1317,45 @@ enum MHD_StatusCode * MHD is closing a connection because parsing the * request failed. */ - MHD_SC_CONNECTION_PARSE_FAIL_CLOSED = 40000, - + MHD_SC_CONNECTION_PARSE_FAIL_CLOSED = 40000 + , /** * MHD is closing a connection because it was reset. */ - MHD_SC_CONNECTION_RESET_CLOSED = 40001, - + MHD_SC_CONNECTION_RESET_CLOSED = 40001 + , /** * MHD is closing a connection because reading the * request failed. */ - MHD_SC_CONNECTION_READ_FAIL_CLOSED = 40002, - + MHD_SC_CONNECTION_READ_FAIL_CLOSED = 40002 + , /** * MHD is closing a connection because writing the response failed. */ - MHD_SC_CONNECTION_WRITE_FAIL_CLOSED = 40003, - + MHD_SC_CONNECTION_WRITE_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 = 40004 + , /** * An HTTP/1.1 request was sent without the "Host:" header. */ - MHD_SC_HOST_HEADER_MISSING = 40005, - + MHD_SC_HOST_HEADER_MISSING = 40005 + , /** * The given content length was not a number. */ - MHD_SC_CONTENT_LENGTH_MALFORMED = 40006, - + MHD_SC_CONTENT_LENGTH_MALFORMED = 40006 + , /** * The given uploaded, chunked-encoded body was malformed. */ - MHD_SC_CHUNKED_ENCODING_MALFORMED = 40007, - + MHD_SC_CHUNKED_ENCODING_MALFORMED = 40007 + , /* 50000-level errors are because of an error internal to the MHD logic, possibly including our interaction @@ -873,297 +1365,296 @@ enum MHD_StatusCode * This build of MHD does not support TLS, but the application * requested TLS. */ - MHD_SC_TLS_DISABLED = 50000, - + MHD_SC_TLS_DISABLED = 50000 + , /** * The application attempted to setup TLS parameters before * enabling TLS. */ - MHD_SC_TLS_BACKEND_UNINITIALIZED = 50003, - + MHD_SC_TLS_BACKEND_UNINITIALIZED = 50003 + , /** * The selected TLS backend does not yet support this operation. */ - MHD_SC_TLS_BACKEND_OPERATION_UNSUPPORTED = 50004, - + MHD_SC_TLS_BACKEND_OPERATION_UNSUPPORTED = 50004 + , /** * Failed to setup ITC channel. */ - MHD_SC_ITC_INITIALIZATION_FAILED = 50005, - + MHD_SC_ITC_INITIALIZATION_FAILED = 50005 + , /** * File descriptor for ITC channel too large. */ - MHD_SC_ITC_DESCRIPTOR_TOO_LARGE = 50006, - + MHD_SC_ITC_DESCRIPTOR_TOO_LARGE = 50006 + , /** * The specified value for the NC length is way too large * for this platform (integer overflow on `size_t`). */ - MHD_SC_DIGEST_AUTH_NC_LENGTH_TOO_BIG = 50007, - + MHD_SC_DIGEST_AUTH_NC_LENGTH_TOO_BIG = 50007 + , /** * We failed to allocate memory for the specified nonce * counter array. The option was not set. */ - MHD_SC_DIGEST_AUTH_NC_ALLOCATION_FAILURE = 50008, - + MHD_SC_DIGEST_AUTH_NC_ALLOCATION_FAILURE = 50008 + , /** * This build of the library does not support * digest authentication. */ - MHD_SC_DIGEST_AUTH_NOT_SUPPORTED_BY_BUILD = 50009, - + MHD_SC_DIGEST_AUTH_NOT_SUPPORTED_BY_BUILD = 50009 + , /** * IPv6 requested but not supported by this build. */ - MHD_SC_IPV6_NOT_SUPPORTED_BY_BUILD = 50010, - - /// FIXME: Similar to 60xxx??? + MHD_SC_IPV6_NOT_SUPPORTED_BY_BUILD = 50010 + , /** * We failed to open the listen socket. Maybe the build * supports IPv6, but your kernel does not? */ - MHD_SC_FAILED_TO_OPEN_LISTEN_SOCKET = 50011, - + MHD_SC_FAILED_TO_OPEN_LISTEN_SOCKET = 50011 + , /** * Specified address family is not supported by this build. */ - MHD_SC_AF_NOT_SUPPORTED_BY_BUILD = 50012, - + MHD_SC_AF_NOT_SUPPORTED_BY_BUILD = 50012 + , /** * Failed to enable listen address reuse. */ - MHD_SC_LISTEN_ADDRESS_REUSE_ENABLE_FAILED = 50013, - + MHD_SC_LISTEN_ADDRESS_REUSE_ENABLE_FAILED = 50013 + , /** * Enabling listen address reuse is not supported by this platform. */ - MHD_SC_LISTEN_ADDRESS_REUSE_ENABLE_NOT_SUPPORTED = 50014, - + MHD_SC_LISTEN_ADDRESS_REUSE_ENABLE_NOT_SUPPORTED = 50014 + , /** * Failed to disable listen address reuse. */ - MHD_SC_LISTEN_ADDRESS_REUSE_DISABLE_FAILED = 50015, - + MHD_SC_LISTEN_ADDRESS_REUSE_DISABLE_FAILED = 50015 + , /** * Disabling listen address reuse is not supported by this platform. */ - MHD_SC_LISTEN_ADDRESS_REUSE_DISABLE_NOT_SUPPORTED = 50016, - + MHD_SC_LISTEN_ADDRESS_REUSE_DISABLE_NOT_SUPPORTED = 50016 + , /** * We failed to explicitly enable or disable dual stack for * the IPv6 listen socket. The socket will be used in whatever * the default is the OS gives us. */ - MHD_SC_LISTEN_DUAL_STACK_CONFIGURATION_FAILED = 50017, - + MHD_SC_LISTEN_DUAL_STACK_CONFIGURATION_FAILED = 50017 + , /** * On this platform, MHD does not support explicitly configuring * dual stack behavior. */ - MHD_SC_LISTEN_DUAL_STACK_CONFIGURATION_NOT_SUPPORTED = 50018, - + MHD_SC_LISTEN_DUAL_STACK_CONFIGURATION_NOT_SUPPORTED = 50018 + , /** * Failed to enable TCP FAST OPEN option. */ - MHD_SC_FAST_OPEN_FAILURE = 50020, - + MHD_SC_FAST_OPEN_FAILURE = 50020 + , /** * Failed to start listening on listen socket. */ - MHD_SC_LISTEN_FAILURE = 50021, - + MHD_SC_LISTEN_FAILURE = 50021 + , /** * Failed to obtain our listen port via introspection. */ - MHD_SC_LISTEN_PORT_INTROSPECTION_FAILURE = 50022, - + MHD_SC_LISTEN_PORT_INTROSPECTION_FAILURE = 50022 + , /** * Failed to obtain our listen port via introspection * due to unsupported address family being used. */ - MHD_SC_LISTEN_PORT_INTROSPECTION_UNKNOWN_AF = 50023, - + MHD_SC_LISTEN_PORT_INTROSPECTION_UNKNOWN_AF = 50023 + , /** * We failed to set the listen socket to non-blocking. */ - MHD_SC_LISTEN_SOCKET_NONBLOCKING_FAILURE = 50024, - + MHD_SC_LISTEN_SOCKET_NONBLOCKING_FAILURE = 50024 + , /** * Listen socket value is too large (for use with select()). */ - MHD_SC_LISTEN_SOCKET_TOO_LARGE = 50025, - + MHD_SC_LISTEN_SOCKET_TOO_LARGE = 50025 + , /** * We failed to allocate memory for the thread pool. */ - MHD_SC_THREAD_POOL_MALLOC_FAILURE = 50026, - + MHD_SC_THREAD_POOL_MALLOC_FAILURE = 50026 + , /** * We failed to allocate mutex for thread pool worker. */ - MHD_SC_THREAD_POOL_CREATE_MUTEX_FAILURE = 50027, - + MHD_SC_THREAD_POOL_CREATE_MUTEX_FAILURE = 50027 + , /** * There was an attempt to upgrade a connection on * a daemon where upgrades are disallowed. */ - MHD_SC_UPGRADE_ON_DAEMON_WITH_UPGRADE_DISALLOWED = 50028, - + MHD_SC_UPGRADE_ON_DAEMON_WITH_UPGRADE_DISALLOWED = 50028 + , /** * Failed to signal via ITC channel. */ - MHD_SC_ITC_USE_FAILED = 50029, - + MHD_SC_ITC_USE_FAILED = 50029 + , /** * We failed to initialize the main thread for listening. */ - MHD_SC_THREAD_MAIN_LAUNCH_FAILURE = 50030, - + MHD_SC_THREAD_MAIN_LAUNCH_FAILURE = 50030 + , /** * We failed to initialize the threads for the worker pool. */ - MHD_SC_THREAD_POOL_LAUNCH_FAILURE = 50031, - + MHD_SC_THREAD_POOL_LAUNCH_FAILURE = 50031 + , /** * We failed to add a socket to the epoll() set. */ - MHD_SC_EPOLL_CTL_ADD_FAILED = 50032, - + MHD_SC_EPOLL_CTL_ADD_FAILED = 50032 + , /** * We failed to create control socket for the epoll(). */ - MHD_SC_EPOLL_CTL_CREATE_FAILED = 50034, - + MHD_SC_EPOLL_CTL_CREATE_FAILED = 50034 + , /** * We failed to configure control socket for the epoll() * to be non-inheritable. */ - MHD_SC_EPOLL_CTL_CONFIGURE_NOINHERIT_FAILED = 50035, - + MHD_SC_EPOLL_CTL_CONFIGURE_NOINHERIT_FAILED = 50035 + , /** * We failed to build the FD set because a socket was * outside of the permitted range. */ - MHD_SC_SOCKET_OUTSIDE_OF_FDSET_RANGE = 50036, - + MHD_SC_SOCKET_OUTSIDE_OF_FDSET_RANGE = 50036 + , /** * This daemon was not configured with options that * would allow us to build an FD set for select(). */ - MHD_SC_CONFIGURATION_MISMATCH_FOR_GET_FDSET = 50037, - + MHD_SC_CONFIGURATION_MISMATCH_FOR_GET_FDSET = 50037 + , /** * This daemon was not configured with options that * would allow us to obtain a meaningful timeout. */ - MHD_SC_CONFIGURATION_MISMATCH_FOR_GET_TIMEOUT = 50038, - + MHD_SC_CONFIGURATION_MISMATCH_FOR_GET_TIMEOUT = 50038 + , /** * This daemon was not configured with options that * would allow us to run with select() data. */ - MHD_SC_CONFIGURATION_MISMATCH_FOR_RUN_SELECT = 50039, - + MHD_SC_CONFIGURATION_MISMATCH_FOR_RUN_SELECT = 50039 + , /** * This daemon was not configured to run with an * external event loop. */ - MHD_SC_CONFIGURATION_MISMATCH_FOR_RUN_EXTERNAL = 50040, - + MHD_SC_CONFIGURATION_MISMATCH_FOR_RUN_EXTERNAL = 50040 + , /** * Encountered an unexpected event loop style * (should never happen). */ - MHD_SC_CONFIGURATION_UNEXPECTED_ELS = 50041, - + MHD_SC_CONFIGURATION_UNEXPECTED_ELS = 50041 + , /** * Encountered an unexpected error from select() * (should never happen). */ - MHD_SC_UNEXPECTED_SELECT_ERROR = 50042, - + MHD_SC_UNEXPECTED_SELECT_ERROR = 50042 + , /** * poll() is not supported. */ - MHD_SC_POLL_NOT_SUPPORTED = 50043, - + MHD_SC_POLL_NOT_SUPPORTED = 50043 + , /** * Encountered an unexpected error from poll() * (should never happen). */ - MHD_SC_UNEXPECTED_POLL_ERROR = 50044, - + MHD_SC_UNEXPECTED_POLL_ERROR = 50044 + , /** * We failed to configure accepted socket * to not use a signal pipe. */ - MHD_SC_ACCEPT_CONFIGURE_NOSIGPIPE_FAILED = 50045, - + MHD_SC_ACCEPT_CONFIGURE_NOSIGPIPE_FAILED = 50045 + , /** * Encountered an unexpected error from epoll_wait() * (should never happen). */ - MHD_SC_UNEXPECTED_EPOLL_WAIT_ERROR = 50046, - + MHD_SC_UNEXPECTED_EPOLL_WAIT_ERROR = 50046 + , /** * epoll file descriptor is invalid (strange) */ - MHD_SC_EPOLL_FD_INVALID = 50047, - + MHD_SC_EPOLL_FD_INVALID = 50047 + , /** * We failed to configure accepted socket * to be non-inheritable. */ - MHD_SC_ACCEPT_CONFIGURE_NOINHERIT_FAILED = 50048, - + MHD_SC_ACCEPT_CONFIGURE_NOINHERIT_FAILED = 50048 + , /** * We failed to configure accepted socket * to be non-blocking. */ - MHD_SC_ACCEPT_CONFIGURE_NONBLOCKING_FAILED = 50049, - + MHD_SC_ACCEPT_CONFIGURE_NONBLOCKING_FAILED = 50049 + , /** * accept() returned non-transient error. */ - MHD_SC_ACCEPT_FAILED_UNEXPECTEDLY = 50050, - + MHD_SC_ACCEPT_FAILED_UNEXPECTEDLY = 50050 + , /** * Operating resource limits hit on accept() while * zero connections are active. Oopsie. */ - MHD_SC_ACCEPT_SYSTEM_LIMIT_REACHED_INSTANTLY = 50051, - + MHD_SC_ACCEPT_SYSTEM_LIMIT_REACHED_INSTANTLY = 50051 + , /** * Failed to add IP address to per-IP counter for * some reason. */ - MHD_SC_IP_COUNTER_FAILURE = 50052, - + MHD_SC_IP_COUNTER_FAILURE = 50052 + , /** * Application violated our API by calling shutdown * while having an upgrade connection still open. */ - MHD_SC_SHUTDOWN_WITH_OPEN_UPGRADED_CONNECTION = 50053, - + MHD_SC_SHUTDOWN_WITH_OPEN_UPGRADED_CONNECTION = 50053 + , /** * Due to an unexpected internal error with the * state machine, we closed the connection. */ - MHD_SC_STATEMACHINE_FAILURE_CONNECTION_CLOSED = 50054, - + MHD_SC_STATEMACHINE_FAILURE_CONNECTION_CLOSED = 50054 + , /** * Failed to allocate memory in connection's pool * to parse the cookie header. */ - MHD_SC_COOKIE_POOL_ALLOCATION_FAILURE = 50055, - + MHD_SC_COOKIE_POOL_ALLOCATION_FAILURE = 50055 + , /** * MHD failed to build the response header. */ - MHD_SC_FAILED_RESPONSE_HEADER_GENERATION = 50056, - + MHD_SC_FAILED_RESPONSE_HEADER_GENERATION = 50056 + , /** * The feature is not supported by this MHD build (either * disabled by configure parameters or build platform @@ -1173,8 +1664,8 @@ enum MHD_StatusCode * will be run on another kernel, computer or system * configuration. */ - MHD_SC_FEATURE_DISABLED = 500057, - + MHD_SC_FEATURE_DISABLED = 500057 + , /** * The feature is not supported by this platform, while * supported by MHD build. @@ -1182,8 +1673,8 @@ enum MHD_StatusCode * running on another computer or with other system * configuration. */ - MHD_SC_FEATURE_NOT_AVAILABLE = 500058, - + MHD_SC_FEATURE_NOT_AVAILABLE = 500058 + , /* 60000-level errors are because the application logic did something wrong or generated an error. */ @@ -1192,63 +1683,62 @@ enum MHD_StatusCode * MHD does not support the requested combination of * EPOLL with thread-per-connection mode. */ - MHD_SC_SYSCALL_THREAD_COMBINATION_INVALID = 60000, - + MHD_SC_SYSCALL_THREAD_COMBINATION_INVALID = 60000 + , /** * MHD does not support quiescing if ITC was disabled * and threads are used. */ - MHD_SC_SYSCALL_QUIESCE_REQUIRES_ITC = 60001, - - // FIXME: similar to 50xxx??? + MHD_SC_SYSCALL_QUIESCE_REQUIRES_ITC = 60001 + , /** * We failed to bind the listen socket. */ - MHD_SC_LISTEN_SOCKET_BIND_FAILED = 60002, - + MHD_SC_LISTEN_SOCKET_BIND_FAILED = 60002 + , /** * The application requested an unsupported TLS backend to be used. */ - MHD_SC_TLS_BACKEND_UNSUPPORTED = 60003, - + MHD_SC_TLS_BACKEND_UNSUPPORTED = 60003 + , /** * The application requested a TLS cipher suite which is not * supported by the selected backend. */ - MHD_SC_TLS_CIPHERS_INVALID = 60004, - + MHD_SC_TLS_CIPHERS_INVALID = 60004 + , /** * MHD is closing a connection because the application * logic to generate the response data failed. */ - MHD_SC_APPLICATION_DATA_GENERATION_FAILURE_CLOSED = 60005, - + MHD_SC_APPLICATION_DATA_GENERATION_FAILURE_CLOSED = 60005 + , /** * MHD is closing a connection because the application * callback told it to do so. */ - MHD_SC_APPLICATION_CALLBACK_FAILURE_CLOSED = 60006, - + MHD_SC_APPLICATION_CALLBACK_FAILURE_CLOSED = 60006 + , /** * Application only partially processed upload and did * not suspend connection. This may result in a hung * connection. */ - MHD_SC_APPLICATION_HUNG_CONNECTION = 60007, - + MHD_SC_APPLICATION_HUNG_CONNECTION = 60007 + , /** * Application only partially processed upload and did * not suspend connection and the read buffer was maxxed * out, so MHD closed the connection. */ - MHD_SC_APPLICATION_HUNG_CONNECTION_CLOSED = 60008, - + MHD_SC_APPLICATION_HUNG_CONNECTION_CLOSED = 60008 + , /** * Application called function too late, for example because * MHD already changed state. */ - MHD_SC_TOO_LATE = 60009, - + MHD_SC_TOO_LATE = 60009 + , /** * Attempted to set an option that conflicts with another option * already set. @@ -1258,16 +1748,17 @@ enum MHD_StatusCode }; - -// FIXME: maybe not needed? Too large possibly? -enum MHD_Bool -MHD_status_code_is_fatal (enum MHD_StatusCode code) -MHD_FUNC_CONST_; - - -const struct MHD_String * +/** + * Get text description for the MHD error code. + * + * This function works for @b MHD error codes, not for @b HTTP status codes. + * @param code the MHD code to get description for + * @return the pointer to the text description, + * NULL if MHD code in not known. + */ +MHD_EXTERN_ const struct MHD_String * MHD_status_code_to_string (enum MHD_StatusCode code) -MHD_FUNC_CONST_ MHD_FUNC_RETURNS_NONNULL_; +MHD_FN_PURE_; /** * HTTP methods explicitly supported by MHD. Note that for @@ -1287,64 +1778,64 @@ MHD_FUNC_CONST_ MHD_FUNC_RETURNS_NONNULL_; * Registry Version 2015-05-19 * @{ */ -enum MHD_HTTP_Method +enum MHD_FIXED_ENUM_ MHD_HTTP_Method { /** * Method did not match any of the methods given below. */ - MHD_HTTP_METHOD_OTHER = 0, - + MHD_HTTP_METHOD_OTHER = 0 + , /* Main HTTP methods. */ /** * "GET" * Safe. Idempotent. RFC9110, Section 9.3.1. */ - MHD_HTTP_METHOD_GET = 1, - + MHD_HTTP_METHOD_GET = 1 + , /** * "HEAD" * Safe. Idempotent. RFC9110, Section 9.3.2. */ - MHD_HTTP_METHOD_HEAD = 2, - + MHD_HTTP_METHOD_HEAD = 2 + , /** * "POST" * Not safe. Not idempotent. RFC9110, Section 9.3.3. */ - MHD_HTTP_METHOD_POST = 3, - + MHD_HTTP_METHOD_POST = 3 + , /** * "PUT" * Not safe. Idempotent. RFC9110, Section 9.3.4. */ - MHD_HTTP_METHOD_PUT = 4, - + MHD_HTTP_METHOD_PUT = 4 + , /** * "DELETE" * Not safe. Idempotent. RFC9110, Section 9.3.5. */ - MHD_HTTP_METHOD_DELETE = 5, - + MHD_HTTP_METHOD_DELETE = 5 + , /** * "CONNECT" * Not safe. Not idempotent. RFC9110, Section 9.3.6. */ - MHD_HTTP_METHOD_CONNECT = 6, - + MHD_HTTP_METHOD_CONNECT = 6 + , /** * "OPTIONS" * Safe. Idempotent. RFC9110, Section 9.3.7. */ - MHD_HTTP_METHOD_OPTIONS = 7, - + MHD_HTTP_METHOD_OPTIONS = 7 + , /** * "TRACE" * Safe. Idempotent. RFC9110, Section 9.3.8. */ - MHD_HTTP_METHOD_TRACE = 8, - + MHD_HTTP_METHOD_TRACE = 8 + , /** * "*" * Not safe. Not idempotent. RFC9110, Section 18.2. @@ -1352,11 +1843,16 @@ enum MHD_HTTP_Method MHD_HTTP_METHOD_ASTERISK = 9 }; -// FIXME: added -// FIXME: return 'const char *'? -_MHD_EXTERN const struct MHD_String * -MHD_get_http_method_string (enum MHD_HTTP_Method method) -MHD_FUNC_CONST_; +/** + * Get text version of the method name. + * @param method the method to get the text version + * @return the pointer to the text version, + * NULL if method is MHD_HTTP_METHOD_OTHER + * or not known. + */ +MHD_EXTERN_ const struct MHD_String * +MHD_http_method_to_string (enum MHD_HTTP_Method method) +MHD_FN_PURE_; /** * @defgroup methods HTTP methods @@ -1383,6 +1879,8 @@ MHD_FUNC_CONST_; #define MHD_HTTP_METHOD_STR_OPTIONS "OPTIONS" /* Safe. Idempotent. RFC9110, Section 9.3.8. */ #define MHD_HTTP_METHOD_STR_TRACE "TRACE" +/* Not safe. Not idempotent. RFC9110, Section 18.2. */ +#define MHD_HTTP_METHOD_STR_ASTERISK "*" /* Additional HTTP methods. */ /* Not safe. Idempotent. RFC3744, Section 8.1. */ @@ -1447,40 +1945,38 @@ MHD_FUNC_CONST_; #define MHD_HTTP_METHOD_STR_UPDATEREDIRECTREF "UPDATEREDIRECTREF" /* Not safe. Idempotent. RFC3253, Section 3.5. */ #define MHD_HTTP_METHOD_STR_VERSION_CONTROL "VERSION-CONTROL" -/* Not safe. Not idempotent. RFC9110, Section 18.2. */ -#define MHD_HTTP_METHOD_STR_ASTERISK "*" /** @} */ /* end of group methods */ /** * @defgroup postenc HTTP POST encodings - * See also: http://www.w3.org/TR/html4/interact/forms.html#h-17.13.4 + * See also: https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#form-submission-2 * @{ */ -enum MHD_HTTP_PostEncoding +enum MHD_FIXED_ENUM_MHD_APP_SET_ MHD_HTTP_PostEncoding { /** * No post encoding / broken data / unknown encoding */ - MHD_HTTP_POST_ENCODING_OTHER = 0, - + MHD_HTTP_POST_ENCODING_OTHER = 0 + , /** * "application/x-www-form-urlencoded" * See https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#url-encoded-form-data * See https://url.spec.whatwg.org/#application/x-www-form-urlencoded * See https://datatracker.ietf.org/doc/html/rfc3986#section-2 */ - MHD_HTTP_POST_ENCODING_FORM_URLENCODED = 1, - + MHD_HTTP_POST_ENCODING_FORM_URLENCODED = 1 + , /** * "multipart/form-data" - * See https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#url-encoded-form-data + * See https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#multipart-form-data * See https://www.rfc-editor.org/rfc/rfc7578.html */ - MHD_HTTP_POST_ENCODING_MULTIPART_FORMDATA = 2, - + MHD_HTTP_POST_ENCODING_MULTIPART_FORMDATA = 2 + , /** * "text/plain" * Introduced by HTML5 @@ -2026,9 +2522,6 @@ enum MHD_HTTP_PostEncoding /** @} */ /* end of group headers */ -/* Forward declaration */ -struct MHD_Action; - /** * A client has requested the given url using the given method * (#MHD_HTTP_METHOD_GET, #MHD_HTTP_METHOD_PUT, @@ -2036,6 +2529,7 @@ struct MHD_Action; * * @param cls argument given together with the function * pointer when the handler was registered with MHD + * @param request the request object * @param path the requested uri (without arguments after "?") * @param method the HTTP method used (#MHD_HTTP_METHOD_GET, * #MHD_HTTP_METHOD_PUT, etc.) @@ -2049,7 +2543,7 @@ struct MHD_Action; * socket closure). */ typedef const struct MHD_Action * -(MHD_FUNC_PARAM_NONNULL_ (2) MHD_FUNC_PARAM_NONNULL_ (3) +(MHD_FN_PAR_NONNULL_ (2) MHD_FN_PAR_NONNULL_ (3) *MHD_RequestCallback)(void *cls, struct MHD_Request *request, const struct MHD_String *path, @@ -2059,30 +2553,36 @@ typedef const struct MHD_Action * /** * Create (but do not yet start) an MHD daemon. - * Usually, you will want to set various options before + * Usually, various options are set before * starting the daemon with #MHD_daemon_start(). * - * @param cb function to be called for incoming requests - * @param cb_cls closure for @a cb - * @return NULL on error + * @param req_cb the function to be called for incoming requests + * @param req_cb_cls the closure for @a cb + * @return the pointer to the new object on success, + * NULL on error (like out-of-memory) */ -_MHD_EXTERN struct MHD_Daemon * -MHD_daemon_create (MHD_RequestCallback cb, - void *cb_cls) -MHD_FUNC_PARAM_NONNULL_ (1); +MHD_EXTERN_ struct MHD_Daemon * +MHD_daemon_create (MHD_RequestCallback req_cb, + void *req_cb_cls) +MHD_FN_PAR_NONNULL_ (1) MHD_FN_PAR_IN_(1); /** * Start a webserver. + * This function: + * + checks the combination of set options, + * + initialises the TLS library (if TLS is requested), + * + creates the listen socket (if not provided and if allowed), + * + starts the daemon internal threads (if allowed) * * @param[in,out] daemon daemon to start; you can no longer set * options on this daemon after this call! * @return #MHD_SC_OK on success * @ingroup event */ -_MHD_EXTERN enum MHD_StatusCode +MHD_EXTERN_ enum MHD_StatusCode MHD_daemon_start (struct MHD_Daemon *daemon) -MHD_FUNC_PARAM_NONNULL_ (1); +MHD_FN_PAR_NONNULL_ (1); /** @@ -2094,20 +2594,15 @@ MHD_FUNC_PARAM_NONNULL_ (1); * #MHD_stop_daemon has been called (as it is theoretically possible * that an existing thread is still using it). * - * Note that some thread modes require the caller to have passed - * #MHD_USE_ITC when using this API. If this daemon is - * in one of those modes and this option was not given to - * #MHD_start_daemon, this function will return #MHD_INVALID_SOCKET. - * - * @param[in,out] daemon daemon to stop accepting new connections for - * @return old listen socket on success, #MHD_INVALID_SOCKET if + * @param[in,out] daemon the daemon to stop accepting new connections for + * @return the old listen socket on success, #MHD_INVALID_SOCKET if * the daemon was already not listening anymore, or - * was never started, or has not listen socket. + * was never started, or has no listen socket. * @ingroup specialized */ -_MHD_EXTERN MHD_socket +MHD_EXTERN_ MHD_socket MHD_daemon_quiesce (struct MHD_Daemon *daemon) -MHD_FUNC_PARAM_NONNULL_ALL_; +MHD_FN_PAR_NONNULL_ALL_ MHD_FN_PAR_INOUT_ (1); /** @@ -2116,498 +2611,750 @@ MHD_FUNC_PARAM_NONNULL_ALL_; * @param[in] daemon daemon to stop * @ingroup event */ -_MHD_EXTERN void +MHD_EXTERN_ void MHD_daemon_destroy (struct MHD_Daemon *daemon) -MHD_FUNC_PARAM_NONNULL_ALL_; - - -/* ********************* daemon options ************** */ - - -/** - * Type of a callback function used for logging by MHD. - * - * @param cls closure - * @param sc status code of the event - * @param fm format string (`printf()`-style) - * @param ap arguments to @a fm - * @ingroup logging - */ -typedef void -(*MHD_LoggingCallback)(void *cls, - enum MHD_StatusCode sc, - const char *fm, - va_list ap); - - -/** - * Set logging method. Specify NULL to disable logging entirely. By - * default (if this option is not given), we log error messages to - * stderr. - * - * Logging will not work if MHD was compiled with "--disable-logging". - * (The function will still be exported, but the @a logger will never - * be invoked.) - * - * @param[in,out] daemon which instance to setup logging for - * @param logger function to invoke - * @param logger_cls closure for @a logger - * @return #MHD_SC_FEATURE_DISABLED - */ -_MHD_EXTERN enum MHD_StatusCode -MHD_daemon_set_logger (struct MHD_Daemon *daemon, - MHD_LoggingCallback logger, - void *logger_cls) -MHD_FUNC_PARAM_NONNULL_ (1); +MHD_FN_PAR_NONNULL_ALL_; +/* ******************* External event loop ************************ */ /** - * Convenience macro used to disable logging. + * The network status of the socket. + * When set by MHD (by #MHD_get_watched_fds(), #MHD_get_watched_fds_update() and + * similar) it indicates a request to watch for specific socket state: + * readiness for receiving the data, readiness for sending the data and/or + * exception state of the socket. + * When set by application (and provided for #MHD_process_watched_fds() and + * similar) it must indicate the actual status of the socket. * - * @param daemon which instance to disable logging for + * Any actual state is a bitwise OR combination of #MHD_FD_STATE_RECV, + * #MHD_FD_STATE_SEND, #MHD_FD_STATE_EXCEPT. + * @ingroup event */ -#define MHD_daemon_disable_logging(daemon) \ - MHD_daemon_set_logger ((daemon), \ - NULL, \ - NULL) -// TODO: Sort values and assign numbers -enum MHD_DeamonOptionBool +enum MHD_FIXED_ENUM_ MHD_FdState { - // FIXME: edited names, shortened /** - * Suppresses use of "Date:" header. - * According to RFC should be used only if the system has no RTC. + * The socket is not ready for receiving or sending and + * does not have any exceptional state. + * The state never set by MHD, except de-registration of the sockets + * for #MHD_SocketRegistrationUpdateCallback(). */ - MHD_DAEMON_OB_SUPPRESS_DATE_HEADER = 1, + MHD_FD_STATE_NONE = 0 + , + /* ** Three bit-flags ** */ /** - * Disable use of inter-thread communication channel. - * #MHD_daemon_disable_itc() can be used with - * #MHD_daemon_thread_internal() to perform some additional - * optimizations (in particular, not creating a pipe for IPC - * signaling). If it is used, certain functions like - * #MHD_daemon_quiesce() or #MHD_daemon_add_connection() or - * #MHD_action_suspend() cannot be used anymore. - * #MHD_daemon_disable_itc() is not beneficial on platforms where - * select()/poll()/other signal shutdown() of a listen socket. - * - * You should only use this function if you are sure you do - * satisfy all of its requirements and need a generally minor - * boost in performance. + * Indicates that socket should be watched for incoming data + * (when set by #MHD_get_watched_fds()) + * / socket has incoming data ready to read (when used for + * #MHD_process_watched_fds()) */ - MHD_DAEMON_OB_SUPPRESS_ITC = 2, - + MHD_FD_STATE_RECV = 1 << 0, /** - * Enable `turbo`. Disables certain calls to `shutdown()`, - * enables aggressive non-blocking optimistic reads and - * other potentially unsafe optimizations. - * Most effects only happen with #MHD_USE_EPOLL. + * Indicates that socket should be watched for availability for sending + * (when set by #MHD_get_watched_fds()) + * / socket has ability to send data (when used for + * #MHD_process_watched_fds()) */ - MHD_DAEMON_OB_TURBO = 3, - + MHD_FD_STATE_SEND = 1 << 1, /** - * You need to set this option if you want to disable use of HTTP "Upgrade". - * "Upgrade" may require usage of additional internal resources, - * which we can avoid providing if they will not be used. - * - * You should only use this function if you are sure you do - * satisfy all of its requirements and need a generally minor - * boost in performance. + * Indicates that socket should be watched for disconnect, out-of-band + * data available or high priority data available (when set by + * #MHD_get_watched_fds()) + * / socket has been disconnected, has out-of-band data available or + * has high priority data available (when used for + * #MHD_process_watched_fds()). This status must not include "remote + * peer shut down writing" status. + * Note: #MHD_get_watched_fds() always set it as exceptions must be + * always watched. */ - MHD_DAEMON_OB_DISALLOW_UPGRADE, + MHD_FD_STATE_EXCEPT = 1 << 2, - /** - * Disable #MHD_action_suspend() functionality. - * - * You should only use this function if you are sure you do - * satisfy all of its requirements and need a generally minor - * boost in performance. + /* The rest of the list is a bit-wise combination of three main + * states. Application may use three main states directly as + * a bit-mask instead of using of following values */ - MHD_DAEMON_OB_DISALLOW_SUSPEND_RESUME, /** - * If present true, allow reusing address:port socket (by using - * SO_REUSEPORT on most platform, or platform-specific ways). If - * present and set to false, disallow reusing address:port socket - * (does nothing on most platform, but uses SO_EXCLUSIVEADDRUSE on - * Windows). - * Ineffective in conjunction with #MHD_daemon_listen_socket(). + * Combination of #MHD_FD_STATE_RECV and #MHD_FD_STATE_SEND states. */ - MHD_DAEMON_OB_LISTEN_ALLOW_ADDRESS_REUSE, - + MHD_FD_STATE_RECV_SEND = MHD_FD_STATE_RECV | MHD_FD_STATE_SEND, /** - * Use SHOUTcast. This will cause *all* responses to begin - * with the SHOUTcast "ICY" line instead of "HTTP". + * Combination of #MHD_FD_STATE_RECV and #MHD_FD_STATE_EXCEPT states. */ - MHD_DAEMON_OB_ENABLE_SHOUTCAST, - - // FIXME: Added + MHD_FD_STATE_RECV_EXCEPT = MHD_FD_STATE_RECV | MHD_FD_STATE_EXCEPT, + /** + * Combination of #MHD_FD_STATE_RECV and #MHD_FD_STATE_EXCEPT states. + */ + MHD_FD_STATE_SEND_EXCEPT = MHD_FD_STATE_RECV | MHD_FD_STATE_EXCEPT, /** - * Disable converting plus ('+') character to space in GET - * parameters (URI part after '?'). - * TODO: Add explanation, RFCs, HTML + * Combination of #MHD_FD_STATE_RECV, #MHD_FD_STATE_SEND and + * #MHD_FD_STATE_EXCEPT states. */ - MHD_DAEMON_OB_DISABLE_PLUS_SPACE + MHD_FD_STATE_RECV_SEND_EXCEPT = \ + MHD_FD_STATE_RECV | MHD_FD_STATE_SEND | MHD_FD_STATE_EXCEPT }; +/** + * Checks whether specific @a state is enabled in @a var + */ +#define MHD_FD_STATE_IS_SET(var,state) \ + (MHD_FD_STATE_NONE != \ + (((enum MHD_FdState) (var)) & ((enum MHD_FdState) (state)))) /** - * Set boolean MHD option. - * - * @param[in,out] daemon which instance to set boolean @a option for - * @param option option to modify - * @param value new value for the option - * @return #MHD_SC_OK on on success, - * #MHD_SC_TOO_LATE if this option was set after the daemon was started and it cannot be set anymore - * #MHD_SC_FEATURE_DISABLED if this option is not implemented in this version of the library, - * #MHD_SC_FEATURE_NOT_AVAILABLE if this options is not supported on this system - * #MHD_SC_OPTIONS_CONFLICT - */ -_MHD_EXTERN enum MHD_StatusCode -MHD_daemon_set_option_bool (struct MHD_Daemon *daemon, - enum MHD_DaemonOptionBool option, - enum MHD_Bool value) -MHD_FUNC_PARAM_NONNULL_ALL_ MHD_FUNC_MUST_CHECK_RESULT_; - - -#if PSEUDO - -#define MHD_daemon_set_option_shoutcast() \ - (struct MHD_DaemonOption) { \ - .type = MHD_DAEMON_OB_ENABLE_SHOUTCAST, \ - .details.shoutcast.value = true \ - } - -#define MHD_daemon_set_option_timeout(val) \ - (struct MHD_DaemonOption) { \ - .type = MHD_DAEMON_OB_CONNECTION_TIMEOUT, \ - .details.timeout.delay = val \ - } - -#define MHD_daemon_set_options(...) \ - MHD_daemon_set_options_ ((struct MHD_DaemonOption[]) { __VA_ARGS__, \ - MHD_daemon_set_options_end_ ()}) - - -main () -{ - // one at a time - assert (MHD_daemon_set_options (daemon, - MHD_daemon_set_option_timeout (42))); - // multiple at once - assert (MHD_daemon_set_options (daemon, - MHD_daemon_set_option_shoutcast (), - MHD_daemon_set_option_timeout (42))); - // manual build-up: - struct MHD_DaemonOption options[42]; - options[0] = MHD_daemon_set_option_timeout (42); - options[1] = MHD_daemon_set_option_shoutcast (); - options[2] = MHD_daemon_set_options_end_ (); - MHD_daemon_set_options_ (daemon, - options); -} + * Checks whether RECV is enabled in @a var + */ +#define MHD_FD_STATE_IS_SET_RECV(var) \ + MHD_FD_STATE_IS_SET ((var),MHD_FD_STATE_RECV) +/** + * Checks whether SEND is enabled in @a var + */ +#define MHD_FD_STATE_IS_SET_SEND(var) \ + MHD_FD_STATE_IS_SET ((var),MHD_FD_STATE_SEND) +/** + * Checks whether EXCEPT is enabled in @a var + */ +#define MHD_FD_STATE_IS_SET_EXCEPT(var) \ + MHD_FD_STATE_IS_SET ((var),MHD_FD_STATE_EXCEPT) -#endif +/** + * Enable specific @a state in @a var + */ +#define MHD_FD_STATE_SET(var,state) \ + (var) = (enum MHD_FdState) ((var) | (state)) +/** + * Enable RECV state in @a var + */ +#define MHD_FD_STATE_SET_RECV(var) MHD_FD_STATE_SET ((var),MHD_FD_STATE_RECV) +/** + * Enable SEND state in @a var + */ +#define MHD_FD_STATE_SET_SEND(var) MHD_FD_STATE_SET ((var),MHD_FD_STATE_SEND) +/** + * Enable EXCEPT state in @a var + */ +#define MHD_FD_STATE_SET_EXCEPT(var) \ + MHD_FD_STATE_SET ((var),MHD_FD_STATE_EXCEPT) /** - * Possible levels of enforcement for TCP_FASTOPEN. + * Clear/disable specific @a state in @a var */ -enum MHD_FastOpenOption -{ - /** - * Disable use of TCP_FASTOPEN. - */ - MHD_FOM_DISABLE = -1, +#define MHD_FD_STATE_CLEAR(var,state) \ + (var) = (enum MHD_FdState) ((var) & (((enum MHD_FdState))(~state))) +/** + * Clear/disable RECV state in @a var + */ +#define MHD_FD_STATE_CLEAR_RECV(var) \ + MHD_FD_STATE_CLEAR ((var),MHD_FD_STATE_RECV) +/** + * Clear/disable SEND state in @a var + */ +#define MHD_FD_STATE_CLEAR_SEND(var) \ + MHD_FD_STATE_CLEAR ((var),MHD_FD_STATE_SEND) +/** + * Clear/disable EXCEPT state in @a var + */ +#define MHD_FD_STATE_CLEAR_EXCEPT(var) \ + MHD_FD_STATE_CLEAR ((var),MHD_FD_STATE_EXCEPT) - /** - * Enable TCP_FASTOPEN where supported. - * On GNU/Linux it works with a kernel >= 3.6. - * This is the default. - */ - MHD_FOM_AUTO = 0, - /** - * If TCP_FASTOPEN is not available, return #MHD_NO. - * Also causes #MHD_daemon_start() to fail if setting - * the option fails later. - */ - MHD_FOM_REQUIRE = 1 -}; +/* Changes: + * + status update callback replaced with function + * + status update accepts array of updates + */ + +/** + * The context data to be used for updates of the socket state + */ +struct MHD_EventUpdateContext; +/* Define MHD_APP_SOCKET_CNTX_TYPE to the socket context type before + * including this header. + * This is optional, but improves the types safety. + * For example: + * #define MHD_APP_SOCKET_CNTX_TYPE struct my_structure + */ +#ifndef MHD_APP_SOCKET_CNTX_TYPE +# define MHD_APP_SOCKET_CNTX_TYPE void +#endif + /** - * Configure TCP_FASTOPEN option, including setting a - * custom @a queue_length. + * The callback for registration/de-registration of the sockets to watch. * - * Note that having a larger queue size can cause resource exhaustion - * attack as the TCP stack has to now allocate resources for the SYN - * packet along with its DATA. + * This callback must not call #MHD_daemon_destroy(), #MHD_daemon_quiesce(), + * #MHD_daemon_add_connection(). + * + * @param cls the closure + * @param fd the socket to watch + * @param watch_for the states of the @a fd to watch, if set to + * #MHD_FD_STATE_NONE the socket must be de-registred + * @param app_cntx_old the old application defined context for the socket, + * 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), + * or the new socket context + * @ingroup event + */ +typedef MHD_APP_SOCKET_CNTX_TYPE * +(MHD_FN_PAR_NONNULL_ (5) + *MHD_SocketRegistrationUpdateCallback)( + void *cls, + MHD_socket fd, + enum MHD_FdState watch_for, + MHD_APP_SOCKET_CNTX_TYPE *app_cntx_old, + struct MHD_EventUpdateContext *ecb_cntx); + + +/** + * Update the sockets state. + * Must be called for every socket that got state updated. + * For #MHD_TM_EXTERNAL_EVENT_LOOP_CB_LEVEL mode should be called for each + * socket. + * Available only for daemons stated in #MHD_TM_EXTERNAL_EVENT_LOOP_CB_LEVEL or + * #MHD_TM_EXTERNAL_EVENT_LOOP_CB_EDGE modes. + * @param daemon the daemon handle + * @param ecb_cntx the context handle provided + * for #MHD_SocketRegistrationUpdateCallback + * @param fd_current_state the current state of the socket + */ +MHD_EXTERN_ void +MHD_daemon_event_update ( + struct MHD_Daemon *daemon, + struct MHD_EventUpdateContext *ecb_cntx, + enum MHD_FdState fd_current_state) +MHD_FN_PAR_NONNULL_ (1) MHD_FN_PAR_NONNULL_ (2); + + +/** + * Perform sockets registration, process registered network events. + * + * This function first processes all registered (by MHD_daemon_event_update()) + * network events (if any) and then calls #MHD_SocketRegistrationUpdateCallback + * callback for every socket that needs to be added/updated/removed. * - * @param daemon which instance to configure TCP_FASTOPEN for - * @param fom under which conditions should we use TCP_FASTOPEN? - * @param queue_length queue length to use, default is 50 if this - * option is never given. - * @return #MHD_SC_OK on on success, - * #MHD_SC_TOO_LATE if this option was set after the daemon was started and it cannot be set anymore - * #MHD_SC_FEATURE_DISABLED, - * #MHD_SC_FEATURE_NOT_AVAILABLE, - * #MHD_SC_OPTIONS_CONFLICT + * Available only for daemons stated in #MHD_TM_EXTERNAL_EVENT_LOOP_CB_LEVEL or + * #MHD_TM_EXTERNAL_EVENT_LOOP_CB_EDGE modes. + * + * @param daemon the daemon handle + * @param[out] next_max_wait the optional pointer to receive the next maximum + * wait time in microseconds to be used for sockets + * polling function, can be NULL + * @return MHD_SC_OK on success, + * error code otherwise */ -_MHD_EXTERN enum MHD_StatusCode -MHD_daemon_set_option_tcp_fastopen (struct MHD_Daemon *daemon, - enum MHD_FastOpenOption option, - unsigned int queue_length) -MHD_FUNC_PARAM_NONNULL_ALL_ MHD_FUNC_MUST_CHECK_RESULT_; +MHD_EXTERN_ enum MHD_StatusCode +MHD_deamon_process_reg_events(struct MHD_Daemon *daemon, + uint_fast64_t *next_max_wait) +MHD_FN_PAR_NONNULL_ (1); + +/* ********************* daemon options ************** */ /** - * Address family to be used by MHD. + * Which threading and polling mode should be used by MHD? */ -enum MHD_AddressFamily +enum MHD_FIXED_ENUM_APP_SET_ MHD_WorkMode { /** - * Option not given, do not listen at all - * (unless listen socket or address specified by - * other means). + * Work mode with no internal threads. + * The application periodically calls #MHD_daemon_process_blocking(), where + * MHD internally checks all sockets automatically. + * This is the default mode. */ - MHD_AF_NONE = 0, - + MHD_WM_EXTERNAL_PERIODIC = 0 + , /** - * Pick "best" available method automatically. + * Work mode with an external event loop with level triggers. + * Application uses #MHD_SocketRegistrationUpdateCallback, level triggered + * sockets polling (like select() or poll()) and #MHD_daemon_event_update(). */ - MHD_AF_AUTO = 1, - + MHD_WM_EXTERNAL_EVENT_LOOP_CB_LEVEL = 8 + , /** - * Use IPv4. + * Work mode with an external event loop with edge triggers. + * Application uses #MHD_SocketRegistrationUpdateCallback, edge triggered + * sockets polling (like epoll with EPOLLET) and #MHD_daemon_event_update(). */ - MHD_AF_INET4 = 2, - + MHD_WM_EXTERNAL_EVENT_LOOP_CB_EDGE = 9 + , /** - * Use IPv6. + * Work mode with no internal threads and aggregate watch FD. + * Application uses #MHD_DAEMON_INFO_FIXED_AGGREAGATE_FD to get single FD + * that gets triggered by any MHD event. + * This FD can be watched as an aggregate indicator for all MHD events. + * This mode is available only on selected platforms (currently + * GNU/Linux only), see #MHD_LIB_INFO_FIXED_HAS_AGGREGATE_FD. + * When the FD is triggered, #MHD_daemon_process_nonblocking() should + * be called. */ - MHD_AF_INET6 = 3, - + MHD_WM_EXTERNAL_SINGLE_FD_WATCH = 16 + , /** - * Use dual stack. - */ - MHD_AF_DUAL = 4 -}; - + * Work mode with one or more worker threads. + * If #MHD_DAEMON_OPTION_UINT_NUM_WORKERS is not specified + * then daemon starts with single worker thread that process + * all connections. + * If #MHD_DAEMON_OPTION_UINT_NUM_WORKERS used with value more + * than one, then that number of worker threads and distributed + * processing of requests among the workers. + */ + MHD_WM_WORKER_THREADS = 24 + , + /** + * Work mode with one internal thread for listening and additional threads + * per every connection. Use this if handling requests is CPU-intensive or + * blocking, your application is thread-safe and you have plenty of + * memory (per connection). + */ + MHD_WM_THREAD_PER_CONNECTION = 32 +}; /** - * Bind to the given TCP port and address family. - * - * Ineffective in conjunction with #MHD_daemon_listen_socket(). - * Ineffective in conjunction with #MHD_daemon_bind_sa(). - * - * If neither this option nor the other two mentioned above - * is specified, MHD will simply not listen on any socket! - * - * @param[in,out] daemon which instance to configure the TCP port for - * @param af address family to use - * @param port port to use, 0 to bind to a random (free) port - * @return #MHD_SC_OK on on success, - * #MHD_SC_TOO_LATE if this option was set after the daemon was started and it cannot be set anymore - * #MHD_SC_FEATURE_DISABLED, - * #MHD_SC_FEATURE_NOT_AVAILABLE, - * #MHD_SC_OPTIONS_CONFLICT + * Work mode parameters for #MHD_WM_EXTERNAL_EVENT_LOOP_CB_LEVEL and + * #MHD_WM_EXTERNAL_EVENT_LOOP_CB_EDGE modes */ -_MHD_EXTERN enum MHD_StatusCode -MHD_daemon_bind_port (struct MHD_Daemon *daemon, - enum MHD_AddressFamily af, - uint16_t port) -MHD_FUNC_PARAM_NONNULL_ALL_ MHD_FUNC_MUST_CHECK_RESULT_; - +struct MHD_WorkModeExternalEventLoopCBParam +{ + /** + * Socket registration callback + */ + MHD_SocketRegistrationUpdateCallback reg_cb; + /** + * Closure for the @a reg_cb + */ + void *reg_cb_cls; +}; /** - * Bind to the given socket address. - * Ineffective in conjunction with #MHD_daemon_listen_socket(). - * - * @param[in,out] daemon which instance to configure the binding address for - * @param sa address to bind to; can be IPv4 (AF_INET), IPv6 (AF_INET6) - * or even a UNIX domain socket (AF_UNIX) - * @param sa_len number of bytes in @a sa - * @return #MHD_SC_OK on on success, - * #MHD_SC_TOO_LATE if this option was set after the daemon was started and it cannot be set anymore - * #MHD_SC_FEATURE_DISABLED, - * #MHD_SC_FEATURE_NOT_AVAILABLE, - * #MHD_SC_OPTIONS_CONFLICT + * MHD work mode parameters */ -_MHD_EXTERN enum MHD_StatusCode -MHD_daemon_bind_socket_address (struct MHD_Daemon *daemon, - const struct sockaddr *sa, - size_t sa_len) -MHD_FUNC_PARAM_NONNULL_ALL_ MHD_FUNC_MUST_CHECK_RESULT_; - -// TODO: Sort values and assign numbers -enum MHD_DeamonOptionUInt +union MHD_WorkModeParam { /** - * Use the given backlog for the listen() call. - * Ineffective in conjunction with #MHD_daemon_listen_socket() - */ - MHD_DAEMON_OPTION_UINT_LISTEN_BACKLOG, - /** - * Maximum number of (concurrent) network connections served - * by daemon + * Work mode parameters for #MHD_WM_EXTERNAL_EVENT_LOOP_CB_LEVEL and + * #MHD_WM_EXTERNAL_EVENT_LOOP_CB_EDGE modes */ - MHD_DAEMON_OPTION_UINT_GLOBAL_CONNECTION_LIMIT, + MHD_SocketRegistrationUpdateCallback v_external_event_loop_cb; /** - * Limit on the number of (concurrent) network connections - * made to the server from the same IP address. - * Can be used to prevent one IP from taking over all of - * the allowed connections. If the same IP tries to establish - * more than the specified number of connections, they will - * be immediately rejected. + * Number of worker threads for #MHD_WM_WORKER_THREADS. + * If set to one, then daemon starts with single worker thread that process + * all connections. + * If set to value larger than one, then that number of worker threads + * and distributed handling of requests among the workers. + * Zero is treated as one. */ - MHD_DAEMON_OPTION_UINT_IP_CONNECTION_LIMIT, + unsigned int num_worker_threads; +}; +/** + * Parameter for #MHD_DAEMON_OPTION_WORK_MODE(). + * Not recommended to be used directly, better use macro/functions to create it: + * #MHD_WM_OPTION_EXTERNAL_PERIODIC(), + * #MHD_WM_OPTION_EXTERNAL_EVENT_LOOP_CB_LEVEL(), + * #MHD_WM_OPTION_EXTERNAL_EVENT_LOOP_CB_EDGE(), + * #MHD_WM_OPTION_EXTERNAL_SINGLE_FD_WATCH(), + * #MHD_WM_OPTION_WORKER_THREADS(), + * #MHD_WM_OPTION_THREAD_PER_CONNECTION() + */ +struct MHD_WorkModeWithParam +{ /** - * After how many seconds of inactivity should a - * connection automatically be timed out? - * Use zero for no timeout, which is also the (unsafe!) default. + * The work mode for MHD */ - MHD_DAEMON_OPTION_UINT_DEFAULT_TIMEOUT, - + enum MHD_WorkMode mode; /** - * The number of worker threads. - * Only useful if the selected threading mode - * is #MHD_TM_WORKER_THREADS. - * Zero number is silently ignored. + * The parameters used for specified work mode */ - MHD_DAEMON_OPTION_UINT_NUM_WORKERS - + union MHD_WorkModeParam params; }; -// ADD - Discussed + +#if defined(MHD_USE_COMPOUND_LITERALS) && defined(MHD_USE_DESIG_NEST_INIT) +/** + * Create parameter for #MHD_DAEMON_OPTION_WORK_MODE() for work mode with + * no internal threads. + * The application periodically calls #MHD_daemon_process_blocking(), where + * MHD internally checks all sockets automatically. + * This is the default mode. + * @return the object of struct MHD_WorkModeWithParam with requested values + */ +# define MHD_WM_OPTION_EXTERNAL_PERIODIC() \ + MHD_NOWARN_COMPOUND_LITERALS_ \ + (const struct MHD_WorkModeWithParam) \ + { \ + .mode = (MHD_WM_EXTERNAL_PERIODIC) \ + } \ + MHD_RESTORE_WARN_COMPOUND_LITERALS_ + +/** + * Create parameter for #MHD_DAEMON_OPTION_WORK_MODE() for work mode with + * an external event loop with level triggers. + * Application uses #MHD_SocketRegistrationUpdateCallback, level triggered + * sockets polling (like select() or poll()) and #MHD_daemon_event_update(). + * @param cb_val the callback for sockets registration + * @param cb_cls_val the closure for the @a cv_val callback + * @return the object of struct MHD_WorkModeWithParam with requested values + */ +# define MHD_WM_OPTION_EXTERNAL_EVENT_LOOP_CB_LEVEL(cb_val,cb_cls_val) \ + MHD_NOWARN_COMPOUND_LITERALS_ \ + (const struct MHD_WorkModeWithParam) \ + { \ + .mode = (MHD_WM_EXTERNAL_EVENT_LOOP_CB_LEVEL), \ + .params.v_external_event_loop_cb.reg_cb = (cb_val), \ + .params.v_external_event_loop_cb.reg_cb_cls = (cb_cls_val) \ + } \ + MHD_RESTORE_WARN_COMPOUND_LITERALS_ + +/** + * Create parameter for #MHD_DAEMON_OPTION_WORK_MODE() for work mode with + * an external event loop with edge triggers. + * Application uses #MHD_SocketRegistrationUpdateCallback, edge triggered + * sockets polling (like epoll with EPOLLET) and #MHD_daemon_event_update(). + * @param cb_val the callback for sockets registration + * @param cb_cls_val the closure for the @a cv_val callback + * @return the object of struct MHD_WorkModeWithParam with requested values + */ +# define MHD_WM_OPTION_EXTERNAL_EVENT_LOOP_CB_EDGE(cb_val,cb_cls_val) \ + MHD_NOWARN_COMPOUND_LITERALS_ \ + (const struct MHD_WorkModeWithParam) \ + { \ + .mode = (MHD_WM_EXTERNAL_EVENT_LOOP_CB_EDGE), \ + .params.v_external_event_loop_cb.reg_cb = (cb_val), \ + .params.v_external_event_loop_cb.reg_cb_cls = (cb_cls_val) \ + } \ + MHD_RESTORE_WARN_COMPOUND_LITERALS_ + +/** + * Create parameter for #MHD_DAEMON_OPTION_WORK_MODE() for work mode with + * no internal threads and aggregate watch FD. + * Application uses #MHD_DAEMON_INFO_FIXED_AGGREAGATE_FD to get single FD + * that gets triggered by any MHD event. + * This FD can be watched as an aggregate indicator for all MHD events. + * This mode is available only on selected platforms (currently + * GNU/Linux only), see #MHD_LIB_INFO_FIXED_HAS_AGGREGATE_FD. + * When the FD is triggered, #MHD_daemon_process_nonblocking() should + * be called. + * @return the object of struct MHD_WorkModeWithParam with requested values + */ +# define MHD_WM_OPTION_EXTERNAL_SINGLE_FD_WATCH() \ + MHD_NOWARN_COMPOUND_LITERALS_ \ + (const struct MHD_WorkModeWithParam) \ + { \ + .mode = (MHD_WM_EXTERNAL_SINGLE_FD_WATCH) \ + } \ + MHD_RESTORE_WARN_COMPOUND_LITERALS_ + +/** + * Create parameter for #MHD_DAEMON_OPTION_WORK_MODE() for work mode with + * one or more worker threads. + * If number of threads is one, then daemon starts with single worker thread + * that handles all connections. + * If number of threads is larger than one, then that number of worker threads, + * and handling of connection is distributed among the workers. + * @param num_workers the number of worker threads, zero is treated as one + * @return the object of struct MHD_WorkModeWithParam with requested values + */ +# define MHD_WM_OPTION_WORKER_THREADS(num_workers) \ + MHD_NOWARN_COMPOUND_LITERALS_ \ + (const struct MHD_WorkModeWithParam) \ + { \ + .mode = (MHD_WM_WORKER_THREADS), \ + .params.num_worker_threads = (num_workers) \ + } \ + MHD_RESTORE_WARN_COMPOUND_LITERALS_ + +/** + * Create parameter for #MHD_DAEMON_OPTION_WORK_MODE() for work mode with + * one internal thread for listening and additional threads per every + * connection. Use this if handling requests is CPU-intensive or blocking, + * your application is thread-safe and you have plenty of memory (per + * connection). + * @return the object of struct MHD_WorkModeWithParam with requested values + */ +# define MHD_WM_OPTION_THREAD_PER_CONNECTION() \ + MHD_NOWARN_COMPOUND_LITERALS_ \ + (const struct MHD_WorkModeWithParam) \ + { \ + .mode = (MHD_WM_THREAD_PER_CONNECTION) \ + } \ + MHD_RESTORE_WARN_COMPOUND_LITERALS_ + +#else /* !MHD_USE_COMPOUND_LITERALS || !MHD_USE_DESIG_NEST_INIT */ +MHD_NOWARN_UNUSED_FUNC_ + +/** + * Create parameter for #MHD_DAEMON_OPTION_WORK_MODE() for work mode with + * no internal threads. + * The application periodically calls #MHD_daemon_process_blocking(), where + * MHD internally checks all sockets automatically. + * This is the default mode. + * @return the object of struct MHD_WorkModeWithParam with requested values + */ +static MHD_INLINE struct MHD_WorkModeWithParam +MHD_WM_OPTION_EXTERNAL_PERIODIC (void) +{ + struct MHD_WorkModeWithParam wm_val; + + wm_val.mode = MHD_WM_EXTERNAL_PERIODIC; + + return wm_val; +} + + /** - * Set unsigned integer MHD option. - * - * @param[in,out] daemon which instance to set uint @a option for - * @param option option to modify - * @param value new value for the option - * @return #MHD_SC_OK on on success, - * #MHD_SC_TOO_LATE if this option was set after the daemon was started and it cannot be set anymore - * #MHD_SC_FEATURE_DISABLED if this option is not implemented in this version of the library, - * #MHD_SC_FEATURE_NOT_AVAILABLE if this options is not supported on this system - * #MHD_SC_OPTIONS_CONFLICT + * Create parameter for #MHD_DAEMON_OPTION_WORK_MODE() for work mode with + * an external event loop with level triggers. + * Application uses #MHD_SocketRegistrationUpdateCallback, level triggered + * sockets polling (like select() or poll()) and #MHD_daemon_event_update(). + * @param cb_val the callback for sockets registration + * @param cb_cls_val the closure for the @a cv_val callback + * @return the object of struct MHD_WorkModeWithParam with requested values + */ +static MHD_INLINE struct MHD_WorkModeWithParam +MHD_WM_OPTION_EXTERNAL_EVENT_LOOP_CB_LEVEL ( + MHD_SocketRegistrationUpdateCallback cb_val, + void *cb_cls_val) +{ + struct MHD_WorkModeWithParam wm_val; + + wm_val.mode = MHD_WM_EXTERNAL_EVENT_LOOP_CB_LEVEL; + wm_val.params.v_external_event_loop_cb.reg_cb = cb_val; + wm_val.params.v_external_event_loop_cb.reg_cb_cls = cb_cls_val; + + return wm_val; +} + + +/** + * Create parameter for #MHD_DAEMON_OPTION_WORK_MODE() for work mode with + * an external event loop with edge triggers. + * Application uses #MHD_SocketRegistrationUpdateCallback, edge triggered + * sockets polling (like epoll with EPOLLET) and #MHD_daemon_event_update(). + * @param cb_val the callback for sockets registration + * @param cb_cls_val the closure for the @a cv_val callback + * @return the object of struct MHD_WorkModeWithParam with requested values + */ +static MHD_INLINE struct MHD_WorkModeWithParam +MHD_WM_OPTION_EXTERNAL_EVENT_LOOP_CB_EDGE ( + MHD_SocketRegistrationUpdateCallback cb_val, + void *cb_cls_val) +{ + struct MHD_WorkModeWithParam wm_val; + + wm_val.mode = MHD_WM_EXTERNAL_EVENT_LOOP_CB_EDGE; + wm_val.params.v_external_event_loop_cb.reg_cb = cb_val; + wm_val.params.v_external_event_loop_cb.reg_cb_cls = cb_cls_val; + + return wm_val; +} + + +/** + * Create parameter for #MHD_DAEMON_OPTION_WORK_MODE() for work mode with + * no internal threads and aggregate watch FD. + * Application uses #MHD_DAEMON_INFO_FIXED_AGGREAGATE_FD to get single FD + * that gets triggered by any MHD event. + * This FD can be watched as an aggregate indicator for all MHD events. + * This mode is available only on selected platforms (currently + * GNU/Linux only), see #MHD_LIB_INFO_FIXED_HAS_AGGREGATE_FD. + * When the FD is triggered, #MHD_daemon_process_nonblocking() should + * be called. + * @return the object of struct MHD_WorkModeWithParam with requested values + */ +static MHD_INLINE struct MHD_WorkModeWithParam +MHD_WM_OPTION_EXTERNAL_SINGLE_FD_WATCH (void) +{ + struct MHD_WorkModeWithParam wm_val; + + wm_val.mode = MHD_WM_EXTERNAL_SINGLE_FD_WATCH; + + return wm_val; +} + + +/** + * Create parameter for #MHD_DAEMON_OPTION_WORK_MODE() for work mode with + * one or more worker threads. + * If number of threads is one, then daemon starts with single worker thread + * that handles all connections. + * If number of threads is larger than one, then that number of worker threads, + * and handling of connection is distributed among the workers. + * @param num_workers the number of worker threads, zero is treated as one + * @return the object of struct MHD_WorkModeWithParam with requested values + */ +static MHD_INLINE struct MHD_WorkModeWithParam +MHD_WM_OPTION_WORKER_THREADS (unsigned int num_workers) +{ + struct MHD_WorkModeWithParam wm_val; + + wm_val.mode = MHD_WM_EXTERNAL_EVENT_LOOP_CB_EDGE; + wm_val.params.num_worker_threads = num_workers; + + return wm_val; +} + + +/** + * Create parameter for #MHD_DAEMON_OPTION_WORK_MODE() for work mode with + * one internal thread for listening and additional threads per every + * connection. Use this if handling requests is CPU-intensive or blocking, + * your application is thread-safe and you have plenty of memory (per + * connection). + * @return the object of struct MHD_WorkModeWithParam with requested values */ -_MHD_EXTERN enum MHD_StatusCode -MHD_daemon_set_option_uint (struct MHD_Daemon *daemon, - enum MHD_DeamonOptionUInt option, - unsigned int value) -MHD_FUNC_PARAM_NONNULL_ (1); +static MHD_INLINE struct MHD_WorkModeWithParam +MHD_WM_OPTION_THREAD_PER_CONNECTION (void) +{ + struct MHD_WorkModeWithParam wm_val; + + wm_val.mode = MHD_WM_THREAD_PER_CONNECTION; + + return wm_val; +} -// FIXME: Alternative or additional implementation. -struct MHD_DaemonOptioniUIntEntry +MHD_RESTORE_WARN_UNUSED_FUNC_ +#endif /* !MHD_USE_COMPOUND_LITERALS || !MHD_USE_DESIG_NEST_INIT */ + + +/** + * Type of a callback function used for logging by MHD. + * + * @param cls closure + * @param sc status code of the event + * @param fm format string (`printf()`-style) + * @param ap arguments to @a fm + * @ingroup logging + */ +typedef void +(MHD_FN_PAR_NONNULL_ (3) + MHD_FN_PAR_CSTR_ (3) + *MHD_LoggingCallback)(void *cls, + enum MHD_StatusCode sc, + const char *fm, + va_list ap); + +/** + * Parameter for listen socket binding type + */ +enum MHD_FIXED_ENUM_APP_SET_ MHD_DaemonOptionBindType { /** - * The option to update the @a value + * The listen socket bind to the networks address without sharing the address. + * Default. + */ + MHD_DAEMON_OPTION_BIND_TYPE_NOT_SHARED = 0 + , + /** + * The listen socket bind to the networks address with sharing the address. + * Several sockets can bind to the same address. */ - enum MHD_DeamonOptionUInt option; + MHD_DAEMON_OPTION_BIND_TYPE_SHARED = 1 + , /** - * The value to update for the @a option + * The list socket bind to the networks address in explicit exclusive mode. + * Ignored on platforms without support for the explicit exclusive socket use. */ - unsigned int value; - // TODO: union + MHD_DAEMON_OPTION_BIND_TYPE_EXCLUSIVE = 2 }; + /** - * Set unsigned integer MHD options. - * - * @param[in,out] daemon which instance to set uint @a option for - * @param num_entries the number of entries in the @a opt_val array - * and in @a results (if not NULL) - * @param[in] opt_val the array with options and values to modify - * @param[out] results the results for the applying the options, - * can be NULL, - * if not NULL must have @a num_entries entries - * @return #MHD_YES if all options have applied successfully - * #MHD_NO if at least single option failed (for more - * details check @a results) + * Possible levels of enforcement for TCP_FASTOPEN. */ -_MHD_EXTERN enum MHD_StatusCode // First failed // TODO: Document that rest may be used -MHD_daemon_set_option_uint ( - struct MHD_Daemon *daemon, - size_t num_entries, - struct MHD_DaemonOptioniUIntEntry opt_val[MHD_C99_ (static num_entries)]) -MHD_FUNC_PARAM_NONNULL_ (1) MHD_FUNC_PARAM_NONNULL_ (3); +enum MHD_FIXED_ENUM_APP_SET_ MHD_TCPFastOpenType +{ + /** + * Disable use of TCP_FASTOPEN. + */ + MHD_FOM_DISABLE = -1 + , + /** + * Enable TCP_FASTOPEN where supported. + * On GNU/Linux it works with a kernel >= 3.6. + * This is the default. + */ + MHD_FOM_AUTO = 0 + , + /** + * Require TCP_FASTOPEN. + * Also causes #MHD_daemon_start() to fail if setting + * the option fails later. + */ + MHD_FOM_REQUIRE = 1 +}; + -// TODO: combine all types of options into single list with union /** - * Accept connections from the given socket. Socket - * must be a TCP or UNIX domain (stream) socket. - * - * Unless MHD_INVALID_SOCKET is given, this disables - * other listen options. - * - * @param daemon daemon to set listen socket for - * @param listen_socket listen socket to use, - * MHD_INVALID_SOCKET value will cause this call to be - * ignored (other binding options may still be effective) - * @return #MHD_SC_OK on on success, - * #MHD_SC_TOO_LATE if this option was set after the daemon was started and it cannot be set anymore - * #MHD_SC_FEATURE_DISABLED if this option is not implemented in this version of the library, - * #MHD_SC_FEATURE_NOT_AVAILABLE if this options is not supported on this system - * #MHD_SC_OPTIONS_CONFLICT + * Address family to be used by MHD. */ -_MHD_EXTERN enum MHD_StatusCode -MHD_daemon_listen_socket (struct MHD_Daemon *daemon, - MHD_socket listen_socket) -MHD_FUNC_PARAM_NONNULL_ (1); +enum MHD_FIXED_ENUM_APP_SET_ MHD_AddressFamily +{ + /** + * Option not given, do not listen at all + * (unless listen socket or address specified by + * other means). + */ + MHD_AF_NONE = 0 + , + /** + * Pick "best" available method automatically. + */ + MHD_AF_AUTO = 1 + , + /** + * Use IPv4. + */ + MHD_AF_INET4 = 2 + , + /** + * Use IPv6. + */ + MHD_AF_INET6 = 3 + , + /** + * Use dual stack. + */ + MHD_AF_DUAL = 4 +}; + /** - * Event loop internal syscalls supported by MHD. + * Sockets polling internal syscalls used by MHD. */ -enum MHD_EventLoopSyscall +enum MHD_FIXED_ENUM_APP_SET_ MHD_SockPollSyscall { /** * Automatic selection of best-available method. This is also the * default. */ - MHD_ELS_AUTO = 0, - + MHD_ELS_AUTO = 0 + , /** * Use select(). */ - MHD_ELS_SELECT = 1, - + MHD_ELS_SELECT = 1 + , /** * Use poll(). */ - MHD_ELS_POLL = 2, - + MHD_ELS_POLL = 2 + , /** - * Use epoll(). + * Use epoll. */ MHD_ELS_EPOLL = 3 }; /** - * Force use of a particular event loop system call. - * - * @param daemon daemon to set event loop style for - * @param els event loop syscall to use - * @return #MHD_SC_OK on on success, - * #MHD_SC_TOO_LATE if this option was set after the daemon was started and it cannot be set anymore - * #MHD_SC_FEATURE_DISABLED if this option is not implemented in this version of the library, - * #MHD_SC_FEATURE_NOT_AVAILABLE if this options is not supported on this system - * #MHD_SC_OPTIONS_CONFLICT - */ -_MHD_EXTERN enum MHD_StatusCode // FIXME - corrected -MHD_daemon_event_loop (struct MHD_Daemon *daemon, - enum MHD_EventLoopSyscall els) -MHD_FUNC_PARAM_NONNULL_ (1); - - -/** * Protocol strictness enforced by MHD on clients. * All levels have different parsing settings for the headers. */ -enum MHD_ProtocolStrictLevel +enum MHD_FIXED_ENUM_APP_SET_ MHD_ProtocolStrictLevel { /* * Basic levels * */ @@ -2616,8 +3363,8 @@ enum MHD_ProtocolStrictLevel * A balance between extra security and broader compatibility, * as allowed by RFCs for HTTP servers. */ - MHD_PSL_DEFAULT = 0, - + MHD_PSL_DEFAULT = 0 + , /** * Be strict about the protocol (as opposed to as tolerant as * possible), within the limits set by RFCs for HTTP servers. @@ -2626,8 +3373,8 @@ enum MHD_ProtocolStrictLevel * and "Content-Length:". * It is suitable for public servers. */ - MHD_PSL_STRICT = 1, - + MHD_PSL_STRICT = 1 + , /** * Be particularly permissive about the protocol, within * the limits set by RFCs for HTTP servers. @@ -2650,8 +3397,8 @@ enum MHD_ProtocolStrictLevel * MHD. Also can be used for security-centric application, * however it is slight violation of RFCs' requirements. */ - MHD_PSL_VERY_STRICT = 2, - + MHD_PSL_VERY_STRICT = 2 + , /** * The most strict interpretation of the HTTP protocol, * much stricter that defined for HTTP servers by RFC. @@ -2663,11 +3410,11 @@ enum MHD_ProtocolStrictLevel * reject legitimate clients (clients not following "SHOULD" * type of RFC requirements). */ - MHD_PSL_EXTRA_STRICT = 3, - + MHD_PSL_EXTRA_STRICT = 3 + , /** * More relaxed protocol interpretation, violating RFCs' - * "SHOULD" type of requirements for HTTP servers. + * "SHOULD" type of restrictions for HTTP servers. * For cookies parsing this (and more permissive) level * allows whitespaces in cookie values. * This level can be used in isolated environments. @@ -2676,7 +3423,7 @@ enum MHD_ProtocolStrictLevel /** * The most flexible protocol interpretation, beyond - * RFCs' "MUST" type of requirements for HTTP server. + * RFCs' "MUST" type of restrictions for HTTP server. * The level allow HTTP/1.1 requests without "Host:" header. * For cookies parsing this level adds allowance of * whitespaces before and after '=' character. @@ -2692,19 +3439,22 @@ enum MHD_ProtocolStrictLevel * MHD can be compiled with limited set of strictness levels. * These values instructs MHD how to apply the request level. */ -enum MHD_UseStictLevel +enum MHD_FIXED_ENUM_APP_SET_ MHD_UseStictLevel { /** * Use requested level if available or the nearest stricter * level. * Fail if only more permissive levels available. + * Recommended value. */ - MHD_USL_THIS_OR_STRICTER = 0, + MHD_USL_THIS_OR_STRICTER = 0 + , /** * Use requested level only. * Fail if this level is not available. */ - MHD_USL_PRECISE = 1, + MHD_USL_PRECISE = 1 + , /** * Use requested level if available or the nearest level (stricter * or more permissive). @@ -2712,102 +3462,25 @@ enum MHD_UseStictLevel MHD_USL_NEAREST = 2 }; -/** - * Set how strictly MHD will enforce the HTTP protocol. - * - * @param[in,out] daemon daemon to configure strictness for - * @param sl the level of strictness - * @param how the way how to use the requested level - * @return #MHD_SC_OK on on success, - * #MHD_SC_TOO_LATE if this option was set after the daemon was started and it cannot be set anymore - * #MHD_SC_FEATURE_DISABLED if this option is not implemented in this version of the library, - */ -_MHD_EXTERN enum MHD_StatusCode -MHD_daemon_protocol_strict_level (struct MHD_Daemon *daemon, - enum MHD_ProtocolStrictLevel sl, - enum MHD_UseStictLevel how) -MHD_FUNC_PARAM_NONNULL_ (1); - -// FIXME: do we want to keep it as generic API? -// FIXME: other TLS backends will not support it. -// TODO: remove and use low-level from callback -// + TLS ciphers -// + 'application name' for lookup -// of TLS cipher option in configuration file. -// ciphers which ciphers should be used by TLS, default is -// "NORMAL" -_MHD_EXTERN enum MHD_StatusCode -MHD_daemon_set_option_string (struct MHD_Daemon *daemon, - enum foo, - const char *value) -MHD_FUNC_PARAM_NONNULL_ (1); - -// TODO: three options -/** - * Provide TLS key and certificate data in-memory. - * - * @param daemon which instance should be configured - * @param mem_key private key (key.pem) to be used by the - * HTTPS daemon. Must be the actual data in-memory, not a filename. - * @param mem_cert certificate (cert.pem) to be used by the - * HTTPS daemon. Must be the actual data in-memory, not a filename. - * @param pass passphrase phrase to decrypt 'key.pem', NULL - * if @param mem_key is in cleartext already - * @return #MHD_SC_OK upon success; TODO: define failure modes - */ -_MHD_EXTERN enum MHD_StatusCode -MHD_daemon_tls_key_and_cert_from_memory (struct MHD_Daemon *daemon, - const char *mem_key, - const char *mem_cert, - const char *pass) -MHD_FUNC_PARAM_NONNULL_ (1) MHD_FUNC_PARAM_NONNULL_ (2) -MHD_FUNC_PARAM_NONNULL_ (3); - - -/** - * Configure DH parameters (dh.pem) to use for the TLS key - * exchange. - * - * @param daemon daemon to configure tls for - * @param dh parameters to use - * @return #MHD_SC_OK upon success; TODO: define failure modes - */ -_MHD_EXTERN enum MHD_StatusCode -MHD_daemon_tls_mem_dhparams (struct MHD_Daemon *daemon, - const char *dh) -MHD_FUNC_PARAM_NONNULL_ (1); - -/** - * Memory pointer for the certificate (ca.pem) to be used by the - * HTTPS daemon for client authentication. - * - * @param daemon daemon to configure tls for - * @param mem_trust memory pointer to the certificate - * @return #MHD_SC_OK upon success; TODO: define failure modes - */ -_MHD_EXTERN enum MHD_StatusCode -MHD_daemon_tls_mem_trust (struct MHD_Daemon *daemon, - const char *mem_trust) -MHD_FUNC_PARAM_NONNULL_ (1); - - /* ********************** (d) TLS support ********************** */ /** * The TLS backend choice */ -enum MHD_TlsBackend +enum MHD_FIXED_ENUM_APP_SET_ MHD_TlsBackend { /** - * TODO add descr + * Disable TLS, use plain TCP connections */ - MHD_TLS_BACKEND_NONE = 0, + MHD_TLS_BACKEND_NONE = 0 + , /** * Use best available TLS backend. * Currently this is equivalent to GnuTLS (if TLS is enabled * for MHD build). */ - MHD_TLS_BACKEND_ANY = 1, + MHD_TLS_BACKEND_ANY = 1 + , /** * Use GnuTLS as TLS backend. */ @@ -2815,22 +3488,68 @@ enum MHD_TlsBackend }; /** - * Enable and configure TLS. + * Values for #MHD_OPTION_DIGEST_AUTH_NONCE_BIND_TYPE. * - * @param daemon which instance should be configured - * @param tls_backend which TLS backend should be used, - * currently only "gnutls" is supported. You can - * also specify NULL for best-available (which is the default). - * @return status code, #MHD_SC_OK upon success - * #MHD_TLS_BACKEND_UNSUPPORTED if the @a backend is unknown - * #MHD_TLS_DISABLED if this build of MHD does not support TLS - * #MHD_TLS_CIPHERS_INVALID if the given @a ciphers are not supported - * by this backend + * These values can limit the scope of validity of MHD-generated nonces. + * Values can be combined with bitwise OR. + * Any value, except #MHD_DAUTH_BIND_NONCE_NONE, enforce function + * #MHD_digest_auth_check() (and similar functions) to check nonce by + * re-generating it again with the same parameters, which is CPU-intensive + * operation. */ -_MHD_EXTERN enum MHD_StatusCode -MHD_daemon_set_tls_backend (struct MHD_Daemon *daemon, - enum MHD_TlsBackend backend) -MHD_FUNC_PARAM_NONNULL_ (1); +enum MHD_FIXED_FLAGS_ENUM_APP_SET_ MHD_DaemonOptionValueDAuthBindNonce +{ + /** + * Generated nonces are valid for any request from any client until expired. + * This is default and recommended value. + * #MHD_digest_auth_check3() (and similar functions) would check only whether + * the nonce value that is used by client has been generated by MHD and not + * expired yet. + * It is recommended because RFC 7616 allows clients to use the same nonce + * for any request in the same "protection space". + * When checking client's authorisation requests CPU is loaded less if this + * value is used. + * This mode gives MHD maximum flexibility for nonces generation and can + * prevent possible nonce collisions (and corresponding log warning messages) + * when clients' requests are intensive. + * This value cannot be biwise-OR combined with other values. + */ + MHD_DAEMON_OPTION_VALUE_DAUTH_BIND_NONCE_NONE = 0, + + /** + * Generated nonces are valid only for the same realm. + */ + MHD_DAEMON_OPTION_VALUE_DAUTH_BIND_NONCE_REALM = 1 << 0, + + /** + * Generated nonces are valid only for the same URI (excluding parameters + * after '?' in URI) and request method (GET, POST etc). + * Not recommended unless "protection space" is limited to a single URI as + * RFC 7616 allows clients to re-use server-generated nonces for any URI + * in the same "protection space" which by default consists of all server + * URIs. + * Before #MHD_VERSION 0x00097701 this was default (and only supported) + * nonce bind type. + */ + MHD_DAEMON_OPTION_VALUE_DAUTH_BIND_NONCE_URI = 1 << 1, + + /** + * Generated nonces are valid only for the same URI including URI parameters + * and request method (GET, POST etc). + * This value implies #MHD_DAUTH_BIND_NONCE_URI. + * Not recommended for that same reasons as #MHD_DAUTH_BIND_NONCE_URI. + */ + MHD_DAEMON_OPTION_VALUE_DAUTH_BIND_NONCE_URI_PARAMS = 1 << 2, + + /** + * Generated nonces are valid only for the single client's IP. + * While it looks like security improvement, in practice the same client may + * jump from one IP to another (mobile or Wi-Fi handover, DHCP re-assignment, + * Multi-NAT, different proxy chain and other reasons), while IP address + * spoofing could be used relatively easily. + */ + MHD_DAEMON_OPTION_VALUE_DAUTH_BIND_NONCE_CLIENT_IP = 1 << 3 +}; /** @@ -2844,7 +3563,7 @@ MHD_FUNC_PARAM_NONNULL_ (1); */ struct MHD_ServerCredentialsContext; -enum MHD_StatusCode +MHD_EXTERN_ enum MHD_StatusCode MHD_connection_set_psk (struct MHD_ServerCredentialsContext *mscc, size_t psk_size, const /*void? */ char psk[MHD_C99_ (psk_size)]); @@ -2874,79 +3593,19 @@ typedef void /** - * Configure PSK to use for the TLS key exchange. - * - * @param daemon daemon to configure tls for - * @param psk_cb function to call to obtain pre-shared key - * @param psk_cb_cls closure for @a psk_cb - * @return #MHD_SC_OK upon success; TODO: define failure modes - */ -_MHD_EXTERN enum MHD_StatusCode -MHD_daemon_set_tls_psk_callback (struct MHD_Daemon *daemon, - MHD_PskServerCredentialsCallback psk_cb, - void *psk_cb_cls) -MHD_FUNC_PARAM_NONNULL_ (1); - - -/** - * Configure daemon credentials type for GnuTLS. - * - * @param gnutls_credentials must be a value of - * type `gnutls_credentials_type_t` - * @return #MHD_SC_OK upon success; TODO: define failure modes - * - * FIXME: find a way to do this better that is TLS backend independent! - * => replace by exposing TLS library low-level details via - * introspection, see below - */ -_MHD_EXTERN enum MHD_StatusCode -MHD_daemon_gnutls_credentials (struct MHD_Daemon *daemon, - int gnutls_credentials) -MHD_FUNC_PARAM_NONNULL_ (1); - - -/** - * Provide TLS key and certificate data via callback. + * The specified callback will be called one time, + * after network initialisation, TLS pre-initialisation, but before + * the start of the internal threads (if allowed). * - * Use a callback to determine which X.509 certificate should be used - * for a given HTTPS connection. This option provides an alternative - * to #MHD_daemon_tls_key_and_cert_from_memory(). You must use this - * version if multiple domains are to be hosted at the same IP address - * using TLS's Server Name Indication (SNI) extension. In this case, - * the callback is expected to select the correct certificate based on - * the SNI information provided. The callback is expected to access - * the SNI data using `gnutls_server_name_get()`. Using this option - * requires GnuTLS 3.0 or higher. - * - * @param daemon daemon to configure callback for - * @param cb must be of type `gnutls_certificate_retrieve_function2 *`. - * @return #MHD_SC_OK on success - * - * FIXME: find a way to do this better that is TLS backend independent! - * => replace by exposing TLS library low-level details via - * introspection, see below + * This callback may use introspection call to retrieve and adjust + * some of the daemon aspects. For example, TLS backend handler can be used + * to configure some TLS aspects. + * @param cls the callback closure */ -_MHD_EXTERN enum MHD_StatusCode -MHD_daemon_gnutls_key_and_cert_from_callback (struct MHD_Daemon *daemon, - void *cb) -MHD_FUNC_PARAM_NONNULL_ (1); - -// Callback invoked between full initialization of MHD -// during MHD_daemon_start() and actual event loop -// starting to accept incoming connections. So at this -// point, the listen socket (and if applicable TLS context) -// will be available for introspection. typedef void (*MHD_DaemonReadyCallback)(void *cls); -_MHD_EXTERN enum MHD_StatusCode -MHD_daemon_set_daemon_ready_callback (struct MHD_Daemon *daemon, - MHD_DaemonReadyCallback cb, - void *cb) -MHD_FUNC_PARAM_NONNULL_ (1); - - /** * Allow or deny a client to connect. * @@ -2963,22 +3622,6 @@ typedef enum MHD_Bool /** - * Set a policy callback that accepts/rejects connections - * based on the client's IP address. This function will be called - * before a connection object is created. - * - * @param daemon daemon to set policy for - * @param apc function to call to check the policy - * @param apc_cls closure for @a apc - */ -_MHD_EXTERN void -MHD_daemon_accept_policy (struct MHD_Daemon *daemon, - MHD_AcceptPolicyCallback apc, - void *apc_cls) -MHD_FUNC_PARAM_NONNULL_ (1); - - -/** * Function called by MHD to allow the application to log * the @a full_uri of a @a request. * This is the only moment when unmodified URI is provided. @@ -2991,42 +3634,25 @@ MHD_FUNC_PARAM_NONNULL_ (1); * @param uri the full URI from the HTTP request including parameters (after '?') */ typedef void -(MHD_FUNC_PARAM_NONNULL_ (2) MHD_FUNC_PARAM_NONNULL_ (3) +(MHD_FN_PAR_NONNULL_ (2) MHD_FN_PAR_NONNULL_ (3) *MHD_EarlyUriLogCallback)(void *cls, struct MHD_Request *request, const struct MHD_String *full_uri); - -/** - * Register a callback to be called first for every request - * (before any parsing of the header). Makes it easy to - * log the full URL. - * - * @param daemon daemon for which to set the logger - * @param cb function to call - * @param cb_cls closure for @a cb - */ -_MHD_EXTERN enum MHD_StatusCode -MHD_daemon_set_early_uri_logger (struct MHD_Daemon *daemon, - MHD_EarlyUriLogCallback cb, - void *cb_cls) -MHD_FUNC_PARAM_NONNULL_ (1); - - /** * The `enum MHD_ConnectionNotificationCode` specifies types * of connection notifications. * @ingroup request */ -enum MHD_ConnectionNotificationCode +enum MHD_FIXED_ENUM_MHD_SET_ MHD_ConnectionNotificationCode { /** * A new connection has been started. * @ingroup request */ - MHD_CONNECTION_NOTIFY_STARTED = 0, - + MHD_CONNECTION_NOTIFY_STARTED = 0 + , /** * A connection is closed. * @ingroup request @@ -3035,53 +3661,73 @@ enum MHD_ConnectionNotificationCode }; - /** - * Signature of the callback used by MHD to notify the - * application about started/stopped network connections - * - * @param cls client-defined closure - * @param connection connection handle - * @param toe reason for connection notification - * @see #MHD_daemon_set_notify_connection() - * @ingroup request + * Extra details for connection notifications. + * Currently not used */ -typedef void -(MHD_FUNC_PARAM_NONNULL_ (2) - *MHD_NotifyConnectionCallback)(void *cls, - struct MHD_Connection *connection, - enum MHD_ConnectionNotificationCode toe); +union MHD_ConnectionNotificationDetails +{ + /** + * Unused + */ + int reserved1; +}; /** - * Register a function that should be called whenever a connection is - * started or closed. + * The connection notification data structure + */ +struct MHD_ConnectionNotificationData +{ + /** + * The connection handle + */ + struct MHD_Connection *connection; + /** + * The connection-specific application context data (opaque for MHD). + * Initially set to NULL (for connections added by MHD) or set by + * @a connection_cntx parameter for connections added by + * #MHD_daemon_add_connection(). + */ + void *application_context; + /** + * The code of the event + */ + enum MHD_ConnectionNotificationCode code; + /** + * Event details + */ + union MHD_ConnectionNotificationDetails details; +}; + + +/** + * Signature of the callback used by MHD to notify the + * application about started/stopped network connections * - * @param daemon daemon to set callback for - * @param ncc function to call to check the policy - * @param ncc_cls closure for @a apc + * @param cls client-defined closure + * @param[in,out] data the details about the event + * @see #MHD_daemon_set_notify_connection() + * @ingroup request */ -_MHD_EXTERN enum MHD_StatusCode -MHD_daemon_set_notify_connection (struct MHD_Daemon *daemon, - MHD_NotifyConnectionCallback ncc, - void *ncc_cls) -MHD_FUNC_PARAM_NONNULL_ (1); +typedef void +(MHD_FN_PAR_NONNULL_ (2) + *MHD_NotifyConnectionCallback)(void *cls, + struct MHD_ConnectionNotificationData *data); /** - * The `enum MHD_ConnectionNotificationCode` specifies types - * of connection notifications. - * TODO: document possible extensibility + * The type of stream notifications. * @ingroup request */ -enum MHD_StreamNotificationCode +enum MHD_FIXED_ENUM_MHD_SET_ MHD_StreamNotificationCode { /** * A new connection has been started. * @ingroup request */ - MHD_STREAM_NOTIFY_STARTED = 0, - + MHD_STREAM_NOTIFY_STARTED = 0 + , /** * A connection is closed. * @ingroup request @@ -3090,14 +3736,48 @@ enum MHD_StreamNotificationCode }; -// TODO: finish -struct MHD_something +/** + * Additional information about stream started event + */ +struct MHD_StreamNotificationDetailStarted +{ + /** + * Set to #MHD_YES of the stream was started by client + */ + enum MHD_Bool by_client; +}; + +/** + * Additional information about stream events + */ +union MHD_StreamNotificationDetail +{ + /** + * Information for event #MHD_STREAM_NOTIFY_STARTED + */ + struct MHD_StreamNotificationDetailStarted started; +}; + +/** + * Stream notification data structure + */ +struct MHD_StreamNotificationData { - struct MHD_Stream *stream; // const? + /** + * The handle of the stream + */ + struct MHD_Stream *stream; + /** + * The code of the event + */ enum MHD_StreamNotificationCode code; - union something; + /** + * Detailed information about notification event + */ + union MHD_StreamNotificationDetail details; }; + /** * Signature of the callback used by MHD to notify the * application about started/stopped data stream @@ -3105,554 +3785,2832 @@ struct MHD_something * with 1:1 match. * * @param cls client-defined closure - * @param stream the stream handle - * @param toe reason for connection notification + * @param data the details about the event * @see #MHD_OPTION_NOTIFY_CONNECTION * @ingroup request */ typedef void -(MHD_FUNC_PARAM_NONNULL_ (2) - *MHD_NotifyStreamCallback)(void *cls, - const struct MHD_something *notification); +(MHD_FN_PAR_NONNULL_ (2) + *MHD_NotifyStreamCallback)( + void *cls, + const struct MHD_StreamNotificationData *data); /** - * Register a function that should be called whenever a stream is - * started or closed. - * - * @param daemon daemon to set callback for - * @param nsc function to call to check the policy - * @param nsc_cls closure for @a apc + * The options (parameters) for MHD daemon */ -_MHD_EXTERN enum MHD_StatusCode -MHD_daemon_set_notify_stream (struct MHD_Daemon *daemon, - MHD_NotifyStreamCallback nsc, - void *nsc_cls) -MHD_FUNC_PARAM_NONNULL_ (1); - -// TODO: Sort and assign values -enum MHD_DaemonOptionSizet +enum MHD_FIXED_ENUM_APP_SET_ MHD_DaemonOption { /** - * Maximum memory size per connection. - * Default is 32 kb (#MHD_POOL_SIZE_DEFAULT). - * Values above 128k are unlikely to result in much performance benefit, - * as half of the memory will be typically used for IO, and TCP buffers - * are unlikely to support window sizes above 64k on most systems. - * The size should be large enough to fit all request headers (together - * with internal parsing information). - */ - MHD_DAEMON_OPTION_SIZET_CONN_MEM_LIMIT, - // FIXME: remove this option completely and manage it in MHD? - // Users do not have clear understanding of what is it and why is it needed/ - // TODO: remove for now - /** - * The step in which read buffer is incremented when needed. - * If initial half size of the connection's memory region is not enough - * for message header and initial part of the request context/body then - * buffer is increased by this size. - */ - MHD_DAEMON_OPTION_SIZET_CONN_INCR_SIZE, - /** - * Desired size of the stack for threads created by MHD. - * Use 0 for system default, which is also MHD default. - * Only useful if the selected threading mode - * is not #MHD_TM_EXTERNAL_EVENT_LOOP. + * Not a real option. + * Should not be used directly. + * This value indicates the end of the list of the options. */ - MHD_DAEMON_OPTION_SIZET_STACK_SIZE, - -}; -// FIXME: finish -_MHD_EXTERN void -MHD_daemon_option_set_sizet (struct MHD_Daemon *daemon, - enum MHD_DaemonOptionSizet option, - size_t value) -MHD_FUNC_PARAM_NONNULL_ (1); - -/* ******************* Event loop ************************ */ - + MHD_D_O_END = 0 + , -// FIXME: updated, renamed -/** - * Which threading and polling mode should be used by MHD? - */ -enum MHD_ThreadingPollingMode -{ - // FIXME: Updated - OK + /* = MHD Daemon Option enum values below are generated automatically = */ /** - * The daemon has no internal threads. - * The application periodically calls #MHD_process_data(), MHD checks - * all sockets internally automatically. - * This is the default. // FIXME: keep as default? + * Set MHD work (threading and polling) mode. + * Consider use of #MHD_DAEMON_OPTION_WM_EXTERNAL_PERIODIC(), + * #MHD_DAEMON_OPTION_WM_EXTERNAL_EVENT_LOOP_CB_LEVEL(), + * #MHD_DAEMON_OPTION_WM_EXTERNAL_EVENT_LOOP_CB_EDGE(), + * #MHD_DAEMON_OPTION_WM_EXTERNAL_SINGLE_FD_WATCH(), + * #MHD_DAEMON_OPTION_WM_WORKER_THREADS() or + * #MHD_DAEMON_OPTION_WM_THREAD_PER_CONNECTION() instead of direct use of + * this parameter. + * The parameter value must be placed to the + * @a v_work_mode member. */ - MHD_TM_EXTERNAL_PERIODIC = 0, - // FIXME: updated + MHD_D_O_WORK_MODE = 40 + , /** - * Use an external event loop. - * Application use #MHD_set_external_event_loop() and level - * triggered sockets polling (like select() or poll()). + * Select a sockets watch system call used for internal polling. + * The parameter value must be placed to the + * @a v_poll_syscall member. */ - MHD_TM_EXTERNAL_EVENT_LOOP_CB_LEVEL = 1, + MHD_D_O_POLL_SYSCALL = 41 + , /** - * Use an external event loop. - * Application use #MHD_set_external_event_loop() and edge - * triggered sockets polling. + * Set a callback to use for logging + * The parameter value must be placed to the + * @a v_log_callback member. */ - MHD_TM_EXTERNAL_EVENT_LOOP_CB_EDGE = 2, + MHD_D_O_LOG_CALLBACK = 60 + , /** - * Use an external event loop. - * Application use #MHD_get_watched_fds()/#MHD_get_watched_fds_update() - * and #MHD_process_watched_fds() with level triggered sockets - * polling (like select() or poll()). + * Bind to the given TCP port and address family. + * + * Does not work with #MHD_DAEMON_OPTION_BIND_SA() or + * #MHD_DAEMON_OPTION_LISTEN_SOCKET(). + * + * If no listen socket optins (#MHD_DAEMON_OPTION_BIND_PORT(), + * #MHD_DAEMON_OPTION_BIND_SA(), #MHD_DAEMON_OPTION_LISTEN_SOCKET()) are + * used, MHD does not listen for incoming connection. + * The parameter value must be placed to the + * @a v_bind_port member. */ - MHD_TM_EXTERNAL_EVENT_LOOP_WFD_LEVEL = 3, + MHD_D_O_BIND_PORT = 80 + , /** - * Use an external event loop. - * Application use #MHD_get_watched_fds()/#MHD_get_watched_fds_update() - * and #MHD_process_watched_fds() with edge triggered sockets polling. + * Bind to the given socket address. + * + * Does not work with #MHD_DAEMON_OPTION_BIND_PORT() or + * #MHD_DAEMON_OPTION_LISTEN_SOCKET(). + * + * If no listen socket optins (#MHD_DAEMON_OPTION_BIND_PORT(), + * #MHD_DAEMON_OPTION_BIND_SA(), #MHD_DAEMON_OPTION_LISTEN_SOCKET()) are + * used, MHD does not listen for incoming connection. + * The parameter value must be placed to the + * @a v_bind_sa member. */ - MHD_TM_EXTERNAL_EVENT_LOOP_WFD_EDGE = 4, + MHD_D_O_BIND_SA = 81 + , /** - * Run with one or more worker threads. - * If #MHD_DAEMON_OPTION_UINT_NUM_WORKERS is not specified - * then daemon starts with single worker thread that process - * all connections. - * If #MHD_DAEMON_OPTION_UINT_NUM_WORKERS used with value more - * than one, then that number of worker threads and distributed - * processing of requests among the workers. + * Accept connections from the given socket. Socket + * must be a TCP or UNIX domain (SOCK_STREAM) socket. + * + * Does not work with #MHD_DAEMON_OPTION_BIND_PORT() or + * #MHD_DAEMON_OPTION_BIND_SA(). * - * If this mode is specified, #MHD_daemon_run() and - * #MHD_daemon_run_from_select() cannot be used. + * If no listen socket optins (#MHD_DAEMON_OPTION_BIND_PORT(), + * #MHD_DAEMON_OPTION_BIND_SA(), #MHD_DAEMON_OPTION_LISTEN_SOCKET()) are + * used, MHD does not listen for incoming connection. + * The parameter value must be placed to the + * @a v_listen_socket member. */ - MHD_TM_WORKER_THREADS = 5, - - // FIXME: could be unavailable for HTTP/2 and /3. Streams must be - // multiplexed. Multiplexing from several threads looks overcomplicated. - // TODO: update doxy + MHD_D_O_LISTEN_SOCKET = 82 + , /** - * MHD should create its own thread for listening and furthermore create - * another thread per request. Threads may be re-used on the same - * connection. Use this if handling requests is CPU-intensive or blocking, - * your application is thread-safe and you have plenty of memory (per - * connection). + * Select mode of reusing address:port listen address. + * + * Works only when #MHD_DAEMON_OPTION_BIND_PORT() or + * #MHD_DAEMON_OPTION_BIND_SA() are used. + * The parameter value must be placed to the + * @a v_listen_addr_reuse member. */ - MHD_TM_THREAD_PER_CONNECTION = 6 - -}; - -/* FUTURE: - (with eventually option "number of masters") - MHD_TM_WORKER_THREADS_WITH_MASTER_LISTENER = 3 */ - - -/** - * Specify threading mode to use. - * - * @param[in,out] daemon daemon to configure - * @param tm mode to use - */ -_MHD_EXTERN enum MHD_StatusCode -MHD_daemon_set_threading_mode (struct MHD_Daemon *daemon, - enum MHD_ThreadingMode tm) -MHD_FUNC_PARAM_NONNULL_ (1); - - -// edge vs. level triggers? howto unify? => application returns type? -// thread safety? -// existing cascaded epoll FD approach, how to keep? -// -> introspection API to return the FD -// -> if app does NOT set MHD_set_external_event_loop() -// we presumably use 'internal' implementation(s), -// if internal e-pool implementation configured... - -enum MHD_EventType // bitmask -{ - MHD_ET_LISTEN = 1,// want to accept - MHD_ET_READ = 2, // want to read - MHD_ET_WRITE = 4, // want to write - MHD_ET_EXCEPT = 8 // care about remote close / interruption -}; - -// FIXME: remove it, pre-selected by Polling Mode -enum MHD_TriggerLevel -{ - MHD_TL_EDGE, // epoll in edge trigger mode - MHD_TL_LEVEL // epoll in level trigger mode -}; - -// implemented within MHD! -typedef void -(*MHD_EventCallback) (void *cls, - enum MHD_EventType et, - enum MHD_TriggerLevel tl); - - -#ifdef EXAMPLE_APP_CODE - -struct MHD_ApplicationRegistrationContext * -// NULL -app_ereg_cb_select (void *cls, - enum MHD_EventType et, - int fd, - MHD_EventCallback cb, - void *cb_cls) -{ - assert (fd < FD_SETSIZE); - max_fd = MAX (fd, max_fd); - events[fd].cb = cb; - events[fd].cb_cls = cb_cls; - if (1 == 1 & et) - FD_SET (fd, &reads); - if (2 == 2 & et) - FD_SET (fd, &writes); - if (4 == 4 & et) - FD_SET (fd, &excepts); - return &events[fd]; -} - - -void -app_unreg (ptr) -{ - ptr->cb = NULL; - // whichever applicable... - int fd = ptr - events; - FD_CLR (fd, &reads); - FD_CLR (fd, &writes); - FD_CLR (fd, &excepts); - if (fd == max_fd) - while ( (max_fd > 0) && - (NULL == events[--max_fd].cb) ) - ; -} - - -loop_do () -{ - d = MHD_daemon_create (...); - MHD_set_external_event_loop (d, - &app_reg, - &app_unreg); - MHD_daemon_go (d); // => calls app_reg on listen socket - while (1) - { - rs = reads; // copy! - ws = writes; // copy! - es = excepts; // copy! - // + add application FDs here (if not in global reads/writes/excepts) - // once per iteration (also runs edge-based events) - new_timeout = MHD_run_jobs_and_get_timeout (d); - select (max_fd, &rs, &ws, &es, new_timeout); - for (bits_set) - { - events[bit].cb (events[bit].cb_cls, - LISTEN / READ / WRITE / EXCEPT, - MHD_TL_LEVEL); - } - } -} -#endif - - -uint64_t -MHD_external_event_loop_get_timeout (struct MHD_Daemon *d); - - -struct MHD_ApplicationRegistrationContext; // opaque to MHD, app must define per socket/event - -// implemented usually by application, -typedef struct MHD_ApplicationRegistrationContext * // NULL on error, e.g. fd too large / out of memory => log + close connection -(*MHD_EventRegistrationUpdateCallback)( - void *cls, - struct MHD_ApplicationRegistrationContext *old, // null if no previous reg for fd exists - enum MHD_EventType et, // use NONE to unregister - int fd, - MHD_EventCallback cb, - void *cb_cls); - -// NEW style: -void -MHD_set_external_event_loop (struct MHD_Daemon *daemon, - MHD_EventRegistrationUpdateCallback cb, - void *cb_cls); - - -// FIXME: Updated -// FIXME: any better name? "send_ready"? -/** - * The network status of the socket. - * When set by MHD (by #MHD_get_watched_fds() or #MHD_get_watched_fds_update()) - * it indicates a request to watch for specific socket state: - * readiness for receiving the data, readiness for sending the data and/or - * exception state of the socket. - * When set by application and provided for #MHD_process_watched_fds() it must - * indicate the actual status of the socket. - * - * Any actual state is a bitwise OR combination of #MHD_FD_STATE_RECV, - * #MHD_FD_STATE_SEND, #MHD_FD_STATE_EXCEPT. - */ -enum MHD_FdState -{ + MHD_D_O_LISTEN_ADDR_REUSE = 100 + , /** - * The socket is not ready for receiving or sending and - * does not have any exceptional state. - * The state never set by MHD. + * Configure TCP_FASTOPEN option, including setting a + * custom @a queue_length. + * + * Note that having a larger queue size can cause resource exhaustion + * attack as the TCP stack has to now allocate resources for the SYN + * packet along with its DATA. + * + * Works only when #MHD_DAEMON_OPTION_BIND_PORT() or + * #MHD_DAEMON_OPTION_BIND_SA() are used. + * The parameter value must be placed to the + * @a v_tcp_fastopen member. */ - MHD_FD_STATE_NONE = 0, - - /* ** Three bit-flags ** */ - + MHD_D_O_TCP_FASTOPEN = 101 + , /** - * Indicates that socket should be watched for incoming data - * (when set by #MHD_get_watched_fds()) - * / socket has incoming data ready to read (when used for - * #MHD_process_watched_fds()) + * Use the given backlog for the listen() call. + * + * Works only when #MHD_DAEMON_OPTION_BIND_PORT() or + * #MHD_DAEMON_OPTION_BIND_SA() are used. + * The parameter value must be placed to the + * @a v_listen_backlog member. */ - MHD_FD_STATE_RECV = 1 << 0, + MHD_D_O_LISTEN_BACKLOG = 102 + , /** - * Indicates that socket should be watched for availability for sending - * (when set by #MHD_get_watched_fds()) - * / socket has ability to send data (when used for - * #MHD_process_watched_fds()) + * Inform that SIGPIPE is suppressed or handled by application. + * If suppressed/handled, MHD uses network functions that could generate + * SIGPIPE, like `sendfile()`. + * Silently ignored when MHD creates internal threads as for them SIGPIPE is + * suppressed automatically. + * The parameter value must be placed to the + * @a v_sigpipe_suppressed member. */ - MHD_FD_STATE_SEND = 1 << 1, + MHD_D_O_SIGPIPE_SUPPRESSED = 103 + , /** - * Indicates that socket should be watched for disconnect, out-of-band - * data available or high priority data available (when set by - * #MHD_get_watched_fds()) - * / socket has been disconnected, has out-of-band data available or - * has high priority data available (when used for - * #MHD_process_watched_fds()). This status must not include "remote - * peer shut down writing" status. - * Note: #MHD_get_watched_fds() always set it as exceptions must be - * always watched. + * Enable TLS (HTTPS) and select TLS backend + * The parameter value must be placed to the + * @a v_tls member. */ - MHD_FD_STATE_EXCEPT = 1 << 2, - - /* The rest of the list is a bit-wise combination of three main - * state. Application may use three main states directly as - * a bit-mask instead of using of following values + MHD_D_O_TLS = 120 + , + /** + * Provide TLS key and certificate data in-memory. + * Works only if TLS mode is enabled. + * The parameter value must be placed to the + * @a v_tls_key_cert member. */ - + MHD_D_O_TLS_KEY_CERT = 121 + , /** - * Combination of #MHD_FD_STATE_RECV and #MHD_FD_STATE_SEND states. + * Provide the certificate of the certificate authority (CA) to be used by + * the MHD daemon for client authentication. + * Works only if TLS mode is enabled. + * The parameter value must be placed to the + * @a v_tls_client_ca member. */ - MHD_FD_STATE_RECV_SEND = MHD_FD_STATE_RECV | MHD_FD_STATE_SEND, + MHD_D_O_TLS_CLIENT_CA = 122 + , /** - * Combination of #MHD_FD_STATE_RECV and #MHD_FD_STATE_EXCEPT states. + * Configure PSK to use for the TLS key exchange. + * The parameter value must be placed to the + * @a v_tls_psk_callback member. */ - MHD_FD_STATE_RECV_EXCEPT = MHD_FD_STATE_RECV | MHD_FD_STATE_EXCEPT, + MHD_D_O_TLS_PSK_CALLBACK = 130 + , /** - * Combination of #MHD_FD_STATE_RECV and #MHD_FD_STATE_EXCEPT states. + * Control ALPN for TLS connection. + * Silently ignored for non-TLS. + * By default ALPN is automatically used for TLS connections. + * The parameter value must be placed to the + * @a v_no_alpn member. */ - MHD_FD_STATE_SEND_EXCEPT = MHD_FD_STATE_RECV | MHD_FD_STATE_EXCEPT, + MHD_D_O_NO_ALPN = 140 + , /** - * Combination of #MHD_FD_STATE_RECV, #MHD_FD_STATE_SEND and - * #MHD_FD_STATE_EXCEPT states. + * Specify inactivity timeout for connection. + * When no activity for specified time on connection, it is closed + * automatically. + * Use zero for no timeout, which is also the (unsafe!) default. + * The parameter value must be placed to the + * @a v_default_timeout member. */ - MHD_FD_STATE_RECV_SEND_EXCEPT = \ - MHD_FD_STATE_RECV | MHD_FD_STATE_SEND | MHD_FD_STATE_EXCEPT -}; - -// FIXME: added macros -// TODO: add doxy -#define MHD_FD_STATE_IS_SET(var,state) \ - (0 != (((unsigned int) (var)) & ((unsigned int) (state)))) - -#define MHD_FD_STATE_IS_SET_RECV(var) \ - MHD_FD_STATE_IS_SET ((var),MHD_FD_STATE_RECV) -#define MHD_FD_STATE_IS_SET_SEND(var) \ - MHD_FD_STATE_IS_SET ((var),MHD_FD_STATE_SEND) -#define MHD_FD_STATE_IS_SET_EXCEPT(var) \ - MHD_FD_STATE_IS_SET ((var),MHD_FD_STATE_EXCEPT) - - -#define MHD_FD_STATE_SET(var,state) \ - (var) = (enum MHD_FdState) ((var) | (state)) -#define MHD_FD_STATE_CLEAR(var,state) \ - (var) = (enum MHD_FdState) ((var) & (((enum MHD_FdState))(~state))) - -#define MHD_FD_STATE_SET_RECV(var) MHD_FD_STATE_SET ((var),MHD_FD_STATE_RECV) -#define MHD_FD_STATE_SET_SEND(var) MHD_FD_STATE_SET ((var),MHD_FD_STATE_SEND) -#define MHD_FD_STATE_SET_EXCEPT(var) \ - MHD_FD_STATE_SET ((var),MHD_FD_STATE_EXCEPT) - -#define MHD_FD_STATE_CLEAR_RECV(var) \ - MHD_FD_STATE_CLEAR ((var),MHD_FD_STATE_RECV) -#define MHD_FD_STATE_CLEAR_SEND(var) \ - MHD_FD_STATE_CLEAR ((var),MHD_FD_STATE_SEND) -#define MHD_FD_STATE_CLEAR_EXCEPT(var) \ - MHD_FD_STATE_CLEAR ((var),MHD_FD_STATE_EXCEPT) - -struct MHD_WatchedFD -{ + MHD_D_O_DEFAULT_TIMEOUT = 160 + , /** - * The watched socket. - * Ignored if set by application to #MHD_INVALID_SOCKET. TODO: Improve wording + * Maximum number of (concurrent) network connections served by daemon + * The parameter value must be placed to the + * @a v_global_connection_limit member. */ - MHD_socket fd; - + MHD_D_O_GLOBAL_CONNECTION_LIMIT = 161 + , /** - * Indicates that socket should be watched for specific network state - * (when set by #MHD_get_watched_fds(), #MHD_get_watched_fds_update()) - * / the network state of the socket (when used for - * #MHD_process_watched_fds()) + * Limit on the number of (concurrent) network connections made to the server + * from the same IP address. + * Can be used to prevent one IP from taking over all of the allowed + * connections. If the same IP tries to establish more than the specified + * number of connections, they will be immediately rejected. + * The parameter value must be placed to the + * @a v_per_ip_limit member. */ - enum MHD_FdState state; -}; - -/** - * Get the full list of the sockets that must be watched by application. - * - * The application may use this function each time to get a full list of - * the sockets for watch or may use #MHD_get_watched_fds_update() to - * get the incremental updates. - * - * @param daemon the daemon to get the list - * @param num_elements the number of elements in @a fds list - * @param[out] fds the arrays of @a num_elements of sockets to be watched - * by application, - * could be NULL to get the required number of elements // TODO: replace with introspection - * @param[out] max_wait the pointer to value set to maximum wait time - * for the network events, set only if @fds is not NULL - * @return number of elements set in @a fds, never larger than - * @a num_elements (if @a fds in not NULL); - * the required number elements in @a fds (if @a fds is NULL) - */ -_MHD_EXTERN unsigned int -MHD_get_watched_fds (struct MHD_Daemon *daemon, - unsigned int num_elements, - struct MHD_WatchedFD *fds, - uint_fast64_t *max_wait) // FIXME: never return "no timeout" -MHD_FUNC_PARAM_NONNULL_ (1) MHD_FUNC_PARAM_NONNULL_ (4); - - -enum MHD_WatchedFdAction -{ + MHD_D_O_PER_IP_LIMIT = 162 + , /** - * New watched FD, to be added to the list + * Set a policy callback that accepts/rejects connections based on the + * client's IP address. The callbeck function will be called before + * servicing any new incoming connection. + * The parameter value must be placed to the + * @a v_accept_policy member. */ - MHD_WFA_ADD = 1 + MHD_D_O_ACCEPT_POLICY = 163 , /** - * Update watching interest in already watched FD + * Set how strictly MHD will enforce the HTTP protocol. + * The parameter value must be placed to the + * @a v_protocol_strict_level member. */ - MHD_WFA_UPDATE = 2 + MHD_D_O_PROTOCOL_STRICT_LEVEL = 200 , /** - * Delete FD from watching list + * Set a callback to be called first for every request when the request line + * is received (before any parsing of the header). + * This callback is the only way to get raw (unmodified) request URI as URI + * is parsed and modified by MHD in-place. + * Mandatory URI modification may apply before this call, like binary zero + * replacement, as required by RFCs. + * The parameter value must be placed to the + * @a v_early_uri_logger member. */ - MHD_WFA_REMOVE = 3 -}; - -struct MHD_WatchedFdUpdate -{ + MHD_D_O_EARLY_URI_LOGGER = 201 + , + /** + * Disable converting plus ('+') character to space in GET parameters (URI + * part after '?'). + * Plus conversion is not required by HTTP RFCs, however it required by HTML + * specifications, see + * https://url.spec.whatwg.org/#application/x-www-form-urlencoded for + * details. + * By default plus is converted to space in the query part of URI. + * The parameter value must be placed to the + * @a v_disable_uri_query_plus_as_space member. + */ + MHD_D_O_DISABLE_URI_QUERY_PLUS_AS_SPACE = 202 + , /** - * The required action: add/update/delete + * Suppresse use of "Date:" header. + * According to RFC should be suppressed only if the system has no RTC. + * The "Date:" is not suppressed (the header is enabled) by default. + * The parameter value must be placed to the + * @a v_suppress_date_header member. */ - enum MHD_WatchedFdAction action; - + MHD_D_O_SUPPRESS_DATE_HEADER = 240 + , /** - * The watched FD to add, update or delete. + * Use SHOUTcast for responses. + * This will cause *all* responses to begin with the SHOUTcast "ICY" line + * instead of "HTTP". + * The parameter value must be placed to the + * @a v_enable_shoutcast member. */ - struct MHD_WatchedFD watched_fd; -}; - -/** - * Get the update of the list of the sockets that must be watched - * by application. - * This function provides an update to the list of watched sockets - * since the last call of #MHD_get_watched_fds() or - * #MHD_get_watched_fds_update() with non-NULL @a fds. - * If this function is called before #MHD_get_watched_fds() then it - * returns full list of sockets to watch with action #MHD_WFA_ADD. - * - * @param daemon the daemon to get the list - * @param num_elements the number of elements in @a fds list - * @param[out] fds the arrays of @a num_elements to update the list - * of watched sockets, - * could be NULL to get the required number of elements // TODO: convert to introspection - * @param[out] max_wait the pointer to value set to maximum wait time in millisec // TODO: check with microseconds - * for the network events, set only if @fds is not NULL - * @return number of elements set in @a fds, never larger than - * @a num_elements (if @a fds in not NULL); - * the required number elements in @a fds (if @a fds is NULL) - */ -_MHD_EXTERN unsigned int -MHD_get_watched_fds_update (struct MHD_Daemon *daemon, - unsigned int num_elements, - struct MHD_WatchedFdUpdate *fds, - uint_fast64_t *max_wait) -MHD_FUNC_PARAM_NONNULL_ (1); - - -/** - * Perform round of sockets processing, including receiving, sending, - * data processing, sockets closing and other things. - * @param daemon the daemon to process - * @param num_elements the number of elements in the @a fds array - * @param fds the array of watched sockets, must be complete list of - * all watched sockets if @a type is #MHD_TL_LEVEL or - * just partial list otherwise - * @param type the type of the trigger used to watch sockets - * @return #MHD_SC_OK on success, - * otherwise error code TODO: complete list of error codes - */ -_MHD_EXTERN enum MHD_StatusCode // FIXME: bool? void? -MHD_process_watched_fds ( - struct MHD_Daemon *daemon, - unsigned int num_elements, - struct MHD_WatchedFD fds[MHD_C99_ (static num_elements)], - enum MHD_TriggerLevel type) // TODO: maybe not need -MHD_FUNC_PARAM_NONNULL_ (1) MHD_FUNC_PARAM_NONNULL_ (2); - - -/** - * Obtain timeout value for polling function for this daemon. - * This function set value to amount of milliseconds for which polling - * function (`select()` or `poll()`) should at most block, not the - * timeout value set for connections. - * It is important to always use this function, even if connection - * timeout is not set, as in some cases MHD may already have more - * data to process on next turn (data pending in TLS buffers, - * connections are already ready with epoll etc.) and returned timeout - * will be zero. - * - * @param[in,out] daemon daemon to query for timeout - * @param[out] timeout set to the timeout (in milliseconds) - * @return #MHD_SC_OK on success, #MHD_SC_NO_TIMEOUT if timeouts are - * not used (or no connections exist that would - * necessitate the use of a timeout right now), otherwise - * an error code - * @ingroup event - */ -// @deprecated, new CB approach / use for inspiration -_MHD_EXTERN enum MHD_StatusCode -MHD_daemon_get_timeout (struct MHD_Daemon *daemon, - uint64_fast_t *timeout) -MHD_FUNC_PARAM_NONNULL_ (1) MHD_FUNC_PARAM_NONNULL_ (2); - - -/** - * Run websever operation with possible blocking. - * - * This function does the following: waits for any network event not more than - * specified number of milliseconds, processes all incoming and outgoing data, - * processes new connections, processes any timed-out connection, and does - * other things required to run webserver. - * Once all connections are processed, function returns. - * - * This function is useful for quick and simple (lazy) webserver implementation - * if application needs to run a single thread only and does not have any other - * network activity. - * - * FIXME: document use of this function for epoll(), too! + MHD_D_O_ENABLE_SHOUTCAST = 241 + , + /** + * Maximum memory size per connection. + * Default is 32kb. + * Values above 128kb are unlikely to result in much performance benefit, as + * half of the memory will be typically used for IO, and TCP buffers are + * unlikely to support window sizes above 64k on most systems. + * The size should be large enough to fit all request headers (together with + * internal parsing information). + * The parameter value must be placed to the + * @a v_conn_memory_limit member. + */ + MHD_D_O_CONN_MEMORY_LIMIT = 280 + , + /** + * The size of the shared memory pool for accamulated upload processing. + * The same "large" pool is shared for all connections server by MHD and used + * when application requests avoiding of incremental upload processing to + * accamulate complete content upload before giving it to the application. + * Default is 8Mb. + * Can be set to zero to disable share pool. + * The parameter value must be placed to the + * @a v_large_pool_size member. + */ + MHD_D_O_LARGE_POOL_SIZE = 281 + , + /** + * Desired size of the stack for the threads started by MHD. + * Use 0 for system default, which is also MHD default. + * Works only with ##MHD_DAEMON_OPTION_WORKER_THREADS() or + * #MHD_DAEMON_OPTION_THREAD_PER_CONNECTION(). + * The parameter value must be placed to the + * @a v_stack_size member. + */ + MHD_D_O_STACK_SIZE = 282 + , + /** + * The the maximum FD value. + * The limit is applied to all sockets used by MHD. + * If listen socket FD is equal or higher that specified value, the daemon + * fail to start. + * If new connection FD is equal or higher that specified value, the + * connection is rejected. + * Useful if application uses select() for polling the sockets, system + * FD_SETSIZE is good value for this option in such case. + * Does not work with ##MHD_DAEMON_OPTION_WORKER_THREADS() or + * #MHD_DAEMON_OPTION_THREAD_PER_CONNECTION(). + * Does not work on W32 (WinSock sockets). + * The parameter value must be placed to the + * @a v_fd_number_limit member. + */ + MHD_D_O_FD_NUMBER_LIMIT = 283 + , + /** + * Enable `turbo`. + * Disables certain calls to `shutdown()`, enables aggressive non-blocking + * optimistic reads and other potentially unsafe optimisations. + * Most effects only happen with internal threads with epoll. + * The 'turbo' mode is not enabled (mode is disabled) by default. + * The parameter value must be placed to the + * @a v_turbo member. + */ + MHD_D_O_TURBO = 320 + , + /** + * Disable some internal thread safety. + * Indicates that MHD daemon will be used by application in single-threaded + * mode only. When this flag is set then application must call any MHD + * function only within a single thread. + * This flag turns off some internal thread-safety and allows MHD making some + * of the internal optimisations suitable only for single-threaded + * environment. + * Not compatible with any internal threads modes. + * If MHD is compiled with custom configuration for embedded projects without + * threads support, this option is mandatory. + * Thread safety is not disabled (safety is enabled) by default. + * The parameter value must be placed to the + * @a v_disable_thread_safety member. + */ + MHD_D_O_DISABLE_THREAD_SAFETY = 321 + , + /** + * You need to set this option if you want to disable use of HTTP "Upgrade". + * "Upgrade" may require usage of additional internal resources, which we can + * avoid providing if they will not be used. + * You should only use this option if you do not use "Upgrade" functionality + * and need a generally minor boost in performance and resources saving. + * The "Upgrade" is not disallowed ("upgrade" is allowed) by default. + * The parameter value must be placed to the + * @a v_disallow_upgrade member. + */ + MHD_D_O_DISALLOW_UPGRADE = 322 + , + /** + * Disable #MHD_action_suspend() functionality. + * + * You should only use this function if you do not use suspend functionality + * and need a generally minor boost in performance. + * The suspend is not disallowed (suspend is allowed) by default. + * The parameter value must be placed to the + * @a v_disallow_suspend_resume member. + */ + MHD_D_O_DISALLOW_SUSPEND_RESUME = 323 + , + /** + * Set a callback to be called for pre-start finalisation. + * + * The specified callback will be called one time, after network + * initialisation, TLS pre-initialisation, but before the start of the + * internal threads (if allowed) + * The parameter value must be placed to the + * @a v_daemon_ready_callback member. + */ + MHD_D_O_DAEMON_READY_CALLBACK = 360 + , + /** + * Set a function that should be called whenever a connection is started or + * closed. + * The parameter value must be placed to the + * @a v_notify_connection member. + */ + MHD_D_O_NOTIFY_CONNECTION = 361 + , + /** + * Register a function that should be called whenever a stream is started or + * closed. + * For HTTP/1.1 this callback is called one time for every connection. + * The parameter value must be placed to the + * @a v_notify_stream member. + */ + MHD_D_O_NOTIFY_STREAM = 362 + , + /** + * Set strong random data to be used by MHD. + * Currently the data is only needed for Digest Auth module. + * The recommended size is between 8 and 32 bytes. Security can be lower for + * sizes less or equal four. + * Sizes larger then 32 (or, probably, larger than 16 - debatable) will not + * increase the security. + * The parameter value must be placed to the + * @a v_random_entropy member. + */ + MHD_D_O_RANDOM_ENTROPY = 400 + , + /** + * Specify the size of the internal hash map array that tracks generated + * digest nonces usage. + * When the size of the map is too small then need to handle concurrent DAuth + * requests, a lot of "stale nonce" results will be produced. + * By default the size is 8 bytes (very small). + * The parameter value must be placed to the + * @a v_dauth_map_size member. + */ + MHD_D_O_DAUTH_MAP_SIZE = 401 + , + /** + * Control the scope of validity of MHD-generated nonces. + * This regulates how "nonces" are generated and how "nonces" are checked by + * #MHD_digest_auth_check() and similar functions. + * This option allows bitwise OR combination of + * #MHD_DaemonOptionValueDAuthBindNonce values. + * When this option is not used then default value is + * #MHD_DAEMON_OPTION_VALUE_DAUTH_BIND_NONCE_NONE. + * The parameter value must be placed to the + * @a v_dauth_nonce_bind_type member. + */ + MHD_D_O_DAUTH_NONCE_BIND_TYPE = 402 + , + /** + * Default nonce timeout value (in seconds) used for Digest Auth. + * Silently ignored if followed by zero value. + * @see #MHD_digest_auth_check(), MHD_digest_auth_check_digest() + * The parameter value must be placed to the + * @a v_dauth_def_nonce_timeout member. + */ + MHD_D_O_DAUTH_DEF_NONCE_TIMEOUT = 403 + , + /** + * Default maximum nc (nonce count) value used for Digest Auth. + * Silently ignored if followed by zero value. + * @see #MHD_digest_auth_check(), MHD_digest_auth_check_digest() + * The parameter value must be placed to the + * @a v_dauth_def_max_nc member. + */ + MHD_D_O_DAUTH_DEF_MAX_NC = 404 + , + /* = MHD Daemon Option enum values above are generated automatically = */ + + /* * Sentinel * */ + /** + * The sentinel value. + * This value enforces specific underlying integer type for the enum. + * Do not use. + */ + MHD_D_O_SENTINEL = 65535 + +}; + +/* = MHD Daemon Option structures below are generated automatically = */ +/** + * Data for #MHD_D_O_LOG_CALLBACK + */ +struct MHD_DaemonOptionValueLog +{ + /** + * The callback to use for logging, + * NULL to disable logging + */ + MHD_LoggingCallback v_log_cb; + /** + * The closure for the logging callback + */ + void *v_lob_cb_cls; +}; + +/** + * Data for #MHD_D_O_BIND_PORT + */ +struct MHD_DaemonOptionValueBind +{ + /** + * The address family to use, + * the #MHD_AF_NONE to disable listen socket (the same effect as if this + * option is not used) + */ + enum MHD_AddressFamily v_af; + /** + * Port to use, 0 to let system assign any free port, + * ignored if @a af is #MHD_AF_NONE + */ + uint_fast16_t v_port; +}; + +/** + * Data for #MHD_D_O_BIND_SA + */ +struct MHD_DaemonOptionValueSA +{ + /** + * The size of the socket address pointed by @a sa. + */ + size_t v_sa_len; + /** + * The address to bind to; can be IPv4 (AF_INET), IPv6 (AF_INET6) or even a + * UNIX domain socket (AF_UNIX) + */ + const struct sockaddr *v_sa; +}; + +/** + * Data for #MHD_D_O_TCP_FASTOPEN + */ +struct MHD_DaemonOptionValueTFO +{ + /** + * The type use of of TCP FastOpen + */ + enum MHD_TCPFastOpenType v_option; + /** + * The length of the queue, zero to use system or MHD default, + * silently ignored on platforms without support for custom queue size + */ + unsigned int v_queue_length; +}; + +/** + * Data for #MHD_D_O_TLS_KEY_CERT + */ +struct MHD_DaemonOptionValueTlsCert +{ + /** + * The private key loaded into memory (not a filename) + */ + const char *v_mem_key; + /** + * The certificate loaded into memory (not a filename) + */ + const char *v_mem_cert; + /** + * The option passphrase phrase to decrypt the private key, + * could be NULL is private does not need a password + */ + const char *v_mem_cert; +}; + +/** + * Data for #MHD_D_O_TLS_PSK_CALLBACK + */ +struct MHD_DaemonOptionValueTlsPskCB +{ + /** + * The function to call to obtain pre-shared key + */ + MHD_PskServerCredentialsCallback v_psk_cb; + /** + * The closure for @a psk_cb + */ + void *v_psk_cb_cls; +}; + +/** + * Data for #MHD_D_O_ACCEPT_POLICY + */ +struct MHD_DaemonOptionValueAcceptPol +{ + /** + * The accept policy callback + */ + MHD_AcceptPolicyCallback v_apc; + /** + * The closure for the callback + */ + void *v_apc_cls; +}; + +/** + * Data for #MHD_D_O_PROTOCOL_STRICT_LEVEL + */ +struct MHD_DaemonOptionValueStrctLvl +{ + /** + * The level of strictness + */ + enum MHD_ProtocolStrictLevel v_sl; + /** + * The way how to use the requested level + */ + enum MHD_UseStictLevel v_how; +}; + +/** + * Data for #MHD_D_O_EARLY_URI_LOGGER + */ +struct MHD_DaemonOptionValueUriCB +{ + /** + * The early URI callback + */ + MHD_EarlyUriLogCallback v_cb; + /** + * The closure for the callback + */ + void *v_cls; +}; + +/** + * Data for #MHD_D_O_DAEMON_READY_CALLBACK + */ +struct MHD_DaemonOptionValueReadyCB +{ + /** + * The pre-start callback + */ + MHD_DaemonReadyCallback v_cb; + /** + * The closure for the callback + */ + void *v_cb_cls; +}; + +/** + * Data for #MHD_D_O_NOTIFY_CONNECTION + */ +struct MHD_DaemonOptionValueNotifConnCB +{ + /** + * The callback for notifications + */ + MHD_NotifyConnectionCallback v_ncc; + /** + * The closure for the callback + */ + void *v_cls; +}; + +/** + * Data for #MHD_D_O_NOTIFY_STREAM + */ +struct MHD_DaemonOptionValueNotifStreamCB +{ + /** + * The callback for notifications + */ + MHD_NotifyStreamCallback v_nsc; + /** + * The closure for the callback + */ + void *v_cls; +}; + +/** + * Data for #MHD_D_O_RANDOM_ENTROPY + */ +struct MHD_DaemonOptionValueRand +{ + /** + * The size of the buffer + */ + size_t v_buf_size; + /** + * The buffer with strong random data, the content will be copied by MHD + */ + const void *v_buf; +}; + +/* = MHD Daemon Option structures above are generated automatically = */ + + +/** + * Parameters for MHD daemon options + */ +union MHD_DaemonOptionValue +{ + /* = MHD Daemon Option union members below are generated automatically = */ + /** + * Value for #MHD_D_O_WORK_MODE + */ + struct MHD_WorkModeWithParam v_work_mode; + /** + * Value for #MHD_D_O_POLL_SYSCALL + */ + enum MHD_SockPollSyscall v_poll_syscall; + /** + * Value for #MHD_D_O_LOG_CALLBACK + */ + struct MHD_DaemonOptionValueLog v_log_callback; + /** + * Value for #MHD_D_O_BIND_PORT + */ + struct MHD_DaemonOptionValueBind v_bind_port; + /** + * Value for #MHD_D_O_BIND_SA + */ + struct MHD_DaemonOptionValueSA v_bind_sa; + /** + * Value for #MHD_D_O_LISTEN_SOCKET + */ + MHD_socket v_listen_socket; + /** + * Value for #MHD_D_O_LISTEN_ADDR_REUSE + */ + enum MHD_DaemonOptionBindType v_listen_addr_reuse; + /** + * Value for #MHD_D_O_TCP_FASTOPEN + */ + struct MHD_DaemonOptionValueTFO v_tcp_fastopen; + /** + * Value for #MHD_D_O_LISTEN_BACKLOG + */ + unsigned int v_listen_backlog; + /** + * Value for #MHD_D_O_SIGPIPE_SUPPRESSED + */ + enum MHD_Bool v_sigpipe_suppressed; + /** + * Value for #MHD_D_O_TLS + */ + enum MHD_TlsBackend v_tls; + /** + * Value for #MHD_D_O_TLS_KEY_CERT + */ + struct MHD_DaemonOptionValueTlsCert v_tls_key_cert; + /** + * Value for #MHD_D_O_TLS_CLIENT_CA + */ + const char *v_tls_client_ca; + /** + * Value for #MHD_D_O_TLS_PSK_CALLBACK + */ + struct MHD_DaemonOptionValueTlsPskCB v_tls_psk_callback; + /** + * Value for #MHD_D_O_NO_ALPN + */ + enum MHD_Bool v_no_alpn; + /** + * Value for #MHD_D_O_DEFAULT_TIMEOUT + */ + unsigned int v_default_timeout; + /** + * Value for #MHD_D_O_GLOBAL_CONNECTION_LIMIT + */ + unsigned int v_global_connection_limit; + /** + * Value for #MHD_D_O_PER_IP_LIMIT + */ + unsigned int v_per_ip_limit; + /** + * Value for #MHD_D_O_ACCEPT_POLICY + */ + struct MHD_DaemonOptionValueAcceptPol v_accept_policy; + /** + * Value for #MHD_D_O_PROTOCOL_STRICT_LEVEL + */ + struct MHD_DaemonOptionValueStrctLvl v_protocol_strict_level; + /** + * Value for #MHD_D_O_EARLY_URI_LOGGER + */ + struct MHD_DaemonOptionValueUriCB v_early_uri_logger; + /** + * Value for #MHD_D_O_DISABLE_URI_QUERY_PLUS_AS_SPACE + */ + enum MHD_Bool v_disable_uri_query_plus_as_space; + /** + * Value for #MHD_D_O_SUPPRESS_DATE_HEADER + */ + enum MHD_Bool v_suppress_date_header; + /** + * Value for #MHD_D_O_ENABLE_SHOUTCAST + */ + enum MHD_Bool v_enable_shoutcast; + /** + * Value for #MHD_D_O_CONN_MEMORY_LIMIT + */ + size_t v_conn_memory_limit; + /** + * Value for #MHD_D_O_LARGE_POOL_SIZE + */ + size_t v_large_pool_size; + /** + * Value for #MHD_D_O_STACK_SIZE + */ + size_t v_stack_size; + /** + * Value for #MHD_D_O_FD_NUMBER_LIMIT + */ + MHD_socket v_fd_number_limit; + /** + * Value for #MHD_D_O_TURBO + */ + enum MHD_Bool v_turbo; + /** + * Value for #MHD_D_O_DISABLE_THREAD_SAFETY + */ + enum MHD_Bool v_disable_thread_safety; + /** + * Value for #MHD_D_O_DISALLOW_UPGRADE + */ + enum MHD_Bool v_disallow_upgrade; + /** + * Value for #MHD_D_O_DISALLOW_SUSPEND_RESUME + */ + enum MHD_Bool v_disallow_suspend_resume; + /** + * Value for #MHD_D_O_DAEMON_READY_CALLBACK + */ + struct MHD_DaemonOptionValueReadyCB v_daemon_ready_callback; + /** + * Value for #MHD_D_O_NOTIFY_CONNECTION + */ + struct MHD_DaemonOptionValueNotifConnCB v_notify_connection; + /** + * Value for #MHD_D_O_NOTIFY_STREAM + */ + struct MHD_DaemonOptionValueNotifStreamCB v_notify_stream; + /** + * Value for #MHD_D_O_RANDOM_ENTROPY + */ + struct MHD_DaemonOptionValueRand v_random_entropy; + /** + * Value for #MHD_D_O_DAUTH_MAP_SIZE + */ + size_t v_dauth_map_size; + /** + * Value for #MHD_D_O_DAUTH_NONCE_BIND_TYPE + */ + enum MHD_DaemonOptionValueDAuthBindNonce v_dauth_nonce_bind_type; + /** + * Value for #MHD_D_O_DAUTH_DEF_NONCE_TIMEOUT + */ + unsigned int v_dauth_def_nonce_timeout; + /** + * Value for #MHD_D_O_DAUTH_DEF_MAX_NC + */ + uint_fast32_t v_dauth_def_max_nc; + /* = MHD Daemon Option union members above are generated automatically = */ +}; + +/** + * Combination of MHD daemon option with parameters values + */ +struct MHD_DaemonOptionAndValue +{ + /** + * The daemon configuration option + */ + enum MHD_DaemonOption opt; + /** + * The value for the @a opt option + */ + union MHD_DaemonOptionValue val; +}; + + +#if defined(MHD_USE_COMPOUND_LITERALS) && defined(MHD_USE_DESIG_NEST_INIT) +/* = MHD Daemon Option macros below are generated automatically = */ +/** + * Set MHD work (threading and polling) mode. + * Consider use of #MHD_DAEMON_OPTION_WM_EXTERNAL_PERIODIC(), + * #MHD_DAEMON_OPTION_WM_EXTERNAL_EVENT_LOOP_CB_LEVEL(), + * #MHD_DAEMON_OPTION_WM_EXTERNAL_EVENT_LOOP_CB_EDGE(), + * #MHD_DAEMON_OPTION_WM_EXTERNAL_SINGLE_FD_WATCH(), + * #MHD_DAEMON_OPTION_WM_WORKER_THREADS() or + * #MHD_DAEMON_OPTION_WM_THREAD_PER_CONNECTION() instead of direct use of this + * parameter. + * @param wmp the object created by one of the next functions/macros: + * #MHD_WM_OPTION_EXTERNAL_PERIODIC(), + * #MHD_WM_OPTION_EXTERNAL_EVENT_LOOP_CB_LEVEL(), + * #MHD_WM_OPTION_EXTERNAL_EVENT_LOOP_CB_EDGE(), + * #MHD_WM_OPTION_EXTERNAL_SINGLE_FD_WATCH(), + * #MHD_WM_OPTION_WORKER_THREADS(), + * #MHD_WM_OPTION_THREAD_PER_CONNECTION() + * @return the object of struct MHD_DaemonOptionAndValue with the requested + * values + */ +# define MHD_D_OPTION_WORK_MODE(wmp) \ + MHD_NOWARN_COMPOUND_LITERALS_ \ + (const struct MHD_DaemonOptionAndValue) \ + { \ + .opt = (MHD_D_O_WORK_MODE), \ + .val.v_work_mode = (wmp) \ + } \ + MHD_RESTORE_WARN_COMPOUND_LITERALS_ + +/** + * Select a sockets watch system call used for internal polling. + * @param els the value of the parameter + * @return the object of struct MHD_DaemonOptionAndValue with the requested + * values + */ +# define MHD_D_OPTION_POLL_SYSCALL(els) \ + MHD_NOWARN_COMPOUND_LITERALS_ \ + (const struct MHD_DaemonOptionAndValue) \ + { \ + .opt = (MHD_D_O_POLL_SYSCALL), \ + .val.v_poll_syscall = (els) \ + } \ + MHD_RESTORE_WARN_COMPOUND_LITERALS_ + +/** + * Set a callback to use for logging + * @param log_cb the callback to use for logging, + * NULL to disable logging + * @param lob_cb_cls the closure for the logging callback + * @return the object of struct MHD_DaemonOptionAndValue with the requested + * values + */ +# define MHD_D_OPTION_LOG_CALLBACK(log_cb,lob_cb_cls) \ + MHD_NOWARN_COMPOUND_LITERALS_ \ + (const struct MHD_DaemonOptionAndValue) \ + { \ + .opt = (MHD_D_O_LOG_CALLBACK), \ + .val.v_log_callback.v_log_cb = (log_cb), \ + .val.v_log_callback.v_lob_cb_cls = (lob_cb_cls) \ + } \ + MHD_RESTORE_WARN_COMPOUND_LITERALS_ + +/** + * Bind to the given TCP port and address family. + * + * Does not work with #MHD_DAEMON_OPTION_BIND_SA() or + * #MHD_DAEMON_OPTION_LISTEN_SOCKET(). + * + * If no listen socket optins (#MHD_DAEMON_OPTION_BIND_PORT(), + * #MHD_DAEMON_OPTION_BIND_SA(), #MHD_DAEMON_OPTION_LISTEN_SOCKET()) are used, + * MHD does not listen for incoming connection. + * @param af the address family to use, + * the #MHD_AF_NONE to disable listen socket (the same effect as if + * this option is not used) + * @param port port to use, 0 to let system assign any free port, + * ignored if @a af is #MHD_AF_NONE + * @return the object of struct MHD_DaemonOptionAndValue with the requested + * values + */ +# define MHD_D_OPTION_BIND_PORT(af,port) \ + MHD_NOWARN_COMPOUND_LITERALS_ \ + (const struct MHD_DaemonOptionAndValue) \ + { \ + .opt = (MHD_D_O_BIND_PORT), \ + .val.v_bind_port.v_af = (af), \ + .val.v_bind_port.v_port = (port) \ + } \ + MHD_RESTORE_WARN_COMPOUND_LITERALS_ + +/** + * Bind to the given socket address. + * + * Does not work with #MHD_DAEMON_OPTION_BIND_PORT() or + * #MHD_DAEMON_OPTION_LISTEN_SOCKET(). + * + * If no listen socket optins (#MHD_DAEMON_OPTION_BIND_PORT(), + * #MHD_DAEMON_OPTION_BIND_SA(), #MHD_DAEMON_OPTION_LISTEN_SOCKET()) are used, + * MHD does not listen for incoming connection. + * @param sa_len the size of the socket address pointed by @a sa. + * @param sa the address to bind to; can be IPv4 (AF_INET), IPv6 (AF_INET6) or + * even a UNIX domain socket (AF_UNIX) + * @return the object of struct MHD_DaemonOptionAndValue with the requested + * values + */ +# define MHD_D_OPTION_BIND_SA(sa_len,sa) \ + MHD_NOWARN_COMPOUND_LITERALS_ \ + (const struct MHD_DaemonOptionAndValue) \ + { \ + .opt = (MHD_D_O_BIND_SA), \ + .val.v_bind_sa.v_sa_len = (sa_len), \ + .val.v_bind_sa.v_sa = (sa) \ + } \ + MHD_RESTORE_WARN_COMPOUND_LITERALS_ + +/** + * Accept connections from the given socket. Socket + * must be a TCP or UNIX domain (SOCK_STREAM) socket. + * + * Does not work with #MHD_DAEMON_OPTION_BIND_PORT() or + * #MHD_DAEMON_OPTION_BIND_SA(). + * + * If no listen socket optins (#MHD_DAEMON_OPTION_BIND_PORT(), + * #MHD_DAEMON_OPTION_BIND_SA(), #MHD_DAEMON_OPTION_LISTEN_SOCKET()) are used, + * MHD does not listen for incoming connection. + * @param listen_fd the listen socket to use, ignored if set to + * #MHD_INVALID_SOCKET + * @return the object of struct MHD_DaemonOptionAndValue with the requested + * values + */ +# define MHD_D_OPTION_LISTEN_SOCKET(listen_fd) \ + MHD_NOWARN_COMPOUND_LITERALS_ \ + (const struct MHD_DaemonOptionAndValue) \ + { \ + .opt = (MHD_D_O_LISTEN_SOCKET), \ + .val.v_listen_socket = (listen_fd) \ + } \ + MHD_RESTORE_WARN_COMPOUND_LITERALS_ + +/** + * Select mode of reusing address:port listen address. + * + * Works only when #MHD_DAEMON_OPTION_BIND_PORT() or + * #MHD_DAEMON_OPTION_BIND_SA() are used. + * @param reuse_type the value of the parameter + * @return the object of struct MHD_DaemonOptionAndValue with the requested + * values + */ +# define MHD_D_OPTION_LISTEN_ADDR_REUSE(reuse_type) \ + MHD_NOWARN_COMPOUND_LITERALS_ \ + (const struct MHD_DaemonOptionAndValue) \ + { \ + .opt = (MHD_D_O_LISTEN_ADDR_REUSE), \ + .val.v_listen_addr_reuse = (reuse_type) \ + } \ + MHD_RESTORE_WARN_COMPOUND_LITERALS_ + +/** + * Configure TCP_FASTOPEN option, including setting a + * custom @a queue_length. + * + * Note that having a larger queue size can cause resource exhaustion + * attack as the TCP stack has to now allocate resources for the SYN + * packet along with its DATA. + * + * Works only when #MHD_DAEMON_OPTION_BIND_PORT() or + * #MHD_DAEMON_OPTION_BIND_SA() are used. + * @param option the type use of of TCP FastOpen + * @param queue_length the length of the queue, zero to use system or MHD + * default, + * silently ignored on platforms without support for custom + * queue size + * @return the object of struct MHD_DaemonOptionAndValue with the requested + * values + */ +# define MHD_D_OPTION_TCP_FASTOPEN(option,queue_length) \ + MHD_NOWARN_COMPOUND_LITERALS_ \ + (const struct MHD_DaemonOptionAndValue) \ + { \ + .opt = (MHD_D_O_TCP_FASTOPEN), \ + .val.v_tcp_fastopen.v_option = (option), \ + .val.v_tcp_fastopen.v_queue_length = (queue_length) \ + } \ + MHD_RESTORE_WARN_COMPOUND_LITERALS_ + +/** + * Use the given backlog for the listen() call. + * + * Works only when #MHD_DAEMON_OPTION_BIND_PORT() or + * #MHD_DAEMON_OPTION_BIND_SA() are used. + * @param backlog_size the value of the parameter + * @return the object of struct MHD_DaemonOptionAndValue with the requested + * values + */ +# define MHD_D_OPTION_LISTEN_BACKLOG(backlog_size) \ + MHD_NOWARN_COMPOUND_LITERALS_ \ + (const struct MHD_DaemonOptionAndValue) \ + { \ + .opt = (MHD_D_O_LISTEN_BACKLOG), \ + .val.v_listen_backlog = (backlog_size) \ + } \ + MHD_RESTORE_WARN_COMPOUND_LITERALS_ + +/** + * Inform that SIGPIPE is suppressed or handled by application. + * If suppressed/handled, MHD uses network functions that could generate + * SIGPIPE, like `sendfile()`. + * Silently ignored when MHD creates internal threads as for them SIGPIPE is + * suppressed automatically. + * @param bool_val the value of the parameter + * @return the object of struct MHD_DaemonOptionAndValue with the requested + * values + */ +# define MHD_D_OPTION_SIGPIPE_SUPPRESSED(bool_val) \ + MHD_NOWARN_COMPOUND_LITERALS_ \ + (const struct MHD_DaemonOptionAndValue) \ + { \ + .opt = (MHD_D_O_SIGPIPE_SUPPRESSED), \ + .val.v_sigpipe_suppressed = (bool_val) \ + } \ + MHD_RESTORE_WARN_COMPOUND_LITERALS_ + +/** + * Enable TLS (HTTPS) and select TLS backend + * @param backend the TLS backend to use, + * #MHD_TLS_BACKEND_NONE for non-TLS (plain TCP) connections + * @return the object of struct MHD_DaemonOptionAndValue with the requested + * values + */ +# define MHD_D_OPTION_TLS(backend) \ + MHD_NOWARN_COMPOUND_LITERALS_ \ + (const struct MHD_DaemonOptionAndValue) \ + { \ + .opt = (MHD_D_O_TLS), \ + .val.v_tls = (backend) \ + } \ + MHD_RESTORE_WARN_COMPOUND_LITERALS_ + +/** + * Provide TLS key and certificate data in-memory. + * Works only if TLS mode is enabled. + * @param mem_key the private key loaded into memory (not a filename) + * @param mem_cert the certificate loaded into memory (not a filename) + * @param mem_cert the option passphrase phrase to decrypt the private key, + * could be NULL is private does not need a password + * @return the object of struct MHD_DaemonOptionAndValue with the requested + * values + */ +# define MHD_D_OPTION_TLS_KEY_CERT(mem_key,mem_cert,mem_cert) \ + MHD_NOWARN_COMPOUND_LITERALS_ \ + (const struct MHD_DaemonOptionAndValue) \ + { \ + .opt = (MHD_D_O_TLS_KEY_CERT), \ + .val.v_tls_key_cert.v_mem_key = (mem_key), \ + .val.v_tls_key_cert.v_mem_cert = (mem_cert), \ + .val.v_tls_key_cert.v_mem_cert = (mem_cert) \ + } \ + MHD_RESTORE_WARN_COMPOUND_LITERALS_ + +/** + * Provide the certificate of the certificate authority (CA) to be used by the + * MHD daemon for client authentication. + * Works only if TLS mode is enabled. + * @param mem_client_ca the CA certificate in memory (not a filename) + * @return the object of struct MHD_DaemonOptionAndValue with the requested + * values + */ +# define MHD_D_OPTION_TLS_CLIENT_CA(mem_client_ca) \ + MHD_NOWARN_COMPOUND_LITERALS_ \ + (const struct MHD_DaemonOptionAndValue) \ + { \ + .opt = (MHD_D_O_TLS_CLIENT_CA), \ + .val.v_tls_client_ca = (mem_client_ca) \ + } \ + MHD_RESTORE_WARN_COMPOUND_LITERALS_ + +/** + * Configure PSK to use for the TLS key exchange. + * @param psk_cb the function to call to obtain pre-shared key + * @param psk_cb_cls the closure for @a psk_cb + * @return the object of struct MHD_DaemonOptionAndValue with the requested + * values + */ +# define MHD_D_OPTION_TLS_PSK_CALLBACK(psk_cb,psk_cb_cls) \ + MHD_NOWARN_COMPOUND_LITERALS_ \ + (const struct MHD_DaemonOptionAndValue) \ + { \ + .opt = (MHD_D_O_TLS_PSK_CALLBACK), \ + .val.v_tls_psk_callback.v_psk_cb = (psk_cb), \ + .val.v_tls_psk_callback.v_psk_cb_cls = (psk_cb_cls) \ + } \ + MHD_RESTORE_WARN_COMPOUND_LITERALS_ + +/** + * Control ALPN for TLS connection. + * Silently ignored for non-TLS. + * By default ALPN is automatically used for TLS connections. + * @param bool_val the value of the parameter + * @return the object of struct MHD_DaemonOptionAndValue with the requested + * values + */ +# define MHD_D_OPTION_NO_ALPN(bool_val) \ + MHD_NOWARN_COMPOUND_LITERALS_ \ + (const struct MHD_DaemonOptionAndValue) \ + { \ + .opt = (MHD_D_O_NO_ALPN), \ + .val.v_no_alpn = (bool_val) \ + } \ + MHD_RESTORE_WARN_COMPOUND_LITERALS_ + +/** + * Specify inactivity timeout for connection. + * When no activity for specified time on connection, it is closed + * automatically. + * Use zero for no timeout, which is also the (unsafe!) default. + * @param timeout the in seconds, zero for no timeout + * @return the object of struct MHD_DaemonOptionAndValue with the requested + * values + */ +# define MHD_D_OPTION_DEFAULT_TIMEOUT(timeout) \ + MHD_NOWARN_COMPOUND_LITERALS_ \ + (const struct MHD_DaemonOptionAndValue) \ + { \ + .opt = (MHD_D_O_DEFAULT_TIMEOUT), \ + .val.v_default_timeout = (timeout) \ + } \ + MHD_RESTORE_WARN_COMPOUND_LITERALS_ + +/** + * Maximum number of (concurrent) network connections served by daemon + * @param glob_limit the value of the parameter + * @return the object of struct MHD_DaemonOptionAndValue with the requested + * values + */ +# define MHD_D_OPTION_GLOBAL_CONNECTION_LIMIT(glob_limit) \ + MHD_NOWARN_COMPOUND_LITERALS_ \ + (const struct MHD_DaemonOptionAndValue) \ + { \ + .opt = (MHD_D_O_GLOBAL_CONNECTION_LIMIT), \ + .val.v_global_connection_limit = (glob_limit) \ + } \ + MHD_RESTORE_WARN_COMPOUND_LITERALS_ + +/** + * Limit on the number of (concurrent) network connections made to the server + * from the same IP address. + * Can be used to prevent one IP from taking over all of the allowed + * connections. If the same IP tries to establish more than the specified + * number of connections, they will be immediately rejected. + * @param per_ip_limit the value of the parameter + * @return the object of struct MHD_DaemonOptionAndValue with the requested + * values + */ +# define MHD_D_OPTION_PER_IP_LIMIT(per_ip_limit) \ + MHD_NOWARN_COMPOUND_LITERALS_ \ + (const struct MHD_DaemonOptionAndValue) \ + { \ + .opt = (MHD_D_O_PER_IP_LIMIT), \ + .val.v_per_ip_limit = (per_ip_limit) \ + } \ + MHD_RESTORE_WARN_COMPOUND_LITERALS_ + +/** + * Set a policy callback that accepts/rejects connections based on the client's + * IP address. The callbeck function will be called before servicing any new + * incoming connection. + * @param apc the accept policy callback + * @param apc_cls the closure for the callback + * @return the object of struct MHD_DaemonOptionAndValue with the requested + * values + */ +# define MHD_D_OPTION_ACCEPT_POLICY(apc,apc_cls) \ + MHD_NOWARN_COMPOUND_LITERALS_ \ + (const struct MHD_DaemonOptionAndValue) \ + { \ + .opt = (MHD_D_O_ACCEPT_POLICY), \ + .val.v_accept_policy.v_apc = (apc), \ + .val.v_accept_policy.v_apc_cls = (apc_cls) \ + } \ + MHD_RESTORE_WARN_COMPOUND_LITERALS_ + +/** + * Set how strictly MHD will enforce the HTTP protocol. + * @param sl the level of strictness + * @param how the way how to use the requested level + * @return the object of struct MHD_DaemonOptionAndValue with the requested + * values + */ +# define MHD_D_OPTION_PROTOCOL_STRICT_LEVEL(sl,how) \ + MHD_NOWARN_COMPOUND_LITERALS_ \ + (const struct MHD_DaemonOptionAndValue) \ + { \ + .opt = (MHD_D_O_PROTOCOL_STRICT_LEVEL), \ + .val.v_protocol_strict_level.v_sl = (sl), \ + .val.v_protocol_strict_level.v_how = (how) \ + } \ + MHD_RESTORE_WARN_COMPOUND_LITERALS_ + +/** + * Set a callback to be called first for every request when the request line is + * received (before any parsing of the header). + * This callback is the only way to get raw (unmodified) request URI as URI is + * parsed and modified by MHD in-place. + * Mandatory URI modification may apply before this call, like binary zero + * replacement, as required by RFCs. + * @param cb the early URI callback + * @param cls the closure for the callback + * @return the object of struct MHD_DaemonOptionAndValue with the requested + * values + */ +# define MHD_D_OPTION_EARLY_URI_LOGGER(cb,cls) \ + MHD_NOWARN_COMPOUND_LITERALS_ \ + (const struct MHD_DaemonOptionAndValue) \ + { \ + .opt = (MHD_D_O_EARLY_URI_LOGGER), \ + .val.v_early_uri_logger.v_cb = (cb), \ + .val.v_early_uri_logger.v_cls = (cls) \ + } \ + MHD_RESTORE_WARN_COMPOUND_LITERALS_ + +/** + * Disable converting plus ('+') character to space in GET parameters (URI part + * after '?'). + * Plus conversion is not required by HTTP RFCs, however it required by HTML + * specifications, see + * https://url.spec.whatwg.org/#application/x-www-form-urlencoded for details. + * By default plus is converted to space in the query part of URI. + * @param bool_val the value of the parameter + * @return the object of struct MHD_DaemonOptionAndValue with the requested + * values + */ +# define MHD_D_OPTION_DISABLE_URI_QUERY_PLUS_AS_SPACE(bool_val) \ + MHD_NOWARN_COMPOUND_LITERALS_ \ + (const struct MHD_DaemonOptionAndValue) \ + { \ + .opt = (MHD_D_O_DISABLE_URI_QUERY_PLUS_AS_SPACE), \ + .val.v_disable_uri_query_plus_as_space = (bool_val) \ + } \ + MHD_RESTORE_WARN_COMPOUND_LITERALS_ + +/** + * Suppresse use of "Date:" header. + * According to RFC should be suppressed only if the system has no RTC. + * The "Date:" is not suppressed (the header is enabled) by default. + * @param bool_val the value of the parameter + * @return the object of struct MHD_DaemonOptionAndValue with the requested + * values + */ +# define MHD_D_OPTION_SUPPRESS_DATE_HEADER(bool_val) \ + MHD_NOWARN_COMPOUND_LITERALS_ \ + (const struct MHD_DaemonOptionAndValue) \ + { \ + .opt = (MHD_D_O_SUPPRESS_DATE_HEADER), \ + .val.v_suppress_date_header = (bool_val) \ + } \ + MHD_RESTORE_WARN_COMPOUND_LITERALS_ + +/** + * Use SHOUTcast for responses. + * This will cause *all* responses to begin with the SHOUTcast "ICY" line + * instead of "HTTP". + * @param bool_val the value of the parameter + * @return the object of struct MHD_DaemonOptionAndValue with the requested + * values + */ +# define MHD_D_OPTION_ENABLE_SHOUTCAST(bool_val) \ + MHD_NOWARN_COMPOUND_LITERALS_ \ + (const struct MHD_DaemonOptionAndValue) \ + { \ + .opt = (MHD_D_O_ENABLE_SHOUTCAST), \ + .val.v_enable_shoutcast = (bool_val) \ + } \ + MHD_RESTORE_WARN_COMPOUND_LITERALS_ + +/** + * Maximum memory size per connection. + * Default is 32kb. + * Values above 128kb are unlikely to result in much performance benefit, as + * half of the memory will be typically used for IO, and TCP buffers are + * unlikely to support window sizes above 64k on most systems. + * The size should be large enough to fit all request headers (together with + * internal parsing information). + * @param sizet_val the value of the parameter + * @return the object of struct MHD_DaemonOptionAndValue with the requested + * values + */ +# define MHD_D_OPTION_CONN_MEMORY_LIMIT(sizet_val) \ + MHD_NOWARN_COMPOUND_LITERALS_ \ + (const struct MHD_DaemonOptionAndValue) \ + { \ + .opt = (MHD_D_O_CONN_MEMORY_LIMIT), \ + .val.v_conn_memory_limit = (sizet_val) \ + } \ + MHD_RESTORE_WARN_COMPOUND_LITERALS_ + +/** + * The size of the shared memory pool for accamulated upload processing. + * The same "large" pool is shared for all connections server by MHD and used + * when application requests avoiding of incremental upload processing to + * accamulate complete content upload before giving it to the application. + * Default is 8Mb. + * Can be set to zero to disable share pool. + * @param sizet_val the value of the parameter + * @return the object of struct MHD_DaemonOptionAndValue with the requested + * values + */ +# define MHD_D_OPTION_LARGE_POOL_SIZE(sizet_val) \ + MHD_NOWARN_COMPOUND_LITERALS_ \ + (const struct MHD_DaemonOptionAndValue) \ + { \ + .opt = (MHD_D_O_LARGE_POOL_SIZE), \ + .val.v_large_pool_size = (sizet_val) \ + } \ + MHD_RESTORE_WARN_COMPOUND_LITERALS_ + +/** + * Desired size of the stack for the threads started by MHD. + * Use 0 for system default, which is also MHD default. + * Works only with ##MHD_DAEMON_OPTION_WORKER_THREADS() or + * #MHD_DAEMON_OPTION_THREAD_PER_CONNECTION(). + * @param sizet_val the value of the parameter + * @return the object of struct MHD_DaemonOptionAndValue with the requested + * values + */ +# define MHD_D_OPTION_STACK_SIZE(sizet_val) \ + MHD_NOWARN_COMPOUND_LITERALS_ \ + (const struct MHD_DaemonOptionAndValue) \ + { \ + .opt = (MHD_D_O_STACK_SIZE), \ + .val.v_stack_size = (sizet_val) \ + } \ + MHD_RESTORE_WARN_COMPOUND_LITERALS_ + +/** + * The the maximum FD value. + * The limit is applied to all sockets used by MHD. + * If listen socket FD is equal or higher that specified value, the daemon fail + * to start. + * If new connection FD is equal or higher that specified value, the connection + * is rejected. + * Useful if application uses select() for polling the sockets, system + * FD_SETSIZE is good value for this option in such case. + * Does not work with ##MHD_DAEMON_OPTION_WORKER_THREADS() or + * #MHD_DAEMON_OPTION_THREAD_PER_CONNECTION(). + * Does not work on W32 (WinSock sockets). + * @param max_fd the value of the parameter + * @return the object of struct MHD_DaemonOptionAndValue with the requested + * values + */ +# define MHD_D_OPTION_FD_NUMBER_LIMIT(max_fd) \ + MHD_NOWARN_COMPOUND_LITERALS_ \ + (const struct MHD_DaemonOptionAndValue) \ + { \ + .opt = (MHD_D_O_FD_NUMBER_LIMIT), \ + .val.v_fd_number_limit = (max_fd) \ + } \ + MHD_RESTORE_WARN_COMPOUND_LITERALS_ + +/** + * Enable `turbo`. + * Disables certain calls to `shutdown()`, enables aggressive non-blocking + * optimistic reads and other potentially unsafe optimisations. + * Most effects only happen with internal threads with epoll. + * The 'turbo' mode is not enabled (mode is disabled) by default. + * @param bool_val the value of the parameter + * @return the object of struct MHD_DaemonOptionAndValue with the requested + * values + */ +# define MHD_D_OPTION_TURBO(bool_val) \ + MHD_NOWARN_COMPOUND_LITERALS_ \ + (const struct MHD_DaemonOptionAndValue) \ + { \ + .opt = (MHD_D_O_TURBO), \ + .val.v_turbo = (bool_val) \ + } \ + MHD_RESTORE_WARN_COMPOUND_LITERALS_ + +/** + * Disable some internal thread safety. + * Indicates that MHD daemon will be used by application in single-threaded + * mode only. When this flag is set then application must call any MHD + * function only within a single thread. + * This flag turns off some internal thread-safety and allows MHD making some + * of the internal optimisations suitable only for single-threaded environment. + * Not compatible with any internal threads modes. + * If MHD is compiled with custom configuration for embedded projects without + * threads support, this option is mandatory. + * Thread safety is not disabled (safety is enabled) by default. + * @param bool_val the value of the parameter + * @return the object of struct MHD_DaemonOptionAndValue with the requested + * values + */ +# define MHD_D_OPTION_DISABLE_THREAD_SAFETY(bool_val) \ + MHD_NOWARN_COMPOUND_LITERALS_ \ + (const struct MHD_DaemonOptionAndValue) \ + { \ + .opt = (MHD_D_O_DISABLE_THREAD_SAFETY), \ + .val.v_disable_thread_safety = (bool_val) \ + } \ + MHD_RESTORE_WARN_COMPOUND_LITERALS_ + +/** + * You need to set this option if you want to disable use of HTTP "Upgrade". + * "Upgrade" may require usage of additional internal resources, which we can + * avoid providing if they will not be used. + * You should only use this option if you do not use "Upgrade" functionality + * and need a generally minor boost in performance and resources saving. + * The "Upgrade" is not disallowed ("upgrade" is allowed) by default. + * @param bool_val the value of the parameter + * @return the object of struct MHD_DaemonOptionAndValue with the requested + * values + */ +# define MHD_D_OPTION_DISALLOW_UPGRADE(bool_val) \ + MHD_NOWARN_COMPOUND_LITERALS_ \ + (const struct MHD_DaemonOptionAndValue) \ + { \ + .opt = (MHD_D_O_DISALLOW_UPGRADE), \ + .val.v_disallow_upgrade = (bool_val) \ + } \ + MHD_RESTORE_WARN_COMPOUND_LITERALS_ + +/** + * Disable #MHD_action_suspend() functionality. + * + * You should only use this function if you do not use suspend functionality + * and need a generally minor boost in performance. + * The suspend is not disallowed (suspend is allowed) by default. + * @param bool_val the value of the parameter + * @return the object of struct MHD_DaemonOptionAndValue with the requested + * values + */ +# define MHD_D_OPTION_DISALLOW_SUSPEND_RESUME(bool_val) \ + MHD_NOWARN_COMPOUND_LITERALS_ \ + (const struct MHD_DaemonOptionAndValue) \ + { \ + .opt = (MHD_D_O_DISALLOW_SUSPEND_RESUME), \ + .val.v_disallow_suspend_resume = (bool_val) \ + } \ + MHD_RESTORE_WARN_COMPOUND_LITERALS_ + +/** + * Set a callback to be called for pre-start finalisation. + * + * The specified callback will be called one time, after network + * initialisation, TLS pre-initialisation, but before the start of the internal + * threads (if allowed) + * @param cb the pre-start callback + * @param cb_cls the closure for the callback + * @return the object of struct MHD_DaemonOptionAndValue with the requested + * values + */ +# define MHD_D_OPTION_DAEMON_READY_CALLBACK(cb,cb_cls) \ + MHD_NOWARN_COMPOUND_LITERALS_ \ + (const struct MHD_DaemonOptionAndValue) \ + { \ + .opt = (MHD_D_O_DAEMON_READY_CALLBACK), \ + .val.v_daemon_ready_callback.v_cb = (cb), \ + .val.v_daemon_ready_callback.v_cb_cls = (cb_cls) \ + } \ + MHD_RESTORE_WARN_COMPOUND_LITERALS_ + +/** + * Set a function that should be called whenever a connection is started or + * closed. + * @param ncc the callback for notifications + * @param cls the closure for the callback + * @return the object of struct MHD_DaemonOptionAndValue with the requested + * values + */ +# define MHD_D_OPTION_NOTIFY_CONNECTION(ncc,cls) \ + MHD_NOWARN_COMPOUND_LITERALS_ \ + (const struct MHD_DaemonOptionAndValue) \ + { \ + .opt = (MHD_D_O_NOTIFY_CONNECTION), \ + .val.v_notify_connection.v_ncc = (ncc), \ + .val.v_notify_connection.v_cls = (cls) \ + } \ + MHD_RESTORE_WARN_COMPOUND_LITERALS_ + +/** + * Register a function that should be called whenever a stream is started or + * closed. + * For HTTP/1.1 this callback is called one time for every connection. + * @param nsc the callback for notifications + * @param cls the closure for the callback + * @return the object of struct MHD_DaemonOptionAndValue with the requested + * values + */ +# define MHD_D_OPTION_NOTIFY_STREAM(nsc,cls) \ + MHD_NOWARN_COMPOUND_LITERALS_ \ + (const struct MHD_DaemonOptionAndValue) \ + { \ + .opt = (MHD_D_O_NOTIFY_STREAM), \ + .val.v_notify_stream.v_nsc = (nsc), \ + .val.v_notify_stream.v_cls = (cls) \ + } \ + MHD_RESTORE_WARN_COMPOUND_LITERALS_ + +/** + * Set strong random data to be used by MHD. + * Currently the data is only needed for Digest Auth module. + * The recommended size is between 8 and 32 bytes. Security can be lower for + * sizes less or equal four. + * Sizes larger then 32 (or, probably, larger than 16 - debatable) will not + * increase the security. + * @param buf_size the size of the buffer + * @param buf the buffer with strong random data, the content will be copied by + * MHD + * @return the object of struct MHD_DaemonOptionAndValue with the requested + * values + */ +# define MHD_D_OPTION_RANDOM_ENTROPY(buf_size,buf) \ + MHD_NOWARN_COMPOUND_LITERALS_ \ + (const struct MHD_DaemonOptionAndValue) \ + { \ + .opt = (MHD_D_O_RANDOM_ENTROPY), \ + .val.v_random_entropy.v_buf_size = (buf_size), \ + .val.v_random_entropy.v_buf = (buf) \ + } \ + MHD_RESTORE_WARN_COMPOUND_LITERALS_ + +/** + * Specify the size of the internal hash map array that tracks generated digest + * nonces usage. + * When the size of the map is too small then need to handle concurrent DAuth + * requests, a lot of "stale nonce" results will be produced. + * By default the size is 8 bytes (very small). + * @param size the size of the map array + * @return the object of struct MHD_DaemonOptionAndValue with the requested + * values + */ +# define MHD_D_OPTION_DAUTH_MAP_SIZE(size) \ + MHD_NOWARN_COMPOUND_LITERALS_ \ + (const struct MHD_DaemonOptionAndValue) \ + { \ + .opt = (MHD_D_O_DAUTH_MAP_SIZE), \ + .val.v_dauth_map_size = (size) \ + } \ + MHD_RESTORE_WARN_COMPOUND_LITERALS_ + +/** + * Control the scope of validity of MHD-generated nonces. + * This regulates how "nonces" are generated and how "nonces" are checked by + * #MHD_digest_auth_check() and similar functions. + * This option allows bitwise OR combination of + * #MHD_DaemonOptionValueDAuthBindNonce values. + * When this option is not used then default value is + * #MHD_DAEMON_OPTION_VALUE_DAUTH_BIND_NONCE_NONE. + * @param bind_type the value of the parameter + * @return the object of struct MHD_DaemonOptionAndValue with the requested + * values + */ +# define MHD_D_OPTION_DAUTH_NONCE_BIND_TYPE(bind_type) \ + MHD_NOWARN_COMPOUND_LITERALS_ \ + (const struct MHD_DaemonOptionAndValue) \ + { \ + .opt = (MHD_D_O_DAUTH_NONCE_BIND_TYPE), \ + .val.v_dauth_nonce_bind_type = (bind_type) \ + } \ + MHD_RESTORE_WARN_COMPOUND_LITERALS_ + +/** + * Default nonce timeout value (in seconds) used for Digest Auth. + * Silently ignored if followed by zero value. + * @see #MHD_digest_auth_check(), MHD_digest_auth_check_digest() + * @param timeout the value of the parameter + * @return the object of struct MHD_DaemonOptionAndValue with the requested + * values + */ +# define MHD_D_OPTION_DAUTH_DEF_NONCE_TIMEOUT(timeout) \ + MHD_NOWARN_COMPOUND_LITERALS_ \ + (const struct MHD_DaemonOptionAndValue) \ + { \ + .opt = (MHD_D_O_DAUTH_DEF_NONCE_TIMEOUT), \ + .val.v_dauth_def_nonce_timeout = (timeout) \ + } \ + MHD_RESTORE_WARN_COMPOUND_LITERALS_ + +/** + * Default maximum nc (nonce count) value used for Digest Auth. + * Silently ignored if followed by zero value. + * @see #MHD_digest_auth_check(), MHD_digest_auth_check_digest() + * @param max_nc the value of the parameter + * @return the object of struct MHD_DaemonOptionAndValue with the requested + * values + */ +# define MHD_D_OPTION_DAUTH_DEF_MAX_NC(max_nc) \ + MHD_NOWARN_COMPOUND_LITERALS_ \ + (const struct MHD_DaemonOptionAndValue) \ + { \ + .opt = (MHD_D_O_DAUTH_DEF_MAX_NC), \ + .val.v_dauth_def_max_nc = (max_nc) \ + } \ + MHD_RESTORE_WARN_COMPOUND_LITERALS_ + +/* = MHD Daemon Option macros above are generated automatically = */ + +/** + * Terminate the list of the options + * @return the terminating object of struct MHD_DaemonOptionAndValue + */ +# define MHD_D_OPTION_TERMINATE() \ + MHD_NOWARN_COMPOUND_LITERALS_ \ + (const struct MHD_DaemonOptionAndValue) \ + { \ + .opt = (MHD_D_O_END) \ + } \ + MHD_RESTORE_WARN_COMPOUND_LITERALS_ + +#else /* !MHD_USE_COMPOUND_LITERALS || !MHD_USE_DESIG_NEST_INIT */ +MHD_NOWARN_UNUSED_FUNC_ +/* = MHD Daemon Option static functions below are generated automatically = */ +/** + * Set MHD work (threading and polling) mode. + * Consider use of #MHD_DAEMON_OPTION_WM_EXTERNAL_PERIODIC(), + * #MHD_DAEMON_OPTION_WM_EXTERNAL_EVENT_LOOP_CB_LEVEL(), + * #MHD_DAEMON_OPTION_WM_EXTERNAL_EVENT_LOOP_CB_EDGE(), + * #MHD_DAEMON_OPTION_WM_EXTERNAL_SINGLE_FD_WATCH(), + * #MHD_DAEMON_OPTION_WM_WORKER_THREADS() or + * #MHD_DAEMON_OPTION_WM_THREAD_PER_CONNECTION() instead of direct use of this + * parameter. + * @param wmp the object created by one of the next functions/macros: + * #MHD_WM_OPTION_EXTERNAL_PERIODIC(), + * #MHD_WM_OPTION_EXTERNAL_EVENT_LOOP_CB_LEVEL(), + * #MHD_WM_OPTION_EXTERNAL_EVENT_LOOP_CB_EDGE(), + * #MHD_WM_OPTION_EXTERNAL_SINGLE_FD_WATCH(), + * #MHD_WM_OPTION_WORKER_THREADS(), + * #MHD_WM_OPTION_THREAD_PER_CONNECTION() + * @return the object of struct MHD_DaemonOptionAndValue with the requested + * values + */ +static MHD_INLINE struct MHD_DaemonOptionAndValue +MHD_D_OPTION_WORK_MODE (struct MHD_WorkModeWithParam wmp) +{ + struct MHD_DaemonOptionAndValue opt_val; + + opt_val.opt = MHD_D_O_WORK_MODE; + opt_val.val.v_work_mode = wmp; + + return opt_val; +} + + +/** + * Select a sockets watch system call used for internal polling. + * @param els the value of the parameter + * @return the object of struct MHD_DaemonOptionAndValue with the requested + * values + */ +static MHD_INLINE struct MHD_DaemonOptionAndValue +MHD_D_OPTION_POLL_SYSCALL (enum MHD_SockPollSyscall els) +{ + struct MHD_DaemonOptionAndValue opt_val; + + opt_val.opt = MHD_D_O_POLL_SYSCALL; + opt_val.val.v_poll_syscall = els; + + return opt_val; +} + + +/** + * Set a callback to use for logging + * @param log_cb the callback to use for logging, + * NULL to disable logging + * @param lob_cb_cls the closure for the logging callback + * @return the object of struct MHD_DaemonOptionAndValue with the requested + * values + */ +static MHD_INLINE struct MHD_DaemonOptionAndValue +MHD_D_OPTION_LOG_CALLBACK ( + MHD_LoggingCallback log_cb, + void *lob_cb_cls) +{ + struct MHD_DaemonOptionAndValue opt_val; + + opt_val.opt = MHD_D_O_LOG_CALLBACK; + opt_val.val.v_log_callback.v_log_cb = log_cb; + opt_val.val.v_log_callback.v_lob_cb_cls = lob_cb_cls; + + return opt_val; +} + + +/** + * Bind to the given TCP port and address family. + * + * Does not work with #MHD_DAEMON_OPTION_BIND_SA() or + * #MHD_DAEMON_OPTION_LISTEN_SOCKET(). + * + * If no listen socket optins (#MHD_DAEMON_OPTION_BIND_PORT(), + * #MHD_DAEMON_OPTION_BIND_SA(), #MHD_DAEMON_OPTION_LISTEN_SOCKET()) are used, + * MHD does not listen for incoming connection. + * @param af the address family to use, + * the #MHD_AF_NONE to disable listen socket (the same effect as if + * this option is not used) + * @param port port to use, 0 to let system assign any free port, + * ignored if @a af is #MHD_AF_NONE + * @return the object of struct MHD_DaemonOptionAndValue with the requested + * values + */ +static MHD_INLINE struct MHD_DaemonOptionAndValue +MHD_D_OPTION_BIND_PORT ( + enum MHD_AddressFamily af, + uint_fast16_t port) +{ + struct MHD_DaemonOptionAndValue opt_val; + + opt_val.opt = MHD_D_O_BIND_PORT; + opt_val.val.v_bind_port.v_af = af; + opt_val.val.v_bind_port.v_port = port; + + return opt_val; +} + + +/** + * Bind to the given socket address. + * + * Does not work with #MHD_DAEMON_OPTION_BIND_PORT() or + * #MHD_DAEMON_OPTION_LISTEN_SOCKET(). + * + * If no listen socket optins (#MHD_DAEMON_OPTION_BIND_PORT(), + * #MHD_DAEMON_OPTION_BIND_SA(), #MHD_DAEMON_OPTION_LISTEN_SOCKET()) are used, + * MHD does not listen for incoming connection. + * @param sa_len the size of the socket address pointed by @a sa. + * @param sa the address to bind to; can be IPv4 (AF_INET), IPv6 (AF_INET6) or + * even a UNIX domain socket (AF_UNIX) + * @return the object of struct MHD_DaemonOptionAndValue with the requested + * values + */ +static MHD_INLINE struct MHD_DaemonOptionAndValue +MHD_D_OPTION_BIND_SA ( + size_t sa_len, + const struct sockaddr *sa) +{ + struct MHD_DaemonOptionAndValue opt_val; + + opt_val.opt = MHD_D_O_BIND_SA; + opt_val.val.v_bind_sa.v_sa_len = sa_len; + opt_val.val.v_bind_sa.v_sa = sa; + + return opt_val; +} + + +/** + * Accept connections from the given socket. Socket + * must be a TCP or UNIX domain (SOCK_STREAM) socket. + * + * Does not work with #MHD_DAEMON_OPTION_BIND_PORT() or + * #MHD_DAEMON_OPTION_BIND_SA(). + * + * If no listen socket optins (#MHD_DAEMON_OPTION_BIND_PORT(), + * #MHD_DAEMON_OPTION_BIND_SA(), #MHD_DAEMON_OPTION_LISTEN_SOCKET()) are used, + * MHD does not listen for incoming connection. + * @param listen_fd the listen socket to use, ignored if set to + * #MHD_INVALID_SOCKET + * @return the object of struct MHD_DaemonOptionAndValue with the requested + * values + */ +static MHD_INLINE struct MHD_DaemonOptionAndValue +MHD_D_OPTION_LISTEN_SOCKET (MHD_socket listen_fd) +{ + struct MHD_DaemonOptionAndValue opt_val; + + opt_val.opt = MHD_D_O_LISTEN_SOCKET; + opt_val.val.v_listen_socket = listen_fd; + + return opt_val; +} + + +/** + * Select mode of reusing address:port listen address. + * + * Works only when #MHD_DAEMON_OPTION_BIND_PORT() or + * #MHD_DAEMON_OPTION_BIND_SA() are used. + * @param reuse_type the value of the parameter + * @return the object of struct MHD_DaemonOptionAndValue with the requested + * values + */ +static MHD_INLINE struct MHD_DaemonOptionAndValue +MHD_D_OPTION_LISTEN_ADDR_REUSE (enum MHD_DaemonOptionBindType reuse_type) +{ + struct MHD_DaemonOptionAndValue opt_val; + + opt_val.opt = MHD_D_O_LISTEN_ADDR_REUSE; + opt_val.val.v_listen_addr_reuse = reuse_type; + + return opt_val; +} + + +/** + * Configure TCP_FASTOPEN option, including setting a + * custom @a queue_length. + * + * Note that having a larger queue size can cause resource exhaustion + * attack as the TCP stack has to now allocate resources for the SYN + * packet along with its DATA. + * + * Works only when #MHD_DAEMON_OPTION_BIND_PORT() or + * #MHD_DAEMON_OPTION_BIND_SA() are used. + * @param option the type use of of TCP FastOpen + * @param queue_length the length of the queue, zero to use system or MHD + * default, + * silently ignored on platforms without support for custom + * queue size + * @return the object of struct MHD_DaemonOptionAndValue with the requested + * values + */ +static MHD_INLINE struct MHD_DaemonOptionAndValue +MHD_D_OPTION_TCP_FASTOPEN ( + enum MHD_TCPFastOpenType option, + unsigned int queue_length) +{ + struct MHD_DaemonOptionAndValue opt_val; + + opt_val.opt = MHD_D_O_TCP_FASTOPEN; + opt_val.val.v_tcp_fastopen.v_option = option; + opt_val.val.v_tcp_fastopen.v_queue_length = queue_length; + + return opt_val; +} + + +/** + * Use the given backlog for the listen() call. + * + * Works only when #MHD_DAEMON_OPTION_BIND_PORT() or + * #MHD_DAEMON_OPTION_BIND_SA() are used. + * @param backlog_size the value of the parameter + * @return the object of struct MHD_DaemonOptionAndValue with the requested + * values + */ +static MHD_INLINE struct MHD_DaemonOptionAndValue +MHD_D_OPTION_LISTEN_BACKLOG (unsigned int backlog_size) +{ + struct MHD_DaemonOptionAndValue opt_val; + + opt_val.opt = MHD_D_O_LISTEN_BACKLOG; + opt_val.val.v_listen_backlog = backlog_size; + + return opt_val; +} + + +/** + * Inform that SIGPIPE is suppressed or handled by application. + * If suppressed/handled, MHD uses network functions that could generate + * SIGPIPE, like `sendfile()`. + * Silently ignored when MHD creates internal threads as for them SIGPIPE is + * suppressed automatically. + * @param bool_val the value of the parameter + * @return the object of struct MHD_DaemonOptionAndValue with the requested + * values + */ +static MHD_INLINE struct MHD_DaemonOptionAndValue +MHD_D_OPTION_SIGPIPE_SUPPRESSED (enum MHD_Bool bool_val) +{ + struct MHD_DaemonOptionAndValue opt_val; + + opt_val.opt = MHD_D_O_SIGPIPE_SUPPRESSED; + opt_val.val.v_sigpipe_suppressed = bool_val; + + return opt_val; +} + + +/** + * Enable TLS (HTTPS) and select TLS backend + * @param backend the TLS backend to use, + * #MHD_TLS_BACKEND_NONE for non-TLS (plain TCP) connections + * @return the object of struct MHD_DaemonOptionAndValue with the requested + * values + */ +static MHD_INLINE struct MHD_DaemonOptionAndValue +MHD_D_OPTION_TLS (enum MHD_TlsBackend backend) +{ + struct MHD_DaemonOptionAndValue opt_val; + + opt_val.opt = MHD_D_O_TLS; + opt_val.val.v_tls = backend; + + return opt_val; +} + + +/** + * Provide TLS key and certificate data in-memory. + * Works only if TLS mode is enabled. + * @param mem_key the private key loaded into memory (not a filename) + * @param mem_cert the certificate loaded into memory (not a filename) + * @param mem_cert the option passphrase phrase to decrypt the private key, + * could be NULL is private does not need a password + * @return the object of struct MHD_DaemonOptionAndValue with the requested + * values + */ +static MHD_INLINE struct MHD_DaemonOptionAndValue +MHD_D_OPTION_TLS_KEY_CERT ( + const char *mem_key, + const char *mem_cert, + const char *mem_cert) +{ + struct MHD_DaemonOptionAndValue opt_val; + + opt_val.opt = MHD_D_O_TLS_KEY_CERT; + opt_val.val.v_tls_key_cert.v_mem_key = mem_key; + opt_val.val.v_tls_key_cert.v_mem_cert = mem_cert; + opt_val.val.v_tls_key_cert.v_mem_cert = mem_cert; + + return opt_val; +} + + +/** + * Provide the certificate of the certificate authority (CA) to be used by the + * MHD daemon for client authentication. + * Works only if TLS mode is enabled. + * @param mem_client_ca the CA certificate in memory (not a filename) + * @return the object of struct MHD_DaemonOptionAndValue with the requested + * values + */ +static MHD_INLINE struct MHD_DaemonOptionAndValue +MHD_D_OPTION_TLS_CLIENT_CA (const char *mem_client_ca) +{ + struct MHD_DaemonOptionAndValue opt_val; + + opt_val.opt = MHD_D_O_TLS_CLIENT_CA; + opt_val.val.v_tls_client_ca = mem_client_ca; + + return opt_val; +} + + +/** + * Configure PSK to use for the TLS key exchange. + * @param psk_cb the function to call to obtain pre-shared key + * @param psk_cb_cls the closure for @a psk_cb + * @return the object of struct MHD_DaemonOptionAndValue with the requested + * values + */ +static MHD_INLINE struct MHD_DaemonOptionAndValue +MHD_D_OPTION_TLS_PSK_CALLBACK ( + MHD_PskServerCredentialsCallback psk_cb, + void *psk_cb_cls) +{ + struct MHD_DaemonOptionAndValue opt_val; + + opt_val.opt = MHD_D_O_TLS_PSK_CALLBACK; + opt_val.val.v_tls_psk_callback.v_psk_cb = psk_cb; + opt_val.val.v_tls_psk_callback.v_psk_cb_cls = psk_cb_cls; + + return opt_val; +} + + +/** + * Control ALPN for TLS connection. + * Silently ignored for non-TLS. + * By default ALPN is automatically used for TLS connections. + * @param bool_val the value of the parameter + * @return the object of struct MHD_DaemonOptionAndValue with the requested + * values + */ +static MHD_INLINE struct MHD_DaemonOptionAndValue +MHD_D_OPTION_NO_ALPN (enum MHD_Bool bool_val) +{ + struct MHD_DaemonOptionAndValue opt_val; + + opt_val.opt = MHD_D_O_NO_ALPN; + opt_val.val.v_no_alpn = bool_val; + + return opt_val; +} + + +/** + * Specify inactivity timeout for connection. + * When no activity for specified time on connection, it is closed + * automatically. + * Use zero for no timeout, which is also the (unsafe!) default. + * @param timeout the in seconds, zero for no timeout + * @return the object of struct MHD_DaemonOptionAndValue with the requested + * values + */ +static MHD_INLINE struct MHD_DaemonOptionAndValue +MHD_D_OPTION_DEFAULT_TIMEOUT (unsigned int timeout) +{ + struct MHD_DaemonOptionAndValue opt_val; + + opt_val.opt = MHD_D_O_DEFAULT_TIMEOUT; + opt_val.val.v_default_timeout = timeout; + + return opt_val; +} + + +/** + * Maximum number of (concurrent) network connections served by daemon + * @param glob_limit the value of the parameter + * @return the object of struct MHD_DaemonOptionAndValue with the requested + * values + */ +static MHD_INLINE struct MHD_DaemonOptionAndValue +MHD_D_OPTION_GLOBAL_CONNECTION_LIMIT (unsigned int glob_limit) +{ + struct MHD_DaemonOptionAndValue opt_val; + + opt_val.opt = MHD_D_O_GLOBAL_CONNECTION_LIMIT; + opt_val.val.v_global_connection_limit = glob_limit; + + return opt_val; +} + + +/** + * Limit on the number of (concurrent) network connections made to the server + * from the same IP address. + * Can be used to prevent one IP from taking over all of the allowed + * connections. If the same IP tries to establish more than the specified + * number of connections, they will be immediately rejected. + * @param per_ip_limit the value of the parameter + * @return the object of struct MHD_DaemonOptionAndValue with the requested + * values + */ +static MHD_INLINE struct MHD_DaemonOptionAndValue +MHD_D_OPTION_PER_IP_LIMIT (unsigned int per_ip_limit) +{ + struct MHD_DaemonOptionAndValue opt_val; + + opt_val.opt = MHD_D_O_PER_IP_LIMIT; + opt_val.val.v_per_ip_limit = per_ip_limit; + + return opt_val; +} + + +/** + * Set a policy callback that accepts/rejects connections based on the client's + * IP address. The callbeck function will be called before servicing any new + * incoming connection. + * @param apc the accept policy callback + * @param apc_cls the closure for the callback + * @return the object of struct MHD_DaemonOptionAndValue with the requested + * values + */ +static MHD_INLINE struct MHD_DaemonOptionAndValue +MHD_D_OPTION_ACCEPT_POLICY ( + MHD_AcceptPolicyCallback apc, + void *apc_cls) +{ + struct MHD_DaemonOptionAndValue opt_val; + + opt_val.opt = MHD_D_O_ACCEPT_POLICY; + opt_val.val.v_accept_policy.v_apc = apc; + opt_val.val.v_accept_policy.v_apc_cls = apc_cls; + + return opt_val; +} + + +/** + * Set how strictly MHD will enforce the HTTP protocol. + * @param sl the level of strictness + * @param how the way how to use the requested level + * @return the object of struct MHD_DaemonOptionAndValue with the requested + * values + */ +static MHD_INLINE struct MHD_DaemonOptionAndValue +MHD_D_OPTION_PROTOCOL_STRICT_LEVEL ( + enum MHD_ProtocolStrictLevel sl, + enum MHD_UseStictLevel how) +{ + struct MHD_DaemonOptionAndValue opt_val; + + opt_val.opt = MHD_D_O_PROTOCOL_STRICT_LEVEL; + opt_val.val.v_protocol_strict_level.v_sl = sl; + opt_val.val.v_protocol_strict_level.v_how = how; + + return opt_val; +} + + +/** + * Set a callback to be called first for every request when the request line is + * received (before any parsing of the header). + * This callback is the only way to get raw (unmodified) request URI as URI is + * parsed and modified by MHD in-place. + * Mandatory URI modification may apply before this call, like binary zero + * replacement, as required by RFCs. + * @param cb the early URI callback + * @param cls the closure for the callback + * @return the object of struct MHD_DaemonOptionAndValue with the requested + * values + */ +static MHD_INLINE struct MHD_DaemonOptionAndValue +MHD_D_OPTION_EARLY_URI_LOGGER ( + MHD_EarlyUriLogCallback cb, + void *cls) +{ + struct MHD_DaemonOptionAndValue opt_val; + + opt_val.opt = MHD_D_O_EARLY_URI_LOGGER; + opt_val.val.v_early_uri_logger.v_cb = cb; + opt_val.val.v_early_uri_logger.v_cls = cls; + + return opt_val; +} + + +/** + * Disable converting plus ('+') character to space in GET parameters (URI part + * after '?'). + * Plus conversion is not required by HTTP RFCs, however it required by HTML + * specifications, see + * https://url.spec.whatwg.org/#application/x-www-form-urlencoded for details. + * By default plus is converted to space in the query part of URI. + * @param bool_val the value of the parameter + * @return the object of struct MHD_DaemonOptionAndValue with the requested + * values + */ +static MHD_INLINE struct MHD_DaemonOptionAndValue +MHD_D_OPTION_DISABLE_URI_QUERY_PLUS_AS_SPACE (enum MHD_Bool bool_val) +{ + struct MHD_DaemonOptionAndValue opt_val; + + opt_val.opt = MHD_D_O_DISABLE_URI_QUERY_PLUS_AS_SPACE; + opt_val.val.v_disable_uri_query_plus_as_space = bool_val; + + return opt_val; +} + + +/** + * Suppresse use of "Date:" header. + * According to RFC should be suppressed only if the system has no RTC. + * The "Date:" is not suppressed (the header is enabled) by default. + * @param bool_val the value of the parameter + * @return the object of struct MHD_DaemonOptionAndValue with the requested + * values + */ +static MHD_INLINE struct MHD_DaemonOptionAndValue +MHD_D_OPTION_SUPPRESS_DATE_HEADER (enum MHD_Bool bool_val) +{ + struct MHD_DaemonOptionAndValue opt_val; + + opt_val.opt = MHD_D_O_SUPPRESS_DATE_HEADER; + opt_val.val.v_suppress_date_header = bool_val; + + return opt_val; +} + + +/** + * Use SHOUTcast for responses. + * This will cause *all* responses to begin with the SHOUTcast "ICY" line + * instead of "HTTP". + * @param bool_val the value of the parameter + * @return the object of struct MHD_DaemonOptionAndValue with the requested + * values + */ +static MHD_INLINE struct MHD_DaemonOptionAndValue +MHD_D_OPTION_ENABLE_SHOUTCAST (enum MHD_Bool bool_val) +{ + struct MHD_DaemonOptionAndValue opt_val; + + opt_val.opt = MHD_D_O_ENABLE_SHOUTCAST; + opt_val.val.v_enable_shoutcast = bool_val; + + return opt_val; +} + + +/** + * Maximum memory size per connection. + * Default is 32kb. + * Values above 128kb are unlikely to result in much performance benefit, as + * half of the memory will be typically used for IO, and TCP buffers are + * unlikely to support window sizes above 64k on most systems. + * The size should be large enough to fit all request headers (together with + * internal parsing information). + * @param sizet_val the value of the parameter + * @return the object of struct MHD_DaemonOptionAndValue with the requested + * values + */ +static MHD_INLINE struct MHD_DaemonOptionAndValue +MHD_D_OPTION_CONN_MEMORY_LIMIT (size_t sizet_val) +{ + struct MHD_DaemonOptionAndValue opt_val; + + opt_val.opt = MHD_D_O_CONN_MEMORY_LIMIT; + opt_val.val.v_conn_memory_limit = sizet_val; + + return opt_val; +} + + +/** + * The size of the shared memory pool for accamulated upload processing. + * The same "large" pool is shared for all connections server by MHD and used + * when application requests avoiding of incremental upload processing to + * accamulate complete content upload before giving it to the application. + * Default is 8Mb. + * Can be set to zero to disable share pool. + * @param sizet_val the value of the parameter + * @return the object of struct MHD_DaemonOptionAndValue with the requested + * values + */ +static MHD_INLINE struct MHD_DaemonOptionAndValue +MHD_D_OPTION_LARGE_POOL_SIZE (size_t sizet_val) +{ + struct MHD_DaemonOptionAndValue opt_val; + + opt_val.opt = MHD_D_O_LARGE_POOL_SIZE; + opt_val.val.v_large_pool_size = sizet_val; + + return opt_val; +} + + +/** + * Desired size of the stack for the threads started by MHD. + * Use 0 for system default, which is also MHD default. + * Works only with ##MHD_DAEMON_OPTION_WORKER_THREADS() or + * #MHD_DAEMON_OPTION_THREAD_PER_CONNECTION(). + * @param sizet_val the value of the parameter + * @return the object of struct MHD_DaemonOptionAndValue with the requested + * values + */ +static MHD_INLINE struct MHD_DaemonOptionAndValue +MHD_D_OPTION_STACK_SIZE (size_t sizet_val) +{ + struct MHD_DaemonOptionAndValue opt_val; + + opt_val.opt = MHD_D_O_STACK_SIZE; + opt_val.val.v_stack_size = sizet_val; + + return opt_val; +} + + +/** + * The the maximum FD value. + * The limit is applied to all sockets used by MHD. + * If listen socket FD is equal or higher that specified value, the daemon fail + * to start. + * If new connection FD is equal or higher that specified value, the connection + * is rejected. + * Useful if application uses select() for polling the sockets, system + * FD_SETSIZE is good value for this option in such case. + * Does not work with ##MHD_DAEMON_OPTION_WORKER_THREADS() or + * #MHD_DAEMON_OPTION_THREAD_PER_CONNECTION(). + * Does not work on W32 (WinSock sockets). + * @param max_fd the value of the parameter + * @return the object of struct MHD_DaemonOptionAndValue with the requested + * values + */ +static MHD_INLINE struct MHD_DaemonOptionAndValue +MHD_D_OPTION_FD_NUMBER_LIMIT (MHD_socket max_fd) +{ + struct MHD_DaemonOptionAndValue opt_val; + + opt_val.opt = MHD_D_O_FD_NUMBER_LIMIT; + opt_val.val.v_fd_number_limit = max_fd; + + return opt_val; +} + + +/** + * Enable `turbo`. + * Disables certain calls to `shutdown()`, enables aggressive non-blocking + * optimistic reads and other potentially unsafe optimisations. + * Most effects only happen with internal threads with epoll. + * The 'turbo' mode is not enabled (mode is disabled) by default. + * @param bool_val the value of the parameter + * @return the object of struct MHD_DaemonOptionAndValue with the requested + * values + */ +static MHD_INLINE struct MHD_DaemonOptionAndValue +MHD_D_OPTION_TURBO (enum MHD_Bool bool_val) +{ + struct MHD_DaemonOptionAndValue opt_val; + + opt_val.opt = MHD_D_O_TURBO; + opt_val.val.v_turbo = bool_val; + + return opt_val; +} + + +/** + * Disable some internal thread safety. + * Indicates that MHD daemon will be used by application in single-threaded + * mode only. When this flag is set then application must call any MHD + * function only within a single thread. + * This flag turns off some internal thread-safety and allows MHD making some + * of the internal optimisations suitable only for single-threaded environment. + * Not compatible with any internal threads modes. + * If MHD is compiled with custom configuration for embedded projects without + * threads support, this option is mandatory. + * Thread safety is not disabled (safety is enabled) by default. + * @param bool_val the value of the parameter + * @return the object of struct MHD_DaemonOptionAndValue with the requested + * values + */ +static MHD_INLINE struct MHD_DaemonOptionAndValue +MHD_D_OPTION_DISABLE_THREAD_SAFETY (enum MHD_Bool bool_val) +{ + struct MHD_DaemonOptionAndValue opt_val; + + opt_val.opt = MHD_D_O_DISABLE_THREAD_SAFETY; + opt_val.val.v_disable_thread_safety = bool_val; + + return opt_val; +} + + +/** + * You need to set this option if you want to disable use of HTTP "Upgrade". + * "Upgrade" may require usage of additional internal resources, which we can + * avoid providing if they will not be used. + * You should only use this option if you do not use "Upgrade" functionality + * and need a generally minor boost in performance and resources saving. + * The "Upgrade" is not disallowed ("upgrade" is allowed) by default. + * @param bool_val the value of the parameter + * @return the object of struct MHD_DaemonOptionAndValue with the requested + * values + */ +static MHD_INLINE struct MHD_DaemonOptionAndValue +MHD_D_OPTION_DISALLOW_UPGRADE (enum MHD_Bool bool_val) +{ + struct MHD_DaemonOptionAndValue opt_val; + + opt_val.opt = MHD_D_O_DISALLOW_UPGRADE; + opt_val.val.v_disallow_upgrade = bool_val; + + return opt_val; +} + + +/** + * Disable #MHD_action_suspend() functionality. + * + * You should only use this function if you do not use suspend functionality + * and need a generally minor boost in performance. + * The suspend is not disallowed (suspend is allowed) by default. + * @param bool_val the value of the parameter + * @return the object of struct MHD_DaemonOptionAndValue with the requested + * values + */ +static MHD_INLINE struct MHD_DaemonOptionAndValue +MHD_D_OPTION_DISALLOW_SUSPEND_RESUME (enum MHD_Bool bool_val) +{ + struct MHD_DaemonOptionAndValue opt_val; + + opt_val.opt = MHD_D_O_DISALLOW_SUSPEND_RESUME; + opt_val.val.v_disallow_suspend_resume = bool_val; + + return opt_val; +} + + +/** + * Set a callback to be called for pre-start finalisation. + * + * The specified callback will be called one time, after network + * initialisation, TLS pre-initialisation, but before the start of the internal + * threads (if allowed) + * @param cb the pre-start callback + * @param cb_cls the closure for the callback + * @return the object of struct MHD_DaemonOptionAndValue with the requested + * values + */ +static MHD_INLINE struct MHD_DaemonOptionAndValue +MHD_D_OPTION_DAEMON_READY_CALLBACK ( + MHD_DaemonReadyCallback cb, + void *cb_cls) +{ + struct MHD_DaemonOptionAndValue opt_val; + + opt_val.opt = MHD_D_O_DAEMON_READY_CALLBACK; + opt_val.val.v_daemon_ready_callback.v_cb = cb; + opt_val.val.v_daemon_ready_callback.v_cb_cls = cb_cls; + + return opt_val; +} + + +/** + * Set a function that should be called whenever a connection is started or + * closed. + * @param ncc the callback for notifications + * @param cls the closure for the callback + * @return the object of struct MHD_DaemonOptionAndValue with the requested + * values + */ +static MHD_INLINE struct MHD_DaemonOptionAndValue +MHD_D_OPTION_NOTIFY_CONNECTION ( + MHD_NotifyConnectionCallback ncc, + void *cls) +{ + struct MHD_DaemonOptionAndValue opt_val; + + opt_val.opt = MHD_D_O_NOTIFY_CONNECTION; + opt_val.val.v_notify_connection.v_ncc = ncc; + opt_val.val.v_notify_connection.v_cls = cls; + + return opt_val; +} + + +/** + * Register a function that should be called whenever a stream is started or + * closed. + * For HTTP/1.1 this callback is called one time for every connection. + * @param nsc the callback for notifications + * @param cls the closure for the callback + * @return the object of struct MHD_DaemonOptionAndValue with the requested + * values + */ +static MHD_INLINE struct MHD_DaemonOptionAndValue +MHD_D_OPTION_NOTIFY_STREAM ( + MHD_NotifyStreamCallback nsc, + void *cls) +{ + struct MHD_DaemonOptionAndValue opt_val; + + opt_val.opt = MHD_D_O_NOTIFY_STREAM; + opt_val.val.v_notify_stream.v_nsc = nsc; + opt_val.val.v_notify_stream.v_cls = cls; + + return opt_val; +} + + +/** + * Set strong random data to be used by MHD. + * Currently the data is only needed for Digest Auth module. + * The recommended size is between 8 and 32 bytes. Security can be lower for + * sizes less or equal four. + * Sizes larger then 32 (or, probably, larger than 16 - debatable) will not + * increase the security. + * @param buf_size the size of the buffer + * @param buf the buffer with strong random data, the content will be copied by + * MHD + * @return the object of struct MHD_DaemonOptionAndValue with the requested + * values + */ +static MHD_INLINE struct MHD_DaemonOptionAndValue +MHD_D_OPTION_RANDOM_ENTROPY ( + size_t buf_size, + const void *buf) +{ + struct MHD_DaemonOptionAndValue opt_val; + + opt_val.opt = MHD_D_O_RANDOM_ENTROPY; + opt_val.val.v_random_entropy.v_buf_size = buf_size; + opt_val.val.v_random_entropy.v_buf = buf; + + return opt_val; +} + + +/** + * Specify the size of the internal hash map array that tracks generated digest + * nonces usage. + * When the size of the map is too small then need to handle concurrent DAuth + * requests, a lot of "stale nonce" results will be produced. + * By default the size is 8 bytes (very small). + * @param size the size of the map array + * @return the object of struct MHD_DaemonOptionAndValue with the requested + * values + */ +static MHD_INLINE struct MHD_DaemonOptionAndValue +MHD_D_OPTION_DAUTH_MAP_SIZE (size_t size) +{ + struct MHD_DaemonOptionAndValue opt_val; + + opt_val.opt = MHD_D_O_DAUTH_MAP_SIZE; + opt_val.val.v_dauth_map_size = size; + + return opt_val; +} + + +/** + * Control the scope of validity of MHD-generated nonces. + * This regulates how "nonces" are generated and how "nonces" are checked by + * #MHD_digest_auth_check() and similar functions. + * This option allows bitwise OR combination of + * #MHD_DaemonOptionValueDAuthBindNonce values. + * When this option is not used then default value is + * #MHD_DAEMON_OPTION_VALUE_DAUTH_BIND_NONCE_NONE. + * @param bind_type the value of the parameter + * @return the object of struct MHD_DaemonOptionAndValue with the requested + * values + */ +static MHD_INLINE struct MHD_DaemonOptionAndValue +MHD_D_OPTION_DAUTH_NONCE_BIND_TYPE ( + enum MHD_DaemonOptionValueDAuthBindNonce bind_type) +{ + struct MHD_DaemonOptionAndValue opt_val; + + opt_val.opt = MHD_D_O_DAUTH_NONCE_BIND_TYPE; + opt_val.val.v_dauth_nonce_bind_type = bind_type; + + return opt_val; +} + + +/** + * Default nonce timeout value (in seconds) used for Digest Auth. + * Silently ignored if followed by zero value. + * @see #MHD_digest_auth_check(), MHD_digest_auth_check_digest() + * @param timeout the value of the parameter + * @return the object of struct MHD_DaemonOptionAndValue with the requested + * values + */ +static MHD_INLINE struct MHD_DaemonOptionAndValue +MHD_D_OPTION_DAUTH_DEF_NONCE_TIMEOUT (unsigned int timeout) +{ + struct MHD_DaemonOptionAndValue opt_val; + + opt_val.opt = MHD_D_O_DAUTH_DEF_NONCE_TIMEOUT; + opt_val.val.v_dauth_def_nonce_timeout = timeout; + + return opt_val; +} + + +/** + * Default maximum nc (nonce count) value used for Digest Auth. + * Silently ignored if followed by zero value. + * @see #MHD_digest_auth_check(), MHD_digest_auth_check_digest() + * @param max_nc the value of the parameter + * @return the object of struct MHD_DaemonOptionAndValue with the requested + * values + */ +static MHD_INLINE struct MHD_DaemonOptionAndValue +MHD_D_OPTION_DAUTH_DEF_MAX_NC (uint_fast32_t max_nc) +{ + struct MHD_DaemonOptionAndValue opt_val; + + opt_val.opt = MHD_D_O_DAUTH_DEF_MAX_NC; + opt_val.val.v_dauth_def_max_nc = max_nc; + + return opt_val; +} + + +/* = MHD Daemon Option static functions above are generated automatically = */ +/** + * Terminate the list of the options + * @return the terminating object of struct MHD_DaemonOptionAndValue + */ +static MHD_INLINE struct MHD_DaemonOptionAndValue +MHD_D_OPTION_TERMINATE (void) +{ + struct MHD_DaemonOptionAndValue opt_val; + + opt_val.opt = MHD_D_O_END; + + return opt_val; +} + + +MHD_RESTORE_WARN_UNUSED_FUNC_ +#endif /* !MHD_USE_COMPOUND_LITERALS || !MHD_USE_DESIG_NEST_INIT */ + + +/** + * Create parameter for #MHD_daemon_options_set() for work mode with + * no internal threads. + * The application periodically calls #MHD_daemon_process_blocking(), where + * MHD internally checks all sockets automatically. + * This is the default mode. + * @return the object of struct MHD_DaemonOptionAndValue with requested values + */ +#define MHD_D_OPTION_WM_EXTERNAL_PERIODIC() \ + MHD_D_OPTION_WORK_MODE(MHD_WM_OPTION_EXTERNAL_PERIODIC()) + +/** +* Create parameter for #MHD_daemon_options_set() for work mode with +* an external event loop with level triggers. +* Application uses #MHD_SocketRegistrationUpdateCallback, level triggered +* sockets polling (like select() or poll()) and #MHD_daemon_event_update(). +* @param cb_val the callback for sockets registration +* @param cb_cls_val the closure for the @a cv_val callback +* @return the object of struct MHD_DaemonOptionAndValue with requested values +*/ +#define MHD_D_OPTION_WM_EXTERNAL_EVENT_LOOP_CB_LEVEL(cb_val,cb_cls_val) \ + MHD_D_OPTION_WORK_MODE( \ + MHD_WM_OPTION_EXTERNAL_EVENT_LOOP_CB_LEVEL((cb_val),(cb_cls_val))) + +/** + * Create parameter for #MHD_daemon_options_set() for work mode with + * an external event loop with edge triggers. + * Application uses #MHD_SocketRegistrationUpdateCallback, edge triggered + * sockets polling (like epoll with EPOLLET) and #MHD_daemon_event_update(). + * @param cb_val the callback for sockets registration + * @param cb_cls_val the closure for the @a cv_val callback + * @return the object of struct MHD_DaemonOptionAndValue with requested values + */ +#define MHD_D_OPTION_WM_EXTERNAL_EVENT_LOOP_CB_EDGE(cb_val,cb_cls_val) \ + MHD_D_OPTION_WORK_MODE( \ + MHD_WM_OPTION_EXTERNAL_EVENT_LOOP_CB_EDGE((cb_val),(cb_cls_val))) + +/** + * Create parameter for #MHD_daemon_options_set() for work mode with + * no internal threads and aggregate watch FD. + * Application uses #MHD_DAEMON_INFO_FIXED_AGGREAGATE_FD to get single FD + * that gets triggered by any MHD event. + * This FD can be watched as an aggregate indicator for all MHD events. + * This mode is available only on selected platforms (currently + * GNU/Linux only), see #MHD_LIB_INFO_FIXED_HAS_AGGREGATE_FD. + * When the FD is triggered, #MHD_daemon_process_nonblocking() should + * be called. + * @return the object of struct MHD_DaemonOptionAndValue with requested values + */ +#define MHD_D_OPTION_WM_EXTERNAL_SINGLE_FD_WATCH() \ + MHD_D_OPTION_WORK_MODE(MHD_WM_OPTION_EXTERNAL_SINGLE_FD_WATCH()) + +/** + * Create parameter for #MHD_daemon_options_set() for work mode with + * one or more worker threads. + * If number of threads is one, then daemon starts with single worker thread + * that handles all connections. + * If number of threads is larger than one, then that number of worker threads, + * and handling of connection is distributed among the workers. + * @param num_workers the number of worker threads, zero is treated as one + * @return the object of struct MHD_DaemonOptionAndValue with requested values + */ +#define MHD_D_OPTION_WM_WORKER_THREADS(num_workers) \ + MHD_D_OPTION_WORK_MODE(MHD_WM_OPTION_WORKER_THREADS(num_workers)) + +/** + * Create parameter for #MHD_daemon_options_set() for work mode with + * one internal thread for listening and additional threads per every + * connection. Use this if handling requests is CPU-intensive or blocking, + * your application is thread-safe and you have plenty of memory (per + * connection). + * @return the object of struct MHD_DaemonOptionAndValue with requested values + */ +#define MHD_D_OPTION_WM_THREAD_PER_CONNECTION() \ + MHD_D_OPTION_WORK_MODE(MHD_WM_OPTION_THREAD_PER_CONNECTION()) + +/** + * Set the requested options for the daemon. + * + * If any option fail other options may be or may be not applied. + * @param daemon the daemon to set the options + * @param[in] options the pointer to the array with the options; + * the array processing stops at the first ::MHD_D_O_END + * option, but not later than after processing + * @a options_max_num entries + * @param options_max_num the maximum number of entries in the @a options, + * use #MHD_OPTIONS_ARRAY_MAX_SIZE if options processing + * must stop only at zero-termination option + * @return ::MHD_SC_OK on success, + * error code otherwise + */ +MHD_EXTERN_ enum MHD_StatusCode +MHD_daemon_options_set(struct MHD_Daemon *daemon, + const struct MHD_DaemonOptionAndValue *options, + size_t options_max_num) +MHD_FN_PAR_NONNULL_ALL_; + + +/** + * Set the requested single option for the daemon. + * + * @param daemon the daemon to set the option + * @param[in] options the pointer to the option + * @return ::MHD_SC_OK on success, + * error code otherwise + */ +#define MHD_daemon_option_set(daemon, option_ptr) \ + MHD_daemon_options_set(daemon, options_ptr, 1) + + +#ifdef MHD_USE_VARARG_MACROS +MHD_NOWARN_VARIADIC_MACROS_ +# if defined(MHD_USE_COMPOUND_LITERALS) && \ + defined(MHD_USE_COMP_LIT_FUNC_PARAMS) +/** + * Set the requested options for the daemon. + * + * If any option fail other options may be or may be not applied. + * + * It should be used with helpers that creates required options, for example: + * + * MHD_DAEMON_OPTIONS_SET(d, MHD_D_OPTION_SUPPRESS_DATE_HEADER(MHD_YES), + * MHD_D_OPTION_SOCK_ADDR(sa_len, sa)) + * + * @param daemon the daemon to set the options + * @param ... the list of the options, each option must be created + * by helpers MHD_D_OPTION_NameOfOption(option_value) + * @return ::MHD_SC_OK on success, + * error code otherwise + */ +# define MHD_DAEMON_OPTIONS_SET(daemon,...) \ + MHD_NOWARN_COMPOUND_LITERALS_ \ + MHD_daemon_options_set(daemon, \ + ((const struct MHD_DaemonOptionAndValue[]) \ + {__VA_ARGS__, MHD_D_OPTION_TERMINATE()}), \ + MHD_OPTIONS_ARRAY_MAX_SIZE) \ + MHD_RESTORE_WARN_COMPOUND_LITERALS_ +# elif defined(MHD_USE_CPP_INIT_LIST) +} /* extern "C" */ +# include <vector> +extern "C" +{ +/** + * Set the requested options for the daemon. + * + * If any option fail other options may be or may be not applied. + * + * It should be used with helpers that creates required options, for example: + * + * MHD_DAEMON_OPTIONS_SET(d, MHD_D_OPTION_SUPPRESS_DATE_HEADER(MHD_YES), + * MHD_D_OPTION_SOCK_ADDR(sa_len, sa)) + * + * @param daemon the daemon to set the options + * @param ... the list of the options, each option must be created + * by helpers MHD_D_OPTION_NameOfOption(option_value) + * @return ::MHD_SC_OK on success, + * error code otherwise + */ +# define MHD_DAEMON_OPTIONS_SET(daemon,...) \ + MHD_NOWARN_CPP_INIT_LIST_ \ + MHD_daemon_options_set(daemon, \ + (std::vector<struct MHD_DaemonOptionAndValue> \ + {__VA_ARGS__,MHD_D_OPTION_TERMINATE()}).data(), \ + MHD_OPTIONS_ARRAY_MAX_SIZE) \ + MHD_RESTORE_WARN_CPP_INIT_LIST_ +# endif +MHD_RESTORE_WARN_VARIADIC_MACROS_ +#endif /* MHD_USE_VARARG_MACROS && MHD_USE_COMP_LIT_FUNC_PARAMS */ + + +/* ******************* Event loop ************************ */ + + +/** + * Run websever operation with possible blocking. * - * This function calls MHD_get_timeout() internally and use returned value as - * maximum wait time if it less than value of @a millisec parameter. + * Supported only in #MHD_TM_EXTERNAL_PERIODIC and + * #MHD_TM_EXTERNAL_SINGLE_FD_WATCH modes. + * + * This function does the following: waits for any network event not more than + * specified number of milliseconds, processes all incoming and outgoing data, + * processes new connections, processes any timed-out connection, and does + * other things required to run webserver. + * Once all connections are processed, function returns. + * + * This function is useful for quick and simple (lazy) webserver implementation + * if application needs to run a single thread only and does not have any other + * network activity. * - * It is expected that the "external" socket polling function is not used in - * conjunction with this function unless the @a millisec is set to zero. + * In #MHD_TM_EXTERNAL_PERIODIC mode if @a millisec parameter is not zero + * this function calls #MHD_get_timeout()internally and use returned value + * as maximum wait time if it less than value of @a millisec parameter. * * @param daemon the daemon to run * @param millisec the maximum time in milliseconds to wait for network and @@ -3662,47 +6620,44 @@ MHD_FUNC_PARAM_NONNULL_ (1) MHD_FUNC_PARAM_NONNULL_ (2); * comes earlier) or longer (if data processing requires more * time, especially in user callbacks). * If set to '0' then function does not block and processes - * only already available data (if any). - * If set to '-1' then function waits for events - * indefinitely (blocks until next network activity or - * connection timeout). - * @return #MHD_YES on success, #MHD_NO if this - * daemon was not started with the right - * options for this call or some serious - * unrecoverable error occurs. - * @note Available since #MHD_VERSION 0x00097206 + * only already available data (if any). Zero value is + * recommended when used in #MHD_TM_EXTERNAL_SINGLE_FD_WATCH + * and the watched FD has been triggered. + * If set to #MHD_WAIT_INDEFINITELY then function waits + * for events indefinitely (blocks until next network activity + * or connection timeout). + * Always used as zero value in + * #MHD_TM_EXTERNAL_SINGLE_FD_WATCH mode. + * @return #MHD_SC_OK on success, otherwise + * an error code * @ingroup event */ -// @deprecated, new CB approach! -// FIXME: NOT deprecated, useful, renamed -// FIXME: to be used only in ::MHD_TM_EXTERNAL_PERIODIC mode -_MHD_EXTERN enum MHD_Result -MHD_process_data (struct MHD_Daemon *daemon, - int32_t millisec); - +MHD_EXTERN_ enum MHD_StatusCode +MHD_daemon_process_blocking (struct MHD_Daemon *daemon, + uint_fast64_t microsec) +MHD_FN_PAR_NONNULL_ (1); /** * Run webserver operations (without blocking unless in client - * callbacks). This method should be called by clients in combination - * with #MHD_get_fdset if the client-controlled select method is used - * and #MHD_get_timeout(). + * callbacks). + * + * Supported only in #MHD_TM_EXTERNAL_SINGLE_FD_WATCH mode. * - * FIXME: document use of this function for epoll(), too! + * This function does the following: processes all incoming and outgoing data, + * processes new connections, processes any timed-out connection, and does + * other things required to run webserver. + * Once all connections are processed, function returns. * - * This function is a convenience method, which is useful if the - * fd_sets from #MHD_get_fdset were not directly passed to `select()`; - * with this function, MHD will internally do the appropriate `select()` - * call itself again. While it is always safe to call #MHD_run (if - * #MHD_USE_INTERNAL_POLLING_THREAD is not set), you should call - * #MHD_run_from_select if performance is important (as it saves an - * expensive call to `select()`). + * The optional @a next_max_wait pointer returns the same value as + * if #MHD_daemon_get_timeout() would called immediately. * - * @param[in,out] daemon daemon to run - * @return #MHD_SC_OK on success + * @param daemon the daemon to run + * @return #MHD_SC_OK on success, otherwise + * an error code * @ingroup event */ -#define MHD_process_data_simple(d) \ - MHD_process_data (d, 0); +#define MHD_daemon_process_nonblocking(daemon) \ + MHD_daemon_process_blocking(daemon, 0) /** @@ -3723,86 +6678,299 @@ MHD_process_data (struct MHD_Daemon *daemon, * @param daemon daemon that manages the connection * @param client_socket socket to manage (MHD will expect * to receive an HTTP request from this socket next). - * @param addr IP address of the client + * @param[in] addr IP address of the client * @param addrlen number of bytes in @a addr - * @param connection_cls meta data the application wants to - * associate with the new connection object + * @param connection_cntx meta data the application wants to + * associate with the new connection object * @return #MHD_SC_OK on success - * FIXME: add detailed list of codes + * error on failure * @ingroup specialized */ -_MHD_EXTERN enum MHD_StatusCode +MHD_EXTERN_ enum MHD_StatusCode MHD_daemon_add_connection (struct MHD_Daemon *daemon, MHD_socket client_socket, + size_t addrlen, const struct sockaddr *addr, - socklen_t addrlen, - void *connection_cls) -MHD_FUNC_PARAM_NONNULL_ (1); + void *connection_cntx) +MHD_FN_PAR_NONNULL_ (1) +MHD_FN_PAR_IN_SIZE_ (4,3); /* ********************* connection options ************** */ +enum MHD_FIXED_ENUM_APP_SET_ MHD_ConnectionOption +{ + /** + * Not a real option. + * Should not be used directly. + * This value indicates the end of the list of the options. + */ + MHD_C_O_END = 0 + , + /** + * Set custom timeout for the given connection. + * Specified as the number of seconds. Use zero for no timeout. + * Setting this option resets connection timeout timer. + */ + MHD_C_O_TIMEOUT = 1 + , + + + /* * Sentinel * */ + /** + * The sentinel value. + * This value enforces specific underlying integer type for the enum. + * Do not use. + */ + MHD_C_O_SENTINEL = 65535 +}; + +struct MHD_ReservedStruct +{ + uint_fast64_t reserved1; + void *reserved2; +}; + + +/** + * Parameters for MHD connection options + */ +union MHD_ConnectionOptionValue +{ + /** + * Value for #MHD_C_O_TIMEOUT + */ + unsigned int v_timeout; + /** + * Reserved member. Do not use. + */ + struct MHD_ReservedStruct reserved; +}; + +/** + * Combination of MHD connection option with parameters values + */ +struct MHD_ConnectionOptionAndValue +{ + /** + * The connection configuration option + */ + enum MHD_ConnectionOption opt; + /** + * The value for the @a opt option + */ + union MHD_ConnectionOptionValue val; +}; + +#if defined(MHD_USE_COMPOUND_LITERALS) && defined(MHD_USE_DESIG_NEST_INIT) +/** + * Set custom timeout for the given connection. + * Specified as the number of seconds. Use zero for no timeout. + * Setting this option resets connection timeout timer. + * @param timeout the in seconds, zero for no timeout + * @return the object of struct MHD_ConnectionOptionAndValue with the requested + * values + */ +# define MHD_C_OPTION_TIMEOUT(timeout) \ + MHD_NOWARN_COMPOUND_LITERALS_ \ + (const struct MHD_ConnectionOptionAndValue) \ + { \ + .opt = (option), \ + .val.v_timeout = (timeout) \ + } \ + MHD_RESTORE_WARN_COMPOUND_LITERALS_ + +/** + * Terminate the list of the options + * @return the terminating object of struct MHD_ConnectionOptionAndValue + */ +# define MHD_C_OPTION_TERMINATE() \ + MHD_NOWARN_COMPOUND_LITERALS_ \ + (const struct MHD_ConnectionOptionAndValue) \ + { \ + .opt = (MHD_C_O_END) \ + } \ + MHD_RESTORE_WARN_COMPOUND_LITERALS_ + +#else /* !MHD_USE_COMPOUND_LITERALS || !MHD_USE_DESIG_NEST_INIT */ +MHD_NOWARN_UNUSED_FUNC_ /** * Set custom timeout for the given connection. * Specified as the number of seconds. Use zero for no timeout. - * Calling this function will reset its timeout timer. + * Setting this option resets connection timeout timer. + * @param timeout the in seconds, zero for no timeout + * @return the object of struct MHD_ConnectionOptionAndValue with the requested + * values + */ +static MHD_INLINE struct MHD_ConnectionOptionAndValue +MHD_C_OPTION_TIMEOUT (unsigned int timeout) +{ + struct MHD_ConnectionOptionAndValue opt_val; + + opt_val.opt = option; + opt_val.val.v_timeout = timeout; + + return opt_val; +} + + +/** + * Terminate the list of the options + * @return the terminating object of struct MHD_ConnectionOptionAndValue + */ +static MHD_INLINE struct MHD_ConnectionOptionAndValue +MHD_C_OPTION_TERMINATE (void) +{ + struct MHD_ConnectionOptionAndValue opt_val; + + opt_val.opt = MHD_C_O_END; + + return opt_val; +} + + +MHD_RESTORE_WARN_UNUSED_FUNC_ +#endif /* !MHD_USE_COMPOUND_LITERALS || !MHD_USE_DESIG_NEST_INIT */ + +/** + * Set the requested options for the connection. + * + * If any option fail other options may be or may be not applied. + * @param connection the connection to set the options + * @param[in] options the pointer to the array with the options; + * the array processing stops at the first ::MHD_D_O_END + * option, but not later than after processing + * @a options_max_num entries + * @param options_max_num the maximum number of entries in the @a options, + * use #MHD_OPTIONS_ARRAY_MAX_SIZE if options processing + * must stop only at zero-termination option + * @return ::MHD_SC_OK on success, + * error code otherwise + */ +MHD_EXTERN_ enum MHD_StatusCode +MHD_connection_options_set( + struct MHD_Connection *connection, + const struct MHD_ConnectionOptionAndValue *options, + size_t options_max_num) +MHD_FN_PAR_NONNULL_ALL_; + + +/** + * Set the requested single option for the connection. + * + * @param connection the connection to set the options + * @param[in] options the pointer to the option + * @return ::MHD_SC_OK on success, + * error code otherwise + */ +#define MHD_connection_option_set(connection, option_ptr) \ + MHD_connection_options_set(connection, options_ptr, 1) + + +#ifdef MHD_USE_VARARG_MACROS +MHD_NOWARN_VARIADIC_MACROS_ +# if defined(MHD_USE_COMPOUND_LITERALS) && defined(MHD_USE_COMP_LIT_FUNC_PARAMS \ + ) +/** + * Set the requested options for the connection. + * + * If any option fail other options may be or may be not applied. * - * @param[in,out] connection connection to configure timeout for - * @param timeout_s new timeout in seconds + * It should be used with helpers that creates required options, for example: + * + * MHD_CONNECTION_OPTIONS_SET(d, MHD_C_OPTION_TIMEOUT(30)) + * + * @param connection the connection to set the options + * @param ... the list of the options, each option must be created + * by helpers MHD_C_OPTION_NameOfOption(option_value) + * @return ::MHD_SC_OK on success, + * error code otherwise + */ +# define MHD_CONNECTION_OPTIONS_SET(connection,...) \ + MHD_NOWARN_COMPOUND_LITERALS_ \ + MHD_connection_options_set(daemon, \ + ((const struct MHD_ConnectionOptionAndValue[]) \ + {__VA_ARGS__, MHD_C_OPTION_TERMINATE()}), \ + MHD_OPTIONS_ARRAY_MAX_SIZE) \ + MHD_RESTORE_WARN_COMPOUND_LITERALS_ +# elif defined(MHD_USE_CPP_INIT_LIST) +} /* extern "C" */ +# include <vector> +extern "C" +{ +/** + * Set the requested options for the connection. + * + * If any option fail other options may be or may be not applied. + * + * It should be used with helpers that creates required options, for example: + * + * MHD_CONNECTION_OPTIONS_SET(d, MHD_C_OPTION_TIMEOUT(30)) + * + * @param connection the connection to set the options + * @param ... the list of the options, each option must be created + * by helpers MHD_C_OPTION_NameOfOption(option_value) + * @return ::MHD_SC_OK on success, + * error code otherwise */ -_MHD_EXTERN enum MHD_StatusCode -MHD_connection_set_timeout (struct MHD_Connection *connection, - unsigned int timeout_s) -MHD_FUNC_PARAM_NONNULL_ (1); +# define MHD_CONNECTION_OPTIONS_SET(daemon,...) \ + MHD_NOWARN_CPP_INIT_LIST_ \ + MHD_daemon_options_set(daemon, \ + (std::vector<struct MHD_ConnectionOptionAndValue> \ + {__VA_ARGS__,MHD_C_OPTION_TERMINATE()}).data(), \ + MHD_OPTIONS_ARRAY_MAX_SIZE) \ + MHD_RESTORE_WARN_CPP_INIT_LIST_ +# endif +MHD_RESTORE_WARN_VARIADIC_MACROS_ +#endif /* MHD_USE_VARARG_MACROS && MHD_USE_COMP_LIT_FUNC_PARAMS */ /* **************** Request handling functions ***************** */ -// FIXME: Updated /** * The `enum MHD_ValueKind` specifies the source of - * the key-value pairs in the HTTP protocol. + * the name-value pairs in the HTTP protocol. */ -enum MHD_ValueKind +enum MHD_FLAGS_ENUM_ MHD_ValueKind { /** * HTTP header. */ - MHD_VK_HEADER = 1, - + MHD_VK_HEADER = 1 + , /** * Cookies. Note that the original HTTP header containing * the cookie(s) will still be available and intact. */ - MHD_VK_COOKIE = 2, - - // FIXME: swapped values + MHD_VK_COOKIE = 2 + , /** * GET (URI) arguments. */ - MHD_VK_GET_ARGUMENT = 4, - + MHD_VK_GET_ARGUMENT = 4 + , /** * POST data. - * FIXME: Correct description * This is available only if a content encoding * supported by MHD is used, and only if the posted content * fits within the available memory pool. - * Note that in that case, the upload data given to - * the #MHD_AccessHandlerCallback will be empty (since it has - * already been processed). + * + * @warning The encoding "multipart/form-data" has more fields than just + * "name" and "value". See #MHD_request_get_post_processor_values_cb() and + * #MHD_request_get_post_processor_values_list(). In particular it could be + * important to check used "Transfer-Encoding". While it is deprecated and + * not used by modern clients, hypothetically it can be used. */ - MHD_VK_POSTDATA = 8, - + MHD_VK_POSTDATA = 8 + , /** * HTTP footer (only for HTTP 1.1 chunked encodings). */ - MHD_VK_FOOTER = 16, - - // FIXME: combined values + MHD_VK_FOOTER = 16 + , /** * Header and footer values */ @@ -3812,39 +6980,65 @@ enum MHD_ValueKind * Values from get arguments or post data */ MHD_VK_GET_POST = MHD_VK_POSTDATA | MHD_VK_GET_ARGUMENT - // FIXME: Add chunk extension? Another API for extension? }; -// FIXME: use struct MHD_KeyValue? /** - * Iterator over key-value pairs. This iterator can be used to + * Name with value pair + */ +struct MHD_NameAndValue +{ + /** + * The name (key) of the field. + * The pointer to the C string must never be NULL. + * Some types (kinds) allow empty strings. + */ + struct MHD_String name; + /** + * The value of the field. + * Some types (kinds) allow absence of the value. The absence is indicated + * by NULL pointer to the C string. + */ + struct MHD_StringNullable value; +}; + +/** + * Name, value and kind (type) of data + */ +struct MHD_NameValueKind +{ + /** + * The name and the value of the field + */ + struct MHD_NameAndValue nv; + /** + * The kind (type) of the field + */ + enum MHD_ValueKind kind; +}; + +/** + * Iterator over name-value pairs. This iterator can be used to * iterate over all of the cookies, headers, or POST-data fields of a * request, and also to iterate over the headers that have been added * to a response. * - * The pointers to the strings in @a key and @a value are valid - * until the response is queued. If the data is needed beyond this - * point, it should be copied. + * The pointers to the strings in @a nvt are valid until the response + * is queued. If the data is needed beyond this point, it should be copied. * * @param cls closure - * @param kind kind of the header we are looking at - * @param key key for the value, can be an empty string - * @param value corresponding value, can be NULL (no value set) or - * empty (the value is empty) + * @param nvt the name, the value and the kind of the element * @return #MHD_YES to continue iterating, * #MHD_NO to abort the iteration * @ingroup request */ typedef enum MHD_Bool -(MHD_FUNC_PARAM_NONNULL_ (3) - *MHD_KeyValueIterator)(void *cls, - enum MHD_ValueKind kind, - const struct MHD_String *key, - const struct MHD_String *value); +(MHD_FN_PAR_NONNULL_ (2) + *MHD_NameValueIterator)(void *cls, + const struct MHD_NameValueKind *nvt); /** - * Get all of the headers from the request via callback. + * Get all of the headers (or other kind of request data) via callback. * * @param[in,out] request request to get values from * @param kind types of values to iterate over, can be a bitmask @@ -3854,26 +7048,13 @@ typedef enum MHD_Bool * @return number of entries iterated over * @ingroup request */ -_MHD_EXTERN unsigned int +MHD_EXTERN_ size_t MHD_request_get_values_cb (struct MHD_Request *request, enum MHD_ValueKind kind, - MHD_KeyValueIterator iterator, + MHD_NameValueIterator iterator, void *iterator_cls) -MHD_FUNC_PARAM_NONNULL_ (1); - +MHD_FN_PAR_NONNULL_ (1); -// FIXME: added - to discuss - -/** - * The Key-Value pair - */ -struct MHD_KeyValue -{ - // FIXME: adding here, so remove elsewhere... - enum MHD_ValueKind kind; - struct MHD_String key; - struct MHD_String value; -}; /** * Get all of the headers (or other kind of request data) from the request. @@ -3888,17 +7069,18 @@ struct MHD_KeyValue * the key-value pairs; if @a request has more elements * than @a num_elements than any @a num_elements are * stored - * @return the number of elements stored in @a key (and in @a values), the + * @return the number of elements stored in @a elements, the * number cannot be larger then @a num_elements, * zero if there is no such values or any error occurs */ -_MHD_EXTERN unsigned int +MHD_EXTERN_ size_t MHD_request_get_values_list ( struct MHD_Request *request, enum MHD_ValueKind kind, - unsigned int num_elements, - struct MHD_KeyValue elements[MHD_C99_ (static num_elements)]) -MHD_FUNC_PARAM_NONNULL_ (1) MHD_FUNC_PARAM_NONNULL_ (4); + size_t num_elements, + struct MHD_NameValueKind elements[MHD_FN_PAR_DYN_ARR_SIZE_ (num_elements)]) +MHD_FN_PAR_NONNULL_ (1) +MHD_FN_PAR_NONNULL_ (4) MHD_FN_PAR_OUT_ (4); /** @@ -3914,199 +7096,273 @@ MHD_FUNC_PARAM_NONNULL_ (1) MHD_FUNC_PARAM_NONNULL_ (4); * @return NULL if no such item was found * @ingroup request */ -_MHD_EXTERN const char * +MHD_EXTERN_ const struct MHD_String * MHD_request_get_value (struct MHD_Request *request, enum MHD_ValueKind kind, const char *key) -MHD_FUNC_PARAM_NONNULL_ (1); +MHD_FN_PAR_NONNULL_ (1) +MHD_FN_PAR_NONNULL_ (3) MHD_FN_PAR_CSTR_(3); -// FIXME: Remove duplicate?? -/** - * Get a particular header (or other kind of request data) value. - * If multiple values match the kind, return any one of them. - * - * The pointer to the string in @a value 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[in] key the header to look for, zero-length to - * lookup 'trailing' value without a key - * @param[out] value the found value, the str pointer set to - * NULL if nothing is found - * @return #MHD_SC_OK if found, - * // FIXME: add error codes - * @ingroup request +/** + * @defgroup httpcode HTTP response codes. + * These are the status codes defined for HTTP responses. + * @{ */ -_MHD_EXTERN enum MHD_StatusCode -MHD_request_get_value_string (struct MHD_Request *request, - enum MHD_ValueKind kind, - struct MHD_String *key, - struct MHD_String *value) -MHD_FUNC_PARAM_NONNULL_ (1) MHD_FUNC_PARAM_NONNULL_ (3) -MHD_FUNC_PARAM_NONNULL_ (4); +/* See http://www.iana.org/assignments/http-status-codes/http-status-codes.xhtml */ +enum MHD_FIXED_ENUM_APP_SET_ MHD_HTTP_StatusCode +{ + + MHD_HTTP_STATUS_CONTINUE = 100 + , + MHD_HTTP_STATUS_SWITCHING_PROTOCOLS = 101 + , + MHD_HTTP_STATUS_PROCESSING = 102 + , + MHD_HTTP_STATUS_OK = 200 + , + MHD_HTTP_STATUS_CREATED = 201 + , + MHD_HTTP_STATUS_ACCEPTED = 202 + , + MHD_HTTP_STATUS_NON_AUTHORITATIVE_INFORMATION = 203 + , + MHD_HTTP_STATUS_NO_CONTENT = 204 + , + MHD_HTTP_STATUS_RESET_CONTENT = 205 + , + MHD_HTTP_STATUS_PARTIAL_CONTENT = 206 + , + MHD_HTTP_STATUS_MULTI_STATUS = 207 + , + MHD_HTTP_STATUS_ALREADY_REPORTED = 208 + , + MHD_HTTP_STATUS_IM_USED = 226 + , + MHD_HTTP_STATUS_MULTIPLE_CHOICES = 300 + , + MHD_HTTP_STATUS_MOVED_PERMANENTLY = 301 + , + MHD_HTTP_STATUS_FOUND = 302 + , + MHD_HTTP_STATUS_SEE_OTHER = 303 + , + MHD_HTTP_STATUS_NOT_MODIFIED = 304 + , + MHD_HTTP_STATUS_USE_PROXY = 305 + , + MHD_HTTP_STATUS_SWITCH_PROXY = 306 /* IANA: unused */ + , + MHD_HTTP_STATUS_TEMPORARY_REDIRECT = 307 + , + MHD_HTTP_STATUS_PERMANENT_REDIRECT = 308 + , + MHD_HTTP_STATUS_BAD_REQUEST = 400 + , + MHD_HTTP_STATUS_UNAUTHORIZED = 401 + , + MHD_HTTP_STATUS_PAYMENT_REQUIRED = 402 + , + MHD_HTTP_STATUS_FORBIDDEN = 403 + , + MHD_HTTP_STATUS_NOT_FOUND = 404 + , + MHD_HTTP_STATUS_METHOD_NOT_ALLOWED = 405 + , + MHD_HTTP_STATUS_NOT_ACCEPTABLE = 406 + , + MHD_HTTP_STATUS_PROXY_AUTHENTICATION_REQUIRED = 407 + , + MHD_HTTP_STATUS_REQUEST_TIMEOUT = 408 + , + MHD_HTTP_STATUS_CONFLICT = 409 + , + MHD_HTTP_STATUS_GONE = 410 + , + MHD_HTTP_STATUS_LENGTH_REQUIRED = 411 + , + MHD_HTTP_STATUS_PRECONDITION_FAILED = 412 + , + MHD_HTTP_STATUS_PAYLOAD_TOO_LARGE = 413 + , + MHD_HTTP_STATUS_URI_TOO_LONG = 414 + , + MHD_HTTP_STATUS_UNSUPPORTED_MEDIA_TYPE = 415 + , + MHD_HTTP_STATUS_RANGE_NOT_SATISFIABLE = 416 + , + MHD_HTTP_STATUS_EXPECTATION_FAILED = 417 + , + MHD_HTTP_STATUS_MISDIRECTED_REQUEST = 421 + , + MHD_HTTP_STATUS_UNPROCESSABLE_ENTITY = 422 + , + MHD_HTTP_STATUS_LOCKED = 423 + , + MHD_HTTP_STATUS_FAILED_DEPENDENCY = 424 + , + MHD_HTTP_STATUS_UNORDERED_COLLECTION = 425 /* IANA: unused */ + , + MHD_HTTP_STATUS_UPGRADE_REQUIRED = 426 + , + MHD_HTTP_STATUS_PRECONDITION_REQUIRED = 428 + , + MHD_HTTP_STATUS_TOO_MANY_REQUESTS = 429 + , + MHD_HTTP_STATUS_REQUEST_HEADER_FIELDS_TOO_LARGE = 431 + , + MHD_HTTP_STATUS_NO_RESPONSE = 444 /* IANA: unused */ + , + MHD_HTTP_STATUS_RETRY_WITH = 449 /* IANA: unused */ + , + MHD_HTTP_STATUS_BLOCKED_BY_WINDOWS_PARENTAL_CONTROLS = 450 /* IANA: unused */ + , + MHD_HTTP_STATUS_UNAVAILABLE_FOR_LEGAL_REASONS = 451 + , + MHD_HTTP_STATUS_INTERNAL_SERVER_ERROR = 500 + , + MHD_HTTP_STATUS_NOT_IMPLEMENTED = 501 + , + MHD_HTTP_STATUS_BAD_GATEWAY = 502 + , + MHD_HTTP_STATUS_SERVICE_UNAVAILABLE = 503 + , + MHD_HTTP_STATUS_GATEWAY_TIMEOUT = 504 + , + MHD_HTTP_STATUS_HTTP_VERSION_NOT_SUPPORTED = 505 + , + MHD_HTTP_STATUS_VARIANT_ALSO_NEGOTIATES = 506 + , + MHD_HTTP_STATUS_INSUFFICIENT_STORAGE = 507 + , + MHD_HTTP_STATUS_LOOP_DETECTED = 508 + , + MHD_HTTP_STATUS_BANDWIDTH_LIMIT_EXCEEDED = 509 /* IANA: unused */ + , + MHD_HTTP_STATUS_NOT_EXTENDED = 510 + , + MHD_HTTP_STATUS_NETWORK_AUTHENTICATION_REQUIRED = 511 +}; -// FIXME: gana? table for RFC 7541... -// TODO: extract https://www.rfc-editor.org/rfc/rfc7541.html#appendix-A -enum MHD_PredefinedHeader; -// FIXME: Updated /** - * Get last occurence of a particular header value under - * the given @a skt. - * - * The pointer to the string in @a value is valid until the response - * is queued. If the data is needed beyond this point, it should be copied. + * Returns the string status for a response code. * - * @param[in,out] request request to get values from - * @param kind what kind of value are we looking for - * @param skt the header to look for based on RFC 7541 Appendix A. - * @param[out] value the found value, the str pointer set to - * NULL if nothing is found - * @return #MHD_SC_OK if found, - * // FIXME: add error codes - * @ingroup request + * This function works for @b HTTP status code, not for @b MHD error codes/ + * @param code the HTTP code to get text representation for + * @return the pointer to the text representation, + * NULL if HTTP status code in not known. */ -_MHD_EXTERN enum MHD_StatusCode -MHD_request_lookup_value_by_static_header (struct MHD_Request *request, - enum MHD_ValueKind kind, - enum MHD_PredefinedHeader skt, - struct MHD_String *value) -MHD_FUNC_PARAM_NONNULL_ (1) MHD_FUNC_PARAM_NONNULL_ (4); +MHD_EXTERN_ const struct MHD_String * +MHD_HTTP_status_code_to_string (enum MHD_HTTP_StatusCode code) +MHD_FN_PURE_; + +/** @} */ /* end of group httpcode */ /** - * @defgroup httpcode HTTP response codes. - * These are the status codes defined for HTTP responses. + * @defgroup versions HTTP versions + * These strings should be used to match against the first line of the + * HTTP header. * @{ */ -/* See http://www.iana.org/assignments/http-status-codes/http-status-codes.xhtml */ -// Use GANA! -// FIXME: Discuss GANA. Not clear how to use automatic substitution for missing entries -enum MHD_HTTP_StatusCode -{ - - MHD_HTTP_STATUS_CONTINUE = 100, - MHD_HTTP_STATUS_SWITCHING_PROTOCOLS = 101, - MHD_HTTP_STATUS_PROCESSING = 102, - - MHD_HTTP_STATUS_OK = 200, - MHD_HTTP_STATUS_CREATED = 201, - MHD_HTTP_STATUS_ACCEPTED = 202, - MHD_HTTP_STATUS_NON_AUTHORITATIVE_INFORMATION = 203, - MHD_HTTP_STATUS_NO_CONTENT = 204, - MHD_HTTP_STATUS_RESET_CONTENT = 205, - MHD_HTTP_STATUS_PARTIAL_CONTENT = 206, - MHD_HTTP_STATUS_MULTI_STATUS = 207, - MHD_HTTP_STATUS_ALREADY_REPORTED = 208, - - MHD_HTTP_STATUS_IM_USED = 226, - - MHD_HTTP_STATUS_MULTIPLE_CHOICES = 300, - MHD_HTTP_STATUS_MOVED_PERMANENTLY = 301, - MHD_HTTP_STATUS_FOUND = 302, - MHD_HTTP_STATUS_SEE_OTHER = 303, - MHD_HTTP_STATUS_NOT_MODIFIED = 304, - MHD_HTTP_STATUS_USE_PROXY = 305, - MHD_HTTP_STATUS_SWITCH_PROXY = 306, /* IANA: unused */ - MHD_HTTP_STATUS_TEMPORARY_REDIRECT = 307, - MHD_HTTP_STATUS_PERMANENT_REDIRECT = 308, - - MHD_HTTP_STATUS_BAD_REQUEST = 400, - MHD_HTTP_STATUS_UNAUTHORIZED = 401, - MHD_HTTP_STATUS_PAYMENT_REQUIRED = 402, - MHD_HTTP_STATUS_FORBIDDEN = 403, - MHD_HTTP_STATUS_NOT_FOUND = 404, - MHD_HTTP_STATUS_METHOD_NOT_ALLOWED = 405, - MHD_HTTP_STATUS_NOT_ACCEPTABLE = 406, - MHD_HTTP_STATUS_PROXY_AUTHENTICATION_REQUIRED = 407, - MHD_HTTP_STATUS_REQUEST_TIMEOUT = 408, - MHD_HTTP_STATUS_CONFLICT = 409, - MHD_HTTP_STATUS_GONE = 410, - MHD_HTTP_STATUS_LENGTH_REQUIRED = 411, - MHD_HTTP_STATUS_PRECONDITION_FAILED = 412, - MHD_HTTP_STATUS_PAYLOAD_TOO_LARGE = 413, - MHD_HTTP_STATUS_URI_TOO_LONG = 414, - MHD_HTTP_STATUS_UNSUPPORTED_MEDIA_TYPE = 415, - MHD_HTTP_STATUS_RANGE_NOT_SATISFIABLE = 416, - MHD_HTTP_STATUS_EXPECTATION_FAILED = 417, - - MHD_HTTP_STATUS_MISDIRECTED_REQUEST = 421, - MHD_HTTP_STATUS_UNPROCESSABLE_ENTITY = 422, - MHD_HTTP_STATUS_LOCKED = 423, - MHD_HTTP_STATUS_FAILED_DEPENDENCY = 424, - MHD_HTTP_STATUS_UNORDERED_COLLECTION = 425, /* IANA: unused */ - MHD_HTTP_STATUS_UPGRADE_REQUIRED = 426, - - MHD_HTTP_STATUS_PRECONDITION_REQUIRED = 428, - MHD_HTTP_STATUS_TOO_MANY_REQUESTS = 429, - MHD_HTTP_STATUS_REQUEST_HEADER_FIELDS_TOO_LARGE = 431, - - MHD_HTTP_STATUS_NO_RESPONSE = 444, /* IANA: unused */ - - MHD_HTTP_STATUS_RETRY_WITH = 449, /* IANA: unused */ - MHD_HTTP_STATUS_BLOCKED_BY_WINDOWS_PARENTAL_CONTROLS = 450, /* IANA: unused */ - MHD_HTTP_STATUS_UNAVAILABLE_FOR_LEGAL_REASONS = 451, - - MHD_HTTP_STATUS_INTERNAL_SERVER_ERROR = 500, - MHD_HTTP_STATUS_NOT_IMPLEMENTED = 501, - MHD_HTTP_STATUS_BAD_GATEWAY = 502, - MHD_HTTP_STATUS_SERVICE_UNAVAILABLE = 503, - MHD_HTTP_STATUS_GATEWAY_TIMEOUT = 504, - MHD_HTTP_STATUS_HTTP_VERSION_NOT_SUPPORTED = 505, - MHD_HTTP_STATUS_VARIANT_ALSO_NEGOTIATES = 506, - MHD_HTTP_STATUS_INSUFFICIENT_STORAGE = 507, - MHD_HTTP_STATUS_LOOP_DETECTED = 508, - MHD_HTTP_STATUS_BANDWIDTH_LIMIT_EXCEEDED = 509, /* IANA: unused */ - MHD_HTTP_STATUS_NOT_EXTENDED = 510, - MHD_HTTP_STATUS_NETWORK_AUTHENTICATION_REQUIRED = 511 +enum MHD_FIXED_ENUM_MHD_SET_ MHD_HTTP_ProtocolVersion +{ + MHD_HTTP_VERSION_INVALID = 0 + , + MHD_HTTP_VERSION_1_0 = 1 + , + MHD_HTTP_VERSION_1_1 = 2 + , + MHD_HTTP_VERSION_2_0 = 3 + , + MHD_HTTP_VERSION_3_0 = 4 + , + MHD_HTTP_VERSION_FUTURE = 99 +}; + +/** + * Return the string representation of the requested HTTP version. + * Note: this is suitable mainly for logging and similar proposes as + * HTTP/2 (and later) is not used inside the HTTP protocol. + * @param pv the protocol version + * @return the string representation of the protocol version, + * NULL for invalid values + */ +MHD_EXTERN_ const struct MHD_String * +MHD_protocol_version_to_string (enum MHD_HTTP_ProtocolVersion pv) +MHD_FN_PURE_; + +/** + * HTTP/1.0 identification string + */ +#define MHD_HTTP_VERSION_1_0 "HTTP/1.0" +/** + * HTTP/1.1 identification string + */ +#define MHD_HTTP_VERSION_1_1 "HTTP/1.1" +/** + * HTTP/2 identification string. + * Not used by the HTTP protocol (except non-TLS handshake), useful for logs and + * similar proposes. + */ +#define MHD_HTTP_VERSION_2 "HTTP/2" +/** + * HTTP/3 identification string. + * Not used by the HTTP protocol, useful for logs and similar proposes. + */ +#define MHD_HTTP_VERSION_3 "HTTP/3" -}; +/** @} */ /* end of group versions */ /** - * Returns the string status for a response code. + * Resume handling of network data for suspended request. It is + * safe to resume a suspended request at any time. Calling this + * function on a request that was not previously suspended will + * result in undefined behaviour. + * + * If you are using this function in ``external'' select mode, you must + * make sure to run #MHD_run() afterwards (before again calling + * #MHD_get_fdset(), as otherwise the change may not be reflected in + * the set returned by #MHD_get_fdset() and you may end up with a + * request that is stuck until the next network activity. * - * If we don't have a string for a status code, we give the first - * message in that status code class. + * @param[in,out] request the request to resume */ -_MHD_EXTERN const char * -MHD_status_code_to_string (enum MHD_HTTP_StatusCode code); +MHD_EXTERN_ void +MHD_request_resume (struct MHD_Request *request) +MHD_FN_PAR_NONNULL_ALL_; -/** @} */ /* end of group httpcode */ +/* ************** Action and Response manipulation functions **************** */ /** - * @defgroup versions HTTP versions - * These strings should be used to match against the first line of the - * HTTP header. - * @{ + * Name with value pair as C strings */ -// Again: GANA? -// FIXME: Discuss GANA. Just a few entries so far. -enum MHD_HTTP_ProtocolVersion +struct MHD_NameValueCStr { - MHD_HTTP_VERSION_INVALID = 0, - MHD_HTTP_VERSION_1_0 = 1, - MHD_HTTP_VERSION_1_1 = 2, - MHD_HTTP_VERSION_2_0 = 3, - MHD_HTTP_VERSION_3_0 = 4, - MHD_HTTP_VERSION_FUTURE = 99 + /** + * The name (key) of the field. + * Must never be NULL. + * Some types (kinds) allow empty strings. + */ + const char *name; + /** + * The value of the field. + * Some types (kinds) allow absence of the value. The absence is indicated + * by NULL pointer. + */ + const char *value; }; -// FIXME: remove completely, usable only for HTTP/1.x, no practical use with the new API -_MHD_EXTERN const char * -MHD_protocol_version_to_string (enum MHD_HTTP_ProtocolVersion pv); - -// FIXME: remove completely, usable only for HTTP/1.x, no practical use with the new API -// Reminder: -// #define MHD_HTTP_VERSION_1_0 "HTTP/1.0" -// #define MHD_HTTP_VERSION_1_1 "HTTP/1.1" -// #define MHD_HTTP_VERSION_2 "HTTP/2" // FIXME: Used only for non-TLS handshake -// #define MHD_HTTP_VERSION_3 "HTTP/3" // FIXME: not defined anywhere - -/** @} */ /* end of group versions */ +/** + * Data transmitted in response to an HTTP request. + * Usually the final action taken in response to + * receiving a request. + */ +struct MHD_Response; /** @@ -4127,47 +7383,14 @@ MHD_protocol_version_to_string (enum MHD_HTTP_ProtocolVersion pv); * the precise resume moment is not guaranteed, it * may happen later (but not earlier) depending * on timer granularity and the system load; - * if set to UINT64_MAX (or higher) the request - * is not resumed automatically, - * the suspension period can be shorter then requested - * if the number is higher than 86 400 000 000 (one day) // FIXME: discuss + * if set to #MHD_WAIT_INDEFINITELY (or higher) + * the request is not resumed automatically * @return action to cause a request to be suspended. */ -_MHD_EXTERN const struct MHD_Action * -MHD_action_suspend (struct MHD_Request *request, // FIXME: need check whether used Action matches Request +MHD_EXTERN_ const struct MHD_Action * +MHD_action_suspend (struct MHD_Request *request, uint_fast64_t suspend_microsec) -MHD_FUNC_RETURNS_NONNULL_ MHD_FUNC_PARAM_NONNULL_ALL_; - - -/** - * Resume handling of network data for suspended request. It is - * safe to resume a suspended request at any time. Calling this - * function on a request that was not previously suspended will - * result in undefined behavior. - * - * If you are using this function in ``external'' select mode, you must - * make sure to run #MHD_run() afterwards (before again calling - * #MHD_get_fdset(), as otherwise the change may not be reflected in - * the set returned by #MHD_get_fdset() and you may end up with a - * request that is stuck until the next network activity. - * - * @param[in,out] request the request to resume - */ -_MHD_EXTERN void -MHD_request_resume (struct MHD_Request *request) -MHD_FUNC_PARAM_NONNULL_ALL_; - - -/* **************** Response manipulation functions ***************** */ - - -/** - * Data transmitted in response to an HTTP request. - * Usually the final action taken in response to - * receiving a request. - */ -struct MHD_Response; - +MHD_FN_RETURNS_NONNULL_ MHD_FN_PAR_NONNULL_ALL_; /** * Converts a @a response to an action. If @a MHD_RESP_OPT_BOOL_REUSABLE @@ -4187,271 +7410,793 @@ struct MHD_Response; * the response object is consumed and need not * to be "destroyed". */ -_MHD_EXTERN const struct MHD_Action * -MHD_action_from_response (struct MHD_Response *response); +MHD_EXTERN_ const struct MHD_Action * +MHD_action_from_response (struct MHD_Request *request, + struct MHD_Response *response); + + +/** + * The `enum MHD_RequestTerminationCode` specifies reasons + * why a request has been terminated (or completed). + * @ingroup request + */ +enum MHD_FIXED_ENUM_MHD_SET_ MHD_RequestTerminationCode +{ + + /** + * The response was successfully sent. + * @ingroup request + */ + MHD_REQUEST_TERMINATED_COMPLETED_OK = 0 + , + /** + * The application terminated request without response. + * @ingroup request + */ + MHD_REQUEST_TERMINATED_BY_APP = 1 + , + /** + * The request is not valid according to + * HTTP specifications. + * @ingroup request + */ + MHD_REQUEST_TERMINATED_HTTP_PROTOCOL_ERROR = 2 + , + /** + * The client terminated the connection by closing the socket + * for writing (TCP half-closed) before sending complete request; + * MHD aborted sending the response according to RFC 2616, section 8.1.4. + * @ingroup request + */ + MHD_REQUEST_TERMINATED_CLIENT_ABORT = 3 + , + /** + * Error handling the connection due to resources exhausted. + * @ingroup request + */ + MHD_REQUEST_TERMINATED_NO_RESOURCES = 4 + , + /** + * We had to close the session since MHD was being shut down. + * @ingroup request + */ + MHD_REQUEST_TERMINATED_DAEMON_SHUTDOWN = 5 + , + /** + * No activity on the connection for the number of seconds specified using + * #MHD_C_OPTION_TIMEOUT(). + * @ingroup request + */ + MHD_REQUEST_TERMINATED_TIMEOUT_REACHED = 6 + , + /** + * The connection was broken or TLS protocol error. + * @ingroup request + */ + MHD_REQUEST_TERMINATED_CONNECTION_ERROR = 7 +}; + +/** + * Additional information about request termination + */ +union MHD_RequestTerminationDetail +{ + /** + * Reserved member. + * Do not use. + */ + void *reserved; +}; + +/** + * Request termination data structure + */ +struct MHD_RequestTerminationData +{ + /** + * The code of the event + */ + enum MHD_RequestTerminationCode code; + /** + * Detailed information about termination event + */ + union MHD_RequestTerminationDetail details; +}; + + +/** + * Signature of the callback used by MHD to notify the application + * about completed requests. + * + * @param cls client-defined closure + * @param data the details about the event + * @param request_context request context value, as originally + * returned by the #MHD_EarlyUriLogCallback + * @see #MHD_option_request_completion() + * @ingroup request + */ +typedef void +(*MHD_RequestTerminationCallback) (void *cls, + struct MHD_RequestTerminationData *data, + void *request_context); + + +/** + * The options (parameters) for responses. + */ +enum MHD_FIXED_ENUM_APP_SET_ MHD_ResponseOption +{ + /** + * Not a real option, terminate the list of options + */ + MHD_R_O_END = 0 + , + + /* = MHD Response Option enum values below are generated automatically = */ + /** + * Make the response object re-usable. + * The response will not be consumed by MHD_action_from_response() and must + * be destroyed by MHD_response_destroy(). + * Useful if the same response is often used to reply. + * The parameter value must be placed to the + * @a v_reusable member. + */ + MHD_R_O_REUSABLE = 20 + , + /** + * Enable special processing of the response as body-less (with undefined + * body size). No automatic "Content-Length" or "Transfer-Encoding: chunked" + * headers are added when the response is used with #MHD_HTTP_NOT_MODIFIED + * code or to respond to HEAD request. + * The flag also allow to set arbitrary "Content-Length" by + * #MHD_response_add_header() function. + * This flag value can be used only with responses created without body + * (zero-size body). + * Responses with this flag enabled cannot be used in situations where reply + * body must be sent to the client. + * This flag is primarily intended to be used when automatic "Content-Length" + * header is undesirable in response to HEAD requests. + * The parameter value must be placed to the + * @a v_head_only_response member. + */ + MHD_R_O_HEAD_ONLY_RESPONSE = 40 + , + /** + * Force use of chunked encoding even if the response content size is known. + * Ignored when the reply cannot have body/content. + * The parameter value must be placed to the + * @a v_chunked_enc member. + */ + MHD_R_O_CHUNKED_ENC = 41 + , + /** + * Force close connection after sending the response, prevents keep-alive + * connections and adds "Connection: close" header. + * The parameter value must be placed to the + * @a v_conn_close member. + */ + MHD_R_O_CONN_CLOSE = 60 + , + /** + * Only respond in conservative (dumb) HTTP/1.0-compatible mode. + * Response still use HTTP/1.1 version in header, but always close the + * connection after sending the response and do not use chunked encoding for + * the response. + * You can also set the #MHD_R_O_HTTP_1_0_SERVER flag to force HTTP/1.0 + * version in the response. + * Responses are still compatible with HTTP/1.1. + * This option can be used to communicate with some broken client, which does + * not implement HTTP/1.1 features, but advertises HTTP/1.1 support. + * The parameter value must be placed to the + * @a v_http_1_0_compatible_stric member. + */ + MHD_R_O_HTTP_1_0_COMPATIBLE_STRIC = 80 + , + /** + * Only respond in HTTP/1.0-mode. + * Contrary to the #MHD_R_O_HTTP_1_0_COMPATIBLE_STRICT flag, the response's + * HTTP version will always be set to 1.0 and keep-alive connections will be + * used if explicitly requested by the client. + * The "Connection:" header will be added for both "close" and "keep-alive" + * connections. + * Chunked encoding will not be used for the response. + * Due to backward compatibility, responses still can be used with HTTP/1.1 + * clients. + * This option can be used to emulate HTTP/1.0 server (for response part only + * as chunked encoding in requests (if any) is processed by MHD). + * With this option HTTP/1.0 server is emulated (with support for + * "keep-alive" connections). + * The parameter value must be placed to the + * @a v_http_1_0_server member. + */ + MHD_R_O_HTTP_1_0_SERVER = 81 + , + /** + * Disable sanity check preventing clients from manually setting the HTTP + * content length option. + * Allow to set several "Content-Length" headers. These headers will be used + * even with replies without body. + * The parameter value must be placed to the + * @a v_insanity_header_content_length member. + */ + MHD_R_O_INSANITY_HEADER_CONTENT_LENGTH = 100 + , + /** + * Set a function to be called once MHD is finished with the request. + * The parameter value must be placed to the + * @a v_termination_callback member. + */ + MHD_R_O_TERMINATION_CALLBACK = 121 + , + /* = MHD Response Option enum values above are generated automatically = */ + + /* * Sentinel * */ + /** + * The sentinel value. + * This value enforces specific underlying integer type for the enum. + * Do not use. + */ + MHD_R_O_SENTINEL = 65535 + +}; + +/* = MHD Response Option structures below are generated automatically = */ +/** + * Data for #MHD_R_O_TERMINATION_CALLBACK + */ +struct MHD_ResponeOptionValueTermCB +{ + /** + * The function to call, + * NULL to not use the callback + */ + MHD_RequestTerminationCallback v_term_cb; + /** + * The closure for the callback + */ + void *v_term_cb_cls; +}; + +/* = MHD Response Option structures above are generated automatically = */ + +/** + * Parameters for response options + */ +union MHD_ResponseOptionValue +{ + /* = MHD Response Option union members below are generated automatically = */ + /** + * Value for #MHD_R_O_REUSABLE + */ + enum MHD_Bool v_reusable; + /** + * Value for #MHD_R_O_HEAD_ONLY_RESPONSE + */ + enum MHD_Bool v_head_only_response; + /** + * Value for #MHD_R_O_CHUNKED_ENC + */ + enum MHD_Bool v_chunked_enc; + /** + * Value for #MHD_R_O_CONN_CLOSE + */ + enum MHD_Bool v_conn_close; + /** + * Value for #MHD_R_O_HTTP_1_0_COMPATIBLE_STRIC + */ + enum MHD_Bool v_http_1_0_compatible_stric; + /** + * Value for #MHD_R_O_HTTP_1_0_SERVER + */ + enum MHD_Bool v_http_1_0_server; + /** + * Value for #MHD_R_O_INSANITY_HEADER_CONTENT_LENGTH + */ + enum MHD_Bool v_insanity_header_content_length; + /** + * Value for #MHD_R_O_TERMINATION_CALLBACK + */ + struct MHD_ResponeOptionValueTermCB v_termination_callback; + /* = MHD Response Option union members above are generated automatically = */ +}; + +/** + * Combination of response option with parameters values + */ +struct MHD_ResponseOptionAndValue +{ + /** + * The response configuration option + */ + enum MHD_ResponseOption opt; + /** + * The value for the @a opt option + */ + union MHD_ResponseOptionValue val; +}; + + +#if defined(MHD_USE_COMPOUND_LITERALS) && defined(MHD_USE_DESIG_NEST_INIT) +/* = MHD Response Option macros below are generated automatically = */ +/** + * Make the response object re-usable. + * The response will not be consumed by MHD_action_from_response() and must be + * destroyed by MHD_response_destroy(). + * Useful if the same response is often used to reply. + * @param bool_val the value of the parameter + * @return the object of struct MHD_ResponseOptionAndValue with the requested + * values + */ +# define MHD_R_OPTION_REUSABLE(bool_val) \ + MHD_NOWARN_COMPOUND_LITERALS_ \ + (const struct MHD_ResponseOptionAndValue) \ + { \ + .opt = (MHD_R_O_REUSABLE), \ + .val.v_reusable = (bool_val) \ + } \ + MHD_RESTORE_WARN_COMPOUND_LITERALS_ + +/** + * Enable special processing of the response as body-less (with undefined body + * size). No automatic "Content-Length" or "Transfer-Encoding: chunked" headers + * are added when the response is used with #MHD_HTTP_NOT_MODIFIED code or to + * respond to HEAD request. + * The flag also allow to set arbitrary "Content-Length" by + * #MHD_response_add_header() function. + * This flag value can be used only with responses created without body + * (zero-size body). + * Responses with this flag enabled cannot be used in situations where reply + * body must be sent to the client. + * This flag is primarily intended to be used when automatic "Content-Length" + * header is undesirable in response to HEAD requests. + * @param bool_val the value of the parameter + * @return the object of struct MHD_ResponseOptionAndValue with the requested + * values + */ +# define MHD_R_OPTION_HEAD_ONLY_RESPONSE(bool_val) \ + MHD_NOWARN_COMPOUND_LITERALS_ \ + (const struct MHD_ResponseOptionAndValue) \ + { \ + .opt = (MHD_R_O_HEAD_ONLY_RESPONSE), \ + .val.v_head_only_response = (bool_val) \ + } \ + MHD_RESTORE_WARN_COMPOUND_LITERALS_ + +/** + * Force use of chunked encoding even if the response content size is known. + * Ignored when the reply cannot have body/content. + * @param bool_val the value of the parameter + * @return the object of struct MHD_ResponseOptionAndValue with the requested + * values + */ +# define MHD_R_OPTION_CHUNKED_ENC(bool_val) \ + MHD_NOWARN_COMPOUND_LITERALS_ \ + (const struct MHD_ResponseOptionAndValue) \ + { \ + .opt = (MHD_R_O_CHUNKED_ENC), \ + .val.v_chunked_enc = (bool_val) \ + } \ + MHD_RESTORE_WARN_COMPOUND_LITERALS_ + +/** + * Force close connection after sending the response, prevents keep-alive + * connections and adds "Connection: close" header. + * @param bool_val the value of the parameter + * @return the object of struct MHD_ResponseOptionAndValue with the requested + * values + */ +# define MHD_R_OPTION_CONN_CLOSE(bool_val) \ + MHD_NOWARN_COMPOUND_LITERALS_ \ + (const struct MHD_ResponseOptionAndValue) \ + { \ + .opt = (MHD_R_O_CONN_CLOSE), \ + .val.v_conn_close = (bool_val) \ + } \ + MHD_RESTORE_WARN_COMPOUND_LITERALS_ + +/** + * Only respond in conservative (dumb) HTTP/1.0-compatible mode. + * Response still use HTTP/1.1 version in header, but always close the + * connection after sending the response and do not use chunked encoding for + * the response. + * You can also set the #MHD_R_O_HTTP_1_0_SERVER flag to force HTTP/1.0 version + * in the response. + * Responses are still compatible with HTTP/1.1. + * This option can be used to communicate with some broken client, which does + * not implement HTTP/1.1 features, but advertises HTTP/1.1 support. + * @param bool_val the value of the parameter + * @return the object of struct MHD_ResponseOptionAndValue with the requested + * values + */ +# define MHD_R_OPTION_HTTP_1_0_COMPATIBLE_STRIC(bool_val) \ + MHD_NOWARN_COMPOUND_LITERALS_ \ + (const struct MHD_ResponseOptionAndValue) \ + { \ + .opt = (MHD_R_O_HTTP_1_0_COMPATIBLE_STRIC), \ + .val.v_http_1_0_compatible_stric = (bool_val) \ + } \ + MHD_RESTORE_WARN_COMPOUND_LITERALS_ + +/** + * Only respond in HTTP/1.0-mode. + * Contrary to the #MHD_R_O_HTTP_1_0_COMPATIBLE_STRICT flag, the response's + * HTTP version will always be set to 1.0 and keep-alive connections will be + * used if explicitly requested by the client. + * The "Connection:" header will be added for both "close" and "keep-alive" + * connections. + * Chunked encoding will not be used for the response. + * Due to backward compatibility, responses still can be used with HTTP/1.1 + * clients. + * This option can be used to emulate HTTP/1.0 server (for response part only + * as chunked encoding in requests (if any) is processed by MHD). + * With this option HTTP/1.0 server is emulated (with support for "keep-alive" + * connections). + * @param bool_val the value of the parameter + * @return the object of struct MHD_ResponseOptionAndValue with the requested + * values + */ +# define MHD_R_OPTION_HTTP_1_0_SERVER(bool_val) \ + MHD_NOWARN_COMPOUND_LITERALS_ \ + (const struct MHD_ResponseOptionAndValue) \ + { \ + .opt = (MHD_R_O_HTTP_1_0_SERVER), \ + .val.v_http_1_0_server = (bool_val) \ + } \ + MHD_RESTORE_WARN_COMPOUND_LITERALS_ + +/** + * Disable sanity check preventing clients from manually setting the HTTP + * content length option. + * Allow to set several "Content-Length" headers. These headers will be used + * even with replies without body. + * @param bool_val the value of the parameter + * @return the object of struct MHD_ResponseOptionAndValue with the requested + * values + */ +# define MHD_R_OPTION_INSANITY_HEADER_CONTENT_LENGTH(bool_val) \ + MHD_NOWARN_COMPOUND_LITERALS_ \ + (const struct MHD_ResponseOptionAndValue) \ + { \ + .opt = (MHD_R_O_INSANITY_HEADER_CONTENT_LENGTH), \ + .val.v_insanity_header_content_length = (bool_val) \ + } \ + MHD_RESTORE_WARN_COMPOUND_LITERALS_ + +/** + * Set a function to be called once MHD is finished with the request. + * @param term_cb the function to call, + * NULL to not use the callback + * @param term_cb_cls the closure for the callback + * @return the object of struct MHD_ResponseOptionAndValue with the requested + * values + */ +# define MHD_R_OPTION_TERMINATION_CALLBACK(term_cb,term_cb_cls) \ + MHD_NOWARN_COMPOUND_LITERALS_ \ + (const struct MHD_ResponseOptionAndValue) \ + { \ + .opt = (MHD_R_O_TERMINATION_CALLBACK), \ + .val.v_termination_callback.v_term_cb = (term_cb), \ + .val.v_termination_callback.v_term_cb_cls = (term_cb_cls) \ + } \ + MHD_RESTORE_WARN_COMPOUND_LITERALS_ + +/* = MHD Response Option macros above are generated automatically = */ + +/** + * Terminate the list of the options + * @return the terminating object of struct MHD_ResponseOptionAndValue + */ +# define MHD_R_OPTION_TERMINATE() \ + MHD_NOWARN_COMPOUND_LITERALS_ \ + (const struct MHD_ResponseOptionAndValue) \ + { \ + .opt = (MHD_R_O_END) \ + } \ + MHD_RESTORE_WARN_COMPOUND_LITERALS_ + +#else /* !MHD_USE_COMPOUND_LITERALS || !MHD_USE_DESIG_NEST_INIT */ +MHD_NOWARN_UNUSED_FUNC_ +/* = MHD Response Option static functions below are generated automatically = */ +/** + * Make the response object re-usable. + * The response will not be consumed by MHD_action_from_response() and must be + * destroyed by MHD_response_destroy(). + * Useful if the same response is often used to reply. + * @param bool_val the value of the parameter + * @return the object of struct MHD_ResponseOptionAndValue with the requested + * values + */ +static MHD_INLINE struct MHD_ResponseOptionAndValue +MHD_R_OPTION_REUSABLE (enum MHD_Bool bool_val) +{ + struct MHD_ResponseOptionAndValue opt_val; + + opt_val.opt = MHD_R_O_REUSABLE; + opt_val.val.v_reusable = bool_val; + + return opt_val; +} + + +/** + * Enable special processing of the response as body-less (with undefined body + * size). No automatic "Content-Length" or "Transfer-Encoding: chunked" headers + * are added when the response is used with #MHD_HTTP_NOT_MODIFIED code or to + * respond to HEAD request. + * The flag also allow to set arbitrary "Content-Length" by + * #MHD_response_add_header() function. + * This flag value can be used only with responses created without body + * (zero-size body). + * Responses with this flag enabled cannot be used in situations where reply + * body must be sent to the client. + * This flag is primarily intended to be used when automatic "Content-Length" + * header is undesirable in response to HEAD requests. + * @param bool_val the value of the parameter + * @return the object of struct MHD_ResponseOptionAndValue with the requested + * values + */ +static MHD_INLINE struct MHD_ResponseOptionAndValue +MHD_R_OPTION_HEAD_ONLY_RESPONSE (enum MHD_Bool bool_val) +{ + struct MHD_ResponseOptionAndValue opt_val; + + opt_val.opt = MHD_R_O_HEAD_ONLY_RESPONSE; + opt_val.val.v_head_only_response = bool_val; + + return opt_val; +} /** - * Flags for special handling of responses. + * Force use of chunked encoding even if the response content size is known. + * Ignored when the reply cannot have body/content. + * @param bool_val the value of the parameter + * @return the object of struct MHD_ResponseOptionAndValue with the requested + * values */ -// FIXME: extended, sorted -enum MHD_ResponseOptionBool +static MHD_INLINE struct MHD_ResponseOptionAndValue +MHD_R_OPTION_CHUNKED_ENC (enum MHD_Bool bool_val) { - /** - * Not a real option, terminate the list of options - */ - MHD_RESP_OPT_BOOL_END = 0, + struct MHD_ResponseOptionAndValue opt_val; - /** - * Make the response object re-usable. - * The response will not be consumed by MHD_action_from_response() and - * must be destroyed by MHD_response_destroy(). - * Useful if the response is often used to reply. - */ - MHD_RESP_OPT_BOOL_REUSABLE = 1, + opt_val.opt = MHD_R_O_CHUNKED_ENC; + opt_val.val.v_chunked_enc = bool_val; - /** - * Force close connection after sending the response, prevents keep-alive - * connections and adds "Connection: close" header. - */ - MHD_RESP_OPT_BOOL_CONN_CLOSE = 21, + return opt_val; +} - /** - * Force use of chunked encoding even if the response content size is known. - * Ignored when the reply cannot have body/content. - */ - MHD_RESP_OPT_BOOL_CHUNKED_ENC = 22, - /** - * Enable sending of "Connection: keep-alive" header even for - * HTTP/1.1 clients when "Keep-Alive" connection is used. - * Disabled by default for HTTP/1.1 clients as per RFC. - */ - MHD_RESP_OPT_BOOL_SEND_KEEP_ALIVE_HEADER = 41, +/** + * Force close connection after sending the response, prevents keep-alive + * connections and adds "Connection: close" header. + * @param bool_val the value of the parameter + * @return the object of struct MHD_ResponseOptionAndValue with the requested + * values + */ +static MHD_INLINE struct MHD_ResponseOptionAndValue +MHD_R_OPTION_CONN_CLOSE (enum MHD_Bool bool_val) +{ + struct MHD_ResponseOptionAndValue opt_val; - /** - * Only respond in conservative (dumb) HTTP/1.0-compatible mode. - * Response still use HTTP/1.1 version in header, but always close - * the connection after sending the response and do not use chunked - * encoding for the response. - * You can also set the #MHD_RESP_OPT_BOOL_HTTP_1_0_SERVER flag to force - * HTTP/1.0 version in the response. - * Responses are still compatible with HTTP/1.1. - * This option can be used to communicate with some broken client, which - * does not implement HTTP/1.1 features, but advertises HTTP/1.1 support. - */ - MHD_RESP_OPT_BOOL_HTTP_1_0_COMPATIBLE_STRICT = 42, + opt_val.opt = MHD_R_O_CONN_CLOSE; + opt_val.val.v_conn_close = bool_val; - /** - * Only respond in HTTP/1.0-mode. - * Contrary to the #MHD_RESP_OPT_BOOL_HTTP_1_0_COMPATIBLE_STRICT flag, the response's - * HTTP version will always be set to 1.0 and keep-alive connections - * will be used if explicitly requested by the client. - * The "Connection:" header will be added for both "close" and "keep-alive" - * connections. - * Chunked encoding will not be used for the response. - * Due to backward compatibility, responses still can be used with - * HTTP/1.1 clients. - * This option can be used to emulate HTTP/1.0 server (for response part - * only as chunked encoding in requests (if any) is processed by MHD). - */ - MHD_RESP_OPT_BOOL_HTTP_1_0_SERVER = 43, - /** - * Disable sanity check preventing clients from manually - * setting the HTTP content length option. - * Allow to set several "Content-Length" headers. These headers will - * be used even with replies without body. - */ - MHD_RESP_OPT_BOOL_INSANITY_HEADER_CONTENT_LENGTH = 61, + return opt_val; +} - /** - * Enable special processing of the response as body-less (with undefined - * body size). No automatic "Content-Length" or "Transfer-Encoding: chunked" - * headers are added when the response is used with #MHD_HTTP_NOT_MODIFIED - * code or to respond to HEAD request. - * The flag also allow to set arbitrary "Content-Length" by - * MHD_add_response_header() function. - * This flag value can be used only with responses created without body - * (zero-size body). - * Responses with this flag enabled cannot be used in situations where - * reply body must be sent to the client. - * This flag is primarily intended to be used when automatic "Content-Length" - * header is undesirable in response to HEAD requests. - */ - MHD_RESP_OPT_BOOL_HEAD_ONLY_RESPONSE = 81 // FIXME: replace with special "create" function? -} _MHD_FIXED_FLAGS_ENUM; +/** + * Only respond in conservative (dumb) HTTP/1.0-compatible mode. + * Response still use HTTP/1.1 version in header, but always close the + * connection after sending the response and do not use chunked encoding for + * the response. + * You can also set the #MHD_R_O_HTTP_1_0_SERVER flag to force HTTP/1.0 version + * in the response. + * Responses are still compatible with HTTP/1.1. + * This option can be used to communicate with some broken client, which does + * not implement HTTP/1.1 features, but advertises HTTP/1.1 support. + * @param bool_val the value of the parameter + * @return the object of struct MHD_ResponseOptionAndValue with the requested + * values + */ +static MHD_INLINE struct MHD_ResponseOptionAndValue +MHD_R_OPTION_HTTP_1_0_COMPATIBLE_STRIC (enum MHD_Bool bool_val) +{ + struct MHD_ResponseOptionAndValue opt_val; + + opt_val.opt = MHD_R_O_HTTP_1_0_COMPATIBLE_STRIC; + opt_val.val.v_http_1_0_compatible_stric = bool_val; -// FIXME: use the same approach as for the daemon -_MHD_EXTERN enum MHD_StatusCode -MHD_response_set_option_bool (struct MHD_Response *response, - enum MHD_ResponseOption ro, - enum MHD_Bool value) -MHD_FUNC_PARAM_NONNULL_ALL_; + return opt_val; +} -// FIXME: the suggested approach -struct MHD_ResponseOptionBoolSet +/** + * Only respond in HTTP/1.0-mode. + * Contrary to the #MHD_R_O_HTTP_1_0_COMPATIBLE_STRICT flag, the response's + * HTTP version will always be set to 1.0 and keep-alive connections will be + * used if explicitly requested by the client. + * The "Connection:" header will be added for both "close" and "keep-alive" + * connections. + * Chunked encoding will not be used for the response. + * Due to backward compatibility, responses still can be used with HTTP/1.1 + * clients. + * This option can be used to emulate HTTP/1.0 server (for response part only + * as chunked encoding in requests (if any) is processed by MHD). + * With this option HTTP/1.0 server is emulated (with support for "keep-alive" + * connections). + * @param bool_val the value of the parameter + * @return the object of struct MHD_ResponseOptionAndValue with the requested + * values + */ +static MHD_INLINE struct MHD_ResponseOptionAndValue +MHD_R_OPTION_HTTP_1_0_SERVER (enum MHD_Bool bool_val) { - enum MHD_ResponseOptionBool option; - enum MHD_Bool value; -}; + struct MHD_ResponseOptionAndValue opt_val; + + opt_val.opt = MHD_R_O_HTTP_1_0_SERVER; + opt_val.val.v_http_1_0_server = bool_val; + + return opt_val; +} -// FIXME: fully type-safe, options array can be built incrementally -// See https://github.com/babelouest/ulfius/blob/1ed26069fd7e1decd38e8d403a5649b0337893ff/src/ulfius.c#L1073 -// for incrementally built options /** - * Set several options for the response object - * @param response the response to set the options - * @param options_array the pointer to the array with the options; - * the array is read until first ::MHD_RESP_OPT_BOOL_END - * option, but not more than @a max_num_options elements - * @param max_num_options the maximum number of elements to read - * from @a options_array, ignored if set to SIZE_MAX - * @return #MHD_SC_OK if found, - * // FIXME: add error codes + * Disable sanity check preventing clients from manually setting the HTTP + * content length option. + * Allow to set several "Content-Length" headers. These headers will be used + * even with replies without body. + * @param bool_val the value of the parameter + * @return the object of struct MHD_ResponseOptionAndValue with the requested + * values */ -_MHD_EXTERN enum MHD_StatusCode -MHD_response_set_options_bool (struct MHD_Response *response, - struct MHD_ResponseOptionBoolSet *options_array, - size_t max_num_options) // FIXME: another sequence, as intended -MHD_FUNC_PARAM_NONNULL_ALL_; +static MHD_INLINE struct MHD_ResponseOptionAndValue +MHD_R_OPTION_INSANITY_HEADER_CONTENT_LENGTH (enum MHD_Bool bool_val) +{ + struct MHD_ResponseOptionAndValue opt_val; + opt_val.opt = MHD_R_O_INSANITY_HEADER_CONTENT_LENGTH; + opt_val.val.v_insanity_header_content_length = bool_val; -#if 1 // def MHD_USE_VARARG_MACROS_ // FIXME -// FIXME: How? -#define MHD_response_set_options_bool_macro(response,...) -#endif /* MHD_USE_VARARG_MACROS_ */ + return opt_val; +} /** - * The `enum MHD_RequestTerminationCode` specifies reasons - * why a request has been terminated (or completed). - * @ingroup request + * Set a function to be called once MHD is finished with the request. + * @param term_cb the function to call, + * NULL to not use the callback + * @param term_cb_cls the closure for the callback + * @return the object of struct MHD_ResponseOptionAndValue with the requested + * values */ -enum MHD_RequestTerminationCode +static MHD_INLINE struct MHD_ResponseOptionAndValue +MHD_R_OPTION_TERMINATION_CALLBACK ( + MHD_RequestTerminationCallback term_cb, + void *term_cb_cls) { + struct MHD_ResponseOptionAndValue opt_val; - /** - * We finished sending the response. - * @ingroup request - */ - MHD_REQUEST_TERMINATED_COMPLETED_OK = 0 - , - // FIXME: extended, sorted - /** - * The application terminated request without response. - * @ingroup request - */ - MHD_REQUEST_TERMINATED_BY_APP = 1 - , - /** - * The request is not valid according to - * HTTP specifications. - * @ingroup request - */ - MHD_REQUEST_TERMINATED_HTTP_PROTOCOL_ERROR = 2 - , - /** - * The client terminated the connection by closing the socket - * for writing (TCP half-closed) before sending complete request; - * MHD aborted sending the response according to RFC 2616, section 8.1.4. - * @ingroup request - */ - MHD_REQUEST_TERMINATED_CLIENT_ABORT = 3 - , - /** - * Error handling the connection due to resources - * exhausted. - * @ingroup request - */ - MHD_REQUEST_TERMINATED_NO_RESOURCES = 4 - , - /** - * We had to close the session since MHD was being - * shut down. - * @ingroup request - */ - MHD_REQUEST_TERMINATED_DAEMON_SHUTDOWN = 5 - , - /** - * No activity on the connection for the number - * of seconds specified using - * #MHD_OPTION_CONNECTION_TIMEOUT. - * @ingroup request - */ - MHD_REQUEST_TERMINATED_TIMEOUT_REACHED = 6 - , - /** - * The connection was broken or TLS protocol error. - * @ingroup request - */ - MHD_REQUEST_TERMINATED_CONNECTION_ERROR = 7 + opt_val.opt = MHD_R_O_TERMINATION_CALLBACK; + opt_val.val.v_termination_callback.v_term_cb = term_cb; + opt_val.val.v_termination_callback.v_term_cb_cls = term_cb_cls; -}; + return opt_val; +} +/* = MHD Response Option static functions above are generated automatically = */ /** - * Signature of the callback used by MHD to notify the application - * about completed requests. - * - * @param cls client-defined closure - * @param reqtc the reason for request termination - * @param request_context request context value, as originally - * returned by the #MHD_EarlyUriLogCallback - * @see #MHD_option_request_completion() - * @ingroup request + * Terminate the list of the options + * @return the terminating object of struct MHD_ResponseOptionAndValue */ -typedef void -(*MHD_RequestTerminationCallback) (void *cls, - enum MHD_RequestTerminationCode reqtc, - void *request_context); +static MHD_INLINE struct MHD_ResponseOptionAndValue +MHD_R_OPTION_TERMINATE (void) +{ + struct MHD_ResponseOptionAndValue opt_val; + + opt_val.opt = MHD_R_O_END; + + return opt_val; +} + + +MHD_RESTORE_WARN_UNUSED_FUNC_ +#endif /* !MHD_USE_COMPOUND_LITERALS || !MHD_USE_DESIG_NEST_INIT */ /** - * Set a function to be called once MHD is finished with the - * request. + * Set the requested options for the response. * - * @param[in,out] response which response to set the callback for - * @param termination_cb function to call, can be NULL to not use the callback - * @param termination_cb_cls closure for @e termination_cb + * If any option fail other options may be or may be not applied. + * @param response the response to set the options + * @param[in] options the pointer to the array with the options; + * the array processing stops at the first ::MHD_D_O_END + * option, but not later than after processing + * @a options_max_num entries + * @param options_max_num the maximum number of entries in the @a options, + * use #MHD_OPTIONS_ARRAY_MAX_SIZE if options processing + * must stop only at zero-termination option + * @return ::MHD_SC_OK on success, + * error code otherwise */ -_MHD_EXTERN enum MHD_StatusCode -MHD_response_set_option_termination_callback ( - struct MHD_Response *response, - MHD_RequestTerminationCallback termination_cb, - void *termination_cb_cls) -MHD_FUNC_PARAM_NONNULL_ (1); +MHD_EXTERN_ enum MHD_StatusCode +MHD_response_options_set(struct MHD_Response *daemon, + const struct MHD_ResponseOptionAndValue *options, + size_t options_max_num) +MHD_FN_PAR_NONNULL_ALL_; -// FIXME: remove? -enum MHD_DynContCreatorActionType -{ - /** - * Continue with response content - */ - MHD_DYN_CONT_CREATOR_ACT_CONTINUE = 0 - , - /** - * The final chunk of content is created - */ - MHD_DYN_CONT_CREATOR_ACT_FINISHED = 1 - , +/** + * Set the requested single option for the response. + * + * @param response the response to set the option + * @param[in] options the pointer to the option + * @return ::MHD_SC_OK on success, + * error code otherwise + */ +#define MHD_response_option_set(response,option_ptr) \ + MHD_response_options_set(response,options_ptr,1) - /** - * Error creating the content. - * The request will be closed in a hard way. - */ - MHD_DYN_CONT_CREATOR_ACT_ERROR_STOP = 2 - , - /** - * Suspend content creation. - * // TODO: describe - */ - MHD_DYN_CONT_CREATOR_ACT_SUSPEND = 3 -}; +#ifdef MHD_USE_VARARG_MACROS +MHD_NOWARN_VARIADIC_MACROS_ +# if defined(MHD_USE_COMPOUND_LITERALS) && \ + defined(MHD_USE_COMP_LIT_FUNC_PARAMS) +/** + * Set the requested options for the response. + * + * If any option fail other options may be or may be not applied. + * + * It should be used with helpers that creates required options, for example: + * + * MHD_RESPONE_OPTIONS_SET(d, MHD_R_OPTION_REUSABLE(MHD_YES), + * MHD_R_OPTION_TERMINATION_CALLBACK(func, cls)) + * + * @param response the response to set the option + * @param ... the list of the options, each option must be created + * by helpers MHD_RESPONSE_OPTION_NameOfOption(option_value) + * @return ::MHD_SC_OK on success, + * error code otherwise + */ +# define MHD_RESPONSE_OPTIONS_SET(response,...) \ + MHD_NOWARN_COMPOUND_LITERALS_ \ + MHD_response_options_set(daemon, \ + ((const struct MHD_ResponseOptionAndValue[]) \ + {__VA_ARGS__, MHD_R_OPTION_TERMINATE()}), \ + MHD_OPTIONS_ARRAY_MAX_SIZE) \ + MHD_RESTORE_WARN_COMPOUND_LITERALS_ +# elif defined(MHD_USE_CPP_INIT_LIST) +} /* extern "C" */ +# include <vector> +extern "C" +{ +/** + * Set the requested options for the daemon. + * + * If any option fail other options may be or may be not applied. + * + * It should be used with helpers that creates required options, for example: + * + * MHD_RESPONE_OPTIONS_SET(d, MHD_R_OPTION_REUSABLE(MHD_YES), + * MHD_R_OPTION_TERMINATION_CALLBACK(func, cls)) + * + * @param daemon the daemon to set the options + * @param ... the list of the options, each option must be created + * by helpers MHD_D_OPTION_NameOfOption(option_value) + * @return ::MHD_SC_OK on success, + * error code otherwise + */ +# define MHD_DAEMON_OPTIONS_SET(daemon,...) \ + MHD_NOWARN_CPP_INIT_LIST_ \ + MHD_daemon_options_set(daemon, \ + (std::vector<struct MHD_DaemonOptionAndValue> \ + {__VA_ARGS__,MHD_R_OPTION_TERMINATE()}).data(), \ + MHD_OPTIONS_ARRAY_MAX_SIZE) \ + MHD_RESTORE_WARN_CPP_INIT_LIST_ +# endif +MHD_RESTORE_WARN_VARIADIC_MACROS_ +#endif /* MHD_USE_VARARG_MACROS && MHD_USE_COMP_LIT_FUNC_PARAMS */ /** @@ -4466,7 +8211,10 @@ typedef void (*MHD_FreeCallback) (void *free_cls); -// TODO: Doxy +/** + * Structure for iov type of the response. + * Used for zero-copy response content data. + */ struct MHD_DynContentZCIoVec { /** @@ -4489,271 +8237,125 @@ struct MHD_DynContentZCIoVec void *iov_fcb_cls; }; +/** + * The action type returned by Dynamic Content Creator callback + */ struct MHD_DynamicContentCreatorAction; +/** + * The context used for Dynamic Content Creator callback + */ struct MHD_DynamicContentCreatorContext; -// internally: -struct MHD_DynamicContentCreatorAction -{ - enum DCC_Actiontype type; - union - { - struct - { - uint_fast64_t suspend_microsec; - } suspend; - } details; -}; -struct MHD_DynamicContentCreatorContext -{ - struct MHD_DynamicContentCreatorAction action; -}; - - /** * Set action to "continue processing", the data is provided in the - * buffer. - * If function failed for any reason, the action is automatically - * set to "stop with error". - * @param[in,out] action the pointer the action as provided to the callback + * buffer and/or in the zero-copy @a iov_data. + * If data is provided both in the buffer and @a ivo_data then + * data in the buffer sent first, following the iov data. + * The total size of the data in the buffer and in @a iov_data must + * be non-zero. + * @param[in,out] ctx the pointer the context as provided to the callback * @param data_size the amount of the data placed to the provided buffer, - * cannot be larger than provided buffer size + * cannot be larger than provided buffer size, + * must be non-zero if @a iov_data is NULL or has no data, + * @param iov_data the optional pointer to the iov data, + * must not be NULL and have non-zero size data if @a data_size + * is zero, * @param chunk_ext the optional pointer to chunk extension string, * can be NULL to not use chunk extension, * ignored if chunked encoding is not used - * @return MHD_SC_OK if success, - * error code otherwise // TODO: add the list + * @return the pointer to the action if succeed, + * NULL (equivalent of MHD_DCC_action_abort())in case of any error */ -_MHD_EXTERN const struct MHD_DynamicContentCreatorAction * -MHD_DCC_action_continue ( +MHD_EXTERN_ const struct MHD_DynamicContentCreatorAction * +MHD_DCC_action_continue_zc ( struct MHD_DynamicContentCreatorContext *ctx, size_t data_size, + const struct MHD_DynContentZCIoVec *iov_data, const char *chunk_ext) -MHD_FUNC_PARAM_NONNULL_ (1); +MHD_FN_PAR_NONNULL_ (1) +MHD_FN_PAR_CSTR_(4); - -// FIXME: the @a buf parameter will be ignored -/** - * Set action to "continue processing", the zero-copy data is provided - * in the @a iov_data. - * If function failed for any reason, the action is automatically - * set to "stop with error". - * @param[in,out] action the pointer the action as provided to the callback - * @param data_size the amount of the data placed to the provided buffer, - * cannot be larger than provided buffer size - * @param chunk_ext the optional pointer to chunk extension string, - * can be NULL to not use chunk extension, - * ignored if chunked encoding is not used - * @return MHD_SC_OK if success, - * error code otherwise // TODO: add the list - */ -_MHD_EXTERN enum MHD_StatusCode -MHD_DCC_set_action_continue_zc ( - struct MHD_DynamicContentCreatorAction *action, - size_t bytes_in_buf, - struct MHD_DynContentZCIoVec *iov_data, - const char *chunk_ext) -MHD_FUNC_PARAM_NONNULL_ (1); - -#define MHD_DCC_set_action_continue (a,b) \ - MHD_DCC_set_action_continue_zc (a, b, NULL, NULL) +#define MHD_DCC_action_continue(ctx,data_size,chunk_ext) \ + MHD_DCC_action_continue_zc (ctx, data_size, NULL, chunk_ext) /** * Set action to "finished". * If function failed for any reason, the action is automatically * set to "stop with error". - * @param[in,out] action the pointer the action as provided to the callback + * @param[in,out] ctx the pointer the context as provided to the callback * @param num_footers number of elements in the @a footers array, * must be zero if @a footers is NULL - * @param footers the optional pointer to the array of the footers, - * can be NULL - * @return #MHD_SC_OK if success, - * error code otherwise // TODO: add the list - */ -_MHD_EXTERN enum MHD_StatusCode -MHD_DCC_set_action_finished_with_footer ( - struct MHD_DynamicContentCreatorAction *action, + * @param footers the optional pointer to the array of the footers (the strings + * are copied and does not need to be valid after return from + * this function), + * can be NULL if @a num_footers is zero + * @return the pointer to the action if succeed, + * NULL (equivalent of MHD_DCC_action_abort())in case of any error + */ +MHD_EXTERN_ const struct MHD_DynamicContentCreatorAction * +MHD_DCC_action_finished_with_footer ( + struct MHD_DynamicContentCreatorContext *ctx, size_t num_footers, - const struct MHD_CStringPair *footers) -MHD_FUNC_PARAM_NONNULL_ (1); + const struct MHD_NameValueCStr *footers) +MHD_FN_PAR_NONNULL_ (1); -#define MHD_DCC_set_action_finished(action) \ +#define MHD_DCC_action_finished(action) \ MHD_DCC_set_action_finished_with_footer (action, 0, NULL) /** - * Set action to "finished". + * Set action to "suspend". * If function failed for any reason, the action is automatically * set to "stop with error". - * @param[in,out] action the pointer the action as provided to the callback - * @param suspend_microsec the maximum duration of suspension after which - * the request is automatically resumed, if not - * resumed earlier by #MHD_request_resume(), - * the precise resume moment is not guaranteed, it - * may happen later (but not earlier) depending - * on timer granularity and the system load; - * if set to UINT64_MAX (or higher) the request - * is not resumed automatically, - * the suspension period can be shorter then requested - * if the number is higher than 86 400 000 000 (one day) // FIXME: discuss - * @return MHD_SC_OK if success, - * error code otherwise // TODO: add the list + * @param[in,out] ctx the pointer the context as provided to the callback + * @return the pointer to the action if succeed, + * NULL (equivalent of MHD_DCC_action_abort())in case of any error */ -_MHD_EXTERN enum MHD_StatusCode -MHD_DCC_set_action_suspend ( - struct MHD_DynamicContentCreatorAction *action, - uint_fast64_t suspend_microsec) -MHD_FUNC_PARAM_NONNULL_ (1); +MHD_EXTERN_ const struct MHD_DynamicContentCreatorAction * +MHD_DCC_action_suspend (struct MHD_DynamicContentCreatorContext *ctx) +MHD_FN_PAR_NONNULL_ (1) +MHD_FN_RETURNS_NONNULL_; /** * Set action to "stop with error". - * @param[in,out] action the pointer the action as provided to the callback - * @return always MHD_SC_OK + * @param[in,out] ctx the pointer the context as provided to the callback + * @return always NULL (the action "stop with error") */ -_MHD_EXTERN enum MHD_StatusCode -MHD_DCC_set_action_error_stop ( - struct MHD_DynamicContentCreatorAction *action) -MHD_FUNC_PARAM_NONNULL_ (1); +#define MHD_DCC_action_abort(ctx) \ + MHD_STATIC_CAST_(const struct MHD_DynamicContentCreatorAction *, NULL) - -// FIXME: Updated /** * Callback used by libmicrohttpd in order to obtain content. The - * callback is to copy at most @a max bytes of content into @a buf. The - * total number of bytes that has been placed into @a buf should be - * returned. + * callback is to copy at most @a max bytes of content into @a buf or + * provide zero-copy data for #MHD_DCC_action_continue_zc(). * * @param dyn_cont_cls closure argument to the callback + * @param ctx the context to produce the action to return, + * the pointer is only valid until the callback returns * @param pos position in the datastream to access; * note that if a `struct MHD_Response` object is re-used, * it is possible for the same content reader to * be queried multiple times for the same data; * however, if a `struct MHD_Response` is not re-used, * libmicrohttpd guarantees that "pos" will be - * the sum of all non-negative return values - * obtained from the content reader so far. + * the sum of all data sizes provided by this callback * @param[out] buf where to copy the data - * @param max maximum number of bytes to copy to @a buf (size of @a buf), - * the value of @a max is always less or equal SSIZE_MAX + * @param max maximum number of bytes to copy to @a buf (size of @a buf) * @param[out] action the action to set, * the pointer is only valid until * the callback returns - * @return number of bytes written to @a buf; - * 0 is legal only for external polling modes; - * with internal polling thread(s) it is interpreted as - * #MHD_DYNAMIC_CONTENT_END_WITH_ERROR (see below); - * #MHD_DYNAMIC_CONTENT_END_OF_STREAM (-1) for the regular - * end of transmission (with chunked encoding, MHD will then - * terminate the chunk and send any HTTP footers that might be - * present; with HTTP/1.0 and given an unknown response size, - * MHD will simply close the connection; note that while - * returning #MHD_DYNAMIC_CONTENT_END_OF_STREAM is not technically - * legal if a response size was specified, MHD accepts this - * and treats it just as #MHD_DYNAMIC_CONTENT_END_WITH_ERROR; - * #MHD_DYNAMIC_CONTENT_STOP_WITH_ERROR (-2) to indicate a server - * error generating the response; this will cause MHD to simply - * close the connection immediately. If a response size was - * given or if chunked encoding is in use, this will indicate - * an error to the client. Note, however, that if HTTP/1.0 - * is used then the clients will not be able to differentiate between - * #MHD_DYNAMIC_CONTENT_STOP_WITH_ERROR and #MHD_DYNAMIC_CONTENT_END_OF_STREAM. - * This is not a limitation of MHD but rather of the HTTP/1.0 protocol. - * #MHD_DYNAMIC_CONTENT_SUSPEND_REQUEST (-3) to suspend the request - * processing until MHD_request_resume() is called. - */ -typedef const struct MHD_DynamicContentCreatorAction * -(MHD_FUNC_PARAM_NONNULL_ (2,4) - *MHD_DynamicContentCreator)(void *dyn_cont_cls, - struct MHD_DynamicContentCreatorContext *ctx, - uint64_t pos, - void *buf, - size_t max); - - -/** - * Create a response. The response object can be extended with - * header information. - * - * @param sc status code to return - * @param size size of the data portion of the response, #MHD_SIZE_UNKNOWN for unknown - * @param block_size preferred block size for querying crc (advisory only, - * MHD may still call @a crc using smaller chunks); this - * is essentially the buffer size used for IO, clients - * should pick a value that is appropriate for IO and - * memory performance requirements - * @param dyn_cont callback to use to obtain response data - * @param dyn_cont_cls extra argument to @a crc - * @param dyn_cont_fc callback to call to free @a dyn_cont_cls resources - * @return NULL on error (i.e. invalid arguments, out of memory) - * @ingroup response - */ -_MHD_EXTERN struct MHD_Response * -MHD_response_from_callback (enum MHD_HTTP_StatusCode sc, - uint64_t size, - size_t block_size, // FIXME: replace with option - MHD_DynamicContentCreator dyn_cont, - void *dyn_cont_cls, - MHD_FreeCallback dyn_cont_fc); - - -enum MHD_DynContentZCAction -{ - MHD_DYN_CONTENT_ZC_ACTION_CONTINUE = 0, - MHD_DYN_CONTENT_ZC_ACTION_END_OF_STREAM = 1, - MHD_DYN_CONTENT_ZC_ACTION_STOP_WITH_ERROR = 2, - MHD_DYN_CONTENT_ZC_ACTION_SUSPEND_REQUEST = 3 // TODO: add timeout -}; - -// TODO: Doxy -struct MHD_DynContentZCIoVec -{ - /** - * The number of elements in @a iov - */ - unsigned int iov_count; - /** - * The pointer to the array with @a iov_count elements. - */ - const struct MHD_IoVec *iov; - /** - * The callback to free resources. - * It is called once the full array of iov elements is sent. - * No callback is called if NULL. - */ - MHD_FreeCallback iov_fcb; - /** - * The parameter for @a iov_fcb - */ - void *iov_fcb_cls; -}; - -/** - * Callback used by libmicrohttpd in order to obtain content. The - * callback is to copy at most @a max bytes of content into @a buf. The - * total number of bytes that has been placed into @a buf should be - * returned. - * - * If total data size set in @a iov_data by this callback is zero and - * internal polling thread(s) is used then it is interpreted like - * return of #MHD_DYN_CONTENT_ZC_ACTION_STOP_WITH_ERROR. - * - * @param dyn_cont_zc_cls extra argument to the callback - * @param pos position in the datastream to access; - * note that if a `struct MHD_Response` object is re-used, - * it is possible for the same content reader to - * be queried multiple times for the same data; - * however, if a `struct MHD_Response` is not re-used, - * libmicrohttpd guarantees that "pos" will be - * the sum of all data provided so far. - * @param[out] iov_data the parameters - * @return the requested next action + * @return action to use, + * NULL in case of any error (the response will be aborted) */ -typedef enum MHD_DynContentZCAction -(*MHD_DynamicContentCreatorZC)(void *dyn_cont_zc_cls, - uint64_t pos, - struct MHD_DynContentZCIoVec iov_data); +typedef const struct MHD_DynamicContentCreatorAction * +(MHD_FN_PAR_NONNULL_ (2) MHD_FN_PAR_NONNULL_ (4) + *MHD_DynamicContentCreator)(void *dyn_cont_cls, + struct MHD_DynamicContentCreatorContext *ctx, + uint_fast64_t pos, + void *buf, + size_t max); /** @@ -4762,73 +8364,18 @@ typedef enum MHD_DynContentZCAction * * @param sc status code to return * @param size size of the data portion of the response, #MHD_SIZE_UNKNOWN for unknown - * @param block_size preferred block size for querying crc (advisory only, - * MHD may still call @a crc using smaller chunks); this - * is essentially the buffer size used for IO, clients - * should pick a value that is appropriate for IO and - * memory performance requirements - * @param dyn_cont_zc callback to use to obtain response data - * @param dyn_cont_zc_cls extra argument to @a crc - * @param dyn_cont_zc_fc callback to call to free @a dyn_cont_zc_cls resources - * @return NULL on error (i.e. invalid arguments, out of memory) - * @ingroup response - */ -_MHD_EXTERN struct MHD_Response * -MHD_response_from_callback_zc (enum MHD_HTTP_StatusCode sc, - uint64_t size, - MHD_DynamicContentCreatorZC dyn_cont_zc, - void *dyn_cont_zc_cls, - MHD_FreeCallback dyn_cont_zc_fc); - -// FIXME: alt version -#ifdef ORIG_VERSION -/** - * Specification for how MHD should treat the memory buffer - * given for the response. - * @ingroup response - */ -enum MHD_ResponseMemoryMode -{ - - /** - * Buffer is a persistent (static/global) buffer that won't change - * for at least the lifetime of the response, MHD should just use - * it, not free it, not copy it, just keep an alias to it. - * @ingroup response - */ - MHD_RESPMEM_PERSISTENT = 0, - - /** - * Buffer is in transient memory, but not on the heap (for example, - * on the stack or non-`malloc()` allocated) and only valid during the - * call to #MHD_create_response_from_buffer. MHD must make its - * own private copy of the data for processing. - * @ingroup response - */ - MHD_RESPMEM_MUST_COPY = 1 - -}; - - -/** - * Create a response object. The response object can be extended with - * header information and then be used any number of times. - * - * @param sc status code to use for the response; - * #MHD_HTTP_NO_CONTENT is only valid if @a size is 0; - * @param size size of the data portion of the response - * @param buffer size bytes containing the response's data portion - * @param mode flags for buffer management + * @param dyn_cont callback to use to obtain response data + * @param dyn_cont_cls extra argument to @a crc + * @param dyn_cont_fc callback to call to free @a dyn_cont_cls resources * @return NULL on error (i.e. invalid arguments, out of memory) * @ingroup response */ -_MHD_EXTERN struct MHD_Response * -MHD_response_from_buffer (enum MHD_HTTP_StatusCode sc, - size_t buffer_size, - const char buffer[MHD_C99_ (static buffer_size)], - enum MHD_ResponseMemoryMode mode); - -#else +MHD_EXTERN_ struct MHD_Response * +MHD_response_from_callback (enum MHD_HTTP_StatusCode sc, + uint_fast64_t size, + MHD_DynamicContentCreator dyn_cont, + void *dyn_cont_cls, + MHD_FreeCallback dyn_cont_fc); /** @@ -4842,25 +8389,37 @@ MHD_response_from_buffer (enum MHD_HTTP_StatusCode sc, * needs to be valid while the response is used * @param free_cb the callback to free any allocated data, called * when response is being destroyed, can be NULL - * to skip callback + * to skip the free/cleanup callback * @param free_cb_cls the parameter for @a free_cb * @return NULL on error (i.e. invalid arguments, out of memory) * @ingroup response */ -_MHD_EXTERN struct MHD_Response * -MHD_response_from_buffer (enum MHD_HTTP_StatusCode sc, - size_t buffer_size, - const char buffer[MHD_C99_ (static buffer_size)], - MHD_FreeCallback free_cb, - void *free_cb_cls); +MHD_EXTERN_ struct MHD_Response * +MHD_response_from_buffer ( + enum MHD_HTTP_StatusCode sc, + size_t buffer_size, + const char buffer[MHD_FN_PAR_DYN_ARR_SIZE_ (buffer_size)], + MHD_FreeCallback free_cb, + void *free_cb_cls) +MHD_FN_PAR_IN_SIZE_(3,2); + + +/** + * Create a response object with empty (zero size) body. + * + * The response object can be extended with header information and then be used + * any number of times. + * @param sc status code to use for the response + */ +#define MHD_response_from_empty(sc) \ + MHD_response_from_buffer (sc, 0, NULL, NULL, NULL) /** * Create a response object. The response object can be extended with * header information. * - * @param sc status code to use for the response; - * #MHD_HTTP_NO_CONTENT is only valid if @a size is 0; // FIXME: remove comment? Too many statuses without body + * @param sc status code to use for the response * @param size the size of the data portion of the response * @param buffer the @a size bytes containing the response's data portion, * an internal copy will be made, there is no need to @@ -4868,25 +8427,12 @@ MHD_response_from_buffer (enum MHD_HTTP_StatusCode sc, * @return NULL on error (i.e. invalid arguments, out of memory) * @ingroup response */ -_MHD_EXTERN struct MHD_Response * +MHD_EXTERN_ struct MHD_Response * MHD_response_from_buffer_copy ( enum MHD_HTTP_StatusCode sc, size_t buffer_size, - const char buffer[MHD_C99_ (static buffer_size)]); - -#endif - -/** - * Create a response object with empty (zero size) body. - * - * The response object can be extended with header information and then be used - * any number of times. - */ -#define MHD_response_from_empty(sc) \ - MHD_response_from_buffer (sc, \ - 0, \ - NULL, \ - MHD_RESPMEM_PERSISTENT) + const char buffer[MHD_FN_PAR_DYN_ARR_SIZE_ (buffer_size)]) +MHD_FN_PAR_IN_SIZE_(3,2); /** @@ -4908,11 +8454,11 @@ MHD_response_from_buffer_copy ( * @return NULL on error (i.e. invalid arguments, out of memory) * @ingroup response */ -_MHD_EXTERN struct MHD_Response * +MHD_EXTERN_ struct MHD_Response * MHD_response_from_iovec ( enum MHD_HTTP_StatusCode sc, unsigned int iov_count, - const struct MHD_IoVec iov[MHD_C99_ (iov_count)], + const struct MHD_IoVec iov[MHD_FN_PAR_DYN_ARR_SIZE_ (iov_count)], MHD_FreeCallback free_cb, void *free_cb_cls); @@ -4935,11 +8481,12 @@ MHD_response_from_iovec ( * @return NULL on error (i.e. invalid arguments, out of memory) * @ingroup response */ -_MHD_EXTERN struct MHD_Response * +MHD_EXTERN_ struct MHD_Response * MHD_response_from_fd (enum MHD_HTTP_StatusCode sc, int fd, - uint64_t offset, - uint64_t size); + uint_fast64_t offset, + uint_fast64_t size) +MHD_FN_PAR_FD_READ_(2); /** * Create a response object with the response body created by reading @@ -4958,12 +8505,11 @@ MHD_response_from_fd (enum MHD_HTTP_StatusCode sc, * @return NULL on error (i.e. invalid arguments, out of memory) * @ingroup response */ -_MHD_EXTERN struct MHD_Response * +MHD_EXTERN_ struct MHD_Response * MHD_response_from_pipe (enum MHD_HTTP_StatusCode sc, int fd); -// FIXME: corrected /** * Destroy response. * Should be called if response was created but not consumed. @@ -4975,183 +8521,73 @@ MHD_response_from_pipe (enum MHD_HTTP_StatusCode sc, * @param[in] response the response to destroy * @ingroup response */ -_MHD_EXTERN void +MHD_EXTERN_ void MHD_response_destroy (struct MHD_Response *response) -MHD_FUNC_PARAM_NONNULL_ (1); +MHD_FN_PAR_NONNULL_ (1); /** * Add a header line to the response. * * @param response response to add a header to - * @param header the header to add - * @param content value to add - * @return #MHD_NO on error (i.e. invalid header or content format), - * or out of memory + * @param name the name of the header to add, + * an internal copy of the string will be made + * @param value the value of the header to add, + * an internal copy of the string will be made + * @return #MHD_SC_OK on success, + * error code otherwise * @ingroup response */ -_MHD_EXTERN enum MHD_StatusCode +MHD_EXTERN_ enum MHD_StatusCode MHD_response_add_header (struct MHD_Response *response, - const char *header, - const char *content) -MHD_FUNC_PARAM_NONNULL_ (1) MHD_FUNC_PARAM_NONNULL_ (2) -MHD_FUNC_PARAM_NONNULL_ (3); + const char *name, + const char *value) +MHD_FN_PAR_NONNULL_ (1) +MHD_FN_PAR_NONNULL_ (2) MHD_FN_PAR_CSTR_(2) +MHD_FN_PAR_NONNULL_ (3) MHD_FN_PAR_CSTR_ (3); + -// FIXME: duplication - remove /** - * Add a header line to the response. - * - * This function uses application-provided length of string. When using - * large strings or many headers this case save some CPU cycles. + * Add a header with predefined (standard) name to the response. * * @param response response to add a header to - * @param header the header to add - * @param content value to add - * @return #MHD_NO on error (i.e. invalid header or content format), - * or out of memory + * @param stk the code of the predefined header + * @param value the value of the header to add, + * an internal copy of the string will be made + * @return #MHD_SC_OK on success, + * error code otherwise * @ingroup response */ -_MHD_EXTERN enum MHD_StatusCode -MHD_response_add_header_str (struct MHD_Response *response, - const struct MHD_String *header_str, - const struct MHD_String *content_str) -MHD_FUNC_PARAM_NONNULL_ (1) MHD_FUNC_PARAM_NONNULL_ (2) -MHD_FUNC_PARAM_NONNULL_ (3); - - -_MHD_EXTERN enum MHD_StatusCode +MHD_EXTERN_ enum MHD_StatusCode MHD_response_add_predef_header (struct MHD_Response *response, enum MHD_PredefinedHeader stk, const char *content) -MHD_FUNC_PARAM_NONNULL_ (1) MHD_FUNC_PARAM_NONNULL_ (3); - -// TODO remove -/** - * Delete a header (or footer) line from the response. - * - * @param[in,out] response response to remove a header from - * @param header the header to delete - * @param content value to delete - * @return #MHD_NO on error (no such header known) - * @ingroup response - */ -_MHD_EXTERN enum MHD_StatusCode -MHD_response_del_header (struct MHD_Response *response, - const char *header, - const char *content) -MHD_FUNC_PARAM_NONNULL_ (1,2,3); - - -/** - * Get all of the headers that were added to a response. - * - * @param response response to query - * @param iterator callback to call on each header; - * maybe NULL (then just count headers) - * @param iterator_cls extra argument to @a iterator - * @return number of entries iterated over - * @ingroup response - */ -_MHD_EXTERN unsigned int -MHD_response_get_headers (const struct MHD_Response *response, - MHD_KeyValueIterator iterator, - void *iterator_cls) -MHD_FUNC_PARAM_NONNULL_ (1); - - -/** - * Get a particular header from the response. Valid as - * long as the response is valid and the header is not - * explicitly deleted from the response. - * - * @param response response to query - * @param key which header to get - * @return NULL if header does not exist - * @ingroup response - */ -_MHD_EXTERN const struct MHD_String * -MHD_response_get_header (const struct MHD_Response *response, - const char *key) -MHD_FUNC_PARAM_NONNULL_ (1) MHD_FUNC_PARAM_NONNULL_ (2); - - -// FIXME: Removed trailer function, chunk ext - add -/** - * Add a tailer line to the response for this request. - * Usually called within a MHD_ContentReaderCallback. - * - * @param response response to add a footer to - * @param footer the footer to add - * @param content value to add - * @return #MHD_NO on error (i.e. invalid footer or content format), - * or out of memory - * @ingroup response - */ -_MHD_EXTERN enum MHD_Bool -MHD_request_set_response_trailer ( - struct MHD_Request *request, - const char *footer, - const char *content) -MHD_FUNC_PARAM_NONNULL_ (1,2,3); +MHD_FN_PAR_NONNULL_ (1) +MHD_FN_PAR_NONNULL_ (3) MHD_FN_PAR_CSTR_ (3); /* ************ (b) Upload and PostProcessor functions ********************** */ /** - * This function can be used to add an entry to the HTTP headers of a - * request (so that the #MHD_request_get_values function will - * return them -- and the `struct MHD_PostProcessor` will also see - * them). This maybe required in certain situations (see Mantis - * #1399) where (broken) HTTP implementations fail to supply values - * needed by the post processor (or other parts of the application). - * - * This function MUST only be called from within the - * request callbacks (otherwise, access maybe improperly - * synchronized). Furthermore, the client must guarantee that the key - * and value arguments are 0-terminated strings that are NOT freed - * until the connection is closed. (The easiest way to do this is by - * passing only arguments to permanently allocated strings.). - * - * @param[in,out] request the request for which a - * value should be set - * @param kind kind of the value - * @param key key for the value - * @param value the value itself - * @return #MHD_NO if the operation could not be - * performed due to insufficient memory; - * #MHD_YES on success - * @ingroup request - * - * FIXME: remove, instead fox PostProcessor API to allow application to provide value! - */ -_MHD_EXTERN enum MHD_Bool -MHD_request_set_value (struct MHD_Request *request, - enum MHD_ValueKind kind, - const char *key, - const char *value) -MHD_FUNC_PARAM_NONNULL_ (1,3,4); - - -/** * Action telling MHD to continue processing the upload. * + * @param req the request to make an action * @return action operation, never NULL */ -_MHD_EXTERN const struct MHD_Action * -MHD_action_continue (void); +MHD_EXTERN_ const struct MHD_Action * +MHD_action_continue (struct MHD_Request *req); /** * Action telling MHD to close the connection hard * (kind-of breaking HTTP specification). * - * FIXME: Note: equvalent to returning MHD_NO before! - * - * @return action operation, always NULL ? :-) + * @param req the request to make an action + * @return action operation, always NULL */ -#define MHD_action_close_connection() \ - ((const struct MHD_Action *) NULL) +#define MHD_action_close_connection(req) \ + MHD_STATIC_CAST_(const struct MHD_Action *, NULL) /** @@ -5159,34 +8595,22 @@ MHD_action_continue (void); * * @param cls argument given together with the function * pointer when the handler was registered with MHD - * @param path the requested uri (without arguments after "?") - * @param method the HTTP method used (#MHD_HTTP_METHOD_GET, - * #MHD_HTTP_METHOD_PUT, etc.) - * @param content_total_size the size of the message content payload, - * #MHD_SIZE_UNKNOWN for chunked uploads - * when the final chunk has not been - * processed yet. - * @param uploaded_content_size the size of already uploaded - * content in @a content_data + * @param request the request is being processed + * @param content_data_size the size of the @a content_data, + * zero if all data have been processed * @param[in] content_data the uploaded content data, - * may be modified in ..... - * must not be freed - * NULL if no content has been - * processed yet, - * not NULL if any content has been - * processed even if content is - * zero size - * @param content_processed_size the size of previously provided and - * processes content data + * may be modified in the callback, + * valid only until return from the callback, + * NULL is all data have been processed * @return action specifying how to proceed, often * #MHD_action_continue() if all is well, * #MHD_action_suspend() to stop reading the upload until * the request is resumed, - * NULL to close the socket, or a response + * MHD_action_close_connection to close the socket, or a response * to discard the rest of the upload and return the data given */ typedef const struct MHD_Action * -(MHD_FUNC_PARAM_NONNULL_ (2) MHD_FUNC_PARAM_NONNULL_ (3) +(MHD_FN_PAR_NONNULL_ (2) MHD_FN_PAR_NONNULL_ (3) *MHD_UploadCallback)(void *upload_cls, struct MHD_Request *request, size_t content_data_size, @@ -5196,27 +8620,65 @@ typedef const struct MHD_Action * /** * Create an action that handles an upload. * - * @param uc function to call with uploaded data - * @param uc_cls closure for @a uc - * @param upload_buffer_size how large should the - * upload buffer be. Use 0 for stream processing using - * the normal memory pool. May allocate memory from - * the large memory pool if necessary and non-zero is given. - * @param call_when_full only call @a uc when the buffer is full - * (or the upload is complete); otherwise call as soon - * as data is available - * @return NULL on error (out of memory) + * If @a uc_inc is NULL and upload cannot fit the allocated buffer + * then request is aborted without response. + * + * @param request the request to create action for + * @param upload_buffer_size how large should the upload buffer be. + * May allocate memory from the shared "large" + * memory pool if necessary and non-zero is given. + * Must be zero if @a uc_full is NULL. + * @param uc_full the function to call when complete upload + * is received (only if fit @a upload_buffer_size), + * can be NULL if uc_inc is not NULL, + * must be NULL is @a upload_buffer_size is zero. + * @param uc_full_cls closure for @a uc_full + * @param uc_inc the function to incrementally process the upload data + * if the upload if larger than @a upload_buffer_size or + * @a upload_buffer_size cannot be allocated or + * @a uc_full is NULL, + * can be NULL if uc_full is not NULL + * @param uc_inc_cls closure for @a uc_inc + * @return NULL on error (out of memory. both @a uc_full and @a uc_inc are NULL) + * @sa #MHD_D_OPTION_LARGE_POOL_SIZE() * @ingroup action */ -_MHD_EXTERN const struct MHD_Action * +MHD_EXTERN_ const struct MHD_Action * MHD_action_process_upload ( - // ?? ugly, how to avoid alloc otherwise?? struct MHD_Request *request, size_t upload_buffer_size, - bool call_when_full, - MHD_UploadCallback uc, - void *uc_cls) -MHD_FUNC_PARAM_NONNULL_ (1); + MHD_UploadCallback uc_full, + void *uc_full_cls, + MHD_UploadCallback uc_inc, + void *uc_inc_cls) +MHD_FN_PAR_NONNULL_ (1); + +/** + * Create an action that handles an upload as full upload data. + * + * @param request the request to create action for + * @param buff_size how large should the upload buffer be. May allocate memory + * from the large memory pool if necessary. Must not be zero. + * @param uc the function to call when complete upload + * is received (only if fit @a upload_buffer_size) + * @param uc_cls closure for @a uc + * @return NULL on error (out of memory. both @a uc_full and @a uc_inc are NULL) + * @ingroup action + */ +#define MHD_action_process_upload_full(req,buff_size,uc,uc_cls) \ + MHD_action_process_upload(req, buff_size, uc, uc_cls, NULL, NULL) + +/** + * Create an action that handles an upload incrementally. + * + * @param request the request to create action for + * @param uc the function to incrementally process the upload data + * @param uc_cls closure for @a uc + * @return NULL on error (out of memory. both @a uc_full and @a uc_inc are NULL) + * @ingroup action + */ +#define MHD_action_process_upload_inc(req,uc,uc_cls) \ + MHD_action_process_upload(req, 0, NULL, NULL, uc, uc_cls) /** @@ -5226,12 +8688,13 @@ MHD_FUNC_PARAM_NONNULL_ (1); * requests, use #MHD_action_process_upload() instead. * * @param cls user-specified closure - * @param key 0-terminated key for the value + * @param name 0-terminated key for the value * @param filename name of the uploaded file, NULL if not known * @param content_type mime-type of the data, NULL if not known - * @param transfer_encoding encoding of the data, NULL if not known + * @param encoding the encoding of the data * @param data pointer to @a size bytes of data at the - * specified offset + * specified @a off offset, + * NOT zero-terminated * @param off offset of data in the overall value * @param size number of bytes in @a data available * @return action specifying how to proceed, often @@ -5242,52 +8705,153 @@ MHD_FUNC_PARAM_NONNULL_ (1); * to discard the rest of the upload and return the data given */ typedef const struct MHD_Action * -(*MHD_PostDataIterator) (void *cls, - const struct MHD_String *key, - const struct MHD_String *filename, - const struct MHD_String *content_type, - const struct MHD_String *transfer_encoding, - const struct MHD_String *data, - uint64_t off, - size_t size); +(*MHD_PostDataReader) (struct MHD_Request *req, + void *cls, + const struct MHD_String *name, + const struct MHD_String *filename, + const struct MHD_String *content_type, + const struct MHD_String *encoding, + const void *data, + uint_fast64_t off, + size_t size); +/** + * The callback to be called when finished with processing + * of the postprocessor upload data. + * @param req the request + * @param cls the closure + * @return the action to proceed + */ typedef const struct MHD_Action * -(*MHD_PostDataFinished) (void *cls); +(*MHD_PostDataFinished) (struct MHD_Request *req, + void *cls); /** * @param pp_buffer_size how much data should the post processor + * buffer in memory. May allocate memory from + * the shared "large" memory pool if necessary. + * @param pp_buffer_size how much data should the post processor * buffer in memory * @param pp_stream_limit values above which length should be * given to @a iter for stream processing - * @param iter function to call for "oversize" values in the stream, - * can be NULL - * @param iter_cls closure for @a iter + * @param enc the data encoding to use, + * set to #MHD_HTTP_POST_ENCODING_OTHER to detect automatically + * @param reader function to call for "oversize" values in the stream, + * can be NULL + * @param reader_cls closure for @a reader * @param done_cb called once all data has been processed for * the final action; values smaller than @a pp_stream_limit that * fit into @a pp_buffer_size will be available via - * MHD_request_get_post_processor_value() + * #MHD_request_get_values_cb(), #MHD_request_get_values_list() and + * #MHD_request_get_post_processor_values() + * @sa #MHD_D_OPTION_LARGE_POOL_SIZE() */ -_MHD_EXTERN struct MHD_Action * +MHD_EXTERN_ struct MHD_Action * MHD_action_post_processor (struct MHD_Request *req, size_t pp_buffer_size, size_t pp_stream_limit, - MHD_PostDataIterator iter, - void *iter_cls, + enum MHD_HTTP_PostEncoding enc, + MHD_PostDataReader reader, + void *reader_cls, MHD_PostDataFinished done_cb, void *done_cb_cls) -MHD_FUNC_PARAM_NONNULL_ (2); +MHD_FN_PAR_NONNULL_ (2); + + +/** + * Post data element. + * If any member is not provided/set then pointer to C string is NULL. + * If any member is set to empty string then pointer to C string not NULL, + * but the length is zero. + */ +struct MHD_PostData +{ + /** + * The name of the field + */ + struct MHD_String name; + /** + * The filename if provided (only for "multipart/form-data") + * If not set or defined then to C string is NULL. + * If set to empty string then pointer to C string not NULL, + */ + struct MHD_StringNullable filename; + /** + * The Content-Type if provided (only for "multipart/form-data") + * If not set or defined then to C string is NULL. + * If set to empty string then pointer to C string not NULL, + */ + struct MHD_StringNullable content_type; + /** + * The Transfer-Encoding if provided (only for "multipart/form-data") + * If not set or defined then to C string is NULL. + * If set to empty string then pointer to C string not NULL, + */ + struct MHD_StringNullable transfer_encoding; + /** + * The field data + * If not set or defined then to C string is NULL. + * If set to empty string then pointer to C string not NULL, + */ + struct MHD_StringNullable value; +}; +/** + * Iterator over POST data. + * + * The pointers to the strings in @a data are valid until the response + * is queued. If the data is needed beyond this point, it should be copied. + * + * @param cls closure + * @param nvt the name, the value and the kind of the element + * @return #MHD_YES to continue iterating, + * #MHD_NO to abort the iteration + * @ingroup request + */ +typedef enum MHD_Bool +(MHD_FN_PAR_NONNULL_ (2) + *MHD_PostDataIterator)(void *cls, + const struct MHD_PostData *data); -// @a kind can be filename, content_type, transfer_encoding or (raw) data -// NULL if key not found or PP not used. -_MHD_EXTERN const struct MHD_String * -MHD_request_get_post_processor_value (struct MHD_Request *req, - enum MHD_ValueKind kind, - const char *key) -MHD_FUNC_PARAM_NONNULL_ (2); +/** + * Get all of the post data from the request via request. + * + * The pointers to the strings in @a elements are valid until the response + * is queued. If the data is needed beyond this point, it should be copied. + * @param request the request to get data for + * @param iterator callback to call on each header; + * maybe NULL (then just count headers) + * @param iterator_cls extra argument to @a iterator + * @return number of entries iterated over + * @ingroup request + */ +MHD_EXTERN_ size_t +MHD_request_get_post_data_cb (struct MHD_Request *request, + MHD_PostDataIterator iterator, + void *iterator_cls) +MHD_FN_PAR_NONNULL_ (1); +/** + * Get all of the post data from the request. + * + * The pointers to the strings in @a elements are valid until the response + * is queued. If the data is needed beyond this point, it should be copied. + * @param request the request to get data for + * @param num_elements the number of elements in @a elements array + * @param[out] elements the array of @a num_elements to get the data + * @return the number of elements stored in @a elements, + * zero if no data or postprocessor was not used. + * @ingroup request + */ +MHD_EXTERN_ size_t +MHD_request_get_post_data_list ( + struct MHD_Request *request, + size_t num_elements, + struct MHD_PostData elements[MHD_FN_PAR_DYN_ARR_SIZE_ (num_elements)]) +MHD_FN_PAR_NONNULL_ (1) +MHD_FN_PAR_NONNULL_ (3) MHD_FN_PAR_OUT_ (3); /* ***************** (c) WebSocket support ********** */ @@ -5297,16 +8861,32 @@ MHD_FUNC_PARAM_NONNULL_ (2); * the final set of actions is yet to be decided. This is just an * idea for what we might want. */ -enum MHD_UpgradeOperation +enum MHD_FIXED_ENUM_APP_SET_ MHD_UpgradeOperation { /** * Close the socket, the application is done with it. - * - * Takes no extra arguments. */ MHD_UPGRADE_OPERATION_CLOSE = 0 + , + /** + * Turn on flushing the network buffers after each data piece. + */ + MHD_UPGRADE_OPERATION_DISABLE_NETWORK_BUFFERING = 1 + , + /** + * Turn on normal data buffering (default). + */ + MHD_UPGRADE_OPERATION_ENABLE_NETWORK_BUFFERING = 2 + , + /* * Sentinel * */ + /** + * The sentinel value. + * This value enforces specific underlying integer type for the enum. + * Do not use. + */ + MHD_UPGRADE_OPERATION_SENTINEL = 65535 }; @@ -5315,8 +8895,7 @@ enum MHD_UpgradeOperation * actions relating to MHD responses that "upgrade" * the HTTP protocol (i.e. to WebSockets). */ -struct MHD_UpgradeResponseHandle; - +struct MHD_UpgradeHandle; /** * This connection-specific callback is provided by MHD to @@ -5324,20 +8903,16 @@ struct MHD_UpgradeResponseHandle; * It allows applications to perform 'special' actions on * the underlying socket from the upgrade. * - * FIXME: this API still uses the untyped, ugly varargs. - * Should we not modernize this one as well? - * * @param urh the handle identifying the connection to perform * the upgrade @a action on. * @param operation which operation should be performed * @param ... arguments to the action (depends on the action) * @return #MHD_NO on error, #MHD_YES on success */ -_MHD_EXTERN struct MHD_Action *// ??? -MHD_upgrade_operation (struct MHD_UpgradeResponseHandle *urh, - enum MHD_UpgradeOperation operation, - ...) -MHD_FUNC_PARAM_NONNULL_ (1); +MHD_EXTERN_ enum MHD_StatusCode +MHD_upgrade_operation (struct MHD_UpgradeHandle *urh, + enum MHD_UpgradeOperation operation) +MHD_FN_PAR_NONNULL_ (1); /** @@ -5383,29 +8958,26 @@ MHD_FUNC_PARAM_NONNULL_ (1); * to perform read()/recv() and write()/send() calls on the socket. * The application may also call shutdown(), but must not call * close() directly. - * @param urh argument for #MHD_upgrade_action()s on this @a connection. + * @param urh argument for #MHD_upgrade_action()s on this @a respose. * Applications must eventually use this callback to (indirectly) * perform the close() action on the @a sock. */ typedef void (*MHD_UpgradeHandler)(void *cls, - struct MHD_Connection *connection, - void *req_cls, - const char *extra_in, + struct MHD_Request *request, size_t extra_in_size, + const char *extra_in, MHD_socket sock, - struct MHD_UpgradeResponseHandle *urh); + struct MHD_UpgradeHandle *urh); /** - * Create a response object that can be used for 101 UPGRADE + * Create a action object that can be used for 101 UPGRADE * responses, for example to implement WebSockets. After sending the * response, control over the data stream is given to the callback (which * can then, for example, start some bi-directional communication). - * If the response is queued for multiple connections, the callback - * will be called for each connection. The callback - * will ONLY be called after the response header was successfully passed - * to the OS; if there are communication errors before, the usual MHD + * The callback will ONLY be called after the response header was successfully + * passed to the OS; if there are communication errors before, the usual MHD * connection error handling code will be performed. * * MHD will automatically set the correct HTTP status @@ -5413,24 +8985,30 @@ typedef void * Setting correct HTTP headers for the upgrade must be done * manually (this way, it is possible to implement most existing * WebSocket versions using this API; in fact, this API might be useful - * for any protocol switch, not just WebSockets). Note that - * draft-ietf-hybi-thewebsocketprotocol-00 cannot be implemented this - * way as the header "HTTP/1.1 101 WebSocket Protocol Handshake" - * cannot be generated; instead, MHD will always produce "HTTP/1.1 101 - * Switching Protocols" (if the response code 101 is used). + * for any protocol switch, not just WebSockets). * * As usual, the response object can be extended with header * information and then be used any number of times (as long as the * header information is not connection-specific). * + * @param request the request to create action for * @param upgrade_handler function to call with the "upgraded" socket * @param upgrade_handler_cls closure for @a upgrade_handler + * @param num_headers number of elements in the @a headers array, + * must be zero if @a headers is NULL + * @param headers the optional pointer to the array of the headers (the strings + * are copied and does not need to be valid after return from + * this function), + * can be NULL if @a num_headers is zero * @return NULL on error (i.e. invalid arguments, out of memory) */ -_MHD_EXTERN struct MHD_Response * -MHD_response_for_upgrade (MHD_UpgradeHandler upgrade_handler, - void *upgrade_handler_cls) -MHD_FUNC_PARAM_NONNULL_ (1); +MHD_EXTERN_ struct MHD_Action * +MHD_action_upgrade (struct MHD_Request *request, + MHD_UpgradeHandler upgrade_handler, + void *upgrade_handler_cls, + size_t num_headers, + const struct MHD_NameValueCStr *headers) +MHD_FN_PAR_NONNULL_ (1); /* ********************** (e) Client auth ********************** */ @@ -5455,25 +9033,23 @@ MHD_FUNC_PARAM_NONNULL_ (1); * @warning While this value is the same as the #MHD_SHA256_DIGEST_SIZE, * the calculated digests for SHA-256 and SHA-512/256 are different. * @sa #MHD_digest_get_hash_size() - * @note Available since #MHD_VERSION 0x00097701 * @ingroup authentication */ #define MHD_SHA512_256_DIGEST_SIZE 32 /** * Base type of hash calculation. - * Used as part of #MHD_DigestAuthAlgo3 values. + * Used as part of #MHD_DigestAuthAlgo values. * * @warning Not used directly by MHD API. - * @note Available since #MHD_VERSION 0x00097701 */ -enum MHD_DigestBaseAlgo +enum MHD_FIXED_ENUM_MHD_APP_SET_ MHD_DigestBaseAlgo { /** * Invalid hash algorithm value */ - MHD_DIGEST_BASE_ALGO_INVALID = 0, - + MHD_DIGEST_BASE_ALGO_INVALID = 0 + , /** * MD5 hash algorithm. * As specified by RFC1321 @@ -5491,75 +9067,70 @@ enum MHD_DigestBaseAlgo * As specified by FIPS PUB 180-4 */ MHD_DIGEST_BASE_ALGO_SHA512_256 = (1 << 2) -} _MHD_FIXED_FLAGS_ENUM; +}; /** * The flag indicating non-session algorithm types, * like 'MD5', 'SHA-256' or 'SHA-512-256'. - * @note Available since #MHD_VERSION 0x00097701 */ -#define MHD_DIGEST_AUTH_ALGO3_NON_SESSION (1 << 6) +#define MHD_DIGEST_AUTH_ALGO_NON_SESSION (1 << 6) /** * The flag indicating session algorithm types, * like 'MD5-sess', 'SHA-256-sess' or 'SHA-512-256-sess'. - * @note Available since #MHD_VERSION 0x00097701 */ -#define MHD_DIGEST_AUTH_ALGO3_SESSION (1 << 7) +#define MHD_DIGEST_AUTH_ALGO_SESSION (1 << 7) /** * Digest algorithm identification - * @warning Do not be confused with #MHD_DigestAuthAlgorithm, - * which uses other values! - * @note Available since #MHD_VERSION 0x00097701 */ -enum MHD_DigestAuthAlgo3 +enum MHD_FIXED_ENUM_MHD_APP_SET_ MHD_DigestAuthAlgo { /** * Unknown or wrong algorithm type. * Used in struct MHD_DigestAuthInfo to indicate client value that * cannot by identified. */ - MHD_DIGEST_AUTH_ALGO3_INVALID = 0, - + MHD_DIGEST_AUTH_ALGO_INVALID = 0 + , /** * The 'MD5' algorithm, non-session version. */ - MHD_DIGEST_AUTH_ALGO3_MD5 = - MHD_DIGEST_BASE_ALGO_MD5 | MHD_DIGEST_AUTH_ALGO3_NON_SESSION, + MHD_DIGEST_AUTH_ALGO_MD5 = + MHD_DIGEST_BASE_ALGO_MD5 | MHD_DIGEST_AUTH_ALGO_NON_SESSION, /** * The 'MD5-sess' algorithm. * Not supported by MHD for authentication. */ - MHD_DIGEST_AUTH_ALGO3_MD5_SESSION = - MHD_DIGEST_BASE_ALGO_MD5 | MHD_DIGEST_AUTH_ALGO3_SESSION, + MHD_DIGEST_AUTH_ALGO_MD5_SESSION = + MHD_DIGEST_BASE_ALGO_MD5 | MHD_DIGEST_AUTH_ALGO_SESSION, /** * The 'SHA-256' algorithm, non-session version. */ - MHD_DIGEST_AUTH_ALGO3_SHA256 = - MHD_DIGEST_BASE_ALGO_SHA256 | MHD_DIGEST_AUTH_ALGO3_NON_SESSION, + MHD_DIGEST_AUTH_ALGO_SHA256 = + MHD_DIGEST_BASE_ALGO_SHA256 | MHD_DIGEST_AUTH_ALGO_NON_SESSION, /** * The 'SHA-256-sess' algorithm. * Not supported by MHD for authentication. */ - MHD_DIGEST_AUTH_ALGO3_SHA256_SESSION = - MHD_DIGEST_BASE_ALGO_SHA256 | MHD_DIGEST_AUTH_ALGO3_SESSION, + MHD_DIGEST_AUTH_ALGO_SHA256_SESSION = + MHD_DIGEST_BASE_ALGO_SHA256 | MHD_DIGEST_AUTH_ALGO_SESSION, /** * The 'SHA-512-256' (SHA-512/256) algorithm. */ - MHD_DIGEST_AUTH_ALGO3_SHA512_256 = - MHD_DIGEST_BASE_ALGO_SHA512_256 | MHD_DIGEST_AUTH_ALGO3_NON_SESSION, + MHD_DIGEST_AUTH_ALGO_SHA512_256 = + MHD_DIGEST_BASE_ALGO_SHA512_256 | MHD_DIGEST_AUTH_ALGO_NON_SESSION, /** * The 'SHA-512-256-sess' (SHA-512/256 session) algorithm. * Not supported by MHD for authentication. */ - MHD_DIGEST_AUTH_ALGO3_SHA512_256_SESSION = - MHD_DIGEST_BASE_ALGO_SHA512_256 | MHD_DIGEST_AUTH_ALGO3_SESSION + MHD_DIGEST_AUTH_ALGO_SHA512_256_SESSION = + MHD_DIGEST_BASE_ALGO_SHA512_256 | MHD_DIGEST_AUTH_ALGO_SESSION }; @@ -5568,138 +9139,136 @@ enum MHD_DigestAuthAlgo3 * * The size of the digest specifies the size of the userhash, userdigest * and other parameters which size depends on used hash algorithm. - * @param algo3 the algorithm to check + * @param algo the algorithm to check * @return the size of the digest (either #MHD_MD5_DIGEST_SIZE or * #MHD_SHA256_DIGEST_SIZE/MHD_SHA512_256_DIGEST_SIZE) * or zero if the input value is not supported or not valid * @sa #MHD_digest_auth_calc_userdigest() * @sa #MHD_digest_auth_calc_userhash(), #MHD_digest_auth_calc_userhash_hex() - * @note Available since #MHD_VERSION 0x00097701 * @ingroup authentication */ -_MHD_EXTERN size_t -MHD_digest_get_hash_size (enum MHD_DigestAuthAlgo3 algo3); +MHD_EXTERN_ size_t +MHD_digest_get_hash_size (enum MHD_DigestAuthAlgo algo) +MHD_FN_CONST_; /** * Digest algorithm identification, allow multiple selection. * - * #MHD_DigestAuthAlgo3 always can be casted to #MHD_DigestAuthMultiAlgo3, but + * #MHD_DigestAuthAlgo always can be casted to #MHD_DigestAuthMultiAlgo, but * not vice versa. - * - * @note Available since #MHD_VERSION 0x00097701 */ -enum MHD_DigestAuthMultiAlgo3 +enum MHD_FIXED_ENUM_MHD_APP_SET_ MHD_DigestAuthMultiAlgo { /** * Unknown or wrong algorithm type. */ - MHD_DIGEST_AUTH_MULT_ALGO3_INVALID = MHD_DIGEST_AUTH_ALGO3_INVALID, + MHD_DIGEST_AUTH_MULT_ALGO_INVALID = MHD_DIGEST_AUTH_ALGO_INVALID, /** * The 'MD5' algorithm, non-session version. */ - MHD_DIGEST_AUTH_MULT_ALGO3_MD5 = MHD_DIGEST_AUTH_ALGO3_MD5, + MHD_DIGEST_AUTH_MULT_ALGO_MD5 = MHD_DIGEST_AUTH_ALGO_MD5, /** * The 'MD5-sess' algorithm. * Not supported by MHD for authentication. * Reserved value. */ - MHD_DIGEST_AUTH_MULT_ALGO3_MD5_SESSION = MHD_DIGEST_AUTH_ALGO3_MD5_SESSION, + MHD_DIGEST_AUTH_MULT_ALGO_MD5_SESSION = MHD_DIGEST_AUTH_ALGO_MD5_SESSION, /** * The 'SHA-256' algorithm, non-session version. */ - MHD_DIGEST_AUTH_MULT_ALGO3_SHA256 = MHD_DIGEST_AUTH_ALGO3_SHA256, + MHD_DIGEST_AUTH_MULT_ALGO_SHA256 = MHD_DIGEST_AUTH_ALGO_SHA256, /** * The 'SHA-256-sess' algorithm. * Not supported by MHD for authentication. * Reserved value. */ - MHD_DIGEST_AUTH_MULT_ALGO3_SHA256_SESSION = - MHD_DIGEST_AUTH_ALGO3_SHA256_SESSION, + MHD_DIGEST_AUTH_MULT_ALGO_SHA256_SESSION = + MHD_DIGEST_AUTH_ALGO_SHA256_SESSION, /** * The 'SHA-512-256' (SHA-512/256) algorithm, non-session version. */ - MHD_DIGEST_AUTH_MULT_ALGO3_SHA512_256 = MHD_DIGEST_AUTH_ALGO3_SHA512_256, + MHD_DIGEST_AUTH_MULT_ALGO_SHA512_256 = MHD_DIGEST_AUTH_ALGO_SHA512_256, /** * The 'SHA-512-256-sess' (SHA-512/256 session) algorithm. * Not supported by MHD for authentication. * Reserved value. */ - MHD_DIGEST_AUTH_MULT_ALGO3_SHA512_256_SESSION = - MHD_DIGEST_AUTH_ALGO3_SHA512_256_SESSION, + MHD_DIGEST_AUTH_MULT_ALGO_SHA512_256_SESSION = + MHD_DIGEST_AUTH_ALGO_SHA512_256_SESSION, /** * SHA-256 or SHA-512/256 non-session algorithm, MHD will choose * the preferred or the matching one. */ - MHD_DIGEST_AUTH_MULT_ALGO3_SHA_ANY_NON_SESSION = - MHD_DIGEST_AUTH_ALGO3_SHA256 | MHD_DIGEST_AUTH_ALGO3_SHA512_256, + MHD_DIGEST_AUTH_MULT_ALGO_SHA_ANY_NON_SESSION = + MHD_DIGEST_AUTH_ALGO_SHA256 | MHD_DIGEST_AUTH_ALGO_SHA512_256, /** * Any non-session algorithm, MHD will choose the preferred or * the matching one. */ - MHD_DIGEST_AUTH_MULT_ALGO3_ANY_NON_SESSION = - (0x3F) | MHD_DIGEST_AUTH_ALGO3_NON_SESSION, + MHD_DIGEST_AUTH_MULT_ALGO_ANY_NON_SESSION = + (0x3F) | MHD_DIGEST_AUTH_ALGO_NON_SESSION, /** * The SHA-256 or SHA-512/256 session algorithm. * Not supported by MHD. * Reserved value. */ - MHD_DIGEST_AUTH_MULT_ALGO3_SHA_ANY_SESSION = - MHD_DIGEST_AUTH_ALGO3_SHA256_SESSION - | MHD_DIGEST_AUTH_ALGO3_SHA512_256_SESSION, + MHD_DIGEST_AUTH_MULT_ALGO_SHA_ANY_SESSION = + MHD_DIGEST_AUTH_ALGO_SHA256_SESSION + | MHD_DIGEST_AUTH_ALGO_SHA512_256_SESSION, /** * Any session algorithm. * Not supported by MHD. * Reserved value. */ - MHD_DIGEST_AUTH_MULT_ALGO3_ANY_SESSION = - (0x3F) | MHD_DIGEST_AUTH_ALGO3_SESSION, + MHD_DIGEST_AUTH_MULT_ALGO_ANY_SESSION = + (0x3F) | MHD_DIGEST_AUTH_ALGO_SESSION, /** * The MD5 algorithm, session or non-session. * Currently supported as non-session only. */ - MHD_DIGEST_AUTH_MULT_ALGO3_MD5_ANY = - MHD_DIGEST_AUTH_MULT_ALGO3_MD5 | MHD_DIGEST_AUTH_MULT_ALGO3_MD5_SESSION, + MHD_DIGEST_AUTH_MULT_ALGO_MD5_ANY = + MHD_DIGEST_AUTH_MULT_ALGO_MD5 | MHD_DIGEST_AUTH_MULT_ALGO_MD5_SESSION, /** * The SHA-256 algorithm, session or non-session. * Currently supported as non-session only. */ - MHD_DIGEST_AUTH_MULT_ALGO3_SHA256_ANY = - MHD_DIGEST_AUTH_MULT_ALGO3_SHA256 - | MHD_DIGEST_AUTH_MULT_ALGO3_SHA256_SESSION, + MHD_DIGEST_AUTH_MULT_ALGO_SHA256_ANY = + MHD_DIGEST_AUTH_MULT_ALGO_SHA256 + | MHD_DIGEST_AUTH_MULT_ALGO_SHA256_SESSION, /** * The SHA-512/256 algorithm, session or non-session. * Currently supported as non-session only. */ - MHD_DIGEST_AUTH_MULT_ALGO3_SHA512_256_ANY = - MHD_DIGEST_AUTH_MULT_ALGO3_SHA512_256 - | MHD_DIGEST_AUTH_MULT_ALGO3_SHA512_256_SESSION, + MHD_DIGEST_AUTH_MULT_ALGO_SHA512_256_ANY = + MHD_DIGEST_AUTH_MULT_ALGO_SHA512_256 + | MHD_DIGEST_AUTH_MULT_ALGO_SHA512_256_SESSION, /** * The SHA-256 or SHA-512/256 algorithm, session or non-session. * Currently supported as non-session only. */ - MHD_DIGEST_AUTH_MULT_ALGO3_SHA_ANY_ANY = - MHD_DIGEST_AUTH_MULT_ALGO3_SHA_ANY_NON_SESSION - | MHD_DIGEST_AUTH_MULT_ALGO3_SHA_ANY_SESSION, + MHD_DIGEST_AUTH_MULT_ALGO_SHA_ANY_ANY = + MHD_DIGEST_AUTH_MULT_ALGO_SHA_ANY_NON_SESSION + | MHD_DIGEST_AUTH_MULT_ALGO_SHA_ANY_SESSION, /** * Any algorithm, MHD will choose the preferred or the matching one. */ - MHD_DIGEST_AUTH_MULT_ALGO3_ANY = - (0x3F) | MHD_DIGEST_AUTH_ALGO3_NON_SESSION | MHD_DIGEST_AUTH_ALGO3_SESSION + MHD_DIGEST_AUTH_MULT_ALGO_ANY = + (0x3F) | MHD_DIGEST_AUTH_ALGO_NON_SESSION | MHD_DIGEST_AUTH_ALGO_SESSION }; @@ -5726,29 +9295,30 @@ enum MHD_DigestAuthMultiAlgo3 * combination as it will cause excessive CPU load; save and re-use the result * instead. * - * @param algo3 the algorithm for userhash calculations + * @param algo the algorithm for userhash calculations * @param username the username * @param realm the realm * @param[out] userhash_bin the output buffer for userhash as binary data; * if this function succeeds, then this buffer has - * #MHD_digest_get_hash_size(algo3) bytes of userhash + * #MHD_digest_get_hash_size(algo) bytes of userhash * upon return * @param bin_buf_size the size of the @a userhash_bin buffer, must be - * at least #MHD_digest_get_hash_size(algo3) bytes long - * @return MHD_YES on success, - * MHD_NO if @a bin_buf_size is too small or if @a algo3 algorithm is - * not supported (or external error has occurred, - * see #MHD_FEATURE_EXTERN_HASH) + * at least #MHD_digest_get_hash_size(algo) bytes long + * @return MHD_SC_OK on success, + * error code otherwise * @sa #MHD_digest_auth_calc_userhash_hex() - * @note Available since #MHD_VERSION 0x00097701 * @ingroup authentication */ -_MHD_EXTERN enum MHD_Result -MHD_digest_auth_calc_userhash (enum MHD_DigestAuthAlgo3 algo3, +MHD_EXTERN_ enum MHD_StatusCode +MHD_digest_auth_calc_userhash (enum MHD_DigestAuthAlgo algo, const char *username, const char *realm, - void *userhash_bin, - size_t bin_buf_size); + size_t bin_buf_size, + void *userhash_bin) +MHD_FN_PURE_ +MHD_FN_PAR_NONNULL_ALL_ +MHD_FN_PAR_CSTR_(2) MHD_FN_PAR_CSTR_(3) +MHD_FN_PAR_OUT_SIZE_ (4,3); /** @@ -5774,29 +9344,33 @@ MHD_digest_auth_calc_userhash (enum MHD_DigestAuthAlgo3 algo3, * combination as it will cause excessive CPU load; save and re-use the result * instead. * - * @param algo3 the algorithm for userhash calculations + * @param algo the algorithm for userhash calculations * @param username the username * @param realm the realm + * @param bin_buf_size the size of the @a userhash_bin buffer, must be + * at least #MHD_digest_get_hash_size(algo)*2+1 chars long * @param[out] userhash_hex the output buffer for userhash as hex string; * if this function succeeds, then this buffer has - * #MHD_digest_get_hash_size(algo3)*2 chars long + * #MHD_digest_get_hash_size(algo)*2 chars long * userhash zero-terminated string - * @param bin_buf_size the size of the @a userhash_bin buffer, must be - * at least #MHD_digest_get_hash_size(algo3)*2+1 chars long - * @return MHD_YES on success, - * MHD_NO if @a bin_buf_size is too small or if @a algo3 algorithm is - * not supported (or external error has occurred, - * see #MHD_FEATURE_EXTERN_HASH). + * @return MHD_SC_OK on success, + * error code otherwise * @sa #MHD_digest_auth_calc_userhash() * @note Available since #MHD_VERSION 0x00097701 * @ingroup authentication */ -_MHD_EXTERN enum MHD_Result -MHD_digest_auth_calc_userhash_hex (enum MHD_DigestAuthAlgo3 algo3, - const char *username, - const char *realm, - char *userhash_hex, - size_t hex_buf_size); +MHD_EXTERN_ enum MHD_StatusCode +MHD_digest_auth_calc_userhash_hex ( + enum MHD_DigestAuthAlgo algo, + const char *username, + const char *realm, + size_t hex_buf_size, + char userhash_hex[MHD_FN_PAR_DYN_ARR_SIZE_ (hex_buf_size)]) +MHD_FN_PURE_ +MHD_FN_PAR_NONNULL_ALL_ +MHD_FN_PAR_CSTR_(2) MHD_FN_PAR_CSTR_(3) +MHD_FN_PAR_OUT_SIZE_ (4,3); +; /** @@ -5810,17 +9384,15 @@ MHD_digest_auth_calc_userhash_hex (enum MHD_DigestAuthAlgo3 algo3, * provided in any form * * (value >= MHD_DIGEST_AUTH_UNAME_TYPE_STANDARD) is true if username is * provided in clear text (no userhash matching is needed) - * - * @note Available since #MHD_VERSION 0x00097701 */ -enum MHD_DigestAuthUsernameType +enum MHD_FIXED_ENUM_MHD_SET_ MHD_DigestAuthUsernameType { /** * No username parameter in in Digest Authorization header. * This should be treated as an error. */ - MHD_DIGEST_AUTH_UNAME_TYPE_MISSING = 0, - + MHD_DIGEST_AUTH_UNAME_TYPE_MISSING = 0 + , /** * The 'username' parameter is used to specify the username. */ @@ -5850,21 +9422,20 @@ enum MHD_DigestAuthUsernameType * * 'username' is not hexadecimal string, while 'userhash' set to 'true' */ MHD_DIGEST_AUTH_UNAME_TYPE_INVALID = (1 << 0) -} _MHD_FIXED_ENUM; +}; /** * The QOP ('quality of protection') types. - * @note Available since #MHD_VERSION 0x00097701 */ -enum MHD_DigestAuthQOP +enum MHD_FIXED_ENUM_MHD_APP_SET_ MHD_DigestAuthQOP { /** * Invalid/unknown QOP. * Used in struct MHD_DigestAuthInfo to indicate client value that * cannot by identified. */ - MHD_DIGEST_AUTH_QOP_INVALID = 0, - + MHD_DIGEST_AUTH_QOP_INVALID = 0 + , /** * No QOP parameter. * As described in old RFC 2069 original specification. @@ -5885,17 +9456,15 @@ enum MHD_DigestAuthQOP * Not supported by MHD for authentication. */ MHD_DIGEST_AUTH_QOP_AUTH_INT = 1 << 2 -} _MHD_FIXED_FLAGS_ENUM; +}; /** * The QOP ('quality of protection') types, multiple selection. * * #MHD_DigestAuthQOP always can be casted to #MHD_DigestAuthMultiQOP, but * not vice versa. - * - * @note Available since #MHD_VERSION 0x00097701 */ -enum MHD_DigestAuthMultiQOP +enum MHD_FIXED_ENUM_MHD_APP_SET_ MHD_DigestAuthMultiQOP { /** * Invalid/unknown QOP. @@ -5939,33 +9508,25 @@ enum MHD_DigestAuthMultiQOP */ MHD_DIGEST_AUTH_MULT_QOP_AUTH_ANY = MHD_DIGEST_AUTH_QOP_AUTH | MHD_DIGEST_AUTH_QOP_AUTH_INT -} _MHD_FIXED_ENUM; +}; /** * The invalid value of 'nc' parameter in client Digest Authorization header. - * @note Available since #MHD_VERSION 0x00097701 */ #define MHD_DIGEST_AUTH_INVALID_NC_VALUE (0) /** * Information from Digest Authorization client's header. * - * All buffers pointed by any struct members are freed when #MHD_free() is - * called for pointer to this structure. - * - * Application may modify buffers as needed until #MHD_free() is called for - * pointer to this structure - * @note Available since #MHD_VERSION 0x00097701 + * @see #MHD_REQUEST_INFO_DYNAMIC_DAUTH_REQ_INFO */ struct MHD_DigestAuthInfo { /** * The algorithm as defined by client. * Set automatically to MD5 if not specified by client. - * @warning Do not be confused with #MHD_DigestAuthAlgorithm, - * which uses other values! */ - enum MHD_DigestAuthAlgo3 algo3; + enum MHD_DigestAuthAlgo algo; /** * The type of username used by client. @@ -5978,45 +9539,26 @@ struct MHD_DigestAuthInfo * If extended notation is used, this string is pct-decoded string * with charset and language tag removed (i.e. it is original username * extracted from the extended notation). - * When userhash is used by the client, this member is NULL and + * When userhash is used by the client, the string pointer is NULL and * @a userhash_hex and @a userhash_bin are set. - * The buffer pointed by the @a username becomes invalid when the pointer - * to the structure is freed by #MHD_free(). */ - char *username; - - /** - * The length of the @a username. - * When the @a username is NULL, this member is always zero. - */ - size_t username_len; + struct MHD_StringNullable username; /** * The userhash string. * Valid only if username type is userhash. * This is unqoted string without decoding of the hexadecimal * digits (as provided by the client). - * The buffer pointed by the @a userhash_hex becomes invalid when the pointer - * to the structure is freed by #MHD_free(). * @sa #MHD_digest_auth_calc_userhash_hex() */ - char *userhash_hex; - - /** - * The length of the @a userhash_hex in characters. - * The valid size should be #MHD_digest_get_hash_size(algo3) * 2 characters. - * When the @a userhash_hex is NULL, this member is always zero. - */ - size_t userhash_hex_len; + struct MHD_StringNullable userhash_hex; /** * The userhash decoded to binary form. * Used only if username type is userhash, always NULL otherwise. - * When not NULL, this points to binary sequence @a userhash_hex_len /2 bytes + * When not NULL, this points to binary sequence @a userhash_bin_size bytes * long. - * The valid size should be #MHD_digest_get_hash_size(algo3) bytes. - * The buffer pointed by the @a userhash_bin becomes invalid when the pointer - * to the structure is freed by #MHD_free(). + * The valid size should be #MHD_digest_get_hash_size(algo) bytes. * @warning This is a binary data, no zero termination. * @warning To avoid buffer overruns, always check the size of the data before * use, because @a userhash_bin can point even to zero-sized @@ -6026,32 +9568,22 @@ struct MHD_DigestAuthInfo uint8_t *userhash_bin; /** - * The 'opaque' parameter value, as specified by client. - * NULL if not specified by client. - * The buffer pointed by the @a opaque becomes invalid when the pointer - * to the structure is freed by #MHD_free(). + * The size of the data pointed by @a userhash_bin. + * Always zero when @a userhash_bin is NULL. */ - char *opaque; + size_t userhash_bin_size; /** - * The length of the @a opaque. - * When the @a opaque is NULL, this member is always zero. + * The 'opaque' parameter value, as specified by client. + * If not specified by client then string pointer is NULL. */ - size_t opaque_len; + struct MHD_StringNullable opaque; /** * The 'realm' parameter value, as specified by client. - * NULL if not specified by client. - * The buffer pointed by the @a realm becomes invalid when the pointer - * to the structure is freed by #MHD_free(). - */ - char *realm; - - /** - * The length of the @a realm. - * When the @a realm is NULL, this member is always zero. + * If not specified by client then string pointer is NULL. */ - size_t realm_len; + struct MHD_StringNull realm; /** * The 'qop' parameter value. @@ -6077,44 +9609,22 @@ struct MHD_DigestAuthInfo * If not specified by client or does not have hexadecimal digits only, the * value is #MHD_DIGEST_AUTH_INVALID_NC_VALUE. */ - uint32_t nc; + uint_fast32_t nc; }; /** - * Get information about Digest Authorization client's header. - * - * @param connection The MHD connection structure - * @return NULL if no valid Digest Authorization header is used in the request; - * a pointer to the structure with information if the valid request - * header found, free using #MHD_free(). - * @sa #MHD_digest_auth_get_username3() - * @note Available since #MHD_VERSION 0x00097701 - * @ingroup authentication - */ -_MHD_EXTERN struct MHD_DigestAuthInfo * -MHD_digest_auth_get_request_info3 (struct MHD_Connection *connection); - - -/** * Information from Digest Authorization client's header. * - * All buffers pointed by any struct members are freed when #MHD_free() is - * called for pointer to this structure. - * - * Application may modify buffers as needed until #MHD_free() is called for - * pointer to this structure - * @note Available since #MHD_VERSION 0x00097701 + * @see #MHD_REQUEST_INFO_DYNAMIC_DAUTH_USERNAME_INFO */ struct MHD_DigestAuthUsernameInfo { /** * The algorithm as defined by client. * Set automatically to MD5 if not specified by client. - * @warning Do not be confused with #MHD_DigestAuthAlgorithm, - * which uses other values! */ - enum MHD_DigestAuthAlgo3 algo3; + enum MHD_DigestAuthAlgo algo; /** * The type of username used by client. @@ -6134,13 +9644,7 @@ struct MHD_DigestAuthUsernameInfo * The buffer pointed by the @a username becomes invalid when the pointer * to the structure is freed by #MHD_free(). */ - char *username; - - /** - * The length of the @a username. - * When the @a username is NULL, this member is always zero. - */ - size_t username_len; + struct MHD_String username; /** * The userhash string. @@ -6151,21 +9655,14 @@ struct MHD_DigestAuthUsernameInfo * to the structure is freed by #MHD_free(). * @sa #MHD_digest_auth_calc_userhash_hex() */ - char *userhash_hex; - - /** - * The length of the @a userhash_hex in characters. - * The valid size should be #MHD_digest_get_hash_size(algo3) * 2 characters. - * When the @a userhash_hex is NULL, this member is always zero. - */ - size_t userhash_hex_len; + struct MHD_String userhash_hex; /** * The userhash decoded to binary form. * Used only if username type is userhash, always NULL otherwise. * When not NULL, this points to binary sequence @a userhash_hex_len /2 bytes * long. - * The valid size should be #MHD_digest_get_hash_size(algo3) bytes. + * The valid size should be #MHD_digest_get_hash_size(algo) bytes. * The buffer pointed by the @a userhash_bin becomes invalid when the pointer * to the structure is freed by #MHD_free(). * @warning This is a binary data, no zero termination. @@ -6179,42 +9676,22 @@ struct MHD_DigestAuthUsernameInfo /** - * Get the username from Digest Authorization client's header. - * - * @param connection The MHD connection structure - * @return NULL if no valid Digest Authorization header is used in the request, - * or no username parameter is present in the header, or username is - * provided incorrectly by client (see description for - * #MHD_DIGEST_AUTH_UNAME_TYPE_INVALID); - * a pointer structure with information if the valid request header - * found, free using #MHD_free(). - * @sa #MHD_digest_auth_get_request_info3() provides more complete information - * @note Available since #MHD_VERSION 0x00097701 - * @ingroup authentication - */ -_MHD_EXTERN struct MHD_DigestAuthUsernameInfo * -MHD_digest_auth_get_username3 (struct MHD_Connection *connection); - - -/** * The result of digest authentication of the client. * * All error values are zero or negative. - * - * @note Available since #MHD_VERSION 0x00097701 */ -enum MHD_DigestAuthResult +enum MHD_FIXED_ENUM_MHD_SET_ MHD_DigestAuthResult { /** * Authentication OK. */ - MHD_DAUTH_OK = 1, - + MHD_DAUTH_OK = 1 + , /** * General error, like "out of memory". */ - MHD_DAUTH_ERROR = 0, - + MHD_DAUTH_ERROR = 0 + , /** * No "Authorization" header or wrong format of the header. * Also may be returned if required parameters in client Authorisation header @@ -6299,7 +9776,7 @@ enum MHD_DigestAuthResult * be generated and client repeats all requests twice (first time to get a new * nonce and second time to perform an authorised request). * - * @param connection the MHD connection structure + * @param request the request * @param realm the realm for authorization of the client * @param username the username to be authenticated, must be in clear text * even if userhash is used by the client @@ -6312,22 +9789,25 @@ enum MHD_DigestAuthResult * returned; * if zero is specified then daemon default value is used. * @param mqop the QOP to use - * @param malgo3 digest algorithms allowed to use, fail if algorithm used + * @param malgo digest algorithms allowed to use, fail if algorithm used * by the client is not allowed by this parameter * @return #MHD_DAUTH_OK if authenticated, * the error code otherwise - * @note Available since #MHD_VERSION 0x00097708 * @ingroup authentication */ -_MHD_EXTERN enum MHD_DigestAuthResult -MHD_digest_auth_check3 (struct MHD_Connection *connection, - const char *realm, - const char *username, - const char *password, - unsigned int nonce_timeout, - uint32_t max_nc, - enum MHD_DigestAuthMultiQOP mqop, - enum MHD_DigestAuthMultiAlgo3 malgo3); +MHD_EXTERN_ enum MHD_DigestAuthResult +MHD_digest_auth_check (struct MHD_Request *request, + const char *realm, + const char *username, + const char *password, + unsigned int nonce_timeout, + uint_fast32_t max_nc, + enum MHD_DigestAuthMultiQOP mqop, + enum MHD_DigestAuthMultiAlgo malgo) +MHD_FN_PAR_NONNULL_(1) +MHD_FN_PAR_NONNULL_(2) MHD_FN_PAR_CSTR_(2) +MHD_FN_PAR_NONNULL_(3) MHD_FN_PAR_CSTR_(3) +MHD_FN_PAR_NONNULL_(4) MHD_FN_PAR_CSTR_ (4); /** @@ -6345,31 +9825,33 @@ MHD_digest_auth_check3 (struct MHD_Connection *connection, * username & password pairs. To further improve security, application may * store username & userhash & userdigest triplets. * - * @param algo3 the digest algorithm + * @param algo the digest algorithm * @param username the username * @param realm the realm * @param password the password * @param[out] userdigest_bin the output buffer for userdigest; * if this function succeeds, then this buffer has - * #MHD_digest_get_hash_size(algo3) bytes of + * #MHD_digest_get_hash_size(algo) bytes of * userdigest upon return * @param userdigest_bin the size of the @a userdigest_bin buffer, must be - * at least #MHD_digest_get_hash_size(algo3) bytes long - * @return MHD_YES on success, - * MHD_NO if @a userdigest_bin is too small or if @a algo3 algorithm is - * not supported (or external error has occurred, - * see #MHD_FEATURE_EXTERN_HASH). - * @sa #MHD_digest_auth_check_digest3() - * @note Available since #MHD_VERSION 0x00097701 + * at least #MHD_digest_get_hash_size(algo) bytes long + * @return #MHD_SC_OK on success, + * error code otherwise. + * @sa #MHD_digest_auth_check_digest() * @ingroup authentication */ -_MHD_EXTERN enum MHD_Result -MHD_digest_auth_calc_userdigest (enum MHD_DigestAuthAlgo3 algo3, +MHD_EXTERN_ enum MHD_StatusCode +MHD_digest_auth_calc_userdigest (enum MHD_DigestAuthAlgo algo, const char *username, const char *realm, const char *password, - void *userdigest_bin, - size_t bin_buf_size); + size_t bin_buf_size, + void *userdigest_bin) +MHD_FN_PURE_ MHD_FN_PAR_NONNULL_ALL_ +MHD_FN_PAR_CSTR_(2) +MHD_FN_PAR_CSTR_(3) +MHD_FN_PAR_CSTR_(4) +MHD_FN_PAR_OUT_SIZE_ (6,5); /** @@ -6384,7 +9866,7 @@ MHD_digest_auth_calc_userdigest (enum MHD_DigestAuthAlgo3 algo3, * be generated and client repeats all requests twice (first time to get a new * nonce and second time to perform an authorised request). * - * @param connection the MHD connection structure + * @param request the request * @param realm the realm for authorization of the client * @param username the username to be authenticated, must be in clear text * even if userhash is used by the client @@ -6403,7 +9885,7 @@ MHD_digest_auth_calc_userdigest (enum MHD_DigestAuthAlgo3 algo3, * returned; * if zero is specified then daemon default value is used. * @param mqop the QOP to use - * @param malgo3 digest algorithms allowed to use, fail if algorithm used + * @param malgo digest algorithms allowed to use, fail if algorithm used * by the client is not allowed by this parameter; * more than one base algorithms (MD5, SHA-256, SHA-512/256) * cannot be used at the same time for this function @@ -6411,27 +9893,26 @@ MHD_digest_auth_calc_userdigest (enum MHD_DigestAuthAlgo3 algo3, * @return #MHD_DAUTH_OK if authenticated, * the error code otherwise * @sa #MHD_digest_auth_calc_userdigest() - * @note Available since #MHD_VERSION 0x00097701 * @ingroup authentication */ -_MHD_EXTERN enum MHD_DigestAuthResult -MHD_digest_auth_check_digest3 (struct MHD_Connection *connection, - const char *realm, - const char *username, - const void *userdigest, - size_t userdigest_size, - unsigned int nonce_timeout, - uint32_t max_nc, - enum MHD_DigestAuthMultiQOP mqop, - enum MHD_DigestAuthMultiAlgo3 malgo3); +MHD_EXTERN_ enum MHD_DigestAuthResult +MHD_digest_auth_check_digest (struct MHD_Request *request, + const char *realm, + const char *username, + const void *userdigest, + size_t userdigest_size, + unsigned int nonce_timeout, + uint_fast32_t max_nc, + enum MHD_DigestAuthMultiQOP mqop, + enum MHD_DigestAuthMultiAlgo malgo) +MHD_FN_PAR_NONNULL_ALL_ +MHD_FN_PAR_CSTR_(2) +MHD_FN_PAR_CSTR_(3) +MHD_FN_PAR_CSTR_ (4); /** - * Queues a response to request authentication from the client - * - * This function modifies provided @a response. The @a response must not be - * reused and should be destroyed (by #MHD_destroy_response()) after call of - * this function. + * Create an action to request authentication from the client * * If @a mqop allows both RFC 2069 (MHD_DIGEST_AUTH_QOP_NONE) and QOP with * value, then response is formed like if MHD_DIGEST_AUTH_QOP_NONE bit was @@ -6442,7 +9923,7 @@ MHD_digest_auth_check_digest3 (struct MHD_Connection *connection, * 'charset'). For better compatibility with clients, it is recommended (but * not required) to set @a domain to NULL in this mode. * - * @param connection the MHD connection structure + * @param request the request * @param realm the realm presented to the client * @param opaque the string for opaque value, can be NULL, but NULL is * not recommended for better compatibility with clients; @@ -6461,14 +9942,16 @@ MHD_digest_auth_check_digest3 (struct MHD_Connection *connection, * body; * note: this function sets the "WWW Authenticate" header and * the caller should not set this header; - * the NULL is tolerated + * the response must have #MHD_HTTP_STATUS_FORBIDDEN status + * code, must not have #MHD_RESP_OPT_BOOL_REUSABLE enabled; + * the NULL is tolerated (the result is NULL) * @param signal_stale if set to #MHD_YES then indication of stale nonce used in * the client's request is signalled by adding 'stale=true' * to the authentication header, this instructs the client * to retry immediately with the new nonce and the same * credentials, without asking user for the new password * @param mqop the QOP to use - * @param malgo3 digest algorithm to use; if several algorithms are allowed + * @param malgo digest algorithm to use; if several algorithms are allowed * then MD5 is preferred (currently, may be changed in next * versions) * @param userhash_support if set to non-zero value (#MHD_YES) then support of @@ -6484,1056 +9967,1720 @@ MHD_digest_auth_check_digest3 (struct MHD_Connection *connection, * @param prefer_utf8 if not set to #MHD_NO, parameter 'charset=UTF-8' is * added, indicating for the client that UTF-8 encoding for * the username is preferred - * @return #MHD_YES on success, #MHD_NO otherwise - * @note Available since #MHD_VERSION 0x00097701 + * @return pointer to the action on success, + * NULL on failure + * @ingroup authentication + */ +MHD_EXTERN_ const struct MHD_Action * +MHD_queue_auth_required_response (struct MHD_Request *request, + const char *realm, + const char *opaque, + const char *domain, + struct MHD_Response *response, + enum MHD_Bool signal_stale, + enum MHD_DigestAuthMultiQOP mqop, + enum MHD_DigestAuthMultiAlgo algo, + enum MHD_Bool userhash_support, + enum MHD_Bool prefer_utf8) +MHD_FN_PAR_NONNULL_ (1) MHD_FN_PAR_NONNULL_ (2) MHD_FN_PAR_CSTR_(2) +MHD_FN_PAR_CSTR_(3) MHD_FN_PAR_CSTR_(4) MHD_FN_PAR_NONNULL_ (5); + + +/** + * Constant to indicate that the nonce of the provided + * authentication code was wrong. + * Used as return code by #MHD_digest_auth_check(), + * #MHD_digest_auth_check_digest() + * @ingroup authentication + */ +#define MHD_INVALID_NONCE -1 + + +/** + * Information decoded from Basic Authentication client's header. + * + * @see #MHD_REQUEST_INFO_DYNAMIC_BAUTH_REQ_INFO + */ +struct MHD_BasicAuthInfo +{ + /** + * The username + */ + struct MHD_String username; + + /** + * The password, string pointer may be NULL if password is not encoded + * by the client. + */ + struct MHD_StringNullable password; +}; + +/** + * Send a response to request basic authentication from the client. + * + * See RFC 7617#section-2 for details. + * + * @param connection the MHD connection structure + * @param realm the realm presented to the client + * @param prefer_utf8 if not set to #MHD_NO, parameter'charset="UTF-8"' will + * be added, indicating for client that UTF-8 encoding + * is preferred + * @param response the reply to send; should contain the "access denied" + * body; + * note: this function sets the "WWW Authenticate" header and + * the caller should not set this header; + * the response must have #MHD_HTTP_STATUS_FORBIDDEN status + * code, must not have #MHD_RESP_OPT_BOOL_REUSABLE enabled; + * the NULL is tolerated (the result is NULL) + * @return pointer to the action on success, + * NULL on failure * @ingroup authentication */ -_MHD_EXTERN enum MHD_Result -MHD_queue_auth_required_response3 (struct MHD_Connection *connection, - const char *realm, - const char *opaque, - const char *domain, - struct MHD_Response *response, - int signal_stale, - enum MHD_DigestAuthMultiQOP mqop, - enum MHD_DigestAuthMultiAlgo3 algo, - int userhash_support, - int prefer_utf8); +MHD_EXTERN_ const struct MHD_Action * +MHD_queue_basic_auth_required_response (struct MHD_Connection *connection, + const char *realm, + enum MHD_Bool prefer_utf8, + struct MHD_Response *response); + + +/* ********************** (f) Introspection ********************** */ + + +/** + * Types of information about MHD, + * used by #MHD_lib_get_info_fixed_sz(). + * This information is not changed at run-time. + */ +enum MHD_FIXED_ENUM_APP_SET_ MHD_LibInfoFixed +{ + /* * Basic MHD information * */ + + /** + * Get the MHD version as a number. + * The result is placed in @a v_uint32 member. + */ + MHD_LIB_INFO_FIXED_VERSION_NUM = 0 + , + /** + * Get the MHD version as a string. + * The result is placed in @a v_string member. + */ + MHD_LIB_INFO_FIXED_VERSION_STR = 1 + , + + /* * Basic MHD features, buid-time configurable * */ + /* These features should be always available unless the library was + * not compiled specifically for some embedded project. + * Exceptions are marked explicitly in the description. */ + + /** + * Get whether messages are supported. If supported then in debug + * mode messages can be printed to stderr or to external logger. + * The result is placed in @a v_bool member. + */ + MHD_LIB_INFO_FIXED_HAS_MESSAGES = 11 + , + /** + * Get whether MHD supports threads. + * The result is placed in @a v_bool member. + */ + MHD_LIB_INFO_FIXED_HAS_THREADS = 12 + , + /** + * Get whether MHD was built with asserts enabled. + * Enabled only on special debug builds. + * For debug builds the error log is always enabled. + * The result is placed in @a v_bool member. + */ + MHD_LIB_INFO_FIXED_HAS_DEBUG = 13 + , + /** + * Get whether automatic parsing of HTTP Cookie header is supported. + * If disabled, no #MHD_COOKIE_KIND will be generated by MHD. + * The result is placed in @a v_bool member. + */ + MHD_LIB_INFO_FIXED_HAS_COOKIE_PARSING = 14 + , + /** + * Get whether postprocessor is supported. If supported then + * functions #MHD_create_post_processor(), #MHD_post_process() and + * #MHD_destroy_post_processor() can + * be used. + * The result is placed in @a v_bool member. + */ + MHD_LIB_INFO_FIXED_HAS_POSTPROCESSOR = 15 + , + /** + * Get whether HTTP "Upgrade" is supported. + * If supported then #MHD_ALLOW_UPGRADE, #MHD_upgrade_action() and + * #MHD_create_response_for_upgrade() can be used. + * The result is placed in @a v_bool member. + */ + MHD_LIB_INFO_FIXED_HAS_UPGRADE = 16 + , + /** + * Get whether HTTP Basic authorization is supported. If supported + * then functions #MHD_basic_auth_get_username_password and + * #MHD_queue_basic_auth_fail_response can be used. + * The result is placed in @a v_bool member. + */ + MHD_LIB_INFO_FIXED_HAS_BASIC_AUTH = 20 + , + /** + * Get whether HTTP Digest authorization is supported. If + * supported then options #MHD_OPTION_DIGEST_AUTH_RANDOM, + * #MHD_OPTION_NONCE_NC_SIZE and + * #MHD_digest_auth_check() can be used. + * The result is placed in @a v_bool member. + */ + MHD_LIB_INFO_FIXED_HAS_DIGEST_AUTH = 21 + , + /** + * Get whether the early version the Digest Authorization (RFC 2069) is + * supported (digest authorisation without QOP parameter). + * Since #MHD_VERSION 0x00097701 it is always supported if Digest Auth + * module is built. + * The result is placed in @a v_bool member. + */ + MHD_LIB_INFO_FIXED_HAS_DIGEST_AUTH_RFC2069 = 22 + , + /** + * Get whether the MD5-based hashing algorithms are supported for Digest + * Authorization and the type of the implementation if supported. + * Currently it is always supported if Digest Auth module is built + * unless manually disabled in a custom build. + * The result is placed in @a v_d_algo member. + */ + MHD_LIB_INFO_FIXED_TYPE_DIGEST_AUTH_MD5 = 23 + , + /** + * Get whether the SHA-256-based hashing algorithms are supported for Digest + * Authorization and the type of the implementation if supported. + * Currently it is always supported if Digest Auth module is built + * unless manually disabled in a custom build. + * The result is placed in @a v_d_algo member. + */ + MHD_LIB_INFO_FIXED_TYPE_DIGEST_AUTH_SHA256 = 24 + , + /** + * Get whether the SHA-512/256-based hashing algorithms are supported + * Authorization and the type of the implementation if supported. + * Currently it is always supported if Digest Auth module is built + * unless manually disabled in a custom build. + * The result is placed in @a v_d_algo member. + */ + MHD_LIB_INFO_FIXED_TYPE_DIGEST_AUTH_SHA512_256 = 25 + , + /** + * Get whether QOP with value 'auth-int' (authentication with integrity + * protection) is supported for Digest Authorization. + * Currently it is always not supported. + * The result is placed in @a v_bool member. + */ + MHD_LIB_INFO_FIXED_HAS_DIGEST_AUTH_AUTH_INT = 28 + , + /** + * Get whether 'session' algorithms (like 'MD5-sess') are supported for Digest + * Authorization. + * Currently it is always not supported. + * The result is placed in @a v_bool member. + */ + MHD_LIB_INFO_FIXED_HAS_DIGEST_AUTH_ALGO_SESSION = 29 + , + /** + * Get whether 'userhash' is supported for Digest Authorization. + * Currently it is always supported if Digest Auth module is built. + * The result is placed in @a v_bool member. + */ + MHD_LIB_INFO_FIXED_HAS_DIGEST_AUTH_USERHASH = 30 + , + + /* * Platform-dependent features, some are configurable at build-time * */ + /* These features depends on the platform, third-party libraries and + * the toolchain. + * Some of the features can be disabled or selected at build-time. */ + /** + * Get supported sockets polling function/techniques. + * The result is placed in @a v_polling member. + */ + MHD_LIB_INFO_FIXED_TYPE_SOCKETS_POLLING = 50 + , + /** + * Get whether aggregate FD external polling is supported. + * The result is placed in @a v_polling member. + */ + MHD_LIB_INFO_FIXED_HAS_AGGREGATE_FD = 51 + , + /** + * Get whether IPv6 is supported on the platform and whether IPv6 without IPv4 + * can be used. + * The result is placed in @a v_ipv6 member. + * @note The platform may have disabled IPv6 at run-time, it is not checked + * by this information type. + */ + MHD_LIB_INFO_FIXED_TYPE_IPv6 = 52 + , + /** + * Get whether TCP Fast Open is supported. If supported then + * flag #MHD_USE_TCP_FASTOPEN and option + * #MHD_OPTION_TCP_FASTOPEN_QUEUE_SIZE can be used. + * The result is placed in @a v_bool member. + */ + MHD_LIB_INFO_FIXED_HAS_TCP_FASTOPEN = 53 + , + /** + * Get whether MHD support automatic detection of bind port number. + * @sa #MHD_DAEMON_INFO_BIND_PORT + * The result is placed in @a v_bool member. + */ + MHD_LIB_INFO_FIXED_HAS_AUTODETECT_BIND_PORT = 54 + , + /** + * Get whether MHD use system's sendfile() function to send + * file-FD based responses over non-TLS connections. + * The result is placed in @a v_bool member. + */ + MHD_LIB_INFO_FIXED_HAS_SENDFILE = 55 + , + /** + * Get whether MHD supports automatic SIGPIPE suppression. + * If SIGPIPE suppression is not supported, application must handle + * SIGPIPE signal by itself. + * The result is placed in @a v_bool member. + */ + MHD_LIB_INFO_FIXED_HAS_AUTOSUPPRESS_SIGPIPE = 60 + , + /** + * Get whether MHD sets names on generated threads. + * The result is placed in @a v_bool member. + */ + MHD_LIB_INFO_FIXED_HAS_THREAD_NAMES = 61 + , + /** + * Get the type of supported inter-thread communication. + * The result is placed in @a v_itc member. + */ + MHD_LIB_INFO_FIXED_TYPE_ITC = 62 + , + /** + * Get whether reading files beyond 2 GiB boundary is supported. + * If supported then #MHD_create_response_from_fd(), + * #MHD_create_response_from_fd64 #MHD_create_response_from_fd_at_offset() + * and #MHD_create_response_from_fd_at_offset64() can be used with sizes and + * offsets larger than 2 GiB. If not supported value of size+offset is + * limited to 2 GiB. + * The result is placed in @a v_bool member. + */ + MHD_LIB_INFO_FIXED_HAS_LARGE_FILE = 63 + , + + /* * Platform-dependent features, some set on startup and some are + * configurable at build-time * */ + /* These features depends on the platform, third-party libraries availability + * and configuration. The features can be enabled/disabled during startup + * of the library depending on conditions. + * Some of the features can be disabled or selected at build-time. */ + /** + * Get whether HTTPS is supported and type of TLS backend(s) available if + * HTTPS is supported. + * The result is placed in @a v_tls member. + */ + MHD_LIB_INFO_FIXED_TYPE_TLS = 100 + , + /** + * Get whether option #MHD_OPTION_HTTPS_CERT_CALLBACK is + * supported. + * The result is placed in @a v_bool member. + */ + MHD_LIB_INFO_FIXED_HAS_TLS_CERT_CALLBACK = 101 + , + /** + * Get whether password encrypted private key for HTTPS daemon is + * supported. If supported then option + * ::MHD_OPTION_HTTPS_KEY_PASSWORD can be used. + * The result is placed in @a v_bool member. + */ + MHD_LIB_INFO_FIXED_HAS_TLS_KEY_PASSWORD = 102 + , + /** + * Get whether option #MHD_OPTION_HTTPS_CERT_CALLBACK2 is + * supported. + * The result is placed in @a v_bool member. + */ + MHD_LIB_INFO_FIXED_HAS_TLS_CERT_CALLBACK2 = 103 + , + + /* * Sentinel * */ + /** + * The sentinel value. + * This value enforces specific underlying integer type for the enum. + * Do not use. + */ + MHD_LIB_INFO_FIXED_SENTINEL = 65535 +}; + +/** + * The type of the data for digest algorithm implementations. + */ +enum MHD_FIXED_ENUM_MHD_SET_ MHD_LibInfoFixedDigestAlgoType +{ + /** + * The algorithm is not implemented or disabled at the build time. + */ + MHD_LIB_INFO_FIXED_DIGEST_ALGO_TYPE_NOT_AVAILABLE = 0 + , + /** + * The algorithm is implemented by MHD internal code. + */ + MHD_LIB_INFO_FIXED_DIGEST_ALGO_TYPE_BUILT_IN = 1 + , + /** + * The algorithm is implemented by external code that never fails. + */ + MHD_LIB_INFO_FIXED_DIGEST_ALGO_TYPE_EXTERNAL_NEVER_FAIL = 2 + , + /** + * The algorithm is implemented by external code that may hypothetically fail. + */ + MHD_LIB_INFO_FIXED_DIGEST_ALGO_TYPE_EXTERNAL_MAY_FAIL = 3 +}; + +/** + * The types of the sockets polling functions/techniques supported + */ +struct MHD_LibInfoFixedPollingFunc +{ + /** + * select() function for sockets polling + */ + enum MHD_Bool func_select; + /** + * poll() function for sockets polling + */ + enum MHD_Bool func_poll; + /** + * epoll technique for sockets polling + */ + enum MHD_Bool tech_epoll; +}; + +/** + * The types of IPv6 supported + */ +enum MHD_FIXED_ENUM_MHD_SET_ MHD_LibInfoFixedIPv6Type +{ + /** + * IPv6 is not supported by this MHD build + */ + MHD_LIB_INFO_FIXED_IPV6_TYPE_NONE = 0 + , + /** + * IPv6 is supported only as "dual stack". + * IPv4 connections can be received by IPv6 listen socket. + */ + MHD_LIB_INFO_FIXED_IPV6_TYPE_DUAL_ONLY = 1 + , + /** + * IPv6 is supported as IPv6-only or as "dual stack". + */ + MHD_LIB_INFO_FIXED_IPV6_TYPE_BOTH = 2 +}; + +/** + * The types of inter-thread communication + * @note the enum can be extended in future versions with new values + */ +enum MHD_FIXED_ENUM_MHD_SET_ MHD_LibInfoFixedITCType +{ + /** + * The pair of sockets are used as inter-thread communication. + * The is the least efficient method of communication. + */ + MHD_LIB_INFO_FIXED_ITC_TYPE_SOCKETPAIR = 0 + , + /** + * The pipe is used as inter-thread communication. + */ + MHD_LIB_INFO_FIXED_ITC_TYPE_PIPE = 1 + , + /** + * The EventFD is used as inter-thread communication. + * This is the most efficient method of communication. + */ + MHD_LIB_INFO_FIXED_ITC_TYPE_EVENTFD = 2 +}; /** - * Constant to indicate that the nonce of the provided - * authentication code was wrong. - * Used as return code by #MHD_digest_auth_check(), #MHD_digest_auth_check2(), - * #MHD_digest_auth_check_digest(), #MHD_digest_auth_check_digest2(). - * @ingroup authentication + * The types of the TLS backend supported + * @note the enum can be extended in future versions with new members */ -#define MHD_INVALID_NONCE -1 +struct MHD_LibInfoFixedTLSType +{ + /** + * The TLS is supported. + * Set to #MHD_YES if any other member is #MHD_YES. + */ + enum MHD_Bool tls_supported; + /** + * The TLS is supported by GnuTLS backend. + */ + enum MHD_Bool tls_gnutls; +}; +/** + * The data provided by #MHD_lib_get_info_fixed_sz() + */ +union MHD_LibInfoFixedData +{ + /** + * The 32-bit unsigned integer value + */ + uint_fast32_t v_uint32; + /** + * The MHD string value + */ + struct MHD_String v_string; + /** + * The boolean value + */ + enum MHD_Bool v_bool; + /** + * The type of digest algorithm implemtation + */ + enum MHD_LibInfoFixedDigestAlgoType v_d_algo; + /** + * The types of the sockets polling functions/techniques supported + */ + struct MHD_LibInfoFixedPollingFunc v_polling; + /** + * The type of IPv6 supported + */ + enum MHD_LibInfoFixedIPv6Type v_ipv6; + /** + * The type of inter-thread communication + */ + enum MHD_LibInfoFixedITCType v_itc; + /** + * The types of the TLS backend supported + */ + struct MHD_LibInfoFixedTLSType v_tls; +}; /** - * Get the username from the authorization header sent by the client - * - * This function supports username in standard and extended notations. - * "userhash" is not supported by this function. + * Get fixed information about MHD that is not changed at run-time. + * The returned information can be cached by application as it will be not + * changed at run-time. + * The wrapper macro #MHD_lib_get_info_fixed() could be more convenient. * - * @param connection The MHD connection structure - * @return NULL if no username could be found, username provided as - * "userhash", extended notation broken or memory allocation error - * occurs; - * a pointer to the username if found, free using #MHD_free(). - * @warning Returned value must be freed by #MHD_free(). - * @sa #MHD_digest_auth_get_username3() - * @ingroup authentication + * @param info_type the type of requested information + * @param[out] return_data the pointer to union to be set to the required + * information + * @param return_data_size the size of the memory area pointed + * by @a return_data, in bytes + * @return #MHD_SC_OK if succeed, + * error code otherwise + * @ingroup specialized */ -_MHD_EXTERN char * -MHD_digest_auth_get_username (struct MHD_Connection *connection); +MHD_EXTERN_ enum MHD_StatusCode +MHD_lib_get_info_fixed_sz (enum MHD_LibInfoFixed info_type, + union MHD_LibInfoFixedData *return_data, + size_t return_data_size) +MHD_FN_PAR_NONNULL_(2) MHD_FN_PAR_OUT_SIZE_(2,3) +MHD_FN_PURE_; +/** + * Get fixed information about MHD that is not changed at run-time. + * The returned information can be cached by application as it will be not + * changed at run-time. + * + * @param info the type of requested information + * @param[out] data the pointer to union to set to the required information + * @return #MHD_SC_OK if succeed, + * error code otherwise + * @ingroup specialized + */ +#define MHD_lib_get_info_fixed(info,data) \ + MHD_lib_get_info_fixed_sz((info),(data),sizeof(*(data))) /** - * Which digest algorithm should MHD use for HTTP digest authentication? - * Used as parameter for #MHD_digest_auth_check2(), - * #MHD_digest_auth_check_digest2(), #MHD_queue_auth_fail_response2(). + * Types of information about MHD, + * used by #MHD_lib_get_dymanic_info_sz(). + * This information may vary over time. */ -enum MHD_DigestAuthAlgorithm +enum MHD_FIXED_ENUM_APP_SET_ MHD_LibInfoDynamic { + /* * Basic MHD information * */ /** - * MHD should pick (currently defaults to MD5). + * Get whether MHD was successfully initialised. + * The result is #MHD_NO when the library has not been yet initialised or + * when library has been de-initialised. + * Under normal conditions the result must be always #MHD_YES when requested + * by application. + * The result is placed in @a v_bool member. */ - MHD_DIGEST_ALG_AUTO = 0, - - /** - * Force use of MD5. - */ - MHD_DIGEST_ALG_MD5, + MHD_LIB_INFO_DYNAMIC_INITED = 0 + , + /* * Sentinel * */ /** - * Force use of SHA-256. + * The sentinel value. + * This value enforces specific underlying integer type for the enum. + * Do not use. */ - MHD_DIGEST_ALG_SHA256 - -} _MHD_FIXED_ENUM; + MHD_LIB_INFO_DYNAMIC_SENTINEL = 65535 +}; /** - * Authenticates the authorization header sent by the client. - * - * @param connection The MHD connection structure - * @param realm The realm presented to the client - * @param username The username needs to be authenticated - * @param password The password used in the authentication - * @param nonce_timeout The amount of time for a nonce to be - * invalid in seconds - * @param algo digest algorithms allowed for verification - * @return #MHD_YES if authenticated, #MHD_NO if not, - * #MHD_INVALID_NONCE if nonce is invalid or stale - * @note Available since #MHD_VERSION 0x00096200 - * @deprecated use MHD_digest_auth_check3() - * @ingroup authentication + * The data provided by #MHD_lib_get_dynamic_info_sz(). + * The resulting value may vary over time. */ -_MHD_EXTERN int -MHD_digest_auth_check2 (struct MHD_Connection *connection, - const char *realm, - const char *username, - const char *password, - unsigned int nonce_timeout, - enum MHD_DigestAuthAlgorithm algo); +union MHD_LibInfoDynamicData +{ + /** + * The boolean value + */ + enum MHD_Bool v_bool; + /** + * Unused member. + * Help enforcing future-proof alignment of the union. + * Do not use. + */ + void *reserved; +}; /** - * Authenticates the authorization header sent by the client. - * Uses #MHD_DIGEST_ALG_MD5 (for now, for backwards-compatibility). - * Note that this MAY change to #MHD_DIGEST_ALG_AUTO in the future. - * If you want to be sure you get MD5, use #MHD_digest_auth_check2() - * and specify MD5 explicitly. - * - * @param connection The MHD connection structure - * @param realm The realm presented to the client - * @param username The username needs to be authenticated - * @param password The password used in the authentication - * @param nonce_timeout The amount of time for a nonce to be - * invalid in seconds - * @return #MHD_YES if authenticated, #MHD_NO if not, - * #MHD_INVALID_NONCE if nonce is invalid or stale - * @deprecated use MHD_digest_auth_check3() - * @ingroup authentication + * Get dynamic information about MHD that may be changed at run-time. + * The wrapper macro #MHD_lib_get_info_dynamic() could be more convenient. + * + * @param info_type the type of requested information + * @param[out] return_data the pointer to union to be set to the required + * information + * @param return_data_size the size of the memory area pointed + * by @a return_data, in bytes + * @return #MHD_SC_OK if succeed, + * error code otherwise + * @ingroup specialized */ -_MHD_EXTERN int -MHD_digest_auth_check (struct MHD_Connection *connection, - const char *realm, - const char *username, - const char *password, - unsigned int nonce_timeout); - +MHD_EXTERN_ enum MHD_StatusCode +MHD_lib_get_info_dynamic_sz (enum MHD_LibDynamicInfo info_type, + union MHD_LibDynamicInfoData *return_data, + size_t return_data_size) +MHD_FN_PAR_NONNULL_(2) MHD_FN_PAR_OUT_SIZE_ (2,3); /** - * Authenticates the authorization header sent by the client. + * Get dynamic information about MHD that may be changed at run-time. * - * @param connection The MHD connection structure - * @param realm The realm presented to the client - * @param username The username needs to be authenticated - * @param digest An `unsigned char *' pointer to the binary MD5 sum - * for the precalculated hash value "username:realm:password" - * of @a digest_size bytes - * @param digest_size number of bytes in @a digest (size must match @a algo!) - * @param nonce_timeout The amount of time for a nonce to be - * invalid in seconds - * @param algo digest algorithms allowed for verification - * @return #MHD_YES if authenticated, #MHD_NO if not, - * #MHD_INVALID_NONCE if nonce is invalid or stale - * @note Available since #MHD_VERSION 0x00096200 - * @deprecated use MHD_digest_auth_check_digest3() - * @ingroup authentication - */ -_MHD_EXTERN int -MHD_digest_auth_check_digest2 (struct MHD_Connection *connection, - const char *realm, - const char *username, - const uint8_t *digest, - size_t digest_size, - unsigned int nonce_timeout, - enum MHD_DigestAuthAlgorithm algo); - - -/** - * Authenticates the authorization header sent by the client - * Uses #MHD_DIGEST_ALG_MD5 (required, as @a digest is of fixed - * size). - * - * @param connection The MHD connection structure - * @param realm The realm presented to the client - * @param username The username needs to be authenticated - * @param digest An `unsigned char *' pointer to the binary hash - * for the precalculated hash value "username:realm:password"; - * length must be #MHD_MD5_DIGEST_SIZE bytes - * @param nonce_timeout The amount of time for a nonce to be - * invalid in seconds - * @return #MHD_YES if authenticated, #MHD_NO if not, - * #MHD_INVALID_NONCE if nonce is invalid or stale - * @note Available since #MHD_VERSION 0x00096000 - * @deprecated use #MHD_digest_auth_check_digest3() - * @ingroup authentication + * @param info the type of requested information + * @param[out] data the pointer to union to set to the required information + * @return #MHD_SC_OK if succeed, + * error code otherwise + * @ingroup specialized */ -_MHD_EXTERN int -MHD_digest_auth_check_digest (struct MHD_Connection *connection, - const char *realm, - const char *username, - const uint8_t digest[MHD_MD5_DIGEST_SIZE], - unsigned int nonce_timeout); +#define MHD_lib_get_info_dynamic(info,data) \ + MHD_lib_get_info_fixed_sz((info),(data),sizeof(*(data))) /** - * Queues a response to request authentication from the client - * - * This function modifies provided @a response. The @a response must not be - * reused and should be destroyed after call of this function. - * - * @param connection The MHD connection structure - * @param realm the realm presented to the client - * @param opaque string to user for opaque value - * @param response reply to send; should contain the "access denied" - * body; note that this function will set the "WWW Authenticate" - * header and that the caller should not do this; the NULL is tolerated - * @param signal_stale #MHD_YES if the nonce is stale to add - * 'stale=true' to the authentication header - * @param algo digest algorithm to use - * @return #MHD_YES on success, #MHD_NO otherwise - * @note Available since #MHD_VERSION 0x00096200 - * @deprecated use MHD_queue_auth_required_response3() - * @ingroup authentication + * Values of this enum are used to specify what + * information about a daemon is desired. + * This types of information are not changed at after start of the daemon until + * the daemon is destroyed. */ -_MHD_EXTERN enum MHD_Result -MHD_queue_auth_fail_response2 (struct MHD_Connection *connection, - const char *realm, - const char *opaque, - struct MHD_Response *response, - int signal_stale, - enum MHD_DigestAuthAlgorithm algo); +enum MHD_DaemonInfoFixedType +{ + /** + * Request the file descriptor for the listening socket. + * The result is placed in @a v_socket member. + */ + MHD_DAEMON_INFO_FIXED_LISTEN_SOCKET = 1 + , + /** + * Request the file descriptor for the single FD that triggered when + * any MHD event happens. + * This FD can be watched as aggregate indicator for all MHD events. + * The result is placed in @a v_fd member. + */ + MHD_DAEMON_INFO_FIXED_AGGREAGATE_FD + , + /** + * Request the port number of daemon's listen socket. + * No extra arguments should be passed. + * Note: if port '0' was specified for #MHD_option_port(), returned + * value will be real port number. + * The result is placed in @a v_port member. + */ + MHD_DAEMON_INFO_FIXED_BIND_PORT + , + /* * Sentinel * */ + /** + * The sentinel value. + * This value enforces specific underlying integer type for the enum. + * Do not use. + */ + MHD_DAEMON_INFO_FIXED_SENTINEL = 65535 -/** - * Queues a response to request authentication from the client. - * For now uses MD5 (for backwards-compatibility). Still, if you - * need to be sure, use #MHD_queue_auth_fail_response2(). - * - * This function modifies provided @a response. The @a response must not be - * reused and should be destroyed after call of this function. - * - * @param connection The MHD connection structure - * @param realm the realm presented to the client - * @param opaque string to user for opaque value - * @param response reply to send; should contain the "access denied" - * body; note that this function will set the "WWW Authenticate" - * header and that the caller should not do this; the NULL is tolerated - * @param signal_stale #MHD_YES if the nonce is stale to add - * 'stale=true' to the authentication header - * @return #MHD_YES on success, #MHD_NO otherwise - * @deprecated use MHD_queue_auth_required_response3() - * @ingroup authentication - */ -_MHD_EXTERN enum MHD_Result -MHD_queue_auth_fail_response (struct MHD_Connection *connection, - const char *realm, - const char *opaque, - struct MHD_Response *response, - int signal_stale); +}; /** - * Information decoded from Basic Authentication client's header. - * - * The username and the password are technically allowed to have binary zeros, - * username_len and password_len could be used to detect such situations. - * - * The buffers pointed by username and password members are freed - * when #MHD_free() is called for pointer to this structure. - * - * Application may modify buffers as needed until #MHD_free() is called for - * pointer to this structure + * Information about an MHD daemon. */ -struct MHD_BasicAuthInfo +union MHD_DaemonInfoFixedData { + /** - * The username, cannot be NULL. - * The buffer pointed by the @a username becomes invalid when the pointer - * to the structure is freed by #MHD_free(). + * The socket type of data. */ - char *username; + MHD_socket v_socket; /** - * The length of the @a username, not including zero-termination + * File descriptor, except sockets */ - size_t username_len; + int v_fd; /** - * The password, may be NULL if password is not encoded by the client. - * The buffer pointed by the @a password becomes invalid when the pointer - * to the structure is freed by #MHD_free(). + * Port number */ - char *password; + uint_fast16_t v_port; /** - * The length of the @a password, not including zero-termination; - * when the @a password is NULL, the length is always zero. + * Unused member. + * Help enforcing future-proof alignment of the union. + * Do not use. */ - size_t password_len; + void *reserved; }; + /** - * Get the username and password from the Basic Authorisation header - * sent by the client + * Obtain fixed information about the given daemon. + * This information is not changed at after start of the daemon until + * the daemon is destroyed. + * The wrapper macro #MHD_daemon_get_info_fixed() could be more convenient. * - * @param connection the MHD connection structure - * @return NULL if no valid Basic Authentication header is present in - * current request, or - * pointer to structure with username and password, which must be - * freed by #MHD_free(). - * @note Available since #MHD_VERSION 0x00097701 - * @ingroup authentication + * @param daemon the daemon to get information about + * @param info_type the type of information requested + * @param[out] return_value pointer to union where requested information will + * be stored + * @param return_value_size the size of the memory area pointed + * by @a return_data, in bytes + * @return #MHD_SC_OK if succeed, + * error code otherwise + * @ingroup specialized */ -_MHD_EXTERN struct MHD_BasicAuthInfo * -MHD_basic_auth_get_username_password3 (struct MHD_Connection *connection); +MHD_EXTERN_ enum MHD_StatusCode +MHD_daemon_get_info_fixed_sz (struct MHD_Daemon *daemon, + enum MHD_DaemonInfoFixedType info_type, + union MHD_DaemonInfoFixedData *return_value, + size_t return_value_size) +MHD_FN_PAR_NONNULL_ (1) +MHD_FN_PAR_NONNULL_ (3) MHD_FN_PAR_INOUT_SIZE_(3,4) +MHD_FN_PURE_; /** - * Queues a response to request basic authentication from the client. - * - * The given response object is expected to include the payload for - * the response; the "WWW-Authenticate" header will be added and the - * response queued with the 'UNAUTHORIZED' status code. - * - * See RFC 7617#section-2 for details. + * Obtain fixed information about the given daemon. + * This types of information are not changed at after start of the daemon until + * the daemon is destroyed. * - * The @a response is modified by this function. The modified response object - * can be used to respond subsequent requests by #MHD_queue_response() - * function with status code #MHD_HTTP_UNAUTHORIZED and must not be used again - * with MHD_queue_basic_auth_required_response3() function. The response could - * be destroyed right after call of this function. - * - * @param connection the MHD connection structure - * @param realm the realm presented to the client - * @param prefer_utf8 if not set to #MHD_NO, parameter'charset="UTF-8"' will - * be added, indicating for client that UTF-8 encoding - * is preferred - * @param response the response object to modify and queue; the NULL - * is tolerated - * @return #MHD_YES on success, #MHD_NO otherwise - * @note Available since #MHD_VERSION 0x00097704 - * @ingroup authentication + * @param daemon the daemon to get information about + * @param info_type the type of information requested + * @param[out] return_value pointer to union where requested information will + * be stored + * @return #MHD_SC_OK if succeed, + * error code otherwise + * @ingroup specialized */ -_MHD_EXTERN enum MHD_Result -MHD_queue_basic_auth_required_response3 (struct MHD_Connection *connection, - const char *realm, - int prefer_utf8, - struct MHD_Response *response); +#define MHD_daemon_get_info_fixed(daemon,info_type,return_value) \ + MHD_daemon_get_info_fixed_sz ((daemon), (info_type), (return_value), \ + sizeof(*(return_value))) + /** - * Get the username and password from the basic authorization header sent by the client - * - * @param connection The MHD connection structure - * @param[out] password a pointer for the password, free using #MHD_free(). - * @return NULL if no username could be found, a pointer - * to the username if found, free using #MHD_free(). - * @deprecated use #MHD_basic_auth_get_username_password3() - * @ingroup authentication + * Values of this enum are used to specify what + * information about a daemon is desired. + * This types of information may be changed after the start of the daemon. */ -_MHD_EXTERN char * -MHD_basic_auth_get_username_password (struct MHD_Connection *connection, - char **password); +enum MHD_DaemonInfoDynamicType +{ + /** + * The the maximum number of microseconds from the current moment until + * the mandatory call of the daemon data processing function (like + * #MHD_deamon_process_reg_events(), #MHD_daemon_process_blocking()). + * If resulting value is zero then daemon data processing function should be + * called as soon as possible as some data processing is already pending. + * The data processing function can also be called earlier as well. + * Available only for daemons stated in #MHD_TM_EXTERNAL_PERIODIC, + * #MHD_TM_EXTERNAL_EVENT_LOOP_CB_LEVEL, #MHD_TM_EXTERNAL_EVENT_LOOP_CB_EDGE + * or #MHD_TM_EXTERNAL_SINGLE_FD_WATCH modes. + * The result is placed in @a v_uint64 member. + */ + MHD_DAEMON_INFO_DYNAMIC_MAX_TIME_TO_WAIT = 1 + , + /** + * Request the number of current connections handled by the daemon. + * No extra arguments should be passed. + * Note: when using MHD in external polling mode, this type of request + * could be used only when #MHD_run()/#MHD_run_from_select is not + * working in other thread at the same time. + * The result is placed in @a v_uint member. + */ + MHD_DAEMON_INFO_DYNAMIC_CURRENT_CONNECTIONS = 20 + , + /* * Sentinel * */ + /** + * The sentinel value. + * This value enforces specific underlying integer type for the enum. + * Do not use. + */ + MHD_DAEMON_INFO_FIXED_SENTINEL = 65535 +}; /** - * Queues a response to request basic authentication from the client - * The given response object is expected to include the payload for - * the response; the "WWW-Authenticate" header will be added and the - * response queued with the 'UNAUTHORIZED' status code. - * - * @param connection The MHD connection structure - * @param realm the realm presented to the client - * @param response response object to modify and queue; the NULL is tolerated - * @return #MHD_YES on success, #MHD_NO otherwise - * @deprecated use MHD_queue_basic_auth_required_response3() - * @ingroup authentication + * Information about an MHD daemon. */ -_MHD_EXTERN enum MHD_Result -MHD_queue_basic_auth_fail_response (struct MHD_Connection *connection, - const char *realm, - struct MHD_Response *response); +union MHD_DaemonInfoDynamicData +{ + /** + * Unsigned 64 bits integer value. + */ + uint_fast64_t v_uint64; + + /** + * Unsigned integer value. + */ + unsigned int v_uint; + + /** + * Unused member. + * Help enforcing future-proof alignment of the union. + * Do not use. + */ + void *reserved; +}; /** - * Set random values to be used by the Digest Auth module. Note that - * the application must ensure that @a buf remains allocated and - * unmodified while the daemon is running. + * Obtain dynamic information about the given daemon. + * This information may be changed after the start of the daemon. + * The wrapper macro #MHD_daemon_get_info_dynamic() could be more convenient. * - * @param daemon daemon to configure - * @param buf_size number of bytes in @a buf - * @param buf entropy buffer + * @param daemon the daemon to get information about + * @param info_type the type of information requested + * @param[out] return_value pointer to union where requested information will + * be stored + * @param return_value_size the size of the memory area pointed + * by @a return_data, in bytes + * @return #MHD_SC_OK if succeed, + * error code otherwise + * @ingroup specialized */ -_MHD_EXTERN void -MHD_daemon_digest_auth_random (struct MHD_Daemon *daemon, - size_t buf_size, - const void *buf) -MHD_FUNC_PARAM_NONNULL_ (1,3); - +MHD_EXTERN_ enum MHD_StatusCode +MHD_daemon_get_info_dynamic_sz (struct MHD_Daemon *daemon, + enum MHD_DaemonInfoDynamicType info_type, + union MHD_DaemonInfoDynamicData *return_value, + size_t return_value_size) +MHD_FN_PAR_NONNULL_ (1) +MHD_FN_PAR_NONNULL_ (3) MHD_FN_PAR_INOUT_SIZE_ (3,4); /** - * Length of the internal array holding the map of the nonce and - * the nonce counter. + * Obtain dynamic information about the given daemon. + * This types of information may be changed after the start of the daemon. * - * @param daemon daemon to configure - * @param nc_length desired array length + * @param daemon the daemon to get information about + * @param info_type the type of information requested + * @param[out] return_value pointer to union where requested information will + * be stored + * @return #MHD_SC_OK if succeed, + * error code otherwise + * @ingroup specialized */ -_MHD_EXTERN enum MHD_StatusCode -MHD_daemon_digest_auth_nc_length (struct MHD_Daemon *daemon, - size_t nc_length) -MHD_FUNC_PARAM_NONNULL_ (1); - - -/* ********************** (f) Introspection ********************** */ +#define MHD_daemon_get_info_dynamic(daemon,info_type,return_value) \ + MHD_daemon_get_info_dynamic_sz ((daemon), (info_type), (return_value), \ + sizeof(*(return_value))) /** - * Select which member of the `struct ConnectionInformation` - * union is desired to be returned by #MHD_connection_get_info(). + * Select which fixed information about connection is desired. + * This information is not changed during the lifetime of the connection. */ -enum MHD_ConnectionInformationType +enum MHD_ConnectionInfoFixedType { /** - * What cipher algorithm is being used. - * Takes no extra arguments. + * Obtain IP address of the client. + * The result is placed in @a vs_sa member. * @ingroup request */ - MHD_CONNECTION_INFORMATION_CIPHER_ALGO, - + MHD_CONNECTION_INFO_FIXED_CLIENT_ADDRESS = 1 + , /** - * - * Takes no extra arguments. + * Request the file descriptor for the connection socket. + * The result is placed in @a v_fd member. * @ingroup request */ - MHD_CONNECTION_INFORMATION_PROTOCOL, - + MHD_CONNECTION_INFO_FIXED_CONNECTION_FD = 2 + , /** - * Obtain IP address of the client. Takes no extra arguments. - * Returns essentially a `struct sockaddr **` (since the API returns - * a `union MHD_ConnectionInfo *` and that union contains a `struct - * sockaddr *`). + * Get the `struct MHD_Daemon *` responsible for managing this connection. + * The result is placed in @a v_daemon member. * @ingroup request */ - MHD_CONNECTION_INFORMATION_CLIENT_ADDRESS, - + MHD_CONNECTION_INFO_FIXED_DAEMON = 20 + , + /* * Sentinel * */ /** - * Get the gnuTLS session handle. - * @ingroup request + * The sentinel value. + * This value enforces specific underlying integer type for the enum. + * Do not use. */ - MHD_CONNECTION_INFORMATION_GNUTLS_SESSION, + MHD_CONNECTION_INFO_FIXED_SENTINEL = 65535 +}; + + +/** + * Information about a connection. + */ +union MHD_ConnectionInfoFixedData +{ /** - * Get the gnuTLS client certificate handle. Dysfunctional (never - * implemented, deprecated). Use #MHD_CONNECTION_INFORMATION_GNUTLS_SESSION - * to get the `gnutls_session_t` and then call - * gnutls_certificate_get_peers(). + * Socket Address type */ - MHD_CONNECTION_INFORMATION_GNUTLS_CLIENT_CERT, + const struct sockaddr *vs_sa; /** - * Get the `struct MHD_Daemon *` responsible for managing this connection. - * @ingroup request + * Socket type */ - MHD_CONNECTION_INFORMATION_DAEMON, + MHD_socket v_fd; /** - * Request the file descriptor for the connection socket. - * No extra arguments should be passed. - * @ingroup request + * Daemon handler type */ - MHD_CONNECTION_INFORMATION_CONNECTION_FD, + struct MHD_Daemon *v_daemon; +}; + + +/** + * Obtain fixed information about the given connection. + * This information is not changed for the lifetime of the connection. + * The wrapper macro #MHD_connection_get_info_fixed() could be more convenient. + * + * @param connection the connection to get information about + * @param info_type the type of information requested + * @param[out] return_value pointer to union where requested information will + * be stored + * @param return_value_size the size of the memory area pointed + by @a return_data, in bytes + * @return #MHD_SC_OK if succeed, + * error code otherwise + * @ingroup specialized + */ +MHD_EXTERN_ enum MHD_StatusCode +MHD_connection_get_info_fixed_sz ( + struct MHD_Connection *connection, + enum MHD_ConnectionInfoFixedType info_type, + union MHD_ConnectionInfoFixedData *return_value, + size_t return_value_size) +MHD_FN_PAR_NONNULL_ (1) +MHD_FN_PAR_NONNULL_ (3) MHD_FN_PAR_INOUT_SIZE_(3,4) +MHD_FN_PURE_; + + +/** + * Obtain fixed information about the given connection. + * This information is not changed for the lifetime of the connection. + * + * @param connection the connection to get information about + * @param info_type the type of information requested + * @param[out] return_value pointer to union where requested information will + * be stored + * @return #MHD_SC_OK if succeed, + * error code otherwise + * @ingroup specialized + */ +#define MHD_connection_get_info_fixed(connection,info_type,return_value) \ + MHD_connection_get_info_fixed_sz ((connection),(info_type),(return_value), \ + sizeof(*(return_value))) + +/** + * Select which dynamic information about connection is desired. + * This information may be changed during the lifetime of the connection. + */ +enum MHD_ConnectionInfoDynamicType +{ /** - * Returns the client-specific pointer to a `void *` that was (possibly) - * set during a #MHD_NotifyConnectionCallback when the socket was - * first accepted. Note that this is NOT the same as the "req_cls" - * argument of the #MHD_AccessHandlerCallback. The "req_cls" is - * fresh for each HTTP request, while the "socket_context" is fresh - * for each socket. + * Get current version of HTTP protocol used for connection. + * The result is placed in @a v_http_ver member. + * @ingroup request */ - MHD_CONNECTION_INFORMATION_SOCKET_CONTEXT, - + MHD_CONNECTION_INFO_DYNAMIC_HTTP_VER = 1 + , /** - * Get connection timeout + * Get connection timeout. + * The result is placed in @a v_uint member. * @ingroup request */ - MHD_CONNECTION_INFORMATION_CONNECTION_TIMEOUT, - + MHD_CONNECTION_INFO_DYNAMIC_CONNECTION_TIMEOUT = 10 + , /** * Check whether the connection is suspended. + * The result is placed in @a v_bool member. * @ingroup request */ - MHD_CONNECTION_INFORMATION_CONNECTION_SUSPENDED - + MHD_CONNECTION_INFO_DYNAMIC_CONNECTION_SUSPENDED = 11 + , + /** + * Returns the connection-specific application context data that was + * (possibly) set during a #MHD_NotifyConnectionCallback or provided vai + * @a connection_cntx parameter of #MHD_daemon_add_connection(). + * The result is placed in @a v_pvoid member. + */ + MHD_CONNECTION_INFO_DYNAMIC_SOCKET_CONTEXT = 20 + , + /** + * Get current version of TLS transport protocol used for connection + * The result is placed in @a v_tls_ver member. + * @ingroup request + */ + MHD_CONNECTION_INFO_DYNAMIC_TLS_VER = 1 + , + /** + * Get the GnuTLS session handle. + * The result is placed in @a v_gnutls_session member. + * @ingroup request + */ + MHD_CONNECTION_INFO_DYNAMIC_GNUTLS_SESSION = 40 + , + /* * Sentinel * */ + /** + * The sentinel value. + * This value enforces specific underlying integer type for the enum. + * Do not use. + */ + MHD_CONNECTION_INFO_DYNAMIC_SENTINEL = 65535 }; /** - * Information about a connection. + * The versions of TLS protocol */ -union MHD_ConnectionInformation +enum MHD_FIXED_ENUM_MHD_SET_ MHD_TlsVersion { /** - * Cipher algorithm used, of type "enum gnutls_cipher_algorithm". + * No TLS / plain socket connection */ - int /* enum gnutls_cipher_algorithm */ cipher_algorithm; - + MHD_TLS_VERSION_NO_TLS = 0 + , /** - * Protocol used, of type "enum gnutls_protocol". + * Not supported/failed to negotiate/failed to handshake TLS */ - int /* enum gnutls_protocol */ protocol; - + MHD_TLS_VERSION_BROKEN = 1 + , /** - * Amount of second that connection could spend in idle state - * before automatically disconnected. - * Zero for no timeout (unlimited idle time). + * TLS version 1.0 */ - unsigned int connection_timeout; - + MHD_TLS_VERSION_1_0 = 2 + , + /** + * TLS version 1.1 + */ + MHD_TLS_VERSION_1_1 = 3 + , + /** + * TLS version 1.2 + */ + MHD_TLS_VERSION_1_2 = 4 + , + /** + * TLS version 1.3 + */ + MHD_TLS_VERSION_1_3 = 5 + , /** - * Connect socket + * Some unknown TLS version. + * The TLS version is supported by TLS backend, but unknown to MHD. */ - MHD_socket connect_fd; + MHD_TLS_VERSION_UNKNOWN = 1999 +}; +/** + * Information about a connection. + */ +union MHD_ConnectionInfoDynamicData +{ /** - * GNUtls session handle, of type "gnutls_session_t". + * The type for HTTP version */ - void * /* gnutls_session_t */ tls_session; + enum MHD_HTTP_ProtocolVersion v_http_ver; /** - * GNUtls client certificate handle, of type "gnutls_x509_crt_t". + * The unsigned integer type */ - void * /* gnutls_x509_crt_t */ client_cert; + unsigned int v_uint; /** - * Address information for the client. + * The boolean type */ - const struct sockaddr *client_addr; + enum MHD_Bool v_bool; /** - * Which daemon manages this connection (useful in case there are many - * daemons running). + * The pointer to void type */ - struct MHD_Daemon *daemon; + void *v_pvoid; /** - * Pointer to connection-specific client context. Points to the - * same address as the "socket_context" of the - * #MHD_NotifyConnectionCallback. + * The TLS version */ - void **socket_context; + enum MHD_TlsVersion v_tls_ver; + /* Include <gnutls/gnutls.h> before this header to get a better type safety */ /** - * Is this connection right now suspended? + * GnuTLS session handle, of type "gnutls_session_t". */ - enum MHD_Bool suspended; +#if defined(GNUTLS_VERSION_MAJOR) && GNUTLS_VERSION_MAJOR >= 3 + gnutls_session_t +#else + void * /* gnutls_session_t */ +#endif + v_gnutls_session; }; - /** - * Obtain information about the given connection. - * Use wrapper macro #MHD_connection_get_information() instead of direct use - * of this function. + * Obtain dynamic information about the given connection. + * This information may be changed during the lifetime of the connection. + * The wrapper macro #MHD_connection_get_info_dynamic() could be more + * convenient. * - * @param connection what connection to get information about - * @param info_type what information is desired? + * @param connection the connection to get information about + * @param info_type the type of information requested * @param[out] return_value pointer to union where requested information will * be stored - * @param return_value_size size of union MHD_ConnectionInformation at compile - * time - * @return #MHD_YES on success, #MHD_NO on error - * (@a info_type is unknown, NULL pointer etc.) + * @param return_value_size the size of the memory area pointed + by @a return_data, in bytes + * @return #MHD_SC_OK if succeed, + * error code otherwise * @ingroup specialized */ -_MHD_EXTERN enum MHD_Bool -MHD_connection_get_information_sz (struct MHD_Connection *connection, - enum MHD_ConnectionInformationType info_type, - union MHD_ConnectionInformation *return_value - , - size_t return_value_size) -MHD_FUNC_PARAM_NONNULL_ (1,3); +MHD_EXTERN_ enum MHD_StatusCode +MHD_connection_get_info_dynamic_sz ( + struct MHD_Connection *connection, + enum MHD_ConnectionInfoDynamicType info_type, + union MHD_ConnectionInfoDynamicData *return_value, + size_t return_value_size) +MHD_FN_PAR_NONNULL_ (1) +MHD_FN_PAR_NONNULL_ (3) MHD_FN_PAR_INOUT_SIZE_ (3,4); /** - * Obtain information about the given connection. + * Obtain dynamic information about the given connection. + * This information may be changed during the lifetime of the connection. * - * @param connection what connection to get information about - * @param info_type what information is desired? + * @param connection the connection to get information about + * @param info_type the type of information requested * @param[out] return_value pointer to union where requested information will * be stored - * @return #MHD_YES on success, #MHD_NO on error - * (@a info_type is unknown, NULL pointer etc.) + * @return #MHD_SC_OK if succeed, + * error code otherwise * @ingroup specialized */ -#define MHD_connection_get_information(connection, \ - info_type, \ - return_value) \ - MHD_connection_get_information_sz ((connection),(info_type),(return_value), \ - sizeof(union MHD_ConnectionInformation)) +#define MHD_connection_get_info_dynamic(connection,info_type,return_value) \ + MHD_connection_get_info_dynamic_sz ((connection),(info_type),(return_value), \ + sizeof(*(return_value))) /** - * Information we return about a request. + * Select which fixed information about stream is desired. + * This information is not changed during the lifetime of the connection. */ -union MHD_RequestInformation +enum MHD_FIXED_ENUM_APP_SET_ MHD_StreamInfoFixedType { - /** - * Connection via which we received the request. + * Get the `struct MHD_Connection *` responsible for managing this stream. + * The result is placed in @a v_connection member. + * @ingroup request */ - struct MHD_Connection *connection; - + MHD_STREAM_INFO_FIXED_CONNECTION = 1 + , /** - * Pointer to client context. Will also be given to - * the application in a #MHD_RequestTerminationCallback. + * Get the `struct MHD_Daemon *` responsible for managing connection which + * is responsible for this stream. + * The result is placed in @a v_daemon member. + * @ingroup request */ - void **request_context; - + MHD_STREAM_INFO_FIXED_DAEMON = 2 + , + /* * Sentinel * */ /** - * HTTP version requested by the client. + * The sentinel value. + * This value enforces specific underlying integer type for the enum. + * Do not use. */ - const char *http_version; + MHD_STREAM_INFO_FIXED_SENTINEL = 65535 +}; + +/** + * Fixed information about a stream. + */ +union MHD_StreamInfoFixedData +{ /** - * HTTP method of the request, as a string. Particularly useful if - * #MHD_HTTP_METHOD_UNKNOWN was given. + * Connection handler type */ - const char *http_method; - + struct MHD_Connection *v_connection; /** - * Size of the client's HTTP header. + * Daemon handler type */ - size_t header_size; - + struct MHD_Daemon *v_daemon; }; /** - * Select which member of the `struct RequestInformation` - * union is desired to be returned by #MHD_request_get_info(). + * Obtain fixed information about the given stream. + * This information is not changed for the lifetime of the stream. + * The wrapper macro #MHD_stream_get_info_fixed() could be more convenient. + * + * @param stream the stream to get information about + * @param info_type the type of information requested + * @param[out] return_value pointer to union where requested information will + * be stored + * @param return_value_size the size of the memory area pointed + * by @a return_data, in bytes + * @return #MHD_SC_OK if succeed, + * error code otherwise + * @ingroup specialized */ -enum MHD_RequestInformationType -{ - /** - * Return which connection the request is associated with. - */ - MHD_REQUEST_INFORMATION_CONNECTION, +MHD_EXTERN_ enum MHD_StatusCode +MHD_stream_get_info_fixed_sz ( + struct MHD_Stream *stream, + enum MHD_StreamInfoFixedType info_type, + union MHD_StreamInfoFixedData *return_value, + size_t return_value_size) +MHD_FN_PAR_NONNULL_ (1) +MHD_FN_PAR_NONNULL_ (3) MHD_FN_PAR_INOUT_SIZE_(3,4) +MHD_FN_PURE_; + + +/** + * Obtain fixed information about the given stream. + * This information is not changed for the lifetime of the tream. + * + * @param stream the stream to get information about + * @param info_type the type of information requested + * @param[out] return_value pointer to union where requested information will + * be stored + * @return #MHD_SC_OK if succeed, + * error code otherwise + * @ingroup specialized + */ +#define MHD_stream_get_info_fixed(stream,info_type,return_value) \ + MHD_stream_get_info_fixed_sz ((stream),(info_type),(return_value), \ + sizeof(*(return_value))) - /** - * Returns the client-specific pointer to a `void *` that - * is specific to this request. - */ - MHD_REQUEST_INFORMATION_CLIENT_CONTEXT, +/** + * Select which fixed information about stream is desired. + * This information may be changed during the lifetime of the stream. + */ +enum MHD_FIXED_ENUM_APP_SET_ MHD_StreamInfoDynamicType +{ /** - * Return the HTTP version string given by the client. + * Get the `struct MHD_Request *` for current request processed by the stream. + * If no request is being processed, the resulting pointer is NULL. + * The result is placed in @a v_request member. * @ingroup request */ - MHD_REQUEST_INFORMATION_HTTP_VERSION, + MHD_STREAM_INFO_DYNAMIC_REQUEST = 1 + , + /* * Sentinel * */ /** - * Return the HTTP method used by the request. - * @ingroup request + * The sentinel value. + * This value enforces specific underlying integer type for the enum. + * Do not use. */ - MHD_REQUEST_INFORMATION_HTTP_METHOD, + MHD_STREAM_INFO_DYNAMIC_SENTINEL = 65535 +}; + +/** + * Dynamic information about stream. + * This information may be changed during the lifetime of the connection. + */ +union MHD_StreamInfoDynamicData +{ /** - * Return length of the client's HTTP request header. - * @ingroup request + * The MHD_Request handler type */ - MHD_REQUEST_INFORMATION_HEADER_SIZE + struct MHD_Request *v_request; }; - /** - * Obtain information about the given request. - * Use wrapper macro #MHD_request_get_information() instead of direct use - * of this function. + * Obtain dynamic information about the given stream. + * This information may be changed during the lifetime of the stream. + * The wrapper macro #MHD_stream_get_info_dynamic() could be more convenient. * - * @param request what request to get information about - * @param info_type what information is desired? + * @param stream the stream to get information about + * @param info_type the type of information requested * @param[out] return_value pointer to union where requested information will * be stored - * @param return_value_size size of union MHD_RequestInformation at compile - * time - * @return #MHD_YES on success, #MHD_NO on error - * (@a info_type is unknown, NULL pointer etc.) + * @param return_value_size the size of the memory area pointed + by @a return_data, in bytes + * @return #MHD_SC_OK if succeed, + * error code otherwise * @ingroup specialized */ -_MHD_EXTERN enum MHD_Bool -MHD_request_get_information_sz (struct MHD_Request *request, - enum MHD_RequestInformationType info_type, - union MHD_RequestInformation *return_value, - size_t return_value_size) -MHD_FUNC_PARAM_NONNULL_ (1,3); +MHD_EXTERN_ enum MHD_StatusCode +MHD_stream_get_info_dynamic_sz ( + struct MHD_Stream *stream, + enum MHD_StreamInfoDynamicType info_type, + union MHD_StreamInfoDynamicData *return_value, + size_t return_value_size) +MHD_FN_PAR_NONNULL_ (1) +MHD_FN_PAR_NONNULL_ (3) MHD_FN_PAR_INOUT_SIZE_ (3,4); /** - * Obtain information about the given request. + * Obtain dynamic information about the given stream. + * This information may be changed during the lifetime of the stream. * - * @param request what request to get information about - * @param info_type what information is desired? + * @param stream the stream to get information about + * @param info_type the type of information requested * @param[out] return_value pointer to union where requested information will * be stored - * @return #MHD_YES on success, #MHD_NO on error - * (@a info_type is unknown, NULL pointer etc.) + * @return #MHD_SC_OK if succeed, + * error code otherwise * @ingroup specialized */ -#define MHD_request_get_information (request, \ - info_type, \ - return_value) \ - MHD_request_get_information_sz ((request), (info_type), (return_value), \ - sizeof(union MHD_RequestInformation)) +#define MHD_stream_get_info_dynamic(stream,info_type,return_value) \ + MHD_stream_get_info_dynamic_sz ((stream),(info_type),(return_value), \ + sizeof(*(return_value))) /** - * Values of this enum are used to specify what - * information about a daemon is desired. + * Select which fixed information about request is desired. + * This information is not changed during the lifetime of the request. */ -enum MHD_DaemonInformationType +enum MHD_FIXED_ENUM_APP_SET_ MHD_RequestInfoFixedType { - /** - * Request the file descriptor for the listening socket. - * No extra arguments should be passed. + * Return which stream the request is associated with. + * The result is placed in @a v_stream member. */ - MHD_DAEMON_INFORMATION_LISTEN_SOCKET, - + MHD_REQUEST_INFO_FIXED_STREAM = 1 + , /** - * Request the file descriptor for the external epoll. - * No extra arguments should be passed. + * Return which connection is associated with the stream which is associated + * with the request. + * The result is placed in @a v_connection member. */ - MHD_DAEMON_INFORMATION_EPOLL_FD, - + MHD_REQUEST_INFO_FIXED_CONNECTION = 2 + , /** - * Request the number of current connections handled by the daemon. - * No extra arguments should be passed. - * Note: when using MHD in external polling mode, this type of request - * could be used only when #MHD_run()/#MHD_run_from_select is not - * working in other thread at the same time. + * Return MHD daemon to which the request belongs to. + * The result is placed in @a v_daemon member. + */ + MHD_REQUEST_INFO_FIXED_DAEMON = 3 + , + /** + * Get the version of HTTP protocol used for the request. + * The result is placed in @a v_http_ver member. + * @ingroup request + */ + MHD_REQUEST_INFO_FIXED_HTTP_VER = 4 + , + /** + * Get the HTTP method used for the request (as a enum). + * The result is placed in @a v_http_method member. + * @sa #MHD_REQUEST_INFO_DYNAMIC_HTTP_METHOD_STR + * @ingroup request */ - MHD_DAEMON_INFORMATION_CURRENT_CONNECTIONS, + MHD_REQUEST_INFO_FIXED_HTTP_METHOD = 4 + , + /* * Sentinel * */ /** - * Request the port number of daemon's listen socket. - * No extra arguments should be passed. - * Note: if port '0' was specified for #MHD_option_port(), returned - * value will be real port number. + * The sentinel value. + * This value enforces specific underlying integer type for the enum. + * Do not use. */ - MHD_DAEMON_INFORMATION_BIND_PORT + MHD_REQUEST_INFO_FIXED_SENTINEL = 65535 }; /** - * Information about an MHD daemon. + * Fixed information about a request. */ -union MHD_DaemonInformation +union MHD_RequestInfoFixedData { /** - * Socket, returned for #MHD_DAEMON_INFORMATION_LISTEN_SOCKET. + * The MHD stream handler type. */ - MHD_socket listen_socket; + struct MHD_Stream *v_stream; /** - * Bind port number, returned for #MHD_DAEMON_INFORMATION_BIND_PORT. + * The MHD connection handler type. */ - uint16_t port; + struct MHD_Connection *v_connection; /** - * epoll FD, returned for #MHD_DAEMON_INFORMATION_EPOLL_FD. + * The MHD daemon handler type. */ - int epoll_fd; + struct MHD_Daemon *v_daemon; /** - * Number of active connections, for #MHD_DAEMON_INFORMATION_CURRENT_CONNECTIONS. + * The HTTP version type. */ - unsigned int num_connections; + enum MHD_HTTP_Version v_http_ver; + /** + * The HTTP method type. + */ + enum MHD_HTTP_Method v_http_method; }; - /** - * Obtain information about the given daemon. - * Use wrapper macro #MHD_daemon_get_information() instead of direct use - * of this function. + * Obtain fixed information about the given request. + * This information is not changed for the lifetime of the request. + * The wrapper macro #MHD_request_get_info_fixed() could be more convenient. * - * @param daemon what daemon to get information about - * @param info_type what information is desired? + * @param request the request to get information about + * @param info_type the type of information requested * @param[out] return_value pointer to union where requested information will * be stored - * @param return_value_size size of union MHD_DaemonInformation at compile - * time - * @return #MHD_YES on success, #MHD_NO on error - * (@a info_type is unknown, NULL pointer etc.) + * @param return_value_size the size of the memory area pointed + * by @a return_data, in bytes + * @return #MHD_SC_OK if succeed, + * error code otherwise * @ingroup specialized */ -_MHD_EXTERN enum MHD_Bool -MHD_daemon_get_information_sz (struct MHD_Daemon *daemon, - enum MHD_DaemonInformationType info_type, - union MHD_DaemonInformation *return_value, +MHD_EXTERN_ enum MHD_StatusCode +MHD_request_get_info_fixed_sz (struct MHD_Request *request, + enum MHD_RequestInfoFixedType info_type, + union MHD_RequestInfoFixedData *return_value, size_t return_value_size) -MHD_FUNC_PARAM_NONNULL_ (1,3); +MHD_FN_PAR_NONNULL_ (1) +MHD_FN_PAR_NONNULL_ (3) MHD_FN_PAR_INOUT_SIZE_(3,4) +MHD_FN_PURE_; + /** - * Obtain information about the given daemon. + * Obtain fixed information about the given request. + * This information is not changed for the lifetime of the request. * - * @param daemon what daemon to get information about - * @param info_type what information is desired? + * @param request the request to get information about + * @param info_type the type of information requested * @param[out] return_value pointer to union where requested information will * be stored - * @return #MHD_YES on success, #MHD_NO on error - * (@a info_type is unknown, NULL pointer etc.) + * @return #MHD_SC_OK if succeed, + * error code otherwise * @ingroup specialized */ -#define MHD_daemon_get_information(daemon, \ - info_type, \ - return_value) \ - MHD_daemon_get_information_sz ((daemon), (info_type), (return_value), \ - sizeof(union MHD_DaemonInformation)); - - -/** - * Callback for serious error condition. The default action is to print - * an error message and `abort()`. - * - * @param cls user specified value - * @param file where the error occurred - * @param line where the error occurred - * @param reason error detail, may be NULL - * @ingroup logging - */ -typedef void -(*MHD_PanicCallback) (void *cls, - const char *file, - unsigned int line, - const char *reason); - - -/** - * Sets the global error handler to a different implementation. @a cb - * will only be called in the case of typically fatal, serious - * internal consistency issues. These issues should only arise in the - * case of serious memory corruption or similar problems with the - * architecture. While @a cb is allowed to return and MHD will then - * try to continue, this is never safe. - * - * The default implementation that is used if no panic function is set - * simply prints an error message and calls `abort()`. Alternative - * implementations might call `exit()` or other similar functions. - * - * @param cb new error handler - * @param cls passed to @a cb - * @ingroup logging - */ -_MHD_EXTERN void -MHD_set_panic_func (MHD_PanicCallback cb, - void *cls); - - -/** - * Process escape sequences ('%HH') Updates val in place; the - * result should be UTF-8 encoded and cannot be larger than the input. - * The result must also still be 0-terminated. - * - * @param val value to unescape (modified in the process) - * @return length of the resulting val (`strlen(val)` may be - * shorter afterwards due to elimination of escape sequences) - */ -_MHD_EXTERN size_t -MHD_http_unescape (char *val) -MHD_FUNC_PARAM_NONNULL_ (1); +#define MHD_request_get_info_fixed(request,info_type,return_value) \ + MHD_request_get_info_fixed_sz ((request), (info_type), (return_value), \ + sizeof(*(return_value))) /** - * Types of information about MHD features, - * used by #MHD_is_feature_supported(). + * Select which dynamic information about request is desired. + * This information may be changed during the lifetime of the request. + * Any returned string pointers are valid only until a response is provided. */ -enum MHD_Feature +enum MHD_FIXED_ENUM_APP_SET_ MHD_RequestInfoDynamicType { /** - * Get whether messages are supported. If supported then in debug - * mode messages can be printed to stderr or to external logger. + * Get the HTTP method used for the request (as a MHD_String). + * The result is placed in @a v_str member. + * The resulting string pointer in valid only until a response is provided. + * @sa #MHD_REQUEST_INFO_FIXED_HTTP_METHOD + * @ingroup request */ - MHD_FEATURE_MESSAGES = 1, - + MHD_REQUEST_INFO_DYNAMIC_HTTP_METHOD_STR = 1 + , /** - * Get whether HTTPS is supported. If supported then flag - * #MHD_USE_TLS and options #MHD_OPTION_HTTPS_MEM_KEY, - * #MHD_OPTION_HTTPS_MEM_CERT, #MHD_OPTION_HTTPS_MEM_TRUST, - * #MHD_OPTION_HTTPS_MEM_DHPARAMS, #MHD_OPTION_HTTPS_CRED_TYPE, - * #MHD_OPTION_HTTPS_PRIORITIES can be used. + * Get the URI used for the request (as a MHD_String), excluding + * the parameter part (anything after '?'). + * The result is placed in @a v_str member. + * The resulting string pointer in valid only until a response is provided. + * @ingroup request */ - MHD_FEATURE_TLS = 2, - + MHD_REQUEST_INFO_DYNAMIC_URI = 2 + , /** - * Get whether option #MHD_OPTION_HTTPS_CERT_CALLBACK is - * supported. + * Get the number of GET parameters (the decoded part of the origianl + * URI string after '?') + * The result is placed in @a v_sizet member. + * @ingroup request */ - MHD_FEATURE_HTTPS_CERT_CALLBACK = 3, - + MHD_REQUEST_INFO_DYNAMIC_NUMBER_GET_PARAMS = 3 + , /** - * Get whether IPv6 is supported. If supported then flag - * #MHD_USE_IPv6 can be used. + * Get the number of cookies in the request. + * The result is placed in @a v_sizet member. + * @ingroup request */ - MHD_FEATURE_IPv6 = 4, - + MHD_REQUEST_INFO_DYNAMIC_NUMBER_COOKIES = 4 + , /** - * Get whether IPv6 without IPv4 is supported. If not supported - * then IPv4 is always enabled in IPv6 sockets and - * flag #MHD_USE_DUAL_STACK if always used when #MHD_USE_IPv6 is - * specified. + * Get the number of decoded POST entries in the request. + * The result is placed in @a v_sizet member. + * @ingroup request */ - MHD_FEATURE_IPv6_ONLY = 5, - + MHD_REQUEST_INFO_DYNAMIC_NUMBER_POST_PARAMS = 5 + , /** - * Get whether `poll()` is supported. If supported then flag - * #MHD_USE_POLL can be used. + * Get whether the upload content is present in the request. + * The result is #MHD_YES if any upload content is present, even + * if the upload content size is zero. + * The result is placed in @a v_bool member. + * @ingroup request */ - MHD_FEATURE_POLL = 6, - + MHD_REQUEST_INFO_DYNAMIC_UPLOAD_PRESENT = 10 + , /** - * Get whether `epoll()` is supported. If supported then Flags - * #MHD_USE_EPOLL and - * #MHD_USE_EPOLL_INTERNAL_THREAD can be used. + * Get the total content upload size. + * Resulted in zero if no content upload or upload content size is zero, + * #MHD_SIZE_UNKNOWN if size is not known (chunked upload). + * The result is placed in @a v_uint64 member. + * @ingroup request */ - MHD_FEATURE_EPOLL = 7, - + MHD_REQUEST_INFO_DYNAMIC_UPLOAD_SIZE_TOTAL = 11 + , /** - * Get whether shutdown on listen socket to signal other - * threads is supported. If not supported flag - * #MHD_USE_ITC is automatically forced. + * Get the total size of the content upload already received from the client. + * This is the total size received, could be not yet fully processed by the + * application. + * The result is placed in @a v_uint64 member. + * @ingroup request */ - MHD_FEATURE_SHUTDOWN_LISTEN_SOCKET = 8, - + MHD_REQUEST_INFO_DYNAMIC_UPLOAD_SIZE_RECIEVED = 12 + , /** - * Get whether socketpair is used internally instead of pipe to - * signal other threads. + * Get the total size of the content upload left to be received from + * the client. + * Resulted in #MHD_SIZE_UNKNOWN if total size is not known (chunked upload). + * The result is placed in @a v_uint64 member. + * @ingroup request */ - MHD_FEATURE_SOCKETPAIR = 9, - + MHD_REQUEST_INFO_DYNAMIC_UPLOAD_SIZE_TO_RECIEVE = 13 + , /** - * Get whether TCP Fast Open is supported. If supported then - * flag #MHD_USE_TCP_FASTOPEN and option - * #MHD_OPTION_TCP_FASTOPEN_QUEUE_SIZE can be used. + * Get the total size of the content upload already processed (upload callback + * called and completed (if any)). + * If the value is requested from #MHD_UploadCallback, then result does NOT + * include the current data being processed by the callback. + * The result is placed in @a v_uint64 member. + * @ingroup request */ - MHD_FEATURE_TCP_FASTOPEN = 10, - + MHD_REQUEST_INFO_DYNAMIC_UPLOAD_SIZE_PROCESSED = 12 + , /** - * Get whether HTTP Basic authorization is supported. If supported - * then functions #MHD_basic_auth_get_username_password and - * #MHD_queue_basic_auth_fail_response can be used. + * Get the total size of the content upload left to be processed. + * The resulting value includes the size of the data not yet received from + * the client. + * If the value is requested from #MHD_UploadCallback, then result includes + * the current data being processed by the callback. + * Resulted in #MHD_SIZE_UNKNOWN if total size is not known (chunked upload). + * The result is placed in @a v_uint64 member. + * @ingroup request */ - MHD_FEATURE_BASIC_AUTH = 11, - + MHD_REQUEST_INFO_DYNAMIC_UPLOAD_SIZE_TO_PROCESS = 13 + , /** - * Get whether HTTP Digest authorization is supported. If - * supported then options #MHD_OPTION_DIGEST_AUTH_RANDOM, - * #MHD_OPTION_NONCE_NC_SIZE and - * #MHD_digest_auth_check() can be used. + * Return length of the client's HTTP request header. + * This is a total raw size of the header (after TLS decipher if any) + * The result is placed in @a v_sizet member. + * @ingroup request */ - MHD_FEATURE_DIGEST_AUTH = 12, + MHD_REQUEST_INFO_DYNAMIC_HEADER_SIZE = 21 + , /** - * Get whether postprocessor is supported. If supported then - * functions #MHD_create_post_processor(), #MHD_post_process() and - * #MHD_destroy_post_processor() can - * be used. + * Returns the client-specific pointer to a `void *` that + * is specific to this request. // TODO: check reference + * The result is placed in @a v_pvoid member. */ - MHD_FEATURE_POSTPROCESSOR = 13, + MHD_REQUEST_INFO_DYNAMIC_CLIENT_CONTEXT = 31 + , /** - * Get whether password encrypted private key for HTTPS daemon is - * supported. If supported then option - * ::MHD_OPTION_HTTPS_KEY_PASSWORD can be used. - */ - MHD_FEATURE_HTTPS_KEY_PASSWORD = 14, - + * Returns pointer to information about username in client's digest auth + * request. + * The resulting pointer is NULL if no digest auth header is set by + * the client, the format of the digest auth header is broken, no + * username is provided or the format of the username parameter is broken. + * Pointers in the returned structure (if any) are valid until response + * is provided for the request. + * The result is placed in @a v_dauth_username member. + */ + MHD_REQUEST_INFO_DYNAMIC_DAUTH_USERNAME_INFO = 41 + , /** - * Get whether reading files beyond 2 GiB boundary is supported. - * If supported then #MHD_create_response_from_fd(), - * #MHD_create_response_from_fd64 #MHD_create_response_from_fd_at_offset() - * and #MHD_create_response_from_fd_at_offset64() can be used with sizes and - * offsets larger than 2 GiB. If not supported value of size+offset is - * limited to 2 GiB. + * Returns pointer to information about digest auth in client request. + * The resulting pointer is NULL if no digest auth header is set by + * the client or the format of the digest auth header is broken. + * Pointers in the returned structure (if any) are valid until response + * is provided for the request. + * The result is placed in @a v_dauth_info member. */ - MHD_FEATURE_LARGE_FILE = 15, - + MHD_REQUEST_INFO_DYNAMIC_DAUTH_REQ_INFO = 42 + , /** - * Get whether MHD set names on generated threads. + * Returns pointer to information about basic auth in client request. + * The resulting pointer is NULL if no basic auth header is set by + * the client or the format of the basic auth header is broken. + * Pointers in the returned structure (if any) are valid until response + * is provided for the request. + * The result is placed in @a v_bauth_info member. */ - MHD_FEATURE_THREAD_NAMES = 16, + MHD_REQUEST_INFO_DYNAMIC_BAUTH_REQ_INFO = 51 + , + /* * Sentinel * */ /** - * Get whether HTTP "Upgrade" is supported. - * If supported then #MHD_ALLOW_UPGRADE, #MHD_upgrade_action() and - * #MHD_create_response_for_upgrade() can be used. + * The sentinel value. + * This value enforces specific underlying integer type for the enum. + * Do not use. */ - MHD_FEATURE_UPGRADE = 17, + MHD_REQUEST_INFO_DYNAMIC_SENTINEL = 65535 +}; + + +/** + * Dynamic information about a request. + */ +union MHD_RequestInfoDynamicData +{ /** - * Get whether it's safe to use same FD for multiple calls of - * #MHD_create_response_from_fd() and whether it's safe to use single - * response generated by #MHD_create_response_from_fd() with multiple - * connections at same time. - * If #MHD_is_feature_supported() return #MHD_NO for this feature then - * usage of responses with same file FD in multiple parallel threads may - * results in incorrect data sent to remote client. - * It's always safe to use same file FD in multiple responses if MHD - * is run in any single thread mode. + * The MHD String type + */ + struct MHD_String v_str; + /** + * The size_t type + */ + size_t v_sizet; + /** + * The boolean type + */ + enum MHD_Bool v_bool; + /** + * The unsigned 64 bits integer */ - MHD_FEATURE_RESPONSES_SHARED_FD = 18, + uint_fast64_t v_uint64; + /** + * The pointer to void + */ + void *v_pvoid; /** - * Get whether MHD support automatic detection of bind port number. - * @sa #MHD_DAEMON_INFO_BIND_PORT + * The information about client provided username for digest auth */ - MHD_FEATURE_AUTODETECT_BIND_PORT = 19, + struct MHD_DigestAuthUsernameInfo *v_dauth_username; /** - * Get whether MHD support SIGPIPE suppression. - * If SIGPIPE suppression is not supported, application must handle - * SIGPIPE signal by itself. + * The information about client's digest auth */ - MHD_FEATURE_AUTOSUPPRESS_SIGPIPE = 20, + struct MHD_DigestAuthInfo *v_dauth_info; /** - * Get whether MHD use system's sendfile() function to send - * file-FD based responses over non-TLS connections. - * @note Since v0.9.56 + * The information about client's basic auth */ - MHD_FEATURE_SENDFILE = 21 + struct MHD_BasicAuthInfo *v_bauth_info; }; /** - * Get information about supported MHD features. - * Indicate that MHD was compiled with or without support for - * particular feature. Some features require additional support - * by kernel. Kernel support is not checked by this function. + * Obtain dynamic information about the given request. + * This information may be changed during the lifetime of the request. + * The wrapper macro #MHD_request_get_info_dynamic() could be more convenient. * - * @param feature type of requested information - * @return #MHD_YES if feature is supported by MHD, #MHD_NO if - * feature is not supported or feature is unknown. + * @param request the request to get information about + * @param info_type the type of information requested + * @param[out] return_value pointer to union where requested information will + * be stored + * @param return_value_size the size of the memory area pointed + * by @a return_data, in bytes + * @return #MHD_SC_OK if succeed, + * error code otherwise * @ingroup specialized */ -_MHD_EXTERN enum MHD_Bool -MHD_is_feature_supported (enum MHD_Feature feature); +MHD_EXTERN_ enum MHD_StatusCode +MHD_request_get_info_dynamic_sz (struct MHD_Request *request, + enum MHD_RequestInfoDynamicType info_type, + union MHD_RequestInfoDynamicData *return_value, + size_t return_value_size) +MHD_FN_PAR_NONNULL_ (1) +MHD_FN_PAR_NONNULL_ (3) MHD_FN_PAR_INOUT_SIZE_(3,4) +MHD_FN_PURE_; /** - * What is this request waiting for? + * Obtain dynamic information about the given request. + * This information may be changed during the lifetime of the request. + * + * @param request the request to get information about + * @param info_type the type of information requested + * @param[out] return_value pointer to union where requested information will + * be stored + * @return #MHD_SC_OK if succeed, + * error code otherwise + * @ingroup specialized */ -enum MHD_RequestEventLoopInfo -{ - /** - * We are waiting to be able to read. - */ - MHD_EVENT_LOOP_INFO_READ = 0, +#define MHD_request_get_info_dynamic(request,info_type,return_value) \ + MHD_request_get_info_dynamic_sz ((request), (info_type), (return_value), \ + sizeof(*(return_value))) - /** - * We are waiting to be able to write. - */ - MHD_EVENT_LOOP_INFO_WRITE = 1, +/** + * Callback for serious error condition. The default action is to print + * an error message and `abort()`. + * The callback should not return. + * + * @param cls user specified value + * @param file where the error occurred, could be NULL if MHD built without + * messages (only for embedded project) + * @param line where the error occurred + * @param reason error detail, may be NULL + * @ingroup logging + */ +typedef void +(*MHD_PanicCallback) (void *cls, + const char *file, + unsigned int line, + const char *reason); - /** - * We are waiting for the application to provide data. - */ - MHD_EVENT_LOOP_INFO_BLOCK = 2, - /** - * We are finished and are awaiting cleanup. - */ - MHD_EVENT_LOOP_INFO_CLEANUP = 3 -}; +/** + * Sets the global error handler to a different implementation. + * The @a cb will only be called in the case of typically fatal, serious + * internal consistency issues. + * These issues should only arise in the case of serious memory corruption or + * similar problems with the architecture. + * The @a cb should not return. + * + * The default implementation that is used if no panic function is set + * simply prints an error message and calls `abort()`. Alternative + * implementations might call `exit()` or other similar functions. + * + * @param cb new error handler, NULL to reset to default handler + * @param cls passed to @a cb + * @ingroup logging + */ +MHD_EXTERN_ void +MHD_lib_set_panic_func (MHD_PanicCallback cb, + void *cls); + +#define MHD_lib_set_panic_func_default() \ + MHD_lib_set_panic_func (MHD_STATIC_CAST_(MHD_PanicCallback,NULL),NULL) #endif