Merge QpackEncoderStreamSender::Delegate and QpackDecoderStreamSender::Delegate
into a single delegate interface called QpackUnidirectionalStreamSenderDelegate. The new interface is inherited by QpackSendStream.

Before this change, Qpack encoder/decoder stream sender will call the spdy session and the session is responsible for finding the correct stream and write instructions.
Now Qpack encoder/decoder stream sender can access Qpack streams to write instructions directly.

gfe-relnote: v99 only, not used in prod.
PiperOrigin-RevId: 254247942
Change-Id: Iec378d412396d12d51b63843d45630b09b301b69
diff --git a/quic/core/http/end_to_end_test.cc b/quic/core/http/end_to_end_test.cc
index 2ac1043..0aa796a 100644
--- a/quic/core/http/end_to_end_test.cc
+++ b/quic/core/http/end_to_end_test.cc
@@ -2290,7 +2290,7 @@
                            ->transport_version())) {
     // Determine size of compressed headers.
     NoopDecoderStreamErrorDelegate decoder_stream_error_delegate;
-    NoopEncoderStreamSenderDelegate encoder_stream_sender_delegate;
+    NoopQpackStreamSenderDelegate encoder_stream_sender_delegate;
     QpackEncoder qpack_encoder(&decoder_stream_error_delegate,
                                &encoder_stream_sender_delegate);
     auto progressive_encoder =
diff --git a/quic/core/http/quic_spdy_session.cc b/quic/core/http/quic_spdy_session.cc
index fbe8407..b4849ab 100644
--- a/quic/core/http/quic_spdy_session.cc
+++ b/quic/core/http/quic_spdy_session.cc
@@ -366,8 +366,10 @@
   }
 
   if (VersionUsesQpack(connection()->transport_version())) {
-    qpack_encoder_ = QuicMakeUnique<QpackEncoder>(this, this);
-    qpack_decoder_ = QuicMakeUnique<QpackDecoder>(this, this);
+    qpack_encoder_ =
+        QuicMakeUnique<QpackEncoder>(this, &encoder_stream_sender_delegate_);
+    qpack_decoder_ =
+        QuicMakeUnique<QpackDecoder>(this, &decoder_stream_sender_delegate_);
   }
 
   headers_stream_ = QuicMakeUnique<QuicHeadersStream>((this));
@@ -406,13 +408,6 @@
   QUIC_NOTREACHED();
 }
 
-void QuicSpdySession::WriteEncoderStreamData(QuicStringPiece /*data*/) {
-  DCHECK(VersionUsesQpack(connection()->transport_version()));
-
-  // TODO(112770235): Send encoder stream data on encoder stream.
-  QUIC_NOTREACHED();
-}
-
 void QuicSpdySession::OnEncoderStreamError(QuicStringPiece /*error_message*/) {
   DCHECK(VersionUsesQpack(connection()->transport_version()));
 
@@ -420,12 +415,6 @@
   QUIC_NOTREACHED();
 }
 
