diff options
author | ukai@chromium.org <ukai@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-11-11 06:59:38 +0000 |
---|---|---|
committer | ukai@chromium.org <ukai@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-11-11 06:59:38 +0000 |
commit | 7c7377aa746c05b3cfd0cb4b61c3514b7ea38d0f (patch) | |
tree | 783a06a8981cb80103c26cc36366a15d49f5f2f1 | |
parent | 6a781684b760689def3447b084493ca7e1877a82 (diff) | |
download | chromium_src-7c7377aa746c05b3cfd0cb4b61c3514b7ea38d0f.zip chromium_src-7c7377aa746c05b3cfd0cb4b61c3514b7ea38d0f.tar.gz chromium_src-7c7377aa746c05b3cfd0cb4b61c3514b7ea38d0f.tar.bz2 |
WebSocket Live Experiment
BUG=none
TEST=none
Review URL: http://codereview.chromium.org/369002
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@31653 0039d316-1c4b-4281-b951-d872f2087c98
6 files changed, 511 insertions, 37 deletions
diff --git a/chrome/browser/browser_main.cc b/chrome/browser/browser_main.cc index 6475c88..78e35dc 100644 --- a/chrome/browser/browser_main.cc +++ b/chrome/browser/browser_main.cc @@ -39,6 +39,7 @@ #include "chrome/browser/net/dns_global.h" #include "chrome/browser/net/metadata_url_request.h" #include "chrome/browser/net/sdch_dictionary_fetcher.h" +#include "chrome/browser/net/websocket_experiment/websocket_experiment_runner.h" #include "chrome/browser/plugin_service.h" #include "chrome/browser/process_singleton.h" #include "chrome/browser/profile_manager.h" @@ -831,7 +832,9 @@ int BrowserMain(const MainFunctionParams& parameters) { if (enabled) metrics->Start(); } + chrome_browser_net_websocket_experiment::WebSocketExperimentRunner::Start(); } + InstallJankometer(parsed_command_line); #if defined(OS_WIN) && !defined(GOOGLE_CHROME_BUILD) @@ -877,6 +880,7 @@ int BrowserMain(const MainFunctionParams& parameters) { RunUIMessageLoop(browser_process.get()); } } + chrome_browser_net_websocket_experiment::WebSocketExperimentRunner::Stop(); process_singleton.Cleanup(); diff --git a/chrome/browser/net/websocket_experiment/websocket_experiment_runner.cc b/chrome/browser/net/websocket_experiment/websocket_experiment_runner.cc new file mode 100644 index 0000000..43981b0 --- /dev/null +++ b/chrome/browser/net/websocket_experiment/websocket_experiment_runner.cc @@ -0,0 +1,332 @@ +// Copyright (c) 2009 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 "chrome/browser/net/websocket_experiment/websocket_experiment_runner.h" + +#include "base/compiler_specific.h" +#include "base/histogram.h" +#include "base/message_loop.h" +#include "base/task.h" +#include "chrome/browser/chrome_thread.h" +#include "net/base/net_errors.h" + +namespace chrome_browser_net_websocket_experiment { + +static const char *kExperimentHost = "websocket-experiment.chromium.org"; +static const int kAlternativePort = 61985; + +static const char kLastStateName[] = "LastState"; +static const char kUrlFetchName[] = "UrlFetch"; +static const char kWebSocketConnectName[] = "WebSocketConnect"; +static const char kWebSocketEchoName[] = "WebSocketEcho"; +static const char kWebSocketIdleName[] = "WebSocketIdle"; +static const char kWebSocketTotalName[] = "WebSocketTotal"; +static const int kUrlFetchDeadlineSec = 10; +static const int kWebSocketConnectDeadlineSec = 10; +static const int kWebSocketEchoDeadlineSec = 5; +static const int kWebSocketIdleSec = 1; +static const int kWebSocketPushDeadlineSec = 1; +static const int kWebSocketByeDeadlineSec = 10; +static const int kWebSocketCloseDeadlineSec = 5; +static const int kWebSocketTimeSec = 10; + +// Hold reference while experiment is running. +static scoped_refptr<WebSocketExperimentRunner> runner; + +/* static */ +void WebSocketExperimentRunner::Start() { + DCHECK(!runner.get()); + runner = new WebSocketExperimentRunner; + runner->Run(); +} + +/* static */ +void WebSocketExperimentRunner::Stop() { + if (runner.get()) + runner->Cancel(); + runner = NULL; +} + +WebSocketExperimentRunner::WebSocketExperimentRunner() + : next_state_(STATE_NONE), + task_state_(STATE_NONE), + ALLOW_THIS_IN_INITIALIZER_LIST( + task_callback_(this, &WebSocketExperimentRunner::OnTaskCompleted)) { + InitConfig(); + InitHistograms(); +} + +WebSocketExperimentRunner::~WebSocketExperimentRunner() { + DLOG(INFO) << "WebSocketExperimentRunner deleted"; + DCHECK(!task_.get()); +} + +void WebSocketExperimentRunner::Run() { + DCHECK_EQ(next_state_, STATE_NONE); + next_state_ = STATE_RUN_WS; + ChromeThread::PostDelayedTask( + ChromeThread::IO, + FROM_HERE, + NewRunnableMethod(this, &WebSocketExperimentRunner::DoLoop), + config_.initial_delay_ms); +} + +void WebSocketExperimentRunner::Cancel() { + next_state_ = STATE_NONE; + ChromeThread::PostTask( + ChromeThread::IO, + FROM_HERE, + NewRunnableMethod(this, &WebSocketExperimentRunner::DoLoop)); +} + +void WebSocketExperimentRunner::InitConfig() { + config_.initial_delay_ms = 5 * 60 * 1000; // 5 mins + config_.next_delay_ms = 12 * 60 * 60 * 1000; // 12 hours + + WebSocketExperimentTask::Config task_config; + task_config.ws_protocol = "google-websocket-liveexperiment"; + task_config.ws_origin = "http://dev.chromium.org/"; + task_config.url_fetch_deadline_ms = kUrlFetchDeadlineSec * 1000; + task_config.websocket_onopen_deadline_ms = + kWebSocketConnectDeadlineSec * 1000; + task_config.websocket_hello_message = "Hello"; + task_config.websocket_hello_echoback_deadline_ms = + kWebSocketEchoDeadlineSec * 1000; + // Note: wait 1.5 sec in websocket_experiment_def.txt + task_config.websocket_idle_ms = kWebSocketIdleSec * 1000; + task_config.websocket_receive_push_message_deadline_ms = + kWebSocketPushDeadlineSec * 1000; + task_config.websocket_bye_message = "Bye"; + task_config.websocket_bye_deadline_ms = + kWebSocketByeDeadlineSec * 1000; + task_config.websocket_close_deadline_ms = + kWebSocketCloseDeadlineSec * 1000; + + config_.ws_config = task_config; + config_.ws_config.url = + GURL(StringPrintf("ws://%s/live_exp", kExperimentHost)); + config_.ws_config.ws_location = + StringPrintf("ws://%s/live_exp", kExperimentHost); + config_.ws_config.http_url = + GURL(StringPrintf("http://%s/", kExperimentHost)); + + config_.wss_config = task_config; + config_.wss_config.url = + GURL(StringPrintf("wss://%s/live_exp", kExperimentHost)); + config_.wss_config.ws_location = + StringPrintf("wss://%s/live_exp", kExperimentHost); + config_.wss_config.http_url = + GURL(StringPrintf("https://%s/", kExperimentHost)); + + config_.ws_nondefault_config = task_config; + config_.ws_nondefault_config.url = + GURL(StringPrintf("ws://%s:%d/live_exp", + kExperimentHost, kAlternativePort)); + config_.ws_nondefault_config.ws_location = + StringPrintf("ws://%s:%d/live_exp", + kExperimentHost, kAlternativePort); + config_.ws_nondefault_config.http_url = + GURL(StringPrintf("http://%s:%d/", + kExperimentHost, kAlternativePort)); +} + +void WebSocketExperimentRunner::InitHistograms() { + InitHistogram<LinearHistogram, Histogram::Sample>( + kLastStateName, 1, WebSocketExperimentTask::NUM_STATES, + WebSocketExperimentTask::NUM_STATES + 1); + + InitHistogram<Histogram, base::TimeDelta>( + kUrlFetchName, base::TimeDelta::FromMilliseconds(1), + base::TimeDelta::FromSeconds(kUrlFetchDeadlineSec), 50); + + InitHistogram<Histogram, base::TimeDelta>( + kWebSocketConnectName, base::TimeDelta::FromMilliseconds(1), + base::TimeDelta::FromSeconds(kWebSocketConnectDeadlineSec), 50); + + InitHistogram<Histogram, base::TimeDelta>( + kWebSocketEchoName, base::TimeDelta::FromMilliseconds(1), + base::TimeDelta::FromSeconds(kWebSocketEchoDeadlineSec), 50); + + InitHistogram<Histogram, base::TimeDelta>( + kWebSocketIdleName, base::TimeDelta::FromMilliseconds(1), + base::TimeDelta::FromSeconds( + kWebSocketIdleSec + kWebSocketPushDeadlineSec), 50); + + InitHistogram<Histogram, base::TimeDelta>( + kWebSocketTotalName, base::TimeDelta::FromMilliseconds(1), + base::TimeDelta::FromSeconds(kWebSocketTimeSec), 50); +} + +void WebSocketExperimentRunner::DoLoop() { + if (next_state_ == STATE_NONE) { + if (task_.get()) { + AddRef(); // Release in OnTaskCompleted. + task_->Cancel(); + } + return; + } + + State state = next_state_; + task_state_ = STATE_NONE; + next_state_ = STATE_NONE; + + DLOG(INFO) << "WebSocketExperiment state=" << state; + switch (state) { + case STATE_IDLE: + task_.reset(); + next_state_ = STATE_RUN_WS; + ChromeThread::PostDelayedTask( + ChromeThread::IO, + FROM_HERE, + NewRunnableMethod(this, &WebSocketExperimentRunner::DoLoop), + config_.next_delay_ms); + break; + case STATE_RUN_WS: + task_.reset(new WebSocketExperimentTask(config_.ws_config, + &task_callback_)); + task_state_ = STATE_RUN_WS; + next_state_ = STATE_RUN_WSS; + break; + case STATE_RUN_WSS: + task_.reset(new WebSocketExperimentTask(config_.wss_config, + &task_callback_)); + task_state_ = STATE_RUN_WSS; + next_state_ = STATE_RUN_WS_NODEFAULT_PORT; + break; + case STATE_RUN_WS_NODEFAULT_PORT: + task_.reset(new WebSocketExperimentTask(config_.ws_nondefault_config, + &task_callback_)); + task_state_ = STATE_RUN_WS_NODEFAULT_PORT; + next_state_ = STATE_IDLE; + break; + default: + NOTREACHED(); + break; + } + if (task_.get()) + task_->Run(); +} + +void WebSocketExperimentRunner::OnTaskCompleted(int result) { + DLOG(INFO) << "WebSocketExperiment TaskCompleted result=" + << net::ErrorToString(result); + if (result == net::ERR_ABORTED) { + task_.reset(); + // Task is Canceled. + Release(); + return; + } + UpdateTaskResultHistogram(task_.get()); + task_.reset(); + + DoLoop(); +} + +void WebSocketExperimentRunner::UpdateTaskResultHistogram( + const WebSocketExperimentTask* task) { + DCHECK(task); + const WebSocketExperimentTask::Config& task_config = task->config(); + const WebSocketExperimentTask::Result& task_result = task->result(); + DLOG(INFO) << "Result for url=" << task_config.url + << " last_result=" + << net::ErrorToString(task_result.last_result) + << " last_state=" << task_result.last_state + << " url_fetch=" << task_result.url_fetch.InSecondsF() + << " websocket_connect=" + << task_result.websocket_connect.InSecondsF() + << " websocket_echo=" + << task_result.websocket_echo.InSecondsF() + << " websocket_idle=" + << task_result.websocket_idle.InSecondsF() + << " websocket_total=" + << task_result.websocket_total.InSecondsF(); + + + Histogram* last_state = GetHistogram(kLastStateName); + DCHECK(last_state); + last_state->Add(task_result.last_state); + + Histogram* url_fetch = GetHistogram(kUrlFetchName); + DCHECK(url_fetch); + url_fetch->AddTime(task_result.url_fetch); + + if (task_result.last_state < + WebSocketExperimentTask::STATE_WEBSOCKET_CONNECT_COMPLETE) + return; + + Histogram* websocket_connect = GetHistogram(kWebSocketConnectName); + DCHECK(websocket_connect); + websocket_connect->AddTime(task_result.websocket_connect); + + if (task_result.last_state < + WebSocketExperimentTask::STATE_WEBSOCKET_RECV_HELLO) + return; + + Histogram* websocket_echo = GetHistogram(kWebSocketEchoName); + DCHECK(websocket_echo); + websocket_echo->AddTime(task_result.websocket_echo); + + if (task_result.last_state < + WebSocketExperimentTask::STATE_WEBSOCKET_KEEP_IDLE) + return; + + Histogram* websocket_idle = GetHistogram(kWebSocketIdleName); + DCHECK(websocket_idle); + websocket_idle->AddTime(task_result.websocket_idle); + + if (task_result.last_state < + WebSocketExperimentTask::STATE_WEBSOCKET_CLOSE_COMPLETE) + return; + + Histogram* websocket_total = GetHistogram(kWebSocketTotalName); + DCHECK(websocket_total); + websocket_total->AddTime(task_result.websocket_total); +} + +template<class HistogramType, typename HistogramSample> +void WebSocketExperimentRunner::InitHistogram( + const char* type_name, + HistogramSample min, HistogramSample max, size_t bucket_count) { + static std::string name = StringPrintf( + "WebSocketExperiment.Basic.%s", type_name); + HistogramType* counter = new HistogramType(name.c_str(), + min, max, bucket_count); + counter->SetFlags(kUmaTargetedHistogramFlag); + ws_histograms_[type_name] = linked_ptr<Histogram>(counter); + + name = StringPrintf("WebSocketExperiment.Secure.%s", type_name); + counter = new HistogramType(name.c_str(), min, max, bucket_count); + counter->SetFlags(kUmaTargetedHistogramFlag); + wss_histograms_[type_name] = linked_ptr<Histogram>(counter); + + name = StringPrintf("WebSocketExperiment.NoDefaultPort.%s", type_name); + counter = new HistogramType(name.c_str(), min, max, bucket_count); + counter->SetFlags(kUmaTargetedHistogramFlag); + ws_nondefault_histograms_[type_name] = linked_ptr<Histogram>(counter); +} + +Histogram* WebSocketExperimentRunner::GetHistogram( + const std::string& type_name) const { + const HistogramMap* histogram_map = NULL; + switch (task_state_) { + case STATE_RUN_WS: + histogram_map = &ws_histograms_; + break; + case STATE_RUN_WSS: + histogram_map = &wss_histograms_; + break; + case STATE_RUN_WS_NODEFAULT_PORT: + histogram_map = &ws_nondefault_histograms_; + break; + default: + NOTREACHED(); + return NULL; + } + DCHECK(histogram_map); + HistogramMap::const_iterator found = histogram_map->find(type_name); + DCHECK(found != histogram_map->end()); + return found->second.get(); +} + +} // namespace chrome_browser_net_websocket_experiment diff --git a/chrome/browser/net/websocket_experiment/websocket_experiment_runner.h b/chrome/browser/net/websocket_experiment/websocket_experiment_runner.h new file mode 100644 index 0000000..efc5da2 --- /dev/null +++ b/chrome/browser/net/websocket_experiment/websocket_experiment_runner.h @@ -0,0 +1,81 @@ +// Copyright (c) 2009 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. + +#ifndef CHROME_BROWSER_NET_WEBSOCKET_EXPERIMENT_WEBSOCKET_EXPERIMENT_RUNNER_H_ +#define CHROME_BROWSER_NET_WEBSOCKET_EXPERIMENT_WEBSOCKET_EXPERIMENT_RUNNER_H_ + +#include "base/basictypes.h" +#include "base/histogram.h" +#include "base/linked_ptr.h" +#include "base/ref_counted.h" +#include "base/scoped_ptr.h" +#include "chrome/browser/net/websocket_experiment/websocket_experiment_task.h" +#include "net/base/completion_callback.h" + +namespace chrome_browser_net_websocket_experiment { + +class WebSocketExperimentRunner + : public base::RefCountedThreadSafe<WebSocketExperimentRunner> { + public: + class Config { + public: + Config() + : initial_delay_ms(0), + next_delay_ms(0) {} + + int64 initial_delay_ms; + int64 next_delay_ms; + WebSocketExperimentTask::Config ws_config; + WebSocketExperimentTask::Config wss_config; + WebSocketExperimentTask::Config ws_nondefault_config; + }; + static void Start(); + static void Stop(); + + void Run(); + void Cancel(); + + private: + typedef std::map<std::string, linked_ptr<Histogram> > HistogramMap; + + enum State { + STATE_NONE, + STATE_IDLE, + STATE_RUN_WS, + STATE_RUN_WSS, + STATE_RUN_WS_NODEFAULT_PORT, + }; + WebSocketExperimentRunner(); + virtual ~WebSocketExperimentRunner(); + friend class base::RefCountedThreadSafe<WebSocketExperimentRunner>; + + void InitConfig(); + void InitHistograms(); + void DoLoop(); + void OnTaskCompleted(int result); + void UpdateTaskResultHistogram(const WebSocketExperimentTask* task); + + template<class HistogramType, typename HistogramSample> + void InitHistogram(const char* type_name, + HistogramSample min, HistogramSample max, + size_t bucket_count); + + Histogram* GetHistogram(const std::string& type_name) const; + + Config config_; + State next_state_; + State task_state_; + scoped_ptr<WebSocketExperimentTask> task_; + net::CompletionCallbackImpl<WebSocketExperimentRunner> task_callback_; + + HistogramMap ws_histograms_; + HistogramMap wss_histograms_; + HistogramMap ws_nondefault_histograms_; + + DISALLOW_COPY_AND_ASSIGN(WebSocketExperimentRunner); +}; + +} // namespace chrome_browser_net_websocket_experiment + +#endif // CHROME_BROWSER_NET_WEBSOCKET_EXPERIMENT_WEBSOCKET_EXPERIMENT_RUNNER_H_ diff --git a/chrome/browser/net/websocket_experiment/websocket_experiment_task.cc b/chrome/browser/net/websocket_experiment/websocket_experiment_task.cc index 94e0f50..a988008 100644 --- a/chrome/browser/net/websocket_experiment/websocket_experiment_task.cc +++ b/chrome/browser/net/websocket_experiment/websocket_experiment_task.cc @@ -4,43 +4,57 @@ #include "chrome/browser/net/websocket_experiment/websocket_experiment_task.h" -#include "base/message_loop.h" +#include "chrome/browser/chrome_thread.h" #include "chrome/browser/net/url_request_context_getter.h" #include "chrome/browser/profile.h" +#include "net/base/load_flags.h" +#include "net/base/net_errors.h" #include "net/websockets/websocket.h" namespace chrome_browser_net_websocket_experiment { -URLFetcher* WebSocketExperimentTask::Context::CreateURLFetcher() { - return new URLFetcher(config_.http_url, URLFetcher::HEAD, task_); +URLFetcher* WebSocketExperimentTask::Context::CreateURLFetcher( + const Config& config, URLFetcher::Delegate* delegate) { + URLRequestContextGetter* getter = + Profile::GetDefaultRequestContext(); + DCHECK(getter); + DLOG(INFO) << "url=" << config.http_url; + URLFetcher* fetcher = + new URLFetcher(config.http_url, URLFetcher::GET, delegate); + fetcher->set_request_context(getter); + fetcher->set_load_flags( + net::LOAD_BYPASS_CACHE | net::LOAD_DISABLE_CACHE | + net::LOAD_DO_NOT_SEND_COOKIES | net::LOAD_DO_NOT_SEND_AUTH_DATA); + return fetcher; } -net::WebSocket* WebSocketExperimentTask::Context::CreateWebSocket() { +net::WebSocket* WebSocketExperimentTask::Context::CreateWebSocket( + const Config& config, net::WebSocketDelegate* delegate) { URLRequestContextGetter* getter = Profile::GetDefaultRequestContext(); DCHECK(getter); net::WebSocket::Request* request( - new net::WebSocket::Request(config_.url, - config_.ws_protocol, - config_.ws_origin, - config_.ws_location, + new net::WebSocket::Request(config.url, + config.ws_protocol, + config.ws_origin, + config.ws_location, getter->GetURLRequestContext())); - return new net::WebSocket(request, task_); + return new net::WebSocket(request, delegate); } WebSocketExperimentTask::WebSocketExperimentTask( const Config& config, net::CompletionCallback* callback) : config_(config), - context_(ALLOW_THIS_IN_INITIALIZER_LIST(new Context(config, this))), - message_loop_(MessageLoopForIO::current()), + context_(ALLOW_THIS_IN_INITIALIZER_LIST(new Context())), method_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)), callback_(callback), - next_state_(STATE_NONE) { - DCHECK(message_loop_); + next_state_(STATE_NONE), + last_websocket_error_(net::OK) { } WebSocketExperimentTask::~WebSocketExperimentTask() { + DLOG(INFO) << "WebSocketExperimentTask finished"; DCHECK(!websocket_); } @@ -49,6 +63,11 @@ void WebSocketExperimentTask::Run() { DoLoop(net::OK); } +void WebSocketExperimentTask::Cancel() { + next_state_ = STATE_NONE; + DoLoop(net::OK); +} + // URLFetcher::Delegate method. void WebSocketExperimentTask::OnURLFetchComplete( const URLFetcher* source, @@ -59,10 +78,12 @@ void WebSocketExperimentTask::OnURLFetchComplete( const std::string& data) { result_.url_fetch = base::TimeTicks::Now() - url_fetch_start_time_; RevokeTimeoutTimer(); + DLOG(INFO) << "OnURLFetchCompleted"; int result = net::ERR_FAILED; - if (next_state_ != STATE_URL_FETCH_COMPLETE) + if (next_state_ != STATE_URL_FETCH_COMPLETE) { + DLOG(INFO) << "unexpected state=" << next_state_; result = net::ERR_UNEXPECTED; - else if (response_code == 200) + } else if (response_code == 200 || response_code == 304) result = net::OK; DoLoop(result); } @@ -72,10 +93,12 @@ void WebSocketExperimentTask::OnOpen(net::WebSocket* websocket) { result_.websocket_connect = base::TimeTicks::Now() - websocket_connect_start_time_; RevokeTimeoutTimer(); + int result = net::ERR_UNEXPECTED; if (next_state_ == STATE_WEBSOCKET_CONNECT_COMPLETE) - DoLoop(net::OK); + result = net::OK; else - DoLoop(net::ERR_UNEXPECTED); + DLOG(INFO) << "unexpected state=" << next_state_; + DoLoop(result); } void WebSocketExperimentTask::OnMessage( @@ -88,6 +111,7 @@ void WebSocketExperimentTask::OnMessage( result_.websocket_idle = base::TimeTicks::Now() - websocket_idle_start_time_; RevokeTimeoutTimer(); + DLOG(INFO) << "OnMessage msg=" << msg; received_messages_.push_back(msg); int result = net::ERR_UNEXPECTED; switch (next_state_) { @@ -97,6 +121,7 @@ void WebSocketExperimentTask::OnMessage( result = net::OK; break; default: + DLOG(INFO) << "unexpected state=" << next_state_; break; } DoLoop(result); @@ -104,25 +129,42 @@ void WebSocketExperimentTask::OnMessage( void WebSocketExperimentTask::OnClose(net::WebSocket* websocket) { RevokeTimeoutTimer(); + websocket_ = NULL; + result_.websocket_total = + base::TimeTicks::Now() - websocket_connect_start_time_; int result = net::ERR_CONNECTION_CLOSED; + if (last_websocket_error_ != net::OK) + result = last_websocket_error_; if (next_state_ == STATE_WEBSOCKET_CLOSE_COMPLETE) result = net::OK; DoLoop(result); } +void WebSocketExperimentTask::OnError( + const net::WebSocket* websocket, int error) { + DLOG(INFO) << "WebSocket error=" << net::ErrorToString(error); + last_websocket_error_ = error; +} + void WebSocketExperimentTask::SetContext(Context* context) { context_.reset(context); } void WebSocketExperimentTask::OnTimedOut() { + DLOG(INFO) << "OnTimedOut"; RevokeTimeoutTimer(); DoLoop(net::ERR_TIMED_OUT); } void WebSocketExperimentTask::DoLoop(int result) { + if (next_state_ == STATE_NONE) { + Finish(net::ERR_ABORTED); + return; + } do { State state = next_state_; next_state_ = STATE_NONE; + DLOG(INFO) << "WebSocketExperimentTask state=" << state; switch (state) { case STATE_URL_FETCH: result = DoURLFetch(); @@ -167,8 +209,11 @@ void WebSocketExperimentTask::DoLoop(int result) { NOTREACHED(); break; } + result_.last_state = state; } while (result != net::ERR_IO_PENDING && next_state_ != STATE_NONE); + DLOG(INFO) << "WebSocketExperiemntTask Loop done next_state=" << next_state_ + << " result=" << net::ErrorToString(result); if (result != net::ERR_IO_PENDING) Finish(result); } @@ -177,15 +222,17 @@ int WebSocketExperimentTask::DoURLFetch() { next_state_ = STATE_URL_FETCH_COMPLETE; DCHECK(!url_fetcher_.get()); - url_fetcher_.reset(context_->CreateURLFetcher()); + url_fetcher_.reset(context_->CreateURLFetcher(config_, this)); + SetTimeout(config_.url_fetch_deadline_ms); + DLOG(INFO) << "URLFetch url=" << url_fetcher_->url() + << " timeout=" << config_.url_fetch_deadline_ms; url_fetch_start_time_ = base::TimeTicks::Now(); url_fetcher_->Start(); - - SetTimeout(config_.url_fetch_deadline_ms); return net::ERR_IO_PENDING; } int WebSocketExperimentTask::DoURLFetchComplete(int result) { + DLOG(INFO) << "DoURLFetchComplete result=" << result; url_fetcher_.reset(); if (result < 0) @@ -199,7 +246,7 @@ int WebSocketExperimentTask::DoWebSocketConnect() { DCHECK(!websocket_); next_state_ = STATE_WEBSOCKET_CONNECT_COMPLETE; - websocket_ = context_->CreateWebSocket(); + websocket_ = context_->CreateWebSocket(config_, this); websocket_connect_start_time_ = base::TimeTicks::Now(); websocket_->Connect(); @@ -328,10 +375,12 @@ int WebSocketExperimentTask::DoWebSocketCloseComplete(int result) { } void WebSocketExperimentTask::SetTimeout(int64 deadline_ms) { - message_loop_->PostDelayedTask( + bool r = ChromeThread::PostDelayedTask( + ChromeThread::IO, FROM_HERE, method_factory_.NewRunnableMethod(&WebSocketExperimentTask::OnTimedOut), deadline_ms); + DCHECK(r) << "No IO thread running?"; } void WebSocketExperimentTask::RevokeTimeoutTimer() { @@ -339,7 +388,15 @@ void WebSocketExperimentTask::RevokeTimeoutTimer() { } void WebSocketExperimentTask::Finish(int result) { + DLOG(INFO) << "Finish Task for " << config_.url + << " next_state=" << next_state_ + << " result=" << net::ErrorToString(result); + url_fetcher_.reset(); + scoped_refptr<net::WebSocket> websocket = websocket_; + websocket_ = NULL; callback_->Run(result); + if (websocket) + websocket->DetachDelegate(); } } // namespace chrome_browser_net diff --git a/chrome/browser/net/websocket_experiment/websocket_experiment_task.h b/chrome/browser/net/websocket_experiment/websocket_experiment_task.h index 7bf3fdd..eeab4a7 100644 --- a/chrome/browser/net/websocket_experiment/websocket_experiment_task.h +++ b/chrome/browser/net/websocket_experiment/websocket_experiment_task.h @@ -46,8 +46,6 @@ #include "net/base/net_errors.h" #include "net/websockets/websocket.h" -class MessageLoop; - namespace net { class WebSocket; } // namespace net @@ -72,6 +70,7 @@ class WebSocketExperimentTask : public URLFetcher::Delegate, STATE_WEBSOCKET_RECV_BYE, STATE_WEBSOCKET_CLOSE, STATE_WEBSOCKET_CLOSE_COMPLETE, + NUM_STATES, }; class Config { public: @@ -102,16 +101,13 @@ class WebSocketExperimentTask : public URLFetcher::Delegate, }; class Context { public: - Context(const Config& config, WebSocketExperimentTask* task) - : config_(config), task_(task) {} + Context() {} virtual ~Context() {} - virtual URLFetcher* CreateURLFetcher(); - virtual net::WebSocket* CreateWebSocket(); - - protected: - const Config& config_; - WebSocketExperimentTask* task_; + virtual URLFetcher* CreateURLFetcher( + const Config& config, URLFetcher::Delegate* delegate); + virtual net::WebSocket* CreateWebSocket( + const Config& config, net::WebSocketDelegate* delegate); private: DISALLOW_COPY_AND_ASSIGN(Context); @@ -119,7 +115,7 @@ class WebSocketExperimentTask : public URLFetcher::Delegate, class Result { public: Result() - : last_result(net::ERR_UNEXPECTED), + : last_result(net::OK), last_state(STATE_NONE) {} int last_result; State last_state; @@ -128,6 +124,7 @@ class WebSocketExperimentTask : public URLFetcher::Delegate, base::TimeDelta websocket_connect; base::TimeDelta websocket_echo; base::TimeDelta websocket_idle; + base::TimeDelta websocket_total; }; // WebSocketExperimentTask will call |callback| with the last status code @@ -137,10 +134,10 @@ class WebSocketExperimentTask : public URLFetcher::Delegate, virtual ~WebSocketExperimentTask(); void Run(); + void Cancel(); - const Result& GetResult() const { - return result_; - } + const Config& config() const { return config_; } + const Result& result() const { return result_; } // URLFetcher::Delegate method. virtual void OnURLFetchComplete(const URLFetcher* source, @@ -154,6 +151,7 @@ class WebSocketExperimentTask : public URLFetcher::Delegate, virtual void OnOpen(net::WebSocket* websocket); virtual void OnMessage(net::WebSocket* websocket, const std::string& msg); virtual void OnClose(net::WebSocket* websocket); + virtual void OnError(const net::WebSocket* websocket, int error); void SetContext(Context* context); @@ -183,7 +181,6 @@ class WebSocketExperimentTask : public URLFetcher::Delegate, scoped_ptr<Context> context_; Result result_; - MessageLoop* message_loop_; ScopedRunnableMethodFactory<WebSocketExperimentTask> method_factory_; net::CompletionCallback* callback_; State next_state_; @@ -192,6 +189,7 @@ class WebSocketExperimentTask : public URLFetcher::Delegate, base::TimeTicks url_fetch_start_time_; scoped_refptr<net::WebSocket> websocket_; + int last_websocket_error_; std::deque<std::string> received_messages_; std::string push_message_; base::TimeTicks websocket_connect_start_time_; diff --git a/chrome/chrome.gyp b/chrome/chrome.gyp index bc4711d..9e1b50f 100755 --- a/chrome/chrome.gyp +++ b/chrome/chrome.gyp @@ -1854,6 +1854,8 @@ 'browser/net/url_request_slow_http_job.h', 'browser/net/url_request_tracking.cc', 'browser/net/url_request_tracking.h', + 'browser/net/websocket_experiment/websocket_experiment_runner.cc', + 'browser/net/websocket_experiment/websocket_experiment_runner.h', 'browser/net/websocket_experiment/websocket_experiment_task.cc', 'browser/net/websocket_experiment/websocket_experiment_task.h', 'browser/notifications/balloon.cc', |