diff --git a/modules/angular2/src/http/backends/xhr_backend.ts b/modules/angular2/src/http/backends/xhr_backend.ts index 2b80f99209..ebdc7a4be9 100644 --- a/modules/angular2/src/http/backends/xhr_backend.ts +++ b/modules/angular2/src/http/backends/xhr_backend.ts @@ -36,8 +36,21 @@ export class XHRConnection implements Connection { // TODO(jeffbcross): implement error listening/propagation this._xhr.open(requestMethodsMap.getMethod(ENUM_INDEX(req.method)), req.url); this._xhr.addEventListener('load', (_) => { - var responseOptions = new ResponseOptions( - {body: isPresent(this._xhr.response) ? this._xhr.response : this._xhr.responseText}); + // responseText is the old-school way of retrieving response (supported by IE8 & 9) + // response/responseType properties were introduced in XHR Level2 spec (supported by IE10) + let response = isPresent(this._xhr.response) ? this._xhr.response : this._xhr.responseText; + + // normalize IE9 bug (http://bugs.jquery.com/ticket/1450) + let status = this._xhr.status === 1223 ? 204 : this._xhr.status; + + // fix status code when it is 0 (0 status is undocumented). + // Occurs when accessing file resources or on Android 4.1 stock browser + // while retrieving files from application cache. + if (status === 0) { + status = response ? 200 : 0; + } + + var responseOptions = new ResponseOptions({body: response, status: status}); if (isPresent(baseResponseOptions)) { responseOptions = baseResponseOptions.merge(responseOptions); } diff --git a/modules/angular2/test/http/backends/xhr_backend_spec.ts b/modules/angular2/test/http/backends/xhr_backend_spec.ts index 88b90d2d24..848ecc2b8d 100644 --- a/modules/angular2/test/http/backends/xhr_backend_spec.ts +++ b/modules/angular2/test/http/backends/xhr_backend_spec.ts @@ -39,6 +39,7 @@ class MockBrowserXHR extends BrowserXhr { responseText: string; setRequestHeader: any; callbacks: Map; + status: number; constructor() { super(); var spy = new SpyObject(); @@ -49,6 +50,7 @@ class MockBrowserXHR extends BrowserXhr { this.callbacks = new Map(); } + setStatusCode(status) { this.status = status; } addEventListener(type: string, cb: Function) { this.callbacks.set(type, cb); } dispatchEvent(type: string) { this.callbacks.get(type)({}); } @@ -135,6 +137,35 @@ export function main() { expect(setRequestHeaderSpy).toHaveBeenCalledWith('Content-Type', ['text/xml']); expect(setRequestHeaderSpy).toHaveBeenCalledWith('Breaking-Bad', ['<3']); }); + + it('should return the correct status code', inject([AsyncTestCompleter], async => { + var statusCode = 418; + var connection = new XHRConnection(sampleRequest, new MockBrowserXHR(), + new ResponseOptions({status: statusCode})); + + ObservableWrapper.subscribe(connection.response, res => { + expect(res.status).toBe(statusCode); + async.done(); + }); + + existingXHRs[0].setStatusCode(statusCode); + existingXHRs[0].dispatchEvent('load'); + })); + + it('should normalize IE\'s 1223 status code into 204', inject([AsyncTestCompleter], async => { + var statusCode = 1223; + var normalizedCode = 204; + var connection = new XHRConnection(sampleRequest, new MockBrowserXHR(), + new ResponseOptions({status: statusCode})); + + ObservableWrapper.subscribe(connection.response, res => { + expect(res.status).toBe(normalizedCode); + async.done(); + }); + + existingXHRs[0].setStatusCode(statusCode); + existingXHRs[0].dispatchEvent('load'); + })); }); }); }