FazBrowse GitHub Viewer | Trending |
URL:
| Home
Tools: [Download Repo ZIP]   [Original HTTPS Page]

XDomainRequest. IE 8 will not work when CORS requests · Issue #106 · developit/unfetch · GitHub

Repository navigation

XDomainRequest. IE 8 will not work when CORS requests #106

Description

steps to reproduce

unfetch@4.0.1:

<!-- page1.html -->
<body>
  <script src="https://unpkg.com/unfetch@4.0.1/polyfill/index.js"></script>
  <script src="https://unpkg.com/es6-promise-polyfill@1.2.0/promise.min.js"></script>
  <script>
    fetch('page2.html')
        .then(function(response) {
            return response.text();
        })
        .then(function(data) {
            console.log(data);
        });
  </script>
    
<!-- page2.html -->
... any data ...

use any http server that supports Access-Control-Allow-Origin headers:

npm install http-server -g
http-server -p 8081 --cors
  • --cors - to enable CORS via the Access-Control-Allow-Origin

result

Through VM WinXP SP3 with IE version: 8.0.6001.18702 Update version: 0

  • F12 - Document Mode = 8 and 7.

and/or

  • Win10 IE11 - F12 - Emulation - Document Mode = 7 and 8 / User agent: 7/8

It does not work at all!

user-space solutions

Here's my example of hack for already released unfetch version like 4.0.1. Works fine for IE7+:

var send = window.XMLHttpRequest.prototype.send;
window.XMLHttpRequest.prototype.send = function()
{
    this.onreadystatechange = function()
    {
        // TODO: prevent duplicate calling of onload if it's not CORS!
        if(this.readyState === 4 && this.status === 200) {
            return this.onload.apply(this, arguments);
        }
    }
    return send.apply(this, arguments);
}
 
// IE7+ ok now

Actually, even IE 11 with 5+ emulation, that of course strange :) because it should be ActiveXObject before IE7. Bad emulation :)

However, for real IE8 CORS support we should have requests through XDomainRequest not for XMLHttpRequest. Thus, your onload() is silent.

Activity

developit commented on Jan 9, 2019

Owner

Hi @3F - I'm not sure many libraries can be made to work just by aliasing XMLHttpRequest to XDomainRequest, since there are bugs in XDR that can cause requests to be queued indefinitely if not worked around. Instead, why not inject XDomainRequest support into XMLHttpRequest automatically?

