Add long running gmail memory benchmark for background tab.
[chromium-blink-merge.git] / components / cronet / android / cronet_url_request_context_adapter.cc
blobcfb590b463ccf59a0a6fc8df726d02ad01f7d5ce
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 "components/cronet/android/cronet_url_request_context_adapter.h"
7 #include "base/android/jni_android.h"
8 #include "base/android/jni_string.h"
9 #include "base/bind.h"
10 #include "base/files/file_util.h"
11 #include "base/files/scoped_file.h"
12 #include "base/logging.h"
13 #include "base/memory/scoped_vector.h"
14 #include "base/message_loop/message_loop.h"
15 #include "base/prefs/pref_filter.h"
16 #include "base/prefs/pref_registry_simple.h"
17 #include "base/prefs/pref_service.h"
18 #include "base/prefs/pref_service_factory.h"
19 #include "base/single_thread_task_runner.h"
20 #include "base/time/time.h"
21 #include "base/values.h"
22 #include "components/cronet/url_request_context_config.h"
23 #include "jni/CronetUrlRequestContext_jni.h"
24 #include "net/base/load_flags.h"
25 #include "net/base/net_errors.h"
26 #include "net/base/network_delegate_impl.h"
27 #include "net/http/http_auth_handler_factory.h"
28 #include "net/http/http_server_properties_manager.h"
29 #include "net/log/write_to_file_net_log_observer.h"
30 #include "net/proxy/proxy_service.h"
31 #include "net/sdch/sdch_owner.h"
32 #include "net/url_request/url_request_context.h"
33 #include "net/url_request/url_request_context_builder.h"
34 #include "net/url_request/url_request_interceptor.h"
36 #if defined(DATA_REDUCTION_PROXY_SUPPORT)
37 #include "components/cronet/android/cronet_data_reduction_proxy.h"
38 #endif
40 namespace {
42 const char kHttpServerProperties[] = "net.http_server_properties";
44 class BasicNetworkDelegate : public net::NetworkDelegateImpl {
45 public:
46 BasicNetworkDelegate() {}
47 ~BasicNetworkDelegate() override {}
49 private:
50 // net::NetworkDelegate implementation.
51 int OnBeforeURLRequest(net::URLRequest* request,
52 const net::CompletionCallback& callback,
53 GURL* new_url) override {
54 return net::OK;
57 int OnBeforeSendHeaders(net::URLRequest* request,
58 const net::CompletionCallback& callback,
59 net::HttpRequestHeaders* headers) override {
60 return net::OK;
63 void OnSendHeaders(net::URLRequest* request,
64 const net::HttpRequestHeaders& headers) override {}
66 int OnHeadersReceived(
67 net::URLRequest* request,
68 const net::CompletionCallback& callback,
69 const net::HttpResponseHeaders* original_response_headers,
70 scoped_refptr<net::HttpResponseHeaders>* _response_headers,
71 GURL* allowed_unsafe_redirect_url) override {
72 return net::OK;
75 void OnBeforeRedirect(net::URLRequest* request,
76 const GURL& new_location) override {}
78 void OnResponseStarted(net::URLRequest* request) override {}
80 void OnRawBytesRead(const net::URLRequest& request, int bytes_read) override {
83 void OnCompleted(net::URLRequest* request, bool started) override {}
85 void OnURLRequestDestroyed(net::URLRequest* request) override {}
87 void OnPACScriptError(int line_number, const base::string16& error) override {
90 NetworkDelegate::AuthRequiredResponse OnAuthRequired(
91 net::URLRequest* request,
92 const net::AuthChallengeInfo& auth_info,
93 const AuthCallback& callback,
94 net::AuthCredentials* credentials) override {
95 return net::NetworkDelegate::AUTH_REQUIRED_RESPONSE_NO_ACTION;
98 bool OnCanGetCookies(const net::URLRequest& request,
99 const net::CookieList& cookie_list) override {
100 return false;
103 bool OnCanSetCookie(const net::URLRequest& request,
104 const std::string& cookie_line,
105 net::CookieOptions* options) override {
106 return false;
109 bool OnCanAccessFile(const net::URLRequest& request,
110 const base::FilePath& path) const override {
111 return false;
114 DISALLOW_COPY_AND_ASSIGN(BasicNetworkDelegate);
117 } // namespace
119 namespace cronet {
121 // Explicitly register static JNI functions.
122 bool CronetUrlRequestContextAdapterRegisterJni(JNIEnv* env) {
123 return RegisterNativesImpl(env);
126 CronetURLRequestContextAdapter::CronetURLRequestContextAdapter(
127 scoped_ptr<URLRequestContextConfig> context_config)
128 : network_thread_(new base::Thread("network")),
129 http_server_properties_manager_(nullptr),
130 context_config_(context_config.Pass()),
131 is_context_initialized_(false),
132 default_load_flags_(net::LOAD_NORMAL) {
133 base::Thread::Options options;
134 options.message_loop_type = base::MessageLoop::TYPE_IO;
135 network_thread_->StartWithOptions(options);
138 CronetURLRequestContextAdapter::~CronetURLRequestContextAdapter() {
139 DCHECK(GetNetworkTaskRunner()->BelongsToCurrentThread());
141 if (http_server_properties_manager_)
142 http_server_properties_manager_->ShutdownOnPrefThread();
143 if (pref_service_)
144 pref_service_->CommitPendingWrite();
145 StopNetLogOnNetworkThread();
148 void CronetURLRequestContextAdapter::InitRequestContextOnMainThread(
149 JNIEnv* env,
150 jobject jcaller) {
151 base::android::ScopedJavaGlobalRef<jobject> jcaller_ref;
152 jcaller_ref.Reset(env, jcaller);
153 proxy_config_service_.reset(net::ProxyService::CreateSystemProxyConfigService(
154 GetNetworkTaskRunner(), nullptr));
155 GetNetworkTaskRunner()->PostTask(
156 FROM_HERE,
157 base::Bind(&CronetURLRequestContextAdapter::InitializeOnNetworkThread,
158 base::Unretained(this), Passed(&context_config_),
159 jcaller_ref));
162 void CronetURLRequestContextAdapter::InitializeOnNetworkThread(
163 scoped_ptr<URLRequestContextConfig> config,
164 const base::android::ScopedJavaGlobalRef<jobject>&
165 jcronet_url_request_context) {
166 DCHECK(GetNetworkTaskRunner()->BelongsToCurrentThread());
167 DCHECK(!is_context_initialized_);
168 DCHECK(proxy_config_service_);
169 // TODO(mmenke): Add method to have the builder enable SPDY.
170 net::URLRequestContextBuilder context_builder;
172 scoped_ptr<net::NetLog> net_log(new net::NetLog);
173 scoped_ptr<net::NetworkDelegate> network_delegate(new BasicNetworkDelegate());
174 #if defined(DATA_REDUCTION_PROXY_SUPPORT)
175 DCHECK(!data_reduction_proxy_);
176 // For now, the choice to enable the data reduction proxy happens once,
177 // at initialization. It cannot be disabled thereafter.
178 if (!config->data_reduction_proxy_key.empty()) {
179 data_reduction_proxy_.reset(
180 new CronetDataReductionProxy(
181 config->data_reduction_proxy_key,
182 config->data_reduction_primary_proxy,
183 config->data_reduction_fallback_proxy,
184 config->data_reduction_secure_proxy_check_url,
185 config->user_agent,
186 GetNetworkTaskRunner(),
187 net_log.get()));
188 network_delegate =
189 data_reduction_proxy_->CreateNetworkDelegate(network_delegate.Pass());
190 ScopedVector<net::URLRequestInterceptor> interceptors;
191 interceptors.push_back(data_reduction_proxy_->CreateInterceptor());
192 context_builder.SetInterceptors(interceptors.Pass());
194 #endif // defined(DATA_REDUCTION_PROXY_SUPPORT)
195 context_builder.set_network_delegate(network_delegate.release());
196 context_builder.set_net_log(net_log.release());
197 context_builder.set_proxy_config_service(proxy_config_service_.release());
198 config->ConfigureURLRequestContextBuilder(&context_builder);
200 // Set up pref file if storage path is specified.
201 if (!config->storage_path.empty()) {
202 base::FilePath filepath(config->storage_path);
203 filepath = filepath.Append(FILE_PATH_LITERAL("local_prefs.json"));
204 json_pref_store_ = new JsonPrefStore(
205 filepath, GetFileThread()->task_runner(), scoped_ptr<PrefFilter>());
206 context_builder.SetFileTaskRunner(GetFileThread()->task_runner());
208 // Set up HttpServerPropertiesManager.
209 base::PrefServiceFactory factory;
210 factory.set_user_prefs(json_pref_store_);
211 scoped_refptr<PrefRegistrySimple> registry(new PrefRegistrySimple());
212 registry->RegisterDictionaryPref(kHttpServerProperties,
213 new base::DictionaryValue());
214 pref_service_ = factory.Create(registry.get()).Pass();
216 scoped_ptr<net::HttpServerPropertiesManager> http_server_properties_manager(
217 new net::HttpServerPropertiesManager(pref_service_.get(),
218 kHttpServerProperties,
219 GetNetworkTaskRunner()));
220 http_server_properties_manager->InitializeOnNetworkThread();
221 http_server_properties_manager_ = http_server_properties_manager.get();
222 context_builder.SetHttpServerProperties(
223 http_server_properties_manager.Pass());
226 context_.reset(context_builder.Build());
228 default_load_flags_ = net::LOAD_DO_NOT_SAVE_COOKIES |
229 net::LOAD_DO_NOT_SEND_COOKIES;
230 if (config->load_disable_cache)
231 default_load_flags_ |= net::LOAD_DISABLE_CACHE;
233 if (config->enable_sdch) {
234 DCHECK(context_->sdch_manager());
235 sdch_owner_.reset(
236 new net::SdchOwner(context_->sdch_manager(), context_.get()));
237 if (json_pref_store_)
238 sdch_owner_->EnablePersistentStorage(json_pref_store_.get());
241 // Currently (circa M39) enabling QUIC requires setting probability threshold.
242 if (config->enable_quic) {
243 context_->http_server_properties()
244 ->SetAlternativeServiceProbabilityThreshold(0.0f);
245 for (auto hint = config->quic_hints.begin();
246 hint != config->quic_hints.end(); ++hint) {
247 const URLRequestContextConfig::QuicHint& quic_hint = **hint;
248 if (quic_hint.host.empty()) {
249 LOG(ERROR) << "Empty QUIC hint host: " << quic_hint.host;
250 continue;
253 url::CanonHostInfo host_info;
254 std::string canon_host(net::CanonicalizeHost(quic_hint.host, &host_info));
255 if (!host_info.IsIPAddress() &&
256 !net::IsCanonicalizedHostCompliant(canon_host)) {
257 LOG(ERROR) << "Invalid QUIC hint host: " << quic_hint.host;
258 continue;
261 if (quic_hint.port <= std::numeric_limits<uint16>::min() ||
262 quic_hint.port > std::numeric_limits<uint16>::max()) {
263 LOG(ERROR) << "Invalid QUIC hint port: "
264 << quic_hint.port;
265 continue;
268 if (quic_hint.alternate_port <= std::numeric_limits<uint16>::min() ||
269 quic_hint.alternate_port > std::numeric_limits<uint16>::max()) {
270 LOG(ERROR) << "Invalid QUIC hint alternate port: "
271 << quic_hint.alternate_port;
272 continue;
275 net::HostPortPair quic_hint_host_port_pair(canon_host,
276 quic_hint.port);
277 net::AlternativeService alternative_service(
278 net::AlternateProtocol::QUIC, "",
279 static_cast<uint16>(quic_hint.alternate_port));
280 context_->http_server_properties()->SetAlternativeService(
281 quic_hint_host_port_pair, alternative_service, 1.0f,
282 base::Time::Max());
286 JNIEnv* env = base::android::AttachCurrentThread();
287 Java_CronetUrlRequestContext_initNetworkThread(
288 env, jcronet_url_request_context.obj());
290 #if defined(DATA_REDUCTION_PROXY_SUPPORT)
291 if (data_reduction_proxy_)
292 data_reduction_proxy_->Init(true, GetURLRequestContext());
293 #endif
294 is_context_initialized_ = true;
295 while (!tasks_waiting_for_context_.empty()) {
296 tasks_waiting_for_context_.front().Run();
297 tasks_waiting_for_context_.pop();
301 void CronetURLRequestContextAdapter::Destroy(JNIEnv* env, jobject jcaller) {
302 DCHECK(!GetNetworkTaskRunner()->BelongsToCurrentThread());
303 // Stick network_thread_ in a local, as |this| may be destroyed from the
304 // network thread before delete network_thread is called.
305 base::Thread* network_thread = network_thread_;
306 GetNetworkTaskRunner()->DeleteSoon(FROM_HERE, this);
307 // Deleting thread stops it after all tasks are completed.
308 delete network_thread;
311 net::URLRequestContext* CronetURLRequestContextAdapter::GetURLRequestContext() {
312 if (!context_) {
313 LOG(ERROR) << "URLRequestContext is not set up";
315 return context_.get();
318 void CronetURLRequestContextAdapter::PostTaskToNetworkThread(
319 const tracked_objects::Location& posted_from,
320 const base::Closure& callback) {
321 GetNetworkTaskRunner()->PostTask(
322 posted_from, base::Bind(&CronetURLRequestContextAdapter::
323 RunTaskAfterContextInitOnNetworkThread,
324 base::Unretained(this), callback));
327 void CronetURLRequestContextAdapter::RunTaskAfterContextInitOnNetworkThread(
328 const base::Closure& task_to_run_after_context_init) {
329 DCHECK(GetNetworkTaskRunner()->BelongsToCurrentThread());
330 if (is_context_initialized_) {
331 DCHECK(tasks_waiting_for_context_.empty());
332 task_to_run_after_context_init.Run();
333 return;
335 tasks_waiting_for_context_.push(task_to_run_after_context_init);
338 bool CronetURLRequestContextAdapter::IsOnNetworkThread() const {
339 return GetNetworkTaskRunner()->BelongsToCurrentThread();
342 scoped_refptr<base::SingleThreadTaskRunner>
343 CronetURLRequestContextAdapter::GetNetworkTaskRunner() const {
344 return network_thread_->task_runner();
347 void CronetURLRequestContextAdapter::StartNetLogToFile(JNIEnv* env,
348 jobject jcaller,
349 jstring jfile_name,
350 jboolean jlog_all) {
351 PostTaskToNetworkThread(
352 FROM_HERE,
353 base::Bind(
354 &CronetURLRequestContextAdapter::StartNetLogToFileOnNetworkThread,
355 base::Unretained(this),
356 base::android::ConvertJavaStringToUTF8(env, jfile_name), jlog_all));
359 void CronetURLRequestContextAdapter::StopNetLog(JNIEnv* env, jobject jcaller) {
360 PostTaskToNetworkThread(
361 FROM_HERE,
362 base::Bind(&CronetURLRequestContextAdapter::StopNetLogOnNetworkThread,
363 base::Unretained(this)));
366 void CronetURLRequestContextAdapter::StartNetLogToFileOnNetworkThread(
367 const std::string& file_name, bool log_all) {
368 DCHECK(GetNetworkTaskRunner()->BelongsToCurrentThread());
369 DCHECK(is_context_initialized_);
370 DCHECK(context_);
371 // Do nothing if already logging to a file.
372 if (write_to_file_observer_)
373 return;
374 base::FilePath file_path(file_name);
375 base::ScopedFILE file(base::OpenFile(file_path, "w"));
376 if (!file)
377 return;
379 write_to_file_observer_.reset(new net::WriteToFileNetLogObserver());
380 if (log_all) {
381 write_to_file_observer_->set_capture_mode(
382 net::NetLogCaptureMode::IncludeSocketBytes());
384 write_to_file_observer_->StartObserving(context_->net_log(), file.Pass(),
385 nullptr, context_.get());
388 void CronetURLRequestContextAdapter::StopNetLogOnNetworkThread() {
389 DCHECK(GetNetworkTaskRunner()->BelongsToCurrentThread());
390 if (write_to_file_observer_) {
391 write_to_file_observer_->StopObserving(context_.get());
392 write_to_file_observer_.reset();
396 base::Thread* CronetURLRequestContextAdapter::GetFileThread() {
397 DCHECK(GetNetworkTaskRunner()->BelongsToCurrentThread());
398 if (!file_thread_) {
399 file_thread_.reset(new base::Thread("Network File Thread"));
400 file_thread_->Start();
402 return file_thread_.get();
405 // Creates RequestContextAdater if config is valid URLRequestContextConfig,
406 // returns 0 otherwise.
407 static jlong CreateRequestContextAdapter(JNIEnv* env,
408 jclass jcaller,
409 jstring jconfig) {
410 std::string config_string =
411 base::android::ConvertJavaStringToUTF8(env, jconfig);
412 scoped_ptr<URLRequestContextConfig> context_config(
413 new URLRequestContextConfig());
414 if (!context_config->LoadFromJSON(config_string))
415 return 0;
417 CronetURLRequestContextAdapter* context_adapter =
418 new CronetURLRequestContextAdapter(context_config.Pass());
419 return reinterpret_cast<jlong>(context_adapter);
422 static jint SetMinLogLevel(JNIEnv* env, jclass jcaller, jint jlog_level) {
423 jint old_log_level = static_cast<jint>(logging::GetMinLogLevel());
424 // MinLogLevel is global, shared by all URLRequestContexts.
425 logging::SetMinLogLevel(static_cast<int>(jlog_level));
426 return old_log_level;
429 } // namespace cronet