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 <memory>
6 #include "base/android/jni_android.h"
7 #include "base/android/jni_string.h"
8 #include "base/android/path_utils.h"
9 #include "base/files/file_path.h"
10 #include "base/files/file_util.h"
11 #include "base/functional/bind.h"
12 #include "base/functional/callback_forward.h"
13 #include "base/logging.h"
14 #include "base/message_loop/message_pump_type.h"
15 #include "base/strings/stringprintf.h"
16 #include "base/synchronization/waitable_event.h"
17 #include "base/test/test_support_android.h"
18 #include "base/threading/thread.h"
19 #include "components/cronet/android/cronet_test_apk_jni/QuicTestServer_jni.h"
20 #include "components/cronet/android/test/cronet_test_util.h"
21 #include "net/base/ip_address.h"
22 #include "net/base/ip_endpoint.h"
23 #include "net/quic/crypto/proof_source_chromium.h"
24 #include "net/test/test_data_directory.h"
25 #include "net/third_party/quiche/src/quiche/quic/tools/quic_memory_cache_backend.h"
26 #include "net/tools/quic/quic_simple_server.h"
27
28 using base::android::JavaParamRef;
29 using base::android::ScopedJavaLocalRef;
30
31 namespace cronet {
32
33 namespace {
34
35 static const int kServerPort = 6121;
36
37 std::unique_ptr<base::Thread> g_quic_server_thread;
38 std::unique_ptr<quic::QuicMemoryCacheBackend> g_quic_memory_cache_backend;
39 std::unique_ptr<net::QuicSimpleServer> g_quic_server;
40 base::WaitableEvent wait_for_callback(
41 base::WaitableEvent::ResetPolicy::AUTOMATIC);
42
43 template <typename T>
WrapCallbackWithSignal(base::OnceCallback<T> callback)44 base::OnceCallback<void()> WrapCallbackWithSignal(
45 base::OnceCallback<T> callback) {
46 return base::BindOnce(base::IgnoreResult(std::move(callback)))
47 .Then(base::BindOnce([] { wait_for_callback.Signal(); }));
48 }
49
50 template <typename T>
ExecuteSynchronouslyOnServerThread(base::OnceCallback<T> callback,base::Location from_here=FROM_HERE)51 void ExecuteSynchronouslyOnServerThread(base::OnceCallback<T> callback,
52 base::Location from_here = FROM_HERE) {
53 CHECK(g_quic_server_thread);
54 g_quic_server_thread->task_runner()->PostTask(
55 from_here, WrapCallbackWithSignal(std::move(callback)));
56 wait_for_callback.Wait();
57 }
58
StartOnServerThread(const base::FilePath & test_files_root,const base::FilePath & test_data_dir)59 void StartOnServerThread(const base::FilePath& test_files_root,
60 const base::FilePath& test_data_dir) {
61 CHECK(g_quic_server_thread->task_runner()->BelongsToCurrentThread());
62 CHECK(!g_quic_server);
63 CHECK(!g_quic_memory_cache_backend);
64
65 // Set up in-memory cache.
66 base::FilePath file_dir = test_files_root.Append("quic_data");
67 CHECK(base::PathExists(file_dir)) << "Quic data does not exist";
68 g_quic_memory_cache_backend =
69 std::make_unique<quic::QuicMemoryCacheBackend>();
70 g_quic_memory_cache_backend->InitializeBackend(file_dir.value());
71 quic::QuicConfig config;
72
73 // Set up server certs.
74 base::FilePath directory = test_data_dir.Append("net/data/ssl/certificates");
75 std::unique_ptr<net::ProofSourceChromium> proof_source(
76 new net::ProofSourceChromium());
77 CHECK(proof_source->Initialize(directory.Append("quic-chain.pem"),
78 directory.Append("quic-leaf-cert.key"),
79 base::FilePath()));
80 g_quic_server = std::make_unique<net::QuicSimpleServer>(
81 std::move(proof_source), config,
82 quic::QuicCryptoServerConfig::ConfigOptions(),
83 quic::AllSupportedVersions(), g_quic_memory_cache_backend.get());
84
85 // Start listening.
86 int rv = g_quic_server->Listen(
87 net::IPEndPoint(net::IPAddress::IPv4AllZeros(), kServerPort));
88 CHECK_GE(rv, 0) << "Quic server fails to start";
89 }
90
SetResponseDelayOnServerThread(const std::string & path,base::TimeDelta delay)91 void SetResponseDelayOnServerThread(const std::string& path,
92 base::TimeDelta delay) {
93 CHECK(g_quic_server_thread->task_runner()->BelongsToCurrentThread());
94 CHECK(g_quic_memory_cache_backend);
95
96 // TODO(crbug.com/40283192): Stop hardcoding server hostname.
97 CHECK(g_quic_memory_cache_backend->SetResponseDelay(
98 base::StringPrintf("%s:%d", "test.example.com", kServerPort), path,
99 quic::QuicTime::Delta::FromMicroseconds(delay.InMicroseconds())));
100 }
101
ShutdownOnServerThread()102 void ShutdownOnServerThread() {
103 CHECK(g_quic_server_thread->task_runner()->BelongsToCurrentThread());
104 CHECK(g_quic_server);
105 CHECK(g_quic_memory_cache_backend);
106 g_quic_server->Shutdown();
107 g_quic_server.reset();
108 g_quic_memory_cache_backend.reset();
109 }
110
111 } // namespace
112
113 // Quic server is currently hardcoded to run on port 6121 of the localhost on
114 // the device.
JNI_QuicTestServer_StartQuicTestServer(JNIEnv * env,const JavaParamRef<jstring> & jtest_files_root,const JavaParamRef<jstring> & jtest_data_dir)115 void JNI_QuicTestServer_StartQuicTestServer(
116 JNIEnv* env,
117 const JavaParamRef<jstring>& jtest_files_root,
118 const JavaParamRef<jstring>& jtest_data_dir) {
119 CHECK(!g_quic_server_thread);
120 base::FilePath test_data_dir(
121 base::android::ConvertJavaStringToUTF8(env, jtest_data_dir));
122 base::InitAndroidTestPaths(test_data_dir);
123 g_quic_server_thread = std::make_unique<base::Thread>("quic server thread");
124 base::Thread::Options thread_options;
125 thread_options.message_pump_type = base::MessagePumpType::IO;
126 bool started =
127 g_quic_server_thread->StartWithOptions(std::move(thread_options));
128 CHECK(started);
129 base::FilePath test_files_root(
130 base::android::ConvertJavaStringToUTF8(env, jtest_files_root));
131 ExecuteSynchronouslyOnServerThread(
132 base::BindOnce(&StartOnServerThread, test_files_root, test_data_dir));
133 }
134
JNI_QuicTestServer_ShutdownQuicTestServer(JNIEnv * env)135 void JNI_QuicTestServer_ShutdownQuicTestServer(JNIEnv* env) {
136 CHECK(!g_quic_server_thread->task_runner()->BelongsToCurrentThread());
137 ExecuteSynchronouslyOnServerThread(base::BindOnce(&ShutdownOnServerThread));
138 g_quic_server_thread.reset();
139 }
140
JNI_QuicTestServer_GetServerPort(JNIEnv * env)141 int JNI_QuicTestServer_GetServerPort(JNIEnv* env) {
142 return kServerPort;
143 }
144
JNI_QuicTestServer_DelayResponse(JNIEnv * env,const JavaParamRef<jstring> & jpath,int delayInSeconds)145 void JNI_QuicTestServer_DelayResponse(JNIEnv* env,
146 const JavaParamRef<jstring>& jpath,
147 int delayInSeconds) {
148 CHECK(!g_quic_server_thread->task_runner()->BelongsToCurrentThread());
149 std::string path = base::android::ConvertJavaStringToUTF8(env, jpath);
150 base::TimeDelta delay = base::Seconds(delayInSeconds);
151 ExecuteSynchronouslyOnServerThread(
152 base::BindOnce(&SetResponseDelayOnServerThread, path, delay));
153 }
154
155 } // namespace cronet
156