1 // Copyright 2012 The Chromium Authors
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/quic/quic_chromium_client_stream.h"
6
7 #include <utility>
8
9 #include "base/functional/bind.h"
10 #include "base/functional/callback_helpers.h"
11 #include "base/location.h"
12 #include "base/memory/ptr_util.h"
13 #include "base/memory/raw_ptr.h"
14 #include "base/metrics/histogram_functions.h"
15 #include "base/task/single_thread_task_runner.h"
16 #include "net/base/io_buffer.h"
17 #include "net/base/net_errors.h"
18 #include "net/http/http_status_code.h"
19 #include "net/log/net_log_event_type.h"
20 #include "net/quic/quic_chromium_client_session.h"
21 #include "net/quic/quic_http_utils.h"
22 #include "net/spdy/spdy_log_util.h"
23 #include "net/third_party/quiche/src/quiche/quic/core/http/quic_spdy_session.h"
24 #include "net/third_party/quiche/src/quiche/quic/core/http/spdy_utils.h"
25 #include "net/third_party/quiche/src/quiche/quic/core/quic_utils.h"
26 #include "net/third_party/quiche/src/quiche/quic/core/quic_write_blocked_list.h"
27
28 namespace net {
29 namespace {
30 // Sets a boolean to a value, and restores it to the previous value once
31 // the saver goes out of scope.
32 class ScopedBoolSaver {
33 public:
ScopedBoolSaver(bool * var,bool new_val)34 ScopedBoolSaver(bool* var, bool new_val) : var_(var), old_val_(*var) {
35 *var_ = new_val;
36 }
37
~ScopedBoolSaver()38 ~ScopedBoolSaver() { *var_ = old_val_; }
39
40 private:
41 raw_ptr<bool> var_;
42 bool old_val_;
43 };
44 } // namespace
45
Handle(QuicChromiumClientStream * stream)46 QuicChromiumClientStream::Handle::Handle(QuicChromiumClientStream* stream)
47 : stream_(stream), net_log_(stream->net_log()) {
48 SaveState();
49 }
50
~Handle()51 QuicChromiumClientStream::Handle::~Handle() {
52 if (stream_) {
53 stream_->ClearHandle();
54 // TODO(rch): If stream_ is still valid, it should probably be Reset()
55 // so that it does not leak.
56 // stream_->Reset(quic::QUIC_STREAM_CANCELLED);
57 }
58 }
59
OnEarlyHintsAvailable()60 void QuicChromiumClientStream::Handle::OnEarlyHintsAvailable() {
61 if (first_early_hints_time_.is_null())
62 first_early_hints_time_ = base::TimeTicks::Now();
63
64 if (!read_headers_callback_)
65 return; // Wait for ReadInitialHeaders to be called.
66
67 DCHECK(read_headers_buffer_);
68 int rv = stream_->DeliverEarlyHints(read_headers_buffer_);
69 DCHECK_NE(ERR_IO_PENDING, rv);
70
71 ResetAndRun(std::move(read_headers_callback_), rv);
72 }
73
OnInitialHeadersAvailable()74 void QuicChromiumClientStream::Handle::OnInitialHeadersAvailable() {
75 if (headers_received_start_time_.is_null())
76 headers_received_start_time_ = base::TimeTicks::Now();
77
78 if (!read_headers_callback_)
79 return; // Wait for ReadInitialHeaders to be called.
80
81 int rv = stream_->DeliverInitialHeaders(read_headers_buffer_);
82 DCHECK_NE(ERR_IO_PENDING, rv);
83
84 ResetAndRun(std::move(read_headers_callback_), rv);
85 }
86
OnTrailingHeadersAvailable()87 void QuicChromiumClientStream::Handle::OnTrailingHeadersAvailable() {
88 if (!read_headers_callback_)
89 return; // Wait for ReadInitialHeaders to be called.
90
91 int rv = ERR_QUIC_PROTOCOL_ERROR;
92 if (!stream_->DeliverTrailingHeaders(read_headers_buffer_, &rv))
93 rv = ERR_QUIC_PROTOCOL_ERROR;
94
95 base::UmaHistogramBoolean(
96 "Net.QuicChromiumClientStream.TrailingHeadersProcessSuccess", rv >= 0);
97 ResetAndRun(std::move(read_headers_callback_), rv);
98 }
99
OnDataAvailable()100 void QuicChromiumClientStream::Handle::OnDataAvailable() {
101 if (!read_body_callback_)
102 return; // Wait for ReadBody to be called.
103
104 DCHECK(read_body_buffer_);
105 DCHECK_GT(read_body_buffer_len_, 0);
106
107 int rv = stream_->Read(read_body_buffer_, read_body_buffer_len_);
108 if (rv == ERR_IO_PENDING)
109 return; // Spurrious, likely because of trailers?
110
111 read_body_buffer_ = nullptr;
112 read_body_buffer_len_ = 0;
113 ResetAndRun(std::move(read_body_callback_), rv);
114 }
115
OnCanWrite()116 void QuicChromiumClientStream::Handle::OnCanWrite() {
117 if (!write_callback_)
118 return;
119
120 ResetAndRun(std::move(write_callback_), OK);
121 }
122
OnClose()123 void QuicChromiumClientStream::Handle::OnClose() {
124 if (net_error_ == ERR_UNEXPECTED) {
125 if (stream_error() == quic::QUIC_STREAM_NO_ERROR &&
126 connection_error() == quic::QUIC_NO_ERROR && fin_sent() &&
127 fin_received()) {
128 net_error_ = ERR_CONNECTION_CLOSED;
129 } else {
130 net_error_ = ERR_QUIC_PROTOCOL_ERROR;
131 }
132 }
133 base::UmaHistogramSparse("Net.QuicChromiumClientStream.HandleOnCloseNetError",
134 -net_error_);
135 base::UmaHistogramSparse(
136 "Net.QuicChromiumClientStream.HandleOnCloseStreamError", stream_error());
137 base::UmaHistogramSparse(
138 "Net.QuicChromiumClientStream.HandleOnCloseConnectionError",
139 connection_error());
140 OnError(net_error_);
141 }
142
OnError(int error)143 void QuicChromiumClientStream::Handle::OnError(int error) {
144 net_error_ = error;
145 if (stream_)
146 SaveState();
147 stream_ = nullptr;
148
149 // Post a task to invoke the callbacks to ensure that there is no reentrancy.
150 // A ScopedPacketFlusher might cause an error which closes the stream under
151 // the call stack of the owner of the handle.
152 base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
153 FROM_HERE,
154 base::BindOnce(&QuicChromiumClientStream::Handle::InvokeCallbacksOnClose,
155 weak_factory_.GetWeakPtr(), error));
156 }
157
InvokeCallbacksOnClose(int error)158 void QuicChromiumClientStream::Handle::InvokeCallbacksOnClose(int error) {
159 // Invoking a callback may cause |this| to be deleted. If this happens, no
160 // more callbacks should be invoked. Guard against this by holding a WeakPtr
161 // to |this| and ensuring it's still valid.
162 auto guard(weak_factory_.GetWeakPtr());
163 for (auto* callback :
164 {&read_headers_callback_, &read_body_callback_, &write_callback_}) {
165 if (*callback)
166 ResetAndRun(std::move(*callback), error);
167 if (!guard.get())
168 return;
169 }
170 }
171
ReadInitialHeaders(spdy::Http2HeaderBlock * header_block,CompletionOnceCallback callback)172 int QuicChromiumClientStream::Handle::ReadInitialHeaders(
173 spdy::Http2HeaderBlock* header_block,
174 CompletionOnceCallback callback) {
175 ScopedBoolSaver saver(&may_invoke_callbacks_, false);
176 if (!stream_)
177 return net_error_;
178
179 // Check Early Hints first.
180 int rv = stream_->DeliverEarlyHints(header_block);
181 if (rv != ERR_IO_PENDING) {
182 return rv;
183 }
184
185 rv = stream_->DeliverInitialHeaders(header_block);
186 if (rv != ERR_IO_PENDING) {
187 return rv;
188 }
189
190 read_headers_buffer_ = header_block;
191 DCHECK(!read_headers_callback_);
192 SetCallback(std::move(callback), &read_headers_callback_);
193 return ERR_IO_PENDING;
194 }
195
ReadBody(IOBuffer * buffer,int buffer_len,CompletionOnceCallback callback)196 int QuicChromiumClientStream::Handle::ReadBody(
197 IOBuffer* buffer,
198 int buffer_len,
199 CompletionOnceCallback callback) {
200 ScopedBoolSaver saver(&may_invoke_callbacks_, false);
201 if (IsDoneReading())
202 return OK;
203
204 if (!stream_)
205 return net_error_;
206
207 if (stream_->read_side_closed()) {
208 return OK;
209 }
210
211 int rv = stream_->Read(buffer, buffer_len);
212 if (rv != ERR_IO_PENDING)
213 return rv;
214
215 DCHECK(buffer);
216 DCHECK_GT(buffer_len, 0);
217
218 SetCallback(std::move(callback), &read_body_callback_);
219 read_body_buffer_ = buffer;
220 read_body_buffer_len_ = buffer_len;
221 return ERR_IO_PENDING;
222 }
223
ReadTrailingHeaders(spdy::Http2HeaderBlock * header_block,CompletionOnceCallback callback)224 int QuicChromiumClientStream::Handle::ReadTrailingHeaders(
225 spdy::Http2HeaderBlock* header_block,
226 CompletionOnceCallback callback) {
227 ScopedBoolSaver saver(&may_invoke_callbacks_, false);
228 if (!stream_)
229 return net_error_;
230
231 int frame_len = 0;
232 if (stream_->DeliverTrailingHeaders(header_block, &frame_len))
233 return frame_len;
234
235 read_headers_buffer_ = header_block;
236 SetCallback(std::move(callback), &read_headers_callback_);
237 return ERR_IO_PENDING;
238 }
239
WriteHeaders(spdy::Http2HeaderBlock header_block,bool fin,quiche::QuicheReferenceCountedPointer<quic::QuicAckListenerInterface> ack_notifier_delegate)240 int QuicChromiumClientStream::Handle::WriteHeaders(
241 spdy::Http2HeaderBlock header_block,
242 bool fin,
243 quiche::QuicheReferenceCountedPointer<quic::QuicAckListenerInterface>
244 ack_notifier_delegate) {
245 if (!stream_)
246 return 0;
247 return HandleIOComplete(stream_->WriteHeaders(std::move(header_block), fin,
248 ack_notifier_delegate));
249 }
250
WriteStreamData(base::StringPiece data,bool fin,CompletionOnceCallback callback)251 int QuicChromiumClientStream::Handle::WriteStreamData(
252 base::StringPiece data,
253 bool fin,
254 CompletionOnceCallback callback) {
255 ScopedBoolSaver saver(&may_invoke_callbacks_, false);
256 if (!stream_)
257 return net_error_;
258
259 if (stream_->WriteStreamData(data, fin)) {
260 return HandleIOComplete(OK);
261 }
262
263 SetCallback(std::move(callback), &write_callback_);
264 return ERR_IO_PENDING;
265 }
266
WritevStreamData(const std::vector<scoped_refptr<IOBuffer>> & buffers,const std::vector<int> & lengths,bool fin,CompletionOnceCallback callback)267 int QuicChromiumClientStream::Handle::WritevStreamData(
268 const std::vector<scoped_refptr<IOBuffer>>& buffers,
269 const std::vector<int>& lengths,
270 bool fin,
271 CompletionOnceCallback callback) {
272 ScopedBoolSaver saver(&may_invoke_callbacks_, false);
273 if (!stream_)
274 return net_error_;
275
276 if (stream_->WritevStreamData(buffers, lengths, fin))
277 return HandleIOComplete(OK);
278
279 SetCallback(std::move(callback), &write_callback_);
280 return ERR_IO_PENDING;
281 }
282
Read(IOBuffer * buf,int buf_len)283 int QuicChromiumClientStream::Handle::Read(IOBuffer* buf, int buf_len) {
284 if (!stream_)
285 return net_error_;
286 return stream_->Read(buf, buf_len);
287 }
288
OnFinRead()289 void QuicChromiumClientStream::Handle::OnFinRead() {
290 read_headers_callback_.Reset();
291 if (stream_)
292 stream_->OnFinRead();
293 }
294
295 void QuicChromiumClientStream::Handle::
DisableConnectionMigrationToCellularNetwork()296 DisableConnectionMigrationToCellularNetwork() {
297 if (stream_)
298 stream_->DisableConnectionMigrationToCellularNetwork();
299 }
300
SetPriority(const quic::QuicStreamPriority & priority)301 void QuicChromiumClientStream::Handle::SetPriority(
302 const quic::QuicStreamPriority& priority) {
303 if (stream_) {
304 stream_->SetPriority(priority);
305 }
306 }
307
Reset(quic::QuicRstStreamErrorCode error_code)308 void QuicChromiumClientStream::Handle::Reset(
309 quic::QuicRstStreamErrorCode error_code) {
310 if (stream_)
311 stream_->Reset(error_code);
312 }
313
id() const314 quic::QuicStreamId QuicChromiumClientStream::Handle::id() const {
315 if (!stream_)
316 return id_;
317 return stream_->id();
318 }
319
connection_error() const320 quic::QuicErrorCode QuicChromiumClientStream::Handle::connection_error() const {
321 if (!stream_)
322 return connection_error_;
323 return stream_->connection_error();
324 }
325
stream_error() const326 quic::QuicRstStreamErrorCode QuicChromiumClientStream::Handle::stream_error()
327 const {
328 if (!stream_)
329 return stream_error_;
330 return stream_->stream_error();
331 }
332
fin_sent() const333 bool QuicChromiumClientStream::Handle::fin_sent() const {
334 if (!stream_)
335 return fin_sent_;
336 return stream_->fin_sent();
337 }
338
fin_received() const339 bool QuicChromiumClientStream::Handle::fin_received() const {
340 if (!stream_)
341 return fin_received_;
342 return stream_->fin_received();
343 }
344
stream_bytes_read() const345 uint64_t QuicChromiumClientStream::Handle::stream_bytes_read() const {
346 if (!stream_)
347 return stream_bytes_read_;
348 return stream_->stream_bytes_read();
349 }
350
stream_bytes_written() const351 uint64_t QuicChromiumClientStream::Handle::stream_bytes_written() const {
352 if (!stream_)
353 return stream_bytes_written_;
354 return stream_->stream_bytes_written();
355 }
356
NumBytesConsumed() const357 size_t QuicChromiumClientStream::Handle::NumBytesConsumed() const {
358 if (!stream_)
359 return num_bytes_consumed_;
360 return stream_->sequencer()->NumBytesConsumed();
361 }
362
HasBytesToRead() const363 bool QuicChromiumClientStream::Handle::HasBytesToRead() const {
364 if (!stream_)
365 return false;
366 return stream_->HasBytesToRead();
367 }
368
IsDoneReading() const369 bool QuicChromiumClientStream::Handle::IsDoneReading() const {
370 if (!stream_)
371 return is_done_reading_;
372 return stream_->IsDoneReading();
373 }
374
IsFirstStream() const375 bool QuicChromiumClientStream::Handle::IsFirstStream() const {
376 if (!stream_)
377 return is_first_stream_;
378 return stream_->IsFirstStream();
379 }
380
can_migrate_to_cellular_network()381 bool QuicChromiumClientStream::Handle::can_migrate_to_cellular_network() {
382 if (!stream_)
383 return false;
384 return stream_->can_migrate_to_cellular_network();
385 }
386
net_log() const387 const NetLogWithSource& QuicChromiumClientStream::Handle::net_log() const {
388 return net_log_;
389 }
390
SaveState()391 void QuicChromiumClientStream::Handle::SaveState() {
392 DCHECK(stream_);
393 fin_sent_ = stream_->fin_sent();
394 fin_received_ = stream_->fin_received();
395 num_bytes_consumed_ = stream_->sequencer()->NumBytesConsumed();
396 id_ = stream_->id();
397 connection_error_ = stream_->connection_error();
398 stream_error_ = stream_->stream_error();
399 is_done_reading_ = stream_->IsDoneReading();
400 is_first_stream_ = stream_->IsFirstStream();
401 stream_bytes_read_ = stream_->stream_bytes_read();
402 stream_bytes_written_ = stream_->stream_bytes_written();
403 }
404
SetCallback(CompletionOnceCallback new_callback,CompletionOnceCallback * callback)405 void QuicChromiumClientStream::Handle::SetCallback(
406 CompletionOnceCallback new_callback,
407 CompletionOnceCallback* callback) {
408 // TODO(rch): Convert this to a DCHECK once we ensure the API is stable and
409 // bug free.
410 CHECK(!may_invoke_callbacks_);
411 *callback = std::move(new_callback);
412 }
413
ResetAndRun(CompletionOnceCallback callback,int rv)414 void QuicChromiumClientStream::Handle::ResetAndRun(
415 CompletionOnceCallback callback,
416 int rv) {
417 // TODO(rch): Convert this to a DCHECK once we ensure the API is stable and
418 // bug free.
419 CHECK(may_invoke_callbacks_);
420 std::move(callback).Run(rv);
421 }
422
HandleIOComplete(int rv)423 int QuicChromiumClientStream::Handle::HandleIOComplete(int rv) {
424 // If |stream_| is still valid the stream has not been closed. If the stream
425 // has not been closed, then just return |rv|.
426 if (rv < 0 || stream_)
427 return rv;
428
429 if (stream_error_ == quic::QUIC_STREAM_NO_ERROR &&
430 connection_error_ == quic::QUIC_NO_ERROR && fin_sent_ && fin_received_) {
431 return rv;
432 }
433
434 return net_error_;
435 }
436
SetRequestIdempotency(Idempotency idempotency)437 void QuicChromiumClientStream::Handle::SetRequestIdempotency(
438 Idempotency idempotency) {
439 idempotency_ = idempotency;
440 }
441
GetRequestIdempotency() const442 Idempotency QuicChromiumClientStream::Handle::GetRequestIdempotency() const {
443 return idempotency_;
444 }
445
QuicChromiumClientStream(quic::QuicStreamId id,quic::QuicSpdyClientSessionBase * session,quic::StreamType type,const NetLogWithSource & net_log,const NetworkTrafficAnnotationTag & traffic_annotation)446 QuicChromiumClientStream::QuicChromiumClientStream(
447 quic::QuicStreamId id,
448 quic::QuicSpdyClientSessionBase* session,
449 quic::StreamType type,
450 const NetLogWithSource& net_log,
451 const NetworkTrafficAnnotationTag& traffic_annotation)
452 : quic::QuicSpdyStream(id, session, type),
453 net_log_(net_log),
454 session_(session),
455 quic_version_(session->connection()->transport_version()) {}
456
QuicChromiumClientStream(quic::PendingStream * pending,quic::QuicSpdyClientSessionBase * session,const NetLogWithSource & net_log,const NetworkTrafficAnnotationTag & traffic_annotation)457 QuicChromiumClientStream::QuicChromiumClientStream(
458 quic::PendingStream* pending,
459 quic::QuicSpdyClientSessionBase* session,
460 const NetLogWithSource& net_log,
461 const NetworkTrafficAnnotationTag& traffic_annotation)
462 : quic::QuicSpdyStream(pending, session),
463 net_log_(net_log),
464 session_(session),
465 quic_version_(session->connection()->transport_version()) {}
466
~QuicChromiumClientStream()467 QuicChromiumClientStream::~QuicChromiumClientStream() {
468 if (handle_)
469 handle_->OnClose();
470 }
471
OnInitialHeadersComplete(bool fin,size_t frame_len,const quic::QuicHeaderList & header_list)472 void QuicChromiumClientStream::OnInitialHeadersComplete(
473 bool fin,
474 size_t frame_len,
475 const quic::QuicHeaderList& header_list) {
476 DCHECK(!initial_headers_arrived_);
477 quic::QuicSpdyStream::OnInitialHeadersComplete(fin, frame_len, header_list);
478
479 spdy::Http2HeaderBlock header_block;
480 int64_t length = -1;
481 if (!quic::SpdyUtils::CopyAndValidateHeaders(header_list, &length,
482 &header_block)) {
483 DLOG(ERROR) << "Failed to parse header list: " << header_list.DebugString();
484 ConsumeHeaderList();
485 Reset(quic::QUIC_BAD_APPLICATION_PAYLOAD);
486 return;
487 }
488
489 // Handle informational response. If the response is an Early Hints response,
490 // deliver the response to the owner of the handle. Otherwise ignore the
491 // response.
492 int response_code;
493 if (!ParseHeaderStatusCode(header_block, &response_code)) {
494 DLOG(ERROR) << "Received invalid response code: '"
495 << header_block[":status"].as_string() << "' on stream "
496 << id();
497 Reset(quic::QUIC_BAD_APPLICATION_PAYLOAD);
498 return;
499 }
500
501 if (response_code == HTTP_SWITCHING_PROTOCOLS) {
502 DLOG(ERROR) << "Received forbidden 101 response code on stream " << id();
503 Reset(quic::QUIC_BAD_APPLICATION_PAYLOAD);
504 return;
505 }
506
507 if (response_code >= 100 && response_code < 200) {
508 set_headers_decompressed(false);
509 ConsumeHeaderList();
510 if (response_code == HTTP_EARLY_HINTS) {
511 early_hints_.emplace_back(std::move(header_block), frame_len);
512 if (handle_)
513 handle_->OnEarlyHintsAvailable();
514 } else {
515 DVLOG(1) << "Ignore informational response " << response_code
516 << " on stream" << id();
517 }
518 return;
519 }
520
521 ConsumeHeaderList();
522
523 // Buffer the headers and deliver them when the handle arrives.
524 initial_headers_arrived_ = true;
525 initial_headers_ = std::move(header_block);
526 initial_headers_frame_len_ = frame_len;
527
528 if (handle_) {
529 // The handle will be notified of the headers via a posted task.
530 NotifyHandleOfInitialHeadersAvailableLater();
531 }
532 }
533
OnTrailingHeadersComplete(bool fin,size_t frame_len,const quic::QuicHeaderList & header_list)534 void QuicChromiumClientStream::OnTrailingHeadersComplete(
535 bool fin,
536 size_t frame_len,
537 const quic::QuicHeaderList& header_list) {
538 quic::QuicSpdyStream::OnTrailingHeadersComplete(fin, frame_len, header_list);
539 trailing_headers_frame_len_ = frame_len;
540 if (handle_) {
541 // The handle will be notified of the headers via a posted task.
542 NotifyHandleOfTrailingHeadersAvailableLater();
543 }
544 }
545
OnBodyAvailable()546 void QuicChromiumClientStream::OnBodyAvailable() {
547 if (!FinishedReadingHeaders() || !headers_delivered_) {
548 // Buffer the data in the sequencer until the headers have been read.
549 return;
550 }
551
552 if (!HasBytesToRead() && !FinishedReadingTrailers()) {
553 // If there is no data to read, wait until either FIN is received or
554 // trailers are delivered.
555 return;
556 }
557
558 // The handle will read the data via a posted task, and
559 // will be able to, potentially, read all data which has queued up.
560 if (handle_)
561 NotifyHandleOfDataAvailableLater();
562 }
563
OnClose()564 void QuicChromiumClientStream::OnClose() {
565 if (handle_) {
566 handle_->OnClose();
567 handle_ = nullptr;
568 }
569 quic::QuicStream::OnClose();
570 }
571
OnCanWrite()572 void QuicChromiumClientStream::OnCanWrite() {
573 quic::QuicStream::OnCanWrite();
574
575 if (!HasBufferedData() && handle_)
576 handle_->OnCanWrite();
577 }
578
WriteHeaders(spdy::Http2HeaderBlock header_block,bool fin,quiche::QuicheReferenceCountedPointer<quic::QuicAckListenerInterface> ack_listener)579 size_t QuicChromiumClientStream::WriteHeaders(
580 spdy::Http2HeaderBlock header_block,
581 bool fin,
582 quiche::QuicheReferenceCountedPointer<quic::QuicAckListenerInterface>
583 ack_listener) {
584 if (!session()->OneRttKeysAvailable()) {
585 auto entry = header_block.find(":method");
586 DCHECK(entry != header_block.end());
587 DCHECK(
588 entry->second != "POST" ||
589 (handle_ != nullptr && handle_->GetRequestIdempotency() == IDEMPOTENT));
590 }
591 net_log_.AddEvent(
592 NetLogEventType::QUIC_CHROMIUM_CLIENT_STREAM_SEND_REQUEST_HEADERS,
593 [&](NetLogCaptureMode capture_mode) {
594 return QuicRequestNetLogParams(id(), &header_block, priority(),
595 capture_mode);
596 });
597 size_t len = quic::QuicSpdyStream::WriteHeaders(std::move(header_block), fin,
598 std::move(ack_listener));
599 initial_headers_sent_ = true;
600 return len;
601 }
602
WriteStreamData(std::string_view data,bool fin)603 bool QuicChromiumClientStream::WriteStreamData(std::string_view data,
604 bool fin) {
605 // Writes the data, or buffers it.
606 WriteOrBufferBody(data, fin);
607 return !HasBufferedData(); // Was all data written?
608 }
609
WritevStreamData(const std::vector<scoped_refptr<IOBuffer>> & buffers,const std::vector<int> & lengths,bool fin)610 bool QuicChromiumClientStream::WritevStreamData(
611 const std::vector<scoped_refptr<IOBuffer>>& buffers,
612 const std::vector<int>& lengths,
613 bool fin) {
614 // Writes the data, or buffers it.
615 for (size_t i = 0; i < buffers.size(); ++i) {
616 bool is_fin = fin && (i == buffers.size() - 1);
617 std::string_view string_data(buffers[i]->data(), lengths[i]);
618 WriteOrBufferBody(string_data, is_fin);
619 }
620 return !HasBufferedData(); // Was all data written?
621 }
622
623 std::unique_ptr<QuicChromiumClientStream::Handle>
CreateHandle()624 QuicChromiumClientStream::CreateHandle() {
625 DCHECK(!handle_);
626 auto handle = base::WrapUnique(new QuicChromiumClientStream::Handle(this));
627 handle_ = handle.get();
628
629 // Should this perhaps be via PostTask to make reasoning simpler?
630 if (initial_headers_arrived_) {
631 handle_->OnInitialHeadersAvailable();
632 }
633
634 return handle;
635 }
636
ClearHandle()637 void QuicChromiumClientStream::ClearHandle() {
638 handle_ = nullptr;
639 }
640
OnError(int error)641 void QuicChromiumClientStream::OnError(int error) {
642 if (handle_) {
643 QuicChromiumClientStream::Handle* handle = handle_;
644 handle_ = nullptr;
645 handle->OnError(error);
646 }
647 }
648
Read(IOBuffer * buf,int buf_len)649 int QuicChromiumClientStream::Read(IOBuffer* buf, int buf_len) {
650 DCHECK_GT(buf_len, 0);
651 DCHECK(buf->data());
652
653 if (IsDoneReading())
654 return 0; // EOF
655
656 if (!HasBytesToRead())
657 return ERR_IO_PENDING;
658
659 iovec iov;
660 iov.iov_base = buf->data();
661 iov.iov_len = buf_len;
662 size_t bytes_read = Readv(&iov, 1);
663 // Since HasBytesToRead is true, Readv() must of read some data.
664 DCHECK_NE(0u, bytes_read);
665 return bytes_read;
666 }
667
NotifyHandleOfInitialHeadersAvailableLater()668 void QuicChromiumClientStream::NotifyHandleOfInitialHeadersAvailableLater() {
669 DCHECK(handle_);
670 base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
671 FROM_HERE,
672 base::BindOnce(
673 &QuicChromiumClientStream::NotifyHandleOfInitialHeadersAvailable,
674 weak_factory_.GetWeakPtr()));
675 }
676
NotifyHandleOfInitialHeadersAvailable()677 void QuicChromiumClientStream::NotifyHandleOfInitialHeadersAvailable() {
678 if (!handle_)
679 return;
680
681 if (!headers_delivered_)
682 handle_->OnInitialHeadersAvailable();
683 }
684
NotifyHandleOfTrailingHeadersAvailableLater()685 void QuicChromiumClientStream::NotifyHandleOfTrailingHeadersAvailableLater() {
686 DCHECK(handle_);
687 base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
688 FROM_HERE,
689 base::BindOnce(
690 &QuicChromiumClientStream::NotifyHandleOfTrailingHeadersAvailable,
691 weak_factory_.GetWeakPtr()));
692 }
693
NotifyHandleOfTrailingHeadersAvailable()694 void QuicChromiumClientStream::NotifyHandleOfTrailingHeadersAvailable() {
695 if (!handle_)
696 return;
697
698 // If trailers aren't decompressed it means that trailers are invalid
699 // (e.g., contain ":status" field). Don't notify to the handle if trailers
700 // aren't decompressed since the stream will be closed and
701 // `headers_delivered_` won't become true.
702 if (!trailers_decompressed())
703 return;
704
705 // Notify only after the handle reads initial headers.
706 if (!headers_delivered_)
707 return;
708
709 // Post an async task to notify handle of the FIN flag.
710 NotifyHandleOfDataAvailableLater();
711 handle_->OnTrailingHeadersAvailable();
712 }
713
DeliverEarlyHints(spdy::Http2HeaderBlock * headers)714 int QuicChromiumClientStream::DeliverEarlyHints(
715 spdy::Http2HeaderBlock* headers) {
716 if (early_hints_.empty()) {
717 return ERR_IO_PENDING;
718 }
719
720 DCHECK(!headers_delivered_);
721
722 EarlyHints& hints = early_hints_.front();
723 *headers = std::move(hints.headers);
724 size_t frame_len = hints.frame_len;
725 early_hints_.pop_front();
726
727 net_log_.AddEvent(
728 NetLogEventType::
729 QUIC_CHROMIUM_CLIENT_STREAM_READ_EARLY_HINTS_RESPONSE_HEADERS,
730 [&](NetLogCaptureMode capture_mode) {
731 return QuicResponseNetLogParams(id(), fin_received(), headers,
732 capture_mode);
733 });
734
735 return frame_len;
736 }
737
DeliverInitialHeaders(spdy::Http2HeaderBlock * headers)738 int QuicChromiumClientStream::DeliverInitialHeaders(
739 spdy::Http2HeaderBlock* headers) {
740 if (!initial_headers_arrived_) {
741 return ERR_IO_PENDING;
742 }
743
744 headers_delivered_ = true;
745
746 if (initial_headers_.empty()) {
747 return ERR_INVALID_RESPONSE;
748 }
749
750 net_log_.AddEvent(
751 NetLogEventType::QUIC_CHROMIUM_CLIENT_STREAM_READ_RESPONSE_HEADERS,
752 [&](NetLogCaptureMode capture_mode) {
753 return QuicResponseNetLogParams(id(), fin_received(), &initial_headers_,
754 capture_mode);
755 });
756
757 *headers = std::move(initial_headers_);
758 return initial_headers_frame_len_;
759 }
760
DeliverTrailingHeaders(spdy::Http2HeaderBlock * headers,int * frame_len)761 bool QuicChromiumClientStream::DeliverTrailingHeaders(
762 spdy::Http2HeaderBlock* headers,
763 int* frame_len) {
764 if (received_trailers().empty())
765 return false;
766
767 net_log_.AddEvent(
768 NetLogEventType::QUIC_CHROMIUM_CLIENT_STREAM_READ_RESPONSE_TRAILERS,
769 [&](NetLogCaptureMode capture_mode) {
770 return QuicResponseNetLogParams(id(), fin_received(),
771 &received_trailers(), capture_mode);
772 });
773
774 *headers = received_trailers().Clone();
775 *frame_len = trailing_headers_frame_len_;
776
777 MarkTrailersConsumed();
778 return true;
779 }
780
NotifyHandleOfDataAvailableLater()781 void QuicChromiumClientStream::NotifyHandleOfDataAvailableLater() {
782 DCHECK(handle_);
783 base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
784 FROM_HERE,
785 base::BindOnce(&QuicChromiumClientStream::NotifyHandleOfDataAvailable,
786 weak_factory_.GetWeakPtr()));
787 }
788
NotifyHandleOfDataAvailable()789 void QuicChromiumClientStream::NotifyHandleOfDataAvailable() {
790 if (handle_)
791 handle_->OnDataAvailable();
792 }
793
DisableConnectionMigrationToCellularNetwork()794 void QuicChromiumClientStream::DisableConnectionMigrationToCellularNetwork() {
795 can_migrate_to_cellular_network_ = false;
796 }
797
IsFirstStream()798 bool QuicChromiumClientStream::IsFirstStream() {
799 return id() == quic::QuicUtils::GetFirstBidirectionalStreamId(
800 quic_version_, quic::Perspective::IS_CLIENT);
801 }
802
803 } // namespace net
804