summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorrch@chromium.org <rch@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-03-08 05:49:36 +0000
committerrch@chromium.org <rch@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-03-08 05:49:36 +0000
commitf54a4a4f889ac4e99b3a4b0a3ee9b2507dde18ae (patch)
tree3319eb0d0ff265adc467d5702c2c0287bc10e6ac
parent5aad680df5d54c9f9f618912e391cc1c06aee8c1 (diff)
downloadchromium_src-f54a4a4f889ac4e99b3a4b0a3ee9b2507dde18ae.zip
chromium_src-f54a4a4f889ac4e99b3a4b0a3ee9b2507dde18ae.tar.gz
chromium_src-f54a4a4f889ac4e99b3a4b0a3ee9b2507dde18ae.tar.bz2
When SpdySession is initialized with a socket that negotiated a specific SPDY version, use that version to determine if flow control should be used.
Remove flow control tests from spdy/2 tests, since flow control is not part of spdy/2 (only spdy/2.1 and spdy/3) Review URL: http://codereview.chromium.org/9632004 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@125572 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--net/spdy/spdy_network_transaction_spdy2_unittest.cc379
-rw-r--r--net/spdy/spdy_session.cc12
2 files changed, 5 insertions, 386 deletions
diff --git a/net/spdy/spdy_network_transaction_spdy2_unittest.cc b/net/spdy/spdy_network_transaction_spdy2_unittest.cc
index 8a8e001..5859a98 100644
--- a/net/spdy/spdy_network_transaction_spdy2_unittest.cc
+++ b/net/spdy/spdy_network_transaction_spdy2_unittest.cc
@@ -1870,385 +1870,6 @@ TEST_P(SpdyNetworkTransactionSpdy2Test, ResponseWithTwoSynReplies) {
helper.VerifyDataConsumed();
}
-// Test that sent data frames and received WINDOW_UPDATE frames change
-// the send_window_size_ correctly.
-
-// WINDOW_UPDATE is different than most other frames in that it can arrive
-// while the client is still sending the request body. In order to enforce
-// this scenario, we feed a couple of dummy frames and give a delay of 0 to
-// socket data provider, so that initial read that is done as soon as the
-// stream is created, succeeds and schedules another read. This way reads
-// and writes are interleaved; after doing a full frame write, SpdyStream
-// will break out of DoLoop and will read and process a WINDOW_UPDATE.
-// Once our WINDOW_UPDATE is read, we cannot send SYN_REPLY right away
-// since request has not been completely written, therefore we feed
-// enough number of WINDOW_UPDATEs to finish the first read and cause a
-// write, leading to a complete write of request body; after that we send
-// a reply with a body, to cause a graceful shutdown.
-
-// TODO(agayev): develop a socket data provider where both, reads and
-// writes are ordered so that writing tests like these are easy and rewrite
-// all these tests using it. Right now we are working around the
-// limitations as described above and it's not deterministic, tests may
-// fail under specific circumstances.
-TEST_P(SpdyNetworkTransactionSpdy2Test, WindowUpdateReceived) {
- SpdySession::set_use_flow_control(SpdySession::kEnableFlowControl);
-
- static int kFrameCount = 2;
- scoped_ptr<std::string> content(
- new std::string(kMaxSpdyFrameChunkSize, 'a'));
- scoped_ptr<spdy::SpdyFrame> req(ConstructSpdyPost(
- kMaxSpdyFrameChunkSize * kFrameCount, NULL, 0));
- scoped_ptr<spdy::SpdyFrame> body(
- ConstructSpdyBodyFrame(1, content->c_str(), content->size(), false));
- scoped_ptr<spdy::SpdyFrame> body_end(
- ConstructSpdyBodyFrame(1, content->c_str(), content->size(), true));
-
- MockWrite writes[] = {
- CreateMockWrite(*req),
- CreateMockWrite(*body),
- CreateMockWrite(*body_end),
- };
-
- static const int32 kDeltaWindowSize = 0xff;
- static const int kDeltaCount = 4;
- scoped_ptr<spdy::SpdyFrame> window_update(
- ConstructSpdyWindowUpdate(1, kDeltaWindowSize));
- scoped_ptr<spdy::SpdyFrame> window_update_dummy(
- ConstructSpdyWindowUpdate(2, kDeltaWindowSize));
- scoped_ptr<spdy::SpdyFrame> resp(ConstructSpdyPostSynReply(NULL, 0));
- MockRead reads[] = {
- CreateMockRead(*window_update_dummy),
- CreateMockRead(*window_update_dummy),
- CreateMockRead(*window_update_dummy),
- CreateMockRead(*window_update), // Four updates, therefore window
- CreateMockRead(*window_update), // size should increase by
- CreateMockRead(*window_update), // kDeltaWindowSize * 4
- CreateMockRead(*window_update),
- CreateMockRead(*resp),
- CreateMockRead(*body_end),
- MockRead(ASYNC, 0, 0) // EOF
- };
-
- scoped_ptr<DelayedSocketData> data(
- new DelayedSocketData(0, reads, arraysize(reads),
- writes, arraysize(writes)));
-
- // Setup the request
- HttpRequestInfo request;
- request.method = "POST";
- request.url = GURL(kDefaultURL);
- request.upload_data = new UploadData();
- for (int i = 0; i < kFrameCount; ++i)
- request.upload_data->AppendBytes(content->c_str(), content->size());
-
- NormalSpdyTransactionHelper helper(request, BoundNetLog(), GetParam());
- helper.AddData(data.get());
- helper.RunPreTestSetup();
-
- HttpNetworkTransaction* trans = helper.trans();
-
- TestCompletionCallback callback;
- int rv = trans->Start(&helper.request(), callback.callback(), BoundNetLog());
-
- EXPECT_EQ(ERR_IO_PENDING, rv);
- rv = callback.WaitForResult();
- EXPECT_EQ(OK, rv);
-
- SpdyHttpStream* stream = static_cast<SpdyHttpStream*>(trans->stream_.get());
- ASSERT_TRUE(stream != NULL);
- ASSERT_TRUE(stream->stream() != NULL);
- EXPECT_EQ(static_cast<int>(spdy::kSpdyStreamInitialWindowSize) +
- kDeltaWindowSize * kDeltaCount -
- kMaxSpdyFrameChunkSize * kFrameCount,
- stream->stream()->send_window_size());
- helper.VerifyDataConsumed();
-
- SpdySession::set_use_flow_control(SpdySession::kFlowControlBasedOnNPN);
-}
-
-// Test that received data frames and sent WINDOW_UPDATE frames change
-// the recv_window_size_ correctly.
-TEST_P(SpdyNetworkTransactionSpdy2Test, WindowUpdateSent) {
- SpdySession::set_use_flow_control(SpdySession::kEnableFlowControl);
-
- scoped_ptr<spdy::SpdyFrame> req(ConstructSpdyGet(NULL, 0, false, 1, LOWEST));
- scoped_ptr<spdy::SpdyFrame> window_update(
- ConstructSpdyWindowUpdate(1, kUploadDataSize));
-
- MockWrite writes[] = {
- CreateMockWrite(*req),
- CreateMockWrite(*window_update),
- };
-
- scoped_ptr<spdy::SpdyFrame> resp(
- ConstructSpdyGetSynReply(NULL, 0, 1));
- scoped_ptr<spdy::SpdyFrame> body_no_fin(
- ConstructSpdyBodyFrame(1, false));
- scoped_ptr<spdy::SpdyFrame> body_fin(
- ConstructSpdyBodyFrame(1, NULL, 0, true));
- MockRead reads[] = {
- CreateMockRead(*resp),
- CreateMockRead(*body_no_fin),
- MockRead(ASYNC, ERR_IO_PENDING, 0), // Force a pause
- CreateMockRead(*body_fin),
- MockRead(ASYNC, ERR_IO_PENDING, 0), // Force a pause
- MockRead(ASYNC, 0, 0) // EOF
- };
-
- scoped_ptr<DelayedSocketData> data(
- new DelayedSocketData(1, reads, arraysize(reads),
- writes, arraysize(writes)));
-
- NormalSpdyTransactionHelper helper(CreateGetRequest(),
- BoundNetLog(), GetParam());
- helper.AddData(data.get());
- helper.RunPreTestSetup();
- HttpNetworkTransaction* trans = helper.trans();
-
- TestCompletionCallback callback;
- int rv = trans->Start(&helper.request(), callback.callback(), BoundNetLog());
-
- EXPECT_EQ(ERR_IO_PENDING, rv);
- rv = callback.WaitForResult();
- EXPECT_EQ(OK, rv);
-
- SpdyHttpStream* stream =
- static_cast<SpdyHttpStream*>(trans->stream_.get());
- ASSERT_TRUE(stream != NULL);
- ASSERT_TRUE(stream->stream() != NULL);
-
- EXPECT_EQ(
- static_cast<int>(spdy::kSpdyStreamInitialWindowSize) - kUploadDataSize,
- stream->stream()->recv_window_size());
-
- const HttpResponseInfo* response = trans->GetResponseInfo();
- ASSERT_TRUE(response != NULL);
- ASSERT_TRUE(response->headers != NULL);
- EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine());
- EXPECT_TRUE(response->was_fetched_via_spdy);
-
- // Force sending of WINDOW_UPDATE by setting initial_recv_window_size to a
- // small value.
- stream->stream()->set_initial_recv_window_size(kUploadDataSize / 2);
-
- // Issue a read which will cause a WINDOW_UPDATE to be sent and window
- // size increased to default.
- scoped_refptr<net::IOBuffer> buf(new net::IOBuffer(kUploadDataSize));
- rv = trans->Read(buf, kUploadDataSize, CompletionCallback());
- EXPECT_EQ(kUploadDataSize, rv);
- std::string content(buf->data(), buf->data()+kUploadDataSize);
- EXPECT_STREQ(kUploadData, content.c_str());
-
- // Schedule the reading of empty data frame with FIN
- data->CompleteRead();
-
- // Force write of WINDOW_UPDATE which was scheduled during the above
- // read.
- MessageLoop::current()->RunAllPending();
-
- // Read EOF.
- data->CompleteRead();
-
- helper.VerifyDataConsumed();
-
- SpdySession::set_use_flow_control(SpdySession::kFlowControlBasedOnNPN);
-}
-
-// Test that WINDOW_UPDATE frame causing overflow is handled correctly. We
-// use the same trick as in the above test to enforce our scenario.
-TEST_P(SpdyNetworkTransactionSpdy2Test, WindowUpdateOverflow) {
- SpdySession::set_use_flow_control(SpdySession::kEnableFlowControl);
-
- // number of full frames we hope to write (but will not, used to
- // set content-length header correctly)
- static int kFrameCount = 3;
-
- scoped_ptr<std::string> content(
- new std::string(kMaxSpdyFrameChunkSize, 'a'));
- scoped_ptr<spdy::SpdyFrame> req(ConstructSpdyPost(
- kMaxSpdyFrameChunkSize * kFrameCount, NULL, 0));
- scoped_ptr<spdy::SpdyFrame> body(
- ConstructSpdyBodyFrame(1, content->c_str(), content->size(), false));
- scoped_ptr<spdy::SpdyFrame> rst(
- ConstructSpdyRstStream(1, spdy::FLOW_CONTROL_ERROR));
-
- // We're not going to write a data frame with FIN, we'll receive a bad
- // WINDOW_UPDATE while sending a request and will send a RST_STREAM frame.
- MockWrite writes[] = {
- CreateMockWrite(*req),
- CreateMockWrite(*body),
- CreateMockWrite(*rst),
- };
-
- static const int32 kDeltaWindowSize = 0x7fffffff; // cause an overflow
- scoped_ptr<spdy::SpdyFrame> window_update(
- ConstructSpdyWindowUpdate(1, kDeltaWindowSize));
- scoped_ptr<spdy::SpdyFrame> window_update2(
- ConstructSpdyWindowUpdate(2, kDeltaWindowSize));
- scoped_ptr<spdy::SpdyFrame> reply(ConstructSpdyPostSynReply(NULL, 0));
-
- MockRead reads[] = {
- CreateMockRead(*window_update2),
- CreateMockRead(*window_update2),
- CreateMockRead(*window_update),
- CreateMockRead(*window_update),
- CreateMockRead(*window_update),
- MockRead(ASYNC, ERR_IO_PENDING, 0), // Wait for the RST to be written.
- MockRead(ASYNC, 0, 0) // EOF
- };
-
- scoped_ptr<DelayedSocketData> data(
- new DelayedSocketData(0, reads, arraysize(reads),
- writes, arraysize(writes)));
-
- // Setup the request
- HttpRequestInfo request;
- request.method = "POST";
- request.url = GURL("http://www.google.com/");
- request.upload_data = new UploadData();
- for (int i = 0; i < kFrameCount; ++i)
- request.upload_data->AppendBytes(content->c_str(), content->size());
-
- NormalSpdyTransactionHelper helper(request,
- BoundNetLog(), GetParam());
- helper.AddData(data.get());
- helper.RunPreTestSetup();
-
- HttpNetworkTransaction* trans = helper.trans();
-
- TestCompletionCallback callback;
- int rv = trans->Start(&helper.request(), callback.callback(), BoundNetLog());
-
- EXPECT_EQ(ERR_IO_PENDING, rv);
- rv = callback.WaitForResult();
- EXPECT_EQ(ERR_SPDY_PROTOCOL_ERROR, rv);
-
- data->CompleteRead();
-
- ASSERT_TRUE(helper.session() != NULL);
- ASSERT_TRUE(helper.session()->spdy_session_pool() != NULL);
- helper.session()->spdy_session_pool()->CloseAllSessions();
- helper.VerifyDataConsumed();
-
- SpdySession::set_use_flow_control(SpdySession::kFlowControlBasedOnNPN);
-}
-
-// Test that after hitting a send window size of 0, the write process
-// stalls and upon receiving WINDOW_UPDATE frame write resumes.
-
-// This test constructs a POST request followed by enough data frames
-// containing 'a' that would make the window size 0, followed by another
-// data frame containing default content (which is "hello!") and this frame
-// also contains a FIN flag. DelayedSocketData is used to enforce all
-// writes go through before a read could happen. However, the last frame
-// ("hello!") is not supposed to go through since by the time its turn
-// arrives, window size is 0. At this point MessageLoop::Run() called via
-// callback would block. Therefore we call MessageLoop::RunAllPending()
-// which returns after performing all possible writes. We use DCHECKS to
-// ensure that last data frame is still there and stream has stalled.
-// After that, next read is artifically enforced, which causes a
-// WINDOW_UPDATE to be read and I/O process resumes.
-TEST_P(SpdyNetworkTransactionSpdy2Test, FlowControlStallResume) {
- SpdySession::set_use_flow_control(SpdySession::kEnableFlowControl);
-
- // Number of frames we need to send to zero out the window size: data
- // frames plus SYN_STREAM plus the last data frame; also we need another
- // data frame that we will send once the WINDOW_UPDATE is received,
- // therefore +3.
- size_t nwrites =
- spdy::kSpdyStreamInitialWindowSize / kMaxSpdyFrameChunkSize + 3;
-
- // Calculate last frame's size; 0 size data frame is legal.
- size_t last_frame_size =
- spdy::kSpdyStreamInitialWindowSize % kMaxSpdyFrameChunkSize;
-
- // Construct content for a data frame of maximum size.
- scoped_ptr<std::string> content(
- new std::string(kMaxSpdyFrameChunkSize, 'a'));
-
- scoped_ptr<spdy::SpdyFrame> req(ConstructSpdyPost(
- spdy::kSpdyStreamInitialWindowSize + kUploadDataSize, NULL, 0));
-
- // Full frames.
- scoped_ptr<spdy::SpdyFrame> body1(
- ConstructSpdyBodyFrame(1, content->c_str(), content->size(), false));
-
- // Last frame to zero out the window size.
- scoped_ptr<spdy::SpdyFrame> body2(
- ConstructSpdyBodyFrame(1, content->c_str(), last_frame_size, false));
-
- // Data frame to be sent once WINDOW_UPDATE frame is received.
- scoped_ptr<spdy::SpdyFrame> body3(ConstructSpdyBodyFrame(1, true));
-
- // Fill in mock writes.
- scoped_array<MockWrite> writes(new MockWrite[nwrites]);
- size_t i = 0;
- writes[i] = CreateMockWrite(*req);
- for (i = 1; i < nwrites-2; i++)
- writes[i] = CreateMockWrite(*body1);
- writes[i++] = CreateMockWrite(*body2);
- writes[i] = CreateMockWrite(*body3);
-
- // Construct read frame, give enough space to upload the rest of the
- // data.
- scoped_ptr<spdy::SpdyFrame> window_update(
- ConstructSpdyWindowUpdate(1, kUploadDataSize));
- scoped_ptr<spdy::SpdyFrame> reply(ConstructSpdyPostSynReply(NULL, 0));
- MockRead reads[] = {
- CreateMockRead(*window_update),
- CreateMockRead(*window_update),
- CreateMockRead(*reply),
- CreateMockRead(*body2),
- CreateMockRead(*body3),
- MockRead(ASYNC, 0, 0) // EOF
- };
-
- // Force all writes to happen before any read, last write will not
- // actually queue a frame, due to window size being 0.
- scoped_ptr<DelayedSocketData> data(
- new DelayedSocketData(nwrites, reads, arraysize(reads),
- writes.get(), nwrites));
-
- HttpRequestInfo request;
- request.method = "POST";
- request.url = GURL("http://www.google.com/");
- request.upload_data = new UploadData();
- scoped_ptr<std::string> upload_data(
- new std::string(spdy::kSpdyStreamInitialWindowSize, 'a'));
- upload_data->append(kUploadData, kUploadDataSize);
- request.upload_data->AppendBytes(upload_data->c_str(), upload_data->size());
- NormalSpdyTransactionHelper helper(request,
- BoundNetLog(), GetParam());
- helper.AddData(data.get());
- helper.RunPreTestSetup();
-
- HttpNetworkTransaction* trans = helper.trans();
-
- TestCompletionCallback callback;
- int rv = trans->Start(&helper.request(), callback.callback(), BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
-
- MessageLoop::current()->RunAllPending(); // Write as much as we can.
-
- SpdyHttpStream* stream = static_cast<SpdyHttpStream*>(trans->stream_.get());
- ASSERT_TRUE(stream != NULL);
- ASSERT_TRUE(stream->stream() != NULL);
- EXPECT_EQ(0, stream->stream()->send_window_size());
- // All the body data should have been read.
- // TODO(satorux): This is because of the weirdness in reading the request
- // body in OnSendBodyComplete(). See crbug.com/113107.
- EXPECT_TRUE(stream->request_body_stream_->IsEOF());
- // But the body is not yet fully sent ("hello!" is not yet sent).
- EXPECT_FALSE(stream->stream()->body_sent());
-
- data->ForceNextRead(); // Read in WINDOW_UPDATE frame.
- rv = callback.WaitForResult();
- helper.VerifyDataConsumed();
-
- SpdySession::set_use_flow_control(SpdySession::kFlowControlBasedOnNPN);
-}
-
TEST_P(SpdyNetworkTransactionSpdy2Test, CancelledTransaction) {
// Construct the request.
scoped_ptr<spdy::SpdyFrame> req(ConstructSpdyGet(NULL, 0, false, 1, LOWEST));
diff --git a/net/spdy/spdy_session.cc b/net/spdy/spdy_session.cc
index c9b83d1..772c041 100644
--- a/net/spdy/spdy_session.cc
+++ b/net/spdy/spdy_session.cc
@@ -390,13 +390,11 @@ net::Error SpdySession::InitializeWithSocket(
reinterpret_cast<SSLClientSocket*>(connection_->socket());
DCHECK(ssl_socket);
- // For SPDY 2.1 and above versions, flow control is enabled by default and
- // for older versions, flow control is disabled by default. Unit tests can
- // either enable or disable flow_control_ by setting the use_flow_control_.
- if (ssl_socket->protocol_negotiated() >= SSLClientSocket::kProtoSPDY21)
- flow_control_ = (use_flow_control_ != SpdySession::kDisableFlowControl);
- else
- flow_control_ = (use_flow_control_ == SpdySession::kEnableFlowControl);
+ SSLClientSocket::NextProto protocol_negotiated =
+ ssl_socket->protocol_negotiated();
+ if (protocol_negotiated != SSLClientSocket::kProtoUnknown)
+ flow_control_ = (protocol_negotiated >= SSLClientSocket::kProtoSPDY21);
+
if (ssl_socket->WasOriginBoundCertSent()) {
// According to the SPDY spec, the credential associated with the TLS
// connection is stored in slot[0].