blob: 9e19233cb53fef07eacb16b6f25821c3f17c55a7 [file] [log] [blame]
// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "content/renderer/media/android/media_info_loader.h"
#include <utility>
#include "base/bits.h"
#include "base/callback_helpers.h"
#include "base/metrics/histogram_macros.h"
#include "third_party/WebKit/public/platform/WebURLError.h"
#include "third_party/WebKit/public/platform/WebURLRequest.h"
#include "third_party/WebKit/public/platform/WebURLResponse.h"
#include "third_party/WebKit/public/web/WebAssociatedURLLoader.h"
#include "third_party/WebKit/public/web/WebFrame.h"
using blink::WebAssociatedURLLoader;
using blink::WebAssociatedURLLoaderOptions;
using blink::WebFrame;
using blink::WebURLError;
using blink::WebURLRequest;
using blink::WebURLResponse;
namespace content {
static const int kHttpOK = 200;
static const int kHttpPartialContentOK = 206;
MediaInfoLoader::MediaInfoLoader(
const GURL& url,
blink::WebMediaPlayer::CORSMode cors_mode,
const ReadyCB& ready_cb)
: loader_failed_(false),
url_(url),
allow_stored_credentials_(false),
cors_mode_(cors_mode),
single_origin_(true),
ready_cb_(ready_cb) {}
MediaInfoLoader::~MediaInfoLoader() {}
void MediaInfoLoader::Start(blink::WebFrame* frame) {
// Make sure we have not started.
DCHECK(!ready_cb_.is_null());
CHECK(frame);
start_time_ = base::TimeTicks::Now();
first_party_url_ = frame->GetDocument().FirstPartyForCookies();
// Prepare the request.
WebURLRequest request(url_);
// TODO(mkwst): Split this into video/audio.
request.SetRequestContext(WebURLRequest::kRequestContextVideo);
frame->SetReferrerForRequest(request, blink::WebURL());
// Since we don't actually care about the media data at this time, use a two
// byte range request to avoid unnecessarily downloading resources. Not all
// servers support HEAD unfortunately, so use a range request; which is no
// worse than the previous request+cancel code. See http://crbug.com/400788
request.AddHTTPHeaderField("Range", "bytes=0-1");
std::unique_ptr<WebAssociatedURLLoader> loader;
if (test_loader_) {
loader = std::move(test_loader_);
} else {
WebAssociatedURLLoaderOptions options;
if (cors_mode_ == blink::WebMediaPlayer::kCORSModeUnspecified) {
request.SetFetchCredentialsMode(
WebURLRequest::kFetchCredentialsModeInclude);
options.fetch_request_mode = WebURLRequest::kFetchRequestModeNoCORS;
allow_stored_credentials_ = true;
} else {
options.expose_all_response_headers = true;
// The author header set is empty, no preflight should go ahead.
options.preflight_policy =
WebAssociatedURLLoaderOptions::kPreventPreflight;
options.fetch_request_mode = WebURLRequest::kFetchRequestModeCORS;
if (cors_mode_ == blink::WebMediaPlayer::kCORSModeUseCredentials) {
request.SetFetchCredentialsMode(
WebURLRequest::kFetchCredentialsModeInclude);
allow_stored_credentials_ = true;
} else {
request.SetFetchCredentialsMode(
WebURLRequest::kFetchCredentialsModeSameOrigin);
}
}
loader.reset(frame->CreateAssociatedURLLoader(options));
}
// Start the resource loading.
loader->LoadAsynchronously(request, this);
active_loader_.reset(new media::ActiveLoader(std::move(loader)));
}
/////////////////////////////////////////////////////////////////////////////
// blink::WebAssociatedURLLoaderClient implementation.
bool MediaInfoLoader::WillFollowRedirect(
const WebURLRequest& newRequest,
const WebURLResponse& redirectResponse) {
// The load may have been stopped and |ready_cb| is destroyed.
// In this case we shouldn't do anything.
if (ready_cb_.is_null())
return false;
// Only allow |single_origin_| if we haven't seen a different origin yet.
if (single_origin_)
single_origin_ = url_.GetOrigin() == GURL(newRequest.Url()).GetOrigin();
url_ = newRequest.Url();
first_party_url_ = newRequest.FirstPartyForCookies();
allow_stored_credentials_ = newRequest.AllowStoredCredentials();
return true;
}
void MediaInfoLoader::DidSendData(unsigned long long bytes_sent,
unsigned long long total_bytes_to_be_sent) {
NOTIMPLEMENTED();
}
void MediaInfoLoader::DidReceiveResponse(const WebURLResponse& response) {
DVLOG(1) << "didReceiveResponse: HTTP/"
<< (response.HttpVersion() == WebURLResponse::kHTTPVersion_0_9
? "0.9"
: response.HttpVersion() == WebURLResponse::kHTTPVersion_1_0
? "1.0"
: response.HttpVersion() ==
WebURLResponse::kHTTPVersion_1_1
? "1.1"
: "Unknown")
<< " " << response.HttpStatusCode();
DCHECK(active_loader_.get());
if (!url_.SchemeIs(url::kHttpScheme) && !url_.SchemeIs(url::kHttpsScheme)) {
DidBecomeReady(kOk);
return;
}
if (response.HttpStatusCode() == kHttpOK ||
response.HttpStatusCode() == kHttpPartialContentOK) {
DidBecomeReady(kOk);
return;
}
loader_failed_ = true;
DidBecomeReady(kFailed);
}
void MediaInfoLoader::DidReceiveData(const char* data, int data_length) {
// Ignored.
}
void MediaInfoLoader::DidDownloadData(int dataLength) {
NOTIMPLEMENTED();
}
void MediaInfoLoader::DidReceiveCachedMetadata(const char* data,
int data_length) {
NOTIMPLEMENTED();
}
void MediaInfoLoader::DidFinishLoading(double finishTime) {
DCHECK(active_loader_.get());
DidBecomeReady(kOk);
}
void MediaInfoLoader::DidFail(const WebURLError& error) {
DVLOG(1) << "didFail: reason=" << error.reason
<< ", isCancellation=" << error.is_cancellation
<< ", domain=" << error.domain.Utf8().data()
<< ", localizedDescription="
<< error.localized_description.Utf8().data();
DCHECK(active_loader_.get());
loader_failed_ = true;
DidBecomeReady(kFailed);
}
bool MediaInfoLoader::HasSingleOrigin() const {
DCHECK(ready_cb_.is_null())
<< "Must become ready before calling HasSingleOrigin()";
return single_origin_;
}
bool MediaInfoLoader::DidPassCORSAccessCheck() const {
DCHECK(ready_cb_.is_null())
<< "Must become ready before calling DidPassCORSAccessCheck()";
return !loader_failed_ &&
cors_mode_ != blink::WebMediaPlayer::kCORSModeUnspecified;
}
/////////////////////////////////////////////////////////////////////////////
// Helper methods.
void MediaInfoLoader::DidBecomeReady(Status status) {
UMA_HISTOGRAM_TIMES("Media.InfoLoadDelay",
base::TimeTicks::Now() - start_time_);
active_loader_.reset();
if (!ready_cb_.is_null())
base::ResetAndReturn(&ready_cb_).Run(status, url_, first_party_url_,
allow_stored_credentials_);
}
} // namespace content