1 // Copyright 2017 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 "net/reporting/reporting_uploader.h"
6
7 #include <memory>
8 #include <string>
9 #include <utility>
10
11 #include "base/functional/bind.h"
12 #include "base/functional/callback.h"
13 #include "base/run_loop.h"
14 #include "base/test/scoped_feature_list.h"
15 #include "net/base/features.h"
16 #include "net/base/network_anonymization_key.h"
17 #include "net/base/schemeful_site.h"
18 #include "net/cookies/cookie_access_result.h"
19 #include "net/cookies/cookie_store.h"
20 #include "net/cookies/cookie_store_test_callbacks.h"
21 #include "net/http/http_status_code.h"
22 #include "net/socket/socket_test_util.h"
23 #include "net/test/embedded_test_server/embedded_test_server.h"
24 #include "net/test/embedded_test_server/http_request.h"
25 #include "net/test/embedded_test_server/http_response.h"
26 #include "net/test/test_with_task_environment.h"
27 #include "net/url_request/url_request_context.h"
28 #include "net/url_request/url_request_context_builder.h"
29 #include "net/url_request/url_request_test_util.h"
30 #include "testing/gtest/include/gtest/gtest.h"
31 #include "url/gurl.h"
32 #include "url/origin.h"
33
34 namespace net {
35 namespace {
36
37 class ReportingUploaderTest : public TestWithTaskEnvironment {
38 protected:
ReportingUploaderTest()39 ReportingUploaderTest()
40 : server_(test_server::EmbeddedTestServer::TYPE_HTTPS),
41 context_(CreateTestURLRequestContextBuilder()->Build()),
42 uploader_(ReportingUploader::Create(context_.get())) {}
43
44 test_server::EmbeddedTestServer server_;
45 std::unique_ptr<URLRequestContext> context_;
46 std::unique_ptr<ReportingUploader> uploader_;
47
48 const url::Origin kOrigin = url::Origin::Create(GURL("https://origin/"));
49 };
50
51 const char kUploadBody[] = "{}";
52
CheckUpload(const test_server::HttpRequest & request)53 void CheckUpload(const test_server::HttpRequest& request) {
54 if (request.method_string != "POST") {
55 return;
56 }
57 auto it = request.headers.find("Content-Type");
58 EXPECT_TRUE(it != request.headers.end());
59 EXPECT_EQ("application/reports+json", it->second);
60 EXPECT_TRUE(request.has_content);
61 EXPECT_EQ(kUploadBody, request.content);
62 }
63
AllowPreflight(const test_server::HttpRequest & request)64 std::unique_ptr<test_server::HttpResponse> AllowPreflight(
65 const test_server::HttpRequest& request) {
66 if (request.method_string != "OPTIONS") {
67 return nullptr;
68 }
69 auto it = request.headers.find("Origin");
70 EXPECT_TRUE(it != request.headers.end());
71 auto response = std::make_unique<test_server::BasicHttpResponse>();
72 response->AddCustomHeader("Access-Control-Allow-Origin", it->second);
73 response->AddCustomHeader("Access-Control-Allow-Methods", "POST");
74 response->AddCustomHeader("Access-Control-Allow-Headers", "Content-Type");
75 response->set_code(HTTP_OK);
76 response->set_content("");
77 response->set_content_type("text/plain");
78 return std::move(response);
79 }
80
ReturnResponse(HttpStatusCode code,const test_server::HttpRequest & request)81 std::unique_ptr<test_server::HttpResponse> ReturnResponse(
82 HttpStatusCode code,
83 const test_server::HttpRequest& request) {
84 auto response = std::make_unique<test_server::BasicHttpResponse>();
85 response->set_code(code);
86 response->set_content("");
87 response->set_content_type("text/plain");
88 return std::move(response);
89 }
90
ReturnInvalidResponse(const test_server::HttpRequest & request)91 std::unique_ptr<test_server::HttpResponse> ReturnInvalidResponse(
92 const test_server::HttpRequest& request) {
93 return std::make_unique<test_server::RawHttpResponse>(
94 "", "Not a valid HTTP response.");
95 }
96
97 class TestUploadCallback {
98 public:
99 TestUploadCallback() = default;
100
callback()101 ReportingUploader::UploadCallback callback() {
102 return base::BindOnce(&TestUploadCallback::OnUploadComplete,
103 base::Unretained(this));
104 }
105
WaitForCall()106 void WaitForCall() {
107 if (called_)
108 return;
109
110 base::RunLoop run_loop;
111
112 waiting_ = true;
113 closure_ = run_loop.QuitClosure();
114 run_loop.Run();
115 }
116
outcome() const117 ReportingUploader::Outcome outcome() const { return outcome_; }
118
119 private:
OnUploadComplete(ReportingUploader::Outcome outcome)120 void OnUploadComplete(ReportingUploader::Outcome outcome) {
121 EXPECT_FALSE(called_);
122
123 called_ = true;
124 outcome_ = outcome;
125
126 if (waiting_) {
127 waiting_ = false;
128 std::move(closure_).Run();
129 }
130 }
131
132 bool called_ = false;
133 ReportingUploader::Outcome outcome_;
134
135 bool waiting_ = false;
136 base::OnceClosure closure_;
137 };
138
TEST_F(ReportingUploaderTest,Upload)139 TEST_F(ReportingUploaderTest, Upload) {
140 server_.RegisterRequestMonitor(base::BindRepeating(&CheckUpload));
141 server_.RegisterRequestHandler(base::BindRepeating(&AllowPreflight));
142 server_.RegisterRequestHandler(base::BindRepeating(&ReturnResponse, HTTP_OK));
143 ASSERT_TRUE(server_.Start());
144
145 TestUploadCallback callback;
146 uploader_->StartUpload(kOrigin, server_.GetURL("/"),
147 IsolationInfo::CreateTransient(), kUploadBody, 0,
148 false, callback.callback());
149 callback.WaitForCall();
150 }
151
TEST_F(ReportingUploaderTest,Success)152 TEST_F(ReportingUploaderTest, Success) {
153 server_.RegisterRequestHandler(base::BindRepeating(&AllowPreflight));
154 server_.RegisterRequestHandler(base::BindRepeating(&ReturnResponse, HTTP_OK));
155 ASSERT_TRUE(server_.Start());
156
157 TestUploadCallback callback;
158 uploader_->StartUpload(kOrigin, server_.GetURL("/"),
159 IsolationInfo::CreateTransient(), kUploadBody, 0,
160 false, callback.callback());
161 callback.WaitForCall();
162
163 EXPECT_EQ(ReportingUploader::Outcome::SUCCESS, callback.outcome());
164 }
165
TEST_F(ReportingUploaderTest,NetworkError1)166 TEST_F(ReportingUploaderTest, NetworkError1) {
167 ASSERT_TRUE(server_.Start());
168 GURL url = server_.GetURL("/");
169 ASSERT_TRUE(server_.ShutdownAndWaitUntilComplete());
170
171 TestUploadCallback callback;
172 uploader_->StartUpload(kOrigin, url, IsolationInfo::CreateTransient(),
173 kUploadBody, 0, false, callback.callback());
174 callback.WaitForCall();
175
176 EXPECT_EQ(ReportingUploader::Outcome::FAILURE, callback.outcome());
177 }
178
TEST_F(ReportingUploaderTest,NetworkError2)179 TEST_F(ReportingUploaderTest, NetworkError2) {
180 server_.RegisterRequestHandler(base::BindRepeating(&AllowPreflight));
181 server_.RegisterRequestHandler(base::BindRepeating(&ReturnInvalidResponse));
182 ASSERT_TRUE(server_.Start());
183
184 TestUploadCallback callback;
185 uploader_->StartUpload(kOrigin, server_.GetURL("/"),
186 IsolationInfo::CreateTransient(), kUploadBody, 0,
187 false, callback.callback());
188 callback.WaitForCall();
189
190 EXPECT_EQ(ReportingUploader::Outcome::FAILURE, callback.outcome());
191 }
192
TEST_F(ReportingUploaderTest,ServerError)193 TEST_F(ReportingUploaderTest, ServerError) {
194 server_.RegisterRequestHandler(base::BindRepeating(&AllowPreflight));
195 server_.RegisterRequestHandler(
196 base::BindRepeating(&ReturnResponse, HTTP_INTERNAL_SERVER_ERROR));
197 ASSERT_TRUE(server_.Start());
198
199 TestUploadCallback callback;
200 uploader_->StartUpload(kOrigin, server_.GetURL("/"),
201 IsolationInfo::CreateTransient(), kUploadBody, 0,
202 false, callback.callback());
203 callback.WaitForCall();
204
205 EXPECT_EQ(ReportingUploader::Outcome::FAILURE, callback.outcome());
206 }
207
VerifyPreflight(bool * preflight_received_out,const test_server::HttpRequest & request)208 std::unique_ptr<test_server::HttpResponse> VerifyPreflight(
209 bool* preflight_received_out,
210 const test_server::HttpRequest& request) {
211 if (request.method_string != "OPTIONS") {
212 return nullptr;
213 }
214 *preflight_received_out = true;
215 return AllowPreflight(request);
216 }
217
TEST_F(ReportingUploaderTest,VerifyPreflight)218 TEST_F(ReportingUploaderTest, VerifyPreflight) {
219 bool preflight_received = false;
220 server_.RegisterRequestHandler(
221 base::BindRepeating(&VerifyPreflight, &preflight_received));
222 server_.RegisterRequestHandler(base::BindRepeating(&ReturnResponse, HTTP_OK));
223 ASSERT_TRUE(server_.Start());
224
225 TestUploadCallback callback;
226 uploader_->StartUpload(kOrigin, server_.GetURL("/"),
227 IsolationInfo::CreateTransient(), kUploadBody, 0,
228 false, callback.callback());
229 callback.WaitForCall();
230
231 EXPECT_TRUE(preflight_received);
232 EXPECT_EQ(ReportingUploader::Outcome::SUCCESS, callback.outcome());
233 }
234
TEST_F(ReportingUploaderTest,SkipPreflightForSameOrigin)235 TEST_F(ReportingUploaderTest, SkipPreflightForSameOrigin) {
236 bool preflight_received = false;
237 server_.RegisterRequestHandler(
238 base::BindRepeating(&VerifyPreflight, &preflight_received));
239 server_.RegisterRequestHandler(base::BindRepeating(&ReturnResponse, HTTP_OK));
240 ASSERT_TRUE(server_.Start());
241
242 TestUploadCallback callback;
243 auto server_origin = url::Origin::Create(server_.base_url());
244 uploader_->StartUpload(server_origin, server_.GetURL("/"),
245 IsolationInfo::CreateTransient(), kUploadBody, 0,
246 false, callback.callback());
247 callback.WaitForCall();
248
249 EXPECT_FALSE(preflight_received);
250 EXPECT_EQ(ReportingUploader::Outcome::SUCCESS, callback.outcome());
251 }
252
ReturnPreflightError(const test_server::HttpRequest & request)253 std::unique_ptr<test_server::HttpResponse> ReturnPreflightError(
254 const test_server::HttpRequest& request) {
255 if (request.method_string != "OPTIONS") {
256 return nullptr;
257 }
258 auto response = std::make_unique<test_server::BasicHttpResponse>();
259 response->set_code(HTTP_FORBIDDEN);
260 response->set_content("");
261 response->set_content_type("text/plain");
262 return std::move(response);
263 }
264
TEST_F(ReportingUploaderTest,FailedCorsPreflight)265 TEST_F(ReportingUploaderTest, FailedCorsPreflight) {
266 server_.RegisterRequestHandler(base::BindRepeating(&ReturnPreflightError));
267 server_.RegisterRequestHandler(base::BindRepeating(&ReturnResponse, HTTP_OK));
268 ASSERT_TRUE(server_.Start());
269
270 TestUploadCallback callback;
271 uploader_->StartUpload(kOrigin, server_.GetURL("/"),
272 IsolationInfo::CreateTransient(), kUploadBody, 0,
273 false, callback.callback());
274 callback.WaitForCall();
275
276 EXPECT_EQ(ReportingUploader::Outcome::FAILURE, callback.outcome());
277 }
278
ReturnPreflightWithoutOrigin(const test_server::HttpRequest & request)279 std::unique_ptr<test_server::HttpResponse> ReturnPreflightWithoutOrigin(
280 const test_server::HttpRequest& request) {
281 if (request.method_string != "OPTIONS") {
282 return nullptr;
283 }
284 auto it = request.headers.find("Origin");
285 EXPECT_TRUE(it != request.headers.end());
286 auto response = std::make_unique<test_server::BasicHttpResponse>();
287 response->AddCustomHeader("Access-Control-Allow-Methods", "POST");
288 response->AddCustomHeader("Access-Control-Allow-Headers", "Content-Type");
289 response->set_code(HTTP_OK);
290 response->set_content("");
291 response->set_content_type("text/plain");
292 return std::move(response);
293 }
294
TEST_F(ReportingUploaderTest,CorsPreflightWithoutOrigin)295 TEST_F(ReportingUploaderTest, CorsPreflightWithoutOrigin) {
296 server_.RegisterRequestHandler(
297 base::BindRepeating(&ReturnPreflightWithoutOrigin));
298 server_.RegisterRequestHandler(base::BindRepeating(&ReturnResponse, HTTP_OK));
299 ASSERT_TRUE(server_.Start());
300
301 TestUploadCallback callback;
302 uploader_->StartUpload(kOrigin, server_.GetURL("/"),
303 IsolationInfo::CreateTransient(), kUploadBody, 0,
304 false, callback.callback());
305 callback.WaitForCall();
306
307 EXPECT_EQ(ReportingUploader::Outcome::FAILURE, callback.outcome());
308 }
309
ReturnPreflightWithoutMethods(const test_server::HttpRequest & request)310 std::unique_ptr<test_server::HttpResponse> ReturnPreflightWithoutMethods(
311 const test_server::HttpRequest& request) {
312 if (request.method_string != "OPTIONS") {
313 return nullptr;
314 }
315 auto it = request.headers.find("Origin");
316 EXPECT_TRUE(it != request.headers.end());
317 auto response = std::make_unique<test_server::BasicHttpResponse>();
318 response->AddCustomHeader("Access-Control-Allow-Origin", it->second);
319 response->AddCustomHeader("Access-Control-Allow-Headers", "Content-Type");
320 response->set_code(HTTP_OK);
321 response->set_content("");
322 response->set_content_type("text/plain");
323 return std::move(response);
324 }
325
TEST_F(ReportingUploaderTest,CorsPreflightWithoutMethods)326 TEST_F(ReportingUploaderTest, CorsPreflightWithoutMethods) {
327 server_.RegisterRequestHandler(
328 base::BindRepeating(&ReturnPreflightWithoutMethods));
329 server_.RegisterRequestHandler(base::BindRepeating(&ReturnResponse, HTTP_OK));
330 ASSERT_TRUE(server_.Start());
331
332 TestUploadCallback callback;
333 uploader_->StartUpload(kOrigin, server_.GetURL("/"),
334 IsolationInfo::CreateTransient(), kUploadBody, 0,
335 false, callback.callback());
336 callback.WaitForCall();
337
338 EXPECT_EQ(ReportingUploader::Outcome::SUCCESS, callback.outcome());
339 }
340
ReturnPreflightWithWildcardMethods(const test_server::HttpRequest & request)341 std::unique_ptr<test_server::HttpResponse> ReturnPreflightWithWildcardMethods(
342 const test_server::HttpRequest& request) {
343 if (request.method_string != "OPTIONS") {
344 return nullptr;
345 }
346 auto it = request.headers.find("Origin");
347 EXPECT_TRUE(it != request.headers.end());
348 auto response = std::make_unique<test_server::BasicHttpResponse>();
349 response->AddCustomHeader("Access-Control-Allow-Origin", it->second);
350 response->AddCustomHeader("Access-Control-Allow-Headers", "Content-Type");
351 response->AddCustomHeader("Access-Control-Allow-Methods", "*");
352 response->set_code(HTTP_OK);
353 response->set_content("");
354 response->set_content_type("text/plain");
355 return std::move(response);
356 }
357
TEST_F(ReportingUploaderTest,CorsPreflightWildcardMethods)358 TEST_F(ReportingUploaderTest, CorsPreflightWildcardMethods) {
359 server_.RegisterRequestHandler(
360 base::BindRepeating(&ReturnPreflightWithWildcardMethods));
361 server_.RegisterRequestHandler(base::BindRepeating(&ReturnResponse, HTTP_OK));
362 ASSERT_TRUE(server_.Start());
363
364 TestUploadCallback callback;
365 uploader_->StartUpload(kOrigin, server_.GetURL("/"),
366 IsolationInfo::CreateTransient(), kUploadBody, 0,
367 false, callback.callback());
368 callback.WaitForCall();
369
370 EXPECT_EQ(ReportingUploader::Outcome::SUCCESS, callback.outcome());
371 }
372
ReturnPreflightWithoutHeaders(const test_server::HttpRequest & request)373 std::unique_ptr<test_server::HttpResponse> ReturnPreflightWithoutHeaders(
374 const test_server::HttpRequest& request) {
375 if (request.method_string != "OPTIONS") {
376 return nullptr;
377 }
378 auto it = request.headers.find("Origin");
379 EXPECT_TRUE(it != request.headers.end());
380 auto response = std::make_unique<test_server::BasicHttpResponse>();
381 response->AddCustomHeader("Access-Control-Allow-Origin", it->second);
382 response->AddCustomHeader("Access-Control-Allow-Methods", "POST");
383 response->set_code(HTTP_OK);
384 response->set_content("");
385 response->set_content_type("text/plain");
386 return std::move(response);
387 }
388
TEST_F(ReportingUploaderTest,CorsPreflightWithoutHeaders)389 TEST_F(ReportingUploaderTest, CorsPreflightWithoutHeaders) {
390 server_.RegisterRequestHandler(
391 base::BindRepeating(&ReturnPreflightWithoutHeaders));
392 server_.RegisterRequestHandler(base::BindRepeating(&ReturnResponse, HTTP_OK));
393 ASSERT_TRUE(server_.Start());
394
395 TestUploadCallback callback;
396 uploader_->StartUpload(kOrigin, server_.GetURL("/"),
397 IsolationInfo::CreateTransient(), kUploadBody, 0,
398 false, callback.callback());
399 callback.WaitForCall();
400
401 EXPECT_EQ(ReportingUploader::Outcome::FAILURE, callback.outcome());
402 }
403
ReturnPreflightWithWildcardHeaders(const test_server::HttpRequest & request)404 std::unique_ptr<test_server::HttpResponse> ReturnPreflightWithWildcardHeaders(
405 const test_server::HttpRequest& request) {
406 if (request.method_string != "OPTIONS") {
407 return nullptr;
408 }
409 auto it = request.headers.find("Origin");
410 EXPECT_TRUE(it != request.headers.end());
411 auto response = std::make_unique<test_server::BasicHttpResponse>();
412 response->AddCustomHeader("Access-Control-Allow-Origin", it->second);
413 response->AddCustomHeader("Access-Control-Allow-Headers", "*");
414 response->AddCustomHeader("Access-Control-Allow-Methods", "POST");
415 response->set_code(HTTP_OK);
416 response->set_content("");
417 response->set_content_type("text/plain");
418 return std::move(response);
419 }
420
TEST_F(ReportingUploaderTest,CorsPreflightWildcardHeaders)421 TEST_F(ReportingUploaderTest, CorsPreflightWildcardHeaders) {
422 server_.RegisterRequestHandler(
423 base::BindRepeating(&ReturnPreflightWithWildcardHeaders));
424 server_.RegisterRequestHandler(base::BindRepeating(&ReturnResponse, HTTP_OK));
425 ASSERT_TRUE(server_.Start());
426
427 TestUploadCallback callback;
428 uploader_->StartUpload(kOrigin, server_.GetURL("/"),
429 IsolationInfo::CreateTransient(), kUploadBody, 0,
430 false, callback.callback());
431 callback.WaitForCall();
432
433 EXPECT_EQ(ReportingUploader::Outcome::SUCCESS, callback.outcome());
434 }
435
TEST_F(ReportingUploaderTest,RemoveEndpoint)436 TEST_F(ReportingUploaderTest, RemoveEndpoint) {
437 server_.RegisterRequestHandler(base::BindRepeating(&AllowPreflight));
438 server_.RegisterRequestHandler(
439 base::BindRepeating(&ReturnResponse, HTTP_GONE));
440 ASSERT_TRUE(server_.Start());
441
442 TestUploadCallback callback;
443 uploader_->StartUpload(kOrigin, server_.GetURL("/"),
444 IsolationInfo::CreateTransient(), kUploadBody, 0,
445 false, callback.callback());
446 callback.WaitForCall();
447
448 EXPECT_EQ(ReportingUploader::Outcome::REMOVE_ENDPOINT, callback.outcome());
449 }
450
451 const char kRedirectPath[] = "/redirect";
452
ReturnRedirect(const std::string & location,const test_server::HttpRequest & request)453 std::unique_ptr<test_server::HttpResponse> ReturnRedirect(
454 const std::string& location,
455 const test_server::HttpRequest& request) {
456 if (request.relative_url != "/")
457 return nullptr;
458
459 auto response = std::make_unique<test_server::BasicHttpResponse>();
460 response->set_code(HTTP_FOUND);
461 response->AddCustomHeader("Location", location);
462 response->set_content(
463 "Thank you, Mario! But our Princess is in another castle.");
464 response->set_content_type("text/plain");
465 return std::move(response);
466 }
467
CheckRedirect(bool * redirect_followed_out,const test_server::HttpRequest & request)468 std::unique_ptr<test_server::HttpResponse> CheckRedirect(
469 bool* redirect_followed_out,
470 const test_server::HttpRequest& request) {
471 if (request.relative_url != kRedirectPath)
472 return nullptr;
473
474 *redirect_followed_out = true;
475 return ReturnResponse(HTTP_OK, request);
476 }
477
TEST_F(ReportingUploaderTest,FollowHttpsRedirect)478 TEST_F(ReportingUploaderTest, FollowHttpsRedirect) {
479 bool followed = false;
480 server_.RegisterRequestHandler(base::BindRepeating(&AllowPreflight));
481 server_.RegisterRequestHandler(
482 base::BindRepeating(&ReturnRedirect, kRedirectPath));
483 server_.RegisterRequestHandler(
484 base::BindRepeating(&CheckRedirect, &followed));
485 ASSERT_TRUE(server_.Start());
486
487 TestUploadCallback callback;
488 uploader_->StartUpload(kOrigin, server_.GetURL("/"),
489 IsolationInfo::CreateTransient(), kUploadBody, 0,
490 false, callback.callback());
491 callback.WaitForCall();
492
493 EXPECT_TRUE(followed);
494 EXPECT_EQ(ReportingUploader::Outcome::SUCCESS, callback.outcome());
495 }
496
TEST_F(ReportingUploaderTest,DontFollowHttpRedirect)497 TEST_F(ReportingUploaderTest, DontFollowHttpRedirect) {
498 bool followed = false;
499
500 test_server::EmbeddedTestServer http_server_;
501 http_server_.RegisterRequestHandler(
502 base::BindRepeating(&CheckRedirect, &followed));
503 ASSERT_TRUE(http_server_.Start());
504
505 const GURL target = http_server_.GetURL(kRedirectPath);
506 server_.RegisterRequestHandler(base::BindRepeating(&AllowPreflight));
507 server_.RegisterRequestHandler(
508 base::BindRepeating(&ReturnRedirect, target.spec()));
509 ASSERT_TRUE(server_.Start());
510
511 TestUploadCallback callback;
512 uploader_->StartUpload(kOrigin, server_.GetURL("/"),
513 IsolationInfo::CreateTransient(), kUploadBody, 0,
514 false, callback.callback());
515 callback.WaitForCall();
516
517 EXPECT_FALSE(followed);
518 EXPECT_EQ(ReportingUploader::Outcome::FAILURE, callback.outcome());
519 }
520
CheckNoCookie(const test_server::HttpRequest & request)521 void CheckNoCookie(const test_server::HttpRequest& request) {
522 auto it = request.headers.find("Cookie");
523 EXPECT_TRUE(it == request.headers.end());
524 }
525
TEST_F(ReportingUploaderTest,DontSendCookies)526 TEST_F(ReportingUploaderTest, DontSendCookies) {
527 server_.RegisterRequestMonitor(base::BindRepeating(&CheckNoCookie));
528 server_.RegisterRequestHandler(base::BindRepeating(&AllowPreflight));
529 server_.RegisterRequestHandler(base::BindRepeating(&ReturnResponse, HTTP_OK));
530 ASSERT_TRUE(server_.Start());
531
532 ResultSavingCookieCallback<CookieAccessResult> cookie_callback;
533 GURL url = server_.GetURL("/");
534 auto cookie =
535 CanonicalCookie::CreateForTesting(url, "foo=bar", base::Time::Now());
536 context_->cookie_store()->SetCanonicalCookieAsync(
537 std::move(cookie), url, CookieOptions::MakeAllInclusive(),
538 cookie_callback.MakeCallback());
539 cookie_callback.WaitUntilDone();
540 ASSERT_TRUE(cookie_callback.result().status.IsInclude());
541
542 TestUploadCallback upload_callback;
543 uploader_->StartUpload(kOrigin, server_.GetURL("/"),
544 IsolationInfo::CreateTransient(), kUploadBody, 0,
545 false, upload_callback.callback());
546 upload_callback.WaitForCall();
547 }
548
SendCookie(const test_server::HttpRequest & request)549 std::unique_ptr<test_server::HttpResponse> SendCookie(
550 const test_server::HttpRequest& request) {
551 auto response = std::make_unique<test_server::BasicHttpResponse>();
552 response->set_code(HTTP_OK);
553 response->AddCustomHeader("Set-Cookie", "foo=bar");
554 response->set_content("");
555 response->set_content_type("text/plain");
556 return std::move(response);
557 }
558
TEST_F(ReportingUploaderTest,DontSaveCookies)559 TEST_F(ReportingUploaderTest, DontSaveCookies) {
560 server_.RegisterRequestHandler(base::BindRepeating(&AllowPreflight));
561 server_.RegisterRequestHandler(base::BindRepeating(&SendCookie));
562 ASSERT_TRUE(server_.Start());
563
564 TestUploadCallback upload_callback;
565 uploader_->StartUpload(kOrigin, server_.GetURL("/"),
566 IsolationInfo::CreateTransient(), kUploadBody, 0,
567 false, upload_callback.callback());
568 upload_callback.WaitForCall();
569
570 GetCookieListCallback cookie_callback;
571 context_->cookie_store()->GetCookieListWithOptionsAsync(
572 server_.GetURL("/"), CookieOptions::MakeAllInclusive(),
573 CookiePartitionKeyCollection(),
574 base::BindOnce(&GetCookieListCallback::Run,
575 base::Unretained(&cookie_callback)));
576 cookie_callback.WaitUntilDone();
577
578 EXPECT_TRUE(cookie_callback.cookies().empty());
579 }
580
ReturnCacheableResponse(int * request_count_out,const test_server::HttpRequest & request)581 std::unique_ptr<test_server::HttpResponse> ReturnCacheableResponse(
582 int* request_count_out,
583 const test_server::HttpRequest& request) {
584 ++*request_count_out;
585 auto response = std::make_unique<test_server::BasicHttpResponse>();
586 response->set_code(HTTP_OK);
587 response->AddCustomHeader("Cache-Control", "max-age=86400");
588 response->set_content("");
589 response->set_content_type("text/plain");
590 return std::move(response);
591 }
592
593 // TODO(juliatuttle): This passes even if the uploader doesn't set
594 // LOAD_DISABLE_CACHE. Maybe that's okay -- Chromium might not cache POST
595 // responses ever -- but this test should either not exist or be sure that it is
596 // testing actual functionality, not a default.
TEST_F(ReportingUploaderTest,DontCacheResponse)597 TEST_F(ReportingUploaderTest, DontCacheResponse) {
598 int request_count = 0;
599 server_.RegisterRequestHandler(base::BindRepeating(&AllowPreflight));
600 server_.RegisterRequestHandler(
601 base::BindRepeating(&ReturnCacheableResponse, &request_count));
602 ASSERT_TRUE(server_.Start());
603
604 {
605 TestUploadCallback callback;
606 uploader_->StartUpload(kOrigin, server_.GetURL("/"),
607 IsolationInfo::CreateTransient(), kUploadBody, 0,
608 false, callback.callback());
609 callback.WaitForCall();
610 }
611 EXPECT_EQ(1, request_count);
612
613 {
614 TestUploadCallback callback;
615 uploader_->StartUpload(kOrigin, server_.GetURL("/"),
616 IsolationInfo::CreateTransient(), kUploadBody, 0,
617 false, callback.callback());
618 callback.WaitForCall();
619 }
620 EXPECT_EQ(2, request_count);
621 }
622
623 // Create two requests with the same NetworkAnonymizationKey, and one request
624 // with a different one, and make sure only the requests with the same
625 // NetworkAnonymizationKey share a socket.
TEST_F(ReportingUploaderTest,RespectsNetworkAnonymizationKey)626 TEST_F(ReportingUploaderTest, RespectsNetworkAnonymizationKey) {
627 // While network state partitioning is not needed for reporting code to
628 // respect NetworkAnonymizationKey, this test works by ensuring that
629 // Reporting's NetworkAnonymizationKey makes it to the socket pool layer and
630 // is respected there, so this test needs to enable
631 // network state partitioning.
632 base::test::ScopedFeatureList feature_list;
633 feature_list.InitAndEnableFeature(
634 features::kPartitionConnectionsByNetworkIsolationKey);
635
636 const SchemefulSite kSite1 = SchemefulSite(kOrigin);
637 const SchemefulSite kSite2(GURL("https://origin2/"));
638 ASSERT_NE(kSite1, kSite2);
639 const url::Origin kSiteOrigin1 = url::Origin::Create(kSite1.GetURL());
640 const url::Origin kSiteOrigin2 = url::Origin::Create(kSite2.GetURL());
641 const IsolationInfo kIsolationInfo1 =
642 IsolationInfo::Create(net::IsolationInfo::RequestType::kOther,
643 kSiteOrigin1, kSiteOrigin1, net::SiteForCookies());
644 const IsolationInfo kIsolationInfo2 =
645 IsolationInfo::Create(net::IsolationInfo::RequestType::kOther,
646 kSiteOrigin2, kSiteOrigin2, net::SiteForCookies());
647
648 MockClientSocketFactory socket_factory;
649 auto context_builder = CreateTestURLRequestContextBuilder();
650 context_builder->set_client_socket_factory_for_testing(&socket_factory);
651 auto context = context_builder->Build();
652
653 // First socket handles first and third requests.
654 MockWrite writes1[] = {
655 MockWrite(SYNCHRONOUS, 0,
656 "POST /1 HTTP/1.1\r\n"
657 "Host: origin\r\n"
658 "Connection: keep-alive\r\n"
659 "Content-Length: 2\r\n"
660 "Content-Type: application/reports+json\r\n"
661 "User-Agent: \r\n"
662 "Accept-Encoding: gzip, deflate\r\n"
663 "Accept-Language: en-us,fr\r\n\r\n"),
664 MockWrite(SYNCHRONOUS, 1, kUploadBody),
665 MockWrite(SYNCHRONOUS, 3,
666 "POST /3 HTTP/1.1\r\n"
667 "Host: origin\r\n"
668 "Connection: keep-alive\r\n"
669 "Content-Length: 2\r\n"
670 "Content-Type: application/reports+json\r\n"
671 "User-Agent: \r\n"
672 "Accept-Encoding: gzip, deflate\r\n"
673 "Accept-Language: en-us,fr\r\n\r\n"),
674 MockWrite(SYNCHRONOUS, 4, kUploadBody),
675 };
676 MockRead reads1[] = {
677 MockRead(SYNCHRONOUS, 2,
678 "HTTP/1.1 200 OK\r\n"
679 "Connection: Keep-Alive\r\n"
680 "Content-Length: 0\r\n\r\n"),
681 MockRead(SYNCHRONOUS, 5,
682 "HTTP/1.1 200 OK\r\n"
683 "Connection: Keep-Alive\r\n"
684 "Content-Length: 0\r\n\r\n"),
685 };
686 SequencedSocketData data1(reads1, writes1);
687 socket_factory.AddSocketDataProvider(&data1);
688 SSLSocketDataProvider ssl_data1(ASYNC, OK);
689 socket_factory.AddSSLSocketDataProvider(&ssl_data1);
690
691 // Second socket handles second request.
692 MockWrite writes2[] = {
693 MockWrite(SYNCHRONOUS, 0,
694 "POST /2 HTTP/1.1\r\n"
695 "Host: origin\r\n"
696 "Connection: keep-alive\r\n"
697 "Content-Length: 2\r\n"
698 "Content-Type: application/reports+json\r\n"
699 "User-Agent: \r\n"
700 "Accept-Encoding: gzip, deflate\r\n"
701 "Accept-Language: en-us,fr\r\n\r\n"),
702 MockWrite(SYNCHRONOUS, 1, kUploadBody),
703 };
704 MockRead reads2[] = {
705 MockRead(SYNCHRONOUS, 2,
706 "HTTP/1.1 200 OK\r\n"
707 "Connection: Keep-Alive\r\n"
708 "Content-Length: 0\r\n\r\n"),
709 };
710 SequencedSocketData data2(reads2, writes2);
711 socket_factory.AddSocketDataProvider(&data2);
712 SSLSocketDataProvider ssl_data2(ASYNC, OK);
713 socket_factory.AddSSLSocketDataProvider(&ssl_data2);
714
715 TestUploadCallback callback1;
716 std::unique_ptr<ReportingUploader> uploader1 =
717 ReportingUploader::Create(context.get());
718 uploader1->StartUpload(kOrigin, GURL("https://origin/1"), kIsolationInfo1,
719 kUploadBody, 0, false, callback1.callback());
720 callback1.WaitForCall();
721 EXPECT_EQ(ReportingUploader::Outcome::SUCCESS, callback1.outcome());
722
723 // Start two more requests in parallel. The first started uses a different
724 // NetworkAnonymizationKey, so should create a new socket, while the second
725 // one gets the other socket. Start in parallel to make sure that a new socket
726 // isn't created just because the first is returned to the socket pool
727 // asynchronously.
728 TestUploadCallback callback2;
729 std::unique_ptr<ReportingUploader> uploader2 =
730 ReportingUploader::Create(context.get());
731 uploader2->StartUpload(kOrigin, GURL("https://origin/2"), kIsolationInfo2,
732 kUploadBody, 0, false, callback2.callback());
733 TestUploadCallback callback3;
734 std::unique_ptr<ReportingUploader> uploader3 =
735 ReportingUploader::Create(context.get());
736 uploader3->StartUpload(kOrigin, GURL("https://origin/3"), kIsolationInfo1,
737 kUploadBody, 0, false, callback3.callback());
738
739 callback2.WaitForCall();
740 EXPECT_EQ(ReportingUploader::Outcome::SUCCESS, callback2.outcome());
741
742 callback3.WaitForCall();
743 EXPECT_EQ(ReportingUploader::Outcome::SUCCESS, callback3.outcome());
744 }
745
746 } // namespace
747 } // namespace net
748