• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2010 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 "net/proxy/proxy_resolver_js_bindings.h"
6 
7 #include "base/logging.h"
8 #include "base/string_util.h"
9 #include "base/values.h"
10 #include "net/base/address_list.h"
11 #include "net/base/host_cache.h"
12 #include "net/base/host_resolver.h"
13 #include "net/base/net_errors.h"
14 #include "net/base/net_log.h"
15 #include "net/base/net_util.h"
16 #include "net/base/sys_addrinfo.h"
17 #include "net/proxy/proxy_resolver_request_context.h"
18 
19 namespace net {
20 
21 namespace {
22 
23 // Event parameters for a PAC error message (line number + message).
24 class ErrorNetlogParams : public NetLog::EventParameters {
25  public:
ErrorNetlogParams(int line_number,const string16 & message)26   ErrorNetlogParams(int line_number,
27                     const string16& message)
28       : line_number_(line_number),
29         message_(message) {
30   }
31 
ToValue() const32   virtual Value* ToValue() const {
33     DictionaryValue* dict = new DictionaryValue();
34     dict->SetInteger("line_number", line_number_);
35     dict->SetString("message", message_);
36     return dict;
37   }
38 
39  private:
40   const int line_number_;
41   const string16 message_;
42 
43   DISALLOW_COPY_AND_ASSIGN(ErrorNetlogParams);
44 };
45 
46 // Event parameters for a PAC alert().
47 class AlertNetlogParams : public NetLog::EventParameters {
48  public:
AlertNetlogParams(const string16 & message)49   explicit AlertNetlogParams(const string16& message) : message_(message) {
50   }
51 
ToValue() const52   virtual Value* ToValue() const {
53     DictionaryValue* dict = new DictionaryValue();
54     dict->SetString("message", message_);
55     return dict;
56   }
57 
58  private:
59   const string16 message_;
60 
61   DISALLOW_COPY_AND_ASSIGN(AlertNetlogParams);
62 };
63 
64 // ProxyResolverJSBindings implementation.
65 class DefaultJSBindings : public ProxyResolverJSBindings {
66  public:
DefaultJSBindings(HostResolver * host_resolver,NetLog * net_log)67   DefaultJSBindings(HostResolver* host_resolver, NetLog* net_log)
68       : host_resolver_(host_resolver),
69         net_log_(net_log) {
70   }
71 
72   // Handler for "alert(message)".
Alert(const string16 & message)73   virtual void Alert(const string16& message) {
74     VLOG(1) << "PAC-alert: " << message;
75 
76     // Send to the NetLog.
77     LogEventToCurrentRequestAndGlobally(NetLog::TYPE_PAC_JAVASCRIPT_ALERT,
78                                         new AlertNetlogParams(message));
79   }
80 
81   // Handler for "myIpAddress()".
82   // TODO(eroman): Perhaps enumerate the interfaces directly, using
83   // getifaddrs().
MyIpAddress(std::string * first_ip_address)84   virtual bool MyIpAddress(std::string* first_ip_address) {
85     LogEventToCurrentRequest(NetLog::PHASE_BEGIN,
86                              NetLog::TYPE_PAC_JAVASCRIPT_MY_IP_ADDRESS,
87                              NULL);
88 
89     bool ok = MyIpAddressImpl(first_ip_address);
90 
91     LogEventToCurrentRequest(NetLog::PHASE_END,
92                              NetLog::TYPE_PAC_JAVASCRIPT_MY_IP_ADDRESS,
93                              NULL);
94     return ok;
95   }
96 
97   // Handler for "myIpAddressEx()".
MyIpAddressEx(std::string * ip_address_list)98   virtual bool MyIpAddressEx(std::string* ip_address_list) {
99     LogEventToCurrentRequest(NetLog::PHASE_BEGIN,
100                              NetLog::TYPE_PAC_JAVASCRIPT_MY_IP_ADDRESS_EX,
101                              NULL);
102 
103     bool ok = MyIpAddressExImpl(ip_address_list);
104 
105     LogEventToCurrentRequest(NetLog::PHASE_END,
106                              NetLog::TYPE_PAC_JAVASCRIPT_MY_IP_ADDRESS_EX,
107                              NULL);
108     return ok;
109   }
110 
111   // Handler for "dnsResolve(host)".
DnsResolve(const std::string & host,std::string * first_ip_address)112   virtual bool DnsResolve(const std::string& host,
113                           std::string* first_ip_address) {
114     LogEventToCurrentRequest(NetLog::PHASE_BEGIN,
115                              NetLog::TYPE_PAC_JAVASCRIPT_DNS_RESOLVE,
116                              NULL);
117 
118     bool ok = DnsResolveImpl(host, first_ip_address);
119 
120     LogEventToCurrentRequest(NetLog::PHASE_END,
121                              NetLog::TYPE_PAC_JAVASCRIPT_DNS_RESOLVE,
122                              NULL);
123     return ok;
124   }
125 
126   // Handler for "dnsResolveEx(host)".
DnsResolveEx(const std::string & host,std::string * ip_address_list)127   virtual bool DnsResolveEx(const std::string& host,
128                             std::string* ip_address_list) {
129     LogEventToCurrentRequest(NetLog::PHASE_BEGIN,
130                              NetLog::TYPE_PAC_JAVASCRIPT_DNS_RESOLVE_EX,
131                              NULL);
132 
133     bool ok = DnsResolveExImpl(host, ip_address_list);
134 
135     LogEventToCurrentRequest(NetLog::PHASE_END,
136                              NetLog::TYPE_PAC_JAVASCRIPT_DNS_RESOLVE_EX,
137                              NULL);
138     return ok;
139   }
140 
141   // Handler for when an error is encountered. |line_number| may be -1.
OnError(int line_number,const string16 & message)142   virtual void OnError(int line_number, const string16& message) {
143     // Send to the chrome log.
144     if (line_number == -1)
145       VLOG(1) << "PAC-error: " << message;
146     else
147       VLOG(1) << "PAC-error: " << "line: " << line_number << ": " << message;
148 
149     // Send the error to the NetLog.
150     LogEventToCurrentRequestAndGlobally(
151         NetLog::TYPE_PAC_JAVASCRIPT_ERROR,
152         new ErrorNetlogParams(line_number, message));
153   }
154 
Shutdown()155   virtual void Shutdown() {
156     host_resolver_->Shutdown();
157   }
158 
159  private:
MyIpAddressImpl(std::string * first_ip_address)160   bool MyIpAddressImpl(std::string* first_ip_address) {
161     std::string my_hostname = GetHostName();
162     if (my_hostname.empty())
163       return false;
164     return DnsResolveImpl(my_hostname, first_ip_address);
165   }
166 
MyIpAddressExImpl(std::string * ip_address_list)167   bool MyIpAddressExImpl(std::string* ip_address_list) {
168     std::string my_hostname = GetHostName();
169     if (my_hostname.empty())
170       return false;
171     return DnsResolveExImpl(my_hostname, ip_address_list);
172   }
173 
DnsResolveImpl(const std::string & host,std::string * first_ip_address)174   bool DnsResolveImpl(const std::string& host,
175                       std::string* first_ip_address) {
176     // Do a sync resolve of the hostname (port doesn't matter).
177     // Disable IPv6 results. We do this because the PAC specification isn't
178     // really IPv6 friendly, and Internet Explorer also restricts to IPv4.
179     // Consequently a lot of existing PAC scripts assume they will only get
180     // IPv4 results, and will misbehave if they get an IPv6 result.
181     // See http://crbug.com/24641 for more details.
182     HostResolver::RequestInfo info(HostPortPair(host, 80));
183     info.set_address_family(ADDRESS_FAMILY_IPV4);
184     AddressList address_list;
185 
186     int result = DnsResolveHelper(info, &address_list);
187     if (result != OK)
188       return false;
189 
190     // There may be multiple results; we will just use the first one.
191     // This returns empty string on failure.
192     *first_ip_address = net::NetAddressToString(address_list.head());
193     if (first_ip_address->empty())
194       return false;
195 
196     return true;
197   }
198 
DnsResolveExImpl(const std::string & host,std::string * ip_address_list)199   bool DnsResolveExImpl(const std::string& host,
200                         std::string* ip_address_list) {
201     // Do a sync resolve of the hostname (port doesn't matter).
202     HostResolver::RequestInfo info(HostPortPair(host, 80));
203     AddressList address_list;
204     int result = DnsResolveHelper(info, &address_list);
205 
206     if (result != OK)
207       return false;
208 
209     // Stringify all of the addresses in the address list, separated
210     // by semicolons.
211     std::string address_list_str;
212     const struct addrinfo* current_address = address_list.head();
213     while (current_address) {
214       if (!address_list_str.empty())
215         address_list_str += ";";
216       const std::string address_string = NetAddressToString(current_address);
217       if (address_string.empty())
218         return false;
219       address_list_str += address_string;
220       current_address = current_address->ai_next;
221     }
222 
223     *ip_address_list = address_list_str;
224     return true;
225   }
226 
227   // Helper to execute a synchronous DNS resolve, using the per-request
228   // DNS cache if there is one.
DnsResolveHelper(const HostResolver::RequestInfo & info,AddressList * address_list)229   int DnsResolveHelper(const HostResolver::RequestInfo& info,
230                        AddressList* address_list) {
231     HostCache::Key cache_key(info.hostname(),
232                              info.address_family(),
233                              info.host_resolver_flags());
234 
235     HostCache* host_cache = current_request_context() ?
236         current_request_context()->host_cache : NULL;
237 
238     // First try to service this request from the per-request DNS cache.
239     // (we cache DNS failures much more aggressively within the context
240     // of a FindProxyForURL() request).
241     if (host_cache) {
242       const HostCache::Entry* entry =
243           host_cache->Lookup(cache_key, base::TimeTicks::Now());
244       if (entry) {
245         if (entry->error == OK)
246           *address_list = entry->addrlist;
247         return entry->error;
248       }
249     }
250 
251     // Otherwise ask the resolver.
252     int result = host_resolver_->Resolve(info, address_list, NULL, NULL,
253                                          BoundNetLog());
254 
255     // Save the result back to the per-request DNS cache.
256     if (host_cache) {
257       host_cache->Set(cache_key, result, *address_list,
258                       base::TimeTicks::Now());
259     }
260 
261     return result;
262   }
263 
LogEventToCurrentRequest(NetLog::EventPhase phase,NetLog::EventType type,scoped_refptr<NetLog::EventParameters> params)264   void LogEventToCurrentRequest(
265       NetLog::EventPhase phase,
266       NetLog::EventType type,
267       scoped_refptr<NetLog::EventParameters> params) {
268     if (current_request_context() && current_request_context()->net_log)
269       current_request_context()->net_log->AddEntry(type, phase, params);
270   }
271 
LogEventToCurrentRequestAndGlobally(NetLog::EventType type,scoped_refptr<NetLog::EventParameters> params)272   void LogEventToCurrentRequestAndGlobally(
273       NetLog::EventType type,
274       scoped_refptr<NetLog::EventParameters> params) {
275     LogEventToCurrentRequest(NetLog::PHASE_NONE, type, params);
276 
277     // Emit to the global NetLog event stream.
278     if (net_log_) {
279       net_log_->AddEntry(
280           type,
281           base::TimeTicks::Now(),
282           NetLog::Source(),
283           NetLog::PHASE_NONE,
284           params);
285     }
286   }
287 
288   HostResolver* const host_resolver_;
289   NetLog* net_log_;
290 };
291 
292 }  // namespace
293 
294 // static
CreateDefault(HostResolver * host_resolver,NetLog * net_log)295 ProxyResolverJSBindings* ProxyResolverJSBindings::CreateDefault(
296     HostResolver* host_resolver, NetLog* net_log) {
297   return new DefaultJSBindings(host_resolver, net_log);
298 }
299 
300 }  // namespace net
301