diff --git a/modules/@angular/http/src/backends/xhr_backend.ts b/modules/@angular/http/src/backends/xhr_backend.ts index 3b827ffa2c..32706bde06 100644 --- a/modules/@angular/http/src/backends/xhr_backend.ts +++ b/modules/@angular/http/src/backends/xhr_backend.ts @@ -35,7 +35,9 @@ export class XHRConnection implements Connection { this.response = new Observable((responseObserver: Observer) => { 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) diff --git a/modules/@angular/http/src/base_request_options.ts b/modules/@angular/http/src/base_request_options.ts index 9eb579b095..e761e21eeb 100644 --- a/modules/@angular/http/src/base_request_options.ts +++ b/modules/@angular/http/src/base_request_options.ts @@ -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((search)) : (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((options.search)) : ((options.search)).clone()) : - this.search + this.search, + withCredentials: isPresent(options) && isPresent(options.withCredentials) ? + options.withCredentials : + this.withCredentials }); } } diff --git a/modules/@angular/http/src/http.ts b/modules/@angular/http/src/http.ts index f68dc5645b..aeda0bc68a 100644 --- a/modules/@angular/http/src/http.ts +++ b/modules/@angular/http/src/http.ts @@ -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)) { diff --git a/modules/@angular/http/src/interfaces.ts b/modules/@angular/http/src/interfaces.ts index 4e48ba5db6..f11761a5bc 100644 --- a/modules/@angular/http/src/interfaces.ts +++ b/modules/@angular/http/src/interfaces.ts @@ -30,6 +30,7 @@ export interface RequestOptionsArgs { search?: string | URLSearchParams; headers?: Headers; body?: any; + withCredentials?: boolean; } /** diff --git a/modules/@angular/http/src/static_request.ts b/modules/@angular/http/src/static_request.ts index 3ce95605e7..4fbd8cf4b8 100644 --- a/modules/@angular/http/src/static_request.ts +++ b/modules/@angular/http/src/static_request.ts @@ -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; } diff --git a/modules/@angular/http/test/backends/xhr_backend_spec.ts b/modules/@angular/http/test/backends/xhr_backend_spec.ts index 63641174d6..06ceaed293 100644 --- a/modules/@angular/http/test/backends/xhr_backend_spec.ts +++ b/modules/@angular/http/test/backends/xhr_backend_spec.ts @@ -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'); + })); }); }); }