diff --git a/include/opendht/http.h b/include/opendht/http.h index 954772e0..444fa16d 100644 --- a/include/opendht/http.h +++ b/include/opendht/http.h @@ -330,6 +330,8 @@ private: void build(); + static std::string url_encode(const std::string& value); + void init_default_headers(); /** * Initialized and wraps the http_parser callbacks with our user defined callbacks. diff --git a/src/http.cpp b/src/http.cpp index e1e0d7a7..c26ffef9 100644 --- a/src/http.cpp +++ b/src/http.cpp @@ -33,6 +33,10 @@ #include #include +#include +#include +#include + #define MAXAGE_SEC (14*24*60*60) #define JITTER_SEC (60) #define OCSP_MAX_RESPONSE_SIZE (20480) @@ -1048,7 +1052,7 @@ Request::build() bool append_body = !body_.empty(); // first header - request << header_.method().c_str() << " " << header_.request_target() << " " << + request << header_.method().c_str() << " " << url_encode(header_.request_target()) << " " << "HTTP/" << header_.http_major() << "." << header_.http_minor() << "\r\n"; // other headers @@ -1084,6 +1088,30 @@ Request::build() request_ = request.str(); } +// https://stackoverflow.com/a/17708801 +static std::string +Request::url_encode(const std::string& value) +{ + std::ostringstream escaped; + escaped.fill('0'); + escaped << std::hex; + + for (const char& c : value) { + // Keep alphanumeric and other accepted characters intact + if (std::isalnum(c) || c == '-' || c == '_' || c == '.' || c == '~') { + escaped << c; + continue; + } + + // Any other characters are percent-encoded + escaped << std::uppercase; + escaped << '%' << std::setw(2) << static_cast(static_cast(c)); + escaped << std::nouppercase; + } + + return escaped.str(); +} + void Request::add_on_status_callback(OnStatusCb cb) { cbs_.on_status = std::move(cb);