blob: 026df00dbe43bd6426552a47e5ce2f4c708a0661 [file] [log] [blame]
// Copyright 2024 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "net/http/http_stream_pool_quic_attempt.h"
#include <memory>
#include <vector>
#include "base/task/sequenced_task_runner.h"
#include "base/time/time.h"
#include "base/trace_event/trace_event.h"
#include "base/trace_event/trace_id_helper.h"
#include "base/values.h"
#include "net/base/connection_endpoint_metadata.h"
#include "net/base/ip_endpoint.h"
#include "net/base/net_error_details.h"
#include "net/base/net_errors.h"
#include "net/dns/host_resolver.h"
#include "net/dns/public/host_resolver_results.h"
#include "net/http/http_network_session.h"
#include "net/http/http_stream_pool.h"
#include "net/http/http_stream_pool_attempt_manager.h"
#include "net/http/http_stream_pool_group.h"
#include "net/log/net_log_source_type.h"
#include "net/log/net_log_with_source.h"
#include "net/quic/quic_session_alias_key.h"
#include "net/quic/quic_session_attempt_manager.h"
#include "net/quic/quic_session_attempt_request.h"
#include "net/quic/quic_session_key.h"
#include "net/quic/quic_session_pool.h"
#include "net/third_party/quiche/src/quiche/quic/core/quic_versions.h"
namespace net {
HttpStreamPool::QuicAttempt::QuicAttempt(AttemptManager* manager,
QuicEndpoint quic_endpoint)
: manager_(manager),
quic_endpoint_(std::move(quic_endpoint)),
start_time_(base::TimeTicks::Now()),
net_log_(NetLogWithSource::Make(
manager->net_log().net_log(),
NetLogSourceType::HTTP_STREAM_POOL_QUIC_ATTEMPT)),
track_(base::trace_event::GetNextGlobalTraceId()),
flow_(perfetto::Flow::ProcessScoped(
base::trace_event::GetNextGlobalTraceId())) {
CHECK(manager_);
TRACE_EVENT_INSTANT("net.stream", "QuicAttemptStart", manager_->track(),
flow_);
TRACE_EVENT_BEGIN("net.stream", "QuicAttempt::QuicAttempt", track_, flow_,
"ip_endpoint", quic_endpoint_.ip_endpoint.ToString());
net_log_.BeginEvent(
NetLogEventType::HTTP_STREAM_POOL_QUIC_ATTEMPT_ALIVE, [&] {
base::Value::Dict dict;
dict.Set("quic_version",
quic::ParsedQuicVersionToString(quic_endpoint_.quic_version));
dict.Set("ip_endpoint", quic_endpoint_.ip_endpoint.ToString());
dict.Set("metadata", quic_endpoint_.metadata.ToValue());
manager_->net_log().source().AddToEventParameters(dict);
return dict;
});
manager_->net_log().AddEventReferencingSource(
NetLogEventType::HTTP_STREAM_POOL_ATTEMPT_MANAGER_QUIC_ATTEMPT_BOUND,
net_log_.source());
request_ = quic_session_pool()->session_attempt_manager()->CreateRequest(
quic_session_alias_key());
}
HttpStreamPool::QuicAttempt::~QuicAttempt() {
net_log_.EndEventWithNetErrorCode(
NetLogEventType::HTTP_STREAM_POOL_QUIC_ATTEMPT_ALIVE,
result_.value_or(ERR_ABORTED));
TRACE_EVENT_END("net.stream", track_, "result",
result_.value_or(ERR_ABORTED));
TRACE_EVENT_INSTANT("net.stream", "QuicAttemptEnd", manager_->track(), flow_);
}
void HttpStreamPool::QuicAttempt::Start() {
if (GetTcpBasedAttemptDelayBehavior() ==
TcpBasedAttemptDelayBehavior::kStartTimerOnFirstQuicAttempt) {
manager_->MaybeRunTcpBasedAttemptDelayTimer();
}
SSLConfig ssl_config;
ssl_config.disable_cert_verification_network_fetches =
stream_key().disable_cert_network_fetches();
int cert_verify_flags = ssl_config.GetCertVerifyFlags();
base::TimeTicks dns_resolution_start_time =
manager_->dns_resolution_start_time();
// The DNS resolution end time could be null when the resolution is still
// ongoing. In that case, use the current time to make sure the connect
// start time is already greater than the DNS resolution end time.
base::TimeTicks dns_resolution_end_time =
manager_->dns_resolution_end_time().is_null()
? base::TimeTicks::Now()
: manager_->dns_resolution_end_time();
std::set<std::string> dns_aliases =
manager_->service_endpoint_request()->GetDnsAliasResults();
int rv = request_->RequestSession(
quic_endpoint_, cert_verify_flags, dns_resolution_start_time,
dns_resolution_end_time, /*use_dns_aliases=*/true, std::move(dns_aliases),
manager_->CalculateMultiplexedSessionCreationInitiator(),
/*connection_management_config=*/std::nullopt, net_log_,
base::BindOnce(&QuicAttempt::OnSessionAttemptComplete,
weak_ptr_factory_.GetWeakPtr()));
if (rv == ERR_IO_PENDING) {
slow_timer_.Start(FROM_HERE, HttpStreamPool::GetConnectionAttemptDelay(),
base::BindOnce(&QuicAttempt::OnSessionAttemptSlow,
base::Unretained(this)));
} else {
OnSessionAttemptComplete(rv);
}
}
base::Value::Dict HttpStreamPool::QuicAttempt::GetInfoAsValue() const {
base::Value::Dict dict;
dict.Set("quic_version",
quic::ParsedQuicVersionToString(quic_endpoint_.quic_version));
dict.Set("ip_endpoint", quic_endpoint_.ip_endpoint.ToString());
base::TimeDelta elapsed = base::TimeTicks::Now() - start_time_;
dict.Set("elapsed_ms", static_cast<int>(elapsed.InMilliseconds()));
if (result_.has_value()) {
dict.Set("result", *result_);
}
return dict;
}
const HttpStreamKey& HttpStreamPool::QuicAttempt::stream_key() const {
return manager_->group()->stream_key();
}
const QuicSessionAliasKey& HttpStreamPool::QuicAttempt::quic_session_alias_key()
const {
return manager_->group()->quic_session_alias_key();
}
QuicSessionPool* HttpStreamPool::QuicAttempt::quic_session_pool() {
return manager_->group()->http_network_session()->quic_session_pool();
}
void HttpStreamPool::QuicAttempt::OnSessionAttemptSlow() {
CHECK(!is_slow_);
is_slow_ = true;
manager_->OnQuicAttemptSlow();
}
void HttpStreamPool::QuicAttempt::OnSessionAttemptComplete(int rv) {
slow_timer_.Stop();
if (rv == OK) {
if (!manager_->CanUseExistingQuicSession()) {
// QUIC session is closed or marked broken before stream can be created.
rv = ERR_CONNECTION_CLOSED;
}
}
if (rv == OK &&
!quic_session_pool()->has_quic_ever_worked_on_current_network()) {
quic_session_pool()->set_has_quic_ever_worked_on_current_network(true);
}
result_ = rv;
QuicAttemptOutcome outcome(rv);
if (request_) {
outcome.session = request_->session();
outcome.error_details = request_->error_details();
}
request_.reset();
manager_->OnQuicAttemptComplete(std::move(outcome));
// `this` is deleted.
}
} // namespace net