-
Notifications
You must be signed in to change notification settings - Fork 11
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: copy curl command support in span detail component (#2603)
* fix: copy curl command support in span detail component * fix: support to generate curl command
- Loading branch information
1 parent
7080b66
commit d9db405
Showing
7 changed files
with
258 additions
and
9 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
120 changes: 120 additions & 0 deletions
120
...observability/src/shared/utils/curl-command-generator/curl-command-generator-util.test.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,120 @@ | ||
import { CurlCommandGeneratorUtil } from './curl-command-generator-util'; | ||
|
||
describe('generateCurlCommand', () => { | ||
test('should generate a curl command for HTTP GET requests', () => { | ||
const requestUrl = 'https://example.com'; | ||
const protocol = 'HTTP'; | ||
const methodType = 'GET'; | ||
const requestHeaders = {}; | ||
const requestCookies = {}; | ||
const requestBody = ''; | ||
|
||
const curlCommand = CurlCommandGeneratorUtil.generateCurlCommand( | ||
requestHeaders, | ||
requestCookies, | ||
requestBody, | ||
requestUrl, | ||
protocol, | ||
methodType, | ||
); | ||
|
||
expect(curlCommand).toEqual(`curl -X GET https://example.com`); | ||
}); | ||
|
||
test('should generate a curl command for HTTP POST requests with headers and body', () => { | ||
const requestUrl = 'https://example.com'; | ||
const protocol = 'HTTP'; | ||
const methodType = 'POST'; | ||
const requestHeaders = { | ||
'Content-Type': 'application/json', | ||
Accept: 'application/json', | ||
}; | ||
const requestCookies = {}; | ||
const requestBody = '{"name": "John", "age": 30}'; | ||
|
||
const curlCommand = CurlCommandGeneratorUtil.generateCurlCommand( | ||
requestHeaders, | ||
requestCookies, | ||
requestBody, | ||
requestUrl, | ||
protocol, | ||
methodType, | ||
); | ||
|
||
expect(curlCommand).toEqual( | ||
`curl -X POST -H 'Content-Type: application/json' -H 'Accept: application/json' -d '{"name": "John", "age": 30}' https://example.com`, | ||
); | ||
}); | ||
|
||
test('should generate a curl command for HTTP POST requests with cookies', () => { | ||
const requestUrl = 'https://example.com'; | ||
const protocol = 'HTTP'; | ||
const methodType = 'POST'; | ||
const requestHeaders = {}; | ||
const requestCookies = { | ||
sessionid: '123456789', | ||
user: 'John Doe', | ||
}; | ||
const requestBody = '{"name": "John", "age": 30}'; | ||
const curlCommand = CurlCommandGeneratorUtil.generateCurlCommand( | ||
requestHeaders, | ||
requestCookies, | ||
requestBody, | ||
requestUrl, | ||
protocol, | ||
methodType, | ||
); | ||
|
||
expect(curlCommand).toEqual( | ||
`curl -X POST -b 'sessionid=123456789;user=John Doe' -d '{"name": "John", "age": 30}' https://example.com`, | ||
); | ||
}); | ||
|
||
test('should generate a curl command for HTTP POST requests with headers, cookies, and body', () => { | ||
const requestUrl = 'https://example.com'; | ||
const protocol = 'HTTP'; | ||
const methodType = 'POST'; | ||
const requestHeaders = { | ||
'Content-Type': 'application/json', | ||
Accept: 'application/json', | ||
}; | ||
const requestCookies = { | ||
sessionid: '123456789', | ||
user: 'John Doe', | ||
}; | ||
const requestBody = '{"name": "John", "age": 30}'; | ||
|
||
const curlCommand = CurlCommandGeneratorUtil.generateCurlCommand( | ||
requestHeaders, | ||
requestCookies, | ||
requestBody, | ||
requestUrl, | ||
protocol, | ||
methodType, | ||
); | ||
|
||
expect(curlCommand).toEqual( | ||
`curl -X POST -H 'Content-Type: application/json' -H 'Accept: application/json' -b 'sessionid=123456789;user=John Doe' -d '{"name": "John", "age": 30}' https://example.com`, | ||
); | ||
}); | ||
|
||
test('should return an error message for unsupported protocols', () => { | ||
const requestUrl = 'https://example.com'; | ||
const protocol = 'ftp'; | ||
const methodType = 'POST'; | ||
const requestHeaders = {}; | ||
const requestCookies = {}; | ||
const requestBody = ''; | ||
|
||
const curlCommand = CurlCommandGeneratorUtil.generateCurlCommand( | ||
requestHeaders, | ||
requestCookies, | ||
requestBody, | ||
requestUrl, | ||
protocol, | ||
methodType, | ||
); | ||
|
||
expect(curlCommand).toEqual('curl command is not supported'); | ||
}); | ||
}); |
90 changes: 90 additions & 0 deletions
90
...ects/observability/src/shared/utils/curl-command-generator/curl-command-generator-util.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,90 @@ | ||
import { Dictionary } from '@hypertrace/common'; | ||
|
||
export abstract class CurlCommandGeneratorUtil { | ||
private static readonly CURL_COMMAND_NAME: string = 'curl'; | ||
private static readonly HEADER_OPTION: string = '-H'; | ||
private static readonly REQUEST_OPTION: string = '-X'; | ||
private static readonly BODY_OPTION: string = '-d'; | ||
private static readonly COOKIES_OPTION: string = '-b'; | ||
private static readonly SINGLE_SPACE: string = ' '; | ||
private static readonly SINGLE_QUOTES_DELIMITER_CHAR: string = "\\'"; | ||
private static readonly SINGLE_QUOTE_CHAR: string = "'"; | ||
private static readonly SEMI_COLON_CHAR: string = ';'; | ||
private static readonly COLON_CHAR: string = ':'; | ||
private static readonly EQUALS_CHAR: string = '='; | ||
private static readonly GET_METHOD: string = 'GET'; | ||
private static readonly DELETE_METHOD: string = 'DELETE'; | ||
private static readonly NOT_SUPPORTED_MESSAGE: string = 'curl command is not supported'; | ||
|
||
public static generateCurlCommand( | ||
requestHeaders: Dictionary<unknown>, | ||
requestCookies: Dictionary<unknown>, | ||
requestBody: string, | ||
requestUrl: string, | ||
protocol: string, | ||
methodType: string, | ||
): string { | ||
let curlCommand: string = ''; | ||
|
||
if (protocol === Protocol.PROTOCOL_HTTP || protocol === Protocol.PROTOCOL_HTTPS) { | ||
curlCommand += `${this.CURL_COMMAND_NAME}${this.SINGLE_SPACE}${this.REQUEST_OPTION}${this.SINGLE_SPACE}${methodType}${this.SINGLE_SPACE}`; | ||
|
||
if (Object.entries(requestHeaders).length > 0) { | ||
curlCommand += `${this.getHeadersAsString(requestHeaders)}`; | ||
} | ||
|
||
if (Object.entries(requestCookies).length > 0) { | ||
curlCommand += `${this.getCookiesAsString(requestCookies)}`; | ||
} | ||
|
||
// { POST, PUT, PATCH } methodType will have a body, and { GET, DELETE } will not. | ||
if (!(methodType.includes(this.GET_METHOD) || methodType.includes(this.DELETE_METHOD))) { | ||
curlCommand += `${this.BODY_OPTION}${this.SINGLE_SPACE}${this.SINGLE_QUOTE_CHAR}${this.getEnrichedBody( | ||
requestBody, | ||
)}${this.SINGLE_QUOTE_CHAR}${this.SINGLE_SPACE}`; | ||
} | ||
|
||
curlCommand += requestUrl; | ||
} else { | ||
curlCommand += this.NOT_SUPPORTED_MESSAGE; | ||
} | ||
|
||
return curlCommand; | ||
} | ||
|
||
private static getHeadersAsString(requestHeaders: Dictionary<unknown>): string { | ||
return Object.entries(requestHeaders) | ||
.map( | ||
([key, value]) => | ||
`${this.HEADER_OPTION}${this.SINGLE_SPACE}${this.SINGLE_QUOTE_CHAR}${key}${this.COLON_CHAR}${this.SINGLE_SPACE}${value}${this.SINGLE_QUOTE_CHAR}${this.SINGLE_SPACE}`, | ||
) | ||
.join(''); | ||
} | ||
|
||
private static getCookiesAsString(requestCookies: Dictionary<unknown>): string { | ||
let cookiesString: string = ''; | ||
|
||
cookiesString += `${this.COOKIES_OPTION}${this.SINGLE_SPACE}${this.SINGLE_QUOTE_CHAR}`; | ||
|
||
Object.entries(requestCookies).forEach(([key, value]) => { | ||
cookiesString += `${key}${this.EQUALS_CHAR}${value}${this.SEMI_COLON_CHAR}`; | ||
}); | ||
|
||
if (cookiesString[cookiesString.length - 1] === this.SEMI_COLON_CHAR) { | ||
cookiesString = cookiesString.substr(0, cookiesString.length - 1); | ||
} | ||
|
||
cookiesString += `${this.SINGLE_QUOTE_CHAR}${this.SINGLE_SPACE}`; | ||
|
||
return cookiesString; | ||
} | ||
|
||
private static getEnrichedBody(body: string): string { | ||
return body.replaceAll(this.SINGLE_QUOTE_CHAR, this.SINGLE_QUOTES_DELIMITER_CHAR); | ||
} | ||
} | ||
|
||
const enum Protocol { | ||
PROTOCOL_HTTP = 'HTTP', | ||
PROTOCOL_HTTPS = 'HTTPS', | ||
} |