Allow QuicSession::WritevData() to write data at a specified encryption level.

gfe-relnote: protected by gfe2_reloadable_flag_quic_writevdata_at_level
PiperOrigin-RevId: 297697074
Change-Id: Ib4e5d860f22f506f36db76f4f8ee1c1e406f6a20
diff --git a/common/platform/api/quiche_optional.h b/common/platform/api/quiche_optional.h
index 7342714..141c0e4 100644
--- a/common/platform/api/quiche_optional.h
+++ b/common/platform/api/quiche_optional.h
@@ -13,6 +13,7 @@
 
 template <typename T>
 using QuicheOptional = QuicheOptionalImpl<T>;
+#define QuicheNullOpt QuicheNullOptImpl
 
 }  // namespace quiche
 
diff --git a/quic/core/http/quic_headers_stream_test.cc b/quic/core/http/quic_headers_stream_test.cc
index 4337318..9459351 100644
--- a/quic/core/http/quic_headers_stream_test.cc
+++ b/quic/core/http/quic_headers_stream_test.cc
@@ -288,7 +288,7 @@
     // Write the headers and capture the outgoing data
     EXPECT_CALL(session_, WritevData(QuicUtils::GetHeadersStreamId(
                                          connection_->transport_version()),
-                                     _, _, NO_FIN, _))
+                                     _, _, NO_FIN, _, _))
         .WillOnce(WithArgs<1>(Invoke(this, &QuicHeadersStreamTest::SaveIov)));
     QuicSpdySessionPeer::WriteHeadersOnHeadersStream(
         &session_, stream_id, headers_.Clone(), fin,
@@ -412,7 +412,7 @@
       // Write the headers and capture the outgoing data
       EXPECT_CALL(session_, WritevData(QuicUtils::GetHeadersStreamId(
                                            connection_->transport_version()),
-                                       _, _, NO_FIN, _))
+                                       _, _, NO_FIN, _, _))
           .WillOnce(WithArgs<1>(Invoke(this, &QuicHeadersStreamTest::SaveIov)));
       session_.WritePushPromise(stream_id, promised_stream_id,
                                 headers_.Clone());
@@ -827,7 +827,7 @@
 TEST_P(QuicHeadersStreamTest, AckSentData) {
   EXPECT_CALL(session_, WritevData(QuicUtils::GetHeadersStreamId(
                                        connection_->transport_version()),
-                                   _, _, NO_FIN, _))
+                                   _, _, NO_FIN, _, _))
       .WillRepeatedly(Invoke(&session_, &MockQuicSpdySession::ConsumeData));
   InSequence s;
   QuicReferenceCountedPointer<MockAckListener> ack_listener1(
@@ -896,7 +896,7 @@
   // In this test, a stream frame can contain multiple headers.
   EXPECT_CALL(session_, WritevData(QuicUtils::GetHeadersStreamId(
                                        connection_->transport_version()),
-                                   _, _, NO_FIN, _))
+                                   _, _, NO_FIN, _, _))
       .WillRepeatedly(Invoke(&session_, &MockQuicSpdySession::ConsumeData));
   InSequence s;
   QuicReferenceCountedPointer<MockAckListener> ack_listener1(
@@ -946,7 +946,7 @@
 TEST_P(QuicHeadersStreamTest, HeadersGetAckedMultipleTimes) {
   EXPECT_CALL(session_, WritevData(QuicUtils::GetHeadersStreamId(
                                        connection_->transport_version()),
-                                   _, _, NO_FIN, _))
+                                   _, _, NO_FIN, _, _))
       .WillRepeatedly(Invoke(&session_, &MockQuicSpdySession::ConsumeData));
   InSequence s;
   QuicReferenceCountedPointer<MockAckListener> ack_listener1(
diff --git a/quic/core/http/quic_send_control_stream_test.cc b/quic/core/http/quic_send_control_stream_test.cc
index 49c5dea..9e72f23 100644
--- a/quic/core/http/quic_send_control_stream_test.cc
+++ b/quic/core/http/quic_send_control_stream_test.cc
@@ -73,7 +73,7 @@
             perspective(),
             SupportedVersions(GetParam().version))),
         session_(connection_) {
-    ON_CALL(session_, WritevData(_, _, _, _, _))
+    ON_CALL(session_, WritevData(_, _, _, _, _, _))
         .WillByDefault(Invoke(&session_, &MockQuicSpdySession::ConsumeData));
   }
 
@@ -132,22 +132,22 @@
 
   // A lambda to save and consume stream data when QuicSession::WritevData() is
   // called.
-  auto save_write_data = [&writer, this](QuicStreamId /*id*/,
-                                         size_t write_length,
-                                         QuicStreamOffset offset,
-                                         StreamSendingState /*state*/,
-                                         bool /*is_retransmission*/) {
-    send_control_stream_->WriteStreamData(offset, write_length, &writer);
-    return QuicConsumedData(/* bytes_consumed = */ write_length,
-                            /* fin_consumed = */ false);
-  };
+  auto save_write_data =
+      [&writer, this](QuicStreamId /*id*/, size_t write_length,
+                      QuicStreamOffset offset, StreamSendingState /*state*/,
+                      bool /*is_retransmission*/,
+                      quiche::QuicheOptional<EncryptionLevel> /*level*/) {
+        send_control_stream_->WriteStreamData(offset, write_length, &writer);
+        return QuicConsumedData(/* bytes_consumed = */ write_length,
+                                /* fin_consumed = */ false);
+      };
 
-  EXPECT_CALL(session_, WritevData(send_control_stream_->id(), 1, _, _, _))
+  EXPECT_CALL(session_, WritevData(send_control_stream_->id(), 1, _, _, _, _))
       .WillOnce(Invoke(save_write_data));
   EXPECT_CALL(session_, WritevData(send_control_stream_->id(),
-                                   expected_write_data.size() - 5, _, _, _))
+                                   expected_write_data.size() - 5, _, _, _, _))
       .WillOnce(Invoke(save_write_data));
-  EXPECT_CALL(session_, WritevData(send_control_stream_->id(), 4, _, _, _))
+  EXPECT_CALL(session_, WritevData(send_control_stream_->id(), 4, _, _, _, _))
       .WillOnce(Invoke(save_write_data));
 
   send_control_stream_->MaybeSendSettingsFrame();
@@ -159,8 +159,8 @@
   Initialize();
   testing::InSequence s;
 
-  EXPECT_CALL(session_, WritevData(send_control_stream_->id(), 1, _, _, _));
-  EXPECT_CALL(session_, WritevData(send_control_stream_->id(), _, _, _, _))
+  EXPECT_CALL(session_, WritevData(send_control_stream_->id(), 1, _, _, _, _));
+  EXPECT_CALL(session_, WritevData(send_control_stream_->id(), _, _, _, _, _))
       .Times(2);
   send_control_stream_->MaybeSendSettingsFrame();
 
@@ -176,12 +176,12 @@
 
   // The first write will trigger the control stream to write stream type, a
   // SETTINGS frame, and a greased frame before the PRIORITY_UPDATE frame.
-  EXPECT_CALL(session_, WritevData(send_control_stream_->id(), _, _, _, _))
+  EXPECT_CALL(session_, WritevData(send_control_stream_->id(), _, _, _, _, _))
       .Times(4);
   PriorityUpdateFrame frame;
   send_control_stream_->WritePriorityUpdate(frame);
 
-  EXPECT_CALL(session_, WritevData(send_control_stream_->id(), _, _, _, _));
+  EXPECT_CALL(session_, WritevData(send_control_stream_->id(), _, _, _, _, _));
   send_control_stream_->WritePriorityUpdate(frame);
 }
 
diff --git a/quic/core/http/quic_spdy_client_session_test.cc b/quic/core/http/quic_spdy_client_session_test.cc
index 01e9fd8..a8ddc09 100644
--- a/quic/core/http/quic_spdy_client_session_test.cc
+++ b/quic/core/http/quic_spdy_client_session_test.cc
@@ -232,7 +232,7 @@
   // Verify that no data may be send on existing streams.
   char data[] = "hello world";
   QuicConsumedData consumed = session_->WritevData(
-      stream->id(), QUICHE_ARRAYSIZE(data), 0, NO_FIN, false);
+      stream->id(), QUICHE_ARRAYSIZE(data), 0, NO_FIN, false, QuicheNullOpt);
   EXPECT_FALSE(consumed.fin_consumed);
   EXPECT_EQ(0u, consumed.bytes_consumed);
 }
diff --git a/quic/core/http/quic_spdy_session_test.cc b/quic/core/http/quic_spdy_session_test.cc
index bff8bbc..37b559c 100644
--- a/quic/core/http/quic_spdy_session_test.cc
+++ b/quic/core/http/quic_spdy_session_test.cc
@@ -267,16 +267,18 @@
     return QuicSpdySession::GetOrCreateStream(stream_id);
   }
 
-  QuicConsumedData WritevData(QuicStreamId id,
-                              size_t write_length,
-                              QuicStreamOffset offset,
-                              StreamSendingState state,
-                              bool is_retransmission) override {
+  QuicConsumedData WritevData(
+      QuicStreamId id,
+      size_t write_length,
+      QuicStreamOffset offset,
+      StreamSendingState state,
+      bool is_retransmission,
+      quiche::QuicheOptional<EncryptionLevel> level) override {
     bool fin = state != NO_FIN;
     QuicConsumedData consumed(write_length, fin);
     if (!writev_consumes_all_data_) {
       consumed = QuicSession::WritevData(id, write_length, offset, state,
-                                         is_retransmission);
+                                         is_retransmission, level);
     }
     QuicSessionPeer::GetWriteBlockedStreams(this)->UpdateBytesForStream(
         id, consumed.bytes_consumed);
@@ -296,7 +298,8 @@
     }
     MakeIOVector("not empty", &iov);
     QuicStreamPeer::SendBuffer(stream).SaveStreamData(&iov, 1, 0, 9);
-    QuicConsumedData consumed = WritevData(stream->id(), 9, 0, FIN, false);
+    QuicConsumedData consumed =
+        WritevData(stream->id(), 9, 0, FIN, false, QuicheNullOpt);
     QuicStreamPeer::SendBuffer(stream).OnStreamDataConsumed(
         consumed.bytes_consumed);
     return consumed;
@@ -304,7 +307,7 @@
 
   QuicConsumedData SendLargeFakeData(QuicStream* stream, int bytes) {
     DCHECK(writev_consumes_all_data_);
-    return WritevData(stream->id(), bytes, 0, FIN, false);
+    return WritevData(stream->id(), bytes, 0, FIN, false, QuicheNullOpt);
   }
 
   using QuicSession::closed_streams;
diff --git a/quic/core/http/quic_spdy_stream_test.cc b/quic/core/http/quic_spdy_stream_test.cc
index c8f9d3a..5b70813 100644
--- a/quic/core/http/quic_spdy_stream_test.cc
+++ b/quic/core/http/quic_spdy_stream_test.cc
@@ -202,7 +202,7 @@
         &helper_, &alarm_factory_, perspective, SupportedVersions(GetParam()));
     session_ = std::make_unique<StrictMock<MockQuicSpdySession>>(connection_);
     session_->Initialize();
-    ON_CALL(*session_, WritevData(_, _, _, _, _))
+    ON_CALL(*session_, WritevData(_, _, _, _, _, _))
         .WillByDefault(
             Invoke(session_.get(), &MockQuicSpdySession::ConsumeData));
 
@@ -237,16 +237,17 @@
       }
       auto send_control_stream =
           QuicSpdySessionPeer::GetSendControlStream(session_.get());
-      EXPECT_CALL(*session_, WritevData(send_control_stream->id(), _, _, _, _))
+      EXPECT_CALL(*session_,
+                  WritevData(send_control_stream->id(), _, _, _, _, _))
           .Times(num_control_stream_writes);
       auto qpack_decoder_stream =
           QuicSpdySessionPeer::GetQpackDecoderSendStream(session_.get());
       EXPECT_CALL(*session_,
-                  WritevData(qpack_decoder_stream->id(), 1, 0, _, _));
+                  WritevData(qpack_decoder_stream->id(), 1, 0, _, _, _));
       auto qpack_encoder_stream =
           QuicSpdySessionPeer::GetQpackEncoderSendStream(session_.get());
       EXPECT_CALL(*session_,
-                  WritevData(qpack_encoder_stream->id(), 1, 0, _, _));
+                  WritevData(qpack_encoder_stream->id(), 1, 0, _, _, _));
     }
     static_cast<QuicSession*>(session_.get())
         ->SetDefaultEncryptionLevel(ENCRYPTION_ZERO_RTT);
@@ -769,9 +770,9 @@
 
   const uint64_t kHeaderLength = UsesHttp3() ? 2 : 0;
   if (UsesHttp3()) {
-    EXPECT_CALL(*session_, WritevData(_, kHeaderLength, _, NO_FIN, _));
+    EXPECT_CALL(*session_, WritevData(_, kHeaderLength, _, NO_FIN, _, _));
   }
-  EXPECT_CALL(*session_, WritevData(_, _, _, _, _))
+  EXPECT_CALL(*session_, WritevData(_, _, _, _, _, _))
       .WillOnce(Return(QuicConsumedData(kWindow - kHeaderLength, true)));
   EXPECT_CALL(*connection_, SendControlFrame(_));
   stream_->WriteOrBufferBody(body, false);
@@ -1047,7 +1048,7 @@
   EXPECT_CALL(*connection_,
               SendBlocked(GetNthClientInitiatedBidirectionalId(0)))
       .Times(0);
-  EXPECT_CALL(*session_, WritevData(_, 0, _, FIN, _));
+  EXPECT_CALL(*session_, WritevData(_, 0, _, FIN, _, _));
 
   stream_->WriteOrBufferBody(body, fin);
 }
