diff --git a/Release/src/http/client/http_client.cpp b/Release/src/http/client/http_client.cpp index 62701737cc..2963fae3c2 100644 --- a/Release/src/http/client/http_client.cpp +++ b/Release/src/http/client/http_client.cpp @@ -123,15 +123,19 @@ bool request_context::handle_content_encoding_compression() return true; } -void request_context::add_accept_encoding_header(utility::string_t& headers) const +utility::string_t request_context::get_accept_encoding_header() const { + utility::string_t headers; // Add the header needed to request a compressed response if supported on this platform and it has been specified in the config - if (web::http::details::compression::stream_decompressor::is_supported() && m_http_client->client_config().request_compressed_response()) + if (web::http::details::compression::stream_decompressor::is_supported() + && m_http_client->client_config().request_compressed_response()) { headers.append(U("Accept-Encoding: ")); headers.append(web::http::details::compression::stream_decompressor::known_algorithms()); headers.append(U("\r\n")); } + + return headers; } concurrency::streams::streambuf request_context::_get_readbuffer() diff --git a/Release/src/http/client/http_client_asio.cpp b/Release/src/http/client/http_client_asio.cpp index f9b9ac1f73..3a79963a0c 100644 --- a/Release/src/http/client/http_client_asio.cpp +++ b/Release/src/http/client/http_client_asio.cpp @@ -460,14 +460,14 @@ class asio_context : public request_context, public std::enable_shared_from_this ctx->m_timer.set_ctx(std::weak_ptr(ctx)); return ctx; } - + class ssl_proxy_tunnel : public std::enable_shared_from_this { public: ssl_proxy_tunnel(std::shared_ptr context, std::function)> ssl_tunnel_established) : m_ssl_tunnel_established(ssl_tunnel_established), m_context(context) {} - + void start_proxy_connect() { auto proxy = m_context->m_http_client->client_config().proxy(); @@ -502,7 +502,7 @@ class asio_context : public request_context, public std::enable_shared_from_this client->m_resolver.async_resolve(query, boost::bind(&ssl_proxy_tunnel::handle_resolve, shared_from_this(), boost::asio::placeholders::error, boost::asio::placeholders::iterator)); } - private: + private: void handle_resolve(const boost::system::error_code& ec, tcp::resolver::iterator endpoints) { if (ec) @@ -553,7 +553,7 @@ class asio_context : public request_context, public std::enable_shared_from_this m_context->report_error("Failed to send connect request to proxy.", err, httpclient_errorcode_context::writebody); } } - + void handle_status_line(const boost::system::error_code& ec) { if (!ec) @@ -565,13 +565,13 @@ class asio_context : public request_context, public std::enable_shared_from_this response_stream >> http_version; status_code status_code; response_stream >> status_code; - + if (!response_stream || http_version.substr(0, 5) != "HTTP/") { m_context->report_error("Invalid HTTP status line during proxy connection", ec, httpclient_errorcode_context::readheader); return; } - + if (status_code != 200) { m_context->report_error("Expected a 200 response from proxy, received: " + to_string(status_code), ec, httpclient_errorcode_context::readheader); @@ -593,14 +593,14 @@ class asio_context : public request_context, public std::enable_shared_from_this // Failed to write to socket because connection was already closed while it was in the pool. // close() here ensures socket is closed in a robust way and prevents the connection from being put to the pool again. m_context->m_connection->close(); - + // Create a new context and copy the request object, completion event and // cancellation registration to maintain the old state. // This also obtains a new connection from pool. auto new_ctx = m_context->create_request_context(m_context->m_http_client, m_context->m_request); new_ctx->m_request_completion = m_context->m_request_completion; new_ctx->m_cancellationRegistration = m_context->m_cancellationRegistration; - + auto client = std::static_pointer_cast(m_context->m_http_client); // Resend the request using the new context. client->send_request(new_ctx); @@ -611,15 +611,15 @@ class asio_context : public request_context, public std::enable_shared_from_this } } } - + std::function)> m_ssl_tunnel_established; std::shared_ptr m_context; - + boost::asio::streambuf m_request; boost::asio::streambuf m_response; }; - - + + enum class http_proxy_type { none, @@ -634,11 +634,11 @@ class asio_context : public request_context, public std::enable_shared_from_this request_context::report_error(make_error_code(std::errc::operation_canceled).value(), "Request canceled by user."); return; } - + http_proxy_type proxy_type = http_proxy_type::none; std::string proxy_host; int proxy_port = -1; - + // There is no support for auto-detection of proxies on non-windows platforms, it must be specified explicitly from the client code. if (m_http_client->client_config().proxy().is_specified()) { @@ -648,7 +648,7 @@ class asio_context : public request_context, public std::enable_shared_from_this proxy_port = proxy_uri.port() == -1 ? 8080 : proxy_uri.port(); proxy_host = utility::conversions::to_utf8string(proxy_uri.host()); } - + auto start_http_request_flow = [proxy_type, proxy_host, proxy_port AND_CAPTURE_MEMBER_FUNCTION_POINTERS](std::shared_ptr ctx) { if (ctx->m_request._cancellation_token().is_canceled()) @@ -656,20 +656,20 @@ class asio_context : public request_context, public std::enable_shared_from_this ctx->request_context::report_error(make_error_code(std::errc::operation_canceled).value(), "Request canceled by user."); return; } - + const auto &base_uri = ctx->m_http_client->base_uri(); const auto full_uri = uri_builder(base_uri).append(ctx->m_request.relative_uri()).to_uri(); - + // For a normal http proxy, we need to specify the full request uri, otherwise just specify the resource auto encoded_resource = proxy_type == http_proxy_type::http ? full_uri.to_string() : full_uri.resource().to_string(); - + if (encoded_resource.empty()) { encoded_resource = U("/"); } - + const auto &method = ctx->m_request.method(); - + // stop injection of headers via method // resource should be ok, since it's been encoded // and host won't resolve @@ -678,20 +678,20 @@ class asio_context : public request_context, public std::enable_shared_from_this ctx->report_exception(http_exception("The method string is invalid.")); return; } - + std::ostream request_stream(&ctx->m_body_buf); request_stream.imbue(std::locale::classic()); const auto &host = utility::conversions::to_utf8string(base_uri.host()); - + request_stream << utility::conversions::to_utf8string(method) << " " << utility::conversions::to_utf8string(encoded_resource) << " " << "HTTP/1.1" << CRLF; - + int port = base_uri.port(); - + if (base_uri.is_port_default()) { port = (ctx->m_connection->is_ssl() ? 443 : 80); } - + // Add the Host header if user has not specified it explicitly if (!ctx->m_request.headers().has(header_names::host)) { @@ -701,10 +701,10 @@ class asio_context : public request_context, public std::enable_shared_from_this } request_stream << CRLF; } - + // Extra request headers are constructed here. std::string extra_headers; - + // Add header for basic proxy authentication if (proxy_type == http_proxy_type::http && ctx->m_http_client->client_config().proxy().credentials().is_set()) { @@ -716,7 +716,7 @@ class asio_context : public request_context, public std::enable_shared_from_this extra_headers.append(ctx->generate_basic_auth_header()); } - ctx->add_accept_encoding_header(extra_headers); + extra_headers += utility::conversions::to_utf8string(ctx->get_accept_encoding_header()); // Check user specified transfer-encoding. std::string transferencoding; @@ -740,25 +740,25 @@ class asio_context : public request_context, public std::enable_shared_from_this extra_headers.append("Content-Length: 0\r\n"); } } - + if (proxy_type == http_proxy_type::http) { extra_headers.append( "Cache-Control: no-store, no-cache\r\n" "Pragma: no-cache\r\n"); } - + request_stream << utility::conversions::to_utf8string(::web::http::details::flatten_http_headers(ctx->m_request.headers())); request_stream << extra_headers; // Enforce HTTP connection keep alive (even for the old HTTP/1.0 protocol). request_stream << "Connection: Keep-Alive" << CRLF << CRLF; - + // Start connection timeout timer. if (!ctx->m_timer.has_started()) { ctx->m_timer.start(); } - + if (ctx->m_connection->is_reused() || proxy_type == http_proxy_type::ssl_tunnel) { // If socket is a reused connection or we're connected via an ssl-tunneling proxy, try to write the request directly. In both cases we have already established a tcp connection. @@ -768,16 +768,16 @@ class asio_context : public request_context, public std::enable_shared_from_this { // If the connection is new (unresolved and unconnected socket), then start async // call to resolve first, leading eventually to request write. - + // For normal http proxies, we want to connect directly to the proxy server. It will relay our request. auto tcp_host = proxy_type == http_proxy_type::http ? proxy_host : host; auto tcp_port = proxy_type == http_proxy_type::http ? proxy_port : port; - + tcp::resolver::query query(tcp_host, to_string(tcp_port)); auto client = std::static_pointer_cast(ctx->m_http_client); client->m_resolver.async_resolve(query, boost::bind(&asio_context::handle_resolve, ctx, boost::asio::placeholders::error, boost::asio::placeholders::iterator)); } - + // Register for notification on cancellation to abort this request. if (ctx->m_request._cancellation_token() != pplx::cancellation_token::none()) { @@ -794,7 +794,7 @@ class asio_context : public request_context, public std::enable_shared_from_this }); } }; - + if (proxy_type == http_proxy_type::ssl_tunnel) { // The ssl_tunnel_proxy keeps the context alive and then calls back once the ssl tunnel is established via 'start_http_request_flow' @@ -1073,7 +1073,7 @@ class asio_context : public request_context, public std::enable_shared_from_this // Reuse error handling. return handle_write_body(ec); } - + m_timer.reset(); const auto &progress = m_request._get_impl()->_progress_handler(); if (progress) @@ -1154,7 +1154,7 @@ class asio_context : public request_context, public std::enable_shared_from_this response_stream >> http_version; status_code status_code; response_stream >> status_code; - + std::string status_message; std::getline(response_stream, status_message); @@ -1418,7 +1418,7 @@ class asio_context : public request_context, public std::enable_shared_from_this } this_request->m_body_buf.consume(to_read + CRLF.size()); // consume crlf this_request->m_connection->async_read_until(this_request->m_body_buf, CRLF, boost::bind(&asio_context::handle_chunk_header, this_request, boost::asio::placeholders::error)); - }); + }); } } } @@ -1471,7 +1471,7 @@ class asio_context : public request_context, public std::enable_shared_from_this if(m_decompressor) { auto decompressed = m_decompressor->decompress(boost::asio::buffer_cast(m_body_buf.data()), read_size); - + if (m_decompressor->has_error()) { this_request->report_exception(std::runtime_error("Failed to decompress the response body")); @@ -1646,7 +1646,7 @@ class asio_context : public request_context, public std::enable_shared_from_this timeout_timer m_timer; boost::asio::streambuf m_body_buf; std::shared_ptr m_connection; - + #if defined(__APPLE__) || (defined(ANDROID) || defined(__ANDROID__)) bool m_openssl_failed; #endif @@ -1668,7 +1668,7 @@ void asio_client::send_request(const std::shared_ptr &request_c { client_config().invoke_nativehandle_options(ctx->m_connection->m_ssl_stream.get()); } - else + else { client_config().invoke_nativehandle_options(&(ctx->m_connection->m_socket)); } diff --git a/Release/src/http/client/http_client_impl.h b/Release/src/http/client/http_client_impl.h index e4508ebcf1..7b6c974a0d 100644 --- a/Release/src/http/client/http_client_impl.h +++ b/Release/src/http/client/http_client_impl.h @@ -75,7 +75,7 @@ class request_context bool handle_content_encoding_compression(); /// Append an Accept-Encoding header if requested by the http_client settings - void add_accept_encoding_header(utility::string_t& headers) const; + utility::string_t get_accept_encoding_header() const; concurrency::streams::streambuf _get_writebuffer(); diff --git a/Release/src/http/client/http_client_winhttp.cpp b/Release/src/http/client/http_client_winhttp.cpp index c81dd6b317..f92f252bd9 100644 --- a/Release/src/http/client/http_client_winhttp.cpp +++ b/Release/src/http/client/http_client_winhttp.cpp @@ -759,8 +759,7 @@ class winhttp_client : public _http_client_communicator } utility::string_t flattened_headers = web::http::details::flatten_http_headers(msg.headers()); - - winhttp_context->add_accept_encoding_header(flattened_headers); + flattened_headers += winhttp_context->get_accept_encoding_header(); // Add headers. if(!flattened_headers.empty())