Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(339)

Unified Diff: net/quic/quic_headers_stream.cc

Issue 2115033002: Adds QUIC_VERSION_36 which adds support to force HOL blocking between streams for measurement purpo… (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@126085461
Patch Set: typo Created 4 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « net/quic/quic_headers_stream.h ('k') | net/quic/quic_headers_stream_test.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: net/quic/quic_headers_stream.cc
diff --git a/net/quic/quic_headers_stream.cc b/net/quic/quic_headers_stream.cc
index 72c3ac9bbefd189fae366cf501f64a5943cb0b53..75ef2c7d1c321730c7cb2d13b4c5d7da12545b52 100644
--- a/net/quic/quic_headers_stream.cc
+++ b/net/quic/quic_headers_stream.cc
@@ -56,6 +56,46 @@ class HeaderTableDebugVisitor : public HpackHeaderTable::DebugVisitorInterface {
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(QuicAckListenerInterface* stream_ack_listener,
+ int extra_bytes)
+ : stream_ack_listener_(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);
+ }
+
+ private:
+ ~ForceHolAckListener() override {}
+
+ scoped_refptr<QuicAckListenerInterface> stream_ack_listener_;
+ int extra_bytes_;
+
+ DISALLOW_COPY_AND_ASSIGN(ForceHolAckListener);
+};
+
} // namespace
QuicHeadersStream::HpackDebugVisitor::HpackDebugVisitor() {}
@@ -97,6 +137,9 @@ class QuicHeadersStream::SpdyFramerVisitor
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.");
}
@@ -133,6 +176,9 @@ class QuicHeadersStream::SpdyFramerVisitor
void OnDataFrameHeader(SpdyStreamId stream_id,
size_t length,
bool fin) override {
+ if (stream_->OnDataFrameHeader(stream_id, length, fin)) {
+ return;
+ }
CloseConnection("SPDY DATA frame received.");
}
@@ -330,6 +376,63 @@ size_t QuicHeadersStream::WritePushPromise(
return frame.size();
}
+QuicConsumedData QuicHeadersStream::WritevStreamData(
+ QuicStreamId id,
+ QuicIOVector iov,
+ QuicStreamOffset offset,
+ bool fin,
+ QuicAckListenerInterface* ack_notifier_delegate) {
+ const size_t max_len = SpdyConstants::GetFrameMaximumSize(HTTP2) -
+ SpdyConstants::GetDataFrameMinimumSize(HTTP2);
+
+ QuicConsumedData result(0, false);
+ size_t total_length = iov.total_length;
+
+ // 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 eacho 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 offset = 0;
+ const struct iovec* src_iov = &iov.iov[i];
+ do {
+ size_t len =
+ std::min(std::min(src_iov->iov_len - offset, max_len), total_length);
+ char* data = static_cast<char*>(src_iov->iov_base) + offset;
+ SpdyDataIR spdy_data(id, StringPiece(data, len));
+ offset += len;
+ // fin handling, set it only it only very last generated HTTP/2
+ // DATA frame.
+ bool last_iov = i == iov.iov_count - 1;
+ bool last_fragment_within_iov = offset >= src_iov->iov_len;
+ bool frame_fin = (last_iov && last_fragment_within_iov) ? fin : false;
+ spdy_data.set_fin(frame_fin);
+ if (frame_fin) {
+ result.fin_consumed = true;
+ }
+ SpdySerializedFrame frame(spdy_framer_.SerializeFrame(spdy_data));
+ DVLOG(1) << "Encapsulating in DATA frame for stream " << id << " len "
+ << len << " fin " << spdy_data.fin() << " remaining "
+ << src_iov->iov_len - offset;
+
+ scoped_refptr<ForceHolAckListener> ack_listener;
+ if (ack_notifier_delegate != nullptr) {
+ ack_listener =
+ new ForceHolAckListener(ack_notifier_delegate, frame.size() - len);
+ }
+
+ WriteOrBufferData(StringPiece(frame.data(), frame.size()), false,
+ ack_listener.get());
+ result.bytes_consumed += len;
+ total_length -= len;
+ if (total_length <= 0) {
+ return result;
+ }
+ } while (offset < src_iov->iov_len);
+ }
+ return result;
+}
+
void QuicHeadersStream::OnDataAvailable() {
char buffer[1024];
struct iovec iov;
@@ -506,4 +609,39 @@ void QuicHeadersStream::UpdateHeaderEncoderTableSize(uint32_t value) {
spdy_framer_.UpdateHeaderEncoderTableSize(value);
}
+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
« no previous file with comments | « net/quic/quic_headers_stream.h ('k') | net/quic/quic_headers_stream_test.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698