Index: net/spdy/spdy_http_stream_unittest.cc |
diff --git a/net/spdy/spdy_http_stream_unittest.cc b/net/spdy/spdy_http_stream_unittest.cc |
deleted file mode 100644 |
index 04b5088be5ee08a0e6b2236e3901093dd68e6f88..0000000000000000000000000000000000000000 |
--- a/net/spdy/spdy_http_stream_unittest.cc |
+++ /dev/null |
@@ -1,793 +0,0 @@ |
-// Copyright (c) 2012 The Chromium Authors. All rights reserved. |
-// Use of this source code is governed by a BSD-style license that can be |
-// found in the LICENSE file. |
- |
-#include "net/spdy/spdy_http_stream.h" |
- |
-#include <vector> |
- |
-#include "base/memory/scoped_ptr.h" |
-#include "base/message_loop/message_loop_proxy.h" |
-#include "base/run_loop.h" |
-#include "base/stl_util.h" |
-#include "crypto/ec_private_key.h" |
-#include "crypto/ec_signature_creator.h" |
-#include "crypto/signature_creator.h" |
-#include "net/base/capturing_net_log.h" |
-#include "net/base/chunked_upload_data_stream.h" |
-#include "net/base/load_timing_info.h" |
-#include "net/base/load_timing_info_test_util.h" |
-#include "net/base/test_completion_callback.h" |
-#include "net/cert/asn1_util.h" |
-#include "net/http/http_request_info.h" |
-#include "net/http/http_response_headers.h" |
-#include "net/http/http_response_info.h" |
-#include "net/socket/next_proto.h" |
-#include "net/socket/socket_test_util.h" |
-#include "net/spdy/spdy_http_utils.h" |
-#include "net/spdy/spdy_session.h" |
-#include "net/spdy/spdy_test_util_common.h" |
-#include "net/ssl/default_channel_id_store.h" |
-#include "testing/gtest/include/gtest/gtest.h" |
- |
-namespace net { |
- |
-namespace { |
- |
-// Tests the load timing of a stream that's connected and is not the first |
-// request sent on a connection. |
-void TestLoadTimingReused(const HttpStream& stream) { |
- LoadTimingInfo load_timing_info; |
- EXPECT_TRUE(stream.GetLoadTimingInfo(&load_timing_info)); |
- |
- EXPECT_TRUE(load_timing_info.socket_reused); |
- EXPECT_NE(NetLog::Source::kInvalidId, load_timing_info.socket_log_id); |
- |
- ExpectConnectTimingHasNoTimes(load_timing_info.connect_timing); |
- ExpectLoadTimingHasOnlyConnectionTimes(load_timing_info); |
-} |
- |
-// Tests the load timing of a stream that's connected and using a fresh |
-// connection. |
-void TestLoadTimingNotReused(const HttpStream& stream) { |
- LoadTimingInfo load_timing_info; |
- EXPECT_TRUE(stream.GetLoadTimingInfo(&load_timing_info)); |
- |
- EXPECT_FALSE(load_timing_info.socket_reused); |
- EXPECT_NE(NetLog::Source::kInvalidId, load_timing_info.socket_log_id); |
- |
- ExpectConnectTimingHasTimes(load_timing_info.connect_timing, |
- CONNECT_TIMING_HAS_DNS_TIMES); |
- ExpectLoadTimingHasOnlyConnectionTimes(load_timing_info); |
-} |
- |
-} // namespace |
- |
-class SpdyHttpStreamTest : public testing::Test, |
- public testing::WithParamInterface<NextProto> { |
- public: |
- SpdyHttpStreamTest() |
- : spdy_util_(GetParam()), |
- session_deps_(GetParam()) { |
- session_deps_.net_log = &net_log_; |
- } |
- |
- DeterministicSocketData* deterministic_data() { |
- return deterministic_data_.get(); |
- } |
- |
- OrderedSocketData* data() { return data_.get(); } |
- |
- protected: |
- void TearDown() override { |
- crypto::ECSignatureCreator::SetFactoryForTesting(NULL); |
- base::MessageLoop::current()->RunUntilIdle(); |
- } |
- |
- // Initializes the session using DeterministicSocketData. It's advisable |
- // to use this function rather than the OrderedSocketData, since the |
- // DeterministicSocketData behaves in a reasonable manner. |
- void InitSessionDeterministic(MockRead* reads, size_t reads_count, |
- MockWrite* writes, size_t writes_count, |
- const SpdySessionKey& key) { |
- deterministic_data_.reset( |
- new DeterministicSocketData(reads, reads_count, writes, writes_count)); |
- session_deps_.deterministic_socket_factory->AddSocketDataProvider( |
- deterministic_data_.get()); |
- http_session_ = |
- SpdySessionDependencies::SpdyCreateSessionDeterministic(&session_deps_); |
- session_ = CreateInsecureSpdySession(http_session_, key, BoundNetLog()); |
- } |
- |
- // Initializes the session using the finicky OrderedSocketData class. |
- void InitSession(MockRead* reads, size_t reads_count, |
- MockWrite* writes, size_t writes_count, |
- const SpdySessionKey& key) { |
- data_.reset(new OrderedSocketData(reads, reads_count, |
- writes, writes_count)); |
- session_deps_.socket_factory->AddSocketDataProvider(data_.get()); |
- http_session_ = SpdySessionDependencies::SpdyCreateSession(&session_deps_); |
- session_ = CreateInsecureSpdySession(http_session_, key, BoundNetLog()); |
- } |
- |
- void TestSendCredentials( |
- ChannelIDService* channel_id_service, |
- const std::string& cert, |
- const std::string& proof); |
- |
- SpdyTestUtil spdy_util_; |
- CapturingNetLog net_log_; |
- SpdySessionDependencies session_deps_; |
- scoped_ptr<OrderedSocketData> data_; |
- scoped_ptr<DeterministicSocketData> deterministic_data_; |
- scoped_refptr<HttpNetworkSession> http_session_; |
- base::WeakPtr<SpdySession> session_; |
- |
- private: |
- MockECSignatureCreatorFactory ec_signature_creator_factory_; |
-}; |
- |
-INSTANTIATE_TEST_CASE_P( |
- NextProto, |
- SpdyHttpStreamTest, |
- testing::Values(kProtoSPDY31, kProtoSPDY4_14, kProtoSPDY4_15)); |
- |
-// SpdyHttpStream::GetUploadProgress() should still work even before the |
-// stream is initialized. |
-TEST_P(SpdyHttpStreamTest, GetUploadProgressBeforeInitialization) { |
- MockRead reads[] = { |
- MockRead(ASYNC, 0, 0) // EOF |
- }; |
- |
- HostPortPair host_port_pair("www.google.com", 80); |
- SpdySessionKey key(host_port_pair, ProxyServer::Direct(), |
- PRIVACY_MODE_DISABLED); |
- InitSession(reads, arraysize(reads), NULL, 0, key); |
- |
- SpdyHttpStream stream(session_, false); |
- UploadProgress progress = stream.GetUploadProgress(); |
- EXPECT_EQ(0u, progress.size()); |
- EXPECT_EQ(0u, progress.position()); |
- |
- // Pump the event loop so |reads| is consumed before the function returns. |
- base::RunLoop().RunUntilIdle(); |
-} |
- |
-TEST_P(SpdyHttpStreamTest, SendRequest) { |
- scoped_ptr<SpdyFrame> req( |
- spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true)); |
- MockWrite writes[] = { |
- CreateMockWrite(*req.get(), 1), |
- }; |
- scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1)); |
- MockRead reads[] = { |
- CreateMockRead(*resp, 2), |
- MockRead(SYNCHRONOUS, 0, 3) // EOF |
- }; |
- |
- HostPortPair host_port_pair("www.google.com", 80); |
- SpdySessionKey key(host_port_pair, ProxyServer::Direct(), |
- PRIVACY_MODE_DISABLED); |
- InitSession(reads, arraysize(reads), writes, arraysize(writes), key); |
- |
- HttpRequestInfo request; |
- request.method = "GET"; |
- request.url = GURL("http://www.google.com/"); |
- TestCompletionCallback callback; |
- HttpResponseInfo response; |
- HttpRequestHeaders headers; |
- BoundNetLog net_log; |
- scoped_ptr<SpdyHttpStream> http_stream(new SpdyHttpStream(session_, true)); |
- // Make sure getting load timing information the stream early does not crash. |
- LoadTimingInfo load_timing_info; |
- EXPECT_FALSE(http_stream->GetLoadTimingInfo(&load_timing_info)); |
- |
- ASSERT_EQ( |
- OK, |
- http_stream->InitializeStream(&request, DEFAULT_PRIORITY, |
- net_log, CompletionCallback())); |
- EXPECT_FALSE(http_stream->GetLoadTimingInfo(&load_timing_info)); |
- |
- EXPECT_EQ(ERR_IO_PENDING, http_stream->SendRequest(headers, &response, |
- callback.callback())); |
- EXPECT_TRUE(HasSpdySession(http_session_->spdy_session_pool(), key)); |
- EXPECT_FALSE(http_stream->GetLoadTimingInfo(&load_timing_info)); |
- |
- // This triggers the MockWrite and read 2 |
- callback.WaitForResult(); |
- |
- // Can get timing information once the stream connects. |
- TestLoadTimingNotReused(*http_stream); |
- |
- // This triggers read 3. The empty read causes the session to shut down. |
- data()->CompleteRead(); |
- |
- // Because we abandoned the stream, we don't expect to find a session in the |
- // pool anymore. |
- EXPECT_FALSE(HasSpdySession(http_session_->spdy_session_pool(), key)); |
- EXPECT_TRUE(data()->at_read_eof()); |
- EXPECT_TRUE(data()->at_write_eof()); |
- |
- TestLoadTimingNotReused(*http_stream); |
- http_stream->Close(true); |
- // Test that there's no crash when trying to get the load timing after the |
- // stream has been closed. |
- TestLoadTimingNotReused(*http_stream); |
-} |
- |
-TEST_P(SpdyHttpStreamTest, LoadTimingTwoRequests) { |
- scoped_ptr<SpdyFrame> req1( |
- spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true)); |
- scoped_ptr<SpdyFrame> req2( |
- spdy_util_.ConstructSpdyGet(NULL, 0, false, 3, LOWEST, true)); |
- MockWrite writes[] = { |
- CreateMockWrite(*req1, 0), |
- CreateMockWrite(*req2, 1), |
- }; |
- scoped_ptr<SpdyFrame> resp1( |
- spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1)); |
- scoped_ptr<SpdyFrame> body1( |
- spdy_util_.ConstructSpdyBodyFrame(1, "", 0, true)); |
- scoped_ptr<SpdyFrame> resp2( |
- spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 3)); |
- scoped_ptr<SpdyFrame> body2( |
- spdy_util_.ConstructSpdyBodyFrame(3, "", 0, true)); |
- MockRead reads[] = { |
- CreateMockRead(*resp1, 2), |
- CreateMockRead(*body1, 3), |
- CreateMockRead(*resp2, 4), |
- CreateMockRead(*body2, 5), |
- MockRead(ASYNC, 0, 6) // EOF |
- }; |
- |
- HostPortPair host_port_pair("www.google.com", 80); |
- SpdySessionKey key(host_port_pair, ProxyServer::Direct(), |
- PRIVACY_MODE_DISABLED); |
- InitSessionDeterministic(reads, arraysize(reads), |
- writes, arraysize(writes), |
- key); |
- |
- HttpRequestInfo request1; |
- request1.method = "GET"; |
- request1.url = GURL("http://www.google.com/"); |
- TestCompletionCallback callback1; |
- HttpResponseInfo response1; |
- HttpRequestHeaders headers1; |
- scoped_ptr<SpdyHttpStream> http_stream1(new SpdyHttpStream(session_, true)); |
- |
- HttpRequestInfo request2; |
- request2.method = "GET"; |
- request2.url = GURL("http://www.google.com/"); |
- TestCompletionCallback callback2; |
- HttpResponseInfo response2; |
- HttpRequestHeaders headers2; |
- scoped_ptr<SpdyHttpStream> http_stream2(new SpdyHttpStream(session_, true)); |
- |
- // First write. |
- ASSERT_EQ(OK, |
- http_stream1->InitializeStream(&request1, DEFAULT_PRIORITY, |
- BoundNetLog(), |
- CompletionCallback())); |
- EXPECT_EQ(ERR_IO_PENDING, http_stream1->SendRequest(headers1, &response1, |
- callback1.callback())); |
- EXPECT_TRUE(HasSpdySession(http_session_->spdy_session_pool(), key)); |
- |
- deterministic_data()->RunFor(1); |
- EXPECT_LE(0, callback1.WaitForResult()); |
- |
- TestLoadTimingNotReused(*http_stream1); |
- LoadTimingInfo load_timing_info1; |
- LoadTimingInfo load_timing_info2; |
- EXPECT_TRUE(http_stream1->GetLoadTimingInfo(&load_timing_info1)); |
- EXPECT_FALSE(http_stream2->GetLoadTimingInfo(&load_timing_info2)); |
- |
- // Second write. |
- ASSERT_EQ(OK, |
- http_stream2->InitializeStream(&request2, DEFAULT_PRIORITY, |
- BoundNetLog(), |
- CompletionCallback())); |
- EXPECT_EQ(ERR_IO_PENDING, http_stream2->SendRequest(headers2, &response2, |
- callback2.callback())); |
- EXPECT_TRUE(HasSpdySession(http_session_->spdy_session_pool(), key)); |
- |
- deterministic_data()->RunFor(1); |
- EXPECT_LE(0, callback2.WaitForResult()); |
- TestLoadTimingReused(*http_stream2); |
- EXPECT_TRUE(http_stream2->GetLoadTimingInfo(&load_timing_info2)); |
- EXPECT_EQ(load_timing_info1.socket_log_id, load_timing_info2.socket_log_id); |
- |
- // All the reads. |
- deterministic_data()->RunFor(6); |
- |
- // Read stream 1 to completion, before making sure we can still read load |
- // timing from both streams. |
- scoped_refptr<IOBuffer> buf1(new IOBuffer(1)); |
- ASSERT_EQ( |
- 0, http_stream1->ReadResponseBody(buf1.get(), 1, callback1.callback())); |
- |
- // Stream 1 has been read to completion. |
- TestLoadTimingNotReused(*http_stream1); |
- // Stream 2 still has queued body data. |
- TestLoadTimingReused(*http_stream2); |
-} |
- |
-TEST_P(SpdyHttpStreamTest, SendChunkedPost) { |
- BufferedSpdyFramer framer(spdy_util_.spdy_version(), false); |
- |
- scoped_ptr<SpdyFrame> req( |
- spdy_util_.ConstructChunkedSpdyPost(NULL, 0)); |
- scoped_ptr<SpdyFrame> body( |
- framer.CreateDataFrame(1, kUploadData, kUploadDataSize, DATA_FLAG_FIN)); |
- std::vector<MockWrite> writes; |
- int seq = 0; |
- writes.push_back(CreateMockWrite(*req, seq++)); |
- writes.push_back(CreateMockWrite(*body, seq++)); // POST upload frame |
- |
- scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyPostSynReply(NULL, 0)); |
- std::vector<MockRead> reads; |
- reads.push_back(CreateMockRead(*resp, seq++)); |
- reads.push_back(CreateMockRead(*body, seq++)); |
- reads.push_back(MockRead(SYNCHRONOUS, 0, seq++)); // EOF |
- |
- HostPortPair host_port_pair("www.google.com", 80); |
- SpdySessionKey key(host_port_pair, ProxyServer::Direct(), |
- PRIVACY_MODE_DISABLED); |
- InitSession(vector_as_array(&reads), reads.size(), |
- vector_as_array(&writes), writes.size(), |
- key); |
- EXPECT_EQ(spdy_util_.spdy_version(), session_->GetProtocolVersion()); |
- |
- ChunkedUploadDataStream upload_stream(0); |
- const int kFirstChunkSize = kUploadDataSize/2; |
- upload_stream.AppendData(kUploadData, kFirstChunkSize, false); |
- upload_stream.AppendData(kUploadData + kFirstChunkSize, |
- kUploadDataSize - kFirstChunkSize, true); |
- |
- HttpRequestInfo request; |
- request.method = "POST"; |
- request.url = GURL("http://www.google.com/"); |
- request.upload_data_stream = &upload_stream; |
- |
- ASSERT_EQ(OK, upload_stream.Init(TestCompletionCallback().callback())); |
- |
- TestCompletionCallback callback; |
- HttpResponseInfo response; |
- HttpRequestHeaders headers; |
- BoundNetLog net_log; |
- SpdyHttpStream http_stream(session_, true); |
- ASSERT_EQ( |
- OK, |
- http_stream.InitializeStream(&request, DEFAULT_PRIORITY, |
- net_log, CompletionCallback())); |
- |
- EXPECT_EQ(ERR_IO_PENDING, http_stream.SendRequest( |
- headers, &response, callback.callback())); |
- EXPECT_TRUE(HasSpdySession(http_session_->spdy_session_pool(), key)); |
- |
- // This results in writing the post body and reading the response headers. |
- callback.WaitForResult(); |
- |
- // This triggers reading the body and the EOF, causing the session to shut |
- // down. |
- data()->CompleteRead(); |
- base::MessageLoop::current()->RunUntilIdle(); |
- |
- // Because we abandoned the stream, we don't expect to find a session in the |
- // pool anymore. |
- EXPECT_FALSE(HasSpdySession(http_session_->spdy_session_pool(), key)); |
- EXPECT_TRUE(data()->at_read_eof()); |
- EXPECT_TRUE(data()->at_write_eof()); |
-} |
- |
-// Test to ensure the SpdyStream state machine does not get confused when a |
-// chunk becomes available while a write is pending. |
-TEST_P(SpdyHttpStreamTest, DelayedSendChunkedPost) { |
- const char kUploadData1[] = "12345678"; |
- const int kUploadData1Size = arraysize(kUploadData1)-1; |
- scoped_ptr<SpdyFrame> req(spdy_util_.ConstructChunkedSpdyPost(NULL, 0)); |
- scoped_ptr<SpdyFrame> chunk1(spdy_util_.ConstructSpdyBodyFrame(1, false)); |
- scoped_ptr<SpdyFrame> chunk2( |
- spdy_util_.ConstructSpdyBodyFrame( |
- 1, kUploadData1, kUploadData1Size, false)); |
- scoped_ptr<SpdyFrame> chunk3(spdy_util_.ConstructSpdyBodyFrame(1, true)); |
- MockWrite writes[] = { |
- CreateMockWrite(*req.get(), 0), |
- CreateMockWrite(*chunk1, 1), // POST upload frames |
- CreateMockWrite(*chunk2, 2), |
- CreateMockWrite(*chunk3, 3), |
- }; |
- scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyPostSynReply(NULL, 0)); |
- MockRead reads[] = { |
- CreateMockRead(*resp, 4), |
- CreateMockRead(*chunk1, 5), |
- CreateMockRead(*chunk2, 6), |
- CreateMockRead(*chunk3, 7), |
- MockRead(ASYNC, 0, 8) // EOF |
- }; |
- |
- HostPortPair host_port_pair("www.google.com", 80); |
- SpdySessionKey key(host_port_pair, ProxyServer::Direct(), |
- PRIVACY_MODE_DISABLED); |
- InitSessionDeterministic(reads, arraysize(reads), |
- writes, arraysize(writes), |
- key); |
- |
- ChunkedUploadDataStream upload_stream(0); |
- |
- HttpRequestInfo request; |
- request.method = "POST"; |
- request.url = GURL("http://www.google.com/"); |
- request.upload_data_stream = &upload_stream; |
- |
- ASSERT_EQ(OK, upload_stream.Init(TestCompletionCallback().callback())); |
- upload_stream.AppendData(kUploadData, kUploadDataSize, false); |
- |
- BoundNetLog net_log; |
- scoped_ptr<SpdyHttpStream> http_stream(new SpdyHttpStream(session_, true)); |
- ASSERT_EQ(OK, http_stream->InitializeStream(&request, DEFAULT_PRIORITY, |
- net_log, CompletionCallback())); |
- |
- TestCompletionCallback callback; |
- HttpRequestHeaders headers; |
- HttpResponseInfo response; |
- // This will attempt to Write() the initial request and headers, which will |
- // complete asynchronously. |
- EXPECT_EQ(ERR_IO_PENDING, http_stream->SendRequest(headers, &response, |
- callback.callback())); |
- EXPECT_TRUE(HasSpdySession(http_session_->spdy_session_pool(), key)); |
- |
- // Complete the initial request write and the first chunk. |
- deterministic_data()->RunFor(2); |
- ASSERT_TRUE(callback.have_result()); |
- EXPECT_EQ(OK, callback.WaitForResult()); |
- |
- // Now append the final two chunks which will enqueue two more writes. |
- upload_stream.AppendData(kUploadData1, kUploadData1Size, false); |
- upload_stream.AppendData(kUploadData, kUploadDataSize, true); |
- |
- // Finish writing all the chunks. |
- deterministic_data()->RunFor(2); |
- |
- // Read response headers. |
- deterministic_data()->RunFor(1); |
- ASSERT_EQ(OK, http_stream->ReadResponseHeaders(callback.callback())); |
- |
- // Read and check |chunk1| response. |
- deterministic_data()->RunFor(1); |
- scoped_refptr<IOBuffer> buf1(new IOBuffer(kUploadDataSize)); |
- ASSERT_EQ(kUploadDataSize, |
- http_stream->ReadResponseBody( |
- buf1.get(), kUploadDataSize, callback.callback())); |
- EXPECT_EQ(kUploadData, std::string(buf1->data(), kUploadDataSize)); |
- |
- // Read and check |chunk2| response. |
- deterministic_data()->RunFor(1); |
- scoped_refptr<IOBuffer> buf2(new IOBuffer(kUploadData1Size)); |
- ASSERT_EQ(kUploadData1Size, |
- http_stream->ReadResponseBody( |
- buf2.get(), kUploadData1Size, callback.callback())); |
- EXPECT_EQ(kUploadData1, std::string(buf2->data(), kUploadData1Size)); |
- |
- // Read and check |chunk3| response. |
- deterministic_data()->RunFor(1); |
- scoped_refptr<IOBuffer> buf3(new IOBuffer(kUploadDataSize)); |
- ASSERT_EQ(kUploadDataSize, |
- http_stream->ReadResponseBody( |
- buf3.get(), kUploadDataSize, callback.callback())); |
- EXPECT_EQ(kUploadData, std::string(buf3->data(), kUploadDataSize)); |
- |
- // Finish reading the |EOF|. |
- deterministic_data()->RunFor(1); |
- ASSERT_TRUE(response.headers.get()); |
- ASSERT_EQ(200, response.headers->response_code()); |
- EXPECT_TRUE(deterministic_data()->at_read_eof()); |
- EXPECT_TRUE(deterministic_data()->at_write_eof()); |
-} |
- |
-// Test that the SpdyStream state machine can handle sending a final empty data |
-// frame when uploading a chunked data stream. |
-TEST_P(SpdyHttpStreamTest, DelayedSendChunkedPostWithEmptyFinalDataFrame) { |
- scoped_ptr<SpdyFrame> req(spdy_util_.ConstructChunkedSpdyPost(NULL, 0)); |
- scoped_ptr<SpdyFrame> chunk1(spdy_util_.ConstructSpdyBodyFrame(1, false)); |
- scoped_ptr<SpdyFrame> chunk2( |
- spdy_util_.ConstructSpdyBodyFrame(1, "", 0, true)); |
- MockWrite writes[] = { |
- CreateMockWrite(*req.get(), 0), |
- CreateMockWrite(*chunk1, 1), // POST upload frames |
- CreateMockWrite(*chunk2, 2), |
- }; |
- scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyPostSynReply(NULL, 0)); |
- MockRead reads[] = { |
- CreateMockRead(*resp, 3), |
- CreateMockRead(*chunk1, 4), |
- CreateMockRead(*chunk2, 5), |
- MockRead(ASYNC, 0, 6) // EOF |
- }; |
- |
- HostPortPair host_port_pair("www.google.com", 80); |
- SpdySessionKey key(host_port_pair, ProxyServer::Direct(), |
- PRIVACY_MODE_DISABLED); |
- InitSessionDeterministic(reads, arraysize(reads), |
- writes, arraysize(writes), |
- key); |
- |
- ChunkedUploadDataStream upload_stream(0); |
- |
- HttpRequestInfo request; |
- request.method = "POST"; |
- request.url = GURL("http://www.google.com/"); |
- request.upload_data_stream = &upload_stream; |
- |
- ASSERT_EQ(OK, upload_stream.Init(TestCompletionCallback().callback())); |
- upload_stream.AppendData(kUploadData, kUploadDataSize, false); |
- |
- BoundNetLog net_log; |
- scoped_ptr<SpdyHttpStream> http_stream(new SpdyHttpStream(session_, true)); |
- ASSERT_EQ(OK, http_stream->InitializeStream(&request, DEFAULT_PRIORITY, |
- net_log, CompletionCallback())); |
- |
- TestCompletionCallback callback; |
- HttpRequestHeaders headers; |
- HttpResponseInfo response; |
- // This will attempt to Write() the initial request and headers, which will |
- // complete asynchronously. |
- EXPECT_EQ(ERR_IO_PENDING, http_stream->SendRequest(headers, &response, |
- callback.callback())); |
- EXPECT_TRUE(HasSpdySession(http_session_->spdy_session_pool(), key)); |
- |
- // Complete the initial request write and the first chunk. |
- deterministic_data()->RunFor(2); |
- ASSERT_TRUE(callback.have_result()); |
- EXPECT_EQ(OK, callback.WaitForResult()); |
- |
- // Now end the stream with an empty data frame and the FIN set. |
- upload_stream.AppendData(NULL, 0, true); |
- |
- // Finish writing the final frame. |
- deterministic_data()->RunFor(1); |
- |
- // Read response headers. |
- deterministic_data()->RunFor(1); |
- ASSERT_EQ(OK, http_stream->ReadResponseHeaders(callback.callback())); |
- |
- // Read and check |chunk1| response. |
- deterministic_data()->RunFor(1); |
- scoped_refptr<IOBuffer> buf1(new IOBuffer(kUploadDataSize)); |
- ASSERT_EQ(kUploadDataSize, |
- http_stream->ReadResponseBody( |
- buf1.get(), kUploadDataSize, callback.callback())); |
- EXPECT_EQ(kUploadData, std::string(buf1->data(), kUploadDataSize)); |
- |
- // Read and check |chunk2| response. |
- deterministic_data()->RunFor(1); |
- ASSERT_EQ(0, |
- http_stream->ReadResponseBody( |
- buf1.get(), kUploadDataSize, callback.callback())); |
- |
- // Finish reading the |EOF|. |
- deterministic_data()->RunFor(1); |
- ASSERT_TRUE(response.headers.get()); |
- ASSERT_EQ(200, response.headers->response_code()); |
- EXPECT_TRUE(deterministic_data()->at_read_eof()); |
- EXPECT_TRUE(deterministic_data()->at_write_eof()); |
-} |
- |
-// Test that the SpdyStream state machine handles a chunked upload with no |
-// payload. Unclear if this is a case worth supporting. |
-TEST_P(SpdyHttpStreamTest, ChunkedPostWithEmptyPayload) { |
- scoped_ptr<SpdyFrame> req(spdy_util_.ConstructChunkedSpdyPost(NULL, 0)); |
- scoped_ptr<SpdyFrame> chunk( |
- spdy_util_.ConstructSpdyBodyFrame(1, "", 0, true)); |
- MockWrite writes[] = { |
- CreateMockWrite(*req.get(), 0), |
- CreateMockWrite(*chunk, 1), |
- }; |
- scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyPostSynReply(NULL, 0)); |
- MockRead reads[] = { |
- CreateMockRead(*resp, 2), |
- CreateMockRead(*chunk, 3), |
- MockRead(ASYNC, 0, 4) // EOF |
- }; |
- |
- HostPortPair host_port_pair("www.google.com", 80); |
- SpdySessionKey key(host_port_pair, ProxyServer::Direct(), |
- PRIVACY_MODE_DISABLED); |
- InitSessionDeterministic(reads, arraysize(reads), |
- writes, arraysize(writes), |
- key); |
- |
- ChunkedUploadDataStream upload_stream(0); |
- |
- HttpRequestInfo request; |
- request.method = "POST"; |
- request.url = GURL("http://www.google.com/"); |
- request.upload_data_stream = &upload_stream; |
- |
- ASSERT_EQ(OK, upload_stream.Init(TestCompletionCallback().callback())); |
- upload_stream.AppendData("", 0, true); |
- |
- BoundNetLog net_log; |
- scoped_ptr<SpdyHttpStream> http_stream(new SpdyHttpStream(session_, true)); |
- ASSERT_EQ(OK, http_stream->InitializeStream(&request, DEFAULT_PRIORITY, |
- net_log, CompletionCallback())); |
- |
- TestCompletionCallback callback; |
- HttpRequestHeaders headers; |
- HttpResponseInfo response; |
- // This will attempt to Write() the initial request and headers, which will |
- // complete asynchronously. |
- EXPECT_EQ(ERR_IO_PENDING, http_stream->SendRequest(headers, &response, |
- callback.callback())); |
- EXPECT_TRUE(HasSpdySession(http_session_->spdy_session_pool(), key)); |
- |
- // Complete writing request, followed by a FIN. |
- deterministic_data()->RunFor(2); |
- ASSERT_TRUE(callback.have_result()); |
- EXPECT_EQ(OK, callback.WaitForResult()); |
- |
- // Read response headers. |
- deterministic_data()->RunFor(1); |
- ASSERT_EQ(OK, http_stream->ReadResponseHeaders(callback.callback())); |
- |
- // Read and check |chunk| response. |
- deterministic_data()->RunFor(1); |
- scoped_refptr<IOBuffer> buf(new IOBuffer(1)); |
- ASSERT_EQ(0, |
- http_stream->ReadResponseBody( |
- buf.get(), 1, callback.callback())); |
- |
- // Finish reading the |EOF|. |
- deterministic_data()->RunFor(1); |
- ASSERT_TRUE(response.headers.get()); |
- ASSERT_EQ(200, response.headers->response_code()); |
- EXPECT_TRUE(deterministic_data()->at_read_eof()); |
- EXPECT_TRUE(deterministic_data()->at_write_eof()); |
-} |
- |
-// Test case for bug: http://code.google.com/p/chromium/issues/detail?id=50058 |
-TEST_P(SpdyHttpStreamTest, SpdyURLTest) { |
- const char * const full_url = "http://www.google.com/foo?query=what#anchor"; |
- const char * const base_url = "http://www.google.com/foo?query=what"; |
- scoped_ptr<SpdyFrame> req( |
- spdy_util_.ConstructSpdyGet(base_url, false, 1, LOWEST)); |
- MockWrite writes[] = { |
- CreateMockWrite(*req.get(), 1), |
- }; |
- scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1)); |
- MockRead reads[] = { |
- CreateMockRead(*resp, 2), |
- MockRead(SYNCHRONOUS, 0, 3) // EOF |
- }; |
- |
- HostPortPair host_port_pair("www.google.com", 80); |
- SpdySessionKey key(host_port_pair, ProxyServer::Direct(), |
- PRIVACY_MODE_DISABLED); |
- InitSession(reads, arraysize(reads), writes, arraysize(writes), key); |
- |
- HttpRequestInfo request; |
- request.method = "GET"; |
- request.url = GURL(full_url); |
- TestCompletionCallback callback; |
- HttpResponseInfo response; |
- HttpRequestHeaders headers; |
- BoundNetLog net_log; |
- scoped_ptr<SpdyHttpStream> http_stream(new SpdyHttpStream(session_, true)); |
- ASSERT_EQ(OK, |
- http_stream->InitializeStream( |
- &request, DEFAULT_PRIORITY, net_log, CompletionCallback())); |
- |
- EXPECT_EQ(ERR_IO_PENDING, http_stream->SendRequest(headers, &response, |
- callback.callback())); |
- |
- EXPECT_EQ(base_url, http_stream->stream()->GetUrlFromHeaders().spec()); |
- |
- // This triggers the MockWrite and read 2 |
- callback.WaitForResult(); |
- |
- // This triggers read 3. The empty read causes the session to shut down. |
- data()->CompleteRead(); |
- |
- // Because we abandoned the stream, we don't expect to find a session in the |
- // pool anymore. |
- EXPECT_FALSE(HasSpdySession(http_session_->spdy_session_pool(), key)); |
- EXPECT_TRUE(data()->at_read_eof()); |
- EXPECT_TRUE(data()->at_write_eof()); |
-} |
- |
-// The tests below are only for SPDY/3 and above. |
- |
-// Test the receipt of a WINDOW_UPDATE frame while waiting for a chunk to be |
-// made available is handled correctly. |
-TEST_P(SpdyHttpStreamTest, DelayedSendChunkedPostWithWindowUpdate) { |
- scoped_ptr<SpdyFrame> req(spdy_util_.ConstructChunkedSpdyPost(NULL, 0)); |
- scoped_ptr<SpdyFrame> chunk1(spdy_util_.ConstructSpdyBodyFrame(1, true)); |
- MockWrite writes[] = { |
- CreateMockWrite(*req.get(), 0), |
- CreateMockWrite(*chunk1, 1), |
- }; |
- scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyPostSynReply(NULL, 0)); |
- scoped_ptr<SpdyFrame> window_update( |
- spdy_util_.ConstructSpdyWindowUpdate(1, kUploadDataSize)); |
- MockRead reads[] = { |
- CreateMockRead(*window_update, 2), |
- CreateMockRead(*resp, 3), |
- CreateMockRead(*chunk1, 4), |
- MockRead(ASYNC, 0, 5) // EOF |
- }; |
- |
- HostPortPair host_port_pair("www.google.com", 80); |
- SpdySessionKey key(host_port_pair, ProxyServer::Direct(), |
- PRIVACY_MODE_DISABLED); |
- |
- InitSessionDeterministic(reads, arraysize(reads), |
- writes, arraysize(writes), |
- key); |
- |
- ChunkedUploadDataStream upload_stream(0); |
- |
- HttpRequestInfo request; |
- request.method = "POST"; |
- request.url = GURL("http://www.google.com/"); |
- request.upload_data_stream = &upload_stream; |
- |
- ASSERT_EQ(OK, upload_stream.Init(TestCompletionCallback().callback())); |
- upload_stream.AppendData(kUploadData, kUploadDataSize, true); |
- |
- BoundNetLog net_log; |
- scoped_ptr<SpdyHttpStream> http_stream(new SpdyHttpStream(session_, true)); |
- ASSERT_EQ(OK, http_stream->InitializeStream(&request, DEFAULT_PRIORITY, |
- net_log, CompletionCallback())); |
- |
- HttpRequestHeaders headers; |
- HttpResponseInfo response; |
- // This will attempt to Write() the initial request and headers, which will |
- // complete asynchronously. |
- TestCompletionCallback callback; |
- EXPECT_EQ(ERR_IO_PENDING, http_stream->SendRequest(headers, &response, |
- callback.callback())); |
- EXPECT_TRUE(HasSpdySession(http_session_->spdy_session_pool(), key)); |
- |
- // Complete the initial request write and first chunk. |
- deterministic_data_->RunFor(2); |
- ASSERT_TRUE(callback.have_result()); |
- EXPECT_EQ(OK, callback.WaitForResult()); |
- |
- // Verify that the window size has decreased. |
- ASSERT_TRUE(http_stream->stream() != NULL); |
- EXPECT_NE( |
- static_cast<int>(SpdySession::GetInitialWindowSize(session_->protocol())), |
- http_stream->stream()->send_window_size()); |
- |
- // Read window update. |
- deterministic_data_->RunFor(1); |
- |
- // Verify the window update. |
- ASSERT_TRUE(http_stream->stream() != NULL); |
- EXPECT_EQ( |
- static_cast<int>(SpdySession::GetInitialWindowSize(session_->protocol())), |
- http_stream->stream()->send_window_size()); |
- |
- // Read response headers. |
- deterministic_data_->RunFor(1); |
- ASSERT_EQ(OK, http_stream->ReadResponseHeaders(callback.callback())); |
- |
- // Read and check |chunk1| response. |
- deterministic_data_->RunFor(1); |
- scoped_refptr<IOBuffer> buf1(new IOBuffer(kUploadDataSize)); |
- ASSERT_EQ(kUploadDataSize, |
- http_stream->ReadResponseBody( |
- buf1.get(), kUploadDataSize, callback.callback())); |
- EXPECT_EQ(kUploadData, std::string(buf1->data(), kUploadDataSize)); |
- |
- // Finish reading the |EOF|. |
- deterministic_data_->RunFor(1); |
- ASSERT_TRUE(response.headers.get()); |
- ASSERT_EQ(200, response.headers->response_code()); |
- EXPECT_TRUE(deterministic_data_->at_read_eof()); |
- EXPECT_TRUE(deterministic_data_->at_write_eof()); |
-} |
- |
-// TODO(willchan): Write a longer test for SpdyStream that exercises all |
-// methods. |
- |
-} // namespace net |