 Chromium Code Reviews
 Chromium Code Reviews Issue 2933773002:
  When a stream is created for a QUIC session to a server which has been  (Closed)
    
  
    Issue 2933773002:
  When a stream is created for a QUIC session to a server which has been  (Closed) 
  | OLD | NEW | 
|---|---|
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be | 
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. | 
| 4 | 4 | 
| 5 #include <algorithm> | 5 #include <algorithm> | 
| 6 #include <memory> | 6 #include <memory> | 
| 7 #include <ostream> | 7 #include <ostream> | 
| 8 #include <string> | 8 #include <string> | 
| 9 #include <utility> | 9 #include <utility> | 
| 10 #include <vector> | 10 #include <vector> | 
| (...skipping 2558 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2569 ASSERT_TRUE(quic_data.AllWriteDataConsumed()); | 2569 ASSERT_TRUE(quic_data.AllWriteDataConsumed()); | 
| 2570 ASSERT_FALSE(http_data.AllReadDataConsumed()); | 2570 ASSERT_FALSE(http_data.AllReadDataConsumed()); | 
| 2571 | 2571 | 
| 2572 // Read the response body over TCP. | 2572 // Read the response body over TCP. | 
| 2573 CheckResponseData(&trans, "hello world"); | 2573 CheckResponseData(&trans, "hello world"); | 
| 2574 ExpectBrokenAlternateProtocolMapping(); | 2574 ExpectBrokenAlternateProtocolMapping(); | 
| 2575 ASSERT_TRUE(http_data.AllWriteDataConsumed()); | 2575 ASSERT_TRUE(http_data.AllWriteDataConsumed()); | 
| 2576 ASSERT_TRUE(http_data.AllReadDataConsumed()); | 2576 ASSERT_TRUE(http_data.AllReadDataConsumed()); | 
| 2577 } | 2577 } | 
| 2578 | 2578 | 
| 2579 // Verify that with retry_without_alt_svc_on_quic_errors enabled, if a QUIC | |
| 2580 // request is reset from, then QUIC will be marked as broken and the request | |
| 2581 // retried over TCP. | |
| 2582 TEST_P(QuicNetworkTransactionTest, | |
| 2583 ResetPooledAfterHandshakeConfirmedThenBroken) { | |
| 2584 session_params_.retry_without_alt_svc_on_quic_errors = true; | |
| 2585 | |
| 2586 GURL origin1 = request_.url; | |
| 2587 GURL origin2("https://www.example.org/"); | |
| 2588 ASSERT_NE(origin1.host(), origin2.host()); | |
| 2589 | |
| 2590 MockQuicData mock_quic_data; | |
| 2591 QuicStreamOffset request_header_offset(0); | |
| 2592 QuicStreamOffset response_header_offset(0); | |
| 2593 | |
| 2594 scoped_refptr<X509Certificate> cert( | |
| 2595 ImportCertFromFile(GetTestCertsDirectory(), "wildcard.pem")); | |
| 2596 ASSERT_TRUE(cert->VerifyNameMatch("www.example.org", false)); | |
| 2597 ASSERT_TRUE(cert->VerifyNameMatch("mail.example.org", false)); | |
| 2598 | |
| 2599 ProofVerifyDetailsChromium verify_details; | |
| 2600 verify_details.cert_verify_result.verified_cert = cert; | |
| 2601 verify_details.cert_verify_result.is_issued_by_known_root = true; | |
| 2602 crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details); | |
| 2603 | |
| 2604 mock_quic_data.AddWrite( | |
| 2605 ConstructInitialSettingsPacket(1, &request_header_offset)); | |
| 2606 // First request. | |
| 2607 mock_quic_data.AddWrite(ConstructClientRequestHeadersPacket( | |
| 2608 2, GetNthClientInitiatedStreamId(0), true, true, | |
| 2609 GetRequestHeaders("GET", "https", "/"), &request_header_offset)); | |
| 2610 mock_quic_data.AddRead(ConstructServerResponseHeadersPacket( | |
| 2611 1, GetNthClientInitiatedStreamId(0), false, false, | |
| 2612 GetResponseHeaders("200 OK"), &response_header_offset)); | |
| 2613 mock_quic_data.AddRead(ConstructServerDataPacket( | |
| 2614 2, GetNthClientInitiatedStreamId(0), false, true, 0, "hello!")); | |
| 2615 mock_quic_data.AddWrite(ConstructClientAckPacket(3, 2, 1, 1)); | |
| 2616 | |
| 2617 // Second request will go over the pooled QUIC connection, but will be | |
| 2618 // reset by the server. | |
| 2619 QuicTestPacketMaker client_maker2(version_, 0, &clock_, origin2.host(), | |
| 2620 Perspective::IS_CLIENT); | |
| 2621 QuicTestPacketMaker server_maker2(version_, 0, &clock_, origin2.host(), | |
| 2622 Perspective::IS_SERVER); | |
| 2623 mock_quic_data.AddWrite(ConstructClientRequestHeadersPacket( | |
| 2624 4, GetNthClientInitiatedStreamId(1), false, true, | |
| 2625 GetRequestHeaders("GET", "https", "/", &client_maker2), | |
| 2626 &request_header_offset)); | |
| 2627 mock_quic_data.AddRead(ConstructServerRstPacket( | |
| 2628 3, false, GetNthClientInitiatedStreamId(1), QUIC_HEADERS_TOO_LARGE)); | |
| 2629 mock_quic_data.AddRead(ASYNC, ERR_IO_PENDING); // No more data to read | |
| 2630 mock_quic_data.AddRead(ASYNC, 0); // EOF | |
| 2631 | |
| 2632 mock_quic_data.AddSocketDataToFactory(&socket_factory_); | |
| 2633 | |
| 2634 // After that fails, it will be resent via TCP. | |
| 2635 MockWrite http_writes[] = { | |
| 2636 MockWrite(SYNCHRONOUS, 0, "GET / HTTP/1.1\r\n"), | |
| 2637 MockWrite(SYNCHRONOUS, 1, "Host: www.example.org\r\n"), | |
| 2638 MockWrite(SYNCHRONOUS, 2, "Connection: keep-alive\r\n\r\n")}; | |
| 2639 | |
| 2640 MockRead http_reads[] = { | |
| 2641 MockRead(SYNCHRONOUS, 3, "HTTP/1.1 200 OK\r\n"), | |
| 2642 MockRead(SYNCHRONOUS, 4, kQuicAlternativeServiceHeader), | |
| 2643 MockRead(SYNCHRONOUS, 5, "hello world"), MockRead(SYNCHRONOUS, OK, 6)}; | |
| 2644 SequencedSocketData http_data(http_reads, arraysize(http_reads), http_writes, | |
| 2645 arraysize(http_writes)); | |
| 2646 socket_factory_.AddSocketDataProvider(&http_data); | |
| 2647 socket_factory_.AddSSLSocketDataProvider(&ssl_data_); | |
| 2648 | |
| 2649 // Then the next request to the second origin will go over a new QUIC | |
| 2650 // connection. | |
| 2651 MockQuicData mock_quic_data2; | |
| 2652 QuicTestPacketMaker client_maker3(version_, 0, &clock_, origin2.host(), | |
| 2653 Perspective::IS_CLIENT); | |
| 2654 QuicTestPacketMaker server_maker3(version_, 0, &clock_, origin2.host(), | |
| 2655 Perspective::IS_SERVER); | |
| 2656 QuicStreamOffset request_header_offset2(0); | |
| 2657 QuicStreamOffset response_header_offset2(0); | |
| 2658 | |
| 2659 crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details); | |
| 2660 | |
| 2661 mock_quic_data2.AddWrite( | |
| 2662 client_maker3.MakeInitialSettingsPacket(1, &request_header_offset2)); | |
| 2663 mock_quic_data2.AddWrite( | |
| 2664 client_maker3.MakeRequestHeadersPacketWithOffsetTracking( | |
| 2665 2, GetNthClientInitiatedStreamId(0), true, true, | |
| 2666 ConvertRequestPriorityToQuicPriority(DEFAULT_PRIORITY), | |
| 2667 GetRequestHeaders("GET", "https", "/", &client_maker3), | |
| 2668 &request_header_offset2)); | |
| 2669 mock_quic_data2.AddRead( | |
| 2670 server_maker2.MakeResponseHeadersPacketWithOffsetTracking( | |
| 2671 1, GetNthClientInitiatedStreamId(0), false, false, | |
| 2672 GetResponseHeaders("200 OK"), &response_header_offset2)); | |
| 2673 mock_quic_data2.AddRead(server_maker2.MakeDataPacket( | |
| 2674 2, GetNthClientInitiatedStreamId(0), false, true, 0, "hello!")); | |
| 2675 mock_quic_data2.AddWrite(ConstructClientAckPacket(3, 2, 1, 1)); | |
| 2676 mock_quic_data2.AddRead(ASYNC, ERR_IO_PENDING); // No more data to read | |
| 2677 mock_quic_data2.AddRead(ASYNC, 0); // EOF | |
| 2678 | |
| 2679 mock_quic_data2.AddSocketDataToFactory(&socket_factory_); | |
| 2680 | |
| 2681 CreateSession(); | |
| 2682 | |
| 2683 // Set up alternative service for |origin1|. | |
| 2684 AlternativeService alternative_service1(kProtoQUIC, "mail.example.com", 443); | |
| 2685 base::Time expiration = base::Time::Now() + base::TimeDelta::FromDays(1); | |
| 2686 http_server_properties_.SetAlternativeService( | |
| 2687 url::SchemeHostPort(origin1), alternative_service1, expiration); | |
| 2688 | |
| 2689 // Set up multiple alternative service entries for |origin2|, | |
| 2690 // the first one with a different destination as for |origin1|, | |
| 2691 // the second one with the same. The second one should be used, | |
| 2692 // because the request can be pooled to that one. | |
| 
Zhongyi Shi
2017/06/12 19:27:47
Reading the comments, I was expecting there are tw
 
