Skip to content

Do not add -X option in curl if -L is present and method is POST. #585

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 10 commits into from
10 changes: 7 additions & 3 deletions codegens/curl/lib/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ var sanitize = require('./util').sanitize,
getUrlStringfromUrlObject = require('./util').getUrlStringfromUrlObject,
addFormParam = require('./util').addFormParam,
form = require('./util').form,
shouldAddXOption = require('./util').shouldAddXOption,
_ = require('./lodash'),
self;

Expand Down Expand Up @@ -45,12 +46,15 @@ self = module.exports = {
indent = ' ';
}
if (request.method === 'HEAD') {
snippet += ` ${form('-I', format)} ${quoteType + url + quoteType}`;
snippet += ` ${form('-I', format)}`;
}
else {
snippet += ` ${form('-X', format)} ${request.method} ${quoteType + url + quoteType}`;

if (shouldAddXOption(request, options)) {
snippet += ` ${form('-X', format)} ${request.method}`;
}

snippet += ` ${quoteType + url + quoteType}`;

if (request.body && !request.headers.has('Content-Type')) {
if (request.body.mode === 'file') {
request.addHeader({
Expand Down
78 changes: 78 additions & 0 deletions codegens/curl/lib/util.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
const _ = require('./lodash');
var self = module.exports = {
/**
* sanitizes input string by handling escape characters eg: converts '''' to '\'\'', (" to \" and \ to \\ )
Expand Down Expand Up @@ -199,5 +200,82 @@ var self = module.exports = {
contentType: contentType
});
}
},

/**
* @param {Object} body
* @returns {boolean}
*
* Determines if a request body is actually empty.
* This is needed because body.isEmpty() returns true for formdata
* and urlencoded when they contain only disabled params which will not
* be a part of the curl request.
*/
isBodyEmpty (body) {
if (!body) {
return true;
}

if (body.isEmpty()) {
return true;
}

if (body.mode === 'formdata' || body.mode === 'urlencoded') {
let memberCount = 0;
body[body.mode].members && body[body.mode].members.forEach((param) => {
if (!param.disabled) {
memberCount += 1;
}
});

return memberCount === 0;
}

return false;
},

/**
* Decide whether we should add the -X option in the snippet or not
* See: https://postmanlabs.atlassian.net/wiki/spaces/AD/pages/3540288287
*
* @param {Object} request
* @param {Object} options
*
* @returns {Boolean}
*/
shouldAddXOption: function (request, options) {
let followOriginalHttpMethod = _.get(request, 'protocolProfileBehavior.followOriginalHttpMethod', false),
disableBodyPruning = _.get(request, 'protocolProfileBehavior.disableBodyPruning', true);

if (!options.followRedirect || followOriginalHttpMethod) {
return true;
}

switch (request.method) {
case 'HEAD':
return false;
case 'GET':
// disableBodyPruning will generally not be present in the request
// the only time it will be present, its value will be _false_
// i.e. the user wants to prune the request body despite it being present
if (!self.isBodyEmpty(request.body) && (disableBodyPruning !== false)) {
return true;
}

return false;

case 'POST':
if (self.isBodyEmpty(request.body)) {
return true;
}

return false;

case 'DELETE':
case 'PUT':
case 'PATCH':
default:
return true;
}
}
};
131 changes: 130 additions & 1 deletion codegens/curl/test/unit/convert.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -277,7 +277,7 @@ describe('curl convert function', function () {
expect.fail(null, null, error);
}
expect(snippet).to.be.a('string');
expect(snippet).to.include("GET 'https://google.com'"); // eslint-disable-line quotes
expect(snippet).to.include("'https://google.com'"); // eslint-disable-line quotes
});
});

Expand Down Expand Up @@ -635,5 +635,134 @@ describe('curl convert function', function () {
expect(outputUrlString).to.equal(rawUrl);
});
});

it('should not add --request parameter in POST request if body is present', function () {
var request = new sdk.Request({
'method': 'POST',
'header': [],
'body': {
'mode': 'graphql',
'graphql': {
'query': '{\n findScenes(\n filter: {per_page: 0}\n scene_filter: {is_missing: "performers"}){\n count\n scenes {\n id\n title\n path\n }\n }\n}', // eslint-disable-line
'variables': '{\n\t"variable_key": "variable_value"\n}'
}
},
'url': {
'raw': 'https://postman-echo.com/post',
'protocol': 'https',
'host': [
'postman-echo',
'com'
],
'path': [
'post'
]
}
});

convert(request, { followRedirect: true }, function (error, snippet) {
if (error) {
expect.fail(null, null, error);
}
expect(snippet).to.be.a('string');
expect(snippet).to.not.include('--request POST');
});
});

it('should add --request parameter in POST request if body is not present', function () {
var request = new sdk.Request({
'method': 'POST',
'header': [],
'url': {
'raw': 'https://postman-echo.com/post',
'protocol': 'https',
'host': [
'postman-echo',
'com'
],
'path': [
'post'
]
}
});

convert(request, { followRedirect: true }, function (error, snippet) {
if (error) {
expect.fail(null, null, error);
}
expect(snippet).to.be.a('string');
expect(snippet).to.include('--request POST');
});
});

it('should add --request parameter in GET request if body is present', function () {
var request = new sdk.Request({
'method': 'GET',
'header': [],
'body': {
'mode': 'graphql',
'graphql': {
'query': '{\n findScenes(\n filter: {per_page: 0}\n scene_filter: {is_missing: "performers"}){\n count\n scenes {\n id\n title\n path\n }\n }\n}', // eslint-disable-line
'variables': '{\n\t"variable_key": "variable_value"\n}'
}
},
'url': {
'raw': 'https://postman-echo.com/get',
'protocol': 'https',
'host': [
'postman-echo',
'com'
],
'path': [
'get'
]
}
});

convert(request, { followRedirect: true, disableBodyPruning: true }, function (error, snippet) {
if (error) {
expect.fail(null, null, error);
}
expect(snippet).to.be.a('string');
expect(snippet).to.include('--request GET');
});
});

it('should always add --request parameter followRedirect option is false', function () {
var methods = ['GET', 'HEAD', 'DELETE', 'PUT', 'POST', 'PATCH'],
request = new sdk.Request({
'method': 'POST',
'header': [],
'body': {
'mode': 'graphql',
'graphql': {
'query': '{\n findScenes(\n filter: {per_page: 0}\n scene_filter: {is_missing: "performers"}){\n count\n scenes {\n id\n title\n path\n }\n }\n}', // eslint-disable-line
'variables': '{\n\t"variable_key": "variable_value"\n}'
}
},
'url': {
'raw': 'https://postman-echo.com/post',
'protocol': 'https',
'host': [
'postman-echo',
'com'
],
'path': [
'post'
]
}
});

for (let method of methods) {
request.method = method;
convert(request, { followRedirect: false }, function (error, snippet) {
if (error) {
expect.fail(null, null, error);
}
expect(snippet).to.be.a('string');
expect(snippet).to.include(`--request ${method}`);
});
}
});
});
});
2 changes: 1 addition & 1 deletion npm/ci-requirements.sh
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ pushd ./codegens/csharp-restsharp &>/dev/null;
sudo apt-get install dotnet-sdk-2.2
dotnet new console -o testProject
pushd ./testProject &>/dev/null;
dotnet add package RestSharp
dotnet add package RestSharp --version 106.15.0
popd &>/dev/null;
popd &>/dev/null;

Expand Down