• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2024 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/http/http_stream_pool_job.h"
6 
7 #include <memory>
8 #include <vector>
9 
10 #include "base/memory/raw_ptr.h"
11 #include "base/task/sequenced_task_runner.h"
12 #include "net/base/net_error_details.h"
13 #include "net/base/net_errors.h"
14 #include "net/base/net_export.h"
15 #include "net/base/port_util.h"
16 #include "net/dns/public/resolve_error_info.h"
17 #include "net/http/http_network_session.h"
18 #include "net/http/http_stream_pool.h"
19 #include "net/http/http_stream_pool_attempt_manager.h"
20 #include "net/http/http_stream_pool_group.h"
21 #include "net/proxy_resolution/proxy_resolution_service.h"
22 #include "net/socket/connection_attempts.h"
23 #include "net/socket/next_proto.h"
24 #include "net/socket/stream_socket.h"
25 #include "net/ssl/ssl_cert_request_info.h"
26 #include "net/ssl/ssl_info.h"
27 #include "net/third_party/quiche/src/quiche/quic/core/quic_versions.h"
28 
29 namespace net {
30 
31 namespace {
32 
CalculateAllowedAlpns(NextProto expected_protocol,bool is_http1_allowed)33 NextProtoSet CalculateAllowedAlpns(NextProto expected_protocol,
34                                    bool is_http1_allowed) {
35   NextProtoSet allowed_alpns = expected_protocol == NextProto::kProtoUnknown
36                                    ? NextProtoSet::All()
37                                    : NextProtoSet({expected_protocol});
38   if (!is_http1_allowed) {
39     static constexpr NextProtoSet kHttp11Protocols = {NextProto::kProtoUnknown,
40                                                       NextProto::kProtoHTTP11};
41     allowed_alpns.RemoveAll(kHttp11Protocols);
42   }
43   return allowed_alpns;
44 }
45 
46 }  // namespace
47 
Job(Delegate * delegate,AttemptManager * attempt_manager,quic::ParsedQuicVersion quic_version,NextProto expected_protocol,const NetLogWithSource & net_log)48 HttpStreamPool::Job::Job(Delegate* delegate,
49                          AttemptManager* attempt_manager,
50                          quic::ParsedQuicVersion quic_version,
51                          NextProto expected_protocol,
52                          const NetLogWithSource& net_log)
53     : delegate_(delegate),
54       attempt_manager_(attempt_manager),
55       quic_version_(quic_version),
56       allowed_alpns_(CalculateAllowedAlpns(expected_protocol,
57                                            delegate_->is_http1_allowed())),
58       net_log_(net_log) {
59   CHECK(delegate_->is_http1_allowed() ||
60         expected_protocol != NextProto::kProtoHTTP11);
61 }
62 
~Job()63 HttpStreamPool::Job::~Job() {
64   CHECK(attempt_manager_);
65   // `attempt_manager_` may be deleted after this call.
66   attempt_manager_.ExtractAsDangling()->OnJobComplete(this);
67 }
68 
Start()69 void HttpStreamPool::Job::Start() {
70   const url::SchemeHostPort& destination =
71       attempt_manager_->group()->stream_key().destination();
72   if (!IsPortAllowedForScheme(destination.port(), destination.scheme())) {
73     base::SequencedTaskRunner::GetCurrentDefault()->PostTask(
74         FROM_HERE,
75         base::BindOnce(&Job::OnStreamFailed, weak_ptr_factory_.GetWeakPtr(),
76                        ERR_UNSAFE_PORT, NetErrorDetails(), ResolveErrorInfo()));
77     return;
78   }
79 
80   attempt_manager_->StartJob(this, priority(), delegate_->allowed_bad_certs(),
81                              quic_version_, net_log_);
82 }
83 
GetLoadState() const84 LoadState HttpStreamPool::Job::GetLoadState() const {
85   CHECK(attempt_manager_);
86   return attempt_manager_->GetLoadState();
87 }
88 
SetPriority(RequestPriority priority)89 void HttpStreamPool::Job::SetPriority(RequestPriority priority) {
90   CHECK(attempt_manager_);
91   attempt_manager_->SetJobPriority(this, priority);
92 }
93 
AddConnectionAttempts(const ConnectionAttempts & attempts)94 void HttpStreamPool::Job::AddConnectionAttempts(
95     const ConnectionAttempts& attempts) {
96   for (const auto& attempt : attempts) {
97     connection_attempts_.emplace_back(attempt);
98   }
99 }
100 
OnStreamReady(std::unique_ptr<HttpStream> stream,NextProto negotiated_protocol)101 void HttpStreamPool::Job::OnStreamReady(std::unique_ptr<HttpStream> stream,
102                                         NextProto negotiated_protocol) {
103   CHECK(delegate_);
104 
105   int result = OK;
106   if (!allowed_alpns_.Has(negotiated_protocol)) {
107     const bool is_h2_or_h3_required = !delegate_->is_http1_allowed();
108     const bool is_h2_or_h3 = negotiated_protocol == NextProto::kProtoHTTP2 ||
109                              negotiated_protocol == NextProto::kProtoQUIC;
110     if (is_h2_or_h3_required && !is_h2_or_h3) {
111       result = ERR_H2_OR_QUIC_REQUIRED;
112     } else {
113       result = ERR_ALPN_NEGOTIATION_FAILED;
114     }
115   }
116 
117   if (result != OK) {
118     OnStreamFailed(result, NetErrorDetails(), ResolveErrorInfo());
119     return;
120   }
121 
122   attempt_manager_->group()
123       ->http_network_session()
124       ->proxy_resolution_service()
125       ->ReportSuccess(delegate_->proxy_info());
126   delegate_->OnStreamReady(this, std::move(stream), negotiated_protocol);
127 }
128 
OnStreamFailed(int status,const NetErrorDetails & net_error_details,ResolveErrorInfo resolve_error_info)129 void HttpStreamPool::Job::OnStreamFailed(
130     int status,
131     const NetErrorDetails& net_error_details,
132     ResolveErrorInfo resolve_error_info) {
133   CHECK(delegate_);
134   delegate_->OnStreamFailed(this, status, net_error_details,
135                             resolve_error_info);
136 }
137 
OnCertificateError(int status,const SSLInfo & ssl_info)138 void HttpStreamPool::Job::OnCertificateError(int status,
139                                              const SSLInfo& ssl_info) {
140   CHECK(delegate_);
141   delegate_->OnCertificateError(this, status, ssl_info);
142 }
143 
OnNeedsClientAuth(SSLCertRequestInfo * cert_info)144 void HttpStreamPool::Job::OnNeedsClientAuth(SSLCertRequestInfo* cert_info) {
145   CHECK(delegate_);
146   delegate_->OnNeedsClientAuth(this, cert_info);
147 }
148 
149 }  // namespace net
150