-void QuicSpdySession::WriteDecoderStreamData(QuicStringPiece /*data*/) {
-  DCHECK(VersionUsesQpack(connection()->transport_version()));
-
-  // TODO(112770235): Send decoder stream data on decoder stream.
-}
-
 void QuicSpdySession::OnStreamHeadersPriority(QuicStreamId stream_id,
                                               SpdyPriority priority) {
   QuicSpdyStream* stream = GetSpdyDataStream(stream_id);
diff --git a/quic/core/http/quic_spdy_session.h b/quic/core/http/quic_spdy_session.h
index 4277496..1b5927a 100644
--- a/quic/core/http/quic_spdy_session.h
+++ b/quic/core/http/quic_spdy_session.h
@@ -18,6 +18,7 @@
 #include "net/third_party/quiche/src/quic/core/qpack/qpack_decoder_stream_sender.h"
 #include "net/third_party/quiche/src/quic/core/qpack/qpack_encoder.h"
 #include "net/third_party/quiche/src/quic/core/qpack/qpack_encoder_stream_sender.h"
+#include "net/third_party/quiche/src/quic/core/qpack/qpack_utils.h"
 #include "net/third_party/quiche/src/quic/core/quic_session.h"
 #include "net/third_party/quiche/src/quic/core/quic_versions.h"
 #include "net/third_party/quiche/src/quic/platform/api/quic_export.h"
@@ -63,9 +64,7 @@
 class QUIC_EXPORT_PRIVATE QuicSpdySession
     : public QuicSession,
       public QpackEncoder::DecoderStreamErrorDelegate,
-      public QpackEncoderStreamSender::Delegate,
-      public QpackDecoder::EncoderStreamErrorDelegate,
-      public QpackDecoderStreamSender::Delegate {
+      public QpackDecoder::EncoderStreamErrorDelegate {
  public:
   // Does not take ownership of |connection| or |visitor|.
   QuicSpdySession(QuicConnection* connection,
@@ -82,15 +81,9 @@
   // QpackEncoder::DecoderStreamErrorDelegate implementation.
   void OnDecoderStreamError(QuicStringPiece error_message) override;
 
-  // QpackEncoderStreamSender::Delegate implemenation.
-  void WriteEncoderStreamData(QuicStringPiece data) override;
-
   // QpackDecoder::EncoderStreamErrorDelegate implementation.
   void OnEncoderStreamError(QuicStringPiece error_message) override;
 
-  // QpackDecoderStreamSender::Delegate implementation.
-  void WriteDecoderStreamData(QuicStringPiece data) override;
-
   // Called by |headers_stream_| when headers with a priority have been
   // received for a stream.  This method will only be called for server streams.
   virtual void OnStreamHeadersPriority(QuicStreamId stream_id,
@@ -331,6 +324,10 @@
   spdy::SpdyFramer spdy_framer_;
   http2::Http2DecoderAdapter h2_deframer_;
   std::unique_ptr<SpdyFramerVisitor> spdy_framer_visitor_;
+
+  // TODO(renjietang): Replace these two members with actual QPACK send streams.
+  NoopQpackStreamSenderDelegate encoder_stream_sender_delegate_;
+  NoopQpackStreamSenderDelegate decoder_stream_sender_delegate_;
 };
 
 }  // namespace quic
diff --git a/quic/core/http/quic_spdy_stream_test.cc b/quic/core/http/quic_spdy_stream_test.cc
index a1e4fab..de13108 100644
--- a/quic/core/http/quic_spdy_stream_test.cc
+++ b/quic/core/http/quic_spdy_stream_test.cc
@@ -159,8 +159,9 @@
   ~QuicSpdyStreamTest() override = default;
 
   std::string EncodeQpackHeaders(QuicStreamId id, SpdyHeaderBlock* header) {
-    auto qpack_encoder =
-        QuicMakeUnique<QpackEncoder>(session_.get(), session_.get());
+    NoopQpackStreamSenderDelegate encoder_stream_sender_delegate;
+    auto qpack_encoder = QuicMakeUnique<QpackEncoder>(
+        session_.get(), &encoder_stream_sender_delegate);
     auto progressive_encoder = qpack_encoder->EncodeHeaderList(id, header);
     std::string encoded_headers;
     while (progressive_encoder->HasNext()) {
diff --git a/quic/core/qpack/fuzzer/qpack_decoder_fuzzer.cc b/quic/core/qpack/fuzzer/qpack_decoder_fuzzer.cc
index cb66b27..1a2aa4d 100644
--- a/quic/core/qpack/fuzzer/qpack_decoder_fuzzer.cc
+++ b/quic/core/qpack/fuzzer/qpack_decoder_fuzzer.cc
@@ -2,13 +2,13 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "net/third_party/quiche/src/quic/core/qpack/qpack_decoder.h"
-
 #include <cstddef>
 #include <cstdint>
 #include <limits>
 
+#include "net/third_party/quiche/src/quic/core/qpack/qpack_decoder.h"
 #include "net/third_party/quiche/src/quic/core/qpack/qpack_decoder_test_utils.h"
+#include "net/third_party/quiche/src/quic/core/qpack/qpack_utils.h"
 #include "net/third_party/quiche/src/quic/platform/api/quic_fuzzed_data_provider.h"
 #include "net/third_party/quiche/src/quic/platform/api/quic_string_piece.h"
 
@@ -31,7 +31,7 @@
                 &provider, 1, std::numeric_limits<uint16_t>::max());
 
   NoopEncoderStreamErrorDelegate encoder_stream_error_delegate;
-  NoopDecoderStreamSenderDelegate decoder_stream_sender_delegate;
+  NoopQpackStreamSenderDelegate decoder_stream_sender_delegate;
   QpackDecode(&encoder_stream_error_delegate, &decoder_stream_sender_delegate,
               &handler, fragment_size_generator,
               provider.ConsumeRemainingBytesAsString());
diff --git a/quic/core/qpack/fuzzer/qpack_encoder_stream_sender_fuzzer.cc b/quic/core/qpack/fuzzer/qpack_encoder_stream_sender_fuzzer.cc
index 844d57a..78c4c20 100644
--- a/quic/core/qpack/fuzzer/qpack_encoder_stream_sender_fuzzer.cc
+++ b/quic/core/qpack/fuzzer/qpack_encoder_stream_sender_fuzzer.cc
@@ -2,14 +2,14 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "net/third_party/quiche/src/quic/core/qpack/qpack_encoder_stream_sender.h"
-
 #include <cstddef>
 #include <cstdint>
 #include <limits>
 #include <string>
 
+#include "net/third_party/quiche/src/quic/core/qpack/qpack_encoder_stream_sender.h"
 #include "net/third_party/quiche/src/quic/core/qpack/qpack_encoder_test_utils.h"
+#include "net/third_party/quiche/src/quic/core/qpack/qpack_utils.h"
 #include "net/third_party/quiche/src/quic/platform/api/quic_fuzzed_data_provider.h"
 #include "net/third_party/quiche/src/quic/platform/api/quic_string_piece.h"
 
@@ -21,7 +21,7 @@
 // decoded instructions directly compared to input.  Figure out how to get gMock
 // enabled for cc_fuzz_target target types.
 extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
-  NoopEncoderStreamSenderDelegate delegate;
+  NoopQpackStreamSenderDelegate delegate;
   QpackEncoderStreamSender sender(&delegate);
 
   QuicFuzzedDataProvider provider(data, size);
diff --git a/quic/core/qpack/fuzzer/qpack_round_trip_fuzzer.cc b/quic/core/qpack/fuzzer/qpack_round_trip_fuzzer.cc
index 5f752ea..0d74c2e 100644
--- a/quic/core/qpack/fuzzer/qpack_round_trip_fuzzer.cc
+++ b/quic/core/qpack/fuzzer/qpack_round_trip_fuzzer.cc
@@ -8,6 +8,7 @@
 
 #include "net/third_party/quiche/src/quic/core/qpack/qpack_decoder_test_utils.h"
 #include "net/third_party/quiche/src/quic/core/qpack/qpack_encoder_test_utils.h"
+#include "net/third_party/quiche/src/quic/core/qpack/qpack_utils.h"
 #include "net/third_party/quiche/src/quic/core/qpack/value_splitting_header_list.h"
 #include "net/third_party/quiche/src/quic/platform/api/quic_fuzzed_data_provider.h"
 #include "net/third_party/quiche/src/spdy/core/spdy_header_block.h"
@@ -126,7 +127,7 @@
 
   // Encode header list.
   NoopDecoderStreamErrorDelegate decoder_stream_error_delegate;
-  NoopEncoderStreamSenderDelegate encoder_stream_sender_delegate;
+  NoopQpackStreamSenderDelegate encoder_stream_sender_delegate;
   std::string encoded_header_block = QpackEncode(
       &decoder_stream_error_delegate, &encoder_stream_sender_delegate,
       fragment_size_generator, &header_list);
@@ -134,7 +135,7 @@
   // Decode header block.
   TestHeadersHandler handler;
   NoopEncoderStreamErrorDelegate encoder_stream_error_delegate;
-  NoopDecoderStreamSenderDelegate decoder_stream_sender_delegate;
+  NoopQpackStreamSenderDelegate decoder_stream_sender_delegate;
   QpackDecode(&encoder_stream_error_delegate, &decoder_stream_sender_delegate,
               &handler, fragment_size_generator, encoded_header_block);
 
diff --git a/quic/core/qpack/offline/qpack_offline_decoder.h b/quic/core/qpack/offline/qpack_offline_decoder.h
index 922fd64..1fc3d4a 100644
--- a/quic/core/qpack/offline/qpack_offline_decoder.h
+++ b/quic/core/qpack/offline/qpack_offline_decoder.h
@@ -9,6 +9,7 @@
 
 #include "net/third_party/quiche/src/quic/core/qpack/qpack_decoder.h"
 #include "net/third_party/quiche/src/quic/core/qpack/qpack_decoder_test_utils.h"
+#include "net/third_party/quiche/src/quic/core/qpack/qpack_utils.h"
 #include "net/third_party/quiche/src/quic/platform/api/quic_string_piece.h"
 #include "net/third_party/quiche/src/spdy/core/spdy_header_block.h"
 
@@ -61,7 +62,7 @@
                            spdy::SpdyHeaderBlock expected_header_list);
 
   bool encoder_stream_error_detected_;
-  test::NoopDecoderStreamSenderDelegate decoder_stream_sender_delegate_;
+  NoopQpackStreamSenderDelegate decoder_stream_sender_delegate_;
   QpackDecoder decoder_;
   std::list<spdy::SpdyHeaderBlock> decoded_header_lists_;
 };
diff --git a/quic/core/qpack/qpack_decoded_headers_accumulator_test.cc b/quic/core/qpack/qpack_decoded_headers_accumulator_test.cc
index c3c0b81..1607292 100644
--- a/quic/core/qpack/qpack_decoded_headers_accumulator_test.cc
+++ b/quic/core/qpack/qpack_decoded_headers_accumulator_test.cc
@@ -39,7 +39,7 @@
         accumulator_(kTestStreamId, &qpack_decoder_, kMaxHeaderListSize) {}
 
   NoopEncoderStreamErrorDelegate encoder_stream_error_delegate_;
-  StrictMock<MockDecoderStreamSenderDelegate> decoder_stream_sender_delegate_;
+  StrictMock<MockQpackStreamSenderDelegate> decoder_stream_sender_delegate_;
   QpackDecoder qpack_decoder_;
   QpackDecodedHeadersAccumulator accumulator_;
 };
@@ -59,7 +59,7 @@
 
 TEST_F(QpackDecodedHeadersAccumulatorTest, EmptyHeaderList) {
   EXPECT_CALL(decoder_stream_sender_delegate_,
-              WriteDecoderStreamData(Eq(kHeaderAcknowledgement)));
+              WriteStreamData(Eq(kHeaderAcknowledgement)));
 
   EXPECT_TRUE(accumulator_.Decode(QuicTextUtils::HexDecode("0000")));
   EXPECT_TRUE(accumulator_.EndHeaderBlock());
@@ -83,7 +83,7 @@
 
 TEST_F(QpackDecodedHeadersAccumulatorTest, Success) {
   EXPECT_CALL(decoder_stream_sender_delegate_,
-              WriteDecoderStreamData(Eq(kHeaderAcknowledgement)));
+              WriteStreamData(Eq(kHeaderAcknowledgement)));
 
   std::string encoded_data(QuicTextUtils::HexDecode("000023666f6f03626172"));
   EXPECT_TRUE(accumulator_.Decode(encoded_data));
@@ -99,7 +99,7 @@
 
 TEST_F(QpackDecodedHeadersAccumulatorTest, ExceedingLimit) {
   EXPECT_CALL(decoder_stream_sender_delegate_,
-              WriteDecoderStreamData(Eq(kHeaderAcknowledgement)));
+              WriteStreamData(Eq(kHeaderAcknowledgement)));
 
   // Total length of header list exceeds kMaxHeaderListSize.
   EXPECT_TRUE(accumulator_.Decode(QuicTextUtils::HexDecode(
diff --git a/quic/core/qpack/qpack_decoder.cc b/quic/core/qpack/qpack_decoder.cc
index 03e15f7..d0e5ad9 100644
--- a/quic/core/qpack/qpack_decoder.cc
+++ b/quic/core/qpack/qpack_decoder.cc
@@ -13,7 +13,7 @@
 
 QpackDecoder::QpackDecoder(
     EncoderStreamErrorDelegate* encoder_stream_error_delegate,
-    QpackDecoderStreamSender::Delegate* decoder_stream_sender_delegate)
+    QpackStreamSenderDelegate* decoder_stream_sender_delegate)
     : encoder_stream_error_delegate_(encoder_stream_error_delegate),
       encoder_stream_receiver_(this),
       decoder_stream_sender_(decoder_stream_sender_delegate) {
diff --git a/quic/core/qpack/qpack_decoder.h b/quic/core/qpack/qpack_decoder.h
index 7ad4b11..9f8a3e3 100644
--- a/quic/core/qpack/qpack_decoder.h
+++ b/quic/core/qpack/qpack_decoder.h
@@ -34,9 +34,8 @@
     virtual void OnEncoderStreamError(QuicStringPiece error_message) = 0;
   };
 
-  QpackDecoder(
-      EncoderStreamErrorDelegate* encoder_stream_error_delegate,
-      QpackDecoderStreamSender::Delegate* decoder_stream_sender_delegate);
+  QpackDecoder(EncoderStreamErrorDelegate* encoder_stream_error_delegate,
+               QpackStreamSenderDelegate* decoder_stream_sender_delegate);
   ~QpackDecoder() override;
 
   // Set maximum capacity of dynamic table.
diff --git a/quic/core/qpack/qpack_decoder_stream_sender.cc b/quic/core/qpack/qpack_decoder_stream_sender.cc
index 9474d6c..a38c6d5 100644
--- a/quic/core/qpack/qpack_decoder_stream_sender.cc
+++ b/quic/core/qpack/qpack_decoder_stream_sender.cc
@@ -13,7 +13,8 @@
 
 namespace quic {
 
-QpackDecoderStreamSender::QpackDecoderStreamSender(Delegate* delegate)
+QpackDecoderStreamSender::QpackDecoderStreamSender(
+    QpackStreamSenderDelegate* delegate)
     : delegate_(delegate) {
   DCHECK(delegate_);
 }
@@ -28,7 +29,7 @@
   instruction_encoder_.Next(std::numeric_limits<size_t>::max(), &output);
   DCHECK(!instruction_encoder_.HasNext());
 
-  delegate_->WriteDecoderStreamData(output);
+  delegate_->WriteStreamData(output);
 }
 
 void QpackDecoderStreamSender::SendHeaderAcknowledgement(
@@ -42,7 +43,7 @@
   instruction_encoder_.Next(std::numeric_limits<size_t>::max(), &output);
   DCHECK(!instruction_encoder_.HasNext());
 
-  delegate_->WriteDecoderStreamData(output);
+  delegate_->WriteStreamData(output);
 }
 
 void QpackDecoderStreamSender::SendStreamCancellation(QuicStreamId stream_id) {
@@ -55,7 +56,7 @@
   instruction_encoder_.Next(std::numeric_limits<size_t>::max(), &output);
   DCHECK(!instruction_encoder_.HasNext());
 
-  delegate_->WriteDecoderStreamData(output);
+  delegate_->WriteStreamData(output);
 }
 
 }  // namespace quic
diff --git a/quic/core/qpack/qpack_decoder_stream_sender.h b/quic/core/qpack/qpack_decoder_stream_sender.h
index a791173..558996e 100644
--- a/quic/core/qpack/qpack_decoder_stream_sender.h
+++ b/quic/core/qpack/qpack_decoder_stream_sender.h
@@ -8,6 +8,7 @@
 #include <cstdint>
 
 #include "net/third_party/quiche/src/quic/core/qpack/qpack_instruction_encoder.h"
+#include "net/third_party/quiche/src/quic/core/qpack/qpack_stream_sender_delegate.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/quic/platform/api/quic_string_piece.h"
@@ -18,19 +19,7 @@
 // stream.
 class QUIC_EXPORT_PRIVATE QpackDecoderStreamSender {
  public:
-  // An interface for handling encoded data.
-  class Delegate {
-   public:
-    virtual ~Delegate() = default;
-
-    // Encoded |data| is ready to be written on the decoder stream.
-    // WriteDecoderStreamData() is called exactly once for each instruction.
-    // |data| contains the entire encoded instruction and it is guaranteed to be
-    // not empty.
-    virtual void WriteDecoderStreamData(QuicStringPiece data) = 0;
-  };
-
-  explicit QpackDecoderStreamSender(Delegate* delegate);
+  explicit QpackDecoderStreamSender(QpackStreamSenderDelegate* delegate);
   QpackDecoderStreamSender() = delete;
   QpackDecoderStreamSender(const QpackDecoderStreamSender&) = delete;
   QpackDecoderStreamSender& operator=(const QpackDecoderStreamSender&) = delete;
@@ -46,7 +35,7 @@
   void SendStreamCancellation(QuicStreamId stream_id);
 
  private:
-  Delegate* const delegate_;
+  QpackStreamSenderDelegate* const delegate_;
   QpackInstructionEncoder instruction_encoder_;
 };
 
diff --git a/quic/core/qpack/qpack_decoder_stream_sender_test.cc b/quic/core/qpack/qpack_decoder_stream_sender_test.cc
index c7c132e..a50df48 100644
--- a/quic/core/qpack/qpack_decoder_stream_sender_test.cc
+++ b/quic/core/qpack/qpack_decoder_stream_sender_test.cc
@@ -20,61 +20,51 @@
   QpackDecoderStreamSenderTest() : stream_(&delegate_) {}
   ~QpackDecoderStreamSenderTest() override = default;
 
-  StrictMock<MockDecoderStreamSenderDelegate> delegate_;
+  StrictMock<MockQpackStreamSenderDelegate> delegate_;
   QpackDecoderStreamSender stream_;
 };
 
 TEST_F(QpackDecoderStreamSenderTest, InsertCountIncrement) {
-  EXPECT_CALL(delegate_,
-              WriteDecoderStreamData(Eq(QuicTextUtils::HexDecode("00"))));
+  EXPECT_CALL(delegate_, WriteStreamData(Eq(QuicTextUtils::HexDecode("00"))));
   stream_.SendInsertCountIncrement(0);
 
-  EXPECT_CALL(delegate_,
-              WriteDecoderStreamData(Eq(QuicTextUtils::HexDecode("0a"))));
+  EXPECT_CALL(delegate_, WriteStreamData(Eq(QuicTextUtils::HexDecode("0a"))));
   stream_.SendInsertCountIncrement(10);
 
-  EXPECT_CALL(delegate_,
-              WriteDecoderStreamData(Eq(QuicTextUtils::HexDecode("3f00"))));
+  EXPECT_CALL(delegate_, WriteStreamData(Eq(QuicTextUtils::HexDecode("3f00"))));
   stream_.SendInsertCountIncrement(63);
 
   EXPECT_CALL(delegate_,
-              WriteDecoderStreamData(Eq(QuicTextUtils::HexDecode("3f8901"))));
+              WriteStreamData(Eq(QuicTextUtils::HexDecode("3f8901"))));
   stream_.SendInsertCountIncrement(200);
 }
 
 TEST_F(QpackDecoderStreamSenderTest, HeaderAcknowledgement) {
-  EXPECT_CALL(delegate_,
-              WriteDecoderStreamData(Eq(QuicTextUtils::HexDecode("80"))));
+  EXPECT_CALL(delegate_, WriteStreamData(Eq(QuicTextUtils::HexDecode("80"))));
   stream_.SendHeaderAcknowledgement(0);
 
-  EXPECT_CALL(delegate_,
-              WriteDecoderStreamData(Eq(QuicTextUtils::HexDecode("a5"))));
+  EXPECT_CALL(delegate_, WriteStreamData(Eq(QuicTextUtils::HexDecode("a5"))));
   stream_.SendHeaderAcknowledgement(37);
 
-  EXPECT_CALL(delegate_,
-              WriteDecoderStreamData(Eq(QuicTextUtils::HexDecode("ff00"))));
+  EXPECT_CALL(delegate_, WriteStreamData(Eq(QuicTextUtils::HexDecode("ff00"))));
   stream_.SendHeaderAcknowledgement(127);
 
   EXPECT_CALL(delegate_,
-              WriteDecoderStreamData(Eq(QuicTextUtils::HexDecode("fff802"))));
+              WriteStreamData(Eq(QuicTextUtils::HexDecode("fff802"))));
   stream_.SendHeaderAcknowledgement(503);
 }
 
 TEST_F(QpackDecoderStreamSenderTest, StreamCancellation) {
-  EXPECT_CALL(delegate_,
-              WriteDecoderStreamData(Eq(QuicTextUtils::HexDecode("40"))));
+  EXPECT_CALL(delegate_, WriteStreamData(Eq(QuicTextUtils::HexDecode("40"))));
   stream_.SendStreamCancellation(0);
 
-  EXPECT_CALL(delegate_,
-              WriteDecoderStreamData(Eq(QuicTextUtils::HexDecode("53"))));
+  EXPECT_CALL(delegate_, WriteStreamData(Eq(QuicTextUtils::HexDecode("53"))));
   stream_.SendStreamCancellation(19);
 
-  EXPECT_CALL(delegate_,
-              WriteDecoderStreamData(Eq(QuicTextUtils::HexDecode("7f00"))));
+  EXPECT_CALL(delegate_, WriteStreamData(Eq(QuicTextUtils::HexDecode("7f00"))));
   stream_.SendStreamCancellation(63);
 
-  EXPECT_CALL(delegate_,
-              WriteDecoderStreamData(Eq(QuicTextUtils::HexDecode("7f2f"))));
+  EXPECT_CALL(delegate_, WriteStreamData(Eq(QuicTextUtils::HexDecode("7f2f"))));
   stream_.SendStreamCancellation(110);
 }
 
