File tree Expand file tree Collapse file tree
Expand file tree Collapse file tree Original file line number Diff line number Diff line change @@ -9734,11 +9734,9 @@ inline std::string decode_query_component(const std::string &component,
97349734
97359735 for (size_t i = 0; i < component.size(); i++) {
97369736 if (component[i] == '%' && i + 2 < component.size()) {
9737- std::string hex = component.substr(i + 1, 2);
9738- char *end;
9739- unsigned long value = std::strtoul(hex.c_str(), &end, 16);
9740- if (end == hex.c_str() + 2) {
9741- result += static_cast<char>(value);
9737+ auto val = 0;
9738+ if (detail::from_hex_to_i(component, i + 1, 2, val)) {
9739+ result += static_cast<char>(val);
97429740 i += 2;
97439741 } else {
97449742 result += component[i];
Original file line number Diff line number Diff line change @@ -386,6 +386,19 @@ TEST(DecodePathTest, UnicodeEncoding) {
386386 EXPECT_EQ("", decode_path_component("%uD800"));
387387}
388388
389+ TEST(DecodeQueryTest, RejectsNonHexEscapes) {
390+ // A sign or whitespace inside the two-character escape window must not be
391+ // accepted as a valid percent-encoding; the sequence is passed through
392+ // literally, matching decode_uri_component / decode_path_component.
393+ EXPECT_EQ("%-1", decode_query_component("%-1", false));
394+ EXPECT_EQ("%-0", decode_query_component("%-0", false));
395+ EXPECT_EQ("%+5", decode_query_component("%+5", false));
396+ EXPECT_EQ("% 5", decode_query_component("% 5", false));
397+ // Well-formed escapes still decode.
398+ EXPECT_EQ("-", decode_query_component("%2D", false));
399+ EXPECT_EQ("A", decode_query_component("%41", false));
400+ }
401+
389402TEST(SanitizeFilenameTest, VariousPatterns) {
390403 // Path traversal
391404 EXPECT_EQ("passwd", httplib::sanitize_filename("../../../etc/passwd"));
You can’t perform that action at this time.
0 commit comments