@@ -1290,7 +1291,7 @@
     // In this case, TestStream::WriteHeadersImpl() does not prevent writes.
     // Four writes on the request stream: HEADERS frame header and payload both
     // for headers and trailers.
-    EXPECT_CALL(*session_, WritevData(stream_->id(), _, _, _, _)).Times(4);
+    EXPECT_CALL(*session_, WritevData(stream_->id(), _, _, _, _, _)).Times(4);
   }
 
   // Write the initial headers, without a FIN.
@@ -1314,13 +1315,13 @@
 
   // Four writes on the request stream: HEADERS frame header and payload both
   // for headers and trailers.
-  EXPECT_CALL(*session_, WritevData(stream_->id(), _, _, _, _)).Times(4);
+  EXPECT_CALL(*session_, WritevData(stream_->id(), _, _, _, _, _)).Times(4);
 
   // No PRIORITY_UPDATE frames on the control stream,
   // because the stream has default priority.
   auto send_control_stream =
       QuicSpdySessionPeer::GetSendControlStream(session_.get());
-  EXPECT_CALL(*session_, WritevData(send_control_stream->id(), _, _, _, _))
+  EXPECT_CALL(*session_, WritevData(send_control_stream->id(), _, _, _, _, _))
       .Times(0);
 
   // Write the initial headers, without a FIN.
@@ -1343,14 +1344,14 @@
   InitializeWithPerspective(kShouldProcessData, Perspective::IS_CLIENT);
 
   // Two writes on the request stream: HEADERS frame header and payload.
-  EXPECT_CALL(*session_, WritevData(stream_->id(), _, _, _, _)).Times(2);
+  EXPECT_CALL(*session_, WritevData(stream_->id(), _, _, _, _, _)).Times(2);
   EXPECT_CALL(*stream_, WriteHeadersMock(false));
   stream_->WriteHeaders(SpdyHeaderBlock(), /*fin=*/false, nullptr);
 
   // PRIORITY_UPDATE frame on the control stream.
   auto send_control_stream =
       QuicSpdySessionPeer::GetSendControlStream(session_.get());
-  EXPECT_CALL(*session_, WritevData(send_control_stream->id(), _, _, _, _));
+  EXPECT_CALL(*session_, WritevData(send_control_stream->id(), _, _, _, _, _));
   stream_->SetPriority(spdy::SpdyStreamPrecedence(kV3HighestPriority));
 }
 
@@ -1365,14 +1366,14 @@
   // is called, before HEADERS frame is sent.
   auto send_control_stream =
       QuicSpdySessionPeer::GetSendControlStream(session_.get());
-  EXPECT_CALL(*session_, WritevData(send_control_stream->id(), _, _, _, _));
+  EXPECT_CALL(*session_, WritevData(send_control_stream->id(), _, _, _, _, _));
 
   stream_->SetPriority(spdy::SpdyStreamPrecedence(kV3HighestPriority));
   testing::Mock::VerifyAndClearExpectations(session_.get());
 
   // Two writes on the request stream: HEADERS frame header and payload.
   // PRIORITY_UPDATE frame is not sent this time, because one is already sent.
-  EXPECT_CALL(*session_, WritevData(stream_->id(), _, _, _, _)).Times(2);
+  EXPECT_CALL(*session_, WritevData(stream_->id(), _, _, _, _, _)).Times(2);
   EXPECT_CALL(*stream_, WriteHeadersMock(true));
   stream_->WriteHeaders(SpdyHeaderBlock(), /*fin=*/true, nullptr);
 }
@@ -1385,7 +1386,7 @@
   if (UsesHttp3()) {
     // In this case, TestStream::WriteHeadersImpl() does not prevent writes.
     // HEADERS frame header and payload on the request stream.
-    EXPECT_CALL(*session_, WritevData(stream_->id(), _, _, _, _)).Times(2);
+    EXPECT_CALL(*session_, WritevData(stream_->id(), _, _, _, _, _)).Times(2);
   }
 
   // Write the initial headers.
@@ -1393,7 +1394,7 @@
   stream_->WriteHeaders(SpdyHeaderBlock(), /*fin=*/false, nullptr);
 
   // Write non-zero body data to force a non-zero final offset.
-  EXPECT_CALL(*session_, WritevData(_, _, _, _, _)).Times(AtLeast(1));
+  EXPECT_CALL(*session_, WritevData(_, _, _, _, _, _)).Times(AtLeast(1));
   std::string body(1024, 'x');  // 1 kB
   QuicByteCount header_length = 0;
   if (UsesHttp3()) {
@@ -1428,7 +1429,7 @@
 
   // Expect data being written on the stream.  In addition to that, headers are
   // also written on the stream in case of IETF QUIC.
-  EXPECT_CALL(*session_, WritevData(stream_->id(), _, _, _, _))
+  EXPECT_CALL(*session_, WritevData(stream_->id(), _, _, _, _, _))
       .Times(AtLeast(1));
 
   // Write the initial headers.
@@ -1467,9 +1468,9 @@
   // Write non-zero body data, but only consume partially, ensuring queueing.
   const int kBodySize = 1 * 1024;  // 1 kB
   if (UsesHttp3()) {
-    EXPECT_CALL(*session_, WritevData(_, 3, _, NO_FIN, _));
+    EXPECT_CALL(*session_, WritevData(_, 3, _, NO_FIN, _, _));
   }
-  EXPECT_CALL(*session_, WritevData(_, kBodySize, _, NO_FIN, _))
+  EXPECT_CALL(*session_, WritevData(_, kBodySize, _, NO_FIN, _, _))
       .WillOnce(Return(QuicConsumedData(kBodySize - 1, false)));
   stream_->WriteOrBufferBody(std::string(kBodySize, 'x'), false);
   EXPECT_EQ(1u, stream_->BufferedDataBytes());
@@ -1482,7 +1483,7 @@
   EXPECT_FALSE(stream_->write_side_closed());
 
   // Writing the queued bytes will close the write side of the stream.
-  EXPECT_CALL(*session_, WritevData(_, 1, _, NO_FIN, _));
+  EXPECT_CALL(*session_, WritevData(_, 1, _, NO_FIN, _, _));
   stream_->OnCanWrite();
   EXPECT_TRUE(stream_->write_side_closed());
 }
@@ -1520,7 +1521,7 @@
   const char kBody2[] = "Test2";
 
   Initialize(kShouldProcessData);
-  EXPECT_CALL(*session_, WritevData(_, _, _, _, _)).Times(AtLeast(1));
+  EXPECT_CALL(*session_, WritevData(_, _, _, _, _, _)).Times(AtLeast(1));
   testing::InSequence s;
   QuicReferenceCountedPointer<MockAckListener> ack_listener1(
       new MockAckListener());
@@ -1566,7 +1567,7 @@
 
 TEST_P(QuicSpdyStreamTest, StreamBecomesZombieWithWriteThatCloses) {
   Initialize(kShouldProcessData);
-  EXPECT_CALL(*session_, WritevData(_, _, _, _, _)).Times(AtLeast(1));
+  EXPECT_CALL(*session_, WritevData(_, _, _, _, _, _)).Times(AtLeast(1));
   QuicStreamPeer::CloseReadSide(stream_);
   // This write causes stream to be closed.
   stream_->WriteOrBufferBody("Test1", true);
@@ -1588,9 +1589,9 @@
   Initialize(kShouldProcessData);
 
   if (UsesHttp3()) {
-    EXPECT_CALL(*session_, WritevData(_, 2, _, NO_FIN, _));
+    EXPECT_CALL(*session_, WritevData(_, 2, _, NO_FIN, _, _));
   }
-  EXPECT_CALL(*session_, WritevData(_, 4, _, FIN, _));
+  EXPECT_CALL(*session_, WritevData(_, 4, _, FIN, _, _));
   stream_->WriteOrBufferBody("data", true);
   stream_->OnPriorityFrame(spdy::SpdyStreamPrecedence(kV3HighestPriority));
   EXPECT_EQ(spdy::SpdyStreamPrecedence(kV3HighestPriority),
@@ -1627,7 +1628,7 @@
   QuicReferenceCountedPointer<MockAckListener> mock_ack_listener(
       new StrictMock<MockAckListener>);
   stream_->set_ack_listener(mock_ack_listener);
-  EXPECT_CALL(*session_, WritevData(_, _, _, _, _)).Times(AtLeast(1));
+  EXPECT_CALL(*session_, WritevData(_, _, _, _, _, _)).Times(AtLeast(1));
   // Stream is not waiting for acks initially.
   EXPECT_FALSE(stream_->IsWaitingForAcks());
   EXPECT_EQ(0u, QuicStreamPeer::SendBuffer(stream_).size());
@@ -1681,7 +1682,7 @@
   QuicReferenceCountedPointer<MockAckListener> mock_ack_listener(
       new StrictMock<MockAckListener>);
   stream_->set_ack_listener(mock_ack_listener);
-  EXPECT_CALL(*session_, WritevData(_, _, _, _, _)).Times(AtLeast(1));
+  EXPECT_CALL(*session_, WritevData(_, _, _, _, _, _)).Times(AtLeast(1));
   // Send [0, 27) and fin.
   stream_->WriteOrBufferData("FooAndBar", false, nullptr);
   stream_->WriteOrBufferData("FooAndBar", false, nullptr);
@@ -1749,7 +1750,7 @@
   std::string body = "Test1";
   std::string body2(100, 'x');
 
-  EXPECT_CALL(*session_, WritevData(_, _, _, _, _)).Times(AtLeast(1));
+  EXPECT_CALL(*session_, WritevData(_, _, _, _, _, _)).Times(AtLeast(1));
   stream_->WriteOrBufferBody(body, false);
   stream_->WriteOrBufferBody(body2, true);
 
@@ -1802,7 +1803,7 @@
                               helper_.GetStreamSendBufferAllocator(), 1024);
   QuicMemSliceStorage storage2(&body2_iov, 1,
                                helper_.GetStreamSendBufferAllocator(), 1024);
-  EXPECT_CALL(*session_, WritevData(_, _, _, _, _)).Times(AtLeast(1));
+  EXPECT_CALL(*session_, WritevData(_, _, _, _, _, _)).Times(AtLeast(1));
   stream_->WriteBodySlices(storage.ToSpan(), false);
   stream_->WriteBodySlices(storage2.ToSpan(), true);
 
@@ -1832,7 +1833,7 @@
   std::string body1 = "Test1";
   std::string body2(100, 'x');
 
-  EXPECT_CALL(*session_, WritevData(_, _, _, _, _)).Times(AtLeast(1));
+  EXPECT_CALL(*session_, WritevData(_, _, _, _, _, _)).Times(AtLeast(1));
   stream_->WriteOrBufferBody(body1, false);
   stream_->WriteOrBufferBody(body2, true);
 
@@ -2022,7 +2023,7 @@
       QuicSpdySessionPeer::GetQpackDecoderSendStream(session_.get());
 
   // The stream byte will be written in the first byte.
-  EXPECT_CALL(*session_, WritevData(decoder_send_stream->id(), _, _, _, _));
+  EXPECT_CALL(*session_, WritevData(decoder_send_stream->id(), _, _, _, _, _));
   // Deliver dynamic table entry to decoder.
   session_->qpack_decoder()->OnInsertWithoutNameReference("foo", "bar");
 
@@ -2044,7 +2045,7 @@
                                          headers.length(), data));
   EXPECT_EQ(kDataFramePayload, stream_->data());
 
-  EXPECT_CALL(*session_, WritevData(decoder_send_stream->id(), _, _, _, _));
+  EXPECT_CALL(*session_, WritevData(decoder_send_stream->id(), _, _, _, _, _));
   // Deliver second dynamic table entry to decoder.
   session_->qpack_decoder()->OnInsertWithoutNameReference("trailing", "foobar");
 
@@ -2085,7 +2086,7 @@
       QuicSpdySessionPeer::GetQpackDecoderSendStream(session_.get());
 
   // The stream byte will be written in the first byte.
-  EXPECT_CALL(*session_, WritevData(decoder_send_stream->id(), _, _, _, _));
+  EXPECT_CALL(*session_, WritevData(decoder_send_stream->id(), _, _, _, _, _));
   // Deliver dynamic table entry to decoder.
   session_->qpack_decoder()->OnInsertWithoutNameReference("foo", "bar");
   EXPECT_TRUE(stream_->headers_decompressed());
@@ -2110,7 +2111,7 @@
   // Decoding is blocked because dynamic table entry has not been received yet.
   EXPECT_FALSE(stream_->trailers_decompressed());
 
-  EXPECT_CALL(*session_, WritevData(decoder_send_stream->id(), _, _, _, _));
+  EXPECT_CALL(*session_, WritevData(decoder_send_stream->id(), _, _, _, _, _));
   // Deliver second dynamic table entry to decoder.
   session_->qpack_decoder()->OnInsertWithoutNameReference("trailing", "foobar");
   EXPECT_TRUE(stream_->trailers_decompressed());
@@ -2204,7 +2205,7 @@
       QuicSpdySessionPeer::GetQpackDecoderSendStream(session_.get());
 
   // The stream byte will be written in the first byte.
-  EXPECT_CALL(*session_, WritevData(decoder_send_stream->id(), _, _, _, _));
+  EXPECT_CALL(*session_, WritevData(decoder_send_stream->id(), _, _, _, _, _));
   // Deliver dynamic table entry to decoder.
   session_->qpack_decoder()->OnInsertWithoutNameReference("foo", "bar");
   EXPECT_TRUE(stream_->headers_decompressed());
@@ -2633,7 +2634,7 @@
 
   auto qpack_decoder_stream =
       QuicSpdySessionPeer::GetQpackDecoderSendStream(session_.get());
