Merge changes I01fea753,I3e67bf92,I8bdbdadd,I1a96285a,I1c67ed93 * changes: Fix return type of QuicSpdyClientBase::latest_response_code Change QuicSpdyStreamBodyBuffer API to decouple from QuicStreamSequencer. gfe-relnote: Add IsStreamReady() interface to WriteScheduler and implement the interface in subclasses. No functional expected. Not protected. Call MarkConsumed() only once in QuicSpdyStreamBodyBuffer::MarkBodyConsumed() with a combined byte count. Add debugging logs for Priority frames.
diff --git a/quic/core/http/http_frames.h b/quic/core/http/http_frames.h index ac590e6..ced2032 100644 --- a/quic/core/http/http_frames.h +++ b/quic/core/http/http_frames.h
@@ -80,6 +80,20 @@ element_dependency_id == rhs.element_dependency_id && weight == rhs.weight; } + std::string ToString() const { + return QuicStrCat("Priority Frame : {prioritized_type: ", prioritized_type, + ", dependency_type: ", dependency_type, + ", exclusive: ", exclusive, + ", prioritized_element_id: ", prioritized_element_id, + ", element_dependency_id: ", element_dependency_id, + ", weight: ", weight, "}"); + } + + friend QUIC_EXPORT_PRIVATE std::ostream& operator<<(std::ostream& os, + const PriorityFrame& s) { + os << s.ToString(); + return os; + } }; // 4.2.4. CANCEL_PUSH
diff --git a/quic/core/http/quic_send_control_stream.cc b/quic/core/http/quic_send_control_stream.cc index a53f931..348f63d 100644 --- a/quic/core/http/quic_send_control_stream.cc +++ b/quic/core/http/quic_send_control_stream.cc
@@ -59,6 +59,7 @@ std::unique_ptr<char[]> buffer; QuicByteCount frame_length = encoder_.SerializePriorityFrame(priority, &buffer); + QUIC_DVLOG(1) << "Control Stream " << id() << " is writing " << priority; WriteOrBufferData(QuicStringPiece(buffer.get(), frame_length), false, nullptr); }
diff --git a/quic/core/http/quic_spdy_stream.cc b/quic/core/http/quic_spdy_stream.cc index c731741..a8e81c1 100644 --- a/quic/core/http/quic_spdy_stream.cc +++ b/quic/core/http/quic_spdy_stream.cc
@@ -188,7 +188,6 @@ headers_bytes_to_be_marked_consumed_(0), http_decoder_visitor_(QuicMakeUnique<HttpDecoderVisitor>(this)), decoder_(http_decoder_visitor_.get()), - body_buffer_(sequencer()), sequencer_offset_(0), is_decoder_processing_input_(false), ack_listener_(nullptr) { @@ -225,7 +224,6 @@ headers_bytes_to_be_marked_consumed_(0), http_decoder_visitor_(QuicMakeUnique<HttpDecoderVisitor>(this)), decoder_(http_decoder_visitor_.get()), - body_buffer_(sequencer()), sequencer_offset_(sequencer()->NumBytesConsumed()), is_decoder_processing_input_(false), ack_listener_(nullptr) { @@ -397,7 +395,8 @@ if (!VersionHasDataFrameHeader(transport_version())) { return sequencer()->Readv(iov, iov_len); } - size_t bytes_read = body_buffer_.ReadBody(iov, iov_len); + size_t bytes_read = 0; + sequencer()->MarkConsumed(body_buffer_.ReadBody(iov, iov_len, &bytes_read)); if (VersionUsesQpack(transport_version())) { // Maybe all DATA frame bytes have been read and some trailing HEADERS had @@ -422,7 +421,7 @@ sequencer()->MarkConsumed(num_bytes); return; } - body_buffer_.MarkBodyConsumed(num_bytes); + sequencer()->MarkConsumed(body_buffer_.OnBodyConsumed(num_bytes)); if (VersionUsesQpack(transport_version())) { // Maybe all DATA frame bytes have been read and some trailing HEADERS had
diff --git a/quic/core/http/quic_spdy_stream_body_buffer.cc b/quic/core/http/quic_spdy_stream_body_buffer.cc index d175e13..c29c766 100644 --- a/quic/core/http/quic_spdy_stream_body_buffer.cc +++ b/quic/core/http/quic_spdy_stream_body_buffer.cc
@@ -6,20 +6,15 @@ #include <algorithm> -#include "net/third_party/quiche/src/quic/core/quic_stream_sequencer.h" #include "net/third_party/quiche/src/quic/platform/api/quic_logging.h" namespace quic { -QuicSpdyStreamBodyBuffer::QuicSpdyStreamBodyBuffer( - QuicStreamSequencer* sequencer) +QuicSpdyStreamBodyBuffer::QuicSpdyStreamBodyBuffer() : bytes_remaining_(0), total_body_bytes_readable_(0), total_body_bytes_received_(0), - total_payload_lengths_(0), - sequencer_(sequencer) {} - -QuicSpdyStreamBodyBuffer::~QuicSpdyStreamBodyBuffer() {} + total_payload_lengths_(0) {} void QuicSpdyStreamBodyBuffer::OnDataHeader(Http3FrameLengths frame_lengths) { frame_meta_.push_back(frame_lengths); @@ -34,21 +29,21 @@ DCHECK_LE(total_body_bytes_received_, total_payload_lengths_); } -void QuicSpdyStreamBodyBuffer::MarkBodyConsumed(size_t num_bytes) { +size_t QuicSpdyStreamBodyBuffer::OnBodyConsumed(size_t num_bytes) { // Check if the stream has enough decoded data. if (num_bytes > total_body_bytes_readable_) { - QUIC_BUG << "Invalid argument to MarkBodyConsumed." + QUIC_BUG << "Invalid argument to OnBodyConsumed." << " expect to consume: " << num_bytes << ", but not enough bytes available. " << "Total bytes readable are: " << total_body_bytes_readable_; - return; + return 0; } // Discard references in the stream before the sequencer marks them consumed. size_t remaining = num_bytes; while (remaining > 0) { if (bodies_.empty()) { QUIC_BUG << "Failed to consume because body buffer is empty."; - return; + return 0; } auto body = bodies_.front(); bodies_.pop_front(); @@ -60,21 +55,26 @@ remaining = 0; } } + // Consume headers. + size_t bytes_to_consume = 0; while (bytes_remaining_ < num_bytes) { if (frame_meta_.empty()) { QUIC_BUG << "Faild to consume because frame header buffer is empty."; - return; + return 0; } auto meta = frame_meta_.front(); frame_meta_.pop_front(); bytes_remaining_ += meta.payload_length; - sequencer_->MarkConsumed(meta.header_length); + bytes_to_consume += meta.header_length; } - sequencer_->MarkConsumed(num_bytes); + bytes_to_consume += num_bytes; + // Update accountings. bytes_remaining_ -= num_bytes; total_body_bytes_readable_ -= num_bytes; + + return bytes_to_consume; } int QuicSpdyStreamBodyBuffer::PeekBody(iovec* iov, size_t iov_len) const { @@ -98,8 +98,9 @@ } size_t QuicSpdyStreamBodyBuffer::ReadBody(const struct iovec* iov, - size_t iov_len) { - size_t total_data_read = 0; + size_t iov_len, + size_t* total_bytes_read) { + *total_bytes_read = 0; QuicByteCount total_remaining = total_body_bytes_readable_; size_t index = 0; size_t src_offset = 0; @@ -114,7 +115,7 @@ bytes_to_copy); dest += bytes_to_copy; dest_remaining -= bytes_to_copy; - total_data_read += bytes_to_copy; + *total_bytes_read += bytes_to_copy; total_remaining -= bytes_to_copy; if (bytes_to_copy < body.length() - src_offset) { src_offset += bytes_to_copy; @@ -125,8 +126,7 @@ } } - MarkBodyConsumed(total_data_read); - return total_data_read; + return OnBodyConsumed(*total_bytes_read); } } // namespace quic
diff --git a/quic/core/http/quic_spdy_stream_body_buffer.h b/quic/core/http/quic_spdy_stream_body_buffer.h index d8431c1..a37f3bf 100644 --- a/quic/core/http/quic_spdy_stream_body_buffer.h +++ b/quic/core/http/quic_spdy_stream_body_buffer.h
@@ -10,6 +10,7 @@ #include "net/third_party/quiche/src/quic/platform/api/quic_containers.h" #include "net/third_party/quiche/src/quic/platform/api/quic_export.h" #include "net/third_party/quiche/src/quic/platform/api/quic_iovec.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_macros.h" namespace quic { @@ -19,11 +20,8 @@ // consume data. class QUIC_EXPORT_PRIVATE QuicSpdyStreamBodyBuffer { public: - // QuicSpdyStreamBodyBuffer doesn't own the sequencer and the sequencer can - // outlive the buffer. - explicit QuicSpdyStreamBodyBuffer(QuicStreamSequencer* sequencer); - - ~QuicSpdyStreamBodyBuffer(); + QuicSpdyStreamBodyBuffer(); + ~QuicSpdyStreamBodyBuffer() = default; // Add metadata of the frame to accountings. // Called when QuicSpdyStream receives data frame header. @@ -35,9 +33,10 @@ // QuicStreamSequencer::MarkConsumed(). void OnDataPayload(QuicStringPiece payload); - // Take |num_bytes| as the body size, calculate header sizes accordingly, and - // consume the right amount of data in the stream sequencer. - void MarkBodyConsumed(size_t num_bytes); + // Internally marks |num_bytes| of DATA frame payload consumed, and returns + // the number of bytes that the caller should mark consumed with the + // sequencer, including DATA frame header bytes, if any. + QUIC_MUST_USE_RESULT size_t OnBodyConsumed(size_t num_bytes); // Fill up to |iov_len| with bodies available in buffer. No data is consumed. // |iov|.iov_base will point to data in the buffer, and |iov|.iov_len will @@ -47,9 +46,11 @@ // Copies from buffer into |iov| up to |iov_len|, and consume data in // sequencer. |iov.iov_base| and |iov.iov_len| are preassigned and will not be - // changed. - // Returns the number of bytes read. - size_t ReadBody(const struct iovec* iov, size_t iov_len); + // changed. |*total_bytes_read| is set to the number of bytes read. Returns + // the number of bytes that should be marked consumed with the sequencer. + QUIC_MUST_USE_RESULT size_t ReadBody(const struct iovec* iov, + size_t iov_len, + size_t* total_bytes_read); bool HasBytesToRead() const { return !bodies_.empty(); } @@ -70,8 +71,6 @@ QuicByteCount total_body_bytes_received_; // Total length of payloads tracked by frame_meta_. QuicByteCount total_payload_lengths_; - // Stream sequencer that directly manages data in the stream. - QuicStreamSequencer* sequencer_; }; } // namespace quic
diff --git a/quic/core/http/quic_spdy_stream_body_buffer_test.cc b/quic/core/http/quic_spdy_stream_body_buffer_test.cc index 6e8e20d..d5e8161 100644 --- a/quic/core/http/quic_spdy_stream_body_buffer_test.cc +++ b/quic/core/http/quic_spdy_stream_body_buffer_test.cc
@@ -6,13 +6,9 @@ #include <string> -#include "net/third_party/quiche/src/quic/core/quic_stream_sequencer.h" #include "net/third_party/quiche/src/quic/platform/api/quic_expect_bug.h" #include "net/third_party/quiche/src/quic/platform/api/quic_logging.h" -#include "net/third_party/quiche/src/quic/platform/api/quic_ptr_util.h" -#include "net/third_party/quiche/src/quic/platform/api/quic_str_cat.h" #include "net/third_party/quiche/src/quic/platform/api/quic_test.h" -#include "net/third_party/quiche/src/quic/test_tools/quic_test_utils.h" namespace quic { @@ -20,51 +16,16 @@ namespace { -class MockStream : public QuicStreamSequencer::StreamInterface { - public: - MOCK_METHOD0(OnFinRead, void()); - MOCK_METHOD0(OnDataAvailable, void()); - MOCK_METHOD2(CloseConnectionWithDetails, - void(QuicErrorCode error, const std::string& details)); - MOCK_METHOD1(Reset, void(QuicRstStreamErrorCode error)); - MOCK_METHOD0(OnCanWrite, void()); - MOCK_METHOD1(AddBytesConsumed, void(QuicByteCount bytes)); - - QuicStreamId id() const override { return 1; } - - const QuicSocketAddress& PeerAddressOfLatestPacket() const override { - return peer_address_; - } - - protected: - QuicSocketAddress peer_address_ = - QuicSocketAddress(QuicIpAddress::Any4(), 65535); -}; - -class MockSequencer : public QuicStreamSequencer { - public: - explicit MockSequencer(MockStream* stream) : QuicStreamSequencer(stream) {} - virtual ~MockSequencer() = default; - MOCK_METHOD1(MarkConsumed, void(size_t num_bytes_consumed)); -}; - class QuicSpdyStreamBodyBufferTest : public QuicTest { - public: - QuicSpdyStreamBodyBufferTest() - : sequencer_(&stream_), body_buffer_(&sequencer_) {} - protected: - MockStream stream_; - MockSequencer sequencer_; QuicSpdyStreamBodyBuffer body_buffer_; - HttpEncoder encoder_; }; TEST_F(QuicSpdyStreamBodyBufferTest, ReceiveBodies) { std::string body(1024, 'a'); EXPECT_FALSE(body_buffer_.HasBytesToRead()); body_buffer_.OnDataHeader(Http3FrameLengths(3, 1024)); - body_buffer_.OnDataPayload(QuicStringPiece(body)); + body_buffer_.OnDataPayload(body); EXPECT_EQ(1024u, body_buffer_.total_body_bytes_received()); EXPECT_TRUE(body_buffer_.HasBytesToRead()); } @@ -72,7 +33,7 @@ TEST_F(QuicSpdyStreamBodyBufferTest, PeekBody) { std::string body(1024, 'a'); body_buffer_.OnDataHeader(Http3FrameLengths(3, 1024)); - body_buffer_.OnDataPayload(QuicStringPiece(body)); + body_buffer_.OnDataPayload(body); EXPECT_EQ(1024u, body_buffer_.total_body_bytes_received()); iovec vec; EXPECT_EQ(1, body_buffer_.PeekBody(&vec, 1)); @@ -85,19 +46,11 @@ TEST_F(QuicSpdyStreamBodyBufferTest, MarkConsumedPartialSingleFrame) { testing::InSequence seq; std::string body(1024, 'a'); - std::unique_ptr<char[]> buffer; - QuicByteCount header_length = - encoder_.SerializeDataFrameHeader(body.length(), &buffer); - std::string header = std::string(buffer.get(), header_length); + const QuicByteCount header_length = 3; Http3FrameLengths lengths(header_length, 1024); - std::string data = header + body; - QuicStreamFrame frame(1, false, 0, data); - sequencer_.OnStreamFrame(frame); body_buffer_.OnDataHeader(lengths); - body_buffer_.OnDataPayload(QuicStringPiece(body)); - EXPECT_CALL(stream_, AddBytesConsumed(header_length)); - EXPECT_CALL(stream_, AddBytesConsumed(1024)); - body_buffer_.MarkBodyConsumed(1024); + body_buffer_.OnDataPayload(body); + EXPECT_EQ(header_length + 1024, body_buffer_.OnBodyConsumed(1024)); } // Buffer received 2 frames. Stream consumes multiple times. @@ -105,37 +58,21 @@ testing::InSequence seq; // 1st frame. std::string body1(1024, 'a'); - std::unique_ptr<char[]> buffer; - QuicByteCount header_length1 = - encoder_.SerializeDataFrameHeader(body1.length(), &buffer); - std::string header1 = std::string(buffer.get(), header_length1); + const QuicByteCount header_length1 = 2; Http3FrameLengths lengths1(header_length1, 1024); - std::string data1 = header1 + body1; - QuicStreamFrame frame1(1, false, 0, data1); - sequencer_.OnStreamFrame(frame1); body_buffer_.OnDataHeader(lengths1); - body_buffer_.OnDataPayload(QuicStringPiece(body1)); + body_buffer_.OnDataPayload(body1); // 2nd frame. std::string body2(2048, 'b'); - QuicByteCount header_length2 = - encoder_.SerializeDataFrameHeader(body2.length(), &buffer); - std::string header2 = std::string(buffer.get(), header_length2); + const QuicByteCount header_length2 = 4; Http3FrameLengths lengths2(header_length2, 2048); - std::string data2 = header2 + body2; - QuicStreamFrame frame2(1, false, data1.length(), data2); - sequencer_.OnStreamFrame(frame2); body_buffer_.OnDataHeader(lengths2); - body_buffer_.OnDataPayload(QuicStringPiece(body2)); + body_buffer_.OnDataPayload(body2); - EXPECT_CALL(stream_, AddBytesConsumed(header_length1)); - EXPECT_CALL(stream_, AddBytesConsumed(512)); - body_buffer_.MarkBodyConsumed(512); - EXPECT_CALL(stream_, AddBytesConsumed(header_length2)); - EXPECT_CALL(stream_, AddBytesConsumed(2048)); - body_buffer_.MarkBodyConsumed(2048); - EXPECT_CALL(stream_, AddBytesConsumed(512)); - body_buffer_.MarkBodyConsumed(512); + EXPECT_EQ(header_length1 + 512, body_buffer_.OnBodyConsumed(512)); + EXPECT_EQ(header_length2 + 2048, body_buffer_.OnBodyConsumed(2048)); + EXPECT_EQ(512u, body_buffer_.OnBodyConsumed(512)); } TEST_F(QuicSpdyStreamBodyBufferTest, MarkConsumedMoreThanBuffered) { @@ -143,33 +80,29 @@ Http3FrameLengths lengths(3, 1024); body_buffer_.OnDataHeader(lengths); body_buffer_.OnDataPayload(body); + size_t bytes_to_consume = 0; EXPECT_QUIC_BUG( - body_buffer_.MarkBodyConsumed(2048), - "Invalid argument to MarkBodyConsumed. expect to consume: 2048, but not " + bytes_to_consume = body_buffer_.OnBodyConsumed(2048), + "Invalid argument to OnBodyConsumed. expect to consume: 2048, but not " "enough bytes available. Total bytes readable are: 1024"); + EXPECT_EQ(0u, bytes_to_consume); } // Buffer receives 1 frame. Stream read from the buffer. TEST_F(QuicSpdyStreamBodyBufferTest, ReadSingleBody) { testing::InSequence seq; std::string body(1024, 'a'); - std::unique_ptr<char[]> buffer; - QuicByteCount header_length = - encoder_.SerializeDataFrameHeader(body.length(), &buffer); - std::string header = std::string(buffer.get(), header_length); + const QuicByteCount header_length = 2; Http3FrameLengths lengths(header_length, 1024); - std::string data = header + body; - QuicStreamFrame frame(1, false, 0, data); - sequencer_.OnStreamFrame(frame); body_buffer_.OnDataHeader(lengths); - body_buffer_.OnDataPayload(QuicStringPiece(body)); - - EXPECT_CALL(stream_, AddBytesConsumed(header_length)); - EXPECT_CALL(stream_, AddBytesConsumed(1024)); + body_buffer_.OnDataPayload(body); char base[1024]; iovec iov = {&base[0], 1024}; - EXPECT_EQ(1024u, body_buffer_.ReadBody(&iov, 1)); + size_t total_bytes_read = 0; + EXPECT_EQ(header_length + 1024, + body_buffer_.ReadBody(&iov, 1, &total_bytes_read)); + EXPECT_EQ(1024u, total_bytes_read); EXPECT_EQ(1024u, iov.iov_len); EXPECT_EQ(body, QuicStringPiece(static_cast<const char*>(iov.iov_base), 1024)); @@ -180,54 +113,44 @@ testing::InSequence seq; // 1st frame. std::string body1(1024, 'a'); - std::unique_ptr<char[]> buffer; - QuicByteCount header_length1 = - encoder_.SerializeDataFrameHeader(body1.length(), &buffer); - std::string header1 = std::string(buffer.get(), header_length1); + const QuicByteCount header_length1 = 2; Http3FrameLengths lengths1(header_length1, 1024); - std::string data1 = header1 + body1; - QuicStreamFrame frame1(1, false, 0, data1); - sequencer_.OnStreamFrame(frame1); body_buffer_.OnDataHeader(lengths1); - body_buffer_.OnDataPayload(QuicStringPiece(body1)); + body_buffer_.OnDataPayload(body1); // 2nd frame. std::string body2(2048, 'b'); - QuicByteCount header_length2 = - encoder_.SerializeDataFrameHeader(body2.length(), &buffer); - std::string header2 = std::string(buffer.get(), header_length2); + const QuicByteCount header_length2 = 4; Http3FrameLengths lengths2(header_length2, 2048); - std::string data2 = header2 + body2; - QuicStreamFrame frame2(1, false, data1.length(), data2); - sequencer_.OnStreamFrame(frame2); body_buffer_.OnDataHeader(lengths2); - body_buffer_.OnDataPayload(QuicStringPiece(body2)); + body_buffer_.OnDataPayload(body2); // First read of 512 bytes. - EXPECT_CALL(stream_, AddBytesConsumed(header_length1)); - EXPECT_CALL(stream_, AddBytesConsumed(512)); char base[512]; iovec iov = {&base[0], 512}; - EXPECT_EQ(512u, body_buffer_.ReadBody(&iov, 1)); + size_t total_bytes_read = 0; + EXPECT_EQ(header_length1 + 512, + body_buffer_.ReadBody(&iov, 1, &total_bytes_read)); + EXPECT_EQ(512u, total_bytes_read); EXPECT_EQ(512u, iov.iov_len); EXPECT_EQ(body1.substr(0, 512), QuicStringPiece(static_cast<const char*>(iov.iov_base), 512)); // Second read of 2048 bytes. - EXPECT_CALL(stream_, AddBytesConsumed(header_length2)); - EXPECT_CALL(stream_, AddBytesConsumed(2048)); char base2[2048]; iovec iov2 = {&base2[0], 2048}; - EXPECT_EQ(2048u, body_buffer_.ReadBody(&iov2, 1)); + EXPECT_EQ(header_length2 + 2048, + body_buffer_.ReadBody(&iov2, 1, &total_bytes_read)); + EXPECT_EQ(2048u, total_bytes_read); EXPECT_EQ(2048u, iov2.iov_len); EXPECT_EQ(body1.substr(512, 512) + body2.substr(0, 1536), QuicStringPiece(static_cast<const char*>(iov2.iov_base), 2048)); // Third read of the rest 512 bytes. - EXPECT_CALL(stream_, AddBytesConsumed(512)); char base3[512]; iovec iov3 = {&base3[0], 512}; - EXPECT_EQ(512u, body_buffer_.ReadBody(&iov3, 1)); + EXPECT_EQ(512u, body_buffer_.ReadBody(&iov3, 1, &total_bytes_read)); + EXPECT_EQ(512u, total_bytes_read); EXPECT_EQ(512u, iov3.iov_len); EXPECT_EQ(body2.substr(1536, 512), QuicStringPiece(static_cast<const char*>(iov3.iov_base), 512));
diff --git a/quic/tools/quic_spdy_client_base.cc b/quic/tools/quic_spdy_client_base.cc index 770b6ab..3a3bafe 100644 --- a/quic/tools/quic_spdy_client_base.cc +++ b/quic/tools/quic_spdy_client_base.cc
@@ -234,7 +234,7 @@ } } -size_t QuicSpdyClientBase::latest_response_code() const { +int QuicSpdyClientBase::latest_response_code() const { QUIC_BUG_IF(!store_response_) << "Response not stored!"; return latest_response_code_; }
diff --git a/quic/tools/quic_spdy_client_base.h b/quic/tools/quic_spdy_client_base.h index dc1811d..b04ba66 100644 --- a/quic/tools/quic_spdy_client_base.h +++ b/quic/tools/quic_spdy_client_base.h
@@ -120,7 +120,7 @@ void set_store_response(bool val) { store_response_ = val; } - size_t latest_response_code() const; + int latest_response_code() const; const std::string& latest_response_headers() const; const std::string& preliminary_response_headers() const; const spdy::SpdyHeaderBlock& latest_response_header_block() const;
diff --git a/quic/tools/quic_toy_client.cc b/quic/tools/quic_toy_client.cc index 06ae497..319d3a2 100644 --- a/quic/tools/quic_toy_client.cc +++ b/quic/tools/quic_toy_client.cc
@@ -325,7 +325,7 @@ return 1; } - size_t response_code = client->latest_response_code(); + int response_code = client->latest_response_code(); if (response_code >= 200 && response_code < 300) { std::cout << "Request succeeded (" << response_code << ")." << std::endl; } else if (response_code >= 300 && response_code < 400) {
diff --git a/spdy/core/priority_write_scheduler.h b/spdy/core/priority_write_scheduler.h index 20c9c13..bcacb25 100644 --- a/spdy/core/priority_write_scheduler.h +++ b/spdy/core/priority_write_scheduler.h
@@ -265,7 +265,7 @@ } // Returns true if a stream is ready. - bool IsStreamReady(StreamIdType stream_id) const { + bool IsStreamReady(StreamIdType stream_id) const override { auto it = stream_infos_.find(stream_id); if (it == stream_infos_.end()) { SPDY_DLOG(INFO) << "Stream " << stream_id << " not registered";
diff --git a/spdy/core/write_scheduler.h b/spdy/core/write_scheduler.h index 07e5fb3..7906ad7 100644 --- a/spdy/core/write_scheduler.h +++ b/spdy/core/write_scheduler.h
@@ -147,6 +147,9 @@ // Returns the number of streams currently marked ready. virtual size_t NumReadyStreams() const = 0; + // Returns true if stream with |stream_id| is ready. + virtual bool IsStreamReady(StreamIdType stream_id) const = 0; + // Returns summary of internal state, for logging/debugging. virtual SpdyString DebugString() const = 0; };