mirror of
https://github.com/elastic/kibana.git
synced 2025-06-27 18:51:07 -04:00
## Summary
This PR adds support for PATCH requests in Console.

Closes #154274
### Checklist
- [x]
[Documentation](https://www.elastic.co/guide/en/kibana/master/development-documentation.html)
was added for features that require explanation or tutorials
- [x] [Unit or functional
tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)
were updated or added to match the most common scenarios
### For maintainers
- [x] This was checked for breaking API changes and was [labeled
appropriately](https://www.elastic.co/guide/en/kibana/master/contributing.html#kibana-release-notes-process)
## Release note
Adds support for PATCH requests in Console.
---------
Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com>
193 lines
5 KiB
JavaScript
193 lines
5 KiB
JavaScript
/*
|
|
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
|
* or more contributor license agreements. Licensed under the Elastic License
|
|
* 2.0 and the Server Side Public License, v 1; you may not use this file except
|
|
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
|
* Side Public License, v 1.
|
|
*/
|
|
|
|
function detectCURLinLine(line) {
|
|
// returns true if text matches a curl request
|
|
return line.match(/^\s*?curl\s+(-X[A-Z]+)?\s*['"]?.*?['"]?(\s*$|\s+?-d\s*?['"])/);
|
|
}
|
|
|
|
export function detectCURL(text) {
|
|
// returns true if text matches a curl request
|
|
if (!text) return false;
|
|
for (const line of text.split('\n')) {
|
|
if (detectCURLinLine(line)) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
export function parseCURL(text) {
|
|
let state = 'NONE';
|
|
const out = [];
|
|
let body = [];
|
|
let line = '';
|
|
const lines = text.trim().split('\n');
|
|
let matches;
|
|
|
|
const EmptyLine = /^\s*$/;
|
|
const Comment = /^\s*(?:#|\/{2,})(.*)\n?$/;
|
|
const ExecutionComment = /^\s*#!/;
|
|
const ClosingSingleQuote = /^([^']*)'/;
|
|
const ClosingDoubleQuote = /^((?:[^\\"]|\\.)*)"/;
|
|
const EscapedQuotes = /^((?:[^\\"']|\\.)+)/;
|
|
|
|
const LooksLikeCurl = /^\s*curl\s+/;
|
|
const CurlVerb = /-X ?(GET|HEAD|POST|PUT|DELETE|PATCH)/;
|
|
|
|
const HasProtocol = /[\s"']https?:\/\//;
|
|
const CurlRequestWithProto = /[\s"']https?:\/\/[^\/ ]+\/+([^\s"']+)/;
|
|
const CurlRequestWithoutProto = /[\s"'][^\/ ]+\/+([^\s"']+)/;
|
|
const CurlData = /^.+\s(--data|-d)\s*/;
|
|
const SenseLine = /^\s*(GET|HEAD|POST|PUT|DELETE|PATCH)\s+\/?(.+)/;
|
|
|
|
if (lines.length > 0 && ExecutionComment.test(lines[0])) {
|
|
lines.shift();
|
|
}
|
|
|
|
function nextLine() {
|
|
if (line.length > 0) {
|
|
return true;
|
|
}
|
|
if (lines.length === 0) {
|
|
return false;
|
|
}
|
|
line = lines.shift().replace(/[\r\n]+/g, '\n') + '\n';
|
|
return true;
|
|
}
|
|
|
|
function unescapeLastBodyEl() {
|
|
const str = body.pop().replace(/\\([\\"'])/g, '$1');
|
|
body.push(str);
|
|
}
|
|
|
|
// Is the next char a single or double quote?
|
|
// If so remove it
|
|
function detectQuote() {
|
|
if (line.substr(0, 1) === "'") {
|
|
line = line.substr(1);
|
|
state = 'SINGLE_QUOTE';
|
|
} else if (line.substr(0, 1) === '"') {
|
|
line = line.substr(1);
|
|
state = 'DOUBLE_QUOTE';
|
|
} else {
|
|
state = 'UNQUOTED';
|
|
}
|
|
}
|
|
|
|
// Body is finished - append to output with final LF
|
|
function addBodyToOut() {
|
|
if (body.length > 0) {
|
|
out.push(body.join(''));
|
|
body = [];
|
|
}
|
|
state = 'LF';
|
|
out.push('\n');
|
|
}
|
|
|
|
// If the pattern matches, then the state is about to change,
|
|
// so add the capture to the body and detect the next state
|
|
// Otherwise add the whole line
|
|
function consumeMatching(pattern) {
|
|
const matches = line.match(pattern);
|
|
if (matches) {
|
|
body.push(matches[1]);
|
|
line = line.substr(matches[0].length);
|
|
detectQuote();
|
|
} else {
|
|
body.push(line);
|
|
line = '';
|
|
}
|
|
}
|
|
|
|
function parseCurlLine() {
|
|
let verb = 'GET';
|
|
let request = '';
|
|
let matches;
|
|
if ((matches = line.match(CurlVerb))) {
|
|
verb = matches[1];
|
|
}
|
|
|
|
// JS regexen don't support possessive quantifiers, so
|
|
// we need two distinct patterns
|
|
const pattern = HasProtocol.test(line) ? CurlRequestWithProto : CurlRequestWithoutProto;
|
|
|
|
if ((matches = line.match(pattern))) {
|
|
request = matches[1];
|
|
}
|
|
|
|
out.push(verb + ' /' + request + '\n');
|
|
|
|
if ((matches = line.match(CurlData))) {
|
|
line = line.substr(matches[0].length);
|
|
detectQuote();
|
|
if (EmptyLine.test(line)) {
|
|
line = '';
|
|
}
|
|
} else {
|
|
state = 'NONE';
|
|
line = '';
|
|
out.push('');
|
|
}
|
|
}
|
|
|
|
while (nextLine()) {
|
|
if (state === 'SINGLE_QUOTE') {
|
|
consumeMatching(ClosingSingleQuote);
|
|
} else if (state === 'DOUBLE_QUOTE') {
|
|
consumeMatching(ClosingDoubleQuote);
|
|
unescapeLastBodyEl();
|
|
} else if (state === 'UNQUOTED') {
|
|
consumeMatching(EscapedQuotes);
|
|
if (body.length) {
|
|
unescapeLastBodyEl();
|
|
}
|
|
if (state === 'UNQUOTED') {
|
|
addBodyToOut();
|
|
line = '';
|
|
}
|
|
}
|
|
|
|
// the BODY state (used to match the body of a Sense request)
|
|
// can be terminated early if it encounters
|
|
// a comment or an empty line
|
|
else if (state === 'BODY') {
|
|
if (Comment.test(line) || EmptyLine.test(line)) {
|
|
addBodyToOut();
|
|
} else {
|
|
body.push(line);
|
|
line = '';
|
|
}
|
|
} else if (EmptyLine.test(line)) {
|
|
if (state !== 'LF') {
|
|
out.push('\n');
|
|
state = 'LF';
|
|
}
|
|
line = '';
|
|
} else if ((matches = line.match(Comment))) {
|
|
out.push('#' + matches[1] + '\n');
|
|
state = 'NONE';
|
|
line = '';
|
|
} else if (LooksLikeCurl.test(line)) {
|
|
parseCurlLine();
|
|
} else if ((matches = line.match(SenseLine))) {
|
|
out.push(matches[1] + ' /' + matches[2] + '\n');
|
|
line = '';
|
|
state = 'BODY';
|
|
}
|
|
|
|
// Nothing else matches, so output with a prefix of !!! for debugging purposes
|
|
else {
|
|
out.push('### ' + line);
|
|
line = '';
|
|
}
|
|
}
|
|
|
|
addBodyToOut();
|
|
return out.join('').trim();
|
|
}
|