summaryrefslogtreecommitdiffstats
path: root/chrome/browser/net/websocket_experiment/websocket_experiment_task.h
blob: fc62fd75be5892179140f797ea38ea43a282236d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
// 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.
//
// 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_

#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();

    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 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_