websocket_end_to_end_test.cc 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765
  1. // 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. // End-to-end tests for WebSocket.
  5. //
  6. // A python server is (re)started for each test, which is moderately
  7. // inefficient. However, it makes these tests a good fit for scenarios which
  8. // require special server configurations.
  9. #include <stdint.h>
  10. #include <memory>
  11. #include <string>
  12. #include <utility>
  13. #include "base/bind.h"
  14. #include "base/callback.h"
  15. #include "base/callback_helpers.h"
  16. #include "base/files/file_path.h"
  17. #include "base/location.h"
  18. #include "base/memory/ptr_util.h"
  19. #include "base/memory/raw_ptr.h"
  20. #include "base/memory/scoped_refptr.h"
  21. #include "base/run_loop.h"
  22. #include "base/strings/strcat.h"
  23. #include "base/strings/string_number_conversions.h"
  24. #include "base/strings/string_piece.h"
  25. #include "base/strings/stringprintf.h"
  26. #include "base/task/single_thread_task_runner.h"
  27. #include "base/test/scoped_feature_list.h"
  28. #include "base/threading/thread_task_runner_handle.h"
  29. #include "build/build_config.h"
  30. #include "net/base/auth.h"
  31. #include "net/base/features.h"
  32. #include "net/base/host_port_pair.h"
  33. #include "net/base/ip_endpoint.h"
  34. #include "net/base/isolation_info.h"
  35. #include "net/base/net_errors.h"
  36. #include "net/base/proxy_delegate.h"
  37. #include "net/base/url_util.h"
  38. #include "net/cert/ct_policy_status.h"
  39. #include "net/dns/mock_host_resolver.h"
  40. #include "net/http/http_request_headers.h"
  41. #include "net/http/transport_security_state.h"
  42. #include "net/log/net_log.h"
  43. #include "net/proxy_resolution/configured_proxy_resolution_service.h"
  44. #include "net/proxy_resolution/proxy_config.h"
  45. #include "net/proxy_resolution/proxy_config_service.h"
  46. #include "net/proxy_resolution/proxy_config_service_fixed.h"
  47. #include "net/proxy_resolution/proxy_config_with_annotation.h"
  48. #include "net/proxy_resolution/proxy_info.h"
  49. #include "net/test/embedded_test_server/embedded_test_server.h"
  50. #include "net/test/embedded_test_server/http_request.h"
  51. #include "net/test/embedded_test_server/http_response.h"
  52. #include "net/test/spawned_test_server/spawned_test_server.h"
  53. #include "net/test/ssl_test_util.h"
  54. #include "net/test/test_data_directory.h"
  55. #include "net/test/test_with_task_environment.h"
  56. #include "net/traffic_annotation/network_traffic_annotation_test_helper.h"
  57. #include "net/url_request/url_request.h"
  58. #include "net/url_request/url_request_context.h"
  59. #include "net/url_request/url_request_context_builder.h"
  60. #include "net/url_request/url_request_test_util.h"
  61. #include "net/websockets/websocket_channel.h"
  62. #include "net/websockets/websocket_event_interface.h"
  63. #include "testing/gtest/include/gtest/gtest.h"
  64. #include "url/gurl.h"
  65. #include "url/origin.h"
  66. #include "url/url_constants.h"
  67. namespace net {
  68. class URLRequest;
  69. namespace {
  70. using test_server::BasicHttpResponse;
  71. using test_server::HttpRequest;
  72. using test_server::HttpResponse;
  73. static const char kEchoServer[] = "echo-with-no-extension";
  74. // Simplify changing URL schemes.
  75. GURL ReplaceUrlScheme(const GURL& in_url, const base::StringPiece& scheme) {
  76. GURL::Replacements replacements;
  77. replacements.SetSchemeStr(scheme);
  78. return in_url.ReplaceComponents(replacements);
  79. }
  80. // An implementation of WebSocketEventInterface that waits for and records the
  81. // results of the connect.
  82. class ConnectTestingEventInterface : public WebSocketEventInterface {
  83. public:
  84. ConnectTestingEventInterface();
  85. ConnectTestingEventInterface(const ConnectTestingEventInterface&) = delete;
  86. ConnectTestingEventInterface& operator=(const ConnectTestingEventInterface&) =
  87. delete;
  88. void WaitForResponse();
  89. bool failed() const { return failed_; }
  90. const std::unique_ptr<WebSocketHandshakeResponseInfo>& response() const {
  91. return response_;
  92. }
  93. // Only set if the handshake failed, otherwise empty.
  94. std::string failure_message() const;
  95. std::string selected_subprotocol() const;
  96. std::string extensions() const;
  97. // Implementation of WebSocketEventInterface.
  98. void OnCreateURLRequest(URLRequest* request) override {}
  99. void OnAddChannelResponse(
  100. std::unique_ptr<WebSocketHandshakeResponseInfo> response,
  101. const std::string& selected_subprotocol,
  102. const std::string& extensions) override;
  103. void OnDataFrame(bool fin,
  104. WebSocketMessageType type,
  105. base::span<const char> payload) override;
  106. bool HasPendingDataFrames() override { return false; }
  107. void OnSendDataFrameDone() override;
  108. void OnClosingHandshake() override;
  109. void OnDropChannel(bool was_clean,
  110. uint16_t code,
  111. const std::string& reason) override;
  112. void OnFailChannel(const std::string& message,
  113. int net_error,
  114. absl::optional<int> response_code) override;
  115. void OnStartOpeningHandshake(
  116. std::unique_ptr<WebSocketHandshakeRequestInfo> request) override;
  117. void OnSSLCertificateError(
  118. std::unique_ptr<SSLErrorCallbacks> ssl_error_callbacks,
  119. const GURL& url,
  120. int net_error,
  121. const SSLInfo& ssl_info,
  122. bool fatal) override;
  123. int OnAuthRequired(const AuthChallengeInfo& auth_info,
  124. scoped_refptr<HttpResponseHeaders> response_headers,
  125. const IPEndPoint& remote_endpoint,
  126. base::OnceCallback<void(const AuthCredentials*)> callback,
  127. absl::optional<AuthCredentials>* credentials) override;
  128. private:
  129. void QuitNestedEventLoop();
  130. // failed_ is true if the handshake failed (ie. OnFailChannel was called).
  131. bool failed_ = false;
  132. std::unique_ptr<WebSocketHandshakeResponseInfo> response_;
  133. std::string selected_subprotocol_;
  134. std::string extensions_;
  135. std::string failure_message_;
  136. base::RunLoop run_loop_;
  137. };
  138. ConnectTestingEventInterface::ConnectTestingEventInterface() = default;
  139. void ConnectTestingEventInterface::WaitForResponse() {
  140. run_loop_.Run();
  141. }
  142. std::string ConnectTestingEventInterface::failure_message() const {
  143. return failure_message_;
  144. }
  145. std::string ConnectTestingEventInterface::selected_subprotocol() const {
  146. return selected_subprotocol_;
  147. }
  148. std::string ConnectTestingEventInterface::extensions() const {
  149. return extensions_;
  150. }
  151. void ConnectTestingEventInterface::OnAddChannelResponse(
  152. std::unique_ptr<WebSocketHandshakeResponseInfo> response,
  153. const std::string& selected_subprotocol,
  154. const std::string& extensions) {
  155. response_ = std::move(response);
  156. selected_subprotocol_ = selected_subprotocol;
  157. extensions_ = extensions;
  158. QuitNestedEventLoop();
  159. }
  160. void ConnectTestingEventInterface::OnDataFrame(bool fin,
  161. WebSocketMessageType type,
  162. base::span<const char> payload) {
  163. }
  164. void ConnectTestingEventInterface::OnSendDataFrameDone() {}
  165. void ConnectTestingEventInterface::OnClosingHandshake() {}
  166. void ConnectTestingEventInterface::OnDropChannel(bool was_clean,
  167. uint16_t code,
  168. const std::string& reason) {}
  169. void ConnectTestingEventInterface::OnFailChannel(
  170. const std::string& message,
  171. int net_error,
  172. absl::optional<int> response_code) {
  173. failed_ = true;
  174. failure_message_ = message;
  175. QuitNestedEventLoop();
  176. }
  177. void ConnectTestingEventInterface::OnStartOpeningHandshake(
  178. std::unique_ptr<WebSocketHandshakeRequestInfo> request) {}
  179. void ConnectTestingEventInterface::OnSSLCertificateError(
  180. std::unique_ptr<SSLErrorCallbacks> ssl_error_callbacks,
  181. const GURL& url,
  182. int net_error,
  183. const SSLInfo& ssl_info,
  184. bool fatal) {
  185. base::ThreadTaskRunnerHandle::Get()->PostTask(
  186. FROM_HERE, base::BindOnce(&SSLErrorCallbacks::CancelSSLRequest,
  187. base::Owned(ssl_error_callbacks.release()),
  188. ERR_SSL_PROTOCOL_ERROR, &ssl_info));
  189. }
  190. int ConnectTestingEventInterface::OnAuthRequired(
  191. const AuthChallengeInfo& auth_info,
  192. scoped_refptr<HttpResponseHeaders> response_headers,
  193. const IPEndPoint& remote_endpoint,
  194. base::OnceCallback<void(const AuthCredentials*)> callback,
  195. absl::optional<AuthCredentials>* credentials) {
  196. *credentials = absl::nullopt;
  197. return OK;
  198. }
  199. void ConnectTestingEventInterface::QuitNestedEventLoop() {
  200. run_loop_.Quit();
  201. }
  202. // A subclass of TestNetworkDelegate that additionally implements the
  203. // OnResolveProxy callback and records the information passed to it.
  204. class TestProxyDelegateWithProxyInfo : public ProxyDelegate {
  205. public:
  206. TestProxyDelegateWithProxyInfo() = default;
  207. TestProxyDelegateWithProxyInfo(const TestProxyDelegateWithProxyInfo&) =
  208. delete;
  209. TestProxyDelegateWithProxyInfo& operator=(
  210. const TestProxyDelegateWithProxyInfo&) = delete;
  211. struct ResolvedProxyInfo {
  212. GURL url;
  213. ProxyInfo proxy_info;
  214. };
  215. const ResolvedProxyInfo& resolved_proxy_info() const {
  216. return resolved_proxy_info_;
  217. }
  218. protected:
  219. void OnResolveProxy(const GURL& url,
  220. const std::string& method,
  221. const ProxyRetryInfoMap& proxy_retry_info,
  222. ProxyInfo* result) override {
  223. resolved_proxy_info_.url = url;
  224. resolved_proxy_info_.proxy_info = *result;
  225. }
  226. void OnFallback(const ProxyServer& bad_proxy, int net_error) override {}
  227. void OnBeforeTunnelRequest(const ProxyServer& proxy_server,
  228. HttpRequestHeaders* extra_headers) override {}
  229. Error OnTunnelHeadersReceived(
  230. const ProxyServer& proxy_server,
  231. const HttpResponseHeaders& response_headers) override {
  232. return OK;
  233. }
  234. private:
  235. ResolvedProxyInfo resolved_proxy_info_;
  236. };
  237. class WebSocketEndToEndTest : public TestWithTaskEnvironment {
  238. protected:
  239. WebSocketEndToEndTest()
  240. : event_interface_(),
  241. proxy_delegate_(std::make_unique<TestProxyDelegateWithProxyInfo>()),
  242. context_builder_(CreateTestURLRequestContextBuilder()) {}
  243. // Initialise the URLRequestContext. Normally done automatically by
  244. // ConnectAndWait(). This method is for the use of tests that need the
  245. // URLRequestContext initialised before calling ConnectAndWait().
  246. void InitialiseContext() {
  247. DCHECK(!context_);
  248. context_ = context_builder_->Build();
  249. context_->proxy_resolution_service()->SetProxyDelegate(
  250. proxy_delegate_.get());
  251. }
  252. // Send the connect request to |socket_url| and wait for a response. Returns
  253. // true if the handshake succeeded.
  254. bool ConnectAndWait(const GURL& socket_url) {
  255. if (!context_) {
  256. InitialiseContext();
  257. }
  258. url::Origin origin = url::Origin::Create(GURL("http://localhost"));
  259. net::SiteForCookies site_for_cookies =
  260. net::SiteForCookies::FromOrigin(origin);
  261. IsolationInfo isolation_info =
  262. IsolationInfo::Create(IsolationInfo::RequestType::kOther, origin,
  263. origin, SiteForCookies::FromOrigin(origin));
  264. auto event_interface = std::make_unique<ConnectTestingEventInterface>();
  265. event_interface_ = event_interface.get();
  266. channel_ = std::make_unique<WebSocketChannel>(std::move(event_interface),
  267. context_.get());
  268. channel_->SendAddChannelRequest(
  269. GURL(socket_url), sub_protocols_, origin, site_for_cookies,
  270. isolation_info, HttpRequestHeaders(), TRAFFIC_ANNOTATION_FOR_TESTS);
  271. event_interface_->WaitForResponse();
  272. return !event_interface_->failed();
  273. }
  274. raw_ptr<ConnectTestingEventInterface> event_interface_; // owned by channel_
  275. std::unique_ptr<TestProxyDelegateWithProxyInfo> proxy_delegate_;
  276. std::unique_ptr<URLRequestContextBuilder> context_builder_;
  277. std::unique_ptr<URLRequestContext> context_;
  278. std::unique_ptr<WebSocketChannel> channel_;
  279. std::vector<std::string> sub_protocols_;
  280. };
  281. // Basic test of connectivity. If this test fails, nothing else can be expected
  282. // to work.
  283. TEST_F(WebSocketEndToEndTest, BasicSmokeTest) {
  284. SpawnedTestServer ws_server(SpawnedTestServer::TYPE_WS,
  285. GetWebSocketTestDataDirectory());
  286. ASSERT_TRUE(ws_server.Start());
  287. EXPECT_TRUE(ConnectAndWait(ws_server.GetURL(kEchoServer)));
  288. }
  289. // Test for issue crbug.com/433695 "Unencrypted WebSocket connection via
  290. // authenticated proxy times out"
  291. // TODO(ricea): Enable this when the issue is fixed.
  292. TEST_F(WebSocketEndToEndTest, DISABLED_HttpsProxyUnauthedFails) {
  293. SpawnedTestServer proxy_server(SpawnedTestServer::TYPE_BASIC_AUTH_PROXY,
  294. base::FilePath());
  295. SpawnedTestServer ws_server(SpawnedTestServer::TYPE_WS,
  296. GetWebSocketTestDataDirectory());
  297. ASSERT_TRUE(proxy_server.StartInBackground());
  298. ASSERT_TRUE(ws_server.StartInBackground());
  299. ASSERT_TRUE(proxy_server.BlockUntilStarted());
  300. ASSERT_TRUE(ws_server.BlockUntilStarted());
  301. std::string proxy_config =
  302. "https=" + proxy_server.host_port_pair().ToString();
  303. std::unique_ptr<ProxyResolutionService> proxy_resolution_service(
  304. ConfiguredProxyResolutionService::CreateFixedForTest(
  305. proxy_config, TRAFFIC_ANNOTATION_FOR_TESTS));
  306. ASSERT_TRUE(proxy_resolution_service);
  307. context_builder_->set_proxy_resolution_service(
  308. std::move(proxy_resolution_service));
  309. EXPECT_FALSE(ConnectAndWait(ws_server.GetURL(kEchoServer)));
  310. EXPECT_EQ("Proxy authentication failed", event_interface_->failure_message());
  311. }
  312. // These test are not compatible with RemoteTestServer because RemoteTestServer
  313. // doesn't support TYPE_BASIC_AUTH_PROXY.
  314. // TODO(ricea): Make these tests work. See crbug.com/441711.
  315. #if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_FUCHSIA)
  316. #define MAYBE_HttpsWssProxyUnauthedFails DISABLED_HttpsWssProxyUnauthedFails
  317. #define MAYBE_HttpsProxyUsed DISABLED_HttpsProxyUsed
  318. #else
  319. #define MAYBE_HttpsWssProxyUnauthedFails HttpsWssProxyUnauthedFails
  320. #define MAYBE_HttpsProxyUsed HttpsProxyUsed
  321. #endif
  322. TEST_F(WebSocketEndToEndTest, MAYBE_HttpsWssProxyUnauthedFails) {
  323. SpawnedTestServer proxy_server(SpawnedTestServer::TYPE_BASIC_AUTH_PROXY,
  324. base::FilePath());
  325. SpawnedTestServer wss_server(SpawnedTestServer::TYPE_WSS,
  326. GetWebSocketTestDataDirectory());
  327. ASSERT_TRUE(proxy_server.StartInBackground());
  328. ASSERT_TRUE(wss_server.StartInBackground());
  329. ASSERT_TRUE(proxy_server.BlockUntilStarted());
  330. ASSERT_TRUE(wss_server.BlockUntilStarted());
  331. ProxyConfig proxy_config;
  332. proxy_config.proxy_rules().ParseFromString(
  333. "https=" + proxy_server.host_port_pair().ToString());
  334. // TODO(https://crbug.com/901896): Don't rely on proxying localhost.
  335. proxy_config.proxy_rules().bypass_rules.AddRulesToSubtractImplicit();
  336. std::unique_ptr<ProxyResolutionService> proxy_resolution_service(
  337. ConfiguredProxyResolutionService::CreateFixedForTest(
  338. ProxyConfigWithAnnotation(proxy_config,
  339. TRAFFIC_ANNOTATION_FOR_TESTS)));
  340. ASSERT_TRUE(proxy_resolution_service);
  341. context_builder_->set_proxy_resolution_service(
  342. std::move(proxy_resolution_service));
  343. EXPECT_FALSE(ConnectAndWait(wss_server.GetURL(kEchoServer)));
  344. EXPECT_EQ("Proxy authentication failed", event_interface_->failure_message());
  345. }
  346. // Regression test for crbug/426736 "WebSocket connections not using configured
  347. // system HTTPS Proxy".
  348. TEST_F(WebSocketEndToEndTest, MAYBE_HttpsProxyUsed) {
  349. SpawnedTestServer proxy_server(SpawnedTestServer::TYPE_PROXY,
  350. base::FilePath());
  351. SpawnedTestServer ws_server(SpawnedTestServer::TYPE_WS,
  352. GetWebSocketTestDataDirectory());
  353. ASSERT_TRUE(proxy_server.StartInBackground());
  354. ASSERT_TRUE(ws_server.StartInBackground());
  355. ASSERT_TRUE(proxy_server.BlockUntilStarted());
  356. ASSERT_TRUE(ws_server.BlockUntilStarted());
  357. ProxyConfig proxy_config;
  358. proxy_config.proxy_rules().ParseFromString(
  359. "https=" + proxy_server.host_port_pair().ToString() + ";" +
  360. "http=" + proxy_server.host_port_pair().ToString());
  361. // TODO(https://crbug.com/901896): Don't rely on proxying localhost.
  362. proxy_config.proxy_rules().bypass_rules.AddRulesToSubtractImplicit();
  363. std::unique_ptr<ProxyResolutionService> proxy_resolution_service(
  364. ConfiguredProxyResolutionService::CreateFixedForTest(
  365. ProxyConfigWithAnnotation(proxy_config,
  366. TRAFFIC_ANNOTATION_FOR_TESTS)));
  367. context_builder_->set_proxy_resolution_service(
  368. std::move(proxy_resolution_service));
  369. InitialiseContext();
  370. GURL ws_url = ws_server.GetURL(kEchoServer);
  371. EXPECT_TRUE(ConnectAndWait(ws_url));
  372. const TestProxyDelegateWithProxyInfo::ResolvedProxyInfo& info =
  373. proxy_delegate_->resolved_proxy_info();
  374. EXPECT_EQ(ws_url, info.url);
  375. EXPECT_TRUE(info.proxy_info.is_http());
  376. }
  377. std::unique_ptr<HttpResponse> ProxyPacHandler(const HttpRequest& request) {
  378. GURL url = request.GetURL();
  379. EXPECT_EQ(url.path_piece(), "/proxy.pac");
  380. EXPECT_TRUE(url.has_query());
  381. std::string proxy;
  382. EXPECT_TRUE(GetValueForKeyInQuery(url, "proxy", &proxy));
  383. auto response = std::make_unique<BasicHttpResponse>();
  384. response->set_content_type("application/x-ns-proxy-autoconfig");
  385. response->set_content(
  386. base::StringPrintf("function FindProxyForURL(url, host) {\n"
  387. " return 'PROXY %s';\n"
  388. "}\n",
  389. proxy.c_str()));
  390. return response;
  391. }
  392. // This tests the proxy.pac resolver that is built into the system. This is not
  393. // the one that Chrome normally uses. Chrome's normal implementation is defined
  394. // as a mojo service. It is outside //net and we can't use it from here. This
  395. // tests the alternative implementations that are selected when the
  396. // --winhttp-proxy-resolver flag is provided to Chrome. These only exist on OS X
  397. // and Windows.
  398. // TODO(ricea): Remove this test if --winhttp-proxy-resolver flag is removed.
  399. // See crbug.com/644030.
  400. #if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_APPLE)
  401. #define MAYBE_ProxyPacUsed ProxyPacUsed
  402. #else
  403. #define MAYBE_ProxyPacUsed DISABLED_ProxyPacUsed
  404. #endif
  405. TEST_F(WebSocketEndToEndTest, MAYBE_ProxyPacUsed) {
  406. EmbeddedTestServer proxy_pac_server(net::EmbeddedTestServer::Type::TYPE_HTTP);
  407. SpawnedTestServer proxy_server(SpawnedTestServer::TYPE_PROXY,
  408. base::FilePath());
  409. SpawnedTestServer ws_server(SpawnedTestServer::TYPE_WS,
  410. GetWebSocketTestDataDirectory());
  411. proxy_pac_server.RegisterRequestHandler(base::BindRepeating(ProxyPacHandler));
  412. proxy_server.set_redirect_connect_to_localhost(true);
  413. ASSERT_TRUE(proxy_pac_server.Start());
  414. ASSERT_TRUE(proxy_server.StartInBackground());
  415. ASSERT_TRUE(ws_server.StartInBackground());
  416. ASSERT_TRUE(proxy_server.BlockUntilStarted());
  417. ASSERT_TRUE(ws_server.BlockUntilStarted());
  418. ProxyConfig proxy_config =
  419. ProxyConfig::CreateFromCustomPacURL(proxy_pac_server.GetURL(base::StrCat(
  420. {"/proxy.pac?proxy=", proxy_server.host_port_pair().ToString()})));
  421. proxy_config.set_pac_mandatory(true);
  422. auto proxy_config_service = std::make_unique<ProxyConfigServiceFixed>(
  423. ProxyConfigWithAnnotation(proxy_config, TRAFFIC_ANNOTATION_FOR_TESTS));
  424. std::unique_ptr<ProxyResolutionService> proxy_resolution_service(
  425. ConfiguredProxyResolutionService::CreateUsingSystemProxyResolver(
  426. std::move(proxy_config_service), NetLog::Get(),
  427. /*quick_check_enabled=*/true));
  428. ASSERT_EQ(ws_server.host_port_pair().host(), "127.0.0.1");
  429. context_builder_->set_proxy_resolution_service(
  430. std::move(proxy_resolution_service));
  431. InitialiseContext();
  432. // Use a name other than localhost, since localhost implicitly bypasses the
  433. // use of proxy.pac.
  434. HostPortPair fake_ws_host_port_pair("stealth-localhost",
  435. ws_server.host_port_pair().port());
  436. GURL ws_url(base::StrCat(
  437. {"ws://", fake_ws_host_port_pair.ToString(), "/", kEchoServer}));
  438. EXPECT_TRUE(ConnectAndWait(ws_url));
  439. const auto& info = proxy_delegate_->resolved_proxy_info();
  440. EXPECT_EQ(ws_url, info.url);
  441. EXPECT_TRUE(info.proxy_info.is_http());
  442. EXPECT_EQ(info.proxy_info.ToPacString(),
  443. base::StrCat({"PROXY ", proxy_server.host_port_pair().ToString()}));
  444. }
  445. // This is a regression test for crbug.com/408061 Crash in
  446. // net::WebSocketBasicHandshakeStream::Upgrade.
  447. TEST_F(WebSocketEndToEndTest, TruncatedResponse) {
  448. SpawnedTestServer ws_server(SpawnedTestServer::TYPE_WS,
  449. GetWebSocketTestDataDirectory());
  450. ASSERT_TRUE(ws_server.Start());
  451. InitialiseContext();
  452. GURL ws_url = ws_server.GetURL("truncated-headers");
  453. EXPECT_FALSE(ConnectAndWait(ws_url));
  454. }
  455. // Regression test for crbug.com/455215 "HSTS not applied to WebSocket"
  456. TEST_F(WebSocketEndToEndTest, HstsHttpsToWebSocket) {
  457. EmbeddedTestServer https_server(net::EmbeddedTestServer::Type::TYPE_HTTPS);
  458. https_server.SetSSLConfig(
  459. net::EmbeddedTestServer::CERT_COMMON_NAME_IS_DOMAIN);
  460. https_server.ServeFilesFromSourceDirectory("net/data/url_request_unittest");
  461. SpawnedTestServer::SSLOptions ssl_options(
  462. SpawnedTestServer::SSLOptions::CERT_COMMON_NAME_IS_DOMAIN);
  463. SpawnedTestServer wss_server(SpawnedTestServer::TYPE_WSS, ssl_options,
  464. GetWebSocketTestDataDirectory());
  465. ASSERT_TRUE(https_server.Start());
  466. ASSERT_TRUE(wss_server.Start());
  467. InitialiseContext();
  468. // Set HSTS via https:
  469. TestDelegate delegate;
  470. GURL https_page = https_server.GetURL("/hsts-headers.html");
  471. std::unique_ptr<URLRequest> request(context_->CreateRequest(
  472. https_page, DEFAULT_PRIORITY, &delegate, TRAFFIC_ANNOTATION_FOR_TESTS));
  473. request->Start();
  474. delegate.RunUntilComplete();
  475. EXPECT_EQ(OK, delegate.request_status());
  476. // Check HSTS with ws:
  477. // Change the scheme from wss: to ws: to verify that it is switched back.
  478. GURL ws_url = ReplaceUrlScheme(wss_server.GetURL(kEchoServer), "ws");
  479. EXPECT_TRUE(ConnectAndWait(ws_url));
  480. }
  481. TEST_F(WebSocketEndToEndTest, HstsWebSocketToHttps) {
  482. EmbeddedTestServer https_server(net::EmbeddedTestServer::Type::TYPE_HTTPS);
  483. https_server.SetSSLConfig(
  484. net::EmbeddedTestServer::CERT_COMMON_NAME_IS_DOMAIN);
  485. https_server.ServeFilesFromSourceDirectory("net/data/url_request_unittest");
  486. SpawnedTestServer::SSLOptions ssl_options(
  487. SpawnedTestServer::SSLOptions::CERT_COMMON_NAME_IS_DOMAIN);
  488. SpawnedTestServer wss_server(SpawnedTestServer::TYPE_WSS, ssl_options,
  489. GetWebSocketTestDataDirectory());
  490. ASSERT_TRUE(https_server.Start());
  491. ASSERT_TRUE(wss_server.Start());
  492. InitialiseContext();
  493. // Set HSTS via wss:
  494. GURL wss_url = wss_server.GetURL("set-hsts");
  495. EXPECT_TRUE(ConnectAndWait(wss_url));
  496. // Verify via http:
  497. TestDelegate delegate;
  498. GURL http_page =
  499. ReplaceUrlScheme(https_server.GetURL("/simple.html"), "http");
  500. std::unique_ptr<URLRequest> request(context_->CreateRequest(
  501. http_page, DEFAULT_PRIORITY, &delegate, TRAFFIC_ANNOTATION_FOR_TESTS));
  502. request->Start();
  503. delegate.RunUntilComplete();
  504. EXPECT_EQ(OK, delegate.request_status());
  505. EXPECT_TRUE(request->url().SchemeIs("https"));
  506. }
  507. TEST_F(WebSocketEndToEndTest, HstsWebSocketToWebSocket) {
  508. SpawnedTestServer::SSLOptions ssl_options(
  509. SpawnedTestServer::SSLOptions::CERT_COMMON_NAME_IS_DOMAIN);
  510. SpawnedTestServer wss_server(SpawnedTestServer::TYPE_WSS, ssl_options,
  511. GetWebSocketTestDataDirectory());
  512. ASSERT_TRUE(wss_server.Start());
  513. InitialiseContext();
  514. // Set HSTS via wss:
  515. GURL wss_url = wss_server.GetURL("set-hsts");
  516. EXPECT_TRUE(ConnectAndWait(wss_url));
  517. // Verify via wss:
  518. GURL ws_url = ReplaceUrlScheme(wss_server.GetURL(kEchoServer), "ws");
  519. EXPECT_TRUE(ConnectAndWait(ws_url));
  520. }
  521. // Regression test for crbug.com/180504 "WebSocket handshake fails when HTTP
  522. // headers have trailing LWS".
  523. TEST_F(WebSocketEndToEndTest, TrailingWhitespace) {
  524. SpawnedTestServer ws_server(SpawnedTestServer::TYPE_WS,
  525. GetWebSocketTestDataDirectory());
  526. ASSERT_TRUE(ws_server.Start());
  527. GURL ws_url = ws_server.GetURL("trailing-whitespace");
  528. sub_protocols_.push_back("sip");
  529. EXPECT_TRUE(ConnectAndWait(ws_url));
  530. EXPECT_EQ("sip", event_interface_->selected_subprotocol());
  531. }
  532. // This is a regression test for crbug.com/169448 "WebSockets should support
  533. // header continuations"
  534. // TODO(ricea): HTTP continuation headers have been deprecated by RFC7230. If
  535. // support for continuation headers is removed from Chrome, then this test will
  536. // break and should be removed.
  537. TEST_F(WebSocketEndToEndTest, HeaderContinuations) {
  538. SpawnedTestServer ws_server(SpawnedTestServer::TYPE_WS,
  539. GetWebSocketTestDataDirectory());
  540. ASSERT_TRUE(ws_server.Start());
  541. GURL ws_url = ws_server.GetURL("header-continuation");
  542. EXPECT_TRUE(ConnectAndWait(ws_url));
  543. EXPECT_EQ("permessage-deflate; server_max_window_bits=10",
  544. event_interface_->extensions());
  545. }
  546. // Test that ws->wss scheme upgrade is supported on receiving a DNS HTTPS
  547. // record.
  548. TEST_F(WebSocketEndToEndTest, DnsSchemeUpgradeSupported) {
  549. base::test::ScopedFeatureList features;
  550. features.InitAndEnableFeatureWithParameters(
  551. features::kUseDnsHttpsSvcb, {{"UseDnsHttpsSvcbHttpUpgrade", "true"}});
  552. SpawnedTestServer wss_server(SpawnedTestServer::TYPE_WSS,
  553. SpawnedTestServer::SSLOptions(base::FilePath(
  554. FILE_PATH_LITERAL("test_names.pem"))),
  555. GetWebSocketTestDataDirectory());
  556. ASSERT_TRUE(wss_server.Start());
  557. GURL wss_url("wss://a.test:" +
  558. base::NumberToString(wss_server.host_port_pair().port()) + "/" +
  559. kEchoServer);
  560. GURL::Replacements replacements;
  561. replacements.SetSchemeStr(url::kWsScheme);
  562. GURL ws_url = wss_url.ReplaceComponents(replacements);
  563. // Note that due to socket pool behavior, HostResolver will see the ws/wss
  564. // requests as http/https.
  565. auto host_resolver = std::make_unique<MockHostResolver>();
  566. MockHostResolverBase::RuleResolver::RuleKey unencrypted_resolve_key;
  567. unencrypted_resolve_key.scheme = url::kHttpScheme;
  568. host_resolver->rules()->AddRule(std::move(unencrypted_resolve_key),
  569. ERR_DNS_NAME_HTTPS_ONLY);
  570. MockHostResolverBase::RuleResolver::RuleKey encrypted_resolve_key;
  571. encrypted_resolve_key.scheme = url::kHttpsScheme;
  572. host_resolver->rules()->AddRule(std::move(encrypted_resolve_key),
  573. "127.0.0.1");
  574. context_builder_->set_host_resolver(std::move(host_resolver));
  575. EXPECT_TRUE(ConnectAndWait(ws_url));
  576. // Expect request to have reached the server using the upgraded URL.
  577. EXPECT_EQ(event_interface_->response()->url, wss_url);
  578. }
  579. // Test that wss connections can use HostResolverEndpointResults from DNS.
  580. TEST_F(WebSocketEndToEndTest, HostResolverEndpointResult) {
  581. base::test::ScopedFeatureList features;
  582. features.InitAndEnableFeature(features::kUseDnsHttpsSvcb);
  583. SpawnedTestServer wss_server(SpawnedTestServer::TYPE_WSS,
  584. SpawnedTestServer::SSLOptions(base::FilePath(
  585. FILE_PATH_LITERAL("test_names.pem"))),
  586. GetWebSocketTestDataDirectory());
  587. ASSERT_TRUE(wss_server.Start());
  588. uint16_t port = wss_server.host_port_pair().port();
  589. GURL wss_url("wss://a.test:" + base::NumberToString(port) + "/" +
  590. kEchoServer);
  591. auto host_resolver = std::make_unique<MockHostResolver>();
  592. MockHostResolverBase::RuleResolver::RuleKey resolve_key;
  593. // The DNS query itself is made with the https scheme rather than wss.
  594. resolve_key.scheme = url::kHttpsScheme;
  595. resolve_key.hostname_pattern = "a.test";
  596. resolve_key.port = port;
  597. HostResolverEndpointResult result;
  598. result.ip_endpoints = {IPEndPoint(IPAddress::IPv4Localhost(), port)};
  599. result.metadata.supported_protocol_alpns = {"http/1.1"};
  600. host_resolver->rules()->AddRule(
  601. std::move(resolve_key),
  602. MockHostResolverBase::RuleResolver::RuleResult(std::vector{result}));
  603. context_builder_->set_host_resolver(std::move(host_resolver));
  604. EXPECT_TRUE(ConnectAndWait(wss_url));
  605. // Expect request to have reached the server using the upgraded URL.
  606. EXPECT_EQ(event_interface_->response()->url, wss_url);
  607. }
  608. // Test that wss connections can use EncryptedClientHello.
  609. TEST_F(WebSocketEndToEndTest, EncryptedClientHello) {
  610. base::test::ScopedFeatureList features;
  611. features.InitWithFeatures(
  612. {features::kUseDnsHttpsSvcb, features::kEncryptedClientHello}, {});
  613. // SpawnedTestServer does not support ECH, while EmbeddedTestServer does not
  614. // support WebSockets (https://crbug.com/1281277). Until that is fixed, test
  615. // ECH by configuring a non-WebSockets HTTPS server. The WebSockets handshake
  616. // will fail, but getting that far tests that ECH worked.
  617. // Configure a test server that speaks ECH.
  618. static constexpr char kRealName[] = "secret.example";
  619. static constexpr char kPublicName[] = "public.example";
  620. EmbeddedTestServer::ServerCertificateConfig server_cert_config;
  621. server_cert_config.dns_names = {kRealName};
  622. SSLServerConfig ssl_server_config;
  623. std::vector<uint8_t> ech_config_list;
  624. ssl_server_config.ech_keys =
  625. MakeTestEchKeys(kPublicName, /*max_name_len=*/128, &ech_config_list);
  626. ASSERT_TRUE(ssl_server_config.ech_keys);
  627. EmbeddedTestServer test_server(EmbeddedTestServer::TYPE_HTTPS);
  628. test_server.SetSSLConfig(server_cert_config, ssl_server_config);
  629. ASSERT_TRUE(test_server.Start());
  630. GURL https_url = test_server.GetURL(kRealName, "/");
  631. GURL::Replacements replacements;
  632. replacements.SetSchemeStr(url::kWssScheme);
  633. GURL wss_url = https_url.ReplaceComponents(replacements);
  634. auto host_resolver = std::make_unique<MockHostResolver>();
  635. MockHostResolverBase::RuleResolver::RuleKey resolve_key;
  636. // The DNS query itself is made with the https scheme rather than wss.
  637. resolve_key.scheme = url::kHttpsScheme;
  638. resolve_key.hostname_pattern = wss_url.host();
  639. resolve_key.port = wss_url.IntPort();
  640. HostResolverEndpointResult result;
  641. result.ip_endpoints = {
  642. IPEndPoint(IPAddress::IPv4Localhost(), wss_url.IntPort())};
  643. result.metadata.supported_protocol_alpns = {"http/1.1"};
  644. result.metadata.ech_config_list = ech_config_list;
  645. host_resolver->rules()->AddRule(
  646. std::move(resolve_key),
  647. MockHostResolverBase::RuleResolver::RuleResult(std::vector{result}));
  648. context_builder_->set_host_resolver(std::move(host_resolver));
  649. EXPECT_FALSE(ConnectAndWait(wss_url));
  650. EXPECT_EQ("Error during WebSocket handshake: Unexpected response code: 404",
  651. event_interface_->failure_message());
  652. }
  653. } // namespace
  654. } // namespace net