You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mesos.apache.org by bm...@apache.org on 2015/06/12 21:21:58 UTC

[3/3] mesos git commit: Treat HTTP headers as case-insensitive.

Treat HTTP headers as case-insensitive.

Review: https://reviews.apache.org/r/33793


Project: http://git-wip-us.apache.org/repos/asf/mesos/repo
Commit: http://git-wip-us.apache.org/repos/asf/mesos/commit/a0811310
Tree: http://git-wip-us.apache.org/repos/asf/mesos/tree/a0811310
Diff: http://git-wip-us.apache.org/repos/asf/mesos/diff/a0811310

Branch: refs/heads/master
Commit: a0811310c82ee25644fc9a6362313ce3619e46d9
Parents: 0b7cbe8
Author: haosdent huang <ha...@gmail.com>
Authored: Fri Jun 12 12:03:27 2015 -0700
Committer: Benjamin Mahler <be...@gmail.com>
Committed: Fri Jun 12 12:13:39 2015 -0700

----------------------------------------------------------------------
 3rdparty/libprocess/include/process/http.hpp | 49 ++++++++++++++++++++---
 3rdparty/libprocess/src/encoder.hpp          |  2 +-
 3rdparty/libprocess/src/tests/http_tests.cpp | 27 +++++++++++++
 3 files changed, 71 insertions(+), 7 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/mesos/blob/a0811310/3rdparty/libprocess/include/process/http.hpp
----------------------------------------------------------------------
diff --git a/3rdparty/libprocess/include/process/http.hpp b/3rdparty/libprocess/include/process/http.hpp
index 51a00f5..e47cc7a 100644
--- a/3rdparty/libprocess/include/process/http.hpp
+++ b/3rdparty/libprocess/include/process/http.hpp
@@ -1,6 +1,7 @@
 #ifndef __PROCESS_HTTP_HPP__
 #define __PROCESS_HTTP_HPP__
 
+#include <ctype.h>
 #include <stdint.h>
 
 #include <atomic>
@@ -11,6 +12,8 @@
 #include <string>
 #include <vector>
 
+#include <boost/functional/hash.hpp>
+
 #include <process/address.hpp>
 #include <process/future.hpp>
 #include <process/owned.hpp>
@@ -45,6 +48,36 @@ extern hashmap<uint16_t, std::string> statuses;
 void initialize();
 
 
+struct CaseInsensitiveHash
+{
+  size_t operator () (const std::string& key) const
+  {
+    size_t seed = 0;
+    foreach (char c, key) {
+      boost::hash_combine(seed, ::tolower(c));
+    }
+    return seed;
+  }
+};
+
+
+struct CaseInsensitiveEqual
+{
+  bool operator () (const std::string& left, const std::string& right) const
+  {
+    if (left.size() != right.size()) {
+      return false;
+    }
+    for (size_t i = 0; i < left.size(); ++i) {
+      if (::tolower(left[i]) != ::tolower(right[i])) {
+        return false;
+      }
+    }
+    return true;
+  }
+};
+
+
 struct Request
 {
   // Contains the client's address. Note that this may
@@ -52,11 +85,11 @@ struct Request
   network::Address client;
 
   // TODO(benh): Add major/minor version.
-  // TODO(bmahler): Header names are not case sensitive! Either make these
-  // case-insensitive, or add a variable for each header in HTTP 1.0/1.1 (like
-  // we've done here with keepAlive).
-  // Tracked by: https://issues.apache.org/jira/browse/MESOS-328.
-  hashmap<std::string, std::string> headers;
+  hashmap<std::string,
+          std::string,
+          CaseInsensitiveHash,
+          CaseInsensitiveEqual> headers;
+
   std::string method;
 
   // TODO(benh): Replace 'url', 'path', 'query', and 'fragment' with URL.
@@ -237,7 +270,11 @@ struct Response
 
   // TODO(benh): Add major/minor version.
   std::string status;
-  hashmap<std::string, std::string> headers;
+
+  hashmap<std::string,
+          std::string,
+          CaseInsensitiveHash,
+          CaseInsensitiveEqual> headers;
 
   // Either provide a 'body', an absolute 'path' to a file, or a
   // 'pipe' for streaming a response. Distinguish between the cases

http://git-wip-us.apache.org/repos/asf/mesos/blob/a0811310/3rdparty/libprocess/src/encoder.hpp
----------------------------------------------------------------------
diff --git a/3rdparty/libprocess/src/encoder.hpp b/3rdparty/libprocess/src/encoder.hpp
index f1b91cf..b898658 100644
--- a/3rdparty/libprocess/src/encoder.hpp
+++ b/3rdparty/libprocess/src/encoder.hpp
@@ -164,7 +164,7 @@ public:
 
     out << "HTTP/1.1 " << response.status << "\r\n";
 
-    hashmap<std::string, std::string> headers = response.headers;
+    auto headers = response.headers;
 
     // HTTP 1.1 requires the "Date" header. In the future once we
     // start checking the version (above) then we can conditionally

http://git-wip-us.apache.org/repos/asf/mesos/blob/a0811310/3rdparty/libprocess/src/tests/http_tests.cpp
----------------------------------------------------------------------
diff --git a/3rdparty/libprocess/src/tests/http_tests.cpp b/3rdparty/libprocess/src/tests/http_tests.cpp
index 708e331..8444b9c 100644
--- a/3rdparty/libprocess/src/tests/http_tests.cpp
+++ b/3rdparty/libprocess/src/tests/http_tests.cpp
@@ -591,6 +591,33 @@ TEST(HTTP, QueryEncodeDecode)
                  http::query::decode("a%26b%3Dc=d%26e%3Dfg"));
 }
 
+
+TEST(HTTP, CaseInsensitiveHeaders)
+{
+  http::Request request;
+  request.headers["Content-Length"] = "20";
+  EXPECT_EQ("20", request.headers["Content-Length"]);
+  EXPECT_EQ("20", request.headers["CONTENT-LENGTH"]);
+  EXPECT_EQ("20", request.headers["content-length"]);
+
+  request.headers["content-length"] = "30";
+  EXPECT_EQ("30", request.headers["content-length"]);
+  EXPECT_EQ("30", request.headers["Content-Length"]);
+  EXPECT_EQ("30", request.headers["CONTENT-LENGTH"]);
+
+  http::Response response;
+  response.headers["Content-Type"] = "application/json";
+  EXPECT_EQ("application/json", response.headers["Content-Type"]);
+  EXPECT_EQ("application/json", response.headers["content-type"]);
+  EXPECT_EQ("application/json", response.headers["CONTENT-TYPE"]);
+
+  response.headers["content-type"] = "text/javascript";
+  EXPECT_EQ("text/javascript", response.headers["content-type"]);
+  EXPECT_EQ("text/javascript", response.headers["Content-Type"]);
+  EXPECT_EQ("text/javascript", response.headers["CONTENT-TYPE"]);
+}
+
+
 // TODO(evelinad): Add URLTest for IPv6.
 TEST(URLTest, stringification)
 {