| Index: net/http/http_network_transaction_unittest.cc
|
| diff --git a/net/http/http_network_transaction_unittest.cc b/net/http/http_network_transaction_unittest.cc
|
| index 5bf07a4e36264f82b931edb5119bc7d07c9c013a..88e3d276338de528faf996bc56001372d0456cda 100644
|
| --- a/net/http/http_network_transaction_unittest.cc
|
| +++ b/net/http/http_network_transaction_unittest.cc
|
| @@ -12018,6 +12018,113 @@ TEST_P(HttpNetworkTransactionTest, AlternativeServiceNotOnHttp11) {
|
| EXPECT_EQ(ERR_NPN_NEGOTIATION_FAILED, callback.GetResult(rv));
|
| }
|
|
|
| +// A request to a server with an alternative service fires two Jobs: one to the
|
| +// origin, and an alternate one to the alternative server. If the former
|
| +// succeeds, the request should succeed, even if the latter fails because
|
| +// HTTP/1.1 is negotiated which is insufficient for alternative service.
|
| +TEST_P(HttpNetworkTransactionTest, FailedAlternativeServiceIsNotUserVisible) {
|
| + HostPortPair origin("origin.example.org", 443);
|
| + HostPortPair alternative("alternative.example.org", 443);
|
| +
|
| + // Negotiate HTTP/1.1 with alternative.
|
| + SSLSocketDataProvider alternative_ssl(ASYNC, OK);
|
| + alternative_ssl.SetNextProto(kProtoHTTP11);
|
| + session_deps_.socket_factory->AddSSLSocketDataProvider(&alternative_ssl);
|
| +
|
| + // No data should be read from the alternative, because HTTP/1.1 is
|
| + // negotiated.
|
| + StaticSocketDataProvider data;
|
| + session_deps_.socket_factory->AddSocketDataProvider(&data);
|
| +
|
| + // Negotiate HTTP/1.1 with origin.
|
| + SSLSocketDataProvider origin_ssl(ASYNC, OK);
|
| + origin_ssl.SetNextProto(kProtoHTTP11);
|
| + session_deps_.socket_factory->AddSSLSocketDataProvider(&origin_ssl);
|
| +
|
| + MockWrite http_writes[] = {
|
| + MockWrite(
|
| + "GET / HTTP/1.1\r\n"
|
| + "Host: origin.example.org\r\n"
|
| + "Connection: keep-alive\r\n\r\n"),
|
| + MockWrite(
|
| + "GET /second HTTP/1.1\r\n"
|
| + "Host: origin.example.org\r\n"
|
| + "Connection: keep-alive\r\n\r\n"),
|
| + };
|
| +
|
| + MockRead http_reads[] = {
|
| + MockRead("HTTP/1.1 200 OK\r\n"),
|
| + MockRead("Content-Type: text/html\r\n"),
|
| + MockRead("Content-Length: 6\r\n\r\n"),
|
| + MockRead("foobar"),
|
| + MockRead("HTTP/1.1 200 OK\r\n"),
|
| + MockRead("Content-Type: text/html\r\n"),
|
| + MockRead("Content-Length: 7\r\n\r\n"),
|
| + MockRead("another"),
|
| + };
|
| + StaticSocketDataProvider http_data(http_reads, arraysize(http_reads),
|
| + http_writes, arraysize(http_writes));
|
| + session_deps_.socket_factory->AddSocketDataProvider(&http_data);
|
| +
|
| + // Set up alternative service for origin.
|
| + session_deps_.use_alternate_protocols = true;
|
| + scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps_));
|
| + base::WeakPtr<HttpServerProperties> http_server_properties =
|
| + session->http_server_properties();
|
| + AlternativeService alternative_service(
|
| + AlternateProtocolFromNextProto(GetParam()), alternative);
|
| + http_server_properties->SetAlternativeService(origin, alternative_service,
|
| + 1.0);
|
| +
|
| + HttpNetworkTransaction trans1(DEFAULT_PRIORITY, session.get());
|
| + HttpRequestInfo request1;
|
| + request1.method = "GET";
|
| + request1.url = GURL("https://origin.example.org:443");
|
| + request1.load_flags = 0;
|
| + TestCompletionCallback callback1;
|
| +
|
| + int rv = trans1.Start(&request1, callback1.callback(), BoundNetLog());
|
| + rv = callback1.GetResult(rv);
|
| + EXPECT_EQ(OK, rv);
|
| +
|
| + const HttpResponseInfo* response1 = trans1.GetResponseInfo();
|
| + ASSERT_TRUE(response1 != nullptr);
|
| + ASSERT_TRUE(response1->headers.get() != nullptr);
|
| + EXPECT_EQ("HTTP/1.1 200 OK", response1->headers->GetStatusLine());
|
| +
|
| + std::string response_data1;
|
| + ASSERT_EQ(OK, ReadTransaction(&trans1, &response_data1));
|
| + EXPECT_EQ("foobar", response_data1);
|
| +
|
| + // Alternative should be marked as broken, because HTTP/1.1 is not sufficient
|
| + // for alternative service.
|
| + EXPECT_TRUE(
|
| + http_server_properties->IsAlternativeServiceBroken(alternative_service));
|
| +
|
| + // Since |alternative_service| is broken, a second transaction to origin
|
| + // should not start an alternate Job. It should pool to existing connection
|
| + // to origin.
|
| + HttpNetworkTransaction trans2(DEFAULT_PRIORITY, session.get());
|
| + HttpRequestInfo request2;
|
| + request2.method = "GET";
|
| + request2.url = GURL("https://origin.example.org:443/second");
|
| + request2.load_flags = 0;
|
| + TestCompletionCallback callback2;
|
| +
|
| + rv = trans2.Start(&request2, callback2.callback(), BoundNetLog());
|
| + rv = callback2.GetResult(rv);
|
| + EXPECT_EQ(OK, rv);
|
| +
|
| + const HttpResponseInfo* response2 = trans2.GetResponseInfo();
|
| + ASSERT_TRUE(response2 != nullptr);
|
| + ASSERT_TRUE(response2->headers.get() != nullptr);
|
| + EXPECT_EQ("HTTP/1.1 200 OK", response2->headers->GetStatusLine());
|
| +
|
| + std::string response_data2;
|
| + ASSERT_EQ(OK, ReadTransaction(&trans2, &response_data2));
|
| + EXPECT_EQ("another", response_data2);
|
| +}
|
| +
|
| // Alternative service requires HTTP/2 (or SPDY), but there is already a
|
| // HTTP/1.1 socket open to the alternative server. That socket should not be
|
| // used.
|
|
|