| Index: net/quic/core/quic_spdy_stream_test.cc
 | 
| diff --git a/net/quic/core/quic_spdy_stream_test.cc b/net/quic/core/quic_spdy_stream_test.cc
 | 
| index e12f9e021434c6f4846342f5e19ffefa76c4abdf..9d14ecb4dff242fe4024d6a63141b006bf544b4a 100644
 | 
| --- a/net/quic/core/quic_spdy_stream_test.cc
 | 
| +++ b/net/quic/core/quic_spdy_stream_test.cc
 | 
| @@ -110,6 +110,12 @@ class QuicSpdyStreamTest : public ::testing::TestWithParam<QuicVersion> {
 | 
|      session_->ActivateStream(base::WrapUnique(stream2_));
 | 
|    }
 | 
|  
 | 
| +  QuicHeaderList ProcessHeaders(bool fin, const SpdyHeaderBlock& headers) {
 | 
| +    QuicHeaderList h = AsHeaderList(headers);
 | 
| +    stream_->OnStreamHeaderList(fin, h.uncompressed_header_bytes(), h);
 | 
| +    return h;
 | 
| +  }
 | 
| +
 | 
|   protected:
 | 
|    QuicFlagSaver flags_;  // Save/restore all QUIC flag values.
 | 
|    MockQuicConnectionHelper helper_;
 | 
| @@ -128,38 +134,17 @@ INSTANTIATE_TEST_CASE_P(Tests,
 | 
|                          QuicSpdyStreamTest,
 | 
|                          ::testing::ValuesIn(AllSupportedVersions()));
 | 
|  
 | 
| -TEST_P(QuicSpdyStreamTest, ProcessHeaders) {
 | 
| -  Initialize(kShouldProcessData);
 | 
| -
 | 
| -  string headers = SpdyUtils::SerializeUncompressedHeaders(headers_);
 | 
| -  stream_->OnStreamHeadersPriority(kV3HighestPriority);
 | 
| -  stream_->OnStreamHeaders(headers);
 | 
| -  EXPECT_EQ("", stream_->data());
 | 
| -  EXPECT_EQ(headers, stream_->decompressed_headers());
 | 
| -  stream_->OnStreamHeadersComplete(false, headers.size());
 | 
| -  EXPECT_EQ(kV3HighestPriority, stream_->priority());
 | 
| -  EXPECT_EQ("", stream_->data());
 | 
| -  EXPECT_EQ(headers, stream_->decompressed_headers());
 | 
| -  EXPECT_FALSE(stream_->IsDoneReading());
 | 
| -}
 | 
| -
 | 
|  TEST_P(QuicSpdyStreamTest, ProcessHeaderList) {
 | 
|    Initialize(kShouldProcessData);
 | 
|  
 | 
| -  size_t total_bytes = 0;
 | 
| -  QuicHeaderList headers;
 | 
| -  for (auto p : headers_) {
 | 
| -    headers.OnHeader(p.first, p.second);
 | 
| -    total_bytes += p.first.size() + p.second.size();
 | 
| -  }
 | 
|    stream_->OnStreamHeadersPriority(kV3HighestPriority);
 | 
| -  stream_->OnStreamHeaderList(false, total_bytes, headers);
 | 
| +  ProcessHeaders(false, headers_);
 | 
|    EXPECT_EQ("", stream_->data());
 | 
|    EXPECT_FALSE(stream_->header_list().empty());
 | 
|    EXPECT_FALSE(stream_->IsDoneReading());
 | 
|  }
 | 
|  
 | 