-  EXPECT_CALL(*session_, WritevData(qpack_decoder_stream->id(), 1, 1, _, _));
+  EXPECT_CALL(*session_, WritevData(qpack_decoder_stream->id(), 1, 1, _, _, _));
   EXPECT_CALL(*session_,
               SendRstStream(stream_->id(), QUIC_STREAM_CANCELLED, 0));
 
@@ -2651,7 +2652,7 @@
 
   auto qpack_decoder_stream =
       QuicSpdySessionPeer::GetQpackDecoderSendStream(session_.get());
-  EXPECT_CALL(*session_, WritevData(qpack_decoder_stream->id(), 1, 1, _, _));
+  EXPECT_CALL(*session_, WritevData(qpack_decoder_stream->id(), 1, 1, _, _, _));
 
   stream_->OnStreamReset(QuicRstStreamFrame(
       kInvalidControlFrameId, stream_->id(), QUIC_STREAM_CANCELLED, 0));
diff --git a/quic/core/qpack/qpack_send_stream_test.cc b/quic/core/qpack/qpack_send_stream_test.cc
index e3fcc15..d6a4df7 100644
--- a/quic/core/qpack/qpack_send_stream_test.cc
+++ b/quic/core/qpack/qpack_send_stream_test.cc
@@ -76,7 +76,7 @@
     qpack_send_stream_ =
         QuicSpdySessionPeer::GetQpackDecoderSendStream(&session_);
 
-    ON_CALL(session_, WritevData(_, _, _, _, _))
+    ON_CALL(session_, WritevData(_, _, _, _, _, _))
         .WillByDefault(Invoke(&session_, &MockQuicSpdySession::ConsumeData));
   }
 
@@ -96,13 +96,13 @@
 
 TEST_P(QpackSendStreamTest, WriteStreamTypeOnlyFirstTime) {
   std::string data = "data";
-  EXPECT_CALL(session_, WritevData(_, 1, _, _, _));
-  EXPECT_CALL(session_, WritevData(_, data.length(), _, _, _));
+  EXPECT_CALL(session_, WritevData(_, 1, _, _, _, _));
+  EXPECT_CALL(session_, WritevData(_, data.length(), _, _, _, _));
   qpack_send_stream_->WriteStreamData(quiche::QuicheStringPiece(data));
 
-  EXPECT_CALL(session_, WritevData(_, data.length(), _, _, _));
+  EXPECT_CALL(session_, WritevData(_, data.length(), _, _, _, _));
   qpack_send_stream_->WriteStreamData(quiche::QuicheStringPiece(data));
-  EXPECT_CALL(session_, WritevData(_, _, _, _, _)).Times(0);
+  EXPECT_CALL(session_, WritevData(_, _, _, _, _, _)).Times(0);
   qpack_send_stream_->MaybeSendStreamType();
 }
 
diff --git a/quic/core/quic_crypto_stream.cc b/quic/core/quic_crypto_stream.cc
index bf0106c..86603a9 100644
--- a/quic/core/quic_crypto_stream.cc
+++ b/quic/core/quic_crypto_stream.cc
@@ -10,10 +10,12 @@
 #include "net/third_party/quiche/src/quic/core/crypto/crypto_utils.h"
 #include "net/third_party/quiche/src/quic/core/quic_connection.h"
 #include "net/third_party/quiche/src/quic/core/quic_session.h"
+#include "net/third_party/quiche/src/quic/core/quic_types.h"
 #include "net/third_party/quiche/src/quic/core/quic_utils.h"
 #include "net/third_party/quiche/src/quic/platform/api/quic_flag_utils.h"
 #include "net/third_party/quiche/src/quic/platform/api/quic_flags.h"
 #include "net/third_party/quiche/src/quic/platform/api/quic_logging.h"
+#include "net/third_party/quiche/src/common/platform/api/quiche_optional.h"
 #include "net/third_party/quiche/src/common/platform/api/quiche_string_piece.h"
 
 namespace quic {
@@ -36,7 +38,8 @@
       substreams_{{{this, ENCRYPTION_INITIAL},
                    {this, ENCRYPTION_HANDSHAKE},
                    {this, ENCRYPTION_ZERO_RTT},
-                   {this, ENCRYPTION_FORWARD_SECURE}}} {
+                   {this, ENCRYPTION_FORWARD_SECURE}}},
+      writevdata_at_level_(GetQuicReloadableFlag(quic_writevdata_at_level)) {
   // The crypto stream is exempt from connection level flow control.
   DisableConnectionFlowControlForThisStream();
 }
@@ -282,25 +285,32 @@
     pending.offset = retransmission.begin()->min();
     pending.length =
         retransmission.begin()->max() - retransmission.begin()->min();
-    EncryptionLevel current_encryption_level =
-        session()->connection()->encryption_level();
-    // Set appropriate encryption level.
-    session()->connection()->SetDefaultEncryptionLevel(
-        retransmission_encryption_level);
-    QuicConsumedData consumed =
-        stream_delegate()->WritevData(id(), pending.length, pending.offset,
-                                      NO_FIN, /*is_retransmission*/ true);
-    QUIC_DVLOG(1) << ENDPOINT << "stream " << id()
-                  << " tries to retransmit stream data [" << pending.offset
-                  << ", " << pending.offset + pending.length
-                  << ") with encryption level: "
-                  << retransmission_encryption_level
-                  << ", consumed: " << consumed;
-    OnStreamFrameRetransmitted(pending.offset, consumed.bytes_consumed,
-                               consumed.fin_consumed);
-    // Restore encryption level.
-    session()->connection()->SetDefaultEncryptionLevel(
-        current_encryption_level);
+    QuicConsumedData consumed(0, false);
+    if (!writevdata_at_level_) {
+      EncryptionLevel current_encryption_level =
+          session()->connection()->encryption_level();
+      // Set appropriate encryption level.
+      session()->connection()->SetDefaultEncryptionLevel(
+          retransmission_encryption_level);
+      consumed = stream_delegate()->WritevData(
+          id(), pending.length, pending.offset, NO_FIN,
+          /*is_retransmission*/ true, QuicheNullOpt);
+      QUIC_DVLOG(1) << ENDPOINT << "stream " << id()
+                    << " tries to retransmit stream data [" << pending.offset
+                    << ", " << pending.offset + pending.length
+                    << ") with encryption level: "
+                    << retransmission_encryption_level
+                    << ", consumed: " << consumed;
+      OnStreamFrameRetransmitted(pending.offset, consumed.bytes_consumed,
+                                 consumed.fin_consumed);
+      // Restore encryption level.
+      session()->connection()->SetDefaultEncryptionLevel(
+          current_encryption_level);
+    } else {
+      QUIC_RELOADABLE_FLAG_COUNT_N(quic_writevdata_at_level, 1, 2);
+      consumed = RetransmitStreamDataAtLevel(pending.offset, pending.length,
+                                             retransmission_encryption_level);
+    }
     if (consumed.bytes_consumed < pending.length) {
       // The connection is write blocked.
       break;
@@ -328,22 +338,29 @@
   for (const auto& interval : retransmission) {
     QuicStreamOffset retransmission_offset = interval.min();
     QuicByteCount retransmission_length = interval.max() - interval.min();
-    // Set appropriate encryption level.
-    session()->connection()->SetDefaultEncryptionLevel(send_encryption_level);
-    QuicConsumedData consumed = stream_delegate()->WritevData(
-        id(), retransmission_length, retransmission_offset, NO_FIN,
-        /*is_retransmission*/ true);
-    QUIC_DVLOG(1) << ENDPOINT << "stream " << id()
-                  << " is forced to retransmit stream data ["
-                  << retransmission_offset << ", "
-                  << retransmission_offset + retransmission_length
-                  << "), with encryption level: " << send_encryption_level
-                  << ", consumed: " << consumed;
-    OnStreamFrameRetransmitted(retransmission_offset, consumed.bytes_consumed,
-                               consumed.fin_consumed);
-    // Restore encryption level.
-    session()->connection()->SetDefaultEncryptionLevel(
-        current_encryption_level);
+    QuicConsumedData consumed(0, false);
+    if (!writevdata_at_level_) {
+      // Set appropriate encryption level.
+      session()->connection()->SetDefaultEncryptionLevel(send_encryption_level);
+      consumed = stream_delegate()->WritevData(
+          id(), retransmission_length, retransmission_offset, NO_FIN,
+          /*is_retransmission*/ true, QuicheNullOpt);
+      QUIC_DVLOG(1) << ENDPOINT << "stream " << id()
+                    << " is forced to retransmit stream data ["
+                    << retransmission_offset << ", "
+                    << retransmission_offset + retransmission_length
+                    << "), with encryption level: " << send_encryption_level
+                    << ", consumed: " << consumed;
+      OnStreamFrameRetransmitted(retransmission_offset, consumed.bytes_consumed,
+                                 consumed.fin_consumed);
+      // Restore encryption level.
+      session()->connection()->SetDefaultEncryptionLevel(
+          current_encryption_level);
+    } else {
+      QUIC_RELOADABLE_FLAG_COUNT_N(quic_writevdata_at_level, 2, 2);
+      consumed = RetransmitStreamDataAtLevel(
+          retransmission_offset, retransmission_length, send_encryption_level);
+    }
     if (consumed.bytes_consumed < retransmission_length) {
       // The connection is write blocked.
       return false;
@@ -353,6 +370,26 @@
   return true;
 }
 
+QuicConsumedData QuicCryptoStream::RetransmitStreamDataAtLevel(
+    QuicStreamOffset retransmission_offset,
+    QuicByteCount retransmission_length,
+    EncryptionLevel encryption_level) {
+  DCHECK(writevdata_at_level_);
+  const auto consumed = stream_delegate()->WritevData(
+      id(), retransmission_length, retransmission_offset, NO_FIN,
+      /*is_retransmission*/ true, encryption_level);
+  QUIC_DVLOG(1) << ENDPOINT << "stream " << id()
+                << " is forced to retransmit stream data ["
+                << retransmission_offset << ", "
+                << retransmission_offset + retransmission_length
+                << "), with encryption level: " << encryption_level
+                << ", consumed: " << consumed;
+  OnStreamFrameRetransmitted(retransmission_offset, consumed.bytes_consumed,
+                             consumed.fin_consumed);
+
+  return consumed;
+}
+
 uint64_t QuicCryptoStream::crypto_bytes_read() const {
   if (!QuicVersionUsesCryptoFrames(session()->transport_version())) {
     return stream_bytes_read();
diff --git a/quic/core/quic_crypto_stream.h b/quic/core/quic_crypto_stream.h
index ecd3201..d07a4e7 100644
--- a/quic/core/quic_crypto_stream.h
+++ b/quic/core/quic_crypto_stream.h
@@ -14,6 +14,7 @@
 #include "net/third_party/quiche/src/quic/core/quic_config.h"
 #include "net/third_party/quiche/src/quic/core/quic_packets.h"
 #include "net/third_party/quiche/src/quic/core/quic_stream.h"
+#include "net/third_party/quiche/src/quic/core/quic_types.h"
 #include "net/third_party/quiche/src/quic/platform/api/quic_export.h"
 #include "net/third_party/quiche/src/common/platform/api/quiche_string_piece.h"
 
@@ -120,6 +121,12 @@
                             QuicByteCount data_length,
                             bool fin) override;
 
+  // Sends stream retransmission data at |encryption_level|.
+  QuicConsumedData RetransmitStreamDataAtLevel(
+      QuicStreamOffset retransmission_offset,
+      QuicByteCount retransmission_length,
+      EncryptionLevel encryption_level);
+
   // Returns the number of bytes of handshake data that have been received from
   // the peer in either CRYPTO or STREAM frames.
   uint64_t crypto_bytes_read() const;
@@ -186,6 +193,9 @@
   // Keeps state for data sent/received in CRYPTO frames at each encryption
   // level.
   std::array<CryptoSubstream, NUM_ENCRYPTION_LEVELS> substreams_;
+
+  // Latched value of gfe2_reloadable_flag_quic_writevdata_at_level.
+  const bool writevdata_at_level_;
 };
 
 }  // namespace quic
diff --git a/quic/core/quic_crypto_stream_test.cc b/quic/core/quic_crypto_stream_test.cc
index 2006e47..e3ba21c 100644
--- a/quic/core/quic_crypto_stream_test.cc
+++ b/quic/core/quic_crypto_stream_test.cc
@@ -158,7 +158,7 @@
   EXPECT_CALL(
       session_,
       WritevData(QuicUtils::GetCryptoStreamId(connection_->transport_version()),
-                 1350, 0, _, _))
+                 1350, 0, _, _, _))
       .WillOnce(Invoke(&session_, &MockQuicSpdySession::ConsumeData));
   stream_->WriteOrBufferData(data, false, nullptr);
   // Send [1350, 2700) in ENCRYPTION_ZERO_RTT.
@@ -167,7 +167,7 @@
   EXPECT_CALL(
       session_,
       WritevData(QuicUtils::GetCryptoStreamId(connection_->transport_version()),
-                 1350, 1350, _, _))
+                 1350, 1350, _, _, _))
       .WillOnce(Invoke(&session_, &MockQuicSpdySession::ConsumeData));
   stream_->WriteOrBufferData(data, false, nullptr);
   connection_->SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE);
