This source file includes following definitions.
- NetLogErrorCallback
- IncrementWithoutOverflow
- metrics_num_errors_
- StartSetPacScript
- StartGetProxyForURL
- Cancel
- GetLoadState
- CheckIsOnWorkerThread
- CheckIsOnOriginThread
- SetCallback
- ReleaseCallback
- v8_resolver
- worker_loop
- host_resolver
- error_observer
- net_log
- NotifyCaller
- NotifyCallerOnOriginLoop
- RecordMetrics
- Start
- ExecuteBlocking
- ExecuteNonBlocking
- ExecuteProxyResolver
- ResolveDns
- Alert
- OnError
- ResolveDnsBlocking
- ResolveDnsNonBlocking
- PostDnsOperationAndWait
- DoDnsOperation
- OnDnsOperationComplete
- ScheduleRestartWithBlockingDns
- GetDnsFromLocalCache
- SaveDnsToLocalCache
- MakeDnsRequestInfo
- MakeDnsCacheKey
- HandleAlertOrError
- DispatchBufferedAlertsAndErrors
- DispatchAlertOrError
- LogEventToCurrentRequestAndGlobally
- num_outstanding_callbacks_
- GetProxyForURL
- CancelRequest
- GetLoadState
- CancelSetPacScript
- SetPacScript
#include "net/proxy/proxy_resolver_v8_tracing.h"
#include "base/bind.h"
#include "base/message_loop/message_loop_proxy.h"
#include "base/metrics/histogram.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"
namespace net {
namespace {
const size_t kMaxUniqueResolveDnsPerExec = 20;
const size_t kMaxAlertsAndErrorsBytes = 2048;
base::Value* NetLogErrorCallback(int line_number,
const base::string16* message,
NetLog::LogLevel ) {
base::DictionaryValue* dict = new base::DictionaryValue();
dict->SetInteger("line_number", line_number);
dict->SetString("message", *message);
return dict;
}
void IncrementWithoutOverflow(uint8* x) {
if (*x != 0xFF)
*x += 1;
}
}
class ProxyResolverV8Tracing::Job
: public base::RefCountedThreadSafe<ProxyResolverV8Tracing::Job>,
public ProxyResolverV8::JSBindings {
public:
explicit Job(ProxyResolverV8Tracing* parent);
void StartSetPacScript(
const scoped_refptr<ProxyResolverScriptData>& script_data,
const CompletionCallback& callback);
void StartGetProxyForURL(const GURL& url,
ProxyInfo* results,
const BoundNetLog& net_log,
const CompletionCallback& callback);
void Cancel();
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;
};
virtual ~Job();
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();
void NotifyCaller(int result);
void NotifyCallerOnOriginLoop(int result);
void RecordMetrics() const;
void Start(Operation op, bool blocking_dns,
const CompletionCallback& callback);
void ExecuteBlocking();
void ExecuteNonBlocking();
int ExecuteProxyResolver();
virtual bool ResolveDns(const std::string& host,
ResolveDnsOperation op,
std::string* output,
bool* terminate) OVERRIDE;
virtual void Alert(const base::string16& message) OVERRIDE;
virtual 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);
static HostResolver::RequestInfo MakeDnsRequestInfo(const std::string& host,
ResolveDnsOperation op);
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);
scoped_refptr<base::MessageLoopProxy> origin_loop_;
ProxyResolverV8Tracing* parent_;
CompletionCallback callback_;
base::CancellationFlag cancelled_;
Operation operation_;
bool blocking_dns_;
base::WaitableEvent event_;
DnsCache dns_cache_;
scoped_refptr<Job> owned_self_reference_;
scoped_refptr<ProxyResolverScriptData> script_data_;
ProxyInfo* user_results_;
GURL url_;
ProxyInfo results_;
BoundNetLog bound_net_log_;
bool abandoned_;
int num_dns_;
std::vector<AlertOrError> alerts_and_errors_;
size_t alerts_and_errors_byte_cost_;
int last_num_dns_;
bool should_restart_with_blocking_dns_;
HostResolver::RequestHandle pending_dns_;
bool pending_dns_completed_synchronously_;
std::string pending_dns_host_;
ResolveDnsOperation pending_dns_op_;
AddressList pending_dns_addresses_;
base::TimeTicks metrics_start_time_;
base::TimeTicks metrics_end_time_;
base::TimeTicks metrics_pending_dns_start_;
base::TimeDelta metrics_dns_total_time_;
uint8 metrics_num_executions_;
uint8 metrics_num_unique_dns_;
uint8 metrics_num_alerts_;
uint8 metrics_num_errors_;
base::TimeDelta metrics_execution_time_;
base::TimeDelta metrics_abandoned_execution_total_time_;
base::TimeDelta metrics_nonblocking_dns_wait_total_time_;
};
ProxyResolverV8Tracing::Job::Job(ProxyResolverV8Tracing* parent)
: origin_loop_(base::MessageLoopProxy::current()),
parent_(parent),
event_(true, false),
last_num_dns_(0),
pending_dns_(NULL),
metrics_num_executions_(0),
metrics_num_unique_dns_(0),
metrics_num_alerts_(0),
metrics_num_errors_(0) {
CheckIsOnOriginThread();
}
void ProxyResolverV8Tracing::Job::StartSetPacScript(
const scoped_refptr<ProxyResolverScriptData>& script_data,
const CompletionCallback& callback) {
CheckIsOnOriginThread();
script_data_ = script_data;
Start(SET_PAC_SCRIPT, true , 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 , callback);
}
void ProxyResolverV8Tracing::Job::Cancel() {
CheckIsOnOriginThread();
cancelled_.Set();
ReleaseCallback();
if (pending_dns_) {
host_resolver()->CancelRequest(pending_dns_);
pending_dns_ = NULL;
}
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();
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();
metrics_end_time_ = base::TimeTicks::Now();
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) {
RecordMetrics();
*user_results_ = results_;
}
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::RecordMetrics() const {
CheckIsOnOriginThread();
DCHECK_EQ(GET_PROXY_FOR_URL, operation_);
base::TimeTicks now = base::TimeTicks::Now();
#define UPDATE_HISTOGRAMS(base_name) \
do {\
UMA_HISTOGRAM_MEDIUM_TIMES(base_name "TotalTime", now - metrics_start_time_);\
UMA_HISTOGRAM_MEDIUM_TIMES(base_name "TotalTimeWorkerThread",\
metrics_end_time_ - metrics_start_time_);\
UMA_HISTOGRAM_TIMES(base_name "OriginThreadLatency",\
now - metrics_end_time_);\
UMA_HISTOGRAM_MEDIUM_TIMES(base_name "TotalTimeDNS",\
metrics_dns_total_time_);\
UMA_HISTOGRAM_MEDIUM_TIMES(base_name "ExecutionTime",\
metrics_execution_time_);\
UMA_HISTOGRAM_MEDIUM_TIMES(base_name "AbandonedExecutionTotalTime",\
metrics_abandoned_execution_total_time_);\
UMA_HISTOGRAM_MEDIUM_TIMES(base_name "DnsWaitTotalTime",\
metrics_nonblocking_dns_wait_total_time_);\
UMA_HISTOGRAM_CUSTOM_COUNTS(\
base_name "NumRestarts", metrics_num_executions_ - 1,\
1, kMaxUniqueResolveDnsPerExec, kMaxUniqueResolveDnsPerExec);\
UMA_HISTOGRAM_CUSTOM_COUNTS(\
base_name "UniqueDNS", metrics_num_unique_dns_,\
1, kMaxUniqueResolveDnsPerExec, kMaxUniqueResolveDnsPerExec);\
UMA_HISTOGRAM_COUNTS_100(base_name "NumAlerts", metrics_num_alerts_);\
UMA_HISTOGRAM_CUSTOM_COUNTS(\
base_name "NumErrors", metrics_num_errors_, 1, 10, 10);\
} while (false)
if (!blocking_dns_)
UPDATE_HISTOGRAMS("Net.ProxyResolver.");
else
UPDATE_HISTOGRAMS("Net.ProxyResolver.BlockingDNSMode.");
#undef UPDATE_HISTOGRAMS
if (!blocking_dns_) {
size_t url_size = url_.spec().size();
UMA_HISTOGRAM_CUSTOM_COUNTS(
"Net.ProxyResolver.URLSize", url_size, 1, 200000, 50);
if (url_size > 2048) {
UMA_HISTOGRAM_MEDIUM_TIMES("Net.ProxyResolver.ExecutionTime_UrlOver2K",
metrics_execution_time_);
}
if (url_size > 4096) {
UMA_HISTOGRAM_MEDIUM_TIMES("Net.ProxyResolver.ExecutionTime_UrlOver4K",
metrics_execution_time_);
}
if (url_size > 8192) {
UMA_HISTOGRAM_MEDIUM_TIMES("Net.ProxyResolver.ExecutionTime_UrlOver8K",
metrics_execution_time_);
}
if (url_size > 131072) {
UMA_HISTOGRAM_MEDIUM_TIMES("Net.ProxyResolver.ExecutionTime_UrlOver128K",
metrics_execution_time_);
}
}
}
void ProxyResolverV8Tracing::Job::Start(Operation op, bool blocking_dns,
const CompletionCallback& callback) {
CheckIsOnOriginThread();
metrics_start_time_ = base::TimeTicks::Now();
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;
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 (abandoned_)
metrics_abandoned_execution_total_time_ += metrics_execution_time_;
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() {
IncrementWithoutOverflow(&metrics_num_executions_);
base::TimeTicks start = base::TimeTicks::Now();
JSBindings* prev_bindings = v8_resolver()->js_bindings();
v8_resolver()->set_js_bindings(this);
int result = ERR_UNEXPECTED;
switch (operation_) {
case SET_PAC_SCRIPT:
result = v8_resolver()->SetPacScript(
script_data_, CompletionCallback());
break;
case GET_PROXY_FOR_URL:
result = v8_resolver()->GetProxyForURL(
url_,
&results_,
CompletionCallback(),
NULL,
bound_net_log_);
break;
}
v8_resolver()->set_js_bindings(prev_bindings);
metrics_execution_time_ = base::TimeTicks::Now() - start;
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()) {
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();
bool rv;
if (GetDnsFromLocalCache(host, op, output, &rv)) {
return rv;
}
IncrementWithoutOverflow(&metrics_num_unique_dns_);
if (dns_cache_.size() >= kMaxUniqueResolveDnsPerExec) {
return false;
}
if (!PostDnsOperationAndWait(host, op, NULL))
return false;
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_) {
return false;
}
num_dns_ += 1;
bool rv;
if (GetDnsFromLocalCache(host, op, output, &rv)) {
return rv;
}
IncrementWithoutOverflow(&metrics_num_unique_dns_);
if (num_dns_ <= last_num_dns_) {
ScheduleRestartWithBlockingDns();
*terminate = true;
return false;
}
if (dns_cache_.size() >= kMaxUniqueResolveDnsPerExec) {
return false;
}
DCHECK(!should_restart_with_blocking_dns_);
bool completed_synchronously;
if (!PostDnsOperationAndWait(host, op, &completed_synchronously))
return false;
if (completed_synchronously) {
CHECK(GetDnsFromLocalCache(host, op, output, &rv));
return rv;
}
abandoned_ = true;
*terminate = true;
last_num_dns_ = num_dns_;
return false;
}
bool ProxyResolverV8Tracing::Job::PostDnsOperationAndWait(
const std::string& host, ResolveDnsOperation op,
bool* completed_synchronously) {
base::TimeTicks start = base::TimeTicks::Now();
DCHECK(!pending_dns_);
metrics_pending_dns_start_ = base::TimeTicks::Now();
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_;
if (!blocking_dns_)
metrics_nonblocking_dns_wait_total_time_ += base::TimeTicks::Now() - start;
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;
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;
}
if (!blocking_dns_) {
event_.Signal();
}
}
void ProxyResolverV8Tracing::Job::OnDnsOperationComplete(int result) {
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;
metrics_dns_total_time_ +=
base::TimeTicks::Now() - metrics_pending_dns_start_;
if (blocking_dns_) {
event_.Signal();
return;
}
if (!blocking_dns_ && !pending_dns_completed_synchronously_) {
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;
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();
std::string cache_value;
if (net_error != OK) {
cache_value = std::string();
} else if (op == DNS_RESOLVE || op == MY_IP_ADDRESS) {
cache_value = addresses.front().ToStringWithoutPort();
} else {
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;
}
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);
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_) {
DispatchAlertOrError(is_alert, line_number, message);
return;
}
if (abandoned_)
return;
alerts_and_errors_byte_cost_ += sizeof(AlertOrError) + message.size() * 2;
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();
if (cancelled_.IsSet())
return;
if (is_alert) {
IncrementWithoutOverflow(&metrics_num_alerts_);
VLOG(1) << "PAC-alert: " << message;
LogEventToCurrentRequestAndGlobally(
NetLog::TYPE_PAC_JAVASCRIPT_ALERT,
NetLog::StringCallback("message", &message));
} else {
IncrementWithoutOverflow(&metrics_num_errors_);
if (line_number == -1)
VLOG(1) << "PAC-error: " << message;
else
VLOG(1) << "PAC-error: " << "line: " << line_number << ": " << message;
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);
if (net_log())
net_log()->AddGlobalEntry(type, parameters_callback);
}
ProxyResolverV8Tracing::ProxyResolverV8Tracing(
HostResolver* host_resolver,
ProxyResolverErrorObserver* error_observer,
NetLog* net_log)
: ProxyResolver(true ),
host_resolver_(host_resolver),
error_observer_(error_observer),
net_log_(net_log),
num_outstanding_callbacks_(0) {
DCHECK(host_resolver);
thread_.reset(new base::Thread("Proxy resolver"));
CHECK(thread_->Start());
v8_resolver_.reset(new ProxyResolverV8);
}
ProxyResolverV8Tracing::~ProxyResolverV8Tracing() {
CHECK(!set_pac_script_job_.get());
CHECK_EQ(0, num_outstanding_callbacks_);
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());
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;
}
}