Forráskód Böngészése

Partial revert of 1b610e5b13b7b96e7b3f372c8da1ec9d840f896a.
Implemented new functions for key and value with binary zero.
Significantly speedup search for key by using key size.

Evgeny Grin (Karlson2k) 6 éve
szülő
commit
8aa7d23219

+ 5 - 12
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;

+ 34 - 8
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);
 
 
 /**

+ 31 - 20
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))

+ 8 - 3
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) )

+ 26 - 21
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)++;

+ 15 - 3
src/microhttpd/internal.h

@@ -270,6 +270,11 @@ struct MHD_HTTP_Header
    */
   char *header;
 
+  /**
+   * Number of bytes in @a header.
+   */
+  size_t header_size;
+
   /**
    * The value of the header.
    */
@@ -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))
 
 
 /**

+ 29 - 0
src/microhttpd/mhd_str.c

@@ -376,6 +376,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.

+ 15 - 0
src/microhttpd/mhd_str.h

@@ -82,6 +82,21 @@ MHD_str_equal_caseless_n_ (const char * const str1,
                   size_t maxlen);
 
 
+/**
+ * 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.

+ 18 - 6
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) )

+ 1 - 7
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,

+ 2 - 7
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;