Skip to content

Commit

Permalink
Merge pull request #53 from postmanlabs/feature/fix-cmd-curl
Browse files Browse the repository at this point in the history
Fixes issue where cURL in Windows cmd formats were not imported correctly.
  • Loading branch information
VShingala authored Feb 6, 2023
2 parents 0e2ed21 + 9a0d192 commit b522c6d
Show file tree
Hide file tree
Showing 2 changed files with 113 additions and 5 deletions.
57 changes: 53 additions & 4 deletions src/lib.js
Original file line number Diff line number Diff line change
Expand Up @@ -118,13 +118,13 @@ var program,
curlObj.dataBinary || curlObj.dataUrlencode.length > 0) &&
curlObj.head && !curlObj.get) {
throw new Error('Error while parsing cURL: Both (--head/-I) and' +
'(-d/--data/--data-raw/--data-binary/--data-ascii/--data-urlencode) are not supported');
' (-d/--data/--data-raw/--data-binary/--data-ascii/--data-urlencode) are not supported');
}

// must have a URL
if (curlObj.args.length > 1 && !curlObj.url) {
throw new Error('Only the URL can be provided without an option preceding it.' +
'All other inputs must be specified via options.');
' All other inputs must be specified via options.');
}
},

Expand Down Expand Up @@ -401,6 +401,28 @@ var program,
}
},

/**
* Transforms corresponding cURL in Windows CMD format to Bash compatible version,
* via unescaping escaped characters for Windows CMD.
*
* @param {String} curlString - curL string to be transformed into respectivve bash version
* @returns {String} - Transformed cURL in Bash format
*/
transformCmdToBash: function (curlString) {
/**
* three kinds of matching groups can be captured with following regexp.
* 1. Certain characters that can be escaped by ^ (caret). Namely ^,{,},[,],<,>,\,",|,&,\n(new line)
* These will be replaced with character itself resulting in removal of escape char (^)
* 2. ^%^ specifically will be replaced with % due to special escape rule
* 3. "" will be replaced with "
* (single quotations are escaped with double quotes when inside string that's wrapped in double quotes)
*
* Ref: https://ss64.com/nt/syntax-esc.html
* See detail regexp composition over here: https://regex101.com/r/Xbiqbq/1
*/
return curlString.replace(new RegExp(/\^(\^|{|}|\[|\]|<|>|\\|"|\||&|\n)|\^(%)\^|"(")/, 'g'), '$1$2$3');
},

/**
* Parses raw data and generates object from it by understanding content present in it
*
Expand Down Expand Up @@ -470,7 +492,26 @@ var program,
return parsedFormData;
},

convertCurlToRequest: function(curlString) {
/**
* Converts cURL string that's in windows cmd compatible format into collection request
*
* @param {String} curlString - Windows cmd compatible cURL string
* @returns {Object} Collection request JSON
*/
convertForCMDFormat: function (curlString) {
try {
const bashCurlString = this.transformCmdToBash(curlString),
request = this.convertCurlToRequest(bashCurlString, false);

request.description = 'Generated from a curl request: \n' + curlString.split('"').join('\\\"');
return request;
}
catch (error) {
throw e;
}
},

convertCurlToRequest: function(curlString, shouldRetry = true) {
try {
this.initialize();
this.requestUrl = '';
Expand Down Expand Up @@ -625,8 +666,16 @@ var program,
return request;
}
catch (e) {
if (shouldRetry) {
try {
// Retry conversion again by considering cURL to be in windows cmd compatible format
return this.convertForCMDFormat(curlString);
}
catch (error) {
// Retry error is not reported
}
}
if (e.message === 'process.exit is not a function') {
// happened because of
e.message = 'Invalid format for cURL.';
}
return { error: e };
Expand Down
61 changes: 60 additions & 1 deletion test/conversion.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,7 @@ describe('Curl converter should', function() {
}, function (err, result) {
expect(result.result).to.equal(false);
expect(result.reason).to.equal('Error while parsing cURL: Both (--head/-I) and' +
'(-d/--data/--data-raw/--data-binary/--data-ascii/--data-urlencode) are not supported');
' (-d/--data/--data-raw/--data-binary/--data-ascii/--data-urlencode) are not supported');
done();
});
});
Expand Down Expand Up @@ -885,6 +885,7 @@ describe('Curl converter should', function() {
});
});
});

