// Copyright (c) 2011 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. // // WebSocket live experiment task. // It will try the following scenario. // // - Fetch |http_url| within |url_fetch_deadline_ms| msec. // If failed, the task is aborted (no http reachability) // // - Connect to |url| with WebSocket protocol within // |websocket_onopen_deadline_ms| msec. // Checks WebSocket connection can be established. // // - Send |websocket_hello_message| on the WebSocket connection and // wait it from server within |websocket_hello_echoback_deadline_ms| msec. // Checks message can be sent/received on the WebSocket connection. // // - Keep connection idle at least |websocket_idle_ms| msec. // Checks WebSocket connection keep open in idle state. // // - Wait for some message from server within // |websocket_receive_push_message_deadline_ms| msec, and echo it back. // Checks server can push a message after connection has been idle. // // - Expect that |websocket_bye_message| message arrives within // |websocket_bye_deadline_ms| msec from server. // Checks previous message was sent to the server. // // - Close the connection and wait |websocket_close_deadline_ms| msec // for onclose. // Checks WebSocket connection can be closed normally. #ifndef CHROME_BROWSER_NET_WEBSOCKET_EXPERIMENT_WEBSOCKET_EXPERIMENT_TASK_H_ #define CHROME_BROWSER_NET_WEBSOCKET_EXPERIMENT_WEBSOCKET_EXPERIMENT_TASK_H_ #pragma once #include <deque> #include <string> #include "base/basictypes.h" #include "base/task.h" #include "base/time.h" #include "chrome/common/net/url_fetcher.h" #include "googleurl/src/gurl.h" #include "net/base/completion_callback.h" #include "net/base/net_errors.h" #include "net/websockets/websocket.h" namespace net { class WebSocket; } // namespace net namespace chrome_browser_net_websocket_experiment { class WebSocketExperimentTask : public URLFetcher::Delegate, public net::WebSocketDelegate { public: enum State { STATE_NONE, STATE_URL_FETCH, STATE_URL_FETCH_COMPLETE, STATE_WEBSOCKET_CONNECT, STATE_WEBSOCKET_CONNECT_COMPLETE, STATE_WEBSOCKET_SEND_HELLO, STATE_WEBSOCKET_RECV_HELLO, STATE_WEBSOCKET_KEEP_IDLE, STATE_WEBSOCKET_KEEP_IDLE_COMPLETE, STATE_WEBSOCKET_RECV_PUSH_MESSAGE, STATE_WEBSOCKET_ECHO_BACK_MESSAGE, STATE_WEBSOCKET_RECV_BYE, STATE_WEBSOCKET_CLOSE, STATE_WEBSOCKET_CLOSE_COMPLETE, NUM_STATES, }; class Config { public: Config(); ~Config(); GURL url; std::string ws_protocol; std::string ws_origin; std::string ws_location; net::WebSocket::ProtocolVersion protocol_version; GURL http_url; int64 url_fetch_deadline_ms; int64 websocket_onopen_deadline_ms; std::string websocket_hello_message; int64 websocket_hello_echoback_deadline_ms; int64 websocket_idle_ms; int64 websocket_receive_push_message_deadline_ms; std::string websocket_bye_message; int64 websocket_bye_deadline_ms; int64 websocket_close_deadline_ms; }; class Context { public: Context() {} virtual ~Context() {} 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); }; class Result { public: Result() : last_result(net::OK), last_state(STATE_NONE) {} int last_result; State last_state; base::TimeDelta url_fetch; 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 // when the task is finished. WebSocketExperimentTask(const Config& config, net::CompletionCallback* callback); virtual ~WebSocketExperimentTask(); // Initializes histograms that WebSocketExperimentTask will use to save // results. Must be called once before calling SaveResult(). static void InitHistogram(); // Releases histograms to store results. // Must be called after all WebSocketExperimentTasks are finished. static void ReleaseHistogram(); void Run(); void Cancel(); void SaveResult() const; const Config& config() const { return config_; } const Result& result() const { return result_; } // URLFetcher::Delegate method. virtual void OnURLFetchComplete(const URLFetcher* source, const GURL& url, const net::URLRequestStatus& status, int response_code, const ResponseCookies& cookies, const std::string& data); // net::WebSocketDelegate methods virtual void OnOpen(net::WebSocket* websocket); virtual void OnMessage(net::WebSocket* websocket, const std::string& msg); virtual void OnError(net::WebSocket* websocket); virtual void OnClose(net::WebSocket* websocket, bool was_clean); virtual void OnSocketError(const net::WebSocket* websocket, int error); void SetContext(Context* context); private: void OnTimedOut(); void DoLoop(int result); int DoURLFetch(); int DoURLFetchComplete(int result); int DoWebSocketConnect(); int DoWebSocketConnectComplete(int result); int DoWebSocketSendHello(); int DoWebSocketReceiveHello(int result); int DoWebSocketKeepIdle(); int DoWebSocketKeepIdleComplete(int result); int DoWebSocketReceivePushMessage(int result); int DoWebSocketEchoBackMessage(); int DoWebSocketReceiveBye(int result); int DoWebSocketClose(); int DoWebSocketCloseComplete(int result); void SetTimeout(int64 deadline_ms); void RevokeTimeoutTimer(); void Finish(int result); Config config_; scoped_ptr<Context> context_; Result result_; ScopedRunnableMethodFactory<WebSocketExperimentTask> method_factory_; net::CompletionCallback* callback_; State next_state_; scoped_ptr<URLFetcher> url_fetcher_; 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_; base::TimeTicks websocket_echo_start_time_; base::TimeTicks websocket_idle_start_time_; DISALLOW_COPY_AND_ASSIGN(WebSocketExperimentTask); }; } // namespace chrome_browser_net #endif // CHROME_BROWSER_NET_WEBSOCKET_EXPERIMENT_WEBSOCKET_EXPERIMENT_TASK_H_