• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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