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