diff --git a/quic/core/qpack/qpack_decoder_test.cc b/quic/core/qpack/qpack_decoder_test.cc
index eabc7b9..185aab9 100644
--- a/quic/core/qpack/qpack_decoder_test.cc
+++ b/quic/core/qpack/qpack_decoder_test.cc
@@ -54,7 +54,7 @@
   }
 
   StrictMock<MockEncoderStreamErrorDelegate> encoder_stream_error_delegate_;
-  StrictMock<MockDecoderStreamSenderDelegate> decoder_stream_sender_delegate_;
+  StrictMock<MockQpackStreamSenderDelegate> decoder_stream_sender_delegate_;
   StrictMock<MockHeadersHandler> handler_;
 
  private:
@@ -78,7 +78,7 @@
 TEST_P(QpackDecoderTest, EmptyHeaderBlock) {
   EXPECT_CALL(handler_, OnDecodingCompleted());
   EXPECT_CALL(decoder_stream_sender_delegate_,
-              WriteDecoderStreamData(Eq(kHeaderAcknowledgement)));
+              WriteStreamData(Eq(kHeaderAcknowledgement)));
 
   DecodeHeaderBlock(QuicTextUtils::HexDecode("0000"));
 }
@@ -87,7 +87,7 @@
   EXPECT_CALL(handler_, OnHeaderDecoded(Eq(""), Eq("foo")));
   EXPECT_CALL(handler_, OnDecodingCompleted());
   EXPECT_CALL(decoder_stream_sender_delegate_,
-              WriteDecoderStreamData(Eq(kHeaderAcknowledgement)));
+              WriteStreamData(Eq(kHeaderAcknowledgement)));
 
   DecodeHeaderBlock(QuicTextUtils::HexDecode("00002003666f6f"));
 }
