1 // Copyright 2020 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/proxy_resolution/configured_proxy_resolution_request.h"
6
7 #include <utility>
8
9 #include "base/functional/bind.h"
10 #include "base/functional/callback_helpers.h"
11 #include "net/base/net_errors.h"
12 #include "net/log/net_log_event_type.h"
13 #include "net/proxy_resolution/configured_proxy_resolution_service.h"
14 #include "net/proxy_resolution/proxy_info.h"
15
16 namespace net {
17
ConfiguredProxyResolutionRequest(ConfiguredProxyResolutionService * service,const GURL & url,const std::string & method,const NetworkAnonymizationKey & network_anonymization_key,ProxyInfo * results,CompletionOnceCallback user_callback,const NetLogWithSource & net_log)18 ConfiguredProxyResolutionRequest::ConfiguredProxyResolutionRequest(
19 ConfiguredProxyResolutionService* service,
20 const GURL& url,
21 const std::string& method,
22 const NetworkAnonymizationKey& network_anonymization_key,
23 ProxyInfo* results,
24 CompletionOnceCallback user_callback,
25 const NetLogWithSource& net_log)
26 : service_(service),
27 user_callback_(std::move(user_callback)),
28 results_(results),
29 url_(url),
30 method_(method),
31 network_anonymization_key_(network_anonymization_key),
32 net_log_(net_log),
33 creation_time_(base::TimeTicks::Now()) {
34 DCHECK(!user_callback_.is_null());
35 }
36
~ConfiguredProxyResolutionRequest()37 ConfiguredProxyResolutionRequest::~ConfiguredProxyResolutionRequest() {
38 if (service_) {
39 service_->RemovePendingRequest(this);
40 net_log_.AddEvent(NetLogEventType::CANCELLED);
41
42 if (is_started())
43 CancelResolveJob();
44
45 // This should be emitted last, after any message |CancelResolveJob()| may
46 // trigger.
47 net_log_.EndEvent(NetLogEventType::PROXY_RESOLUTION_SERVICE);
48 }
49 }
50
51 // Starts the resolve proxy request.
Start()52 int ConfiguredProxyResolutionRequest::Start() {
53 DCHECK(!was_completed());
54 DCHECK(!is_started());
55
56 DCHECK(service_->config_);
57 traffic_annotation_ = MutableNetworkTrafficAnnotationTag(
58 service_->config_->traffic_annotation());
59
60 if (service_->ApplyPacBypassRules(url_, results_))
61 return OK;
62
63 return service_->GetProxyResolver()->GetProxyForURL(
64 url_, network_anonymization_key_, results_,
65 base::BindOnce(&ConfiguredProxyResolutionRequest::QueryComplete,
66 base::Unretained(this)),
67 &resolve_job_, net_log_);
68 }
69
70 void ConfiguredProxyResolutionRequest::
StartAndCompleteCheckingForSynchronous()71 StartAndCompleteCheckingForSynchronous() {
72 int rv = service_->TryToCompleteSynchronously(url_, results_);
73 if (rv == ERR_IO_PENDING)
74 rv = Start();
75 if (rv != ERR_IO_PENDING)
76 QueryComplete(rv);
77 }
78
CancelResolveJob()79 void ConfiguredProxyResolutionRequest::CancelResolveJob() {
80 DCHECK(is_started());
81 // The request may already be running in the resolver.
82 resolve_job_.reset();
83 DCHECK(!is_started());
84 }
85
QueryDidComplete(int result_code)86 int ConfiguredProxyResolutionRequest::QueryDidComplete(int result_code) {
87 DCHECK(!was_completed());
88
89 // Clear |resolve_job_| so is_started() returns false while
90 // DidFinishResolvingProxy() runs.
91 resolve_job_.reset();
92
93 // Note that DidFinishResolvingProxy might modify |results_|.
94 int rv = service_->DidFinishResolvingProxy(url_, network_anonymization_key_,
95 method_, results_, result_code,
96 net_log_);
97
98 // Make a note in the results which configuration was in use at the
99 // time of the resolve.
100 results_->set_proxy_resolve_start_time(creation_time_);
101 results_->set_proxy_resolve_end_time(base::TimeTicks::Now());
102
103 // If annotation is not already set, e.g. through TryToCompleteSynchronously
104 // function, use in-progress-resolve annotation.
105 if (!results_->traffic_annotation().is_valid())
106 results_->set_traffic_annotation(traffic_annotation_);
107
108 // If proxy is set without error, ensure that an annotation is provided.
109 if (result_code != ERR_ABORTED && !rv)
110 DCHECK(results_->traffic_annotation().is_valid());
111
112 // Reset the state associated with in-progress-resolve.
113 traffic_annotation_.reset();
114
115 return rv;
116 }
117
QueryDidCompleteSynchronously(int result_code)118 int ConfiguredProxyResolutionRequest::QueryDidCompleteSynchronously(
119 int result_code) {
120 int rv = QueryDidComplete(result_code);
121 service_ = nullptr;
122 return rv;
123 }
124
GetLoadState() const125 LoadState ConfiguredProxyResolutionRequest::GetLoadState() const {
126 LoadState load_state = LOAD_STATE_IDLE;
127 if (service_ && service_->GetLoadStateIfAvailable(&load_state))
128 return load_state;
129
130 if (is_started())
131 return resolve_job_->GetLoadState();
132 return LOAD_STATE_RESOLVING_PROXY_FOR_URL;
133 }
134
135 // Callback for when the ProxyResolver request has completed.
QueryComplete(int result_code)136 void ConfiguredProxyResolutionRequest::QueryComplete(int result_code) {
137 result_code = QueryDidComplete(result_code);
138
139 CompletionOnceCallback callback = std::move(user_callback_);
140
141 service_->RemovePendingRequest(this);
142 service_ = nullptr;
143 user_callback_.Reset();
144 std::move(callback).Run(result_code);
145 }
146
147 } // namespace net
148