Index: net/quic/core/quic_headers_stream.cc |
diff --git a/net/quic/core/quic_headers_stream.cc b/net/quic/core/quic_headers_stream.cc |
index 81e9886c80af6e0740d47743abde2050824baeda..9f035732844ace71fd6a3660c5d43eb9591f93d6 100644 |
--- a/net/quic/core/quic_headers_stream.cc |
+++ b/net/quic/core/quic_headers_stream.cc |
@@ -4,455 +4,19 @@ |
#include "net/quic/core/quic_headers_stream.h" |
-#include <algorithm> |
-#include <cstdint> |
-#include <string> |
-#include <utility> |
- |
-#include "base/macros.h" |
-#include "base/metrics/histogram_macros.h" |
-#include "base/strings/string_number_conversions.h" |
-#include "base/strings/stringprintf.h" |
-#include "net/quic/core/quic_bug_tracker.h" |
#include "net/quic/core/quic_flags.h" |
-#include "net/quic/core/quic_header_list.h" |
-#include "net/quic/core/quic_server_session_base.h" |
#include "net/quic/core/quic_spdy_session.h" |
-#include "net/quic/core/quic_time.h" |
-#include "net/quic/platform/api/quic_str_cat.h" |
-#include "net/spdy/spdy_protocol.h" |
- |
-using base::StringPiece; |
-using std::string; |
namespace net { |
-namespace { |
- |
-class HeaderTableDebugVisitor : public HpackHeaderTable::DebugVisitorInterface { |
- public: |
- HeaderTableDebugVisitor( |
- const QuicClock* clock, |
- std::unique_ptr<QuicHeadersStream::HpackDebugVisitor> visitor) |
- : clock_(clock), headers_stream_hpack_visitor_(std::move(visitor)) {} |
- |
- int64_t OnNewEntry(const HpackEntry& entry) override { |
- DVLOG(1) << entry.GetDebugString(); |
- return (clock_->ApproximateNow() - QuicTime::Zero()).ToMicroseconds(); |
- } |
- |
- void OnUseEntry(const HpackEntry& entry) override { |
- const QuicTime::Delta elapsed( |
- clock_->ApproximateNow() - |
- QuicTime::Delta::FromMicroseconds(entry.time_added()) - |
- QuicTime::Zero()); |
- DVLOG(1) << entry.GetDebugString() << " " << elapsed.ToMilliseconds() |
- << " ms"; |
- headers_stream_hpack_visitor_->OnUseEntry(elapsed); |
- } |
- |
- private: |
- const QuicClock* clock_; |
- std::unique_ptr<QuicHeadersStream::HpackDebugVisitor> |
- headers_stream_hpack_visitor_; |
- |
- DISALLOW_COPY_AND_ASSIGN(HeaderTableDebugVisitor); |
-}; |
- |
-// When forced HOL blocking is enabled, extra bytes in the form of |
-// HTTP/2 DATA frame headers are inserted on the way down to the |
-// session layer. |ForceAckListener| filters the |OnPacketAcked()| |
-// notifications generated by the session layer to not count the extra |
-// bytes. Otherwise, code that is using ack listener on streams might |
-// consider it an error if more bytes are acked than were written to |
-// the stream, it is the case with some internal stats gathering code. |
-class ForceHolAckListener : public QuicAckListenerInterface { |
- public: |
- // |extra_bytes| should be initialized to the size of the HTTP/2 |
- // DATA frame header inserted when forced HOL blocking is enabled. |
- ForceHolAckListener( |
- QuicReferenceCountedPointer<QuicAckListenerInterface> stream_ack_listener, |
- int extra_bytes) |
- : stream_ack_listener_(std::move(stream_ack_listener)), |
- extra_bytes_(extra_bytes) { |
- DCHECK_GE(extra_bytes, 0); |
- } |
- |
- void OnPacketAcked(int acked_bytes, QuicTime::Delta ack_delay_time) override { |
- if (extra_bytes_ > 0) { |
- // Don't count the added HTTP/2 DATA frame header bytes |
- int delta = std::min(extra_bytes_, acked_bytes); |
- extra_bytes_ -= delta; |
- acked_bytes -= delta; |
- } |
- stream_ack_listener_->OnPacketAcked(acked_bytes, ack_delay_time); |
- } |
- |
- void OnPacketRetransmitted(int retransmitted_bytes) override { |
- stream_ack_listener_->OnPacketRetransmitted(retransmitted_bytes); |
- } |
- |
- protected: |
- ~ForceHolAckListener() override {} |
- |
- private: |
- QuicReferenceCountedPointer<QuicAckListenerInterface> stream_ack_listener_; |
- int extra_bytes_; |
- |
- DISALLOW_COPY_AND_ASSIGN(ForceHolAckListener); |
-}; |
- |
-} // namespace |
- |
-QuicHeadersStream::HpackDebugVisitor::HpackDebugVisitor() {} |
- |
-QuicHeadersStream::HpackDebugVisitor::~HpackDebugVisitor() {} |
- |
-// A SpdyFramerVisitor that passes HEADERS frames to the QuicSpdyStream, and |
-// closes the connection if any unexpected frames are received. |
-class QuicHeadersStream::SpdyFramerVisitor |
- : public SpdyFramerVisitorInterface, |
- public SpdyFramerDebugVisitorInterface { |
- public: |
- explicit SpdyFramerVisitor(QuicHeadersStream* stream) : stream_(stream) {} |
- |
- SpdyHeadersHandlerInterface* OnHeaderFrameStart( |
- SpdyStreamId /* stream_id */) override { |
- return &header_list_; |
- } |
- |
- void OnHeaderFrameEnd(SpdyStreamId /* stream_id */, |
- bool end_headers) override { |
- if (end_headers) { |
- if (stream_->IsConnected()) { |
- stream_->OnHeaderList(header_list_); |
- } |
- header_list_.Clear(); |
- } |
- } |
- |
- void OnStreamFrameData(SpdyStreamId stream_id, |
- const char* data, |
- size_t len) override { |
- if (stream_->OnStreamFrameData(stream_id, data, len)) { |
- return; |
- } |
- CloseConnection("SPDY DATA frame received."); |
- } |
- |
- void OnStreamEnd(SpdyStreamId stream_id) override { |
- // The framer invokes OnStreamEnd after processing a frame that had the fin |
- // bit set. |
- } |
- |
- void OnStreamPadding(SpdyStreamId stream_id, size_t len) override { |
- CloseConnection("SPDY frame padding received."); |
- } |
- |
- void OnError(SpdyFramer* framer) override { |
- CloseConnection( |
- QuicStrCat("SPDY framing error: ", |
- SpdyFramer::ErrorCodeToString(framer->error_code()))); |
- } |
- |
- void OnDataFrameHeader(SpdyStreamId stream_id, |
- size_t length, |
- bool fin) override { |
- if (stream_->OnDataFrameHeader(stream_id, length, fin)) { |
- return; |
- } |
- CloseConnection("SPDY DATA frame received."); |
- } |
- |
- void OnRstStream(SpdyStreamId stream_id, |
- SpdyRstStreamStatus status) override { |
- CloseConnection("SPDY RST_STREAM frame received."); |
- } |
- |
- void OnSetting(SpdySettingsIds id, uint32_t value) override { |
- if (!FLAGS_quic_reloadable_flag_quic_respect_http2_settings_frame) { |
- CloseConnection("SPDY SETTINGS frame received."); |
- return; |
- } |
- switch (id) { |
- case SETTINGS_HEADER_TABLE_SIZE: |
- stream_->UpdateHeaderEncoderTableSize(value); |
- break; |
- case SETTINGS_ENABLE_PUSH: |
- if (FLAGS_quic_reloadable_flag_quic_enable_server_push_by_default && |
- stream_->session()->perspective() == Perspective::IS_SERVER) { |
- // See rfc7540, Section 6.5.2. |
- if (value > 1) { |
- CloseConnection( |
- QuicStrCat("Invalid value for SETTINGS_ENABLE_PUSH: ", value)); |
- return; |
- } |
- stream_->UpdateEnableServerPush(value > 0); |
- break; |
- } else { |
- CloseConnection( |
- QuicStrCat("Unsupported field of HTTP/2 SETTINGS frame: ", id)); |
- } |
- break; |
- // TODO(fayang): Need to support SETTINGS_MAX_HEADER_LIST_SIZE when |
- // clients are actually sending it. |
- case SETTINGS_MAX_HEADER_LIST_SIZE: |
- if (FLAGS_quic_reloadable_flag_quic_send_max_header_list_size) { |
- break; |
- } |
- default: |
- CloseConnection( |
- QuicStrCat("Unsupported field of HTTP/2 SETTINGS frame: ", id)); |
- } |
- } |
- |
- void OnSettingsAck() override { |
- if (!FLAGS_quic_reloadable_flag_quic_respect_http2_settings_frame) { |
- CloseConnection("SPDY SETTINGS frame received."); |
- } |
- } |
- |
- void OnSettingsEnd() override { |
- if (!FLAGS_quic_reloadable_flag_quic_respect_http2_settings_frame) { |
- CloseConnection("SPDY SETTINGS frame received."); |
- } |
- } |
- |
- void OnPing(SpdyPingId unique_id, bool is_ack) override { |
- CloseConnection("SPDY PING frame received."); |
- } |
- |
- void OnGoAway(SpdyStreamId last_accepted_stream_id, |
- SpdyGoAwayStatus status) override { |
- CloseConnection("SPDY GOAWAY frame received."); |
- } |
- |
- void OnHeaders(SpdyStreamId stream_id, |
- bool has_priority, |
- int weight, |
- SpdyStreamId /*parent_stream_id*/, |
- bool /*exclusive*/, |
- bool fin, |
- bool end) override { |
- if (!stream_->IsConnected()) { |
- return; |
- } |
- |
- // TODO(mpw): avoid down-conversion and plumb SpdyStreamPrecedence through |
- // QuicHeadersStream. |
- SpdyPriority priority = |
- has_priority ? Http2WeightToSpdy3Priority(weight) : 0; |
- stream_->OnHeaders(stream_id, has_priority, priority, fin); |
- } |
- |
- void OnWindowUpdate(SpdyStreamId stream_id, int delta_window_size) override { |
- CloseConnection("SPDY WINDOW_UPDATE frame received."); |
- } |
- |
- void OnPushPromise(SpdyStreamId stream_id, |
- SpdyStreamId promised_stream_id, |
- bool end) override { |
- if (!stream_->supports_push_promise()) { |
- CloseConnection("PUSH_PROMISE not supported."); |
- return; |
- } |
- if (!stream_->IsConnected()) { |
- return; |
- } |
- stream_->OnPushPromise(stream_id, promised_stream_id, end); |
- } |
- |
- void OnContinuation(SpdyStreamId stream_id, bool end) override {} |
- |
- void OnPriority(SpdyStreamId stream_id, |
- SpdyStreamId parent_id, |
- int weight, |
- bool exclusive) override { |
- CloseConnection("SPDY PRIORITY frame received."); |
- } |
- |
- bool OnUnknownFrame(SpdyStreamId stream_id, int frame_type) override { |
- CloseConnection("Unknown frame type received."); |
- return false; |
- } |
- |
- // SpdyFramerDebugVisitorInterface implementation |
- void OnSendCompressedFrame(SpdyStreamId stream_id, |
- SpdyFrameType type, |
- size_t payload_len, |
- size_t frame_len) override { |
- if (payload_len == 0) { |
- QUIC_BUG << "Zero payload length."; |
- return; |
- } |
- int compression_pct = 100 - (100 * frame_len) / payload_len; |
- DVLOG(1) << "Net.QuicHpackCompressionPercentage: " << compression_pct; |
- UMA_HISTOGRAM_PERCENTAGE("Net.QuicHpackCompressionPercentage", |
- compression_pct); |
- } |
- |
- void OnReceiveCompressedFrame(SpdyStreamId stream_id, |
- SpdyFrameType type, |
- size_t frame_len) override { |
- if (stream_->IsConnected()) { |
- stream_->OnCompressedFrameSize(frame_len); |
- } |
- } |
- |
- void set_max_uncompressed_header_bytes( |
- size_t set_max_uncompressed_header_bytes) { |
- header_list_.set_max_uncompressed_header_bytes( |
- set_max_uncompressed_header_bytes); |
- } |
- |
- private: |
- void CloseConnection(const string& details) { |
- if (stream_->IsConnected()) { |
- stream_->CloseConnectionWithDetails(QUIC_INVALID_HEADERS_STREAM_DATA, |
- details); |
- } |
- } |
- |
- private: |
- QuicHeadersStream* stream_; |
- QuicHeaderList header_list_; |
- |
- DISALLOW_COPY_AND_ASSIGN(SpdyFramerVisitor); |
-}; |
- |
QuicHeadersStream::QuicHeadersStream(QuicSpdySession* session) |
- : QuicStream(kHeadersStreamId, session), |
- spdy_session_(session), |
- stream_id_(kInvalidStreamId), |
- promised_stream_id_(kInvalidStreamId), |
- fin_(false), |
- frame_len_(0), |
- uncompressed_frame_len_(0), |
- supports_push_promise_(session->perspective() == Perspective::IS_CLIENT), |
- cur_max_timestamp_(QuicTime::Zero()), |
- prev_max_timestamp_(QuicTime::Zero()), |
- spdy_framer_(SpdyFramer::ENABLE_COMPRESSION), |
- spdy_framer_visitor_(new SpdyFramerVisitor(this)) { |
- spdy_framer_.set_visitor(spdy_framer_visitor_.get()); |
- spdy_framer_.set_debug_visitor(spdy_framer_visitor_.get()); |
+ : QuicStream(kHeadersStreamId, session), spdy_session_(session) { |
// The headers stream is exempt from connection level flow control. |
DisableConnectionFlowControlForThisStream(); |
} |
QuicHeadersStream::~QuicHeadersStream() {} |
-size_t QuicHeadersStream::WriteHeaders( |
- QuicStreamId stream_id, |
- SpdyHeaderBlock headers, |
- bool fin, |
- SpdyPriority priority, |
- QuicReferenceCountedPointer<QuicAckListenerInterface> ack_listener) { |
- SpdyHeadersIR headers_frame(stream_id, std::move(headers)); |
- headers_frame.set_fin(fin); |
- if (session()->perspective() == Perspective::IS_CLIENT) { |
- headers_frame.set_has_priority(true); |
- headers_frame.set_weight(Spdy3PriorityToHttp2Weight(priority)); |
- } |
- SpdySerializedFrame frame(spdy_framer_.SerializeFrame(headers_frame)); |
- WriteOrBufferData(StringPiece(frame.data(), frame.size()), false, |
- std::move(ack_listener)); |
- return frame.size(); |
-} |
- |
-size_t QuicHeadersStream::WritePushPromise(QuicStreamId original_stream_id, |
- QuicStreamId promised_stream_id, |
- SpdyHeaderBlock headers) { |
- if (session()->perspective() == Perspective::IS_CLIENT) { |
- QUIC_BUG << "Client shouldn't send PUSH_PROMISE"; |
- return 0; |
- } |
- |
- SpdyPushPromiseIR push_promise(original_stream_id, promised_stream_id, |
- std::move(headers)); |
- |
- // PUSH_PROMISE must not be the last frame sent out, at least followed by |
- // response headers. |
- push_promise.set_fin(false); |
- |
- SpdySerializedFrame frame(spdy_framer_.SerializeFrame(push_promise)); |
- WriteOrBufferData(StringPiece(frame.data(), frame.size()), false, nullptr); |
- return frame.size(); |
-} |
- |
-void QuicHeadersStream::WriteDataFrame( |
- QuicStreamId id, |
- StringPiece data, |
- bool fin, |
- QuicReferenceCountedPointer<QuicAckListenerInterface> ack_listener) { |
- SpdyDataIR spdy_data(id, data); |
- spdy_data.set_fin(fin); |
- SpdySerializedFrame frame(spdy_framer_.SerializeFrame(spdy_data)); |
- QuicReferenceCountedPointer<ForceHolAckListener> force_hol_ack_listener; |
- if (ack_listener != nullptr) { |
- force_hol_ack_listener = new ForceHolAckListener( |
- std::move(ack_listener), frame.size() - data.length()); |
- } |
- // Use buffered writes so that coherence of framing is preserved |
- // between streams. |
- WriteOrBufferData(StringPiece(frame.data(), frame.size()), false, |
- std::move(force_hol_ack_listener)); |
-} |
- |
-QuicConsumedData QuicHeadersStream::WritevStreamData( |
- QuicStreamId id, |
- QuicIOVector iov, |
- QuicStreamOffset offset, |
- bool fin, |
- QuicReferenceCountedPointer<QuicAckListenerInterface> ack_listener) { |
- const size_t max_len = kSpdyInitialFrameSizeLimit - kDataFrameMinimumSize; |
- |
- QuicConsumedData result(0, false); |
- size_t total_length = iov.total_length; |
- |
- if (total_length == 0 && fin) { |
- WriteDataFrame(id, StringPiece(), true, std::move(ack_listener)); |
- result.fin_consumed = true; |
- return result; |
- } |
- |
- // Encapsulate the data into HTTP/2 DATA frames. The outer loop |
- // handles each element of the source iov, the inner loop handles |
- // the possibility of fragmenting each of those into multiple DATA |
- // frames, as the DATA frames have a max size of 16KB. |
- for (int i = 0; i < iov.iov_count; i++) { |
- size_t src_iov_offset = 0; |
- const struct iovec* src_iov = &iov.iov[i]; |
- do { |
- if (queued_data_bytes() > 0) { |
- // Limit the amount of buffering to the minimum needed to |
- // preserve framing. |
- return result; |
- } |
- size_t len = std::min( |
- std::min(src_iov->iov_len - src_iov_offset, max_len), total_length); |
- char* data = static_cast<char*>(src_iov->iov_base) + src_iov_offset; |
- src_iov_offset += len; |
- offset += len; |
- // fin handling, only set it for the final HTTP/2 DATA frame. |
- bool last_iov = i == iov.iov_count - 1; |
- bool last_fragment_within_iov = src_iov_offset >= src_iov->iov_len; |
- bool frame_fin = (last_iov && last_fragment_within_iov) ? fin : false; |
- WriteDataFrame(id, StringPiece(data, len), frame_fin, ack_listener); |
- result.bytes_consumed += len; |
- if (frame_fin) { |
- result.fin_consumed = true; |
- } |
- DCHECK_GE(total_length, len); |
- total_length -= len; |
- if (total_length <= 0) { |
- return result; |
- } |
- } while (src_iov_offset < src_iov->iov_len); |
- } |
- |
- return result; |
-} |
- |
void QuicHeadersStream::OnDataAvailable() { |
char buffer[1024]; |
struct iovec iov; |
@@ -464,10 +28,7 @@ void QuicHeadersStream::OnDataAvailable() { |
// No more data to read. |
break; |
} |
- DCHECK(timestamp.IsInitialized()); |
- cur_max_timestamp_ = std::max(timestamp, cur_max_timestamp_); |
- if (spdy_framer_.ProcessInput(static_cast<char*>(iov.iov_base), |
- iov.iov_len) != iov.iov_len) { |
+ if (spdy_session_->ProcessHeaderData(iov, timestamp) != iov.iov_len) { |
// Error processing data. |
return; |
} |
@@ -476,111 +37,6 @@ void QuicHeadersStream::OnDataAvailable() { |
} |
} |
-void QuicHeadersStream::set_max_uncompressed_header_bytes( |
- size_t set_max_uncompressed_header_bytes) { |
- spdy_framer_visitor_->set_max_uncompressed_header_bytes( |
- set_max_uncompressed_header_bytes); |
-} |
- |
-void QuicHeadersStream::OnHeaders(SpdyStreamId stream_id, |
- bool has_priority, |
- SpdyPriority priority, |
- bool fin) { |
- if (has_priority) { |
- if (session()->perspective() == Perspective::IS_CLIENT) { |
- CloseConnectionWithDetails(QUIC_INVALID_HEADERS_STREAM_DATA, |
- "Server must not send priorities."); |
- return; |
- } |
- spdy_session_->OnStreamHeadersPriority(stream_id, priority); |
- } else { |
- if (session()->perspective() == Perspective::IS_SERVER) { |
- CloseConnectionWithDetails(QUIC_INVALID_HEADERS_STREAM_DATA, |
- "Client must send priorities."); |
- return; |
- } |
- } |
- DCHECK_EQ(kInvalidStreamId, stream_id_); |
- DCHECK_EQ(kInvalidStreamId, promised_stream_id_); |
- stream_id_ = stream_id; |
- fin_ = fin; |
-} |
- |
-void QuicHeadersStream::OnPushPromise(SpdyStreamId stream_id, |
- SpdyStreamId promised_stream_id, |
- bool end) { |
- DCHECK_EQ(kInvalidStreamId, stream_id_); |
- DCHECK_EQ(kInvalidStreamId, promised_stream_id_); |
- stream_id_ = stream_id; |
- promised_stream_id_ = promised_stream_id; |
-} |
- |
-void QuicHeadersStream::OnHeaderList(const QuicHeaderList& header_list) { |
- DVLOG(1) << "Received header list for stream " << stream_id_ << ": " |
- << header_list.DebugString(); |
- if (prev_max_timestamp_ > cur_max_timestamp_) { |
- // prev_max_timestamp_ > cur_max_timestamp_ implies that |
- // headers from lower numbered streams actually came off the |
- // wire after headers for the current stream, hence there was |
- // HOL blocking. |
- QuicTime::Delta delta = prev_max_timestamp_ - cur_max_timestamp_; |
- DVLOG(1) << "stream " << stream_id_ |
- << ": Net.QuicSession.HeadersHOLBlockedTime " |
- << delta.ToMilliseconds(); |
- spdy_session_->OnHeadersHeadOfLineBlocking(delta); |
- } |
- |
- prev_max_timestamp_ = std::max(prev_max_timestamp_, cur_max_timestamp_); |
- cur_max_timestamp_ = QuicTime::Zero(); |
- if (promised_stream_id_ == kInvalidStreamId) { |
- spdy_session_->OnStreamHeaderList(stream_id_, fin_, frame_len_, |
- header_list); |
- } else { |
- spdy_session_->OnPromiseHeaderList(stream_id_, promised_stream_id_, |
- frame_len_, header_list); |
- } |
- // Reset state for the next frame. |
- promised_stream_id_ = kInvalidStreamId; |
- stream_id_ = kInvalidStreamId; |
- fin_ = false; |
- frame_len_ = 0; |
- uncompressed_frame_len_ = 0; |
-} |
- |
-void QuicHeadersStream::OnCompressedFrameSize(size_t frame_len) { |
- frame_len_ += frame_len; |
-} |
- |
-bool QuicHeadersStream::IsConnected() { |
- return session()->connection()->connected(); |
-} |
- |
-void QuicHeadersStream::DisableHpackDynamicTable() { |
- spdy_framer_.UpdateHeaderEncoderTableSize(0); |
-} |
- |
-void QuicHeadersStream::SetHpackEncoderDebugVisitor( |
- std::unique_ptr<HpackDebugVisitor> visitor) { |
- spdy_framer_.SetEncoderHeaderTableDebugVisitor( |
- std::unique_ptr<HeaderTableDebugVisitor>(new HeaderTableDebugVisitor( |
- session()->connection()->helper()->GetClock(), std::move(visitor)))); |
-} |
- |
-void QuicHeadersStream::SetHpackDecoderDebugVisitor( |
- std::unique_ptr<HpackDebugVisitor> visitor) { |
- spdy_framer_.SetDecoderHeaderTableDebugVisitor( |
- std::unique_ptr<HeaderTableDebugVisitor>(new HeaderTableDebugVisitor( |
- session()->connection()->helper()->GetClock(), std::move(visitor)))); |
-} |
- |
-void QuicHeadersStream::UpdateHeaderEncoderTableSize(uint32_t value) { |
- spdy_framer_.UpdateHeaderEncoderTableSize(value); |
-} |
- |
-void QuicHeadersStream::UpdateEnableServerPush(bool value) { |
- spdy_session_->set_server_push_enabled(value); |
-} |
- |
void QuicHeadersStream::MaybeReleaseSequencerBuffer() { |
if (FLAGS_quic_reloadable_flag_quic_headers_stream_release_sequencer_buffer && |
spdy_session_->ShouldReleaseHeadersStreamSequencerBuffer()) { |
@@ -588,48 +44,4 @@ void QuicHeadersStream::MaybeReleaseSequencerBuffer() { |
} |
} |
-size_t QuicHeadersStream::SendMaxHeaderListSize(size_t value) { |
- SpdySettingsIR settings_frame; |
- settings_frame.AddSetting(SETTINGS_MAX_HEADER_LIST_SIZE, value); |
- |
- SpdySerializedFrame frame(spdy_framer_.SerializeFrame(settings_frame)); |
- WriteOrBufferData(StringPiece(frame.data(), frame.size()), false, nullptr); |
- return frame.size(); |
-} |
- |
-bool QuicHeadersStream::OnDataFrameHeader(QuicStreamId stream_id, |
- size_t length, |
- bool fin) { |
- if (!spdy_session_->force_hol_blocking()) { |
- return false; |
- } |
- if (!IsConnected()) { |
- return true; |
- } |
- DVLOG(1) << "DATA frame header for stream " << stream_id << " length " |
- << length << " fin " << fin; |
- fin_ = fin; |
- frame_len_ = length; |
- if (fin && length == 0) { |
- OnStreamFrameData(stream_id, "", 0); |
- } |
- return true; |
-} |
- |
-bool QuicHeadersStream::OnStreamFrameData(QuicStreamId stream_id, |
- const char* data, |
- size_t len) { |
- if (!spdy_session_->force_hol_blocking()) { |
- return false; |
- } |
- if (!IsConnected()) { |
- return true; |
- } |
- frame_len_ -= len; |
- // Ignore fin_ while there is more data coming, if frame_len_ > 0. |
- spdy_session_->OnStreamFrameData(stream_id, data, len, |
- frame_len_ > 0 ? false : fin_); |
- return true; |
-} |
- |
} // namespace net |