@@ -181,19 +181,19 @@
   EXPECT_CALL(
       session_,
       WritevData(QuicUtils::GetCryptoStreamId(connection_->transport_version()),
-                 1000, 0, _, _))
+                 1000, 0, _, _, _))
       .WillOnce(Invoke(&session_, &MockQuicSpdySession::ConsumeData));
   // Verify [1200, 2000) are sent in [1200, 1350) and [1350, 2000) because of
   // they are in different encryption levels.
   EXPECT_CALL(
       session_,
       WritevData(QuicUtils::GetCryptoStreamId(connection_->transport_version()),
-                 150, 1200, _, _))
+                 150, 1200, _, _, _))
       .WillOnce(Invoke(&session_, &MockQuicSpdySession::ConsumeData));
   EXPECT_CALL(
       session_,
       WritevData(QuicUtils::GetCryptoStreamId(connection_->transport_version()),
-                 650, 1350, _, _))
+                 650, 1350, _, _, _))
       .WillOnce(Invoke(&session_, &MockQuicSpdySession::ConsumeData));
   stream_->OnCanWrite();
   EXPECT_FALSE(stream_->HasPendingRetransmission());
@@ -263,7 +263,7 @@
   EXPECT_CALL(
       session_,
       WritevData(QuicUtils::GetCryptoStreamId(connection_->transport_version()),
-                 1350, 0, _, _))
+                 1350, 0, _, _, _))
       .WillOnce(Invoke(&session_, &MockQuicSpdySession::ConsumeData));
   stream_->WriteOrBufferData(data, false, nullptr);
   // Send [1350, 2700) in ENCRYPTION_ZERO_RTT.
@@ -272,7 +272,7 @@
   EXPECT_CALL(
       session_,
       WritevData(QuicUtils::GetCryptoStreamId(connection_->transport_version()),
-                 1350, 1350, _, _))
+                 1350, 1350, _, _, _))
       .WillOnce(Invoke(&session_, &MockQuicSpdySession::ConsumeData));
   stream_->WriteOrBufferData(data, false, nullptr);
 
@@ -347,7 +347,7 @@
   EXPECT_CALL(
       session_,
       WritevData(QuicUtils::GetCryptoStreamId(connection_->transport_version()),
-                 1350, 0, _, _))
+                 1350, 0, _, _, _))
       .WillOnce(Invoke(&session_, &MockQuicSpdySession::ConsumeData));
   stream_->WriteOrBufferData(data, false, nullptr);
   // Send [1350, 2700) in ENCRYPTION_ZERO_RTT.
@@ -356,7 +356,7 @@
   EXPECT_CALL(
       session_,
       WritevData(QuicUtils::GetCryptoStreamId(connection_->transport_version()),
-                 1350, 1350, _, _))
+                 1350, 1350, _, _, _))
       .WillOnce(Invoke(&session_, &MockQuicSpdySession::ConsumeData));
   stream_->WriteOrBufferData(data, false, nullptr);
   connection_->SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE);
@@ -372,11 +372,11 @@
   EXPECT_CALL(
       session_,
       WritevData(QuicUtils::GetCryptoStreamId(connection_->transport_version()),
-                 650, 1350, _, _))
+                 650, 1350, _, _, _))
       .WillOnce(InvokeWithoutArgs([this]() {
         return session_.ConsumeData(
             QuicUtils::GetCryptoStreamId(connection_->transport_version()), 150,
-            1350, NO_FIN, 1350);
+            1350, NO_FIN, 1350, QuicheNullOpt);
       }));
 
   EXPECT_FALSE(stream_->RetransmitStreamData(1350, 1350, false));
@@ -387,18 +387,18 @@
   EXPECT_CALL(
       session_,
       WritevData(QuicUtils::GetCryptoStreamId(connection_->transport_version()),
-                 650, 1350, _, _))
+                 650, 1350, _, _, _))
       .WillOnce(Invoke(&session_, &MockQuicSpdySession::ConsumeData));
   EXPECT_CALL(
       session_,
       WritevData(QuicUtils::GetCryptoStreamId(connection_->transport_version()),
-                 200, 2500, _, _))
+                 200, 2500, _, _, _))
       .WillOnce(Invoke(&session_, &MockQuicSpdySession::ConsumeData));
   EXPECT_TRUE(stream_->RetransmitStreamData(1350, 1350, false));
   // Verify connection's encryption level has restored.
   EXPECT_EQ(ENCRYPTION_FORWARD_SECURE, connection_->encryption_level());
 
-  EXPECT_CALL(session_, WritevData(_, _, _, _, _)).Times(0);
+  EXPECT_CALL(session_, WritevData(_, _, _, _, _, _)).Times(0);
   // Force to send an empty frame.
   EXPECT_TRUE(stream_->RetransmitStreamData(0, 0, false));
 }
@@ -470,7 +470,7 @@
   EXPECT_CALL(
       session_,
       WritevData(QuicUtils::GetCryptoStreamId(connection_->transport_version()),
-                 1350, 0, _, _))
+                 1350, 0, _, _, _))
       .WillOnce(testing::Return(QuicConsumedData(0, false)));
   stream_->WriteOrBufferData(data, false, nullptr);
   EXPECT_FALSE(stream_->IsWaitingForAcks());
@@ -481,7 +481,7 @@
   EXPECT_CALL(
       session_,
       WritevData(QuicUtils::GetCryptoStreamId(connection_->transport_version()),
-                 1350, 0, _, _))
+                 1350, 0, _, _, _))
       .WillOnce(Invoke(&session_, &MockQuicSpdySession::ConsumeData));
   stream_->OnCanWrite();
   EXPECT_TRUE(stream_->IsWaitingForAcks());
diff --git a/quic/core/quic_session.cc b/quic/core/quic_session.cc
index c7890d7..1cc1d90 100644
--- a/quic/core/quic_session.cc
+++ b/quic/core/quic_session.cc
@@ -732,11 +732,13 @@
   connection_->ProcessUdpPacket(self_address, peer_address, packet);
 }
 
-QuicConsumedData QuicSession::WritevData(QuicStreamId id,
-                                         size_t write_length,
-                                         QuicStreamOffset offset,
-                                         StreamSendingState state,
-                                         bool is_retransmission) {
+QuicConsumedData QuicSession::WritevData(
+    QuicStreamId id,
+    size_t write_length,
+    QuicStreamOffset offset,
+    StreamSendingState state,
+    bool is_retransmission,
+    quiche::QuicheOptional<EncryptionLevel> level) {
   DCHECK(connection_->connected())
       << ENDPOINT << "Try to write stream data when connection is closed.";
   if (!IsEncryptionEstablished() &&
@@ -746,12 +748,23 @@
     return QuicConsumedData(0, false);
   }
 
+  const auto current_level = connection()->encryption_level();
+  if (level.has_value()) {
+    connection()->SetDefaultEncryptionLevel(level.value());
+  }
+
   QuicConsumedData data =
       connection_->SendStreamData(id, write_length, offset, state);
   if (!is_retransmission) {
     // This is new stream data.
     write_blocked_streams_.UpdateBytesForStream(id, data.bytes_consumed);
   }
+
+  // Restore the encryption level.
+  if (level.has_value()) {
+    connection()->SetDefaultEncryptionLevel(current_level);
+  }
+
   return data;
 }
 
diff --git a/quic/core/quic_session.h b/quic/core/quic_session.h
index beb6763..4549878 100644
--- a/quic/core/quic_session.h
+++ b/quic/core/quic_session.h
@@ -268,11 +268,13 @@
   // indicating if the fin bit was consumed.  This does not indicate the data
   // has been sent on the wire: it may have been turned into a packet and queued
   // if the socket was unexpectedly blocked.
-  QuicConsumedData WritevData(QuicStreamId id,
-                              size_t write_length,
-                              QuicStreamOffset offset,
-                              StreamSendingState state,
-                              bool is_retransmission) override;
+  QuicConsumedData WritevData(
+      QuicStreamId id,
+      size_t write_length,
+      QuicStreamOffset offset,
+      StreamSendingState state,
+      bool is_retransmission,
+      quiche::QuicheOptional<EncryptionLevel> level) override;
 
   // Called by the QuicCryptoStream when a handshake message is sent.
   virtual void OnCryptoHandshakeMessageSent(
diff --git a/quic/core/quic_session_test.cc b/quic/core/quic_session_test.cc
index d9ecbae..93c3a9b 100644
--- a/quic/core/quic_session_test.cc
+++ b/quic/core/quic_session_test.cc
@@ -36,6 +36,7 @@
 #include "net/third_party/quiche/src/quic/test_tools/quic_stream_send_buffer_peer.h"
 #include "net/third_party/quiche/src/quic/test_tools/quic_test_utils.h"
 #include "net/third_party/quiche/src/common/platform/api/quiche_arraysize.h"
+#include "net/third_party/quiche/src/common/platform/api/quiche_optional.h"
 #include "net/third_party/quiche/src/common/platform/api/quiche_str_cat.h"
 #include "net/third_party/quiche/src/common/platform/api/quiche_string_piece.h"
 
@@ -261,16 +262,18 @@
     return GetNumActiveStreams() > 0;
   }
 
-  QuicConsumedData WritevData(QuicStreamId id,
-                              size_t write_length,
-                              QuicStreamOffset offset,
-                              StreamSendingState state,
-                              bool is_retransmission) override {
+  QuicConsumedData WritevData(
+      QuicStreamId id,
+      size_t write_length,
+      QuicStreamOffset offset,
+      StreamSendingState state,
+      bool is_retransmission,
+      quiche::QuicheOptional<EncryptionLevel> level) override {
     bool fin = state != NO_FIN;
     QuicConsumedData consumed(write_length, fin);
     if (!writev_consumes_all_data_) {
       consumed = QuicSession::WritevData(id, write_length, offset, state,
-                                         is_retransmission);
+                                         is_retransmission, level);
     }
     QuicSessionPeer::GetWriteBlockedStreams(this)->UpdateBytesForStream(
         id, consumed.bytes_consumed);
@@ -292,8 +295,8 @@
     }
     MakeIOVector("not empty", &iov);
     QuicStreamPeer::SendBuffer(stream).SaveStreamData(&iov, 1, 0, 9);
-    QuicConsumedData consumed =
-        WritevData(stream->id(), 9, 0, FIN, /*is_retransmission*/ false);
+    QuicConsumedData consumed = WritevData(
+        stream->id(), 9, 0, FIN, /*is_retransmission*/ false, QuicheNullOpt);
     QuicStreamPeer::SendBuffer(stream).OnStreamDataConsumed(
         consumed.bytes_consumed);
     return consumed;
@@ -310,7 +313,7 @@
   QuicConsumedData SendLargeFakeData(QuicStream* stream, int bytes) {
     DCHECK(writev_consumes_all_data_);
     return WritevData(stream->id(), bytes, 0, FIN,
-                      /*is_retransmission*/ false);
+                      /*is_retransmission*/ false, QuicheNullOpt);
   }
 
   bool UsesPendingStreams() const override { return uses_pending_streams_; }
diff --git a/quic/core/quic_stream.cc b/quic/core/quic_stream.cc
index ca33a0c..d952cc0 100644
--- a/quic/core/quic_stream.cc
+++ b/quic/core/quic_stream.cc
@@ -15,6 +15,7 @@
 #include "net/third_party/quiche/src/quic/platform/api/quic_flag_utils.h"
 #include "net/third_party/quiche/src/quic/platform/api/quic_flags.h"
 #include "net/third_party/quiche/src/quic/platform/api/quic_logging.h"
+#include "net/third_party/quiche/src/common/platform/api/quiche_optional.h"
 #include "net/third_party/quiche/src/common/platform/api/quiche_str_cat.h"
 #include "net/third_party/quiche/src/common/platform/api/quiche_string_piece.h"
 
@@ -932,7 +933,8 @@
                            stream_bytes_written());
     consumed = stream_delegate_->WritevData(
         id_, retransmission_length, retransmission_offset,
-        can_bundle_fin ? FIN : NO_FIN, /*is_retransmission*/ true);
+        can_bundle_fin ? FIN : NO_FIN, /*is_retransmission*/ true,
+        QuicheNullOpt);
     QUIC_DVLOG(1) << ENDPOINT << "stream " << id_
                   << " is forced to retransmit stream data ["
                   << retransmission_offset << ", "
