commit 8aa7d23219052cde065b93adf04c5ded067a1fea
parent 08ea0cc894bfdd9aeddeb8bb113514c247d2c69e
Author: Evgeny Grin (Karlson2k) <k2k@narod.ru>
Date: Wed, 1 May 2019 22:10:38 +0300
Partial revert of 1b610e5b13b7b96e7b3f372c8da1ec9d840f896a.
Implemented new functions for key and value with binary zero.
Significantly speedup search for key by using key size.
Diffstat:
11 files changed, 184 insertions(+), 87 deletions(-)
diff --git a/doc/examples/logging.c b/doc/examples/logging.c
@@ -15,16 +15,11 @@
static int
-print_out_key (void *cls,
- enum MHD_ValueKind kind,
- const char *key,
- const char *value,
- size_t value_size)
+print_out_key (void *cls, enum MHD_ValueKind kind, const char *key,
+ const char *value)
{
- (void) cls; /* Unused. Silent compiler warning. */
- (void) kind; /* Unused. Silent compiler warning. */
- (void) value_size;
-
+ (void)cls; /* Unused. Silent compiler warning. */
+ (void)kind; /* Unused. Silent compiler warning. */
printf ("%s: %s\n", key, value);
return MHD_YES;
}
@@ -43,9 +38,7 @@ 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/src/include/microhttpd.h b/src/include/microhttpd.h
@@ -128,7 +128,7 @@ typedef intptr_t ssize_t;
* Current version of the library.
* 0x01093001 = 1.9.30-1.
*/
-#define MHD_VERSION 0x00096302
+#define MHD_VERSION 0x00096303
/**
* MHD-internal return code for "YES".
@@ -2041,6 +2041,29 @@ 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
+ * @return #MHD_YES to continue iterating,
+ * #MHD_NO to abort the iteration
+ * @ingroup request
+ */
+typedef int
+(*MHD_KeyValueIterator) (void *cls,
+ enum MHD_ValueKind kind,
+ const char *key,
+ const char *value);
+
+
+/**
+ * Iterator over key-value pairs with size parameters.
+ * 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.
+ * @note Available since #MHD_VERSION 0x00096303
+ *
+ * @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
* @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,
@@ -2048,11 +2071,12 @@ typedef void
* @ingroup request
*/
typedef int
-(*MHD_KeyValueIterator) (void *cls,
+(*MHD_KeyValueIteratorN) (void *cls,
enum MHD_ValueKind kind,
const char *key,
+ size_t key_size,
const char *value,
- size_t value_size);
+ size_t value_size);
/**
@@ -2531,6 +2555,7 @@ MHD_set_connection_value (struct MHD_Connection *connection,
* value should be set
* @param kind kind of the value
* @param key key for the value
+ * @param key_size number of bytes in @a key (excluding 0-terminator for C-strings)
* @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
@@ -2539,11 +2564,12 @@ MHD_set_connection_value (struct MHD_Connection *connection,
* @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);
+MHD_set_connection_value_n (struct MHD_Connection *connection,
+ enum MHD_ValueKind kind,
+ const char *key,
+ size_t key_size,
+ const char *value,
+ size_t value_size);
/**
diff --git a/src/microhttpd/connection.c b/src/microhttpd/connection.c
@@ -706,8 +706,7 @@ MHD_get_connection_values (struct MHD_Connection *connection,
(MHD_YES != iterator (iterator_cls,
pos->kind,
pos->header,
- pos->value,
- pos->value_size)) )
+ pos->value)) )
return ret;
}
return ret;
@@ -733,19 +732,21 @@ MHD_get_connection_values (struct MHD_Connection *connection,
* value should be set
* @param kind kind of the value
* @param key key for the value
+ * @param key_size number of bytes in @a key (excluding 0-terminator for C-strings)
* @param value the value itself
- * @param value_size number of bytes in @a value
+ * @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)
+MHD_set_connection_value_n (struct MHD_Connection *connection,
+ enum MHD_ValueKind kind,
+ const char *key,
+ size_t key_size,
+ const char *value,
+ size_t value_size)
{
struct MHD_HTTP_Header *pos;
@@ -755,6 +756,7 @@ MHD_set_connection_value2 (struct MHD_Connection *connection,
if (NULL == pos)
return MHD_NO;
pos->header = (char *) key;
+ pos->header_size = key_size;
pos->value = (char *) value;
pos->value_size = value_size;
pos->kind = kind;
@@ -805,13 +807,16 @@ MHD_set_connection_value (struct MHD_Connection *connection,
const char *key,
const char *value)
{
- return MHD_set_connection_value2 (connection,
- kind,
- key,
- value,
- NULL != value
- ? strlen (value)
- : 0);
+ return MHD_set_connection_value_n (connection,
+ kind,
+ key,
+ NULL != key
+ ? strlen (key)
+ : 0,
+ value,
+ NULL != value
+ ? strlen (value)
+ : 0);
}
@@ -2105,6 +2110,7 @@ get_next_header_line (struct MHD_Connection *connection,
* value should be set
* @param kind kind of the value
* @param key key for the value
+ * @param key_size number of bytes in @a key
* @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
@@ -2112,16 +2118,18 @@ get_next_header_line (struct MHD_Connection *connection,
static int
connection_add_header (struct MHD_Connection *connection,
const char *key,
+ size_t key_size,
const char *value,
size_t value_size,
enum MHD_ValueKind kind)
{
if (MHD_NO ==
- MHD_set_connection_value2 (connection,
- kind,
- key,
- value,
- value_size))
+ MHD_set_connection_value_n (connection,
+ kind,
+ key,
+ key_size,
+ value,
+ value_size))
{
#ifdef HAVE_MESSAGES
MHD_DLOG (connection->daemon,
@@ -2203,6 +2211,7 @@ parse_cookie_header (struct MHD_Connection *connection)
if (MHD_NO ==
connection_add_header (connection,
pos,
+ ekill - pos + 1,
"",
0,
MHD_COOKIE_KIND))
@@ -2243,6 +2252,7 @@ parse_cookie_header (struct MHD_Connection *connection)
if (MHD_NO ==
connection_add_header (connection,
pos,
+ ekill - pos + 1,
equals,
end - equals,
MHD_COOKIE_KIND))
@@ -2774,6 +2784,7 @@ process_broken_line (struct MHD_Connection *connection,
if (MHD_NO ==
connection_add_header (connection,
last,
+ strlen (last),
connection->colon,
strlen (connection->colon),
kind))
diff --git a/src/microhttpd/digestauth.c b/src/microhttpd/digestauth.c
@@ -731,6 +731,7 @@ calculate_nonce (uint32_t nonce_time,
*
* @param connection the connection
* @param key the key
+ * @param key_size number of bytes in @a key
* @param value the value, can be NULL
* @param value_size number of bytes in @a value
* @param kind type of the header
@@ -740,6 +741,7 @@ calculate_nonce (uint32_t nonce_time,
static int
test_header (struct MHD_Connection *connection,
const char *key,
+ size_t key_size,
const char *value,
size_t value_size,
enum MHD_ValueKind kind)
@@ -750,10 +752,13 @@ test_header (struct MHD_Connection *connection,
{
if (kind != pos->kind)
continue;
- if (value_size != pos->value_size)
+ if (key_size != pos->header_size)
continue;
- if (0 != strcmp (key,
- pos->header))
+ if (value_size != pos->value_size)
+ continue;
+ if (0 != memcmp (key,
+ pos->header,
+ key_size))
continue;
if ( (NULL == value) &&
(NULL == pos->value) )
diff --git a/src/microhttpd/internal.c b/src/microhttpd/internal.c
@@ -190,12 +190,13 @@ 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) &&
('\0' != args[0]) )
{
+ size_t key_len;
+ size_t value_len;
equals = strchr (args, '=');
amper = strchr (args, '&');
if (NULL == amper)
@@ -205,11 +206,12 @@ MHD_parse_arguments_ (struct MHD_Connection *connection,
{
/* last argument, without '=' */
MHD_unescape_plus (args);
- daemon->unescape_callback (daemon->unescape_callback_cls,
- connection,
- args);
+ key_len = daemon->unescape_callback (daemon->unescape_callback_cls,
+ connection,
+ args);
if (MHD_YES != cb (connection,
args,
+ key_len,
NULL,
0,
kind))
@@ -221,17 +223,18 @@ MHD_parse_arguments_ (struct MHD_Connection *connection,
equals[0] = '\0';
equals++;
MHD_unescape_plus (args);
- daemon->unescape_callback (daemon->unescape_callback_cls,
- connection,
- args);
+ key_len = daemon->unescape_callback (daemon->unescape_callback_cls,
+ connection,
+ args);
MHD_unescape_plus (equals);
- len = daemon->unescape_callback (daemon->unescape_callback_cls,
- connection,
- equals);
+ value_len = daemon->unescape_callback (daemon->unescape_callback_cls,
+ connection,
+ equals);
if (MHD_YES != cb (connection,
args,
+ key_len,
equals,
- len,
+ value_len,
kind))
return MHD_NO;
(*num_headers)++;
@@ -245,11 +248,12 @@ MHD_parse_arguments_ (struct MHD_Connection *connection,
{
/* got 'foo&bar' or 'foo&bar=val', add key 'foo' with NULL for value */
MHD_unescape_plus (args);
- daemon->unescape_callback (daemon->unescape_callback_cls,
- connection,
- args);
+ key_len = daemon->unescape_callback (daemon->unescape_callback_cls,
+ connection,
+ args);
if (MHD_YES != cb (connection,
args,
+ key_len,
NULL,
0,
kind))
@@ -264,17 +268,18 @@ MHD_parse_arguments_ (struct MHD_Connection *connection,
equals[0] = '\0';
equals++;
MHD_unescape_plus (args);
- daemon->unescape_callback (daemon->unescape_callback_cls,
- connection,
- args);
+ key_len = daemon->unescape_callback (daemon->unescape_callback_cls,
+ connection,
+ args);
MHD_unescape_plus (equals);
- len = daemon->unescape_callback (daemon->unescape_callback_cls,
- connection,
- equals);
+ value_len = daemon->unescape_callback (daemon->unescape_callback_cls,
+ connection,
+ equals);
if (MHD_YES != cb (connection,
args,
+ key_len,
equals,
- len,
+ value_len,
kind))
return MHD_NO;
(*num_headers)++;
diff --git a/src/microhttpd/internal.h b/src/microhttpd/internal.h
@@ -271,6 +271,11 @@ struct MHD_HTTP_Header
char *header;
/**
+ * Number of bytes in @a header.
+ */
+ size_t header_size;
+
+ /**
* The value of the header.
*/
char *value;
@@ -1886,6 +1891,7 @@ MHD_unescape_plus (char *arg);
*
* @param connection context of the iteration
* @param key 0-terminated key string, never NULL
+ * @param key_size number of bytes in key
* @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
@@ -1895,6 +1901,7 @@ MHD_unescape_plus (char *arg);
typedef int
(*MHD_ArgumentIterator_)(struct MHD_Connection *connection,
const char *key,
+ size_t key_size,
const char *value,
size_t value_size,
enum MHD_ValueKind kind);
@@ -1923,14 +1930,17 @@ MHD_parse_arguments_ (struct MHD_Connection *connection,
/**
- * Check whether response header contains particular @a token.
+ * Check whether response header contains particular token.
*
* Token could be surrounded by spaces and tabs and delimited by comma.
* Case-insensitive match used for header names and tokens.
+ *
* @param response the response to query
* @param key header name
+ * @param key_len the length of @a key, not including optional
+ * terminating null-character.
* @param token the token to find
- * @param token_len the length of token, not including optional
+ * @param token_len the length of @a token, not including optional
* terminating null-character.
* @return true if token is found in specified header,
* false otherwise
@@ -1938,6 +1948,7 @@ MHD_parse_arguments_ (struct MHD_Connection *connection,
bool
MHD_check_response_header_token_ci (const struct MHD_Response *response,
const char *key,
+ size_t key_len,
const char *token,
size_t token_len);
@@ -1953,7 +1964,8 @@ MHD_check_response_header_token_ci (const struct MHD_Response *response,
* false otherwise
*/
#define MHD_check_response_header_s_token_ci(r,k,tkn) \
- MHD_check_response_header_token_ci((r),(k),(tkn),MHD_STATICSTR_LEN_(tkn))
+ MHD_check_response_header_token_ci((r),(k),MHD_STATICSTR_LEN_(k),\
+ (tkn),MHD_STATICSTR_LEN_(tkn))
/**
diff --git a/src/microhttpd/mhd_str.c b/src/microhttpd/mhd_str.c
@@ -377,6 +377,35 @@ MHD_str_equal_caseless_n_ (const char * const str1,
/**
+ * Check two string for equality, ignoring case of US-ASCII letters and
+ * checking exactly @a len characters.
+ * Compares exactly @a len characters, including binary zero characters.
+ * @param str1 first string to compare
+ * @param str2 second string to compare
+ * @param len number of characters to compare
+ * @return non-zero if two strings are equal, zero otherwise.
+ */
+bool
+MHD_str_equal_caseless_bin_n_ (const char * const str1,
+ const char * const str2,
+ size_t len)
+{
+ size_t i;
+
+ for (i = 0; i < len; ++i)
+ {
+ const char c1 = str1[i];
+ const char c2 = str2[i];
+ if ( (c1 != c2) &&
+ (toasciilower (c1) != toasciilower (c2)) )
+ return 0;
+ }
+ return !0;
+}
+
+
+
+/**
* Check whether @a str has case-insensitive @a token.
* Token could be surrounded by spaces and tabs and delimited by comma.
* Match succeed if substring between start, end (of string) or comma
diff --git a/src/microhttpd/mhd_str.h b/src/microhttpd/mhd_str.h
@@ -83,6 +83,21 @@ MHD_str_equal_caseless_n_ (const char * const str1,
/**
+ * Check two string for equality, ignoring case of US-ASCII letters and
+ * checking exactly @a len characters.
+ * Compares exactly @a len characters, including binary zero characters.
+ * @param str1 first string to compare
+ * @param str2 second string to compare
+ * @param len number of characters to compare
+ * @return non-zero if two strings are equal, zero otherwise.
+ */
+bool
+MHD_str_equal_caseless_bin_n_ (const char * const str1,
+ const char * const str2,
+ size_t len);
+
+
+/**
* Check whether @a str has case-insensitive @a token.
* Token could be surrounded by spaces and tabs and delimited by comma.
* Match succeed if substring between start, end of string or comma
diff --git a/src/microhttpd/response.c b/src/microhttpd/response.c
@@ -105,6 +105,7 @@ add_response_entry (struct MHD_Response *response,
free (hdr);
return MHD_NO;
}
+ hdr->header_size = strlen (header);
if (NULL == (hdr->value = strdup (content)))
{
free (hdr->header);
@@ -254,8 +255,7 @@ MHD_get_response_headers (struct MHD_Response *response,
(MHD_YES != iterator (iterator_cls,
pos->kind,
pos->header,
- pos->value,
- pos->value_size)))
+ pos->value)))
break;
}
return numHeaders;
@@ -275,14 +275,18 @@ MHD_get_response_header (struct MHD_Response *response,
const char *key)
{
struct MHD_HTTP_Header *pos;
+ size_t key_size;
if (NULL == key)
return NULL;
+
+ key_size = strlen (key);
for (pos = response->first_header;
NULL != pos;
pos = pos->next)
{
- if (MHD_str_equal_caseless_ (pos->header, key))
+ if ((pos->header_size == key_size) &&
+ (MHD_str_equal_caseless_bin_n_ (pos->header, key, pos->header_size)))
return pos->value;
}
return NULL;
@@ -297,8 +301,10 @@ MHD_get_response_header (struct MHD_Response *response,
*
* @param response the response to query
* @param key header name
+ * @param key_len the length of @a key, not including optional
+ * terminating null-character.
* @param token the token to find
- * @param token_len the length of token, not including optional
+ * @param token_len the length of @a token, not including optional
* terminating null-character.
* @return true if token is found in specified header,
* false otherwise
@@ -306,6 +312,7 @@ MHD_get_response_header (struct MHD_Response *response,
bool
MHD_check_response_header_token_ci (const struct MHD_Response *response,
const char *key,
+ size_t key_len,
const char *token,
size_t token_len)
{
@@ -317,13 +324,18 @@ MHD_check_response_header_token_ci (const struct MHD_Response *response,
('\0' == token[0]) )
return false;
+ /* Token must not contain binary zero! */
+ mhd_assert(strlen(token) == token_len);
+
for (pos = response->first_header;
NULL != pos;
pos = pos->next)
{
if ( (pos->kind == MHD_HEADER_KIND) &&
- MHD_str_equal_caseless_ (pos->header,
- key) &&
+ (key_len == pos->header_size) &&
+ MHD_str_equal_caseless_bin_n_ (pos->header,
+ key,
+ key_len) &&
MHD_str_has_token_caseless_ (pos->value,
token,
token_len) )
diff --git a/src/testcurl/test_process_headers.c b/src/testcurl/test_process_headers.c
@@ -65,13 +65,8 @@ 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,
- size_t value_size)
+kv_cb (void *cls, enum MHD_ValueKind kind, const char *key, const char *value)
{
if ((0 == strcmp (key, MHD_HTTP_HEADER_HOST)) &&
(0 == strncmp (value, "127.0.0.1", strlen("127.0.0.1"))) && (kind == MHD_HEADER_KIND))
@@ -82,7 +77,6 @@ kv_cb (void *cls,
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,18 +67,13 @@ 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,
- size_t value_size)
+ const char *value)
{
- (void) cls;
- (void) kind;
- (void) value_size;
-
+ (void)cls;(void)kind; /* Unused. Silent compiler warning. */
if ( (0 == strcmp (key, "a")) &&
(0 == strcmp (value, "b")) )
matches += 1;