@@ -96,7 +96,7 @@
   EXPECT_CALL(handler_, OnHeaderDecoded(Eq("foo"), Eq("")));
   EXPECT_CALL(handler_, OnDecodingCompleted());
   EXPECT_CALL(decoder_stream_sender_delegate_,
-              WriteDecoderStreamData(Eq(kHeaderAcknowledgement)));
+              WriteStreamData(Eq(kHeaderAcknowledgement)));
 
   DecodeHeaderBlock(QuicTextUtils::HexDecode("000023666f6f00"));
 }
@@ -105,7 +105,7 @@
   EXPECT_CALL(handler_, OnHeaderDecoded(Eq(""), Eq("")));
   EXPECT_CALL(handler_, OnDecodingCompleted());
   EXPECT_CALL(decoder_stream_sender_delegate_,
-              WriteDecoderStreamData(Eq(kHeaderAcknowledgement)));
+              WriteStreamData(Eq(kHeaderAcknowledgement)));
 
   DecodeHeaderBlock(QuicTextUtils::HexDecode("00002000"));
 }
@@ -114,7 +114,7 @@
   EXPECT_CALL(handler_, OnHeaderDecoded(Eq("foo"), Eq("bar")));
   EXPECT_CALL(handler_, OnDecodingCompleted());
   EXPECT_CALL(decoder_stream_sender_delegate_,
-              WriteDecoderStreamData(Eq(kHeaderAcknowledgement)));
+              WriteStreamData(Eq(kHeaderAcknowledgement)));
 
   DecodeHeaderBlock(QuicTextUtils::HexDecode("000023666f6f03626172"));
 }
