blob: 5397909e8f6aa65d2d0f8a73d4801422b0829180 [file] [log] [blame]
[email protected]dd3fd0e2012-11-04 05:14:401// Copyright (c) 2012 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
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
Sebastien Marchand6d0558fd2019-01-25 16:49:379#include "base/bind.h"
[email protected]6adeb922013-09-01 22:43:2510#include "base/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"
gabf767595f2016-05-11 18:50:3516#include "base/threading/thread_task_runner_handle.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.
155 base::ThreadTaskRunnerHandle::Get()->PostTask(
156 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(
Dan Zhang98f8c7062019-07-30 14:32:00302 const spdy::SpdyStreamPrecedence& precedence) {
rch08e198572017-05-09 16:56:55303 if (stream_)
Dan Zhang98f8c7062019-07-30 14:32:00304 stream_->SetPriority(precedence);
rch08e198572017-05-09 16:56:55305}
306
307void QuicChromiumClientStream::Handle::Reset(
Ryan Hamilton8d9ee76e2018-05-29 23:52:52308 quic::QuicRstStreamErrorCode error_code) {
rch08e198572017-05-09 16:56:55309 if (stream_)
310 stream_->Reset(error_code);
311}
312
Ryan Hamilton8d9ee76e2018-05-29 23:52:52313quic::QuicStreamId QuicChromiumClientStream::Handle::id() const {
rch08e198572017-05-09 16:56:55314 if (!stream_)
315 return id_;
316 return stream_->id();
317}
318
Ryan Hamilton8d9ee76e2018-05-29 23:52:52319quic::QuicErrorCode QuicChromiumClientStream::Handle::connection_error() const {
rch08e198572017-05-09 16:56:55320 if (!stream_)
321 return connection_error_;
322 return stream_->connection_error();
323}
324
Ryan Hamilton8d9ee76e2018-05-29 23:52:52325quic::QuicRstStreamErrorCode QuicChromiumClientStream::Handle::stream_error()
326 const {
rch08e198572017-05-09 16:56:55327 if (!stream_)
328 return stream_error_;
329 return stream_->stream_error();
330}
331
332bool QuicChromiumClientStream::Handle::fin_sent() const {
333 if (!stream_)
334 return fin_sent_;
335 return stream_->fin_sent();
336}
337
338bool QuicChromiumClientStream::Handle::fin_received() const {
339 if (!stream_)
340 return fin_received_;
341 return stream_->fin_received();
342}
343
344uint64_t QuicChromiumClientStream::Handle::stream_bytes_read() const {
345 if (!stream_)
346 return stream_bytes_read_;
347 return stream_->stream_bytes_read();
348}
349
350uint64_t QuicChromiumClientStream::Handle::stream_bytes_written() const {
351 if (!stream_)
352 return stream_bytes_written_;
353 return stream_->stream_bytes_written();
354}
355
356size_t QuicChromiumClientStream::Handle::NumBytesConsumed() const {
357 if (!stream_)
358 return num_bytes_consumed_;
359 return stream_->sequencer()->NumBytesConsumed();
360}
361
Yixin Wang0d2c6b7e12017-08-16 21:12:55362bool QuicChromiumClientStream::Handle::HasBytesToRead() const {
363 if (!stream_)
364 return false;
Renjief49758b2019-01-11 23:32:41365 return stream_->HasBytesToRead();
Yixin Wang0d2c6b7e12017-08-16 21:12:55366}
367
rch08e198572017-05-09 16:56:55368bool QuicChromiumClientStream::Handle::IsDoneReading() const {
369 if (!stream_)
370 return is_done_reading_;
371 return stream_->IsDoneReading();
372}
373
374bool QuicChromiumClientStream::Handle::IsFirstStream() const {
375 if (!stream_)
376 return is_first_stream_;
377 return stream_->IsFirstStream();
378}
379
380void QuicChromiumClientStream::Handle::OnPromiseHeaderList(
Ryan Hamilton8d9ee76e2018-05-29 23:52:52381 quic::QuicStreamId promised_id,
rch08e198572017-05-09 16:56:55382 size_t frame_len,
Ryan Hamilton8d9ee76e2018-05-29 23:52:52383 const quic::QuicHeaderList& header_list) {
rch08e198572017-05-09 16:56:55384 stream_->OnPromiseHeaderList(promised_id, frame_len, header_list);
385}
386
Zhongyi Shibb28b1f2018-07-18 02:41:26387bool QuicChromiumClientStream::Handle::can_migrate_to_cellular_network() {
rch08e198572017-05-09 16:56:55388 if (!stream_)
389 return false;
Zhongyi Shibb28b1f2018-07-18 02:41:26390 return stream_->can_migrate_to_cellular_network();
rch08e198572017-05-09 16:56:55391}
392
Yixin Wang0d2c6b7e12017-08-16 21:12:55393const NetLogWithSource& QuicChromiumClientStream::Handle::net_log() const {
394 return net_log_;
395}
396
rch08e198572017-05-09 16:56:55397void QuicChromiumClientStream::Handle::SaveState() {
398 DCHECK(stream_);
399 fin_sent_ = stream_->fin_sent();
400 fin_received_ = stream_->fin_received();
401 num_bytes_consumed_ = stream_->sequencer()->NumBytesConsumed();
402 id_ = stream_->id();
403 connection_error_ = stream_->connection_error();
404 stream_error_ = stream_->stream_error();
405 is_done_reading_ = stream_->IsDoneReading();
406 is_first_stream_ = stream_->IsFirstStream();
407 stream_bytes_read_ = stream_->stream_bytes_read();
408 stream_bytes_written_ = stream_->stream_bytes_written();
rch08e198572017-05-09 16:56:55409}
410
rch1bcfddf22017-06-03 00:26:29411void QuicChromiumClientStream::Handle::SetCallback(
Bence Békyd8a21fc32018-06-27 18:29:58412 CompletionOnceCallback new_callback,
413 CompletionOnceCallback* callback) {
rch1bcfddf22017-06-03 00:26:29414 // TODO(rch): Convert this to a DCHECK once we ensure the API is stable and
415 // bug free.
416 CHECK(!may_invoke_callbacks_);
Bence Békyd8a21fc32018-06-27 18:29:58417 *callback = std::move(new_callback);
rch1bcfddf22017-06-03 00:26:29418}
419
Bence Békyd8a21fc32018-06-27 18:29:58420void QuicChromiumClientStream::Handle::ResetAndRun(
421 CompletionOnceCallback callback,
422 int rv) {
rch1bcfddf22017-06-03 00:26:29423 // TODO(rch): Convert this to a DCHECK once we ensure the API is stable and
424 // bug free.
425 CHECK(may_invoke_callbacks_);
Bence Békyd8a21fc32018-06-27 18:29:58426 std::move(callback).Run(rv);
rch1bcfddf22017-06-03 00:26:29427}
428
429int QuicChromiumClientStream::Handle::HandleIOComplete(int rv) {
430 // If |stream_| is still valid the stream has not been closed. If the stream
431 // has not been closed, then just return |rv|.
432 if (rv < 0 || stream_)
433 return rv;
434
Ryan Hamilton8d9ee76e2018-05-29 23:52:52435 if (stream_error_ == quic::QUIC_STREAM_NO_ERROR &&
436 connection_error_ == quic::QUIC_NO_ERROR && fin_sent_ && fin_received_) {
rch1bcfddf22017-06-03 00:26:29437 return rv;
438 }
439
440 return net_error_;
441}
442
Yu Suba2a1d72020-12-04 02:14:41443void QuicChromiumClientStream::Handle::SetRequestIdempotency(
444 Idempotency idempotency) {
445 idempotency_ = idempotency;
446}
447
448Idempotency QuicChromiumClientStream::Handle::GetRequestIdempotency() const {
449 return idempotency_;
450}
451
ckrasic244375a32016-02-04 21:21:22452QuicChromiumClientStream::QuicChromiumClientStream(
Ryan Hamilton8d9ee76e2018-05-29 23:52:52453 quic::QuicStreamId id,
454 quic::QuicSpdyClientSessionBase* session,
Fan Yang70c2dd22018-10-10 17:12:15455 quic::StreamType type,
Ramin Halavati683bcaa92018-02-14 08:42:39456 const NetLogWithSource& net_log,
457 const NetworkTrafficAnnotationTag& traffic_annotation)
Fan Yang70c2dd22018-10-10 17:12:15458 : quic::QuicSpdyStream(id, session, type),
rchb27683c2015-07-29 23:53:50459 net_log_(net_log),
ckrasic244375a32016-02-04 21:21:22460 session_(session),
Tsuyoshi Horo432981d52022-06-09 09:50:13461 quic_version_(session->connection()->transport_version()) {}
[email protected]dd3fd0e2012-11-04 05:14:40462
Fan Yang32c5a112018-12-10 20:06:33463QuicChromiumClientStream::QuicChromiumClientStream(
Ryan Hamilton8380c652019-06-04 02:25:06464 quic::PendingStream* pending,
Fan Yang32c5a112018-12-10 20:06:33465 quic::QuicSpdyClientSessionBase* session,
Fan Yang32c5a112018-12-10 20:06:33466 const NetLogWithSource& net_log,
467 const NetworkTrafficAnnotationTag& traffic_annotation)
Haoyue Wang5c11f22fb2021-09-17 22:34:56468 : quic::QuicSpdyStream(pending, session),
Fan Yang32c5a112018-12-10 20:06:33469 net_log_(net_log),
Fan Yang32c5a112018-12-10 20:06:33470 session_(session),
Tsuyoshi Horo432981d52022-06-09 09:50:13471 quic_version_(session->connection()->transport_version()) {}
Fan Yang32c5a112018-12-10 20:06:33472
rch12fef552016-01-15 16:26:31473QuicChromiumClientStream::~QuicChromiumClientStream() {
rch08e198572017-05-09 16:56:55474 if (handle_)
475 handle_->OnClose();
[email protected]dd3fd0e2012-11-04 05:14:40476}
477
dahollingsaf3796492016-05-25 19:21:35478void QuicChromiumClientStream::OnInitialHeadersComplete(
479 bool fin,
480 size_t frame_len,
Ryan Hamilton8d9ee76e2018-05-29 23:52:52481 const quic::QuicHeaderList& header_list) {
Kenichi Ishibashi51bac23b2021-03-18 10:05:17482 DCHECK(!initial_headers_arrived_);
Ryan Hamilton8d9ee76e2018-05-29 23:52:52483 quic::QuicSpdyStream::OnInitialHeadersComplete(fin, frame_len, header_list);
dahollingsaf3796492016-05-25 19:21:35484
Bence Béky4c325e52020-10-22 20:48:01485 spdy::Http2HeaderBlock header_block;
dahollingsaf3796492016-05-25 19:21:35486 int64_t length = -1;
Ryan Hamilton8d9ee76e2018-05-29 23:52:52487 if (!quic::SpdyUtils::CopyAndValidateHeaders(header_list, &length,
488 &header_block)) {
dahollingsaf3796492016-05-25 19:21:35489 DLOG(ERROR) << "Failed to parse header list: " << header_list.DebugString();
490 ConsumeHeaderList();
Ryan Hamilton8d9ee76e2018-05-29 23:52:52491 Reset(quic::QUIC_BAD_APPLICATION_PAYLOAD);
dahollingsaf3796492016-05-25 19:21:35492 return;
493 }
494
Kenichi Ishibashi51bac23b2021-03-18 10:05:17495 // Handle informational response. If the response is an Early Hints response,
496 // deliver the response to the owner of the handle. Otherwise ignore the
497 // response.
Kenichi Ishibashi10111e82021-03-23 02:19:06498 int response_code;
499 if (!ParseHeaderStatusCode(header_block, &response_code)) {
500 DLOG(ERROR) << "Received invalid response code: '"
501 << header_block[":status"].as_string() << "' on stream "
502 << id();
503 Reset(quic::QUIC_BAD_APPLICATION_PAYLOAD);
504 return;
505 }
Kenichi Ishibashi51bac23b2021-03-18 10:05:17506
Kenichi Ishibashi10111e82021-03-23 02:19:06507 if (response_code == HTTP_SWITCHING_PROTOCOLS) {
508 DLOG(ERROR) << "Received forbidden 101 response code on stream " << id();
509 Reset(quic::QUIC_BAD_APPLICATION_PAYLOAD);
510 return;
511 }
Kenichi Ishibashi51bac23b2021-03-18 10:05:17512
Kenichi Ishibashi10111e82021-03-23 02:19:06513 if (response_code >= 100 && response_code < 200) {
514 set_headers_decompressed(false);
515 ConsumeHeaderList();
516 if (response_code == HTTP_EARLY_HINTS) {
517 early_hints_.emplace_back(std::move(header_block), frame_len);
518 if (handle_)
519 handle_->OnEarlyHintsAvailable();
520 } else {
521 DVLOG(1) << "Ignore informational response " << response_code
522 << " on stream" << id();
Kenichi Ishibashi51bac23b2021-03-18 10:05:17523 }
Kenichi Ishibashi10111e82021-03-23 02:19:06524 return;
Kenichi Ishibashi51bac23b2021-03-18 10:05:17525 }
526
dahollingsaf3796492016-05-25 19:21:35527 ConsumeHeaderList();
528 session_->OnInitialHeadersComplete(id(), header_block);
529
rch08e198572017-05-09 16:56:55530 // Buffer the headers and deliver them when the handle arrives.
Bence Békyb6300042020-01-28 21:18:20531 initial_headers_arrived_ = true;
rch6788ad52017-05-09 04:49:04532 initial_headers_ = std::move(header_block);
533 initial_headers_frame_len_ = frame_len;
rchfb47f712017-05-21 03:24:00534
535 if (handle_) {
536 // The handle will be notified of the headers via a posted task.
537 NotifyHandleOfInitialHeadersAvailableLater();
538 }
dahollingsaf3796492016-05-25 19:21:35539}
540
541void QuicChromiumClientStream::OnTrailingHeadersComplete(
542 bool fin,
543 size_t frame_len,
Ryan Hamilton8d9ee76e2018-05-29 23:52:52544 const quic::QuicHeaderList& header_list) {
545 quic::QuicSpdyStream::OnTrailingHeadersComplete(fin, frame_len, header_list);
rchce246412017-05-30 13:51:50546 trailing_headers_frame_len_ = frame_len;
547 if (handle_) {
548 // The handle will be notified of the headers via a posted task.
549 NotifyHandleOfTrailingHeadersAvailableLater();
550 }
dahollingsaf3796492016-05-25 19:21:35551}
552
ckrasic769733c2016-06-30 00:42:13553void QuicChromiumClientStream::OnPromiseHeaderList(
Ryan Hamilton8d9ee76e2018-05-29 23:52:52554 quic::QuicStreamId promised_id,
ckrasic769733c2016-06-30 00:42:13555 size_t frame_len,
Ryan Hamilton8d9ee76e2018-05-29 23:52:52556 const quic::QuicHeaderList& header_list) {
Bence Béky4c325e52020-10-22 20:48:01557 spdy::Http2HeaderBlock promise_headers;
ckrasic769733c2016-06-30 00:42:13558 int64_t content_length = -1;
Ryan Hamilton8d9ee76e2018-05-29 23:52:52559 if (!quic::SpdyUtils::CopyAndValidateHeaders(header_list, &content_length,
560 &promise_headers)) {
ckrasic769733c2016-06-30 00:42:13561 DLOG(ERROR) << "Failed to parse header list: " << header_list.DebugString();
562 ConsumeHeaderList();
Ryan Hamilton8d9ee76e2018-05-29 23:52:52563 Reset(quic::QUIC_BAD_APPLICATION_PAYLOAD);
ckrasic769733c2016-06-30 00:42:13564 return;
565 }
566 ConsumeHeaderList();
567
568 session_->HandlePromised(id(), promised_id, promise_headers);
569}
570
Frank Kastenholz1dac18b62018-11-29 18:50:36571void QuicChromiumClientStream::OnBodyAvailable() {
rchb27683c2015-07-29 23:53:50572 if (!FinishedReadingHeaders() || !headers_delivered_) {
rch7dd15702015-07-01 18:57:57573 // Buffer the data in the sequencer until the headers have been read.
rchb27683c2015-07-29 23:53:50574 return;
rch7dd15702015-07-01 18:57:57575 }
576
Renjief49758b2019-01-11 23:32:41577 if (!HasBytesToRead() && !FinishedReadingTrailers()) {
xunjieli7640faa2016-10-06 00:45:42578 // If there is no data to read, wait until either FIN is received or
579 // trailers are delivered.
580 return;
581 }
582
rch08e198572017-05-09 16:56:55583 // The handle will read the data via a posted task, and
rchb27683c2015-07-29 23:53:50584 // will be able to, potentially, read all data which has queued up.
rch08e198572017-05-09 16:56:55585 if (handle_)
586 NotifyHandleOfDataAvailableLater();
[email protected]dd3fd0e2012-11-04 05:14:40587}
588
rch12fef552016-01-15 16:26:31589void QuicChromiumClientStream::OnClose() {
rch08e198572017-05-09 16:56:55590 if (handle_) {
591 handle_->OnClose();
592 handle_ = nullptr;
[email protected]f702d572012-12-04 15:56:20593 }
Ryan Hamilton8d9ee76e2018-05-29 23:52:52594 quic::QuicStream::OnClose();
[email protected]dd3fd0e2012-11-04 05:14:40595}
596
rch12fef552016-01-15 16:26:31597void QuicChromiumClientStream::OnCanWrite() {
Ryan Hamilton8d9ee76e2018-05-29 23:52:52598 quic::QuicStream::OnCanWrite();
[email protected]6adeb922013-09-01 22:43:25599
rch2ab4d872017-05-28 15:15:40600 if (!HasBufferedData() && handle_)
601 handle_->OnCanWrite();
[email protected]6adeb922013-09-01 22:43:25602}
603
xunjieli5fafe142016-03-23 23:32:54604size_t QuicChromiumClientStream::WriteHeaders(
Bence Béky4c325e52020-10-22 20:48:01605 spdy::Http2HeaderBlock header_block,
xunjieli5fafe142016-03-23 23:32:54606 bool fin,
Victor Vasiliev5b04a6b2022-03-15 14:24:25607 quiche::QuicheReferenceCountedPointer<quic::QuicAckListenerInterface>
Ryan Hamilton8d9ee76e2018-05-29 23:52:52608 ack_listener) {
Victor Vasiliev29197e22020-01-16 20:48:32609 if (!session()->OneRttKeysAvailable()) {
rchcb1d6bde2016-06-18 00:33:07610 auto entry = header_block.find(":method");
611 DCHECK(entry != header_block.end());
Yu Suba2a1d72020-12-04 02:14:41612 DCHECK(
613 entry->second != "POST" ||
614 (handle_ != nullptr && handle_->GetRequestIdempotency() == IDEMPOTENT));
rchcb1d6bde2016-06-18 00:33:07615 }
xunjieli5fafe142016-03-23 23:32:54616 net_log_.AddEvent(
mikecirone8b85c432016-09-08 19:11:00617 NetLogEventType::QUIC_CHROMIUM_CLIENT_STREAM_SEND_REQUEST_HEADERS,
Eric Roman06bd9742019-07-13 15:19:13618 [&](NetLogCaptureMode capture_mode) {
Dan Zhang98f8c7062019-07-30 14:32:00619 return QuicRequestNetLogParams(
620 id(), &header_block, precedence().spdy3_priority(), capture_mode);
Eric Roman06bd9742019-07-13 15:19:13621 });
Ryan Hamilton8d9ee76e2018-05-29 23:52:52622 size_t len = quic::QuicSpdyStream::WriteHeaders(std::move(header_block), fin,
623 std::move(ack_listener));
rchd4651b92017-05-04 00:41:17624 initial_headers_sent_ = true;
625 return len;
xunjieli5fafe142016-03-23 23:32:54626}
627
Victor Vasiliev47ecb6a2020-10-14 17:22:10628bool QuicChromiumClientStream::WriteStreamData(absl::string_view data,
Ryan Hamilton8d9ee76e2018-05-29 23:52:52629 bool fin) {
Fan Yanga9caa8d2020-11-19 20:29:10630 // For gQUIC, this must not be called when data is buffered because headers
631 // are sent on the dedicated header stream.
632 DCHECK(!HasBufferedData() || VersionUsesHttp3(quic_version_));
[email protected]6adeb922013-09-01 22:43:25633 // Writes the data, or buffers it.
Dan Zhang5ae7041a22019-02-13 23:58:18634 WriteOrBufferBody(data, fin);
rch2ab4d872017-05-28 15:15:40635 return !HasBufferedData(); // Was all data written?
[email protected]6adeb922013-09-01 22:43:25636}
637
rch2ab4d872017-05-28 15:15:40638bool QuicChromiumClientStream::WritevStreamData(
xunjieli2328a2682016-05-16 19:38:25639 const std::vector<scoped_refptr<IOBuffer>>& buffers,
xunjieli07a42ce2016-04-26 20:05:31640 const std::vector<int>& lengths,
rch2ab4d872017-05-28 15:15:40641 bool fin) {
David Schinazic9db3672021-04-14 18:12:55642 // For gQUIC, this must not be called when data is buffered because headers
643 // are sent on the dedicated header stream.
644 DCHECK(!HasBufferedData() || VersionUsesHttp3(quic_version_));
xunjieli07a42ce2016-04-26 20:05:31645 // Writes the data, or buffers it.
Ryan Hamiltona3ee93a72018-08-01 22:03:08646 for (size_t i = 0; i < buffers.size(); ++i) {
647 bool is_fin = fin && (i == buffers.size() - 1);
Victor Vasiliev47ecb6a2020-10-14 17:22:10648 absl::string_view string_data(buffers[i]->data(), lengths[i]);
Dan Zhang5ae7041a22019-02-13 23:58:18649 WriteOrBufferBody(string_data, is_fin);
Ryan Hamiltona3ee93a72018-08-01 22:03:08650 }
rch2ab4d872017-05-28 15:15:40651 return !HasBufferedData(); // Was all data written?
xunjieli07a42ce2016-04-26 20:05:31652}
653
rch08e198572017-05-09 16:56:55654std::unique_ptr<QuicChromiumClientStream::Handle>
rch1bcfddf22017-06-03 00:26:29655QuicChromiumClientStream::CreateHandle() {
rch08e198572017-05-09 16:56:55656 DCHECK(!handle_);
Ryan Hamiltona3ee93a72018-08-01 22:03:08657 auto handle = base::WrapUnique(new QuicChromiumClientStream::Handle(this));
rch08e198572017-05-09 16:56:55658 handle_ = handle.get();
rch6788ad52017-05-09 04:49:04659
660 // Should this perhaps be via PostTask to make reasoning simpler?
Bence Békyb6300042020-01-28 21:18:20661 if (initial_headers_arrived_) {
rchfb47f712017-05-21 03:24:00662 handle_->OnInitialHeadersAvailable();
Bence Békyb6300042020-01-28 21:18:20663 }
rch08e198572017-05-09 16:56:55664
665 return handle;
666}
667
668void QuicChromiumClientStream::ClearHandle() {
669 handle_ = nullptr;
[email protected]dd3fd0e2012-11-04 05:14:40670}
671
rch12fef552016-01-15 16:26:31672void QuicChromiumClientStream::OnError(int error) {
rch08e198572017-05-09 16:56:55673 if (handle_) {
674 QuicChromiumClientStream::Handle* handle = handle_;
675 handle_ = nullptr;
676 handle->OnError(error);
[email protected]56dfb902013-01-03 23:17:55677 }
678}
679
rch12fef552016-01-15 16:26:31680int QuicChromiumClientStream::Read(IOBuffer* buf, int buf_len) {
Nidhi Jajuf41dd4a2022-09-12 10:14:47681 // TODO(https://crbug.com/1335423): Change to DCHECK() or remove after bug
Bence Béky707a52242022-06-13 20:46:47682 // is fixed.
683 CHECK_GT(buf_len, 0);
Nidhi Jajuf41dd4a2022-09-12 10:14:47684 CHECK(buf->data());
Bence Béky707a52242022-06-13 20:46:47685
xunjieliec0ed02a2016-10-10 18:05:06686 if (IsDoneReading())
rchb27683c2015-07-29 23:53:50687 return 0; // EOF
688
689 if (!HasBytesToRead())
690 return ERR_IO_PENDING;
691
692 iovec iov;
693 iov.iov_base = buf->data();
694 iov.iov_len = buf_len;
xunjieliec0ed02a2016-10-10 18:05:06695 size_t bytes_read = Readv(&iov, 1);
rch03499252017-05-03 17:44:37696 // Since HasBytesToRead is true, Readv() must of read some data.
697 DCHECK_NE(0u, bytes_read);
xunjieliec0ed02a2016-10-10 18:05:06698 return bytes_read;
rchb27683c2015-07-29 23:53:50699}
700
rchfb47f712017-05-21 03:24:00701void QuicChromiumClientStream::NotifyHandleOfInitialHeadersAvailableLater() {
rch08e198572017-05-09 16:56:55702 DCHECK(handle_);
rch6788ad52017-05-09 04:49:04703 base::ThreadTaskRunnerHandle::Get()->PostTask(
704 FROM_HERE,
kylecharf4fe5172019-02-15 18:53:49705 base::BindOnce(
rch08e198572017-05-09 16:56:55706 &QuicChromiumClientStream::NotifyHandleOfInitialHeadersAvailable,
rchfb47f712017-05-21 03:24:00707 weak_factory_.GetWeakPtr()));
rchb27683c2015-07-29 23:53:50708}
709
rchfb47f712017-05-21 03:24:00710void QuicChromiumClientStream::NotifyHandleOfInitialHeadersAvailable() {
rch08e198572017-05-09 16:56:55711 if (!handle_)
rchb27683c2015-07-29 23:53:50712 return;
713
rchfb47f712017-05-21 03:24:00714 if (!headers_delivered_)
715 handle_->OnInitialHeadersAvailable();
rchec5b74ac2017-05-09 13:31:40716}
717
rchce246412017-05-30 13:51:50718void QuicChromiumClientStream::NotifyHandleOfTrailingHeadersAvailableLater() {
rch08e198572017-05-09 16:56:55719 DCHECK(handle_);
rchec5b74ac2017-05-09 13:31:40720 base::ThreadTaskRunnerHandle::Get()->PostTask(
721 FROM_HERE,
kylecharf4fe5172019-02-15 18:53:49722 base::BindOnce(
rch08e198572017-05-09 16:56:55723 &QuicChromiumClientStream::NotifyHandleOfTrailingHeadersAvailable,
rchce246412017-05-30 13:51:50724 weak_factory_.GetWeakPtr()));
rchec5b74ac2017-05-09 13:31:40725}
726
rchce246412017-05-30 13:51:50727void QuicChromiumClientStream::NotifyHandleOfTrailingHeadersAvailable() {
rch08e198572017-05-09 16:56:55728 if (!handle_)
rchec5b74ac2017-05-09 13:31:40729 return;
730
Kenichi Ishibashi9bc79772021-03-22 00:53:12731 // If trailers aren't decompressed it means that trailers are invalid
732 // (e.g., contain ":status" field). Don't notify to the handle if trailers
733 // aren't decompressed since the stream will be closed and
734 // `headers_delivered_` won't become true.
735 if (!trailers_decompressed())
736 return;
737
Kenichi Ishibashi0176ff92021-09-28 00:29:06738 // Notify only after the handle reads initial headers.
739 if (!headers_delivered_)
740 return;
741
rch1bcfddf22017-06-03 00:26:29742 // Post an async task to notify handle of the FIN flag.
rch08e198572017-05-09 16:56:55743 NotifyHandleOfDataAvailableLater();
rchce246412017-05-30 13:51:50744 handle_->OnTrailingHeadersAvailable();
rchb27683c2015-07-29 23:53:50745}
746
Kenichi Ishibashi51bac23b2021-03-18 10:05:17747int QuicChromiumClientStream::DeliverEarlyHints(
748 spdy::Http2HeaderBlock* headers) {
749 if (early_hints_.empty()) {
750 return ERR_IO_PENDING;
751 }
752
753 DCHECK(!headers_delivered_);
754
755 EarlyHints& hints = early_hints_.front();
756 *headers = std::move(hints.headers);
757 size_t frame_len = hints.frame_len;
758 early_hints_.pop_front();
759
760 net_log_.AddEvent(
761 NetLogEventType::
762 QUIC_CHROMIUM_CLIENT_STREAM_READ_EARLY_HINTS_RESPONSE_HEADERS,
763 [&](NetLogCaptureMode capture_mode) {
764 return QuicResponseNetLogParams(id(), fin_received(), headers,
765 capture_mode);
766 });
767
768 return frame_len;
769}
770
Bence Békyb6300042020-01-28 21:18:20771int QuicChromiumClientStream::DeliverInitialHeaders(
Bence Béky4c325e52020-10-22 20:48:01772 spdy::Http2HeaderBlock* headers) {
Bence Békyb6300042020-01-28 21:18:20773 if (!initial_headers_arrived_) {
774 return ERR_IO_PENDING;
775 }
rchfb47f712017-05-21 03:24:00776
777 headers_delivered_ = true;
Bence Békyb6300042020-01-28 21:18:20778
779 if (initial_headers_.empty()) {
780 return ERR_INVALID_RESPONSE;
781 }
782
rchfb47f712017-05-21 03:24:00783 net_log_.AddEvent(
784 NetLogEventType::QUIC_CHROMIUM_CLIENT_STREAM_READ_RESPONSE_HEADERS,
Eric Roman06bd9742019-07-13 15:19:13785 [&](NetLogCaptureMode capture_mode) {
786 return QuicResponseNetLogParams(id(), fin_received(), &initial_headers_,
787 capture_mode);
788 });
rchfb47f712017-05-21 03:24:00789
790 *headers = std::move(initial_headers_);
Bence Békyb6300042020-01-28 21:18:20791 return initial_headers_frame_len_;
rchfb47f712017-05-21 03:24:00792}
793
Ryan Hamilton0239aac2018-05-19 00:03:13794bool QuicChromiumClientStream::DeliverTrailingHeaders(
Bence Béky4c325e52020-10-22 20:48:01795 spdy::Http2HeaderBlock* headers,
Ryan Hamilton0239aac2018-05-19 00:03:13796 int* frame_len) {
rchce246412017-05-30 13:51:50797 if (received_trailers().empty())
798 return false;
799
800 net_log_.AddEvent(
801 NetLogEventType::QUIC_CHROMIUM_CLIENT_STREAM_READ_RESPONSE_TRAILERS,
Eric Roman06bd9742019-07-13 15:19:13802 [&](NetLogCaptureMode capture_mode) {
803 return QuicResponseNetLogParams(id(), fin_received(),
804 &received_trailers(), capture_mode);
805 });
rchce246412017-05-30 13:51:50806
807 *headers = received_trailers().Clone();
808 *frame_len = trailing_headers_frame_len_;
809
810 MarkTrailersConsumed();
811 return true;
812}
813
rch08e198572017-05-09 16:56:55814void QuicChromiumClientStream::NotifyHandleOfDataAvailableLater() {
815 DCHECK(handle_);
rch6788ad52017-05-09 04:49:04816 base::ThreadTaskRunnerHandle::Get()->PostTask(
817 FROM_HERE,
kylecharf4fe5172019-02-15 18:53:49818 base::BindOnce(&QuicChromiumClientStream::NotifyHandleOfDataAvailable,
819 weak_factory_.GetWeakPtr()));
rchb27683c2015-07-29 23:53:50820}
821
rch08e198572017-05-09 16:56:55822void QuicChromiumClientStream::NotifyHandleOfDataAvailable() {
823 if (handle_)
824 handle_->OnDataAvailable();
rchb27683c2015-07-29 23:53:50825}
826
Zhongyi Shibb28b1f2018-07-18 02:41:26827void QuicChromiumClientStream::DisableConnectionMigrationToCellularNetwork() {
828 can_migrate_to_cellular_network_ = false;
jri231c2972016-03-08 19:50:11829}
830
xunjieli100937eb52016-09-15 20:09:37831bool QuicChromiumClientStream::IsFirstStream() {
Victor Vasiliev7da08172019-10-14 06:04:25832 if (VersionUsesHttp3(quic_version_)) {
Fan Yang2330d182019-08-05 14:50:50833 return id() == quic::QuicUtils::GetFirstBidirectionalStreamId(
834 quic_version_, quic::Perspective::IS_CLIENT);
835 }
Fan Yang32c5a112018-12-10 20:06:33836 return id() == quic::QuicUtils::GetHeadersStreamId(quic_version_) +
837 quic::QuicUtils::StreamIdDelta(quic_version_);
xunjieli100937eb52016-09-15 20:09:37838}
839
[email protected]dd3fd0e2012-11-04 05:14:40840} // namespace net