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"
10 #include "base/files/file_util.h"
11 #include "base/files/scoped_file.h"
12 #include "base/logging.h"
13 #include "base/single_thread_task_runner.h"
14 #include "base/values.h"
15 #include "components/cronet/url_request_context_config.h"
16 #include "jni/CronetUrlRequestContext_jni.h"
17 #include "net/base/load_flags.h"
18 #include "net/base/net_errors.h"
19 #include "net/base/network_delegate_impl.h"
20 #include "net/http/http_auth_handler_factory.h"
21 #include "net/log/write_to_file_net_log_observer.h"
22 #include "net/proxy/proxy_service.h"
23 #include "net/sdch/sdch_owner.h"
24 #include "net/url_request/url_request_context.h"
25 #include "net/url_request/url_request_context_builder.h"
29 class BasicNetworkDelegate
: public net::NetworkDelegateImpl
{
31 BasicNetworkDelegate() {}
32 ~BasicNetworkDelegate() override
{}
35 // net::NetworkDelegate implementation.
36 int OnBeforeURLRequest(net::URLRequest
* request
,
37 const net::CompletionCallback
& callback
,
38 GURL
* new_url
) override
{
42 int OnBeforeSendHeaders(net::URLRequest
* request
,
43 const net::CompletionCallback
& callback
,
44 net::HttpRequestHeaders
* headers
) override
{
48 void OnSendHeaders(net::URLRequest
* request
,
49 const net::HttpRequestHeaders
& headers
) override
{}
51 int OnHeadersReceived(
52 net::URLRequest
* request
,
53 const net::CompletionCallback
& callback
,
54 const net::HttpResponseHeaders
* original_response_headers
,
55 scoped_refptr
<net::HttpResponseHeaders
>* _response_headers
,
56 GURL
* allowed_unsafe_redirect_url
) override
{
60 void OnBeforeRedirect(net::URLRequest
* request
,
61 const GURL
& new_location
) override
{}
63 void OnResponseStarted(net::URLRequest
* request
) override
{}
65 void OnRawBytesRead(const net::URLRequest
& request
, int bytes_read
) override
{
68 void OnCompleted(net::URLRequest
* request
, bool started
) override
{}
70 void OnURLRequestDestroyed(net::URLRequest
* request
) override
{}
72 void OnPACScriptError(int line_number
, const base::string16
& error
) override
{
75 NetworkDelegate::AuthRequiredResponse
OnAuthRequired(
76 net::URLRequest
* request
,
77 const net::AuthChallengeInfo
& auth_info
,
78 const AuthCallback
& callback
,
79 net::AuthCredentials
* credentials
) override
{
80 return net::NetworkDelegate::AUTH_REQUIRED_RESPONSE_NO_ACTION
;
83 bool OnCanGetCookies(const net::URLRequest
& request
,
84 const net::CookieList
& cookie_list
) override
{
88 bool OnCanSetCookie(const net::URLRequest
& request
,
89 const std::string
& cookie_line
,
90 net::CookieOptions
* options
) override
{
94 bool OnCanAccessFile(const net::URLRequest
& request
,
95 const base::FilePath
& path
) const override
{
99 bool OnCanThrottleRequest(const net::URLRequest
& request
) const override
{
103 DISALLOW_COPY_AND_ASSIGN(BasicNetworkDelegate
);
110 // Explicitly register static JNI functions.
111 bool CronetUrlRequestContextAdapterRegisterJni(JNIEnv
* env
) {
112 return RegisterNativesImpl(env
);
115 CronetURLRequestContextAdapter::CronetURLRequestContextAdapter(
116 scoped_ptr
<URLRequestContextConfig
> context_config
)
117 : network_thread_(new base::Thread("network")),
118 context_config_(context_config
.Pass()),
119 is_context_initialized_(false),
120 default_load_flags_(net::LOAD_NORMAL
) {
121 base::Thread::Options options
;
122 options
.message_loop_type
= base::MessageLoop::TYPE_IO
;
123 network_thread_
->StartWithOptions(options
);
126 CronetURLRequestContextAdapter::~CronetURLRequestContextAdapter() {
127 DCHECK(GetNetworkTaskRunner()->BelongsToCurrentThread());
128 StopNetLogOnNetworkThread();
131 void CronetURLRequestContextAdapter::InitRequestContextOnMainThread(
134 base::android::ScopedJavaGlobalRef
<jobject
> jcaller_ref
;
135 jcaller_ref
.Reset(env
, jcaller
);
136 proxy_config_service_
.reset(net::ProxyService::CreateSystemProxyConfigService(
137 GetNetworkTaskRunner(), nullptr));
138 GetNetworkTaskRunner()->PostTask(
140 base::Bind(&CronetURLRequestContextAdapter::InitializeOnNetworkThread
,
141 base::Unretained(this), Passed(&context_config_
),
145 void CronetURLRequestContextAdapter::InitializeOnNetworkThread(
146 scoped_ptr
<URLRequestContextConfig
> config
,
147 const base::android::ScopedJavaGlobalRef
<jobject
>&
148 jcronet_url_request_context
) {
149 DCHECK(GetNetworkTaskRunner()->BelongsToCurrentThread());
150 DCHECK(!is_context_initialized_
);
151 DCHECK(proxy_config_service_
);
152 // TODO(mmenke): Add method to have the builder enable SPDY.
153 net::URLRequestContextBuilder context_builder
;
154 context_builder
.set_network_delegate(new BasicNetworkDelegate());
155 context_builder
.set_proxy_config_service(proxy_config_service_
.release());
156 config
->ConfigureURLRequestContextBuilder(&context_builder
);
158 context_
.reset(context_builder
.Build());
160 default_load_flags_
= net::LOAD_DO_NOT_SAVE_COOKIES
|
161 net::LOAD_DO_NOT_SEND_COOKIES
;
162 if (config
->load_disable_cache
)
163 default_load_flags_
|= net::LOAD_DISABLE_CACHE
;
165 if (config
->enable_sdch
) {
166 DCHECK(context_
->sdch_manager());
168 new net::SdchOwner(context_
->sdch_manager(), context_
.get()));
171 // Currently (circa M39) enabling QUIC requires setting probability threshold.
172 if (config
->enable_quic
) {
173 context_
->http_server_properties()
174 ->SetAlternativeServiceProbabilityThreshold(0.0f
);
175 for (auto hint
= config
->quic_hints
.begin();
176 hint
!= config
->quic_hints
.end(); ++hint
) {
177 const URLRequestContextConfig::QuicHint
& quic_hint
= **hint
;
178 if (quic_hint
.host
.empty()) {
179 LOG(ERROR
) << "Empty QUIC hint host: " << quic_hint
.host
;
183 url::CanonHostInfo host_info
;
184 std::string
canon_host(net::CanonicalizeHost(quic_hint
.host
, &host_info
));
185 if (!host_info
.IsIPAddress() &&
186 !net::IsCanonicalizedHostCompliant(canon_host
)) {
187 LOG(ERROR
) << "Invalid QUIC hint host: " << quic_hint
.host
;
191 if (quic_hint
.port
<= std::numeric_limits
<uint16
>::min() ||
192 quic_hint
.port
> std::numeric_limits
<uint16
>::max()) {
193 LOG(ERROR
) << "Invalid QUIC hint port: "
198 if (quic_hint
.alternate_port
<= std::numeric_limits
<uint16
>::min() ||
199 quic_hint
.alternate_port
> std::numeric_limits
<uint16
>::max()) {
200 LOG(ERROR
) << "Invalid QUIC hint alternate port: "
201 << quic_hint
.alternate_port
;
205 net::HostPortPair
quic_hint_host_port_pair(canon_host
,
207 net::AlternativeService
alternative_service(
208 net::AlternateProtocol::QUIC
, "",
209 static_cast<uint16
>(quic_hint
.alternate_port
));
210 context_
->http_server_properties()->SetAlternativeService(
211 quic_hint_host_port_pair
, alternative_service
, 1.0f
);
215 JNIEnv
* env
= base::android::AttachCurrentThread();
216 Java_CronetUrlRequestContext_initNetworkThread(
217 env
, jcronet_url_request_context
.obj());
219 is_context_initialized_
= true;
220 while (!tasks_waiting_for_context_
.empty()) {
221 tasks_waiting_for_context_
.front().Run();
222 tasks_waiting_for_context_
.pop();
226 void CronetURLRequestContextAdapter::Destroy(JNIEnv
* env
, jobject jcaller
) {
227 DCHECK(!GetNetworkTaskRunner()->BelongsToCurrentThread());
228 // Stick network_thread_ in a local, as |this| may be destroyed from the
229 // network thread before delete network_thread is called.
230 base::Thread
* network_thread
= network_thread_
;
231 GetNetworkTaskRunner()->DeleteSoon(FROM_HERE
, this);
232 // Deleting thread stops it after all tasks are completed.
233 delete network_thread
;
236 net::URLRequestContext
* CronetURLRequestContextAdapter::GetURLRequestContext() {
238 LOG(ERROR
) << "URLRequestContext is not set up";
240 return context_
.get();
243 void CronetURLRequestContextAdapter::PostTaskToNetworkThread(
244 const tracked_objects::Location
& posted_from
,
245 const base::Closure
& callback
) {
246 GetNetworkTaskRunner()->PostTask(
247 posted_from
, base::Bind(&CronetURLRequestContextAdapter::
248 RunTaskAfterContextInitOnNetworkThread
,
249 base::Unretained(this), callback
));
252 void CronetURLRequestContextAdapter::RunTaskAfterContextInitOnNetworkThread(
253 const base::Closure
& task_to_run_after_context_init
) {
254 DCHECK(GetNetworkTaskRunner()->BelongsToCurrentThread());
255 if (is_context_initialized_
) {
256 DCHECK(tasks_waiting_for_context_
.empty());
257 task_to_run_after_context_init
.Run();
260 tasks_waiting_for_context_
.push(task_to_run_after_context_init
);
263 bool CronetURLRequestContextAdapter::IsOnNetworkThread() const {
264 return GetNetworkTaskRunner()->BelongsToCurrentThread();
267 scoped_refptr
<base::SingleThreadTaskRunner
>
268 CronetURLRequestContextAdapter::GetNetworkTaskRunner() const {
269 return network_thread_
->task_runner();
272 void CronetURLRequestContextAdapter::StartNetLogToFile(JNIEnv
* env
,
276 PostTaskToNetworkThread(
279 &CronetURLRequestContextAdapter::StartNetLogToFileOnNetworkThread
,
280 base::Unretained(this),
281 base::android::ConvertJavaStringToUTF8(env
, jfile_name
), jlog_all
));
284 void CronetURLRequestContextAdapter::StopNetLog(JNIEnv
* env
, jobject jcaller
) {
285 PostTaskToNetworkThread(
287 base::Bind(&CronetURLRequestContextAdapter::StopNetLogOnNetworkThread
,
288 base::Unretained(this)));
291 void CronetURLRequestContextAdapter::StartNetLogToFileOnNetworkThread(
292 const std::string
& file_name
, bool log_all
) {
293 DCHECK(GetNetworkTaskRunner()->BelongsToCurrentThread());
294 DCHECK(is_context_initialized_
);
296 // Do nothing if already logging to a file.
297 if (write_to_file_observer_
)
299 base::FilePath
file_path(file_name
);
300 base::ScopedFILE
file(base::OpenFile(file_path
, "w"));
304 write_to_file_observer_
.reset(new net::WriteToFileNetLogObserver());
306 write_to_file_observer_
->set_capture_mode(
307 net::NetLogCaptureMode::IncludeSocketBytes());
309 write_to_file_observer_
->StartObserving(context_
->net_log(), file
.Pass(),
310 nullptr, context_
.get());
313 void CronetURLRequestContextAdapter::StopNetLogOnNetworkThread() {
314 DCHECK(GetNetworkTaskRunner()->BelongsToCurrentThread());
315 if (write_to_file_observer_
) {
316 write_to_file_observer_
->StopObserving(context_
.get());
317 write_to_file_observer_
.reset();
321 // Creates RequestContextAdater if config is valid URLRequestContextConfig,
322 // returns 0 otherwise.
323 static jlong
CreateRequestContextAdapter(JNIEnv
* env
,
326 std::string config_string
=
327 base::android::ConvertJavaStringToUTF8(env
, jconfig
);
328 scoped_ptr
<URLRequestContextConfig
> context_config(
329 new URLRequestContextConfig());
330 if (!context_config
->LoadFromJSON(config_string
))
333 CronetURLRequestContextAdapter
* context_adapter
=
334 new CronetURLRequestContextAdapter(context_config
.Pass());
335 return reinterpret_cast<jlong
>(context_adapter
);
338 static jint
SetMinLogLevel(JNIEnv
* env
, jclass jcaller
, jint jlog_level
) {
339 jint old_log_level
= static_cast<jint
>(logging::GetMinLogLevel());
340 // MinLogLevel is global, shared by all URLRequestContexts.
341 logging::SetMinLogLevel(static_cast<int>(jlog_level
));
342 return old_log_level
;
345 } // namespace cronet