Skip to content

Commit 71ddf32

Browse files
authored
URL encode HTTP request path (#106)
* URL encode HTTP request path * better hexify * add URL encoding test
1 parent a6373dc commit 71ddf32

File tree

2 files changed

+46
-3
lines changed

2 files changed

+46
-3
lines changed

src/http_req.c

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -97,14 +97,35 @@ void free_hdr_list(um_header_list *l) {
9797
}
9898
}
9999

100+
#define HEXIFY(c) (((c) < 10) ? '0' + (c) : 'A' + (c) - 10)
101+
102+
static size_t write_url_encoded(char *buf, const char *url) {
103+
static char unsafe[] = "\"<>%{}|\\^`";
104+
char *p = buf;
105+
for(; *url != 0; url++) {
106+
if (*url <= ' ' || strchr(unsafe, *url) != NULL) {
107+
*p++ = '%';
108+
*p++ = HEXIFY((*url >> 4) & 0xf);
109+
*p++ = HEXIFY(*url & 0xf);
110+
} else {
111+
*p++ = *url;
112+
}
113+
}
114+
return p - buf;
115+
}
116+
100117
size_t http_req_write(um_http_req_t *req, char *buf, size_t maxlen) {
101118
const char *pfx = "";
102119
if (req->client && req->client->prefix) {
103120
pfx = req->client->prefix;
104121
}
105-
size_t len = snprintf(buf, maxlen,
106-
"%s %s%s HTTP/1.1\r\n",
107-
req->method, pfx, req->path);
122+
123+
size_t len = 0;
124+
len += snprintf(buf, maxlen, "%s ", req->method);
125+
len += write_url_encoded(buf + len, pfx);
126+
len += write_url_encoded(buf + len, req->path);
127+
len += snprintf(buf + len, maxlen - len, " HTTP/1.1\r\n");
128+
108129

109130
if (strcmp(req->method, "POST") == 0 ||
110131
strcmp(req->method, "PUT") == 0 ||

tests/http_tests.cpp

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -822,6 +822,28 @@ TEST_CASE("HTTP deflate", "[http]") {
822822
CHECK(resp.resp_body_end_called == 1);
823823

824824

825+
std::cout << resp.req_body << std::endl;
826+
827+
um_http_close(&clt, nullptr);
828+
}
829+
830+
TEST_CASE("URL encode", "[http]") {
831+
UvLoopTest test;
832+
833+
um_http_t clt;
834+
resp_capture resp(resp_body_cb);
835+
836+
um_http_init(test.loop, &clt, "https://www.google.com/search");
837+
um_http_req_t *req = um_http_req(&clt, "GET", R"(?query=this is a <test>!)", resp_capture_cb, &resp);
838+
839+
test.run();
840+
841+
CHECK(resp.code == HTTP_STATUS_OK);
842+
CHECK_THAT(resp.http_version, Equals("1.1"));
843+
CHECK_THAT(resp.status, Equals("OK"));
844+
CHECK(resp.resp_body_end_called == 1);
845+
CHECK_THAT(resp.body, Contains("this is a test", Catch::CaseSensitive::No));
846+
825847
std::cout << resp.req_body << std::endl;
826848

827849
um_http_close(&clt, nullptr);

0 commit comments

Comments
 (0)