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 // TODO(https://crbug.com/1335423): Change to DCHECK() or remove after bug is
105 // fixed.
106 CHECK(read_body_buffer_);
107 CHECK_GT(read_body_buffer_len_, 0);
108
109 int rv = stream_->Read(read_body_buffer_, read_body_buffer_len_);
110 if (rv == ERR_IO_PENDING)
111 return; // Spurrious, likely because of trailers?
112
113 read_body_buffer_ = nullptr;
114 read_body_buffer_len_ = 0;
115 ResetAndRun(std::move(read_body_callback_), rv);
116 }
117
OnCanWrite()118 void QuicChromiumClientStream::Handle::OnCanWrite() {
119 if (!write_callback_)
120 return;
121
122 ResetAndRun(std::move(write_callback_), OK);
123 }
124
OnClose()125 void QuicChromiumClientStream::Handle::OnClose() {
126 if (net_error_ == ERR_UNEXPECTED) {
127 if (stream_error() == quic::QUIC_STREAM_NO_ERROR &&
128 connection_error() == quic::QUIC_NO_ERROR && fin_sent() &&
129 fin_received()) {
130 net_error_ = ERR_CONNECTION_CLOSED;
131 } else {
132 net_error_ = ERR_QUIC_PROTOCOL_ERROR;
133 }
134 }
135 base::UmaHistogramSparse("Net.QuicChromiumClientStream.HandleOnCloseNetError",
136 -net_error_);
137 base::UmaHistogramSparse(
138 "Net.QuicChromiumClientStream.HandleOnCloseStreamError", stream_error());
139 base::UmaHistogramSparse(
140 "Net.QuicChromiumClientStream.HandleOnCloseConnectionError",
141 connection_error());
142 OnError(net_error_);
143 }
144
OnError(int error)145 void QuicChromiumClientStream::Handle::OnError(int error) {
146 net_error_ = error;
147 if (stream_)
148 SaveState();
149 stream_ = nullptr;
150
151 // Post a task to invoke the callbacks to ensure that there is no reentrancy.
152 // A ScopedPacketFlusher might cause an error which closes the stream under
153 // the call stack of the owner of the handle.
154 base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
155 FROM_HERE,
156 base::BindOnce(&QuicChromiumClientStream::Handle::InvokeCallbacksOnClose,
157 weak_factory_.GetWeakPtr(), error));
158 }
159
InvokeCallbacksOnClose(int error)160 void QuicChromiumClientStream::Handle::InvokeCallbacksOnClose(int error) {
161 // Invoking a callback may cause |this| to be deleted. If this happens, no
162 // more callbacks should be invoked. Guard against this by holding a WeakPtr
163 // to |this| and ensuring it's still valid.
164 auto guard(weak_factory_.GetWeakPtr());
165 for (auto* callback :
166 {&read_headers_callback_, &read_body_callback_, &write_callback_}) {
167 if (*callback)
168 ResetAndRun(std::move(*callback), error);
169 if (!guard.get())
170 return;
171 }
172 }
173
ReadInitialHeaders(spdy::Http2HeaderBlock * header_block,CompletionOnceCallback callback)174 int QuicChromiumClientStream::Handle::ReadInitialHeaders(
175 spdy::Http2HeaderBlock* header_block,
176 CompletionOnceCallback callback) {
177 ScopedBoolSaver saver(&may_invoke_callbacks_, false);
178 if (!stream_)
179 return net_error_;
180
181 // Check Early Hints first.
182 int rv = stream_->DeliverEarlyHints(header_block);
183 if (rv != ERR_IO_PENDING) {
184 return rv;
185 }
186
187 rv = stream_->DeliverInitialHeaders(header_block);
188 if (rv != ERR_IO_PENDING) {
189 return rv;
190 }
191
192 read_headers_buffer_ = header_block;
193 DCHECK(!read_headers_callback_);
194 SetCallback(std::move(callback), &read_headers_callback_);
195 return ERR_IO_PENDING;
196 }
197
ReadBody(IOBuffer * buffer,int buffer_len,CompletionOnceCallback callback)198 int QuicChromiumClientStream::Handle::ReadBody(
199 IOBuffer* buffer,
200 int buffer_len,
201 CompletionOnceCallback callback) {
202 ScopedBoolSaver saver(&may_invoke_callbacks_, false);
203 if (IsDoneReading())
204 return OK;
205
206 if (!stream_)
207 return net_error_;
208
209 int rv = stream_->Read(buffer, buffer_len);
210 if (rv != ERR_IO_PENDING)
211 return rv;
212
213 // TODO(https://crbug.com/1335423): Change to DCHECK() or remove after bug is
214 // fixed.
215 CHECK(buffer);
216 CHECK_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
OnPromiseHeaderList(quic::QuicStreamId promised_id,size_t frame_len,const quic::QuicHeaderList & header_list)381 void QuicChromiumClientStream::Handle::OnPromiseHeaderList(
382 quic::QuicStreamId promised_id,
383 size_t frame_len,
384 const quic::QuicHeaderList& header_list) {
385 stream_->OnPromiseHeaderList(promised_id, frame_len, header_list);
386 }
387
can_migrate_to_cellular_network()388 bool QuicChromiumClientStream::Handle::can_migrate_to_cellular_network() {
389 if (!stream_)
390 return false;
391 return stream_->can_migrate_to_cellular_network();
392 }
393
net_log() const394 const NetLogWithSource& QuicChromiumClientStream::Handle::net_log() const {
395 return net_log_;
396 }
397
SaveState()398 void 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();
410 }
411
SetCallback(CompletionOnceCallback new_callback,CompletionOnceCallback * callback)412 void QuicChromiumClientStream::Handle::SetCallback(
413 CompletionOnceCallback new_callback,
414 CompletionOnceCallback* callback) {
415 // TODO(rch): Convert this to a DCHECK once we ensure the API is stable and
416 // bug free.
417 CHECK(!may_invoke_callbacks_);
418 *callback = std::move(new_callback);
419 }
420
ResetAndRun(CompletionOnceCallback callback,int rv)421 void QuicChromiumClientStream::Handle::ResetAndRun(
422 CompletionOnceCallback callback,
423 int rv) {
424 // TODO(rch): Convert this to a DCHECK once we ensure the API is stable and
425 // bug free.
426 CHECK(may_invoke_callbacks_);
427 std::move(callback).Run(rv);
428 }
429
HandleIOComplete(int rv)430 int 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
436 if (stream_error_ == quic::QUIC_STREAM_NO_ERROR &&
437 connection_error_ == quic::QUIC_NO_ERROR && fin_sent_ && fin_received_) {
438 return rv;
439 }
440
441 return net_error_;
442 }
443
SetRequestIdempotency(Idempotency idempotency)444 void QuicChromiumClientStream::Handle::SetRequestIdempotency(
445 Idempotency idempotency) {
446 idempotency_ = idempotency;
447 }
448
GetRequestIdempotency() const449 Idempotency QuicChromiumClientStream::Handle::GetRequestIdempotency() const {
450 return idempotency_;
451 }
452
QuicChromiumClientStream(quic::QuicStreamId id,quic::QuicSpdyClientSessionBase * session,quic::StreamType type,const NetLogWithSource & net_log,const NetworkTrafficAnnotationTag & traffic_annotation)453 QuicChromiumClientStream::QuicChromiumClientStream(
454 quic::QuicStreamId id,
455 quic::QuicSpdyClientSessionBase* session,
456 quic::StreamType type,
457 const NetLogWithSource& net_log,
458 const NetworkTrafficAnnotationTag& traffic_annotation)
459 : quic::QuicSpdyStream(id, session, type),
460 net_log_(net_log),
461 session_(session),
462 quic_version_(session->connection()->transport_version()) {}
463
QuicChromiumClientStream(quic::PendingStream * pending,quic::QuicSpdyClientSessionBase * session,const NetLogWithSource & net_log,const NetworkTrafficAnnotationTag & traffic_annotation)464 QuicChromiumClientStream::QuicChromiumClientStream(
465 quic::PendingStream* pending,
466 quic::QuicSpdyClientSessionBase* session,
467 const NetLogWithSource& net_log,
468 const NetworkTrafficAnnotationTag& traffic_annotation)
469 : quic::QuicSpdyStream(pending, session),
470 net_log_(net_log),
471 session_(session),
472 quic_version_(session->connection()->transport_version()) {}
473
~QuicChromiumClientStream()474 QuicChromiumClientStream::~QuicChromiumClientStream() {
475 if (handle_)
476 handle_->OnClose();
477 }
478
OnInitialHeadersComplete(bool fin,size_t frame_len,const quic::QuicHeaderList & header_list)479 void QuicChromiumClientStream::OnInitialHeadersComplete(
480 bool fin,
481 size_t frame_len,
482 const quic::QuicHeaderList& header_list) {
483 DCHECK(!initial_headers_arrived_);
484 quic::QuicSpdyStream::OnInitialHeadersComplete(fin, frame_len, header_list);
485
486 spdy::Http2HeaderBlock header_block;
487 int64_t length = -1;
488 if (!quic::SpdyUtils::CopyAndValidateHeaders(header_list, &length,
489 &header_block)) {
490 DLOG(ERROR) << "Failed to parse header list: " << header_list.DebugString();
491 ConsumeHeaderList();
492 Reset(quic::QUIC_BAD_APPLICATION_PAYLOAD);
493 return;
494 }
495
496 // 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.
499 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 }
507
508 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 }
513
514 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();
524 }
525 return;
526 }
527
528 ConsumeHeaderList();
529 session_->OnInitialHeadersComplete(id(), header_block);
530
531 // Buffer the headers and deliver them when the handle arrives.
532 initial_headers_arrived_ = true;
533 initial_headers_ = std::move(header_block);
534 initial_headers_frame_len_ = frame_len;
535
536 if (handle_) {
537 // The handle will be notified of the headers via a posted task.
538 NotifyHandleOfInitialHeadersAvailableLater();
539 }
540 }
541
OnTrailingHeadersComplete(bool fin,size_t frame_len,const quic::QuicHeaderList & header_list)542 void QuicChromiumClientStream::OnTrailingHeadersComplete(
543 bool fin,
544 size_t frame_len,
545 const quic::QuicHeaderList& header_list) {
546 quic::QuicSpdyStream::OnTrailingHeadersComplete(fin, frame_len, header_list);
547 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 }
552 }
553
OnPromiseHeaderList(quic::QuicStreamId promised_id,size_t frame_len,const quic::QuicHeaderList & header_list)554 void QuicChromiumClientStream::OnPromiseHeaderList(
555 quic::QuicStreamId promised_id,
556 size_t frame_len,
557 const quic::QuicHeaderList& header_list) {
558 spdy::Http2HeaderBlock promise_headers;
559 int64_t content_length = -1;
560 if (!quic::SpdyUtils::CopyAndValidateHeaders(header_list, &content_length,
561 &promise_headers)) {
562 DLOG(ERROR) << "Failed to parse header list: " << header_list.DebugString();
563 ConsumeHeaderList();
564 Reset(quic::QUIC_BAD_APPLICATION_PAYLOAD);
565 return;
566 }
567 ConsumeHeaderList();
568
569 session_->HandlePromised(id(), promised_id, promise_headers);
570 }
571
OnBodyAvailable()572 void QuicChromiumClientStream::OnBodyAvailable() {
573 if (!FinishedReadingHeaders() || !headers_delivered_) {
574 // Buffer the data in the sequencer until the headers have been read.
575 return;
576 }
577
578 if (!HasBytesToRead() && !FinishedReadingTrailers()) {
579 // If there is no data to read, wait until either FIN is received or
580 // trailers are delivered.
581 return;
582 }
583
584 // The handle will read the data via a posted task, and
585 // will be able to, potentially, read all data which has queued up.
586 if (handle_)
587 NotifyHandleOfDataAvailableLater();
588 }
589
OnClose()590 void QuicChromiumClientStream::OnClose() {
591 if (handle_) {
592 handle_->OnClose();
593 handle_ = nullptr;
594 }
595 quic::QuicStream::OnClose();
596 }
597
OnCanWrite()598 void QuicChromiumClientStream::OnCanWrite() {
599 quic::QuicStream::OnCanWrite();
600
601 if (!HasBufferedData() && handle_)
602 handle_->OnCanWrite();
603 }
604
WriteHeaders(spdy::Http2HeaderBlock header_block,bool fin,quiche::QuicheReferenceCountedPointer<quic::QuicAckListenerInterface> ack_listener)605 size_t QuicChromiumClientStream::WriteHeaders(
606 spdy::Http2HeaderBlock header_block,
607 bool fin,
608 quiche::QuicheReferenceCountedPointer<quic::QuicAckListenerInterface>
609 ack_listener) {
610 if (!session()->OneRttKeysAvailable()) {
611 auto entry = header_block.find(":method");
612 DCHECK(entry != header_block.end());
613 DCHECK(
614 entry->second != "POST" ||
615 (handle_ != nullptr && handle_->GetRequestIdempotency() == IDEMPOTENT));
616 }
617 net_log_.AddEvent(
618 NetLogEventType::QUIC_CHROMIUM_CLIENT_STREAM_SEND_REQUEST_HEADERS,
619 [&](NetLogCaptureMode capture_mode) {
620 return QuicRequestNetLogParams(id(), &header_block, priority(),
621 capture_mode);
622 });
623 size_t len = quic::QuicSpdyStream::WriteHeaders(std::move(header_block), fin,
624 std::move(ack_listener));
625 initial_headers_sent_ = true;
626 return len;
627 }
628
WriteStreamData(absl::string_view data,bool fin)629 bool QuicChromiumClientStream::WriteStreamData(absl::string_view data,
630 bool fin) {
631 // Writes the data, or buffers it.
632 WriteOrBufferBody(data, fin);
633 return !HasBufferedData(); // Was all data written?
634 }
635
WritevStreamData(const std::vector<scoped_refptr<IOBuffer>> & buffers,const std::vector<int> & lengths,bool fin)636 bool QuicChromiumClientStream::WritevStreamData(
637 const std::vector<scoped_refptr<IOBuffer>>& buffers,
638 const std::vector<int>& lengths,
639 bool fin) {
640 // Writes the data, or buffers it.
641 for (size_t i = 0; i < buffers.size(); ++i) {
642 bool is_fin = fin && (i == buffers.size() - 1);
643 absl::string_view string_data(buffers[i]->data(), lengths[i]);
644 WriteOrBufferBody(string_data, is_fin);
645 }
646 return !HasBufferedData(); // Was all data written?
647 }
648
649 std::unique_ptr<QuicChromiumClientStream::Handle>
CreateHandle()650 QuicChromiumClientStream::CreateHandle() {
651 DCHECK(!handle_);
652 auto handle = base::WrapUnique(new QuicChromiumClientStream::Handle(this));
653 handle_ = handle.get();
654
655 // Should this perhaps be via PostTask to make reasoning simpler?
656 if (initial_headers_arrived_) {
657 handle_->OnInitialHeadersAvailable();
658 }
659
660 return handle;
661 }
662
ClearHandle()663 void QuicChromiumClientStream::ClearHandle() {
664 handle_ = nullptr;
665 }
666
OnError(int error)667 void QuicChromiumClientStream::OnError(int error) {
668 if (handle_) {
669 QuicChromiumClientStream::Handle* handle = handle_;
670 handle_ = nullptr;
671 handle->OnError(error);
672 }
673 }
674
Read(IOBuffer * buf,int buf_len)675 int QuicChromiumClientStream::Read(IOBuffer* buf, int buf_len) {
676 // TODO(https://crbug.com/1335423): Change to DCHECK() or remove after bug
677 // is fixed.
678 CHECK_GT(buf_len, 0);
679 CHECK(buf->data());
680
681 if (IsDoneReading())
682 return 0; // EOF
683
684 if (!HasBytesToRead())
685 return ERR_IO_PENDING;
686
687 iovec iov;
688 iov.iov_base = buf->data();
689 iov.iov_len = buf_len;
690 size_t bytes_read = Readv(&iov, 1);
691 // Since HasBytesToRead is true, Readv() must of read some data.
692 DCHECK_NE(0u, bytes_read);
693 return bytes_read;
694 }
695
NotifyHandleOfInitialHeadersAvailableLater()696 void QuicChromiumClientStream::NotifyHandleOfInitialHeadersAvailableLater() {
697 DCHECK(handle_);
698 base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
699 FROM_HERE,
700 base::BindOnce(
701 &QuicChromiumClientStream::NotifyHandleOfInitialHeadersAvailable,
702 weak_factory_.GetWeakPtr()));
703 }
704
NotifyHandleOfInitialHeadersAvailable()705 void QuicChromiumClientStream::NotifyHandleOfInitialHeadersAvailable() {
706 if (!handle_)
707 return;
708
709 if (!headers_delivered_)
710 handle_->OnInitialHeadersAvailable();
711 }
712
NotifyHandleOfTrailingHeadersAvailableLater()713 void QuicChromiumClientStream::NotifyHandleOfTrailingHeadersAvailableLater() {
714 DCHECK(handle_);
715 base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
716 FROM_HERE,
717 base::BindOnce(
718 &QuicChromiumClientStream::NotifyHandleOfTrailingHeadersAvailable,
719 weak_factory_.GetWeakPtr()));
720 }
721
NotifyHandleOfTrailingHeadersAvailable()722 void QuicChromiumClientStream::NotifyHandleOfTrailingHeadersAvailable() {
723 if (!handle_)
724 return;
725
726 // If trailers aren't decompressed it means that trailers are invalid
727 // (e.g., contain ":status" field). Don't notify to the handle if trailers
728 // aren't decompressed since the stream will be closed and
729 // `headers_delivered_` won't become true.
730 if (!trailers_decompressed())
731 return;
732
733 // Notify only after the handle reads initial headers.
734 if (!headers_delivered_)
735 return;
736
737 // Post an async task to notify handle of the FIN flag.
738 NotifyHandleOfDataAvailableLater();
739 handle_->OnTrailingHeadersAvailable();
740 }
741
DeliverEarlyHints(spdy::Http2HeaderBlock * headers)742 int QuicChromiumClientStream::DeliverEarlyHints(
743 spdy::Http2HeaderBlock* headers) {
744 if (early_hints_.empty()) {
745 return ERR_IO_PENDING;
746 }
747
748 DCHECK(!headers_delivered_);
749
750 EarlyHints& hints = early_hints_.front();
751 *headers = std::move(hints.headers);
752 size_t frame_len = hints.frame_len;
753 early_hints_.pop_front();
754
755 net_log_.AddEvent(
756 NetLogEventType::
757 QUIC_CHROMIUM_CLIENT_STREAM_READ_EARLY_HINTS_RESPONSE_HEADERS,
758 [&](NetLogCaptureMode capture_mode) {
759 return QuicResponseNetLogParams(id(), fin_received(), headers,
760 capture_mode);
761 });
762
763 return frame_len;
764 }
765
DeliverInitialHeaders(spdy::Http2HeaderBlock * headers)766 int QuicChromiumClientStream::DeliverInitialHeaders(
767 spdy::Http2HeaderBlock* headers) {
768 if (!initial_headers_arrived_) {
769 return ERR_IO_PENDING;
770 }
771
772 headers_delivered_ = true;
773
774 if (initial_headers_.empty()) {
775 return ERR_INVALID_RESPONSE;
776 }
777
778 net_log_.AddEvent(
779 NetLogEventType::QUIC_CHROMIUM_CLIENT_STREAM_READ_RESPONSE_HEADERS,
780 [&](NetLogCaptureMode capture_mode) {
781 return QuicResponseNetLogParams(id(), fin_received(), &initial_headers_,
782 capture_mode);
783 });
784
785 *headers = std::move(initial_headers_);
786 return initial_headers_frame_len_;
787 }
788
DeliverTrailingHeaders(spdy::Http2HeaderBlock * headers,int * frame_len)789 bool QuicChromiumClientStream::DeliverTrailingHeaders(
790 spdy::Http2HeaderBlock* headers,
791 int* frame_len) {
792 if (received_trailers().empty())
793 return false;
794
795 net_log_.AddEvent(
796 NetLogEventType::QUIC_CHROMIUM_CLIENT_STREAM_READ_RESPONSE_TRAILERS,
797 [&](NetLogCaptureMode capture_mode) {
798 return QuicResponseNetLogParams(id(), fin_received(),
799 &received_trailers(), capture_mode);
800 });
801
802 *headers = received_trailers().Clone();
803 *frame_len = trailing_headers_frame_len_;
804
805 MarkTrailersConsumed();
806 return true;
807 }
808
NotifyHandleOfDataAvailableLater()809 void QuicChromiumClientStream::NotifyHandleOfDataAvailableLater() {
810 DCHECK(handle_);
811 base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
812 FROM_HERE,
813 base::BindOnce(&QuicChromiumClientStream::NotifyHandleOfDataAvailable,
814 weak_factory_.GetWeakPtr()));
815 }
816
NotifyHandleOfDataAvailable()817 void QuicChromiumClientStream::NotifyHandleOfDataAvailable() {
818 if (handle_)
819 handle_->OnDataAvailable();
820 }
821
DisableConnectionMigrationToCellularNetwork()822 void QuicChromiumClientStream::DisableConnectionMigrationToCellularNetwork() {
823 can_migrate_to_cellular_network_ = false;
824 }
825
IsFirstStream()826 bool QuicChromiumClientStream::IsFirstStream() {
827 return id() == quic::QuicUtils::GetFirstBidirectionalStreamId(
828 quic_version_, quic::Perspective::IS_CLIENT);
829 }
830
831 } // namespace net
832