gnunet-svn
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[GNUnet-SVN] [libmicrohttpd] branch master updated (4809ee65 -> e0825eab


From: gnunet
Subject: [GNUnet-SVN] [libmicrohttpd] branch master updated (4809ee65 -> e0825eab)
Date: Tue, 09 May 2017 21:34:06 +0200

This is an automated email from the git hooks/post-receive script.

karlson2k pushed a change to branch master
in repository libmicrohttpd.

    from 4809ee65 Revert: continue match footers in MHD_get_response_header(). 
This is a partial revert of 6894504f51ecd271f7471c69935329b1402f49c2
     new b03ee4c5 Fixed missing include
     new e93439da Added function for detection of token inside comma-separated 
string, added tests
     new ad7652a2 Added internal function for finding token in response headers 
MHD_check_response_header_token_ci()
     new 22ab1e90 Detect several tokens in single header line of response.
     new 17d1176f Added internal function for finding token in request headers
     new e0825eab Fixed: check all request "Connection" headers for "Close" and 
"Upgrade" tokens instead of using only first "Connection" header with full 
string match.

The 6 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 ChangeLog                   |   5 ++
 src/microhttpd/Makefile.am  |   4 +
 src/microhttpd/connection.c | 197 ++++++++++++++++++++++++++++----------------
 src/microhttpd/internal.h   |  37 +++++++++
 src/microhttpd/mhd_str.c    |  58 +++++++++++++
 src/microhttpd/mhd_str.h    |  42 ++++++++++
 src/microhttpd/response.c   |  35 ++++++++
 7 files changed, 305 insertions(+), 73 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index 9a1f3dae..ed19ecc9 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,8 @@
+Tue May  9 21:01:00 MSK 2017
+       Fixed: check all "Connection" headers of request for "Close" and 
"Upgrade"
+       tokens instead of using only first "Connection" header with full string
+       match. -EG
+
 Tue May  9 12:28:00 MSK 2017
        Revert: continue match footers in MHD_get_response_header() for backward
        compatibility. -EG
diff --git a/src/microhttpd/Makefile.am b/src/microhttpd/Makefile.am
index 3f1b828f..36121539 100644
--- a/src/microhttpd/Makefile.am
+++ b/src/microhttpd/Makefile.am
@@ -142,6 +142,7 @@ endif
 check_PROGRAMS = \
   test_str_compare \
   test_str_to_value \
+  test_str_token \
   test_http_reasons \
   test_shutdown_select \
   test_shutdown_poll \
@@ -251,6 +252,9 @@ test_str_compare_SOURCES = \
 test_str_to_value_SOURCES = \
   test_str.c test_helpers.h mhd_str.c
 
+test_str_token_SOURCES = \
+  test_str_token.c mhd_str.c
+
 test_http_reasons_SOURCES = \
   test_http_reasons.c \
   reason_phrase.c mhd_str.c mhd_str.h
diff --git a/src/microhttpd/connection.c b/src/microhttpd/connection.c
index e4873073..e3bf9e29 100644
--- a/src/microhttpd/connection.c
+++ b/src/microhttpd/connection.c
@@ -468,6 +468,57 @@ MHD_lookup_connection_value (struct MHD_Connection 
*connection,
 
 
 /**
+ * Check whether request 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 connection the connection to get values from
+ * @param header     the header name
+ * @param token      the token to find
+ * @param token_len  the length of token, not including optional
+ *                   terminating null-character.
+ * @return true if token is found in specified header,
+ *         false otherwise
+ */
+static bool
+MHD_lookup_header_token_ci (const struct MHD_Connection *connection,
+                         const char *header,
+                         const char *token,
+                         size_t token_len)
+{
+  struct MHD_HTTP_Header *pos;
+
+  if (NULL == connection || NULL == header || 0 == header[0] || NULL == token 
|| 0 == token[0])
+    return false;
+  for (pos = connection->headers_received; NULL != pos; pos = pos->next)
+    {
+      if ((0 != (pos->kind & MHD_HEADER_KIND)) &&
+          ( (header == pos->header) ||
+            (MHD_str_equal_caseless_(header,
+                                      pos->header)) ) &&
+          (MHD_str_has_token_caseless_ (pos->value, token, token_len)))
+        return true;
+    }
+  return false;
+}
+
+
+/**
+ * Check whether request header contains particular static @a tkn.
+ *
+ * Token could be surrounded by spaces and tabs and delimited by comma.
+ * Case-insensitive match used for header names and tokens.
+ * @param c   the connection to get values from
+ * @param h   the header name
+ * @param tkn the static string of token to find
+ * @return true if token is found in specified header,
+ *         false otherwise
+ */
+#define MHD_lookup_header_s_token_ci(c,h,tkn) \
+    MHD_lookup_header_token_ci((c),(h),(tkn),MHD_STATICSTR_LEN_(tkn))
+
+
+/**
  * Do we (still) need to send a 100 continue
  * message for this connection?
  *
@@ -861,8 +912,6 @@ try_ready_chunked_body (struct MHD_Connection *connection)
 static int
 keepalive_possible (struct MHD_Connection *connection)
 {
-  const char *end;
-
   if (MHD_CONN_MUST_CLOSE == connection->keepalive)
     return MHD_NO;
   if (NULL == connection->version)
@@ -870,37 +919,37 @@ keepalive_possible (struct MHD_Connection *connection)
   if ( (NULL != connection->response) &&
        (0 != (connection->response->flags & MHD_RF_HTTP_VERSION_1_0_ONLY) ) )
     return MHD_NO;
-  end = MHD_lookup_connection_value (connection,
-                                     MHD_HEADER_KIND,
-                                     MHD_HTTP_HEADER_CONNECTION);
+
   if (MHD_str_equal_caseless_(connection->version,
                               MHD_HTTP_VERSION_1_1))
-  {
-    if (NULL == end)
-      return MHD_YES;
-    if (MHD_str_equal_caseless_ (end,
-                                 "close"))
-      return MHD_NO;
+    {
+      if (MHD_lookup_header_s_token_ci (connection,
+                                        MHD_HTTP_HEADER_CONNECTION,
+                                        "upgrade"))
+        {
 #ifdef UPGRADE_SUPPORT
-    if ( (MHD_str_equal_caseless_ (end,
-                                   "upgrade")) &&
-         ( (NULL == connection->response) ||
-           (NULL == connection->response->upgrade_handler) ) )
-      return MHD_NO;
+           if ( (NULL == connection->response) ||
+                (NULL == connection->response->upgrade_handler) )
 #endif /* UPGRADE_SUPPORT */
+             return MHD_NO;
+        }
+      if (MHD_lookup_header_s_token_ci (connection,
+                                        MHD_HTTP_HEADER_CONNECTION,
+                                        "close"))
+        return MHD_NO;
 
-    return MHD_YES;
-  }
+      return MHD_YES;
+    }
   if (MHD_str_equal_caseless_(connection->version,
                               MHD_HTTP_VERSION_1_0))
