• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2015 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include <memory>
6 #include <string>
7 #include <utility>
8 #include <vector>
9 
10 #include "base/functional/bind.h"
11 #include "base/functional/callback_forward.h"
12 #include "base/location.h"
13 #include "base/memory/scoped_refptr.h"
14 #include "base/memory/weak_ptr.h"
15 #include "base/run_loop.h"
16 #include "base/strings/strcat.h"
17 #include "base/strings/string_piece.h"
18 #include "base/strings/stringprintf.h"
19 #include "base/task/single_thread_task_runner.h"
20 #include "base/time/time.h"
21 #include "base/timer/timer.h"
22 #include "net/base/isolation_info.h"
23 #include "net/base/net_errors.h"
24 #include "net/cookies/canonical_cookie.h"
25 #include "net/cookies/canonical_cookie_test_helpers.h"
26 #include "net/cookies/cookie_access_result.h"
27 #include "net/cookies/cookie_inclusion_status.h"
28 #include "net/cookies/cookie_options.h"
29 #include "net/cookies/cookie_partition_key.h"
30 #include "net/cookies/cookie_partition_key_collection.h"
31 #include "net/cookies/cookie_store.h"
32 #include "net/cookies/cookie_util.h"
33 #include "net/cookies/site_for_cookies.h"
34 #include "net/http/http_request_headers.h"
35 #include "net/socket/socket_test_util.h"
36 #include "net/url_request/url_request_context.h"
37 #include "net/websockets/websocket_stream.h"
38 #include "net/websockets/websocket_stream_create_test_base.h"
39 #include "net/websockets/websocket_test_util.h"
40 #include "testing/gmock/include/gmock/gmock.h"
41 #include "testing/gtest/include/gtest/gtest.h"
42 #include "third_party/abseil-cpp/absl/types/optional.h"
43 #include "url/gurl.h"
44 #include "url/origin.h"
45 
46 namespace net {
47 namespace {
48 
49 using ::testing::TestWithParam;
50 using ::testing::ValuesIn;
51 
52 const WebSocketExtraHeaders kNoCookieHeader = {};
53 
54 class TestBase : public WebSocketStreamCreateTestBase {
55  public:
CreateAndConnect(const GURL & url,const url::Origin & origin,const SiteForCookies & site_for_cookies,const IsolationInfo & isolation_info,const WebSocketExtraHeaders & cookie_header,const std::string & response_body)56   void CreateAndConnect(const GURL& url,
57                         const url::Origin& origin,
58                         const SiteForCookies& site_for_cookies,
59                         const IsolationInfo& isolation_info,
60                         const WebSocketExtraHeaders& cookie_header,
61                         const std::string& response_body) {
62     url_request_context_host_.SetExpectations(
63         WebSocketStandardRequestWithCookies(
64             url.path(), url.host(), origin, cookie_header,
65             /*send_additional_request_headers=*/{}, /*extra_headers=*/{}),
66         response_body);
67     CreateAndConnectStream(url, NoSubProtocols(), origin, site_for_cookies,
68                            /*has_storage_access=*/false, isolation_info,
69                            HttpRequestHeaders(), nullptr);
70   }
71 };
72 
73 struct ClientUseCookieParameter {
74   // The URL for the WebSocket connection.
75   const char* const url;
76   // The URL for the previously set cookies.
77   const char* const cookie_url;
78   // The previously set cookies contents.
79   const char* const cookie_line;
80   // The Cookie: HTTP header expected to appear in the WS request.
81   const WebSocketExtraHeaders cookie_header;
82 };
83 
84 class WebSocketStreamClientUseCookieTest
85     : public TestBase,
86       public TestWithParam<ClientUseCookieParameter> {
87  public:
~WebSocketStreamClientUseCookieTest()88   ~WebSocketStreamClientUseCookieTest() override {
89     // Permit any endpoint locks to be released.
90     stream_request_.reset();
91     stream_.reset();
92     base::RunLoop().RunUntilIdle();
93   }
94 
SetCookieHelperFunction(const base::RepeatingClosure & task,base::WeakPtr<bool> weak_is_called,base::WeakPtr<bool> weak_result,CookieAccessResult access_result)95   static void SetCookieHelperFunction(const base::RepeatingClosure& task,
96                                       base::WeakPtr<bool> weak_is_called,
97                                       base::WeakPtr<bool> weak_result,
98                                       CookieAccessResult access_result) {
99     *weak_is_called = true;
100     *weak_result = access_result.status.IsInclude();
101     base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask(FROM_HERE,
102                                                                 task);
103   }
104 };
105 
106 struct ServerSetCookieParameter {
107   // The URL for the WebSocket connection.
108   const char* const url;
109   // The URL used to query cookies after the response received.
110   const char* const cookie_url;
111   // The cookies expected to appear for |cookie_url| inquiry.
112   const char* const cookie_line;
113   // The Set-Cookie: HTTP header attached to the response.
114   const WebSocketExtraHeaders cookie_header;
115 };
116 
117 class WebSocketStreamServerSetCookieTest
118     : public TestBase,
119       public TestWithParam<ServerSetCookieParameter> {
120  public:
~WebSocketStreamServerSetCookieTest()121   ~WebSocketStreamServerSetCookieTest() override {
122     // Permit any endpoint locks to be released.
123     stream_request_.reset();
124     stream_.reset();
125     base::RunLoop().RunUntilIdle();
126   }
127 
GetCookieListHelperFunction(base::OnceClosure task,base::WeakPtr<bool> weak_is_called,base::WeakPtr<CookieList> weak_result,const CookieAccessResultList & cookie_list,const CookieAccessResultList & excluded_cookies)128   static void GetCookieListHelperFunction(
129       base::OnceClosure task,
130       base::WeakPtr<bool> weak_is_called,
131       base::WeakPtr<CookieList> weak_result,
132       const CookieAccessResultList& cookie_list,
133       const CookieAccessResultList& excluded_cookies) {
134     *weak_is_called = true;
135     *weak_result = cookie_util::StripAccessResults(cookie_list);
136     base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
137         FROM_HERE, std::move(task));
138   }
139 };
140 
TEST_P(WebSocketStreamClientUseCookieTest,ClientUseCookie)141 TEST_P(WebSocketStreamClientUseCookieTest, ClientUseCookie) {
142   // For wss tests.
143   url_request_context_host_.AddSSLSocketDataProvider(
144       std::make_unique<SSLSocketDataProvider>(ASYNC, OK));
145 
146   CookieStore* store =
147       url_request_context_host_.GetURLRequestContext()->cookie_store();
148 
149   const GURL url(GetParam().url);
150   const GURL cookie_url(GetParam().cookie_url);
151   const url::Origin origin = url::Origin::Create(GURL(GetParam().url));
152   const SiteForCookies site_for_cookies = SiteForCookies::FromOrigin(origin);
153   const IsolationInfo isolation_info =
154       IsolationInfo::Create(IsolationInfo::RequestType::kOther, origin, origin,
155                             SiteForCookies::FromOrigin(origin));
156   const std::string cookie_line(GetParam().cookie_line);
157 
158   bool is_called = false;
159   bool set_cookie_result = false;
160   base::WeakPtrFactory<bool> weak_is_called(&is_called);
161   base::WeakPtrFactory<bool> weak_set_cookie_result(&set_cookie_result);
162 
163   base::RunLoop run_loop;
164   auto cookie =
165       CanonicalCookie::Create(cookie_url, cookie_line, base::Time::Now(),
166                               absl::nullopt /* server_time */,
167                               absl::nullopt /* cookie_partition_key */);
168   store->SetCanonicalCookieAsync(
169       std::move(cookie), cookie_url, net::CookieOptions::MakeAllInclusive(),
170       base::BindOnce(&SetCookieHelperFunction, run_loop.QuitClosure(),
171                      weak_is_called.GetWeakPtr(),
172                      weak_set_cookie_result.GetWeakPtr()));
173   run_loop.Run();
174   ASSERT_TRUE(is_called);
175   ASSERT_TRUE(set_cookie_result);
176 
177   CreateAndConnect(url, origin, site_for_cookies, isolation_info,
178                    GetParam().cookie_header, WebSocketStandardResponse(""));
179   WaitUntilConnectDone();
180   EXPECT_FALSE(has_failed());
181 }
182 
TEST_P(WebSocketStreamServerSetCookieTest,ServerSetCookie)183 TEST_P(WebSocketStreamServerSetCookieTest, ServerSetCookie) {
184   // For wss tests.
185   url_request_context_host_.AddSSLSocketDataProvider(
186       std::make_unique<SSLSocketDataProvider>(ASYNC, OK));
187 
188   const GURL url(GetParam().url);
189   const GURL cookie_url(GetParam().cookie_url);
190   const url::Origin origin = url::Origin::Create(GURL(GetParam().url));
191   const SiteForCookies site_for_cookies = SiteForCookies::FromOrigin(origin);
192   const IsolationInfo isolation_info =
193       IsolationInfo::Create(IsolationInfo::RequestType::kOther, origin, origin,
194                             SiteForCookies::FromOrigin(origin));
195   const std::string cookie_line(GetParam().cookie_line);
196   HttpRequestHeaders headers;
197   for (const auto& [key, value] : GetParam().cookie_header)
198     headers.SetHeader(key, value);
199   std::string cookie_header(headers.ToString());
200   const std::string response =
201       base::StrCat({"HTTP/1.1 101 Switching Protocols\r\n"
202                     "Upgrade: websocket\r\n"
203                     "Connection: Upgrade\r\n"
204                     "Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\r\n",
205                     cookie_header});
206   CookieStore* store =
207       url_request_context_host_.GetURLRequestContext()->cookie_store();
208 
209   CreateAndConnect(url, origin, site_for_cookies, isolation_info,
210                    /*cookie_header=*/{}, response);
211   WaitUntilConnectDone();
212   EXPECT_FALSE(has_failed()) << failure_message();
213 
214   bool is_called = false;
215   CookieList get_cookie_list_result;
216   base::WeakPtrFactory<bool> weak_is_called(&is_called);
217   base::WeakPtrFactory<CookieList> weak_get_cookie_list_result(
218       &get_cookie_list_result);
219   base::RunLoop run_loop;
220   store->GetCookieListWithOptionsAsync(
221       cookie_url, net::CookieOptions::MakeAllInclusive(),
222       CookiePartitionKeyCollection(),
223       base::BindOnce(&GetCookieListHelperFunction, run_loop.QuitClosure(),
224                      weak_is_called.GetWeakPtr(),
225                      weak_get_cookie_list_result.GetWeakPtr()));
226   run_loop.Run();
227   EXPECT_TRUE(is_called);
228   EXPECT_THAT(get_cookie_list_result, MatchesCookieLine(cookie_line));
229 }
230 
231 // Test parameters definitions follow...
232 
233 const ClientUseCookieParameter kClientUseCookieParameters[] = {
234     // Non-secure cookies for ws
235     {"ws://www.example.com",
236      "http://www.example.com",
237      "test-cookie",
238      {{"Cookie", "test-cookie"}}},
239 
240     {"ws://www.example.com",
241      "https://www.example.com",
242      "test-cookie",
243      {{"Cookie", "test-cookie"}}},
244 
245     {"ws://www.example.com",
246      "ws://www.example.com",
247      "test-cookie",
248      {{"Cookie", "test-cookie"}}},
249 
250     {"ws://www.example.com",
251      "wss://www.example.com",
252      "test-cookie",
253      {{"Cookie", "test-cookie"}}},
254 
255     // Non-secure cookies for wss
256     {"wss://www.example.com",
257      "http://www.example.com",
258      "test-cookie",
259      {{"Cookie", "test-cookie"}}},
260 
261     {"wss://www.example.com",
262      "https://www.example.com",
263      "test-cookie",
264      {{"Cookie", "test-cookie"}}},
265 
266     {"wss://www.example.com",
267      "ws://www.example.com",
268      "test-cookie",
269      {{"Cookie", "test-cookie"}}},
270 
271     {"wss://www.example.com",
272      "wss://www.example.com",
273      "test-cookie",
274      {{"Cookie", "test-cookie"}}},
275 
276     // Secure-cookies for ws
277     {"ws://www.example.com", "https://www.example.com", "test-cookie; secure",
278      kNoCookieHeader},
279 
280     {"ws://www.example.com", "wss://www.example.com", "test-cookie; secure",
281      kNoCookieHeader},
282 
283     // Secure-cookies for wss
284     {"wss://www.example.com",
285      "https://www.example.com",
286      "test-cookie; secure",
287      {{"Cookie", "test-cookie"}}},
288 
289     {"wss://www.example.com",
290      "wss://www.example.com",
291      "test-cookie; secure",
292      {{"Cookie", "test-cookie"}}},
293 
294     // Non-secure cookies for ws (sharing domain)
295     {"ws://www.example.com",
296      "http://www2.example.com",
297      "test-cookie; Domain=example.com",
298      {{"Cookie", "test-cookie"}}},
299 
300     {"ws://www.example.com",
301      "https://www2.example.com",
302      "test-cookie; Domain=example.com",
303      {{"Cookie", "test-cookie"}}},
304 
305     {"ws://www.example.com",
306      "ws://www2.example.com",
307      "test-cookie; Domain=example.com",
308      {{"Cookie", "test-cookie"}}},
309 
310     {"ws://www.example.com",
311      "wss://www2.example.com",
312      "test-cookie; Domain=example.com",
313      {{"Cookie", "test-cookie"}}},
314 
315     // Non-secure cookies for wss (sharing domain)
316     {"wss://www.example.com",
317      "http://www2.example.com",
318      "test-cookie; Domain=example.com",
319      {{"Cookie", "test-cookie"}}},
320 
321     {"wss://www.example.com",
322      "https://www2.example.com",
323      "test-cookie; Domain=example.com",
324      {{"Cookie", "test-cookie"}}},
325 
326     {"wss://www.example.com",
327      "ws://www2.example.com",
328      "test-cookie; Domain=example.com",
329      {{"Cookie", "test-cookie"}}},
330 
331     {"wss://www.example.com",
332      "wss://www2.example.com",
333      "test-cookie; Domain=example.com",
334      {{"Cookie", "test-cookie"}}},
335 
336     // Secure-cookies for ws (sharing domain)
337     {"ws://www.example.com", "https://www2.example.com",
338      "test-cookie; Domain=example.com; secure", kNoCookieHeader},
339 
340     {"ws://www.example.com", "wss://www2.example.com",
341      "test-cookie; Domain=example.com; secure", kNoCookieHeader},
342 
343     // Secure-cookies for wss (sharing domain)
344     {"wss://www.example.com",
345      "https://www2.example.com",
346      "test-cookie; Domain=example.com; secure",
347      {{"Cookie", "test-cookie"}}},
348 
349     {"wss://www.example.com",
350      "wss://www2.example.com",
351      "test-cookie; Domain=example.com; secure",
352      {{"Cookie", "test-cookie"}}},
353 
354     // Non-matching cookies for ws
355     {"ws://www.example.com", "http://www2.example.com", "test-cookie",
356      kNoCookieHeader},
357 
358     {"ws://www.example.com", "https://www2.example.com", "test-cookie",
359      kNoCookieHeader},
360 
361     {"ws://www.example.com", "ws://www2.example.com", "test-cookie",
362      kNoCookieHeader},
363 
364     {"ws://www.example.com", "wss://www2.example.com", "test-cookie",
365      kNoCookieHeader},
366 
367     // Non-matching cookies for wss
368     {"wss://www.example.com", "http://www2.example.com", "test-cookie",
369      kNoCookieHeader},
370 
371     {"wss://www.example.com", "https://www2.example.com", "test-cookie",
372      kNoCookieHeader},
373 
374     {"wss://www.example.com", "ws://www2.example.com", "test-cookie",
375      kNoCookieHeader},
376 
377     {"wss://www.example.com", "wss://www2.example.com", "test-cookie",
378      kNoCookieHeader},
379 };
380 
381 INSTANTIATE_TEST_SUITE_P(WebSocketStreamClientUseCookieTest,
382                          WebSocketStreamClientUseCookieTest,
383                          ValuesIn(kClientUseCookieParameters));
384 
385 const ServerSetCookieParameter kServerSetCookieParameters[] = {
386     // Cookies coming from ws
387     {"ws://www.example.com",
388      "http://www.example.com",
389      "test-cookie",
390      {{"Set-Cookie", "test-cookie"}}},
391 
392     {"ws://www.example.com",
393      "https://www.example.com",
394      "test-cookie",
395      {{"Set-Cookie", "test-cookie"}}},
396 
397     {"ws://www.example.com",
398      "ws://www.example.com",
399      "test-cookie",
400      {{"Set-Cookie", "test-cookie"}}},
401 
402     {"ws://www.example.com",
403      "wss://www.example.com",
404      "test-cookie",
405      {{"Set-Cookie", "test-cookie"}}},
406 
407     // Cookies coming from wss
408     {"wss://www.example.com",
409      "http://www.example.com",
410      "test-cookie",
411      {{"Set-Cookie", "test-cookie"}}},
412 
413     {"wss://www.example.com",
414      "https://www.example.com",
415      "test-cookie",
416      {{"Set-Cookie", "test-cookie"}}},
417 
418     {"wss://www.example.com",
419      "ws://www.example.com",
420      "test-cookie",
421      {{"Set-Cookie", "test-cookie"}}},
422 
423     {"wss://www.example.com",
424      "wss://www.example.com",
425      "test-cookie",
426      {{"Set-Cookie", "test-cookie"}}},
427 
428     // cookies coming from ws (sharing domain)
429     {"ws://www.example.com",
430      "http://www2.example.com",
431      "test-cookie",
432      {{"Set-Cookie", "test-cookie; Domain=example.com"}}},
433 
434     {"ws://www.example.com",
435      "https://www2.example.com",
436      "test-cookie",
437      {{"Set-Cookie", "test-cookie; Domain=example.com"}}},
438 
439     {"ws://www.example.com",
440      "ws://www2.example.com",
441      "test-cookie",
442      {{"Set-Cookie", "test-cookie; Domain=example.com"}}},
443 
444     {"ws://www.example.com",
445      "wss://www2.example.com",
446      "test-cookie",
447      {{"Set-Cookie", "test-cookie; Domain=example.com"}}},
448 
449     // cookies coming from wss (sharing domain)
450     {"wss://www.example.com",
451      "http://www2.example.com",
452      "test-cookie",
453      {{"Set-Cookie", "test-cookie; Domain=example.com"}}},
454 
455     {"wss://www.example.com",
456      "https://www2.example.com",
457      "test-cookie",
458      {{"Set-Cookie", "test-cookie; Domain=example.com"}}},
459 
460     {"wss://www.example.com",
461      "ws://www2.example.com",
462      "test-cookie",
463      {{"Set-Cookie", "test-cookie; Domain=example.com"}}},
464 
465     {"wss://www.example.com",
466      "wss://www2.example.com",
467      "test-cookie",
468      {{"Set-Cookie", "test-cookie; Domain=example.com"}}},
469 
470     // Non-matching cookies coming from ws
471     {"ws://www.example.com",
472      "http://www2.example.com",
473      "",
474      {{"Set-Cookie", "test-cookie"}}},
475 
476     {"ws://www.example.com",
477      "https://www2.example.com",
478      "",
479      {{"Set-Cookie", "test-cookie"}}},
480 
481     {"ws://www.example.com",
482      "ws://www2.example.com",
483      "",
484      {{"Set-Cookie", "test-cookie"}}},
485 
486     {"ws://www.example.com",
487      "wss://www2.example.com",
488      "",
489      {{"Set-Cookie", "test-cookie"}}},
490 
491     // Non-matching cookies coming from wss
492     {"wss://www.example.com",
493      "http://www2.example.com",
494      "",
495      {{"Set-Cookie", "test-cookie"}}},
496 
497     {"wss://www.example.com",
498      "https://www2.example.com",
499      "",
500      {{"Set-Cookie", "test-cookie"}}},
501 
502     {"wss://www.example.com",
503      "ws://www2.example.com",
504      "",
505      {{"Set-Cookie", "test-cookie"}}},
506 
507     {"wss://www.example.com",
508      "wss://www2.example.com",
509      "",
510      {{"Set-Cookie", "test-cookie"}}},
511 };
512 
513 INSTANTIATE_TEST_SUITE_P(WebSocketStreamServerSetCookieTest,
514                          WebSocketStreamServerSetCookieTest,
515                          ValuesIn(kServerSetCookieParameters));
516 
517 }  // namespace
518 }  // namespace net
519