import * as cookie from "cookie" import * as URL from "url" import * as querystring from "querystring" import parser from "yargs-parser" /** * 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 = /\\/gi.test(curlCommand) if (newlineFound) { // remove '\' and newlines curlCommand = curlCommand.replace(/\\/gi, "") curlCommand = curlCommand.replace(/\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 = 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