-  {
-    if (NULL == end)
+    {
+      if (MHD_lookup_header_s_token_ci (connection,
+                                        MHD_HTTP_HEADER_CONNECTION,
+                                        "Keep-Alive"))
+        return MHD_YES;
+
       return MHD_NO;
-    if (MHD_str_equal_caseless_(end,
-                                "Keep-Alive"))
-      return MHD_YES;
-    return MHD_NO;
-  }
+    }
   return MHD_NO;
 }
 
@@ -1018,9 +1067,9 @@ build_header_response (struct MHD_Connection *connection)
   enum MHD_ValueKind kind;
   const char *reason_phrase;
   uint32_t rc;
-  const char *client_requested_close;
-  const char *response_has_close;
-  const char *response_has_keepalive;
+  bool client_requested_close;
+  bool response_has_close;
+  bool response_has_keepalive;
   const char *have_encoding;
   const char *have_content_length;
   int must_add_close;
@@ -1082,28 +1131,20 @@ build_header_response (struct MHD_Connection 
*connection)
   must_add_chunked_encoding = MHD_NO;
   must_add_keep_alive = MHD_NO;
   must_add_content_length = MHD_NO;
-  response_has_keepalive = NULL;
+  response_has_close = false;
+  response_has_keepalive = false;
   switch (connection->state)
     {
     case MHD_CONNECTION_FOOTERS_RECEIVED:
-      response_has_close = MHD_get_response_header (connection->response,
-                                                    
MHD_HTTP_HEADER_CONNECTION);
-      response_has_keepalive = response_has_close;
-      if ( (NULL != response_has_close) &&
-           (! MHD_str_equal_caseless_ (response_has_close,
-                                       "close")) )
-        response_has_close = NULL;
-      if ( (NULL != response_has_keepalive) &&
-           (! MHD_str_equal_caseless_ (response_has_keepalive,
-                                       "Keep-Alive")) )
-        response_has_keepalive = NULL;
-      client_requested_close = MHD_lookup_connection_value (connection,
-                                                            MHD_HEADER_KIND,
-                                                            
MHD_HTTP_HEADER_CONNECTION);
-      if ( (NULL != client_requested_close) &&
-           (! MHD_str_equal_caseless_ (client_requested_close,
-                                       "close")) )
-        client_requested_close = NULL;
+      response_has_close = MHD_check_response_header_s_token_ci 
(connection->response,
+                                                                 
MHD_HTTP_HEADER_CONNECTION,
+                                                                 "close");
+      response_has_keepalive = MHD_check_response_header_s_token_ci 
(connection->response,
+                                                                     
MHD_HTTP_HEADER_CONNECTION,
+                                                                     
"Keep-Alive");
+      client_requested_close = MHD_lookup_header_s_token_ci (connection,
+                                                            
MHD_HTTP_HEADER_CONNECTION,
+                                                            "close");
 
       if (0 != (connection->response->flags & MHD_RF_HTTP_VERSION_1_0_ONLY))
         connection->keepalive = MHD_CONN_MUST_CLOSE;
@@ -1112,8 +1153,8 @@ build_header_response (struct MHD_Connection *connection)
       connection->have_chunked_upload = false;
 
       if ( (MHD_SIZE_UNKNOWN == connection->response->total_size) &&
-           (NULL == response_has_close) &&
-           (NULL == client_requested_close) )
+           (! response_has_close) &&
+           (! client_requested_close) )
         {
           /* size is unknown, and close was not explicitly requested;
              need to either to HTTP 1.1 chunked encoding or
@@ -1146,16 +1187,16 @@ build_header_response (struct MHD_Connection 
*connection)
             {
               /* Keep alive or chunking not possible
                  => set close header if not present */
-              if (NULL == response_has_close)
+              if (! response_has_close)
                 must_add_close = MHD_YES;
             }
         }
 
       /* check for other reasons to add 'close' header */
