blob: 87beb9f35a30a6d57a5993fac541daae851f1574 [file] [log] [blame]
ricea433bdab2015-01-26 07:25:371// Copyright 2014 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5// End-to-end tests for WebSocket.
6//
7// A python server is (re)started for each test, which is moderately
8// inefficient. However, it makes these tests a good fit for scenarios which
9// require special server configurations.
10
tfarina8a2c66c22015-10-13 19:14:4911#include <stdint.h>
ryansturm4bab06832016-03-03 23:41:0712
danakj9c5cab52016-04-16 00:54:3313#include <memory>
ricea433bdab2015-01-26 07:25:3714#include <string>
Adam Rice5b4a3d82018-08-02 15:28:4315#include <utility>
ricea433bdab2015-01-26 07:25:3716
17#include "base/bind.h"
18#include "base/bind_helpers.h"
19#include "base/callback.h"
skyostil4891b25b2015-06-11 11:43:4520#include "base/location.h"
Avi Drissman13fc8932015-12-20 04:40:4621#include "base/macros.h"
danakj9c5cab52016-04-16 00:54:3322#include "base/memory/ptr_util.h"
Bence Béky65623972018-03-05 15:31:5623#include "base/memory/scoped_refptr.h"
ricea433bdab2015-01-26 07:25:3724#include "base/run_loop.h"
skyostil4891b25b2015-06-11 11:43:4525#include "base/single_thread_task_runner.h"
Adam Rice5b4a3d82018-08-02 15:28:4326#include "base/strings/strcat.h"
Adam Ricecb76ac62015-02-20 05:33:2527#include "base/strings/string_piece.h"
Adam Rice5b4a3d82018-08-02 15:28:4328#include "base/strings/stringprintf.h"
gabf767595f2016-05-11 18:50:3529#include "base/threading/thread_task_runner_handle.h"
Sergey Ulanova337dcd2017-09-08 20:53:1430#include "build/build_config.h"
ricea433bdab2015-01-26 07:25:3731#include "net/base/auth.h"
Adam Rice5b4a3d82018-08-02 15:28:4332#include "net/base/host_port_pair.h"
Tsuyoshi Horo01faed62019-02-20 22:11:3733#include "net/base/ip_endpoint.h"
ryansturm7de050c2016-02-23 00:10:2134#include "net/base/proxy_delegate.h"
Adam Rice5b4a3d82018-08-02 15:28:4335#include "net/base/url_util.h"
Yutaka Hirano2f65eec2018-05-23 01:58:2236#include "net/http/http_request_headers.h"
Adam Rice5b4a3d82018-08-02 15:28:4337#include "net/log/net_log.h"
38#include "net/proxy_resolution/proxy_config.h"
39#include "net/proxy_resolution/proxy_config_service.h"
40#include "net/proxy_resolution/proxy_config_service_fixed.h"
41#include "net/proxy_resolution/proxy_config_with_annotation.h"
42#include "net/proxy_resolution/proxy_info.h"
Lily Houghtonffe89daa02018-03-09 18:30:0343#include "net/proxy_resolution/proxy_resolution_service.h"
tommycli59a63432015-11-06 00:10:5544#include "net/test/embedded_test_server/embedded_test_server.h"
Adam Rice5b4a3d82018-08-02 15:28:4345#include "net/test/embedded_test_server/http_request.h"
46#include "net/test/embedded_test_server/http_response.h"
ricea433bdab2015-01-26 07:25:3747#include "net/test/spawned_test_server/spawned_test_server.h"
rsleevia69c79a2016-06-22 03:28:4348#include "net/test/test_data_directory.h"
Gabriel Charettec7108742019-08-23 03:31:4049#include "net/test/test_with_task_environment.h"
rhalavati9ebaba7e2017-04-27 06:16:2950#include "net/traffic_annotation/network_traffic_annotation_test_helper.h"
Adam Rice5b4a3d82018-08-02 15:28:4351#include "net/url_request/url_request.h"
52#include "net/url_request/url_request_context.h"
ricea433bdab2015-01-26 07:25:3753#include "net/url_request/url_request_test_util.h"
54#include "net/websockets/websocket_channel.h"
55#include "net/websockets/websocket_event_interface.h"
56#include "testing/gtest/include/gtest/gtest.h"
Adam Rice5b4a3d82018-08-02 15:28:4357#include "url/gurl.h"
mkwst4997ce82015-07-25 12:00:0558#include "url/origin.h"
ricea433bdab2015-01-26 07:25:3759
60namespace net {
61
yhirano4a593832016-10-24 18:58:2262class URLRequest;
63
ricea433bdab2015-01-26 07:25:3764namespace {
65
Adam Rice5b4a3d82018-08-02 15:28:4366using test_server::BasicHttpResponse;
67using test_server::HttpRequest;
68using test_server::HttpResponse;
69
ricea433bdab2015-01-26 07:25:3770static const char kEchoServer[] = "echo-with-no-extension";
71
Adam Ricecb76ac62015-02-20 05:33:2572// Simplify changing URL schemes.
73GURL ReplaceUrlScheme(const GURL& in_url, const base::StringPiece& scheme) {
74 GURL::Replacements replacements;
75 replacements.SetSchemeStr(scheme);
76 return in_url.ReplaceComponents(replacements);
77}
78
ricea433bdab2015-01-26 07:25:3779// An implementation of WebSocketEventInterface that waits for and records the
80// results of the connect.
81class ConnectTestingEventInterface : public WebSocketEventInterface {
82 public:
83 ConnectTestingEventInterface();
84
85 void WaitForResponse();
86
87 bool failed() const { return failed_; }
88
89 // Only set if the handshake failed, otherwise empty.
90 std::string failure_message() const;
91
92 std::string selected_subprotocol() const;
93
94 std::string extensions() const;
95
96 // Implementation of WebSocketEventInterface.
yhirano4a593832016-10-24 18:58:2297 void OnCreateURLRequest(URLRequest* request) override {}
98
Yutaka Hirano4165de92018-04-10 11:46:4999 void OnAddChannelResponse(const std::string& selected_subprotocol,
Yoichi Osato1bcffbc2019-10-30 03:17:31100 const std::string& extensions,
101 int64_t send_flow_control_quota) override;
ricea433bdab2015-01-26 07:25:37102
Yutaka Hirano4165de92018-04-10 11:46:49103 void OnDataFrame(bool fin,
104 WebSocketMessageType type,
Yutaka Hirano76aacb202019-09-05 16:36:56105 base::span<const char> payload) override;
ricea433bdab2015-01-26 07:25:37106
Yoichi Osatofcaa2a22019-08-28 08:22:36107 bool HasPendingDataFrames() override { return false; }
108
Yoichi Osatob088adc2019-06-06 05:52:19109 void OnSendFlowControlQuotaAdded(int64_t quota) override;
ricea433bdab2015-01-26 07:25:37110
Yutaka Hirano4165de92018-04-10 11:46:49111 void OnClosingHandshake() override;
ricea433bdab2015-01-26 07:25:37112
Yutaka Hirano4165de92018-04-10 11:46:49113 void OnDropChannel(bool was_clean,
114 uint16_t code,
115 const std::string& reason) override;
ricea433bdab2015-01-26 07:25:37116
Yutaka Hirano4165de92018-04-10 11:46:49117 void OnFailChannel(const std::string& message) override;
ricea433bdab2015-01-26 07:25:37118
Yutaka Hirano4165de92018-04-10 11:46:49119 void OnStartOpeningHandshake(
danakj9c5cab52016-04-16 00:54:33120 std::unique_ptr<WebSocketHandshakeRequestInfo> request) override;
ricea433bdab2015-01-26 07:25:37121
Yutaka Hirano4165de92018-04-10 11:46:49122 void OnFinishOpeningHandshake(
danakj9c5cab52016-04-16 00:54:33123 std::unique_ptr<WebSocketHandshakeResponseInfo> response) override;
ricea433bdab2015-01-26 07:25:37124
Yutaka Hirano4165de92018-04-10 11:46:49125 void OnSSLCertificateError(
danakj9c5cab52016-04-16 00:54:33126 std::unique_ptr<SSLErrorCallbacks> ssl_error_callbacks,
ricea433bdab2015-01-26 07:25:37127 const GURL& url,
Emily Starkd9df3d32019-04-29 17:54:57128 int net_error,
ricea433bdab2015-01-26 07:25:37129 const SSLInfo& ssl_info,
130 bool fatal) override;
131
Emily Starkf2c9bbd2019-04-09 17:08:58132 int OnAuthRequired(const AuthChallengeInfo& auth_info,
Yutaka Hirano70fa25912018-06-06 05:26:54133 scoped_refptr<HttpResponseHeaders> response_headers,
Tsuyoshi Horo01faed62019-02-20 22:11:37134 const IPEndPoint& remote_endpoint,
Yutaka Hirano70fa25912018-06-06 05:26:54135 base::OnceCallback<void(const AuthCredentials*)> callback,
136 base::Optional<AuthCredentials>* credentials) override;
137
ricea433bdab2015-01-26 07:25:37138 private:
139 void QuitNestedEventLoop();
140
141 // failed_ is true if the handshake failed (ie. OnFailChannel was called).
142 bool failed_;
143 std::string selected_subprotocol_;
144 std::string extensions_;
145 std::string failure_message_;
146 base::RunLoop run_loop_;
147
148 DISALLOW_COPY_AND_ASSIGN(ConnectTestingEventInterface);
149};
150
tyoshinoc06da562015-03-06 06:02:42151ConnectTestingEventInterface::ConnectTestingEventInterface() : failed_(false) {
ricea433bdab2015-01-26 07:25:37152}
153
154void ConnectTestingEventInterface::WaitForResponse() {
155 run_loop_.Run();
156}
157
158std::string ConnectTestingEventInterface::failure_message() const {
159 return failure_message_;
160}
161
162std::string ConnectTestingEventInterface::selected_subprotocol() const {
163 return selected_subprotocol_;
164}
165
166std::string ConnectTestingEventInterface::extensions() const {
167 return extensions_;
168}
169
Yutaka Hirano4165de92018-04-10 11:46:49170void ConnectTestingEventInterface::OnAddChannelResponse(
ricea433bdab2015-01-26 07:25:37171 const std::string& selected_subprotocol,
Yoichi Osato1bcffbc2019-10-30 03:17:31172 const std::string& extensions,
173 int64_t send_flow_control_quota) {
ricea433bdab2015-01-26 07:25:37174 selected_subprotocol_ = selected_subprotocol;
175 extensions_ = extensions;
176 QuitNestedEventLoop();
ricea433bdab2015-01-26 07:25:37177}
178
Yutaka Hirano4165de92018-04-10 11:46:49179void ConnectTestingEventInterface::OnDataFrame(bool fin,
180 WebSocketMessageType type,
Yutaka Hirano76aacb202019-09-05 16:36:56181 base::span<const char> payload) {
182}
ricea433bdab2015-01-26 07:25:37183
Yoichi Osatob088adc2019-06-06 05:52:19184void ConnectTestingEventInterface::OnSendFlowControlQuotaAdded(int64_t quota) {}
ricea433bdab2015-01-26 07:25:37185
Yutaka Hirano4165de92018-04-10 11:46:49186void ConnectTestingEventInterface::OnClosingHandshake() {}
ricea433bdab2015-01-26 07:25:37187
Yutaka Hirano4165de92018-04-10 11:46:49188void ConnectTestingEventInterface::OnDropChannel(bool was_clean,
189 uint16_t code,
190 const std::string& reason) {}
ricea433bdab2015-01-26 07:25:37191
Yutaka Hirano4165de92018-04-10 11:46:49192void ConnectTestingEventInterface::OnFailChannel(const std::string& message) {
ricea433bdab2015-01-26 07:25:37193 failed_ = true;
194 failure_message_ = message;
195 QuitNestedEventLoop();
ricea433bdab2015-01-26 07:25:37196}
197
Yutaka Hirano4165de92018-04-10 11:46:49198void ConnectTestingEventInterface::OnStartOpeningHandshake(
199 std::unique_ptr<WebSocketHandshakeRequestInfo> request) {}
ricea433bdab2015-01-26 07:25:37200
Yutaka Hirano4165de92018-04-10 11:46:49201void ConnectTestingEventInterface::OnFinishOpeningHandshake(
202 std::unique_ptr<WebSocketHandshakeResponseInfo> response) {}
ricea433bdab2015-01-26 07:25:37203
Yutaka Hirano4165de92018-04-10 11:46:49204void ConnectTestingEventInterface::OnSSLCertificateError(
danakj9c5cab52016-04-16 00:54:33205 std::unique_ptr<SSLErrorCallbacks> ssl_error_callbacks,
ricea433bdab2015-01-26 07:25:37206 const GURL& url,
Emily Starkd9df3d32019-04-29 17:54:57207 int net_error,
ricea433bdab2015-01-26 07:25:37208 const SSLInfo& ssl_info,
209 bool fatal) {
skyostil4891b25b2015-06-11 11:43:45210 base::ThreadTaskRunnerHandle::Get()->PostTask(
kylecharf4fe5172019-02-15 18:53:49211 FROM_HERE, base::BindOnce(&SSLErrorCallbacks::CancelSSLRequest,
212 base::Owned(ssl_error_callbacks.release()),
213 ERR_SSL_PROTOCOL_ERROR, &ssl_info));
ricea433bdab2015-01-26 07:25:37214}
215
Yutaka Hirano70fa25912018-06-06 05:26:54216int ConnectTestingEventInterface::OnAuthRequired(
Emily Starkf2c9bbd2019-04-09 17:08:58217 const AuthChallengeInfo& auth_info,
Yutaka Hirano70fa25912018-06-06 05:26:54218 scoped_refptr<HttpResponseHeaders> response_headers,
Tsuyoshi Horo01faed62019-02-20 22:11:37219 const IPEndPoint& remote_endpoint,
Yutaka Hirano70fa25912018-06-06 05:26:54220 base::OnceCallback<void(const AuthCredentials*)> callback,
221 base::Optional<AuthCredentials>* credentials) {
222 *credentials = base::nullopt;
223 return OK;
224}
225
ricea433bdab2015-01-26 07:25:37226void ConnectTestingEventInterface::QuitNestedEventLoop() {
227 run_loop_.Quit();
228}
229
230// A subclass of TestNetworkDelegate that additionally implements the
231// OnResolveProxy callback and records the information passed to it.
ryansturm7de050c2016-02-23 00:10:21232class TestProxyDelegateWithProxyInfo : public ProxyDelegate {
ricea433bdab2015-01-26 07:25:37233 public:
Chris Watkins28c2fdd2017-11-30 06:06:52234 TestProxyDelegateWithProxyInfo() = default;
ricea433bdab2015-01-26 07:25:37235
236 struct ResolvedProxyInfo {
237 GURL url;
238 ProxyInfo proxy_info;
239 };
240
241 const ResolvedProxyInfo& resolved_proxy_info() const {
242 return resolved_proxy_info_;
243 }
244
245 protected:
246 void OnResolveProxy(const GURL& url,
ryansturm4bab06832016-03-03 23:41:07247 const std::string& method,
Reilly Grantb414ace72017-11-14 23:03:22248 const ProxyRetryInfoMap& proxy_retry_info,
ricea433bdab2015-01-26 07:25:37249 ProxyInfo* result) override {
250 resolved_proxy_info_.url = url;
251 resolved_proxy_info_.proxy_info = *result;
252 }
253
ryansturm7de050c2016-02-23 00:10:21254 void OnFallback(const ProxyServer& bad_proxy, int net_error) override {}
ryansturm7de050c2016-02-23 00:10:21255
Wojciech Dzierżanowskic2704042019-02-07 20:54:28256 void OnBeforeHttp1TunnelRequest(const ProxyServer& proxy_server,
257 HttpRequestHeaders* extra_headers) override {}
Wojciech Dzierżanowski1f823562019-01-18 11:26:00258
Wojciech Dzierżanowskic2704042019-02-07 20:54:28259 Error OnHttp1TunnelHeadersReceived(
Wojciech Dzierżanowski1f823562019-01-18 11:26:00260 const ProxyServer& proxy_server,
261 const HttpResponseHeaders& response_headers) override {
262 return OK;
263 }
264
ricea433bdab2015-01-26 07:25:37265 private:
266 ResolvedProxyInfo resolved_proxy_info_;
267
ryansturm7de050c2016-02-23 00:10:21268 DISALLOW_COPY_AND_ASSIGN(TestProxyDelegateWithProxyInfo);
ricea433bdab2015-01-26 07:25:37269};
270
Gabriel Charette694c3c332019-08-19 14:53:05271class WebSocketEndToEndTest : public TestWithTaskEnvironment {
ricea433bdab2015-01-26 07:25:37272 protected:
273 WebSocketEndToEndTest()
Adam Ricecb76ac62015-02-20 05:33:25274 : event_interface_(),
Bence Béky65623972018-03-05 15:31:56275 proxy_delegate_(std::make_unique<TestProxyDelegateWithProxyInfo>()),
ricea433bdab2015-01-26 07:25:37276 context_(true),
Adam Ricecb76ac62015-02-20 05:33:25277 channel_(),
ricea433bdab2015-01-26 07:25:37278 initialised_context_(false) {}
279
280 // Initialise the URLRequestContext. Normally done automatically by
281 // ConnectAndWait(). This method is for the use of tests that need the
282 // URLRequestContext initialised before calling ConnectAndWait().
283 void InitialiseContext() {
ricea433bdab2015-01-26 07:25:37284 context_.Init();
Eric Roman3d8546a2018-09-10 17:00:52285 context_.proxy_resolution_service()->SetProxyDelegate(
286 proxy_delegate_.get());
ricea433bdab2015-01-26 07:25:37287 initialised_context_ = true;
288 }
289
290 // Send the connect request to |socket_url| and wait for a response. Returns
291 // true if the handshake succeeded.
292 bool ConnectAndWait(const GURL& socket_url) {
293 if (!initialised_context_) {
294 InitialiseContext();
295 }
Daniel Cheng88186bd52017-10-20 08:14:46296 url::Origin origin = url::Origin::Create(GURL("http://localhost"));
Maks Orlovich8be0e252019-12-09 18:35:49297 net::SiteForCookies site_for_cookies =
298 net::SiteForCookies::FromOrigin(origin);
Ehimare Okoyomon4446d8c2019-10-23 12:47:32299 net::NetworkIsolationKey network_isolation_key(origin, origin);
Adam Rice5b4a3d82018-08-02 15:28:43300 event_interface_ = new ConnectTestingEventInterface();
Bence Béky65623972018-03-05 15:31:56301 channel_ = std::make_unique<WebSocketChannel>(
302 base::WrapUnique(event_interface_), &context_);
alladacef397d2016-06-29 17:52:23303 channel_->SendAddChannelRequest(GURL(socket_url), sub_protocols_, origin,
Ehimare Okoyomon4446d8c2019-10-23 12:47:32304 site_for_cookies, network_isolation_key,
305 HttpRequestHeaders());
ricea433bdab2015-01-26 07:25:37306 event_interface_->WaitForResponse();
307 return !event_interface_->failed();
308 }
309
310 ConnectTestingEventInterface* event_interface_; // owned by channel_
danakj9c5cab52016-04-16 00:54:33311 std::unique_ptr<TestProxyDelegateWithProxyInfo> proxy_delegate_;
ricea433bdab2015-01-26 07:25:37312 TestURLRequestContext context_;
danakj9c5cab52016-04-16 00:54:33313 std::unique_ptr<WebSocketChannel> channel_;
ricea5acb1faf72015-03-16 15:34:00314 std::vector<std::string> sub_protocols_;
ricea433bdab2015-01-26 07:25:37315 bool initialised_context_;
316};
317
ricea433bdab2015-01-26 07:25:37318// Basic test of connectivity. If this test fails, nothing else can be expected
319// to work.
Sergey Ulanov4c786d32017-09-08 22:53:25320TEST_F(WebSocketEndToEndTest, BasicSmokeTest) {
ricea433bdab2015-01-26 07:25:37321 SpawnedTestServer ws_server(SpawnedTestServer::TYPE_WS,
ricea433bdab2015-01-26 07:25:37322 GetWebSocketTestDataDirectory());
323 ASSERT_TRUE(ws_server.Start());
324 EXPECT_TRUE(ConnectAndWait(ws_server.GetURL(kEchoServer)));
325}
326
327// Test for issue crbug.com/433695 "Unencrypted WebSocket connection via
328// authenticated proxy times out"
329// TODO(ricea): Enable this when the issue is fixed.
330TEST_F(WebSocketEndToEndTest, DISABLED_HttpsProxyUnauthedFails) {
331 SpawnedTestServer proxy_server(SpawnedTestServer::TYPE_BASIC_AUTH_PROXY,
ricea433bdab2015-01-26 07:25:37332 base::FilePath());
333 SpawnedTestServer ws_server(SpawnedTestServer::TYPE_WS,
ricea433bdab2015-01-26 07:25:37334 GetWebSocketTestDataDirectory());
335 ASSERT_TRUE(proxy_server.StartInBackground());
336 ASSERT_TRUE(ws_server.StartInBackground());
337 ASSERT_TRUE(proxy_server.BlockUntilStarted());
338 ASSERT_TRUE(ws_server.BlockUntilStarted());
339 std::string proxy_config =
340 "https=" + proxy_server.host_port_pair().ToString();
Lily Houghton8c2f97d2018-01-22 05:06:59341 std::unique_ptr<ProxyResolutionService> proxy_resolution_service(
Ramin Halavatica8d5252018-03-12 05:33:49342 ProxyResolutionService::CreateFixed(proxy_config,
343 TRAFFIC_ANNOTATION_FOR_TESTS));
Lily Houghton8c2f97d2018-01-22 05:06:59344 ASSERT_TRUE(proxy_resolution_service);
345 context_.set_proxy_resolution_service(proxy_resolution_service.get());
ricea433bdab2015-01-26 07:25:37346 EXPECT_FALSE(ConnectAndWait(ws_server.GetURL(kEchoServer)));
347 EXPECT_EQ("Proxy authentication failed", event_interface_->failure_message());
348}
349
Sergey Ulanov4c786d32017-09-08 22:53:25350// These test are not compatible with RemoteTestServer because RemoteTestServer
351// doesn't support TYPE_BASIC_AUTH_PROXY.
352// TODO(ricea): Make these tests work. See crbug.com/441711.
353#if defined(OS_ANDROID) || defined(OS_FUCHSIA)
354#define MAYBE_HttpsWssProxyUnauthedFails DISABLED_HttpsWssProxyUnauthedFails
355#define MAYBE_HttpsProxyUsed DISABLED_HttpsProxyUsed
356#else
357#define MAYBE_HttpsWssProxyUnauthedFails HttpsWssProxyUnauthedFails
358#define MAYBE_HttpsProxyUsed HttpsProxyUsed
359#endif
360
361TEST_F(WebSocketEndToEndTest, MAYBE_HttpsWssProxyUnauthedFails) {
ricea433bdab2015-01-26 07:25:37362 SpawnedTestServer proxy_server(SpawnedTestServer::TYPE_BASIC_AUTH_PROXY,
ricea433bdab2015-01-26 07:25:37363 base::FilePath());
364 SpawnedTestServer wss_server(SpawnedTestServer::TYPE_WSS,
ricea433bdab2015-01-26 07:25:37365 GetWebSocketTestDataDirectory());
366 ASSERT_TRUE(proxy_server.StartInBackground());
367 ASSERT_TRUE(wss_server.StartInBackground());
368 ASSERT_TRUE(proxy_server.BlockUntilStarted());
369 ASSERT_TRUE(wss_server.BlockUntilStarted());
Eric Romanda790f92018-11-07 19:17:15370 ProxyConfig proxy_config;
371 proxy_config.proxy_rules().ParseFromString(
372 "https=" + proxy_server.host_port_pair().ToString());
373 // TODO(https://crbug.com/901896): Don't rely on proxying localhost.
374 proxy_config.proxy_rules().bypass_rules.AddRulesToSubtractImplicit();
375
Lily Houghton8c2f97d2018-01-22 05:06:59376 std::unique_ptr<ProxyResolutionService> proxy_resolution_service(
Eric Romanda790f92018-11-07 19:17:15377 ProxyResolutionService::CreateFixed(ProxyConfigWithAnnotation(
378 proxy_config, TRAFFIC_ANNOTATION_FOR_TESTS)));
Lily Houghton8c2f97d2018-01-22 05:06:59379 ASSERT_TRUE(proxy_resolution_service);
380 context_.set_proxy_resolution_service(proxy_resolution_service.get());
ricea433bdab2015-01-26 07:25:37381 EXPECT_FALSE(ConnectAndWait(wss_server.GetURL(kEchoServer)));
382 EXPECT_EQ("Proxy authentication failed", event_interface_->failure_message());
383}
384
385// Regression test for crbug/426736 "WebSocket connections not using configured
386// system HTTPS Proxy".
Sergey Ulanov4c786d32017-09-08 22:53:25387TEST_F(WebSocketEndToEndTest, MAYBE_HttpsProxyUsed) {
Adam Rice5b4a3d82018-08-02 15:28:43388 SpawnedTestServer proxy_server(SpawnedTestServer::TYPE_PROXY,
ricea433bdab2015-01-26 07:25:37389 base::FilePath());
390 SpawnedTestServer ws_server(SpawnedTestServer::TYPE_WS,
ricea433bdab2015-01-26 07:25:37391 GetWebSocketTestDataDirectory());
392 ASSERT_TRUE(proxy_server.StartInBackground());
393 ASSERT_TRUE(ws_server.StartInBackground());
394 ASSERT_TRUE(proxy_server.BlockUntilStarted());
395 ASSERT_TRUE(ws_server.BlockUntilStarted());
Eric Romanda790f92018-11-07 19:17:15396 ProxyConfig proxy_config;
397 proxy_config.proxy_rules().ParseFromString(
398 "https=" + proxy_server.host_port_pair().ToString() + ";" +
399 "http=" + proxy_server.host_port_pair().ToString());
400 // TODO(https://crbug.com/901896): Don't rely on proxying localhost.
401 proxy_config.proxy_rules().bypass_rules.AddRulesToSubtractImplicit();
402
Lily Houghton8c2f97d2018-01-22 05:06:59403 std::unique_ptr<ProxyResolutionService> proxy_resolution_service(
Eric Romanda790f92018-11-07 19:17:15404 ProxyResolutionService::CreateFixed(ProxyConfigWithAnnotation(
405 proxy_config, TRAFFIC_ANNOTATION_FOR_TESTS)));
Lily Houghton8c2f97d2018-01-22 05:06:59406 context_.set_proxy_resolution_service(proxy_resolution_service.get());
ricea433bdab2015-01-26 07:25:37407 InitialiseContext();
408
ricea433bdab2015-01-26 07:25:37409 GURL ws_url = ws_server.GetURL(kEchoServer);
410 EXPECT_TRUE(ConnectAndWait(ws_url));
ryansturm7de050c2016-02-23 00:10:21411 const TestProxyDelegateWithProxyInfo::ResolvedProxyInfo& info =
412 proxy_delegate_->resolved_proxy_info();
ricea433bdab2015-01-26 07:25:37413 EXPECT_EQ(ws_url, info.url);
414 EXPECT_TRUE(info.proxy_info.is_http());
415}
416
Adam Rice5b4a3d82018-08-02 15:28:43417std::unique_ptr<HttpResponse> ProxyPacHandler(const HttpRequest& request) {
418 GURL url = request.GetURL();
419 EXPECT_EQ(url.path_piece(), "/proxy.pac");
420 EXPECT_TRUE(url.has_query());
421 std::string proxy;
422 EXPECT_TRUE(GetValueForKeyInQuery(url, "proxy", &proxy));
423 auto response = std::make_unique<BasicHttpResponse>();
424 response->set_content_type("application/x-ns-proxy-autoconfig");
425 response->set_content(
426 base::StringPrintf("function FindProxyForURL(url, host) {\n"
427 " return 'PROXY %s';\n"
428 "}\n",
429 proxy.c_str()));
430 return response;
431}
432
433// This tests the proxy.pac resolver that is built into the system. This is not
434// the one that Chrome normally uses. Chrome's normal implementation is defined
435// as a mojo service. It is outside //net and we can't use it from here. This
436// tests the alternative implementations that are selected when the
437// --winhttp-proxy-resolver flag is provided to Chrome. These only exist on OS X
438// and Windows.
439// TODO(ricea): Remove this test if --winhttp-proxy-resolver flag is removed.
440// See crbug.com/644030.
441
442#if defined(OS_WIN) || defined(OS_MACOSX)
443#define MAYBE_ProxyPacUsed ProxyPacUsed
444#else
445#define MAYBE_ProxyPacUsed DISABLED_ProxyPacUsed
446#endif
447
448TEST_F(WebSocketEndToEndTest, MAYBE_ProxyPacUsed) {
449 EmbeddedTestServer proxy_pac_server(net::EmbeddedTestServer::Type::TYPE_HTTP);
450 SpawnedTestServer proxy_server(SpawnedTestServer::TYPE_PROXY,
451 base::FilePath());
452 SpawnedTestServer ws_server(SpawnedTestServer::TYPE_WS,
453 GetWebSocketTestDataDirectory());
454 proxy_pac_server.RegisterRequestHandler(base::BindRepeating(ProxyPacHandler));
455 proxy_server.set_redirect_connect_to_localhost(true);
456
457 ASSERT_TRUE(proxy_pac_server.Start());
458 ASSERT_TRUE(proxy_server.StartInBackground());
459 ASSERT_TRUE(ws_server.StartInBackground());
460 ASSERT_TRUE(proxy_server.BlockUntilStarted());
461 ASSERT_TRUE(ws_server.BlockUntilStarted());
462
463 ProxyConfig proxy_config =
464 ProxyConfig::CreateFromCustomPacURL(proxy_pac_server.GetURL(base::StrCat(
465 {"/proxy.pac?proxy=", proxy_server.host_port_pair().ToString()})));
466 proxy_config.set_pac_mandatory(true);
467 auto proxy_config_service = std::make_unique<ProxyConfigServiceFixed>(
468 ProxyConfigWithAnnotation(proxy_config, TRAFFIC_ANNOTATION_FOR_TESTS));
Adam Rice5b4a3d82018-08-02 15:28:43469 std::unique_ptr<ProxyResolutionService> proxy_resolution_service(
470 ProxyResolutionService::CreateUsingSystemProxyResolver(
Matt Muellerde5dadf2019-11-27 20:11:58471 std::move(proxy_config_service), NetLog::Get()));
Adam Rice5b4a3d82018-08-02 15:28:43472 ASSERT_EQ(ws_server.host_port_pair().host(), "127.0.0.1");
473 context_.set_proxy_resolution_service(proxy_resolution_service.get());
474 InitialiseContext();
475
Eric Romanda790f92018-11-07 19:17:15476 // Use a name other than localhost, since localhost implicitly bypasses the
477 // use of proxy.pac.
Adam Rice5b4a3d82018-08-02 15:28:43478 HostPortPair fake_ws_host_port_pair("stealth-localhost",
479 ws_server.host_port_pair().port());
480
481 GURL ws_url(base::StrCat(
482 {"ws://", fake_ws_host_port_pair.ToString(), "/", kEchoServer}));
483 EXPECT_TRUE(ConnectAndWait(ws_url));
484 const auto& info = proxy_delegate_->resolved_proxy_info();
485 EXPECT_EQ(ws_url, info.url);
486 EXPECT_TRUE(info.proxy_info.is_http());
487 EXPECT_EQ(info.proxy_info.ToPacString(),
488 base::StrCat({"PROXY ", proxy_server.host_port_pair().ToString()}));
489}
490
ricea23c3f942015-02-02 13:35:13491// This is a regression test for crbug.com/408061 Crash in
492// net::WebSocketBasicHandshakeStream::Upgrade.
Sergey Ulanov4c786d32017-09-08 22:53:25493TEST_F(WebSocketEndToEndTest, TruncatedResponse) {
ricea23c3f942015-02-02 13:35:13494 SpawnedTestServer ws_server(SpawnedTestServer::TYPE_WS,
ricea23c3f942015-02-02 13:35:13495 GetWebSocketTestDataDirectory());
496 ASSERT_TRUE(ws_server.Start());
497 InitialiseContext();
498
499 GURL ws_url = ws_server.GetURL("truncated-headers");
500 EXPECT_FALSE(ConnectAndWait(ws_url));
501}
502
Adam Ricecb76ac62015-02-20 05:33:25503// Regression test for crbug.com/455215 "HSTS not applied to WebSocket"
Sergey Ulanov4c786d32017-09-08 22:53:25504TEST_F(WebSocketEndToEndTest, HstsHttpsToWebSocket) {
tommycli59a63432015-11-06 00:10:55505 EmbeddedTestServer https_server(net::EmbeddedTestServer::Type::TYPE_HTTPS);
506 https_server.SetSSLConfig(
507 net::EmbeddedTestServer::CERT_COMMON_NAME_IS_DOMAIN);
508 https_server.ServeFilesFromSourceDirectory("net/data/url_request_unittest");
509
estarka5da76702015-04-09 04:00:16510 SpawnedTestServer::SSLOptions ssl_options(
511 SpawnedTestServer::SSLOptions::CERT_COMMON_NAME_IS_DOMAIN);
Adam Ricecb76ac62015-02-20 05:33:25512 SpawnedTestServer wss_server(SpawnedTestServer::TYPE_WSS, ssl_options,
513 GetWebSocketTestDataDirectory());
estarka5da76702015-04-09 04:00:16514
tommycli59a63432015-11-06 00:10:55515 ASSERT_TRUE(https_server.Start());
516 ASSERT_TRUE(wss_server.Start());
Adam Ricecb76ac62015-02-20 05:33:25517 InitialiseContext();
518 // Set HSTS via https:
519 TestDelegate delegate;
tommycli59a63432015-11-06 00:10:55520 GURL https_page = https_server.GetURL("/hsts-headers.html");
rhalavati9ebaba7e2017-04-27 06:16:29521 std::unique_ptr<URLRequest> request(context_.CreateRequest(
522 https_page, DEFAULT_PRIORITY, &delegate, TRAFFIC_ANNOTATION_FOR_TESTS));
Adam Ricecb76ac62015-02-20 05:33:25523 request->Start();
Wez2a31b222018-06-07 22:07:15524 delegate.RunUntilComplete();
maksim.sisov7f60c8e2016-09-16 19:38:17525 EXPECT_EQ(OK, delegate.request_status());
Adam Ricecb76ac62015-02-20 05:33:25526
527 // Check HSTS with ws:
528 // Change the scheme from wss: to ws: to verify that it is switched back.
529 GURL ws_url = ReplaceUrlScheme(wss_server.GetURL(kEchoServer), "ws");
530 EXPECT_TRUE(ConnectAndWait(ws_url));
531}
532
Sergey Ulanov4c786d32017-09-08 22:53:25533TEST_F(WebSocketEndToEndTest, HstsWebSocketToHttps) {
tommycli59a63432015-11-06 00:10:55534 EmbeddedTestServer https_server(net::EmbeddedTestServer::Type::TYPE_HTTPS);
535 https_server.SetSSLConfig(
536 net::EmbeddedTestServer::CERT_COMMON_NAME_IS_DOMAIN);
537 https_server.ServeFilesFromSourceDirectory("net/data/url_request_unittest");
538
estarka5da76702015-04-09 04:00:16539 SpawnedTestServer::SSLOptions ssl_options(
540 SpawnedTestServer::SSLOptions::CERT_COMMON_NAME_IS_DOMAIN);
Adam Ricecb76ac62015-02-20 05:33:25541 SpawnedTestServer wss_server(SpawnedTestServer::TYPE_WSS, ssl_options,
542 GetWebSocketTestDataDirectory());
tommycli59a63432015-11-06 00:10:55543 ASSERT_TRUE(https_server.Start());
544 ASSERT_TRUE(wss_server.Start());
Adam Ricecb76ac62015-02-20 05:33:25545 InitialiseContext();
546 // Set HSTS via wss:
547 GURL wss_url = wss_server.GetURL("set-hsts");
548 EXPECT_TRUE(ConnectAndWait(wss_url));
549
550 // Verify via http:
551 TestDelegate delegate;
552 GURL http_page =
tommycli59a63432015-11-06 00:10:55553 ReplaceUrlScheme(https_server.GetURL("/simple.html"), "http");
rhalavati9ebaba7e2017-04-27 06:16:29554 std::unique_ptr<URLRequest> request(context_.CreateRequest(
555 http_page, DEFAULT_PRIORITY, &delegate, TRAFFIC_ANNOTATION_FOR_TESTS));
Adam Ricecb76ac62015-02-20 05:33:25556 request->Start();
Wez2a31b222018-06-07 22:07:15557 delegate.RunUntilComplete();
maksim.sisov7f60c8e2016-09-16 19:38:17558 EXPECT_EQ(OK, delegate.request_status());
Adam Ricecb76ac62015-02-20 05:33:25559 EXPECT_TRUE(request->url().SchemeIs("https"));
560}
561
Sergey Ulanov4c786d32017-09-08 22:53:25562TEST_F(WebSocketEndToEndTest, HstsWebSocketToWebSocket) {
estarka5da76702015-04-09 04:00:16563 SpawnedTestServer::SSLOptions ssl_options(
564 SpawnedTestServer::SSLOptions::CERT_COMMON_NAME_IS_DOMAIN);
Adam Ricecb76ac62015-02-20 05:33:25565 SpawnedTestServer wss_server(SpawnedTestServer::TYPE_WSS, ssl_options,
566 GetWebSocketTestDataDirectory());
567 ASSERT_TRUE(wss_server.Start());
568 InitialiseContext();
569 // Set HSTS via wss:
570 GURL wss_url = wss_server.GetURL("set-hsts");
571 EXPECT_TRUE(ConnectAndWait(wss_url));
572
573 // Verify via wss:
574 GURL ws_url = ReplaceUrlScheme(wss_server.GetURL(kEchoServer), "ws");
575 EXPECT_TRUE(ConnectAndWait(ws_url));
576}
577
ricea5acb1faf72015-03-16 15:34:00578// Regression test for crbug.com/180504 "WebSocket handshake fails when HTTP
579// headers have trailing LWS".
Sergey Ulanov4c786d32017-09-08 22:53:25580TEST_F(WebSocketEndToEndTest, TrailingWhitespace) {
ricea5acb1faf72015-03-16 15:34:00581 SpawnedTestServer ws_server(SpawnedTestServer::TYPE_WS,
ricea5acb1faf72015-03-16 15:34:00582 GetWebSocketTestDataDirectory());
583 ASSERT_TRUE(ws_server.Start());
584
585 GURL ws_url = ws_server.GetURL("trailing-whitespace");
586 sub_protocols_.push_back("sip");
587 EXPECT_TRUE(ConnectAndWait(ws_url));
588 EXPECT_EQ("sip", event_interface_->selected_subprotocol());
589}
590
riceae1d67672015-03-19 10:10:17591// This is a regression test for crbug.com/169448 "WebSockets should support
592// header continuations"
593// TODO(ricea): HTTP continuation headers have been deprecated by RFC7230. If
594// support for continuation headers is removed from Chrome, then this test will
595// break and should be removed.
Sergey Ulanov4c786d32017-09-08 22:53:25596TEST_F(WebSocketEndToEndTest, HeaderContinuations) {
riceae1d67672015-03-19 10:10:17597 SpawnedTestServer ws_server(SpawnedTestServer::TYPE_WS,
riceae1d67672015-03-19 10:10:17598 GetWebSocketTestDataDirectory());
599 ASSERT_TRUE(ws_server.Start());
600
601 GURL ws_url = ws_server.GetURL("header-continuation");
602
603 EXPECT_TRUE(ConnectAndWait(ws_url));
604 EXPECT_EQ("permessage-deflate; server_max_window_bits=10",
605 event_interface_->extensions());
606}
607
ricea433bdab2015-01-26 07:25:37608} // namespace
609
610} // namespace net