feat(http): added withCredentials support

Taken into account the withCredentials property within the request options:
- added corresponding property in the RequestOptions class
- added corresponding property in the Request class
- handle this property when merging options
- set the withCredentials property on the XHR object when specified

Added a test in the xhr_backend_spec.ts to check that the property is actually
set on the XHR object

Closes https://github.com/angular/http/issues/65

Closes #7281

Closes #7281
This commit is contained in:
Thierry Templier 2016-02-24 22:57:35 +01:00 committed by Misko Hevery
parent 0f0a8ade7c
commit 95af14b97c
6 changed files with 40 additions and 4 deletions

View File

@ -35,7 +35,9 @@ export class XHRConnection implements Connection {
this.response = new Observable<Response>((responseObserver: Observer<Response>) => {
let _xhr: XMLHttpRequest = browserXHR.build();
_xhr.open(RequestMethod[req.method].toUpperCase(), req.url);
if (isPresent(req.withCredentials)) {
_xhr.withCredentials = req.withCredentials;
}
// load event handler
let onLoad = () => {
// responseText is the old-school way of retrieving response (supported by IE8 & 9)

View File

@ -52,7 +52,11 @@ export class RequestOptions {
* Search parameters to be included in a {@link Request}.
*/
search: URLSearchParams;
constructor({method, headers, body, url, search}: RequestOptionsArgs = {}) {
/**
* Enable use credentials for a {@link Request}.
*/
withCredentials: boolean;
constructor({method, headers, body, url, search, withCredentials}: RequestOptionsArgs = {}) {
this.method = isPresent(method) ? normalizeMethodName(method) : null;
this.headers = isPresent(headers) ? headers : null;
this.body = isPresent(body) ? body : null;
@ -60,6 +64,7 @@ export class RequestOptions {
this.search = isPresent(search) ? (isString(search) ? new URLSearchParams(<string>(search)) :
<URLSearchParams>(search)) :
null;
this.withCredentials = isPresent(withCredentials) ? withCredentials : null;
}
/**
@ -96,7 +101,10 @@ export class RequestOptions {
search: isPresent(options) && isPresent(options.search) ?
(isString(options.search) ? new URLSearchParams(<string>(options.search)) :
(<URLSearchParams>(options.search)).clone()) :
this.search
this.search,
withCredentials: isPresent(options) && isPresent(options.withCredentials) ?
options.withCredentials :
this.withCredentials
});
}
}

View File

@ -23,7 +23,8 @@ function mergeOptions(defaultOpts: BaseRequestOptions, providedOpts: RequestOpti
url: providedOpts.url || url,
search: providedOpts.search,
headers: providedOpts.headers,
body: providedOpts.body
body: providedOpts.body,
withCredentials: providedOpts.withCredentials
}));
}
if (isPresent(method)) {

View File

@ -30,6 +30,7 @@ export interface RequestOptionsArgs {
search?: string | URLSearchParams;
headers?: Headers;
body?: any;
withCredentials?: boolean;
}
/**

View File

@ -59,6 +59,8 @@ export class Request {
private _body: any;
/** Type of the request body **/
private contentType: ContentType;
/** Enable use credentials */
withCredentials: boolean;
constructor(requestOptions: RequestArgs) {
// TODO: assert that url is present
let url = requestOptions.url;
@ -81,6 +83,7 @@ export class Request {
// Defaults to 'omit', consistent with browser
// TODO(jeffbcross): implement behavior
this.headers = new Headers(requestOptions.headers);
this.withCredentials = requestOptions.withCredentials;
}

View File

@ -42,6 +42,7 @@ class MockBrowserXHR extends BrowserXhr {
responseHeaders: string;
responseURL: string;
statusText: string;
withCredentials: boolean;
constructor() {
super();
@ -511,6 +512,26 @@ export function main() {
existingXHRs[0].dispatchEvent('load');
}));
it('should set withCredentials to true when defined in request options for CORS situations',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
var statusCode = 200;
sampleRequest.withCredentials = true;
var mockXhr = new MockBrowserXHR();
var connection =
new XHRConnection(sampleRequest, mockXhr, new ResponseOptions({status: statusCode}));
var responseHeaders = `X-Request-URL: http://somedomain.com
Foo: Bar`
connection.response.subscribe((res: Response) => {
expect(res.url).toEqual('http://somedomain.com');
expect(existingXHRs[0].withCredentials).toBeTruthy();
async.done();
});
existingXHRs[0].setResponseHeaders(responseHeaders);
existingXHRs[0].setStatusCode(statusCode);
existingXHRs[0].dispatchEvent('load');
}));
});
});
}