From: "Nickle Wang via groups.io" <nicklew=nvidia.com@groups.io>
To: Mike Maslenkin <mike.maslenkin@gmail.com>
Cc: "devel@edk2.groups.io" <devel@edk2.groups.io>,
Igor Kulchytskyy <igork@ami.com>,
Abner Chang <abner.chang@amd.com>,
Nick Ramirez <nramirez@nvidia.com>
Subject: Re: [edk2-devel] [PATCH v2 2/6] RedfishPkg: implement Redfish HTTP protocol
Date: Mon, 26 Feb 2024 13:43:49 +0000 [thread overview]
Message-ID: <MW4PR12MB70315BAEE316B23C18D262D5D95A2@MW4PR12MB7031.namprd12.prod.outlook.com> (raw)
In-Reply-To: <CAL77WPCgNPo2wEM8B+t1wM0scAAhsJ92gq6u3HVOnM9-rbYo2A@mail.gmail.com>
Hi Mike,
> So finally we have
> HttpFreeHeaderFields (Response->Headers, Response->HeaderCount);
> but Response->HeaderCount does not count partially allocated elements. Right?
>
> To fix this, it is required to set
> *DstHeaderCount = SrcHeaderCount unconditionally right after
> DstHeaders allocation, and HttpFreeHeaderFields() will do the work
> then.
I follow your suggestion to update DstHeaderCount right after DstHeaders is allocated. So, HttpFreeHeaderFields can release headers correctly. I also create a macro to implemented AsciiStrCpy. Please check below link to see my changes:
https://github.com/tianocore/edk2/compare/0f391b1c2f988d90a3ac723b314ac28ba7b0b8df..f0fa1b8fdcd933beb52fd3127c2476443c00ef8d
Thanks,
Nickle
> -----Original Message-----
> From: Mike Maslenkin <mike.maslenkin@gmail.com>
> Sent: Saturday, February 24, 2024 12:05 AM
> To: Nickle Wang <nicklew@nvidia.com>
> Cc: devel@edk2.groups.io; Igor Kulchytskyy <igork@ami.com>; Abner Chang
> <abner.chang@amd.com>; Nick Ramirez <nramirez@nvidia.com>
> Subject: Re: [edk2-devel] [PATCH v2 2/6] RedfishPkg: implement Redfish HTTP
> protocol
>
> External email: Use caution opening links or attachments
>
>
> Hi Nickle,
>
> On Fri, Feb 23, 2024 at 5:07 PM Nickle Wang <nicklew@nvidia.com> wrote:
> >
> > Thanks for your review, Mike.
> >
> > > %s/Resrouce/Resource/ this comes from RedfishClient autogenerated files...
> >
> > Typos are Addressed. I will send v3 later.
> >
> > >> +ON_ERROR:
> > >> +
> > >> + ReleaseRedfishPayload (NewPayload);
> > >> +
> > >
> > > NewPayload->Service is leaked
> >
> > NewPayload->Service will be released in ReleaseRedfishPayload function.
> ReleaseRedfishService() will be called in ReleaseRedfishPayload() when Service is
> not NULL. Please let me know if I misunderstand your comment.
>
> Oh, I see.
> I missed ReleaseRedfishService() call.
>
> >
> >
> > >> + (*DstHeaders)[Index].FieldValue = AllocateCopyPool (AsciiStrSize
> (SrcHeaders[Index].FieldValue), SrcHeaders[Index].FieldValue);
> > >> + if ((*DstHeaders)[Index].FieldValue == NULL) {
> > >> + return EFI_OUT_OF_RESOURCES;
> > >
> > > Looks like orevious allocations leaked.
> > > Didn't you think to implement smth like this ....?
> >
> > Yes, I can implement AsciiStrDup() here. But this won't fix the allocation leaking,
> right? To fix allocation leaking, my idea is to call HttpFreeHeaderFields() before
> returning EFI_OUT_OF_RESOURCES. HttpFreeHeaderFields() will skip NULL
> FieldName and FieldValue automatically. Does this sound good to you?
> >
> > I think I covered all your comments, but I am bad to find review comment in
> email. If I missed any review comment, please kindly let me know. Thanks!
>
> AsciiStrDup() is not handy here, because it requires preallocated buffer.
> I mentioned about function similar to StrDup just to get shorter and
> cleaner code.
>
> I think I understood the idea now.
> I'm just looking into code and assume that if function returns an
> error, it must deallocate/cleanup resources.
>
> So finally we have
> HttpFreeHeaderFields (Response->Headers, Response->HeaderCount);
> but Response->HeaderCount does not count partially allocated elements. Right?
>
> To fix this, it is required to set
> *DstHeaderCount = SrcHeaderCount unconditionally right after
> DstHeaders allocation, and HttpFreeHeaderFields() will do the work
> then.
>
> Regards,
> Mike.
>
> >
> > Regards,
> > Nickle
> >
> > > -----Original Message-----
> > > From: Mike Maslenkin <mike.maslenkin@gmail.com>
> > > Sent: Friday, February 23, 2024 7:29 PM
> > > To: devel@edk2.groups.io; Nickle Wang <nicklew@nvidia.com>
> > > Cc: Igor Kulchytskyy <igork@ami.com>; Abner Chang
> <abner.chang@amd.com>;
> > > Nick Ramirez <nramirez@nvidia.com>
> > > Subject: Re: [edk2-devel] [PATCH v2 2/6] RedfishPkg: implement Redfish HTTP
> > > protocol
> > >
> > > External email: Use caution opening links or attachments
> > >
> > >
> > > Hi Nickle,
> > >
> > > %s/Resrouce/Resource/ this comes from RedfishClient autogenerated files...
> > > there are thousands of "Resrouce" typos.
> > >
> > > please, find my minor notes below:
> > >
> > >
> > > On Thu, Feb 22, 2024 at 12:11 PM Nickle Wang via groups.io
> > > <nicklew=nvidia.com@groups.io> wrote:
> > > >
> > > > 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>
> > > > ---
> > > > RedfishPkg/RedfishPkg.dec | 7 +-
> > > > RedfishPkg/RedfishComponents.dsc.inc | 3 +-
> > > > RedfishPkg/RedfishPkg.dsc | 2 +
> > > > RedfishPkg/RedfishHttpDxe/RedfishHttpDxe.inf | 73 +
> > > > RedfishPkg/RedfishHttpDxe/RedfishHttpData.h | 256 ++++
> > > > RedfishPkg/RedfishHttpDxe/RedfishHttpDxe.h | 44 +
> > > > .../RedfishHttpDxe/RedfishHttpOperation.h | 76 +
> > > > RedfishPkg/RedfishHttpDxe/RedfishHttpData.c | 667 ++++++++
> > > > RedfishPkg/RedfishHttpDxe/RedfishHttpDxe.c | 1344 +++++++++++++++++
> > > > .../RedfishHttpDxe/RedfishHttpOperation.c | 693 +++++++++
> > > > RedfishPkg/Redfish.fdf.inc | 3 +-
> > > > 11 files changed, 3164 insertions(+), 4 deletions(-)
> > > > create mode 100644 RedfishPkg/RedfishHttpDxe/RedfishHttpDxe.inf
> > > > create mode 100644 RedfishPkg/RedfishHttpDxe/RedfishHttpData.h
> > > > create mode 100644 RedfishPkg/RedfishHttpDxe/RedfishHttpDxe.h
> > > > create mode 100644 RedfishPkg/RedfishHttpDxe/RedfishHttpOperation.h
> > > > create mode 100644 RedfishPkg/RedfishHttpDxe/RedfishHttpData.c
> > > > create mode 100644 RedfishPkg/RedfishHttpDxe/RedfishHttpDxe.c
> > > > create mode 100644 RedfishPkg/RedfishHttpDxe/RedfishHttpOperation.c
> > > >
> > > > diff --git a/RedfishPkg/RedfishPkg.dec b/RedfishPkg/RedfishPkg.dec
> > > > index 9b424efdf3..114f8d2ad8 100644
> > > > --- a/RedfishPkg/RedfishPkg.dec
> > > > +++ b/RedfishPkg/RedfishPkg.dec
> > > > @@ -157,8 +157,11 @@
> > > > # set to EFI_REST_EX_PROTOCOL.
> > > > #
> > > >
> > >
> gEfiRedfishPkgTokenSpaceGuid.PcdRedfishSendReceiveTimeout|5000|UINT32|0
> > > x00001009
> > > > - ## This is used to enable HTTP content encoding on Redfish
> communication.
> > > > -
> > >
> gEfiRedfishPkgTokenSpaceGuid.PcdRedfishServiceContentEncoding|TRUE|BOOLE
> > > AN|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.
> > > > #
> > > > diff --git a/RedfishPkg/RedfishComponents.dsc.inc
> > > b/RedfishPkg/RedfishComponents.dsc.inc
> > > > index 464ffc8606..d6c5b73d7f 100644
> > > > --- a/RedfishPkg/RedfishComponents.dsc.inc
> > > > +++ b/RedfishPkg/RedfishComponents.dsc.inc
> > > > @@ -7,7 +7,7 @@
> > > > # "RedfishDefines.dsc.inc".
> > > > #
> > > > # (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
> > > > #
> > > > @@ -28,4 +28,5 @@
> > > > RedfishPkg/RedfishConfigHandler/RedfishConfigHandlerDriver.inf
> > > > RedfishPkg/RedfishPlatformConfigDxe/RedfishPlatformConfigDxe.inf
> > > >
> MdeModulePkg/Universal/RegularExpressionDxe/RegularExpressionDxe.inf
> > > > + RedfishPkg/RedfishHttpDxe/RedfishHttpDxe.inf
> > > > !endif
> > > > diff --git a/RedfishPkg/RedfishPkg.dsc b/RedfishPkg/RedfishPkg.dsc
> > > > index 25ed193182..5849e7cf9e 100644
> > > > --- a/RedfishPkg/RedfishPkg.dsc
> > > > +++ b/RedfishPkg/RedfishPkg.dsc
> > > > @@ -45,6 +45,8 @@
> > > >
> > >
> UefiHiiServicesLib|MdeModulePkg/Library/UefiHiiServicesLib/UefiHiiServicesLib.
> > > inf
> > > >
> > >
> RedfishPlatformCredentialLib|RedfishPkg/Library/PlatformCredentialLibNull/Platf
> > > ormCredentialLibNull.inf
> > > >
> > >
> RedfishContentCodingLib|RedfishPkg/Library/RedfishContentCodingLibNull/Redfi
> > > shContentCodingLibNull.inf
> > > > +
> > >
> ReportStatusCodeLib|MdeModulePkg/Library/DxeReportStatusCodeLib/DxeRepo
> > > rtStatusCodeLib.inf
> > > > + SortLib|MdeModulePkg/Library/UefiSortLib/UefiSortLib.inf
> > > >
> > > > # NULL instance of IPMI related library.
> > > > IpmiLib|MdeModulePkg/Library/BaseIpmiLibNull/BaseIpmiLibNull.inf
> > > > diff --git a/RedfishPkg/RedfishHttpDxe/RedfishHttpDxe.inf
> > > b/RedfishPkg/RedfishHttpDxe/RedfishHttpDxe.inf
> > > > new file mode 100644
> > > > index 0000000000..c7dfdffacf
> > > > --- /dev/null
> > > > +++ b/RedfishPkg/RedfishHttpDxe/RedfishHttpDxe.inf
> > > > @@ -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
> > > > diff --git a/RedfishPkg/RedfishHttpDxe/RedfishHttpData.h
> > > b/RedfishPkg/RedfishHttpDxe/RedfishHttpData.h
> > > > new file mode 100644
> > > > index 0000000000..6be610142e
> > > > --- /dev/null
> > > > +++ b/RedfishPkg/RedfishHttpDxe/RedfishHttpData.h
> > > > @@ -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
> > > > diff --git a/RedfishPkg/RedfishHttpDxe/RedfishHttpDxe.h
> > > b/RedfishPkg/RedfishHttpDxe/RedfishHttpDxe.h
> > > > new file mode 100644
> > > > index 0000000000..cf6ba9cb47
> > > > --- /dev/null
> > > > +++ b/RedfishPkg/RedfishHttpDxe/RedfishHttpDxe.h
> > > > @@ -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
> > > > diff --git a/RedfishPkg/RedfishHttpDxe/RedfishHttpOperation.h
> > > b/RedfishPkg/RedfishHttpDxe/RedfishHttpOperation.h
> > > > new file mode 100644
> > > > index 0000000000..d2f7cf4c27
> > > > --- /dev/null
> > > > +++ b/RedfishPkg/RedfishHttpDxe/RedfishHttpOperation.h
> > > > @@ -0,0 +1,76 @@
> > > > +/** @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"
> > > > +
> > > > +/**
> > > > + 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 Resrouce 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 Resrouce 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
> > > > diff --git a/RedfishPkg/RedfishHttpDxe/RedfishHttpData.c
> > > b/RedfishPkg/RedfishHttpDxe/RedfishHttpData.c
> > > > new file mode 100644
> > > > index 0000000000..bf95e9f8d4
> > > > --- /dev/null
> > > > +++ b/RedfishPkg/RedfishHttpDxe/RedfishHttpData.c
> > > > @@ -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 = AllocateCopyPool (AsciiStrSize (Token), 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 = AllocateCopyPool (AsciiStrSize (Host), Host);
> > > > + if (NewService->Host == NULL) {
> > > > + goto ON_ERROR;
> > > > + }
> > > > +
> > > > + NewService->HostName = AllocateCopyPool (AsciiStrSize (HostName),
> > > 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 = AllocateCopyPool (AsciiStrSize
> (SessionToken),
> > > 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);
> > > > +
> > >
> > >
> > > NewPayload->Service is leaked
> > >
> > >
> > > > + 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;
> > > > + }
> > > > +
> > > > + for (Index = 0; Index < SrcResponse->HeaderCount; Index++) {
> > > > + DstResponse->Headers[Index].FieldName = AllocateCopyPool
> (AsciiStrSize
> > > (SrcResponse->Headers[Index].FieldName), SrcResponse-
> > > >Headers[Index].FieldName);
> > > > + if (DstResponse->Headers[Index].FieldName == NULL) {
> > > > + goto ON_ERROR;
> > > > + }
> > > > +
> > > > + DstResponse->Headers[Index].FieldValue = AllocateCopyPool
> (AsciiStrSize
> > > (SrcResponse->Headers[Index].FieldValue), SrcResponse-
> > > >Headers[Index].FieldValue);
> > > > + if (DstResponse->Headers[Index].FieldValue == NULL) {
> > > > + goto ON_ERROR;
> > > > + }
> > > > +
> > > > + DstResponse->HeaderCount += 1;
> > > > + }
> > > > + }
> > > > +
> > > > + //
> > > > + // 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;
> > > > +}
> > > > diff --git a/RedfishPkg/RedfishHttpDxe/RedfishHttpDxe.c
> > > b/RedfishPkg/RedfishHttpDxe/RedfishHttpDxe.c
> > > > new file mode 100644
> > > > index 0000000000..39958d4865
> > > > --- /dev/null
> > > > +++ b/RedfishPkg/RedfishHttpDxe/RedfishHttpDxe.c
> > > > @@ -0,0 +1,1344 @@
> > > > +/** @file
> > > > + RedfishHttpDxe produces EdkIIRedfishHttpProtocol
> > > > + for EDK2 Redfish Feature driver to do HTTP operations.
> > > > +
> > > > + Copyright (c) 2023-2024, NVIDIA CORPORATION & AFFILIATES. All rights
> > > reserved.
> > > > +
> > > > + SPDX-License-Identifier: BSD-2-Clause-Patent
> > > > +
> > > > +**/
> > > > +
> > > > +#include "RedfishHttpDxe.h"
> > > > +#include "RedfishHttpData.h"
> > > > +#include "RedfishHttpOperation.h"
> > > > +
> > > > +REDFISH_HTTP_CACHE_PRIVATE *mRedfishHttpCachePrivate = NULL;
> > > > +
> > > > +/**
> > > > + Debug output the cache list.
> > > > +
> > > > + @param[in] Msg Debug message string.
> > > > + @param[in] ErrorLevel Output error level.
> > > > + @param[in] CacheList Target list to dump.
> > > > +
> > > > + @retval EFI_SUCCESS Debug dump finished.
> > > > + @retval EFI_INVALID_PARAMETER HttpCacheList is NULL.
> > > > +
> > > > +**/
> > > > +EFI_STATUS
> > > > +DebugPrintHttpCacheList (
> > > > + IN CONST CHAR8 *Msg,
> > > > + IN UINTN ErrorLevel,
> > > > + IN REDFISH_HTTP_CACHE_LIST *CacheList
> > > > + )
> > > > +{
> > > > + LIST_ENTRY *List;
> > > > + REDFISH_HTTP_CACHE_DATA *Data;
> > > > + UINTN Index;
> > > > +
> > > > + if (CacheList == NULL) {
> > > > + return EFI_INVALID_PARAMETER;
> > > > + }
> > > > +
> > > > + if (!IS_EMPTY_STRING (Msg)) {
> > > > + DEBUG ((ErrorLevel, "%a\n", Msg));
> > > > + }
> > > > +
> > > > + if (IsListEmpty (&CacheList->Head)) {
> > > > + DEBUG ((ErrorLevel, "list is empty\n"));
> > > > + return EFI_NOT_FOUND;
> > > > + }
> > > > +
> > > > + DEBUG ((ErrorLevel, "list count: %d capacity: %d\n", CacheList->Count,
> > > CacheList->Capacity));
> > > > + Data = NULL;
> > > > + Index = 0;
> > > > + List = GetFirstNode (&CacheList->Head);
> > > > + while (!IsNull (&CacheList->Head, List)) {
> > > > + Data = REDFISH_HTTP_CACHE_FROM_LIST (List);
> > > > +
> > > > + DEBUG ((ErrorLevel, "%d) Uri: %s Hit: %d\n", ++Index, Data->Uri, Data-
> > > >HitCount));
> > > > +
> > > > + List = GetNextNode (&CacheList->Head, List);
> > > > + }
> > > > +
> > > > + return EFI_SUCCESS;
> > > > +}
> > > > +
> > > > +/**
> > > > +
> > > > + Check HTTP status code to see if we like to retry HTTP request or not.
> > > > +
> > > > + @param[in] StatusCode HTTP status code.
> > > > +
> > > > + @retval BOOLEAN Return true when we like to retry request.
> > > > + Return false when we don't want to retry request.
> > > > +
> > > > +**/
> > > > +BOOLEAN
> > > > +RedfishRetryRequired (
> > > > + IN EFI_HTTP_STATUS_CODE *StatusCode
> > > > + )
> > > > +{
> > > > + if (StatusCode == NULL) {
> > > > + return TRUE;
> > > > + }
> > > > +
> > > > + if ((*StatusCode == HTTP_STATUS_500_INTERNAL_SERVER_ERROR) ||
> > > > + (*StatusCode == HTTP_STATUS_UNSUPPORTED_STATUS))
> > > > + {
> > > > + return TRUE;
> > > > + }
> > > > +
> > > > + return FALSE;
> > > > +}
> > > > +
> > > > +/**
> > > > +
> > > > + Convert Unicode string to ASCII string. It's call responsibility to release
> > > returned buffer.
> > > > +
> > > > + @param[in] UnicodeStr Unicode string to convert.
> > > > +
> > > > + @retval CHAR8 * ASCII string returned.
> > > > + @retval NULL Errors occur.
> > > > +
> > > > +**/
> > > > +CHAR8 *
> > > > +StringUnicodeToAscii (
> > > > + IN EFI_STRING UnicodeStr
> > > > + )
> > > > +{
> > > > + CHAR8 *AsciiStr;
> > > > + UINTN AsciiStrSize;
> > > > + EFI_STATUS Status;
> > > > +
> > > > + if (IS_EMPTY_STRING (UnicodeStr)) {
> > > > + return NULL;
> > > > + }
> > > > +
> > > > + AsciiStrSize = StrLen (UnicodeStr) + 1;
> > > > + AsciiStr = AllocateZeroPool (AsciiStrSize);
> > > > + if (AsciiStr == NULL) {
> > > > + return NULL;
> > > > + }
> > > > +
> > > > + Status = UnicodeStrToAsciiStrS (UnicodeStr, AsciiStr, AsciiStrSize);
> > > > + if (EFI_ERROR (Status)) {
> > > > + DEBUG ((DEBUG_ERROR, "UnicodeStrToAsciiStrS failed: %r\n", Status));
> > > > + FreePool (AsciiStr);
> > > > + return NULL;
> > > > + }
> > > > +
> > > > + return AsciiStr;
> > > > +}
> > > > +
> > > > +/**
> > > > + Return HTTP method in ASCII string. Caller does not need
> > > > + to free returned string buffer.
> > > > +
> > > > + @param[in] Method HTTP method.
> > > > +
> > > > + @retval CHAR8 * Method in string.
> > > > +**/
> > > > +CHAR8 *
> > > > +HttpMethodToString (
> > > > + IN EFI_HTTP_METHOD Method
> > > > + )
> > > > +{
> > > > + switch (Method) {
> > > > + case HttpMethodGet:
> > > > + return HTTP_METHOD_GET;
> > > > + break;
> > > > + case HttpMethodPost:
> > > > + return HTTP_METHOD_POST;
> > > > + break;
> > > > + case HttpMethodPatch:
> > > > + return HTTP_METHOD_PATCH;
> > > > + break;
> > > > + case HttpMethodPut:
> > > > + return HTTP_METHOD_PUT;
> > > > + break;
> > > > + case HttpMethodDelete:
> > > > + return HTTP_METHOD_DELETE;
> > > > + break;
> > > > + default:
> > > > + break;
> > > > + }
> > > > +
> > > > + return "Unknown";
> > > > +}
> > > > +
> > > > +/**
> > > > + Report HTTP communication error via report status code.
> > > > +
> > > > + @param[in] Method HTTP method.
> > > > + @param[in] Uri The URI which has failure.
> > > > + @param[in] HttpStatusCode HTTP status code.
> > > > +
> > > > +**/
> > > > +VOID
> > > > +ReportHttpError (
> > > > + IN EFI_HTTP_METHOD Method,
> > > > + IN EFI_STRING Uri,
> > > > + IN EFI_HTTP_STATUS_CODE *HttpStatusCode OPTIONAL
> > > > + )
> > > > +{
> > > > + CHAR8 ErrorMsg[REDFISH_ERROR_MSG_MAX];
> > > > +
> > > > + if (IS_EMPTY_STRING (Uri)) {
> > > > + DEBUG ((DEBUG_ERROR, "%a: no URI to report error status\n",
> __func__));
> > > > + return;
> > > > + }
> > > > +
> > > > + //
> > > > + // Report failure of URI and HTTP status code.
> > > > + //
> > > > + AsciiSPrint (ErrorMsg, sizeof (ErrorMsg), REDFISH_HTTP_ERROR_REPORT,
> > > HttpMethodToString (Method), (HttpStatusCode == NULL ?
> > > HTTP_STATUS_UNSUPPORTED_STATUS : *HttpStatusCode), Uri);
> > > > + DEBUG ((DEBUG_ERROR, "%a\n", ErrorMsg));
> > > > + //
> > > > + // TODO:
> > > > + // Below PI status code is approved by PIWG and wait for specification
> > > published.
> > > > + // We will uncomment below report status code after PI status code get
> > > published.
> > > > + // REF:
> > >
> https://bugzilla.ti/
> %2F&data=05%7C02%7Cnicklew%40nvidia.com%7Cb82203c2d6124060850308d
> c34894020%7C43083d15727340c1b7db39efd9ccc17a%7C0%7C0%7C638443011
> 350942592%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLjAwMDAiLCJQIjoiV2
> luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C0%7C%7C%7C&sdata=PbXKoTXf7
> HRXt7q1qhRbtmwEqAisA1qeblTN5GUMPe8%3D&reserved=0
> > >
> anocore.org%2Fshow_bug.cgi%3Fid%3D4483&data=05%7C02%7Cnicklew%40nvi
> > >
> dia.com%7Cf659c54c3edb43527c3608dc3462ab2a%7C43083d15727340c1b7db
> > >
> 39efd9ccc17a%7C0%7C0%7C638442845601051396%7CUnknown%7CTWFpbGZs
> > >
> b3d8eyJWIjoiMC4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%
> > >
> 3D%7C0%7C%7C%7C&sdata=T1bN7KmTa1v49cOFkd9%2F9hlzkdzbHPLebxSiUkp
> > > VuU4%3D&reserved=0
> > > > + //
> > > > + // REPORT_STATUS_CODE_WITH_EXTENDED_DATA (
> > > > + // EFI_ERROR_CODE | EFI_ERROR_MAJOR,
> > > > + // EFI_COMPUTING_UNIT_MANAGEABILITY |
> > > EFI_MANAGEABILITY_EC_REDFISH_COMMUNICATION_ERROR,
> > > > + // ErrorMsg,
> > > > + // AsciiStrSize (ErrorMsg)
> > > > + // );
> > > > +}
> > > > +
> > > > +/**
> > > > + This function create Redfish service. It's caller's responsibility to free
> returned
> > > > + Redfish service by calling FreeService ().
> > > > +
> > > > + @param[in] This Pointer to
> EDKII_REDFISH_HTTP_PROTOCOL
> > > instance.
> > > > + @param[in] RedfishConfigServiceInfo Redfish config service
> information.
> > > > +
> > > > + @retval REDFISH_SERVICE Redfish service is created.
> > > > + @retval NULL Errors occur.
> > > > +
> > > > +**/
> > > > +REDFISH_SERVICE
> > > > +EFIAPI
> > > > +RedfishCreateRedfishService (
> > > > + IN EDKII_REDFISH_HTTP_PROTOCOL *This,
> > > > + IN REDFISH_CONFIG_SERVICE_INFORMATION
> *RedfishConfigServiceInfo
> > > > + )
> > > > +{
> > > > + EFI_STATUS Status;
> > > > + REDFISH_HTTP_CACHE_PRIVATE *Private;
> > > > + REDFISH_SERVICE_PRIVATE *NewService;
> > > > + CHAR8 *AsciiLocation;
> > > > + CHAR8 *Host;
> > > > + CHAR8 *BasicAuthString;
> > > > + UINTN BasicAuthStrSize;
> > > > + CHAR8 *EncodedAuthString;
> > > > + UINTN EncodedAuthStrSize;
> > > > + EDKII_REDFISH_AUTH_METHOD AuthMethod;
> > > > + CHAR8 *Username;
> > > > + CHAR8 *Password;
> > > > + UINTN UsernameSize;
> > > > + UINTN PasswordSize;
> > > > + EFI_REST_EX_PROTOCOL *RestEx;
> > > > +
> > > > + if ((This == NULL) || (RedfishConfigServiceInfo == NULL)) {
> > > > + return NULL;
> > > > + }
> > > > +
> > > > + DEBUG ((REDFISH_HTTP_CACHE_DEBUG, "%a: service location: %s\n",
> > > __func__, RedfishConfigServiceInfo->RedfishServiceLocation));
> > > > +
> > > > + Private = REDFISH_HTTP_CACHE_PRIVATE_FROM_THIS (This);
> > > > + BasicAuthString = NULL;
> > > > + EncodedAuthString = NULL;
> > > > + Username = NULL;
> > > > + Password = NULL;
> > > > + NewService = NULL;
> > > > + AsciiLocation = NULL;
> > > > + Host = NULL;
> > > > + BasicAuthStrSize = 0;
> > > > + EncodedAuthStrSize = 0;
> > > > + UsernameSize = 0;
> > > > + PasswordSize = 0;
> > > > +
> > > > + //
> > > > + // Build host and host name from service location
> > > > + //
> > > > + if (!IS_EMPTY_STRING (RedfishConfigServiceInfo-
> >RedfishServiceLocation)) {
> > > > + AsciiLocation = StringUnicodeToAscii (RedfishConfigServiceInfo-
> > > >RedfishServiceLocation);
> > > > + if (AsciiLocation == NULL) {
> > > > + goto ON_RELEASE;
> > > > + }
> > > > +
> > > > + Host = AllocateZeroPool (REDFISH_HOST_NAME_MAX);
> > > > + if (AsciiLocation == NULL) {
> > > > + goto ON_RELEASE;
> > > > + }
> > > > +
> > > > + if (RedfishConfigServiceInfo->RedfishServiceUseHttps) {
> > > > + AsciiSPrint (Host, REDFISH_HOST_NAME_MAX, "https://%a",
> > > AsciiLocation);
> > > > + } else {
> > > > + AsciiSPrint (Host, REDFISH_HOST_NAME_MAX, "http://%a",
> AsciiLocation);
> > > > + }
> > > > +
> > > > + DEBUG ((REDFISH_HTTP_CACHE_DEBUG, "%a: Host: %a\n", __func__,
> > > Host));
> > > > + }
> > > > +
> > > > + //
> > > > + // Find Rest Ex protocol
> > > > + //
> > > > + if (RedfishConfigServiceInfo->RedfishServiceRestExHandle != NULL) {
> > > > + Status = gBS->HandleProtocol (
> > > > + RedfishConfigServiceInfo->RedfishServiceRestExHandle,
> > > > + &gEfiRestExProtocolGuid,
> > > > + (VOID **)&RestEx
> > > > + );
> > > > + } else {
> > > > + DEBUG ((DEBUG_ERROR, "%a: Rest Ex protocol is not available\n",
> > > __func__));
> > > > + goto ON_RELEASE;
> > > > + }
> > > > +
> > > > + //
> > > > + // Get credential
> > > > + //
> > > > + if (Private->CredentialProtocol == NULL) {
> > > > + //
> > > > + // No credential available on this system.
> > > > + //
> > > > + DEBUG ((DEBUG_WARN, "%a: no credential protocol available\n",
> > > __func__));
> > > > + } else {
> > > > + Status = Private->CredentialProtocol->GetAuthInfo (
> > > > + Private->CredentialProtocol,
> > > > + &AuthMethod,
> > > > + &Username,
> > > > + &Password
> > > > + );
> > > > + if (EFI_ERROR (Status) || IS_EMPTY_STRING (Username) ||
> > > IS_EMPTY_STRING (Password)) {
> > > > + DEBUG ((DEBUG_ERROR, "%a: cannot get authentication information:
> > > %r\n", __func__, Status));
> > > > + goto ON_RELEASE;
> > > > + } else {
> > > > + DEBUG ((REDFISH_HTTP_CACHE_DEBUG, "%a: Auth method: 0x%x
> > > username: %a password: %a\n", __func__, AuthMethod, Username,
> Password));
> > > > +
> > > > + //
> > > > + // Perform base64 encoding (RFC 7617)
> > > > + //
> > > > + UsernameSize = AsciiStrSize (Username);
> > > > + PasswordSize = AsciiStrSize (Password);
> > > > + BasicAuthStrSize = UsernameSize + PasswordSize; // one byte taken
> from
> > > null-terminator for ':'
> > > > + BasicAuthString = AllocateZeroPool (BasicAuthStrSize);
> > > > + if (BasicAuthString == NULL) {
> > > > + goto ON_RELEASE;
> > > > + }
> > > > +
> > > > + AsciiSPrint (
> > > > + BasicAuthString,
> > > > + BasicAuthStrSize,
> > > > + "%a:%a",
> > > > + Username,
> > > > + Password
> > > > + );
> > > > +
> > > > + Status = Base64Encode (
> > > > + (CONST UINT8 *)BasicAuthString,
> > > > + BasicAuthStrSize,
> > > > + EncodedAuthString,
> > > > + &EncodedAuthStrSize
> > > > + );
> > > > + if ((Status == EFI_BUFFER_TOO_SMALL) && (EncodedAuthStrSize > 0)) {
> > > > + EncodedAuthString = AllocateZeroPool (EncodedAuthStrSize);
> > > > + if (EncodedAuthString == NULL) {
> > > > + goto ON_RELEASE;
> > > > + }
> > > > +
> > > > + Status = Base64Encode (
> > > > + (CONST UINT8 *)BasicAuthString,
> > > > + BasicAuthStrSize,
> > > > + EncodedAuthString,
> > > > + &EncodedAuthStrSize
> > > > + );
> > > > + if (EFI_ERROR (Status)) {
> > > > + DEBUG ((DEBUG_ERROR, "%a: Base64Encode failure: %r\n",
> __func__,
> > > Status));
> > > > + }
> > > > +
> > > > + DEBUG ((REDFISH_HTTP_CACHE_DEBUG, "%a: Basic authorization:
> > > %a\n", __func__, EncodedAuthString));
> > > > + } else {
> > > > + DEBUG ((DEBUG_ERROR, "%a: Base64Encode failure: %r\n",
> __func__,
> > > Status));
> > > > + goto ON_RELEASE;
> > > > + }
> > > > + }
> > > > + }
> > > > +
> > > > + NewService = CreateRedfishService (Host, AsciiLocation,
> EncodedAuthString,
> > > NULL, RestEx);
> > > > + if (NewService == NULL) {
> > > > + DEBUG ((DEBUG_ERROR, "%a: CreateRedfishService\n", __func__));
> > > > + }
> > > > +
> > > > +ON_RELEASE:
> > > > +
> > > > + if (BasicAuthString != NULL) {
> > > > + ZeroMem (BasicAuthString, BasicAuthStrSize);
> > > > + FreePool (BasicAuthString);
> > > > + }
> > > > +
> > > > + if (EncodedAuthString != NULL) {
> > > > + ZeroMem (BasicAuthString, EncodedAuthStrSize);
> > > > + FreePool (EncodedAuthString);
> > > > + }
> > > > +
> > > > + if (Username != NULL) {
> > > > + ZeroMem (Username, UsernameSize);
> > > > + FreePool (Username);
> > > > + }
> > > > +
> > > > + if (Password != NULL) {
> > > > + ZeroMem (Password, PasswordSize);
> > > > + FreePool (Password);
> > > > + }
> > > > +
> > > > + if (AsciiLocation != NULL) {
> > > > + FreePool (AsciiLocation);
> > > > + }
> > > > +
> > > > + if (Host != NULL) {
> > > > + FreePool (Host);
> > > > + }
> > > > +
> > > > + return NewService;
> > > > +}
> > > > +
> > > > +/**
> > > > + This function free resources in Redfish service. RedfishService is no longer
> > > available
> > > > + after this function returns successfully.
> > > > +
> > > > + @param[in] This Pointer to EDKII_REDFISH_HTTP_PROTOCOL
> > > instance.
> > > > + @param[in] RedfishService Pointer to Redfish service to be released.
> > > > +
> > > > + @retval EFI_SUCCESS Resrouce is released successfully.
> > > > + @retval Others Errors occur.
> > > > +
> > > > +**/
> > > > +EFI_STATUS
> > > > +EFIAPI
> > > > +RedfishFreeRedfishService (
> > > > + IN EDKII_REDFISH_HTTP_PROTOCOL *This,
> > > > + IN REDFISH_SERVICE RedfishService
> > > > + )
> > > > +{
> > > > + REDFISH_SERVICE_PRIVATE *Service;
> > > > +
> > > > + if ((This == NULL) || (RedfishService == NULL)) {
> > > > + return EFI_INVALID_PARAMETER;
> > > > + }
> > > > +
> > > > + Service = (REDFISH_SERVICE_PRIVATE *)RedfishService;
> > > > + if (Service->Signature != REDFISH_HTTP_SERVICE_SIGNATURE) {
> > > > + DEBUG ((DEBUG_ERROR, "%a: signature check failure\n", __func__));
> > > > + }
> > > > +
> > > > + return ReleaseRedfishService (Service);
> > > > +}
> > > > +
> > > > +/**
> > > > + This function returns JSON value in given RedfishPayload. Returned JSON
> > > value
> > > > + is a reference to the JSON value in RedfishPayload. Any modification to
> > > returned
> > > > + JSON value will change JSON value in RedfishPayload.
> > > > +
> > > > + @param[in] This Pointer to EDKII_REDFISH_HTTP_PROTOCOL
> > > instance.
> > > > + @param[in] RedfishPayload Pointer to Redfish payload.
> > > > +
> > > > + @retval EDKII_JSON_VALUE JSON value is returned.
> > > > + @retval NULL Errors occur.
> > > > +
> > > > +**/
> > > > +EDKII_JSON_VALUE
> > > > +EFIAPI
> > > > +RedfishJsonInRedfishPayload (
> > > > + IN EDKII_REDFISH_HTTP_PROTOCOL *This,
> > > > + IN REDFISH_PAYLOAD RedfishPayload
> > > > + )
> > > > +{
> > > > + REDFISH_PAYLOAD_PRIVATE *Payload;
> > > > +
> > > > + if ((This == NULL) || (RedfishPayload == NULL)) {
> > > > + return NULL;
> > > > + }
> > > > +
> > > > + Payload = (REDFISH_PAYLOAD_PRIVATE *)RedfishPayload;
> > > > + if (Payload->Signature != REDFISH_HTTP_PAYLOAD_SIGNATURE) {
> > > > + DEBUG ((DEBUG_ERROR, "%a: signature check failure\n", __func__));
> > > > + }
> > > > +
> > > > + return Payload->JsonValue;
> > > > +}
> > > > +
> > > > +/**
> > > > + Perform HTTP GET to Get redfish resource from given resource URI with
> > > > + cache mechanism supported. It's caller's responsibility to free Response
> > > > + by calling FreeResponse ().
> > > > +
> > > > + @param[in] This Pointer to EDKII_REDFISH_HTTP_PROTOCOL
> instance.
> > > > + @param[in] Service Redfish service instance to perform HTTP GET.
> > > > + @param[in] Uri Target resource URI.
> > > > + @param[in] Request Additional request context. This is optional.
> > > > + @param[out] Response HTTP response from redfish service.
> > > > + @param[in] UseCache If it is TRUE, this function will search for
> > > > + cache first. If it is FALSE, this function
> > > > + will query Redfish URI directly.
> > > > +
> > > > + @retval EFI_SUCCESS Resrouce is returned successfully.
> > > > + @retval Others Errors occur.
> > > > +
> > > > +**/
> > > > +EFI_STATUS
> > > > +EFIAPI
> > > > +RedfishGetResource (
> > > > + IN EDKII_REDFISH_HTTP_PROTOCOL *This,
> > > > + IN REDFISH_SERVICE Service,
> > > > + IN EFI_STRING Uri,
> > > > + IN REDFISH_REQUEST *Request OPTIONAL,
> > > > + OUT REDFISH_RESPONSE *Response,
> > > > + IN BOOLEAN UseCache
> > > > + )
> > > > +{
> > > > + EFI_STATUS Status;
> > > > + REDFISH_HTTP_CACHE_DATA *CacheData;
> > > > + UINTN RetryCount;
> > > > + REDFISH_HTTP_CACHE_PRIVATE *Private;
> > > > +
> > > > + if ((This == NULL) || (Service == NULL) || (Response == NULL) ||
> > > IS_EMPTY_STRING (Uri)) {
> > > > + return EFI_INVALID_PARAMETER;
> > > > + }
> > > > +
> > > > + DEBUG ((REDFISH_HTTP_CACHE_DEBUG, "%a: Get URI: %s cache:
> %a\n",
> > > __func__, Uri, (UseCache ? "true" : "false")));
> > > > +
> > > > + Private = REDFISH_HTTP_CACHE_PRIVATE_FROM_THIS (This);
> > > > + CacheData = NULL;
> > > > + RetryCount = 0;
> > > > + ZeroMem (Response, sizeof (REDFISH_RESPONSE));
> > > > +
> > > > + if (Private->CacheDisabled) {
> > > > + UseCache = FALSE;
> > > > + DEBUG ((REDFISH_HTTP_CACHE_DEBUG, "%a: cache is disabled by
> > > PCD!\n", __func__));
> > > > + }
> > > > +
> > > > + //
> > > > + // Search for cache list.
> > > > + //
> > > > + if (UseCache) {
> > > > + CacheData = FindHttpCacheData (&Private->CacheList.Head, Uri);
> > > > + if (CacheData != NULL) {
> > > > + DEBUG ((REDFISH_HTTP_CACHE_DEBUG_REQUEST, "%a: cache hit!
> %s\n",
> > > __func__, Uri));
> > > > +
> > > > + //
> > > > + // Copy cached response to caller's buffer.
> > > > + //
> > > > + Status = CopyRedfishResponse (CacheData->Response,
> Response);
> > > > + CacheData->HitCount += 1;
> > > > + return Status;
> > > > + }
> > > > + }
> > > > +
> > > > + //
> > > > + // Get resource from redfish service.
> > > > + //
> > > > + do {
> > > > + RetryCount += 1;
> > > > + Status = HttpSendReceive (
> > > > + Service,
> > > > + Uri,
> > > > + HttpMethodGet,
> > > > + Request,
> > > > + Response
> > > > + );
> > > > + DEBUG ((REDFISH_HTTP_CACHE_DEBUG_REQUEST, "%a: HTTP request:
> > > %s :%r\n", __func__, Uri, Status));
> > > > + if (!EFI_ERROR (Status) || (RetryCount >= Private-
> > > >RetrySetting.MaximumRetryGet)) {
> > > > + break;
> > > > + }
> > > > +
> > > > + //
> > > > + // Retry when BMC is not ready.
> > > > + //
> > > > + if ((Response->StatusCode != NULL)) {
> > > > + DEBUG_CODE (
> > > > + DumpRedfishResponse (NULL, DEBUG_ERROR, Response);
> > > > + );
> > > > +
> > > > + if (!RedfishRetryRequired (Response->StatusCode)) {
> > > > + break;
> > > > + }
> > > > +
> > > > + //
> > > > + // Release response for next round of request.
> > > > + //
> > > > + This->FreeResponse (This, Response);
> > > > + }
> > > > +
> > > > + DEBUG ((DEBUG_WARN, "%a: RedfishGetByUriEx failed, retry
> (%d/%d)\n",
> > > __func__, RetryCount, Private->RetrySetting.MaximumRetryGet));
> > > > + if (Private->RetrySetting.RetryWait > 0) {
> > > > + gBS->Stall (Private->RetrySetting.RetryWait);
> > > > + }
> > > > + } while (TRUE);
> > > > +
> > > > + if (EFI_ERROR (Status)) {
> > > > + DEBUG_CODE (
> > > > + DumpRedfishResponse (NULL, DEBUG_ERROR, Response);
> > > > + );
> > > > + //
> > > > + // Report status code for Redfish failure
> > > > + //
> > > > + ReportHttpError (HttpMethodGet, Uri, Response->StatusCode);
> > > > + DEBUG ((DEBUG_ERROR, "%a: get %s failed (%d/%d): %r\n", __func__,
> Uri,
> > > RetryCount, Private->RetrySetting.MaximumRetryGet, Status));
> > > > + goto ON_RELEASE;
> > > > + }
> > > > +
> > > > + if (!Private->CacheDisabled) {
> > > > + //
> > > > + // Keep response in cache list
> > > > + //
> > > > + Status = AddHttpCacheData (&Private->CacheList, Uri, Response);
> > > > + if (EFI_ERROR (Status)) {
> > > > + DEBUG ((DEBUG_ERROR, "%a: failed to cache %s: %r\n", __func__, Uri,
> > > Status));
> > > > + goto ON_RELEASE;
> > > > + }
> > > > +
> > > > + DEBUG_CODE (
> > > > + DebugPrintHttpCacheList (__func__,
> > > REDFISH_HTTP_CACHE_DEBUG_DUMP, &Private->CacheList);
> > > > + );
> > > > + }
> > > > +
> > > > +ON_RELEASE:
> > > > +
> > > > + return Status;
> > > > +}
> > > > +
> > > > +/**
> > > > + This function free resources in Request. Request is no longer available
> > > > + after this function returns successfully.
> > > > +
> > > > + @param[in] This Pointer to EDKII_REDFISH_HTTP_PROTOCOL
> instance.
> > > > + @param[in] Request HTTP request to be released.
> > > > +
> > > > + @retval EFI_SUCCESS Resrouce is released successfully.
> > > > + @retval Others Errors occur.
> > > > +
> > > > +**/
> > > > +EFI_STATUS
> > > > +EFIAPI
> > > > +RedfishFreeRequest (
> > > > + IN EDKII_REDFISH_HTTP_PROTOCOL *This,
> > > > + IN REDFISH_REQUEST *Request
> > > > + )
> > > > +{
> > > > + if ((This == NULL) || (Request == NULL)) {
> > > > + return EFI_INVALID_PARAMETER;
> > > > + }
> > > > +
> > > > + DEBUG ((REDFISH_HTTP_CACHE_DEBUG, "%a: entry\n", __func__));
> > > > +
> > > > + return ReleaseRedfishRequest (Request);
> > > > +}
> > > > +
> > > > +/**
> > > > + This function free resources in given Response.
> > > > +
> > > > + @param[in] This Pointer to EDKII_REDFISH_HTTP_PROTOCOL
> instance.
> > > > + @param[in] Response HTTP response to be released.
> > > > +
> > > > + @retval EFI_SUCCESS Resrouce is released successfully.
> > > > + @retval Others Errors occur.
> > > > +
> > > > +**/
> > > > +EFI_STATUS
> > > > +EFIAPI
> > > > +RedfishFreeResponse (
> > > > + IN EDKII_REDFISH_HTTP_PROTOCOL *This,
> > > > + IN REDFISH_RESPONSE *Response
> > > > + )
> > > > +{
> > > > + if ((This == NULL) || (Response == NULL)) {
> > > > + return EFI_INVALID_PARAMETER;
> > > > + }
> > > > +
> > > > + DEBUG ((REDFISH_HTTP_CACHE_DEBUG, "%a: entry\n", __func__));
> > > > +
> > > > + return ReleaseRedfishResponse (Response);
> > > > +}
> > > > +
> > > > +/**
> > > > + This function expire the cached response of given URI.
> > > > +
> > > > + @param[in] This Pointer to EDKII_REDFISH_HTTP_PROTOCOL
> instance.
> > > > + @param[in] Uri Target response of URI.
> > > > +
> > > > + @retval EFI_SUCCESS Target response is expired successfully.
> > > > + @retval Others Errors occur.
> > > > +
> > > > +**/
> > > > +EFI_STATUS
> > > > +EFIAPI
> > > > +RedfishExpireResponse (
> > > > + IN EDKII_REDFISH_HTTP_PROTOCOL *This,
> > > > + IN EFI_STRING Uri
> > > > + )
> > > > +{
> > > > + REDFISH_HTTP_CACHE_PRIVATE *Private;
> > > > + REDFISH_HTTP_CACHE_DATA *CacheData;
> > > > +
> > > > + if ((This == NULL) || IS_EMPTY_STRING (Uri)) {
> > > > + return EFI_INVALID_PARAMETER;
> > > > + }
> > > > +
> > > > + DEBUG ((REDFISH_HTTP_CACHE_DEBUG, "%a: expire URI: %s\n",
> __func__,
> > > Uri));
> > > > +
> > > > + Private = REDFISH_HTTP_CACHE_PRIVATE_FROM_THIS (This);
> > > > +
> > > > + CacheData = FindHttpCacheData (&Private->CacheList.Head, Uri);
> > > > + if (CacheData == NULL) {
> > > > + return EFI_NOT_FOUND;
> > > > + }
> > > > +
> > > > + return DeleteHttpCacheData (&Private->CacheList, CacheData);
> > > > +}
> > > > +
> > > > +/**
> > > > + Perform HTTP PATCH to send redfish resource to given resource URI.
> > > > + It's caller's responsibility to free Response by calling FreeResponse ().
> > > > +
> > > > + @param[in] This Pointer to EDKII_REDFISH_HTTP_PROTOCOL
> instance.
> > > > + @param[in] Service Redfish service instance to perform HTTP PATCH.
> > > > + @param[in] Uri Target resource URI.
> > > > + @param[in] Content Data to patch.
> > > > + @param[in] ContentSize Size of the Content to be send to Redfish
> service.
> > > > + This is optional. When ContentSize is 0, ContentSize
> > > > + is the size of Content.
> > > > + @param[in] ContentType Type of the Content to be send to Redfish
> service.
> > > > + This is optional. When ContentType is NULL, content
> > > > + type HTTP_CONTENT_TYPE_APP_JSON will be used.
> > > > + @param[out] Response HTTP response from redfish service.
> > > > +
> > > > + @retval EFI_SUCCESS Resrouce is returned successfully.
> > > > + @retval Others Errors occur.
> > > > +
> > > > +**/
> > > > +EFI_STATUS
> > > > +EFIAPI
> > > > +RedfishPatchResource (
> > > > + IN EDKII_REDFISH_HTTP_PROTOCOL *This,
> > > > + IN REDFISH_SERVICE Service,
> > > > + IN EFI_STRING Uri,
> > > > + IN CHAR8 *Content,
> > > > + IN UINTN ContentSize OPTIONAL,
> > > > + IN CHAR8 *ContentType OPTIONAL,
> > > > + OUT REDFISH_RESPONSE *Response
> > > > + )
> > > > +{
> > > > + EFI_STATUS Status;
> > > > + UINTN RetryCount;
> > > > + REDFISH_REQUEST Request;
> > > > + REDFISH_HTTP_CACHE_PRIVATE *Private;
> > > > +
> > > > + if ((This == NULL) || (Service == NULL) || (Response == NULL) ||
> > > IS_EMPTY_STRING (Uri) || IS_EMPTY_STRING (Content)) {
> > > > + return EFI_INVALID_PARAMETER;
> > > > + }
> > > > +
> > > > + DEBUG ((REDFISH_HTTP_CACHE_DEBUG, "%a: Patch URI: %s\n",
> __func__,
> > > Uri));
> > > > +
> > > > + Private = REDFISH_HTTP_CACHE_PRIVATE_FROM_THIS (This);
> > > > + RetryCount = 0;
> > > > + ZeroMem (Response, sizeof (REDFISH_RESPONSE));
> > > > + ZeroMem (&Request, sizeof (REDFISH_REQUEST));
> > > > +
> > > > + Request.Content = Content;
> > > > + Request.ContentLength = ContentSize;
> > > > + Request.ContentType = ContentType;
> > > > +
> > > > + //
> > > > + // Patch resource to redfish service.
> > > > + //
> > > > + do {
> > > > + RetryCount += 1;
> > > > + Status = HttpSendReceive (
> > > > + Service,
> > > > + Uri,
> > > > + HttpMethodPatch,
> > > > + &Request,
> > > > + Response
> > > > + );
> > > > + DEBUG ((REDFISH_HTTP_CACHE_DEBUG_REQUEST, "%a: HTTP request:
> > > %s :%r\n", __func__, Uri, Status));
> > > > + if (!EFI_ERROR (Status) || (RetryCount >= Private-
> > > >RetrySetting.MaximumRetryPatch)) {
> > > > + break;
> > > > + }
> > > > +
> > > > + //
> > > > + // Retry when BMC is not ready.
> > > > + //
> > > > + if ((Response->StatusCode != NULL)) {
> > > > + DEBUG_CODE (
> > > > + DumpRedfishResponse (NULL, DEBUG_ERROR, Response);
> > > > + );
> > > > +
> > > > + if (!RedfishRetryRequired (Response->StatusCode)) {
> > > > + break;
> > > > + }
> > > > +
> > > > + //
> > > > + // Release response for next round of request.
> > > > + //
> > > > + This->FreeResponse (This, Response);
> > > > + }
> > > > +
> > > > + DEBUG ((DEBUG_WARN, "%a: RedfishPatchToUriEx failed, retry
> (%d/%d)\n",
> > > __func__, RetryCount, Private->RetrySetting.MaximumRetryPatch));
> > > > + if (Private->RetrySetting.RetryWait > 0) {
> > > > + gBS->Stall (Private->RetrySetting.RetryWait);
> > > > + }
> > > > + } while (TRUE);
> > > > +
> > > > + //
> > > > + // Redfish resource is updated. Automatically expire the cached response
> > > > + // so application can directly get resource from Redfish service again.
> > > > + //
> > > > + DEBUG ((REDFISH_HTTP_CACHE_DEBUG, "%a: Resource is updated,
> expire
> > > URI: %s\n", __func__, Uri));
> > > > + RedfishExpireResponse (This, Uri);
> > > > +
> > > > + if (EFI_ERROR (Status)) {
> > > > + DEBUG_CODE (
> > > > + DumpRedfishResponse (NULL, DEBUG_ERROR, Response);
> > > > + );
> > > > + //
> > > > + // Report status code for Redfish failure
> > > > + //
> > > > + ReportHttpError (HttpMethodPatch, Uri, Response->StatusCode);
> > > > + DEBUG ((DEBUG_ERROR, "%a: patch %s failed (%d/%d): %r\n",
> __func__,
> > > Uri, RetryCount, Private->RetrySetting.MaximumRetryPatch, Status));
> > > > + goto ON_RELEASE;
> > > > + }
> > > > +
> > > > +ON_RELEASE:
> > > > +
> > > > + return Status;
> > > > +}
> > > > +
> > > > +/**
> > > > + Perform HTTP PUT to send redfish resource to given resource URI.
> > > > + It's caller's responsibility to free Response by calling FreeResponse ().
> > > > +
> > > > + @param[in] This Pointer to EDKII_REDFISH_HTTP_PROTOCOL
> instance.
> > > > + @param[in] Service Redfish service instance to perform HTTP PUT.
> > > > + @param[in] Uri Target resource URI.
> > > > + @param[in] Content Data to put.
> > > > + @param[in] ContentSize Size of the Content to be send to Redfish
> service.
> > > > + This is optional. When ContentSize is 0, ContentSize
> > > > + is the size of Content.
> > > > + @param[in] ContentType Type of the Content to be send to Redfish
> service.
> > > > + This is optional. When ContentType is NULL, content
> > > > + type HTTP_CONTENT_TYPE_APP_JSON will be used.
> > > > + @param[out] Response HTTP response from redfish service.
> > > > +
> > > > + @retval EFI_SUCCESS Resrouce is returned successfully.
> > > > + @retval Others Errors occur.
> > > > +
> > > > +**/
> > > > +EFI_STATUS
> > > > +EFIAPI
> > > > +RedfishPutResource (
> > > > + IN EDKII_REDFISH_HTTP_PROTOCOL *This,
> > > > + IN REDFISH_SERVICE Service,
> > > > + IN EFI_STRING Uri,
> > > > + IN CHAR8 *Content,
> > > > + IN UINTN ContentSize OPTIONAL,
> > > > + IN CHAR8 *ContentType OPTIONAL,
> > > > + OUT REDFISH_RESPONSE *Response
> > > > + )
> > > > +{
> > > > + EFI_STATUS Status;
> > > > + UINTN RetryCount;
> > > > + REDFISH_REQUEST Request;
> > > > + REDFISH_HTTP_CACHE_PRIVATE *Private;
> > > > +
> > > > + if ((This == NULL) || (Service == NULL) || (Response == NULL) ||
> > > IS_EMPTY_STRING (Uri) || IS_EMPTY_STRING (Content)) {
> > > > + return EFI_INVALID_PARAMETER;
> > > > + }
> > > > +
> > > > + DEBUG ((REDFISH_HTTP_CACHE_DEBUG, "%a: Put URI: %s\n", __func__,
> > > Uri));
> > > > +
> > > > + Private = REDFISH_HTTP_CACHE_PRIVATE_FROM_THIS (This);
> > > > + RetryCount = 0;
> > > > + ZeroMem (Response, sizeof (REDFISH_RESPONSE));
> > > > + ZeroMem (&Request, sizeof (REDFISH_REQUEST));
> > > > +
> > > > + Request.Content = Content;
> > > > + Request.ContentLength = ContentSize;
> > > > + Request.ContentType = ContentType;
> > > > +
> > > > + //
> > > > + // Patch resource to redfish service.
> > > > + //
> > > > + do {
> > > > + RetryCount += 1;
> > > > + Status = HttpSendReceive (
> > > > + Service,
> > > > + Uri,
> > > > + HttpMethodPut,
> > > > + &Request,
> > > > + Response
> > > > + );
> > > > + DEBUG ((REDFISH_HTTP_CACHE_DEBUG_REQUEST, "%a: HTTP request:
> > > %s :%r\n", __func__, Uri, Status));
> > > > + if (!EFI_ERROR (Status) || (RetryCount >= Private-
> > > >RetrySetting.MaximumRetryPut)) {
> > > > + break;
> > > > + }
> > > > +
> > > > + //
> > > > + // Retry when BMC is not ready.
> > > > + //
> > > > + if ((Response->StatusCode != NULL)) {
> > > > + DEBUG_CODE (
> > > > + DumpRedfishResponse (NULL, DEBUG_ERROR, Response);
> > > > + );
> > > > +
> > > > + if (!RedfishRetryRequired (Response->StatusCode)) {
> > > > + break;
> > > > + }
> > > > +
> > > > + //
> > > > + // Release response for next round of request.
> > > > + //
> > > > + This->FreeResponse (This, Response);
> > > > + }
> > > > +
> > > > + DEBUG ((DEBUG_WARN, "%a: RedfishPutToUri failed, retry (%d/%d)\n",
> > > __func__, RetryCount, Private->RetrySetting.MaximumRetryPut));
> > > > + if (Private->RetrySetting.RetryWait > 0) {
> > > > + gBS->Stall (Private->RetrySetting.RetryWait);
> > > > + }
> > > > + } while (TRUE);
> > > > +
> > > > + //
> > > > + // Redfish resource is updated. Automatically expire the cached response
> > > > + // so application can directly get resource from Redfish service again.
> > > > + //
> > > > + DEBUG ((REDFISH_HTTP_CACHE_DEBUG, "%a: Resource is updated,
> expire
> > > URI: %s\n", __func__, Uri));
> > > > + RedfishExpireResponse (This, Uri);
> > > > +
> > > > + if (EFI_ERROR (Status)) {
> > > > + DEBUG_CODE (
> > > > + DumpRedfishResponse (NULL, DEBUG_ERROR, Response);
> > > > + );
> > > > + //
> > > > + // Report status code for Redfish failure
> > > > + //
> > > > + ReportHttpError (HttpMethodPut, Uri, Response->StatusCode);
> > > > + DEBUG ((DEBUG_ERROR, "%a: put %s failed (%d/%d): %r\n", __func__,
> Uri,
> > > RetryCount, Private->RetrySetting.MaximumRetryPut, Status));
> > > > + goto ON_RELEASE;
> > > > + }
> > > > +
> > > > +ON_RELEASE:
> > > > +
> > > > + return Status;
> > > > +}
> > > > +
> > > > +/**
> > > > + Perform HTTP POST to send redfish resource to given resource URI.
> > > > + It's caller's responsibility to free Response by calling FreeResponse ().
> > > > +
> > > > + @param[in] This Pointer to EDKII_REDFISH_HTTP_PROTOCOL
> instance.
> > > > + @param[in] Service Redfish service instance to perform HTTP POST.
> > > > + @param[in] Uri Target resource URI.
> > > > + @param[in] Content Data to post.
> > > > + @param[in] ContentSize Size of the Content to be send to Redfish
> service.
> > > > + This is optional. When ContentSize is 0, ContentSize
> > > > + is the size of Content.
> > > > + @param[in] ContentType Type of the Content to be send to Redfish
> service.
> > > > + This is optional. When ContentType is NULL, content
> > > > + type HTTP_CONTENT_TYPE_APP_JSON will be used.
> > > > + @param[out] Response HTTP response from redfish service.
> > > > +
> > > > + @retval EFI_SUCCESS Resrouce is returned successfully.
> > > > + @retval Others Errors occur.
> > > > +
> > > > +**/
> > > > +EFI_STATUS
> > > > +EFIAPI
> > > > +RedfishPostResource (
> > > > + IN EDKII_REDFISH_HTTP_PROTOCOL *This,
> > > > + IN REDFISH_SERVICE Service,
> > > > + IN EFI_STRING Uri,
> > > > + IN CHAR8 *Content,
> > > > + IN UINTN ContentSize OPTIONAL,
> > > > + IN CHAR8 *ContentType OPTIONAL,
> > > > + OUT REDFISH_RESPONSE *Response
> > > > + )
> > > > +{
> > > > + EFI_STATUS Status;
> > > > + UINTN RetryCount;
> > > > + REDFISH_REQUEST Request;
> > > > + REDFISH_HTTP_CACHE_PRIVATE *Private;
> > > > +
> > > > + if ((This == NULL) || (Service == NULL) || (Response == NULL) ||
> > > IS_EMPTY_STRING (Uri) || IS_EMPTY_STRING (Content)) {
> > > > + return EFI_INVALID_PARAMETER;
> > > > + }
> > > > +
> > > > + DEBUG ((REDFISH_HTTP_CACHE_DEBUG, "%a: Post URI: %s\n",
> __func__,
> > > Uri));
> > > > +
> > > > + Private = REDFISH_HTTP_CACHE_PRIVATE_FROM_THIS (This);
> > > > + RetryCount = 0;
> > > > + ZeroMem (Response, sizeof (REDFISH_RESPONSE));
> > > > + ZeroMem (&Request, sizeof (REDFISH_REQUEST));
> > > > +
> > > > + Request.Content = Content;
> > > > + Request.ContentLength = ContentSize;
> > > > + Request.ContentType = ContentType;
> > > > +
> > > > + //
> > > > + // Patch resource to redfish service.
> > > > + //
> > > > + do {
> > > > + RetryCount += 1;
> > > > + Status = HttpSendReceive (
> > > > + Service,
> > > > + Uri,
> > > > + HttpMethodPost,
> > > > + &Request,
> > > > + Response
> > > > + );
> > > > + DEBUG ((REDFISH_HTTP_CACHE_DEBUG_REQUEST, "%a: HTTP request:
> > > %s :%r\n", __func__, Uri, Status));
> > > > + if (!EFI_ERROR (Status) || (RetryCount >= Private-
> > > >RetrySetting.MaximumRetryPost)) {
> > > > + break;
> > > > + }
> > > > +
> > > > + //
> > > > + // Retry when BMC is not ready.
> > > > + //
> > > > + if ((Response->StatusCode != NULL)) {
> > > > + DEBUG_CODE (
> > > > + DumpRedfishResponse (NULL, DEBUG_ERROR, Response);
> > > > + );
> > > > +
> > > > + if (!RedfishRetryRequired (Response->StatusCode)) {
> > > > + break;
> > > > + }
> > > > +
> > > > + //
> > > > + // Release response for next round of request.
> > > > + //
> > > > + This->FreeResponse (This, Response);
> > > > + }
> > > > +
> > > > + DEBUG ((DEBUG_WARN, "%a: RedfishPostToUri failed, retry (%d/%d)\n",
> > > __func__, RetryCount, Private->RetrySetting.MaximumRetryPost));
> > > > + if (Private->RetrySetting.RetryWait > 0) {
> > > > + gBS->Stall (Private->RetrySetting.RetryWait);
> > > > + }
> > > > + } while (TRUE);
> > > > +
> > > > + //
> > > > + // Redfish resource is updated. Automatically expire the cached response
> > > > + // so application can directly get resource from Redfish service again.
> > > > + //
> > > > + DEBUG ((REDFISH_HTTP_CACHE_DEBUG, "%a: Resource is updated,
> expire
> > > URI: %s\n", __func__, Uri));
> > > > + RedfishExpireResponse (This, Uri);
> > > > +
> > > > + if (EFI_ERROR (Status)) {
> > > > + DEBUG_CODE (
> > > > + DumpRedfishResponse (NULL, DEBUG_ERROR, Response);
> > > > + );
> > > > + //
> > > > + // Report status code for Redfish failure
> > > > + //
> > > > + ReportHttpError (HttpMethodPost, Uri, Response->StatusCode);
> > > > + DEBUG ((DEBUG_ERROR, "%a: post %s failed (%d/%d): %r\n", __func__,
> Uri,
> > > RetryCount, Private->RetrySetting.MaximumRetryPost, Status));
> > > > + goto ON_RELEASE;
> > > > + }
> > > > +
> > > > +ON_RELEASE:
> > > > +
> > > > + return Status;
> > > > +}
> > > > +
> > > > +/**
> > > > + Perform HTTP DELETE to delete redfish resource on given resource URI.
> > > > + It's caller's responsibility to free Response by calling FreeResponse ().
> > > > +
> > > > + @param[in] This Pointer to EDKII_REDFISH_HTTP_PROTOCOL
> instance.
> > > > + @param[in] Service Redfish service instance to perform HTTP
> DELETE.
> > > > + @param[in] Uri Target resource URI.
> > > > + @param[in] Content JSON represented properties to be deleted. This
> is
> > > > + optional.
> > > > + @param[in] ContentSize Size of the Content to be send to Redfish
> service.
> > > > + This is optional. When ContentSize is 0, ContentSize
> > > > + is the size of Content if Content is not NULL.
> > > > + @param[in] ContentType Type of the Content to be send to Redfish
> service.
> > > > + This is optional. When Content is not NULL and
> > > > + ContentType is NULL, content type
> > > HTTP_CONTENT_TYPE_APP_JSON
> > > > + will be used.
> > > > + @param[out] Response HTTP response from redfish service.
> > > > +
> > > > + @retval EFI_SUCCESS Resrouce is returned successfully.
> > > > + @retval Others Errors occur.
> > > > +
> > > > +**/
> > > > +EFI_STATUS
> > > > +EFIAPI
> > > > +RedfishDeleteResource (
> > > > + IN EDKII_REDFISH_HTTP_PROTOCOL *This,
> > > > + IN REDFISH_SERVICE Service,
> > > > + IN EFI_STRING Uri,
> > > > + IN CHAR8 *Content OPTIONAL,
> > > > + IN UINTN ContentSize OPTIONAL,
> > > > + IN CHAR8 *ContentType OPTIONAL,
> > > > + OUT REDFISH_RESPONSE *Response
> > > > + )
> > > > +{
> > > > + EFI_STATUS Status;
> > > > + UINTN RetryCount;
> > > > + REDFISH_REQUEST Request;
> > > > + REDFISH_HTTP_CACHE_PRIVATE *Private;
> > > > +
> > > > + if ((This == NULL) || (Service == NULL) || (Response == NULL) ||
> > > IS_EMPTY_STRING (Uri)) {
> > > > + return EFI_INVALID_PARAMETER;
> > > > + }
> > > > +
> > > > + DEBUG ((REDFISH_HTTP_CACHE_DEBUG, "%a: Delete URI: %s\n",
> __func__,
> > > Uri));
> > > > +
> > > > + Private = REDFISH_HTTP_CACHE_PRIVATE_FROM_THIS (This);
> > > > + RetryCount = 0;
> > > > + ZeroMem (Response, sizeof (REDFISH_RESPONSE));
> > > > + ZeroMem (&Request, sizeof (REDFISH_REQUEST));
> > > > +
> > > > + Request.Content = Content;
> > > > + Request.ContentLength = ContentSize;
> > > > + Request.ContentType = ContentType;
> > > > +
> > > > + //
> > > > + // Patch resource to redfish service.
> > > > + //
> > > > + do {
> > > > + RetryCount += 1;
> > > > + Status = HttpSendReceive (
> > > > + Service,
> > > > + Uri,
> > > > + HttpMethodDelete,
> > > > + &Request,
> > > > + Response
> > > > + );
> > > > + DEBUG ((REDFISH_HTTP_CACHE_DEBUG_REQUEST, "%a: HTTP request:
> > > %s :%r\n", __func__, Uri, Status));
> > > > + if (!EFI_ERROR (Status) || (RetryCount >= Private-
> > > >RetrySetting.MaximumRetryDelete)) {
> > > > + break;
> > > > + }
> > > > +
> > > > + //
> > > > + // Retry when BMC is not ready.
> > > > + //
> > > > + if ((Response->StatusCode != NULL)) {
> > > > + DEBUG_CODE (
> > > > + DumpRedfishResponse (NULL, DEBUG_ERROR, Response);
> > > > + );
> > > > +
> > > > + if (!RedfishRetryRequired (Response->StatusCode)) {
> > > > + break;
> > > > + }
> > > > +
> > > > + //
> > > > + // Release response for next round of request.
> > > > + //
> > > > + This->FreeResponse (This, Response);
> > > > + }
> > > > +
> > > > + DEBUG ((DEBUG_WARN, "%a: RedfishDeleteByUri failed, retry
> (%d/%d)\n",
> > > __func__, RetryCount, Private->RetrySetting.MaximumRetryDelete));
> > > > + if (Private->RetrySetting.RetryWait > 0) {
> > > > + gBS->Stall (Private->RetrySetting.RetryWait);
> > > > + }
> > > > + } while (TRUE);
> > > > +
> > > > + //
> > > > + // Redfish resource is updated. Automatically expire the cached response
> > > > + // so application can directly get resource from Redfish service again.
> > > > + //
> > > > + DEBUG ((REDFISH_HTTP_CACHE_DEBUG, "%a: Resource is updated,
> expire
> > > URI: %s\n", __func__, Uri));
> > > > + RedfishExpireResponse (This, Uri);
> > > > +
> > > > + if (EFI_ERROR (Status)) {
> > > > + DEBUG_CODE (
> > > > + DumpRedfishResponse (NULL, DEBUG_ERROR, Response);
> > > > + );
> > > > + //
> > > > + // Report status code for Redfish failure
> > > > + //
> > > > + ReportHttpError (HttpMethodDelete, Uri, Response->StatusCode);
> > > > + DEBUG ((DEBUG_ERROR, "%a: delete %s failed (%d/%d): %r\n",
> __func__,
> > > Uri, RetryCount, Private->RetrySetting.MaximumRetryDelete, Status));
> > > > + goto ON_RELEASE;
> > > > + }
> > > > +
> > > > +ON_RELEASE:
> > > > +
> > > > + return Status;
> > > > +}
> > > > +
> > > > +EDKII_REDFISH_HTTP_PROTOCOL mEdkIIRedfishHttpProtocol = {
> > > > + EDKII_REDFISH_HTTP_PROTOCOL_REVISION,
> > > > + RedfishCreateRedfishService,
> > > > + RedfishFreeRedfishService,
> > > > + RedfishJsonInRedfishPayload,
> > > > + RedfishGetResource,
> > > > + RedfishPatchResource,
> > > > + RedfishPutResource,
> > > > + RedfishPostResource,
> > > > + RedfishDeleteResource,
> > > > + RedfishFreeRequest,
> > > > + RedfishFreeResponse,
> > > > + RedfishExpireResponse
> > > > +};
> > > > +
> > > > +/**
> > > > + Unloads an image.
> > > > +
> > > > + @param[in] ImageHandle Handle that identifies the image to be
> > > unloaded.
> > > > +
> > > > + @retval EFI_SUCCESS The image has been unloaded.
> > > > + @retval EFI_INVALID_PARAMETER ImageHandle is not a valid image
> > > handle.
> > > > +
> > > > +**/
> > > > +EFI_STATUS
> > > > +EFIAPI
> > > > +RedfishHttpDriverUnload (
> > > > + IN EFI_HANDLE ImageHandle
> > > > + )
> > > > +{
> > > > + if (mRedfishHttpCachePrivate == NULL) {
> > > > + return EFI_SUCCESS;
> > > > + }
> > > > +
> > > > + if (!IsListEmpty (&mRedfishHttpCachePrivate->CacheList.Head)) {
> > > > + ReleaseCacheList (&mRedfishHttpCachePrivate->CacheList);
> > > > + }
> > > > +
> > > > + gBS->UninstallMultipleProtocolInterfaces (
> > > > + ImageHandle,
> > > > + &gEdkIIRedfishHttpProtocolGuid,
> > > > + &mRedfishHttpCachePrivate->Protocol,
> > > > + NULL
> > > > + );
> > > > +
> > > > + FreePool (mRedfishHttpCachePrivate);
> > > > + mRedfishHttpCachePrivate = NULL;
> > > > +
> > > > + return EFI_SUCCESS;
> > > > +}
> > > > +
> > > > +/**
> > > > + This is a EDKII_REDFISH_CREDENTIAL_PROTOCOL notification event
> handler.
> > > > +
> > > > + @param[in] Event Event whose notification function is being invoked.
> > > > + @param[in] Context Pointer to the notification function's context.
> > > > +
> > > > +**/
> > > > +VOID
> > > > +EFIAPI
> > > > +CredentialProtocolInstalled (
> > > > + IN EFI_EVENT Event,
> > > > + IN VOID *Context
> > > > + )
> > > > +{
> > > > + EFI_STATUS Status;
> > > > + REDFISH_HTTP_CACHE_PRIVATE *Private;
> > > > +
> > > > + Private = (REDFISH_HTTP_CACHE_PRIVATE *)Context;
> > > > + if (Private->Signature != REDFISH_HTTP_DRIVER_SIGNATURE) {
> > > > + DEBUG ((DEBUG_ERROR, "%a: signature check failure\n", __func__));
> > > > + return;
> > > > + }
> > > > +
> > > > + //
> > > > + // Locate HII database protocol.
> > > > + //
> > > > + Status = gBS->LocateProtocol (
> > > > + &gEdkIIRedfishCredentialProtocolGuid,
> > > > + NULL,
> > > > + (VOID **)&Private->CredentialProtocol
> > > > + );
> > > > + if (EFI_ERROR (Status)) {
> > > > + return;
> > > > + }
> > > > +
> > > > + gBS->CloseEvent (Event);
> > > > +}
> > > > +
> > > > +/**
> > > > + Main entry for this driver.
> > > > +
> > > > + @param[in] ImageHandle Image handle this driver.
> > > > + @param[in] SystemTable Pointer to SystemTable.
> > > > +
> > > > + @retval EFI_SUCCESS This function always complete successfully.
> > > > +
> > > > +**/
> > > > +EFI_STATUS
> > > > +EFIAPI
> > > > +RedfishHttpEntryPoint (
> > > > + IN EFI_HANDLE ImageHandle,
> > > > + IN EFI_SYSTEM_TABLE *SystemTable
> > > > + )
> > > > +{
> > > > + EFI_STATUS Status;
> > > > + VOID *Registration;
> > > > +
> > > > + if (mRedfishHttpCachePrivate != NULL) {
> > > > + return EFI_ALREADY_STARTED;
> > > > + }
> > > > +
> > > > + mRedfishHttpCachePrivate = AllocateZeroPool (sizeof
> > > (REDFISH_HTTP_CACHE_PRIVATE));
> > > > + if (mRedfishHttpCachePrivate == NULL) {
> > > > + return EFI_OUT_OF_RESOURCES;
> > > > + }
> > > > +
> > > > + //
> > > > + // Initial cache list and protocol instance.
> > > > + //
> > > > + mRedfishHttpCachePrivate->Signature =
> > > REDFISH_HTTP_DRIVER_SIGNATURE;
> > > > + mRedfishHttpCachePrivate->ImageHandle = ImageHandle;
> > > > + CopyMem (&mRedfishHttpCachePrivate->Protocol,
> > > &mEdkIIRedfishHttpProtocol, sizeof (EDKII_REDFISH_HTTP_PROTOCOL));
> > > > + mRedfishHttpCachePrivate->CacheList.Capacity =
> > > REDFISH_HTTP_CACHE_LIST_SIZE;
> > > > + mRedfishHttpCachePrivate->CacheList.Count = 0x00;
> > > > + mRedfishHttpCachePrivate->CacheDisabled = PcdGetBool
> > > (PcdHttpCacheDisabled);
> > > > + InitializeListHead (&mRedfishHttpCachePrivate->CacheList.Head);
> > > > +
> > > > + //
> > > > + // Get retry settings
> > > > + //
> > > > + mRedfishHttpCachePrivate->RetrySetting.MaximumRetryGet =
> PcdGet16
> > > (PcdHttpGetRetry);
> > > > + mRedfishHttpCachePrivate->RetrySetting.MaximumRetryPut =
> PcdGet16
> > > (PcdHttpPutRetry);
> > > > + mRedfishHttpCachePrivate->RetrySetting.MaximumRetryPatch =
> PcdGet16
> > > (PcdHttpPatchRetry);
> > > > + mRedfishHttpCachePrivate->RetrySetting.MaximumRetryPost =
> PcdGet16
> > > (PcdHttpPostRetry);
> > > > + mRedfishHttpCachePrivate->RetrySetting.MaximumRetryDelete =
> PcdGet16
> > > (PcdHttpDeleteRetry);
> > > > + mRedfishHttpCachePrivate->RetrySetting.RetryWait = PcdGet16
> > > (PcdHttpRetryWaitInSecond) * 1000000U;
> > > > +
> > > > + //
> > > > + // Install the gEdkIIRedfishHttpProtocolGuid onto Handle.
> > > > + //
> > > > + Status = gBS->InstallMultipleProtocolInterfaces (
> > > > + &mRedfishHttpCachePrivate->ImageHandle,
> > > > + &gEdkIIRedfishHttpProtocolGuid,
> > > > + &mRedfishHttpCachePrivate->Protocol,
> > > > + NULL
> > > > + );
> > > > + if (EFI_ERROR (Status)) {
> > > > + DEBUG ((DEBUG_ERROR, "%a: cannot install Redfish http protocol:
> %r\n",
> > > __func__, Status));
> > > > + RedfishHttpDriverUnload (ImageHandle);
> > > > + return Status;
> > > > + }
> > > > +
> > > > + //
> > > > + // Install protocol notification if credential protocol is installed.
> > > > + //
> > > > + mRedfishHttpCachePrivate->NotifyEvent = EfiCreateProtocolNotifyEvent (
> > > > + &gEdkIIRedfishCredentialProtocolGuid,
> > > > + TPL_CALLBACK,
> > > > + CredentialProtocolInstalled,
> > > > + mRedfishHttpCachePrivate,
> > > > + &Registration
> > > > + );
> > > > + if (mRedfishHttpCachePrivate->NotifyEvent == NULL) {
> > > > + DEBUG ((DEBUG_ERROR, "%a: failed to create protocol notification for
> > > gEdkIIRedfishCredentialProtocolGuid\n", __func__));
> > > > + ASSERT (FALSE);
> > > > + RedfishHttpDriverUnload (ImageHandle);
> > > > + return Status;
> > > > + }
> > > > +
> > > > + return EFI_SUCCESS;
> > > > +}
> > > > diff --git a/RedfishPkg/RedfishHttpDxe/RedfishHttpOperation.c
> > > b/RedfishPkg/RedfishHttpDxe/RedfishHttpOperation.c
> > > > new file mode 100644
> > > > index 0000000000..5652818d16
> > > > --- /dev/null
> > > > +++ b/RedfishPkg/RedfishHttpDxe/RedfishHttpOperation.c
> > > > @@ -0,0 +1,693 @@
> > > > +/** @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;
> > > > + }
> > > > +
> > > > + for (Index = 0; Index < SrcHeaderCount; Index++) {
> > > > + (*DstHeaders)[Index].FieldName = AllocateCopyPool (AsciiStrSize
> > > (SrcHeaders[Index].FieldName), SrcHeaders[Index].FieldName);
> > > > + if ((*DstHeaders)[Index].FieldName == NULL) {
> > > > + return EFI_OUT_OF_RESOURCES;
> > > > + }
> > > > +
> > > > + (*DstHeaders)[Index].FieldValue = AllocateCopyPool (AsciiStrSize
> > > (SrcHeaders[Index].FieldValue), SrcHeaders[Index].FieldValue);
> > > > + if ((*DstHeaders)[Index].FieldValue == NULL) {
> > > > + return EFI_OUT_OF_RESOURCES;
> > >
> > >
> > >
> > > Looks like orevious allocations leaked.
> > > Didn't you think to implement smth like this
> > >
> https://github.co/
> %2F&data=05%7C02%7Cnicklew%40nvidia.com%7Cb82203c2d6124060850308d
> c34894020%7C43083d15727340c1b7db39efd9ccc17a%7C0%7C0%7C638443011
> 350956245%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLjAwMDAiLCJQIjoiV2
> luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C0%7C%7C%7C&sdata=j7ozA8KXgZ
> LpU1HoE0xsWua7Nzzx66BqdA0QGar1xqA%3D&reserved=0
> > >
> m%2Ftianocore%2Fedk2%2Fblob%2Fmaster%2FOvmfPkg%2FXenBusDxe%2FHelp
> > >
> ers.c%23L4&data=05%7C02%7Cnicklew%40nvidia.com%7Cf659c54c3edb43527c
> > >
> 3608dc3462ab2a%7C43083d15727340c1b7db39efd9ccc17a%7C0%7C0%7C6384
> > >
> 42845601059719%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLjAwMDAiLCJ
> > >
> QIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C0%7C%7C%7C&sdata=oYv
> > > XkfjOpakMOXV1w6nYVphDRuPM7R73lqr8QVqh%2BI4%3D&reserved=0 ?
> > >
> > >
> > > > + }
> > > > +
> > > > + *DstHeaderCount += 1;
> > > > + }
> > > > +
> > > > + 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 Resrouce 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 Resrouce 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 Resrouce 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;
> > > > +}
> > > > diff --git a/RedfishPkg/Redfish.fdf.inc b/RedfishPkg/Redfish.fdf.inc
> > > > index 3e5a77766e..5cbe3592fd 100644
> > > > --- a/RedfishPkg/Redfish.fdf.inc
> > > > +++ b/RedfishPkg/Redfish.fdf.inc
> > > > @@ -6,7 +6,7 @@
> > > > # to be built in the firmware volume.
> > > > #
> > > > # (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
> > > > #
> > > > @@ -20,4 +20,5 @@
> > > > INF RedfishPkg/RedfishConfigHandler/RedfishConfigHandlerDriver.inf
> > > > INF RedfishPkg/RedfishPlatformConfigDxe/RedfishPlatformConfigDxe.inf
> > > > INF
> > > MdeModulePkg/Universal/RegularExpressionDxe/RegularExpressionDxe.inf
> > > > + INF RedfishPkg/RedfishHttpDxe/RedfishHttpDxe.inf
> > > > !endif
> > > > --
> > > > 2.34.1
> > > >
> > > >
> > > >
> > > >
> > > >
> > >
> > > Regards,
> > > Mike.
> > > >
-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#115958): https://edk2.groups.io/g/devel/message/115958
Mute This Topic: https://groups.io/mt/104505404/7686176
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [rebecca@openfw.io]
-=-=-=-=-=-=-=-=-=-=-=-
next prev parent reply other threads:[~2024-02-26 13:44 UTC|newest]
Thread overview: 15+ messages / expand[flat|nested] mbox.gz Atom feed top
2024-02-22 9:11 [edk2-devel] [PATCH v2 2/6] RedfishPkg: implement Redfish HTTP protocol Nickle Wang via groups.io
2024-02-22 13:39 ` Chang, Abner via groups.io
2024-02-22 14:17 ` Igor Kulchytskyy via groups.io
2024-02-23 11:29 ` Mike Maslenkin
2024-02-23 14:07 ` Nickle Wang via groups.io
2024-02-23 16:04 ` Mike Maslenkin
2024-02-26 13:43 ` Nickle Wang via groups.io [this message]
2024-02-27 0:13 ` Mike Maslenkin
2024-02-27 0:48 ` Nickle Wang via groups.io
[not found] ` <17B791D5F1D9AF42.14830@groups.io>
2024-02-28 11:47 ` Nickle Wang via groups.io
2024-02-28 17:56 ` Mike Maslenkin
2024-02-29 0:11 ` Nickle Wang via groups.io
2024-02-29 0:30 ` Chang, Abner via groups.io
2024-02-29 1:37 ` Igor Kulchytskyy via groups.io
2024-02-29 4:01 ` Chang, Abner via groups.io
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-list from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=MW4PR12MB70315BAEE316B23C18D262D5D95A2@MW4PR12MB7031.namprd12.prod.outlook.com \
--to=devel@edk2.groups.io \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox