- add third_party src.
[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_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"
25 #include "url/gurl.h"
26 #include "xwalk/runtime/browser/android/intercepted_request_data_impl.h"
27
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;
36 using std::map;
37 using std::pair;
38
39 namespace xwalk {
40
41 namespace {
42
43 struct IoThreadClientData {
44   bool pending_association;
45   JavaObjectWeakGlobalRef io_thread_client;
46
47   IoThreadClientData();
48 };
49
50 IoThreadClientData::IoThreadClientData() : pending_association(false) {}
51
52 typedef map<pair<int, int>, IoThreadClientData>
53     RenderViewHostToIoThreadClientType;
54
55 static pair<int, int> GetRenderViewHostIdPair(RenderViewHost* rvh) {
56   return pair<int, int>(rvh->GetProcess()->GetID(), rvh->GetRoutingID());
57 }
58
59 // RvhToIoThreadClientMap -----------------------------------------------------
60 class RvhToIoThreadClientMap {
61  public:
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);
66
67  private:
68   static LazyInstance<RvhToIoThreadClientMap> g_instance_;
69   base::Lock map_lock_;
70   RenderViewHostToIoThreadClientType rvh_to_io_thread_client_;
71 };
72
73 // static
74 LazyInstance<RvhToIoThreadClientMap> RvhToIoThreadClientMap::g_instance_ =
75     LAZY_INSTANCE_INITIALIZER;
76
77 // static
78 RvhToIoThreadClientMap* RvhToIoThreadClientMap::GetInstance() {
79   return g_instance_.Pointer();
80 }
81
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;
86 }
87
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())
94     return false;
95
96   *client = iterator->second;
97   return true;
98 }
99
100 void RvhToIoThreadClientMap::Erase(pair<int, int> rvh_id) {
101   base::AutoLock lock(map_lock_);
102   rvh_to_io_thread_client_.erase(rvh_id);
103 }
104
105 // ClientMapEntryUpdater ------------------------------------------------------
106
107 class ClientMapEntryUpdater : public content::WebContentsObserver {
108  public:
109   ClientMapEntryUpdater(JNIEnv* env, WebContents* web_contents,
110                         jobject jdelegate);
111
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;
115
116  private:
117   JavaObjectWeakGlobalRef jdelegate_;
118 };
119
120 ClientMapEntryUpdater::ClientMapEntryUpdater(JNIEnv* env,
121                                              WebContents* web_contents,
122                                              jobject jdelegate)
123     : content::WebContentsObserver(web_contents),
124       jdelegate_(env, jdelegate) {
125   DCHECK(web_contents);
126   DCHECK(jdelegate);
127
128   if (web_contents->GetRenderViewHost())
129     RenderViewCreated(web_contents->GetRenderViewHost());
130 }
131
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);
138 }
139
140
141 void ClientMapEntryUpdater::RenderViewDeleted(RenderViewHost* rvh) {
142   RvhToIoThreadClientMap::GetInstance()->Erase(GetRenderViewHostIdPair(rvh));
143 }
144
145 void ClientMapEntryUpdater::WebContentsDestroyed(WebContents* web_contents) {
146   delete this;
147 }
148
149 }  // namespace
150
151 // XWalkContentsIoThreadClientImpl -------------------------------------------
152
153 // static
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>();
160
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));
168 }
169
170 // static
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);
177 }
178
179 // static
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());
186 }
187
188 XWalkContentsIoThreadClientImpl::XWalkContentsIoThreadClientImpl(
189     bool pending_association,
190     const JavaRef<jobject>& obj)
191   : pending_association_(pending_association),
192     java_object_(obj) {
193 }
194
195 XWalkContentsIoThreadClientImpl::~XWalkContentsIoThreadClientImpl() {
196   // explict, out-of-line destructor.
197 }
198
199 bool XWalkContentsIoThreadClientImpl::PendingAssociation() const {
200   return pending_association_;
201 }
202
203 XWalkContentsIoThreadClient::CacheMode
204 XWalkContentsIoThreadClientImpl::GetCacheMode() const {
205   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
206   if (java_object_.is_null())
207     return XWalkContentsIoThreadClient::LOAD_DEFAULT;
208
209   JNIEnv* env = AttachCurrentThread();
210   return static_cast<XWalkContentsIoThreadClient::CacheMode>(
211       Java_XWalkContentsIoThreadClient_getCacheMode(
212           env, java_object_.obj()));
213 }
214
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;
226
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);
233   if (ret.is_null())
234     return scoped_ptr<InterceptedRequestData>();
235   return scoped_ptr<InterceptedRequestData>(
236       new InterceptedRequestDataImpl(ret));
237 }
238
239 bool XWalkContentsIoThreadClientImpl::ShouldBlockContentUrls() const {
240   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
241   if (java_object_.is_null())
242     return false;
243
244   JNIEnv* env = AttachCurrentThread();
245   return Java_XWalkContentsIoThreadClient_shouldBlockContentUrls(
246       env, java_object_.obj());
247 }
248
249 bool XWalkContentsIoThreadClientImpl::ShouldBlockFileUrls() const {
250   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
251   if (java_object_.is_null())
252     return false;
253
254   JNIEnv* env = AttachCurrentThread();
255   return Java_XWalkContentsIoThreadClient_shouldBlockFileUrls(
256       env, java_object_.obj());
257 }
258
259 bool XWalkContentsIoThreadClientImpl::ShouldBlockNetworkLoads() const {
260   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
261   if (java_object_.is_null())
262     return false;
263
264   JNIEnv* env = AttachCurrentThread();
265   return Java_XWalkContentsIoThreadClient_shouldBlockNetworkLoads(
266       env, java_object_.obj());
267 }
268
269 void XWalkContentsIoThreadClientImpl::NewDownload(
270     const GURL& url,
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())
277     return;
278
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);
288
289   Java_XWalkContentsIoThreadClient_onDownloadStart(
290       env,
291       java_object_.obj(),
292       jstring_url.obj(),
293       jstring_user_agent.obj(),
294       jstring_content_disposition.obj(),
295       jstring_mime_type.obj(),
296       content_length);
297 }
298
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())
305     return;
306
307   JNIEnv* env = AttachCurrentThread();
308   ScopedJavaLocalRef<jstring> jrealm = ConvertUTF8ToJavaString(env, realm);
309   ScopedJavaLocalRef<jstring> jargs = ConvertUTF8ToJavaString(env, args);
310
311   ScopedJavaLocalRef<jstring> jaccount;
312   if (!account.empty())
313     jaccount = ConvertUTF8ToJavaString(env, account);
314
315   Java_XWalkContentsIoThreadClient_newLoginRequest(
316       env, java_object_.obj(), jrealm.obj(), jaccount.obj(), jargs.obj());
317 }
318
319 bool RegisterXWalkContentsIoThreadClientImpl(JNIEnv* env) {
320   return RegisterNativesImpl(env);
321 }
322
323 }  // namespace xwalk