| Index: net/spdy/spdy_network_transaction_unittest.cc
|
| diff --git a/net/spdy/spdy_network_transaction_unittest.cc b/net/spdy/spdy_network_transaction_unittest.cc
|
| index 5bbabab7c9414f3ceb5868f5513a74245cd5b5af..a7fc72d6bde6515a2f7278482ac3fe56b40dfc26 100644
|
| --- a/net/spdy/spdy_network_transaction_unittest.cc
|
| +++ b/net/spdy/spdy_network_transaction_unittest.cc
|
| @@ -2,6 +2,7 @@
|
| // Use of this source code is governed by a BSD-style license that can be
|
| // found in the LICENSE file.
|
|
|
| +#include <cmath>
|
| #include <memory>
|
| #include <string>
|
| #include <utility>
|
| @@ -58,6 +59,8 @@ namespace {
|
| using testing::Each;
|
| using testing::Eq;
|
|
|
| +const int32_t kBufferSize = SpdyHttpStream::kRequestBodyBufferSize;
|
| +
|
| enum SpdyNetworkTransactionTestSSLType {
|
| // Request an https:// URL and use NPN (or ALPN) to negotiate SPDY during
|
| // the TLS handshake.
|
| @@ -6535,68 +6538,104 @@ TEST_P(SpdyNetworkTransactionTest, WindowUpdateOverflow) {
|
| TEST_P(SpdyNetworkTransactionTest, FlowControlStallResume) {
|
| const int32_t initial_window_size =
|
| SpdySession::GetDefaultInitialWindowSize(GetParam().protocol);
|
| - // 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 num_writes = initial_window_size / kMaxSpdyFrameChunkSize + 3;
|
| -
|
| - // Calculate last frame's size; 0 size data frame is legal.
|
| - size_t last_frame_size = initial_window_size % kMaxSpdyFrameChunkSize;
|
| + // Number of upload data buffers we need to send to zero out the window size
|
| + // is the minimal number of upload buffers takes to be bigger than
|
| + // |initial_window_size|.
|
| + size_t num_upload_buffers =
|
| + ceil(static_cast<double>(initial_window_size) / kBufferSize);
|
| + // Each upload data buffer consists of |num_frames_in_one_upload_buffer|
|
| + // frames, each with |kMaxSpdyFrameChunkSize| bytes except the last frame,
|
| + // which has kBufferSize % kMaxSpdyChunkSize bytes.
|
| + size_t num_frames_in_one_upload_buffer =
|
| + ceil(static_cast<double>(kBufferSize) / kMaxSpdyFrameChunkSize);
|
|
|
| // Construct content for a data frame of maximum size.
|
| std::string content(kMaxSpdyFrameChunkSize, 'a');
|
|
|
| std::unique_ptr<SpdySerializedFrame> req(spdy_util_.ConstructSpdyPost(
|
| - GetDefaultUrl(), 1, initial_window_size + kUploadDataSize, LOWEST, NULL,
|
| - 0));
|
| + GetDefaultUrl(), 1,
|
| + /*content_length=*/kBufferSize * num_upload_buffers + kUploadDataSize,
|
| + LOWEST, NULL, 0));
|
|
|
| // Full frames.
|
| std::unique_ptr<SpdySerializedFrame> body1(spdy_util_.ConstructSpdyBodyFrame(
|
| 1, content.c_str(), content.size(), false));
|
|
|
| - // Last frame to zero out the window size.
|
| + // Last frame in each upload data buffer.
|
| std::unique_ptr<SpdySerializedFrame> body2(spdy_util_.ConstructSpdyBodyFrame(
|
| - 1, content.c_str(), last_frame_size, false));
|
| + 1, content.c_str(), kBufferSize % kMaxSpdyFrameChunkSize, false));
|
|
|
| - // Data frame to be sent once WINDOW_UPDATE frame is received.
|
| - std::unique_ptr<SpdySerializedFrame> body3(
|
| + // The very last frame before the stalled frames.
|
| + std::unique_ptr<SpdySerializedFrame> body3(spdy_util_.ConstructSpdyBodyFrame(
|
| + 1, content.c_str(),
|
| + initial_window_size % kBufferSize % kMaxSpdyFrameChunkSize, false));
|
| +
|
| + // Data frames to be sent once WINDOW_UPDATE frame is received.
|
| +
|
| + // If kBufferSize * num_upload_buffers > initial_window_size,
|
| + // we need one additional frame to send the rest of 'a'.
|
| + std::string last_body(kBufferSize * num_upload_buffers - initial_window_size,
|
| + 'a');
|
| + std::unique_ptr<SpdySerializedFrame> body4(spdy_util_.ConstructSpdyBodyFrame(
|
| + 1, last_body.c_str(), last_body.size(), false));
|
| +
|
| + // Also send a "hello!" after WINDOW_UPDATE.
|
| + std::unique_ptr<SpdySerializedFrame> body5(
|
| spdy_util_.ConstructSpdyBodyFrame(1, true));
|
|
|
| // Fill in mock writes.
|
| - std::unique_ptr<MockWrite[]> writes(new MockWrite[num_writes]);
|
| size_t i = 0;
|
| - writes[i] = CreateMockWrite(*req, i);
|
| - for (i = 1; i < num_writes - 2; i++)
|
| - writes[i] = CreateMockWrite(*body1, i);
|
| - writes[i] = CreateMockWrite(*body2, i);
|
| - // The last write must not be attempted until after the WINDOW_UPDATES
|
| - // have been received.
|
| - writes[i + 1] = CreateMockWrite(*body3, i + 4, SYNCHRONOUS);
|
| -
|
| - // Construct read frame, give enough space to upload the rest of the
|
| - // data.
|
| + std::vector<MockWrite> writes;
|
| + writes.push_back(CreateMockWrite(*req, i++));
|
| + for (size_t j = 0; j < num_upload_buffers; j++) {
|
| + for (size_t k = 0; k < num_frames_in_one_upload_buffer; k++) {
|
| + if (k == num_frames_in_one_upload_buffer - 1 &&
|
| + kBufferSize % kMaxSpdyFrameChunkSize != 0) {
|
| + if (j == num_upload_buffers - 1 &&
|
| + (initial_window_size % kBufferSize != 0)) {
|
| + writes.push_back(CreateMockWrite(*body3, i++));
|
| + } else {
|
| + writes.push_back(CreateMockWrite(*body2, i++));
|
| + }
|
| + } else {
|
| + writes.push_back(CreateMockWrite(*body1, i++));
|
| + }
|
| + }
|
| + }
|
| +
|
| + // Fill in mock reads.
|
| + std::vector<MockRead> reads;
|
| + // Force a pause.
|
| + reads.push_back(MockRead(ASYNC, ERR_IO_PENDING, i++));
|
| + // Construct read frame for window updates that gives enough space to upload
|
| + // the rest of the data.
|
| std::unique_ptr<SpdySerializedFrame> session_window_update(
|
| - spdy_util_.ConstructSpdyWindowUpdate(0, kUploadDataSize));
|
| + spdy_util_.ConstructSpdyWindowUpdate(0,
|
| + kUploadDataSize + last_body.size()));
|
| std::unique_ptr<SpdySerializedFrame> window_update(
|
| - spdy_util_.ConstructSpdyWindowUpdate(1, kUploadDataSize));
|
| + spdy_util_.ConstructSpdyWindowUpdate(1,
|
| + kUploadDataSize + last_body.size()));
|
| +
|
| + reads.push_back(CreateMockRead(*session_window_update, i++));
|
| + reads.push_back(CreateMockRead(*window_update, i++));
|
| +
|
| + // Stalled frames which can be sent after receiving window updates.
|
| + if (last_body.size() > 0)
|
| + writes.push_back(CreateMockWrite(*body4, i++));
|
| + writes.push_back(CreateMockWrite(*body5, i++));
|
| +
|
| std::unique_ptr<SpdySerializedFrame> reply(
|
| spdy_util_.ConstructSpdyPostSynReply(NULL, 0));
|
| - MockRead reads[] = {
|
| - MockRead(ASYNC, ERR_IO_PENDING, i + 1), // Force a pause
|
| - CreateMockRead(*session_window_update, i + 2),
|
| - CreateMockRead(*window_update, i + 3),
|
| - // Now the last write will occur.
|
| - CreateMockRead(*reply, i + 5),
|
| - CreateMockRead(*body2, i + 6),
|
| - CreateMockRead(*body3, i + 7),
|
| - MockRead(ASYNC, 0, i + 8) // EOF
|
| - };
|
| + reads.push_back(CreateMockRead(*reply, i++));
|
| + reads.push_back(CreateMockRead(*body2, i++));
|
| + reads.push_back(CreateMockRead(*body5, i++));
|
| + reads.push_back(MockRead(ASYNC, 0, i++)); // EOF
|
|
|
| - SequencedSocketData data(reads, arraysize(reads), writes.get(), num_writes);
|
| + SequencedSocketData data(reads.data(), reads.size(), writes.data(),
|
| + writes.size());
|
|
|
| std::vector<std::unique_ptr<UploadElementReader>> element_readers;
|
| - std::string upload_data_string(initial_window_size, 'a');
|
| + std::string upload_data_string(kBufferSize * num_upload_buffers, 'a');
|
| upload_data_string.append(kUploadData, kUploadDataSize);
|
| element_readers.push_back(base::WrapUnique(new UploadBytesElementReader(
|
| upload_data_string.c_str(), upload_data_string.size())));
|
| @@ -6606,8 +6645,8 @@ TEST_P(SpdyNetworkTransactionTest, FlowControlStallResume) {
|
| request.method = "POST";
|
| request.url = GURL(GetDefaultUrl());
|
| request.upload_data_stream = &upload_data_stream;
|
| - NormalSpdyTransactionHelper helper(request, DEFAULT_PRIORITY,
|
| - BoundNetLog(), GetParam(), NULL);
|
| + NormalSpdyTransactionHelper helper(request, DEFAULT_PRIORITY, BoundNetLog(),
|
| + GetParam(), NULL);
|
| helper.AddData(&data);
|
| helper.RunPreTestSetup();
|
|
|
| @@ -6623,10 +6662,17 @@ TEST_P(SpdyNetworkTransactionTest, FlowControlStallResume) {
|
| 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(upload_data_stream.IsEOF());
|
| + if (initial_window_size % kBufferSize != 0) {
|
| + // If it does not take whole number of full upload buffer to zero out
|
| + // initial window size, then the upload data is not at EOF, because the
|
| + // last read must be stalled.
|
| + EXPECT_FALSE(upload_data_stream.IsEOF());
|
| + } else {
|
| + // 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(upload_data_stream.IsEOF());
|
| + }
|
| // But the body is not yet fully sent (kUploadData is not yet sent)
|
| // since we're send-stalled.
|
| EXPECT_TRUE(stream->stream()->send_stalled_by_flow_control());
|
| @@ -6641,43 +6687,74 @@ TEST_P(SpdyNetworkTransactionTest, FlowControlStallResume) {
|
| TEST_P(SpdyNetworkTransactionTest, FlowControlStallResumeAfterSettings) {
|
| const int32_t initial_window_size =
|
| SpdySession::GetDefaultInitialWindowSize(GetParam().protocol);
|
| -
|
| - // 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 SETTING is received, therefore +3.
|
| - size_t num_writes = initial_window_size / kMaxSpdyFrameChunkSize + 3;
|
| -
|
| - // Calculate last frame's size; 0 size data frame is legal.
|
| - size_t last_frame_size = initial_window_size % kMaxSpdyFrameChunkSize;
|
| + // Number of upload data buffers we need to send to zero out the window size
|
| + // is the minimal number of upload buffers takes to be bigger than
|
| + // |initial_window_size|.
|
| + size_t num_upload_buffers =
|
| + ceil(static_cast<double>(initial_window_size) / kBufferSize);
|
| + // Each upload data buffer consists of |num_frames_in_one_upload_buffer|
|
| + // frames, each with |kMaxSpdyFrameChunkSize| bytes except the last frame,
|
| + // which has kBufferSize % kMaxSpdyChunkSize bytes.
|
| + size_t num_frames_in_one_upload_buffer =
|
| + ceil(static_cast<double>(kBufferSize) / kMaxSpdyFrameChunkSize);
|
|
|
| // Construct content for a data frame of maximum size.
|
| std::string content(kMaxSpdyFrameChunkSize, 'a');
|
|
|
| std::unique_ptr<SpdySerializedFrame> req(spdy_util_.ConstructSpdyPost(
|
| - GetDefaultUrl(), 1, initial_window_size + kUploadDataSize, LOWEST, NULL,
|
| - 0));
|
| + GetDefaultUrl(), 1,
|
| + /*content_length=*/kBufferSize * num_upload_buffers + kUploadDataSize,
|
| + LOWEST, NULL, 0));
|
|
|
| // Full frames.
|
| std::unique_ptr<SpdySerializedFrame> body1(spdy_util_.ConstructSpdyBodyFrame(
|
| 1, content.c_str(), content.size(), false));
|
|
|
| - // Last frame to zero out the window size.
|
| + // Last frame in each upload data buffer.
|
| std::unique_ptr<SpdySerializedFrame> body2(spdy_util_.ConstructSpdyBodyFrame(
|
| - 1, content.c_str(), last_frame_size, false));
|
| + 1, content.c_str(), kBufferSize % kMaxSpdyFrameChunkSize, false));
|
|
|
| - // Data frame to be sent once SETTINGS frame is received.
|
| - std::unique_ptr<SpdySerializedFrame> body3(
|
| + // The very last frame before the stalled frames.
|
| + std::unique_ptr<SpdySerializedFrame> body3(spdy_util_.ConstructSpdyBodyFrame(
|
| + 1, content.c_str(),
|
| + initial_window_size % kBufferSize % kMaxSpdyFrameChunkSize, false));
|
| +
|
| + // Data frames to be sent once WINDOW_UPDATE frame is received.
|
| +
|
| + // If kBufferSize * num_upload_buffers > initial_window_size,
|
| + // we need one additional frame to send the rest of 'a'.
|
| + std::string last_body(kBufferSize * num_upload_buffers - initial_window_size,
|
| + 'a');
|
| + std::unique_ptr<SpdySerializedFrame> body4(spdy_util_.ConstructSpdyBodyFrame(
|
| + 1, last_body.c_str(), last_body.size(), false));
|
| +
|
| + // Also send a "hello!" after WINDOW_UPDATE.
|
| + std::unique_ptr<SpdySerializedFrame> body5(
|
| spdy_util_.ConstructSpdyBodyFrame(1, true));
|
|
|
| - // Fill in mock reads/writes.
|
| - std::vector<MockRead> reads;
|
| - std::vector<MockWrite> writes;
|
| + // Fill in mock writes.
|
| size_t i = 0;
|
| + std::vector<MockWrite> writes;
|
| writes.push_back(CreateMockWrite(*req, i++));
|
| - while (i < num_writes - 2)
|
| - writes.push_back(CreateMockWrite(*body1, i++));
|
| - writes.push_back(CreateMockWrite(*body2, i++));
|
| + for (size_t j = 0; j < num_upload_buffers; j++) {
|
| + for (size_t k = 0; k < num_frames_in_one_upload_buffer; k++) {
|
| + if (k == num_frames_in_one_upload_buffer - 1 &&
|
| + kBufferSize % kMaxSpdyFrameChunkSize != 0) {
|
| + if (j == num_upload_buffers - 1 &&
|
| + (initial_window_size % kBufferSize != 0)) {
|
| + writes.push_back(CreateMockWrite(*body3, i++));
|
| + } else {
|
| + writes.push_back(CreateMockWrite(*body2, i++));
|
| + }
|
| + } else {
|
| + writes.push_back(CreateMockWrite(*body1, i++));
|
| + }
|
| + }
|
| + }
|
|
|
| + // Fill in mock reads.
|
| + std::vector<MockRead> reads;
|
| + // Force a pause.
|
| reads.push_back(MockRead(ASYNC, ERR_IO_PENDING, i++));
|
|
|
| // Construct read frame for SETTINGS that gives enough space to upload the
|
| @@ -6691,20 +6768,24 @@ TEST_P(SpdyNetworkTransactionTest, FlowControlStallResumeAfterSettings) {
|
| reads.push_back(CreateMockRead(*settings_frame_large, i++));
|
|
|
| std::unique_ptr<SpdySerializedFrame> session_window_update(
|
| - spdy_util_.ConstructSpdyWindowUpdate(0, kUploadDataSize));
|
| + spdy_util_.ConstructSpdyWindowUpdate(0,
|
| + last_body.size() + kUploadDataSize));
|
| reads.push_back(CreateMockRead(*session_window_update, i++));
|
|
|
| std::unique_ptr<SpdySerializedFrame> settings_ack(
|
| spdy_util_.ConstructSpdySettingsAck());
|
| writes.push_back(CreateMockWrite(*settings_ack, i++));
|
|
|
| - writes.push_back(CreateMockWrite(*body3, i++));
|
| + // Stalled frames which can be sent after |settings_ack|.
|
| + if (last_body.size() > 0)
|
| + writes.push_back(CreateMockWrite(*body4, i++));
|
| + writes.push_back(CreateMockWrite(*body5, i++));
|
|
|
| std::unique_ptr<SpdySerializedFrame> reply(
|
| spdy_util_.ConstructSpdyPostSynReply(NULL, 0));
|
| reads.push_back(CreateMockRead(*reply, i++));
|
| reads.push_back(CreateMockRead(*body2, i++));
|
| - reads.push_back(CreateMockRead(*body3, i++));
|
| + reads.push_back(CreateMockRead(*body5, i++));
|
| reads.push_back(MockRead(ASYNC, 0, i++)); // EOF
|
|
|
| // Force all writes to happen before any read, last write will not
|
| @@ -6713,7 +6794,7 @@ TEST_P(SpdyNetworkTransactionTest, FlowControlStallResumeAfterSettings) {
|
| writes.size());
|
|
|
| std::vector<std::unique_ptr<UploadElementReader>> element_readers;
|
| - std::string upload_data_string(initial_window_size, 'a');
|
| + std::string upload_data_string(kBufferSize * num_upload_buffers, 'a');
|
| upload_data_string.append(kUploadData, kUploadDataSize);
|
| element_readers.push_back(base::WrapUnique(new UploadBytesElementReader(
|
| upload_data_string.c_str(), upload_data_string.size())));
|
| @@ -6742,10 +6823,17 @@ TEST_P(SpdyNetworkTransactionTest, FlowControlStallResumeAfterSettings) {
|
| 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(upload_data_stream.IsEOF());
|
| + if (initial_window_size % kBufferSize != 0) {
|
| + // If it does not take whole number of full upload buffer to zero out
|
| + // initial window size, then the upload data is not at EOF, because the
|
| + // last read must be stalled.
|
| + EXPECT_FALSE(upload_data_stream.IsEOF());
|
| + } else {
|
| + // 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(upload_data_stream.IsEOF());
|
| + }
|
| // But the body is not yet fully sent (kUploadData is not yet sent)
|
| // since we're send-stalled.
|
| EXPECT_TRUE(stream->stream()->send_stalled_by_flow_control());
|
| @@ -6765,44 +6853,75 @@ TEST_P(SpdyNetworkTransactionTest, FlowControlStallResumeAfterSettings) {
|
| TEST_P(SpdyNetworkTransactionTest, FlowControlNegativeSendWindowSize) {
|
| const int32_t initial_window_size =
|
| SpdySession::GetDefaultInitialWindowSize(GetParam().protocol);
|
| - // 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 SETTING is received, therefore +3.
|
| - size_t num_writes = initial_window_size / kMaxSpdyFrameChunkSize + 3;
|
| -
|
| - // Calculate last frame's size; 0 size data frame is legal.
|
| - size_t last_frame_size = initial_window_size % kMaxSpdyFrameChunkSize;
|
| + // Number of upload data buffers we need to send to zero out the window size
|
| + // is the minimal number of upload buffers takes to be bigger than
|
| + // |initial_window_size|.
|
| + size_t num_upload_buffers =
|
| + ceil(static_cast<double>(initial_window_size) / kBufferSize);
|
| + // Each upload data buffer consists of |num_frames_in_one_upload_buffer|
|
| + // frames, each with |kMaxSpdyFrameChunkSize| bytes except the last frame,
|
| + // which has kBufferSize % kMaxSpdyChunkSize bytes.
|
| + size_t num_frames_in_one_upload_buffer =
|
| + ceil(static_cast<double>(kBufferSize) / kMaxSpdyFrameChunkSize);
|
|
|
| // Construct content for a data frame of maximum size.
|
| std::string content(kMaxSpdyFrameChunkSize, 'a');
|
|
|
| std::unique_ptr<SpdySerializedFrame> req(spdy_util_.ConstructSpdyPost(
|
| - GetDefaultUrl(), 1, initial_window_size + kUploadDataSize, LOWEST, NULL,
|
| - 0));
|
| + GetDefaultUrl(), 1,
|
| + /*content_length=*/kBufferSize * num_upload_buffers + kUploadDataSize,
|
| + LOWEST, NULL, 0));
|
|
|
| // Full frames.
|
| std::unique_ptr<SpdySerializedFrame> body1(spdy_util_.ConstructSpdyBodyFrame(
|
| 1, content.c_str(), content.size(), false));
|
|
|
| - // Last frame to zero out the window size.
|
| + // Last frame in each upload data buffer.
|
| std::unique_ptr<SpdySerializedFrame> body2(spdy_util_.ConstructSpdyBodyFrame(
|
| - 1, content.c_str(), last_frame_size, false));
|
| + 1, content.c_str(), kBufferSize % kMaxSpdyFrameChunkSize, false));
|
|
|
| - // Data frame to be sent once SETTINGS frame is received.
|
| - std::unique_ptr<SpdySerializedFrame> body3(
|
| + // The very last frame before the stalled frames.
|
| + std::unique_ptr<SpdySerializedFrame> body3(spdy_util_.ConstructSpdyBodyFrame(
|
| + 1, content.c_str(),
|
| + initial_window_size % kBufferSize % kMaxSpdyFrameChunkSize, false));
|
| +
|
| + // Data frames to be sent once WINDOW_UPDATE frame is received.
|
| +
|
| + // If kBufferSize * num_upload_buffers > initial_window_size,
|
| + // we need one additional frame to send the rest of 'a'.
|
| + std::string last_body(kBufferSize * num_upload_buffers - initial_window_size,
|
| + 'a');
|
| + std::unique_ptr<SpdySerializedFrame> body4(spdy_util_.ConstructSpdyBodyFrame(
|
| + 1, last_body.c_str(), last_body.size(), false));
|
| +
|
| + // Also send a "hello!" after WINDOW_UPDATE.
|
| + std::unique_ptr<SpdySerializedFrame> body5(
|
| spdy_util_.ConstructSpdyBodyFrame(1, true));
|
|
|
| - // Fill in mock reads/writes.
|
| - std::vector<MockRead> reads;
|
| - std::vector<MockWrite> writes;
|
| + // Fill in mock writes.
|
| size_t i = 0;
|
| + std::vector<MockWrite> writes;
|
| writes.push_back(CreateMockWrite(*req, i++));
|
| - while (i < num_writes - 2)
|
| - writes.push_back(CreateMockWrite(*body1, i++));
|
| - writes.push_back(CreateMockWrite(*body2, i++));
|
| + for (size_t j = 0; j < num_upload_buffers; j++) {
|
| + for (size_t k = 0; k < num_frames_in_one_upload_buffer; k++) {
|
| + if (k == num_frames_in_one_upload_buffer - 1 &&
|
| + kBufferSize % kMaxSpdyFrameChunkSize != 0) {
|
| + if (j == num_upload_buffers - 1 &&
|
| + (initial_window_size % kBufferSize != 0)) {
|
| + writes.push_back(CreateMockWrite(*body3, i++));
|
| + } else {
|
| + writes.push_back(CreateMockWrite(*body2, i++));
|
| + }
|
| + } else {
|
| + writes.push_back(CreateMockWrite(*body1, i++));
|
| + }
|
| + }
|
| + }
|
|
|
| + // Fill in mock reads.
|
| + std::vector<MockRead> reads;
|
| + // Force a pause.
|
| reads.push_back(MockRead(ASYNC, ERR_IO_PENDING, i++));
|
| -
|
| // Construct read frame for SETTINGS that makes the send_window_size
|
| // negative.
|
| SettingsMap new_settings;
|
| @@ -6825,13 +6944,16 @@ TEST_P(SpdyNetworkTransactionTest, FlowControlNegativeSendWindowSize) {
|
| spdy_util_.ConstructSpdySettingsAck());
|
| writes.push_back(CreateMockWrite(*settings_ack, i++));
|
|
|
| - writes.push_back(CreateMockWrite(*body3, i++));
|
| + // Stalled frames which can be sent after |settings_ack|.
|
| + if (last_body.size() > 0)
|
| + writes.push_back(CreateMockWrite(*body4, i++));
|
| + writes.push_back(CreateMockWrite(*body5, i++));
|
|
|
| std::unique_ptr<SpdySerializedFrame> reply(
|
| spdy_util_.ConstructSpdyPostSynReply(NULL, 0));
|
| reads.push_back(CreateMockRead(*reply, i++));
|
| reads.push_back(CreateMockRead(*body2, i++));
|
| - reads.push_back(CreateMockRead(*body3, i++));
|
| + reads.push_back(CreateMockRead(*body5, i++));
|
| reads.push_back(MockRead(ASYNC, 0, i++)); // EOF
|
|
|
| // Force all writes to happen before any read, last write will not
|
| @@ -6840,7 +6962,7 @@ TEST_P(SpdyNetworkTransactionTest, FlowControlNegativeSendWindowSize) {
|
| writes.size());
|
|
|
| std::vector<std::unique_ptr<UploadElementReader>> element_readers;
|
| - std::string upload_data_string(initial_window_size, 'a');
|
| + std::string upload_data_string(kBufferSize * num_upload_buffers, 'a');
|
| upload_data_string.append(kUploadData, kUploadDataSize);
|
| element_readers.push_back(base::WrapUnique(new UploadBytesElementReader(
|
| upload_data_string.c_str(), upload_data_string.size())));
|
| @@ -6869,13 +6991,17 @@ TEST_P(SpdyNetworkTransactionTest, FlowControlNegativeSendWindowSize) {
|
| 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(upload_data_stream.IsEOF());
|
| - // But the body is not yet fully sent (kUploadData is not yet sent)
|
| - // since we're send-stalled.
|
| - EXPECT_TRUE(stream->stream()->send_stalled_by_flow_control());
|
| + if (initial_window_size % kBufferSize != 0) {
|
| + // If it does not take whole number of full upload buffer to zero out
|
| + // initial window size, then the upload data is not at EOF, because the
|
| + // last read must be stalled.
|
| + EXPECT_FALSE(upload_data_stream.IsEOF());
|
| + } else {
|
| + // 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(upload_data_stream.IsEOF());
|
| + }
|
|
|
| // Read in WINDOW_UPDATE or SETTINGS frame.
|
| data.Resume();
|
|
|