| Index: net/proxy/proxy_resolver_v8_tracing.cc
|
| diff --git a/net/proxy/proxy_resolver_v8_tracing.cc b/net/proxy/proxy_resolver_v8_tracing.cc
|
| deleted file mode 100644
|
| index c498f749bb6e8163a2dab165a7cf88c9dea0ddee..0000000000000000000000000000000000000000
|
| --- a/net/proxy/proxy_resolver_v8_tracing.cc
|
| +++ /dev/null
|
| @@ -1,1016 +0,0 @@
|
| -// Copyright (c) 2013 The Chromium Authors. All rights reserved.
|
| -// Use of this source code is governed by a BSD-style license that can be
|
| -// found in the LICENSE file.
|
| -
|
| -#include "net/proxy/proxy_resolver_v8_tracing.h"
|
| -
|
| -#include "base/bind.h"
|
| -#include "base/message_loop/message_loop_proxy.h"
|
| -#include "base/profiler/scoped_tracker.h"
|
| -#include "base/strings/stringprintf.h"
|
| -#include "base/synchronization/cancellation_flag.h"
|
| -#include "base/synchronization/waitable_event.h"
|
| -#include "base/threading/thread.h"
|
| -#include "base/threading/thread_restrictions.h"
|
| -#include "base/values.h"
|
| -#include "net/base/address_list.h"
|
| -#include "net/base/net_errors.h"
|
| -#include "net/base/net_log.h"
|
| -#include "net/dns/host_resolver.h"
|
| -#include "net/proxy/proxy_info.h"
|
| -#include "net/proxy/proxy_resolver_error_observer.h"
|
| -#include "net/proxy/proxy_resolver_v8.h"
|
| -
|
| -// The intent of this class is explained in the design document:
|
| -// https://docs.google.com/a/chromium.org/document/d/16Ij5OcVnR3s0MH4Z5XkhI9VTPoMJdaBn9rKreAmGOdE/edit
|
| -//
|
| -// In a nutshell, PAC scripts are Javascript programs and may depend on
|
| -// network I/O, by calling functions like dnsResolve().
|
| -//
|
| -// This is problematic since functions such as dnsResolve() will block the
|
| -// Javascript execution until the DNS result is availble, thereby stalling the
|
| -// PAC thread, which hurts the ability to process parallel proxy resolves.
|
| -// An obvious solution is to simply start more PAC threads, however this scales
|
| -// poorly, which hurts the ability to process parallel proxy resolves.
|
| -//
|
| -// The solution in ProxyResolverV8Tracing is to model PAC scripts as being
|
| -// deterministic, and depending only on the inputted URL. When the script
|
| -// issues a dnsResolve() for a yet unresolved hostname, the Javascript
|
| -// execution is "aborted", and then re-started once the DNS result is
|
| -// known.
|
| -namespace net {
|
| -
|
| -namespace {
|
| -
|
| -// Upper bound on how many *unique* DNS resolves a PAC script is allowed
|
| -// to make. This is a failsafe both for scripts that do a ridiculous
|
| -// number of DNS resolves, as well as scripts which are misbehaving
|
| -// under the tracing optimization. It is not expected to hit this normally.
|
| -const size_t kMaxUniqueResolveDnsPerExec = 20;
|
| -
|
| -// Approximate number of bytes to use for buffering alerts() and errors.
|
| -// This is a failsafe in case repeated executions of the script causes
|
| -// too much memory bloat. It is not expected for well behaved scripts to
|
| -// hit this. (In fact normal scripts should not even have alerts() or errors).
|
| -const size_t kMaxAlertsAndErrorsBytes = 2048;
|
| -
|
| -// Returns event parameters for a PAC error message (line number + message).
|
| -base::Value* NetLogErrorCallback(int line_number,
|
| - const base::string16* message,
|
| - NetLog::LogLevel /* log_level */) {
|
| - base::DictionaryValue* dict = new base::DictionaryValue();
|
| - dict->SetInteger("line_number", line_number);
|
| - dict->SetString("message", *message);
|
| - return dict;
|
| -}
|
| -
|
| -} // namespace
|
| -
|
| -// The Job class is responsible for executing GetProxyForURL() and
|
| -// SetPacScript(), since both of these operations share similar code.
|
| -//
|
| -// The DNS for these operations can operate in either blocking or
|
| -// non-blocking mode. Blocking mode is used as a fallback when the PAC script
|
| -// seems to be misbehaving under the tracing optimization.
|
| -//
|
| -// Note that this class runs on both the origin thread and a worker
|
| -// thread. Most methods are expected to be used exclusively on one thread
|
| -// or the other.
|
| -//
|
| -// The lifetime of Jobs does not exceed that of the ProxyResolverV8Tracing that
|
| -// spawned it. Destruction might happen on either the origin thread or the
|
| -// worker thread.
|
| -class ProxyResolverV8Tracing::Job
|
| - : public base::RefCountedThreadSafe<ProxyResolverV8Tracing::Job>,
|
| - public ProxyResolverV8::JSBindings {
|
| - public:
|
| - // |parent| is non-owned. It is the ProxyResolverV8Tracing that spawned this
|
| - // Job, and must oulive it.
|
| - explicit Job(ProxyResolverV8Tracing* parent);
|
| -
|
| - // Called from origin thread.
|
| - void StartSetPacScript(
|
| - const scoped_refptr<ProxyResolverScriptData>& script_data,
|
| - const CompletionCallback& callback);
|
| -
|
| - // Called from origin thread.
|
| - void StartGetProxyForURL(const GURL& url,
|
| - ProxyInfo* results,
|
| - const BoundNetLog& net_log,
|
| - const CompletionCallback& callback);
|
| -
|
| - // Called from origin thread.
|
| - void Cancel();
|
| -
|
| - // Called from origin thread.
|
| - LoadState GetLoadState() const;
|
| -
|
| - private:
|
| - typedef std::map<std::string, std::string> DnsCache;
|
| - friend class base::RefCountedThreadSafe<ProxyResolverV8Tracing::Job>;
|
| -
|
| - enum Operation {
|
| - SET_PAC_SCRIPT,
|
| - GET_PROXY_FOR_URL,
|
| - };
|
| -
|
| - struct AlertOrError {
|
| - bool is_alert;
|
| - int line_number;
|
| - base::string16 message;
|
| - };
|
| -
|
| - ~Job() override;
|
| -
|
| - void CheckIsOnWorkerThread() const;
|
| - void CheckIsOnOriginThread() const;
|
| -
|
| - void SetCallback(const CompletionCallback& callback);
|
| - void ReleaseCallback();
|
| -
|
| - ProxyResolverV8* v8_resolver();
|
| - base::MessageLoop* worker_loop();
|
| - HostResolver* host_resolver();
|
| - ProxyResolverErrorObserver* error_observer();
|
| - NetLog* net_log();
|
| -
|
| - // Invokes the user's callback.
|
| - void NotifyCaller(int result);
|
| - void NotifyCallerOnOriginLoop(int result);
|
| -
|
| - void Start(Operation op, bool blocking_dns,
|
| - const CompletionCallback& callback);
|
| -
|
| - void ExecuteBlocking();
|
| - void ExecuteNonBlocking();
|
| - int ExecuteProxyResolver();
|
| -
|
| - // Implementation of ProxyResolverv8::JSBindings
|
| - bool ResolveDns(const std::string& host,
|
| - ResolveDnsOperation op,
|
| - std::string* output,
|
| - bool* terminate) override;
|
| - void Alert(const base::string16& message) override;
|
| - void OnError(int line_number, const base::string16& error) override;
|
| -
|
| - bool ResolveDnsBlocking(const std::string& host,
|
| - ResolveDnsOperation op,
|
| - std::string* output);
|
| -
|
| - bool ResolveDnsNonBlocking(const std::string& host,
|
| - ResolveDnsOperation op,
|
| - std::string* output,
|
| - bool* terminate);
|
| -
|
| - bool PostDnsOperationAndWait(const std::string& host,
|
| - ResolveDnsOperation op,
|
| - bool* completed_synchronously)
|
| - WARN_UNUSED_RESULT;
|
| -
|
| - void DoDnsOperation();
|
| - void OnDnsOperationComplete(int result);
|
| -
|
| - void ScheduleRestartWithBlockingDns();
|
| -
|
| - bool GetDnsFromLocalCache(const std::string& host, ResolveDnsOperation op,
|
| - std::string* output, bool* return_value);
|
| -
|
| - void SaveDnsToLocalCache(const std::string& host, ResolveDnsOperation op,
|
| - int net_error, const net::AddressList& addresses);
|
| -
|
| - // Builds a RequestInfo to service the specified PAC DNS operation.
|
| - static HostResolver::RequestInfo MakeDnsRequestInfo(const std::string& host,
|
| - ResolveDnsOperation op);
|
| -
|
| - // Makes a key for looking up |host, op| in |dns_cache_|. Strings are used for
|
| - // convenience, to avoid defining custom comparators.
|
| - static std::string MakeDnsCacheKey(const std::string& host,
|
| - ResolveDnsOperation op);
|
| -
|
| - void HandleAlertOrError(bool is_alert, int line_number,
|
| - const base::string16& message);
|
| - void DispatchBufferedAlertsAndErrors();
|
| - void DispatchAlertOrError(bool is_alert, int line_number,
|
| - const base::string16& message);
|
| -
|
| - void LogEventToCurrentRequestAndGlobally(
|
| - NetLog::EventType type,
|
| - const NetLog::ParametersCallback& parameters_callback);
|
| -
|
| - // The thread which called into ProxyResolverV8Tracing, and on which the
|
| - // completion callback is expected to run.
|
| - scoped_refptr<base::MessageLoopProxy> origin_loop_;
|
| -
|
| - // The ProxyResolverV8Tracing which spawned this Job.
|
| - // Initialized on origin thread and then accessed from both threads.
|
| - ProxyResolverV8Tracing* parent_;
|
| -
|
| - // The callback to run (on the origin thread) when the Job finishes.
|
| - // Should only be accessed from origin thread.
|
| - CompletionCallback callback_;
|
| -
|
| - // Flag to indicate whether the request has been cancelled.
|
| - base::CancellationFlag cancelled_;
|
| -
|
| - // The operation that this Job is running.
|
| - // Initialized on origin thread and then accessed from both threads.
|
| - Operation operation_;
|
| -
|
| - // The DNS mode for this Job.
|
| - // Initialized on origin thread, mutated on worker thread, and accessed
|
| - // by both the origin thread and worker thread.
|
| - bool blocking_dns_;
|
| -
|
| - // Used to block the worker thread on a DNS operation taking place on the
|
| - // origin thread.
|
| - base::WaitableEvent event_;
|
| -
|
| - // Map of DNS operations completed so far. Written into on the origin thread
|
| - // and read on the worker thread.
|
| - DnsCache dns_cache_;
|
| -
|
| - // The job holds a reference to itself to ensure that it remains alive until
|
| - // either completion or cancellation.
|
| - scoped_refptr<Job> owned_self_reference_;
|
| -
|
| - // -------------------------------------------------------
|
| - // State specific to SET_PAC_SCRIPT.
|
| - // -------------------------------------------------------
|
| -
|
| - scoped_refptr<ProxyResolverScriptData> script_data_;
|
| -
|
| - // -------------------------------------------------------
|
| - // State specific to GET_PROXY_FOR_URL.
|
| - // -------------------------------------------------------
|
| -
|
| - ProxyInfo* user_results_; // Owned by caller, lives on origin thread.
|
| - GURL url_;
|
| - ProxyInfo results_;
|
| - BoundNetLog bound_net_log_;
|
| -
|
| - // ---------------------------------------------------------------------------
|
| - // State for ExecuteNonBlocking()
|
| - // ---------------------------------------------------------------------------
|
| - // These variables are used exclusively on the worker thread and are only
|
| - // meaningful when executing inside of ExecuteNonBlocking().
|
| -
|
| - // Whether this execution was abandoned due to a missing DNS dependency.
|
| - bool abandoned_;
|
| -
|
| - // Number of calls made to ResolveDns() by this execution.
|
| - int num_dns_;
|
| -
|
| - // Sequence of calls made to Alert() or OnError() by this execution.
|
| - std::vector<AlertOrError> alerts_and_errors_;
|
| - size_t alerts_and_errors_byte_cost_; // Approximate byte cost of the above.
|
| -
|
| - // Number of calls made to ResolveDns() by the PREVIOUS execution.
|
| - int last_num_dns_;
|
| -
|
| - // Whether the current execution needs to be restarted in blocking mode.
|
| - bool should_restart_with_blocking_dns_;
|
| -
|
| - // ---------------------------------------------------------------------------
|
| - // State for pending DNS request.
|
| - // ---------------------------------------------------------------------------
|
| -
|
| - // Handle to the outstanding request in the HostResolver, or NULL.
|
| - // This is mutated and used on the origin thread, however it may be read by
|
| - // the worker thread for some DCHECKS().
|
| - HostResolver::RequestHandle pending_dns_;
|
| -
|
| - // Indicates if the outstanding DNS request completed synchronously. Written
|
| - // on the origin thread, and read by the worker thread.
|
| - bool pending_dns_completed_synchronously_;
|
| -
|
| - // These are the inputs to DoDnsOperation(). Written on the worker thread,
|
| - // read by the origin thread.
|
| - std::string pending_dns_host_;
|
| - ResolveDnsOperation pending_dns_op_;
|
| -
|
| - // This contains the resolved address list that DoDnsOperation() fills in.
|
| - // Used exclusively on the origin thread.
|
| - AddressList pending_dns_addresses_;
|
| -};
|
| -
|
| -ProxyResolverV8Tracing::Job::Job(ProxyResolverV8Tracing* parent)
|
| - : origin_loop_(base::MessageLoopProxy::current()),
|
| - parent_(parent),
|
| - event_(true, false),
|
| - last_num_dns_(0),
|
| - pending_dns_(NULL) {
|
| - CheckIsOnOriginThread();
|
| -}
|
| -
|
| -void ProxyResolverV8Tracing::Job::StartSetPacScript(
|
| - const scoped_refptr<ProxyResolverScriptData>& script_data,
|
| - const CompletionCallback& callback) {
|
| - CheckIsOnOriginThread();
|
| -
|
| - script_data_ = script_data;
|
| -
|
| - // Script initialization uses blocking DNS since there isn't any
|
| - // advantage to using non-blocking mode here. That is because the
|
| - // parent ProxyService can't submit any ProxyResolve requests until
|
| - // initialization has completed successfully!
|
| - Start(SET_PAC_SCRIPT, true /*blocking*/, callback);
|
| -}
|
| -
|
| -void ProxyResolverV8Tracing::Job::StartGetProxyForURL(
|
| - const GURL& url,
|
| - ProxyInfo* results,
|
| - const BoundNetLog& net_log,
|
| - const CompletionCallback& callback) {
|
| - CheckIsOnOriginThread();
|
| -
|
| - url_ = url;
|
| - user_results_ = results;
|
| - bound_net_log_ = net_log;
|
| -
|
| - Start(GET_PROXY_FOR_URL, false /*non-blocking*/, callback);
|
| -}
|
| -
|
| -void ProxyResolverV8Tracing::Job::Cancel() {
|
| - CheckIsOnOriginThread();
|
| -
|
| - // There are several possibilities to consider for cancellation:
|
| - // (a) The job has been posted to the worker thread, however script execution
|
| - // has not yet started.
|
| - // (b) The script is executing on the worker thread.
|
| - // (c) The script is executing on the worker thread, however is blocked inside
|
| - // of dnsResolve() waiting for a response from the origin thread.
|
| - // (d) Nothing is running on the worker thread, however the host resolver has
|
| - // a pending DNS request which upon completion will restart the script
|
| - // execution.
|
| - // (e) The worker thread has a pending task to restart execution, which was
|
| - // posted after the DNS dependency was resolved and saved to local cache.
|
| - // (f) The script execution completed entirely, and posted a task to the
|
| - // origin thread to notify the caller.
|
| - //
|
| - // |cancelled_| is read on both the origin thread and worker thread. The
|
| - // code that runs on the worker thread is littered with checks on
|
| - // |cancelled_| to break out early.
|
| - cancelled_.Set();
|
| -
|
| - ReleaseCallback();
|
| -
|
| - if (pending_dns_) {
|
| - host_resolver()->CancelRequest(pending_dns_);
|
| - pending_dns_ = NULL;
|
| - }
|
| -
|
| - // The worker thread might be blocked waiting for DNS.
|
| - event_.Signal();
|
| -
|
| - owned_self_reference_ = NULL;
|
| -}
|
| -
|
| -LoadState ProxyResolverV8Tracing::Job::GetLoadState() const {
|
| - CheckIsOnOriginThread();
|
| -
|
| - if (pending_dns_)
|
| - return LOAD_STATE_RESOLVING_HOST_IN_PROXY_SCRIPT;
|
| -
|
| - return LOAD_STATE_RESOLVING_PROXY_FOR_URL;
|
| -}
|
| -
|
| -ProxyResolverV8Tracing::Job::~Job() {
|
| - DCHECK(!pending_dns_);
|
| - DCHECK(callback_.is_null());
|
| -}
|
| -
|
| -void ProxyResolverV8Tracing::Job::CheckIsOnWorkerThread() const {
|
| - DCHECK_EQ(base::MessageLoop::current(), parent_->thread_->message_loop());
|
| -}
|
| -
|
| -void ProxyResolverV8Tracing::Job::CheckIsOnOriginThread() const {
|
| - DCHECK(origin_loop_->BelongsToCurrentThread());
|
| -}
|
| -
|
| -void ProxyResolverV8Tracing::Job::SetCallback(
|
| - const CompletionCallback& callback) {
|
| - CheckIsOnOriginThread();
|
| - DCHECK(callback_.is_null());
|
| - parent_->num_outstanding_callbacks_++;
|
| - callback_ = callback;
|
| -}
|
| -
|
| -void ProxyResolverV8Tracing::Job::ReleaseCallback() {
|
| - CheckIsOnOriginThread();
|
| - DCHECK(!callback_.is_null());
|
| - CHECK_GT(parent_->num_outstanding_callbacks_, 0);
|
| - parent_->num_outstanding_callbacks_--;
|
| - callback_.Reset();
|
| -
|
| - // For good measure, clear this other user-owned pointer.
|
| - user_results_ = NULL;
|
| -}
|
| -
|
| -ProxyResolverV8* ProxyResolverV8Tracing::Job::v8_resolver() {
|
| - return parent_->v8_resolver_.get();
|
| -}
|
| -
|
| -base::MessageLoop* ProxyResolverV8Tracing::Job::worker_loop() {
|
| - return parent_->thread_->message_loop();
|
| -}
|
| -
|
| -HostResolver* ProxyResolverV8Tracing::Job::host_resolver() {
|
| - return parent_->host_resolver_;
|
| -}
|
| -
|
| -ProxyResolverErrorObserver* ProxyResolverV8Tracing::Job::error_observer() {
|
| - return parent_->error_observer_.get();
|
| -}
|
| -
|
| -NetLog* ProxyResolverV8Tracing::Job::net_log() {
|
| - return parent_->net_log_;
|
| -}
|
| -
|
| -void ProxyResolverV8Tracing::Job::NotifyCaller(int result) {
|
| - CheckIsOnWorkerThread();
|
| -
|
| - origin_loop_->PostTask(
|
| - FROM_HERE,
|
| - base::Bind(&Job::NotifyCallerOnOriginLoop, this, result));
|
| -}
|
| -
|
| -void ProxyResolverV8Tracing::Job::NotifyCallerOnOriginLoop(int result) {
|
| - CheckIsOnOriginThread();
|
| -
|
| - if (cancelled_.IsSet())
|
| - return;
|
| -
|
| - DCHECK(!callback_.is_null());
|
| - DCHECK(!pending_dns_);
|
| -
|
| - if (operation_ == GET_PROXY_FOR_URL) {
|
| - *user_results_ = results_;
|
| - }
|
| -
|
| - // There is only ever 1 outstanding SET_PAC_SCRIPT job. It needs to be
|
| - // tracked to support cancellation.
|
| - if (operation_ == SET_PAC_SCRIPT) {
|
| - DCHECK_EQ(parent_->set_pac_script_job_.get(), this);
|
| - parent_->set_pac_script_job_ = NULL;
|
| - }
|
| -
|
| - CompletionCallback callback = callback_;
|
| - ReleaseCallback();
|
| - callback.Run(result);
|
| -
|
| - owned_self_reference_ = NULL;
|
| -}
|
| -
|
| -void ProxyResolverV8Tracing::Job::Start(Operation op, bool blocking_dns,
|
| - const CompletionCallback& callback) {
|
| - CheckIsOnOriginThread();
|
| -
|
| - operation_ = op;
|
| - blocking_dns_ = blocking_dns;
|
| - SetCallback(callback);
|
| -
|
| - owned_self_reference_ = this;
|
| -
|
| - worker_loop()->PostTask(FROM_HERE,
|
| - blocking_dns_ ? base::Bind(&Job::ExecuteBlocking, this) :
|
| - base::Bind(&Job::ExecuteNonBlocking, this));
|
| -}
|
| -
|
| -void ProxyResolverV8Tracing::Job::ExecuteBlocking() {
|
| - CheckIsOnWorkerThread();
|
| - DCHECK(blocking_dns_);
|
| -
|
| - if (cancelled_.IsSet())
|
| - return;
|
| -
|
| - NotifyCaller(ExecuteProxyResolver());
|
| -}
|
| -
|
| -void ProxyResolverV8Tracing::Job::ExecuteNonBlocking() {
|
| - CheckIsOnWorkerThread();
|
| - DCHECK(!blocking_dns_);
|
| -
|
| - if (cancelled_.IsSet())
|
| - return;
|
| -
|
| - // Reset state for the current execution.
|
| - abandoned_ = false;
|
| - num_dns_ = 0;
|
| - alerts_and_errors_.clear();
|
| - alerts_and_errors_byte_cost_ = 0;
|
| - should_restart_with_blocking_dns_ = false;
|
| -
|
| - int result = ExecuteProxyResolver();
|
| -
|
| - if (should_restart_with_blocking_dns_) {
|
| - DCHECK(!blocking_dns_);
|
| - DCHECK(abandoned_);
|
| - blocking_dns_ = true;
|
| - ExecuteBlocking();
|
| - return;
|
| - }
|
| -
|
| - if (abandoned_)
|
| - return;
|
| -
|
| - DispatchBufferedAlertsAndErrors();
|
| - NotifyCaller(result);
|
| -}
|
| -
|
| -int ProxyResolverV8Tracing::Job::ExecuteProxyResolver() {
|
| - JSBindings* prev_bindings = v8_resolver()->js_bindings();
|
| - v8_resolver()->set_js_bindings(this);
|
| -
|
| - int result = ERR_UNEXPECTED; // Initialized to silence warnings.
|
| -
|
| - switch (operation_) {
|
| - case SET_PAC_SCRIPT:
|
| - result = v8_resolver()->SetPacScript(
|
| - script_data_, CompletionCallback());
|
| - break;
|
| - case GET_PROXY_FOR_URL:
|
| - result = v8_resolver()->GetProxyForURL(
|
| - url_,
|
| - // Important: Do not write directly into |user_results_|, since if the
|
| - // request were to be cancelled from the origin thread, must guarantee
|
| - // that |user_results_| is not accessed anymore.
|
| - &results_,
|
| - CompletionCallback(),
|
| - NULL,
|
| - bound_net_log_);
|
| - break;
|
| - }
|
| -
|
| - v8_resolver()->set_js_bindings(prev_bindings);
|
| -
|
| - return result;
|
| -}
|
| -
|
| -bool ProxyResolverV8Tracing::Job::ResolveDns(const std::string& host,
|
| - ResolveDnsOperation op,
|
| - std::string* output,
|
| - bool* terminate) {
|
| - if (cancelled_.IsSet()) {
|
| - *terminate = true;
|
| - return false;
|
| - }
|
| -
|
| - if ((op == DNS_RESOLVE || op == DNS_RESOLVE_EX) && host.empty()) {
|
| - // a DNS resolve with an empty hostname is considered an error.
|
| - return false;
|
| - }
|
| -
|
| - return blocking_dns_ ?
|
| - ResolveDnsBlocking(host, op, output) :
|
| - ResolveDnsNonBlocking(host, op, output, terminate);
|
| -}
|
| -
|
| -void ProxyResolverV8Tracing::Job::Alert(const base::string16& message) {
|
| - HandleAlertOrError(true, -1, message);
|
| -}
|
| -
|
| -void ProxyResolverV8Tracing::Job::OnError(int line_number,
|
| - const base::string16& error) {
|
| - HandleAlertOrError(false, line_number, error);
|
| -}
|
| -
|
| -bool ProxyResolverV8Tracing::Job::ResolveDnsBlocking(const std::string& host,
|
| - ResolveDnsOperation op,
|
| - std::string* output) {
|
| - CheckIsOnWorkerThread();
|
| -
|
| - // Check if the DNS result for this host has already been cached.
|
| - bool rv;
|
| - if (GetDnsFromLocalCache(host, op, output, &rv)) {
|
| - // Yay, cache hit!
|
| - return rv;
|
| - }
|
| -
|
| - if (dns_cache_.size() >= kMaxUniqueResolveDnsPerExec) {
|
| - // Safety net for scripts with unexpectedly many DNS calls.
|
| - // We will continue running to completion, but will fail every
|
| - // subsequent DNS request.
|
| - return false;
|
| - }
|
| -
|
| - if (!PostDnsOperationAndWait(host, op, NULL))
|
| - return false; // Was cancelled.
|
| -
|
| - CHECK(GetDnsFromLocalCache(host, op, output, &rv));
|
| - return rv;
|
| -}
|
| -
|
| -bool ProxyResolverV8Tracing::Job::ResolveDnsNonBlocking(const std::string& host,
|
| - ResolveDnsOperation op,
|
| - std::string* output,
|
| - bool* terminate) {
|
| - CheckIsOnWorkerThread();
|
| -
|
| - if (abandoned_) {
|
| - // If this execution was already abandoned can fail right away. Only 1 DNS
|
| - // dependency will be traced at a time (for more predictable outcomes).
|
| - return false;
|
| - }
|
| -
|
| - num_dns_ += 1;
|
| -
|
| - // Check if the DNS result for this host has already been cached.
|
| - bool rv;
|
| - if (GetDnsFromLocalCache(host, op, output, &rv)) {
|
| - // Yay, cache hit!
|
| - return rv;
|
| - }
|
| -
|
| - if (num_dns_ <= last_num_dns_) {
|
| - // The sequence of DNS operations is different from last time!
|
| - ScheduleRestartWithBlockingDns();
|
| - *terminate = true;
|
| - return false;
|
| - }
|
| -
|
| - if (dns_cache_.size() >= kMaxUniqueResolveDnsPerExec) {
|
| - // Safety net for scripts with unexpectedly many DNS calls.
|
| - return false;
|
| - }
|
| -
|
| - DCHECK(!should_restart_with_blocking_dns_);
|
| -
|
| - bool completed_synchronously;
|
| - if (!PostDnsOperationAndWait(host, op, &completed_synchronously))
|
| - return false; // Was cancelled.
|
| -
|
| - if (completed_synchronously) {
|
| - CHECK(GetDnsFromLocalCache(host, op, output, &rv));
|
| - return rv;
|
| - }
|
| -
|
| - // Otherwise if the result was not in the cache, then a DNS request has
|
| - // been started. Abandon this invocation of FindProxyForURL(), it will be
|
| - // restarted once the DNS request completes.
|
| - abandoned_ = true;
|
| - *terminate = true;
|
| - last_num_dns_ = num_dns_;
|
| - return false;
|
| -}
|
| -
|
| -bool ProxyResolverV8Tracing::Job::PostDnsOperationAndWait(
|
| - const std::string& host, ResolveDnsOperation op,
|
| - bool* completed_synchronously) {
|
| -
|
| - // Post the DNS request to the origin thread.
|
| - DCHECK(!pending_dns_);
|
| - pending_dns_host_ = host;
|
| - pending_dns_op_ = op;
|
| - origin_loop_->PostTask(FROM_HERE, base::Bind(&Job::DoDnsOperation, this));
|
| -
|
| - event_.Wait();
|
| - event_.Reset();
|
| -
|
| - if (cancelled_.IsSet())
|
| - return false;
|
| -
|
| - if (completed_synchronously)
|
| - *completed_synchronously = pending_dns_completed_synchronously_;
|
| -
|
| - return true;
|
| -}
|
| -
|
| -void ProxyResolverV8Tracing::Job::DoDnsOperation() {
|
| - CheckIsOnOriginThread();
|
| - DCHECK(!pending_dns_);
|
| -
|
| - if (cancelled_.IsSet())
|
| - return;
|
| -
|
| - HostResolver::RequestHandle dns_request = NULL;
|
| - int result = host_resolver()->Resolve(
|
| - MakeDnsRequestInfo(pending_dns_host_, pending_dns_op_),
|
| - DEFAULT_PRIORITY,
|
| - &pending_dns_addresses_,
|
| - base::Bind(&Job::OnDnsOperationComplete, this),
|
| - &dns_request,
|
| - bound_net_log_);
|
| -
|
| - pending_dns_completed_synchronously_ = result != ERR_IO_PENDING;
|
| -
|
| - // Check if the request was cancelled as a side-effect of calling into the
|
| - // HostResolver. This isn't the ordinary execution flow, however it is
|
| - // exercised by unit-tests.
|
| - if (cancelled_.IsSet()) {
|
| - if (!pending_dns_completed_synchronously_)
|
| - host_resolver()->CancelRequest(dns_request);
|
| - return;
|
| - }
|
| -
|
| - if (pending_dns_completed_synchronously_) {
|
| - OnDnsOperationComplete(result);
|
| - } else {
|
| - DCHECK(dns_request);
|
| - pending_dns_ = dns_request;
|
| - // OnDnsOperationComplete() will be called by host resolver on completion.
|
| - }
|
| -
|
| - if (!blocking_dns_) {
|
| - // The worker thread always blocks waiting to see if the result can be
|
| - // serviced from cache before restarting.
|
| - event_.Signal();
|
| - }
|
| -}
|
| -
|
| -void ProxyResolverV8Tracing::Job::OnDnsOperationComplete(int result) {
|
| - // TODO(vadimt): Remove ScopedTracker below once crbug.com/436634 is fixed.
|
| - tracked_objects::ScopedTracker tracking_profile(
|
| - FROM_HERE_WITH_EXPLICIT_FUNCTION(
|
| - "436634 ProxyResolverV8Tracing::Job::OnDnsOperationComplete"));
|
| -
|
| - CheckIsOnOriginThread();
|
| -
|
| - DCHECK(!cancelled_.IsSet());
|
| - DCHECK(pending_dns_completed_synchronously_ == (pending_dns_ == NULL));
|
| -
|
| - SaveDnsToLocalCache(pending_dns_host_, pending_dns_op_, result,
|
| - pending_dns_addresses_);
|
| - pending_dns_ = NULL;
|
| -
|
| - if (blocking_dns_) {
|
| - event_.Signal();
|
| - return;
|
| - }
|
| -
|
| - if (!blocking_dns_ && !pending_dns_completed_synchronously_) {
|
| - // Restart. This time it should make more progress due to having
|
| - // cached items.
|
| - worker_loop()->PostTask(FROM_HERE,
|
| - base::Bind(&Job::ExecuteNonBlocking, this));
|
| - }
|
| -}
|
| -
|
| -void ProxyResolverV8Tracing::Job::ScheduleRestartWithBlockingDns() {
|
| - CheckIsOnWorkerThread();
|
| -
|
| - DCHECK(!should_restart_with_blocking_dns_);
|
| - DCHECK(!abandoned_);
|
| - DCHECK(!blocking_dns_);
|
| -
|
| - abandoned_ = true;
|
| -
|
| - // The restart will happen after ExecuteNonBlocking() finishes.
|
| - should_restart_with_blocking_dns_ = true;
|
| -}
|
| -
|
| -bool ProxyResolverV8Tracing::Job::GetDnsFromLocalCache(
|
| - const std::string& host,
|
| - ResolveDnsOperation op,
|
| - std::string* output,
|
| - bool* return_value) {
|
| - CheckIsOnWorkerThread();
|
| -
|
| - DnsCache::const_iterator it = dns_cache_.find(MakeDnsCacheKey(host, op));
|
| - if (it == dns_cache_.end())
|
| - return false;
|
| -
|
| - *output = it->second;
|
| - *return_value = !it->second.empty();
|
| - return true;
|
| -}
|
| -
|
| -void ProxyResolverV8Tracing::Job::SaveDnsToLocalCache(
|
| - const std::string& host,
|
| - ResolveDnsOperation op,
|
| - int net_error,
|
| - const net::AddressList& addresses) {
|
| - CheckIsOnOriginThread();
|
| -
|
| - // Serialize the result into a string to save to the cache.
|
| - std::string cache_value;
|
| - if (net_error != OK) {
|
| - cache_value = std::string();
|
| - } else if (op == DNS_RESOLVE || op == MY_IP_ADDRESS) {
|
| - // dnsResolve() and myIpAddress() are expected to return a single IP
|
| - // address.
|
| - cache_value = addresses.front().ToStringWithoutPort();
|
| - } else {
|
| - // The *Ex versions are expected to return a semi-colon separated list.
|
| - for (AddressList::const_iterator iter = addresses.begin();
|
| - iter != addresses.end(); ++iter) {
|
| - if (!cache_value.empty())
|
| - cache_value += ";";
|
| - cache_value += iter->ToStringWithoutPort();
|
| - }
|
| - }
|
| -
|
| - dns_cache_[MakeDnsCacheKey(host, op)] = cache_value;
|
| -}
|
| -
|
| -// static
|
| -HostResolver::RequestInfo ProxyResolverV8Tracing::Job::MakeDnsRequestInfo(
|
| - const std::string& host, ResolveDnsOperation op) {
|
| - HostPortPair host_port = HostPortPair(host, 80);
|
| - if (op == MY_IP_ADDRESS || op == MY_IP_ADDRESS_EX) {
|
| - host_port.set_host(GetHostName());
|
| - }
|
| -
|
| - HostResolver::RequestInfo info(host_port);
|
| - // Flag myIpAddress requests.
|
| - if (op == MY_IP_ADDRESS || op == MY_IP_ADDRESS_EX) {
|
| - // TODO: Provide a RequestInfo construction mechanism that does not
|
| - // require a hostname and sets is_my_ip_address to true instead of this.
|
| - info.set_is_my_ip_address(true);
|
| - }
|
| - // The non-ex flavors are limited to IPv4 results.
|
| - if (op == MY_IP_ADDRESS || op == DNS_RESOLVE) {
|
| - info.set_address_family(ADDRESS_FAMILY_IPV4);
|
| - }
|
| -
|
| - return info;
|
| -}
|
| -
|
| -std::string ProxyResolverV8Tracing::Job::MakeDnsCacheKey(
|
| - const std::string& host, ResolveDnsOperation op) {
|
| - return base::StringPrintf("%d:%s", op, host.c_str());
|
| -}
|
| -
|
| -void ProxyResolverV8Tracing::Job::HandleAlertOrError(
|
| - bool is_alert,
|
| - int line_number,
|
| - const base::string16& message) {
|
| - CheckIsOnWorkerThread();
|
| -
|
| - if (cancelled_.IsSet())
|
| - return;
|
| -
|
| - if (blocking_dns_) {
|
| - // In blocking DNS mode the events can be dispatched immediately.
|
| - DispatchAlertOrError(is_alert, line_number, message);
|
| - return;
|
| - }
|
| -
|
| - // Otherwise in nonblocking mode, buffer all the messages until
|
| - // the end.
|
| -
|
| - if (abandoned_)
|
| - return;
|
| -
|
| - alerts_and_errors_byte_cost_ += sizeof(AlertOrError) + message.size() * 2;
|
| -
|
| - // If there have been lots of messages, enqueing could be expensive on
|
| - // memory. Consider a script which does megabytes worth of alerts().
|
| - // Avoid this by falling back to blocking mode.
|
| - if (alerts_and_errors_byte_cost_ > kMaxAlertsAndErrorsBytes) {
|
| - ScheduleRestartWithBlockingDns();
|
| - return;
|
| - }
|
| -
|
| - AlertOrError entry = {is_alert, line_number, message};
|
| - alerts_and_errors_.push_back(entry);
|
| -}
|
| -
|
| -void ProxyResolverV8Tracing::Job::DispatchBufferedAlertsAndErrors() {
|
| - CheckIsOnWorkerThread();
|
| - DCHECK(!blocking_dns_);
|
| - DCHECK(!abandoned_);
|
| -
|
| - for (size_t i = 0; i < alerts_and_errors_.size(); ++i) {
|
| - const AlertOrError& x = alerts_and_errors_[i];
|
| - DispatchAlertOrError(x.is_alert, x.line_number, x.message);
|
| - }
|
| -}
|
| -
|
| -void ProxyResolverV8Tracing::Job::DispatchAlertOrError(
|
| - bool is_alert, int line_number, const base::string16& message) {
|
| - CheckIsOnWorkerThread();
|
| -
|
| - // Note that the handling of cancellation is racy with regard to
|
| - // alerts/errors. The request might get cancelled shortly after this
|
| - // check! (There is no lock being held to guarantee otherwise).
|
| - //
|
| - // If this happens, then some information will get written to the NetLog
|
| - // needlessly, however the NetLog will still be alive so it shouldn't cause
|
| - // problems.
|
| - if (cancelled_.IsSet())
|
| - return;
|
| -
|
| - if (is_alert) {
|
| - // -------------------
|
| - // alert
|
| - // -------------------
|
| - VLOG(1) << "PAC-alert: " << message;
|
| -
|
| - // Send to the NetLog.
|
| - LogEventToCurrentRequestAndGlobally(
|
| - NetLog::TYPE_PAC_JAVASCRIPT_ALERT,
|
| - NetLog::StringCallback("message", &message));
|
| - } else {
|
| - // -------------------
|
| - // error
|
| - // -------------------
|
| - if (line_number == -1)
|
| - VLOG(1) << "PAC-error: " << message;
|
| - else
|
| - VLOG(1) << "PAC-error: " << "line: " << line_number << ": " << message;
|
| -
|
| - // Send the error to the NetLog.
|
| - LogEventToCurrentRequestAndGlobally(
|
| - NetLog::TYPE_PAC_JAVASCRIPT_ERROR,
|
| - base::Bind(&NetLogErrorCallback, line_number, &message));
|
| -
|
| - if (error_observer())
|
| - error_observer()->OnPACScriptError(line_number, message);
|
| - }
|
| -}
|
| -
|
| -void ProxyResolverV8Tracing::Job::LogEventToCurrentRequestAndGlobally(
|
| - NetLog::EventType type,
|
| - const NetLog::ParametersCallback& parameters_callback) {
|
| - CheckIsOnWorkerThread();
|
| - bound_net_log_.AddEvent(type, parameters_callback);
|
| -
|
| - // Emit to the global NetLog event stream.
|
| - if (net_log())
|
| - net_log()->AddGlobalEntry(type, parameters_callback);
|
| -}
|
| -
|
| -ProxyResolverV8Tracing::ProxyResolverV8Tracing(
|
| - HostResolver* host_resolver,
|
| - ProxyResolverErrorObserver* error_observer,
|
| - NetLog* net_log)
|
| - : ProxyResolver(true /*expects_pac_bytes*/),
|
| - host_resolver_(host_resolver),
|
| - error_observer_(error_observer),
|
| - net_log_(net_log),
|
| - num_outstanding_callbacks_(0) {
|
| - DCHECK(host_resolver);
|
| - // Start up the thread.
|
| - thread_.reset(new base::Thread("Proxy resolver"));
|
| - base::Thread::Options options;
|
| - options.timer_slack = base::TIMER_SLACK_MAXIMUM;
|
| - CHECK(thread_->StartWithOptions(options));
|
| -
|
| - v8_resolver_.reset(new ProxyResolverV8);
|
| -}
|
| -
|
| -ProxyResolverV8Tracing::~ProxyResolverV8Tracing() {
|
| - // Note, all requests should have been cancelled.
|
| - CHECK(!set_pac_script_job_.get());
|
| - CHECK_EQ(0, num_outstanding_callbacks_);
|
| -
|
| - // Join the worker thread. See http://crbug.com/69710. Note that we call
|
| - // Stop() here instead of simply clearing thread_ since there may be pending
|
| - // callbacks on the worker thread which want to dereference thread_.
|
| - base::ThreadRestrictions::ScopedAllowIO allow_io;
|
| - thread_->Stop();
|
| -}
|
| -
|
| -int ProxyResolverV8Tracing::GetProxyForURL(const GURL& url,
|
| - ProxyInfo* results,
|
| - const CompletionCallback& callback,
|
| - RequestHandle* request,
|
| - const BoundNetLog& net_log) {
|
| - DCHECK(CalledOnValidThread());
|
| - DCHECK(!callback.is_null());
|
| - DCHECK(!set_pac_script_job_.get());
|
| -
|
| - scoped_refptr<Job> job = new Job(this);
|
| -
|
| - if (request)
|
| - *request = job.get();
|
| -
|
| - job->StartGetProxyForURL(url, results, net_log, callback);
|
| - return ERR_IO_PENDING;
|
| -}
|
| -
|
| -void ProxyResolverV8Tracing::CancelRequest(RequestHandle request) {
|
| - Job* job = reinterpret_cast<Job*>(request);
|
| - job->Cancel();
|
| -}
|
| -
|
| -LoadState ProxyResolverV8Tracing::GetLoadState(RequestHandle request) const {
|
| - Job* job = reinterpret_cast<Job*>(request);
|
| - return job->GetLoadState();
|
| -}
|
| -
|
| -void ProxyResolverV8Tracing::CancelSetPacScript() {
|
| - DCHECK(set_pac_script_job_.get());
|
| - set_pac_script_job_->Cancel();
|
| - set_pac_script_job_ = NULL;
|
| -}
|
| -
|
| -int ProxyResolverV8Tracing::SetPacScript(
|
| - const scoped_refptr<ProxyResolverScriptData>& script_data,
|
| - const CompletionCallback& callback) {
|
| - DCHECK(CalledOnValidThread());
|
| - DCHECK(!callback.is_null());
|
| -
|
| - // Note that there should not be any outstanding (non-cancelled) Jobs when
|
| - // setting the PAC script (ProxyService should guarantee this). If there are,
|
| - // then they might complete in strange ways after the new script is set.
|
| - DCHECK(!set_pac_script_job_.get());
|
| - CHECK_EQ(0, num_outstanding_callbacks_);
|
| -
|
| - set_pac_script_job_ = new Job(this);
|
| - set_pac_script_job_->StartSetPacScript(script_data, callback);
|
| -
|
| - return ERR_IO_PENDING;
|
| -}
|
| -
|
| -} // namespace net
|
|
|