From c458c5a3e65d198e766012ab990bbe6d39e8cfa7 Mon Sep 17 00:00:00 2001 From: Md Junaed Hossain <169046794+junaed-optimizely@users.noreply.github.com> Date: Mon, 6 Jul 2026 20:14:19 +0600 Subject: [PATCH 1/3] [FSSDK-12865] url parse fix --- .../request_handler.node.ts | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/lib/utils/http_request_handler/request_handler.node.ts b/lib/utils/http_request_handler/request_handler.node.ts index 1c7ef4435..f4abd828f 100644 --- a/lib/utils/http_request_handler/request_handler.node.ts +++ b/lib/utils/http_request_handler/request_handler.node.ts @@ -15,7 +15,6 @@ */ import http from 'http'; import https from 'https'; -import url from 'url'; import { AbortableRequest, Headers, RequestHandler, Response } from './http'; import decompressResponse from 'decompress-response'; import { LoggerFacade } from '../../logging/logger'; @@ -46,7 +45,15 @@ export class NodeRequestHandler implements RequestHandler { * @returns AbortableRequest contains both the response Promise and capability to abort() */ makeRequest(requestUrl: string, headers: Headers, method: string, data?: string): AbortableRequest { - const parsedUrl = url.parse(requestUrl); + let parsedUrl: URL; + try { + parsedUrl = new URL(requestUrl); + } catch { + return { + responsePromise: Promise.reject(new OptimizelyError(UNSUPPORTED_PROTOCOL, requestUrl)), + abort: () => {}, + }; + } if (parsedUrl.protocol !== 'https:' && parsedUrl.protocol !== 'http:') { return { @@ -79,11 +86,11 @@ export class NodeRequestHandler implements RequestHandler { * @private * @returns http.RequestOptions Standard request options dictionary compatible with both http and https */ - private getRequestOptionsFromUrl(url: url.UrlWithStringQuery): http.RequestOptions { + private getRequestOptionsFromUrl(url: URL): http.RequestOptions { return { hostname: url.hostname, - path: url.path, - port: url.port, + path: url.pathname + url.search, + port: url.port || null, protocol: url.protocol, }; } From aa3ca413523aa344a8322fde8c9edd19e5d912c8 Mon Sep 17 00:00:00 2001 From: Md Junaed Hossain <169046794+junaed-optimizely@users.noreply.github.com> Date: Mon, 6 Jul 2026 21:43:11 +0600 Subject: [PATCH 2/3] [FSSDK-12865] error message improv. + test addition --- lib/message/error_message.ts | 1 + lib/utils/http_request_handler/request_handler.node.spec.ts | 6 ++++++ lib/utils/http_request_handler/request_handler.node.ts | 4 ++-- 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/lib/message/error_message.ts b/lib/message/error_message.ts index 83059f93f..20433e153 100644 --- a/lib/message/error_message.ts +++ b/lib/message/error_message.ts @@ -87,6 +87,7 @@ export const OUT_OF_BOUNDS = export const REQUEST_TIMEOUT = 'Request timeout'; export const REQUEST_ERROR = 'Request error'; export const NO_STATUS_CODE_IN_RESPONSE = 'No status code in response'; +export const INVALID_REQUEST_URL = 'Invalid request URL: %s'; export const UNSUPPORTED_PROTOCOL = 'Unsupported protocol: %s'; export const RETRY_CANCELLED = 'Retry cancelled'; export const ONLY_POST_REQUESTS_ARE_SUPPORTED = 'Only POST requests are supported'; diff --git a/lib/utils/http_request_handler/request_handler.node.spec.ts b/lib/utils/http_request_handler/request_handler.node.spec.ts index 8f5b62806..dc9f7c83a 100644 --- a/lib/utils/http_request_handler/request_handler.node.spec.ts +++ b/lib/utils/http_request_handler/request_handler.node.spec.ts @@ -173,6 +173,12 @@ describe('NodeRequestHandler', () => { await expect(request.responsePromise).rejects.toThrow(); }); + it('should return a rejected response promise when the URL is malformed', async () => { + const request = nodeRequestHandler.makeRequest('not a valid url', {}, 'get'); + + await expect(request.responsePromise).rejects.toThrow(); + }); + it('should return a rejected promise when there is a request error', async () => { const scope = nock(host) .get(path) diff --git a/lib/utils/http_request_handler/request_handler.node.ts b/lib/utils/http_request_handler/request_handler.node.ts index f4abd828f..51202ca13 100644 --- a/lib/utils/http_request_handler/request_handler.node.ts +++ b/lib/utils/http_request_handler/request_handler.node.ts @@ -19,7 +19,7 @@ import { AbortableRequest, Headers, RequestHandler, Response } from './http'; import decompressResponse from 'decompress-response'; import { LoggerFacade } from '../../logging/logger'; import { REQUEST_TIMEOUT_MS } from '../enums'; -import { NO_STATUS_CODE_IN_RESPONSE, REQUEST_ERROR, REQUEST_TIMEOUT, UNSUPPORTED_PROTOCOL } from 'error_message'; +import { INVALID_REQUEST_URL, NO_STATUS_CODE_IN_RESPONSE, REQUEST_ERROR, REQUEST_TIMEOUT, UNSUPPORTED_PROTOCOL } from 'error_message'; import { OptimizelyError } from '../../error/optimizly_error'; import { Platform } from '../../platform_support'; /** @@ -50,7 +50,7 @@ export class NodeRequestHandler implements RequestHandler { parsedUrl = new URL(requestUrl); } catch { return { - responsePromise: Promise.reject(new OptimizelyError(UNSUPPORTED_PROTOCOL, requestUrl)), + responsePromise: Promise.reject(new OptimizelyError(INVALID_REQUEST_URL, requestUrl)), abort: () => {}, }; } From 359f6589bdfeab3bb84cf4a6357c0a04a6163a29 Mon Sep 17 00:00:00 2001 From: Md Junaed Hossain <169046794+junaed-optimizely@users.noreply.github.com> Date: Tue, 7 Jul 2026 21:28:43 +0600 Subject: [PATCH 3/3] test update --- .../http_request_handler/request_handler.node.spec.ts | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/lib/utils/http_request_handler/request_handler.node.spec.ts b/lib/utils/http_request_handler/request_handler.node.spec.ts index dc9f7c83a..b982c5ec5 100644 --- a/lib/utils/http_request_handler/request_handler.node.spec.ts +++ b/lib/utils/http_request_handler/request_handler.node.spec.ts @@ -21,6 +21,8 @@ import nock from 'nock'; import zlib from 'zlib'; import { NodeRequestHandler } from './request_handler.node'; import { getMockLogger } from '../../tests/mock/mock_logger'; +import { OptimizelyError } from '../../error/optimizly_error'; +import { INVALID_REQUEST_URL } from 'error_message'; beforeAll(() => { nock.disableNetConnect(); @@ -174,9 +176,13 @@ describe('NodeRequestHandler', () => { }); it('should return a rejected response promise when the URL is malformed', async () => { - const request = nodeRequestHandler.makeRequest('not a valid url', {}, 'get'); + const malformedUrl = 'not a valid url'; + const request = nodeRequestHandler.makeRequest(malformedUrl, {}, 'get'); - await expect(request.responsePromise).rejects.toThrow(); + const error = await request.responsePromise.catch((e) => e); + expect(error).toBeInstanceOf(OptimizelyError); + expect(error.baseMessage).toBe(INVALID_REQUEST_URL); + expect(error.params).toEqual([malformedUrl]); }); it('should return a rejected promise when there is a request error', async () => {