mirror of https://github.com/acidanthera/audk.git
RedfishPkg: implement Redfish HTTP protocol
implement Redfish HTTP protocol driver. Signed-off-by: Nickle Wang <nicklew@nvidia.com> Co-authored-by: Igor Kulchytskyy <igork@ami.com> Cc: Abner Chang <abner.chang@amd.com> Cc: Igor Kulchytskyy <igork@ami.com> Cc: Nick Ramirez <nramirez@nvidia.com> Reviewed-by: Abner Chang <abner.chang@amd.com> Reviewed-by: Igor Kulchytskyy <igork@ami.com> Reviewed-by: Mike Maslenkin <mike.maslenkin@gmail.com>
This commit is contained in:
parent
1988f2df29
commit
0ce2012c6c
|
@ -6,7 +6,7 @@
|
||||||
# to be built in the firmware volume.
|
# to be built in the firmware volume.
|
||||||
#
|
#
|
||||||
# (C) Copyright 2020-2021 Hewlett Packard Enterprise Development LP<BR>
|
# (C) Copyright 2020-2021 Hewlett Packard Enterprise Development LP<BR>
|
||||||
# Copyright (c) 2023, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
# Copyright (c) 2023-2024, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||||
#
|
#
|
||||||
# SPDX-License-Identifier: BSD-2-Clause-Patent
|
# SPDX-License-Identifier: BSD-2-Clause-Patent
|
||||||
#
|
#
|
||||||
|
@ -20,4 +20,5 @@
|
||||||
INF RedfishPkg/RedfishConfigHandler/RedfishConfigHandlerDriver.inf
|
INF RedfishPkg/RedfishConfigHandler/RedfishConfigHandlerDriver.inf
|
||||||
INF RedfishPkg/RedfishPlatformConfigDxe/RedfishPlatformConfigDxe.inf
|
INF RedfishPkg/RedfishPlatformConfigDxe/RedfishPlatformConfigDxe.inf
|
||||||
INF MdeModulePkg/Universal/RegularExpressionDxe/RegularExpressionDxe.inf
|
INF MdeModulePkg/Universal/RegularExpressionDxe/RegularExpressionDxe.inf
|
||||||
|
INF RedfishPkg/RedfishHttpDxe/RedfishHttpDxe.inf
|
||||||
!endif
|
!endif
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
# "RedfishDefines.dsc.inc".
|
# "RedfishDefines.dsc.inc".
|
||||||
#
|
#
|
||||||
# (C) Copyright 2020-2021 Hewlett Packard Enterprise Development LP<BR>
|
# (C) Copyright 2020-2021 Hewlett Packard Enterprise Development LP<BR>
|
||||||
# Copyright (c) 2023, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
# Copyright (c) 2023-2024, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||||
#
|
#
|
||||||
# SPDX-License-Identifier: BSD-2-Clause-Patent
|
# SPDX-License-Identifier: BSD-2-Clause-Patent
|
||||||
#
|
#
|
||||||
|
@ -28,4 +28,5 @@
|
||||||
RedfishPkg/RedfishConfigHandler/RedfishConfigHandlerDriver.inf
|
RedfishPkg/RedfishConfigHandler/RedfishConfigHandlerDriver.inf
|
||||||
RedfishPkg/RedfishPlatformConfigDxe/RedfishPlatformConfigDxe.inf
|
RedfishPkg/RedfishPlatformConfigDxe/RedfishPlatformConfigDxe.inf
|
||||||
MdeModulePkg/Universal/RegularExpressionDxe/RegularExpressionDxe.inf
|
MdeModulePkg/Universal/RegularExpressionDxe/RegularExpressionDxe.inf
|
||||||
|
RedfishPkg/RedfishHttpDxe/RedfishHttpDxe.inf
|
||||||
!endif
|
!endif
|
||||||
|
|
|
@ -0,0 +1,667 @@
|
||||||
|
/** @file
|
||||||
|
RedfishHttpData handles internal data to support Redfish HTTP protocol.
|
||||||
|
|
||||||
|
Copyright (c) 2023-2024, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||||
|
|
||||||
|
SPDX-License-Identifier: BSD-2-Clause-Patent
|
||||||
|
|
||||||
|
**/
|
||||||
|
|
||||||
|
#include "RedfishHttpData.h"
|
||||||
|
#include "RedfishHttpOperation.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
This function update session token in Redfish Service.
|
||||||
|
|
||||||
|
@param[in] Service Pointer to service instance.
|
||||||
|
@param[in] Token Session token.
|
||||||
|
|
||||||
|
@retval EFI_SUCCESS Session token is updated.
|
||||||
|
@retval Others Error occurs.
|
||||||
|
|
||||||
|
**/
|
||||||
|
EFI_STATUS
|
||||||
|
UpdateSessionToken (
|
||||||
|
IN REDFISH_SERVICE_PRIVATE *Service,
|
||||||
|
IN CHAR8 *Token
|
||||||
|
)
|
||||||
|
{
|
||||||
|
if ((Service == NULL) || IS_EMPTY_STRING (Token)) {
|
||||||
|
return EFI_INVALID_PARAMETER;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Service->SessionToken != NULL) {
|
||||||
|
FreePool (Service->SessionToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
Service->SessionToken = ASCII_STR_DUPLICATE (Token);
|
||||||
|
if (Service->SessionToken == NULL) {
|
||||||
|
return EFI_OUT_OF_RESOURCES;
|
||||||
|
}
|
||||||
|
|
||||||
|
return EFI_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
This function release Redfish Service.
|
||||||
|
|
||||||
|
@param[in] Service Pointer to service instance.
|
||||||
|
|
||||||
|
@retval EFI_SUCCESS Service is released.
|
||||||
|
@retval Others Error occurs.
|
||||||
|
|
||||||
|
**/
|
||||||
|
EFI_STATUS
|
||||||
|
ReleaseRedfishService (
|
||||||
|
IN REDFISH_SERVICE_PRIVATE *Service
|
||||||
|
)
|
||||||
|
{
|
||||||
|
if (Service == NULL) {
|
||||||
|
return EFI_INVALID_PARAMETER;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Service->Host != NULL) {
|
||||||
|
FreePool (Service->Host);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Service->HostName != NULL) {
|
||||||
|
FreePool (Service->HostName);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Service->BasicAuth != NULL) {
|
||||||
|
ZeroMem (Service->BasicAuth, AsciiStrSize (Service->BasicAuth));
|
||||||
|
FreePool (Service->BasicAuth);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Service->SessionToken != NULL) {
|
||||||
|
ZeroMem (Service->SessionToken, AsciiStrSize (Service->SessionToken));
|
||||||
|
FreePool (Service->SessionToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
FreePool (Service);
|
||||||
|
|
||||||
|
return EFI_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
This function creat new service. Host and HostName are copied to
|
||||||
|
newly created service instance.
|
||||||
|
|
||||||
|
@param[in] Host Host string.
|
||||||
|
@param[in] HostName Hostname string.
|
||||||
|
@param[in] BasicAuth Basic Authorization string.
|
||||||
|
@param[in] SessionToken Session token string.
|
||||||
|
@param[in] RestEx Rest EX protocol instance.
|
||||||
|
|
||||||
|
@retval REDFISH_PAYLOAD_PRIVATE Newly created service.
|
||||||
|
@retval NULL Error occurs.
|
||||||
|
|
||||||
|
**/
|
||||||
|
REDFISH_SERVICE_PRIVATE *
|
||||||
|
CreateRedfishService (
|
||||||
|
IN CHAR8 *Host,
|
||||||
|
IN CHAR8 *HostName,
|
||||||
|
IN CHAR8 *BasicAuth OPTIONAL,
|
||||||
|
IN CHAR8 *SessionToken OPTIONAL,
|
||||||
|
IN EFI_REST_EX_PROTOCOL *RestEx
|
||||||
|
)
|
||||||
|
{
|
||||||
|
REDFISH_SERVICE_PRIVATE *NewService;
|
||||||
|
UINTN AuthStrSize;
|
||||||
|
|
||||||
|
if (IS_EMPTY_STRING (Host) || IS_EMPTY_STRING (HostName) || (RestEx == NULL)) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
NewService = AllocateZeroPool (sizeof (REDFISH_SERVICE_PRIVATE));
|
||||||
|
if (NewService == NULL) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
NewService->Signature = REDFISH_HTTP_SERVICE_SIGNATURE;
|
||||||
|
NewService->Host = ASCII_STR_DUPLICATE (Host);
|
||||||
|
if (NewService->Host == NULL) {
|
||||||
|
goto ON_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
NewService->HostName = ASCII_STR_DUPLICATE (HostName);
|
||||||
|
if (NewService->HostName == NULL) {
|
||||||
|
goto ON_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!IS_EMPTY_STRING (BasicAuth)) {
|
||||||
|
AuthStrSize = AsciiStrSize (BasicAuth) + AsciiStrLen (REDFISH_HTTP_BASIC_AUTH_STR);
|
||||||
|
NewService->BasicAuth = AllocateZeroPool (AuthStrSize);
|
||||||
|
if (NewService->BasicAuth == NULL) {
|
||||||
|
goto ON_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
AsciiSPrint (NewService->BasicAuth, AuthStrSize, "%a%a", REDFISH_HTTP_BASIC_AUTH_STR, BasicAuth);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!IS_EMPTY_STRING (SessionToken)) {
|
||||||
|
NewService->SessionToken = ASCII_STR_DUPLICATE (SessionToken);
|
||||||
|
if (NewService->SessionToken == NULL) {
|
||||||
|
goto ON_ERROR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
NewService->RestEx = RestEx;
|
||||||
|
|
||||||
|
return NewService;
|
||||||
|
|
||||||
|
ON_ERROR:
|
||||||
|
|
||||||
|
ReleaseRedfishService (NewService);
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
This function release Redfish Payload.
|
||||||
|
|
||||||
|
@param[in] Payload Pointer to payload instance.
|
||||||
|
|
||||||
|
@retval EFI_SUCCESS Payload is released.
|
||||||
|
@retval Others Error occurs.
|
||||||
|
|
||||||
|
**/
|
||||||
|
EFI_STATUS
|
||||||
|
ReleaseRedfishPayload (
|
||||||
|
IN REDFISH_PAYLOAD_PRIVATE *Payload
|
||||||
|
)
|
||||||
|
{
|
||||||
|
if (Payload == NULL) {
|
||||||
|
return EFI_INVALID_PARAMETER;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Payload->Service != NULL) {
|
||||||
|
ReleaseRedfishService (Payload->Service);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Payload->JsonValue != NULL) {
|
||||||
|
JsonValueFree (Payload->JsonValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
FreePool (Payload);
|
||||||
|
|
||||||
|
return EFI_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
This function creat new payload. Server and JsonObj are
|
||||||
|
copied to newly created payload.
|
||||||
|
|
||||||
|
@param[in] Service Pointer to Service instance.
|
||||||
|
@param[in] JsonValue Pointer to JSON value.
|
||||||
|
|
||||||
|
@retval REDFISH_PAYLOAD_PRIVATE Newly created payload.
|
||||||
|
@retval NULL Error occurs.
|
||||||
|
|
||||||
|
**/
|
||||||
|
REDFISH_PAYLOAD_PRIVATE *
|
||||||
|
CreateRedfishPayload (
|
||||||
|
IN REDFISH_SERVICE_PRIVATE *Service,
|
||||||
|
IN EDKII_JSON_VALUE JsonValue
|
||||||
|
)
|
||||||
|
{
|
||||||
|
REDFISH_PAYLOAD_PRIVATE *NewPayload;
|
||||||
|
|
||||||
|
if ((Service == NULL) || (JsonValue == NULL)) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
NewPayload = AllocateZeroPool (sizeof (REDFISH_PAYLOAD_PRIVATE));
|
||||||
|
if (NewPayload == NULL) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
NewPayload->Signature = REDFISH_HTTP_PAYLOAD_SIGNATURE;
|
||||||
|
NewPayload->Service = CreateRedfishService (Service->Host, Service->HostName, Service->BasicAuth, Service->SessionToken, Service->RestEx);
|
||||||
|
if (NewPayload->Service == NULL) {
|
||||||
|
goto ON_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
NewPayload->JsonValue = JsonValueClone (JsonValue);
|
||||||
|
if (NewPayload->JsonValue == NULL) {
|
||||||
|
goto ON_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NewPayload;
|
||||||
|
|
||||||
|
ON_ERROR:
|
||||||
|
|
||||||
|
ReleaseRedfishPayload (NewPayload);
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
This function copy the data in SrcResponse to DstResponse.
|
||||||
|
|
||||||
|
@param[in] SrcResponse Source Response to copy.
|
||||||
|
@param[out] DstResponse Destination Response.
|
||||||
|
|
||||||
|
@retval EFI_SUCCESS Response is copied successfully.
|
||||||
|
@retval Others Error occurs.
|
||||||
|
|
||||||
|
**/
|
||||||
|
EFI_STATUS
|
||||||
|
CopyRedfishResponse (
|
||||||
|
IN REDFISH_RESPONSE *SrcResponse,
|
||||||
|
OUT REDFISH_RESPONSE *DstResponse
|
||||||
|
)
|
||||||
|
{
|
||||||
|
REDFISH_PAYLOAD_PRIVATE *Payload;
|
||||||
|
UINTN Index;
|
||||||
|
|
||||||
|
if ((SrcResponse == NULL) || (DstResponse == NULL)) {
|
||||||
|
return EFI_INVALID_PARAMETER;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (SrcResponse == DstResponse) {
|
||||||
|
return EFI_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Status code
|
||||||
|
//
|
||||||
|
if (SrcResponse->StatusCode != NULL) {
|
||||||
|
DstResponse->StatusCode = AllocateCopyPool (sizeof (EFI_HTTP_STATUS_CODE), SrcResponse->StatusCode);
|
||||||
|
if (DstResponse->StatusCode == NULL) {
|
||||||
|
goto ON_ERROR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Header
|
||||||
|
//
|
||||||
|
if ((SrcResponse->HeaderCount > 0) && (SrcResponse->Headers != NULL)) {
|
||||||
|
DstResponse->HeaderCount = 0;
|
||||||
|
DstResponse->Headers = AllocateZeroPool (sizeof (EFI_HTTP_HEADER) * SrcResponse->HeaderCount);
|
||||||
|
if (DstResponse->Headers == NULL) {
|
||||||
|
goto ON_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
DstResponse->HeaderCount = SrcResponse->HeaderCount;
|
||||||
|
|
||||||
|
for (Index = 0; Index < SrcResponse->HeaderCount; Index++) {
|
||||||
|
DstResponse->Headers[Index].FieldName = ASCII_STR_DUPLICATE (SrcResponse->Headers[Index].FieldName);
|
||||||
|
if (DstResponse->Headers[Index].FieldName == NULL) {
|
||||||
|
goto ON_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
DstResponse->Headers[Index].FieldValue = ASCII_STR_DUPLICATE (SrcResponse->Headers[Index].FieldValue);
|
||||||
|
if (DstResponse->Headers[Index].FieldValue == NULL) {
|
||||||
|
goto ON_ERROR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Payload
|
||||||
|
//
|
||||||
|
if (SrcResponse->Payload != NULL) {
|
||||||
|
Payload = (REDFISH_PAYLOAD_PRIVATE *)SrcResponse->Payload;
|
||||||
|
if (Payload->Signature != REDFISH_HTTP_PAYLOAD_SIGNATURE) {
|
||||||
|
DEBUG ((DEBUG_ERROR, "%a: signature check failure\n", __func__));
|
||||||
|
goto ON_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
DstResponse->Payload = CreateRedfishPayload (Payload->Service, Payload->JsonValue);
|
||||||
|
if (DstResponse->Payload == NULL) {
|
||||||
|
goto ON_ERROR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return EFI_SUCCESS;
|
||||||
|
|
||||||
|
ON_ERROR:
|
||||||
|
|
||||||
|
ReleaseRedfishResponse (DstResponse);
|
||||||
|
|
||||||
|
return EFI_OUT_OF_RESOURCES;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
This function clone input response and return to caller
|
||||||
|
|
||||||
|
@param[in] Response Response to clone.
|
||||||
|
|
||||||
|
@retval REDFISH_RESPONSE * Response is cloned.
|
||||||
|
@retval NULL Errors occur.
|
||||||
|
|
||||||
|
**/
|
||||||
|
REDFISH_RESPONSE *
|
||||||
|
CloneRedfishResponse (
|
||||||
|
IN REDFISH_RESPONSE *Response
|
||||||
|
)
|
||||||
|
{
|
||||||
|
EFI_STATUS Status;
|
||||||
|
REDFISH_RESPONSE *NewResponse;
|
||||||
|
|
||||||
|
if (Response == NULL) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
NewResponse = AllocateZeroPool (sizeof (REDFISH_RESPONSE));
|
||||||
|
if (NewResponse == NULL) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
Status = CopyRedfishResponse (Response, NewResponse);
|
||||||
|
if (EFI_ERROR (Status)) {
|
||||||
|
FreePool (NewResponse);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NewResponse;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Release REDFISH_HTTP_CACHE_DATA resource
|
||||||
|
|
||||||
|
@param[in] Data Pointer to REDFISH_HTTP_CACHE_DATA instance
|
||||||
|
|
||||||
|
@retval EFI_SUCCESS REDFISH_HTTP_CACHE_DATA is released successfully.
|
||||||
|
@retval EFI_INVALID_PARAMETER Data is NULL
|
||||||
|
|
||||||
|
**/
|
||||||
|
EFI_STATUS
|
||||||
|
ReleaseHttpCacheData (
|
||||||
|
IN REDFISH_HTTP_CACHE_DATA *Data
|
||||||
|
)
|
||||||
|
{
|
||||||
|
if (Data == NULL) {
|
||||||
|
return EFI_INVALID_PARAMETER;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Data->Uri != NULL) {
|
||||||
|
FreePool (Data->Uri);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Data->Response != NULL) {
|
||||||
|
ReleaseRedfishResponse (Data->Response);
|
||||||
|
FreePool (Data->Response);
|
||||||
|
}
|
||||||
|
|
||||||
|
FreePool (Data);
|
||||||
|
|
||||||
|
return EFI_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Create new cache data.
|
||||||
|
|
||||||
|
@param[in] Uri The URI string matching to this cache data.
|
||||||
|
@param[in] Response HTTP response.
|
||||||
|
|
||||||
|
@retval REDFISH_HTTP_CACHE_DATA * Pointer to newly created cache data.
|
||||||
|
@retval NULL No memory available.
|
||||||
|
|
||||||
|
**/
|
||||||
|
REDFISH_HTTP_CACHE_DATA *
|
||||||
|
NewHttpCacheData (
|
||||||
|
IN EFI_STRING Uri,
|
||||||
|
IN REDFISH_RESPONSE *Response
|
||||||
|
)
|
||||||
|
{
|
||||||
|
REDFISH_HTTP_CACHE_DATA *NewData;
|
||||||
|
UINTN Size;
|
||||||
|
|
||||||
|
if (IS_EMPTY_STRING (Uri) || (Response == NULL)) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
NewData = AllocateZeroPool (sizeof (REDFISH_HTTP_CACHE_DATA));
|
||||||
|
if (NewData == NULL) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
NewData->Signature = REDFISH_HTTP_CACHE_SIGNATURE;
|
||||||
|
Size = StrSize (Uri);
|
||||||
|
NewData->Uri = AllocateCopyPool (Size, Uri);
|
||||||
|
if (NewData->Uri == NULL) {
|
||||||
|
goto ON_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
NewData->Response = Response;
|
||||||
|
NewData->HitCount = 1;
|
||||||
|
|
||||||
|
return NewData;
|
||||||
|
|
||||||
|
ON_ERROR:
|
||||||
|
|
||||||
|
if (NewData != NULL) {
|
||||||
|
ReleaseHttpCacheData (NewData);
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Search on given ListHeader for given URI string.
|
||||||
|
|
||||||
|
@param[in] ListHeader Target list to search.
|
||||||
|
@param[in] Uri Target URI to search.
|
||||||
|
|
||||||
|
@retval REDFISH_HTTP_CACHE_DATA Target cache data is found.
|
||||||
|
@retval NULL No cache data with given URI is found.
|
||||||
|
|
||||||
|
**/
|
||||||
|
REDFISH_HTTP_CACHE_DATA *
|
||||||
|
FindHttpCacheData (
|
||||||
|
IN LIST_ENTRY *ListHeader,
|
||||||
|
IN EFI_STRING Uri
|
||||||
|
)
|
||||||
|
{
|
||||||
|
LIST_ENTRY *List;
|
||||||
|
REDFISH_HTTP_CACHE_DATA *Data;
|
||||||
|
|
||||||
|
if (IS_EMPTY_STRING (Uri)) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (IsListEmpty (ListHeader)) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
Data = NULL;
|
||||||
|
List = GetFirstNode (ListHeader);
|
||||||
|
while (!IsNull (ListHeader, List)) {
|
||||||
|
Data = REDFISH_HTTP_CACHE_FROM_LIST (List);
|
||||||
|
|
||||||
|
if (StrCmp (Data->Uri, Uri) == 0) {
|
||||||
|
return Data;
|
||||||
|
}
|
||||||
|
|
||||||
|
List = GetNextNode (ListHeader, List);
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Search on given ListHeader and return cache data with minimum hit count.
|
||||||
|
|
||||||
|
@param[in] ListHeader Target list to search.
|
||||||
|
|
||||||
|
@retval REDFISH_HTTP_CACHE_DATA Target cache data is returned.
|
||||||
|
@retval NULL No cache data is found.
|
||||||
|
|
||||||
|
**/
|
||||||
|
REDFISH_HTTP_CACHE_DATA *
|
||||||
|
FindUnusedHttpCacheData (
|
||||||
|
IN LIST_ENTRY *ListHeader
|
||||||
|
)
|
||||||
|
{
|
||||||
|
LIST_ENTRY *List;
|
||||||
|
REDFISH_HTTP_CACHE_DATA *Data;
|
||||||
|
REDFISH_HTTP_CACHE_DATA *UnusedData;
|
||||||
|
UINTN HitCount;
|
||||||
|
|
||||||
|
if (IsListEmpty (ListHeader)) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
Data = NULL;
|
||||||
|
UnusedData = NULL;
|
||||||
|
HitCount = 0;
|
||||||
|
|
||||||
|
List = GetFirstNode (ListHeader);
|
||||||
|
Data = REDFISH_HTTP_CACHE_FROM_LIST (List);
|
||||||
|
UnusedData = Data;
|
||||||
|
HitCount = Data->HitCount;
|
||||||
|
List = GetNextNode (ListHeader, List);
|
||||||
|
|
||||||
|
while (!IsNull (ListHeader, List)) {
|
||||||
|
Data = REDFISH_HTTP_CACHE_FROM_LIST (List);
|
||||||
|
|
||||||
|
if (Data->HitCount < HitCount) {
|
||||||
|
HitCount = Data->HitCount;
|
||||||
|
UnusedData = Data;
|
||||||
|
}
|
||||||
|
|
||||||
|
List = GetNextNode (ListHeader, List);
|
||||||
|
}
|
||||||
|
|
||||||
|
return UnusedData;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Delete a cache data by given cache instance.
|
||||||
|
|
||||||
|
@param[in] List Target cache list to be removed.
|
||||||
|
@param[in] Data Pointer to the instance to be deleted.
|
||||||
|
|
||||||
|
@retval EFI_SUCCESS Cache data is removed.
|
||||||
|
@retval Others Fail to remove cache data.
|
||||||
|
|
||||||
|
**/
|
||||||
|
EFI_STATUS
|
||||||
|
DeleteHttpCacheData (
|
||||||
|
IN REDFISH_HTTP_CACHE_LIST *List,
|
||||||
|
IN REDFISH_HTTP_CACHE_DATA *Data
|
||||||
|
)
|
||||||
|
{
|
||||||
|
if ((List == NULL) || (Data == NULL)) {
|
||||||
|
return EFI_INVALID_PARAMETER;
|
||||||
|
}
|
||||||
|
|
||||||
|
DEBUG ((REDFISH_HTTP_CACHE_DEBUG, "%a: delete: %s\n", __func__, Data->Uri));
|
||||||
|
|
||||||
|
RemoveEntryList (&Data->List);
|
||||||
|
--List->Count;
|
||||||
|
|
||||||
|
return ReleaseHttpCacheData (Data);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Add new cache by given URI and HTTP response to specify List.
|
||||||
|
|
||||||
|
@param[in] List Target cache list to add.
|
||||||
|
@param[in] Uri The URI string matching to this cache data.
|
||||||
|
@param[in] Response HTTP response.
|
||||||
|
|
||||||
|
@retval EFI_SUCCESS Cache data is added.
|
||||||
|
@retval Others Fail to add cache data.
|
||||||
|
|
||||||
|
**/
|
||||||
|
EFI_STATUS
|
||||||
|
AddHttpCacheData (
|
||||||
|
IN REDFISH_HTTP_CACHE_LIST *List,
|
||||||
|
IN EFI_STRING Uri,
|
||||||
|
IN REDFISH_RESPONSE *Response
|
||||||
|
)
|
||||||
|
{
|
||||||
|
REDFISH_HTTP_CACHE_DATA *NewData;
|
||||||
|
REDFISH_HTTP_CACHE_DATA *OldData;
|
||||||
|
REDFISH_HTTP_CACHE_DATA *UnusedData;
|
||||||
|
REDFISH_RESPONSE *NewResponse;
|
||||||
|
|
||||||
|
if ((List == NULL) || IS_EMPTY_STRING (Uri) || (Response == NULL)) {
|
||||||
|
return EFI_INVALID_PARAMETER;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// If same cache data exist, replace it with latest one.
|
||||||
|
//
|
||||||
|
OldData = FindHttpCacheData (&List->Head, Uri);
|
||||||
|
if (OldData != NULL) {
|
||||||
|
DeleteHttpCacheData (List, OldData);
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Check capacity
|
||||||
|
//
|
||||||
|
if (List->Count >= List->Capacity) {
|
||||||
|
DEBUG ((REDFISH_HTTP_CACHE_DEBUG, "%a: list is full and retire unused cache\n", __func__));
|
||||||
|
UnusedData = FindUnusedHttpCacheData (&List->Head);
|
||||||
|
if (UnusedData == NULL) {
|
||||||
|
return EFI_OUT_OF_RESOURCES;
|
||||||
|
}
|
||||||
|
|
||||||
|
DeleteHttpCacheData (List, UnusedData);
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Clone a local copy
|
||||||
|
//
|
||||||
|
NewResponse = CloneRedfishResponse (Response);
|
||||||
|
if (NewResponse == NULL) {
|
||||||
|
return EFI_OUT_OF_RESOURCES;
|
||||||
|
}
|
||||||
|
|
||||||
|
NewData = NewHttpCacheData (Uri, NewResponse);
|
||||||
|
if (NewData == NULL) {
|
||||||
|
return EFI_OUT_OF_RESOURCES;
|
||||||
|
}
|
||||||
|
|
||||||
|
InsertTailList (&List->Head, &NewData->List);
|
||||||
|
++List->Count;
|
||||||
|
|
||||||
|
DEBUG ((REDFISH_HTTP_CACHE_DEBUG, "%a: cache(%d/%d) %s\n", __func__, List->Count, List->Capacity, NewData->Uri));
|
||||||
|
|
||||||
|
return EFI_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Release all cache from list.
|
||||||
|
|
||||||
|
@param[in] CacheList The list to be released.
|
||||||
|
|
||||||
|
@retval EFI_SUCCESS All cache data are released.
|
||||||
|
@retval EFI_INVALID_PARAMETER CacheList is NULL.
|
||||||
|
|
||||||
|
**/
|
||||||
|
EFI_STATUS
|
||||||
|
ReleaseCacheList (
|
||||||
|
IN REDFISH_HTTP_CACHE_LIST *CacheList
|
||||||
|
)
|
||||||
|
{
|
||||||
|
LIST_ENTRY *List;
|
||||||
|
LIST_ENTRY *Next;
|
||||||
|
REDFISH_HTTP_CACHE_DATA *Data;
|
||||||
|
|
||||||
|
if (CacheList == NULL) {
|
||||||
|
return EFI_INVALID_PARAMETER;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (IsListEmpty (&CacheList->Head)) {
|
||||||
|
return EFI_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
Data = NULL;
|
||||||
|
Next = NULL;
|
||||||
|
List = GetFirstNode (&CacheList->Head);
|
||||||
|
while (!IsNull (&CacheList->Head, List)) {
|
||||||
|
Data = REDFISH_HTTP_CACHE_FROM_LIST (List);
|
||||||
|
Next = GetNextNode (&CacheList->Head, List);
|
||||||
|
|
||||||
|
DeleteHttpCacheData (CacheList, Data);
|
||||||
|
|
||||||
|
List = Next;
|
||||||
|
}
|
||||||
|
|
||||||
|
return EFI_SUCCESS;
|
||||||
|
}
|
|
@ -0,0 +1,256 @@
|
||||||
|
/** @file
|
||||||
|
Definitions of RedfishHttpData
|
||||||
|
|
||||||
|
Copyright (c) 2023-2024, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||||
|
|
||||||
|
SPDX-License-Identifier: BSD-2-Clause-Patent
|
||||||
|
|
||||||
|
**/
|
||||||
|
|
||||||
|
#ifndef EDKII_REDFISH_HTTP_DATA_H_
|
||||||
|
#define EDKII_REDFISH_HTTP_DATA_H_
|
||||||
|
|
||||||
|
#include "RedfishHttpDxe.h"
|
||||||
|
|
||||||
|
#define REDFISH_HTTP_DRIVER_SIGNATURE SIGNATURE_32 ('r', 'f', 'h', 'p')
|
||||||
|
#define REDFISH_HTTP_CACHE_SIGNATURE SIGNATURE_32 ('r', 'f', 'c', 'h')
|
||||||
|
#define REDFISH_HTTP_SERVICE_SIGNATURE SIGNATURE_32 ('r', 'f', 's', 'v')
|
||||||
|
#define REDFISH_HTTP_PAYLOAD_SIGNATURE SIGNATURE_32 ('r', 'f', 'p', 'l')
|
||||||
|
#define REDFISH_HTTP_BASIC_AUTH_STR "Basic "
|
||||||
|
|
||||||
|
///
|
||||||
|
/// REDFISH_SERVICE_PRIVATE definition.
|
||||||
|
///
|
||||||
|
typedef struct {
|
||||||
|
UINT32 Signature;
|
||||||
|
CHAR8 *Host;
|
||||||
|
CHAR8 *HostName;
|
||||||
|
CHAR8 *BasicAuth;
|
||||||
|
CHAR8 *SessionToken;
|
||||||
|
EFI_REST_EX_PROTOCOL *RestEx;
|
||||||
|
} REDFISH_SERVICE_PRIVATE;
|
||||||
|
|
||||||
|
///
|
||||||
|
/// REDFISH_PAYLOAD_PRIVATE definition.
|
||||||
|
///
|
||||||
|
typedef struct {
|
||||||
|
UINT32 Signature;
|
||||||
|
REDFISH_SERVICE_PRIVATE *Service;
|
||||||
|
EDKII_JSON_VALUE JsonValue;
|
||||||
|
} REDFISH_PAYLOAD_PRIVATE;
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Definition of REDFISH_HTTP_CACHE_DATA
|
||||||
|
///
|
||||||
|
typedef struct {
|
||||||
|
UINT32 Signature;
|
||||||
|
LIST_ENTRY List;
|
||||||
|
EFI_STRING Uri;
|
||||||
|
UINTN HitCount;
|
||||||
|
REDFISH_RESPONSE *Response;
|
||||||
|
} REDFISH_HTTP_CACHE_DATA;
|
||||||
|
|
||||||
|
#define REDFISH_HTTP_CACHE_FROM_LIST(a) CR (a, REDFISH_HTTP_CACHE_DATA, List, REDFISH_HTTP_CACHE_SIGNATURE)
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Definition of REDFISH_HTTP_CACHE_LIST
|
||||||
|
///
|
||||||
|
typedef struct {
|
||||||
|
LIST_ENTRY Head;
|
||||||
|
UINTN Count;
|
||||||
|
UINTN Capacity;
|
||||||
|
} REDFISH_HTTP_CACHE_LIST;
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Definition of REDFISH_HTTP_RETRY_SETTING
|
||||||
|
///
|
||||||
|
typedef struct {
|
||||||
|
UINT16 MaximumRetryGet;
|
||||||
|
UINT16 MaximumRetryPut;
|
||||||
|
UINT16 MaximumRetryPost;
|
||||||
|
UINT16 MaximumRetryPatch;
|
||||||
|
UINT16 MaximumRetryDelete;
|
||||||
|
UINTN RetryWait;
|
||||||
|
} REDFISH_HTTP_RETRY_SETTING;
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Definition of REDFISH_HTTP_CACHE_PRIVATE
|
||||||
|
///
|
||||||
|
typedef struct {
|
||||||
|
UINT32 Signature;
|
||||||
|
EFI_HANDLE ImageHandle;
|
||||||
|
BOOLEAN CacheDisabled;
|
||||||
|
EFI_EVENT NotifyEvent;
|
||||||
|
REDFISH_HTTP_CACHE_LIST CacheList;
|
||||||
|
EDKII_REDFISH_HTTP_PROTOCOL Protocol;
|
||||||
|
EDKII_REDFISH_CREDENTIAL_PROTOCOL *CredentialProtocol;
|
||||||
|
REDFISH_HTTP_RETRY_SETTING RetrySetting;
|
||||||
|
} REDFISH_HTTP_CACHE_PRIVATE;
|
||||||
|
|
||||||
|
#define REDFISH_HTTP_CACHE_PRIVATE_FROM_THIS(a) CR (a, REDFISH_HTTP_CACHE_PRIVATE, Protocol, REDFISH_HTTP_DRIVER_SIGNATURE)
|
||||||
|
|
||||||
|
/**
|
||||||
|
Search on given ListHeader for given URI string.
|
||||||
|
|
||||||
|
@param[in] ListHeader Target list to search.
|
||||||
|
@param[in] Uri Target URI to search.
|
||||||
|
|
||||||
|
@retval REDFISH_HTTP_CACHE_DATA Target cache data is found.
|
||||||
|
@retval NULL No cache data with given URI is found.
|
||||||
|
|
||||||
|
**/
|
||||||
|
REDFISH_HTTP_CACHE_DATA *
|
||||||
|
FindHttpCacheData (
|
||||||
|
IN LIST_ENTRY *ListHeader,
|
||||||
|
IN EFI_STRING Uri
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
This function copy the data in SrcResponse to DstResponse.
|
||||||
|
|
||||||
|
@param[in] SrcResponse Source Response to copy.
|
||||||
|
@param[out] DstResponse Destination Response.
|
||||||
|
|
||||||
|
@retval EFI_SUCCESS Response is copied successfully.
|
||||||
|
@retval Others Error occurs.
|
||||||
|
|
||||||
|
**/
|
||||||
|
EFI_STATUS
|
||||||
|
CopyRedfishResponse (
|
||||||
|
IN REDFISH_RESPONSE *SrcResponse,
|
||||||
|
OUT REDFISH_RESPONSE *DstResponse
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
Release all cache from list.
|
||||||
|
|
||||||
|
@param[in] CacheList The list to be released.
|
||||||
|
|
||||||
|
@retval EFI_SUCCESS All cache data are released.
|
||||||
|
@retval EFI_INVALID_PARAMETER CacheList is NULL.
|
||||||
|
|
||||||
|
**/
|
||||||
|
EFI_STATUS
|
||||||
|
ReleaseCacheList (
|
||||||
|
IN REDFISH_HTTP_CACHE_LIST *CacheList
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
Add new cache by given URI and HTTP response to specify List.
|
||||||
|
|
||||||
|
@param[in] List Target cache list to add.
|
||||||
|
@param[in] Uri The URI string matching to this cache data.
|
||||||
|
@param[in] Response HTTP response.
|
||||||
|
|
||||||
|
@retval EFI_SUCCESS Cache data is added.
|
||||||
|
@retval Others Fail to add cache data.
|
||||||
|
|
||||||
|
**/
|
||||||
|
EFI_STATUS
|
||||||
|
AddHttpCacheData (
|
||||||
|
IN REDFISH_HTTP_CACHE_LIST *List,
|
||||||
|
IN EFI_STRING Uri,
|
||||||
|
IN REDFISH_RESPONSE *Response
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
Delete a cache data by given cache instance.
|
||||||
|
|
||||||
|
@param[in] List Target cache list to be removed.
|
||||||
|
@param[in] Data Pointer to the instance to be deleted.
|
||||||
|
|
||||||
|
@retval EFI_SUCCESS Cache data is removed.
|
||||||
|
@retval Others Fail to remove cache data.
|
||||||
|
|
||||||
|
**/
|
||||||
|
EFI_STATUS
|
||||||
|
DeleteHttpCacheData (
|
||||||
|
IN REDFISH_HTTP_CACHE_LIST *List,
|
||||||
|
IN REDFISH_HTTP_CACHE_DATA *Data
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
This function release Redfish Payload.
|
||||||
|
|
||||||
|
@param[in] Payload Pointer to payload instance.
|
||||||
|
|
||||||
|
@retval EFI_SUCCESS Payload is released.
|
||||||
|
@retval Others Error occurs.
|
||||||
|
|
||||||
|
**/
|
||||||
|
EFI_STATUS
|
||||||
|
ReleaseRedfishPayload (
|
||||||
|
IN REDFISH_PAYLOAD_PRIVATE *Payload
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
This function creat new payload. Server and JsonObj are
|
||||||
|
copied to newly created payload.
|
||||||
|
|
||||||
|
@param[in] Service Pointer to Service instance.
|
||||||
|
@param[in] JsonObj Pointer to JSON object.
|
||||||
|
|
||||||
|
@retval REDFISH_PAYLOAD_PRIVATE Newly created payload.
|
||||||
|
@retval NULL Error occurs.
|
||||||
|
|
||||||
|
**/
|
||||||
|
REDFISH_PAYLOAD_PRIVATE *
|
||||||
|
CreateRedfishPayload (
|
||||||
|
IN REDFISH_SERVICE_PRIVATE *Service,
|
||||||
|
IN EDKII_JSON_VALUE JsonValue
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
This function release Redfish Service.
|
||||||
|
|
||||||
|
@param[in] Service Pointer to service instance.
|
||||||
|
|
||||||
|
@retval EFI_SUCCESS Service is released.
|
||||||
|
@retval Others Error occurs.
|
||||||
|
|
||||||
|
**/
|
||||||
|
EFI_STATUS
|
||||||
|
ReleaseRedfishService (
|
||||||
|
IN REDFISH_SERVICE_PRIVATE *Service
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
This function creat new service. Host and HostName are copied to
|
||||||
|
newly created service instance.
|
||||||
|
|
||||||
|
@param[in] Host Host string.
|
||||||
|
@param[in] HostName Hostname string.
|
||||||
|
@param[in] BasicAuth Basic Authorization string.
|
||||||
|
@param[in] SessionToken Session token string.
|
||||||
|
@param[in] RestEx Rest EX protocol instance.
|
||||||
|
|
||||||
|
@retval REDFISH_PAYLOAD_PRIVATE Newly created service.
|
||||||
|
@retval NULL Error occurs.
|
||||||
|
|
||||||
|
**/
|
||||||
|
REDFISH_SERVICE_PRIVATE *
|
||||||
|
CreateRedfishService (
|
||||||
|
IN CHAR8 *Host,
|
||||||
|
IN CHAR8 *HostName,
|
||||||
|
IN CHAR8 *BasicAuth OPTIONAL,
|
||||||
|
IN CHAR8 *SessionToken OPTIONAL,
|
||||||
|
IN EFI_REST_EX_PROTOCOL *RestEx
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
This function update session token in Redfish Service.
|
||||||
|
|
||||||
|
@param[in] Service Pointer to service instance.
|
||||||
|
@param[in] Token Session token.
|
||||||
|
|
||||||
|
@retval EFI_SUCCESS Session token is updated.
|
||||||
|
@retval Others Error occurs.
|
||||||
|
|
||||||
|
**/
|
||||||
|
EFI_STATUS
|
||||||
|
UpdateSessionToken (
|
||||||
|
IN REDFISH_SERVICE_PRIVATE *Service,
|
||||||
|
IN CHAR8 *Token
|
||||||
|
);
|
||||||
|
|
||||||
|
#endif
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,44 @@
|
||||||
|
/** @file
|
||||||
|
Definitions of RedfishHttpDxe
|
||||||
|
|
||||||
|
Copyright (c) 2023-2024, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||||
|
|
||||||
|
SPDX-License-Identifier: BSD-2-Clause-Patent
|
||||||
|
|
||||||
|
**/
|
||||||
|
|
||||||
|
#ifndef EDKII_REDFISH_HTTP_DXE_H_
|
||||||
|
#define EDKII_REDFISH_HTTP_DXE_H_
|
||||||
|
|
||||||
|
#include <Uefi.h>
|
||||||
|
#include <IndustryStandard/Http11.h>
|
||||||
|
|
||||||
|
#include <Library/UefiLib.h>
|
||||||
|
#include <Library/BaseLib.h>
|
||||||
|
#include <Library/BaseMemoryLib.h>
|
||||||
|
#include <Library/RedfishContentCodingLib.h>
|
||||||
|
#include <Library/DebugLib.h>
|
||||||
|
#include <Library/HttpLib.h>
|
||||||
|
#include <Library/JsonLib.h>
|
||||||
|
#include <Library/UefiBootServicesTableLib.h>
|
||||||
|
#include <Library/MemoryAllocationLib.h>
|
||||||
|
#include <Library/RedfishDebugLib.h>
|
||||||
|
#include <Library/ReportStatusCodeLib.h>
|
||||||
|
#include <Library/PrintLib.h>
|
||||||
|
|
||||||
|
#include <Protocol/Http.h>
|
||||||
|
#include <Protocol/EdkIIRedfishHttpProtocol.h>
|
||||||
|
#include <Protocol/EdkIIRedfishCredential.h>
|
||||||
|
#include <Protocol/RestEx.h>
|
||||||
|
|
||||||
|
#define IS_EMPTY_STRING(a) ((a) == NULL || (a)[0] == '\0')
|
||||||
|
#define REDFISH_HTTP_CACHE_LIST_SIZE 0x80
|
||||||
|
#define REDFISH_ERROR_MSG_MAX 128
|
||||||
|
#define REDFISH_DEBUG_STRING_LENGTH 200
|
||||||
|
#define REDFISH_HOST_NAME_MAX 64 // IPv6 maximum length (39) + "https://" (8) + port number (maximum 5)
|
||||||
|
#define REDFISH_HTTP_ERROR_REPORT "Redfish HTTP %a failure(0x%x): %s"
|
||||||
|
#define REDFISH_HTTP_CACHE_DEBUG DEBUG_MANAGEABILITY
|
||||||
|
#define REDFISH_HTTP_CACHE_DEBUG_DUMP DEBUG_MANAGEABILITY
|
||||||
|
#define REDFISH_HTTP_CACHE_DEBUG_REQUEST DEBUG_MANAGEABILITY
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,73 @@
|
||||||
|
## @file
|
||||||
|
# RedfishHttpDxe is the DXE driver which provides
|
||||||
|
# EdkIIRedfishHttpProtocol to EDK2 Redfish Feature
|
||||||
|
# drivers for HTTP operation.
|
||||||
|
#
|
||||||
|
# Copyright (c) 2023-2024, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||||
|
#
|
||||||
|
# SPDX-License-Identifier: BSD-2-Clause-Patent
|
||||||
|
#
|
||||||
|
##
|
||||||
|
|
||||||
|
[Defines]
|
||||||
|
INF_VERSION = 0x0001000b
|
||||||
|
BASE_NAME = RedfishHttpDxe
|
||||||
|
FILE_GUID = 85ADB2F1-DA93-47D4-AF4F-3D920D9BD2C0
|
||||||
|
MODULE_TYPE = DXE_DRIVER
|
||||||
|
VERSION_STRING = 1.0
|
||||||
|
ENTRY_POINT = RedfishHttpEntryPoint
|
||||||
|
UNLOAD_IMAGE = RedfishHttpDriverUnload
|
||||||
|
|
||||||
|
#
|
||||||
|
# VALID_ARCHITECTURES = IA32 X64 ARM AARCH64 RISCV64
|
||||||
|
#
|
||||||
|
|
||||||
|
[Sources]
|
||||||
|
RedfishHttpData.c
|
||||||
|
RedfishHttpData.h
|
||||||
|
RedfishHttpDxe.c
|
||||||
|
RedfishHttpDxe.h
|
||||||
|
RedfishHttpOperation.c
|
||||||
|
RedfishHttpOperation.h
|
||||||
|
|
||||||
|
[Packages]
|
||||||
|
MdePkg/MdePkg.dec
|
||||||
|
MdeModulePkg/MdeModulePkg.dec
|
||||||
|
NetworkPkg/NetworkPkg.dec
|
||||||
|
RedfishPkg/RedfishPkg.dec
|
||||||
|
|
||||||
|
[LibraryClasses.ARM]
|
||||||
|
ArmSoftFloatLib
|
||||||
|
|
||||||
|
[LibraryClasses]
|
||||||
|
BaseLib
|
||||||
|
BaseMemoryLib
|
||||||
|
RedfishContentCodingLib
|
||||||
|
DebugLib
|
||||||
|
HttpLib
|
||||||
|
JsonLib
|
||||||
|
MemoryAllocationLib
|
||||||
|
PrintLib
|
||||||
|
RedfishDebugLib
|
||||||
|
ReportStatusCodeLib
|
||||||
|
UefiBootServicesTableLib
|
||||||
|
UefiDriverEntryPoint
|
||||||
|
UefiLib
|
||||||
|
|
||||||
|
[Protocols]
|
||||||
|
gEdkIIRedfishHttpProtocolGuid ## PRODUCED
|
||||||
|
gEdkIIRedfishCredentialProtocolGuid ## CONSUMES
|
||||||
|
gEfiRestExProtocolGuid ## CONSUEMS
|
||||||
|
|
||||||
|
[Pcd]
|
||||||
|
gEfiRedfishPkgTokenSpaceGuid.PcdHttpGetRetry
|
||||||
|
gEfiRedfishPkgTokenSpaceGuid.PcdHttpPutRetry
|
||||||
|
gEfiRedfishPkgTokenSpaceGuid.PcdHttpPatchRetry
|
||||||
|
gEfiRedfishPkgTokenSpaceGuid.PcdHttpPostRetry
|
||||||
|
gEfiRedfishPkgTokenSpaceGuid.PcdHttpDeleteRetry
|
||||||
|
gEfiRedfishPkgTokenSpaceGuid.PcdHttpRetryWaitInSecond
|
||||||
|
gEfiRedfishPkgTokenSpaceGuid.PcdHttpCacheDisabled
|
||||||
|
gEfiRedfishPkgTokenSpaceGuid.PcdRedfishServiceContentEncoding
|
||||||
|
|
||||||
|
[Depex]
|
||||||
|
TRUE
|
|
@ -0,0 +1,692 @@
|
||||||
|
/** @file
|
||||||
|
RedfishHttpOperation handles HTTP operations.
|
||||||
|
|
||||||
|
Copyright (c) 2024, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||||
|
|
||||||
|
SPDX-License-Identifier: BSD-2-Clause-Patent
|
||||||
|
|
||||||
|
**/
|
||||||
|
|
||||||
|
#include "RedfishHttpOperation.h"
|
||||||
|
#include "RedfishHttpData.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
This function copies all headers in SrcHeaders to DstHeaders.
|
||||||
|
It's call responsibility to release returned DstHeaders.
|
||||||
|
|
||||||
|
@param[in] SrcHeaders Source headers.
|
||||||
|
@param[in] SrcHeaderCount Number of header in source headers.
|
||||||
|
@param[out] DstHeaders Destination headers.
|
||||||
|
@param[out] DstHeaderCount Number of header in designation headers.
|
||||||
|
|
||||||
|
@retval EFI_SUCCESS Headers are copied successfully.
|
||||||
|
@retval Others Errors occur.
|
||||||
|
|
||||||
|
**/
|
||||||
|
EFI_STATUS
|
||||||
|
CopyHttpHeaders (
|
||||||
|
IN EFI_HTTP_HEADER *SrcHeaders,
|
||||||
|
IN UINTN SrcHeaderCount,
|
||||||
|
OUT EFI_HTTP_HEADER **DstHeaders,
|
||||||
|
OUT UINTN *DstHeaderCount
|
||||||
|
)
|
||||||
|
{
|
||||||
|
UINTN Index;
|
||||||
|
|
||||||
|
if ((SrcHeaders == NULL) || (SrcHeaderCount == 0) || (DstHeaders == NULL) || (DstHeaderCount == NULL)) {
|
||||||
|
return EFI_INVALID_PARAMETER;
|
||||||
|
}
|
||||||
|
|
||||||
|
*DstHeaderCount = 0;
|
||||||
|
*DstHeaders = AllocateZeroPool (sizeof (EFI_HTTP_HEADER) * SrcHeaderCount);
|
||||||
|
if (*DstHeaders == NULL) {
|
||||||
|
return EFI_OUT_OF_RESOURCES;
|
||||||
|
}
|
||||||
|
|
||||||
|
*DstHeaderCount = SrcHeaderCount;
|
||||||
|
for (Index = 0; Index < SrcHeaderCount; Index++) {
|
||||||
|
(*DstHeaders)[Index].FieldName = ASCII_STR_DUPLICATE (SrcHeaders[Index].FieldName);
|
||||||
|
if ((*DstHeaders)[Index].FieldName == NULL) {
|
||||||
|
return EFI_OUT_OF_RESOURCES;
|
||||||
|
}
|
||||||
|
|
||||||
|
(*DstHeaders)[Index].FieldValue = ASCII_STR_DUPLICATE (SrcHeaders[Index].FieldValue);
|
||||||
|
if ((*DstHeaders)[Index].FieldValue == NULL) {
|
||||||
|
return EFI_OUT_OF_RESOURCES;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return EFI_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
This function free resources in Request. Request is no longer available
|
||||||
|
after this function returns successfully.
|
||||||
|
|
||||||
|
@param[in] Request HTTP request to be released.
|
||||||
|
|
||||||
|
@retval EFI_SUCCESS Resource is released successfully.
|
||||||
|
@retval Others Errors occur.
|
||||||
|
|
||||||
|
**/
|
||||||
|
EFI_STATUS
|
||||||
|
ReleaseRedfishRequest (
|
||||||
|
IN REDFISH_REQUEST *Request
|
||||||
|
)
|
||||||
|
{
|
||||||
|
if (Request == NULL) {
|
||||||
|
return EFI_INVALID_PARAMETER;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((Request->Headers != NULL) && (Request->HeaderCount > 0)) {
|
||||||
|
HttpFreeHeaderFields (Request->Headers, Request->HeaderCount);
|
||||||
|
Request->Headers = NULL;
|
||||||
|
Request->HeaderCount = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Request->Content != NULL) {
|
||||||
|
FreePool (Request->Content);
|
||||||
|
Request->Content = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Request->ContentType != NULL) {
|
||||||
|
FreePool (Request->ContentType);
|
||||||
|
Request->ContentType = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
Request->ContentLength = 0;
|
||||||
|
|
||||||
|
return EFI_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
This function free resources in given Response.
|
||||||
|
|
||||||
|
@param[in] Response HTTP response to be released.
|
||||||
|
|
||||||
|
@retval EFI_SUCCESS Resource is released successfully.
|
||||||
|
@retval Others Errors occur.
|
||||||
|
|
||||||
|
**/
|
||||||
|
EFI_STATUS
|
||||||
|
ReleaseRedfishResponse (
|
||||||
|
IN REDFISH_RESPONSE *Response
|
||||||
|
)
|
||||||
|
{
|
||||||
|
if (Response == NULL) {
|
||||||
|
return EFI_INVALID_PARAMETER;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((Response->Headers != NULL) && (Response->HeaderCount > 0)) {
|
||||||
|
HttpFreeHeaderFields (Response->Headers, Response->HeaderCount);
|
||||||
|
Response->Headers = NULL;
|
||||||
|
Response->HeaderCount = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Response->Payload != NULL) {
|
||||||
|
ReleaseRedfishPayload (Response->Payload);
|
||||||
|
Response->Payload = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Response->StatusCode != NULL) {
|
||||||
|
FreePool (Response->StatusCode);
|
||||||
|
Response->StatusCode = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return EFI_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
This function free resources in given HTTP message.
|
||||||
|
|
||||||
|
@param[in] HttpMessage HTTP message to be released.
|
||||||
|
@param[in] IsRequest TRUE if this is request type of HTTP message.
|
||||||
|
FALSE if this is response type of HTTP message.
|
||||||
|
|
||||||
|
@retval EFI_SUCCESS Resource is released successfully.
|
||||||
|
@retval Others Errors occur.
|
||||||
|
|
||||||
|
**/
|
||||||
|
EFI_STATUS
|
||||||
|
ReleaseHttpMessage (
|
||||||
|
IN EFI_HTTP_MESSAGE *HttpMessage,
|
||||||
|
IN BOOLEAN IsRequest
|
||||||
|
)
|
||||||
|
{
|
||||||
|
if (HttpMessage == NULL) {
|
||||||
|
return EFI_INVALID_PARAMETER;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (IsRequest) {
|
||||||
|
if (HttpMessage->Data.Request != NULL) {
|
||||||
|
if (HttpMessage->Data.Request->Url != NULL) {
|
||||||
|
FreePool (HttpMessage->Data.Request->Url);
|
||||||
|
}
|
||||||
|
|
||||||
|
FreePool (HttpMessage->Data.Request);
|
||||||
|
HttpMessage->Data.Request = NULL;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (HttpMessage->Data.Response != NULL) {
|
||||||
|
FreePool (HttpMessage->Data.Response);
|
||||||
|
HttpMessage->Data.Response = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (HttpMessage->Body != NULL) {
|
||||||
|
FreePool (HttpMessage->Body);
|
||||||
|
HttpMessage->Body = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (HttpMessage->Headers != NULL) {
|
||||||
|
HttpFreeHeaderFields (HttpMessage->Headers, HttpMessage->HeaderCount);
|
||||||
|
HttpMessage->Headers = NULL;
|
||||||
|
HttpMessage->HeaderCount = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return EFI_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
This function build Redfish message for sending data to Redfish service.
|
||||||
|
It's call responsibility to properly release returned HTTP message by
|
||||||
|
calling ReleaseHttpMessage.
|
||||||
|
|
||||||
|
@param[in] ServicePrivate Pointer to Redfish service private data.
|
||||||
|
@param[in] Uri Redfish service URI.
|
||||||
|
@param[in] Method HTTP method.
|
||||||
|
@param[in] Request Additional data to send to Redfish service.
|
||||||
|
This is optional.
|
||||||
|
@param[in] ContentEncoding Content encoding method to compress HTTP context.
|
||||||
|
This is optional. When ContentEncoding is NULL,
|
||||||
|
No compress method will be performed.
|
||||||
|
|
||||||
|
@retval EFI_HTTP_MESSAGE * Pointer to newly created HTTP message.
|
||||||
|
@retval NULL Error occurred.
|
||||||
|
|
||||||
|
**/
|
||||||
|
EFI_HTTP_MESSAGE *
|
||||||
|
BuildRequestMessage (
|
||||||
|
IN REDFISH_SERVICE_PRIVATE *ServicePrivate,
|
||||||
|
IN EFI_STRING Uri,
|
||||||
|
IN EFI_HTTP_METHOD Method,
|
||||||
|
IN REDFISH_REQUEST *Request OPTIONAL,
|
||||||
|
IN CHAR8 *ContentEncoding OPTIONAL
|
||||||
|
)
|
||||||
|
{
|
||||||
|
EFI_STATUS Status;
|
||||||
|
EFI_STRING Url;
|
||||||
|
UINTN UrlSize;
|
||||||
|
UINTN Index;
|
||||||
|
EFI_HTTP_MESSAGE *RequestMsg;
|
||||||
|
EFI_HTTP_REQUEST_DATA *RequestData;
|
||||||
|
UINTN HeaderCount;
|
||||||
|
UINTN HeaderIndex;
|
||||||
|
EFI_HTTP_HEADER *Headers;
|
||||||
|
CHAR8 ContentLengthStr[REDFISH_CONTENT_LENGTH_SIZE];
|
||||||
|
VOID *Content;
|
||||||
|
UINTN ContentLength;
|
||||||
|
BOOLEAN HasContent;
|
||||||
|
BOOLEAN DoContentEncoding;
|
||||||
|
|
||||||
|
RequestMsg = NULL;
|
||||||
|
RequestData = NULL;
|
||||||
|
Url = NULL;
|
||||||
|
UrlSize = 0;
|
||||||
|
Content = NULL;
|
||||||
|
ContentLength = 0;
|
||||||
|
HeaderCount = REDFISH_COMMON_HEADER_SIZE;
|
||||||
|
HeaderIndex = 0;
|
||||||
|
Headers = NULL;
|
||||||
|
HasContent = FALSE;
|
||||||
|
DoContentEncoding = FALSE;
|
||||||
|
|
||||||
|
if ((ServicePrivate == NULL) || (IS_EMPTY_STRING (Uri))) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Method >= HttpMethodMax) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
DEBUG ((REDFISH_HTTP_CACHE_DEBUG_REQUEST, "%a: %s\n", __func__, Uri));
|
||||||
|
|
||||||
|
//
|
||||||
|
// Build full URL for HTTP query.
|
||||||
|
//
|
||||||
|
UrlSize = (AsciiStrLen (ServicePrivate->Host) + StrLen (Uri) + 1) * sizeof (CHAR16);
|
||||||
|
Url = AllocateZeroPool (UrlSize);
|
||||||
|
if (Url == NULL) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
UnicodeSPrint (Url, UrlSize, L"%a%s", ServicePrivate->Host, Uri);
|
||||||
|
DEBUG ((REDFISH_HTTP_CACHE_DEBUG_REQUEST, "%a: Url: %s\n", __func__, Url));
|
||||||
|
|
||||||
|
//
|
||||||
|
// Step 1: build the HTTP headers.
|
||||||
|
//
|
||||||
|
if (!IS_EMPTY_STRING (ServicePrivate->SessionToken) || !IS_EMPTY_STRING (ServicePrivate->BasicAuth)) {
|
||||||
|
HeaderCount++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((Request != NULL) && (Request->HeaderCount > 0)) {
|
||||||
|
HeaderCount += Request->HeaderCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Check and see if we will do content encoding or not
|
||||||
|
//
|
||||||
|
if (!IS_EMPTY_STRING (ContentEncoding)) {
|
||||||
|
if (AsciiStrCmp (ContentEncoding, REDFISH_HTTP_CONTENT_ENCODING_NONE) != 0) {
|
||||||
|
DoContentEncoding = TRUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((Request != NULL) && !IS_EMPTY_STRING (Request->Content)) {
|
||||||
|
HeaderCount += 2;
|
||||||
|
HasContent = TRUE;
|
||||||
|
if (DoContentEncoding) {
|
||||||
|
HeaderCount += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Headers = AllocateZeroPool (HeaderCount * sizeof (EFI_HTTP_HEADER));
|
||||||
|
if (Headers == NULL) {
|
||||||
|
goto ON_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!IS_EMPTY_STRING (ServicePrivate->SessionToken)) {
|
||||||
|
Status = HttpSetFieldNameAndValue (&Headers[HeaderIndex++], HTTP_HEADER_X_AUTH_TOKEN, ServicePrivate->SessionToken);
|
||||||
|
if (EFI_ERROR (Status)) {
|
||||||
|
goto ON_ERROR;
|
||||||
|
}
|
||||||
|
} else if (!IS_EMPTY_STRING (ServicePrivate->BasicAuth)) {
|
||||||
|
Status = HttpSetFieldNameAndValue (&Headers[HeaderIndex++], HTTP_HEADER_AUTHORIZATION, ServicePrivate->BasicAuth);
|
||||||
|
if (EFI_ERROR (Status)) {
|
||||||
|
goto ON_ERROR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Request != NULL) {
|
||||||
|
for (Index = 0; Index < Request->HeaderCount; Index++) {
|
||||||
|
Status = HttpSetFieldNameAndValue (&Headers[HeaderIndex++], Request->Headers[Index].FieldName, Request->Headers[Index].FieldValue);
|
||||||
|
if (EFI_ERROR (Status)) {
|
||||||
|
goto ON_ERROR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Status = HttpSetFieldNameAndValue (&Headers[HeaderIndex++], HTTP_HEADER_HOST, ServicePrivate->HostName);
|
||||||
|
if (EFI_ERROR (Status)) {
|
||||||
|
goto ON_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
Status = HttpSetFieldNameAndValue (&Headers[HeaderIndex++], REDFISH_HTTP_HEADER_ODATA_VERSION_STR, REDFISH_HTTP_HEADER_ODATA_VERSION_VALUE);
|
||||||
|
if (EFI_ERROR (Status)) {
|
||||||
|
goto ON_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
Status = HttpSetFieldNameAndValue (&Headers[HeaderIndex++], HTTP_HEADER_ACCEPT, HTTP_CONTENT_TYPE_APP_JSON);
|
||||||
|
if (EFI_ERROR (Status)) {
|
||||||
|
goto ON_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
Status = HttpSetFieldNameAndValue (&Headers[HeaderIndex++], HTTP_HEADER_USER_AGENT, REDFISH_HTTP_HEADER_USER_AGENT_VALUE);
|
||||||
|
if (EFI_ERROR (Status)) {
|
||||||
|
goto ON_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
Status = HttpSetFieldNameAndValue (&Headers[HeaderIndex++], REDFISH_HTTP_HEADER_CONNECTION_STR, REDFISH_HTTP_HEADER_CONNECTION_VALUE);
|
||||||
|
if (EFI_ERROR (Status)) {
|
||||||
|
goto ON_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Handle content header
|
||||||
|
//
|
||||||
|
if (HasContent) {
|
||||||
|
if (Request->ContentType == NULL) {
|
||||||
|
Status = HttpSetFieldNameAndValue (&Headers[HeaderIndex++], HTTP_HEADER_CONTENT_TYPE, HTTP_CONTENT_TYPE_APP_JSON);
|
||||||
|
if (EFI_ERROR (Status)) {
|
||||||
|
goto ON_ERROR;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Status = HttpSetFieldNameAndValue (&Headers[HeaderIndex++], HTTP_HEADER_CONTENT_TYPE, Request->ContentType);
|
||||||
|
if (EFI_ERROR (Status)) {
|
||||||
|
goto ON_ERROR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Request->ContentLength == 0) {
|
||||||
|
Request->ContentLength = AsciiStrLen (Request->Content);
|
||||||
|
}
|
||||||
|
|
||||||
|
AsciiSPrint (
|
||||||
|
ContentLengthStr,
|
||||||
|
sizeof (ContentLengthStr),
|
||||||
|
"%lu",
|
||||||
|
(UINT64)Request->ContentLength
|
||||||
|
);
|
||||||
|
Status = HttpSetFieldNameAndValue (&Headers[HeaderIndex++], HTTP_HEADER_CONTENT_LENGTH, ContentLengthStr);
|
||||||
|
if (EFI_ERROR (Status)) {
|
||||||
|
goto ON_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Encoding
|
||||||
|
//
|
||||||
|
if (DoContentEncoding) {
|
||||||
|
//
|
||||||
|
// We currently only support gzip Content-Encoding.
|
||||||
|
//
|
||||||
|
Status = RedfishContentEncode (
|
||||||
|
ContentEncoding,
|
||||||
|
Request->Content,
|
||||||
|
Request->ContentLength,
|
||||||
|
&Content,
|
||||||
|
&ContentLength
|
||||||
|
);
|
||||||
|
if (Status == EFI_INVALID_PARAMETER) {
|
||||||
|
DEBUG ((DEBUG_ERROR, "%a: Error to encode content.\n", __func__));
|
||||||
|
goto ON_ERROR;
|
||||||
|
} else if (Status == EFI_UNSUPPORTED) {
|
||||||
|
DoContentEncoding = FALSE;
|
||||||
|
DEBUG ((REDFISH_HTTP_CACHE_DEBUG_REQUEST, "%a: No content coding for %a! Use raw data instead.\n", __func__, ContentEncoding));
|
||||||
|
Status = HttpSetFieldNameAndValue (&Headers[HeaderIndex++], HTTP_HEADER_CONTENT_ENCODING, HTTP_CONTENT_ENCODING_IDENTITY);
|
||||||
|
if (EFI_ERROR (Status)) {
|
||||||
|
goto ON_ERROR;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Status = HttpSetFieldNameAndValue (&Headers[HeaderIndex++], HTTP_HEADER_CONTENT_ENCODING, HTTP_CONTENT_ENCODING_GZIP);
|
||||||
|
if (EFI_ERROR (Status)) {
|
||||||
|
goto ON_ERROR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// When the content is from caller, we use our own copy so that we properly release it later.
|
||||||
|
//
|
||||||
|
if (!DoContentEncoding) {
|
||||||
|
Content = AllocateCopyPool (Request->ContentLength, Request->Content);
|
||||||
|
if (Content == NULL) {
|
||||||
|
goto ON_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
ContentLength = Request->ContentLength;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Step 2: build the rest of HTTP request info.
|
||||||
|
//
|
||||||
|
RequestData = AllocateZeroPool (sizeof (EFI_HTTP_REQUEST_DATA));
|
||||||
|
if (RequestData == NULL) {
|
||||||
|
goto ON_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
RequestData->Method = Method;
|
||||||
|
RequestData->Url = Url;
|
||||||
|
|
||||||
|
//
|
||||||
|
// Step 3: fill in EFI_HTTP_MESSAGE
|
||||||
|
//
|
||||||
|
RequestMsg = AllocateZeroPool (sizeof (EFI_HTTP_MESSAGE));
|
||||||
|
if (RequestMsg == NULL) {
|
||||||
|
goto ON_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
ASSERT (HeaderIndex == HeaderCount);
|
||||||
|
RequestMsg->Data.Request = RequestData;
|
||||||
|
RequestMsg->HeaderCount = HeaderIndex;
|
||||||
|
RequestMsg->Headers = Headers;
|
||||||
|
|
||||||
|
if (HasContent) {
|
||||||
|
RequestMsg->BodyLength = ContentLength;
|
||||||
|
RequestMsg->Body = Content;
|
||||||
|
}
|
||||||
|
|
||||||
|
return RequestMsg;
|
||||||
|
|
||||||
|
ON_ERROR:
|
||||||
|
|
||||||
|
if (Headers != NULL) {
|
||||||
|
HttpFreeHeaderFields (Headers, HeaderIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (RequestData != NULL) {
|
||||||
|
FreePool (RequestData);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (RequestMsg != NULL) {
|
||||||
|
FreePool (RequestMsg);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Url != NULL) {
|
||||||
|
FreePool (Url);
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
This function parse response message from Redfish service, and
|
||||||
|
build Redfish response for caller. It's call responsibility to
|
||||||
|
properly release Redfish response by calling ReleaseRedfishResponse.
|
||||||
|
|
||||||
|
@param[in] ServicePrivate Pointer to Redfish service private data.
|
||||||
|
@param[in] ResponseMsg Response message from Redfish service.
|
||||||
|
@param[out] RedfishResponse Redfish response data.
|
||||||
|
|
||||||
|
@retval EFI_SUCCESS Redfish response is returned successfully.
|
||||||
|
@retval Others Errors occur.
|
||||||
|
|
||||||
|
**/
|
||||||
|
EFI_STATUS
|
||||||
|
ParseResponseMessage (
|
||||||
|
IN REDFISH_SERVICE_PRIVATE *ServicePrivate,
|
||||||
|
IN EFI_HTTP_MESSAGE *ResponseMsg,
|
||||||
|
OUT REDFISH_RESPONSE *RedfishResponse
|
||||||
|
)
|
||||||
|
{
|
||||||
|
EFI_STATUS Status;
|
||||||
|
EDKII_JSON_VALUE JsonData;
|
||||||
|
EFI_HTTP_HEADER *ContentEncodedHeader;
|
||||||
|
VOID *DecodedBody;
|
||||||
|
UINTN DecodedLength;
|
||||||
|
|
||||||
|
if ((ServicePrivate == NULL) || (ResponseMsg == NULL) || (RedfishResponse == NULL)) {
|
||||||
|
return EFI_INVALID_PARAMETER;
|
||||||
|
}
|
||||||
|
|
||||||
|
DEBUG ((REDFISH_HTTP_CACHE_DEBUG_REQUEST, "%a\n", __func__));
|
||||||
|
|
||||||
|
//
|
||||||
|
// Initialization
|
||||||
|
//
|
||||||
|
JsonData = NULL;
|
||||||
|
RedfishResponse->HeaderCount = 0;
|
||||||
|
RedfishResponse->Headers = NULL;
|
||||||
|
RedfishResponse->Payload = NULL;
|
||||||
|
RedfishResponse->StatusCode = NULL;
|
||||||
|
DecodedBody = NULL;
|
||||||
|
DecodedLength = 0;
|
||||||
|
|
||||||
|
//
|
||||||
|
// Return the HTTP StatusCode.
|
||||||
|
//
|
||||||
|
if (ResponseMsg->Data.Response != NULL) {
|
||||||
|
DEBUG ((REDFISH_HTTP_CACHE_DEBUG_REQUEST, "%a: status: %d\n", __func__, ResponseMsg->Data.Response->StatusCode));
|
||||||
|
RedfishResponse->StatusCode = AllocateCopyPool (sizeof (EFI_HTTP_STATUS_CODE), &ResponseMsg->Data.Response->StatusCode);
|
||||||
|
if (RedfishResponse->StatusCode == NULL) {
|
||||||
|
DEBUG ((DEBUG_ERROR, "%a: Failed to create status code.\n", __func__));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Return the HTTP headers.
|
||||||
|
//
|
||||||
|
if (ResponseMsg->Headers != NULL) {
|
||||||
|
DEBUG ((REDFISH_HTTP_CACHE_DEBUG_REQUEST, "%a: header count: %d\n", __func__, ResponseMsg->HeaderCount));
|
||||||
|
Status = CopyHttpHeaders (
|
||||||
|
ResponseMsg->Headers,
|
||||||
|
ResponseMsg->HeaderCount,
|
||||||
|
&RedfishResponse->Headers,
|
||||||
|
&RedfishResponse->HeaderCount
|
||||||
|
);
|
||||||
|
if (EFI_ERROR (Status)) {
|
||||||
|
DEBUG ((DEBUG_ERROR, "%a: Failed to copy HTTP headers: %r\n", __func__, Status));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Return the HTTP body.
|
||||||
|
//
|
||||||
|
if ((ResponseMsg->BodyLength != 0) && (ResponseMsg->Body != NULL)) {
|
||||||
|
DEBUG ((REDFISH_HTTP_CACHE_DEBUG_REQUEST, "%a: body length: %d\n", __func__, ResponseMsg->BodyLength));
|
||||||
|
//
|
||||||
|
// Check if data is encoded.
|
||||||
|
//
|
||||||
|
ContentEncodedHeader = HttpFindHeader (RedfishResponse->HeaderCount, RedfishResponse->Headers, HTTP_HEADER_CONTENT_ENCODING);
|
||||||
|
if (ContentEncodedHeader != NULL) {
|
||||||
|
//
|
||||||
|
// The content is encoded.
|
||||||
|
//
|
||||||
|
Status = RedfishContentDecode (
|
||||||
|
ContentEncodedHeader->FieldValue,
|
||||||
|
ResponseMsg->Body,
|
||||||
|
ResponseMsg->BodyLength,
|
||||||
|
&DecodedBody,
|
||||||
|
&DecodedLength
|
||||||
|
);
|
||||||
|
if (EFI_ERROR (Status)) {
|
||||||
|
DEBUG ((DEBUG_ERROR, "%a: Failed to decompress the response content: %r decoding method: %a\n.", __func__, Status, ContentEncodedHeader->FieldValue));
|
||||||
|
goto ON_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
JsonData = JsonLoadBuffer (DecodedBody, DecodedLength, 0, NULL);
|
||||||
|
FreePool (DecodedBody);
|
||||||
|
} else {
|
||||||
|
JsonData = JsonLoadBuffer (ResponseMsg->Body, ResponseMsg->BodyLength, 0, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!JsonValueIsNull (JsonData)) {
|
||||||
|
RedfishResponse->Payload = CreateRedfishPayload (ServicePrivate, JsonData);
|
||||||
|
if (RedfishResponse->Payload == NULL) {
|
||||||
|
DEBUG ((DEBUG_ERROR, "%a: Failed to create payload\n.", __func__));
|
||||||
|
}
|
||||||
|
|
||||||
|
JsonValueFree (JsonData);
|
||||||
|
} else {
|
||||||
|
DEBUG ((DEBUG_ERROR, "%a: No payload available\n", __func__));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return EFI_SUCCESS;
|
||||||
|
|
||||||
|
ON_ERROR:
|
||||||
|
|
||||||
|
if (RedfishResponse != NULL) {
|
||||||
|
ReleaseRedfishResponse (RedfishResponse);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Status;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
This function send Redfish request to Redfish service by calling
|
||||||
|
Rest Ex protocol.
|
||||||
|
|
||||||
|
@param[in] Service Pointer to Redfish service.
|
||||||
|
@param[in] Uri Uri of Redfish service.
|
||||||
|
@param[in] Method HTTP method.
|
||||||
|
@param[in] Request Request data. This is optional.
|
||||||
|
@param[out] Response Redfish response data.
|
||||||
|
|
||||||
|
@retval EFI_SUCCESS Request is sent and received successfully.
|
||||||
|
@retval Others Errors occur.
|
||||||
|
|
||||||
|
**/
|
||||||
|
EFI_STATUS
|
||||||
|
HttpSendReceive (
|
||||||
|
IN REDFISH_SERVICE Service,
|
||||||
|
IN EFI_STRING Uri,
|
||||||
|
IN EFI_HTTP_METHOD Method,
|
||||||
|
IN REDFISH_REQUEST *Request OPTIONAL,
|
||||||
|
OUT REDFISH_RESPONSE *Response
|
||||||
|
)
|
||||||
|
{
|
||||||
|
EFI_STATUS Status;
|
||||||
|
EFI_STATUS RestExStatus;
|
||||||
|
EFI_HTTP_MESSAGE *RequestMsg;
|
||||||
|
EFI_HTTP_MESSAGE ResponseMsg;
|
||||||
|
REDFISH_SERVICE_PRIVATE *ServicePrivate;
|
||||||
|
EFI_HTTP_HEADER *XAuthTokenHeader;
|
||||||
|
CHAR8 *HttpContentEncoding;
|
||||||
|
|
||||||
|
if ((Service == NULL) || IS_EMPTY_STRING (Uri) || (Response == NULL)) {
|
||||||
|
return EFI_INVALID_PARAMETER;
|
||||||
|
}
|
||||||
|
|
||||||
|
DEBUG ((REDFISH_HTTP_CACHE_DEBUG_REQUEST, "%a: Method: 0x%x %s\n", __func__, Method, Uri));
|
||||||
|
|
||||||
|
ServicePrivate = (REDFISH_SERVICE_PRIVATE *)Service;
|
||||||
|
if (ServicePrivate->Signature != REDFISH_HTTP_SERVICE_SIGNATURE) {
|
||||||
|
DEBUG ((DEBUG_ERROR, "%a: signature check failure\n", __func__));
|
||||||
|
return EFI_INVALID_PARAMETER;
|
||||||
|
}
|
||||||
|
|
||||||
|
ZeroMem (&ResponseMsg, sizeof (ResponseMsg));
|
||||||
|
HttpContentEncoding = (CHAR8 *)PcdGetPtr (PcdRedfishServiceContentEncoding);
|
||||||
|
|
||||||
|
RequestMsg = BuildRequestMessage (Service, Uri, Method, Request, HttpContentEncoding);
|
||||||
|
if (RequestMsg == NULL) {
|
||||||
|
DEBUG ((DEBUG_ERROR, "%a: cannot build request message for %s\n", __func__, Uri));
|
||||||
|
return EFI_PROTOCOL_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// call RESTEx to get response from REST service.
|
||||||
|
//
|
||||||
|
RestExStatus = ServicePrivate->RestEx->SendReceive (ServicePrivate->RestEx, RequestMsg, &ResponseMsg);
|
||||||
|
if (EFI_ERROR (RestExStatus)) {
|
||||||
|
DEBUG ((DEBUG_ERROR, "%a: %s SendReceive failure: %r\n", __func__, Uri, RestExStatus));
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Return status code, headers and payload to caller as much as possible even when RestEx returns failure.
|
||||||
|
//
|
||||||
|
Status = ParseResponseMessage (ServicePrivate, &ResponseMsg, Response);
|
||||||
|
if (EFI_ERROR (Status)) {
|
||||||
|
DEBUG ((DEBUG_ERROR, "%a: %s parse response failure: %r\n", __func__, Uri, Status));
|
||||||
|
} else {
|
||||||
|
//
|
||||||
|
// Capture session token in header
|
||||||
|
//
|
||||||
|
if ((Method == HttpMethodPost) &&
|
||||||
|
(Response->StatusCode != NULL) &&
|
||||||
|
((*Response->StatusCode == HTTP_STATUS_200_OK) || (*Response->StatusCode == HTTP_STATUS_204_NO_CONTENT)))
|
||||||
|
{
|
||||||
|
XAuthTokenHeader = HttpFindHeader (ResponseMsg.HeaderCount, ResponseMsg.Headers, HTTP_HEADER_X_AUTH_TOKEN);
|
||||||
|
if (XAuthTokenHeader != NULL) {
|
||||||
|
Status = UpdateSessionToken (ServicePrivate, XAuthTokenHeader->FieldValue);
|
||||||
|
if (EFI_ERROR (Status)) {
|
||||||
|
DEBUG ((DEBUG_ERROR, "%a: update session token failure: %r\n", __func__, Status));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Release resources
|
||||||
|
//
|
||||||
|
if (RequestMsg != NULL) {
|
||||||
|
ReleaseHttpMessage (RequestMsg, TRUE);
|
||||||
|
FreePool (RequestMsg);
|
||||||
|
}
|
||||||
|
|
||||||
|
ReleaseHttpMessage (&ResponseMsg, FALSE);
|
||||||
|
|
||||||
|
return RestExStatus;
|
||||||
|
}
|
|
@ -0,0 +1,77 @@
|
||||||
|
/** @file
|
||||||
|
Definitions of RedfishHttpOperation
|
||||||
|
|
||||||
|
Copyright (c) 2024, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||||
|
|
||||||
|
SPDX-License-Identifier: BSD-2-Clause-Patent
|
||||||
|
|
||||||
|
**/
|
||||||
|
|
||||||
|
#ifndef EDKII_REDFISH_HTTP_OPERATION_H_
|
||||||
|
#define EDKII_REDFISH_HTTP_OPERATION_H_
|
||||||
|
|
||||||
|
#include "RedfishHttpDxe.h"
|
||||||
|
|
||||||
|
#define REDFISH_CONTENT_LENGTH_SIZE 80
|
||||||
|
#define REDFISH_COMMON_HEADER_SIZE 5
|
||||||
|
#define REDFISH_HTTP_HEADER_ODATA_VERSION_STR "OData-Version"
|
||||||
|
#define REDFISH_HTTP_HEADER_ODATA_VERSION_VALUE "4.0"
|
||||||
|
#define REDFISH_HTTP_HEADER_USER_AGENT_VALUE "edk2redfish"
|
||||||
|
#define REDFISH_HTTP_HEADER_CONNECTION_STR "Connection"
|
||||||
|
#define REDFISH_HTTP_HEADER_CONNECTION_VALUE "Keep-Alive"
|
||||||
|
#define REDFISH_HTTP_CONTENT_ENCODING_NONE "None"
|
||||||
|
#define ASCII_STR_DUPLICATE(a) (AllocateCopyPool (AsciiStrSize ((a)), (a)))
|
||||||
|
|
||||||
|
/**
|
||||||
|
This function free resources in Request. Request is no longer available
|
||||||
|
after this function returns successfully.
|
||||||
|
|
||||||
|
@param[in] Request HTTP request to be released.
|
||||||
|
|
||||||
|
@retval EFI_SUCCESS Resource is released successfully.
|
||||||
|
@retval Others Errors occur.
|
||||||
|
|
||||||
|
**/
|
||||||
|
EFI_STATUS
|
||||||
|
ReleaseRedfishRequest (
|
||||||
|
IN REDFISH_REQUEST *Request
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
This function free resources in given Response.
|
||||||
|
|
||||||
|
@param[in] Response HTTP response to be released.
|
||||||
|
|
||||||
|
@retval EFI_SUCCESS Resource is released successfully.
|
||||||
|
@retval Others Errors occur.
|
||||||
|
|
||||||
|
**/
|
||||||
|
EFI_STATUS
|
||||||
|
ReleaseRedfishResponse (
|
||||||
|
IN REDFISH_RESPONSE *Response
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
This function send Redfish request to Redfish service by calling
|
||||||
|
Rest Ex protocol.
|
||||||
|
|
||||||
|
@param[in] Service Pointer to Redfish service.
|
||||||
|
@param[in] Uri Uri of Redfish service.
|
||||||
|
@param[in] Method HTTP method.
|
||||||
|
@param[in] Request Request data. This is optional.
|
||||||
|
@param[out] Response Redfish response data.
|
||||||
|
|
||||||
|
@retval EFI_SUCCESS Request is sent and received successfully.
|
||||||
|
@retval Others Errors occur.
|
||||||
|
|
||||||
|
**/
|
||||||
|
EFI_STATUS
|
||||||
|
HttpSendReceive (
|
||||||
|
IN REDFISH_SERVICE Service,
|
||||||
|
IN EFI_STRING Uri,
|
||||||
|
IN EFI_HTTP_METHOD Method,
|
||||||
|
IN REDFISH_REQUEST *Request OPTIONAL,
|
||||||
|
OUT REDFISH_RESPONSE *Response
|
||||||
|
);
|
||||||
|
|
||||||
|
#endif
|
|
@ -157,8 +157,11 @@
|
||||||
# set to EFI_REST_EX_PROTOCOL.
|
# set to EFI_REST_EX_PROTOCOL.
|
||||||
#
|
#
|
||||||
gEfiRedfishPkgTokenSpaceGuid.PcdRedfishSendReceiveTimeout|5000|UINT32|0x00001009
|
gEfiRedfishPkgTokenSpaceGuid.PcdRedfishSendReceiveTimeout|5000|UINT32|0x00001009
|
||||||
## This is used to enable HTTP content encoding on Redfish communication.
|
#
|
||||||
gEfiRedfishPkgTokenSpaceGuid.PcdRedfishServiceContentEncoding|TRUE|BOOLEAN|0x0000100A
|
# This PCD string is introduced for platform developer to set the encoding method supported by BMC Redfish.
|
||||||
|
# Currently only "None" and "gzip" are supported.
|
||||||
|
#
|
||||||
|
gEfiRedfishPkgTokenSpaceGuid.PcdRedfishServiceContentEncoding|"None"|VOID*|0x0000100A
|
||||||
#
|
#
|
||||||
# Use below PCDs to control Redfhs HTTP protocol.
|
# Use below PCDs to control Redfhs HTTP protocol.
|
||||||
#
|
#
|
||||||
|
|
|
@ -45,6 +45,8 @@
|
||||||
UefiHiiServicesLib|MdeModulePkg/Library/UefiHiiServicesLib/UefiHiiServicesLib.inf
|
UefiHiiServicesLib|MdeModulePkg/Library/UefiHiiServicesLib/UefiHiiServicesLib.inf
|
||||||
RedfishPlatformCredentialLib|RedfishPkg/Library/PlatformCredentialLibNull/PlatformCredentialLibNull.inf
|
RedfishPlatformCredentialLib|RedfishPkg/Library/PlatformCredentialLibNull/PlatformCredentialLibNull.inf
|
||||||
RedfishContentCodingLib|RedfishPkg/Library/RedfishContentCodingLibNull/RedfishContentCodingLibNull.inf
|
RedfishContentCodingLib|RedfishPkg/Library/RedfishContentCodingLibNull/RedfishContentCodingLibNull.inf
|
||||||
|
ReportStatusCodeLib|MdeModulePkg/Library/DxeReportStatusCodeLib/DxeReportStatusCodeLib.inf
|
||||||
|
SortLib|MdeModulePkg/Library/UefiSortLib/UefiSortLib.inf
|
||||||
|
|
||||||
# NULL instance of IPMI related library.
|
# NULL instance of IPMI related library.
|
||||||
IpmiLib|MdeModulePkg/Library/BaseIpmiLibNull/BaseIpmiLibNull.inf
|
IpmiLib|MdeModulePkg/Library/BaseIpmiLibNull/BaseIpmiLibNull.inf
|
||||||
|
|
Loading…
Reference in New Issue