Upstream version 7.36.149.0
[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/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"
27 #include "url/gurl.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 android_webview {
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 void ClientMapEntryUpdater::RenderFrameDeleted(RenderFrameHost* rfh) {
142   RfhToIoThreadClientMap::GetInstance()->Erase(GetRenderFrameHostIdPair(rfh));
143 }
144
145 void ClientMapEntryUpdater::WebContentsDestroyed() {
146   delete this;
147 }
148
149 } // namespace
150
151 // AwContentsIoThreadClientImpl -----------------------------------------------
152
153 // static
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>();
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<AwContentsIoThreadClient>(new AwContentsIoThreadClientImpl(
166       client_data.pending_association, java_delegate));
167 }
168
169 // static
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,
177                                                   &client_data)) {
178     NOTREACHED();
179     return;
180   }
181
182   RfhToIoThreadClientMap::GetInstance()->Set(child_rfh_id, client_data);
183 }
184
185 // static
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);
192 }
193
194 // static
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());
201 }
202
203 AwContentsIoThreadClientImpl::AwContentsIoThreadClientImpl(
204     bool pending_association,
205     const JavaRef<jobject>& obj)
206   : pending_association_(pending_association),
207     java_object_(obj) {
208 }
209
210 AwContentsIoThreadClientImpl::~AwContentsIoThreadClientImpl() {
211   // explict, out-of-line destructor.
212 }
213
214 bool AwContentsIoThreadClientImpl::PendingAssociation() const {
215   return pending_association_;
216 }
217
218 AwContentsIoThreadClient::CacheMode
219 AwContentsIoThreadClientImpl::GetCacheMode() const {
220   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
221   if (java_object_.is_null())
222     return AwContentsIoThreadClient::LOAD_DEFAULT;
223
224   JNIEnv* env = AttachCurrentThread();
225   return static_cast<AwContentsIoThreadClient::CacheMode>(
226       Java_AwContentsIoThreadClient_getCacheMode(
227           env, java_object_.obj()));
228 }
229
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;
241
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);
250   if (ret.is_null())
251     return scoped_ptr<InterceptedRequestData>();
252   return scoped_ptr<InterceptedRequestData>(
253       new InterceptedRequestDataImpl(ret));
254 }
255
256 bool AwContentsIoThreadClientImpl::ShouldBlockContentUrls() 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_shouldBlockContentUrls(
263       env, java_object_.obj());
264 }
265
266 bool AwContentsIoThreadClientImpl::ShouldBlockFileUrls() const {
267   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
268   if (java_object_.is_null())
269     return false;
270
271   JNIEnv* env = AttachCurrentThread();
272   return Java_AwContentsIoThreadClient_shouldBlockFileUrls(
273       env, java_object_.obj());
274 }
275
276 bool AwContentsIoThreadClientImpl::ShouldBlockNetworkLoads() const {
277   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
278   if (java_object_.is_null())
279     return false;
280
281   JNIEnv* env = AttachCurrentThread();
282   return Java_AwContentsIoThreadClient_shouldBlockNetworkLoads(
283       env, java_object_.obj());
284 }
285
286 void AwContentsIoThreadClientImpl::NewDownload(
287     const GURL& url,
288     const std::string& user_agent,
289     const std::string& content_disposition,
290     const std::string& mime_type,
291     int64 content_length) {
292   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
293   if (java_object_.is_null())
294     return;
295
296   JNIEnv* env = AttachCurrentThread();
297   ScopedJavaLocalRef<jstring> jstring_url =
298       ConvertUTF8ToJavaString(env, url.spec());
299   ScopedJavaLocalRef<jstring> jstring_user_agent =
300       ConvertUTF8ToJavaString(env, user_agent);
301   ScopedJavaLocalRef<jstring> jstring_content_disposition =
302       ConvertUTF8ToJavaString(env, content_disposition);
303   ScopedJavaLocalRef<jstring> jstring_mime_type =
304       ConvertUTF8ToJavaString(env, mime_type);
305
306   Java_AwContentsIoThreadClient_onDownloadStart(
307       env,
308       java_object_.obj(),
309       jstring_url.obj(),
310       jstring_user_agent.obj(),
311       jstring_content_disposition.obj(),
312       jstring_mime_type.obj(),
313       content_length);
314 }
315
316 void AwContentsIoThreadClientImpl::NewLoginRequest(const std::string& realm,
317                                                    const std::string& account,
318                                                    const std::string& args) {
319   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
320   if (java_object_.is_null())
321     return;
322
323   JNIEnv* env = AttachCurrentThread();
324   ScopedJavaLocalRef<jstring> jrealm = ConvertUTF8ToJavaString(env, realm);
325   ScopedJavaLocalRef<jstring> jargs = ConvertUTF8ToJavaString(env, args);
326
327   ScopedJavaLocalRef<jstring> jaccount;
328   if (!account.empty())
329     jaccount = ConvertUTF8ToJavaString(env, account);
330
331   Java_AwContentsIoThreadClient_newLoginRequest(
332       env, java_object_.obj(), jrealm.obj(), jaccount.obj(), jargs.obj());
333 }
334
335 bool RegisterAwContentsIoThreadClientImpl(JNIEnv* env) {
336   return RegisterNativesImpl(env);
337 }
338
339 } // namespace android_webview