Skip to content

Commit

Permalink
Provide better sandbox error messages, and disallow running from file…
Browse files Browse the repository at this point in the history
…:// URLs
  • Loading branch information
esprehn authored and IgorMinar committed Nov 2, 2010
1 parent 56a3d52 commit dcf76e6
Show file tree
Hide file tree
Showing 4 changed files with 48 additions and 26 deletions.
5 changes: 5 additions & 0 deletions css/angular-scenario.css
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,11 @@ body {
font-size: 14px;
}

#system-error {
font-size: 1.5em;
text-align: center;
}

#json, #xml {
display: none;
}
Expand Down
8 changes: 4 additions & 4 deletions src/scenario/Application.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ angular.scenario.Application.prototype.getWindow_ = function() {
* Checks that a URL would return a 2xx success status code. Callback is called
* with no arguments on success, or with an error on failure.
*
* Warning: This requires the server to be able to respond to HEAD requests
* Warning: This requires the server to be able to respond to HEAD requests
* and not modify the state of your application.
*
* @param {string} url Url to check
Expand Down Expand Up @@ -69,7 +69,7 @@ angular.scenario.Application.prototype.checkUrlStatus_ = function(url, callback)
/**
* Changes the location of the frame.
*
* @param {string} url The URL. If it begins with a # then only the
* @param {string} url The URL. If it begins with a # then only the
* hash of the page is changed.
* @param {Function} loadFn function($window, $document) Called when frame loads.
* @param {Function} errorFn function(error) Called if any error when loading.
Expand All @@ -79,8 +79,8 @@ angular.scenario.Application.prototype.navigateTo = function(url, loadFn, errorF
var frame = this.getFrame_();
//TODO(esprehn): Refactor to use rethrow()
errorFn = errorFn || function(e) { throw e; };
if (/^file:\/\//.test(url)) {
errorFn('Sandbox Error: Cannot load file:// URL.');
if (url === 'about:blank') {
errorFn('Sandbox Error: Navigating to about:blank is not allowed.');
} else if (url.charAt(0) === '#') {
url = frame.attr('src').split('#')[0] + url;
frame.attr('src', url);
Expand Down
12 changes: 11 additions & 1 deletion src/scenario/Scenario.js
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ angular.scenario.matcher = angular.scenario.matcher || function(name, fn) {
* @param {Object} config Config options
*/
function angularScenarioInit($scenario, config) {
var href = window.location.href;
var body = _jQuery(document.body);
var output = [];

Expand All @@ -108,6 +109,15 @@ function angularScenarioInit($scenario, config) {
}
});

if (!/^http/.test(href) && !/^https/.test(href)) {
body.append('<p id="system-error"></p>');
body.find('#system-error').text(
'Scenario runner must be run using http or https. The protocol ' +
href.split(':')[0] + ':// is not supported.'
);
return;
}

var appFrame = body.append('<div id="application"></div>').find('#application');
var application = new angular.scenario.Application(appFrame);

