commit 312713c3634aa22d538c09d0146b5ac1d62c206b
parent 83a86be948420f7bd902ceee9d661fc208eec1cd
Author: Christian Grothoff <christian@grothoff.org>
Date: Mon, 8 Apr 2019 15:12:45 +0200
merge
Diffstat:
16 files changed, 648 insertions(+), 209 deletions(-)
diff --git a/ChangeLog b/ChangeLog
@@ -2,6 +2,25 @@ Mon 08 Apr 2019 03:06:05 PM CEST
Fix close() checks as suggested by MK on the mailinglist
(#3926). -MK/CG
+Wed 20 Mar 2019 10:20:24 AM CET
+ Adding additional "value_length" argument to MHD_KeyValueIterator
+ callback to support binary zeros in values. This is done in a
+ backwards-compatible way, but may require adding a cast to existing
+ code to avoid a compiler warning. -CG
+
+Sun Feb 10 21:00:37 BRT 2019
+ Added example for how to compress a chunked HTTP response. -SC
+
+Sun 10 Feb 2019 05:03:44 PM CET
+ Releasing libmicrohttpd 0.9.63. -CG
+
+Sat 09 Feb 2019 01:51:02 PM CET
+ Extended test_get to test URI logging and query string parsing
+ to avoid regression fixed in previous patch in the future. -CG
+
+Thu Feb 7 16:16:12 CET 2019
+ Preliminary patch for the raw query string issue, to be tested. -CG
+
Tue Jan 8 02:57:21 BRT 2019
Added minimal example for how to compress HTTP response. -SC
diff --git a/configure.ac b/configure.ac
@@ -22,15 +22,15 @@
#
AC_PREREQ([2.64])
LT_PREREQ([2.4.0])
-AC_INIT([GNU Libmicrohttpd],[0.9.62],[libmicrohttpd@gnu.org])
+AC_INIT([GNU Libmicrohttpd],[0.9.63],[libmicrohttpd@gnu.org])
AC_CONFIG_AUX_DIR([build-aux])
AM_INIT_AUTOMAKE([silent-rules] [subdir-objects])
AC_CONFIG_HEADERS([MHD_config.h])
AC_CONFIG_MACRO_DIR([m4])
-LIB_VERSION_CURRENT=61
+LIB_VERSION_CURRENT=62
LIB_VERSION_REVISION=0
-LIB_VERSION_AGE=49
+LIB_VERSION_AGE=50
AC_SUBST(LIB_VERSION_CURRENT)
AC_SUBST(LIB_VERSION_REVISION)
AC_SUBST(LIB_VERSION_AGE)
diff --git a/doc/examples/logging.c b/doc/examples/logging.c
@@ -15,11 +15,16 @@
static int
-print_out_key (void *cls, enum MHD_ValueKind kind, const char *key,
- const char *value)
+print_out_key (void *cls,
+ enum MHD_ValueKind kind,
+ const char *key,
+ const char *value,
+ size_t value_size)
{
- (void)cls; /* Unused. Silent compiler warning. */
- (void)kind; /* Unused. Silent compiler warning. */
+ (void) cls; /* Unused. Silent compiler warning. */
+ (void) kind; /* Unused. Silent compiler warning. */
+ (void) value_size;
+
printf ("%s: %s\n", key, value);
return MHD_YES;
}
@@ -38,7 +43,9 @@ answer_to_connection (void *cls, struct MHD_Connection *connection,
(void)con_cls; /* Unused. Silent compiler warning. */
printf ("New %s request for %s using version %s\n", method, url, version);
- MHD_get_connection_values (connection, MHD_HEADER_KIND, print_out_key,
+ MHD_get_connection_values (connection,
+ MHD_HEADER_KIND,
+ &print_out_key,
NULL);
return MHD_NO;
diff --git a/doc/libmicrohttpd.texi b/doc/libmicrohttpd.texi
@@ -1356,7 +1356,7 @@ reason for request termination see @code{MHD_OPTION_NOTIFY_COMPLETED}.
@end deftypefn
-@deftypefn {Function Pointer} int {*MHD_KeyValueIterator} (void *cls, enum MHD_ValueKind kind, const char *key, const char *value)
+@deftypefn {Function Pointer} int {*MHD_KeyValueIterator} (void *cls, enum MHD_ValueKind kind, const char *key, const char *value, size_t value_size)
Iterator over key-value pairs. This iterator can be used to iterate
over all of the cookies, headers, or @code{POST}-data fields of a
request, and also to iterate over the headers that have been added to a
@@ -1375,6 +1375,17 @@ key for the value, can be an empty string
@item value
value corresponding value, can be NULL
+@item value_size
+number of bytes in @code{value}. This argument was introduced in
+@code{MHD_VERSION} 0x00096301 to allow applications to use binary
+zeros in values. Applications using this argument must ensure that
+they are using a sufficiently recent version of MHD, i.e. by testing
+@code{MHD_get_version()} for values above or equal to 0.9.64.
+Applications that do not need zeros in values and that want to compile
+without warnings against newer versions of MHD should not declare this
+argument and cast the function pointer argument to
+@code{MHD_KeyValueIterator}.
+
@end table
Return @code{MHD_YES} to continue iterating, @code{MHD_NO} to abort the
diff --git a/po/libmicrohttpd.pot b/po/libmicrohttpd.pot
@@ -6,9 +6,9 @@
#, fuzzy
msgid ""
msgstr ""
-"Project-Id-Version: GNU libmicrohttpd 0.9.62\n"
+"Project-Id-Version: GNU libmicrohttpd 0.9.63\n"
"Report-Msgid-Bugs-To: libmicrohttpd@gnu.org\n"
-"POT-Creation-Date: 2018-12-08 23:11+0100\n"
+"POT-Creation-Date: 2019-02-10 17:12+0100\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
@@ -37,53 +37,53 @@ msgstr ""
msgid "Failed to close FD.\n"
msgstr ""
-#: src/microhttpd/digestauth.c:563
+#: src/microhttpd/digestauth.c:599
msgid ""
"Stale nonce received. If this happens a lot, you should probably increase "
"the size of the nonce array.\n"
msgstr ""
-#: src/microhttpd/digestauth.c:755
+#: src/microhttpd/digestauth.c:792
msgid "Failed to allocate memory for copy of URI arguments\n"
msgstr ""
-#: src/microhttpd/digestauth.c:893
+#: src/microhttpd/digestauth.c:932
msgid "Authentication failed, invalid timestamp format.\n"
msgstr ""
-#: src/microhttpd/digestauth.c:956
+#: src/microhttpd/digestauth.c:995
msgid "Authentication failed, invalid format.\n"
msgstr ""
-#: src/microhttpd/digestauth.c:966
+#: src/microhttpd/digestauth.c:1005
msgid "Authentication failed, invalid nc format.\n"
msgstr ""
-#: src/microhttpd/digestauth.c:992
+#: src/microhttpd/digestauth.c:1031
msgid "Failed to allocate memory for auth header processing\n"
msgstr ""
-#: src/microhttpd/digestauth.c:1049
+#: src/microhttpd/digestauth.c:1090
msgid "Authentication failed, URI does not match.\n"
msgstr ""
-#: src/microhttpd/digestauth.c:1069
+#: src/microhttpd/digestauth.c:1109
msgid "Authentication failed, arguments do not match.\n"
msgstr ""
-#: src/microhttpd/digestauth.c:1224
+#: src/microhttpd/digestauth.c:1264
msgid "digest size missmatch"
msgstr ""
-#: src/microhttpd/digestauth.c:1314
+#: src/microhttpd/digestauth.c:1356
msgid "Could not register nonce (is the nonce array size zero?).\n"
msgstr ""
-#: src/microhttpd/digestauth.c:1339
+#: src/microhttpd/digestauth.c:1381
msgid "Failed to allocate memory for auth response header\n"
msgstr ""
-#: src/microhttpd/digestauth.c:1375
+#: src/microhttpd/digestauth.c:1417
msgid "Failed to add Digest auth header\n"
msgstr ""
@@ -126,7 +126,7 @@ msgid ""
"unsupported.\n"
msgstr ""
-#: src/microhttpd/daemon.c:1279 src/microhttpd/daemon.c:6454
+#: src/microhttpd/daemon.c:1279 src/microhttpd/daemon.c:6469
msgid ""
"Initiated daemon shutdown while \"upgraded\" connection was not closed.\n"
msgstr ""
@@ -180,7 +180,7 @@ msgstr ""
msgid "PSK authentication failed: gnutls_malloc failed to allocate memory\n"
msgstr ""
-#: src/microhttpd/daemon.c:2318 src/microhttpd/daemon.c:6104
+#: src/microhttpd/daemon.c:2318 src/microhttpd/daemon.c:6113
#, c-format
msgid "Socket descriptor larger than FD_SETSIZE: %d > %d\n"
msgstr ""
@@ -190,7 +190,7 @@ msgstr ""
msgid "Failed to set SO_NOSIGPIPE on accepted socket: %s\n"
msgstr ""
-#: src/microhttpd/daemon.c:2351 src/microhttpd/daemon.c:3155
+#: src/microhttpd/daemon.c:2351 src/microhttpd/daemon.c:3164
#, c-format
msgid "Accepted connection on socket %d\n"
msgstr ""
@@ -204,7 +204,7 @@ msgid "Connection rejected by application. Closing connection.\n"
msgstr ""
#: src/microhttpd/daemon.c:2414 src/microhttpd/daemon.c:2434
-#: src/microhttpd/daemon.c:3741
+#: src/microhttpd/daemon.c:3750
#, c-format
msgid "Error allocating memory: %s\n"
msgstr ""
@@ -218,9 +218,9 @@ msgstr ""
msgid "Unknown credential type"
msgstr ""
-#: src/microhttpd/daemon.c:2607 src/microhttpd/daemon.c:4231
-#: src/microhttpd/daemon.c:4264 src/microhttpd/daemon.c:5409
-#: src/microhttpd/daemon.c:5426 src/microhttpd/connection.c:3867
+#: src/microhttpd/daemon.c:2607 src/microhttpd/daemon.c:4240
+#: src/microhttpd/daemon.c:4273 src/microhttpd/daemon.c:5418
+#: src/microhttpd/daemon.c:5435 src/microhttpd/connection.c:3857
#: src/microhttpd/response.c:968 src/microhttpd/response.c:994
#, c-format
msgid "Call to epoll_ctl failed: %s\n"
@@ -230,9 +230,9 @@ msgstr ""
msgid "Failed to signal new connection via inter-thread communication channel."
msgstr ""
-#: src/microhttpd/daemon.c:2737 src/microhttpd/daemon.c:3239
-#: src/microhttpd/daemon.c:6350 src/microhttpd/connection.c:992
-#: src/microhttpd/connection.c:1011
+#: src/microhttpd/daemon.c:2737 src/microhttpd/daemon.c:3248
+#: src/microhttpd/daemon.c:6359 src/microhttpd/connection.c:979
+#: src/microhttpd/connection.c:998
msgid "Failed to remove FD from epoll set\n"
msgstr ""
@@ -266,474 +266,478 @@ msgstr ""
msgid "Failed to set noninheritable mode on new client socket.\n"
msgstr ""
-#: src/microhttpd/daemon.c:3093
+#: src/microhttpd/daemon.c:3029
+msgid "Failed to reset buffering mode on new client socket.\n"
+msgstr ""
+
+#: src/microhttpd/daemon.c:3102
#, c-format
msgid "Error accepting connection: %s\n"
msgstr ""
-#: src/microhttpd/daemon.c:3110
+#: src/microhttpd/daemon.c:3119
msgid ""
"Hit process or system resource limit at FIRST connection. This is really bad "
"as there is no sane way to proceed. Will try busy waiting for system "
"resources to become magically available.\n"
msgstr ""
-#: src/microhttpd/daemon.c:3124
+#: src/microhttpd/daemon.c:3133
#, c-format
msgid ""
"Hit process or system resource limit at %u connections, temporarily "
"suspending accept(). Consider setting a lower MHD_OPTION_CONNECTION_LIMIT.\n"
msgstr ""
-#: src/microhttpd/daemon.c:3136
+#: src/microhttpd/daemon.c:3145
#, c-format
msgid "Failed to set nonblocking mode on incoming connection socket: %s\n"
msgstr ""
-#: src/microhttpd/daemon.c:3148
+#: src/microhttpd/daemon.c:3157
msgid "Failed to set noninheritable mode on incoming connection socket.\n"
msgstr ""
-#: src/microhttpd/daemon.c:3196 src/microhttpd/daemon.c:6496
-#: src/microhttpd/daemon.c:6528 src/microhttpd/daemon.c:6628
+#: src/microhttpd/daemon.c:3205 src/microhttpd/daemon.c:6511
+#: src/microhttpd/daemon.c:6543 src/microhttpd/daemon.c:6643
msgid "Failed to join a thread\n"
msgstr ""
-#: src/microhttpd/daemon.c:3300
+#: src/microhttpd/daemon.c:3309
msgid "Illegal call to MHD_get_timeout\n"
msgstr ""
-#: src/microhttpd/daemon.c:3497
+#: src/microhttpd/daemon.c:3506
msgid ""
"MHD_run_from_select() called with except_fd_set set to NULL. Such behavior "
"is deprecated.\n"
msgstr ""
-#: src/microhttpd/daemon.c:3577
+#: src/microhttpd/daemon.c:3586
msgid "Could not obtain daemon fdsets"
msgstr ""
-#: src/microhttpd/daemon.c:3594
+#: src/microhttpd/daemon.c:3603
msgid "Could not add listen socket to fdset"
msgstr ""
-#: src/microhttpd/daemon.c:3622
+#: src/microhttpd/daemon.c:3631
msgid "Could not add control inter-thread communication channel FD to fdset"
msgstr ""
-#: src/microhttpd/daemon.c:3678
+#: src/microhttpd/daemon.c:3687
#, c-format
msgid "select failed: %s\n"
msgstr ""
-#: src/microhttpd/daemon.c:3823 src/microhttpd/daemon.c:3970
+#: src/microhttpd/daemon.c:3832 src/microhttpd/daemon.c:3979
#, c-format
msgid "poll failed: %s\n"
msgstr ""
-#: src/microhttpd/daemon.c:4100 src/microhttpd/daemon.c:4331
+#: src/microhttpd/daemon.c:4109 src/microhttpd/daemon.c:4340
#, c-format
msgid "Call to epoll_wait failed: %s\n"
msgstr ""
-#: src/microhttpd/daemon.c:4283 src/microhttpd/daemon.c:4740
+#: src/microhttpd/daemon.c:4292 src/microhttpd/daemon.c:4749
msgid "Failed to remove listen FD from epoll set\n"
msgstr ""
-#: src/microhttpd/daemon.c:4748
+#: src/microhttpd/daemon.c:4757
msgid "Failed to signal quiesce via inter-thread communication channel"
msgstr ""
-#: src/microhttpd/daemon.c:4770
+#: src/microhttpd/daemon.c:4779
msgid "failed to signal quiesce via inter-thread communication channel"
msgstr ""
-#: src/microhttpd/daemon.c:4878
+#: src/microhttpd/daemon.c:4887
msgid "Warning: Too large timeout value, ignored.\n"
msgstr ""
-#: src/microhttpd/daemon.c:4919
+#: src/microhttpd/daemon.c:4928
msgid ""
"Warning: Zero size, specified for thread pool size, is ignored. Thread pool "
"is not used.\n"
msgstr ""
-#: src/microhttpd/daemon.c:4927
+#: src/microhttpd/daemon.c:4936
msgid ""
"Warning: \"1\", specified for thread pool size, is ignored. Thread pool is "
"not used.\n"
msgstr ""
-#: src/microhttpd/daemon.c:4939
+#: src/microhttpd/daemon.c:4948
#, c-format
msgid "Specified thread pool size (%u) too big\n"
msgstr ""
-#: src/microhttpd/daemon.c:4950
+#: src/microhttpd/daemon.c:4959
msgid ""
"MHD_OPTION_THREAD_POOL_SIZE option is specified but "
"MHD_USE_INTERNAL_POLLING_THREAD flag is not specified.\n"
msgstr ""
-#: src/microhttpd/daemon.c:4959
+#: src/microhttpd/daemon.c:4968
msgid ""
"Both MHD_OPTION_THREAD_POOL_SIZE option and MHD_USE_THREAD_PER_CONNECTION "
"flag are specified.\n"
msgstr ""
-#: src/microhttpd/daemon.c:4976 src/microhttpd/daemon.c:4988
-#: src/microhttpd/daemon.c:5000 src/microhttpd/daemon.c:5012
-#: src/microhttpd/daemon.c:5053 src/microhttpd/daemon.c:5081
-#: src/microhttpd/daemon.c:5100
+#: src/microhttpd/daemon.c:4985 src/microhttpd/daemon.c:4997
+#: src/microhttpd/daemon.c:5009 src/microhttpd/daemon.c:5021
+#: src/microhttpd/daemon.c:5062 src/microhttpd/daemon.c:5090
+#: src/microhttpd/daemon.c:5109
#, c-format
msgid "MHD HTTPS option %d passed to MHD but MHD_USE_TLS not set\n"
msgstr ""
-#: src/microhttpd/daemon.c:5031
+#: src/microhttpd/daemon.c:5040
msgid "Error initializing DH parameters\n"
msgstr ""
-#: src/microhttpd/daemon.c:5043
+#: src/microhttpd/daemon.c:5052
msgid "Bad Diffie-Hellman parameters format\n"
msgstr ""
-#: src/microhttpd/daemon.c:5070
+#: src/microhttpd/daemon.c:5079
#, c-format
msgid "Setting priorities to `%s' failed: %s\n"
msgstr ""
-#: src/microhttpd/daemon.c:5089
+#: src/microhttpd/daemon.c:5098
msgid ""
"MHD_OPTION_HTTPS_CERT_CALLBACK requires building MHD with GnuTLS >= 3.0\n"
msgstr ""
-#: src/microhttpd/daemon.c:5123
+#: src/microhttpd/daemon.c:5132
msgid ""
"MHD_OPTION_LISTEN_SOCKET specified for daemon with MHD_USE_NO_LISTEN_SOCKET "
"flag set.\n"
msgstr ""
-#: src/microhttpd/daemon.c:5172
+#: src/microhttpd/daemon.c:5181
msgid ""
"Flag MHD_USE_PEDANTIC_CHECKS is ignored because another behavior is "
"specified by MHD_OPTION_STRICT_CLIENT.\n"
msgstr ""
-#: src/microhttpd/daemon.c:5304
+#: src/microhttpd/daemon.c:5313
#, c-format
msgid "MHD HTTPS option %d passed to MHD compiled without GNUtls >= 3\n"
msgstr ""
-#: src/microhttpd/daemon.c:5317
+#: src/microhttpd/daemon.c:5326
#, c-format
msgid "MHD HTTPS option %d passed to MHD compiled without HTTPS support\n"
msgstr ""
-#: src/microhttpd/daemon.c:5323
+#: src/microhttpd/daemon.c:5332
#, c-format
msgid "Invalid option %d! (Did you terminate the list with MHD_OPTION_END?)\n"
msgstr ""
-#: src/microhttpd/daemon.c:5353
+#: src/microhttpd/daemon.c:5362
#, c-format
msgid "Call to epoll_create1 failed: %s\n"
msgstr ""
-#: src/microhttpd/daemon.c:5363
+#: src/microhttpd/daemon.c:5372
msgid "Failed to set noninheritable mode on epoll FD.\n"
msgstr ""
-#: src/microhttpd/daemon.c:5606
+#: src/microhttpd/daemon.c:5615
msgid ""
"Warning: MHD_USE_THREAD_PER_CONNECTION must be used only with "
"MHD_USE_INTERNAL_POLLING_THREAD. Flag MHD_USE_INTERNAL_POLLING_THREAD was "
"added. Consider setting MHD_USE_INTERNAL_POLLING_THREAD explicitly.\n"
msgstr ""
-#: src/microhttpd/daemon.c:5654
+#: src/microhttpd/daemon.c:5663
msgid "Using debug build of libmicrohttpd.\n"
msgstr ""
-#: src/microhttpd/daemon.c:5668
+#: src/microhttpd/daemon.c:5677
#, c-format
msgid "Failed to create inter-thread communication channel: %s\n"
msgstr ""
-#: src/microhttpd/daemon.c:5684
+#: src/microhttpd/daemon.c:5693
msgid ""
"file descriptor for inter-thread communication channel exceeds maximum "
"value\n"
msgstr ""
-#: src/microhttpd/daemon.c:5704
+#: src/microhttpd/daemon.c:5713
msgid "Specified value for NC_SIZE too large\n"
msgstr ""
-#: src/microhttpd/daemon.c:5718
+#: src/microhttpd/daemon.c:5727
#, c-format
msgid "Failed to allocate memory for nonce-nc map: %s\n"
msgstr ""
-#: src/microhttpd/daemon.c:5735
+#: src/microhttpd/daemon.c:5744
msgid "MHD failed to initialize nonce-nc mutex\n"
msgstr ""
-#: src/microhttpd/daemon.c:5755
+#: src/microhttpd/daemon.c:5764
msgid "MHD thread pooling only works with MHD_USE_INTERNAL_POLLING_THREAD\n"
msgstr ""
-#: src/microhttpd/daemon.c:5779
+#: src/microhttpd/daemon.c:5788
#, c-format
msgid "Failed to create socket for listening: %s\n"
msgstr ""
-#: src/microhttpd/daemon.c:5800 src/microhttpd/daemon.c:5819
-#: src/microhttpd/daemon.c:5842 src/microhttpd/daemon.c:5879
-#: src/microhttpd/daemon.c:5956 src/microhttpd/daemon.c:5987
+#: src/microhttpd/daemon.c:5809 src/microhttpd/daemon.c:5828
+#: src/microhttpd/daemon.c:5851 src/microhttpd/daemon.c:5888
+#: src/microhttpd/daemon.c:5965 src/microhttpd/daemon.c:5996
#, c-format
msgid "setsockopt failed: %s\n"
msgstr ""
-#: src/microhttpd/daemon.c:5852
+#: src/microhttpd/daemon.c:5861
msgid "Cannot allow listening address reuse: SO_REUSEPORT not defined\n"
msgstr ""
-#: src/microhttpd/daemon.c:5887
+#: src/microhttpd/daemon.c:5896
msgid ""
"Cannot disallow listening address reuse: SO_EXCLUSIVEADDRUSE not defined\n"
msgstr ""
-#: src/microhttpd/daemon.c:5967
+#: src/microhttpd/daemon.c:5976
#, c-format
msgid "Failed to bind to port %u: %s\n"
msgstr ""
-#: src/microhttpd/daemon.c:5998
+#: src/microhttpd/daemon.c:6007
#, c-format
msgid "Failed to listen for connections: %s\n"
msgstr ""
-#: src/microhttpd/daemon.c:6025
+#: src/microhttpd/daemon.c:6034
#, c-format
msgid "Failed to get listen port number: %s\n"
msgstr ""
-#: src/microhttpd/daemon.c:6035
+#: src/microhttpd/daemon.c:6044
msgid ""
"Failed to get listen port number (`struct sockaddr_storage` too small!?)\n"
msgstr ""
-#: src/microhttpd/daemon.c:6068
+#: src/microhttpd/daemon.c:6077
msgid "Unknown address family!\n"
msgstr ""
-#: src/microhttpd/daemon.c:6081
+#: src/microhttpd/daemon.c:6090
#, c-format
msgid "Failed to set nonblocking mode on listening socket: %s\n"
msgstr ""
-#: src/microhttpd/daemon.c:6123
+#: src/microhttpd/daemon.c:6132
msgid ""
"Combining MHD_USE_THREAD_PER_CONNECTION and MHD_USE_EPOLL is not supported.\n"
msgstr ""
-#: src/microhttpd/daemon.c:6137 src/microhttpd/daemon.c:6150
+#: src/microhttpd/daemon.c:6146 src/microhttpd/daemon.c:6159
msgid "MHD failed to initialize IP connection limit mutex\n"
msgstr ""
-#: src/microhttpd/daemon.c:6169
+#: src/microhttpd/daemon.c:6178
msgid "Failed to initialize TLS support\n"
msgstr ""
-#: src/microhttpd/daemon.c:6196
+#: src/microhttpd/daemon.c:6205
#, c-format
msgid "Failed to create listen thread: %s\n"
msgstr ""
-#: src/microhttpd/daemon.c:6244
+#: src/microhttpd/daemon.c:6253
#, c-format
msgid "Failed to create worker inter-thread communication channel: %s\n"
msgstr ""
-#: src/microhttpd/daemon.c:6255
+#: src/microhttpd/daemon.c:6264
msgid ""
"File descriptor for worker inter-thread communication channel exceeds "
"maximum value\n"
msgstr ""
-#: src/microhttpd/daemon.c:6280
+#: src/microhttpd/daemon.c:6289
msgid "MHD failed to initialize cleanup connection mutex\n"
msgstr ""
-#: src/microhttpd/daemon.c:6294
+#: src/microhttpd/daemon.c:6303
#, c-format
msgid "Failed to create pool thread: %s\n"
msgstr ""
-#: src/microhttpd/daemon.c:6441 src/microhttpd/daemon.c:6472
+#: src/microhttpd/daemon.c:6456 src/microhttpd/daemon.c:6487
msgid "MHD_stop_daemon() called while we have suspended connections.\n"
msgstr ""
-#: src/microhttpd/daemon.c:6481 src/microhttpd/daemon.c:6610
+#: src/microhttpd/daemon.c:6496 src/microhttpd/daemon.c:6625
msgid "Failed to signal shutdown via inter-thread communication channel"
msgstr ""
-#: src/microhttpd/daemon.c:6573
+#: src/microhttpd/daemon.c:6588
msgid "Failed to signal shutdown via inter-thread communication channel."
msgstr ""
-#: src/microhttpd/daemon.c:7040
+#: src/microhttpd/daemon.c:7055
msgid "Failed to initialize winsock\n"
msgstr ""
-#: src/microhttpd/daemon.c:7043
+#: src/microhttpd/daemon.c:7058
msgid "Winsock version 2.2 is not available\n"
msgstr ""
-#: src/microhttpd/daemon.c:7051 src/microhttpd/daemon.c:7055
+#: src/microhttpd/daemon.c:7066 src/microhttpd/daemon.c:7070
msgid "Failed to initialise multithreading in libgcrypt\n"
msgstr ""
-#: src/microhttpd/daemon.c:7060
+#: src/microhttpd/daemon.c:7075
msgid "libgcrypt is too old. MHD was compiled for libgcrypt 1.6.0 or newer\n"
msgstr ""
-#: src/microhttpd/mhd_sockets.h:248
+#: src/microhttpd/mhd_sockets.h:261
msgid "Close socket failed.\n"
msgstr ""
-#: src/microhttpd/connection.c:1117
+#: src/microhttpd/connection.c:1104
msgid "Closing connection (application reported error generating data)\n"
msgstr ""
-#: src/microhttpd/connection.c:1170
+#: src/microhttpd/connection.c:1157
msgid "Closing connection (out of memory)\n"
msgstr ""
-#: src/microhttpd/connection.c:1217
+#: src/microhttpd/connection.c:1204
msgid "Closing connection (application error generating response)\n"
msgstr ""
-#: src/microhttpd/connection.c:1799
+#: src/microhttpd/connection.c:1786
#, c-format
msgid ""
"Error processing request (HTTP response code is %u (`%s')). Closing "
"connection.\n"
msgstr ""
-#: src/microhttpd/connection.c:1825 src/microhttpd/connection.c:2810
+#: src/microhttpd/connection.c:1812 src/microhttpd/connection.c:2800
msgid "Closing connection (failed to queue response)\n"
msgstr ""
-#: src/microhttpd/connection.c:1835 src/microhttpd/connection.c:3579
-#: src/microhttpd/connection.c:3702
+#: src/microhttpd/connection.c:1822 src/microhttpd/connection.c:3569
+#: src/microhttpd/connection.c:3692
msgid "Closing connection (failed to create response header)\n"
msgstr ""
-#: src/microhttpd/connection.c:1881 src/microhttpd/connection.c:2960
-#: src/microhttpd/connection.c:3028 src/microhttpd/connection.c:3344
+#: src/microhttpd/connection.c:1868 src/microhttpd/connection.c:2950
+#: src/microhttpd/connection.c:3018 src/microhttpd/connection.c:3334
#, c-format
msgid "In function %s handling connection at state: %s\n"
msgstr ""
-#: src/microhttpd/connection.c:2093
+#: src/microhttpd/connection.c:2080
msgid "Not enough memory in pool to allocate header record!\n"
msgstr ""
-#: src/microhttpd/connection.c:2135
+#: src/microhttpd/connection.c:2122
msgid "Not enough memory in pool to parse cookies!\n"
msgstr ""
-#: src/microhttpd/connection.c:2356 src/microhttpd/connection.c:2541
+#: src/microhttpd/connection.c:2346 src/microhttpd/connection.c:2531
msgid "Application reported internal error, closing connection.\n"
msgstr ""
-#: src/microhttpd/connection.c:2409 src/microhttpd/connection.c:2486
+#: src/microhttpd/connection.c:2399 src/microhttpd/connection.c:2476
msgid ""
"Received malformed HTTP request (bad chunked encoding). Closing connection.\n"
msgstr ""
-#: src/microhttpd/connection.c:2549
+#: src/microhttpd/connection.c:2539
msgid "libmicrohttpd API violation"
msgstr ""
-#: src/microhttpd/connection.c:2564
+#: src/microhttpd/connection.c:2554
msgid ""
"WARNING: incomplete upload processing and connection not suspended may "
"result in hung connection.\n"
msgstr ""
-#: src/microhttpd/connection.c:2634
+#: src/microhttpd/connection.c:2624
msgid "Received malformed line (no colon). Closing connection.\n"
msgstr ""
-#: src/microhttpd/connection.c:2788
+#: src/microhttpd/connection.c:2778
msgid "Received HTTP 1.1 request without `Host' header.\n"
msgstr ""
-#: src/microhttpd/connection.c:2799
+#: src/microhttpd/connection.c:2789
msgid "Closing connection (failed to create response)\n"
msgstr ""
-#: src/microhttpd/connection.c:2939
+#: src/microhttpd/connection.c:2929
msgid "Socket disconnected while reading request.\n"
msgstr ""
-#: src/microhttpd/connection.c:2945
+#: src/microhttpd/connection.c:2935
msgid "Connection socket is closed due to error when reading request.\n"
msgstr ""
-#: src/microhttpd/connection.c:3054
+#: src/microhttpd/connection.c:3044
#, c-format
msgid "Failed to send data in request for %s.\n"
msgstr ""
-#: src/microhttpd/connection.c:3063
+#: src/microhttpd/connection.c:3053
#, c-format
msgid "Sent 100 continue response: `%.*s'\n"
msgstr ""
-#: src/microhttpd/connection.c:3087
+#: src/microhttpd/connection.c:3077
msgid "Connection was closed while sending response headers.\n"
msgstr ""
-#: src/microhttpd/connection.c:3128
+#: src/microhttpd/connection.c:3118
msgid "Data offset exceeds limit"
msgstr ""
-#: src/microhttpd/connection.c:3137
+#: src/microhttpd/connection.c:3127
#, c-format
msgid "Sent %d-byte DATA response: `%.*s'\n"
msgstr ""
-#: src/microhttpd/connection.c:3154
+#: src/microhttpd/connection.c:3144
#, c-format
msgid "Failed to send data in request for `%s'.\n"
msgstr ""
-#: src/microhttpd/connection.c:3182 src/microhttpd/connection.c:3210
+#: src/microhttpd/connection.c:3172 src/microhttpd/connection.c:3200
msgid "Connection was closed while sending response body.\n"
msgstr ""
-#: src/microhttpd/connection.c:3233
+#: src/microhttpd/connection.c:3223
msgid "Internal error\n"
msgstr ""
-#: src/microhttpd/connection.c:3306
+#: src/microhttpd/connection.c:3296
msgid ""
"Failed to signal end of connection via inter-thread communication channel"
msgstr ""
-#: src/microhttpd/connection.c:4053
+#: src/microhttpd/connection.c:4043
msgid "Attempted to queue response on wrong thread!\n"
msgstr ""
-#: src/microhttpd/connection.c:4064
+#: src/microhttpd/connection.c:4054
msgid ""
"Attempted 'upgrade' connection on daemon without MHD_ALLOW_UPGRADE option!\n"
msgstr ""
-#: src/microhttpd/connection.c:4073
+#: src/microhttpd/connection.c:4063
msgid "Application used invalid status code for 'upgrade' response!\n"
msgstr ""
diff --git a/src/examples/Makefile.am b/src/examples/Makefile.am
@@ -70,7 +70,8 @@ endif
if HAVE_ZLIB
noinst_PROGRAMS += \
- http_compression
+ http_compression \
+ http_chunked_compression
endif
if HAVE_W32
@@ -206,8 +207,13 @@ https_fileserver_example_LDADD = \
http_compression_SOURCES = \
http_compression.c
+http_chunked_compression_SOURCES = \
+ http_chunked_compression.c
http_compression_LDADD = \
$(top_builddir)/src/microhttpd/libmicrohttpd.la
+http_chunked_compression_LDADD = \
+ $(top_builddir)/src/microhttpd/libmicrohttpd.la
if HAVE_ZLIB
http_compression_LDADD += -lz
+ http_chunked_compression_LDADD += -lz
endif
\ No newline at end of file
diff --git a/src/examples/http_chunked_compression.c b/src/examples/http_chunked_compression.c
@@ -0,0 +1,199 @@
+/*
+ This file is part of libmicrohttpd
+ Copyright (C) 2019 Christian Grothoff (and other contributing authors)
+
+ 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
+*/
+/**
+ * @file http_chunked_compression.c
+ * @brief example for how to compress a chunked HTTP response
+ * @author Silvio Clecio (silvioprog)
+ */
+
+#include "platform.h"
+#include <zlib.h>
+#include <microhttpd.h>
+
+#define CHUNK 16384
+
+struct Holder {
+ FILE *file;
+ z_stream stream;
+ void *buf;
+};
+
+static int
+compress_buf (z_stream *strm, const void *src, size_t src_size, size_t *offset, void **dest, size_t *dest_size,
+ void *tmp)
+{
+ unsigned int have;
+ int ret;
+ int flush;
+ *dest = NULL;
+ *dest_size = 0;
+ do
+ {
+ if (src_size > CHUNK)
+ {
+ strm->avail_in = CHUNK;
+ src_size -= CHUNK;
+ flush = Z_NO_FLUSH;
+ }
+ else
+ {
+ strm->avail_in = (uInt) src_size;
+ flush = Z_SYNC_FLUSH;
+ }
+ *offset += strm->avail_in;
+ strm->next_in = (Bytef *) src;
+ do
+ {
+ strm->avail_out = CHUNK;
+ strm->next_out = tmp;
+ ret = deflate (strm, flush);
+ have = CHUNK - strm->avail_out;
+ *dest_size += have;
+ *dest = realloc (*dest, *dest_size);
+ if (NULL == *dest)
+ return MHD_NO;
+ memcpy ((*dest) + ((*dest_size) - have), tmp, have);
+ }
+ while (0 == strm->avail_out);
+ }
+ while (flush != Z_SYNC_FLUSH);
+ return (Z_OK == ret) ? MHD_YES : MHD_NO;
+}
+
+static ssize_t
+read_cb (void *cls, uint64_t pos, char *mem, size_t size)
+{
+ struct Holder *holder = cls;
+ void *src;
+ void *buf;
+ src = malloc (size);
+ if (NULL == src)
+ return MHD_CONTENT_READER_END_WITH_ERROR;
+ size = fread (src, 1, size, holder->file);
+ if (size < 0)
+ {
+ size = MHD_CONTENT_READER_END_WITH_ERROR;
+ goto done;
+ }
+ if (0 == size)
+ {
+ size = MHD_CONTENT_READER_END_OF_STREAM;
+ goto done;
+ }
+ if (MHD_YES != compress_buf (&holder->stream, src, size, &pos, &buf, &size, holder->buf))
+ size = MHD_CONTENT_READER_END_WITH_ERROR;
+ else
+ {
+ memcpy (mem, buf, size);
+ free (buf);
+ }
+done:
+ free (src);
+ return size;
+}
+
+static void
+free_cb (void *cls)
+{
+ struct Holder *holder = cls;
+ fclose (holder->file);
+ deflateEnd (&holder->stream);
+ free (holder->buf);
+ free (holder);
+}
+
+static int
+ahc_echo (void *cls, struct MHD_Connection *con, const char *url, const char *method, const char *version,
+ const char *upload_data, size_t *upload_size, void **ptr)
+{
+ struct Holder *holder;
+ struct MHD_Response *res;
+ int ret;
+ (void) cls;
+ (void) url;
+ (void) method;
+ (void) version;
+ (void) upload_data;
+ (void) upload_size;
+ if (NULL == *ptr)
+ {
+ *ptr = (void *) 1;
+ return MHD_YES;
+ }
+ *ptr = NULL;
+ holder = calloc (1, sizeof (struct Holder));
+ if (!holder)
+ return MHD_NO;
+ holder->file = fopen (__FILE__, "rb");
+ if (NULL == holder->file)
+ goto file_error;
+ ret = deflateInit(&holder->stream, Z_BEST_COMPRESSION);
+ if (ret != Z_OK)
+ goto stream_error;
+ holder->buf = malloc (CHUNK);
+ if (NULL == holder->buf)
+ goto buf_error;
+ res = MHD_create_response_from_callback (MHD_SIZE_UNKNOWN, 1024, &read_cb, holder, &free_cb);
+ if (NULL == res)
+ goto error;
+ ret = MHD_add_response_header (res, MHD_HTTP_HEADER_CONTENT_ENCODING, "deflate");
+ if (MHD_YES != ret)
+ goto res_error;
+ ret = MHD_add_response_header (res, MHD_HTTP_HEADER_CONTENT_TYPE, "text/x-c");
+ if (MHD_YES != ret)
+ goto res_error;
+ ret = MHD_queue_response (con, MHD_HTTP_OK, res);
+res_error:
+ MHD_destroy_response (res);
+ return ret;
+error:
+ free (holder->buf);
+buf_error:
+ deflateEnd (&holder->stream);
+stream_error:
+ fclose (holder->file);
+file_error:
+ free (holder);
+ return MHD_NO;
+}
+
+int
+main (int argc, char *const *argv)
+{
+ struct MHD_Daemon *d;
+ unsigned int port;
+ if ((argc != 2) ||
+ (1 != sscanf (argv[1], "%u", &port)) ||
+ (UINT16_MAX < port))
+ {
+ fprintf (stderr, "%s PORT\n", argv[0]);
+ return 1;
+ }
+ d = MHD_start_daemon (MHD_USE_AUTO | MHD_USE_INTERNAL_POLLING_THREAD, (uint16_t) port, NULL, NULL,
+ &ahc_echo, NULL,
+ MHD_OPTION_END);
+ if (NULL == d)
+ return 1;
+ if (0 == port)
+ MHD_get_daemon_info (d, MHD_DAEMON_INFO_BIND_PORT, &port);
+ fprintf (stdout, "HTTP server running at http://localhost:%u\n\nPress ENTER to stop the server ...\n", port);
+ (void) getc (stdin);
+ MHD_stop_daemon (d);
+ return 0;
+}
diff --git a/src/include/microhttpd.h b/src/include/microhttpd.h
@@ -1,6 +1,6 @@
/*
This file is part of libmicrohttpd
- Copyright (C) 2006-2018 Christian Grothoff (and other contributing authors)
+ Copyright (C) 2006--2019 Christian Grothoff (and other contributing authors)
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
@@ -126,7 +126,7 @@ typedef intptr_t ssize_t;
* Current version of the library.
* 0x01093001 = 1.9.30-1.
*/
-#define MHD_VERSION 0x00096203
+#define MHD_VERSION 0x00096301
/**
* MHD-internal return code for "YES".
@@ -1380,10 +1380,12 @@ enum MHD_OPTION
* struct MHD_Connection *c,
* char *s)
*
- * where the return value must be "strlen(s)" and "s" should be
- * updated. Note that the unescape function must not lengthen "s"
- * (the result must be shorter than the input and still be
- * 0-terminated). "cls" will be set to the second argument
+ * where the return value must be the length of the value left in
+ * "s" (without the 0-terminator) and "s" should be updated. Note
+ * that the unescape function must not lengthen "s" (the result must
+ * be shorter than the input and must still be 0-terminated).
+ * However, it may also include binary zeros before the
+ * 0-termination. "cls" will be set to the second argument
* following #MHD_OPTION_UNESCAPE_CALLBACK.
*/
MHD_OPTION_UNESCAPE_CALLBACK = 16,
@@ -2025,6 +2027,8 @@ typedef void
* @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
+ * @param value_size number of bytes in @a value, NEW since #MHD_VERSION 0x00096301;
+ * for C-strings, the length excludes the 0-terminator
* @return #MHD_YES to continue iterating,
* #MHD_NO to abort the iteration
* @ingroup request
@@ -2033,7 +2037,8 @@ typedef int
(*MHD_KeyValueIterator) (void *cls,
enum MHD_ValueKind kind,
const char *key,
- const char *value);
+ const char *value,
+ size_t value_size);
/**
@@ -2494,6 +2499,40 @@ MHD_set_connection_value (struct MHD_Connection *connection,
/**
+ * This function can be used to add an entry to the HTTP headers of a
+ * connection (so that the #MHD_get_connection_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
+ * #MHD_AccessHandlerCallback (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 connection the connection for which a
+ * value should be set
+ * @param kind kind of the value
+ * @param key key for the value
+ * @param value the value itself
+ * @param value_size number of bytes in @a value (excluding 0-terminator for C-strings)
+ * @return #MHD_NO if the operation could not be
+ * performed due to insufficient memory;
+ * #MHD_YES on success
+ * @ingroup request
+ */
+int
+MHD_set_connection_value2 (struct MHD_Connection *connection,
+ enum MHD_ValueKind kind,
+ const char *key,
+ const char *value,
+ size_t value_size);
+
+
+/**
* 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
@@ -3075,7 +3114,8 @@ MHD_del_response_header (struct MHD_Response *response,
*/
_MHD_EXTERN int
MHD_get_response_headers (struct MHD_Response *response,
- MHD_KeyValueIterator iterator, void *iterator_cls);
+ MHD_KeyValueIterator iterator,
+ void *iterator_cls);
/**
diff --git a/src/microhttpd/connection.c b/src/microhttpd/connection.c
@@ -1,6 +1,6 @@
/*
This file is part of libmicrohttpd
- Copyright (C) 2007-2017 Daniel Pittman and Christian Grothoff
+ Copyright (C) 2007-2019 Daniel Pittman and Christian Grothoff
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
@@ -706,7 +706,8 @@ MHD_get_connection_values (struct MHD_Connection *connection,
(MHD_YES != iterator (iterator_cls,
pos->kind,
pos->header,
- pos->value)) )
+ pos->value,
+ pos->value_size)) )
return ret;
}
return ret;
@@ -733,16 +734,18 @@ MHD_get_connection_values (struct MHD_Connection *connection,
* @param kind kind of the value
* @param key key for the value
* @param value the value itself
+ * @param value_size number of bytes in @a value
* @return #MHD_NO if the operation could not be
* performed due to insufficient memory;
* #MHD_YES on success
* @ingroup request
*/
int
-MHD_set_connection_value (struct MHD_Connection *connection,
- enum MHD_ValueKind kind,
- const char *key,
- const char *value)
+MHD_set_connection_value2 (struct MHD_Connection *connection,
+ enum MHD_ValueKind kind,
+ const char *key,
+ const char *value,
+ size_t value_size)
{
struct MHD_HTTP_Header *pos;
@@ -753,6 +756,7 @@ MHD_set_connection_value (struct MHD_Connection *connection,
return MHD_NO;
pos->header = (char *) key;
pos->value = (char *) value;
+ pos->value_size = value_size;
pos->kind = kind;
pos->next = NULL;
/* append 'pos' to the linked list of headers */
@@ -771,6 +775,47 @@ MHD_set_connection_value (struct MHD_Connection *connection,
/**
+ * This function can be used to add an entry to the HTTP headers of a
+ * connection (so that the #MHD_get_connection_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
+ * #MHD_AccessHandlerCallback (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 connection the connection 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
+ */
+int
+MHD_set_connection_value (struct MHD_Connection *connection,
+ enum MHD_ValueKind kind,
+ const char *key,
+ const char *value)
+{
+ return MHD_set_connection_value2 (connection,
+ kind,
+ key,
+ value,
+ NULL != value
+ ? strlen (value)
+ : 0);
+}
+
+
+/**
* Get a particular header value. If multiple
* values match the kind, return any one of them.
*
@@ -2061,19 +2106,22 @@ get_next_header_line (struct MHD_Connection *connection,
* @param kind kind of the value
* @param key key for the value
* @param value the value itself
+ * @param value_size number of bytes in @a value
* @return #MHD_NO on failure (out of memory), #MHD_YES for success
*/
static int
connection_add_header (struct MHD_Connection *connection,
const char *key,
const char *value,
+ size_t value_size,
enum MHD_ValueKind kind)
{
if (MHD_NO ==
- MHD_set_connection_value (connection,
- kind,
- key,
- value))
+ MHD_set_connection_value2 (connection,
+ kind,
+ key,
+ value,
+ value_size))
{
#ifdef HAVE_MESSAGES
MHD_DLOG (connection->daemon,
@@ -2104,6 +2152,7 @@ parse_cookie_header (struct MHD_Connection *connection)
char *semicolon;
char *equals;
char *ekill;
+ char *end;
char old;
int quotes;
@@ -2155,6 +2204,7 @@ parse_cookie_header (struct MHD_Connection *connection)
connection_add_header (connection,
pos,
"",
+ 0,
MHD_COOKIE_KIND))
return MHD_NO;
if (old == '\0')
@@ -2174,6 +2224,7 @@ parse_cookie_header (struct MHD_Connection *connection)
quotes = (quotes + 1) & 1;
semicolon++;
}
+ end = semicolon;
if ('\0' == semicolon[0])
semicolon = NULL;
if (NULL != semicolon)
@@ -2183,15 +2234,17 @@ parse_cookie_header (struct MHD_Connection *connection)
}
/* remove quotes */
if ( ('"' == equals[0]) &&
- ('"' == equals[strlen (equals) - 1]) )
+ ('"' == end[-1]) )
{
- equals[strlen (equals) - 1] = '\0';
equals++;
+ end--;
+ *end = '\0';
}
if (MHD_NO ==
connection_add_header (connection,
pos,
equals,
+ end - equals,
MHD_COOKIE_KIND))
return MHD_NO;
pos = semicolon;
@@ -2257,7 +2310,7 @@ parse_initial_message_line (struct MHD_Connection *connection,
http_version--;
if (http_version > uri)
{
- /* http_version points to string before HTTP version string */
+ /* http_version points to character before HTTP version string */
http_version[0] = '\0';
connection->version = http_version + 1;
uri_len = http_version - uri;
@@ -2277,24 +2330,21 @@ parse_initial_message_line (struct MHD_Connection *connection,
return MHD_NO;
}
- /* unescape URI before searching for arguments */
- daemon->unescape_callback (daemon->unescape_callback_cls,
- connection,
- uri);
- uri_len = strlen (uri); /* recalculate: may have changed! */
args = memchr (uri,
'?',
uri_len);
}
+ /* log callback before we modify URI *or* args */
if (NULL != daemon->uri_log_callback)
{
connection->client_aware = true;
connection->client_context
= daemon->uri_log_callback (daemon->uri_log_callback_cls,
- curi,
+ uri,
connection);
}
+
if (NULL != args)
{
args[0] = '\0';
@@ -2306,6 +2356,12 @@ parse_initial_message_line (struct MHD_Connection *connection,
&connection_add_header,
&unused_num_headers);
}
+
+ /* unescape URI *after* searching for arguments and log callback */
+ if (NULL != uri)
+ daemon->unescape_callback (daemon->unescape_callback_cls,
+ connection,
+ uri);
connection->url = curi;
return MHD_YES;
}
@@ -2708,16 +2764,20 @@ process_broken_line (struct MHD_Connection *connection,
REQUEST_TOO_BIG);
return MHD_NO;
}
- memcpy (&last[last_len], tmp, tmp_len + 1);
+ memcpy (&last[last_len],
+ tmp,
+ tmp_len + 1);
connection->last = last;
return MHD_YES; /* possibly more than 2 lines... */
}
mhd_assert ( (NULL != last) &&
(NULL != connection->colon) );
- if ((MHD_NO == connection_add_header (connection,
- last,
- connection->colon,
- kind)))
+ if (MHD_NO ==
+ connection_add_header (connection,
+ last,
+ connection->colon,
+ strlen (connection->colon),
+ kind))
{
transmit_error_response (connection,
MHD_HTTP_REQUEST_HEADER_FIELDS_TOO_LARGE,
diff --git a/src/microhttpd/digestauth.c b/src/microhttpd/digestauth.c
@@ -732,6 +732,7 @@ calculate_nonce (uint32_t nonce_time,
* @param connection the connection
* @param key the key
* @param value the value, can be NULL
+ * @param value_size number of bytes in @a value
* @param kind type of the header
* @return #MHD_YES if the key-value pair is in the headers,
* #MHD_NO if not
@@ -740,6 +741,7 @@ static int
test_header (struct MHD_Connection *connection,
const char *key,
const char *value,
+ size_t value_size,
enum MHD_ValueKind kind)
{
struct MHD_HTTP_Header *pos;
@@ -748,6 +750,8 @@ test_header (struct MHD_Connection *connection,
{
if (kind != pos->kind)
continue;
+ if (value_size != pos->value_size)
+ continue;
if (0 != strcmp (key,
pos->header))
continue;
@@ -756,8 +760,9 @@ test_header (struct MHD_Connection *connection,
return MHD_YES;
if ( (NULL == value) ||
(NULL == pos->value) ||
- (0 != strcmp (value,
- pos->value)) )
+ (0 != memcmp (value,
+ pos->value,
+ value_size)) )
continue;
return MHD_YES;
}
@@ -862,6 +867,7 @@ digest_auth_check_all (struct MHD_Connection *connection,
uint32_t t;
size_t left; /* number of characters left in 'header' for 'uri' */
uint64_t nci;
+ char *qmark;
VLA_CHECK_LEN_DIGEST(da->digest_size);
header = MHD_lookup_connection_value (connection,
@@ -1072,15 +1078,17 @@ digest_auth_check_all (struct MHD_Connection *connection,
uri,
hentity,
da);
-
+ qmark = strchr (uri,
+ '?');
+ if (NULL != qmark)
+ *qmark = '\0';
/* Need to unescape URI before comparing with connection->url */
daemon->unescape_callback (daemon->unescape_callback_cls,
connection,
uri);
- if (0 != strncmp (uri,
- connection->url,
- strlen (connection->url)))
+ if (0 != strcmp (uri,
+ connection->url))
{
#ifdef HAVE_MESSAGES
MHD_DLOG (daemon,
@@ -1091,8 +1099,7 @@ digest_auth_check_all (struct MHD_Connection *connection,
}
{
- const char *args = strchr (uri,
- '?');
+ const char *args = qmark;
if (NULL == args)
args = "";
diff --git a/src/microhttpd/internal.c b/src/microhttpd/internal.c
@@ -162,7 +162,7 @@ MHD_http_unescape (char *val)
}
}
*wpos = '\0'; /* add 0-terminator */
- return wpos - val; /* = strlen(val) */
+ return wpos - val;
}
@@ -190,6 +190,7 @@ MHD_parse_arguments_ (struct MHD_Connection *connection,
struct MHD_Daemon *daemon = connection->daemon;
char *equals;
char *amper;
+ size_t len;
*num_headers = 0;
while ( (NULL != args) &&
@@ -210,6 +211,7 @@ MHD_parse_arguments_ (struct MHD_Connection *connection,
if (MHD_YES != cb (connection,
args,
NULL,
+ 0,
kind))
return MHD_NO;
(*num_headers)++;
@@ -223,12 +225,13 @@ MHD_parse_arguments_ (struct MHD_Connection *connection,
connection,
args);
MHD_unescape_plus (equals);
- daemon->unescape_callback (daemon->unescape_callback_cls,
- connection,
- equals);
+ len = daemon->unescape_callback (daemon->unescape_callback_cls,
+ connection,
+ equals);
if (MHD_YES != cb (connection,
args,
equals,
+ len,
kind))
return MHD_NO;
(*num_headers)++;
@@ -248,6 +251,7 @@ MHD_parse_arguments_ (struct MHD_Connection *connection,
if (MHD_YES != cb (connection,
args,
NULL,
+ 0,
kind))
return MHD_NO;
/* continue with 'bar' */
@@ -264,12 +268,13 @@ MHD_parse_arguments_ (struct MHD_Connection *connection,
connection,
args);
MHD_unescape_plus (equals);
- daemon->unescape_callback (daemon->unescape_callback_cls,
- connection,
- equals);
+ len = daemon->unescape_callback (daemon->unescape_callback_cls,
+ connection,
+ equals);
if (MHD_YES != cb (connection,
args,
equals,
+ len,
kind))
return MHD_NO;
(*num_headers)++;
diff --git a/src/microhttpd/internal.h b/src/microhttpd/internal.h
@@ -276,6 +276,11 @@ struct MHD_HTTP_Header
char *value;
/**
+ * Number of bytes in @a value.
+ */
+ size_t value_size;
+
+ /**
* Type of the header (where in the HTTP protocol is this header
* from).
*/
@@ -1881,7 +1886,8 @@ MHD_unescape_plus (char *arg);
*
* @param connection context of the iteration
* @param key 0-terminated key string, never NULL
- * @param value 0-terminated value string, may be NULL
+ * @param value 0-terminated binary data, may include binary zeros, may be NULL
+ * @param value_size number of bytes in value
* @param kind origin of the key-value pair
* @return #MHD_YES on success (continue to iterate)
* #MHD_NO to signal failure (and abort iteration)
@@ -1890,6 +1896,7 @@ typedef int
(*MHD_ArgumentIterator_)(struct MHD_Connection *connection,
const char *key,
const char *value,
+ size_t value_size,
enum MHD_ValueKind kind);
diff --git a/src/microhttpd/response.c b/src/microhttpd/response.c
@@ -240,7 +240,8 @@ MHD_get_response_headers (struct MHD_Response *response,
(MHD_YES != iterator (iterator_cls,
pos->kind,
pos->header,
- pos->value)))
+ pos->value,
+ pos->value_size)))
break;
}
return numHeaders;
diff --git a/src/testcurl/test_get.c b/src/testcurl/test_get.c
@@ -35,6 +35,8 @@
#include "mhd_sockets.h" /* only macros used */
+#define EXPECTED_URI_PATH "/hello_world?a=%26&b=c"
+
#ifdef _WIN32
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN 1
@@ -64,6 +66,7 @@ struct CBC
size_t size;
};
+
static size_t
copyBuffer (void *ptr, size_t size, size_t nmemb, void *ctx)
{
@@ -76,6 +79,24 @@ copyBuffer (void *ptr, size_t size, size_t nmemb, void *ctx)
return size * nmemb;
}
+
+static void *
+log_cb (void *cls,
+ const char *uri,
+ struct MHD_Connection *con)
+{
+ if (0 != strcmp (uri,
+ EXPECTED_URI_PATH))
+ {
+ fprintf (stderr,
+ "Wrong URI: `%s'\n",
+ uri);
+ abort ();
+ }
+ return NULL;
+}
+
+
static int
ahc_echo (void *cls,
struct MHD_Connection *connection,
@@ -89,7 +110,10 @@ ahc_echo (void *cls,
const char *me = cls;
struct MHD_Response *response;
int ret;
- (void)version;(void)upload_data;(void)upload_data_size; /* Unused. Silent compiler warning. */
+ const char *v;
+ (void) version;
+ (void) upload_data;
+ (void) upload_data_size; /* Unused. Silence compiler warning. */
if (0 != strcasecmp (me, method))
return MHD_NO; /* unexpected method */
@@ -99,10 +123,26 @@ ahc_echo (void *cls,
return MHD_YES;
}
*unused = NULL;
+ v = MHD_lookup_connection_value (connection,
+ MHD_GET_ARGUMENT_KIND,
+ "a");
+ if ( (NULL == v) ||
+ (0 != strcmp ("&",
+ v)) )
+ abort ();
+ v = MHD_lookup_connection_value (connection,
+ MHD_GET_ARGUMENT_KIND,
+ "b");
+ if ( (NULL == v) ||
+ (0 != strcmp ("c",
+ v)) )
+ abort ();
response = MHD_create_response_from_buffer (strlen (url),
(void *) url,
MHD_RESPMEM_MUST_COPY);
- ret = MHD_queue_response (connection, MHD_HTTP_OK, response);
+ ret = MHD_queue_response (connection,
+ MHD_HTTP_OK,
+ response);
MHD_destroy_response (response);
if (ret == MHD_NO)
abort ();
@@ -131,7 +171,10 @@ testInternalGet (int poll_flag)
cbc.size = 2048;
cbc.pos = 0;
d = MHD_start_daemon (MHD_USE_INTERNAL_POLLING_THREAD | MHD_USE_ERROR_LOG | poll_flag,
- global_port, NULL, NULL, &ahc_echo, "GET", MHD_OPTION_END);
+ global_port, NULL, NULL,
+ &ahc_echo, "GET",
+ MHD_OPTION_URI_LOG_CALLBACK, &log_cb, NULL,
+ MHD_OPTION_END);
if (d == NULL)
return 1;
if (0 == global_port)
@@ -143,7 +186,7 @@ testInternalGet (int poll_flag)
global_port = (int)dinfo->port;
}
c = curl_easy_init ();
- curl_easy_setopt (c, CURLOPT_URL, "http://127.0.0.1/hello_world");
+ curl_easy_setopt (c, CURLOPT_URL, "http://127.0.0.1" EXPECTED_URI_PATH);
curl_easy_setopt (c, CURLOPT_PORT, (long)global_port);
curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, ©Buffer);
curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc);
@@ -198,7 +241,10 @@ testMultithreadedGet (int poll_flag)
cbc.size = 2048;
cbc.pos = 0;
d = MHD_start_daemon (MHD_USE_THREAD_PER_CONNECTION | MHD_USE_INTERNAL_POLLING_THREAD | MHD_USE_ERROR_LOG | poll_flag,
- global_port, NULL, NULL, &ahc_echo, "GET", MHD_OPTION_END);
+ global_port, NULL, NULL,
+ &ahc_echo, "GET",
+ MHD_OPTION_URI_LOG_CALLBACK, &log_cb, NULL,
+ MHD_OPTION_END);
if (d == NULL)
return 16;
if (0 == global_port)
@@ -210,7 +256,7 @@ testMultithreadedGet (int poll_flag)
global_port = (int)dinfo->port;
}
c = curl_easy_init ();
- curl_easy_setopt (c, CURLOPT_URL, "http://127.0.0.1/hello_world");
+ curl_easy_setopt (c, CURLOPT_URL, "http://127.0.0.1" EXPECTED_URI_PATH);
curl_easy_setopt (c, CURLOPT_PORT, (long)global_port);
curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, ©Buffer);
curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc);
@@ -265,8 +311,11 @@ testMultithreadedPoolGet (int poll_flag)
cbc.size = 2048;
cbc.pos = 0;
d = MHD_start_daemon (MHD_USE_INTERNAL_POLLING_THREAD | MHD_USE_ERROR_LOG | poll_flag,
- global_port, NULL, NULL, &ahc_echo, "GET",
- MHD_OPTION_THREAD_POOL_SIZE, CPU_COUNT, MHD_OPTION_END);
+ global_port, NULL, NULL,
+ &ahc_echo, "GET",
+ MHD_OPTION_THREAD_POOL_SIZE, CPU_COUNT,
+ MHD_OPTION_URI_LOG_CALLBACK, &log_cb, NULL,
+ MHD_OPTION_END);
if (d == NULL)
return 16;
if (0 == global_port)
@@ -278,7 +327,7 @@ testMultithreadedPoolGet (int poll_flag)
global_port = (int)dinfo->port;
}
c = curl_easy_init ();
- curl_easy_setopt (c, CURLOPT_URL, "http://127.0.0.1/hello_world");
+ curl_easy_setopt (c, CURLOPT_URL, "http://127.0.0.1" EXPECTED_URI_PATH);
curl_easy_setopt (c, CURLOPT_PORT, (long)global_port);
curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, ©Buffer);
curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc);
@@ -348,7 +397,10 @@ testExternalGet ()
cbc.size = 2048;
cbc.pos = 0;
d = MHD_start_daemon (MHD_USE_ERROR_LOG,
- global_port, NULL, NULL, &ahc_echo, "GET", MHD_OPTION_END);
+ global_port, NULL, NULL,
+ &ahc_echo, "GET",
+ MHD_OPTION_URI_LOG_CALLBACK, &log_cb, NULL,
+ MHD_OPTION_END);
if (d == NULL)
return 256;
if (0 == global_port)
@@ -360,7 +412,7 @@ testExternalGet ()
global_port = (int)dinfo->port;
}
c = curl_easy_init ();
- curl_easy_setopt (c, CURLOPT_URL, "http://127.0.0.1/hello_world");
+ curl_easy_setopt (c, CURLOPT_URL, "http://127.0.0.1" EXPECTED_URI_PATH);
curl_easy_setopt (c, CURLOPT_PORT, (long)global_port);
curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, ©Buffer);
curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc);
@@ -494,6 +546,7 @@ testUnknownPortGet (int poll_flag)
d = MHD_start_daemon (MHD_USE_INTERNAL_POLLING_THREAD | MHD_USE_ERROR_LOG | poll_flag,
0, NULL, NULL, &ahc_echo, "GET",
MHD_OPTION_SOCK_ADDR, &addr,
+ MHD_OPTION_URI_LOG_CALLBACK, &log_cb, NULL,
MHD_OPTION_END);
if (MHD_NO == MHD_is_feature_supported (MHD_FEATURE_AUTODETECT_BIND_PORT))
{
@@ -517,8 +570,11 @@ testUnknownPortGet (int poll_flag)
port = (int)dinfo->port;
}
- snprintf(buf, sizeof(buf), "http://127.0.0.1:%d/hello_world",
- port);
+ snprintf(buf,
+ sizeof(buf),
+ "http://127.0.0.1:%d%s",
+ port,
+ EXPECTED_URI_PATH);
c = curl_easy_init ();
curl_easy_setopt (c, CURLOPT_URL, buf);
@@ -570,7 +626,10 @@ testStopRace (int poll_flag)
}
d = MHD_start_daemon (MHD_USE_THREAD_PER_CONNECTION | MHD_USE_INTERNAL_POLLING_THREAD | MHD_USE_ERROR_LOG | poll_flag,
- global_port, NULL, NULL, &ahc_echo, "GET", MHD_OPTION_END);
+ global_port, NULL, NULL,
+ &ahc_echo, "GET",
+ MHD_OPTION_URI_LOG_CALLBACK, &log_cb, NULL,
+ MHD_OPTION_END);
if (d == NULL)
return 16;
if (0 == global_port)
@@ -686,7 +745,10 @@ testEmptyGet (int poll_flag)
cbc.size = 2048;
cbc.pos = 0;
d = MHD_start_daemon (MHD_USE_INTERNAL_POLLING_THREAD | MHD_USE_ERROR_LOG | poll_flag,
- global_port, NULL, NULL, &ahc_empty, NULL, MHD_OPTION_END);
+ global_port, NULL, NULL,
+ &ahc_empty, NULL,
+ MHD_OPTION_URI_LOG_CALLBACK, &log_cb, NULL,
+ MHD_OPTION_END);
if (d == NULL)
return 4194304;
if (0 == global_port)
@@ -698,7 +760,7 @@ testEmptyGet (int poll_flag)
global_port = (int)dinfo->port;
}
c = curl_easy_init ();
- curl_easy_setopt (c, CURLOPT_URL, "http://127.0.0.1/hello_world");
+ curl_easy_setopt (c, CURLOPT_URL, "http://127.0.0.1" EXPECTED_URI_PATH);
curl_easy_setopt (c, CURLOPT_PORT, (long)global_port);
curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, ©Buffer);
curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc);
diff --git a/src/testcurl/test_process_headers.c b/src/testcurl/test_process_headers.c
@@ -65,8 +65,13 @@ copyBuffer (void *ptr, size_t size, size_t nmemb, void *ctx)
return size * nmemb;
}
+
static int
-kv_cb (void *cls, enum MHD_ValueKind kind, const char *key, const char *value)
+kv_cb (void *cls,
+ enum MHD_ValueKind kind,
+ const char *key,
+ const char *value,
+ size_t value_size)
{
if ((0 == strcmp (key, MHD_HTTP_HEADER_HOST)) &&
(0 == strncmp (value, "127.0.0.1", strlen("127.0.0.1"))) && (kind == MHD_HEADER_KIND))
@@ -77,6 +82,7 @@ kv_cb (void *cls, enum MHD_ValueKind kind, const char *key, const char *value)
return MHD_YES;
}
+
static int
ahc_echo (void *cls,
struct MHD_Connection *connection,
diff --git a/src/testcurl/test_urlparse.c b/src/testcurl/test_urlparse.c
@@ -67,13 +67,18 @@ copyBuffer (void *ptr, size_t size, size_t nmemb, void *ctx)
return size * nmemb;
}
+
static int
test_values (void *cls,
enum MHD_ValueKind kind,
const char *key,
- const char *value)
+ const char *value,
+ size_t value_size)
{
- (void)cls;(void)kind; /* Unused. Silent compiler warning. */
+ (void) cls;
+ (void) kind;
+ (void) value_size;
+
if ( (0 == strcmp (key, "a")) &&
(0 == strcmp (value, "b")) )
matches += 1;