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