• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2016 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 "components/cronet/testing/test_server/test_server.h"
6 
7 #include <memory>
8 #include <utility>
9 
10 #include "base/base_paths.h"
11 #include "base/format_macros.h"
12 #include "base/functional/bind.h"
13 #include "base/lazy_instance.h"
14 #include "base/path_service.h"
15 #include "base/strings/string_number_conversions.h"
16 #include "base/strings/string_util.h"
17 #include "base/strings/stringprintf.h"
18 #include "net/http/http_status_code.h"
19 #include "net/test/embedded_test_server/default_handlers.h"
20 #include "net/test/embedded_test_server/embedded_test_server.h"
21 #include "net/test/embedded_test_server/http_request.h"
22 #include "net/test/embedded_test_server/http_response.h"
23 
24 namespace {
25 
26 // Cronet test data directory, relative to source root.
27 const base::FilePath::CharType kTestDataRelativePath[] =
28     FILE_PATH_LITERAL("components/cronet/testing/test_server/data");
29 
30 const char kSimplePath[] = "/simple";
31 const char kEchoHeaderPath[] = "/echo_header?";
32 const char kEchoMethodPath[] = "/echo_method";
33 const char kEchoAllHeadersPath[] = "/echo_all_headers";
34 const char kRedirectToEchoBodyPath[] = "/redirect_to_echo_body";
35 const char kSetCookiePath[] = "/set_cookie?";
36 const char kBigDataPath[] = "/big_data?";
37 const char kUseEncodingPath[] = "/use_encoding?";
38 const char kEchoBodyPath[] = "/echo_body";
39 
40 const char kSimpleResponse[] = "The quick brown fox jumps over the lazy dog.";
41 
42 std::unique_ptr<net::EmbeddedTestServer> g_test_server;
43 base::LazyInstance<std::string>::Leaky g_big_data_body =
44     LAZY_INSTANCE_INITIALIZER;
45 
SimpleRequest()46 std::unique_ptr<net::test_server::HttpResponse> SimpleRequest() {
47   auto http_response = std::make_unique<net::test_server::BasicHttpResponse>();
48   http_response->set_code(net::HTTP_OK);
49   http_response->set_content(kSimpleResponse);
50   return std::move(http_response);
51 }
52 
UseEncodingInResponse(const net::test_server::HttpRequest & request)53 std::unique_ptr<net::test_server::HttpResponse> UseEncodingInResponse(
54     const net::test_server::HttpRequest& request) {
55   std::string encoding;
56   DCHECK(base::StartsWith(request.relative_url, kUseEncodingPath,
57                           base::CompareCase::INSENSITIVE_ASCII));
58 
59   encoding = request.relative_url.substr(strlen(kUseEncodingPath));
60   auto http_response = std::make_unique<net::test_server::BasicHttpResponse>();
61   if (!encoding.compare("brotli")) {
62     const uint8_t quickfoxCompressed[] = {
63         0x0b, 0x15, 0x80, 0x54, 0x68, 0x65, 0x20, 0x71, 0x75, 0x69, 0x63, 0x6b,
64         0x20, 0x62, 0x72, 0x6f, 0x77, 0x6e, 0x20, 0x66, 0x6f, 0x78, 0x20, 0x6a,
65         0x75, 0x6d, 0x70, 0x73, 0x20, 0x6f, 0x76, 0x65, 0x72, 0x20, 0x74, 0x68,
66         0x65, 0x20, 0x6c, 0x61, 0x7a, 0x79, 0x20, 0x64, 0x6f, 0x67, 0x03};
67     std::string quickfoxCompressedStr(
68         reinterpret_cast<const char*>(quickfoxCompressed),
69         sizeof(quickfoxCompressed));
70     http_response->set_code(net::HTTP_OK);
71     http_response->set_content(quickfoxCompressedStr);
72     http_response->AddCustomHeader(std::string("content-encoding"),
73                                    std::string("br"));
74   }
75   return std::move(http_response);
76 }
77 
ReturnBigDataInResponse(const net::test_server::HttpRequest & request)78 std::unique_ptr<net::test_server::HttpResponse> ReturnBigDataInResponse(
79     const net::test_server::HttpRequest& request) {
80   DCHECK(base::StartsWith(request.relative_url, kBigDataPath,
81                           base::CompareCase::INSENSITIVE_ASCII));
82   std::string data_size_str = request.relative_url.substr(strlen(kBigDataPath));
83   int64_t data_size;
84   CHECK(base::StringToInt64(base::StringPiece(data_size_str), &data_size));
85   CHECK(data_size == static_cast<int64_t>(g_big_data_body.Get().size()));
86   return std::make_unique<net::test_server::RawHttpResponse>(
87       std::string(), g_big_data_body.Get());
88 }
89 
SetAndEchoCookieInResponse(const net::test_server::HttpRequest & request)90 std::unique_ptr<net::test_server::HttpResponse> SetAndEchoCookieInResponse(
91     const net::test_server::HttpRequest& request) {
92   std::string cookie_line;
93   DCHECK(base::StartsWith(request.relative_url, kSetCookiePath,
94                           base::CompareCase::INSENSITIVE_ASCII));
95   cookie_line = request.relative_url.substr(strlen(kSetCookiePath));
96   auto http_response = std::make_unique<net::test_server::BasicHttpResponse>();
97   http_response->set_code(net::HTTP_OK);
98   http_response->set_content(cookie_line);
99   http_response->AddCustomHeader("Set-Cookie", cookie_line);
100   return std::move(http_response);
101 }
102 
CronetTestRequestHandler(const net::test_server::HttpRequest & request)103 std::unique_ptr<net::test_server::HttpResponse> CronetTestRequestHandler(
104     const net::test_server::HttpRequest& request) {
105   if (base::StartsWith(request.relative_url, kSimplePath,
106                        base::CompareCase::INSENSITIVE_ASCII)) {
107     return SimpleRequest();
108   }
109   if (base::StartsWith(request.relative_url, kSetCookiePath,
110                        base::CompareCase::INSENSITIVE_ASCII)) {
111     return SetAndEchoCookieInResponse(request);
112   }
113   if (base::StartsWith(request.relative_url, kBigDataPath,
114                        base::CompareCase::INSENSITIVE_ASCII)) {
115     return ReturnBigDataInResponse(request);
116   }
117   if (base::StartsWith(request.relative_url, kUseEncodingPath,
118                        base::CompareCase::INSENSITIVE_ASCII)) {
119     return UseEncodingInResponse(request);
120   }
121 
122   std::unique_ptr<net::test_server::BasicHttpResponse> response(
123       new net::test_server::BasicHttpResponse());
124   response->set_content_type("text/plain");
125 
126   if (request.relative_url == kEchoBodyPath) {
127     if (request.has_content) {
128       response->set_content(request.content);
129     } else {
130       response->set_content("Request has no body. :(");
131     }
132     return std::move(response);
133   }
134 
135   if (base::StartsWith(request.relative_url, kEchoHeaderPath,
136                        base::CompareCase::SENSITIVE)) {
137     GURL url = g_test_server->GetURL(request.relative_url);
138     auto it = request.headers.find(url.query());
139     if (it != request.headers.end()) {
140       response->set_content(it->second);
141     } else {
142       response->set_content("Header not found. :(");
143     }
144     return std::move(response);
145   }
146 
147   if (request.relative_url == kEchoAllHeadersPath) {
148     response->set_content(request.all_headers);
149     return std::move(response);
150   }
151 
152   if (request.relative_url == kEchoMethodPath) {
153     response->set_content(request.method_string);
154     return std::move(response);
155   }
156 
157   if (request.relative_url == kRedirectToEchoBodyPath) {
158     response->set_code(net::HTTP_TEMPORARY_REDIRECT);
159     response->AddCustomHeader("Location", kEchoBodyPath);
160     return std::move(response);
161   }
162 
163   // Unhandled requests result in the Embedded test server sending a 404.
164   return nullptr;
165 }
166 
167 }  // namespace
168 
169 namespace cronet {
170 
171 /* static */
StartServeFilesFromDirectory(const base::FilePath & test_files_root)172 bool TestServer::StartServeFilesFromDirectory(
173     const base::FilePath& test_files_root) {
174   // Shouldn't happen.
175   if (g_test_server)
176     return false;
177 
178   g_test_server = std::make_unique<net::EmbeddedTestServer>(
179       net::EmbeddedTestServer::TYPE_HTTP);
180   g_test_server->RegisterRequestHandler(
181       base::BindRepeating(&CronetTestRequestHandler));
182   g_test_server->ServeFilesFromDirectory(test_files_root);
183   net::test_server::RegisterDefaultHandlers(g_test_server.get());
184   CHECK(g_test_server->Start());
185   return true;
186 }
187 
188 /* static */
Start()189 bool TestServer::Start() {
190   base::FilePath src_root;
191   CHECK(base::PathService::Get(base::DIR_SOURCE_ROOT, &src_root));
192   return StartServeFilesFromDirectory(src_root.Append(kTestDataRelativePath));
193 }
194 
195 /* static */
Shutdown()196 void TestServer::Shutdown() {
197   if (!g_test_server)
198     return;
199   g_test_server.reset();
200 }
201 
202 /* static */
GetPort()203 int TestServer::GetPort() {
204   DCHECK(g_test_server);
205   return g_test_server->port();
206 }
207 
208 /* static */
GetHostPort()209 std::string TestServer::GetHostPort() {
210   DCHECK(g_test_server);
211   return net::HostPortPair::FromURL(g_test_server->base_url()).ToString();
212 }
213 
214 /* static */
GetSimpleURL()215 std::string TestServer::GetSimpleURL() {
216   return GetFileURL(kSimplePath);
217 }
218 
219 /* static */
GetEchoMethodURL()220 std::string TestServer::GetEchoMethodURL() {
221   return GetFileURL(kEchoMethodPath);
222 }
223 
224 /* static */
GetEchoHeaderURL(const std::string & header_name)225 std::string TestServer::GetEchoHeaderURL(const std::string& header_name) {
226   return GetFileURL(kEchoHeaderPath + header_name);
227 }
228 
229 /* static */
GetUseEncodingURL(const std::string & encoding_name)230 std::string TestServer::GetUseEncodingURL(const std::string& encoding_name) {
231   return GetFileURL(kUseEncodingPath + encoding_name);
232 }
233 
234 /* static */
GetSetCookieURL(const std::string & cookie_line)235 std::string TestServer::GetSetCookieURL(const std::string& cookie_line) {
236   return GetFileURL(kSetCookiePath + cookie_line);
237 }
238 
239 /* static */
GetEchoAllHeadersURL()240 std::string TestServer::GetEchoAllHeadersURL() {
241   return GetFileURL(kEchoAllHeadersPath);
242 }
243 
244 /* static */
GetEchoRequestBodyURL()245 std::string TestServer::GetEchoRequestBodyURL() {
246   return GetFileURL(kEchoBodyPath);
247 }
248 
249 /* static */
GetRedirectToEchoBodyURL()250 std::string TestServer::GetRedirectToEchoBodyURL() {
251   return GetFileURL(kRedirectToEchoBodyPath);
252 }
253 
254 /* static */
GetExabyteResponseURL()255 std::string TestServer::GetExabyteResponseURL() {
256   return GetFileURL("/exabyte_response");
257 }
258 
259 /* static */
PrepareBigDataURL(size_t data_size)260 std::string TestServer::PrepareBigDataURL(size_t data_size) {
261   DCHECK(g_test_server);
262   DCHECK(g_big_data_body.Get().empty());
263   // Response line with headers.
264   std::string response_builder;
265   base::StringAppendF(&response_builder, "HTTP/1.1 200 OK\r\n");
266   base::StringAppendF(&response_builder, "Content-Length: %" PRIuS "\r\n",
267                       data_size);
268   base::StringAppendF(&response_builder, "\r\n");
269   response_builder += std::string(data_size, 'c');
270   g_big_data_body.Get() = response_builder;
271   return g_test_server
272       ->GetURL(kBigDataPath + base::NumberToString(response_builder.size()))
273       .spec();
274 }
275 
276 /* static */
ReleaseBigDataURL()277 void TestServer::ReleaseBigDataURL() {
278   DCHECK(!g_big_data_body.Get().empty());
279   g_big_data_body.Get() = std::string();
280 }
281 
282 /* static */
GetFileURL(const std::string & file_path)283 std::string TestServer::GetFileURL(const std::string& file_path) {
284   DCHECK(g_test_server);
285   return g_test_server->GetURL(file_path).spec();
286 }
287 
288 }  // namespace cronet
289