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