| 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
|
|
|