blob: b4d1281a963b0cb2cc0141ab73aec32872220077 [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"
Eric Orthcd71ede2021-09-14 18:18:5020#include "base/files/file_path.h"
skyostil4891b25b2015-06-11 11:43:4521#include "base/location.h"
danakj9c5cab52016-04-16 00:54:3322#include "base/memory/ptr_util.h"
Keishi Hattori0e45c022021-11-27 09:25:5223#include "base/memory/raw_ptr.h"
Bence Béky65623972018-03-05 15:31:5624#include "base/memory/scoped_refptr.h"
ricea433bdab2015-01-26 07:25:3725#include "base/run_loop.h"
Adam Rice5b4a3d82018-08-02 15:28:4326#include "base/strings/strcat.h"
Eric Orthcd71ede2021-09-14 18:18:5027#include "base/strings/string_number_conversions.h"
Adam Ricecb76ac62015-02-20 05:33:2528#include "base/strings/string_piece.h"
Adam Rice5b4a3d82018-08-02 15:28:4329#include "base/strings/stringprintf.h"
Patrick Monette643cdf62021-10-15 19:13:4230#include "base/task/single_thread_task_runner.h"
Eric Orthcd71ede2021-09-14 18:18:5031#include "base/test/scoped_feature_list.h"
gabf767595f2016-05-11 18:50:3532#include "base/threading/thread_task_runner_handle.h"
Sergey Ulanova337dcd2017-09-08 20:53:1433#include "build/build_config.h"
ricea433bdab2015-01-26 07:25:3734#include "net/base/auth.h"
Eric Orthcd71ede2021-09-14 18:18:5035#include "net/base/features.h"
Adam Rice5b4a3d82018-08-02 15:28:4336#include "net/base/host_port_pair.h"
Tsuyoshi Horo01faed62019-02-20 22:11:3737#include "net/base/ip_endpoint.h"
Matt Menke29a538d2020-04-29 16:12:1738#include "net/base/isolation_info.h"
Chris Thompsone3c3a3b02020-12-17 23:20:4039#include "net/base/net_errors.h"
ryansturm7de050c2016-02-23 00:10:2140#include "net/base/proxy_delegate.h"
Adam Rice5b4a3d82018-08-02 15:28:4341#include "net/base/url_util.h"
Chris Thompsone3c3a3b02020-12-17 23:20:4042#include "net/cert/ct_policy_status.h"
Eric Orthcd71ede2021-09-14 18:18:5043#include "net/dns/mock_host_resolver.h"
Yutaka Hirano2f65eec2018-05-23 01:58:2244#include "net/http/http_request_headers.h"
Matt Menkece5d765372021-08-17 18:24:1245#include "net/http/transport_security_state.h"
Adam Rice5b4a3d82018-08-02 15:28:4346#include "net/log/net_log.h"
Nicolas Arciniegad2013f92020-02-07 23:00:5647#include "net/proxy_resolution/configured_proxy_resolution_service.h"
Adam Rice5b4a3d82018-08-02 15:28:4348#include "net/proxy_resolution/proxy_config.h"
49#include "net/proxy_resolution/proxy_config_service.h"
50#include "net/proxy_resolution/proxy_config_service_fixed.h"
51#include "net/proxy_resolution/proxy_config_with_annotation.h"
52#include "net/proxy_resolution/proxy_info.h"
tommycli59a63432015-11-06 00:10:5553#include "net/test/embedded_test_server/embedded_test_server.h"
Adam Rice5b4a3d82018-08-02 15:28:4354#include "net/test/embedded_test_server/http_request.h"
55#include "net/test/embedded_test_server/http_response.h"
ricea433bdab2015-01-26 07:25:3756#include "net/test/spawned_test_server/spawned_test_server.h"
David Benjamin9f47d662022-05-13 21:09:0257#include "net/test/ssl_test_util.h"
rsleevia69c79a2016-06-22 03:28:4358#include "net/test/test_data_directory.h"
Gabriel Charettec7108742019-08-23 03:31:4059#include "net/test/test_with_task_environment.h"
rhalavati9ebaba7e2017-04-27 06:16:2960#include "net/traffic_annotation/network_traffic_annotation_test_helper.h"
Adam Rice5b4a3d82018-08-02 15:28:4361#include "net/url_request/url_request.h"
62#include "net/url_request/url_request_context.h"
Yutaka Hirano5e97e072022-02-04 07:52:5263#include "net/url_request/url_request_context_builder.h"
ricea433bdab2015-01-26 07:25:3764#include "net/url_request/url_request_test_util.h"
65#include "net/websockets/websocket_channel.h"
66#include "net/websockets/websocket_event_interface.h"
67#include "testing/gtest/include/gtest/gtest.h"
Adam Rice5b4a3d82018-08-02 15:28:4368#include "url/gurl.h"
mkwst4997ce82015-07-25 12:00:0569#include "url/origin.h"
Eric Orthbe86fee2021-10-28 22:31:1170#include "url/url_constants.h"
ricea433bdab2015-01-26 07:25:3771
72namespace net {
73
yhirano4a593832016-10-24 18:58:2274class URLRequest;
75
ricea433bdab2015-01-26 07:25:3776namespace {
77
Adam Rice5b4a3d82018-08-02 15:28:4378using test_server::BasicHttpResponse;
79using test_server::HttpRequest;
80using test_server::HttpResponse;
81
ricea433bdab2015-01-26 07:25:3782static const char kEchoServer[] = "echo-with-no-extension";
83
David Benjamin51eeec92021-09-21 03:56:3684// Simplify changing URL schemes.
85GURL ReplaceUrlScheme(const GURL& in_url, const base::StringPiece& scheme) {
86 GURL::Replacements replacements;
87 replacements.SetSchemeStr(scheme);
88 return in_url.ReplaceComponents(replacements);
89}
90
ricea433bdab2015-01-26 07:25:3791// An implementation of WebSocketEventInterface that waits for and records the
92// results of the connect.
93class ConnectTestingEventInterface : public WebSocketEventInterface {
94 public:
95 ConnectTestingEventInterface();
96
Peter Boström407869b2021-10-07 04:42:4897 ConnectTestingEventInterface(const ConnectTestingEventInterface&) = delete;
98 ConnectTestingEventInterface& operator=(const ConnectTestingEventInterface&) =
99 delete;
100
ricea433bdab2015-01-26 07:25:37101 void WaitForResponse();
102
103 bool failed() const { return failed_; }
104
Eric Orthcd71ede2021-09-14 18:18:50105 const std::unique_ptr<WebSocketHandshakeResponseInfo>& response() const {
106 return response_;
107 }
108
ricea433bdab2015-01-26 07:25:37109 // Only set if the handshake failed, otherwise empty.
110 std::string failure_message() const;
111
112 std::string selected_subprotocol() const;
113
114 std::string extensions() const;
115
116 // Implementation of WebSocketEventInterface.
yhirano4a593832016-10-24 18:58:22117 void OnCreateURLRequest(URLRequest* request) override {}
118
Yoichi Osato1ead61a2020-01-06 04:52:57119 void OnAddChannelResponse(
120 std::unique_ptr<WebSocketHandshakeResponseInfo> response,
121 const std::string& selected_subprotocol,
Adam Rice250bb012020-05-26 15:56:10122 const std::string& extensions) override;
ricea433bdab2015-01-26 07:25:37123
Yutaka Hirano4165de92018-04-10 11:46:49124 void OnDataFrame(bool fin,
125 WebSocketMessageType type,
Yutaka Hirano76aacb202019-09-05 16:36:56126 base::span<const char> payload) override;
ricea433bdab2015-01-26 07:25:37127
Yoichi Osatofcaa2a22019-08-28 08:22:36128 bool HasPendingDataFrames() override { return false; }
129
Adam Riced0095702020-05-26 06:18:25130 void OnSendDataFrameDone() override;
ricea433bdab2015-01-26 07:25:37131
Yutaka Hirano4165de92018-04-10 11:46:49132 void OnClosingHandshake() override;
ricea433bdab2015-01-26 07:25:37133
Yutaka Hirano4165de92018-04-10 11:46:49134 void OnDropChannel(bool was_clean,
135 uint16_t code,
136 const std::string& reason) override;
ricea433bdab2015-01-26 07:25:37137
Adam Langleya48b636a2020-11-12 23:42:52138 void OnFailChannel(const std::string& message,
139 int net_error,
Anton Bikineev068d2912021-05-15 20:43:52140 absl::optional<int> response_code) override;
ricea433bdab2015-01-26 07:25:37141
Yutaka Hirano4165de92018-04-10 11:46:49142 void OnStartOpeningHandshake(
danakj9c5cab52016-04-16 00:54:33143 std::unique_ptr<WebSocketHandshakeRequestInfo> request) override;
ricea433bdab2015-01-26 07:25:37144
Yutaka Hirano4165de92018-04-10 11:46:49145 void OnSSLCertificateError(
danakj9c5cab52016-04-16 00:54:33146 std::unique_ptr<SSLErrorCallbacks> ssl_error_callbacks,
ricea433bdab2015-01-26 07:25:37147 const GURL& url,
Emily Starkd9df3d32019-04-29 17:54:57148 int net_error,
ricea433bdab2015-01-26 07:25:37149 const SSLInfo& ssl_info,
150 bool fatal) override;
151
Emily Starkf2c9bbd2019-04-09 17:08:58152 int OnAuthRequired(const AuthChallengeInfo& auth_info,
Yutaka Hirano70fa25912018-06-06 05:26:54153 scoped_refptr<HttpResponseHeaders> response_headers,
Tsuyoshi Horo01faed62019-02-20 22:11:37154 const IPEndPoint& remote_endpoint,
Yutaka Hirano70fa25912018-06-06 05:26:54155 base::OnceCallback<void(const AuthCredentials*)> callback,
Anton Bikineev068d2912021-05-15 20:43:52156 absl::optional<AuthCredentials>* credentials) override;
Yutaka Hirano70fa25912018-06-06 05:26:54157
ricea433bdab2015-01-26 07:25:37158 private:
159 void QuitNestedEventLoop();
160
161 // failed_ is true if the handshake failed (ie. OnFailChannel was called).
Tsuyoshi Horoa0b9c0f2022-06-09 01:41:51162 bool failed_ = false;
Eric Orthcd71ede2021-09-14 18:18:50163 std::unique_ptr<WebSocketHandshakeResponseInfo> response_;
ricea433bdab2015-01-26 07:25:37164 std::string selected_subprotocol_;
165 std::string extensions_;
166 std::string failure_message_;
167 base::RunLoop run_loop_;
ricea433bdab2015-01-26 07:25:37168};
169
Tsuyoshi Horoa0b9c0f2022-06-09 01:41:51170ConnectTestingEventInterface::ConnectTestingEventInterface() = default;
ricea433bdab2015-01-26 07:25:37171
172void ConnectTestingEventInterface::WaitForResponse() {
173 run_loop_.Run();
174}
175
176std::string ConnectTestingEventInterface::failure_message() const {
177 return failure_message_;
178}
179
180std::string ConnectTestingEventInterface::selected_subprotocol() const {
181 return selected_subprotocol_;
182}
183
184std::string ConnectTestingEventInterface::extensions() const {
185 return extensions_;
186}
187
Yutaka Hirano4165de92018-04-10 11:46:49188void ConnectTestingEventInterface::OnAddChannelResponse(
Yoichi Osato1ead61a2020-01-06 04:52:57189 std::unique_ptr<WebSocketHandshakeResponseInfo> response,
ricea433bdab2015-01-26 07:25:37190 const std::string& selected_subprotocol,
Adam Rice250bb012020-05-26 15:56:10191 const std::string& extensions) {
Eric Orthcd71ede2021-09-14 18:18:50192 response_ = std::move(response);
ricea433bdab2015-01-26 07:25:37193 selected_subprotocol_ = selected_subprotocol;
194 extensions_ = extensions;
195 QuitNestedEventLoop();
ricea433bdab2015-01-26 07:25:37196}
197
Yutaka Hirano4165de92018-04-10 11:46:49198void ConnectTestingEventInterface::OnDataFrame(bool fin,
199 WebSocketMessageType type,
Yutaka Hirano76aacb202019-09-05 16:36:56200 base::span<const char> payload) {
201}
ricea433bdab2015-01-26 07:25:37202
Adam Riced0095702020-05-26 06:18:25203void ConnectTestingEventInterface::OnSendDataFrameDone() {}
ricea433bdab2015-01-26 07:25:37204
Yutaka Hirano4165de92018-04-10 11:46:49205void ConnectTestingEventInterface::OnClosingHandshake() {}
ricea433bdab2015-01-26 07:25:37206
Yutaka Hirano4165de92018-04-10 11:46:49207void ConnectTestingEventInterface::OnDropChannel(bool was_clean,
208 uint16_t code,
209 const std::string& reason) {}
ricea433bdab2015-01-26 07:25:37210
Adam Langleya48b636a2020-11-12 23:42:52211void ConnectTestingEventInterface::OnFailChannel(
212 const std::string& message,
213 int net_error,
Anton Bikineev068d2912021-05-15 20:43:52214 absl::optional<int> response_code) {
ricea433bdab2015-01-26 07:25:37215 failed_ = true;
216 failure_message_ = message;
217 QuitNestedEventLoop();
ricea433bdab2015-01-26 07:25:37218}
219
Yutaka Hirano4165de92018-04-10 11:46:49220void ConnectTestingEventInterface::OnStartOpeningHandshake(
221 std::unique_ptr<WebSocketHandshakeRequestInfo> request) {}
ricea433bdab2015-01-26 07:25:37222
Yutaka Hirano4165de92018-04-10 11:46:49223void ConnectTestingEventInterface::OnSSLCertificateError(
danakj9c5cab52016-04-16 00:54:33224 std::unique_ptr<SSLErrorCallbacks> ssl_error_callbacks,
ricea433bdab2015-01-26 07:25:37225 const GURL& url,
Emily Starkd9df3d32019-04-29 17:54:57226 int net_error,
ricea433bdab2015-01-26 07:25:37227 const SSLInfo& ssl_info,
228 bool fatal) {
skyostil4891b25b2015-06-11 11:43:45229 base::ThreadTaskRunnerHandle::Get()->PostTask(
kylecharf4fe5172019-02-15 18:53:49230 FROM_HERE, base::BindOnce(&SSLErrorCallbacks::CancelSSLRequest,
231 base::Owned(ssl_error_callbacks.release()),
232 ERR_SSL_PROTOCOL_ERROR, &ssl_info));
ricea433bdab2015-01-26 07:25:37233}
234
Yutaka Hirano70fa25912018-06-06 05:26:54235int ConnectTestingEventInterface::OnAuthRequired(
Emily Starkf2c9bbd2019-04-09 17:08:58236 const AuthChallengeInfo& auth_info,
Yutaka Hirano70fa25912018-06-06 05:26:54237 scoped_refptr<HttpResponseHeaders> response_headers,
Tsuyoshi Horo01faed62019-02-20 22:11:37238 const IPEndPoint& remote_endpoint,
Yutaka Hirano70fa25912018-06-06 05:26:54239 base::OnceCallback<void(const AuthCredentials*)> callback,
Anton Bikineev068d2912021-05-15 20:43:52240 absl::optional<AuthCredentials>* credentials) {
241 *credentials = absl::nullopt;
Yutaka Hirano70fa25912018-06-06 05:26:54242 return OK;
243}
244
ricea433bdab2015-01-26 07:25:37245void ConnectTestingEventInterface::QuitNestedEventLoop() {
246 run_loop_.Quit();
247}
248
249// A subclass of TestNetworkDelegate that additionally implements the
250// OnResolveProxy callback and records the information passed to it.
ryansturm7de050c2016-02-23 00:10:21251class TestProxyDelegateWithProxyInfo : public ProxyDelegate {
ricea433bdab2015-01-26 07:25:37252 public:
Chris Watkins28c2fdd2017-11-30 06:06:52253 TestProxyDelegateWithProxyInfo() = default;
ricea433bdab2015-01-26 07:25:37254
Peter Boström407869b2021-10-07 04:42:48255 TestProxyDelegateWithProxyInfo(const TestProxyDelegateWithProxyInfo&) =
256 delete;
257 TestProxyDelegateWithProxyInfo& operator=(
258 const TestProxyDelegateWithProxyInfo&) = delete;
259
ricea433bdab2015-01-26 07:25:37260 struct ResolvedProxyInfo {
261 GURL url;
262 ProxyInfo proxy_info;
263 };
264
265 const ResolvedProxyInfo& resolved_proxy_info() const {
266 return resolved_proxy_info_;
267 }
268
269 protected:
270 void OnResolveProxy(const GURL& url,
ryansturm4bab06832016-03-03 23:41:07271 const std::string& method,
Reilly Grantb414ace72017-11-14 23:03:22272 const ProxyRetryInfoMap& proxy_retry_info,
ricea433bdab2015-01-26 07:25:37273 ProxyInfo* result) override {
274 resolved_proxy_info_.url = url;
275 resolved_proxy_info_.proxy_info = *result;
276 }
277
ryansturm7de050c2016-02-23 00:10:21278 void OnFallback(const ProxyServer& bad_proxy, int net_error) override {}
ryansturm7de050c2016-02-23 00:10:21279
Robert Ogden78d4f9eb2020-03-17 20:56:38280 void OnBeforeTunnelRequest(const ProxyServer& proxy_server,
281 HttpRequestHeaders* extra_headers) override {}
Wojciech Dzierżanowski1f823562019-01-18 11:26:00282
Robert Ogden78d4f9eb2020-03-17 20:56:38283 Error OnTunnelHeadersReceived(
Wojciech Dzierżanowski1f823562019-01-18 11:26:00284 const ProxyServer& proxy_server,
285 const HttpResponseHeaders& response_headers) override {
286 return OK;
287 }
288
ricea433bdab2015-01-26 07:25:37289 private:
290 ResolvedProxyInfo resolved_proxy_info_;
ricea433bdab2015-01-26 07:25:37291};
292
Gabriel Charette694c3c332019-08-19 14:53:05293class WebSocketEndToEndTest : public TestWithTaskEnvironment {
ricea433bdab2015-01-26 07:25:37294 protected:
295 WebSocketEndToEndTest()
Adam Ricecb76ac62015-02-20 05:33:25296 : event_interface_(),
Bence Béky65623972018-03-05 15:31:56297 proxy_delegate_(std::make_unique<TestProxyDelegateWithProxyInfo>()),
Yutaka Hirano5e97e072022-02-04 07:52:52298 context_builder_(CreateTestURLRequestContextBuilder()) {}
ricea433bdab2015-01-26 07:25:37299
300 // Initialise the URLRequestContext. Normally done automatically by
301 // ConnectAndWait(). This method is for the use of tests that need the
302 // URLRequestContext initialised before calling ConnectAndWait().
303 void InitialiseContext() {
Yutaka Hirano5e97e072022-02-04 07:52:52304 DCHECK(!context_);
305 context_ = context_builder_->Build();
306 context_->proxy_resolution_service()->SetProxyDelegate(
Eric Roman3d8546a2018-09-10 17:00:52307 proxy_delegate_.get());
ricea433bdab2015-01-26 07:25:37308 }
309
310 // Send the connect request to |socket_url| and wait for a response. Returns
311 // true if the handshake succeeded.
312 bool ConnectAndWait(const GURL& socket_url) {
Yutaka Hirano5e97e072022-02-04 07:52:52313 if (!context_) {
ricea433bdab2015-01-26 07:25:37314 InitialiseContext();
315 }
Daniel Cheng88186bd52017-10-20 08:14:46316 url::Origin origin = url::Origin::Create(GURL("http://localhost"));
Maks Orlovich8be0e252019-12-09 18:35:49317 net::SiteForCookies site_for_cookies =
318 net::SiteForCookies::FromOrigin(origin);
shivanigithub4e78015f592020-10-21 13:26:23319 IsolationInfo isolation_info =
320 IsolationInfo::Create(IsolationInfo::RequestType::kOther, origin,
321 origin, SiteForCookies::FromOrigin(origin));
Tsuyoshi Horoc39623a82022-07-11 01:27:58322 auto event_interface = std::make_unique<ConnectTestingEventInterface>();
323 event_interface_ = event_interface.get();
324 channel_ = std::make_unique<WebSocketChannel>(std::move(event_interface),
325 context_.get());
Adam Langleyacbad242020-08-18 15:14:52326 channel_->SendAddChannelRequest(
327 GURL(socket_url), sub_protocols_, origin, site_for_cookies,
328 isolation_info, HttpRequestHeaders(), TRAFFIC_ANNOTATION_FOR_TESTS);
ricea433bdab2015-01-26 07:25:37329 event_interface_->WaitForResponse();
330 return !event_interface_->failed();
331 }
332
Keishi Hattori0e45c022021-11-27 09:25:52333 raw_ptr<ConnectTestingEventInterface> event_interface_; // owned by channel_
danakj9c5cab52016-04-16 00:54:33334 std::unique_ptr<TestProxyDelegateWithProxyInfo> proxy_delegate_;
Yutaka Hirano5e97e072022-02-04 07:52:52335 std::unique_ptr<URLRequestContextBuilder> context_builder_;
336 std::unique_ptr<URLRequestContext> context_;
danakj9c5cab52016-04-16 00:54:33337 std::unique_ptr<WebSocketChannel> channel_;
ricea5acb1faf72015-03-16 15:34:00338 std::vector<std::string> sub_protocols_;
ricea433bdab2015-01-26 07:25:37339};
340
ricea433bdab2015-01-26 07:25:37341// Basic test of connectivity. If this test fails, nothing else can be expected
342// to work.
Sergey Ulanov4c786d32017-09-08 22:53:25343TEST_F(WebSocketEndToEndTest, BasicSmokeTest) {
ricea433bdab2015-01-26 07:25:37344 SpawnedTestServer ws_server(SpawnedTestServer::TYPE_WS,
ricea433bdab2015-01-26 07:25:37345 GetWebSocketTestDataDirectory());
346 ASSERT_TRUE(ws_server.Start());
347 EXPECT_TRUE(ConnectAndWait(ws_server.GetURL(kEchoServer)));
348}
349
350// Test for issue crbug.com/433695 "Unencrypted WebSocket connection via
351// authenticated proxy times out"
352// TODO(ricea): Enable this when the issue is fixed.
353TEST_F(WebSocketEndToEndTest, DISABLED_HttpsProxyUnauthedFails) {
354 SpawnedTestServer proxy_server(SpawnedTestServer::TYPE_BASIC_AUTH_PROXY,
ricea433bdab2015-01-26 07:25:37355 base::FilePath());
356 SpawnedTestServer ws_server(SpawnedTestServer::TYPE_WS,
ricea433bdab2015-01-26 07:25:37357 GetWebSocketTestDataDirectory());
358 ASSERT_TRUE(proxy_server.StartInBackground());
359 ASSERT_TRUE(ws_server.StartInBackground());
360 ASSERT_TRUE(proxy_server.BlockUntilStarted());
361 ASSERT_TRUE(ws_server.BlockUntilStarted());
362 std::string proxy_config =
363 "https=" + proxy_server.host_port_pair().ToString();
Nicolas Arciniega8ec5bfa2020-03-20 05:07:26364 std::unique_ptr<ProxyResolutionService> proxy_resolution_service(
Yoichi Osato016748f2022-07-21 07:42:06365 ConfiguredProxyResolutionService::CreateFixedForTest(
Nicolas Arciniegad2013f92020-02-07 23:00:56366 proxy_config, TRAFFIC_ANNOTATION_FOR_TESTS));
Lily Houghton8c2f97d2018-01-22 05:06:59367 ASSERT_TRUE(proxy_resolution_service);
Yutaka Hirano5e97e072022-02-04 07:52:52368 context_builder_->set_proxy_resolution_service(
369 std::move(proxy_resolution_service));
ricea433bdab2015-01-26 07:25:37370 EXPECT_FALSE(ConnectAndWait(ws_server.GetURL(kEchoServer)));
371 EXPECT_EQ("Proxy authentication failed", event_interface_->failure_message());
372}
373
Sergey Ulanov4c786d32017-09-08 22:53:25374// These test are not compatible with RemoteTestServer because RemoteTestServer
375// doesn't support TYPE_BASIC_AUTH_PROXY.
376// TODO(ricea): Make these tests work. See crbug.com/441711.
Xiaohan Wang2a6845b2022-01-08 04:40:57377#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_FUCHSIA)
Sergey Ulanov4c786d32017-09-08 22:53:25378#define MAYBE_HttpsWssProxyUnauthedFails DISABLED_HttpsWssProxyUnauthedFails
379#define MAYBE_HttpsProxyUsed DISABLED_HttpsProxyUsed
380#else
381#define MAYBE_HttpsWssProxyUnauthedFails HttpsWssProxyUnauthedFails
382#define MAYBE_HttpsProxyUsed HttpsProxyUsed
383#endif
384
385TEST_F(WebSocketEndToEndTest, MAYBE_HttpsWssProxyUnauthedFails) {
ricea433bdab2015-01-26 07:25:37386 SpawnedTestServer proxy_server(SpawnedTestServer::TYPE_BASIC_AUTH_PROXY,
ricea433bdab2015-01-26 07:25:37387 base::FilePath());
388 SpawnedTestServer wss_server(SpawnedTestServer::TYPE_WSS,
ricea433bdab2015-01-26 07:25:37389 GetWebSocketTestDataDirectory());
390 ASSERT_TRUE(proxy_server.StartInBackground());
391 ASSERT_TRUE(wss_server.StartInBackground());
392 ASSERT_TRUE(proxy_server.BlockUntilStarted());
393 ASSERT_TRUE(wss_server.BlockUntilStarted());
Eric Romanda790f92018-11-07 19:17:15394 ProxyConfig proxy_config;
395 proxy_config.proxy_rules().ParseFromString(
396 "https=" + proxy_server.host_port_pair().ToString());
397 // TODO(https://crbug.com/901896): Don't rely on proxying localhost.
398 proxy_config.proxy_rules().bypass_rules.AddRulesToSubtractImplicit();
399
Nicolas Arciniega8ec5bfa2020-03-20 05:07:26400 std::unique_ptr<ProxyResolutionService> proxy_resolution_service(
Yoichi Osato016748f2022-07-21 07:42:06401 ConfiguredProxyResolutionService::CreateFixedForTest(
402 ProxyConfigWithAnnotation(proxy_config,
403 TRAFFIC_ANNOTATION_FOR_TESTS)));
Lily Houghton8c2f97d2018-01-22 05:06:59404 ASSERT_TRUE(proxy_resolution_service);
Yutaka Hirano5e97e072022-02-04 07:52:52405 context_builder_->set_proxy_resolution_service(
406 std::move(proxy_resolution_service));
ricea433bdab2015-01-26 07:25:37407 EXPECT_FALSE(ConnectAndWait(wss_server.GetURL(kEchoServer)));
408 EXPECT_EQ("Proxy authentication failed", event_interface_->failure_message());
409}
410
411// Regression test for crbug/426736 "WebSocket connections not using configured
412// system HTTPS Proxy".
Sergey Ulanov4c786d32017-09-08 22:53:25413TEST_F(WebSocketEndToEndTest, MAYBE_HttpsProxyUsed) {
Adam Rice5b4a3d82018-08-02 15:28:43414 SpawnedTestServer proxy_server(SpawnedTestServer::TYPE_PROXY,
ricea433bdab2015-01-26 07:25:37415 base::FilePath());
416 SpawnedTestServer ws_server(SpawnedTestServer::TYPE_WS,
ricea433bdab2015-01-26 07:25:37417 GetWebSocketTestDataDirectory());
418 ASSERT_TRUE(proxy_server.StartInBackground());
419 ASSERT_TRUE(ws_server.StartInBackground());
420 ASSERT_TRUE(proxy_server.BlockUntilStarted());
421 ASSERT_TRUE(ws_server.BlockUntilStarted());
Eric Romanda790f92018-11-07 19:17:15422 ProxyConfig proxy_config;
423 proxy_config.proxy_rules().ParseFromString(
424 "https=" + proxy_server.host_port_pair().ToString() + ";" +
425 "http=" + proxy_server.host_port_pair().ToString());
426 // TODO(https://crbug.com/901896): Don't rely on proxying localhost.
427 proxy_config.proxy_rules().bypass_rules.AddRulesToSubtractImplicit();
428
Nicolas Arciniega8ec5bfa2020-03-20 05:07:26429 std::unique_ptr<ProxyResolutionService> proxy_resolution_service(
Yoichi Osato016748f2022-07-21 07:42:06430 ConfiguredProxyResolutionService::CreateFixedForTest(
431 ProxyConfigWithAnnotation(proxy_config,
432 TRAFFIC_ANNOTATION_FOR_TESTS)));
Yutaka Hirano5e97e072022-02-04 07:52:52433 context_builder_->set_proxy_resolution_service(
434 std::move(proxy_resolution_service));
ricea433bdab2015-01-26 07:25:37435 InitialiseContext();
436
ricea433bdab2015-01-26 07:25:37437 GURL ws_url = ws_server.GetURL(kEchoServer);
438 EXPECT_TRUE(ConnectAndWait(ws_url));
ryansturm7de050c2016-02-23 00:10:21439 const TestProxyDelegateWithProxyInfo::ResolvedProxyInfo& info =
440 proxy_delegate_->resolved_proxy_info();
ricea433bdab2015-01-26 07:25:37441 EXPECT_EQ(ws_url, info.url);
442 EXPECT_TRUE(info.proxy_info.is_http());
443}
444
Adam Rice5b4a3d82018-08-02 15:28:43445std::unique_ptr<HttpResponse> ProxyPacHandler(const HttpRequest& request) {
446 GURL url = request.GetURL();
447 EXPECT_EQ(url.path_piece(), "/proxy.pac");
448 EXPECT_TRUE(url.has_query());
449 std::string proxy;
450 EXPECT_TRUE(GetValueForKeyInQuery(url, "proxy", &proxy));
451 auto response = std::make_unique<BasicHttpResponse>();
452 response->set_content_type("application/x-ns-proxy-autoconfig");
453 response->set_content(
454 base::StringPrintf("function FindProxyForURL(url, host) {\n"
455 " return 'PROXY %s';\n"
456 "}\n",
457 proxy.c_str()));
458 return response;
459}
460
461// This tests the proxy.pac resolver that is built into the system. This is not
462// the one that Chrome normally uses. Chrome's normal implementation is defined
463// as a mojo service. It is outside //net and we can't use it from here. This
464// tests the alternative implementations that are selected when the
465// --winhttp-proxy-resolver flag is provided to Chrome. These only exist on OS X
466// and Windows.
467// TODO(ricea): Remove this test if --winhttp-proxy-resolver flag is removed.
468// See crbug.com/644030.
469
Xiaohan Wang2a6845b2022-01-08 04:40:57470#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_APPLE)
Adam Rice5b4a3d82018-08-02 15:28:43471#define MAYBE_ProxyPacUsed ProxyPacUsed
472#else
473#define MAYBE_ProxyPacUsed DISABLED_ProxyPacUsed
474#endif
475
476TEST_F(WebSocketEndToEndTest, MAYBE_ProxyPacUsed) {
477 EmbeddedTestServer proxy_pac_server(net::EmbeddedTestServer::Type::TYPE_HTTP);
478 SpawnedTestServer proxy_server(SpawnedTestServer::TYPE_PROXY,
479 base::FilePath());
480 SpawnedTestServer ws_server(SpawnedTestServer::TYPE_WS,
481 GetWebSocketTestDataDirectory());
482 proxy_pac_server.RegisterRequestHandler(base::BindRepeating(ProxyPacHandler));
483 proxy_server.set_redirect_connect_to_localhost(true);
484
485 ASSERT_TRUE(proxy_pac_server.Start());
486 ASSERT_TRUE(proxy_server.StartInBackground());
487 ASSERT_TRUE(ws_server.StartInBackground());
488 ASSERT_TRUE(proxy_server.BlockUntilStarted());
489 ASSERT_TRUE(ws_server.BlockUntilStarted());
490
491 ProxyConfig proxy_config =
492 ProxyConfig::CreateFromCustomPacURL(proxy_pac_server.GetURL(base::StrCat(
493 {"/proxy.pac?proxy=", proxy_server.host_port_pair().ToString()})));
494 proxy_config.set_pac_mandatory(true);
495 auto proxy_config_service = std::make_unique<ProxyConfigServiceFixed>(
496 ProxyConfigWithAnnotation(proxy_config, TRAFFIC_ANNOTATION_FOR_TESTS));
Nicolas Arciniega8ec5bfa2020-03-20 05:07:26497 std::unique_ptr<ProxyResolutionService> proxy_resolution_service(
Nicolas Arciniegad2013f92020-02-07 23:00:56498 ConfiguredProxyResolutionService::CreateUsingSystemProxyResolver(
Eric Roman3be01ba2020-04-03 21:37:09499 std::move(proxy_config_service), NetLog::Get(),
500 /*quick_check_enabled=*/true));
Adam Rice5b4a3d82018-08-02 15:28:43501 ASSERT_EQ(ws_server.host_port_pair().host(), "127.0.0.1");
Yutaka Hirano5e97e072022-02-04 07:52:52502 context_builder_->set_proxy_resolution_service(
503 std::move(proxy_resolution_service));
Adam Rice5b4a3d82018-08-02 15:28:43504 InitialiseContext();
505
Eric Romanda790f92018-11-07 19:17:15506 // Use a name other than localhost, since localhost implicitly bypasses the
507 // use of proxy.pac.
Adam Rice5b4a3d82018-08-02 15:28:43508 HostPortPair fake_ws_host_port_pair("stealth-localhost",
509 ws_server.host_port_pair().port());
510
511 GURL ws_url(base::StrCat(
512 {"ws://", fake_ws_host_port_pair.ToString(), "/", kEchoServer}));
513 EXPECT_TRUE(ConnectAndWait(ws_url));
514 const auto& info = proxy_delegate_->resolved_proxy_info();
515 EXPECT_EQ(ws_url, info.url);
516 EXPECT_TRUE(info.proxy_info.is_http());
517 EXPECT_EQ(info.proxy_info.ToPacString(),
518 base::StrCat({"PROXY ", proxy_server.host_port_pair().ToString()}));
519}
520
ricea23c3f942015-02-02 13:35:13521// This is a regression test for crbug.com/408061 Crash in
522// net::WebSocketBasicHandshakeStream::Upgrade.
Sergey Ulanov4c786d32017-09-08 22:53:25523TEST_F(WebSocketEndToEndTest, TruncatedResponse) {
ricea23c3f942015-02-02 13:35:13524 SpawnedTestServer ws_server(SpawnedTestServer::TYPE_WS,
ricea23c3f942015-02-02 13:35:13525 GetWebSocketTestDataDirectory());
526 ASSERT_TRUE(ws_server.Start());
527 InitialiseContext();
528
529 GURL ws_url = ws_server.GetURL("truncated-headers");
530 EXPECT_FALSE(ConnectAndWait(ws_url));
531}
532
David Benjamin51eeec92021-09-21 03:56:36533// Regression test for crbug.com/455215 "HSTS not applied to WebSocket"
534TEST_F(WebSocketEndToEndTest, HstsHttpsToWebSocket) {
535 EmbeddedTestServer https_server(net::EmbeddedTestServer::Type::TYPE_HTTPS);
536 https_server.SetSSLConfig(
537 net::EmbeddedTestServer::CERT_COMMON_NAME_IS_DOMAIN);
538 https_server.ServeFilesFromSourceDirectory("net/data/url_request_unittest");
539
540 SpawnedTestServer::SSLOptions ssl_options(
541 SpawnedTestServer::SSLOptions::CERT_COMMON_NAME_IS_DOMAIN);
542 SpawnedTestServer wss_server(SpawnedTestServer::TYPE_WSS, ssl_options,
543 GetWebSocketTestDataDirectory());
544
545 ASSERT_TRUE(https_server.Start());
546 ASSERT_TRUE(wss_server.Start());
547 InitialiseContext();
548 // Set HSTS via https:
549 TestDelegate delegate;
550 GURL https_page = https_server.GetURL("/hsts-headers.html");
Yutaka Hirano5e97e072022-02-04 07:52:52551 std::unique_ptr<URLRequest> request(context_->CreateRequest(
David Benjamin51eeec92021-09-21 03:56:36552 https_page, DEFAULT_PRIORITY, &delegate, TRAFFIC_ANNOTATION_FOR_TESTS));
553 request->Start();
554 delegate.RunUntilComplete();
555 EXPECT_EQ(OK, delegate.request_status());
556
557 // Check HSTS with ws:
558 // Change the scheme from wss: to ws: to verify that it is switched back.
559 GURL ws_url = ReplaceUrlScheme(wss_server.GetURL(kEchoServer), "ws");
560 EXPECT_TRUE(ConnectAndWait(ws_url));
561}
562
563TEST_F(WebSocketEndToEndTest, HstsWebSocketToHttps) {
564 EmbeddedTestServer https_server(net::EmbeddedTestServer::Type::TYPE_HTTPS);
565 https_server.SetSSLConfig(
566 net::EmbeddedTestServer::CERT_COMMON_NAME_IS_DOMAIN);
567 https_server.ServeFilesFromSourceDirectory("net/data/url_request_unittest");
568
569 SpawnedTestServer::SSLOptions ssl_options(
570 SpawnedTestServer::SSLOptions::CERT_COMMON_NAME_IS_DOMAIN);
571 SpawnedTestServer wss_server(SpawnedTestServer::TYPE_WSS, ssl_options,
572 GetWebSocketTestDataDirectory());
573 ASSERT_TRUE(https_server.Start());
574 ASSERT_TRUE(wss_server.Start());
575 InitialiseContext();
576 // Set HSTS via wss:
577 GURL wss_url = wss_server.GetURL("set-hsts");
578 EXPECT_TRUE(ConnectAndWait(wss_url));
579
580 // Verify via http:
581 TestDelegate delegate;
582 GURL http_page =
583 ReplaceUrlScheme(https_server.GetURL("/simple.html"), "http");
Yutaka Hirano5e97e072022-02-04 07:52:52584 std::unique_ptr<URLRequest> request(context_->CreateRequest(
David Benjamin51eeec92021-09-21 03:56:36585 http_page, DEFAULT_PRIORITY, &delegate, TRAFFIC_ANNOTATION_FOR_TESTS));
586 request->Start();
587 delegate.RunUntilComplete();
588 EXPECT_EQ(OK, delegate.request_status());
589 EXPECT_TRUE(request->url().SchemeIs("https"));
590}
591
592TEST_F(WebSocketEndToEndTest, HstsWebSocketToWebSocket) {
593 SpawnedTestServer::SSLOptions ssl_options(
594 SpawnedTestServer::SSLOptions::CERT_COMMON_NAME_IS_DOMAIN);
595 SpawnedTestServer wss_server(SpawnedTestServer::TYPE_WSS, ssl_options,
596 GetWebSocketTestDataDirectory());
597 ASSERT_TRUE(wss_server.Start());
598 InitialiseContext();
599 // Set HSTS via wss:
600 GURL wss_url = wss_server.GetURL("set-hsts");
601 EXPECT_TRUE(ConnectAndWait(wss_url));
602
603 // Verify via wss:
604 GURL ws_url = ReplaceUrlScheme(wss_server.GetURL(kEchoServer), "ws");
605 EXPECT_TRUE(ConnectAndWait(ws_url));
606}
607
ricea5acb1faf72015-03-16 15:34:00608// Regression test for crbug.com/180504 "WebSocket handshake fails when HTTP
609// headers have trailing LWS".
Sergey Ulanov4c786d32017-09-08 22:53:25610TEST_F(WebSocketEndToEndTest, TrailingWhitespace) {
ricea5acb1faf72015-03-16 15:34:00611 SpawnedTestServer ws_server(SpawnedTestServer::TYPE_WS,
ricea5acb1faf72015-03-16 15:34:00612 GetWebSocketTestDataDirectory());
613 ASSERT_TRUE(ws_server.Start());
614
615 GURL ws_url = ws_server.GetURL("trailing-whitespace");
616 sub_protocols_.push_back("sip");
617 EXPECT_TRUE(ConnectAndWait(ws_url));
618 EXPECT_EQ("sip", event_interface_->selected_subprotocol());
619}
620
riceae1d67672015-03-19 10:10:17621// This is a regression test for crbug.com/169448 "WebSockets should support
622// header continuations"
623// TODO(ricea): HTTP continuation headers have been deprecated by RFC7230. If
624// support for continuation headers is removed from Chrome, then this test will
625// break and should be removed.
Sergey Ulanov4c786d32017-09-08 22:53:25626TEST_F(WebSocketEndToEndTest, HeaderContinuations) {
riceae1d67672015-03-19 10:10:17627 SpawnedTestServer ws_server(SpawnedTestServer::TYPE_WS,
riceae1d67672015-03-19 10:10:17628 GetWebSocketTestDataDirectory());
629 ASSERT_TRUE(ws_server.Start());
630
631 GURL ws_url = ws_server.GetURL("header-continuation");
632
633 EXPECT_TRUE(ConnectAndWait(ws_url));
634 EXPECT_EQ("permessage-deflate; server_max_window_bits=10",
635 event_interface_->extensions());
636}
637
Eric Orthcd71ede2021-09-14 18:18:50638// Test that ws->wss scheme upgrade is supported on receiving a DNS HTTPS
639// record.
David Benjamin51eeec92021-09-21 03:56:36640TEST_F(WebSocketEndToEndTest, DnsSchemeUpgradeSupported) {
Eric Orthcd71ede2021-09-14 18:18:50641 base::test::ScopedFeatureList features;
642 features.InitAndEnableFeatureWithParameters(
643 features::kUseDnsHttpsSvcb, {{"UseDnsHttpsSvcbHttpUpgrade", "true"}});
644
645 SpawnedTestServer wss_server(SpawnedTestServer::TYPE_WSS,
646 SpawnedTestServer::SSLOptions(base::FilePath(
647 FILE_PATH_LITERAL("test_names.pem"))),
648 GetWebSocketTestDataDirectory());
649 ASSERT_TRUE(wss_server.Start());
650
651 GURL wss_url("wss://a.test:" +
652 base::NumberToString(wss_server.host_port_pair().port()) + "/" +
653 kEchoServer);
654 GURL::Replacements replacements;
655 replacements.SetSchemeStr(url::kWsScheme);
656 GURL ws_url = wss_url.ReplaceComponents(replacements);
657
Eric Orthbe86fee2021-10-28 22:31:11658 // Note that due to socket pool behavior, HostResolver will see the ws/wss
659 // requests as http/https.
Yutaka Hirano5e97e072022-02-04 07:52:52660 auto host_resolver = std::make_unique<MockHostResolver>();
Eric Orthbe86fee2021-10-28 22:31:11661 MockHostResolverBase::RuleResolver::RuleKey unencrypted_resolve_key;
662 unencrypted_resolve_key.scheme = url::kHttpScheme;
Yutaka Hirano5e97e072022-02-04 07:52:52663 host_resolver->rules()->AddRule(std::move(unencrypted_resolve_key),
664 ERR_DNS_NAME_HTTPS_ONLY);
Eric Orthbe86fee2021-10-28 22:31:11665 MockHostResolverBase::RuleResolver::RuleKey encrypted_resolve_key;
666 encrypted_resolve_key.scheme = url::kHttpsScheme;
Yutaka Hirano5e97e072022-02-04 07:52:52667 host_resolver->rules()->AddRule(std::move(encrypted_resolve_key),
668 "127.0.0.1");
669 context_builder_->set_host_resolver(std::move(host_resolver));
Eric Orthcd71ede2021-09-14 18:18:50670
671 EXPECT_TRUE(ConnectAndWait(ws_url));
672
673 // Expect request to have reached the server using the upgraded URL.
674 EXPECT_EQ(event_interface_->response()->url, wss_url);
675}
676
David Benjamin9f47d662022-05-13 21:09:02677// Test that wss connections can use HostResolverEndpointResults from DNS.
678TEST_F(WebSocketEndToEndTest, HostResolverEndpointResult) {
679 base::test::ScopedFeatureList features;
680 features.InitAndEnableFeature(features::kUseDnsHttpsSvcb);
681
682 SpawnedTestServer wss_server(SpawnedTestServer::TYPE_WSS,
683 SpawnedTestServer::SSLOptions(base::FilePath(
684 FILE_PATH_LITERAL("test_names.pem"))),
685 GetWebSocketTestDataDirectory());
686 ASSERT_TRUE(wss_server.Start());
687
688 uint16_t port = wss_server.host_port_pair().port();
689 GURL wss_url("wss://a.test:" + base::NumberToString(port) + "/" +
690 kEchoServer);
691
692 auto host_resolver = std::make_unique<MockHostResolver>();
693 MockHostResolverBase::RuleResolver::RuleKey resolve_key;
694 // The DNS query itself is made with the https scheme rather than wss.
695 resolve_key.scheme = url::kHttpsScheme;
696 resolve_key.hostname_pattern = "a.test";
697 resolve_key.port = port;
698 HostResolverEndpointResult result;
699 result.ip_endpoints = {IPEndPoint(IPAddress::IPv4Localhost(), port)};
700 result.metadata.supported_protocol_alpns = {"http/1.1"};
701 host_resolver->rules()->AddRule(std::move(resolve_key), std::vector{result});
702 context_builder_->set_host_resolver(std::move(host_resolver));
703
704 EXPECT_TRUE(ConnectAndWait(wss_url));
705
706 // Expect request to have reached the server using the upgraded URL.
707 EXPECT_EQ(event_interface_->response()->url, wss_url);
708}
709
710// Test that wss connections can use EncryptedClientHello.
711TEST_F(WebSocketEndToEndTest, EncryptedClientHello) {
712 base::test::ScopedFeatureList features;
713 features.InitWithFeatures(
714 {features::kUseDnsHttpsSvcb, features::kEncryptedClientHello}, {});
715
716 // SpawnedTestServer does not support ECH, while EmbeddedTestServer does not
717 // support WebSockets (https://crbug.com/1281277). Until that is fixed, test
718 // ECH by configuring a non-WebSockets HTTPS server. The WebSockets handshake
719 // will fail, but getting that far tests that ECH worked.
720
721 // Configure a test server that speaks ECH.
722 static constexpr char kRealName[] = "secret.example";
723 static constexpr char kPublicName[] = "public.example";
724 EmbeddedTestServer::ServerCertificateConfig server_cert_config;
725 server_cert_config.dns_names = {kRealName};
726 SSLServerConfig ssl_server_config;
727 std::vector<uint8_t> ech_config_list;
728 ssl_server_config.ech_keys =
729 MakeTestEchKeys(kPublicName, /*max_name_len=*/128, &ech_config_list);
730 ASSERT_TRUE(ssl_server_config.ech_keys);
731
732 EmbeddedTestServer test_server(EmbeddedTestServer::TYPE_HTTPS);
733 test_server.SetSSLConfig(server_cert_config, ssl_server_config);
734 ASSERT_TRUE(test_server.Start());
735
736 GURL https_url = test_server.GetURL(kRealName, "/");
737 GURL::Replacements replacements;
738 replacements.SetSchemeStr(url::kWssScheme);
739 GURL wss_url = https_url.ReplaceComponents(replacements);
740
741 auto host_resolver = std::make_unique<MockHostResolver>();
742 MockHostResolverBase::RuleResolver::RuleKey resolve_key;
743 // The DNS query itself is made with the https scheme rather than wss.
744 resolve_key.scheme = url::kHttpsScheme;
745 resolve_key.hostname_pattern = wss_url.host();
746 resolve_key.port = wss_url.IntPort();
747 HostResolverEndpointResult result;
748 result.ip_endpoints = {
749 IPEndPoint(IPAddress::IPv4Localhost(), wss_url.IntPort())};
750 result.metadata.supported_protocol_alpns = {"http/1.1"};
751 result.metadata.ech_config_list = ech_config_list;
752 host_resolver->rules()->AddRule(std::move(resolve_key), std::vector{result});
753 context_builder_->set_host_resolver(std::move(host_resolver));
754
755 EXPECT_FALSE(ConnectAndWait(wss_url));
756 EXPECT_EQ("Error during WebSocket handshake: Unexpected response code: 404",
757 event_interface_->failure_message());
758}
ricea433bdab2015-01-26 07:25:37759} // namespace
760
761} // namespace net