From fdff6e551d5502c97c8c6089a4a8958cddec5c0b Mon Sep 17 00:00:00 2001 From: "Jain, Vinod Kumar" Date: Wed, 29 Jul 2026 09:09:17 -0500 Subject: [PATCH 1/5] RDKEMW-22637 : [VIPA][NativeScript][Rogers] FW request is getting truncated in device logs Reason for change: Logs are truncating Test Procedure: Full log line must display Risk: low Priority: P1 --- src/jsc/JavaScriptUtils.cpp | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/src/jsc/JavaScriptUtils.cpp b/src/jsc/JavaScriptUtils.cpp index 7fe4aef..b98e77b 100644 --- a/src/jsc/JavaScriptUtils.cpp +++ b/src/jsc/JavaScriptUtils.cpp @@ -880,7 +880,24 @@ static JSValueRef consoleCallbackImpl(JSContextRef ctx, size_t argumentCount, InspectorHTTPServer::singleton().sendConsoleMessage(ctx, level, oss.str().c_str()); #endif - NativeJSLogger::log(INFO, "%s", oss.str().c_str()); + const std::string fullMsg = oss.str(); + constexpr size_t kMaxLogChunk = 420; + + if (fullMsg.size() <= kMaxLogChunk) { + NativeJSLogger::log(INFO, "%s", fullMsg.c_str()); + } else { + size_t offset = 0; + while (offset < fullMsg.size()) { + const size_t len = std::min(kMaxLogChunk, fullMsg.size() - offset); + const bool hasMore = (offset + len) < fullMsg.size(); + std::string chunk = fullMsg.substr(offset, len); + if (hasMore) { + chunk += " \u21b5"; // ↵ continuation marker + } + NativeJSLogger::log(INFO, "%s", chunk.c_str()); + offset += len; + } + } return JSValueMakeUndefined(ctx); } From 2cec2d125509bed57a781702e60b6263ecfc7f79 Mon Sep 17 00:00:00 2001 From: gurpreet319 Date: Thu, 30 Jul 2026 11:48:17 +0000 Subject: [PATCH 2/5] RDKEMW-22317 : Integrate VIPA widget 1.4.4.5 with nativescript Reason for change: Integrate VIPA 1.4.4.5 with nativescript, updated the xhr and URLSearchParams. Test Procedure: build should be successful Risk: low Priority: P2 --- src/jsc/modules/lib/URLSearchParams.js | 92 ++++++++++- utils/xhr.js | 206 ++++++++++++------------- 2 files changed, 189 insertions(+), 109 deletions(-) diff --git a/src/jsc/modules/lib/URLSearchParams.js b/src/jsc/modules/lib/URLSearchParams.js index d724f26..75aec3e 100644 --- a/src/jsc/modules/lib/URLSearchParams.js +++ b/src/jsc/modules/lib/URLSearchParams.js @@ -3,8 +3,21 @@ const urlencoded = require("./urlencoded"); exports.implementation = class URLSearchParamsImpl { constructor(globalObject, constructorArgs = [""], options = {}) { - const { doNotStripQMark = false } = options || {}; - let init = constructorArgs[0]; + let doNotStripQMark = false; + let init = ""; + + if (arguments.length === 1) { + init = globalObject; + } else { + const resolvedOptions = options || {}; + doNotStripQMark = !!resolvedOptions.doNotStripQMark; + if (Array.isArray(constructorArgs)) { + init = constructorArgs[0]; + } else { + init = constructorArgs; + } + } + this._list = []; this._url = null; @@ -20,10 +33,26 @@ exports.implementation = class URLSearchParamsImpl { } this._list.push([pair[0], pair[1]]); } - } else if (typeof init === "object" && Object.getPrototypeOf(init) === null) { - for (const name of Object.keys(init)) { - const value = init[name]; - this._list.push([name, value]); + } else if (typeof init === "object" && init !== null && !Array.isArray(init)) { + // Handle URLSearchParams-like objects that expose an internal _list. + if (Array.isArray(init._list)) { + for (const pair of init._list) { + if (Array.isArray(pair) && pair.length >= 2) { + this._list.push([pair[0], pair[1]]); + } + } + } else if (typeof init.entries === "function") { + // Handle iterable URLSearchParams-compatible objects. + for (const pair of init.entries()) { + if (Array.isArray(pair) && pair.length >= 2) { + this._list.push([pair[0], pair[1]]); + } + } + } else { + for (const name of Object.keys(init)) { + const value = init[name]; + this._list.push([name, value]); + } } } else { this._list = urlencoded.parseUrlencodedString(init); @@ -42,6 +71,7 @@ exports.implementation = class URLSearchParamsImpl { if (serializedQuery === null) { this._url._potentiallyStripTrailingSpacesFromAnOpaquePath(); } + } } @@ -126,6 +156,56 @@ exports.implementation = class URLSearchParamsImpl { this._updateSteps(); } + forEach(callback, thisArg) { + if (typeof callback !== "function") { + throw new TypeError("Failed to execute 'forEach' on 'URLSearchParams': parameter 1 is not a function."); + } + + for (const tuple of this._list) { + callback.call(thisArg, tuple[1], tuple[0], this); + } + } + + entries() { + return this._list[Symbol.iterator](); + } + + keys() { + const list = this._list; + let index = 0; + return { + next() { + if (index >= list.length) { + return { value: undefined, done: true }; + } + const value = list[index][0]; + index++; + return { value: value, done: false }; + }, + [Symbol.iterator]() { + return this; + } + }; + } + + values() { + const list = this._list; + let index = 0; + return { + next() { + if (index >= list.length) { + return { value: undefined, done: true }; + } + const value = list[index][1]; + index++; + return { value: value, done: false }; + }, + [Symbol.iterator]() { + return this; + } + }; + } + [Symbol.iterator]() { return this._list[Symbol.iterator](); } diff --git a/utils/xhr.js b/utils/xhr.js index 47b7f91..aff145d 100644 --- a/utils/xhr.js +++ b/utils/xhr.js @@ -5,10 +5,9 @@ * allow the use of existing libraries. * * Usage: include("XMLHttpRequest.js") and use XMLHttpRequest per W3C specs. + * Original code by DeFelippi. + * Some modifications by Comcast. * - * @author Dan DeFelippi - * @contributor David Ellis - * @license MIT */ @@ -29,9 +28,6 @@ XMLHttpRequest = function() { // Not part of XHR specs. var disableHeaderCheck = false; - // Set some default headers - var defaultHeaders = {}; - var defaultHeaders = { "User-Agent": "Mozilla/5.0 (Linux; x86_64 GNU/Linux) AppleWebKit/601.1 (KHTML, like Gecko) Version/8.0 Safari/601.1 WPE", "Accept": "*/*", @@ -148,8 +144,22 @@ XMLHttpRequest = function() { * @param string password Password for basic authentication (optional) */ this.open = function(method, url, async, user, password) { - this.abort(); + // Reset internal request state without dispatching an abort event. + // RxJS treats abort as a hard request failure if emitted during open(). + if (request) { + request.abort(); + request = null; + } + response = null; + headers = {}; + headersCase = {}; + sendFlag = false; errorFlag = false; + this.status = 0; + this.statusText = null; + this.responseText = ""; + this.responseXML = ""; + this.readyState = this.UNSENT; // Check for valid request method if (!isAllowedHttpMethod(method)) { @@ -267,73 +277,35 @@ XMLHttpRequest = function() { throw new Error("INVALID_STATE_ERR: send has already been called"); } - //JSRUNTIME PREVENT URL LIBRARY USE + var urlToUse = settings.url; + + // Parse URL using the URL API available in this JSRuntime var ssl = false; - /* - var local = false; - var url = new Url(settings.url); var host; - // Determine the server - switch (url.protocol) { - case "https:": - ssl = true; - // SSL & non-SSL both need host, no break here. - case "http:": - host = url.protocol + "//" + url.hostname; - break; - - case "file:": - local = true; - break; - - case undefined: - case null: - case "": - host = "localhost"; - break; - - default: - throw new Error("Protocol not supported."); - } - if (local) { - // JSC TODO implement local file access - if (settings.method !== "GET") { - throw new Error("XMLHttpRequest: Only GET method is supported"); - } - - if (settings.async) { - fs.readFile(url.pathname, "utf8", function(error, data) { - if (error) { - self.handleError(error); - } else { - self.status = 200; - self.responseText = data; - setState(self.DONE); - } - }); - } else { - try { - this.responseText = fs.readFileSync(url.pathname, "utf8"); - this.status = 200; - setState(self.DONE); - } catch(e) { - this.handleError(e); - } + var port; + var uri; + + try { + var parsedUrl = new URL(urlToUse); + switch (parsedUrl.protocol) { + case "https:": + ssl = true; + host = parsedUrl.hostname; + port = parseInt(parsedUrl.port, 10) || 443; + break; + case "http:": + ssl = false; + host = parsedUrl.hostname; + port = parseInt(parsedUrl.port, 10) || 80; + break; + default: + throw new Error("Protocol not supported: " + parsedUrl.protocol); } - console.log("local file access not yet implemented "); + uri = parsedUrl.pathname + (parsedUrl.search || ""); + } catch (urlParseErr) { + self.handleError(new Error("XMLHttpRequest: Failed to parse URL '" + urlToUse + "': " + urlParseErr.message)); return; } - // Default to port 80. If accessing localhost on another port be sure - // to use http://localhost:port/path - var port = url.port || (ssl ? 443 : 80); - // Add query string if one is used - var index = settings.url.indexOf("/", 9); - var search = settings.url.substr(index); - //var uri = url.pathname + (url.search ? url.search : ""); - //var uri = settings.url; - var uri = search; -*/ - var uri = settings.url; // Set the defaults if they haven't been set for (var name in defaultHeaders) { if (!headersCase[name.toLowerCase()]) { @@ -349,7 +321,7 @@ XMLHttpRequest = function() { if (typeof settings.password === "undefined") { settings.password = ""; } - var authBuf = new Buffer(settings.user + ":" + settings.password); + var authBuf = Buffer.from(settings.user + ":" + settings.password); headers.Authorization = "Basic " + authBuf.toString("base64"); } @@ -369,9 +341,12 @@ XMLHttpRequest = function() { } var options = { - /*host: host, - port: port,*/ + hostname: host, + host: host, + port: port, path: uri, + protocol: ssl ? "https:" : "http:", + ssl: ssl, method: settings.method, headers: headers, agent: false, @@ -384,7 +359,12 @@ XMLHttpRequest = function() { // Handle async requests if (settings.async) { // Use the proper protocol - var doRequest = ssl ? https.request : http.request; + var transport = ssl ? https : http; + if (!transport || typeof transport.request !== "function") { + self.handleError(new Error("XMLHttpRequest: transport.request is unavailable for protocol " + (ssl ? "https" : "http"))); + return; + } + var doRequest = transport.request; // Request is being sent, set send flag sendFlag = true; @@ -400,32 +380,32 @@ XMLHttpRequest = function() { // Check for redirect // @TODO Prevent looped redirects if (response.statusCode === 301 || response.statusCode === 302 || response.statusCode === 303 || response.statusCode === 307) { - // Change URL to the redirect location - settings.url = response.headers.location; - //var url = Url.parse(settings.url); - var url = settings.url; - /* - // Set host var in case it's used later - host = url.hostname; - // Options for the new request - var newOptions = { - hostname: url.hostname, - port: url.port, - path: url.path, - method: response.statusCode === 303 ? "GET" : settings.method, - headers: headers, - withCredentials: self.withCredentials - }; - */ - var newOptions = { - path: url, - method: response.statusCode === 303 ? "GET" : settings.method, - headers: headers, - withCredentials: self.withCredentials - }; - // Issue the new request - request = doRequest(newOptions, responseHandler).on("error", errorHandler); - request.end(); + try { + var redirectLocation = response.headers.location; + var redirectUrl = new URL(redirectLocation, settings.url); + settings.url = redirectUrl.toString(); + var redirectSsl = redirectUrl.protocol === "https:"; + var redirectPort = parseInt(redirectUrl.port, 10) || (redirectSsl ? 443 : 80); + var redirectOptions = { + hostname: redirectUrl.hostname, + host: redirectUrl.hostname, + port: redirectPort, + path: redirectUrl.pathname + (redirectUrl.search || ""), + protocol: redirectSsl ? "https:" : "http:", + ssl: redirectSsl, + method: response.statusCode === 303 ? "GET" : settings.method, + headers: headers, + withCredentials: self.withCredentials + }; + var redirectTransport = redirectSsl ? https : http; + if (!redirectTransport || typeof redirectTransport.request !== "function") { + throw new Error("Redirect transport.request is unavailable for protocol " + (redirectSsl ? "https" : "http")); + } + request = redirectTransport.request(redirectOptions, responseHandler).on("error", errorHandler); + request.end(); + } catch (redirectErr) { + self.handleError(redirectErr); + } // @TODO Check if an XHR event needs to be fired here return; } @@ -465,8 +445,18 @@ XMLHttpRequest = function() { }; // Create the request - request = doRequest(options, responseHandler); + try { + request = doRequest(options, responseHandler); + } catch (requestCreateErr) { + self.handleError(requestCreateErr); + return; + } request.on("error", errorHandler); + if (typeof request.on === "function") { + request.on("abort", function() { + self.handleError(new Error("XMLHttpRequest: request aborted by transport")); + }); + } // Node 0.4 and later won't accept empty data. Make sure it's needed. if (data) { @@ -499,6 +489,8 @@ XMLHttpRequest = function() { * Aborts a request. */ this.abort = function() { + var hadActiveRequest = !!request || sendFlag || (this.readyState !== this.UNSENT && this.readyState !== this.DONE); + if (request) { request.abort(); request = null; @@ -518,7 +510,9 @@ XMLHttpRequest = function() { setState(this.DONE); } this.readyState = this.UNSENT; - this.dispatchEvent('abort'); + if (hadActiveRequest) { + this.dispatchEvent('abort'); + } }; /** @@ -549,12 +543,18 @@ XMLHttpRequest = function() { * Dispatch any events, including both "on" methods and events attached using addEventListener. */ this.dispatchEvent = function(event) { + var evt = { + type: event, + target: self, + currentTarget: self + }; + if (typeof self["on" + event] === "function") { - self["on" + event](); + self["on" + event](evt); } if (event in listeners) { for (var i = 0, len = listeners[event].length; i < len; i++) { - listeners[event][i].call(self); + listeners[event][i].call(self, evt); } } }; From 6ec28366bc681c34b5868d5354920dc8afaaa2c3 Mon Sep 17 00:00:00 2001 From: Vinod Jain <98183059+vjain008@users.noreply.github.com> Date: Sun, 9 Aug 2026 02:07:48 -0500 Subject: [PATCH 3/5] Update xhr.js with contributor and license details Added contributor and license information. --- utils/xhr.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/utils/xhr.js b/utils/xhr.js index aff145d..da77db8 100644 --- a/utils/xhr.js +++ b/utils/xhr.js @@ -5,8 +5,9 @@ * allow the use of existing libraries. * * Usage: include("XMLHttpRequest.js") and use XMLHttpRequest per W3C specs. - * Original code by DeFelippi. * Some modifications by Comcast. + * @contributor David Ellis + * @license MIT * */ From ac789be2957fdf2218397dc39c193d479eab5610 Mon Sep 17 00:00:00 2001 From: Vinod Jain <98183059+vjain008@users.noreply.github.com> Date: Sun, 9 Aug 2026 12:04:16 -0500 Subject: [PATCH 4/5] Update author and contributor information in xhr.js --- utils/xhr.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/utils/xhr.js b/utils/xhr.js index da77db8..a5e1d77 100644 --- a/utils/xhr.js +++ b/utils/xhr.js @@ -5,9 +5,10 @@ * allow the use of existing libraries. * * Usage: include("XMLHttpRequest.js") and use XMLHttpRequest per W3C specs. - * Some modifications by Comcast. + * @author Dan DeFelippi * @contributor David Ellis * @license MIT + * Some modifications by Comcast. * */ From 88c46b7635cf3d9a05903cf4b29293aa5f6fd2bc Mon Sep 17 00:00:00 2001 From: Vinod Kumar Jain Date: Mon, 10 Aug 2026 07:41:06 -0500 Subject: [PATCH 5/5] 2.0.8 release changelog updates --- CHANGELOG.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2074a9e..75168a7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,12 @@ All notable changes to this project will be documented in this file. Dates are d Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog). +#### [2.0.8](https://github-personal/rdkcentral/rdkNativeScript/compare/2.0.6...2.0.8) + +- RDKEMW-22317 : Integrate VIPA widget 1.4.4.5 with nativescript [`#138`](https://github-personal/rdkcentral/rdkNativeScript/pull/138) +- RDKEMW-22637 : [VIPA][NativeScript][Rogers] FW request is getting tru… [`#137`](https://github-personal/rdkcentral/rdkNativeScript/pull/137) +- RDKEMW-22637 : [VIPA][NativeScript][Rogers] FW request is getting truncated in device logs [`fdff6e5`](https://github-personal/rdkcentral/rdkNativeScript/commit/fdff6e551d5502c97c8c6089a4a8958cddec5c0b) + #### [2.0.6](https://github-personal/rdkcentral/rdkNativeScript/compare/2.0.4...2.0.6) - RDKEMW-18491 : [rdknativescript] add debugger support similar to webkit [`#134`](https://github-personal/rdkcentral/rdkNativeScript/pull/134)