@@ -125,7 +125,7 @@
   EXPECT_CALL(handler_, OnHeaderDecoded(Eq("foobaar"), QuicStringPiece(str)));
   EXPECT_CALL(handler_, OnDecodingCompleted());
   EXPECT_CALL(decoder_stream_sender_delegate_,
-              WriteDecoderStreamData(Eq(kHeaderAcknowledgement)));
+              WriteStreamData(Eq(kHeaderAcknowledgement)));
 
   DecodeHeaderBlock(QuicTextUtils::HexDecode(
       "0000"                // prefix
@@ -184,7 +184,7 @@
   EXPECT_CALL(handler_, OnHeaderDecoded(Eq("custom-key"), Eq("custom-value")));
   EXPECT_CALL(handler_, OnDecodingCompleted());
   EXPECT_CALL(decoder_stream_sender_delegate_,
-              WriteDecoderStreamData(Eq(kHeaderAcknowledgement)));
+              WriteStreamData(Eq(kHeaderAcknowledgement)));
 
   DecodeHeaderBlock(
       QuicTextUtils::HexDecode("00002f0125a849e95ba97d7f8925a849e95bb8e8b4bf"));
@@ -195,7 +195,7 @@
       .Times(4);
   EXPECT_CALL(handler_, OnDecodingCompleted());
   EXPECT_CALL(decoder_stream_sender_delegate_,
-              WriteDecoderStreamData(Eq(kHeaderAcknowledgement)));
+              WriteStreamData(Eq(kHeaderAcknowledgement)));
 
   DecodeHeaderBlock(QuicTextUtils::HexDecode(
       "0000"                        // Prefix.
@@ -269,7 +269,7 @@
 
   EXPECT_CALL(handler_, OnDecodingCompleted());
   EXPECT_CALL(decoder_stream_sender_delegate_,
-              WriteDecoderStreamData(Eq(kHeaderAcknowledgement)));
+              WriteStreamData(Eq(kHeaderAcknowledgement)));
 
   DecodeHeaderBlock(QuicTextUtils::HexDecode(
       "0000d1dfccd45f108621e9aec2a11f5c8294e75f000554524143455f1000"));
@@ -312,7 +312,7 @@
   EXPECT_CALL(handler_, OnHeaderDecoded(Eq("foo"), Eq("ZZZ"))).InSequence(s);
   EXPECT_CALL(handler_, OnHeaderDecoded(Eq(":method"), Eq("ZZ"))).InSequence(s);
   EXPECT_CALL(decoder_stream_sender_delegate_,
-              WriteDecoderStreamData(Eq(kHeaderAcknowledgement)))
+              WriteStreamData(Eq(kHeaderAcknowledgement)))
       .InSequence(s);
   EXPECT_CALL(handler_, OnDecodingCompleted()).InSequence(s);
 
@@ -333,7 +333,7 @@
   EXPECT_CALL(handler_, OnHeaderDecoded(Eq("foo"), Eq("ZZZ"))).InSequence(s);
   EXPECT_CALL(handler_, OnHeaderDecoded(Eq(":method"), Eq("ZZ"))).InSequence(s);
   EXPECT_CALL(decoder_stream_sender_delegate_,
-              WriteDecoderStreamData(Eq(kHeaderAcknowledgement)))
+              WriteStreamData(Eq(kHeaderAcknowledgement)))
       .InSequence(s);
   EXPECT_CALL(handler_, OnDecodingCompleted()).InSequence(s);
 
@@ -354,7 +354,7 @@
   EXPECT_CALL(handler_, OnHeaderDecoded(Eq("foo"), Eq("ZZZ"))).InSequence(s);
   EXPECT_CALL(handler_, OnHeaderDecoded(Eq(":method"), Eq("ZZ"))).InSequence(s);
   EXPECT_CALL(decoder_stream_sender_delegate_,
-              WriteDecoderStreamData(Eq(kHeaderAcknowledgement)))
+              WriteStreamData(Eq(kHeaderAcknowledgement)))
       .InSequence(s);
   EXPECT_CALL(handler_, OnDecodingCompleted()).InSequence(s);
 
