Skip to content

Commit

Permalink
Fix: Query parameter including query delimiter ('?') not being parsed…
Browse files Browse the repository at this point in the history
… properly (yhirose#1713)

* Fix: Query parameter including query delimiter ('?') not being parsed properly

* Add details::split function with and without m argument to allow split parameters with/without counter

* Revert changes in SplitTest.ParseQueryString
  • Loading branch information
davidalo authored Dec 7, 2023
1 parent f14accb commit e426a38
Show file tree
Hide file tree
Showing 2 changed files with 26 additions and 2 deletions.
15 changes: 13 additions & 2 deletions httplib.h
Original file line number Diff line number Diff line change
Expand Up @@ -1989,8 +1989,12 @@ void read_file(const std::string &path, std::string &out);
std::string trim_copy(const std::string &s);

void split(const char *b, const char *e, char d,
std::function<void(const char *, const char *)> fn);

void split(const char *b, const char *e, char d, size_t m,
std::function<void(const char *, const char *)> fn);


bool process_client_socket(socket_t sock, time_t read_timeout_sec,
time_t read_timeout_usec, time_t write_timeout_sec,
time_t write_timeout_usec,
Expand Down Expand Up @@ -2473,14 +2477,21 @@ inline std::string trim_double_quotes_copy(const std::string &s) {

inline void split(const char *b, const char *e, char d,
std::function<void(const char *, const char *)> fn) {
return split(b, e, d, std::numeric_limits<size_t>::max(), fn);
}

inline void split(const char *b, const char *e, char d, size_t m,
std::function<void(const char *, const char *)> fn) {
size_t i = 0;
size_t beg = 0;
size_t count = 1;

while (e ? (b + i < e) : (b[i] != '\0')) {
if (b[i] == d) {
if (b[i] == d && count < m) {
auto r = trim(b, e, beg, i);
if (r.first < r.second) { fn(&b[r.first], &b[r.second]); }
beg = i + 1;
count++;
}
i++;
}
Expand Down Expand Up @@ -5804,7 +5815,7 @@ inline bool Server::parse_request_line(const char *s, Request &req) const {

size_t count = 0;

detail::split(req.target.data(), req.target.data() + req.target.size(), '?',
detail::split(req.target.data(), req.target.data() + req.target.size(), '?', 2,
[&](const char *b, const char *e) {
switch (count) {
case 0:
Expand Down
13 changes: 13 additions & 0 deletions test/test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1847,6 +1847,11 @@ class ServerTest : public ::testing::Test {
return true;
});
})
.Get("/regex-with-delimiter",
[&](const Request & req, Response &res) {
ASSERT_TRUE(req.has_param("key"));
EXPECT_EQ("^(?.*(value))", req.get_param_value("key"));
})
.Get("/with-range",
[&](const Request & /*req*/, Response &res) {
res.set_content("abcdefg", "text/plain");
Expand Down Expand Up @@ -3352,6 +3357,14 @@ TEST_F(ServerTest, GetStreamedChunkedWithGzip2) {
EXPECT_EQ(std::string("123456789"), res->body);
}


TEST_F(ServerTest, SplitDelimiterInPathRegex) {
auto res = cli_.Get("/regex-with-delimiter?key=^(?.*(value))");
ASSERT_TRUE(res);
EXPECT_EQ(200, res->status);
}


TEST(GzipDecompressor, ChunkedDecompression) {
std::string data;
for (size_t i = 0; i < 32 * 1024; ++i) {
Expand Down

0 comments on commit e426a38

Please sign in to comment.