Torne (Richard Coles) | 5821806 | 2012-11-14 11:43:16 +0000 | [diff] [blame] | 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" |
Torne (Richard Coles) | 2a99a7e | 2013-03-28 15:31:22 +0000 | [diff] [blame] | 20 | #include "content/public/browser/resource_request_info.h" |
Torne (Richard Coles) | 5821806 | 2012-11-14 11:43:16 +0000 | [diff] [blame] | 21 | #include "content/public/browser/web_contents.h" |
| 22 | #include "content/public/browser/web_contents_observer.h" |
Torne (Richard Coles) | 5821806 | 2012-11-14 11:43:16 +0000 | [diff] [blame] | 23 | #include "jni/AwContentsIoThreadClient_jni.h" |
Ben Murdoch | 7dbb3d5 | 2013-07-17 14:55:54 +0100 | [diff] [blame] | 24 | #include "net/url_request/url_request.h" |
| 25 | #include "url/gurl.h" |
Torne (Richard Coles) | 5821806 | 2012-11-14 11:43:16 +0000 | [diff] [blame] | 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 | |
Torne (Richard Coles) | d0247b1 | 2013-09-19 22:36:51 +0100 | [diff] [blame] | 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; |
Torne (Richard Coles) | 5821806 | 2012-11-14 11:43:16 +0000 | [diff] [blame] | 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(); |
Torne (Richard Coles) | d0247b1 | 2013-09-19 22:36:51 +0100 | [diff] [blame] | 62 | void Set(pair<int, int> rvh_id, const IoThreadClientData& client); |
| 63 | bool Get(pair<int, int> rvh_id, IoThreadClientData* client); |
Torne (Richard Coles) | 5821806 | 2012-11-14 11:43:16 +0000 | [diff] [blame] | 64 | void Erase(pair<int, int> rvh_id); |
| 65 | |
| 66 | private: |
| 67 | static LazyInstance<RvhToIoThreadClientMap> g_instance_; |
| 68 | base::Lock map_lock_; |
Torne (Richard Coles) | d0247b1 | 2013-09-19 22:36:51 +0100 | [diff] [blame] | 69 | RenderViewHostToIoThreadClientType rvh_to_io_thread_client_; |
Torne (Richard Coles) | 5821806 | 2012-11-14 11:43:16 +0000 | [diff] [blame] | 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 | |
Torne (Richard Coles) | d0247b1 | 2013-09-19 22:36:51 +0100 | [diff] [blame] | 81 | void RvhToIoThreadClientMap::Set(pair<int, int> rvh_id, |
| 82 | const IoThreadClientData& client) { |
Torne (Richard Coles) | 5821806 | 2012-11-14 11:43:16 +0000 | [diff] [blame] | 83 | base::AutoLock lock(map_lock_); |
Torne (Richard Coles) | d0247b1 | 2013-09-19 22:36:51 +0100 | [diff] [blame] | 84 | rvh_to_io_thread_client_[rvh_id] = client; |
Torne (Richard Coles) | 5821806 | 2012-11-14 11:43:16 +0000 | [diff] [blame] | 85 | } |
| 86 | |
Torne (Richard Coles) | d0247b1 | 2013-09-19 22:36:51 +0100 | [diff] [blame] | 87 | bool RvhToIoThreadClientMap::Get( |
| 88 | pair<int, int> rvh_id, IoThreadClientData* client) { |
Torne (Richard Coles) | 5821806 | 2012-11-14 11:43:16 +0000 | [diff] [blame] | 89 | base::AutoLock lock(map_lock_); |
Torne (Richard Coles) | d0247b1 | 2013-09-19 22:36:51 +0100 | [diff] [blame] | 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; |
Torne (Richard Coles) | 5821806 | 2012-11-14 11:43:16 +0000 | [diff] [blame] | 94 | |
Torne (Richard Coles) | d0247b1 | 2013-09-19 22:36:51 +0100 | [diff] [blame] | 95 | *client = iterator->second; |
| 96 | return true; |
Torne (Richard Coles) | 5821806 | 2012-11-14 11:43:16 +0000 | [diff] [blame] | 97 | } |
| 98 | |
| 99 | void RvhToIoThreadClientMap::Erase(pair<int, int> rvh_id) { |
| 100 | base::AutoLock lock(map_lock_); |
Torne (Richard Coles) | d0247b1 | 2013-09-19 22:36:51 +0100 | [diff] [blame] | 101 | rvh_to_io_thread_client_.erase(rvh_id); |
Torne (Richard Coles) | 5821806 | 2012-11-14 11:43:16 +0000 | [diff] [blame] | 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 RenderViewForInterstitialPageCreated( |
| 113 | RenderViewHost* render_view_host) OVERRIDE; |
| 114 | virtual void RenderViewDeleted(RenderViewHost* render_view_host) OVERRIDE; |
Torne (Richard Coles) | a93a17c | 2013-05-15 11:34:50 +0100 | [diff] [blame] | 115 | virtual void WebContentsDestroyed(WebContents* web_contents) OVERRIDE; |
Torne (Richard Coles) | 5821806 | 2012-11-14 11:43:16 +0000 | [diff] [blame] | 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->GetRenderViewHost()) |
| 130 | RenderViewCreated(web_contents->GetRenderViewHost()); |
| 131 | } |
| 132 | |
| 133 | void ClientMapEntryUpdater::RenderViewCreated(RenderViewHost* rvh) { |
Torne (Richard Coles) | d0247b1 | 2013-09-19 22:36:51 +0100 | [diff] [blame] | 134 | 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) | 5821806 | 2012-11-14 11:43:16 +0000 | [diff] [blame] | 139 | } |
| 140 | |
| 141 | void ClientMapEntryUpdater::RenderViewForInterstitialPageCreated( |
| 142 | RenderViewHost* rvh) { |
| 143 | RenderViewCreated(rvh); |
| 144 | } |
| 145 | |
| 146 | void ClientMapEntryUpdater::RenderViewDeleted(RenderViewHost* rvh) { |
| 147 | RvhToIoThreadClientMap::GetInstance()->Erase(GetRenderViewHostIdPair(rvh)); |
| 148 | } |
| 149 | |
| 150 | void 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 |
| 161 | scoped_ptr<AwContentsIoThreadClient> |
| 162 | AwContentsIoThreadClient::FromID(int render_process_id, int render_view_id) { |
| 163 | pair<int, int> rvh_id(render_process_id, render_view_id); |
Torne (Richard Coles) | d0247b1 | 2013-09-19 22:36:51 +0100 | [diff] [blame] | 164 | IoThreadClientData client_data; |
| 165 | if (!RvhToIoThreadClientMap::GetInstance()->Get(rvh_id, &client_data)) |
Torne (Richard Coles) | 5821806 | 2012-11-14 11:43:16 +0000 | [diff] [blame] | 166 | return scoped_ptr<AwContentsIoThreadClient>(); |
| 167 | |
Torne (Richard Coles) | d0247b1 | 2013-09-19 22:36:51 +0100 | [diff] [blame] | 168 | 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 |
| 177 | void 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) | 5821806 | 2012-11-14 11:43:16 +0000 | [diff] [blame] | 183 | } |
| 184 | |
| 185 | // static |
| 186 | void 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 | |
| 194 | AwContentsIoThreadClientImpl::AwContentsIoThreadClientImpl( |
Torne (Richard Coles) | d0247b1 | 2013-09-19 22:36:51 +0100 | [diff] [blame] | 195 | bool pending_association, |
Torne (Richard Coles) | 5821806 | 2012-11-14 11:43:16 +0000 | [diff] [blame] | 196 | const JavaRef<jobject>& obj) |
Torne (Richard Coles) | d0247b1 | 2013-09-19 22:36:51 +0100 | [diff] [blame] | 197 | : pending_association_(pending_association), |
| 198 | java_object_(obj) { |
Torne (Richard Coles) | 5821806 | 2012-11-14 11:43:16 +0000 | [diff] [blame] | 199 | } |
| 200 | |
| 201 | AwContentsIoThreadClientImpl::~AwContentsIoThreadClientImpl() { |
| 202 | // explict, out-of-line destructor. |
| 203 | } |
| 204 | |
Torne (Richard Coles) | d0247b1 | 2013-09-19 22:36:51 +0100 | [diff] [blame] | 205 | bool AwContentsIoThreadClientImpl::PendingAssociation() const { |
| 206 | return pending_association_; |
| 207 | } |
| 208 | |
Torne (Richard Coles) | 2a99a7e | 2013-03-28 15:31:22 +0000 | [diff] [blame] | 209 | AwContentsIoThreadClient::CacheMode |
| 210 | AwContentsIoThreadClientImpl::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) | 5821806 | 2012-11-14 11:43:16 +0000 | [diff] [blame] | 221 | scoped_ptr<InterceptedRequestData> |
| 222 | AwContentsIoThreadClientImpl::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) | 2a99a7e | 2013-03-28 15:31:22 +0000 | [diff] [blame] | 228 | const content::ResourceRequestInfo* info = |
| 229 | content::ResourceRequestInfo::ForRequest(request); |
Torne (Richard Coles) | 424c4d7 | 2013-08-30 15:14:49 +0100 | [diff] [blame] | 230 | bool is_main_frame = info && |
| 231 | info->GetResourceType() == ResourceType::MAIN_FRAME; |
Torne (Richard Coles) | 5821806 | 2012-11-14 11:43:16 +0000 | [diff] [blame] | 232 | |
| 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) | 2a99a7e | 2013-03-28 15:31:22 +0000 | [diff] [blame] | 238 | env, java_object_.obj(), jstring_url.obj(), is_main_frame); |
Torne (Richard Coles) | 5821806 | 2012-11-14 11:43:16 +0000 | [diff] [blame] | 239 | if (ret.is_null()) |
| 240 | return scoped_ptr<InterceptedRequestData>(); |
| 241 | return scoped_ptr<InterceptedRequestData>( |
| 242 | new InterceptedRequestDataImpl(ret)); |
| 243 | } |
| 244 | |
| 245 | bool 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 | |
| 255 | bool 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 | |
| 265 | bool 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) | 2a99a7e | 2013-03-28 15:31:22 +0000 | [diff] [blame] | 275 | void 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 | |
| 305 | void 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) | 5821806 | 2012-11-14 11:43:16 +0000 | [diff] [blame] | 324 | bool RegisterAwContentsIoThreadClientImpl(JNIEnv* env) { |
| 325 | return RegisterNativesImpl(env); |
| 326 | } |
| 327 | |
| 328 | } // namespace android_webview |