From f3fcc1ef51a79783cf0e5e1deb8f65d1790e90e5 Mon Sep 17 00:00:00 2001 From: Ritul Date: Wed, 8 Apr 2026 17:47:01 +0530 Subject: [PATCH] fixing curl normalization --- server/services/curlExecutor.js | 188 +++++++++++++++++++++++++++++--- 1 file changed, 175 insertions(+), 13 deletions(-) diff --git a/server/services/curlExecutor.js b/server/services/curlExecutor.js index 8874051..5a98858 100644 --- a/server/services/curlExecutor.js +++ b/server/services/curlExecutor.js @@ -30,11 +30,81 @@ function createExecutionError(message, extra = {}) { return error; } +function skipShellIndentation(input, index) { + let cursor = index; + + while (cursor < input.length && /[\t \f\v\u00a0]/.test(input[cursor])) { + cursor += 1; + } + + return cursor; +} + function normalizeCommand(command) { - return String(command || '') + const input = String(command || '') .replace(/\r\n/g, '\n') - .replace(/\\\n\s*/g, ' ') - .trim(); + .replace(/\r/g, '\n'); + + let output = ''; + let quote = null; + + for (let index = 0; index < input.length; index += 1) { + const char = input[index]; + + if (quote === '\'') { + output += char; + if (char === '\'') { + quote = null; + } + continue; + } + + if (quote === '"') { + output += char; + + if (char === '\\' && index + 1 < input.length) { + output += input[index + 1]; + index += 1; + continue; + } + + if (char === '"') { + quote = null; + } + continue; + } + + if (char === '\'' || char === '"') { + quote = char; + output += char; + continue; + } + + if (char === '\\') { + const nextChar = input[index + 1]; + if (nextChar === '\n') { + output += ' '; + index = skipShellIndentation(input, index + 2) - 1; + continue; + } + + if (nextChar === 'n') { + output += ' '; + index = skipShellIndentation(input, index + 2) - 1; + continue; + } + + if (nextChar === 'r' && input[index + 2] === 'n') { + output += ' '; + index = skipShellIndentation(input, index + 3) - 1; + continue; + } + } + + output += char; + } + + return output.trim(); } function tokenizeCurlCommand(command) { @@ -164,20 +234,112 @@ function replaceTokensInJsonValue(value, tokenValues = {}) { return value; } +function normalizeJsonFormattingEscapes(value) { + const input = String(value || '') + .replace(/\r\n/g, '\n') + .replace(/\r/g, '\n'); + + let output = ''; + let inString = false; + let escaping = false; + + for (let index = 0; index < input.length; index += 1) { + const char = input[index]; + + if (inString) { + output += char; + + if (escaping) { + escaping = false; + continue; + } + + if (char === '\\') { + escaping = true; + continue; + } + + if (char === '"') { + inString = false; + } + continue; + } + + if (char === '"') { + inString = true; + output += char; + continue; + } + + if (char === '\\') { + const nextChar = input[index + 1]; + + if (nextChar === 'n') { + output += '\n'; + index += 1; + continue; + } + + if (nextChar === 'r' && input[index + 2] === 'n') { + output += '\n'; + index += 2; + continue; + } + + if (nextChar === 'r') { + output += '\n'; + index += 1; + continue; + } + + if (nextChar === 't') { + output += '\t'; + index += 1; + continue; + } + } + + output += char; + } + + return output; +} + +function parseJsonLikeArgument(value) { + const trimmed = String(value || '').trim(); + if ( + !trimmed + || !( + (trimmed.startsWith('{') && trimmed.endsWith('}')) + || (trimmed.startsWith('[') && trimmed.endsWith(']')) + ) + ) { + return null; + } + + try { + return JSON.parse(trimmed); + } catch { + const normalized = normalizeJsonFormattingEscapes(trimmed); + if (normalized === trimmed) { + return null; + } + + try { + return JSON.parse(normalized); + } catch { + return null; + } + } +} + function hydrateDataArgument(rawArgument, tokenValues = {}) { const trimmed = String(rawArgument || '').trim(); if (!trimmed) return ''; - if ( - (trimmed.startsWith('{') && trimmed.endsWith('}')) - || (trimmed.startsWith('[') && trimmed.endsWith(']')) - ) { - try { - const parsed = JSON.parse(trimmed); - return JSON.stringify(replaceTokensInJsonValue(parsed, tokenValues)); - } catch { - return replaceTokensInString(rawArgument, tokenValues); - } + const parsedJson = parseJsonLikeArgument(trimmed); + if (parsedJson !== null) { + return JSON.stringify(replaceTokensInJsonValue(parsedJson, tokenValues)); } return replaceTokensInString(rawArgument, tokenValues);