var xhr2 = false;
try { xhr2 = 'useCredentials' in new XMLHttpRequest; } catch (e) {}
var old = window.XMLHttpRequest;
function XMLHttpRequest() {
  if (xhr2) return new old();
}
XMLHttpRequest.prototype.open = function(method, url, async, user, pass) {
  var pageOrigin = location.protocol + ':' + location.host;
  var self = this;
  function wrap(m) {
    xhr[m] = function() {
      for (var i in xhr) if (typeof xhr[i] !== 'function') {
        try { self[i] = xhr[i]; } catch (e) {}
      }
      if (fn) fn();
      if (self[m]) self[m].apply(self, arguments);
    };
  }
  var xhr;
  if (url && /^https?:\/\//i.test(url) && url.indexOf(host)!==0 && self.XDomainRequest) {
    xhr = new XDomainRequest();
    wrap('onload', function() {
      self.readyState = 4;
      if (self.onreadystatechange) self.onreadystatechange();
    });
    wrap('onerror', function() {
      self.readyState = 4;
      if (self.onreadystatechange) self.onreadystatechange();
    });
  }
  else {
    xhr = new old();
    wrap('onreadystatechange', function() {
      if (xhr.readyState===4) {
        if (xhr.status && xhr.status <400 && xhr.status >= 200) {
          if (self.onload) self.onload();
        }
        else if (self.onerror) self.onerror(Error(0));
      }
    };
  }
  this._xhr = xhr;
  xhr.timeout = self.timeout;
  wrap('onprogress');
  wrap('ontimeout');
  xhr.open(method, url, async, user, pass); 
};
XMLHttpRequest.prototype.abort = function(){
  this._xhr.abort();
};
XMLHttpRequest.prototype.getAllResponseHeaders = function() {
  try { return this._xhr.getAllResponseHeaders(); } catch (e) {}
};
XMLHttpRequest.prototype.getResponseHeaders = function() {
  try { return this._xhr.getResponseHeaders(); } catch (e) {}
};
XMLHttpRequest.prototype.send = function() {
  setTimeout(function (x) { x.send(); }, 0, this._xhr); 
};

3F commented on Jan 9, 2019

Author

@developit
Why not to use XHR + onreadystatechange (#107) ? It seems works for IE and we have no major changes for other browsers. Because onload just wraps onreadystatechange with an readystate = 4, so basically it solves this issue even without XDomainRequest.

developit commented on Jan 14, 2019

Owner

I'd be willing to do something like this if it doesn't increase filesize:

xhr.onreadystatechange = () => {
  if (xhr.readyState==4) {
    if (xhr.status/100|0) == 2) resolve(response());
    else reject(Error());
  }
};

If we use onreadystatechange to avoid onload we should also be avoiding onerror. IIRC it isn't supported in IE8- either.

(Also FWIW IE's emulation is super inaccurate)

3F commented on Jan 14, 2019

Author

Also FWIW IE's emulation is super inaccurate

VM WinXP SP3 with the real IE version: 8.0.6001.18702 as I wrote above.

or what IE version do you mean? about other cool IE emulation I already noticed above.

if (xhr.status/100|0) == 2)

isn't it easier to use !== 0 ? or you've found some RFC ? #107 (comment)

else reject(Error());

I did not understand this thought

developit commented on Jan 15, 2019

Owner

Ah you're right - I was forgetting resolve() is called even if the status is not ok (outside [200,399]). Given that, your if (xhr.status) resolve(response()) would work.

My point about onerror was that onload and onerror are both unsupported in IE8. If we're moving to onreadystatechange to improve support in those older browsers, we should include the error event as well.

3F commented on Jan 16, 2019

Author

if (xhr.status)

hmm, yes, at least Firefox uses uint16_t and uint32_t

uint16_t XMLHttpRequestMainThread::ReadyState
uint32_t XMLHttpRequestMainThread::GetStatus

so OK, why not :)

My point about onerror was that onload and onerror are both unsupported in IE8.

Right, it was implemented as an additional events much more later.

:) However,

we should include the error event as well.

It means nothing to IE.

Well, looks like the mentioned IE 8 will not reset status to 0 even for the same failed requests. For example, via the same an abort operations:

xhr.onreadystatechange = function()
{
    if(this.readyState !== 4) return;
    console.log('evt: ', this.readyState, this.status);
    console.log('rcv len: ', this.responseText.length);
}

xhr.open('GET', 'http://192.168.1.10:8082/rcv', true); 
// remote data is equal to 125 829 120 bytes for this example
...

IE 8:

* when abort:

    evt: 4 200        <<<<<
    rcv len: 596719

    evt: 4 200        <<<<<
    rcv len: 8902359

    evt: 4 200        <<<<<
    rcv len: 2701359


* when no abort:

    evt: 4 200
    Exception: Not enough storage is available to complete this operation.
    ( hmmm o_o )

Firefox 64:

* when abort:

    evt: 4 0    <<<<<
    rcv len: 0


* when no abort:

    evt: 4 200 
    rcv len: 125829120

So what does this mean

We can finally use something like:

request.onreadystatechange = function() {
    if(this.readyState === 4) {
        this.status ? resolve(response()) : reject(Error());
        // ------------------------------------^ still not for IE
    }
};

But, we will never make IE happy as you can see above.

For other modern browsers will be raised onerror.

Or to be sure, for full coverage the old implementations, we can also invoke this reject. Unfortunately, I have no info about all this cases. So ...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions


      Back | FazBrowse Home | New Git URL