-      if ( ( (NULL != client_requested_close) ||
+      if ( ( (client_requested_close) ||
              (connection->read_closed) ||
              (MHD_CONN_MUST_CLOSE == connection->keepalive)) &&
-           (NULL == response_has_close) &&
+           (! response_has_close) &&
            (0 == (connection->response->flags & MHD_RF_HTTP_VERSION_1_0_ONLY) 
) )
         must_add_close = MHD_YES;
 
@@ -1199,15 +1240,15 @@ build_header_response (struct MHD_Connection 
*connection)
         }
 
       /* check for adding keep alive */
-      if ( (NULL == response_has_keepalive) &&
-           (NULL == response_has_close) &&
+      if ( (! response_has_keepalive) &&
+           (! response_has_close) &&
            (MHD_NO == must_add_close) &&
            (MHD_CONN_MUST_CLOSE != connection->keepalive) &&
            (MHD_YES == keepalive_possible (connection)) )
         must_add_keep_alive = MHD_YES;
       break;
     case MHD_CONNECTION_BODY_SENT:
-      response_has_keepalive = NULL;
+      response_has_keepalive = false;
       break;
     default:
       EXTRA_CHECK (0);
@@ -1215,9 +1256,9 @@ build_header_response (struct MHD_Connection *connection)
 
   if (MHD_CONN_MUST_CLOSE != connection->keepalive)
     {
-      if ( (must_add_close) || (NULL != response_has_close) )
+      if ( (must_add_close) || (response_has_close) )
         connection->keepalive = MHD_CONN_MUST_CLOSE;
-      else if ( (must_add_keep_alive) || (NULL != response_has_keepalive) )
+      else if ( (must_add_keep_alive) || (response_has_keepalive) )
         connection->keepalive = MHD_CONN_USE_KEEPALIVE;
     }
 
@@ -1233,12 +1274,17 @@ build_header_response (struct MHD_Connection 
*connection)
   EXTRA_CHECK (! (must_add_chunked_encoding && must_add_content_length) );
 
   for (pos = connection->response->first_header; NULL != pos; pos = pos->next)
-    if ( (pos->kind == kind) &&
-         (! ( (MHD_YES == must_add_close) &&
-              (pos->value == response_has_keepalive) &&
-              (MHD_str_equal_caseless_(pos->header,
-                                MHD_HTTP_HEADER_CONNECTION) ) ) ) )
-      size += strlen (pos->header) + strlen (pos->value) + 4; /* colon, space, 
linefeeds */
+    {
+      /* TODO: add proper support for excluding "Keep-Alive" token. */
+      if ( (pos->kind == kind) &&
+           (! ( (MHD_YES == must_add_close) &&
+                (response_has_keepalive) &&
+                (MHD_str_equal_caseless_(pos->header,
+                                         MHD_HTTP_HEADER_CONNECTION)) &&
+                (MHD_str_equal_caseless_(pos->value,
+                                         "Keep-Alive")) ) ) )
+        size += strlen (pos->header) + strlen (pos->value) + 4; /* colon, 
space, linefeeds */
+    }
   /* produce data */
   data = MHD_pool_allocate (connection->pool,
                             size + 1,
@@ -1290,16 +1336,21 @@ build_header_response (struct MHD_Connection 
*connection)
       off += content_length_len;
     }
   for (pos = connection->response->first_header; NULL != pos; pos = pos->next)
-    if ( (pos->kind == kind) &&
-         (! ( (pos->value == response_has_keepalive) &&
-              (MHD_YES == must_add_close) &&
-              (MHD_str_equal_caseless_(pos->header,
-                                       MHD_HTTP_HEADER_CONNECTION) ) ) ) )
-      off += MHD_snprintf_ (&data[off],
-                           size - off,
-                           "%s: %s\r\n",
-                           pos->header,
-                           pos->value);
+    {
+      /* TODO: add proper support for excluding "Keep-Alive" token. */
+      if ( (pos->kind == kind) &&
+           (! ( (MHD_YES == must_add_close) &&
+                (response_has_keepalive) &&
+                (MHD_str_equal_caseless_(pos->header,
+                                         MHD_HTTP_HEADER_CONNECTION)) &&
+                (MHD_str_equal_caseless_(pos->value,
+                                         "Keep-Alive")) ) ) )
+        off += MHD_snprintf_ (&data[off],
+                              size - off,
+                              "%s: %s\r\n",
+                              pos->header,
+                              pos->value);
+    }
   if (MHD_CONNECTION_FOOTERS_RECEIVED == connection->state)
     {
       strcpy (&data[off],
diff --git a/src/microhttpd/internal.h b/src/microhttpd/internal.h
index cb6753c9..e2d8cfb6 100644
--- a/src/microhttpd/internal.h
+++ b/src/microhttpd/internal.h
@@ -117,10 +117,13 @@ extern void *mhd_panic_cls;
 #define BUILTIN_NOT_REACHED
 #endif
 
+#ifndef MHD_STATICSTR_LEN_
 /**
  * Determine length of static string / macro strings at compile time.
  */
 #define MHD_STATICSTR_LEN_(macro) (sizeof(macro)/sizeof(char) - 1)
+#endif /* ! MHD_STATICSTR_LEN_ */
+
 
 /**
  * State of the socket with respect to epoll (bitmask).
@@ -1885,4 +1888,38 @@ MHD_parse_arguments_ (struct MHD_Connection *connection,
                      unsigned int *num_headers);
 
 
+/**
+ * Check whether response header contains particular @a 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 token     the token to find
+ * @param token_len the length of token, not including optional
+ *                  terminating null-character.
+ * @return true if token is found in specified header,
+ *         false otherwise
+ */
+bool
+MHD_check_response_header_token_ci (const struct MHD_Response *response,
+                                    const char *key,
+                                    const char *token,
+                                    size_t token_len);
+
+/**
+ * Check whether response header contains particular static @a tkn.
+ *
+ * Token could be surrounded by spaces and tabs and delimited by comma.
+ * Case-insensitive match used for header names and tokens.
+ * @param r   the response to query
+ * @param k   header name
+ * @param tkn the static string of token to find
+ * @return true if token is found in specified header,
+ *         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))
+
+
 #endif
diff --git a/src/microhttpd/mhd_str.c b/src/microhttpd/mhd_str.c
index c5e9813c..bb10d26f 100644
--- a/src/microhttpd/mhd_str.c
+++ b/src/microhttpd/mhd_str.c
@@ -365,6 +365,64 @@ MHD_str_equal_caseless_n_ (const char * const str1,
   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
+ * contains only case-insensitive token and optional spaces and tabs.
+ * @warning token must not contain null-charters except optional
+ *          terminating null-character.
+ * @param str the string to check
+ * @param token the token to find
+ * @param token_len length of token, not including optional terminating
+ *                  null-character.
+ * @return non-zero if two strings are equal, zero otherwise.
+ */
+bool
+MHD_str_has_token_caseless_ (const char * str,
+                             const char * const token,
+                             size_t token_len)
+{
+  if (0 == token_len)
+    return false;
+
+  while (0 != *str)
+    {
+      size_t i;
+      /* Skip all whitespaces and empty tokens. */
+      while (' ' == *str || '\t' == *str || ',' == *str) str++;
+
+      /* Check for token match. */
+      i = 0;
+      while (1)
+        {
+          const char sc = *(str++);
+          const char tc = token[i++];
+
+          if (0 == sc)
+            return false;
+          if ( (sc != tc) &&
+               (toasciilower (sc) != toasciilower (tc)) )
+            break;
+          if (i >= token_len)
+            {
+              /* Check whether substring match token fully or
+               * has additional unmatched chars at tail. */
+              while (' ' == *str || '\t' == *str) str++;
+              /* End of (sub)string? */
+              if (0 == *str || ',' == *str)
+                return true;
+              /* Unmatched chars at end of substring. */
+              break;
+            }
+        }
+       /* Find next substring. */
+      while (0 != *str && ',' != *str) str++;
+    }
+  return false;
+}
+
 #ifndef MHD_FAVOR_SMALL_CODE
 /* Use individual function for each case */
 
diff --git a/src/microhttpd/mhd_str.h b/src/microhttpd/mhd_str.h
index 0ee41717..410cc36e 100644
--- a/src/microhttpd/mhd_str.h
+++ b/src/microhttpd/mhd_str.h
@@ -30,11 +30,21 @@
 
 #include <stdint.h>
 #include <stdlib.h>
+#ifdef HAVE_STDBOOL_H
+#include <stdbool.h>
+#endif /* HAVE_STDBOOL_H */
 
 #ifdef MHD_FAVOR_SMALL_CODE
 #include "mhd_limits.h"
 #endif /* MHD_FAVOR_SMALL_CODE */
 
+#ifndef MHD_STATICSTR_LEN_
+/**
+ * Determine length of static string / macro strings at compile time.
+ */
+#define MHD_STATICSTR_LEN_(macro) (sizeof(macro)/sizeof(char) - 1)
+#endif /* ! MHD_STATICSTR_LEN_ */
+
 /*
  * Block of functions/macros that use US-ASCII charset as required by HTTP
  * standards. Not affected by current locale settings.
@@ -71,6 +81,38 @@ MHD_str_equal_caseless_n_ (const char * const str1,
                   const char * const str2,
                   size_t maxlen);
 
+
+/**
+ * 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
+ * contains only case-insensitive token and optional spaces and tabs.
+ * @warning token must not contain null-charters except optional
+ *          terminating null-character.
+ * @param str the string to check
+ * @param token the token to find
+ * @param token_len length of token, not including optional terminating
+ *                  null-character.
+ * @return non-zero if two strings are equal, zero otherwise.
+ */
+bool
+MHD_str_has_token_caseless_ (const char * str,
+                             const char * const token,
+                             size_t token_len);
+
+/**
+ * Check whether @a str has case-insensitive static @a tkn.
+ * Token could be surrounded by spaces and tabs and delimited by comma.
+ * Match succeed if substring between start, end of string or comma
+ * contains only case-insensitive token and optional spaces and tabs.
+ * @warning tkn must be static string
+ * @param str the string to check
+ * @param tkn the static string of token to find
+ * @return non-zero if two strings are equal, zero otherwise.
+ */
+#define MHD_str_has_s_token_caseless_(str,tkn) \
+    MHD_str_has_token_caseless_((str),(tkn),MHD_STATICSTR_LEN_(tkn))
+
 #ifndef MHD_FAVOR_SMALL_CODE
 /* Use individual function for each case to improve speed */
 
diff --git a/src/microhttpd/response.c b/src/microhttpd/response.c
index 4326da07..5ab97b35 100644
--- a/src/microhttpd/response.c
+++ b/src/microhttpd/response.c
@@ -39,6 +39,7 @@
 #include "mhd_limits.h"
 #include "mhd_sockets.h"
 #include "mhd_itc.h"
+#include "mhd_str.h"
 #include "connection.h"
 #include "memorypool.h"
 #include "mhd_compat.h"
@@ -247,6 +248,40 @@ MHD_get_response_header (struct MHD_Response *response,
   return NULL;
 }
 
+/**
+ * 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 token     the token to find
+ * @param token_len the length of token, not including optional
+ *                  terminating null-character.
+ * @return true if token is found in specified header,
+ *         false otherwise
+ */
+bool
+MHD_check_response_header_token_ci (const struct MHD_Response *response,
+                                    const char *key,
+                                    const char *token,
+                                    size_t token_len)
+{
+  struct MHD_HTTP_Header *pos;
+
+  if (NULL == key || 0 == key[0] || NULL == token || 0 == token[0])
+    return false;
+
+  for (pos = response->first_header; NULL != pos; pos = pos->next)
+    {
+      if ( (pos->kind == MHD_HEADER_KIND) &&
+           MHD_str_equal_caseless_ (pos->header, key) &&
+           MHD_str_has_token_caseless_ (pos->value, token, token_len) )
+        return true;
+    }
+  return false;
+}
+
 
 /**
  * Create a response object.  The response object can be extended with

-- 
To stop receiving notification emails like this one, please contact
address@hidden



reply via email to

[Prev in Thread] Current Thread [Next in Thread]