Skip to content

Commit

Permalink
fix(AjaxObservable): support withCredentials for CORS request
Browse files Browse the repository at this point in the history
- AjaxRequest now support setting withCredentials flag

closes ReactiveX#1732, ReactiveX#1711
  • Loading branch information
kwonoj committed Jun 9, 2016
1 parent 01df713 commit 58ee4ce
Show file tree
Hide file tree
Showing 3 changed files with 60 additions and 13 deletions.
1 change: 1 addition & 0 deletions spec/helpers/ajax-helper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,7 @@ export class MockXMLHttpRequest {
method: any;
data: any;
requestHeaders: any = {};
withCredentials: boolean = false;

constructor() {
this.previousRequest = MockXMLHttpRequest.recentRequest;
Expand Down
22 changes: 22 additions & 0 deletions spec/observables/dom/ajax-spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,28 @@ describe('Observable.ajax', () => {
root.XMLHttpRequest = rXHR;
});

it('should create default XMLHttpRequest for non CORS', () => {
const obj: Rx.AjaxRequest = {
url: '/',
method: ''
};

Rx.Observable.ajax(obj).subscribe();
expect(MockXMLHttpRequest.mostRecent.withCredentials).to.be.false;
});

it('should create XMLHttpRequest for CORS', () => {
const obj: Rx.AjaxRequest = {
url: '/',
method: '',
crossDomain: true,
withCredentials: true
};

Rx.Observable.ajax(obj).subscribe();
expect(MockXMLHttpRequest.mostRecent.withCredentials).to.be.true;
});

it('should set headers', () => {
const obj: Rx.AjaxRequest = {
url: '/talk-to-me-goose',
Expand Down
50 changes: 37 additions & 13 deletions src/observable/dom/AjaxObservable.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,25 +16,48 @@ export interface AjaxRequest {
password?: string;
hasContent?: boolean;
crossDomain?: boolean;
withCredentials?: boolean;
createXHR?: () => XMLHttpRequest;
progressSubscriber?: Subscriber<any>;
resultSelector?: <T>(response: AjaxResponse) => T;
responseType?: string;
}

function createXHRDefault(): XMLHttpRequest {
let xhr = new root.XMLHttpRequest();
if (this.crossDomain) {
function getCORSRequest(): XMLHttpRequest {
if (root.XMLHttpRequest) {
const xhr = new root.XMLHttpRequest();
if ('withCredentials' in xhr) {
xhr.withCredentials = true;
return xhr;
} else if (!!root.XDomainRequest) {
return new root.XDomainRequest();
} else {
throw new Error('CORS is not supported by your browser');
xhr.withCredentials = !!this.withCredentials;
}
} else {
return xhr;
} else if (!!root.XDomainRequest) {
return new root.XDomainRequest();
} else {
throw new Error('CORS is not supported by your browser');
}
}

function getXMLHttpRequest(): XMLHttpRequest {
if (root.XMLHttpRequest) {
return new root.XMLHttpRequest();
} else {
let progId: string;
try {
const progIds = ['Msxml2.XMLHTTP', 'Microsoft.XMLHTTP', 'Msxml2.XMLHTTP.4.0'];
for (let i = 0; i < 3; i++) {
try {
progId = progIds[i];
if (new root.ActiveXObject(progId)) {
break;
}
} catch (e) {
//suppress exceptions
}
}
return new root.ActiveXObject(progId);
} catch (e) {
throw new Error('XMLHttpRequest is not supported by your browser');
}
}
}

Expand Down Expand Up @@ -104,8 +127,6 @@ export class AjaxObservable<T> extends Observable<T> {
* @name ajax
* @owner Observable
*/
static _create_stub(): void { return null; }

static create: AjaxCreationMethod = (() => {
const create: any = (urlOrRequest: string | AjaxRequest) => {
return new AjaxObservable(urlOrRequest);
Expand All @@ -127,8 +148,11 @@ export class AjaxObservable<T> extends Observable<T> {

const request: AjaxRequest = {
async: true,
createXHR: createXHRDefault,
createXHR: function() {
return this.crossDomain ? getCORSRequest.call(this) : getXMLHttpRequest();
},
crossDomain: false,
withCredentials: false,
headers: {},
method: 'GET',
responseType: 'json',
Expand Down

0 comments on commit 58ee4ce

Please sign in to comment.