| OLD | NEW |
| 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the 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/logging.h" | 7 #include "base/logging.h" |
| 8 #include "base/string_util.h" | 8 #include "base/string_util.h" |
| 9 #include "googleurl/src/gurl.h" | 9 #include "googleurl/src/gurl.h" |
| 10 #include "net/base/host_cache.h" |
| 10 #include "net/base/net_errors.h" | 11 #include "net/base/net_errors.h" |
| 11 #include "net/base/net_log.h" | 12 #include "net/base/net_log.h" |
| 12 #include "net/proxy/proxy_info.h" | 13 #include "net/proxy/proxy_info.h" |
| 13 #include "net/proxy/proxy_resolver_js_bindings.h" | 14 #include "net/proxy/proxy_resolver_js_bindings.h" |
| 15 #include "net/proxy/proxy_resolver_request_context.h" |
| 14 #include "net/proxy/proxy_resolver_script.h" | 16 #include "net/proxy/proxy_resolver_script.h" |
| 15 #include "v8/include/v8.h" | 17 #include "v8/include/v8.h" |
| 16 | 18 |
| 17 // Notes on the javascript environment: | 19 // Notes on the javascript environment: |
| 18 // | 20 // |
| 19 // For the majority of the PAC utility functions, we use the same code | 21 // For the majority of the PAC utility functions, we use the same code |
| 20 // as Firefox. See the javascript library that proxy_resolver_scipt.h | 22 // as Firefox. See the javascript library that proxy_resolver_scipt.h |
| 21 // pulls in. | 23 // pulls in. |
| 22 // | 24 // |
| 23 // In addition, we implement a subset of Microsoft's extensions to PAC. | 25 // In addition, we implement a subset of Microsoft's extensions to PAC. |
| (...skipping 183 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 207 | 209 |
| 208 // At a minimum, the FindProxyForURL() function must be defined for this | 210 // At a minimum, the FindProxyForURL() function must be defined for this |
| 209 // to be a legitimiate PAC script. | 211 // to be a legitimiate PAC script. |
| 210 v8::Local<v8::Value> function; | 212 v8::Local<v8::Value> function; |
| 211 if (!GetFindProxyForURL(&function)) | 213 if (!GetFindProxyForURL(&function)) |
| 212 return ERR_PAC_SCRIPT_FAILED; | 214 return ERR_PAC_SCRIPT_FAILED; |
| 213 | 215 |
| 214 return OK; | 216 return OK; |
| 215 } | 217 } |
| 216 | 218 |
| 217 void SetCurrentRequestNetLog(const BoundNetLog& net_log) { | 219 void SetCurrentRequestContext(ProxyResolverRequestContext* context) { |
| 218 current_request_net_log_ = net_log; | 220 js_bindings_->set_current_request_context(context); |
| 219 } | 221 } |
| 220 | 222 |
| 221 void PurgeMemory() { | 223 void PurgeMemory() { |
| 222 v8::Locker locked; | 224 v8::Locker locked; |
| 223 // Repeatedly call the V8 idle notification until it returns true ("nothing | 225 // Repeatedly call the V8 idle notification until it returns true ("nothing |
| 224 // more to free"). Note that it makes more sense to do this than to | 226 // more to free"). Note that it makes more sense to do this than to |
| 225 // implement a new "delete everything" pass because object references make | 227 // implement a new "delete everything" pass because object references make |
| 226 // it difficult to free everything possible in just one pass. | 228 // it difficult to free everything possible in just one pass. |
| 227 while (!v8::V8::IdleNotification()) | 229 while (!v8::V8::IdleNotification()) |
| 228 ; | 230 ; |
| (...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 291 // V8 callback for when "myIpAddress()" is invoked by the PAC script. | 293 // V8 callback for when "myIpAddress()" is invoked by the PAC script. |
| 292 static v8::Handle<v8::Value> MyIpAddressCallback(const v8::Arguments& args) { | 294 static v8::Handle<v8::Value> MyIpAddressCallback(const v8::Arguments& args) { |
| 293 Context* context = | 295 Context* context = |
| 294 static_cast<Context*>(v8::External::Cast(*args.Data())->Value()); | 296 static_cast<Context*>(v8::External::Cast(*args.Data())->Value()); |
| 295 | 297 |
| 296 std::string result; | 298 std::string result; |
| 297 | 299 |
| 298 { | 300 { |
| 299 v8::Unlocker unlocker; | 301 v8::Unlocker unlocker; |
| 300 | 302 |
| 301 context->current_request_net_log_.BeginEvent( | 303 LogEventToCurrentRequest(context, |
| 302 NetLog::TYPE_PROXY_RESOLVER_V8_MY_IP_ADDRESS, NULL); | 304 NetLog::PHASE_BEGIN, |
| 305 NetLog::TYPE_PROXY_RESOLVER_V8_MY_IP_ADDRESS, |
| 306 NULL); |
| 303 | 307 |
| 304 // We shouldn't be called with any arguments, but will not complain if | 308 // We shouldn't be called with any arguments, but will not complain if |
| 305 // we are. | 309 // we are. |
| 306 result = context->js_bindings_->MyIpAddress(); | 310 result = context->js_bindings_->MyIpAddress(); |
| 307 | 311 |
| 308 context->current_request_net_log_.EndEvent( | 312 LogEventToCurrentRequest(context, |
| 309 NetLog::TYPE_PROXY_RESOLVER_V8_MY_IP_ADDRESS, NULL); | 313 NetLog::PHASE_END, |
| 314 NetLog::TYPE_PROXY_RESOLVER_V8_MY_IP_ADDRESS, |
| 315 NULL); |
| 310 } | 316 } |
| 311 | 317 |
| 312 if (result.empty()) | 318 if (result.empty()) |
| 313 result = "127.0.0.1"; | 319 result = "127.0.0.1"; |
| 314 return StdStringToV8String(result); | 320 return StdStringToV8String(result); |
| 315 } | 321 } |
| 316 | 322 |
| 317 // V8 callback for when "myIpAddressEx()" is invoked by the PAC script. | 323 // V8 callback for when "myIpAddressEx()" is invoked by the PAC script. |
| 318 static v8::Handle<v8::Value> MyIpAddressExCallback( | 324 static v8::Handle<v8::Value> MyIpAddressExCallback( |
| 319 const v8::Arguments& args) { | 325 const v8::Arguments& args) { |
| 320 Context* context = | 326 Context* context = |
| 321 static_cast<Context*>(v8::External::Cast(*args.Data())->Value()); | 327 static_cast<Context*>(v8::External::Cast(*args.Data())->Value()); |
| 322 | 328 |
| 323 std::string result; | 329 std::string result; |
| 324 | 330 |
| 325 { | 331 { |
| 326 v8::Unlocker unlocker; | 332 v8::Unlocker unlocker; |
| 327 | 333 |
| 328 context->current_request_net_log_.BeginEvent( | 334 LogEventToCurrentRequest(context, |
| 329 NetLog::TYPE_PROXY_RESOLVER_V8_MY_IP_ADDRESS_EX, NULL); | 335 NetLog::PHASE_BEGIN, |
| 336 NetLog::TYPE_PROXY_RESOLVER_V8_MY_IP_ADDRESS_EX, |
| 337 NULL); |
| 330 | 338 |
| 331 // We shouldn't be called with any arguments, but will not complain if | 339 // We shouldn't be called with any arguments, but will not complain if |
| 332 // we are. | 340 // we are. |
| 333 context->js_bindings_->MyIpAddressEx(); | 341 context->js_bindings_->MyIpAddressEx(); |
| 334 | 342 |
| 335 context->current_request_net_log_.EndEvent( | 343 LogEventToCurrentRequest(context, |
| 336 NetLog::TYPE_PROXY_RESOLVER_V8_MY_IP_ADDRESS_EX, NULL); | 344 NetLog::PHASE_END, |
| 345 NetLog::TYPE_PROXY_RESOLVER_V8_MY_IP_ADDRESS_EX, |
| 346 NULL); |
| 337 } | 347 } |
| 338 | 348 |
| 339 return StdStringToV8String(result); | 349 return StdStringToV8String(result); |
| 340 } | 350 } |
| 341 | 351 |
| 342 // V8 callback for when "dnsResolve()" is invoked by the PAC script. | 352 // V8 callback for when "dnsResolve()" is invoked by the PAC script. |
| 343 static v8::Handle<v8::Value> DnsResolveCallback(const v8::Arguments& args) { | 353 static v8::Handle<v8::Value> DnsResolveCallback(const v8::Arguments& args) { |
| 344 Context* context = | 354 Context* context = |
| 345 static_cast<Context*>(v8::External::Cast(*args.Data())->Value()); | 355 static_cast<Context*>(v8::External::Cast(*args.Data())->Value()); |
| 346 | 356 |
| 347 // We need at least one string argument. | 357 // We need at least one string argument. |
| 348 if (args.Length() == 0 || args[0].IsEmpty() || !args[0]->IsString()) | 358 if (args.Length() == 0 || args[0].IsEmpty() || !args[0]->IsString()) |
| 349 return v8::Null(); | 359 return v8::Null(); |
| 350 std::string host = V8StringToStdString(args[0]->ToString()); | 360 std::string host = V8StringToStdString(args[0]->ToString()); |
| 351 | 361 |
| 352 std::string result; | 362 std::string result; |
| 353 | 363 |
| 354 { | 364 { |
| 355 v8::Unlocker unlocker; | 365 v8::Unlocker unlocker; |
| 356 | 366 |
| 357 context->current_request_net_log_.BeginEvent( | 367 LogEventToCurrentRequest(context, |
| 358 NetLog::TYPE_PROXY_RESOLVER_V8_DNS_RESOLVE, NULL); | 368 NetLog::PHASE_BEGIN, |
| 369 NetLog::TYPE_PROXY_RESOLVER_V8_DNS_RESOLVE, |
| 370 NULL); |
| 359 | 371 |
| 360 result = context->js_bindings_->DnsResolve(host); | 372 result = context->js_bindings_->DnsResolve(host); |
| 361 | 373 |
| 362 context->current_request_net_log_.EndEvent( | 374 LogEventToCurrentRequest(context, |
| 363 NetLog::TYPE_PROXY_RESOLVER_V8_DNS_RESOLVE, NULL); | 375 NetLog::PHASE_END, |
| 376 NetLog::TYPE_PROXY_RESOLVER_V8_DNS_RESOLVE, |
| 377 NULL); |
| 364 } | 378 } |
| 365 | 379 |
| 366 // DnsResolve() returns empty string on failure. | 380 // DnsResolve() returns empty string on failure. |
| 367 return result.empty() ? v8::Null() : StdStringToV8String(result); | 381 return result.empty() ? v8::Null() : StdStringToV8String(result); |
| 368 } | 382 } |
| 369 | 383 |
| 370 // V8 callback for when "dnsResolveEx()" is invoked by the PAC script. | 384 // V8 callback for when "dnsResolveEx()" is invoked by the PAC script. |
| 371 static v8::Handle<v8::Value> DnsResolveExCallback(const v8::Arguments& args) { | 385 static v8::Handle<v8::Value> DnsResolveExCallback(const v8::Arguments& args) { |
| 372 Context* context = | 386 Context* context = |
| 373 static_cast<Context*>(v8::External::Cast(*args.Data())->Value()); | 387 static_cast<Context*>(v8::External::Cast(*args.Data())->Value()); |
| 374 | 388 |
| 375 // We need at least one string argument. | 389 // We need at least one string argument. |
| 376 if (args.Length() == 0 || args[0].IsEmpty() || !args[0]->IsString()) | 390 if (args.Length() == 0 || args[0].IsEmpty() || !args[0]->IsString()) |
| 377 return v8::Undefined(); | 391 return v8::Undefined(); |
| 378 std::string host = V8StringToStdString(args[0]->ToString()); | 392 std::string host = V8StringToStdString(args[0]->ToString()); |
| 379 | 393 |
| 380 std::string result; | 394 std::string result; |
| 381 | 395 |
| 382 { | 396 { |
| 383 v8::Unlocker unlocker; | 397 v8::Unlocker unlocker; |
| 384 | 398 |
| 385 context->current_request_net_log_.BeginEvent( | 399 LogEventToCurrentRequest(context, |
| 386 NetLog::TYPE_PROXY_RESOLVER_V8_DNS_RESOLVE_EX, NULL); | 400 NetLog::PHASE_BEGIN, |
| 401 NetLog::TYPE_PROXY_RESOLVER_V8_DNS_RESOLVE_EX, |
| 402 NULL); |
| 387 | 403 |
| 388 result = context->js_bindings_->DnsResolveEx(host); | 404 result = context->js_bindings_->DnsResolveEx(host); |
| 389 | 405 |
| 390 context->current_request_net_log_.EndEvent( | 406 LogEventToCurrentRequest(context, |
| 391 NetLog::TYPE_PROXY_RESOLVER_V8_DNS_RESOLVE_EX, NULL); | 407 NetLog::PHASE_END, |
| 408 NetLog::TYPE_PROXY_RESOLVER_V8_DNS_RESOLVE_EX, |
| 409 NULL); |
| 392 } | 410 } |
| 393 | 411 |
| 394 return StdStringToV8String(result); | 412 return StdStringToV8String(result); |
| 395 } | 413 } |
| 396 | 414 |
| 415 static void LogEventToCurrentRequest(Context* context, |
| 416 NetLog::EventPhase phase, |
| 417 NetLog::EventType type, |
| 418 NetLog::EventParameters* params) { |
| 419 if (context->js_bindings_->current_request_context()) { |
| 420 context->js_bindings_->current_request_context()->net_log->AddEntry( |
| 421 type, phase, params); |
| 422 } |
| 423 } |
| 424 |
| 397 ProxyResolverJSBindings* js_bindings_; | 425 ProxyResolverJSBindings* js_bindings_; |
| 398 BoundNetLog current_request_net_log_; | |
| 399 v8::Persistent<v8::External> v8_this_; | 426 v8::Persistent<v8::External> v8_this_; |
| 400 v8::Persistent<v8::Context> v8_context_; | 427 v8::Persistent<v8::Context> v8_context_; |
| 401 }; | 428 }; |
| 402 | 429 |
| 403 // ProxyResolverV8 ------------------------------------------------------------ | 430 // ProxyResolverV8 ------------------------------------------------------------ |
| 404 | 431 |
| 405 ProxyResolverV8::ProxyResolverV8( | 432 ProxyResolverV8::ProxyResolverV8( |
| 406 ProxyResolverJSBindings* custom_js_bindings) | 433 ProxyResolverJSBindings* custom_js_bindings) |
| 407 : ProxyResolver(true /*expects_pac_bytes*/), | 434 : ProxyResolver(true /*expects_pac_bytes*/), |
| 408 js_bindings_(custom_js_bindings) { | 435 js_bindings_(custom_js_bindings) { |
| 409 } | 436 } |
| 410 | 437 |
| 411 ProxyResolverV8::~ProxyResolverV8() {} | 438 ProxyResolverV8::~ProxyResolverV8() {} |
| 412 | 439 |
| 413 int ProxyResolverV8::GetProxyForURL(const GURL& query_url, | 440 int ProxyResolverV8::GetProxyForURL(const GURL& query_url, |
| 414 ProxyInfo* results, | 441 ProxyInfo* results, |
| 415 CompletionCallback* /*callback*/, | 442 CompletionCallback* /*callback*/, |
| 416 RequestHandle* /*request*/, | 443 RequestHandle* /*request*/, |
| 417 const BoundNetLog& net_log) { | 444 const BoundNetLog& net_log) { |
| 418 // If the V8 instance has not been initialized (either because | 445 // If the V8 instance has not been initialized (either because |
| 419 // SetPacScript() wasn't called yet, or because it failed. | 446 // SetPacScript() wasn't called yet, or because it failed. |
| 420 if (!context_.get()) | 447 if (!context_.get()) |
| 421 return ERR_FAILED; | 448 return ERR_FAILED; |
| 422 | 449 |
| 450 // Associate some short-lived context with this request. This context will be |
| 451 // available to any of the javascript "bindings" that are subsequently invoked |
| 452 // from the javascript. |
| 453 // |
| 454 // In particular, we create a HostCache that is aggressive about caching |
| 455 // failed DNS resolves. |
| 456 HostCache host_cache( |
| 457 50, |
| 458 base::TimeDelta::FromMinutes(5), |
| 459 base::TimeDelta::FromMinutes(5)); |
| 460 |
| 461 ProxyResolverRequestContext request_context( |
| 462 &query_url, &net_log, &host_cache); |
| 463 |
| 423 // Otherwise call into V8. | 464 // Otherwise call into V8. |
| 424 context_->SetCurrentRequestNetLog(net_log); | 465 context_->SetCurrentRequestContext(&request_context); |
| 425 int rv = context_->ResolveProxy(query_url, results); | 466 int rv = context_->ResolveProxy(query_url, results); |
| 426 context_->SetCurrentRequestNetLog(BoundNetLog()); | 467 context_->SetCurrentRequestContext(NULL); |
| 427 | 468 |
| 428 return rv; | 469 return rv; |
| 429 } | 470 } |
| 430 | 471 |
| 431 void ProxyResolverV8::CancelRequest(RequestHandle request) { | 472 void ProxyResolverV8::CancelRequest(RequestHandle request) { |
| 432 // This is a synchronous ProxyResolver; no possibility for async requests. | 473 // This is a synchronous ProxyResolver; no possibility for async requests. |
| 433 NOTREACHED(); | 474 NOTREACHED(); |
| 434 } | 475 } |
| 435 | 476 |
| 436 void ProxyResolverV8::PurgeMemory() { | 477 void ProxyResolverV8::PurgeMemory() { |
| 437 context_->PurgeMemory(); | 478 context_->PurgeMemory(); |
| 438 } | 479 } |
| 439 | 480 |
| 440 int ProxyResolverV8::SetPacScript(const GURL& /*url*/, | 481 int ProxyResolverV8::SetPacScript(const GURL& /*url*/, |
| 441 const std::string& bytes_utf8, | 482 const std::string& bytes_utf8, |
| 442 CompletionCallback* /*callback*/) { | 483 CompletionCallback* /*callback*/) { |
| 443 context_.reset(); | 484 context_.reset(); |
| 444 if (bytes_utf8.empty()) | 485 if (bytes_utf8.empty()) |
| 445 return ERR_PAC_SCRIPT_FAILED; | 486 return ERR_PAC_SCRIPT_FAILED; |
| 446 | 487 |
| 447 // Try parsing the PAC script. | 488 // Try parsing the PAC script. |
| 448 scoped_ptr<Context> context(new Context(js_bindings_.get())); | 489 scoped_ptr<Context> context(new Context(js_bindings_.get())); |
| 449 int rv = context->InitV8(bytes_utf8); | 490 int rv = context->InitV8(bytes_utf8); |
| 450 if (rv == OK) | 491 if (rv == OK) |
| 451 context_.reset(context.release()); | 492 context_.reset(context.release()); |
| 452 return rv; | 493 return rv; |
| 453 } | 494 } |
| 454 | 495 |
| 455 } // namespace net | 496 } // namespace net |
| OLD | NEW |