blob: a92e96a374c1b2f94321220eea3a231eac435f1c [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"
ryansturm7de050c2016-02-23 00:10:2135#include "net/base/proxy_delegate.h"
Adam Rice5b4a3d82018-08-02 15:28:4336#include "net/base/url_util.h"
Yutaka Hirano2f65eec2018-05-23 01:58:2237#include "net/http/http_request_headers.h"
Adam Rice5b4a3d82018-08-02 15:28:4338#include "net/log/net_log.h"
Nicolas Arciniegad2013f92020-02-07 23:00:5639#include "net/proxy_resolution/configured_proxy_resolution_service.h"
Adam Rice5b4a3d82018-08-02 15:28:4340#include "net/proxy_resolution/proxy_config.h"
41#include "net/proxy_resolution/proxy_config_service.h"
42#include "net/proxy_resolution/proxy_config_service_fixed.h"
43#include "net/proxy_resolution/proxy_config_with_annotation.h"
44#include "net/proxy_resolution/proxy_info.h"
tommycli59a63432015-11-06 00:10:5545#include "net/test/embedded_test_server/embedded_test_server.h"
Adam Rice5b4a3d82018-08-02 15:28:4346#include "net/test/embedded_test_server/http_request.h"
47#include "net/test/embedded_test_server/http_response.h"
ricea433bdab2015-01-26 07:25:3748#include "net/test/spawned_test_server/spawned_test_server.h"
rsleevia69c79a2016-06-22 03:28:4349#include "net/test/test_data_directory.h"
Gabriel Charettec7108742019-08-23 03:31:4050#include "net/test/test_with_task_environment.h"
rhalavati9ebaba7e2017-04-27 06:16:2951#include "net/traffic_annotation/network_traffic_annotation_test_helper.h"
Adam Rice5b4a3d82018-08-02 15:28:4352#include "net/url_request/url_request.h"
53#include "net/url_request/url_request_context.h"
ricea433bdab2015-01-26 07:25:3754#include "net/url_request/url_request_test_util.h"
55#include "net/websockets/websocket_channel.h"
56#include "net/websockets/websocket_event_interface.h"
57#include "testing/gtest/include/gtest/gtest.h"
Adam Rice5b4a3d82018-08-02 15:28:4358#include "url/gurl.h"
mkwst4997ce82015-07-25 12:00:0559#include "url/origin.h"
ricea433bdab2015-01-26 07:25:3760
61namespace net {
62
yhirano4a593832016-10-24 18:58:2263class URLRequest;
64
ricea433bdab2015-01-26 07:25:3765namespace {
66
Adam Rice5b4a3d82018-08-02 15:28:4367using test_server::BasicHttpResponse;
68using test_server::HttpRequest;
69using test_server::HttpResponse;
70
ricea433bdab2015-01-26 07:25:3771static const char kEchoServer[] = "echo-with-no-extension";
72
Adam Ricecb76ac62015-02-20 05:33:2573// Simplify changing URL schemes.
74GURL ReplaceUrlScheme(const GURL& in_url, const base::StringPiece& scheme) {
75 GURL::Replacements replacements;
76 replacements.SetSchemeStr(scheme);
77 return in_url.ReplaceComponents(replacements);
78}
79
ricea433bdab2015-01-26 07:25:3780// 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
Yutaka Hirano4165de92018-04-10 11:46:49119 void OnFailChannel(const std::string& message) override;
ricea433bdab2015-01-26 07:25:37120
Yutaka Hirano4165de92018-04-10 11:46:49121 void OnStartOpeningHandshake(
danakj9c5cab52016-04-16 00:54:33122 std::unique_ptr<WebSocketHandshakeRequestInfo> request) override;
ricea433bdab2015-01-26 07:25:37123
Yutaka Hirano4165de92018-04-10 11:46:49124 void OnSSLCertificateError(
danakj9c5cab52016-04-16 00:54:33125 std::unique_ptr<SSLErrorCallbacks> ssl_error_callbacks,
ricea433bdab2015-01-26 07:25:37126 const GURL& url,
Emily Starkd9df3d32019-04-29 17:54:57127 int net_error,
ricea433bdab2015-01-26 07:25:37128 const SSLInfo& ssl_info,
129 bool fatal) override;
130
Emily Starkf2c9bbd2019-04-09 17:08:58131 int OnAuthRequired(const AuthChallengeInfo& auth_info,
Yutaka Hirano70fa25912018-06-06 05:26:54132 scoped_refptr<HttpResponseHeaders> response_headers,
Tsuyoshi Horo01faed62019-02-20 22:11:37133 const IPEndPoint& remote_endpoint,
Yutaka Hirano70fa25912018-06-06 05:26:54134 base::OnceCallback<void(const AuthCredentials*)> callback,
135 base::Optional<AuthCredentials>* credentials) override;
136
ricea433bdab2015-01-26 07:25:37137 private:
138 void QuitNestedEventLoop();
139
140 // failed_ is true if the handshake failed (ie. OnFailChannel was called).
141 bool failed_;
142 std::string selected_subprotocol_;
143 std::string extensions_;
144 std::string failure_message_;
145 base::RunLoop run_loop_;
146
147 DISALLOW_COPY_AND_ASSIGN(ConnectTestingEventInterface);
148};
149
tyoshinoc06da562015-03-06 06:02:42150ConnectTestingEventInterface::ConnectTestingEventInterface() : failed_(false) {
ricea433bdab2015-01-26 07:25:37151}
152
153void ConnectTestingEventInterface::WaitForResponse() {
154 run_loop_.Run();
155}
156
157std::string ConnectTestingEventInterface::failure_message() const {
158 return failure_message_;
159}
160
161std::string ConnectTestingEventInterface::selected_subprotocol() const {
162 return selected_subprotocol_;
163}
164
165std::string ConnectTestingEventInterface::extensions() const {
166 return extensions_;
167}
168
Yutaka Hirano4165de92018-04-10 11:46:49169void ConnectTestingEventInterface::OnAddChannelResponse(
Yoichi Osato1ead61a2020-01-06 04:52:57170 std::unique_ptr<WebSocketHandshakeResponseInfo> response,
ricea433bdab2015-01-26 07:25:37171 const std::string& selected_subprotocol,
Adam Rice250bb012020-05-26 15:56:10172 const std::string& extensions) {
ricea433bdab2015-01-26 07:25:37173 selected_subprotocol_ = selected_subprotocol;
174 extensions_ = extensions;
175 QuitNestedEventLoop();
ricea433bdab2015-01-26 07:25:37176}
177
Yutaka Hirano4165de92018-04-10 11:46:49178void ConnectTestingEventInterface::OnDataFrame(bool fin,
179 WebSocketMessageType type,
Yutaka Hirano76aacb202019-09-05 16:36:56180 base::span<const char> payload) {
181}
ricea433bdab2015-01-26 07:25:37182
Adam Riced0095702020-05-26 06:18:25183void ConnectTestingEventInterface::OnSendDataFrameDone() {}
ricea433bdab2015-01-26 07:25:37184
Yutaka Hirano4165de92018-04-10 11:46:49185void ConnectTestingEventInterface::OnClosingHandshake() {}
ricea433bdab2015-01-26 07:25:37186
Yutaka Hirano4165de92018-04-10 11:46:49187void ConnectTestingEventInterface::OnDropChannel(bool was_clean,
188 uint16_t code,
189 const std::string& reason) {}
ricea433bdab2015-01-26 07:25:37190
Yutaka Hirano4165de92018-04-10 11:46:49191void ConnectTestingEventInterface::OnFailChannel(const std::string& message) {
ricea433bdab2015-01-26 07:25:37192 failed_ = true;
193 failure_message_ = message;
194 QuitNestedEventLoop();
ricea433bdab2015-01-26 07:25:37195}
196
Yutaka Hirano4165de92018-04-10 11:46:49197void ConnectTestingEventInterface::OnStartOpeningHandshake(
198 std::unique_ptr<WebSocketHandshakeRequestInfo> request) {}
ricea433bdab2015-01-26 07:25:37199
Yutaka Hirano4165de92018-04-10 11:46:49200void ConnectTestingEventInterface::OnSSLCertificateError(
danakj9c5cab52016-04-16 00:54:33201 std::unique_ptr<SSLErrorCallbacks> ssl_error_callbacks,
ricea433bdab2015-01-26 07:25:37202 const GURL& url,
Emily Starkd9df3d32019-04-29 17:54:57203 int net_error,
ricea433bdab2015-01-26 07:25:37204 const SSLInfo& ssl_info,
205 bool fatal) {
skyostil4891b25b2015-06-11 11:43:45206 base::ThreadTaskRunnerHandle::Get()->PostTask(
kylecharf4fe5172019-02-15 18:53:49207 FROM_HERE, base::BindOnce(&SSLErrorCallbacks::CancelSSLRequest,
208 base::Owned(ssl_error_callbacks.release()),
209 ERR_SSL_PROTOCOL_ERROR, &ssl_info));
ricea433bdab2015-01-26 07:25:37210}
211
Yutaka Hirano70fa25912018-06-06 05:26:54212int ConnectTestingEventInterface::OnAuthRequired(
Emily Starkf2c9bbd2019-04-09 17:08:58213 const AuthChallengeInfo& auth_info,
Yutaka Hirano70fa25912018-06-06 05:26:54214 scoped_refptr<HttpResponseHeaders> response_headers,
Tsuyoshi Horo01faed62019-02-20 22:11:37215 const IPEndPoint& remote_endpoint,
Yutaka Hirano70fa25912018-06-06 05:26:54216 base::OnceCallback<void(const AuthCredentials*)> callback,
217 base::Optional<AuthCredentials>* credentials) {
218 *credentials = base::nullopt;
219 return OK;
220}
221
ricea433bdab2015-01-26 07:25:37222void ConnectTestingEventInterface::QuitNestedEventLoop() {
223 run_loop_.Quit();
224}
225
226// A subclass of TestNetworkDelegate that additionally implements the
227// OnResolveProxy callback and records the information passed to it.
ryansturm7de050c2016-02-23 00:10:21228class TestProxyDelegateWithProxyInfo : public ProxyDelegate {
ricea433bdab2015-01-26 07:25:37229 public:
Chris Watkins28c2fdd2017-11-30 06:06:52230 TestProxyDelegateWithProxyInfo() = default;
ricea433bdab2015-01-26 07:25:37231
232 struct ResolvedProxyInfo {
233 GURL url;
234 ProxyInfo proxy_info;
235 };
236
237 const ResolvedProxyInfo& resolved_proxy_info() const {
238 return resolved_proxy_info_;
239 }
240
241 protected:
242 void OnResolveProxy(const GURL& url,
ryansturm4bab06832016-03-03 23:41:07243 const std::string& method,
Reilly Grantb414ace72017-11-14 23:03:22244 const ProxyRetryInfoMap& proxy_retry_info,
ricea433bdab2015-01-26 07:25:37245 ProxyInfo* result) override {
246 resolved_proxy_info_.url = url;
247 resolved_proxy_info_.proxy_info = *result;
248 }
249
ryansturm7de050c2016-02-23 00:10:21250 void OnFallback(const ProxyServer& bad_proxy, int net_error) override {}
ryansturm7de050c2016-02-23 00:10:21251
Robert Ogden78d4f9eb2020-03-17 20:56:38252 void OnBeforeTunnelRequest(const ProxyServer& proxy_server,
253 HttpRequestHeaders* extra_headers) override {}
Wojciech Dzierżanowski1f823562019-01-18 11:26:00254
Robert Ogden78d4f9eb2020-03-17 20:56:38255 Error OnTunnelHeadersReceived(
Wojciech Dzierżanowski1f823562019-01-18 11:26:00256 const ProxyServer& proxy_server,
257 const HttpResponseHeaders& response_headers) override {
258 return OK;
259 }
260
ricea433bdab2015-01-26 07:25:37261 private:
262 ResolvedProxyInfo resolved_proxy_info_;
263
ryansturm7de050c2016-02-23 00:10:21264 DISALLOW_COPY_AND_ASSIGN(TestProxyDelegateWithProxyInfo);
ricea433bdab2015-01-26 07:25:37265};
266
Gabriel Charette694c3c332019-08-19 14:53:05267class WebSocketEndToEndTest : public TestWithTaskEnvironment {
ricea433bdab2015-01-26 07:25:37268 protected:
269 WebSocketEndToEndTest()
Adam Ricecb76ac62015-02-20 05:33:25270 : event_interface_(),
Bence Béky65623972018-03-05 15:31:56271 proxy_delegate_(std::make_unique<TestProxyDelegateWithProxyInfo>()),
ricea433bdab2015-01-26 07:25:37272 context_(true),
Adam Ricecb76ac62015-02-20 05:33:25273 channel_(),
ricea433bdab2015-01-26 07:25:37274 initialised_context_(false) {}
275
276 // Initialise the URLRequestContext. Normally done automatically by
277 // ConnectAndWait(). This method is for the use of tests that need the
278 // URLRequestContext initialised before calling ConnectAndWait().
279 void InitialiseContext() {
ricea433bdab2015-01-26 07:25:37280 context_.Init();
Eric Roman3d8546a2018-09-10 17:00:52281 context_.proxy_resolution_service()->SetProxyDelegate(
282 proxy_delegate_.get());
ricea433bdab2015-01-26 07:25:37283 initialised_context_ = true;
284 }
285
286 // Send the connect request to |socket_url| and wait for a response. Returns
287 // true if the handshake succeeded.
288 bool ConnectAndWait(const GURL& socket_url) {
289 if (!initialised_context_) {
290 InitialiseContext();
291 }
Daniel Cheng88186bd52017-10-20 08:14:46292 url::Origin origin = url::Origin::Create(GURL("http://localhost"));
Maks Orlovich8be0e252019-12-09 18:35:49293 net::SiteForCookies site_for_cookies =
294 net::SiteForCookies::FromOrigin(origin);
shivanigithub4e78015f592020-10-21 13:26:23295 IsolationInfo isolation_info =
296 IsolationInfo::Create(IsolationInfo::RequestType::kOther, origin,
297 origin, SiteForCookies::FromOrigin(origin));
Adam Rice5b4a3d82018-08-02 15:28:43298 event_interface_ = new ConnectTestingEventInterface();
Bence Béky65623972018-03-05 15:31:56299 channel_ = std::make_unique<WebSocketChannel>(
300 base::WrapUnique(event_interface_), &context_);
Adam Langleyacbad242020-08-18 15:14:52301 channel_->SendAddChannelRequest(
302 GURL(socket_url), sub_protocols_, origin, site_for_cookies,
303 isolation_info, HttpRequestHeaders(), TRAFFIC_ANNOTATION_FOR_TESTS);
ricea433bdab2015-01-26 07:25:37304 event_interface_->WaitForResponse();
305 return !event_interface_->failed();
306 }
307
308 ConnectTestingEventInterface* event_interface_; // owned by channel_
danakj9c5cab52016-04-16 00:54:33309 std::unique_ptr<TestProxyDelegateWithProxyInfo> proxy_delegate_;
ricea433bdab2015-01-26 07:25:37310 TestURLRequestContext context_;
danakj9c5cab52016-04-16 00:54:33311 std::unique_ptr<WebSocketChannel> channel_;
ricea5acb1faf72015-03-16 15:34:00312 std::vector<std::string> sub_protocols_;
ricea433bdab2015-01-26 07:25:37313 bool initialised_context_;
314};
315
ricea433bdab2015-01-26 07:25:37316// Basic test of connectivity. If this test fails, nothing else can be expected
317// to work.
Sergey Ulanov4c786d32017-09-08 22:53:25318TEST_F(WebSocketEndToEndTest, BasicSmokeTest) {
ricea433bdab2015-01-26 07:25:37319 SpawnedTestServer ws_server(SpawnedTestServer::TYPE_WS,
ricea433bdab2015-01-26 07:25:37320 GetWebSocketTestDataDirectory());
321 ASSERT_TRUE(ws_server.Start());
322 EXPECT_TRUE(ConnectAndWait(ws_server.GetURL(kEchoServer)));
323}
324
325// Test for issue crbug.com/433695 "Unencrypted WebSocket connection via
326// authenticated proxy times out"
327// TODO(ricea): Enable this when the issue is fixed.
328TEST_F(WebSocketEndToEndTest, DISABLED_HttpsProxyUnauthedFails) {
329 SpawnedTestServer proxy_server(SpawnedTestServer::TYPE_BASIC_AUTH_PROXY,
ricea433bdab2015-01-26 07:25:37330 base::FilePath());
331 SpawnedTestServer ws_server(SpawnedTestServer::TYPE_WS,
ricea433bdab2015-01-26 07:25:37332 GetWebSocketTestDataDirectory());
333 ASSERT_TRUE(proxy_server.StartInBackground());
334 ASSERT_TRUE(ws_server.StartInBackground());
335 ASSERT_TRUE(proxy_server.BlockUntilStarted());
336 ASSERT_TRUE(ws_server.BlockUntilStarted());
337 std::string proxy_config =
338 "https=" + proxy_server.host_port_pair().ToString();
Nicolas Arciniega8ec5bfa2020-03-20 05:07:26339 std::unique_ptr<ProxyResolutionService> proxy_resolution_service(
Nicolas Arciniegad2013f92020-02-07 23:00:56340 ConfiguredProxyResolutionService::CreateFixed(
341 proxy_config, TRAFFIC_ANNOTATION_FOR_TESTS));
Lily Houghton8c2f97d2018-01-22 05:06:59342 ASSERT_TRUE(proxy_resolution_service);
343 context_.set_proxy_resolution_service(proxy_resolution_service.get());
ricea433bdab2015-01-26 07:25:37344 EXPECT_FALSE(ConnectAndWait(ws_server.GetURL(kEchoServer)));
345 EXPECT_EQ("Proxy authentication failed", event_interface_->failure_message());
346}
347
Sergey Ulanov4c786d32017-09-08 22:53:25348// These test are not compatible with RemoteTestServer because RemoteTestServer
349// doesn't support TYPE_BASIC_AUTH_PROXY.
350// TODO(ricea): Make these tests work. See crbug.com/441711.
351#if defined(OS_ANDROID) || defined(OS_FUCHSIA)
352#define MAYBE_HttpsWssProxyUnauthedFails DISABLED_HttpsWssProxyUnauthedFails
353#define MAYBE_HttpsProxyUsed DISABLED_HttpsProxyUsed
354#else
355#define MAYBE_HttpsWssProxyUnauthedFails HttpsWssProxyUnauthedFails
356#define MAYBE_HttpsProxyUsed HttpsProxyUsed
357#endif
358
359TEST_F(WebSocketEndToEndTest, MAYBE_HttpsWssProxyUnauthedFails) {
ricea433bdab2015-01-26 07:25:37360 SpawnedTestServer proxy_server(SpawnedTestServer::TYPE_BASIC_AUTH_PROXY,
ricea433bdab2015-01-26 07:25:37361 base::FilePath());
362 SpawnedTestServer wss_server(SpawnedTestServer::TYPE_WSS,
ricea433bdab2015-01-26 07:25:37363 GetWebSocketTestDataDirectory());
364 ASSERT_TRUE(proxy_server.StartInBackground());
365 ASSERT_TRUE(wss_server.StartInBackground());
366 ASSERT_TRUE(proxy_server.BlockUntilStarted());
367 ASSERT_TRUE(wss_server.BlockUntilStarted());
Eric Romanda790f92018-11-07 19:17:15368 ProxyConfig proxy_config;
369 proxy_config.proxy_rules().ParseFromString(
370 "https=" + proxy_server.host_port_pair().ToString());
371 // TODO(https://crbug.com/901896): Don't rely on proxying localhost.
372 proxy_config.proxy_rules().bypass_rules.AddRulesToSubtractImplicit();
373
Nicolas Arciniega8ec5bfa2020-03-20 05:07:26374 std::unique_ptr<ProxyResolutionService> proxy_resolution_service(
Nicolas Arciniegad2013f92020-02-07 23:00:56375 ConfiguredProxyResolutionService::CreateFixed(ProxyConfigWithAnnotation(
Eric Romanda790f92018-11-07 19:17:15376 proxy_config, TRAFFIC_ANNOTATION_FOR_TESTS)));
Lily Houghton8c2f97d2018-01-22 05:06:59377 ASSERT_TRUE(proxy_resolution_service);
378 context_.set_proxy_resolution_service(proxy_resolution_service.get());
ricea433bdab2015-01-26 07:25:37379 EXPECT_FALSE(ConnectAndWait(wss_server.GetURL(kEchoServer)));
380 EXPECT_EQ("Proxy authentication failed", event_interface_->failure_message());
381}
382
383// Regression test for crbug/426736 "WebSocket connections not using configured
384// system HTTPS Proxy".
Sergey Ulanov4c786d32017-09-08 22:53:25385TEST_F(WebSocketEndToEndTest, MAYBE_HttpsProxyUsed) {
Adam Rice5b4a3d82018-08-02 15:28:43386 SpawnedTestServer proxy_server(SpawnedTestServer::TYPE_PROXY,
ricea433bdab2015-01-26 07:25:37387 base::FilePath());
388 SpawnedTestServer ws_server(SpawnedTestServer::TYPE_WS,
ricea433bdab2015-01-26 07:25:37389 GetWebSocketTestDataDirectory());
390 ASSERT_TRUE(proxy_server.StartInBackground());
391 ASSERT_TRUE(ws_server.StartInBackground());
392 ASSERT_TRUE(proxy_server.BlockUntilStarted());
393 ASSERT_TRUE(ws_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 "http=" + proxy_server.host_port_pair().ToString());
398 // TODO(https://crbug.com/901896): Don't rely on proxying localhost.
399 proxy_config.proxy_rules().bypass_rules.AddRulesToSubtractImplicit();
400
Nicolas Arciniega8ec5bfa2020-03-20 05:07:26401 std::unique_ptr<ProxyResolutionService> proxy_resolution_service(
Nicolas Arciniegad2013f92020-02-07 23:00:56402 ConfiguredProxyResolutionService::CreateFixed(ProxyConfigWithAnnotation(
Eric Romanda790f92018-11-07 19:17:15403 proxy_config, TRAFFIC_ANNOTATION_FOR_TESTS)));
Lily Houghton8c2f97d2018-01-22 05:06:59404 context_.set_proxy_resolution_service(proxy_resolution_service.get());
ricea433bdab2015-01-26 07:25:37405 InitialiseContext();
406
ricea433bdab2015-01-26 07:25:37407 GURL ws_url = ws_server.GetURL(kEchoServer);
408 EXPECT_TRUE(ConnectAndWait(ws_url));
ryansturm7de050c2016-02-23 00:10:21409 const TestProxyDelegateWithProxyInfo::ResolvedProxyInfo& info =
410 proxy_delegate_->resolved_proxy_info();
ricea433bdab2015-01-26 07:25:37411 EXPECT_EQ(ws_url, info.url);
412 EXPECT_TRUE(info.proxy_info.is_http());
413}
414
Adam Rice5b4a3d82018-08-02 15:28:43415std::unique_ptr<HttpResponse> ProxyPacHandler(const HttpRequest& request) {
416 GURL url = request.GetURL();
417 EXPECT_EQ(url.path_piece(), "/proxy.pac");
418 EXPECT_TRUE(url.has_query());
419 std::string proxy;
420 EXPECT_TRUE(GetValueForKeyInQuery(url, "proxy", &proxy));
421 auto response = std::make_unique<BasicHttpResponse>();
422 response->set_content_type("application/x-ns-proxy-autoconfig");
423 response->set_content(
424 base::StringPrintf("function FindProxyForURL(url, host) {\n"
425 " return 'PROXY %s';\n"
426 "}\n",
427 proxy.c_str()));
428 return response;
429}
430
431// This tests the proxy.pac resolver that is built into the system. This is not
432// the one that Chrome normally uses. Chrome's normal implementation is defined
433// as a mojo service. It is outside //net and we can't use it from here. This
434// tests the alternative implementations that are selected when the
435// --winhttp-proxy-resolver flag is provided to Chrome. These only exist on OS X
436// and Windows.
437// TODO(ricea): Remove this test if --winhttp-proxy-resolver flag is removed.
438// See crbug.com/644030.
439
Avi Drissman25292af62020-07-29 21:57:11440#if defined(OS_WIN) || defined(OS_APPLE)
Adam Rice5b4a3d82018-08-02 15:28:43441#define MAYBE_ProxyPacUsed ProxyPacUsed
442#else
443#define MAYBE_ProxyPacUsed DISABLED_ProxyPacUsed
444#endif
445
446TEST_F(WebSocketEndToEndTest, MAYBE_ProxyPacUsed) {
447 EmbeddedTestServer proxy_pac_server(net::EmbeddedTestServer::Type::TYPE_HTTP);
448 SpawnedTestServer proxy_server(SpawnedTestServer::TYPE_PROXY,
449 base::FilePath());
450 SpawnedTestServer ws_server(SpawnedTestServer::TYPE_WS,
451 GetWebSocketTestDataDirectory());
452 proxy_pac_server.RegisterRequestHandler(base::BindRepeating(ProxyPacHandler));
453 proxy_server.set_redirect_connect_to_localhost(true);
454
455 ASSERT_TRUE(proxy_pac_server.Start());
456 ASSERT_TRUE(proxy_server.StartInBackground());
457 ASSERT_TRUE(ws_server.StartInBackground());
458 ASSERT_TRUE(proxy_server.BlockUntilStarted());
459 ASSERT_TRUE(ws_server.BlockUntilStarted());
460
461 ProxyConfig proxy_config =
462 ProxyConfig::CreateFromCustomPacURL(proxy_pac_server.GetURL(base::StrCat(
463 {"/proxy.pac?proxy=", proxy_server.host_port_pair().ToString()})));
464 proxy_config.set_pac_mandatory(true);
465 auto proxy_config_service = std::make_unique<ProxyConfigServiceFixed>(
466 ProxyConfigWithAnnotation(proxy_config, TRAFFIC_ANNOTATION_FOR_TESTS));
Nicolas Arciniega8ec5bfa2020-03-20 05:07:26467 std::unique_ptr<ProxyResolutionService> proxy_resolution_service(
Nicolas Arciniegad2013f92020-02-07 23:00:56468 ConfiguredProxyResolutionService::CreateUsingSystemProxyResolver(
Eric Roman3be01ba2020-04-03 21:37:09469 std::move(proxy_config_service), NetLog::Get(),
470 /*quick_check_enabled=*/true));
Adam Rice5b4a3d82018-08-02 15:28:43471 ASSERT_EQ(ws_server.host_port_pair().host(), "127.0.0.1");
472 context_.set_proxy_resolution_service(proxy_resolution_service.get());
473 InitialiseContext();
474
Eric Romanda790f92018-11-07 19:17:15475 // Use a name other than localhost, since localhost implicitly bypasses the
476 // use of proxy.pac.
Adam Rice5b4a3d82018-08-02 15:28:43477 HostPortPair fake_ws_host_port_pair("stealth-localhost",
478 ws_server.host_port_pair().port());
479
480 GURL ws_url(base::StrCat(
481 {"ws://", fake_ws_host_port_pair.ToString(), "/", kEchoServer}));
482 EXPECT_TRUE(ConnectAndWait(ws_url));
483 const auto& info = proxy_delegate_->resolved_proxy_info();
484 EXPECT_EQ(ws_url, info.url);
485 EXPECT_TRUE(info.proxy_info.is_http());
486 EXPECT_EQ(info.proxy_info.ToPacString(),
487 base::StrCat({"PROXY ", proxy_server.host_port_pair().ToString()}));
488}
489
ricea23c3f942015-02-02 13:35:13490// This is a regression test for crbug.com/408061 Crash in
491// net::WebSocketBasicHandshakeStream::Upgrade.
Sergey Ulanov4c786d32017-09-08 22:53:25492TEST_F(WebSocketEndToEndTest, TruncatedResponse) {
ricea23c3f942015-02-02 13:35:13493 SpawnedTestServer ws_server(SpawnedTestServer::TYPE_WS,
ricea23c3f942015-02-02 13:35:13494 GetWebSocketTestDataDirectory());
495 ASSERT_TRUE(ws_server.Start());
496 InitialiseContext();
497
498 GURL ws_url = ws_server.GetURL("truncated-headers");
499 EXPECT_FALSE(ConnectAndWait(ws_url));
500}
501
Adam Ricecb76ac62015-02-20 05:33:25502// Regression test for crbug.com/455215 "HSTS not applied to WebSocket"
Sergey Ulanov4c786d32017-09-08 22:53:25503TEST_F(WebSocketEndToEndTest, HstsHttpsToWebSocket) {
tommycli59a63432015-11-06 00:10:55504 EmbeddedTestServer https_server(net::EmbeddedTestServer::Type::TYPE_HTTPS);
505 https_server.SetSSLConfig(
506 net::EmbeddedTestServer::CERT_COMMON_NAME_IS_DOMAIN);
507 https_server.ServeFilesFromSourceDirectory("net/data/url_request_unittest");
508
estarka5da76702015-04-09 04:00:16509 SpawnedTestServer::SSLOptions ssl_options(
510 SpawnedTestServer::SSLOptions::CERT_COMMON_NAME_IS_DOMAIN);
Adam Ricecb76ac62015-02-20 05:33:25511 SpawnedTestServer wss_server(SpawnedTestServer::TYPE_WSS, ssl_options,
512 GetWebSocketTestDataDirectory());
estarka5da76702015-04-09 04:00:16513
tommycli59a63432015-11-06 00:10:55514 ASSERT_TRUE(https_server.Start());
515 ASSERT_TRUE(wss_server.Start());
Adam Ricecb76ac62015-02-20 05:33:25516 InitialiseContext();
517 // Set HSTS via https:
518 TestDelegate delegate;
tommycli59a63432015-11-06 00:10:55519 GURL https_page = https_server.GetURL("/hsts-headers.html");
rhalavati9ebaba7e2017-04-27 06:16:29520 std::unique_ptr<URLRequest> request(context_.CreateRequest(
521 https_page, DEFAULT_PRIORITY, &delegate, TRAFFIC_ANNOTATION_FOR_TESTS));
Adam Ricecb76ac62015-02-20 05:33:25522 request->Start();
Wez2a31b222018-06-07 22:07:15523 delegate.RunUntilComplete();
maksim.sisov7f60c8e2016-09-16 19:38:17524 EXPECT_EQ(OK, delegate.request_status());
Adam Ricecb76ac62015-02-20 05:33:25525
526 // Check HSTS with ws:
527 // Change the scheme from wss: to ws: to verify that it is switched back.
528 GURL ws_url = ReplaceUrlScheme(wss_server.GetURL(kEchoServer), "ws");
529 EXPECT_TRUE(ConnectAndWait(ws_url));
530}
531
Sergey Ulanov4c786d32017-09-08 22:53:25532TEST_F(WebSocketEndToEndTest, HstsWebSocketToHttps) {
tommycli59a63432015-11-06 00:10:55533 EmbeddedTestServer https_server(net::EmbeddedTestServer::Type::TYPE_HTTPS);
534 https_server.SetSSLConfig(
535 net::EmbeddedTestServer::CERT_COMMON_NAME_IS_DOMAIN);
536 https_server.ServeFilesFromSourceDirectory("net/data/url_request_unittest");
537
estarka5da76702015-04-09 04:00:16538 SpawnedTestServer::SSLOptions ssl_options(
539 SpawnedTestServer::SSLOptions::CERT_COMMON_NAME_IS_DOMAIN);
Adam Ricecb76ac62015-02-20 05:33:25540 SpawnedTestServer wss_server(SpawnedTestServer::TYPE_WSS, ssl_options,
541 GetWebSocketTestDataDirectory());
tommycli59a63432015-11-06 00:10:55542 ASSERT_TRUE(https_server.Start());
543 ASSERT_TRUE(wss_server.Start());
Adam Ricecb76ac62015-02-20 05:33:25544 InitialiseContext();
545 // Set HSTS via wss:
546 GURL wss_url = wss_server.GetURL("set-hsts");
547 EXPECT_TRUE(ConnectAndWait(wss_url));
548
549 // Verify via http:
550 TestDelegate delegate;
551 GURL http_page =
tommycli59a63432015-11-06 00:10:55552 ReplaceUrlScheme(https_server.GetURL("/simple.html"), "http");
rhalavati9ebaba7e2017-04-27 06:16:29553 std::unique_ptr<URLRequest> request(context_.CreateRequest(
554 http_page, DEFAULT_PRIORITY, &delegate, TRAFFIC_ANNOTATION_FOR_TESTS));
Adam Ricecb76ac62015-02-20 05:33:25555 request->Start();
Wez2a31b222018-06-07 22:07:15556 delegate.RunUntilComplete();
maksim.sisov7f60c8e2016-09-16 19:38:17557 EXPECT_EQ(OK, delegate.request_status());
Adam Ricecb76ac62015-02-20 05:33:25558 EXPECT_TRUE(request->url().SchemeIs("https"));
559}
560
Sergey Ulanov4c786d32017-09-08 22:53:25561TEST_F(WebSocketEndToEndTest, HstsWebSocketToWebSocket) {
estarka5da76702015-04-09 04:00:16562 SpawnedTestServer::SSLOptions ssl_options(
563 SpawnedTestServer::SSLOptions::CERT_COMMON_NAME_IS_DOMAIN);
Adam Ricecb76ac62015-02-20 05:33:25564 SpawnedTestServer wss_server(SpawnedTestServer::TYPE_WSS, ssl_options,
565 GetWebSocketTestDataDirectory());
566 ASSERT_TRUE(wss_server.Start());
567 InitialiseContext();
568 // Set HSTS via wss:
569 GURL wss_url = wss_server.GetURL("set-hsts");
570 EXPECT_TRUE(ConnectAndWait(wss_url));
571
572 // Verify via wss:
573 GURL ws_url = ReplaceUrlScheme(wss_server.GetURL(kEchoServer), "ws");
574 EXPECT_TRUE(ConnectAndWait(ws_url));
575}
576
ricea5acb1faf72015-03-16 15:34:00577// Regression test for crbug.com/180504 "WebSocket handshake fails when HTTP
578// headers have trailing LWS".
Sergey Ulanov4c786d32017-09-08 22:53:25579TEST_F(WebSocketEndToEndTest, TrailingWhitespace) {
ricea5acb1faf72015-03-16 15:34:00580 SpawnedTestServer ws_server(SpawnedTestServer::TYPE_WS,
ricea5acb1faf72015-03-16 15:34:00581 GetWebSocketTestDataDirectory());
582 ASSERT_TRUE(ws_server.Start());
583
584 GURL ws_url = ws_server.GetURL("trailing-whitespace");
585 sub_protocols_.push_back("sip");
586 EXPECT_TRUE(ConnectAndWait(ws_url));
587 EXPECT_EQ("sip", event_interface_->selected_subprotocol());
588}
589
riceae1d67672015-03-19 10:10:17590// This is a regression test for crbug.com/169448 "WebSockets should support
591// header continuations"
592// TODO(ricea): HTTP continuation headers have been deprecated by RFC7230. If
593// support for continuation headers is removed from Chrome, then this test will
594// break and should be removed.
Sergey Ulanov4c786d32017-09-08 22:53:25595TEST_F(WebSocketEndToEndTest, HeaderContinuations) {
riceae1d67672015-03-19 10:10:17596 SpawnedTestServer ws_server(SpawnedTestServer::TYPE_WS,
riceae1d67672015-03-19 10:10:17597 GetWebSocketTestDataDirectory());
598 ASSERT_TRUE(ws_server.Start());
599
600 GURL ws_url = ws_server.GetURL("header-continuation");
601
602 EXPECT_TRUE(ConnectAndWait(ws_url));
603 EXPECT_EQ("permessage-deflate; server_max_window_bits=10",
604 event_interface_->extensions());
605}
606
ricea433bdab2015-01-26 07:25:37607} // namespace
608
609} // namespace net