1 // Copyright 2018 The Chromium Authors. All rights reserved.
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 "services/network/resolve_host_request.h"
6
7 #include <utility>
8
9 #include "base/bind.h"
10 #include "base/logging.h"
11 #include "base/no_destructor.h"
12 #include "base/optional.h"
13 #include "net/base/net_errors.h"
14 #include "net/log/net_log.h"
15 #include "net/log/net_log_with_source.h"
16
17 namespace network {
18
ResolveHostRequest(net::HostResolver * resolver,const net::HostPortPair & host,const net::NetworkIsolationKey & network_isolation_key,const base::Optional<net::HostResolver::ResolveHostParameters> & optional_parameters,net::NetLog * net_log)19 ResolveHostRequest::ResolveHostRequest(
20 net::HostResolver* resolver,
21 const net::HostPortPair& host,
22 const net::NetworkIsolationKey& network_isolation_key,
23 const base::Optional<net::HostResolver::ResolveHostParameters>&
24 optional_parameters,
25 net::NetLog* net_log) {
26 DCHECK(resolver);
27
28 internal_request_ = resolver->CreateRequest(
29 host, network_isolation_key,
30 net::NetLogWithSource::Make(net_log, net::NetLogSourceType::NONE),
31 optional_parameters);
32 }
33
~ResolveHostRequest()34 ResolveHostRequest::~ResolveHostRequest() {
35 control_handle_receiver_.reset();
36
37 if (response_client_.is_bound()) {
38 response_client_->OnComplete(net::ERR_NAME_NOT_RESOLVED,
39 net::ResolveErrorInfo(net::ERR_FAILED),
40 base::nullopt);
41 response_client_.reset();
42 }
43 }
44
Start(mojo::PendingReceiver<mojom::ResolveHostHandle> control_handle_receiver,mojo::PendingRemote<mojom::ResolveHostClient> pending_response_client,net::CompletionOnceCallback callback)45 int ResolveHostRequest::Start(
46 mojo::PendingReceiver<mojom::ResolveHostHandle> control_handle_receiver,
47 mojo::PendingRemote<mojom::ResolveHostClient> pending_response_client,
48 net::CompletionOnceCallback callback) {
49 DCHECK(internal_request_);
50 DCHECK(!control_handle_receiver_.is_bound());
51 DCHECK(!response_client_.is_bound());
52
53 // Unretained |this| reference is safe because if |internal_request_| goes out
54 // of scope, it will cancel the request and ResolveHost() will not call the
55 // callback.
56 int rv = internal_request_->Start(
57 base::BindOnce(&ResolveHostRequest::OnComplete, base::Unretained(this)));
58 mojo::Remote<mojom::ResolveHostClient> response_client(
59 std::move(pending_response_client));
60 if (rv != net::ERR_IO_PENDING) {
61 response_client->OnComplete(rv, GetResolveErrorInfo(), GetAddressResults());
62 return rv;
63 }
64
65 if (control_handle_receiver)
66 control_handle_receiver_.Bind(std::move(control_handle_receiver));
67
68 response_client_ = std::move(response_client);
69 // Unretained |this| reference is safe because connection error cannot occur
70 // if |response_client_| goes out of scope.
71 response_client_.set_disconnect_handler(base::BindOnce(
72 &ResolveHostRequest::Cancel, base::Unretained(this), net::ERR_FAILED));
73
74 callback_ = std::move(callback);
75
76 return net::ERR_IO_PENDING;
77 }
78
Cancel(int error)79 void ResolveHostRequest::Cancel(int error) {
80 DCHECK_NE(net::OK, error);
81
82 if (cancelled_)
83 return;
84
85 internal_request_ = nullptr;
86 cancelled_ = true;
87 resolve_error_info_ = net::ResolveErrorInfo(error);
88 OnComplete(error);
89 }
90
OnComplete(int error)91 void ResolveHostRequest::OnComplete(int error) {
92 DCHECK(response_client_.is_bound());
93 DCHECK(callback_);
94
95 control_handle_receiver_.reset();
96 SignalNonAddressResults();
97 response_client_->OnComplete(error, GetResolveErrorInfo(),
98 GetAddressResults());
99 response_client_.reset();
100
101 // Invoke completion callback last as it may delete |this|.
102 std::move(callback_).Run(GetResolveErrorInfo().error);
103 }
104
GetResolveErrorInfo() const105 net::ResolveErrorInfo ResolveHostRequest::GetResolveErrorInfo() const {
106 if (cancelled_) {
107 return resolve_error_info_;
108 }
109
110 DCHECK(internal_request_);
111 return internal_request_->GetResolveErrorInfo();
112 }
113
GetAddressResults() const114 const base::Optional<net::AddressList>& ResolveHostRequest::GetAddressResults()
115 const {
116 if (cancelled_) {
117 static base::NoDestructor<base::Optional<net::AddressList>>
118 cancelled_result(base::nullopt);
119 return *cancelled_result;
120 }
121
122 DCHECK(internal_request_);
123 return internal_request_->GetAddressResults();
124 }
125
SignalNonAddressResults()126 void ResolveHostRequest::SignalNonAddressResults() {
127 if (cancelled_)
128 return;
129 DCHECK(internal_request_);
130
131 if (internal_request_->GetTextResults()) {
132 response_client_->OnTextResults(
133 internal_request_->GetTextResults().value());
134 }
135
136 if (internal_request_->GetHostnameResults()) {
137 response_client_->OnHostnameResults(
138 internal_request_->GetHostnameResults().value());
139 }
140 }
141
142 } // namespace network
143