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