websocket_experiment_task.h revision c407dc5cd9bdc5668497f21b26b09d988ab439de
1c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Copyright (c) 2009 The Chromium Authors. All rights reserved.
2c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Use of this source code is governed by a BSD-style license that can be
3c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// found in the LICENSE file.
4c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch//
5c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// WebSocket live experiment task.
6c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// It will try the following scenario.
7c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch//
8c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch//  - Fetch |http_url| within |url_fetch_deadline_ms| msec.
9c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch//    If failed, the task is aborted (no http reachability)
10c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch//
11c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch//  - Connect to |url| with WebSocket protocol within
12c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch//    |websocket_onopen_deadline_ms| msec.
13c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch//    Checks WebSocket connection can be established.
14c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch//
15c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch//  - Send |websocket_hello_message| on the WebSocket connection and
16c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch//    wait it from server within |websocket_hello_echoback_deadline_ms| msec.
17c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch//    Checks message can be sent/received on the WebSocket connection.
18c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch//
19c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch//  - Keep connection idle at least |websocket_idle_ms| msec.
20c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch//    Checks WebSocket connection keep open in idle state.
21c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch//
22c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch//  - Wait for some message from server within
23c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch//    |websocket_receive_push_message_deadline_ms| msec, and echo it back.
24c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch//    Checks server can push a message after connection has been idle.
25c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch//
26c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch//  - Expect that |websocket_bye_message| message arrives within
27c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch//    |websocket_bye_deadline_ms| msec from server.
28c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch//    Checks previous message was sent to the server.
29c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch//
30c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch//  - Close the connection and wait |websocket_close_deadline_ms| msec
31c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch//    for onclose.
32c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch//    Checks WebSocket connection can be closed normally.
33c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
34c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#ifndef CHROME_BROWSER_NET_WEBSOCKET_EXPERIMENT_WEBSOCKET_EXPERIMENT_TASK_H_
35c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#define CHROME_BROWSER_NET_WEBSOCKET_EXPERIMENT_WEBSOCKET_EXPERIMENT_TASK_H_
36c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
37c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include <deque>
38c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include <string>
39c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
40c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/basictypes.h"
41c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/task.h"
42c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/time.h"
43c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/common/net/url_fetcher.h"
44c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "googleurl/src/gurl.h"
45c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "net/base/completion_callback.h"
46c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "net/base/net_errors.h"
47c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "net/websockets/websocket.h"
48c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
49c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochnamespace net {
50c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochclass WebSocket;
51c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}  // namespace net
52c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
53c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochnamespace chrome_browser_net_websocket_experiment {
54c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
55c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochclass WebSocketExperimentTask : public URLFetcher::Delegate,
56c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                public net::WebSocketDelegate {
57c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch public:
58c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  enum State {
59c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    STATE_NONE,
60c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    STATE_URL_FETCH,
61c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    STATE_URL_FETCH_COMPLETE,
62c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    STATE_WEBSOCKET_CONNECT,
63c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    STATE_WEBSOCKET_CONNECT_COMPLETE,
64c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    STATE_WEBSOCKET_SEND_HELLO,
65c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    STATE_WEBSOCKET_RECV_HELLO,
66c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    STATE_WEBSOCKET_KEEP_IDLE,
67c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    STATE_WEBSOCKET_KEEP_IDLE_COMPLETE,
68c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    STATE_WEBSOCKET_RECV_PUSH_MESSAGE,
69c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    STATE_WEBSOCKET_ECHO_BACK_MESSAGE,
70c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    STATE_WEBSOCKET_RECV_BYE,
71c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    STATE_WEBSOCKET_CLOSE,
72c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    STATE_WEBSOCKET_CLOSE_COMPLETE,
73c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    NUM_STATES,
74c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  };
75c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  class Config {
76c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch   public:
77c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    Config();
78c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
79c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    GURL url;
80c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    std::string ws_protocol;
81c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    std::string ws_origin;
82c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    std::string ws_location;
83c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    net::WebSocket::ProtocolVersion protocol_version;
84c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
85c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    GURL http_url;
86c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
87c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    int64 url_fetch_deadline_ms;
88c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    int64 websocket_onopen_deadline_ms;
89c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    std::string websocket_hello_message;
90c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    int64 websocket_hello_echoback_deadline_ms;
91c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    int64 websocket_idle_ms;
92c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    int64 websocket_receive_push_message_deadline_ms;
93c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    std::string websocket_bye_message;
94c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    int64 websocket_bye_deadline_ms;
95c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    int64 websocket_close_deadline_ms;
96c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  };
97c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  class Context {
98c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch   public:
99c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    Context() {}
100c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    virtual ~Context() {}
101c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
102c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    virtual URLFetcher* CreateURLFetcher(
103c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        const Config& config, URLFetcher::Delegate* delegate);
104c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    virtual net::WebSocket* CreateWebSocket(
105c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        const Config& config, net::WebSocketDelegate* delegate);
106c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
107c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch   private:
108c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    DISALLOW_COPY_AND_ASSIGN(Context);
109c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  };
110c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  class Result {
111c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch   public:
112c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    Result()
113c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        : last_result(net::OK),
114c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          last_state(STATE_NONE) {}
115c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    int last_result;
116c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    State last_state;
117c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
118c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    base::TimeDelta url_fetch;
119c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    base::TimeDelta websocket_connect;
120c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    base::TimeDelta websocket_echo;
121c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    base::TimeDelta websocket_idle;
122c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    base::TimeDelta websocket_total;
123c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  };
124c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
125c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // WebSocketExperimentTask will call |callback| with the last status code
126c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // when the task is finished.
127c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  WebSocketExperimentTask(const Config& config,
128c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                          net::CompletionCallback* callback);
129c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  virtual ~WebSocketExperimentTask();
130c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
131c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Initializes histograms that WebSocketExperimentTask will use to save
132c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // results.  Must be called once before calling SaveResult().
133c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  static void InitHistogram();
134c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
135c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Releases histograms to store results.
136c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Must be called after all WebSocketExperimentTasks are finished.
137c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  static void ReleaseHistogram();
138c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
139c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  void Run();
140c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  void Cancel();
141c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  void SaveResult() const;
142c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
143c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  const Config& config() const { return config_; }
144c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  const Result& result() const { return result_; }
145c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
146c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // URLFetcher::Delegate method.
147c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  virtual void OnURLFetchComplete(const URLFetcher* source,
148c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                  const GURL& url,
149c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                  const URLRequestStatus& status,
150c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                  int response_code,
151c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                  const ResponseCookies& cookies,
152c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                  const std::string& data);
153c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
154c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // net::WebSocketDelegate methods
155c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  virtual void OnOpen(net::WebSocket* websocket);
156c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  virtual void OnMessage(net::WebSocket* websocket, const std::string& msg);
157c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  virtual void OnError(net::WebSocket* websocket);
158c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  virtual void OnClose(net::WebSocket* websocket, bool was_clean);
159c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  virtual void OnSocketError(const net::WebSocket* websocket, int error);
160c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
161c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  void SetContext(Context* context);
162c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
163c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch private:
164c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  void OnTimedOut();
165c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
166c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  void DoLoop(int result);
167c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
168c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int DoURLFetch();
169c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int DoURLFetchComplete(int result);
170c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int DoWebSocketConnect();
171c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int DoWebSocketConnectComplete(int result);
172c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int DoWebSocketSendHello();
173c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int DoWebSocketReceiveHello(int result);
174c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int DoWebSocketKeepIdle();
175c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int DoWebSocketKeepIdleComplete(int result);
176c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int DoWebSocketReceivePushMessage(int result);
177c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int DoWebSocketEchoBackMessage();
178c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int DoWebSocketReceiveBye(int result);
179c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int DoWebSocketClose();
180c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int DoWebSocketCloseComplete(int result);
181c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  void SetTimeout(int64 deadline_ms);
182c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  void RevokeTimeoutTimer();
183c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  void Finish(int result);
184c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
185c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  Config config_;
186c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  scoped_ptr<Context> context_;
187c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  Result result_;
188c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
189c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  ScopedRunnableMethodFactory<WebSocketExperimentTask> method_factory_;
190c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  net::CompletionCallback* callback_;
191c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  State next_state_;
192c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
193c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  scoped_ptr<URLFetcher> url_fetcher_;
194c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  base::TimeTicks url_fetch_start_time_;
195c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
196c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  scoped_refptr<net::WebSocket> websocket_;
197c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int last_websocket_error_;
198c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  std::deque<std::string> received_messages_;
199c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  std::string push_message_;
200c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  base::TimeTicks websocket_connect_start_time_;
201c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  base::TimeTicks websocket_echo_start_time_;
202c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  base::TimeTicks websocket_idle_start_time_;
203c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
204c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DISALLOW_COPY_AND_ASSIGN(WebSocketExperimentTask);
205c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch};
206c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
207c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}  // namespace chrome_browser_net
208c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
209c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#endif  // CHROME_BROWSER_NET_WEBSOCKET_EXPERIMENT_WEBSOCKET_EXPERIMENT_TASK_H_
210