1 // Copyright 2017 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "base/macros.h"
6 #include "base/run_loop.h"
7 #include "base/single_thread_task_runner.h"
8 #include "base/strings/stringprintf.h"
9 #include "base/test/values_test_util.h"
10 #include "base/threading/thread_task_runner_handle.h"
11 #include "base/time/time.h"
12 #include "base/values.h"
13 #include "build/build_config.h"
14 #include "net/base/net_errors.h"
15 #include "net/network_error_logging/network_error_logging_service.h"
16 #include "net/reporting/reporting_policy.h"
17 #include "net/test/embedded_test_server/embedded_test_server.h"
18 #include "net/test/embedded_test_server/http_request.h"
19 #include "net/test/embedded_test_server/http_response.h"
20 #include "net/traffic_annotation/network_traffic_annotation_test_helper.h"
21 #include "net/url_request/url_request.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_status.h"
25 #include "net/url_request/url_request_test_util.h"
26 #include "testing/gtest/include/gtest/gtest.h"
28 #if defined(OS_LINUX) || defined(OS_ANDROID)
29 #include "net/proxy_resolution/proxy_config.h"
30 #include "net/proxy_resolution/proxy_config_service_fixed.h"
31 #endif // defined(OS_LINUX) || defined(OS_ANDROID)
36 const char kGroup[] = "network-errors";
37 const int kMaxAgeSec = 86400;
39 const char kConfigurePath[] = "/configure";
40 const char kFailPath[] = "/fail";
41 const char kReportPath[] = "/report";
43 class HungHttpResponse : public test_server::HttpResponse {
45 HungHttpResponse() = default;
47 void SendResponse(const test_server::SendBytesCallback& send,
48 const test_server::SendCompleteCallback& done) override {}
51 DISALLOW_COPY_AND_ASSIGN(HungHttpResponse);
54 class NetworkErrorLoggingEndToEndTest : public ::testing::Test {
56 NetworkErrorLoggingEndToEndTest()
57 : main_task_runner_(base::ThreadTaskRunnerHandle::Get()),
58 test_server_(test_server::EmbeddedTestServer::TYPE_HTTPS),
59 upload_should_hang_(false),
60 upload_received_(false) {
61 // Make report delivery happen instantly.
62 auto policy = std::make_unique<ReportingPolicy>();
63 policy->delivery_interval = base::TimeDelta::FromSeconds(0);
65 URLRequestContextBuilder builder;
66 #if defined(OS_LINUX) || defined(OS_ANDROID)
67 builder.set_proxy_config_service(std::make_unique<ProxyConfigServiceFixed>(
68 ProxyConfigWithAnnotation::CreateDirect()));
69 #endif // defined(OS_LINUX) || defined(OS_ANDROID)
70 builder.set_reporting_policy(std::move(policy));
71 builder.set_network_error_logging_enabled(true);
72 url_request_context_ = builder.Build();
74 EXPECT_TRUE(url_request_context_->reporting_service());
75 EXPECT_TRUE(url_request_context_->network_error_logging_service());
77 test_server_.RegisterRequestHandler(base::BindRepeating(
78 &NetworkErrorLoggingEndToEndTest::HandleConfigureRequest,
79 base::Unretained(this)));
80 test_server_.RegisterRequestHandler(
81 base::BindRepeating(&NetworkErrorLoggingEndToEndTest::HandleFailRequest,
82 base::Unretained(this)));
83 test_server_.RegisterRequestHandler(base::BindRepeating(
84 &NetworkErrorLoggingEndToEndTest::HandleReportRequest,
85 base::Unretained(this)));
86 EXPECT_TRUE(test_server_.Start());
89 ~NetworkErrorLoggingEndToEndTest() override {
90 EXPECT_TRUE(test_server_.ShutdownAndWaitUntilComplete());
93 GURL GetConfigureURL() { return test_server_.GetURL(kConfigurePath); }
95 GURL GetFailURL() { return test_server_.GetURL(kFailPath); }
97 GURL GetReportURL() { return test_server_.GetURL(kReportPath); }
99 std::unique_ptr<test_server::HttpResponse> HandleConfigureRequest(
100 const test_server::HttpRequest& request) {
101 if (request.relative_url != kConfigurePath)
104 GURL endpoint_url = GetReportURL();
106 auto response = std::make_unique<test_server::BasicHttpResponse>();
107 response->AddCustomHeader(
109 base::StringPrintf("{\"endpoints\":[{\"url\":\"%s\"}],\"group\":\"%s\","
111 endpoint_url.spec().c_str(), kGroup, kMaxAgeSec));
112 response->AddCustomHeader(
113 "NEL", base::StringPrintf("{\"report-to\":\"%s\",\"max-age\":%d}",
114 kGroup, kMaxAgeSec));
115 response->set_content_type("text/plain");
116 response->set_content("");
117 return std::move(response);
120 std::unique_ptr<test_server::HttpResponse> HandleFailRequest(
121 const test_server::HttpRequest& request) {
122 if (request.relative_url != kFailPath)
125 return std::make_unique<test_server::RawHttpResponse>("", "");
128 std::unique_ptr<test_server::HttpResponse> HandleReportRequest(
129 const test_server::HttpRequest& request) {
130 if (request.relative_url != kReportPath)
133 EXPECT_TRUE(request.has_content);
134 main_task_runner_->PostTask(
136 base::BindOnce(&NetworkErrorLoggingEndToEndTest::OnUploadReceived,
137 base::Unretained(this), request.content));
139 if (upload_should_hang_)
140 return std::make_unique<HungHttpResponse>();
142 auto response = std::make_unique<test_server::BasicHttpResponse>();
143 response->set_content_type("text/plain");
144 response->set_content("");
145 return std::move(response);
148 void OnUploadReceived(std::string content) {
149 upload_received_ = true;
150 upload_content_ = content;
151 upload_run_loop_.Quit();
154 scoped_refptr<base::SingleThreadTaskRunner> main_task_runner_;
155 std::unique_ptr<URLRequestContext> url_request_context_;
156 test_server::EmbeddedTestServer test_server_;
158 bool upload_should_hang_;
159 bool upload_received_;
160 std::string upload_content_;
161 base::RunLoop upload_run_loop_;
164 DISALLOW_COPY_AND_ASSIGN(NetworkErrorLoggingEndToEndTest);
168 // TODO(https://crbug.com/829650): Fix and re-enable these tests.
169 #define MAYBE_ReportNetworkError DISABLED_ReportNetworkError
171 #define MAYBE_ReportNetworkError ReportNetworkError
173 TEST_F(NetworkErrorLoggingEndToEndTest, MAYBE_ReportNetworkError) {
174 TestDelegate configure_delegate;
175 configure_delegate.set_quit_on_complete(false);
176 auto configure_request = url_request_context_->CreateRequest(
177 GetConfigureURL(), DEFAULT_PRIORITY, &configure_delegate,
178 TRAFFIC_ANNOTATION_FOR_TESTS);
179 configure_request->set_method("GET");
180 configure_request->Start();
182 TestDelegate fail_delegate;
183 fail_delegate.set_quit_on_complete(false);
184 auto fail_request = url_request_context_->CreateRequest(
185 GetFailURL(), DEFAULT_PRIORITY, &fail_delegate,
186 TRAFFIC_ANNOTATION_FOR_TESTS);
187 fail_request->set_method("GET");
188 fail_request->Start();
190 upload_run_loop_.Run();
192 EXPECT_TRUE(upload_received_);
193 auto reports = base::test::ParseJson(upload_content_);
195 base::ListValue* reports_list;
196 ASSERT_TRUE(reports->GetAsList(&reports_list));
197 ASSERT_EQ(1u, reports_list->GetSize());
198 base::DictionaryValue* report_dict;
199 ASSERT_TRUE(reports_list->GetDictionary(0u, &report_dict));
201 ExpectDictStringValue("network-error", *report_dict, "type");
202 ExpectDictStringValue(GetFailURL().spec(), *report_dict, "url");
203 base::DictionaryValue* body_dict;
204 ASSERT_TRUE(report_dict->GetDictionary("report", &body_dict));
206 ExpectDictStringValue("http.response.empty", *body_dict, "type");
207 ExpectDictIntegerValue(0, *body_dict, "status-code");
208 ExpectDictStringValue(GetFailURL().spec(), *body_dict, "uri");
212 // TODO(https://crbug.com/829650): Fix and re-enable these tests.
213 #define MAYBE_UploadAtShutdown DISABLED_UploadAtShutdown
215 #define MAYBE_UploadAtShutdown UploadAtShutdown
217 // Make sure an upload that is in progress at shutdown does not crash.
218 // This verifies that https://crbug.com/792978 is fixed.
219 TEST_F(NetworkErrorLoggingEndToEndTest, MAYBE_UploadAtShutdown) {
220 upload_should_hang_ = true;
222 TestDelegate configure_delegate;
223 configure_delegate.set_quit_on_complete(false);
224 auto configure_request = url_request_context_->CreateRequest(
225 GetConfigureURL(), DEFAULT_PRIORITY, &configure_delegate,
226 TRAFFIC_ANNOTATION_FOR_TESTS);
227 configure_request->set_method("GET");
228 configure_request->Start();
230 TestDelegate fail_delegate;
231 fail_delegate.set_quit_on_complete(false);
232 auto fail_request = url_request_context_->CreateRequest(
233 GetFailURL(), DEFAULT_PRIORITY, &fail_delegate,
234 TRAFFIC_ANNOTATION_FOR_TESTS);
235 fail_request->set_method("GET");
236 fail_request->Start();
238 upload_run_loop_.Run();
240 // Let Reporting and NEL shut down with the upload still pending to see if