• 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 <string_view>
8 #include <utility>
9 
10 #include "base/functional/bind.h"
11 #include "base/functional/callback_helpers.h"
12 #include "base/location.h"
13 #include "base/memory/ptr_util.h"
14 #include "base/memory/raw_ptr.h"
15 #include "base/memory/scoped_refptr.h"
16 #include "base/metrics/histogram_functions.h"
17 #include "base/not_fatal_until.h"
18 #include "base/task/single_thread_task_runner.h"
19 #include "net/base/io_buffer.h"
20 #include "net/base/net_errors.h"
21 #include "net/base/url_util.h"
22 #include "net/http/http_status_code.h"
23 #include "net/log/net_log_event_type.h"
24 #include "net/quic/quic_chromium_client_session.h"
25 #include "net/quic/quic_http_utils.h"
26 #include "net/spdy/spdy_log_util.h"
27 #include "net/third_party/quiche/src/quiche/quic/core/http/quic_spdy_session.h"
28 #include "net/third_party/quiche/src/quiche/quic/core/http/spdy_utils.h"
29 #include "net/third_party/quiche/src/quiche/quic/core/quic_utils.h"
30 #include "net/third_party/quiche/src/quiche/quic/core/quic_write_blocked_list.h"
31 
32 namespace net {
33 namespace {
34 // Sets a boolean to a value, and restores it to the previous value once
35 // the saver goes out of scope.
36 class ScopedBoolSaver {
37  public:
ScopedBoolSaver(bool * var,bool new_val)38   ScopedBoolSaver(bool* var, bool new_val) : var_(var), old_val_(*var) {
39     *var_ = new_val;
40   }
41 
~ScopedBoolSaver()42   ~ScopedBoolSaver() { *var_ = old_val_; }
43 
44  private:
45   raw_ptr<bool> var_;
46   bool old_val_;
47 };
48 }  // namespace
49 
Handle(QuicChromiumClientStream * stream)50 QuicChromiumClientStream::Handle::Handle(QuicChromiumClientStream* stream)
51     : stream_(stream), net_log_(stream->net_log()) {
52   SaveState();
53 }
54 
~Handle()55 QuicChromiumClientStream::Handle::~Handle() {
56   if (stream_) {
57     stream_->ClearHandle();
58     // TODO(rch): If stream_ is still valid, it should probably be Reset()
59     // so that it does not leak.
60     // stream_->Reset(quic::QUIC_STREAM_CANCELLED);
61   }
62 }
63 
OnEarlyHintsAvailable()64 void QuicChromiumClientStream::Handle::OnEarlyHintsAvailable() {
65   if (first_early_hints_time_.is_null())
66     first_early_hints_time_ = base::TimeTicks::Now();
67 
68   if (!read_headers_callback_)
69     return;  // Wait for ReadInitialHeaders to be called.
70 
71   DCHECK(read_headers_buffer_);
72   int rv = stream_->DeliverEarlyHints(read_headers_buffer_);
73   DCHECK_NE(ERR_IO_PENDING, rv);
74 
75   ResetAndRun(std::move(read_headers_callback_), rv);
76 }
77 
OnInitialHeadersAvailable()78 void QuicChromiumClientStream::Handle::OnInitialHeadersAvailable() {
79   if (headers_received_start_time_.is_null())
80     headers_received_start_time_ = base::TimeTicks::Now();
81 
82   if (!read_headers_callback_)
83     return;  // Wait for ReadInitialHeaders to be called.
84 
85   int rv = stream_->DeliverInitialHeaders(read_headers_buffer_);
86   DCHECK_NE(ERR_IO_PENDING, rv);
87 
88   ResetAndRun(std::move(read_headers_callback_), rv);
89 }
90 
OnTrailingHeadersAvailable()91 void QuicChromiumClientStream::Handle::OnTrailingHeadersAvailable() {
92   if (!read_headers_callback_)
93     return;  // Wait for ReadInitialHeaders to be called.
94 
95   int rv = ERR_QUIC_PROTOCOL_ERROR;
96   if (!stream_->DeliverTrailingHeaders(read_headers_buffer_, &rv))
97     rv = ERR_QUIC_PROTOCOL_ERROR;
98 
99   base::UmaHistogramBoolean(
100       "Net.QuicChromiumClientStream.TrailingHeadersProcessSuccess", rv >= 0);
101   ResetAndRun(std::move(read_headers_callback_), rv);
102 }
103 
OnDataAvailable()104 void QuicChromiumClientStream::Handle::OnDataAvailable() {
105   if (!read_body_callback_)
106     return;  // Wait for ReadBody to be called.
107 
108   DCHECK(read_body_buffer_);
109   DCHECK_GT(read_body_buffer_len_, 0);
110 
111   int rv = stream_->Read(read_body_buffer_.get(), read_body_buffer_len_);
112   if (rv == ERR_IO_PENDING)
113     return;  // Spurrious, likely because of trailers?
114 
115   read_body_buffer_ = nullptr;
116   read_body_buffer_len_ = 0;
117   ResetAndRun(std::move(read_body_callback_), rv);
118 }
119 
OnCanWrite()120 void QuicChromiumClientStream::Handle::OnCanWrite() {
121   if (!write_callback_)
122     return;
123 
124   ResetAndRun(std::move(write_callback_), OK);
125 }
126 
OnClose()127 void QuicChromiumClientStream::Handle::OnClose() {
128   if (net_error_ == ERR_UNEXPECTED) {
129     if (stream_error() == quic::QUIC_STREAM_NO_ERROR &&
130         connection_error() == quic::QUIC_NO_ERROR && fin_sent() &&
131         fin_received()) {
132       net_error_ = ERR_CONNECTION_CLOSED;
133     } else {
134       net_error_ = ERR_QUIC_PROTOCOL_ERROR;
135     }
136   }
137   base::UmaHistogramSparse("Net.QuicChromiumClientStream.HandleOnCloseNetError",
138                            -net_error_);
139   base::UmaHistogramSparse(
140       "Net.QuicChromiumClientStream.HandleOnCloseStreamError", stream_error());
141   base::UmaHistogramSparse(
142       "Net.QuicChromiumClientStream.HandleOnCloseConnectionError",
143       connection_error());
144   OnError(net_error_);
145 }
146 
OnError(int error)147 void QuicChromiumClientStream::Handle::OnError(int error) {
148   net_error_ = error;
149   if (stream_)
150     SaveState();
151   stream_ = nullptr;
152 
153   // Post a task to invoke the callbacks to ensure that there is no reentrancy.
154   // A ScopedPacketFlusher might cause an error which closes the stream under
155   // the call stack of the owner of the handle.
156   base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
157       FROM_HERE,
158       base::BindOnce(&QuicChromiumClientStream::Handle::InvokeCallbacksOnClose,
159                      weak_factory_.GetWeakPtr(), error));
160 }
161 
InvokeCallbacksOnClose(int error)162 void QuicChromiumClientStream::Handle::InvokeCallbacksOnClose(int error) {
163   // Invoking a callback may cause |this| to be deleted. If this happens, no
164   // more callbacks should be invoked. Guard against this by holding a WeakPtr
165   // to |this| and ensuring it's still valid.
166 
167   // Free read buffer, if present. Reads are synchronous and pull-based, so
168   // there is no ongoing asynchronous read that could write to the buffer.
169   read_body_buffer_ = nullptr;
170   read_body_buffer_len_ = 0;
171 
172   auto guard(weak_factory_.GetWeakPtr());
173   for (auto* callback :
174        {&read_headers_callback_, &read_body_callback_, &write_callback_}) {
175     if (*callback)
176       ResetAndRun(std::move(*callback), error);
177     if (!guard.get())
178       return;
179   }
180 }
181 
ReadInitialHeaders(quiche::HttpHeaderBlock * header_block,CompletionOnceCallback callback)182 int QuicChromiumClientStream::Handle::ReadInitialHeaders(
183     quiche::HttpHeaderBlock* header_block,
184     CompletionOnceCallback callback) {
185   ScopedBoolSaver saver(&may_invoke_callbacks_, false);
186   if (!stream_)
187     return net_error_;
188 
189   // Check Early Hints first.
190   int rv = stream_->DeliverEarlyHints(header_block);
191   if (rv != ERR_IO_PENDING) {
192     return rv;
193   }
194 
195   rv = stream_->DeliverInitialHeaders(header_block);
196   if (rv != ERR_IO_PENDING) {
197     return rv;
198   }
199 
200   read_headers_buffer_ = header_block;
201   DCHECK(!read_headers_callback_);
202   SetCallback(std::move(callback), &read_headers_callback_);
203   return ERR_IO_PENDING;
204 }
205 
ReadBody(IOBuffer * buffer,int buffer_len,CompletionOnceCallback callback)206 int QuicChromiumClientStream::Handle::ReadBody(
207     IOBuffer* buffer,
208     int buffer_len,
209     CompletionOnceCallback callback) {
210   ScopedBoolSaver saver(&may_invoke_callbacks_, false);
211   if (IsDoneReading())
212     return OK;
213 
214   if (!stream_)
215     return net_error_;
216 
217   if (stream_->read_side_closed()) {
218     return OK;
219   }
220 
221   int rv = stream_->Read(buffer, buffer_len);
222   if (rv != ERR_IO_PENDING)
223     return rv;
224 
225   DCHECK(buffer);
226   DCHECK_GT(buffer_len, 0);
227 
228   SetCallback(std::move(callback), &read_body_callback_);
229   read_body_buffer_ = buffer;
230   read_body_buffer_len_ = buffer_len;
231   return ERR_IO_PENDING;
232 }
233 
ReadTrailingHeaders(quiche::HttpHeaderBlock * header_block,CompletionOnceCallback callback)234 int QuicChromiumClientStream::Handle::ReadTrailingHeaders(
235     quiche::HttpHeaderBlock* header_block,
236     CompletionOnceCallback callback) {
237   ScopedBoolSaver saver(&may_invoke_callbacks_, false);
238   if (!stream_)
239     return net_error_;
240 
241   int frame_len = 0;
242   if (stream_->DeliverTrailingHeaders(header_block, &frame_len))
243     return frame_len;
244 
245   read_headers_buffer_ = header_block;
246   SetCallback(std::move(callback), &read_headers_callback_);
247   return ERR_IO_PENDING;
248 }
249 
WriteHeaders(quiche::HttpHeaderBlock header_block,bool fin,quiche::QuicheReferenceCountedPointer<quic::QuicAckListenerInterface> ack_notifier_delegate)250 int QuicChromiumClientStream::Handle::WriteHeaders(
251     quiche::HttpHeaderBlock header_block,
252     bool fin,
253     quiche::QuicheReferenceCountedPointer<quic::QuicAckListenerInterface>
254         ack_notifier_delegate) {
255   if (!stream_)
256     return 0;
257   return HandleIOComplete(stream_->WriteHeaders(std::move(header_block), fin,
258                                                 ack_notifier_delegate));
259 }
260 
WriteStreamData(std::string_view data,bool fin,CompletionOnceCallback callback)261 int QuicChromiumClientStream::Handle::WriteStreamData(
262     std::string_view data,
263     bool fin,
264     CompletionOnceCallback callback) {
265   ScopedBoolSaver saver(&may_invoke_callbacks_, false);
266   if (!stream_)
267     return net_error_;
268 
269   if (stream_->WriteStreamData(data, fin)) {
270     return HandleIOComplete(OK);
271   }
272 
273   SetCallback(std::move(callback), &write_callback_);
274   return ERR_IO_PENDING;
275 }
276 
WritevStreamData(const std::vector<scoped_refptr<IOBuffer>> & buffers,const std::vector<int> & lengths,bool fin,CompletionOnceCallback callback)277 int QuicChromiumClientStream::Handle::WritevStreamData(
278     const std::vector<scoped_refptr<IOBuffer>>& buffers,
279     const std::vector<int>& lengths,
280     bool fin,
281     CompletionOnceCallback callback) {
282   ScopedBoolSaver saver(&may_invoke_callbacks_, false);
283   if (!stream_)
284     return net_error_;
285 
286   if (stream_->WritevStreamData(buffers, lengths, fin))
287     return HandleIOComplete(OK);
288 
289   SetCallback(std::move(callback), &write_callback_);
290   return ERR_IO_PENDING;
291 }
292 
WriteConnectUdpPayload(std::string_view packet)293 int QuicChromiumClientStream::Handle::WriteConnectUdpPayload(
294     std::string_view packet) {
295   ScopedBoolSaver saver(&may_invoke_callbacks_, false);
296   if (!stream_) {
297     return net_error_;
298   }
299 
300   base::UmaHistogramBoolean(kHttp3DatagramDroppedHistogram,
301                             !stream_->SupportsH3Datagram());
302   if (!stream_->SupportsH3Datagram()) {
303     DLOG(WARNING)
304         << "Dropping datagram because the session has either not received "
305            "settings frame with H3_DATAGRAM yet or received settings that "
306            "indicate datagrams are not supported (i.e., H3_DATAGRAM=0).";
307     return OK;
308   }
309   // Set Context ID to zero as per RFC 9298
310   // (https://datatracker.ietf.org/doc/html/rfc9298#name-http-datagram-payload-forma)
311   // and copy packet data.
312   std::string http_payload;
313   http_payload.resize(1 + packet.size());
314   http_payload[0] = 0;
315   memcpy(&http_payload[1], packet.data(), packet.size());
316 
317   // Attempt to send the HTTP payload as a datagram over the stream.
318   quic::MessageStatus message_status = stream_->SendHttp3Datagram(http_payload);
319 
320   // If the attempt was successful or blocked (e.g., due to buffer
321   // constraints), proceed to handle the I/O completion with an OK status.
322   if (message_status == quic::MessageStatus::MESSAGE_STATUS_SUCCESS ||
323       message_status == quic::MessageStatus::MESSAGE_STATUS_BLOCKED) {
324     return HandleIOComplete(OK);
325   }
326   // If the attempt failed due to a unsupported feature, internal error, or
327   // unexpected condition (encryption not established or message too large),
328   // reset the stream and close the connection.
329   else {
330     // These two errors should not be possible here.
331     DCHECK(message_status !=
332            quic::MessageStatus::MESSAGE_STATUS_ENCRYPTION_NOT_ESTABLISHED);
333     DCHECK(message_status != quic::MessageStatus::MESSAGE_STATUS_TOO_LARGE);
334     DLOG(ERROR) << "Failed to send Http3 Datagram on " << stream_->id();
335     stream_->Reset(quic::QUIC_STREAM_CANCELLED);
336     return ERR_CONNECTION_CLOSED;
337   }
338 }
339 
Read(IOBuffer * buf,int buf_len)340 int QuicChromiumClientStream::Handle::Read(IOBuffer* buf, int buf_len) {
341   if (!stream_)
342     return net_error_;
343   return stream_->Read(buf, buf_len);
344 }
345 
OnFinRead()346 void QuicChromiumClientStream::Handle::OnFinRead() {
347   read_headers_callback_.Reset();
348   if (stream_)
349     stream_->OnFinRead();
350 }
351 
352 void QuicChromiumClientStream::Handle::
DisableConnectionMigrationToCellularNetwork()353     DisableConnectionMigrationToCellularNetwork() {
354   if (stream_)
355     stream_->DisableConnectionMigrationToCellularNetwork();
356 }
357 
SetPriority(const quic::QuicStreamPriority & priority)358 void QuicChromiumClientStream::Handle::SetPriority(
359     const quic::QuicStreamPriority& priority) {
360   if (stream_) {
361     stream_->SetPriority(priority);
362   }
363 }
364 
Reset(quic::QuicRstStreamErrorCode error_code)365 void QuicChromiumClientStream::Handle::Reset(
366     quic::QuicRstStreamErrorCode error_code) {
367   if (stream_)
368     stream_->Reset(error_code);
369 }
370 
RegisterHttp3DatagramVisitor(Http3DatagramVisitor * visitor)371 void QuicChromiumClientStream::Handle::RegisterHttp3DatagramVisitor(
372     Http3DatagramVisitor* visitor) {
373   if (stream_) {
374     stream_->RegisterHttp3DatagramVisitor(visitor);
375   }
376 }
377 
UnregisterHttp3DatagramVisitor()378 void QuicChromiumClientStream::Handle::UnregisterHttp3DatagramVisitor() {
379   if (stream_) {
380     stream_->UnregisterHttp3DatagramVisitor();
381   }
382 }
383 
id() const384 quic::QuicStreamId QuicChromiumClientStream::Handle::id() const {
385   if (!stream_)
386     return id_;
387   return stream_->id();
388 }
389 
connection_error() const390 quic::QuicErrorCode QuicChromiumClientStream::Handle::connection_error() const {
391   if (!stream_)
392     return connection_error_;
393   return stream_->connection_error();
394 }
395 
stream_error() const396 quic::QuicRstStreamErrorCode QuicChromiumClientStream::Handle::stream_error()
397     const {
398   if (!stream_)
399     return stream_error_;
400   return stream_->stream_error();
401 }
402 
connection_wire_error() const403 uint64_t QuicChromiumClientStream::Handle::connection_wire_error() const {
404   if (!stream_) {
405     return connection_wire_error_;
406   }
407   // TODO(crbug.com/40715622): Don't access session. Instead, modify
408   // quic::QuicStream::OnConnectionClosed() to take the wire error code.
409   CHECK(stream_->session());
410   return stream_->session()->wire_error();
411 }
412 
ietf_application_error() const413 uint64_t QuicChromiumClientStream::Handle::ietf_application_error() const {
414   if (!stream_) {
415     return ietf_application_error_;
416   }
417   return stream_->ietf_application_error();
418 }
419 
fin_sent() const420 bool QuicChromiumClientStream::Handle::fin_sent() const {
421   if (!stream_)
422     return fin_sent_;
423   return stream_->fin_sent();
424 }
425 
fin_received() const426 bool QuicChromiumClientStream::Handle::fin_received() const {
427   if (!stream_)
428     return fin_received_;
429   return stream_->fin_received();
430 }
431 
stream_bytes_read() const432 uint64_t QuicChromiumClientStream::Handle::stream_bytes_read() const {
433   if (!stream_)
434     return stream_bytes_read_;
435   return stream_->stream_bytes_read();
436 }
437 
stream_bytes_written() const438 uint64_t QuicChromiumClientStream::Handle::stream_bytes_written() const {
439   if (!stream_)
440     return stream_bytes_written_;
441   return stream_->stream_bytes_written();
442 }
443 
NumBytesConsumed() const444 size_t QuicChromiumClientStream::Handle::NumBytesConsumed() const {
445   if (!stream_)
446     return num_bytes_consumed_;
447   return stream_->sequencer()->NumBytesConsumed();
448 }
449 
HasBytesToRead() const450 bool QuicChromiumClientStream::Handle::HasBytesToRead() const {
451   if (!stream_)
452     return false;
453   return stream_->HasBytesToRead();
454 }
455 
IsDoneReading() const456 bool QuicChromiumClientStream::Handle::IsDoneReading() const {
457   if (!stream_)
458     return is_done_reading_;
459   return stream_->IsDoneReading();
460 }
461 
IsFirstStream() const462 bool QuicChromiumClientStream::Handle::IsFirstStream() const {
463   if (!stream_)
464     return is_first_stream_;
465   return stream_->IsFirstStream();
466 }
467 
can_migrate_to_cellular_network()468 bool QuicChromiumClientStream::Handle::can_migrate_to_cellular_network() {
469   if (!stream_)
470     return false;
471   return stream_->can_migrate_to_cellular_network();
472 }
473 
net_log() const474 const NetLogWithSource& QuicChromiumClientStream::Handle::net_log() const {
475   return net_log_;
476 }
477 
SaveState()478 void QuicChromiumClientStream::Handle::SaveState() {
479   DCHECK(stream_);
480   fin_sent_ = stream_->fin_sent();
481   fin_received_ = stream_->fin_received();
482   num_bytes_consumed_ = stream_->sequencer()->NumBytesConsumed();
483   id_ = stream_->id();
484   connection_error_ = stream_->connection_error();
485   stream_error_ = stream_->stream_error();
486   // TODO(crbug.com/40715622): Don't access stream_->session(). Instead, update
487   // quic::QuicStream::OnConnectionClosed() to take the wire error code.
488   CHECK(stream_->session());
489   connection_wire_error_ = stream_->session()->wire_error();
490   ietf_application_error_ = stream_->ietf_application_error();
491   is_done_reading_ = stream_->IsDoneReading();
492   is_first_stream_ = stream_->IsFirstStream();
493   stream_bytes_read_ = stream_->stream_bytes_read();
494   stream_bytes_written_ = stream_->stream_bytes_written();
495 }
496 
SetCallback(CompletionOnceCallback new_callback,CompletionOnceCallback * callback)497 void QuicChromiumClientStream::Handle::SetCallback(
498     CompletionOnceCallback new_callback,
499     CompletionOnceCallback* callback) {
500   // TODO(rch): Convert this to a DCHECK once we ensure the API is stable and
501   // bug free.
502   CHECK(!may_invoke_callbacks_);
503   *callback = std::move(new_callback);
504 }
505 
ResetAndRun(CompletionOnceCallback callback,int rv)506 void QuicChromiumClientStream::Handle::ResetAndRun(
507     CompletionOnceCallback callback,
508     int rv) {
509   // TODO(rch): Convert this to a DCHECK once we ensure the API is stable and
510   // bug free.
511   CHECK(may_invoke_callbacks_);
512   std::move(callback).Run(rv);
513 }
514 
HandleIOComplete(int rv)515 int QuicChromiumClientStream::Handle::HandleIOComplete(int rv) {
516   // If |stream_| is still valid the stream has not been closed. If the stream
517   // has not been closed, then just return |rv|.
518   if (rv < 0 || stream_)
519     return rv;
520 
521   if (stream_error_ == quic::QUIC_STREAM_NO_ERROR &&
522       connection_error_ == quic::QUIC_NO_ERROR && fin_sent_ && fin_received_) {
523     return rv;
524   }
525 
526   return net_error_;
527 }
528 
SetRequestIdempotency(Idempotency idempotency)529 void QuicChromiumClientStream::Handle::SetRequestIdempotency(
530     Idempotency idempotency) {
531   idempotency_ = idempotency;
532 }
533 
GetRequestIdempotency() const534 Idempotency QuicChromiumClientStream::Handle::GetRequestIdempotency() const {
535   return idempotency_;
536 }
537 
538 quic::QuicPacketLength
GetGuaranteedLargestMessagePayload() const539 QuicChromiumClientStream::Handle::GetGuaranteedLargestMessagePayload() const {
540   if (!stream_) {
541     return 0;
542   }
543   return stream_->GetGuaranteedLargestMessagePayload();
544 }
545 
QuicChromiumClientStream(quic::QuicStreamId id,quic::QuicSpdyClientSessionBase * session,quic::QuicServerId server_id,quic::StreamType type,const NetLogWithSource & net_log,const NetworkTrafficAnnotationTag & traffic_annotation)546 QuicChromiumClientStream::QuicChromiumClientStream(
547     quic::QuicStreamId id,
548     quic::QuicSpdyClientSessionBase* session,
549     quic::QuicServerId server_id,
550     quic::StreamType type,
551     const NetLogWithSource& net_log,
552     const NetworkTrafficAnnotationTag& traffic_annotation)
553     : quic::QuicSpdyStream(id, session, type),
554       net_log_(net_log),
555       session_(session),
556       server_id_(std::move(server_id)),
557       quic_version_(session->connection()->transport_version()) {}
558 
QuicChromiumClientStream(quic::PendingStream * pending,quic::QuicSpdyClientSessionBase * session,quic::QuicServerId server_id,const NetLogWithSource & net_log,const NetworkTrafficAnnotationTag & traffic_annotation)559 QuicChromiumClientStream::QuicChromiumClientStream(
560     quic::PendingStream* pending,
561     quic::QuicSpdyClientSessionBase* session,
562     quic::QuicServerId server_id,
563     const NetLogWithSource& net_log,
564     const NetworkTrafficAnnotationTag& traffic_annotation)
565     : quic::QuicSpdyStream(pending, session),
566       net_log_(net_log),
567       session_(session),
568       server_id_(std::move(server_id)),
569       quic_version_(session->connection()->transport_version()) {}
570 
~QuicChromiumClientStream()571 QuicChromiumClientStream::~QuicChromiumClientStream() {
572   if (handle_)
573     handle_->OnClose();
574 }
575 
OnInitialHeadersComplete(bool fin,size_t frame_len,const quic::QuicHeaderList & header_list)576 void QuicChromiumClientStream::OnInitialHeadersComplete(
577     bool fin,
578     size_t frame_len,
579     const quic::QuicHeaderList& header_list) {
580   DCHECK(!initial_headers_arrived_);
581   quic::QuicSpdyStream::OnInitialHeadersComplete(fin, frame_len, header_list);
582 
583   if (header_decoding_delay().has_value()) {
584     const int64_t delay_in_milliseconds =
585         header_decoding_delay()->ToMilliseconds();
586     base::UmaHistogramTimes("Net.QuicChromiumClientStream.HeaderDecodingDelay",
587                             base::Milliseconds(delay_in_milliseconds));
588     if (IsGoogleHost(server_id_.host())) {
589       base::UmaHistogramTimes(
590           "Net.QuicChromiumClientStream.HeaderDecodingDelayGoogle",
591           base::Milliseconds(delay_in_milliseconds));
592     }
593   }
594 
595   quiche::HttpHeaderBlock header_block;
596   int64_t length = -1;
597   if (!quic::SpdyUtils::CopyAndValidateHeaders(header_list, &length,
598                                                &header_block)) {
599     DLOG(ERROR) << "Failed to parse header list: " << header_list.DebugString();
600     ConsumeHeaderList();
601     Reset(quic::QUIC_BAD_APPLICATION_PAYLOAD);
602     return;
603   }
604 
605   // Handle informational response. If the response is an Early Hints response,
606   // deliver the response to the owner of the handle. Otherwise ignore the
607   // response.
608   int response_code;
609   if (!ParseHeaderStatusCode(header_block, &response_code)) {
610     DLOG(ERROR) << "Received invalid response code: '"
611                 << header_block[":status"].as_string() << "' on stream "
612                 << id();
613     Reset(quic::QUIC_BAD_APPLICATION_PAYLOAD);
614     return;
615   }
616 
617   if (response_code == HTTP_SWITCHING_PROTOCOLS) {
618     DLOG(ERROR) << "Received forbidden 101 response code on stream " << id();
619     Reset(quic::QUIC_BAD_APPLICATION_PAYLOAD);
620     return;
621   }
622 
623   if (response_code >= 100 && response_code < 200) {
624     set_headers_decompressed(false);
625     ConsumeHeaderList();
626     if (response_code == HTTP_EARLY_HINTS) {
627       early_hints_.emplace_back(std::move(header_block), frame_len);
628       if (handle_)
629         handle_->OnEarlyHintsAvailable();
630     } else {
631       DVLOG(1) << "Ignore informational response " << response_code
632                << " on stream" << id();
633     }
634     return;
635   }
636 
637   ConsumeHeaderList();
638 
639   // Buffer the headers and deliver them when the handle arrives.
640   initial_headers_arrived_ = true;
641   initial_headers_ = std::move(header_block);
642   initial_headers_frame_len_ = frame_len;
643 
644   if (handle_) {
645     // The handle will be notified of the headers via a posted task.
646     NotifyHandleOfInitialHeadersAvailableLater();
647   }
648 }
649 
OnTrailingHeadersComplete(bool fin,size_t frame_len,const quic::QuicHeaderList & header_list)650 void QuicChromiumClientStream::OnTrailingHeadersComplete(
651     bool fin,
652     size_t frame_len,
653     const quic::QuicHeaderList& header_list) {
654   quic::QuicSpdyStream::OnTrailingHeadersComplete(fin, frame_len, header_list);
655   trailing_headers_frame_len_ = frame_len;
656   if (handle_) {
657     // The handle will be notified of the headers via a posted task.
658     NotifyHandleOfTrailingHeadersAvailableLater();
659   }
660 }
661 
OnBodyAvailable()662 void QuicChromiumClientStream::OnBodyAvailable() {
663   if (!FinishedReadingHeaders() || !headers_delivered_) {
664     // Buffer the data in the sequencer until the headers have been read.
665     return;
666   }
667 
668   if (!HasBytesToRead() && !FinishedReadingTrailers()) {
669     // If there is no data to read, wait until either FIN is received or
670     // trailers are delivered.
671     return;
672   }
673 
674   // The handle will read the data via a posted task, and
675   // will be able to, potentially, read all data which has queued up.
676   if (handle_)
677     NotifyHandleOfDataAvailableLater();
678 }
679 
OnClose()680 void QuicChromiumClientStream::OnClose() {
681   if (handle_) {
682     handle_->OnClose();
683     handle_ = nullptr;
684   }
685   quic::QuicStream::OnClose();
686 }
687 
OnCanWrite()688 void QuicChromiumClientStream::OnCanWrite() {
689   quic::QuicStream::OnCanWrite();
690 
691   if (!HasBufferedData() && handle_)
692     handle_->OnCanWrite();
693 }
694 
WriteHeaders(quiche::HttpHeaderBlock header_block,bool fin,quiche::QuicheReferenceCountedPointer<quic::QuicAckListenerInterface> ack_listener)695 size_t QuicChromiumClientStream::WriteHeaders(
696     quiche::HttpHeaderBlock header_block,
697     bool fin,
698     quiche::QuicheReferenceCountedPointer<quic::QuicAckListenerInterface>
699         ack_listener) {
700   if (!session()->OneRttKeysAvailable()) {
701     auto entry = header_block.find(":method");
702     CHECK(entry != header_block.end(), base::NotFatalUntil::M130);
703     DCHECK(
704         entry->second != "POST" ||
705         (handle_ != nullptr && handle_->GetRequestIdempotency() == IDEMPOTENT));
706   }
707   net_log_.AddEvent(
708       NetLogEventType::QUIC_CHROMIUM_CLIENT_STREAM_SEND_REQUEST_HEADERS,
709       [&](NetLogCaptureMode capture_mode) {
710         return QuicRequestNetLogParams(id(), &header_block, priority(),
711                                        capture_mode);
712       });
713   size_t len = quic::QuicSpdyStream::WriteHeaders(std::move(header_block), fin,
714                                                   std::move(ack_listener));
715   initial_headers_sent_ = true;
716   return len;
717 }
718 
WriteStreamData(std::string_view data,bool fin)719 bool QuicChromiumClientStream::WriteStreamData(std::string_view data,
720                                                bool fin) {
721   // Writes the data, or buffers it.
722   WriteOrBufferBody(data, fin);
723   return !HasBufferedData();  // Was all data written?
724 }
725 
WritevStreamData(const std::vector<scoped_refptr<IOBuffer>> & buffers,const std::vector<int> & lengths,bool fin)726 bool QuicChromiumClientStream::WritevStreamData(
727     const std::vector<scoped_refptr<IOBuffer>>& buffers,
728     const std::vector<int>& lengths,
729     bool fin) {
730   // Writes the data, or buffers it.
731   for (size_t i = 0; i < buffers.size(); ++i) {
732     bool is_fin = fin && (i == buffers.size() - 1);
733     std::string_view string_data(buffers[i]->data(), lengths[i]);
734     WriteOrBufferBody(string_data, is_fin);
735   }
736   return !HasBufferedData();  // Was all data written?
737 }
738 
739 std::unique_ptr<QuicChromiumClientStream::Handle>
CreateHandle()740 QuicChromiumClientStream::CreateHandle() {
741   DCHECK(!handle_);
742   auto handle = base::WrapUnique(new QuicChromiumClientStream::Handle(this));
743   handle_ = handle.get();
744 
745   // Should this perhaps be via PostTask to make reasoning simpler?
746   if (initial_headers_arrived_) {
747     handle_->OnInitialHeadersAvailable();
748   }
749 
750   return handle;
751 }
752 
ClearHandle()753 void QuicChromiumClientStream::ClearHandle() {
754   handle_ = nullptr;
755 }
756 
OnError(int error)757 void QuicChromiumClientStream::OnError(int error) {
758   if (handle_) {
759     QuicChromiumClientStream::Handle* handle = handle_;
760     handle_ = nullptr;
761     handle->OnError(error);
762   }
763 }
764 
SupportsH3Datagram() const765 bool QuicChromiumClientStream::SupportsH3Datagram() const {
766   return session_->SupportsH3Datagram();
767 }
768 
Read(IOBuffer * buf,int buf_len)769 int QuicChromiumClientStream::Read(IOBuffer* buf, int buf_len) {
770   DCHECK_GT(buf_len, 0);
771   DCHECK(buf->data());
772 
773   if (IsDoneReading())
774     return 0;  // EOF
775 
776   if (!HasBytesToRead())
777     return ERR_IO_PENDING;
778 
779   iovec iov;
780   iov.iov_base = buf->data();
781   iov.iov_len = buf_len;
782   size_t bytes_read = Readv(&iov, 1);
783   // Since HasBytesToRead is true, Readv() must of read some data.
784   DCHECK_NE(0u, bytes_read);
785   return bytes_read;
786 }
787 
NotifyHandleOfInitialHeadersAvailableLater()788 void QuicChromiumClientStream::NotifyHandleOfInitialHeadersAvailableLater() {
789   DCHECK(handle_);
790   base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
791       FROM_HERE,
792       base::BindOnce(
793           &QuicChromiumClientStream::NotifyHandleOfInitialHeadersAvailable,
794           weak_factory_.GetWeakPtr()));
795 }
796 
NotifyHandleOfInitialHeadersAvailable()797 void QuicChromiumClientStream::NotifyHandleOfInitialHeadersAvailable() {
798   if (!handle_)
799     return;
800 
801   if (!headers_delivered_)
802     handle_->OnInitialHeadersAvailable();
803 }
804 
NotifyHandleOfTrailingHeadersAvailableLater()805 void QuicChromiumClientStream::NotifyHandleOfTrailingHeadersAvailableLater() {
806   DCHECK(handle_);
807   base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
808       FROM_HERE,
809       base::BindOnce(
810           &QuicChromiumClientStream::NotifyHandleOfTrailingHeadersAvailable,
811           weak_factory_.GetWeakPtr()));
812 }
813 
NotifyHandleOfTrailingHeadersAvailable()814 void QuicChromiumClientStream::NotifyHandleOfTrailingHeadersAvailable() {
815   if (!handle_)
816     return;
817 
818   // If trailers aren't decompressed it means that trailers are invalid
819   // (e.g., contain ":status" field). Don't notify to the handle if trailers
820   // aren't decompressed since the stream will be closed and
821   // `headers_delivered_` won't become true.
822   if (!trailers_decompressed())
823     return;
824 
825   // Notify only after the handle reads initial headers.
826   if (!headers_delivered_)
827     return;
828 
829   // Post an async task to notify handle of the FIN flag.
830   NotifyHandleOfDataAvailableLater();
831   handle_->OnTrailingHeadersAvailable();
832 }
833 
DeliverEarlyHints(quiche::HttpHeaderBlock * headers)834 int QuicChromiumClientStream::DeliverEarlyHints(
835     quiche::HttpHeaderBlock* headers) {
836   if (early_hints_.empty()) {
837     return ERR_IO_PENDING;
838   }
839 
840   DCHECK(!headers_delivered_);
841 
842   EarlyHints& hints = early_hints_.front();
843   *headers = std::move(hints.headers);
844   size_t frame_len = hints.frame_len;
845   early_hints_.pop_front();
846 
847   net_log_.AddEvent(
848       NetLogEventType::
849           QUIC_CHROMIUM_CLIENT_STREAM_READ_EARLY_HINTS_RESPONSE_HEADERS,
850       [&](NetLogCaptureMode capture_mode) {
851         return QuicResponseNetLogParams(id(), fin_received(), headers,
852                                         capture_mode);
853       });
854 
855   return frame_len;
856 }
857 
DeliverInitialHeaders(quiche::HttpHeaderBlock * headers)858 int QuicChromiumClientStream::DeliverInitialHeaders(
859     quiche::HttpHeaderBlock* headers) {
860   if (!initial_headers_arrived_) {
861     return ERR_IO_PENDING;
862   }
863 
864   headers_delivered_ = true;
865 
866   if (initial_headers_.empty()) {
867     return ERR_INVALID_RESPONSE;
868   }
869 
870   net_log_.AddEvent(
871       NetLogEventType::QUIC_CHROMIUM_CLIENT_STREAM_READ_RESPONSE_HEADERS,
872       [&](NetLogCaptureMode capture_mode) {
873         return QuicResponseNetLogParams(id(), fin_received(), &initial_headers_,
874                                         capture_mode);
875       });
876 
877   *headers = std::move(initial_headers_);
878   return initial_headers_frame_len_;
879 }
880 
DeliverTrailingHeaders(quiche::HttpHeaderBlock * headers,int * frame_len)881 bool QuicChromiumClientStream::DeliverTrailingHeaders(
882     quiche::HttpHeaderBlock* headers,
883     int* frame_len) {
884   if (trailing_headers_frame_len_ == 0) {
885     return false;
886   }
887 
888   net_log_.AddEvent(
889       NetLogEventType::QUIC_CHROMIUM_CLIENT_STREAM_READ_RESPONSE_TRAILERS,
890       [&](NetLogCaptureMode capture_mode) {
891         return QuicResponseNetLogParams(id(), fin_received(),
892                                         &received_trailers(), capture_mode);
893       });
894 
895   *headers = received_trailers().Clone();
896   *frame_len = trailing_headers_frame_len_;
897 
898   MarkTrailersConsumed();
899   return true;
900 }
901 
NotifyHandleOfDataAvailableLater()902 void QuicChromiumClientStream::NotifyHandleOfDataAvailableLater() {
903   DCHECK(handle_);
904   base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
905       FROM_HERE,
906       base::BindOnce(&QuicChromiumClientStream::NotifyHandleOfDataAvailable,
907                      weak_factory_.GetWeakPtr()));
908 }
909 
NotifyHandleOfDataAvailable()910 void QuicChromiumClientStream::NotifyHandleOfDataAvailable() {
911   if (handle_)
912     handle_->OnDataAvailable();
913 }
914 
DisableConnectionMigrationToCellularNetwork()915 void QuicChromiumClientStream::DisableConnectionMigrationToCellularNetwork() {
916   can_migrate_to_cellular_network_ = false;
917 }
918 
919 quic::QuicPacketLength
GetGuaranteedLargestMessagePayload() const920 QuicChromiumClientStream::GetGuaranteedLargestMessagePayload() const {
921   if (!session()) {
922     return 0;
923   }
924   return session()->GetGuaranteedLargestMessagePayload();
925 }
926 
IsFirstStream()927 bool QuicChromiumClientStream::IsFirstStream() {
928   return id() == quic::QuicUtils::GetFirstBidirectionalStreamId(
929                      quic_version_, quic::Perspective::IS_CLIENT);
930 }
931 
932 }  // namespace net
933