websocket_stream_test.cc 71 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808
  1. // Copyright 2013 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. #include "net/websockets/websocket_stream.h"
  5. #include <algorithm>
  6. #include <string>
  7. #include <utility>
  8. #include <vector>
  9. #include "base/compiler_specific.h"
  10. #include "base/containers/span.h"
  11. #include "base/memory/ptr_util.h"
  12. #include "base/metrics/histogram.h"
  13. #include "base/metrics/histogram_samples.h"
  14. #include "base/metrics/statistics_recorder.h"
  15. #include "base/run_loop.h"
  16. #include "base/strings/string_piece.h"
  17. #include "base/strings/stringprintf.h"
  18. #include "base/test/metrics/histogram_tester.h"
  19. #include "base/test/scoped_feature_list.h"
  20. #include "base/timer/mock_timer.h"
  21. #include "base/timer/timer.h"
  22. #include "net/base/features.h"
  23. #include "net/base/isolation_info.h"
  24. #include "net/base/net_errors.h"
  25. #include "net/base/url_util.h"
  26. #include "net/http/http_request_headers.h"
  27. #include "net/http/http_response_headers.h"
  28. #include "net/proxy_resolution/proxy_resolution_service.h"
  29. #include "net/socket/client_socket_handle.h"
  30. #include "net/socket/socket_test_util.h"
  31. #include "net/spdy/spdy_test_util_common.h"
  32. #include "net/test/cert_test_util.h"
  33. #include "net/test/gtest_util.h"
  34. #include "net/test/test_data_directory.h"
  35. #include "net/third_party/quiche/src/quiche/spdy/core/spdy_protocol.h"
  36. #include "net/url_request/url_request_test_util.h"
  37. #include "net/websockets/websocket_basic_handshake_stream.h"
  38. #include "net/websockets/websocket_frame.h"
  39. #include "net/websockets/websocket_stream_create_test_base.h"
  40. #include "net/websockets/websocket_test_util.h"
  41. #include "testing/gmock/include/gmock/gmock.h"
  42. #include "testing/gtest/include/gtest/gtest.h"
  43. #include "url/gurl.h"
  44. #include "url/origin.h"
  45. using ::net::test::IsError;
  46. using ::net::test::IsOk;
  47. using ::testing::TestWithParam;
  48. using ::testing::Values;
  49. namespace net {
  50. namespace {
  51. enum HandshakeStreamType { BASIC_HANDSHAKE_STREAM, HTTP2_HANDSHAKE_STREAM };
  52. // Simple builder for a SequencedSocketData object to save repetitive code.
  53. // It always sets the connect data to MockConnect(SYNCHRONOUS, OK), so it cannot
  54. // be used in tests where the connect fails. In practice, those tests never have
  55. // any read/write data and so can't benefit from it anyway. The arrays are not
  56. // copied. It is up to the caller to ensure they stay in scope until the test
  57. // ends.
  58. std::unique_ptr<SequencedSocketData> BuildSocketData(
  59. base::span<MockRead> reads,
  60. base::span<MockWrite> writes) {
  61. auto socket_data = std::make_unique<SequencedSocketData>(reads, writes);
  62. socket_data->set_connect_data(MockConnect(SYNCHRONOUS, OK));
  63. return socket_data;
  64. }
  65. // Builder for a SequencedSocketData that expects nothing. This does not
  66. // set the connect data, so the calling code must do that explicitly.
  67. std::unique_ptr<SequencedSocketData> BuildNullSocketData() {
  68. return std::make_unique<SequencedSocketData>();
  69. }
  70. class MockWeakTimer : public base::MockOneShotTimer,
  71. public base::SupportsWeakPtr<MockWeakTimer> {
  72. public:
  73. MockWeakTimer() = default;
  74. };
  75. const char kOrigin[] = "http://www.example.org";
  76. static url::Origin Origin() {
  77. return url::Origin::Create(GURL(kOrigin));
  78. }
  79. static net::SiteForCookies SiteForCookies() {
  80. return net::SiteForCookies::FromOrigin(Origin());
  81. }
  82. static IsolationInfo CreateIsolationInfo() {
  83. url::Origin origin = Origin();
  84. return IsolationInfo::Create(IsolationInfo::RequestType::kOther, origin,
  85. origin, SiteForCookies::FromOrigin(origin));
  86. }
  87. class WebSocketStreamCreateTest : public TestWithParam<HandshakeStreamType>,
  88. public WebSocketStreamCreateTestBase {
  89. protected:
  90. WebSocketStreamCreateTest() : stream_type_(GetParam()) {
  91. // Make sure these tests all pass with connection partitioning enabled. The
  92. // disabled case is less interesting, and is tested more directly at lower
  93. // layers.
  94. feature_list_.InitAndEnableFeature(
  95. features::kPartitionConnectionsByNetworkIsolationKey);
  96. }
  97. ~WebSocketStreamCreateTest() override {
  98. // Permit any endpoint locks to be released.
  99. stream_request_.reset();
  100. stream_.reset();
  101. base::RunLoop().RunUntilIdle();
  102. }
  103. // Normally it's easier to use CreateAndConnectRawExpectations() instead. This
  104. // method is only needed when multiple sockets are involved.
  105. void AddRawExpectations(std::unique_ptr<SequencedSocketData> socket_data) {
  106. url_request_context_host_.AddRawExpectations(std::move(socket_data));
  107. }
  108. void AddSSLData() {
  109. auto ssl_data = std::make_unique<SSLSocketDataProvider>(ASYNC, OK);
  110. ssl_data->ssl_info.cert =
  111. ImportCertFromFile(GetTestCertsDirectory(), "wildcard.pem");
  112. if (stream_type_ == HTTP2_HANDSHAKE_STREAM)
  113. ssl_data->next_proto = kProtoHTTP2;
  114. ASSERT_TRUE(ssl_data->ssl_info.cert.get());
  115. url_request_context_host_.AddSSLSocketDataProvider(std::move(ssl_data));
  116. }
  117. void SetTimer(std::unique_ptr<base::OneShotTimer> timer) {
  118. timer_ = std::move(timer);
  119. }
  120. void SetAdditionalResponseData(std::string additional_data) {
  121. additional_data_ = std::move(additional_data);
  122. }
  123. void SetHttp2ResponseStatus(const char* const http2_response_status) {
  124. http2_response_status_ = http2_response_status;
  125. }
  126. void SetResetWebSocketHttp2Stream(bool reset_websocket_http2_stream) {
  127. reset_websocket_http2_stream_ = reset_websocket_http2_stream;
  128. }
  129. // Set up mock data and start websockets request, either for WebSocket
  130. // upgraded from an HTTP/1 connection, or for a WebSocket request over HTTP/2.
  131. void CreateAndConnectStandard(
  132. base::StringPiece url,
  133. const std::vector<std::string>& sub_protocols,
  134. const WebSocketExtraHeaders& send_additional_request_headers,
  135. const WebSocketExtraHeaders& extra_request_headers,
  136. const WebSocketExtraHeaders& extra_response_headers) {
  137. const GURL socket_url(url);
  138. const std::string socket_host = GetHostAndOptionalPort(socket_url);
  139. const std::string socket_path = socket_url.path();
  140. if (stream_type_ == BASIC_HANDSHAKE_STREAM) {
  141. url_request_context_host_.SetExpectations(
  142. WebSocketStandardRequest(socket_path, socket_host, Origin(),
  143. send_additional_request_headers,
  144. extra_request_headers),
  145. WebSocketStandardResponse(
  146. WebSocketExtraHeadersToString(extra_response_headers)) +
  147. additional_data_);
  148. CreateAndConnectStream(socket_url, sub_protocols, Origin(),
  149. SiteForCookies(), CreateIsolationInfo(),
  150. WebSocketExtraHeadersToHttpRequestHeaders(
  151. send_additional_request_headers),
  152. std::move(timer_));
  153. return;
  154. }
  155. DCHECK_EQ(stream_type_, HTTP2_HANDSHAKE_STREAM);
  156. // TODO(bnc): Find a way to clear
  157. // spdy_session_pool.enable_sending_initial_data_ to avoid sending
  158. // connection preface, initial settings, and window update.
  159. // HTTP/2 connection preface.
  160. frames_.emplace_back(const_cast<char*>(spdy::kHttp2ConnectionHeaderPrefix),
  161. spdy::kHttp2ConnectionHeaderPrefixSize,
  162. /* owns_buffer = */ false);
  163. AddWrite(&frames_.back());
  164. // Server advertises WebSockets over HTTP/2 support.
  165. spdy::SettingsMap read_settings;
  166. read_settings[spdy::SETTINGS_ENABLE_CONNECT_PROTOCOL] = 1;
  167. frames_.push_back(spdy_util_.ConstructSpdySettings(read_settings));
  168. AddRead(&frames_.back());
  169. // Initial SETTINGS frame.
  170. spdy::SettingsMap write_settings;
  171. write_settings[spdy::SETTINGS_HEADER_TABLE_SIZE] = kSpdyMaxHeaderTableSize;
  172. write_settings[spdy::SETTINGS_MAX_CONCURRENT_STREAMS] =
  173. kSpdyMaxConcurrentPushedStreams;
  174. write_settings[spdy::SETTINGS_INITIAL_WINDOW_SIZE] = 6 * 1024 * 1024;
  175. write_settings[spdy::SETTINGS_MAX_HEADER_LIST_SIZE] =
  176. kSpdyMaxHeaderListSize;
  177. frames_.push_back(spdy_util_.ConstructSpdySettings(write_settings));
  178. AddWrite(&frames_.back());
  179. // Initial window update frame.
  180. frames_.push_back(spdy_util_.ConstructSpdyWindowUpdate(0, 0x00ef0001));
  181. AddWrite(&frames_.back());
  182. // SETTINGS ACK sent as a response to server's SETTINGS frame.
  183. frames_.push_back(spdy_util_.ConstructSpdySettingsAck());
  184. AddWrite(&frames_.back());
  185. // First request. This is necessary, because a WebSockets request currently
  186. // does not open a new HTTP/2 connection, it only uses an existing one.
  187. const char* const kExtraRequestHeaders[] = {
  188. "user-agent", "", "accept-encoding", "gzip, deflate",
  189. "accept-language", "en-us,fr"};
  190. frames_.push_back(spdy_util_.ConstructSpdyGet(
  191. kExtraRequestHeaders, std::size(kExtraRequestHeaders) / 2, 1,
  192. DEFAULT_PRIORITY));
  193. AddWrite(&frames_.back());
  194. // SETTINGS ACK frame sent by the server in response to the client's
  195. // initial SETTINGS frame.
  196. frames_.push_back(spdy_util_.ConstructSpdySettingsAck());
  197. AddRead(&frames_.back());
  198. // Response headers to first request.
  199. frames_.push_back(spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
  200. AddRead(&frames_.back());
  201. // Response body to first request.
  202. frames_.push_back(spdy_util_.ConstructSpdyDataFrame(1, true));
  203. AddRead(&frames_.back());
  204. // First request is closed.
  205. spdy_util_.UpdateWithStreamDestruction(1);
  206. // WebSocket request.
  207. spdy::Http2HeaderBlock request_headers = WebSocketHttp2Request(
  208. socket_path, socket_host, kOrigin, extra_request_headers);
  209. frames_.push_back(spdy_util_.ConstructSpdyHeaders(
  210. 3, std::move(request_headers), DEFAULT_PRIORITY, false));
  211. AddWrite(&frames_.back());
  212. if (reset_websocket_http2_stream_) {
  213. frames_.push_back(
  214. spdy_util_.ConstructSpdyRstStream(3, spdy::ERROR_CODE_CANCEL));
  215. AddRead(&frames_.back());
  216. } else {
  217. // Response to WebSocket request.
  218. std::vector<std::string> extra_response_header_keys;
  219. std::vector<const char*> extra_response_headers_vector;
  220. for (const auto& extra_header : extra_response_headers) {
  221. // Save a lowercase copy of the header key.
  222. extra_response_header_keys.push_back(
  223. base::ToLowerASCII(extra_header.first));
  224. // Save a pointer to this lowercase copy.
  225. extra_response_headers_vector.push_back(
  226. extra_response_header_keys.back().c_str());
  227. // Save a pointer to the original header value provided by the caller.
  228. extra_response_headers_vector.push_back(extra_header.second.c_str());
  229. }
  230. frames_.push_back(spdy_util_.ConstructSpdyReplyError(
  231. http2_response_status_, extra_response_headers_vector.data(),
  232. extra_response_headers_vector.size() / 2, 3));
  233. AddRead(&frames_.back());
  234. // WebSocket data received.
  235. if (!additional_data_.empty()) {
  236. frames_.push_back(
  237. spdy_util_.ConstructSpdyDataFrame(3, additional_data_, true));
  238. AddRead(&frames_.back());
  239. }
  240. // Client cancels HTTP/2 stream when request is destroyed.
  241. frames_.push_back(
  242. spdy_util_.ConstructSpdyRstStream(3, spdy::ERROR_CODE_CANCEL));
  243. AddWrite(&frames_.back());
  244. }
  245. // EOF.
  246. reads_.emplace_back(ASYNC, 0, sequence_number_++);
  247. auto socket_data = std::make_unique<SequencedSocketData>(reads_, writes_);
  248. socket_data->set_connect_data(MockConnect(SYNCHRONOUS, OK));
  249. AddRawExpectations(std::move(socket_data));
  250. // Send first request. This makes sure server's
  251. // spdy::SETTINGS_ENABLE_CONNECT_PROTOCOL advertisement is read.
  252. URLRequestContext* context =
  253. url_request_context_host_.GetURLRequestContext();
  254. TestDelegate delegate;
  255. std::unique_ptr<URLRequest> request = context->CreateRequest(
  256. GURL("https://www.example.org/"), DEFAULT_PRIORITY, &delegate,
  257. TRAFFIC_ANNOTATION_FOR_TESTS, /*is_for_websockets=*/false);
  258. // The IsolationInfo has to match for a socket to be reused.
  259. request->set_isolation_info(CreateIsolationInfo());
  260. request->Start();
  261. EXPECT_TRUE(request->is_pending());
  262. delegate.RunUntilComplete();
  263. EXPECT_FALSE(request->is_pending());
  264. CreateAndConnectStream(socket_url, sub_protocols, Origin(),
  265. SiteForCookies(), CreateIsolationInfo(),
  266. WebSocketExtraHeadersToHttpRequestHeaders(
  267. send_additional_request_headers),
  268. std::move(timer_));
  269. }
  270. // Like CreateAndConnectStandard(), but allow for arbitrary response body.
  271. // Only for HTTP/1-based WebSockets.
  272. void CreateAndConnectCustomResponse(
  273. base::StringPiece url,
  274. const std::vector<std::string>& sub_protocols,
  275. const WebSocketExtraHeaders& send_additional_request_headers,
  276. const WebSocketExtraHeaders& extra_request_headers,
  277. const std::string& response_body) {
  278. ASSERT_EQ(BASIC_HANDSHAKE_STREAM, stream_type_);
  279. const GURL socket_url(url);
  280. const std::string socket_host = GetHostAndOptionalPort(socket_url);
  281. const std::string socket_path = socket_url.path();
  282. url_request_context_host_.SetExpectations(
  283. WebSocketStandardRequest(socket_path, socket_host, Origin(),
  284. send_additional_request_headers,
  285. extra_request_headers),
  286. response_body);
  287. CreateAndConnectStream(socket_url, sub_protocols, Origin(),
  288. SiteForCookies(), CreateIsolationInfo(),
  289. WebSocketExtraHeadersToHttpRequestHeaders(
  290. send_additional_request_headers),
  291. nullptr);
  292. }
  293. // Like CreateAndConnectStandard(), but take extra response headers as a
  294. // string. This can save space in case of a very large response.
  295. // Only for HTTP/1-based WebSockets.
  296. void CreateAndConnectStringResponse(
  297. base::StringPiece url,
  298. const std::vector<std::string>& sub_protocols,
  299. const std::string& extra_response_headers) {
  300. ASSERT_EQ(BASIC_HANDSHAKE_STREAM, stream_type_);
  301. const GURL socket_url(url);
  302. const std::string socket_host = GetHostAndOptionalPort(socket_url);
  303. const std::string socket_path = socket_url.path();
  304. url_request_context_host_.SetExpectations(
  305. WebSocketStandardRequest(socket_path, socket_host, Origin(),
  306. /*send_additional_request_headers=*/{},
  307. /*extra_headers=*/{}),
  308. WebSocketStandardResponse(extra_response_headers));
  309. CreateAndConnectStream(socket_url, sub_protocols, Origin(),
  310. SiteForCookies(), CreateIsolationInfo(),
  311. HttpRequestHeaders(), nullptr);
  312. }
  313. // Like CreateAndConnectStandard(), but take raw mock data.
  314. void CreateAndConnectRawExpectations(
  315. base::StringPiece url,
  316. const std::vector<std::string>& sub_protocols,
  317. const HttpRequestHeaders& additional_headers,
  318. std::unique_ptr<SequencedSocketData> socket_data) {
  319. ASSERT_EQ(BASIC_HANDSHAKE_STREAM, stream_type_);
  320. AddRawExpectations(std::move(socket_data));
  321. CreateAndConnectStream(GURL(url), sub_protocols, Origin(), SiteForCookies(),
  322. CreateIsolationInfo(), additional_headers,
  323. std::move(timer_));
  324. }
  325. private:
  326. void AddWrite(const spdy::SpdySerializedFrame* frame) {
  327. writes_.emplace_back(ASYNC, frame->data(), frame->size(),
  328. sequence_number_++);
  329. }
  330. void AddRead(const spdy::SpdySerializedFrame* frame) {
  331. reads_.emplace_back(ASYNC, frame->data(), frame->size(),
  332. sequence_number_++);
  333. }
  334. protected:
  335. const HandshakeStreamType stream_type_;
  336. private:
  337. base::test::ScopedFeatureList feature_list_;
  338. std::unique_ptr<base::OneShotTimer> timer_;
  339. std::string additional_data_;
  340. const char* http2_response_status_ = "200";
  341. bool reset_websocket_http2_stream_ = false;
  342. SpdyTestUtil spdy_util_;
  343. NetLogWithSource log_;
  344. int sequence_number_ = 0;
  345. // Store mock HTTP/2 data.
  346. std::vector<spdy::SpdySerializedFrame> frames_;
  347. // Store MockRead and MockWrite objects that have pointers to above data.
  348. std::vector<MockRead> reads_;
  349. std::vector<MockWrite> writes_;
  350. };
  351. INSTANTIATE_TEST_SUITE_P(All,
  352. WebSocketStreamCreateTest,
  353. Values(BASIC_HANDSHAKE_STREAM));
  354. using WebSocketMultiProtocolStreamCreateTest = WebSocketStreamCreateTest;
  355. INSTANTIATE_TEST_SUITE_P(All,
  356. WebSocketMultiProtocolStreamCreateTest,
  357. Values(BASIC_HANDSHAKE_STREAM,
  358. HTTP2_HANDSHAKE_STREAM));
  359. // There are enough tests of the Sec-WebSocket-Extensions header that they
  360. // deserve their own test fixture.
  361. class WebSocketStreamCreateExtensionTest
  362. : public WebSocketMultiProtocolStreamCreateTest {
  363. protected:
  364. // Performs a standard connect, with the value of the Sec-WebSocket-Extensions
  365. // header in the response set to |extensions_header_value|. Runs the event
  366. // loop to allow the connect to complete.
  367. void CreateAndConnectWithExtensions(
  368. const std::string& extensions_header_value) {
  369. AddSSLData();
  370. CreateAndConnectStandard(
  371. "wss://www.example.org/testing_path", NoSubProtocols(), {}, {},
  372. {{"Sec-WebSocket-Extensions", extensions_header_value}});
  373. WaitUntilConnectDone();
  374. }
  375. };
  376. INSTANTIATE_TEST_SUITE_P(All,
  377. WebSocketStreamCreateExtensionTest,
  378. Values(BASIC_HANDSHAKE_STREAM,
  379. HTTP2_HANDSHAKE_STREAM));
  380. // Common code to construct expectations for authentication tests that receive
  381. // the auth challenge on one connection and then create a second connection to
  382. // send the authenticated request on.
  383. class CommonAuthTestHelper {
  384. public:
  385. CommonAuthTestHelper() : reads_(), writes_() {}
  386. CommonAuthTestHelper(const CommonAuthTestHelper&) = delete;
  387. CommonAuthTestHelper& operator=(const CommonAuthTestHelper&) = delete;
  388. std::unique_ptr<SequencedSocketData> BuildAuthSocketData(
  389. std::string response1,
  390. std::string request2,
  391. std::string response2) {
  392. request1_ = WebSocketStandardRequest("/", "www.example.org", Origin(),
  393. /*send_additional_request_headers=*/{},
  394. /*extra_headers=*/{});
  395. response1_ = std::move(response1);
  396. request2_ = std::move(request2);
  397. response2_ = std::move(response2);
  398. writes_[0] = MockWrite(SYNCHRONOUS, 0, request1_.c_str());
  399. reads_[0] = MockRead(SYNCHRONOUS, 1, response1_.c_str());
  400. writes_[1] = MockWrite(SYNCHRONOUS, 2, request2_.c_str());
  401. reads_[1] = MockRead(SYNCHRONOUS, 3, response2_.c_str());
  402. reads_[2] = MockRead(SYNCHRONOUS, OK, 4); // Close connection
  403. return BuildSocketData(reads_, writes_);
  404. }
  405. private:
  406. // These need to be object-scoped since they have to remain valid until all
  407. // socket operations in the test are complete.
  408. std::string request1_;
  409. std::string request2_;
  410. std::string response1_;
  411. std::string response2_;
  412. MockRead reads_[3];
  413. MockWrite writes_[2];
  414. };
  415. // Data and methods for BasicAuth tests.
  416. class WebSocketStreamCreateBasicAuthTest : public WebSocketStreamCreateTest {
  417. protected:
  418. void CreateAndConnectAuthHandshake(base::StringPiece url,
  419. base::StringPiece base64_user_pass,
  420. base::StringPiece response2) {
  421. CreateAndConnectRawExpectations(
  422. url, NoSubProtocols(), HttpRequestHeaders(),
  423. helper_.BuildAuthSocketData(kUnauthorizedResponse,
  424. RequestExpectation(base64_user_pass),
  425. std::string(response2)));
  426. }
  427. static std::string RequestExpectation(base::StringPiece base64_user_pass) {
  428. static const char request2format[] =
  429. "GET / HTTP/1.1\r\n"
  430. "Host: www.example.org\r\n"
  431. "Connection: Upgrade\r\n"
  432. "Pragma: no-cache\r\n"
  433. "Cache-Control: no-cache\r\n"
  434. "Authorization: Basic %s\r\n"
  435. "Upgrade: websocket\r\n"
  436. "Origin: http://www.example.org\r\n"
  437. "Sec-WebSocket-Version: 13\r\n"
  438. "User-Agent: \r\n"
  439. "Accept-Encoding: gzip, deflate\r\n"
  440. "Accept-Language: en-us,fr\r\n"
  441. "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n"
  442. "Sec-WebSocket-Extensions: permessage-deflate; "
  443. "client_max_window_bits\r\n"
  444. "\r\n";
  445. return base::StringPrintf(request2format, base64_user_pass.data());
  446. }
  447. static const char kUnauthorizedResponse[];
  448. CommonAuthTestHelper helper_;
  449. };
  450. INSTANTIATE_TEST_SUITE_P(All,
  451. WebSocketStreamCreateBasicAuthTest,
  452. Values(BASIC_HANDSHAKE_STREAM));
  453. class WebSocketStreamCreateDigestAuthTest : public WebSocketStreamCreateTest {
  454. protected:
  455. static const char kUnauthorizedResponse[];
  456. static const char kAuthorizedRequest[];
  457. CommonAuthTestHelper helper_;
  458. };
  459. INSTANTIATE_TEST_SUITE_P(All,
  460. WebSocketStreamCreateDigestAuthTest,
  461. Values(BASIC_HANDSHAKE_STREAM));
  462. const char WebSocketStreamCreateBasicAuthTest::kUnauthorizedResponse[] =
  463. "HTTP/1.1 401 Unauthorized\r\n"
  464. "Content-Length: 0\r\n"
  465. "WWW-Authenticate: Basic realm=\"camelot\"\r\n"
  466. "\r\n";
  467. // These negotiation values are borrowed from
  468. // http_auth_handler_digest_unittest.cc. Feel free to come up with new ones if
  469. // you are bored. Only the weakest (no qop) variants of Digest authentication
  470. // can be tested by this method, because the others involve random input.
  471. const char WebSocketStreamCreateDigestAuthTest::kUnauthorizedResponse[] =
  472. "HTTP/1.1 401 Unauthorized\r\n"
  473. "Content-Length: 0\r\n"
  474. "WWW-Authenticate: Digest realm=\"Oblivion\", nonce=\"nonce-value\"\r\n"
  475. "\r\n";
  476. const char WebSocketStreamCreateDigestAuthTest::kAuthorizedRequest[] =
  477. "GET / HTTP/1.1\r\n"
  478. "Host: www.example.org\r\n"
  479. "Connection: Upgrade\r\n"
  480. "Pragma: no-cache\r\n"
  481. "Cache-Control: no-cache\r\n"
  482. "Authorization: Digest username=\"FooBar\", realm=\"Oblivion\", "
  483. "nonce=\"nonce-value\", uri=\"/\", "
  484. "response=\"f72ff54ebde2f928860f806ec04acd1b\"\r\n"
  485. "Upgrade: websocket\r\n"
  486. "Origin: http://www.example.org\r\n"
  487. "Sec-WebSocket-Version: 13\r\n"
  488. "User-Agent: \r\n"
  489. "Accept-Encoding: gzip, deflate\r\n"
  490. "Accept-Language: en-us,fr\r\n"
  491. "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n"
  492. "Sec-WebSocket-Extensions: permessage-deflate; "
  493. "client_max_window_bits\r\n"
  494. "\r\n";
  495. // Confirm that the basic case works as expected.
  496. TEST_P(WebSocketMultiProtocolStreamCreateTest, SimpleSuccess) {
  497. base::HistogramTester histogram_tester;
  498. AddSSLData();
  499. EXPECT_FALSE(url_request_);
  500. CreateAndConnectStandard("wss://www.example.org/", NoSubProtocols(), {}, {},
  501. {});
  502. EXPECT_FALSE(request_info_);
  503. EXPECT_FALSE(response_info_);
  504. EXPECT_TRUE(url_request_);
  505. WaitUntilConnectDone();
  506. EXPECT_FALSE(has_failed());
  507. EXPECT_TRUE(stream_);
  508. EXPECT_TRUE(request_info_);
  509. EXPECT_TRUE(response_info_);
  510. EXPECT_EQ(ERR_WS_UPGRADE,
  511. url_request_context_host_.network_delegate().last_error());
  512. auto samples = histogram_tester.GetHistogramSamplesSinceCreation(
  513. "Net.WebSocket.HandshakeResult2");
  514. EXPECT_EQ(1, samples->TotalCount());
  515. if (stream_type_ == BASIC_HANDSHAKE_STREAM) {
  516. EXPECT_EQ(1,
  517. samples->GetCount(static_cast<int>(
  518. WebSocketHandshakeStreamBase::HandshakeResult::CONNECTED)));
  519. } else {
  520. DCHECK_EQ(stream_type_, HTTP2_HANDSHAKE_STREAM);
  521. EXPECT_EQ(
  522. 1,
  523. samples->GetCount(static_cast<int>(
  524. WebSocketHandshakeStreamBase::HandshakeResult::HTTP2_CONNECTED)));
  525. }
  526. }
  527. TEST_P(WebSocketStreamCreateTest, HandshakeInfo) {
  528. static const char kResponse[] =
  529. "HTTP/1.1 101 Switching Protocols\r\n"
  530. "Upgrade: websocket\r\n"
  531. "Connection: Upgrade\r\n"
  532. "Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\r\n"
  533. "foo: bar, baz\r\n"
  534. "hoge: fuga\r\n"
  535. "hoge: piyo\r\n"
  536. "\r\n";
  537. CreateAndConnectCustomResponse("ws://www.example.org/", NoSubProtocols(), {},
  538. {}, kResponse);
  539. EXPECT_FALSE(request_info_);
  540. EXPECT_FALSE(response_info_);
  541. WaitUntilConnectDone();
  542. EXPECT_TRUE(stream_);
  543. ASSERT_TRUE(request_info_);
  544. ASSERT_TRUE(response_info_);
  545. std::vector<HeaderKeyValuePair> request_headers =
  546. RequestHeadersToVector(request_info_->headers);
  547. // We examine the contents of request_info_ and response_info_
  548. // mainly only in this test case.
  549. EXPECT_EQ(GURL("ws://www.example.org/"), request_info_->url);
  550. EXPECT_EQ(GURL("ws://www.example.org/"), response_info_->url);
  551. EXPECT_EQ(101, response_info_->headers->response_code());
  552. EXPECT_EQ("Switching Protocols", response_info_->headers->GetStatusText());
  553. ASSERT_EQ(12u, request_headers.size());
  554. EXPECT_EQ(HeaderKeyValuePair("Host", "www.example.org"), request_headers[0]);
  555. EXPECT_EQ(HeaderKeyValuePair("Connection", "Upgrade"), request_headers[1]);
  556. EXPECT_EQ(HeaderKeyValuePair("Pragma", "no-cache"), request_headers[2]);
  557. EXPECT_EQ(HeaderKeyValuePair("Cache-Control", "no-cache"),
  558. request_headers[3]);
  559. EXPECT_EQ(HeaderKeyValuePair("Upgrade", "websocket"), request_headers[4]);
  560. EXPECT_EQ(HeaderKeyValuePair("Origin", "http://www.example.org"),
  561. request_headers[5]);
  562. EXPECT_EQ(HeaderKeyValuePair("Sec-WebSocket-Version", "13"),
  563. request_headers[6]);
  564. EXPECT_EQ(HeaderKeyValuePair("User-Agent", ""), request_headers[7]);
  565. EXPECT_EQ(HeaderKeyValuePair("Accept-Encoding", "gzip, deflate"),
  566. request_headers[8]);
  567. EXPECT_EQ(HeaderKeyValuePair("Accept-Language", "en-us,fr"),
  568. request_headers[9]);
  569. EXPECT_EQ("Sec-WebSocket-Key", request_headers[10].first);
  570. EXPECT_EQ(HeaderKeyValuePair("Sec-WebSocket-Extensions",
  571. "permessage-deflate; client_max_window_bits"),
  572. request_headers[11]);
  573. std::vector<HeaderKeyValuePair> response_headers =
  574. ResponseHeadersToVector(*response_info_->headers.get());
  575. ASSERT_EQ(6u, response_headers.size());
  576. // Sort the headers for ease of verification.
  577. std::sort(response_headers.begin(), response_headers.end());
  578. EXPECT_EQ(HeaderKeyValuePair("Connection", "Upgrade"), response_headers[0]);
  579. EXPECT_EQ("Sec-WebSocket-Accept", response_headers[1].first);
  580. EXPECT_EQ(HeaderKeyValuePair("Upgrade", "websocket"), response_headers[2]);
  581. EXPECT_EQ(HeaderKeyValuePair("foo", "bar, baz"), response_headers[3]);
  582. EXPECT_EQ(HeaderKeyValuePair("hoge", "fuga"), response_headers[4]);
  583. EXPECT_EQ(HeaderKeyValuePair("hoge", "piyo"), response_headers[5]);
  584. }
  585. // Confirms that request headers are overriden/added after handshake
  586. TEST_P(WebSocketStreamCreateTest, HandshakeOverrideHeaders) {
  587. WebSocketExtraHeaders additional_headers(
  588. {{"User-Agent", "OveRrIde"}, {"rAnDomHeader", "foobar"}});
  589. CreateAndConnectStandard("ws://www.example.org/", NoSubProtocols(),
  590. additional_headers, additional_headers, {});
  591. EXPECT_FALSE(request_info_);
  592. EXPECT_FALSE(response_info_);
  593. WaitUntilConnectDone();
  594. EXPECT_FALSE(has_failed());
  595. EXPECT_TRUE(stream_);
  596. EXPECT_TRUE(request_info_);
  597. EXPECT_TRUE(response_info_);
  598. std::vector<HeaderKeyValuePair> request_headers =
  599. RequestHeadersToVector(request_info_->headers);
  600. EXPECT_EQ(HeaderKeyValuePair("User-Agent", "OveRrIde"), request_headers[4]);
  601. EXPECT_EQ(HeaderKeyValuePair("rAnDomHeader", "foobar"), request_headers[5]);
  602. }
  603. // Confirm that the stream isn't established until the message loop runs.
  604. TEST_P(WebSocketStreamCreateTest, NeedsToRunLoop) {
  605. CreateAndConnectStandard("ws://www.example.org/", NoSubProtocols(), {}, {},
  606. {});
  607. EXPECT_FALSE(has_failed());
  608. EXPECT_FALSE(stream_);
  609. }
  610. // Check the path is used.
  611. TEST_P(WebSocketMultiProtocolStreamCreateTest, PathIsUsed) {
  612. AddSSLData();
  613. CreateAndConnectStandard("wss://www.example.org/testing_path",
  614. NoSubProtocols(), {}, {}, {});
  615. WaitUntilConnectDone();
  616. EXPECT_FALSE(has_failed());
  617. EXPECT_TRUE(stream_);
  618. }
  619. // Check that sub-protocols are sent and parsed.
  620. TEST_P(WebSocketMultiProtocolStreamCreateTest, SubProtocolIsUsed) {
  621. AddSSLData();
  622. std::vector<std::string> sub_protocols;
  623. sub_protocols.push_back("chatv11.chromium.org");
  624. sub_protocols.push_back("chatv20.chromium.org");
  625. CreateAndConnectStandard(
  626. "wss://www.example.org/testing_path", sub_protocols, {},
  627. {{"Sec-WebSocket-Protocol",
  628. "chatv11.chromium.org, chatv20.chromium.org"}},
  629. {{"Sec-WebSocket-Protocol", "chatv20.chromium.org"}});
  630. WaitUntilConnectDone();
  631. ASSERT_TRUE(stream_);
  632. EXPECT_FALSE(has_failed());
  633. EXPECT_EQ("chatv20.chromium.org", stream_->GetSubProtocol());
  634. }
  635. // Unsolicited sub-protocols are rejected.
  636. TEST_P(WebSocketMultiProtocolStreamCreateTest, UnsolicitedSubProtocol) {
  637. base::HistogramTester histogram_tester;
  638. AddSSLData();
  639. CreateAndConnectStandard(
  640. "wss://www.example.org/testing_path", NoSubProtocols(), {}, {},
  641. {{"Sec-WebSocket-Protocol", "chatv20.chromium.org"}});
  642. WaitUntilConnectDone();
  643. EXPECT_FALSE(stream_);
  644. EXPECT_TRUE(has_failed());
  645. EXPECT_EQ("Error during WebSocket handshake: "
  646. "Response must not include 'Sec-WebSocket-Protocol' header "
  647. "if not present in request: chatv20.chromium.org",
  648. failure_message());
  649. EXPECT_EQ(ERR_INVALID_RESPONSE,
  650. url_request_context_host_.network_delegate().last_error());
  651. stream_request_.reset();
  652. auto samples = histogram_tester.GetHistogramSamplesSinceCreation(
  653. "Net.WebSocket.HandshakeResult2");
  654. EXPECT_EQ(1, samples->TotalCount());
  655. if (stream_type_ == BASIC_HANDSHAKE_STREAM) {
  656. EXPECT_EQ(
  657. 1,
  658. samples->GetCount(static_cast<int>(
  659. WebSocketHandshakeStreamBase::HandshakeResult::FAILED_SUBPROTO)));
  660. } else {
  661. DCHECK_EQ(stream_type_, HTTP2_HANDSHAKE_STREAM);
  662. EXPECT_EQ(1, samples->GetCount(static_cast<int>(
  663. WebSocketHandshakeStreamBase::HandshakeResult::
  664. HTTP2_FAILED_SUBPROTO)));
  665. }
  666. }
  667. // Missing sub-protocol response is rejected.
  668. TEST_P(WebSocketMultiProtocolStreamCreateTest, UnacceptedSubProtocol) {
  669. AddSSLData();
  670. std::vector<std::string> sub_protocols;
  671. sub_protocols.push_back("chat.example.com");
  672. CreateAndConnectStandard("wss://www.example.org/testing_path", sub_protocols,
  673. {}, {{"Sec-WebSocket-Protocol", "chat.example.com"}},
  674. {});
  675. WaitUntilConnectDone();
  676. EXPECT_FALSE(stream_);
  677. EXPECT_TRUE(has_failed());
  678. EXPECT_EQ("Error during WebSocket handshake: "
  679. "Sent non-empty 'Sec-WebSocket-Protocol' header "
  680. "but no response was received",
  681. failure_message());
  682. }
  683. // Only one sub-protocol can be accepted.
  684. TEST_P(WebSocketMultiProtocolStreamCreateTest, MultipleSubProtocolsInResponse) {
  685. AddSSLData();
  686. std::vector<std::string> sub_protocols;
  687. sub_protocols.push_back("chatv11.chromium.org");
  688. sub_protocols.push_back("chatv20.chromium.org");
  689. CreateAndConnectStandard("wss://www.example.org/testing_path", sub_protocols,
  690. {},
  691. {{"Sec-WebSocket-Protocol",
  692. "chatv11.chromium.org, chatv20.chromium.org"}},
  693. {{"Sec-WebSocket-Protocol",
  694. "chatv11.chromium.org, chatv20.chromium.org"}});
  695. WaitUntilConnectDone();
  696. EXPECT_FALSE(stream_);
  697. EXPECT_TRUE(has_failed());
  698. EXPECT_EQ(
  699. "Error during WebSocket handshake: "
  700. "'Sec-WebSocket-Protocol' header must not appear "
  701. "more than once in a response",
  702. failure_message());
  703. }
  704. // Unmatched sub-protocol should be rejected.
  705. TEST_P(WebSocketMultiProtocolStreamCreateTest, UnmatchedSubProtocolInResponse) {
  706. AddSSLData();
  707. std::vector<std::string> sub_protocols;
  708. sub_protocols.push_back("chatv11.chromium.org");
  709. sub_protocols.push_back("chatv20.chromium.org");
  710. CreateAndConnectStandard(
  711. "wss://www.example.org/testing_path", sub_protocols, {},
  712. {{"Sec-WebSocket-Protocol",
  713. "chatv11.chromium.org, chatv20.chromium.org"}},
  714. {{"Sec-WebSocket-Protocol", "chatv21.chromium.org"}});
  715. WaitUntilConnectDone();
  716. EXPECT_FALSE(stream_);
  717. EXPECT_TRUE(has_failed());
  718. EXPECT_EQ("Error during WebSocket handshake: "
  719. "'Sec-WebSocket-Protocol' header value 'chatv21.chromium.org' "
  720. "in response does not match any of sent values",
  721. failure_message());
  722. }
  723. // permessage-deflate extension basic success case.
  724. TEST_P(WebSocketStreamCreateExtensionTest, PerMessageDeflateSuccess) {
  725. CreateAndConnectWithExtensions("permessage-deflate");
  726. EXPECT_TRUE(stream_);
  727. EXPECT_FALSE(has_failed());
  728. }
  729. // permessage-deflate extensions success with all parameters.
  730. TEST_P(WebSocketStreamCreateExtensionTest, PerMessageDeflateParamsSuccess) {
  731. CreateAndConnectWithExtensions(
  732. "permessage-deflate; client_no_context_takeover; "
  733. "server_max_window_bits=11; client_max_window_bits=13; "
  734. "server_no_context_takeover");
  735. EXPECT_TRUE(stream_);
  736. EXPECT_FALSE(has_failed());
  737. }
  738. // Verify that incoming messages are actually decompressed with
  739. // permessage-deflate enabled.
  740. TEST_P(WebSocketStreamCreateExtensionTest, PerMessageDeflateInflates) {
  741. AddSSLData();
  742. SetAdditionalResponseData(std::string(
  743. "\xc1\x07" // WebSocket header (FIN + RSV1, Text payload 7 bytes)
  744. "\xf2\x48\xcd\xc9\xc9\x07\x00", // "Hello" DEFLATE compressed
  745. 9));
  746. CreateAndConnectStandard(
  747. "wss://www.example.org/testing_path", NoSubProtocols(), {}, {},
  748. {{"Sec-WebSocket-Extensions", "permessage-deflate"}});
  749. WaitUntilConnectDone();
  750. ASSERT_TRUE(stream_);
  751. std::vector<std::unique_ptr<WebSocketFrame>> frames;
  752. TestCompletionCallback callback;
  753. int rv = stream_->ReadFrames(&frames, callback.callback());
  754. rv = callback.GetResult(rv);
  755. ASSERT_THAT(rv, IsOk());
  756. ASSERT_EQ(1U, frames.size());
  757. ASSERT_EQ(5U, frames[0]->header.payload_length);
  758. EXPECT_EQ(std::string("Hello"),
  759. std::string(frames[0]->payload, frames[0]->header.payload_length));
  760. }
  761. // Unknown extension in the response is rejected
  762. TEST_P(WebSocketStreamCreateExtensionTest, UnknownExtension) {
  763. CreateAndConnectWithExtensions("x-unknown-extension");
  764. EXPECT_FALSE(stream_);
  765. EXPECT_TRUE(has_failed());
  766. EXPECT_EQ("Error during WebSocket handshake: "
  767. "Found an unsupported extension 'x-unknown-extension' "
  768. "in 'Sec-WebSocket-Extensions' header",
  769. failure_message());
  770. }
  771. // Malformed extensions are rejected (this file does not cover all possible
  772. // parse failures, as the parser is covered thoroughly by its own unit tests).
  773. TEST_P(WebSocketStreamCreateExtensionTest, MalformedExtension) {
  774. CreateAndConnectWithExtensions(";");
  775. EXPECT_FALSE(stream_);
  776. EXPECT_TRUE(has_failed());
  777. EXPECT_EQ(
  778. "Error during WebSocket handshake: 'Sec-WebSocket-Extensions' header "
  779. "value is rejected by the parser: ;",
  780. failure_message());
  781. }
  782. // The permessage-deflate extension may only be specified once.
  783. TEST_P(WebSocketStreamCreateExtensionTest, OnlyOnePerMessageDeflateAllowed) {
  784. base::HistogramTester histogram_tester;
  785. CreateAndConnectWithExtensions(
  786. "permessage-deflate, permessage-deflate; client_max_window_bits=10");
  787. EXPECT_FALSE(stream_);
  788. EXPECT_TRUE(has_failed());
  789. EXPECT_EQ(
  790. "Error during WebSocket handshake: "
  791. "Received duplicate permessage-deflate response",
  792. failure_message());
  793. stream_request_.reset();
  794. auto samples = histogram_tester.GetHistogramSamplesSinceCreation(
  795. "Net.WebSocket.HandshakeResult2");
  796. EXPECT_EQ(1, samples->TotalCount());
  797. if (stream_type_ == BASIC_HANDSHAKE_STREAM) {
  798. EXPECT_EQ(
  799. 1,
  800. samples->GetCount(static_cast<int>(
  801. WebSocketHandshakeStreamBase::HandshakeResult::FAILED_EXTENSIONS)));
  802. } else {
  803. DCHECK_EQ(stream_type_, HTTP2_HANDSHAKE_STREAM);
  804. EXPECT_EQ(1, samples->GetCount(static_cast<int>(
  805. WebSocketHandshakeStreamBase::HandshakeResult::
  806. HTTP2_FAILED_EXTENSIONS)));
  807. }
  808. }
  809. // client_max_window_bits must have an argument
  810. TEST_P(WebSocketStreamCreateExtensionTest, NoMaxWindowBitsArgument) {
  811. CreateAndConnectWithExtensions("permessage-deflate; client_max_window_bits");
  812. EXPECT_FALSE(stream_);
  813. EXPECT_TRUE(has_failed());
  814. EXPECT_EQ(
  815. "Error during WebSocket handshake: Error in permessage-deflate: "
  816. "client_max_window_bits must have value",
  817. failure_message());
  818. }
  819. // Other cases for permessage-deflate parameters are tested in
  820. // websocket_deflate_parameters_test.cc.
  821. // TODO(ricea): Check that WebSocketDeflateStream is initialised with the
  822. // arguments from the server. This is difficult because the data written to the
  823. // socket is randomly masked.
  824. // Additional Sec-WebSocket-Accept headers should be rejected.
  825. TEST_P(WebSocketStreamCreateTest, DoubleAccept) {
  826. CreateAndConnectStandard(
  827. "ws://www.example.org/", NoSubProtocols(), {}, {},
  828. {{"Sec-WebSocket-Accept", "s3pPLMBiTxaQ9kYGzzhZRbK+xOo="}});
  829. WaitUntilConnectDone();
  830. EXPECT_FALSE(stream_);
  831. EXPECT_TRUE(has_failed());
  832. EXPECT_EQ("Error during WebSocket handshake: "
  833. "'Sec-WebSocket-Accept' header must not appear "
  834. "more than once in a response",
  835. failure_message());
  836. }
  837. // When upgrading an HTTP/1 connection, response code 200 is invalid and must be
  838. // rejected. Response code 101 means success. On the other hand, when
  839. // requesting a WebSocket stream over HTTP/2, response code 101 is invalid and
  840. // must be rejected. Response code 200 means success.
  841. TEST_P(WebSocketMultiProtocolStreamCreateTest, InvalidStatusCode) {
  842. base::HistogramTester histogram_tester;
  843. AddSSLData();
  844. if (stream_type_ == BASIC_HANDSHAKE_STREAM) {
  845. static const char kInvalidStatusCodeResponse[] =
  846. "HTTP/1.1 200 OK\r\n"
  847. "Upgrade: websocket\r\n"
  848. "Connection: Upgrade\r\n"
  849. "Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\r\n"
  850. "\r\n";
  851. CreateAndConnectCustomResponse("wss://www.example.org/", NoSubProtocols(),
  852. {}, {}, kInvalidStatusCodeResponse);
  853. } else {
  854. DCHECK_EQ(stream_type_, HTTP2_HANDSHAKE_STREAM);
  855. SetHttp2ResponseStatus("101");
  856. CreateAndConnectStandard("wss://www.example.org/", NoSubProtocols(), {}, {},
  857. {});
  858. }
  859. WaitUntilConnectDone();
  860. stream_request_.reset();
  861. EXPECT_TRUE(has_failed());
  862. auto samples = histogram_tester.GetHistogramSamplesSinceCreation(
  863. "Net.WebSocket.HandshakeResult2");
  864. EXPECT_EQ(1, samples->TotalCount());
  865. if (stream_type_ == BASIC_HANDSHAKE_STREAM) {
  866. EXPECT_EQ("Error during WebSocket handshake: Unexpected response code: 200",
  867. failure_message());
  868. EXPECT_EQ(failure_response_code(), 200);
  869. EXPECT_EQ(
  870. 1, samples->GetCount(static_cast<int>(
  871. WebSocketHandshakeStreamBase::HandshakeResult::INVALID_STATUS)));
  872. } else {
  873. DCHECK_EQ(stream_type_, HTTP2_HANDSHAKE_STREAM);
  874. EXPECT_EQ("Error during WebSocket handshake: Unexpected response code: 101",
  875. failure_message());
  876. EXPECT_EQ(failure_response_code(), 101);
  877. EXPECT_EQ(1, samples->GetCount(static_cast<int>(
  878. WebSocketHandshakeStreamBase::HandshakeResult::
  879. HTTP2_INVALID_STATUS)));
  880. }
  881. }
  882. // Redirects are not followed (according to the WHATWG WebSocket API, which
  883. // overrides RFC6455 for browser applications).
  884. TEST_P(WebSocketMultiProtocolStreamCreateTest, RedirectsRejected) {
  885. AddSSLData();
  886. if (stream_type_ == BASIC_HANDSHAKE_STREAM) {
  887. static const char kRedirectResponse[] =
  888. "HTTP/1.1 302 Moved Temporarily\r\n"
  889. "Content-Type: text/html\r\n"
  890. "Content-Length: 34\r\n"
  891. "Connection: keep-alive\r\n"
  892. "Location: wss://www.example.org/other\r\n"
  893. "\r\n"
  894. "<title>Moved</title><h1>Moved</h1>";
  895. CreateAndConnectCustomResponse("wss://www.example.org/", NoSubProtocols(),
  896. {}, {}, kRedirectResponse);
  897. } else {
  898. DCHECK_EQ(stream_type_, HTTP2_HANDSHAKE_STREAM);
  899. SetHttp2ResponseStatus("302");
  900. CreateAndConnectStandard("wss://www.example.org/", NoSubProtocols(), {}, {},
  901. {});
  902. }
  903. WaitUntilConnectDone();
  904. EXPECT_TRUE(has_failed());
  905. EXPECT_EQ("Error during WebSocket handshake: Unexpected response code: 302",
  906. failure_message());
  907. }
  908. // Malformed responses should be rejected. HttpStreamParser will accept just
  909. // about any garbage in the middle of the headers. To make it give up, the junk
  910. // has to be at the start of the response. Even then, it just gets treated as an
  911. // HTTP/0.9 response.
  912. TEST_P(WebSocketStreamCreateTest, MalformedResponse) {
  913. static const char kMalformedResponse[] =
  914. "220 mx.google.com ESMTP\r\n"
  915. "HTTP/1.1 101 OK\r\n"
  916. "Upgrade: websocket\r\n"
  917. "Connection: Upgrade\r\n"
  918. "Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\r\n"
  919. "\r\n";
  920. CreateAndConnectCustomResponse("ws://www.example.org/", NoSubProtocols(), {},
  921. {}, kMalformedResponse);
  922. WaitUntilConnectDone();
  923. EXPECT_TRUE(has_failed());
  924. EXPECT_EQ("Error during WebSocket handshake: Invalid status line",
  925. failure_message());
  926. }
  927. // Upgrade header must be present.
  928. TEST_P(WebSocketStreamCreateTest, MissingUpgradeHeader) {
  929. base::HistogramTester histogram_tester;
  930. static const char kMissingUpgradeResponse[] =
  931. "HTTP/1.1 101 Switching Protocols\r\n"
  932. "Connection: Upgrade\r\n"
  933. "Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\r\n"
  934. "\r\n";
  935. CreateAndConnectCustomResponse("ws://www.example.org/", NoSubProtocols(), {},
  936. {}, kMissingUpgradeResponse);
  937. WaitUntilConnectDone();
  938. EXPECT_TRUE(has_failed());
  939. EXPECT_EQ("Error during WebSocket handshake: 'Upgrade' header is missing",
  940. failure_message());
  941. stream_request_.reset();
  942. auto samples = histogram_tester.GetHistogramSamplesSinceCreation(
  943. "Net.WebSocket.HandshakeResult2");
  944. EXPECT_EQ(1, samples->TotalCount());
  945. EXPECT_EQ(
  946. 1, samples->GetCount(static_cast<int>(
  947. WebSocketHandshakeStreamBase::HandshakeResult::FAILED_UPGRADE)));
  948. }
  949. // There must only be one upgrade header.
  950. TEST_P(WebSocketStreamCreateTest, DoubleUpgradeHeader) {
  951. CreateAndConnectStandard("ws://www.example.org/", NoSubProtocols(), {}, {},
  952. {{"Upgrade", "HTTP/2.0"}});
  953. WaitUntilConnectDone();
  954. EXPECT_TRUE(has_failed());
  955. EXPECT_EQ("Error during WebSocket handshake: "
  956. "'Upgrade' header must not appear more than once in a response",
  957. failure_message());
  958. }
  959. // There must only be one correct upgrade header.
  960. TEST_P(WebSocketStreamCreateTest, IncorrectUpgradeHeader) {
  961. static const char kMissingUpgradeResponse[] =
  962. "HTTP/1.1 101 Switching Protocols\r\n"
  963. "Connection: Upgrade\r\n"
  964. "Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\r\n"
  965. "Upgrade: hogefuga\r\n"
  966. "\r\n";
  967. CreateAndConnectCustomResponse("ws://www.example.org/", NoSubProtocols(), {},
  968. {}, kMissingUpgradeResponse);
  969. WaitUntilConnectDone();
  970. EXPECT_TRUE(has_failed());
  971. EXPECT_EQ("Error during WebSocket handshake: "
  972. "'Upgrade' header value is not 'WebSocket': hogefuga",
  973. failure_message());
  974. }
  975. // Connection header must be present.
  976. TEST_P(WebSocketStreamCreateTest, MissingConnectionHeader) {
  977. base::HistogramTester histogram_tester;
  978. static const char kMissingConnectionResponse[] =
  979. "HTTP/1.1 101 Switching Protocols\r\n"
  980. "Upgrade: websocket\r\n"
  981. "Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\r\n"
  982. "\r\n";
  983. CreateAndConnectCustomResponse("ws://www.example.org/", NoSubProtocols(), {},
  984. {}, kMissingConnectionResponse);
  985. WaitUntilConnectDone();
  986. EXPECT_TRUE(has_failed());
  987. EXPECT_EQ("Error during WebSocket handshake: "
  988. "'Connection' header is missing",
  989. failure_message());
  990. stream_request_.reset();
  991. auto samples = histogram_tester.GetHistogramSamplesSinceCreation(
  992. "Net.WebSocket.HandshakeResult2");
  993. EXPECT_EQ(1, samples->TotalCount());
  994. EXPECT_EQ(
  995. 1,
  996. samples->GetCount(static_cast<int>(
  997. WebSocketHandshakeStreamBase::HandshakeResult::FAILED_CONNECTION)));
  998. }
  999. // Connection header must contain "Upgrade".
  1000. TEST_P(WebSocketStreamCreateTest, IncorrectConnectionHeader) {
  1001. static const char kMissingConnectionResponse[] =
  1002. "HTTP/1.1 101 Switching Protocols\r\n"
  1003. "Upgrade: websocket\r\n"
  1004. "Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\r\n"
  1005. "Connection: hogefuga\r\n"
  1006. "\r\n";
  1007. CreateAndConnectCustomResponse("ws://www.example.org/", NoSubProtocols(), {},
  1008. {}, kMissingConnectionResponse);
  1009. WaitUntilConnectDone();
  1010. EXPECT_TRUE(has_failed());
  1011. EXPECT_EQ("Error during WebSocket handshake: "
  1012. "'Connection' header value must contain 'Upgrade'",
  1013. failure_message());
  1014. }
  1015. // Connection header is permitted to contain other tokens.
  1016. TEST_P(WebSocketStreamCreateTest, AdditionalTokenInConnectionHeader) {
  1017. static const char kAdditionalConnectionTokenResponse[] =
  1018. "HTTP/1.1 101 Switching Protocols\r\n"
  1019. "Upgrade: websocket\r\n"
  1020. "Connection: Upgrade, Keep-Alive\r\n"
  1021. "Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\r\n"
  1022. "\r\n";
  1023. CreateAndConnectCustomResponse("ws://www.example.org/", NoSubProtocols(), {},
  1024. {}, kAdditionalConnectionTokenResponse);
  1025. WaitUntilConnectDone();
  1026. EXPECT_FALSE(has_failed());
  1027. EXPECT_TRUE(stream_);
  1028. }
  1029. // Sec-WebSocket-Accept header must be present.
  1030. TEST_P(WebSocketStreamCreateTest, MissingSecWebSocketAccept) {
  1031. base::HistogramTester histogram_tester;
  1032. static const char kMissingAcceptResponse[] =
  1033. "HTTP/1.1 101 Switching Protocols\r\n"
  1034. "Upgrade: websocket\r\n"
  1035. "Connection: Upgrade\r\n"
  1036. "\r\n";
  1037. CreateAndConnectCustomResponse("ws://www.example.org/", NoSubProtocols(), {},
  1038. {}, kMissingAcceptResponse);
  1039. WaitUntilConnectDone();
  1040. EXPECT_TRUE(has_failed());
  1041. EXPECT_EQ("Error during WebSocket handshake: "
  1042. "'Sec-WebSocket-Accept' header is missing",
  1043. failure_message());
  1044. stream_request_.reset();
  1045. auto samples = histogram_tester.GetHistogramSamplesSinceCreation(
  1046. "Net.WebSocket.HandshakeResult2");
  1047. EXPECT_EQ(1, samples->TotalCount());
  1048. EXPECT_EQ(1,
  1049. samples->GetCount(static_cast<int>(
  1050. WebSocketHandshakeStreamBase::HandshakeResult::FAILED_ACCEPT)));
  1051. }
  1052. // Sec-WebSocket-Accept header must match the key that was sent.
  1053. TEST_P(WebSocketStreamCreateTest, WrongSecWebSocketAccept) {
  1054. static const char kIncorrectAcceptResponse[] =
  1055. "HTTP/1.1 101 Switching Protocols\r\n"
  1056. "Upgrade: websocket\r\n"
  1057. "Connection: Upgrade\r\n"
  1058. "Sec-WebSocket-Accept: x/byyPZ2tOFvJCGkkugcKvqhhPk=\r\n"
  1059. "\r\n";
  1060. CreateAndConnectCustomResponse("ws://www.example.org/", NoSubProtocols(), {},
  1061. {}, kIncorrectAcceptResponse);
  1062. WaitUntilConnectDone();
  1063. EXPECT_TRUE(has_failed());
  1064. EXPECT_EQ("Error during WebSocket handshake: "
  1065. "Incorrect 'Sec-WebSocket-Accept' header value",
  1066. failure_message());
  1067. }
  1068. // Cancellation works.
  1069. TEST_P(WebSocketStreamCreateTest, Cancellation) {
  1070. CreateAndConnectStandard("ws://www.example.org/", NoSubProtocols(), {}, {},
  1071. {});
  1072. stream_request_.reset();
  1073. // WaitUntilConnectDone doesn't work in this case.
  1074. base::RunLoop().RunUntilIdle();
  1075. EXPECT_FALSE(has_failed());
  1076. EXPECT_FALSE(stream_);
  1077. EXPECT_FALSE(request_info_);
  1078. EXPECT_FALSE(response_info_);
  1079. }
  1080. // Connect failure must look just like negotiation failure.
  1081. TEST_P(WebSocketStreamCreateTest, ConnectionFailure) {
  1082. std::unique_ptr<SequencedSocketData> socket_data(BuildNullSocketData());
  1083. socket_data->set_connect_data(
  1084. MockConnect(SYNCHRONOUS, ERR_CONNECTION_REFUSED));
  1085. CreateAndConnectRawExpectations("ws://www.example.org/", NoSubProtocols(),
  1086. HttpRequestHeaders(), std::move(socket_data));
  1087. WaitUntilConnectDone();
  1088. EXPECT_TRUE(has_failed());
  1089. EXPECT_EQ("Error in connection establishment: net::ERR_CONNECTION_REFUSED",
  1090. failure_message());
  1091. EXPECT_FALSE(request_info_);
  1092. EXPECT_FALSE(response_info_);
  1093. }
  1094. // Connect timeout must look just like any other failure.
  1095. TEST_P(WebSocketStreamCreateTest, ConnectionTimeout) {
  1096. std::unique_ptr<SequencedSocketData> socket_data(BuildNullSocketData());
  1097. socket_data->set_connect_data(
  1098. MockConnect(ASYNC, ERR_CONNECTION_TIMED_OUT));
  1099. CreateAndConnectRawExpectations("ws://www.example.org/", NoSubProtocols(),
  1100. HttpRequestHeaders(), std::move(socket_data));
  1101. WaitUntilConnectDone();
  1102. EXPECT_TRUE(has_failed());
  1103. EXPECT_EQ("Error in connection establishment: net::ERR_CONNECTION_TIMED_OUT",
  1104. failure_message());
  1105. }
  1106. // The server doesn't respond to the opening handshake.
  1107. TEST_P(WebSocketStreamCreateTest, HandshakeTimeout) {
  1108. std::unique_ptr<SequencedSocketData> socket_data(BuildNullSocketData());
  1109. socket_data->set_connect_data(MockConnect(SYNCHRONOUS, ERR_IO_PENDING));
  1110. auto timer = std::make_unique<MockWeakTimer>();
  1111. base::WeakPtr<MockWeakTimer> weak_timer = timer->AsWeakPtr();
  1112. SetTimer(std::move(timer));
  1113. CreateAndConnectRawExpectations("ws://www.example.org/", NoSubProtocols(),
  1114. HttpRequestHeaders(), std::move(socket_data));
  1115. EXPECT_FALSE(has_failed());
  1116. ASSERT_TRUE(weak_timer.get());
  1117. EXPECT_TRUE(weak_timer->IsRunning());
  1118. weak_timer->Fire();
  1119. WaitUntilConnectDone();
  1120. EXPECT_TRUE(has_failed());
  1121. EXPECT_EQ("WebSocket opening handshake timed out", failure_message());
  1122. ASSERT_TRUE(weak_timer.get());
  1123. EXPECT_FALSE(weak_timer->IsRunning());
  1124. }
  1125. // When the connection establishes the timer should be stopped.
  1126. TEST_P(WebSocketStreamCreateTest, HandshakeTimerOnSuccess) {
  1127. auto timer = std::make_unique<MockWeakTimer>();
  1128. base::WeakPtr<MockWeakTimer> weak_timer = timer->AsWeakPtr();
  1129. SetTimer(std::move(timer));
  1130. CreateAndConnectStandard("ws://www.example.org/", NoSubProtocols(), {}, {},
  1131. {});
  1132. ASSERT_TRUE(weak_timer);
  1133. EXPECT_TRUE(weak_timer->IsRunning());
  1134. WaitUntilConnectDone();
  1135. EXPECT_FALSE(has_failed());
  1136. EXPECT_TRUE(stream_);
  1137. ASSERT_TRUE(weak_timer);
  1138. EXPECT_FALSE(weak_timer->IsRunning());
  1139. }
  1140. // When the connection fails the timer should be stopped.
  1141. TEST_P(WebSocketStreamCreateTest, HandshakeTimerOnFailure) {
  1142. std::unique_ptr<SequencedSocketData> socket_data(BuildNullSocketData());
  1143. socket_data->set_connect_data(
  1144. MockConnect(SYNCHRONOUS, ERR_CONNECTION_REFUSED));
  1145. auto timer = std::make_unique<MockWeakTimer>();
  1146. base::WeakPtr<MockWeakTimer> weak_timer = timer->AsWeakPtr();
  1147. SetTimer(std::move(timer));
  1148. CreateAndConnectRawExpectations("ws://www.example.org/", NoSubProtocols(),
  1149. HttpRequestHeaders(), std::move(socket_data));
  1150. ASSERT_TRUE(weak_timer.get());
  1151. EXPECT_TRUE(weak_timer->IsRunning());
  1152. WaitUntilConnectDone();
  1153. EXPECT_TRUE(has_failed());
  1154. EXPECT_EQ("Error in connection establishment: net::ERR_CONNECTION_REFUSED",
  1155. failure_message());
  1156. ASSERT_TRUE(weak_timer.get());
  1157. EXPECT_FALSE(weak_timer->IsRunning());
  1158. }
  1159. // Cancellation during connect works.
  1160. TEST_P(WebSocketStreamCreateTest, CancellationDuringConnect) {
  1161. std::unique_ptr<SequencedSocketData> socket_data(BuildNullSocketData());
  1162. socket_data->set_connect_data(MockConnect(SYNCHRONOUS, ERR_IO_PENDING));
  1163. CreateAndConnectRawExpectations("ws://www.example.org/", NoSubProtocols(),
  1164. HttpRequestHeaders(), std::move(socket_data));
  1165. stream_request_.reset();
  1166. // WaitUntilConnectDone doesn't work in this case.
  1167. base::RunLoop().RunUntilIdle();
  1168. EXPECT_FALSE(has_failed());
  1169. EXPECT_FALSE(stream_);
  1170. }
  1171. // Cancellation during write of the request headers works.
  1172. TEST_P(WebSocketStreamCreateTest, CancellationDuringWrite) {
  1173. // First write never completes.
  1174. MockWrite writes[] = {MockWrite(SYNCHRONOUS, ERR_IO_PENDING, 0)};
  1175. auto socket_data =
  1176. std::make_unique<SequencedSocketData>(base::span<MockRead>(), writes);
  1177. auto* socket_data_ptr = socket_data.get();
  1178. socket_data->set_connect_data(MockConnect(SYNCHRONOUS, OK));
  1179. CreateAndConnectRawExpectations("ws://www.example.org/", NoSubProtocols(),
  1180. HttpRequestHeaders(), std::move(socket_data));
  1181. base::RunLoop().RunUntilIdle();
  1182. EXPECT_TRUE(socket_data_ptr->AllWriteDataConsumed());
  1183. stream_request_.reset();
  1184. // WaitUntilConnectDone doesn't work in this case.
  1185. base::RunLoop().RunUntilIdle();
  1186. EXPECT_FALSE(has_failed());
  1187. EXPECT_FALSE(stream_);
  1188. EXPECT_TRUE(request_info_);
  1189. EXPECT_FALSE(response_info_);
  1190. }
  1191. // Cancellation during read of the response headers works.
  1192. TEST_P(WebSocketStreamCreateTest, CancellationDuringRead) {
  1193. std::string request = WebSocketStandardRequest(
  1194. "/", "www.example.org", Origin(), /*send_additional_request_headers=*/{},
  1195. /*extra_headers=*/{});
  1196. MockWrite writes[] = {MockWrite(ASYNC, 0, request.c_str())};
  1197. MockRead reads[] = {
  1198. MockRead(SYNCHRONOUS, ERR_IO_PENDING, 1),
  1199. };
  1200. std::unique_ptr<SequencedSocketData> socket_data(
  1201. BuildSocketData(reads, writes));
  1202. SequencedSocketData* socket_data_raw_ptr = socket_data.get();
  1203. CreateAndConnectRawExpectations("ws://www.example.org/", NoSubProtocols(),
  1204. HttpRequestHeaders(), std::move(socket_data));
  1205. base::RunLoop().RunUntilIdle();
  1206. EXPECT_TRUE(socket_data_raw_ptr->AllReadDataConsumed());
  1207. stream_request_.reset();
  1208. // WaitUntilConnectDone doesn't work in this case.
  1209. base::RunLoop().RunUntilIdle();
  1210. EXPECT_FALSE(has_failed());
  1211. EXPECT_FALSE(stream_);
  1212. EXPECT_TRUE(request_info_);
  1213. EXPECT_FALSE(response_info_);
  1214. }
  1215. // Over-size response headers (> 256KB) should not cause a crash. This is a
  1216. // regression test for crbug.com/339456. It is based on the layout test
  1217. // "cookie-flood.html".
  1218. TEST_P(WebSocketStreamCreateTest, VeryLargeResponseHeaders) {
  1219. base::HistogramTester histogram_tester;
  1220. std::string set_cookie_headers;
  1221. set_cookie_headers.reserve(24 * 20000);
  1222. for (int i = 0; i < 20000; ++i) {
  1223. set_cookie_headers += base::StringPrintf("Set-Cookie: ws-%d=1\r\n", i);
  1224. }
  1225. ASSERT_GT(set_cookie_headers.size(), 256U * 1024U);
  1226. CreateAndConnectStringResponse("ws://www.example.org/", NoSubProtocols(),
  1227. set_cookie_headers);
  1228. WaitUntilConnectDone();
  1229. EXPECT_TRUE(has_failed());
  1230. EXPECT_FALSE(response_info_);
  1231. stream_request_.reset();
  1232. auto samples = histogram_tester.GetHistogramSamplesSinceCreation(
  1233. "Net.WebSocket.HandshakeResult2");
  1234. EXPECT_EQ(1, samples->TotalCount());
  1235. EXPECT_EQ(1, samples->GetCount(static_cast<int>(
  1236. WebSocketHandshakeStreamBase::HandshakeResult::FAILED)));
  1237. }
  1238. // If the remote host closes the connection without sending headers, we should
  1239. // log the console message "Connection closed before receiving a handshake
  1240. // response".
  1241. TEST_P(WebSocketStreamCreateTest, NoResponse) {
  1242. base::HistogramTester histogram_tester;
  1243. std::string request = WebSocketStandardRequest(
  1244. "/", "www.example.org", Origin(), /*send_additional_request_headers=*/{},
  1245. /*extra_headers=*/{});
  1246. MockWrite writes[] = {MockWrite(ASYNC, request.data(), request.size(), 0)};
  1247. MockRead reads[] = {MockRead(ASYNC, 0, 1)};
  1248. std::unique_ptr<SequencedSocketData> socket_data(
  1249. BuildSocketData(reads, writes));
  1250. SequencedSocketData* socket_data_raw_ptr = socket_data.get();
  1251. CreateAndConnectRawExpectations("ws://www.example.org/", NoSubProtocols(),
  1252. HttpRequestHeaders(), std::move(socket_data));
  1253. base::RunLoop().RunUntilIdle();
  1254. EXPECT_TRUE(socket_data_raw_ptr->AllReadDataConsumed());
  1255. EXPECT_TRUE(has_failed());
  1256. EXPECT_FALSE(stream_);
  1257. EXPECT_FALSE(response_info_);
  1258. EXPECT_EQ("Connection closed before receiving a handshake response",
  1259. failure_message());
  1260. stream_request_.reset();
  1261. auto samples = histogram_tester.GetHistogramSamplesSinceCreation(
  1262. "Net.WebSocket.HandshakeResult2");
  1263. EXPECT_EQ(1, samples->TotalCount());
  1264. EXPECT_EQ(
  1265. 1, samples->GetCount(static_cast<int>(
  1266. WebSocketHandshakeStreamBase::HandshakeResult::EMPTY_RESPONSE)));
  1267. }
  1268. TEST_P(WebSocketStreamCreateTest, SelfSignedCertificateFailure) {
  1269. auto ssl_socket_data = std::make_unique<SSLSocketDataProvider>(
  1270. ASYNC, ERR_CERT_AUTHORITY_INVALID);
  1271. ssl_socket_data->ssl_info.cert =
  1272. ImportCertFromFile(GetTestCertsDirectory(), "unittest.selfsigned.der");
  1273. ASSERT_TRUE(ssl_socket_data->ssl_info.cert.get());
  1274. url_request_context_host_.AddSSLSocketDataProvider(
  1275. std::move(ssl_socket_data));
  1276. std::unique_ptr<SequencedSocketData> raw_socket_data(BuildNullSocketData());
  1277. CreateAndConnectRawExpectations("wss://www.example.org/", NoSubProtocols(),
  1278. HttpRequestHeaders(),
  1279. std::move(raw_socket_data));
  1280. // WaitUntilConnectDone doesn't work in this case.
  1281. base::RunLoop().RunUntilIdle();
  1282. EXPECT_FALSE(has_failed());
  1283. ASSERT_TRUE(ssl_error_callbacks_);
  1284. ssl_error_callbacks_->CancelSSLRequest(ERR_CERT_AUTHORITY_INVALID,
  1285. &ssl_info_);
  1286. WaitUntilConnectDone();
  1287. EXPECT_TRUE(has_failed());
  1288. }
  1289. TEST_P(WebSocketStreamCreateTest, SelfSignedCertificateSuccess) {
  1290. auto ssl_socket_data = std::make_unique<SSLSocketDataProvider>(
  1291. ASYNC, ERR_CERT_AUTHORITY_INVALID);
  1292. ssl_socket_data->ssl_info.cert =
  1293. ImportCertFromFile(GetTestCertsDirectory(), "unittest.selfsigned.der");
  1294. ASSERT_TRUE(ssl_socket_data->ssl_info.cert.get());
  1295. url_request_context_host_.AddSSLSocketDataProvider(
  1296. std::move(ssl_socket_data));
  1297. url_request_context_host_.AddSSLSocketDataProvider(
  1298. std::make_unique<SSLSocketDataProvider>(ASYNC, OK));
  1299. AddRawExpectations(BuildNullSocketData());
  1300. CreateAndConnectStandard("wss://www.example.org/", NoSubProtocols(), {}, {},
  1301. {});
  1302. // WaitUntilConnectDone doesn't work in this case.
  1303. base::RunLoop().RunUntilIdle();
  1304. ASSERT_TRUE(ssl_error_callbacks_);
  1305. ssl_error_callbacks_->ContinueSSLRequest();
  1306. WaitUntilConnectDone();
  1307. EXPECT_FALSE(has_failed());
  1308. EXPECT_TRUE(stream_);
  1309. }
  1310. // If the server requests authorisation, but we have no credentials, the
  1311. // connection should fail cleanly.
  1312. TEST_P(WebSocketStreamCreateBasicAuthTest, FailureNoCredentials) {
  1313. CreateAndConnectCustomResponse("ws://www.example.org/", NoSubProtocols(), {},
  1314. {}, kUnauthorizedResponse);
  1315. WaitUntilConnectDone();
  1316. EXPECT_TRUE(has_failed());
  1317. EXPECT_EQ("HTTP Authentication failed; no valid credentials available",
  1318. failure_message());
  1319. EXPECT_FALSE(response_info_);
  1320. }
  1321. TEST_P(WebSocketStreamCreateBasicAuthTest, SuccessPasswordInUrl) {
  1322. CreateAndConnectAuthHandshake("ws://foo:bar@www.example.org/", "Zm9vOmJhcg==",
  1323. WebSocketStandardResponse(std::string()));
  1324. WaitUntilConnectDone();
  1325. EXPECT_FALSE(has_failed());
  1326. EXPECT_TRUE(stream_);
  1327. ASSERT_TRUE(response_info_);
  1328. EXPECT_EQ(101, response_info_->headers->response_code());
  1329. }
  1330. TEST_P(WebSocketStreamCreateBasicAuthTest, FailureIncorrectPasswordInUrl) {
  1331. CreateAndConnectAuthHandshake("ws://foo:baz@www.example.org/",
  1332. "Zm9vOmJheg==", kUnauthorizedResponse);
  1333. WaitUntilConnectDone();
  1334. EXPECT_TRUE(has_failed());
  1335. EXPECT_FALSE(response_info_);
  1336. }
  1337. TEST_P(WebSocketStreamCreateBasicAuthTest, SuccessfulConnectionReuse) {
  1338. std::string request1 = WebSocketStandardRequest(
  1339. "/", "www.example.org", Origin(), /*send_additional_request_headers=*/{},
  1340. /*extra_headers=*/{});
  1341. std::string response1 = kUnauthorizedResponse;
  1342. std::string request2 = WebSocketStandardRequest(
  1343. "/", "www.example.org", Origin(),
  1344. {{"Authorization", "Basic Zm9vOmJhcg=="}}, /*extra_headers=*/{});
  1345. std::string response2 = WebSocketStandardResponse(std::string());
  1346. MockWrite writes[] = {
  1347. MockWrite(SYNCHRONOUS, 0, request1.c_str()),
  1348. MockWrite(SYNCHRONOUS, 2, request2.c_str()),
  1349. };
  1350. MockRead reads[3] = {
  1351. MockRead(SYNCHRONOUS, 1, response1.c_str()),
  1352. MockRead(SYNCHRONOUS, 3, response2.c_str()),
  1353. MockRead(SYNCHRONOUS, ERR_IO_PENDING, 4),
  1354. };
  1355. CreateAndConnectRawExpectations("ws://foo:bar@www.example.org/",
  1356. NoSubProtocols(), HttpRequestHeaders(),
  1357. BuildSocketData(reads, writes));
  1358. WaitUntilConnectDone();
  1359. EXPECT_FALSE(has_failed());
  1360. EXPECT_TRUE(stream_);
  1361. ASSERT_TRUE(response_info_);
  1362. EXPECT_EQ(101, response_info_->headers->response_code());
  1363. }
  1364. TEST_P(WebSocketStreamCreateBasicAuthTest, OnAuthRequiredCancelAuth) {
  1365. CreateAndConnectCustomResponse("ws://www.example.org/", NoSubProtocols(), {},
  1366. {}, kUnauthorizedResponse);
  1367. EXPECT_FALSE(request_info_);
  1368. EXPECT_FALSE(response_info_);
  1369. on_auth_required_rv_ = ERR_IO_PENDING;
  1370. WaitUntilOnAuthRequired();
  1371. EXPECT_FALSE(stream_);
  1372. EXPECT_FALSE(has_failed());
  1373. std::move(on_auth_required_callback_).Run(nullptr);
  1374. WaitUntilConnectDone();
  1375. EXPECT_FALSE(stream_);
  1376. EXPECT_TRUE(has_failed());
  1377. }
  1378. TEST_P(WebSocketStreamCreateBasicAuthTest, OnAuthRequiredSetAuth) {
  1379. CreateAndConnectRawExpectations(
  1380. "ws://www.example.org/", NoSubProtocols(), HttpRequestHeaders(),
  1381. helper_.BuildAuthSocketData(kUnauthorizedResponse,
  1382. RequestExpectation("Zm9vOmJheg=="),
  1383. WebSocketStandardResponse(std::string())));
  1384. EXPECT_FALSE(request_info_);
  1385. EXPECT_FALSE(response_info_);
  1386. on_auth_required_rv_ = ERR_IO_PENDING;
  1387. WaitUntilOnAuthRequired();
  1388. EXPECT_FALSE(stream_);
  1389. EXPECT_FALSE(has_failed());
  1390. AuthCredentials credentials(u"foo", u"baz");
  1391. std::move(on_auth_required_callback_).Run(&credentials);
  1392. WaitUntilConnectDone();
  1393. EXPECT_TRUE(stream_);
  1394. EXPECT_FALSE(has_failed());
  1395. }
  1396. // Digest auth has the same connection semantics as Basic auth, so we can
  1397. // generally assume that whatever works for Basic auth will also work for
  1398. // Digest. There's just one test here, to confirm that it works at all.
  1399. TEST_P(WebSocketStreamCreateDigestAuthTest, DigestPasswordInUrl) {
  1400. CreateAndConnectRawExpectations(
  1401. "ws://FooBar:pass@www.example.org/", NoSubProtocols(),
  1402. HttpRequestHeaders(),
  1403. helper_.BuildAuthSocketData(kUnauthorizedResponse, kAuthorizedRequest,
  1404. WebSocketStandardResponse(std::string())));
  1405. WaitUntilConnectDone();
  1406. EXPECT_FALSE(has_failed());
  1407. EXPECT_TRUE(stream_);
  1408. ASSERT_TRUE(response_info_);
  1409. EXPECT_EQ(101, response_info_->headers->response_code());
  1410. }
  1411. TEST_P(WebSocketMultiProtocolStreamCreateTest, Incomplete) {
  1412. base::HistogramTester histogram_tester;
  1413. AddSSLData();
  1414. if (stream_type_ == BASIC_HANDSHAKE_STREAM) {
  1415. std::string request = WebSocketStandardRequest(
  1416. "/", "www.example.org", Origin(),
  1417. /*send_additional_request_headers=*/{}, /*extra_headers=*/{});
  1418. MockRead reads[] = {MockRead(ASYNC, ERR_IO_PENDING, 0)};
  1419. MockWrite writes[] = {MockWrite(ASYNC, 1, request.c_str())};
  1420. CreateAndConnectRawExpectations("wss://www.example.org/", NoSubProtocols(),
  1421. HttpRequestHeaders(),
  1422. BuildSocketData(reads, writes));
  1423. base::RunLoop().RunUntilIdle();
  1424. stream_request_.reset();
  1425. auto samples = histogram_tester.GetHistogramSamplesSinceCreation(
  1426. "Net.WebSocket.HandshakeResult2");
  1427. EXPECT_EQ(1, samples->TotalCount());
  1428. EXPECT_EQ(1,
  1429. samples->GetCount(static_cast<int>(
  1430. WebSocketHandshakeStreamBase::HandshakeResult::INCOMPLETE)));
  1431. } else {
  1432. DCHECK_EQ(stream_type_, HTTP2_HANDSHAKE_STREAM);
  1433. CreateAndConnectStandard("wss://www.example.org/", NoSubProtocols(), {}, {},
  1434. {});
  1435. stream_request_.reset();
  1436. auto samples = histogram_tester.GetHistogramSamplesSinceCreation(
  1437. "Net.WebSocket.HandshakeResult2");
  1438. EXPECT_EQ(1, samples->TotalCount());
  1439. EXPECT_EQ(
  1440. 1,
  1441. samples->GetCount(static_cast<int>(
  1442. WebSocketHandshakeStreamBase::HandshakeResult::HTTP2_INCOMPLETE)));
  1443. }
  1444. }
  1445. TEST_P(WebSocketMultiProtocolStreamCreateTest, Http2StreamReset) {
  1446. AddSSLData();
  1447. if (stream_type_ == BASIC_HANDSHAKE_STREAM) {
  1448. // This is a dummy transaction to avoid crash in ~URLRequestContext().
  1449. CreateAndConnectStandard("wss://www.example.org/", NoSubProtocols(), {}, {},
  1450. {});
  1451. } else {
  1452. DCHECK_EQ(stream_type_, HTTP2_HANDSHAKE_STREAM);
  1453. base::HistogramTester histogram_tester;
  1454. SetResetWebSocketHttp2Stream(true);
  1455. CreateAndConnectStandard("wss://www.example.org/", NoSubProtocols(), {}, {},
  1456. {});
  1457. base::RunLoop().RunUntilIdle();
  1458. stream_request_.reset();
  1459. EXPECT_TRUE(has_failed());
  1460. EXPECT_EQ("Stream closed with error: net::ERR_HTTP2_PROTOCOL_ERROR",
  1461. failure_message());
  1462. auto samples = histogram_tester.GetHistogramSamplesSinceCreation(
  1463. "Net.WebSocket.HandshakeResult2");
  1464. EXPECT_EQ(1, samples->TotalCount());
  1465. EXPECT_EQ(
  1466. 1, samples->GetCount(static_cast<int>(
  1467. WebSocketHandshakeStreamBase::HandshakeResult::HTTP2_FAILED)));
  1468. }
  1469. }
  1470. TEST_P(WebSocketStreamCreateTest, HandleErrConnectionClosed) {
  1471. base::HistogramTester histogram_tester;
  1472. static const char kTruncatedResponse[] =
  1473. "HTTP/1.1 101 Switching Protocols\r\n"
  1474. "Upgrade: websocket\r\n"
  1475. "Connection: Upgrade\r\n"
  1476. "Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\r\n"
  1477. "Cache-Control: no-sto";
  1478. std::string request = WebSocketStandardRequest(
  1479. "/", "www.example.org", Origin(), /*send_additional_request_headers=*/{},
  1480. /*extra_headers=*/{});
  1481. MockRead reads[] = {
  1482. MockRead(SYNCHRONOUS, 1, kTruncatedResponse),
  1483. MockRead(SYNCHRONOUS, ERR_CONNECTION_CLOSED, 2),
  1484. };
  1485. MockWrite writes[] = {MockWrite(SYNCHRONOUS, 0, request.c_str())};
  1486. std::unique_ptr<SequencedSocketData> socket_data(
  1487. BuildSocketData(reads, writes));
  1488. socket_data->set_connect_data(MockConnect(SYNCHRONOUS, OK));
  1489. CreateAndConnectRawExpectations("ws://www.example.org/", NoSubProtocols(),
  1490. HttpRequestHeaders(), std::move(socket_data));
  1491. WaitUntilConnectDone();
  1492. EXPECT_TRUE(has_failed());
  1493. stream_request_.reset();
  1494. auto samples = histogram_tester.GetHistogramSamplesSinceCreation(
  1495. "Net.WebSocket.HandshakeResult2");
  1496. EXPECT_EQ(1, samples->TotalCount());
  1497. EXPECT_EQ(1, samples->GetCount(static_cast<int>(
  1498. WebSocketHandshakeStreamBase::HandshakeResult::
  1499. FAILED_SWITCHING_PROTOCOLS)));
  1500. }
  1501. TEST_P(WebSocketStreamCreateTest, HandleErrTunnelConnectionFailed) {
  1502. static const char kConnectRequest[] =
  1503. "CONNECT www.example.org:80 HTTP/1.1\r\n"
  1504. "Host: www.example.org:80\r\n"
  1505. "Proxy-Connection: keep-alive\r\n"
  1506. "\r\n";
  1507. static const char kProxyResponse[] =
  1508. "HTTP/1.1 403 Forbidden\r\n"
  1509. "Content-Type: text/html\r\n"
  1510. "Content-Length: 9\r\n"
  1511. "Connection: keep-alive\r\n"
  1512. "\r\n"
  1513. "Forbidden";
  1514. MockRead reads[] = {MockRead(SYNCHRONOUS, 1, kProxyResponse)};
  1515. MockWrite writes[] = {MockWrite(SYNCHRONOUS, 0, kConnectRequest)};
  1516. std::unique_ptr<SequencedSocketData> socket_data(
  1517. BuildSocketData(reads, writes));
  1518. url_request_context_host_.SetProxyConfig("https=proxy:8000");
  1519. CreateAndConnectRawExpectations("ws://www.example.org/", NoSubProtocols(),
  1520. HttpRequestHeaders(), std::move(socket_data));
  1521. WaitUntilConnectDone();
  1522. EXPECT_TRUE(has_failed());
  1523. EXPECT_EQ("Establishing a tunnel via proxy server failed.",
  1524. failure_message());
  1525. }
  1526. TEST_P(WebSocketStreamCreateTest, CancelSSLRequestAfterDelete) {
  1527. auto ssl_socket_data = std::make_unique<SSLSocketDataProvider>(
  1528. ASYNC, ERR_CERT_AUTHORITY_INVALID);
  1529. ssl_socket_data->ssl_info.cert =
  1530. ImportCertFromFile(GetTestCertsDirectory(), "unittest.selfsigned.der");
  1531. ASSERT_TRUE(ssl_socket_data->ssl_info.cert.get());
  1532. url_request_context_host_.AddSSLSocketDataProvider(
  1533. std::move(ssl_socket_data));
  1534. MockRead reads[] = {MockRead(SYNCHRONOUS, ERR_CONNECTION_RESET, 0)};
  1535. MockWrite writes[] = {MockWrite(SYNCHRONOUS, ERR_CONNECTION_RESET, 1)};
  1536. std::unique_ptr<SequencedSocketData> raw_socket_data(
  1537. BuildSocketData(reads, writes));
  1538. CreateAndConnectRawExpectations("wss://www.example.org/", NoSubProtocols(),
  1539. HttpRequestHeaders(),
  1540. std::move(raw_socket_data));
  1541. base::RunLoop().RunUntilIdle();
  1542. EXPECT_FALSE(has_failed());
  1543. ASSERT_TRUE(ssl_error_callbacks_);
  1544. stream_request_.reset();
  1545. ssl_error_callbacks_->CancelSSLRequest(ERR_CERT_AUTHORITY_INVALID,
  1546. &ssl_info_);
  1547. }
  1548. TEST_P(WebSocketStreamCreateTest, ContinueSSLRequestAfterDelete) {
  1549. auto ssl_socket_data = std::make_unique<SSLSocketDataProvider>(
  1550. ASYNC, ERR_CERT_AUTHORITY_INVALID);
  1551. ssl_socket_data->ssl_info.cert =
  1552. ImportCertFromFile(GetTestCertsDirectory(), "unittest.selfsigned.der");
  1553. ASSERT_TRUE(ssl_socket_data->ssl_info.cert.get());
  1554. url_request_context_host_.AddSSLSocketDataProvider(
  1555. std::move(ssl_socket_data));
  1556. MockRead reads[] = {MockRead(SYNCHRONOUS, ERR_CONNECTION_RESET, 0)};
  1557. MockWrite writes[] = {MockWrite(SYNCHRONOUS, ERR_CONNECTION_RESET, 1)};
  1558. std::unique_ptr<SequencedSocketData> raw_socket_data(
  1559. BuildSocketData(reads, writes));
  1560. CreateAndConnectRawExpectations("wss://www.example.org/", NoSubProtocols(),
  1561. HttpRequestHeaders(),
  1562. std::move(raw_socket_data));
  1563. base::RunLoop().RunUntilIdle();
  1564. EXPECT_FALSE(has_failed());
  1565. ASSERT_TRUE(ssl_error_callbacks_);
  1566. stream_request_.reset();
  1567. ssl_error_callbacks_->ContinueSSLRequest();
  1568. }
  1569. TEST_P(WebSocketStreamCreateTest, HandleConnectionCloseInFirstSegment) {
  1570. std::string request = WebSocketStandardRequest(
  1571. "/", "www.example.org", Origin(), /*send_additional_request_headers=*/{},
  1572. /*extra_headers=*/{});
  1573. // The response headers are immediately followed by a close frame, length 11,
  1574. // code 1013, reason "Try Again".
  1575. std::string close_body = "\x03\xf5Try Again";
  1576. std::string response = WebSocketStandardResponse(std::string()) + "\x88" +
  1577. static_cast<char>(close_body.size()) + close_body;
  1578. MockRead reads[] = {
  1579. MockRead(SYNCHRONOUS, response.data(), response.size(), 1),
  1580. MockRead(SYNCHRONOUS, ERR_CONNECTION_CLOSED, 2),
  1581. };
  1582. MockWrite writes[] = {MockWrite(SYNCHRONOUS, 0, request.c_str())};
  1583. std::unique_ptr<SequencedSocketData> socket_data(
  1584. BuildSocketData(reads, writes));
  1585. socket_data->set_connect_data(MockConnect(SYNCHRONOUS, OK));
  1586. CreateAndConnectRawExpectations("ws://www.example.org/", NoSubProtocols(),
  1587. HttpRequestHeaders(), std::move(socket_data));
  1588. WaitUntilConnectDone();
  1589. ASSERT_TRUE(stream_);
  1590. std::vector<std::unique_ptr<WebSocketFrame>> frames;
  1591. TestCompletionCallback callback1;
  1592. int rv1 = stream_->ReadFrames(&frames, callback1.callback());
  1593. rv1 = callback1.GetResult(rv1);
  1594. ASSERT_THAT(rv1, IsOk());
  1595. ASSERT_EQ(1U, frames.size());
  1596. EXPECT_EQ(frames[0]->header.opcode, WebSocketFrameHeader::kOpCodeClose);
  1597. EXPECT_TRUE(frames[0]->header.final);
  1598. EXPECT_EQ(close_body,
  1599. std::string(frames[0]->payload, frames[0]->header.payload_length));
  1600. std::vector<std::unique_ptr<WebSocketFrame>> empty_frames;
  1601. TestCompletionCallback callback2;
  1602. int rv2 = stream_->ReadFrames(&empty_frames, callback2.callback());
  1603. rv2 = callback2.GetResult(rv2);
  1604. ASSERT_THAT(rv2, IsError(ERR_CONNECTION_CLOSED));
  1605. }
  1606. } // namespace
  1607. } // namespace net