From 0eaadd60c716050f5e3701d513a028a9cd49085a Mon Sep 17 00:00:00 2001
From: Ben Lesh <ben@benlesh.com>
Date: Fri, 31 Jul 2020 14:59:22 -0500
Subject: [PATCH] refactor(ajax): Drop support for IE10 and lower

This gets us in-line with other AJAX implementations like Axios.

BREAKING CHANGE: Ajax implementation drops support for IE10 and lower. This puts us in-line with other implementations and helps clean up code in this area
---
 spec/observables/dom/ajax-spec.ts             | 165 +-----------------
 src/internal/observable/dom/AjaxObservable.ts |  56 +-----
 2 files changed, 5 insertions(+), 216 deletions(-)

diff --git a/spec/observables/dom/ajax-spec.ts b/spec/observables/dom/ajax-spec.ts
index b94ed58d51..c37a8d77b1 100644
--- a/spec/observables/dom/ajax-spec.ts
+++ b/spec/observables/dom/ajax-spec.ts
@@ -40,22 +40,6 @@ describe('ajax', () => {
     expect(MockXMLHttpRequest.mostRecent.withCredentials).to.be.false;
   });
 
-  it('should try to create AXObject for XHR in old version of IE', () => {
-    const axObjectStub = sandbox.stub();
-    axObjectStub.returns(sinon.stub(new MockXMLHttpRequest()));
-    root.ActiveXObject = axObjectStub;
-    root.XMLHttpRequest = null;
-
-    const obj: AjaxRequest = {
-      url: '/',
-      method: '',
-      crossDomain: false,
-    };
-
-    ajax(obj).subscribe();
-    expect(axObjectStub).to.have.been.called;
-  });
-
   it('should raise an error if not able to create XMLHttpRequest', () => {
     root.XMLHttpRequest = null;
     root.ActiveXObject = null;
@@ -80,23 +64,6 @@ describe('ajax', () => {
     expect(MockXMLHttpRequest.mostRecent.withCredentials).to.be.true;
   });
 
-  it('should try to create XDomainRequest for CORS if XMLHttpRequest is not available', () => {
-    const xDomainStub = sandbox.stub();
-    xDomainStub.returns(sinon.stub(new MockXMLHttpRequest()));
-    root.XDomainRequest = xDomainStub;
-    root.XMLHttpRequest = null;
-
-    const obj: AjaxRequest = {
-      url: '/',
-      method: '',
-      crossDomain: true,
-      withCredentials: true
-    };
-
-    ajax(obj).subscribe();
-    expect(xDomainStub).to.have.been.called;
-  });
-
   it('should raise an error if not able to create CORS request', () => {
     root.XMLHttpRequest = null;
     root.XDomainRequest = null;
@@ -820,39 +787,7 @@ describe('ajax', () => {
       expect(result!.response).to.equal(expected);
       expect(complete).to.be.true;
     });
-
-    it('should succeed in IE on 204 No Content', () => {
-      const expected: null = null;
-      let result: AjaxResponse;
-      let complete = false;
-
-      root.XMLHttpRequest = MockXMLHttpRequestInternetExplorer;
-
-      ajax.post('/flibbertyJibbet', expected)
-        .subscribe(x => {
-          result = x;
-        }, null, () => {
-          complete = true;
-        });
-
-      const request = MockXMLHttpRequest.mostRecent;
-
-      expect(request.method).to.equal('POST');
-      expect(request.url).to.equal('/flibbertyJibbet');
-      expect(request.requestHeaders).to.deep.equal({
-        'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'
-      });
-
-      //IE behavior: IE does not provide the a responseText property, so also exercise the code which handles this.
-      request.respondWith({
-          'status': 204,
-          'contentType': 'application/json'
-      });
-
-      expect(result!.response).to.equal(expected);
-      expect(complete).to.be.true;
-    });
-
+    
     it('should emit progress event when progressSubscriber is specified', function() {
       const spy = sinon.spy();
       const progressSubscriber = (<any>{
@@ -881,69 +816,6 @@ describe('ajax', () => {
 
       expect(spy).to.be.calledThrice;
     });
-
-    it('should emit progress event when progressSubscriber is specified in IE', function() {
-      const spy = sinon.spy();
-      const progressSubscriber = (<any>{
-        next: spy,
-        error: () => {
-          // noop
-        },
-        complete: () => {
-          // noop
-        }
-      });
-
-      root.XMLHttpRequest = MockXMLHttpRequestInternetExplorer;
-      root.XDomainRequest = MockXMLHttpRequestInternetExplorer;
-
-      ajax({
-        url: '/flibbertyJibbet',
-        progressSubscriber
-      })
-        .subscribe();
-
-      const request = MockXMLHttpRequest.mostRecent;
-
-      request.respondWith({
-        'status': 200,
-        'contentType': 'application/json',
-        'responseText': JSON.stringify({})
-      }, 3);
-
-      expect(spy.callCount).to.equal(3);
-    });
-
-  });
-
-  it('should work fine when XMLHttpRequest onreadystatechange property is monkey patched', function() {
-    Object.defineProperty(root.XMLHttpRequest.prototype, 'onreadystatechange', {
-      set: function (fn: (e: ProgressEvent) => any) {
-        const wrapFn = (ev: ProgressEvent) => {
-          const result = fn.call(this, ev);
-          if (result === false) {
-            ev.preventDefault();
-          }
-        };
-        this['_onreadystatechange'] = wrapFn;
-      },
-      get() {
-        return this['_onreadystatechange'];
-      },
-      configurable: true
-    });
-
-    ajax({
-      url: '/flibbertyJibbet'
-    })
-      .subscribe();
-
-    const request = MockXMLHttpRequest.mostRecent;
-    expect(() => {
-      request.onreadystatechange((<any>'onreadystatechange'));
-    }).not.throw();
-
-    delete root.XMLHttpRequest.prototype.onreadystatechange;
   });
 
   it('should work fine when XMLHttpRequest ontimeout property is monkey patched', function(done) {
@@ -1255,37 +1127,4 @@ class MockXMLHttpRequest {
       this.upload['on' + name](e);
     }
   }
-}
-
-class MockXMLHttpRequestInternetExplorer extends MockXMLHttpRequest {
-
-  private mockHttp204() {
-    this.responseType = '';
-    this.responseText = '';
-    this.response = '';
-  }
-
-  protected jsonResponseValue(response: any) {
-    if (this.status == 204) {
-      this.mockHttp204();
-      return;
-    }
-    return super.jsonResponseValue(response);
-  }
-
-  protected defaultResponseValue() {
-    if (this.status == 204) {
-      this.mockHttp204();
-      return;
-    }
-    return super.defaultResponseValue();
-  }
-
-  triggerUploadEvent(this: any, name: any, eventObj?: any): void {
-    // TODO: create a better default event
-    const e: any = eventObj || {};
-    if (this['on' + name]) {
-      this['on' + name](e);
-    }
-  }
-}
+}
\ No newline at end of file
diff --git a/src/internal/observable/dom/AjaxObservable.ts b/src/internal/observable/dom/AjaxObservable.ts
index 31c39e6209..3ef9b70edc 100644
--- a/src/internal/observable/dom/AjaxObservable.ts
+++ b/src/internal/observable/dom/AjaxObservable.ts
@@ -21,45 +21,10 @@ export interface AjaxRequest {
   responseType?: string;
 }
 
-// Declare older APIs we'll check for on global scope.
-declare const XDomainRequest: any;
-declare const ActiveXObject: any;
-
 function isFormData(body: any): body is FormData {
   return typeof FormData !== 'undefined' && body instanceof FormData;
 }
 
-function getCORSRequest(): XMLHttpRequest {
-  if (typeof XMLHttpRequest === 'function') {
-    return new XMLHttpRequest();
-  } else if (typeof XDomainRequest === 'function') {
-    return new XDomainRequest();
-  } else {
-    throw new Error('CORS is not supported by your browser');
-  }
-}
-
-const ancientInternetExplorerProgIDs = ['Msxml2.XMLHTTP', 'Microsoft.XMLHTTP', 'Msxml2.XMLHTTP.4.0'];
-
-function getXMLHttpRequest(): XMLHttpRequest {
-  if (XMLHttpRequest) {
-    return new XMLHttpRequest();
-  } else if (typeof ActiveXObject === 'function') {
-    // TODO: Remove when we stop supporting IE.
-    for (const progId of ancientInternetExplorerProgIDs) {
-      try {
-        const axoXHR = new ActiveXObject(progId);
-        if (axoXHR) {
-          return axoXHR;
-        }
-      } catch (e) {
-        // Ignore and try the next one
-      }
-    }
-  }
-  throw new Error('XMLHttpRequest is not supported by your browser');
-}
-
 export interface AjaxCreationMethod {
   (urlOrRequest: string | AjaxRequest): Observable<AjaxResponse>;
   get(url: string, headers?: Object): Observable<AjaxResponse>;
@@ -162,9 +127,7 @@ export class AjaxObservable<T> extends Observable<T> {
 
     const request: AjaxRequest = {
       async: true,
-      createXHR: function (this: AjaxRequest) {
-        return this.crossDomain ? getCORSRequest() : getXMLHttpRequest();
-      },
+      createXHR: () => new XMLHttpRequest(),
       crossDomain: true,
       withCredentials: false,
       headers: {},
@@ -351,12 +314,8 @@ export class AjaxSubscriber<T> extends Subscriber<Event> {
           const { progressSubscriber } = <any>xhrProgress;
           progressSubscriber.next(e);
         };
-        if (typeof XDomainRequest === 'function') {
-          xhr.onprogress = xhrProgress;
-        } else {
-          xhr.upload.onprogress = xhrProgress;
-        }
         (<any>xhrProgress).progressSubscriber = progressSubscriber;
+        xhr.upload.onprogress = xhrProgress;
       }
       let xhrError: (e: any) => void;
       xhrError = function (this: XMLHttpRequest, e: ErrorEvent) {
@@ -378,19 +337,10 @@ export class AjaxSubscriber<T> extends Subscriber<Event> {
       (<any>xhrError).progressSubscriber = progressSubscriber;
     }
 
-    function xhrReadyStateChange(this: XMLHttpRequest) {
-      return;
-    }
-    xhr.onreadystatechange = xhrReadyStateChange;
-    (<any>xhrReadyStateChange).subscriber = this;
-    (<any>xhrReadyStateChange).progressSubscriber = progressSubscriber;
-    (<any>xhrReadyStateChange).request = request;
-
     function xhrLoad(this: XMLHttpRequest, e: Event) {
       const { subscriber, progressSubscriber, request } = <any>xhrLoad;
       if (this.readyState === 4) {
-        // normalize IE9 bug (http://bugs.jquery.com/ticket/1450)
-        let status: number = this.status === 1223 ? 204 : this.status;
+        let status = this.status;
         let response: any = this.responseType === 'text' ? this.response || this.responseText : this.response;
 
         // fix status code when it is 0 (0 status is undocumented).