@@ -376,7 +376,7 @@
   EXPECT_CALL(handler_, OnHeaderDecoded(Eq("foo"), Eq("bar")));
   EXPECT_CALL(handler_, OnDecodingCompleted());
   EXPECT_CALL(decoder_stream_sender_delegate_,
-              WriteDecoderStreamData(Eq(kHeaderAcknowledgement)));
+              WriteStreamData(Eq(kHeaderAcknowledgement)));
 
   DecodeHeaderBlock(QuicTextUtils::HexDecode(
       "0200"   // Required Insert Count 1 and Delta Base 0.
@@ -580,7 +580,7 @@
   EXPECT_CALL(handler_, OnHeaderDecoded(Eq("foo"), Eq(header_value)));
   EXPECT_CALL(handler_, OnDecodingCompleted());
   EXPECT_CALL(decoder_stream_sender_delegate_,
-              WriteDecoderStreamData(Eq(kHeaderAcknowledgement)));
+              WriteStreamData(Eq(kHeaderAcknowledgement)));
 
   // Send header block with Required Insert Count = 201.
   DecodeHeaderBlock(QuicTextUtils::HexDecode(
diff --git a/quic/core/qpack/qpack_decoder_test_utils.cc b/quic/core/qpack/qpack_decoder_test_utils.cc
index d00e528..ab0e2b8 100644
--- a/quic/core/qpack/qpack_decoder_test_utils.cc
+++ b/quic/core/qpack/qpack_decoder_test_utils.cc
@@ -16,9 +16,6 @@
 void NoopEncoderStreamErrorDelegate::OnEncoderStreamError(
     QuicStringPiece /*error_message*/) {}
 
-void NoopDecoderStreamSenderDelegate::WriteDecoderStreamData(
-    QuicStringPiece /*data*/) {}
-
 TestHeadersHandler::TestHeadersHandler()
     : decoding_completed_(false), decoding_error_detected_(false) {}
 
@@ -62,7 +59,7 @@
 
 void QpackDecode(
     QpackDecoder::EncoderStreamErrorDelegate* encoder_stream_error_delegate,
-    QpackDecoderStreamSender::Delegate* decoder_stream_sender_delegate,
+    QpackStreamSenderDelegate* decoder_stream_sender_delegate,
     QpackProgressiveDecoder::HeadersHandlerInterface* handler,
     const FragmentSizeGenerator& fragment_size_generator,
     QuicStringPiece data) {
diff --git a/quic/core/qpack/qpack_decoder_test_utils.h b/quic/core/qpack/qpack_decoder_test_utils.h
index 7cc684c..c2e909c 100644
--- a/quic/core/qpack/qpack_decoder_test_utils.h
+++ b/quic/core/qpack/qpack_decoder_test_utils.h
@@ -33,24 +33,6 @@
   MOCK_METHOD1(OnEncoderStreamError, void(QuicStringPiece error_message));
 };
 
-// QpackDecoderStreamSender::Delegate implementation that does nothing.
-class NoopDecoderStreamSenderDelegate
-    : public QpackDecoderStreamSender::Delegate {
- public:
-  ~NoopDecoderStreamSenderDelegate() override = default;
-
-  void WriteDecoderStreamData(QuicStringPiece data) override;
-};
-
-// Mock QpackDecoderStreamSender::Delegate implementation.
-class MockDecoderStreamSenderDelegate
-    : public QpackDecoderStreamSender::Delegate {
- public:
-  ~MockDecoderStreamSenderDelegate() override = default;
-
-  MOCK_METHOD1(WriteDecoderStreamData, void(QuicStringPiece data));
-};
-
 // HeadersHandlerInterface implementation that collects decoded headers
 // into a SpdyHeaderBlock.
 class TestHeadersHandler
@@ -104,7 +86,7 @@
 
 void QpackDecode(
     QpackDecoder::EncoderStreamErrorDelegate* encoder_stream_error_delegate,
-    QpackDecoderStreamSender::Delegate* decoder_stream_sender_delegate,
+    QpackStreamSenderDelegate* decoder_stream_sender_delegate,
     QpackProgressiveDecoder::HeadersHandlerInterface* handler,
     const FragmentSizeGenerator& fragment_size_generator,
     QuicStringPiece data);
diff --git a/quic/core/qpack/qpack_encoder.cc b/quic/core/qpack/qpack_encoder.cc
index 2c1e453..92bf0dc 100644
--- a/quic/core/qpack/qpack_encoder.cc
+++ b/quic/core/qpack/qpack_encoder.cc
@@ -14,7 +14,7 @@
 
 QpackEncoder::QpackEncoder(
     DecoderStreamErrorDelegate* decoder_stream_error_delegate,
-    QpackEncoderStreamSender::Delegate* encoder_stream_sender_delegate)
+    QpackStreamSenderDelegate* encoder_stream_sender_delegate)
     : decoder_stream_error_delegate_(decoder_stream_error_delegate),
       decoder_stream_receiver_(this),
       encoder_stream_sender_(encoder_stream_sender_delegate) {
diff --git a/quic/core/qpack/qpack_encoder.h b/quic/core/qpack/qpack_encoder.h
index 2c450b1..a14d91b 100644
--- a/quic/core/qpack/qpack_encoder.h
+++ b/quic/core/qpack/qpack_encoder.h
@@ -40,9 +40,8 @@
     virtual void OnDecoderStreamError(QuicStringPiece error_message) = 0;
   };
 
-  QpackEncoder(
-      DecoderStreamErrorDelegate* decoder_stream_error_delegate,
-      QpackEncoderStreamSender::Delegate* encoder_stream_sender_delegate);
+  QpackEncoder(DecoderStreamErrorDelegate* decoder_stream_error_delegate,
+               QpackStreamSenderDelegate* encoder_stream_sender_delegate);
   ~QpackEncoder() override;
 
   // This factory method is called to start encoding a header list.
diff --git a/quic/core/qpack/qpack_encoder_stream_sender.cc b/quic/core/qpack/qpack_encoder_stream_sender.cc
index 3fb3b33..e4299ed 100644
--- a/quic/core/qpack/qpack_encoder_stream_sender.cc
+++ b/quic/core/qpack/qpack_encoder_stream_sender.cc
@@ -13,7 +13,8 @@
 
 namespace quic {
 
-QpackEncoderStreamSender::QpackEncoderStreamSender(Delegate* delegate)
+QpackEncoderStreamSender::QpackEncoderStreamSender(
+    QpackStreamSenderDelegate* delegate)
     : delegate_(delegate) {
   DCHECK(delegate_);
 }
@@ -33,7 +34,7 @@
   instruction_encoder_.Next(std::numeric_limits<size_t>::max(), &output);
   DCHECK(!instruction_encoder_.HasNext());
 
-  delegate_->WriteEncoderStreamData(output);
+  delegate_->WriteStreamData(output);
 }
 
 void QpackEncoderStreamSender::SendInsertWithoutNameReference(
@@ -49,7 +50,7 @@
   instruction_encoder_.Next(std::numeric_limits<size_t>::max(), &output);
   DCHECK(!instruction_encoder_.HasNext());
 
-  delegate_->WriteEncoderStreamData(output);
+  delegate_->WriteStreamData(output);
 }
 
 void QpackEncoderStreamSender::SendDuplicate(uint64_t index) {
@@ -62,7 +63,7 @@
   instruction_encoder_.Next(std::numeric_limits<size_t>::max(), &output);
   DCHECK(!instruction_encoder_.HasNext());
 
-  delegate_->WriteEncoderStreamData(output);
+  delegate_->WriteStreamData(output);
 }
 
 void QpackEncoderStreamSender::SendSetDynamicTableCapacity(uint64_t capacity) {
@@ -75,7 +76,7 @@
   instruction_encoder_.Next(std::numeric_limits<size_t>::max(), &output);
   DCHECK(!instruction_encoder_.HasNext());
 
-  delegate_->WriteEncoderStreamData(output);
+  delegate_->WriteStreamData(output);
 }
 
 }  // namespace quic
diff --git a/quic/core/qpack/qpack_encoder_stream_sender.h b/quic/core/qpack/qpack_encoder_stream_sender.h
index ad34568..e395b6d 100644
--- a/quic/core/qpack/qpack_encoder_stream_sender.h
+++ b/quic/core/qpack/qpack_encoder_stream_sender.h
@@ -8,6 +8,7 @@
 #include <cstdint>
 
 #include "net/third_party/quiche/src/quic/core/qpack/qpack_instruction_encoder.h"
+#include "net/third_party/quiche/src/quic/core/qpack/qpack_stream_sender_delegate.h"
 #include "net/third_party/quiche/src/quic/platform/api/quic_export.h"
 #include "net/third_party/quiche/src/quic/platform/api/quic_string_piece.h"
 
@@ -16,19 +17,7 @@
 // This class serializes instructions for transmission on the encoder stream.
 class QUIC_EXPORT_PRIVATE QpackEncoderStreamSender {
  public:
-  // An interface for handling encoded data.
-  class Delegate {
-   public:
-    virtual ~Delegate() = default;
-
-    // Encoded |data| is ready to be written on the encoder stream.
-    // WriteEncoderStreamData() is called exactly once for each instruction.
-    // |data| contains the entire encoded instruction and it is guaranteed to be
-    // not empty.
-    virtual void WriteEncoderStreamData(QuicStringPiece data) = 0;
-  };
-
-  explicit QpackEncoderStreamSender(Delegate* delegate);
+  explicit QpackEncoderStreamSender(QpackStreamSenderDelegate* delegate);
   QpackEncoderStreamSender() = delete;
   QpackEncoderStreamSender(const QpackEncoderStreamSender&) = delete;
   QpackEncoderStreamSender& operator=(const QpackEncoderStreamSender&) = delete;
@@ -49,7 +38,7 @@
   void SendSetDynamicTableCapacity(uint64_t capacity);
 
  private:
-  Delegate* const delegate_;
+  QpackStreamSenderDelegate* const delegate_;
   QpackInstructionEncoder instruction_encoder_;
 };
 
diff --git a/quic/core/qpack/qpack_encoder_stream_sender_test.cc b/quic/core/qpack/qpack_encoder_stream_sender_test.cc
index ee8f399..2df9ffc 100644
--- a/quic/core/qpack/qpack_encoder_stream_sender_test.cc
+++ b/quic/core/qpack/qpack_encoder_stream_sender_test.cc
@@ -20,31 +20,30 @@
   QpackEncoderStreamSenderTest() : stream_(&delegate_) {}
   ~QpackEncoderStreamSenderTest() override = default;
 
-  StrictMock<MockEncoderStreamSenderDelegate> delegate_;
+  StrictMock<MockQpackStreamSenderDelegate> delegate_;
   QpackEncoderStreamSender stream_;
 };
 
 TEST_F(QpackEncoderStreamSenderTest, InsertWithNameReference) {
   // Static, index fits in prefix, empty value.
-  EXPECT_CALL(delegate_,
-              WriteEncoderStreamData(Eq(QuicTextUtils::HexDecode("c500"))));
+  EXPECT_CALL(delegate_, WriteStreamData(Eq(QuicTextUtils::HexDecode("c500"))));
   stream_.SendInsertWithNameReference(true, 5, "");
 
   // Static, index fits in prefix, Huffman encoded value.
   EXPECT_CALL(delegate_,
-              WriteEncoderStreamData(Eq(QuicTextUtils::HexDecode("c28294e7"))));
+              WriteStreamData(Eq(QuicTextUtils::HexDecode("c28294e7"))));
   stream_.SendInsertWithNameReference(true, 2, "foo");
 
   // Not static, index does not fit in prefix, not Huffman encoded value.
