core/source/logic/check_kinds/http_request.ts
Christian Fraß 2b6e350e3b [int]
2023-06-19 18:27:04 +02:00

355 lines
7.6 KiB
TypeScript

namespace _heimdall.check_kinds.http_request
{
/**
*/
function parameters_schema(
) : _heimdall.helpers.json_schema.type_schema
{
return {
"type": "object",
"additionalProperties": false,
"properties": {
"request": {
"type": "object",
"additionalProperties": false,
"properties": {
"target": {
"description": "URL",
"type": "string"
},
"method": {
"type": "string",
"enum": [
"GET",
"POST"
],
"default": "GET"
}
},
"required": [
"target"
]
},
"timeout": {
"description": "maximum allowed execution time in seconds",
"type": "number",
"default": 5.0
},
"follow_redirects": {
"description": "whether redirect instructions in responses shall be followend instead of being exposed as result",
"type": "boolean",
"default": false
},
"response": {
"type": "object",
"additionalProperties": false,
"properties": {
"status_code": {
"description": "checks whether the response status code is this",
"type": ["null", "integer"],
"default": 200
},
"headers": {
"description": "conjunctively checks header key-value pairs",
"type": "object",
"additionalProperties": {
"description": "header value",
"type": "string"
},
"properties": {
},
"required": [
],
"default": {}
},
"body_part": {
"description": "checks whether the response body contains this string",
"type": "string"
}
},
"required": [
]
},
"critical": {
"description": "whether a violation of this check shall be leveled as critical instead of concerning",
"type": "boolean",
"default": true
},
"strict": {
"deprecated": true,
"description": "alias for 'critical'",
"type": "boolean",
"default": true
},
},
"required": [
"request",
]
};
}
/**
*/
function normalize_order_node(
node : any
) : any
{
const version : string = (
(! ("critical" in node))
? "v1"
: "v2"
);
switch (version) {
default: {
throw (new Error("unhandled version"));
break;
}
case "v1": {
const node_ = lib_plankton.object.patched(
{
"request": {
"method": "GET"
},
"timeout": 5.0,
"follow_redirects": false,
"response": {
"status_code": 200
},
"strict": true,
},
node,
true
);
const allowed_methods : Array<string> = ["GET", "POST"];
if (! allowed_methods.includes(node_["request"]["method"])) {
throw (new Error("invalid HTTP request method: " + node_["request"]["method"]));
}
else {
return {
"request": node_["request"],
"timeout": node_["timeout"],
"follow_redirects": node_["follow_redirects"],
"response": node_["response"],
"critical": node_["strict"],
};
}
break;
}
case "v2": {
const node_ = lib_plankton.object.patched(
{
"request": {
"method": "GET"
},
"timeout": 5.0,
"follow_redirects": false,
"response": {
"status_code": 200
},
"critical": true,
},
node,
true
);
const allowed_methods : Array<string> = ["GET", "POST"];
if (! allowed_methods.includes(node_["request"]["method"])) {
throw (new Error("invalid HTTP request method: " + node_["request"]["method"]));
}
else {
return node_;
}
break;
}
}
}
/**
*/
async function run(
parameters
) : Promise<_heimdall.type_result>
{
let error : (null | Error);
const http_request : lib_plankton.http.type_request = {
"host": parameters["request"]["target"],
"query": "",
"method": {
"GET": lib_plankton.http.enum_method.get,
"POST": lib_plankton.http.enum_method.post,
}[parameters["request"]["method"]],
"headers": {},
"body": "",
};
let http_response : (null | lib_plankton.http.type_response);
try {
http_response = await lib_plankton.http.call(
http_request,
{
"timeout": parameters["timeout"],
"follow_redirects": parameters["follow_redirects"],
}
);
error = null;
}
catch (error_) {
http_response = null;
error = error_;
}
if (http_response === null) {
return {
"condition": (
parameters["strict"]
? _heimdall.enum_condition.critical
: _heimdall.enum_condition.concerning
),
"info": {
"request": parameters["request"],
"faults": [
lib_plankton.translate.get("checks.http_request.request_failed"),
],
},
};
}
else {
let faults : Array<string> = [];
// status code
{
if (
(! ("status_code" in parameters["response"]))
||
(parameters["response"]["status_code"] === null)
) {
// do nothing
}
else {
const status_code_expected : int = (parameters["response"]["status_code"] as int);
if (http_response.statuscode === status_code_expected) {
faults.push(
lib_plankton.translate.get(
"checks.http_request.status_code_mismatch",
{
"status_code_actual": http_response.statuscode.toFixed(0),
"status_code_expected": status_code_expected.toFixed(0),
}
)
);
}
else {
// do nothing
}
}
}
// headers
{
if (
(! ("headers" in parameters["response"]))
||
(parameters["response"]["headers"] === null)
) {
// do nothing
}
else {
const headers_expected : Record<string, string> = (parameters["response"]["headers"] as Record<string, string>);
Object.entries(headers_expected).forEach(
([header_key, header_value]) => {
if (! (header_key in http_response.headers)) {
faults.push(
lib_plankton.translate.get(
"checks.http_request.header_missing",
{
"key": header_key,
"value_expected": header_value,
}
)
);
}
else {
if (! (http_response.headers[header_key] === header_value)) {
faults.push(
lib_plankton.translate.get(
"checks.http_request.header_value_mismatch",
{
"key": header_key,
"value_actual": http_response.headers[header_key],
"value_expected": header_value,
}
)
);
}
else {
// do nothing
}
}
}
);
}
}
// body
{
if (
(! ("body_part" in parameters["response"]))
||
(parameters["response"]["body_part"] === null)
) {
// do nothing
}
else {
const body_part : string = (parameters["response"]["body_part"] as string);
if (! http_response.body.includes(body_part)) {
faults.push(
lib_plankton.translate.get(
"checks.http_request.body_misses_part",
{
"part": body_part,
}
)
);
}
else {
// do nothing
}
}
}
return {
"condition": (
(faults.length <= 0)
? _heimdall.enum_condition.ok
: (
parameters["critical"]
? _heimdall.enum_condition.critical
: _heimdall.enum_condition.concerning
)
),
"info": {
"request": parameters["request"],
"response": {
"status_code": http_response.statuscode,
"headers": http_response.headers,
// "body": http_response.body,
},
"faults": faults,
}
};
}
}
/**
*/
export function check_kind_implementation(
) : type_check_kind
{
return {
"parameters_schema": parameters_schema,
"normalize_order_node": normalize_order_node,
"run": run,
};
}
}