Skip to content

Commit 4fb2f51

Browse files
committed
Fixed yhirose#19
1 parent 3dded8c commit 4fb2f51

File tree

2 files changed

+56
-24
lines changed

2 files changed

+56
-24
lines changed

httplib.h

Lines changed: 25 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -738,18 +738,21 @@ inline bool is_hex(char c, int& v)
738738
return false;
739739
}
740740

741-
inline int from_hex_to_i(const std::string& s, int i, int cnt, int& val)
741+
inline bool from_hex_to_i(const std::string& s, int i, int cnt, int& val)
742742
{
743743
val = 0;
744-
for (; s[i] && cnt; i++, cnt--) {
744+
for (; cnt; i++, cnt--) {
745+
if (!s[i]) {
746+
return false;
747+
}
745748
int v = 0;
746749
if (is_hex(s[i], v)) {
747750
val = val * 16 + v;
748751
} else {
749-
break;
752+
return false;
750753
}
751754
}
752-
return --i;
755+
return true;
753756
}
754757

755758
inline size_t to_utf8(int code, char* buff)
@@ -791,30 +794,28 @@ inline std::string decode_url(const std::string& s)
791794

792795
for (int i = 0; s[i]; i++) {
793796
if (s[i] == '%') {
794-
i++;
795-
assert(s[i]);
796-
797-
if (s[i] == '%') {
798-
result += s[i];
799-
} else if (s[i] == 'u') {
800-
// Unicode
801-
i++;
802-
assert(s[i]);
803-
797+
if (s[i + 1] && s[i + 1] == 'u') {
804798
int val = 0;
805-
i = from_hex_to_i(s, i, 4, val);
806-
807-
char buff[4];
808-
size_t len = to_utf8(val, buff);
809-
810-
if (len > 0) {
811-
result.append(buff, len);
799+
if (from_hex_to_i(s, i + 2, 4, val)) {
800+
// 4 digits Unicode codes
801+
char buff[4];
802+
size_t len = to_utf8(val, buff);
803+
if (len > 0) {
804+
result.append(buff, len);
805+
}
806+
i += 5; // 'u0000'
807+
} else {
808+
result += s[i];
812809
}
813810
} else {
814-
// HEX
815811
int val = 0;
816-
i = from_hex_to_i(s, i, 2, val);
817-
result += val;
812+
if (from_hex_to_i(s, i + 1, 2, val)) {
813+
// 2 digits hex codes
814+
result += val;
815+
i += 2; // '00'
816+
} else {
817+
result += s[i];
818+
}
818819
}
819820
} else if (s[i] == '+') {
820821
result += ' ';

test/test.cc

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,9 @@ class ServerTest : public ::testing::Test {
151151
svr_.get("/hi", [&](const Request& /*req*/, Response& res) {
152152
res.set_content("Hello World!", "text/plain");
153153
})
154+
.get("/endwith%", [&](const Request& /*req*/, Response& res) {
155+
res.set_content("Hello World!", "text/plain");
156+
})
154157
.get("/", [&](const Request& /*req*/, Response& res) {
155158
res.set_redirect("/hi");
156159
})
@@ -427,6 +430,34 @@ TEST_F(ServerTest, TooLongHeader)
427430
EXPECT_EQ(400, res->status);
428431
}
429432

433+
TEST_F(ServerTest, PercentEncoding)
434+
{
435+
auto res = cli_.get("/e%6edwith%");
436+
ASSERT_TRUE(res != nullptr);
437+
EXPECT_EQ(200, res->status);
438+
}
439+
440+
TEST_F(ServerTest, PercentEncodingUnicode)
441+
{
442+
auto res = cli_.get("/e%u006edwith%");
443+
ASSERT_TRUE(res != nullptr);
444+
EXPECT_EQ(200, res->status);
445+
}
446+
447+
TEST_F(ServerTest, InvalidPercentEncoding)
448+
{
449+
auto res = cli_.get("/%endwith%");
450+
ASSERT_TRUE(res != nullptr);
451+
EXPECT_EQ(404, res->status);
452+
}
453+
454+
TEST_F(ServerTest, InvalidPercentEncodingUnicode)
455+
{
456+
auto res = cli_.get("/%uendwith%");
457+
ASSERT_TRUE(res != nullptr);
458+
EXPECT_EQ(404, res->status);
459+
}
460+
430461
class ServerTestWithAI_PASSIVE : public ::testing::Test {
431462
protected:
432463
ServerTestWithAI_PASSIVE()

0 commit comments

Comments
 (0)