Skip to content

Commit

Permalink
Handle Data URIs passed in to THREE.XHRLoader manually since Safari c…
Browse files Browse the repository at this point in the history
…an not load Data URIs through XMLHttpRequest (mrdoob#9823)
  • Loading branch information
richtr authored and mrdoob committed Oct 7, 2016
1 parent 6ab1bdd commit 18a33bd
Showing 1 changed file with 122 additions and 30 deletions.
152 changes: 122 additions & 30 deletions src/loaders/XHRLoader.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ Object.assign( XHRLoader.prototype, {

load: function ( url, onLoad, onProgress, onError ) {

if ( url === undefined ) url = '';

if ( this.path !== undefined ) url = this.path + url;

var scope = this;
Expand All @@ -37,66 +39,156 @@ Object.assign( XHRLoader.prototype, {

}

var request = new XMLHttpRequest();
request.open( 'GET', url, true );
// Check for data: URI
var dataUriRegex = /^data:(.*?)(;base64)?,(.*)$/;
var dataUriRegexResult = url.match( dataUriRegex );

request.addEventListener( 'load', function ( event ) {
// Safari can not handle Data URIs through XMLHttpRequest so process manually
if ( dataUriRegexResult ) {

var response = event.target.response;
var mimeType = dataUriRegexResult[1];
var isBase64 = !!dataUriRegexResult[2];
var data = dataUriRegexResult[3];

Cache.add( url, response );
data = window.decodeURIComponent(data);

if ( this.status === 200 ) {
if( isBase64 ) {
data = window.atob(data);
}

if ( onLoad ) onLoad( response );
try {

scope.manager.itemEnd( url );
var response;
var responseType = ( this.responseType || '' ).toLowerCase();

} else if ( this.status === 0 ) {
switch ( responseType ) {

// Some browsers return HTTP Status 0 when using non-http protocol
// e.g. 'file://' or 'data://'. Handle as success.
case 'arraybuffer':
case 'blob':

console.warn( 'THREE.XHRLoader: HTTP Status 0 received.' );
response = new ArrayBuffer( data.length );
var view = new Uint8Array( response );
for ( var i = 0; i < data.length; i ++ ) {

if ( onLoad ) onLoad( response );
view[ i ] = data.charCodeAt( i );

scope.manager.itemEnd( url );
}

} else {
if ( responseType === 'blob' ) {

if ( onError ) onError( event );
response = new Blob( [ response ], { "type" : mimeType } );

scope.manager.itemError( url );
}

break;

case 'document':

var parser = new DOMParser();
response = parser.parseFromString( data, mimeType );

break;

case 'json':

response = JSON.parse( data );

break;

default: // 'text' or other

response = data;

break;

}

// Wait for next browser tick
window.setTimeout( function() {

if ( onLoad ) onLoad( response );

scope.manager.itemEnd( url );

}, 0);

} catch ( error ) {

// Wait for next browser tick
window.setTimeout( function() {

if ( onError ) onError( error );

scope.manager.itemError( url );

}, 0);

}

}, false );
} else {

var request = new XMLHttpRequest();
request.open( 'GET', url, true );

request.addEventListener( 'load', function ( event ) {

var response = event.target.response;

Cache.add( url, response );

if ( this.status === 200 ) {

if ( onLoad ) onLoad( response );

scope.manager.itemEnd( url );

} else if ( this.status === 0 ) {

// Some browsers return HTTP Status 0 when using non-http protocol
// e.g. 'file://' or 'data://'. Handle as success.

console.warn( 'THREE.XHRLoader: HTTP Status 0 received.' );

if ( onLoad ) onLoad( response );

scope.manager.itemEnd( url );

if ( onProgress !== undefined ) {
} else {

request.addEventListener( 'progress', function ( event ) {
if ( onError ) onError( event );

onProgress( event );
scope.manager.itemError( url );

}

}, false );

}
if ( onProgress !== undefined ) {

request.addEventListener( 'progress', function ( event ) {

onProgress( event );

}, false );

}

request.addEventListener( 'error', function ( event ) {

request.addEventListener( 'error', function ( event ) {
if ( onError ) onError( event );

if ( onError ) onError( event );
scope.manager.itemError( url );

scope.manager.itemError( url );
}, false );

}, false );
if ( this.responseType !== undefined ) request.responseType = this.responseType;
if ( this.withCredentials !== undefined ) request.withCredentials = this.withCredentials;

if ( this.responseType !== undefined ) request.responseType = this.responseType;
if ( this.withCredentials !== undefined ) request.withCredentials = this.withCredentials;
if ( request.overrideMimeType ) request.overrideMimeType( 'text/plain' );

if ( request.overrideMimeType ) request.overrideMimeType( 'text/plain' );
request.send( null );

request.send( null );
}

scope.manager.itemStart( url );

Expand Down

0 comments on commit 18a33bd

Please sign in to comment.