• 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 "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