it('in case where there is a invalid character at the end it should throw an error', function(done) {
convert({
type: 'string',
Expand All @@ -900,4 +901,62 @@ describe('Curl converter should', function() {
done();
});
});

describe('[Github #5182]: It should correctly import cURL commands compatible with Windows cmd', function() {

it('containing double quotes escaped with ^ (caret)', function(done) {
convert({
type: 'string',
data: 'curl "https://trello.com/1/cards" --data-binary ' +
'"^{^\\^"name^\\^":^\\^"hello world^\\^",^\\^"pos^\\^":65535,^\\^"closed^\\^":false,' +
'^\\^"idLabels^\\^":^[^],^\\^"idMembers^\\^":^[^],^\\^"dateLastActivity^\\^":1536871503239,' +
'^\\^"idBoard^\\^":^\\^"5a84a94fc77d9f99cf9ecd8a^\\^",^\\^"idList^\\^":^\\^"a^\\^",' +
'^\\^"token^\\^":^\\^"a/L8nmd9rC5gyBYaBx6RVXGjHuMIRfMQS4b3p3zIhKWin8ejxTzJ5E5ERACxT2IILp^\\^"^}" --compressed'
}, function (err, result) {
expect(result.result).to.equal(true);
expect(result.output.length).to.equal(1);
expect(result.output[0].type).to.equal('request');
expect(result.output[0].data.url).to.equal('https://trello.com/1/cards');
done();
});
});

it('containing double quotes escaped with " (double quotes)', function(done) {
convert({
type: 'string',
data: `curl "https://www.youtube.com/youtubei/v1/guide?key=321456467855697&prettyPrint=false" ^
-H "authority: www.youtube.com" ^
-H "sec-ch-ua: ^\\^"Not_A Brand^\\^";v=^\\^"99^\\^", ^\\^"Chromium^\\^";v=^\\^"109^\\^"" ^
-H "sec-ch-ua-arch: ^\\^"arm^\\^"" ^
-H "user-agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) (KHTML, like Gecko) Chrome/109.0.0.0" ^
-H "content-type: application/json" ^
--data-raw "^{^\\^"context^\\^":^{^\\^"client^\\^":^{^\\^"hl^\\^":^\\^"en^\\^"^}^},^\\^"state^\\^":true^}" ^
--compressed
`
}, function (err, result) {
expect(result.result).to.equal(true);
expect(result.output.length).to.equal(1);
expect(result.output[0].type).to.equal('request');
const headerArr = result.output[0].data.header;
expect(headerArr[0].key).to.equal('authority');
expect(headerArr[0].value).to.equal('www.youtube.com');
expect(headerArr[1].key).to.equal('sec-ch-ua');
expect(headerArr[1].value).to.equal(
'\"Not_A Brand\";v=\"99\", \"Chromium\";v=\"109\"');
expect(headerArr[2].key).to.equal('sec-ch-ua-arch');
expect(headerArr[2].value).to.equal('\"arm\"');
expect(headerArr[3].key).to.equal('user-agent');
expect(headerArr[3].value).to.equal(
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) (KHTML, like Gecko) Chrome/109.0.0.0');
expect(headerArr[4].key).to.equal('content-type');
expect(headerArr[4].value).to.equal('application/json');
expect(result.output[0].data.url).to.equal(
'https://www.youtube.com/youtubei/v1/guide?key=321456467855697&prettyPrint=false');
expect(result.output[0].data.body.mode).to.equal('raw');
expect(result.output[0].data.body.raw).to.equal(
'{\"context\":{\"client\":{\"hl\":\"en\"}},\"state\":true}');
done();
});
});
});
});

0 comments on commit b522c6d

Please sign in to comment.