@@ -953,8 +955,9 @@
   if (retransmit_fin) {
     QUIC_DVLOG(1) << ENDPOINT << "stream " << id_
                   << " retransmits fin only frame.";
-    consumed = stream_delegate_->WritevData(id_, 0, stream_bytes_written(), FIN,
-                                            /*is_retransmission*/ true);
+    consumed =
+        stream_delegate_->WritevData(id_, 0, stream_bytes_written(), FIN,
+                                     /*is_retransmission*/ true, QuicheNullOpt);
     if (!consumed.fin_consumed) {
       return false;
     }
@@ -1024,9 +1027,9 @@
   if (fin && add_random_padding_after_fin_) {
     state = FIN_AND_PADDING;
   }
-  QuicConsumedData consumed_data =
-      stream_delegate_->WritevData(id(), write_length, stream_bytes_written(),
-                                   state, /*is_retransmission*/ false);
+  QuicConsumedData consumed_data = stream_delegate_->WritevData(
+      id(), write_length, stream_bytes_written(), state,
+      /*is_retransmission*/ false, QuicheNullOpt);
 
   OnStreamDataConsumed(consumed_data.bytes_consumed);
 
@@ -1100,8 +1103,9 @@
     if (!send_buffer_.HasPendingRetransmission()) {
       QUIC_DVLOG(1) << ENDPOINT << "stream " << id_
                     << " retransmits fin only frame.";
-      consumed = stream_delegate_->WritevData(id_, 0, stream_bytes_written(),
-                                              FIN, /*is_retransmission*/ true);
+      consumed = stream_delegate_->WritevData(
+          id_, 0, stream_bytes_written(), FIN,
+          /*is_retransmission*/ true, QuicheNullOpt);
       fin_lost_ = !consumed.fin_consumed;
       if (fin_lost_) {
         // Connection is write blocked.
@@ -1116,7 +1120,7 @@
           (pending.offset + pending.length == stream_bytes_written());
       consumed = stream_delegate_->WritevData(
           id_, pending.length, pending.offset, can_bundle_fin ? FIN : NO_FIN,
-          /*is_retransmission*/ true);
+          /*is_retransmission*/ true, QuicheNullOpt);
       QUIC_DVLOG(1) << ENDPOINT << "stream " << id_
                     << " tries to retransmit stream data [" << pending.offset
                     << ", " << pending.offset + pending.length
diff --git a/quic/core/quic_stream_test.cc b/quic/core/quic_stream_test.cc
index c7e650b..4055b4c 100644
--- a/quic/core/quic_stream_test.cc
+++ b/quic/core/quic_stream_test.cc
@@ -31,6 +31,7 @@
 #include "net/third_party/quiche/src/quic/test_tools/quic_stream_sequencer_peer.h"
 #include "net/third_party/quiche/src/quic/test_tools/quic_test_utils.h"
 #include "net/third_party/quiche/src/common/platform/api/quiche_arraysize.h"
+#include "net/third_party/quiche/src/common/platform/api/quiche_optional.h"
 #include "net/third_party/quiche/src/common/platform/api/quiche_string_piece.h"
 
 using testing::_;
@@ -122,11 +123,13 @@
            write_blocked_list_->HasWriteBlockedDataStreams();
   }
 
-  QuicConsumedData CloseStreamOnWriteError(QuicStreamId id,
-                                           size_t /*write_length*/,
-                                           QuicStreamOffset /*offset*/,
-                                           StreamSendingState /*state*/,
-                                           QuicByteCount /*bytes_written*/) {
+  QuicConsumedData CloseStreamOnWriteError(
+      QuicStreamId id,
+      size_t /*write_length*/,
+      QuicStreamOffset /*offset*/,
+      StreamSendingState /*state*/,
+      QuicByteCount /*bytes_written*/,
+      quiche::QuicheOptional<EncryptionLevel> /*level*/) {
     session_->CloseStream(id);
     return QuicConsumedData(1, false);
   }
@@ -277,7 +280,7 @@
               VARIABLE_LENGTH_INTEGER_LENGTH_0, 0u);
   connection_->SetMaxPacketLength(length);
 
-  EXPECT_CALL(*session_, WritevData(kTestStreamId, _, _, _, _))
+  EXPECT_CALL(*session_, WritevData(kTestStreamId, _, _, _, _, _))
       .WillOnce(Invoke(session_.get(), &MockQuicSession::ConsumeData));
   stream_->WriteOrBufferData(kData1, false, nullptr);
   EXPECT_FALSE(HasWriteBlockedStreams());
@@ -299,9 +302,10 @@
 
   // Write some data and no fin.  If we consume some but not all of the data,
   // we should be write blocked a not all the data was consumed.
-  EXPECT_CALL(*session_, WritevData(kTestStreamId, _, _, _, _))
+  EXPECT_CALL(*session_, WritevData(kTestStreamId, _, _, _, _, _))
       .WillOnce(InvokeWithoutArgs([this]() {
-        return session_->ConsumeData(stream_->id(), 1u, 0u, NO_FIN, false);
+        return session_->ConsumeData(stream_->id(), 1u, 0u, NO_FIN, false,
+                                     QuicheNullOpt);
       }));
   stream_->WriteOrBufferData(quiche::QuicheStringPiece(kData1, 2), false,
                              nullptr);
@@ -317,9 +321,10 @@
   // we should be write blocked because the fin was not consumed.
   // (This should never actually happen as the fin should be sent out with the
   // last data)
-  EXPECT_CALL(*session_, WritevData(kTestStreamId, _, _, _, _))
+  EXPECT_CALL(*session_, WritevData(kTestStreamId, _, _, _, _, _))
       .WillOnce(InvokeWithoutArgs([this]() {
-        return session_->ConsumeData(stream_->id(), 2u, 0u, NO_FIN, false);
+        return session_->ConsumeData(stream_->id(), 2u, 0u, NO_FIN, false,
+                                     QuicheNullOpt);
       }));
   stream_->WriteOrBufferData(quiche::QuicheStringPiece(kData1, 2), true,
                              nullptr);
@@ -332,7 +337,7 @@
 
   // Write no data and a fin.  If we consume nothing we should be write blocked,
   // as the fin was not consumed.
-  EXPECT_CALL(*session_, WritevData(kTestStreamId, _, _, _, _))
+  EXPECT_CALL(*session_, WritevData(kTestStreamId, _, _, _, _, _))
       .WillOnce(Return(QuicConsumedData(0, false)));
   stream_->WriteOrBufferData(quiche::QuicheStringPiece(), true, nullptr);
   ASSERT_EQ(1u, write_blocked_list_->NumBlockedStreams());
@@ -344,7 +349,7 @@
   // Write some data and no fin. However, while writing the data
   // close the stream and verify that MarkConnectionLevelWriteBlocked does not
   // crash with an unknown stream.
-  EXPECT_CALL(*session_, WritevData(kTestStreamId, _, _, _, _))
+  EXPECT_CALL(*session_, WritevData(kTestStreamId, _, _, _, _, _))
       .WillOnce(Invoke(this, &QuicStreamTest::CloseStreamOnWriteError));
   stream_->WriteOrBufferData(quiche::QuicheStringPiece(kData1, 2), false,
                              nullptr);
@@ -364,10 +369,10 @@
               VARIABLE_LENGTH_INTEGER_LENGTH_0, 0u);
   connection_->SetMaxPacketLength(length);
 
-  EXPECT_CALL(*session_, WritevData(_, _, _, _, _))
+  EXPECT_CALL(*session_, WritevData(_, _, _, _, _, _))
       .WillOnce(InvokeWithoutArgs([this]() {
         return session_->ConsumeData(stream_->id(), kDataLen - 1, 0u, NO_FIN,
-                                     false);
+                                     false, QuicheNullOpt);
       }));
   stream_->WriteOrBufferData(kData1, false, nullptr);
 
@@ -380,20 +385,20 @@
   EXPECT_EQ(10u, stream_->BufferedDataBytes());
   // Make sure we get the tail of the first write followed by the bytes_consumed
   InSequence s;
-  EXPECT_CALL(*session_, WritevData(_, _, _, _, _))
+  EXPECT_CALL(*session_, WritevData(_, _, _, _, _, _))
       .WillOnce(InvokeWithoutArgs([this]() {
         return session_->ConsumeData(stream_->id(), kDataLen - 1, kDataLen - 1,
-                                     NO_FIN, false);
+                                     NO_FIN, false, QuicheNullOpt);
       }));
   EXPECT_CALL(*stream_, OnCanWriteNewData());
   stream_->OnCanWrite();
   EXPECT_TRUE(session_->HasUnackedStreamData());
 
   // And finally the end of the bytes_consumed.
-  EXPECT_CALL(*session_, WritevData(_, _, _, _, _))
+  EXPECT_CALL(*session_, WritevData(_, _, _, _, _, _))
       .WillOnce(InvokeWithoutArgs([this]() {
         return session_->ConsumeData(stream_->id(), 2u, 2 * kDataLen - 2,
-                                     NO_FIN, false);
+                                     NO_FIN, false, QuicheNullOpt);
       }));
   EXPECT_CALL(*stream_, OnCanWriteNewData());
   stream_->OnCanWrite();
@@ -405,7 +410,7 @@
   std::string data("aaaaa");
   QuicStreamPeer::SetStreamBytesWritten(kMaxStreamLength - data.length(),
                                         stream_);
-  EXPECT_CALL(*session_, WritevData(_, _, _, _, _))
+  EXPECT_CALL(*session_, WritevData(_, _, _, _, _, _))
       .WillOnce(Invoke(session_.get(), &MockQuicSession::ConsumeData));
   stream_->WriteOrBufferData(data, false, nullptr);
   EXPECT_TRUE(session_->HasUnackedStreamData());
@@ -437,9 +442,10 @@
   EXPECT_FALSE(rst_sent());
 
   // Write some data, with no FIN.
-  EXPECT_CALL(*session_, WritevData(kTestStreamId, _, _, _, _))
+  EXPECT_CALL(*session_, WritevData(kTestStreamId, _, _, _, _, _))
       .WillOnce(InvokeWithoutArgs([this]() {
-        return session_->ConsumeData(stream_->id(), 1u, 0u, NO_FIN, false);
+        return session_->ConsumeData(stream_->id(), 1u, 0u, NO_FIN, false,
+                                     QuicheNullOpt);
       }));
   stream_->WriteOrBufferData(quiche::QuicheStringPiece(kData1, 1), false,
                              nullptr);
@@ -465,9 +471,10 @@
   EXPECT_FALSE(rst_sent());
 
   // Write some data, with FIN.
-  EXPECT_CALL(*session_, WritevData(kTestStreamId, _, _, _, _))
+  EXPECT_CALL(*session_, WritevData(kTestStreamId, _, _, _, _, _))
       .WillOnce(InvokeWithoutArgs([this]() {
-        return session_->ConsumeData(stream_->id(), 1u, 0u, FIN, false);
+        return session_->ConsumeData(stream_->id(), 1u, 0u, FIN, false,
+                                     QuicheNullOpt);
       }));
   stream_->WriteOrBufferData(quiche::QuicheStringPiece(kData1, 1), true,
                              nullptr);
@@ -730,9 +737,10 @@
   EXPECT_EQ(1u, session_->GetNumOpenIncomingStreams());
 
   // Outgoing data with FIN.
-  EXPECT_CALL(*session_, WritevData(kTestStreamId, _, _, _, _))
+  EXPECT_CALL(*session_, WritevData(kTestStreamId, _, _, _, _, _))
       .WillOnce(InvokeWithoutArgs([this]() {
-        return session_->ConsumeData(stream_->id(), 2u, 0u, FIN, false);
+        return session_->ConsumeData(stream_->id(), 2u, 0u, FIN, false,
+                                     QuicheNullOpt);
       }));
   stream_->WriteOrBufferData(quiche::QuicheStringPiece(kData1, 2), true,
                              nullptr);
@@ -748,9 +756,10 @@
   Initialize();
 
   // Outgoing data with FIN.
-  EXPECT_CALL(*session_, WritevData(kTestStreamId, _, _, _, _))
+  EXPECT_CALL(*session_, WritevData(kTestStreamId, _, _, _, _, _))
       .WillOnce(InvokeWithoutArgs([this]() {
-        return session_->ConsumeData(stream_->id(), 2u, 0u, FIN, false);
+        return session_->ConsumeData(stream_->id(), 2u, 0u, FIN, false,
+                                     QuicheNullOpt);
       }));
   stream_->WriteOrBufferData(quiche::QuicheStringPiece(kData1, 2), true,
                              nullptr);
@@ -777,7 +786,7 @@
 
   Initialize();
   EXPECT_CALL(*connection_, CloseConnection(_, _, _)).Times(0);
-  EXPECT_CALL(*session_, WritevData(_, _, _, _, _))
+  EXPECT_CALL(*session_, WritevData(_, _, _, _, _, _))
       .WillRepeatedly(Invoke(session_.get(), &MockQuicSession::ConsumeData));
 
   // Receive data for the request.