Ryan Hamilton
2017/06/12 19:43:08
Yup. Out of date. Fixed.
 | |
| 2693 AlternativeService alternative_service2(kProtoQUIC, "www.example.com", 443); | |
| 2694 AlternativeServiceInfoVector alternative_services; | |
| 2695 alternative_services.push_back( | |
| 2696 AlternativeServiceInfo(alternative_service2, expiration)); | |
| 2697 http_server_properties_.SetAlternativeServices(url::SchemeHostPort(origin2), | |
| 2698 alternative_services); | |
| 2699 // First request opens connection to |destination1| | |
| 2700 // with QuicServerId.host() == origin1.host(). | |
| 2701 SendRequestAndExpectQuicResponse("hello!"); | |
| 2702 | |
| 2703 // Second request pools to existing connection with same destination, | |
| 2704 // because certificate matches, even though QuicServerId is different. | |
| 2705 // After it is reset, it will fail back to QUIC and mark QUIC as broken. | |
| 2706 request_.url = origin2; | |
| 2707 SendRequestAndExpectHttpResponse("hello world"); | |
| 2708 | |
| 2709 // The third request should use a new QUIC connection, not the broken | |
| 2710 // QUIC connection. | |
| 2711 SendRequestAndExpectQuicResponse("hello!"); | |
| 2712 } | |
| 2713 | |
| 2714 // Verify that with retry_without_alt_svc_on_quic_errors enabled, if a QUIC | |
| 2715 // request is reset from, then QUIC will be marked as broken and the request | |
| 2716 // retried over TCP. | |
| 
Zhongyi Shi
2017/06/12 19:27:47
nit: the description of the two tests are identica
 
