xref: /aosp_15_r20/external/cronet/net/third_party/quiche/src/quiche/quic/core/http/quic_headers_stream.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
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