From 4fb2f51766554dcae4383df6150f60b448e9ae04 Mon Sep 17 00:00:00 2001 From: yhirose Date: Sun, 3 Dec 2017 22:31:00 -0500 Subject: [PATCH] Fixed #19 --- httplib.h | 49 +++++++++++++++++++++++++------------------------ test/test.cc | 31 +++++++++++++++++++++++++++++++ 2 files changed, 56 insertions(+), 24 deletions(-) diff --git a/httplib.h b/httplib.h index 0647800..3f8f41f 100644 --- a/httplib.h +++ b/httplib.h @@ -738,18 +738,21 @@ inline bool is_hex(char c, int& v) 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; - for (; s[i] && cnt; i++, cnt--) { + for (; cnt; i++, cnt--) { + if (!s[i]) { + return false; + } int v = 0; if (is_hex(s[i], v)) { val = val * 16 + v; } else { - break; + return false; } } - return --i; + return true; } 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++) { 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; - 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 { - // HEX 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] == '+') { result += ' '; diff --git a/test/test.cc b/test/test.cc index cca1305..b3a2d47 100644 --- a/test/test.cc +++ b/test/test.cc @@ -151,6 +151,9 @@ protected: svr_.get("/hi", [&](const Request& /*req*/, Response& res) { 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) { res.set_redirect("/hi"); }) @@ -427,6 +430,34 @@ TEST_F(ServerTest, TooLongHeader) 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 { protected: ServerTestWithAI_PASSIVE()