blob: 1bac2b7acb0b10fd587fa588a4fea237438aefbe [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
5#include "net/third_party/quiche/src/quic/core/http/quic_headers_stream.h"
6
7#include "net/third_party/quiche/src/quic/core/http/quic_spdy_session.h"
8#include "net/third_party/quiche/src/quic/core/quic_utils.h"
QUICHE teama6ef0a62019-03-07 20:34:33 -05009#include "net/third_party/quiche/src/quic/platform/api/quic_flag_utils.h"
10#include "net/third_party/quiche/src/quic/platform/api/quic_flags.h"
bnc4e9283d2019-12-17 07:08:57 -080011#include "net/third_party/quiche/src/common/platform/api/quiche_arraysize.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,
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 << "Unsent stream data is acked. unacked_length: "
87 << header.unacked_length << " acked_length: " << header_length;
renjietang87df0d02020-02-13 11:53:52 -080088 OnUnrecoverableError(QUIC_INTERNAL_ERROR,
89 "Unsent stream data is acked");
QUICHE teama6ef0a62019-03-07 20:34:33 -050090 return false;
91 }
92 if (header.ack_listener != nullptr && header_length > 0) {
93 header.ack_listener->OnPacketAcked(header_length, ack_delay_time);
94 }
95 header.unacked_length -= header_length;
96 acked_offset += header_length;
97 acked_length -= header_length;
98 }
99 }
100 // Remove headers which are fully acked. Please note, header frames can be
101 // acked out of order, but unacked_headers_ is cleaned up in order.
102 while (!unacked_headers_.empty() &&
103 unacked_headers_.front().unacked_length == 0) {
104 unacked_headers_.pop_front();
105 }
106 return QuicStream::OnStreamFrameAcked(offset, data_length, fin_acked,
107 ack_delay_time, newly_acked_length);
108}
109
110void QuicHeadersStream::OnStreamFrameRetransmitted(QuicStreamOffset offset,
111 QuicByteCount data_length,
112 bool /*fin_retransmitted*/) {
113 QuicStream::OnStreamFrameRetransmitted(offset, data_length, false);
114 for (CompressedHeaderInfo& header : unacked_headers_) {
115 if (offset < header.headers_stream_offset) {
116 // This header frame offset belongs to headers with smaller offset, stop
117 // processing.
118 break;
119 }
120
121 if (offset >= header.headers_stream_offset + header.full_length) {
122 // This header frame belongs to headers with larger offset.
123 continue;
124 }
125
126 QuicByteCount header_offset = offset - header.headers_stream_offset;
127 QuicByteCount retransmitted_length =
128 std::min(data_length, header.full_length - header_offset);
129 if (header.ack_listener != nullptr && retransmitted_length > 0) {
130 header.ack_listener->OnPacketRetransmitted(retransmitted_length);
131 }
132 offset += retransmitted_length;
133 data_length -= retransmitted_length;
134 }
135}
136
137void QuicHeadersStream::OnDataBuffered(
138 QuicStreamOffset offset,
139 QuicByteCount data_length,
140 const QuicReferenceCountedPointer<QuicAckListenerInterface>& ack_listener) {
141 // Populate unacked_headers_.
142 if (!unacked_headers_.empty() &&
143 (offset == unacked_headers_.back().headers_stream_offset +
144 unacked_headers_.back().full_length) &&
145 ack_listener == unacked_headers_.back().ack_listener) {
146 // Try to combine with latest inserted entry if they belong to the same
147 // header (i.e., having contiguous offset and the same ack listener).
148 unacked_headers_.back().full_length += data_length;
149 unacked_headers_.back().unacked_length += data_length;
150 } else {
151 unacked_headers_.push_back(
152 CompressedHeaderInfo(offset, data_length, ack_listener));
153 }
154}
155
156} // namespace quic