• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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