Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / components / cronet / android / test / native_test_server.cc
blob5c8c6d4b8547c5c2ec887e1e07a8a3639ee3699c
1 // Copyright 2014 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 "native_test_server.h"
7 #include <string>
9 #include "base/android/jni_android.h"
10 #include "base/android/jni_string.h"
11 #include "base/android/path_utils.h"
12 #include "base/bind.h"
13 #include "base/files/file_path.h"
14 #include "base/files/file_util.h"
15 #include "base/macros.h"
16 #include "base/memory/scoped_ptr.h"
17 #include "base/path_service.h"
18 #include "base/strings/string_util.h"
19 #include "base/strings/stringprintf.h"
20 #include "components/cronet/android/cronet_url_request_context_adapter.h"
21 #include "components/cronet/android/url_request_context_adapter.h"
22 #include "jni/NativeTestServer_jni.h"
23 #include "net/base/host_port_pair.h"
24 #include "net/base/url_util.h"
25 #include "net/dns/host_resolver_impl.h"
26 #include "net/dns/mock_host_resolver.h"
27 #include "net/http/http_status_code.h"
28 #include "net/test/embedded_test_server/embedded_test_server.h"
29 #include "net/test/embedded_test_server/http_request.h"
30 #include "net/test/embedded_test_server/http_response.h"
31 #include "url/gurl.h"
33 namespace cronet {
35 namespace {
37 const char kEchoBodyPath[] = "/echo_body";
38 const char kEchoHeaderPath[] = "/echo_header";
39 const char kEchoAllHeadersPath[] = "/echo_all_headers";
40 const char kEchoMethodPath[] = "/echo_method";
41 const char kRedirectToEchoBodyPath[] = "/redirect_to_echo_body";
42 const char kFakeSdchDomain[] = "fake.sdch.domain";
43 // Path that advertises the dictionary passed in query params if client
44 // supports Sdch encoding. E.g. /sdch/index?q=LeQxM80O will make the server
45 // responds with "Get-Dictionary: /sdch/dict/LeQxM80O".
46 const char kSdchPath[] = "/sdch/index";
47 // Path that returns encoded response if client has the right dictionary.
48 const char kSdchTestPath[] = "/sdch/test";
49 // Path where dictionaries are stored.
50 const char kSdchDictPath[] = "/sdch/dict/";
52 net::test_server::EmbeddedTestServer* g_test_server = nullptr;
54 class CustomHttpResponse : public net::test_server::HttpResponse {
55 public:
56 CustomHttpResponse(const std::string& headers, const std::string& contents)
57 : headers_(headers), contents_(contents) {}
59 std::string ToResponseString() const override {
60 return headers_ + "\r\n" + contents_;
63 void AddHeader(const std::string& key_value_pair) {
64 headers_.append(base::StringPrintf("%s\r\n", key_value_pair.c_str()));
67 private:
68 std::string headers_;
69 std::string contents_;
71 DISALLOW_COPY_AND_ASSIGN(CustomHttpResponse);
74 scoped_ptr<CustomHttpResponse> ConstructResponseBasedOnFile(
75 const base::FilePath& file_path) {
76 std::string file_contents;
77 bool read_file = base::ReadFileToString(file_path, &file_contents);
78 DCHECK(read_file);
79 base::FilePath headers_path(
80 file_path.AddExtension(FILE_PATH_LITERAL("mock-http-headers")));
81 std::string headers_contents;
82 bool read_headers = base::ReadFileToString(headers_path, &headers_contents);
83 DCHECK(read_headers);
84 scoped_ptr<CustomHttpResponse> http_response(
85 new CustomHttpResponse(headers_contents, file_contents));
86 return http_response.Pass();
89 scoped_ptr<net::test_server::HttpResponse> NativeTestServerRequestHandler(
90 const net::test_server::HttpRequest& request) {
91 DCHECK(g_test_server);
92 scoped_ptr<net::test_server::BasicHttpResponse> response(
93 new net::test_server::BasicHttpResponse());
94 response->set_content_type("text/plain");
96 if (request.relative_url == kEchoBodyPath) {
97 if (request.has_content) {
98 response->set_content(request.content);
99 } else {
100 response->set_content("Request has no body. :(");
102 return response.Pass();
105 if (base::StartsWith(request.relative_url, kEchoHeaderPath,
106 base::CompareCase::SENSITIVE)) {
107 GURL url = g_test_server->GetURL(request.relative_url);
108 auto it = request.headers.find(url.query());
109 if (it != request.headers.end()) {
110 response->set_content(it->second);
111 } else {
112 response->set_content("Header not found. :(");
114 return response.Pass();
117 if (request.relative_url == kEchoAllHeadersPath) {
118 response->set_content(request.all_headers);
119 return response.Pass();
122 if (request.relative_url == kEchoMethodPath) {
123 response->set_content(request.method_string);
124 return response.Pass();
127 if (request.relative_url == kRedirectToEchoBodyPath) {
128 response->set_code(net::HTTP_TEMPORARY_REDIRECT);
129 response->AddCustomHeader("Location", kEchoBodyPath);
130 return response.Pass();
133 // Unhandled requests result in the Embedded test server sending a 404.
134 return scoped_ptr<net::test_server::BasicHttpResponse>();
137 scoped_ptr<net::test_server::HttpResponse> SdchRequestHandler(
138 const net::test_server::HttpRequest& request) {
139 DCHECK(g_test_server);
140 base::FilePath dir_path;
141 bool get_data_dir = base::android::GetDataDirectory(&dir_path);
142 DCHECK(get_data_dir);
143 dir_path = dir_path.Append(FILE_PATH_LITERAL("test"));
145 if (base::StartsWith(request.relative_url, kSdchPath,
146 base::CompareCase::SENSITIVE)) {
147 base::FilePath file_path = dir_path.Append("sdch/index");
148 scoped_ptr<CustomHttpResponse> response =
149 ConstructResponseBasedOnFile(file_path).Pass();
150 // Check for query params to see which dictionary to advertise.
151 // For instance, ?q=dictionaryA will make the server advertise dictionaryA.
152 GURL url = g_test_server->GetURL(request.relative_url);
153 std::string dictionary;
154 if (!net::GetValueForKeyInQuery(url, "q", &dictionary)) {
155 CHECK(false) << "dictionary is not found in query params of "
156 << request.relative_url;
158 auto accept_encoding_header = request.headers.find("Accept-Encoding");
159 if (accept_encoding_header != request.headers.end()) {
160 if (accept_encoding_header->second.find("sdch") != std::string::npos)
161 response->AddHeader(base::StringPrintf(
162 "Get-Dictionary: %s%s", kSdchDictPath, dictionary.c_str()));
164 return response.Pass();
167 if (base::StartsWith(request.relative_url, kSdchTestPath,
168 base::CompareCase::SENSITIVE)) {
169 auto avail_dictionary_header = request.headers.find("Avail-Dictionary");
170 if (avail_dictionary_header != request.headers.end()) {
171 base::FilePath file_path = dir_path.Append(
172 "sdch/" + avail_dictionary_header->second + "_encoded");
173 return ConstructResponseBasedOnFile(file_path).Pass();
175 scoped_ptr<net::test_server::BasicHttpResponse> response(
176 new net::test_server::BasicHttpResponse());
177 response->set_content_type("text/plain");
178 response->set_content("Sdch is not used.\n");
179 return response.Pass();
182 // Unhandled requests result in the Embedded test server sending a 404.
183 return scoped_ptr<net::test_server::BasicHttpResponse>();
186 void RegisterHostResolverProcHelper(
187 net::URLRequestContext* url_request_context) {
188 net::HostResolverImpl* resolver =
189 static_cast<net::HostResolverImpl*>(url_request_context->host_resolver());
190 scoped_refptr<net::RuleBasedHostResolverProc> proc =
191 new net::RuleBasedHostResolverProc(NULL);
192 proc->AddRule(kFakeSdchDomain, "127.0.0.1");
193 resolver->set_proc_params_for_test(
194 net::HostResolverImpl::ProcTaskParams(proc.get(), 1u));
195 JNIEnv* env = base::android::AttachCurrentThread();
196 Java_NativeTestServer_onHostResolverProcRegistered(env);
199 void RegisterHostResolverProcOnNetworkThread(
200 CronetURLRequestContextAdapter* context_adapter) {
201 RegisterHostResolverProcHelper(context_adapter->GetURLRequestContext());
204 // TODO(xunjieli): Delete this once legacy API is removed.
205 void RegisterHostResolverProcOnNetworkThreadLegacyAPI(
206 URLRequestContextAdapter* context_adapter) {
207 RegisterHostResolverProcHelper(context_adapter->GetURLRequestContext());
210 } // namespace
212 jboolean StartNativeTestServer(JNIEnv* env,
213 const JavaParamRef<jclass>& jcaller,
214 const JavaParamRef<jstring>& jtest_files_root) {
215 // Shouldn't happen.
216 if (g_test_server)
217 return false;
218 g_test_server = new net::test_server::EmbeddedTestServer();
219 g_test_server->RegisterRequestHandler(
220 base::Bind(&NativeTestServerRequestHandler));
221 g_test_server->RegisterRequestHandler(base::Bind(&SdchRequestHandler));
222 base::FilePath test_files_root(
223 base::android::ConvertJavaStringToUTF8(env, jtest_files_root));
225 // Add a third handler for paths that NativeTestServerRequestHandler does not
226 // handle.
227 g_test_server->ServeFilesFromDirectory(test_files_root);
228 return g_test_server->InitializeAndWaitUntilReady();
231 void RegisterHostResolverProc(JNIEnv* env,
232 const JavaParamRef<jclass>& jcaller,
233 jlong jadapter,
234 jboolean jlegacy_api) {
235 if (jlegacy_api == JNI_TRUE) {
236 URLRequestContextAdapter* context_adapter =
237 reinterpret_cast<URLRequestContextAdapter*>(jadapter);
238 context_adapter->PostTaskToNetworkThread(
239 FROM_HERE, base::Bind(&RegisterHostResolverProcOnNetworkThreadLegacyAPI,
240 base::Unretained(context_adapter)));
241 } else {
242 CronetURLRequestContextAdapter* context_adapter =
243 reinterpret_cast<CronetURLRequestContextAdapter*>(jadapter);
244 context_adapter->PostTaskToNetworkThread(
245 FROM_HERE, base::Bind(&RegisterHostResolverProcOnNetworkThread,
246 base::Unretained(context_adapter)));
250 void ShutdownNativeTestServer(JNIEnv* env,
251 const JavaParamRef<jclass>& jcaller) {
252 if (!g_test_server)
253 return;
254 delete g_test_server;
255 g_test_server = NULL;
258 ScopedJavaLocalRef<jstring> GetEchoBodyURL(
259 JNIEnv* env,
260 const JavaParamRef<jclass>& jcaller) {
261 DCHECK(g_test_server);
262 GURL url = g_test_server->GetURL(kEchoBodyPath);
263 return base::android::ConvertUTF8ToJavaString(env, url.spec());
266 ScopedJavaLocalRef<jstring> GetEchoHeaderURL(
267 JNIEnv* env,
268 const JavaParamRef<jclass>& jcaller,
269 const JavaParamRef<jstring>& jheader) {
270 DCHECK(g_test_server);
271 GURL url = g_test_server->GetURL(kEchoHeaderPath);
272 GURL::Replacements replacements;
273 std::string header = base::android::ConvertJavaStringToUTF8(env, jheader);
274 replacements.SetQueryStr(header.c_str());
275 url = url.ReplaceComponents(replacements);
276 return base::android::ConvertUTF8ToJavaString(env, url.spec());
279 ScopedJavaLocalRef<jstring> GetEchoAllHeadersURL(
280 JNIEnv* env,
281 const JavaParamRef<jclass>& jcaller) {
282 DCHECK(g_test_server);
283 GURL url = g_test_server->GetURL(kEchoAllHeadersPath);
284 return base::android::ConvertUTF8ToJavaString(env, url.spec());
287 ScopedJavaLocalRef<jstring> GetEchoMethodURL(
288 JNIEnv* env,
289 const JavaParamRef<jclass>& jcaller) {
290 DCHECK(g_test_server);
291 GURL url = g_test_server->GetURL(kEchoMethodPath);
292 return base::android::ConvertUTF8ToJavaString(env, url.spec());
295 ScopedJavaLocalRef<jstring> GetRedirectToEchoBody(
296 JNIEnv* env,
297 const JavaParamRef<jclass>& jcaller) {
298 DCHECK(g_test_server);
299 GURL url = g_test_server->GetURL(kRedirectToEchoBodyPath);
300 return base::android::ConvertUTF8ToJavaString(env, url.spec());
303 ScopedJavaLocalRef<jstring> GetFileURL(
304 JNIEnv* env,
305 const JavaParamRef<jclass>& jcaller,
306 const JavaParamRef<jstring>& jfile_path) {
307 DCHECK(g_test_server);
308 std::string file = base::android::ConvertJavaStringToUTF8(env, jfile_path);
309 GURL url = g_test_server->GetURL(file);
310 return base::android::ConvertUTF8ToJavaString(env, url.spec());
313 ScopedJavaLocalRef<jstring> GetSdchURL(JNIEnv* env,
314 const JavaParamRef<jclass>& jcaller) {
315 DCHECK(g_test_server);
316 std::string url(base::StringPrintf("http://%s:%d", kFakeSdchDomain,
317 g_test_server->port()));
318 return base::android::ConvertUTF8ToJavaString(env, url);
321 ScopedJavaLocalRef<jstring> GetHostPort(JNIEnv* env,
322 const JavaParamRef<jclass>& jcaller) {
323 DCHECK(g_test_server);
324 std::string host_port =
325 net::HostPortPair::FromURL(g_test_server->base_url()).ToString();
326 return base::android::ConvertUTF8ToJavaString(env, host_port);
329 jboolean IsDataReductionProxySupported(JNIEnv* env,
330 const JavaParamRef<jclass>& jcaller) {
331 #if defined(DATA_REDUCTION_PROXY_SUPPORT)
332 return JNI_TRUE;
333 #else
334 return JNI_FALSE;
335 #endif
338 bool RegisterNativeTestServer(JNIEnv* env) {
339 return RegisterNativesImpl(env);
342 } // namespace cronet