Home | History | Annotate | Download | only in android
      1 // Copyright 2013 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/media/android/media_resource_getter_impl.h"
      6 
      7 #include "base/android/jni_android.h"
      8 #include "base/android/jni_string.h"
      9 #include "base/bind.h"
     10 #include "base/path_service.h"
     11 #include "base/threading/sequenced_worker_pool.h"
     12 #include "content/browser/child_process_security_policy_impl.h"
     13 #include "content/browser/fileapi/browser_file_system_helper.h"
     14 #include "content/browser/fileapi/chrome_blob_storage_context.h"
     15 #include "content/public/browser/browser_context.h"
     16 #include "content/public/browser/browser_thread.h"
     17 #include "content/public/browser/content_browser_client.h"
     18 #include "content/public/common/content_client.h"
     19 #include "content/public/common/url_constants.h"
     20 #include "jni/MediaResourceGetter_jni.h"
     21 #include "media/base/android/media_url_interceptor.h"
     22 #include "net/base/auth.h"
     23 #include "net/cookies/cookie_monster.h"
     24 #include "net/cookies/cookie_store.h"
     25 #include "net/url_request/url_request_context.h"
     26 #include "net/url_request/url_request_context_getter.h"
     27 #include "url/gurl.h"
     28 #include "webkit/browser/blob/blob_data_handle.h"
     29 #include "webkit/browser/blob/blob_storage_context.h"
     30 
     31 using base::android::ConvertUTF8ToJavaString;
     32 using base::android::ScopedJavaLocalRef;
     33 
     34 namespace content {
     35 
     36 static void ReturnResultOnUIThread(
     37     const base::Callback<void(const std::string&)>& callback,
     38     const std::string& result) {
     39   BrowserThread::PostTask(
     40       BrowserThread::UI, FROM_HERE, base::Bind(callback, result));
     41 }
     42 
     43 static void RequestPlatformPathFromBlobURL(
     44     const GURL& url,
     45     BrowserContext* browser_context,
     46     const base::Callback<void(const std::string&)>& callback) {
     47   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
     48   ChromeBlobStorageContext* context =
     49       ChromeBlobStorageContext::GetFor(browser_context);
     50   scoped_ptr<webkit_blob::BlobDataHandle> handle =
     51       context->context()->GetBlobDataFromPublicURL(url);
     52   const std::vector<webkit_blob::BlobData::Item> items =
     53       handle->data()->items();
     54 
     55   // TODO(qinmin): handle the case when the blob data is not a single file.
     56   DLOG_IF(WARNING, items.size() != 1u)
     57       << "More than one blob data are present: " << items.size();
     58   ReturnResultOnUIThread(callback, items[0].path().value());
     59 }
     60 
     61 static void RequestPlaformPathFromFileSystemURL(
     62     const GURL& url,
     63     int render_process_id,
     64     scoped_refptr<fileapi::FileSystemContext> file_system_context,
     65     const base::Callback<void(const std::string&)>& callback) {
     66   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
     67   base::FilePath platform_path;
     68   SyncGetPlatformPath(file_system_context.get(),
     69                       render_process_id,
     70                       url,
     71                       &platform_path);
     72   base::FilePath data_storage_path;
     73   PathService::Get(base::DIR_ANDROID_APP_DATA, &data_storage_path);
     74   if (data_storage_path.IsParent(platform_path))
     75     ReturnResultOnUIThread(callback, platform_path.value());
     76   else
     77     ReturnResultOnUIThread(callback, std::string());
     78 }
     79 
     80 // Posts a task to the UI thread to run the callback function.
     81 static void PostMediaMetadataCallbackTask(
     82     const media::MediaResourceGetter::ExtractMediaMetadataCB& callback,
     83     JNIEnv* env, ScopedJavaLocalRef<jobject>& j_metadata) {
     84   BrowserThread::PostTask(
     85         BrowserThread::UI, FROM_HERE,
     86         base::Bind(callback, base::TimeDelta::FromMilliseconds(
     87                        Java_MediaMetadata_getDurationInMilliseconds(
     88                            env, j_metadata.obj())),
     89                    Java_MediaMetadata_getWidth(env, j_metadata.obj()),
     90                    Java_MediaMetadata_getHeight(env, j_metadata.obj()),
     91                    Java_MediaMetadata_isSuccess(env, j_metadata.obj())));
     92 }
     93 
     94 // Gets the metadata from a media URL. When finished, a task is posted to the UI
     95 // thread to run the callback function.
     96 static void GetMediaMetadata(
     97     const std::string& url, const std::string& cookies,
     98     const std::string& user_agent,
     99     const media::MediaResourceGetter::ExtractMediaMetadataCB& callback) {
    100   JNIEnv* env = base::android::AttachCurrentThread();
    101 
    102   ScopedJavaLocalRef<jstring> j_url_string = ConvertUTF8ToJavaString(env, url);
    103   ScopedJavaLocalRef<jstring> j_cookies = ConvertUTF8ToJavaString(env, cookies);
    104   jobject j_context = base::android::GetApplicationContext();
    105   ScopedJavaLocalRef<jstring> j_user_agent = ConvertUTF8ToJavaString(
    106       env, user_agent);
    107   ScopedJavaLocalRef<jobject> j_metadata =
    108       Java_MediaResourceGetter_extractMediaMetadata(env,
    109                                                     j_context,
    110                                                     j_url_string.obj(),
    111                                                     j_cookies.obj(),
    112                                                     j_user_agent.obj());
    113 
    114   PostMediaMetadataCallbackTask(callback, env, j_metadata);
    115 }
    116 
    117 // Gets the metadata from a file descriptor. When finished, a task is posted to
    118 // the UI thread to run the callback function.
    119 static void GetMediaMetadataFromFd(
    120     const int fd, const int64 offset, const int64 size,
    121     const media::MediaResourceGetter::ExtractMediaMetadataCB& callback) {
    122   JNIEnv* env = base::android::AttachCurrentThread();
    123 
    124   ScopedJavaLocalRef<jobject> j_metadata =
    125       Java_MediaResourceGetter_extractMediaMetadataFromFd(
    126           env, fd, offset, size);
    127 
    128   PostMediaMetadataCallbackTask(callback, env, j_metadata);
    129 }
    130 
    131 // The task object that retrieves cookie on the IO thread.
    132 // TODO(qinmin): refactor this class to make the code reusable by others as
    133 // there are lots of duplicated functionalities elsewhere.
    134 class CookieGetterTask
    135      : public base::RefCountedThreadSafe<CookieGetterTask> {
    136  public:
    137   CookieGetterTask(BrowserContext* browser_context,
    138                    int render_process_id, int render_frame_id);
    139 
    140   // Called by CookieGetterImpl to start getting cookies for a URL.
    141   void RequestCookies(
    142       const GURL& url, const GURL& first_party_for_cookies,
    143       const media::MediaResourceGetter::GetCookieCB& callback);
    144 
    145  private:
    146   friend class base::RefCountedThreadSafe<CookieGetterTask>;
    147   virtual ~CookieGetterTask();
    148 
    149   void CheckPolicyForCookies(
    150       const GURL& url, const GURL& first_party_for_cookies,
    151       const media::MediaResourceGetter::GetCookieCB& callback,
    152       const net::CookieList& cookie_list);
    153 
    154   // Context getter used to get the CookieStore.
    155   net::URLRequestContextGetter* context_getter_;
    156 
    157   // Resource context for checking cookie policies.
    158   ResourceContext* resource_context_;
    159 
    160   // Render process id, used to check whether the process can access cookies.
    161   int render_process_id_;
    162 
    163   // Render frame id, used to check tab specific cookie policy.
    164   int render_frame_id_;
    165 
    166   DISALLOW_COPY_AND_ASSIGN(CookieGetterTask);
    167 };
    168 
    169 CookieGetterTask::CookieGetterTask(
    170     BrowserContext* browser_context, int render_process_id, int render_frame_id)
    171     : context_getter_(browser_context->GetRequestContext()),
    172       resource_context_(browser_context->GetResourceContext()),
    173       render_process_id_(render_process_id),
    174       render_frame_id_(render_frame_id) {
    175 }
    176 
    177 CookieGetterTask::~CookieGetterTask() {}
    178 
    179 void CookieGetterTask::RequestCookies(
    180     const GURL& url, const GURL& first_party_for_cookies,
    181     const media::MediaResourceGetter::GetCookieCB& callback) {
    182   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    183   ChildProcessSecurityPolicyImpl* policy =
    184       ChildProcessSecurityPolicyImpl::GetInstance();
    185   if (!policy->CanAccessCookiesForOrigin(render_process_id_, url)) {
    186     callback.Run(std::string());
    187     return;
    188   }
    189 
    190   net::CookieStore* cookie_store =
    191       context_getter_->GetURLRequestContext()->cookie_store();
    192   if (!cookie_store) {
    193     callback.Run(std::string());
    194     return;
    195   }
    196 
    197   net::CookieMonster* cookie_monster = cookie_store->GetCookieMonster();
    198   if (cookie_monster) {
    199     cookie_monster->GetAllCookiesForURLAsync(url, base::Bind(
    200         &CookieGetterTask::CheckPolicyForCookies, this,
    201         url, first_party_for_cookies, callback));
    202   } else {
    203     callback.Run(std::string());
    204   }
    205 }
    206 
    207 void CookieGetterTask::CheckPolicyForCookies(
    208     const GURL& url, const GURL& first_party_for_cookies,
    209     const media::MediaResourceGetter::GetCookieCB& callback,
    210     const net::CookieList& cookie_list) {
    211   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    212   if (GetContentClient()->browser()->AllowGetCookie(
    213       url, first_party_for_cookies, cookie_list,
    214       resource_context_, render_process_id_, render_frame_id_)) {
    215     net::CookieStore* cookie_store =
    216         context_getter_->GetURLRequestContext()->cookie_store();
    217     cookie_store->GetCookiesWithOptionsAsync(
    218         url, net::CookieOptions(), callback);
    219   } else {
    220     callback.Run(std::string());
    221   }
    222 }
    223 
    224 MediaResourceGetterImpl::MediaResourceGetterImpl(
    225     BrowserContext* browser_context,
    226     fileapi::FileSystemContext* file_system_context,
    227     int render_process_id,
    228     int render_frame_id)
    229     : browser_context_(browser_context),
    230       file_system_context_(file_system_context),
    231       render_process_id_(render_process_id),
    232       render_frame_id_(render_frame_id),
    233       weak_factory_(this) {}
    234 
    235 MediaResourceGetterImpl::~MediaResourceGetterImpl() {}
    236 
    237 void MediaResourceGetterImpl::GetCookies(
    238     const GURL& url, const GURL& first_party_for_cookies,
    239     const GetCookieCB& callback) {
    240   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    241   scoped_refptr<CookieGetterTask> task = new CookieGetterTask(
    242       browser_context_, render_process_id_, render_frame_id_);
    243 
    244   GetCookieCB cb = base::Bind(&MediaResourceGetterImpl::GetCookiesCallback,
    245                               weak_factory_.GetWeakPtr(),
    246                               callback);
    247   BrowserThread::PostTask(
    248       BrowserThread::IO,
    249       FROM_HERE,
    250       base::Bind(&CookieGetterTask::RequestCookies,
    251                  task, url, first_party_for_cookies,
    252                  base::Bind(&ReturnResultOnUIThread, cb)));
    253 }
    254 
    255 void MediaResourceGetterImpl::GetCookiesCallback(
    256     const GetCookieCB& callback, const std::string& cookies) {
    257   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    258   callback.Run(cookies);
    259 }
    260 
    261 void MediaResourceGetterImpl::GetPlatformPathFromURL(
    262     const GURL& url, const GetPlatformPathCB& callback) {
    263   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    264   DCHECK(url.SchemeIsFileSystem() || url.SchemeIs(url::kBlobScheme));
    265 
    266   GetPlatformPathCB cb =
    267       base::Bind(&MediaResourceGetterImpl::GetPlatformPathCallback,
    268                  weak_factory_.GetWeakPtr(),
    269                  callback);
    270 
    271   if (url.SchemeIs(url::kBlobScheme)) {
    272     BrowserThread::PostTask(
    273         BrowserThread::IO,
    274         FROM_HERE,
    275         base::Bind(&RequestPlatformPathFromBlobURL, url, browser_context_, cb));
    276     return;
    277   }
    278 
    279   scoped_refptr<fileapi::FileSystemContext> context(file_system_context_);
    280   BrowserThread::PostTask(
    281       BrowserThread::FILE,
    282       FROM_HERE,
    283       base::Bind(&RequestPlaformPathFromFileSystemURL, url, render_process_id_,
    284                  context, cb));
    285 }
    286 
    287 void MediaResourceGetterImpl::GetPlatformPathCallback(
    288     const GetPlatformPathCB& callback, const std::string& platform_path) {
    289   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    290   callback.Run(platform_path);
    291 }
    292 
    293 void MediaResourceGetterImpl::ExtractMediaMetadata(
    294     const std::string& url, const std::string& cookies,
    295     const std::string& user_agent, const ExtractMediaMetadataCB& callback) {
    296   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    297   base::SequencedWorkerPool* pool = content::BrowserThread::GetBlockingPool();
    298   pool->PostWorkerTask(
    299       FROM_HERE,
    300       base::Bind(&GetMediaMetadata, url, cookies, user_agent, callback));
    301 }
    302 
    303 void MediaResourceGetterImpl::ExtractMediaMetadata(
    304     const int fd, const int64 offset, const int64 size,
    305     const ExtractMediaMetadataCB& callback) {
    306   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    307   base::SequencedWorkerPool* pool = content::BrowserThread::GetBlockingPool();
    308   pool->PostWorkerTask(
    309       FROM_HERE,
    310       base::Bind(&GetMediaMetadataFromFd, fd, offset, size, callback));
    311 }
    312 
    313 // static
    314 bool MediaResourceGetterImpl::RegisterMediaResourceGetter(JNIEnv* env) {
    315   return RegisterNativesImpl(env);
    316 }
    317 
    318 }  // namespace content
    319