@@ -799,7 +808,7 @@
 
 TEST_P(QuicStreamTest, StreamWaitsForAcks) {
   Initialize();
-  EXPECT_CALL(*session_, WritevData(_, _, _, _, _))
+  EXPECT_CALL(*session_, WritevData(_, _, _, _, _, _))
       .WillRepeatedly(Invoke(session_.get(), &MockQuicSession::ConsumeData));
   // Stream is not waiting for acks initially.
   EXPECT_FALSE(stream_->IsWaitingForAcks());
@@ -856,7 +865,7 @@
 
 TEST_P(QuicStreamTest, StreamDataGetAckedOutOfOrder) {
   Initialize();
-  EXPECT_CALL(*session_, WritevData(_, _, _, _, _))
+  EXPECT_CALL(*session_, WritevData(_, _, _, _, _, _))
       .WillRepeatedly(Invoke(session_.get(), &MockQuicSession::ConsumeData));
   // Send data.
   stream_->WriteOrBufferData(kData1, false, nullptr);
@@ -898,7 +907,7 @@
 
 TEST_P(QuicStreamTest, CancelStream) {
   Initialize();
-  EXPECT_CALL(*session_, WritevData(_, _, _, _, _))
+  EXPECT_CALL(*session_, WritevData(_, _, _, _, _, _))
       .WillRepeatedly(Invoke(session_.get(), &MockQuicSession::ConsumeData));
   EXPECT_FALSE(stream_->IsWaitingForAcks());
   EXPECT_FALSE(session_->HasUnackedStreamData());
@@ -940,7 +949,7 @@
   }
 
   Initialize();
-  EXPECT_CALL(*session_, WritevData(_, _, _, _, _))
+  EXPECT_CALL(*session_, WritevData(_, _, _, _, _, _))
       .WillRepeatedly(Invoke(session_.get(), &MockQuicSession::ConsumeData));
   EXPECT_FALSE(stream_->IsWaitingForAcks());
   EXPECT_FALSE(session_->HasUnackedStreamData());
@@ -966,7 +975,7 @@
 
 TEST_P(QuicStreamTest, RstFrameReceivedStreamFinishSending) {
   Initialize();
-  EXPECT_CALL(*session_, WritevData(_, _, _, _, _))
+  EXPECT_CALL(*session_, WritevData(_, _, _, _, _, _))
       .WillRepeatedly(Invoke(session_.get(), &MockQuicSession::ConsumeData));
   EXPECT_FALSE(stream_->IsWaitingForAcks());
   EXPECT_FALSE(session_->HasUnackedStreamData());
@@ -989,7 +998,7 @@
 
 TEST_P(QuicStreamTest, ConnectionClosed) {
   Initialize();
-  EXPECT_CALL(*session_, WritevData(_, _, _, _, _))
+  EXPECT_CALL(*session_, WritevData(_, _, _, _, _, _))
       .WillRepeatedly(Invoke(session_.get(), &MockQuicSession::ConsumeData));
   EXPECT_FALSE(stream_->IsWaitingForAcks());
   EXPECT_FALSE(session_->HasUnackedStreamData());
@@ -1024,9 +1033,10 @@
   EXPECT_TRUE(stream_->CanWriteNewData());
 
   // Testing WriteOrBufferData.
-  EXPECT_CALL(*session_, WritevData(_, _, _, _, _))
+  EXPECT_CALL(*session_, WritevData(_, _, _, _, _, _))
       .WillOnce(InvokeWithoutArgs([this]() {
-        return session_->ConsumeData(stream_->id(), 100u, 0u, NO_FIN, false);
+        return session_->ConsumeData(stream_->id(), 100u, 0u, NO_FIN, false,
+                                     QuicheNullOpt);
       }));
   stream_->WriteOrBufferData(data, false, nullptr);
   stream_->WriteOrBufferData(data, false, nullptr);
@@ -1036,9 +1046,10 @@
   // Verify all data is saved.
   EXPECT_EQ(3 * data.length() - 100, stream_->BufferedDataBytes());
 
-  EXPECT_CALL(*session_, WritevData(_, _, _, _, _))
+  EXPECT_CALL(*session_, WritevData(_, _, _, _, _, _))
       .WillOnce(InvokeWithoutArgs([this]() {
-        return session_->ConsumeData(stream_->id(), 100, 100u, NO_FIN, false);
+        return session_->ConsumeData(stream_->id(), 100, 100u, NO_FIN, false,
+                                     QuicheNullOpt);
       }));
   // Buffered data size > threshold, do not ask upper layer for more data.
   EXPECT_CALL(*stream_, OnCanWriteNewData()).Times(0);
@@ -1049,10 +1060,10 @@
   // Send buffered data to make buffered data size < threshold.
   size_t data_to_write = 3 * data.length() - 200 -
                          GetQuicFlag(FLAGS_quic_buffered_data_threshold) + 1;
-  EXPECT_CALL(*session_, WritevData(_, _, _, _, _))
+  EXPECT_CALL(*session_, WritevData(_, _, _, _, _, _))
       .WillOnce(InvokeWithoutArgs([this, data_to_write]() {
         return session_->ConsumeData(stream_->id(), data_to_write, 200u, NO_FIN,
-                                     false);
+                                     false, QuicheNullOpt);
       }));
   // Buffered data size < threshold, ask upper layer for more data.
   EXPECT_CALL(*stream_, OnCanWriteNewData()).Times(1);
@@ -1063,7 +1074,7 @@
   EXPECT_TRUE(stream_->CanWriteNewData());
 
   // Flush all buffered data.
-  EXPECT_CALL(*session_, WritevData(_, _, _, _, _))
+  EXPECT_CALL(*session_, WritevData(_, _, _, _, _, _))
       .WillOnce(Invoke(session_.get(), &MockQuicSession::ConsumeData));
   EXPECT_CALL(*stream_, OnCanWriteNewData()).Times(1);
   stream_->OnCanWrite();
@@ -1072,7 +1083,7 @@
   EXPECT_TRUE(stream_->CanWriteNewData());
 
   // Testing Writev.
-  EXPECT_CALL(*session_, WritevData(_, _, _, _, _))
+  EXPECT_CALL(*session_, WritevData(_, _, _, _, _, _))
       .WillOnce(Return(QuicConsumedData(0, false)));
   struct iovec iov = {const_cast<char*>(data.data()), data.length()};
   QuicMemSliceStorage storage(
@@ -1087,7 +1098,7 @@
   EXPECT_EQ(data.length(), stream_->BufferedDataBytes());
   EXPECT_FALSE(stream_->CanWriteNewData());
 
-  EXPECT_CALL(*session_, WritevData(_, _, _, _, _)).Times(0);
+  EXPECT_CALL(*session_, WritevData(_, _, _, _, _, _)).Times(0);
   QuicMemSliceStorage storage2(
       &iov, 1, session_->connection()->helper()->GetStreamSendBufferAllocator(),
       1024);
@@ -1099,10 +1110,10 @@
 
   data_to_write =
       data.length() - GetQuicFlag(FLAGS_quic_buffered_data_threshold) + 1;
-  EXPECT_CALL(*session_, WritevData(_, _, _, _, _))
+  EXPECT_CALL(*session_, WritevData(_, _, _, _, _, _))
       .WillOnce(InvokeWithoutArgs([this, data_to_write]() {
         return session_->ConsumeData(stream_->id(), data_to_write, 0u, NO_FIN,
-                                     false);
+                                     false, QuicheNullOpt);
       }));
 
   EXPECT_CALL(*stream_, OnCanWriteNewData()).Times(1);
@@ -1112,7 +1123,7 @@
             stream_->BufferedDataBytes());
   EXPECT_TRUE(stream_->CanWriteNewData());
 
-  EXPECT_CALL(*session_, WritevData(_, _, _, _, _)).Times(0);
+  EXPECT_CALL(*session_, WritevData(_, _, _, _, _, _)).Times(0);
   // All data can be consumed as buffered data is below upper limit.
   QuicMemSliceStorage storage3(
       &iov, 1, session_->connection()->helper()->GetStreamSendBufferAllocator(),
@@ -1130,7 +1141,7 @@
   std::string data("aaaaa");
   QuicStreamPeer::SetStreamBytesWritten(kMaxStreamLength - data.length(),
                                         stream_);
-  EXPECT_CALL(*session_, WritevData(_, _, _, _, _))
+  EXPECT_CALL(*session_, WritevData(_, _, _, _, _, _))
       .WillOnce(Invoke(session_.get(), &MockQuicSession::ConsumeData));
   struct iovec iov = {const_cast<char*>(data.data()), 5u};
   QuicMemSliceStorage storage(
@@ -1161,9 +1172,10 @@
   QuicMemSliceSpan span1 = vector1.span();
   QuicMemSliceSpan span2 = vector2.span();
 
-  EXPECT_CALL(*session_, WritevData(_, _, _, _, _))
+  EXPECT_CALL(*session_, WritevData(_, _, _, _, _, _))
       .WillOnce(InvokeWithoutArgs([this]() {
-        return session_->ConsumeData(stream_->id(), 100u, 0u, NO_FIN, false);
+        return session_->ConsumeData(stream_->id(), 100u, 0u, NO_FIN, false,
+                                     QuicheNullOpt);
       }));
   // There is no buffered data before, all data should be consumed.
   QuicConsumedData consumed = stream_->WriteMemSlices(span1, false);
@@ -1172,7 +1184,7 @@
   EXPECT_EQ(2 * QUICHE_ARRAYSIZE(data) - 100, stream_->BufferedDataBytes());
   EXPECT_FALSE(stream_->fin_buffered());
 
-  EXPECT_CALL(*session_, WritevData(_, _, _, _, _)).Times(0);
+  EXPECT_CALL(*session_, WritevData(_, _, _, _, _, _)).Times(0);
   // No Data can be consumed as buffered data is beyond upper limit.
   consumed = stream_->WriteMemSlices(span2, true);
   EXPECT_EQ(0u, consumed.bytes_consumed);
@@ -1182,10 +1194,10 @@
 
   size_t data_to_write = 2 * QUICHE_ARRAYSIZE(data) - 100 -
                          GetQuicFlag(FLAGS_quic_buffered_data_threshold) + 1;
-  EXPECT_CALL(*session_, WritevData(_, _, _, _, _))
+  EXPECT_CALL(*session_, WritevData(_, _, _, _, _, _))
       .WillOnce(InvokeWithoutArgs([this, data_to_write]() {
         return session_->ConsumeData(stream_->id(), data_to_write, 100u, NO_FIN,
-                                     false);
+                                     false, QuicheNullOpt);
       }));
   EXPECT_CALL(*stream_, OnCanWriteNewData()).Times(1);
   stream_->OnCanWrite();
@@ -1193,7 +1205,7 @@
                 GetQuicFlag(FLAGS_quic_buffered_data_threshold) - 1),
             stream_->BufferedDataBytes());
   // Try to write slices2 again.
-  EXPECT_CALL(*session_, WritevData(_, _, _, _, _)).Times(0);
+  EXPECT_CALL(*session_, WritevData(_, _, _, _, _, _)).Times(0);
   consumed = stream_->WriteMemSlices(span2, true);
   EXPECT_EQ(2048u, consumed.bytes_consumed);
   EXPECT_TRUE(consumed.fin_consumed);
@@ -1203,7 +1215,7 @@
   EXPECT_TRUE(stream_->fin_buffered());
 
   // Flush all buffered data.
-  EXPECT_CALL(*session_, WritevData(_, _, _, _, _))
+  EXPECT_CALL(*session_, WritevData(_, _, _, _, _, _))
       .WillOnce(Invoke(session_.get(), &MockQuicSession::ConsumeData));
   stream_->OnCanWrite();
   EXPECT_CALL(*stream_, OnCanWriteNewData()).Times(0);
@@ -1219,9 +1231,10 @@
   buffers.push_back(std::make_pair(data, QUICHE_ARRAYSIZE(data)));
   QuicTestMemSliceVector vector1(buffers);
   QuicMemSliceSpan span1 = vector1.span();
-  EXPECT_CALL(*session_, WritevData(_, _, _, _, _))
+  EXPECT_CALL(*session_, WritevData(_, _, _, _, _, _))
       .WillOnce(InvokeWithoutArgs([this]() {
-        return session_->ConsumeData(stream_->id(), 5u, 0u, NO_FIN, false);
+        return session_->ConsumeData(stream_->id(), 5u, 0u, NO_FIN, false,
+                                     QuicheNullOpt);
       }));
   // There is no buffered data before, all data should be consumed.
   QuicConsumedData consumed = stream_->WriteMemSlices(span1, false);
@@ -1238,7 +1251,7 @@
 
 TEST_P(QuicStreamTest, StreamDataGetAckedMultipleTimes) {
   Initialize();
-  EXPECT_CALL(*session_, WritevData(_, _, _, _, _))
+  EXPECT_CALL(*session_, WritevData(_, _, _, _, _, _))
       .WillRepeatedly(Invoke(session_.get(), &MockQuicSession::ConsumeData));
   EXPECT_FALSE(stream_->IsWaitingForAcks());
   EXPECT_FALSE(session_->HasUnackedStreamData());
@@ -1305,14 +1318,14 @@
   Initialize();
 
   // Send [0, 9).
-  EXPECT_CALL(*session_, WritevData(_, _, _, _, _))
+  EXPECT_CALL(*session_, WritevData(_, _, _, _, _, _))
       .WillOnce(Invoke(session_.get(), &MockQuicSession::ConsumeData));
   stream_->WriteOrBufferData(kData1, false, nullptr);
   EXPECT_FALSE(stream_->HasBufferedData());
   EXPECT_TRUE(stream_->IsStreamFrameOutstanding(0, 9, false));
 
   // Try to send [9, 27), but connection is blocked.
-  EXPECT_CALL(*session_, WritevData(_, _, _, _, _))
+  EXPECT_CALL(*session_, WritevData(_, _, _, _, _, _))
       .WillOnce(Return(QuicConsumedData(0, false)));
   stream_->WriteOrBufferData(kData2, false, nullptr);
   stream_->WriteOrBufferData(kData2, false, nullptr);
@@ -1323,7 +1336,7 @@
   // transmitted.
   stream_->OnStreamFrameLost(0, 9, false);
   EXPECT_TRUE(stream_->HasPendingRetransmission());
-  EXPECT_CALL(*session_, WritevData(_, _, _, _, _))
+  EXPECT_CALL(*session_, WritevData(_, _, _, _, _, _))
       .WillOnce(Invoke(session_.get(), &MockQuicSession::ConsumeData));
   EXPECT_CALL(*stream_, OnCanWriteNewData()).Times(1);
   stream_->OnCanWrite();
@@ -1331,13 +1344,13 @@
   EXPECT_TRUE(stream_->HasBufferedData());
 
   // This OnCanWrite causes [9, 27) to be sent.
-  EXPECT_CALL(*session_, WritevData(_, _, _, _, _))
+  EXPECT_CALL(*session_, WritevData(_, _, _, _, _, _))
       .WillOnce(Invoke(session_.get(), &MockQuicSession::ConsumeData));
   stream_->OnCanWrite();
   EXPECT_FALSE(stream_->HasBufferedData());
 
   // Send a fin only frame.
-  EXPECT_CALL(*session_, WritevData(_, _, _, _, _))
+  EXPECT_CALL(*session_, WritevData(_, _, _, _, _, _))
       .WillOnce(Invoke(session_.get(), &MockQuicSession::ConsumeData));
   stream_->WriteOrBufferData("", true, nullptr);
 
@@ -1356,9 +1369,10 @@
   EXPECT_TRUE(stream_->HasPendingRetransmission());
   // This OnCanWrite causes [18, 27) and fin to be retransmitted. Verify fin can
   // be bundled with data.
-  EXPECT_CALL(*session_, WritevData(_, _, _, _, _))
+  EXPECT_CALL(*session_, WritevData(_, _, _, _, _, _))
       .WillOnce(InvokeWithoutArgs([this]() {
-        return session_->ConsumeData(stream_->id(), 9u, 18u, FIN, false);
+        return session_->ConsumeData(stream_->id(), 9u, 18u, FIN, false,
+                                     QuicheNullOpt);
       }));
   stream_->OnCanWrite();
   EXPECT_FALSE(stream_->HasPendingRetransmission());
@@ -1373,7 +1387,7 @@
   Initialize();
 
   // Send [0, 18) and fin.
-  EXPECT_CALL(*session_, WritevData(_, _, _, _, _))
+  EXPECT_CALL(*session_, WritevData(_, _, _, _, _, _))
       .WillRepeatedly(Invoke(session_.get(), &MockQuicSession::ConsumeData));
   stream_->WriteOrBufferData(kData1, false, nullptr);
   stream_->WriteOrBufferData(kData2, true, nullptr);
@@ -1385,11 +1399,12 @@
   // Retransmit lost data. Verify [0, 9) and fin are retransmitted in two
   // frames.
   InSequence s;
-  EXPECT_CALL(*session_, WritevData(_, _, _, _, _))
+  EXPECT_CALL(*session_, WritevData(_, _, _, _, _, _))
       .WillOnce(InvokeWithoutArgs([this]() {
-        return session_->ConsumeData(stream_->id(), 9u, 0u, NO_FIN, false);
+        return session_->ConsumeData(stream_->id(), 9u, 0u, NO_FIN, false,
+                                     QuicheNullOpt);
       }));
-  EXPECT_CALL(*session_, WritevData(_, _, _, _, _))
+  EXPECT_CALL(*session_, WritevData(_, _, _, _, _, _))
       .WillOnce(Return(QuicConsumedData(0, true)));
   stream_->OnCanWrite();
 }
@@ -1408,7 +1423,7 @@
                                session_.get(), BIDIRECTIONAL);
   session_->ActivateStream(QuicWrapUnique(stream));
 
