Updating trunk VERSION from 2139.0 to 2140.0
[chromium-blink-merge.git] / android_webview / native / aw_contents_io_thread_client_impl.cc
blob8bdbf77ac21b8cff68c57ae4558ad6abdb57bf70
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.
5 #include "android_webview/native/aw_contents_io_thread_client_impl.h"
7 #include <map>
8 #include <utility>
10 #include "android_webview/common/devtools_instrumentation.h"
11 #include "android_webview/native/aw_web_resource_response_impl.h"
12 #include "base/android/jni_array.h"
13 #include "base/android/jni_string.h"
14 #include "base/android/jni_weak_ref.h"
15 #include "base/lazy_instance.h"
16 #include "base/memory/linked_ptr.h"
17 #include "base/memory/scoped_ptr.h"
18 #include "base/synchronization/lock.h"
19 #include "content/public/browser/browser_thread.h"
20 #include "content/public/browser/render_frame_host.h"
21 #include "content/public/browser/render_process_host.h"
22 #include "content/public/browser/render_view_host.h"
23 #include "content/public/browser/resource_request_info.h"
24 #include "content/public/browser/web_contents.h"
25 #include "content/public/browser/web_contents_observer.h"
26 #include "jni/AwContentsIoThreadClient_jni.h"
27 #include "net/http/http_request_headers.h"
28 #include "net/url_request/url_request.h"
29 #include "url/gurl.h"
31 using base::android::AttachCurrentThread;
32 using base::android::ConvertUTF8ToJavaString;
33 using base::android::JavaRef;
34 using base::android::ScopedJavaLocalRef;
35 using base::android::ToJavaArrayOfStrings;
36 using base::LazyInstance;
37 using content::BrowserThread;
38 using content::RenderFrameHost;
39 using content::ResourceType;
40 using content::WebContents;
41 using std::map;
42 using std::pair;
43 using std::string;
44 using std::vector;
46 namespace android_webview {
48 namespace {
50 struct IoThreadClientData {
51 bool pending_association;
52 JavaObjectWeakGlobalRef io_thread_client;
54 IoThreadClientData();
57 IoThreadClientData::IoThreadClientData() : pending_association(false) {}
59 typedef map<pair<int, int>, IoThreadClientData>
60 RenderFrameHostToIoThreadClientType;
62 static pair<int, int> GetRenderFrameHostIdPair(RenderFrameHost* rfh) {
63 return pair<int, int>(rfh->GetProcess()->GetID(), rfh->GetRoutingID());
66 // RfhToIoThreadClientMap -----------------------------------------------------
67 class RfhToIoThreadClientMap {
68 public:
69 static RfhToIoThreadClientMap* GetInstance();
70 void Set(pair<int, int> rfh_id, const IoThreadClientData& client);
71 bool Get(pair<int, int> rfh_id, IoThreadClientData* client);
72 void Erase(pair<int, int> rfh_id);
74 private:
75 static LazyInstance<RfhToIoThreadClientMap> g_instance_;
76 base::Lock map_lock_;
77 RenderFrameHostToIoThreadClientType rfh_to_io_thread_client_;
80 // static
81 LazyInstance<RfhToIoThreadClientMap> RfhToIoThreadClientMap::g_instance_ =
82 LAZY_INSTANCE_INITIALIZER;
84 // static
85 RfhToIoThreadClientMap* RfhToIoThreadClientMap::GetInstance() {
86 return g_instance_.Pointer();
89 void RfhToIoThreadClientMap::Set(pair<int, int> rfh_id,
90 const IoThreadClientData& client) {
91 base::AutoLock lock(map_lock_);
92 rfh_to_io_thread_client_[rfh_id] = client;
95 bool RfhToIoThreadClientMap::Get(
96 pair<int, int> rfh_id, IoThreadClientData* client) {
97 base::AutoLock lock(map_lock_);
98 RenderFrameHostToIoThreadClientType::iterator iterator =
99 rfh_to_io_thread_client_.find(rfh_id);
100 if (iterator == rfh_to_io_thread_client_.end())
101 return false;
103 *client = iterator->second;
104 return true;
107 void RfhToIoThreadClientMap::Erase(pair<int, int> rfh_id) {
108 base::AutoLock lock(map_lock_);
109 rfh_to_io_thread_client_.erase(rfh_id);
112 // ClientMapEntryUpdater ------------------------------------------------------
114 class ClientMapEntryUpdater : public content::WebContentsObserver {
115 public:
116 ClientMapEntryUpdater(JNIEnv* env, WebContents* web_contents,
117 jobject jdelegate);
119 virtual void RenderFrameCreated(RenderFrameHost* render_frame_host) OVERRIDE;
120 virtual void RenderFrameDeleted(RenderFrameHost* render_frame_host) OVERRIDE;
121 virtual void WebContentsDestroyed() OVERRIDE;
123 private:
124 JavaObjectWeakGlobalRef jdelegate_;
127 ClientMapEntryUpdater::ClientMapEntryUpdater(JNIEnv* env,
128 WebContents* web_contents,
129 jobject jdelegate)
130 : content::WebContentsObserver(web_contents),
131 jdelegate_(env, jdelegate) {
132 DCHECK(web_contents);
133 DCHECK(jdelegate);
135 if (web_contents->GetMainFrame())
136 RenderFrameCreated(web_contents->GetMainFrame());
139 void ClientMapEntryUpdater::RenderFrameCreated(RenderFrameHost* rfh) {
140 IoThreadClientData client_data;
141 client_data.io_thread_client = jdelegate_;
142 client_data.pending_association = false;
143 RfhToIoThreadClientMap::GetInstance()->Set(
144 GetRenderFrameHostIdPair(rfh), client_data);
147 void ClientMapEntryUpdater::RenderFrameDeleted(RenderFrameHost* rfh) {
148 RfhToIoThreadClientMap::GetInstance()->Erase(GetRenderFrameHostIdPair(rfh));
151 void ClientMapEntryUpdater::WebContentsDestroyed() {
152 delete this;
155 } // namespace
157 // AwContentsIoThreadClientImpl -----------------------------------------------
159 // static
160 scoped_ptr<AwContentsIoThreadClient>
161 AwContentsIoThreadClient::FromID(int render_process_id, int render_frame_id) {
162 pair<int, int> rfh_id(render_process_id, render_frame_id);
163 IoThreadClientData client_data;
164 if (!RfhToIoThreadClientMap::GetInstance()->Get(rfh_id, &client_data))
165 return scoped_ptr<AwContentsIoThreadClient>();
167 JNIEnv* env = AttachCurrentThread();
168 ScopedJavaLocalRef<jobject> java_delegate =
169 client_data.io_thread_client.get(env);
170 DCHECK(!client_data.pending_association || java_delegate.is_null());
171 return scoped_ptr<AwContentsIoThreadClient>(new AwContentsIoThreadClientImpl(
172 client_data.pending_association, java_delegate));
175 // static
176 void AwContentsIoThreadClient::SubFrameCreated(int render_process_id,
177 int parent_render_frame_id,
178 int child_render_frame_id) {
179 pair<int, int> parent_rfh_id(render_process_id, parent_render_frame_id);
180 pair<int, int> child_rfh_id(render_process_id, child_render_frame_id);
181 IoThreadClientData client_data;
182 if (!RfhToIoThreadClientMap::GetInstance()->Get(parent_rfh_id,
183 &client_data)) {
184 NOTREACHED();
185 return;
188 RfhToIoThreadClientMap::GetInstance()->Set(child_rfh_id, client_data);
191 // static
192 void AwContentsIoThreadClientImpl::RegisterPendingContents(
193 WebContents* web_contents) {
194 IoThreadClientData client_data;
195 client_data.pending_association = true;
196 RfhToIoThreadClientMap::GetInstance()->Set(
197 GetRenderFrameHostIdPair(web_contents->GetMainFrame()), client_data);
200 // static
201 void AwContentsIoThreadClientImpl::Associate(
202 WebContents* web_contents,
203 const JavaRef<jobject>& jclient) {
204 JNIEnv* env = AttachCurrentThread();
205 // The ClientMapEntryUpdater lifespan is tied to the WebContents.
206 new ClientMapEntryUpdater(env, web_contents, jclient.obj());
209 AwContentsIoThreadClientImpl::AwContentsIoThreadClientImpl(
210 bool pending_association,
211 const JavaRef<jobject>& obj)
212 : pending_association_(pending_association),
213 java_object_(obj) {
216 AwContentsIoThreadClientImpl::~AwContentsIoThreadClientImpl() {
217 // explict, out-of-line destructor.
220 bool AwContentsIoThreadClientImpl::PendingAssociation() const {
221 return pending_association_;
224 AwContentsIoThreadClient::CacheMode
225 AwContentsIoThreadClientImpl::GetCacheMode() const {
226 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
227 if (java_object_.is_null())
228 return AwContentsIoThreadClient::LOAD_DEFAULT;
230 JNIEnv* env = AttachCurrentThread();
231 return static_cast<AwContentsIoThreadClient::CacheMode>(
232 Java_AwContentsIoThreadClient_getCacheMode(
233 env, java_object_.obj()));
236 scoped_ptr<AwWebResourceResponse>
237 AwContentsIoThreadClientImpl::ShouldInterceptRequest(
238 const GURL& location,
239 const net::URLRequest* request) {
240 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
241 if (java_object_.is_null())
242 return scoped_ptr<AwWebResourceResponse>();
243 const content::ResourceRequestInfo* info =
244 content::ResourceRequestInfo::ForRequest(request);
245 bool is_main_frame = info &&
246 info->GetResourceType() == content::RESOURCE_TYPE_MAIN_FRAME;
247 bool has_user_gesture = info && info->HasUserGesture();
249 vector<string> headers_names;
250 vector<string> headers_values;
252 net::HttpRequestHeaders headers;
253 if (!request->GetFullRequestHeaders(&headers))
254 headers = request->extra_request_headers();
255 net::HttpRequestHeaders::Iterator headers_iterator(headers);
256 while (headers_iterator.GetNext()) {
257 headers_names.push_back(headers_iterator.name());
258 headers_values.push_back(headers_iterator.value());
262 JNIEnv* env = AttachCurrentThread();
263 ScopedJavaLocalRef<jstring> jstring_url =
264 ConvertUTF8ToJavaString(env, location.spec());
265 ScopedJavaLocalRef<jstring> jstring_method =
266 ConvertUTF8ToJavaString(env, request->method());
267 ScopedJavaLocalRef<jobjectArray> jstringArray_headers_names =
268 ToJavaArrayOfStrings(env, headers_names);
269 ScopedJavaLocalRef<jobjectArray> jstringArray_headers_values =
270 ToJavaArrayOfStrings(env, headers_values);
271 devtools_instrumentation::ScopedEmbedderCallbackTask embedder_callback(
272 "shouldInterceptRequest");
273 ScopedJavaLocalRef<jobject> ret =
274 Java_AwContentsIoThreadClient_shouldInterceptRequest(
275 env,
276 java_object_.obj(),
277 jstring_url.obj(),
278 is_main_frame,
279 has_user_gesture,
280 jstring_method.obj(),
281 jstringArray_headers_names.obj(),
282 jstringArray_headers_values.obj());
283 if (ret.is_null())
284 return scoped_ptr<AwWebResourceResponse>();
285 return scoped_ptr<AwWebResourceResponse>(
286 new AwWebResourceResponseImpl(ret));
289 bool AwContentsIoThreadClientImpl::ShouldBlockContentUrls() const {
290 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
291 if (java_object_.is_null())
292 return false;
294 JNIEnv* env = AttachCurrentThread();
295 return Java_AwContentsIoThreadClient_shouldBlockContentUrls(
296 env, java_object_.obj());
299 bool AwContentsIoThreadClientImpl::ShouldBlockFileUrls() const {
300 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
301 if (java_object_.is_null())
302 return false;
304 JNIEnv* env = AttachCurrentThread();
305 return Java_AwContentsIoThreadClient_shouldBlockFileUrls(
306 env, java_object_.obj());
309 bool AwContentsIoThreadClientImpl::ShouldAcceptThirdPartyCookies() const {
310 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
311 if (java_object_.is_null())
312 return false;
314 JNIEnv* env = AttachCurrentThread();
315 return Java_AwContentsIoThreadClient_shouldAcceptThirdPartyCookies(
316 env, java_object_.obj());
319 bool AwContentsIoThreadClientImpl::ShouldBlockNetworkLoads() const {
320 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
321 if (java_object_.is_null())
322 return false;
324 JNIEnv* env = AttachCurrentThread();
325 return Java_AwContentsIoThreadClient_shouldBlockNetworkLoads(
326 env, java_object_.obj());
329 void AwContentsIoThreadClientImpl::NewDownload(
330 const GURL& url,
331 const string& user_agent,
332 const string& content_disposition,
333 const string& mime_type,
334 int64 content_length) {
335 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
336 if (java_object_.is_null())
337 return;
339 JNIEnv* env = AttachCurrentThread();
340 ScopedJavaLocalRef<jstring> jstring_url =
341 ConvertUTF8ToJavaString(env, url.spec());
342 ScopedJavaLocalRef<jstring> jstring_user_agent =
343 ConvertUTF8ToJavaString(env, user_agent);
344 ScopedJavaLocalRef<jstring> jstring_content_disposition =
345 ConvertUTF8ToJavaString(env, content_disposition);
346 ScopedJavaLocalRef<jstring> jstring_mime_type =
347 ConvertUTF8ToJavaString(env, mime_type);
349 Java_AwContentsIoThreadClient_onDownloadStart(
350 env,
351 java_object_.obj(),
352 jstring_url.obj(),
353 jstring_user_agent.obj(),
354 jstring_content_disposition.obj(),
355 jstring_mime_type.obj(),
356 content_length);
359 void AwContentsIoThreadClientImpl::NewLoginRequest(const string& realm,
360 const string& account,
361 const string& args) {
362 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
363 if (java_object_.is_null())
364 return;
366 JNIEnv* env = AttachCurrentThread();
367 ScopedJavaLocalRef<jstring> jrealm = ConvertUTF8ToJavaString(env, realm);
368 ScopedJavaLocalRef<jstring> jargs = ConvertUTF8ToJavaString(env, args);
370 ScopedJavaLocalRef<jstring> jaccount;
371 if (!account.empty())
372 jaccount = ConvertUTF8ToJavaString(env, account);
374 Java_AwContentsIoThreadClient_newLoginRequest(
375 env, java_object_.obj(), jrealm.obj(), jaccount.obj(), jargs.obj());
378 bool RegisterAwContentsIoThreadClientImpl(JNIEnv* env) {
379 return RegisterNativesImpl(env);
382 } // namespace android_webview