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 = CanonicalCookie::Create(
535 url, "foo=bar", base::Time::Now(), absl::nullopt /* server_time */,
536 absl::nullopt /* cookie_partition_key */);
537 context_->cookie_store()->SetCanonicalCookieAsync(
538 std::move(cookie), url, CookieOptions::MakeAllInclusive(),
539 cookie_callback.MakeCallback());
540 cookie_callback.WaitUntilDone();
541 ASSERT_TRUE(cookie_callback.result().status.IsInclude());
542
543 TestUploadCallback upload_callback;
544 uploader_->StartUpload(kOrigin, server_.GetURL("/"),
545 IsolationInfo::CreateTransient(), kUploadBody, 0,
546 false, upload_callback.callback());
547 upload_callback.WaitForCall();
548 }
549
SendCookie(const test_server::HttpRequest & request)550 std::unique_ptr<test_server::HttpResponse> SendCookie(
551 const test_server::HttpRequest& request) {
552 auto response = std::make_unique<test_server::BasicHttpResponse>();
553 response->set_code(HTTP_OK);
554 response->AddCustomHeader("Set-Cookie", "foo=bar");
555 response->set_content("");
556 response->set_content_type("text/plain");
557 return std::move(response);
558 }
559
TEST_F(ReportingUploaderTest,DontSaveCookies)560 TEST_F(ReportingUploaderTest, DontSaveCookies) {
561 server_.RegisterRequestHandler(base::BindRepeating(&AllowPreflight));
562 server_.RegisterRequestHandler(base::BindRepeating(&SendCookie));
563 ASSERT_TRUE(server_.Start());
564
565 TestUploadCallback upload_callback;
566 uploader_->StartUpload(kOrigin, server_.GetURL("/"),
567 IsolationInfo::CreateTransient(), kUploadBody, 0,
568 false, upload_callback.callback());
569 upload_callback.WaitForCall();
570
571 GetCookieListCallback cookie_callback;
572 context_->cookie_store()->GetCookieListWithOptionsAsync(
573 server_.GetURL("/"), CookieOptions::MakeAllInclusive(),
574 CookiePartitionKeyCollection(),
575 base::BindOnce(&GetCookieListCallback::Run,
576 base::Unretained(&cookie_callback)));
577 cookie_callback.WaitUntilDone();
578
579 EXPECT_TRUE(cookie_callback.cookies().empty());
580 }
581
ReturnCacheableResponse(int * request_count_out,const test_server::HttpRequest & request)582 std::unique_ptr<test_server::HttpResponse> ReturnCacheableResponse(
583 int* request_count_out,
584 const test_server::HttpRequest& request) {
585 ++*request_count_out;
586 auto response = std::make_unique<test_server::BasicHttpResponse>();
587 response->set_code(HTTP_OK);
588 response->AddCustomHeader("Cache-Control", "max-age=86400");
589 response->set_content("");
590 response->set_content_type("text/plain");
591 return std::move(response);
592 }
593
594 // TODO(juliatuttle): This passes even if the uploader doesn't set
595 // LOAD_DISABLE_CACHE. Maybe that's okay -- Chromium might not cache POST
596 // responses ever -- but this test should either not exist or be sure that it is
597 // testing actual functionality, not a default.
TEST_F(ReportingUploaderTest,DontCacheResponse)598 TEST_F(ReportingUploaderTest, DontCacheResponse) {
599 int request_count = 0;
600 server_.RegisterRequestHandler(base::BindRepeating(&AllowPreflight));
601 server_.RegisterRequestHandler(
602 base::BindRepeating(&ReturnCacheableResponse, &request_count));
603 ASSERT_TRUE(server_.Start());
604
605 {
606 TestUploadCallback callback;
607 uploader_->StartUpload(kOrigin, server_.GetURL("/"),
608 IsolationInfo::CreateTransient(), kUploadBody, 0,
609 false, callback.callback());
610 callback.WaitForCall();
611 }
612 EXPECT_EQ(1, request_count);
613
614 {
615 TestUploadCallback callback;
616 uploader_->StartUpload(kOrigin, server_.GetURL("/"),
617 IsolationInfo::CreateTransient(), kUploadBody, 0,
618 false, callback.callback());
619 callback.WaitForCall();
620 }
621 EXPECT_EQ(2, request_count);
622 }
623
624 // Create two requests with the same NetworkAnonymizationKey, and one request
625 // with a different one, and make sure only the requests with the same
626 // NetworkAnonymizationKey share a socket.
TEST_F(ReportingUploaderTest,RespectsNetworkAnonymizationKey)627 TEST_F(ReportingUploaderTest, RespectsNetworkAnonymizationKey) {
628 // While network state partitioning is not needed for reporting code to
629 // respect NetworkAnonymizationKey, this test works by ensuring that
630 // Reporting's NetworkAnonymizationKey makes it to the socket pool layer and
631 // is respected there, so this test needs to enable
632 // network state partitioning.
633 base::test::ScopedFeatureList feature_list;
634 feature_list.InitAndEnableFeature(
635 features::kPartitionConnectionsByNetworkIsolationKey);
636
637 const SchemefulSite kSite1 = SchemefulSite(kOrigin);
638 const SchemefulSite kSite2(GURL("https://origin2/"));
639 ASSERT_NE(kSite1, kSite2);
640 const NetworkIsolationKey kNetworkIsolationKey1(kSite1, kSite1);
641 const NetworkIsolationKey kNetworkIsolationKey2(kSite2, kSite2);
642 const url::Origin kSiteOrigin1 = url::Origin::Create(kSite1.GetURL());
643 const url::Origin kSiteOrigin2 = url::Origin::Create(kSite2.GetURL());
644 const IsolationInfo kIsolationInfo1 =
645 IsolationInfo::Create(net::IsolationInfo::RequestType::kOther,
646 kSiteOrigin1, kSiteOrigin1, net::SiteForCookies());
647 const IsolationInfo kIsolationInfo2 =
648 IsolationInfo::Create(net::IsolationInfo::RequestType::kOther,
649 kSiteOrigin2, kSiteOrigin2, net::SiteForCookies());
650
651 MockClientSocketFactory socket_factory;
652 auto context_builder = CreateTestURLRequestContextBuilder();
653 context_builder->set_client_socket_factory_for_testing(&socket_factory);
654 auto context = context_builder->Build();
655
656 // First socket handles first and third requests.
657 MockWrite writes1[] = {
658 MockWrite(SYNCHRONOUS, 0,
659 "POST /1 HTTP/1.1\r\n"
660 "Host: origin\r\n"
661 "Connection: keep-alive\r\n"
662 "Content-Length: 2\r\n"
663 "Content-Type: application/reports+json\r\n"
664 "User-Agent: \r\n"
665 "Accept-Encoding: gzip, deflate\r\n"
666 "Accept-Language: en-us,fr\r\n\r\n"),
667 MockWrite(SYNCHRONOUS, 1, kUploadBody),
668 MockWrite(SYNCHRONOUS, 3,
669 "POST /3 HTTP/1.1\r\n"
670 "Host: origin\r\n"
671 "Connection: keep-alive\r\n"
672 "Content-Length: 2\r\n"
673 "Content-Type: application/reports+json\r\n"
674 "User-Agent: \r\n"
675 "Accept-Encoding: gzip, deflate\r\n"
676 "Accept-Language: en-us,fr\r\n\r\n"),
677 MockWrite(SYNCHRONOUS, 4, kUploadBody),
678 };
679 MockRead reads1[] = {
680 MockRead(SYNCHRONOUS, 2,
681 "HTTP/1.1 200 OK\r\n"
682 "Connection: Keep-Alive\r\n"
683 "Content-Length: 0\r\n\r\n"),
684 MockRead(SYNCHRONOUS, 5,
685 "HTTP/1.1 200 OK\r\n"
686 "Connection: Keep-Alive\r\n"
687 "Content-Length: 0\r\n\r\n"),
688 };
689 SequencedSocketData data1(reads1, writes1);
690 socket_factory.AddSocketDataProvider(&data1);
691 SSLSocketDataProvider ssl_data1(ASYNC, OK);
692 socket_factory.AddSSLSocketDataProvider(&ssl_data1);
693
694 // Second socket handles second request.
695 MockWrite writes2[] = {
696 MockWrite(SYNCHRONOUS, 0,
697 "POST /2 HTTP/1.1\r\n"
698 "Host: origin\r\n"
699 "Connection: keep-alive\r\n"
700 "Content-Length: 2\r\n"
701 "Content-Type: application/reports+json\r\n"
702 "User-Agent: \r\n"
703 "Accept-Encoding: gzip, deflate\r\n"
704 "Accept-Language: en-us,fr\r\n\r\n"),
705 MockWrite(SYNCHRONOUS, 1, kUploadBody),
706 };
707 MockRead reads2[] = {
708 MockRead(SYNCHRONOUS, 2,
709 "HTTP/1.1 200 OK\r\n"
710 "Connection: Keep-Alive\r\n"
711 "Content-Length: 0\r\n\r\n"),
712 };
713 SequencedSocketData data2(reads2, writes2);
714 socket_factory.AddSocketDataProvider(&data2);
715 SSLSocketDataProvider ssl_data2(ASYNC, OK);
716 socket_factory.AddSSLSocketDataProvider(&ssl_data2);
717
718 TestUploadCallback callback1;
719 std::unique_ptr<ReportingUploader> uploader1 =
720 ReportingUploader::Create(context.get());
721 uploader1->StartUpload(kOrigin, GURL("https://origin/1"), kIsolationInfo1,
722 kUploadBody, 0, false, callback1.callback());
723 callback1.WaitForCall();
724 EXPECT_EQ(ReportingUploader::Outcome::SUCCESS, callback1.outcome());
725
726 // Start two more requests in parallel. The first started uses a different
727 // NetworkAnonymizationKey, so should create a new socket, while the second
728 // one gets the other socket. Start in parallel to make sure that a new socket
729 // isn't created just because the first is returned to the socket pool
730 // asynchronously.
731 TestUploadCallback callback2;
732 std::unique_ptr<ReportingUploader> uploader2 =
733 ReportingUploader::Create(context.get());
734 uploader2->StartUpload(kOrigin, GURL("https://origin/2"), kIsolationInfo2,
735 kUploadBody, 0, false, callback2.callback());
736 TestUploadCallback callback3;
737 std::unique_ptr<ReportingUploader> uploader3 =
738 ReportingUploader::Create(context.get());
739 uploader3->StartUpload(kOrigin, GURL("https://origin/3"), kIsolationInfo1,
740 kUploadBody, 0, false, callback3.callback());
741
742 callback2.WaitForCall();
743 EXPECT_EQ(ReportingUploader::Outcome::SUCCESS, callback2.outcome());
744
745 callback3.WaitForCall();
746 EXPECT_EQ(ReportingUploader::Outcome::SUCCESS, callback3.outcome());
747 }
748
749 } // namespace
750 } // namespace net
751