- add sources.
[platform/framework/web/crosswalk.git] / src / android_webview / native / aw_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 "android_webview/native/aw_contents_io_thread_client_impl.h"
6
7 #include <map>
8 #include <utility>
9
10 #include "android_webview/native/intercepted_request_data_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/AwContentsIoThreadClient_jni.h"
24 #include "net/url_request/url_request.h"
25 #include "url/gurl.h"
26
27 using base::android::AttachCurrentThread;
28 using base::android::ConvertUTF8ToJavaString;
29 using base::android::JavaRef;
30 using base::android::ScopedJavaLocalRef;
31 using base::LazyInstance;
32 using content::BrowserThread;
33 using content::RenderViewHost;
34 using content::WebContents;
35 using std::map;
36 using std::pair;
37
38 namespace android_webview {
39
40 namespace {
41
42 struct IoThreadClientData {
43   bool pending_association;
44   JavaObjectWeakGlobalRef io_thread_client;
45
46   IoThreadClientData();
47 };
48
49 IoThreadClientData::IoThreadClientData() : pending_association(false) {}
50
51 typedef map<pair<int, int>, IoThreadClientData>
52     RenderViewHostToIoThreadClientType;
53
54 static pair<int, int> GetRenderViewHostIdPair(RenderViewHost* rvh) {
55   return pair<int, int>(rvh->GetProcess()->GetID(), rvh->GetRoutingID());
56 }
57
58 // RvhToIoThreadClientMap -----------------------------------------------------
59 class RvhToIoThreadClientMap {
60  public:
61   static RvhToIoThreadClientMap* GetInstance();
62   void Set(pair<int, int> rvh_id, const IoThreadClientData& client);
63   bool Get(pair<int, int> rvh_id, IoThreadClientData* client);
64   void Erase(pair<int, int> rvh_id);
65
66  private:
67   static LazyInstance<RvhToIoThreadClientMap> g_instance_;
68   base::Lock map_lock_;
69   RenderViewHostToIoThreadClientType rvh_to_io_thread_client_;
70 };
71
72 // static
73 LazyInstance<RvhToIoThreadClientMap> RvhToIoThreadClientMap::g_instance_ =
74     LAZY_INSTANCE_INITIALIZER;
75
76 // static
77 RvhToIoThreadClientMap* RvhToIoThreadClientMap::GetInstance() {
78   return g_instance_.Pointer();
79 }
80
81 void RvhToIoThreadClientMap::Set(pair<int, int> rvh_id,
82                                  const IoThreadClientData& client) {
83   base::AutoLock lock(map_lock_);
84   rvh_to_io_thread_client_[rvh_id] = client;
85 }
86
87 bool RvhToIoThreadClientMap::Get(
88     pair<int, int> rvh_id, IoThreadClientData* client) {
89   base::AutoLock lock(map_lock_);
90   RenderViewHostToIoThreadClientType::iterator iterator =
91       rvh_to_io_thread_client_.find(rvh_id);
92   if (iterator == rvh_to_io_thread_client_.end())
93     return false;
94
95   *client = iterator->second;
96   return true;
97 }
98
99 void RvhToIoThreadClientMap::Erase(pair<int, int> rvh_id) {
100   base::AutoLock lock(map_lock_);
101   rvh_to_io_thread_client_.erase(rvh_id);
102 }
103
104 // ClientMapEntryUpdater ------------------------------------------------------
105
106 class ClientMapEntryUpdater : public content::WebContentsObserver {
107  public:
108   ClientMapEntryUpdater(JNIEnv* env, WebContents* web_contents,
109                         jobject jdelegate);
110
111   virtual void RenderViewCreated(RenderViewHost* render_view_host) OVERRIDE;
112   virtual void RenderViewDeleted(RenderViewHost* render_view_host) OVERRIDE;
113   virtual void WebContentsDestroyed(WebContents* web_contents) OVERRIDE;
114
115  private:
116   JavaObjectWeakGlobalRef jdelegate_;
117 };
118
119 ClientMapEntryUpdater::ClientMapEntryUpdater(JNIEnv* env,
120                                              WebContents* web_contents,
121                                              jobject jdelegate)
122     : content::WebContentsObserver(web_contents),
123       jdelegate_(env, jdelegate) {
124   DCHECK(web_contents);
125   DCHECK(jdelegate);
126
127   if (web_contents->GetRenderViewHost())
128     RenderViewCreated(web_contents->GetRenderViewHost());
129 }
130
131 void ClientMapEntryUpdater::RenderViewCreated(RenderViewHost* rvh) {
132   IoThreadClientData client_data;
133   client_data.io_thread_client = jdelegate_;
134   client_data.pending_association = false;
135   RvhToIoThreadClientMap::GetInstance()->Set(
136       GetRenderViewHostIdPair(rvh), client_data);
137 }
138
139 void ClientMapEntryUpdater::RenderViewDeleted(RenderViewHost* rvh) {
140   RvhToIoThreadClientMap::GetInstance()->Erase(GetRenderViewHostIdPair(rvh));
141 }
142
143 void ClientMapEntryUpdater::WebContentsDestroyed(WebContents* web_contents) {
144   delete this;
145 }
146
147 } // namespace
148
149 // AwContentsIoThreadClientImpl -----------------------------------------------
150
151 // static
152 scoped_ptr<AwContentsIoThreadClient>
153 AwContentsIoThreadClient::FromID(int render_process_id, int render_view_id) {
154   pair<int, int> rvh_id(render_process_id, render_view_id);
155   IoThreadClientData client_data;
156   if (!RvhToIoThreadClientMap::GetInstance()->Get(rvh_id, &client_data))
157     return scoped_ptr<AwContentsIoThreadClient>();
158
159   JNIEnv* env = AttachCurrentThread();
160   ScopedJavaLocalRef<jobject> java_delegate =
161       client_data.io_thread_client.get(env);
162   DCHECK(!client_data.pending_association || java_delegate.is_null());
163   return scoped_ptr<AwContentsIoThreadClient>(new AwContentsIoThreadClientImpl(
164       client_data.pending_association, java_delegate));
165 }
166
167 // static
168 void AwContentsIoThreadClientImpl::RegisterPendingContents(
169     WebContents* web_contents) {
170   IoThreadClientData client_data;
171   client_data.pending_association = true;
172   RvhToIoThreadClientMap::GetInstance()->Set(
173       GetRenderViewHostIdPair(web_contents->GetRenderViewHost()), client_data);
174 }
175
176 // static
177 void AwContentsIoThreadClientImpl::Associate(
178     WebContents* web_contents,
179     const JavaRef<jobject>& jclient) {
180   JNIEnv* env = AttachCurrentThread();
181   // The ClientMapEntryUpdater lifespan is tied to the WebContents.
182   new ClientMapEntryUpdater(env, web_contents, jclient.obj());
183 }
184
185 AwContentsIoThreadClientImpl::AwContentsIoThreadClientImpl(
186     bool pending_association,
187     const JavaRef<jobject>& obj)
188   : pending_association_(pending_association),
189     java_object_(obj) {
190 }
191
192 AwContentsIoThreadClientImpl::~AwContentsIoThreadClientImpl() {
193   // explict, out-of-line destructor.
194 }
195
196 bool AwContentsIoThreadClientImpl::PendingAssociation() const {
197   return pending_association_;
198 }
199
200 AwContentsIoThreadClient::CacheMode
201 AwContentsIoThreadClientImpl::GetCacheMode() const {
202   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
203   if (java_object_.is_null())
204     return AwContentsIoThreadClient::LOAD_DEFAULT;
205
206   JNIEnv* env = AttachCurrentThread();
207   return static_cast<AwContentsIoThreadClient::CacheMode>(
208       Java_AwContentsIoThreadClient_getCacheMode(
209           env, java_object_.obj()));
210 }
211
212 scoped_ptr<InterceptedRequestData>
213 AwContentsIoThreadClientImpl::ShouldInterceptRequest(
214     const GURL& location,
215     const net::URLRequest* request) {
216   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
217   if (java_object_.is_null())
218     return scoped_ptr<InterceptedRequestData>();
219   const content::ResourceRequestInfo* info =
220       content::ResourceRequestInfo::ForRequest(request);
221   bool is_main_frame = info &&
222       info->GetResourceType() == ResourceType::MAIN_FRAME;
223
224   JNIEnv* env = AttachCurrentThread();
225   ScopedJavaLocalRef<jstring> jstring_url =
226       ConvertUTF8ToJavaString(env, location.spec());
227   ScopedJavaLocalRef<jobject> ret =
228       Java_AwContentsIoThreadClient_shouldInterceptRequest(
229           env, java_object_.obj(), jstring_url.obj(), is_main_frame);
230   if (ret.is_null())
231     return scoped_ptr<InterceptedRequestData>();
232   return scoped_ptr<InterceptedRequestData>(
233       new InterceptedRequestDataImpl(ret));
234 }
235
236 bool AwContentsIoThreadClientImpl::ShouldBlockContentUrls() const {
237   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
238   if (java_object_.is_null())
239     return false;
240
241   JNIEnv* env = AttachCurrentThread();
242   return Java_AwContentsIoThreadClient_shouldBlockContentUrls(
243       env, java_object_.obj());
244 }
245
246 bool AwContentsIoThreadClientImpl::ShouldBlockFileUrls() const {
247   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
248   if (java_object_.is_null())
249     return false;
250
251   JNIEnv* env = AttachCurrentThread();
252   return Java_AwContentsIoThreadClient_shouldBlockFileUrls(
253       env, java_object_.obj());
254 }
255
256 bool AwContentsIoThreadClientImpl::ShouldBlockNetworkLoads() const {
257   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
258   if (java_object_.is_null())
259     return false;
260
261   JNIEnv* env = AttachCurrentThread();
262   return Java_AwContentsIoThreadClient_shouldBlockNetworkLoads(
263       env, java_object_.obj());
264 }
265
266 void AwContentsIoThreadClientImpl::NewDownload(
267     const GURL& url,
268     const std::string& user_agent,
269     const std::string& content_disposition,
270     const std::string& mime_type,
271     int64 content_length) {
272   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
273   if (java_object_.is_null())
274     return;
275
276   JNIEnv* env = AttachCurrentThread();
277   ScopedJavaLocalRef<jstring> jstring_url =
278       ConvertUTF8ToJavaString(env, url.spec());
279   ScopedJavaLocalRef<jstring> jstring_user_agent =
280       ConvertUTF8ToJavaString(env, user_agent);
281   ScopedJavaLocalRef<jstring> jstring_content_disposition =
282       ConvertUTF8ToJavaString(env, content_disposition);
283   ScopedJavaLocalRef<jstring> jstring_mime_type =
284       ConvertUTF8ToJavaString(env, mime_type);
285
286   Java_AwContentsIoThreadClient_onDownloadStart(
287       env,
288       java_object_.obj(),
289       jstring_url.obj(),
290       jstring_user_agent.obj(),
291       jstring_content_disposition.obj(),
292       jstring_mime_type.obj(),
293       content_length);
294 }
295
296 void AwContentsIoThreadClientImpl::NewLoginRequest(const std::string& realm,
297                                                    const std::string& account,
298                                                    const std::string& args) {
299   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
300   if (java_object_.is_null())
301     return;
302
303   JNIEnv* env = AttachCurrentThread();
304   ScopedJavaLocalRef<jstring> jrealm = ConvertUTF8ToJavaString(env, realm);
305   ScopedJavaLocalRef<jstring> jargs = ConvertUTF8ToJavaString(env, args);
306
307   ScopedJavaLocalRef<jstring> jaccount;
308   if (!account.empty())
309     jaccount = ConvertUTF8ToJavaString(env, account);
310
311   Java_AwContentsIoThreadClient_newLoginRequest(
312       env, java_object_.obj(), jrealm.obj(), jaccount.obj(), jargs.obj());
313 }
314
315 bool RegisterAwContentsIoThreadClientImpl(JNIEnv* env) {
316   return RegisterNativesImpl(env);
317 }
318
319 } // namespace android_webview