Index: net/quic/bidirectional_stream_quic_impl_unittest.cc |
diff --git a/net/quic/bidirectional_stream_quic_impl_unittest.cc b/net/quic/bidirectional_stream_quic_impl_unittest.cc |
index 4f75ba31819b4e559fe1821e3b48085166c9928c..7110a7e4371b71f03a1eee8bed257bec5ddc4184 100644 |
--- a/net/quic/bidirectional_stream_quic_impl_unittest.cc |
+++ b/net/quic/bidirectional_stream_quic_impl_unittest.cc |
@@ -74,13 +74,14 @@ class TestDelegateBase : public BidirectionalStreamImpl::Delegate { |
error_(OK), |
on_data_read_count_(0), |
on_data_sent_count_(0), |
- not_expect_callback_(false) { |
+ not_expect_callback_(false), |
+ disable_auto_flush_(false) { |
loop_.reset(new base::RunLoop); |
} |
~TestDelegateBase() override {} |
- void OnHeadersSent() override { |
+ void OnStreamReady() override { |
CHECK(!not_expect_callback_); |
loop_->Quit(); |
} |
@@ -129,7 +130,8 @@ class TestDelegateBase : public BidirectionalStreamImpl::Delegate { |
const BoundNetLog& net_log, |
const base::WeakPtr<QuicChromiumClientSession> session) { |
stream_job_.reset(new BidirectionalStreamQuicImpl(session)); |
- stream_job_->Start(request_info, net_log, this, nullptr); |
+ stream_job_->Start(request_info, net_log, disable_auto_flush_, this, |
+ nullptr); |
} |
void SendData(IOBuffer* data, int length, bool end_of_stream) { |
@@ -138,6 +140,14 @@ class TestDelegateBase : public BidirectionalStreamImpl::Delegate { |
not_expect_callback_ = false; |
} |
+ void SendvData(const std::vector<IOBuffer*>& data, |
+ const std::vector<int>& lengths, |
+ bool end_of_stream) { |
+ not_expect_callback_ = true; |
+ stream_job_->SendvData(data, lengths, end_of_stream); |
+ not_expect_callback_ = false; |
+ } |
+ |
// Waits until next Delegate callback. |
void WaitUntilNextCallback() { |
loop_->Run(); |
@@ -167,6 +177,8 @@ class TestDelegateBase : public BidirectionalStreamImpl::Delegate { |
int64_t GetTotalSentBytes() const { return stream_job_->GetTotalSentBytes(); } |
+ void DisableAutoFlush() { disable_auto_flush_ = true; } |
+ |
// Const getters for internal states. |
const std::string& data_received() const { return data_received_; } |
int error() const { return error_; } |
@@ -198,6 +210,7 @@ class TestDelegateBase : public BidirectionalStreamImpl::Delegate { |
// calling into |stream_|. |
bool not_expect_callback_; |
CompletionCallback callback_; |
+ bool disable_auto_flush_; |
DISALLOW_COPY_AND_ASSIGN(TestDelegateBase); |
}; |
@@ -377,6 +390,21 @@ class BidirectionalStreamQuicImplTest |
<< QuicUtils::StringToHexASCIIDump(packet->AsStringPiece()); |
return packet; |
} |
+ // Construct a data packet with multiple data frames |
+ std::unique_ptr<QuicReceivedPacket> ConstructMultipleDataFramesPacket( |
+ QuicPacketNumber packet_number, |
+ bool should_include_version, |
+ bool fin, |
+ QuicStreamOffset offset, |
+ const std::vector<std::string>& data_writes) { |
+ std::unique_ptr<QuicReceivedPacket> packet( |
+ maker_.MakeMultipleDataFramesPacket(packet_number, stream_id_, |
+ should_include_version, fin, offset, |
+ data_writes)); |
+ DVLOG(2) << "packet(" << packet_number << "): " << std::endl |
+ << QuicUtils::StringToHexASCIIDump(packet->AsStringPiece()); |
+ return packet; |
+ } |
std::unique_ptr<QuicReceivedPacket> ConstructRequestHeadersPacket( |
QuicPacketNumber packet_number, |
@@ -390,6 +418,24 @@ class BidirectionalStreamQuicImplTest |
request_headers_, spdy_headers_frame_length); |
} |
+ std::unique_ptr<QuicReceivedPacket> |
+ ConstructRequestHeadersAndMultipleDataFramesPacket( |
+ QuicPacketNumber packet_number, |
+ bool fin, |
+ RequestPriority request_priority, |
+ size_t* spdy_headers_frame_length, |
+ const std::vector<std::string>& data) { |
+ SpdyPriority priority = |
+ ConvertRequestPriorityToQuicPriority(request_priority); |
+ std::unique_ptr<QuicReceivedPacket> packet( |
+ maker_.MakeRequestHeadersAndMultipleDataFramesPacket( |
+ packet_number, stream_id_, kIncludeVersion, fin, priority, |
+ request_headers_, spdy_headers_frame_length, data)); |
+ DVLOG(2) << "packet(" << packet_number << "): " << std::endl |
+ << QuicUtils::StringToHexASCIIDump(packet->AsStringPiece()); |
+ return packet; |
+ } |
+ |
std::unique_ptr<QuicReceivedPacket> ConstructResponseHeadersPacket( |
QuicPacketNumber packet_number, |
bool fin, |
@@ -517,7 +563,7 @@ TEST_P(BidirectionalStreamQuicImplTest, GetRequest) { |
std::unique_ptr<TestDelegateBase> delegate( |
new TestDelegateBase(read_buffer.get(), kReadBufferSize)); |
delegate->Start(&request, net_log().bound(), session()->GetWeakPtr()); |
- delegate->WaitUntilNextCallback(); // OnHeadersSent |
+ delegate->WaitUntilNextCallback(); // OnStreamReady |
// Server acks the request. |
ProcessPacket(ConstructAckPacket(1, 0, 0)); |
@@ -588,6 +634,108 @@ TEST_P(BidirectionalStreamQuicImplTest, GetRequest) { |
NetLog::PHASE_NONE); |
} |
+TEST_P(BidirectionalStreamQuicImplTest, CoalesceSmallBuffers) { |
+ SetRequest("POST", "/", DEFAULT_PRIORITY); |
+ size_t spdy_request_headers_frame_length; |
+ |
+ const char kBody1[] = "here are some data"; |
+ const char kBody2[] = "data keep coming"; |
+ std::vector<std::string> two_writes = {kBody1, kBody2}; |
+ AddWrite(ConstructRequestHeadersAndMultipleDataFramesPacket( |
+ 1, !kFin, DEFAULT_PRIORITY, &spdy_request_headers_frame_length, |
+ two_writes)); |
+ // Ack server's data packet. |
+ AddWrite(ConstructAckPacket(2, 3, 1)); |
+ const char kBody3[] = "hello there"; |
+ const char kBody4[] = "another piece of small data"; |
+ const char kBody5[] = "really small"; |
+ QuicStreamOffset data_offset = strlen(kBody1) + strlen(kBody2); |
+ AddWrite(ConstructMultipleDataFramesPacket( |
+ 3, !kIncludeVersion, kFin, data_offset, {kBody3, kBody4, kBody5})); |
+ |
+ Initialize(); |
+ |
+ BidirectionalStreamRequestInfo request; |
+ request.method = "POST"; |
+ request.url = GURL("http://www.google.com/"); |
+ request.end_stream_on_headers = false; |
+ request.priority = DEFAULT_PRIORITY; |
+ |
+ scoped_refptr<IOBuffer> read_buffer(new IOBuffer(kReadBufferSize)); |
+ std::unique_ptr<TestDelegateBase> delegate( |
+ new TestDelegateBase(read_buffer.get(), kReadBufferSize)); |
+ delegate->DisableAutoFlush(); |
+ delegate->Start(&request, net_log().bound(), session()->GetWeakPtr()); |
+ delegate->WaitUntilNextCallback(); // OnStreamReady |
+ |
+ // Send a Data packet. |
+ scoped_refptr<StringIOBuffer> buf1(new StringIOBuffer(kBody1)); |
+ scoped_refptr<StringIOBuffer> buf2(new StringIOBuffer(kBody2)); |
+ |
+ std::vector<IOBuffer*> buffers = {buf1.get(), buf2.get()}; |
+ std::vector<int> lengths = {buf1->size(), buf2->size()}; |
+ delegate->SendvData(buffers, lengths, !kFin); |
+ delegate->WaitUntilNextCallback(); // OnDataSent |
+ |
+ // Server acks the request. |
+ ProcessPacket(ConstructAckPacket(1, 0, 0)); |
+ |
+ // Server sends the response headers. |
+ SpdyHeaderBlock response_headers = ConstructResponseHeaders("200"); |
+ size_t spdy_response_headers_frame_length; |
+ QuicStreamOffset offset = 0; |
+ ProcessPacket(ConstructResponseHeadersPacket( |
+ 2, !kFin, response_headers, &spdy_response_headers_frame_length, |
+ &offset)); |
+ |
+ delegate->WaitUntilNextCallback(); // OnHeadersReceived |
+ TestCompletionCallback cb; |
+ int rv = delegate->ReadData(cb.callback()); |
+ EXPECT_EQ(ERR_IO_PENDING, rv); |
+ EXPECT_EQ("200", delegate->response_headers().find(":status")->second); |
+ const char kResponseBody[] = "Hello world!"; |
+ // Server sends data. |
+ ProcessPacket( |
+ ConstructDataPacket(3, !kIncludeVersion, !kFin, 0, kResponseBody)); |
+ |
+ EXPECT_EQ(static_cast<int>(strlen(kResponseBody)), cb.WaitForResult()); |
+ |
+ // Send a second Data packet. |
+ scoped_refptr<StringIOBuffer> buf3(new StringIOBuffer(kBody3)); |
+ scoped_refptr<StringIOBuffer> buf4(new StringIOBuffer(kBody4)); |
+ scoped_refptr<StringIOBuffer> buf5(new StringIOBuffer(kBody5)); |
+ |
+ delegate->SendvData({buf3.get(), buf4.get(), buf5.get()}, |
+ {buf3->size(), buf4->size(), buf5->size()}, kFin); |
+ delegate->WaitUntilNextCallback(); // OnDataSent |
+ |
+ size_t spdy_trailers_frame_length; |
+ SpdyHeaderBlock trailers; |
+ trailers["foo"] = "bar"; |
+ trailers[kFinalOffsetHeaderKey] = base::IntToString(strlen(kResponseBody)); |
+ // Server sends trailers. |
+ ProcessPacket(ConstructResponseTrailersPacket( |
+ 4, kFin, trailers, &spdy_trailers_frame_length, &offset)); |
+ |
+ delegate->WaitUntilNextCallback(); // OnTrailersReceived |
+ trailers.erase(kFinalOffsetHeaderKey); |
+ EXPECT_EQ(trailers, delegate->trailers()); |
+ EXPECT_EQ(OK, delegate->ReadData(cb.callback())); |
+ |
+ EXPECT_EQ(1, delegate->on_data_read_count()); |
+ EXPECT_EQ(2, delegate->on_data_sent_count()); |
+ EXPECT_EQ(kProtoQUIC1SPDY3, delegate->GetProtocol()); |
+ EXPECT_EQ( |
+ static_cast<int64_t>(spdy_request_headers_frame_length + strlen(kBody1) + |
+ strlen(kBody2) + strlen(kBody3) + strlen(kBody4) + |
+ strlen(kBody5)), |
+ delegate->GetTotalSentBytes()); |
+ EXPECT_EQ( |
+ static_cast<int64_t>(spdy_response_headers_frame_length + |
+ strlen(kResponseBody) + spdy_trailers_frame_length), |
+ delegate->GetTotalReceivedBytes()); |
+} |
+ |
TEST_P(BidirectionalStreamQuicImplTest, PostRequest) { |
SetRequest("POST", "/", DEFAULT_PRIORITY); |
size_t spdy_request_headers_frame_length; |
@@ -608,7 +756,7 @@ TEST_P(BidirectionalStreamQuicImplTest, PostRequest) { |
std::unique_ptr<TestDelegateBase> delegate( |
new TestDelegateBase(read_buffer.get(), kReadBufferSize)); |
delegate->Start(&request, net_log().bound(), session()->GetWeakPtr()); |
- delegate->WaitUntilNextCallback(); // OnHeadersSent |
+ delegate->WaitUntilNextCallback(); // OnStreamReady |
// Send a DATA frame. |
scoped_refptr<StringIOBuffer> buf(new StringIOBuffer(kUploadData)); |
@@ -685,7 +833,7 @@ TEST_P(BidirectionalStreamQuicImplTest, InterleaveReadDataAndSendData) { |
std::unique_ptr<TestDelegateBase> delegate( |
new TestDelegateBase(read_buffer.get(), kReadBufferSize)); |
delegate->Start(&request, net_log().bound(), session()->GetWeakPtr()); |
- delegate->WaitUntilNextCallback(); // OnHeadersSent |
+ delegate->WaitUntilNextCallback(); // OnStreamReady |
// Server acks the request. |
ProcessPacket(ConstructAckPacket(1, 0, 0)); |
@@ -762,7 +910,7 @@ TEST_P(BidirectionalStreamQuicImplTest, ServerSendsRstAfterHeaders) { |
std::unique_ptr<TestDelegateBase> delegate( |
new TestDelegateBase(read_buffer.get(), kReadBufferSize)); |
delegate->Start(&request, net_log().bound(), session()->GetWeakPtr()); |
- delegate->WaitUntilNextCallback(); // OnHeadersSent |
+ delegate->WaitUntilNextCallback(); // OnStreamReady |
// Server sends a Rst. |
ProcessPacket(ConstructRstStreamPacket(1)); |
@@ -801,7 +949,7 @@ TEST_P(BidirectionalStreamQuicImplTest, ServerSendsRstAfterReadData) { |
std::unique_ptr<TestDelegateBase> delegate( |
new TestDelegateBase(read_buffer.get(), kReadBufferSize)); |
delegate->Start(&request, net_log().bound(), session()->GetWeakPtr()); |
- delegate->WaitUntilNextCallback(); // OnHeadersSent |
+ delegate->WaitUntilNextCallback(); // OnStreamReady |
// Server acks the request. |
ProcessPacket(ConstructAckPacket(1, 0, 0)); |
@@ -858,7 +1006,7 @@ TEST_P(BidirectionalStreamQuicImplTest, CancelStreamAfterSendData) { |
std::unique_ptr<TestDelegateBase> delegate( |
new TestDelegateBase(read_buffer.get(), kReadBufferSize)); |
delegate->Start(&request, net_log().bound(), session()->GetWeakPtr()); |
- delegate->WaitUntilNextCallback(); // OnHeadersSent |
+ delegate->WaitUntilNextCallback(); // OnStreamReady |
// Server acks the request. |
ProcessPacket(ConstructAckPacket(1, 0, 0)); |
@@ -908,7 +1056,7 @@ TEST_P(BidirectionalStreamQuicImplTest, SessionClosedBeforeReadData) { |
std::unique_ptr<TestDelegateBase> delegate( |
new TestDelegateBase(read_buffer.get(), kReadBufferSize)); |
delegate->Start(&request, net_log().bound(), session()->GetWeakPtr()); |
- delegate->WaitUntilNextCallback(); // OnHeadersSent |
+ delegate->WaitUntilNextCallback(); // OnStreamReady |
// Server acks the request. |
ProcessPacket(ConstructAckPacket(1, 0, 0)); |
@@ -962,7 +1110,7 @@ TEST_P(BidirectionalStreamQuicImplTest, CancelStreamAfterReadData) { |
std::unique_ptr<TestDelegateBase> delegate( |
new TestDelegateBase(read_buffer.get(), kReadBufferSize)); |
delegate->Start(&request, net_log().bound(), session()->GetWeakPtr()); |
- delegate->WaitUntilNextCallback(); // OnHeadersSent |
+ delegate->WaitUntilNextCallback(); // OnStreamReady |
// Server acks the request. |
ProcessPacket(ConstructAckPacket(1, 0, 0)); |
@@ -1012,7 +1160,7 @@ TEST_P(BidirectionalStreamQuicImplTest, DeleteStreamDuringOnHeadersReceived) { |
read_buffer.get(), kReadBufferSize, |
DeleteStreamDelegate::ON_HEADERS_RECEIVED, true)); |
delegate->Start(&request, net_log().bound(), session()->GetWeakPtr()); |
- delegate->WaitUntilNextCallback(); // OnHeadersSent |
+ delegate->WaitUntilNextCallback(); // OnStreamReady |
// Server acks the request. |
ProcessPacket(ConstructAckPacket(1, 0, 0)); |
@@ -1055,7 +1203,7 @@ TEST_P(BidirectionalStreamQuicImplTest, DeleteStreamDuringOnDataRead) { |
new DeleteStreamDelegate(read_buffer.get(), kReadBufferSize, |
DeleteStreamDelegate::ON_DATA_READ, true)); |
delegate->Start(&request, net_log().bound(), session()->GetWeakPtr()); |
- delegate->WaitUntilNextCallback(); // OnHeadersSent |
+ delegate->WaitUntilNextCallback(); // OnStreamReady |
// Server acks the request. |
ProcessPacket(ConstructAckPacket(1, 0, 0)); |
@@ -1107,7 +1255,7 @@ TEST_P(BidirectionalStreamQuicImplTest, DeleteStreamDuringOnTrailersReceived) { |
read_buffer.get(), kReadBufferSize, |
DeleteStreamDelegate::ON_TRAILERS_RECEIVED, true)); |
delegate->Start(&request, net_log().bound(), session()->GetWeakPtr()); |
- delegate->WaitUntilNextCallback(); // OnHeadersSent |
+ delegate->WaitUntilNextCallback(); // OnStreamReady |
// Server acks the request. |
ProcessPacket(ConstructAckPacket(1, 0, 0)); |