blob: 9d9c97df27155cca03a975bec9b9a5f570568bdf [file] [log] [blame]
Avi Drissman64595482022-09-14 20:52:291// Copyright 2012 The Chromium Authors
[email protected]dd3fd0e2012-11-04 05:14:402// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
Ryan Hamiltona3ee93a72018-08-01 22:03:085#include "net/quic/quic_chromium_client_stream.h"
[email protected]dd3fd0e2012-11-04 05:14:406
bnc2dc1cc42016-06-23 23:08:347#include <utility>
8
Avi Drissman41c4a412023-01-11 22:45:379#include "base/functional/bind.h"
10#include "base/functional/callback_helpers.h"
rchb27683c2015-07-29 23:53:5011#include "base/location.h"
Gabriel Charette9f60dd12020-03-06 20:48:0412#include "base/memory/ptr_util.h"
Keishi Hattori0e45c022021-11-27 09:25:5213#include "base/memory/raw_ptr.h"
Renjie Tanga2f41122021-02-16 22:36:0314#include "base/metrics/histogram_functions.h"
Victor Vasiliev502ba582020-09-15 23:16:1515#include "base/strings/abseil_string_conversions.h"
Sean Maher5b9af51f2022-11-21 15:32:4716#include "base/task/single_thread_task_runner.h"
rchb27683c2015-07-29 23:53:5017#include "net/base/io_buffer.h"
[email protected]dd3fd0e2012-11-04 05:14:4018#include "net/base/net_errors.h"
Kenichi Ishibashi51bac23b2021-03-18 10:05:1719#include "net/http/http_status_code.h"
mikecirone8b85c432016-09-08 19:11:0020#include "net/log/net_log_event_type.h"
Ryan Hamiltona3ee93a72018-08-01 22:03:0821#include "net/quic/quic_chromium_client_session.h"
22#include "net/quic/quic_http_utils.h"
Bence Béky94658bf2018-05-11 19:22:5823#include "net/spdy/spdy_log_util.h"
Ryan Hamiltonea4fa192022-04-12 18:30:4924#include "net/third_party/quiche/src/quiche/quic/core/http/quic_spdy_session.h"
25#include "net/third_party/quiche/src/quiche/quic/core/http/spdy_utils.h"
26#include "net/third_party/quiche/src/quiche/quic/core/quic_utils.h"
27#include "net/third_party/quiche/src/quiche/quic/core/quic_write_blocked_list.h"
[email protected]dd3fd0e2012-11-04 05:14:4028
29namespace net {
rch1bcfddf22017-06-03 00:26:2930namespace {
31// Sets a boolean to a value, and restores it to the previous value once
32// the saver goes out of scope.
33class ScopedBoolSaver {
34 public:
35 ScopedBoolSaver(bool* var, bool new_val) : var_(var), old_val_(*var) {
36 *var_ = new_val;
37 }
[email protected]dd3fd0e2012-11-04 05:14:4038
rch1bcfddf22017-06-03 00:26:2939 ~ScopedBoolSaver() { *var_ = old_val_; }
40
41 private:
Keishi Hattori0e45c022021-11-27 09:25:5242 raw_ptr<bool> var_;
rch1bcfddf22017-06-03 00:26:2943 bool old_val_;
44};
45} // namespace
46
47QuicChromiumClientStream::Handle::Handle(QuicChromiumClientStream* stream)
Tsuyoshi Horo432981d52022-06-09 09:50:1348 : stream_(stream), net_log_(stream->net_log()) {
rch08e198572017-05-09 16:56:5549 SaveState();
50}
51
52QuicChromiumClientStream::Handle::~Handle() {
53 if (stream_) {
54 stream_->ClearHandle();
55 // TODO(rch): If stream_ is still valid, it should probably be Reset()
56 // so that it does not leak.
Ryan Hamilton8d9ee76e2018-05-29 23:52:5257 // stream_->Reset(quic::QUIC_STREAM_CANCELLED);
rch08e198572017-05-09 16:56:5558 }
59}
60
Kenichi Ishibashi51bac23b2021-03-18 10:05:1761void QuicChromiumClientStream::Handle::OnEarlyHintsAvailable() {
Kenichi Ishibashi24716e82021-03-30 13:16:0562 if (first_early_hints_time_.is_null())
63 first_early_hints_time_ = base::TimeTicks::Now();
64
Kenichi Ishibashi51bac23b2021-03-18 10:05:1765 if (!read_headers_callback_)
66 return; // Wait for ReadInitialHeaders to be called.
67
68 DCHECK(read_headers_buffer_);
69 int rv = stream_->DeliverEarlyHints(read_headers_buffer_);
70 DCHECK_NE(ERR_IO_PENDING, rv);
71
72 ResetAndRun(std::move(read_headers_callback_), rv);
73}
74
rchfb47f712017-05-21 03:24:0075void QuicChromiumClientStream::Handle::OnInitialHeadersAvailable() {
Victor Vasiliev6522c3a2022-08-22 00:27:1476 if (headers_received_start_time_.is_null())
77 headers_received_start_time_ = base::TimeTicks::Now();
78
rchfb47f712017-05-21 03:24:0079 if (!read_headers_callback_)
80 return; // Wait for ReadInitialHeaders to be called.
81
Bence Békyb6300042020-01-28 21:18:2082 int rv = stream_->DeliverInitialHeaders(read_headers_buffer_);
83 DCHECK_NE(ERR_IO_PENDING, rv);
rchfb47f712017-05-21 03:24:0084
Bence Békyd8a21fc32018-06-27 18:29:5885 ResetAndRun(std::move(read_headers_callback_), rv);
rch08e198572017-05-09 16:56:5586}
87
rchce246412017-05-30 13:51:5088void QuicChromiumClientStream::Handle::OnTrailingHeadersAvailable() {
89 if (!read_headers_callback_)
90 return; // Wait for ReadInitialHeaders to be called.
91
92 int rv = ERR_QUIC_PROTOCOL_ERROR;
93 if (!stream_->DeliverTrailingHeaders(read_headers_buffer_, &rv))
94 rv = ERR_QUIC_PROTOCOL_ERROR;
95
Renjie Tanga2f41122021-02-16 22:36:0396 base::UmaHistogramBoolean(
97 "Net.QuicChromiumClientStream.TrailingHeadersProcessSuccess", rv >= 0);
Bence Békyd8a21fc32018-06-27 18:29:5898 ResetAndRun(std::move(read_headers_callback_), rv);
rch08e198572017-05-09 16:56:5599}
100
101void QuicChromiumClientStream::Handle::OnDataAvailable() {
rch27da0452017-05-26 22:54:54102 if (!read_body_callback_)
103 return; // Wait for ReadBody to be called.
104
Kenichi Ishibashie20c9b12022-07-12 04:00:15105 // TODO(https://crbug.com/1335423): Change to DCHECK() or remove after bug is
106 // fixed.
107 CHECK(read_body_buffer_);
108 CHECK_GT(read_body_buffer_len_, 0);
109
rch27da0452017-05-26 22:54:54110 int rv = stream_->Read(read_body_buffer_, read_body_buffer_len_);
111 if (rv == ERR_IO_PENDING)
112 return; // Spurrious, likely because of trailers?
113
114 read_body_buffer_ = nullptr;
115 read_body_buffer_len_ = 0;
Bence Békyd8a21fc32018-06-27 18:29:58116 ResetAndRun(std::move(read_body_callback_), rv);
rch08e198572017-05-09 16:56:55117}
118
rch2ab4d872017-05-28 15:15:40119void QuicChromiumClientStream::Handle::OnCanWrite() {
120 if (!write_callback_)
121 return;
122
Bence Békyd8a21fc32018-06-27 18:29:58123 ResetAndRun(std::move(write_callback_), OK);
rch2ab4d872017-05-28 15:15:40124}
125
rch08e198572017-05-09 16:56:55126void QuicChromiumClientStream::Handle::OnClose() {
rch1bcfddf22017-06-03 00:26:29127 if (net_error_ == ERR_UNEXPECTED) {
Ryan Hamilton8d9ee76e2018-05-29 23:52:52128 if (stream_error() == quic::QUIC_STREAM_NO_ERROR &&
129 connection_error() == quic::QUIC_NO_ERROR && fin_sent() &&
130 fin_received()) {
rch1bcfddf22017-06-03 00:26:29131 net_error_ = ERR_CONNECTION_CLOSED;
132 } else {
133 net_error_ = ERR_QUIC_PROTOCOL_ERROR;
134 }
rch08e198572017-05-09 16:56:55135 }
Renjie Tanga2f41122021-02-16 22:36:03136 base::UmaHistogramSparse("Net.QuicChromiumClientStream.HandleOnCloseNetError",
137 -net_error_);
138 base::UmaHistogramSparse(
139 "Net.QuicChromiumClientStream.HandleOnCloseStreamError", stream_error());
140 base::UmaHistogramSparse(
141 "Net.QuicChromiumClientStream.HandleOnCloseConnectionError",
142 connection_error());
rch1bcfddf22017-06-03 00:26:29143 OnError(net_error_);
rch08e198572017-05-09 16:56:55144}
145
146void QuicChromiumClientStream::Handle::OnError(int error) {
rch1bcfddf22017-06-03 00:26:29147 net_error_ = error;
rch08e198572017-05-09 16:56:55148 if (stream_)
149 SaveState();
150 stream_ = nullptr;
rch1bcfddf22017-06-03 00:26:29151
152 // Post a task to invoke the callbacks to ensure that there is no reentrancy.
Ryan Hamilton8df4adab2017-11-14 00:13:27153 // A ScopedPacketFlusher might cause an error which closes the stream under
rch1bcfddf22017-06-03 00:26:29154 // the call stack of the owner of the handle.
Sean Maher5b9af51f2022-11-21 15:32:47155 base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
rch1bcfddf22017-06-03 00:26:29156 FROM_HERE,
kylecharf4fe5172019-02-15 18:53:49157 base::BindOnce(&QuicChromiumClientStream::Handle::InvokeCallbacksOnClose,
158 weak_factory_.GetWeakPtr(), error));
rch1bcfddf22017-06-03 00:26:29159}
160
161void QuicChromiumClientStream::Handle::InvokeCallbacksOnClose(int error) {
162 // Invoking a callback may cause |this| to be deleted. If this happens, no
163 // more callbacks should be invoked. Guard against this by holding a WeakPtr
164 // to |this| and ensuring it's still valid.
165 auto guard(weak_factory_.GetWeakPtr());
166 for (auto* callback :
167 {&read_headers_callback_, &read_body_callback_, &write_callback_}) {
168 if (*callback)
Bence Békyd8a21fc32018-06-27 18:29:58169 ResetAndRun(std::move(*callback), error);
rch1bcfddf22017-06-03 00:26:29170 if (!guard.get())
171 return;
rch08e198572017-05-09 16:56:55172 }
173}
174
rchfb47f712017-05-21 03:24:00175int QuicChromiumClientStream::Handle::ReadInitialHeaders(
Bence Béky4c325e52020-10-22 20:48:01176 spdy::Http2HeaderBlock* header_block,
Bence Békyd8a21fc32018-06-27 18:29:58177 CompletionOnceCallback callback) {
rch1bcfddf22017-06-03 00:26:29178 ScopedBoolSaver saver(&may_invoke_callbacks_, false);
rchfb47f712017-05-21 03:24:00179 if (!stream_)
rch1bcfddf22017-06-03 00:26:29180 return net_error_;
rchfb47f712017-05-21 03:24:00181
Kenichi Ishibashi51bac23b2021-03-18 10:05:17182 // Check Early Hints first.
183 int rv = stream_->DeliverEarlyHints(header_block);
184 if (rv != ERR_IO_PENDING) {
185 return rv;
186 }
187
188 rv = stream_->DeliverInitialHeaders(header_block);
Bence Békyb6300042020-01-28 21:18:20189 if (rv != ERR_IO_PENDING) {
190 return rv;
191 }
rchfb47f712017-05-21 03:24:00192
193 read_headers_buffer_ = header_block;
Kenichi Ishibashi51bac23b2021-03-18 10:05:17194 DCHECK(!read_headers_callback_);
Bence Békyd8a21fc32018-06-27 18:29:58195 SetCallback(std::move(callback), &read_headers_callback_);
rchfb47f712017-05-21 03:24:00196 return ERR_IO_PENDING;
197}
198
rch27da0452017-05-26 22:54:54199int QuicChromiumClientStream::Handle::ReadBody(
200 IOBuffer* buffer,
201 int buffer_len,
Bence Békyd8a21fc32018-06-27 18:29:58202 CompletionOnceCallback callback) {
rch1bcfddf22017-06-03 00:26:29203 ScopedBoolSaver saver(&may_invoke_callbacks_, false);
204 if (IsDoneReading())
205 return OK;
206
rch27da0452017-05-26 22:54:54207 if (!stream_)
rch1bcfddf22017-06-03 00:26:29208 return net_error_;
rch27da0452017-05-26 22:54:54209
210 int rv = stream_->Read(buffer, buffer_len);
211 if (rv != ERR_IO_PENDING)
212 return rv;
213
Kenichi Ishibashie20c9b12022-07-12 04:00:15214 // TODO(https://crbug.com/1335423): Change to DCHECK() or remove after bug is
215 // fixed.
216 CHECK(buffer);
217 CHECK_GT(buffer_len, 0);
218
Bence Békyd8a21fc32018-06-27 18:29:58219 SetCallback(std::move(callback), &read_body_callback_);
rch27da0452017-05-26 22:54:54220 read_body_buffer_ = buffer;
221 read_body_buffer_len_ = buffer_len;
222 return ERR_IO_PENDING;
223}
224
rchce246412017-05-30 13:51:50225int QuicChromiumClientStream::Handle::ReadTrailingHeaders(
Bence Béky4c325e52020-10-22 20:48:01226 spdy::Http2HeaderBlock* header_block,
Bence Békyd8a21fc32018-06-27 18:29:58227 CompletionOnceCallback callback) {
rch1bcfddf22017-06-03 00:26:29228 ScopedBoolSaver saver(&may_invoke_callbacks_, false);
rchce246412017-05-30 13:51:50229 if (!stream_)
rch1bcfddf22017-06-03 00:26:29230 return net_error_;
rchce246412017-05-30 13:51:50231
232 int frame_len = 0;
233 if (stream_->DeliverTrailingHeaders(header_block, &frame_len))
234 return frame_len;
235
236 read_headers_buffer_ = header_block;
Bence Békyd8a21fc32018-06-27 18:29:58237 SetCallback(std::move(callback), &read_headers_callback_);
rchce246412017-05-30 13:51:50238 return ERR_IO_PENDING;
239}
240
rch1bcfddf22017-06-03 00:26:29241int QuicChromiumClientStream::Handle::WriteHeaders(
Bence Béky4c325e52020-10-22 20:48:01242 spdy::Http2HeaderBlock header_block,
rch08e198572017-05-09 16:56:55243 bool fin,
Victor Vasiliev5b04a6b2022-03-15 14:24:25244 quiche::QuicheReferenceCountedPointer<quic::QuicAckListenerInterface>
rch08e198572017-05-09 16:56:55245 ack_notifier_delegate) {
246 if (!stream_)
247 return 0;
rch1bcfddf22017-06-03 00:26:29248 return HandleIOComplete(stream_->WriteHeaders(std::move(header_block), fin,
249 ack_notifier_delegate));
rch08e198572017-05-09 16:56:55250}
251
252int QuicChromiumClientStream::Handle::WriteStreamData(
253 base::StringPiece data,
254 bool fin,
Bence Békyd8a21fc32018-06-27 18:29:58255 CompletionOnceCallback callback) {
rch1bcfddf22017-06-03 00:26:29256 ScopedBoolSaver saver(&may_invoke_callbacks_, false);
rch08e198572017-05-09 16:56:55257 if (!stream_)
rch1bcfddf22017-06-03 00:26:29258 return net_error_;
rch2ab4d872017-05-28 15:15:40259
Victor Vasiliev502ba582020-09-15 23:16:15260 if (stream_->WriteStreamData(base::StringPieceToStringView(data), fin))
rch1bcfddf22017-06-03 00:26:29261 return HandleIOComplete(OK);
rch2ab4d872017-05-28 15:15:40262
Bence Békyd8a21fc32018-06-27 18:29:58263 SetCallback(std::move(callback), &write_callback_);
rch2ab4d872017-05-28 15:15:40264 return ERR_IO_PENDING;
rch08e198572017-05-09 16:56:55265}
266
267int QuicChromiumClientStream::Handle::WritevStreamData(
268 const std::vector<scoped_refptr<IOBuffer>>& buffers,
269 const std::vector<int>& lengths,
270 bool fin,
Bence Békyd8a21fc32018-06-27 18:29:58271 CompletionOnceCallback callback) {
rch1bcfddf22017-06-03 00:26:29272 ScopedBoolSaver saver(&may_invoke_callbacks_, false);
rch08e198572017-05-09 16:56:55273 if (!stream_)
rch1bcfddf22017-06-03 00:26:29274 return net_error_;
rch2ab4d872017-05-28 15:15:40275
276 if (stream_->WritevStreamData(buffers, lengths, fin))
rch1bcfddf22017-06-03 00:26:29277 return HandleIOComplete(OK);
rch2ab4d872017-05-28 15:15:40278
Bence Békyd8a21fc32018-06-27 18:29:58279 SetCallback(std::move(callback), &write_callback_);
rch2ab4d872017-05-28 15:15:40280 return ERR_IO_PENDING;
rch08e198572017-05-09 16:56:55281}
282
283int QuicChromiumClientStream::Handle::Read(IOBuffer* buf, int buf_len) {
284 if (!stream_)
rch1bcfddf22017-06-03 00:26:29285 return net_error_;
rch08e198572017-05-09 16:56:55286 return stream_->Read(buf, buf_len);
287}
288
289void QuicChromiumClientStream::Handle::OnFinRead() {
rch1bcfddf22017-06-03 00:26:29290 read_headers_callback_.Reset();
rch08e198572017-05-09 16:56:55291 if (stream_)
292 stream_->OnFinRead();
293}
294
Zhongyi Shibb28b1f2018-07-18 02:41:26295void QuicChromiumClientStream::Handle::
296 DisableConnectionMigrationToCellularNetwork() {
rch08e198572017-05-09 16:56:55297 if (stream_)
Zhongyi Shibb28b1f2018-07-18 02:41:26298 stream_->DisableConnectionMigrationToCellularNetwork();
rch08e198572017-05-09 16:56:55299}
300
Ryan Hamilton0239aac2018-05-19 00:03:13301void QuicChromiumClientStream::Handle::SetPriority(
Patrick Meenanf741c6082023-01-03 18:06:43302 const quic::QuicStreamPriority& priority) {
303 if (stream_) {
304 stream_->SetPriority(priority);
305 }
rch08e198572017-05-09 16:56:55306}
307
308void QuicChromiumClientStream::Handle::Reset(
Ryan Hamilton8d9ee76e2018-05-29 23:52:52309 quic::QuicRstStreamErrorCode error_code) {
rch08e198572017-05-09 16:56:55310 if (stream_)
311 stream_->Reset(error_code);
312}
313
Ryan Hamilton8d9ee76e2018-05-29 23:52:52314quic::QuicStreamId QuicChromiumClientStream::Handle::id() const {
rch08e198572017-05-09 16:56:55315 if (!stream_)
316 return id_;
317 return stream_->id();
318}
319
Ryan Hamilton8d9ee76e2018-05-29 23:52:52320quic::QuicErrorCode QuicChromiumClientStream::Handle::connection_error() const {
rch08e198572017-05-09 16:56:55321 if (!stream_)
322 return connection_error_;
323 return stream_->connection_error();
324}
325
Ryan Hamilton8d9ee76e2018-05-29 23:52:52326quic::QuicRstStreamErrorCode QuicChromiumClientStream::Handle::stream_error()
327 const {
rch08e198572017-05-09 16:56:55328 if (!stream_)
329 return stream_error_;
330 return stream_->stream_error();
331}
332
333bool QuicChromiumClientStream::Handle::fin_sent() const {
334 if (!stream_)
335 return fin_sent_;
336 return stream_->fin_sent();
337}
338
339bool QuicChromiumClientStream::Handle::fin_received() const {
340 if (!stream_)
341 return fin_received_;
342 return stream_->fin_received();
343}
344
345uint64_t QuicChromiumClientStream::Handle::stream_bytes_read() const {
346 if (!stream_)
347 return stream_bytes_read_;
348 return stream_->stream_bytes_read();
349}
350
351uint64_t QuicChromiumClientStream::Handle::stream_bytes_written() const {
352 if (!stream_)
353 return stream_bytes_written_;
354 return stream_->stream_bytes_written();
355}
356
357size_t QuicChromiumClientStream::Handle::NumBytesConsumed() const {
358 if (!stream_)
359 return num_bytes_consumed_;
360 return stream_->sequencer()->NumBytesConsumed();
361}
362
Yixin Wang0d2c6b7e12017-08-16 21:12:55363bool QuicChromiumClientStream::Handle::HasBytesToRead() const {
364 if (!stream_)
365 return false;
Renjief49758b2019-01-11 23:32:41366 return stream_->HasBytesToRead();
Yixin Wang0d2c6b7e12017-08-16 21:12:55367}
368
rch08e198572017-05-09 16:56:55369bool QuicChromiumClientStream::Handle::IsDoneReading() const {
370 if (!stream_)
371 return is_done_reading_;
372 return stream_->IsDoneReading();
373}
374
375bool QuicChromiumClientStream::Handle::IsFirstStream() const {
376 if (!stream_)
377 return is_first_stream_;
378 return stream_->IsFirstStream();
379}
380
381void QuicChromiumClientStream::Handle::OnPromiseHeaderList(
Ryan Hamilton8d9ee76e2018-05-29 23:52:52382 quic::QuicStreamId promised_id,
rch08e198572017-05-09 16:56:55383 size_t frame_len,
Ryan Hamilton8d9ee76e2018-05-29 23:52:52384 const quic::QuicHeaderList& header_list) {
rch08e198572017-05-09 16:56:55385 stream_->OnPromiseHeaderList(promised_id, frame_len, header_list);
386}
387
Zhongyi Shibb28b1f2018-07-18 02:41:26388bool QuicChromiumClientStream::Handle::can_migrate_to_cellular_network() {
rch08e198572017-05-09 16:56:55389 if (!stream_)
390 return false;
Zhongyi Shibb28b1f2018-07-18 02:41:26391 return stream_->can_migrate_to_cellular_network();
rch08e198572017-05-09 16:56:55392}
393
Yixin Wang0d2c6b7e12017-08-16 21:12:55394const NetLogWithSource& QuicChromiumClientStream::Handle::net_log() const {
395 return net_log_;
396}
397
rch08e198572017-05-09 16:56:55398void QuicChromiumClientStream::Handle::SaveState() {
399 DCHECK(stream_);
400 fin_sent_ = stream_->fin_sent();
401 fin_received_ = stream_->fin_received();
402 num_bytes_consumed_ = stream_->sequencer()->NumBytesConsumed();
403 id_ = stream_->id();
404 connection_error_ = stream_->connection_error();
405 stream_error_ = stream_->stream_error();
406 is_done_reading_ = stream_->IsDoneReading();
407 is_first_stream_ = stream_->IsFirstStream();
408 stream_bytes_read_ = stream_->stream_bytes_read();
409 stream_bytes_written_ = stream_->stream_bytes_written();
rch08e198572017-05-09 16:56:55410}
411
rch1bcfddf22017-06-03 00:26:29412void QuicChromiumClientStream::Handle::SetCallback(
Bence Békyd8a21fc32018-06-27 18:29:58413 CompletionOnceCallback new_callback,
414 CompletionOnceCallback* callback) {
rch1bcfddf22017-06-03 00:26:29415 // TODO(rch): Convert this to a DCHECK once we ensure the API is stable and
416 // bug free.
417 CHECK(!may_invoke_callbacks_);
Bence Békyd8a21fc32018-06-27 18:29:58418 *callback = std::move(new_callback);
rch1bcfddf22017-06-03 00:26:29419}
420
Bence Békyd8a21fc32018-06-27 18:29:58421void QuicChromiumClientStream::Handle::ResetAndRun(
422 CompletionOnceCallback callback,
423 int rv) {
rch1bcfddf22017-06-03 00:26:29424 // TODO(rch): Convert this to a DCHECK once we ensure the API is stable and
425 // bug free.
426 CHECK(may_invoke_callbacks_);
Bence Békyd8a21fc32018-06-27 18:29:58427 std::move(callback).Run(rv);
rch1bcfddf22017-06-03 00:26:29428}
429
430int QuicChromiumClientStream::Handle::HandleIOComplete(int rv) {
431 // If |stream_| is still valid the stream has not been closed. If the stream
432 // has not been closed, then just return |rv|.
433 if (rv < 0 || stream_)
434 return rv;
435
Ryan Hamilton8d9ee76e2018-05-29 23:52:52436 if (stream_error_ == quic::QUIC_STREAM_NO_ERROR &&
437 connection_error_ == quic::QUIC_NO_ERROR && fin_sent_ && fin_received_) {
rch1bcfddf22017-06-03 00:26:29438 return rv;
439 }
440
441 return net_error_;
442}
443
Yu Suba2a1d72020-12-04 02:14:41444void QuicChromiumClientStream::Handle::SetRequestIdempotency(
445 Idempotency idempotency) {
446 idempotency_ = idempotency;
447}
448
449Idempotency QuicChromiumClientStream::Handle::GetRequestIdempotency() const {
450 return idempotency_;
451}
452
ckrasic244375a32016-02-04 21:21:22453QuicChromiumClientStream::QuicChromiumClientStream(
Ryan Hamilton8d9ee76e2018-05-29 23:52:52454 quic::QuicStreamId id,
455 quic::QuicSpdyClientSessionBase* session,
Fan Yang70c2dd22018-10-10 17:12:15456 quic::StreamType type,
Ramin Halavati683bcaa92018-02-14 08:42:39457 const NetLogWithSource& net_log,
458 const NetworkTrafficAnnotationTag& traffic_annotation)
Fan Yang70c2dd22018-10-10 17:12:15459 : quic::QuicSpdyStream(id, session, type),
rchb27683c2015-07-29 23:53:50460 net_log_(net_log),
ckrasic244375a32016-02-04 21:21:22461 session_(session),
Tsuyoshi Horo432981d52022-06-09 09:50:13462 quic_version_(session->connection()->transport_version()) {}
[email protected]dd3fd0e2012-11-04 05:14:40463
Fan Yang32c5a112018-12-10 20:06:33464QuicChromiumClientStream::QuicChromiumClientStream(
Ryan Hamilton8380c652019-06-04 02:25:06465 quic::PendingStream* pending,
Fan Yang32c5a112018-12-10 20:06:33466 quic::QuicSpdyClientSessionBase* session,
Fan Yang32c5a112018-12-10 20:06:33467 const NetLogWithSource& net_log,
468 const NetworkTrafficAnnotationTag& traffic_annotation)
Haoyue Wang5c11f22fb2021-09-17 22:34:56469 : quic::QuicSpdyStream(pending, session),
Fan Yang32c5a112018-12-10 20:06:33470 net_log_(net_log),
Fan Yang32c5a112018-12-10 20:06:33471 session_(session),
Tsuyoshi Horo432981d52022-06-09 09:50:13472 quic_version_(session->connection()->transport_version()) {}
Fan Yang32c5a112018-12-10 20:06:33473
rch12fef552016-01-15 16:26:31474QuicChromiumClientStream::~QuicChromiumClientStream() {
rch08e198572017-05-09 16:56:55475 if (handle_)
476 handle_->OnClose();
[email protected]dd3fd0e2012-11-04 05:14:40477}
478
dahollingsaf3796492016-05-25 19:21:35479void QuicChromiumClientStream::OnInitialHeadersComplete(
480 bool fin,
481 size_t frame_len,
Ryan Hamilton8d9ee76e2018-05-29 23:52:52482 const quic::QuicHeaderList& header_list) {
Kenichi Ishibashi51bac23b2021-03-18 10:05:17483 DCHECK(!initial_headers_arrived_);
Ryan Hamilton8d9ee76e2018-05-29 23:52:52484 quic::QuicSpdyStream::OnInitialHeadersComplete(fin, frame_len, header_list);
dahollingsaf3796492016-05-25 19:21:35485
Bence Béky4c325e52020-10-22 20:48:01486 spdy::Http2HeaderBlock header_block;
dahollingsaf3796492016-05-25 19:21:35487 int64_t length = -1;
Ryan Hamilton8d9ee76e2018-05-29 23:52:52488 if (!quic::SpdyUtils::CopyAndValidateHeaders(header_list, &length,
489 &header_block)) {
dahollingsaf3796492016-05-25 19:21:35490 DLOG(ERROR) << "Failed to parse header list: " << header_list.DebugString();
491 ConsumeHeaderList();
Ryan Hamilton8d9ee76e2018-05-29 23:52:52492 Reset(quic::QUIC_BAD_APPLICATION_PAYLOAD);
dahollingsaf3796492016-05-25 19:21:35493 return;
494 }
495
Kenichi Ishibashi51bac23b2021-03-18 10:05:17496 // Handle informational response. If the response is an Early Hints response,
497 // deliver the response to the owner of the handle. Otherwise ignore the
498 // response.
Kenichi Ishibashi10111e82021-03-23 02:19:06499 int response_code;
500 if (!ParseHeaderStatusCode(header_block, &response_code)) {
501 DLOG(ERROR) << "Received invalid response code: '"
502 << header_block[":status"].as_string() << "' on stream "
503 << id();
504 Reset(quic::QUIC_BAD_APPLICATION_PAYLOAD);
505 return;
506 }
Kenichi Ishibashi51bac23b2021-03-18 10:05:17507
Kenichi Ishibashi10111e82021-03-23 02:19:06508 if (response_code == HTTP_SWITCHING_PROTOCOLS) {
509 DLOG(ERROR) << "Received forbidden 101 response code on stream " << id();
510 Reset(quic::QUIC_BAD_APPLICATION_PAYLOAD);
511 return;
512 }
Kenichi Ishibashi51bac23b2021-03-18 10:05:17513
Kenichi Ishibashi10111e82021-03-23 02:19:06514 if (response_code >= 100 && response_code < 200) {
515 set_headers_decompressed(false);
516 ConsumeHeaderList();
517 if (response_code == HTTP_EARLY_HINTS) {
518 early_hints_.emplace_back(std::move(header_block), frame_len);
519 if (handle_)
520 handle_->OnEarlyHintsAvailable();
521 } else {
522 DVLOG(1) << "Ignore informational response " << response_code
523 << " on stream" << id();
Kenichi Ishibashi51bac23b2021-03-18 10:05:17524 }
Kenichi Ishibashi10111e82021-03-23 02:19:06525 return;
Kenichi Ishibashi51bac23b2021-03-18 10:05:17526 }
527
dahollingsaf3796492016-05-25 19:21:35528 ConsumeHeaderList();
529 session_->OnInitialHeadersComplete(id(), header_block);
530
rch08e198572017-05-09 16:56:55531 // Buffer the headers and deliver them when the handle arrives.
Bence Békyb6300042020-01-28 21:18:20532 initial_headers_arrived_ = true;
rch6788ad52017-05-09 04:49:04533 initial_headers_ = std::move(header_block);
534 initial_headers_frame_len_ = frame_len;
rchfb47f712017-05-21 03:24:00535
536 if (handle_) {
537 // The handle will be notified of the headers via a posted task.
538 NotifyHandleOfInitialHeadersAvailableLater();
539 }
dahollingsaf3796492016-05-25 19:21:35540}
541
542void QuicChromiumClientStream::OnTrailingHeadersComplete(
543 bool fin,
544 size_t frame_len,
Ryan Hamilton8d9ee76e2018-05-29 23:52:52545 const quic::QuicHeaderList& header_list) {
546 quic::QuicSpdyStream::OnTrailingHeadersComplete(fin, frame_len, header_list);
rchce246412017-05-30 13:51:50547 trailing_headers_frame_len_ = frame_len;
548 if (handle_) {
549 // The handle will be notified of the headers via a posted task.
550 NotifyHandleOfTrailingHeadersAvailableLater();
551 }
dahollingsaf3796492016-05-25 19:21:35552}
553
ckrasic769733c2016-06-30 00:42:13554void QuicChromiumClientStream::OnPromiseHeaderList(
Ryan Hamilton8d9ee76e2018-05-29 23:52:52555 quic::QuicStreamId promised_id,
ckrasic769733c2016-06-30 00:42:13556 size_t frame_len,
Ryan Hamilton8d9ee76e2018-05-29 23:52:52557 const quic::QuicHeaderList& header_list) {
Bence Béky4c325e52020-10-22 20:48:01558 spdy::Http2HeaderBlock promise_headers;
ckrasic769733c2016-06-30 00:42:13559 int64_t content_length = -1;
Ryan Hamilton8d9ee76e2018-05-29 23:52:52560 if (!quic::SpdyUtils::CopyAndValidateHeaders(header_list, &content_length,
561 &promise_headers)) {
ckrasic769733c2016-06-30 00:42:13562 DLOG(ERROR) << "Failed to parse header list: " << header_list.DebugString();
563 ConsumeHeaderList();
Ryan Hamilton8d9ee76e2018-05-29 23:52:52564 Reset(quic::QUIC_BAD_APPLICATION_PAYLOAD);
ckrasic769733c2016-06-30 00:42:13565 return;
566 }
567 ConsumeHeaderList();
568
569 session_->HandlePromised(id(), promised_id, promise_headers);
570}
571
Frank Kastenholz1dac18b62018-11-29 18:50:36572void QuicChromiumClientStream::OnBodyAvailable() {
rchb27683c2015-07-29 23:53:50573 if (!FinishedReadingHeaders() || !headers_delivered_) {
rch7dd15702015-07-01 18:57:57574 // Buffer the data in the sequencer until the headers have been read.
rchb27683c2015-07-29 23:53:50575 return;
rch7dd15702015-07-01 18:57:57576 }
577
Renjief49758b2019-01-11 23:32:41578 if (!HasBytesToRead() && !FinishedReadingTrailers()) {
xunjieli7640faa2016-10-06 00:45:42579 // If there is no data to read, wait until either FIN is received or
580 // trailers are delivered.
581 return;
582 }
583
rch08e198572017-05-09 16:56:55584 // The handle will read the data via a posted task, and
rchb27683c2015-07-29 23:53:50585 // will be able to, potentially, read all data which has queued up.
rch08e198572017-05-09 16:56:55586 if (handle_)
587 NotifyHandleOfDataAvailableLater();
[email protected]dd3fd0e2012-11-04 05:14:40588}
589
rch12fef552016-01-15 16:26:31590void QuicChromiumClientStream::OnClose() {
rch08e198572017-05-09 16:56:55591 if (handle_) {
592 handle_->OnClose();
593 handle_ = nullptr;
[email protected]f702d572012-12-04 15:56:20594 }
Ryan Hamilton8d9ee76e2018-05-29 23:52:52595 quic::QuicStream::OnClose();
[email protected]dd3fd0e2012-11-04 05:14:40596}
597
rch12fef552016-01-15 16:26:31598void QuicChromiumClientStream::OnCanWrite() {
Ryan Hamilton8d9ee76e2018-05-29 23:52:52599 quic::QuicStream::OnCanWrite();
[email protected]6adeb922013-09-01 22:43:25600
rch2ab4d872017-05-28 15:15:40601 if (!HasBufferedData() && handle_)
602 handle_->OnCanWrite();
[email protected]6adeb922013-09-01 22:43:25603}
604
xunjieli5fafe142016-03-23 23:32:54605size_t QuicChromiumClientStream::WriteHeaders(
Bence Béky4c325e52020-10-22 20:48:01606 spdy::Http2HeaderBlock header_block,
xunjieli5fafe142016-03-23 23:32:54607 bool fin,
Victor Vasiliev5b04a6b2022-03-15 14:24:25608 quiche::QuicheReferenceCountedPointer<quic::QuicAckListenerInterface>
Ryan Hamilton8d9ee76e2018-05-29 23:52:52609 ack_listener) {
Victor Vasiliev29197e22020-01-16 20:48:32610 if (!session()->OneRttKeysAvailable()) {
rchcb1d6bde2016-06-18 00:33:07611 auto entry = header_block.find(":method");
612 DCHECK(entry != header_block.end());
Yu Suba2a1d72020-12-04 02:14:41613 DCHECK(
614 entry->second != "POST" ||
615 (handle_ != nullptr && handle_->GetRequestIdempotency() == IDEMPOTENT));
rchcb1d6bde2016-06-18 00:33:07616 }
xunjieli5fafe142016-03-23 23:32:54617 net_log_.AddEvent(
mikecirone8b85c432016-09-08 19:11:00618 NetLogEventType::QUIC_CHROMIUM_CLIENT_STREAM_SEND_REQUEST_HEADERS,
Eric Roman06bd9742019-07-13 15:19:13619 [&](NetLogCaptureMode capture_mode) {
Patrick Meenanf741c6082023-01-03 18:06:43620 return QuicRequestNetLogParams(id(), &header_block, priority(),
Bence Béky42765d52022-12-12 22:38:28621 capture_mode);
Eric Roman06bd9742019-07-13 15:19:13622 });
Ryan Hamilton8d9ee76e2018-05-29 23:52:52623 size_t len = quic::QuicSpdyStream::WriteHeaders(std::move(header_block), fin,
624 std::move(ack_listener));
rchd4651b92017-05-04 00:41:17625 initial_headers_sent_ = true;
626 return len;
xunjieli5fafe142016-03-23 23:32:54627}
628
Victor Vasiliev47ecb6a2020-10-14 17:22:10629bool QuicChromiumClientStream::WriteStreamData(absl::string_view data,
Ryan Hamilton8d9ee76e2018-05-29 23:52:52630 bool fin) {
Fan Yanga9caa8d2020-11-19 20:29:10631 // For gQUIC, this must not be called when data is buffered because headers
632 // are sent on the dedicated header stream.
633 DCHECK(!HasBufferedData() || VersionUsesHttp3(quic_version_));
[email protected]6adeb922013-09-01 22:43:25634 // Writes the data, or buffers it.
Dan Zhang5ae7041a22019-02-13 23:58:18635 WriteOrBufferBody(data, fin);
rch2ab4d872017-05-28 15:15:40636 return !HasBufferedData(); // Was all data written?
[email protected]6adeb922013-09-01 22:43:25637}
638
rch2ab4d872017-05-28 15:15:40639bool QuicChromiumClientStream::WritevStreamData(
xunjieli2328a2682016-05-16 19:38:25640 const std::vector<scoped_refptr<IOBuffer>>& buffers,
xunjieli07a42ce2016-04-26 20:05:31641 const std::vector<int>& lengths,
rch2ab4d872017-05-28 15:15:40642 bool fin) {
David Schinazic9db3672021-04-14 18:12:55643 // For gQUIC, this must not be called when data is buffered because headers
644 // are sent on the dedicated header stream.
645 DCHECK(!HasBufferedData() || VersionUsesHttp3(quic_version_));
xunjieli07a42ce2016-04-26 20:05:31646 // Writes the data, or buffers it.
Ryan Hamiltona3ee93a72018-08-01 22:03:08647 for (size_t i = 0; i < buffers.size(); ++i) {
648 bool is_fin = fin && (i == buffers.size() - 1);
Victor Vasiliev47ecb6a2020-10-14 17:22:10649 absl::string_view string_data(buffers[i]->data(), lengths[i]);
Dan Zhang5ae7041a22019-02-13 23:58:18650 WriteOrBufferBody(string_data, is_fin);
Ryan Hamiltona3ee93a72018-08-01 22:03:08651 }
rch2ab4d872017-05-28 15:15:40652 return !HasBufferedData(); // Was all data written?
xunjieli07a42ce2016-04-26 20:05:31653}
654
rch08e198572017-05-09 16:56:55655std::unique_ptr<QuicChromiumClientStream::Handle>
rch1bcfddf22017-06-03 00:26:29656QuicChromiumClientStream::CreateHandle() {
rch08e198572017-05-09 16:56:55657 DCHECK(!handle_);
Ryan Hamiltona3ee93a72018-08-01 22:03:08658 auto handle = base::WrapUnique(new QuicChromiumClientStream::Handle(this));
rch08e198572017-05-09 16:56:55659 handle_ = handle.get();
rch6788ad52017-05-09 04:49:04660
661 // Should this perhaps be via PostTask to make reasoning simpler?
Bence Békyb6300042020-01-28 21:18:20662 if (initial_headers_arrived_) {
rchfb47f712017-05-21 03:24:00663 handle_->OnInitialHeadersAvailable();
Bence Békyb6300042020-01-28 21:18:20664 }
rch08e198572017-05-09 16:56:55665
666 return handle;
667}
668
669void QuicChromiumClientStream::ClearHandle() {
670 handle_ = nullptr;
[email protected]dd3fd0e2012-11-04 05:14:40671}
672
rch12fef552016-01-15 16:26:31673void QuicChromiumClientStream::OnError(int error) {
rch08e198572017-05-09 16:56:55674 if (handle_) {
675 QuicChromiumClientStream::Handle* handle = handle_;
676 handle_ = nullptr;
677 handle->OnError(error);
[email protected]56dfb902013-01-03 23:17:55678 }
679}
680
rch12fef552016-01-15 16:26:31681int QuicChromiumClientStream::Read(IOBuffer* buf, int buf_len) {
Nidhi Jajuf41dd4a2022-09-12 10:14:47682 // TODO(https://crbug.com/1335423): Change to DCHECK() or remove after bug
Bence Béky707a52242022-06-13 20:46:47683 // is fixed.
684 CHECK_GT(buf_len, 0);
Nidhi Jajuf41dd4a2022-09-12 10:14:47685 CHECK(buf->data());
Bence Béky707a52242022-06-13 20:46:47686
xunjieliec0ed02a2016-10-10 18:05:06687 if (IsDoneReading())
rchb27683c2015-07-29 23:53:50688 return 0; // EOF
689
690 if (!HasBytesToRead())
691 return ERR_IO_PENDING;
692
693 iovec iov;
694 iov.iov_base = buf->data();
695 iov.iov_len = buf_len;
xunjieliec0ed02a2016-10-10 18:05:06696 size_t bytes_read = Readv(&iov, 1);
rch03499252017-05-03 17:44:37697 // Since HasBytesToRead is true, Readv() must of read some data.
698 DCHECK_NE(0u, bytes_read);
xunjieliec0ed02a2016-10-10 18:05:06699 return bytes_read;
rchb27683c2015-07-29 23:53:50700}
701
rchfb47f712017-05-21 03:24:00702void QuicChromiumClientStream::NotifyHandleOfInitialHeadersAvailableLater() {
rch08e198572017-05-09 16:56:55703 DCHECK(handle_);
Sean Maher5b9af51f2022-11-21 15:32:47704 base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
rch6788ad52017-05-09 04:49:04705 FROM_HERE,
kylecharf4fe5172019-02-15 18:53:49706 base::BindOnce(
rch08e198572017-05-09 16:56:55707 &QuicChromiumClientStream::NotifyHandleOfInitialHeadersAvailable,
rchfb47f712017-05-21 03:24:00708 weak_factory_.GetWeakPtr()));
rchb27683c2015-07-29 23:53:50709}
710
rchfb47f712017-05-21 03:24:00711void QuicChromiumClientStream::NotifyHandleOfInitialHeadersAvailable() {
rch08e198572017-05-09 16:56:55712 if (!handle_)
rchb27683c2015-07-29 23:53:50713 return;
714
rchfb47f712017-05-21 03:24:00715 if (!headers_delivered_)
716 handle_->OnInitialHeadersAvailable();
rchec5b74ac2017-05-09 13:31:40717}
718
rchce246412017-05-30 13:51:50719void QuicChromiumClientStream::NotifyHandleOfTrailingHeadersAvailableLater() {
rch08e198572017-05-09 16:56:55720 DCHECK(handle_);
Sean Maher5b9af51f2022-11-21 15:32:47721 base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
rchec5b74ac2017-05-09 13:31:40722 FROM_HERE,
kylecharf4fe5172019-02-15 18:53:49723 base::BindOnce(
rch08e198572017-05-09 16:56:55724 &QuicChromiumClientStream::NotifyHandleOfTrailingHeadersAvailable,
rchce246412017-05-30 13:51:50725 weak_factory_.GetWeakPtr()));
rchec5b74ac2017-05-09 13:31:40726}
727
rchce246412017-05-30 13:51:50728void QuicChromiumClientStream::NotifyHandleOfTrailingHeadersAvailable() {
rch08e198572017-05-09 16:56:55729 if (!handle_)
rchec5b74ac2017-05-09 13:31:40730 return;
731
Kenichi Ishibashi9bc79772021-03-22 00:53:12732 // If trailers aren't decompressed it means that trailers are invalid
733 // (e.g., contain ":status" field). Don't notify to the handle if trailers
734 // aren't decompressed since the stream will be closed and
735 // `headers_delivered_` won't become true.
736 if (!trailers_decompressed())
737 return;
738
Kenichi Ishibashi0176ff92021-09-28 00:29:06739 // Notify only after the handle reads initial headers.
740 if (!headers_delivered_)
741 return;
742
rch1bcfddf22017-06-03 00:26:29743 // Post an async task to notify handle of the FIN flag.
rch08e198572017-05-09 16:56:55744 NotifyHandleOfDataAvailableLater();
rchce246412017-05-30 13:51:50745 handle_->OnTrailingHeadersAvailable();
rchb27683c2015-07-29 23:53:50746}
747
Kenichi Ishibashi51bac23b2021-03-18 10:05:17748int QuicChromiumClientStream::DeliverEarlyHints(
749 spdy::Http2HeaderBlock* headers) {
750 if (early_hints_.empty()) {
751 return ERR_IO_PENDING;
752 }
753
754 DCHECK(!headers_delivered_);
755
756 EarlyHints& hints = early_hints_.front();
757 *headers = std::move(hints.headers);
758 size_t frame_len = hints.frame_len;
759 early_hints_.pop_front();
760
761 net_log_.AddEvent(
762 NetLogEventType::
763 QUIC_CHROMIUM_CLIENT_STREAM_READ_EARLY_HINTS_RESPONSE_HEADERS,
764 [&](NetLogCaptureMode capture_mode) {
765 return QuicResponseNetLogParams(id(), fin_received(), headers,
766 capture_mode);
767 });
768
769 return frame_len;
770}
771
Bence Békyb6300042020-01-28 21:18:20772int QuicChromiumClientStream::DeliverInitialHeaders(
Bence Béky4c325e52020-10-22 20:48:01773 spdy::Http2HeaderBlock* headers) {
Bence Békyb6300042020-01-28 21:18:20774 if (!initial_headers_arrived_) {
775 return ERR_IO_PENDING;
776 }
rchfb47f712017-05-21 03:24:00777
778 headers_delivered_ = true;
Bence Békyb6300042020-01-28 21:18:20779
780 if (initial_headers_.empty()) {
781 return ERR_INVALID_RESPONSE;
782 }
783
rchfb47f712017-05-21 03:24:00784 net_log_.AddEvent(
785 NetLogEventType::QUIC_CHROMIUM_CLIENT_STREAM_READ_RESPONSE_HEADERS,
Eric Roman06bd9742019-07-13 15:19:13786 [&](NetLogCaptureMode capture_mode) {
787 return QuicResponseNetLogParams(id(), fin_received(), &initial_headers_,
788 capture_mode);
789 });
rchfb47f712017-05-21 03:24:00790
791 *headers = std::move(initial_headers_);
Bence Békyb6300042020-01-28 21:18:20792 return initial_headers_frame_len_;
rchfb47f712017-05-21 03:24:00793}
794
Ryan Hamilton0239aac2018-05-19 00:03:13795bool QuicChromiumClientStream::DeliverTrailingHeaders(
Bence Béky4c325e52020-10-22 20:48:01796 spdy::Http2HeaderBlock* headers,
Ryan Hamilton0239aac2018-05-19 00:03:13797 int* frame_len) {
rchce246412017-05-30 13:51:50798 if (received_trailers().empty())
799 return false;
800
801 net_log_.AddEvent(
802 NetLogEventType::QUIC_CHROMIUM_CLIENT_STREAM_READ_RESPONSE_TRAILERS,
Eric Roman06bd9742019-07-13 15:19:13803 [&](NetLogCaptureMode capture_mode) {
804 return QuicResponseNetLogParams(id(), fin_received(),
805 &received_trailers(), capture_mode);
806 });
rchce246412017-05-30 13:51:50807
808 *headers = received_trailers().Clone();
809 *frame_len = trailing_headers_frame_len_;
810
811 MarkTrailersConsumed();
812 return true;
813}
814
rch08e198572017-05-09 16:56:55815void QuicChromiumClientStream::NotifyHandleOfDataAvailableLater() {
816 DCHECK(handle_);
Sean Maher5b9af51f2022-11-21 15:32:47817 base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
rch6788ad52017-05-09 04:49:04818 FROM_HERE,
kylecharf4fe5172019-02-15 18:53:49819 base::BindOnce(&QuicChromiumClientStream::NotifyHandleOfDataAvailable,
820 weak_factory_.GetWeakPtr()));
rchb27683c2015-07-29 23:53:50821}
822
rch08e198572017-05-09 16:56:55823void QuicChromiumClientStream::NotifyHandleOfDataAvailable() {
824 if (handle_)
825 handle_->OnDataAvailable();
rchb27683c2015-07-29 23:53:50826}
827
Zhongyi Shibb28b1f2018-07-18 02:41:26828void QuicChromiumClientStream::DisableConnectionMigrationToCellularNetwork() {
829 can_migrate_to_cellular_network_ = false;
jri231c2972016-03-08 19:50:11830}
831
xunjieli100937eb52016-09-15 20:09:37832bool QuicChromiumClientStream::IsFirstStream() {
Victor Vasiliev7da08172019-10-14 06:04:25833 if (VersionUsesHttp3(quic_version_)) {
Fan Yang2330d182019-08-05 14:50:50834 return id() == quic::QuicUtils::GetFirstBidirectionalStreamId(
835 quic_version_, quic::Perspective::IS_CLIENT);
836 }
Fan Yang32c5a112018-12-10 20:06:33837 return id() == quic::QuicUtils::GetHeadersStreamId(quic_version_) +
838 quic::QuicUtils::StreamIdDelta(quic_version_);
xunjieli100937eb52016-09-15 20:09:37839}
840
[email protected]dd3fd0e2012-11-04 05:14:40841} // namespace net