Skip to content

Fix/freewheel xhr location compliance - #141

Closed
vjain008 wants to merge 9 commits into
developfrom
fix/freewheel-xhr-location-compliance
Closed

vjain008 wants to merge 9 commits into
developfrom
fix/freewheel-xhr-location-compliance

Conversation

@vjain008

Copy link
Copy Markdown
Contributor

No description provided.

This module provides a factory function to create browser-compatible
location objects that work consistently across NativeScript environments.

Fixes issues with:
- window.location.protocol missing colon
- Missing hostname, port, origin, pathname properties
- Undefined values causing FreeWheel orig parameter to be malformed
- Inconsistency between window.location and globalThis.location
CRITICAL FIXES:
1. Add missing response properties: response, responseURL
2. Add timeout support with proper event handling
3. Fix loadend dispatch - must fire for ALL terminal events (load, error, timeout, abort)
4. Populate statusText before callbacks fire
5. Separate error/abort/timeout callbacks from load callback
6. Add proper state transition logging
7. Preserve full URL through request chain
8. Handle non-2xx HTTP responses correctly (not as errors)
9. Add diagnostic logging support for FreeWheel debugging

These changes ensure:
- FreeWheel receives response before 5-second timeout
- All callback handlers execute in correct order
- Complex query strings (semicolons, ampersands, encoding) preserved
- Multiple concurrent XHR instances remain isolated
- Response status/body available before onload callback
- Add protocol colon (file: not file)
- Add all missing properties: hostname, port, origin, pathname, search, hash
- Set globalThis.location to match window.location
- Ensure encodeURIComponent(location.protocol + '//' + location.host) works correctly
- Add protocol colon (file: not file)
- Add all missing properties: hostname, port, origin, pathname, search, hash
- Set globalThis.location to match window.location
- Ensure encodeURIComponent(location.protocol + '//' + location.host) works correctly
- Add protocol colon (file: not file)
- Add all missing properties: hostname, port, origin, pathname, search, hash
- Set globalThis.location to match window.location
- Ensure encodeURIComponent(location.protocol + '//' + location.host) works correctly
Documents:
- All 8 files changed
- Root causes and fixes for each
- Before/after code comparisons
- Test strategy and verification
- Performance impact
- Backward compatibility assurance
- Rollback procedures
- Future enhancements
@vjain008
vjain008 requested a review from a team as a code owner August 21, 2026 21:09
Copilot AI lite review requested due to automatic review settings August 21, 2026 21:09
@rdkcmf-jenkins

Copy link
Copy Markdown
Contributor

b'## Blackduck scan failure details

Summary: 0 violations, 0 files pending approval, 1 file pending identification.

  • Protex Server Path: /home/blackduck/github/rdkNativeScript/141/rdkcentral/rdkNativeScript

  • Commit: 63db7f5

Report detail: gist'

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

This PR targets FreeWheel compatibility in the NativeScript JS runtime by making window.location values more browser-like and bringing the XMLHttpRequest polyfill closer to W3C event/property semantics, with added tests and diagnostic tooling to aid debugging.

Changes:

  • Updated the XHR polyfill to add W3C properties (response, responseURL, timeout) and refine terminal event dispatch (load vs error/timeout/abort + loadend).
  • Standardized window.location objects across runtime initialization paths to avoid malformed protocol + "//" + host values used by FreeWheel.
  • Added new tests and documentation covering location encoding and XHR lifecycle expectations.

Reviewed changes

Copilot reviewed 9 out of 9 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
utils/xhrdiagnostics.js Adds an optional XHR lifecycle diagnostic logger (new utility).
utils/xhr.js Enhances XHR polyfill with timeout/response properties and adjusted event semantics.
utils/window.js Replaces minimal window.location stub with a fuller, FreeWheel-compatible shape; also re-indents existing code.
utils/location.js Adds a location object factory for creating standardized location objects (new utility).
test/xhr.test.js Adds a standalone test suite for XHR/location behavior and event dispatch expectations.
test/location-encoding.test.js Adds encoding-focused tests for FreeWheel-style orig construction.
src/jsc/modules/windowwrapper.js Updates JSC window wrapper location shape and syncs globalThis.location.
src/jsc/modules/linkedjsdomwrapper.js Updates linked JSDOM wrapper location shape and syncs globalThis.location.
FREEWHEEL_FIX_SUMMARY.md Adds a detailed write-up of the problem, root causes, and the implemented changes.
Suppressed comments (5)

