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 "net/url_request/report_sender.h"
6
7 #include "base/functional/bind.h"
8 #include "base/functional/callback_helpers.h"
9 #include "base/run_loop.h"
10 #include "net/base/load_flags.h"
11 #include "net/base/network_delegate_impl.h"
12 #include "net/base/upload_bytes_element_reader.h"
13 #include "net/base/upload_data_stream.h"
14 #include "net/base/upload_element_reader.h"
15 #include "net/http/http_response_headers.h"
16 #include "net/http/http_status_code.h"
17 #include "net/test/test_with_task_environment.h"
18 #include "net/test/url_request/url_request_failed_job.h"
19 #include "net/test/url_request/url_request_mock_data_job.h"
20 #include "net/test/url_request/url_request_mock_http_job.h"
21 #include "net/traffic_annotation/network_traffic_annotation_test_helper.h"
22 #include "net/url_request/url_request_context.h"
23 #include "net/url_request/url_request_context_builder.h"
24 #include "net/url_request/url_request_filter.h"
25 #include "net/url_request/url_request_test_util.h"
26 #include "testing/gtest/include/gtest/gtest.h"
27
28 namespace net {
29 namespace {
30
31 const char kDummyReport[] = "foo.test";
32 const char kSecondDummyReport[] = "foo2.test";
33 const char kServerErrorHostname[] = "mock.server.error";
34
MarkURLRequestDestroyed(bool * url_request_destroyed)35 void MarkURLRequestDestroyed(bool* url_request_destroyed) {
36 *url_request_destroyed = true;
37 }
38
39 // Checks that data uploaded in the request matches the test report
40 // data. Erases the sent reports from |expect_reports|.
CheckUploadData(const URLRequest & request,std::set<std::string> * expect_reports)41 void CheckUploadData(const URLRequest& request,
42 std::set<std::string>* expect_reports) {
43 const UploadDataStream* upload = request.get_upload_for_testing();
44 ASSERT_TRUE(upload);
45 ASSERT_TRUE(upload->GetElementReaders());
46 ASSERT_EQ(1u, upload->GetElementReaders()->size());
47
48 const UploadBytesElementReader* reader =
49 (*upload->GetElementReaders())[0]->AsBytesReader();
50 ASSERT_TRUE(reader);
51 std::string upload_data(reader->bytes(), reader->length());
52
53 EXPECT_EQ(1u, expect_reports->erase(upload_data));
54 }
55
56 // Error callback for a report with a net error.
ErrorCallback(bool * called,const GURL & report_uri,int net_error,int http_response_code)57 void ErrorCallback(bool* called,
58 const GURL& report_uri,
59 int net_error,
60 int http_response_code) {
61 EXPECT_NE(OK, net_error);
62 EXPECT_EQ(-1, http_response_code);
63 *called = true;
64 }
65
66 // Error callback for a report with a non-200 HTTP response code and no net
67 // errors.
ServerErrorResponseCallback(bool * called,const GURL & report_uri,int net_error,int http_response_code)68 void ServerErrorResponseCallback(bool* called,
69 const GURL& report_uri,
70 int net_error,
71 int http_response_code) {
72 EXPECT_EQ(OK, net_error);
73 EXPECT_EQ(HTTP_INTERNAL_SERVER_ERROR, http_response_code);
74 *called = true;
75 }
76
SuccessCallback(bool * called)77 void SuccessCallback(bool* called) {
78 *called = true;
79 }
80
81 // URLRequestJob that returns an HTTP 500 response.
82 class MockServerErrorJob : public URLRequestJob {
83 public:
MockServerErrorJob(URLRequest * request)84 explicit MockServerErrorJob(URLRequest* request) : URLRequestJob(request) {}
85
86 MockServerErrorJob(const MockServerErrorJob&) = delete;
87 MockServerErrorJob& operator=(const MockServerErrorJob&) = delete;
88
89 ~MockServerErrorJob() override = default;
90
91 protected:
GetResponseInfo(HttpResponseInfo * info)92 void GetResponseInfo(HttpResponseInfo* info) override {
93 info->headers = base::MakeRefCounted<HttpResponseHeaders>(
94 "HTTP/1.1 500 Internal Server Error\n"
95 "Content-type: text/plain\n"
96 "Content-Length: 0\n");
97 }
Start()98 void Start() override { NotifyHeadersComplete(); }
99 };
100
101 class MockServerErrorJobInterceptor : public URLRequestInterceptor {
102 public:
103 MockServerErrorJobInterceptor() = default;
104
105 MockServerErrorJobInterceptor(const MockServerErrorJobInterceptor&) = delete;
106 MockServerErrorJobInterceptor& operator=(
107 const MockServerErrorJobInterceptor&) = delete;
108
109 ~MockServerErrorJobInterceptor() override = default;
110
MaybeInterceptRequest(URLRequest * request) const111 std::unique_ptr<URLRequestJob> MaybeInterceptRequest(
112 URLRequest* request) const override {
113 return std::make_unique<MockServerErrorJob>(request);
114 }
115 };
116
117 // A network delegate that lets tests check that a report
118 // was sent. It counts the number of requests and lets tests register a
119 // callback to run when the request is destroyed. It also checks that
120 // the uploaded data is as expected.
121 class TestReportSenderNetworkDelegate : public NetworkDelegateImpl {
122 public:
TestReportSenderNetworkDelegate()123 TestReportSenderNetworkDelegate()
124 : url_request_destroyed_callback_(base::DoNothing()),
125 all_url_requests_destroyed_callback_(base::DoNothing()) {}
126
127 TestReportSenderNetworkDelegate(const TestReportSenderNetworkDelegate&) =
128 delete;
129 TestReportSenderNetworkDelegate& operator=(
130 const TestReportSenderNetworkDelegate&) = delete;
131
ExpectReport(const std::string & report)132 void ExpectReport(const std::string& report) {
133 expect_reports_.insert(report);
134 }
135
set_all_url_requests_destroyed_callback(base::RepeatingClosure callback)136 void set_all_url_requests_destroyed_callback(
137 base::RepeatingClosure callback) {
138 all_url_requests_destroyed_callback_ = std::move(callback);
139 }
140
set_url_request_destroyed_callback(base::RepeatingClosure callback)141 void set_url_request_destroyed_callback(base::RepeatingClosure callback) {
142 url_request_destroyed_callback_ = std::move(callback);
143 }
144
set_expect_url(const GURL & expect_url)145 void set_expect_url(const GURL& expect_url) { expect_url_ = expect_url; }
146
num_requests() const147 size_t num_requests() const { return num_requests_; }
148
set_expected_content_type(const std::string & content_type)149 void set_expected_content_type(const std::string& content_type) {
150 expected_content_type_ = content_type;
151 }
152
set_expected_network_anonymization_key(const NetworkAnonymizationKey & expected_network_anonymization_key)153 void set_expected_network_anonymization_key(
154 const NetworkAnonymizationKey& expected_network_anonymization_key) {
155 expected_network_anonymization_key_ = expected_network_anonymization_key;
156 }
157
158 // NetworkDelegateImpl implementation.
OnBeforeURLRequest(URLRequest * request,CompletionOnceCallback callback,GURL * new_url)159 int OnBeforeURLRequest(URLRequest* request,
160 CompletionOnceCallback callback,
161 GURL* new_url) override {
162 num_requests_++;
163 EXPECT_EQ(expect_url_, request->url());
164 EXPECT_STRCASEEQ("POST", request->method().data());
165 EXPECT_FALSE(request->allow_credentials());
166 EXPECT_TRUE(request->load_flags() & LOAD_DO_NOT_SAVE_COOKIES);
167
168 EXPECT_EQ(expected_network_anonymization_key_,
169 request->isolation_info().network_anonymization_key());
170 EXPECT_EQ(IsolationInfo::RequestType::kOther,
171 request->isolation_info().request_type());
172 EXPECT_TRUE(request->site_for_cookies().IsNull());
173
174 const HttpRequestHeaders& extra_headers = request->extra_request_headers();
175 std::string content_type;
176 EXPECT_TRUE(extra_headers.GetHeader(HttpRequestHeaders::kContentType,
177 &content_type));
178 EXPECT_EQ(expected_content_type_, content_type);
179
180 CheckUploadData(*request, &expect_reports_);
181
182 // Unconditionally return OK, since the sender ignores the results
183 // anyway.
184 return OK;
185 }
186
OnURLRequestDestroyed(URLRequest * request)187 void OnURLRequestDestroyed(URLRequest* request) override {
188 url_request_destroyed_callback_.Run();
189 if (expect_reports_.empty())
190 all_url_requests_destroyed_callback_.Run();
191 }
192
193 private:
194 base::RepeatingClosure url_request_destroyed_callback_;
195 base::RepeatingClosure all_url_requests_destroyed_callback_;
196 size_t num_requests_ = 0;
197 GURL expect_url_;
198 std::set<std::string> expect_reports_;
199 std::string expected_content_type_;
200 NetworkAnonymizationKey expected_network_anonymization_key_;
201 };
202
203 class ReportSenderTest : public TestWithTaskEnvironment {
204 public:
ReportSenderTest()205 ReportSenderTest() {
206 auto builder = CreateTestURLRequestContextBuilder();
207 builder->set_network_delegate(
208 std::make_unique<TestReportSenderNetworkDelegate>());
209 context_ = builder->Build();
210 }
211
SetUp()212 void SetUp() override {
213 URLRequestFailedJob::AddUrlHandler();
214 URLRequestMockDataJob::AddUrlHandler();
215 URLRequestFilter::GetInstance()->AddHostnameInterceptor(
216 "http", kServerErrorHostname,
217 std::make_unique<MockServerErrorJobInterceptor>());
218 }
219
TearDown()220 void TearDown() override { URLRequestFilter::GetInstance()->ClearHandlers(); }
221
context()222 URLRequestContext* context() { return context_.get(); }
223
network_delegate()224 TestReportSenderNetworkDelegate& network_delegate() {
225 // This cast is safe because we set a TestReportSenderNetworkDelegate in the
226 // constructor.
227 return *static_cast<TestReportSenderNetworkDelegate*>(
228 context_->network_delegate());
229 }
230
231 protected:
SendReport(ReportSender * reporter,const std::string & report,const GURL & url,size_t request_sequence_number,base::OnceCallback<void ()> success_callback,base::OnceCallback<void (const GURL &,int,int)> error_callback)232 void SendReport(
233 ReportSender* reporter,
234 const std::string& report,
235 const GURL& url,
236 size_t request_sequence_number,
237 base::OnceCallback<void()> success_callback,
238 base::OnceCallback<void(const GURL&, int, int)> error_callback) {
239 NetworkAnonymizationKey network_anonymization_key =
240 NetworkAnonymizationKey::CreateTransient();
241
242 base::RunLoop run_loop;
243 network_delegate().set_url_request_destroyed_callback(
244 run_loop.QuitClosure());
245
246 network_delegate().set_expect_url(url);
247 network_delegate().ExpectReport(report);
248 network_delegate().set_expected_content_type("application/foobar");
249 network_delegate().set_expected_network_anonymization_key(
250 network_anonymization_key);
251
252 EXPECT_EQ(request_sequence_number, network_delegate().num_requests());
253
254 reporter->Send(url, "application/foobar", report, network_anonymization_key,
255 std::move(success_callback), std::move(error_callback));
256
257 // The report is sent asynchronously, so wait for the report's
258 // URLRequest to be destroyed before checking that the report was
259 // sent.
260 run_loop.Run();
261
262 EXPECT_EQ(request_sequence_number + 1, network_delegate().num_requests());
263 }
264
SendReport(ReportSender * reporter,const std::string & report,const GURL & url,size_t request_sequence_number)265 void SendReport(ReportSender* reporter,
266 const std::string& report,
267 const GURL& url,
268 size_t request_sequence_number) {
269 SendReport(reporter, report, url, request_sequence_number,
270 base::OnceCallback<void()>(),
271 base::OnceCallback<void(const GURL&, int, int)>());
272 }
273
274 private:
275 std::unique_ptr<URLRequestContext> context_;
276 };
277
278 // Test that ReportSender::Send creates a URLRequest for the
279 // endpoint and sends the expected data.
TEST_F(ReportSenderTest,SendsRequest)280 TEST_F(ReportSenderTest, SendsRequest) {
281 GURL url = URLRequestMockDataJob::GetMockHttpsUrl("dummy data", 1);
282 ReportSender reporter(context(), TRAFFIC_ANNOTATION_FOR_TESTS);
283 SendReport(&reporter, kDummyReport, url, 0);
284 }
285
TEST_F(ReportSenderTest,SendMultipleReportsSequentially)286 TEST_F(ReportSenderTest, SendMultipleReportsSequentially) {
287 GURL url = URLRequestMockDataJob::GetMockHttpsUrl("dummy data", 1);
288 ReportSender reporter(context(), TRAFFIC_ANNOTATION_FOR_TESTS);
289 SendReport(&reporter, kDummyReport, url, 0);
290 SendReport(&reporter, kDummyReport, url, 1);
291 }
292
TEST_F(ReportSenderTest,SendMultipleReportsSimultaneously)293 TEST_F(ReportSenderTest, SendMultipleReportsSimultaneously) {
294 base::RunLoop run_loop;
295 network_delegate().set_all_url_requests_destroyed_callback(
296 run_loop.QuitClosure());
297
298 GURL url = URLRequestMockDataJob::GetMockHttpsUrl("dummy data", 1);
299 network_delegate().set_expect_url(url);
300 network_delegate().ExpectReport(kDummyReport);
301 network_delegate().ExpectReport(kSecondDummyReport);
302 network_delegate().set_expected_content_type("application/foobar");
303
304 ReportSender reporter(context(), TRAFFIC_ANNOTATION_FOR_TESTS);
305
306 EXPECT_EQ(0u, network_delegate().num_requests());
307
308 reporter.Send(url, "application/foobar", kDummyReport,
309 NetworkAnonymizationKey(), base::OnceCallback<void()>(),
310 base::OnceCallback<void(const GURL&, int, int)>());
311 reporter.Send(url, "application/foobar", kSecondDummyReport,
312 NetworkAnonymizationKey(), base::OnceCallback<void()>(),
313 base::OnceCallback<void(const GURL&, int, int)>());
314
315 run_loop.Run();
316
317 EXPECT_EQ(2u, network_delegate().num_requests());
318 }
319
320 // Test that pending URLRequests get cleaned up when the report sender
321 // is deleted.
TEST_F(ReportSenderTest,PendingRequestGetsDeleted)322 TEST_F(ReportSenderTest, PendingRequestGetsDeleted) {
323 bool url_request_destroyed = false;
324 network_delegate().set_url_request_destroyed_callback(base::BindRepeating(
325 &MarkURLRequestDestroyed, base::Unretained(&url_request_destroyed)));
326
327 GURL url = URLRequestFailedJob::GetMockHttpUrlWithFailurePhase(
328 URLRequestFailedJob::START, ERR_IO_PENDING);
329 network_delegate().set_expect_url(url);
330 network_delegate().ExpectReport(kDummyReport);
331 network_delegate().set_expected_content_type("application/foobar");
332
333 EXPECT_EQ(0u, network_delegate().num_requests());
334
335 auto reporter =
336 std::make_unique<ReportSender>(context(), TRAFFIC_ANNOTATION_FOR_TESTS);
337 reporter->Send(url, "application/foobar", kDummyReport,
338 NetworkAnonymizationKey(), base::OnceCallback<void()>(),
339 base::OnceCallback<void(const GURL&, int, int)>());
340 reporter.reset();
341
342 EXPECT_EQ(1u, network_delegate().num_requests());
343 EXPECT_TRUE(url_request_destroyed);
344 }
345
346 // Test that a request that returns an error gets cleaned up.
TEST_F(ReportSenderTest,ErroredRequestGetsDeleted)347 TEST_F(ReportSenderTest, ErroredRequestGetsDeleted) {
348 GURL url = URLRequestFailedJob::GetMockHttpsUrl(ERR_FAILED);
349 ReportSender reporter(context(), TRAFFIC_ANNOTATION_FOR_TESTS);
350 // SendReport will block until the URLRequest is destroyed.
351 SendReport(&reporter, kDummyReport, url, 0);
352 }
353
354 // Test that the error callback, if provided, gets called when a request
355 // returns an error and the success callback doesn't get called.
TEST_F(ReportSenderTest,ErroredRequestCallsErrorCallback)356 TEST_F(ReportSenderTest, ErroredRequestCallsErrorCallback) {
357 bool error_callback_called = false;
358 bool success_callback_called = false;
359 const GURL url = URLRequestFailedJob::GetMockHttpsUrl(ERR_FAILED);
360 ReportSender reporter(context(), TRAFFIC_ANNOTATION_FOR_TESTS);
361 // SendReport will block until the URLRequest is destroyed.
362 SendReport(&reporter, kDummyReport, url, 0,
363 base::BindOnce(SuccessCallback, &success_callback_called),
364 base::BindOnce(ErrorCallback, &error_callback_called));
365 EXPECT_TRUE(error_callback_called);
366 EXPECT_FALSE(success_callback_called);
367 }
368
369 // Test that the error callback, if provided, gets called when a request
370 // finishes successfully but results in a server error, and the success callback
371 // doesn't get called.
TEST_F(ReportSenderTest,BadResponseCodeCallsErrorCallback)372 TEST_F(ReportSenderTest, BadResponseCodeCallsErrorCallback) {
373 bool error_callback_called = false;
374 bool success_callback_called = false;
375 const GURL url(std::string("http://") + kServerErrorHostname);
376 ReportSender reporter(context(), TRAFFIC_ANNOTATION_FOR_TESTS);
377 // SendReport will block until the URLRequest is destroyed.
378 SendReport(
379 &reporter, kDummyReport, url, 0,
380 base::BindOnce(SuccessCallback, &success_callback_called),
381 base::BindOnce(ServerErrorResponseCallback, &error_callback_called));
382 EXPECT_TRUE(error_callback_called);
383 EXPECT_FALSE(success_callback_called);
384 }
385
386 // Test that the error callback does not get called and the success callback
387 /// gets called when a request does not return an error.
TEST_F(ReportSenderTest,SuccessfulRequestCallsSuccessCallback)388 TEST_F(ReportSenderTest, SuccessfulRequestCallsSuccessCallback) {
389 bool error_callback_called = false;
390 bool success_callback_called = false;
391 const GURL url = URLRequestMockDataJob::GetMockHttpsUrl("dummy data", 1);
392 ReportSender reporter(context(), TRAFFIC_ANNOTATION_FOR_TESTS);
393 SendReport(&reporter, kDummyReport, url, 0,
394 base::BindOnce(SuccessCallback, &success_callback_called),
395 base::BindOnce(ErrorCallback, &error_callback_called));
396 EXPECT_FALSE(error_callback_called);
397 EXPECT_TRUE(success_callback_called);
398 }
399
400 } // namespace
401 } // namespace net
402