yhirose 8 years ago
parent
commit
4fb2f51766
2 changed files with 56 additions and 24 deletions
  1. 25 24
      httplib.h
  2. 31 0
      test/test.cc

+ 25 - 24
httplib.h

@@ -738,18 +738,21 @@ inline bool is_hex(char c, int& v)
     return false;
     return false;
 }
 }
 
 
-inline int from_hex_to_i(const std::string& s, int i, int cnt, int& val)
+inline bool from_hex_to_i(const std::string& s, int i, int cnt, int& val)
 {
 {
     val = 0;
     val = 0;
-    for (; s[i] && cnt; i++, cnt--) {
+    for (; cnt; i++, cnt--) {
+        if (!s[i]) {
+            return false;
+        }
         int v = 0;
         int v = 0;
         if (is_hex(s[i], v)) {
         if (is_hex(s[i], v)) {
             val = val * 16 + v;
             val = val * 16 + v;
         } else {
         } else {
-            break;
+            return false;
         }
         }
     }
     }
-    return --i;
+    return true;
 }
 }
 
 
 inline size_t to_utf8(int code, char* buff)
 inline size_t to_utf8(int code, char* buff)
@@ -791,30 +794,28 @@ inline std::string decode_url(const std::string& s)
 
 
     for (int i = 0; s[i]; i++) {
     for (int i = 0; s[i]; i++) {
         if (s[i] == '%') {
         if (s[i] == '%') {
-            i++;
-            assert(s[i]);
-
-            if (s[i] == '%') {
-                result += s[i];
-            } else if (s[i] == 'u') {
-                // Unicode
-                i++;
-                assert(s[i]);
-
+            if (s[i + 1] && s[i + 1] == 'u') {
                 int val = 0;
                 int val = 0;
-                i = from_hex_to_i(s, i, 4, val);
-
-                char buff[4];
-                size_t len = to_utf8(val, buff);
-
-                if (len > 0) {
-                    result.append(buff, len);
+                if (from_hex_to_i(s, i + 2, 4, val)) {
+                    // 4 digits Unicode codes
+                    char buff[4];
+                    size_t len = to_utf8(val, buff);
+                    if (len > 0) {
+                        result.append(buff, len);
+                    }
+                    i += 5; // 'u0000'
+                } else {
+                    result += s[i];
                 }
                 }
             } else {
             } else {
-                // HEX
                 int val = 0;
                 int val = 0;
-                i = from_hex_to_i(s, i, 2, val);
-                result += val;
+                if (from_hex_to_i(s, i + 1, 2, val)) {
+                    // 2 digits hex codes
+                    result += val;
+                    i += 2; // '00'
+                } else {
+                    result += s[i];
+                }
             }
             }
         } else if (s[i] == '+') {
         } else if (s[i] == '+') {
             result += ' ';
             result += ' ';

+ 31 - 0
test/test.cc

@@ -151,6 +151,9 @@ protected:
         svr_.get("/hi", [&](const Request& /*req*/, Response& res) {
         svr_.get("/hi", [&](const Request& /*req*/, Response& res) {
                 res.set_content("Hello World!", "text/plain");
                 res.set_content("Hello World!", "text/plain");
             })
             })
+            .get("/endwith%", [&](const Request& /*req*/, Response& res) {
+                res.set_content("Hello World!", "text/plain");
+            })
             .get("/", [&](const Request& /*req*/, Response& res) {
             .get("/", [&](const Request& /*req*/, Response& res) {
                 res.set_redirect("/hi");
                 res.set_redirect("/hi");
             })
             })
@@ -427,6 +430,34 @@ TEST_F(ServerTest, TooLongHeader)
 	EXPECT_EQ(400, res->status);
 	EXPECT_EQ(400, res->status);
 }
 }
 
 
+TEST_F(ServerTest, PercentEncoding)
+{
+    auto res = cli_.get("/e%6edwith%");
+    ASSERT_TRUE(res != nullptr);
+	EXPECT_EQ(200, res->status);
+}
+
+TEST_F(ServerTest, PercentEncodingUnicode)
+{
+    auto res = cli_.get("/e%u006edwith%");
+    ASSERT_TRUE(res != nullptr);
+	EXPECT_EQ(200, res->status);
+}
+
+TEST_F(ServerTest, InvalidPercentEncoding)
+{
+    auto res = cli_.get("/%endwith%");
+    ASSERT_TRUE(res != nullptr);
+	EXPECT_EQ(404, res->status);
+}
+
+TEST_F(ServerTest, InvalidPercentEncodingUnicode)
+{
+    auto res = cli_.get("/%uendwith%");
+    ASSERT_TRUE(res != nullptr);
+	EXPECT_EQ(404, res->status);
+}
+
 class ServerTestWithAI_PASSIVE : public ::testing::Test {
 class ServerTestWithAI_PASSIVE : public ::testing::Test {
 protected:
 protected:
     ServerTestWithAI_PASSIVE()
     ServerTestWithAI_PASSIVE()