Expand All @@ -134,7 +144,7 @@ function angularScenarioInit($scenario, config) {
*
* @param {Array} list list to iterate over
* @param {Function} iterator Callback function(value, continueFunction)
* @param {Function} done Callback function(error, result) called when
* @param {Function} done Callback function(error, result) called when
* iteration finishes or an error occurs.
*/
function asyncForEach(list, iterator, done) {
Expand Down
49 changes: 28 additions & 21 deletions test/scenario/ApplicationSpec.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
describe('angular.scenario.Application', function() {
var $window;
var app, frames;

function callLoadHandlers(app) {
Expand Down Expand Up @@ -52,61 +53,67 @@ describe('angular.scenario.Application', function() {
});

it('should use a new iframe each time', function() {
app.navigateTo('about:blank');
app.navigateTo('http://localhost/');
var frame = app.getFrame_();
frame.attr('test', true);
app.navigateTo('about:blank');
app.navigateTo('http://localhost/');
expect(app.getFrame_().attr('test')).toBeFalsy();
});

it('should call error handler if document not accessible', function() {
var called;
app.getWindow_ = function() {
return {};
};
app.navigateTo('about:blank', angular.noop, function(error) {
app.navigateTo('http://localhost/', angular.noop, function(error) {
expect(error).toMatch(/Sandbox Error/);
called = true;
});
callLoadHandlers(app);
expect(called).toBeTruthy();
});

it('should call error handler if using file:// URL', function() {
app.navigateTo('file://foo/bar.txt', angular.noop, function(error) {
it('should call error handler if navigating to about:blank', function() {
var called;
app.navigateTo('about:blank', angular.noop, function(error) {
expect(error).toMatch(/Sandbox Error/);
called = true;
});
expect(called).toBeTruthy();
});

it('should call error handler if status check fails', function() {
app.checkUrlStatus_ = function(url, callback) {
callback.call(this, 'Example Error');
};
app.navigateTo('about:blank', angular.noop, function(error) {
app.navigateTo('http://localhost/', angular.noop, function(error) {
expect(error).toEqual('Example Error');
});
});

it('should hide old iframes and navigate to about:blank', function() {
app.navigateTo('about:blank#foo');
app.navigateTo('about:blank#bar');
app.navigateTo('http://localhost/#foo');
app.navigateTo('http://localhost/#bar');
var iframes = frames.find('iframe');
expect(iframes.length).toEqual(2);
expect(iframes[0].src).toEqual('about:blank');
expect(iframes[1].src).toEqual('about:blank#bar');
expect(iframes[1].src).toEqual('http://localhost/#bar');
expect(_jQuery(iframes[0]).css('display')).toEqual('none');
});

it('should URL update description bar', function() {
app.navigateTo('about:blank');
app.navigateTo('http://localhost/');
var anchor = frames.find('> h2 a');
expect(anchor.attr('href')).toEqual('about:blank');
expect(anchor.text()).toEqual('about:blank');
expect(anchor.attr('href')).toEqual('http://localhost/');
expect(anchor.text()).toEqual('http://localhost/');
});

it('should call onload handler when frame loads', function() {
var called;
app.getWindow_ = function() {
return {document: {}};
};
app.navigateTo('about:blank', function($window, $document) {
app.navigateTo('http://localhost/', function($window, $document) {
called = true;
});
callLoadHandlers(app);
Expand All @@ -130,7 +137,7 @@ describe('angular.scenario.Application', function() {
notifyWhenNoOutstandingRequests: function(fn) {
handlers.push(fn);
}
}
};
};
app.getWindow_ = function() {
return testWindow;
Expand Down Expand Up @@ -173,35 +180,35 @@ describe('angular.scenario.Application', function() {
expect(options.type).toEqual('HEAD');
expect(options.url).toEqual('http://www.google.com/');
});

it('should call error handler if status code is less than 200', function() {
var finished;
response.status = 199;
response.statusText = 'Error Message';
app.navigateTo('about:blank', angular.noop, function(error) {
app.navigateTo('http://localhost/', angular.noop, function(error) {
expect(error).toEqual('199 Error Message');
finished = true;
});
expect(finished).toBeTruthy();
});

it('should call error handler if status code is greater than 299', function() {
var finished;
response.status = 300;
response.statusText = 'Error';
app.navigateTo('about:blank', angular.noop, function(error) {
app.navigateTo('http://localhost/', angular.noop, function(error) {
expect(error).toEqual('300 Error');
finished = true;
});
expect(finished).toBeTruthy();
});

it('should call error handler if status code is 0 for sandbox error', function() {
var finished;
response.status = 0;
response.statusText = '';
app.navigateTo('about:blank', angular.noop, function(error) {
expect(error).toEqual('Sandbox Error: Cannot access about:blank');
app.navigateTo('http://localhost/', angular.noop, function(error) {
expect(error).toEqual('Sandbox Error: Cannot access http://localhost/');
finished = true;
});
expect(finished).toBeTruthy();
Expand Down

0 comments on commit dcf76e6

Please sign in to comment.