-  EXPECT_CALL(*session_, WritevData(_, _, _, _, _))
+  EXPECT_CALL(*session_, WritevData(_, _, _, _, _, _))
       .WillRepeatedly(Invoke(session_.get(), &MockQuicSession::ConsumeData));
   EXPECT_CALL(*connection_, SendControlFrame(_))
       .WillOnce(Invoke(&ClearControlFrame));
@@ -1442,7 +1457,7 @@
   session_->ActivateStream(QuicWrapUnique(stream));
 
   std::string data(100, '.');
-  EXPECT_CALL(*session_, WritevData(_, _, _, _, _))
+  EXPECT_CALL(*session_, WritevData(_, _, _, _, _, _))
       .WillRepeatedly(Invoke(session_.get(), &MockQuicSession::ConsumeData));
   EXPECT_CALL(*connection_, SendControlFrame(_))
       .WillOnce(Invoke(&ClearControlFrame));
@@ -1462,7 +1477,7 @@
   InSequence s;
 
   // Send [0, 18) with fin.
-  EXPECT_CALL(*session_, WritevData(stream_->id(), _, _, _, _))
+  EXPECT_CALL(*session_, WritevData(stream_->id(), _, _, _, _, _))
       .Times(2)
       .WillRepeatedly(Invoke(session_.get(), &MockQuicSession::ConsumeData));
   stream_->WriteOrBufferData(kData1, false, nullptr);
@@ -1473,23 +1488,24 @@
                               QuicTime::Zero(), &newly_acked_length);
   EXPECT_EQ(3u, newly_acked_length);
   // Retransmit [0, 18) with fin, and only [0, 8) is consumed.
-  EXPECT_CALL(*session_, WritevData(stream_->id(), 10, 0, NO_FIN, _))
+  EXPECT_CALL(*session_, WritevData(stream_->id(), 10, 0, NO_FIN, _, _))
       .WillOnce(InvokeWithoutArgs([this]() {
-        return session_->ConsumeData(stream_->id(), 8, 0u, NO_FIN, false);
+        return session_->ConsumeData(stream_->id(), 8, 0u, NO_FIN, false,
+                                     QuicheNullOpt);
       }));
   EXPECT_FALSE(stream_->RetransmitStreamData(0, 18, true));
 
   // Retransmit [0, 18) with fin, and all is consumed.
-  EXPECT_CALL(*session_, WritevData(stream_->id(), 10, 0, NO_FIN, _))
+  EXPECT_CALL(*session_, WritevData(stream_->id(), 10, 0, NO_FIN, _, _))
       .WillOnce(Invoke(session_.get(), &MockQuicSession::ConsumeData));
-  EXPECT_CALL(*session_, WritevData(stream_->id(), 5, 13, FIN, _))
+  EXPECT_CALL(*session_, WritevData(stream_->id(), 5, 13, FIN, _, _))
       .WillOnce(Invoke(session_.get(), &MockQuicSession::ConsumeData));
   EXPECT_TRUE(stream_->RetransmitStreamData(0, 18, true));
 
   // Retransmit [0, 8) with fin, and all is consumed.
-  EXPECT_CALL(*session_, WritevData(stream_->id(), 8, 0, NO_FIN, _))
+  EXPECT_CALL(*session_, WritevData(stream_->id(), 8, 0, NO_FIN, _, _))
       .WillOnce(Invoke(session_.get(), &MockQuicSession::ConsumeData));
-  EXPECT_CALL(*session_, WritevData(stream_->id(), 0, 18, FIN, _))
+  EXPECT_CALL(*session_, WritevData(stream_->id(), 0, 18, FIN, _, _))
       .WillOnce(Invoke(session_.get(), &MockQuicSession::ConsumeData));
   EXPECT_TRUE(stream_->RetransmitStreamData(0, 8, true));
 }
