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 "xwalk/runtime/browser/android/xwalk_contents_io_thread_client_impl.h"
11 #include "base/android/jni_helper.h"
12 #include "base/android/jni_string.h"
13 #include "base/lazy_instance.h"
14 #include "base/memory/linked_ptr.h"
15 #include "base/memory/scoped_ptr.h"
16 #include "base/synchronization/lock.h"
17 #include "content/public/browser/browser_thread.h"
18 #include "content/public/browser/render_process_host.h"
19 #include "content/public/browser/render_view_host.h"
20 #include "content/public/browser/resource_request_info.h"
21 #include "content/public/browser/web_contents.h"
22 #include "content/public/browser/web_contents_observer.h"
23 #include "jni/XWalkContentsIoThreadClient_jni.h"
24 #include "net/url_request/url_request.h"
26 #include "xwalk/runtime/browser/android/intercepted_request_data_impl.h"
28 using base::android::AttachCurrentThread;
29 using base::android::ConvertUTF8ToJavaString;
30 using base::android::JavaRef;
31 using base::android::ScopedJavaLocalRef;
32 using base::LazyInstance;
33 using content::BrowserThread;
34 using content::RenderViewHost;
35 using content::WebContents;
43 struct IoThreadClientData {
44 bool pending_association;
45 JavaObjectWeakGlobalRef io_thread_client;
50 IoThreadClientData::IoThreadClientData() : pending_association(false) {}
52 typedef map<pair<int, int>, IoThreadClientData>
53 RenderViewHostToIoThreadClientType;
55 static pair<int, int> GetRenderViewHostIdPair(RenderViewHost* rvh) {
56 return pair<int, int>(rvh->GetProcess()->GetID(), rvh->GetRoutingID());
59 // RvhToIoThreadClientMap -----------------------------------------------------
60 class RvhToIoThreadClientMap {
62 static RvhToIoThreadClientMap* GetInstance();
63 void Set(pair<int, int> rvh_id, const IoThreadClientData& client);
64 bool Get(pair<int, int> rvh_id, IoThreadClientData* client);
65 void Erase(pair<int, int> rvh_id);
68 static LazyInstance<RvhToIoThreadClientMap> g_instance_;
70 RenderViewHostToIoThreadClientType rvh_to_io_thread_client_;
74 LazyInstance<RvhToIoThreadClientMap> RvhToIoThreadClientMap::g_instance_ =
75 LAZY_INSTANCE_INITIALIZER;
78 RvhToIoThreadClientMap* RvhToIoThreadClientMap::GetInstance() {
79 return g_instance_.Pointer();
82 void RvhToIoThreadClientMap::Set(pair<int, int> rvh_id,
83 const IoThreadClientData& client) {
84 base::AutoLock lock(map_lock_);
85 rvh_to_io_thread_client_[rvh_id] = client;
88 bool RvhToIoThreadClientMap::Get(
89 pair<int, int> rvh_id, IoThreadClientData* client) {
90 base::AutoLock lock(map_lock_);
91 RenderViewHostToIoThreadClientType::iterator iterator =
92 rvh_to_io_thread_client_.find(rvh_id);
93 if (iterator == rvh_to_io_thread_client_.end())
96 *client = iterator->second;
100 void RvhToIoThreadClientMap::Erase(pair<int, int> rvh_id) {
101 base::AutoLock lock(map_lock_);
102 rvh_to_io_thread_client_.erase(rvh_id);
105 // ClientMapEntryUpdater ------------------------------------------------------
107 class ClientMapEntryUpdater : public content::WebContentsObserver {
109 ClientMapEntryUpdater(JNIEnv* env, WebContents* web_contents,
112 virtual void RenderViewCreated(RenderViewHost* render_view_host) OVERRIDE;
113 virtual void RenderViewDeleted(RenderViewHost* render_view_host) OVERRIDE;
114 virtual void WebContentsDestroyed(WebContents* web_contents) OVERRIDE;
117 JavaObjectWeakGlobalRef jdelegate_;
120 ClientMapEntryUpdater::ClientMapEntryUpdater(JNIEnv* env,
121 WebContents* web_contents,
123 : content::WebContentsObserver(web_contents),
124 jdelegate_(env, jdelegate) {
125 DCHECK(web_contents);
128 if (web_contents->GetRenderViewHost())
129 RenderViewCreated(web_contents->GetRenderViewHost());
132 void ClientMapEntryUpdater::RenderViewCreated(RenderViewHost* rvh) {
133 IoThreadClientData client_data;
134 client_data.io_thread_client = jdelegate_;
135 client_data.pending_association = false;
136 RvhToIoThreadClientMap::GetInstance()->Set(
137 GetRenderViewHostIdPair(rvh), client_data);
141 void ClientMapEntryUpdater::RenderViewDeleted(RenderViewHost* rvh) {
142 RvhToIoThreadClientMap::GetInstance()->Erase(GetRenderViewHostIdPair(rvh));
145 void ClientMapEntryUpdater::WebContentsDestroyed(WebContents* web_contents) {
151 // XWalkContentsIoThreadClientImpl -------------------------------------------
154 scoped_ptr<XWalkContentsIoThreadClient>
155 XWalkContentsIoThreadClient::FromID(int render_process_id, int render_view_id) {
156 pair<int, int> rvh_id(render_process_id, render_view_id);
157 IoThreadClientData client_data;
158 if (!RvhToIoThreadClientMap::GetInstance()->Get(rvh_id, &client_data))
159 return scoped_ptr<XWalkContentsIoThreadClient>();
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<XWalkContentsIoThreadClient>(
166 new XWalkContentsIoThreadClientImpl(
167 client_data.pending_association, java_delegate));
171 void XWalkContentsIoThreadClientImpl::RegisterPendingContents(
172 WebContents* web_contents) {
173 IoThreadClientData client_data;
174 client_data.pending_association = true;
175 RvhToIoThreadClientMap::GetInstance()->Set(
176 GetRenderViewHostIdPair(web_contents->GetRenderViewHost()), client_data);
180 void XWalkContentsIoThreadClientImpl::Associate(
181 WebContents* web_contents,
182 const JavaRef<jobject>& jclient) {
183 JNIEnv* env = AttachCurrentThread();
184 // The ClientMapEntryUpdater lifespan is tied to the WebContents.
185 new ClientMapEntryUpdater(env, web_contents, jclient.obj());
188 XWalkContentsIoThreadClientImpl::XWalkContentsIoThreadClientImpl(
189 bool pending_association,
190 const JavaRef<jobject>& obj)
191 : pending_association_(pending_association),
195 XWalkContentsIoThreadClientImpl::~XWalkContentsIoThreadClientImpl() {
196 // explict, out-of-line destructor.
199 bool XWalkContentsIoThreadClientImpl::PendingAssociation() const {
200 return pending_association_;
203 XWalkContentsIoThreadClient::CacheMode
204 XWalkContentsIoThreadClientImpl::GetCacheMode() const {
205 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
206 if (java_object_.is_null())
207 return XWalkContentsIoThreadClient::LOAD_DEFAULT;
209 JNIEnv* env = AttachCurrentThread();
210 return static_cast<XWalkContentsIoThreadClient::CacheMode>(
211 Java_XWalkContentsIoThreadClient_getCacheMode(
212 env, java_object_.obj()));
215 scoped_ptr<InterceptedRequestData>
216 XWalkContentsIoThreadClientImpl::ShouldInterceptRequest(
217 const GURL& location,
218 const net::URLRequest* request) {
219 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
220 if (java_object_.is_null())
221 return scoped_ptr<InterceptedRequestData>();
222 const content::ResourceRequestInfo* info =
223 content::ResourceRequestInfo::ForRequest(request);
224 bool is_main_frame = info &&
225 info->GetResourceType() == ResourceType::MAIN_FRAME;
227 JNIEnv* env = AttachCurrentThread();
228 ScopedJavaLocalRef<jstring> jstring_url =
229 ConvertUTF8ToJavaString(env, location.spec());
230 ScopedJavaLocalRef<jobject> ret =
231 Java_XWalkContentsIoThreadClient_shouldInterceptRequest(
232 env, java_object_.obj(), jstring_url.obj(), is_main_frame);
234 return scoped_ptr<InterceptedRequestData>();
235 return scoped_ptr<InterceptedRequestData>(
236 new InterceptedRequestDataImpl(ret));
239 bool XWalkContentsIoThreadClientImpl::ShouldBlockContentUrls() const {
240 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
241 if (java_object_.is_null())
244 JNIEnv* env = AttachCurrentThread();
245 return Java_XWalkContentsIoThreadClient_shouldBlockContentUrls(
246 env, java_object_.obj());
249 bool XWalkContentsIoThreadClientImpl::ShouldBlockFileUrls() const {
250 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
251 if (java_object_.is_null())
254 JNIEnv* env = AttachCurrentThread();
255 return Java_XWalkContentsIoThreadClient_shouldBlockFileUrls(
256 env, java_object_.obj());
259 bool XWalkContentsIoThreadClientImpl::ShouldBlockNetworkLoads() const {
260 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
261 if (java_object_.is_null())
264 JNIEnv* env = AttachCurrentThread();
265 return Java_XWalkContentsIoThreadClient_shouldBlockNetworkLoads(
266 env, java_object_.obj());
269 void XWalkContentsIoThreadClientImpl::NewDownload(
271 const std::string& user_agent,
272 const std::string& content_disposition,
273 const std::string& mime_type,
274 int64 content_length) {
275 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
276 if (java_object_.is_null())
279 JNIEnv* env = AttachCurrentThread();
280 ScopedJavaLocalRef<jstring> jstring_url =
281 ConvertUTF8ToJavaString(env, url.spec());
282 ScopedJavaLocalRef<jstring> jstring_user_agent =
283 ConvertUTF8ToJavaString(env, user_agent);
284 ScopedJavaLocalRef<jstring> jstring_content_disposition =
285 ConvertUTF8ToJavaString(env, content_disposition);
286 ScopedJavaLocalRef<jstring> jstring_mime_type =
287 ConvertUTF8ToJavaString(env, mime_type);
289 Java_XWalkContentsIoThreadClient_onDownloadStart(
293 jstring_user_agent.obj(),
294 jstring_content_disposition.obj(),
295 jstring_mime_type.obj(),
299 void XWalkContentsIoThreadClientImpl::NewLoginRequest(
300 const std::string& realm,
301 const std::string& account,
302 const std::string& args) {
303 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
304 if (java_object_.is_null())
307 JNIEnv* env = AttachCurrentThread();
308 ScopedJavaLocalRef<jstring> jrealm = ConvertUTF8ToJavaString(env, realm);
309 ScopedJavaLocalRef<jstring> jargs = ConvertUTF8ToJavaString(env, args);
311 ScopedJavaLocalRef<jstring> jaccount;
312 if (!account.empty())
313 jaccount = ConvertUTF8ToJavaString(env, account);
315 Java_XWalkContentsIoThreadClient_newLoginRequest(
316 env, java_object_.obj(), jrealm.obj(), jaccount.obj(), jargs.obj());
319 bool RegisterXWalkContentsIoThreadClientImpl(JNIEnv* env) {
320 return RegisterNativesImpl(env);