diff --git a/src/asio_client_request_impl.cc b/src/asio_client_request_impl.cc index 4be1cd10..ab92333c 100644 --- a/src/asio_client_request_impl.cc +++ b/src/asio_client_request_impl.cc @@ -80,26 +80,12 @@ void request_impl::uri(uri_ref uri) { uri_ = std::move(uri); } const uri_ref &request_impl::uri() const { return uri_; } +uri_ref &request_impl::uri() { return uri_; } + void request_impl::method(std::string s) { method_ = std::move(s); } const std::string &request_impl::method() const { return method_; } -void request_impl::scheme(std::string s) { scheme_ = std::move(s); } - -const std::string &request_impl::scheme() const { return scheme_; } - -void request_impl::path(std::string s) { path_ = std::move(s); } - -const std::string &request_impl::path() const { return path_; } - -void request_impl::authority(std::string s) { authority_ = std::move(s); } - -const std::string &request_impl::authority() const { return authority_; } - -void request_impl::host(std::string s) { host_ = std::move(s); } - -const std::string &request_impl::host() const { return host_; } - } // namespace client } // namespace asio_http2 } // namespace nghttp2 diff --git a/src/asio_client_request_impl.h b/src/asio_client_request_impl.h index 0ad938da..5fdf09b7 100644 --- a/src/asio_client_request_impl.h +++ b/src/asio_client_request_impl.h @@ -65,22 +65,11 @@ public: void uri(uri_ref uri); const uri_ref &uri() const; + uri_ref &uri(); void method(std::string s); const std::string &method() const; - void scheme(std::string s); - const std::string &scheme() const; - - void path(std::string s); - const std::string &path() const; - - void authority(std::string s); - const std::string &authority() const; - - void host(std::string s); - const std::string &host() const; - private: header_map header_; response_cb response_cb_; @@ -90,10 +79,6 @@ private: class stream *strm_; uri_ref uri_; std::string method_; - std::string scheme_; - std::string path_; - std::string authority_; - std::string host_; }; } // namespace client diff --git a/src/asio_client_session_impl.cc b/src/asio_client_session_impl.cc index 5282e8cc..1803cf57 100644 --- a/src/asio_client_session_impl.cc +++ b/src/asio_client_session_impl.cc @@ -162,24 +162,25 @@ int on_header_callback(nghttp2_session *session, const nghttp2_frame *frame, } auto &req = strm->request().impl(); + auto &uri = req.uri(); switch (http2::lookup_token(name, namelen)) { case http2::HD__METHOD: req.method(std::string(value, value + valuelen)); break; case http2::HD__SCHEME: - req.scheme(std::string(value, value + valuelen)); + uri.scheme.assign(value, value + valuelen); break; case http2::HD__PATH: - req.path(std::string(value, value + valuelen)); + split_path(uri, value, value + valuelen); break; case http2::HD__AUTHORITY: - req.authority(std::string(value, value + valuelen)); - // host defaults to authority value - req.host(std::string(value, value + valuelen)); + uri.host.assign(value, value + valuelen); break; case http2::HD_HOST: - req.host(std::string(value, value + valuelen)); + if (uri.host.empty()) { + uri.host.assign(value, value + valuelen); + } // fall through default: req.header().emplace(std::string(name, name + namelen), @@ -246,11 +247,6 @@ int on_frame_recv_callback(nghttp2_session *session, const nghttp2_frame *frame, return 0; } - auto &req = push_strm->request().impl(); - req.uri(make_uri_ref(req.scheme(), - req.authority().empty() ? req.host() : req.authority(), - req.path())); - strm->request().impl().call_on_push(push_strm->request()); break; @@ -392,16 +388,13 @@ const request *session_impl::submit(boost::system::error_code &ec, auto &req = strm->request().impl(); req.header(std::move(h)); - { - std::string scheme, host, raw_path, raw_query; - http2::copy_url_component(scheme, &u, UF_SCHEMA, uri.c_str()); - http2::copy_url_component(host, &u, UF_HOST, uri.c_str()); - http2::copy_url_component(raw_path, &u, UF_PATH, uri.c_str()); - http2::copy_url_component(raw_query, &u, UF_QUERY, uri.c_str()); + auto &uref = req.uri(); + http2::copy_url_component(uref.scheme, &u, UF_SCHEMA, uri.c_str()); + http2::copy_url_component(uref.host, &u, UF_HOST, uri.c_str()); + http2::copy_url_component(uref.raw_path, &u, UF_PATH, uri.c_str()); + http2::copy_url_component(uref.raw_query, &u, UF_QUERY, uri.c_str()); - req.uri(make_uri_ref(std::move(scheme), std::move(host), - std::move(raw_path), std::move(raw_query))); - } + uref.path = percent_decode(uref.raw_path); nghttp2_data_provider *prdptr = nullptr; nghttp2_data_provider prd; diff --git a/src/asio_common.cc b/src/asio_common.cc index fdad1915..34efefa5 100644 --- a/src/asio_common.cc +++ b/src/asio_common.cc @@ -57,28 +57,5 @@ read_cb string_reader(std::string data) { }; } -uri_ref make_uri_ref(std::string scheme, std::string host, std::string raw_path, - std::string raw_query) { - return uri_ref{ - std::move(scheme), std::move(host), percent_decode(raw_path), - std::move(raw_path), - }; -} - -uri_ref make_uri_ref(std::string scheme, std::string host, - const std::string &raw_path_query) { - auto path_end = raw_path_query.find('?'); - std::size_t query_pos; - if (path_end == std::string::npos) { - query_pos = path_end = raw_path_query.size(); - } else { - query_pos = path_end + 1; - } - return uri_ref{std::move(scheme), std::move(host), - util::percentDecode(std::begin(raw_path_query), - std::begin(raw_path_query) + path_end), - raw_path_query.substr(query_pos)}; -} - } // namespace asio_http2 } // namespace nghttp2 diff --git a/src/asio_common.h b/src/asio_common.h index ca6a63f0..fa3b01eb 100644 --- a/src/asio_common.h +++ b/src/asio_common.h @@ -31,20 +31,32 @@ #include +#include "util.h" + namespace nghttp2 { + namespace asio_http2 { read_cb string_reader(std::string data); boost::system::error_code make_error_code(nghttp2_error ev); -uri_ref make_uri_ref(std::string scheme, std::string host, std::string raw_path, - std::string raw_query); - -uri_ref make_uri_ref(std::string scheme, std::string host, - const std::string &raw_path_query); +template +void split_path(uri_ref &dst, InputIt first, InputIt last) { + auto path_last = std::find(first, last, '?'); + InputIt query_first; + if (path_last == last) { + query_first = path_last = last; + } else { + query_first = path_last + 1; + } + dst.path = util::percentDecode(first, path_last); + dst.raw_path.assign(first, path_last); + dst.raw_query.assign(query_first, last); +} } // namespace asio_http2 + } // namespace nghttp2 #endif // ASIO_COMMON_H diff --git a/src/includes/nghttp2/asio_http2.h b/src/includes/nghttp2/asio_http2.h index e38e8100..97c1b5d0 100644 --- a/src/includes/nghttp2/asio_http2.h +++ b/src/includes/nghttp2/asio_http2.h @@ -79,6 +79,7 @@ struct uri_ref { std::string host; // percent-decoded form std::string path; + std::string raw_path; std::string raw_query; std::string fragment; }; diff --git a/src/util.cc b/src/util.cc index 9d785a40..199bc27a 100644 --- a/src/util.cc +++ b/src/util.cc @@ -137,25 +137,6 @@ uint32_t hex_to_uint(char c) { return c; } -std::string percentDecode(std::string::const_iterator first, - std::string::const_iterator last) { - std::string result; - for (; first != last; ++first) { - if (*first == '%') { - if (first + 1 != last && first + 2 != last && isHexDigit(*(first + 1)) && - isHexDigit(*(first + 2))) { - result += (hex_to_uint(*(first + 1)) << 4) + hex_to_uint(*(first + 2)); - first += 2; - continue; - } - result += *first; - continue; - } - result += *first; - } - return result; -} - std::string quote_string(const std::string &target) { auto cnt = std::count(std::begin(target), std::end(target), '"'); diff --git a/src/util.h b/src/util.h index ca8155ab..c0be68ac 100644 --- a/src/util.h +++ b/src/util.h @@ -175,8 +175,24 @@ std::string percentEncode(const unsigned char *target, size_t len); std::string percentEncode(const std::string &target); -std::string percentDecode(std::string::const_iterator first, - std::string::const_iterator last); +template +std::string percentDecode(InputIt first, InputIt last) { + std::string result; + for (; first != last; ++first) { + if (*first == '%') { + if (first + 1 != last && first + 2 != last && isHexDigit(*(first + 1)) && + isHexDigit(*(first + 2))) { + result += (hex_to_uint(*(first + 1)) << 4) + hex_to_uint(*(first + 2)); + first += 2; + continue; + } + result += *first; + continue; + } + result += *first; + } + return result; +} // Percent encode |target| if character is not in token or '%'. std::string percent_encode_token(const std::string &target);