@@ -1497,7 +1513,7 @@
 TEST_P(QuicStreamTest, ResetStreamOnTtlExpiresRetransmitLostData) {
   Initialize();
 
-  EXPECT_CALL(*session_, WritevData(stream_->id(), 200, 0, FIN, _))
+  EXPECT_CALL(*session_, WritevData(stream_->id(), 200, 0, FIN, _, _))
       .WillOnce(Invoke(session_.get(), &MockQuicSession::ConsumeData));
   std::string body(200, 'a');
   stream_->WriteOrBufferData(body, true, nullptr);
@@ -1506,7 +1522,7 @@
   QuicTime::Delta ttl = QuicTime::Delta::FromSeconds(1);
   ASSERT_TRUE(stream_->MaybeSetTtl(ttl));
   // Verify data gets retransmitted because TTL does not expire.
-  EXPECT_CALL(*session_, WritevData(stream_->id(), 100, 0, NO_FIN, _))
+  EXPECT_CALL(*session_, WritevData(stream_->id(), 100, 0, NO_FIN, _, _))
       .WillOnce(Invoke(session_.get(), &MockQuicSession::ConsumeData));
   EXPECT_TRUE(stream_->RetransmitStreamData(0, 100, false));
   stream_->OnStreamFrameLost(100, 100, true);
@@ -1521,7 +1537,7 @@
 TEST_P(QuicStreamTest, ResetStreamOnTtlExpiresEarlyRetransmitData) {
   Initialize();
 
-  EXPECT_CALL(*session_, WritevData(stream_->id(), 200, 0, FIN, _))
+  EXPECT_CALL(*session_, WritevData(stream_->id(), 200, 0, FIN, _, _))
       .WillOnce(Invoke(session_.get(), &MockQuicSession::ConsumeData));
   std::string body(200, 'a');
   stream_->WriteOrBufferData(body, true, nullptr);
diff --git a/quic/core/stream_delegate_interface.h b/quic/core/stream_delegate_interface.h
index 2443a74..898baa5 100644
--- a/quic/core/stream_delegate_interface.h
+++ b/quic/core/stream_delegate_interface.h
@@ -7,6 +7,7 @@
 
 #include <cstddef>
 #include "net/third_party/quiche/src/quic/core/quic_types.h"
+#include "net/third_party/quiche/src/common/platform/api/quiche_optional.h"
 #include "net/third_party/quiche/src/spdy/core/spdy_protocol.h"
 
 namespace quic {
@@ -20,12 +21,15 @@
   // Called when the stream has encountered errors that it can't handle.
   virtual void OnStreamError(QuicErrorCode error_code,
                              std::string error_details) = 0;
-  // Called when the stream needs to write data.
-  virtual QuicConsumedData WritevData(QuicStreamId id,
-                                      size_t write_length,
-                                      QuicStreamOffset offset,
-                                      StreamSendingState state,
-                                      bool is_retransmission) = 0;
+  // Called when the stream needs to write data. If |level| is present, the data
+  // will be written at the specified |level|.
+  virtual QuicConsumedData WritevData(
+      QuicStreamId id,
+      size_t write_length,
+      QuicStreamOffset offset,
+      StreamSendingState state,
+      bool is_retransmission,
+      quiche::QuicheOptional<EncryptionLevel> level) = 0;
   // Called on stream creation.
   virtual void RegisterStreamPriority(
       QuicStreamId id,
diff --git a/quic/qbone/qbone_stream_test.cc b/quic/qbone/qbone_stream_test.cc
index 06dbd34..df25f6b 100644
--- a/quic/qbone/qbone_stream_test.cc
+++ b/quic/qbone/qbone_stream_test.cc
@@ -40,11 +40,13 @@
   ~MockQuicSession() override {}
 
   // Writes outgoing data from QuicStream to a string.
-  QuicConsumedData WritevData(QuicStreamId id,
-                              size_t write_length,
-                              QuicStreamOffset offset,
-                              StreamSendingState state,
-                              bool is_retransmission) override {
+  QuicConsumedData WritevData(
+      QuicStreamId id,
+      size_t write_length,
+      QuicStreamOffset offset,
+      StreamSendingState state,
+      bool is_retransmission,
+      quiche::QuicheOptional<EncryptionLevel> level) override {
     if (!writable_) {
       return QuicConsumedData(0, false);
     }
diff --git a/quic/quartc/quartc_stream_test.cc b/quic/quartc/quartc_stream_test.cc
index fd4c578..d0a527c 100644
--- a/quic/quartc/quartc_stream_test.cc
+++ b/quic/quartc/quartc_stream_test.cc
@@ -77,11 +77,13 @@
   ~MockQuicSession() override {}
 
   // Writes outgoing data from QuicStream to a string.
-  QuicConsumedData WritevData(QuicStreamId id,
-                              size_t write_length,
-                              QuicStreamOffset offset,
-                              StreamSendingState state,
-                              bool /*is_retransmission*/) override {
+  QuicConsumedData WritevData(
+      QuicStreamId id,
+      size_t write_length,
+      QuicStreamOffset offset,
+      StreamSendingState state,
+      bool /*is_retransmission*/,
+      quiche::QuicheOptional<EncryptionLevel> /*level*/) override {
     if (!writable_) {
       return QuicConsumedData(0, false);
     }
diff --git a/quic/quic_transport/quic_transport_stream_test.cc b/quic/quic_transport/quic_transport_stream_test.cc
index 9fce821..31e01a0 100644
--- a/quic/quic_transport/quic_transport_stream_test.cc
+++ b/quic/quic_transport/quic_transport_stream_test.cc
@@ -141,7 +141,7 @@
   EXPECT_CALL(interface_, IsSessionReady()).WillRepeatedly(Return(true));
   ASSERT_TRUE(stream_->CanWrite());
 
-  EXPECT_CALL(session_, WritevData(stream_->id(), _, _, _, _))
+  EXPECT_CALL(session_, WritevData(stream_->id(), _, _, _, _, _))
       .WillOnce(Return(QuicConsumedData(0, /*fin_consumed=*/true)));
   EXPECT_TRUE(stream_->SendFin());
   EXPECT_FALSE(stream_->CanWrite());
diff --git a/quic/test_tools/quic_test_utils.cc b/quic/test_tools/quic_test_utils.cc
index 6ba98de..680b16c 100644
--- a/quic/test_tools/quic_test_utils.cc
+++ b/quic/test_tools/quic_test_utils.cc
@@ -557,7 +557,7 @@
   if (create_mock_crypto_stream) {
     crypto_stream_ = std::make_unique<MockQuicCryptoStream>(this);
   }
-  ON_CALL(*this, WritevData(_, _, _, _, _))
+  ON_CALL(*this, WritevData(_, _, _, _, _, _))
       .WillByDefault(testing::Return(QuicConsumedData(0, false)));
 }
 
@@ -577,11 +577,13 @@
   crypto_stream_.reset(crypto_stream);
 }
 
-QuicConsumedData MockQuicSession::ConsumeData(QuicStreamId id,
-                                              size_t write_length,
-                                              QuicStreamOffset offset,
-                                              StreamSendingState state,
-                                              bool /*is_retransmission*/) {
+QuicConsumedData MockQuicSession::ConsumeData(
+    QuicStreamId id,
+    size_t write_length,
+    QuicStreamOffset offset,
+    StreamSendingState state,
+    bool /*is_retransmission*/,
+    quiche::QuicheOptional<EncryptionLevel> /*level*/) {
   if (write_length > 0) {
     auto buf = std::make_unique<char[]>(write_length);
     QuicStream* stream = GetOrCreateStream(id);
@@ -629,7 +631,7 @@
     crypto_stream_ = std::make_unique<MockQuicCryptoStream>(this);
   }
 
-  ON_CALL(*this, WritevData(_, _, _, _, _))
+  ON_CALL(*this, WritevData(_, _, _, _, _, _))
       .WillByDefault(testing::Return(QuicConsumedData(0, false)));
 }
 
@@ -649,11 +651,13 @@
   crypto_stream_.reset(crypto_stream);
 }
 
-QuicConsumedData MockQuicSpdySession::ConsumeData(QuicStreamId id,
-                                                  size_t write_length,
-                                                  QuicStreamOffset offset,
-                                                  StreamSendingState state,
-                                                  bool /*is_retransmission*/) {
+QuicConsumedData MockQuicSpdySession::ConsumeData(
+    QuicStreamId id,
+    size_t write_length,
+    QuicStreamOffset offset,
+    StreamSendingState state,
+    bool /*is_retransmission*/,
+    quiche::QuicheOptional<EncryptionLevel> /*level*/) {
   if (write_length > 0) {
     auto buf = std::make_unique<char[]>(write_length);
     QuicStream* stream = GetOrCreateStream(id);
diff --git a/quic/test_tools/quic_test_utils.h b/quic/test_tools/quic_test_utils.h
index 7a95250..7440c4d 100644
--- a/quic/test_tools/quic_test_utils.h
+++ b/quic/test_tools/quic_test_utils.h
@@ -633,12 +633,13 @@
   MOCK_METHOD1(ShouldCreateIncomingStream2, bool(QuicStreamId id));
   MOCK_METHOD0(ShouldCreateOutgoingBidirectionalStream, bool());
   MOCK_METHOD0(ShouldCreateOutgoingUnidirectionalStream, bool());
-  MOCK_METHOD5(WritevData,
+  MOCK_METHOD6(WritevData,
                QuicConsumedData(QuicStreamId id,
                                 size_t write_length,
                                 QuicStreamOffset offset,
                                 StreamSendingState state,
-                                bool is_retransmission));
+                                bool is_retransmission,
+                                quiche::QuicheOptional<EncryptionLevel> level));
 
   MOCK_METHOD3(SendRstStream,
                void(QuicStreamId stream_id,
@@ -668,7 +669,8 @@
                                size_t write_length,
                                QuicStreamOffset offset,
                                StreamSendingState state,
-                               bool is_retransmission);
+                               bool is_retransmission,
+                               quiche::QuicheOptional<EncryptionLevel> level);
 
   void ReallySendRstStream(QuicStreamId id,
                            QuicRstStreamErrorCode error,
@@ -732,12 +734,13 @@
   MOCK_METHOD1(ShouldCreateIncomingStream, bool(QuicStreamId id));
   MOCK_METHOD0(ShouldCreateOutgoingBidirectionalStream, bool());
   MOCK_METHOD0(ShouldCreateOutgoingUnidirectionalStream, bool());
-  MOCK_METHOD5(WritevData,
+  MOCK_METHOD6(WritevData,
                QuicConsumedData(QuicStreamId id,
                                 size_t write_length,
                                 QuicStreamOffset offset,
                                 StreamSendingState state,
-                                bool is_retransmission));
+                                bool is_retransmission,
+                                quiche::QuicheOptional<EncryptionLevel> level));
 
   MOCK_METHOD3(SendRstStream,
                void(QuicStreamId stream_id,
@@ -784,7 +787,8 @@
                                size_t write_length,
                                QuicStreamOffset offset,
                                StreamSendingState state,
-                               bool is_retransmission);
+                               bool is_retransmission,
+                               quiche::QuicheOptional<EncryptionLevel> level);
 
   using QuicSession::ActivateStream;
 
diff --git a/quic/tools/quic_simple_server_stream_test.cc b/quic/tools/quic_simple_server_stream_test.cc
index 880d3aa..1c71af1 100644
--- a/quic/tools/quic_simple_server_stream_test.cc
+++ b/quic/tools/quic_simple_server_stream_test.cc
@@ -10,6 +10,7 @@
 
 #include "net/third_party/quiche/src/quic/core/http/http_encoder.h"
 #include "net/third_party/quiche/src/quic/core/http/spdy_utils.h"
+#include "net/third_party/quiche/src/quic/core/quic_types.h"
 #include "net/third_party/quiche/src/quic/core/quic_utils.h"
 #include "net/third_party/quiche/src/quic/platform/api/quic_expect_bug.h"
 #include "net/third_party/quiche/src/quic/platform/api/quic_ptr_util.h"
@@ -25,6 +26,7 @@
 #include "net/third_party/quiche/src/quic/tools/quic_memory_cache_backend.h"
 #include "net/third_party/quiche/src/quic/tools/quic_simple_server_session.h"
 #include "net/third_party/quiche/src/common/platform/api/quiche_arraysize.h"
+#include "net/third_party/quiche/src/common/platform/api/quiche_optional.h"
 #include "net/third_party/quiche/src/common/platform/api/quiche_string_piece.h"
 
 using testing::_;
@@ -109,7 +111,7 @@
       QuicSessionPeer::SetMaxOpenIncomingStreams(this, kMaxStreamsForTest);
       QuicSessionPeer::SetMaxOpenOutgoingStreams(this, kMaxStreamsForTest);
     }
-    ON_CALL(*this, WritevData(_, _, _, _, _))
+    ON_CALL(*this, WritevData(_, _, _, _, _, _))
         .WillByDefault(Invoke(this, &MockQuicSimpleServerSession::ConsumeData));
   }
 
@@ -122,12 +124,13 @@
                void(const QuicConnectionCloseFrame& frame,
                     ConnectionCloseSource source));
   MOCK_METHOD1(CreateIncomingStream, QuicSpdyStream*(QuicStreamId id));
-  MOCK_METHOD5(WritevData,
+  MOCK_METHOD6(WritevData,
                QuicConsumedData(QuicStreamId id,
                                 size_t write_length,
                                 QuicStreamOffset offset,
                                 StreamSendingState state,
-                                bool is_retransmission));
+                                bool is_retransmission,
+                                quiche::QuicheOptional<EncryptionLevel> level));
   MOCK_METHOD4(OnStreamHeaderList,
                void(QuicStreamId stream_id,
                     bool fin,
@@ -163,11 +166,13 @@
 
   MOCK_METHOD1(OnStopSendingReceived, void(const QuicStopSendingFrame& frame));
 
-  QuicConsumedData ConsumeData(QuicStreamId id,
-                               size_t write_length,
-                               QuicStreamOffset offset,
-                               StreamSendingState state,
-                               bool /*is_retransmission*/) {
+  QuicConsumedData ConsumeData(
+      QuicStreamId id,
+      size_t write_length,
+      QuicStreamOffset offset,
+      StreamSendingState state,
+      bool /*is_retransmission*/,
+      quiche::QuicheOptional<EncryptionLevel> /*level*/) {
     if (write_length > 0) {
       auto buf = std::make_unique<char[]>(write_length);
       QuicStream* stream = GetOrCreateStream(id);
@@ -273,7 +278,7 @@
                          ::testing::PrintToStringParamName());
 
 TEST_P(QuicSimpleServerStreamTest, TestFraming) {
-  EXPECT_CALL(session_, WritevData(_, _, _, _, _))
+  EXPECT_CALL(session_, WritevData(_, _, _, _, _, _))
       .WillRepeatedly(
           Invoke(&session_, &MockQuicSimpleServerSession::ConsumeData));
   stream_->OnStreamHeaderList(false, kFakeFrameLen, header_list_);
@@ -291,7 +296,7 @@
 }
 
 TEST_P(QuicSimpleServerStreamTest, TestFramingOnePacket) {
-  EXPECT_CALL(session_, WritevData(_, _, _, _, _))
+  EXPECT_CALL(session_, WritevData(_, _, _, _, _, _))
       .WillRepeatedly(
           Invoke(&session_, &MockQuicSimpleServerSession::ConsumeData));
 
@@ -310,7 +315,7 @@
 }
 
 TEST_P(QuicSimpleServerStreamTest, SendQuicRstStreamNoErrorInStopReading) {
-  EXPECT_CALL(session_, WritevData(_, _, _, _, _))
+  EXPECT_CALL(session_, WritevData(_, _, _, _, _, _))
       .WillRepeatedly(
           Invoke(&session_, &MockQuicSimpleServerSession::ConsumeData));
 
@@ -331,9 +336,10 @@
   // We'll automatically write out an error (headers + body)
   EXPECT_CALL(*stream_, WriteHeadersMock(false));
   if (UsesHttp3()) {
-    EXPECT_CALL(session_, WritevData(_, kDataFrameHeaderLength, _, NO_FIN, _));
+    EXPECT_CALL(session_,
+                WritevData(_, kDataFrameHeaderLength, _, NO_FIN, _, _));
   }
-  EXPECT_CALL(session_, WritevData(_, kErrorLength, _, FIN, _));
+  EXPECT_CALL(session_, WritevData(_, kErrorLength, _, FIN, _, _));
 
   EXPECT_CALL(session_, SendRstStream(_, QUIC_STREAM_NO_ERROR, _)).Times(0);
 
@@ -382,9 +388,9 @@
   InSequence s;
   EXPECT_CALL(*stream_, WriteHeadersMock(false));
   if (UsesHttp3()) {
-    EXPECT_CALL(session_, WritevData(_, header_length, _, NO_FIN, _));
+    EXPECT_CALL(session_, WritevData(_, header_length, _, NO_FIN, _, _));
   }
-  EXPECT_CALL(session_, WritevData(_, kErrorLength, _, FIN, _));
+  EXPECT_CALL(session_, WritevData(_, kErrorLength, _, FIN, _, _));
 
   stream_->DoSendResponse();
   EXPECT_FALSE(QuicStreamPeer::read_side_closed(stream_));
@@ -415,9 +421,9 @@
   InSequence s;
   EXPECT_CALL(*stream_, WriteHeadersMock(false));
   if (UsesHttp3()) {
-    EXPECT_CALL(session_, WritevData(_, header_length, _, NO_FIN, _));
+    EXPECT_CALL(session_, WritevData(_, header_length, _, NO_FIN, _, _));
   }
-  EXPECT_CALL(session_, WritevData(_, kErrorLength, _, FIN, _));
+  EXPECT_CALL(session_, WritevData(_, kErrorLength, _, FIN, _, _));
 
   stream_->DoSendResponse();
   EXPECT_FALSE(QuicStreamPeer::read_side_closed(stream_));
@@ -475,9 +481,9 @@
   InSequence s;
   EXPECT_CALL(*stream_, WriteHeadersMock(false));
   if (UsesHttp3()) {
-    EXPECT_CALL(session_, WritevData(_, header_length, _, NO_FIN, _));
+    EXPECT_CALL(session_, WritevData(_, header_length, _, NO_FIN, _, _));
   }
-  EXPECT_CALL(session_, WritevData(_, body.length(), _, FIN, _));
+  EXPECT_CALL(session_, WritevData(_, body.length(), _, FIN, _, _));
 
   stream_->DoSendResponse();
   EXPECT_FALSE(QuicStreamPeer::read_side_closed(stream_));
@@ -517,9 +523,9 @@
                             _, _));
   EXPECT_CALL(*stream_, WriteHeadersMock(false));
   if (UsesHttp3()) {
-    EXPECT_CALL(session_, WritevData(_, header_length, _, NO_FIN, _));
+    EXPECT_CALL(session_, WritevData(_, header_length, _, NO_FIN, _, _));
   }
-  EXPECT_CALL(session_, WritevData(_, body.length(), _, FIN, _));
+  EXPECT_CALL(session_, WritevData(_, body.length(), _, FIN, _, _));
   stream_->DoSendResponse();
   EXPECT_EQ(*request_headers, session_.original_request_headers_);
 }
@@ -574,10 +580,10 @@
 
   if (UsesHttp3()) {
     EXPECT_CALL(session_, WritevData(kServerInitiatedStreamId, header_length, _,
-                                     NO_FIN, _));
+                                     NO_FIN, _, _));
   }
   EXPECT_CALL(session_,
-              WritevData(kServerInitiatedStreamId, kBody.size(), _, FIN, _));
+              WritevData(kServerInitiatedStreamId, kBody.size(), _, FIN, _, _));
   server_initiated_stream->PushResponse(std::move(headers));
   EXPECT_EQ(kPath, server_initiated_stream->GetHeader(":path"));
   EXPECT_EQ("GET", server_initiated_stream->GetHeader(":method"));
@@ -591,9 +597,10 @@
   InSequence s;
   EXPECT_CALL(*stream_, WriteHeadersMock(false));
   if (UsesHttp3()) {
-    EXPECT_CALL(session_, WritevData(_, kDataFrameHeaderLength, _, NO_FIN, _));
+    EXPECT_CALL(session_,
+                WritevData(_, kDataFrameHeaderLength, _, NO_FIN, _, _));
   }
-  EXPECT_CALL(session_, WritevData(_, kErrorLength, _, FIN, _));
+  EXPECT_CALL(session_, WritevData(_, kErrorLength, _, FIN, _, _));
 
   stream_->DoSendErrorResponse();
   EXPECT_FALSE(QuicStreamPeer::read_side_closed(stream_));
@@ -609,7 +616,7 @@
                         quiche::QuicheStringPiece("11\00012", 5));
 
   EXPECT_CALL(*stream_, WriteHeadersMock(false));
-  EXPECT_CALL(session_, WritevData(_, _, _, _, _))
+  EXPECT_CALL(session_, WritevData(_, _, _, _, _, _))
       .WillRepeatedly(
           Invoke(&session_, &MockQuicSimpleServerSession::ConsumeData));
   stream_->OnStreamHeaderList(true, kFakeFrameLen, header_list_);
@@ -628,7 +635,7 @@
                         quiche::QuicheStringPiece("\00012", 3));
 
   EXPECT_CALL(*stream_, WriteHeadersMock(false));
-  EXPECT_CALL(session_, WritevData(_, _, _, _, _))
+  EXPECT_CALL(session_, WritevData(_, _, _, _, _, _))
       .WillRepeatedly(
           Invoke(&session_, &MockQuicSimpleServerSession::ConsumeData));
   stream_->OnStreamHeaderList(true, kFakeFrameLen, header_list_);
@@ -664,7 +671,7 @@
     // assumption on their number or size.
     auto* qpack_decoder_stream =
         QuicSpdySessionPeer::GetQpackDecoderSendStream(&session_);
-    EXPECT_CALL(session_, WritevData(qpack_decoder_stream->id(), _, _, _, _))
+    EXPECT_CALL(session_, WritevData(qpack_decoder_stream->id(), _, _, _, _, _))
         .Times(AnyNumber());
   }
   EXPECT_CALL(session_, SendRstStream(_, QUIC_RST_ACKNOWLEDGEMENT, _)).Times(1);