blob: d8cfbdf3ba8e947f228421a400cca77d87189251 [file] [log] [blame]
QUICHE teama6ef0a62019-03-07 20:34:33 -05001// 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
QUICHE team5be974e2020-12-29 18:35:24 -05005#include "quic/core/http/quic_headers_stream.h"
QUICHE teama6ef0a62019-03-07 20:34:33 -05006
vasilvvfe1c8f32020-10-19 14:10:59 -07007#include "absl/base/macros.h"
QUICHE team5be974e2020-12-29 18:35:24 -05008#include "quic/core/http/quic_spdy_session.h"
9#include "quic/core/quic_utils.h"
10#include "quic/platform/api/quic_flag_utils.h"
11#include "quic/platform/api/quic_flags.h"
QUICHE teama6ef0a62019-03-07 20:34:33 -050012
13namespace quic {
14
15QuicHeadersStream::CompressedHeaderInfo::CompressedHeaderInfo(
16 QuicStreamOffset headers_stream_offset,
17 QuicStreamOffset full_length,
18 QuicReferenceCountedPointer<QuicAckListenerInterface> 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
24QuicHeadersStream::CompressedHeaderInfo::CompressedHeaderInfo(
25 const CompressedHeaderInfo& other) = default;
26
27QuicHeadersStream::CompressedHeaderInfo::~CompressedHeaderInfo() {}
28
29QuicHeadersStream::QuicHeadersStream(QuicSpdySession* session)
renjietangd1d00852019-09-06 10:43:12 -070030 : QuicStream(QuicUtils::GetHeadersStreamId(session->transport_version()),
QUICHE teama6ef0a62019-03-07 20:34:33 -050031 session,
32 /*is_static=*/true,
33 BIDIRECTIONAL),
34 spdy_session_(session) {
35 // The headers stream is exempt from connection level flow control.
36 DisableConnectionFlowControlForThisStream();
37}
38
39QuicHeadersStream::~QuicHeadersStream() {}
40
41void QuicHeadersStream::OnDataAvailable() {
42 struct iovec iov;
43 while (sequencer()->GetReadableRegion(&iov)) {
44 if (spdy_session_->ProcessHeaderData(iov) != iov.iov_len) {
45 // Error processing data.
46 return;
47 }
48 sequencer()->MarkConsumed(iov.iov_len);
49 MaybeReleaseSequencerBuffer();
50 }
51}
52
53void QuicHeadersStream::MaybeReleaseSequencerBuffer() {
54 if (spdy_session_->ShouldReleaseHeadersStreamSequencerBuffer()) {
55 sequencer()->ReleaseBufferIfEmpty();
56 }
57}
58
59bool QuicHeadersStream::OnStreamFrameAcked(QuicStreamOffset offset,
60 QuicByteCount data_length,
61 bool fin_acked,
62 QuicTime::Delta ack_delay_time,
QUICHE team2f5f30b2020-02-18 08:52:28 -080063 QuicTime receive_timestamp,
QUICHE teama6ef0a62019-03-07 20:34:33 -050064 QuicByteCount* newly_acked_length) {
65 QuicIntervalSet<QuicStreamOffset> newly_acked(offset, offset + data_length);
66 newly_acked.Difference(bytes_acked());
67 for (const auto& acked : newly_acked) {
68 QuicStreamOffset acked_offset = acked.min();
69 QuicByteCount acked_length = acked.max() - acked.min();
70 for (CompressedHeaderInfo& header : unacked_headers_) {
71 if (acked_offset < header.headers_stream_offset) {
72 // This header frame offset belongs to headers with smaller offset, stop
73 // processing.
74 break;
75 }
76
77 if (acked_offset >= header.headers_stream_offset + header.full_length) {
78 // This header frame belongs to headers with larger offset.
79 continue;
80 }
81
82 QuicByteCount header_offset = acked_offset - header.headers_stream_offset;
83 QuicByteCount header_length =
84 std::min(acked_length, header.full_length - header_offset);
85
86 if (header.unacked_length < header_length) {
87 QUIC_BUG << "Unsent stream data is acked. unacked_length: "
88 << header.unacked_length << " acked_length: " << header_length;
renjietang87df0d02020-02-13 11:53:52 -080089 OnUnrecoverableError(QUIC_INTERNAL_ERROR,
90 "Unsent stream data is acked");
QUICHE teama6ef0a62019-03-07 20:34:33 -050091 return false;
92 }
93 if (header.ack_listener != nullptr && header_length > 0) {
wub2146ce82020-07-30 13:17:52 -070094 header.ack_listener->OnPacketAcked(header_length, ack_delay_time);
QUICHE teama6ef0a62019-03-07 20:34:33 -050095 }
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,
QUICHE team2f5f30b2020-02-18 08:52:28 -0800108 ack_delay_time, receive_timestamp,
109 newly_acked_length);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500110}
111
112void 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
139void QuicHeadersStream::OnDataBuffered(
140 QuicStreamOffset offset,
141 QuicByteCount data_length,
142 const QuicReferenceCountedPointer<QuicAckListenerInterface>& 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
renjietang546c7142020-03-05 14:12:10 -0800158void QuicHeadersStream::OnStreamReset(const QuicRstStreamFrame& /*frame*/) {
159 stream_delegate()->OnStreamError(QUIC_INVALID_STREAM_ID,
160 "Attempt to reset headers stream");
161}
162
QUICHE teama6ef0a62019-03-07 20:34:33 -0500163} // namespace quic