blob: b1ad5967e83ed15661e843fc3b9fb4069bf1ddc1 [file] [log] [blame]
ricea433bdab2015-01-26 07:25:371// 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.
4
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.
10
tfarina8a2c66c22015-10-13 19:14:4911#include <stdint.h>
ryansturm4bab06832016-03-03 23:41:0712
danakj9c5cab52016-04-16 00:54:3313#include <memory>
ricea433bdab2015-01-26 07:25:3714#include <string>
Adam Rice5b4a3d82018-08-02 15:28:4315#include <utility>
ricea433bdab2015-01-26 07:25:3716
17#include "base/bind.h"
18#include "base/bind_helpers.h"
19#include "base/callback.h"
skyostil4891b25b2015-06-11 11:43:4520#include "base/location.h"
Avi Drissman13fc8932015-12-20 04:40:4621#include "base/macros.h"
danakj9c5cab52016-04-16 00:54:3322#include "base/memory/ptr_util.h"
Bence Béky65623972018-03-05 15:31:5623#include "base/memory/scoped_refptr.h"
ricea433bdab2015-01-26 07:25:3724#include "base/run_loop.h"
skyostil4891b25b2015-06-11 11:43:4525#include "base/single_thread_task_runner.h"
Adam Rice5b4a3d82018-08-02 15:28:4326#include "base/strings/strcat.h"
Adam Ricecb76ac62015-02-20 05:33:2527#include "base/strings/string_piece.h"
Adam Rice5b4a3d82018-08-02 15:28:4328#include "base/strings/stringprintf.h"
gabf767595f2016-05-11 18:50:3529#include "base/threading/thread_task_runner_handle.h"
Sergey Ulanova337dcd2017-09-08 20:53:1430#include "build/build_config.h"
ricea433bdab2015-01-26 07:25:3731#include "net/base/auth.h"
Adam Rice5b4a3d82018-08-02 15:28:4332#include "net/base/host_port_pair.h"
ryansturm7de050c2016-02-23 00:10:2133#include "net/base/proxy_delegate.h"
Adam Rice5b4a3d82018-08-02 15:28:4334#include "net/base/url_util.h"
Yutaka Hirano2f65eec2018-05-23 01:58:2235#include "net/http/http_request_headers.h"
Adam Rice5b4a3d82018-08-02 15:28:4336#include "net/log/net_log.h"
37#include "net/proxy_resolution/proxy_config.h"
38#include "net/proxy_resolution/proxy_config_service.h"
39#include "net/proxy_resolution/proxy_config_service_fixed.h"
40#include "net/proxy_resolution/proxy_config_with_annotation.h"
41#include "net/proxy_resolution/proxy_info.h"
Lily Houghtonffe89daa02018-03-09 18:30:0342#include "net/proxy_resolution/proxy_resolution_service.h"
tommycli59a63432015-11-06 00:10:5543#include "net/test/embedded_test_server/embedded_test_server.h"
Adam Rice5b4a3d82018-08-02 15:28:4344#include "net/test/embedded_test_server/http_request.h"
45#include "net/test/embedded_test_server/http_response.h"
ricea433bdab2015-01-26 07:25:3746#include "net/test/spawned_test_server/spawned_test_server.h"
rsleevia69c79a2016-06-22 03:28:4347#include "net/test/test_data_directory.h"
Bence Béky98447b12018-05-08 03:14:0148#include "net/test/test_with_scoped_task_environment.h"
rhalavati9ebaba7e2017-04-27 06:16:2949#include "net/traffic_annotation/network_traffic_annotation_test_helper.h"
Adam Rice5b4a3d82018-08-02 15:28:4350#include "net/url_request/url_request.h"
51#include "net/url_request/url_request_context.h"
ricea433bdab2015-01-26 07:25:3752#include "net/url_request/url_request_test_util.h"
53#include "net/websockets/websocket_channel.h"
54#include "net/websockets/websocket_event_interface.h"
55#include "testing/gtest/include/gtest/gtest.h"
Adam Rice5b4a3d82018-08-02 15:28:4356#include "url/gurl.h"
mkwst4997ce82015-07-25 12:00:0557#include "url/origin.h"
ricea433bdab2015-01-26 07:25:3758
59namespace net {
60
yhirano4a593832016-10-24 18:58:2261class URLRequest;
62
ricea433bdab2015-01-26 07:25:3763namespace {
64
Adam Rice5b4a3d82018-08-02 15:28:4365using test_server::BasicHttpResponse;
66using test_server::HttpRequest;
67using test_server::HttpResponse;
68
ricea433bdab2015-01-26 07:25:3769static const char kEchoServer[] = "echo-with-no-extension";
70
Adam Ricecb76ac62015-02-20 05:33:2571// Simplify changing URL schemes.
72GURL ReplaceUrlScheme(const GURL& in_url, const base::StringPiece& scheme) {
73 GURL::Replacements replacements;
74 replacements.SetSchemeStr(scheme);
75 return in_url.ReplaceComponents(replacements);
76}
77
ricea433bdab2015-01-26 07:25:3778// An implementation of WebSocketEventInterface that waits for and records the
79// results of the connect.
80class ConnectTestingEventInterface : public WebSocketEventInterface {
81 public:
82 ConnectTestingEventInterface();
83
84 void WaitForResponse();
85
86 bool failed() const { return failed_; }
87
88 // Only set if the handshake failed, otherwise empty.
89 std::string failure_message() const;
90
91 std::string selected_subprotocol() const;
92
93 std::string extensions() const;
94
95 // Implementation of WebSocketEventInterface.
yhirano4a593832016-10-24 18:58:2296 void OnCreateURLRequest(URLRequest* request) override {}
97
Yutaka Hirano4165de92018-04-10 11:46:4998 void OnAddChannelResponse(const std::string& selected_subprotocol,
99 const std::string& extensions) override;
ricea433bdab2015-01-26 07:25:37100
Yutaka Hirano4165de92018-04-10 11:46:49101 void OnDataFrame(bool fin,
102 WebSocketMessageType type,
103 scoped_refptr<IOBuffer> data,
104 size_t data_size) override;
ricea433bdab2015-01-26 07:25:37105
Yutaka Hirano4165de92018-04-10 11:46:49106 void OnFlowControl(int64_t quota) override;
ricea433bdab2015-01-26 07:25:37107
Yutaka Hirano4165de92018-04-10 11:46:49108 void OnClosingHandshake() override;
ricea433bdab2015-01-26 07:25:37109
Yutaka Hirano4165de92018-04-10 11:46:49110 void OnDropChannel(bool was_clean,
111 uint16_t code,
112 const std::string& reason) override;
ricea433bdab2015-01-26 07:25:37113
Yutaka Hirano4165de92018-04-10 11:46:49114 void OnFailChannel(const std::string& message) override;
ricea433bdab2015-01-26 07:25:37115
Yutaka Hirano4165de92018-04-10 11:46:49116 void OnStartOpeningHandshake(
danakj9c5cab52016-04-16 00:54:33117 std::unique_ptr<WebSocketHandshakeRequestInfo> request) override;
ricea433bdab2015-01-26 07:25:37118
Yutaka Hirano4165de92018-04-10 11:46:49119 void OnFinishOpeningHandshake(
danakj9c5cab52016-04-16 00:54:33120 std::unique_ptr<WebSocketHandshakeResponseInfo> response) override;
ricea433bdab2015-01-26 07:25:37121
Yutaka Hirano4165de92018-04-10 11:46:49122 void OnSSLCertificateError(
danakj9c5cab52016-04-16 00:54:33123 std::unique_ptr<SSLErrorCallbacks> ssl_error_callbacks,
ricea433bdab2015-01-26 07:25:37124 const GURL& url,
125 const SSLInfo& ssl_info,
126 bool fatal) override;
127
Yutaka Hirano70fa25912018-06-06 05:26:54128 int OnAuthRequired(scoped_refptr<AuthChallengeInfo> auth_info,
129 scoped_refptr<HttpResponseHeaders> response_headers,
130 const HostPortPair& host_port_pair,
131 base::OnceCallback<void(const AuthCredentials*)> callback,
132 base::Optional<AuthCredentials>* credentials) override;
133
ricea433bdab2015-01-26 07:25:37134 private:
135 void QuitNestedEventLoop();
136
137 // failed_ is true if the handshake failed (ie. OnFailChannel was called).
138 bool failed_;
139 std::string selected_subprotocol_;
140 std::string extensions_;
141 std::string failure_message_;
142 base::RunLoop run_loop_;
143
144 DISALLOW_COPY_AND_ASSIGN(ConnectTestingEventInterface);
145};
146
tyoshinoc06da562015-03-06 06:02:42147ConnectTestingEventInterface::ConnectTestingEventInterface() : failed_(false) {
ricea433bdab2015-01-26 07:25:37148}
149
150void ConnectTestingEventInterface::WaitForResponse() {
151 run_loop_.Run();
152}
153
154std::string ConnectTestingEventInterface::failure_message() const {
155 return failure_message_;
156}
157
158std::string ConnectTestingEventInterface::selected_subprotocol() const {
159 return selected_subprotocol_;
160}
161
162std::string ConnectTestingEventInterface::extensions() const {
163 return extensions_;
164}
165
Yutaka Hirano4165de92018-04-10 11:46:49166void ConnectTestingEventInterface::OnAddChannelResponse(
ricea433bdab2015-01-26 07:25:37167 const std::string& selected_subprotocol,
168 const std::string& extensions) {
ricea433bdab2015-01-26 07:25:37169 selected_subprotocol_ = selected_subprotocol;
170 extensions_ = extensions;
171 QuitNestedEventLoop();
ricea433bdab2015-01-26 07:25:37172}
173
Yutaka Hirano4165de92018-04-10 11:46:49174void ConnectTestingEventInterface::OnDataFrame(bool fin,
175 WebSocketMessageType type,
176 scoped_refptr<IOBuffer> data,
177 size_t data_size) {}
ricea433bdab2015-01-26 07:25:37178
Yutaka Hirano4165de92018-04-10 11:46:49179void ConnectTestingEventInterface::OnFlowControl(int64_t quota) {}
ricea433bdab2015-01-26 07:25:37180
Yutaka Hirano4165de92018-04-10 11:46:49181void ConnectTestingEventInterface::OnClosingHandshake() {}
ricea433bdab2015-01-26 07:25:37182
Yutaka Hirano4165de92018-04-10 11:46:49183void ConnectTestingEventInterface::OnDropChannel(bool was_clean,
184 uint16_t code,
185 const std::string& reason) {}
ricea433bdab2015-01-26 07:25:37186
Yutaka Hirano4165de92018-04-10 11:46:49187void ConnectTestingEventInterface::OnFailChannel(const std::string& message) {
ricea433bdab2015-01-26 07:25:37188 failed_ = true;
189 failure_message_ = message;
190 QuitNestedEventLoop();
ricea433bdab2015-01-26 07:25:37191}
192
Yutaka Hirano4165de92018-04-10 11:46:49193void ConnectTestingEventInterface::OnStartOpeningHandshake(
194 std::unique_ptr<WebSocketHandshakeRequestInfo> request) {}
ricea433bdab2015-01-26 07:25:37195
Yutaka Hirano4165de92018-04-10 11:46:49196void ConnectTestingEventInterface::OnFinishOpeningHandshake(
197 std::unique_ptr<WebSocketHandshakeResponseInfo> response) {}
ricea433bdab2015-01-26 07:25:37198
Yutaka Hirano4165de92018-04-10 11:46:49199void ConnectTestingEventInterface::OnSSLCertificateError(
danakj9c5cab52016-04-16 00:54:33200 std::unique_ptr<SSLErrorCallbacks> ssl_error_callbacks,
ricea433bdab2015-01-26 07:25:37201 const GURL& url,
202 const SSLInfo& ssl_info,
203 bool fatal) {
skyostil4891b25b2015-06-11 11:43:45204 base::ThreadTaskRunnerHandle::Get()->PostTask(
kylecharf4fe5172019-02-15 18:53:49205 FROM_HERE, base::BindOnce(&SSLErrorCallbacks::CancelSSLRequest,
206 base::Owned(ssl_error_callbacks.release()),
207 ERR_SSL_PROTOCOL_ERROR, &ssl_info));
ricea433bdab2015-01-26 07:25:37208}
209
Yutaka Hirano70fa25912018-06-06 05:26:54210int ConnectTestingEventInterface::OnAuthRequired(
211 scoped_refptr<AuthChallengeInfo> auth_info,
212 scoped_refptr<HttpResponseHeaders> response_headers,
213 const HostPortPair& host_port_pair,
214 base::OnceCallback<void(const AuthCredentials*)> callback,
215 base::Optional<AuthCredentials>* credentials) {
216 *credentials = base::nullopt;
217 return OK;
218}
219
ricea433bdab2015-01-26 07:25:37220void ConnectTestingEventInterface::QuitNestedEventLoop() {
221 run_loop_.Quit();
222}
223
224// A subclass of TestNetworkDelegate that additionally implements the
225// OnResolveProxy callback and records the information passed to it.
ryansturm7de050c2016-02-23 00:10:21226class TestProxyDelegateWithProxyInfo : public ProxyDelegate {
ricea433bdab2015-01-26 07:25:37227 public:
Chris Watkins28c2fdd2017-11-30 06:06:52228 TestProxyDelegateWithProxyInfo() = default;
ricea433bdab2015-01-26 07:25:37229
230 struct ResolvedProxyInfo {
231 GURL url;
232 ProxyInfo proxy_info;
233 };
234
235 const ResolvedProxyInfo& resolved_proxy_info() const {
236 return resolved_proxy_info_;
237 }
238
239 protected:
240 void OnResolveProxy(const GURL& url,
ryansturm4bab06832016-03-03 23:41:07241 const std::string& method,
Reilly Grantb414ace72017-11-14 23:03:22242 const ProxyRetryInfoMap& proxy_retry_info,
ricea433bdab2015-01-26 07:25:37243 ProxyInfo* result) override {
244 resolved_proxy_info_.url = url;
245 resolved_proxy_info_.proxy_info = *result;
246 }
247
ryansturm7de050c2016-02-23 00:10:21248 void OnFallback(const ProxyServer& bad_proxy, int net_error) override {}
ryansturm7de050c2016-02-23 00:10:21249
Wojciech Dzierżanowskic2704042019-02-07 20:54:28250 void OnBeforeHttp1TunnelRequest(const ProxyServer& proxy_server,
251 HttpRequestHeaders* extra_headers) override {}
Wojciech Dzierżanowski1f823562019-01-18 11:26:00252
Wojciech Dzierżanowskic2704042019-02-07 20:54:28253 Error OnHttp1TunnelHeadersReceived(
Wojciech Dzierżanowski1f823562019-01-18 11:26:00254 const ProxyServer& proxy_server,
255 const HttpResponseHeaders& response_headers) override {
256 return OK;
257 }
258
ricea433bdab2015-01-26 07:25:37259 private:
260 ResolvedProxyInfo resolved_proxy_info_;
261
ryansturm7de050c2016-02-23 00:10:21262 DISALLOW_COPY_AND_ASSIGN(TestProxyDelegateWithProxyInfo);
ricea433bdab2015-01-26 07:25:37263};
264
Bence Béky98447b12018-05-08 03:14:01265class WebSocketEndToEndTest : public TestWithScopedTaskEnvironment {
ricea433bdab2015-01-26 07:25:37266 protected:
267 WebSocketEndToEndTest()
Adam Ricecb76ac62015-02-20 05:33:25268 : event_interface_(),
Bence Béky65623972018-03-05 15:31:56269 proxy_delegate_(std::make_unique<TestProxyDelegateWithProxyInfo>()),
ricea433bdab2015-01-26 07:25:37270 context_(true),
Adam Ricecb76ac62015-02-20 05:33:25271 channel_(),
ricea433bdab2015-01-26 07:25:37272 initialised_context_(false) {}
273
274 // Initialise the URLRequestContext. Normally done automatically by
275 // ConnectAndWait(). This method is for the use of tests that need the
276 // URLRequestContext initialised before calling ConnectAndWait().
277 void InitialiseContext() {
ricea433bdab2015-01-26 07:25:37278 context_.Init();
Eric Roman3d8546a2018-09-10 17:00:52279 context_.proxy_resolution_service()->SetProxyDelegate(
280 proxy_delegate_.get());
ricea433bdab2015-01-26 07:25:37281 initialised_context_ = true;
282 }
283
284 // Send the connect request to |socket_url| and wait for a response. Returns
285 // true if the handshake succeeded.
286 bool ConnectAndWait(const GURL& socket_url) {
287 if (!initialised_context_) {
288 InitialiseContext();
289 }
Daniel Cheng88186bd52017-10-20 08:14:46290 url::Origin origin = url::Origin::Create(GURL("http://localhost"));
Mike Westb85da8ed2017-08-10 14:16:46291 GURL site_for_cookies("http://localhost/");
Adam Rice5b4a3d82018-08-02 15:28:43292 event_interface_ = new ConnectTestingEventInterface();
Bence Béky65623972018-03-05 15:31:56293 channel_ = std::make_unique<WebSocketChannel>(
294 base::WrapUnique(event_interface_), &context_);
alladacef397d2016-06-29 17:52:23295 channel_->SendAddChannelRequest(GURL(socket_url), sub_protocols_, origin,
Yutaka Hirano2f65eec2018-05-23 01:58:22296 site_for_cookies, HttpRequestHeaders());
ricea433bdab2015-01-26 07:25:37297 event_interface_->WaitForResponse();
298 return !event_interface_->failed();
299 }
300
301 ConnectTestingEventInterface* event_interface_; // owned by channel_
danakj9c5cab52016-04-16 00:54:33302 std::unique_ptr<TestProxyDelegateWithProxyInfo> proxy_delegate_;
ricea433bdab2015-01-26 07:25:37303 TestURLRequestContext context_;
danakj9c5cab52016-04-16 00:54:33304 std::unique_ptr<WebSocketChannel> channel_;
ricea5acb1faf72015-03-16 15:34:00305 std::vector<std::string> sub_protocols_;
ricea433bdab2015-01-26 07:25:37306 bool initialised_context_;
307};
308
ricea433bdab2015-01-26 07:25:37309// Basic test of connectivity. If this test fails, nothing else can be expected
310// to work.
Sergey Ulanov4c786d32017-09-08 22:53:25311TEST_F(WebSocketEndToEndTest, BasicSmokeTest) {
ricea433bdab2015-01-26 07:25:37312 SpawnedTestServer ws_server(SpawnedTestServer::TYPE_WS,
ricea433bdab2015-01-26 07:25:37313 GetWebSocketTestDataDirectory());
314 ASSERT_TRUE(ws_server.Start());
315 EXPECT_TRUE(ConnectAndWait(ws_server.GetURL(kEchoServer)));
316}
317
318// Test for issue crbug.com/433695 "Unencrypted WebSocket connection via
319// authenticated proxy times out"
320// TODO(ricea): Enable this when the issue is fixed.
321TEST_F(WebSocketEndToEndTest, DISABLED_HttpsProxyUnauthedFails) {
322 SpawnedTestServer proxy_server(SpawnedTestServer::TYPE_BASIC_AUTH_PROXY,
ricea433bdab2015-01-26 07:25:37323 base::FilePath());
324 SpawnedTestServer ws_server(SpawnedTestServer::TYPE_WS,
ricea433bdab2015-01-26 07:25:37325 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 =
331 "https=" + proxy_server.host_port_pair().ToString();
Lily Houghton8c2f97d2018-01-22 05:06:59332 std::unique_ptr<ProxyResolutionService> proxy_resolution_service(
Ramin Halavatica8d5252018-03-12 05:33:49333 ProxyResolutionService::CreateFixed(proxy_config,
334 TRAFFIC_ANNOTATION_FOR_TESTS));
Lily Houghton8c2f97d2018-01-22 05:06:59335 ASSERT_TRUE(proxy_resolution_service);
336 context_.set_proxy_resolution_service(proxy_resolution_service.get());
ricea433bdab2015-01-26 07:25:37337 EXPECT_FALSE(ConnectAndWait(ws_server.GetURL(kEchoServer)));
338 EXPECT_EQ("Proxy authentication failed", event_interface_->failure_message());
339}
340
Sergey Ulanov4c786d32017-09-08 22:53:25341// These test are not compatible with RemoteTestServer because RemoteTestServer
342// doesn't support TYPE_BASIC_AUTH_PROXY.
343// TODO(ricea): Make these tests work. See crbug.com/441711.
344#if defined(OS_ANDROID) || defined(OS_FUCHSIA)
345#define MAYBE_HttpsWssProxyUnauthedFails DISABLED_HttpsWssProxyUnauthedFails
346#define MAYBE_HttpsProxyUsed DISABLED_HttpsProxyUsed
347#else
348#define MAYBE_HttpsWssProxyUnauthedFails HttpsWssProxyUnauthedFails
349#define MAYBE_HttpsProxyUsed HttpsProxyUsed
350#endif
351
352TEST_F(WebSocketEndToEndTest, MAYBE_HttpsWssProxyUnauthedFails) {
ricea433bdab2015-01-26 07:25:37353 SpawnedTestServer proxy_server(SpawnedTestServer::TYPE_BASIC_AUTH_PROXY,
ricea433bdab2015-01-26 07:25:37354 base::FilePath());
355 SpawnedTestServer wss_server(SpawnedTestServer::TYPE_WSS,
ricea433bdab2015-01-26 07:25:37356 GetWebSocketTestDataDirectory());
357 ASSERT_TRUE(proxy_server.StartInBackground());
358 ASSERT_TRUE(wss_server.StartInBackground());
359 ASSERT_TRUE(proxy_server.BlockUntilStarted());
360 ASSERT_TRUE(wss_server.BlockUntilStarted());
Eric Romanda790f92018-11-07 19:17:15361 ProxyConfig proxy_config;
362 proxy_config.proxy_rules().ParseFromString(
363 "https=" + proxy_server.host_port_pair().ToString());
364 // TODO(https://crbug.com/901896): Don't rely on proxying localhost.
365 proxy_config.proxy_rules().bypass_rules.AddRulesToSubtractImplicit();
366
Lily Houghton8c2f97d2018-01-22 05:06:59367 std::unique_ptr<ProxyResolutionService> proxy_resolution_service(
Eric Romanda790f92018-11-07 19:17:15368 ProxyResolutionService::CreateFixed(ProxyConfigWithAnnotation(
369 proxy_config, TRAFFIC_ANNOTATION_FOR_TESTS)));
Lily Houghton8c2f97d2018-01-22 05:06:59370 ASSERT_TRUE(proxy_resolution_service);
371 context_.set_proxy_resolution_service(proxy_resolution_service.get());
ricea433bdab2015-01-26 07:25:37372 EXPECT_FALSE(ConnectAndWait(wss_server.GetURL(kEchoServer)));
373 EXPECT_EQ("Proxy authentication failed", event_interface_->failure_message());
374}
375
376// Regression test for crbug/426736 "WebSocket connections not using configured
377// system HTTPS Proxy".
Sergey Ulanov4c786d32017-09-08 22:53:25378TEST_F(WebSocketEndToEndTest, MAYBE_HttpsProxyUsed) {
Adam Rice5b4a3d82018-08-02 15:28:43379 SpawnedTestServer proxy_server(SpawnedTestServer::TYPE_PROXY,
ricea433bdab2015-01-26 07:25:37380 base::FilePath());
381 SpawnedTestServer ws_server(SpawnedTestServer::TYPE_WS,
ricea433bdab2015-01-26 07:25:37382 GetWebSocketTestDataDirectory());
383 ASSERT_TRUE(proxy_server.StartInBackground());
384 ASSERT_TRUE(ws_server.StartInBackground());
385 ASSERT_TRUE(proxy_server.BlockUntilStarted());
386 ASSERT_TRUE(ws_server.BlockUntilStarted());
Eric Romanda790f92018-11-07 19:17:15387 ProxyConfig proxy_config;
388 proxy_config.proxy_rules().ParseFromString(
389 "https=" + proxy_server.host_port_pair().ToString() + ";" +
390 "http=" + proxy_server.host_port_pair().ToString());
391 // TODO(https://crbug.com/901896): Don't rely on proxying localhost.
392 proxy_config.proxy_rules().bypass_rules.AddRulesToSubtractImplicit();
393
Lily Houghton8c2f97d2018-01-22 05:06:59394 std::unique_ptr<ProxyResolutionService> proxy_resolution_service(
Eric Romanda790f92018-11-07 19:17:15395 ProxyResolutionService::CreateFixed(ProxyConfigWithAnnotation(
396 proxy_config, TRAFFIC_ANNOTATION_FOR_TESTS)));
Lily Houghton8c2f97d2018-01-22 05:06:59397 context_.set_proxy_resolution_service(proxy_resolution_service.get());
ricea433bdab2015-01-26 07:25:37398 InitialiseContext();
399
ricea433bdab2015-01-26 07:25:37400 GURL ws_url = ws_server.GetURL(kEchoServer);
401 EXPECT_TRUE(ConnectAndWait(ws_url));
ryansturm7de050c2016-02-23 00:10:21402 const TestProxyDelegateWithProxyInfo::ResolvedProxyInfo& info =
403 proxy_delegate_->resolved_proxy_info();
ricea433bdab2015-01-26 07:25:37404 EXPECT_EQ(ws_url, info.url);
405 EXPECT_TRUE(info.proxy_info.is_http());
406}
407
Adam Rice5b4a3d82018-08-02 15:28:43408std::unique_ptr<HttpResponse> ProxyPacHandler(const HttpRequest& request) {
409 GURL url = request.GetURL();
410 EXPECT_EQ(url.path_piece(), "/proxy.pac");
411 EXPECT_TRUE(url.has_query());
412 std::string proxy;
413 EXPECT_TRUE(GetValueForKeyInQuery(url, "proxy", &proxy));
414 auto response = std::make_unique<BasicHttpResponse>();
415 response->set_content_type("application/x-ns-proxy-autoconfig");
416 response->set_content(
417 base::StringPrintf("function FindProxyForURL(url, host) {\n"
418 " return 'PROXY %s';\n"
419 "}\n",
420 proxy.c_str()));
421 return response;
422}
423
424// This tests the proxy.pac resolver that is built into the system. This is not
425// the one that Chrome normally uses. Chrome's normal implementation is defined
426// as a mojo service. It is outside //net and we can't use it from here. This
427// tests the alternative implementations that are selected when the
428// --winhttp-proxy-resolver flag is provided to Chrome. These only exist on OS X
429// and Windows.
430// TODO(ricea): Remove this test if --winhttp-proxy-resolver flag is removed.
431// See crbug.com/644030.
432
433#if defined(OS_WIN) || defined(OS_MACOSX)
434#define MAYBE_ProxyPacUsed ProxyPacUsed
435#else
436#define MAYBE_ProxyPacUsed DISABLED_ProxyPacUsed
437#endif
438
439TEST_F(WebSocketEndToEndTest, MAYBE_ProxyPacUsed) {
440 EmbeddedTestServer proxy_pac_server(net::EmbeddedTestServer::Type::TYPE_HTTP);
441 SpawnedTestServer proxy_server(SpawnedTestServer::TYPE_PROXY,
442 base::FilePath());
443 SpawnedTestServer ws_server(SpawnedTestServer::TYPE_WS,
444 GetWebSocketTestDataDirectory());
445 proxy_pac_server.RegisterRequestHandler(base::BindRepeating(ProxyPacHandler));
446 proxy_server.set_redirect_connect_to_localhost(true);
447
448 ASSERT_TRUE(proxy_pac_server.Start());
449 ASSERT_TRUE(proxy_server.StartInBackground());
450 ASSERT_TRUE(ws_server.StartInBackground());
451 ASSERT_TRUE(proxy_server.BlockUntilStarted());
452 ASSERT_TRUE(ws_server.BlockUntilStarted());
453
454 ProxyConfig proxy_config =
455 ProxyConfig::CreateFromCustomPacURL(proxy_pac_server.GetURL(base::StrCat(
456 {"/proxy.pac?proxy=", proxy_server.host_port_pair().ToString()})));
457 proxy_config.set_pac_mandatory(true);
458 auto proxy_config_service = std::make_unique<ProxyConfigServiceFixed>(
459 ProxyConfigWithAnnotation(proxy_config, TRAFFIC_ANNOTATION_FOR_TESTS));
460 NetLog net_log;
461 std::unique_ptr<ProxyResolutionService> proxy_resolution_service(
462 ProxyResolutionService::CreateUsingSystemProxyResolver(
463 std::move(proxy_config_service), &net_log));
464 ASSERT_EQ(ws_server.host_port_pair().host(), "127.0.0.1");
465 context_.set_proxy_resolution_service(proxy_resolution_service.get());
466 InitialiseContext();
467
Eric Romanda790f92018-11-07 19:17:15468 // Use a name other than localhost, since localhost implicitly bypasses the
469 // use of proxy.pac.
Adam Rice5b4a3d82018-08-02 15:28:43470 HostPortPair fake_ws_host_port_pair("stealth-localhost",
471 ws_server.host_port_pair().port());
472
473 GURL ws_url(base::StrCat(
474 {"ws://", fake_ws_host_port_pair.ToString(), "/", kEchoServer}));
475 EXPECT_TRUE(ConnectAndWait(ws_url));
476 const auto& info = proxy_delegate_->resolved_proxy_info();
477 EXPECT_EQ(ws_url, info.url);
478 EXPECT_TRUE(info.proxy_info.is_http());
479 EXPECT_EQ(info.proxy_info.ToPacString(),
480 base::StrCat({"PROXY ", proxy_server.host_port_pair().ToString()}));
481}
482
ricea23c3f942015-02-02 13:35:13483// This is a regression test for crbug.com/408061 Crash in
484// net::WebSocketBasicHandshakeStream::Upgrade.
Sergey Ulanov4c786d32017-09-08 22:53:25485TEST_F(WebSocketEndToEndTest, TruncatedResponse) {
ricea23c3f942015-02-02 13:35:13486 SpawnedTestServer ws_server(SpawnedTestServer::TYPE_WS,
ricea23c3f942015-02-02 13:35:13487 GetWebSocketTestDataDirectory());
488 ASSERT_TRUE(ws_server.Start());
489 InitialiseContext();
490
491 GURL ws_url = ws_server.GetURL("truncated-headers");
492 EXPECT_FALSE(ConnectAndWait(ws_url));
493}
494
Adam Ricecb76ac62015-02-20 05:33:25495// Regression test for crbug.com/455215 "HSTS not applied to WebSocket"
Sergey Ulanov4c786d32017-09-08 22:53:25496TEST_F(WebSocketEndToEndTest, HstsHttpsToWebSocket) {
tommycli59a63432015-11-06 00:10:55497 EmbeddedTestServer https_server(net::EmbeddedTestServer::Type::TYPE_HTTPS);
498 https_server.SetSSLConfig(
499 net::EmbeddedTestServer::CERT_COMMON_NAME_IS_DOMAIN);
500 https_server.ServeFilesFromSourceDirectory("net/data/url_request_unittest");
501
estarka5da76702015-04-09 04:00:16502 SpawnedTestServer::SSLOptions ssl_options(
503 SpawnedTestServer::SSLOptions::CERT_COMMON_NAME_IS_DOMAIN);
Adam Ricecb76ac62015-02-20 05:33:25504 SpawnedTestServer wss_server(SpawnedTestServer::TYPE_WSS, ssl_options,
505 GetWebSocketTestDataDirectory());
estarka5da76702015-04-09 04:00:16506
tommycli59a63432015-11-06 00:10:55507 ASSERT_TRUE(https_server.Start());
508 ASSERT_TRUE(wss_server.Start());
Adam Ricecb76ac62015-02-20 05:33:25509 InitialiseContext();
510 // Set HSTS via https:
511 TestDelegate delegate;
tommycli59a63432015-11-06 00:10:55512 GURL https_page = https_server.GetURL("/hsts-headers.html");
rhalavati9ebaba7e2017-04-27 06:16:29513 std::unique_ptr<URLRequest> request(context_.CreateRequest(
514 https_page, DEFAULT_PRIORITY, &delegate, TRAFFIC_ANNOTATION_FOR_TESTS));
Adam Ricecb76ac62015-02-20 05:33:25515 request->Start();
Wez2a31b222018-06-07 22:07:15516 delegate.RunUntilComplete();
maksim.sisov7f60c8e2016-09-16 19:38:17517 EXPECT_EQ(OK, delegate.request_status());
Adam Ricecb76ac62015-02-20 05:33:25518
519 // Check HSTS with ws:
520 // Change the scheme from wss: to ws: to verify that it is switched back.
521 GURL ws_url = ReplaceUrlScheme(wss_server.GetURL(kEchoServer), "ws");
522 EXPECT_TRUE(ConnectAndWait(ws_url));
523}
524
Sergey Ulanov4c786d32017-09-08 22:53:25525TEST_F(WebSocketEndToEndTest, HstsWebSocketToHttps) {
tommycli59a63432015-11-06 00:10:55526 EmbeddedTestServer https_server(net::EmbeddedTestServer::Type::TYPE_HTTPS);
527 https_server.SetSSLConfig(
528 net::EmbeddedTestServer::CERT_COMMON_NAME_IS_DOMAIN);
529 https_server.ServeFilesFromSourceDirectory("net/data/url_request_unittest");
530
estarka5da76702015-04-09 04:00:16531 SpawnedTestServer::SSLOptions ssl_options(
532 SpawnedTestServer::SSLOptions::CERT_COMMON_NAME_IS_DOMAIN);
Adam Ricecb76ac62015-02-20 05:33:25533 SpawnedTestServer wss_server(SpawnedTestServer::TYPE_WSS, ssl_options,
534 GetWebSocketTestDataDirectory());
tommycli59a63432015-11-06 00:10:55535 ASSERT_TRUE(https_server.Start());
536 ASSERT_TRUE(wss_server.Start());
Adam Ricecb76ac62015-02-20 05:33:25537 InitialiseContext();
538 // Set HSTS via wss:
539 GURL wss_url = wss_server.GetURL("set-hsts");
540 EXPECT_TRUE(ConnectAndWait(wss_url));
541
542 // Verify via http:
543 TestDelegate delegate;
544 GURL http_page =
tommycli59a63432015-11-06 00:10:55545 ReplaceUrlScheme(https_server.GetURL("/simple.html"), "http");
rhalavati9ebaba7e2017-04-27 06:16:29546 std::unique_ptr<URLRequest> request(context_.CreateRequest(
547 http_page, DEFAULT_PRIORITY, &delegate, TRAFFIC_ANNOTATION_FOR_TESTS));
Adam Ricecb76ac62015-02-20 05:33:25548 request->Start();
Wez2a31b222018-06-07 22:07:15549 delegate.RunUntilComplete();
maksim.sisov7f60c8e2016-09-16 19:38:17550 EXPECT_EQ(OK, delegate.request_status());
Adam Ricecb76ac62015-02-20 05:33:25551 EXPECT_TRUE(request->url().SchemeIs("https"));
552}
553
Sergey Ulanov4c786d32017-09-08 22:53:25554TEST_F(WebSocketEndToEndTest, HstsWebSocketToWebSocket) {
estarka5da76702015-04-09 04:00:16555 SpawnedTestServer::SSLOptions ssl_options(
556 SpawnedTestServer::SSLOptions::CERT_COMMON_NAME_IS_DOMAIN);
Adam Ricecb76ac62015-02-20 05:33:25557 SpawnedTestServer wss_server(SpawnedTestServer::TYPE_WSS, ssl_options,
558 GetWebSocketTestDataDirectory());
559 ASSERT_TRUE(wss_server.Start());
560 InitialiseContext();
561 // Set HSTS via wss:
562 GURL wss_url = wss_server.GetURL("set-hsts");
563 EXPECT_TRUE(ConnectAndWait(wss_url));
564
565 // Verify via wss:
566 GURL ws_url = ReplaceUrlScheme(wss_server.GetURL(kEchoServer), "ws");
567 EXPECT_TRUE(ConnectAndWait(ws_url));
568}
569
ricea5acb1faf72015-03-16 15:34:00570// Regression test for crbug.com/180504 "WebSocket handshake fails when HTTP
571// headers have trailing LWS".
Sergey Ulanov4c786d32017-09-08 22:53:25572TEST_F(WebSocketEndToEndTest, TrailingWhitespace) {
ricea5acb1faf72015-03-16 15:34:00573 SpawnedTestServer ws_server(SpawnedTestServer::TYPE_WS,
ricea5acb1faf72015-03-16 15:34:00574 GetWebSocketTestDataDirectory());
575 ASSERT_TRUE(ws_server.Start());
576
577 GURL ws_url = ws_server.GetURL("trailing-whitespace");
578 sub_protocols_.push_back("sip");
579 EXPECT_TRUE(ConnectAndWait(ws_url));
580 EXPECT_EQ("sip", event_interface_->selected_subprotocol());
581}
582
riceae1d67672015-03-19 10:10:17583// This is a regression test for crbug.com/169448 "WebSockets should support
584// header continuations"
585// TODO(ricea): HTTP continuation headers have been deprecated by RFC7230. If
586// support for continuation headers is removed from Chrome, then this test will
587// break and should be removed.
Sergey Ulanov4c786d32017-09-08 22:53:25588TEST_F(WebSocketEndToEndTest, HeaderContinuations) {
riceae1d67672015-03-19 10:10:17589 SpawnedTestServer ws_server(SpawnedTestServer::TYPE_WS,
riceae1d67672015-03-19 10:10:17590 GetWebSocketTestDataDirectory());
591 ASSERT_TRUE(ws_server.Start());
592
593 GURL ws_url = ws_server.GetURL("header-continuation");
594
595 EXPECT_TRUE(ConnectAndWait(ws_url));
596 EXPECT_EQ("permessage-deflate; server_max_window_bits=10",
597 event_interface_->extensions());
598}
599
ricea433bdab2015-01-26 07:25:37600} // namespace
601
602} // namespace net