Commit 20bd0b28 authored by qinmin@chromium.org's avatar qinmin@chromium.org

Support basic authentication for html5 media

This change passes the basic auth information to android mediaplayer to solve the issue that media with basic auth is not able to play.
Previously MediaInfoLoader and MediaResourceGetter could be ran at the same time. 
However, MediaResourceGetter could miss the credential info if we do that. 
As a result, we should wait until MediaInfoLoader finishes before creating the browser side MediaPlayer.

BUG=319885

Review URL: https://codereview.chromium.org/405663002

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@284535 0039d316-1c4b-4281-b951-d872f2087c98
parent 370c7838
......@@ -18,8 +18,11 @@
#include "content/public/common/content_client.h"
#include "content/public/common/url_constants.h"
#include "jni/MediaResourceGetter_jni.h"
#include "net/base/auth.h"
#include "net/cookies/cookie_monster.h"
#include "net/cookies/cookie_store.h"
#include "net/http/http_auth.h"
#include "net/http/http_transaction_factory.h"
#include "net/url_request/url_request_context.h"
#include "net/url_request/url_request_context_getter.h"
#include "url/gurl.h"
......@@ -104,30 +107,34 @@ static void GetMediaMetadata(
Java_MediaMetadata_isSuccess(env, j_metadata.obj())));
}
// The task object that retrieves cookie on the IO thread.
// The task object that retrieves media resources on the IO thread.
// TODO(qinmin): refactor this class to make the code reusable by others as
// there are lots of duplicated functionalities elsewhere.
class CookieGetterTask
: public base::RefCountedThreadSafe<CookieGetterTask> {
// http://crbug.com/395762.
class MediaResourceGetterTask
: public base::RefCountedThreadSafe<MediaResourceGetterTask> {
public:
CookieGetterTask(BrowserContext* browser_context,
int render_process_id, int render_frame_id);
MediaResourceGetterTask(BrowserContext* browser_context,
int render_process_id, int render_frame_id);
// Called by CookieGetterImpl to start getting cookies for a URL.
// Called by MediaResourceGetterImpl to start getting auth credentials.
net::AuthCredentials RequestAuthCredentials(const GURL& url) const;
// Called by MediaResourceGetterImpl to start getting cookies for a URL.
void RequestCookies(
const GURL& url, const GURL& first_party_for_cookies,
const media::MediaResourceGetter::GetCookieCB& callback);
private:
friend class base::RefCountedThreadSafe<CookieGetterTask>;
virtual ~CookieGetterTask();
friend class base::RefCountedThreadSafe<MediaResourceGetterTask>;
virtual ~MediaResourceGetterTask();
void CheckPolicyForCookies(
const GURL& url, const GURL& first_party_for_cookies,
const media::MediaResourceGetter::GetCookieCB& callback,
const net::CookieList& cookie_list);
// Context getter used to get the CookieStore.
// Context getter used to get the CookieStore and auth cache.
net::URLRequestContextGetter* context_getter_;
// Resource context for checking cookie policies.
......@@ -139,10 +146,10 @@ class CookieGetterTask
// Render frame id, used to check tab specific cookie policy.
int render_frame_id_;
DISALLOW_COPY_AND_ASSIGN(CookieGetterTask);
DISALLOW_COPY_AND_ASSIGN(MediaResourceGetterTask);
};
CookieGetterTask::CookieGetterTask(
MediaResourceGetterTask::MediaResourceGetterTask(
BrowserContext* browser_context, int render_process_id, int render_frame_id)
: context_getter_(browser_context->GetRequestContext()),
resource_context_(browser_context->GetResourceContext()),
......@@ -150,9 +157,32 @@ CookieGetterTask::CookieGetterTask(
render_frame_id_(render_frame_id) {
}
CookieGetterTask::~CookieGetterTask() {}
MediaResourceGetterTask::~MediaResourceGetterTask() {}
void CookieGetterTask::RequestCookies(
net::AuthCredentials MediaResourceGetterTask::RequestAuthCredentials(
const GURL& url) const {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
net::HttpTransactionFactory* factory =
context_getter_->GetURLRequestContext()->http_transaction_factory();
if (!factory)
return net::AuthCredentials();
net::HttpAuthCache* auth_cache =
factory->GetSession()->http_auth_cache();
if (!auth_cache)
return net::AuthCredentials();
net::HttpAuthCache::Entry* entry =
auth_cache->LookupByPath(url.GetOrigin(), url.path());
// TODO(qinmin): handle other auth schemes. See http://crbug.com/395219.
if (entry && entry->scheme() == net::HttpAuth::AUTH_SCHEME_BASIC)
return entry->credentials();
else
return net::AuthCredentials();
}
void MediaResourceGetterTask::RequestCookies(
const GURL& url, const GURL& first_party_for_cookies,
const media::MediaResourceGetter::GetCookieCB& callback) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
......@@ -173,14 +203,14 @@ void CookieGetterTask::RequestCookies(
net::CookieMonster* cookie_monster = cookie_store->GetCookieMonster();
if (cookie_monster) {
cookie_monster->GetAllCookiesForURLAsync(url, base::Bind(
&CookieGetterTask::CheckPolicyForCookies, this,
&MediaResourceGetterTask::CheckPolicyForCookies, this,
url, first_party_for_cookies, callback));
} else {
callback.Run(std::string());
}
}
void CookieGetterTask::CheckPolicyForCookies(
void MediaResourceGetterTask::CheckPolicyForCookies(
const GURL& url, const GURL& first_party_for_cookies,
const media::MediaResourceGetter::GetCookieCB& callback,
const net::CookieList& cookie_list) {
......@@ -211,11 +241,25 @@ MediaResourceGetterImpl::MediaResourceGetterImpl(
MediaResourceGetterImpl::~MediaResourceGetterImpl() {}
void MediaResourceGetterImpl::GetAuthCredentials(
const GURL& url, const GetAuthCredentialsCB& callback) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
scoped_refptr<MediaResourceGetterTask> task = new MediaResourceGetterTask(
browser_context_, 0, 0);
BrowserThread::PostTaskAndReplyWithResult(
BrowserThread::IO,
FROM_HERE,
base::Bind(&MediaResourceGetterTask::RequestAuthCredentials, task, url),
base::Bind(&MediaResourceGetterImpl::GetAuthCredentialsCallback,
weak_factory_.GetWeakPtr(), callback));
}
void MediaResourceGetterImpl::GetCookies(
const GURL& url, const GURL& first_party_for_cookies,
const GetCookieCB& callback) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
scoped_refptr<CookieGetterTask> task = new CookieGetterTask(
scoped_refptr<MediaResourceGetterTask> task = new MediaResourceGetterTask(
browser_context_, render_process_id_, render_frame_id_);
GetCookieCB cb = base::Bind(&MediaResourceGetterImpl::GetCookiesCallback,
......@@ -224,11 +268,18 @@ void MediaResourceGetterImpl::GetCookies(
BrowserThread::PostTask(
BrowserThread::IO,
FROM_HERE,
base::Bind(&CookieGetterTask::RequestCookies,
base::Bind(&MediaResourceGetterTask::RequestCookies,
task, url, first_party_for_cookies,
base::Bind(&ReturnResultOnUIThread, cb)));
}
void MediaResourceGetterImpl::GetAuthCredentialsCallback(
const GetAuthCredentialsCB& callback,
const net::AuthCredentials& credentials) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
callback.Run(credentials.username(), credentials.password());
}
void MediaResourceGetterImpl::GetCookiesCallback(
const GetCookieCB& callback, const std::string& cookies) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
......
......@@ -12,6 +12,7 @@
#include "base/memory/weak_ptr.h"
#include "base/synchronization/waitable_event.h"
#include "media/base/android/media_resource_getter.h"
#include "net/base/auth.h"
#include "net/cookies/canonical_cookie.h"
namespace fileapi {
......@@ -41,20 +42,30 @@ class MediaResourceGetterImpl : public media::MediaResourceGetter {
// media::MediaResourceGetter implementation.
// Must be called on the UI thread.
virtual void GetCookies(const GURL& url,
const GURL& first_party_for_cookies,
const GetCookieCB& callback) OVERRIDE;
virtual void GetAuthCredentials(
const GURL& url,
const GetAuthCredentialsCB& callback) OVERRIDE;
virtual void GetCookies(
const GURL& url,
const GURL& first_party_for_cookies,
const GetCookieCB& callback) OVERRIDE;
virtual void GetPlatformPathFromURL(
const GURL& url,
const GetPlatformPathCB& callback) OVERRIDE;
virtual void ExtractMediaMetadata(
const std::string& url, const std::string& cookies,
const std::string& url,
const std::string& cookies,
const std::string& user_agent,
const ExtractMediaMetadataCB& callback) OVERRIDE;
static bool RegisterMediaResourceGetter(JNIEnv* env);
private:
// Called when GetAuthCredentials() finishes.
void GetAuthCredentialsCallback(
const GetAuthCredentialsCB& callback,
const net::AuthCredentials& credentials);
// Called when GetCookies() finishes.
void GetCookiesCallback(
const GetCookieCB& callback, const std::string& cookies);
......
......@@ -108,12 +108,9 @@ WebMediaPlayerAndroid::WebMediaPlayerAndroid(
texture_id_(0),
stream_id_(0),
is_playing_(false),
playing_started_(false),
needs_establish_peer_(true),
stream_texture_proxy_initialized_(false),
has_size_info_(false),
has_media_metadata_(false),
has_media_info_(false),
stream_texture_factory_(factory),
needs_external_surface_(false),
video_frame_provider_client_(NULL),
......@@ -190,13 +187,9 @@ void WebMediaPlayerAndroid::load(LoadType load_type,
return;
}
has_media_metadata_ = false;
has_media_info_ = false;
url_ = url;
int demuxer_client_id = 0;
if (player_type_ != MEDIA_PLAYER_TYPE_URL) {
has_media_info_ = true;
RendererDemuxerAndroid* demuxer =
RenderThreadImpl::current()->renderer_demuxer();
demuxer_client_id = demuxer->GetNextDemuxerClientID();
......@@ -220,6 +213,7 @@ void WebMediaPlayerAndroid::load(LoadType load_type,
weak_factory_.GetWeakPtr()),
base::Bind(&WebMediaPlayerAndroid::OnDurationChanged,
weak_factory_.GetWeakPtr()));
InitializePlayer(demuxer_client_id);
}
} else {
info_loader_.reset(
......@@ -236,12 +230,6 @@ void WebMediaPlayerAndroid::load(LoadType load_type,
info_loader_->Start(frame_);
}
url_ = url;
GURL first_party_url = frame_->document().firstPartyForCookies();
player_manager_->Initialize(
player_type_, player_id_, url, first_party_url, demuxer_client_id,
frame_->document().url());
if (player_manager_->ShouldEnterFullscreen(frame_))
player_manager_->EnterFullscreen(player_id_, frame_);
......@@ -257,17 +245,9 @@ void WebMediaPlayerAndroid::DidLoadMediaInfo(MediaInfoLoader::Status status) {
return;
}
has_media_info_ = true;
if (has_media_metadata_ &&
ready_state_ != WebMediaPlayer::ReadyStateHaveEnoughData) {
UpdateReadyState(WebMediaPlayer::ReadyStateHaveMetadata);
UpdateReadyState(WebMediaPlayer::ReadyStateHaveEnoughData);
}
// Android doesn't start fetching resources until an implementation-defined
// event (e.g. playback request) occurs. Sets the network state to IDLE
// if play is not requested yet.
if (!playing_started_)
UpdateNetworkState(WebMediaPlayer::NetworkStateIdle);
InitializePlayer(0);
UpdateNetworkState(WebMediaPlayer::NetworkStateIdle);
}
void WebMediaPlayerAndroid::play() {
......@@ -291,7 +271,6 @@ void WebMediaPlayerAndroid::play() {
player_manager_->Start(player_id_);
UpdatePlayingState(true);
UpdateNetworkState(WebMediaPlayer::NetworkStateLoading);
playing_started_ = true;
}
void WebMediaPlayerAndroid::pause() {
......@@ -613,9 +592,7 @@ void WebMediaPlayerAndroid::OnMediaMetadataChanged(
}
}
has_media_metadata_ = true;
if (has_media_info_ &&
ready_state_ != WebMediaPlayer::ReadyStateHaveEnoughData) {
if (ready_state_ != WebMediaPlayer::ReadyStateHaveEnoughData) {
UpdateReadyState(WebMediaPlayer::ReadyStateHaveMetadata);
UpdateReadyState(WebMediaPlayer::ReadyStateHaveEnoughData);
}
......@@ -880,6 +857,14 @@ void WebMediaPlayerAndroid::OnDestruct() {
"the RenderFrame goes away.";
}
void WebMediaPlayerAndroid::InitializePlayer(
int demuxer_client_id) {
GURL first_party_url = frame_->document().firstPartyForCookies();
player_manager_->Initialize(
player_type_, player_id_, url_, first_party_url, demuxer_client_id,
frame_->document().url());
}
void WebMediaPlayerAndroid::Pause(bool is_media_related_action) {
player_manager_->Pause(player_id_, is_media_related_action);
UpdatePlayingState(false);
......
......@@ -249,6 +249,7 @@ class WebMediaPlayerAndroid : public blink::WebMediaPlayer,
void SetNeedsEstablishPeer(bool needs_establish_peer);
private:
void InitializePlayer(int demuxer_client_id);
void Pause(bool is_media_related_action);
void DrawRemotePlaybackText(const std::string& remote_playback_message);
void ReallocateVideoFrame();
......@@ -357,9 +358,6 @@ class WebMediaPlayerAndroid : public blink::WebMediaPlayer,
// Whether the mediaplayer is playing.
bool is_playing_;
// Whether the mediaplayer has already started playing.
bool playing_started_;
// Whether media player needs to re-establish the surface texture peer.
bool needs_establish_peer_;
......@@ -369,10 +367,6 @@ class WebMediaPlayerAndroid : public blink::WebMediaPlayer,
// Whether the video size info is available.
bool has_size_info_;
// Whether the video metadata and info are available.
bool has_media_metadata_;
bool has_media_info_;
// Object for allocating stream textures.
scoped_refptr<StreamTextureFactory> stream_texture_factory_;
......
......@@ -209,6 +209,21 @@ void MediaPlayerBridge::OnDidSetDataUriDataSource(JNIEnv* env, jobject obj,
void MediaPlayerBridge::OnCookiesRetrieved(const std::string& cookies) {
cookies_ = cookies;
manager()->GetMediaResourceGetter()->GetAuthCredentials(
url_,
base::Bind(&MediaPlayerBridge::OnAuthCredentialsRetrieved,
weak_factory_.GetWeakPtr()));
}
void MediaPlayerBridge::OnAuthCredentialsRetrieved(
const base::string16& username, const base::string16& password) {
GURL::ReplacementsW replacements;
if (!username.empty()) {
replacements.SetUsernameStr(username);
if (!password.empty())
replacements.SetPasswordStr(password);
url_ = url_.ReplaceComponents(replacements);
}
ExtractMediaMetadata(url_.spec());
}
......
......@@ -13,6 +13,7 @@
#include "base/callback.h"
#include "base/memory/scoped_ptr.h"
#include "base/memory/weak_ptr.h"
#include "base/strings/string16.h"
#include "base/time/time.h"
#include "base/timer/timer.h"
#include "media/base/android/media_player_android.h"
......@@ -126,6 +127,11 @@ class MEDIA_EXPORT MediaPlayerBridge : public MediaPlayerAndroid {
// are retrieved.
void OnCookiesRetrieved(const std::string& cookies);
// Callback function passed to |resource_getter_|. Called when the auth
// credentials are retrieved.
void OnAuthCredentialsRetrieved(
const base::string16& username, const base::string16& password);
// Extract the media metadata from a url, asynchronously.
// OnMediaMetadataExtracted() will be called when this call finishes.
void ExtractMediaMetadata(const std::string& url);
......
......@@ -9,6 +9,7 @@
#include "base/callback.h"
#include "base/files/file_path.h"
#include "base/strings/string16.h"
#include "base/time/time.h"
#include "media/base/media_export.h"
#include "url/gurl.h"
......@@ -19,12 +20,26 @@ namespace media {
// are executed on the caller's thread.
class MEDIA_EXPORT MediaResourceGetter {
public:
// Callback to get the cookies. Args: cookies string.
typedef base::Callback<void(const std::string&)> GetCookieCB;
// Callback to get the platform path. Args: platform path.
typedef base::Callback<void(const std::string&)> GetPlatformPathCB;
// Callback to get the auth credentials. Args: username and password.
typedef base::Callback<void(const base::string16&, const base::string16&)>
GetAuthCredentialsCB;
// Callback to get the media metadata. Args: duration, width, height, and
// whether the information is retrieved successfully.
typedef base::Callback<void(base::TimeDelta, int, int, bool)>
ExtractMediaMetadataCB;
virtual ~MediaResourceGetter();
// Method for getting the auth credentials for a URL.
virtual void GetAuthCredentials(const GURL& url,
const GetAuthCredentialsCB& callback) = 0;
// Method for getting the cookies for a given URL.
virtual void GetCookies(const GURL& url,
const GURL& first_party_for_cookies,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment