blob: 79b58de036796acab9e4ef880d034c5733fc8981 [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"
Adam Rice5b4a3d82018-08-02 15:28:4341#include "net/log/net_log.h"
Nicolas Arciniegad2013f92020-02-07 23:00:5642#include "net/proxy_resolution/configured_proxy_resolution_service.h"
Adam Rice5b4a3d82018-08-02 15:28:4343#include "net/proxy_resolution/proxy_config.h"
44#include "net/proxy_resolution/proxy_config_service.h"
45#include "net/proxy_resolution/proxy_config_service_fixed.h"
46#include "net/proxy_resolution/proxy_config_with_annotation.h"
47#include "net/proxy_resolution/proxy_info.h"
Chris Thompsone3c3a3b02020-12-17 23:20:4048#include "net/socket/socket_test_util.h"
49#include "net/test/cert_test_util.h"
tommycli59a63432015-11-06 00:10:5550#include "net/test/embedded_test_server/embedded_test_server.h"
Adam Rice5b4a3d82018-08-02 15:28:4351#include "net/test/embedded_test_server/http_request.h"
52#include "net/test/embedded_test_server/http_response.h"
ricea433bdab2015-01-26 07:25:3753#include "net/test/spawned_test_server/spawned_test_server.h"
rsleevia69c79a2016-06-22 03:28:4354#include "net/test/test_data_directory.h"
Gabriel Charettec7108742019-08-23 03:31:4055#include "net/test/test_with_task_environment.h"
rhalavati9ebaba7e2017-04-27 06:16:2956#include "net/traffic_annotation/network_traffic_annotation_test_helper.h"
Adam Rice5b4a3d82018-08-02 15:28:4357#include "net/url_request/url_request.h"
58#include "net/url_request/url_request_context.h"
ricea433bdab2015-01-26 07:25:3759#include "net/url_request/url_request_test_util.h"
Chris Thompsone3c3a3b02020-12-17 23:20:4060#include "net/url_request/websocket_handshake_userdata_key.h"
ricea433bdab2015-01-26 07:25:3761#include "net/websockets/websocket_channel.h"
62#include "net/websockets/websocket_event_interface.h"
Chris Thompsone3c3a3b02020-12-17 23:20:4063#include "net/websockets/websocket_test_util.h"
ricea433bdab2015-01-26 07:25:3764#include "testing/gtest/include/gtest/gtest.h"
Adam Rice5b4a3d82018-08-02 15:28:4365#include "url/gurl.h"
mkwst4997ce82015-07-25 12:00:0566#include "url/origin.h"
ricea433bdab2015-01-26 07:25:3767
68namespace net {
69
yhirano4a593832016-10-24 18:58:2270class URLRequest;
71
ricea433bdab2015-01-26 07:25:3772namespace {
73
Adam Rice5b4a3d82018-08-02 15:28:4374using test_server::BasicHttpResponse;
75using test_server::HttpRequest;
76using test_server::HttpResponse;
77
ricea433bdab2015-01-26 07:25:3778static const char kEchoServer[] = "echo-with-no-extension";
79
80// An implementation of WebSocketEventInterface that waits for and records the
81// results of the connect.
82class ConnectTestingEventInterface : public WebSocketEventInterface {
83 public:
84 ConnectTestingEventInterface();
85
86 void WaitForResponse();
87
88 bool failed() const { return failed_; }
89
90 // Only set if the handshake failed, otherwise empty.
91 std::string failure_message() const;
92
93 std::string selected_subprotocol() const;
94
95 std::string extensions() const;
96
97 // Implementation of WebSocketEventInterface.
yhirano4a593832016-10-24 18:58:2298 void OnCreateURLRequest(URLRequest* request) override {}
99
Yoichi Osato1ead61a2020-01-06 04:52:57100 void OnAddChannelResponse(
101 std::unique_ptr<WebSocketHandshakeResponseInfo> response,
102 const std::string& selected_subprotocol,
Adam Rice250bb012020-05-26 15:56:10103 const std::string& extensions) override;
ricea433bdab2015-01-26 07:25:37104
Yutaka Hirano4165de92018-04-10 11:46:49105 void OnDataFrame(bool fin,
106 WebSocketMessageType type,
Yutaka Hirano76aacb202019-09-05 16:36:56107 base::span<const char> payload) override;
ricea433bdab2015-01-26 07:25:37108
Yoichi Osatofcaa2a22019-08-28 08:22:36109 bool HasPendingDataFrames() override { return false; }
110
Adam Riced0095702020-05-26 06:18:25111 void OnSendDataFrameDone() override;
ricea433bdab2015-01-26 07:25:37112
Yutaka Hirano4165de92018-04-10 11:46:49113 void OnClosingHandshake() override;
ricea433bdab2015-01-26 07:25:37114
Yutaka Hirano4165de92018-04-10 11:46:49115 void OnDropChannel(bool was_clean,
116 uint16_t code,
117 const std::string& reason) override;
ricea433bdab2015-01-26 07:25:37118
Adam Langleya48b636a2020-11-12 23:42:52119 void OnFailChannel(const std::string& message,
120 int net_error,
121 base::Optional<int> response_code) override;
ricea433bdab2015-01-26 07:25:37122
Yutaka Hirano4165de92018-04-10 11:46:49123 void OnStartOpeningHandshake(
danakj9c5cab52016-04-16 00:54:33124 std::unique_ptr<WebSocketHandshakeRequestInfo> request) override;
ricea433bdab2015-01-26 07:25:37125
Yutaka Hirano4165de92018-04-10 11:46:49126 void OnSSLCertificateError(
danakj9c5cab52016-04-16 00:54:33127 std::unique_ptr<SSLErrorCallbacks> ssl_error_callbacks,
ricea433bdab2015-01-26 07:25:37128 const GURL& url,
Emily Starkd9df3d32019-04-29 17:54:57129 int net_error,
ricea433bdab2015-01-26 07:25:37130 const SSLInfo& ssl_info,
131 bool fatal) override;
132
Emily Starkf2c9bbd2019-04-09 17:08:58133 int OnAuthRequired(const AuthChallengeInfo& auth_info,
Yutaka Hirano70fa25912018-06-06 05:26:54134 scoped_refptr<HttpResponseHeaders> response_headers,
Tsuyoshi Horo01faed62019-02-20 22:11:37135 const IPEndPoint& remote_endpoint,
Yutaka Hirano70fa25912018-06-06 05:26:54136 base::OnceCallback<void(const AuthCredentials*)> callback,
137 base::Optional<AuthCredentials>* credentials) override;
138
ricea433bdab2015-01-26 07:25:37139 private:
140 void QuitNestedEventLoop();
141
142 // failed_ is true if the handshake failed (ie. OnFailChannel was called).
143 bool failed_;
144 std::string selected_subprotocol_;
145 std::string extensions_;
146 std::string failure_message_;
147 base::RunLoop run_loop_;
148
149 DISALLOW_COPY_AND_ASSIGN(ConnectTestingEventInterface);
150};
151
tyoshinoc06da562015-03-06 06:02:42152ConnectTestingEventInterface::ConnectTestingEventInterface() : failed_(false) {
ricea433bdab2015-01-26 07:25:37153}
154
155void ConnectTestingEventInterface::WaitForResponse() {
156 run_loop_.Run();
157}
158
159std::string ConnectTestingEventInterface::failure_message() const {
160 return failure_message_;
161}
162
163std::string ConnectTestingEventInterface::selected_subprotocol() const {
164 return selected_subprotocol_;
165}
166
167std::string ConnectTestingEventInterface::extensions() const {
168 return extensions_;
169}
170
Yutaka Hirano4165de92018-04-10 11:46:49171void ConnectTestingEventInterface::OnAddChannelResponse(
Yoichi Osato1ead61a2020-01-06 04:52:57172 std::unique_ptr<WebSocketHandshakeResponseInfo> response,
ricea433bdab2015-01-26 07:25:37173 const std::string& selected_subprotocol,
Adam Rice250bb012020-05-26 15:56:10174 const std::string& extensions) {
ricea433bdab2015-01-26 07:25:37175 selected_subprotocol_ = selected_subprotocol;
176 extensions_ = extensions;
177 QuitNestedEventLoop();
ricea433bdab2015-01-26 07:25:37178}
179
Yutaka Hirano4165de92018-04-10 11:46:49180void ConnectTestingEventInterface::OnDataFrame(bool fin,
181 WebSocketMessageType type,
Yutaka Hirano76aacb202019-09-05 16:36:56182 base::span<const char> payload) {
183}
ricea433bdab2015-01-26 07:25:37184
Adam Riced0095702020-05-26 06:18:25185void ConnectTestingEventInterface::OnSendDataFrameDone() {}
ricea433bdab2015-01-26 07:25:37186
Yutaka Hirano4165de92018-04-10 11:46:49187void ConnectTestingEventInterface::OnClosingHandshake() {}
ricea433bdab2015-01-26 07:25:37188
Yutaka Hirano4165de92018-04-10 11:46:49189void ConnectTestingEventInterface::OnDropChannel(bool was_clean,
190 uint16_t code,
191 const std::string& reason) {}
ricea433bdab2015-01-26 07:25:37192
Adam Langleya48b636a2020-11-12 23:42:52193void ConnectTestingEventInterface::OnFailChannel(
194 const std::string& message,
195 int net_error,
196 base::Optional<int> response_code) {
ricea433bdab2015-01-26 07:25:37197 failed_ = true;
198 failure_message_ = message;
199 QuitNestedEventLoop();
ricea433bdab2015-01-26 07:25:37200}
201
Yutaka Hirano4165de92018-04-10 11:46:49202void ConnectTestingEventInterface::OnStartOpeningHandshake(
203 std::unique_ptr<WebSocketHandshakeRequestInfo> request) {}
ricea433bdab2015-01-26 07:25:37204
Yutaka Hirano4165de92018-04-10 11:46:49205void ConnectTestingEventInterface::OnSSLCertificateError(
danakj9c5cab52016-04-16 00:54:33206 std::unique_ptr<SSLErrorCallbacks> ssl_error_callbacks,
ricea433bdab2015-01-26 07:25:37207 const GURL& url,
Emily Starkd9df3d32019-04-29 17:54:57208 int net_error,
ricea433bdab2015-01-26 07:25:37209 const SSLInfo& ssl_info,
210 bool fatal) {
skyostil4891b25b2015-06-11 11:43:45211 base::ThreadTaskRunnerHandle::Get()->PostTask(
kylecharf4fe5172019-02-15 18:53:49212 FROM_HERE, base::BindOnce(&SSLErrorCallbacks::CancelSSLRequest,
213 base::Owned(ssl_error_callbacks.release()),
214 ERR_SSL_PROTOCOL_ERROR, &ssl_info));
ricea433bdab2015-01-26 07:25:37215}
216
Yutaka Hirano70fa25912018-06-06 05:26:54217int ConnectTestingEventInterface::OnAuthRequired(
Emily Starkf2c9bbd2019-04-09 17:08:58218 const AuthChallengeInfo& auth_info,
Yutaka Hirano70fa25912018-06-06 05:26:54219 scoped_refptr<HttpResponseHeaders> response_headers,
Tsuyoshi Horo01faed62019-02-20 22:11:37220 const IPEndPoint& remote_endpoint,
Yutaka Hirano70fa25912018-06-06 05:26:54221 base::OnceCallback<void(const AuthCredentials*)> callback,
222 base::Optional<AuthCredentials>* credentials) {
223 *credentials = base::nullopt;
224 return OK;
225}
226
ricea433bdab2015-01-26 07:25:37227void ConnectTestingEventInterface::QuitNestedEventLoop() {
228 run_loop_.Quit();
229}
230
231// A subclass of TestNetworkDelegate that additionally implements the
232// OnResolveProxy callback and records the information passed to it.
ryansturm7de050c2016-02-23 00:10:21233class TestProxyDelegateWithProxyInfo : public ProxyDelegate {
ricea433bdab2015-01-26 07:25:37234 public:
Chris Watkins28c2fdd2017-11-30 06:06:52235 TestProxyDelegateWithProxyInfo() = default;
ricea433bdab2015-01-26 07:25:37236
237 struct ResolvedProxyInfo {
238 GURL url;
239 ProxyInfo proxy_info;
240 };
241
242 const ResolvedProxyInfo& resolved_proxy_info() const {
243 return resolved_proxy_info_;
244 }
245
246 protected:
247 void OnResolveProxy(const GURL& url,
ryansturm4bab06832016-03-03 23:41:07248 const std::string& method,
Reilly Grantb414ace72017-11-14 23:03:22249 const ProxyRetryInfoMap& proxy_retry_info,
ricea433bdab2015-01-26 07:25:37250 ProxyInfo* result) override {
251 resolved_proxy_info_.url = url;
252 resolved_proxy_info_.proxy_info = *result;
253 }
254
ryansturm7de050c2016-02-23 00:10:21255 void OnFallback(const ProxyServer& bad_proxy, int net_error) override {}
ryansturm7de050c2016-02-23 00:10:21256
Robert Ogden78d4f9eb2020-03-17 20:56:38257 void OnBeforeTunnelRequest(const ProxyServer& proxy_server,
258 HttpRequestHeaders* extra_headers) override {}
Wojciech Dzierżanowski1f823562019-01-18 11:26:00259
Robert Ogden78d4f9eb2020-03-17 20:56:38260 Error OnTunnelHeadersReceived(
Wojciech Dzierżanowski1f823562019-01-18 11:26:00261 const ProxyServer& proxy_server,
262 const HttpResponseHeaders& response_headers) override {
263 return OK;
264 }
265
ricea433bdab2015-01-26 07:25:37266 private:
267 ResolvedProxyInfo resolved_proxy_info_;
268
ryansturm7de050c2016-02-23 00:10:21269 DISALLOW_COPY_AND_ASSIGN(TestProxyDelegateWithProxyInfo);
ricea433bdab2015-01-26 07:25:37270};
271
Gabriel Charette694c3c332019-08-19 14:53:05272class WebSocketEndToEndTest : public TestWithTaskEnvironment {
ricea433bdab2015-01-26 07:25:37273 protected:
274 WebSocketEndToEndTest()
Adam Ricecb76ac62015-02-20 05:33:25275 : event_interface_(),
Bence Béky65623972018-03-05 15:31:56276 proxy_delegate_(std::make_unique<TestProxyDelegateWithProxyInfo>()),
ricea433bdab2015-01-26 07:25:37277 context_(true),
Adam Ricecb76ac62015-02-20 05:33:25278 channel_(),
ricea433bdab2015-01-26 07:25:37279 initialised_context_(false) {}
280
281 // Initialise the URLRequestContext. Normally done automatically by
282 // ConnectAndWait(). This method is for the use of tests that need the
283 // URLRequestContext initialised before calling ConnectAndWait().
284 void InitialiseContext() {
ricea433bdab2015-01-26 07:25:37285 context_.Init();
Eric Roman3d8546a2018-09-10 17:00:52286 context_.proxy_resolution_service()->SetProxyDelegate(
287 proxy_delegate_.get());
ricea433bdab2015-01-26 07:25:37288 initialised_context_ = true;
289 }
290
291 // Send the connect request to |socket_url| and wait for a response. Returns
292 // true if the handshake succeeded.
293 bool ConnectAndWait(const GURL& socket_url) {
294 if (!initialised_context_) {
295 InitialiseContext();
296 }
Daniel Cheng88186bd52017-10-20 08:14:46297 url::Origin origin = url::Origin::Create(GURL("http://localhost"));
Maks Orlovich8be0e252019-12-09 18:35:49298 net::SiteForCookies site_for_cookies =
299 net::SiteForCookies::FromOrigin(origin);
shivanigithub4e78015f592020-10-21 13:26:23300 IsolationInfo isolation_info =
301 IsolationInfo::Create(IsolationInfo::RequestType::kOther, origin,
302 origin, SiteForCookies::FromOrigin(origin));
Adam Rice5b4a3d82018-08-02 15:28:43303 event_interface_ = new ConnectTestingEventInterface();
Bence Béky65623972018-03-05 15:31:56304 channel_ = std::make_unique<WebSocketChannel>(
305 base::WrapUnique(event_interface_), &context_);
Adam Langleyacbad242020-08-18 15:14:52306 channel_->SendAddChannelRequest(
307 GURL(socket_url), sub_protocols_, origin, site_for_cookies,
308 isolation_info, HttpRequestHeaders(), TRAFFIC_ANNOTATION_FOR_TESTS);
ricea433bdab2015-01-26 07:25:37309 event_interface_->WaitForResponse();
310 return !event_interface_->failed();
311 }
312
313 ConnectTestingEventInterface* event_interface_; // owned by channel_
danakj9c5cab52016-04-16 00:54:33314 std::unique_ptr<TestProxyDelegateWithProxyInfo> proxy_delegate_;
ricea433bdab2015-01-26 07:25:37315 TestURLRequestContext context_;
danakj9c5cab52016-04-16 00:54:33316 std::unique_ptr<WebSocketChannel> channel_;
ricea5acb1faf72015-03-16 15:34:00317 std::vector<std::string> sub_protocols_;
ricea433bdab2015-01-26 07:25:37318 bool initialised_context_;
319};
320
ricea433bdab2015-01-26 07:25:37321// Basic test of connectivity. If this test fails, nothing else can be expected
322// to work.
Sergey Ulanov4c786d32017-09-08 22:53:25323TEST_F(WebSocketEndToEndTest, BasicSmokeTest) {
ricea433bdab2015-01-26 07:25:37324 SpawnedTestServer ws_server(SpawnedTestServer::TYPE_WS,
ricea433bdab2015-01-26 07:25:37325 GetWebSocketTestDataDirectory());
326 ASSERT_TRUE(ws_server.Start());
327 EXPECT_TRUE(ConnectAndWait(ws_server.GetURL(kEchoServer)));
328}
329
330// Test for issue crbug.com/433695 "Unencrypted WebSocket connection via
331// authenticated proxy times out"
332// TODO(ricea): Enable this when the issue is fixed.
333TEST_F(WebSocketEndToEndTest, DISABLED_HttpsProxyUnauthedFails) {
334 SpawnedTestServer proxy_server(SpawnedTestServer::TYPE_BASIC_AUTH_PROXY,
ricea433bdab2015-01-26 07:25:37335 base::FilePath());
336 SpawnedTestServer ws_server(SpawnedTestServer::TYPE_WS,
ricea433bdab2015-01-26 07:25:37337 GetWebSocketTestDataDirectory());
338 ASSERT_TRUE(proxy_server.StartInBackground());
339 ASSERT_TRUE(ws_server.StartInBackground());
340 ASSERT_TRUE(proxy_server.BlockUntilStarted());
341 ASSERT_TRUE(ws_server.BlockUntilStarted());
342 std::string proxy_config =
343 "https=" + proxy_server.host_port_pair().ToString();
Nicolas Arciniega8ec5bfa2020-03-20 05:07:26344 std::unique_ptr<ProxyResolutionService> proxy_resolution_service(
Nicolas Arciniegad2013f92020-02-07 23:00:56345 ConfiguredProxyResolutionService::CreateFixed(
346 proxy_config, TRAFFIC_ANNOTATION_FOR_TESTS));
Lily Houghton8c2f97d2018-01-22 05:06:59347 ASSERT_TRUE(proxy_resolution_service);
348 context_.set_proxy_resolution_service(proxy_resolution_service.get());
ricea433bdab2015-01-26 07:25:37349 EXPECT_FALSE(ConnectAndWait(ws_server.GetURL(kEchoServer)));
350 EXPECT_EQ("Proxy authentication failed", event_interface_->failure_message());
351}
352
Sergey Ulanov4c786d32017-09-08 22:53:25353// These test are not compatible with RemoteTestServer because RemoteTestServer
354// doesn't support TYPE_BASIC_AUTH_PROXY.
355// TODO(ricea): Make these tests work. See crbug.com/441711.
356#if defined(OS_ANDROID) || defined(OS_FUCHSIA)
357#define MAYBE_HttpsWssProxyUnauthedFails DISABLED_HttpsWssProxyUnauthedFails
358#define MAYBE_HttpsProxyUsed DISABLED_HttpsProxyUsed
359#else
360#define MAYBE_HttpsWssProxyUnauthedFails HttpsWssProxyUnauthedFails
361#define MAYBE_HttpsProxyUsed HttpsProxyUsed
362#endif
363
364TEST_F(WebSocketEndToEndTest, MAYBE_HttpsWssProxyUnauthedFails) {
ricea433bdab2015-01-26 07:25:37365 SpawnedTestServer proxy_server(SpawnedTestServer::TYPE_BASIC_AUTH_PROXY,
ricea433bdab2015-01-26 07:25:37366 base::FilePath());
367 SpawnedTestServer wss_server(SpawnedTestServer::TYPE_WSS,
ricea433bdab2015-01-26 07:25:37368 GetWebSocketTestDataDirectory());
369 ASSERT_TRUE(proxy_server.StartInBackground());
370 ASSERT_TRUE(wss_server.StartInBackground());
371 ASSERT_TRUE(proxy_server.BlockUntilStarted());
372 ASSERT_TRUE(wss_server.BlockUntilStarted());
Eric Romanda790f92018-11-07 19:17:15373 ProxyConfig proxy_config;
374 proxy_config.proxy_rules().ParseFromString(
375 "https=" + proxy_server.host_port_pair().ToString());
376 // TODO(https://crbug.com/901896): Don't rely on proxying localhost.
377 proxy_config.proxy_rules().bypass_rules.AddRulesToSubtractImplicit();
378
Nicolas Arciniega8ec5bfa2020-03-20 05:07:26379 std::unique_ptr<ProxyResolutionService> proxy_resolution_service(
Nicolas Arciniegad2013f92020-02-07 23:00:56380 ConfiguredProxyResolutionService::CreateFixed(ProxyConfigWithAnnotation(
Eric Romanda790f92018-11-07 19:17:15381 proxy_config, TRAFFIC_ANNOTATION_FOR_TESTS)));
Lily Houghton8c2f97d2018-01-22 05:06:59382 ASSERT_TRUE(proxy_resolution_service);
383 context_.set_proxy_resolution_service(proxy_resolution_service.get());
ricea433bdab2015-01-26 07:25:37384 EXPECT_FALSE(ConnectAndWait(wss_server.GetURL(kEchoServer)));
385 EXPECT_EQ("Proxy authentication failed", event_interface_->failure_message());
386}
387
388// Regression test for crbug/426736 "WebSocket connections not using configured
389// system HTTPS Proxy".
Sergey Ulanov4c786d32017-09-08 22:53:25390TEST_F(WebSocketEndToEndTest, MAYBE_HttpsProxyUsed) {
Adam Rice5b4a3d82018-08-02 15:28:43391 SpawnedTestServer proxy_server(SpawnedTestServer::TYPE_PROXY,
ricea433bdab2015-01-26 07:25:37392 base::FilePath());
393 SpawnedTestServer ws_server(SpawnedTestServer::TYPE_WS,
ricea433bdab2015-01-26 07:25:37394 GetWebSocketTestDataDirectory());
395 ASSERT_TRUE(proxy_server.StartInBackground());
396 ASSERT_TRUE(ws_server.StartInBackground());
397 ASSERT_TRUE(proxy_server.BlockUntilStarted());
398 ASSERT_TRUE(ws_server.BlockUntilStarted());
Eric Romanda790f92018-11-07 19:17:15399 ProxyConfig proxy_config;
400 proxy_config.proxy_rules().ParseFromString(
401 "https=" + proxy_server.host_port_pair().ToString() + ";" +
402 "http=" + proxy_server.host_port_pair().ToString());
403 // TODO(https://crbug.com/901896): Don't rely on proxying localhost.
404 proxy_config.proxy_rules().bypass_rules.AddRulesToSubtractImplicit();
405
Nicolas Arciniega8ec5bfa2020-03-20 05:07:26406 std::unique_ptr<ProxyResolutionService> proxy_resolution_service(
Nicolas Arciniegad2013f92020-02-07 23:00:56407 ConfiguredProxyResolutionService::CreateFixed(ProxyConfigWithAnnotation(
Eric Romanda790f92018-11-07 19:17:15408 proxy_config, TRAFFIC_ANNOTATION_FOR_TESTS)));
Lily Houghton8c2f97d2018-01-22 05:06:59409 context_.set_proxy_resolution_service(proxy_resolution_service.get());
ricea433bdab2015-01-26 07:25:37410 InitialiseContext();
411
ricea433bdab2015-01-26 07:25:37412 GURL ws_url = ws_server.GetURL(kEchoServer);
413 EXPECT_TRUE(ConnectAndWait(ws_url));
ryansturm7de050c2016-02-23 00:10:21414 const TestProxyDelegateWithProxyInfo::ResolvedProxyInfo& info =
415 proxy_delegate_->resolved_proxy_info();
ricea433bdab2015-01-26 07:25:37416 EXPECT_EQ(ws_url, info.url);
417 EXPECT_TRUE(info.proxy_info.is_http());
418}
419
Adam Rice5b4a3d82018-08-02 15:28:43420std::unique_ptr<HttpResponse> ProxyPacHandler(const HttpRequest& request) {
421 GURL url = request.GetURL();
422 EXPECT_EQ(url.path_piece(), "/proxy.pac");
423 EXPECT_TRUE(url.has_query());
424 std::string proxy;
425 EXPECT_TRUE(GetValueForKeyInQuery(url, "proxy", &proxy));
426 auto response = std::make_unique<BasicHttpResponse>();
427 response->set_content_type("application/x-ns-proxy-autoconfig");
428 response->set_content(
429 base::StringPrintf("function FindProxyForURL(url, host) {\n"
430 " return 'PROXY %s';\n"
431 "}\n",
432 proxy.c_str()));
433 return response;
434}
435
436// This tests the proxy.pac resolver that is built into the system. This is not
437// the one that Chrome normally uses. Chrome's normal implementation is defined
438// as a mojo service. It is outside //net and we can't use it from here. This
439// tests the alternative implementations that are selected when the
440// --winhttp-proxy-resolver flag is provided to Chrome. These only exist on OS X
441// and Windows.
442// TODO(ricea): Remove this test if --winhttp-proxy-resolver flag is removed.
443// See crbug.com/644030.
444
Avi Drissman25292af62020-07-29 21:57:11445#if defined(OS_WIN) || defined(OS_APPLE)
Adam Rice5b4a3d82018-08-02 15:28:43446#define MAYBE_ProxyPacUsed ProxyPacUsed
447#else
448#define MAYBE_ProxyPacUsed DISABLED_ProxyPacUsed
449#endif
450
451TEST_F(WebSocketEndToEndTest, MAYBE_ProxyPacUsed) {
452 EmbeddedTestServer proxy_pac_server(net::EmbeddedTestServer::Type::TYPE_HTTP);
453 SpawnedTestServer proxy_server(SpawnedTestServer::TYPE_PROXY,
454 base::FilePath());
455 SpawnedTestServer ws_server(SpawnedTestServer::TYPE_WS,
456 GetWebSocketTestDataDirectory());
457 proxy_pac_server.RegisterRequestHandler(base::BindRepeating(ProxyPacHandler));
458 proxy_server.set_redirect_connect_to_localhost(true);
459
460 ASSERT_TRUE(proxy_pac_server.Start());
461 ASSERT_TRUE(proxy_server.StartInBackground());
462 ASSERT_TRUE(ws_server.StartInBackground());
463 ASSERT_TRUE(proxy_server.BlockUntilStarted());
464 ASSERT_TRUE(ws_server.BlockUntilStarted());
465
466 ProxyConfig proxy_config =
467 ProxyConfig::CreateFromCustomPacURL(proxy_pac_server.GetURL(base::StrCat(
468 {"/proxy.pac?proxy=", proxy_server.host_port_pair().ToString()})));
469 proxy_config.set_pac_mandatory(true);
470 auto proxy_config_service = std::make_unique<ProxyConfigServiceFixed>(
471 ProxyConfigWithAnnotation(proxy_config, TRAFFIC_ANNOTATION_FOR_TESTS));
Nicolas Arciniega8ec5bfa2020-03-20 05:07:26472 std::unique_ptr<ProxyResolutionService> proxy_resolution_service(
Nicolas Arciniegad2013f92020-02-07 23:00:56473 ConfiguredProxyResolutionService::CreateUsingSystemProxyResolver(
Eric Roman3be01ba2020-04-03 21:37:09474 std::move(proxy_config_service), NetLog::Get(),
475 /*quick_check_enabled=*/true));
Adam Rice5b4a3d82018-08-02 15:28:43476 ASSERT_EQ(ws_server.host_port_pair().host(), "127.0.0.1");
477 context_.set_proxy_resolution_service(proxy_resolution_service.get());
478 InitialiseContext();
479
Eric Romanda790f92018-11-07 19:17:15480 // Use a name other than localhost, since localhost implicitly bypasses the
481 // use of proxy.pac.
Adam Rice5b4a3d82018-08-02 15:28:43482 HostPortPair fake_ws_host_port_pair("stealth-localhost",
483 ws_server.host_port_pair().port());
484
485 GURL ws_url(base::StrCat(
486 {"ws://", fake_ws_host_port_pair.ToString(), "/", kEchoServer}));
487 EXPECT_TRUE(ConnectAndWait(ws_url));
488 const auto& info = proxy_delegate_->resolved_proxy_info();
489 EXPECT_EQ(ws_url, info.url);
490 EXPECT_TRUE(info.proxy_info.is_http());
491 EXPECT_EQ(info.proxy_info.ToPacString(),
492 base::StrCat({"PROXY ", proxy_server.host_port_pair().ToString()}));
493}
494
ricea23c3f942015-02-02 13:35:13495// This is a regression test for crbug.com/408061 Crash in
496// net::WebSocketBasicHandshakeStream::Upgrade.
Sergey Ulanov4c786d32017-09-08 22:53:25497TEST_F(WebSocketEndToEndTest, TruncatedResponse) {
ricea23c3f942015-02-02 13:35:13498 SpawnedTestServer ws_server(SpawnedTestServer::TYPE_WS,
ricea23c3f942015-02-02 13:35:13499 GetWebSocketTestDataDirectory());
500 ASSERT_TRUE(ws_server.Start());
501 InitialiseContext();
502
503 GURL ws_url = ws_server.GetURL("truncated-headers");
504 EXPECT_FALSE(ConnectAndWait(ws_url));
505}
506
ricea5acb1faf72015-03-16 15:34:00507// Regression test for crbug.com/180504 "WebSocket handshake fails when HTTP
508// headers have trailing LWS".
Sergey Ulanov4c786d32017-09-08 22:53:25509TEST_F(WebSocketEndToEndTest, TrailingWhitespace) {
ricea5acb1faf72015-03-16 15:34:00510 SpawnedTestServer ws_server(SpawnedTestServer::TYPE_WS,
ricea5acb1faf72015-03-16 15:34:00511 GetWebSocketTestDataDirectory());
512 ASSERT_TRUE(ws_server.Start());
513
514 GURL ws_url = ws_server.GetURL("trailing-whitespace");
515 sub_protocols_.push_back("sip");
516 EXPECT_TRUE(ConnectAndWait(ws_url));
517 EXPECT_EQ("sip", event_interface_->selected_subprotocol());
518}
519
riceae1d67672015-03-19 10:10:17520// This is a regression test for crbug.com/169448 "WebSockets should support
521// header continuations"
522// TODO(ricea): HTTP continuation headers have been deprecated by RFC7230. If
523// support for continuation headers is removed from Chrome, then this test will
524// break and should be removed.
Sergey Ulanov4c786d32017-09-08 22:53:25525TEST_F(WebSocketEndToEndTest, HeaderContinuations) {
riceae1d67672015-03-19 10:10:17526 SpawnedTestServer ws_server(SpawnedTestServer::TYPE_WS,
riceae1d67672015-03-19 10:10:17527 GetWebSocketTestDataDirectory());
528 ASSERT_TRUE(ws_server.Start());
529
530 GURL ws_url = ws_server.GetURL("header-continuation");
531
532 EXPECT_TRUE(ConnectAndWait(ws_url));
533 EXPECT_EQ("permessage-deflate; server_max_window_bits=10",
534 event_interface_->extensions());
535}
536
Chris Thompsone3c3a3b02020-12-17 23:20:40537// These are not true end-to-end tests as the SpawnedTestServer doesn't
538// support TLS 1.2.
539// TODO(ricea): Make these be true end-to-end tests again when
540// SpawnedTestServer supports TLS 1.2 or EmbeddedTestServer supports
541// WebSockets.
542class WebSocketHstsTest : public TestWithTaskEnvironment {
543 protected:
544 WebSocketHstsTest() : context_(true) {
545 context_.set_client_socket_factory(&socket_factory_);
546 context_.Init();
547 }
548
549 void MakeHttpConnection(const GURL& url) {
550 // Set up SSL details, because otherwise HSTS headers aren't processed.
551 SSLSocketDataProvider ssl_socket_data(net::ASYNC, net::OK);
552 ssl_socket_data.ssl_info.cert =
553 ImportCertFromFile(GetTestCertsDirectory(), "ok_cert.pem");
554 ssl_socket_data.ssl_info.is_issued_by_known_root = true;
555 ssl_socket_data.ssl_info.ct_policy_compliance =
556 ct::CTPolicyCompliance::CT_POLICY_COMPLIES_VIA_SCTS;
557 ssl_socket_data.ssl_info.cert_status = 0;
558 socket_factory_.AddSSLSocketDataProvider(&ssl_socket_data);
559
560 req_ = context_.CreateRequest(url, DEFAULT_PRIORITY, &delegate_,
561 TRAFFIC_ANNOTATION_FOR_TESTS);
562
563 MockWrite writes[] = {
564 MockWrite("GET / HTTP/1.1\r\n"
565 "Host: www.example.org\r\n"
566 "Connection: keep-alive\r\n"
567 "User-Agent: \r\n"
568 "Accept-Encoding: gzip, deflate\r\n"
569 "Accept-Language: en-us,fr\r\n\r\n")};
570 MockRead reads[] = {MockRead("HTTP/1.1 200 OK\r\n"
571 "Strict-Transport-Security: max-age=123; "
572 "includeSubdomains\r\n\r\n"),
573 MockRead(ASYNC, 0)};
574
575 StaticSocketDataProvider data(reads, writes);
576 socket_factory_.AddSocketDataProvider(&data);
577
578 req_->Start();
579 base::RunLoop().RunUntilIdle();
580 }
581
582 void MakeWebsocketConnection(const GURL& url) {
583 // Set up SSL details, because otherwise HSTS headers aren't processed.
584 SSLSocketDataProvider ssl_socket_data(net::ASYNC, net::OK);
585 ssl_socket_data.ssl_info.cert =
586 ImportCertFromFile(GetTestCertsDirectory(), "ok_cert.pem");
587 ssl_socket_data.ssl_info.is_issued_by_known_root = true;
588 ssl_socket_data.ssl_info.ct_policy_compliance =
589 ct::CTPolicyCompliance::CT_POLICY_COMPLIES_VIA_SCTS;
590 ssl_socket_data.ssl_info.cert_status = 0;
591 socket_factory_.AddSSLSocketDataProvider(&ssl_socket_data);
592
593 req_ = context_.CreateRequest(url, DEFAULT_PRIORITY, &delegate_,
594 TRAFFIC_ANNOTATION_FOR_TESTS);
595
596 HttpRequestHeaders headers;
597 headers.SetHeader("Connection", "Upgrade");
598 headers.SetHeader("Upgrade", "websocket");
599 headers.SetHeader("Origin", "null");
600 headers.SetHeader("Sec-WebSocket-Version", "13");
601 req_->SetExtraRequestHeaders(headers);
602
603 MockWrite writes[] = {
604 MockWrite("GET / HTTP/1.1\r\n"
605 "Host: www.example.org\r\n"
606 "Connection: Upgrade\r\n"
607 "Upgrade: websocket\r\n"
608 "Origin: null\r\n"
609 "Sec-WebSocket-Version: 13\r\n"
610 "User-Agent: \r\n"
611 "Accept-Encoding: gzip, deflate\r\n"
612 "Accept-Language: en-us,fr\r\n"
613 "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n"
614 "Sec-WebSocket-Extensions: permessage-deflate; "
615 "client_max_window_bits\r\n\r\n")};
616 MockRead reads[] = {
617 MockRead("HTTP/1.1 101 Switching Protocols\r\n"
618 "Upgrade: websocket\r\n"
619 "Connection: Upgrade\r\n"
620 "Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\r\n"
621 "Strict-Transport-Security: max-age=123; "
622 "includeSubdomains\r\n\r\n"),
623 MockRead(ASYNC, 0)};
624
625 StaticSocketDataProvider data(reads, writes);
626 socket_factory_.AddSocketDataProvider(&data);
627
628 req_->SetUserData(
629 kWebSocketHandshakeUserDataKey,
630 std::make_unique<TestWebSocketHandshakeStreamCreateHelper>());
631 req_->SetLoadFlags(LOAD_DISABLE_CACHE);
632 req_->Start();
633 base::RunLoop().RunUntilIdle();
634 }
635
636 TestURLRequestContext context_;
637 MockClientSocketFactory socket_factory_;
638 TestDelegate delegate_;
639 std::unique_ptr<URLRequest> req_;
640};
641
642// Regression test for crbug.com/455215 "HSTS not applied to WebSocket"
643TEST_F(WebSocketHstsTest, HTTPSToWebSocket) {
644 // Set HSTS via https:
645 MakeHttpConnection(GURL("https://www.example.org"));
646 EXPECT_EQ(OK, delegate_.request_status());
647
648 ASSERT_TRUE(context_.transport_security_state()->ShouldUpgradeToSSL(
649 "www.example.org"));
650
651 // Check HSTS by starting a request over ws: and verifying that it gets
652 // ugpraded to wss:.
653 MakeWebsocketConnection(GURL("ws://www.example.org"));
654 EXPECT_EQ(OK, delegate_.request_status());
655 EXPECT_TRUE(delegate_.response_completed());
656 EXPECT_TRUE(req_->url().SchemeIs("wss"));
657}
658
659TEST_F(WebSocketHstsTest, WebSocketToHTTP) {
660 // Set HSTS via wss:
661 MakeWebsocketConnection(GURL("wss://www.example.org"));
662 EXPECT_EQ(OK, delegate_.request_status());
663 EXPECT_TRUE(delegate_.response_completed());
664
665 ASSERT_TRUE(context_.transport_security_state()->ShouldUpgradeToSSL(
666 "www.example.org"));
667
668 // Check HSTS by starting a request over http: and verifying that it gets
669 // ugpraded to https:.
670 MakeHttpConnection(GURL("http://www.example.org"));
671 EXPECT_EQ(OK, delegate_.request_status());
672 EXPECT_TRUE(req_->url().SchemeIs("https"));
673}
674
675TEST_F(WebSocketHstsTest, WebSocketToWebSocket) {
676 // Set HSTS via wss:
677 MakeWebsocketConnection(GURL("wss://www.example.org"));
678 EXPECT_EQ(OK, delegate_.request_status());
679 EXPECT_TRUE(delegate_.response_completed());
680
681 ASSERT_TRUE(context_.transport_security_state()->ShouldUpgradeToSSL(
682 "www.example.org"));
683
684 // Check HSTS by starting a request over ws: and verifying that it gets
685 // ugpraded to wss:.
686 MakeWebsocketConnection(GURL("ws://www.example.org"));
687 EXPECT_EQ(OK, delegate_.request_status());
688 EXPECT_TRUE(delegate_.response_completed());
689 EXPECT_TRUE(req_->url().SchemeIs("wss"));
690}
691
ricea433bdab2015-01-26 07:25:37692} // namespace
693
694} // namespace net