Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Full implementation of xhr.responseType, rigorous test and a perf imp… #16

Open
wants to merge 3 commits into
base: master
Choose a base branch
from

Conversation

pringseth
Copy link

…rovement.
Implemented section 3.6, subsections 8,9,10,11 of https://xhr.spec.whatwg.org/#the-response-attribute.
The test: test-response-type.js excerises it well.
Basically async download looks like this:

    xhr.open("GET", url, true);

    xhr.responseType =  responseType;

    xhr.onloadend = () => {
      if (xhr.status >= 200 && xhr.status < 300)
      {
        switch (responseType)
        {
          case "":
          case "text":
            resolve(xhr.responseText);
            break;
          case "document":
            resolve(xhr.responseXML);
            break;
          default:
            resolve(xhr.response);
            break;
        }
      }
      else
      {
        const errorTxt = `${xhr.status}: ${xhr.statusText}`;
        reject(errorTxt);
      }
    };

    xhr.send();

In order to use xhr.responseType="document" the npm package "@xmldom/xmldom" needs to be installed.
There's also been a perf improvement (new test: test-perf.js ):

As part of the implementation, there has been a major perf improvement.
On a 3 year old i9-10900K, a local download using this changelist of a 400MB Float32Array 
from node 'http' module takes about 300ms. However, using xmlhttprequest-ssl v2.1.1 it takes 372734ms.
That's over 1200x faster.

paul added 3 commits October 9, 2023 15:25
…. When the default xhr.responseType we only set xhr.responseText. To get the desired xhr.response we need to separately GET with xhr.responseType='arraybuffer'.
@mjwwit
Copy link
Owner

mjwwit commented Oct 10, 2023

Thanks for this! Looking at the scope of the changes I think I'll need some time to review it.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This test file actually contained one extra case; requesting binary data without setting xhr.responseType = 'arraybuffer'. This was previously covered on lines 36-48:

  xhr = new XMLHttpRequest();
  isSync = false;

  xhr.onreadystatechange = function () {
    if (xhr.readyState === 4) {
      assert.equal(xhr.response.toString(), 'Hello world!');
      assert.equal(xhr.getResponseHeader('content-type'), 'application/octet-stream')
      isSync = true;
    }
  }
  
  xhr.open("GET", "http://localhost:8888/binary", false);
  xhr.send();

When applying this test case to your changes in lib/XMLHttpRequest.js it fails. When checking browser behavior though, this case should work:

    var xhr = new XMLHttpRequest();

    xhr.onreadystatechange = function() {
      if (this.readyState == 4) {
        if ("Hello world!" !== this.response.toString()) {
            throw new Error(`Text does not match! ${this.response.toString()}`);
        }
      }
    };

    var url = "http://localhost:8888/binary";
    xhr.open("GET", url);
    xhr.send();

throw new Error(`Download from urlUtf8_2 has incorrect content: ${text2_f32} !== ${_f32_2}`);

try {
const { XMLSerializer } = require('@xmldom/xmldom'); // Throws when xmldom not installed.
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you think this warrants the addition of an optional peerDependency on @xmldom/xmldom?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
2 participants