1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "quiche/quic/core/http/quic_headers_stream.h"
6
7 #include "absl/base/macros.h"
8 #include "quiche/quic/core/http/quic_spdy_session.h"
9 #include "quiche/quic/core/quic_utils.h"
10 #include "quiche/quic/platform/api/quic_flag_utils.h"
11 #include "quiche/quic/platform/api/quic_flags.h"
12
13 namespace quic {
14
CompressedHeaderInfo(QuicStreamOffset headers_stream_offset,QuicStreamOffset full_length,quiche::QuicheReferenceCountedPointer<QuicAckListenerInterface> ack_listener)15 QuicHeadersStream::CompressedHeaderInfo::CompressedHeaderInfo(
16 QuicStreamOffset headers_stream_offset, QuicStreamOffset full_length,
17 quiche::QuicheReferenceCountedPointer<QuicAckListenerInterface>
18 ack_listener)
19 : headers_stream_offset(headers_stream_offset),
20 full_length(full_length),
21 unacked_length(full_length),
22 ack_listener(std::move(ack_listener)) {}
23
24 QuicHeadersStream::CompressedHeaderInfo::CompressedHeaderInfo(
25 const CompressedHeaderInfo& other) = default;
26
~CompressedHeaderInfo()27 QuicHeadersStream::CompressedHeaderInfo::~CompressedHeaderInfo() {}
28
QuicHeadersStream(QuicSpdySession * session)29 QuicHeadersStream::QuicHeadersStream(QuicSpdySession* session)
30 : QuicStream(QuicUtils::GetHeadersStreamId(session->transport_version()),
31 session,
32 /*is_static=*/true, BIDIRECTIONAL),
33 spdy_session_(session) {
34 // The headers stream is exempt from connection level flow control.
35 DisableConnectionFlowControlForThisStream();
36 }
37
~QuicHeadersStream()38 QuicHeadersStream::~QuicHeadersStream() {}
39
OnDataAvailable()40 void QuicHeadersStream::OnDataAvailable() {
41 struct iovec iov;
42 while (sequencer()->GetReadableRegion(&iov)) {
43 if (spdy_session_->ProcessHeaderData(iov) != iov.iov_len) {
44 // Error processing data.
45 return;
46 }
47 sequencer()->MarkConsumed(iov.iov_len);
48 MaybeReleaseSequencerBuffer();
49 }
50 }
51
MaybeReleaseSequencerBuffer()52 void QuicHeadersStream::MaybeReleaseSequencerBuffer() {
53 if (spdy_session_->ShouldReleaseHeadersStreamSequencerBuffer()) {
54 sequencer()->ReleaseBufferIfEmpty();
55 }
56 }
57
OnStreamFrameAcked(QuicStreamOffset offset,QuicByteCount data_length,bool fin_acked,QuicTime::Delta ack_delay_time,QuicTime receive_timestamp,QuicByteCount * newly_acked_length)58 bool QuicHeadersStream::OnStreamFrameAcked(QuicStreamOffset offset,
59 QuicByteCount data_length,
60 bool fin_acked,
61 QuicTime::Delta ack_delay_time,
62 QuicTime receive_timestamp,
63 QuicByteCount* newly_acked_length) {
64 QuicIntervalSet<QuicStreamOffset> newly_acked(offset, offset + data_length);
65 newly_acked.Difference(bytes_acked());
66 for (const auto& acked : newly_acked) {
67 QuicStreamOffset acked_offset = acked.min();
68 QuicByteCount acked_length = acked.max() - acked.min();
69 for (CompressedHeaderInfo& header : unacked_headers_) {
70 if (acked_offset < header.headers_stream_offset) {
71 // This header frame offset belongs to headers with smaller offset, stop
72 // processing.
73 break;
74 }
75
76 if (acked_offset >= header.headers_stream_offset + header.full_length) {
77 // This header frame belongs to headers with larger offset.
78 continue;
79 }
80
81 QuicByteCount header_offset = acked_offset - header.headers_stream_offset;
82 QuicByteCount header_length =
83 std::min(acked_length, header.full_length - header_offset);
84
85 if (header.unacked_length < header_length) {
86 QUIC_BUG(quic_bug_10416_1)
87 << "Unsent stream data is acked. unacked_length: "
88 << header.unacked_length << " acked_length: " << header_length;
89 OnUnrecoverableError(QUIC_INTERNAL_ERROR,
90 "Unsent stream data is acked");
91 return false;
92 }
93 if (header.ack_listener != nullptr && header_length > 0) {
94 header.ack_listener->OnPacketAcked(header_length, ack_delay_time);
95 }
96 header.unacked_length -= header_length;
97 acked_offset += header_length;
98 acked_length -= header_length;
99 }
100 }
101 // Remove headers which are fully acked. Please note, header frames can be
102 // acked out of order, but unacked_headers_ is cleaned up in order.
103 while (!unacked_headers_.empty() &&
104 unacked_headers_.front().unacked_length == 0) {
105 unacked_headers_.pop_front();
106 }
107 return QuicStream::OnStreamFrameAcked(offset, data_length, fin_acked,
108 ack_delay_time, receive_timestamp,
109 newly_acked_length);
110 }
111
OnStreamFrameRetransmitted(QuicStreamOffset offset,QuicByteCount data_length,bool)112 void QuicHeadersStream::OnStreamFrameRetransmitted(QuicStreamOffset offset,
113 QuicByteCount data_length,
114 bool /*fin_retransmitted*/) {
115 QuicStream::OnStreamFrameRetransmitted(offset, data_length, false);
116 for (CompressedHeaderInfo& header : unacked_headers_) {
117 if (offset < header.headers_stream_offset) {
118 // This header frame offset belongs to headers with smaller offset, stop
119 // processing.
120 break;
121 }
122
123 if (offset >= header.headers_stream_offset + header.full_length) {
124 // This header frame belongs to headers with larger offset.
125 continue;
126 }
127
128 QuicByteCount header_offset = offset - header.headers_stream_offset;
129 QuicByteCount retransmitted_length =
130 std::min(data_length, header.full_length - header_offset);
131 if (header.ack_listener != nullptr && retransmitted_length > 0) {
132 header.ack_listener->OnPacketRetransmitted(retransmitted_length);
133 }
134 offset += retransmitted_length;
135 data_length -= retransmitted_length;
136 }
137 }
138
OnDataBuffered(QuicStreamOffset offset,QuicByteCount data_length,const quiche::QuicheReferenceCountedPointer<QuicAckListenerInterface> & ack_listener)139 void QuicHeadersStream::OnDataBuffered(
140 QuicStreamOffset offset, QuicByteCount data_length,
141 const quiche::QuicheReferenceCountedPointer<QuicAckListenerInterface>&
142 ack_listener) {
143 // Populate unacked_headers_.
144 if (!unacked_headers_.empty() &&
145 (offset == unacked_headers_.back().headers_stream_offset +
146 unacked_headers_.back().full_length) &&
147 ack_listener == unacked_headers_.back().ack_listener) {
148 // Try to combine with latest inserted entry if they belong to the same
149 // header (i.e., having contiguous offset and the same ack listener).
150 unacked_headers_.back().full_length += data_length;
151 unacked_headers_.back().unacked_length += data_length;
152 } else {
153 unacked_headers_.push_back(
154 CompressedHeaderInfo(offset, data_length, ack_listener));
155 }
156 }
157
OnStreamReset(const QuicRstStreamFrame &)158 void QuicHeadersStream::OnStreamReset(const QuicRstStreamFrame& /*frame*/) {
159 stream_delegate()->OnStreamError(QUIC_INVALID_STREAM_ID,
160 "Attempt to reset headers stream");
161 }
162
163 } // namespace quic
164