blob: caa66af74312b286e39fa77fc21c68410eb46649 [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 "base/bits.h"
#include "base/callback_helpers.h"
#include "base/metrics/histogram.h"
#include "third_party/WebKit/public/platform/WebURLError.h"
#include "third_party/WebKit/public/platform/WebURLLoader.h"
#include "third_party/WebKit/public/platform/WebURLResponse.h"
#include "third_party/WebKit/public/web/WebFrame.h"
using blink::WebFrame;
using blink::WebURLError;
using blink::WebURLLoader;
using blink::WebURLLoaderOptions;
using blink::WebURLRequest;
using blink::WebURLResponse;
namespace content {
static const int kHttpOK = 200;
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->document().firstPartyForCookies();
// Prepare the request.
WebURLRequest request(url_);
request.setTargetType(WebURLRequest::TargetIsMedia);
frame->setReferrerForRequest(request, blink::WebURL());
scoped_ptr<WebURLLoader> loader;
if (test_loader_) {
loader = test_loader_.Pass();
} else {
WebURLLoaderOptions options;
if (cors_mode_ == blink::WebMediaPlayer::CORSModeUnspecified) {
options.allowCredentials = true;
options.crossOriginRequestPolicy =
WebURLLoaderOptions::CrossOriginRequestPolicyAllow;
allow_stored_credentials_ = true;
} else {
options.exposeAllResponseHeaders = true;
// The author header set is empty, no preflight should go ahead.
options.preflightPolicy = WebURLLoaderOptions::PreventPreflight;
options.crossOriginRequestPolicy =
WebURLLoaderOptions::CrossOriginRequestPolicyUseAccessControl;
if (cors_mode_ == blink::WebMediaPlayer::CORSModeUseCredentials) {
options.allowCredentials = true;
allow_stored_credentials_ = true;
}
}
loader.reset(frame->createAssociatedURLLoader(options));
}
// Start the resource loading.
loader->loadAsynchronously(request, this);
active_loader_.reset(new ActiveLoader(loader.Pass()));
}
/////////////////////////////////////////////////////////////////////////////
// blink::WebURLLoaderClient implementation.
void MediaInfoLoader::willSendRequest(
WebURLLoader* loader,
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()) {
// Set the url in the request to an invalid value (empty url).
newRequest.setURL(blink::WebURL());
return;
}
// 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();
}
void MediaInfoLoader::didSendData(
WebURLLoader* loader,
unsigned long long bytes_sent,
unsigned long long total_bytes_to_be_sent) {
NOTIMPLEMENTED();
}
void MediaInfoLoader::didReceiveResponse(
WebURLLoader* loader,
const WebURLResponse& response) {
DVLOG(1) << "didReceiveResponse: HTTP/"
<< (response.httpVersion() == WebURLResponse::HTTP_0_9 ? "0.9" :
response.httpVersion() == WebURLResponse::HTTP_1_0 ? "1.0" :
response.httpVersion() == WebURLResponse::HTTP_1_1 ? "1.1" :
"Unknown")
<< " " << response.httpStatusCode();
DCHECK(active_loader_.get());
if (!url_.SchemeIs("http") && !url_.SchemeIs("https")) {
DidBecomeReady(kOk);
return;
}
if (response.httpStatusCode() == kHttpOK) {
DidBecomeReady(kOk);
return;
}
loader_failed_ = true;
DidBecomeReady(kFailed);
}
void MediaInfoLoader::didReceiveData(
WebURLLoader* loader,
const char* data,
int data_length,
int encoded_data_length) {
// Ignored.
}
void MediaInfoLoader::didDownloadData(
blink::WebURLLoader* loader,
int dataLength,
int encodedDataLength) {
NOTIMPLEMENTED();
}
void MediaInfoLoader::didReceiveCachedMetadata(
WebURLLoader* loader,
const char* data,
int data_length) {
NOTIMPLEMENTED();
}
void MediaInfoLoader::didFinishLoading(
WebURLLoader* loader,
double finishTime,
int64_t total_encoded_data_length) {
DCHECK(active_loader_.get());
DidBecomeReady(kOk);
}
void MediaInfoLoader::didFail(
WebURLLoader* loader,
const WebURLError& error) {
DVLOG(1) << "didFail: reason=" << error.reason
<< ", isCancellation=" << error.isCancellation
<< ", domain=" << error.domain.utf8().data()
<< ", localizedDescription="
<< error.localizedDescription.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::CORSModeUnspecified;
}
/////////////////////////////////////////////////////////////////////////////
// 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