blob: 4c64db2ab947bbc7a14032c5e64789b9cee6e217 [file] [log] [blame]
Torne (Richard Coles)58218062012-11-14 11:43:16 +00001// 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"
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +000020#include "content/public/browser/resource_request_info.h"
Torne (Richard Coles)58218062012-11-14 11:43:16 +000021#include "content/public/browser/web_contents.h"
22#include "content/public/browser/web_contents_observer.h"
Torne (Richard Coles)58218062012-11-14 11:43:16 +000023#include "jni/AwContentsIoThreadClient_jni.h"
Ben Murdoch7dbb3d52013-07-17 14:55:54 +010024#include "net/url_request/url_request.h"
25#include "url/gurl.h"
Torne (Richard Coles)58218062012-11-14 11:43:16 +000026
27using base::android::AttachCurrentThread;
28using base::android::ConvertUTF8ToJavaString;
29using base::android::JavaRef;
30using base::android::ScopedJavaLocalRef;
31using base::LazyInstance;
32using content::BrowserThread;
33using content::RenderViewHost;
34using content::WebContents;
35using std::map;
36using std::pair;
37
38namespace android_webview {
39
40namespace {
41
Torne (Richard Coles)d0247b12013-09-19 22:36:51 +010042struct IoThreadClientData {
43 bool pending_association;
44 JavaObjectWeakGlobalRef io_thread_client;
45
46 IoThreadClientData();
47};
48
49IoThreadClientData::IoThreadClientData() : pending_association(false) {}
50
51typedef map<pair<int, int>, IoThreadClientData>
52 RenderViewHostToIoThreadClientType;
Torne (Richard Coles)58218062012-11-14 11:43:16 +000053
54static pair<int, int> GetRenderViewHostIdPair(RenderViewHost* rvh) {
55 return pair<int, int>(rvh->GetProcess()->GetID(), rvh->GetRoutingID());
56}
57
58// RvhToIoThreadClientMap -----------------------------------------------------
59class RvhToIoThreadClientMap {
60 public:
61 static RvhToIoThreadClientMap* GetInstance();
Torne (Richard Coles)d0247b12013-09-19 22:36:51 +010062 void Set(pair<int, int> rvh_id, const IoThreadClientData& client);
63 bool Get(pair<int, int> rvh_id, IoThreadClientData* client);
Torne (Richard Coles)58218062012-11-14 11:43:16 +000064 void Erase(pair<int, int> rvh_id);
65
66 private:
67 static LazyInstance<RvhToIoThreadClientMap> g_instance_;
68 base::Lock map_lock_;
Torne (Richard Coles)d0247b12013-09-19 22:36:51 +010069 RenderViewHostToIoThreadClientType rvh_to_io_thread_client_;
Torne (Richard Coles)58218062012-11-14 11:43:16 +000070};
71
72// static
73LazyInstance<RvhToIoThreadClientMap> RvhToIoThreadClientMap::g_instance_ =
74 LAZY_INSTANCE_INITIALIZER;
75
76// static
77RvhToIoThreadClientMap* RvhToIoThreadClientMap::GetInstance() {
78 return g_instance_.Pointer();
79}
80
Torne (Richard Coles)d0247b12013-09-19 22:36:51 +010081void RvhToIoThreadClientMap::Set(pair<int, int> rvh_id,
82 const IoThreadClientData& client) {
Torne (Richard Coles)58218062012-11-14 11:43:16 +000083 base::AutoLock lock(map_lock_);
Torne (Richard Coles)d0247b12013-09-19 22:36:51 +010084 rvh_to_io_thread_client_[rvh_id] = client;
Torne (Richard Coles)58218062012-11-14 11:43:16 +000085}
86
Torne (Richard Coles)d0247b12013-09-19 22:36:51 +010087bool RvhToIoThreadClientMap::Get(
88 pair<int, int> rvh_id, IoThreadClientData* client) {
Torne (Richard Coles)58218062012-11-14 11:43:16 +000089 base::AutoLock lock(map_lock_);
Torne (Richard Coles)d0247b12013-09-19 22:36:51 +010090 RenderViewHostToIoThreadClientType::iterator iterator =
91 rvh_to_io_thread_client_.find(rvh_id);
92 if (iterator == rvh_to_io_thread_client_.end())
93 return false;
Torne (Richard Coles)58218062012-11-14 11:43:16 +000094
Torne (Richard Coles)d0247b12013-09-19 22:36:51 +010095 *client = iterator->second;
96 return true;
Torne (Richard Coles)58218062012-11-14 11:43:16 +000097}
98
99void RvhToIoThreadClientMap::Erase(pair<int, int> rvh_id) {
100 base::AutoLock lock(map_lock_);
Torne (Richard Coles)d0247b12013-09-19 22:36:51 +0100101 rvh_to_io_thread_client_.erase(rvh_id);
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000102}
103
104// ClientMapEntryUpdater ------------------------------------------------------
105
106class 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 RenderViewForInterstitialPageCreated(
113 RenderViewHost* render_view_host) OVERRIDE;
114 virtual void RenderViewDeleted(RenderViewHost* render_view_host) OVERRIDE;
Torne (Richard Coles)a93a17c2013-05-15 11:34:50 +0100115 virtual void WebContentsDestroyed(WebContents* web_contents) OVERRIDE;
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000116
117 private:
118 JavaObjectWeakGlobalRef jdelegate_;
119};
120
121ClientMapEntryUpdater::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->GetRenderViewHost())
130 RenderViewCreated(web_contents->GetRenderViewHost());
131}
132
133void ClientMapEntryUpdater::RenderViewCreated(RenderViewHost* rvh) {
Torne (Richard Coles)d0247b12013-09-19 22:36:51 +0100134 IoThreadClientData client_data;
135 client_data.io_thread_client = jdelegate_;
136 client_data.pending_association = false;
137 RvhToIoThreadClientMap::GetInstance()->Set(
138 GetRenderViewHostIdPair(rvh), client_data);
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000139}
140
141void ClientMapEntryUpdater::RenderViewForInterstitialPageCreated(
142 RenderViewHost* rvh) {
143 RenderViewCreated(rvh);
144}
145
146void ClientMapEntryUpdater::RenderViewDeleted(RenderViewHost* rvh) {
147 RvhToIoThreadClientMap::GetInstance()->Erase(GetRenderViewHostIdPair(rvh));
148}
149
150void ClientMapEntryUpdater::WebContentsDestroyed(WebContents* web_contents) {
151 if (web_contents->GetRenderViewHost())
152 RenderViewDeleted(web_contents->GetRenderViewHost());
153 delete this;
154}
155
156} // namespace
157
158// AwContentsIoThreadClientImpl -----------------------------------------------
159
160// static
161scoped_ptr<AwContentsIoThreadClient>
162AwContentsIoThreadClient::FromID(int render_process_id, int render_view_id) {
163 pair<int, int> rvh_id(render_process_id, render_view_id);
Torne (Richard Coles)d0247b12013-09-19 22:36:51 +0100164 IoThreadClientData client_data;
165 if (!RvhToIoThreadClientMap::GetInstance()->Get(rvh_id, &client_data))
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000166 return scoped_ptr<AwContentsIoThreadClient>();
167
Torne (Richard Coles)d0247b12013-09-19 22:36:51 +0100168 JNIEnv* env = AttachCurrentThread();
169 ScopedJavaLocalRef<jobject> java_delegate =
170 client_data.io_thread_client.get(env);
171 DCHECK(!client_data.pending_association || java_delegate.is_null());
172 return scoped_ptr<AwContentsIoThreadClient>(new AwContentsIoThreadClientImpl(
173 client_data.pending_association, java_delegate));
174}
175
176// static
177void AwContentsIoThreadClientImpl::RegisterPendingContents(
178 WebContents* web_contents) {
179 IoThreadClientData client_data;
180 client_data.pending_association = true;
181 RvhToIoThreadClientMap::GetInstance()->Set(
182 GetRenderViewHostIdPair(web_contents->GetRenderViewHost()), client_data);
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000183}
184
185// static
186void AwContentsIoThreadClientImpl::Associate(
187 WebContents* web_contents,
188 const JavaRef<jobject>& jclient) {
189 JNIEnv* env = AttachCurrentThread();
190 // The ClientMapEntryUpdater lifespan is tied to the WebContents.
191 new ClientMapEntryUpdater(env, web_contents, jclient.obj());
192}
193
194AwContentsIoThreadClientImpl::AwContentsIoThreadClientImpl(
Torne (Richard Coles)d0247b12013-09-19 22:36:51 +0100195 bool pending_association,
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000196 const JavaRef<jobject>& obj)
Torne (Richard Coles)d0247b12013-09-19 22:36:51 +0100197 : pending_association_(pending_association),
198 java_object_(obj) {
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000199}
200
201AwContentsIoThreadClientImpl::~AwContentsIoThreadClientImpl() {
202 // explict, out-of-line destructor.
203}
204
Torne (Richard Coles)d0247b12013-09-19 22:36:51 +0100205bool AwContentsIoThreadClientImpl::PendingAssociation() const {
206 return pending_association_;
207}
208
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000209AwContentsIoThreadClient::CacheMode
210AwContentsIoThreadClientImpl::GetCacheMode() const {
211 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
212 if (java_object_.is_null())
213 return AwContentsIoThreadClient::LOAD_DEFAULT;
214
215 JNIEnv* env = AttachCurrentThread();
216 return static_cast<AwContentsIoThreadClient::CacheMode>(
217 Java_AwContentsIoThreadClient_getCacheMode(
218 env, java_object_.obj()));
219}
220
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000221scoped_ptr<InterceptedRequestData>
222AwContentsIoThreadClientImpl::ShouldInterceptRequest(
223 const GURL& location,
224 const net::URLRequest* request) {
225 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
226 if (java_object_.is_null())
227 return scoped_ptr<InterceptedRequestData>();
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000228 const content::ResourceRequestInfo* info =
229 content::ResourceRequestInfo::ForRequest(request);
Torne (Richard Coles)424c4d72013-08-30 15:14:49 +0100230 bool is_main_frame = info &&
231 info->GetResourceType() == ResourceType::MAIN_FRAME;
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000232
233 JNIEnv* env = AttachCurrentThread();
234 ScopedJavaLocalRef<jstring> jstring_url =
235 ConvertUTF8ToJavaString(env, location.spec());
236 ScopedJavaLocalRef<jobject> ret =
237 Java_AwContentsIoThreadClient_shouldInterceptRequest(
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000238 env, java_object_.obj(), jstring_url.obj(), is_main_frame);
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000239 if (ret.is_null())
240 return scoped_ptr<InterceptedRequestData>();
241 return scoped_ptr<InterceptedRequestData>(
242 new InterceptedRequestDataImpl(ret));
243}
244
245bool AwContentsIoThreadClientImpl::ShouldBlockContentUrls() const {
246 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
247 if (java_object_.is_null())
248 return false;
249
250 JNIEnv* env = AttachCurrentThread();
251 return Java_AwContentsIoThreadClient_shouldBlockContentUrls(
252 env, java_object_.obj());
253}
254
255bool AwContentsIoThreadClientImpl::ShouldBlockFileUrls() const {
256 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
257 if (java_object_.is_null())
258 return false;
259
260 JNIEnv* env = AttachCurrentThread();
261 return Java_AwContentsIoThreadClient_shouldBlockFileUrls(
262 env, java_object_.obj());
263}
264
265bool AwContentsIoThreadClientImpl::ShouldBlockNetworkLoads() const {
266 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
267 if (java_object_.is_null())
268 return false;
269
270 JNIEnv* env = AttachCurrentThread();
271 return Java_AwContentsIoThreadClient_shouldBlockNetworkLoads(
272 env, java_object_.obj());
273}
274
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000275void AwContentsIoThreadClientImpl::NewDownload(
276 const GURL& url,
277 const std::string& user_agent,
278 const std::string& content_disposition,
279 const std::string& mime_type,
280 int64 content_length) {
281 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
282 if (java_object_.is_null())
283 return;
284
285 JNIEnv* env = AttachCurrentThread();
286 ScopedJavaLocalRef<jstring> jstring_url =
287 ConvertUTF8ToJavaString(env, url.spec());
288 ScopedJavaLocalRef<jstring> jstring_user_agent =
289 ConvertUTF8ToJavaString(env, user_agent);
290 ScopedJavaLocalRef<jstring> jstring_content_disposition =
291 ConvertUTF8ToJavaString(env, content_disposition);
292 ScopedJavaLocalRef<jstring> jstring_mime_type =
293 ConvertUTF8ToJavaString(env, mime_type);
294
295 Java_AwContentsIoThreadClient_onDownloadStart(
296 env,
297 java_object_.obj(),
298 jstring_url.obj(),
299 jstring_user_agent.obj(),
300 jstring_content_disposition.obj(),
301 jstring_mime_type.obj(),
302 content_length);
303}
304
305void AwContentsIoThreadClientImpl::NewLoginRequest(const std::string& realm,
306 const std::string& account,
307 const std::string& args) {
308 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
309 if (java_object_.is_null())
310 return;
311
312 JNIEnv* env = AttachCurrentThread();
313 ScopedJavaLocalRef<jstring> jrealm = ConvertUTF8ToJavaString(env, realm);
314 ScopedJavaLocalRef<jstring> jargs = ConvertUTF8ToJavaString(env, args);
315
316 ScopedJavaLocalRef<jstring> jaccount;
317 if (!account.empty())
318 jaccount = ConvertUTF8ToJavaString(env, account);
319
320 Java_AwContentsIoThreadClient_newLoginRequest(
321 env, java_object_.obj(), jrealm.obj(), jaccount.obj(), jargs.obj());
322}
323
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000324bool RegisterAwContentsIoThreadClientImpl(JNIEnv* env) {
325 return RegisterNativesImpl(env);
326}
327
328} // namespace android_webview