| OLD | NEW |
| (Empty) | |
| 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 "content/browser/android/download_controller.h" |
| 6 |
| 7 #include "base/android/jni_android.h" |
| 8 #include "base/android/jni_string.h" |
| 9 #include "base/bind.h" |
| 10 #include "base/logging.h" |
| 11 #include "base/memory/scoped_ptr.h" |
| 12 #include "content/browser/download/download_item_impl.h" |
| 13 #include "content/browser/renderer_host/render_process_host_impl.h" |
| 14 #include "content/browser/renderer_host/render_view_host_delegate.h" |
| 15 #include "content/browser/renderer_host/render_view_host_impl.h" |
| 16 #include "content/browser/renderer_host/resource_dispatcher_host_impl.h" |
| 17 #include "content/browser/web_contents/web_contents_impl.h" |
| 18 #include "content/public/browser/browser_thread.h" |
| 19 #include "content/public/browser/global_request_id.h" |
| 20 #include "jni/download_controller_jni.h" |
| 21 #include "net/cookies/cookie_options.h" |
| 22 #include "net/cookies/cookie_store.h" |
| 23 #include "net/http/http_request_headers.h" |
| 24 #include "net/url_request/url_request.h" |
| 25 #include "net/url_request/url_request_context.h" |
| 26 |
| 27 using base::android::AttachCurrentThread; |
| 28 using base::android::CheckException; |
| 29 using base::android::ConvertUTF8ToJavaString; |
| 30 using base::android::GetClass; |
| 31 using base::android::ScopedJavaLocalRef; |
| 32 |
| 33 // JNI methods |
| 34 static void Init(JNIEnv* env, jobject obj) { |
| 35 content::DownloadController::GetInstance()->Init(env, obj); |
| 36 } |
| 37 |
| 38 namespace { |
| 39 const char* kDownloadControllerClassPathName = |
| 40 "org/chromium/content/browser/DownloadController"; |
| 41 } // namespace |
| 42 |
| 43 namespace content { |
| 44 |
| 45 struct DownloadController::JavaObject { |
| 46 ScopedJavaLocalRef<jobject> Controller(JNIEnv* env) { |
| 47 return GetRealObject(env, obj); |
| 48 } |
| 49 jweak obj; |
| 50 }; |
| 51 |
| 52 // static |
| 53 bool DownloadController::RegisterDownloadController(JNIEnv* env) { |
| 54 return RegisterNativesImpl(env); |
| 55 } |
| 56 |
| 57 DownloadController* DownloadController::GetInstance() { |
| 58 return Singleton<DownloadController>::get(); |
| 59 } |
| 60 |
| 61 DownloadController::DownloadController() |
| 62 : java_object_(NULL) { |
| 63 } |
| 64 |
| 65 DownloadController::~DownloadController() { |
| 66 if (java_object_) { |
| 67 JNIEnv* env = AttachCurrentThread(); |
| 68 env->DeleteWeakGlobalRef(java_object_->obj); |
| 69 delete java_object_; |
| 70 CheckException(env); |
| 71 } |
| 72 } |
| 73 |
| 74 // Initialize references to Java object. |
| 75 void DownloadController::Init(JNIEnv* env, jobject obj) { |
| 76 java_object_ = new JavaObject; |
| 77 java_object_->obj = env->NewWeakGlobalRef(obj); |
| 78 } |
| 79 |
| 80 void DownloadController::CreateGETDownload( |
| 81 RenderViewHost* render_view_host, |
| 82 int request_id) { |
| 83 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 84 int render_process_id = render_view_host->GetProcess()->GetID(); |
| 85 GlobalRequestID global_id(render_process_id, request_id); |
| 86 |
| 87 // We are yielding the UI thread and render_view_host may go away by |
| 88 // the time we come back. Pass along render_process_id and render_view_id |
| 89 // to retrieve it later (if it still exists). |
| 90 BrowserThread::PostTask( |
| 91 BrowserThread::IO, FROM_HERE, |
| 92 base::Bind(&DownloadController::PrepareDownloadInfo, |
| 93 base::Unretained(this), global_id, |
| 94 render_process_id, |
| 95 render_view_host->GetRoutingID())); |
| 96 } |
| 97 |
| 98 void DownloadController::PrepareDownloadInfo( |
| 99 const GlobalRequestID& global_id, |
| 100 int render_process_id, int render_view_id) { |
| 101 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| 102 |
| 103 net::URLRequest* request = |
| 104 ResourceDispatcherHostImpl::Get()->GetURLRequest(global_id); |
| 105 DCHECK(request) << "Request to download not found."; |
| 106 |
| 107 DownloadInfoAndroid info_android(request); |
| 108 |
| 109 net::CookieStore* cookie_store = request->context()->cookie_store(); |
| 110 if (cookie_store) { |
| 111 net::CookieMonster* cookie_monster = cookie_store->GetCookieMonster(); |
| 112 if (cookie_monster) { |
| 113 cookie_monster->GetAllCookiesForURLAsync( |
| 114 request->url(), |
| 115 base::Bind(&DownloadController::CheckPolicyAndLoadCookies, |
| 116 base::Unretained(this), info_android, render_process_id, |
| 117 render_view_id, global_id)); |
| 118 } else { |
| 119 DoLoadCookies( |
| 120 info_android, render_process_id, render_view_id, global_id); |
| 121 } |
| 122 } else { |
| 123 // Can't get any cookies, start android download. |
| 124 StartAndroidDownload(info_android, render_process_id, render_view_id); |
| 125 } |
| 126 } |
| 127 |
| 128 void DownloadController::CheckPolicyAndLoadCookies( |
| 129 const DownloadInfoAndroid& info, int render_process_id, |
| 130 int render_view_id, const GlobalRequestID& global_id, |
| 131 const net::CookieList& cookie_list) { |
| 132 net::URLRequest* request = |
| 133 ResourceDispatcherHostImpl::Get()->GetURLRequest(global_id); |
| 134 DCHECK(request) << "Request to download not found."; |
| 135 |
| 136 if (request->context()->network_delegate()->CanGetCookies( |
| 137 *request, cookie_list)) { |
| 138 DoLoadCookies(info, render_process_id, render_view_id, global_id); |
| 139 } else { |
| 140 StartAndroidDownload(info, render_process_id, render_view_id); |
| 141 } |
| 142 } |
| 143 |
| 144 void DownloadController::DoLoadCookies( |
| 145 const DownloadInfoAndroid& info, int render_process_id, |
| 146 int render_view_id, const GlobalRequestID& global_id) { |
| 147 net::CookieOptions options; |
| 148 options.set_include_httponly(); |
| 149 |
| 150 net::URLRequest* request = |
| 151 ResourceDispatcherHostImpl::Get()->GetURLRequest(global_id); |
| 152 DCHECK(request) << "Request to download not found."; |
| 153 |
| 154 request->context()->cookie_store()->GetCookiesWithOptionsAsync( |
| 155 info.url, options, |
| 156 base::Bind(&DownloadController::OnCookieResponse, |
| 157 base::Unretained(this), info, render_process_id, |
| 158 render_view_id)); |
| 159 } |
| 160 |
| 161 void DownloadController::OnCookieResponse(DownloadInfoAndroid download_info, |
| 162 int render_process_id, |
| 163 int render_view_id, |
| 164 const std::string& cookie) { |
| 165 download_info.cookie = cookie; |
| 166 |
| 167 // We have everything we need, start Android download. |
| 168 StartAndroidDownload(download_info, render_process_id, render_view_id); |
| 169 } |
| 170 |
| 171 void DownloadController::StartAndroidDownload( |
| 172 const DownloadInfoAndroid& info, |
| 173 int render_process_id, |
| 174 int render_view_id) { |
| 175 // Call ourself on the UI thread if not already on it. |
| 176 if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) { |
| 177 BrowserThread::PostTask( |
| 178 BrowserThread::UI, FROM_HERE, |
| 179 base::Bind(&DownloadController::StartAndroidDownload, |
| 180 base::Unretained(this), info, render_process_id, |
| 181 render_view_id)); |
| 182 return; |
| 183 } |
| 184 |
| 185 JNIEnv* env = AttachCurrentThread(); |
| 186 |
| 187 // Call newHttpGetDownload |
| 188 jobject view = GetContentView(render_process_id, render_view_id); |
| 189 if (!view) { |
| 190 // The view went away. Can't proceed. |
| 191 LOG(ERROR) << "Download failed on URL:" << info.url.spec(); |
| 192 return; |
| 193 } |
| 194 |
| 195 ScopedJavaLocalRef<jstring> jurl = |
| 196 ConvertUTF8ToJavaString(env, info.url.spec()); |
| 197 ScopedJavaLocalRef<jstring> juser_agent = |
| 198 ConvertUTF8ToJavaString(env, info.user_agent); |
| 199 ScopedJavaLocalRef<jstring> jcontent_disposition = |
| 200 ConvertUTF8ToJavaString(env, info.content_disposition); |
| 201 ScopedJavaLocalRef<jstring> jmime_type = |
| 202 ConvertUTF8ToJavaString(env, info.original_mime_type); |
| 203 ScopedJavaLocalRef<jstring> jcookie = |
| 204 ConvertUTF8ToJavaString(env, info.cookie); |
| 205 |
| 206 Java_DownloadController_newHttpGetDownload( |
| 207 env, GetJavaObject()->Controller(env).obj(), view, jurl.obj(), |
| 208 juser_agent.obj(), jcontent_disposition.obj(), jmime_type.obj(), |
| 209 jcookie.obj(), info.total_bytes); |
| 210 } |
| 211 |
| 212 void DownloadController::OnPostDownloadStarted( |
| 213 WebContents* web_contents, |
| 214 DownloadItem* download_item) { |
| 215 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 216 JNIEnv* env = AttachCurrentThread(); |
| 217 |
| 218 // Register for updates to the DownloadItem. |
| 219 download_item->AddObserver(this); |
| 220 |
| 221 jobject view = GetContentViewFromWebContents(web_contents); |
| 222 if(!view) { |
| 223 // The view went away. Can't proceed. |
| 224 return; |
| 225 } |
| 226 |
| 227 Java_DownloadController_onHttpPostDownloadStarted( |
| 228 env, GetJavaObject()->Controller(env).obj(), view); |
| 229 } |
| 230 |
| 231 void DownloadController::OnDownloadUpdated(DownloadItem* item) { |
| 232 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 233 |
| 234 if (item->GetState() != DownloadItem::COMPLETE) |
| 235 return; |
| 236 |
| 237 // Call onHttpPostDownloadCompleted |
| 238 JNIEnv* env = AttachCurrentThread(); |
| 239 ScopedJavaLocalRef<jstring> jurl = |
| 240 ConvertUTF8ToJavaString(env, item->GetURL().spec()); |
| 241 ScopedJavaLocalRef<jstring> jcontent_disposition = |
| 242 ConvertUTF8ToJavaString(env, item->GetContentDisposition()); |
| 243 ScopedJavaLocalRef<jstring> jmime_type = |
| 244 ConvertUTF8ToJavaString(env, item->GetMimeType()); |
| 245 ScopedJavaLocalRef<jstring> jpath = |
| 246 ConvertUTF8ToJavaString(env, item->GetFullPath().value()); |
| 247 |
| 248 jobject view = GetContentViewFromWebContents(item->GetWebContents()); |
| 249 if(!view) { |
| 250 // We can get NULL WebContents from the DownloadItem. |
| 251 return; |
| 252 } |
| 253 |
| 254 Java_DownloadController_onHttpPostDownloadCompleted(env, |
| 255 GetJavaObject()->Controller(env).obj(), view, jurl.obj(), |
| 256 jcontent_disposition.obj(), jmime_type.obj(), jpath.obj(), |
| 257 item->GetReceivedBytes(), true); |
| 258 } |
| 259 |
| 260 void DownloadController::OnDownloadOpened(DownloadItem* item) { |
| 261 } |
| 262 |
| 263 jobject DownloadController::GetContentView(int render_process_id, |
| 264 int render_view_id) { |
| 265 RenderViewHost* render_view_host = |
| 266 RenderViewHost::FromID(render_process_id, render_view_id); |
| 267 |
| 268 if (!render_view_host) |
| 269 return NULL; |
| 270 |
| 271 WebContents* web_contents = |
| 272 render_view_host->GetDelegate()->GetAsWebContents(); |
| 273 |
| 274 if (!web_contents) |
| 275 return NULL; |
| 276 |
| 277 return GetContentViewFromWebContents(web_contents); |
| 278 } |
| 279 |
| 280 jobject DownloadController::GetContentViewFromWebContents( |
| 281 WebContents* web_contents) { |
| 282 NOTIMPLEMENTED(); |
| 283 return NULL; |
| 284 } |
| 285 |
| 286 DownloadController::JavaObject* DownloadController::GetJavaObject() { |
| 287 if (!java_object_) { |
| 288 // Initialize Java DownloadController by calling |
| 289 // DownloadController.getInstance(), which will call Init() |
| 290 // if Java DownloadController is not instantiated already. |
| 291 JNIEnv* env = AttachCurrentThread(); |
| 292 ScopedJavaLocalRef<jclass> clazz = |
| 293 GetClass(env, kDownloadControllerClassPathName); |
| 294 jmethodID get_instance = GetStaticMethodID(env, clazz, "getInstance", |
| 295 "()Lorg/chromium/content/browser/DownloadController;"); |
| 296 ScopedJavaLocalRef<jobject> jobj(env, |
| 297 env->CallStaticObjectMethod(clazz.obj(), get_instance)); |
| 298 CheckException(env); |
| 299 } |
| 300 |
| 301 DCHECK(java_object_); |
| 302 return java_object_; |
| 303 } |
| 304 |
| 305 DownloadController::DownloadInfoAndroid::DownloadInfoAndroid( |
| 306 net::URLRequest* request) { |
| 307 request->GetResponseHeaderByName("content-disposition", &content_disposition); |
| 308 request->GetResponseHeaderByName("mime-type", &original_mime_type); |
| 309 request->extra_request_headers().GetHeader( |
| 310 net::HttpRequestHeaders::kUserAgent, |
| 311 &user_agent); |
| 312 if (!request->url_chain().empty()) { |
| 313 original_url = request->url_chain().front(); |
| 314 url = request->url_chain().back(); |
| 315 } |
| 316 } |
| 317 |
| 318 } // namespace content |
| OLD | NEW |