diff options
author | xunjieli <xunjieli@chromium.org> | 2016-03-21 20:39:51 -0700 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2016-03-22 03:42:17 +0000 |
commit | b3a648e3abbf08d0b08ba9cf1b273ef0e960b748 (patch) | |
tree | 1a886f5642fd0cd3d2846eb2d30d4730f7755f62 /net | |
parent | ed6ca6fe46c2f728192b5492ce67362181a47280 (diff) | |
download | chromium_src-b3a648e3abbf08d0b08ba9cf1b273ef0e960b748.zip chromium_src-b3a648e3abbf08d0b08ba9cf1b273ef0e960b748.tar.gz chromium_src-b3a648e3abbf08d0b08ba9cf1b273ef0e960b748.tar.bz2 |
Process Alternative Service headers in net::BidirectionalStream
This CL adds processing of alternative service headers to
net::BidirectionalStream, so that protocols advertised in
alternative service headers can be discovered.
BUG=584338
Review URL: https://codereview.chromium.org/1817583002
Cr-Commit-Position: refs/heads/master@{#382501}
Diffstat (limited to 'net')
-rw-r--r-- | net/http/bidirectional_stream.cc | 13 | ||||
-rw-r--r-- | net/http/bidirectional_stream.h | 2 | ||||
-rw-r--r-- | net/http/bidirectional_stream_unittest.cc | 68 | ||||
-rw-r--r-- | net/http/http_network_transaction.cc | 42 | ||||
-rw-r--r-- | net/http/http_stream_factory.cc | 70 | ||||
-rw-r--r-- | net/http/http_stream_factory.h | 27 | ||||
-rw-r--r-- | net/spdy/spdy_test_util_common.cc | 3 | ||||
-rw-r--r-- | net/spdy/spdy_test_util_common.h | 1 |
8 files changed, 159 insertions, 67 deletions
diff --git a/net/http/bidirectional_stream.cc b/net/http/bidirectional_stream.cc index cacb084..d9b04e0 100644 --- a/net/http/bidirectional_stream.cc +++ b/net/http/bidirectional_stream.cc @@ -15,7 +15,9 @@ #include "net/base/net_errors.h" #include "net/http/bidirectional_stream_request_info.h" #include "net/http/http_network_session.h" +#include "net/http/http_response_headers.h" #include "net/http/http_stream.h" +#include "net/spdy/spdy_http_utils.h" #include "net/ssl/ssl_cert_request_info.h" #include "net/ssl/ssl_config.h" #include "url/gurl.h" @@ -43,6 +45,7 @@ BidirectionalStream::BidirectionalStream( : request_info_(std::move(request_info)), net_log_(BoundNetLog::Make(session->net_log(), NetLog::SOURCE_BIDIRECTIONAL_STREAM)), + session_(session), delegate_(delegate), timer_(std::move(timer)) { DCHECK(delegate_); @@ -129,6 +132,16 @@ void BidirectionalStream::OnHeadersSent() { void BidirectionalStream::OnHeadersReceived( const SpdyHeaderBlock& response_headers) { + HttpResponseInfo response_info; + if (!SpdyHeadersToHttpResponse(response_headers, HTTP2, &response_info)) { + DLOG(WARNING) << "Invalid headers"; + delegate_->OnFailed(ERR_FAILED); + return; + } + + session_->http_stream_factory()->ProcessAlternativeServices( + session_, response_info.headers.get(), + HostPortPair::FromURL(request_info_->url)); delegate_->OnHeadersReceived(response_headers); } diff --git a/net/http/bidirectional_stream.h b/net/http/bidirectional_stream.h index 0cb3a15..78aeeaf 100644 --- a/net/http/bidirectional_stream.h +++ b/net/http/bidirectional_stream.h @@ -187,6 +187,8 @@ class NET_EXPORT BidirectionalStream scoped_ptr<BidirectionalStreamRequestInfo> request_info_; const BoundNetLog net_log_; + HttpNetworkSession* session_; + Delegate* const delegate_; // Timer used to buffer data received in short time-spans and send a single diff --git a/net/http/bidirectional_stream_unittest.cc b/net/http/bidirectional_stream_unittest.cc index a3bc810..6d4cb81 100644 --- a/net/http/bidirectional_stream_unittest.cc +++ b/net/http/bidirectional_stream_unittest.cc @@ -16,6 +16,7 @@ #include "net/http/bidirectional_stream_request_info.h" #include "net/http/http_network_session.h" #include "net/http/http_response_headers.h" +#include "net/http/http_server_properties.h" #include "net/log/net_log.h" #include "net/socket/socket_test_util.h" #include "net/spdy/spdy_session.h" @@ -1195,4 +1196,71 @@ TEST_P(BidirectionalStreamTest, CancelOrDeleteStreamDuringOnFailed) { EXPECT_EQ(kProtoUnknown, delegate->GetProtocol()); } +TEST_F(BidirectionalStreamTest, TestHonorAlternativeServiceHeader) { + scoped_ptr<SpdyFrame> req( + spdy_util_.ConstructSpdyGet("https://www.example.org", 1, LOWEST)); + // Empty DATA frame with an END_STREAM flag. + scoped_ptr<SpdyFrame> end_stream( + spdy_util_.ConstructSpdyBodyFrame(1, nullptr, 0, true)); + + MockWrite writes[] = {CreateMockWrite(*req.get(), 0)}; + + std::string alt_svc_header_value = AlternateProtocolToString(QUIC); + alt_svc_header_value.append("=\"www.example.org:443\""); + const char* const kExtraResponseHeaders[] = {"alt-svc", + alt_svc_header_value.c_str()}; + + scoped_ptr<SpdyFrame> resp( + spdy_util_.ConstructSpdyGetSynReply(kExtraResponseHeaders, 1, 1)); + scoped_ptr<SpdyFrame> body_frame(spdy_util_.ConstructSpdyBodyFrame(1, true)); + + MockRead reads[] = { + CreateMockRead(*resp, 1), CreateMockRead(*body_frame, 2), + MockRead(SYNCHRONOUS, 0, 3), + }; + + HostPortPair host_port_pair("www.example.org", 443); + SpdySessionKey key(host_port_pair, ProxyServer::Direct(), + PRIVACY_MODE_DISABLED); + session_deps_.parse_alternative_services = true; + // Enable QUIC so that the alternative service header can be added to + // HttpServerProperties. + session_deps_.enable_quic = true; + InitSession(reads, arraysize(reads), writes, arraysize(writes), key); + + scoped_ptr<BidirectionalStreamRequestInfo> request_info( + new BidirectionalStreamRequestInfo); + request_info->method = "GET"; + request_info->url = GURL("https://www.example.org/"); + request_info->priority = LOWEST; + request_info->end_stream_on_headers = true; + + scoped_refptr<IOBuffer> read_buffer(new IOBuffer(kReadBufferSize)); + MockTimer* timer = new MockTimer(); + scoped_ptr<TestDelegateBase> delegate(new TestDelegateBase( + read_buffer.get(), kReadBufferSize, make_scoped_ptr(timer))); + delegate->SetRunUntilCompletion(true); + delegate->Start(std::move(request_info), http_session_.get()); + + const SpdyHeaderBlock response_headers = delegate->response_headers(); + EXPECT_EQ("200", response_headers.find(":status")->second); + EXPECT_EQ(alt_svc_header_value, response_headers.find("alt-svc")->second); + EXPECT_EQ(0, delegate->on_data_sent_count()); + EXPECT_EQ(kProtoHTTP2, delegate->GetProtocol()); + EXPECT_EQ(kUploadData, delegate->data_received()); + EXPECT_EQ(CountWriteBytes(writes, arraysize(writes)), + delegate->GetTotalSentBytes()); + EXPECT_EQ(CountReadBytes(reads, arraysize(reads)), + delegate->GetTotalReceivedBytes()); + + AlternativeServiceVector alternative_service_vector = + http_session_->http_server_properties()->GetAlternativeServices( + host_port_pair); + ASSERT_EQ(1u, alternative_service_vector.size()); + EXPECT_EQ(AlternateProtocolFromNextProto(kProtoQUIC1SPDY3), + alternative_service_vector[0].protocol); + EXPECT_EQ("www.example.org", alternative_service_vector[0].host); + EXPECT_EQ(443, alternative_service_vector[0].port); +} + } // namespace net diff --git a/net/http/http_network_transaction.cc b/net/http/http_network_transaction.cc index 14da6c7..41c1acf 100644 --- a/net/http/http_network_transaction.cc +++ b/net/http/http_network_transaction.cc @@ -71,44 +71,6 @@ namespace net { namespace { -void ProcessAlternativeServices(HttpNetworkSession* session, - const HttpResponseHeaders& headers, - const HostPortPair& http_host_port_pair) { - if (session->params().parse_alternative_services) { - if (headers.HasHeader(kAlternativeServiceHeader)) { - std::string alternative_service_str; - headers.GetNormalizedHeader(kAlternativeServiceHeader, - &alternative_service_str); - session->http_stream_factory()->ProcessAlternativeService( - session->http_server_properties(), alternative_service_str, - http_host_port_pair, *session); - } - // If "Alt-Svc" is enabled, then ignore "Alternate-Protocol". - return; - } - - if (!headers.HasHeader(kAlternateProtocolHeader)) - return; - - std::vector<std::string> alternate_protocol_values; - size_t iter = 0; - std::string alternate_protocol_str; - while (headers.EnumerateHeader(&iter, kAlternateProtocolHeader, - &alternate_protocol_str)) { - base::TrimWhitespaceASCII(alternate_protocol_str, base::TRIM_ALL, - &alternate_protocol_str); - if (!alternate_protocol_str.empty()) { - alternate_protocol_values.push_back(alternate_protocol_str); - } - } - - session->http_stream_factory()->ProcessAlternateProtocol( - session->http_server_properties(), - alternate_protocol_values, - http_host_port_pair, - *session); -} - scoped_ptr<base::Value> NetLogSSLVersionFallbackCallback( const GURL* url, int net_error, @@ -1238,8 +1200,8 @@ int HttpNetworkTransaction::DoReadHeadersComplete(int result) { return OK; } - ProcessAlternativeServices(session_, *response_.headers.get(), - HostPortPair::FromURL(request_->url)); + session_->http_stream_factory()->ProcessAlternativeServices( + session_, response_.headers.get(), HostPortPair::FromURL(request_->url)); int rv = HandleAuthChallenge(); if (rv != OK) diff --git a/net/http/http_stream_factory.cc b/net/http/http_stream_factory.cc index f61a317..6ea3224 100644 --- a/net/http/http_stream_factory.cc +++ b/net/http/http_stream_factory.cc @@ -13,6 +13,7 @@ #include "net/base/host_port_pair.h" #include "net/base/port_util.h" #include "net/http/http_network_session.h" +#include "net/http/http_response_headers.h" #include "net/quic/quic_protocol.h" #include "net/spdy/spdy_alt_svc_wire_format.h" #include "url/gurl.h" @@ -32,6 +33,59 @@ void HttpStreamFactory::ResetStaticSettingsToInit() { spdy_enabled_ = true; } +void HttpStreamFactory::ProcessAlternativeServices( + HttpNetworkSession* session, + const HttpResponseHeaders* headers, + const HostPortPair& http_host_port_pair) { + if (session->params().parse_alternative_services) { + if (headers->HasHeader(kAlternativeServiceHeader)) { + std::string alternative_service_str; + headers->GetNormalizedHeader(kAlternativeServiceHeader, + &alternative_service_str); + ProcessAlternativeService(session->http_server_properties(), + alternative_service_str, http_host_port_pair, + *session); + } + // If "Alt-Svc" is enabled, then ignore "Alternate-Protocol". + return; + } + + if (!headers->HasHeader(kAlternateProtocolHeader)) + return; + + std::vector<std::string> alternate_protocol_values; + size_t iter = 0; + std::string alternate_protocol_str; + while (headers->EnumerateHeader(&iter, kAlternateProtocolHeader, + &alternate_protocol_str)) { + base::TrimWhitespaceASCII(alternate_protocol_str, base::TRIM_ALL, + &alternate_protocol_str); + if (!alternate_protocol_str.empty()) { + alternate_protocol_values.push_back(alternate_protocol_str); + } + } + + ProcessAlternateProtocol(session->http_server_properties(), + alternate_protocol_values, http_host_port_pair, + *session); +} + +GURL HttpStreamFactory::ApplyHostMappingRules(const GURL& url, + HostPortPair* endpoint) { + const HostMappingRules* mapping_rules = GetHostMappingRules(); + if (mapping_rules && mapping_rules->RewriteHost(endpoint)) { + url::Replacements<char> replacements; + const std::string port_str = base::UintToString(endpoint->port()); + replacements.SetPort(port_str.c_str(), url::Component(0, port_str.size())); + replacements.SetHost(endpoint->host().c_str(), + url::Component(0, endpoint->host().size())); + return url.ReplaceComponents(replacements); + } + return url; +} + +HttpStreamFactory::HttpStreamFactory() {} + void HttpStreamFactory::ProcessAlternativeService( const base::WeakPtr<HttpServerProperties>& http_server_properties, base::StringPiece alternative_service_str, @@ -146,22 +200,6 @@ void HttpStreamFactory::ProcessAlternateProtocol( base::Time::Now() + base::TimeDelta::FromDays(30)); } -GURL HttpStreamFactory::ApplyHostMappingRules(const GURL& url, - HostPortPair* endpoint) { - const HostMappingRules* mapping_rules = GetHostMappingRules(); - if (mapping_rules && mapping_rules->RewriteHost(endpoint)) { - url::Replacements<char> replacements; - const std::string port_str = base::UintToString(endpoint->port()); - replacements.SetPort(port_str.c_str(), url::Component(0, port_str.size())); - replacements.SetHost(endpoint->host().c_str(), - url::Component(0, endpoint->host().size())); - return url.ReplaceComponents(replacements); - } - return url; -} - -HttpStreamFactory::HttpStreamFactory() {} - HostPortPair HttpStreamFactory::RewriteHost(HostPortPair host_port_pair) { const HostMappingRules* mapping_rules = GetHostMappingRules(); if (mapping_rules) diff --git a/net/http/http_stream_factory.h b/net/http/http_stream_factory.h index f47ada1..e207a86 100644 --- a/net/http/http_stream_factory.h +++ b/net/http/http_stream_factory.h @@ -38,6 +38,7 @@ class HostMappingRules; class HostPortPair; class HttpAuthController; class HttpNetworkSession; +class HttpResponseHeaders; class HttpResponseInfo; class HttpServerProperties; class HttpStream; @@ -200,17 +201,9 @@ class NET_EXPORT HttpStreamFactory { public: virtual ~HttpStreamFactory(); - void ProcessAlternativeService( - const base::WeakPtr<HttpServerProperties>& http_server_properties, - base::StringPiece alternative_service_str, - const HostPortPair& http_host_port_pair, - const HttpNetworkSession& session); - - void ProcessAlternateProtocol( - const base::WeakPtr<HttpServerProperties>& http_server_properties, - const std::vector<std::string>& alternate_protocol_values, - const HostPortPair& http_host_port_pair, - const HttpNetworkSession& session); + void ProcessAlternativeServices(HttpNetworkSession* session, + const HttpResponseHeaders* headers, + const HostPortPair& http_host_port_pair); GURL ApplyHostMappingRules(const GURL& url, HostPortPair* endpoint); @@ -274,6 +267,18 @@ class NET_EXPORT HttpStreamFactory { HttpStreamFactory(); private: + void ProcessAlternativeService( + const base::WeakPtr<HttpServerProperties>& http_server_properties, + base::StringPiece alternative_service_str, + const HostPortPair& http_host_port_pair, + const HttpNetworkSession& session); + + void ProcessAlternateProtocol( + const base::WeakPtr<HttpServerProperties>& http_server_properties, + const std::vector<std::string>& alternate_protocol_values, + const HostPortPair& http_host_port_pair, + const HttpNetworkSession& session); + static bool spdy_enabled_; HostPortPair RewriteHost(HostPortPair host_port_pair); diff --git a/net/spdy/spdy_test_util_common.cc b/net/spdy/spdy_test_util_common.cc index 2a37dab..250819e 100644 --- a/net/spdy/spdy_test_util_common.cc +++ b/net/spdy/spdy_test_util_common.cc @@ -342,6 +342,7 @@ SpdySessionDependencies::SpdySessionDependencies(NextProto protocol) enable_user_alternate_protocol_ports(false), enable_npn(true), enable_priority_dependencies(true), + enable_quic(false), protocol(protocol), session_max_recv_window_size( SpdySession::GetDefaultInitialWindowSize(protocol)), @@ -379,6 +380,7 @@ SpdySessionDependencies::SpdySessionDependencies( enable_user_alternate_protocol_ports(false), enable_npn(true), enable_priority_dependencies(true), + enable_quic(false), protocol(protocol), session_max_recv_window_size( SpdySession::GetDefaultInitialWindowSize(protocol)), @@ -428,6 +430,7 @@ HttpNetworkSession::Params SpdySessionDependencies::CreateSessionParams( params.enable_npn = session_deps->enable_npn; params.enable_priority_dependencies = session_deps->enable_priority_dependencies; + params.enable_quic = session_deps->enable_quic; params.spdy_default_protocol = session_deps->protocol; params.spdy_session_max_recv_window_size = session_deps->session_max_recv_window_size; diff --git a/net/spdy/spdy_test_util_common.h b/net/spdy/spdy_test_util_common.h index 64992a6..f7b4800 100644 --- a/net/spdy/spdy_test_util_common.h +++ b/net/spdy/spdy_test_util_common.h @@ -198,6 +198,7 @@ struct SpdySessionDependencies { bool enable_user_alternate_protocol_ports; bool enable_npn; bool enable_priority_dependencies; + bool enable_quic; NextProto protocol; size_t session_max_recv_window_size; size_t stream_max_recv_window_size; |