• 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   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