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_http_stream.h"
6
7 #include <set>
8 #include <utility>
9
10 #include "base/auto_reset.h"
11 #include "base/functional/bind.h"
12 #include "base/metrics/histogram_functions.h"
13 #include "base/strings/string_split.h"
14 #include "base/task/single_thread_task_runner.h"
15 #include "net/base/features.h"
16 #include "net/base/ip_endpoint.h"
17 #include "net/base/load_flags.h"
18 #include "net/base/net_errors.h"
19 #include "net/http/http_response_headers.h"
20 #include "net/http/http_status_code.h"
21 #include "net/http/http_util.h"
22 #include "net/log/net_log.h"
23 #include "net/log/net_log_event_type.h"
24 #include "net/log/net_log_source.h"
25 #include "net/quic/quic_http_utils.h"
26 #include "net/spdy/spdy_http_utils.h"
27 #include "net/ssl/ssl_info.h"
28 #include "net/third_party/quiche/src/quiche/quic/core/http/quic_client_promised_info.h"
29 #include "net/third_party/quiche/src/quiche/quic/core/http/spdy_utils.h"
30 #include "net/third_party/quiche/src/quiche/quic/core/quic_stream_sequencer.h"
31 #include "net/third_party/quiche/src/quiche/quic/core/quic_utils.h"
32 #include "net/third_party/quiche/src/quiche/spdy/core/spdy_frame_builder.h"
33 #include "net/third_party/quiche/src/quiche/spdy/core/spdy_framer.h"
34 #include "url/origin.h"
35 #include "url/scheme_host_port.h"
36
37 namespace net {
38
39 namespace {
40
NetLogQuicPushStreamParams(quic::QuicStreamId stream_id,const GURL & url)41 base::Value::Dict NetLogQuicPushStreamParams(quic::QuicStreamId stream_id,
42 const GURL& url) {
43 base::Value::Dict dict;
44 dict.Set("stream_id", static_cast<int>(stream_id));
45 dict.Set("url", url.spec());
46 return dict;
47 }
48
NetLogQuicPushStream(const NetLogWithSource & net_log1,const NetLogWithSource & net_log2,NetLogEventType type,quic::QuicStreamId stream_id,const GURL & url)49 void NetLogQuicPushStream(const NetLogWithSource& net_log1,
50 const NetLogWithSource& net_log2,
51 NetLogEventType type,
52 quic::QuicStreamId stream_id,
53 const GURL& url) {
54 net_log1.AddEvent(type,
55 [&] { return NetLogQuicPushStreamParams(stream_id, url); });
56 net_log2.AddEvent(type,
57 [&] { return NetLogQuicPushStreamParams(stream_id, url); });
58 }
59
60 } // namespace
61
QuicHttpStream(std::unique_ptr<QuicChromiumClientSession::Handle> session,std::set<std::string> dns_aliases)62 QuicHttpStream::QuicHttpStream(
63 std::unique_ptr<QuicChromiumClientSession::Handle> session,
64 std::set<std::string> dns_aliases)
65 : MultiplexedHttpStream(std::move(session)),
66 dns_aliases_(std::move(dns_aliases)) {}
67
~QuicHttpStream()68 QuicHttpStream::~QuicHttpStream() {
69 CHECK(!in_loop_);
70 Close(false);
71 }
72
ConnectionInfoFromQuicVersion(quic::ParsedQuicVersion quic_version)73 HttpResponseInfo::ConnectionInfo QuicHttpStream::ConnectionInfoFromQuicVersion(
74 quic::ParsedQuicVersion quic_version) {
75 switch (quic_version.transport_version) {
76 case quic::QUIC_VERSION_UNSUPPORTED:
77 return HttpResponseInfo::CONNECTION_INFO_QUIC_UNKNOWN_VERSION;
78 case quic::QUIC_VERSION_43:
79 return HttpResponseInfo::CONNECTION_INFO_QUIC_43;
80 case quic::QUIC_VERSION_46:
81 return HttpResponseInfo::CONNECTION_INFO_QUIC_46;
82 case quic::QUIC_VERSION_50:
83 return quic_version.UsesTls()
84 ? HttpResponseInfo::CONNECTION_INFO_QUIC_T050
85 : HttpResponseInfo::CONNECTION_INFO_QUIC_Q050;
86 case quic::QUIC_VERSION_IETF_DRAFT_29:
87 DCHECK(quic_version.UsesTls());
88 return HttpResponseInfo::CONNECTION_INFO_QUIC_DRAFT_29;
89 case quic::QUIC_VERSION_IETF_RFC_V1:
90 DCHECK(quic_version.UsesTls());
91 return HttpResponseInfo::CONNECTION_INFO_QUIC_RFC_V1;
92 case quic::QUIC_VERSION_RESERVED_FOR_NEGOTIATION:
93 return HttpResponseInfo::CONNECTION_INFO_QUIC_999;
94 case quic::QUIC_VERSION_IETF_2_DRAFT_08:
95 DCHECK(quic_version.UsesTls());
96 return HttpResponseInfo::CONNECTION_INFO_QUIC_2_DRAFT_8;
97 }
98 NOTREACHED();
99 return HttpResponseInfo::CONNECTION_INFO_QUIC_UNKNOWN_VERSION;
100 }
101
RegisterRequest(const HttpRequestInfo * request_info)102 void QuicHttpStream::RegisterRequest(const HttpRequestInfo* request_info) {
103 DCHECK(request_info);
104 DCHECK(request_info->traffic_annotation.is_valid());
105 request_info_ = request_info;
106 }
107
InitializeStream(bool can_send_early,RequestPriority priority,const NetLogWithSource & stream_net_log,CompletionOnceCallback callback)108 int QuicHttpStream::InitializeStream(bool can_send_early,
109 RequestPriority priority,
110 const NetLogWithSource& stream_net_log,
111 CompletionOnceCallback callback) {
112 CHECK(callback_.is_null());
113 DCHECK(request_info_);
114 DCHECK(!stream_);
115
116 // HttpNetworkTransaction will retry any request that fails with
117 // ERR_QUIC_HANDSHAKE_FAILED. It will retry any request with
118 // ERR_CONNECTION_CLOSED so long as the connection has been used for other
119 // streams first and headers have not yet been received.
120 if (!quic_session()->IsConnected())
121 return GetResponseStatus();
122
123 stream_net_log.AddEventReferencingSource(
124 NetLogEventType::HTTP_STREAM_REQUEST_BOUND_TO_QUIC_SESSION,
125 quic_session()->net_log().source());
126 stream_net_log.AddEventWithIntParams(
127 NetLogEventType::QUIC_CONNECTION_MIGRATION_MODE,
128 "connection_migration_mode",
129 static_cast<int>(quic_session()->connection_migration_mode()));
130
131 stream_net_log_ = stream_net_log;
132 can_send_early_ = can_send_early;
133 request_time_ = base::Time::Now();
134 priority_ = priority;
135
136 SaveSSLInfo();
137
138 std::string url(request_info_->url.spec());
139 quic::QuicClientPromisedInfo* promised =
140 quic_session()->GetPushPromiseIndex()->GetPromised(url);
141 if (promised) {
142 found_promise_ = true;
143 NetLogQuicPushStream(
144 stream_net_log_, quic_session()->net_log(),
145 NetLogEventType::QUIC_HTTP_STREAM_PUSH_PROMISE_RENDEZVOUS,
146 promised->id(), request_info_->url);
147 return OK;
148 }
149
150 next_state_ = STATE_REQUEST_STREAM;
151 int rv = DoLoop(OK);
152 if (rv == ERR_IO_PENDING)
153 callback_ = std::move(callback);
154
155 return MapStreamError(rv);
156 }
157
DoHandlePromise()158 int QuicHttpStream::DoHandlePromise() {
159 next_state_ = STATE_HANDLE_PROMISE_COMPLETE;
160 return quic_session()->RendezvousWithPromised(
161 request_headers_, base::BindOnce(&QuicHttpStream::OnIOComplete,
162 weak_factory_.GetWeakPtr()));
163 }
164
DoHandlePromiseComplete(int rv)165 int QuicHttpStream::DoHandlePromiseComplete(int rv) {
166 DCHECK_NE(ERR_IO_PENDING, rv);
167 DCHECK_GE(OK, rv);
168 DCHECK(request_info_);
169 if (rv != OK) {
170 // rendezvous has failed so proceed as with a non-push request.
171 next_state_ = STATE_REQUEST_STREAM;
172 return OK;
173 }
174
175 stream_ = quic_session()->ReleasePromisedStream();
176
177 uint8_t urgency = ConvertRequestPriorityToQuicPriority(priority_);
178 bool incremental = quic::HttpStreamPriority::kDefaultIncremental;
179 if (base::FeatureList::IsEnabled(features::kPriorityIncremental)) {
180 incremental = request_info_->priority_incremental;
181 }
182 stream_->SetPriority(
183 quic::QuicStreamPriority(quic::HttpStreamPriority{urgency, incremental}));
184
185 next_state_ = STATE_OPEN;
186 NetLogQuicPushStream(stream_net_log_, quic_session()->net_log(),
187 NetLogEventType::QUIC_HTTP_STREAM_ADOPTED_PUSH_STREAM,
188 stream_->id(), request_info_->url);
189 return OK;
190 }
191
SendRequest(const HttpRequestHeaders & request_headers,HttpResponseInfo * response,CompletionOnceCallback callback)192 int QuicHttpStream::SendRequest(const HttpRequestHeaders& request_headers,
193 HttpResponseInfo* response,
194 CompletionOnceCallback callback) {
195 CHECK(!request_body_stream_);
196 CHECK(!response_info_);
197 CHECK(callback_.is_null());
198 CHECK(!callback.is_null());
199 CHECK(response);
200
201 // In order to rendezvous with a push stream, the session still needs to be
202 // available. Otherwise the stream needs to be available.
203 if ((!found_promise_ && !stream_) || !quic_session()->IsConnected())
204 return GetResponseStatus();
205
206 // Store the serialized request headers.
207 CreateSpdyHeadersFromHttpRequest(*request_info_, request_headers,
208 &request_headers_);
209
210 // Store the request body.
211 request_body_stream_ = request_info_->upload_data_stream;
212 if (request_body_stream_) {
213 // A request with a body is ineligible for push, so reset the
214 // promised stream and request a new stream.
215 if (found_promise_) {
216 std::string url(request_info_->url.spec());
217 quic::QuicClientPromisedInfo* promised =
218 quic_session()->GetPushPromiseIndex()->GetPromised(url);
219 if (promised != nullptr) {
220 quic_session()->ResetPromised(promised->id(),
221 quic::QUIC_STREAM_CANCELLED);
222 }
223 }
224
225 // TODO(rch): Can we be more precise about when to allocate
226 // raw_request_body_buf_. Removed the following check. DoReadRequestBody()
227 // was being called even if we didn't yet allocate raw_request_body_buf_.
228 // && (request_body_stream_->size() ||
229 // request_body_stream_->is_chunked()))
230 // Set the body buffer size to be the size of the body clamped
231 // into the range [10 * quic::kMaxOutgoingPacketSize, 256 *
232 // quic::kMaxOutgoingPacketSize]. With larger bodies, larger buffers reduce
233 // CPU usage.
234 raw_request_body_buf_ =
235 base::MakeRefCounted<IOBufferWithSize>(static_cast<size_t>(
236 std::max(10 * quic::kMaxOutgoingPacketSize,
237 std::min(request_body_stream_->size(),
238 256 * quic::kMaxOutgoingPacketSize))));
239 // The request body buffer is empty at first.
240 request_body_buf_ =
241 base::MakeRefCounted<DrainableIOBuffer>(raw_request_body_buf_, 0);
242 }
243
244 // Store the response info.
245 response_info_ = response;
246
247 // Put the peer's IP address and port into the response.
248 IPEndPoint address;
249 int rv = quic_session()->GetPeerAddress(&address);
250 if (rv != OK)
251 return rv;
252 response_info_->remote_endpoint = address;
253
254 if (!found_promise_) {
255 next_state_ = STATE_SET_REQUEST_PRIORITY;
256 } else if (!request_body_stream_) {
257 next_state_ = STATE_HANDLE_PROMISE;
258 } else {
259 found_promise_ = false;
260 next_state_ = STATE_REQUEST_STREAM;
261 }
262 rv = DoLoop(OK);
263
264 if (rv == ERR_IO_PENDING)
265 callback_ = std::move(callback);
266
267 return rv > 0 ? OK : MapStreamError(rv);
268 }
269
ReadResponseHeaders(CompletionOnceCallback callback)270 int QuicHttpStream::ReadResponseHeaders(CompletionOnceCallback callback) {
271 CHECK(callback_.is_null());
272 CHECK(!callback.is_null());
273
274 int rv = stream_->ReadInitialHeaders(
275 &response_header_block_,
276 base::BindOnce(&QuicHttpStream::OnReadResponseHeadersComplete,
277 weak_factory_.GetWeakPtr()));
278
279 if (rv == ERR_IO_PENDING) {
280 // Still waiting for the response, return IO_PENDING.
281 CHECK(callback_.is_null());
282 callback_ = std::move(callback);
283 return ERR_IO_PENDING;
284 }
285
286 if (rv < 0)
287 return MapStreamError(rv);
288
289 // Check if we already have the response headers. If so, return synchronously.
290 if (response_headers_received_)
291 return OK;
292
293 headers_bytes_received_ += rv;
294 return ProcessResponseHeaders(response_header_block_);
295 }
296
ReadResponseBody(IOBuffer * buf,int buf_len,CompletionOnceCallback callback)297 int QuicHttpStream::ReadResponseBody(IOBuffer* buf,
298 int buf_len,
299 CompletionOnceCallback callback) {
300 CHECK(callback_.is_null());
301 CHECK(!callback.is_null());
302 CHECK(!user_buffer_.get());
303 CHECK_EQ(0, user_buffer_len_);
304
305 // Invalidate HttpRequestInfo pointer. This is to allow the stream to be
306 // shared across multiple transactions which might require this
307 // stream to outlive the request_info_'s owner.
308 // Only allowed when Read state machine starts. It is safe to reset it at
309 // this point since request_info_->upload_data_stream is also not needed
310 // anymore.
311 request_info_ = nullptr;
312
313 // If the stream is already closed, there is no body to read.
314 if (stream_->IsDoneReading())
315 return HandleReadComplete(OK);
316
317 int rv = stream_->ReadBody(buf, buf_len,
318 base::BindOnce(&QuicHttpStream::OnReadBodyComplete,
319 weak_factory_.GetWeakPtr()));
320 if (rv == ERR_IO_PENDING) {
321 callback_ = std::move(callback);
322 user_buffer_ = buf;
323 user_buffer_len_ = buf_len;
324 return ERR_IO_PENDING;
325 }
326
327 if (rv < 0)
328 return MapStreamError(rv);
329
330 return HandleReadComplete(rv);
331 }
332
Close(bool)333 void QuicHttpStream::Close(bool /*not_reusable*/) {
334 session_error_ = ERR_ABORTED;
335 SaveResponseStatus();
336 // Note: the not_reusable flag has no meaning for QUIC streams.
337 if (stream_)
338 stream_->Reset(quic::QUIC_STREAM_CANCELLED);
339 ResetStream();
340 }
341
IsResponseBodyComplete() const342 bool QuicHttpStream::IsResponseBodyComplete() const {
343 return next_state_ == STATE_OPEN && stream_->IsDoneReading();
344 }
345
IsConnectionReused() const346 bool QuicHttpStream::IsConnectionReused() const {
347 // TODO(rch): do something smarter here.
348 return stream_ && stream_->id() > 1;
349 }
350
GetTotalReceivedBytes() const351 int64_t QuicHttpStream::GetTotalReceivedBytes() const {
352 if (stream_) {
353 DCHECK_LE(stream_->NumBytesConsumed(), stream_->stream_bytes_read());
354 // Only count the uniquely received bytes.
355 return stream_->NumBytesConsumed();
356 }
357 return closed_stream_received_bytes_;
358 }
359
GetTotalSentBytes() const360 int64_t QuicHttpStream::GetTotalSentBytes() const {
361 if (stream_) {
362 return stream_->stream_bytes_written();
363 }
364 return closed_stream_sent_bytes_;
365 }
366
GetLoadTimingInfo(LoadTimingInfo * load_timing_info) const367 bool QuicHttpStream::GetLoadTimingInfo(LoadTimingInfo* load_timing_info) const {
368 bool is_first_stream = closed_is_first_stream_;
369 if (stream_) {
370 is_first_stream = stream_->IsFirstStream();
371 load_timing_info->first_early_hints_time =
372 stream_->first_early_hints_time();
373 load_timing_info->receive_non_informational_headers_start =
374 stream_->headers_received_start_time();
375 load_timing_info->receive_headers_start =
376 load_timing_info->first_early_hints_time.is_null()
377 ? load_timing_info->receive_non_informational_headers_start
378 : load_timing_info->first_early_hints_time;
379 }
380
381 if (is_first_stream) {
382 load_timing_info->socket_reused = false;
383 load_timing_info->connect_timing = connect_timing_;
384 } else {
385 load_timing_info->socket_reused = true;
386 }
387 return true;
388 }
389
GetAlternativeService(AlternativeService * alternative_service) const390 bool QuicHttpStream::GetAlternativeService(
391 AlternativeService* alternative_service) const {
392 alternative_service->protocol = kProtoQUIC;
393 const url::SchemeHostPort& destination = quic_session()->destination();
394 alternative_service->host = destination.host();
395 alternative_service->port = destination.port();
396 return true;
397 }
398
PopulateNetErrorDetails(NetErrorDetails * details)399 void QuicHttpStream::PopulateNetErrorDetails(NetErrorDetails* details) {
400 details->connection_info =
401 ConnectionInfoFromQuicVersion(quic_session()->GetQuicVersion());
402 quic_session()->PopulateNetErrorDetails(details);
403 if (quic_session()->OneRttKeysAvailable() && stream_ &&
404 stream_->connection_error() != quic::QUIC_NO_ERROR)
405 details->quic_connection_error = stream_->connection_error();
406 }
407
SetPriority(RequestPriority priority)408 void QuicHttpStream::SetPriority(RequestPriority priority) {
409 priority_ = priority;
410 }
411
OnReadResponseHeadersComplete(int rv)412 void QuicHttpStream::OnReadResponseHeadersComplete(int rv) {
413 DCHECK(callback_);
414 DCHECK(!response_headers_received_);
415 if (rv > 0) {
416 headers_bytes_received_ += rv;
417 rv = ProcessResponseHeaders(response_header_block_);
418 }
419 if (rv != ERR_IO_PENDING && !callback_.is_null()) {
420 DoCallback(rv);
421 }
422 }
423
GetDnsAliases() const424 const std::set<std::string>& QuicHttpStream::GetDnsAliases() const {
425 return dns_aliases_;
426 }
427
GetAcceptChViaAlps() const428 base::StringPiece QuicHttpStream::GetAcceptChViaAlps() const {
429 if (!request_info_) {
430 return {};
431 }
432
433 return session()->GetAcceptChViaAlps(url::SchemeHostPort(request_info_->url));
434 }
435
GetQuicErrorCode() const436 absl::optional<quic::QuicErrorCode> QuicHttpStream::GetQuicErrorCode() const {
437 if (stream_) {
438 return stream_->connection_error();
439 }
440 return connection_error_;
441 }
442
443 absl::optional<quic::QuicRstStreamErrorCode>
GetQuicRstStreamErrorCode() const444 QuicHttpStream::GetQuicRstStreamErrorCode() const {
445 if (stream_) {
446 return stream_->stream_error();
447 }
448 return stream_error_;
449 }
450
ReadTrailingHeaders()451 void QuicHttpStream::ReadTrailingHeaders() {
452 int rv = stream_->ReadTrailingHeaders(
453 &trailing_header_block_,
454 base::BindOnce(&QuicHttpStream::OnReadTrailingHeadersComplete,
455 weak_factory_.GetWeakPtr()));
456
457 if (rv != ERR_IO_PENDING)
458 OnReadTrailingHeadersComplete(rv);
459 }
460
OnReadTrailingHeadersComplete(int rv)461 void QuicHttpStream::OnReadTrailingHeadersComplete(int rv) {
462 DCHECK(response_headers_received_);
463 if (rv > 0)
464 headers_bytes_received_ += rv;
465
466 // QuicHttpStream ignores trailers.
467 if (stream_->IsDoneReading()) {
468 // Close the read side. If the write side has been closed, this will
469 // invoke QuicHttpStream::OnClose to reset the stream.
470 stream_->OnFinRead();
471 SetResponseStatus(OK);
472 }
473 }
474
OnIOComplete(int rv)475 void QuicHttpStream::OnIOComplete(int rv) {
476 rv = DoLoop(rv);
477
478 if (rv != ERR_IO_PENDING && !callback_.is_null()) {
479 DoCallback(rv);
480 }
481 }
482
DoCallback(int rv)483 void QuicHttpStream::DoCallback(int rv) {
484 CHECK_NE(rv, ERR_IO_PENDING);
485 CHECK(!callback_.is_null());
486 CHECK(!in_loop_);
487
488 // The client callback can do anything, including destroying this class,
489 // so any pending callback must be issued after everything else is done.
490 std::move(callback_).Run(MapStreamError(rv));
491 }
492
DoLoop(int rv)493 int QuicHttpStream::DoLoop(int rv) {
494 CHECK(!in_loop_);
495 base::AutoReset<bool> auto_reset_in_loop(&in_loop_, true);
496 std::unique_ptr<quic::QuicConnection::ScopedPacketFlusher> packet_flusher =
497 quic_session()->CreatePacketBundler();
498 do {
499 State state = next_state_;
500 next_state_ = STATE_NONE;
501 switch (state) {
502 case STATE_HANDLE_PROMISE:
503 CHECK_EQ(OK, rv);
504 rv = DoHandlePromise();
505 break;
506 case STATE_HANDLE_PROMISE_COMPLETE:
507 rv = DoHandlePromiseComplete(rv);
508 break;
509 case STATE_REQUEST_STREAM:
510 CHECK_EQ(OK, rv);
511 rv = DoRequestStream();
512 break;
513 case STATE_REQUEST_STREAM_COMPLETE:
514 rv = DoRequestStreamComplete(rv);
515 break;
516 case STATE_SET_REQUEST_PRIORITY:
517 CHECK_EQ(OK, rv);
518 rv = DoSetRequestPriority();
519 break;
520 case STATE_SEND_HEADERS:
521 CHECK_EQ(OK, rv);
522 rv = DoSendHeaders();
523 break;
524 case STATE_SEND_HEADERS_COMPLETE:
525 rv = DoSendHeadersComplete(rv);
526 break;
527 case STATE_READ_REQUEST_BODY:
528 CHECK_EQ(OK, rv);
529 rv = DoReadRequestBody();
530 break;
531 case STATE_READ_REQUEST_BODY_COMPLETE:
532 rv = DoReadRequestBodyComplete(rv);
533 break;
534 case STATE_SEND_BODY:
535 CHECK_EQ(OK, rv);
536 rv = DoSendBody();
537 break;
538 case STATE_SEND_BODY_COMPLETE:
539 rv = DoSendBodyComplete(rv);
540 break;
541 case STATE_OPEN:
542 CHECK_EQ(OK, rv);
543 break;
544 default:
545 NOTREACHED() << "next_state_: " << next_state_;
546 break;
547 }
548 } while (next_state_ != STATE_NONE && next_state_ != STATE_OPEN &&
549 rv != ERR_IO_PENDING);
550
551 return rv;
552 }
553
DoRequestStream()554 int QuicHttpStream::DoRequestStream() {
555 next_state_ = STATE_REQUEST_STREAM_COMPLETE;
556
557 return quic_session()->RequestStream(
558 !can_send_early_,
559 base::BindOnce(&QuicHttpStream::OnIOComplete, weak_factory_.GetWeakPtr()),
560 NetworkTrafficAnnotationTag(request_info_->traffic_annotation));
561 }
562
DoRequestStreamComplete(int rv)563 int QuicHttpStream::DoRequestStreamComplete(int rv) {
564 DCHECK(rv == OK || !stream_);
565 if (rv != OK) {
566 session_error_ = rv;
567 return GetResponseStatus();
568 }
569
570 stream_ = quic_session()->ReleaseStream();
571 DCHECK(stream_);
572 if (!stream_->IsOpen()) {
573 session_error_ = ERR_CONNECTION_CLOSED;
574 return GetResponseStatus();
575 }
576
577 if (request_info_->load_flags &
578 LOAD_DISABLE_CONNECTION_MIGRATION_TO_CELLULAR) {
579 stream_->DisableConnectionMigrationToCellularNetwork();
580 }
581
582 if (response_info_) {
583 // This happens in the case of a asynchronous push rendezvous
584 // that ultimately fails (e.g. vary failure). |response_info_|
585 // non-null implies that |DoRequestStream()| was called via
586 // |SendRequest()|.
587 next_state_ = STATE_SET_REQUEST_PRIORITY;
588 }
589
590 return OK;
591 }
592
DoSetRequestPriority()593 int QuicHttpStream::DoSetRequestPriority() {
594 // Set priority according to request
595 DCHECK(stream_);
596 DCHECK(response_info_);
597 DCHECK(request_info_);
598
599 uint8_t urgency = ConvertRequestPriorityToQuicPriority(priority_);
600 bool incremental = quic::HttpStreamPriority::kDefaultIncremental;
601 if (base::FeatureList::IsEnabled(features::kPriorityIncremental)) {
602 incremental = request_info_->priority_incremental;
603 }
604 stream_->SetPriority(
605 quic::QuicStreamPriority(quic::HttpStreamPriority{urgency, incremental}));
606 next_state_ = STATE_SEND_HEADERS;
607 return OK;
608 }
609
DoSendHeaders()610 int QuicHttpStream::DoSendHeaders() {
611 uint8_t urgency = ConvertRequestPriorityToQuicPriority(priority_);
612 bool incremental = quic::HttpStreamPriority::kDefaultIncremental;
613 if (base::FeatureList::IsEnabled(features::kPriorityIncremental)) {
614 incremental = request_info_->priority_incremental;
615 }
616 quic::QuicStreamPriority priority(
617 quic::HttpStreamPriority{urgency, incremental});
618 // Log the actual request with the URL Request's net log.
619 stream_net_log_.AddEvent(
620 NetLogEventType::HTTP_TRANSACTION_QUIC_SEND_REQUEST_HEADERS,
621 [&](NetLogCaptureMode capture_mode) {
622 return QuicRequestNetLogParams(stream_->id(), &request_headers_,
623 priority, capture_mode);
624 });
625 DispatchRequestHeadersCallback(request_headers_);
626 bool has_upload_data = request_body_stream_ != nullptr;
627
628 next_state_ = STATE_SEND_HEADERS_COMPLETE;
629 int rv = stream_->WriteHeaders(std::move(request_headers_), !has_upload_data,
630 nullptr);
631 if (rv > 0)
632 headers_bytes_sent_ += rv;
633
634 request_headers_ = spdy::Http2HeaderBlock();
635 return rv;
636 }
637
DoSendHeadersComplete(int rv)638 int QuicHttpStream::DoSendHeadersComplete(int rv) {
639 if (rv < 0)
640 return rv;
641
642 next_state_ = request_body_stream_ ? STATE_READ_REQUEST_BODY : STATE_OPEN;
643
644 return OK;
645 }
646
DoReadRequestBody()647 int QuicHttpStream::DoReadRequestBody() {
648 next_state_ = STATE_READ_REQUEST_BODY_COMPLETE;
649 return request_body_stream_->Read(
650 raw_request_body_buf_.get(), raw_request_body_buf_->size(),
651 base::BindOnce(&QuicHttpStream::OnIOComplete,
652 weak_factory_.GetWeakPtr()));
653 }
654
DoReadRequestBodyComplete(int rv)655 int QuicHttpStream::DoReadRequestBodyComplete(int rv) {
656 // |rv| is the result of read from the request body from the last call to
657 // DoSendBody().
658 if (rv < 0) {
659 stream_->Reset(quic::QUIC_ERROR_PROCESSING_STREAM);
660 ResetStream();
661 return rv;
662 }
663
664 request_body_buf_ =
665 base::MakeRefCounted<DrainableIOBuffer>(raw_request_body_buf_, rv);
666 if (rv == 0) { // Reached the end.
667 DCHECK(request_body_stream_->IsEOF());
668 }
669
670 next_state_ = STATE_SEND_BODY;
671 return OK;
672 }
673
DoSendBody()674 int QuicHttpStream::DoSendBody() {
675 CHECK(request_body_stream_);
676 CHECK(request_body_buf_.get());
677 const bool eof = request_body_stream_->IsEOF();
678 int len = request_body_buf_->BytesRemaining();
679 if (len > 0 || eof) {
680 next_state_ = STATE_SEND_BODY_COMPLETE;
681 base::StringPiece data(request_body_buf_->data(), len);
682 return stream_->WriteStreamData(
683 data, eof,
684 base::BindOnce(&QuicHttpStream::OnIOComplete,
685 weak_factory_.GetWeakPtr()));
686 }
687
688 next_state_ = STATE_OPEN;
689 return OK;
690 }
691
DoSendBodyComplete(int rv)692 int QuicHttpStream::DoSendBodyComplete(int rv) {
693 if (rv < 0)
694 return rv;
695
696 request_body_buf_->DidConsume(request_body_buf_->BytesRemaining());
697
698 if (!request_body_stream_->IsEOF()) {
699 next_state_ = STATE_READ_REQUEST_BODY;
700 return OK;
701 }
702
703 next_state_ = STATE_OPEN;
704 return OK;
705 }
706
ProcessResponseHeaders(const spdy::Http2HeaderBlock & headers)707 int QuicHttpStream::ProcessResponseHeaders(
708 const spdy::Http2HeaderBlock& headers) {
709 const int rv = SpdyHeadersToHttpResponse(headers, response_info_);
710 base::UmaHistogramBoolean("Net.QuicHttpStream.ProcessResponseHeaderSuccess",
711 rv == OK);
712 if (rv != OK) {
713 DLOG(WARNING) << "Invalid headers";
714 return ERR_QUIC_PROTOCOL_ERROR;
715 }
716
717 if (response_info_->headers->response_code() == HTTP_EARLY_HINTS) {
718 DCHECK(!response_headers_received_);
719 headers_bytes_received_ = 0;
720 return OK;
721 }
722
723 response_info_->connection_info =
724 ConnectionInfoFromQuicVersion(quic_session()->GetQuicVersion());
725 response_info_->was_alpn_negotiated = true;
726 response_info_->alpn_negotiated_protocol =
727 HttpResponseInfo::ConnectionInfoToString(response_info_->connection_info);
728 response_info_->response_time = base::Time::Now();
729 response_info_->request_time = request_time_;
730 response_headers_received_ = true;
731
732 // Populate |connect_timing_| when response headers are received. This should
733 // take care of 0-RTT where request is sent before handshake is confirmed.
734 connect_timing_ = quic_session()->GetConnectTiming();
735
736 base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
737 FROM_HERE, base::BindOnce(&QuicHttpStream::ReadTrailingHeaders,
738 weak_factory_.GetWeakPtr()));
739
740 if (stream_->IsDoneReading()) {
741 session_error_ = OK;
742 SaveResponseStatus();
743 stream_->OnFinRead();
744 }
745
746 return OK;
747 }
748
OnReadBodyComplete(int rv)749 void QuicHttpStream::OnReadBodyComplete(int rv) {
750 CHECK(callback_);
751 user_buffer_ = nullptr;
752 user_buffer_len_ = 0;
753 rv = HandleReadComplete(rv);
754 DoCallback(rv);
755 }
756
HandleReadComplete(int rv)757 int QuicHttpStream::HandleReadComplete(int rv) {
758 if (stream_->IsDoneReading()) {
759 stream_->OnFinRead();
760 SetResponseStatus(OK);
761 ResetStream();
762 }
763 return rv;
764 }
765
ResetStream()766 void QuicHttpStream::ResetStream() {
767 // If |request_body_stream_| is non-NULL, Reset it, to abort any in progress
768 // read.
769 if (request_body_stream_)
770 request_body_stream_->Reset();
771
772 if (!stream_)
773 return;
774
775 DCHECK_LE(stream_->NumBytesConsumed(), stream_->stream_bytes_read());
776 // Only count the uniquely received bytes.
777 closed_stream_received_bytes_ = stream_->NumBytesConsumed();
778 closed_stream_sent_bytes_ = stream_->stream_bytes_written();
779 closed_is_first_stream_ = stream_->IsFirstStream();
780 connection_error_ = stream_->connection_error();
781 stream_error_ = stream_->stream_error();
782 }
783
MapStreamError(int rv)784 int QuicHttpStream::MapStreamError(int rv) {
785 if (rv == ERR_QUIC_PROTOCOL_ERROR && !quic_session()->OneRttKeysAvailable()) {
786 return ERR_QUIC_HANDSHAKE_FAILED;
787 }
788 return rv;
789 }
790
GetResponseStatus()791 int QuicHttpStream::GetResponseStatus() {
792 SaveResponseStatus();
793 return response_status_;
794 }
795
SaveResponseStatus()796 void QuicHttpStream::SaveResponseStatus() {
797 if (!has_response_status_)
798 SetResponseStatus(ComputeResponseStatus());
799 }
800
SetResponseStatus(int response_status)801 void QuicHttpStream::SetResponseStatus(int response_status) {
802 has_response_status_ = true;
803 response_status_ = response_status;
804 }
805
ComputeResponseStatus() const806 int QuicHttpStream::ComputeResponseStatus() const {
807 DCHECK(!has_response_status_);
808
809 // If the handshake has failed this will be handled by the QuicStreamFactory
810 // and HttpStreamFactory to mark QUIC as broken if TCP is actually working.
811 if (!quic_session()->OneRttKeysAvailable())
812 return ERR_QUIC_HANDSHAKE_FAILED;
813
814 // If the session was aborted by a higher layer, simply use that error code.
815 if (session_error_ != ERR_UNEXPECTED)
816 return session_error_;
817
818 // If |response_info_| is null then the request has not been sent, so
819 // return ERR_CONNECTION_CLOSED to permit HttpNetworkTransaction to
820 // retry the request.
821 if (!response_info_)
822 return ERR_CONNECTION_CLOSED;
823
824 base::UmaHistogramEnumeration("Net.QuicHttpStream.ResponseStatus",
825 stream_->stream_error(),
826 quic::QUIC_STREAM_LAST_ERROR);
827
828 return ERR_QUIC_PROTOCOL_ERROR;
829 }
830
SetRequestIdempotency(Idempotency idempotency)831 void QuicHttpStream::SetRequestIdempotency(Idempotency idempotency) {
832 if (stream_ == nullptr) {
833 return;
834 }
835 stream_->SetRequestIdempotency(idempotency);
836 }
837
838 } // namespace net
839