/** @file | |
Redfish debug library to debug Redfish application. | |
Copyright (c) 2023-2024, NVIDIA CORPORATION & AFFILIATES. All rights reserved. | |
Copyright (C) 2024 Advanced Micro Devices, Inc. All rights reserved.<BR> | |
SPDX-License-Identifier: BSD-2-Clause-Patent | |
**/ | |
#include <Uefi.h> | |
#include <Library/BaseLib.h> | |
#include <Library/DebugLib.h> | |
#include <Library/MemoryAllocationLib.h> | |
#include <Library/RedfishDebugLib.h> | |
#include <Library/RedfishHttpLib.h> | |
#include <Library/UefiLib.h> | |
#ifndef IS_EMPTY_STRING | |
#define IS_EMPTY_STRING(a) ((a) == NULL || (a)[0] == '\0') | |
#endif | |
#define REDFISH_JSON_STRING_LENGTH 200 | |
#define REDFISH_JSON_OUTPUT_FORMAT (EDKII_JSON_COMPACT | EDKII_JSON_INDENT(2)) | |
#define REDFISH_PRINT_BUFFER_BYTES_PER_ROW 16 | |
/** | |
Determine whether the Redfish debug category is enabled in | |
gEfiRedfishPkgTokenSpaceGuid.PcdRedfishDebugCategory. | |
@param[in] RedfishDebugCategory Redfish debug category. | |
@retval TRUE This debug category is enabled. | |
@retval FALSE This debug category is disabled.. | |
**/ | |
BOOLEAN | |
DebugRedfishComponentEnabled ( | |
IN UINT64 RedfishDebugCategory | |
) | |
{ | |
UINT64 DebugCategory; | |
DebugCategory = FixedPcdGet64 (PcdRedfishDebugCategory); | |
return ((DebugCategory & RedfishDebugCategory) != 0); | |
} | |
/** | |
Debug print the value of RedfishValue. | |
@param[in] ErrorLevel DEBUG macro error level. | |
@param[in] RedfishValue The statement value to print. | |
@retval EFI_SUCCESS RedfishValue is printed. | |
@retval EFI_INVALID_PARAMETER RedfishValue is NULL. | |
**/ | |
EFI_STATUS | |
DumpRedfishValue ( | |
IN UINTN ErrorLevel, | |
IN EDKII_REDFISH_VALUE *RedfishValue | |
) | |
{ | |
UINTN Index; | |
if (RedfishValue == NULL) { | |
return EFI_INVALID_PARAMETER; | |
} | |
DEBUG ((ErrorLevel, "Type: 0x%x\n", RedfishValue->Type)); | |
DEBUG ((ErrorLevel, "ArrayCount: 0x%x\n", RedfishValue->ArrayCount)); | |
switch (RedfishValue->Type) { | |
case RedfishValueTypeInteger: | |
DEBUG ((ErrorLevel, "Value: 0x%x\n", RedfishValue->Value.Integer)); | |
break; | |
case RedfishValueTypeBoolean: | |
DEBUG ((ErrorLevel, "Value: %a\n", (RedfishValue->Value.Boolean ? "true" : "false"))); | |
break; | |
case RedfishValueTypeString: | |
DEBUG ((ErrorLevel, "Value: %a\n", RedfishValue->Value.Buffer)); | |
break; | |
case RedfishValueTypeStringArray: | |
for (Index = 0; Index < RedfishValue->ArrayCount; Index++) { | |
DEBUG ((ErrorLevel, "Value[%d]: %a\n", Index, RedfishValue->Value.StringArray[Index])); | |
} | |
break; | |
case RedfishValueTypeIntegerArray: | |
for (Index = 0; Index < RedfishValue->ArrayCount; Index++) { | |
DEBUG ((ErrorLevel, "Value[%d]: 0x%x\n", Index, RedfishValue->Value.IntegerArray[Index])); | |
} | |
break; | |
case RedfishValueTypeBooleanArray: | |
for (Index = 0; Index < RedfishValue->ArrayCount; Index++) { | |
DEBUG ((ErrorLevel, "Value[%d]: %a\n", Index, (RedfishValue->Value.BooleanArray[Index] ? "true" : "false"))); | |
} | |
break; | |
case RedfishValueTypeUnknown: | |
case RedfishValueTypeMax: | |
default: | |
break; | |
} | |
return EFI_SUCCESS; | |
} | |
/** | |
This function dump the Json string in given error level. | |
@param[in] ErrorLevel DEBUG macro error level | |
@param[in] JsonValue Json value to dump. | |
@retval EFI_SUCCESS Json string is printed. | |
@retval Others Errors occur. | |
**/ | |
EFI_STATUS | |
DumpJsonValue ( | |
IN UINTN ErrorLevel, | |
IN EDKII_JSON_VALUE JsonValue | |
) | |
{ | |
CHAR8 *String; | |
CHAR8 *Runner; | |
CHAR8 Buffer[REDFISH_JSON_STRING_LENGTH + 1]; | |
UINTN StrLen; | |
UINTN Count; | |
UINTN Index; | |
if (JsonValue == NULL) { | |
return EFI_INVALID_PARAMETER; | |
} | |
String = JsonDumpString (JsonValue, REDFISH_JSON_OUTPUT_FORMAT); | |
if (String == NULL) { | |
return EFI_UNSUPPORTED; | |
} | |
StrLen = AsciiStrLen (String); | |
if (StrLen == 0) { | |
return EFI_UNSUPPORTED; | |
} | |
Count = StrLen / REDFISH_JSON_STRING_LENGTH; | |
Runner = String; | |
for (Index = 0; Index < Count; Index++) { | |
AsciiStrnCpyS (Buffer, (REDFISH_JSON_STRING_LENGTH + 1), Runner, REDFISH_JSON_STRING_LENGTH); | |
Buffer[REDFISH_JSON_STRING_LENGTH] = '\0'; | |
DEBUG ((ErrorLevel, "%a", Buffer)); | |
Runner += REDFISH_JSON_STRING_LENGTH; | |
} | |
Count = StrLen % REDFISH_JSON_STRING_LENGTH; | |
if (Count > 0) { | |
DEBUG ((ErrorLevel, "%a", Runner)); | |
} | |
DEBUG ((ErrorLevel, "\n")); | |
FreePool (String); | |
return EFI_SUCCESS; | |
} | |
/** | |
This function dump the status code, header and body in given | |
Redfish payload. | |
@param[in] ErrorLevel DEBUG macro error level | |
@param[in] Payload Redfish payload to dump | |
@retval EFI_SUCCESS Redfish payload is printed. | |
@retval Others Errors occur. | |
**/ | |
EFI_STATUS | |
DumpRedfishPayload ( | |
IN UINTN ErrorLevel, | |
IN REDFISH_PAYLOAD Payload | |
) | |
{ | |
EDKII_JSON_VALUE JsonValue; | |
if (Payload == NULL) { | |
return EFI_INVALID_PARAMETER; | |
} | |
JsonValue = RedfishJsonInPayload (Payload); | |
if (JsonValue != NULL) { | |
DEBUG ((ErrorLevel, "Payload:\n")); | |
DumpJsonValue (ErrorLevel, JsonValue); | |
} | |
return EFI_SUCCESS; | |
} | |
/** | |
This function dump the HTTP status code. | |
@param[in] ErrorLevel DEBUG macro error level | |
@param[in] HttpStatusCode HTTP status code | |
@retval EFI_SUCCESS HTTP status code is printed | |
**/ | |
EFI_STATUS | |
DumpHttpStatusCode ( | |
IN UINTN ErrorLevel, | |
IN EFI_HTTP_STATUS_CODE HttpStatusCode | |
) | |
{ | |
switch (HttpStatusCode) { | |
case HTTP_STATUS_100_CONTINUE: | |
DEBUG ((ErrorLevel, "Status code: 100 CONTINUE\n")); | |
break; | |
case HTTP_STATUS_200_OK: | |
DEBUG ((ErrorLevel, "Status code: 200 OK\n")); | |
break; | |
case HTTP_STATUS_201_CREATED: | |
DEBUG ((ErrorLevel, "Status code: 201 CREATED\n")); | |
break; | |
case HTTP_STATUS_202_ACCEPTED: | |
DEBUG ((ErrorLevel, "Status code: 202 ACCEPTED\n")); | |
break; | |
case HTTP_STATUS_304_NOT_MODIFIED: | |
DEBUG ((ErrorLevel, "Status code: 304 NOT MODIFIED\n")); | |
break; | |
case HTTP_STATUS_400_BAD_REQUEST: | |
DEBUG ((ErrorLevel, "Status code: 400 BAD REQUEST\n")); | |
break; | |
case HTTP_STATUS_401_UNAUTHORIZED: | |
DEBUG ((ErrorLevel, "Status code: 401 UNAUTHORIZED\n")); | |
break; | |
case HTTP_STATUS_403_FORBIDDEN: | |
DEBUG ((ErrorLevel, "Status code: 403 FORBIDDEN\n")); | |
break; | |
case HTTP_STATUS_404_NOT_FOUND: | |
DEBUG ((ErrorLevel, "Status code: 404 NOT FOUND\n")); | |
break; | |
case HTTP_STATUS_405_METHOD_NOT_ALLOWED: | |
DEBUG ((ErrorLevel, "Status code: 405 METHOD NOT ALLOWED\n")); | |
break; | |
case HTTP_STATUS_500_INTERNAL_SERVER_ERROR: | |
DEBUG ((ErrorLevel, "Status code: 500 INTERNAL SERVER ERROR\n")); | |
break; | |
default: | |
DEBUG ((ErrorLevel, "Status code: 0x%x\n", HttpStatusCode)); | |
break; | |
} | |
return EFI_SUCCESS; | |
} | |
/** | |
This function dump the status code, header and body in given | |
Redfish response. | |
@param[in] Message Message string | |
@param[in] ErrorLevel DEBUG macro error level | |
@param[in] Response Redfish response to dump | |
@retval EFI_SUCCESS Redfish response is printed. | |
@retval Others Errors occur. | |
**/ | |
EFI_STATUS | |
DumpRedfishResponse ( | |
IN CONST CHAR8 *Message, | |
IN UINTN ErrorLevel, | |
IN REDFISH_RESPONSE *Response | |
) | |
{ | |
UINTN Index; | |
if (Response == NULL) { | |
return EFI_INVALID_PARAMETER; | |
} | |
if (!IS_EMPTY_STRING (Message)) { | |
DEBUG ((ErrorLevel, "%a\n", Message)); | |
} | |
// | |
// status code | |
// | |
if (Response->StatusCode != NULL) { | |
DumpHttpStatusCode (ErrorLevel, *(Response->StatusCode)); | |
} | |
// | |
// header | |
// | |
if (Response->HeaderCount > 0) { | |
DEBUG ((ErrorLevel, "Header: %d\n", Response->HeaderCount)); | |
for (Index = 0; Index < Response->HeaderCount; Index++) { | |
DEBUG ((ErrorLevel, " %a: %a\n", Response->Headers[Index].FieldName, Response->Headers[Index].FieldValue)); | |
} | |
} | |
// | |
// Body | |
// | |
if (Response->Payload != NULL) { | |
DumpRedfishPayload (ErrorLevel, Response->Payload); | |
} | |
return EFI_SUCCESS; | |
} | |
/** | |
This function dump the IPv4 address in given error level. | |
@param[in] ErrorLevel DEBUG macro error level | |
@param[in] Ipv4Address IPv4 address to dump | |
@retval EFI_SUCCESS IPv4 address string is printed. | |
@retval Others Errors occur. | |
**/ | |
EFI_STATUS | |
DumpIpv4Address ( | |
IN UINTN ErrorLevel, | |
IN EFI_IPv4_ADDRESS *Ipv4Address | |
) | |
{ | |
if (Ipv4Address == NULL) { | |
return EFI_INVALID_PARAMETER; | |
} | |
DEBUG ((ErrorLevel, "%d.%d.%d.%d\n", Ipv4Address->Addr[0], Ipv4Address->Addr[1], Ipv4Address->Addr[2], Ipv4Address->Addr[3])); | |
return EFI_SUCCESS; | |
} | |
/** | |
Debug output raw data buffer. | |
@param[in] ErrorLevel DEBUG macro error level | |
@param[in] Buffer Debug output data buffer. | |
@param[in] BufferSize The size of Buffer in byte. | |
@retval EFI_SUCCESS Debug dump finished. | |
@retval EFI_INVALID_PARAMETER Buffer is NULL. | |
**/ | |
EFI_STATUS | |
DumpBuffer ( | |
IN UINTN ErrorLevel, | |
IN UINT8 *Buffer, | |
IN UINTN BufferSize | |
) | |
{ | |
UINTN Index; | |
if (Buffer == NULL) { | |
return EFI_INVALID_PARAMETER; | |
} | |
DEBUG ((ErrorLevel, "Address: 0x%p size: %d\n", Buffer, BufferSize)); | |
for (Index = 0; Index < BufferSize; Index++) { | |
if (Index % REDFISH_PRINT_BUFFER_BYTES_PER_ROW == 0) { | |
DEBUG ((ErrorLevel, "\n%04X: ", Index)); | |
} | |
DEBUG ((ErrorLevel, "%02X ", Buffer[Index])); | |
} | |
DEBUG ((ErrorLevel, "\n")); | |
return EFI_SUCCESS; | |
} |