Index: net/spdy/spdy_stream_unittest.cc |
diff --git a/net/spdy/spdy_stream_unittest.cc b/net/spdy/spdy_stream_unittest.cc |
index b87634f5c2ce26ad87b585c253e6824b8302e8f0..af606b37c8ce3af2ee8bb583eeb49420720c7fd6 100644 |
--- a/net/spdy/spdy_stream_unittest.cc |
+++ b/net/spdy/spdy_stream_unittest.cc |
@@ -175,6 +175,92 @@ TEST_P(SpdyStreamTest, SendDataAfterOpen) { |
EXPECT_TRUE(data.AllWriteDataConsumed()); |
} |
+// Delegate that receives trailers. |
+class StreamDelegateWithTrailers : public test::StreamDelegateWithBody { |
+ public: |
+ StreamDelegateWithTrailers(const base::WeakPtr<SpdyStream>& stream, |
+ base::StringPiece data) |
+ : StreamDelegateWithBody(stream, data) {} |
+ |
+ ~StreamDelegateWithTrailers() override {} |
+ |
+ void OnTrailers(const SpdyHeaderBlock& trailers) override { |
+ trailers_ = trailers; |
+ } |
+ |
+ const SpdyHeaderBlock& trailers() const { return trailers_; } |
+ |
+ private: |
+ SpdyHeaderBlock trailers_; |
+}; |
+ |
+// Regression test for crbug.com/481033. |
+TEST_P(SpdyStreamTest, Trailers) { |
+ GURL url(kStreamUrl); |
+ |
+ session_ = |
+ SpdySessionDependencies::SpdyCreateSessionDeterministic(&session_deps_); |
+ |
+ scoped_ptr<SpdyFrame> req(spdy_util_.ConstructSpdyPost( |
+ kStreamUrl, 1, kPostBodyLength, LOWEST, NULL, 0)); |
+ AddWrite(*req); |
+ |
+ scoped_ptr<SpdyFrame> msg( |
+ spdy_util_.ConstructSpdyBodyFrame(1, kPostBody, kPostBodyLength, true)); |
+ AddWrite(*msg); |
+ |
+ scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyPostSynReply(NULL, 0)); |
+ AddRead(*resp); |
+ |
+ scoped_ptr<SpdyFrame> echo( |
+ spdy_util_.ConstructSpdyBodyFrame(1, kPostBody, kPostBodyLength, false)); |
+ AddRead(*echo); |
+ |
+ const char* const kExtraHeaders[] = {"foo", "bar"}; |
+ scoped_ptr<SpdyFrame> trailers( |
+ spdy_util_.ConstructSpdyHeaderFrame(1, kExtraHeaders, 1)); |
+ AddRead(*trailers); |
+ |
+ AddReadEOF(); |
+ |
+ DeterministicSocketData data(GetReads(), GetNumReads(), GetWrites(), |
+ GetNumWrites()); |
+ MockConnect connect_data(SYNCHRONOUS, OK); |
+ data.set_connect_data(connect_data); |
+ |
+ session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data); |
+ |
+ base::WeakPtr<SpdySession> session(CreateDefaultSpdySession()); |
+ |
+ base::WeakPtr<SpdyStream> stream = CreateStreamSynchronously( |
+ SPDY_REQUEST_RESPONSE_STREAM, session, url, LOWEST, BoundNetLog()); |
+ ASSERT_TRUE(stream.get() != NULL); |
+ |
+ StreamDelegateWithTrailers delegate(stream, kPostBodyStringPiece); |
+ stream->SetDelegate(&delegate); |
+ |
+ EXPECT_FALSE(stream->HasUrlFromHeaders()); |
+ |
+ scoped_ptr<SpdyHeaderBlock> headers( |
+ spdy_util_.ConstructPostHeaderBlock(kStreamUrl, kPostBodyLength)); |
+ EXPECT_EQ(ERR_IO_PENDING, |
+ stream->SendRequestHeaders(headers.Pass(), MORE_DATA_TO_SEND)); |
+ EXPECT_TRUE(stream->HasUrlFromHeaders()); |
+ EXPECT_EQ(kStreamUrl, stream->GetUrlFromHeaders().spec()); |
+ |
+ data.RunFor(GetNumReads() + GetNumWrites()); |
+ EXPECT_EQ(ERR_CONNECTION_CLOSED, delegate.WaitForClose()); |
+ |
+ EXPECT_TRUE(delegate.send_headers_completed()); |
+ EXPECT_EQ("200", delegate.GetResponseHeaderValue(spdy_util_.GetStatusKey())); |
+ const SpdyHeaderBlock& received_trailers = delegate.trailers(); |
+ SpdyHeaderBlock::const_iterator it = received_trailers.find("foo"); |
+ EXPECT_EQ("bar", it->second); |
+ EXPECT_EQ(std::string(kPostBody, kPostBodyLength), |
+ delegate.TakeReceivedData()); |
+ EXPECT_TRUE(data.AllWriteDataConsumed()); |
+} |
+ |
TEST_P(SpdyStreamTest, PushedStream) { |
session_ = |
SpdySessionDependencies::SpdyCreateSessionDeterministic(&session_deps_); |