1 // Copyright (c) 2012 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 "android_webview/native/aw_contents_io_thread_client_impl.h"
10 #include "android_webview/common/devtools_instrumentation.h"
11 #include "android_webview/native/intercepted_request_data_impl.h"
12 #include "base/android/jni_string.h"
13 #include "base/android/jni_weak_ref.h"
14 #include "base/lazy_instance.h"
15 #include "base/memory/linked_ptr.h"
16 #include "base/memory/scoped_ptr.h"
17 #include "base/synchronization/lock.h"
18 #include "content/public/browser/browser_thread.h"
19 #include "content/public/browser/render_frame_host.h"
20 #include "content/public/browser/render_process_host.h"
21 #include "content/public/browser/render_view_host.h"
22 #include "content/public/browser/resource_request_info.h"
23 #include "content/public/browser/web_contents.h"
24 #include "content/public/browser/web_contents_observer.h"
25 #include "jni/AwContentsIoThreadClient_jni.h"
26 #include "net/url_request/url_request.h"
29 using base::android::AttachCurrentThread
;
30 using base::android::ConvertUTF8ToJavaString
;
31 using base::android::JavaRef
;
32 using base::android::ScopedJavaLocalRef
;
33 using base::LazyInstance
;
34 using content::BrowserThread
;
35 using content::RenderFrameHost
;
36 using content::WebContents
;
40 namespace android_webview
{
44 struct IoThreadClientData
{
45 bool pending_association
;
46 JavaObjectWeakGlobalRef io_thread_client
;
51 IoThreadClientData::IoThreadClientData() : pending_association(false) {}
53 typedef map
<pair
<int, int>, IoThreadClientData
>
54 RenderFrameHostToIoThreadClientType
;
56 static pair
<int, int> GetRenderFrameHostIdPair(RenderFrameHost
* rfh
) {
57 return pair
<int, int>(rfh
->GetProcess()->GetID(), rfh
->GetRoutingID());
60 // RfhToIoThreadClientMap -----------------------------------------------------
61 class RfhToIoThreadClientMap
{
63 static RfhToIoThreadClientMap
* GetInstance();
64 void Set(pair
<int, int> rfh_id
, const IoThreadClientData
& client
);
65 bool Get(pair
<int, int> rfh_id
, IoThreadClientData
* client
);
66 void Erase(pair
<int, int> rfh_id
);
69 static LazyInstance
<RfhToIoThreadClientMap
> g_instance_
;
71 RenderFrameHostToIoThreadClientType rfh_to_io_thread_client_
;
75 LazyInstance
<RfhToIoThreadClientMap
> RfhToIoThreadClientMap::g_instance_
=
76 LAZY_INSTANCE_INITIALIZER
;
79 RfhToIoThreadClientMap
* RfhToIoThreadClientMap::GetInstance() {
80 return g_instance_
.Pointer();
83 void RfhToIoThreadClientMap::Set(pair
<int, int> rfh_id
,
84 const IoThreadClientData
& client
) {
85 base::AutoLock
lock(map_lock_
);
86 rfh_to_io_thread_client_
[rfh_id
] = client
;
89 bool RfhToIoThreadClientMap::Get(
90 pair
<int, int> rfh_id
, IoThreadClientData
* client
) {
91 base::AutoLock
lock(map_lock_
);
92 RenderFrameHostToIoThreadClientType::iterator iterator
=
93 rfh_to_io_thread_client_
.find(rfh_id
);
94 if (iterator
== rfh_to_io_thread_client_
.end())
97 *client
= iterator
->second
;
101 void RfhToIoThreadClientMap::Erase(pair
<int, int> rfh_id
) {
102 base::AutoLock
lock(map_lock_
);
103 rfh_to_io_thread_client_
.erase(rfh_id
);
106 // ClientMapEntryUpdater ------------------------------------------------------
108 class ClientMapEntryUpdater
: public content::WebContentsObserver
{
110 ClientMapEntryUpdater(JNIEnv
* env
, WebContents
* web_contents
,
113 virtual void RenderFrameCreated(RenderFrameHost
* render_frame_host
) OVERRIDE
;
114 virtual void RenderFrameDeleted(RenderFrameHost
* render_frame_host
) OVERRIDE
;
115 virtual void WebContentsDestroyed() OVERRIDE
;
118 JavaObjectWeakGlobalRef jdelegate_
;
121 ClientMapEntryUpdater::ClientMapEntryUpdater(JNIEnv
* env
,
122 WebContents
* web_contents
,
124 : content::WebContentsObserver(web_contents
),
125 jdelegate_(env
, jdelegate
) {
126 DCHECK(web_contents
);
129 if (web_contents
->GetMainFrame())
130 RenderFrameCreated(web_contents
->GetMainFrame());
133 void ClientMapEntryUpdater::RenderFrameCreated(RenderFrameHost
* rfh
) {
134 IoThreadClientData client_data
;
135 client_data
.io_thread_client
= jdelegate_
;
136 client_data
.pending_association
= false;
137 RfhToIoThreadClientMap::GetInstance()->Set(
138 GetRenderFrameHostIdPair(rfh
), client_data
);
141 void ClientMapEntryUpdater::RenderFrameDeleted(RenderFrameHost
* rfh
) {
142 RfhToIoThreadClientMap::GetInstance()->Erase(GetRenderFrameHostIdPair(rfh
));
145 void ClientMapEntryUpdater::WebContentsDestroyed() {
151 // AwContentsIoThreadClientImpl -----------------------------------------------
154 scoped_ptr
<AwContentsIoThreadClient
>
155 AwContentsIoThreadClient::FromID(int render_process_id
, int render_frame_id
) {
156 pair
<int, int> rfh_id(render_process_id
, render_frame_id
);
157 IoThreadClientData client_data
;
158 if (!RfhToIoThreadClientMap::GetInstance()->Get(rfh_id
, &client_data
))
159 return scoped_ptr
<AwContentsIoThreadClient
>();
161 JNIEnv
* env
= AttachCurrentThread();
162 ScopedJavaLocalRef
<jobject
> java_delegate
=
163 client_data
.io_thread_client
.get(env
);
164 DCHECK(!client_data
.pending_association
|| java_delegate
.is_null());
165 return scoped_ptr
<AwContentsIoThreadClient
>(new AwContentsIoThreadClientImpl(
166 client_data
.pending_association
, java_delegate
));
170 void AwContentsIoThreadClient::SubFrameCreated(int render_process_id
,
171 int parent_render_frame_id
,
172 int child_render_frame_id
) {
173 pair
<int, int> parent_rfh_id(render_process_id
, parent_render_frame_id
);
174 pair
<int, int> child_rfh_id(render_process_id
, child_render_frame_id
);
175 IoThreadClientData client_data
;
176 if (!RfhToIoThreadClientMap::GetInstance()->Get(parent_rfh_id
,
182 RfhToIoThreadClientMap::GetInstance()->Set(child_rfh_id
, client_data
);
186 void AwContentsIoThreadClientImpl::RegisterPendingContents(
187 WebContents
* web_contents
) {
188 IoThreadClientData client_data
;
189 client_data
.pending_association
= true;
190 RfhToIoThreadClientMap::GetInstance()->Set(
191 GetRenderFrameHostIdPair(web_contents
->GetMainFrame()), client_data
);
195 void AwContentsIoThreadClientImpl::Associate(
196 WebContents
* web_contents
,
197 const JavaRef
<jobject
>& jclient
) {
198 JNIEnv
* env
= AttachCurrentThread();
199 // The ClientMapEntryUpdater lifespan is tied to the WebContents.
200 new ClientMapEntryUpdater(env
, web_contents
, jclient
.obj());
203 AwContentsIoThreadClientImpl::AwContentsIoThreadClientImpl(
204 bool pending_association
,
205 const JavaRef
<jobject
>& obj
)
206 : pending_association_(pending_association
),
210 AwContentsIoThreadClientImpl::~AwContentsIoThreadClientImpl() {
211 // explict, out-of-line destructor.
214 bool AwContentsIoThreadClientImpl::PendingAssociation() const {
215 return pending_association_
;
218 AwContentsIoThreadClient::CacheMode
219 AwContentsIoThreadClientImpl::GetCacheMode() const {
220 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
221 if (java_object_
.is_null())
222 return AwContentsIoThreadClient::LOAD_DEFAULT
;
224 JNIEnv
* env
= AttachCurrentThread();
225 return static_cast<AwContentsIoThreadClient::CacheMode
>(
226 Java_AwContentsIoThreadClient_getCacheMode(
227 env
, java_object_
.obj()));
230 scoped_ptr
<InterceptedRequestData
>
231 AwContentsIoThreadClientImpl::ShouldInterceptRequest(
232 const GURL
& location
,
233 const net::URLRequest
* request
) {
234 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
235 if (java_object_
.is_null())
236 return scoped_ptr
<InterceptedRequestData
>();
237 const content::ResourceRequestInfo
* info
=
238 content::ResourceRequestInfo::ForRequest(request
);
239 bool is_main_frame
= info
&&
240 info
->GetResourceType() == ResourceType::MAIN_FRAME
;
242 JNIEnv
* env
= AttachCurrentThread();
243 ScopedJavaLocalRef
<jstring
> jstring_url
=
244 ConvertUTF8ToJavaString(env
, location
.spec());
245 devtools_instrumentation::ScopedEmbedderCallbackTask
embedder_callback(
246 "shouldInterceptRequest");
247 ScopedJavaLocalRef
<jobject
> ret
=
248 Java_AwContentsIoThreadClient_shouldInterceptRequest(
249 env
, java_object_
.obj(), jstring_url
.obj(), is_main_frame
);
251 return scoped_ptr
<InterceptedRequestData
>();
252 return scoped_ptr
<InterceptedRequestData
>(
253 new InterceptedRequestDataImpl(ret
));
256 bool AwContentsIoThreadClientImpl::ShouldBlockContentUrls() const {
257 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
258 if (java_object_
.is_null())
261 JNIEnv
* env
= AttachCurrentThread();
262 return Java_AwContentsIoThreadClient_shouldBlockContentUrls(
263 env
, java_object_
.obj());
266 bool AwContentsIoThreadClientImpl::ShouldBlockFileUrls() const {
267 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
268 if (java_object_
.is_null())
271 JNIEnv
* env
= AttachCurrentThread();
272 return Java_AwContentsIoThreadClient_shouldBlockFileUrls(
273 env
, java_object_
.obj());
276 bool AwContentsIoThreadClientImpl::ShouldAcceptThirdPartyCookies() const {
277 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
278 if (java_object_
.is_null())
281 JNIEnv
* env
= AttachCurrentThread();
282 return Java_AwContentsIoThreadClient_shouldAcceptThirdPartyCookies(
283 env
, java_object_
.obj());
286 bool AwContentsIoThreadClientImpl::ShouldBlockNetworkLoads() const {
287 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
288 if (java_object_
.is_null())
291 JNIEnv
* env
= AttachCurrentThread();
292 return Java_AwContentsIoThreadClient_shouldBlockNetworkLoads(
293 env
, java_object_
.obj());
296 void AwContentsIoThreadClientImpl::NewDownload(
298 const std::string
& user_agent
,
299 const std::string
& content_disposition
,
300 const std::string
& mime_type
,
301 int64 content_length
) {
302 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
303 if (java_object_
.is_null())
306 JNIEnv
* env
= AttachCurrentThread();
307 ScopedJavaLocalRef
<jstring
> jstring_url
=
308 ConvertUTF8ToJavaString(env
, url
.spec());
309 ScopedJavaLocalRef
<jstring
> jstring_user_agent
=
310 ConvertUTF8ToJavaString(env
, user_agent
);
311 ScopedJavaLocalRef
<jstring
> jstring_content_disposition
=
312 ConvertUTF8ToJavaString(env
, content_disposition
);
313 ScopedJavaLocalRef
<jstring
> jstring_mime_type
=
314 ConvertUTF8ToJavaString(env
, mime_type
);
316 Java_AwContentsIoThreadClient_onDownloadStart(
320 jstring_user_agent
.obj(),
321 jstring_content_disposition
.obj(),
322 jstring_mime_type
.obj(),
326 void AwContentsIoThreadClientImpl::NewLoginRequest(const std::string
& realm
,
327 const std::string
& account
,
328 const std::string
& args
) {
329 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
330 if (java_object_
.is_null())
333 JNIEnv
* env
= AttachCurrentThread();
334 ScopedJavaLocalRef
<jstring
> jrealm
= ConvertUTF8ToJavaString(env
, realm
);
335 ScopedJavaLocalRef
<jstring
> jargs
= ConvertUTF8ToJavaString(env
, args
);
337 ScopedJavaLocalRef
<jstring
> jaccount
;
338 if (!account
.empty())
339 jaccount
= ConvertUTF8ToJavaString(env
, account
);
341 Java_AwContentsIoThreadClient_newLoginRequest(
342 env
, java_object_
.obj(), jrealm
.obj(), jaccount
.obj(), jargs
.obj());
345 bool RegisterAwContentsIoThreadClientImpl(JNIEnv
* env
) {
346 return RegisterNativesImpl(env
);
349 } // namespace android_webview