| Index: chrome/browser/net/websocket_experiment/websocket_experiment_task.cc
|
| diff --git a/chrome/browser/net/websocket_experiment/websocket_experiment_task.cc b/chrome/browser/net/websocket_experiment/websocket_experiment_task.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..94e0f502a3f60f7747d9ba280cf75c44beebe862
|
| --- /dev/null
|
| +++ b/chrome/browser/net/websocket_experiment/websocket_experiment_task.cc
|
| @@ -0,0 +1,345 @@
|
| +// 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_task.h"
|
| +
|
| +#include "base/message_loop.h"
|
| +#include "chrome/browser/net/url_request_context_getter.h"
|
| +#include "chrome/browser/profile.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_);
|
| +}
|
| +
|
| +net::WebSocket* WebSocketExperimentTask::Context::CreateWebSocket() {
|
| + 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,
|
| + getter->GetURLRequestContext()));
|
| + return new net::WebSocket(request, task_);
|
| +}
|
| +
|
| +WebSocketExperimentTask::WebSocketExperimentTask(
|
| + const Config& config,
|
| + net::CompletionCallback* callback)
|
| + : config_(config),
|
| + context_(ALLOW_THIS_IN_INITIALIZER_LIST(new Context(config, this))),
|
| + message_loop_(MessageLoopForIO::current()),
|
| + method_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)),
|
| + callback_(callback),
|
| + next_state_(STATE_NONE) {
|
| + DCHECK(message_loop_);
|
| +}
|
| +
|
| +WebSocketExperimentTask::~WebSocketExperimentTask() {
|
| + DCHECK(!websocket_);
|
| +}
|
| +
|
| +void WebSocketExperimentTask::Run() {
|
| + next_state_ = STATE_URL_FETCH;
|
| + DoLoop(net::OK);
|
| +}
|
| +
|
| +// URLFetcher::Delegate method.
|
| +void WebSocketExperimentTask::OnURLFetchComplete(
|
| + const URLFetcher* source,
|
| + const GURL& url,
|
| + const URLRequestStatus& status,
|
| + int response_code,
|
| + const ResponseCookies& cookies,
|
| + const std::string& data) {
|
| + result_.url_fetch = base::TimeTicks::Now() - url_fetch_start_time_;
|
| + RevokeTimeoutTimer();
|
| + int result = net::ERR_FAILED;
|
| + if (next_state_ != STATE_URL_FETCH_COMPLETE)
|
| + result = net::ERR_UNEXPECTED;
|
| + else if (response_code == 200)
|
| + result = net::OK;
|
| + DoLoop(result);
|
| +}
|
| +
|
| +// net::WebSocketDelegate
|
| +void WebSocketExperimentTask::OnOpen(net::WebSocket* websocket) {
|
| + result_.websocket_connect =
|
| + base::TimeTicks::Now() - websocket_connect_start_time_;
|
| + RevokeTimeoutTimer();
|
| + if (next_state_ == STATE_WEBSOCKET_CONNECT_COMPLETE)
|
| + DoLoop(net::OK);
|
| + else
|
| + DoLoop(net::ERR_UNEXPECTED);
|
| +}
|
| +
|
| +void WebSocketExperimentTask::OnMessage(
|
| + net::WebSocket* websocket, const std::string& msg) {
|
| + if (!result_.websocket_echo.ToInternalValue())
|
| + result_.websocket_echo =
|
| + base::TimeTicks::Now() - websocket_echo_start_time_;
|
| + if (!websocket_idle_start_time_.is_null() &&
|
| + !result_.websocket_idle.ToInternalValue())
|
| + result_.websocket_idle =
|
| + base::TimeTicks::Now() - websocket_idle_start_time_;
|
| + RevokeTimeoutTimer();
|
| + received_messages_.push_back(msg);
|
| + int result = net::ERR_UNEXPECTED;
|
| + switch (next_state_) {
|
| + case STATE_WEBSOCKET_RECV_HELLO:
|
| + case STATE_WEBSOCKET_RECV_PUSH_MESSAGE:
|
| + case STATE_WEBSOCKET_RECV_BYE:
|
| + result = net::OK;
|
| + break;
|
| + default:
|
| + break;
|
| + }
|
| + DoLoop(result);
|
| +}
|
| +
|
| +void WebSocketExperimentTask::OnClose(net::WebSocket* websocket) {
|
| + RevokeTimeoutTimer();
|
| + int result = net::ERR_CONNECTION_CLOSED;
|
| + if (next_state_ == STATE_WEBSOCKET_CLOSE_COMPLETE)
|
| + result = net::OK;
|
| + DoLoop(result);
|
| +}
|
| +
|
| +void WebSocketExperimentTask::SetContext(Context* context) {
|
| + context_.reset(context);
|
| +}
|
| +
|
| +void WebSocketExperimentTask::OnTimedOut() {
|
| + RevokeTimeoutTimer();
|
| + DoLoop(net::ERR_TIMED_OUT);
|
| +}
|
| +
|
| +void WebSocketExperimentTask::DoLoop(int result) {
|
| + do {
|
| + State state = next_state_;
|
| + next_state_ = STATE_NONE;
|
| + switch (state) {
|
| + case STATE_URL_FETCH:
|
| + result = DoURLFetch();
|
| + break;
|
| + case STATE_URL_FETCH_COMPLETE:
|
| + result = DoURLFetchComplete(result);
|
| + break;
|
| + case STATE_WEBSOCKET_CONNECT:
|
| + result = DoWebSocketConnect();
|
| + break;
|
| + case STATE_WEBSOCKET_CONNECT_COMPLETE:
|
| + result = DoWebSocketConnectComplete(result);
|
| + break;
|
| + case STATE_WEBSOCKET_SEND_HELLO:
|
| + result = DoWebSocketSendHello();
|
| + break;
|
| + case STATE_WEBSOCKET_RECV_HELLO:
|
| + result = DoWebSocketReceiveHello(result);
|
| + break;
|
| + case STATE_WEBSOCKET_KEEP_IDLE:
|
| + result = DoWebSocketKeepIdle();
|
| + break;
|
| + case STATE_WEBSOCKET_KEEP_IDLE_COMPLETE:
|
| + result = DoWebSocketKeepIdleComplete(result);
|
| + break;
|
| + case STATE_WEBSOCKET_RECV_PUSH_MESSAGE:
|
| + result = DoWebSocketReceivePushMessage(result);
|
| + break;
|
| + case STATE_WEBSOCKET_ECHO_BACK_MESSAGE:
|
| + result = DoWebSocketEchoBackMessage();
|
| + break;
|
| + case STATE_WEBSOCKET_RECV_BYE:
|
| + result = DoWebSocketReceiveBye(result);
|
| + break;
|
| + case STATE_WEBSOCKET_CLOSE:
|
| + result = DoWebSocketClose();
|
| + break;
|
| + case STATE_WEBSOCKET_CLOSE_COMPLETE:
|
| + result = DoWebSocketCloseComplete(result);
|
| + break;
|
| + default:
|
| + NOTREACHED();
|
| + break;
|
| + }
|
| + } while (result != net::ERR_IO_PENDING && next_state_ != STATE_NONE);
|
| +
|
| + if (result != net::ERR_IO_PENDING)
|
| + Finish(result);
|
| +}
|
| +
|
| +int WebSocketExperimentTask::DoURLFetch() {
|
| + next_state_ = STATE_URL_FETCH_COMPLETE;
|
| + DCHECK(!url_fetcher_.get());
|
| +
|
| + url_fetcher_.reset(context_->CreateURLFetcher());
|
| + 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) {
|
| + url_fetcher_.reset();
|
| +
|
| + if (result < 0)
|
| + return result;
|
| +
|
| + next_state_ = STATE_WEBSOCKET_CONNECT;
|
| + return net::OK;
|
| +}
|
| +
|
| +int WebSocketExperimentTask::DoWebSocketConnect() {
|
| + DCHECK(!websocket_);
|
| +
|
| + next_state_ = STATE_WEBSOCKET_CONNECT_COMPLETE;
|
| + websocket_ = context_->CreateWebSocket();
|
| + websocket_connect_start_time_ = base::TimeTicks::Now();
|
| + websocket_->Connect();
|
| +
|
| + SetTimeout(config_.websocket_onopen_deadline_ms);
|
| + return net::ERR_IO_PENDING;
|
| +}
|
| +
|
| +int WebSocketExperimentTask::DoWebSocketConnectComplete(int result) {
|
| + if (result < 0)
|
| + return result;
|
| + DCHECK(websocket_);
|
| +
|
| + next_state_ = STATE_WEBSOCKET_SEND_HELLO;
|
| + return net::OK;
|
| +}
|
| +
|
| +int WebSocketExperimentTask::DoWebSocketSendHello() {
|
| + DCHECK(websocket_);
|
| +
|
| + next_state_ = STATE_WEBSOCKET_RECV_HELLO;
|
| +
|
| + websocket_echo_start_time_ = base::TimeTicks::Now();
|
| + websocket_->Send(config_.websocket_hello_message);
|
| + SetTimeout(config_.websocket_hello_echoback_deadline_ms);
|
| + return net::ERR_IO_PENDING;
|
| +}
|
| +
|
| +int WebSocketExperimentTask::DoWebSocketReceiveHello(int result) {
|
| + if (result < 0)
|
| + return result;
|
| +
|
| + DCHECK(websocket_);
|
| +
|
| + if (received_messages_.size() != 1)
|
| + return net::ERR_INVALID_RESPONSE;
|
| +
|
| + std::string msg = received_messages_.front();
|
| + received_messages_.pop_front();
|
| + if (msg != config_.websocket_hello_message)
|
| + return net::ERR_INVALID_RESPONSE;
|
| +
|
| + next_state_ = STATE_WEBSOCKET_KEEP_IDLE;
|
| + return net::OK;
|
| +}
|
| +
|
| +int WebSocketExperimentTask::DoWebSocketKeepIdle() {
|
| + DCHECK(websocket_);
|
| +
|
| + next_state_ = STATE_WEBSOCKET_KEEP_IDLE_COMPLETE;
|
| + websocket_idle_start_time_ = base::TimeTicks::Now();
|
| + SetTimeout(config_.websocket_idle_ms);
|
| + return net::ERR_IO_PENDING;
|
| +}
|
| +
|
| +int WebSocketExperimentTask::DoWebSocketKeepIdleComplete(int result) {
|
| + if (result != net::ERR_TIMED_OUT) {
|
| + // Server sends back too early, or unexpected close?
|
| + if (result == net::OK)
|
| + result = net::ERR_UNEXPECTED;
|
| + return result;
|
| + }
|
| +
|
| + DCHECK(websocket_);
|
| +
|
| + next_state_ = STATE_WEBSOCKET_RECV_PUSH_MESSAGE;
|
| + SetTimeout(config_.websocket_receive_push_message_deadline_ms);
|
| + return net::ERR_IO_PENDING;
|
| +}
|
| +
|
| +int WebSocketExperimentTask::DoWebSocketReceivePushMessage(int result) {
|
| + if (result < 0)
|
| + return result;
|
| +
|
| + DCHECK(websocket_);
|
| + if (received_messages_.size() != 1)
|
| + return net::ERR_INVALID_RESPONSE;
|
| +
|
| + push_message_ = received_messages_.front();
|
| + received_messages_.pop_front();
|
| +
|
| + next_state_ = STATE_WEBSOCKET_ECHO_BACK_MESSAGE;
|
| + return net::OK;
|
| +}
|
| +
|
| +int WebSocketExperimentTask::DoWebSocketEchoBackMessage() {
|
| + DCHECK(websocket_);
|
| + DCHECK(!push_message_.empty());
|
| +
|
| + next_state_ = STATE_WEBSOCKET_RECV_BYE;
|
| + websocket_->Send(push_message_);
|
| + SetTimeout(config_.websocket_bye_deadline_ms);
|
| + return net::ERR_IO_PENDING;
|
| +}
|
| +
|
| +int WebSocketExperimentTask::DoWebSocketReceiveBye(int result) {
|
| + if (result < 0)
|
| + return result;
|
| +
|
| + DCHECK(websocket_);
|
| +
|
| + if (received_messages_.size() != 1)
|
| + return net::ERR_INVALID_RESPONSE;
|
| +
|
| + std::string bye = received_messages_.front();
|
| + received_messages_.pop_front();
|
| +
|
| + if (bye != config_.websocket_bye_message)
|
| + return net::ERR_INVALID_RESPONSE;
|
| +
|
| + next_state_ = STATE_WEBSOCKET_CLOSE;
|
| + return net::OK;
|
| +}
|
| +
|
| +int WebSocketExperimentTask::DoWebSocketClose() {
|
| + DCHECK(websocket_);
|
| +
|
| + next_state_ = STATE_WEBSOCKET_CLOSE_COMPLETE;
|
| + websocket_->Close();
|
| + SetTimeout(config_.websocket_close_deadline_ms);
|
| + return net::ERR_IO_PENDING;
|
| +}
|
| +
|
| +int WebSocketExperimentTask::DoWebSocketCloseComplete(int result) {
|
| + websocket_ = NULL;
|
| + return result;
|
| +}
|
| +
|
| +void WebSocketExperimentTask::SetTimeout(int64 deadline_ms) {
|
| + message_loop_->PostDelayedTask(
|
| + FROM_HERE,
|
| + method_factory_.NewRunnableMethod(&WebSocketExperimentTask::OnTimedOut),
|
| + deadline_ms);
|
| +}
|
| +
|
| +void WebSocketExperimentTask::RevokeTimeoutTimer() {
|
| + method_factory_.RevokeAll();
|
| +}
|
| +
|
| +void WebSocketExperimentTask::Finish(int result) {
|
| + callback_->Run(result);
|
| +}
|
| +
|
| +} // namespace chrome_browser_net
|
|
|