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 A5F337803CF for ; Fri, 23 Feb 2024 11:29:19 +0000 (UTC) DKIM-Signature: a=rsa-sha256; bh=mL48X3dLydVF6S4B2MKuDEDG64Wyq7Au+MwJ8gtwNz4=; c=relaxed/simple; d=groups.io; h=Mime-Version:Subject:From:In-Reply-To:Date:Cc:Message-Id:References:To: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=1708687758; v=1; b=UC63yHSgKi8FJRQLcfcQcn+AcBZ9fvWs5BPOsxFMT9QWuBpR1fABQeAcB362t+ZAEZ5tRupe StlxvLeO2QdlaF9vd6G6ndnMvvaIfvuHwzJZjZz4z0oL4LnAS9vvbl1pgQh7aEWEnVschIcQFoc DKvWcRsgGWS6nI9NWt2G4bYk= X-Received: by 127.0.0.2 with SMTP id 9IWsYY7687511xOJ13omn0JH; Fri, 23 Feb 2024 03:29:18 -0800 X-Received: from mail-lj1-f180.google.com (mail-lj1-f180.google.com [209.85.208.180]) by mx.groups.io with SMTP id smtpd.web11.8519.1708687756872401280 for ; Fri, 23 Feb 2024 03:29:17 -0800 X-Received: by mail-lj1-f180.google.com with SMTP id 38308e7fff4ca-2d25a7b02d6so10149271fa.2 for ; Fri, 23 Feb 2024 03:29:16 -0800 (PST) X-Gm-Message-State: M3BLuIxT1Icy3eObhBW0dLqux7686176AA= X-Google-Smtp-Source: AGHT+IFGrW6+EUH2GIWsGsCl2/Todw/b5jtAZ2XMgx4Wy832U3StqUXDtDBwAf6CvSm+VJgyWicuoQ== X-Received: by 2002:a19:9110:0:b0:512:cc91:8860 with SMTP id t16-20020a199110000000b00512cc918860mr1213672lfd.9.1708687754197; Fri, 23 Feb 2024 03:29:14 -0800 (PST) X-Received: from smtpclient.apple ([79.164.221.98]) by smtp.gmail.com with ESMTPSA id a17-20020a056512375100b00512c531e9d1sm1345976lfs.119.2024.02.23.03.29.13 (version=TLS1_2 cipher=ECDHE-ECDSA-AES128-GCM-SHA256 bits=128/128); Fri, 23 Feb 2024 03:29:13 -0800 (PST) Mime-Version: 1.0 (Mac OS X Mail 16.0 \(3696.100.31\)) Subject: Re: [edk2-devel] [PATCH v2 2/6] RedfishPkg: implement Redfish HTTP protocol From: "Mike Maslenkin" In-Reply-To: <20240222091122.644-1-nicklew@nvidia.com> Date: Fri, 23 Feb 2024 14:29:12 +0300 Cc: Igor Kulchytskyy , Abner Chang , Nick Ramirez Message-Id: <9A76E719-1472-4E4C-A480-B38C7D305AAF@gmail.com> References: <20240222091122.644-1-nicklew@nvidia.com> To: devel@edk2.groups.io, Nickle Wang 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=UC63yHSg; 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, %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: >=20 > implement Redfish HTTP protocol driver. >=20 > 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 >=20 > 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 communicati= on. > - gEfiRedfishPkgTokenSpaceGuid.PcdRedfishServiceContentEncoding|TRUE|BOO= LEAN|0x0000100A > + # > + # This PCD string is introduced for platform developer to set the enco= ding method supported by BMC Redfish. > + # Currently only "None" and "gzip" are supported. > + # > + gEfiRedfishPkgTokenSpaceGuid.PcdRedfishServiceContentEncoding|"None"|V= OID*|0x0000100A > # > # Use below PCDs to control Redfhs HTTP protocol. > # > diff --git a/RedfishPkg/RedfishComponents.dsc.inc b/RedfishPkg/RedfishCom= ponents.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 reserv= ed. > +# Copyright (c) 2023-2024, NVIDIA CORPORATION & AFFILIATES. All rights r= eserved. > # > # SPDX-License-Identifier: BSD-2-Clause-Patent > # > @@ -28,4 +28,5 @@ > RedfishPkg/RedfishConfigHandler/RedfishConfigHandlerDriver.inf > RedfishPkg/RedfishPlatformConfigDxe/RedfishPlatformConfigDxe.inf > MdeModulePkg/Universal/RegularExpressionDxe/RegularExpressionDxe.inf > + RedfishPkg/RedfishHttpDxe/RedfishHttpDxe.inf > !endif > diff --git a/RedfishPkg/RedfishPkg.dsc b/RedfishPkg/RedfishPkg.dsc > index 25ed193182..5849e7cf9e 100644 > --- a/RedfishPkg/RedfishPkg.dsc > +++ b/RedfishPkg/RedfishPkg.dsc > @@ -45,6 +45,8 @@ > UefiHiiServicesLib|MdeModulePkg/Library/UefiHiiServicesLib/UefiHiiServi= cesLib.inf > RedfishPlatformCredentialLib|RedfishPkg/Library/PlatformCredentialLibNu= ll/PlatformCredentialLibNull.inf > RedfishContentCodingLib|RedfishPkg/Library/RedfishContentCodingLibNull/= RedfishContentCodingLibNull.inf > + ReportStatusCodeLib|MdeModulePkg/Library/DxeReportStatusCodeLib/DxeRep= ortStatusCodeLib.inf > + SortLib|MdeModulePkg/Library/UefiSortLib/UefiSortLib.inf >=20 > # NULL instance of IPMI related library. > IpmiLib|MdeModulePkg/Library/BaseIpmiLibNull/BaseIpmiLibNull.inf > diff --git a/RedfishPkg/RedfishHttpDxe/RedfishHttpDxe.inf b/RedfishPkg/Re= dfishHttpDxe/RedfishHttpDxe.inf > new file mode 100644 > index 0000000000..c7dfdffacf > --- /dev/null > +++ b/RedfishPkg/RedfishHttpDxe/RedfishHttpDxe.inf > @@ -0,0 +1,73 @@ > +## @file > +# RedfishHttpDxe is the DXE driver which provides > +# EdkIIRedfishHttpProtocol to EDK2 Redfish Feature > +# drivers for HTTP operation. > +# > +# Copyright (c) 2023-2024, NVIDIA CORPORATION & AFFILIATES. All rights = reserved. > +# > +# SPDX-License-Identifier: BSD-2-Clause-Patent > +# > +## > + > +[Defines] > + INF_VERSION =3D 0x0001000b > + BASE_NAME =3D RedfishHttpDxe > + FILE_GUID =3D 85ADB2F1-DA93-47D4-AF4F-3D920D9BD2C= 0 > + 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/Red= fishHttpDxe/RedfishHttpData.h > new file mode 100644 > index 0000000000..6be610142e > --- /dev/null > +++ b/RedfishPkg/RedfishHttpDxe/RedfishHttpData.h > @@ -0,0 +1,256 @@ > +/** @file > + Definitions of RedfishHttpData > + > + Copyright (c) 2023-2024, NVIDIA CORPORATION & AFFILIATES. All rights r= eserved. > + > + 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_CAC= HE_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 foun= d. > + > +**/ > +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/Redf= ishHttpDxe/RedfishHttpDxe.h > new file mode 100644 > index 0000000000..cf6ba9cb47 > --- /dev/null > +++ b/RedfishPkg/RedfishHttpDxe/RedfishHttpDxe.h > @@ -0,0 +1,44 @@ > +/** @file > + Definitions of RedfishHttpDxe > + > + Copyright (c) 2023-2024, NVIDIA CORPORATION & AFFILIATES. All rights r= eserved. > + > + 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 length (3= 9) + "https://" (8) + port number (maximum 5) > +#define REDFISH_HTTP_ERROR_REPORT "Redfish HTTP %a failure(0x%x)= : %s" > +#define REDFISH_HTTP_CACHE_DEBUG DEBUG_MANAGEABILITY > +#define REDFISH_HTTP_CACHE_DEBUG_DUMP DEBUG_MANAGEABILITY > +#define REDFISH_HTTP_CACHE_DEBUG_REQUEST DEBUG_MANAGEABILITY > + > +#endif > diff --git a/RedfishPkg/RedfishHttpDxe/RedfishHttpOperation.h b/RedfishPk= g/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 reserv= ed. > + > + 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 availabl= e > + after this function returns successfully. > + > + @param[in] Request HTTP request to be released. > + > + @retval EFI_SUCCESS Resrouce is released successfully. > + @retval Others Errors occur. > + > +**/ > +EFI_STATUS > +ReleaseRedfishRequest ( > + IN REDFISH_REQUEST *Request > + ); > + > +/** > + This function free resources in given Response. > + > + @param[in] Response HTTP response to be released. > + > + @retval EFI_SUCCESS Resrouce is released successfully. > + @retval Others Errors occur. > + > +**/ > +EFI_STATUS > +ReleaseRedfishResponse ( > + IN REDFISH_RESPONSE *Response > + ); > + > +/** > + This function send Redfish request to Redfish service by calling > + Rest Ex protocol. > + > + @param[in] Service Pointer to Redfish service. > + @param[in] Uri Uri of Redfish service. > + @param[in] Method HTTP method. > + @param[in] Request Request data. This is optional. > + @param[out] Response Redfish response data. > + > + @retval EFI_SUCCESS Request is sent and received successfully. > + @retval Others Errors occur. > + > +**/ > +EFI_STATUS > +HttpSendReceive ( > + IN REDFISH_SERVICE Service, > + IN EFI_STRING Uri, > + IN EFI_HTTP_METHOD Method, > + IN REDFISH_REQUEST *Request OPTIONAL, > + OUT REDFISH_RESPONSE *Response > + ); > + > +#endif > diff --git a/RedfishPkg/RedfishHttpDxe/RedfishHttpData.c b/RedfishPkg/Red= fishHttpDxe/RedfishHttpData.c > new file mode 100644 > index 0000000000..bf95e9f8d4 > --- /dev/null > +++ b/RedfishPkg/RedfishHttpDxe/RedfishHttpData.c > @@ -0,0 +1,667 @@ > +/** @file > + RedfishHttpData handles internal data to support Redfish HTTP protocol= . > + > + Copyright (c) 2023-2024, NVIDIA CORPORATION & AFFILIATES. All rights r= eserved. > + > + 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), Toke= n); > + 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->SessionToken)= ); > + FreePool (Service->SessionToken); > + } > + > + FreePool (Service); > + > + return EFI_SUCCESS; > +} > + > +/** > + This function creat new service. Host and HostName are copied to > + newly created service instance. > + > + @param[in] Host Host string. > + @param[in] HostName Hostname string. > + @param[in] BasicAuth Basic Authorization string. > + @param[in] SessionToken Session token string. > + @param[in] RestEx Rest EX protocol instance. > + > + @retval REDFISH_PAYLOAD_PRIVATE Newly created service. > + @retval NULL Error occurs. > + > +**/ > +REDFISH_SERVICE_PRIVATE * > +CreateRedfishService ( > + IN CHAR8 *Host, > + IN CHAR8 *HostName, > + IN CHAR8 *BasicAuth OPTIONAL, > + IN CHAR8 *SessionToken OPTIONAL, > + IN EFI_REST_EX_PROTOCOL *RestEx > + ) > +{ > + REDFISH_SERVICE_PRIVATE *NewService; > + UINTN AuthStrSize; > + > + if (IS_EMPTY_STRING (Host) || IS_EMPTY_STRING (HostName) || (RestEx = =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), Host)= ; > + if (NewService->Host =3D=3D NULL) { > + goto ON_ERROR; > + } > + > + NewService->HostName =3D AllocateCopyPool (AsciiStrSize (HostName), Ho= stName); > + if (NewService->HostName =3D=3D NULL) { > + goto ON_ERROR; > + } > + > + if (!IS_EMPTY_STRING (BasicAuth)) { > + AuthStrSize =3D AsciiStrSize (BasicAuth) + AsciiStrLen (RE= DFISH_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_HTT= P_BASIC_AUTH_STR, BasicAuth); > + } > + > + if (!IS_EMPTY_STRING (SessionToken)) { > + NewService->SessionToken =3D AllocateCopyPool (AsciiStrSize (Session= Token), 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, Service= ->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_STATU= S_CODE), SrcResponse->StatusCode); > + if (DstResponse->StatusCode =3D=3D NULL) { > + goto ON_ERROR; > + } > + } > + > + // > + // Header > + // > + if ((SrcResponse->HeaderCount > 0) && (SrcResponse->Headers !=3D NULL)= ) { > + DstResponse->HeaderCount =3D 0; > + DstResponse->Headers =3D AllocateZeroPool (sizeof (EFI_HTTP_HEAD= ER) * 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 (AsciiS= trSize (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 (Ascii= StrSize (SrcResponse->Headers[Index].FieldValue), SrcResponse->Headers[Inde= x].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, Pay= load->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 released su= ccessfully. > + @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 dat= a. > + @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 foun= d. > + > +**/ > +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 coun= t. > + > + @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 NU= LL)) { > + 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 unuse= d 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__, L= ist->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/Redf= ishHttpDxe/RedfishHttpDxe.c > new file mode 100644 > index 0000000000..39958d4865 > --- /dev/null > +++ b/RedfishPkg/RedfishHttpDxe/RedfishHttpDxe.c > @@ -0,0 +1,1344 @@ > +/** @file > + RedfishHttpDxe produces EdkIIRedfishHttpProtocol > + for EDK2 Redfish Feature driver to do HTTP operations. > + > + Copyright (c) 2023-2024, NVIDIA CORPORATION & AFFILIATES. All rights r= eserved. > + > + 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->Count,= 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, Dat= a->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 request. > + Return false when we don't want to retry r= equest. > + > +**/ > +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 to re= lease 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, AsciiStrSize); > + if (EFI_ERROR (Status)) { > + DEBUG ((DEBUG_ERROR, "UnicodeStrToAsciiStrS failed: %r\n", Status)); > + FreePool (AsciiStr); > + return NULL; > + } > + > + return AsciiStr; > +} > + > +/** > + Return HTTP method in ASCII string. Caller does not need > + to free returned string buffer. > + > + @param[in] Method HTTP method. > + > + @retval CHAR8 * Method in string. > +**/ > +CHAR8 * > +HttpMethodToString ( > + IN EFI_HTTP_METHOD Method > + ) > +{ > + switch (Method) { > + case HttpMethodGet: > + return HTTP_METHOD_GET; > + break; > + case HttpMethodPost: > + return HTTP_METHOD_POST; > + break; > + case HttpMethodPatch: > + return HTTP_METHOD_PATCH; > + break; > + case HttpMethodPut: > + return HTTP_METHOD_PUT; > + break; > + case HttpMethodDelete: > + return HTTP_METHOD_DELETE; > + break; > + default: > + break; > + } > + > + return "Unknown"; > +} > + > +/** > + Report HTTP communication error via report status code. > + > + @param[in] Method HTTP method. > + @param[in] Uri The URI which has failure. > + @param[in] HttpStatusCode HTTP status code. > + > +**/ > +VOID > +ReportHttpError ( > + IN EFI_HTTP_METHOD Method, > + IN EFI_STRING Uri, > + IN EFI_HTTP_STATUS_CODE *HttpStatusCode OPTIONAL > + ) > +{ > + CHAR8 ErrorMsg[REDFISH_ERROR_MSG_MAX]; > + > + if (IS_EMPTY_STRING (Uri)) { > + DEBUG ((DEBUG_ERROR, "%a: no URI to report error status\n", __func__= )); > + return; > + } > + > + // > + // Report failure of URI and HTTP status code. > + // > + AsciiSPrint (ErrorMsg, sizeof (ErrorMsg), REDFISH_HTTP_ERROR_REPORT, H= ttpMethodToString (Method), (HttpStatusCode =3D=3D NULL ? HTTP_STATUS_UNSUP= PORTED_STATUS : *HttpStatusCode), Uri); > + DEBUG ((DEBUG_ERROR, "%a\n", ErrorMsg)); > + // > + // TODO: > + // Below PI status code is approved by PIWG and wait for specification= published. > + // We will uncomment below report status code after PI status code get= published. > + // REF: https://bugzilla.tianocore.org/show_bug.cgi?id=3D4483 > + // > + // REPORT_STATUS_CODE_WITH_EXTENDED_DATA ( > + // EFI_ERROR_CODE | EFI_ERROR_MAJOR, > + // EFI_COMPUTING_UNIT_MANAGEABILITY | EFI_MANAGEABILITY_EC_REDFISH_CO= MMUNICATION_ERROR, > + // ErrorMsg, > + // AsciiStrSize (ErrorMsg) > + // ); > +} > + > +/** > + This function create Redfish service. It's caller's responsibility to = free returned > + Redfish service by calling FreeService (). > + > + @param[in] This Pointer to EDKII_REDFISH_HTTP_P= ROTOCOL instance. > + @param[in] RedfishConfigServiceInfo Redfish config service informat= ion. > + > + @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->RedfishServiceLocation= )) { > + AsciiLocation =3D StringUnicodeToAscii (RedfishConfigServiceInfo->Re= dfishServiceLocation); > + 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", AsciiLocat= ion); > + } else { > + AsciiSPrint (Host, REDFISH_HOST_NAME_MAX, "http://%a", AsciiLocati= on); > + } > + > + 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->RedfishServiceRestExHandle= , > + &gEfiRestExProtocolGuid, > + (VOID **)&RestEx > + ); > + } else { > + DEBUG ((DEBUG_ERROR, "%a: Rest Ex protocol is not available\n", __fu= nc__)); > + 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->CredentialProtocol, > + &AuthMethod, > + &Username, > + &Password > + ); > + if (EFI_ERROR (Status) || IS_EMPTY_STRING (Username) || IS_EMPTY_STR= ING (Password)) { > + DEBUG ((DEBUG_ERROR, "%a: cannot get authentication information: %= r\n", __func__, Status)); > + goto ON_RELEASE; > + } else { > + DEBUG ((REDFISH_HTTP_CACHE_DEBUG, "%a: Auth method: 0x%x username:= %a password: %a\n", __func__, AuthMethod, Username, Password)); > + > + // > + // Perform base64 encoding (RFC 7617) > + // > + UsernameSize =3D AsciiStrSize (Username); > + PasswordSize =3D AsciiStrSize (Password); > + BasicAuthStrSize =3D UsernameSize + PasswordSize; // one byte ta= ken 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) && (EncodedAuthStrSize > = 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", __func_= _, Status)); > + } > + > + DEBUG ((REDFISH_HTTP_CACHE_DEBUG, "%a: Basic authorization: %a\n= ", __func__, EncodedAuthString)); > + } else { > + DEBUG ((DEBUG_ERROR, "%a: Base64Encode failure: %r\n", __func__,= Status)); > + goto ON_RELEASE; > + } > + } > + } > + > + NewService =3D CreateRedfishService (Host, AsciiLocation, EncodedAuthS= tring, 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 ins= tance. > + @param[in] RedfishService Pointer to Redfish service to be released. > + > + @retval EFI_SUCCESS Resrouce is released successfully. > + @retval Others Errors occur. > + > +**/ > +EFI_STATUS > +EFIAPI > +RedfishFreeRedfishService ( > + IN EDKII_REDFISH_HTTP_PROTOCOL *This, > + IN REDFISH_SERVICE RedfishService > + ) > +{ > + REDFISH_SERVICE_PRIVATE *Service; > + > + if ((This =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 JSO= N value > + is a reference to the JSON value in RedfishPayload. Any modification t= o returned > + JSON value will change JSON value in RedfishPayload. > + > + @param[in] This Pointer to EDKII_REDFISH_HTTP_PROTOCOL ins= tance. > + @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 with > + cache mechanism supported. It's caller's responsibility to free Respon= se > + by calling FreeResponse (). > + > + @param[in] This Pointer to EDKII_REDFISH_HTTP_PROTOCOL insta= nce. > + @param[in] Service Redfish service instance to perform HTTP GET= . > + @param[in] Uri Target resource URI. > + @param[in] Request Additional request context. This is optional= . > + @param[out] Response HTTP response from redfish service. > + @param[in] UseCache If it is TRUE, this function will search for > + cache first. If it is FALSE, this function > + will query Redfish URI directly. > + > + @retval EFI_SUCCESS Resrouce is returned successfully. > + @retval Others Errors occur. > + > +**/ > +EFI_STATUS > +EFIAPI > +RedfishGetResource ( > + IN EDKII_REDFISH_HTTP_PROTOCOL *This, > + IN REDFISH_SERVICE Service, > + IN EFI_STRING Uri, > + IN REDFISH_REQUEST *Request OPTIONAL, > + OUT REDFISH_RESPONSE *Response, > + IN BOOLEAN UseCache > + ) > +{ > + EFI_STATUS Status; > + REDFISH_HTTP_CACHE_DATA *CacheData; > + UINTN RetryCount; > + REDFISH_HTTP_CACHE_PRIVATE *Private; > + > + if ((This =3D=3D NULL) || (Service =3D=3D NULL) || (Response =3D=3D NU= LL) || IS_EMPTY_STRING (Uri)) { > + return EFI_INVALID_PARAMETER; > + } > + > + DEBUG ((REDFISH_HTTP_CACHE_DEBUG, "%a: Get URI: %s cache: %a\n", __fun= c__, 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->Response,= 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.Ma= ximumRetryGet)) { > + 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__, Ur= i, 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 availabl= e > + after this function returns successfully. > + > + @param[in] This Pointer to EDKII_REDFISH_HTTP_PROTOCOL instan= ce. > + @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 instan= ce. > + @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 instan= ce. > + @param[in] Uri Target response of URI. > + > + @retval EFI_SUCCESS Target response is expired successfully. > + @retval Others Errors occur. > + > +**/ > +EFI_STATUS > +EFIAPI > +RedfishExpireResponse ( > + IN EDKII_REDFISH_HTTP_PROTOCOL *This, > + IN EFI_STRING Uri > + ) > +{ > + REDFISH_HTTP_CACHE_PRIVATE *Private; > + REDFISH_HTTP_CACHE_DATA *CacheData; > + > + if ((This =3D=3D NULL) || IS_EMPTY_STRING (Uri)) { > + return EFI_INVALID_PARAMETER; > + } > + > + DEBUG ((REDFISH_HTTP_CACHE_DEBUG, "%a: expire URI: %s\n", __func__, Ur= i)); > + > + 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 FreeResponse = (). > + > + @param[in] This Pointer to EDKII_REDFISH_HTTP_PROTOCOL insta= nce. > + @param[in] Service Redfish service instance to perform HTTP PAT= CH. > + @param[in] Uri Target resource URI. > + @param[in] Content Data to patch. > + @param[in] ContentSize Size of the Content to be send to Redfish se= rvice. > + This is optional. When ContentSize is 0, Con= tentSize > + is the size of Content. > + @param[in] ContentType Type of the Content to be send to Redfish se= rvice. > + This is optional. When ContentType is NULL, = content > + type HTTP_CONTENT_TYPE_APP_JSON will be used= . > + @param[out] Response HTTP response from redfish service. > + > + @retval EFI_SUCCESS Resrouce is returned successfully. > + @retval Others Errors occur. > + > +**/ > +EFI_STATUS > +EFIAPI > +RedfishPatchResource ( > + IN EDKII_REDFISH_HTTP_PROTOCOL *This, > + IN REDFISH_SERVICE Service, > + IN EFI_STRING Uri, > + IN CHAR8 *Content, > + IN UINTN ContentSize OPTIONAL, > + IN CHAR8 *ContentType OPTIONAL, > + OUT REDFISH_RESPONSE *Response > + ) > +{ > + EFI_STATUS Status; > + UINTN RetryCount; > + REDFISH_REQUEST Request; > + REDFISH_HTTP_CACHE_PRIVATE *Private; > + > + if ((This =3D=3D NULL) || (Service =3D=3D NULL) || (Response =3D=3D NU= LL) || 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.Ma= ximumRetryPatch)) { > + 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 respon= se > + // so application can directly get resource from Redfish service again= . > + // > + DEBUG ((REDFISH_HTTP_CACHE_DEBUG, "%a: Resource is updated, expire URI= : %s\n", __func__, Uri)); > + RedfishExpireResponse (This, Uri); > + > + if (EFI_ERROR (Status)) { > + DEBUG_CODE ( > + DumpRedfishResponse (NULL, DEBUG_ERROR, Response); > + ); > + // > + // Report status code for Redfish failure > + // > + ReportHttpError (HttpMethodPatch, Uri, Response->StatusCode); > + DEBUG ((DEBUG_ERROR, "%a: patch %s failed (%d/%d): %r\n", __func__, = Uri, RetryCount, Private->RetrySetting.MaximumRetryPatch, Status)); > + goto ON_RELEASE; > + } > + > +ON_RELEASE: > + > + return Status; > +} > + > +/** > + Perform HTTP PUT to send redfish resource to given resource URI. > + It's caller's responsibility to free Response by calling FreeResponse = (). > + > + @param[in] This Pointer to EDKII_REDFISH_HTTP_PROTOCOL insta= nce. > + @param[in] Service Redfish service instance to perform HTTP PUT= . > + @param[in] Uri Target resource URI. > + @param[in] Content Data to put. > + @param[in] ContentSize Size of the Content to be send to Redfish se= rvice. > + This is optional. When ContentSize is 0, Con= tentSize > + is the size of Content. > + @param[in] ContentType Type of the Content to be send to Redfish se= rvice. > + This is optional. When ContentType is NULL, = content > + type HTTP_CONTENT_TYPE_APP_JSON will be used= . > + @param[out] Response HTTP response from redfish service. > + > + @retval EFI_SUCCESS Resrouce is returned successfully. > + @retval Others Errors occur. > + > +**/ > +EFI_STATUS > +EFIAPI > +RedfishPutResource ( > + IN EDKII_REDFISH_HTTP_PROTOCOL *This, > + IN REDFISH_SERVICE Service, > + IN EFI_STRING Uri, > + IN CHAR8 *Content, > + IN UINTN ContentSize OPTIONAL, > + IN CHAR8 *ContentType OPTIONAL, > + OUT REDFISH_RESPONSE *Response > + ) > +{ > + EFI_STATUS Status; > + UINTN RetryCount; > + REDFISH_REQUEST Request; > + REDFISH_HTTP_CACHE_PRIVATE *Private; > + > + if ((This =3D=3D NULL) || (Service =3D=3D NULL) || (Response =3D=3D NU= LL) || 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.Ma= ximumRetryPut)) { > + 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 respon= se > + // so application can directly get resource from Redfish service again= . > + // > + DEBUG ((REDFISH_HTTP_CACHE_DEBUG, "%a: Resource is updated, expire URI= : %s\n", __func__, Uri)); > + RedfishExpireResponse (This, Uri); > + > + if (EFI_ERROR (Status)) { > + DEBUG_CODE ( > + DumpRedfishResponse (NULL, DEBUG_ERROR, Response); > + ); > + // > + // Report status code for Redfish failure > + // > + ReportHttpError (HttpMethodPut, Uri, Response->StatusCode); > + DEBUG ((DEBUG_ERROR, "%a: put %s failed (%d/%d): %r\n", __func__, Ur= i, RetryCount, Private->RetrySetting.MaximumRetryPut, Status)); > + goto ON_RELEASE; > + } > + > +ON_RELEASE: > + > + return Status; > +} > + > +/** > + Perform HTTP POST to send redfish resource to given resource URI. > + It's caller's responsibility to free Response by calling FreeResponse = (). > + > + @param[in] This Pointer to EDKII_REDFISH_HTTP_PROTOCOL insta= nce. > + @param[in] Service Redfish service instance to perform HTTP POS= T. > + @param[in] Uri Target resource URI. > + @param[in] Content Data to post. > + @param[in] ContentSize Size of the Content to be send to Redfish se= rvice. > + This is optional. When ContentSize is 0, Con= tentSize > + is the size of Content. > + @param[in] ContentType Type of the Content to be send to Redfish se= rvice. > + This is optional. When ContentType is NULL, = content > + type HTTP_CONTENT_TYPE_APP_JSON will be used= . > + @param[out] Response HTTP response from redfish service. > + > + @retval EFI_SUCCESS Resrouce is returned successfully. > + @retval Others Errors occur. > + > +**/ > +EFI_STATUS > +EFIAPI > +RedfishPostResource ( > + IN EDKII_REDFISH_HTTP_PROTOCOL *This, > + IN REDFISH_SERVICE Service, > + IN EFI_STRING Uri, > + IN CHAR8 *Content, > + IN UINTN ContentSize OPTIONAL, > + IN CHAR8 *ContentType OPTIONAL, > + OUT REDFISH_RESPONSE *Response > + ) > +{ > + EFI_STATUS Status; > + UINTN RetryCount; > + REDFISH_REQUEST Request; > + REDFISH_HTTP_CACHE_PRIVATE *Private; > + > + if ((This =3D=3D NULL) || (Service =3D=3D NULL) || (Response =3D=3D NU= LL) || 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.Ma= ximumRetryPost)) { > + 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 respon= se > + // so application can directly get resource from Redfish service again= . > + // > + DEBUG ((REDFISH_HTTP_CACHE_DEBUG, "%a: Resource is updated, expire URI= : %s\n", __func__, Uri)); > + RedfishExpireResponse (This, Uri); > + > + if (EFI_ERROR (Status)) { > + DEBUG_CODE ( > + DumpRedfishResponse (NULL, DEBUG_ERROR, Response); > + ); > + // > + // Report status code for Redfish failure > + // > + ReportHttpError (HttpMethodPost, Uri, Response->StatusCode); > + DEBUG ((DEBUG_ERROR, "%a: post %s failed (%d/%d): %r\n", __func__, U= ri, RetryCount, Private->RetrySetting.MaximumRetryPost, Status)); > + goto ON_RELEASE; > + } > + > +ON_RELEASE: > + > + return Status; > +} > + > +/** > + Perform HTTP DELETE to delete redfish resource on given resource URI. > + It's caller's responsibility to free Response by calling FreeResponse = (). > + > + @param[in] This Pointer to EDKII_REDFISH_HTTP_PROTOCOL insta= nce. > + @param[in] Service Redfish service instance to perform HTTP DEL= ETE. > + @param[in] Uri Target resource URI. > + @param[in] Content JSON represented properties to be deleted. T= his is > + optional. > + @param[in] ContentSize Size of the Content to be send to Redfish se= rvice. > + This is optional. When ContentSize is 0, Con= tentSize > + is the size of Content if Content is not NUL= L. > + @param[in] ContentType Type of the Content to be send to Redfish se= rvice. > + This is optional. When Content is not NULL a= nd > + ContentType is NULL, content type HTTP_CONTE= NT_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 NU= LL) || IS_EMPTY_STRING (Uri)) { > + return EFI_INVALID_PARAMETER; > + } > + > + DEBUG ((REDFISH_HTTP_CACHE_DEBUG, "%a: Delete URI: %s\n", __func__, Ur= i)); > + > + 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.Ma= ximumRetryDelete)) { > + 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 respon= se > + // so application can directly get resource from Redfish service again= . > + // > + DEBUG ((REDFISH_HTTP_CACHE_DEBUG, "%a: Resource is updated, expire URI= : %s\n", __func__, Uri)); > + RedfishExpireResponse (This, Uri); > + > + if (EFI_ERROR (Status)) { > + DEBUG_CODE ( > + DumpRedfishResponse (NULL, DEBUG_ERROR, Response); > + ); > + // > + // Report status code for Redfish failure > + // > + ReportHttpError (HttpMethodDelete, Uri, Response->StatusCode); > + DEBUG ((DEBUG_ERROR, "%a: delete %s failed (%d/%d): %r\n", __func__,= Uri, RetryCount, Private->RetrySetting.MaximumRetryDelete, Status)); > + goto ON_RELEASE; > + } > + > +ON_RELEASE: > + > + return Status; > +} > + > +EDKII_REDFISH_HTTP_PROTOCOL mEdkIIRedfishHttpProtocol =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 to be= unloaded. > + > + @retval EFI_SUCCESS The image has been unloaded. > + @retval EFI_INVALID_PARAMETER ImageHandle is not a valid image handl= e. > + > +**/ > +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 handler= . > + > + @param[in] Event Event whose notification function is being invoked= . > + @param[in] Context Pointer to the notification function's context. > + > +**/ > +VOID > +EFIAPI > +CredentialProtocolInstalled ( > + IN EFI_EVENT Event, > + IN VOID *Context > + ) > +{ > + EFI_STATUS Status; > + REDFISH_HTTP_CACHE_PRIVATE *Private; > + > + Private =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_CA= CHE_PRIVATE)); > + if (mRedfishHttpCachePrivate =3D=3D NULL) { > + return EFI_OUT_OF_RESOURCES; > + } > + > + // > + // Initial cache list and protocol instance. > + // > + mRedfishHttpCachePrivate->Signature =3D REDFISH_HTTP_DRIVER_SIGNATUR= E; > + mRedfishHttpCachePrivate->ImageHandle =3D ImageHandle; > + CopyMem (&mRedfishHttpCachePrivate->Protocol, &mEdkIIRedfishHttpProtoc= ol, sizeof (EDKII_REDFISH_HTTP_PROTOCOL)); > + mRedfishHttpCachePrivate->CacheList.Capacity =3D REDFISH_HTTP_CACHE_LI= ST_SIZE; > + mRedfishHttpCachePrivate->CacheList.Count =3D 0x00; > + mRedfishHttpCachePrivate->CacheDisabled =3D PcdGetBool (PcdHttpCa= cheDisabled); > + InitializeListHead (&mRedfishHttpCachePrivate->CacheList.Head); > + > + // > + // Get retry settings > + // > + mRedfishHttpCachePrivate->RetrySetting.MaximumRetryGet =3D PcdGet16= (PcdHttpGetRetry); > + mRedfishHttpCachePrivate->RetrySetting.MaximumRetryPut =3D PcdGet16= (PcdHttpPutRetry); > + mRedfishHttpCachePrivate->RetrySetting.MaximumRetryPatch =3D PcdGet16= (PcdHttpPatchRetry); > + mRedfishHttpCachePrivate->RetrySetting.MaximumRetryPost =3D PcdGet16= (PcdHttpPostRetry); > + mRedfishHttpCachePrivate->RetrySetting.MaximumRetryDelete =3D PcdGet16= (PcdHttpDeleteRetry); > + mRedfishHttpCachePrivate->RetrySetting.RetryWait =3D PcdGet16= (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 installed. > + // > + mRedfishHttpCachePrivate->NotifyEvent =3D EfiCreateProtocolNotifyEvent= ( > + &gEdkIIRedfishCredentialProt= ocolGuid, > + TPL_CALLBACK, > + CredentialProtocolInstalled, > + 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/RedfishPk= g/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 reserv= ed. > + > + SPDX-License-Identifier: BSD-2-Clause-Patent > + > +**/ > + > +#include "RedfishHttpOperation.h" > +#include "RedfishHttpData.h" > + > +/** > + This function copies all headers in SrcHeaders to DstHeaders. > + It's call responsibility to release returned DstHeaders. > + > + @param[in] SrcHeaders Source headers. > + @param[in] SrcHeaderCount Number of header in source headers. > + @param[out] DstHeaders Destination headers. > + @param[out] DstHeaderCount Number of header in designation headers. > + > + @retval EFI_SUCCESS Headers are copied successfully. > + @retval Others Errors occur. > + > +**/ > +EFI_STATUS > +CopyHttpHeaders ( > + IN EFI_HTTP_HEADER *SrcHeaders, > + IN UINTN SrcHeaderCount, > + OUT EFI_HTTP_HEADER **DstHeaders, > + OUT UINTN *DstHeaderCount > + ) > +{ > + UINTN Index; > + > + if ((SrcHeaders =3D=3D NULL) || (SrcHeaderCount =3D=3D 0) || (DstHeade= rs =3D=3D NULL) || (DstHeaderCount =3D=3D NULL)) { > + return EFI_INVALID_PARAMETER; > + } > + > + *DstHeaderCount =3D 0; > + *DstHeaders =3D AllocateZeroPool (sizeof (EFI_HTTP_HEADER) * SrcHe= aderCount); > + if (*DstHeaders =3D=3D NULL) { > + return EFI_OUT_OF_RESOURCES; > + } > + > + for (Index =3D 0; Index < SrcHeaderCount; Index++) { > + (*DstHeaders)[Index].FieldName =3D AllocateCopyPool (AsciiStrSize (S= rcHeaders[Index].FieldName), SrcHeaders[Index].FieldName); > + if ((*DstHeaders)[Index].FieldName =3D=3D NULL) { > + return EFI_OUT_OF_RESOURCES; > + } > + > + (*DstHeaders)[Index].FieldValue =3D AllocateCopyPool (AsciiStrSize (= 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.com/tianocore/e= dk2/blob/master/OvmfPkg/XenBusDxe/Helpers.c#L4 ? > + } > + > + *DstHeaderCount +=3D 1; > + } > + > + return EFI_SUCCESS; > +} > + > +/** > + This function free resources in Request. Request is no longer availabl= e > + 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 messa= ge. > + FALSE if this is response type of HTTP mes= sage. > + > + @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 servic= e. > + 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 serv= ice. > + This is optional. > + @param[in] ContentEncoding Content encoding method to compress HTT= P context. > + This is optional. When ContentEncoding = is NULL, > + No compress method will be performed. > + > + @retval EFI_HTTP_MESSAGE * Pointer to newly created HTTP message= . > + @retval NULL Error occurred. > + > +**/ > +EFI_HTTP_MESSAGE * > +BuildRequestMessage ( > + IN REDFISH_SERVICE_PRIVATE *ServicePrivate, > + IN EFI_STRING Uri, > + IN EFI_HTTP_METHOD Method, > + IN REDFISH_REQUEST *Request OPTIONAL, > + IN CHAR8 *ContentEncoding OPTIONAL > + ) > +{ > + EFI_STATUS Status; > + EFI_STRING Url; > + UINTN UrlSize; > + UINTN Index; > + EFI_HTTP_MESSAGE *RequestMsg; > + EFI_HTTP_REQUEST_DATA *RequestData; > + UINTN HeaderCount; > + UINTN HeaderIndex; > + EFI_HTTP_HEADER *Headers; > + CHAR8 ContentLengthStr[REDFISH_CONTENT_LENGTH_SIZE]; > + VOID *Content; > + UINTN ContentLength; > + BOOLEAN HasContent; > + BOOLEAN DoContentEncoding; > + > + RequestMsg =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__, U= rl)); > + > + // > + // Step 1: build the HTTP headers. > + // > + if (!IS_EMPTY_STRING (ServicePrivate->SessionToken) || !IS_EMPTY_STRIN= G (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_HEADER)); > + if (Headers =3D=3D NULL) { > + goto ON_ERROR; > + } > + > + if (!IS_EMPTY_STRING (ServicePrivate->SessionToken)) { > + Status =3D HttpSetFieldNameAndValue (&Headers[HeaderIndex++], HTTP_H= EADER_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_H= EADER_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++], Requ= est->Headers[Index].FieldName, Request->Headers[Index].FieldValue); > + if (EFI_ERROR (Status)) { > + goto ON_ERROR; > + } > + } > + } > + > + Status =3D HttpSetFieldNameAndValue (&Headers[HeaderIndex++], HTTP_HEA= DER_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_HEA= DER_ACCEPT, HTTP_CONTENT_TYPE_APP_JSON); > + if (EFI_ERROR (Status)) { > + goto ON_ERROR; > + } > + > + Status =3D HttpSetFieldNameAndValue (&Headers[HeaderIndex++], HTTP_HEA= DER_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_H= EADER_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", __func__)= ); > + 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++], HT= TP_HEADER_CONTENT_ENCODING, HTTP_CONTENT_ENCODING_IDENTITY); > + if (EFI_ERROR (Status)) { > + goto ON_ERROR; > + } > + } else { > + Status =3D HttpSetFieldNameAndValue (&Headers[HeaderIndex++], HT= TP_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 p= roperly release it later. > + // > + if (!DoContentEncoding) { > + Content =3D AllocateCopyPool (Request->ContentLength, Request->Con= tent); > + 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 ReleaseRedfishResponse. > + > + @param[in] ServicePrivate Pointer to Redfish service private data. > + @param[in] ResponseMsg Response message from Redfish service. > + @param[out] RedfishResponse Redfish response data. > + > + @retval EFI_SUCCESS Redfish response is returned successfully. > + @retval Others Errors occur. > + > +**/ > +EFI_STATUS > +ParseResponseMessage ( > + IN REDFISH_SERVICE_PRIVATE *ServicePrivate, > + IN EFI_HTTP_MESSAGE *ResponseMsg, > + OUT REDFISH_RESPONSE *RedfishResponse > + ) > +{ > + EFI_STATUS Status; > + EDKII_JSON_VALUE JsonData; > + EFI_HTTP_HEADER *ContentEncodedHeader; > + VOID *DecodedBody; > + UINTN DecodedLength; > + > + if ((ServicePrivate =3D=3D NULL) || (ResponseMsg =3D=3D NULL) || (Redf= ishResponse =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_S= TATUS_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", __fu= nc__, Status)); > + } > + } > + > + // > + // Return the HTTP body. > + // > + if ((ResponseMsg->BodyLength !=3D 0) && (ResponseMsg->Body !=3D NULL))= { > + DEBUG ((REDFISH_HTTP_CACHE_DEBUG_REQUEST, "%a: body length: %d\n", _= _func__, ResponseMsg->BodyLength)); > + // > + // Check if data is encoded. > + // > + ContentEncodedHeader =3D HttpFindHeader (RedfishResponse->HeaderCoun= t, 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 cont= ent: %r decoding method: %a\n.", __func__, Status, ContentEncodedHeader->Fi= eldValue)); > + goto ON_ERROR; > + } > + > + JsonData =3D JsonLoadBuffer (DecodedBody, DecodedLength, 0, NULL); > + FreePool (DecodedBody); > + } else { > + JsonData =3D JsonLoadBuffer (ResponseMsg->Body, ResponseMsg->BodyL= ength, 0, NULL); > + } > + > + if (!JsonValueIsNull (JsonData)) { > + RedfishResponse->Payload =3D CreateRedfishPayload (ServicePrivate,= JsonData); > + if (RedfishResponse->Payload =3D=3D NULL) { > + DEBUG ((DEBUG_ERROR, "%a: Failed to create payload\n.", __func__= )); > + } > + > + JsonValueFree (JsonData); > + } else { > + DEBUG ((DEBUG_ERROR, "%a: No payload available\n", __func__)); > + } > + } > + > + return EFI_SUCCESS; > + > +ON_ERROR: > + > + if (RedfishResponse !=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 successfully. > + @retval Others Errors occur. > + > +**/ > +EFI_STATUS > +HttpSendReceive ( > + IN REDFISH_SERVICE Service, > + IN EFI_STRING Uri, > + IN EFI_HTTP_METHOD Method, > + IN REDFISH_REQUEST *Request OPTIONAL, > + OUT REDFISH_RESPONSE *Response > + ) > +{ > + EFI_STATUS Status; > + EFI_STATUS RestExStatus; > + EFI_HTTP_MESSAGE *RequestMsg; > + EFI_HTTP_MESSAGE ResponseMsg; > + REDFISH_SERVICE_PRIVATE *ServicePrivate; > + EFI_HTTP_HEADER *XAuthTokenHeader; > + CHAR8 *HttpContentEncoding; > + > + if ((Service =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", __f= unc__, 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 (PcdRedfishServiceContentEn= coding); > + > + RequestMsg =3D BuildRequestMessage (Service, Uri, Method, Request, Htt= pContentEncoding); > + 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 (ServicePrivate->= RestEx, RequestMsg, &ResponseMsg); > + if (EFI_ERROR (RestExStatus)) { > + DEBUG ((DEBUG_ERROR, "%a: %s SendReceive failure: %r\n", __func__, U= ri, RestExStatus)); > + } > + > + // > + // Return status code, headers and payload to caller as much as possib= le even when RestEx returns failure. > + // > + Status =3D ParseResponseMessage (ServicePrivate, &ResponseMsg, Respons= e); > + if (EFI_ERROR (Status)) { > + DEBUG ((DEBUG_ERROR, "%a: %s parse response failure: %r\n", __func__= , Uri, Status)); > + } else { > + // > + // Capture session token in header > + // > + if ((Method =3D=3D HttpMethodPost) && > + (Response->StatusCode !=3D NULL) && > + ((*Response->StatusCode =3D=3D HTTP_STATUS_200_OK) || (*Response= ->StatusCode =3D=3D HTTP_STATUS_204_NO_CONTENT))) > + { > + XAuthTokenHeader =3D HttpFindHeader (ResponseMsg.HeaderCount, Resp= onseMsg.Headers, HTTP_HEADER_X_AUTH_TOKEN); > + if (XAuthTokenHeader !=3D NULL) { > + Status =3D UpdateSessionToken (ServicePrivate, XAuthTokenHeader-= >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 reserv= ed. > +# Copyright (c) 2023-2024, NVIDIA CORPORATION & AFFILIATES. All rights r= eserved. > # > # SPDX-License-Identifier: BSD-2-Clause-Patent > # > @@ -20,4 +20,5 @@ > INF RedfishPkg/RedfishConfigHandler/RedfishConfigHandlerDriver.inf > INF RedfishPkg/RedfishPlatformConfigDxe/RedfishPlatformConfigDxe.inf > INF MdeModulePkg/Universal/RegularExpressionDxe/RegularExpressionDxe.in= f > + INF RedfishPkg/RedfishHttpDxe/RedfishHttpDxe.inf > !endif > -- > 2.34.1 >=20 >=20 >=20 >=20 >=20 Regards, Mike. >=20 -=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 (#115881): https://edk2.groups.io/g/devel/message/115881 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-