Roll src/third_party/WebKit 66fcf2e:f05b633 (svn 189594:189607)
[chromium-blink-merge.git] / net / websockets / websocket_end_to_end_test.cc
blob1a3df040e9f429320a9c099f86ccc0edd046d0c7
1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 // End-to-end tests for WebSocket.
6 //
7 // A python server is (re)started for each test, which is moderately
8 // inefficient. However, it makes these tests a good fit for scenarios which
9 // require special server configurations.
11 #include <string>
13 #include "base/bind.h"
14 #include "base/bind_helpers.h"
15 #include "base/callback.h"
16 #include "base/memory/scoped_ptr.h"
17 #include "base/message_loop/message_loop.h"
18 #include "base/run_loop.h"
19 #include "net/base/auth.h"
20 #include "net/base/network_delegate.h"
21 #include "net/base/test_data_directory.h"
22 #include "net/proxy/proxy_service.h"
23 #include "net/test/spawned_test_server/spawned_test_server.h"
24 #include "net/url_request/url_request_test_util.h"
25 #include "net/websockets/websocket_channel.h"
26 #include "net/websockets/websocket_event_interface.h"
27 #include "testing/gtest/include/gtest/gtest.h"
28 #include "url/origin.h"
30 namespace net {
32 namespace {
34 static const char kEchoServer[] = "echo-with-no-extension";
36 // An implementation of WebSocketEventInterface that waits for and records the
37 // results of the connect.
38 class ConnectTestingEventInterface : public WebSocketEventInterface {
39 public:
40 ConnectTestingEventInterface();
42 void WaitForResponse();
44 bool failed() const { return failed_; }
46 // Only set if the handshake failed, otherwise empty.
47 std::string failure_message() const;
49 std::string selected_subprotocol() const;
51 std::string extensions() const;
53 // Implementation of WebSocketEventInterface.
54 ChannelState OnAddChannelResponse(bool fail,
55 const std::string& selected_subprotocol,
56 const std::string& extensions) override;
58 ChannelState OnDataFrame(bool fin,
59 WebSocketMessageType type,
60 const std::vector<char>& data) override;
62 ChannelState OnFlowControl(int64 quota) override;
64 ChannelState OnClosingHandshake() override;
66 ChannelState OnDropChannel(bool was_clean,
67 uint16 code,
68 const std::string& reason) override;
70 ChannelState OnFailChannel(const std::string& message) override;
72 ChannelState OnStartOpeningHandshake(
73 scoped_ptr<WebSocketHandshakeRequestInfo> request) override;
75 ChannelState OnFinishOpeningHandshake(
76 scoped_ptr<WebSocketHandshakeResponseInfo> response) override;
78 ChannelState OnSSLCertificateError(
79 scoped_ptr<SSLErrorCallbacks> ssl_error_callbacks,
80 const GURL& url,
81 const SSLInfo& ssl_info,
82 bool fatal) override;
84 private:
85 void QuitNestedEventLoop();
87 // failed_ is true if the handshake failed (ie. OnFailChannel was called).
88 bool failed_;
89 std::string selected_subprotocol_;
90 std::string extensions_;
91 std::string failure_message_;
92 base::RunLoop run_loop_;
94 DISALLOW_COPY_AND_ASSIGN(ConnectTestingEventInterface);
97 ConnectTestingEventInterface::ConnectTestingEventInterface() : failed_(true) {
100 void ConnectTestingEventInterface::WaitForResponse() {
101 run_loop_.Run();
104 std::string ConnectTestingEventInterface::failure_message() const {
105 return failure_message_;
108 std::string ConnectTestingEventInterface::selected_subprotocol() const {
109 return selected_subprotocol_;
112 std::string ConnectTestingEventInterface::extensions() const {
113 return extensions_;
116 // Make the function definitions below less verbose.
117 typedef ConnectTestingEventInterface::ChannelState ChannelState;
119 ChannelState ConnectTestingEventInterface::OnAddChannelResponse(
120 bool fail,
121 const std::string& selected_subprotocol,
122 const std::string& extensions) {
123 failed_ = fail;
124 selected_subprotocol_ = selected_subprotocol;
125 extensions_ = extensions;
126 QuitNestedEventLoop();
127 return fail ? CHANNEL_DELETED : CHANNEL_ALIVE;
130 ChannelState ConnectTestingEventInterface::OnDataFrame(
131 bool fin,
132 WebSocketMessageType type,
133 const std::vector<char>& data) {
134 return CHANNEL_ALIVE;
137 ChannelState ConnectTestingEventInterface::OnFlowControl(int64 quota) {
138 return CHANNEL_ALIVE;
141 ChannelState ConnectTestingEventInterface::OnClosingHandshake() {
142 return CHANNEL_ALIVE;
145 ChannelState ConnectTestingEventInterface::OnDropChannel(
146 bool was_clean,
147 uint16 code,
148 const std::string& reason) {
149 return CHANNEL_DELETED;
152 ChannelState ConnectTestingEventInterface::OnFailChannel(
153 const std::string& message) {
154 failed_ = true;
155 failure_message_ = message;
156 QuitNestedEventLoop();
157 return CHANNEL_DELETED;
160 ChannelState ConnectTestingEventInterface::OnStartOpeningHandshake(
161 scoped_ptr<WebSocketHandshakeRequestInfo> request) {
162 return CHANNEL_ALIVE;
165 ChannelState ConnectTestingEventInterface::OnFinishOpeningHandshake(
166 scoped_ptr<WebSocketHandshakeResponseInfo> response) {
167 return CHANNEL_ALIVE;
170 ChannelState ConnectTestingEventInterface::OnSSLCertificateError(
171 scoped_ptr<SSLErrorCallbacks> ssl_error_callbacks,
172 const GURL& url,
173 const SSLInfo& ssl_info,
174 bool fatal) {
175 base::MessageLoop::current()->PostTask(
176 FROM_HERE, base::Bind(&SSLErrorCallbacks::CancelSSLRequest,
177 base::Owned(ssl_error_callbacks.release()),
178 ERR_SSL_PROTOCOL_ERROR, &ssl_info));
179 return CHANNEL_ALIVE;
182 void ConnectTestingEventInterface::QuitNestedEventLoop() {
183 run_loop_.Quit();
186 // A subclass of TestNetworkDelegate that additionally implements the
187 // OnResolveProxy callback and records the information passed to it.
188 class TestNetworkDelegateWithProxyInfo : public TestNetworkDelegate {
189 public:
190 TestNetworkDelegateWithProxyInfo() {}
192 struct ResolvedProxyInfo {
193 GURL url;
194 ProxyInfo proxy_info;
197 const ResolvedProxyInfo& resolved_proxy_info() const {
198 return resolved_proxy_info_;
201 protected:
202 void OnResolveProxy(const GURL& url,
203 int load_flags,
204 const ProxyService& proxy_service,
205 ProxyInfo* result) override {
206 resolved_proxy_info_.url = url;
207 resolved_proxy_info_.proxy_info = *result;
210 private:
211 ResolvedProxyInfo resolved_proxy_info_;
213 DISALLOW_COPY_AND_ASSIGN(TestNetworkDelegateWithProxyInfo);
216 class WebSocketEndToEndTest : public ::testing::Test {
217 protected:
218 WebSocketEndToEndTest()
219 : event_interface_(new ConnectTestingEventInterface),
220 network_delegate_(new TestNetworkDelegateWithProxyInfo),
221 context_(true),
222 channel_(make_scoped_ptr(event_interface_), &context_),
223 initialised_context_(false) {}
225 // Initialise the URLRequestContext. Normally done automatically by
226 // ConnectAndWait(). This method is for the use of tests that need the
227 // URLRequestContext initialised before calling ConnectAndWait().
228 void InitialiseContext() {
229 context_.set_network_delegate(network_delegate_.get());
230 context_.Init();
231 initialised_context_ = true;
234 // Send the connect request to |socket_url| and wait for a response. Returns
235 // true if the handshake succeeded.
236 bool ConnectAndWait(const GURL& socket_url) {
237 if (!initialised_context_) {
238 InitialiseContext();
240 std::vector<std::string> sub_protocols;
241 url::Origin origin("http://localhost");
242 channel_.SendAddChannelRequest(GURL(socket_url), sub_protocols, origin);
243 event_interface_->WaitForResponse();
244 return !event_interface_->failed();
247 ConnectTestingEventInterface* event_interface_; // owned by channel_
248 scoped_ptr<TestNetworkDelegateWithProxyInfo> network_delegate_;
249 TestURLRequestContext context_;
250 WebSocketChannel channel_;
251 bool initialised_context_;
254 // None of these tests work on Android.
255 // TODO(ricea): Make these tests work on Android. See crbug.com/441711.
256 #if defined(OS_ANDROID)
257 #define DISABLED_ON_ANDROID(test) DISABLED_##test
258 #else
259 #define DISABLED_ON_ANDROID(test) test
260 #endif
262 // Basic test of connectivity. If this test fails, nothing else can be expected
263 // to work.
264 TEST_F(WebSocketEndToEndTest, DISABLED_ON_ANDROID(BasicSmokeTest)) {
265 SpawnedTestServer ws_server(SpawnedTestServer::TYPE_WS,
266 SpawnedTestServer::kLocalhost,
267 GetWebSocketTestDataDirectory());
268 ASSERT_TRUE(ws_server.Start());
269 EXPECT_TRUE(ConnectAndWait(ws_server.GetURL(kEchoServer)));
272 // Test for issue crbug.com/433695 "Unencrypted WebSocket connection via
273 // authenticated proxy times out"
274 // TODO(ricea): Enable this when the issue is fixed.
275 TEST_F(WebSocketEndToEndTest, DISABLED_HttpsProxyUnauthedFails) {
276 SpawnedTestServer proxy_server(SpawnedTestServer::TYPE_BASIC_AUTH_PROXY,
277 SpawnedTestServer::kLocalhost,
278 base::FilePath());
279 SpawnedTestServer ws_server(SpawnedTestServer::TYPE_WS,
280 SpawnedTestServer::kLocalhost,
281 GetWebSocketTestDataDirectory());
282 ASSERT_TRUE(proxy_server.StartInBackground());
283 ASSERT_TRUE(ws_server.StartInBackground());
284 ASSERT_TRUE(proxy_server.BlockUntilStarted());
285 ASSERT_TRUE(ws_server.BlockUntilStarted());
286 std::string proxy_config =
287 "https=" + proxy_server.host_port_pair().ToString();
288 scoped_ptr<ProxyService> proxy_service(
289 ProxyService::CreateFixed(proxy_config));
290 ASSERT_TRUE(proxy_service);
291 context_.set_proxy_service(proxy_service.get());
292 EXPECT_FALSE(ConnectAndWait(ws_server.GetURL(kEchoServer)));
293 EXPECT_EQ("Proxy authentication failed", event_interface_->failure_message());
296 TEST_F(WebSocketEndToEndTest, DISABLED_ON_ANDROID(HttpsWssProxyUnauthedFails)) {
297 SpawnedTestServer proxy_server(SpawnedTestServer::TYPE_BASIC_AUTH_PROXY,
298 SpawnedTestServer::kLocalhost,
299 base::FilePath());
300 SpawnedTestServer wss_server(SpawnedTestServer::TYPE_WSS,
301 SpawnedTestServer::kLocalhost,
302 GetWebSocketTestDataDirectory());
303 ASSERT_TRUE(proxy_server.StartInBackground());
304 ASSERT_TRUE(wss_server.StartInBackground());
305 ASSERT_TRUE(proxy_server.BlockUntilStarted());
306 ASSERT_TRUE(wss_server.BlockUntilStarted());
307 std::string proxy_config =
308 "https=" + proxy_server.host_port_pair().ToString();
309 scoped_ptr<ProxyService> proxy_service(
310 ProxyService::CreateFixed(proxy_config));
311 ASSERT_TRUE(proxy_service);
312 context_.set_proxy_service(proxy_service.get());
313 EXPECT_FALSE(ConnectAndWait(wss_server.GetURL(kEchoServer)));
314 EXPECT_EQ("Proxy authentication failed", event_interface_->failure_message());
317 // Regression test for crbug/426736 "WebSocket connections not using configured
318 // system HTTPS Proxy".
319 TEST_F(WebSocketEndToEndTest, DISABLED_ON_ANDROID(HttpsProxyUsed)) {
320 SpawnedTestServer proxy_server(SpawnedTestServer::TYPE_BASIC_AUTH_PROXY,
321 SpawnedTestServer::kLocalhost,
322 base::FilePath());
323 SpawnedTestServer ws_server(SpawnedTestServer::TYPE_WS,
324 SpawnedTestServer::kLocalhost,
325 GetWebSocketTestDataDirectory());
326 ASSERT_TRUE(proxy_server.StartInBackground());
327 ASSERT_TRUE(ws_server.StartInBackground());
328 ASSERT_TRUE(proxy_server.BlockUntilStarted());
329 ASSERT_TRUE(ws_server.BlockUntilStarted());
330 std::string proxy_config = "https=" +
331 proxy_server.host_port_pair().ToString() + ";" +
332 "http=" + proxy_server.host_port_pair().ToString();
333 scoped_ptr<ProxyService> proxy_service(
334 ProxyService::CreateFixed(proxy_config));
335 context_.set_proxy_service(proxy_service.get());
336 InitialiseContext();
338 // The test server doesn't have an unauthenticated proxy mode. WebSockets
339 // cannot provide auth information that isn't already cached, so it's
340 // necessary to preflight an HTTP request to authenticate against the proxy.
341 GURL::Replacements replacements;
342 replacements.SetSchemeStr("http");
343 // It doesn't matter what the URL is, as long as it is an HTTP navigation.
344 GURL http_page =
345 ws_server.GetURL("connect_check.html").ReplaceComponents(replacements);
346 TestDelegate delegate;
347 delegate.set_credentials(
348 AuthCredentials(base::ASCIIToUTF16("foo"), base::ASCIIToUTF16("bar")));
350 scoped_ptr<URLRequest> request(
351 context_.CreateRequest(http_page, DEFAULT_PRIORITY, &delegate, NULL));
352 request->Start();
353 // TestDelegate exits the message loop when the request completes by
354 // default.
355 base::RunLoop().Run();
356 EXPECT_TRUE(delegate.auth_required_called());
359 GURL ws_url = ws_server.GetURL(kEchoServer);
360 EXPECT_TRUE(ConnectAndWait(ws_url));
361 const TestNetworkDelegateWithProxyInfo::ResolvedProxyInfo& info =
362 network_delegate_->resolved_proxy_info();
363 EXPECT_EQ(ws_url, info.url);
364 EXPECT_TRUE(info.proxy_info.is_http());
367 // This is a regression test for crbug.com/408061 Crash in
368 // net::WebSocketBasicHandshakeStream::Upgrade.
369 TEST_F(WebSocketEndToEndTest, DISABLED_ON_ANDROID(TruncatedResponse)) {
370 SpawnedTestServer ws_server(SpawnedTestServer::TYPE_WS,
371 SpawnedTestServer::kLocalhost,
372 GetWebSocketTestDataDirectory());
373 ASSERT_TRUE(ws_server.Start());
374 InitialiseContext();
376 GURL ws_url = ws_server.GetURL("truncated-headers");
377 EXPECT_FALSE(ConnectAndWait(ws_url));
380 } // namespace
382 } // namespace net