utils/xhr.js:571

  • The transport 'abort' handler always converts an abort into handleError(), which results in an 'error' event firing for intentional aborts/timeouts. It should ignore aborts once the XHR is already in a terminal state (sendFlag cleared / errorFlag set).
      if (typeof request.on === "function") {
        request.on("abort", function() {
          if (timeoutHandle) {
            clearTimeout(timeoutHandle);
            timeoutHandle = null;
          }
          self.handleError(new Error("XMLHttpRequest: request aborted by transport"));
        });
      }

utils/xhr.js:553

  • The request-level error/abort handlers always call handleError(). When abort() or the timeout path aborts the underlying transport, these handlers can incorrectly dispatch an 'error' event (and an extra loadend) for what should be an abort/timeout terminal event.
      // Error handler for the request
      var errorHandler = function errorHandler(error) {
        if (timeoutHandle) {
          clearTimeout(timeoutHandle);
          timeoutHandle = null;
        }
        self.handleError(error);
      };

utils/xhr.js:599

  • In the timeout path, request.abort() is called before sendFlag/errorFlag are updated. If the transport emits an 'abort' or 'error' event immediately, the request-level handlers can still call handleError() and dispatch an erroneous 'error' event in addition to 'timeout'.
      if (self.timeout > 0) {
        timeoutHandle = setTimeout(function() {
          if (sendFlag && request) {
            logDiag('timeout fired after ' + self.timeout + 'ms, aborting request');
            
            request.abort();
            request = null;
            sendFlag = false;
            
            self.status = 0;
            self.statusText = 'Timeout';
            self.responseText = '';
            self.response = '';
            errorFlag = true;

            setState(self.DONE);
            
            // Per W3C spec, dispatch timeout event
            self.dispatchEvent('timeout');
            // After timeout, must dispatch loadend
            self.dispatchEvent('loadend');
          }
        }, self.timeout);
      }

utils/xhr.js:665

  • abort() calls request.abort() before setting sendFlag/errorFlag. If the transport emits 'abort'/'error' synchronously, the request-level handlers can still call handleError() and dispatch an 'error' event in addition to the intended abort/loadend events.
    if (request) {
      request.abort();
      request = null;
    }

utils/window.js:215

  • Performance.clearMarks() iterates entries, but that identifier is not defined in this method (it was a local in mark()). This will throw and leave marks uncleared; use this.entries instead.
   clearMarks()
   {
     for (var key in entries)
     {
         entries[key] = null;

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread utils/window.js
entries[name]['startTime'] = Date.now();
console.log("KRISHNA MARKING2 " + name);
}
if (options != undefined && option['detail'] != undefined)
Comment thread utils/xhr.js
Comment on lines 222 to 227
this.statusText = null;
this.responseText = "";
this.responseXML = "";
this.response = "";
this.responseURL = "";
this.readyState = this.UNSENT;
Comment thread test/xhr.test.js

TestRunner.it('xhr.open changes readyState to OPENED (1)', function() {
var xhr = new XMLHttpRequest();
xhr.open('GET', 'http://example.com', true);
Comment thread test/xhr.test.js

TestRunner.it('xhr.open resets status to 0', function() {
var xhr = new XMLHttpRequest();
xhr.open('GET', 'http://example.com', true);
Comment thread test/xhr.test.js

TestRunner.it('xhr.open resets responseText', function() {
var xhr = new XMLHttpRequest();
xhr.open('GET', 'http://example.com', true);
Comment thread test/xhr.test.js

TestRunner.it('xhr.open resets response', function() {
var xhr = new XMLHttpRequest();
xhr.open('GET', 'http://example.com', true);
Comment thread test/xhr.test.js
});

// Simulate error by calling handleError
xhr.open('GET', 'http://example.com', true);
Comment thread test/xhr.test.js
loadendCalled = true;
});

xhr.open('GET', 'http://example.com', true);
Comment thread test/xhr.test.js
var xhr1 = new XMLHttpRequest();
var xhr2 = new XMLHttpRequest();

xhr1.open('GET', 'http://example1.com', true);
Comment thread test/xhr.test.js
var xhr2 = new XMLHttpRequest();

xhr1.open('GET', 'http://example1.com', true);
xhr2.open('GET', 'http://example2.com', true);
@vjain008 vjain008 closed this Aug 22, 2026
@vjain008
vjain008 deleted the fix/freewheel-xhr-location-compliance branch August 22, 2026 19:46
@github-actions github-actions Bot locked and limited conversation to collaborators Aug 22, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants