Skip to content

Commit

Permalink
fix(http): return Response headers
Browse files Browse the repository at this point in the history
Properly parse and add response Headers to Response.

Closes #5237
  • Loading branch information
robwormald committed Nov 23, 2015
1 parent 201f189 commit 4332ccf
Show file tree
Hide file tree
Showing 4 changed files with 64 additions and 3 deletions.
8 changes: 5 additions & 3 deletions modules/angular2/src/http/backends/xhr_backend.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import {ConnectionBackend, Connection} from '../interfaces';
import {ReadyStates, RequestMethods, ResponseTypes} from '../enums';
import {Request} from '../static_request';
import {Response} from '../static_response';
import {Headers} from '../headers';
import {ResponseOptions, BaseResponseOptions} from '../base_response_options';
import {Injectable} from 'angular2/angular2';
import {BrowserXhr} from './browser_xhr';
Expand Down Expand Up @@ -34,8 +35,9 @@ export class XHRConnection implements Connection {
// 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 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)
let status: number = _xhr.status === 1223 ? 204 : _xhr.status;
Expand All @@ -44,9 +46,9 @@ export class XHRConnection implements Connection {
// Occurs when accessing file resources or on Android 4.1 stock browser
// while retrieving files from application cache.
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)) {
responseOptions = baseResponseOptions.merge(responseOptions);
}
Expand Down
11 changes: 11 additions & 0 deletions modules/angular2/src/http/headers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,17 @@ export class Headers {
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.
*/
Expand Down
29 changes: 29 additions & 0 deletions modules/angular2/test/http/backends/xhr_backend_spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ class MockBrowserXHR extends BrowserXhr {
setRequestHeader: any;
callbacks = new Map<string, Function>();
status: number;
responseHeaders: string;
constructor() {
super();
var spy = new SpyObject();
Expand All @@ -55,6 +56,10 @@ class MockBrowserXHR extends BrowserXhr {

setResponseText(value) { this.responseText = value; }

setResponseHeaders(value) { this.responseHeaders = value; }

getAllResponseHeaders() { return this.responseHeaders || ''; }

addEventListener(type: string, cb: Function) { this.callbacks.set(type, cb); }

removeEventListener(type: string, cb: Function) { this.callbacks.delete(type); }
Expand Down Expand Up @@ -256,6 +261,30 @@ export function main() {
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');
}));
});
});
}
19 changes: 19 additions & 0 deletions modules/angular2/test/http/headers_spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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');

});
});
}

0 comments on commit 4332ccf

Please sign in to comment.