1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. Use of this
2 // source code is governed by a BSD-style license that can be found in the
3 // LICENSE file.
4
5 #include "net/proxy/proxy_resolver_js_bindings.h"
6
7 #include "base/compiler_specific.h"
8 #include "base/logging.h"
9 #include "base/message_loop.h"
10 #include "base/waitable_event.h"
11 #include "net/base/address_list.h"
12 #include "net/base/host_resolver.h"
13 #include "net/base/net_errors.h"
14 #include "net/base/net_util.h"
15 #include "net/base/sys_addrinfo.h"
16
17 namespace net {
18 namespace {
19
20 // Wrapper around HostResolver to give a sync API while running the resolve
21 // in async mode on |host_resolver_loop|. If |host_resolver_loop| is NULL,
22 // runs sync on the current thread (this mode is just used by testing).
23 class SyncHostResolverBridge
24 : public base::RefCountedThreadSafe<SyncHostResolverBridge> {
25 public:
SyncHostResolverBridge(HostResolver * host_resolver,MessageLoop * host_resolver_loop)26 SyncHostResolverBridge(HostResolver* host_resolver,
27 MessageLoop* host_resolver_loop)
28 : host_resolver_(host_resolver),
29 host_resolver_loop_(host_resolver_loop),
30 event_(false, false),
31 ALLOW_THIS_IN_INITIALIZER_LIST(
32 callback_(this, &SyncHostResolverBridge::OnResolveCompletion)) {
33 }
34
35 // Run the resolve on host_resolver_loop, and wait for result.
Resolve(const std::string & hostname,AddressFamily address_family,net::AddressList * addresses)36 int Resolve(const std::string& hostname,
37 AddressFamily address_family,
38 net::AddressList* addresses) {
39 // Port number doesn't matter.
40 HostResolver::RequestInfo info(hostname, 80);
41 info.set_address_family(address_family);
42
43 // Hack for tests -- run synchronously on current thread.
44 if (!host_resolver_loop_)
45 return host_resolver_->Resolve(info, addresses, NULL, NULL, NULL);
46
47 // Otherwise start an async resolve on the resolver's thread.
48 host_resolver_loop_->PostTask(FROM_HERE, NewRunnableMethod(this,
49 &SyncHostResolverBridge::StartResolve, info, addresses));
50
51 // Wait for the resolve to complete in the resolver's thread.
52 event_.Wait();
53 return err_;
54 }
55
56 private:
57 friend class base::RefCountedThreadSafe<SyncHostResolverBridge>;
58
~SyncHostResolverBridge()59 ~SyncHostResolverBridge() {}
60
61 // Called on host_resolver_loop_.
StartResolve(const HostResolver::RequestInfo & info,net::AddressList * addresses)62 void StartResolve(const HostResolver::RequestInfo& info,
63 net::AddressList* addresses) {
64 DCHECK_EQ(host_resolver_loop_, MessageLoop::current());
65 int error = host_resolver_->Resolve(
66 info, addresses, &callback_, NULL, NULL);
67 if (error != ERR_IO_PENDING)
68 OnResolveCompletion(error); // Completed synchronously.
69 }
70
71 // Called on host_resolver_loop_.
OnResolveCompletion(int result)72 void OnResolveCompletion(int result) {
73 DCHECK_EQ(host_resolver_loop_, MessageLoop::current());
74 err_ = result;
75 event_.Signal();
76 }
77
78 scoped_refptr<HostResolver> host_resolver_;
79 MessageLoop* host_resolver_loop_;
80
81 // Event to notify completion of resolve request.
82 base::WaitableEvent event_;
83
84 // Callback for when the resolve completes on host_resolver_loop_.
85 net::CompletionCallbackImpl<SyncHostResolverBridge> callback_;
86
87 // The result from the result request (set by in host_resolver_loop_).
88 int err_;
89 };
90
91 // ProxyResolverJSBindings implementation.
92 class DefaultJSBindings : public ProxyResolverJSBindings {
93 public:
DefaultJSBindings(HostResolver * host_resolver,MessageLoop * host_resolver_loop)94 DefaultJSBindings(HostResolver* host_resolver,
95 MessageLoop* host_resolver_loop)
96 : host_resolver_(new SyncHostResolverBridge(
97 host_resolver, host_resolver_loop)) {}
98
99 // Handler for "alert(message)".
Alert(const std::string & message)100 virtual void Alert(const std::string& message) {
101 LOG(INFO) << "PAC-alert: " << message;
102 }
103
104 // Handler for "myIpAddress()". Returns empty string on failure.
105 // TODO(eroman): Perhaps enumerate the interfaces directly, using
106 // getifaddrs().
MyIpAddress()107 virtual std::string MyIpAddress() {
108 // DnsResolve("") returns "", so no need to check for failure.
109 return DnsResolve(GetHostName());
110 }
111
112 // Handler for "myIpAddressEx()". Returns empty string on failure.
MyIpAddressEx()113 virtual std::string MyIpAddressEx() {
114 return DnsResolveEx(GetHostName());
115 }
116
117 // Handler for "dnsResolve(host)". Returns empty string on failure.
DnsResolve(const std::string & host)118 virtual std::string DnsResolve(const std::string& host) {
119 // Do a sync resolve of the hostname.
120 // Disable IPv6 results. We do this because the PAC specification isn't
121 // really IPv6 friendly, and Internet Explorer also restricts to IPv4.
122 // Consequently a lot of existing PAC scripts assume they will only get
123 // IPv4 results, and will misbehave if they get an IPv6 result.
124 // See http://crbug.com/24641 for more details.
125 net::AddressList address_list;
126 int result = host_resolver_->Resolve(host,
127 ADDRESS_FAMILY_IPV4,
128 &address_list);
129
130 if (result != OK)
131 return std::string(); // Failed.
132
133 if (!address_list.head())
134 return std::string();
135
136 // There may be multiple results; we will just use the first one.
137 // This returns empty string on failure.
138 return net::NetAddressToString(address_list.head());
139 }
140
141 // Handler for "dnsResolveEx(host)". Returns empty string on failure.
DnsResolveEx(const std::string & host)142 virtual std::string DnsResolveEx(const std::string& host) {
143 // Do a sync resolve of the hostname.
144 net::AddressList address_list;
145 int result = host_resolver_->Resolve(host,
146 ADDRESS_FAMILY_UNSPECIFIED,
147 &address_list);
148
149 if (result != OK)
150 return std::string(); // Failed.
151
152 // Stringify all of the addresses in the address list, separated
153 // by semicolons.
154 std::string address_list_str;
155 const struct addrinfo* current_address = address_list.head();
156 while (current_address) {
157 if (!address_list_str.empty())
158 address_list_str += ";";
159 address_list_str += net::NetAddressToString(current_address);
160 current_address = current_address->ai_next;
161 }
162
163 return address_list_str;
164 }
165
166 // Handler for when an error is encountered. |line_number| may be -1.
OnError(int line_number,const std::string & message)167 virtual void OnError(int line_number, const std::string& message) {
168 if (line_number == -1)
169 LOG(INFO) << "PAC-error: " << message;
170 else
171 LOG(INFO) << "PAC-error: " << "line: " << line_number << ": " << message;
172 }
173
174 private:
175 scoped_refptr<SyncHostResolverBridge> host_resolver_;
176 };
177
178 } // namespace
179
180 // static
CreateDefault(HostResolver * host_resolver,MessageLoop * host_resolver_loop)181 ProxyResolverJSBindings* ProxyResolverJSBindings::CreateDefault(
182 HostResolver* host_resolver, MessageLoop* host_resolver_loop) {
183 return new DefaultJSBindings(host_resolver, host_resolver_loop);
184 }
185
186 } // namespace net
187