| Index: chrome/browser/resources/image_loader/request.js
|
| diff --git a/chrome/browser/resources/image_loader/request.js b/chrome/browser/resources/image_loader/request.js
|
| index 4b847204c9d81ef00daf664f37e752733fdf1a4d..40c3b40cbd0bbf4f9f2dbb6c8fdd3b03d787f104 100644
|
| --- a/chrome/browser/resources/image_loader/request.js
|
| +++ b/chrome/browser/resources/image_loader/request.js
|
| @@ -55,10 +55,10 @@ function Request(id, cache, request, callback) {
|
|
|
| /**
|
| * Used to download remote images using http:// or https:// protocols.
|
| - * @type {XMLHttpRequest}
|
| + * @type {AuthorizedXHR}
|
| * @private
|
| */
|
| - this.xhr_ = new XMLHttpRequest();
|
| + this.xhr_ = new AuthorizedXHR();
|
|
|
| /**
|
| * Temporary canvas used to resize and compress the image.
|
| @@ -194,34 +194,122 @@ Request.prototype.downloadOriginal_ = function(onSuccess, onFailure) {
|
| return;
|
| }
|
|
|
| - // Download using an xhr request.
|
| - this.xhr_.responseType = 'blob';
|
| -
|
| - this.xhr_.onerror = this.image_.onerror;
|
| - this.xhr_.onload = function() {
|
| - if (this.xhr_.status != 200) {
|
| - this.image_.onerror();
|
| - return;
|
| - }
|
| -
|
| - // Process returned data, including the mime type.
|
| - this.contentType_ = this.xhr_.getResponseHeader('Content-Type');
|
| + // Fetch the image via authorized XHR and parse it.
|
| + var parseImage = function(contentType, blob) {
|
| var reader = new FileReader();
|
| - reader.onerror = this.image_.onerror;
|
| + reader.onerror = onFailure;
|
| reader.onload = function(e) {
|
| this.image_.src = e.target.result;
|
| }.bind(this);
|
|
|
| // Load the data to the image as a data url.
|
| - reader.readAsDataURL(this.xhr_.response);
|
| + reader.readAsDataURL(blob);
|
| + }.bind(this);
|
| +
|
| + // Request raw data via XHR.
|
| + this.xhr_.load(this.request_.url, parseImage, onFailure);
|
| +};
|
| +
|
| +/**
|
| + * Creates a XmlHttpRequest wrapper with injected OAuth2 authentication headers.
|
| + * @constructor
|
| + */
|
| +function AuthorizedXHR() {
|
| + this.xhr_ = null;
|
| + this.aborted_ = false;
|
| +}
|
| +
|
| +/**
|
| + * Aborts the current request (if running).
|
| + */
|
| +AuthorizedXHR.prototype.abort = function() {
|
| + this.aborted_ = true;
|
| + if (this.xhr_)
|
| + this.xhr_.abort();
|
| +};
|
| +
|
| +/**
|
| + * Loads an image using a OAuth2 token. If it fails, then tries to retry with
|
| + * a refreshed OAuth2 token.
|
| + *
|
| + * @param {string} url URL to the resource to be fetched.
|
| + * @param {function(string, Blob}) onSuccess Success callback with the content
|
| + * type and the fetched data.
|
| + * @param {function()} onFailure Failure callback.
|
| + */
|
| +AuthorizedXHR.prototype.load = function(url, onSuccess, onFailure) {
|
| + this.aborted_ = false;
|
| +
|
| + // Do not call any callbacks when aborting.
|
| + var onMaybeSuccess = function(contentType, response) {
|
| + if (!this.aborted_)
|
| + onSuccess(contentType, response);
|
| + }.bind(this);
|
| + var onMaybeFailure = function(opt_code) {
|
| + if (!this.aborted_)
|
| + onFailure();
|
| + }.bind(this);
|
| +
|
| + // Fetches the access token and makes an authorized call. If refresh is true,
|
| + // then forces refreshing the access token.
|
| + var requestTokenAndCall = function(refresh, onInnerSuccess, onInnerFailure) {
|
| + chrome.fileBrowserPrivate.requestAccessToken(refresh, function(token) {
|
| + if (this.aborted_)
|
| + return;
|
| + if (!token) {
|
| + onInnerFailure();
|
| + return;
|
| + }
|
| + this.xhr_ = AuthorizedXHR.loadWithToken_(
|
| + token, url, onInnerSuccess, onInnerFailure);
|
| + }.bind(this));
|
| + }.bind(this);
|
| +
|
| + // Refreshes the access token and retries the request.
|
| + var maybeRetryCall = function(code) {
|
| + if (this.aborted_)
|
| + return;
|
| + requestTokenAndCall(true, onMaybeSuccess, onMaybeFailure);
|
| + }.bind(this);
|
| +
|
| + // Make the request with reusing the current token. If it fails, then retry.
|
| + requestTokenAndCall(false, onMaybeSuccess, maybeRetryCall);
|
| +};
|
| +
|
| +/**
|
| + * Fetches data using authorized XmlHttpRequest with the provided OAuth2 token.
|
| + * If the token is invalid, the request will fail.
|
| + *
|
| + * @param {string} token OAuth2 token to be injected to the request.
|
| + * @param {string} url URL to the resource to be fetched.
|
| + * @param {function(string, Blob}) onSuccess Success callback with the content
|
| + * type and the fetched data.
|
| + * @param {function(number=)} onFailure Failure callback with the error code
|
| + * if available.
|
| + * @private
|
| + */
|
| +AuthorizedXHR.loadWithToken_ = function(token, url, onSuccess, onFailure) {
|
| + var xhr = new XMLHttpRequest();
|
| + xhr.responseType = 'blob';
|
| +
|
| + xhr.onreadystatechange = function() {
|
| + if (xhr.readyState != 4)
|
| + return;
|
| + if (xhr.status != 200) {
|
| + onFailure(xhr.status);
|
| + return;
|
| + }
|
| + var contentType = xhr.getResponseHeader('Content-Type');
|
| + onSuccess(contentType, xhr.response);
|
| }.bind(this);
|
|
|
| // Perform a xhr request.
|
| try {
|
| - this.xhr_.open('GET', this.request_.url, true);
|
| - this.xhr_.send();
|
| + xhr.open('GET', url, true);
|
| + xhr.setRequestHeader('Authorization', 'Bearer ' + token);
|
| + xhr.send();
|
| } catch (e) {
|
| - this.image_.onerror();
|
| + onFailure();
|
| }
|
| };
|
|
|
| @@ -330,7 +418,6 @@ Request.prototype.cleanup_ = function() {
|
| this.image_.src = 'data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAA' +
|
| 'ABAAEAAAICTAEAOw==';
|
|
|
| - this.xhr_.onerror = function() {};
|
| this.xhr_.onload = function() {};
|
| this.xhr_.abort();
|
|
|
|
|