From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mail02.groups.io (mail02.groups.io [66.175.222.108]) by spool.mail.gandi.net (Postfix) with ESMTPS id 9616A7803DA for ; Fri, 23 Feb 2024 16:05:29 +0000 (UTC) DKIM-Signature: a=rsa-sha256; bh=Z98kZciKKsLtmDweEkUQmOm7lfl+ssne1SQ53UFO2Wg=; c=relaxed/simple; d=groups.io; h=MIME-Version:References:In-Reply-To:From:Date:Message-ID:Subject:To:Cc:Precedence:List-Subscribe:List-Help:Sender:List-Id:Mailing-List:Delivered-To:Reply-To:List-Unsubscribe-Post:List-Unsubscribe:Content-Type:Content-Transfer-Encoding; s=20140610; t=1708704328; v=1; b=uW/6GceiI+KlYvTkXGYv+vfw5cXs0I0tp/KdH+lUZVJLG8vUZ4f03UdLOAz4T3TTISzwuPss /RLWzIUyaiiYIvmKhs3wDQH3iNbus0/WQqEcn4dHX+hq9Mq2sMCuHZKEeBG6wSvqxx+uDz8uTV6 xNGsHRiMo5f5vkOq1e0PMdW8= X-Received: by 127.0.0.2 with SMTP id WBvSYY7687511xuEhdBGtKK5; Fri, 23 Feb 2024 08:05:28 -0800 X-Received: from mail-yb1-f178.google.com (mail-yb1-f178.google.com [209.85.219.178]) by mx.groups.io with SMTP id smtpd.web10.16345.1708704327107201099 for ; Fri, 23 Feb 2024 08:05:27 -0800 X-Received: by mail-yb1-f178.google.com with SMTP id 3f1490d57ef6-dc23bf7e5aaso631121276.0 for ; Fri, 23 Feb 2024 08:05:27 -0800 (PST) X-Gm-Message-State: 1hJdbTByEvroD80SsauH251nx7686176AA= X-Google-Smtp-Source: AGHT+IGN7iaEsayN3bsgl5BD2O95NMeORGl6IOa6wq5k0fkdIDmFlL3Oc1CerWTaGneoI35gzg80MYyHUMuUYOM+Ou4= X-Received: by 2002:a25:2f0e:0:b0:dcd:d94:3db5 with SMTP id v14-20020a252f0e000000b00dcd0d943db5mr229142ybv.52.1708704324162; Fri, 23 Feb 2024 08:05:24 -0800 (PST) MIME-Version: 1.0 References: <20240222091122.644-1-nicklew@nvidia.com> <9A76E719-1472-4E4C-A480-B38C7D305AAF@gmail.com> In-Reply-To: From: "Mike Maslenkin" Date: Fri, 23 Feb 2024 19:04:47 +0300 Message-ID: Subject: Re: [edk2-devel] [PATCH v2 2/6] RedfishPkg: implement Redfish HTTP protocol To: Nickle Wang Cc: "devel@edk2.groups.io" , Igor Kulchytskyy , Abner Chang , Nick Ramirez Precedence: Bulk List-Subscribe: List-Help: Sender: devel@edk2.groups.io List-Id: Mailing-List: list devel@edk2.groups.io; contact devel+owner@edk2.groups.io Reply-To: devel@edk2.groups.io,mike.maslenkin@gmail.com List-Unsubscribe-Post: List-Unsubscribe=One-Click List-Unsubscribe: Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: quoted-printable X-GND-Status: LEGIT Authentication-Results: spool.mail.gandi.net; dkim=pass header.d=groups.io header.s=20140610 header.b="uW/6Gcei"; dmarc=fail reason="SPF not aligned (relaxed), DKIM not aligned (relaxed)" header.from=gmail.com (policy=none); spf=pass (spool.mail.gandi.net: domain of bounce@groups.io designates 66.175.222.108 as permitted sender) smtp.mailfrom=bounce@groups.io Hi Nickle, On Fri, Feb 23, 2024 at 5:07=E2=80=AFPM Nickle Wang wr= ote: > > 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 Serv= ice is not NULL. Please let me know if I misunderstand your comment. Oh, I see. I missed ReleaseRedfishService() call. > > > >> + (*DstHeaders)[Index].FieldValue =3D AllocateCopyPool (AsciiStrSiz= e (SrcHeaders[Index].FieldValue), SrcHeaders[Index].FieldValue); > >> + if ((*DstHeaders)[Index].FieldValue =3D=3D 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 allocatio= n leaking, right? To fix allocation leaking, my idea is to call HttpFreeHea= derFields() 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. Righ= t? To fix this, it is required to set *DstHeaderCount =3D SrcHeaderCount unconditionally right after DstHeaders allocation, and HttpFreeHeaderFields() will do the work then. Regards, Mike. > > Regards, > Nickle > > > -----Original Message----- > > From: Mike Maslenkin > > Sent: Friday, February 23, 2024 7:29 PM > > To: devel@edk2.groups.io; Nickle Wang > > Cc: Igor Kulchytskyy ; Abner Chang = ; > > Nick Ramirez > > 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=E2=80=AFPM Nickle Wang via groups.io > > wrote: > > > > > > implement Redfish HTTP protocol driver. > > > > > > Signed-off-by: Nickle Wang > > > Co-authored-by: Igor Kulchytskyy > > > Cc: Abner Chang > > > Cc: Igor Kulchytskyy > > > Cc: Nick Ramirez > > > --- > > > 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 communi= cation. > > > - > > gEfiRedfishPkgTokenSpaceGuid.PcdRedfishServiceContentEncoding|TRUE|BOOL= E > > 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"|VO= ID > > *|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 > > > -# Copyright (c) 2023, NVIDIA CORPORATION & AFFILIATES. All rights re= served. > > > +# Copyright (c) 2023-2024, NVIDIA CORPORATION & AFFILIATES. All righ= ts > > reserved. > > > # > > > # SPDX-License-Identifier: BSD-2-Clause-Patent > > > # > > > @@ -28,4 +28,5 @@ > > > RedfishPkg/RedfishConfigHandler/RedfishConfigHandlerDriver.inf > > > RedfishPkg/RedfishPlatformConfigDxe/RedfishPlatformConfigDxe.inf > > > MdeModulePkg/Universal/RegularExpressionDxe/RegularExpressionDxe.in= f > > > + 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/UefiHiiServi= cesLib. > > inf > > > > > RedfishPlatformCredentialLib|RedfishPkg/Library/PlatformCredentialLibNu= ll/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 rig= hts > > reserved. > > > +# > > > +# SPDX-License-Identifier: BSD-2-Clause-Patent > > > +# > > > +## > > > + > > > +[Defines] > > > + INF_VERSION =3D 0x0001000b > > > + BASE_NAME =3D RedfishHttpDxe > > > + FILE_GUID =3D 85ADB2F1-DA93-47D4-AF4F-3D920D9= BD2C0 > > > + MODULE_TYPE =3D DXE_DRIVER > > > + VERSION_STRING =3D 1.0 > > > + ENTRY_POINT =3D RedfishHttpEntryPoint > > > + UNLOAD_IMAGE =3D RedfishHttpDriverUnload > > > + > > > +# > > > +# VALID_ARCHITECTURES =3D 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 righ= ts > > 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 righ= ts > > reserved. > > > + > > > + SPDX-License-Identifier: BSD-2-Clause-Patent > > > + > > > +**/ > > > + > > > +#ifndef EDKII_REDFISH_HTTP_DXE_H_ > > > +#define EDKII_REDFISH_HTTP_DXE_H_ > > > + > > > +#include > > > +#include > > > + > > > +#include > > > +#include > > > +#include > > > +#include > > > +#include > > > +#include > > > +#include > > > +#include > > > +#include > > > +#include > > > +#include > > > +#include > > > + > > > +#include > > > +#include > > > +#include > > > +#include > > > + > > > +#define IS_EMPTY_STRING(a) ((a) =3D=3D NULL || (a)[0] =3D=3D '\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 lengt= h (39) > > + "https://" (8) + port number (maximum 5) > > > +#define REDFISH_HTTP_ERROR_REPORT "Redfish HTTP %a failure(0= x%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 re= served. > > > + > > > + 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 avai= lable > > > + 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 successfu= lly. > > > + @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 prot= ocol. > > > + > > > + Copyright (c) 2023-2024, NVIDIA CORPORATION & AFFILIATES. All righ= ts > > 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 =3D=3D NULL) || IS_EMPTY_STRING (Token)) { > > > + return EFI_INVALID_PARAMETER; > > > + } > > > + > > > + if (Service->SessionToken !=3D NULL) { > > > + FreePool (Service->SessionToken); > > > + } > > > + > > > + Service->SessionToken =3D AllocateCopyPool (AsciiStrSize (Token), = Token); > > > + if (Service->SessionToken =3D=3D 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 =3D=3D NULL) { > > > + return EFI_INVALID_PARAMETER; > > > + } > > > + > > > + if (Service->Host !=3D NULL) { > > > + FreePool (Service->Host); > > > + } > > > + > > > + if (Service->HostName !=3D NULL) { > > > + FreePool (Service->HostName); > > > + } > > > + > > > + if (Service->BasicAuth !=3D NULL) { > > > + ZeroMem (Service->BasicAuth, AsciiStrSize (Service->BasicAuth)); > > > + FreePool (Service->BasicAuth); > > > + } > > > + > > > + if (Service->SessionToken !=3D NULL) { > > > + ZeroMem (Service->SessionToken, AsciiStrSize (Service->SessionTo= ken)); > > > + 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) || (RestE= x =3D=3D > > NULL)) { > > > + return NULL; > > > + } > > > + > > > + NewService =3D AllocateZeroPool (sizeof (REDFISH_SERVICE_PRIVATE))= ; > > > + if (NewService =3D=3D NULL) { > > > + return NULL; > > > + } > > > + > > > + NewService->Signature =3D REDFISH_HTTP_SERVICE_SIGNATURE; > > > + NewService->Host =3D AllocateCopyPool (AsciiStrSize (Host), H= ost); > > > + if (NewService->Host =3D=3D NULL) { > > > + goto ON_ERROR; > > > + } > > > + > > > + NewService->HostName =3D AllocateCopyPool (AsciiStrSize (HostName)= , > > HostName); > > > + if (NewService->HostName =3D=3D NULL) { > > > + goto ON_ERROR; > > > + } > > > + > > > + if (!IS_EMPTY_STRING (BasicAuth)) { > > > + AuthStrSize =3D AsciiStrSize (BasicAuth) + AsciiStrLen > > (REDFISH_HTTP_BASIC_AUTH_STR); > > > + NewService->BasicAuth =3D AllocateZeroPool (AuthStrSize); > > > + if (NewService->BasicAuth =3D=3D NULL) { > > > + goto ON_ERROR; > > > + } > > > + > > > + AsciiSPrint (NewService->BasicAuth, AuthStrSize, "%a%a", > > REDFISH_HTTP_BASIC_AUTH_STR, BasicAuth); > > > + } > > > + > > > + if (!IS_EMPTY_STRING (SessionToken)) { > > > + NewService->SessionToken =3D AllocateCopyPool (AsciiStrSize (Ses= sionToken), > > SessionToken); > > > + if (NewService->SessionToken =3D=3D NULL) { > > > + goto ON_ERROR; > > > + } > > > + } > > > + > > > + NewService->RestEx =3D 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 =3D=3D NULL) { > > > + return EFI_INVALID_PARAMETER; > > > + } > > > + > > > + if (Payload->Service !=3D NULL) { > > > + ReleaseRedfishService (Payload->Service); > > > + } > > > + > > > + if (Payload->JsonValue !=3D 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 =3D=3D NULL) || (JsonValue =3D=3D NULL)) { > > > + return NULL; > > > + } > > > + > > > + NewPayload =3D AllocateZeroPool (sizeof (REDFISH_PAYLOAD_PRIVATE))= ; > > > + if (NewPayload =3D=3D NULL) { > > > + return NULL; > > > + } > > > + > > > + NewPayload->Signature =3D REDFISH_HTTP_PAYLOAD_SIGNATURE; > > > + NewPayload->Service =3D CreateRedfishService (Service->Host, Ser= vice- > > >HostName, Service->BasicAuth, Service->SessionToken, Service->RestEx); > > > + if (NewPayload->Service =3D=3D NULL) { > > > + goto ON_ERROR; > > > + } > > > + > > > + NewPayload->JsonValue =3D JsonValueClone (JsonValue); > > > + if (NewPayload->JsonValue =3D=3D 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 =3D=3D NULL) || (DstResponse =3D=3D NULL)) { > > > + return EFI_INVALID_PARAMETER; > > > + } > > > + > > > + if (SrcResponse =3D=3D DstResponse) { > > > + return EFI_SUCCESS; > > > + } > > > + > > > + // > > > + // Status code > > > + // > > > + if (SrcResponse->StatusCode !=3D NULL) { > > > + DstResponse->StatusCode =3D AllocateCopyPool (sizeof > > (EFI_HTTP_STATUS_CODE), SrcResponse->StatusCode); > > > + if (DstResponse->StatusCode =3D=3D NULL) { > > > + goto ON_ERROR; > > > + } > > > + } > > > + > > > + // > > > + // Header > > > + // > > > + if ((SrcResponse->HeaderCount > 0) && (SrcResponse->Headers !=3D N= ULL)) { > > > + DstResponse->HeaderCount =3D 0; > > > + DstResponse->Headers =3D AllocateZeroPool (sizeof (EFI_HTTP_= HEADER) * > > SrcResponse->HeaderCount); > > > + if (DstResponse->Headers =3D=3D NULL) { > > > + goto ON_ERROR; > > > + } > > > + > > > + for (Index =3D 0; Index < SrcResponse->HeaderCount; Index++) { > > > + DstResponse->Headers[Index].FieldName =3D AllocateCopyPool (As= ciiStrSize > > (SrcResponse->Headers[Index].FieldName), SrcResponse- > > >Headers[Index].FieldName); > > > + if (DstResponse->Headers[Index].FieldName =3D=3D NULL) { > > > + goto ON_ERROR; > > > + } > > > + > > > + DstResponse->Headers[Index].FieldValue =3D AllocateCopyPool (A= sciiStrSize > > (SrcResponse->Headers[Index].FieldValue), SrcResponse- > > >Headers[Index].FieldValue); > > > + if (DstResponse->Headers[Index].FieldValue =3D=3D NULL) { > > > + goto ON_ERROR; > > > + } > > > + > > > + DstResponse->HeaderCount +=3D 1; > > > + } > > > + } > > > + > > > + // > > > + // Payload > > > + // > > > + if (SrcResponse->Payload !=3D NULL) { > > > + Payload =3D (REDFISH_PAYLOAD_PRIVATE *)SrcResponse->Payload; > > > + if (Payload->Signature !=3D REDFISH_HTTP_PAYLOAD_SIGNATURE) { > > > + DEBUG ((DEBUG_ERROR, "%a: signature check failure\n", __func__= )); > > > + goto ON_ERROR; > > > + } > > > + > > > + DstResponse->Payload =3D CreateRedfishPayload (Payload->Service,= Payload- > > >JsonValue); > > > + if (DstResponse->Payload =3D=3D 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 =3D=3D NULL) { > > > + return NULL; > > > + } > > > + > > > + NewResponse =3D AllocateZeroPool (sizeof (REDFISH_RESPONSE)); > > > + if (NewResponse =3D=3D NULL) { > > > + return NULL; > > > + } > > > + > > > + Status =3D 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 release= d > > successfully. > > > + @retval EFI_INVALID_PARAMETER Data is NULL > > > + > > > +**/ > > > +EFI_STATUS > > > +ReleaseHttpCacheData ( > > > + IN REDFISH_HTTP_CACHE_DATA *Data > > > + ) > > > +{ > > > + if (Data =3D=3D NULL) { > > > + return EFI_INVALID_PARAMETER; > > > + } > > > + > > > + if (Data->Uri !=3D NULL) { > > > + FreePool (Data->Uri); > > > + } > > > + > > > + if (Data->Response !=3D 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 =3D=3D NULL)) { > > > + return NULL; > > > + } > > > + > > > + NewData =3D AllocateZeroPool (sizeof (REDFISH_HTTP_CACHE_DATA)); > > > + if (NewData =3D=3D NULL) { > > > + return NULL; > > > + } > > > + > > > + NewData->Signature =3D REDFISH_HTTP_CACHE_SIGNATURE; > > > + Size =3D StrSize (Uri); > > > + NewData->Uri =3D AllocateCopyPool (Size, Uri); > > > + if (NewData->Uri =3D=3D NULL) { > > > + goto ON_ERROR; > > > + } > > > + > > > + NewData->Response =3D Response; > > > + NewData->HitCount =3D 1; > > > + > > > + return NewData; > > > + > > > +ON_ERROR: > > > + > > > + if (NewData !=3D 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 =3D NULL; > > > + List =3D GetFirstNode (ListHeader); > > > + while (!IsNull (ListHeader, List)) { > > > + Data =3D REDFISH_HTTP_CACHE_FROM_LIST (List); > > > + > > > + if (StrCmp (Data->Uri, Uri) =3D=3D 0) { > > > + return Data; > > > + } > > > + > > > + List =3D 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 =3D NULL; > > > + UnusedData =3D NULL; > > > + HitCount =3D 0; > > > + > > > + List =3D GetFirstNode (ListHeader); > > > + Data =3D REDFISH_HTTP_CACHE_FROM_LIST (List); > > > + UnusedData =3D Data; > > > + HitCount =3D Data->HitCount; > > > + List =3D GetNextNode (ListHeader, List); > > > + > > > + while (!IsNull (ListHeader, List)) { > > > + Data =3D REDFISH_HTTP_CACHE_FROM_LIST (List); > > > + > > > + if (Data->HitCount < HitCount) { > > > + HitCount =3D Data->HitCount; > > > + UnusedData =3D Data; > > > + } > > > + > > > + List =3D 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 =3D=3D NULL) || (Data =3D=3D 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 =3D=3D NULL) || IS_EMPTY_STRING (Uri) || (Response =3D= =3D NULL)) { > > > + return EFI_INVALID_PARAMETER; > > > + } > > > + > > > + // > > > + // If same cache data exist, replace it with latest one. > > > + // > > > + OldData =3D FindHttpCacheData (&List->Head, Uri); > > > + if (OldData !=3D NULL) { > > > + DeleteHttpCacheData (List, OldData); > > > + } > > > + > > > + // > > > + // Check capacity > > > + // > > > + if (List->Count >=3D List->Capacity) { > > > + DEBUG ((REDFISH_HTTP_CACHE_DEBUG, "%a: list is full and retire u= nused > > cache\n", __func__)); > > > + UnusedData =3D FindUnusedHttpCacheData (&List->Head); > > > + if (UnusedData =3D=3D NULL) { > > > + return EFI_OUT_OF_RESOURCES; > > > + } > > > + > > > + DeleteHttpCacheData (List, UnusedData); > > > + } > > > + > > > + // > > > + // Clone a local copy > > > + // > > > + NewResponse =3D CloneRedfishResponse (Response); > > > + if (NewResponse =3D=3D NULL) { > > > + return EFI_OUT_OF_RESOURCES; > > > + } > > > + > > > + NewData =3D NewHttpCacheData (Uri, NewResponse); > > > + if (NewData =3D=3D 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 =3D=3D NULL) { > > > + return EFI_INVALID_PARAMETER; > > > + } > > > + > > > + if (IsListEmpty (&CacheList->Head)) { > > > + return EFI_SUCCESS; > > > + } > > > + > > > + Data =3D NULL; > > > + Next =3D NULL; > > > + List =3D GetFirstNode (&CacheList->Head); > > > + while (!IsNull (&CacheList->Head, List)) { > > > + Data =3D REDFISH_HTTP_CACHE_FROM_LIST (List); > > > + Next =3D GetNextNode (&CacheList->Head, List); > > > + > > > + DeleteHttpCacheData (CacheList, Data); > > > + > > > + List =3D 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 righ= ts > > reserved. > > > + > > > + SPDX-License-Identifier: BSD-2-Clause-Patent > > > + > > > +**/ > > > + > > > +#include "RedfishHttpDxe.h" > > > +#include "RedfishHttpData.h" > > > +#include "RedfishHttpOperation.h" > > > + > > > +REDFISH_HTTP_CACHE_PRIVATE *mRedfishHttpCachePrivate =3D 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 =3D=3D 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->Co= unt, > > CacheList->Capacity)); > > > + Data =3D NULL; > > > + Index =3D 0; > > > + List =3D GetFirstNode (&CacheList->Head); > > > + while (!IsNull (&CacheList->Head, List)) { > > > + Data =3D REDFISH_HTTP_CACHE_FROM_LIST (List); > > > + > > > + DEBUG ((ErrorLevel, "%d) Uri: %s Hit: %d\n", ++Index, Data->Uri,= Data- > > >HitCount)); > > > + > > > + List =3D 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 requ= est. > > > + Return false when we don't want to ret= ry request. > > > + > > > +**/ > > > +BOOLEAN > > > +RedfishRetryRequired ( > > > + IN EFI_HTTP_STATUS_CODE *StatusCode > > > + ) > > > +{ > > > + if (StatusCode =3D=3D NULL) { > > > + return TRUE; > > > + } > > > + > > > + if ((*StatusCode =3D=3D HTTP_STATUS_500_INTERNAL_SERVER_ERROR) || > > > + (*StatusCode =3D=3D HTTP_STATUS_UNSUPPORTED_STATUS)) > > > + { > > > + return TRUE; > > > + } > > > + > > > + return FALSE; > > > +} > > > + > > > +/** > > > + > > > + Convert Unicode string to ASCII string. It's call responsibility t= o 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 =3D StrLen (UnicodeStr) + 1; > > > + AsciiStr =3D AllocateZeroPool (AsciiStrSize); > > > + if (AsciiStr =3D=3D NULL) { > > > + return NULL; > > > + } > > > + > > > + Status =3D UnicodeStrToAsciiStrS (UnicodeStr, AsciiStr, AsciiStrSi= ze); > > > + if (EFI_ERROR (Status)) { > > > + DEBUG ((DEBUG_ERROR, "UnicodeStrToAsciiStrS failed: %r\n", Statu= s)); > > > + 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", __fu= nc__)); > > > + return; > > > + } > > > + > > > + // > > > + // Report failure of URI and HTTP status code. > > > + // > > > + AsciiSPrint (ErrorMsg, sizeof (ErrorMsg), REDFISH_HTTP_ERROR_REPOR= T, > > HttpMethodToString (Method), (HttpStatusCode =3D=3D 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 specifica= tion > > published. > > > + // We will uncomment below report status code after PI status code= get > > published. > > > + // REF: > > https://bugzilla.ti/ > > anocore.org%2Fshow_bug.cgi%3Fid%3D4483&data=3D05%7C02%7Cnicklew%40nvi > > dia.com%7Cf659c54c3edb43527c3608dc3462ab2a%7C43083d15727340c1b7db > > 39efd9ccc17a%7C0%7C0%7C638442845601051396%7CUnknown%7CTWFpbGZs > > b3d8eyJWIjoiMC4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0% > > 3D%7C0%7C%7C%7C&sdata=3DT1bN7KmTa1v49cOFkd9%2F9hlzkdzbHPLebxSiUkp > > VuU4%3D&reserved=3D0 > > > + // > > > + // 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_HT= TP_PROTOCOL > > instance. > > > + @param[in] RedfishConfigServiceInfo Redfish config service info= rmation. > > > + > > > + @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 =3D=3D NULL) || (RedfishConfigServiceInfo =3D=3D NULL)) = { > > > + return NULL; > > > + } > > > + > > > + DEBUG ((REDFISH_HTTP_CACHE_DEBUG, "%a: service location: %s\n", > > __func__, RedfishConfigServiceInfo->RedfishServiceLocation)); > > > + > > > + Private =3D REDFISH_HTTP_CACHE_PRIVATE_FROM_THIS (This)= ; > > > + BasicAuthString =3D NULL; > > > + EncodedAuthString =3D NULL; > > > + Username =3D NULL; > > > + Password =3D NULL; > > > + NewService =3D NULL; > > > + AsciiLocation =3D NULL; > > > + Host =3D NULL; > > > + BasicAuthStrSize =3D 0; > > > + EncodedAuthStrSize =3D 0; > > > + UsernameSize =3D 0; > > > + PasswordSize =3D 0; > > > + > > > + // > > > + // Build host and host name from service location > > > + // > > > + if (!IS_EMPTY_STRING (RedfishConfigServiceInfo->RedfishServiceLoca= tion)) { > > > + AsciiLocation =3D StringUnicodeToAscii (RedfishConfigServiceInfo= - > > >RedfishServiceLocation); > > > + if (AsciiLocation =3D=3D NULL) { > > > + goto ON_RELEASE; > > > + } > > > + > > > + Host =3D AllocateZeroPool (REDFISH_HOST_NAME_MAX); > > > + if (AsciiLocation =3D=3D 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", AsciiLo= cation); > > > + } > > > + > > > + DEBUG ((REDFISH_HTTP_CACHE_DEBUG, "%a: Host: %a\n", __func__, > > Host)); > > > + } > > > + > > > + // > > > + // Find Rest Ex protocol > > > + // > > > + if (RedfishConfigServiceInfo->RedfishServiceRestExHandle !=3D NULL= ) { > > > + Status =3D gBS->HandleProtocol ( > > > + RedfishConfigServiceInfo->RedfishServiceRestExHa= ndle, > > > + &gEfiRestExProtocolGuid, > > > + (VOID **)&RestEx > > > + ); > > > + } else { > > > + DEBUG ((DEBUG_ERROR, "%a: Rest Ex protocol is not available\n", > > __func__)); > > > + goto ON_RELEASE; > > > + } > > > + > > > + // > > > + // Get credential > > > + // > > > + if (Private->CredentialProtocol =3D=3D NULL) { > > > + // > > > + // No credential available on this system. > > > + // > > > + DEBUG ((DEBUG_WARN, "%a: no credential protocol available\n", > > __func__)); > > > + } else { > > > + Status =3D Private->CredentialProtocol->GetAuthInfo ( > > > + Private->CredentialProto= col, > > > + &AuthMethod, > > > + &Username, > > > + &Password > > > + ); > > > + if (EFI_ERROR (Status) || IS_EMPTY_STRING (Username) || > > IS_EMPTY_STRING (Password)) { > > > + DEBUG ((DEBUG_ERROR, "%a: cannot get authentication informatio= n: > > %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 =3D AsciiStrSize (Username); > > > + PasswordSize =3D AsciiStrSize (Password); > > > + BasicAuthStrSize =3D UsernameSize + PasswordSize; // one byt= e taken from > > null-terminator for ':' > > > + BasicAuthString =3D AllocateZeroPool (BasicAuthStrSize); > > > + if (BasicAuthString =3D=3D NULL) { > > > + goto ON_RELEASE; > > > + } > > > + > > > + AsciiSPrint ( > > > + BasicAuthString, > > > + BasicAuthStrSize, > > > + "%a:%a", > > > + Username, > > > + Password > > > + ); > > > + > > > + Status =3D Base64Encode ( > > > + (CONST UINT8 *)BasicAuthString, > > > + BasicAuthStrSize, > > > + EncodedAuthString, > > > + &EncodedAuthStrSize > > > + ); > > > + if ((Status =3D=3D EFI_BUFFER_TOO_SMALL) && (EncodedAuthStrSiz= e > 0)) { > > > + EncodedAuthString =3D AllocateZeroPool (EncodedAuthStrSize); > > > + if (EncodedAuthString =3D=3D NULL) { > > > + goto ON_RELEASE; > > > + } > > > + > > > + Status =3D Base64Encode ( > > > + (CONST UINT8 *)BasicAuthString, > > > + BasicAuthStrSize, > > > + EncodedAuthString, > > > + &EncodedAuthStrSize > > > + ); > > > + if (EFI_ERROR (Status)) { > > > + DEBUG ((DEBUG_ERROR, "%a: Base64Encode failure: %r\n", __f= unc__, > > Status)); > > > + } > > > + > > > + DEBUG ((REDFISH_HTTP_CACHE_DEBUG, "%a: Basic authorization: > > %a\n", __func__, EncodedAuthString)); > > > + } else { > > > + DEBUG ((DEBUG_ERROR, "%a: Base64Encode failure: %r\n", __fun= c__, > > Status)); > > > + goto ON_RELEASE; > > > + } > > > + } > > > + } > > > + > > > + NewService =3D CreateRedfishService (Host, AsciiLocation, EncodedA= uthString, > > NULL, RestEx); > > > + if (NewService =3D=3D NULL) { > > > + DEBUG ((DEBUG_ERROR, "%a: CreateRedfishService\n", __func__)); > > > + } > > > + > > > +ON_RELEASE: > > > + > > > + if (BasicAuthString !=3D NULL) { > > > + ZeroMem (BasicAuthString, BasicAuthStrSize); > > > + FreePool (BasicAuthString); > > > + } > > > + > > > + if (EncodedAuthString !=3D NULL) { > > > + ZeroMem (BasicAuthString, EncodedAuthStrSize); > > > + FreePool (EncodedAuthString); > > > + } > > > + > > > + if (Username !=3D NULL) { > > > + ZeroMem (Username, UsernameSize); > > > + FreePool (Username); > > > + } > > > + > > > + if (Password !=3D NULL) { > > > + ZeroMem (Password, PasswordSize); > > > + FreePool (Password); > > > + } > > > + > > > + if (AsciiLocation !=3D NULL) { > > > + FreePool (AsciiLocation); > > > + } > > > + > > > + if (Host !=3D 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 relea= sed. > > > + > > > + @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 =3D=3D NULL) || (RedfishService =3D=3D NULL)) { > > > + return EFI_INVALID_PARAMETER; > > > + } > > > + > > > + Service =3D (REDFISH_SERVICE_PRIVATE *)RedfishService; > > > + if (Service->Signature !=3D 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 modificati= on 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 =3D=3D NULL) || (RedfishPayload =3D=3D NULL)) { > > > + return NULL; > > > + } > > > + > > > + Payload =3D (REDFISH_PAYLOAD_PRIVATE *)RedfishPayload; > > > + if (Payload->Signature !=3D 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 w= ith > > > + cache mechanism supported. It's caller's responsibility to free Re= sponse > > > + by calling FreeResponse (). > > > + > > > + @param[in] This Pointer to EDKII_REDFISH_HTTP_PROTOCOL i= nstance. > > > + @param[in] Service Redfish service instance to perform HTTP= GET. > > > + @param[in] Uri Target resource URI. > > > + @param[in] Request Additional request context. This is opti= onal. > > > + @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 functi= on > > > + 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 =3D=3D NULL) || (Service =3D=3D NULL) || (Response =3D= =3D 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 =3D REDFISH_HTTP_CACHE_PRIVATE_FROM_THIS (This); > > > + CacheData =3D NULL; > > > + RetryCount =3D 0; > > > + ZeroMem (Response, sizeof (REDFISH_RESPONSE)); > > > + > > > + if (Private->CacheDisabled) { > > > + UseCache =3D FALSE; > > > + DEBUG ((REDFISH_HTTP_CACHE_DEBUG, "%a: cache is disabled by > > PCD!\n", __func__)); > > > + } > > > + > > > + // > > > + // Search for cache list. > > > + // > > > + if (UseCache) { > > > + CacheData =3D FindHttpCacheData (&Private->CacheList.Head, Uri); > > > + if (CacheData !=3D NULL) { > > > + DEBUG ((REDFISH_HTTP_CACHE_DEBUG_REQUEST, "%a: cache hit! %s\n= ", > > __func__, Uri)); > > > + > > > + // > > > + // Copy cached response to caller's buffer. > > > + // > > > + Status =3D CopyRedfishResponse (CacheData->Respo= nse, Response); > > > + CacheData->HitCount +=3D 1; > > > + return Status; > > > + } > > > + } > > > + > > > + // > > > + // Get resource from redfish service. > > > + // > > > + do { > > > + RetryCount +=3D 1; > > > + Status =3D 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 >=3D Private- > > >RetrySetting.MaximumRetryGet)) { > > > + break; > > > + } > > > + > > > + // > > > + // Retry when BMC is not ready. > > > + // > > > + if ((Response->StatusCode !=3D 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 =3D 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 avai= lable > > > + after this function returns successfully. > > > + > > > + @param[in] This Pointer to EDKII_REDFISH_HTTP_PROTOCOL in= stance. > > > + @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 =3D=3D NULL) || (Request =3D=3D 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 in= stance. > > > + @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 =3D=3D NULL) || (Response =3D=3D 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 in= stance. > > > + @param[in] Uri Target response of URI. > > > + > > > + @retval EFI_SUCCESS Target response is expired successfull= y. > > > + @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 =3D=3D NULL) || IS_EMPTY_STRING (Uri)) { > > > + return EFI_INVALID_PARAMETER; > > > + } > > > + > > > + DEBUG ((REDFISH_HTTP_CACHE_DEBUG, "%a: expire URI: %s\n", __func__= , > > Uri)); > > > + > > > + Private =3D REDFISH_HTTP_CACHE_PRIVATE_FROM_THIS (This); > > > + > > > + CacheData =3D FindHttpCacheData (&Private->CacheList.Head, Uri); > > > + if (CacheData =3D=3D 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 FreeRespo= nse (). > > > + > > > + @param[in] This Pointer to EDKII_REDFISH_HTTP_PROTOCOL i= nstance. > > > + @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 Redfis= h 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 Redfis= h service. > > > + This is optional. When ContentType is NU= LL, 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 =3D=3D NULL) || (Service =3D=3D NULL) || (Response =3D= =3D 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 =3D REDFISH_HTTP_CACHE_PRIVATE_FROM_THIS (This); > > > + RetryCount =3D 0; > > > + ZeroMem (Response, sizeof (REDFISH_RESPONSE)); > > > + ZeroMem (&Request, sizeof (REDFISH_REQUEST)); > > > + > > > + Request.Content =3D Content; > > > + Request.ContentLength =3D ContentSize; > > > + Request.ContentType =3D ContentType; > > > + > > > + // > > > + // Patch resource to redfish service. > > > + // > > > + do { > > > + RetryCount +=3D 1; > > > + Status =3D 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 >=3D Private- > > >RetrySetting.MaximumRetryPatch)) { > > > + break; > > > + } > > > + > > > + // > > > + // Retry when BMC is not ready. > > > + // > > > + if ((Response->StatusCode !=3D 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 re= sponse > > > + // so application can directly get resource from Redfish service a= gain. > > > + // > > > + 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 FreeRespo= nse (). > > > + > > > + @param[in] This Pointer to EDKII_REDFISH_HTTP_PROTOCOL i= nstance. > > > + @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 Redfis= h 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 Redfis= h service. > > > + This is optional. When ContentType is NU= LL, 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 =3D=3D NULL) || (Service =3D=3D NULL) || (Response =3D= =3D 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 =3D REDFISH_HTTP_CACHE_PRIVATE_FROM_THIS (This); > > > + RetryCount =3D 0; > > > + ZeroMem (Response, sizeof (REDFISH_RESPONSE)); > > > + ZeroMem (&Request, sizeof (REDFISH_REQUEST)); > > > + > > > + Request.Content =3D Content; > > > + Request.ContentLength =3D ContentSize; > > > + Request.ContentType =3D ContentType; > > > + > > > + // > > > + // Patch resource to redfish service. > > > + // > > > + do { > > > + RetryCount +=3D 1; > > > + Status =3D 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 >=3D Private- > > >RetrySetting.MaximumRetryPut)) { > > > + break; > > > + } > > > + > > > + // > > > + // Retry when BMC is not ready. > > > + // > > > + if ((Response->StatusCode !=3D 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 re= sponse > > > + // so application can directly get resource from Redfish service a= gain. > > > + // > > > + 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 FreeRespo= nse (). > > > + > > > + @param[in] This Pointer to EDKII_REDFISH_HTTP_PROTOCOL i= nstance. > > > + @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 Redfis= h 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 Redfis= h service. > > > + This is optional. When ContentType is NU= LL, 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 =3D=3D NULL) || (Service =3D=3D NULL) || (Response =3D= =3D 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 =3D REDFISH_HTTP_CACHE_PRIVATE_FROM_THIS (This); > > > + RetryCount =3D 0; > > > + ZeroMem (Response, sizeof (REDFISH_RESPONSE)); > > > + ZeroMem (&Request, sizeof (REDFISH_REQUEST)); > > > + > > > + Request.Content =3D Content; > > > + Request.ContentLength =3D ContentSize; > > > + Request.ContentType =3D ContentType; > > > + > > > + // > > > + // Patch resource to redfish service. > > > + // > > > + do { > > > + RetryCount +=3D 1; > > > + Status =3D 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 >=3D Private- > > >RetrySetting.MaximumRetryPost)) { > > > + break; > > > + } > > > + > > > + // > > > + // Retry when BMC is not ready. > > > + // > > > + if ((Response->StatusCode !=3D 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 re= sponse > > > + // so application can directly get resource from Redfish service a= gain. > > > + // > > > + 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 U= RI. > > > + It's caller's responsibility to free Response by calling FreeRespo= nse (). > > > + > > > + @param[in] This Pointer to EDKII_REDFISH_HTTP_PROTOCOL i= nstance. > > > + @param[in] Service Redfish service instance to perform HTTP= DELETE. > > > + @param[in] Uri Target resource URI. > > > + @param[in] Content JSON represented properties to be delete= d. This is > > > + optional. > > > + @param[in] ContentSize Size of the Content to be send to Redfis= h 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 Redfis= h service. > > > + This is optional. When Content is not NU= LL 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 =3D=3D NULL) || (Service =3D=3D NULL) || (Response =3D= =3D NULL) || > > IS_EMPTY_STRING (Uri)) { > > > + return EFI_INVALID_PARAMETER; > > > + } > > > + > > > + DEBUG ((REDFISH_HTTP_CACHE_DEBUG, "%a: Delete URI: %s\n", __func__= , > > Uri)); > > > + > > > + Private =3D REDFISH_HTTP_CACHE_PRIVATE_FROM_THIS (This); > > > + RetryCount =3D 0; > > > + ZeroMem (Response, sizeof (REDFISH_RESPONSE)); > > > + ZeroMem (&Request, sizeof (REDFISH_REQUEST)); > > > + > > > + Request.Content =3D Content; > > > + Request.ContentLength =3D ContentSize; > > > + Request.ContentType =3D ContentType; > > > + > > > + // > > > + // Patch resource to redfish service. > > > + // > > > + do { > > > + RetryCount +=3D 1; > > > + Status =3D 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 >=3D Private- > > >RetrySetting.MaximumRetryDelete)) { > > > + break; > > > + } > > > + > > > + // > > > + // Retry when BMC is not ready. > > > + // > > > + if ((Response->StatusCode !=3D 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 re= sponse > > > + // so application can directly get resource from Redfish service a= gain. > > > + // > > > + 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", __fun= c__, > > Uri, RetryCount, Private->RetrySetting.MaximumRetryDelete, Status)); > > > + goto ON_RELEASE; > > > + } > > > + > > > +ON_RELEASE: > > > + > > > + return Status; > > > +} > > > + > > > +EDKII_REDFISH_HTTP_PROTOCOL mEdkIIRedfishHttpProtocol =3D { > > > + 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 t= o 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 =3D=3D NULL) { > > > + return EFI_SUCCESS; > > > + } > > > + > > > + if (!IsListEmpty (&mRedfishHttpCachePrivate->CacheList.Head)) { > > > + ReleaseCacheList (&mRedfishHttpCachePrivate->CacheList); > > > + } > > > + > > > + gBS->UninstallMultipleProtocolInterfaces ( > > > + ImageHandle, > > > + &gEdkIIRedfishHttpProtocolGuid, > > > + &mRedfishHttpCachePrivate->Protocol, > > > + NULL > > > + ); > > > + > > > + FreePool (mRedfishHttpCachePrivate); > > > + mRedfishHttpCachePrivate =3D NULL; > > > + > > > + return EFI_SUCCESS; > > > +} > > > + > > > +/** > > > + This is a EDKII_REDFISH_CREDENTIAL_PROTOCOL notification event han= dler. > > > + > > > + @param[in] Event Event whose notification function is being inv= oked. > > > + @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 =3D (REDFISH_HTTP_CACHE_PRIVATE *)Context; > > > + if (Private->Signature !=3D REDFISH_HTTP_DRIVER_SIGNATURE) { > > > + DEBUG ((DEBUG_ERROR, "%a: signature check failure\n", __func__))= ; > > > + return; > > > + } > > > + > > > + // > > > + // Locate HII database protocol. > > > + // > > > + Status =3D 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 !=3D NULL) { > > > + return EFI_ALREADY_STARTED; > > > + } > > > + > > > + mRedfishHttpCachePrivate =3D AllocateZeroPool (sizeof > > (REDFISH_HTTP_CACHE_PRIVATE)); > > > + if (mRedfishHttpCachePrivate =3D=3D NULL) { > > > + return EFI_OUT_OF_RESOURCES; > > > + } > > > + > > > + // > > > + // Initial cache list and protocol instance. > > > + // > > > + mRedfishHttpCachePrivate->Signature =3D > > REDFISH_HTTP_DRIVER_SIGNATURE; > > > + mRedfishHttpCachePrivate->ImageHandle =3D ImageHandle; > > > + CopyMem (&mRedfishHttpCachePrivate->Protocol, > > &mEdkIIRedfishHttpProtocol, sizeof (EDKII_REDFISH_HTTP_PROTOCOL)); > > > + mRedfishHttpCachePrivate->CacheList.Capacity =3D > > REDFISH_HTTP_CACHE_LIST_SIZE; > > > + mRedfishHttpCachePrivate->CacheList.Count =3D 0x00; > > > + mRedfishHttpCachePrivate->CacheDisabled =3D PcdGetBool > > (PcdHttpCacheDisabled); > > > + InitializeListHead (&mRedfishHttpCachePrivate->CacheList.Head); > > > + > > > + // > > > + // Get retry settings > > > + // > > > + mRedfishHttpCachePrivate->RetrySetting.MaximumRetryGet =3D PcdG= et16 > > (PcdHttpGetRetry); > > > + mRedfishHttpCachePrivate->RetrySetting.MaximumRetryPut =3D PcdG= et16 > > (PcdHttpPutRetry); > > > + mRedfishHttpCachePrivate->RetrySetting.MaximumRetryPatch =3D PcdG= et16 > > (PcdHttpPatchRetry); > > > + mRedfishHttpCachePrivate->RetrySetting.MaximumRetryPost =3D PcdG= et16 > > (PcdHttpPostRetry); > > > + mRedfishHttpCachePrivate->RetrySetting.MaximumRetryDelete =3D PcdG= et16 > > (PcdHttpDeleteRetry); > > > + mRedfishHttpCachePrivate->RetrySetting.RetryWait =3D PcdG= et16 > > (PcdHttpRetryWaitInSecond) * 1000000U; > > > + > > > + // > > > + // Install the gEdkIIRedfishHttpProtocolGuid onto Handle. > > > + // > > > + Status =3D 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 install= ed. > > > + // > > > + mRedfishHttpCachePrivate->NotifyEvent =3D EfiCreateProtocolNotifyE= vent ( > > > + &gEdkIIRedfishCredential= ProtocolGuid, > > > + TPL_CALLBACK, > > > + CredentialProtocolInstal= led, > > > + mRedfishHttpCachePrivate= , > > > + &Registration > > > + ); > > > + if (mRedfishHttpCachePrivate->NotifyEvent =3D=3D 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 re= served. > > > + > > > + 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 header= s. > > > + > > > + @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 =3D=3D NULL) || (SrcHeaderCount =3D=3D 0) || (DstH= eaders =3D=3D NULL) > > || (DstHeaderCount =3D=3D NULL)) { > > > + return EFI_INVALID_PARAMETER; > > > + } > > > + > > > + *DstHeaderCount =3D 0; > > > + *DstHeaders =3D AllocateZeroPool (sizeof (EFI_HTTP_HEADER) * > > SrcHeaderCount); > > > + if (*DstHeaders =3D=3D NULL) { > > > + return EFI_OUT_OF_RESOURCES; > > > + } > > > + > > > + for (Index =3D 0; Index < SrcHeaderCount; Index++) { > > > + (*DstHeaders)[Index].FieldName =3D AllocateCopyPool (AsciiStrSiz= e > > (SrcHeaders[Index].FieldName), SrcHeaders[Index].FieldName); > > > + if ((*DstHeaders)[Index].FieldName =3D=3D NULL) { > > > + return EFI_OUT_OF_RESOURCES; > > > + } > > > + > > > + (*DstHeaders)[Index].FieldValue =3D AllocateCopyPool (AsciiStrSi= ze > > (SrcHeaders[Index].FieldValue), SrcHeaders[Index].FieldValue); > > > + if ((*DstHeaders)[Index].FieldValue =3D=3D NULL) { > > > + return EFI_OUT_OF_RESOURCES; > > > > > > > > Looks like orevious allocations leaked. > > Didn't you think to implement smth like this > > https://github.co/ > > m%2Ftianocore%2Fedk2%2Fblob%2Fmaster%2FOvmfPkg%2FXenBusDxe%2FHelp > > ers.c%23L4&data=3D05%7C02%7Cnicklew%40nvidia.com%7Cf659c54c3edb43527c > > 3608dc3462ab2a%7C43083d15727340c1b7db39efd9ccc17a%7C0%7C0%7C6384 > > 42845601059719%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLjAwMDAiLCJ > > QIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C0%7C%7C%7C&sdata=3DoYv > > XkfjOpakMOXV1w6nYVphDRuPM7R73lqr8QVqh%2BI4%3D&reserved=3D0 ? > > > > > > > + } > > > + > > > + *DstHeaderCount +=3D 1; > > > + } > > > + > > > + return EFI_SUCCESS; > > > +} > > > + > > > +/** > > > + This function free resources in Request. Request is no longer avai= lable > > > + 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 =3D=3D NULL) { > > > + return EFI_INVALID_PARAMETER; > > > + } > > > + > > > + if ((Request->Headers !=3D NULL) && (Request->HeaderCount > 0)) { > > > + HttpFreeHeaderFields (Request->Headers, Request->HeaderCount); > > > + Request->Headers =3D NULL; > > > + Request->HeaderCount =3D 0; > > > + } > > > + > > > + if (Request->Content !=3D NULL) { > > > + FreePool (Request->Content); > > > + Request->Content =3D NULL; > > > + } > > > + > > > + if (Request->ContentType !=3D NULL) { > > > + FreePool (Request->ContentType); > > > + Request->ContentType =3D NULL; > > > + } > > > + > > > + Request->ContentLength =3D 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 =3D=3D NULL) { > > > + return EFI_INVALID_PARAMETER; > > > + } > > > + > > > + if ((Response->Headers !=3D NULL) && (Response->HeaderCount > 0)) = { > > > + HttpFreeHeaderFields (Response->Headers, Response->HeaderCount); > > > + Response->Headers =3D NULL; > > > + Response->HeaderCount =3D 0; > > > + } > > > + > > > + if (Response->Payload !=3D NULL) { > > > + ReleaseRedfishPayload (Response->Payload); > > > + Response->Payload =3D NULL; > > > + } > > > + > > > + if (Response->StatusCode !=3D NULL) { > > > + FreePool (Response->StatusCode); > > > + Response->StatusCode =3D 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 m= essage. > > > + 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 =3D=3D NULL) { > > > + return EFI_INVALID_PARAMETER; > > > + } > > > + > > > + if (IsRequest) { > > > + if (HttpMessage->Data.Request !=3D NULL) { > > > + if (HttpMessage->Data.Request->Url !=3D NULL) { > > > + FreePool (HttpMessage->Data.Request->Url); > > > + } > > > + > > > + FreePool (HttpMessage->Data.Request); > > > + HttpMessage->Data.Request =3D NULL; > > > + } > > > + } else { > > > + if (HttpMessage->Data.Response !=3D NULL) { > > > + FreePool (HttpMessage->Data.Response); > > > + HttpMessage->Data.Response =3D NULL; > > > + } > > > + } > > > + > > > + if (HttpMessage->Body !=3D NULL) { > > > + FreePool (HttpMessage->Body); > > > + HttpMessage->Body =3D NULL; > > > + } > > > + > > > + if (HttpMessage->Headers !=3D NULL) { > > > + HttpFreeHeaderFields (HttpMessage->Headers, HttpMessage- > > >HeaderCount); > > > + HttpMessage->Headers =3D NULL; > > > + HttpMessage->HeaderCount =3D 0; > > > + } > > > + > > > + return EFI_SUCCESS; > > > +} > > > + > > > +/** > > > + This function build Redfish message for sending data to Redfish se= rvice. > > > + 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 ContentEncod= ing is NULL, > > > + No compress method will be performe= d. > > > + > > > + @retval EFI_HTTP_MESSAGE * Pointer to newly created HTTP mes= sage. > > > + @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_SIZ= E]; > > > + VOID *Content; > > > + UINTN ContentLength; > > > + BOOLEAN HasContent; > > > + BOOLEAN DoContentEncoding; > > > + > > > + RequestMsg =3D NULL; > > > + RequestData =3D NULL; > > > + Url =3D NULL; > > > + UrlSize =3D 0; > > > + Content =3D NULL; > > > + ContentLength =3D 0; > > > + HeaderCount =3D REDFISH_COMMON_HEADER_SIZE; > > > + HeaderIndex =3D 0; > > > + Headers =3D NULL; > > > + HasContent =3D FALSE; > > > + DoContentEncoding =3D FALSE; > > > + > > > + if ((ServicePrivate =3D=3D NULL) || (IS_EMPTY_STRING (Uri))) { > > > + return NULL; > > > + } > > > + > > > + if (Method >=3D HttpMethodMax) { > > > + return NULL; > > > + } > > > + > > > + DEBUG ((REDFISH_HTTP_CACHE_DEBUG_REQUEST, "%a: %s\n", __func__, > > Uri)); > > > + > > > + // > > > + // Build full URL for HTTP query. > > > + // > > > + UrlSize =3D (AsciiStrLen (ServicePrivate->Host) + StrLen (Uri) + 1= ) * sizeof > > (CHAR16); > > > + Url =3D AllocateZeroPool (UrlSize); > > > + if (Url =3D=3D 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_S= TRING > > (ServicePrivate->BasicAuth)) { > > > + HeaderCount++; > > > + } > > > + > > > + if ((Request !=3D NULL) && (Request->HeaderCount > 0)) { > > > + HeaderCount +=3D 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) !=3D 0) { > > > + DoContentEncoding =3D TRUE; > > > + } > > > + } > > > + > > > + if ((Request !=3D NULL) && !IS_EMPTY_STRING (Request->Content)) { > > > + HeaderCount +=3D 2; > > > + HasContent =3D TRUE; > > > + if (DoContentEncoding) { > > > + HeaderCount +=3D 1; > > > + } > > > + } > > > + > > > + Headers =3D AllocateZeroPool (HeaderCount * sizeof (EFI_HTTP_HEADE= R)); > > > + if (Headers =3D=3D NULL) { > > > + goto ON_ERROR; > > > + } > > > + > > > + if (!IS_EMPTY_STRING (ServicePrivate->SessionToken)) { > > > + Status =3D 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 =3D HttpSetFieldNameAndValue (&Headers[HeaderIndex++], > > HTTP_HEADER_AUTHORIZATION, ServicePrivate->BasicAuth); > > > + if (EFI_ERROR (Status)) { > > > + goto ON_ERROR; > > > + } > > > + } > > > + > > > + if (Request !=3D NULL) { > > > + for (Index =3D 0; Index < Request->HeaderCount; Index++) { > > > + Status =3D HttpSetFieldNameAndValue (&Headers[HeaderIndex++], = Request- > > >Headers[Index].FieldName, Request->Headers[Index].FieldValue); > > > + if (EFI_ERROR (Status)) { > > > + goto ON_ERROR; > > > + } > > > + } > > > + } > > > + > > > + Status =3D HttpSetFieldNameAndValue (&Headers[HeaderIndex++], > > HTTP_HEADER_HOST, ServicePrivate->HostName); > > > + if (EFI_ERROR (Status)) { > > > + goto ON_ERROR; > > > + } > > > + > > > + Status =3D HttpSetFieldNameAndValue (&Headers[HeaderIndex++], > > REDFISH_HTTP_HEADER_ODATA_VERSION_STR, > > REDFISH_HTTP_HEADER_ODATA_VERSION_VALUE); > > > + if (EFI_ERROR (Status)) { > > > + goto ON_ERROR; > > > + } > > > + > > > + Status =3D HttpSetFieldNameAndValue (&Headers[HeaderIndex++], > > HTTP_HEADER_ACCEPT, HTTP_CONTENT_TYPE_APP_JSON); > > > + if (EFI_ERROR (Status)) { > > > + goto ON_ERROR; > > > + } > > > + > > > + Status =3D HttpSetFieldNameAndValue (&Headers[HeaderIndex++], > > HTTP_HEADER_USER_AGENT, REDFISH_HTTP_HEADER_USER_AGENT_VALUE); > > > + if (EFI_ERROR (Status)) { > > > + goto ON_ERROR; > > > + } > > > + > > > + Status =3D 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 =3D=3D NULL) { > > > + Status =3D HttpSetFieldNameAndValue (&Headers[HeaderIndex++], > > HTTP_HEADER_CONTENT_TYPE, HTTP_CONTENT_TYPE_APP_JSON); > > > + if (EFI_ERROR (Status)) { > > > + goto ON_ERROR; > > > + } > > > + } else { > > > + Status =3D HttpSetFieldNameAndValue (&Headers[HeaderIndex++], > > HTTP_HEADER_CONTENT_TYPE, Request->ContentType); > > > + if (EFI_ERROR (Status)) { > > > + goto ON_ERROR; > > > + } > > > + } > > > + > > > + if (Request->ContentLength =3D=3D 0) { > > > + Request->ContentLength =3D AsciiStrLen (Request->Content); > > > + } > > > + > > > + AsciiSPrint ( > > > + ContentLengthStr, > > > + sizeof (ContentLengthStr), > > > + "%lu", > > > + (UINT64)Request->ContentLength > > > + ); > > > + Status =3D 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 =3D RedfishContentEncode ( > > > + ContentEncoding, > > > + Request->Content, > > > + Request->ContentLength, > > > + &Content, > > > + &ContentLength > > > + ); > > > + if (Status =3D=3D EFI_INVALID_PARAMETER) { > > > + DEBUG ((DEBUG_ERROR, "%a: Error to encode content.\n", __fun= c__)); > > > + goto ON_ERROR; > > > + } else if (Status =3D=3D EFI_UNSUPPORTED) { > > > + DoContentEncoding =3D FALSE; > > > + DEBUG ((REDFISH_HTTP_CACHE_DEBUG_REQUEST, "%a: No content > > coding for %a! Use raw data instead.\n", __func__, ContentEncoding)); > > > + Status =3D HttpSetFieldNameAndValue (&Headers[HeaderIndex++]= , > > HTTP_HEADER_CONTENT_ENCODING, HTTP_CONTENT_ENCODING_IDENTITY); > > > + if (EFI_ERROR (Status)) { > > > + goto ON_ERROR; > > > + } > > > + } else { > > > + Status =3D 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 =3D AllocateCopyPool (Request->ContentLength, Request-= >Content); > > > + if (Content =3D=3D NULL) { > > > + goto ON_ERROR; > > > + } > > > + > > > + ContentLength =3D Request->ContentLength; > > > + } > > > + } > > > + > > > + // > > > + // Step 2: build the rest of HTTP request info. > > > + // > > > + RequestData =3D AllocateZeroPool (sizeof (EFI_HTTP_REQUEST_DATA)); > > > + if (RequestData =3D=3D NULL) { > > > + goto ON_ERROR; > > > + } > > > + > > > + RequestData->Method =3D Method; > > > + RequestData->Url =3D Url; > > > + > > > + // > > > + // Step 3: fill in EFI_HTTP_MESSAGE > > > + // > > > + RequestMsg =3D AllocateZeroPool (sizeof (EFI_HTTP_MESSAGE)); > > > + if (RequestMsg =3D=3D NULL) { > > > + goto ON_ERROR; > > > + } > > > + > > > + ASSERT (HeaderIndex =3D=3D HeaderCount); > > > + RequestMsg->Data.Request =3D RequestData; > > > + RequestMsg->HeaderCount =3D HeaderIndex; > > > + RequestMsg->Headers =3D Headers; > > > + > > > + if (HasContent) { > > > + RequestMsg->BodyLength =3D ContentLength; > > > + RequestMsg->Body =3D Content; > > > + } > > > + > > > + return RequestMsg; > > > + > > > +ON_ERROR: > > > + > > > + if (Headers !=3D NULL) { > > > + HttpFreeHeaderFields (Headers, HeaderIndex); > > > + } > > > + > > > + if (RequestData !=3D NULL) { > > > + FreePool (RequestData); > > > + } > > > + > > > + if (RequestMsg !=3D NULL) { > > > + FreePool (RequestMsg); > > > + } > > > + > > > + if (Url !=3D 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 ReleaseRedfishRespons= e. > > > + > > > + @param[in] ServicePrivate Pointer to Redfish service private d= ata. > > > + @param[in] ResponseMsg Response message from Redfish servic= e. > > > + @param[out] RedfishResponse Redfish response data. > > > + > > > + @retval EFI_SUCCESS Redfish response is returned successfu= lly. > > > + @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 =3D=3D NULL) || (ResponseMsg =3D=3D NULL) || (= RedfishResponse > > =3D=3D NULL)) { > > > + return EFI_INVALID_PARAMETER; > > > + } > > > + > > > + DEBUG ((REDFISH_HTTP_CACHE_DEBUG_REQUEST, "%a\n", __func__)); > > > + > > > + // > > > + // Initialization > > > + // > > > + JsonData =3D NULL; > > > + RedfishResponse->HeaderCount =3D 0; > > > + RedfishResponse->Headers =3D NULL; > > > + RedfishResponse->Payload =3D NULL; > > > + RedfishResponse->StatusCode =3D NULL; > > > + DecodedBody =3D NULL; > > > + DecodedLength =3D 0; > > > + > > > + // > > > + // Return the HTTP StatusCode. > > > + // > > > + if (ResponseMsg->Data.Response !=3D NULL) { > > > + DEBUG ((REDFISH_HTTP_CACHE_DEBUG_REQUEST, "%a: status: %d\n", > > __func__, ResponseMsg->Data.Response->StatusCode)); > > > + RedfishResponse->StatusCode =3D AllocateCopyPool (sizeof > > (EFI_HTTP_STATUS_CODE), &ResponseMsg->Data.Response->StatusCode); > > > + if (RedfishResponse->StatusCode =3D=3D NULL) { > > > + DEBUG ((DEBUG_ERROR, "%a: Failed to create status code.\n", __= func__)); > > > + } > > > + } > > > + > > > + // > > > + // Return the HTTP headers. > > > + // > > > + if (ResponseMsg->Headers !=3D NULL) { > > > + DEBUG ((REDFISH_HTTP_CACHE_DEBUG_REQUEST, "%a: header count: > > %d\n", __func__, ResponseMsg->HeaderCount)); > > > + Status =3D 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 !=3D 0) && (ResponseMsg->Body !=3D NU= LL)) { > > > + DEBUG ((REDFISH_HTTP_CACHE_DEBUG_REQUEST, "%a: body length: > > %d\n", __func__, ResponseMsg->BodyLength)); > > > + // > > > + // Check if data is encoded. > > > + // > > > + ContentEncodedHeader =3D HttpFindHeader (RedfishResponse->Header= Count, > > RedfishResponse->Headers, HTTP_HEADER_CONTENT_ENCODING); > > > + if (ContentEncodedHeader !=3D NULL) { > > > + // > > > + // The content is encoded. > > > + // > > > + Status =3D 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, ContentEncodedHe= ader- > > >FieldValue)); > > > + goto ON_ERROR; > > > + } > > > + > > > + JsonData =3D JsonLoadBuffer (DecodedBody, DecodedLength, 0, NU= LL); > > > + FreePool (DecodedBody); > > > + } else { > > > + JsonData =3D JsonLoadBuffer (ResponseMsg->Body, ResponseMsg- > > >BodyLength, 0, NULL); > > > + } > > > + > > > + if (!JsonValueIsNull (JsonData)) { > > > + RedfishResponse->Payload =3D CreateRedfishPayload (ServicePriv= ate, > > JsonData); > > > + if (RedfishResponse->Payload =3D=3D NULL) { > > > + DEBUG ((DEBUG_ERROR, "%a: Failed to create payload\n.", __fu= nc__)); > > > + } > > > + > > > + JsonValueFree (JsonData); > > > + } else { > > > + DEBUG ((DEBUG_ERROR, "%a: No payload available\n", __func__)); > > > + } > > > + } > > > + > > > + return EFI_SUCCESS; > > > + > > > +ON_ERROR: > > > + > > > + if (RedfishResponse !=3D 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 successfu= lly. > > > + @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 =3D=3D NULL) || IS_EMPTY_STRING (Uri) || (Response = =3D=3D NULL)) { > > > + return EFI_INVALID_PARAMETER; > > > + } > > > + > > > + DEBUG ((REDFISH_HTTP_CACHE_DEBUG_REQUEST, "%a: Method: 0x%x > > %s\n", __func__, Method, Uri)); > > > + > > > + ServicePrivate =3D (REDFISH_SERVICE_PRIVATE *)Service; > > > + if (ServicePrivate->Signature !=3D REDFISH_HTTP_SERVICE_SIGNATURE)= { > > > + DEBUG ((DEBUG_ERROR, "%a: signature check failure\n", __func__))= ; > > > + return EFI_INVALID_PARAMETER; > > > + } > > > + > > > + ZeroMem (&ResponseMsg, sizeof (ResponseMsg)); > > > + HttpContentEncoding =3D (CHAR8 *)PcdGetPtr > > (PcdRedfishServiceContentEncoding); > > > + > > > + RequestMsg =3D BuildRequestMessage (Service, Uri, Method, Request, > > HttpContentEncoding); > > > + if (RequestMsg =3D=3D 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 =3D ServicePrivate->RestEx->SendReceive (ServicePriva= te->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 po= ssible even > > when RestEx returns failure. > > > + // > > > + Status =3D ParseResponseMessage (ServicePrivate, &ResponseMsg, Res= ponse); > > > + if (EFI_ERROR (Status)) { > > > + DEBUG ((DEBUG_ERROR, "%a: %s parse response failure: %r\n", __fu= nc__, > > Uri, Status)); > > > + } else { > > > + // > > > + // Capture session token in header > > > + // > > > + if ((Method =3D=3D HttpMethodPost) && > > > + (Response->StatusCode !=3D NULL) && > > > + ((*Response->StatusCode =3D=3D HTTP_STATUS_200_OK) || (*Resp= onse- > > >StatusCode =3D=3D HTTP_STATUS_204_NO_CONTENT))) > > > + { > > > + XAuthTokenHeader =3D HttpFindHeader (ResponseMsg.HeaderCount, > > ResponseMsg.Headers, HTTP_HEADER_X_AUTH_TOKEN); > > > + if (XAuthTokenHeader !=3D NULL) { > > > + Status =3D UpdateSessionToken (ServicePrivate, XAuthTokenHea= der- > > >FieldValue); > > > + if (EFI_ERROR (Status)) { > > > + DEBUG ((DEBUG_ERROR, "%a: update session token failure: %r= \n", > > __func__, Status)); > > > + } > > > + } > > > + } > > > + } > > > + > > > + // > > > + // Release resources > > > + // > > > + if (RequestMsg !=3D 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 > > > -# Copyright (c) 2023, NVIDIA CORPORATION & AFFILIATES. All rights re= served. > > > +# Copyright (c) 2023-2024, NVIDIA CORPORATION & AFFILIATES. All righ= ts > > reserved. > > > # > > > # SPDX-License-Identifier: BSD-2-Clause-Patent > > > # > > > @@ -20,4 +20,5 @@ > > > INF RedfishPkg/RedfishConfigHandler/RedfishConfigHandlerDriver.inf > > > INF RedfishPkg/RedfishPlatformConfigDxe/RedfishPlatformConfigDxe.in= f > > > INF > > MdeModulePkg/Universal/RegularExpressionDxe/RegularExpressionDxe.inf > > > + INF RedfishPkg/RedfishHttpDxe/RedfishHttpDxe.inf > > > !endif > > > -- > > > 2.34.1 > > > > > > > > > > > >=20 > > > > > > > Regards, > > Mike. > > > -=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D- Groups.io Links: You receive all messages sent to this group. View/Reply Online (#115889): https://edk2.groups.io/g/devel/message/115889 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] -=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-