| Index: net/spdy/spdy_session_unittest.cc
|
| diff --git a/net/spdy/spdy_session_unittest.cc b/net/spdy/spdy_session_unittest.cc
|
| index e6dd43974fd7ac7c25d49582dc6e4e1c3cdb3664..b8472d759a31481a3b5ee33cf95bfd96ca1905a4 100644
|
| --- a/net/spdy/spdy_session_unittest.cc
|
| +++ b/net/spdy/spdy_session_unittest.cc
|
| @@ -78,6 +78,28 @@ class MockRequireCTDelegate : public TransportSecurityState::RequireCTDelegate {
|
| CTRequirementLevel(const std::string& host));
|
| };
|
|
|
| +class TestServerPushDelegate : public ServerPushDelegate {
|
| + public:
|
| + explicit TestServerPushDelegate() {}
|
| +
|
| + void OnPush(std::unique_ptr<ServerPushHelper> push_helper) override {
|
| + push_helpers[push_helper->GetURL()] = std::move(push_helper);
|
| + }
|
| +
|
| + bool CancelPush(GURL url) {
|
| + auto itr = push_helpers.find(url);
|
| + if (itr == push_helpers.end())
|
| + return false;
|
| +
|
| + itr->second->Cancel();
|
| + push_helpers.erase(itr);
|
| + return true;
|
| + }
|
| +
|
| + private:
|
| + std::map<GURL, std::unique_ptr<ServerPushHelper>> push_helpers;
|
| +};
|
| +
|
| } // namespace
|
|
|
| class SpdySessionTest : public PlatformTest {
|
| @@ -208,6 +230,7 @@ class SpdySessionTest : public PlatformTest {
|
| SpdySessionDependencies session_deps_;
|
| std::unique_ptr<HttpNetworkSession> http_session_;
|
| base::WeakPtr<SpdySession> session_;
|
| + TestServerPushDelegate test_push_delegate_;
|
| SpdySessionPool* spdy_session_pool_;
|
| const GURL test_url_;
|
| const url::SchemeHostPort test_server_;
|
| @@ -1277,6 +1300,92 @@ TEST_F(SpdySessionTest, UnstallRacesWithStreamCreation) {
|
| EXPECT_THAT(callback2.WaitForResult(), IsOk());
|
| }
|
|
|
| +TEST_F(SpdySessionTest, CancelPushAfterSessionGoesAway) {
|
| + base::HistogramTester histogram_tester;
|
| + session_deps_.host_resolver->set_synchronous_mode(true);
|
| + session_deps_.time_func = TheNearFuture;
|
| +
|
| + SpdySerializedFrame req(
|
| + spdy_util_.ConstructSpdyGet(nullptr, 0, 1, MEDIUM, true));
|
| + SpdySerializedFrame rst(
|
| + spdy_util_.ConstructSpdyRstStream(2, RST_STREAM_REFUSED_STREAM));
|
| + MockWrite writes[] = {CreateMockWrite(req, 0), CreateMockWrite(rst, 5)};
|
| +
|
| + SpdySerializedFrame push_a(spdy_util_.ConstructSpdyPush(
|
| + nullptr, 0, 2, 1, "https://www.example.org/a.dat"));
|
| + SpdySerializedFrame push_a_body(spdy_util_.ConstructSpdyDataFrame(2, false));
|
| + // In ascii "0" < "a". We use it to verify that we properly handle std::map
|
| + // iterators inside. See http://crbug.com/443490
|
| + SpdySerializedFrame push_b(spdy_util_.ConstructSpdyPush(
|
| + nullptr, 0, 4, 1, "https://www.example.org/0.dat"));
|
| + MockRead reads[] = {
|
| + CreateMockRead(push_a, 1), CreateMockRead(push_a_body, 2),
|
| + MockRead(ASYNC, ERR_IO_PENDING, 3), CreateMockRead(push_b, 4),
|
| + MockRead(ASYNC, ERR_IO_PENDING, 6), MockRead(ASYNC, 0, 7) // EOF
|
| + };
|
| +
|
| + SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
|
| + session_deps_.socket_factory->AddSocketDataProvider(&data);
|
| +
|
| + AddSSLSocketData();
|
| +
|
| + CreateNetworkSession();
|
| + CreateSecureSpdySession();
|
| + session_->set_push_delegate(&test_push_delegate_);
|
| +
|
| + // Process the principal request, and the first push stream request & body.
|
| + base::WeakPtr<SpdyStream> spdy_stream =
|
| + CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM, session_,
|
| + test_url_, MEDIUM, NetLogWithSource());
|
| + test::StreamDelegateDoNothing delegate(spdy_stream);
|
| + spdy_stream->SetDelegate(&delegate);
|
| +
|
| + SpdyHeaderBlock headers(spdy_util_.ConstructGetHeaderBlock(kDefaultUrl));
|
| + spdy_stream->SendRequestHeaders(std::move(headers), NO_MORE_DATA_TO_SEND);
|
| +
|
| + base::RunLoop().RunUntilIdle();
|
| +
|
| + // Verify that there is one unclaimed push stream.
|
| + EXPECT_EQ(1u, session_->num_unclaimed_pushed_streams());
|
| + EXPECT_EQ(1u, session_->count_unclaimed_pushed_streams_for_url(
|
| + GURL("https://www.example.org/a.dat")));
|
| +
|
| + // Unclaimed push body consumed bytes from the session window.
|
| + EXPECT_EQ(kDefaultInitialWindowSize - kUploadDataSize,
|
| + session_->session_recv_window_size_);
|
| + EXPECT_EQ(0, session_->session_unacked_recv_window_bytes_);
|
| +
|
| + // Shift time to expire the push stream. Read the second HEADERS,
|
| + // and verify a RST_STREAM was written.
|
| + g_time_delta = base::TimeDelta::FromSeconds(301);
|
| + data.Resume();
|
| + base::RunLoop().RunUntilIdle();
|
| +
|
| + // Verify that the second pushed stream evicted the first pushed stream.
|
| + EXPECT_EQ(1u, session_->num_unclaimed_pushed_streams());
|
| + EXPECT_EQ(1u, session_->count_unclaimed_pushed_streams_for_url(
|
| + GURL("https://www.example.org/0.dat")));
|
| +
|
| + // Verify that the session window reclaimed the evicted stream body.
|
| + EXPECT_EQ(kDefaultInitialWindowSize, session_->session_recv_window_size_);
|
| + EXPECT_EQ(kUploadDataSize, session_->session_unacked_recv_window_bytes_);
|
| + EXPECT_TRUE(session_);
|
| +
|
| + // Read and process EOF.
|
| + data.Resume();
|
| + base::RunLoop().RunUntilIdle();
|
| +
|
| + // Cancel the first push after session goes away. Verify the test doesn't
|
| + // crash.
|
| + EXPECT_FALSE(session_);
|
| + EXPECT_TRUE(
|
| + test_push_delegate_.CancelPush(GURL("https://www.example.org/a.dat")));
|
| +
|
| + histogram_tester.ExpectBucketCount("Net.SpdySession.PushedBytes", 6, 1);
|
| + histogram_tester.ExpectBucketCount("Net.SpdySession.PushedAndUnclaimedBytes",
|
| + 6, 1);
|
| +}
|
| +
|
| TEST_F(SpdySessionTest, CancelPushAfterExpired) {
|
| base::HistogramTester histogram_tester;
|
| session_deps_.host_resolver->set_synchronous_mode(true);
|
| @@ -1308,6 +1417,7 @@ TEST_F(SpdySessionTest, CancelPushAfterExpired) {
|
|
|
| CreateNetworkSession();
|
| CreateSecureSpdySession();
|
| + session_->set_push_delegate(&test_push_delegate_);
|
|
|
| // Process the principal request, and the first push stream request & body.
|
| base::WeakPtr<SpdyStream> spdy_stream =
|
| @@ -1343,7 +1453,8 @@ TEST_F(SpdySessionTest, CancelPushAfterExpired) {
|
| GURL("https://www.example.org/0.dat")));
|
|
|
| // Cancel the first push after its expiration.
|
| - session_->CancelPush(GURL("https://www.example.org/a.dat"));
|
| + EXPECT_TRUE(
|
| + test_push_delegate_.CancelPush(GURL("https://www.example.org/a.dat")));
|
| EXPECT_EQ(1u, session_->num_unclaimed_pushed_streams());
|
| EXPECT_TRUE(session_);
|
|
|
| @@ -1356,6 +1467,7 @@ TEST_F(SpdySessionTest, CancelPushAfterExpired) {
|
| data.Resume();
|
| base::RunLoop().RunUntilIdle();
|
| EXPECT_FALSE(session_);
|
| +
|
| histogram_tester.ExpectBucketCount("Net.SpdySession.PushedBytes", 6, 1);
|
| histogram_tester.ExpectBucketCount("Net.SpdySession.PushedAndUnclaimedBytes",
|
| 6, 1);
|
| @@ -1392,6 +1504,7 @@ TEST_F(SpdySessionTest, CancelPushBeforeClaimed) {
|
|
|
| CreateNetworkSession();
|
| CreateSecureSpdySession();
|
| + session_->set_push_delegate(&test_push_delegate_);
|
|
|
| // Process the principal request, and the first push stream request & body.
|
| base::WeakPtr<SpdyStream> spdy_stream =
|
| @@ -1432,7 +1545,7 @@ TEST_F(SpdySessionTest, CancelPushBeforeClaimed) {
|
|
|
| EXPECT_TRUE(session_);
|
| // Cancel the push before it's claimed.
|
| - session_->CancelPush(pushed_url);
|
| + EXPECT_TRUE(test_push_delegate_.CancelPush(pushed_url));
|
| EXPECT_EQ(0u, session_->num_unclaimed_pushed_streams());
|
| EXPECT_EQ(0u, session_->count_unclaimed_pushed_streams_for_url(pushed_url));
|
|
|
|
|