Upstream version 8.37.183.0
[platform/framework/web/crosswalk.git] / src / xwalk / runtime / browser / android / xwalk_contents_io_thread_client_impl.cc
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.
4
5 #include "xwalk/runtime/browser/android/xwalk_contents_io_thread_client_impl.h"
6
7 #include <map>
8 #include <string>
9 #include <utility>
10
11 #include "base/android/jni_string.h"
12 #include "base/android/jni_weak_ref.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_frame_host.h"
19 #include "content/public/browser/render_process_host.h"
20 #include "content/public/browser/render_view_host.h"
21 #include "content/public/browser/resource_request_info.h"
22 #include "content/public/browser/web_contents.h"
23 #include "content/public/browser/web_contents_observer.h"
24 #include "jni/XWalkContentsIoThreadClient_jni.h"
25 #include "net/url_request/url_request.h"
26 #include "url/gurl.h"
27 #include "xwalk/runtime/browser/android/intercepted_request_data_impl.h"
28
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;
37 using std::map;
38 using std::pair;
39
40 namespace xwalk {
41
42 namespace {
43
44 struct IoThreadClientData {
45   bool pending_association;
46   JavaObjectWeakGlobalRef io_thread_client;
47
48   IoThreadClientData();
49 };
50
51 IoThreadClientData::IoThreadClientData() : pending_association(false) {}
52
53 typedef map<pair<int, int>, IoThreadClientData>
54     RenderFrameHostToIoThreadClientType;
55
56 static pair<int, int> GetRenderFrameHostIdPair(RenderFrameHost* rfh) {
57   return pair<int, int>(rfh->GetProcess()->GetID(), rfh->GetRoutingID());
58 }
59
60 // RfhToIoThreadClientMap -----------------------------------------------------
61 class RfhToIoThreadClientMap {
62  public:
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);
67
68  private:
69   static LazyInstance<RfhToIoThreadClientMap> g_instance_;
70   base::Lock map_lock_;
71   RenderFrameHostToIoThreadClientType rfh_to_io_thread_client_;
72 };
73
74 // static
75 LazyInstance<RfhToIoThreadClientMap> RfhToIoThreadClientMap::g_instance_ =
76     LAZY_INSTANCE_INITIALIZER;
77
78 // static
79 RfhToIoThreadClientMap* RfhToIoThreadClientMap::GetInstance() {
80   return g_instance_.Pointer();
81 }
82
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;
87 }
88
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())
95     return false;
96
97   *client = iterator->second;
98   return true;
99 }
100
101 void RfhToIoThreadClientMap::Erase(pair<int, int> rfh_id) {
102   base::AutoLock lock(map_lock_);
103   rfh_to_io_thread_client_.erase(rfh_id);
104 }
105
106 // ClientMapEntryUpdater ------------------------------------------------------
107
108 class ClientMapEntryUpdater : public content::WebContentsObserver {
109  public:
110   ClientMapEntryUpdater(JNIEnv* env, WebContents* web_contents,
111                         jobject jdelegate);
112
113   virtual void RenderFrameCreated(RenderFrameHost* render_frame_host) OVERRIDE;
114   virtual void RenderFrameDeleted(RenderFrameHost* render_frame_host) OVERRIDE;
115   virtual void WebContentsDestroyed() OVERRIDE;
116
117  private:
118   JavaObjectWeakGlobalRef jdelegate_;
119 };
120
121 ClientMapEntryUpdater::ClientMapEntryUpdater(JNIEnv* env,
122                                              WebContents* web_contents,
123                                              jobject jdelegate)
124     : content::WebContentsObserver(web_contents),
125       jdelegate_(env, jdelegate) {
126   DCHECK(web_contents);
127   DCHECK(jdelegate);
128
129   if (web_contents->GetMainFrame())
130     RenderFrameCreated(web_contents->GetMainFrame());
131 }
132
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);
139 }
140
141
142 void ClientMapEntryUpdater::RenderFrameDeleted(RenderFrameHost* rfh) {
143   RfhToIoThreadClientMap::GetInstance()->Erase(GetRenderFrameHostIdPair(rfh));
144 }
145
146 void ClientMapEntryUpdater::WebContentsDestroyed() {
147   delete this;
148 }
149
150 }  // namespace
151
152 // XWalkContentsIoThreadClientImpl -------------------------------------------
153
154 // static
155 scoped_ptr<XWalkContentsIoThreadClient>
156 XWalkContentsIoThreadClient::FromID(int render_process_id,
157                                     int render_frame_id) {
158   pair<int, int> rfh_id(render_process_id, render_frame_id);
159   IoThreadClientData client_data;
160   if (!RfhToIoThreadClientMap::GetInstance()->Get(rfh_id, &client_data))
161     return scoped_ptr<XWalkContentsIoThreadClient>();
162
163   JNIEnv* env = AttachCurrentThread();
164   ScopedJavaLocalRef<jobject> java_delegate =
165       client_data.io_thread_client.get(env);
166   DCHECK(!client_data.pending_association || java_delegate.is_null());
167   return scoped_ptr<XWalkContentsIoThreadClient>(
168       new XWalkContentsIoThreadClientImpl(
169           client_data.pending_association, java_delegate));
170 }
171
172 // static
173 void XWalkContentsIoThreadClient::SubFrameCreated(int render_process_id,
174                                                   int parent_render_frame_id,
175                                                   int child_render_frame_id) {
176   pair<int, int> parent_rfh_id(render_process_id, parent_render_frame_id);
177   pair<int, int> child_rfh_id(render_process_id, child_render_frame_id);
178   IoThreadClientData client_data;
179   if (!RfhToIoThreadClientMap::GetInstance()->Get(parent_rfh_id,
180                                                   &client_data)) {
181     NOTREACHED();
182     return;
183   }
184
185   RfhToIoThreadClientMap::GetInstance()->Set(child_rfh_id, client_data);
186 }
187
188
189 // static
190 void XWalkContentsIoThreadClientImpl::RegisterPendingContents(
191     WebContents* web_contents) {
192   IoThreadClientData client_data;
193   client_data.pending_association = true;
194   RfhToIoThreadClientMap::GetInstance()->Set(
195       GetRenderFrameHostIdPair(web_contents->GetMainFrame()), client_data);
196 }
197
198 // static
199 void XWalkContentsIoThreadClientImpl::Associate(
200     WebContents* web_contents,
201     const JavaRef<jobject>& jclient) {
202   JNIEnv* env = AttachCurrentThread();
203   // The ClientMapEntryUpdater lifespan is tied to the WebContents.
204   new ClientMapEntryUpdater(env, web_contents, jclient.obj());
205 }
206
207 XWalkContentsIoThreadClientImpl::XWalkContentsIoThreadClientImpl(
208     bool pending_association,
209     const JavaRef<jobject>& obj)
210   : pending_association_(pending_association),
211     java_object_(obj) {
212 }
213
214 XWalkContentsIoThreadClientImpl::~XWalkContentsIoThreadClientImpl() {
215   // explict, out-of-line destructor.
216 }
217
218 bool XWalkContentsIoThreadClientImpl::PendingAssociation() const {
219   return pending_association_;
220 }
221
222 XWalkContentsIoThreadClient::CacheMode
223 XWalkContentsIoThreadClientImpl::GetCacheMode() const {
224   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
225   if (java_object_.is_null())
226     return XWalkContentsIoThreadClient::LOAD_DEFAULT;
227
228   JNIEnv* env = AttachCurrentThread();
229   return static_cast<XWalkContentsIoThreadClient::CacheMode>(
230       Java_XWalkContentsIoThreadClient_getCacheMode(
231           env, java_object_.obj()));
232 }
233
234 scoped_ptr<InterceptedRequestData>
235 XWalkContentsIoThreadClientImpl::ShouldInterceptRequest(
236     const GURL& location,
237     const net::URLRequest* request) {
238   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
239   if (java_object_.is_null())
240     return scoped_ptr<InterceptedRequestData>();
241   const content::ResourceRequestInfo* info =
242       content::ResourceRequestInfo::ForRequest(request);
243   bool is_main_frame = info &&
244       info->GetResourceType() == ResourceType::MAIN_FRAME;
245
246   JNIEnv* env = AttachCurrentThread();
247   ScopedJavaLocalRef<jstring> jstring_url =
248       ConvertUTF8ToJavaString(env, location.spec());
249   ScopedJavaLocalRef<jobject> ret =
250       Java_XWalkContentsIoThreadClient_shouldInterceptRequest(
251           env, java_object_.obj(), jstring_url.obj(), is_main_frame);
252   if (ret.is_null())
253     return scoped_ptr<InterceptedRequestData>();
254   return scoped_ptr<InterceptedRequestData>(
255       new InterceptedRequestDataImpl(ret));
256 }
257
258 bool XWalkContentsIoThreadClientImpl::ShouldBlockContentUrls() const {
259   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
260   if (java_object_.is_null())
261     return false;
262
263   JNIEnv* env = AttachCurrentThread();
264   return Java_XWalkContentsIoThreadClient_shouldBlockContentUrls(
265       env, java_object_.obj());
266 }
267
268 bool XWalkContentsIoThreadClientImpl::ShouldBlockFileUrls() const {
269   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
270   if (java_object_.is_null())
271     return false;
272
273   JNIEnv* env = AttachCurrentThread();
274   return Java_XWalkContentsIoThreadClient_shouldBlockFileUrls(
275       env, java_object_.obj());
276 }
277
278 bool XWalkContentsIoThreadClientImpl::ShouldBlockNetworkLoads() const {
279   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
280   if (java_object_.is_null())
281     return false;
282
283   JNIEnv* env = AttachCurrentThread();
284   return Java_XWalkContentsIoThreadClient_shouldBlockNetworkLoads(
285       env, java_object_.obj());
286 }
287
288 void XWalkContentsIoThreadClientImpl::NewDownload(
289     const GURL& url,
290     const std::string& user_agent,
291     const std::string& content_disposition,
292     const std::string& mime_type,
293     int64 content_length) {
294   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
295   if (java_object_.is_null())
296     return;
297
298   JNIEnv* env = AttachCurrentThread();
299   ScopedJavaLocalRef<jstring> jstring_url =
300       ConvertUTF8ToJavaString(env, url.spec());
301   ScopedJavaLocalRef<jstring> jstring_user_agent =
302       ConvertUTF8ToJavaString(env, user_agent);
303   ScopedJavaLocalRef<jstring> jstring_content_disposition =
304       ConvertUTF8ToJavaString(env, content_disposition);
305   ScopedJavaLocalRef<jstring> jstring_mime_type =
306       ConvertUTF8ToJavaString(env, mime_type);
307
308   Java_XWalkContentsIoThreadClient_onDownloadStart(
309       env,
310       java_object_.obj(),
311       jstring_url.obj(),
312       jstring_user_agent.obj(),
313       jstring_content_disposition.obj(),
314       jstring_mime_type.obj(),
315       content_length);
316 }
317
318 void XWalkContentsIoThreadClientImpl::NewLoginRequest(
319     const std::string& realm,
320     const std::string& account,
321     const std::string& args) {
322   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
323   if (java_object_.is_null())
324     return;
325
326   JNIEnv* env = AttachCurrentThread();
327   ScopedJavaLocalRef<jstring> jrealm = ConvertUTF8ToJavaString(env, realm);
328   ScopedJavaLocalRef<jstring> jargs = ConvertUTF8ToJavaString(env, args);
329
330   ScopedJavaLocalRef<jstring> jaccount;
331   if (!account.empty())
332     jaccount = ConvertUTF8ToJavaString(env, account);
333
334   Java_XWalkContentsIoThreadClient_newLoginRequest(
335       env, java_object_.obj(), jrealm.obj(), jaccount.obj(), jargs.obj());
336 }
337
338 bool RegisterXWalkContentsIoThreadClientImpl(JNIEnv* env) {
339   return RegisterNativesImpl(env);
340 }
341
342 }  // namespace xwalk