-  EXPECT_CALL(delegate_, WriteEncoderStreamData(
-                             Eq(QuicTextUtils::HexDecode("bf4a03626172"))));
+  EXPECT_CALL(delegate_,
+              WriteStreamData(Eq(QuicTextUtils::HexDecode("bf4a03626172"))));
   stream_.SendInsertWithNameReference(false, 137, "bar");
 
   // Value length does not fit in prefix.
   // 'Z' would be Huffman encoded to 8 bits, so no Huffman encoding is used.
   EXPECT_CALL(
       delegate_,
-      WriteEncoderStreamData(Eq(QuicTextUtils::HexDecode(
+      WriteStreamData(Eq(QuicTextUtils::HexDecode(
           "aa7f005a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a"
           "5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a"
           "5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a"
@@ -54,25 +53,24 @@
 
 TEST_F(QpackEncoderStreamSenderTest, InsertWithoutNameReference) {
   // Empty name and value.
-  EXPECT_CALL(delegate_,
-              WriteEncoderStreamData(Eq(QuicTextUtils::HexDecode("4000"))));
+  EXPECT_CALL(delegate_, WriteStreamData(Eq(QuicTextUtils::HexDecode("4000"))));
   stream_.SendInsertWithoutNameReference("", "");
 
   // Huffman encoded short strings.
-  EXPECT_CALL(delegate_, WriteEncoderStreamData(
+  EXPECT_CALL(delegate_, WriteStreamData(
                              Eq(QuicTextUtils::HexDecode("4362617203626172"))));
   stream_.SendInsertWithoutNameReference("bar", "bar");
 
   // Not Huffman encoded short strings.
-  EXPECT_CALL(delegate_, WriteEncoderStreamData(
-                             Eq(QuicTextUtils::HexDecode("6294e78294e7"))));
+  EXPECT_CALL(delegate_,
+              WriteStreamData(Eq(QuicTextUtils::HexDecode("6294e78294e7"))));
   stream_.SendInsertWithoutNameReference("foo", "foo");
 
   // Not Huffman encoded long strings; length does not fit on prefix.
   // 'Z' would be Huffman encoded to 8 bits, so no Huffman encoding is used.
   EXPECT_CALL(
       delegate_,
-      WriteEncoderStreamData(Eq(QuicTextUtils::HexDecode(
+      WriteStreamData(Eq(QuicTextUtils::HexDecode(
           "5f005a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a7f"
           "005a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a"
           "5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a"
@@ -84,25 +82,23 @@
 
 TEST_F(QpackEncoderStreamSenderTest, Duplicate) {
   // Small index fits in prefix.
-  EXPECT_CALL(delegate_,
-              WriteEncoderStreamData(Eq(QuicTextUtils::HexDecode("11"))));
+  EXPECT_CALL(delegate_, WriteStreamData(Eq(QuicTextUtils::HexDecode("11"))));
   stream_.SendDuplicate(17);
 
   // Large index requires two extension bytes.
   EXPECT_CALL(delegate_,
-              WriteEncoderStreamData(Eq(QuicTextUtils::HexDecode("1fd503"))));
+              WriteStreamData(Eq(QuicTextUtils::HexDecode("1fd503"))));
   stream_.SendDuplicate(500);
 }
 
 TEST_F(QpackEncoderStreamSenderTest, SetDynamicTableCapacity) {
   // Small capacity fits in prefix.
-  EXPECT_CALL(delegate_,
-              WriteEncoderStreamData(Eq(QuicTextUtils::HexDecode("31"))));
+  EXPECT_CALL(delegate_, WriteStreamData(Eq(QuicTextUtils::HexDecode("31"))));
   stream_.SendSetDynamicTableCapacity(17);
 
   // Large capacity requires two extension bytes.
   EXPECT_CALL(delegate_,
-              WriteEncoderStreamData(Eq(QuicTextUtils::HexDecode("3fd503"))));
+              WriteStreamData(Eq(QuicTextUtils::HexDecode("3fd503"))));
   stream_.SendSetDynamicTableCapacity(500);
 }
 
diff --git a/quic/core/qpack/qpack_encoder_test.cc b/quic/core/qpack/qpack_encoder_test.cc
index 8200e14..add6a74 100644
--- a/quic/core/qpack/qpack_encoder_test.cc
+++ b/quic/core/qpack/qpack_encoder_test.cc
@@ -8,6 +8,7 @@
 
 #include "net/third_party/quiche/src/quic/core/qpack/qpack_encoder_test_utils.h"
 #include "net/third_party/quiche/src/quic/core/qpack/qpack_test_utils.h"
+#include "net/third_party/quiche/src/quic/core/qpack/qpack_utils.h"
 #include "net/third_party/quiche/src/quic/platform/api/quic_test.h"
 #include "net/third_party/quiche/src/quic/platform/api/quic_text_utils.h"
 
@@ -31,7 +32,7 @@
   }
 
   StrictMock<MockDecoderStreamErrorDelegate> decoder_stream_error_delegate_;
-  NoopEncoderStreamSenderDelegate encoder_stream_sender_delegate_;
+  NoopQpackStreamSenderDelegate encoder_stream_sender_delegate_;
 
  private:
   const FragmentMode fragment_mode_;
diff --git a/quic/core/qpack/qpack_encoder_test_utils.cc b/quic/core/qpack/qpack_encoder_test_utils.cc
index a58b0ae..a5fdbea 100644
--- a/quic/core/qpack/qpack_encoder_test_utils.cc
+++ b/quic/core/qpack/qpack_encoder_test_utils.cc
@@ -12,12 +12,9 @@
 void NoopDecoderStreamErrorDelegate::OnDecoderStreamError(
     QuicStringPiece /*error_message*/) {}
 
-void NoopEncoderStreamSenderDelegate::WriteEncoderStreamData(
-    QuicStringPiece /*data*/) {}
-
 std::string QpackEncode(
     QpackEncoder::DecoderStreamErrorDelegate* decoder_stream_error_delegate,
-    QpackEncoderStreamSender::Delegate* encoder_stream_sender_delegate,
+    QpackStreamSenderDelegate* encoder_stream_sender_delegate,
     const FragmentSizeGenerator& fragment_size_generator,
     const spdy::SpdyHeaderBlock* header_list) {
   QpackEncoder encoder(decoder_stream_error_delegate,
diff --git a/quic/core/qpack/qpack_encoder_test_utils.h b/quic/core/qpack/qpack_encoder_test_utils.h
index 3c9b404..f897d45 100644
--- a/quic/core/qpack/qpack_encoder_test_utils.h
+++ b/quic/core/qpack/qpack_encoder_test_utils.h
@@ -34,27 +34,9 @@
   MOCK_METHOD1(OnDecoderStreamError, void(QuicStringPiece error_message));
 };
 
-// QpackEncoderStreamSender::Delegate implementation that does nothing.
-class NoopEncoderStreamSenderDelegate
-    : public QpackEncoderStreamSender::Delegate {
- public:
-  ~NoopEncoderStreamSenderDelegate() override = default;
-
-  void WriteEncoderStreamData(QuicStringPiece data) override;
-};
-
-// Mock QpackEncoderStreamSender::Delegate implementation.
-class MockEncoderStreamSenderDelegate
-    : public QpackEncoderStreamSender::Delegate {
- public:
-  ~MockEncoderStreamSenderDelegate() override = default;
-
-  MOCK_METHOD1(WriteEncoderStreamData, void(QuicStringPiece data));
-};
-
 std::string QpackEncode(
     QpackEncoder::DecoderStreamErrorDelegate* decoder_stream_error_delegate,
-    QpackEncoderStreamSender::Delegate* encoder_stream_sender_delegate,
+    QpackStreamSenderDelegate* encoder_stream_sender_delegate,
     const FragmentSizeGenerator& fragment_size_generator,
     const spdy::SpdyHeaderBlock* header_list);
 
diff --git a/quic/core/qpack/qpack_round_trip_test.cc b/quic/core/qpack/qpack_round_trip_test.cc
index 45ad667..4fc1a38 100644
--- a/quic/core/qpack/qpack_round_trip_test.cc
+++ b/quic/core/qpack/qpack_round_trip_test.cc
@@ -8,6 +8,7 @@
 #include "net/third_party/quiche/src/quic/core/qpack/qpack_decoder_test_utils.h"
 #include "net/third_party/quiche/src/quic/core/qpack/qpack_encoder_test_utils.h"
 #include "net/third_party/quiche/src/quic/core/qpack/qpack_test_utils.h"
+#include "net/third_party/quiche/src/quic/core/qpack/qpack_utils.h"
 #include "net/third_party/quiche/src/quic/platform/api/quic_string_piece.h"
 #include "net/third_party/quiche/src/quic/platform/api/quic_test.h"
 #include "net/third_party/quiche/src/spdy/core/spdy_header_block.h"
@@ -30,7 +31,7 @@
   spdy::SpdyHeaderBlock EncodeThenDecode(
       const spdy::SpdyHeaderBlock& header_list) {
     NoopDecoderStreamErrorDelegate decoder_stream_error_delegate;
-    NoopEncoderStreamSenderDelegate encoder_stream_sender_delegate;
+    NoopQpackStreamSenderDelegate encoder_stream_sender_delegate;
     std::string encoded_header_block = QpackEncode(
         &decoder_stream_error_delegate, &encoder_stream_sender_delegate,
         FragmentModeToFragmentSizeGenerator(encoding_fragment_mode_),
@@ -38,7 +39,7 @@
 
     TestHeadersHandler handler;
     NoopEncoderStreamErrorDelegate encoder_stream_error_delegate;
-    NoopDecoderStreamSenderDelegate decoder_stream_sender_delegate;
+    NoopQpackStreamSenderDelegate decoder_stream_sender_delegate;
     QpackDecode(&encoder_stream_error_delegate, &decoder_stream_sender_delegate,
                 &handler,
                 FragmentModeToFragmentSizeGenerator(decoding_fragment_mode_),
diff --git a/quic/core/qpack/qpack_send_stream.h b/quic/core/qpack/qpack_send_stream.h
index dab4fd0..aa3cb79 100644
--- a/quic/core/qpack/qpack_send_stream.h
+++ b/quic/core/qpack/qpack_send_stream.h
@@ -5,6 +5,7 @@
 #ifndef QUICHE_QUIC_CORE_QPACK_QPACK_SEND_STREAM_H_
 #define QUICHE_QUIC_CORE_QPACK_QPACK_SEND_STREAM_H_
 
+#include "net/third_party/quiche/src/quic/core/qpack/qpack_stream_sender_delegate.h"
 #include "net/third_party/quiche/src/quic/core/quic_stream.h"
 #include "net/third_party/quiche/src/quic/platform/api/quic_export.h"
 
@@ -14,7 +15,8 @@
 
 // QPACK 4.2.1 Encoder and Decoder Streams.
 // The QPACK send stream is self initiated and is write only.
-class QUIC_EXPORT_PRIVATE QpackSendStream : public QuicStream {
+class QUIC_EXPORT_PRIVATE QpackSendStream : public QuicStream,
+                                            public QpackStreamSenderDelegate {
  public:
   // |session| can't be nullptr, and the ownership is not passed. |session| owns
   // this stream.
@@ -35,7 +37,7 @@
 
   // Writes the instructions to peer. The stream type will be sent
   // before the first instruction so that the peer can open an qpack stream.
-  void WriteStreamData(QuicStringPiece data);
+  void WriteStreamData(QuicStringPiece data) override;
 
  private:
   const uint64_t stream_type_;
diff --git a/quic/core/qpack/qpack_stream_sender_delegate.h b/quic/core/qpack/qpack_stream_sender_delegate.h
new file mode 100644
index 0000000..616df98
--- /dev/null
+++ b/quic/core/qpack/qpack_stream_sender_delegate.h
@@ -0,0 +1,24 @@
+// Copyright (c) 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef QUICHE_QUIC_CORE_QPACK_QPACK_STREAM_SENDER_DELEGATE_H_
+#define QUICHE_QUIC_CORE_QPACK_QPACK_STREAM_SENDER_DELEGATE_H_
+
+#include "net/third_party/quiche/src/quic/platform/api/quic_export.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_string_piece.h"
+
+namespace quic {
+
+// This interface writes encoder/decoder data to peer.
+class QUIC_EXPORT_PRIVATE QpackStreamSenderDelegate {
+ public:
+  virtual ~QpackStreamSenderDelegate() = default;
+
+  // Write data on the unidirectional stream.
+  virtual void WriteStreamData(QuicStringPiece data) = 0;
+};
+
+}  // namespace quic
+
+#endif  // QUICHE_QUIC_CORE_QPACK_QPACK_STREAM_SENDER_DELEGATE_H_
diff --git a/quic/core/qpack/qpack_test_utils.h b/quic/core/qpack/qpack_test_utils.h
index 65bb5a2..42fa383 100644
--- a/quic/core/qpack/qpack_test_utils.h
+++ b/quic/core/qpack/qpack_test_utils.h
@@ -8,6 +8,9 @@
 #include <cstddef>
 #include <functional>
 
+#include "net/third_party/quiche/src/quic/core/qpack/qpack_stream_sender_delegate.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_test.h"
+
 namespace quic {
 namespace test {
 
@@ -23,6 +26,14 @@
 FragmentSizeGenerator FragmentModeToFragmentSizeGenerator(
     FragmentMode fragment_mode);
 
+// Mock QpackUnidirectionalStreamSenderDelegate implementation.
+class MockQpackStreamSenderDelegate : public QpackStreamSenderDelegate {
+ public:
+  ~MockQpackStreamSenderDelegate() override = default;
+
+  MOCK_METHOD1(WriteStreamData, void(QuicStringPiece data));
+};
+
 }  // namespace test
 }  // namespace quic
 
diff --git a/quic/core/qpack/qpack_utils.h b/quic/core/qpack/qpack_utils.h
new file mode 100644
index 0000000..1b63422
--- /dev/null
+++ b/quic/core/qpack/qpack_utils.h
@@ -0,0 +1,23 @@
+// Copyright (c) 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef QUICHE_QUIC_CORE_QPACK_QPACK_UTILS_H_
+#define QUICHE_QUIC_CORE_QPACK_QPACK_UTILS_H_
+
+#include "net/third_party/quiche/src/quic/core/qpack/qpack_stream_sender_delegate.h"
+
+namespace quic {
+// TODO(renjietang): Move this class to qpack_test_utils.h once it is not needed
+// in QuicSpdySession.
+class QUIC_EXPORT_PRIVATE NoopQpackStreamSenderDelegate
+    : public QpackStreamSenderDelegate {
+ public:
+  ~NoopQpackStreamSenderDelegate() override = default;
+
+  void WriteStreamData(QuicStringPiece /*data*/) override {}
+};
+
+}  // namespace quic
+
+#endif  // QUICHE_QUIC_CORE_QPACK_QPACK_UTILS_H_