| -TEST_P(QuicSpdyStreamTest, ProcessEmptyHeaderList) {
 | 
| +TEST_P(QuicSpdyStreamTest, ProcessTooLargeHeaderList) {
 | 
|    FLAGS_quic_limit_uncompressed_headers = true;
 | 
|    Initialize(kShouldProcessData);
 | 
|  
 | 
| @@ -172,22 +157,6 @@ TEST_P(QuicSpdyStreamTest, ProcessEmptyHeaderList) {
 | 
|    EXPECT_EQ(QUIC_HEADERS_TOO_LARGE, stream_->stream_error());
 | 
|  }
 | 
|  
 | 
| -TEST_P(QuicSpdyStreamTest, ProcessHeadersWithFin) {
 | 
| -  Initialize(kShouldProcessData);
 | 
| -
 | 
| -  string headers = SpdyUtils::SerializeUncompressedHeaders(headers_);
 | 
| -  stream_->OnStreamHeadersPriority(kV3HighestPriority);
 | 
| -  stream_->OnStreamHeaders(headers);
 | 
| -  EXPECT_EQ("", stream_->data());
 | 
| -  EXPECT_EQ(headers, stream_->decompressed_headers());
 | 
| -  stream_->OnStreamHeadersComplete(true, headers.size());
 | 
| -  EXPECT_EQ(kV3HighestPriority, stream_->priority());
 | 
| -  EXPECT_EQ("", stream_->data());
 | 
| -  EXPECT_EQ(headers, stream_->decompressed_headers());
 | 
| -  EXPECT_FALSE(stream_->IsDoneReading());
 | 
| -  EXPECT_TRUE(stream_->HasFinalReceivedByteOffset());
 | 
| -}
 | 
| -
 | 
|  TEST_P(QuicSpdyStreamTest, ProcessHeaderListWithFin) {
 | 
|    Initialize(kShouldProcessData);
 | 
|  
 | 
| @@ -252,55 +221,37 @@ TEST_P(QuicSpdyStreamTest, ParseHeaderStatusCode) {
 | 
|  TEST_P(QuicSpdyStreamTest, MarkHeadersConsumed) {
 | 
|    Initialize(kShouldProcessData);
 | 
|  
 | 
| -  string headers = SpdyUtils::SerializeUncompressedHeaders(headers_);
 | 
|    string body = "this is the body";
 | 
| +  QuicHeaderList headers = ProcessHeaders(false, headers_);
 | 
| +  EXPECT_EQ(headers, stream_->header_list());
 | 
|  
 | 
| -  stream_->OnStreamHeaders(headers);
 | 
| -  stream_->OnStreamHeadersComplete(false, headers.size());
 | 
| -  EXPECT_EQ(headers, stream_->decompressed_headers());
 | 
| -
 | 
| -  headers.erase(0, 10);
 | 
| -  stream_->MarkHeadersConsumed(10);
 | 
| -  EXPECT_EQ(headers, stream_->decompressed_headers());
 | 
| -
 | 
| -  stream_->MarkHeadersConsumed(headers.length());
 | 
| -  EXPECT_EQ("", stream_->decompressed_headers());
 | 
| +  stream_->ConsumeHeaderList();
 | 
| +  EXPECT_EQ(QuicHeaderList(), stream_->header_list());
 | 
|  }
 | 
|  
 | 
|  TEST_P(QuicSpdyStreamTest, ProcessHeadersAndBody) {
 | 
|    Initialize(kShouldProcessData);
 | 
|  
 | 
| -  string headers = SpdyUtils::SerializeUncompressedHeaders(headers_);
 | 
|    string body = "this is the body";
 | 
|  
 | 
| -  stream_->OnStreamHeaders(headers);
 | 
|    EXPECT_EQ("", stream_->data());
 | 
| -  EXPECT_EQ(headers, stream_->decompressed_headers());
 | 
| -  stream_->OnStreamHeadersComplete(false, headers.size());
 | 
| -  EXPECT_EQ(headers, stream_->decompressed_headers());
 | 
| -  stream_->MarkHeadersConsumed(headers.length());
 | 
| +  QuicHeaderList headers = ProcessHeaders(false, headers_);
 | 
| +  EXPECT_EQ(headers, stream_->header_list());
 | 
| +  stream_->ConsumeHeaderList();
 | 
|    QuicStreamFrame frame(kClientDataStreamId1, false, 0, StringPiece(body));
 | 
|    stream_->OnStreamFrame(frame);
 | 
| -  EXPECT_EQ("", stream_->decompressed_headers());
 | 
| +  EXPECT_EQ(QuicHeaderList(), stream_->header_list());
 | 
|    EXPECT_EQ(body, stream_->data());
 | 
|  }
 | 
|  
 | 
|  TEST_P(QuicSpdyStreamTest, ProcessHeadersAndBodyFragments) {
 | 
| -  string headers = SpdyUtils::SerializeUncompressedHeaders(headers_);
 | 
|    string body = "this is the body";
 | 
|  
 | 
|    for (size_t fragment_size = 1; fragment_size < body.size(); ++fragment_size) {
 | 
|      Initialize(kShouldProcessData);
 | 
| -    for (size_t offset = 0; offset < headers.size(); offset += fragment_size) {
 | 
| -      size_t remaining_data = headers.size() - offset;
 | 
| -      StringPiece fragment(headers.data() + offset,
 | 
| -                           min(fragment_size, remaining_data));
 | 
| -      stream_->OnStreamHeaders(fragment);
 | 
| -    }
 | 
| -    stream_->OnStreamHeadersComplete(false, headers.size());
 | 
| -    ASSERT_EQ(headers, stream_->decompressed_headers()) << "fragment_size: "
 | 
| -                                                        << fragment_size;
 | 
| -    stream_->MarkHeadersConsumed(headers.length());
 | 
| +    QuicHeaderList headers = ProcessHeaders(false, headers_);
 | 
| +    ASSERT_EQ(headers, stream_->header_list());
 | 
| +    stream_->ConsumeHeaderList();
 | 
|      for (size_t offset = 0; offset < body.size(); offset += fragment_size) {
 | 
|        size_t remaining_data = body.size() - offset;
 | 
|        StringPiece fragment(body.data() + offset,
 | 
| @@ -314,21 +265,13 @@ TEST_P(QuicSpdyStreamTest, ProcessHeadersAndBodyFragments) {
 | 
|  }
 | 
|  
 | 
|  TEST_P(QuicSpdyStreamTest, ProcessHeadersAndBodyFragmentsSplit) {
 | 
| -  string headers = SpdyUtils::SerializeUncompressedHeaders(headers_);
 | 
|    string body = "this is the body";
 | 
|  
 | 
|    for (size_t split_point = 1; split_point < body.size() - 1; ++split_point) {
 | 
|      Initialize(kShouldProcessData);
 | 
| -    StringPiece headers1(headers.data(), split_point);
 | 
| -    stream_->OnStreamHeaders(headers1);
 | 
| -
 | 
| -    StringPiece headers2(headers.data() + split_point,
 | 
| -                         headers.size() - split_point);
 | 
| -    stream_->OnStreamHeaders(headers2);
 | 
| -    stream_->OnStreamHeadersComplete(false, headers.size());
 | 
| -    ASSERT_EQ(headers, stream_->decompressed_headers()) << "split_point: "
 | 
| -                                                        << split_point;
 | 
| -    stream_->MarkHeadersConsumed(headers.length());
 | 
| +    QuicHeaderList headers = ProcessHeaders(false, headers_);
 | 
| +    ASSERT_EQ(headers, stream_->header_list());
 | 
| +    stream_->ConsumeHeaderList();
 | 
|  
 | 
|      StringPiece fragment1(body.data(), split_point);
 | 
|      QuicStreamFrame frame1(kClientDataStreamId1, false, 0,
 | 
| @@ -347,14 +290,12 @@ TEST_P(QuicSpdyStreamTest, ProcessHeadersAndBodyFragmentsSplit) {
 | 
|  TEST_P(QuicSpdyStreamTest, ProcessHeadersAndBodyReadv) {
 | 
|    Initialize(!kShouldProcessData);
 | 
|  
 | 
| -  string headers = SpdyUtils::SerializeUncompressedHeaders(headers_);
 | 
|    string body = "this is the body";
 | 
|  
 | 
| -  stream_->OnStreamHeaders(headers);
 | 
| -  stream_->OnStreamHeadersComplete(false, headers.size());
 | 
| +  ProcessHeaders(false, headers_);
 | 
|    QuicStreamFrame frame(kClientDataStreamId1, false, 0, StringPiece(body));
 | 
|    stream_->OnStreamFrame(frame);
 | 
| -  stream_->MarkHeadersConsumed(headers.length());
 | 
| +  stream_->ConsumeHeaderList();
 | 
|  
 | 
|    char buffer[2048];
 | 
|    ASSERT_LT(body.length(), arraysize(buffer));
 | 
| @@ -370,14 +311,12 @@ TEST_P(QuicSpdyStreamTest, ProcessHeadersAndBodyReadv) {
 | 
|  TEST_P(QuicSpdyStreamTest, ProcessHeadersAndBodyMarkConsumed) {
 | 
|    Initialize(!kShouldProcessData);
 | 
|  
 | 
| -  string headers = SpdyUtils::SerializeUncompressedHeaders(headers_);
 | 
|    string body = "this is the body";
 | 
|  
 | 
| -  stream_->OnStreamHeaders(headers);
 | 
| -  stream_->OnStreamHeadersComplete(false, headers.size());
 | 
| +  ProcessHeaders(false, headers_);
 | 
|    QuicStreamFrame frame(kClientDataStreamId1, false, 0, StringPiece(body));
 | 
|    stream_->OnStreamFrame(frame);
 | 
| -  stream_->MarkHeadersConsumed(headers.length());
 | 
| +  stream_->ConsumeHeaderList();
 | 
|  
 | 
|    struct iovec vec;
 | 
|  
 | 
| @@ -392,13 +331,11 @@ TEST_P(QuicSpdyStreamTest, ProcessHeadersAndBodyMarkConsumed) {
 | 
|  TEST_P(QuicSpdyStreamTest, ProcessHeadersAndBodyIncrementalReadv) {
 | 
|    Initialize(!kShouldProcessData);
 | 
|  
 | 
| -  string headers = SpdyUtils::SerializeUncompressedHeaders(headers_);
 | 
|    string body = "this is the body";
 | 
| -  stream_->OnStreamHeaders(headers);
 | 
| -  stream_->OnStreamHeadersComplete(false, headers.size());
 | 
| +  ProcessHeaders(false, headers_);
 | 
|    QuicStreamFrame frame(kClientDataStreamId1, false, 0, StringPiece(body));
 | 
|    stream_->OnStreamFrame(frame);
 | 
| -  stream_->MarkHeadersConsumed(headers.length());
 | 
| +  stream_->ConsumeHeaderList();
 | 
|  
 | 
|    char buffer[1];
 | 
|    struct iovec vec;
 | 
| @@ -415,13 +352,11 @@ TEST_P(QuicSpdyStreamTest, ProcessHeadersAndBodyIncrementalReadv) {
 | 
|  TEST_P(QuicSpdyStreamTest, ProcessHeadersUsingReadvWithMultipleIovecs) {
 | 
|    Initialize(!kShouldProcessData);
 | 
|  
 | 
| -  string headers = SpdyUtils::SerializeUncompressedHeaders(headers_);
 | 
|    string body = "this is the body";
 | 
| -  stream_->OnStreamHeaders(headers);
 | 
| -  stream_->OnStreamHeadersComplete(false, headers.size());
 | 
| +  ProcessHeaders(false, headers_);
 | 
|    QuicStreamFrame frame(kClientDataStreamId1, false, 0, StringPiece(body));
 | 
|    stream_->OnStreamFrame(frame);
 | 
| -  stream_->MarkHeadersConsumed(headers.length());
 | 
| +  stream_->ConsumeHeaderList();
 | 
|  
 | 
|    char buffer1[1];
 | 
|    char buffer2[1];
 | 
| @@ -492,11 +427,9 @@ TEST_P(QuicSpdyStreamTest, StreamFlowControlNoWindowUpdateIfNotConsumed) {
 | 
|                           stream_->flow_controller()));
 | 
|  
 | 
|    // Stream receives enough data to fill a fraction of the receive window.
 | 
| -  string headers = SpdyUtils::SerializeUncompressedHeaders(headers_);
 | 
|    string body;
 | 
|    GenerateBody(&body, kWindow / 3);
 | 
| -  stream_->OnStreamHeaders(headers);
 | 
| -  stream_->OnStreamHeadersComplete(false, headers.size());
 | 
| +  ProcessHeaders(false, headers_);
 | 
|  
 | 
|    QuicStreamFrame frame1(kClientDataStreamId1, false, 0, StringPiece(body));
 | 
|    stream_->OnStreamFrame(frame1);
 | 
| @@ -530,12 +463,10 @@ TEST_P(QuicSpdyStreamTest, StreamFlowControlWindowUpdate) {
 | 
|                           stream_->flow_controller()));
 | 
|  
 | 
|    // Stream receives enough data to fill a fraction of the receive window.
 | 
| -  string headers = SpdyUtils::SerializeUncompressedHeaders(headers_);
 | 
|    string body;
 | 
|    GenerateBody(&body, kWindow / 3);
 | 
| -  stream_->OnStreamHeaders(headers);
 | 
| -  stream_->OnStreamHeadersComplete(false, headers.size());
 | 
| -  stream_->MarkHeadersConsumed(headers.length());
 | 
| +  ProcessHeaders(false, headers_);
 | 
| +  stream_->ConsumeHeaderList();
 | 
|  
 | 
|    QuicStreamFrame frame1(kClientDataStreamId1, false, 0, StringPiece(body));
 | 
|    stream_->OnStreamFrame(frame1);
 | 
| @@ -580,13 +511,13 @@ TEST_P(QuicSpdyStreamTest, ConnectionFlowControlWindowUpdate) {
 | 
|                                                kWindow);
 | 
|  
 | 
|    // Supply headers to both streams so that they are happy to receive data.
 | 
| -  string headers = SpdyUtils::SerializeUncompressedHeaders(headers_);
 | 
| -  stream_->OnStreamHeaders(headers);
 | 
| -  stream_->OnStreamHeadersComplete(false, headers.size());
 | 
| -  stream_->MarkHeadersConsumed(headers.length());
 | 
| -  stream2_->OnStreamHeaders(headers);
 | 
| -  stream2_->OnStreamHeadersComplete(false, headers.size());
 | 
| -  stream2_->MarkHeadersConsumed(headers.length());
 | 
| +  auto headers = AsHeaderList(headers_);
 | 
| +  stream_->OnStreamHeaderList(false, headers.uncompressed_header_bytes(),
 | 
| +                              headers);
 | 
| +  stream_->ConsumeHeaderList();
 | 
| +  stream2_->OnStreamHeaderList(false, headers.uncompressed_header_bytes(),
 | 
| +                               headers);
 | 
| +  stream2_->ConsumeHeaderList();
 | 
|  
 | 
|    // Each stream gets a quarter window of data. This should not trigger a
 | 
|    // WINDOW_UPDATE for either stream, nor for the connection.
 | 
| @@ -624,9 +555,7 @@ TEST_P(QuicSpdyStreamTest, StreamFlowControlViolation) {
 | 
|    QuicFlowControllerPeer::SetReceiveWindowOffset(stream_->flow_controller(),
 | 
|                                                   kWindow);
 | 
|  
 | 
| -  string headers = SpdyUtils::SerializeUncompressedHeaders(headers_);
 | 
| -  stream_->OnStreamHeaders(headers);
 | 
| -  stream_->OnStreamHeadersComplete(false, headers.size());
 | 
| +  ProcessHeaders(false, headers_);
 | 
|  
 | 
|    // Receive data to overflow the window, violating flow control.
 | 
|    string body;
 | 
| @@ -639,9 +568,7 @@ TEST_P(QuicSpdyStreamTest, StreamFlowControlViolation) {
 | 
|  
 | 
|  TEST_P(QuicSpdyStreamTest, TestHandlingQuicRstStreamNoError) {
 | 
|    Initialize(kShouldProcessData);
 | 
| -  string headers = SpdyUtils::SerializeUncompressedHeaders(headers_);
 | 
| -  stream_->OnStreamHeaders(headers);
 | 
| -  stream_->OnStreamHeadersComplete(false, headers.size());
 | 
| +  ProcessHeaders(false, headers_);
 | 
|  
 | 
|    stream_->OnStreamReset(
 | 
|        QuicRstStreamFrame(stream_->id(), QUIC_STREAM_NO_ERROR, 0));
 | 
| @@ -666,9 +593,7 @@ TEST_P(QuicSpdyStreamTest, ConnectionFlowControlViolation) {
 | 
|    QuicFlowControllerPeer::SetReceiveWindowOffset(session_->flow_controller(),
 | 
|                                                   kConnectionWindow);
 | 
|  
 | 
| -  string headers = SpdyUtils::SerializeUncompressedHeaders(headers_);
 | 
| -  stream_->OnStreamHeaders(headers);
 | 
| -  stream_->OnStreamHeadersComplete(false, headers.size());
 | 
| +  ProcessHeaders(false, headers_);
 | 
|  
 | 
|    // Send enough data to overflow the connection level flow control window.
 | 
|    string body;
 | 
| @@ -703,35 +628,46 @@ TEST_P(QuicSpdyStreamTest, StreamFlowControlFinNotBlocked) {
 | 
|    stream_->WriteOrBufferData(body, fin, nullptr);
 | 
|  }
 | 
|  
 | 
| -TEST_P(QuicSpdyStreamTest, ReceivingTrailers) {
 | 
| -  // Test that receiving trailing headers from the peer works, and can be read
 | 
| -  // from the stream and consumed.
 | 
| +TEST_P(QuicSpdyStreamTest, ReceivingTrailersViaHeaderList) {
 | 
| +  // Test that receiving trailing headers from the peer via
 | 
| +  // OnStreamHeaderList() works, and can be read from the stream and consumed.
 | 
|    Initialize(kShouldProcessData);
 | 
|  
 | 
|    // Receive initial headers.
 | 
| -  string headers = SpdyUtils::SerializeUncompressedHeaders(headers_);
 | 
| -  stream_->OnStreamHeaders(headers);
 | 
| -  stream_->OnStreamHeadersComplete(false, headers.size());
 | 
| -  stream_->MarkHeadersConsumed(stream_->decompressed_headers().size());
 | 
| +  size_t total_bytes = 0;
 | 
| +  QuicHeaderList headers;
 | 
| +  for (const auto& p : headers_) {
 | 
| +    headers.OnHeader(p.first, p.second);
 | 
| +    total_bytes += p.first.size() + p.second.size();
 | 
| +  }
 | 
| +
 | 
| +  stream_->OnStreamHeadersPriority(kV3HighestPriority);
 | 
| +  stream_->OnStreamHeaderList(/*fin=*/false, total_bytes, headers);
 | 
| +  stream_->ConsumeHeaderList();
 | 
|  
 | 
|    // Receive trailing headers.
 | 
|    SpdyHeaderBlock trailers_block;
 | 
|    trailers_block["key1"] = "value1";
 | 
|    trailers_block["key2"] = "value2";
 | 
|    trailers_block["key3"] = "value3";
 | 
| -  trailers_block[kFinalOffsetHeaderKey] = "0";
 | 
| -  string trailers = SpdyUtils::SerializeUncompressedHeaders(trailers_block);
 | 
| -  stream_->OnStreamHeaders(trailers);
 | 
| -  stream_->OnStreamHeadersComplete(/*fin=*/true, trailers.size());
 | 
| +  SpdyHeaderBlock trailers_block_with_final_offset = trailers_block.Clone();
 | 
| +  trailers_block_with_final_offset[kFinalOffsetHeaderKey] = "0";
 | 
| +  total_bytes = 0;
 | 
| +  QuicHeaderList trailers;
 | 
| +  for (const auto& p : trailers_block_with_final_offset) {
 | 
| +    trailers.OnHeader(p.first, p.second);
 | 
| +    total_bytes += p.first.size() + p.second.size();
 | 
| +  }
 | 
| +  stream_->OnStreamHeaderList(/*fin=*/true, total_bytes, trailers);
 | 
|  
 | 
|    // The trailers should be decompressed, and readable from the stream.
 | 
|    EXPECT_TRUE(stream_->trailers_decompressed());
 | 
| -  const string decompressed_trailers = stream_->decompressed_trailers();
 | 
| -  EXPECT_EQ(trailers, decompressed_trailers);
 | 
| +  EXPECT_EQ(trailers_block, stream_->received_trailers());
 | 
|  
 | 
| -  // Consuming the trailers erases them from the stream.
 | 
| -  stream_->MarkTrailersConsumed(decompressed_trailers.size());
 | 
| -  EXPECT_EQ("", stream_->decompressed_trailers());
 | 
| +  // IsDoneReading() returns false until trailers marked consumed.
 | 
| +  EXPECT_FALSE(stream_->IsDoneReading());
 | 
| +  stream_->MarkTrailersConsumed();
 | 
| +  EXPECT_TRUE(stream_->IsDoneReading());
 | 
|  }
 | 
|  
 | 
|  TEST_P(QuicSpdyStreamTest, ReceivingTrailersWithoutOffset) {
 | 
| @@ -739,10 +675,10 @@ TEST_P(QuicSpdyStreamTest, ReceivingTrailersWithoutOffset) {
 | 
|    Initialize(kShouldProcessData);
 | 
|  
 | 
|    // Receive initial headers.
 | 
| -  string headers = SpdyUtils::SerializeUncompressedHeaders(headers_);
 | 
| -  stream_->OnStreamHeaders(headers);
 | 
| -  stream_->OnStreamHeadersComplete(false, headers.size());
 | 
| -  stream_->MarkHeadersConsumed(stream_->decompressed_headers().size());
 | 
| +  auto headers = AsHeaderList(headers_);
 | 
| +  stream_->OnStreamHeaderList(false, headers.uncompressed_header_bytes(),
 | 
| +                              headers);
 | 
| +  stream_->ConsumeHeaderList();
 | 
|  
 | 
|    const string body = "this is the body";
 | 
|    // Receive trailing headers, without kFinalOffsetHeaderKey.
 | 
| @@ -750,8 +686,7 @@ TEST_P(QuicSpdyStreamTest, ReceivingTrailersWithoutOffset) {
 | 
|    trailers_block["key1"] = "value1";
 | 
|    trailers_block["key2"] = "value2";
 | 
|    trailers_block["key3"] = "value3";
 | 
| -  string trailers = SpdyUtils::SerializeUncompressedHeaders(trailers_block);
 | 
| -  stream_->OnStreamHeaders(trailers);
 | 
| +  auto trailers = AsHeaderList(trailers_block);
 | 
|  
 | 
|    // Verify that the trailers block didn't contain a final offset.
 | 
|    EXPECT_EQ("", trailers_block[kFinalOffsetHeaderKey].as_string());
 | 
| @@ -760,7 +695,8 @@ TEST_P(QuicSpdyStreamTest, ReceivingTrailersWithoutOffset) {
 | 
|    EXPECT_CALL(*connection_,
 | 
|                CloseConnection(QUIC_INVALID_HEADERS_STREAM_DATA, _, _))
 | 
|        .Times(1);
 | 
| -  stream_->OnStreamHeadersComplete(/*fin=*/true, trailers.size());
 | 
| +  stream_->OnStreamHeaderList(/*fin=*/true,
 | 
| +                              trailers.uncompressed_header_bytes(), trailers);
 | 
|  }
 | 
|  
 | 
|  TEST_P(QuicSpdyStreamTest, ReceivingTrailersWithoutFin) {
 | 
| @@ -768,19 +704,19 @@ TEST_P(QuicSpdyStreamTest, ReceivingTrailersWithoutFin) {
 | 
|    Initialize(kShouldProcessData);
 | 
|  
 | 
|    // Receive initial headers.
 | 
| -  string headers = SpdyUtils::SerializeUncompressedHeaders(headers_);
 | 
| -  stream_->OnStreamHeaders(headers);
 | 
| -  stream_->OnStreamHeadersComplete(false, headers.size());
 | 
| +  auto headers = AsHeaderList(headers_);
 | 
| +  stream_->OnStreamHeaderList(/*fin=*/false,
 | 
| +                              headers.uncompressed_header_bytes(), headers);
 | 
|  
 | 
|    // Receive trailing headers with FIN deliberately set to false.
 | 
|    SpdyHeaderBlock trailers_block;
 | 
| -  string trailers = SpdyUtils::SerializeUncompressedHeaders(trailers_block);
 | 
| -  stream_->OnStreamHeaders(trailers);
 | 
| +  auto trailers = AsHeaderList(trailers_block);
 | 
|  
 | 
|    EXPECT_CALL(*connection_,
 | 
|                CloseConnection(QUIC_INVALID_HEADERS_STREAM_DATA, _, _))
 | 
|        .Times(1);
 | 
| -  stream_->OnStreamHeadersComplete(/*fin=*/false, trailers.size());
 | 
| +  stream_->OnStreamHeaderList(/*fin=*/false,
 | 
| +                              trailers.uncompressed_header_bytes(), trailers);
 | 
|  }
 | 
|  
 | 
|  TEST_P(QuicSpdyStreamTest, ReceivingTrailersAfterFin) {
 | 
| @@ -788,19 +724,14 @@ TEST_P(QuicSpdyStreamTest, ReceivingTrailersAfterFin) {
 | 
|    Initialize(kShouldProcessData);
 | 
|  
 | 
|    // Receive initial headers with FIN set.
 | 
| -  string headers = SpdyUtils::SerializeUncompressedHeaders(headers_);
 | 
| -  stream_->OnStreamHeaders(headers);
 | 
| -  stream_->OnStreamHeadersComplete(/*fin=*/true, headers.size());
 | 
| +  ProcessHeaders(true, headers_);
 | 
|  
 | 
|    // Receive trailing headers after FIN already received.
 | 
|    SpdyHeaderBlock trailers_block;
 | 
| -  string trailers = SpdyUtils::SerializeUncompressedHeaders(trailers_block);
 | 
| -  stream_->OnStreamHeaders(trailers);
 | 
| -
 | 
|    EXPECT_CALL(*connection_,
 | 
|                CloseConnection(QUIC_INVALID_HEADERS_STREAM_DATA, _, _))
 | 
|        .Times(1);
 | 
| -  stream_->OnStreamHeadersComplete(/*fin=*/true, trailers.size());
 | 
| +  ProcessHeaders(true, trailers_block);
 | 
|  }
 | 
|  
 | 
|  TEST_P(QuicSpdyStreamTest, ReceivingTrailersAfterBodyWithFin) {
 | 
| @@ -808,9 +739,7 @@ TEST_P(QuicSpdyStreamTest, ReceivingTrailersAfterBodyWithFin) {
 | 
|    Initialize(kShouldProcessData);
 | 
|  
 | 
|    // Receive initial headers without FIN set.
 | 
| -  string headers = SpdyUtils::SerializeUncompressedHeaders(headers_);
 | 
| -  stream_->OnStreamHeaders(headers);
 | 
| -  stream_->OnStreamHeadersComplete(/*fin=*/false, headers.size());
 | 
| +  ProcessHeaders(false, headers_);
 | 
|  
 | 
|    // Receive body data, with FIN.
 | 
|    QuicStreamFrame frame(kClientDataStreamId1, /*fin=*/true, 0, "body");
 | 
| @@ -818,13 +747,10 @@ TEST_P(QuicSpdyStreamTest, ReceivingTrailersAfterBodyWithFin) {
 | 
|  
 | 
|    // Receive trailing headers after FIN already received.
 | 
|    SpdyHeaderBlock trailers_block;
 | 
| -  string trailers = SpdyUtils::SerializeUncompressedHeaders(trailers_block);
 | 
| -  stream_->OnStreamHeaders(trailers);
 | 
| -
 | 
|    EXPECT_CALL(*connection_,
 | 
|                CloseConnection(QUIC_INVALID_HEADERS_STREAM_DATA, _, _))
 | 
|        .Times(1);
 | 
| -  stream_->OnStreamHeadersComplete(/*fin=*/true, trailers.size());
 | 
| +  ProcessHeaders(false, trailers_block);
 | 
|  }
 | 
|  
 | 
|  TEST_P(QuicSpdyStreamTest, ReceivingTrailersWithOffset) {
 | 
| @@ -833,10 +759,8 @@ TEST_P(QuicSpdyStreamTest, ReceivingTrailersWithOffset) {
 | 
|    Initialize(kShouldProcessData);
 | 
|  
 | 
|    // Receive initial headers.
 | 
| -  string headers = SpdyUtils::SerializeUncompressedHeaders(headers_);
 | 
| -  stream_->OnStreamHeaders(headers);
 | 
| -  stream_->OnStreamHeadersComplete(false, headers.size());
 | 
| -  stream_->MarkHeadersConsumed(stream_->decompressed_headers().size());
 | 
| +  QuicHeaderList headers = ProcessHeaders(false, headers_);
 | 
| +  stream_->ConsumeHeaderList();
 | 
|  
 | 
|    const string body = "this is the body";
 | 
|    // Receive trailing headers.
 | 
| @@ -845,18 +769,19 @@ TEST_P(QuicSpdyStreamTest, ReceivingTrailersWithOffset) {
 | 
|    trailers_block["key2"] = "value2";
 | 
|    trailers_block["key3"] = "value3";
 | 
|    trailers_block[kFinalOffsetHeaderKey] = base::IntToString(body.size());
 | 
| -  string trailers = SpdyUtils::SerializeUncompressedHeaders(trailers_block);
 | 
| -  stream_->OnStreamHeaders(trailers);
 | 
| -  stream_->OnStreamHeadersComplete(/*fin=*/true, trailers.size());
 | 
| +
 | 
| +  QuicHeaderList trailers = ProcessHeaders(true, trailers_block);
 | 
|  
 | 
|    // The trailers should be decompressed, and readable from the stream.
 | 
|    EXPECT_TRUE(stream_->trailers_decompressed());
 | 
| -  const string decompressed_trailers = stream_->decompressed_trailers();
 | 
| -  EXPECT_EQ(trailers, decompressed_trailers);
 | 
| +
 | 
| +  // The final offset trailer will be consumed by QUIC.
 | 
| +  trailers_block.erase(kFinalOffsetHeaderKey);
 | 
| +  EXPECT_EQ(trailers_block, stream_->received_trailers());
 | 
| +
 | 
|    // Consuming the trailers erases them from the stream.
 | 
| -  stream_->MarkTrailersConsumed(decompressed_trailers.size());
 | 
|    stream_->MarkTrailersConsumed();
 | 
| -  EXPECT_EQ("", stream_->decompressed_trailers());
 | 
| +  EXPECT_TRUE(stream_->FinishedReadingTrailers());
 | 
|  
 | 
|    EXPECT_FALSE(stream_->IsDoneReading());
 | 
|    // Receive and consume body.
 | 
| @@ -872,10 +797,9 @@ TEST_P(QuicSpdyStreamTest, ClosingStreamWithNoTrailers) {
 | 
|    Initialize(kShouldProcessData);
 | 
|  
 | 
|    // Receive and consume initial headers with FIN not set.
 | 
| -  string headers = SpdyUtils::SerializeUncompressedHeaders(headers_);
 | 
| -  stream_->OnStreamHeaders(headers);
 | 
| -  stream_->OnStreamHeadersComplete(/*fin=*/false, headers.size());
 | 
| -  stream_->MarkHeadersConsumed(headers.size());
 | 
| +  auto h = AsHeaderList(headers_);
 | 
| +  stream_->OnStreamHeaderList(/*fin=*/false, h.uncompressed_header_bytes(), h);
 | 
| +  stream_->ConsumeHeaderList();
 | 
|  
 | 
|    // Receive and consume body with FIN set, and no trailers.
 | 
|    const string kBody = string(1024, 'x');
 | 
| @@ -926,7 +850,7 @@ TEST_P(QuicSpdyStreamTest, WritingTrailersFinalOffset) {
 | 
|    SpdyHeaderBlock trailers;
 | 
|    trailers["trailer key"] = "trailer value";
 | 
|    SpdyHeaderBlock trailers_with_offset(trailers.Clone());
 | 
| -  trailers_with_offset[kFinalOffsetHeaderKey] = base::IntToString(kBodySize);
 | 
| +  trailers_with_offset[kFinalOffsetHeaderKey] = base::Uint64ToString(kBodySize);
 | 
|    EXPECT_CALL(*session_, WriteHeadersMock(_, _, true, _, _));
 | 
|    stream_->WriteTrailers(std::move(trailers), nullptr);
 | 
|    EXPECT_EQ(trailers_with_offset, session_->GetWriteHeaders());
 | 
| 
 |