| Index: net/spdy/spdy_network_transaction_unittest.cc
|
| diff --git a/net/spdy/spdy_network_transaction_unittest.cc b/net/spdy/spdy_network_transaction_unittest.cc
|
| index 4c6c2059e80e8d4787d31beba34c9e29c117f87a..21401b5e1f7c276fbc5b89b198427accc3edb21b 100644
|
| --- a/net/spdy/spdy_network_transaction_unittest.cc
|
| +++ b/net/spdy/spdy_network_transaction_unittest.cc
|
| @@ -263,6 +263,12 @@ class SpdyNetworkTransactionTest
|
| output_.rv = ReadTransaction(trans_.get(), &output_.response_data);
|
| }
|
|
|
| + void FinishDefaultTestWithoutVerification() {
|
| + output_.rv = callback_.WaitForResult();
|
| + if (output_.rv != OK)
|
| + session_->spdy_session_pool()->CloseCurrentSessions(net::ERR_ABORTED);
|
| + }
|
| +
|
| // Most tests will want to call this function. In particular, the MockReads
|
| // should end with an empty read, and that read needs to be processed to
|
| // ensure proper deletion of the spdy_session_pool.
|
| @@ -4550,6 +4556,208 @@ TEST_P(SpdyNetworkTransactionTest, CloseWithActiveStream) {
|
| helper.VerifyDataConsumed();
|
| }
|
|
|
| +// Retry with HTTP/1.1 when receiving HTTP_1_1_REQUIRED. Note that no actual
|
| +// protocol negotiation happens, instead this test forces protocols for both
|
| +// sockets.
|
| +TEST_P(SpdyNetworkTransactionTest, HTTP11RequiredRetry) {
|
| + // HTTP_1_1_REQUIRED is only supported by SPDY4.
|
| + if (spdy_util_.spdy_version() < SPDY4)
|
| + return;
|
| + // HTTP_1_1_REQUIRED implementation relies on the assumption that HTTP/2 is
|
| + // only spoken over SSL.
|
| + if (GetParam().ssl_type != SPDYSSL)
|
| + return;
|
| +
|
| + HttpRequestInfo request;
|
| + request.method = "GET";
|
| + request.url = GURL("https://www.google.com/");
|
| + scoped_ptr<SpdySessionDependencies> session_deps(
|
| + CreateSpdySessionDependencies(GetParam()));
|
| + // Do not force SPDY so that second socket can negotiate HTTP/1.1.
|
| + session_deps->force_spdy_over_ssl = false;
|
| + session_deps->force_spdy_always = false;
|
| + session_deps->next_protos = SpdyNextProtos();
|
| + NormalSpdyTransactionHelper helper(request, DEFAULT_PRIORITY, BoundNetLog(),
|
| + GetParam(), session_deps.release());
|
| +
|
| + // First socket: HTTP/2 request rejected with HTTP_1_1_REQUIRED.
|
| + const char* url = "https://www.google.com/";
|
| + scoped_ptr<SpdyHeaderBlock> headers(spdy_util_.ConstructGetHeaderBlock(url));
|
| + scoped_ptr<SpdyFrame> req(
|
| + spdy_util_.ConstructSpdySyn(1, *headers, LOWEST, false, true));
|
| + MockWrite writes0[] = {CreateMockWrite(*req)};
|
| + scoped_ptr<SpdyFrame> go_away(spdy_util_.ConstructSpdyGoAway(
|
| + 0, GOAWAY_HTTP_1_1_REQUIRED, "Try again using HTTP/1.1 please."));
|
| + MockRead reads0[] = {CreateMockRead(*go_away)};
|
| + DelayedSocketData data0(1, reads0, arraysize(reads0), writes0,
|
| + arraysize(writes0));
|
| +
|
| + scoped_ptr<SSLSocketDataProvider> ssl_provider0(
|
| + new SSLSocketDataProvider(ASYNC, OK));
|
| + // Expect HTTP/2 protocols too in SSLConfig.
|
| + ssl_provider0->next_protos_expected_in_ssl_config.push_back(kProtoHTTP11);
|
| + ssl_provider0->next_protos_expected_in_ssl_config.push_back(kProtoSPDY31);
|
| + ssl_provider0->next_protos_expected_in_ssl_config.push_back(kProtoSPDY4_14);
|
| + ssl_provider0->next_protos_expected_in_ssl_config.push_back(kProtoSPDY4_15);
|
| + // Force SPDY.
|
| + ssl_provider0->SetNextProto(GetParam().protocol);
|
| + helper.AddDataWithSSLSocketDataProvider(&data0, ssl_provider0.Pass());
|
| +
|
| + // Second socket: falling back to HTTP/1.1.
|
| + MockWrite writes1[] = {MockWrite(
|
| + "GET / HTTP/1.1\r\n"
|
| + "Host: www.google.com\r\n"
|
| + "Connection: keep-alive\r\n\r\n")};
|
| + MockRead reads1[] = {MockRead(
|
| + "HTTP/1.1 200 OK\r\n"
|
| + "Content-Length: 5\r\n\r\n"
|
| + "hello")};
|
| + DelayedSocketData data1(1, reads1, arraysize(reads1), writes1,
|
| + arraysize(writes1));
|
| +
|
| + scoped_ptr<SSLSocketDataProvider> ssl_provider1(
|
| + new SSLSocketDataProvider(ASYNC, OK));
|
| + // Expect only HTTP/1.1 protocol in SSLConfig.
|
| + ssl_provider1->next_protos_expected_in_ssl_config.push_back(kProtoHTTP11);
|
| + // Force HTTP/1.1.
|
| + ssl_provider1->SetNextProto(kProtoHTTP11);
|
| + helper.AddDataWithSSLSocketDataProvider(&data1, ssl_provider1.Pass());
|
| +
|
| + base::WeakPtr<HttpServerProperties> http_server_properties =
|
| + helper.session()->spdy_session_pool()->http_server_properties();
|
| + const HostPortPair host_port_pair = HostPortPair::FromURL(GURL(url));
|
| + EXPECT_FALSE(http_server_properties->RequiresHTTP11(host_port_pair));
|
| +
|
| + helper.RunPreTestSetup();
|
| + helper.StartDefaultTest();
|
| + helper.FinishDefaultTestWithoutVerification();
|
| + helper.VerifyDataConsumed();
|
| + EXPECT_TRUE(http_server_properties->RequiresHTTP11(host_port_pair));
|
| +
|
| + const HttpResponseInfo* response = helper.trans()->GetResponseInfo();
|
| + ASSERT_TRUE(response != nullptr);
|
| + ASSERT_TRUE(response->headers.get() != nullptr);
|
| + EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine());
|
| + EXPECT_FALSE(response->was_fetched_via_spdy);
|
| + EXPECT_EQ(HttpResponseInfo::CONNECTION_INFO_HTTP1, response->connection_info);
|
| + EXPECT_TRUE(response->was_npn_negotiated);
|
| + EXPECT_TRUE(request.url.SchemeIs("https"));
|
| + EXPECT_EQ("127.0.0.1", response->socket_address.host());
|
| + EXPECT_EQ(443, response->socket_address.port());
|
| + std::string response_data;
|
| + ASSERT_EQ(OK, ReadTransaction(helper.trans(), &response_data));
|
| + EXPECT_EQ("hello", response_data);
|
| +}
|
| +
|
| +// Retry with HTTP/1.1 to the proxy when receiving HTTP_1_1_REQUIRED from the
|
| +// proxy. Note that no actual protocol negotiation happens, instead this test
|
| +// forces protocols for both sockets.
|
| +TEST_P(SpdyNetworkTransactionTest, HTTP11RequiredProxyRetry) {
|
| + // HTTP_1_1_REQUIRED is only supported by SPDY4.
|
| + if (spdy_util_.spdy_version() < SPDY4)
|
| + return;
|
| + // HTTP_1_1_REQUIRED implementation relies on the assumption that HTTP/2 is
|
| + // only spoken over SSL.
|
| + if (GetParam().ssl_type != SPDYSSL)
|
| + return;
|
| +
|
| + HttpRequestInfo request;
|
| + request.method = "GET";
|
| + request.url = GURL("https://www.google.com/");
|
| + scoped_ptr<SpdySessionDependencies> session_deps(
|
| + CreateSpdySessionDependencies(
|
| + GetParam(),
|
| + ProxyService::CreateFixedFromPacResult("HTTPS myproxy:70")));
|
| + // Do not force SPDY so that second socket can negotiate HTTP/1.1.
|
| + session_deps->force_spdy_over_ssl = false;
|
| + session_deps->force_spdy_always = false;
|
| + session_deps->next_protos = SpdyNextProtos();
|
| + NormalSpdyTransactionHelper helper(request, DEFAULT_PRIORITY, BoundNetLog(),
|
| + GetParam(), session_deps.release());
|
| +
|
| + // First socket: HTTP/2 CONNECT rejected with HTTP_1_1_REQUIRED.
|
| + scoped_ptr<SpdyFrame> req(spdy_util_.ConstructSpdyConnect(
|
| + nullptr, 0, 1, LOWEST, HostPortPair("www.google.com", 443)));
|
| + MockWrite writes0[] = {CreateMockWrite(*req)};
|
| + scoped_ptr<SpdyFrame> go_away(spdy_util_.ConstructSpdyGoAway(
|
| + 0, GOAWAY_HTTP_1_1_REQUIRED, "Try again using HTTP/1.1 please."));
|
| + MockRead reads0[] = {CreateMockRead(*go_away)};
|
| + DelayedSocketData data0(1, reads0, arraysize(reads0), writes0,
|
| + arraysize(writes0));
|
| +
|
| + scoped_ptr<SSLSocketDataProvider> ssl_provider0(
|
| + new SSLSocketDataProvider(ASYNC, OK));
|
| + // Expect HTTP/2 protocols too in SSLConfig.
|
| + ssl_provider0->next_protos_expected_in_ssl_config.push_back(kProtoHTTP11);
|
| + ssl_provider0->next_protos_expected_in_ssl_config.push_back(kProtoSPDY31);
|
| + ssl_provider0->next_protos_expected_in_ssl_config.push_back(kProtoSPDY4_14);
|
| + ssl_provider0->next_protos_expected_in_ssl_config.push_back(kProtoSPDY4_15);
|
| + // Force SPDY.
|
| + ssl_provider0->SetNextProto(GetParam().protocol);
|
| + helper.AddDataWithSSLSocketDataProvider(&data0, ssl_provider0.Pass());
|
| +
|
| + // Second socket: retry using HTTP/1.1.
|
| + MockWrite writes1[] = {
|
| + MockWrite(ASYNC, 1,
|
| + "CONNECT www.google.com:443 HTTP/1.1\r\n"
|
| + "Host: www.google.com\r\n"
|
| + "Proxy-Connection: keep-alive\r\n\r\n"),
|
| + MockWrite(ASYNC, 3,
|
| + "GET / HTTP/1.1\r\n"
|
| + "Host: www.google.com\r\n"
|
| + "Connection: keep-alive\r\n\r\n"),
|
| + };
|
| +
|
| + MockRead reads1[] = {
|
| + MockRead(ASYNC, 2, "HTTP/1.1 200 OK\r\n\r\n"),
|
| + MockRead(ASYNC, 4,
|
| + "HTTP/1.1 200 OK\r\n"
|
| + "Content-Length: 5\r\n\r\n"
|
| + "hello"),
|
| + };
|
| + DelayedSocketData data1(1, reads1, arraysize(reads1), writes1,
|
| + arraysize(writes1));
|
| +
|
| + scoped_ptr<SSLSocketDataProvider> ssl_provider1(
|
| + new SSLSocketDataProvider(ASYNC, OK));
|
| + // Expect only HTTP/1.1 protocol in SSLConfig.
|
| + ssl_provider1->next_protos_expected_in_ssl_config.push_back(kProtoHTTP11);
|
| + // Force HTTP/1.1.
|
| + ssl_provider1->SetNextProto(kProtoHTTP11);
|
| + helper.AddDataWithSSLSocketDataProvider(&data1, ssl_provider1.Pass());
|
| +
|
| + // A third socket is needed for the tunnelled connection.
|
| + scoped_ptr<SSLSocketDataProvider> ssl_provider2(
|
| + new SSLSocketDataProvider(ASYNC, OK));
|
| + helper.session_deps()->socket_factory->AddSSLSocketDataProvider(
|
| + ssl_provider2.get());
|
| +
|
| + base::WeakPtr<HttpServerProperties> http_server_properties =
|
| + helper.session()->spdy_session_pool()->http_server_properties();
|
| + const HostPortPair proxy_host_port_pair = HostPortPair("myproxy", 70);
|
| + EXPECT_FALSE(http_server_properties->RequiresHTTP11(proxy_host_port_pair));
|
| +
|
| + helper.RunPreTestSetup();
|
| + helper.StartDefaultTest();
|
| + helper.FinishDefaultTestWithoutVerification();
|
| + helper.VerifyDataConsumed();
|
| + EXPECT_TRUE(http_server_properties->RequiresHTTP11(proxy_host_port_pair));
|
| +
|
| + const HttpResponseInfo* response = helper.trans()->GetResponseInfo();
|
| + ASSERT_TRUE(response != nullptr);
|
| + ASSERT_TRUE(response->headers.get() != nullptr);
|
| + EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine());
|
| + EXPECT_FALSE(response->was_fetched_via_spdy);
|
| + EXPECT_EQ(HttpResponseInfo::CONNECTION_INFO_HTTP1, response->connection_info);
|
| + EXPECT_FALSE(response->was_npn_negotiated);
|
| + EXPECT_TRUE(request.url.SchemeIs("https"));
|
| + EXPECT_EQ("127.0.0.1", response->socket_address.host());
|
| + EXPECT_EQ(70, response->socket_address.port());
|
| + std::string response_data;
|
| + ASSERT_EQ(OK, ReadTransaction(helper.trans(), &response_data));
|
| + EXPECT_EQ("hello", response_data);
|
| +}
|
| +
|
| // Test to make sure we can correctly connect through a proxy.
|
| TEST_P(SpdyNetworkTransactionTest, ProxyConnect) {
|
| NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY,
|
|
|