| OLD | NEW |
| 1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. Use of this | 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 | 2 // source code is governed by a BSD-style license that can be found in the |
| 3 // LICENSE file. | 3 // LICENSE file. |
| 4 | 4 |
| 5 #include "net/proxy/proxy_resolver_v8.h" | 5 #include "net/proxy/proxy_resolver_v8.h" |
| 6 | 6 |
| 7 #include "base/compiler_specific.h" |
| 7 #include "base/logging.h" | 8 #include "base/logging.h" |
| 9 #include "base/message_loop.h" |
| 10 #include "base/waitable_event.h" |
| 8 #include "base/string_util.h" | 11 #include "base/string_util.h" |
| 9 #include "googleurl/src/gurl.h" | 12 #include "googleurl/src/gurl.h" |
| 10 #include "net/base/address_list.h" | 13 #include "net/base/address_list.h" |
| 11 #include "net/base/host_resolver.h" | 14 #include "net/base/host_resolver.h" |
| 12 #include "net/base/net_errors.h" | 15 #include "net/base/net_errors.h" |
| 13 #include "net/base/net_util.h" | 16 #include "net/base/net_util.h" |
| 14 #include "net/proxy/proxy_info.h" | 17 #include "net/proxy/proxy_info.h" |
| 15 #include "net/proxy/proxy_resolver_script.h" | 18 #include "net/proxy/proxy_resolver_script.h" |
| 16 #include "v8/include/v8.h" | 19 #include "v8/include/v8.h" |
| 17 | 20 |
| (...skipping 25 matching lines...) Expand all Loading... |
| 43 return false; | 46 return false; |
| 44 | 47 |
| 45 v8::HandleScope scope; | 48 v8::HandleScope scope; |
| 46 v8::Local<v8::String> str_object = object->ToString(); | 49 v8::Local<v8::String> str_object = object->ToString(); |
| 47 if (str_object.IsEmpty()) | 50 if (str_object.IsEmpty()) |
| 48 return false; | 51 return false; |
| 49 *result = V8StringToStdString(str_object); | 52 *result = V8StringToStdString(str_object); |
| 50 return true; | 53 return true; |
| 51 } | 54 } |
| 52 | 55 |
| 56 // Wrapper around HostResolver to give a sync API while running the resolve |
| 57 // in async mode on |host_resolver_loop|. If |host_resolver_loop| is NULL, |
| 58 // runs sync on the current thread (this mode is just used by testing). |
| 59 class SyncHostResolverBridge |
| 60 : public base::RefCountedThreadSafe<SyncHostResolverBridge> { |
| 61 public: |
| 62 SyncHostResolverBridge(HostResolver* host_resolver, |
| 63 MessageLoop* host_resolver_loop) |
| 64 : host_resolver_(host_resolver), |
| 65 host_resolver_loop_(host_resolver_loop), |
| 66 event_(false, false), |
| 67 ALLOW_THIS_IN_INITIALIZER_LIST( |
| 68 callback_(this, &SyncHostResolverBridge::OnResolveCompletion)) { |
| 69 } |
| 70 |
| 71 // Run the resolve on host_resolver_loop, and wait for result. |
| 72 int Resolve(const std::string& hostname, net::AddressList* addresses) { |
| 73 int kPort = 80; // Doesn't matter. |
| 74 |
| 75 // Hack for tests -- run synchronously on current thread. |
| 76 if (!host_resolver_loop_) |
| 77 return host_resolver_->Resolve(hostname, kPort, addresses, NULL, NULL); |
| 78 |
| 79 // Otherwise start an async resolve on the resolver's thread. |
| 80 host_resolver_loop_->PostTask(FROM_HERE, NewRunnableMethod(this, |
| 81 &SyncHostResolverBridge::StartResolve, hostname, kPort, addresses)); |
| 82 |
| 83 // Wait for the resolve to complete in the resolver's thread. |
| 84 event_.Wait(); |
| 85 return err_; |
| 86 } |
| 87 |
| 88 private: |
| 89 // Called on host_resolver_loop_. |
| 90 void StartResolve(const std::string& hostname, |
| 91 int port, |
| 92 net::AddressList* addresses) { |
| 93 DCHECK_EQ(host_resolver_loop_, MessageLoop::current()); |
| 94 int error = host_resolver_->Resolve( |
| 95 hostname, port, addresses, &callback_, NULL); |
| 96 if (error != ERR_IO_PENDING) |
| 97 OnResolveCompletion(error); // Completed synchronously. |
| 98 } |
| 99 |
| 100 // Called on host_resolver_loop_. |
| 101 void OnResolveCompletion(int result) { |
| 102 DCHECK_EQ(host_resolver_loop_, MessageLoop::current()); |
| 103 err_ = result; |
| 104 event_.Signal(); |
| 105 } |
| 106 |
| 107 HostResolver* host_resolver_; |
| 108 MessageLoop* host_resolver_loop_; |
| 109 |
| 110 // Event to notify completion of resolve request. |
| 111 base::WaitableEvent event_; |
| 112 |
| 113 // Callback for when the resolve completes on host_resolver_loop_. |
| 114 net::CompletionCallbackImpl<SyncHostResolverBridge> callback_; |
| 115 |
| 116 // The result from the result request (set by in host_resolver_loop_). |
| 117 int err_; |
| 118 }; |
| 119 |
| 53 // JSBIndings implementation. | 120 // JSBIndings implementation. |
| 54 class DefaultJSBindings : public ProxyResolverV8::JSBindings { | 121 class DefaultJSBindings : public ProxyResolverV8::JSBindings { |
| 55 public: | 122 public: |
| 123 DefaultJSBindings(HostResolver* host_resolver, |
| 124 MessageLoop* host_resolver_loop) |
| 125 : host_resolver_(new SyncHostResolverBridge( |
| 126 host_resolver, host_resolver_loop)) {} |
| 127 |
| 56 // Handler for "alert(message)". | 128 // Handler for "alert(message)". |
| 57 virtual void Alert(const std::string& message) { | 129 virtual void Alert(const std::string& message) { |
| 58 LOG(INFO) << "PAC-alert: " << message; | 130 LOG(INFO) << "PAC-alert: " << message; |
| 59 } | 131 } |
| 60 | 132 |
| 61 // Handler for "myIpAddress()". Returns empty string on failure. | 133 // Handler for "myIpAddress()". Returns empty string on failure. |
| 62 virtual std::string MyIpAddress() { | 134 virtual std::string MyIpAddress() { |
| 63 // DnsResolve("") returns "", so no need to check for failure. | 135 // DnsResolve("") returns "", so no need to check for failure. |
| 64 return DnsResolve(GetHostName()); | 136 return DnsResolve(GetHostName()); |
| 65 } | 137 } |
| 66 | 138 |
| 67 // Handler for "dnsResolve(host)". Returns empty string on failure. | 139 // Handler for "dnsResolve(host)". Returns empty string on failure. |
| 68 virtual std::string DnsResolve(const std::string& host) { | 140 virtual std::string DnsResolve(const std::string& host) { |
| 69 // TODO(eroman): Should this return our IP address, or fail, or | 141 // TODO(eroman): Should this return our IP address, or fail, or |
| 70 // simply be unspecified (works differently on windows and mac os x). | 142 // simply be unspecified (works differently on windows and mac os x). |
| 71 if (host.empty()) | 143 if (host.empty()) |
| 72 return std::string(); | 144 return std::string(); |
| 73 | 145 |
| 74 // Try to resolve synchronously. | 146 // Do a sync resolve of the hostname. |
| 75 net::AddressList address_list; | 147 net::AddressList address_list; |
| 76 const int kPort = 80; // Doesn't matter what this is. | 148 int result = host_resolver_->Resolve(host, &address_list); |
| 77 int result = host_resolver_.Resolve(host, kPort, &address_list, NULL); | |
| 78 | 149 |
| 79 if (result != OK) | 150 if (result != OK) |
| 80 return std::string(); // Failed. | 151 return std::string(); // Failed. |
| 81 | 152 |
| 82 if (!address_list.head()) | 153 if (!address_list.head()) |
| 83 return std::string(); | 154 return std::string(); |
| 84 | 155 |
| 85 // There may be multiple results; we will just use the first one. | 156 // There may be multiple results; we will just use the first one. |
| 86 // This returns empty string on failure. | 157 // This returns empty string on failure. |
| 87 return net::NetAddressToString(address_list.head()); | 158 return net::NetAddressToString(address_list.head()); |
| 88 } | 159 } |
| 89 | 160 |
| 90 // Handler for when an error is encountered. |line_number| may be -1. | 161 // Handler for when an error is encountered. |line_number| may be -1. |
| 91 virtual void OnError(int line_number, const std::string& message) { | 162 virtual void OnError(int line_number, const std::string& message) { |
| 92 if (line_number == -1) | 163 if (line_number == -1) |
| 93 LOG(INFO) << "PAC-error: " << message; | 164 LOG(INFO) << "PAC-error: " << message; |
| 94 else | 165 else |
| 95 LOG(INFO) << "PAC-error: " << "line: " << line_number << ": " << message; | 166 LOG(INFO) << "PAC-error: " << "line: " << line_number << ": " << message; |
| 96 } | 167 } |
| 97 | 168 |
| 98 private: | 169 private: |
| 99 HostResolver host_resolver_; | 170 scoped_refptr<SyncHostResolverBridge> host_resolver_; |
| 100 }; | 171 }; |
| 101 | 172 |
| 102 } // namespace | 173 } // namespace |
| 103 | 174 |
| 104 // ProxyResolverV8::Context --------------------------------------------------- | 175 // ProxyResolverV8::Context --------------------------------------------------- |
| 105 | 176 |
| 106 class ProxyResolverV8::Context { | 177 class ProxyResolverV8::Context { |
| 107 public: | 178 public: |
| 108 Context(JSBindings* js_bindings, const std::string& pac_data) | 179 Context(JSBindings* js_bindings, const std::string& pac_data) |
| 109 : js_bindings_(js_bindings) { | 180 : js_bindings_(js_bindings) { |
| 110 DCHECK(js_bindings != NULL); | 181 DCHECK(js_bindings != NULL); |
| 111 InitV8(pac_data); | 182 InitV8(pac_data); |
| 112 } | 183 } |
| 113 | 184 |
| 114 ~Context() { | 185 ~Context() { |
| 115 v8::Locker locked; | 186 v8::Locker locked; |
| 116 | 187 |
| 117 v8_this_.Dispose(); | 188 v8_this_.Dispose(); |
| 118 v8_context_.Dispose(); | 189 v8_context_.Dispose(); |
| 119 } | 190 } |
| (...skipping 139 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 259 return v8::Undefined(); | 330 return v8::Undefined(); |
| 260 } | 331 } |
| 261 | 332 |
| 262 std::string result = context->js_bindings_->DnsResolve(host); | 333 std::string result = context->js_bindings_->DnsResolve(host); |
| 263 | 334 |
| 264 // DoDnsResolve() returns empty string on failure. | 335 // DoDnsResolve() returns empty string on failure. |
| 265 return result.empty() ? v8::Null() : StdStringToV8String(result); | 336 return result.empty() ? v8::Null() : StdStringToV8String(result); |
| 266 } | 337 } |
| 267 | 338 |
| 268 JSBindings* js_bindings_; | 339 JSBindings* js_bindings_; |
| 269 HostResolver host_resolver_; | |
| 270 v8::Persistent<v8::External> v8_this_; | 340 v8::Persistent<v8::External> v8_this_; |
| 271 v8::Persistent<v8::Context> v8_context_; | 341 v8::Persistent<v8::Context> v8_context_; |
| 272 }; | 342 }; |
| 273 | 343 |
| 274 // ProxyResolverV8 ------------------------------------------------------------ | 344 // ProxyResolverV8 ------------------------------------------------------------ |
| 275 | 345 |
| 276 // the |false| argument to ProxyResolver means the ProxyService will handle | |
| 277 // downloading of the PAC script, and notify changes through SetPacScript(). | |
| 278 ProxyResolverV8::ProxyResolverV8() | |
| 279 : ProxyResolver(false /*does_fetch*/), | |
| 280 js_bindings_(new DefaultJSBindings()) { | |
| 281 } | |
| 282 | |
| 283 ProxyResolverV8::ProxyResolverV8( | 346 ProxyResolverV8::ProxyResolverV8( |
| 284 ProxyResolverV8::JSBindings* custom_js_bindings) | 347 ProxyResolverV8::JSBindings* custom_js_bindings) |
| 285 : ProxyResolver(false), js_bindings_(custom_js_bindings) { | 348 : ProxyResolver(false), js_bindings_(custom_js_bindings) { |
| 286 } | 349 } |
| 287 | 350 |
| 288 ProxyResolverV8::~ProxyResolverV8() {} | 351 ProxyResolverV8::~ProxyResolverV8() {} |
| 289 | 352 |
| 290 int ProxyResolverV8::GetProxyForURL(const GURL& query_url, | 353 int ProxyResolverV8::GetProxyForURL(const GURL& query_url, |
| 291 const GURL& /*pac_url*/, | 354 const GURL& /*pac_url*/, |
| 292 ProxyInfo* results) { | 355 ProxyInfo* results) { |
| 293 // If the V8 instance has not been initialized (either because SetPacScript() | 356 // If the V8 instance has not been initialized (either because SetPacScript() |
| 294 // wasn't called yet, or because it was called with empty string). | 357 // wasn't called yet, or because it was called with empty string). |
| 295 if (!context_.get()) | 358 if (!context_.get()) |
| 296 return ERR_FAILED; | 359 return ERR_FAILED; |
| 297 | 360 |
| 298 // Otherwise call into V8. | 361 // Otherwise call into V8. |
| 299 return context_->ResolveProxy(query_url, results); | 362 return context_->ResolveProxy(query_url, results); |
| 300 } | 363 } |
| 301 | 364 |
| 302 void ProxyResolverV8::SetPacScript(const std::string& data) { | 365 void ProxyResolverV8::SetPacScript(const std::string& data) { |
| 303 context_.reset(); | 366 context_.reset(); |
| 304 if (!data.empty()) | 367 if (!data.empty()) |
| 305 context_.reset(new Context(js_bindings_.get(), data)); | 368 context_.reset(new Context(js_bindings_.get(), data)); |
| 306 } | 369 } |
| 307 | 370 |
| 371 // static |
| 372 ProxyResolverV8::JSBindings* ProxyResolverV8::CreateDefaultBindings( |
| 373 HostResolver* host_resolver, MessageLoop* host_resolver_loop) { |
| 374 return new DefaultJSBindings(host_resolver, host_resolver_loop); |
| 375 } |
| 376 |
| 308 } // namespace net | 377 } // namespace net |
| OLD | NEW |