Ryan Hamilton
2017/06/12 19:43:08
Whoops, sorry about that. I wrote this first and t
 | |
| 2717 TEST_P(QuicNetworkTransactionTest, ResetAfterHandshakeConfirmedThenBroken) { | |
| 2718 session_params_.retry_without_alt_svc_on_quic_errors = true; | |
| 2719 | |
| 2720 // The request will initially go out over QUIC. | |
| 2721 MockQuicData quic_data; | |
| 2722 QuicStreamOffset header_stream_offset = 0; | |
| 2723 SpdyPriority priority = | |
| 2724 ConvertRequestPriorityToQuicPriority(DEFAULT_PRIORITY); | |
| 2725 | |
| 2726 std::string request_data; | |
| 2727 quic_data.AddWrite(client_maker_.MakeRequestHeadersPacketAndSaveData( | |
| 2728 1, GetNthClientInitiatedStreamId(0), true, true, priority, | |
| 2729 GetRequestHeaders("GET", "https", "/"), nullptr, &header_stream_offset, | |
| 2730 &request_data)); | |
| 2731 | |
| 2732 std::string settings_data; | |
| 2733 // QuicStreamOffset settings_offset = header_stream_offset; | |
| 2734 quic_data.AddWrite(client_maker_.MakeInitialSettingsPacketAndSaveData( | |
| 2735 2, &header_stream_offset, &settings_data)); | |
| 2736 | |
| 2737 quic_data.AddRead(ConstructServerRstPacket( | |
| 2738 1, false, GetNthClientInitiatedStreamId(0), QUIC_HEADERS_TOO_LARGE)); | |
| 2739 | |
| 2740 quic_data.AddRead(ASYNC, OK); | |
| 2741 quic_data.AddSocketDataToFactory(&socket_factory_); | |
| 2742 | |
| 2743 // After that fails, it will be resent via TCP. | |
| 2744 MockWrite http_writes[] = { | |
| 2745 MockWrite(SYNCHRONOUS, 0, "GET / HTTP/1.1\r\n"), | |
| 2746 MockWrite(SYNCHRONOUS, 1, "Host: mail.example.org\r\n"), | |
| 2747 MockWrite(SYNCHRONOUS, 2, "Connection: keep-alive\r\n\r\n")}; | |
| 2748 | |
| 2749 MockRead http_reads[] = { | |
| 2750 MockRead(SYNCHRONOUS, 3, "HTTP/1.1 200 OK\r\n"), | |
| 2751 MockRead(SYNCHRONOUS, 4, kQuicAlternativeServiceHeader), | |
| 2752 MockRead(SYNCHRONOUS, 5, "hello world"), MockRead(SYNCHRONOUS, OK, 6)}; | |
| 2753 SequencedSocketData http_data(http_reads, arraysize(http_reads), http_writes, | |
| 2754 arraysize(http_writes)); | |
| 2755 socket_factory_.AddSocketDataProvider(&http_data); | |
| 2756 socket_factory_.AddSSLSocketDataProvider(&ssl_data_); | |
| 2757 | |
| 2758 // In order for a new QUIC session to be established via alternate-protocol | |
| 2759 // without racing an HTTP connection, we need the host resolution to happen | |
| 2760 // synchronously. Of course, even though QUIC *could* perform a 0-RTT | |
| 2761 // connection to the the server, in this test we require confirmation | |
| 2762 // before encrypting so the HTTP job will still start. | |
| 2763 host_resolver_.set_synchronous_mode(true); | |
| 2764 host_resolver_.rules()->AddIPLiteralRule("mail.example.org", "192.168.0.1", | |
| 2765 ""); | |
| 2766 HostResolver::RequestInfo info(HostPortPair("mail.example.org", 443)); | |
| 2767 AddressList address; | |
| 2768 std::unique_ptr<HostResolver::Request> request; | |
| 2769 host_resolver_.Resolve(info, DEFAULT_PRIORITY, &address, CompletionCallback(), | |
| 2770 &request, net_log_.bound()); | |
| 2771 | |
| 2772 CreateSession(); | |
| 2773 | |
| 2774 AddQuicAlternateProtocolMapping(MockCryptoClientStream::ZERO_RTT); | |
| 2775 | |
| 2776 HttpNetworkTransaction trans(DEFAULT_PRIORITY, session_.get()); | |
| 2777 TestCompletionCallback callback; | |
| 2778 int rv = trans.Start(&request_, callback.callback(), net_log_.bound()); | |
| 2779 EXPECT_THAT(rv, IsError(ERR_IO_PENDING)); | |
| 2780 | |
| 2781 // Pump the message loop to get the request started. | |
| 2782 base::RunLoop().RunUntilIdle(); | |
| 2783 // Explicitly confirm the handshake. | |
| 2784 crypto_client_stream_factory_.last_stream()->SendOnCryptoHandshakeEvent( | |
| 2785 QuicSession::HANDSHAKE_CONFIRMED); | |
| 2786 | |
| 2787 // Run the QUIC session to completion. | |
| 2788 ASSERT_TRUE(quic_data.AllWriteDataConsumed()); | |
| 2789 | |
| 2790 ExpectQuicAlternateProtocolMapping(); | |
| 2791 | |
| 2792 // Let the transaction proceed which will result in QUIC being marked | |
| 2793 // as broken and the request falling back to TCP. | |
| 2794 EXPECT_THAT(callback.WaitForResult(), IsOk()); | |
| 2795 | |
| 2796 ASSERT_TRUE(quic_data.AllWriteDataConsumed()); | |
| 2797 ASSERT_FALSE(http_data.AllReadDataConsumed()); | |
| 2798 | |
| 2799 // Read the response body over TCP. | |
| 2800 CheckResponseData(&trans, "hello world"); | |
| 2801 ExpectBrokenAlternateProtocolMapping(); | |
| 2802 ASSERT_TRUE(http_data.AllWriteDataConsumed()); | |
| 2803 ASSERT_TRUE(http_data.AllReadDataConsumed()); | |
| 2804 } | |
| 2805 | |
| 2579 TEST_P(QuicNetworkTransactionTest, | 2806 TEST_P(QuicNetworkTransactionTest, | 
| 2580 DoNotUseAlternativeServiceQuicUnsupportedVersion) { | 2807 DoNotUseAlternativeServiceQuicUnsupportedVersion) { | 
| 2581 std::string altsvc_header = base::StringPrintf( | 2808 std::string altsvc_header = base::StringPrintf( | 
| 2582 "Alt-Svc: quic=\":443\"; v=\"%u\"\r\n\r\n", version_ - 1); | 2809 "Alt-Svc: quic=\":443\"; v=\"%u\"\r\n\r\n", version_ - 1); | 
| 2583 MockRead http_reads[] = { | 2810 MockRead http_reads[] = { | 
| 2584 MockRead("HTTP/1.1 200 OK\r\n"), MockRead(altsvc_header.c_str()), | 2811 MockRead("HTTP/1.1 200 OK\r\n"), MockRead(altsvc_header.c_str()), | 
| 2585 MockRead("hello world"), | 2812 MockRead("hello world"), | 
| 2586 MockRead(SYNCHRONOUS, ERR_TEST_PEER_CLOSE_AFTER_NEXT_MOCK_READ), | 2813 MockRead(SYNCHRONOUS, ERR_TEST_PEER_CLOSE_AFTER_NEXT_MOCK_READ), | 
| 2587 MockRead(ASYNC, OK)}; | 2814 MockRead(ASYNC, OK)}; | 
| 2588 | 2815 | 
| (...skipping 2213 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 4802 | 5029 | 
| 4803 request_.url = GURL("https://mail.example.org/pushed.jpg"); | 5030 request_.url = GURL("https://mail.example.org/pushed.jpg"); | 
| 4804 ChunkedUploadDataStream upload_data(0); | 5031 ChunkedUploadDataStream upload_data(0); | 
| 4805 upload_data.AppendData("1", 1, true); | 5032 upload_data.AppendData("1", 1, true); | 
| 4806 request_.upload_data_stream = &upload_data; | 5033 request_.upload_data_stream = &upload_data; | 
| 4807 SendRequestAndExpectQuicResponse("and hello!"); | 5034 SendRequestAndExpectQuicResponse("and hello!"); | 
| 4808 } | 5035 } | 
| 4809 | 5036 | 
| 4810 } // namespace test | 5037 } // namespace test | 
| 4811 } // namespace net | 5038 } // namespace net | 
| OLD | NEW |