blob: c5d97d964b7bdf49dc1bfc896e81103d9a735881 [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"
ricea433bdab2015-01-26 07:25:3718#include "base/callback.h"
danakjdb9ae7942020-11-11 16:01:3519#include "base/callback_helpers.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"
Tsuyoshi Horo01faed62019-02-20 22:11:3733#include "net/base/ip_endpoint.h"
Matt Menke29a538d2020-04-29 16:12:1734#include "net/base/isolation_info.h"
Chris Thompsone3c3a3b02020-12-17 23:20:4035#include "net/base/load_flags.h"
36#include "net/base/net_errors.h"
ryansturm7de050c2016-02-23 00:10:2137#include "net/base/proxy_delegate.h"
Adam Rice5b4a3d82018-08-02 15:28:4338#include "net/base/url_util.h"
Chris Thompsone3c3a3b02020-12-17 23:20:4039#include "net/cert/ct_policy_status.h"
Yutaka Hirano2f65eec2018-05-23 01:58:2240#include "net/http/http_request_headers.h"
Matt Menkece5d765372021-08-17 18:24:1241#include "net/http/transport_security_state.h"
Adam Rice5b4a3d82018-08-02 15:28:4342#include "net/log/net_log.h"
Nicolas Arciniegad2013f92020-02-07 23:00:5643#include "net/proxy_resolution/configured_proxy_resolution_service.h"
Adam Rice5b4a3d82018-08-02 15:28:4344#include "net/proxy_resolution/proxy_config.h"
45#include "net/proxy_resolution/proxy_config_service.h"
46#include "net/proxy_resolution/proxy_config_service_fixed.h"
47#include "net/proxy_resolution/proxy_config_with_annotation.h"
48#include "net/proxy_resolution/proxy_info.h"
Chris Thompsone3c3a3b02020-12-17 23:20:4049#include "net/socket/socket_test_util.h"
50#include "net/test/cert_test_util.h"
tommycli59a63432015-11-06 00:10:5551#include "net/test/embedded_test_server/embedded_test_server.h"
Adam Rice5b4a3d82018-08-02 15:28:4352#include "net/test/embedded_test_server/http_request.h"
53#include "net/test/embedded_test_server/http_response.h"
ricea433bdab2015-01-26 07:25:3754#include "net/test/spawned_test_server/spawned_test_server.h"
rsleevia69c79a2016-06-22 03:28:4355#include "net/test/test_data_directory.h"
Gabriel Charettec7108742019-08-23 03:31:4056#include "net/test/test_with_task_environment.h"
rhalavati9ebaba7e2017-04-27 06:16:2957#include "net/traffic_annotation/network_traffic_annotation_test_helper.h"
Adam Rice5b4a3d82018-08-02 15:28:4358#include "net/url_request/url_request.h"
59#include "net/url_request/url_request_context.h"
ricea433bdab2015-01-26 07:25:3760#include "net/url_request/url_request_test_util.h"
Chris Thompsone3c3a3b02020-12-17 23:20:4061#include "net/url_request/websocket_handshake_userdata_key.h"
ricea433bdab2015-01-26 07:25:3762#include "net/websockets/websocket_channel.h"
63#include "net/websockets/websocket_event_interface.h"
Chris Thompsone3c3a3b02020-12-17 23:20:4064#include "net/websockets/websocket_test_util.h"
ricea433bdab2015-01-26 07:25:3765#include "testing/gtest/include/gtest/gtest.h"
Adam Rice5b4a3d82018-08-02 15:28:4366#include "url/gurl.h"
mkwst4997ce82015-07-25 12:00:0567#include "url/origin.h"
ricea433bdab2015-01-26 07:25:3768
69namespace net {
70
yhirano4a593832016-10-24 18:58:2271class URLRequest;
72
ricea433bdab2015-01-26 07:25:3773namespace {
74
Adam Rice5b4a3d82018-08-02 15:28:4375using test_server::BasicHttpResponse;
76using test_server::HttpRequest;
77using test_server::HttpResponse;
78
ricea433bdab2015-01-26 07:25:3779static const char kEchoServer[] = "echo-with-no-extension";
80
81// An implementation of WebSocketEventInterface that waits for and records the
82// results of the connect.
83class ConnectTestingEventInterface : public WebSocketEventInterface {
84 public:
85 ConnectTestingEventInterface();
86
87 void WaitForResponse();
88
89 bool failed() const { return failed_; }
90
91 // Only set if the handshake failed, otherwise empty.
92 std::string failure_message() const;
93
94 std::string selected_subprotocol() const;
95
96 std::string extensions() const;
97
98 // Implementation of WebSocketEventInterface.
yhirano4a593832016-10-24 18:58:2299 void OnCreateURLRequest(URLRequest* request) override {}
100
Yoichi Osato1ead61a2020-01-06 04:52:57101 void OnAddChannelResponse(
102 std::unique_ptr<WebSocketHandshakeResponseInfo> response,
103 const std::string& selected_subprotocol,
Adam Rice250bb012020-05-26 15:56:10104 const std::string& extensions) override;
ricea433bdab2015-01-26 07:25:37105
Yutaka Hirano4165de92018-04-10 11:46:49106 void OnDataFrame(bool fin,
107 WebSocketMessageType type,
Yutaka Hirano76aacb202019-09-05 16:36:56108 base::span<const char> payload) override;
ricea433bdab2015-01-26 07:25:37109
Yoichi Osatofcaa2a22019-08-28 08:22:36110 bool HasPendingDataFrames() override { return false; }
111
Adam Riced0095702020-05-26 06:18:25112 void OnSendDataFrameDone() override;
ricea433bdab2015-01-26 07:25:37113
Yutaka Hirano4165de92018-04-10 11:46:49114 void OnClosingHandshake() override;
ricea433bdab2015-01-26 07:25:37115
Yutaka Hirano4165de92018-04-10 11:46:49116 void OnDropChannel(bool was_clean,
117 uint16_t code,
118 const std::string& reason) override;
ricea433bdab2015-01-26 07:25:37119
Adam Langleya48b636a2020-11-12 23:42:52120 void OnFailChannel(const std::string& message,
121 int net_error,
Anton Bikineev068d2912021-05-15 20:43:52122 absl::optional<int> response_code) override;
ricea433bdab2015-01-26 07:25:37123
Yutaka Hirano4165de92018-04-10 11:46:49124 void OnStartOpeningHandshake(
danakj9c5cab52016-04-16 00:54:33125 std::unique_ptr<WebSocketHandshakeRequestInfo> request) override;
ricea433bdab2015-01-26 07:25:37126
Yutaka Hirano4165de92018-04-10 11:46:49127 void OnSSLCertificateError(
danakj9c5cab52016-04-16 00:54:33128 std::unique_ptr<SSLErrorCallbacks> ssl_error_callbacks,
ricea433bdab2015-01-26 07:25:37129 const GURL& url,
Emily Starkd9df3d32019-04-29 17:54:57130 int net_error,
ricea433bdab2015-01-26 07:25:37131 const SSLInfo& ssl_info,
132 bool fatal) override;
133
Emily Starkf2c9bbd2019-04-09 17:08:58134 int OnAuthRequired(const AuthChallengeInfo& auth_info,
Yutaka Hirano70fa25912018-06-06 05:26:54135 scoped_refptr<HttpResponseHeaders> response_headers,
Tsuyoshi Horo01faed62019-02-20 22:11:37136 const IPEndPoint& remote_endpoint,
Yutaka Hirano70fa25912018-06-06 05:26:54137 base::OnceCallback<void(const AuthCredentials*)> callback,
Anton Bikineev068d2912021-05-15 20:43:52138 absl::optional<AuthCredentials>* credentials) override;
Yutaka Hirano70fa25912018-06-06 05:26:54139
ricea433bdab2015-01-26 07:25:37140 private:
141 void QuitNestedEventLoop();
142
143 // failed_ is true if the handshake failed (ie. OnFailChannel was called).
144 bool failed_;
145 std::string selected_subprotocol_;
146 std::string extensions_;
147 std::string failure_message_;
148 base::RunLoop run_loop_;
149
150 DISALLOW_COPY_AND_ASSIGN(ConnectTestingEventInterface);
151};
152
tyoshinoc06da562015-03-06 06:02:42153ConnectTestingEventInterface::ConnectTestingEventInterface() : failed_(false) {
ricea433bdab2015-01-26 07:25:37154}
155
156void ConnectTestingEventInterface::WaitForResponse() {
157 run_loop_.Run();
158}
159
160std::string ConnectTestingEventInterface::failure_message() const {
161 return failure_message_;
162}
163
164std::string ConnectTestingEventInterface::selected_subprotocol() const {
165 return selected_subprotocol_;
166}
167
168std::string ConnectTestingEventInterface::extensions() const {
169 return extensions_;
170}
171
Yutaka Hirano4165de92018-04-10 11:46:49172void ConnectTestingEventInterface::OnAddChannelResponse(
Yoichi Osato1ead61a2020-01-06 04:52:57173 std::unique_ptr<WebSocketHandshakeResponseInfo> response,
ricea433bdab2015-01-26 07:25:37174 const std::string& selected_subprotocol,
Adam Rice250bb012020-05-26 15:56:10175 const std::string& extensions) {
ricea433bdab2015-01-26 07:25:37176 selected_subprotocol_ = selected_subprotocol;
177 extensions_ = extensions;
178 QuitNestedEventLoop();
ricea433bdab2015-01-26 07:25:37179}
180
Yutaka Hirano4165de92018-04-10 11:46:49181void ConnectTestingEventInterface::OnDataFrame(bool fin,
182 WebSocketMessageType type,
Yutaka Hirano76aacb202019-09-05 16:36:56183 base::span<const char> payload) {
184}
ricea433bdab2015-01-26 07:25:37185
Adam Riced0095702020-05-26 06:18:25186void ConnectTestingEventInterface::OnSendDataFrameDone() {}
ricea433bdab2015-01-26 07:25:37187
Yutaka Hirano4165de92018-04-10 11:46:49188void ConnectTestingEventInterface::OnClosingHandshake() {}
ricea433bdab2015-01-26 07:25:37189
Yutaka Hirano4165de92018-04-10 11:46:49190void ConnectTestingEventInterface::OnDropChannel(bool was_clean,
191 uint16_t code,
192 const std::string& reason) {}
ricea433bdab2015-01-26 07:25:37193
Adam Langleya48b636a2020-11-12 23:42:52194void ConnectTestingEventInterface::OnFailChannel(
195 const std::string& message,
196 int net_error,
Anton Bikineev068d2912021-05-15 20:43:52197 absl::optional<int> response_code) {
ricea433bdab2015-01-26 07:25:37198 failed_ = true;
199 failure_message_ = message;
200 QuitNestedEventLoop();
ricea433bdab2015-01-26 07:25:37201}
202
Yutaka Hirano4165de92018-04-10 11:46:49203void ConnectTestingEventInterface::OnStartOpeningHandshake(
204 std::unique_ptr<WebSocketHandshakeRequestInfo> request) {}
ricea433bdab2015-01-26 07:25:37205
Yutaka Hirano4165de92018-04-10 11:46:49206void ConnectTestingEventInterface::OnSSLCertificateError(
danakj9c5cab52016-04-16 00:54:33207 std::unique_ptr<SSLErrorCallbacks> ssl_error_callbacks,
ricea433bdab2015-01-26 07:25:37208 const GURL& url,
Emily Starkd9df3d32019-04-29 17:54:57209 int net_error,
ricea433bdab2015-01-26 07:25:37210 const SSLInfo& ssl_info,
211 bool fatal) {
skyostil4891b25b2015-06-11 11:43:45212 base::ThreadTaskRunnerHandle::Get()->PostTask(
kylecharf4fe5172019-02-15 18:53:49213 FROM_HERE, base::BindOnce(&SSLErrorCallbacks::CancelSSLRequest,
214 base::Owned(ssl_error_callbacks.release()),
215 ERR_SSL_PROTOCOL_ERROR, &ssl_info));
ricea433bdab2015-01-26 07:25:37216}
217
Yutaka Hirano70fa25912018-06-06 05:26:54218int ConnectTestingEventInterface::OnAuthRequired(
Emily Starkf2c9bbd2019-04-09 17:08:58219 const AuthChallengeInfo& auth_info,
Yutaka Hirano70fa25912018-06-06 05:26:54220 scoped_refptr<HttpResponseHeaders> response_headers,
Tsuyoshi Horo01faed62019-02-20 22:11:37221 const IPEndPoint& remote_endpoint,
Yutaka Hirano70fa25912018-06-06 05:26:54222 base::OnceCallback<void(const AuthCredentials*)> callback,
Anton Bikineev068d2912021-05-15 20:43:52223 absl::optional<AuthCredentials>* credentials) {
224 *credentials = absl::nullopt;
Yutaka Hirano70fa25912018-06-06 05:26:54225 return OK;
226}
227
ricea433bdab2015-01-26 07:25:37228void ConnectTestingEventInterface::QuitNestedEventLoop() {
229 run_loop_.Quit();
230}
231
232// A subclass of TestNetworkDelegate that additionally implements the
233// OnResolveProxy callback and records the information passed to it.
ryansturm7de050c2016-02-23 00:10:21234class TestProxyDelegateWithProxyInfo : public ProxyDelegate {
ricea433bdab2015-01-26 07:25:37235 public:
Chris Watkins28c2fdd2017-11-30 06:06:52236 TestProxyDelegateWithProxyInfo() = default;
ricea433bdab2015-01-26 07:25:37237
238 struct ResolvedProxyInfo {
239 GURL url;
240 ProxyInfo proxy_info;
241 };
242
243 const ResolvedProxyInfo& resolved_proxy_info() const {
244 return resolved_proxy_info_;
245 }
246
247 protected:
248 void OnResolveProxy(const GURL& url,
ryansturm4bab06832016-03-03 23:41:07249 const std::string& method,
Reilly Grantb414ace72017-11-14 23:03:22250 const ProxyRetryInfoMap& proxy_retry_info,
ricea433bdab2015-01-26 07:25:37251 ProxyInfo* result) override {
252 resolved_proxy_info_.url = url;
253 resolved_proxy_info_.proxy_info = *result;
254 }
255
ryansturm7de050c2016-02-23 00:10:21256 void OnFallback(const ProxyServer& bad_proxy, int net_error) override {}
ryansturm7de050c2016-02-23 00:10:21257
Robert Ogden78d4f9eb2020-03-17 20:56:38258 void OnBeforeTunnelRequest(const ProxyServer& proxy_server,
259 HttpRequestHeaders* extra_headers) override {}
Wojciech Dzierżanowski1f823562019-01-18 11:26:00260
Robert Ogden78d4f9eb2020-03-17 20:56:38261 Error OnTunnelHeadersReceived(
Wojciech Dzierżanowski1f823562019-01-18 11:26:00262 const ProxyServer& proxy_server,
263 const HttpResponseHeaders& response_headers) override {
264 return OK;
265 }
266
ricea433bdab2015-01-26 07:25:37267 private:
268 ResolvedProxyInfo resolved_proxy_info_;
269
ryansturm7de050c2016-02-23 00:10:21270 DISALLOW_COPY_AND_ASSIGN(TestProxyDelegateWithProxyInfo);
ricea433bdab2015-01-26 07:25:37271};
272
Gabriel Charette694c3c332019-08-19 14:53:05273class WebSocketEndToEndTest : public TestWithTaskEnvironment {
ricea433bdab2015-01-26 07:25:37274 protected:
275 WebSocketEndToEndTest()
Adam Ricecb76ac62015-02-20 05:33:25276 : event_interface_(),
Bence Béky65623972018-03-05 15:31:56277 proxy_delegate_(std::make_unique<TestProxyDelegateWithProxyInfo>()),
ricea433bdab2015-01-26 07:25:37278 context_(true),
Adam Ricecb76ac62015-02-20 05:33:25279 channel_(),
ricea433bdab2015-01-26 07:25:37280 initialised_context_(false) {}
281
282 // Initialise the URLRequestContext. Normally done automatically by
283 // ConnectAndWait(). This method is for the use of tests that need the
284 // URLRequestContext initialised before calling ConnectAndWait().
285 void InitialiseContext() {
ricea433bdab2015-01-26 07:25:37286 context_.Init();
Eric Roman3d8546a2018-09-10 17:00:52287 context_.proxy_resolution_service()->SetProxyDelegate(
288 proxy_delegate_.get());
ricea433bdab2015-01-26 07:25:37289 initialised_context_ = true;
290 }
291
292 // Send the connect request to |socket_url| and wait for a response. Returns
293 // true if the handshake succeeded.
294 bool ConnectAndWait(const GURL& socket_url) {
295 if (!initialised_context_) {
296 InitialiseContext();
297 }
Daniel Cheng88186bd52017-10-20 08:14:46298 url::Origin origin = url::Origin::Create(GURL("http://localhost"));
Maks Orlovich8be0e252019-12-09 18:35:49299 net::SiteForCookies site_for_cookies =
300 net::SiteForCookies::FromOrigin(origin);
shivanigithub4e78015f592020-10-21 13:26:23301 IsolationInfo isolation_info =
302 IsolationInfo::Create(IsolationInfo::RequestType::kOther, origin,
303 origin, SiteForCookies::FromOrigin(origin));
Adam Rice5b4a3d82018-08-02 15:28:43304 event_interface_ = new ConnectTestingEventInterface();
Bence Béky65623972018-03-05 15:31:56305 channel_ = std::make_unique<WebSocketChannel>(
306 base::WrapUnique(event_interface_), &context_);
Adam Langleyacbad242020-08-18 15:14:52307 channel_->SendAddChannelRequest(
308 GURL(socket_url), sub_protocols_, origin, site_for_cookies,
309 isolation_info, HttpRequestHeaders(), TRAFFIC_ANNOTATION_FOR_TESTS);
ricea433bdab2015-01-26 07:25:37310 event_interface_->WaitForResponse();
311 return !event_interface_->failed();
312 }
313
314 ConnectTestingEventInterface* event_interface_; // owned by channel_
danakj9c5cab52016-04-16 00:54:33315 std::unique_ptr<TestProxyDelegateWithProxyInfo> proxy_delegate_;
ricea433bdab2015-01-26 07:25:37316 TestURLRequestContext context_;
danakj9c5cab52016-04-16 00:54:33317 std::unique_ptr<WebSocketChannel> channel_;
ricea5acb1faf72015-03-16 15:34:00318 std::vector<std::string> sub_protocols_;
ricea433bdab2015-01-26 07:25:37319 bool initialised_context_;
320};
321
ricea433bdab2015-01-26 07:25:37322// Basic test of connectivity. If this test fails, nothing else can be expected
323// to work.
Sergey Ulanov4c786d32017-09-08 22:53:25324TEST_F(WebSocketEndToEndTest, BasicSmokeTest) {
ricea433bdab2015-01-26 07:25:37325 SpawnedTestServer ws_server(SpawnedTestServer::TYPE_WS,
ricea433bdab2015-01-26 07:25:37326 GetWebSocketTestDataDirectory());
327 ASSERT_TRUE(ws_server.Start());
328 EXPECT_TRUE(ConnectAndWait(ws_server.GetURL(kEchoServer)));
329}
330
331// Test for issue crbug.com/433695 "Unencrypted WebSocket connection via
332// authenticated proxy times out"
333// TODO(ricea): Enable this when the issue is fixed.
334TEST_F(WebSocketEndToEndTest, DISABLED_HttpsProxyUnauthedFails) {
335 SpawnedTestServer proxy_server(SpawnedTestServer::TYPE_BASIC_AUTH_PROXY,
ricea433bdab2015-01-26 07:25:37336 base::FilePath());
337 SpawnedTestServer ws_server(SpawnedTestServer::TYPE_WS,
ricea433bdab2015-01-26 07:25:37338 GetWebSocketTestDataDirectory());
339 ASSERT_TRUE(proxy_server.StartInBackground());
340 ASSERT_TRUE(ws_server.StartInBackground());
341 ASSERT_TRUE(proxy_server.BlockUntilStarted());
342 ASSERT_TRUE(ws_server.BlockUntilStarted());
343 std::string proxy_config =
344 "https=" + proxy_server.host_port_pair().ToString();
Nicolas Arciniega8ec5bfa2020-03-20 05:07:26345 std::unique_ptr<ProxyResolutionService> proxy_resolution_service(
Nicolas Arciniegad2013f92020-02-07 23:00:56346 ConfiguredProxyResolutionService::CreateFixed(
347 proxy_config, TRAFFIC_ANNOTATION_FOR_TESTS));
Lily Houghton8c2f97d2018-01-22 05:06:59348 ASSERT_TRUE(proxy_resolution_service);
349 context_.set_proxy_resolution_service(proxy_resolution_service.get());
ricea433bdab2015-01-26 07:25:37350 EXPECT_FALSE(ConnectAndWait(ws_server.GetURL(kEchoServer)));
351 EXPECT_EQ("Proxy authentication failed", event_interface_->failure_message());
352}
353
Sergey Ulanov4c786d32017-09-08 22:53:25354// These test are not compatible with RemoteTestServer because RemoteTestServer
355// doesn't support TYPE_BASIC_AUTH_PROXY.
356// TODO(ricea): Make these tests work. See crbug.com/441711.
357#if defined(OS_ANDROID) || defined(OS_FUCHSIA)
358#define MAYBE_HttpsWssProxyUnauthedFails DISABLED_HttpsWssProxyUnauthedFails
359#define MAYBE_HttpsProxyUsed DISABLED_HttpsProxyUsed
360#else
361#define MAYBE_HttpsWssProxyUnauthedFails HttpsWssProxyUnauthedFails
362#define MAYBE_HttpsProxyUsed HttpsProxyUsed
363#endif
364
365TEST_F(WebSocketEndToEndTest, MAYBE_HttpsWssProxyUnauthedFails) {
ricea433bdab2015-01-26 07:25:37366 SpawnedTestServer proxy_server(SpawnedTestServer::TYPE_BASIC_AUTH_PROXY,
ricea433bdab2015-01-26 07:25:37367 base::FilePath());
368 SpawnedTestServer wss_server(SpawnedTestServer::TYPE_WSS,
ricea433bdab2015-01-26 07:25:37369 GetWebSocketTestDataDirectory());
370 ASSERT_TRUE(proxy_server.StartInBackground());
371 ASSERT_TRUE(wss_server.StartInBackground());
372 ASSERT_TRUE(proxy_server.BlockUntilStarted());
373 ASSERT_TRUE(wss_server.BlockUntilStarted());
Eric Romanda790f92018-11-07 19:17:15374 ProxyConfig proxy_config;
375 proxy_config.proxy_rules().ParseFromString(
376 "https=" + proxy_server.host_port_pair().ToString());
377 // TODO(https://crbug.com/901896): Don't rely on proxying localhost.
378 proxy_config.proxy_rules().bypass_rules.AddRulesToSubtractImplicit();
379
Nicolas Arciniega8ec5bfa2020-03-20 05:07:26380 std::unique_ptr<ProxyResolutionService> proxy_resolution_service(
Nicolas Arciniegad2013f92020-02-07 23:00:56381 ConfiguredProxyResolutionService::CreateFixed(ProxyConfigWithAnnotation(
Eric Romanda790f92018-11-07 19:17:15382 proxy_config, TRAFFIC_ANNOTATION_FOR_TESTS)));
Lily Houghton8c2f97d2018-01-22 05:06:59383 ASSERT_TRUE(proxy_resolution_service);
384 context_.set_proxy_resolution_service(proxy_resolution_service.get());
ricea433bdab2015-01-26 07:25:37385 EXPECT_FALSE(ConnectAndWait(wss_server.GetURL(kEchoServer)));
386 EXPECT_EQ("Proxy authentication failed", event_interface_->failure_message());
387}
388
389// Regression test for crbug/426736 "WebSocket connections not using configured
390// system HTTPS Proxy".
Sergey Ulanov4c786d32017-09-08 22:53:25391TEST_F(WebSocketEndToEndTest, MAYBE_HttpsProxyUsed) {
Adam Rice5b4a3d82018-08-02 15:28:43392 SpawnedTestServer proxy_server(SpawnedTestServer::TYPE_PROXY,
ricea433bdab2015-01-26 07:25:37393 base::FilePath());
394 SpawnedTestServer ws_server(SpawnedTestServer::TYPE_WS,
ricea433bdab2015-01-26 07:25:37395 GetWebSocketTestDataDirectory());
396 ASSERT_TRUE(proxy_server.StartInBackground());
397 ASSERT_TRUE(ws_server.StartInBackground());
398 ASSERT_TRUE(proxy_server.BlockUntilStarted());
399 ASSERT_TRUE(ws_server.BlockUntilStarted());
Eric Romanda790f92018-11-07 19:17:15400 ProxyConfig proxy_config;
401 proxy_config.proxy_rules().ParseFromString(
402 "https=" + proxy_server.host_port_pair().ToString() + ";" +
403 "http=" + proxy_server.host_port_pair().ToString());
404 // TODO(https://crbug.com/901896): Don't rely on proxying localhost.
405 proxy_config.proxy_rules().bypass_rules.AddRulesToSubtractImplicit();
406
Nicolas Arciniega8ec5bfa2020-03-20 05:07:26407 std::unique_ptr<ProxyResolutionService> proxy_resolution_service(
Nicolas Arciniegad2013f92020-02-07 23:00:56408 ConfiguredProxyResolutionService::CreateFixed(ProxyConfigWithAnnotation(
Eric Romanda790f92018-11-07 19:17:15409 proxy_config, TRAFFIC_ANNOTATION_FOR_TESTS)));
Lily Houghton8c2f97d2018-01-22 05:06:59410 context_.set_proxy_resolution_service(proxy_resolution_service.get());
ricea433bdab2015-01-26 07:25:37411 InitialiseContext();
412
ricea433bdab2015-01-26 07:25:37413 GURL ws_url = ws_server.GetURL(kEchoServer);
414 EXPECT_TRUE(ConnectAndWait(ws_url));
ryansturm7de050c2016-02-23 00:10:21415 const TestProxyDelegateWithProxyInfo::ResolvedProxyInfo& info =
416 proxy_delegate_->resolved_proxy_info();
ricea433bdab2015-01-26 07:25:37417 EXPECT_EQ(ws_url, info.url);
418 EXPECT_TRUE(info.proxy_info.is_http());
419}
420
Adam Rice5b4a3d82018-08-02 15:28:43421std::unique_ptr<HttpResponse> ProxyPacHandler(const HttpRequest& request) {
422 GURL url = request.GetURL();
423 EXPECT_EQ(url.path_piece(), "/proxy.pac");
424 EXPECT_TRUE(url.has_query());
425 std::string proxy;
426 EXPECT_TRUE(GetValueForKeyInQuery(url, "proxy", &proxy));
427 auto response = std::make_unique<BasicHttpResponse>();
428 response->set_content_type("application/x-ns-proxy-autoconfig");
429 response->set_content(
430 base::StringPrintf("function FindProxyForURL(url, host) {\n"
431 " return 'PROXY %s';\n"
432 "}\n",
433 proxy.c_str()));
434 return response;
435}
436
437// This tests the proxy.pac resolver that is built into the system. This is not
438// the one that Chrome normally uses. Chrome's normal implementation is defined
439// as a mojo service. It is outside //net and we can't use it from here. This
440// tests the alternative implementations that are selected when the
441// --winhttp-proxy-resolver flag is provided to Chrome. These only exist on OS X
442// and Windows.
443// TODO(ricea): Remove this test if --winhttp-proxy-resolver flag is removed.
444// See crbug.com/644030.
445
Avi Drissman25292af62020-07-29 21:57:11446#if defined(OS_WIN) || defined(OS_APPLE)
Adam Rice5b4a3d82018-08-02 15:28:43447#define MAYBE_ProxyPacUsed ProxyPacUsed
448#else
449#define MAYBE_ProxyPacUsed DISABLED_ProxyPacUsed
450#endif
451
452TEST_F(WebSocketEndToEndTest, MAYBE_ProxyPacUsed) {
453 EmbeddedTestServer proxy_pac_server(net::EmbeddedTestServer::Type::TYPE_HTTP);
454 SpawnedTestServer proxy_server(SpawnedTestServer::TYPE_PROXY,
455 base::FilePath());
456 SpawnedTestServer ws_server(SpawnedTestServer::TYPE_WS,
457 GetWebSocketTestDataDirectory());
458 proxy_pac_server.RegisterRequestHandler(base::BindRepeating(ProxyPacHandler));
459 proxy_server.set_redirect_connect_to_localhost(true);
460
461 ASSERT_TRUE(proxy_pac_server.Start());
462 ASSERT_TRUE(proxy_server.StartInBackground());
463 ASSERT_TRUE(ws_server.StartInBackground());
464 ASSERT_TRUE(proxy_server.BlockUntilStarted());
465 ASSERT_TRUE(ws_server.BlockUntilStarted());
466
467 ProxyConfig proxy_config =
468 ProxyConfig::CreateFromCustomPacURL(proxy_pac_server.GetURL(base::StrCat(
469 {"/proxy.pac?proxy=", proxy_server.host_port_pair().ToString()})));
470 proxy_config.set_pac_mandatory(true);
471 auto proxy_config_service = std::make_unique<ProxyConfigServiceFixed>(
472 ProxyConfigWithAnnotation(proxy_config, TRAFFIC_ANNOTATION_FOR_TESTS));
Nicolas Arciniega8ec5bfa2020-03-20 05:07:26473 std::unique_ptr<ProxyResolutionService> proxy_resolution_service(
Nicolas Arciniegad2013f92020-02-07 23:00:56474 ConfiguredProxyResolutionService::CreateUsingSystemProxyResolver(
Eric Roman3be01ba2020-04-03 21:37:09475 std::move(proxy_config_service), NetLog::Get(),
476 /*quick_check_enabled=*/true));
Adam Rice5b4a3d82018-08-02 15:28:43477 ASSERT_EQ(ws_server.host_port_pair().host(), "127.0.0.1");
478 context_.set_proxy_resolution_service(proxy_resolution_service.get());
479 InitialiseContext();
480
Eric Romanda790f92018-11-07 19:17:15481 // Use a name other than localhost, since localhost implicitly bypasses the
482 // use of proxy.pac.
Adam Rice5b4a3d82018-08-02 15:28:43483 HostPortPair fake_ws_host_port_pair("stealth-localhost",
484 ws_server.host_port_pair().port());
485
486 GURL ws_url(base::StrCat(
487 {"ws://", fake_ws_host_port_pair.ToString(), "/", kEchoServer}));
488 EXPECT_TRUE(ConnectAndWait(ws_url));
489 const auto& info = proxy_delegate_->resolved_proxy_info();
490 EXPECT_EQ(ws_url, info.url);
491 EXPECT_TRUE(info.proxy_info.is_http());
492 EXPECT_EQ(info.proxy_info.ToPacString(),
493 base::StrCat({"PROXY ", proxy_server.host_port_pair().ToString()}));
494}
495
ricea23c3f942015-02-02 13:35:13496// This is a regression test for crbug.com/408061 Crash in
497// net::WebSocketBasicHandshakeStream::Upgrade.
Sergey Ulanov4c786d32017-09-08 22:53:25498TEST_F(WebSocketEndToEndTest, TruncatedResponse) {
ricea23c3f942015-02-02 13:35:13499 SpawnedTestServer ws_server(SpawnedTestServer::TYPE_WS,
ricea23c3f942015-02-02 13:35:13500 GetWebSocketTestDataDirectory());
501 ASSERT_TRUE(ws_server.Start());
502 InitialiseContext();
503
504 GURL ws_url = ws_server.GetURL("truncated-headers");
505 EXPECT_FALSE(ConnectAndWait(ws_url));
506}
507
ricea5acb1faf72015-03-16 15:34:00508// Regression test for crbug.com/180504 "WebSocket handshake fails when HTTP
509// headers have trailing LWS".
Sergey Ulanov4c786d32017-09-08 22:53:25510TEST_F(WebSocketEndToEndTest, TrailingWhitespace) {
ricea5acb1faf72015-03-16 15:34:00511 SpawnedTestServer ws_server(SpawnedTestServer::TYPE_WS,
ricea5acb1faf72015-03-16 15:34:00512 GetWebSocketTestDataDirectory());
513 ASSERT_TRUE(ws_server.Start());
514
515 GURL ws_url = ws_server.GetURL("trailing-whitespace");
516 sub_protocols_.push_back("sip");
517 EXPECT_TRUE(ConnectAndWait(ws_url));
518 EXPECT_EQ("sip", event_interface_->selected_subprotocol());
519}
520
riceae1d67672015-03-19 10:10:17521// This is a regression test for crbug.com/169448 "WebSockets should support
522// header continuations"
523// TODO(ricea): HTTP continuation headers have been deprecated by RFC7230. If
524// support for continuation headers is removed from Chrome, then this test will
525// break and should be removed.
Sergey Ulanov4c786d32017-09-08 22:53:25526TEST_F(WebSocketEndToEndTest, HeaderContinuations) {
riceae1d67672015-03-19 10:10:17527 SpawnedTestServer ws_server(SpawnedTestServer::TYPE_WS,
riceae1d67672015-03-19 10:10:17528 GetWebSocketTestDataDirectory());
529 ASSERT_TRUE(ws_server.Start());
530
531 GURL ws_url = ws_server.GetURL("header-continuation");
532
533 EXPECT_TRUE(ConnectAndWait(ws_url));
534 EXPECT_EQ("permessage-deflate; server_max_window_bits=10",
535 event_interface_->extensions());
536}
537
Chris Thompsone3c3a3b02020-12-17 23:20:40538// These are not true end-to-end tests as the SpawnedTestServer doesn't
539// support TLS 1.2.
540// TODO(ricea): Make these be true end-to-end tests again when
541// SpawnedTestServer supports TLS 1.2 or EmbeddedTestServer supports
542// WebSockets.
543class WebSocketHstsTest : public TestWithTaskEnvironment {
544 protected:
545 WebSocketHstsTest() : context_(true) {
546 context_.set_client_socket_factory(&socket_factory_);
547 context_.Init();
548 }
549
550 void MakeHttpConnection(const GURL& url) {
551 // Set up SSL details, because otherwise HSTS headers aren't processed.
552 SSLSocketDataProvider ssl_socket_data(net::ASYNC, net::OK);
553 ssl_socket_data.ssl_info.cert =
554 ImportCertFromFile(GetTestCertsDirectory(), "ok_cert.pem");
555 ssl_socket_data.ssl_info.is_issued_by_known_root = true;
556 ssl_socket_data.ssl_info.ct_policy_compliance =
557 ct::CTPolicyCompliance::CT_POLICY_COMPLIES_VIA_SCTS;
558 ssl_socket_data.ssl_info.cert_status = 0;
559 socket_factory_.AddSSLSocketDataProvider(&ssl_socket_data);
560
561 req_ = context_.CreateRequest(url, DEFAULT_PRIORITY, &delegate_,
562 TRAFFIC_ANNOTATION_FOR_TESTS);
563
564 MockWrite writes[] = {
565 MockWrite("GET / HTTP/1.1\r\n"
566 "Host: www.example.org\r\n"
567 "Connection: keep-alive\r\n"
568 "User-Agent: \r\n"
569 "Accept-Encoding: gzip, deflate\r\n"
570 "Accept-Language: en-us,fr\r\n\r\n")};
571 MockRead reads[] = {MockRead("HTTP/1.1 200 OK\r\n"
572 "Strict-Transport-Security: max-age=123; "
573 "includeSubdomains\r\n\r\n"),
574 MockRead(ASYNC, 0)};
575
576 StaticSocketDataProvider data(reads, writes);
577 socket_factory_.AddSocketDataProvider(&data);
578
579 req_->Start();
580 base::RunLoop().RunUntilIdle();
581 }
582
583 void MakeWebsocketConnection(const GURL& url) {
584 // Set up SSL details, because otherwise HSTS headers aren't processed.
585 SSLSocketDataProvider ssl_socket_data(net::ASYNC, net::OK);
586 ssl_socket_data.ssl_info.cert =
587 ImportCertFromFile(GetTestCertsDirectory(), "ok_cert.pem");
588 ssl_socket_data.ssl_info.is_issued_by_known_root = true;
589 ssl_socket_data.ssl_info.ct_policy_compliance =
590 ct::CTPolicyCompliance::CT_POLICY_COMPLIES_VIA_SCTS;
591 ssl_socket_data.ssl_info.cert_status = 0;
592 socket_factory_.AddSSLSocketDataProvider(&ssl_socket_data);
593
594 req_ = context_.CreateRequest(url, DEFAULT_PRIORITY, &delegate_,
595 TRAFFIC_ANNOTATION_FOR_TESTS);
596
597 HttpRequestHeaders headers;
598 headers.SetHeader("Connection", "Upgrade");
599 headers.SetHeader("Upgrade", "websocket");
600 headers.SetHeader("Origin", "null");
601 headers.SetHeader("Sec-WebSocket-Version", "13");
602 req_->SetExtraRequestHeaders(headers);
603
604 MockWrite writes[] = {
605 MockWrite("GET / HTTP/1.1\r\n"
606 "Host: www.example.org\r\n"
607 "Connection: Upgrade\r\n"
608 "Upgrade: websocket\r\n"
609 "Origin: null\r\n"
610 "Sec-WebSocket-Version: 13\r\n"
611 "User-Agent: \r\n"
612 "Accept-Encoding: gzip, deflate\r\n"
613 "Accept-Language: en-us,fr\r\n"
614 "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n"
615 "Sec-WebSocket-Extensions: permessage-deflate; "
616 "client_max_window_bits\r\n\r\n")};
617 MockRead reads[] = {
618 MockRead("HTTP/1.1 101 Switching Protocols\r\n"
619 "Upgrade: websocket\r\n"
620 "Connection: Upgrade\r\n"
621 "Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\r\n"
622 "Strict-Transport-Security: max-age=123; "
623 "includeSubdomains\r\n\r\n"),
624 MockRead(ASYNC, 0)};
625
626 StaticSocketDataProvider data(reads, writes);
627 socket_factory_.AddSocketDataProvider(&data);
628
629 req_->SetUserData(
630 kWebSocketHandshakeUserDataKey,
631 std::make_unique<TestWebSocketHandshakeStreamCreateHelper>());
632 req_->SetLoadFlags(LOAD_DISABLE_CACHE);
633 req_->Start();
634 base::RunLoop().RunUntilIdle();
635 }
636
637 TestURLRequestContext context_;
638 MockClientSocketFactory socket_factory_;
639 TestDelegate delegate_;
640 std::unique_ptr<URLRequest> req_;
641};
642
643// Regression test for crbug.com/455215 "HSTS not applied to WebSocket"
644TEST_F(WebSocketHstsTest, HTTPSToWebSocket) {
645 // Set HSTS via https:
646 MakeHttpConnection(GURL("https://www.example.org"));
647 EXPECT_EQ(OK, delegate_.request_status());
648
649 ASSERT_TRUE(context_.transport_security_state()->ShouldUpgradeToSSL(
650 "www.example.org"));
651
652 // Check HSTS by starting a request over ws: and verifying that it gets
653 // ugpraded to wss:.
654 MakeWebsocketConnection(GURL("ws://www.example.org"));
655 EXPECT_EQ(OK, delegate_.request_status());
656 EXPECT_TRUE(delegate_.response_completed());
657 EXPECT_TRUE(req_->url().SchemeIs("wss"));
658}
659
660TEST_F(WebSocketHstsTest, WebSocketToHTTP) {
661 // Set HSTS via wss:
662 MakeWebsocketConnection(GURL("wss://www.example.org"));
663 EXPECT_EQ(OK, delegate_.request_status());
664 EXPECT_TRUE(delegate_.response_completed());
665
666 ASSERT_TRUE(context_.transport_security_state()->ShouldUpgradeToSSL(
667 "www.example.org"));
668
669 // Check HSTS by starting a request over http: and verifying that it gets
670 // ugpraded to https:.
671 MakeHttpConnection(GURL("http://www.example.org"));
672 EXPECT_EQ(OK, delegate_.request_status());
673 EXPECT_TRUE(req_->url().SchemeIs("https"));
674}
675
676TEST_F(WebSocketHstsTest, WebSocketToWebSocket) {
677 // Set HSTS via wss:
678 MakeWebsocketConnection(GURL("wss://www.example.org"));
679 EXPECT_EQ(OK, delegate_.request_status());
680 EXPECT_TRUE(delegate_.response_completed());
681
682 ASSERT_TRUE(context_.transport_security_state()->ShouldUpgradeToSSL(
683 "www.example.org"));
684
685 // Check HSTS by starting a request over ws: and verifying that it gets
686 // ugpraded to wss:.
687 MakeWebsocketConnection(GURL("ws://www.example.org"));
688 EXPECT_EQ(OK, delegate_.request_status());
689 EXPECT_TRUE(delegate_.response_completed());
690 EXPECT_TRUE(req_->url().SchemeIs("wss"));
691}
692
ricea433bdab2015-01-26 07:25:37693} // namespace
694
695} // namespace net