fix(http): return Response headers
Properly parse and add response Headers to Response. Closes #5237
This commit is contained in:
parent
201f189d0e
commit
4332ccf72c
|
@ -2,6 +2,7 @@ import {ConnectionBackend, Connection} from '../interfaces';
|
||||||
import {ReadyStates, RequestMethods, ResponseTypes} from '../enums';
|
import {ReadyStates, RequestMethods, ResponseTypes} from '../enums';
|
||||||
import {Request} from '../static_request';
|
import {Request} from '../static_request';
|
||||||
import {Response} from '../static_response';
|
import {Response} from '../static_response';
|
||||||
|
import {Headers} from '../headers';
|
||||||
import {ResponseOptions, BaseResponseOptions} from '../base_response_options';
|
import {ResponseOptions, BaseResponseOptions} from '../base_response_options';
|
||||||
import {Injectable} from 'angular2/angular2';
|
import {Injectable} from 'angular2/angular2';
|
||||||
import {BrowserXhr} from './browser_xhr';
|
import {BrowserXhr} from './browser_xhr';
|
||||||
|
@ -34,8 +35,9 @@ export class XHRConnection implements Connection {
|
||||||
// responseText is the old-school way of retrieving response (supported by IE8 & 9)
|
// responseText is the old-school way of retrieving response (supported by IE8 & 9)
|
||||||
// response/responseType properties were introduced in XHR Level2 spec (supported by
|
// response/responseType properties were introduced in XHR Level2 spec (supported by
|
||||||
// IE10)
|
// IE10)
|
||||||
let xhrResponse = isPresent(_xhr.response) ? _xhr.response : _xhr.responseText;
|
let body = isPresent(_xhr.response) ? _xhr.response : _xhr.responseText;
|
||||||
|
|
||||||
|
let headers = Headers.fromResponseHeaderString(_xhr.getAllResponseHeaders());
|
||||||
|
|
||||||
// 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;
|
||||||
|
@ -44,9 +46,9 @@ export class XHRConnection implements Connection {
|
||||||
// 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.
|
||||||
if (status === 0) {
|
if (status === 0) {
|
||||||
status = xhrResponse ? 200 : 0;
|
status = body ? 200 : 0;
|
||||||
}
|
}
|
||||||
var responseOptions = new ResponseOptions({body: xhrResponse, status: status});
|
var responseOptions = new ResponseOptions({body, status, headers});
|
||||||
if (isPresent(baseResponseOptions)) {
|
if (isPresent(baseResponseOptions)) {
|
||||||
responseOptions = baseResponseOptions.merge(responseOptions);
|
responseOptions = baseResponseOptions.merge(responseOptions);
|
||||||
}
|
}
|
||||||
|
|
|
@ -54,6 +54,17 @@ export class Headers {
|
||||||
headers, (v, k) => { this._headersMap.set(k, isListLikeIterable(v) ? v : [v]); });
|
headers, (v, k) => { this._headersMap.set(k, isListLikeIterable(v) ? v : [v]); });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a new Headers instance from the given DOMString of Response Headers
|
||||||
|
*/
|
||||||
|
static fromResponseHeaderString(headersString: string): Headers {
|
||||||
|
return headersString.trim()
|
||||||
|
.split('\n')
|
||||||
|
.map(val => val.split(':'))
|
||||||
|
.map(([key, ...parts]) => ([key.trim(), parts.join(':').trim()]))
|
||||||
|
.reduce((headers, [key, value]) => !headers.set(key, value) && headers, new Headers());
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Appends a header to existing list of header values for a given header name.
|
* Appends a header to existing list of header values for a given header name.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -40,6 +40,7 @@ class MockBrowserXHR extends BrowserXhr {
|
||||||
setRequestHeader: any;
|
setRequestHeader: any;
|
||||||
callbacks = new Map<string, Function>();
|
callbacks = new Map<string, Function>();
|
||||||
status: number;
|
status: number;
|
||||||
|
responseHeaders: string;
|
||||||
constructor() {
|
constructor() {
|
||||||
super();
|
super();
|
||||||
var spy = new SpyObject();
|
var spy = new SpyObject();
|
||||||
|
@ -55,6 +56,10 @@ class MockBrowserXHR extends BrowserXhr {
|
||||||
|
|
||||||
setResponseText(value) { this.responseText = value; }
|
setResponseText(value) { this.responseText = value; }
|
||||||
|
|
||||||
|
setResponseHeaders(value) { this.responseHeaders = value; }
|
||||||
|
|
||||||
|
getAllResponseHeaders() { return this.responseHeaders || ''; }
|
||||||
|
|
||||||
addEventListener(type: string, cb: Function) { this.callbacks.set(type, cb); }
|
addEventListener(type: string, cb: Function) { this.callbacks.set(type, cb); }
|
||||||
|
|
||||||
removeEventListener(type: string, cb: Function) { this.callbacks.delete(type); }
|
removeEventListener(type: string, cb: Function) { this.callbacks.delete(type); }
|
||||||
|
@ -256,6 +261,30 @@ export function main() {
|
||||||
existingXHRs[0].dispatchEvent('load');
|
existingXHRs[0].dispatchEvent('load');
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
it('should parse response headers and add them to the response',
|
||||||
|
inject([AsyncTestCompleter], async => {
|
||||||
|
var statusCode = 200;
|
||||||
|
var connection = new XHRConnection(sampleRequest, new MockBrowserXHR(),
|
||||||
|
new ResponseOptions({status: statusCode}));
|
||||||
|
|
||||||
|
let responseHeaderString =
|
||||||
|
`Date: Fri, 20 Nov 2015 01:45:26 GMT
|
||||||
|
Content-Type: application/json; charset=utf-8
|
||||||
|
Transfer-Encoding: chunked
|
||||||
|
Connection: keep-alive`
|
||||||
|
|
||||||
|
connection.response.subscribe(res => {
|
||||||
|
expect(res.headers.get('Date')).toEqual('Fri, 20 Nov 2015 01:45:26 GMT');
|
||||||
|
expect(res.headers.get('Content-Type')).toEqual('application/json; charset=utf-8');
|
||||||
|
expect(res.headers.get('Transfer-Encoding')).toEqual('chunked');
|
||||||
|
expect(res.headers.get('Connection')).toEqual('keep-alive');
|
||||||
|
async.done();
|
||||||
|
});
|
||||||
|
|
||||||
|
existingXHRs[0].setResponseHeaders(responseHeaderString);
|
||||||
|
existingXHRs[0].setStatusCode(statusCode);
|
||||||
|
existingXHRs[0].dispatchEvent('load');
|
||||||
|
}));
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -63,4 +63,23 @@ export function main() {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('.fromResponseHeaderString()', () => {
|
||||||
|
|
||||||
|
it('should parse a response header string', () => {
|
||||||
|
|
||||||
|
let responseHeaderString = `Date: Fri, 20 Nov 2015 01:45:26 GMT
|
||||||
|
Content-Type: application/json; charset=utf-8
|
||||||
|
Transfer-Encoding: chunked
|
||||||
|
Connection: keep-alive`;
|
||||||
|
|
||||||
|
let responseHeaders = Headers.fromResponseHeaderString(responseHeaderString);
|
||||||
|
|
||||||
|
expect(responseHeaders.get('Date')).toEqual('Fri, 20 Nov 2015 01:45:26 GMT');
|
||||||
|
expect(responseHeaders.get('Content-Type')).toEqual('application/json; charset=utf-8');
|
||||||
|
expect(responseHeaders.get('Transfer-Encoding')).toEqual('chunked');
|
||||||
|
expect(responseHeaders.get('Connection')).toEqual('keep-alive');
|
||||||
|
|
||||||
|
});
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue