import * as cookie from "cookie"; import * as URL from "url"; import * as querystring from "querystring"; /** * given this: [ 'msg1=value1', 'msg2=value2' ] * output this: 'msg1=value1&msg2=value2' * @param dataArguments */ const joinDataArguments = dataArguments => { let data = ""; dataArguments.forEach((argument, i) => { if (i === 0) { data += argument; } else { data += `&${argument}`; } }); return data; }; const parseCurlCommand = curlCommand => { let newlineFound = /\r|\n/.exec(curlCommand); if (newlineFound) { // remove newlines curlCommand = curlCommand.replace(/\r|\n/g, ""); } // yargs parses -XPOST as separate arguments. just prescreen for it. curlCommand = curlCommand.replace(/ -XPOST/, " -X POST"); curlCommand = curlCommand.replace(/ -XGET/, " -X GET"); curlCommand = curlCommand.replace(/ -XPUT/, " -X PUT"); curlCommand = curlCommand.replace(/ -XPATCH/, " -X PATCH"); curlCommand = curlCommand.replace(/ -XDELETE/, " -X DELETE"); curlCommand = curlCommand.trim(); let parsedArguments = require("yargs-parser")(curlCommand); let cookieString; let cookies; let url = parsedArguments._[1]; if (!url) { for (let argName in parsedArguments) { if (typeof parsedArguments[argName] === "string") { if (["http", "www."].includes(parsedArguments[argName])) { url = parsedArguments[argName]; } } } } let headers; const parseHeaders = headerFieldName => { if (parsedArguments[headerFieldName]) { if (!headers) { headers = {}; } if (!Array.isArray(parsedArguments[headerFieldName])) { parsedArguments[headerFieldName] = [parsedArguments[headerFieldName]]; } parsedArguments[headerFieldName].forEach(header => { if (header.includes("Cookie")) { // stupid javascript tricks: closure cookieString = header; } else { let colonIndex = header.indexOf(":"); let headerName = header.substring(0, colonIndex); let headerValue = header.substring(colonIndex + 1).trim(); headers[headerName] = headerValue; } }); } }; parseHeaders("H"); parseHeaders("header"); if (parsedArguments.A) { if (!headers) { headers = []; } headers["User-Agent"] = parsedArguments.A; } else if (parsedArguments["user-agent"]) { if (!headers) { headers = []; } headers["User-Agent"] = parsedArguments["user-agent"]; } if (parsedArguments.b) { cookieString = parsedArguments.b; } if (parsedArguments.cookie) { cookieString = parsedArguments.cookie; } let multipartUploads; if (parsedArguments.F) { multipartUploads = {}; if (!Array.isArray(parsedArguments.F)) { parsedArguments.F = [parsedArguments.F]; } parsedArguments.F.forEach(multipartArgument => { // input looks like key=value. value could be json or a file path prepended with an @ const [key, value] = multipartArgument.split("=", 2); multipartUploads[key] = value; }); } if (cookieString) { const cookieParseOptions = { decode: s => s }; // separate out cookie headers into separate data structure // note: cookie is case insensitive cookies = cookie.parse( cookieString.replace(/^Cookie: /gi, ""), cookieParseOptions ); } let method; if (parsedArguments.X === "POST") { method = "post"; } else if (parsedArguments.X === "PUT" || parsedArguments["T"]) { method = "put"; } else if (parsedArguments.X === "PATCH") { method = "patch"; } else if (parsedArguments.X === "DELETE") { method = "delete"; } else if (parsedArguments.X === "OPTIONS") { method = "options"; } else if ( (parsedArguments["d"] || parsedArguments["data"] || parsedArguments["data-ascii"] || parsedArguments["data-binary"] || parsedArguments["F"] || parsedArguments["form"]) && !(parsedArguments["G"] || parsedArguments["get"]) ) { method = "post"; } else if (parsedArguments["I"] || parsedArguments["head"]) { method = "head"; } else { method = "get"; } let compressed = !!parsedArguments.compressed; let urlObject = URL.parse(url); // eslint-disable-line // if GET request with data, convert data to query string // NB: the -G flag does not change the http verb. It just moves the data into the url. if (parsedArguments["G"] || parsedArguments["get"]) { urlObject.query = urlObject.query ? urlObject.query : ""; let option = "d" in parsedArguments ? "d" : "data" in parsedArguments ? "data" : null; if (option) { let urlQueryString = ""; if (!url.includes("?")) { url += "?"; } else { urlQueryString += "&"; } if (typeof parsedArguments[option] === "object") { urlQueryString += parsedArguments[option].join("&"); } else { urlQueryString += parsedArguments[option]; } urlObject.query += urlQueryString; url += urlQueryString; delete parsedArguments[option]; } } let query = querystring.parse(urlObject.query, null, null, { maxKeys: 10000 }); urlObject.search = null; // Clean out the search/query portion. const request = { url, urlWithoutQuery: URL.format(urlObject) }; if (compressed) { request["compressed"] = true; } if (Object.keys(query).length > 0) { request.query = query; } if (headers) { request.headers = headers; } request["method"] = method; if (cookies) { request.cookies = cookies; request.cookieString = cookieString.replace("Cookie: ", ""); } if (multipartUploads) { request.multipartUploads = multipartUploads; } if (parsedArguments.data) { request.data = parsedArguments.data; } else if (parsedArguments["data-binary"]) { request.data = parsedArguments["data-binary"]; request.isDataBinary = true; } else if (parsedArguments["d"]) { request.data = parsedArguments["d"]; } else if (parsedArguments["data-ascii"]) { request.data = parsedArguments["data-ascii"]; } if (parsedArguments["u"]) { request.auth = parsedArguments["u"]; } if (parsedArguments["user"]) { request.auth = parsedArguments["user"]; } if (Array.isArray(request.data)) { request.dataArray = request.data; request.data = joinDataArguments(request.data); } if (parsedArguments["k"] || parsedArguments["insecure"]) { request.insecure = true; } return request; }; export default parseCurlCommand;