fix(http): correctly handle response body for 204 status code
closes #12830 fixes #12393
This commit is contained in:
parent
d3eff6c483
commit
a0c58a6b5c
|
@ -8,6 +8,8 @@
|
||||||
|
|
||||||
import {Injectable} from '@angular/core';
|
import {Injectable} from '@angular/core';
|
||||||
import {__platform_browser_private__} from '@angular/platform-browser';
|
import {__platform_browser_private__} from '@angular/platform-browser';
|
||||||
|
import {Observable} from 'rxjs/Observable';
|
||||||
|
import {Observer} from 'rxjs/Observer';
|
||||||
import {ResponseOptions} from '../base_response_options';
|
import {ResponseOptions} from '../base_response_options';
|
||||||
import {ContentType, ReadyState, RequestMethod, ResponseContentType, ResponseType} from '../enums';
|
import {ContentType, ReadyState, RequestMethod, ResponseContentType, ResponseType} from '../enums';
|
||||||
import {Headers} from '../headers';
|
import {Headers} from '../headers';
|
||||||
|
@ -16,8 +18,6 @@ import {Connection, ConnectionBackend, XSRFStrategy} from '../interfaces';
|
||||||
import {Request} from '../static_request';
|
import {Request} from '../static_request';
|
||||||
import {Response} from '../static_response';
|
import {Response} from '../static_response';
|
||||||
import {BrowserXhr} from './browser_xhr';
|
import {BrowserXhr} from './browser_xhr';
|
||||||
import {Observable} from 'rxjs/Observable';
|
|
||||||
import {Observer} from 'rxjs/Observer';
|
|
||||||
|
|
||||||
const XSSI_PREFIX = /^\)\]\}',?\n/;
|
const XSSI_PREFIX = /^\)\]\}',?\n/;
|
||||||
|
|
||||||
|
@ -49,19 +49,24 @@ export class XHRConnection implements Connection {
|
||||||
}
|
}
|
||||||
// load event handler
|
// load event handler
|
||||||
const onLoad = () => {
|
const onLoad = () => {
|
||||||
// responseText is the old-school way of retrieving response (supported by IE8 & 9)
|
|
||||||
// response/responseType properties were introduced in ResourceLoader Level2 spec (supported
|
|
||||||
// by IE10)
|
|
||||||
let body = _xhr.response === undefined ? _xhr.responseText : _xhr.response;
|
|
||||||
// Implicitly strip a potential XSSI prefix.
|
|
||||||
if (typeof body === 'string') body = body.replace(XSSI_PREFIX, '');
|
|
||||||
const headers = Headers.fromResponseHeaderString(_xhr.getAllResponseHeaders());
|
|
||||||
|
|
||||||
const url = getResponseURL(_xhr);
|
|
||||||
|
|
||||||
// normalize IE9 bug (http://bugs.jquery.com/ticket/1450)
|
// normalize IE9 bug (http://bugs.jquery.com/ticket/1450)
|
||||||
let status: number = _xhr.status === 1223 ? 204 : _xhr.status;
|
let status: number = _xhr.status === 1223 ? 204 : _xhr.status;
|
||||||
|
|
||||||
|
let body: any = null;
|
||||||
|
|
||||||
|
// HTTP 204 means no content
|
||||||
|
if (status !== 204) {
|
||||||
|
// responseText is the old-school way of retrieving response (supported by IE8 & 9)
|
||||||
|
// response/responseType properties were introduced in ResourceLoader Level2 spec
|
||||||
|
// (supported by IE10)
|
||||||
|
body = _xhr.response == null ? _xhr.responseText : _xhr.response;
|
||||||
|
|
||||||
|
// Implicitly strip a potential XSSI prefix.
|
||||||
|
if (typeof body === 'string') {
|
||||||
|
body = body.replace(XSSI_PREFIX, '');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// fix status code when it is 0 (0 status is undocumented).
|
// fix status code when it is 0 (0 status is undocumented).
|
||||||
// Occurs when accessing file resources or on Android 4.1 stock browser
|
// Occurs when accessing file resources or on Android 4.1 stock browser
|
||||||
// while retrieving files from application cache.
|
// while retrieving files from application cache.
|
||||||
|
@ -69,7 +74,11 @@ export class XHRConnection implements Connection {
|
||||||
status = body ? 200 : 0;
|
status = body ? 200 : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
const statusText = _xhr.statusText || 'OK';
|
const headers: Headers = Headers.fromResponseHeaderString(_xhr.getAllResponseHeaders());
|
||||||
|
|
||||||
|
const url: string = getResponseURL(_xhr);
|
||||||
|
|
||||||
|
const statusText: string = _xhr.statusText || 'OK';
|
||||||
|
|
||||||
let responseOptions = new ResponseOptions({body, status, headers, statusText, url});
|
let responseOptions = new ResponseOptions({body, status, headers, statusText, url});
|
||||||
if (baseResponseOptions != null) {
|
if (baseResponseOptions != null) {
|
||||||
|
@ -86,7 +95,7 @@ export class XHRConnection implements Connection {
|
||||||
responseObserver.error(response);
|
responseObserver.error(response);
|
||||||
};
|
};
|
||||||
// error event handler
|
// error event handler
|
||||||
const onError = (err: any) => {
|
const onError = (err: ErrorEvent) => {
|
||||||
let responseOptions = new ResponseOptions({
|
let responseOptions = new ResponseOptions({
|
||||||
body: err,
|
body: err,
|
||||||
type: ResponseType.Error,
|
type: ResponseType.Error,
|
||||||
|
@ -138,7 +147,7 @@ export class XHRConnection implements Connection {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
setDetectedContentType(req: any /** TODO #9100 */, _xhr: XMLHttpRequest) {
|
setDetectedContentType(req: any /** TODO Request */, _xhr: any /** XMLHttpRequest */) {
|
||||||
// Skip if a custom Content-Type header is provided
|
// Skip if a custom Content-Type header is provided
|
||||||
if (req.headers != null && req.headers.get('Content-Type') != null) {
|
if (req.headers != null && req.headers.get('Content-Type') != null) {
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -9,7 +9,6 @@
|
||||||
import {Injectable} from '@angular/core';
|
import {Injectable} from '@angular/core';
|
||||||
import {AsyncTestCompleter, SpyObject, afterEach, beforeEach, beforeEachProviders, describe, expect, inject, it} from '@angular/core/testing/testing_internal';
|
import {AsyncTestCompleter, SpyObject, afterEach, beforeEach, beforeEachProviders, describe, expect, inject, it} from '@angular/core/testing/testing_internal';
|
||||||
import {__platform_browser_private__} from '@angular/platform-browser';
|
import {__platform_browser_private__} from '@angular/platform-browser';
|
||||||
|
|
||||||
import {BrowserXhr} from '../../src/backends/browser_xhr';
|
import {BrowserXhr} from '../../src/backends/browser_xhr';
|
||||||
import {CookieXSRFStrategy, XHRBackend, XHRConnection} from '../../src/backends/xhr_backend';
|
import {CookieXSRFStrategy, XHRBackend, XHRConnection} from '../../src/backends/xhr_backend';
|
||||||
import {BaseRequestOptions, RequestOptions} from '../../src/base_request_options';
|
import {BaseRequestOptions, RequestOptions} from '../../src/base_request_options';
|
||||||
|
@ -486,6 +485,7 @@ export function main() {
|
||||||
existingXHRs[0].setStatusCode(statusCode);
|
existingXHRs[0].setStatusCode(statusCode);
|
||||||
existingXHRs[0].dispatchEvent('load');
|
existingXHRs[0].dispatchEvent('load');
|
||||||
}));
|
}));
|
||||||
|
|
||||||
it('should normalize IE\'s 1223 status code into 204',
|
it('should normalize IE\'s 1223 status code into 204',
|
||||||
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
|
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
|
||||||
const statusCode = 1223;
|
const statusCode = 1223;
|
||||||
|
@ -502,6 +502,22 @@ export function main() {
|
||||||
existingXHRs[0].dispatchEvent('load');
|
existingXHRs[0].dispatchEvent('load');
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
it('should ignore response body for 204 status code',
|
||||||
|
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
|
||||||
|
const statusCode = 204;
|
||||||
|
const connection = new XHRConnection(
|
||||||
|
sampleRequest, new MockBrowserXHR(), new ResponseOptions({status: statusCode}));
|
||||||
|
|
||||||
|
connection.response.subscribe((res: Response) => {
|
||||||
|
expect(res.text()).toBe('');
|
||||||
|
async.done();
|
||||||
|
});
|
||||||
|
|
||||||
|
existingXHRs[0].setStatusCode(statusCode);
|
||||||
|
existingXHRs[0].setResponseText('Doge');
|
||||||
|
existingXHRs[0].dispatchEvent('load');
|
||||||
|
}));
|
||||||
|
|
||||||
it('should normalize responseText and response',
|
it('should normalize responseText and response',
|
||||||
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
|
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
|
||||||
const responseBody = 'Doge';
|
const responseBody = 'Doge';
|
||||||
|
|
Loading…
Reference in New Issue