Skip to content

Commit 21a4de9

Browse files
Dzmitry Shylovichchuckjaz
authored andcommitted
fix(http): correctly handle response body for 204 status code
closes #12830 fixes #12393
1 parent 82b3483 commit 21a4de9

File tree

2 files changed

+41
-16
lines changed

2 files changed

+41
-16
lines changed

modules/@angular/http/src/backends/xhr_backend.ts

Lines changed: 24 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88

99
import {Injectable} from '@angular/core';
1010
import {__platform_browser_private__} from '@angular/platform-browser';
11+
import {Observable} from 'rxjs/Observable';
12+
import {Observer} from 'rxjs/Observer';
1113
import {ResponseOptions} from '../base_response_options';
1214
import {ContentType, ReadyState, RequestMethod, ResponseContentType, ResponseType} from '../enums';
1315
import {Headers} from '../headers';
@@ -16,8 +18,6 @@ import {Connection, ConnectionBackend, XSRFStrategy} from '../interfaces';
1618
import {Request} from '../static_request';
1719
import {Response} from '../static_response';
1820
import {BrowserXhr} from './browser_xhr';
19-
import {Observable} from 'rxjs/Observable';
20-
import {Observer} from 'rxjs/Observer';
2121

2222
const XSSI_PREFIX = /^\)\]\}',?\n/;
2323

@@ -49,27 +49,36 @@ export class XHRConnection implements Connection {
4949
}
5050
// load event handler
5151
const onLoad = () => {
52-
// responseText is the old-school way of retrieving response (supported by IE8 & 9)
53-
// response/responseType properties were introduced in ResourceLoader Level2 spec (supported
54-
// by IE10)
55-
let body = _xhr.response === undefined ? _xhr.responseText : _xhr.response;
56-
// Implicitly strip a potential XSSI prefix.
57-
if (typeof body === 'string') body = body.replace(XSSI_PREFIX, '');
58-
const headers = Headers.fromResponseHeaderString(_xhr.getAllResponseHeaders());
59-
60-
const url = getResponseURL(_xhr);
61-
6252
// normalize IE9 bug (http://bugs.jquery.com/ticket/1450)
6353
let status: number = _xhr.status === 1223 ? 204 : _xhr.status;
6454

55+
let body: any = null;
56+
57+
// HTTP 204 means no content
58+
if (status !== 204) {
59+
// responseText is the old-school way of retrieving response (supported by IE8 & 9)
60+
// response/responseType properties were introduced in ResourceLoader Level2 spec
61+
// (supported by IE10)
62+
body = _xhr.response == null ? _xhr.responseText : _xhr.response;
63+
64+
// Implicitly strip a potential XSSI prefix.
65+
if (typeof body === 'string') {
66+
body = body.replace(XSSI_PREFIX, '');
67+
}
68+
}
69+
6570
// fix status code when it is 0 (0 status is undocumented).
6671
// Occurs when accessing file resources or on Android 4.1 stock browser
6772
// while retrieving files from application cache.
6873
if (status === 0) {
6974
status = body ? 200 : 0;
7075
}
7176

72-
const statusText = _xhr.statusText || 'OK';
77+
const headers: Headers = Headers.fromResponseHeaderString(_xhr.getAllResponseHeaders());
78+
79+
const url: string = getResponseURL(_xhr);
80+
81+
const statusText: string = _xhr.statusText || 'OK';
7382

7483
let responseOptions = new ResponseOptions({body, status, headers, statusText, url});
7584
if (baseResponseOptions != null) {
@@ -86,7 +95,7 @@ export class XHRConnection implements Connection {
8695
responseObserver.error(response);
8796
};
8897
// error event handler
89-
const onError = (err: any) => {
98+
const onError = (err: ErrorEvent) => {
9099
let responseOptions = new ResponseOptions({
91100
body: err,
92101
type: ResponseType.Error,
@@ -138,7 +147,7 @@ export class XHRConnection implements Connection {
138147
});
139148
}
140149

141-
setDetectedContentType(req: any /** TODO #9100 */, _xhr: XMLHttpRequest) {
150+
setDetectedContentType(req: any /** TODO Request */, _xhr: any /** XMLHttpRequest */) {
142151
// Skip if a custom Content-Type header is provided
143152
if (req.headers != null && req.headers.get('Content-Type') != null) {
144153
return;

modules/@angular/http/test/backends/xhr_backend_spec.ts

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@
99
import {Injectable} from '@angular/core';
1010
import {AsyncTestCompleter, SpyObject, afterEach, beforeEach, beforeEachProviders, describe, expect, inject, it} from '@angular/core/testing/testing_internal';
1111
import {__platform_browser_private__} from '@angular/platform-browser';
12-
1312
import {BrowserXhr} from '../../src/backends/browser_xhr';
1413
import {CookieXSRFStrategy, XHRBackend, XHRConnection} from '../../src/backends/xhr_backend';
1514
import {BaseRequestOptions, RequestOptions} from '../../src/base_request_options';
@@ -486,6 +485,7 @@ export function main() {
486485
existingXHRs[0].setStatusCode(statusCode);
487486
existingXHRs[0].dispatchEvent('load');
488487
}));
488+
489489
it('should normalize IE\'s 1223 status code into 204',
490490
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
491491
const statusCode = 1223;
@@ -502,6 +502,22 @@ export function main() {
502502
existingXHRs[0].dispatchEvent('load');
503503
}));
504504

505+
it('should ignore response body for 204 status code',
506+
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
507+
const statusCode = 204;
508+
const connection = new XHRConnection(
509+
sampleRequest, new MockBrowserXHR(), new ResponseOptions({status: statusCode}));
510+
511+
connection.response.subscribe((res: Response) => {
512+
expect(res.text()).toBe('');
513+
async.done();
514+
});
515+
516+
existingXHRs[0].setStatusCode(statusCode);
517+
existingXHRs[0].setResponseText('Doge');
518+
existingXHRs[0].dispatchEvent('load');
519+
}));
520+
505521
it('should normalize responseText and response',
506522
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
507523
const responseBody = 'Doge';

0 commit comments

Comments
 (0)