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 |