mirror of
https://github.com/Kong/insomnia
synced 2024-11-08 14:49:53 +00:00
257 lines
7.2 KiB
JavaScript
257 lines
7.2 KiB
JavaScript
|
'use strict';
|
||
|
|
||
|
import render from './render'
|
||
|
import * as querystring from './querystring'
|
||
|
import * as db from '../database'
|
||
|
import {DEBOUNCE_MILLIS} from "./constants";
|
||
|
import {METHOD_GET} from "./constants";
|
||
|
|
||
|
const FLAGS = [
|
||
|
'cacert', 'capath', 'E', 'cert', 'cert-type', 'ciphers', 'K', 'config',
|
||
|
'connect-timeout', 'C', 'continue-at', 'b',
|
||
|
'cookie', // TODO: Handle this
|
||
|
'c', 'cookie-jar', 'crlfile', 'd', 'data', 'data-ascii', 'data-binary',
|
||
|
'data-urlencode', 'delegation', 'D', 'dump-header', 'egd-file',
|
||
|
'engine', 'F', 'form', 'form-string', 'ftp-account', 'ftp-method',
|
||
|
'ftp-port', 'H', 'header', 'hostpubmd5', 'interface', 'keepalive-time',
|
||
|
'key', 'key-type', 'krb', 'lib-curl', 'limit-rate', 'local-port',
|
||
|
'mail-from', 'mail-rcpt', 'mail-auth', 'max-filesize', 'max-redirs',
|
||
|
'max-time', 'netrtc-file', 'output', 'pass', 'proto', 'proto-redir',
|
||
|
'proxy', 'proxy-user', 'proxy1.0', 'pubkey', 'Q', 'quote',
|
||
|
'random-file', 'range', 'X', 'request', 'resolve', 'retry',
|
||
|
'retry-delay', 'retry-max-time', 'socks4', 'socks4a', 'socks5',
|
||
|
'socks5-hostname', 'socks5-gssapi-service', 'Y', 'speed-limit',
|
||
|
'y', 'speed-time', 'stderr', 'tftp-blksize', 'z', 'time-cond', 'trace',
|
||
|
'trace-ascii', 'T', 'upload-file',
|
||
|
'url', // TODO: Handle this
|
||
|
'u', 'user', 'tlsuser', 'tlspassword', 'tlsauthtype',
|
||
|
'A', 'user-agent', // TODO: Handle this
|
||
|
'w', 'write-out'
|
||
|
];
|
||
|
|
||
|
const FLAG_REGEXES = [
|
||
|
/\s--([\w\-]{2,})\s+"((?:[^"\\]|\\.)*)"/, // --my-flag "hello"
|
||
|
/\s--([\w\-]{2,})\s+'((?:[^'\\]|\\.)*)'/, // --my-flag 'hello'
|
||
|
/\s--([\w\-]{2,})\s+([^\s]+)/, // --my-flag hello
|
||
|
/\s-([\w])\s*'((?:[^'\\]|\\.)*)'/, // -X 'hello'
|
||
|
/\s-([\w])\s*"((?:[^"\\]|\\.)*)"/, // -X "hello"
|
||
|
/\s-([\w])\s*([^\s]+)/, // -X hello
|
||
|
/\s--([\w\-]+)/ // --switch (cleanup at the end)
|
||
|
];
|
||
|
|
||
|
function getFlags (cmd) {
|
||
|
const flags = {};
|
||
|
const switches = {};
|
||
|
|
||
|
for (var i = 0; i < FLAG_REGEXES.length; i++) {
|
||
|
var matches = [];
|
||
|
var match;
|
||
|
var key;
|
||
|
var val;
|
||
|
var matchedFlag;
|
||
|
|
||
|
// Stop at 1000 to prevent infinite loops
|
||
|
// TODO: Make this recursive
|
||
|
for (var j = 0; (matches = FLAG_REGEXES[i].exec(cmd)); j++) {
|
||
|
if (j > 1000) {
|
||
|
console.error('INFINITE LOOP');
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
match = matches[0];
|
||
|
key = matches[1];
|
||
|
val = matches[2];
|
||
|
matchedFlag = !!val;
|
||
|
|
||
|
if (matchedFlag) {
|
||
|
if (isFlag(key)) {
|
||
|
// Matched a flag
|
||
|
flags[key] = flags[key] || [];
|
||
|
flags[key].push(val);
|
||
|
cmd = cmd.replace(match, '');
|
||
|
} else {
|
||
|
// Matched a flag that was actually a switch
|
||
|
cmd = cmd.replace('--' + key, '');
|
||
|
}
|
||
|
} else {
|
||
|
// Matched a switch directly without a value
|
||
|
switches[key] = true;
|
||
|
cmd = cmd.replace(match, '');
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return {cmd, flags, switches};
|
||
|
}
|
||
|
|
||
|
function isFlag (key) {
|
||
|
for (var i = 0; i < FLAGS.length; i++) {
|
||
|
if (key === FLAGS[i]) {
|
||
|
return true;
|
||
|
}
|
||
|
}
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
function splitHeaders (flags) {
|
||
|
var headers = (flags['H'] || []).concat(flags['header'] || []);
|
||
|
var parsed = [];
|
||
|
|
||
|
for (var i = 0; i < headers.length; i++) {
|
||
|
var header = headers[i].split(':');
|
||
|
var name = header[0].trim();
|
||
|
var value = header[1].trim();
|
||
|
parsed.push({name: name, value: value});
|
||
|
}
|
||
|
|
||
|
return parsed;
|
||
|
}
|
||
|
|
||
|
function getContentType (headers) {
|
||
|
for (var i = 0; i < headers.length; i++) {
|
||
|
var header = headers[i];
|
||
|
if (header.name.toLowerCase() === 'content-type') {
|
||
|
return header.value;
|
||
|
}
|
||
|
}
|
||
|
return null;
|
||
|
}
|
||
|
|
||
|
function getHttpMethod (flags, hasBody) {
|
||
|
var method = (flags['X'] || flags['request'] || [])[0];
|
||
|
|
||
|
// If there is no method specified, but there is a body, default
|
||
|
// to POST, else default to GET
|
||
|
if (!method) {
|
||
|
method = hasBody ? 'POST' : 'GET';
|
||
|
}
|
||
|
|
||
|
return method;
|
||
|
}
|
||
|
|
||
|
function getBasicAuth (flags) {
|
||
|
var authString = flags.u || flags.user;
|
||
|
var auth = {
|
||
|
username: '',
|
||
|
password: ''
|
||
|
};
|
||
|
|
||
|
if (authString) {
|
||
|
var authSplit = authString[0].split(':');
|
||
|
auth.username = (authSplit[0] || '').trim();
|
||
|
auth.password = (authSplit[1] || '').trim();
|
||
|
}
|
||
|
|
||
|
return auth;
|
||
|
}
|
||
|
|
||
|
export function exportCurl (requestId) {
|
||
|
return new Promise((resolve, reject) => {
|
||
|
|
||
|
// First, lets wait for all debounces to finish
|
||
|
setTimeout(() => {
|
||
|
db.requestById(requestId).then(request => {
|
||
|
db.requestGroupById(request.parentId).then(requestGroup => {
|
||
|
const renderCtx = requestGroup ? requestGroup.environment : {};
|
||
|
|
||
|
// Build the querystring
|
||
|
const paramsString = JSON.stringify(request.params);
|
||
|
const params = JSON.parse(render(paramsString, renderCtx));
|
||
|
const qs = querystring.buildFromParams(params);
|
||
|
|
||
|
// Build the Url
|
||
|
const url = querystring.joinURL(request.url, qs);
|
||
|
const IS_GET_REQUEST = request.method.toUpperCase() === METHOD_GET.toUpperCase();
|
||
|
|
||
|
let cmd = 'curl';
|
||
|
|
||
|
// HTTP method
|
||
|
if (!IS_GET_REQUEST) {
|
||
|
cmd += ` -X ${request.method.toUpperCase()}`;
|
||
|
}
|
||
|
|
||
|
// Url
|
||
|
cmd += ` '${url.replace(`'`, `'"'"'`)}'`;
|
||
|
|
||
|
// Payload
|
||
|
if (request.body) {
|
||
|
cmd += ` \\\n -d '${request.body.replace(`'`, `'"'"'`)}'`;
|
||
|
}
|
||
|
|
||
|
// Basic auth
|
||
|
const {username, password} = request.authentication;
|
||
|
if (username || password) {
|
||
|
cmd += ` \\\n -u ${username}:${password}`;
|
||
|
}
|
||
|
|
||
|
// Headers
|
||
|
const hasContentTypeHeader = !!request.headers.find(h => h.name.toUpperCase() === 'CONTENT-TYPE');
|
||
|
|
||
|
if (!hasContentTypeHeader && !IS_GET_REQUEST) {
|
||
|
const value = request.contentType;
|
||
|
const name = 'Content-Type';
|
||
|
|
||
|
request.headers.push({name, value})
|
||
|
}
|
||
|
|
||
|
for (let i = 0; i < request.headers.length; i++) {
|
||
|
const {name, value} = request.headers[i];
|
||
|
cmd += ` \\\n -H '${name}: ${value}'`;
|
||
|
}
|
||
|
|
||
|
resolve(render(cmd, renderCtx));
|
||
|
});
|
||
|
});
|
||
|
}, DEBOUNCE_MILLIS);
|
||
|
});
|
||
|
}
|
||
|
|
||
|
export function importCurl (blob) {
|
||
|
if (!blob || blob.toLowerCase().indexOf('curl ') !== 0) {
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
// Rip out the flags
|
||
|
let {cmd, flags, switches} = getFlags(blob);
|
||
|
|
||
|
// Final values
|
||
|
const headers = splitHeaders(flags);
|
||
|
|
||
|
let body = (
|
||
|
flags.d ||
|
||
|
flags.data ||
|
||
|
flags['data-binary'] ||
|
||
|
flags['data-ascii'] ||
|
||
|
[]
|
||
|
)[0] || '';
|
||
|
|
||
|
const contentType = getContentType(headers) || null;
|
||
|
|
||
|
if (contentType.toLowerCase() === 'application/json') {
|
||
|
try {
|
||
|
body = JSON.stringify(JSON.parse(body), null, '\t');
|
||
|
} catch (e) {}
|
||
|
}
|
||
|
|
||
|
const httpMethod = getHttpMethod(flags, !!body);
|
||
|
const authentication = getBasicAuth(flags);
|
||
|
|
||
|
// Clean up the remaining URL
|
||
|
cmd = (cmd + ' ')
|
||
|
.replace(/\\ /g, ' ').replace(/ \\/g, ' ') // slashes
|
||
|
.replace(/\s/g, ' ') // whitespaces
|
||
|
.replace(/ "/g, ' ').replace(/" /g, ' ') // double-quotes
|
||
|
.replace(/ '/g, ' ').replace(/' /g, ' '); // single-quotes
|
||
|
|
||
|
const url = /curl\s+['"]?((?!('|")).*)['"]?/.exec(cmd)[1].trim();
|
||
|
|
||
|
return {
|
||
|
url: url,
|
||
|
body: body,
|
||
|
headers: headers,
|
||
|
contentType: contentType,
|
||
|
method: httpMethod,
|
||
|
authentication: authentication
|
||
|
};
|
||
|
}
|