public inbox for devel@edk2.groups.io
 help / color / mirror / Atom feed
* [edk2-devel] [PATCH v2 2/6] RedfishPkg: implement Redfish HTTP protocol
@ 2024-02-22  9:11 Nickle Wang via groups.io
  2024-02-22 13:39 ` Chang, Abner via groups.io
                   ` (2 more replies)
  0 siblings, 3 replies; 15+ messages in thread
From: Nickle Wang via groups.io @ 2024-02-22  9:11 UTC (permalink / raw)
  To: devel; +Cc: Igor Kulchytskyy, Abner Chang, Nick Ramirez

implement Redfish HTTP protocol driver.

Signed-off-by: Nickle Wang <nicklew@nvidia.com>
Co-authored-by: Igor Kulchytskyy <igork@ami.com>
Cc: Abner Chang <abner.chang@amd.com>
Cc: Igor Kulchytskyy <igork@ami.com>
Cc: Nick Ramirez <nramirez@nvidia.com>
---
 RedfishPkg/RedfishPkg.dec                     |    7 +-
 RedfishPkg/RedfishComponents.dsc.inc          |    3 +-
 RedfishPkg/RedfishPkg.dsc                     |    2 +
 RedfishPkg/RedfishHttpDxe/RedfishHttpDxe.inf  |   73 +
 RedfishPkg/RedfishHttpDxe/RedfishHttpData.h   |  256 ++++
 RedfishPkg/RedfishHttpDxe/RedfishHttpDxe.h    |   44 +
 .../RedfishHttpDxe/RedfishHttpOperation.h     |   76 +
 RedfishPkg/RedfishHttpDxe/RedfishHttpData.c   |  667 ++++++++
 RedfishPkg/RedfishHttpDxe/RedfishHttpDxe.c    | 1344 +++++++++++++++++
 .../RedfishHttpDxe/RedfishHttpOperation.c     |  693 +++++++++
 RedfishPkg/Redfish.fdf.inc                    |    3 +-
 11 files changed, 3164 insertions(+), 4 deletions(-)
 create mode 100644 RedfishPkg/RedfishHttpDxe/RedfishHttpDxe.inf
 create mode 100644 RedfishPkg/RedfishHttpDxe/RedfishHttpData.h
 create mode 100644 RedfishPkg/RedfishHttpDxe/RedfishHttpDxe.h
 create mode 100644 RedfishPkg/RedfishHttpDxe/RedfishHttpOperation.h
 create mode 100644 RedfishPkg/RedfishHttpDxe/RedfishHttpData.c
 create mode 100644 RedfishPkg/RedfishHttpDxe/RedfishHttpDxe.c
 create mode 100644 RedfishPkg/RedfishHttpDxe/RedfishHttpOperation.c

diff --git a/RedfishPkg/RedfishPkg.dec b/RedfishPkg/RedfishPkg.dec
index 9b424efdf3..114f8d2ad8 100644
--- a/RedfishPkg/RedfishPkg.dec
+++ b/RedfishPkg/RedfishPkg.dec
@@ -157,8 +157,11 @@
   # set to EFI_REST_EX_PROTOCOL.
   #
   gEfiRedfishPkgTokenSpaceGuid.PcdRedfishSendReceiveTimeout|5000|UINT32|0x00001009
-  ## This is used to enable HTTP content encoding on Redfish communication.
-  gEfiRedfishPkgTokenSpaceGuid.PcdRedfishServiceContentEncoding|TRUE|BOOLEAN|0x0000100A
+  #
+  # This PCD string is introduced for platform developer to set the encoding method supported by BMC Redfish.
+  # Currently only "None" and "gzip" are supported.
+  #
+  gEfiRedfishPkgTokenSpaceGuid.PcdRedfishServiceContentEncoding|"None"|VOID*|0x0000100A
   #
   # Use below PCDs to control Redfhs HTTP protocol.
   #
diff --git a/RedfishPkg/RedfishComponents.dsc.inc b/RedfishPkg/RedfishComponents.dsc.inc
index 464ffc8606..d6c5b73d7f 100644
--- a/RedfishPkg/RedfishComponents.dsc.inc
+++ b/RedfishPkg/RedfishComponents.dsc.inc
@@ -7,7 +7,7 @@
 # "RedfishDefines.dsc.inc".
 #
 # (C) Copyright 2020-2021 Hewlett Packard Enterprise Development LP<BR>
-# Copyright (c) 2023, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
+# Copyright (c) 2023-2024, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
 #
 #    SPDX-License-Identifier: BSD-2-Clause-Patent
 #
@@ -28,4 +28,5 @@
   RedfishPkg/RedfishConfigHandler/RedfishConfigHandlerDriver.inf
   RedfishPkg/RedfishPlatformConfigDxe/RedfishPlatformConfigDxe.inf
   MdeModulePkg/Universal/RegularExpressionDxe/RegularExpressionDxe.inf
+  RedfishPkg/RedfishHttpDxe/RedfishHttpDxe.inf
 !endif
diff --git a/RedfishPkg/RedfishPkg.dsc b/RedfishPkg/RedfishPkg.dsc
index 25ed193182..5849e7cf9e 100644
--- a/RedfishPkg/RedfishPkg.dsc
+++ b/RedfishPkg/RedfishPkg.dsc
@@ -45,6 +45,8 @@
   UefiHiiServicesLib|MdeModulePkg/Library/UefiHiiServicesLib/UefiHiiServicesLib.inf
   RedfishPlatformCredentialLib|RedfishPkg/Library/PlatformCredentialLibNull/PlatformCredentialLibNull.inf
   RedfishContentCodingLib|RedfishPkg/Library/RedfishContentCodingLibNull/RedfishContentCodingLibNull.inf
+  ReportStatusCodeLib|MdeModulePkg/Library/DxeReportStatusCodeLib/DxeReportStatusCodeLib.inf
+  SortLib|MdeModulePkg/Library/UefiSortLib/UefiSortLib.inf
 
   # NULL instance of IPMI related library.
   IpmiLib|MdeModulePkg/Library/BaseIpmiLibNull/BaseIpmiLibNull.inf
diff --git a/RedfishPkg/RedfishHttpDxe/RedfishHttpDxe.inf b/RedfishPkg/RedfishHttpDxe/RedfishHttpDxe.inf
new file mode 100644
index 0000000000..c7dfdffacf
--- /dev/null
+++ b/RedfishPkg/RedfishHttpDxe/RedfishHttpDxe.inf
@@ -0,0 +1,73 @@
+## @file
+#  RedfishHttpDxe is the DXE driver which provides
+#  EdkIIRedfishHttpProtocol to EDK2 Redfish Feature
+#  drivers for HTTP operation.
+#
+#  Copyright (c) 2023-2024, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
+#
+#  SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+  INF_VERSION                    = 0x0001000b
+  BASE_NAME                      = RedfishHttpDxe
+  FILE_GUID                      = 85ADB2F1-DA93-47D4-AF4F-3D920D9BD2C0
+  MODULE_TYPE                    = DXE_DRIVER
+  VERSION_STRING                 = 1.0
+  ENTRY_POINT                    = RedfishHttpEntryPoint
+  UNLOAD_IMAGE                   = RedfishHttpDriverUnload
+
+#
+#  VALID_ARCHITECTURES           = IA32 X64 ARM AARCH64 RISCV64
+#
+
+[Sources]
+  RedfishHttpData.c
+  RedfishHttpData.h
+  RedfishHttpDxe.c
+  RedfishHttpDxe.h
+  RedfishHttpOperation.c
+  RedfishHttpOperation.h
+
+[Packages]
+  MdePkg/MdePkg.dec
+  MdeModulePkg/MdeModulePkg.dec
+  NetworkPkg/NetworkPkg.dec
+  RedfishPkg/RedfishPkg.dec
+
+[LibraryClasses.ARM]
+  ArmSoftFloatLib
+
+[LibraryClasses]
+  BaseLib
+  BaseMemoryLib
+  RedfishContentCodingLib
+  DebugLib
+  HttpLib
+  JsonLib
+  MemoryAllocationLib
+  PrintLib
+  RedfishDebugLib
+  ReportStatusCodeLib
+  UefiBootServicesTableLib
+  UefiDriverEntryPoint
+  UefiLib
+
+[Protocols]
+  gEdkIIRedfishHttpProtocolGuid             ## PRODUCED
+  gEdkIIRedfishCredentialProtocolGuid       ## CONSUMES
+  gEfiRestExProtocolGuid                    ## CONSUEMS
+
+[Pcd]
+  gEfiRedfishPkgTokenSpaceGuid.PcdHttpGetRetry
+  gEfiRedfishPkgTokenSpaceGuid.PcdHttpPutRetry
+  gEfiRedfishPkgTokenSpaceGuid.PcdHttpPatchRetry
+  gEfiRedfishPkgTokenSpaceGuid.PcdHttpPostRetry
+  gEfiRedfishPkgTokenSpaceGuid.PcdHttpDeleteRetry
+  gEfiRedfishPkgTokenSpaceGuid.PcdHttpRetryWaitInSecond
+  gEfiRedfishPkgTokenSpaceGuid.PcdHttpCacheDisabled
+  gEfiRedfishPkgTokenSpaceGuid.PcdRedfishServiceContentEncoding
+
+[Depex]
+  TRUE
diff --git a/RedfishPkg/RedfishHttpDxe/RedfishHttpData.h b/RedfishPkg/RedfishHttpDxe/RedfishHttpData.h
new file mode 100644
index 0000000000..6be610142e
--- /dev/null
+++ b/RedfishPkg/RedfishHttpDxe/RedfishHttpData.h
@@ -0,0 +1,256 @@
+/** @file
+  Definitions of RedfishHttpData
+
+  Copyright (c) 2023-2024, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef EDKII_REDFISH_HTTP_DATA_H_
+#define EDKII_REDFISH_HTTP_DATA_H_
+
+#include "RedfishHttpDxe.h"
+
+#define REDFISH_HTTP_DRIVER_SIGNATURE   SIGNATURE_32 ('r', 'f', 'h', 'p')
+#define REDFISH_HTTP_CACHE_SIGNATURE    SIGNATURE_32 ('r', 'f', 'c', 'h')
+#define REDFISH_HTTP_SERVICE_SIGNATURE  SIGNATURE_32 ('r', 'f', 's', 'v')
+#define REDFISH_HTTP_PAYLOAD_SIGNATURE  SIGNATURE_32 ('r', 'f', 'p', 'l')
+#define REDFISH_HTTP_BASIC_AUTH_STR     "Basic "
+
+///
+/// REDFISH_SERVICE_PRIVATE definition.
+///
+typedef struct {
+  UINT32                  Signature;
+  CHAR8                   *Host;
+  CHAR8                   *HostName;
+  CHAR8                   *BasicAuth;
+  CHAR8                   *SessionToken;
+  EFI_REST_EX_PROTOCOL    *RestEx;
+} REDFISH_SERVICE_PRIVATE;
+
+///
+/// REDFISH_PAYLOAD_PRIVATE definition.
+///
+typedef struct {
+  UINT32                     Signature;
+  REDFISH_SERVICE_PRIVATE    *Service;
+  EDKII_JSON_VALUE           JsonValue;
+} REDFISH_PAYLOAD_PRIVATE;
+
+///
+/// Definition of REDFISH_HTTP_CACHE_DATA
+///
+typedef struct {
+  UINT32              Signature;
+  LIST_ENTRY          List;
+  EFI_STRING          Uri;
+  UINTN               HitCount;
+  REDFISH_RESPONSE    *Response;
+} REDFISH_HTTP_CACHE_DATA;
+
+#define REDFISH_HTTP_CACHE_FROM_LIST(a)  CR (a, REDFISH_HTTP_CACHE_DATA, List, REDFISH_HTTP_CACHE_SIGNATURE)
+
+///
+/// Definition of REDFISH_HTTP_CACHE_LIST
+///
+typedef struct {
+  LIST_ENTRY    Head;
+  UINTN         Count;
+  UINTN         Capacity;
+} REDFISH_HTTP_CACHE_LIST;
+
+///
+/// Definition of REDFISH_HTTP_RETRY_SETTING
+///
+typedef struct {
+  UINT16    MaximumRetryGet;
+  UINT16    MaximumRetryPut;
+  UINT16    MaximumRetryPost;
+  UINT16    MaximumRetryPatch;
+  UINT16    MaximumRetryDelete;
+  UINTN     RetryWait;
+} REDFISH_HTTP_RETRY_SETTING;
+
+///
+/// Definition of REDFISH_HTTP_CACHE_PRIVATE
+///
+typedef struct {
+  UINT32                               Signature;
+  EFI_HANDLE                           ImageHandle;
+  BOOLEAN                              CacheDisabled;
+  EFI_EVENT                            NotifyEvent;
+  REDFISH_HTTP_CACHE_LIST              CacheList;
+  EDKII_REDFISH_HTTP_PROTOCOL          Protocol;
+  EDKII_REDFISH_CREDENTIAL_PROTOCOL    *CredentialProtocol;
+  REDFISH_HTTP_RETRY_SETTING           RetrySetting;
+} REDFISH_HTTP_CACHE_PRIVATE;
+
+#define REDFISH_HTTP_CACHE_PRIVATE_FROM_THIS(a)  CR (a, REDFISH_HTTP_CACHE_PRIVATE, Protocol, REDFISH_HTTP_DRIVER_SIGNATURE)
+
+/**
+  Search on given ListHeader for given URI string.
+
+  @param[in]    ListHeader  Target list to search.
+  @param[in]    Uri         Target URI to search.
+
+  @retval REDFISH_HTTP_CACHE_DATA   Target cache data is found.
+  @retval NULL                      No cache data with given URI is found.
+
+**/
+REDFISH_HTTP_CACHE_DATA *
+FindHttpCacheData (
+  IN  LIST_ENTRY  *ListHeader,
+  IN  EFI_STRING  Uri
+  );
+
+/**
+  This function copy the data in SrcResponse to DstResponse.
+
+  @param[in]  SrcResponse      Source Response to copy.
+  @param[out] DstResponse      Destination Response.
+
+  @retval     EFI_SUCCESS      Response is copied successfully.
+  @retval     Others           Error occurs.
+
+**/
+EFI_STATUS
+CopyRedfishResponse (
+  IN  REDFISH_RESPONSE  *SrcResponse,
+  OUT REDFISH_RESPONSE  *DstResponse
+  );
+
+/**
+  Release all cache from list.
+
+  @param[in]    CacheList    The list to be released.
+
+  @retval EFI_SUCCESS             All cache data are released.
+  @retval EFI_INVALID_PARAMETER   CacheList is NULL.
+
+**/
+EFI_STATUS
+ReleaseCacheList (
+  IN  REDFISH_HTTP_CACHE_LIST  *CacheList
+  );
+
+/**
+  Add new cache by given URI and HTTP response to specify List.
+
+  @param[in]    List      Target cache list to add.
+  @param[in]    Uri       The URI string matching to this cache data.
+  @param[in]    Response  HTTP response.
+
+  @retval EFI_SUCCESS   Cache data is added.
+  @retval Others        Fail to add cache data.
+
+**/
+EFI_STATUS
+AddHttpCacheData (
+  IN  REDFISH_HTTP_CACHE_LIST  *List,
+  IN  EFI_STRING               Uri,
+  IN  REDFISH_RESPONSE         *Response
+  );
+
+/**
+  Delete a cache data by given cache instance.
+
+  @param[in]    List    Target cache list to be removed.
+  @param[in]    Data    Pointer to the instance to be deleted.
+
+  @retval EFI_SUCCESS   Cache data is removed.
+  @retval Others        Fail to remove cache data.
+
+**/
+EFI_STATUS
+DeleteHttpCacheData (
+  IN  REDFISH_HTTP_CACHE_LIST  *List,
+  IN  REDFISH_HTTP_CACHE_DATA  *Data
+  );
+
+/**
+  This function release Redfish Payload.
+
+  @param[in]  Payload         Pointer to payload instance.
+
+  @retval     EFI_SUCCESS     Payload is released.
+  @retval     Others          Error occurs.
+
+**/
+EFI_STATUS
+ReleaseRedfishPayload (
+  IN REDFISH_PAYLOAD_PRIVATE  *Payload
+  );
+
+/**
+  This function creat new payload. Server and JsonObj are
+  copied to newly created payload.
+
+  @param[in]  Service          Pointer to Service instance.
+  @param[in]  JsonObj          Pointer to JSON object.
+
+  @retval     REDFISH_PAYLOAD_PRIVATE  Newly created payload.
+  @retval     NULL             Error occurs.
+
+**/
+REDFISH_PAYLOAD_PRIVATE *
+CreateRedfishPayload (
+  IN REDFISH_SERVICE_PRIVATE  *Service,
+  IN EDKII_JSON_VALUE         JsonValue
+  );
+
+/**
+  This function release Redfish Service.
+
+  @param[in]  Service         Pointer to service instance.
+
+  @retval     EFI_SUCCESS     Service is released.
+  @retval     Others          Error occurs.
+
+**/
+EFI_STATUS
+ReleaseRedfishService (
+  IN REDFISH_SERVICE_PRIVATE  *Service
+  );
+
+/**
+  This function creat new service. Host and HostName are copied to
+  newly created service instance.
+
+  @param[in]  Host            Host string.
+  @param[in]  HostName        Hostname string.
+  @param[in]  BasicAuth       Basic Authorization string.
+  @param[in]  SessionToken    Session token string.
+  @param[in]  RestEx          Rest EX protocol instance.
+
+  @retval     REDFISH_PAYLOAD_PRIVATE  Newly created service.
+  @retval     NULL             Error occurs.
+
+**/
+REDFISH_SERVICE_PRIVATE *
+CreateRedfishService (
+  IN CHAR8                 *Host,
+  IN CHAR8                 *HostName,
+  IN CHAR8                 *BasicAuth OPTIONAL,
+  IN CHAR8                 *SessionToken OPTIONAL,
+  IN EFI_REST_EX_PROTOCOL  *RestEx
+  );
+
+/**
+  This function update session token in Redfish Service.
+
+  @param[in]  Service         Pointer to service instance.
+  @param[in]  Token           Session token.
+
+  @retval     EFI_SUCCESS     Session token is updated.
+  @retval     Others          Error occurs.
+
+**/
+EFI_STATUS
+UpdateSessionToken (
+  IN REDFISH_SERVICE_PRIVATE  *Service,
+  IN CHAR8                    *Token
+  );
+
+#endif
diff --git a/RedfishPkg/RedfishHttpDxe/RedfishHttpDxe.h b/RedfishPkg/RedfishHttpDxe/RedfishHttpDxe.h
new file mode 100644
index 0000000000..cf6ba9cb47
--- /dev/null
+++ b/RedfishPkg/RedfishHttpDxe/RedfishHttpDxe.h
@@ -0,0 +1,44 @@
+/** @file
+  Definitions of RedfishHttpDxe
+
+  Copyright (c) 2023-2024, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef EDKII_REDFISH_HTTP_DXE_H_
+#define EDKII_REDFISH_HTTP_DXE_H_
+
+#include <Uefi.h>
+#include <IndustryStandard/Http11.h>
+
+#include <Library/UefiLib.h>
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/RedfishContentCodingLib.h>
+#include <Library/DebugLib.h>
+#include <Library/HttpLib.h>
+#include <Library/JsonLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/RedfishDebugLib.h>
+#include <Library/ReportStatusCodeLib.h>
+#include <Library/PrintLib.h>
+
+#include <Protocol/Http.h>
+#include <Protocol/EdkIIRedfishHttpProtocol.h>
+#include <Protocol/EdkIIRedfishCredential.h>
+#include <Protocol/RestEx.h>
+
+#define IS_EMPTY_STRING(a)  ((a) == NULL || (a)[0] == '\0')
+#define REDFISH_HTTP_CACHE_LIST_SIZE      0x80
+#define REDFISH_ERROR_MSG_MAX             128
+#define REDFISH_DEBUG_STRING_LENGTH       200
+#define REDFISH_HOST_NAME_MAX             64   // IPv6 maximum length (39) + "https://" (8) + port number (maximum 5)
+#define REDFISH_HTTP_ERROR_REPORT         "Redfish HTTP %a failure(0x%x): %s"
+#define REDFISH_HTTP_CACHE_DEBUG          DEBUG_MANAGEABILITY
+#define REDFISH_HTTP_CACHE_DEBUG_DUMP     DEBUG_MANAGEABILITY
+#define REDFISH_HTTP_CACHE_DEBUG_REQUEST  DEBUG_MANAGEABILITY
+
+#endif
diff --git a/RedfishPkg/RedfishHttpDxe/RedfishHttpOperation.h b/RedfishPkg/RedfishHttpDxe/RedfishHttpOperation.h
new file mode 100644
index 0000000000..d2f7cf4c27
--- /dev/null
+++ b/RedfishPkg/RedfishHttpDxe/RedfishHttpOperation.h
@@ -0,0 +1,76 @@
+/** @file
+  Definitions of RedfishHttpOperation
+
+  Copyright (c) 2024, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef EDKII_REDFISH_HTTP_OPERATION_H_
+#define EDKII_REDFISH_HTTP_OPERATION_H_
+
+#include "RedfishHttpDxe.h"
+
+#define REDFISH_CONTENT_LENGTH_SIZE              80
+#define REDFISH_COMMON_HEADER_SIZE               5
+#define REDFISH_HTTP_HEADER_ODATA_VERSION_STR    "OData-Version"
+#define REDFISH_HTTP_HEADER_ODATA_VERSION_VALUE  "4.0"
+#define REDFISH_HTTP_HEADER_USER_AGENT_VALUE     "edk2redfish"
+#define REDFISH_HTTP_HEADER_CONNECTION_STR       "Connection"
+#define REDFISH_HTTP_HEADER_CONNECTION_VALUE     "Keep-Alive"
+#define REDFISH_HTTP_CONTENT_ENCODING_NONE       "None"
+
+/**
+  This function free resources in Request. Request is no longer available
+  after this function returns successfully.
+
+  @param[in]  Request      HTTP request to be released.
+
+  @retval     EFI_SUCCESS     Resrouce is released successfully.
+  @retval     Others          Errors occur.
+
+**/
+EFI_STATUS
+ReleaseRedfishRequest (
+  IN  REDFISH_REQUEST  *Request
+  );
+
+/**
+  This function free resources in given Response.
+
+  @param[in]  Response     HTTP response to be released.
+
+  @retval     EFI_SUCCESS     Resrouce is released successfully.
+  @retval     Others          Errors occur.
+
+**/
+EFI_STATUS
+ReleaseRedfishResponse (
+  IN  REDFISH_RESPONSE  *Response
+  );
+
+/**
+  This function send Redfish request to Redfish service by calling
+  Rest Ex protocol.
+
+  @param[in]   Service       Pointer to Redfish service.
+  @param[in]   Uri           Uri of Redfish service.
+  @param[in]   Method        HTTP method.
+  @param[in]   Request     Request data. This is optional.
+  @param[out]  Response    Redfish response data.
+
+  @retval     EFI_SUCCESS     Request is sent and received successfully.
+  @retval     Others          Errors occur.
+
+**/
+EFI_STATUS
+HttpSendReceive (
+  IN  REDFISH_SERVICE   Service,
+  IN  EFI_STRING        Uri,
+  IN  EFI_HTTP_METHOD   Method,
+  IN  REDFISH_REQUEST   *Request  OPTIONAL,
+  OUT REDFISH_RESPONSE  *Response
+  );
+
+#endif
diff --git a/RedfishPkg/RedfishHttpDxe/RedfishHttpData.c b/RedfishPkg/RedfishHttpDxe/RedfishHttpData.c
new file mode 100644
index 0000000000..bf95e9f8d4
--- /dev/null
+++ b/RedfishPkg/RedfishHttpDxe/RedfishHttpData.c
@@ -0,0 +1,667 @@
+/** @file
+  RedfishHttpData handles internal data to support Redfish HTTP protocol.
+
+  Copyright (c) 2023-2024, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "RedfishHttpData.h"
+#include "RedfishHttpOperation.h"
+
+/**
+  This function update session token in Redfish Service.
+
+  @param[in]  Service         Pointer to service instance.
+  @param[in]  Token           Session token.
+
+  @retval     EFI_SUCCESS     Session token is updated.
+  @retval     Others          Error occurs.
+
+**/
+EFI_STATUS
+UpdateSessionToken (
+  IN REDFISH_SERVICE_PRIVATE  *Service,
+  IN CHAR8                    *Token
+  )
+{
+  if ((Service == NULL) || IS_EMPTY_STRING (Token)) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  if (Service->SessionToken != NULL) {
+    FreePool (Service->SessionToken);
+  }
+
+  Service->SessionToken = AllocateCopyPool (AsciiStrSize (Token), Token);
+  if (Service->SessionToken == NULL) {
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  return EFI_SUCCESS;
+}
+
+/**
+  This function release Redfish Service.
+
+  @param[in]  Service         Pointer to service instance.
+
+  @retval     EFI_SUCCESS     Service is released.
+  @retval     Others          Error occurs.
+
+**/
+EFI_STATUS
+ReleaseRedfishService (
+  IN REDFISH_SERVICE_PRIVATE  *Service
+  )
+{
+  if (Service == NULL) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  if (Service->Host != NULL) {
+    FreePool (Service->Host);
+  }
+
+  if (Service->HostName != NULL) {
+    FreePool (Service->HostName);
+  }
+
+  if (Service->BasicAuth != NULL) {
+    ZeroMem (Service->BasicAuth, AsciiStrSize (Service->BasicAuth));
+    FreePool (Service->BasicAuth);
+  }
+
+  if (Service->SessionToken != NULL) {
+    ZeroMem (Service->SessionToken, AsciiStrSize (Service->SessionToken));
+    FreePool (Service->SessionToken);
+  }
+
+  FreePool (Service);
+
+  return EFI_SUCCESS;
+}
+
+/**
+  This function creat new service. Host and HostName are copied to
+  newly created service instance.
+
+  @param[in]  Host            Host string.
+  @param[in]  HostName        Hostname string.
+  @param[in]  BasicAuth       Basic Authorization string.
+  @param[in]  SessionToken    Session token string.
+  @param[in]  RestEx          Rest EX protocol instance.
+
+  @retval     REDFISH_PAYLOAD_PRIVATE  Newly created service.
+  @retval     NULL             Error occurs.
+
+**/
+REDFISH_SERVICE_PRIVATE *
+CreateRedfishService (
+  IN CHAR8                 *Host,
+  IN CHAR8                 *HostName,
+  IN CHAR8                 *BasicAuth OPTIONAL,
+  IN CHAR8                 *SessionToken OPTIONAL,
+  IN EFI_REST_EX_PROTOCOL  *RestEx
+  )
+{
+  REDFISH_SERVICE_PRIVATE  *NewService;
+  UINTN                    AuthStrSize;
+
+  if (IS_EMPTY_STRING (Host) || IS_EMPTY_STRING (HostName) || (RestEx == NULL)) {
+    return NULL;
+  }
+
+  NewService = AllocateZeroPool (sizeof (REDFISH_SERVICE_PRIVATE));
+  if (NewService == NULL) {
+    return NULL;
+  }
+
+  NewService->Signature = REDFISH_HTTP_SERVICE_SIGNATURE;
+  NewService->Host      = AllocateCopyPool (AsciiStrSize (Host), Host);
+  if (NewService->Host == NULL) {
+    goto ON_ERROR;
+  }
+
+  NewService->HostName = AllocateCopyPool (AsciiStrSize (HostName), HostName);
+  if (NewService->HostName == NULL) {
+    goto ON_ERROR;
+  }
+
+  if (!IS_EMPTY_STRING (BasicAuth)) {
+    AuthStrSize           = AsciiStrSize (BasicAuth) + AsciiStrLen (REDFISH_HTTP_BASIC_AUTH_STR);
+    NewService->BasicAuth = AllocateZeroPool (AuthStrSize);
+    if (NewService->BasicAuth == NULL) {
+      goto ON_ERROR;
+    }
+
+    AsciiSPrint (NewService->BasicAuth, AuthStrSize, "%a%a", REDFISH_HTTP_BASIC_AUTH_STR, BasicAuth);
+  }
+
+  if (!IS_EMPTY_STRING (SessionToken)) {
+    NewService->SessionToken = AllocateCopyPool (AsciiStrSize (SessionToken), SessionToken);
+    if (NewService->SessionToken == NULL) {
+      goto ON_ERROR;
+    }
+  }
+
+  NewService->RestEx = RestEx;
+
+  return NewService;
+
+ON_ERROR:
+
+  ReleaseRedfishService (NewService);
+
+  return NULL;
+}
+
+/**
+  This function release Redfish Payload.
+
+  @param[in]  Payload         Pointer to payload instance.
+
+  @retval     EFI_SUCCESS     Payload is released.
+  @retval     Others          Error occurs.
+
+**/
+EFI_STATUS
+ReleaseRedfishPayload (
+  IN REDFISH_PAYLOAD_PRIVATE  *Payload
+  )
+{
+  if (Payload == NULL) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  if (Payload->Service != NULL) {
+    ReleaseRedfishService (Payload->Service);
+  }
+
+  if (Payload->JsonValue != NULL) {
+    JsonValueFree (Payload->JsonValue);
+  }
+
+  FreePool (Payload);
+
+  return EFI_SUCCESS;
+}
+
+/**
+  This function creat new payload. Server and JsonObj are
+  copied to newly created payload.
+
+  @param[in]  Service          Pointer to Service instance.
+  @param[in]  JsonValue        Pointer to JSON value.
+
+  @retval     REDFISH_PAYLOAD_PRIVATE  Newly created payload.
+  @retval     NULL                     Error occurs.
+
+**/
+REDFISH_PAYLOAD_PRIVATE *
+CreateRedfishPayload (
+  IN REDFISH_SERVICE_PRIVATE  *Service,
+  IN EDKII_JSON_VALUE         JsonValue
+  )
+{
+  REDFISH_PAYLOAD_PRIVATE  *NewPayload;
+
+  if ((Service == NULL) || (JsonValue == NULL)) {
+    return NULL;
+  }
+
+  NewPayload = AllocateZeroPool (sizeof (REDFISH_PAYLOAD_PRIVATE));
+  if (NewPayload == NULL) {
+    return NULL;
+  }
+
+  NewPayload->Signature = REDFISH_HTTP_PAYLOAD_SIGNATURE;
+  NewPayload->Service   = CreateRedfishService (Service->Host, Service->HostName, Service->BasicAuth, Service->SessionToken, Service->RestEx);
+  if (NewPayload->Service == NULL) {
+    goto ON_ERROR;
+  }
+
+  NewPayload->JsonValue = JsonValueClone (JsonValue);
+  if (NewPayload->JsonValue == NULL) {
+    goto ON_ERROR;
+  }
+
+  return NewPayload;
+
+ON_ERROR:
+
+  ReleaseRedfishPayload (NewPayload);
+
+  return NULL;
+}
+
+/**
+  This function copy the data in SrcResponse to DstResponse.
+
+  @param[in]  SrcResponse      Source Response to copy.
+  @param[out] DstResponse      Destination Response.
+
+  @retval     EFI_SUCCESS      Response is copied successfully.
+  @retval     Others           Error occurs.
+
+**/
+EFI_STATUS
+CopyRedfishResponse (
+  IN  REDFISH_RESPONSE  *SrcResponse,
+  OUT REDFISH_RESPONSE  *DstResponse
+  )
+{
+  REDFISH_PAYLOAD_PRIVATE  *Payload;
+  UINTN                    Index;
+
+  if ((SrcResponse == NULL) || (DstResponse == NULL)) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  if (SrcResponse == DstResponse) {
+    return EFI_SUCCESS;
+  }
+
+  //
+  // Status code
+  //
+  if (SrcResponse->StatusCode != NULL) {
+    DstResponse->StatusCode = AllocateCopyPool (sizeof (EFI_HTTP_STATUS_CODE), SrcResponse->StatusCode);
+    if (DstResponse->StatusCode == NULL) {
+      goto ON_ERROR;
+    }
+  }
+
+  //
+  // Header
+  //
+  if ((SrcResponse->HeaderCount > 0) && (SrcResponse->Headers != NULL)) {
+    DstResponse->HeaderCount = 0;
+    DstResponse->Headers     = AllocateZeroPool (sizeof (EFI_HTTP_HEADER) * SrcResponse->HeaderCount);
+    if (DstResponse->Headers == NULL) {
+      goto ON_ERROR;
+    }
+
+    for (Index = 0; Index < SrcResponse->HeaderCount; Index++) {
+      DstResponse->Headers[Index].FieldName = AllocateCopyPool (AsciiStrSize (SrcResponse->Headers[Index].FieldName), SrcResponse->Headers[Index].FieldName);
+      if (DstResponse->Headers[Index].FieldName == NULL) {
+        goto ON_ERROR;
+      }
+
+      DstResponse->Headers[Index].FieldValue = AllocateCopyPool (AsciiStrSize (SrcResponse->Headers[Index].FieldValue), SrcResponse->Headers[Index].FieldValue);
+      if (DstResponse->Headers[Index].FieldValue == NULL) {
+        goto ON_ERROR;
+      }
+
+      DstResponse->HeaderCount += 1;
+    }
+  }
+
+  //
+  // Payload
+  //
+  if (SrcResponse->Payload != NULL) {
+    Payload = (REDFISH_PAYLOAD_PRIVATE *)SrcResponse->Payload;
+    if (Payload->Signature != REDFISH_HTTP_PAYLOAD_SIGNATURE) {
+      DEBUG ((DEBUG_ERROR, "%a: signature check failure\n", __func__));
+      goto ON_ERROR;
+    }
+
+    DstResponse->Payload = CreateRedfishPayload (Payload->Service, Payload->JsonValue);
+    if (DstResponse->Payload  == NULL) {
+      goto ON_ERROR;
+    }
+  }
+
+  return EFI_SUCCESS;
+
+ON_ERROR:
+
+  ReleaseRedfishResponse (DstResponse);
+
+  return EFI_OUT_OF_RESOURCES;
+}
+
+/**
+  This function clone input response and return to caller
+
+  @param[in]  Response      Response to clone.
+
+  @retval     REDFISH_RESPONSE *  Response is cloned.
+  @retval     NULL                Errors occur.
+
+**/
+REDFISH_RESPONSE *
+CloneRedfishResponse (
+  IN REDFISH_RESPONSE  *Response
+  )
+{
+  EFI_STATUS        Status;
+  REDFISH_RESPONSE  *NewResponse;
+
+  if (Response == NULL) {
+    return NULL;
+  }
+
+  NewResponse = AllocateZeroPool (sizeof (REDFISH_RESPONSE));
+  if (NewResponse == NULL) {
+    return NULL;
+  }
+
+  Status = CopyRedfishResponse (Response, NewResponse);
+  if (EFI_ERROR (Status)) {
+    FreePool (NewResponse);
+    return NULL;
+  }
+
+  return NewResponse;
+}
+
+/**
+  Release REDFISH_HTTP_CACHE_DATA resource
+
+  @param[in]    Data    Pointer to REDFISH_HTTP_CACHE_DATA instance
+
+  @retval EFI_SUCCESS             REDFISH_HTTP_CACHE_DATA is released successfully.
+  @retval EFI_INVALID_PARAMETER   Data is NULL
+
+**/
+EFI_STATUS
+ReleaseHttpCacheData (
+  IN REDFISH_HTTP_CACHE_DATA  *Data
+  )
+{
+  if (Data == NULL) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  if (Data->Uri != NULL) {
+    FreePool (Data->Uri);
+  }
+
+  if (Data->Response != NULL) {
+    ReleaseRedfishResponse (Data->Response);
+    FreePool (Data->Response);
+  }
+
+  FreePool (Data);
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Create new cache data.
+
+  @param[in]    Uri       The URI string matching to this cache data.
+  @param[in]    Response  HTTP response.
+
+  @retval REDFISH_HTTP_CACHE_DATA *   Pointer to newly created cache data.
+  @retval NULL                        No memory available.
+
+**/
+REDFISH_HTTP_CACHE_DATA *
+NewHttpCacheData (
+  IN  EFI_STRING        Uri,
+  IN  REDFISH_RESPONSE  *Response
+  )
+{
+  REDFISH_HTTP_CACHE_DATA  *NewData;
+  UINTN                    Size;
+
+  if (IS_EMPTY_STRING (Uri) || (Response == NULL)) {
+    return NULL;
+  }
+
+  NewData = AllocateZeroPool (sizeof (REDFISH_HTTP_CACHE_DATA));
+  if (NewData == NULL) {
+    return NULL;
+  }
+
+  NewData->Signature = REDFISH_HTTP_CACHE_SIGNATURE;
+  Size               = StrSize (Uri);
+  NewData->Uri       = AllocateCopyPool (Size, Uri);
+  if (NewData->Uri == NULL) {
+    goto ON_ERROR;
+  }
+
+  NewData->Response = Response;
+  NewData->HitCount = 1;
+
+  return NewData;
+
+ON_ERROR:
+
+  if (NewData != NULL) {
+    ReleaseHttpCacheData (NewData);
+  }
+
+  return NULL;
+}
+
+/**
+  Search on given ListHeader for given URI string.
+
+  @param[in]    ListHeader  Target list to search.
+  @param[in]    Uri         Target URI to search.
+
+  @retval REDFISH_HTTP_CACHE_DATA   Target cache data is found.
+  @retval NULL                      No cache data with given URI is found.
+
+**/
+REDFISH_HTTP_CACHE_DATA *
+FindHttpCacheData (
+  IN  LIST_ENTRY  *ListHeader,
+  IN  EFI_STRING  Uri
+  )
+{
+  LIST_ENTRY               *List;
+  REDFISH_HTTP_CACHE_DATA  *Data;
+
+  if (IS_EMPTY_STRING (Uri)) {
+    return NULL;
+  }
+
+  if (IsListEmpty (ListHeader)) {
+    return NULL;
+  }
+
+  Data = NULL;
+  List = GetFirstNode (ListHeader);
+  while (!IsNull (ListHeader, List)) {
+    Data = REDFISH_HTTP_CACHE_FROM_LIST (List);
+
+    if (StrCmp (Data->Uri, Uri) == 0) {
+      return Data;
+    }
+
+    List = GetNextNode (ListHeader, List);
+  }
+
+  return NULL;
+}
+
+/**
+  Search on given ListHeader and return cache data with minimum hit count.
+
+  @param[in]    ListHeader  Target list to search.
+
+  @retval REDFISH_HTTP_CACHE_DATA   Target cache data is returned.
+  @retval NULL                      No cache data is found.
+
+**/
+REDFISH_HTTP_CACHE_DATA *
+FindUnusedHttpCacheData (
+  IN  LIST_ENTRY  *ListHeader
+  )
+{
+  LIST_ENTRY               *List;
+  REDFISH_HTTP_CACHE_DATA  *Data;
+  REDFISH_HTTP_CACHE_DATA  *UnusedData;
+  UINTN                    HitCount;
+
+  if (IsListEmpty (ListHeader)) {
+    return NULL;
+  }
+
+  Data       = NULL;
+  UnusedData = NULL;
+  HitCount   = 0;
+
+  List       = GetFirstNode (ListHeader);
+  Data       = REDFISH_HTTP_CACHE_FROM_LIST (List);
+  UnusedData = Data;
+  HitCount   = Data->HitCount;
+  List       = GetNextNode (ListHeader, List);
+
+  while (!IsNull (ListHeader, List)) {
+    Data = REDFISH_HTTP_CACHE_FROM_LIST (List);
+
+    if (Data->HitCount < HitCount) {
+      HitCount   = Data->HitCount;
+      UnusedData = Data;
+    }
+
+    List = GetNextNode (ListHeader, List);
+  }
+
+  return UnusedData;
+}
+
+/**
+  Delete a cache data by given cache instance.
+
+  @param[in]    List    Target cache list to be removed.
+  @param[in]    Data    Pointer to the instance to be deleted.
+
+  @retval EFI_SUCCESS   Cache data is removed.
+  @retval Others        Fail to remove cache data.
+
+**/
+EFI_STATUS
+DeleteHttpCacheData (
+  IN  REDFISH_HTTP_CACHE_LIST  *List,
+  IN  REDFISH_HTTP_CACHE_DATA  *Data
+  )
+{
+  if ((List == NULL) || (Data == NULL)) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  DEBUG ((REDFISH_HTTP_CACHE_DEBUG, "%a: delete: %s\n", __func__, Data->Uri));
+
+  RemoveEntryList (&Data->List);
+  --List->Count;
+
+  return ReleaseHttpCacheData (Data);
+}
+
+/**
+  Add new cache by given URI and HTTP response to specify List.
+
+  @param[in]    List      Target cache list to add.
+  @param[in]    Uri       The URI string matching to this cache data.
+  @param[in]    Response  HTTP response.
+
+  @retval EFI_SUCCESS   Cache data is added.
+  @retval Others        Fail to add cache data.
+
+**/
+EFI_STATUS
+AddHttpCacheData (
+  IN  REDFISH_HTTP_CACHE_LIST  *List,
+  IN  EFI_STRING               Uri,
+  IN  REDFISH_RESPONSE         *Response
+  )
+{
+  REDFISH_HTTP_CACHE_DATA  *NewData;
+  REDFISH_HTTP_CACHE_DATA  *OldData;
+  REDFISH_HTTP_CACHE_DATA  *UnusedData;
+  REDFISH_RESPONSE         *NewResponse;
+
+  if ((List == NULL) || IS_EMPTY_STRING (Uri) || (Response == NULL)) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  //
+  // If same cache data exist, replace it with latest one.
+  //
+  OldData = FindHttpCacheData (&List->Head, Uri);
+  if (OldData != NULL) {
+    DeleteHttpCacheData (List, OldData);
+  }
+
+  //
+  // Check capacity
+  //
+  if (List->Count >= List->Capacity) {
+    DEBUG ((REDFISH_HTTP_CACHE_DEBUG, "%a: list is full and retire unused cache\n", __func__));
+    UnusedData = FindUnusedHttpCacheData (&List->Head);
+    if (UnusedData == NULL) {
+      return EFI_OUT_OF_RESOURCES;
+    }
+
+    DeleteHttpCacheData (List, UnusedData);
+  }
+
+  //
+  // Clone a local copy
+  //
+  NewResponse = CloneRedfishResponse (Response);
+  if (NewResponse == NULL) {
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  NewData = NewHttpCacheData (Uri, NewResponse);
+  if (NewData == NULL) {
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  InsertTailList (&List->Head, &NewData->List);
+  ++List->Count;
+
+  DEBUG ((REDFISH_HTTP_CACHE_DEBUG, "%a: cache(%d/%d) %s\n", __func__, List->Count, List->Capacity, NewData->Uri));
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Release all cache from list.
+
+  @param[in]    CacheList    The list to be released.
+
+  @retval EFI_SUCCESS             All cache data are released.
+  @retval EFI_INVALID_PARAMETER   CacheList is NULL.
+
+**/
+EFI_STATUS
+ReleaseCacheList (
+  IN  REDFISH_HTTP_CACHE_LIST  *CacheList
+  )
+{
+  LIST_ENTRY               *List;
+  LIST_ENTRY               *Next;
+  REDFISH_HTTP_CACHE_DATA  *Data;
+
+  if (CacheList == NULL) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  if (IsListEmpty (&CacheList->Head)) {
+    return EFI_SUCCESS;
+  }
+
+  Data = NULL;
+  Next = NULL;
+  List = GetFirstNode (&CacheList->Head);
+  while (!IsNull (&CacheList->Head, List)) {
+    Data = REDFISH_HTTP_CACHE_FROM_LIST (List);
+    Next = GetNextNode (&CacheList->Head, List);
+
+    DeleteHttpCacheData (CacheList, Data);
+
+    List = Next;
+  }
+
+  return EFI_SUCCESS;
+}
diff --git a/RedfishPkg/RedfishHttpDxe/RedfishHttpDxe.c b/RedfishPkg/RedfishHttpDxe/RedfishHttpDxe.c
new file mode 100644
index 0000000000..39958d4865
--- /dev/null
+++ b/RedfishPkg/RedfishHttpDxe/RedfishHttpDxe.c
@@ -0,0 +1,1344 @@
+/** @file
+  RedfishHttpDxe produces EdkIIRedfishHttpProtocol
+  for EDK2 Redfish Feature driver to do HTTP operations.
+
+  Copyright (c) 2023-2024, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "RedfishHttpDxe.h"
+#include "RedfishHttpData.h"
+#include "RedfishHttpOperation.h"
+
+REDFISH_HTTP_CACHE_PRIVATE  *mRedfishHttpCachePrivate = NULL;
+
+/**
+  Debug output the cache list.
+
+  @param[in]    Msg            Debug message string.
+  @param[in]    ErrorLevel     Output error level.
+  @param[in]    CacheList      Target list to dump.
+
+  @retval EFI_SUCCESS             Debug dump finished.
+  @retval EFI_INVALID_PARAMETER   HttpCacheList is NULL.
+
+**/
+EFI_STATUS
+DebugPrintHttpCacheList (
+  IN  CONST CHAR8              *Msg,
+  IN  UINTN                    ErrorLevel,
+  IN  REDFISH_HTTP_CACHE_LIST  *CacheList
+  )
+{
+  LIST_ENTRY               *List;
+  REDFISH_HTTP_CACHE_DATA  *Data;
+  UINTN                    Index;
+
+  if (CacheList == NULL) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  if (!IS_EMPTY_STRING (Msg)) {
+    DEBUG ((ErrorLevel, "%a\n", Msg));
+  }
+
+  if (IsListEmpty (&CacheList->Head)) {
+    DEBUG ((ErrorLevel, "list is empty\n"));
+    return EFI_NOT_FOUND;
+  }
+
+  DEBUG ((ErrorLevel, "list count: %d capacity: %d\n", CacheList->Count, CacheList->Capacity));
+  Data  = NULL;
+  Index = 0;
+  List  = GetFirstNode (&CacheList->Head);
+  while (!IsNull (&CacheList->Head, List)) {
+    Data = REDFISH_HTTP_CACHE_FROM_LIST (List);
+
+    DEBUG ((ErrorLevel, "%d) Uri: %s Hit: %d\n", ++Index, Data->Uri, Data->HitCount));
+
+    List = GetNextNode (&CacheList->Head, List);
+  }
+
+  return EFI_SUCCESS;
+}
+
+/**
+
+  Check HTTP status code to see if we like to retry HTTP request or not.
+
+  @param[in]  StatusCode      HTTP status code.
+
+  @retval     BOOLEAN         Return true when we like to retry request.
+                              Return false when we don't want to retry request.
+
+**/
+BOOLEAN
+RedfishRetryRequired (
+  IN EFI_HTTP_STATUS_CODE  *StatusCode
+  )
+{
+  if (StatusCode == NULL) {
+    return TRUE;
+  }
+
+  if ((*StatusCode == HTTP_STATUS_500_INTERNAL_SERVER_ERROR) ||
+      (*StatusCode == HTTP_STATUS_UNSUPPORTED_STATUS))
+  {
+    return TRUE;
+  }
+
+  return FALSE;
+}
+
+/**
+
+  Convert Unicode string to ASCII string. It's call responsibility to release returned buffer.
+
+  @param[in]  UnicodeStr      Unicode string to convert.
+
+  @retval     CHAR8 *         ASCII string returned.
+  @retval     NULL            Errors occur.
+
+**/
+CHAR8 *
+StringUnicodeToAscii (
+  IN EFI_STRING  UnicodeStr
+  )
+{
+  CHAR8       *AsciiStr;
+  UINTN       AsciiStrSize;
+  EFI_STATUS  Status;
+
+  if (IS_EMPTY_STRING (UnicodeStr)) {
+    return NULL;
+  }
+
+  AsciiStrSize = StrLen (UnicodeStr) + 1;
+  AsciiStr     = AllocateZeroPool (AsciiStrSize);
+  if (AsciiStr == NULL) {
+    return NULL;
+  }
+
+  Status = UnicodeStrToAsciiStrS (UnicodeStr, AsciiStr, AsciiStrSize);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "UnicodeStrToAsciiStrS failed: %r\n", Status));
+    FreePool (AsciiStr);
+    return NULL;
+  }
+
+  return AsciiStr;
+}
+
+/**
+  Return HTTP method in ASCII string. Caller does not need
+  to free returned string buffer.
+
+  @param[in]  Method         HTTP method.
+
+  @retval CHAR8 *   Method in string.
+**/
+CHAR8 *
+HttpMethodToString (
+  IN  EFI_HTTP_METHOD  Method
+  )
+{
+  switch (Method) {
+    case HttpMethodGet:
+      return HTTP_METHOD_GET;
+      break;
+    case HttpMethodPost:
+      return HTTP_METHOD_POST;
+      break;
+    case HttpMethodPatch:
+      return HTTP_METHOD_PATCH;
+      break;
+    case HttpMethodPut:
+      return HTTP_METHOD_PUT;
+      break;
+    case HttpMethodDelete:
+      return HTTP_METHOD_DELETE;
+      break;
+    default:
+      break;
+  }
+
+  return "Unknown";
+}
+
+/**
+  Report HTTP communication error via report status code.
+
+  @param[in]  Method         HTTP method.
+  @param[in]  Uri            The URI which has failure.
+  @param[in]  HttpStatusCode HTTP status code.
+
+**/
+VOID
+ReportHttpError (
+  IN  EFI_HTTP_METHOD       Method,
+  IN  EFI_STRING            Uri,
+  IN  EFI_HTTP_STATUS_CODE  *HttpStatusCode  OPTIONAL
+  )
+{
+  CHAR8  ErrorMsg[REDFISH_ERROR_MSG_MAX];
+
+  if (IS_EMPTY_STRING (Uri)) {
+    DEBUG ((DEBUG_ERROR, "%a: no URI to report error status\n", __func__));
+    return;
+  }
+
+  //
+  // Report failure of URI and HTTP status code.
+  //
+  AsciiSPrint (ErrorMsg, sizeof (ErrorMsg), REDFISH_HTTP_ERROR_REPORT, HttpMethodToString (Method), (HttpStatusCode == NULL ? HTTP_STATUS_UNSUPPORTED_STATUS : *HttpStatusCode), Uri);
+  DEBUG ((DEBUG_ERROR, "%a\n", ErrorMsg));
+  //
+  // TODO:
+  // Below PI status code is approved by PIWG and wait for specification published.
+  // We will uncomment below report status code after PI status code get published.
+  // REF: https://bugzilla.tianocore.org/show_bug.cgi?id=4483
+  //
+  // REPORT_STATUS_CODE_WITH_EXTENDED_DATA (
+  //  EFI_ERROR_CODE | EFI_ERROR_MAJOR,
+  //  EFI_COMPUTING_UNIT_MANAGEABILITY | EFI_MANAGEABILITY_EC_REDFISH_COMMUNICATION_ERROR,
+  //  ErrorMsg,
+  //  AsciiStrSize (ErrorMsg)
+  //  );
+}
+
+/**
+  This function create Redfish service. It's caller's responsibility to free returned
+  Redfish service by calling FreeService ().
+
+  @param[in]  This                       Pointer to EDKII_REDFISH_HTTP_PROTOCOL instance.
+  @param[in]  RedfishConfigServiceInfo   Redfish config service information.
+
+  @retval     REDFISH_SERVICE  Redfish service is created.
+  @retval     NULL             Errors occur.
+
+**/
+REDFISH_SERVICE
+EFIAPI
+RedfishCreateRedfishService (
+  IN  EDKII_REDFISH_HTTP_PROTOCOL         *This,
+  IN  REDFISH_CONFIG_SERVICE_INFORMATION  *RedfishConfigServiceInfo
+  )
+{
+  EFI_STATUS                  Status;
+  REDFISH_HTTP_CACHE_PRIVATE  *Private;
+  REDFISH_SERVICE_PRIVATE     *NewService;
+  CHAR8                       *AsciiLocation;
+  CHAR8                       *Host;
+  CHAR8                       *BasicAuthString;
+  UINTN                       BasicAuthStrSize;
+  CHAR8                       *EncodedAuthString;
+  UINTN                       EncodedAuthStrSize;
+  EDKII_REDFISH_AUTH_METHOD   AuthMethod;
+  CHAR8                       *Username;
+  CHAR8                       *Password;
+  UINTN                       UsernameSize;
+  UINTN                       PasswordSize;
+  EFI_REST_EX_PROTOCOL        *RestEx;
+
+  if ((This == NULL) || (RedfishConfigServiceInfo == NULL)) {
+    return NULL;
+  }
+
+  DEBUG ((REDFISH_HTTP_CACHE_DEBUG, "%a: service location: %s\n", __func__, RedfishConfigServiceInfo->RedfishServiceLocation));
+
+  Private            = REDFISH_HTTP_CACHE_PRIVATE_FROM_THIS (This);
+  BasicAuthString    = NULL;
+  EncodedAuthString  = NULL;
+  Username           = NULL;
+  Password           = NULL;
+  NewService         = NULL;
+  AsciiLocation      = NULL;
+  Host               = NULL;
+  BasicAuthStrSize   = 0;
+  EncodedAuthStrSize = 0;
+  UsernameSize       = 0;
+  PasswordSize       = 0;
+
+  //
+  // Build host and host name from service location
+  //
+  if (!IS_EMPTY_STRING (RedfishConfigServiceInfo->RedfishServiceLocation)) {
+    AsciiLocation = StringUnicodeToAscii (RedfishConfigServiceInfo->RedfishServiceLocation);
+    if (AsciiLocation == NULL) {
+      goto ON_RELEASE;
+    }
+
+    Host = AllocateZeroPool (REDFISH_HOST_NAME_MAX);
+    if (AsciiLocation == NULL) {
+      goto ON_RELEASE;
+    }
+
+    if (RedfishConfigServiceInfo->RedfishServiceUseHttps) {
+      AsciiSPrint (Host, REDFISH_HOST_NAME_MAX, "https://%a", AsciiLocation);
+    } else {
+      AsciiSPrint (Host, REDFISH_HOST_NAME_MAX, "http://%a", AsciiLocation);
+    }
+
+    DEBUG ((REDFISH_HTTP_CACHE_DEBUG, "%a: Host: %a\n", __func__, Host));
+  }
+
+  //
+  // Find Rest Ex protocol
+  //
+  if (RedfishConfigServiceInfo->RedfishServiceRestExHandle != NULL) {
+    Status = gBS->HandleProtocol (
+                    RedfishConfigServiceInfo->RedfishServiceRestExHandle,
+                    &gEfiRestExProtocolGuid,
+                    (VOID **)&RestEx
+                    );
+  } else {
+    DEBUG ((DEBUG_ERROR, "%a: Rest Ex protocol is not available\n", __func__));
+    goto ON_RELEASE;
+  }
+
+  //
+  // Get credential
+  //
+  if (Private->CredentialProtocol == NULL) {
+    //
+    // No credential available on this system.
+    //
+    DEBUG ((DEBUG_WARN, "%a: no credential protocol available\n", __func__));
+  } else {
+    Status = Private->CredentialProtocol->GetAuthInfo (
+                                            Private->CredentialProtocol,
+                                            &AuthMethod,
+                                            &Username,
+                                            &Password
+                                            );
+    if (EFI_ERROR (Status) || IS_EMPTY_STRING (Username) || IS_EMPTY_STRING (Password)) {
+      DEBUG ((DEBUG_ERROR, "%a: cannot get authentication information: %r\n", __func__, Status));
+      goto ON_RELEASE;
+    } else {
+      DEBUG ((REDFISH_HTTP_CACHE_DEBUG, "%a: Auth method: 0x%x username: %a password: %a\n", __func__, AuthMethod, Username, Password));
+
+      //
+      // Perform base64 encoding (RFC 7617)
+      //
+      UsernameSize     = AsciiStrSize (Username);
+      PasswordSize     = AsciiStrSize (Password);
+      BasicAuthStrSize =  UsernameSize + PasswordSize;  // one byte taken from null-terminator for ':'
+      BasicAuthString  = AllocateZeroPool (BasicAuthStrSize);
+      if (BasicAuthString == NULL) {
+        goto ON_RELEASE;
+      }
+
+      AsciiSPrint (
+        BasicAuthString,
+        BasicAuthStrSize,
+        "%a:%a",
+        Username,
+        Password
+        );
+
+      Status = Base64Encode (
+                 (CONST UINT8 *)BasicAuthString,
+                 BasicAuthStrSize,
+                 EncodedAuthString,
+                 &EncodedAuthStrSize
+                 );
+      if ((Status == EFI_BUFFER_TOO_SMALL) && (EncodedAuthStrSize > 0)) {
+        EncodedAuthString = AllocateZeroPool (EncodedAuthStrSize);
+        if (EncodedAuthString == NULL) {
+          goto ON_RELEASE;
+        }
+
+        Status = Base64Encode (
+                   (CONST UINT8 *)BasicAuthString,
+                   BasicAuthStrSize,
+                   EncodedAuthString,
+                   &EncodedAuthStrSize
+                   );
+        if (EFI_ERROR (Status)) {
+          DEBUG ((DEBUG_ERROR, "%a: Base64Encode failure: %r\n", __func__, Status));
+        }
+
+        DEBUG ((REDFISH_HTTP_CACHE_DEBUG, "%a: Basic authorization: %a\n", __func__, EncodedAuthString));
+      } else {
+        DEBUG ((DEBUG_ERROR, "%a: Base64Encode failure: %r\n", __func__, Status));
+        goto ON_RELEASE;
+      }
+    }
+  }
+
+  NewService = CreateRedfishService (Host, AsciiLocation, EncodedAuthString, NULL, RestEx);
+  if (NewService == NULL) {
+    DEBUG ((DEBUG_ERROR, "%a: CreateRedfishService\n", __func__));
+  }
+
+ON_RELEASE:
+
+  if (BasicAuthString != NULL) {
+    ZeroMem (BasicAuthString, BasicAuthStrSize);
+    FreePool (BasicAuthString);
+  }
+
+  if (EncodedAuthString != NULL) {
+    ZeroMem (BasicAuthString, EncodedAuthStrSize);
+    FreePool (EncodedAuthString);
+  }
+
+  if (Username != NULL) {
+    ZeroMem (Username, UsernameSize);
+    FreePool (Username);
+  }
+
+  if (Password != NULL) {
+    ZeroMem (Password, PasswordSize);
+    FreePool (Password);
+  }
+
+  if (AsciiLocation != NULL) {
+    FreePool (AsciiLocation);
+  }
+
+  if (Host != NULL) {
+    FreePool (Host);
+  }
+
+  return NewService;
+}
+
+/**
+  This function free resources in Redfish service. RedfishService is no longer available
+  after this function returns successfully.
+
+  @param[in]  This            Pointer to EDKII_REDFISH_HTTP_PROTOCOL instance.
+  @param[in]  RedfishService  Pointer to Redfish service to be released.
+
+  @retval     EFI_SUCCESS     Resrouce is released successfully.
+  @retval     Others          Errors occur.
+
+**/
+EFI_STATUS
+EFIAPI
+RedfishFreeRedfishService (
+  IN  EDKII_REDFISH_HTTP_PROTOCOL  *This,
+  IN  REDFISH_SERVICE              RedfishService
+  )
+{
+  REDFISH_SERVICE_PRIVATE  *Service;
+
+  if ((This == NULL) || (RedfishService == NULL)) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  Service = (REDFISH_SERVICE_PRIVATE *)RedfishService;
+  if (Service->Signature != REDFISH_HTTP_SERVICE_SIGNATURE) {
+    DEBUG ((DEBUG_ERROR, "%a: signature check failure\n", __func__));
+  }
+
+  return ReleaseRedfishService (Service);
+}
+
+/**
+  This function returns JSON value in given RedfishPayload. Returned JSON value
+  is a reference to the JSON value in RedfishPayload. Any modification to returned
+  JSON value will change JSON value in RedfishPayload.
+
+  @param[in]  This            Pointer to EDKII_REDFISH_HTTP_PROTOCOL instance.
+  @param[in]  RedfishPayload  Pointer to Redfish payload.
+
+  @retval     EDKII_JSON_VALUE   JSON value is returned.
+  @retval     NULL               Errors occur.
+
+**/
+EDKII_JSON_VALUE
+EFIAPI
+RedfishJsonInRedfishPayload (
+  IN  EDKII_REDFISH_HTTP_PROTOCOL  *This,
+  IN  REDFISH_PAYLOAD              RedfishPayload
+  )
+{
+  REDFISH_PAYLOAD_PRIVATE  *Payload;
+
+  if ((This == NULL) || (RedfishPayload == NULL)) {
+    return NULL;
+  }
+
+  Payload = (REDFISH_PAYLOAD_PRIVATE *)RedfishPayload;
+  if (Payload->Signature != REDFISH_HTTP_PAYLOAD_SIGNATURE) {
+    DEBUG ((DEBUG_ERROR, "%a: signature check failure\n", __func__));
+  }
+
+  return Payload->JsonValue;
+}
+
+/**
+  Perform HTTP GET to Get redfish resource from given resource URI with
+  cache mechanism supported. It's caller's responsibility to free Response
+  by calling FreeResponse ().
+
+  @param[in]  This          Pointer to EDKII_REDFISH_HTTP_PROTOCOL instance.
+  @param[in]  Service       Redfish service instance to perform HTTP GET.
+  @param[in]  Uri           Target resource URI.
+  @param[in]  Request       Additional request context. This is optional.
+  @param[out] Response      HTTP response from redfish service.
+  @param[in]  UseCache      If it is TRUE, this function will search for
+                            cache first. If it is FALSE, this function
+                            will query Redfish URI directly.
+
+  @retval     EFI_SUCCESS     Resrouce is returned successfully.
+  @retval     Others          Errors occur.
+
+**/
+EFI_STATUS
+EFIAPI
+RedfishGetResource (
+  IN  EDKII_REDFISH_HTTP_PROTOCOL  *This,
+  IN  REDFISH_SERVICE              Service,
+  IN  EFI_STRING                   Uri,
+  IN  REDFISH_REQUEST              *Request OPTIONAL,
+  OUT REDFISH_RESPONSE             *Response,
+  IN  BOOLEAN                      UseCache
+  )
+{
+  EFI_STATUS                  Status;
+  REDFISH_HTTP_CACHE_DATA     *CacheData;
+  UINTN                       RetryCount;
+  REDFISH_HTTP_CACHE_PRIVATE  *Private;
+
+  if ((This == NULL) || (Service == NULL) || (Response == NULL) || IS_EMPTY_STRING (Uri)) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  DEBUG ((REDFISH_HTTP_CACHE_DEBUG, "%a: Get URI: %s cache: %a\n", __func__, Uri, (UseCache ? "true" : "false")));
+
+  Private    = REDFISH_HTTP_CACHE_PRIVATE_FROM_THIS (This);
+  CacheData  = NULL;
+  RetryCount = 0;
+  ZeroMem (Response, sizeof (REDFISH_RESPONSE));
+
+  if (Private->CacheDisabled) {
+    UseCache = FALSE;
+    DEBUG ((REDFISH_HTTP_CACHE_DEBUG, "%a: cache is disabled by PCD!\n", __func__));
+  }
+
+  //
+  // Search for cache list.
+  //
+  if (UseCache) {
+    CacheData = FindHttpCacheData (&Private->CacheList.Head, Uri);
+    if (CacheData != NULL) {
+      DEBUG ((REDFISH_HTTP_CACHE_DEBUG_REQUEST, "%a: cache hit! %s\n", __func__, Uri));
+
+      //
+      // Copy cached response to caller's buffer.
+      //
+      Status               = CopyRedfishResponse (CacheData->Response, Response);
+      CacheData->HitCount += 1;
+      return Status;
+    }
+  }
+
+  //
+  // Get resource from redfish service.
+  //
+  do {
+    RetryCount += 1;
+    Status      = HttpSendReceive (
+                    Service,
+                    Uri,
+                    HttpMethodGet,
+                    Request,
+                    Response
+                    );
+    DEBUG ((REDFISH_HTTP_CACHE_DEBUG_REQUEST, "%a: HTTP request: %s :%r\n", __func__, Uri, Status));
+    if (!EFI_ERROR (Status) || (RetryCount >= Private->RetrySetting.MaximumRetryGet)) {
+      break;
+    }
+
+    //
+    // Retry when BMC is not ready.
+    //
+    if ((Response->StatusCode != NULL)) {
+      DEBUG_CODE (
+        DumpRedfishResponse (NULL, DEBUG_ERROR, Response);
+        );
+
+      if (!RedfishRetryRequired (Response->StatusCode)) {
+        break;
+      }
+
+      //
+      // Release response for next round of request.
+      //
+      This->FreeResponse (This, Response);
+    }
+
+    DEBUG ((DEBUG_WARN, "%a: RedfishGetByUriEx failed, retry (%d/%d)\n", __func__, RetryCount, Private->RetrySetting.MaximumRetryGet));
+    if (Private->RetrySetting.RetryWait > 0) {
+      gBS->Stall (Private->RetrySetting.RetryWait);
+    }
+  } while (TRUE);
+
+  if (EFI_ERROR (Status)) {
+    DEBUG_CODE (
+      DumpRedfishResponse (NULL, DEBUG_ERROR, Response);
+      );
+    //
+    // Report status code for Redfish failure
+    //
+    ReportHttpError (HttpMethodGet, Uri, Response->StatusCode);
+    DEBUG ((DEBUG_ERROR, "%a: get %s failed (%d/%d): %r\n", __func__, Uri, RetryCount, Private->RetrySetting.MaximumRetryGet, Status));
+    goto ON_RELEASE;
+  }
+
+  if (!Private->CacheDisabled) {
+    //
+    // Keep response in cache list
+    //
+    Status = AddHttpCacheData (&Private->CacheList, Uri, Response);
+    if (EFI_ERROR (Status)) {
+      DEBUG ((DEBUG_ERROR, "%a: failed to cache %s: %r\n", __func__, Uri, Status));
+      goto ON_RELEASE;
+    }
+
+    DEBUG_CODE (
+      DebugPrintHttpCacheList (__func__, REDFISH_HTTP_CACHE_DEBUG_DUMP, &Private->CacheList);
+      );
+  }
+
+ON_RELEASE:
+
+  return Status;
+}
+
+/**
+  This function free resources in Request. Request is no longer available
+  after this function returns successfully.
+
+  @param[in]  This         Pointer to EDKII_REDFISH_HTTP_PROTOCOL instance.
+  @param[in]  Request      HTTP request to be released.
+
+  @retval     EFI_SUCCESS     Resrouce is released successfully.
+  @retval     Others          Errors occur.
+
+**/
+EFI_STATUS
+EFIAPI
+RedfishFreeRequest (
+  IN  EDKII_REDFISH_HTTP_PROTOCOL  *This,
+  IN  REDFISH_REQUEST              *Request
+  )
+{
+  if ((This == NULL) || (Request == NULL)) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  DEBUG ((REDFISH_HTTP_CACHE_DEBUG, "%a: entry\n", __func__));
+
+  return ReleaseRedfishRequest (Request);
+}
+
+/**
+  This function free resources in given Response.
+
+  @param[in]  This         Pointer to EDKII_REDFISH_HTTP_PROTOCOL instance.
+  @param[in]  Response     HTTP response to be released.
+
+  @retval     EFI_SUCCESS     Resrouce is released successfully.
+  @retval     Others          Errors occur.
+
+**/
+EFI_STATUS
+EFIAPI
+RedfishFreeResponse (
+  IN  EDKII_REDFISH_HTTP_PROTOCOL  *This,
+  IN  REDFISH_RESPONSE             *Response
+  )
+{
+  if ((This == NULL) || (Response == NULL)) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  DEBUG ((REDFISH_HTTP_CACHE_DEBUG, "%a: entry\n", __func__));
+
+  return ReleaseRedfishResponse (Response);
+}
+
+/**
+  This function expire the cached response of given URI.
+
+  @param[in]  This         Pointer to EDKII_REDFISH_HTTP_PROTOCOL instance.
+  @param[in]  Uri          Target response of URI.
+
+  @retval     EFI_SUCCESS     Target response is expired successfully.
+  @retval     Others          Errors occur.
+
+**/
+EFI_STATUS
+EFIAPI
+RedfishExpireResponse (
+  IN  EDKII_REDFISH_HTTP_PROTOCOL  *This,
+  IN  EFI_STRING                   Uri
+  )
+{
+  REDFISH_HTTP_CACHE_PRIVATE  *Private;
+  REDFISH_HTTP_CACHE_DATA     *CacheData;
+
+  if ((This == NULL) || IS_EMPTY_STRING (Uri)) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  DEBUG ((REDFISH_HTTP_CACHE_DEBUG, "%a: expire URI: %s\n", __func__, Uri));
+
+  Private = REDFISH_HTTP_CACHE_PRIVATE_FROM_THIS (This);
+
+  CacheData = FindHttpCacheData (&Private->CacheList.Head, Uri);
+  if (CacheData == NULL) {
+    return EFI_NOT_FOUND;
+  }
+
+  return DeleteHttpCacheData (&Private->CacheList, CacheData);
+}
+
+/**
+  Perform HTTP PATCH to send redfish resource to given resource URI.
+  It's caller's responsibility to free Response by calling FreeResponse ().
+
+  @param[in]  This          Pointer to EDKII_REDFISH_HTTP_PROTOCOL instance.
+  @param[in]  Service       Redfish service instance to perform HTTP PATCH.
+  @param[in]  Uri           Target resource URI.
+  @param[in]  Content       Data to patch.
+  @param[in]  ContentSize   Size of the Content to be send to Redfish service.
+                            This is optional. When ContentSize is 0, ContentSize
+                            is the size of Content.
+  @param[in]  ContentType   Type of the Content to be send to Redfish service.
+                            This is optional. When ContentType is NULL, content
+                            type HTTP_CONTENT_TYPE_APP_JSON will be used.
+  @param[out] Response      HTTP response from redfish service.
+
+  @retval     EFI_SUCCESS     Resrouce is returned successfully.
+  @retval     Others          Errors occur.
+
+**/
+EFI_STATUS
+EFIAPI
+RedfishPatchResource (
+  IN  EDKII_REDFISH_HTTP_PROTOCOL  *This,
+  IN  REDFISH_SERVICE              Service,
+  IN  EFI_STRING                   Uri,
+  IN  CHAR8                        *Content,
+  IN  UINTN                        ContentSize OPTIONAL,
+  IN  CHAR8                        *ContentType OPTIONAL,
+  OUT REDFISH_RESPONSE             *Response
+  )
+{
+  EFI_STATUS                  Status;
+  UINTN                       RetryCount;
+  REDFISH_REQUEST             Request;
+  REDFISH_HTTP_CACHE_PRIVATE  *Private;
+
+  if ((This == NULL) || (Service == NULL) || (Response == NULL) || IS_EMPTY_STRING (Uri) || IS_EMPTY_STRING (Content)) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  DEBUG ((REDFISH_HTTP_CACHE_DEBUG, "%a: Patch URI: %s\n", __func__, Uri));
+
+  Private    = REDFISH_HTTP_CACHE_PRIVATE_FROM_THIS (This);
+  RetryCount = 0;
+  ZeroMem (Response, sizeof (REDFISH_RESPONSE));
+  ZeroMem (&Request, sizeof (REDFISH_REQUEST));
+
+  Request.Content       = Content;
+  Request.ContentLength = ContentSize;
+  Request.ContentType   = ContentType;
+
+  //
+  // Patch resource to redfish service.
+  //
+  do {
+    RetryCount += 1;
+    Status      = HttpSendReceive (
+                    Service,
+                    Uri,
+                    HttpMethodPatch,
+                    &Request,
+                    Response
+                    );
+    DEBUG ((REDFISH_HTTP_CACHE_DEBUG_REQUEST, "%a: HTTP request: %s :%r\n", __func__, Uri, Status));
+    if (!EFI_ERROR (Status) || (RetryCount >= Private->RetrySetting.MaximumRetryPatch)) {
+      break;
+    }
+
+    //
+    // Retry when BMC is not ready.
+    //
+    if ((Response->StatusCode != NULL)) {
+      DEBUG_CODE (
+        DumpRedfishResponse (NULL, DEBUG_ERROR, Response);
+        );
+
+      if (!RedfishRetryRequired (Response->StatusCode)) {
+        break;
+      }
+
+      //
+      // Release response for next round of request.
+      //
+      This->FreeResponse (This, Response);
+    }
+
+    DEBUG ((DEBUG_WARN, "%a: RedfishPatchToUriEx failed, retry (%d/%d)\n", __func__, RetryCount, Private->RetrySetting.MaximumRetryPatch));
+    if (Private->RetrySetting.RetryWait > 0) {
+      gBS->Stall (Private->RetrySetting.RetryWait);
+    }
+  } while (TRUE);
+
+  //
+  // Redfish resource is updated. Automatically expire the cached response
+  // so application can directly get resource from Redfish service again.
+  //
+  DEBUG ((REDFISH_HTTP_CACHE_DEBUG, "%a: Resource is updated, expire URI: %s\n", __func__, Uri));
+  RedfishExpireResponse (This, Uri);
+
+  if (EFI_ERROR (Status)) {
+    DEBUG_CODE (
+      DumpRedfishResponse (NULL, DEBUG_ERROR, Response);
+      );
+    //
+    // Report status code for Redfish failure
+    //
+    ReportHttpError (HttpMethodPatch, Uri, Response->StatusCode);
+    DEBUG ((DEBUG_ERROR, "%a: patch %s failed (%d/%d): %r\n", __func__, Uri, RetryCount, Private->RetrySetting.MaximumRetryPatch, Status));
+    goto ON_RELEASE;
+  }
+
+ON_RELEASE:
+
+  return Status;
+}
+
+/**
+  Perform HTTP PUT to send redfish resource to given resource URI.
+  It's caller's responsibility to free Response by calling FreeResponse ().
+
+  @param[in]  This          Pointer to EDKII_REDFISH_HTTP_PROTOCOL instance.
+  @param[in]  Service       Redfish service instance to perform HTTP PUT.
+  @param[in]  Uri           Target resource URI.
+  @param[in]  Content       Data to put.
+  @param[in]  ContentSize   Size of the Content to be send to Redfish service.
+                            This is optional. When ContentSize is 0, ContentSize
+                            is the size of Content.
+  @param[in]  ContentType   Type of the Content to be send to Redfish service.
+                            This is optional. When ContentType is NULL, content
+                            type HTTP_CONTENT_TYPE_APP_JSON will be used.
+  @param[out] Response      HTTP response from redfish service.
+
+  @retval     EFI_SUCCESS     Resrouce is returned successfully.
+  @retval     Others          Errors occur.
+
+**/
+EFI_STATUS
+EFIAPI
+RedfishPutResource (
+  IN  EDKII_REDFISH_HTTP_PROTOCOL  *This,
+  IN  REDFISH_SERVICE              Service,
+  IN  EFI_STRING                   Uri,
+  IN  CHAR8                        *Content,
+  IN  UINTN                        ContentSize OPTIONAL,
+  IN  CHAR8                        *ContentType OPTIONAL,
+  OUT REDFISH_RESPONSE             *Response
+  )
+{
+  EFI_STATUS                  Status;
+  UINTN                       RetryCount;
+  REDFISH_REQUEST             Request;
+  REDFISH_HTTP_CACHE_PRIVATE  *Private;
+
+  if ((This == NULL) || (Service == NULL) || (Response == NULL) || IS_EMPTY_STRING (Uri) || IS_EMPTY_STRING (Content)) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  DEBUG ((REDFISH_HTTP_CACHE_DEBUG, "%a: Put URI: %s\n", __func__, Uri));
+
+  Private    = REDFISH_HTTP_CACHE_PRIVATE_FROM_THIS (This);
+  RetryCount = 0;
+  ZeroMem (Response, sizeof (REDFISH_RESPONSE));
+  ZeroMem (&Request, sizeof (REDFISH_REQUEST));
+
+  Request.Content       = Content;
+  Request.ContentLength = ContentSize;
+  Request.ContentType   = ContentType;
+
+  //
+  // Patch resource to redfish service.
+  //
+  do {
+    RetryCount += 1;
+    Status      = HttpSendReceive (
+                    Service,
+                    Uri,
+                    HttpMethodPut,
+                    &Request,
+                    Response
+                    );
+    DEBUG ((REDFISH_HTTP_CACHE_DEBUG_REQUEST, "%a: HTTP request: %s :%r\n", __func__, Uri, Status));
+    if (!EFI_ERROR (Status) || (RetryCount >= Private->RetrySetting.MaximumRetryPut)) {
+      break;
+    }
+
+    //
+    // Retry when BMC is not ready.
+    //
+    if ((Response->StatusCode != NULL)) {
+      DEBUG_CODE (
+        DumpRedfishResponse (NULL, DEBUG_ERROR, Response);
+        );
+
+      if (!RedfishRetryRequired (Response->StatusCode)) {
+        break;
+      }
+
+      //
+      // Release response for next round of request.
+      //
+      This->FreeResponse (This, Response);
+    }
+
+    DEBUG ((DEBUG_WARN, "%a: RedfishPutToUri failed, retry (%d/%d)\n", __func__, RetryCount, Private->RetrySetting.MaximumRetryPut));
+    if (Private->RetrySetting.RetryWait > 0) {
+      gBS->Stall (Private->RetrySetting.RetryWait);
+    }
+  } while (TRUE);
+
+  //
+  // Redfish resource is updated. Automatically expire the cached response
+  // so application can directly get resource from Redfish service again.
+  //
+  DEBUG ((REDFISH_HTTP_CACHE_DEBUG, "%a: Resource is updated, expire URI: %s\n", __func__, Uri));
+  RedfishExpireResponse (This, Uri);
+
+  if (EFI_ERROR (Status)) {
+    DEBUG_CODE (
+      DumpRedfishResponse (NULL, DEBUG_ERROR, Response);
+      );
+    //
+    // Report status code for Redfish failure
+    //
+    ReportHttpError (HttpMethodPut, Uri, Response->StatusCode);
+    DEBUG ((DEBUG_ERROR, "%a: put %s failed (%d/%d): %r\n", __func__, Uri, RetryCount, Private->RetrySetting.MaximumRetryPut, Status));
+    goto ON_RELEASE;
+  }
+
+ON_RELEASE:
+
+  return Status;
+}
+
+/**
+  Perform HTTP POST to send redfish resource to given resource URI.
+  It's caller's responsibility to free Response by calling FreeResponse ().
+
+  @param[in]  This          Pointer to EDKII_REDFISH_HTTP_PROTOCOL instance.
+  @param[in]  Service       Redfish service instance to perform HTTP POST.
+  @param[in]  Uri           Target resource URI.
+  @param[in]  Content       Data to post.
+  @param[in]  ContentSize   Size of the Content to be send to Redfish service.
+                            This is optional. When ContentSize is 0, ContentSize
+                            is the size of Content.
+  @param[in]  ContentType   Type of the Content to be send to Redfish service.
+                            This is optional. When ContentType is NULL, content
+                            type HTTP_CONTENT_TYPE_APP_JSON will be used.
+  @param[out] Response      HTTP response from redfish service.
+
+  @retval     EFI_SUCCESS     Resrouce is returned successfully.
+  @retval     Others          Errors occur.
+
+**/
+EFI_STATUS
+EFIAPI
+RedfishPostResource (
+  IN  EDKII_REDFISH_HTTP_PROTOCOL  *This,
+  IN  REDFISH_SERVICE              Service,
+  IN  EFI_STRING                   Uri,
+  IN  CHAR8                        *Content,
+  IN  UINTN                        ContentSize OPTIONAL,
+  IN  CHAR8                        *ContentType OPTIONAL,
+  OUT REDFISH_RESPONSE             *Response
+  )
+{
+  EFI_STATUS                  Status;
+  UINTN                       RetryCount;
+  REDFISH_REQUEST             Request;
+  REDFISH_HTTP_CACHE_PRIVATE  *Private;
+
+  if ((This == NULL) || (Service == NULL) || (Response == NULL) || IS_EMPTY_STRING (Uri) || IS_EMPTY_STRING (Content)) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  DEBUG ((REDFISH_HTTP_CACHE_DEBUG, "%a: Post URI: %s\n", __func__, Uri));
+
+  Private    = REDFISH_HTTP_CACHE_PRIVATE_FROM_THIS (This);
+  RetryCount = 0;
+  ZeroMem (Response, sizeof (REDFISH_RESPONSE));
+  ZeroMem (&Request, sizeof (REDFISH_REQUEST));
+
+  Request.Content       = Content;
+  Request.ContentLength = ContentSize;
+  Request.ContentType   = ContentType;
+
+  //
+  // Patch resource to redfish service.
+  //
+  do {
+    RetryCount += 1;
+    Status      = HttpSendReceive (
+                    Service,
+                    Uri,
+                    HttpMethodPost,
+                    &Request,
+                    Response
+                    );
+    DEBUG ((REDFISH_HTTP_CACHE_DEBUG_REQUEST, "%a: HTTP request: %s :%r\n", __func__, Uri, Status));
+    if (!EFI_ERROR (Status) || (RetryCount >= Private->RetrySetting.MaximumRetryPost)) {
+      break;
+    }
+
+    //
+    // Retry when BMC is not ready.
+    //
+    if ((Response->StatusCode != NULL)) {
+      DEBUG_CODE (
+        DumpRedfishResponse (NULL, DEBUG_ERROR, Response);
+        );
+
+      if (!RedfishRetryRequired (Response->StatusCode)) {
+        break;
+      }
+
+      //
+      // Release response for next round of request.
+      //
+      This->FreeResponse (This, Response);
+    }
+
+    DEBUG ((DEBUG_WARN, "%a: RedfishPostToUri failed, retry (%d/%d)\n", __func__, RetryCount, Private->RetrySetting.MaximumRetryPost));
+    if (Private->RetrySetting.RetryWait > 0) {
+      gBS->Stall (Private->RetrySetting.RetryWait);
+    }
+  } while (TRUE);
+
+  //
+  // Redfish resource is updated. Automatically expire the cached response
+  // so application can directly get resource from Redfish service again.
+  //
+  DEBUG ((REDFISH_HTTP_CACHE_DEBUG, "%a: Resource is updated, expire URI: %s\n", __func__, Uri));
+  RedfishExpireResponse (This, Uri);
+
+  if (EFI_ERROR (Status)) {
+    DEBUG_CODE (
+      DumpRedfishResponse (NULL, DEBUG_ERROR, Response);
+      );
+    //
+    // Report status code for Redfish failure
+    //
+    ReportHttpError (HttpMethodPost, Uri, Response->StatusCode);
+    DEBUG ((DEBUG_ERROR, "%a: post %s failed (%d/%d): %r\n", __func__, Uri, RetryCount, Private->RetrySetting.MaximumRetryPost, Status));
+    goto ON_RELEASE;
+  }
+
+ON_RELEASE:
+
+  return Status;
+}
+
+/**
+  Perform HTTP DELETE to delete redfish resource on given resource URI.
+  It's caller's responsibility to free Response by calling FreeResponse ().
+
+  @param[in]  This          Pointer to EDKII_REDFISH_HTTP_PROTOCOL instance.
+  @param[in]  Service       Redfish service instance to perform HTTP DELETE.
+  @param[in]  Uri           Target resource URI.
+  @param[in]  Content       JSON represented properties to be deleted. This is
+                            optional.
+  @param[in]  ContentSize   Size of the Content to be send to Redfish service.
+                            This is optional. When ContentSize is 0, ContentSize
+                            is the size of Content if Content is not NULL.
+  @param[in]  ContentType   Type of the Content to be send to Redfish service.
+                            This is optional. When Content is not NULL and
+                            ContentType is NULL, content type HTTP_CONTENT_TYPE_APP_JSON
+                            will be used.
+  @param[out] Response      HTTP response from redfish service.
+
+  @retval     EFI_SUCCESS     Resrouce is returned successfully.
+  @retval     Others          Errors occur.
+
+**/
+EFI_STATUS
+EFIAPI
+RedfishDeleteResource (
+  IN  EDKII_REDFISH_HTTP_PROTOCOL  *This,
+  IN  REDFISH_SERVICE              Service,
+  IN  EFI_STRING                   Uri,
+  IN  CHAR8                        *Content OPTIONAL,
+  IN  UINTN                        ContentSize OPTIONAL,
+  IN  CHAR8                        *ContentType OPTIONAL,
+  OUT REDFISH_RESPONSE             *Response
+  )
+{
+  EFI_STATUS                  Status;
+  UINTN                       RetryCount;
+  REDFISH_REQUEST             Request;
+  REDFISH_HTTP_CACHE_PRIVATE  *Private;
+
+  if ((This == NULL) || (Service == NULL) || (Response == NULL) || IS_EMPTY_STRING (Uri)) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  DEBUG ((REDFISH_HTTP_CACHE_DEBUG, "%a: Delete URI: %s\n", __func__, Uri));
+
+  Private    = REDFISH_HTTP_CACHE_PRIVATE_FROM_THIS (This);
+  RetryCount = 0;
+  ZeroMem (Response, sizeof (REDFISH_RESPONSE));
+  ZeroMem (&Request, sizeof (REDFISH_REQUEST));
+
+  Request.Content       = Content;
+  Request.ContentLength = ContentSize;
+  Request.ContentType   = ContentType;
+
+  //
+  // Patch resource to redfish service.
+  //
+  do {
+    RetryCount += 1;
+    Status      = HttpSendReceive (
+                    Service,
+                    Uri,
+                    HttpMethodDelete,
+                    &Request,
+                    Response
+                    );
+    DEBUG ((REDFISH_HTTP_CACHE_DEBUG_REQUEST, "%a: HTTP request: %s :%r\n", __func__, Uri, Status));
+    if (!EFI_ERROR (Status) || (RetryCount >= Private->RetrySetting.MaximumRetryDelete)) {
+      break;
+    }
+
+    //
+    // Retry when BMC is not ready.
+    //
+    if ((Response->StatusCode != NULL)) {
+      DEBUG_CODE (
+        DumpRedfishResponse (NULL, DEBUG_ERROR, Response);
+        );
+
+      if (!RedfishRetryRequired (Response->StatusCode)) {
+        break;
+      }
+
+      //
+      // Release response for next round of request.
+      //
+      This->FreeResponse (This, Response);
+    }
+
+    DEBUG ((DEBUG_WARN, "%a: RedfishDeleteByUri failed, retry (%d/%d)\n", __func__, RetryCount, Private->RetrySetting.MaximumRetryDelete));
+    if (Private->RetrySetting.RetryWait > 0) {
+      gBS->Stall (Private->RetrySetting.RetryWait);
+    }
+  } while (TRUE);
+
+  //
+  // Redfish resource is updated. Automatically expire the cached response
+  // so application can directly get resource from Redfish service again.
+  //
+  DEBUG ((REDFISH_HTTP_CACHE_DEBUG, "%a: Resource is updated, expire URI: %s\n", __func__, Uri));
+  RedfishExpireResponse (This, Uri);
+
+  if (EFI_ERROR (Status)) {
+    DEBUG_CODE (
+      DumpRedfishResponse (NULL, DEBUG_ERROR, Response);
+      );
+    //
+    // Report status code for Redfish failure
+    //
+    ReportHttpError (HttpMethodDelete, Uri, Response->StatusCode);
+    DEBUG ((DEBUG_ERROR, "%a: delete %s failed (%d/%d): %r\n", __func__, Uri, RetryCount, Private->RetrySetting.MaximumRetryDelete, Status));
+    goto ON_RELEASE;
+  }
+
+ON_RELEASE:
+
+  return Status;
+}
+
+EDKII_REDFISH_HTTP_PROTOCOL  mEdkIIRedfishHttpProtocol = {
+  EDKII_REDFISH_HTTP_PROTOCOL_REVISION,
+  RedfishCreateRedfishService,
+  RedfishFreeRedfishService,
+  RedfishJsonInRedfishPayload,
+  RedfishGetResource,
+  RedfishPatchResource,
+  RedfishPutResource,
+  RedfishPostResource,
+  RedfishDeleteResource,
+  RedfishFreeRequest,
+  RedfishFreeResponse,
+  RedfishExpireResponse
+};
+
+/**
+  Unloads an image.
+
+  @param[in]  ImageHandle         Handle that identifies the image to be unloaded.
+
+  @retval EFI_SUCCESS             The image has been unloaded.
+  @retval EFI_INVALID_PARAMETER   ImageHandle is not a valid image handle.
+
+**/
+EFI_STATUS
+EFIAPI
+RedfishHttpDriverUnload (
+  IN EFI_HANDLE  ImageHandle
+  )
+{
+  if (mRedfishHttpCachePrivate == NULL) {
+    return EFI_SUCCESS;
+  }
+
+  if (!IsListEmpty (&mRedfishHttpCachePrivate->CacheList.Head)) {
+    ReleaseCacheList (&mRedfishHttpCachePrivate->CacheList);
+  }
+
+  gBS->UninstallMultipleProtocolInterfaces (
+         ImageHandle,
+         &gEdkIIRedfishHttpProtocolGuid,
+         &mRedfishHttpCachePrivate->Protocol,
+         NULL
+         );
+
+  FreePool (mRedfishHttpCachePrivate);
+  mRedfishHttpCachePrivate = NULL;
+
+  return EFI_SUCCESS;
+}
+
+/**
+  This is a EDKII_REDFISH_CREDENTIAL_PROTOCOL notification event handler.
+
+  @param[in] Event    Event whose notification function is being invoked.
+  @param[in] Context  Pointer to the notification function's context.
+
+**/
+VOID
+EFIAPI
+CredentialProtocolInstalled (
+  IN  EFI_EVENT  Event,
+  IN  VOID       *Context
+  )
+{
+  EFI_STATUS                  Status;
+  REDFISH_HTTP_CACHE_PRIVATE  *Private;
+
+  Private = (REDFISH_HTTP_CACHE_PRIVATE *)Context;
+  if (Private->Signature != REDFISH_HTTP_DRIVER_SIGNATURE) {
+    DEBUG ((DEBUG_ERROR, "%a: signature check failure\n", __func__));
+    return;
+  }
+
+  //
+  // Locate HII database protocol.
+  //
+  Status = gBS->LocateProtocol (
+                  &gEdkIIRedfishCredentialProtocolGuid,
+                  NULL,
+                  (VOID **)&Private->CredentialProtocol
+                  );
+  if (EFI_ERROR (Status)) {
+    return;
+  }
+
+  gBS->CloseEvent (Event);
+}
+
+/**
+  Main entry for this driver.
+
+  @param[in] ImageHandle     Image handle this driver.
+  @param[in] SystemTable     Pointer to SystemTable.
+
+  @retval EFI_SUCCESS     This function always complete successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+RedfishHttpEntryPoint (
+  IN EFI_HANDLE        ImageHandle,
+  IN EFI_SYSTEM_TABLE  *SystemTable
+  )
+{
+  EFI_STATUS  Status;
+  VOID        *Registration;
+
+  if (mRedfishHttpCachePrivate != NULL) {
+    return EFI_ALREADY_STARTED;
+  }
+
+  mRedfishHttpCachePrivate = AllocateZeroPool (sizeof (REDFISH_HTTP_CACHE_PRIVATE));
+  if (mRedfishHttpCachePrivate == NULL) {
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  //
+  // Initial cache list and protocol instance.
+  //
+  mRedfishHttpCachePrivate->Signature   = REDFISH_HTTP_DRIVER_SIGNATURE;
+  mRedfishHttpCachePrivate->ImageHandle = ImageHandle;
+  CopyMem (&mRedfishHttpCachePrivate->Protocol, &mEdkIIRedfishHttpProtocol, sizeof (EDKII_REDFISH_HTTP_PROTOCOL));
+  mRedfishHttpCachePrivate->CacheList.Capacity = REDFISH_HTTP_CACHE_LIST_SIZE;
+  mRedfishHttpCachePrivate->CacheList.Count    = 0x00;
+  mRedfishHttpCachePrivate->CacheDisabled      = PcdGetBool (PcdHttpCacheDisabled);
+  InitializeListHead (&mRedfishHttpCachePrivate->CacheList.Head);
+
+  //
+  // Get retry settings
+  //
+  mRedfishHttpCachePrivate->RetrySetting.MaximumRetryGet    = PcdGet16 (PcdHttpGetRetry);
+  mRedfishHttpCachePrivate->RetrySetting.MaximumRetryPut    = PcdGet16 (PcdHttpPutRetry);
+  mRedfishHttpCachePrivate->RetrySetting.MaximumRetryPatch  = PcdGet16 (PcdHttpPatchRetry);
+  mRedfishHttpCachePrivate->RetrySetting.MaximumRetryPost   = PcdGet16 (PcdHttpPostRetry);
+  mRedfishHttpCachePrivate->RetrySetting.MaximumRetryDelete = PcdGet16 (PcdHttpDeleteRetry);
+  mRedfishHttpCachePrivate->RetrySetting.RetryWait          = PcdGet16 (PcdHttpRetryWaitInSecond) * 1000000U;
+
+  //
+  // Install the gEdkIIRedfishHttpProtocolGuid onto Handle.
+  //
+  Status = gBS->InstallMultipleProtocolInterfaces (
+                  &mRedfishHttpCachePrivate->ImageHandle,
+                  &gEdkIIRedfishHttpProtocolGuid,
+                  &mRedfishHttpCachePrivate->Protocol,
+                  NULL
+                  );
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "%a: cannot install Redfish http protocol: %r\n", __func__, Status));
+    RedfishHttpDriverUnload (ImageHandle);
+    return Status;
+  }
+
+  //
+  // Install protocol notification if credential protocol is installed.
+  //
+  mRedfishHttpCachePrivate->NotifyEvent = EfiCreateProtocolNotifyEvent (
+                                            &gEdkIIRedfishCredentialProtocolGuid,
+                                            TPL_CALLBACK,
+                                            CredentialProtocolInstalled,
+                                            mRedfishHttpCachePrivate,
+                                            &Registration
+                                            );
+  if (mRedfishHttpCachePrivate->NotifyEvent == NULL) {
+    DEBUG ((DEBUG_ERROR, "%a: failed to create protocol notification for gEdkIIRedfishCredentialProtocolGuid\n", __func__));
+    ASSERT (FALSE);
+    RedfishHttpDriverUnload (ImageHandle);
+    return Status;
+  }
+
+  return EFI_SUCCESS;
+}
diff --git a/RedfishPkg/RedfishHttpDxe/RedfishHttpOperation.c b/RedfishPkg/RedfishHttpDxe/RedfishHttpOperation.c
new file mode 100644
index 0000000000..5652818d16
--- /dev/null
+++ b/RedfishPkg/RedfishHttpDxe/RedfishHttpOperation.c
@@ -0,0 +1,693 @@
+/** @file
+  RedfishHttpOperation handles HTTP operations.
+
+  Copyright (c) 2024, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "RedfishHttpOperation.h"
+#include "RedfishHttpData.h"
+
+/**
+  This function copies all headers in SrcHeaders to DstHeaders.
+  It's call responsibility to release returned DstHeaders.
+
+  @param[in]  SrcHeaders      Source headers.
+  @param[in]  SrcHeaderCount  Number of header in source headers.
+  @param[out] DstHeaders      Destination headers.
+  @param[out] DstHeaderCount  Number of header in designation headers.
+
+  @retval     EFI_SUCCESS     Headers are copied successfully.
+  @retval     Others          Errors occur.
+
+**/
+EFI_STATUS
+CopyHttpHeaders (
+  IN  EFI_HTTP_HEADER  *SrcHeaders,
+  IN  UINTN            SrcHeaderCount,
+  OUT EFI_HTTP_HEADER  **DstHeaders,
+  OUT UINTN            *DstHeaderCount
+  )
+{
+  UINTN  Index;
+
+  if ((SrcHeaders == NULL) || (SrcHeaderCount == 0) || (DstHeaders == NULL) || (DstHeaderCount == NULL)) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  *DstHeaderCount = 0;
+  *DstHeaders     = AllocateZeroPool (sizeof (EFI_HTTP_HEADER) * SrcHeaderCount);
+  if (*DstHeaders == NULL) {
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  for (Index = 0; Index < SrcHeaderCount; Index++) {
+    (*DstHeaders)[Index].FieldName = AllocateCopyPool (AsciiStrSize (SrcHeaders[Index].FieldName), SrcHeaders[Index].FieldName);
+    if ((*DstHeaders)[Index].FieldName == NULL) {
+      return EFI_OUT_OF_RESOURCES;
+    }
+
+    (*DstHeaders)[Index].FieldValue = AllocateCopyPool (AsciiStrSize (SrcHeaders[Index].FieldValue), SrcHeaders[Index].FieldValue);
+    if ((*DstHeaders)[Index].FieldValue == NULL) {
+      return EFI_OUT_OF_RESOURCES;
+    }
+
+    *DstHeaderCount += 1;
+  }
+
+  return EFI_SUCCESS;
+}
+
+/**
+  This function free resources in Request. Request is no longer available
+  after this function returns successfully.
+
+  @param[in]  Request      HTTP request to be released.
+
+  @retval     EFI_SUCCESS     Resrouce is released successfully.
+  @retval     Others          Errors occur.
+
+**/
+EFI_STATUS
+ReleaseRedfishRequest (
+  IN  REDFISH_REQUEST  *Request
+  )
+{
+  if (Request == NULL) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  if ((Request->Headers != NULL) && (Request->HeaderCount > 0)) {
+    HttpFreeHeaderFields (Request->Headers, Request->HeaderCount);
+    Request->Headers     = NULL;
+    Request->HeaderCount = 0;
+  }
+
+  if (Request->Content != NULL) {
+    FreePool (Request->Content);
+    Request->Content = NULL;
+  }
+
+  if (Request->ContentType != NULL) {
+    FreePool (Request->ContentType);
+    Request->ContentType = NULL;
+  }
+
+  Request->ContentLength = 0;
+
+  return EFI_SUCCESS;
+}
+
+/**
+  This function free resources in given Response.
+
+  @param[in]  Response     HTTP response to be released.
+
+  @retval     EFI_SUCCESS     Resrouce is released successfully.
+  @retval     Others          Errors occur.
+
+**/
+EFI_STATUS
+ReleaseRedfishResponse (
+  IN  REDFISH_RESPONSE  *Response
+  )
+{
+  if (Response == NULL) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  if ((Response->Headers != NULL) && (Response->HeaderCount > 0)) {
+    HttpFreeHeaderFields (Response->Headers, Response->HeaderCount);
+    Response->Headers     = NULL;
+    Response->HeaderCount = 0;
+  }
+
+  if (Response->Payload != NULL) {
+    ReleaseRedfishPayload (Response->Payload);
+    Response->Payload = NULL;
+  }
+
+  if (Response->StatusCode != NULL) {
+    FreePool (Response->StatusCode);
+    Response->StatusCode = NULL;
+  }
+
+  return EFI_SUCCESS;
+}
+
+/**
+  This function free resources in given HTTP message.
+
+  @param[in]  HttpMessage     HTTP message to be released.
+  @param[in]  IsRequest       TRUE if this is request type of HTTP message.
+                              FALSE if this is response type of HTTP message.
+
+  @retval     EFI_SUCCESS     Resrouce is released successfully.
+  @retval     Others          Errors occur.
+
+**/
+EFI_STATUS
+ReleaseHttpMessage (
+  IN  EFI_HTTP_MESSAGE  *HttpMessage,
+  IN  BOOLEAN           IsRequest
+  )
+{
+  if (HttpMessage == NULL) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  if (IsRequest) {
+    if (HttpMessage->Data.Request != NULL) {
+      if (HttpMessage->Data.Request->Url != NULL) {
+        FreePool (HttpMessage->Data.Request->Url);
+      }
+
+      FreePool (HttpMessage->Data.Request);
+      HttpMessage->Data.Request = NULL;
+    }
+  } else {
+    if (HttpMessage->Data.Response != NULL) {
+      FreePool (HttpMessage->Data.Response);
+      HttpMessage->Data.Response = NULL;
+    }
+  }
+
+  if (HttpMessage->Body != NULL) {
+    FreePool (HttpMessage->Body);
+    HttpMessage->Body = NULL;
+  }
+
+  if (HttpMessage->Headers != NULL) {
+    HttpFreeHeaderFields (HttpMessage->Headers, HttpMessage->HeaderCount);
+    HttpMessage->Headers     = NULL;
+    HttpMessage->HeaderCount = 0;
+  }
+
+  return EFI_SUCCESS;
+}
+
+/**
+  This function build Redfish message for sending data to Redfish service.
+  It's call responsibility to properly release returned HTTP message by
+  calling ReleaseHttpMessage.
+
+  @param[in]   ServicePrivate    Pointer to Redfish service private data.
+  @param[in]   Uri               Redfish service URI.
+  @param[in]   Method            HTTP method.
+  @param[in]   Request           Additional data to send to Redfish service.
+                                 This is optional.
+  @param[in]   ContentEncoding   Content encoding method to compress HTTP context.
+                                 This is optional. When ContentEncoding is NULL,
+                                 No compress method will be performed.
+
+  @retval     EFI_HTTP_MESSAGE *   Pointer to newly created HTTP message.
+  @retval     NULL                 Error occurred.
+
+**/
+EFI_HTTP_MESSAGE *
+BuildRequestMessage (
+  IN REDFISH_SERVICE_PRIVATE  *ServicePrivate,
+  IN EFI_STRING               Uri,
+  IN EFI_HTTP_METHOD          Method,
+  IN REDFISH_REQUEST          *Request OPTIONAL,
+  IN CHAR8                    *ContentEncoding OPTIONAL
+  )
+{
+  EFI_STATUS             Status;
+  EFI_STRING             Url;
+  UINTN                  UrlSize;
+  UINTN                  Index;
+  EFI_HTTP_MESSAGE       *RequestMsg;
+  EFI_HTTP_REQUEST_DATA  *RequestData;
+  UINTN                  HeaderCount;
+  UINTN                  HeaderIndex;
+  EFI_HTTP_HEADER        *Headers;
+  CHAR8                  ContentLengthStr[REDFISH_CONTENT_LENGTH_SIZE];
+  VOID                   *Content;
+  UINTN                  ContentLength;
+  BOOLEAN                HasContent;
+  BOOLEAN                DoContentEncoding;
+
+  RequestMsg        = NULL;
+  RequestData       = NULL;
+  Url               = NULL;
+  UrlSize           = 0;
+  Content           = NULL;
+  ContentLength     = 0;
+  HeaderCount       = REDFISH_COMMON_HEADER_SIZE;
+  HeaderIndex       = 0;
+  Headers           = NULL;
+  HasContent        = FALSE;
+  DoContentEncoding = FALSE;
+
+  if ((ServicePrivate == NULL) || (IS_EMPTY_STRING (Uri))) {
+    return NULL;
+  }
+
+  if (Method >= HttpMethodMax) {
+    return NULL;
+  }
+
+  DEBUG ((REDFISH_HTTP_CACHE_DEBUG_REQUEST, "%a: %s\n", __func__, Uri));
+
+  //
+  // Build full URL for HTTP query.
+  //
+  UrlSize = (AsciiStrLen (ServicePrivate->Host) + StrLen (Uri) + 1) * sizeof (CHAR16);
+  Url     = AllocateZeroPool (UrlSize);
+  if (Url == NULL) {
+    return NULL;
+  }
+
+  UnicodeSPrint (Url, UrlSize, L"%a%s", ServicePrivate->Host, Uri);
+  DEBUG ((REDFISH_HTTP_CACHE_DEBUG_REQUEST, "%a: Url: %s\n", __func__, Url));
+
+  //
+  // Step 1: build the HTTP headers.
+  //
+  if (!IS_EMPTY_STRING (ServicePrivate->SessionToken) || !IS_EMPTY_STRING (ServicePrivate->BasicAuth)) {
+    HeaderCount++;
+  }
+
+  if ((Request != NULL) && (Request->HeaderCount > 0)) {
+    HeaderCount += Request->HeaderCount;
+  }
+
+  //
+  // Check and see if we will do content encoding or not
+  //
+  if (!IS_EMPTY_STRING (ContentEncoding)) {
+    if (AsciiStrCmp (ContentEncoding, REDFISH_HTTP_CONTENT_ENCODING_NONE) != 0) {
+      DoContentEncoding = TRUE;
+    }
+  }
+
+  if ((Request != NULL) && !IS_EMPTY_STRING (Request->Content)) {
+    HeaderCount += 2;
+    HasContent   = TRUE;
+    if (DoContentEncoding) {
+      HeaderCount += 1;
+    }
+  }
+
+  Headers = AllocateZeroPool (HeaderCount * sizeof (EFI_HTTP_HEADER));
+  if (Headers == NULL) {
+    goto ON_ERROR;
+  }
+
+  if (!IS_EMPTY_STRING (ServicePrivate->SessionToken)) {
+    Status = HttpSetFieldNameAndValue (&Headers[HeaderIndex++], HTTP_HEADER_X_AUTH_TOKEN, ServicePrivate->SessionToken);
+    if (EFI_ERROR (Status)) {
+      goto ON_ERROR;
+    }
+  } else if (!IS_EMPTY_STRING (ServicePrivate->BasicAuth)) {
+    Status = HttpSetFieldNameAndValue (&Headers[HeaderIndex++], HTTP_HEADER_AUTHORIZATION, ServicePrivate->BasicAuth);
+    if (EFI_ERROR (Status)) {
+      goto ON_ERROR;
+    }
+  }
+
+  if (Request != NULL) {
+    for (Index = 0; Index < Request->HeaderCount; Index++) {
+      Status = HttpSetFieldNameAndValue (&Headers[HeaderIndex++], Request->Headers[Index].FieldName, Request->Headers[Index].FieldValue);
+      if (EFI_ERROR (Status)) {
+        goto ON_ERROR;
+      }
+    }
+  }
+
+  Status = HttpSetFieldNameAndValue (&Headers[HeaderIndex++], HTTP_HEADER_HOST, ServicePrivate->HostName);
+  if (EFI_ERROR (Status)) {
+    goto ON_ERROR;
+  }
+
+  Status = HttpSetFieldNameAndValue (&Headers[HeaderIndex++], REDFISH_HTTP_HEADER_ODATA_VERSION_STR, REDFISH_HTTP_HEADER_ODATA_VERSION_VALUE);
+  if (EFI_ERROR (Status)) {
+    goto ON_ERROR;
+  }
+
+  Status = HttpSetFieldNameAndValue (&Headers[HeaderIndex++], HTTP_HEADER_ACCEPT, HTTP_CONTENT_TYPE_APP_JSON);
+  if (EFI_ERROR (Status)) {
+    goto ON_ERROR;
+  }
+
+  Status = HttpSetFieldNameAndValue (&Headers[HeaderIndex++], HTTP_HEADER_USER_AGENT, REDFISH_HTTP_HEADER_USER_AGENT_VALUE);
+  if (EFI_ERROR (Status)) {
+    goto ON_ERROR;
+  }
+
+  Status = HttpSetFieldNameAndValue (&Headers[HeaderIndex++], REDFISH_HTTP_HEADER_CONNECTION_STR, REDFISH_HTTP_HEADER_CONNECTION_VALUE);
+  if (EFI_ERROR (Status)) {
+    goto ON_ERROR;
+  }
+
+  //
+  // Handle content header
+  //
+  if (HasContent) {
+    if (Request->ContentType == NULL) {
+      Status = HttpSetFieldNameAndValue (&Headers[HeaderIndex++], HTTP_HEADER_CONTENT_TYPE, HTTP_CONTENT_TYPE_APP_JSON);
+      if (EFI_ERROR (Status)) {
+        goto ON_ERROR;
+      }
+    } else {
+      Status = HttpSetFieldNameAndValue (&Headers[HeaderIndex++], HTTP_HEADER_CONTENT_TYPE, Request->ContentType);
+      if (EFI_ERROR (Status)) {
+        goto ON_ERROR;
+      }
+    }
+
+    if (Request->ContentLength == 0) {
+      Request->ContentLength =  AsciiStrLen (Request->Content);
+    }
+
+    AsciiSPrint (
+      ContentLengthStr,
+      sizeof (ContentLengthStr),
+      "%lu",
+      (UINT64)Request->ContentLength
+      );
+    Status = HttpSetFieldNameAndValue (&Headers[HeaderIndex++], HTTP_HEADER_CONTENT_LENGTH, ContentLengthStr);
+    if (EFI_ERROR (Status)) {
+      goto ON_ERROR;
+    }
+
+    //
+    // Encoding
+    //
+    if (DoContentEncoding) {
+      //
+      // We currently only support gzip Content-Encoding.
+      //
+      Status =  RedfishContentEncode (
+                  ContentEncoding,
+                  Request->Content,
+                  Request->ContentLength,
+                  &Content,
+                  &ContentLength
+                  );
+      if (Status == EFI_INVALID_PARAMETER) {
+        DEBUG ((DEBUG_ERROR, "%a: Error to encode content.\n", __func__));
+        goto ON_ERROR;
+      } else if (Status == EFI_UNSUPPORTED) {
+        DoContentEncoding = FALSE;
+        DEBUG ((REDFISH_HTTP_CACHE_DEBUG_REQUEST, "%a: No content coding for %a! Use raw data instead.\n", __func__, ContentEncoding));
+        Status = HttpSetFieldNameAndValue (&Headers[HeaderIndex++], HTTP_HEADER_CONTENT_ENCODING, HTTP_CONTENT_ENCODING_IDENTITY);
+        if (EFI_ERROR (Status)) {
+          goto ON_ERROR;
+        }
+      } else {
+        Status = HttpSetFieldNameAndValue (&Headers[HeaderIndex++], HTTP_HEADER_CONTENT_ENCODING, HTTP_CONTENT_ENCODING_GZIP);
+        if (EFI_ERROR (Status)) {
+          goto ON_ERROR;
+        }
+      }
+    }
+
+    //
+    // When the content is from caller, we use our own copy so that we properly release it later.
+    //
+    if (!DoContentEncoding) {
+      Content = AllocateCopyPool (Request->ContentLength, Request->Content);
+      if (Content == NULL) {
+        goto ON_ERROR;
+      }
+
+      ContentLength = Request->ContentLength;
+    }
+  }
+
+  //
+  // Step 2: build the rest of HTTP request info.
+  //
+  RequestData = AllocateZeroPool (sizeof (EFI_HTTP_REQUEST_DATA));
+  if (RequestData == NULL) {
+    goto ON_ERROR;
+  }
+
+  RequestData->Method = Method;
+  RequestData->Url    = Url;
+
+  //
+  // Step 3: fill in EFI_HTTP_MESSAGE
+  //
+  RequestMsg = AllocateZeroPool (sizeof (EFI_HTTP_MESSAGE));
+  if (RequestMsg == NULL) {
+    goto ON_ERROR;
+  }
+
+  ASSERT (HeaderIndex == HeaderCount);
+  RequestMsg->Data.Request = RequestData;
+  RequestMsg->HeaderCount  = HeaderIndex;
+  RequestMsg->Headers      = Headers;
+
+  if (HasContent) {
+    RequestMsg->BodyLength = ContentLength;
+    RequestMsg->Body       = Content;
+  }
+
+  return RequestMsg;
+
+ON_ERROR:
+
+  if (Headers != NULL) {
+    HttpFreeHeaderFields (Headers, HeaderIndex);
+  }
+
+  if (RequestData != NULL) {
+    FreePool (RequestData);
+  }
+
+  if (RequestMsg != NULL) {
+    FreePool (RequestMsg);
+  }
+
+  if (Url != NULL) {
+    FreePool (Url);
+  }
+
+  return NULL;
+}
+
+/**
+  This function parse response message from Redfish service, and
+  build Redfish response for caller. It's call responsibility to
+  properly release Redfish response by calling ReleaseRedfishResponse.
+
+  @param[in]   ServicePrivate   Pointer to Redfish service private data.
+  @param[in]   ResponseMsg      Response message from Redfish service.
+  @param[out]  RedfishResponse  Redfish response data.
+
+  @retval     EFI_SUCCESS     Redfish response is returned successfully.
+  @retval     Others          Errors occur.
+
+**/
+EFI_STATUS
+ParseResponseMessage (
+  IN  REDFISH_SERVICE_PRIVATE  *ServicePrivate,
+  IN  EFI_HTTP_MESSAGE         *ResponseMsg,
+  OUT REDFISH_RESPONSE         *RedfishResponse
+  )
+{
+  EFI_STATUS        Status;
+  EDKII_JSON_VALUE  JsonData;
+  EFI_HTTP_HEADER   *ContentEncodedHeader;
+  VOID              *DecodedBody;
+  UINTN             DecodedLength;
+
+  if ((ServicePrivate == NULL) || (ResponseMsg == NULL) || (RedfishResponse == NULL)) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  DEBUG ((REDFISH_HTTP_CACHE_DEBUG_REQUEST, "%a\n", __func__));
+
+  //
+  // Initialization
+  //
+  JsonData                     = NULL;
+  RedfishResponse->HeaderCount = 0;
+  RedfishResponse->Headers     = NULL;
+  RedfishResponse->Payload     = NULL;
+  RedfishResponse->StatusCode  = NULL;
+  DecodedBody                  = NULL;
+  DecodedLength                = 0;
+
+  //
+  // Return the HTTP StatusCode.
+  //
+  if (ResponseMsg->Data.Response != NULL) {
+    DEBUG ((REDFISH_HTTP_CACHE_DEBUG_REQUEST, "%a: status: %d\n", __func__, ResponseMsg->Data.Response->StatusCode));
+    RedfishResponse->StatusCode = AllocateCopyPool (sizeof (EFI_HTTP_STATUS_CODE), &ResponseMsg->Data.Response->StatusCode);
+    if (RedfishResponse->StatusCode == NULL) {
+      DEBUG ((DEBUG_ERROR, "%a: Failed to create status code.\n", __func__));
+    }
+  }
+
+  //
+  // Return the HTTP headers.
+  //
+  if (ResponseMsg->Headers != NULL) {
+    DEBUG ((REDFISH_HTTP_CACHE_DEBUG_REQUEST, "%a: header count: %d\n", __func__, ResponseMsg->HeaderCount));
+    Status = CopyHttpHeaders (
+               ResponseMsg->Headers,
+               ResponseMsg->HeaderCount,
+               &RedfishResponse->Headers,
+               &RedfishResponse->HeaderCount
+               );
+    if (EFI_ERROR (Status)) {
+      DEBUG ((DEBUG_ERROR, "%a: Failed to copy HTTP headers: %r\n", __func__, Status));
+    }
+  }
+
+  //
+  // Return the HTTP body.
+  //
+  if ((ResponseMsg->BodyLength != 0) && (ResponseMsg->Body != NULL)) {
+    DEBUG ((REDFISH_HTTP_CACHE_DEBUG_REQUEST, "%a: body length: %d\n", __func__, ResponseMsg->BodyLength));
+    //
+    // Check if data is encoded.
+    //
+    ContentEncodedHeader = HttpFindHeader (RedfishResponse->HeaderCount, RedfishResponse->Headers, HTTP_HEADER_CONTENT_ENCODING);
+    if (ContentEncodedHeader != NULL) {
+      //
+      // The content is encoded.
+      //
+      Status = RedfishContentDecode (
+                 ContentEncodedHeader->FieldValue,
+                 ResponseMsg->Body,
+                 ResponseMsg->BodyLength,
+                 &DecodedBody,
+                 &DecodedLength
+                 );
+      if (EFI_ERROR (Status)) {
+        DEBUG ((DEBUG_ERROR, "%a: Failed to decompress the response content: %r decoding method: %a\n.", __func__, Status, ContentEncodedHeader->FieldValue));
+        goto ON_ERROR;
+      }
+
+      JsonData = JsonLoadBuffer (DecodedBody, DecodedLength, 0, NULL);
+      FreePool (DecodedBody);
+    } else {
+      JsonData = JsonLoadBuffer (ResponseMsg->Body, ResponseMsg->BodyLength, 0, NULL);
+    }
+
+    if (!JsonValueIsNull (JsonData)) {
+      RedfishResponse->Payload = CreateRedfishPayload (ServicePrivate, JsonData);
+      if (RedfishResponse->Payload == NULL) {
+        DEBUG ((DEBUG_ERROR, "%a: Failed to create payload\n.", __func__));
+      }
+
+      JsonValueFree (JsonData);
+    } else {
+      DEBUG ((DEBUG_ERROR, "%a: No payload available\n", __func__));
+    }
+  }
+
+  return EFI_SUCCESS;
+
+ON_ERROR:
+
+  if (RedfishResponse != NULL) {
+    ReleaseRedfishResponse (RedfishResponse);
+  }
+
+  return Status;
+}
+
+/**
+  This function send Redfish request to Redfish service by calling
+  Rest Ex protocol.
+
+  @param[in]   Service       Pointer to Redfish service.
+  @param[in]   Uri           Uri of Redfish service.
+  @param[in]   Method        HTTP method.
+  @param[in]   Request     Request data. This is optional.
+  @param[out]  Response    Redfish response data.
+
+  @retval     EFI_SUCCESS     Request is sent and received successfully.
+  @retval     Others          Errors occur.
+
+**/
+EFI_STATUS
+HttpSendReceive (
+  IN  REDFISH_SERVICE   Service,
+  IN  EFI_STRING        Uri,
+  IN  EFI_HTTP_METHOD   Method,
+  IN  REDFISH_REQUEST   *Request  OPTIONAL,
+  OUT REDFISH_RESPONSE  *Response
+  )
+{
+  EFI_STATUS               Status;
+  EFI_STATUS               RestExStatus;
+  EFI_HTTP_MESSAGE         *RequestMsg;
+  EFI_HTTP_MESSAGE         ResponseMsg;
+  REDFISH_SERVICE_PRIVATE  *ServicePrivate;
+  EFI_HTTP_HEADER          *XAuthTokenHeader;
+  CHAR8                    *HttpContentEncoding;
+
+  if ((Service == NULL) || IS_EMPTY_STRING (Uri) || (Response == NULL)) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  DEBUG ((REDFISH_HTTP_CACHE_DEBUG_REQUEST, "%a: Method: 0x%x %s\n", __func__, Method, Uri));
+
+  ServicePrivate = (REDFISH_SERVICE_PRIVATE *)Service;
+  if (ServicePrivate->Signature != REDFISH_HTTP_SERVICE_SIGNATURE) {
+    DEBUG ((DEBUG_ERROR, "%a: signature check failure\n", __func__));
+    return EFI_INVALID_PARAMETER;
+  }
+
+  ZeroMem (&ResponseMsg, sizeof (ResponseMsg));
+  HttpContentEncoding = (CHAR8 *)PcdGetPtr (PcdRedfishServiceContentEncoding);
+
+  RequestMsg = BuildRequestMessage (Service, Uri, Method, Request, HttpContentEncoding);
+  if (RequestMsg == NULL) {
+    DEBUG ((DEBUG_ERROR, "%a: cannot build request message for %s\n", __func__, Uri));
+    return EFI_PROTOCOL_ERROR;
+  }
+
+  //
+  // call RESTEx to get response from REST service.
+  //
+  RestExStatus = ServicePrivate->RestEx->SendReceive (ServicePrivate->RestEx, RequestMsg, &ResponseMsg);
+  if (EFI_ERROR (RestExStatus)) {
+    DEBUG ((DEBUG_ERROR, "%a: %s SendReceive failure: %r\n", __func__, Uri, RestExStatus));
+  }
+
+  //
+  // Return status code, headers and payload to caller as much as possible even when RestEx returns failure.
+  //
+  Status = ParseResponseMessage (ServicePrivate, &ResponseMsg, Response);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "%a: %s parse response failure: %r\n", __func__, Uri, Status));
+  } else {
+    //
+    // Capture session token in header
+    //
+    if ((Method == HttpMethodPost) &&
+        (Response->StatusCode != NULL) &&
+        ((*Response->StatusCode == HTTP_STATUS_200_OK) || (*Response->StatusCode == HTTP_STATUS_204_NO_CONTENT)))
+    {
+      XAuthTokenHeader = HttpFindHeader (ResponseMsg.HeaderCount, ResponseMsg.Headers, HTTP_HEADER_X_AUTH_TOKEN);
+      if (XAuthTokenHeader != NULL) {
+        Status = UpdateSessionToken (ServicePrivate, XAuthTokenHeader->FieldValue);
+        if (EFI_ERROR (Status)) {
+          DEBUG ((DEBUG_ERROR, "%a: update session token failure: %r\n", __func__, Status));
+        }
+      }
+    }
+  }
+
+  //
+  // Release resources
+  //
+  if (RequestMsg != NULL) {
+    ReleaseHttpMessage (RequestMsg, TRUE);
+    FreePool (RequestMsg);
+  }
+
+  ReleaseHttpMessage (&ResponseMsg, FALSE);
+
+  return RestExStatus;
+}
diff --git a/RedfishPkg/Redfish.fdf.inc b/RedfishPkg/Redfish.fdf.inc
index 3e5a77766e..5cbe3592fd 100644
--- a/RedfishPkg/Redfish.fdf.inc
+++ b/RedfishPkg/Redfish.fdf.inc
@@ -6,7 +6,7 @@
 # to be built in the firmware volume.
 #
 # (C) Copyright 2020-2021 Hewlett Packard Enterprise Development LP<BR>
-# Copyright (c) 2023, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
+# Copyright (c) 2023-2024, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
 #
 #    SPDX-License-Identifier: BSD-2-Clause-Patent
 #
@@ -20,4 +20,5 @@
   INF RedfishPkg/RedfishConfigHandler/RedfishConfigHandlerDriver.inf
   INF RedfishPkg/RedfishPlatformConfigDxe/RedfishPlatformConfigDxe.inf
   INF MdeModulePkg/Universal/RegularExpressionDxe/RegularExpressionDxe.inf
+  INF RedfishPkg/RedfishHttpDxe/RedfishHttpDxe.inf
 !endif
-- 
2.34.1



-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#115776): https://edk2.groups.io/g/devel/message/115776
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]
-=-=-=-=-=-=-=-=-=-=-=-



^ permalink raw reply related	[flat|nested] 15+ messages in thread

* Re: [edk2-devel] [PATCH v2 2/6] RedfishPkg: implement Redfish HTTP protocol
  2024-02-22  9:11 [edk2-devel] [PATCH v2 2/6] RedfishPkg: implement Redfish HTTP protocol Nickle Wang via groups.io
@ 2024-02-22 13:39 ` Chang, Abner via groups.io
  2024-02-22 14:17 ` Igor Kulchytskyy via groups.io
  2024-02-23 11:29 ` Mike Maslenkin
  2 siblings, 0 replies; 15+ messages in thread
From: Chang, Abner via groups.io @ 2024-02-22 13:39 UTC (permalink / raw)
  To: Nickle Wang, devel@edk2.groups.io; +Cc: Igor Kulchytskyy, Nick Ramirez

[AMD Official Use Only - General]

Thanks!

Reviewed-by: Abner Chang <abner.chang@amd.com>

> -----Original Message-----
> From: Nickle Wang <nicklew@nvidia.com>
> Sent: Thursday, February 22, 2024 5:11 PM
> To: devel@edk2.groups.io
> Cc: Igor Kulchytskyy <igork@ami.com>; Chang, Abner
> <Abner.Chang@amd.com>; Nick Ramirez <nramirez@nvidia.com>
> Subject: [PATCH v2 2/6] RedfishPkg: implement Redfish HTTP protocol
>
> Caution: This message originated from an External Source. Use proper caution
> when opening attachments, clicking links, or responding.
>
>
> implement Redfish HTTP protocol driver.
>
> Signed-off-by: Nickle Wang <nicklew@nvidia.com>
> Co-authored-by: Igor Kulchytskyy <igork@ami.com>
> Cc: Abner Chang <abner.chang@amd.com>
> Cc: Igor Kulchytskyy <igork@ami.com>
> Cc: Nick Ramirez <nramirez@nvidia.com>
> ---
>  RedfishPkg/RedfishPkg.dec                     |    7 +-
>  RedfishPkg/RedfishComponents.dsc.inc          |    3 +-
>  RedfishPkg/RedfishPkg.dsc                     |    2 +
>  RedfishPkg/RedfishHttpDxe/RedfishHttpDxe.inf  |   73 +
>  RedfishPkg/RedfishHttpDxe/RedfishHttpData.h   |  256 ++++
>  RedfishPkg/RedfishHttpDxe/RedfishHttpDxe.h    |   44 +
>  .../RedfishHttpDxe/RedfishHttpOperation.h     |   76 +
>  RedfishPkg/RedfishHttpDxe/RedfishHttpData.c   |  667 ++++++++
>  RedfishPkg/RedfishHttpDxe/RedfishHttpDxe.c    | 1344
> +++++++++++++++++
>  .../RedfishHttpDxe/RedfishHttpOperation.c     |  693 +++++++++
>  RedfishPkg/Redfish.fdf.inc                    |    3 +-
>  11 files changed, 3164 insertions(+), 4 deletions(-)
>  create mode 100644 RedfishPkg/RedfishHttpDxe/RedfishHttpDxe.inf
>  create mode 100644 RedfishPkg/RedfishHttpDxe/RedfishHttpData.h
>  create mode 100644 RedfishPkg/RedfishHttpDxe/RedfishHttpDxe.h
>  create mode 100644 RedfishPkg/RedfishHttpDxe/RedfishHttpOperation.h
>  create mode 100644 RedfishPkg/RedfishHttpDxe/RedfishHttpData.c
>  create mode 100644 RedfishPkg/RedfishHttpDxe/RedfishHttpDxe.c
>  create mode 100644 RedfishPkg/RedfishHttpDxe/RedfishHttpOperation.c
>
> diff --git a/RedfishPkg/RedfishPkg.dec b/RedfishPkg/RedfishPkg.dec
> index 9b424efdf3..114f8d2ad8 100644
> --- a/RedfishPkg/RedfishPkg.dec
> +++ b/RedfishPkg/RedfishPkg.dec
> @@ -157,8 +157,11 @@
>    # set to EFI_REST_EX_PROTOCOL.
>    #
>
> gEfiRedfishPkgTokenSpaceGuid.PcdRedfishSendReceiveTimeout|5000|UINT3
> 2|0x00001009
> -  ## This is used to enable HTTP content encoding on Redfish communication.
> -
> gEfiRedfishPkgTokenSpaceGuid.PcdRedfishServiceContentEncoding|TRUE|BO
> OLEAN|0x0000100A
> +  #
> +  # This PCD string is introduced for platform developer to set the encoding
> method supported by BMC Redfish.
> +  # Currently only "None" and "gzip" are supported.
> +  #
> +
> gEfiRedfishPkgTokenSpaceGuid.PcdRedfishServiceContentEncoding|"None"|V
> OID*|0x0000100A
>    #
>    # Use below PCDs to control Redfhs HTTP protocol.
>    #
> diff --git a/RedfishPkg/RedfishComponents.dsc.inc
> b/RedfishPkg/RedfishComponents.dsc.inc
> index 464ffc8606..d6c5b73d7f 100644
> --- a/RedfishPkg/RedfishComponents.dsc.inc
> +++ b/RedfishPkg/RedfishComponents.dsc.inc
> @@ -7,7 +7,7 @@
>  # "RedfishDefines.dsc.inc".
>  #
>  # (C) Copyright 2020-2021 Hewlett Packard Enterprise Development LP<BR>
> -# Copyright (c) 2023, NVIDIA CORPORATION & AFFILIATES. All rights
> reserved.
> +# Copyright (c) 2023-2024, NVIDIA CORPORATION & AFFILIATES. All rights
> reserved.
>  #
>  #    SPDX-License-Identifier: BSD-2-Clause-Patent
>  #
> @@ -28,4 +28,5 @@
>    RedfishPkg/RedfishConfigHandler/RedfishConfigHandlerDriver.inf
>    RedfishPkg/RedfishPlatformConfigDxe/RedfishPlatformConfigDxe.inf
>    MdeModulePkg/Universal/RegularExpressionDxe/RegularExpressionDxe.inf
> +  RedfishPkg/RedfishHttpDxe/RedfishHttpDxe.inf
>  !endif
> diff --git a/RedfishPkg/RedfishPkg.dsc b/RedfishPkg/RedfishPkg.dsc
> index 25ed193182..5849e7cf9e 100644
> --- a/RedfishPkg/RedfishPkg.dsc
> +++ b/RedfishPkg/RedfishPkg.dsc
> @@ -45,6 +45,8 @@
>
> UefiHiiServicesLib|MdeModulePkg/Library/UefiHiiServicesLib/UefiHiiServicesL
> ib.inf
>
> RedfishPlatformCredentialLib|RedfishPkg/Library/PlatformCredentialLibNull/
> PlatformCredentialLibNull.inf
>
> RedfishContentCodingLib|RedfishPkg/Library/RedfishContentCodingLibNull/
> RedfishContentCodingLibNull.inf
> +
> ReportStatusCodeLib|MdeModulePkg/Library/DxeReportStatusCodeLib/DxeR
> eportStatusCodeLib.inf
> +  SortLib|MdeModulePkg/Library/UefiSortLib/UefiSortLib.inf
>
>    # NULL instance of IPMI related library.
>    IpmiLib|MdeModulePkg/Library/BaseIpmiLibNull/BaseIpmiLibNull.inf
> diff --git a/RedfishPkg/RedfishHttpDxe/RedfishHttpDxe.inf
> b/RedfishPkg/RedfishHttpDxe/RedfishHttpDxe.inf
> new file mode 100644
> index 0000000000..c7dfdffacf
> --- /dev/null
> +++ b/RedfishPkg/RedfishHttpDxe/RedfishHttpDxe.inf
> @@ -0,0 +1,73 @@
> +## @file
> +#  RedfishHttpDxe is the DXE driver which provides
> +#  EdkIIRedfishHttpProtocol to EDK2 Redfish Feature
> +#  drivers for HTTP operation.
> +#
> +#  Copyright (c) 2023-2024, NVIDIA CORPORATION & AFFILIATES. All rights
> reserved.
> +#
> +#  SPDX-License-Identifier: BSD-2-Clause-Patent
> +#
> +##
> +
> +[Defines]
> +  INF_VERSION                    = 0x0001000b
> +  BASE_NAME                      = RedfishHttpDxe
> +  FILE_GUID                      = 85ADB2F1-DA93-47D4-AF4F-3D920D9BD2C0
> +  MODULE_TYPE                    = DXE_DRIVER
> +  VERSION_STRING                 = 1.0
> +  ENTRY_POINT                    = RedfishHttpEntryPoint
> +  UNLOAD_IMAGE                   = RedfishHttpDriverUnload
> +
> +#
> +#  VALID_ARCHITECTURES           = IA32 X64 ARM AARCH64 RISCV64
> +#
> +
> +[Sources]
> +  RedfishHttpData.c
> +  RedfishHttpData.h
> +  RedfishHttpDxe.c
> +  RedfishHttpDxe.h
> +  RedfishHttpOperation.c
> +  RedfishHttpOperation.h
> +
> +[Packages]
> +  MdePkg/MdePkg.dec
> +  MdeModulePkg/MdeModulePkg.dec
> +  NetworkPkg/NetworkPkg.dec
> +  RedfishPkg/RedfishPkg.dec
> +
> +[LibraryClasses.ARM]
> +  ArmSoftFloatLib
> +
> +[LibraryClasses]
> +  BaseLib
> +  BaseMemoryLib
> +  RedfishContentCodingLib
> +  DebugLib
> +  HttpLib
> +  JsonLib
> +  MemoryAllocationLib
> +  PrintLib
> +  RedfishDebugLib
> +  ReportStatusCodeLib
> +  UefiBootServicesTableLib
> +  UefiDriverEntryPoint
> +  UefiLib
> +
> +[Protocols]
> +  gEdkIIRedfishHttpProtocolGuid             ## PRODUCED
> +  gEdkIIRedfishCredentialProtocolGuid       ## CONSUMES
> +  gEfiRestExProtocolGuid                    ## CONSUEMS
> +
> +[Pcd]
> +  gEfiRedfishPkgTokenSpaceGuid.PcdHttpGetRetry
> +  gEfiRedfishPkgTokenSpaceGuid.PcdHttpPutRetry
> +  gEfiRedfishPkgTokenSpaceGuid.PcdHttpPatchRetry
> +  gEfiRedfishPkgTokenSpaceGuid.PcdHttpPostRetry
> +  gEfiRedfishPkgTokenSpaceGuid.PcdHttpDeleteRetry
> +  gEfiRedfishPkgTokenSpaceGuid.PcdHttpRetryWaitInSecond
> +  gEfiRedfishPkgTokenSpaceGuid.PcdHttpCacheDisabled
> +  gEfiRedfishPkgTokenSpaceGuid.PcdRedfishServiceContentEncoding
> +
> +[Depex]
> +  TRUE
> diff --git a/RedfishPkg/RedfishHttpDxe/RedfishHttpData.h
> b/RedfishPkg/RedfishHttpDxe/RedfishHttpData.h
> new file mode 100644
> index 0000000000..6be610142e
> --- /dev/null
> +++ b/RedfishPkg/RedfishHttpDxe/RedfishHttpData.h
> @@ -0,0 +1,256 @@
> +/** @file
> +  Definitions of RedfishHttpData
> +
> +  Copyright (c) 2023-2024, NVIDIA CORPORATION & AFFILIATES. All rights
> reserved.
> +
> +  SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +#ifndef EDKII_REDFISH_HTTP_DATA_H_
> +#define EDKII_REDFISH_HTTP_DATA_H_
> +
> +#include "RedfishHttpDxe.h"
> +
> +#define REDFISH_HTTP_DRIVER_SIGNATURE   SIGNATURE_32 ('r', 'f', 'h', 'p')
> +#define REDFISH_HTTP_CACHE_SIGNATURE    SIGNATURE_32 ('r', 'f', 'c', 'h')
> +#define REDFISH_HTTP_SERVICE_SIGNATURE  SIGNATURE_32 ('r', 'f', 's', 'v')
> +#define REDFISH_HTTP_PAYLOAD_SIGNATURE  SIGNATURE_32 ('r', 'f', 'p', 'l')
> +#define REDFISH_HTTP_BASIC_AUTH_STR     "Basic "
> +
> +///
> +/// REDFISH_SERVICE_PRIVATE definition.
> +///
> +typedef struct {
> +  UINT32                  Signature;
> +  CHAR8                   *Host;
> +  CHAR8                   *HostName;
> +  CHAR8                   *BasicAuth;
> +  CHAR8                   *SessionToken;
> +  EFI_REST_EX_PROTOCOL    *RestEx;
> +} REDFISH_SERVICE_PRIVATE;
> +
> +///
> +/// REDFISH_PAYLOAD_PRIVATE definition.
> +///
> +typedef struct {
> +  UINT32                     Signature;
> +  REDFISH_SERVICE_PRIVATE    *Service;
> +  EDKII_JSON_VALUE           JsonValue;
> +} REDFISH_PAYLOAD_PRIVATE;
> +
> +///
> +/// Definition of REDFISH_HTTP_CACHE_DATA
> +///
> +typedef struct {
> +  UINT32              Signature;
> +  LIST_ENTRY          List;
> +  EFI_STRING          Uri;
> +  UINTN               HitCount;
> +  REDFISH_RESPONSE    *Response;
> +} REDFISH_HTTP_CACHE_DATA;
> +
> +#define REDFISH_HTTP_CACHE_FROM_LIST(a)  CR (a,
> REDFISH_HTTP_CACHE_DATA, List, REDFISH_HTTP_CACHE_SIGNATURE)
> +
> +///
> +/// Definition of REDFISH_HTTP_CACHE_LIST
> +///
> +typedef struct {
> +  LIST_ENTRY    Head;
> +  UINTN         Count;
> +  UINTN         Capacity;
> +} REDFISH_HTTP_CACHE_LIST;
> +
> +///
> +/// Definition of REDFISH_HTTP_RETRY_SETTING
> +///
> +typedef struct {
> +  UINT16    MaximumRetryGet;
> +  UINT16    MaximumRetryPut;
> +  UINT16    MaximumRetryPost;
> +  UINT16    MaximumRetryPatch;
> +  UINT16    MaximumRetryDelete;
> +  UINTN     RetryWait;
> +} REDFISH_HTTP_RETRY_SETTING;
> +
> +///
> +/// Definition of REDFISH_HTTP_CACHE_PRIVATE
> +///
> +typedef struct {
> +  UINT32                               Signature;
> +  EFI_HANDLE                           ImageHandle;
> +  BOOLEAN                              CacheDisabled;
> +  EFI_EVENT                            NotifyEvent;
> +  REDFISH_HTTP_CACHE_LIST              CacheList;
> +  EDKII_REDFISH_HTTP_PROTOCOL          Protocol;
> +  EDKII_REDFISH_CREDENTIAL_PROTOCOL    *CredentialProtocol;
> +  REDFISH_HTTP_RETRY_SETTING           RetrySetting;
> +} REDFISH_HTTP_CACHE_PRIVATE;
> +
> +#define REDFISH_HTTP_CACHE_PRIVATE_FROM_THIS(a)  CR (a,
> REDFISH_HTTP_CACHE_PRIVATE, Protocol,
> REDFISH_HTTP_DRIVER_SIGNATURE)
> +
> +/**
> +  Search on given ListHeader for given URI string.
> +
> +  @param[in]    ListHeader  Target list to search.
> +  @param[in]    Uri         Target URI to search.
> +
> +  @retval REDFISH_HTTP_CACHE_DATA   Target cache data is found.
> +  @retval NULL                      No cache data with given URI is found.
> +
> +**/
> +REDFISH_HTTP_CACHE_DATA *
> +FindHttpCacheData (
> +  IN  LIST_ENTRY  *ListHeader,
> +  IN  EFI_STRING  Uri
> +  );
> +
> +/**
> +  This function copy the data in SrcResponse to DstResponse.
> +
> +  @param[in]  SrcResponse      Source Response to copy.
> +  @param[out] DstResponse      Destination Response.
> +
> +  @retval     EFI_SUCCESS      Response is copied successfully.
> +  @retval     Others           Error occurs.
> +
> +**/
> +EFI_STATUS
> +CopyRedfishResponse (
> +  IN  REDFISH_RESPONSE  *SrcResponse,
> +  OUT REDFISH_RESPONSE  *DstResponse
> +  );
> +
> +/**
> +  Release all cache from list.
> +
> +  @param[in]    CacheList    The list to be released.
> +
> +  @retval EFI_SUCCESS             All cache data are released.
> +  @retval EFI_INVALID_PARAMETER   CacheList is NULL.
> +
> +**/
> +EFI_STATUS
> +ReleaseCacheList (
> +  IN  REDFISH_HTTP_CACHE_LIST  *CacheList
> +  );
> +
> +/**
> +  Add new cache by given URI and HTTP response to specify List.
> +
> +  @param[in]    List      Target cache list to add.
> +  @param[in]    Uri       The URI string matching to this cache data.
> +  @param[in]    Response  HTTP response.
> +
> +  @retval EFI_SUCCESS   Cache data is added.
> +  @retval Others        Fail to add cache data.
> +
> +**/
> +EFI_STATUS
> +AddHttpCacheData (
> +  IN  REDFISH_HTTP_CACHE_LIST  *List,
> +  IN  EFI_STRING               Uri,
> +  IN  REDFISH_RESPONSE         *Response
> +  );
> +
> +/**
> +  Delete a cache data by given cache instance.
> +
> +  @param[in]    List    Target cache list to be removed.
> +  @param[in]    Data    Pointer to the instance to be deleted.
> +
> +  @retval EFI_SUCCESS   Cache data is removed.
> +  @retval Others        Fail to remove cache data.
> +
> +**/
> +EFI_STATUS
> +DeleteHttpCacheData (
> +  IN  REDFISH_HTTP_CACHE_LIST  *List,
> +  IN  REDFISH_HTTP_CACHE_DATA  *Data
> +  );
> +
> +/**
> +  This function release Redfish Payload.
> +
> +  @param[in]  Payload         Pointer to payload instance.
> +
> +  @retval     EFI_SUCCESS     Payload is released.
> +  @retval     Others          Error occurs.
> +
> +**/
> +EFI_STATUS
> +ReleaseRedfishPayload (
> +  IN REDFISH_PAYLOAD_PRIVATE  *Payload
> +  );
> +
> +/**
> +  This function creat new payload. Server and JsonObj are
> +  copied to newly created payload.
> +
> +  @param[in]  Service          Pointer to Service instance.
> +  @param[in]  JsonObj          Pointer to JSON object.
> +
> +  @retval     REDFISH_PAYLOAD_PRIVATE  Newly created payload.
> +  @retval     NULL             Error occurs.
> +
> +**/
> +REDFISH_PAYLOAD_PRIVATE *
> +CreateRedfishPayload (
> +  IN REDFISH_SERVICE_PRIVATE  *Service,
> +  IN EDKII_JSON_VALUE         JsonValue
> +  );
> +
> +/**
> +  This function release Redfish Service.
> +
> +  @param[in]  Service         Pointer to service instance.
> +
> +  @retval     EFI_SUCCESS     Service is released.
> +  @retval     Others          Error occurs.
> +
> +**/
> +EFI_STATUS
> +ReleaseRedfishService (
> +  IN REDFISH_SERVICE_PRIVATE  *Service
> +  );
> +
> +/**
> +  This function creat new service. Host and HostName are copied to
> +  newly created service instance.
> +
> +  @param[in]  Host            Host string.
> +  @param[in]  HostName        Hostname string.
> +  @param[in]  BasicAuth       Basic Authorization string.
> +  @param[in]  SessionToken    Session token string.
> +  @param[in]  RestEx          Rest EX protocol instance.
> +
> +  @retval     REDFISH_PAYLOAD_PRIVATE  Newly created service.
> +  @retval     NULL             Error occurs.
> +
> +**/
> +REDFISH_SERVICE_PRIVATE *
> +CreateRedfishService (
> +  IN CHAR8                 *Host,
> +  IN CHAR8                 *HostName,
> +  IN CHAR8                 *BasicAuth OPTIONAL,
> +  IN CHAR8                 *SessionToken OPTIONAL,
> +  IN EFI_REST_EX_PROTOCOL  *RestEx
> +  );
> +
> +/**
> +  This function update session token in Redfish Service.
> +
> +  @param[in]  Service         Pointer to service instance.
> +  @param[in]  Token           Session token.
> +
> +  @retval     EFI_SUCCESS     Session token is updated.
> +  @retval     Others          Error occurs.
> +
> +**/
> +EFI_STATUS
> +UpdateSessionToken (
> +  IN REDFISH_SERVICE_PRIVATE  *Service,
> +  IN CHAR8                    *Token
> +  );
> +
> +#endif
> diff --git a/RedfishPkg/RedfishHttpDxe/RedfishHttpDxe.h
> b/RedfishPkg/RedfishHttpDxe/RedfishHttpDxe.h
> new file mode 100644
> index 0000000000..cf6ba9cb47
> --- /dev/null
> +++ b/RedfishPkg/RedfishHttpDxe/RedfishHttpDxe.h
> @@ -0,0 +1,44 @@
> +/** @file
> +  Definitions of RedfishHttpDxe
> +
> +  Copyright (c) 2023-2024, NVIDIA CORPORATION & AFFILIATES. All rights
> reserved.
> +
> +  SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +#ifndef EDKII_REDFISH_HTTP_DXE_H_
> +#define EDKII_REDFISH_HTTP_DXE_H_
> +
> +#include <Uefi.h>
> +#include <IndustryStandard/Http11.h>
> +
> +#include <Library/UefiLib.h>
> +#include <Library/BaseLib.h>
> +#include <Library/BaseMemoryLib.h>
> +#include <Library/RedfishContentCodingLib.h>
> +#include <Library/DebugLib.h>
> +#include <Library/HttpLib.h>
> +#include <Library/JsonLib.h>
> +#include <Library/UefiBootServicesTableLib.h>
> +#include <Library/MemoryAllocationLib.h>
> +#include <Library/RedfishDebugLib.h>
> +#include <Library/ReportStatusCodeLib.h>
> +#include <Library/PrintLib.h>
> +
> +#include <Protocol/Http.h>
> +#include <Protocol/EdkIIRedfishHttpProtocol.h>
> +#include <Protocol/EdkIIRedfishCredential.h>
> +#include <Protocol/RestEx.h>
> +
> +#define IS_EMPTY_STRING(a)  ((a) == NULL || (a)[0] == '\0')
> +#define REDFISH_HTTP_CACHE_LIST_SIZE      0x80
> +#define REDFISH_ERROR_MSG_MAX             128
> +#define REDFISH_DEBUG_STRING_LENGTH       200
> +#define REDFISH_HOST_NAME_MAX             64   // IPv6 maximum length (39)
> + "https://" (8) + port number (maximum 5)
> +#define REDFISH_HTTP_ERROR_REPORT         "Redfish HTTP %a failure(0x%x):
> %s"
> +#define REDFISH_HTTP_CACHE_DEBUG          DEBUG_MANAGEABILITY
> +#define REDFISH_HTTP_CACHE_DEBUG_DUMP     DEBUG_MANAGEABILITY
> +#define REDFISH_HTTP_CACHE_DEBUG_REQUEST  DEBUG_MANAGEABILITY
> +
> +#endif
> diff --git a/RedfishPkg/RedfishHttpDxe/RedfishHttpOperation.h
> b/RedfishPkg/RedfishHttpDxe/RedfishHttpOperation.h
> new file mode 100644
> index 0000000000..d2f7cf4c27
> --- /dev/null
> +++ b/RedfishPkg/RedfishHttpDxe/RedfishHttpOperation.h
> @@ -0,0 +1,76 @@
> +/** @file
> +  Definitions of RedfishHttpOperation
> +
> +  Copyright (c) 2024, NVIDIA CORPORATION & AFFILIATES. All rights
> reserved.
> +
> +  SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +#ifndef EDKII_REDFISH_HTTP_OPERATION_H_
> +#define EDKII_REDFISH_HTTP_OPERATION_H_
> +
> +#include "RedfishHttpDxe.h"
> +
> +#define REDFISH_CONTENT_LENGTH_SIZE              80
> +#define REDFISH_COMMON_HEADER_SIZE               5
> +#define REDFISH_HTTP_HEADER_ODATA_VERSION_STR    "OData-Version"
> +#define REDFISH_HTTP_HEADER_ODATA_VERSION_VALUE  "4.0"
> +#define REDFISH_HTTP_HEADER_USER_AGENT_VALUE     "edk2redfish"
> +#define REDFISH_HTTP_HEADER_CONNECTION_STR       "Connection"
> +#define REDFISH_HTTP_HEADER_CONNECTION_VALUE     "Keep-Alive"
> +#define REDFISH_HTTP_CONTENT_ENCODING_NONE       "None"
> +
> +/**
> +  This function free resources in Request. Request is no longer available
> +  after this function returns successfully.
> +
> +  @param[in]  Request      HTTP request to be released.
> +
> +  @retval     EFI_SUCCESS     Resrouce is released successfully.
> +  @retval     Others          Errors occur.
> +
> +**/
> +EFI_STATUS
> +ReleaseRedfishRequest (
> +  IN  REDFISH_REQUEST  *Request
> +  );
> +
> +/**
> +  This function free resources in given Response.
> +
> +  @param[in]  Response     HTTP response to be released.
> +
> +  @retval     EFI_SUCCESS     Resrouce is released successfully.
> +  @retval     Others          Errors occur.
> +
> +**/
> +EFI_STATUS
> +ReleaseRedfishResponse (
> +  IN  REDFISH_RESPONSE  *Response
> +  );
> +
> +/**
> +  This function send Redfish request to Redfish service by calling
> +  Rest Ex protocol.
> +
> +  @param[in]   Service       Pointer to Redfish service.
> +  @param[in]   Uri           Uri of Redfish service.
> +  @param[in]   Method        HTTP method.
> +  @param[in]   Request     Request data. This is optional.
> +  @param[out]  Response    Redfish response data.
> +
> +  @retval     EFI_SUCCESS     Request is sent and received successfully.
> +  @retval     Others          Errors occur.
> +
> +**/
> +EFI_STATUS
> +HttpSendReceive (
> +  IN  REDFISH_SERVICE   Service,
> +  IN  EFI_STRING        Uri,
> +  IN  EFI_HTTP_METHOD   Method,
> +  IN  REDFISH_REQUEST   *Request  OPTIONAL,
> +  OUT REDFISH_RESPONSE  *Response
> +  );
> +
> +#endif
> diff --git a/RedfishPkg/RedfishHttpDxe/RedfishHttpData.c
> b/RedfishPkg/RedfishHttpDxe/RedfishHttpData.c
> new file mode 100644
> index 0000000000..bf95e9f8d4
> --- /dev/null
> +++ b/RedfishPkg/RedfishHttpDxe/RedfishHttpData.c
> @@ -0,0 +1,667 @@
> +/** @file
> +  RedfishHttpData handles internal data to support Redfish HTTP protocol.
> +
> +  Copyright (c) 2023-2024, NVIDIA CORPORATION & AFFILIATES. All rights
> reserved.
> +
> +  SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +#include "RedfishHttpData.h"
> +#include "RedfishHttpOperation.h"
> +
> +/**
> +  This function update session token in Redfish Service.
> +
> +  @param[in]  Service         Pointer to service instance.
> +  @param[in]  Token           Session token.
> +
> +  @retval     EFI_SUCCESS     Session token is updated.
> +  @retval     Others          Error occurs.
> +
> +**/
> +EFI_STATUS
> +UpdateSessionToken (
> +  IN REDFISH_SERVICE_PRIVATE  *Service,
> +  IN CHAR8                    *Token
> +  )
> +{
> +  if ((Service == NULL) || IS_EMPTY_STRING (Token)) {
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  if (Service->SessionToken != NULL) {
> +    FreePool (Service->SessionToken);
> +  }
> +
> +  Service->SessionToken = AllocateCopyPool (AsciiStrSize (Token), Token);
> +  if (Service->SessionToken == NULL) {
> +    return EFI_OUT_OF_RESOURCES;
> +  }
> +
> +  return EFI_SUCCESS;
> +}
> +
> +/**
> +  This function release Redfish Service.
> +
> +  @param[in]  Service         Pointer to service instance.
> +
> +  @retval     EFI_SUCCESS     Service is released.
> +  @retval     Others          Error occurs.
> +
> +**/
> +EFI_STATUS
> +ReleaseRedfishService (
> +  IN REDFISH_SERVICE_PRIVATE  *Service
> +  )
> +{
> +  if (Service == NULL) {
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  if (Service->Host != NULL) {
> +    FreePool (Service->Host);
> +  }
> +
> +  if (Service->HostName != NULL) {
> +    FreePool (Service->HostName);
> +  }
> +
> +  if (Service->BasicAuth != NULL) {
> +    ZeroMem (Service->BasicAuth, AsciiStrSize (Service->BasicAuth));
> +    FreePool (Service->BasicAuth);
> +  }
> +
> +  if (Service->SessionToken != NULL) {
> +    ZeroMem (Service->SessionToken, AsciiStrSize (Service->SessionToken));
> +    FreePool (Service->SessionToken);
> +  }
> +
> +  FreePool (Service);
> +
> +  return EFI_SUCCESS;
> +}
> +
> +/**
> +  This function creat new service. Host and HostName are copied to
> +  newly created service instance.
> +
> +  @param[in]  Host            Host string.
> +  @param[in]  HostName        Hostname string.
> +  @param[in]  BasicAuth       Basic Authorization string.
> +  @param[in]  SessionToken    Session token string.
> +  @param[in]  RestEx          Rest EX protocol instance.
> +
> +  @retval     REDFISH_PAYLOAD_PRIVATE  Newly created service.
> +  @retval     NULL             Error occurs.
> +
> +**/
> +REDFISH_SERVICE_PRIVATE *
> +CreateRedfishService (
> +  IN CHAR8                 *Host,
> +  IN CHAR8                 *HostName,
> +  IN CHAR8                 *BasicAuth OPTIONAL,
> +  IN CHAR8                 *SessionToken OPTIONAL,
> +  IN EFI_REST_EX_PROTOCOL  *RestEx
> +  )
> +{
> +  REDFISH_SERVICE_PRIVATE  *NewService;
> +  UINTN                    AuthStrSize;
> +
> +  if (IS_EMPTY_STRING (Host) || IS_EMPTY_STRING (HostName) || (RestEx
> == NULL)) {
> +    return NULL;
> +  }
> +
> +  NewService = AllocateZeroPool (sizeof (REDFISH_SERVICE_PRIVATE));
> +  if (NewService == NULL) {
> +    return NULL;
> +  }
> +
> +  NewService->Signature = REDFISH_HTTP_SERVICE_SIGNATURE;
> +  NewService->Host      = AllocateCopyPool (AsciiStrSize (Host), Host);
> +  if (NewService->Host == NULL) {
> +    goto ON_ERROR;
> +  }
> +
> +  NewService->HostName = AllocateCopyPool (AsciiStrSize (HostName),
> HostName);
> +  if (NewService->HostName == NULL) {
> +    goto ON_ERROR;
> +  }
> +
> +  if (!IS_EMPTY_STRING (BasicAuth)) {
> +    AuthStrSize           = AsciiStrSize (BasicAuth) + AsciiStrLen
> (REDFISH_HTTP_BASIC_AUTH_STR);
> +    NewService->BasicAuth = AllocateZeroPool (AuthStrSize);
> +    if (NewService->BasicAuth == NULL) {
> +      goto ON_ERROR;
> +    }
> +
> +    AsciiSPrint (NewService->BasicAuth, AuthStrSize, "%a%a",
> REDFISH_HTTP_BASIC_AUTH_STR, BasicAuth);
> +  }
> +
> +  if (!IS_EMPTY_STRING (SessionToken)) {
> +    NewService->SessionToken = AllocateCopyPool (AsciiStrSize
> (SessionToken), SessionToken);
> +    if (NewService->SessionToken == NULL) {
> +      goto ON_ERROR;
> +    }
> +  }
> +
> +  NewService->RestEx = RestEx;
> +
> +  return NewService;
> +
> +ON_ERROR:
> +
> +  ReleaseRedfishService (NewService);
> +
> +  return NULL;
> +}
> +
> +/**
> +  This function release Redfish Payload.
> +
> +  @param[in]  Payload         Pointer to payload instance.
> +
> +  @retval     EFI_SUCCESS     Payload is released.
> +  @retval     Others          Error occurs.
> +
> +**/
> +EFI_STATUS
> +ReleaseRedfishPayload (
> +  IN REDFISH_PAYLOAD_PRIVATE  *Payload
> +  )
> +{
> +  if (Payload == NULL) {
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  if (Payload->Service != NULL) {
> +    ReleaseRedfishService (Payload->Service);
> +  }
> +
> +  if (Payload->JsonValue != NULL) {
> +    JsonValueFree (Payload->JsonValue);
> +  }
> +
> +  FreePool (Payload);
> +
> +  return EFI_SUCCESS;
> +}
> +
> +/**
> +  This function creat new payload. Server and JsonObj are
> +  copied to newly created payload.
> +
> +  @param[in]  Service          Pointer to Service instance.
> +  @param[in]  JsonValue        Pointer to JSON value.
> +
> +  @retval     REDFISH_PAYLOAD_PRIVATE  Newly created payload.
> +  @retval     NULL                     Error occurs.
> +
> +**/
> +REDFISH_PAYLOAD_PRIVATE *
> +CreateRedfishPayload (
> +  IN REDFISH_SERVICE_PRIVATE  *Service,
> +  IN EDKII_JSON_VALUE         JsonValue
> +  )
> +{
> +  REDFISH_PAYLOAD_PRIVATE  *NewPayload;
> +
> +  if ((Service == NULL) || (JsonValue == NULL)) {
> +    return NULL;
> +  }
> +
> +  NewPayload = AllocateZeroPool (sizeof (REDFISH_PAYLOAD_PRIVATE));
> +  if (NewPayload == NULL) {
> +    return NULL;
> +  }
> +
> +  NewPayload->Signature = REDFISH_HTTP_PAYLOAD_SIGNATURE;
> +  NewPayload->Service   = CreateRedfishService (Service->Host, Service-
> >HostName, Service->BasicAuth, Service->SessionToken, Service->RestEx);
> +  if (NewPayload->Service == NULL) {
> +    goto ON_ERROR;
> +  }
> +
> +  NewPayload->JsonValue = JsonValueClone (JsonValue);
> +  if (NewPayload->JsonValue == NULL) {
> +    goto ON_ERROR;
> +  }
> +
> +  return NewPayload;
> +
> +ON_ERROR:
> +
> +  ReleaseRedfishPayload (NewPayload);
> +
> +  return NULL;
> +}
> +
> +/**
> +  This function copy the data in SrcResponse to DstResponse.
> +
> +  @param[in]  SrcResponse      Source Response to copy.
> +  @param[out] DstResponse      Destination Response.
> +
> +  @retval     EFI_SUCCESS      Response is copied successfully.
> +  @retval     Others           Error occurs.
> +
> +**/
> +EFI_STATUS
> +CopyRedfishResponse (
> +  IN  REDFISH_RESPONSE  *SrcResponse,
> +  OUT REDFISH_RESPONSE  *DstResponse
> +  )
> +{
> +  REDFISH_PAYLOAD_PRIVATE  *Payload;
> +  UINTN                    Index;
> +
> +  if ((SrcResponse == NULL) || (DstResponse == NULL)) {
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  if (SrcResponse == DstResponse) {
> +    return EFI_SUCCESS;
> +  }
> +
> +  //
> +  // Status code
> +  //
> +  if (SrcResponse->StatusCode != NULL) {
> +    DstResponse->StatusCode = AllocateCopyPool (sizeof
> (EFI_HTTP_STATUS_CODE), SrcResponse->StatusCode);
> +    if (DstResponse->StatusCode == NULL) {
> +      goto ON_ERROR;
> +    }
> +  }
> +
> +  //
> +  // Header
> +  //
> +  if ((SrcResponse->HeaderCount > 0) && (SrcResponse->Headers != NULL)) {
> +    DstResponse->HeaderCount = 0;
> +    DstResponse->Headers     = AllocateZeroPool (sizeof (EFI_HTTP_HEADER) *
> SrcResponse->HeaderCount);
> +    if (DstResponse->Headers == NULL) {
> +      goto ON_ERROR;
> +    }
> +
> +    for (Index = 0; Index < SrcResponse->HeaderCount; Index++) {
> +      DstResponse->Headers[Index].FieldName = AllocateCopyPool (AsciiStrSize
> (SrcResponse->Headers[Index].FieldName), SrcResponse-
> >Headers[Index].FieldName);
> +      if (DstResponse->Headers[Index].FieldName == NULL) {
> +        goto ON_ERROR;
> +      }
> +
> +      DstResponse->Headers[Index].FieldValue = AllocateCopyPool (AsciiStrSize
> (SrcResponse->Headers[Index].FieldValue), SrcResponse-
> >Headers[Index].FieldValue);
> +      if (DstResponse->Headers[Index].FieldValue == NULL) {
> +        goto ON_ERROR;
> +      }
> +
> +      DstResponse->HeaderCount += 1;
> +    }
> +  }
> +
> +  //
> +  // Payload
> +  //
> +  if (SrcResponse->Payload != NULL) {
> +    Payload = (REDFISH_PAYLOAD_PRIVATE *)SrcResponse->Payload;
> +    if (Payload->Signature != REDFISH_HTTP_PAYLOAD_SIGNATURE) {
> +      DEBUG ((DEBUG_ERROR, "%a: signature check failure\n", __func__));
> +      goto ON_ERROR;
> +    }
> +
> +    DstResponse->Payload = CreateRedfishPayload (Payload->Service, Payload-
> >JsonValue);
> +    if (DstResponse->Payload  == NULL) {
> +      goto ON_ERROR;
> +    }
> +  }
> +
> +  return EFI_SUCCESS;
> +
> +ON_ERROR:
> +
> +  ReleaseRedfishResponse (DstResponse);
> +
> +  return EFI_OUT_OF_RESOURCES;
> +}
> +
> +/**
> +  This function clone input response and return to caller
> +
> +  @param[in]  Response      Response to clone.
> +
> +  @retval     REDFISH_RESPONSE *  Response is cloned.
> +  @retval     NULL                Errors occur.
> +
> +**/
> +REDFISH_RESPONSE *
> +CloneRedfishResponse (
> +  IN REDFISH_RESPONSE  *Response
> +  )
> +{
> +  EFI_STATUS        Status;
> +  REDFISH_RESPONSE  *NewResponse;
> +
> +  if (Response == NULL) {
> +    return NULL;
> +  }
> +
> +  NewResponse = AllocateZeroPool (sizeof (REDFISH_RESPONSE));
> +  if (NewResponse == NULL) {
> +    return NULL;
> +  }
> +
> +  Status = CopyRedfishResponse (Response, NewResponse);
> +  if (EFI_ERROR (Status)) {
> +    FreePool (NewResponse);
> +    return NULL;
> +  }
> +
> +  return NewResponse;
> +}
> +
> +/**
> +  Release REDFISH_HTTP_CACHE_DATA resource
> +
> +  @param[in]    Data    Pointer to REDFISH_HTTP_CACHE_DATA instance
> +
> +  @retval EFI_SUCCESS             REDFISH_HTTP_CACHE_DATA is released
> successfully.
> +  @retval EFI_INVALID_PARAMETER   Data is NULL
> +
> +**/
> +EFI_STATUS
> +ReleaseHttpCacheData (
> +  IN REDFISH_HTTP_CACHE_DATA  *Data
> +  )
> +{
> +  if (Data == NULL) {
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  if (Data->Uri != NULL) {
> +    FreePool (Data->Uri);
> +  }
> +
> +  if (Data->Response != NULL) {
> +    ReleaseRedfishResponse (Data->Response);
> +    FreePool (Data->Response);
> +  }
> +
> +  FreePool (Data);
> +
> +  return EFI_SUCCESS;
> +}
> +
> +/**
> +  Create new cache data.
> +
> +  @param[in]    Uri       The URI string matching to this cache data.
> +  @param[in]    Response  HTTP response.
> +
> +  @retval REDFISH_HTTP_CACHE_DATA *   Pointer to newly created cache
> data.
> +  @retval NULL                        No memory available.
> +
> +**/
> +REDFISH_HTTP_CACHE_DATA *
> +NewHttpCacheData (
> +  IN  EFI_STRING        Uri,
> +  IN  REDFISH_RESPONSE  *Response
> +  )
> +{
> +  REDFISH_HTTP_CACHE_DATA  *NewData;
> +  UINTN                    Size;
> +
> +  if (IS_EMPTY_STRING (Uri) || (Response == NULL)) {
> +    return NULL;
> +  }
> +
> +  NewData = AllocateZeroPool (sizeof (REDFISH_HTTP_CACHE_DATA));
> +  if (NewData == NULL) {
> +    return NULL;
> +  }
> +
> +  NewData->Signature = REDFISH_HTTP_CACHE_SIGNATURE;
> +  Size               = StrSize (Uri);
> +  NewData->Uri       = AllocateCopyPool (Size, Uri);
> +  if (NewData->Uri == NULL) {
> +    goto ON_ERROR;
> +  }
> +
> +  NewData->Response = Response;
> +  NewData->HitCount = 1;
> +
> +  return NewData;
> +
> +ON_ERROR:
> +
> +  if (NewData != NULL) {
> +    ReleaseHttpCacheData (NewData);
> +  }
> +
> +  return NULL;
> +}
> +
> +/**
> +  Search on given ListHeader for given URI string.
> +
> +  @param[in]    ListHeader  Target list to search.
> +  @param[in]    Uri         Target URI to search.
> +
> +  @retval REDFISH_HTTP_CACHE_DATA   Target cache data is found.
> +  @retval NULL                      No cache data with given URI is found.
> +
> +**/
> +REDFISH_HTTP_CACHE_DATA *
> +FindHttpCacheData (
> +  IN  LIST_ENTRY  *ListHeader,
> +  IN  EFI_STRING  Uri
> +  )
> +{
> +  LIST_ENTRY               *List;
> +  REDFISH_HTTP_CACHE_DATA  *Data;
> +
> +  if (IS_EMPTY_STRING (Uri)) {
> +    return NULL;
> +  }
> +
> +  if (IsListEmpty (ListHeader)) {
> +    return NULL;
> +  }
> +
> +  Data = NULL;
> +  List = GetFirstNode (ListHeader);
> +  while (!IsNull (ListHeader, List)) {
> +    Data = REDFISH_HTTP_CACHE_FROM_LIST (List);
> +
> +    if (StrCmp (Data->Uri, Uri) == 0) {
> +      return Data;
> +    }
> +
> +    List = GetNextNode (ListHeader, List);
> +  }
> +
> +  return NULL;
> +}
> +
> +/**
> +  Search on given ListHeader and return cache data with minimum hit count.
> +
> +  @param[in]    ListHeader  Target list to search.
> +
> +  @retval REDFISH_HTTP_CACHE_DATA   Target cache data is returned.
> +  @retval NULL                      No cache data is found.
> +
> +**/
> +REDFISH_HTTP_CACHE_DATA *
> +FindUnusedHttpCacheData (
> +  IN  LIST_ENTRY  *ListHeader
> +  )
> +{
> +  LIST_ENTRY               *List;
> +  REDFISH_HTTP_CACHE_DATA  *Data;
> +  REDFISH_HTTP_CACHE_DATA  *UnusedData;
> +  UINTN                    HitCount;
> +
> +  if (IsListEmpty (ListHeader)) {
> +    return NULL;
> +  }
> +
> +  Data       = NULL;
> +  UnusedData = NULL;
> +  HitCount   = 0;
> +
> +  List       = GetFirstNode (ListHeader);
> +  Data       = REDFISH_HTTP_CACHE_FROM_LIST (List);
> +  UnusedData = Data;
> +  HitCount   = Data->HitCount;
> +  List       = GetNextNode (ListHeader, List);
> +
> +  while (!IsNull (ListHeader, List)) {
> +    Data = REDFISH_HTTP_CACHE_FROM_LIST (List);
> +
> +    if (Data->HitCount < HitCount) {
> +      HitCount   = Data->HitCount;
> +      UnusedData = Data;
> +    }
> +
> +    List = GetNextNode (ListHeader, List);
> +  }
> +
> +  return UnusedData;
> +}
> +
> +/**
> +  Delete a cache data by given cache instance.
> +
> +  @param[in]    List    Target cache list to be removed.
> +  @param[in]    Data    Pointer to the instance to be deleted.
> +
> +  @retval EFI_SUCCESS   Cache data is removed.
> +  @retval Others        Fail to remove cache data.
> +
> +**/
> +EFI_STATUS
> +DeleteHttpCacheData (
> +  IN  REDFISH_HTTP_CACHE_LIST  *List,
> +  IN  REDFISH_HTTP_CACHE_DATA  *Data
> +  )
> +{
> +  if ((List == NULL) || (Data == NULL)) {
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  DEBUG ((REDFISH_HTTP_CACHE_DEBUG, "%a: delete: %s\n", __func__,
> Data->Uri));
> +
> +  RemoveEntryList (&Data->List);
> +  --List->Count;
> +
> +  return ReleaseHttpCacheData (Data);
> +}
> +
> +/**
> +  Add new cache by given URI and HTTP response to specify List.
> +
> +  @param[in]    List      Target cache list to add.
> +  @param[in]    Uri       The URI string matching to this cache data.
> +  @param[in]    Response  HTTP response.
> +
> +  @retval EFI_SUCCESS   Cache data is added.
> +  @retval Others        Fail to add cache data.
> +
> +**/
> +EFI_STATUS
> +AddHttpCacheData (
> +  IN  REDFISH_HTTP_CACHE_LIST  *List,
> +  IN  EFI_STRING               Uri,
> +  IN  REDFISH_RESPONSE         *Response
> +  )
> +{
> +  REDFISH_HTTP_CACHE_DATA  *NewData;
> +  REDFISH_HTTP_CACHE_DATA  *OldData;
> +  REDFISH_HTTP_CACHE_DATA  *UnusedData;
> +  REDFISH_RESPONSE         *NewResponse;
> +
> +  if ((List == NULL) || IS_EMPTY_STRING (Uri) || (Response == NULL)) {
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  //
> +  // If same cache data exist, replace it with latest one.
> +  //
> +  OldData = FindHttpCacheData (&List->Head, Uri);
> +  if (OldData != NULL) {
> +    DeleteHttpCacheData (List, OldData);
> +  }
> +
> +  //
> +  // Check capacity
> +  //
> +  if (List->Count >= List->Capacity) {
> +    DEBUG ((REDFISH_HTTP_CACHE_DEBUG, "%a: list is full and retire unused
> cache\n", __func__));
> +    UnusedData = FindUnusedHttpCacheData (&List->Head);
> +    if (UnusedData == NULL) {
> +      return EFI_OUT_OF_RESOURCES;
> +    }
> +
> +    DeleteHttpCacheData (List, UnusedData);
> +  }
> +
> +  //
> +  // Clone a local copy
> +  //
> +  NewResponse = CloneRedfishResponse (Response);
> +  if (NewResponse == NULL) {
> +    return EFI_OUT_OF_RESOURCES;
> +  }
> +
> +  NewData = NewHttpCacheData (Uri, NewResponse);
> +  if (NewData == NULL) {
> +    return EFI_OUT_OF_RESOURCES;
> +  }
> +
> +  InsertTailList (&List->Head, &NewData->List);
> +  ++List->Count;
> +
> +  DEBUG ((REDFISH_HTTP_CACHE_DEBUG, "%a: cache(%d/%d) %s\n",
> __func__, List->Count, List->Capacity, NewData->Uri));
> +
> +  return EFI_SUCCESS;
> +}
> +
> +/**
> +  Release all cache from list.
> +
> +  @param[in]    CacheList    The list to be released.
> +
> +  @retval EFI_SUCCESS             All cache data are released.
> +  @retval EFI_INVALID_PARAMETER   CacheList is NULL.
> +
> +**/
> +EFI_STATUS
> +ReleaseCacheList (
> +  IN  REDFISH_HTTP_CACHE_LIST  *CacheList
> +  )
> +{
> +  LIST_ENTRY               *List;
> +  LIST_ENTRY               *Next;
> +  REDFISH_HTTP_CACHE_DATA  *Data;
> +
> +  if (CacheList == NULL) {
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  if (IsListEmpty (&CacheList->Head)) {
> +    return EFI_SUCCESS;
> +  }
> +
> +  Data = NULL;
> +  Next = NULL;
> +  List = GetFirstNode (&CacheList->Head);
> +  while (!IsNull (&CacheList->Head, List)) {
> +    Data = REDFISH_HTTP_CACHE_FROM_LIST (List);
> +    Next = GetNextNode (&CacheList->Head, List);
> +
> +    DeleteHttpCacheData (CacheList, Data);
> +
> +    List = Next;
> +  }
> +
> +  return EFI_SUCCESS;
> +}
> diff --git a/RedfishPkg/RedfishHttpDxe/RedfishHttpDxe.c
> b/RedfishPkg/RedfishHttpDxe/RedfishHttpDxe.c
> new file mode 100644
> index 0000000000..39958d4865
> --- /dev/null
> +++ b/RedfishPkg/RedfishHttpDxe/RedfishHttpDxe.c
> @@ -0,0 +1,1344 @@
> +/** @file
> +  RedfishHttpDxe produces EdkIIRedfishHttpProtocol
> +  for EDK2 Redfish Feature driver to do HTTP operations.
> +
> +  Copyright (c) 2023-2024, NVIDIA CORPORATION & AFFILIATES. All rights
> reserved.
> +
> +  SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +#include "RedfishHttpDxe.h"
> +#include "RedfishHttpData.h"
> +#include "RedfishHttpOperation.h"
> +
> +REDFISH_HTTP_CACHE_PRIVATE  *mRedfishHttpCachePrivate = NULL;
> +
> +/**
> +  Debug output the cache list.
> +
> +  @param[in]    Msg            Debug message string.
> +  @param[in]    ErrorLevel     Output error level.
> +  @param[in]    CacheList      Target list to dump.
> +
> +  @retval EFI_SUCCESS             Debug dump finished.
> +  @retval EFI_INVALID_PARAMETER   HttpCacheList is NULL.
> +
> +**/
> +EFI_STATUS
> +DebugPrintHttpCacheList (
> +  IN  CONST CHAR8              *Msg,
> +  IN  UINTN                    ErrorLevel,
> +  IN  REDFISH_HTTP_CACHE_LIST  *CacheList
> +  )
> +{
> +  LIST_ENTRY               *List;
> +  REDFISH_HTTP_CACHE_DATA  *Data;
> +  UINTN                    Index;
> +
> +  if (CacheList == NULL) {
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  if (!IS_EMPTY_STRING (Msg)) {
> +    DEBUG ((ErrorLevel, "%a\n", Msg));
> +  }
> +
> +  if (IsListEmpty (&CacheList->Head)) {
> +    DEBUG ((ErrorLevel, "list is empty\n"));
> +    return EFI_NOT_FOUND;
> +  }
> +
> +  DEBUG ((ErrorLevel, "list count: %d capacity: %d\n", CacheList->Count,
> CacheList->Capacity));
> +  Data  = NULL;
> +  Index = 0;
> +  List  = GetFirstNode (&CacheList->Head);
> +  while (!IsNull (&CacheList->Head, List)) {
> +    Data = REDFISH_HTTP_CACHE_FROM_LIST (List);
> +
> +    DEBUG ((ErrorLevel, "%d) Uri: %s Hit: %d\n", ++Index, Data->Uri, Data-
> >HitCount));
> +
> +    List = GetNextNode (&CacheList->Head, List);
> +  }
> +
> +  return EFI_SUCCESS;
> +}
> +
> +/**
> +
> +  Check HTTP status code to see if we like to retry HTTP request or not.
> +
> +  @param[in]  StatusCode      HTTP status code.
> +
> +  @retval     BOOLEAN         Return true when we like to retry request.
> +                              Return false when we don't want to retry request.
> +
> +**/
> +BOOLEAN
> +RedfishRetryRequired (
> +  IN EFI_HTTP_STATUS_CODE  *StatusCode
> +  )
> +{
> +  if (StatusCode == NULL) {
> +    return TRUE;
> +  }
> +
> +  if ((*StatusCode == HTTP_STATUS_500_INTERNAL_SERVER_ERROR) ||
> +      (*StatusCode == HTTP_STATUS_UNSUPPORTED_STATUS))
> +  {
> +    return TRUE;
> +  }
> +
> +  return FALSE;
> +}
> +
> +/**
> +
> +  Convert Unicode string to ASCII string. It's call responsibility to release
> returned buffer.
> +
> +  @param[in]  UnicodeStr      Unicode string to convert.
> +
> +  @retval     CHAR8 *         ASCII string returned.
> +  @retval     NULL            Errors occur.
> +
> +**/
> +CHAR8 *
> +StringUnicodeToAscii (
> +  IN EFI_STRING  UnicodeStr
> +  )
> +{
> +  CHAR8       *AsciiStr;
> +  UINTN       AsciiStrSize;
> +  EFI_STATUS  Status;
> +
> +  if (IS_EMPTY_STRING (UnicodeStr)) {
> +    return NULL;
> +  }
> +
> +  AsciiStrSize = StrLen (UnicodeStr) + 1;
> +  AsciiStr     = AllocateZeroPool (AsciiStrSize);
> +  if (AsciiStr == NULL) {
> +    return NULL;
> +  }
> +
> +  Status = UnicodeStrToAsciiStrS (UnicodeStr, AsciiStr, AsciiStrSize);
> +  if (EFI_ERROR (Status)) {
> +    DEBUG ((DEBUG_ERROR, "UnicodeStrToAsciiStrS failed: %r\n", Status));
> +    FreePool (AsciiStr);
> +    return NULL;
> +  }
> +
> +  return AsciiStr;
> +}
> +
> +/**
> +  Return HTTP method in ASCII string. Caller does not need
> +  to free returned string buffer.
> +
> +  @param[in]  Method         HTTP method.
> +
> +  @retval CHAR8 *   Method in string.
> +**/
> +CHAR8 *
> +HttpMethodToString (
> +  IN  EFI_HTTP_METHOD  Method
> +  )
> +{
> +  switch (Method) {
> +    case HttpMethodGet:
> +      return HTTP_METHOD_GET;
> +      break;
> +    case HttpMethodPost:
> +      return HTTP_METHOD_POST;
> +      break;
> +    case HttpMethodPatch:
> +      return HTTP_METHOD_PATCH;
> +      break;
> +    case HttpMethodPut:
> +      return HTTP_METHOD_PUT;
> +      break;
> +    case HttpMethodDelete:
> +      return HTTP_METHOD_DELETE;
> +      break;
> +    default:
> +      break;
> +  }
> +
> +  return "Unknown";
> +}
> +
> +/**
> +  Report HTTP communication error via report status code.
> +
> +  @param[in]  Method         HTTP method.
> +  @param[in]  Uri            The URI which has failure.
> +  @param[in]  HttpStatusCode HTTP status code.
> +
> +**/
> +VOID
> +ReportHttpError (
> +  IN  EFI_HTTP_METHOD       Method,
> +  IN  EFI_STRING            Uri,
> +  IN  EFI_HTTP_STATUS_CODE  *HttpStatusCode  OPTIONAL
> +  )
> +{
> +  CHAR8  ErrorMsg[REDFISH_ERROR_MSG_MAX];
> +
> +  if (IS_EMPTY_STRING (Uri)) {
> +    DEBUG ((DEBUG_ERROR, "%a: no URI to report error status\n",
> __func__));
> +    return;
> +  }
> +
> +  //
> +  // Report failure of URI and HTTP status code.
> +  //
> +  AsciiSPrint (ErrorMsg, sizeof (ErrorMsg), REDFISH_HTTP_ERROR_REPORT,
> HttpMethodToString (Method), (HttpStatusCode == NULL ?
> HTTP_STATUS_UNSUPPORTED_STATUS : *HttpStatusCode), Uri);
> +  DEBUG ((DEBUG_ERROR, "%a\n", ErrorMsg));
> +  //
> +  // TODO:
> +  // Below PI status code is approved by PIWG and wait for specification
> published.
> +  // We will uncomment below report status code after PI status code get
> published.
> +  // REF: https://bugzilla.tianocore.org/show_bug.cgi?id=4483
> +  //
> +  // REPORT_STATUS_CODE_WITH_EXTENDED_DATA (
> +  //  EFI_ERROR_CODE | EFI_ERROR_MAJOR,
> +  //  EFI_COMPUTING_UNIT_MANAGEABILITY |
> EFI_MANAGEABILITY_EC_REDFISH_COMMUNICATION_ERROR,
> +  //  ErrorMsg,
> +  //  AsciiStrSize (ErrorMsg)
> +  //  );
> +}
> +
> +/**
> +  This function create Redfish service. It's caller's responsibility to free
> returned
> +  Redfish service by calling FreeService ().
> +
> +  @param[in]  This                       Pointer to EDKII_REDFISH_HTTP_PROTOCOL
> instance.
> +  @param[in]  RedfishConfigServiceInfo   Redfish config service information.
> +
> +  @retval     REDFISH_SERVICE  Redfish service is created.
> +  @retval     NULL             Errors occur.
> +
> +**/
> +REDFISH_SERVICE
> +EFIAPI
> +RedfishCreateRedfishService (
> +  IN  EDKII_REDFISH_HTTP_PROTOCOL         *This,
> +  IN  REDFISH_CONFIG_SERVICE_INFORMATION  *RedfishConfigServiceInfo
> +  )
> +{
> +  EFI_STATUS                  Status;
> +  REDFISH_HTTP_CACHE_PRIVATE  *Private;
> +  REDFISH_SERVICE_PRIVATE     *NewService;
> +  CHAR8                       *AsciiLocation;
> +  CHAR8                       *Host;
> +  CHAR8                       *BasicAuthString;
> +  UINTN                       BasicAuthStrSize;
> +  CHAR8                       *EncodedAuthString;
> +  UINTN                       EncodedAuthStrSize;
> +  EDKII_REDFISH_AUTH_METHOD   AuthMethod;
> +  CHAR8                       *Username;
> +  CHAR8                       *Password;
> +  UINTN                       UsernameSize;
> +  UINTN                       PasswordSize;
> +  EFI_REST_EX_PROTOCOL        *RestEx;
> +
> +  if ((This == NULL) || (RedfishConfigServiceInfo == NULL)) {
> +    return NULL;
> +  }
> +
> +  DEBUG ((REDFISH_HTTP_CACHE_DEBUG, "%a: service location: %s\n",
> __func__, RedfishConfigServiceInfo->RedfishServiceLocation));
> +
> +  Private            = REDFISH_HTTP_CACHE_PRIVATE_FROM_THIS (This);
> +  BasicAuthString    = NULL;
> +  EncodedAuthString  = NULL;
> +  Username           = NULL;
> +  Password           = NULL;
> +  NewService         = NULL;
> +  AsciiLocation      = NULL;
> +  Host               = NULL;
> +  BasicAuthStrSize   = 0;
> +  EncodedAuthStrSize = 0;
> +  UsernameSize       = 0;
> +  PasswordSize       = 0;
> +
> +  //
> +  // Build host and host name from service location
> +  //
> +  if (!IS_EMPTY_STRING (RedfishConfigServiceInfo->RedfishServiceLocation))
> {
> +    AsciiLocation = StringUnicodeToAscii (RedfishConfigServiceInfo-
> >RedfishServiceLocation);
> +    if (AsciiLocation == NULL) {
> +      goto ON_RELEASE;
> +    }
> +
> +    Host = AllocateZeroPool (REDFISH_HOST_NAME_MAX);
> +    if (AsciiLocation == NULL) {
> +      goto ON_RELEASE;
> +    }
> +
> +    if (RedfishConfigServiceInfo->RedfishServiceUseHttps) {
> +      AsciiSPrint (Host, REDFISH_HOST_NAME_MAX, "https://%a",
> AsciiLocation);
> +    } else {
> +      AsciiSPrint (Host, REDFISH_HOST_NAME_MAX, "http://%a",
> AsciiLocation);
> +    }
> +
> +    DEBUG ((REDFISH_HTTP_CACHE_DEBUG, "%a: Host: %a\n", __func__,
> Host));
> +  }
> +
> +  //
> +  // Find Rest Ex protocol
> +  //
> +  if (RedfishConfigServiceInfo->RedfishServiceRestExHandle != NULL) {
> +    Status = gBS->HandleProtocol (
> +                    RedfishConfigServiceInfo->RedfishServiceRestExHandle,
> +                    &gEfiRestExProtocolGuid,
> +                    (VOID **)&RestEx
> +                    );
> +  } else {
> +    DEBUG ((DEBUG_ERROR, "%a: Rest Ex protocol is not available\n",
> __func__));
> +    goto ON_RELEASE;
> +  }
> +
> +  //
> +  // Get credential
> +  //
> +  if (Private->CredentialProtocol == NULL) {
> +    //
> +    // No credential available on this system.
> +    //
> +    DEBUG ((DEBUG_WARN, "%a: no credential protocol available\n",
> __func__));
> +  } else {
> +    Status = Private->CredentialProtocol->GetAuthInfo (
> +                                            Private->CredentialProtocol,
> +                                            &AuthMethod,
> +                                            &Username,
> +                                            &Password
> +                                            );
> +    if (EFI_ERROR (Status) || IS_EMPTY_STRING (Username) ||
> IS_EMPTY_STRING (Password)) {
> +      DEBUG ((DEBUG_ERROR, "%a: cannot get authentication information:
> %r\n", __func__, Status));
> +      goto ON_RELEASE;
> +    } else {
> +      DEBUG ((REDFISH_HTTP_CACHE_DEBUG, "%a: Auth method: 0x%x
> username: %a password: %a\n", __func__, AuthMethod, Username,
> Password));
> +
> +      //
> +      // Perform base64 encoding (RFC 7617)
> +      //
> +      UsernameSize     = AsciiStrSize (Username);
> +      PasswordSize     = AsciiStrSize (Password);
> +      BasicAuthStrSize =  UsernameSize + PasswordSize;  // one byte taken from
> null-terminator for ':'
> +      BasicAuthString  = AllocateZeroPool (BasicAuthStrSize);
> +      if (BasicAuthString == NULL) {
> +        goto ON_RELEASE;
> +      }
> +
> +      AsciiSPrint (
> +        BasicAuthString,
> +        BasicAuthStrSize,
> +        "%a:%a",
> +        Username,
> +        Password
> +        );
> +
> +      Status = Base64Encode (
> +                 (CONST UINT8 *)BasicAuthString,
> +                 BasicAuthStrSize,
> +                 EncodedAuthString,
> +                 &EncodedAuthStrSize
> +                 );
> +      if ((Status == EFI_BUFFER_TOO_SMALL) && (EncodedAuthStrSize > 0)) {
> +        EncodedAuthString = AllocateZeroPool (EncodedAuthStrSize);
> +        if (EncodedAuthString == NULL) {
> +          goto ON_RELEASE;
> +        }
> +
> +        Status = Base64Encode (
> +                   (CONST UINT8 *)BasicAuthString,
> +                   BasicAuthStrSize,
> +                   EncodedAuthString,
> +                   &EncodedAuthStrSize
> +                   );
> +        if (EFI_ERROR (Status)) {
> +          DEBUG ((DEBUG_ERROR, "%a: Base64Encode failure: %r\n", __func__,
> Status));
> +        }
> +
> +        DEBUG ((REDFISH_HTTP_CACHE_DEBUG, "%a: Basic authorization:
> %a\n", __func__, EncodedAuthString));
> +      } else {
> +        DEBUG ((DEBUG_ERROR, "%a: Base64Encode failure: %r\n", __func__,
> Status));
> +        goto ON_RELEASE;
> +      }
> +    }
> +  }
> +
> +  NewService = CreateRedfishService (Host, AsciiLocation,
> EncodedAuthString, NULL, RestEx);
> +  if (NewService == NULL) {
> +    DEBUG ((DEBUG_ERROR, "%a: CreateRedfishService\n", __func__));
> +  }
> +
> +ON_RELEASE:
> +
> +  if (BasicAuthString != NULL) {
> +    ZeroMem (BasicAuthString, BasicAuthStrSize);
> +    FreePool (BasicAuthString);
> +  }
> +
> +  if (EncodedAuthString != NULL) {
> +    ZeroMem (BasicAuthString, EncodedAuthStrSize);
> +    FreePool (EncodedAuthString);
> +  }
> +
> +  if (Username != NULL) {
> +    ZeroMem (Username, UsernameSize);
> +    FreePool (Username);
> +  }
> +
> +  if (Password != NULL) {
> +    ZeroMem (Password, PasswordSize);
> +    FreePool (Password);
> +  }
> +
> +  if (AsciiLocation != NULL) {
> +    FreePool (AsciiLocation);
> +  }
> +
> +  if (Host != NULL) {
> +    FreePool (Host);
> +  }
> +
> +  return NewService;
> +}
> +
> +/**
> +  This function free resources in Redfish service. RedfishService is no longer
> available
> +  after this function returns successfully.
> +
> +  @param[in]  This            Pointer to EDKII_REDFISH_HTTP_PROTOCOL
> instance.
> +  @param[in]  RedfishService  Pointer to Redfish service to be released.
> +
> +  @retval     EFI_SUCCESS     Resrouce is released successfully.
> +  @retval     Others          Errors occur.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +RedfishFreeRedfishService (
> +  IN  EDKII_REDFISH_HTTP_PROTOCOL  *This,
> +  IN  REDFISH_SERVICE              RedfishService
> +  )
> +{
> +  REDFISH_SERVICE_PRIVATE  *Service;
> +
> +  if ((This == NULL) || (RedfishService == NULL)) {
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  Service = (REDFISH_SERVICE_PRIVATE *)RedfishService;
> +  if (Service->Signature != REDFISH_HTTP_SERVICE_SIGNATURE) {
> +    DEBUG ((DEBUG_ERROR, "%a: signature check failure\n", __func__));
> +  }
> +
> +  return ReleaseRedfishService (Service);
> +}
> +
> +/**
> +  This function returns JSON value in given RedfishPayload. Returned JSON
> value
> +  is a reference to the JSON value in RedfishPayload. Any modification to
> returned
> +  JSON value will change JSON value in RedfishPayload.
> +
> +  @param[in]  This            Pointer to EDKII_REDFISH_HTTP_PROTOCOL
> instance.
> +  @param[in]  RedfishPayload  Pointer to Redfish payload.
> +
> +  @retval     EDKII_JSON_VALUE   JSON value is returned.
> +  @retval     NULL               Errors occur.
> +
> +**/
> +EDKII_JSON_VALUE
> +EFIAPI
> +RedfishJsonInRedfishPayload (
> +  IN  EDKII_REDFISH_HTTP_PROTOCOL  *This,
> +  IN  REDFISH_PAYLOAD              RedfishPayload
> +  )
> +{
> +  REDFISH_PAYLOAD_PRIVATE  *Payload;
> +
> +  if ((This == NULL) || (RedfishPayload == NULL)) {
> +    return NULL;
> +  }
> +
> +  Payload = (REDFISH_PAYLOAD_PRIVATE *)RedfishPayload;
> +  if (Payload->Signature != REDFISH_HTTP_PAYLOAD_SIGNATURE) {
> +    DEBUG ((DEBUG_ERROR, "%a: signature check failure\n", __func__));
> +  }
> +
> +  return Payload->JsonValue;
> +}
> +
> +/**
> +  Perform HTTP GET to Get redfish resource from given resource URI with
> +  cache mechanism supported. It's caller's responsibility to free Response
> +  by calling FreeResponse ().
> +
> +  @param[in]  This          Pointer to EDKII_REDFISH_HTTP_PROTOCOL instance.
> +  @param[in]  Service       Redfish service instance to perform HTTP GET.
> +  @param[in]  Uri           Target resource URI.
> +  @param[in]  Request       Additional request context. This is optional.
> +  @param[out] Response      HTTP response from redfish service.
> +  @param[in]  UseCache      If it is TRUE, this function will search for
> +                            cache first. If it is FALSE, this function
> +                            will query Redfish URI directly.
> +
> +  @retval     EFI_SUCCESS     Resrouce is returned successfully.
> +  @retval     Others          Errors occur.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +RedfishGetResource (
> +  IN  EDKII_REDFISH_HTTP_PROTOCOL  *This,
> +  IN  REDFISH_SERVICE              Service,
> +  IN  EFI_STRING                   Uri,
> +  IN  REDFISH_REQUEST              *Request OPTIONAL,
> +  OUT REDFISH_RESPONSE             *Response,
> +  IN  BOOLEAN                      UseCache
> +  )
> +{
> +  EFI_STATUS                  Status;
> +  REDFISH_HTTP_CACHE_DATA     *CacheData;
> +  UINTN                       RetryCount;
> +  REDFISH_HTTP_CACHE_PRIVATE  *Private;
> +
> +  if ((This == NULL) || (Service == NULL) || (Response == NULL) ||
> IS_EMPTY_STRING (Uri)) {
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  DEBUG ((REDFISH_HTTP_CACHE_DEBUG, "%a: Get URI: %s cache: %a\n",
> __func__, Uri, (UseCache ? "true" : "false")));
> +
> +  Private    = REDFISH_HTTP_CACHE_PRIVATE_FROM_THIS (This);
> +  CacheData  = NULL;
> +  RetryCount = 0;
> +  ZeroMem (Response, sizeof (REDFISH_RESPONSE));
> +
> +  if (Private->CacheDisabled) {
> +    UseCache = FALSE;
> +    DEBUG ((REDFISH_HTTP_CACHE_DEBUG, "%a: cache is disabled by
> PCD!\n", __func__));
> +  }
> +
> +  //
> +  // Search for cache list.
> +  //
> +  if (UseCache) {
> +    CacheData = FindHttpCacheData (&Private->CacheList.Head, Uri);
> +    if (CacheData != NULL) {
> +      DEBUG ((REDFISH_HTTP_CACHE_DEBUG_REQUEST, "%a: cache hit!
> %s\n", __func__, Uri));
> +
> +      //
> +      // Copy cached response to caller's buffer.
> +      //
> +      Status               = CopyRedfishResponse (CacheData->Response, Response);
> +      CacheData->HitCount += 1;
> +      return Status;
> +    }
> +  }
> +
> +  //
> +  // Get resource from redfish service.
> +  //
> +  do {
> +    RetryCount += 1;
> +    Status      = HttpSendReceive (
> +                    Service,
> +                    Uri,
> +                    HttpMethodGet,
> +                    Request,
> +                    Response
> +                    );
> +    DEBUG ((REDFISH_HTTP_CACHE_DEBUG_REQUEST, "%a: HTTP request:
> %s :%r\n", __func__, Uri, Status));
> +    if (!EFI_ERROR (Status) || (RetryCount >= Private-
> >RetrySetting.MaximumRetryGet)) {
> +      break;
> +    }
> +
> +    //
> +    // Retry when BMC is not ready.
> +    //
> +    if ((Response->StatusCode != NULL)) {
> +      DEBUG_CODE (
> +        DumpRedfishResponse (NULL, DEBUG_ERROR, Response);
> +        );
> +
> +      if (!RedfishRetryRequired (Response->StatusCode)) {
> +        break;
> +      }
> +
> +      //
> +      // Release response for next round of request.
> +      //
> +      This->FreeResponse (This, Response);
> +    }
> +
> +    DEBUG ((DEBUG_WARN, "%a: RedfishGetByUriEx failed, retry (%d/%d)\n",
> __func__, RetryCount, Private->RetrySetting.MaximumRetryGet));
> +    if (Private->RetrySetting.RetryWait > 0) {
> +      gBS->Stall (Private->RetrySetting.RetryWait);
> +    }
> +  } while (TRUE);
> +
> +  if (EFI_ERROR (Status)) {
> +    DEBUG_CODE (
> +      DumpRedfishResponse (NULL, DEBUG_ERROR, Response);
> +      );
> +    //
> +    // Report status code for Redfish failure
> +    //
> +    ReportHttpError (HttpMethodGet, Uri, Response->StatusCode);
> +    DEBUG ((DEBUG_ERROR, "%a: get %s failed (%d/%d): %r\n", __func__, Uri,
> RetryCount, Private->RetrySetting.MaximumRetryGet, Status));
> +    goto ON_RELEASE;
> +  }
> +
> +  if (!Private->CacheDisabled) {
> +    //
> +    // Keep response in cache list
> +    //
> +    Status = AddHttpCacheData (&Private->CacheList, Uri, Response);
> +    if (EFI_ERROR (Status)) {
> +      DEBUG ((DEBUG_ERROR, "%a: failed to cache %s: %r\n", __func__, Uri,
> Status));
> +      goto ON_RELEASE;
> +    }
> +
> +    DEBUG_CODE (
> +      DebugPrintHttpCacheList (__func__,
> REDFISH_HTTP_CACHE_DEBUG_DUMP, &Private->CacheList);
> +      );
> +  }
> +
> +ON_RELEASE:
> +
> +  return Status;
> +}
> +
> +/**
> +  This function free resources in Request. Request is no longer available
> +  after this function returns successfully.
> +
> +  @param[in]  This         Pointer to EDKII_REDFISH_HTTP_PROTOCOL instance.
> +  @param[in]  Request      HTTP request to be released.
> +
> +  @retval     EFI_SUCCESS     Resrouce is released successfully.
> +  @retval     Others          Errors occur.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +RedfishFreeRequest (
> +  IN  EDKII_REDFISH_HTTP_PROTOCOL  *This,
> +  IN  REDFISH_REQUEST              *Request
> +  )
> +{
> +  if ((This == NULL) || (Request == NULL)) {
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  DEBUG ((REDFISH_HTTP_CACHE_DEBUG, "%a: entry\n", __func__));
> +
> +  return ReleaseRedfishRequest (Request);
> +}
> +
> +/**
> +  This function free resources in given Response.
> +
> +  @param[in]  This         Pointer to EDKII_REDFISH_HTTP_PROTOCOL instance.
> +  @param[in]  Response     HTTP response to be released.
> +
> +  @retval     EFI_SUCCESS     Resrouce is released successfully.
> +  @retval     Others          Errors occur.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +RedfishFreeResponse (
> +  IN  EDKII_REDFISH_HTTP_PROTOCOL  *This,
> +  IN  REDFISH_RESPONSE             *Response
> +  )
> +{
> +  if ((This == NULL) || (Response == NULL)) {
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  DEBUG ((REDFISH_HTTP_CACHE_DEBUG, "%a: entry\n", __func__));
> +
> +  return ReleaseRedfishResponse (Response);
> +}
> +
> +/**
> +  This function expire the cached response of given URI.
> +
> +  @param[in]  This         Pointer to EDKII_REDFISH_HTTP_PROTOCOL instance.
> +  @param[in]  Uri          Target response of URI.
> +
> +  @retval     EFI_SUCCESS     Target response is expired successfully.
> +  @retval     Others          Errors occur.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +RedfishExpireResponse (
> +  IN  EDKII_REDFISH_HTTP_PROTOCOL  *This,
> +  IN  EFI_STRING                   Uri
> +  )
> +{
> +  REDFISH_HTTP_CACHE_PRIVATE  *Private;
> +  REDFISH_HTTP_CACHE_DATA     *CacheData;
> +
> +  if ((This == NULL) || IS_EMPTY_STRING (Uri)) {
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  DEBUG ((REDFISH_HTTP_CACHE_DEBUG, "%a: expire URI: %s\n", __func__,
> Uri));
> +
> +  Private = REDFISH_HTTP_CACHE_PRIVATE_FROM_THIS (This);
> +
> +  CacheData = FindHttpCacheData (&Private->CacheList.Head, Uri);
> +  if (CacheData == NULL) {
> +    return EFI_NOT_FOUND;
> +  }
> +
> +  return DeleteHttpCacheData (&Private->CacheList, CacheData);
> +}
> +
> +/**
> +  Perform HTTP PATCH to send redfish resource to given resource URI.
> +  It's caller's responsibility to free Response by calling FreeResponse ().
> +
> +  @param[in]  This          Pointer to EDKII_REDFISH_HTTP_PROTOCOL instance.
> +  @param[in]  Service       Redfish service instance to perform HTTP PATCH.
> +  @param[in]  Uri           Target resource URI.
> +  @param[in]  Content       Data to patch.
> +  @param[in]  ContentSize   Size of the Content to be send to Redfish service.
> +                            This is optional. When ContentSize is 0, ContentSize
> +                            is the size of Content.
> +  @param[in]  ContentType   Type of the Content to be send to Redfish
> service.
> +                            This is optional. When ContentType is NULL, content
> +                            type HTTP_CONTENT_TYPE_APP_JSON will be used.
> +  @param[out] Response      HTTP response from redfish service.
> +
> +  @retval     EFI_SUCCESS     Resrouce is returned successfully.
> +  @retval     Others          Errors occur.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +RedfishPatchResource (
> +  IN  EDKII_REDFISH_HTTP_PROTOCOL  *This,
> +  IN  REDFISH_SERVICE              Service,
> +  IN  EFI_STRING                   Uri,
> +  IN  CHAR8                        *Content,
> +  IN  UINTN                        ContentSize OPTIONAL,
> +  IN  CHAR8                        *ContentType OPTIONAL,
> +  OUT REDFISH_RESPONSE             *Response
> +  )
> +{
> +  EFI_STATUS                  Status;
> +  UINTN                       RetryCount;
> +  REDFISH_REQUEST             Request;
> +  REDFISH_HTTP_CACHE_PRIVATE  *Private;
> +
> +  if ((This == NULL) || (Service == NULL) || (Response == NULL) ||
> IS_EMPTY_STRING (Uri) || IS_EMPTY_STRING (Content)) {
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  DEBUG ((REDFISH_HTTP_CACHE_DEBUG, "%a: Patch URI: %s\n", __func__,
> Uri));
> +
> +  Private    = REDFISH_HTTP_CACHE_PRIVATE_FROM_THIS (This);
> +  RetryCount = 0;
> +  ZeroMem (Response, sizeof (REDFISH_RESPONSE));
> +  ZeroMem (&Request, sizeof (REDFISH_REQUEST));
> +
> +  Request.Content       = Content;
> +  Request.ContentLength = ContentSize;
> +  Request.ContentType   = ContentType;
> +
> +  //
> +  // Patch resource to redfish service.
> +  //
> +  do {
> +    RetryCount += 1;
> +    Status      = HttpSendReceive (
> +                    Service,
> +                    Uri,
> +                    HttpMethodPatch,
> +                    &Request,
> +                    Response
> +                    );
> +    DEBUG ((REDFISH_HTTP_CACHE_DEBUG_REQUEST, "%a: HTTP request:
> %s :%r\n", __func__, Uri, Status));
> +    if (!EFI_ERROR (Status) || (RetryCount >= Private-
> >RetrySetting.MaximumRetryPatch)) {
> +      break;
> +    }
> +
> +    //
> +    // Retry when BMC is not ready.
> +    //
> +    if ((Response->StatusCode != NULL)) {
> +      DEBUG_CODE (
> +        DumpRedfishResponse (NULL, DEBUG_ERROR, Response);
> +        );
> +
> +      if (!RedfishRetryRequired (Response->StatusCode)) {
> +        break;
> +      }
> +
> +      //
> +      // Release response for next round of request.
> +      //
> +      This->FreeResponse (This, Response);
> +    }
> +
> +    DEBUG ((DEBUG_WARN, "%a: RedfishPatchToUriEx failed, retry
> (%d/%d)\n", __func__, RetryCount, Private-
> >RetrySetting.MaximumRetryPatch));
> +    if (Private->RetrySetting.RetryWait > 0) {
> +      gBS->Stall (Private->RetrySetting.RetryWait);
> +    }
> +  } while (TRUE);
> +
> +  //
> +  // Redfish resource is updated. Automatically expire the cached response
> +  // so application can directly get resource from Redfish service again.
> +  //
> +  DEBUG ((REDFISH_HTTP_CACHE_DEBUG, "%a: Resource is updated, expire
> URI: %s\n", __func__, Uri));
> +  RedfishExpireResponse (This, Uri);
> +
> +  if (EFI_ERROR (Status)) {
> +    DEBUG_CODE (
> +      DumpRedfishResponse (NULL, DEBUG_ERROR, Response);
> +      );
> +    //
> +    // Report status code for Redfish failure
> +    //
> +    ReportHttpError (HttpMethodPatch, Uri, Response->StatusCode);
> +    DEBUG ((DEBUG_ERROR, "%a: patch %s failed (%d/%d): %r\n", __func__,
> Uri, RetryCount, Private->RetrySetting.MaximumRetryPatch, Status));
> +    goto ON_RELEASE;
> +  }
> +
> +ON_RELEASE:
> +
> +  return Status;
> +}
> +
> +/**
> +  Perform HTTP PUT to send redfish resource to given resource URI.
> +  It's caller's responsibility to free Response by calling FreeResponse ().
> +
> +  @param[in]  This          Pointer to EDKII_REDFISH_HTTP_PROTOCOL instance.
> +  @param[in]  Service       Redfish service instance to perform HTTP PUT.
> +  @param[in]  Uri           Target resource URI.
> +  @param[in]  Content       Data to put.
> +  @param[in]  ContentSize   Size of the Content to be send to Redfish service.
> +                            This is optional. When ContentSize is 0, ContentSize
> +                            is the size of Content.
> +  @param[in]  ContentType   Type of the Content to be send to Redfish
> service.
> +                            This is optional. When ContentType is NULL, content
> +                            type HTTP_CONTENT_TYPE_APP_JSON will be used.
> +  @param[out] Response      HTTP response from redfish service.
> +
> +  @retval     EFI_SUCCESS     Resrouce is returned successfully.
> +  @retval     Others          Errors occur.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +RedfishPutResource (
> +  IN  EDKII_REDFISH_HTTP_PROTOCOL  *This,
> +  IN  REDFISH_SERVICE              Service,
> +  IN  EFI_STRING                   Uri,
> +  IN  CHAR8                        *Content,
> +  IN  UINTN                        ContentSize OPTIONAL,
> +  IN  CHAR8                        *ContentType OPTIONAL,
> +  OUT REDFISH_RESPONSE             *Response
> +  )
> +{
> +  EFI_STATUS                  Status;
> +  UINTN                       RetryCount;
> +  REDFISH_REQUEST             Request;
> +  REDFISH_HTTP_CACHE_PRIVATE  *Private;
> +
> +  if ((This == NULL) || (Service == NULL) || (Response == NULL) ||
> IS_EMPTY_STRING (Uri) || IS_EMPTY_STRING (Content)) {
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  DEBUG ((REDFISH_HTTP_CACHE_DEBUG, "%a: Put URI: %s\n", __func__,
> Uri));
> +
> +  Private    = REDFISH_HTTP_CACHE_PRIVATE_FROM_THIS (This);
> +  RetryCount = 0;
> +  ZeroMem (Response, sizeof (REDFISH_RESPONSE));
> +  ZeroMem (&Request, sizeof (REDFISH_REQUEST));
> +
> +  Request.Content       = Content;
> +  Request.ContentLength = ContentSize;
> +  Request.ContentType   = ContentType;
> +
> +  //
> +  // Patch resource to redfish service.
> +  //
> +  do {
> +    RetryCount += 1;
> +    Status      = HttpSendReceive (
> +                    Service,
> +                    Uri,
> +                    HttpMethodPut,
> +                    &Request,
> +                    Response
> +                    );
> +    DEBUG ((REDFISH_HTTP_CACHE_DEBUG_REQUEST, "%a: HTTP request:
> %s :%r\n", __func__, Uri, Status));
> +    if (!EFI_ERROR (Status) || (RetryCount >= Private-
> >RetrySetting.MaximumRetryPut)) {
> +      break;
> +    }
> +
> +    //
> +    // Retry when BMC is not ready.
> +    //
> +    if ((Response->StatusCode != NULL)) {
> +      DEBUG_CODE (
> +        DumpRedfishResponse (NULL, DEBUG_ERROR, Response);
> +        );
> +
> +      if (!RedfishRetryRequired (Response->StatusCode)) {
> +        break;
> +      }
> +
> +      //
> +      // Release response for next round of request.
> +      //
> +      This->FreeResponse (This, Response);
> +    }
> +
> +    DEBUG ((DEBUG_WARN, "%a: RedfishPutToUri failed, retry (%d/%d)\n",
> __func__, RetryCount, Private->RetrySetting.MaximumRetryPut));
> +    if (Private->RetrySetting.RetryWait > 0) {
> +      gBS->Stall (Private->RetrySetting.RetryWait);
> +    }
> +  } while (TRUE);
> +
> +  //
> +  // Redfish resource is updated. Automatically expire the cached response
> +  // so application can directly get resource from Redfish service again.
> +  //
> +  DEBUG ((REDFISH_HTTP_CACHE_DEBUG, "%a: Resource is updated, expire
> URI: %s\n", __func__, Uri));
> +  RedfishExpireResponse (This, Uri);
> +
> +  if (EFI_ERROR (Status)) {
> +    DEBUG_CODE (
> +      DumpRedfishResponse (NULL, DEBUG_ERROR, Response);
> +      );
> +    //
> +    // Report status code for Redfish failure
> +    //
> +    ReportHttpError (HttpMethodPut, Uri, Response->StatusCode);
> +    DEBUG ((DEBUG_ERROR, "%a: put %s failed (%d/%d): %r\n", __func__,
> Uri, RetryCount, Private->RetrySetting.MaximumRetryPut, Status));
> +    goto ON_RELEASE;
> +  }
> +
> +ON_RELEASE:
> +
> +  return Status;
> +}
> +
> +/**
> +  Perform HTTP POST to send redfish resource to given resource URI.
> +  It's caller's responsibility to free Response by calling FreeResponse ().
> +
> +  @param[in]  This          Pointer to EDKII_REDFISH_HTTP_PROTOCOL instance.
> +  @param[in]  Service       Redfish service instance to perform HTTP POST.
> +  @param[in]  Uri           Target resource URI.
> +  @param[in]  Content       Data to post.
> +  @param[in]  ContentSize   Size of the Content to be send to Redfish service.
> +                            This is optional. When ContentSize is 0, ContentSize
> +                            is the size of Content.
> +  @param[in]  ContentType   Type of the Content to be send to Redfish
> service.
> +                            This is optional. When ContentType is NULL, content
> +                            type HTTP_CONTENT_TYPE_APP_JSON will be used.
> +  @param[out] Response      HTTP response from redfish service.
> +
> +  @retval     EFI_SUCCESS     Resrouce is returned successfully.
> +  @retval     Others          Errors occur.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +RedfishPostResource (
> +  IN  EDKII_REDFISH_HTTP_PROTOCOL  *This,
> +  IN  REDFISH_SERVICE              Service,
> +  IN  EFI_STRING                   Uri,
> +  IN  CHAR8                        *Content,
> +  IN  UINTN                        ContentSize OPTIONAL,
> +  IN  CHAR8                        *ContentType OPTIONAL,
> +  OUT REDFISH_RESPONSE             *Response
> +  )
> +{
> +  EFI_STATUS                  Status;
> +  UINTN                       RetryCount;
> +  REDFISH_REQUEST             Request;
> +  REDFISH_HTTP_CACHE_PRIVATE  *Private;
> +
> +  if ((This == NULL) || (Service == NULL) || (Response == NULL) ||
> IS_EMPTY_STRING (Uri) || IS_EMPTY_STRING (Content)) {
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  DEBUG ((REDFISH_HTTP_CACHE_DEBUG, "%a: Post URI: %s\n", __func__,
> Uri));
> +
> +  Private    = REDFISH_HTTP_CACHE_PRIVATE_FROM_THIS (This);
> +  RetryCount = 0;
> +  ZeroMem (Response, sizeof (REDFISH_RESPONSE));
> +  ZeroMem (&Request, sizeof (REDFISH_REQUEST));
> +
> +  Request.Content       = Content;
> +  Request.ContentLength = ContentSize;
> +  Request.ContentType   = ContentType;
> +
> +  //
> +  // Patch resource to redfish service.
> +  //
> +  do {
> +    RetryCount += 1;
> +    Status      = HttpSendReceive (
> +                    Service,
> +                    Uri,
> +                    HttpMethodPost,
> +                    &Request,
> +                    Response
> +                    );
> +    DEBUG ((REDFISH_HTTP_CACHE_DEBUG_REQUEST, "%a: HTTP request:
> %s :%r\n", __func__, Uri, Status));
> +    if (!EFI_ERROR (Status) || (RetryCount >= Private-
> >RetrySetting.MaximumRetryPost)) {
> +      break;
> +    }
> +
> +    //
> +    // Retry when BMC is not ready.
> +    //
> +    if ((Response->StatusCode != NULL)) {
> +      DEBUG_CODE (
> +        DumpRedfishResponse (NULL, DEBUG_ERROR, Response);
> +        );
> +
> +      if (!RedfishRetryRequired (Response->StatusCode)) {
> +        break;
> +      }
> +
> +      //
> +      // Release response for next round of request.
> +      //
> +      This->FreeResponse (This, Response);
> +    }
> +
> +    DEBUG ((DEBUG_WARN, "%a: RedfishPostToUri failed, retry (%d/%d)\n",
> __func__, RetryCount, Private->RetrySetting.MaximumRetryPost));
> +    if (Private->RetrySetting.RetryWait > 0) {
> +      gBS->Stall (Private->RetrySetting.RetryWait);
> +    }
> +  } while (TRUE);
> +
> +  //
> +  // Redfish resource is updated. Automatically expire the cached response
> +  // so application can directly get resource from Redfish service again.
> +  //
> +  DEBUG ((REDFISH_HTTP_CACHE_DEBUG, "%a: Resource is updated, expire
> URI: %s\n", __func__, Uri));
> +  RedfishExpireResponse (This, Uri);
> +
> +  if (EFI_ERROR (Status)) {
> +    DEBUG_CODE (
> +      DumpRedfishResponse (NULL, DEBUG_ERROR, Response);
> +      );
> +    //
> +    // Report status code for Redfish failure
> +    //
> +    ReportHttpError (HttpMethodPost, Uri, Response->StatusCode);
> +    DEBUG ((DEBUG_ERROR, "%a: post %s failed (%d/%d): %r\n", __func__,
> Uri, RetryCount, Private->RetrySetting.MaximumRetryPost, Status));
> +    goto ON_RELEASE;
> +  }
> +
> +ON_RELEASE:
> +
> +  return Status;
> +}
> +
> +/**
> +  Perform HTTP DELETE to delete redfish resource on given resource URI.
> +  It's caller's responsibility to free Response by calling FreeResponse ().
> +
> +  @param[in]  This          Pointer to EDKII_REDFISH_HTTP_PROTOCOL instance.
> +  @param[in]  Service       Redfish service instance to perform HTTP DELETE.
> +  @param[in]  Uri           Target resource URI.
> +  @param[in]  Content       JSON represented properties to be deleted. This is
> +                            optional.
> +  @param[in]  ContentSize   Size of the Content to be send to Redfish service.
> +                            This is optional. When ContentSize is 0, ContentSize
> +                            is the size of Content if Content is not NULL.
> +  @param[in]  ContentType   Type of the Content to be send to Redfish
> service.
> +                            This is optional. When Content is not NULL and
> +                            ContentType is NULL, content type
> HTTP_CONTENT_TYPE_APP_JSON
> +                            will be used.
> +  @param[out] Response      HTTP response from redfish service.
> +
> +  @retval     EFI_SUCCESS     Resrouce is returned successfully.
> +  @retval     Others          Errors occur.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +RedfishDeleteResource (
> +  IN  EDKII_REDFISH_HTTP_PROTOCOL  *This,
> +  IN  REDFISH_SERVICE              Service,
> +  IN  EFI_STRING                   Uri,
> +  IN  CHAR8                        *Content OPTIONAL,
> +  IN  UINTN                        ContentSize OPTIONAL,
> +  IN  CHAR8                        *ContentType OPTIONAL,
> +  OUT REDFISH_RESPONSE             *Response
> +  )
> +{
> +  EFI_STATUS                  Status;
> +  UINTN                       RetryCount;
> +  REDFISH_REQUEST             Request;
> +  REDFISH_HTTP_CACHE_PRIVATE  *Private;
> +
> +  if ((This == NULL) || (Service == NULL) || (Response == NULL) ||
> IS_EMPTY_STRING (Uri)) {
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  DEBUG ((REDFISH_HTTP_CACHE_DEBUG, "%a: Delete URI: %s\n", __func__,
> Uri));
> +
> +  Private    = REDFISH_HTTP_CACHE_PRIVATE_FROM_THIS (This);
> +  RetryCount = 0;
> +  ZeroMem (Response, sizeof (REDFISH_RESPONSE));
> +  ZeroMem (&Request, sizeof (REDFISH_REQUEST));
> +
> +  Request.Content       = Content;
> +  Request.ContentLength = ContentSize;
> +  Request.ContentType   = ContentType;
> +
> +  //
> +  // Patch resource to redfish service.
> +  //
> +  do {
> +    RetryCount += 1;
> +    Status      = HttpSendReceive (
> +                    Service,
> +                    Uri,
> +                    HttpMethodDelete,
> +                    &Request,
> +                    Response
> +                    );
> +    DEBUG ((REDFISH_HTTP_CACHE_DEBUG_REQUEST, "%a: HTTP request:
> %s :%r\n", __func__, Uri, Status));
> +    if (!EFI_ERROR (Status) || (RetryCount >= Private-
> >RetrySetting.MaximumRetryDelete)) {
> +      break;
> +    }
> +
> +    //
> +    // Retry when BMC is not ready.
> +    //
> +    if ((Response->StatusCode != NULL)) {
> +      DEBUG_CODE (
> +        DumpRedfishResponse (NULL, DEBUG_ERROR, Response);
> +        );
> +
> +      if (!RedfishRetryRequired (Response->StatusCode)) {
> +        break;
> +      }
> +
> +      //
> +      // Release response for next round of request.
> +      //
> +      This->FreeResponse (This, Response);
> +    }
> +
> +    DEBUG ((DEBUG_WARN, "%a: RedfishDeleteByUri failed, retry
> (%d/%d)\n", __func__, RetryCount, Private-
> >RetrySetting.MaximumRetryDelete));
> +    if (Private->RetrySetting.RetryWait > 0) {
> +      gBS->Stall (Private->RetrySetting.RetryWait);
> +    }
> +  } while (TRUE);
> +
> +  //
> +  // Redfish resource is updated. Automatically expire the cached response
> +  // so application can directly get resource from Redfish service again.
> +  //
> +  DEBUG ((REDFISH_HTTP_CACHE_DEBUG, "%a: Resource is updated, expire
> URI: %s\n", __func__, Uri));
> +  RedfishExpireResponse (This, Uri);
> +
> +  if (EFI_ERROR (Status)) {
> +    DEBUG_CODE (
> +      DumpRedfishResponse (NULL, DEBUG_ERROR, Response);
> +      );
> +    //
> +    // Report status code for Redfish failure
> +    //
> +    ReportHttpError (HttpMethodDelete, Uri, Response->StatusCode);
> +    DEBUG ((DEBUG_ERROR, "%a: delete %s failed (%d/%d): %r\n", __func__,
> Uri, RetryCount, Private->RetrySetting.MaximumRetryDelete, Status));
> +    goto ON_RELEASE;
> +  }
> +
> +ON_RELEASE:
> +
> +  return Status;
> +}
> +
> +EDKII_REDFISH_HTTP_PROTOCOL  mEdkIIRedfishHttpProtocol = {
> +  EDKII_REDFISH_HTTP_PROTOCOL_REVISION,
> +  RedfishCreateRedfishService,
> +  RedfishFreeRedfishService,
> +  RedfishJsonInRedfishPayload,
> +  RedfishGetResource,
> +  RedfishPatchResource,
> +  RedfishPutResource,
> +  RedfishPostResource,
> +  RedfishDeleteResource,
> +  RedfishFreeRequest,
> +  RedfishFreeResponse,
> +  RedfishExpireResponse
> +};
> +
> +/**
> +  Unloads an image.
> +
> +  @param[in]  ImageHandle         Handle that identifies the image to be
> unloaded.
> +
> +  @retval EFI_SUCCESS             The image has been unloaded.
> +  @retval EFI_INVALID_PARAMETER   ImageHandle is not a valid image
> handle.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +RedfishHttpDriverUnload (
> +  IN EFI_HANDLE  ImageHandle
> +  )
> +{
> +  if (mRedfishHttpCachePrivate == NULL) {
> +    return EFI_SUCCESS;
> +  }
> +
> +  if (!IsListEmpty (&mRedfishHttpCachePrivate->CacheList.Head)) {
> +    ReleaseCacheList (&mRedfishHttpCachePrivate->CacheList);
> +  }
> +
> +  gBS->UninstallMultipleProtocolInterfaces (
> +         ImageHandle,
> +         &gEdkIIRedfishHttpProtocolGuid,
> +         &mRedfishHttpCachePrivate->Protocol,
> +         NULL
> +         );
> +
> +  FreePool (mRedfishHttpCachePrivate);
> +  mRedfishHttpCachePrivate = NULL;
> +
> +  return EFI_SUCCESS;
> +}
> +
> +/**
> +  This is a EDKII_REDFISH_CREDENTIAL_PROTOCOL notification event handler.
> +
> +  @param[in] Event    Event whose notification function is being invoked.
> +  @param[in] Context  Pointer to the notification function's context.
> +
> +**/
> +VOID
> +EFIAPI
> +CredentialProtocolInstalled (
> +  IN  EFI_EVENT  Event,
> +  IN  VOID       *Context
> +  )
> +{
> +  EFI_STATUS                  Status;
> +  REDFISH_HTTP_CACHE_PRIVATE  *Private;
> +
> +  Private = (REDFISH_HTTP_CACHE_PRIVATE *)Context;
> +  if (Private->Signature != REDFISH_HTTP_DRIVER_SIGNATURE) {
> +    DEBUG ((DEBUG_ERROR, "%a: signature check failure\n", __func__));
> +    return;
> +  }
> +
> +  //
> +  // Locate HII database protocol.
> +  //
> +  Status = gBS->LocateProtocol (
> +                  &gEdkIIRedfishCredentialProtocolGuid,
> +                  NULL,
> +                  (VOID **)&Private->CredentialProtocol
> +                  );
> +  if (EFI_ERROR (Status)) {
> +    return;
> +  }
> +
> +  gBS->CloseEvent (Event);
> +}
> +
> +/**
> +  Main entry for this driver.
> +
> +  @param[in] ImageHandle     Image handle this driver.
> +  @param[in] SystemTable     Pointer to SystemTable.
> +
> +  @retval EFI_SUCCESS     This function always complete successfully.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +RedfishHttpEntryPoint (
> +  IN EFI_HANDLE        ImageHandle,
> +  IN EFI_SYSTEM_TABLE  *SystemTable
> +  )
> +{
> +  EFI_STATUS  Status;
> +  VOID        *Registration;
> +
> +  if (mRedfishHttpCachePrivate != NULL) {
> +    return EFI_ALREADY_STARTED;
> +  }
> +
> +  mRedfishHttpCachePrivate = AllocateZeroPool (sizeof
> (REDFISH_HTTP_CACHE_PRIVATE));
> +  if (mRedfishHttpCachePrivate == NULL) {
> +    return EFI_OUT_OF_RESOURCES;
> +  }
> +
> +  //
> +  // Initial cache list and protocol instance.
> +  //
> +  mRedfishHttpCachePrivate->Signature   =
> REDFISH_HTTP_DRIVER_SIGNATURE;
> +  mRedfishHttpCachePrivate->ImageHandle = ImageHandle;
> +  CopyMem (&mRedfishHttpCachePrivate->Protocol,
> &mEdkIIRedfishHttpProtocol, sizeof (EDKII_REDFISH_HTTP_PROTOCOL));
> +  mRedfishHttpCachePrivate->CacheList.Capacity =
> REDFISH_HTTP_CACHE_LIST_SIZE;
> +  mRedfishHttpCachePrivate->CacheList.Count    = 0x00;
> +  mRedfishHttpCachePrivate->CacheDisabled      = PcdGetBool
> (PcdHttpCacheDisabled);
> +  InitializeListHead (&mRedfishHttpCachePrivate->CacheList.Head);
> +
> +  //
> +  // Get retry settings
> +  //
> +  mRedfishHttpCachePrivate->RetrySetting.MaximumRetryGet    = PcdGet16
> (PcdHttpGetRetry);
> +  mRedfishHttpCachePrivate->RetrySetting.MaximumRetryPut    = PcdGet16
> (PcdHttpPutRetry);
> +  mRedfishHttpCachePrivate->RetrySetting.MaximumRetryPatch  = PcdGet16
> (PcdHttpPatchRetry);
> +  mRedfishHttpCachePrivate->RetrySetting.MaximumRetryPost   = PcdGet16
> (PcdHttpPostRetry);
> +  mRedfishHttpCachePrivate->RetrySetting.MaximumRetryDelete = PcdGet16
> (PcdHttpDeleteRetry);
> +  mRedfishHttpCachePrivate->RetrySetting.RetryWait          = PcdGet16
> (PcdHttpRetryWaitInSecond) * 1000000U;
> +
> +  //
> +  // Install the gEdkIIRedfishHttpProtocolGuid onto Handle.
> +  //
> +  Status = gBS->InstallMultipleProtocolInterfaces (
> +                  &mRedfishHttpCachePrivate->ImageHandle,
> +                  &gEdkIIRedfishHttpProtocolGuid,
> +                  &mRedfishHttpCachePrivate->Protocol,
> +                  NULL
> +                  );
> +  if (EFI_ERROR (Status)) {
> +    DEBUG ((DEBUG_ERROR, "%a: cannot install Redfish http protocol: %r\n",
> __func__, Status));
> +    RedfishHttpDriverUnload (ImageHandle);
> +    return Status;
> +  }
> +
> +  //
> +  // Install protocol notification if credential protocol is installed.
> +  //
> +  mRedfishHttpCachePrivate->NotifyEvent = EfiCreateProtocolNotifyEvent (
> +                                            &gEdkIIRedfishCredentialProtocolGuid,
> +                                            TPL_CALLBACK,
> +                                            CredentialProtocolInstalled,
> +                                            mRedfishHttpCachePrivate,
> +                                            &Registration
> +                                            );
> +  if (mRedfishHttpCachePrivate->NotifyEvent == NULL) {
> +    DEBUG ((DEBUG_ERROR, "%a: failed to create protocol notification for
> gEdkIIRedfishCredentialProtocolGuid\n", __func__));
> +    ASSERT (FALSE);
> +    RedfishHttpDriverUnload (ImageHandle);
> +    return Status;
> +  }
> +
> +  return EFI_SUCCESS;
> +}
> diff --git a/RedfishPkg/RedfishHttpDxe/RedfishHttpOperation.c
> b/RedfishPkg/RedfishHttpDxe/RedfishHttpOperation.c
> new file mode 100644
> index 0000000000..5652818d16
> --- /dev/null
> +++ b/RedfishPkg/RedfishHttpDxe/RedfishHttpOperation.c
> @@ -0,0 +1,693 @@
> +/** @file
> +  RedfishHttpOperation handles HTTP operations.
> +
> +  Copyright (c) 2024, NVIDIA CORPORATION & AFFILIATES. All rights
> reserved.
> +
> +  SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +#include "RedfishHttpOperation.h"
> +#include "RedfishHttpData.h"
> +
> +/**
> +  This function copies all headers in SrcHeaders to DstHeaders.
> +  It's call responsibility to release returned DstHeaders.
> +
> +  @param[in]  SrcHeaders      Source headers.
> +  @param[in]  SrcHeaderCount  Number of header in source headers.
> +  @param[out] DstHeaders      Destination headers.
> +  @param[out] DstHeaderCount  Number of header in designation headers.
> +
> +  @retval     EFI_SUCCESS     Headers are copied successfully.
> +  @retval     Others          Errors occur.
> +
> +**/
> +EFI_STATUS
> +CopyHttpHeaders (
> +  IN  EFI_HTTP_HEADER  *SrcHeaders,
> +  IN  UINTN            SrcHeaderCount,
> +  OUT EFI_HTTP_HEADER  **DstHeaders,
> +  OUT UINTN            *DstHeaderCount
> +  )
> +{
> +  UINTN  Index;
> +
> +  if ((SrcHeaders == NULL) || (SrcHeaderCount == 0) || (DstHeaders == NULL)
> || (DstHeaderCount == NULL)) {
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  *DstHeaderCount = 0;
> +  *DstHeaders     = AllocateZeroPool (sizeof (EFI_HTTP_HEADER) *
> SrcHeaderCount);
> +  if (*DstHeaders == NULL) {
> +    return EFI_OUT_OF_RESOURCES;
> +  }
> +
> +  for (Index = 0; Index < SrcHeaderCount; Index++) {
> +    (*DstHeaders)[Index].FieldName = AllocateCopyPool (AsciiStrSize
> (SrcHeaders[Index].FieldName), SrcHeaders[Index].FieldName);
> +    if ((*DstHeaders)[Index].FieldName == NULL) {
> +      return EFI_OUT_OF_RESOURCES;
> +    }
> +
> +    (*DstHeaders)[Index].FieldValue = AllocateCopyPool (AsciiStrSize
> (SrcHeaders[Index].FieldValue), SrcHeaders[Index].FieldValue);
> +    if ((*DstHeaders)[Index].FieldValue == NULL) {
> +      return EFI_OUT_OF_RESOURCES;
> +    }
> +
> +    *DstHeaderCount += 1;
> +  }
> +
> +  return EFI_SUCCESS;
> +}
> +
> +/**
> +  This function free resources in Request. Request is no longer available
> +  after this function returns successfully.
> +
> +  @param[in]  Request      HTTP request to be released.
> +
> +  @retval     EFI_SUCCESS     Resrouce is released successfully.
> +  @retval     Others          Errors occur.
> +
> +**/
> +EFI_STATUS
> +ReleaseRedfishRequest (
> +  IN  REDFISH_REQUEST  *Request
> +  )
> +{
> +  if (Request == NULL) {
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  if ((Request->Headers != NULL) && (Request->HeaderCount > 0)) {
> +    HttpFreeHeaderFields (Request->Headers, Request->HeaderCount);
> +    Request->Headers     = NULL;
> +    Request->HeaderCount = 0;
> +  }
> +
> +  if (Request->Content != NULL) {
> +    FreePool (Request->Content);
> +    Request->Content = NULL;
> +  }
> +
> +  if (Request->ContentType != NULL) {
> +    FreePool (Request->ContentType);
> +    Request->ContentType = NULL;
> +  }
> +
> +  Request->ContentLength = 0;
> +
> +  return EFI_SUCCESS;
> +}
> +
> +/**
> +  This function free resources in given Response.
> +
> +  @param[in]  Response     HTTP response to be released.
> +
> +  @retval     EFI_SUCCESS     Resrouce is released successfully.
> +  @retval     Others          Errors occur.
> +
> +**/
> +EFI_STATUS
> +ReleaseRedfishResponse (
> +  IN  REDFISH_RESPONSE  *Response
> +  )
> +{
> +  if (Response == NULL) {
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  if ((Response->Headers != NULL) && (Response->HeaderCount > 0)) {
> +    HttpFreeHeaderFields (Response->Headers, Response->HeaderCount);
> +    Response->Headers     = NULL;
> +    Response->HeaderCount = 0;
> +  }
> +
> +  if (Response->Payload != NULL) {
> +    ReleaseRedfishPayload (Response->Payload);
> +    Response->Payload = NULL;
> +  }
> +
> +  if (Response->StatusCode != NULL) {
> +    FreePool (Response->StatusCode);
> +    Response->StatusCode = NULL;
> +  }
> +
> +  return EFI_SUCCESS;
> +}
> +
> +/**
> +  This function free resources in given HTTP message.
> +
> +  @param[in]  HttpMessage     HTTP message to be released.
> +  @param[in]  IsRequest       TRUE if this is request type of HTTP message.
> +                              FALSE if this is response type of HTTP message.
> +
> +  @retval     EFI_SUCCESS     Resrouce is released successfully.
> +  @retval     Others          Errors occur.
> +
> +**/
> +EFI_STATUS
> +ReleaseHttpMessage (
> +  IN  EFI_HTTP_MESSAGE  *HttpMessage,
> +  IN  BOOLEAN           IsRequest
> +  )
> +{
> +  if (HttpMessage == NULL) {
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  if (IsRequest) {
> +    if (HttpMessage->Data.Request != NULL) {
> +      if (HttpMessage->Data.Request->Url != NULL) {
> +        FreePool (HttpMessage->Data.Request->Url);
> +      }
> +
> +      FreePool (HttpMessage->Data.Request);
> +      HttpMessage->Data.Request = NULL;
> +    }
> +  } else {
> +    if (HttpMessage->Data.Response != NULL) {
> +      FreePool (HttpMessage->Data.Response);
> +      HttpMessage->Data.Response = NULL;
> +    }
> +  }
> +
> +  if (HttpMessage->Body != NULL) {
> +    FreePool (HttpMessage->Body);
> +    HttpMessage->Body = NULL;
> +  }
> +
> +  if (HttpMessage->Headers != NULL) {
> +    HttpFreeHeaderFields (HttpMessage->Headers, HttpMessage-
> >HeaderCount);
> +    HttpMessage->Headers     = NULL;
> +    HttpMessage->HeaderCount = 0;
> +  }
> +
> +  return EFI_SUCCESS;
> +}
> +
> +/**
> +  This function build Redfish message for sending data to Redfish service.
> +  It's call responsibility to properly release returned HTTP message by
> +  calling ReleaseHttpMessage.
> +
> +  @param[in]   ServicePrivate    Pointer to Redfish service private data.
> +  @param[in]   Uri               Redfish service URI.
> +  @param[in]   Method            HTTP method.
> +  @param[in]   Request           Additional data to send to Redfish service.
> +                                 This is optional.
> +  @param[in]   ContentEncoding   Content encoding method to compress
> HTTP context.
> +                                 This is optional. When ContentEncoding is NULL,
> +                                 No compress method will be performed.
> +
> +  @retval     EFI_HTTP_MESSAGE *   Pointer to newly created HTTP message.
> +  @retval     NULL                 Error occurred.
> +
> +**/
> +EFI_HTTP_MESSAGE *
> +BuildRequestMessage (
> +  IN REDFISH_SERVICE_PRIVATE  *ServicePrivate,
> +  IN EFI_STRING               Uri,
> +  IN EFI_HTTP_METHOD          Method,
> +  IN REDFISH_REQUEST          *Request OPTIONAL,
> +  IN CHAR8                    *ContentEncoding OPTIONAL
> +  )
> +{
> +  EFI_STATUS             Status;
> +  EFI_STRING             Url;
> +  UINTN                  UrlSize;
> +  UINTN                  Index;
> +  EFI_HTTP_MESSAGE       *RequestMsg;
> +  EFI_HTTP_REQUEST_DATA  *RequestData;
> +  UINTN                  HeaderCount;
> +  UINTN                  HeaderIndex;
> +  EFI_HTTP_HEADER        *Headers;
> +  CHAR8                  ContentLengthStr[REDFISH_CONTENT_LENGTH_SIZE];
> +  VOID                   *Content;
> +  UINTN                  ContentLength;
> +  BOOLEAN                HasContent;
> +  BOOLEAN                DoContentEncoding;
> +
> +  RequestMsg        = NULL;
> +  RequestData       = NULL;
> +  Url               = NULL;
> +  UrlSize           = 0;
> +  Content           = NULL;
> +  ContentLength     = 0;
> +  HeaderCount       = REDFISH_COMMON_HEADER_SIZE;
> +  HeaderIndex       = 0;
> +  Headers           = NULL;
> +  HasContent        = FALSE;
> +  DoContentEncoding = FALSE;
> +
> +  if ((ServicePrivate == NULL) || (IS_EMPTY_STRING (Uri))) {
> +    return NULL;
> +  }
> +
> +  if (Method >= HttpMethodMax) {
> +    return NULL;
> +  }
> +
> +  DEBUG ((REDFISH_HTTP_CACHE_DEBUG_REQUEST, "%a: %s\n", __func__,
> Uri));
> +
> +  //
> +  // Build full URL for HTTP query.
> +  //
> +  UrlSize = (AsciiStrLen (ServicePrivate->Host) + StrLen (Uri) + 1) * sizeof
> (CHAR16);
> +  Url     = AllocateZeroPool (UrlSize);
> +  if (Url == NULL) {
> +    return NULL;
> +  }
> +
> +  UnicodeSPrint (Url, UrlSize, L"%a%s", ServicePrivate->Host, Uri);
> +  DEBUG ((REDFISH_HTTP_CACHE_DEBUG_REQUEST, "%a: Url: %s\n",
> __func__, Url));
> +
> +  //
> +  // Step 1: build the HTTP headers.
> +  //
> +  if (!IS_EMPTY_STRING (ServicePrivate->SessionToken)
> || !IS_EMPTY_STRING (ServicePrivate->BasicAuth)) {
> +    HeaderCount++;
> +  }
> +
> +  if ((Request != NULL) && (Request->HeaderCount > 0)) {
> +    HeaderCount += Request->HeaderCount;
> +  }
> +
> +  //
> +  // Check and see if we will do content encoding or not
> +  //
> +  if (!IS_EMPTY_STRING (ContentEncoding)) {
> +    if (AsciiStrCmp (ContentEncoding,
> REDFISH_HTTP_CONTENT_ENCODING_NONE) != 0) {
> +      DoContentEncoding = TRUE;
> +    }
> +  }
> +
> +  if ((Request != NULL) && !IS_EMPTY_STRING (Request->Content)) {
> +    HeaderCount += 2;
> +    HasContent   = TRUE;
> +    if (DoContentEncoding) {
> +      HeaderCount += 1;
> +    }
> +  }
> +
> +  Headers = AllocateZeroPool (HeaderCount * sizeof (EFI_HTTP_HEADER));
> +  if (Headers == NULL) {
> +    goto ON_ERROR;
> +  }
> +
> +  if (!IS_EMPTY_STRING (ServicePrivate->SessionToken)) {
> +    Status = HttpSetFieldNameAndValue (&Headers[HeaderIndex++],
> HTTP_HEADER_X_AUTH_TOKEN, ServicePrivate->SessionToken);
> +    if (EFI_ERROR (Status)) {
> +      goto ON_ERROR;
> +    }
> +  } else if (!IS_EMPTY_STRING (ServicePrivate->BasicAuth)) {
> +    Status = HttpSetFieldNameAndValue (&Headers[HeaderIndex++],
> HTTP_HEADER_AUTHORIZATION, ServicePrivate->BasicAuth);
> +    if (EFI_ERROR (Status)) {
> +      goto ON_ERROR;
> +    }
> +  }
> +
> +  if (Request != NULL) {
> +    for (Index = 0; Index < Request->HeaderCount; Index++) {
> +      Status = HttpSetFieldNameAndValue (&Headers[HeaderIndex++],
> Request->Headers[Index].FieldName, Request->Headers[Index].FieldValue);
> +      if (EFI_ERROR (Status)) {
> +        goto ON_ERROR;
> +      }
> +    }
> +  }
> +
> +  Status = HttpSetFieldNameAndValue (&Headers[HeaderIndex++],
> HTTP_HEADER_HOST, ServicePrivate->HostName);
> +  if (EFI_ERROR (Status)) {
> +    goto ON_ERROR;
> +  }
> +
> +  Status = HttpSetFieldNameAndValue (&Headers[HeaderIndex++],
> REDFISH_HTTP_HEADER_ODATA_VERSION_STR,
> REDFISH_HTTP_HEADER_ODATA_VERSION_VALUE);
> +  if (EFI_ERROR (Status)) {
> +    goto ON_ERROR;
> +  }
> +
> +  Status = HttpSetFieldNameAndValue (&Headers[HeaderIndex++],
> HTTP_HEADER_ACCEPT, HTTP_CONTENT_TYPE_APP_JSON);
> +  if (EFI_ERROR (Status)) {
> +    goto ON_ERROR;
> +  }
> +
> +  Status = HttpSetFieldNameAndValue (&Headers[HeaderIndex++],
> HTTP_HEADER_USER_AGENT,
> REDFISH_HTTP_HEADER_USER_AGENT_VALUE);
> +  if (EFI_ERROR (Status)) {
> +    goto ON_ERROR;
> +  }
> +
> +  Status = HttpSetFieldNameAndValue (&Headers[HeaderIndex++],
> REDFISH_HTTP_HEADER_CONNECTION_STR,
> REDFISH_HTTP_HEADER_CONNECTION_VALUE);
> +  if (EFI_ERROR (Status)) {
> +    goto ON_ERROR;
> +  }
> +
> +  //
> +  // Handle content header
> +  //
> +  if (HasContent) {
> +    if (Request->ContentType == NULL) {
> +      Status = HttpSetFieldNameAndValue (&Headers[HeaderIndex++],
> HTTP_HEADER_CONTENT_TYPE, HTTP_CONTENT_TYPE_APP_JSON);
> +      if (EFI_ERROR (Status)) {
> +        goto ON_ERROR;
> +      }
> +    } else {
> +      Status = HttpSetFieldNameAndValue (&Headers[HeaderIndex++],
> HTTP_HEADER_CONTENT_TYPE, Request->ContentType);
> +      if (EFI_ERROR (Status)) {
> +        goto ON_ERROR;
> +      }
> +    }
> +
> +    if (Request->ContentLength == 0) {
> +      Request->ContentLength =  AsciiStrLen (Request->Content);
> +    }
> +
> +    AsciiSPrint (
> +      ContentLengthStr,
> +      sizeof (ContentLengthStr),
> +      "%lu",
> +      (UINT64)Request->ContentLength
> +      );
> +    Status = HttpSetFieldNameAndValue (&Headers[HeaderIndex++],
> HTTP_HEADER_CONTENT_LENGTH, ContentLengthStr);
> +    if (EFI_ERROR (Status)) {
> +      goto ON_ERROR;
> +    }
> +
> +    //
> +    // Encoding
> +    //
> +    if (DoContentEncoding) {
> +      //
> +      // We currently only support gzip Content-Encoding.
> +      //
> +      Status =  RedfishContentEncode (
> +                  ContentEncoding,
> +                  Request->Content,
> +                  Request->ContentLength,
> +                  &Content,
> +                  &ContentLength
> +                  );
> +      if (Status == EFI_INVALID_PARAMETER) {
> +        DEBUG ((DEBUG_ERROR, "%a: Error to encode content.\n", __func__));
> +        goto ON_ERROR;
> +      } else if (Status == EFI_UNSUPPORTED) {
> +        DoContentEncoding = FALSE;
> +        DEBUG ((REDFISH_HTTP_CACHE_DEBUG_REQUEST, "%a: No content
> coding for %a! Use raw data instead.\n", __func__, ContentEncoding));
> +        Status = HttpSetFieldNameAndValue (&Headers[HeaderIndex++],
> HTTP_HEADER_CONTENT_ENCODING,
> HTTP_CONTENT_ENCODING_IDENTITY);
> +        if (EFI_ERROR (Status)) {
> +          goto ON_ERROR;
> +        }
> +      } else {
> +        Status = HttpSetFieldNameAndValue (&Headers[HeaderIndex++],
> HTTP_HEADER_CONTENT_ENCODING, HTTP_CONTENT_ENCODING_GZIP);
> +        if (EFI_ERROR (Status)) {
> +          goto ON_ERROR;
> +        }
> +      }
> +    }
> +
> +    //
> +    // When the content is from caller, we use our own copy so that we
> properly release it later.
> +    //
> +    if (!DoContentEncoding) {
> +      Content = AllocateCopyPool (Request->ContentLength, Request-
> >Content);
> +      if (Content == NULL) {
> +        goto ON_ERROR;
> +      }
> +
> +      ContentLength = Request->ContentLength;
> +    }
> +  }
> +
> +  //
> +  // Step 2: build the rest of HTTP request info.
> +  //
> +  RequestData = AllocateZeroPool (sizeof (EFI_HTTP_REQUEST_DATA));
> +  if (RequestData == NULL) {
> +    goto ON_ERROR;
> +  }
> +
> +  RequestData->Method = Method;
> +  RequestData->Url    = Url;
> +
> +  //
> +  // Step 3: fill in EFI_HTTP_MESSAGE
> +  //
> +  RequestMsg = AllocateZeroPool (sizeof (EFI_HTTP_MESSAGE));
> +  if (RequestMsg == NULL) {
> +    goto ON_ERROR;
> +  }
> +
> +  ASSERT (HeaderIndex == HeaderCount);
> +  RequestMsg->Data.Request = RequestData;
> +  RequestMsg->HeaderCount  = HeaderIndex;
> +  RequestMsg->Headers      = Headers;
> +
> +  if (HasContent) {
> +    RequestMsg->BodyLength = ContentLength;
> +    RequestMsg->Body       = Content;
> +  }
> +
> +  return RequestMsg;
> +
> +ON_ERROR:
> +
> +  if (Headers != NULL) {
> +    HttpFreeHeaderFields (Headers, HeaderIndex);
> +  }
> +
> +  if (RequestData != NULL) {
> +    FreePool (RequestData);
> +  }
> +
> +  if (RequestMsg != NULL) {
> +    FreePool (RequestMsg);
> +  }
> +
> +  if (Url != NULL) {
> +    FreePool (Url);
> +  }
> +
> +  return NULL;
> +}
> +
> +/**
> +  This function parse response message from Redfish service, and
> +  build Redfish response for caller. It's call responsibility to
> +  properly release Redfish response by calling ReleaseRedfishResponse.
> +
> +  @param[in]   ServicePrivate   Pointer to Redfish service private data.
> +  @param[in]   ResponseMsg      Response message from Redfish service.
> +  @param[out]  RedfishResponse  Redfish response data.
> +
> +  @retval     EFI_SUCCESS     Redfish response is returned successfully.
> +  @retval     Others          Errors occur.
> +
> +**/
> +EFI_STATUS
> +ParseResponseMessage (
> +  IN  REDFISH_SERVICE_PRIVATE  *ServicePrivate,
> +  IN  EFI_HTTP_MESSAGE         *ResponseMsg,
> +  OUT REDFISH_RESPONSE         *RedfishResponse
> +  )
> +{
> +  EFI_STATUS        Status;
> +  EDKII_JSON_VALUE  JsonData;
> +  EFI_HTTP_HEADER   *ContentEncodedHeader;
> +  VOID              *DecodedBody;
> +  UINTN             DecodedLength;
> +
> +  if ((ServicePrivate == NULL) || (ResponseMsg == NULL) || (RedfishResponse
> == NULL)) {
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  DEBUG ((REDFISH_HTTP_CACHE_DEBUG_REQUEST, "%a\n", __func__));
> +
> +  //
> +  // Initialization
> +  //
> +  JsonData                     = NULL;
> +  RedfishResponse->HeaderCount = 0;
> +  RedfishResponse->Headers     = NULL;
> +  RedfishResponse->Payload     = NULL;
> +  RedfishResponse->StatusCode  = NULL;
> +  DecodedBody                  = NULL;
> +  DecodedLength                = 0;
> +
> +  //
> +  // Return the HTTP StatusCode.
> +  //
> +  if (ResponseMsg->Data.Response != NULL) {
> +    DEBUG ((REDFISH_HTTP_CACHE_DEBUG_REQUEST, "%a: status: %d\n",
> __func__, ResponseMsg->Data.Response->StatusCode));
> +    RedfishResponse->StatusCode = AllocateCopyPool (sizeof
> (EFI_HTTP_STATUS_CODE), &ResponseMsg->Data.Response->StatusCode);
> +    if (RedfishResponse->StatusCode == NULL) {
> +      DEBUG ((DEBUG_ERROR, "%a: Failed to create status code.\n",
> __func__));
> +    }
> +  }
> +
> +  //
> +  // Return the HTTP headers.
> +  //
> +  if (ResponseMsg->Headers != NULL) {
> +    DEBUG ((REDFISH_HTTP_CACHE_DEBUG_REQUEST, "%a: header count:
> %d\n", __func__, ResponseMsg->HeaderCount));
> +    Status = CopyHttpHeaders (
> +               ResponseMsg->Headers,
> +               ResponseMsg->HeaderCount,
> +               &RedfishResponse->Headers,
> +               &RedfishResponse->HeaderCount
> +               );
> +    if (EFI_ERROR (Status)) {
> +      DEBUG ((DEBUG_ERROR, "%a: Failed to copy HTTP headers: %r\n",
> __func__, Status));
> +    }
> +  }
> +
> +  //
> +  // Return the HTTP body.
> +  //
> +  if ((ResponseMsg->BodyLength != 0) && (ResponseMsg->Body != NULL)) {
> +    DEBUG ((REDFISH_HTTP_CACHE_DEBUG_REQUEST, "%a: body length:
> %d\n", __func__, ResponseMsg->BodyLength));
> +    //
> +    // Check if data is encoded.
> +    //
> +    ContentEncodedHeader = HttpFindHeader (RedfishResponse-
> >HeaderCount, RedfishResponse->Headers,
> HTTP_HEADER_CONTENT_ENCODING);
> +    if (ContentEncodedHeader != NULL) {
> +      //
> +      // The content is encoded.
> +      //
> +      Status = RedfishContentDecode (
> +                 ContentEncodedHeader->FieldValue,
> +                 ResponseMsg->Body,
> +                 ResponseMsg->BodyLength,
> +                 &DecodedBody,
> +                 &DecodedLength
> +                 );
> +      if (EFI_ERROR (Status)) {
> +        DEBUG ((DEBUG_ERROR, "%a: Failed to decompress the response
> content: %r decoding method: %a\n.", __func__, Status,
> ContentEncodedHeader->FieldValue));
> +        goto ON_ERROR;
> +      }
> +
> +      JsonData = JsonLoadBuffer (DecodedBody, DecodedLength, 0, NULL);
> +      FreePool (DecodedBody);
> +    } else {
> +      JsonData = JsonLoadBuffer (ResponseMsg->Body, ResponseMsg-
> >BodyLength, 0, NULL);
> +    }
> +
> +    if (!JsonValueIsNull (JsonData)) {
> +      RedfishResponse->Payload = CreateRedfishPayload (ServicePrivate,
> JsonData);
> +      if (RedfishResponse->Payload == NULL) {
> +        DEBUG ((DEBUG_ERROR, "%a: Failed to create payload\n.", __func__));
> +      }
> +
> +      JsonValueFree (JsonData);
> +    } else {
> +      DEBUG ((DEBUG_ERROR, "%a: No payload available\n", __func__));
> +    }
> +  }
> +
> +  return EFI_SUCCESS;
> +
> +ON_ERROR:
> +
> +  if (RedfishResponse != NULL) {
> +    ReleaseRedfishResponse (RedfishResponse);
> +  }
> +
> +  return Status;
> +}
> +
> +/**
> +  This function send Redfish request to Redfish service by calling
> +  Rest Ex protocol.
> +
> +  @param[in]   Service       Pointer to Redfish service.
> +  @param[in]   Uri           Uri of Redfish service.
> +  @param[in]   Method        HTTP method.
> +  @param[in]   Request     Request data. This is optional.
> +  @param[out]  Response    Redfish response data.
> +
> +  @retval     EFI_SUCCESS     Request is sent and received successfully.
> +  @retval     Others          Errors occur.
> +
> +**/
> +EFI_STATUS
> +HttpSendReceive (
> +  IN  REDFISH_SERVICE   Service,
> +  IN  EFI_STRING        Uri,
> +  IN  EFI_HTTP_METHOD   Method,
> +  IN  REDFISH_REQUEST   *Request  OPTIONAL,
> +  OUT REDFISH_RESPONSE  *Response
> +  )
> +{
> +  EFI_STATUS               Status;
> +  EFI_STATUS               RestExStatus;
> +  EFI_HTTP_MESSAGE         *RequestMsg;
> +  EFI_HTTP_MESSAGE         ResponseMsg;
> +  REDFISH_SERVICE_PRIVATE  *ServicePrivate;
> +  EFI_HTTP_HEADER          *XAuthTokenHeader;
> +  CHAR8                    *HttpContentEncoding;
> +
> +  if ((Service == NULL) || IS_EMPTY_STRING (Uri) || (Response == NULL)) {
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  DEBUG ((REDFISH_HTTP_CACHE_DEBUG_REQUEST, "%a: Method: 0x%x
> %s\n", __func__, Method, Uri));
> +
> +  ServicePrivate = (REDFISH_SERVICE_PRIVATE *)Service;
> +  if (ServicePrivate->Signature != REDFISH_HTTP_SERVICE_SIGNATURE) {
> +    DEBUG ((DEBUG_ERROR, "%a: signature check failure\n", __func__));
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  ZeroMem (&ResponseMsg, sizeof (ResponseMsg));
> +  HttpContentEncoding = (CHAR8 *)PcdGetPtr
> (PcdRedfishServiceContentEncoding);
> +
> +  RequestMsg = BuildRequestMessage (Service, Uri, Method, Request,
> HttpContentEncoding);
> +  if (RequestMsg == NULL) {
> +    DEBUG ((DEBUG_ERROR, "%a: cannot build request message for %s\n",
> __func__, Uri));
> +    return EFI_PROTOCOL_ERROR;
> +  }
> +
> +  //
> +  // call RESTEx to get response from REST service.
> +  //
> +  RestExStatus = ServicePrivate->RestEx->SendReceive (ServicePrivate-
> >RestEx, RequestMsg, &ResponseMsg);
> +  if (EFI_ERROR (RestExStatus)) {
> +    DEBUG ((DEBUG_ERROR, "%a: %s SendReceive failure: %r\n", __func__,
> Uri, RestExStatus));
> +  }
> +
> +  //
> +  // Return status code, headers and payload to caller as much as possible
> even when RestEx returns failure.
> +  //
> +  Status = ParseResponseMessage (ServicePrivate, &ResponseMsg,
> Response);
> +  if (EFI_ERROR (Status)) {
> +    DEBUG ((DEBUG_ERROR, "%a: %s parse response failure: %r\n", __func__,
> Uri, Status));
> +  } else {
> +    //
> +    // Capture session token in header
> +    //
> +    if ((Method == HttpMethodPost) &&
> +        (Response->StatusCode != NULL) &&
> +        ((*Response->StatusCode == HTTP_STATUS_200_OK) || (*Response-
> >StatusCode == HTTP_STATUS_204_NO_CONTENT)))
> +    {
> +      XAuthTokenHeader = HttpFindHeader (ResponseMsg.HeaderCount,
> ResponseMsg.Headers, HTTP_HEADER_X_AUTH_TOKEN);
> +      if (XAuthTokenHeader != NULL) {
> +        Status = UpdateSessionToken (ServicePrivate, XAuthTokenHeader-
> >FieldValue);
> +        if (EFI_ERROR (Status)) {
> +          DEBUG ((DEBUG_ERROR, "%a: update session token failure: %r\n",
> __func__, Status));
> +        }
> +      }
> +    }
> +  }
> +
> +  //
> +  // Release resources
> +  //
> +  if (RequestMsg != NULL) {
> +    ReleaseHttpMessage (RequestMsg, TRUE);
> +    FreePool (RequestMsg);
> +  }
> +
> +  ReleaseHttpMessage (&ResponseMsg, FALSE);
> +
> +  return RestExStatus;
> +}
> diff --git a/RedfishPkg/Redfish.fdf.inc b/RedfishPkg/Redfish.fdf.inc
> index 3e5a77766e..5cbe3592fd 100644
> --- a/RedfishPkg/Redfish.fdf.inc
> +++ b/RedfishPkg/Redfish.fdf.inc
> @@ -6,7 +6,7 @@
>  # to be built in the firmware volume.
>  #
>  # (C) Copyright 2020-2021 Hewlett Packard Enterprise Development LP<BR>
> -# Copyright (c) 2023, NVIDIA CORPORATION & AFFILIATES. All rights
> reserved.
> +# Copyright (c) 2023-2024, NVIDIA CORPORATION & AFFILIATES. All rights
> reserved.
>  #
>  #    SPDX-License-Identifier: BSD-2-Clause-Patent
>  #
> @@ -20,4 +20,5 @@
>    INF RedfishPkg/RedfishConfigHandler/RedfishConfigHandlerDriver.inf
>    INF RedfishPkg/RedfishPlatformConfigDxe/RedfishPlatformConfigDxe.inf
>    INF
> MdeModulePkg/Universal/RegularExpressionDxe/RegularExpressionDxe.inf
> +  INF RedfishPkg/RedfishHttpDxe/RedfishHttpDxe.inf
>  !endif
> --
> 2.34.1



-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#115815): https://edk2.groups.io/g/devel/message/115815
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]
-=-=-=-=-=-=-=-=-=-=-=-



^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [edk2-devel] [PATCH v2 2/6] RedfishPkg: implement Redfish HTTP protocol
  2024-02-22  9:11 [edk2-devel] [PATCH v2 2/6] RedfishPkg: implement Redfish HTTP protocol Nickle Wang via groups.io
  2024-02-22 13:39 ` Chang, Abner via groups.io
@ 2024-02-22 14:17 ` Igor Kulchytskyy via groups.io
  2024-02-23 11:29 ` Mike Maslenkin
  2 siblings, 0 replies; 15+ messages in thread
From: Igor Kulchytskyy via groups.io @ 2024-02-22 14:17 UTC (permalink / raw)
  To: Nickle Wang, devel@edk2.groups.io; +Cc: Abner Chang, Nick Ramirez

Reviewed-by: Igor Kulchytskyy <igork@ami.com>

-----Original Message-----
From: Nickle Wang <nicklew@nvidia.com>
Sent: Thursday, February 22, 2024 4:11 AM
To: devel@edk2.groups.io
Cc: Igor Kulchytskyy <igork@ami.com>; Abner Chang <abner.chang@amd.com>; Nick Ramirez <nramirez@nvidia.com>
Subject: [EXTERNAL] [PATCH v2 2/6] RedfishPkg: implement Redfish HTTP protocol


**CAUTION: The e-mail below is from an external source. Please exercise caution before opening attachments, clicking links, or following guidance.**

implement Redfish HTTP protocol driver.

Signed-off-by: Nickle Wang <nicklew@nvidia.com>
Co-authored-by: Igor Kulchytskyy <igork@ami.com>
Cc: Abner Chang <abner.chang@amd.com>
Cc: Igor Kulchytskyy <igork@ami.com>
Cc: Nick Ramirez <nramirez@nvidia.com>
---
 RedfishPkg/RedfishPkg.dec                     |    7 +-
 RedfishPkg/RedfishComponents.dsc.inc          |    3 +-
 RedfishPkg/RedfishPkg.dsc                     |    2 +
 RedfishPkg/RedfishHttpDxe/RedfishHttpDxe.inf  |   73 +
 RedfishPkg/RedfishHttpDxe/RedfishHttpData.h   |  256 ++++
 RedfishPkg/RedfishHttpDxe/RedfishHttpDxe.h    |   44 +
 .../RedfishHttpDxe/RedfishHttpOperation.h     |   76 +
 RedfishPkg/RedfishHttpDxe/RedfishHttpData.c   |  667 ++++++++
 RedfishPkg/RedfishHttpDxe/RedfishHttpDxe.c    | 1344 +++++++++++++++++
 .../RedfishHttpDxe/RedfishHttpOperation.c     |  693 +++++++++
 RedfishPkg/Redfish.fdf.inc                    |    3 +-
 11 files changed, 3164 insertions(+), 4 deletions(-)
 create mode 100644 RedfishPkg/RedfishHttpDxe/RedfishHttpDxe.inf
 create mode 100644 RedfishPkg/RedfishHttpDxe/RedfishHttpData.h
 create mode 100644 RedfishPkg/RedfishHttpDxe/RedfishHttpDxe.h
 create mode 100644 RedfishPkg/RedfishHttpDxe/RedfishHttpOperation.h
 create mode 100644 RedfishPkg/RedfishHttpDxe/RedfishHttpData.c
 create mode 100644 RedfishPkg/RedfishHttpDxe/RedfishHttpDxe.c
 create mode 100644 RedfishPkg/RedfishHttpDxe/RedfishHttpOperation.c

diff --git a/RedfishPkg/RedfishPkg.dec b/RedfishPkg/RedfishPkg.dec
index 9b424efdf3..114f8d2ad8 100644
--- a/RedfishPkg/RedfishPkg.dec
+++ b/RedfishPkg/RedfishPkg.dec
@@ -157,8 +157,11 @@
   # set to EFI_REST_EX_PROTOCOL.
   #
   gEfiRedfishPkgTokenSpaceGuid.PcdRedfishSendReceiveTimeout|5000|UINT32|0x00001009
-  ## This is used to enable HTTP content encoding on Redfish communication.
-  gEfiRedfishPkgTokenSpaceGuid.PcdRedfishServiceContentEncoding|TRUE|BOOLEAN|0x0000100A
+  #
+  # This PCD string is introduced for platform developer to set the encoding method supported by BMC Redfish.
+  # Currently only "None" and "gzip" are supported.
+  #
+  gEfiRedfishPkgTokenSpaceGuid.PcdRedfishServiceContentEncoding|"None"|VOID*|0x0000100A
   #
   # Use below PCDs to control Redfhs HTTP protocol.
   #
diff --git a/RedfishPkg/RedfishComponents.dsc.inc b/RedfishPkg/RedfishComponents.dsc.inc
index 464ffc8606..d6c5b73d7f 100644
--- a/RedfishPkg/RedfishComponents.dsc.inc
+++ b/RedfishPkg/RedfishComponents.dsc.inc
@@ -7,7 +7,7 @@
 # "RedfishDefines.dsc.inc".
 #
 # (C) Copyright 2020-2021 Hewlett Packard Enterprise Development LP<BR>
-# Copyright (c) 2023, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
+# Copyright (c) 2023-2024, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
 #
 #    SPDX-License-Identifier: BSD-2-Clause-Patent
 #
@@ -28,4 +28,5 @@
   RedfishPkg/RedfishConfigHandler/RedfishConfigHandlerDriver.inf
   RedfishPkg/RedfishPlatformConfigDxe/RedfishPlatformConfigDxe.inf
   MdeModulePkg/Universal/RegularExpressionDxe/RegularExpressionDxe.inf
+  RedfishPkg/RedfishHttpDxe/RedfishHttpDxe.inf
 !endif
diff --git a/RedfishPkg/RedfishPkg.dsc b/RedfishPkg/RedfishPkg.dsc
index 25ed193182..5849e7cf9e 100644
--- a/RedfishPkg/RedfishPkg.dsc
+++ b/RedfishPkg/RedfishPkg.dsc
@@ -45,6 +45,8 @@
   UefiHiiServicesLib|MdeModulePkg/Library/UefiHiiServicesLib/UefiHiiServicesLib.inf
   RedfishPlatformCredentialLib|RedfishPkg/Library/PlatformCredentialLibNull/PlatformCredentialLibNull.inf
   RedfishContentCodingLib|RedfishPkg/Library/RedfishContentCodingLibNull/RedfishContentCodingLibNull.inf
+  ReportStatusCodeLib|MdeModulePkg/Library/DxeReportStatusCodeLib/DxeReportStatusCodeLib.inf
+  SortLib|MdeModulePkg/Library/UefiSortLib/UefiSortLib.inf

   # NULL instance of IPMI related library.
   IpmiLib|MdeModulePkg/Library/BaseIpmiLibNull/BaseIpmiLibNull.inf
diff --git a/RedfishPkg/RedfishHttpDxe/RedfishHttpDxe.inf b/RedfishPkg/RedfishHttpDxe/RedfishHttpDxe.inf
new file mode 100644
index 0000000000..c7dfdffacf
--- /dev/null
+++ b/RedfishPkg/RedfishHttpDxe/RedfishHttpDxe.inf
@@ -0,0 +1,73 @@
+## @file
+#  RedfishHttpDxe is the DXE driver which provides
+#  EdkIIRedfishHttpProtocol to EDK2 Redfish Feature
+#  drivers for HTTP operation.
+#
+#  Copyright (c) 2023-2024, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
+#
+#  SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+  INF_VERSION                    = 0x0001000b
+  BASE_NAME                      = RedfishHttpDxe
+  FILE_GUID                      = 85ADB2F1-DA93-47D4-AF4F-3D920D9BD2C0
+  MODULE_TYPE                    = DXE_DRIVER
+  VERSION_STRING                 = 1.0
+  ENTRY_POINT                    = RedfishHttpEntryPoint
+  UNLOAD_IMAGE                   = RedfishHttpDriverUnload
+
+#
+#  VALID_ARCHITECTURES           = IA32 X64 ARM AARCH64 RISCV64
+#
+
+[Sources]
+  RedfishHttpData.c
+  RedfishHttpData.h
+  RedfishHttpDxe.c
+  RedfishHttpDxe.h
+  RedfishHttpOperation.c
+  RedfishHttpOperation.h
+
+[Packages]
+  MdePkg/MdePkg.dec
+  MdeModulePkg/MdeModulePkg.dec
+  NetworkPkg/NetworkPkg.dec
+  RedfishPkg/RedfishPkg.dec
+
+[LibraryClasses.ARM]
+  ArmSoftFloatLib
+
+[LibraryClasses]
+  BaseLib
+  BaseMemoryLib
+  RedfishContentCodingLib
+  DebugLib
+  HttpLib
+  JsonLib
+  MemoryAllocationLib
+  PrintLib
+  RedfishDebugLib
+  ReportStatusCodeLib
+  UefiBootServicesTableLib
+  UefiDriverEntryPoint
+  UefiLib
+
+[Protocols]
+  gEdkIIRedfishHttpProtocolGuid             ## PRODUCED
+  gEdkIIRedfishCredentialProtocolGuid       ## CONSUMES
+  gEfiRestExProtocolGuid                    ## CONSUEMS
+
+[Pcd]
+  gEfiRedfishPkgTokenSpaceGuid.PcdHttpGetRetry
+  gEfiRedfishPkgTokenSpaceGuid.PcdHttpPutRetry
+  gEfiRedfishPkgTokenSpaceGuid.PcdHttpPatchRetry
+  gEfiRedfishPkgTokenSpaceGuid.PcdHttpPostRetry
+  gEfiRedfishPkgTokenSpaceGuid.PcdHttpDeleteRetry
+  gEfiRedfishPkgTokenSpaceGuid.PcdHttpRetryWaitInSecond
+  gEfiRedfishPkgTokenSpaceGuid.PcdHttpCacheDisabled
+  gEfiRedfishPkgTokenSpaceGuid.PcdRedfishServiceContentEncoding
+
+[Depex]
+  TRUE
diff --git a/RedfishPkg/RedfishHttpDxe/RedfishHttpData.h b/RedfishPkg/RedfishHttpDxe/RedfishHttpData.h
new file mode 100644
index 0000000000..6be610142e
--- /dev/null
+++ b/RedfishPkg/RedfishHttpDxe/RedfishHttpData.h
@@ -0,0 +1,256 @@
+/** @file
+  Definitions of RedfishHttpData
+
+  Copyright (c) 2023-2024, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef EDKII_REDFISH_HTTP_DATA_H_
+#define EDKII_REDFISH_HTTP_DATA_H_
+
+#include "RedfishHttpDxe.h"
+
+#define REDFISH_HTTP_DRIVER_SIGNATURE   SIGNATURE_32 ('r', 'f', 'h', 'p')
+#define REDFISH_HTTP_CACHE_SIGNATURE    SIGNATURE_32 ('r', 'f', 'c', 'h')
+#define REDFISH_HTTP_SERVICE_SIGNATURE  SIGNATURE_32 ('r', 'f', 's', 'v')
+#define REDFISH_HTTP_PAYLOAD_SIGNATURE  SIGNATURE_32 ('r', 'f', 'p', 'l')
+#define REDFISH_HTTP_BASIC_AUTH_STR     "Basic "
+
+///
+/// REDFISH_SERVICE_PRIVATE definition.
+///
+typedef struct {
+  UINT32                  Signature;
+  CHAR8                   *Host;
+  CHAR8                   *HostName;
+  CHAR8                   *BasicAuth;
+  CHAR8                   *SessionToken;
+  EFI_REST_EX_PROTOCOL    *RestEx;
+} REDFISH_SERVICE_PRIVATE;
+
+///
+/// REDFISH_PAYLOAD_PRIVATE definition.
+///
+typedef struct {
+  UINT32                     Signature;
+  REDFISH_SERVICE_PRIVATE    *Service;
+  EDKII_JSON_VALUE           JsonValue;
+} REDFISH_PAYLOAD_PRIVATE;
+
+///
+/// Definition of REDFISH_HTTP_CACHE_DATA
+///
+typedef struct {
+  UINT32              Signature;
+  LIST_ENTRY          List;
+  EFI_STRING          Uri;
+  UINTN               HitCount;
+  REDFISH_RESPONSE    *Response;
+} REDFISH_HTTP_CACHE_DATA;
+
+#define REDFISH_HTTP_CACHE_FROM_LIST(a)  CR (a, REDFISH_HTTP_CACHE_DATA, List, REDFISH_HTTP_CACHE_SIGNATURE)
+
+///
+/// Definition of REDFISH_HTTP_CACHE_LIST
+///
+typedef struct {
+  LIST_ENTRY    Head;
+  UINTN         Count;
+  UINTN         Capacity;
+} REDFISH_HTTP_CACHE_LIST;
+
+///
+/// Definition of REDFISH_HTTP_RETRY_SETTING
+///
+typedef struct {
+  UINT16    MaximumRetryGet;
+  UINT16    MaximumRetryPut;
+  UINT16    MaximumRetryPost;
+  UINT16    MaximumRetryPatch;
+  UINT16    MaximumRetryDelete;
+  UINTN     RetryWait;
+} REDFISH_HTTP_RETRY_SETTING;
+
+///
+/// Definition of REDFISH_HTTP_CACHE_PRIVATE
+///
+typedef struct {
+  UINT32                               Signature;
+  EFI_HANDLE                           ImageHandle;
+  BOOLEAN                              CacheDisabled;
+  EFI_EVENT                            NotifyEvent;
+  REDFISH_HTTP_CACHE_LIST              CacheList;
+  EDKII_REDFISH_HTTP_PROTOCOL          Protocol;
+  EDKII_REDFISH_CREDENTIAL_PROTOCOL    *CredentialProtocol;
+  REDFISH_HTTP_RETRY_SETTING           RetrySetting;
+} REDFISH_HTTP_CACHE_PRIVATE;
+
+#define REDFISH_HTTP_CACHE_PRIVATE_FROM_THIS(a)  CR (a, REDFISH_HTTP_CACHE_PRIVATE, Protocol, REDFISH_HTTP_DRIVER_SIGNATURE)
+
+/**
+  Search on given ListHeader for given URI string.
+
+  @param[in]    ListHeader  Target list to search.
+  @param[in]    Uri         Target URI to search.
+
+  @retval REDFISH_HTTP_CACHE_DATA   Target cache data is found.
+  @retval NULL                      No cache data with given URI is found.
+
+**/
+REDFISH_HTTP_CACHE_DATA *
+FindHttpCacheData (
+  IN  LIST_ENTRY  *ListHeader,
+  IN  EFI_STRING  Uri
+  );
+
+/**
+  This function copy the data in SrcResponse to DstResponse.
+
+  @param[in]  SrcResponse      Source Response to copy.
+  @param[out] DstResponse      Destination Response.
+
+  @retval     EFI_SUCCESS      Response is copied successfully.
+  @retval     Others           Error occurs.
+
+**/
+EFI_STATUS
+CopyRedfishResponse (
+  IN  REDFISH_RESPONSE  *SrcResponse,
+  OUT REDFISH_RESPONSE  *DstResponse
+  );
+
+/**
+  Release all cache from list.
+
+  @param[in]    CacheList    The list to be released.
+
+  @retval EFI_SUCCESS             All cache data are released.
+  @retval EFI_INVALID_PARAMETER   CacheList is NULL.
+
+**/
+EFI_STATUS
+ReleaseCacheList (
+  IN  REDFISH_HTTP_CACHE_LIST  *CacheList
+  );
+
+/**
+  Add new cache by given URI and HTTP response to specify List.
+
+  @param[in]    List      Target cache list to add.
+  @param[in]    Uri       The URI string matching to this cache data.
+  @param[in]    Response  HTTP response.
+
+  @retval EFI_SUCCESS   Cache data is added.
+  @retval Others        Fail to add cache data.
+
+**/
+EFI_STATUS
+AddHttpCacheData (
+  IN  REDFISH_HTTP_CACHE_LIST  *List,
+  IN  EFI_STRING               Uri,
+  IN  REDFISH_RESPONSE         *Response
+  );
+
+/**
+  Delete a cache data by given cache instance.
+
+  @param[in]    List    Target cache list to be removed.
+  @param[in]    Data    Pointer to the instance to be deleted.
+
+  @retval EFI_SUCCESS   Cache data is removed.
+  @retval Others        Fail to remove cache data.
+
+**/
+EFI_STATUS
+DeleteHttpCacheData (
+  IN  REDFISH_HTTP_CACHE_LIST  *List,
+  IN  REDFISH_HTTP_CACHE_DATA  *Data
+  );
+
+/**
+  This function release Redfish Payload.
+
+  @param[in]  Payload         Pointer to payload instance.
+
+  @retval     EFI_SUCCESS     Payload is released.
+  @retval     Others          Error occurs.
+
+**/
+EFI_STATUS
+ReleaseRedfishPayload (
+  IN REDFISH_PAYLOAD_PRIVATE  *Payload
+  );
+
+/**
+  This function creat new payload. Server and JsonObj are
+  copied to newly created payload.
+
+  @param[in]  Service          Pointer to Service instance.
+  @param[in]  JsonObj          Pointer to JSON object.
+
+  @retval     REDFISH_PAYLOAD_PRIVATE  Newly created payload.
+  @retval     NULL             Error occurs.
+
+**/
+REDFISH_PAYLOAD_PRIVATE *
+CreateRedfishPayload (
+  IN REDFISH_SERVICE_PRIVATE  *Service,
+  IN EDKII_JSON_VALUE         JsonValue
+  );
+
+/**
+  This function release Redfish Service.
+
+  @param[in]  Service         Pointer to service instance.
+
+  @retval     EFI_SUCCESS     Service is released.
+  @retval     Others          Error occurs.
+
+**/
+EFI_STATUS
+ReleaseRedfishService (
+  IN REDFISH_SERVICE_PRIVATE  *Service
+  );
+
+/**
+  This function creat new service. Host and HostName are copied to
+  newly created service instance.
+
+  @param[in]  Host            Host string.
+  @param[in]  HostName        Hostname string.
+  @param[in]  BasicAuth       Basic Authorization string.
+  @param[in]  SessionToken    Session token string.
+  @param[in]  RestEx          Rest EX protocol instance.
+
+  @retval     REDFISH_PAYLOAD_PRIVATE  Newly created service.
+  @retval     NULL             Error occurs.
+
+**/
+REDFISH_SERVICE_PRIVATE *
+CreateRedfishService (
+  IN CHAR8                 *Host,
+  IN CHAR8                 *HostName,
+  IN CHAR8                 *BasicAuth OPTIONAL,
+  IN CHAR8                 *SessionToken OPTIONAL,
+  IN EFI_REST_EX_PROTOCOL  *RestEx
+  );
+
+/**
+  This function update session token in Redfish Service.
+
+  @param[in]  Service         Pointer to service instance.
+  @param[in]  Token           Session token.
+
+  @retval     EFI_SUCCESS     Session token is updated.
+  @retval     Others          Error occurs.
+
+**/
+EFI_STATUS
+UpdateSessionToken (
+  IN REDFISH_SERVICE_PRIVATE  *Service,
+  IN CHAR8                    *Token
+  );
+
+#endif
diff --git a/RedfishPkg/RedfishHttpDxe/RedfishHttpDxe.h b/RedfishPkg/RedfishHttpDxe/RedfishHttpDxe.h
new file mode 100644
index 0000000000..cf6ba9cb47
--- /dev/null
+++ b/RedfishPkg/RedfishHttpDxe/RedfishHttpDxe.h
@@ -0,0 +1,44 @@
+/** @file
+  Definitions of RedfishHttpDxe
+
+  Copyright (c) 2023-2024, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef EDKII_REDFISH_HTTP_DXE_H_
+#define EDKII_REDFISH_HTTP_DXE_H_
+
+#include <Uefi.h>
+#include <IndustryStandard/Http11.h>
+
+#include <Library/UefiLib.h>
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/RedfishContentCodingLib.h>
+#include <Library/DebugLib.h>
+#include <Library/HttpLib.h>
+#include <Library/JsonLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/RedfishDebugLib.h>
+#include <Library/ReportStatusCodeLib.h>
+#include <Library/PrintLib.h>
+
+#include <Protocol/Http.h>
+#include <Protocol/EdkIIRedfishHttpProtocol.h>
+#include <Protocol/EdkIIRedfishCredential.h>
+#include <Protocol/RestEx.h>
+
+#define IS_EMPTY_STRING(a)  ((a) == NULL || (a)[0] == '\0')
+#define REDFISH_HTTP_CACHE_LIST_SIZE      0x80
+#define REDFISH_ERROR_MSG_MAX             128
+#define REDFISH_DEBUG_STRING_LENGTH       200
+#define REDFISH_HOST_NAME_MAX             64   // IPv6 maximum length (39) + "https://" (8) + port number (maximum 5)
+#define REDFISH_HTTP_ERROR_REPORT         "Redfish HTTP %a failure(0x%x): %s"
+#define REDFISH_HTTP_CACHE_DEBUG          DEBUG_MANAGEABILITY
+#define REDFISH_HTTP_CACHE_DEBUG_DUMP     DEBUG_MANAGEABILITY
+#define REDFISH_HTTP_CACHE_DEBUG_REQUEST  DEBUG_MANAGEABILITY
+
+#endif
diff --git a/RedfishPkg/RedfishHttpDxe/RedfishHttpOperation.h b/RedfishPkg/RedfishHttpDxe/RedfishHttpOperation.h
new file mode 100644
index 0000000000..d2f7cf4c27
--- /dev/null
+++ b/RedfishPkg/RedfishHttpDxe/RedfishHttpOperation.h
@@ -0,0 +1,76 @@
+/** @file
+  Definitions of RedfishHttpOperation
+
+  Copyright (c) 2024, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef EDKII_REDFISH_HTTP_OPERATION_H_
+#define EDKII_REDFISH_HTTP_OPERATION_H_
+
+#include "RedfishHttpDxe.h"
+
+#define REDFISH_CONTENT_LENGTH_SIZE              80
+#define REDFISH_COMMON_HEADER_SIZE               5
+#define REDFISH_HTTP_HEADER_ODATA_VERSION_STR    "OData-Version"
+#define REDFISH_HTTP_HEADER_ODATA_VERSION_VALUE  "4.0"
+#define REDFISH_HTTP_HEADER_USER_AGENT_VALUE     "edk2redfish"
+#define REDFISH_HTTP_HEADER_CONNECTION_STR       "Connection"
+#define REDFISH_HTTP_HEADER_CONNECTION_VALUE     "Keep-Alive"
+#define REDFISH_HTTP_CONTENT_ENCODING_NONE       "None"
+
+/**
+  This function free resources in Request. Request is no longer available
+  after this function returns successfully.
+
+  @param[in]  Request      HTTP request to be released.
+
+  @retval     EFI_SUCCESS     Resrouce is released successfully.
+  @retval     Others          Errors occur.
+
+**/
+EFI_STATUS
+ReleaseRedfishRequest (
+  IN  REDFISH_REQUEST  *Request
+  );
+
+/**
+  This function free resources in given Response.
+
+  @param[in]  Response     HTTP response to be released.
+
+  @retval     EFI_SUCCESS     Resrouce is released successfully.
+  @retval     Others          Errors occur.
+
+**/
+EFI_STATUS
+ReleaseRedfishResponse (
+  IN  REDFISH_RESPONSE  *Response
+  );
+
+/**
+  This function send Redfish request to Redfish service by calling
+  Rest Ex protocol.
+
+  @param[in]   Service       Pointer to Redfish service.
+  @param[in]   Uri           Uri of Redfish service.
+  @param[in]   Method        HTTP method.
+  @param[in]   Request     Request data. This is optional.
+  @param[out]  Response    Redfish response data.
+
+  @retval     EFI_SUCCESS     Request is sent and received successfully.
+  @retval     Others          Errors occur.
+
+**/
+EFI_STATUS
+HttpSendReceive (
+  IN  REDFISH_SERVICE   Service,
+  IN  EFI_STRING        Uri,
+  IN  EFI_HTTP_METHOD   Method,
+  IN  REDFISH_REQUEST   *Request  OPTIONAL,
+  OUT REDFISH_RESPONSE  *Response
+  );
+
+#endif
diff --git a/RedfishPkg/RedfishHttpDxe/RedfishHttpData.c b/RedfishPkg/RedfishHttpDxe/RedfishHttpData.c
new file mode 100644
index 0000000000..bf95e9f8d4
--- /dev/null
+++ b/RedfishPkg/RedfishHttpDxe/RedfishHttpData.c
@@ -0,0 +1,667 @@
+/** @file
+  RedfishHttpData handles internal data to support Redfish HTTP protocol.
+
+  Copyright (c) 2023-2024, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "RedfishHttpData.h"
+#include "RedfishHttpOperation.h"
+
+/**
+  This function update session token in Redfish Service.
+
+  @param[in]  Service         Pointer to service instance.
+  @param[in]  Token           Session token.
+
+  @retval     EFI_SUCCESS     Session token is updated.
+  @retval     Others          Error occurs.
+
+**/
+EFI_STATUS
+UpdateSessionToken (
+  IN REDFISH_SERVICE_PRIVATE  *Service,
+  IN CHAR8                    *Token
+  )
+{
+  if ((Service == NULL) || IS_EMPTY_STRING (Token)) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  if (Service->SessionToken != NULL) {
+    FreePool (Service->SessionToken);
+  }
+
+  Service->SessionToken = AllocateCopyPool (AsciiStrSize (Token), Token);
+  if (Service->SessionToken == NULL) {
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  return EFI_SUCCESS;
+}
+
+/**
+  This function release Redfish Service.
+
+  @param[in]  Service         Pointer to service instance.
+
+  @retval     EFI_SUCCESS     Service is released.
+  @retval     Others          Error occurs.
+
+**/
+EFI_STATUS
+ReleaseRedfishService (
+  IN REDFISH_SERVICE_PRIVATE  *Service
+  )
+{
+  if (Service == NULL) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  if (Service->Host != NULL) {
+    FreePool (Service->Host);
+  }
+
+  if (Service->HostName != NULL) {
+    FreePool (Service->HostName);
+  }
+
+  if (Service->BasicAuth != NULL) {
+    ZeroMem (Service->BasicAuth, AsciiStrSize (Service->BasicAuth));
+    FreePool (Service->BasicAuth);
+  }
+
+  if (Service->SessionToken != NULL) {
+    ZeroMem (Service->SessionToken, AsciiStrSize (Service->SessionToken));
+    FreePool (Service->SessionToken);
+  }
+
+  FreePool (Service);
+
+  return EFI_SUCCESS;
+}
+
+/**
+  This function creat new service. Host and HostName are copied to
+  newly created service instance.
+
+  @param[in]  Host            Host string.
+  @param[in]  HostName        Hostname string.
+  @param[in]  BasicAuth       Basic Authorization string.
+  @param[in]  SessionToken    Session token string.
+  @param[in]  RestEx          Rest EX protocol instance.
+
+  @retval     REDFISH_PAYLOAD_PRIVATE  Newly created service.
+  @retval     NULL             Error occurs.
+
+**/
+REDFISH_SERVICE_PRIVATE *
+CreateRedfishService (
+  IN CHAR8                 *Host,
+  IN CHAR8                 *HostName,
+  IN CHAR8                 *BasicAuth OPTIONAL,
+  IN CHAR8                 *SessionToken OPTIONAL,
+  IN EFI_REST_EX_PROTOCOL  *RestEx
+  )
+{
+  REDFISH_SERVICE_PRIVATE  *NewService;
+  UINTN                    AuthStrSize;
+
+  if (IS_EMPTY_STRING (Host) || IS_EMPTY_STRING (HostName) || (RestEx == NULL)) {
+    return NULL;
+  }
+
+  NewService = AllocateZeroPool (sizeof (REDFISH_SERVICE_PRIVATE));
+  if (NewService == NULL) {
+    return NULL;
+  }
+
+  NewService->Signature = REDFISH_HTTP_SERVICE_SIGNATURE;
+  NewService->Host      = AllocateCopyPool (AsciiStrSize (Host), Host);
+  if (NewService->Host == NULL) {
+    goto ON_ERROR;
+  }
+
+  NewService->HostName = AllocateCopyPool (AsciiStrSize (HostName), HostName);
+  if (NewService->HostName == NULL) {
+    goto ON_ERROR;
+  }
+
+  if (!IS_EMPTY_STRING (BasicAuth)) {
+    AuthStrSize           = AsciiStrSize (BasicAuth) + AsciiStrLen (REDFISH_HTTP_BASIC_AUTH_STR);
+    NewService->BasicAuth = AllocateZeroPool (AuthStrSize);
+    if (NewService->BasicAuth == NULL) {
+      goto ON_ERROR;
+    }
+
+    AsciiSPrint (NewService->BasicAuth, AuthStrSize, "%a%a", REDFISH_HTTP_BASIC_AUTH_STR, BasicAuth);
+  }
+
+  if (!IS_EMPTY_STRING (SessionToken)) {
+    NewService->SessionToken = AllocateCopyPool (AsciiStrSize (SessionToken), SessionToken);
+    if (NewService->SessionToken == NULL) {
+      goto ON_ERROR;
+    }
+  }
+
+  NewService->RestEx = RestEx;
+
+  return NewService;
+
+ON_ERROR:
+
+  ReleaseRedfishService (NewService);
+
+  return NULL;
+}
+
+/**
+  This function release Redfish Payload.
+
+  @param[in]  Payload         Pointer to payload instance.
+
+  @retval     EFI_SUCCESS     Payload is released.
+  @retval     Others          Error occurs.
+
+**/
+EFI_STATUS
+ReleaseRedfishPayload (
+  IN REDFISH_PAYLOAD_PRIVATE  *Payload
+  )
+{
+  if (Payload == NULL) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  if (Payload->Service != NULL) {
+    ReleaseRedfishService (Payload->Service);
+  }
+
+  if (Payload->JsonValue != NULL) {
+    JsonValueFree (Payload->JsonValue);
+  }
+
+  FreePool (Payload);
+
+  return EFI_SUCCESS;
+}
+
+/**
+  This function creat new payload. Server and JsonObj are
+  copied to newly created payload.
+
+  @param[in]  Service          Pointer to Service instance.
+  @param[in]  JsonValue        Pointer to JSON value.
+
+  @retval     REDFISH_PAYLOAD_PRIVATE  Newly created payload.
+  @retval     NULL                     Error occurs.
+
+**/
+REDFISH_PAYLOAD_PRIVATE *
+CreateRedfishPayload (
+  IN REDFISH_SERVICE_PRIVATE  *Service,
+  IN EDKII_JSON_VALUE         JsonValue
+  )
+{
+  REDFISH_PAYLOAD_PRIVATE  *NewPayload;
+
+  if ((Service == NULL) || (JsonValue == NULL)) {
+    return NULL;
+  }
+
+  NewPayload = AllocateZeroPool (sizeof (REDFISH_PAYLOAD_PRIVATE));
+  if (NewPayload == NULL) {
+    return NULL;
+  }
+
+  NewPayload->Signature = REDFISH_HTTP_PAYLOAD_SIGNATURE;
+  NewPayload->Service   = CreateRedfishService (Service->Host, Service->HostName, Service->BasicAuth, Service->SessionToken, Service->RestEx);
+  if (NewPayload->Service == NULL) {
+    goto ON_ERROR;
+  }
+
+  NewPayload->JsonValue = JsonValueClone (JsonValue);
+  if (NewPayload->JsonValue == NULL) {
+    goto ON_ERROR;
+  }
+
+  return NewPayload;
+
+ON_ERROR:
+
+  ReleaseRedfishPayload (NewPayload);
+
+  return NULL;
+}
+
+/**
+  This function copy the data in SrcResponse to DstResponse.
+
+  @param[in]  SrcResponse      Source Response to copy.
+  @param[out] DstResponse      Destination Response.
+
+  @retval     EFI_SUCCESS      Response is copied successfully.
+  @retval     Others           Error occurs.
+
+**/
+EFI_STATUS
+CopyRedfishResponse (
+  IN  REDFISH_RESPONSE  *SrcResponse,
+  OUT REDFISH_RESPONSE  *DstResponse
+  )
+{
+  REDFISH_PAYLOAD_PRIVATE  *Payload;
+  UINTN                    Index;
+
+  if ((SrcResponse == NULL) || (DstResponse == NULL)) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  if (SrcResponse == DstResponse) {
+    return EFI_SUCCESS;
+  }
+
+  //
+  // Status code
+  //
+  if (SrcResponse->StatusCode != NULL) {
+    DstResponse->StatusCode = AllocateCopyPool (sizeof (EFI_HTTP_STATUS_CODE), SrcResponse->StatusCode);
+    if (DstResponse->StatusCode == NULL) {
+      goto ON_ERROR;
+    }
+  }
+
+  //
+  // Header
+  //
+  if ((SrcResponse->HeaderCount > 0) && (SrcResponse->Headers != NULL)) {
+    DstResponse->HeaderCount = 0;
+    DstResponse->Headers     = AllocateZeroPool (sizeof (EFI_HTTP_HEADER) * SrcResponse->HeaderCount);
+    if (DstResponse->Headers == NULL) {
+      goto ON_ERROR;
+    }
+
+    for (Index = 0; Index < SrcResponse->HeaderCount; Index++) {
+      DstResponse->Headers[Index].FieldName = AllocateCopyPool (AsciiStrSize (SrcResponse->Headers[Index].FieldName), SrcResponse->Headers[Index].FieldName);
+      if (DstResponse->Headers[Index].FieldName == NULL) {
+        goto ON_ERROR;
+      }
+
+      DstResponse->Headers[Index].FieldValue = AllocateCopyPool (AsciiStrSize (SrcResponse->Headers[Index].FieldValue), SrcResponse->Headers[Index].FieldValue);
+      if (DstResponse->Headers[Index].FieldValue == NULL) {
+        goto ON_ERROR;
+      }
+
+      DstResponse->HeaderCount += 1;
+    }
+  }
+
+  //
+  // Payload
+  //
+  if (SrcResponse->Payload != NULL) {
+    Payload = (REDFISH_PAYLOAD_PRIVATE *)SrcResponse->Payload;
+    if (Payload->Signature != REDFISH_HTTP_PAYLOAD_SIGNATURE) {
+      DEBUG ((DEBUG_ERROR, "%a: signature check failure\n", __func__));
+      goto ON_ERROR;
+    }
+
+    DstResponse->Payload = CreateRedfishPayload (Payload->Service, Payload->JsonValue);
+    if (DstResponse->Payload  == NULL) {
+      goto ON_ERROR;
+    }
+  }
+
+  return EFI_SUCCESS;
+
+ON_ERROR:
+
+  ReleaseRedfishResponse (DstResponse);
+
+  return EFI_OUT_OF_RESOURCES;
+}
+
+/**
+  This function clone input response and return to caller
+
+  @param[in]  Response      Response to clone.
+
+  @retval     REDFISH_RESPONSE *  Response is cloned.
+  @retval     NULL                Errors occur.
+
+**/
+REDFISH_RESPONSE *
+CloneRedfishResponse (
+  IN REDFISH_RESPONSE  *Response
+  )
+{
+  EFI_STATUS        Status;
+  REDFISH_RESPONSE  *NewResponse;
+
+  if (Response == NULL) {
+    return NULL;
+  }
+
+  NewResponse = AllocateZeroPool (sizeof (REDFISH_RESPONSE));
+  if (NewResponse == NULL) {
+    return NULL;
+  }
+
+  Status = CopyRedfishResponse (Response, NewResponse);
+  if (EFI_ERROR (Status)) {
+    FreePool (NewResponse);
+    return NULL;
+  }
+
+  return NewResponse;
+}
+
+/**
+  Release REDFISH_HTTP_CACHE_DATA resource
+
+  @param[in]    Data    Pointer to REDFISH_HTTP_CACHE_DATA instance
+
+  @retval EFI_SUCCESS             REDFISH_HTTP_CACHE_DATA is released successfully.
+  @retval EFI_INVALID_PARAMETER   Data is NULL
+
+**/
+EFI_STATUS
+ReleaseHttpCacheData (
+  IN REDFISH_HTTP_CACHE_DATA  *Data
+  )
+{
+  if (Data == NULL) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  if (Data->Uri != NULL) {
+    FreePool (Data->Uri);
+  }
+
+  if (Data->Response != NULL) {
+    ReleaseRedfishResponse (Data->Response);
+    FreePool (Data->Response);
+  }
+
+  FreePool (Data);
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Create new cache data.
+
+  @param[in]    Uri       The URI string matching to this cache data.
+  @param[in]    Response  HTTP response.
+
+  @retval REDFISH_HTTP_CACHE_DATA *   Pointer to newly created cache data.
+  @retval NULL                        No memory available.
+
+**/
+REDFISH_HTTP_CACHE_DATA *
+NewHttpCacheData (
+  IN  EFI_STRING        Uri,
+  IN  REDFISH_RESPONSE  *Response
+  )
+{
+  REDFISH_HTTP_CACHE_DATA  *NewData;
+  UINTN                    Size;
+
+  if (IS_EMPTY_STRING (Uri) || (Response == NULL)) {
+    return NULL;
+  }
+
+  NewData = AllocateZeroPool (sizeof (REDFISH_HTTP_CACHE_DATA));
+  if (NewData == NULL) {
+    return NULL;
+  }
+
+  NewData->Signature = REDFISH_HTTP_CACHE_SIGNATURE;
+  Size               = StrSize (Uri);
+  NewData->Uri       = AllocateCopyPool (Size, Uri);
+  if (NewData->Uri == NULL) {
+    goto ON_ERROR;
+  }
+
+  NewData->Response = Response;
+  NewData->HitCount = 1;
+
+  return NewData;
+
+ON_ERROR:
+
+  if (NewData != NULL) {
+    ReleaseHttpCacheData (NewData);
+  }
+
+  return NULL;
+}
+
+/**
+  Search on given ListHeader for given URI string.
+
+  @param[in]    ListHeader  Target list to search.
+  @param[in]    Uri         Target URI to search.
+
+  @retval REDFISH_HTTP_CACHE_DATA   Target cache data is found.
+  @retval NULL                      No cache data with given URI is found.
+
+**/
+REDFISH_HTTP_CACHE_DATA *
+FindHttpCacheData (
+  IN  LIST_ENTRY  *ListHeader,
+  IN  EFI_STRING  Uri
+  )
+{
+  LIST_ENTRY               *List;
+  REDFISH_HTTP_CACHE_DATA  *Data;
+
+  if (IS_EMPTY_STRING (Uri)) {
+    return NULL;
+  }
+
+  if (IsListEmpty (ListHeader)) {
+    return NULL;
+  }
+
+  Data = NULL;
+  List = GetFirstNode (ListHeader);
+  while (!IsNull (ListHeader, List)) {
+    Data = REDFISH_HTTP_CACHE_FROM_LIST (List);
+
+    if (StrCmp (Data->Uri, Uri) == 0) {
+      return Data;
+    }
+
+    List = GetNextNode (ListHeader, List);
+  }
+
+  return NULL;
+}
+
+/**
+  Search on given ListHeader and return cache data with minimum hit count.
+
+  @param[in]    ListHeader  Target list to search.
+
+  @retval REDFISH_HTTP_CACHE_DATA   Target cache data is returned.
+  @retval NULL                      No cache data is found.
+
+**/
+REDFISH_HTTP_CACHE_DATA *
+FindUnusedHttpCacheData (
+  IN  LIST_ENTRY  *ListHeader
+  )
+{
+  LIST_ENTRY               *List;
+  REDFISH_HTTP_CACHE_DATA  *Data;
+  REDFISH_HTTP_CACHE_DATA  *UnusedData;
+  UINTN                    HitCount;
+
+  if (IsListEmpty (ListHeader)) {
+    return NULL;
+  }
+
+  Data       = NULL;
+  UnusedData = NULL;
+  HitCount   = 0;
+
+  List       = GetFirstNode (ListHeader);
+  Data       = REDFISH_HTTP_CACHE_FROM_LIST (List);
+  UnusedData = Data;
+  HitCount   = Data->HitCount;
+  List       = GetNextNode (ListHeader, List);
+
+  while (!IsNull (ListHeader, List)) {
+    Data = REDFISH_HTTP_CACHE_FROM_LIST (List);
+
+    if (Data->HitCount < HitCount) {
+      HitCount   = Data->HitCount;
+      UnusedData = Data;
+    }
+
+    List = GetNextNode (ListHeader, List);
+  }
+
+  return UnusedData;
+}
+
+/**
+  Delete a cache data by given cache instance.
+
+  @param[in]    List    Target cache list to be removed.
+  @param[in]    Data    Pointer to the instance to be deleted.
+
+  @retval EFI_SUCCESS   Cache data is removed.
+  @retval Others        Fail to remove cache data.
+
+**/
+EFI_STATUS
+DeleteHttpCacheData (
+  IN  REDFISH_HTTP_CACHE_LIST  *List,
+  IN  REDFISH_HTTP_CACHE_DATA  *Data
+  )
+{
+  if ((List == NULL) || (Data == NULL)) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  DEBUG ((REDFISH_HTTP_CACHE_DEBUG, "%a: delete: %s\n", __func__, Data->Uri));
+
+  RemoveEntryList (&Data->List);
+  --List->Count;
+
+  return ReleaseHttpCacheData (Data);
+}
+
+/**
+  Add new cache by given URI and HTTP response to specify List.
+
+  @param[in]    List      Target cache list to add.
+  @param[in]    Uri       The URI string matching to this cache data.
+  @param[in]    Response  HTTP response.
+
+  @retval EFI_SUCCESS   Cache data is added.
+  @retval Others        Fail to add cache data.
+
+**/
+EFI_STATUS
+AddHttpCacheData (
+  IN  REDFISH_HTTP_CACHE_LIST  *List,
+  IN  EFI_STRING               Uri,
+  IN  REDFISH_RESPONSE         *Response
+  )
+{
+  REDFISH_HTTP_CACHE_DATA  *NewData;
+  REDFISH_HTTP_CACHE_DATA  *OldData;
+  REDFISH_HTTP_CACHE_DATA  *UnusedData;
+  REDFISH_RESPONSE         *NewResponse;
+
+  if ((List == NULL) || IS_EMPTY_STRING (Uri) || (Response == NULL)) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  //
+  // If same cache data exist, replace it with latest one.
+  //
+  OldData = FindHttpCacheData (&List->Head, Uri);
+  if (OldData != NULL) {
+    DeleteHttpCacheData (List, OldData);
+  }
+
+  //
+  // Check capacity
+  //
+  if (List->Count >= List->Capacity) {
+    DEBUG ((REDFISH_HTTP_CACHE_DEBUG, "%a: list is full and retire unused cache\n", __func__));
+    UnusedData = FindUnusedHttpCacheData (&List->Head);
+    if (UnusedData == NULL) {
+      return EFI_OUT_OF_RESOURCES;
+    }
+
+    DeleteHttpCacheData (List, UnusedData);
+  }
+
+  //
+  // Clone a local copy
+  //
+  NewResponse = CloneRedfishResponse (Response);
+  if (NewResponse == NULL) {
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  NewData = NewHttpCacheData (Uri, NewResponse);
+  if (NewData == NULL) {
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  InsertTailList (&List->Head, &NewData->List);
+  ++List->Count;
+
+  DEBUG ((REDFISH_HTTP_CACHE_DEBUG, "%a: cache(%d/%d) %s\n", __func__, List->Count, List->Capacity, NewData->Uri));
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Release all cache from list.
+
+  @param[in]    CacheList    The list to be released.
+
+  @retval EFI_SUCCESS             All cache data are released.
+  @retval EFI_INVALID_PARAMETER   CacheList is NULL.
+
+**/
+EFI_STATUS
+ReleaseCacheList (
+  IN  REDFISH_HTTP_CACHE_LIST  *CacheList
+  )
+{
+  LIST_ENTRY               *List;
+  LIST_ENTRY               *Next;
+  REDFISH_HTTP_CACHE_DATA  *Data;
+
+  if (CacheList == NULL) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  if (IsListEmpty (&CacheList->Head)) {
+    return EFI_SUCCESS;
+  }
+
+  Data = NULL;
+  Next = NULL;
+  List = GetFirstNode (&CacheList->Head);
+  while (!IsNull (&CacheList->Head, List)) {
+    Data = REDFISH_HTTP_CACHE_FROM_LIST (List);
+    Next = GetNextNode (&CacheList->Head, List);
+
+    DeleteHttpCacheData (CacheList, Data);
+
+    List = Next;
+  }
+
+  return EFI_SUCCESS;
+}
diff --git a/RedfishPkg/RedfishHttpDxe/RedfishHttpDxe.c b/RedfishPkg/RedfishHttpDxe/RedfishHttpDxe.c
new file mode 100644
index 0000000000..39958d4865
--- /dev/null
+++ b/RedfishPkg/RedfishHttpDxe/RedfishHttpDxe.c
@@ -0,0 +1,1344 @@
+/** @file
+  RedfishHttpDxe produces EdkIIRedfishHttpProtocol
+  for EDK2 Redfish Feature driver to do HTTP operations.
+
+  Copyright (c) 2023-2024, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "RedfishHttpDxe.h"
+#include "RedfishHttpData.h"
+#include "RedfishHttpOperation.h"
+
+REDFISH_HTTP_CACHE_PRIVATE  *mRedfishHttpCachePrivate = NULL;
+
+/**
+  Debug output the cache list.
+
+  @param[in]    Msg            Debug message string.
+  @param[in]    ErrorLevel     Output error level.
+  @param[in]    CacheList      Target list to dump.
+
+  @retval EFI_SUCCESS             Debug dump finished.
+  @retval EFI_INVALID_PARAMETER   HttpCacheList is NULL.
+
+**/
+EFI_STATUS
+DebugPrintHttpCacheList (
+  IN  CONST CHAR8              *Msg,
+  IN  UINTN                    ErrorLevel,
+  IN  REDFISH_HTTP_CACHE_LIST  *CacheList
+  )
+{
+  LIST_ENTRY               *List;
+  REDFISH_HTTP_CACHE_DATA  *Data;
+  UINTN                    Index;
+
+  if (CacheList == NULL) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  if (!IS_EMPTY_STRING (Msg)) {
+    DEBUG ((ErrorLevel, "%a\n", Msg));
+  }
+
+  if (IsListEmpty (&CacheList->Head)) {
+    DEBUG ((ErrorLevel, "list is empty\n"));
+    return EFI_NOT_FOUND;
+  }
+
+  DEBUG ((ErrorLevel, "list count: %d capacity: %d\n", CacheList->Count, CacheList->Capacity));
+  Data  = NULL;
+  Index = 0;
+  List  = GetFirstNode (&CacheList->Head);
+  while (!IsNull (&CacheList->Head, List)) {
+    Data = REDFISH_HTTP_CACHE_FROM_LIST (List);
+
+    DEBUG ((ErrorLevel, "%d) Uri: %s Hit: %d\n", ++Index, Data->Uri, Data->HitCount));
+
+    List = GetNextNode (&CacheList->Head, List);
+  }
+
+  return EFI_SUCCESS;
+}
+
+/**
+
+  Check HTTP status code to see if we like to retry HTTP request or not.
+
+  @param[in]  StatusCode      HTTP status code.
+
+  @retval     BOOLEAN         Return true when we like to retry request.
+                              Return false when we don't want to retry request.
+
+**/
+BOOLEAN
+RedfishRetryRequired (
+  IN EFI_HTTP_STATUS_CODE  *StatusCode
+  )
+{
+  if (StatusCode == NULL) {
+    return TRUE;
+  }
+
+  if ((*StatusCode == HTTP_STATUS_500_INTERNAL_SERVER_ERROR) ||
+      (*StatusCode == HTTP_STATUS_UNSUPPORTED_STATUS))
+  {
+    return TRUE;
+  }
+
+  return FALSE;
+}
+
+/**
+
+  Convert Unicode string to ASCII string. It's call responsibility to release returned buffer.
+
+  @param[in]  UnicodeStr      Unicode string to convert.
+
+  @retval     CHAR8 *         ASCII string returned.
+  @retval     NULL            Errors occur.
+
+**/
+CHAR8 *
+StringUnicodeToAscii (
+  IN EFI_STRING  UnicodeStr
+  )
+{
+  CHAR8       *AsciiStr;
+  UINTN       AsciiStrSize;
+  EFI_STATUS  Status;
+
+  if (IS_EMPTY_STRING (UnicodeStr)) {
+    return NULL;
+  }
+
+  AsciiStrSize = StrLen (UnicodeStr) + 1;
+  AsciiStr     = AllocateZeroPool (AsciiStrSize);
+  if (AsciiStr == NULL) {
+    return NULL;
+  }
+
+  Status = UnicodeStrToAsciiStrS (UnicodeStr, AsciiStr, AsciiStrSize);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "UnicodeStrToAsciiStrS failed: %r\n", Status));
+    FreePool (AsciiStr);
+    return NULL;
+  }
+
+  return AsciiStr;
+}
+
+/**
+  Return HTTP method in ASCII string. Caller does not need
+  to free returned string buffer.
+
+  @param[in]  Method         HTTP method.
+
+  @retval CHAR8 *   Method in string.
+**/
+CHAR8 *
+HttpMethodToString (
+  IN  EFI_HTTP_METHOD  Method
+  )
+{
+  switch (Method) {
+    case HttpMethodGet:
+      return HTTP_METHOD_GET;
+      break;
+    case HttpMethodPost:
+      return HTTP_METHOD_POST;
+      break;
+    case HttpMethodPatch:
+      return HTTP_METHOD_PATCH;
+      break;
+    case HttpMethodPut:
+      return HTTP_METHOD_PUT;
+      break;
+    case HttpMethodDelete:
+      return HTTP_METHOD_DELETE;
+      break;
+    default:
+      break;
+  }
+
+  return "Unknown";
+}
+
+/**
+  Report HTTP communication error via report status code.
+
+  @param[in]  Method         HTTP method.
+  @param[in]  Uri            The URI which has failure.
+  @param[in]  HttpStatusCode HTTP status code.
+
+**/
+VOID
+ReportHttpError (
+  IN  EFI_HTTP_METHOD       Method,
+  IN  EFI_STRING            Uri,
+  IN  EFI_HTTP_STATUS_CODE  *HttpStatusCode  OPTIONAL
+  )
+{
+  CHAR8  ErrorMsg[REDFISH_ERROR_MSG_MAX];
+
+  if (IS_EMPTY_STRING (Uri)) {
+    DEBUG ((DEBUG_ERROR, "%a: no URI to report error status\n", __func__));
+    return;
+  }
+
+  //
+  // Report failure of URI and HTTP status code.
+  //
+  AsciiSPrint (ErrorMsg, sizeof (ErrorMsg), REDFISH_HTTP_ERROR_REPORT, HttpMethodToString (Method), (HttpStatusCode == NULL ? HTTP_STATUS_UNSUPPORTED_STATUS : *HttpStatusCode), Uri);
+  DEBUG ((DEBUG_ERROR, "%a\n", ErrorMsg));
+  //
+  // TODO:
+  // Below PI status code is approved by PIWG and wait for specification published.
+  // We will uncomment below report status code after PI status code get published.
+  // REF: https://bugzilla.tianocore.org/show_bug.cgi?id=4483
+  //
+  // REPORT_STATUS_CODE_WITH_EXTENDED_DATA (
+  //  EFI_ERROR_CODE | EFI_ERROR_MAJOR,
+  //  EFI_COMPUTING_UNIT_MANAGEABILITY | EFI_MANAGEABILITY_EC_REDFISH_COMMUNICATION_ERROR,
+  //  ErrorMsg,
+  //  AsciiStrSize (ErrorMsg)
+  //  );
+}
+
+/**
+  This function create Redfish service. It's caller's responsibility to free returned
+  Redfish service by calling FreeService ().
+
+  @param[in]  This                       Pointer to EDKII_REDFISH_HTTP_PROTOCOL instance.
+  @param[in]  RedfishConfigServiceInfo   Redfish config service information.
+
+  @retval     REDFISH_SERVICE  Redfish service is created.
+  @retval     NULL             Errors occur.
+
+**/
+REDFISH_SERVICE
+EFIAPI
+RedfishCreateRedfishService (
+  IN  EDKII_REDFISH_HTTP_PROTOCOL         *This,
+  IN  REDFISH_CONFIG_SERVICE_INFORMATION  *RedfishConfigServiceInfo
+  )
+{
+  EFI_STATUS                  Status;
+  REDFISH_HTTP_CACHE_PRIVATE  *Private;
+  REDFISH_SERVICE_PRIVATE     *NewService;
+  CHAR8                       *AsciiLocation;
+  CHAR8                       *Host;
+  CHAR8                       *BasicAuthString;
+  UINTN                       BasicAuthStrSize;
+  CHAR8                       *EncodedAuthString;
+  UINTN                       EncodedAuthStrSize;
+  EDKII_REDFISH_AUTH_METHOD   AuthMethod;
+  CHAR8                       *Username;
+  CHAR8                       *Password;
+  UINTN                       UsernameSize;
+  UINTN                       PasswordSize;
+  EFI_REST_EX_PROTOCOL        *RestEx;
+
+  if ((This == NULL) || (RedfishConfigServiceInfo == NULL)) {
+    return NULL;
+  }
+
+  DEBUG ((REDFISH_HTTP_CACHE_DEBUG, "%a: service location: %s\n", __func__, RedfishConfigServiceInfo->RedfishServiceLocation));
+
+  Private            = REDFISH_HTTP_CACHE_PRIVATE_FROM_THIS (This);
+  BasicAuthString    = NULL;
+  EncodedAuthString  = NULL;
+  Username           = NULL;
+  Password           = NULL;
+  NewService         = NULL;
+  AsciiLocation      = NULL;
+  Host               = NULL;
+  BasicAuthStrSize   = 0;
+  EncodedAuthStrSize = 0;
+  UsernameSize       = 0;
+  PasswordSize       = 0;
+
+  //
+  // Build host and host name from service location
+  //
+  if (!IS_EMPTY_STRING (RedfishConfigServiceInfo->RedfishServiceLocation)) {
+    AsciiLocation = StringUnicodeToAscii (RedfishConfigServiceInfo->RedfishServiceLocation);
+    if (AsciiLocation == NULL) {
+      goto ON_RELEASE;
+    }
+
+    Host = AllocateZeroPool (REDFISH_HOST_NAME_MAX);
+    if (AsciiLocation == NULL) {
+      goto ON_RELEASE;
+    }
+
+    if (RedfishConfigServiceInfo->RedfishServiceUseHttps) {
+      AsciiSPrint (Host, REDFISH_HOST_NAME_MAX, "https://%a", AsciiLocation);
+    } else {
+      AsciiSPrint (Host, REDFISH_HOST_NAME_MAX, "http://%a", AsciiLocation);
+    }
+
+    DEBUG ((REDFISH_HTTP_CACHE_DEBUG, "%a: Host: %a\n", __func__, Host));
+  }
+
+  //
+  // Find Rest Ex protocol
+  //
+  if (RedfishConfigServiceInfo->RedfishServiceRestExHandle != NULL) {
+    Status = gBS->HandleProtocol (
+                    RedfishConfigServiceInfo->RedfishServiceRestExHandle,
+                    &gEfiRestExProtocolGuid,
+                    (VOID **)&RestEx
+                    );
+  } else {
+    DEBUG ((DEBUG_ERROR, "%a: Rest Ex protocol is not available\n", __func__));
+    goto ON_RELEASE;
+  }
+
+  //
+  // Get credential
+  //
+  if (Private->CredentialProtocol == NULL) {
+    //
+    // No credential available on this system.
+    //
+    DEBUG ((DEBUG_WARN, "%a: no credential protocol available\n", __func__));
+  } else {
+    Status = Private->CredentialProtocol->GetAuthInfo (
+                                            Private->CredentialProtocol,
+                                            &AuthMethod,
+                                            &Username,
+                                            &Password
+                                            );
+    if (EFI_ERROR (Status) || IS_EMPTY_STRING (Username) || IS_EMPTY_STRING (Password)) {
+      DEBUG ((DEBUG_ERROR, "%a: cannot get authentication information: %r\n", __func__, Status));
+      goto ON_RELEASE;
+    } else {
+      DEBUG ((REDFISH_HTTP_CACHE_DEBUG, "%a: Auth method: 0x%x username: %a password: %a\n", __func__, AuthMethod, Username, Password));
+
+      //
+      // Perform base64 encoding (RFC 7617)
+      //
+      UsernameSize     = AsciiStrSize (Username);
+      PasswordSize     = AsciiStrSize (Password);
+      BasicAuthStrSize =  UsernameSize + PasswordSize;  // one byte taken from null-terminator for ':'
+      BasicAuthString  = AllocateZeroPool (BasicAuthStrSize);
+      if (BasicAuthString == NULL) {
+        goto ON_RELEASE;
+      }
+
+      AsciiSPrint (
+        BasicAuthString,
+        BasicAuthStrSize,
+        "%a:%a",
+        Username,
+        Password
+        );
+
+      Status = Base64Encode (
+                 (CONST UINT8 *)BasicAuthString,
+                 BasicAuthStrSize,
+                 EncodedAuthString,
+                 &EncodedAuthStrSize
+                 );
+      if ((Status == EFI_BUFFER_TOO_SMALL) && (EncodedAuthStrSize > 0)) {
+        EncodedAuthString = AllocateZeroPool (EncodedAuthStrSize);
+        if (EncodedAuthString == NULL) {
+          goto ON_RELEASE;
+        }
+
+        Status = Base64Encode (
+                   (CONST UINT8 *)BasicAuthString,
+                   BasicAuthStrSize,
+                   EncodedAuthString,
+                   &EncodedAuthStrSize
+                   );
+        if (EFI_ERROR (Status)) {
+          DEBUG ((DEBUG_ERROR, "%a: Base64Encode failure: %r\n", __func__, Status));
+        }
+
+        DEBUG ((REDFISH_HTTP_CACHE_DEBUG, "%a: Basic authorization: %a\n", __func__, EncodedAuthString));
+      } else {
+        DEBUG ((DEBUG_ERROR, "%a: Base64Encode failure: %r\n", __func__, Status));
+        goto ON_RELEASE;
+      }
+    }
+  }
+
+  NewService = CreateRedfishService (Host, AsciiLocation, EncodedAuthString, NULL, RestEx);
+  if (NewService == NULL) {
+    DEBUG ((DEBUG_ERROR, "%a: CreateRedfishService\n", __func__));
+  }
+
+ON_RELEASE:
+
+  if (BasicAuthString != NULL) {
+    ZeroMem (BasicAuthString, BasicAuthStrSize);
+    FreePool (BasicAuthString);
+  }
+
+  if (EncodedAuthString != NULL) {
+    ZeroMem (BasicAuthString, EncodedAuthStrSize);
+    FreePool (EncodedAuthString);
+  }
+
+  if (Username != NULL) {
+    ZeroMem (Username, UsernameSize);
+    FreePool (Username);
+  }
+
+  if (Password != NULL) {
+    ZeroMem (Password, PasswordSize);
+    FreePool (Password);
+  }
+
+  if (AsciiLocation != NULL) {
+    FreePool (AsciiLocation);
+  }
+
+  if (Host != NULL) {
+    FreePool (Host);
+  }
+
+  return NewService;
+}
+
+/**
+  This function free resources in Redfish service. RedfishService is no longer available
+  after this function returns successfully.
+
+  @param[in]  This            Pointer to EDKII_REDFISH_HTTP_PROTOCOL instance.
+  @param[in]  RedfishService  Pointer to Redfish service to be released.
+
+  @retval     EFI_SUCCESS     Resrouce is released successfully.
+  @retval     Others          Errors occur.
+
+**/
+EFI_STATUS
+EFIAPI
+RedfishFreeRedfishService (
+  IN  EDKII_REDFISH_HTTP_PROTOCOL  *This,
+  IN  REDFISH_SERVICE              RedfishService
+  )
+{
+  REDFISH_SERVICE_PRIVATE  *Service;
+
+  if ((This == NULL) || (RedfishService == NULL)) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  Service = (REDFISH_SERVICE_PRIVATE *)RedfishService;
+  if (Service->Signature != REDFISH_HTTP_SERVICE_SIGNATURE) {
+    DEBUG ((DEBUG_ERROR, "%a: signature check failure\n", __func__));
+  }
+
+  return ReleaseRedfishService (Service);
+}
+
+/**
+  This function returns JSON value in given RedfishPayload. Returned JSON value
+  is a reference to the JSON value in RedfishPayload. Any modification to returned
+  JSON value will change JSON value in RedfishPayload.
+
+  @param[in]  This            Pointer to EDKII_REDFISH_HTTP_PROTOCOL instance.
+  @param[in]  RedfishPayload  Pointer to Redfish payload.
+
+  @retval     EDKII_JSON_VALUE   JSON value is returned.
+  @retval     NULL               Errors occur.
+
+**/
+EDKII_JSON_VALUE
+EFIAPI
+RedfishJsonInRedfishPayload (
+  IN  EDKII_REDFISH_HTTP_PROTOCOL  *This,
+  IN  REDFISH_PAYLOAD              RedfishPayload
+  )
+{
+  REDFISH_PAYLOAD_PRIVATE  *Payload;
+
+  if ((This == NULL) || (RedfishPayload == NULL)) {
+    return NULL;
+  }
+
+  Payload = (REDFISH_PAYLOAD_PRIVATE *)RedfishPayload;
+  if (Payload->Signature != REDFISH_HTTP_PAYLOAD_SIGNATURE) {
+    DEBUG ((DEBUG_ERROR, "%a: signature check failure\n", __func__));
+  }
+
+  return Payload->JsonValue;
+}
+
+/**
+  Perform HTTP GET to Get redfish resource from given resource URI with
+  cache mechanism supported. It's caller's responsibility to free Response
+  by calling FreeResponse ().
+
+  @param[in]  This          Pointer to EDKII_REDFISH_HTTP_PROTOCOL instance.
+  @param[in]  Service       Redfish service instance to perform HTTP GET.
+  @param[in]  Uri           Target resource URI.
+  @param[in]  Request       Additional request context. This is optional.
+  @param[out] Response      HTTP response from redfish service.
+  @param[in]  UseCache      If it is TRUE, this function will search for
+                            cache first. If it is FALSE, this function
+                            will query Redfish URI directly.
+
+  @retval     EFI_SUCCESS     Resrouce is returned successfully.
+  @retval     Others          Errors occur.
+
+**/
+EFI_STATUS
+EFIAPI
+RedfishGetResource (
+  IN  EDKII_REDFISH_HTTP_PROTOCOL  *This,
+  IN  REDFISH_SERVICE              Service,
+  IN  EFI_STRING                   Uri,
+  IN  REDFISH_REQUEST              *Request OPTIONAL,
+  OUT REDFISH_RESPONSE             *Response,
+  IN  BOOLEAN                      UseCache
+  )
+{
+  EFI_STATUS                  Status;
+  REDFISH_HTTP_CACHE_DATA     *CacheData;
+  UINTN                       RetryCount;
+  REDFISH_HTTP_CACHE_PRIVATE  *Private;
+
+  if ((This == NULL) || (Service == NULL) || (Response == NULL) || IS_EMPTY_STRING (Uri)) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  DEBUG ((REDFISH_HTTP_CACHE_DEBUG, "%a: Get URI: %s cache: %a\n", __func__, Uri, (UseCache ? "true" : "false")));
+
+  Private    = REDFISH_HTTP_CACHE_PRIVATE_FROM_THIS (This);
+  CacheData  = NULL;
+  RetryCount = 0;
+  ZeroMem (Response, sizeof (REDFISH_RESPONSE));
+
+  if (Private->CacheDisabled) {
+    UseCache = FALSE;
+    DEBUG ((REDFISH_HTTP_CACHE_DEBUG, "%a: cache is disabled by PCD!\n", __func__));
+  }
+
+  //
+  // Search for cache list.
+  //
+  if (UseCache) {
+    CacheData = FindHttpCacheData (&Private->CacheList.Head, Uri);
+    if (CacheData != NULL) {
+      DEBUG ((REDFISH_HTTP_CACHE_DEBUG_REQUEST, "%a: cache hit! %s\n", __func__, Uri));
+
+      //
+      // Copy cached response to caller's buffer.
+      //
+      Status               = CopyRedfishResponse (CacheData->Response, Response);
+      CacheData->HitCount += 1;
+      return Status;
+    }
+  }
+
+  //
+  // Get resource from redfish service.
+  //
+  do {
+    RetryCount += 1;
+    Status      = HttpSendReceive (
+                    Service,
+                    Uri,
+                    HttpMethodGet,
+                    Request,
+                    Response
+                    );
+    DEBUG ((REDFISH_HTTP_CACHE_DEBUG_REQUEST, "%a: HTTP request: %s :%r\n", __func__, Uri, Status));
+    if (!EFI_ERROR (Status) || (RetryCount >= Private->RetrySetting.MaximumRetryGet)) {
+      break;
+    }
+
+    //
+    // Retry when BMC is not ready.
+    //
+    if ((Response->StatusCode != NULL)) {
+      DEBUG_CODE (
+        DumpRedfishResponse (NULL, DEBUG_ERROR, Response);
+        );
+
+      if (!RedfishRetryRequired (Response->StatusCode)) {
+        break;
+      }
+
+      //
+      // Release response for next round of request.
+      //
+      This->FreeResponse (This, Response);
+    }
+
+    DEBUG ((DEBUG_WARN, "%a: RedfishGetByUriEx failed, retry (%d/%d)\n", __func__, RetryCount, Private->RetrySetting.MaximumRetryGet));
+    if (Private->RetrySetting.RetryWait > 0) {
+      gBS->Stall (Private->RetrySetting.RetryWait);
+    }
+  } while (TRUE);
+
+  if (EFI_ERROR (Status)) {
+    DEBUG_CODE (
+      DumpRedfishResponse (NULL, DEBUG_ERROR, Response);
+      );
+    //
+    // Report status code for Redfish failure
+    //
+    ReportHttpError (HttpMethodGet, Uri, Response->StatusCode);
+    DEBUG ((DEBUG_ERROR, "%a: get %s failed (%d/%d): %r\n", __func__, Uri, RetryCount, Private->RetrySetting.MaximumRetryGet, Status));
+    goto ON_RELEASE;
+  }
+
+  if (!Private->CacheDisabled) {
+    //
+    // Keep response in cache list
+    //
+    Status = AddHttpCacheData (&Private->CacheList, Uri, Response);
+    if (EFI_ERROR (Status)) {
+      DEBUG ((DEBUG_ERROR, "%a: failed to cache %s: %r\n", __func__, Uri, Status));
+      goto ON_RELEASE;
+    }
+
+    DEBUG_CODE (
+      DebugPrintHttpCacheList (__func__, REDFISH_HTTP_CACHE_DEBUG_DUMP, &Private->CacheList);
+      );
+  }
+
+ON_RELEASE:
+
+  return Status;
+}
+
+/**
+  This function free resources in Request. Request is no longer available
+  after this function returns successfully.
+
+  @param[in]  This         Pointer to EDKII_REDFISH_HTTP_PROTOCOL instance.
+  @param[in]  Request      HTTP request to be released.
+
+  @retval     EFI_SUCCESS     Resrouce is released successfully.
+  @retval     Others          Errors occur.
+
+**/
+EFI_STATUS
+EFIAPI
+RedfishFreeRequest (
+  IN  EDKII_REDFISH_HTTP_PROTOCOL  *This,
+  IN  REDFISH_REQUEST              *Request
+  )
+{
+  if ((This == NULL) || (Request == NULL)) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  DEBUG ((REDFISH_HTTP_CACHE_DEBUG, "%a: entry\n", __func__));
+
+  return ReleaseRedfishRequest (Request);
+}
+
+/**
+  This function free resources in given Response.
+
+  @param[in]  This         Pointer to EDKII_REDFISH_HTTP_PROTOCOL instance.
+  @param[in]  Response     HTTP response to be released.
+
+  @retval     EFI_SUCCESS     Resrouce is released successfully.
+  @retval     Others          Errors occur.
+
+**/
+EFI_STATUS
+EFIAPI
+RedfishFreeResponse (
+  IN  EDKII_REDFISH_HTTP_PROTOCOL  *This,
+  IN  REDFISH_RESPONSE             *Response
+  )
+{
+  if ((This == NULL) || (Response == NULL)) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  DEBUG ((REDFISH_HTTP_CACHE_DEBUG, "%a: entry\n", __func__));
+
+  return ReleaseRedfishResponse (Response);
+}
+
+/**
+  This function expire the cached response of given URI.
+
+  @param[in]  This         Pointer to EDKII_REDFISH_HTTP_PROTOCOL instance.
+  @param[in]  Uri          Target response of URI.
+
+  @retval     EFI_SUCCESS     Target response is expired successfully.
+  @retval     Others          Errors occur.
+
+**/
+EFI_STATUS
+EFIAPI
+RedfishExpireResponse (
+  IN  EDKII_REDFISH_HTTP_PROTOCOL  *This,
+  IN  EFI_STRING                   Uri
+  )
+{
+  REDFISH_HTTP_CACHE_PRIVATE  *Private;
+  REDFISH_HTTP_CACHE_DATA     *CacheData;
+
+  if ((This == NULL) || IS_EMPTY_STRING (Uri)) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  DEBUG ((REDFISH_HTTP_CACHE_DEBUG, "%a: expire URI: %s\n", __func__, Uri));
+
+  Private = REDFISH_HTTP_CACHE_PRIVATE_FROM_THIS (This);
+
+  CacheData = FindHttpCacheData (&Private->CacheList.Head, Uri);
+  if (CacheData == NULL) {
+    return EFI_NOT_FOUND;
+  }
+
+  return DeleteHttpCacheData (&Private->CacheList, CacheData);
+}
+
+/**
+  Perform HTTP PATCH to send redfish resource to given resource URI.
+  It's caller's responsibility to free Response by calling FreeResponse ().
+
+  @param[in]  This          Pointer to EDKII_REDFISH_HTTP_PROTOCOL instance.
+  @param[in]  Service       Redfish service instance to perform HTTP PATCH.
+  @param[in]  Uri           Target resource URI.
+  @param[in]  Content       Data to patch.
+  @param[in]  ContentSize   Size of the Content to be send to Redfish service.
+                            This is optional. When ContentSize is 0, ContentSize
+                            is the size of Content.
+  @param[in]  ContentType   Type of the Content to be send to Redfish service.
+                            This is optional. When ContentType is NULL, content
+                            type HTTP_CONTENT_TYPE_APP_JSON will be used.
+  @param[out] Response      HTTP response from redfish service.
+
+  @retval     EFI_SUCCESS     Resrouce is returned successfully.
+  @retval     Others          Errors occur.
+
+**/
+EFI_STATUS
+EFIAPI
+RedfishPatchResource (
+  IN  EDKII_REDFISH_HTTP_PROTOCOL  *This,
+  IN  REDFISH_SERVICE              Service,
+  IN  EFI_STRING                   Uri,
+  IN  CHAR8                        *Content,
+  IN  UINTN                        ContentSize OPTIONAL,
+  IN  CHAR8                        *ContentType OPTIONAL,
+  OUT REDFISH_RESPONSE             *Response
+  )
+{
+  EFI_STATUS                  Status;
+  UINTN                       RetryCount;
+  REDFISH_REQUEST             Request;
+  REDFISH_HTTP_CACHE_PRIVATE  *Private;
+
+  if ((This == NULL) || (Service == NULL) || (Response == NULL) || IS_EMPTY_STRING (Uri) || IS_EMPTY_STRING (Content)) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  DEBUG ((REDFISH_HTTP_CACHE_DEBUG, "%a: Patch URI: %s\n", __func__, Uri));
+
+  Private    = REDFISH_HTTP_CACHE_PRIVATE_FROM_THIS (This);
+  RetryCount = 0;
+  ZeroMem (Response, sizeof (REDFISH_RESPONSE));
+  ZeroMem (&Request, sizeof (REDFISH_REQUEST));
+
+  Request.Content       = Content;
+  Request.ContentLength = ContentSize;
+  Request.ContentType   = ContentType;
+
+  //
+  // Patch resource to redfish service.
+  //
+  do {
+    RetryCount += 1;
+    Status      = HttpSendReceive (
+                    Service,
+                    Uri,
+                    HttpMethodPatch,
+                    &Request,
+                    Response
+                    );
+    DEBUG ((REDFISH_HTTP_CACHE_DEBUG_REQUEST, "%a: HTTP request: %s :%r\n", __func__, Uri, Status));
+    if (!EFI_ERROR (Status) || (RetryCount >= Private->RetrySetting.MaximumRetryPatch)) {
+      break;
+    }
+
+    //
+    // Retry when BMC is not ready.
+    //
+    if ((Response->StatusCode != NULL)) {
+      DEBUG_CODE (
+        DumpRedfishResponse (NULL, DEBUG_ERROR, Response);
+        );
+
+      if (!RedfishRetryRequired (Response->StatusCode)) {
+        break;
+      }
+
+      //
+      // Release response for next round of request.
+      //
+      This->FreeResponse (This, Response);
+    }
+
+    DEBUG ((DEBUG_WARN, "%a: RedfishPatchToUriEx failed, retry (%d/%d)\n", __func__, RetryCount, Private->RetrySetting.MaximumRetryPatch));
+    if (Private->RetrySetting.RetryWait > 0) {
+      gBS->Stall (Private->RetrySetting.RetryWait);
+    }
+  } while (TRUE);
+
+  //
+  // Redfish resource is updated. Automatically expire the cached response
+  // so application can directly get resource from Redfish service again.
+  //
+  DEBUG ((REDFISH_HTTP_CACHE_DEBUG, "%a: Resource is updated, expire URI: %s\n", __func__, Uri));
+  RedfishExpireResponse (This, Uri);
+
+  if (EFI_ERROR (Status)) {
+    DEBUG_CODE (
+      DumpRedfishResponse (NULL, DEBUG_ERROR, Response);
+      );
+    //
+    // Report status code for Redfish failure
+    //
+    ReportHttpError (HttpMethodPatch, Uri, Response->StatusCode);
+    DEBUG ((DEBUG_ERROR, "%a: patch %s failed (%d/%d): %r\n", __func__, Uri, RetryCount, Private->RetrySetting.MaximumRetryPatch, Status));
+    goto ON_RELEASE;
+  }
+
+ON_RELEASE:
+
+  return Status;
+}
+
+/**
+  Perform HTTP PUT to send redfish resource to given resource URI.
+  It's caller's responsibility to free Response by calling FreeResponse ().
+
+  @param[in]  This          Pointer to EDKII_REDFISH_HTTP_PROTOCOL instance.
+  @param[in]  Service       Redfish service instance to perform HTTP PUT.
+  @param[in]  Uri           Target resource URI.
+  @param[in]  Content       Data to put.
+  @param[in]  ContentSize   Size of the Content to be send to Redfish service.
+                            This is optional. When ContentSize is 0, ContentSize
+                            is the size of Content.
+  @param[in]  ContentType   Type of the Content to be send to Redfish service.
+                            This is optional. When ContentType is NULL, content
+                            type HTTP_CONTENT_TYPE_APP_JSON will be used.
+  @param[out] Response      HTTP response from redfish service.
+
+  @retval     EFI_SUCCESS     Resrouce is returned successfully.
+  @retval     Others          Errors occur.
+
+**/
+EFI_STATUS
+EFIAPI
+RedfishPutResource (
+  IN  EDKII_REDFISH_HTTP_PROTOCOL  *This,
+  IN  REDFISH_SERVICE              Service,
+  IN  EFI_STRING                   Uri,
+  IN  CHAR8                        *Content,
+  IN  UINTN                        ContentSize OPTIONAL,
+  IN  CHAR8                        *ContentType OPTIONAL,
+  OUT REDFISH_RESPONSE             *Response
+  )
+{
+  EFI_STATUS                  Status;
+  UINTN                       RetryCount;
+  REDFISH_REQUEST             Request;
+  REDFISH_HTTP_CACHE_PRIVATE  *Private;
+
+  if ((This == NULL) || (Service == NULL) || (Response == NULL) || IS_EMPTY_STRING (Uri) || IS_EMPTY_STRING (Content)) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  DEBUG ((REDFISH_HTTP_CACHE_DEBUG, "%a: Put URI: %s\n", __func__, Uri));
+
+  Private    = REDFISH_HTTP_CACHE_PRIVATE_FROM_THIS (This);
+  RetryCount = 0;
+  ZeroMem (Response, sizeof (REDFISH_RESPONSE));
+  ZeroMem (&Request, sizeof (REDFISH_REQUEST));
+
+  Request.Content       = Content;
+  Request.ContentLength = ContentSize;
+  Request.ContentType   = ContentType;
+
+  //
+  // Patch resource to redfish service.
+  //
+  do {
+    RetryCount += 1;
+    Status      = HttpSendReceive (
+                    Service,
+                    Uri,
+                    HttpMethodPut,
+                    &Request,
+                    Response
+                    );
+    DEBUG ((REDFISH_HTTP_CACHE_DEBUG_REQUEST, "%a: HTTP request: %s :%r\n", __func__, Uri, Status));
+    if (!EFI_ERROR (Status) || (RetryCount >= Private->RetrySetting.MaximumRetryPut)) {
+      break;
+    }
+
+    //
+    // Retry when BMC is not ready.
+    //
+    if ((Response->StatusCode != NULL)) {
+      DEBUG_CODE (
+        DumpRedfishResponse (NULL, DEBUG_ERROR, Response);
+        );
+
+      if (!RedfishRetryRequired (Response->StatusCode)) {
+        break;
+      }
+
+      //
+      // Release response for next round of request.
+      //
+      This->FreeResponse (This, Response);
+    }
+
+    DEBUG ((DEBUG_WARN, "%a: RedfishPutToUri failed, retry (%d/%d)\n", __func__, RetryCount, Private->RetrySetting.MaximumRetryPut));
+    if (Private->RetrySetting.RetryWait > 0) {
+      gBS->Stall (Private->RetrySetting.RetryWait);
+    }
+  } while (TRUE);
+
+  //
+  // Redfish resource is updated. Automatically expire the cached response
+  // so application can directly get resource from Redfish service again.
+  //
+  DEBUG ((REDFISH_HTTP_CACHE_DEBUG, "%a: Resource is updated, expire URI: %s\n", __func__, Uri));
+  RedfishExpireResponse (This, Uri);
+
+  if (EFI_ERROR (Status)) {
+    DEBUG_CODE (
+      DumpRedfishResponse (NULL, DEBUG_ERROR, Response);
+      );
+    //
+    // Report status code for Redfish failure
+    //
+    ReportHttpError (HttpMethodPut, Uri, Response->StatusCode);
+    DEBUG ((DEBUG_ERROR, "%a: put %s failed (%d/%d): %r\n", __func__, Uri, RetryCount, Private->RetrySetting.MaximumRetryPut, Status));
+    goto ON_RELEASE;
+  }
+
+ON_RELEASE:
+
+  return Status;
+}
+
+/**
+  Perform HTTP POST to send redfish resource to given resource URI.
+  It's caller's responsibility to free Response by calling FreeResponse ().
+
+  @param[in]  This          Pointer to EDKII_REDFISH_HTTP_PROTOCOL instance.
+  @param[in]  Service       Redfish service instance to perform HTTP POST.
+  @param[in]  Uri           Target resource URI.
+  @param[in]  Content       Data to post.
+  @param[in]  ContentSize   Size of the Content to be send to Redfish service.
+                            This is optional. When ContentSize is 0, ContentSize
+                            is the size of Content.
+  @param[in]  ContentType   Type of the Content to be send to Redfish service.
+                            This is optional. When ContentType is NULL, content
+                            type HTTP_CONTENT_TYPE_APP_JSON will be used.
+  @param[out] Response      HTTP response from redfish service.
+
+  @retval     EFI_SUCCESS     Resrouce is returned successfully.
+  @retval     Others          Errors occur.
+
+**/
+EFI_STATUS
+EFIAPI
+RedfishPostResource (
+  IN  EDKII_REDFISH_HTTP_PROTOCOL  *This,
+  IN  REDFISH_SERVICE              Service,
+  IN  EFI_STRING                   Uri,
+  IN  CHAR8                        *Content,
+  IN  UINTN                        ContentSize OPTIONAL,
+  IN  CHAR8                        *ContentType OPTIONAL,
+  OUT REDFISH_RESPONSE             *Response
+  )
+{
+  EFI_STATUS                  Status;
+  UINTN                       RetryCount;
+  REDFISH_REQUEST             Request;
+  REDFISH_HTTP_CACHE_PRIVATE  *Private;
+
+  if ((This == NULL) || (Service == NULL) || (Response == NULL) || IS_EMPTY_STRING (Uri) || IS_EMPTY_STRING (Content)) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  DEBUG ((REDFISH_HTTP_CACHE_DEBUG, "%a: Post URI: %s\n", __func__, Uri));
+
+  Private    = REDFISH_HTTP_CACHE_PRIVATE_FROM_THIS (This);
+  RetryCount = 0;
+  ZeroMem (Response, sizeof (REDFISH_RESPONSE));
+  ZeroMem (&Request, sizeof (REDFISH_REQUEST));
+
+  Request.Content       = Content;
+  Request.ContentLength = ContentSize;
+  Request.ContentType   = ContentType;
+
+  //
+  // Patch resource to redfish service.
+  //
+  do {
+    RetryCount += 1;
+    Status      = HttpSendReceive (
+                    Service,
+                    Uri,
+                    HttpMethodPost,
+                    &Request,
+                    Response
+                    );
+    DEBUG ((REDFISH_HTTP_CACHE_DEBUG_REQUEST, "%a: HTTP request: %s :%r\n", __func__, Uri, Status));
+    if (!EFI_ERROR (Status) || (RetryCount >= Private->RetrySetting.MaximumRetryPost)) {
+      break;
+    }
+
+    //
+    // Retry when BMC is not ready.
+    //
+    if ((Response->StatusCode != NULL)) {
+      DEBUG_CODE (
+        DumpRedfishResponse (NULL, DEBUG_ERROR, Response);
+        );
+
+      if (!RedfishRetryRequired (Response->StatusCode)) {
+        break;
+      }
+
+      //
+      // Release response for next round of request.
+      //
+      This->FreeResponse (This, Response);
+    }
+
+    DEBUG ((DEBUG_WARN, "%a: RedfishPostToUri failed, retry (%d/%d)\n", __func__, RetryCount, Private->RetrySetting.MaximumRetryPost));
+    if (Private->RetrySetting.RetryWait > 0) {
+      gBS->Stall (Private->RetrySetting.RetryWait);
+    }
+  } while (TRUE);
+
+  //
+  // Redfish resource is updated. Automatically expire the cached response
+  // so application can directly get resource from Redfish service again.
+  //
+  DEBUG ((REDFISH_HTTP_CACHE_DEBUG, "%a: Resource is updated, expire URI: %s\n", __func__, Uri));
+  RedfishExpireResponse (This, Uri);
+
+  if (EFI_ERROR (Status)) {
+    DEBUG_CODE (
+      DumpRedfishResponse (NULL, DEBUG_ERROR, Response);
+      );
+    //
+    // Report status code for Redfish failure
+    //
+    ReportHttpError (HttpMethodPost, Uri, Response->StatusCode);
+    DEBUG ((DEBUG_ERROR, "%a: post %s failed (%d/%d): %r\n", __func__, Uri, RetryCount, Private->RetrySetting.MaximumRetryPost, Status));
+    goto ON_RELEASE;
+  }
+
+ON_RELEASE:
+
+  return Status;
+}
+
+/**
+  Perform HTTP DELETE to delete redfish resource on given resource URI.
+  It's caller's responsibility to free Response by calling FreeResponse ().
+
+  @param[in]  This          Pointer to EDKII_REDFISH_HTTP_PROTOCOL instance.
+  @param[in]  Service       Redfish service instance to perform HTTP DELETE.
+  @param[in]  Uri           Target resource URI.
+  @param[in]  Content       JSON represented properties to be deleted. This is
+                            optional.
+  @param[in]  ContentSize   Size of the Content to be send to Redfish service.
+                            This is optional. When ContentSize is 0, ContentSize
+                            is the size of Content if Content is not NULL.
+  @param[in]  ContentType   Type of the Content to be send to Redfish service.
+                            This is optional. When Content is not NULL and
+                            ContentType is NULL, content type HTTP_CONTENT_TYPE_APP_JSON
+                            will be used.
+  @param[out] Response      HTTP response from redfish service.
+
+  @retval     EFI_SUCCESS     Resrouce is returned successfully.
+  @retval     Others          Errors occur.
+
+**/
+EFI_STATUS
+EFIAPI
+RedfishDeleteResource (
+  IN  EDKII_REDFISH_HTTP_PROTOCOL  *This,
+  IN  REDFISH_SERVICE              Service,
+  IN  EFI_STRING                   Uri,
+  IN  CHAR8                        *Content OPTIONAL,
+  IN  UINTN                        ContentSize OPTIONAL,
+  IN  CHAR8                        *ContentType OPTIONAL,
+  OUT REDFISH_RESPONSE             *Response
+  )
+{
+  EFI_STATUS                  Status;
+  UINTN                       RetryCount;
+  REDFISH_REQUEST             Request;
+  REDFISH_HTTP_CACHE_PRIVATE  *Private;
+
+  if ((This == NULL) || (Service == NULL) || (Response == NULL) || IS_EMPTY_STRING (Uri)) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  DEBUG ((REDFISH_HTTP_CACHE_DEBUG, "%a: Delete URI: %s\n", __func__, Uri));
+
+  Private    = REDFISH_HTTP_CACHE_PRIVATE_FROM_THIS (This);
+  RetryCount = 0;
+  ZeroMem (Response, sizeof (REDFISH_RESPONSE));
+  ZeroMem (&Request, sizeof (REDFISH_REQUEST));
+
+  Request.Content       = Content;
+  Request.ContentLength = ContentSize;
+  Request.ContentType   = ContentType;
+
+  //
+  // Patch resource to redfish service.
+  //
+  do {
+    RetryCount += 1;
+    Status      = HttpSendReceive (
+                    Service,
+                    Uri,
+                    HttpMethodDelete,
+                    &Request,
+                    Response
+                    );
+    DEBUG ((REDFISH_HTTP_CACHE_DEBUG_REQUEST, "%a: HTTP request: %s :%r\n", __func__, Uri, Status));
+    if (!EFI_ERROR (Status) || (RetryCount >= Private->RetrySetting.MaximumRetryDelete)) {
+      break;
+    }
+
+    //
+    // Retry when BMC is not ready.
+    //
+    if ((Response->StatusCode != NULL)) {
+      DEBUG_CODE (
+        DumpRedfishResponse (NULL, DEBUG_ERROR, Response);
+        );
+
+      if (!RedfishRetryRequired (Response->StatusCode)) {
+        break;
+      }
+
+      //
+      // Release response for next round of request.
+      //
+      This->FreeResponse (This, Response);
+    }
+
+    DEBUG ((DEBUG_WARN, "%a: RedfishDeleteByUri failed, retry (%d/%d)\n", __func__, RetryCount, Private->RetrySetting.MaximumRetryDelete));
+    if (Private->RetrySetting.RetryWait > 0) {
+      gBS->Stall (Private->RetrySetting.RetryWait);
+    }
+  } while (TRUE);
+
+  //
+  // Redfish resource is updated. Automatically expire the cached response
+  // so application can directly get resource from Redfish service again.
+  //
+  DEBUG ((REDFISH_HTTP_CACHE_DEBUG, "%a: Resource is updated, expire URI: %s\n", __func__, Uri));
+  RedfishExpireResponse (This, Uri);
+
+  if (EFI_ERROR (Status)) {
+    DEBUG_CODE (
+      DumpRedfishResponse (NULL, DEBUG_ERROR, Response);
+      );
+    //
+    // Report status code for Redfish failure
+    //
+    ReportHttpError (HttpMethodDelete, Uri, Response->StatusCode);
+    DEBUG ((DEBUG_ERROR, "%a: delete %s failed (%d/%d): %r\n", __func__, Uri, RetryCount, Private->RetrySetting.MaximumRetryDelete, Status));
+    goto ON_RELEASE;
+  }
+
+ON_RELEASE:
+
+  return Status;
+}
+
+EDKII_REDFISH_HTTP_PROTOCOL  mEdkIIRedfishHttpProtocol = {
+  EDKII_REDFISH_HTTP_PROTOCOL_REVISION,
+  RedfishCreateRedfishService,
+  RedfishFreeRedfishService,
+  RedfishJsonInRedfishPayload,
+  RedfishGetResource,
+  RedfishPatchResource,
+  RedfishPutResource,
+  RedfishPostResource,
+  RedfishDeleteResource,
+  RedfishFreeRequest,
+  RedfishFreeResponse,
+  RedfishExpireResponse
+};
+
+/**
+  Unloads an image.
+
+  @param[in]  ImageHandle         Handle that identifies the image to be unloaded.
+
+  @retval EFI_SUCCESS             The image has been unloaded.
+  @retval EFI_INVALID_PARAMETER   ImageHandle is not a valid image handle.
+
+**/
+EFI_STATUS
+EFIAPI
+RedfishHttpDriverUnload (
+  IN EFI_HANDLE  ImageHandle
+  )
+{
+  if (mRedfishHttpCachePrivate == NULL) {
+    return EFI_SUCCESS;
+  }
+
+  if (!IsListEmpty (&mRedfishHttpCachePrivate->CacheList.Head)) {
+    ReleaseCacheList (&mRedfishHttpCachePrivate->CacheList);
+  }
+
+  gBS->UninstallMultipleProtocolInterfaces (
+         ImageHandle,
+         &gEdkIIRedfishHttpProtocolGuid,
+         &mRedfishHttpCachePrivate->Protocol,
+         NULL
+         );
+
+  FreePool (mRedfishHttpCachePrivate);
+  mRedfishHttpCachePrivate = NULL;
+
+  return EFI_SUCCESS;
+}
+
+/**
+  This is a EDKII_REDFISH_CREDENTIAL_PROTOCOL notification event handler.
+
+  @param[in] Event    Event whose notification function is being invoked.
+  @param[in] Context  Pointer to the notification function's context.
+
+**/
+VOID
+EFIAPI
+CredentialProtocolInstalled (
+  IN  EFI_EVENT  Event,
+  IN  VOID       *Context
+  )
+{
+  EFI_STATUS                  Status;
+  REDFISH_HTTP_CACHE_PRIVATE  *Private;
+
+  Private = (REDFISH_HTTP_CACHE_PRIVATE *)Context;
+  if (Private->Signature != REDFISH_HTTP_DRIVER_SIGNATURE) {
+    DEBUG ((DEBUG_ERROR, "%a: signature check failure\n", __func__));
+    return;
+  }
+
+  //
+  // Locate HII database protocol.
+  //
+  Status = gBS->LocateProtocol (
+                  &gEdkIIRedfishCredentialProtocolGuid,
+                  NULL,
+                  (VOID **)&Private->CredentialProtocol
+                  );
+  if (EFI_ERROR (Status)) {
+    return;
+  }
+
+  gBS->CloseEvent (Event);
+}
+
+/**
+  Main entry for this driver.
+
+  @param[in] ImageHandle     Image handle this driver.
+  @param[in] SystemTable     Pointer to SystemTable.
+
+  @retval EFI_SUCCESS     This function always complete successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+RedfishHttpEntryPoint (
+  IN EFI_HANDLE        ImageHandle,
+  IN EFI_SYSTEM_TABLE  *SystemTable
+  )
+{
+  EFI_STATUS  Status;
+  VOID        *Registration;
+
+  if (mRedfishHttpCachePrivate != NULL) {
+    return EFI_ALREADY_STARTED;
+  }
+
+  mRedfishHttpCachePrivate = AllocateZeroPool (sizeof (REDFISH_HTTP_CACHE_PRIVATE));
+  if (mRedfishHttpCachePrivate == NULL) {
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  //
+  // Initial cache list and protocol instance.
+  //
+  mRedfishHttpCachePrivate->Signature   = REDFISH_HTTP_DRIVER_SIGNATURE;
+  mRedfishHttpCachePrivate->ImageHandle = ImageHandle;
+  CopyMem (&mRedfishHttpCachePrivate->Protocol, &mEdkIIRedfishHttpProtocol, sizeof (EDKII_REDFISH_HTTP_PROTOCOL));
+  mRedfishHttpCachePrivate->CacheList.Capacity = REDFISH_HTTP_CACHE_LIST_SIZE;
+  mRedfishHttpCachePrivate->CacheList.Count    = 0x00;
+  mRedfishHttpCachePrivate->CacheDisabled      = PcdGetBool (PcdHttpCacheDisabled);
+  InitializeListHead (&mRedfishHttpCachePrivate->CacheList.Head);
+
+  //
+  // Get retry settings
+  //
+  mRedfishHttpCachePrivate->RetrySetting.MaximumRetryGet    = PcdGet16 (PcdHttpGetRetry);
+  mRedfishHttpCachePrivate->RetrySetting.MaximumRetryPut    = PcdGet16 (PcdHttpPutRetry);
+  mRedfishHttpCachePrivate->RetrySetting.MaximumRetryPatch  = PcdGet16 (PcdHttpPatchRetry);
+  mRedfishHttpCachePrivate->RetrySetting.MaximumRetryPost   = PcdGet16 (PcdHttpPostRetry);
+  mRedfishHttpCachePrivate->RetrySetting.MaximumRetryDelete = PcdGet16 (PcdHttpDeleteRetry);
+  mRedfishHttpCachePrivate->RetrySetting.RetryWait          = PcdGet16 (PcdHttpRetryWaitInSecond) * 1000000U;
+
+  //
+  // Install the gEdkIIRedfishHttpProtocolGuid onto Handle.
+  //
+  Status = gBS->InstallMultipleProtocolInterfaces (
+                  &mRedfishHttpCachePrivate->ImageHandle,
+                  &gEdkIIRedfishHttpProtocolGuid,
+                  &mRedfishHttpCachePrivate->Protocol,
+                  NULL
+                  );
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "%a: cannot install Redfish http protocol: %r\n", __func__, Status));
+    RedfishHttpDriverUnload (ImageHandle);
+    return Status;
+  }
+
+  //
+  // Install protocol notification if credential protocol is installed.
+  //
+  mRedfishHttpCachePrivate->NotifyEvent = EfiCreateProtocolNotifyEvent (
+                                            &gEdkIIRedfishCredentialProtocolGuid,
+                                            TPL_CALLBACK,
+                                            CredentialProtocolInstalled,
+                                            mRedfishHttpCachePrivate,
+                                            &Registration
+                                            );
+  if (mRedfishHttpCachePrivate->NotifyEvent == NULL) {
+    DEBUG ((DEBUG_ERROR, "%a: failed to create protocol notification for gEdkIIRedfishCredentialProtocolGuid\n", __func__));
+    ASSERT (FALSE);
+    RedfishHttpDriverUnload (ImageHandle);
+    return Status;
+  }
+
+  return EFI_SUCCESS;
+}
diff --git a/RedfishPkg/RedfishHttpDxe/RedfishHttpOperation.c b/RedfishPkg/RedfishHttpDxe/RedfishHttpOperation.c
new file mode 100644
index 0000000000..5652818d16
--- /dev/null
+++ b/RedfishPkg/RedfishHttpDxe/RedfishHttpOperation.c
@@ -0,0 +1,693 @@
+/** @file
+  RedfishHttpOperation handles HTTP operations.
+
+  Copyright (c) 2024, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "RedfishHttpOperation.h"
+#include "RedfishHttpData.h"
+
+/**
+  This function copies all headers in SrcHeaders to DstHeaders.
+  It's call responsibility to release returned DstHeaders.
+
+  @param[in]  SrcHeaders      Source headers.
+  @param[in]  SrcHeaderCount  Number of header in source headers.
+  @param[out] DstHeaders      Destination headers.
+  @param[out] DstHeaderCount  Number of header in designation headers.
+
+  @retval     EFI_SUCCESS     Headers are copied successfully.
+  @retval     Others          Errors occur.
+
+**/
+EFI_STATUS
+CopyHttpHeaders (
+  IN  EFI_HTTP_HEADER  *SrcHeaders,
+  IN  UINTN            SrcHeaderCount,
+  OUT EFI_HTTP_HEADER  **DstHeaders,
+  OUT UINTN            *DstHeaderCount
+  )
+{
+  UINTN  Index;
+
+  if ((SrcHeaders == NULL) || (SrcHeaderCount == 0) || (DstHeaders == NULL) || (DstHeaderCount == NULL)) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  *DstHeaderCount = 0;
+  *DstHeaders     = AllocateZeroPool (sizeof (EFI_HTTP_HEADER) * SrcHeaderCount);
+  if (*DstHeaders == NULL) {
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  for (Index = 0; Index < SrcHeaderCount; Index++) {
+    (*DstHeaders)[Index].FieldName = AllocateCopyPool (AsciiStrSize (SrcHeaders[Index].FieldName), SrcHeaders[Index].FieldName);
+    if ((*DstHeaders)[Index].FieldName == NULL) {
+      return EFI_OUT_OF_RESOURCES;
+    }
+
+    (*DstHeaders)[Index].FieldValue = AllocateCopyPool (AsciiStrSize (SrcHeaders[Index].FieldValue), SrcHeaders[Index].FieldValue);
+    if ((*DstHeaders)[Index].FieldValue == NULL) {
+      return EFI_OUT_OF_RESOURCES;
+    }
+
+    *DstHeaderCount += 1;
+  }
+
+  return EFI_SUCCESS;
+}
+
+/**
+  This function free resources in Request. Request is no longer available
+  after this function returns successfully.
+
+  @param[in]  Request      HTTP request to be released.
+
+  @retval     EFI_SUCCESS     Resrouce is released successfully.
+  @retval     Others          Errors occur.
+
+**/
+EFI_STATUS
+ReleaseRedfishRequest (
+  IN  REDFISH_REQUEST  *Request
+  )
+{
+  if (Request == NULL) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  if ((Request->Headers != NULL) && (Request->HeaderCount > 0)) {
+    HttpFreeHeaderFields (Request->Headers, Request->HeaderCount);
+    Request->Headers     = NULL;
+    Request->HeaderCount = 0;
+  }
+
+  if (Request->Content != NULL) {
+    FreePool (Request->Content);
+    Request->Content = NULL;
+  }
+
+  if (Request->ContentType != NULL) {
+    FreePool (Request->ContentType);
+    Request->ContentType = NULL;
+  }
+
+  Request->ContentLength = 0;
+
+  return EFI_SUCCESS;
+}
+
+/**
+  This function free resources in given Response.
+
+  @param[in]  Response     HTTP response to be released.
+
+  @retval     EFI_SUCCESS     Resrouce is released successfully.
+  @retval     Others          Errors occur.
+
+**/
+EFI_STATUS
+ReleaseRedfishResponse (
+  IN  REDFISH_RESPONSE  *Response
+  )
+{
+  if (Response == NULL) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  if ((Response->Headers != NULL) && (Response->HeaderCount > 0)) {
+    HttpFreeHeaderFields (Response->Headers, Response->HeaderCount);
+    Response->Headers     = NULL;
+    Response->HeaderCount = 0;
+  }
+
+  if (Response->Payload != NULL) {
+    ReleaseRedfishPayload (Response->Payload);
+    Response->Payload = NULL;
+  }
+
+  if (Response->StatusCode != NULL) {
+    FreePool (Response->StatusCode);
+    Response->StatusCode = NULL;
+  }
+
+  return EFI_SUCCESS;
+}
+
+/**
+  This function free resources in given HTTP message.
+
+  @param[in]  HttpMessage     HTTP message to be released.
+  @param[in]  IsRequest       TRUE if this is request type of HTTP message.
+                              FALSE if this is response type of HTTP message.
+
+  @retval     EFI_SUCCESS     Resrouce is released successfully.
+  @retval     Others          Errors occur.
+
+**/
+EFI_STATUS
+ReleaseHttpMessage (
+  IN  EFI_HTTP_MESSAGE  *HttpMessage,
+  IN  BOOLEAN           IsRequest
+  )
+{
+  if (HttpMessage == NULL) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  if (IsRequest) {
+    if (HttpMessage->Data.Request != NULL) {
+      if (HttpMessage->Data.Request->Url != NULL) {
+        FreePool (HttpMessage->Data.Request->Url);
+      }
+
+      FreePool (HttpMessage->Data.Request);
+      HttpMessage->Data.Request = NULL;
+    }
+  } else {
+    if (HttpMessage->Data.Response != NULL) {
+      FreePool (HttpMessage->Data.Response);
+      HttpMessage->Data.Response = NULL;
+    }
+  }
+
+  if (HttpMessage->Body != NULL) {
+    FreePool (HttpMessage->Body);
+    HttpMessage->Body = NULL;
+  }
+
+  if (HttpMessage->Headers != NULL) {
+    HttpFreeHeaderFields (HttpMessage->Headers, HttpMessage->HeaderCount);
+    HttpMessage->Headers     = NULL;
+    HttpMessage->HeaderCount = 0;
+  }
+
+  return EFI_SUCCESS;
+}
+
+/**
+  This function build Redfish message for sending data to Redfish service.
+  It's call responsibility to properly release returned HTTP message by
+  calling ReleaseHttpMessage.
+
+  @param[in]   ServicePrivate    Pointer to Redfish service private data.
+  @param[in]   Uri               Redfish service URI.
+  @param[in]   Method            HTTP method.
+  @param[in]   Request           Additional data to send to Redfish service.
+                                 This is optional.
+  @param[in]   ContentEncoding   Content encoding method to compress HTTP context.
+                                 This is optional. When ContentEncoding is NULL,
+                                 No compress method will be performed.
+
+  @retval     EFI_HTTP_MESSAGE *   Pointer to newly created HTTP message.
+  @retval     NULL                 Error occurred.
+
+**/
+EFI_HTTP_MESSAGE *
+BuildRequestMessage (
+  IN REDFISH_SERVICE_PRIVATE  *ServicePrivate,
+  IN EFI_STRING               Uri,
+  IN EFI_HTTP_METHOD          Method,
+  IN REDFISH_REQUEST          *Request OPTIONAL,
+  IN CHAR8                    *ContentEncoding OPTIONAL
+  )
+{
+  EFI_STATUS             Status;
+  EFI_STRING             Url;
+  UINTN                  UrlSize;
+  UINTN                  Index;
+  EFI_HTTP_MESSAGE       *RequestMsg;
+  EFI_HTTP_REQUEST_DATA  *RequestData;
+  UINTN                  HeaderCount;
+  UINTN                  HeaderIndex;
+  EFI_HTTP_HEADER        *Headers;
+  CHAR8                  ContentLengthStr[REDFISH_CONTENT_LENGTH_SIZE];
+  VOID                   *Content;
+  UINTN                  ContentLength;
+  BOOLEAN                HasContent;
+  BOOLEAN                DoContentEncoding;
+
+  RequestMsg        = NULL;
+  RequestData       = NULL;
+  Url               = NULL;
+  UrlSize           = 0;
+  Content           = NULL;
+  ContentLength     = 0;
+  HeaderCount       = REDFISH_COMMON_HEADER_SIZE;
+  HeaderIndex       = 0;
+  Headers           = NULL;
+  HasContent        = FALSE;
+  DoContentEncoding = FALSE;
+
+  if ((ServicePrivate == NULL) || (IS_EMPTY_STRING (Uri))) {
+    return NULL;
+  }
+
+  if (Method >= HttpMethodMax) {
+    return NULL;
+  }
+
+  DEBUG ((REDFISH_HTTP_CACHE_DEBUG_REQUEST, "%a: %s\n", __func__, Uri));
+
+  //
+  // Build full URL for HTTP query.
+  //
+  UrlSize = (AsciiStrLen (ServicePrivate->Host) + StrLen (Uri) + 1) * sizeof (CHAR16);
+  Url     = AllocateZeroPool (UrlSize);
+  if (Url == NULL) {
+    return NULL;
+  }
+
+  UnicodeSPrint (Url, UrlSize, L"%a%s", ServicePrivate->Host, Uri);
+  DEBUG ((REDFISH_HTTP_CACHE_DEBUG_REQUEST, "%a: Url: %s\n", __func__, Url));
+
+  //
+  // Step 1: build the HTTP headers.
+  //
+  if (!IS_EMPTY_STRING (ServicePrivate->SessionToken) || !IS_EMPTY_STRING (ServicePrivate->BasicAuth)) {
+    HeaderCount++;
+  }
+
+  if ((Request != NULL) && (Request->HeaderCount > 0)) {
+    HeaderCount += Request->HeaderCount;
+  }
+
+  //
+  // Check and see if we will do content encoding or not
+  //
+  if (!IS_EMPTY_STRING (ContentEncoding)) {
+    if (AsciiStrCmp (ContentEncoding, REDFISH_HTTP_CONTENT_ENCODING_NONE) != 0) {
+      DoContentEncoding = TRUE;
+    }
+  }
+
+  if ((Request != NULL) && !IS_EMPTY_STRING (Request->Content)) {
+    HeaderCount += 2;
+    HasContent   = TRUE;
+    if (DoContentEncoding) {
+      HeaderCount += 1;
+    }
+  }
+
+  Headers = AllocateZeroPool (HeaderCount * sizeof (EFI_HTTP_HEADER));
+  if (Headers == NULL) {
+    goto ON_ERROR;
+  }
+
+  if (!IS_EMPTY_STRING (ServicePrivate->SessionToken)) {
+    Status = HttpSetFieldNameAndValue (&Headers[HeaderIndex++], HTTP_HEADER_X_AUTH_TOKEN, ServicePrivate->SessionToken);
+    if (EFI_ERROR (Status)) {
+      goto ON_ERROR;
+    }
+  } else if (!IS_EMPTY_STRING (ServicePrivate->BasicAuth)) {
+    Status = HttpSetFieldNameAndValue (&Headers[HeaderIndex++], HTTP_HEADER_AUTHORIZATION, ServicePrivate->BasicAuth);
+    if (EFI_ERROR (Status)) {
+      goto ON_ERROR;
+    }
+  }
+
+  if (Request != NULL) {
+    for (Index = 0; Index < Request->HeaderCount; Index++) {
+      Status = HttpSetFieldNameAndValue (&Headers[HeaderIndex++], Request->Headers[Index].FieldName, Request->Headers[Index].FieldValue);
+      if (EFI_ERROR (Status)) {
+        goto ON_ERROR;
+      }
+    }
+  }
+
+  Status = HttpSetFieldNameAndValue (&Headers[HeaderIndex++], HTTP_HEADER_HOST, ServicePrivate->HostName);
+  if (EFI_ERROR (Status)) {
+    goto ON_ERROR;
+  }
+
+  Status = HttpSetFieldNameAndValue (&Headers[HeaderIndex++], REDFISH_HTTP_HEADER_ODATA_VERSION_STR, REDFISH_HTTP_HEADER_ODATA_VERSION_VALUE);
+  if (EFI_ERROR (Status)) {
+    goto ON_ERROR;
+  }
+
+  Status = HttpSetFieldNameAndValue (&Headers[HeaderIndex++], HTTP_HEADER_ACCEPT, HTTP_CONTENT_TYPE_APP_JSON);
+  if (EFI_ERROR (Status)) {
+    goto ON_ERROR;
+  }
+
+  Status = HttpSetFieldNameAndValue (&Headers[HeaderIndex++], HTTP_HEADER_USER_AGENT, REDFISH_HTTP_HEADER_USER_AGENT_VALUE);
+  if (EFI_ERROR (Status)) {
+    goto ON_ERROR;
+  }
+
+  Status = HttpSetFieldNameAndValue (&Headers[HeaderIndex++], REDFISH_HTTP_HEADER_CONNECTION_STR, REDFISH_HTTP_HEADER_CONNECTION_VALUE);
+  if (EFI_ERROR (Status)) {
+    goto ON_ERROR;
+  }
+
+  //
+  // Handle content header
+  //
+  if (HasContent) {
+    if (Request->ContentType == NULL) {
+      Status = HttpSetFieldNameAndValue (&Headers[HeaderIndex++], HTTP_HEADER_CONTENT_TYPE, HTTP_CONTENT_TYPE_APP_JSON);
+      if (EFI_ERROR (Status)) {
+        goto ON_ERROR;
+      }
+    } else {
+      Status = HttpSetFieldNameAndValue (&Headers[HeaderIndex++], HTTP_HEADER_CONTENT_TYPE, Request->ContentType);
+      if (EFI_ERROR (Status)) {
+        goto ON_ERROR;
+      }
+    }
+
+    if (Request->ContentLength == 0) {
+      Request->ContentLength =  AsciiStrLen (Request->Content);
+    }
+
+    AsciiSPrint (
+      ContentLengthStr,
+      sizeof (ContentLengthStr),
+      "%lu",
+      (UINT64)Request->ContentLength
+      );
+    Status = HttpSetFieldNameAndValue (&Headers[HeaderIndex++], HTTP_HEADER_CONTENT_LENGTH, ContentLengthStr);
+    if (EFI_ERROR (Status)) {
+      goto ON_ERROR;
+    }
+
+    //
+    // Encoding
+    //
+    if (DoContentEncoding) {
+      //
+      // We currently only support gzip Content-Encoding.
+      //
+      Status =  RedfishContentEncode (
+                  ContentEncoding,
+                  Request->Content,
+                  Request->ContentLength,
+                  &Content,
+                  &ContentLength
+                  );
+      if (Status == EFI_INVALID_PARAMETER) {
+        DEBUG ((DEBUG_ERROR, "%a: Error to encode content.\n", __func__));
+        goto ON_ERROR;
+      } else if (Status == EFI_UNSUPPORTED) {
+        DoContentEncoding = FALSE;
+        DEBUG ((REDFISH_HTTP_CACHE_DEBUG_REQUEST, "%a: No content coding for %a! Use raw data instead.\n", __func__, ContentEncoding));
+        Status = HttpSetFieldNameAndValue (&Headers[HeaderIndex++], HTTP_HEADER_CONTENT_ENCODING, HTTP_CONTENT_ENCODING_IDENTITY);
+        if (EFI_ERROR (Status)) {
+          goto ON_ERROR;
+        }
+      } else {
+        Status = HttpSetFieldNameAndValue (&Headers[HeaderIndex++], HTTP_HEADER_CONTENT_ENCODING, HTTP_CONTENT_ENCODING_GZIP);
+        if (EFI_ERROR (Status)) {
+          goto ON_ERROR;
+        }
+      }
+    }
+
+    //
+    // When the content is from caller, we use our own copy so that we properly release it later.
+    //
+    if (!DoContentEncoding) {
+      Content = AllocateCopyPool (Request->ContentLength, Request->Content);
+      if (Content == NULL) {
+        goto ON_ERROR;
+      }
+
+      ContentLength = Request->ContentLength;
+    }
+  }
+
+  //
+  // Step 2: build the rest of HTTP request info.
+  //
+  RequestData = AllocateZeroPool (sizeof (EFI_HTTP_REQUEST_DATA));
+  if (RequestData == NULL) {
+    goto ON_ERROR;
+  }
+
+  RequestData->Method = Method;
+  RequestData->Url    = Url;
+
+  //
+  // Step 3: fill in EFI_HTTP_MESSAGE
+  //
+  RequestMsg = AllocateZeroPool (sizeof (EFI_HTTP_MESSAGE));
+  if (RequestMsg == NULL) {
+    goto ON_ERROR;
+  }
+
+  ASSERT (HeaderIndex == HeaderCount);
+  RequestMsg->Data.Request = RequestData;
+  RequestMsg->HeaderCount  = HeaderIndex;
+  RequestMsg->Headers      = Headers;
+
+  if (HasContent) {
+    RequestMsg->BodyLength = ContentLength;
+    RequestMsg->Body       = Content;
+  }
+
+  return RequestMsg;
+
+ON_ERROR:
+
+  if (Headers != NULL) {
+    HttpFreeHeaderFields (Headers, HeaderIndex);
+  }
+
+  if (RequestData != NULL) {
+    FreePool (RequestData);
+  }
+
+  if (RequestMsg != NULL) {
+    FreePool (RequestMsg);
+  }
+
+  if (Url != NULL) {
+    FreePool (Url);
+  }
+
+  return NULL;
+}
+
+/**
+  This function parse response message from Redfish service, and
+  build Redfish response for caller. It's call responsibility to
+  properly release Redfish response by calling ReleaseRedfishResponse.
+
+  @param[in]   ServicePrivate   Pointer to Redfish service private data.
+  @param[in]   ResponseMsg      Response message from Redfish service.
+  @param[out]  RedfishResponse  Redfish response data.
+
+  @retval     EFI_SUCCESS     Redfish response is returned successfully.
+  @retval     Others          Errors occur.
+
+**/
+EFI_STATUS
+ParseResponseMessage (
+  IN  REDFISH_SERVICE_PRIVATE  *ServicePrivate,
+  IN  EFI_HTTP_MESSAGE         *ResponseMsg,
+  OUT REDFISH_RESPONSE         *RedfishResponse
+  )
+{
+  EFI_STATUS        Status;
+  EDKII_JSON_VALUE  JsonData;
+  EFI_HTTP_HEADER   *ContentEncodedHeader;
+  VOID              *DecodedBody;
+  UINTN             DecodedLength;
+
+  if ((ServicePrivate == NULL) || (ResponseMsg == NULL) || (RedfishResponse == NULL)) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  DEBUG ((REDFISH_HTTP_CACHE_DEBUG_REQUEST, "%a\n", __func__));
+
+  //
+  // Initialization
+  //
+  JsonData                     = NULL;
+  RedfishResponse->HeaderCount = 0;
+  RedfishResponse->Headers     = NULL;
+  RedfishResponse->Payload     = NULL;
+  RedfishResponse->StatusCode  = NULL;
+  DecodedBody                  = NULL;
+  DecodedLength                = 0;
+
+  //
+  // Return the HTTP StatusCode.
+  //
+  if (ResponseMsg->Data.Response != NULL) {
+    DEBUG ((REDFISH_HTTP_CACHE_DEBUG_REQUEST, "%a: status: %d\n", __func__, ResponseMsg->Data.Response->StatusCode));
+    RedfishResponse->StatusCode = AllocateCopyPool (sizeof (EFI_HTTP_STATUS_CODE), &ResponseMsg->Data.Response->StatusCode);
+    if (RedfishResponse->StatusCode == NULL) {
+      DEBUG ((DEBUG_ERROR, "%a: Failed to create status code.\n", __func__));
+    }
+  }
+
+  //
+  // Return the HTTP headers.
+  //
+  if (ResponseMsg->Headers != NULL) {
+    DEBUG ((REDFISH_HTTP_CACHE_DEBUG_REQUEST, "%a: header count: %d\n", __func__, ResponseMsg->HeaderCount));
+    Status = CopyHttpHeaders (
+               ResponseMsg->Headers,
+               ResponseMsg->HeaderCount,
+               &RedfishResponse->Headers,
+               &RedfishResponse->HeaderCount
+               );
+    if (EFI_ERROR (Status)) {
+      DEBUG ((DEBUG_ERROR, "%a: Failed to copy HTTP headers: %r\n", __func__, Status));
+    }
+  }
+
+  //
+  // Return the HTTP body.
+  //
+  if ((ResponseMsg->BodyLength != 0) && (ResponseMsg->Body != NULL)) {
+    DEBUG ((REDFISH_HTTP_CACHE_DEBUG_REQUEST, "%a: body length: %d\n", __func__, ResponseMsg->BodyLength));
+    //
+    // Check if data is encoded.
+    //
+    ContentEncodedHeader = HttpFindHeader (RedfishResponse->HeaderCount, RedfishResponse->Headers, HTTP_HEADER_CONTENT_ENCODING);
+    if (ContentEncodedHeader != NULL) {
+      //
+      // The content is encoded.
+      //
+      Status = RedfishContentDecode (
+                 ContentEncodedHeader->FieldValue,
+                 ResponseMsg->Body,
+                 ResponseMsg->BodyLength,
+                 &DecodedBody,
+                 &DecodedLength
+                 );
+      if (EFI_ERROR (Status)) {
+        DEBUG ((DEBUG_ERROR, "%a: Failed to decompress the response content: %r decoding method: %a\n.", __func__, Status, ContentEncodedHeader->FieldValue));
+        goto ON_ERROR;
+      }
+
+      JsonData = JsonLoadBuffer (DecodedBody, DecodedLength, 0, NULL);
+      FreePool (DecodedBody);
+    } else {
+      JsonData = JsonLoadBuffer (ResponseMsg->Body, ResponseMsg->BodyLength, 0, NULL);
+    }
+
+    if (!JsonValueIsNull (JsonData)) {
+      RedfishResponse->Payload = CreateRedfishPayload (ServicePrivate, JsonData);
+      if (RedfishResponse->Payload == NULL) {
+        DEBUG ((DEBUG_ERROR, "%a: Failed to create payload\n.", __func__));
+      }
+
+      JsonValueFree (JsonData);
+    } else {
+      DEBUG ((DEBUG_ERROR, "%a: No payload available\n", __func__));
+    }
+  }
+
+  return EFI_SUCCESS;
+
+ON_ERROR:
+
+  if (RedfishResponse != NULL) {
+    ReleaseRedfishResponse (RedfishResponse);
+  }
+
+  return Status;
+}
+
+/**
+  This function send Redfish request to Redfish service by calling
+  Rest Ex protocol.
+
+  @param[in]   Service       Pointer to Redfish service.
+  @param[in]   Uri           Uri of Redfish service.
+  @param[in]   Method        HTTP method.
+  @param[in]   Request     Request data. This is optional.
+  @param[out]  Response    Redfish response data.
+
+  @retval     EFI_SUCCESS     Request is sent and received successfully.
+  @retval     Others          Errors occur.
+
+**/
+EFI_STATUS
+HttpSendReceive (
+  IN  REDFISH_SERVICE   Service,
+  IN  EFI_STRING        Uri,
+  IN  EFI_HTTP_METHOD   Method,
+  IN  REDFISH_REQUEST   *Request  OPTIONAL,
+  OUT REDFISH_RESPONSE  *Response
+  )
+{
+  EFI_STATUS               Status;
+  EFI_STATUS               RestExStatus;
+  EFI_HTTP_MESSAGE         *RequestMsg;
+  EFI_HTTP_MESSAGE         ResponseMsg;
+  REDFISH_SERVICE_PRIVATE  *ServicePrivate;
+  EFI_HTTP_HEADER          *XAuthTokenHeader;
+  CHAR8                    *HttpContentEncoding;
+
+  if ((Service == NULL) || IS_EMPTY_STRING (Uri) || (Response == NULL)) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  DEBUG ((REDFISH_HTTP_CACHE_DEBUG_REQUEST, "%a: Method: 0x%x %s\n", __func__, Method, Uri));
+
+  ServicePrivate = (REDFISH_SERVICE_PRIVATE *)Service;
+  if (ServicePrivate->Signature != REDFISH_HTTP_SERVICE_SIGNATURE) {
+    DEBUG ((DEBUG_ERROR, "%a: signature check failure\n", __func__));
+    return EFI_INVALID_PARAMETER;
+  }
+
+  ZeroMem (&ResponseMsg, sizeof (ResponseMsg));
+  HttpContentEncoding = (CHAR8 *)PcdGetPtr (PcdRedfishServiceContentEncoding);
+
+  RequestMsg = BuildRequestMessage (Service, Uri, Method, Request, HttpContentEncoding);
+  if (RequestMsg == NULL) {
+    DEBUG ((DEBUG_ERROR, "%a: cannot build request message for %s\n", __func__, Uri));
+    return EFI_PROTOCOL_ERROR;
+  }
+
+  //
+  // call RESTEx to get response from REST service.
+  //
+  RestExStatus = ServicePrivate->RestEx->SendReceive (ServicePrivate->RestEx, RequestMsg, &ResponseMsg);
+  if (EFI_ERROR (RestExStatus)) {
+    DEBUG ((DEBUG_ERROR, "%a: %s SendReceive failure: %r\n", __func__, Uri, RestExStatus));
+  }
+
+  //
+  // Return status code, headers and payload to caller as much as possible even when RestEx returns failure.
+  //
+  Status = ParseResponseMessage (ServicePrivate, &ResponseMsg, Response);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "%a: %s parse response failure: %r\n", __func__, Uri, Status));
+  } else {
+    //
+    // Capture session token in header
+    //
+    if ((Method == HttpMethodPost) &&
+        (Response->StatusCode != NULL) &&
+        ((*Response->StatusCode == HTTP_STATUS_200_OK) || (*Response->StatusCode == HTTP_STATUS_204_NO_CONTENT)))
+    {
+      XAuthTokenHeader = HttpFindHeader (ResponseMsg.HeaderCount, ResponseMsg.Headers, HTTP_HEADER_X_AUTH_TOKEN);
+      if (XAuthTokenHeader != NULL) {
+        Status = UpdateSessionToken (ServicePrivate, XAuthTokenHeader->FieldValue);
+        if (EFI_ERROR (Status)) {
+          DEBUG ((DEBUG_ERROR, "%a: update session token failure: %r\n", __func__, Status));
+        }
+      }
+    }
+  }
+
+  //
+  // Release resources
+  //
+  if (RequestMsg != NULL) {
+    ReleaseHttpMessage (RequestMsg, TRUE);
+    FreePool (RequestMsg);
+  }
+
+  ReleaseHttpMessage (&ResponseMsg, FALSE);
+
+  return RestExStatus;
+}
diff --git a/RedfishPkg/Redfish.fdf.inc b/RedfishPkg/Redfish.fdf.inc
index 3e5a77766e..5cbe3592fd 100644
--- a/RedfishPkg/Redfish.fdf.inc
+++ b/RedfishPkg/Redfish.fdf.inc
@@ -6,7 +6,7 @@
 # to be built in the firmware volume.
 #
 # (C) Copyright 2020-2021 Hewlett Packard Enterprise Development LP<BR>
-# Copyright (c) 2023, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
+# Copyright (c) 2023-2024, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
 #
 #    SPDX-License-Identifier: BSD-2-Clause-Patent
 #
@@ -20,4 +20,5 @@
   INF RedfishPkg/RedfishConfigHandler/RedfishConfigHandlerDriver.inf
   INF RedfishPkg/RedfishPlatformConfigDxe/RedfishPlatformConfigDxe.inf
   INF MdeModulePkg/Universal/RegularExpressionDxe/RegularExpressionDxe.inf
+  INF RedfishPkg/RedfishHttpDxe/RedfishHttpDxe.inf
 !endif
--
2.34.1

-The information contained in this message may be confidential and proprietary to American Megatrends (AMI). This communication is intended to be read only by the individual or entity to whom it is addressed or by their designee. If the reader of this message is not the intended recipient, you are on notice that any distribution of this message, in any form, is strictly prohibited. Please promptly notify the sender by reply e-mail or by telephone at 770-246-8600, and then delete or destroy all copies of the transmission.


-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#115820): https://edk2.groups.io/g/devel/message/115820
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]
-=-=-=-=-=-=-=-=-=-=-=-



^ permalink raw reply related	[flat|nested] 15+ messages in thread

* Re: [edk2-devel] [PATCH v2 2/6] RedfishPkg: implement Redfish HTTP protocol
  2024-02-22  9:11 [edk2-devel] [PATCH v2 2/6] RedfishPkg: implement Redfish HTTP protocol Nickle Wang via groups.io
  2024-02-22 13:39 ` Chang, Abner via groups.io
  2024-02-22 14:17 ` Igor Kulchytskyy via groups.io
@ 2024-02-23 11:29 ` Mike Maslenkin
  2024-02-23 14:07   ` Nickle Wang via groups.io
  2 siblings, 1 reply; 15+ messages in thread
From: Mike Maslenkin @ 2024-02-23 11:29 UTC (permalink / raw)
  To: devel, Nickle Wang; +Cc: Igor Kulchytskyy, Abner Chang, Nick Ramirez

Hi Nickle,

%s/Resrouce/Resource/ this comes from RedfishClient autogenerated files... there are thousands of "Resrouce" typos.

please, find my minor notes below:


On Thu, Feb 22, 2024 at 12:11 PM Nickle Wang via groups.io <nicklew=nvidia.com@groups.io> wrote:
> 
> implement Redfish HTTP protocol driver.
> 
> Signed-off-by: Nickle Wang <nicklew@nvidia.com>
> Co-authored-by: Igor Kulchytskyy <igork@ami.com>
> Cc: Abner Chang <abner.chang@amd.com>
> Cc: Igor Kulchytskyy <igork@ami.com>
> Cc: Nick Ramirez <nramirez@nvidia.com>
> ---
> RedfishPkg/RedfishPkg.dec                     |    7 +-
> RedfishPkg/RedfishComponents.dsc.inc          |    3 +-
> RedfishPkg/RedfishPkg.dsc                     |    2 +
> RedfishPkg/RedfishHttpDxe/RedfishHttpDxe.inf  |   73 +
> RedfishPkg/RedfishHttpDxe/RedfishHttpData.h   |  256 ++++
> RedfishPkg/RedfishHttpDxe/RedfishHttpDxe.h    |   44 +
> .../RedfishHttpDxe/RedfishHttpOperation.h     |   76 +
> RedfishPkg/RedfishHttpDxe/RedfishHttpData.c   |  667 ++++++++
> RedfishPkg/RedfishHttpDxe/RedfishHttpDxe.c    | 1344 +++++++++++++++++
> .../RedfishHttpDxe/RedfishHttpOperation.c     |  693 +++++++++
> RedfishPkg/Redfish.fdf.inc                    |    3 +-
> 11 files changed, 3164 insertions(+), 4 deletions(-)
> create mode 100644 RedfishPkg/RedfishHttpDxe/RedfishHttpDxe.inf
> create mode 100644 RedfishPkg/RedfishHttpDxe/RedfishHttpData.h
> create mode 100644 RedfishPkg/RedfishHttpDxe/RedfishHttpDxe.h
> create mode 100644 RedfishPkg/RedfishHttpDxe/RedfishHttpOperation.h
> create mode 100644 RedfishPkg/RedfishHttpDxe/RedfishHttpData.c
> create mode 100644 RedfishPkg/RedfishHttpDxe/RedfishHttpDxe.c
> create mode 100644 RedfishPkg/RedfishHttpDxe/RedfishHttpOperation.c
> 
> diff --git a/RedfishPkg/RedfishPkg.dec b/RedfishPkg/RedfishPkg.dec
> index 9b424efdf3..114f8d2ad8 100644
> --- a/RedfishPkg/RedfishPkg.dec
> +++ b/RedfishPkg/RedfishPkg.dec
> @@ -157,8 +157,11 @@
>   # set to EFI_REST_EX_PROTOCOL.
>   #
>   gEfiRedfishPkgTokenSpaceGuid.PcdRedfishSendReceiveTimeout|5000|UINT32|0x00001009
> -  ## This is used to enable HTTP content encoding on Redfish communication.
> -  gEfiRedfishPkgTokenSpaceGuid.PcdRedfishServiceContentEncoding|TRUE|BOOLEAN|0x0000100A
> +  #
> +  # This PCD string is introduced for platform developer to set the encoding method supported by BMC Redfish.
> +  # Currently only "None" and "gzip" are supported.
> +  #
> +  gEfiRedfishPkgTokenSpaceGuid.PcdRedfishServiceContentEncoding|"None"|VOID*|0x0000100A
>   #
>   # Use below PCDs to control Redfhs HTTP protocol.
>   #
> diff --git a/RedfishPkg/RedfishComponents.dsc.inc b/RedfishPkg/RedfishComponents.dsc.inc
> index 464ffc8606..d6c5b73d7f 100644
> --- a/RedfishPkg/RedfishComponents.dsc.inc
> +++ b/RedfishPkg/RedfishComponents.dsc.inc
> @@ -7,7 +7,7 @@
> # "RedfishDefines.dsc.inc".
> #
> # (C) Copyright 2020-2021 Hewlett Packard Enterprise Development LP<BR>
> -# Copyright (c) 2023, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
> +# Copyright (c) 2023-2024, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
> #
> #    SPDX-License-Identifier: BSD-2-Clause-Patent
> #
> @@ -28,4 +28,5 @@
>   RedfishPkg/RedfishConfigHandler/RedfishConfigHandlerDriver.inf
>   RedfishPkg/RedfishPlatformConfigDxe/RedfishPlatformConfigDxe.inf
>   MdeModulePkg/Universal/RegularExpressionDxe/RegularExpressionDxe.inf
> +  RedfishPkg/RedfishHttpDxe/RedfishHttpDxe.inf
> !endif
> diff --git a/RedfishPkg/RedfishPkg.dsc b/RedfishPkg/RedfishPkg.dsc
> index 25ed193182..5849e7cf9e 100644
> --- a/RedfishPkg/RedfishPkg.dsc
> +++ b/RedfishPkg/RedfishPkg.dsc
> @@ -45,6 +45,8 @@
>   UefiHiiServicesLib|MdeModulePkg/Library/UefiHiiServicesLib/UefiHiiServicesLib.inf
>   RedfishPlatformCredentialLib|RedfishPkg/Library/PlatformCredentialLibNull/PlatformCredentialLibNull.inf
>   RedfishContentCodingLib|RedfishPkg/Library/RedfishContentCodingLibNull/RedfishContentCodingLibNull.inf
> +  ReportStatusCodeLib|MdeModulePkg/Library/DxeReportStatusCodeLib/DxeReportStatusCodeLib.inf
> +  SortLib|MdeModulePkg/Library/UefiSortLib/UefiSortLib.inf
> 
>   # NULL instance of IPMI related library.
>   IpmiLib|MdeModulePkg/Library/BaseIpmiLibNull/BaseIpmiLibNull.inf
> diff --git a/RedfishPkg/RedfishHttpDxe/RedfishHttpDxe.inf b/RedfishPkg/RedfishHttpDxe/RedfishHttpDxe.inf
> new file mode 100644
> index 0000000000..c7dfdffacf
> --- /dev/null
> +++ b/RedfishPkg/RedfishHttpDxe/RedfishHttpDxe.inf
> @@ -0,0 +1,73 @@
> +## @file
> +#  RedfishHttpDxe is the DXE driver which provides
> +#  EdkIIRedfishHttpProtocol to EDK2 Redfish Feature
> +#  drivers for HTTP operation.
> +#
> +#  Copyright (c) 2023-2024, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
> +#
> +#  SPDX-License-Identifier: BSD-2-Clause-Patent
> +#
> +##
> +
> +[Defines]
> +  INF_VERSION                    = 0x0001000b
> +  BASE_NAME                      = RedfishHttpDxe
> +  FILE_GUID                      = 85ADB2F1-DA93-47D4-AF4F-3D920D9BD2C0
> +  MODULE_TYPE                    = DXE_DRIVER
> +  VERSION_STRING                 = 1.0
> +  ENTRY_POINT                    = RedfishHttpEntryPoint
> +  UNLOAD_IMAGE                   = RedfishHttpDriverUnload
> +
> +#
> +#  VALID_ARCHITECTURES           = IA32 X64 ARM AARCH64 RISCV64
> +#
> +
> +[Sources]
> +  RedfishHttpData.c
> +  RedfishHttpData.h
> +  RedfishHttpDxe.c
> +  RedfishHttpDxe.h
> +  RedfishHttpOperation.c
> +  RedfishHttpOperation.h
> +
> +[Packages]
> +  MdePkg/MdePkg.dec
> +  MdeModulePkg/MdeModulePkg.dec
> +  NetworkPkg/NetworkPkg.dec
> +  RedfishPkg/RedfishPkg.dec
> +
> +[LibraryClasses.ARM]
> +  ArmSoftFloatLib
> +
> +[LibraryClasses]
> +  BaseLib
> +  BaseMemoryLib
> +  RedfishContentCodingLib
> +  DebugLib
> +  HttpLib
> +  JsonLib
> +  MemoryAllocationLib
> +  PrintLib
> +  RedfishDebugLib
> +  ReportStatusCodeLib
> +  UefiBootServicesTableLib
> +  UefiDriverEntryPoint
> +  UefiLib
> +
> +[Protocols]
> +  gEdkIIRedfishHttpProtocolGuid             ## PRODUCED
> +  gEdkIIRedfishCredentialProtocolGuid       ## CONSUMES
> +  gEfiRestExProtocolGuid                    ## CONSUEMS
> +
> +[Pcd]
> +  gEfiRedfishPkgTokenSpaceGuid.PcdHttpGetRetry
> +  gEfiRedfishPkgTokenSpaceGuid.PcdHttpPutRetry
> +  gEfiRedfishPkgTokenSpaceGuid.PcdHttpPatchRetry
> +  gEfiRedfishPkgTokenSpaceGuid.PcdHttpPostRetry
> +  gEfiRedfishPkgTokenSpaceGuid.PcdHttpDeleteRetry
> +  gEfiRedfishPkgTokenSpaceGuid.PcdHttpRetryWaitInSecond
> +  gEfiRedfishPkgTokenSpaceGuid.PcdHttpCacheDisabled
> +  gEfiRedfishPkgTokenSpaceGuid.PcdRedfishServiceContentEncoding
> +
> +[Depex]
> +  TRUE
> diff --git a/RedfishPkg/RedfishHttpDxe/RedfishHttpData.h b/RedfishPkg/RedfishHttpDxe/RedfishHttpData.h
> new file mode 100644
> index 0000000000..6be610142e
> --- /dev/null
> +++ b/RedfishPkg/RedfishHttpDxe/RedfishHttpData.h
> @@ -0,0 +1,256 @@
> +/** @file
> +  Definitions of RedfishHttpData
> +
> +  Copyright (c) 2023-2024, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
> +
> +  SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +#ifndef EDKII_REDFISH_HTTP_DATA_H_
> +#define EDKII_REDFISH_HTTP_DATA_H_
> +
> +#include "RedfishHttpDxe.h"
> +
> +#define REDFISH_HTTP_DRIVER_SIGNATURE   SIGNATURE_32 ('r', 'f', 'h', 'p')
> +#define REDFISH_HTTP_CACHE_SIGNATURE    SIGNATURE_32 ('r', 'f', 'c', 'h')
> +#define REDFISH_HTTP_SERVICE_SIGNATURE  SIGNATURE_32 ('r', 'f', 's', 'v')
> +#define REDFISH_HTTP_PAYLOAD_SIGNATURE  SIGNATURE_32 ('r', 'f', 'p', 'l')
> +#define REDFISH_HTTP_BASIC_AUTH_STR     "Basic "
> +
> +///
> +/// REDFISH_SERVICE_PRIVATE definition.
> +///
> +typedef struct {
> +  UINT32                  Signature;
> +  CHAR8                   *Host;
> +  CHAR8                   *HostName;
> +  CHAR8                   *BasicAuth;
> +  CHAR8                   *SessionToken;
> +  EFI_REST_EX_PROTOCOL    *RestEx;
> +} REDFISH_SERVICE_PRIVATE;
> +
> +///
> +/// REDFISH_PAYLOAD_PRIVATE definition.
> +///
> +typedef struct {
> +  UINT32                     Signature;
> +  REDFISH_SERVICE_PRIVATE    *Service;
> +  EDKII_JSON_VALUE           JsonValue;
> +} REDFISH_PAYLOAD_PRIVATE;
> +
> +///
> +/// Definition of REDFISH_HTTP_CACHE_DATA
> +///
> +typedef struct {
> +  UINT32              Signature;
> +  LIST_ENTRY          List;
> +  EFI_STRING          Uri;
> +  UINTN               HitCount;
> +  REDFISH_RESPONSE    *Response;
> +} REDFISH_HTTP_CACHE_DATA;
> +
> +#define REDFISH_HTTP_CACHE_FROM_LIST(a)  CR (a, REDFISH_HTTP_CACHE_DATA, List, REDFISH_HTTP_CACHE_SIGNATURE)
> +
> +///
> +/// Definition of REDFISH_HTTP_CACHE_LIST
> +///
> +typedef struct {
> +  LIST_ENTRY    Head;
> +  UINTN         Count;
> +  UINTN         Capacity;
> +} REDFISH_HTTP_CACHE_LIST;
> +
> +///
> +/// Definition of REDFISH_HTTP_RETRY_SETTING
> +///
> +typedef struct {
> +  UINT16    MaximumRetryGet;
> +  UINT16    MaximumRetryPut;
> +  UINT16    MaximumRetryPost;
> +  UINT16    MaximumRetryPatch;
> +  UINT16    MaximumRetryDelete;
> +  UINTN     RetryWait;
> +} REDFISH_HTTP_RETRY_SETTING;
> +
> +///
> +/// Definition of REDFISH_HTTP_CACHE_PRIVATE
> +///
> +typedef struct {
> +  UINT32                               Signature;
> +  EFI_HANDLE                           ImageHandle;
> +  BOOLEAN                              CacheDisabled;
> +  EFI_EVENT                            NotifyEvent;
> +  REDFISH_HTTP_CACHE_LIST              CacheList;
> +  EDKII_REDFISH_HTTP_PROTOCOL          Protocol;
> +  EDKII_REDFISH_CREDENTIAL_PROTOCOL    *CredentialProtocol;
> +  REDFISH_HTTP_RETRY_SETTING           RetrySetting;
> +} REDFISH_HTTP_CACHE_PRIVATE;
> +
> +#define REDFISH_HTTP_CACHE_PRIVATE_FROM_THIS(a)  CR (a, REDFISH_HTTP_CACHE_PRIVATE, Protocol, REDFISH_HTTP_DRIVER_SIGNATURE)
> +
> +/**
> +  Search on given ListHeader for given URI string.
> +
> +  @param[in]    ListHeader  Target list to search.
> +  @param[in]    Uri         Target URI to search.
> +
> +  @retval REDFISH_HTTP_CACHE_DATA   Target cache data is found.
> +  @retval NULL                      No cache data with given URI is found.
> +
> +**/
> +REDFISH_HTTP_CACHE_DATA *
> +FindHttpCacheData (
> +  IN  LIST_ENTRY  *ListHeader,
> +  IN  EFI_STRING  Uri
> +  );
> +
> +/**
> +  This function copy the data in SrcResponse to DstResponse.
> +
> +  @param[in]  SrcResponse      Source Response to copy.
> +  @param[out] DstResponse      Destination Response.
> +
> +  @retval     EFI_SUCCESS      Response is copied successfully.
> +  @retval     Others           Error occurs.
> +
> +**/
> +EFI_STATUS
> +CopyRedfishResponse (
> +  IN  REDFISH_RESPONSE  *SrcResponse,
> +  OUT REDFISH_RESPONSE  *DstResponse
> +  );
> +
> +/**
> +  Release all cache from list.
> +
> +  @param[in]    CacheList    The list to be released.
> +
> +  @retval EFI_SUCCESS             All cache data are released.
> +  @retval EFI_INVALID_PARAMETER   CacheList is NULL.
> +
> +**/
> +EFI_STATUS
> +ReleaseCacheList (
> +  IN  REDFISH_HTTP_CACHE_LIST  *CacheList
> +  );
> +
> +/**
> +  Add new cache by given URI and HTTP response to specify List.
> +
> +  @param[in]    List      Target cache list to add.
> +  @param[in]    Uri       The URI string matching to this cache data.
> +  @param[in]    Response  HTTP response.
> +
> +  @retval EFI_SUCCESS   Cache data is added.
> +  @retval Others        Fail to add cache data.
> +
> +**/
> +EFI_STATUS
> +AddHttpCacheData (
> +  IN  REDFISH_HTTP_CACHE_LIST  *List,
> +  IN  EFI_STRING               Uri,
> +  IN  REDFISH_RESPONSE         *Response
> +  );
> +
> +/**
> +  Delete a cache data by given cache instance.
> +
> +  @param[in]    List    Target cache list to be removed.
> +  @param[in]    Data    Pointer to the instance to be deleted.
> +
> +  @retval EFI_SUCCESS   Cache data is removed.
> +  @retval Others        Fail to remove cache data.
> +
> +**/
> +EFI_STATUS
> +DeleteHttpCacheData (
> +  IN  REDFISH_HTTP_CACHE_LIST  *List,
> +  IN  REDFISH_HTTP_CACHE_DATA  *Data
> +  );
> +
> +/**
> +  This function release Redfish Payload.
> +
> +  @param[in]  Payload         Pointer to payload instance.
> +
> +  @retval     EFI_SUCCESS     Payload is released.
> +  @retval     Others          Error occurs.
> +
> +**/
> +EFI_STATUS
> +ReleaseRedfishPayload (
> +  IN REDFISH_PAYLOAD_PRIVATE  *Payload
> +  );
> +
> +/**
> +  This function creat new payload. Server and JsonObj are
> +  copied to newly created payload.
> +
> +  @param[in]  Service          Pointer to Service instance.
> +  @param[in]  JsonObj          Pointer to JSON object.
> +
> +  @retval     REDFISH_PAYLOAD_PRIVATE  Newly created payload.
> +  @retval     NULL             Error occurs.
> +
> +**/
> +REDFISH_PAYLOAD_PRIVATE *
> +CreateRedfishPayload (
> +  IN REDFISH_SERVICE_PRIVATE  *Service,
> +  IN EDKII_JSON_VALUE         JsonValue
> +  );
> +
> +/**
> +  This function release Redfish Service.
> +
> +  @param[in]  Service         Pointer to service instance.
> +
> +  @retval     EFI_SUCCESS     Service is released.
> +  @retval     Others          Error occurs.
> +
> +**/
> +EFI_STATUS
> +ReleaseRedfishService (
> +  IN REDFISH_SERVICE_PRIVATE  *Service
> +  );
> +
> +/**
> +  This function creat new service. Host and HostName are copied to
> +  newly created service instance.
> +
> +  @param[in]  Host            Host string.
> +  @param[in]  HostName        Hostname string.
> +  @param[in]  BasicAuth       Basic Authorization string.
> +  @param[in]  SessionToken    Session token string.
> +  @param[in]  RestEx          Rest EX protocol instance.
> +
> +  @retval     REDFISH_PAYLOAD_PRIVATE  Newly created service.
> +  @retval     NULL             Error occurs.
> +
> +**/
> +REDFISH_SERVICE_PRIVATE *
> +CreateRedfishService (
> +  IN CHAR8                 *Host,
> +  IN CHAR8                 *HostName,
> +  IN CHAR8                 *BasicAuth OPTIONAL,
> +  IN CHAR8                 *SessionToken OPTIONAL,
> +  IN EFI_REST_EX_PROTOCOL  *RestEx
> +  );
> +
> +/**
> +  This function update session token in Redfish Service.
> +
> +  @param[in]  Service         Pointer to service instance.
> +  @param[in]  Token           Session token.
> +
> +  @retval     EFI_SUCCESS     Session token is updated.
> +  @retval     Others          Error occurs.
> +
> +**/
> +EFI_STATUS
> +UpdateSessionToken (
> +  IN REDFISH_SERVICE_PRIVATE  *Service,
> +  IN CHAR8                    *Token
> +  );
> +
> +#endif
> diff --git a/RedfishPkg/RedfishHttpDxe/RedfishHttpDxe.h b/RedfishPkg/RedfishHttpDxe/RedfishHttpDxe.h
> new file mode 100644
> index 0000000000..cf6ba9cb47
> --- /dev/null
> +++ b/RedfishPkg/RedfishHttpDxe/RedfishHttpDxe.h
> @@ -0,0 +1,44 @@
> +/** @file
> +  Definitions of RedfishHttpDxe
> +
> +  Copyright (c) 2023-2024, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
> +
> +  SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +#ifndef EDKII_REDFISH_HTTP_DXE_H_
> +#define EDKII_REDFISH_HTTP_DXE_H_
> +
> +#include <Uefi.h>
> +#include <IndustryStandard/Http11.h>
> +
> +#include <Library/UefiLib.h>
> +#include <Library/BaseLib.h>
> +#include <Library/BaseMemoryLib.h>
> +#include <Library/RedfishContentCodingLib.h>
> +#include <Library/DebugLib.h>
> +#include <Library/HttpLib.h>
> +#include <Library/JsonLib.h>
> +#include <Library/UefiBootServicesTableLib.h>
> +#include <Library/MemoryAllocationLib.h>
> +#include <Library/RedfishDebugLib.h>
> +#include <Library/ReportStatusCodeLib.h>
> +#include <Library/PrintLib.h>
> +
> +#include <Protocol/Http.h>
> +#include <Protocol/EdkIIRedfishHttpProtocol.h>
> +#include <Protocol/EdkIIRedfishCredential.h>
> +#include <Protocol/RestEx.h>
> +
> +#define IS_EMPTY_STRING(a)  ((a) == NULL || (a)[0] == '\0')
> +#define REDFISH_HTTP_CACHE_LIST_SIZE      0x80
> +#define REDFISH_ERROR_MSG_MAX             128
> +#define REDFISH_DEBUG_STRING_LENGTH       200
> +#define REDFISH_HOST_NAME_MAX             64   // IPv6 maximum length (39) + "https://" (8) + port number (maximum 5)
> +#define REDFISH_HTTP_ERROR_REPORT         "Redfish HTTP %a failure(0x%x): %s"
> +#define REDFISH_HTTP_CACHE_DEBUG          DEBUG_MANAGEABILITY
> +#define REDFISH_HTTP_CACHE_DEBUG_DUMP     DEBUG_MANAGEABILITY
> +#define REDFISH_HTTP_CACHE_DEBUG_REQUEST  DEBUG_MANAGEABILITY
> +
> +#endif
> diff --git a/RedfishPkg/RedfishHttpDxe/RedfishHttpOperation.h b/RedfishPkg/RedfishHttpDxe/RedfishHttpOperation.h
> new file mode 100644
> index 0000000000..d2f7cf4c27
> --- /dev/null
> +++ b/RedfishPkg/RedfishHttpDxe/RedfishHttpOperation.h
> @@ -0,0 +1,76 @@
> +/** @file
> +  Definitions of RedfishHttpOperation
> +
> +  Copyright (c) 2024, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
> +
> +  SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +#ifndef EDKII_REDFISH_HTTP_OPERATION_H_
> +#define EDKII_REDFISH_HTTP_OPERATION_H_
> +
> +#include "RedfishHttpDxe.h"
> +
> +#define REDFISH_CONTENT_LENGTH_SIZE              80
> +#define REDFISH_COMMON_HEADER_SIZE               5
> +#define REDFISH_HTTP_HEADER_ODATA_VERSION_STR    "OData-Version"
> +#define REDFISH_HTTP_HEADER_ODATA_VERSION_VALUE  "4.0"
> +#define REDFISH_HTTP_HEADER_USER_AGENT_VALUE     "edk2redfish"
> +#define REDFISH_HTTP_HEADER_CONNECTION_STR       "Connection"
> +#define REDFISH_HTTP_HEADER_CONNECTION_VALUE     "Keep-Alive"
> +#define REDFISH_HTTP_CONTENT_ENCODING_NONE       "None"
> +
> +/**
> +  This function free resources in Request. Request is no longer available
> +  after this function returns successfully.
> +
> +  @param[in]  Request      HTTP request to be released.
> +
> +  @retval     EFI_SUCCESS     Resrouce is released successfully.
> +  @retval     Others          Errors occur.
> +
> +**/
> +EFI_STATUS
> +ReleaseRedfishRequest (
> +  IN  REDFISH_REQUEST  *Request
> +  );
> +
> +/**
> +  This function free resources in given Response.
> +
> +  @param[in]  Response     HTTP response to be released.
> +
> +  @retval     EFI_SUCCESS     Resrouce is released successfully.
> +  @retval     Others          Errors occur.
> +
> +**/
> +EFI_STATUS
> +ReleaseRedfishResponse (
> +  IN  REDFISH_RESPONSE  *Response
> +  );
> +
> +/**
> +  This function send Redfish request to Redfish service by calling
> +  Rest Ex protocol.
> +
> +  @param[in]   Service       Pointer to Redfish service.
> +  @param[in]   Uri           Uri of Redfish service.
> +  @param[in]   Method        HTTP method.
> +  @param[in]   Request     Request data. This is optional.
> +  @param[out]  Response    Redfish response data.
> +
> +  @retval     EFI_SUCCESS     Request is sent and received successfully.
> +  @retval     Others          Errors occur.
> +
> +**/
> +EFI_STATUS
> +HttpSendReceive (
> +  IN  REDFISH_SERVICE   Service,
> +  IN  EFI_STRING        Uri,
> +  IN  EFI_HTTP_METHOD   Method,
> +  IN  REDFISH_REQUEST   *Request  OPTIONAL,
> +  OUT REDFISH_RESPONSE  *Response
> +  );
> +
> +#endif
> diff --git a/RedfishPkg/RedfishHttpDxe/RedfishHttpData.c b/RedfishPkg/RedfishHttpDxe/RedfishHttpData.c
> new file mode 100644
> index 0000000000..bf95e9f8d4
> --- /dev/null
> +++ b/RedfishPkg/RedfishHttpDxe/RedfishHttpData.c
> @@ -0,0 +1,667 @@
> +/** @file
> +  RedfishHttpData handles internal data to support Redfish HTTP protocol.
> +
> +  Copyright (c) 2023-2024, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
> +
> +  SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +#include "RedfishHttpData.h"
> +#include "RedfishHttpOperation.h"
> +
> +/**
> +  This function update session token in Redfish Service.
> +
> +  @param[in]  Service         Pointer to service instance.
> +  @param[in]  Token           Session token.
> +
> +  @retval     EFI_SUCCESS     Session token is updated.
> +  @retval     Others          Error occurs.
> +
> +**/
> +EFI_STATUS
> +UpdateSessionToken (
> +  IN REDFISH_SERVICE_PRIVATE  *Service,
> +  IN CHAR8                    *Token
> +  )
> +{
> +  if ((Service == NULL) || IS_EMPTY_STRING (Token)) {
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  if (Service->SessionToken != NULL) {
> +    FreePool (Service->SessionToken);
> +  }
> +
> +  Service->SessionToken = AllocateCopyPool (AsciiStrSize (Token), Token);
> +  if (Service->SessionToken == NULL) {
> +    return EFI_OUT_OF_RESOURCES;
> +  }
> +
> +  return EFI_SUCCESS;
> +}
> +
> +/**
> +  This function release Redfish Service.
> +
> +  @param[in]  Service         Pointer to service instance.
> +
> +  @retval     EFI_SUCCESS     Service is released.
> +  @retval     Others          Error occurs.
> +
> +**/
> +EFI_STATUS
> +ReleaseRedfishService (
> +  IN REDFISH_SERVICE_PRIVATE  *Service
> +  )
> +{
> +  if (Service == NULL) {
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  if (Service->Host != NULL) {
> +    FreePool (Service->Host);
> +  }
> +
> +  if (Service->HostName != NULL) {
> +    FreePool (Service->HostName);
> +  }
> +
> +  if (Service->BasicAuth != NULL) {
> +    ZeroMem (Service->BasicAuth, AsciiStrSize (Service->BasicAuth));
> +    FreePool (Service->BasicAuth);
> +  }
> +
> +  if (Service->SessionToken != NULL) {
> +    ZeroMem (Service->SessionToken, AsciiStrSize (Service->SessionToken));
> +    FreePool (Service->SessionToken);
> +  }
> +
> +  FreePool (Service);
> +
> +  return EFI_SUCCESS;
> +}
> +
> +/**
> +  This function creat new service. Host and HostName are copied to
> +  newly created service instance.
> +
> +  @param[in]  Host            Host string.
> +  @param[in]  HostName        Hostname string.
> +  @param[in]  BasicAuth       Basic Authorization string.
> +  @param[in]  SessionToken    Session token string.
> +  @param[in]  RestEx          Rest EX protocol instance.
> +
> +  @retval     REDFISH_PAYLOAD_PRIVATE  Newly created service.
> +  @retval     NULL             Error occurs.
> +
> +**/
> +REDFISH_SERVICE_PRIVATE *
> +CreateRedfishService (
> +  IN CHAR8                 *Host,
> +  IN CHAR8                 *HostName,
> +  IN CHAR8                 *BasicAuth OPTIONAL,
> +  IN CHAR8                 *SessionToken OPTIONAL,
> +  IN EFI_REST_EX_PROTOCOL  *RestEx
> +  )
> +{
> +  REDFISH_SERVICE_PRIVATE  *NewService;
> +  UINTN                    AuthStrSize;
> +
> +  if (IS_EMPTY_STRING (Host) || IS_EMPTY_STRING (HostName) || (RestEx == NULL)) {
> +    return NULL;
> +  }
> +
> +  NewService = AllocateZeroPool (sizeof (REDFISH_SERVICE_PRIVATE));
> +  if (NewService == NULL) {
> +    return NULL;
> +  }
> +
> +  NewService->Signature = REDFISH_HTTP_SERVICE_SIGNATURE;
> +  NewService->Host      = AllocateCopyPool (AsciiStrSize (Host), Host);
> +  if (NewService->Host == NULL) {
> +    goto ON_ERROR;
> +  }
> +
> +  NewService->HostName = AllocateCopyPool (AsciiStrSize (HostName), HostName);
> +  if (NewService->HostName == NULL) {
> +    goto ON_ERROR;
> +  }
> +
> +  if (!IS_EMPTY_STRING (BasicAuth)) {
> +    AuthStrSize           = AsciiStrSize (BasicAuth) + AsciiStrLen (REDFISH_HTTP_BASIC_AUTH_STR);
> +    NewService->BasicAuth = AllocateZeroPool (AuthStrSize);
> +    if (NewService->BasicAuth == NULL) {
> +      goto ON_ERROR;
> +    }
> +
> +    AsciiSPrint (NewService->BasicAuth, AuthStrSize, "%a%a", REDFISH_HTTP_BASIC_AUTH_STR, BasicAuth);
> +  }
> +
> +  if (!IS_EMPTY_STRING (SessionToken)) {
> +    NewService->SessionToken = AllocateCopyPool (AsciiStrSize (SessionToken), SessionToken);
> +    if (NewService->SessionToken == NULL) {
> +      goto ON_ERROR;
> +    }
> +  }
> +
> +  NewService->RestEx = RestEx;
> +
> +  return NewService;
> +
> +ON_ERROR:
> +
> +  ReleaseRedfishService (NewService);
> +
> +  return NULL;
> +}
> +
> +/**
> +  This function release Redfish Payload.
> +
> +  @param[in]  Payload         Pointer to payload instance.
> +
> +  @retval     EFI_SUCCESS     Payload is released.
> +  @retval     Others          Error occurs.
> +
> +**/
> +EFI_STATUS
> +ReleaseRedfishPayload (
> +  IN REDFISH_PAYLOAD_PRIVATE  *Payload
> +  )
> +{
> +  if (Payload == NULL) {
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  if (Payload->Service != NULL) {
> +    ReleaseRedfishService (Payload->Service);
> +  }
> +
> +  if (Payload->JsonValue != NULL) {
> +    JsonValueFree (Payload->JsonValue);
> +  }
> +
> +  FreePool (Payload);
> +
> +  return EFI_SUCCESS;
> +}
> +
> +/**
> +  This function creat new payload. Server and JsonObj are
> +  copied to newly created payload.
> +
> +  @param[in]  Service          Pointer to Service instance.
> +  @param[in]  JsonValue        Pointer to JSON value.
> +
> +  @retval     REDFISH_PAYLOAD_PRIVATE  Newly created payload.
> +  @retval     NULL                     Error occurs.
> +
> +**/
> +REDFISH_PAYLOAD_PRIVATE *
> +CreateRedfishPayload (
> +  IN REDFISH_SERVICE_PRIVATE  *Service,
> +  IN EDKII_JSON_VALUE         JsonValue
> +  )
> +{
> +  REDFISH_PAYLOAD_PRIVATE  *NewPayload;
> +
> +  if ((Service == NULL) || (JsonValue == NULL)) {
> +    return NULL;
> +  }
> +
> +  NewPayload = AllocateZeroPool (sizeof (REDFISH_PAYLOAD_PRIVATE));
> +  if (NewPayload == NULL) {
> +    return NULL;
> +  }
> +
> +  NewPayload->Signature = REDFISH_HTTP_PAYLOAD_SIGNATURE;
> +  NewPayload->Service   = CreateRedfishService (Service->Host, Service->HostName, Service->BasicAuth, Service->SessionToken, Service->RestEx);
> +  if (NewPayload->Service == NULL) {
> +    goto ON_ERROR;
> +  }
> +
> +  NewPayload->JsonValue = JsonValueClone (JsonValue);
> +  if (NewPayload->JsonValue == NULL) {
> +    goto ON_ERROR;
> +  }
> +
> +  return NewPayload;
> +
> +ON_ERROR:
> +
> +  ReleaseRedfishPayload (NewPayload);
> +


NewPayload->Service  is leaked


> +  return NULL;
> +}
> +
> +/**
> +  This function copy the data in SrcResponse to DstResponse.
> +
> +  @param[in]  SrcResponse      Source Response to copy.
> +  @param[out] DstResponse      Destination Response.
> +
> +  @retval     EFI_SUCCESS      Response is copied successfully.
> +  @retval     Others           Error occurs.
> +
> +**/
> +EFI_STATUS
> +CopyRedfishResponse (
> +  IN  REDFISH_RESPONSE  *SrcResponse,
> +  OUT REDFISH_RESPONSE  *DstResponse
> +  )
> +{
> +  REDFISH_PAYLOAD_PRIVATE  *Payload;
> +  UINTN                    Index;
> +
> +  if ((SrcResponse == NULL) || (DstResponse == NULL)) {
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  if (SrcResponse == DstResponse) {
> +    return EFI_SUCCESS;
> +  }
> +
> +  //
> +  // Status code
> +  //
> +  if (SrcResponse->StatusCode != NULL) {
> +    DstResponse->StatusCode = AllocateCopyPool (sizeof (EFI_HTTP_STATUS_CODE), SrcResponse->StatusCode);
> +    if (DstResponse->StatusCode == NULL) {
> +      goto ON_ERROR;
> +    }
> +  }
> +
> +  //
> +  // Header
> +  //
> +  if ((SrcResponse->HeaderCount > 0) && (SrcResponse->Headers != NULL)) {
> +    DstResponse->HeaderCount = 0;
> +    DstResponse->Headers     = AllocateZeroPool (sizeof (EFI_HTTP_HEADER) * SrcResponse->HeaderCount);
> +    if (DstResponse->Headers == NULL) {
> +      goto ON_ERROR;
> +    }
> +
> +    for (Index = 0; Index < SrcResponse->HeaderCount; Index++) {
> +      DstResponse->Headers[Index].FieldName = AllocateCopyPool (AsciiStrSize (SrcResponse->Headers[Index].FieldName), SrcResponse->Headers[Index].FieldName);
> +      if (DstResponse->Headers[Index].FieldName == NULL) {
> +        goto ON_ERROR;
> +      }
> +
> +      DstResponse->Headers[Index].FieldValue = AllocateCopyPool (AsciiStrSize (SrcResponse->Headers[Index].FieldValue), SrcResponse->Headers[Index].FieldValue);
> +      if (DstResponse->Headers[Index].FieldValue == NULL) {
> +        goto ON_ERROR;
> +      }
> +
> +      DstResponse->HeaderCount += 1;
> +    }
> +  }
> +
> +  //
> +  // Payload
> +  //
> +  if (SrcResponse->Payload != NULL) {
> +    Payload = (REDFISH_PAYLOAD_PRIVATE *)SrcResponse->Payload;
> +    if (Payload->Signature != REDFISH_HTTP_PAYLOAD_SIGNATURE) {
> +      DEBUG ((DEBUG_ERROR, "%a: signature check failure\n", __func__));
> +      goto ON_ERROR;
> +    }
> +
> +    DstResponse->Payload = CreateRedfishPayload (Payload->Service, Payload->JsonValue);
> +    if (DstResponse->Payload  == NULL) {
> +      goto ON_ERROR;
> +    }
> +  }
> +
> +  return EFI_SUCCESS;
> +
> +ON_ERROR:
> +
> +  ReleaseRedfishResponse (DstResponse);
> +
> +  return EFI_OUT_OF_RESOURCES;
> +}
> +
> +/**
> +  This function clone input response and return to caller
> +
> +  @param[in]  Response      Response to clone.
> +
> +  @retval     REDFISH_RESPONSE *  Response is cloned.
> +  @retval     NULL                Errors occur.
> +
> +**/
> +REDFISH_RESPONSE *
> +CloneRedfishResponse (
> +  IN REDFISH_RESPONSE  *Response
> +  )
> +{
> +  EFI_STATUS        Status;
> +  REDFISH_RESPONSE  *NewResponse;
> +
> +  if (Response == NULL) {
> +    return NULL;
> +  }
> +
> +  NewResponse = AllocateZeroPool (sizeof (REDFISH_RESPONSE));
> +  if (NewResponse == NULL) {
> +    return NULL;
> +  }
> +
> +  Status = CopyRedfishResponse (Response, NewResponse);
> +  if (EFI_ERROR (Status)) {
> +    FreePool (NewResponse);
> +    return NULL;
> +  }
> +
> +  return NewResponse;
> +}
> +
> +/**
> +  Release REDFISH_HTTP_CACHE_DATA resource
> +
> +  @param[in]    Data    Pointer to REDFISH_HTTP_CACHE_DATA instance
> +
> +  @retval EFI_SUCCESS             REDFISH_HTTP_CACHE_DATA is released successfully.
> +  @retval EFI_INVALID_PARAMETER   Data is NULL
> +
> +**/
> +EFI_STATUS
> +ReleaseHttpCacheData (
> +  IN REDFISH_HTTP_CACHE_DATA  *Data
> +  )
> +{
> +  if (Data == NULL) {
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  if (Data->Uri != NULL) {
> +    FreePool (Data->Uri);
> +  }
> +
> +  if (Data->Response != NULL) {
> +    ReleaseRedfishResponse (Data->Response);
> +    FreePool (Data->Response);
> +  }
> +
> +  FreePool (Data);
> +
> +  return EFI_SUCCESS;
> +}
> +
> +/**
> +  Create new cache data.
> +
> +  @param[in]    Uri       The URI string matching to this cache data.
> +  @param[in]    Response  HTTP response.
> +
> +  @retval REDFISH_HTTP_CACHE_DATA *   Pointer to newly created cache data.
> +  @retval NULL                        No memory available.
> +
> +**/
> +REDFISH_HTTP_CACHE_DATA *
> +NewHttpCacheData (
> +  IN  EFI_STRING        Uri,
> +  IN  REDFISH_RESPONSE  *Response
> +  )
> +{
> +  REDFISH_HTTP_CACHE_DATA  *NewData;
> +  UINTN                    Size;
> +
> +  if (IS_EMPTY_STRING (Uri) || (Response == NULL)) {
> +    return NULL;
> +  }
> +
> +  NewData = AllocateZeroPool (sizeof (REDFISH_HTTP_CACHE_DATA));
> +  if (NewData == NULL) {
> +    return NULL;
> +  }
> +
> +  NewData->Signature = REDFISH_HTTP_CACHE_SIGNATURE;
> +  Size               = StrSize (Uri);
> +  NewData->Uri       = AllocateCopyPool (Size, Uri);
> +  if (NewData->Uri == NULL) {
> +    goto ON_ERROR;
> +  }
> +
> +  NewData->Response = Response;
> +  NewData->HitCount = 1;
> +
> +  return NewData;
> +
> +ON_ERROR:
> +
> +  if (NewData != NULL) {
> +    ReleaseHttpCacheData (NewData);
> +  }
> +
> +  return NULL;
> +}
> +
> +/**
> +  Search on given ListHeader for given URI string.
> +
> +  @param[in]    ListHeader  Target list to search.
> +  @param[in]    Uri         Target URI to search.
> +
> +  @retval REDFISH_HTTP_CACHE_DATA   Target cache data is found.
> +  @retval NULL                      No cache data with given URI is found.
> +
> +**/
> +REDFISH_HTTP_CACHE_DATA *
> +FindHttpCacheData (
> +  IN  LIST_ENTRY  *ListHeader,
> +  IN  EFI_STRING  Uri
> +  )
> +{
> +  LIST_ENTRY               *List;
> +  REDFISH_HTTP_CACHE_DATA  *Data;
> +
> +  if (IS_EMPTY_STRING (Uri)) {
> +    return NULL;
> +  }
> +
> +  if (IsListEmpty (ListHeader)) {
> +    return NULL;
> +  }
> +
> +  Data = NULL;
> +  List = GetFirstNode (ListHeader);
> +  while (!IsNull (ListHeader, List)) {
> +    Data = REDFISH_HTTP_CACHE_FROM_LIST (List);
> +
> +    if (StrCmp (Data->Uri, Uri) == 0) {
> +      return Data;
> +    }
> +
> +    List = GetNextNode (ListHeader, List);
> +  }
> +
> +  return NULL;
> +}
> +
> +/**
> +  Search on given ListHeader and return cache data with minimum hit count.
> +
> +  @param[in]    ListHeader  Target list to search.
> +
> +  @retval REDFISH_HTTP_CACHE_DATA   Target cache data is returned.
> +  @retval NULL                      No cache data is found.
> +
> +**/
> +REDFISH_HTTP_CACHE_DATA *
> +FindUnusedHttpCacheData (
> +  IN  LIST_ENTRY  *ListHeader
> +  )
> +{
> +  LIST_ENTRY               *List;
> +  REDFISH_HTTP_CACHE_DATA  *Data;
> +  REDFISH_HTTP_CACHE_DATA  *UnusedData;
> +  UINTN                    HitCount;
> +
> +  if (IsListEmpty (ListHeader)) {
> +    return NULL;
> +  }
> +
> +  Data       = NULL;
> +  UnusedData = NULL;
> +  HitCount   = 0;
> +
> +  List       = GetFirstNode (ListHeader);
> +  Data       = REDFISH_HTTP_CACHE_FROM_LIST (List);
> +  UnusedData = Data;
> +  HitCount   = Data->HitCount;
> +  List       = GetNextNode (ListHeader, List);
> +
> +  while (!IsNull (ListHeader, List)) {
> +    Data = REDFISH_HTTP_CACHE_FROM_LIST (List);
> +
> +    if (Data->HitCount < HitCount) {
> +      HitCount   = Data->HitCount;
> +      UnusedData = Data;
> +    }
> +
> +    List = GetNextNode (ListHeader, List);
> +  }
> +
> +  return UnusedData;
> +}
> +
> +/**
> +  Delete a cache data by given cache instance.
> +
> +  @param[in]    List    Target cache list to be removed.
> +  @param[in]    Data    Pointer to the instance to be deleted.
> +
> +  @retval EFI_SUCCESS   Cache data is removed.
> +  @retval Others        Fail to remove cache data.
> +
> +**/
> +EFI_STATUS
> +DeleteHttpCacheData (
> +  IN  REDFISH_HTTP_CACHE_LIST  *List,
> +  IN  REDFISH_HTTP_CACHE_DATA  *Data
> +  )
> +{
> +  if ((List == NULL) || (Data == NULL)) {
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  DEBUG ((REDFISH_HTTP_CACHE_DEBUG, "%a: delete: %s\n", __func__, Data->Uri));
> +
> +  RemoveEntryList (&Data->List);
> +  --List->Count;
> +
> +  return ReleaseHttpCacheData (Data);
> +}
> +
> +/**
> +  Add new cache by given URI and HTTP response to specify List.
> +
> +  @param[in]    List      Target cache list to add.
> +  @param[in]    Uri       The URI string matching to this cache data.
> +  @param[in]    Response  HTTP response.
> +
> +  @retval EFI_SUCCESS   Cache data is added.
> +  @retval Others        Fail to add cache data.
> +
> +**/
> +EFI_STATUS
> +AddHttpCacheData (
> +  IN  REDFISH_HTTP_CACHE_LIST  *List,
> +  IN  EFI_STRING               Uri,
> +  IN  REDFISH_RESPONSE         *Response
> +  )
> +{
> +  REDFISH_HTTP_CACHE_DATA  *NewData;
> +  REDFISH_HTTP_CACHE_DATA  *OldData;
> +  REDFISH_HTTP_CACHE_DATA  *UnusedData;
> +  REDFISH_RESPONSE         *NewResponse;
> +
> +  if ((List == NULL) || IS_EMPTY_STRING (Uri) || (Response == NULL)) {
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  //
> +  // If same cache data exist, replace it with latest one.
> +  //
> +  OldData = FindHttpCacheData (&List->Head, Uri);
> +  if (OldData != NULL) {
> +    DeleteHttpCacheData (List, OldData);
> +  }
> +
> +  //
> +  // Check capacity
> +  //
> +  if (List->Count >= List->Capacity) {
> +    DEBUG ((REDFISH_HTTP_CACHE_DEBUG, "%a: list is full and retire unused cache\n", __func__));
> +    UnusedData = FindUnusedHttpCacheData (&List->Head);
> +    if (UnusedData == NULL) {
> +      return EFI_OUT_OF_RESOURCES;
> +    }
> +
> +    DeleteHttpCacheData (List, UnusedData);
> +  }
> +
> +  //
> +  // Clone a local copy
> +  //
> +  NewResponse = CloneRedfishResponse (Response);
> +  if (NewResponse == NULL) {
> +    return EFI_OUT_OF_RESOURCES;
> +  }
> +
> +  NewData = NewHttpCacheData (Uri, NewResponse);
> +  if (NewData == NULL) {
> +    return EFI_OUT_OF_RESOURCES;
> +  }
> +
> +  InsertTailList (&List->Head, &NewData->List);
> +  ++List->Count;
> +
> +  DEBUG ((REDFISH_HTTP_CACHE_DEBUG, "%a: cache(%d/%d) %s\n", __func__, List->Count, List->Capacity, NewData->Uri));
> +
> +  return EFI_SUCCESS;
> +}
> +
> +/**
> +  Release all cache from list.
> +
> +  @param[in]    CacheList    The list to be released.
> +
> +  @retval EFI_SUCCESS             All cache data are released.
> +  @retval EFI_INVALID_PARAMETER   CacheList is NULL.
> +
> +**/
> +EFI_STATUS
> +ReleaseCacheList (
> +  IN  REDFISH_HTTP_CACHE_LIST  *CacheList
> +  )
> +{
> +  LIST_ENTRY               *List;
> +  LIST_ENTRY               *Next;
> +  REDFISH_HTTP_CACHE_DATA  *Data;
> +
> +  if (CacheList == NULL) {
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  if (IsListEmpty (&CacheList->Head)) {
> +    return EFI_SUCCESS;
> +  }
> +
> +  Data = NULL;
> +  Next = NULL;
> +  List = GetFirstNode (&CacheList->Head);
> +  while (!IsNull (&CacheList->Head, List)) {
> +    Data = REDFISH_HTTP_CACHE_FROM_LIST (List);
> +    Next = GetNextNode (&CacheList->Head, List);
> +
> +    DeleteHttpCacheData (CacheList, Data);
> +
> +    List = Next;
> +  }
> +
> +  return EFI_SUCCESS;
> +}
> diff --git a/RedfishPkg/RedfishHttpDxe/RedfishHttpDxe.c b/RedfishPkg/RedfishHttpDxe/RedfishHttpDxe.c
> new file mode 100644
> index 0000000000..39958d4865
> --- /dev/null
> +++ b/RedfishPkg/RedfishHttpDxe/RedfishHttpDxe.c
> @@ -0,0 +1,1344 @@
> +/** @file
> +  RedfishHttpDxe produces EdkIIRedfishHttpProtocol
> +  for EDK2 Redfish Feature driver to do HTTP operations.
> +
> +  Copyright (c) 2023-2024, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
> +
> +  SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +#include "RedfishHttpDxe.h"
> +#include "RedfishHttpData.h"
> +#include "RedfishHttpOperation.h"
> +
> +REDFISH_HTTP_CACHE_PRIVATE  *mRedfishHttpCachePrivate = NULL;
> +
> +/**
> +  Debug output the cache list.
> +
> +  @param[in]    Msg            Debug message string.
> +  @param[in]    ErrorLevel     Output error level.
> +  @param[in]    CacheList      Target list to dump.
> +
> +  @retval EFI_SUCCESS             Debug dump finished.
> +  @retval EFI_INVALID_PARAMETER   HttpCacheList is NULL.
> +
> +**/
> +EFI_STATUS
> +DebugPrintHttpCacheList (
> +  IN  CONST CHAR8              *Msg,
> +  IN  UINTN                    ErrorLevel,
> +  IN  REDFISH_HTTP_CACHE_LIST  *CacheList
> +  )
> +{
> +  LIST_ENTRY               *List;
> +  REDFISH_HTTP_CACHE_DATA  *Data;
> +  UINTN                    Index;
> +
> +  if (CacheList == NULL) {
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  if (!IS_EMPTY_STRING (Msg)) {
> +    DEBUG ((ErrorLevel, "%a\n", Msg));
> +  }
> +
> +  if (IsListEmpty (&CacheList->Head)) {
> +    DEBUG ((ErrorLevel, "list is empty\n"));
> +    return EFI_NOT_FOUND;
> +  }
> +
> +  DEBUG ((ErrorLevel, "list count: %d capacity: %d\n", CacheList->Count, CacheList->Capacity));
> +  Data  = NULL;
> +  Index = 0;
> +  List  = GetFirstNode (&CacheList->Head);
> +  while (!IsNull (&CacheList->Head, List)) {
> +    Data = REDFISH_HTTP_CACHE_FROM_LIST (List);
> +
> +    DEBUG ((ErrorLevel, "%d) Uri: %s Hit: %d\n", ++Index, Data->Uri, Data->HitCount));
> +
> +    List = GetNextNode (&CacheList->Head, List);
> +  }
> +
> +  return EFI_SUCCESS;
> +}
> +
> +/**
> +
> +  Check HTTP status code to see if we like to retry HTTP request or not.
> +
> +  @param[in]  StatusCode      HTTP status code.
> +
> +  @retval     BOOLEAN         Return true when we like to retry request.
> +                              Return false when we don't want to retry request.
> +
> +**/
> +BOOLEAN
> +RedfishRetryRequired (
> +  IN EFI_HTTP_STATUS_CODE  *StatusCode
> +  )
> +{
> +  if (StatusCode == NULL) {
> +    return TRUE;
> +  }
> +
> +  if ((*StatusCode == HTTP_STATUS_500_INTERNAL_SERVER_ERROR) ||
> +      (*StatusCode == HTTP_STATUS_UNSUPPORTED_STATUS))
> +  {
> +    return TRUE;
> +  }
> +
> +  return FALSE;
> +}
> +
> +/**
> +
> +  Convert Unicode string to ASCII string. It's call responsibility to release returned buffer.
> +
> +  @param[in]  UnicodeStr      Unicode string to convert.
> +
> +  @retval     CHAR8 *         ASCII string returned.
> +  @retval     NULL            Errors occur.
> +
> +**/
> +CHAR8 *
> +StringUnicodeToAscii (
> +  IN EFI_STRING  UnicodeStr
> +  )
> +{
> +  CHAR8       *AsciiStr;
> +  UINTN       AsciiStrSize;
> +  EFI_STATUS  Status;
> +
> +  if (IS_EMPTY_STRING (UnicodeStr)) {
> +    return NULL;
> +  }
> +
> +  AsciiStrSize = StrLen (UnicodeStr) + 1;
> +  AsciiStr     = AllocateZeroPool (AsciiStrSize);
> +  if (AsciiStr == NULL) {
> +    return NULL;
> +  }
> +
> +  Status = UnicodeStrToAsciiStrS (UnicodeStr, AsciiStr, AsciiStrSize);
> +  if (EFI_ERROR (Status)) {
> +    DEBUG ((DEBUG_ERROR, "UnicodeStrToAsciiStrS failed: %r\n", Status));
> +    FreePool (AsciiStr);
> +    return NULL;
> +  }
> +
> +  return AsciiStr;
> +}
> +
> +/**
> +  Return HTTP method in ASCII string. Caller does not need
> +  to free returned string buffer.
> +
> +  @param[in]  Method         HTTP method.
> +
> +  @retval CHAR8 *   Method in string.
> +**/
> +CHAR8 *
> +HttpMethodToString (
> +  IN  EFI_HTTP_METHOD  Method
> +  )
> +{
> +  switch (Method) {
> +    case HttpMethodGet:
> +      return HTTP_METHOD_GET;
> +      break;
> +    case HttpMethodPost:
> +      return HTTP_METHOD_POST;
> +      break;
> +    case HttpMethodPatch:
> +      return HTTP_METHOD_PATCH;
> +      break;
> +    case HttpMethodPut:
> +      return HTTP_METHOD_PUT;
> +      break;
> +    case HttpMethodDelete:
> +      return HTTP_METHOD_DELETE;
> +      break;
> +    default:
> +      break;
> +  }
> +
> +  return "Unknown";
> +}
> +
> +/**
> +  Report HTTP communication error via report status code.
> +
> +  @param[in]  Method         HTTP method.
> +  @param[in]  Uri            The URI which has failure.
> +  @param[in]  HttpStatusCode HTTP status code.
> +
> +**/
> +VOID
> +ReportHttpError (
> +  IN  EFI_HTTP_METHOD       Method,
> +  IN  EFI_STRING            Uri,
> +  IN  EFI_HTTP_STATUS_CODE  *HttpStatusCode  OPTIONAL
> +  )
> +{
> +  CHAR8  ErrorMsg[REDFISH_ERROR_MSG_MAX];
> +
> +  if (IS_EMPTY_STRING (Uri)) {
> +    DEBUG ((DEBUG_ERROR, "%a: no URI to report error status\n", __func__));
> +    return;
> +  }
> +
> +  //
> +  // Report failure of URI and HTTP status code.
> +  //
> +  AsciiSPrint (ErrorMsg, sizeof (ErrorMsg), REDFISH_HTTP_ERROR_REPORT, HttpMethodToString (Method), (HttpStatusCode == NULL ? HTTP_STATUS_UNSUPPORTED_STATUS : *HttpStatusCode), Uri);
> +  DEBUG ((DEBUG_ERROR, "%a\n", ErrorMsg));
> +  //
> +  // TODO:
> +  // Below PI status code is approved by PIWG and wait for specification published.
> +  // We will uncomment below report status code after PI status code get published.
> +  // REF: https://bugzilla.tianocore.org/show_bug.cgi?id=4483
> +  //
> +  // REPORT_STATUS_CODE_WITH_EXTENDED_DATA (
> +  //  EFI_ERROR_CODE | EFI_ERROR_MAJOR,
> +  //  EFI_COMPUTING_UNIT_MANAGEABILITY | EFI_MANAGEABILITY_EC_REDFISH_COMMUNICATION_ERROR,
> +  //  ErrorMsg,
> +  //  AsciiStrSize (ErrorMsg)
> +  //  );
> +}
> +
> +/**
> +  This function create Redfish service. It's caller's responsibility to free returned
> +  Redfish service by calling FreeService ().
> +
> +  @param[in]  This                       Pointer to EDKII_REDFISH_HTTP_PROTOCOL instance.
> +  @param[in]  RedfishConfigServiceInfo   Redfish config service information.
> +
> +  @retval     REDFISH_SERVICE  Redfish service is created.
> +  @retval     NULL             Errors occur.
> +
> +**/
> +REDFISH_SERVICE
> +EFIAPI
> +RedfishCreateRedfishService (
> +  IN  EDKII_REDFISH_HTTP_PROTOCOL         *This,
> +  IN  REDFISH_CONFIG_SERVICE_INFORMATION  *RedfishConfigServiceInfo
> +  )
> +{
> +  EFI_STATUS                  Status;
> +  REDFISH_HTTP_CACHE_PRIVATE  *Private;
> +  REDFISH_SERVICE_PRIVATE     *NewService;
> +  CHAR8                       *AsciiLocation;
> +  CHAR8                       *Host;
> +  CHAR8                       *BasicAuthString;
> +  UINTN                       BasicAuthStrSize;
> +  CHAR8                       *EncodedAuthString;
> +  UINTN                       EncodedAuthStrSize;
> +  EDKII_REDFISH_AUTH_METHOD   AuthMethod;
> +  CHAR8                       *Username;
> +  CHAR8                       *Password;
> +  UINTN                       UsernameSize;
> +  UINTN                       PasswordSize;
> +  EFI_REST_EX_PROTOCOL        *RestEx;
> +
> +  if ((This == NULL) || (RedfishConfigServiceInfo == NULL)) {
> +    return NULL;
> +  }
> +
> +  DEBUG ((REDFISH_HTTP_CACHE_DEBUG, "%a: service location: %s\n", __func__, RedfishConfigServiceInfo->RedfishServiceLocation));
> +
> +  Private            = REDFISH_HTTP_CACHE_PRIVATE_FROM_THIS (This);
> +  BasicAuthString    = NULL;
> +  EncodedAuthString  = NULL;
> +  Username           = NULL;
> +  Password           = NULL;
> +  NewService         = NULL;
> +  AsciiLocation      = NULL;
> +  Host               = NULL;
> +  BasicAuthStrSize   = 0;
> +  EncodedAuthStrSize = 0;
> +  UsernameSize       = 0;
> +  PasswordSize       = 0;
> +
> +  //
> +  // Build host and host name from service location
> +  //
> +  if (!IS_EMPTY_STRING (RedfishConfigServiceInfo->RedfishServiceLocation)) {
> +    AsciiLocation = StringUnicodeToAscii (RedfishConfigServiceInfo->RedfishServiceLocation);
> +    if (AsciiLocation == NULL) {
> +      goto ON_RELEASE;
> +    }
> +
> +    Host = AllocateZeroPool (REDFISH_HOST_NAME_MAX);
> +    if (AsciiLocation == NULL) {
> +      goto ON_RELEASE;
> +    }
> +
> +    if (RedfishConfigServiceInfo->RedfishServiceUseHttps) {
> +      AsciiSPrint (Host, REDFISH_HOST_NAME_MAX, "https://%a", AsciiLocation);
> +    } else {
> +      AsciiSPrint (Host, REDFISH_HOST_NAME_MAX, "http://%a", AsciiLocation);
> +    }
> +
> +    DEBUG ((REDFISH_HTTP_CACHE_DEBUG, "%a: Host: %a\n", __func__, Host));
> +  }
> +
> +  //
> +  // Find Rest Ex protocol
> +  //
> +  if (RedfishConfigServiceInfo->RedfishServiceRestExHandle != NULL) {
> +    Status = gBS->HandleProtocol (
> +                    RedfishConfigServiceInfo->RedfishServiceRestExHandle,
> +                    &gEfiRestExProtocolGuid,
> +                    (VOID **)&RestEx
> +                    );
> +  } else {
> +    DEBUG ((DEBUG_ERROR, "%a: Rest Ex protocol is not available\n", __func__));
> +    goto ON_RELEASE;
> +  }
> +
> +  //
> +  // Get credential
> +  //
> +  if (Private->CredentialProtocol == NULL) {
> +    //
> +    // No credential available on this system.
> +    //
> +    DEBUG ((DEBUG_WARN, "%a: no credential protocol available\n", __func__));
> +  } else {
> +    Status = Private->CredentialProtocol->GetAuthInfo (
> +                                            Private->CredentialProtocol,
> +                                            &AuthMethod,
> +                                            &Username,
> +                                            &Password
> +                                            );
> +    if (EFI_ERROR (Status) || IS_EMPTY_STRING (Username) || IS_EMPTY_STRING (Password)) {
> +      DEBUG ((DEBUG_ERROR, "%a: cannot get authentication information: %r\n", __func__, Status));
> +      goto ON_RELEASE;
> +    } else {
> +      DEBUG ((REDFISH_HTTP_CACHE_DEBUG, "%a: Auth method: 0x%x username: %a password: %a\n", __func__, AuthMethod, Username, Password));
> +
> +      //
> +      // Perform base64 encoding (RFC 7617)
> +      //
> +      UsernameSize     = AsciiStrSize (Username);
> +      PasswordSize     = AsciiStrSize (Password);
> +      BasicAuthStrSize =  UsernameSize + PasswordSize;  // one byte taken from null-terminator for ':'
> +      BasicAuthString  = AllocateZeroPool (BasicAuthStrSize);
> +      if (BasicAuthString == NULL) {
> +        goto ON_RELEASE;
> +      }
> +
> +      AsciiSPrint (
> +        BasicAuthString,
> +        BasicAuthStrSize,
> +        "%a:%a",
> +        Username,
> +        Password
> +        );
> +
> +      Status = Base64Encode (
> +                 (CONST UINT8 *)BasicAuthString,
> +                 BasicAuthStrSize,
> +                 EncodedAuthString,
> +                 &EncodedAuthStrSize
> +                 );
> +      if ((Status == EFI_BUFFER_TOO_SMALL) && (EncodedAuthStrSize > 0)) {
> +        EncodedAuthString = AllocateZeroPool (EncodedAuthStrSize);
> +        if (EncodedAuthString == NULL) {
> +          goto ON_RELEASE;
> +        }
> +
> +        Status = Base64Encode (
> +                   (CONST UINT8 *)BasicAuthString,
> +                   BasicAuthStrSize,
> +                   EncodedAuthString,
> +                   &EncodedAuthStrSize
> +                   );
> +        if (EFI_ERROR (Status)) {
> +          DEBUG ((DEBUG_ERROR, "%a: Base64Encode failure: %r\n", __func__, Status));
> +        }
> +
> +        DEBUG ((REDFISH_HTTP_CACHE_DEBUG, "%a: Basic authorization: %a\n", __func__, EncodedAuthString));
> +      } else {
> +        DEBUG ((DEBUG_ERROR, "%a: Base64Encode failure: %r\n", __func__, Status));
> +        goto ON_RELEASE;
> +      }
> +    }
> +  }
> +
> +  NewService = CreateRedfishService (Host, AsciiLocation, EncodedAuthString, NULL, RestEx);
> +  if (NewService == NULL) {
> +    DEBUG ((DEBUG_ERROR, "%a: CreateRedfishService\n", __func__));
> +  }
> +
> +ON_RELEASE:
> +
> +  if (BasicAuthString != NULL) {
> +    ZeroMem (BasicAuthString, BasicAuthStrSize);
> +    FreePool (BasicAuthString);
> +  }
> +
> +  if (EncodedAuthString != NULL) {
> +    ZeroMem (BasicAuthString, EncodedAuthStrSize);
> +    FreePool (EncodedAuthString);
> +  }
> +
> +  if (Username != NULL) {
> +    ZeroMem (Username, UsernameSize);
> +    FreePool (Username);
> +  }
> +
> +  if (Password != NULL) {
> +    ZeroMem (Password, PasswordSize);
> +    FreePool (Password);
> +  }
> +
> +  if (AsciiLocation != NULL) {
> +    FreePool (AsciiLocation);
> +  }
> +
> +  if (Host != NULL) {
> +    FreePool (Host);
> +  }
> +
> +  return NewService;
> +}
> +
> +/**
> +  This function free resources in Redfish service. RedfishService is no longer available
> +  after this function returns successfully.
> +
> +  @param[in]  This            Pointer to EDKII_REDFISH_HTTP_PROTOCOL instance.
> +  @param[in]  RedfishService  Pointer to Redfish service to be released.
> +
> +  @retval     EFI_SUCCESS     Resrouce is released successfully.
> +  @retval     Others          Errors occur.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +RedfishFreeRedfishService (
> +  IN  EDKII_REDFISH_HTTP_PROTOCOL  *This,
> +  IN  REDFISH_SERVICE              RedfishService
> +  )
> +{
> +  REDFISH_SERVICE_PRIVATE  *Service;
> +
> +  if ((This == NULL) || (RedfishService == NULL)) {
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  Service = (REDFISH_SERVICE_PRIVATE *)RedfishService;
> +  if (Service->Signature != REDFISH_HTTP_SERVICE_SIGNATURE) {
> +    DEBUG ((DEBUG_ERROR, "%a: signature check failure\n", __func__));
> +  }
> +
> +  return ReleaseRedfishService (Service);
> +}
> +
> +/**
> +  This function returns JSON value in given RedfishPayload. Returned JSON value
> +  is a reference to the JSON value in RedfishPayload. Any modification to returned
> +  JSON value will change JSON value in RedfishPayload.
> +
> +  @param[in]  This            Pointer to EDKII_REDFISH_HTTP_PROTOCOL instance.
> +  @param[in]  RedfishPayload  Pointer to Redfish payload.
> +
> +  @retval     EDKII_JSON_VALUE   JSON value is returned.
> +  @retval     NULL               Errors occur.
> +
> +**/
> +EDKII_JSON_VALUE
> +EFIAPI
> +RedfishJsonInRedfishPayload (
> +  IN  EDKII_REDFISH_HTTP_PROTOCOL  *This,
> +  IN  REDFISH_PAYLOAD              RedfishPayload
> +  )
> +{
> +  REDFISH_PAYLOAD_PRIVATE  *Payload;
> +
> +  if ((This == NULL) || (RedfishPayload == NULL)) {
> +    return NULL;
> +  }
> +
> +  Payload = (REDFISH_PAYLOAD_PRIVATE *)RedfishPayload;
> +  if (Payload->Signature != REDFISH_HTTP_PAYLOAD_SIGNATURE) {
> +    DEBUG ((DEBUG_ERROR, "%a: signature check failure\n", __func__));
> +  }
> +
> +  return Payload->JsonValue;
> +}
> +
> +/**
> +  Perform HTTP GET to Get redfish resource from given resource URI with
> +  cache mechanism supported. It's caller's responsibility to free Response
> +  by calling FreeResponse ().
> +
> +  @param[in]  This          Pointer to EDKII_REDFISH_HTTP_PROTOCOL instance.
> +  @param[in]  Service       Redfish service instance to perform HTTP GET.
> +  @param[in]  Uri           Target resource URI.
> +  @param[in]  Request       Additional request context. This is optional.
> +  @param[out] Response      HTTP response from redfish service.
> +  @param[in]  UseCache      If it is TRUE, this function will search for
> +                            cache first. If it is FALSE, this function
> +                            will query Redfish URI directly.
> +
> +  @retval     EFI_SUCCESS     Resrouce is returned successfully.
> +  @retval     Others          Errors occur.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +RedfishGetResource (
> +  IN  EDKII_REDFISH_HTTP_PROTOCOL  *This,
> +  IN  REDFISH_SERVICE              Service,
> +  IN  EFI_STRING                   Uri,
> +  IN  REDFISH_REQUEST              *Request OPTIONAL,
> +  OUT REDFISH_RESPONSE             *Response,
> +  IN  BOOLEAN                      UseCache
> +  )
> +{
> +  EFI_STATUS                  Status;
> +  REDFISH_HTTP_CACHE_DATA     *CacheData;
> +  UINTN                       RetryCount;
> +  REDFISH_HTTP_CACHE_PRIVATE  *Private;
> +
> +  if ((This == NULL) || (Service == NULL) || (Response == NULL) || IS_EMPTY_STRING (Uri)) {
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  DEBUG ((REDFISH_HTTP_CACHE_DEBUG, "%a: Get URI: %s cache: %a\n", __func__, Uri, (UseCache ? "true" : "false")));
> +
> +  Private    = REDFISH_HTTP_CACHE_PRIVATE_FROM_THIS (This);
> +  CacheData  = NULL;
> +  RetryCount = 0;
> +  ZeroMem (Response, sizeof (REDFISH_RESPONSE));
> +
> +  if (Private->CacheDisabled) {
> +    UseCache = FALSE;
> +    DEBUG ((REDFISH_HTTP_CACHE_DEBUG, "%a: cache is disabled by PCD!\n", __func__));
> +  }
> +
> +  //
> +  // Search for cache list.
> +  //
> +  if (UseCache) {
> +    CacheData = FindHttpCacheData (&Private->CacheList.Head, Uri);
> +    if (CacheData != NULL) {
> +      DEBUG ((REDFISH_HTTP_CACHE_DEBUG_REQUEST, "%a: cache hit! %s\n", __func__, Uri));
> +
> +      //
> +      // Copy cached response to caller's buffer.
> +      //
> +      Status               = CopyRedfishResponse (CacheData->Response, Response);
> +      CacheData->HitCount += 1;
> +      return Status;
> +    }
> +  }
> +
> +  //
> +  // Get resource from redfish service.
> +  //
> +  do {
> +    RetryCount += 1;
> +    Status      = HttpSendReceive (
> +                    Service,
> +                    Uri,
> +                    HttpMethodGet,
> +                    Request,
> +                    Response
> +                    );
> +    DEBUG ((REDFISH_HTTP_CACHE_DEBUG_REQUEST, "%a: HTTP request: %s :%r\n", __func__, Uri, Status));
> +    if (!EFI_ERROR (Status) || (RetryCount >= Private->RetrySetting.MaximumRetryGet)) {
> +      break;
> +    }
> +
> +    //
> +    // Retry when BMC is not ready.
> +    //
> +    if ((Response->StatusCode != NULL)) {
> +      DEBUG_CODE (
> +        DumpRedfishResponse (NULL, DEBUG_ERROR, Response);
> +        );
> +
> +      if (!RedfishRetryRequired (Response->StatusCode)) {
> +        break;
> +      }
> +
> +      //
> +      // Release response for next round of request.
> +      //
> +      This->FreeResponse (This, Response);
> +    }
> +
> +    DEBUG ((DEBUG_WARN, "%a: RedfishGetByUriEx failed, retry (%d/%d)\n", __func__, RetryCount, Private->RetrySetting.MaximumRetryGet));
> +    if (Private->RetrySetting.RetryWait > 0) {
> +      gBS->Stall (Private->RetrySetting.RetryWait);
> +    }
> +  } while (TRUE);
> +
> +  if (EFI_ERROR (Status)) {
> +    DEBUG_CODE (
> +      DumpRedfishResponse (NULL, DEBUG_ERROR, Response);
> +      );
> +    //
> +    // Report status code for Redfish failure
> +    //
> +    ReportHttpError (HttpMethodGet, Uri, Response->StatusCode);
> +    DEBUG ((DEBUG_ERROR, "%a: get %s failed (%d/%d): %r\n", __func__, Uri, RetryCount, Private->RetrySetting.MaximumRetryGet, Status));
> +    goto ON_RELEASE;
> +  }
> +
> +  if (!Private->CacheDisabled) {
> +    //
> +    // Keep response in cache list
> +    //
> +    Status = AddHttpCacheData (&Private->CacheList, Uri, Response);
> +    if (EFI_ERROR (Status)) {
> +      DEBUG ((DEBUG_ERROR, "%a: failed to cache %s: %r\n", __func__, Uri, Status));
> +      goto ON_RELEASE;
> +    }
> +
> +    DEBUG_CODE (
> +      DebugPrintHttpCacheList (__func__, REDFISH_HTTP_CACHE_DEBUG_DUMP, &Private->CacheList);
> +      );
> +  }
> +
> +ON_RELEASE:
> +
> +  return Status;
> +}
> +
> +/**
> +  This function free resources in Request. Request is no longer available
> +  after this function returns successfully.
> +
> +  @param[in]  This         Pointer to EDKII_REDFISH_HTTP_PROTOCOL instance.
> +  @param[in]  Request      HTTP request to be released.
> +
> +  @retval     EFI_SUCCESS     Resrouce is released successfully.
> +  @retval     Others          Errors occur.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +RedfishFreeRequest (
> +  IN  EDKII_REDFISH_HTTP_PROTOCOL  *This,
> +  IN  REDFISH_REQUEST              *Request
> +  )
> +{
> +  if ((This == NULL) || (Request == NULL)) {
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  DEBUG ((REDFISH_HTTP_CACHE_DEBUG, "%a: entry\n", __func__));
> +
> +  return ReleaseRedfishRequest (Request);
> +}
> +
> +/**
> +  This function free resources in given Response.
> +
> +  @param[in]  This         Pointer to EDKII_REDFISH_HTTP_PROTOCOL instance.
> +  @param[in]  Response     HTTP response to be released.
> +
> +  @retval     EFI_SUCCESS     Resrouce is released successfully.
> +  @retval     Others          Errors occur.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +RedfishFreeResponse (
> +  IN  EDKII_REDFISH_HTTP_PROTOCOL  *This,
> +  IN  REDFISH_RESPONSE             *Response
> +  )
> +{
> +  if ((This == NULL) || (Response == NULL)) {
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  DEBUG ((REDFISH_HTTP_CACHE_DEBUG, "%a: entry\n", __func__));
> +
> +  return ReleaseRedfishResponse (Response);
> +}
> +
> +/**
> +  This function expire the cached response of given URI.
> +
> +  @param[in]  This         Pointer to EDKII_REDFISH_HTTP_PROTOCOL instance.
> +  @param[in]  Uri          Target response of URI.
> +
> +  @retval     EFI_SUCCESS     Target response is expired successfully.
> +  @retval     Others          Errors occur.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +RedfishExpireResponse (
> +  IN  EDKII_REDFISH_HTTP_PROTOCOL  *This,
> +  IN  EFI_STRING                   Uri
> +  )
> +{
> +  REDFISH_HTTP_CACHE_PRIVATE  *Private;
> +  REDFISH_HTTP_CACHE_DATA     *CacheData;
> +
> +  if ((This == NULL) || IS_EMPTY_STRING (Uri)) {
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  DEBUG ((REDFISH_HTTP_CACHE_DEBUG, "%a: expire URI: %s\n", __func__, Uri));
> +
> +  Private = REDFISH_HTTP_CACHE_PRIVATE_FROM_THIS (This);
> +
> +  CacheData = FindHttpCacheData (&Private->CacheList.Head, Uri);
> +  if (CacheData == NULL) {
> +    return EFI_NOT_FOUND;
> +  }
> +
> +  return DeleteHttpCacheData (&Private->CacheList, CacheData);
> +}
> +
> +/**
> +  Perform HTTP PATCH to send redfish resource to given resource URI.
> +  It's caller's responsibility to free Response by calling FreeResponse ().
> +
> +  @param[in]  This          Pointer to EDKII_REDFISH_HTTP_PROTOCOL instance.
> +  @param[in]  Service       Redfish service instance to perform HTTP PATCH.
> +  @param[in]  Uri           Target resource URI.
> +  @param[in]  Content       Data to patch.
> +  @param[in]  ContentSize   Size of the Content to be send to Redfish service.
> +                            This is optional. When ContentSize is 0, ContentSize
> +                            is the size of Content.
> +  @param[in]  ContentType   Type of the Content to be send to Redfish service.
> +                            This is optional. When ContentType is NULL, content
> +                            type HTTP_CONTENT_TYPE_APP_JSON will be used.
> +  @param[out] Response      HTTP response from redfish service.
> +
> +  @retval     EFI_SUCCESS     Resrouce is returned successfully.
> +  @retval     Others          Errors occur.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +RedfishPatchResource (
> +  IN  EDKII_REDFISH_HTTP_PROTOCOL  *This,
> +  IN  REDFISH_SERVICE              Service,
> +  IN  EFI_STRING                   Uri,
> +  IN  CHAR8                        *Content,
> +  IN  UINTN                        ContentSize OPTIONAL,
> +  IN  CHAR8                        *ContentType OPTIONAL,
> +  OUT REDFISH_RESPONSE             *Response
> +  )
> +{
> +  EFI_STATUS                  Status;
> +  UINTN                       RetryCount;
> +  REDFISH_REQUEST             Request;
> +  REDFISH_HTTP_CACHE_PRIVATE  *Private;
> +
> +  if ((This == NULL) || (Service == NULL) || (Response == NULL) || IS_EMPTY_STRING (Uri) || IS_EMPTY_STRING (Content)) {
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  DEBUG ((REDFISH_HTTP_CACHE_DEBUG, "%a: Patch URI: %s\n", __func__, Uri));
> +
> +  Private    = REDFISH_HTTP_CACHE_PRIVATE_FROM_THIS (This);
> +  RetryCount = 0;
> +  ZeroMem (Response, sizeof (REDFISH_RESPONSE));
> +  ZeroMem (&Request, sizeof (REDFISH_REQUEST));
> +
> +  Request.Content       = Content;
> +  Request.ContentLength = ContentSize;
> +  Request.ContentType   = ContentType;
> +
> +  //
> +  // Patch resource to redfish service.
> +  //
> +  do {
> +    RetryCount += 1;
> +    Status      = HttpSendReceive (
> +                    Service,
> +                    Uri,
> +                    HttpMethodPatch,
> +                    &Request,
> +                    Response
> +                    );
> +    DEBUG ((REDFISH_HTTP_CACHE_DEBUG_REQUEST, "%a: HTTP request: %s :%r\n", __func__, Uri, Status));
> +    if (!EFI_ERROR (Status) || (RetryCount >= Private->RetrySetting.MaximumRetryPatch)) {
> +      break;
> +    }
> +
> +    //
> +    // Retry when BMC is not ready.
> +    //
> +    if ((Response->StatusCode != NULL)) {
> +      DEBUG_CODE (
> +        DumpRedfishResponse (NULL, DEBUG_ERROR, Response);
> +        );
> +
> +      if (!RedfishRetryRequired (Response->StatusCode)) {
> +        break;
> +      }
> +
> +      //
> +      // Release response for next round of request.
> +      //
> +      This->FreeResponse (This, Response);
> +    }
> +
> +    DEBUG ((DEBUG_WARN, "%a: RedfishPatchToUriEx failed, retry (%d/%d)\n", __func__, RetryCount, Private->RetrySetting.MaximumRetryPatch));
> +    if (Private->RetrySetting.RetryWait > 0) {
> +      gBS->Stall (Private->RetrySetting.RetryWait);
> +    }
> +  } while (TRUE);
> +
> +  //
> +  // Redfish resource is updated. Automatically expire the cached response
> +  // so application can directly get resource from Redfish service again.
> +  //
> +  DEBUG ((REDFISH_HTTP_CACHE_DEBUG, "%a: Resource is updated, expire URI: %s\n", __func__, Uri));
> +  RedfishExpireResponse (This, Uri);
> +
> +  if (EFI_ERROR (Status)) {
> +    DEBUG_CODE (
> +      DumpRedfishResponse (NULL, DEBUG_ERROR, Response);
> +      );
> +    //
> +    // Report status code for Redfish failure
> +    //
> +    ReportHttpError (HttpMethodPatch, Uri, Response->StatusCode);
> +    DEBUG ((DEBUG_ERROR, "%a: patch %s failed (%d/%d): %r\n", __func__, Uri, RetryCount, Private->RetrySetting.MaximumRetryPatch, Status));
> +    goto ON_RELEASE;
> +  }
> +
> +ON_RELEASE:
> +
> +  return Status;
> +}
> +
> +/**
> +  Perform HTTP PUT to send redfish resource to given resource URI.
> +  It's caller's responsibility to free Response by calling FreeResponse ().
> +
> +  @param[in]  This          Pointer to EDKII_REDFISH_HTTP_PROTOCOL instance.
> +  @param[in]  Service       Redfish service instance to perform HTTP PUT.
> +  @param[in]  Uri           Target resource URI.
> +  @param[in]  Content       Data to put.
> +  @param[in]  ContentSize   Size of the Content to be send to Redfish service.
> +                            This is optional. When ContentSize is 0, ContentSize
> +                            is the size of Content.
> +  @param[in]  ContentType   Type of the Content to be send to Redfish service.
> +                            This is optional. When ContentType is NULL, content
> +                            type HTTP_CONTENT_TYPE_APP_JSON will be used.
> +  @param[out] Response      HTTP response from redfish service.
> +
> +  @retval     EFI_SUCCESS     Resrouce is returned successfully.
> +  @retval     Others          Errors occur.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +RedfishPutResource (
> +  IN  EDKII_REDFISH_HTTP_PROTOCOL  *This,
> +  IN  REDFISH_SERVICE              Service,
> +  IN  EFI_STRING                   Uri,
> +  IN  CHAR8                        *Content,
> +  IN  UINTN                        ContentSize OPTIONAL,
> +  IN  CHAR8                        *ContentType OPTIONAL,
> +  OUT REDFISH_RESPONSE             *Response
> +  )
> +{
> +  EFI_STATUS                  Status;
> +  UINTN                       RetryCount;
> +  REDFISH_REQUEST             Request;
> +  REDFISH_HTTP_CACHE_PRIVATE  *Private;
> +
> +  if ((This == NULL) || (Service == NULL) || (Response == NULL) || IS_EMPTY_STRING (Uri) || IS_EMPTY_STRING (Content)) {
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  DEBUG ((REDFISH_HTTP_CACHE_DEBUG, "%a: Put URI: %s\n", __func__, Uri));
> +
> +  Private    = REDFISH_HTTP_CACHE_PRIVATE_FROM_THIS (This);
> +  RetryCount = 0;
> +  ZeroMem (Response, sizeof (REDFISH_RESPONSE));
> +  ZeroMem (&Request, sizeof (REDFISH_REQUEST));
> +
> +  Request.Content       = Content;
> +  Request.ContentLength = ContentSize;
> +  Request.ContentType   = ContentType;
> +
> +  //
> +  // Patch resource to redfish service.
> +  //
> +  do {
> +    RetryCount += 1;
> +    Status      = HttpSendReceive (
> +                    Service,
> +                    Uri,
> +                    HttpMethodPut,
> +                    &Request,
> +                    Response
> +                    );
> +    DEBUG ((REDFISH_HTTP_CACHE_DEBUG_REQUEST, "%a: HTTP request: %s :%r\n", __func__, Uri, Status));
> +    if (!EFI_ERROR (Status) || (RetryCount >= Private->RetrySetting.MaximumRetryPut)) {
> +      break;
> +    }
> +
> +    //
> +    // Retry when BMC is not ready.
> +    //
> +    if ((Response->StatusCode != NULL)) {
> +      DEBUG_CODE (
> +        DumpRedfishResponse (NULL, DEBUG_ERROR, Response);
> +        );
> +
> +      if (!RedfishRetryRequired (Response->StatusCode)) {
> +        break;
> +      }
> +
> +      //
> +      // Release response for next round of request.
> +      //
> +      This->FreeResponse (This, Response);
> +    }
> +
> +    DEBUG ((DEBUG_WARN, "%a: RedfishPutToUri failed, retry (%d/%d)\n", __func__, RetryCount, Private->RetrySetting.MaximumRetryPut));
> +    if (Private->RetrySetting.RetryWait > 0) {
> +      gBS->Stall (Private->RetrySetting.RetryWait);
> +    }
> +  } while (TRUE);
> +
> +  //
> +  // Redfish resource is updated. Automatically expire the cached response
> +  // so application can directly get resource from Redfish service again.
> +  //
> +  DEBUG ((REDFISH_HTTP_CACHE_DEBUG, "%a: Resource is updated, expire URI: %s\n", __func__, Uri));
> +  RedfishExpireResponse (This, Uri);
> +
> +  if (EFI_ERROR (Status)) {
> +    DEBUG_CODE (
> +      DumpRedfishResponse (NULL, DEBUG_ERROR, Response);
> +      );
> +    //
> +    // Report status code for Redfish failure
> +    //
> +    ReportHttpError (HttpMethodPut, Uri, Response->StatusCode);
> +    DEBUG ((DEBUG_ERROR, "%a: put %s failed (%d/%d): %r\n", __func__, Uri, RetryCount, Private->RetrySetting.MaximumRetryPut, Status));
> +    goto ON_RELEASE;
> +  }
> +
> +ON_RELEASE:
> +
> +  return Status;
> +}
> +
> +/**
> +  Perform HTTP POST to send redfish resource to given resource URI.
> +  It's caller's responsibility to free Response by calling FreeResponse ().
> +
> +  @param[in]  This          Pointer to EDKII_REDFISH_HTTP_PROTOCOL instance.
> +  @param[in]  Service       Redfish service instance to perform HTTP POST.
> +  @param[in]  Uri           Target resource URI.
> +  @param[in]  Content       Data to post.
> +  @param[in]  ContentSize   Size of the Content to be send to Redfish service.
> +                            This is optional. When ContentSize is 0, ContentSize
> +                            is the size of Content.
> +  @param[in]  ContentType   Type of the Content to be send to Redfish service.
> +                            This is optional. When ContentType is NULL, content
> +                            type HTTP_CONTENT_TYPE_APP_JSON will be used.
> +  @param[out] Response      HTTP response from redfish service.
> +
> +  @retval     EFI_SUCCESS     Resrouce is returned successfully.
> +  @retval     Others          Errors occur.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +RedfishPostResource (
> +  IN  EDKII_REDFISH_HTTP_PROTOCOL  *This,
> +  IN  REDFISH_SERVICE              Service,
> +  IN  EFI_STRING                   Uri,
> +  IN  CHAR8                        *Content,
> +  IN  UINTN                        ContentSize OPTIONAL,
> +  IN  CHAR8                        *ContentType OPTIONAL,
> +  OUT REDFISH_RESPONSE             *Response
> +  )
> +{
> +  EFI_STATUS                  Status;
> +  UINTN                       RetryCount;
> +  REDFISH_REQUEST             Request;
> +  REDFISH_HTTP_CACHE_PRIVATE  *Private;
> +
> +  if ((This == NULL) || (Service == NULL) || (Response == NULL) || IS_EMPTY_STRING (Uri) || IS_EMPTY_STRING (Content)) {
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  DEBUG ((REDFISH_HTTP_CACHE_DEBUG, "%a: Post URI: %s\n", __func__, Uri));
> +
> +  Private    = REDFISH_HTTP_CACHE_PRIVATE_FROM_THIS (This);
> +  RetryCount = 0;
> +  ZeroMem (Response, sizeof (REDFISH_RESPONSE));
> +  ZeroMem (&Request, sizeof (REDFISH_REQUEST));
> +
> +  Request.Content       = Content;
> +  Request.ContentLength = ContentSize;
> +  Request.ContentType   = ContentType;
> +
> +  //
> +  // Patch resource to redfish service.
> +  //
> +  do {
> +    RetryCount += 1;
> +    Status      = HttpSendReceive (
> +                    Service,
> +                    Uri,
> +                    HttpMethodPost,
> +                    &Request,
> +                    Response
> +                    );
> +    DEBUG ((REDFISH_HTTP_CACHE_DEBUG_REQUEST, "%a: HTTP request: %s :%r\n", __func__, Uri, Status));
> +    if (!EFI_ERROR (Status) || (RetryCount >= Private->RetrySetting.MaximumRetryPost)) {
> +      break;
> +    }
> +
> +    //
> +    // Retry when BMC is not ready.
> +    //
> +    if ((Response->StatusCode != NULL)) {
> +      DEBUG_CODE (
> +        DumpRedfishResponse (NULL, DEBUG_ERROR, Response);
> +        );
> +
> +      if (!RedfishRetryRequired (Response->StatusCode)) {
> +        break;
> +      }
> +
> +      //
> +      // Release response for next round of request.
> +      //
> +      This->FreeResponse (This, Response);
> +    }
> +
> +    DEBUG ((DEBUG_WARN, "%a: RedfishPostToUri failed, retry (%d/%d)\n", __func__, RetryCount, Private->RetrySetting.MaximumRetryPost));
> +    if (Private->RetrySetting.RetryWait > 0) {
> +      gBS->Stall (Private->RetrySetting.RetryWait);
> +    }
> +  } while (TRUE);
> +
> +  //
> +  // Redfish resource is updated. Automatically expire the cached response
> +  // so application can directly get resource from Redfish service again.
> +  //
> +  DEBUG ((REDFISH_HTTP_CACHE_DEBUG, "%a: Resource is updated, expire URI: %s\n", __func__, Uri));
> +  RedfishExpireResponse (This, Uri);
> +
> +  if (EFI_ERROR (Status)) {
> +    DEBUG_CODE (
> +      DumpRedfishResponse (NULL, DEBUG_ERROR, Response);
> +      );
> +    //
> +    // Report status code for Redfish failure
> +    //
> +    ReportHttpError (HttpMethodPost, Uri, Response->StatusCode);
> +    DEBUG ((DEBUG_ERROR, "%a: post %s failed (%d/%d): %r\n", __func__, Uri, RetryCount, Private->RetrySetting.MaximumRetryPost, Status));
> +    goto ON_RELEASE;
> +  }
> +
> +ON_RELEASE:
> +
> +  return Status;
> +}
> +
> +/**
> +  Perform HTTP DELETE to delete redfish resource on given resource URI.
> +  It's caller's responsibility to free Response by calling FreeResponse ().
> +
> +  @param[in]  This          Pointer to EDKII_REDFISH_HTTP_PROTOCOL instance.
> +  @param[in]  Service       Redfish service instance to perform HTTP DELETE.
> +  @param[in]  Uri           Target resource URI.
> +  @param[in]  Content       JSON represented properties to be deleted. This is
> +                            optional.
> +  @param[in]  ContentSize   Size of the Content to be send to Redfish service.
> +                            This is optional. When ContentSize is 0, ContentSize
> +                            is the size of Content if Content is not NULL.
> +  @param[in]  ContentType   Type of the Content to be send to Redfish service.
> +                            This is optional. When Content is not NULL and
> +                            ContentType is NULL, content type HTTP_CONTENT_TYPE_APP_JSON
> +                            will be used.
> +  @param[out] Response      HTTP response from redfish service.
> +
> +  @retval     EFI_SUCCESS     Resrouce is returned successfully.
> +  @retval     Others          Errors occur.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +RedfishDeleteResource (
> +  IN  EDKII_REDFISH_HTTP_PROTOCOL  *This,
> +  IN  REDFISH_SERVICE              Service,
> +  IN  EFI_STRING                   Uri,
> +  IN  CHAR8                        *Content OPTIONAL,
> +  IN  UINTN                        ContentSize OPTIONAL,
> +  IN  CHAR8                        *ContentType OPTIONAL,
> +  OUT REDFISH_RESPONSE             *Response
> +  )
> +{
> +  EFI_STATUS                  Status;
> +  UINTN                       RetryCount;
> +  REDFISH_REQUEST             Request;
> +  REDFISH_HTTP_CACHE_PRIVATE  *Private;
> +
> +  if ((This == NULL) || (Service == NULL) || (Response == NULL) || IS_EMPTY_STRING (Uri)) {
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  DEBUG ((REDFISH_HTTP_CACHE_DEBUG, "%a: Delete URI: %s\n", __func__, Uri));
> +
> +  Private    = REDFISH_HTTP_CACHE_PRIVATE_FROM_THIS (This);
> +  RetryCount = 0;
> +  ZeroMem (Response, sizeof (REDFISH_RESPONSE));
> +  ZeroMem (&Request, sizeof (REDFISH_REQUEST));
> +
> +  Request.Content       = Content;
> +  Request.ContentLength = ContentSize;
> +  Request.ContentType   = ContentType;
> +
> +  //
> +  // Patch resource to redfish service.
> +  //
> +  do {
> +    RetryCount += 1;
> +    Status      = HttpSendReceive (
> +                    Service,
> +                    Uri,
> +                    HttpMethodDelete,
> +                    &Request,
> +                    Response
> +                    );
> +    DEBUG ((REDFISH_HTTP_CACHE_DEBUG_REQUEST, "%a: HTTP request: %s :%r\n", __func__, Uri, Status));
> +    if (!EFI_ERROR (Status) || (RetryCount >= Private->RetrySetting.MaximumRetryDelete)) {
> +      break;
> +    }
> +
> +    //
> +    // Retry when BMC is not ready.
> +    //
> +    if ((Response->StatusCode != NULL)) {
> +      DEBUG_CODE (
> +        DumpRedfishResponse (NULL, DEBUG_ERROR, Response);
> +        );
> +
> +      if (!RedfishRetryRequired (Response->StatusCode)) {
> +        break;
> +      }
> +
> +      //
> +      // Release response for next round of request.
> +      //
> +      This->FreeResponse (This, Response);
> +    }
> +
> +    DEBUG ((DEBUG_WARN, "%a: RedfishDeleteByUri failed, retry (%d/%d)\n", __func__, RetryCount, Private->RetrySetting.MaximumRetryDelete));
> +    if (Private->RetrySetting.RetryWait > 0) {
> +      gBS->Stall (Private->RetrySetting.RetryWait);
> +    }
> +  } while (TRUE);
> +
> +  //
> +  // Redfish resource is updated. Automatically expire the cached response
> +  // so application can directly get resource from Redfish service again.
> +  //
> +  DEBUG ((REDFISH_HTTP_CACHE_DEBUG, "%a: Resource is updated, expire URI: %s\n", __func__, Uri));
> +  RedfishExpireResponse (This, Uri);
> +
> +  if (EFI_ERROR (Status)) {
> +    DEBUG_CODE (
> +      DumpRedfishResponse (NULL, DEBUG_ERROR, Response);
> +      );
> +    //
> +    // Report status code for Redfish failure
> +    //
> +    ReportHttpError (HttpMethodDelete, Uri, Response->StatusCode);
> +    DEBUG ((DEBUG_ERROR, "%a: delete %s failed (%d/%d): %r\n", __func__, Uri, RetryCount, Private->RetrySetting.MaximumRetryDelete, Status));
> +    goto ON_RELEASE;
> +  }
> +
> +ON_RELEASE:
> +
> +  return Status;
> +}
> +
> +EDKII_REDFISH_HTTP_PROTOCOL  mEdkIIRedfishHttpProtocol = {
> +  EDKII_REDFISH_HTTP_PROTOCOL_REVISION,
> +  RedfishCreateRedfishService,
> +  RedfishFreeRedfishService,
> +  RedfishJsonInRedfishPayload,
> +  RedfishGetResource,
> +  RedfishPatchResource,
> +  RedfishPutResource,
> +  RedfishPostResource,
> +  RedfishDeleteResource,
> +  RedfishFreeRequest,
> +  RedfishFreeResponse,
> +  RedfishExpireResponse
> +};
> +
> +/**
> +  Unloads an image.
> +
> +  @param[in]  ImageHandle         Handle that identifies the image to be unloaded.
> +
> +  @retval EFI_SUCCESS             The image has been unloaded.
> +  @retval EFI_INVALID_PARAMETER   ImageHandle is not a valid image handle.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +RedfishHttpDriverUnload (
> +  IN EFI_HANDLE  ImageHandle
> +  )
> +{
> +  if (mRedfishHttpCachePrivate == NULL) {
> +    return EFI_SUCCESS;
> +  }
> +
> +  if (!IsListEmpty (&mRedfishHttpCachePrivate->CacheList.Head)) {
> +    ReleaseCacheList (&mRedfishHttpCachePrivate->CacheList);
> +  }
> +
> +  gBS->UninstallMultipleProtocolInterfaces (
> +         ImageHandle,
> +         &gEdkIIRedfishHttpProtocolGuid,
> +         &mRedfishHttpCachePrivate->Protocol,
> +         NULL
> +         );
> +
> +  FreePool (mRedfishHttpCachePrivate);
> +  mRedfishHttpCachePrivate = NULL;
> +
> +  return EFI_SUCCESS;
> +}
> +
> +/**
> +  This is a EDKII_REDFISH_CREDENTIAL_PROTOCOL notification event handler.
> +
> +  @param[in] Event    Event whose notification function is being invoked.
> +  @param[in] Context  Pointer to the notification function's context.
> +
> +**/
> +VOID
> +EFIAPI
> +CredentialProtocolInstalled (
> +  IN  EFI_EVENT  Event,
> +  IN  VOID       *Context
> +  )
> +{
> +  EFI_STATUS                  Status;
> +  REDFISH_HTTP_CACHE_PRIVATE  *Private;
> +
> +  Private = (REDFISH_HTTP_CACHE_PRIVATE *)Context;
> +  if (Private->Signature != REDFISH_HTTP_DRIVER_SIGNATURE) {
> +    DEBUG ((DEBUG_ERROR, "%a: signature check failure\n", __func__));
> +    return;
> +  }
> +
> +  //
> +  // Locate HII database protocol.
> +  //
> +  Status = gBS->LocateProtocol (
> +                  &gEdkIIRedfishCredentialProtocolGuid,
> +                  NULL,
> +                  (VOID **)&Private->CredentialProtocol
> +                  );
> +  if (EFI_ERROR (Status)) {
> +    return;
> +  }
> +
> +  gBS->CloseEvent (Event);
> +}
> +
> +/**
> +  Main entry for this driver.
> +
> +  @param[in] ImageHandle     Image handle this driver.
> +  @param[in] SystemTable     Pointer to SystemTable.
> +
> +  @retval EFI_SUCCESS     This function always complete successfully.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +RedfishHttpEntryPoint (
> +  IN EFI_HANDLE        ImageHandle,
> +  IN EFI_SYSTEM_TABLE  *SystemTable
> +  )
> +{
> +  EFI_STATUS  Status;
> +  VOID        *Registration;
> +
> +  if (mRedfishHttpCachePrivate != NULL) {
> +    return EFI_ALREADY_STARTED;
> +  }
> +
> +  mRedfishHttpCachePrivate = AllocateZeroPool (sizeof (REDFISH_HTTP_CACHE_PRIVATE));
> +  if (mRedfishHttpCachePrivate == NULL) {
> +    return EFI_OUT_OF_RESOURCES;
> +  }
> +
> +  //
> +  // Initial cache list and protocol instance.
> +  //
> +  mRedfishHttpCachePrivate->Signature   = REDFISH_HTTP_DRIVER_SIGNATURE;
> +  mRedfishHttpCachePrivate->ImageHandle = ImageHandle;
> +  CopyMem (&mRedfishHttpCachePrivate->Protocol, &mEdkIIRedfishHttpProtocol, sizeof (EDKII_REDFISH_HTTP_PROTOCOL));
> +  mRedfishHttpCachePrivate->CacheList.Capacity = REDFISH_HTTP_CACHE_LIST_SIZE;
> +  mRedfishHttpCachePrivate->CacheList.Count    = 0x00;
> +  mRedfishHttpCachePrivate->CacheDisabled      = PcdGetBool (PcdHttpCacheDisabled);
> +  InitializeListHead (&mRedfishHttpCachePrivate->CacheList.Head);
> +
> +  //
> +  // Get retry settings
> +  //
> +  mRedfishHttpCachePrivate->RetrySetting.MaximumRetryGet    = PcdGet16 (PcdHttpGetRetry);
> +  mRedfishHttpCachePrivate->RetrySetting.MaximumRetryPut    = PcdGet16 (PcdHttpPutRetry);
> +  mRedfishHttpCachePrivate->RetrySetting.MaximumRetryPatch  = PcdGet16 (PcdHttpPatchRetry);
> +  mRedfishHttpCachePrivate->RetrySetting.MaximumRetryPost   = PcdGet16 (PcdHttpPostRetry);
> +  mRedfishHttpCachePrivate->RetrySetting.MaximumRetryDelete = PcdGet16 (PcdHttpDeleteRetry);
> +  mRedfishHttpCachePrivate->RetrySetting.RetryWait          = PcdGet16 (PcdHttpRetryWaitInSecond) * 1000000U;
> +
> +  //
> +  // Install the gEdkIIRedfishHttpProtocolGuid onto Handle.
> +  //
> +  Status = gBS->InstallMultipleProtocolInterfaces (
> +                  &mRedfishHttpCachePrivate->ImageHandle,
> +                  &gEdkIIRedfishHttpProtocolGuid,
> +                  &mRedfishHttpCachePrivate->Protocol,
> +                  NULL
> +                  );
> +  if (EFI_ERROR (Status)) {
> +    DEBUG ((DEBUG_ERROR, "%a: cannot install Redfish http protocol: %r\n", __func__, Status));
> +    RedfishHttpDriverUnload (ImageHandle);
> +    return Status;
> +  }
> +
> +  //
> +  // Install protocol notification if credential protocol is installed.
> +  //
> +  mRedfishHttpCachePrivate->NotifyEvent = EfiCreateProtocolNotifyEvent (
> +                                            &gEdkIIRedfishCredentialProtocolGuid,
> +                                            TPL_CALLBACK,
> +                                            CredentialProtocolInstalled,
> +                                            mRedfishHttpCachePrivate,
> +                                            &Registration
> +                                            );
> +  if (mRedfishHttpCachePrivate->NotifyEvent == NULL) {
> +    DEBUG ((DEBUG_ERROR, "%a: failed to create protocol notification for gEdkIIRedfishCredentialProtocolGuid\n", __func__));
> +    ASSERT (FALSE);
> +    RedfishHttpDriverUnload (ImageHandle);
> +    return Status;
> +  }
> +
> +  return EFI_SUCCESS;
> +}
> diff --git a/RedfishPkg/RedfishHttpDxe/RedfishHttpOperation.c b/RedfishPkg/RedfishHttpDxe/RedfishHttpOperation.c
> new file mode 100644
> index 0000000000..5652818d16
> --- /dev/null
> +++ b/RedfishPkg/RedfishHttpDxe/RedfishHttpOperation.c
> @@ -0,0 +1,693 @@
> +/** @file
> +  RedfishHttpOperation handles HTTP operations.
> +
> +  Copyright (c) 2024, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
> +
> +  SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +#include "RedfishHttpOperation.h"
> +#include "RedfishHttpData.h"
> +
> +/**
> +  This function copies all headers in SrcHeaders to DstHeaders.
> +  It's call responsibility to release returned DstHeaders.
> +
> +  @param[in]  SrcHeaders      Source headers.
> +  @param[in]  SrcHeaderCount  Number of header in source headers.
> +  @param[out] DstHeaders      Destination headers.
> +  @param[out] DstHeaderCount  Number of header in designation headers.
> +
> +  @retval     EFI_SUCCESS     Headers are copied successfully.
> +  @retval     Others          Errors occur.
> +
> +**/
> +EFI_STATUS
> +CopyHttpHeaders (
> +  IN  EFI_HTTP_HEADER  *SrcHeaders,
> +  IN  UINTN            SrcHeaderCount,
> +  OUT EFI_HTTP_HEADER  **DstHeaders,
> +  OUT UINTN            *DstHeaderCount
> +  )
> +{
> +  UINTN  Index;
> +
> +  if ((SrcHeaders == NULL) || (SrcHeaderCount == 0) || (DstHeaders == NULL) || (DstHeaderCount == NULL)) {
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  *DstHeaderCount = 0;
> +  *DstHeaders     = AllocateZeroPool (sizeof (EFI_HTTP_HEADER) * SrcHeaderCount);
> +  if (*DstHeaders == NULL) {
> +    return EFI_OUT_OF_RESOURCES;
> +  }
> +
> +  for (Index = 0; Index < SrcHeaderCount; Index++) {
> +    (*DstHeaders)[Index].FieldName = AllocateCopyPool (AsciiStrSize (SrcHeaders[Index].FieldName), SrcHeaders[Index].FieldName);
> +    if ((*DstHeaders)[Index].FieldName == NULL) {
> +      return EFI_OUT_OF_RESOURCES;
> +    }
> +
> +    (*DstHeaders)[Index].FieldValue = AllocateCopyPool (AsciiStrSize (SrcHeaders[Index].FieldValue), SrcHeaders[Index].FieldValue);
> +    if ((*DstHeaders)[Index].FieldValue == NULL) {
> +      return EFI_OUT_OF_RESOURCES;



Looks like orevious allocations leaked.
Didn't you think to implement smth like this https://github.com/tianocore/edk2/blob/master/OvmfPkg/XenBusDxe/Helpers.c#L4 ?


> +    }
> +
> +    *DstHeaderCount += 1;
> +  }
> +
> +  return EFI_SUCCESS;
> +}
> +
> +/**
> +  This function free resources in Request. Request is no longer available
> +  after this function returns successfully.
> +
> +  @param[in]  Request      HTTP request to be released.
> +
> +  @retval     EFI_SUCCESS     Resrouce is released successfully.
> +  @retval     Others          Errors occur.
> +
> +**/
> +EFI_STATUS
> +ReleaseRedfishRequest (
> +  IN  REDFISH_REQUEST  *Request
> +  )
> +{
> +  if (Request == NULL) {
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  if ((Request->Headers != NULL) && (Request->HeaderCount > 0)) {
> +    HttpFreeHeaderFields (Request->Headers, Request->HeaderCount);
> +    Request->Headers     = NULL;
> +    Request->HeaderCount = 0;
> +  }
> +
> +  if (Request->Content != NULL) {
> +    FreePool (Request->Content);
> +    Request->Content = NULL;
> +  }
> +
> +  if (Request->ContentType != NULL) {
> +    FreePool (Request->ContentType);
> +    Request->ContentType = NULL;
> +  }
> +
> +  Request->ContentLength = 0;
> +
> +  return EFI_SUCCESS;
> +}
> +
> +/**
> +  This function free resources in given Response.
> +
> +  @param[in]  Response     HTTP response to be released.
> +
> +  @retval     EFI_SUCCESS     Resrouce is released successfully.
> +  @retval     Others          Errors occur.
> +
> +**/
> +EFI_STATUS
> +ReleaseRedfishResponse (
> +  IN  REDFISH_RESPONSE  *Response
> +  )
> +{
> +  if (Response == NULL) {
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  if ((Response->Headers != NULL) && (Response->HeaderCount > 0)) {
> +    HttpFreeHeaderFields (Response->Headers, Response->HeaderCount);
> +    Response->Headers     = NULL;
> +    Response->HeaderCount = 0;
> +  }
> +
> +  if (Response->Payload != NULL) {
> +    ReleaseRedfishPayload (Response->Payload);
> +    Response->Payload = NULL;
> +  }
> +
> +  if (Response->StatusCode != NULL) {
> +    FreePool (Response->StatusCode);
> +    Response->StatusCode = NULL;
> +  }
> +
> +  return EFI_SUCCESS;
> +}
> +
> +/**
> +  This function free resources in given HTTP message.
> +
> +  @param[in]  HttpMessage     HTTP message to be released.
> +  @param[in]  IsRequest       TRUE if this is request type of HTTP message.
> +                              FALSE if this is response type of HTTP message.
> +
> +  @retval     EFI_SUCCESS     Resrouce is released successfully.
> +  @retval     Others          Errors occur.
> +
> +**/
> +EFI_STATUS
> +ReleaseHttpMessage (
> +  IN  EFI_HTTP_MESSAGE  *HttpMessage,
> +  IN  BOOLEAN           IsRequest
> +  )
> +{
> +  if (HttpMessage == NULL) {
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  if (IsRequest) {
> +    if (HttpMessage->Data.Request != NULL) {
> +      if (HttpMessage->Data.Request->Url != NULL) {
> +        FreePool (HttpMessage->Data.Request->Url);
> +      }
> +
> +      FreePool (HttpMessage->Data.Request);
> +      HttpMessage->Data.Request = NULL;
> +    }
> +  } else {
> +    if (HttpMessage->Data.Response != NULL) {
> +      FreePool (HttpMessage->Data.Response);
> +      HttpMessage->Data.Response = NULL;
> +    }
> +  }
> +
> +  if (HttpMessage->Body != NULL) {
> +    FreePool (HttpMessage->Body);
> +    HttpMessage->Body = NULL;
> +  }
> +
> +  if (HttpMessage->Headers != NULL) {
> +    HttpFreeHeaderFields (HttpMessage->Headers, HttpMessage->HeaderCount);
> +    HttpMessage->Headers     = NULL;
> +    HttpMessage->HeaderCount = 0;
> +  }
> +
> +  return EFI_SUCCESS;
> +}
> +
> +/**
> +  This function build Redfish message for sending data to Redfish service.
> +  It's call responsibility to properly release returned HTTP message by
> +  calling ReleaseHttpMessage.
> +
> +  @param[in]   ServicePrivate    Pointer to Redfish service private data.
> +  @param[in]   Uri               Redfish service URI.
> +  @param[in]   Method            HTTP method.
> +  @param[in]   Request           Additional data to send to Redfish service.
> +                                 This is optional.
> +  @param[in]   ContentEncoding   Content encoding method to compress HTTP context.
> +                                 This is optional. When ContentEncoding is NULL,
> +                                 No compress method will be performed.
> +
> +  @retval     EFI_HTTP_MESSAGE *   Pointer to newly created HTTP message.
> +  @retval     NULL                 Error occurred.
> +
> +**/
> +EFI_HTTP_MESSAGE *
> +BuildRequestMessage (
> +  IN REDFISH_SERVICE_PRIVATE  *ServicePrivate,
> +  IN EFI_STRING               Uri,
> +  IN EFI_HTTP_METHOD          Method,
> +  IN REDFISH_REQUEST          *Request OPTIONAL,
> +  IN CHAR8                    *ContentEncoding OPTIONAL
> +  )
> +{
> +  EFI_STATUS             Status;
> +  EFI_STRING             Url;
> +  UINTN                  UrlSize;
> +  UINTN                  Index;
> +  EFI_HTTP_MESSAGE       *RequestMsg;
> +  EFI_HTTP_REQUEST_DATA  *RequestData;
> +  UINTN                  HeaderCount;
> +  UINTN                  HeaderIndex;
> +  EFI_HTTP_HEADER        *Headers;
> +  CHAR8                  ContentLengthStr[REDFISH_CONTENT_LENGTH_SIZE];
> +  VOID                   *Content;
> +  UINTN                  ContentLength;
> +  BOOLEAN                HasContent;
> +  BOOLEAN                DoContentEncoding;
> +
> +  RequestMsg        = NULL;
> +  RequestData       = NULL;
> +  Url               = NULL;
> +  UrlSize           = 0;
> +  Content           = NULL;
> +  ContentLength     = 0;
> +  HeaderCount       = REDFISH_COMMON_HEADER_SIZE;
> +  HeaderIndex       = 0;
> +  Headers           = NULL;
> +  HasContent        = FALSE;
> +  DoContentEncoding = FALSE;
> +
> +  if ((ServicePrivate == NULL) || (IS_EMPTY_STRING (Uri))) {
> +    return NULL;
> +  }
> +
> +  if (Method >= HttpMethodMax) {
> +    return NULL;
> +  }
> +
> +  DEBUG ((REDFISH_HTTP_CACHE_DEBUG_REQUEST, "%a: %s\n", __func__, Uri));
> +
> +  //
> +  // Build full URL for HTTP query.
> +  //
> +  UrlSize = (AsciiStrLen (ServicePrivate->Host) + StrLen (Uri) + 1) * sizeof (CHAR16);
> +  Url     = AllocateZeroPool (UrlSize);
> +  if (Url == NULL) {
> +    return NULL;
> +  }
> +
> +  UnicodeSPrint (Url, UrlSize, L"%a%s", ServicePrivate->Host, Uri);
> +  DEBUG ((REDFISH_HTTP_CACHE_DEBUG_REQUEST, "%a: Url: %s\n", __func__, Url));
> +
> +  //
> +  // Step 1: build the HTTP headers.
> +  //
> +  if (!IS_EMPTY_STRING (ServicePrivate->SessionToken) || !IS_EMPTY_STRING (ServicePrivate->BasicAuth)) {
> +    HeaderCount++;
> +  }
> +
> +  if ((Request != NULL) && (Request->HeaderCount > 0)) {
> +    HeaderCount += Request->HeaderCount;
> +  }
> +
> +  //
> +  // Check and see if we will do content encoding or not
> +  //
> +  if (!IS_EMPTY_STRING (ContentEncoding)) {
> +    if (AsciiStrCmp (ContentEncoding, REDFISH_HTTP_CONTENT_ENCODING_NONE) != 0) {
> +      DoContentEncoding = TRUE;
> +    }
> +  }
> +
> +  if ((Request != NULL) && !IS_EMPTY_STRING (Request->Content)) {
> +    HeaderCount += 2;
> +    HasContent   = TRUE;
> +    if (DoContentEncoding) {
> +      HeaderCount += 1;
> +    }
> +  }
> +
> +  Headers = AllocateZeroPool (HeaderCount * sizeof (EFI_HTTP_HEADER));
> +  if (Headers == NULL) {
> +    goto ON_ERROR;
> +  }
> +
> +  if (!IS_EMPTY_STRING (ServicePrivate->SessionToken)) {
> +    Status = HttpSetFieldNameAndValue (&Headers[HeaderIndex++], HTTP_HEADER_X_AUTH_TOKEN, ServicePrivate->SessionToken);
> +    if (EFI_ERROR (Status)) {
> +      goto ON_ERROR;
> +    }
> +  } else if (!IS_EMPTY_STRING (ServicePrivate->BasicAuth)) {
> +    Status = HttpSetFieldNameAndValue (&Headers[HeaderIndex++], HTTP_HEADER_AUTHORIZATION, ServicePrivate->BasicAuth);
> +    if (EFI_ERROR (Status)) {
> +      goto ON_ERROR;
> +    }
> +  }
> +
> +  if (Request != NULL) {
> +    for (Index = 0; Index < Request->HeaderCount; Index++) {
> +      Status = HttpSetFieldNameAndValue (&Headers[HeaderIndex++], Request->Headers[Index].FieldName, Request->Headers[Index].FieldValue);
> +      if (EFI_ERROR (Status)) {
> +        goto ON_ERROR;
> +      }
> +    }
> +  }
> +
> +  Status = HttpSetFieldNameAndValue (&Headers[HeaderIndex++], HTTP_HEADER_HOST, ServicePrivate->HostName);
> +  if (EFI_ERROR (Status)) {
> +    goto ON_ERROR;
> +  }
> +
> +  Status = HttpSetFieldNameAndValue (&Headers[HeaderIndex++], REDFISH_HTTP_HEADER_ODATA_VERSION_STR, REDFISH_HTTP_HEADER_ODATA_VERSION_VALUE);
> +  if (EFI_ERROR (Status)) {
> +    goto ON_ERROR;
> +  }
> +
> +  Status = HttpSetFieldNameAndValue (&Headers[HeaderIndex++], HTTP_HEADER_ACCEPT, HTTP_CONTENT_TYPE_APP_JSON);
> +  if (EFI_ERROR (Status)) {
> +    goto ON_ERROR;
> +  }
> +
> +  Status = HttpSetFieldNameAndValue (&Headers[HeaderIndex++], HTTP_HEADER_USER_AGENT, REDFISH_HTTP_HEADER_USER_AGENT_VALUE);
> +  if (EFI_ERROR (Status)) {
> +    goto ON_ERROR;
> +  }
> +
> +  Status = HttpSetFieldNameAndValue (&Headers[HeaderIndex++], REDFISH_HTTP_HEADER_CONNECTION_STR, REDFISH_HTTP_HEADER_CONNECTION_VALUE);
> +  if (EFI_ERROR (Status)) {
> +    goto ON_ERROR;
> +  }
> +
> +  //
> +  // Handle content header
> +  //
> +  if (HasContent) {
> +    if (Request->ContentType == NULL) {
> +      Status = HttpSetFieldNameAndValue (&Headers[HeaderIndex++], HTTP_HEADER_CONTENT_TYPE, HTTP_CONTENT_TYPE_APP_JSON);
> +      if (EFI_ERROR (Status)) {
> +        goto ON_ERROR;
> +      }
> +    } else {
> +      Status = HttpSetFieldNameAndValue (&Headers[HeaderIndex++], HTTP_HEADER_CONTENT_TYPE, Request->ContentType);
> +      if (EFI_ERROR (Status)) {
> +        goto ON_ERROR;
> +      }
> +    }
> +
> +    if (Request->ContentLength == 0) {
> +      Request->ContentLength =  AsciiStrLen (Request->Content);
> +    }
> +
> +    AsciiSPrint (
> +      ContentLengthStr,
> +      sizeof (ContentLengthStr),
> +      "%lu",
> +      (UINT64)Request->ContentLength
> +      );
> +    Status = HttpSetFieldNameAndValue (&Headers[HeaderIndex++], HTTP_HEADER_CONTENT_LENGTH, ContentLengthStr);
> +    if (EFI_ERROR (Status)) {
> +      goto ON_ERROR;
> +    }
> +
> +    //
> +    // Encoding
> +    //
> +    if (DoContentEncoding) {
> +      //
> +      // We currently only support gzip Content-Encoding.
> +      //
> +      Status =  RedfishContentEncode (
> +                  ContentEncoding,
> +                  Request->Content,
> +                  Request->ContentLength,
> +                  &Content,
> +                  &ContentLength
> +                  );
> +      if (Status == EFI_INVALID_PARAMETER) {
> +        DEBUG ((DEBUG_ERROR, "%a: Error to encode content.\n", __func__));
> +        goto ON_ERROR;
> +      } else if (Status == EFI_UNSUPPORTED) {
> +        DoContentEncoding = FALSE;
> +        DEBUG ((REDFISH_HTTP_CACHE_DEBUG_REQUEST, "%a: No content coding for %a! Use raw data instead.\n", __func__, ContentEncoding));
> +        Status = HttpSetFieldNameAndValue (&Headers[HeaderIndex++], HTTP_HEADER_CONTENT_ENCODING, HTTP_CONTENT_ENCODING_IDENTITY);
> +        if (EFI_ERROR (Status)) {
> +          goto ON_ERROR;
> +        }
> +      } else {
> +        Status = HttpSetFieldNameAndValue (&Headers[HeaderIndex++], HTTP_HEADER_CONTENT_ENCODING, HTTP_CONTENT_ENCODING_GZIP);
> +        if (EFI_ERROR (Status)) {
> +          goto ON_ERROR;
> +        }
> +      }
> +    }
> +
> +    //
> +    // When the content is from caller, we use our own copy so that we properly release it later.
> +    //
> +    if (!DoContentEncoding) {
> +      Content = AllocateCopyPool (Request->ContentLength, Request->Content);
> +      if (Content == NULL) {
> +        goto ON_ERROR;
> +      }
> +
> +      ContentLength = Request->ContentLength;
> +    }
> +  }
> +
> +  //
> +  // Step 2: build the rest of HTTP request info.
> +  //
> +  RequestData = AllocateZeroPool (sizeof (EFI_HTTP_REQUEST_DATA));
> +  if (RequestData == NULL) {
> +    goto ON_ERROR;
> +  }
> +
> +  RequestData->Method = Method;
> +  RequestData->Url    = Url;
> +
> +  //
> +  // Step 3: fill in EFI_HTTP_MESSAGE
> +  //
> +  RequestMsg = AllocateZeroPool (sizeof (EFI_HTTP_MESSAGE));
> +  if (RequestMsg == NULL) {
> +    goto ON_ERROR;
> +  }
> +
> +  ASSERT (HeaderIndex == HeaderCount);
> +  RequestMsg->Data.Request = RequestData;
> +  RequestMsg->HeaderCount  = HeaderIndex;
> +  RequestMsg->Headers      = Headers;
> +
> +  if (HasContent) {
> +    RequestMsg->BodyLength = ContentLength;
> +    RequestMsg->Body       = Content;
> +  }
> +
> +  return RequestMsg;
> +
> +ON_ERROR:
> +
> +  if (Headers != NULL) {
> +    HttpFreeHeaderFields (Headers, HeaderIndex);
> +  }
> +
> +  if (RequestData != NULL) {
> +    FreePool (RequestData);
> +  }
> +
> +  if (RequestMsg != NULL) {
> +    FreePool (RequestMsg);
> +  }
> +
> +  if (Url != NULL) {
> +    FreePool (Url);
> +  }
> +
> +  return NULL;
> +}
> +
> +/**
> +  This function parse response message from Redfish service, and
> +  build Redfish response for caller. It's call responsibility to
> +  properly release Redfish response by calling ReleaseRedfishResponse.
> +
> +  @param[in]   ServicePrivate   Pointer to Redfish service private data.
> +  @param[in]   ResponseMsg      Response message from Redfish service.
> +  @param[out]  RedfishResponse  Redfish response data.
> +
> +  @retval     EFI_SUCCESS     Redfish response is returned successfully.
> +  @retval     Others          Errors occur.
> +
> +**/
> +EFI_STATUS
> +ParseResponseMessage (
> +  IN  REDFISH_SERVICE_PRIVATE  *ServicePrivate,
> +  IN  EFI_HTTP_MESSAGE         *ResponseMsg,
> +  OUT REDFISH_RESPONSE         *RedfishResponse
> +  )
> +{
> +  EFI_STATUS        Status;
> +  EDKII_JSON_VALUE  JsonData;
> +  EFI_HTTP_HEADER   *ContentEncodedHeader;
> +  VOID              *DecodedBody;
> +  UINTN             DecodedLength;
> +
> +  if ((ServicePrivate == NULL) || (ResponseMsg == NULL) || (RedfishResponse == NULL)) {
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  DEBUG ((REDFISH_HTTP_CACHE_DEBUG_REQUEST, "%a\n", __func__));
> +
> +  //
> +  // Initialization
> +  //
> +  JsonData                     = NULL;
> +  RedfishResponse->HeaderCount = 0;
> +  RedfishResponse->Headers     = NULL;
> +  RedfishResponse->Payload     = NULL;
> +  RedfishResponse->StatusCode  = NULL;
> +  DecodedBody                  = NULL;
> +  DecodedLength                = 0;
> +
> +  //
> +  // Return the HTTP StatusCode.
> +  //
> +  if (ResponseMsg->Data.Response != NULL) {
> +    DEBUG ((REDFISH_HTTP_CACHE_DEBUG_REQUEST, "%a: status: %d\n", __func__, ResponseMsg->Data.Response->StatusCode));
> +    RedfishResponse->StatusCode = AllocateCopyPool (sizeof (EFI_HTTP_STATUS_CODE), &ResponseMsg->Data.Response->StatusCode);
> +    if (RedfishResponse->StatusCode == NULL) {
> +      DEBUG ((DEBUG_ERROR, "%a: Failed to create status code.\n", __func__));
> +    }
> +  }
> +
> +  //
> +  // Return the HTTP headers.
> +  //
> +  if (ResponseMsg->Headers != NULL) {
> +    DEBUG ((REDFISH_HTTP_CACHE_DEBUG_REQUEST, "%a: header count: %d\n", __func__, ResponseMsg->HeaderCount));
> +    Status = CopyHttpHeaders (
> +               ResponseMsg->Headers,
> +               ResponseMsg->HeaderCount,
> +               &RedfishResponse->Headers,
> +               &RedfishResponse->HeaderCount
> +               );
> +    if (EFI_ERROR (Status)) {
> +      DEBUG ((DEBUG_ERROR, "%a: Failed to copy HTTP headers: %r\n", __func__, Status));
> +    }
> +  }
> +
> +  //
> +  // Return the HTTP body.
> +  //
> +  if ((ResponseMsg->BodyLength != 0) && (ResponseMsg->Body != NULL)) {
> +    DEBUG ((REDFISH_HTTP_CACHE_DEBUG_REQUEST, "%a: body length: %d\n", __func__, ResponseMsg->BodyLength));
> +    //
> +    // Check if data is encoded.
> +    //
> +    ContentEncodedHeader = HttpFindHeader (RedfishResponse->HeaderCount, RedfishResponse->Headers, HTTP_HEADER_CONTENT_ENCODING);
> +    if (ContentEncodedHeader != NULL) {
> +      //
> +      // The content is encoded.
> +      //
> +      Status = RedfishContentDecode (
> +                 ContentEncodedHeader->FieldValue,
> +                 ResponseMsg->Body,
> +                 ResponseMsg->BodyLength,
> +                 &DecodedBody,
> +                 &DecodedLength
> +                 );
> +      if (EFI_ERROR (Status)) {
> +        DEBUG ((DEBUG_ERROR, "%a: Failed to decompress the response content: %r decoding method: %a\n.", __func__, Status, ContentEncodedHeader->FieldValue));
> +        goto ON_ERROR;
> +      }
> +
> +      JsonData = JsonLoadBuffer (DecodedBody, DecodedLength, 0, NULL);
> +      FreePool (DecodedBody);
> +    } else {
> +      JsonData = JsonLoadBuffer (ResponseMsg->Body, ResponseMsg->BodyLength, 0, NULL);
> +    }
> +
> +    if (!JsonValueIsNull (JsonData)) {
> +      RedfishResponse->Payload = CreateRedfishPayload (ServicePrivate, JsonData);
> +      if (RedfishResponse->Payload == NULL) {
> +        DEBUG ((DEBUG_ERROR, "%a: Failed to create payload\n.", __func__));
> +      }
> +
> +      JsonValueFree (JsonData);
> +    } else {
> +      DEBUG ((DEBUG_ERROR, "%a: No payload available\n", __func__));
> +    }
> +  }
> +
> +  return EFI_SUCCESS;
> +
> +ON_ERROR:
> +
> +  if (RedfishResponse != NULL) {
> +    ReleaseRedfishResponse (RedfishResponse);
> +  }
> +
> +  return Status;
> +}
> +
> +/**
> +  This function send Redfish request to Redfish service by calling
> +  Rest Ex protocol.
> +
> +  @param[in]   Service       Pointer to Redfish service.
> +  @param[in]   Uri           Uri of Redfish service.
> +  @param[in]   Method        HTTP method.
> +  @param[in]   Request     Request data. This is optional.
> +  @param[out]  Response    Redfish response data.
> +
> +  @retval     EFI_SUCCESS     Request is sent and received successfully.
> +  @retval     Others          Errors occur.
> +
> +**/
> +EFI_STATUS
> +HttpSendReceive (
> +  IN  REDFISH_SERVICE   Service,
> +  IN  EFI_STRING        Uri,
> +  IN  EFI_HTTP_METHOD   Method,
> +  IN  REDFISH_REQUEST   *Request  OPTIONAL,
> +  OUT REDFISH_RESPONSE  *Response
> +  )
> +{
> +  EFI_STATUS               Status;
> +  EFI_STATUS               RestExStatus;
> +  EFI_HTTP_MESSAGE         *RequestMsg;
> +  EFI_HTTP_MESSAGE         ResponseMsg;
> +  REDFISH_SERVICE_PRIVATE  *ServicePrivate;
> +  EFI_HTTP_HEADER          *XAuthTokenHeader;
> +  CHAR8                    *HttpContentEncoding;
> +
> +  if ((Service == NULL) || IS_EMPTY_STRING (Uri) || (Response == NULL)) {
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  DEBUG ((REDFISH_HTTP_CACHE_DEBUG_REQUEST, "%a: Method: 0x%x %s\n", __func__, Method, Uri));
> +
> +  ServicePrivate = (REDFISH_SERVICE_PRIVATE *)Service;
> +  if (ServicePrivate->Signature != REDFISH_HTTP_SERVICE_SIGNATURE) {
> +    DEBUG ((DEBUG_ERROR, "%a: signature check failure\n", __func__));
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  ZeroMem (&ResponseMsg, sizeof (ResponseMsg));
> +  HttpContentEncoding = (CHAR8 *)PcdGetPtr (PcdRedfishServiceContentEncoding);
> +
> +  RequestMsg = BuildRequestMessage (Service, Uri, Method, Request, HttpContentEncoding);
> +  if (RequestMsg == NULL) {
> +    DEBUG ((DEBUG_ERROR, "%a: cannot build request message for %s\n", __func__, Uri));
> +    return EFI_PROTOCOL_ERROR;
> +  }
> +
> +  //
> +  // call RESTEx to get response from REST service.
> +  //
> +  RestExStatus = ServicePrivate->RestEx->SendReceive (ServicePrivate->RestEx, RequestMsg, &ResponseMsg);
> +  if (EFI_ERROR (RestExStatus)) {
> +    DEBUG ((DEBUG_ERROR, "%a: %s SendReceive failure: %r\n", __func__, Uri, RestExStatus));
> +  }
> +
> +  //
> +  // Return status code, headers and payload to caller as much as possible even when RestEx returns failure.
> +  //
> +  Status = ParseResponseMessage (ServicePrivate, &ResponseMsg, Response);
> +  if (EFI_ERROR (Status)) {
> +    DEBUG ((DEBUG_ERROR, "%a: %s parse response failure: %r\n", __func__, Uri, Status));
> +  } else {
> +    //
> +    // Capture session token in header
> +    //
> +    if ((Method == HttpMethodPost) &&
> +        (Response->StatusCode != NULL) &&
> +        ((*Response->StatusCode == HTTP_STATUS_200_OK) || (*Response->StatusCode == HTTP_STATUS_204_NO_CONTENT)))
> +    {
> +      XAuthTokenHeader = HttpFindHeader (ResponseMsg.HeaderCount, ResponseMsg.Headers, HTTP_HEADER_X_AUTH_TOKEN);
> +      if (XAuthTokenHeader != NULL) {
> +        Status = UpdateSessionToken (ServicePrivate, XAuthTokenHeader->FieldValue);
> +        if (EFI_ERROR (Status)) {
> +          DEBUG ((DEBUG_ERROR, "%a: update session token failure: %r\n", __func__, Status));
> +        }
> +      }
> +    }
> +  }
> +
> +  //
> +  // Release resources
> +  //
> +  if (RequestMsg != NULL) {
> +    ReleaseHttpMessage (RequestMsg, TRUE);
> +    FreePool (RequestMsg);
> +  }
> +
> +  ReleaseHttpMessage (&ResponseMsg, FALSE);
> +
> +  return RestExStatus;
> +}
> diff --git a/RedfishPkg/Redfish.fdf.inc b/RedfishPkg/Redfish.fdf.inc
> index 3e5a77766e..5cbe3592fd 100644
> --- a/RedfishPkg/Redfish.fdf.inc
> +++ b/RedfishPkg/Redfish.fdf.inc
> @@ -6,7 +6,7 @@
> # to be built in the firmware volume.
> #
> # (C) Copyright 2020-2021 Hewlett Packard Enterprise Development LP<BR>
> -# Copyright (c) 2023, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
> +# Copyright (c) 2023-2024, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
> #
> #    SPDX-License-Identifier: BSD-2-Clause-Patent
> #
> @@ -20,4 +20,5 @@
>   INF RedfishPkg/RedfishConfigHandler/RedfishConfigHandlerDriver.inf
>   INF RedfishPkg/RedfishPlatformConfigDxe/RedfishPlatformConfigDxe.inf
>   INF MdeModulePkg/Universal/RegularExpressionDxe/RegularExpressionDxe.inf
> +  INF RedfishPkg/RedfishHttpDxe/RedfishHttpDxe.inf
> !endif
> --
> 2.34.1
> 
> 
> 
> 
> 

Regards,
Mike.
> 


-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#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]
-=-=-=-=-=-=-=-=-=-=-=-



^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [edk2-devel] [PATCH v2 2/6] RedfishPkg: implement Redfish HTTP protocol
  2024-02-23 11:29 ` Mike Maslenkin
@ 2024-02-23 14:07   ` Nickle Wang via groups.io
  2024-02-23 16:04     ` Mike Maslenkin
  0 siblings, 1 reply; 15+ messages in thread
From: Nickle Wang via groups.io @ 2024-02-23 14:07 UTC (permalink / raw)
  To: Mike Maslenkin, devel@edk2.groups.io
  Cc: Igor Kulchytskyy, Abner Chang, Nick Ramirez

Thanks for your review, Mike.

> %s/Resrouce/Resource/ this comes from RedfishClient autogenerated files...

Typos are Addressed. I will send v3 later.

>> +ON_ERROR:
>> +
>> +  ReleaseRedfishPayload (NewPayload);
>> +
>
> NewPayload->Service  is leaked

NewPayload->Service will be released in ReleaseRedfishPayload function.  ReleaseRedfishService() will be called in ReleaseRedfishPayload() when Service is not NULL. Please let me know if I misunderstand your comment.


>> +    (*DstHeaders)[Index].FieldValue = AllocateCopyPool (AsciiStrSize (SrcHeaders[Index].FieldValue), SrcHeaders[Index].FieldValue);
>> +    if ((*DstHeaders)[Index].FieldValue == NULL) {
>> +      return EFI_OUT_OF_RESOURCES;
>
> Looks like orevious allocations leaked.
> Didn't you think to implement smth like this ....?

Yes, I can implement AsciiStrDup() here. But this won't fix the allocation leaking, right? To fix allocation leaking, my idea is to call HttpFreeHeaderFields() before returning EFI_OUT_OF_RESOURCES.  HttpFreeHeaderFields() will skip NULL FieldName and FieldValue automatically. Does this sound good to you?

I think I covered all your comments, but I am bad to find review comment in email. If I missed any review comment, please kindly let me know. Thanks!

Regards,
Nickle

> -----Original Message-----
> From: Mike Maslenkin <mike.maslenkin@gmail.com>
> Sent: Friday, February 23, 2024 7:29 PM
> To: devel@edk2.groups.io; Nickle Wang <nicklew@nvidia.com>
> Cc: Igor Kulchytskyy <igork@ami.com>; Abner Chang <abner.chang@amd.com>;
> Nick Ramirez <nramirez@nvidia.com>
> Subject: Re: [edk2-devel] [PATCH v2 2/6] RedfishPkg: implement Redfish HTTP
> protocol
>
> External email: Use caution opening links or attachments
>
>
> Hi Nickle,
>
> %s/Resrouce/Resource/ this comes from RedfishClient autogenerated files...
> there are thousands of "Resrouce" typos.
>
> please, find my minor notes below:
>
>
> On Thu, Feb 22, 2024 at 12:11 PM Nickle Wang via groups.io
> <nicklew=nvidia.com@groups.io> wrote:
> >
> > implement Redfish HTTP protocol driver.
> >
> > Signed-off-by: Nickle Wang <nicklew@nvidia.com>
> > Co-authored-by: Igor Kulchytskyy <igork@ami.com>
> > Cc: Abner Chang <abner.chang@amd.com>
> > Cc: Igor Kulchytskyy <igork@ami.com>
> > Cc: Nick Ramirez <nramirez@nvidia.com>
> > ---
> > RedfishPkg/RedfishPkg.dec                     |    7 +-
> > RedfishPkg/RedfishComponents.dsc.inc          |    3 +-
> > RedfishPkg/RedfishPkg.dsc                     |    2 +
> > RedfishPkg/RedfishHttpDxe/RedfishHttpDxe.inf  |   73 +
> > RedfishPkg/RedfishHttpDxe/RedfishHttpData.h   |  256 ++++
> > RedfishPkg/RedfishHttpDxe/RedfishHttpDxe.h    |   44 +
> > .../RedfishHttpDxe/RedfishHttpOperation.h     |   76 +
> > RedfishPkg/RedfishHttpDxe/RedfishHttpData.c   |  667 ++++++++
> > RedfishPkg/RedfishHttpDxe/RedfishHttpDxe.c    | 1344 +++++++++++++++++
> > .../RedfishHttpDxe/RedfishHttpOperation.c     |  693 +++++++++
> > RedfishPkg/Redfish.fdf.inc                    |    3 +-
> > 11 files changed, 3164 insertions(+), 4 deletions(-)
> > create mode 100644 RedfishPkg/RedfishHttpDxe/RedfishHttpDxe.inf
> > create mode 100644 RedfishPkg/RedfishHttpDxe/RedfishHttpData.h
> > create mode 100644 RedfishPkg/RedfishHttpDxe/RedfishHttpDxe.h
> > create mode 100644 RedfishPkg/RedfishHttpDxe/RedfishHttpOperation.h
> > create mode 100644 RedfishPkg/RedfishHttpDxe/RedfishHttpData.c
> > create mode 100644 RedfishPkg/RedfishHttpDxe/RedfishHttpDxe.c
> > create mode 100644 RedfishPkg/RedfishHttpDxe/RedfishHttpOperation.c
> >
> > diff --git a/RedfishPkg/RedfishPkg.dec b/RedfishPkg/RedfishPkg.dec
> > index 9b424efdf3..114f8d2ad8 100644
> > --- a/RedfishPkg/RedfishPkg.dec
> > +++ b/RedfishPkg/RedfishPkg.dec
> > @@ -157,8 +157,11 @@
> >   # set to EFI_REST_EX_PROTOCOL.
> >   #
> >
> gEfiRedfishPkgTokenSpaceGuid.PcdRedfishSendReceiveTimeout|5000|UINT32|0
> x00001009
> > -  ## This is used to enable HTTP content encoding on Redfish communication.
> > -
> gEfiRedfishPkgTokenSpaceGuid.PcdRedfishServiceContentEncoding|TRUE|BOOLE
> AN|0x0000100A
> > +  #
> > +  # This PCD string is introduced for platform developer to set the encoding
> method supported by BMC Redfish.
> > +  # Currently only "None" and "gzip" are supported.
> > +  #
> > +
> gEfiRedfishPkgTokenSpaceGuid.PcdRedfishServiceContentEncoding|"None"|VOID
> *|0x0000100A
> >   #
> >   # Use below PCDs to control Redfhs HTTP protocol.
> >   #
> > diff --git a/RedfishPkg/RedfishComponents.dsc.inc
> b/RedfishPkg/RedfishComponents.dsc.inc
> > index 464ffc8606..d6c5b73d7f 100644
> > --- a/RedfishPkg/RedfishComponents.dsc.inc
> > +++ b/RedfishPkg/RedfishComponents.dsc.inc
> > @@ -7,7 +7,7 @@
> > # "RedfishDefines.dsc.inc".
> > #
> > # (C) Copyright 2020-2021 Hewlett Packard Enterprise Development LP<BR>
> > -# Copyright (c) 2023, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
> > +# Copyright (c) 2023-2024, NVIDIA CORPORATION & AFFILIATES. All rights
> reserved.
> > #
> > #    SPDX-License-Identifier: BSD-2-Clause-Patent
> > #
> > @@ -28,4 +28,5 @@
> >   RedfishPkg/RedfishConfigHandler/RedfishConfigHandlerDriver.inf
> >   RedfishPkg/RedfishPlatformConfigDxe/RedfishPlatformConfigDxe.inf
> >   MdeModulePkg/Universal/RegularExpressionDxe/RegularExpressionDxe.inf
> > +  RedfishPkg/RedfishHttpDxe/RedfishHttpDxe.inf
> > !endif
> > diff --git a/RedfishPkg/RedfishPkg.dsc b/RedfishPkg/RedfishPkg.dsc
> > index 25ed193182..5849e7cf9e 100644
> > --- a/RedfishPkg/RedfishPkg.dsc
> > +++ b/RedfishPkg/RedfishPkg.dsc
> > @@ -45,6 +45,8 @@
> >
> UefiHiiServicesLib|MdeModulePkg/Library/UefiHiiServicesLib/UefiHiiServicesLib.
> inf
> >
> RedfishPlatformCredentialLib|RedfishPkg/Library/PlatformCredentialLibNull/Platf
> ormCredentialLibNull.inf
> >
> RedfishContentCodingLib|RedfishPkg/Library/RedfishContentCodingLibNull/Redfi
> shContentCodingLibNull.inf
> > +
> ReportStatusCodeLib|MdeModulePkg/Library/DxeReportStatusCodeLib/DxeRepo
> rtStatusCodeLib.inf
> > +  SortLib|MdeModulePkg/Library/UefiSortLib/UefiSortLib.inf
> >
> >   # NULL instance of IPMI related library.
> >   IpmiLib|MdeModulePkg/Library/BaseIpmiLibNull/BaseIpmiLibNull.inf
> > diff --git a/RedfishPkg/RedfishHttpDxe/RedfishHttpDxe.inf
> b/RedfishPkg/RedfishHttpDxe/RedfishHttpDxe.inf
> > new file mode 100644
> > index 0000000000..c7dfdffacf
> > --- /dev/null
> > +++ b/RedfishPkg/RedfishHttpDxe/RedfishHttpDxe.inf
> > @@ -0,0 +1,73 @@
> > +## @file
> > +#  RedfishHttpDxe is the DXE driver which provides
> > +#  EdkIIRedfishHttpProtocol to EDK2 Redfish Feature
> > +#  drivers for HTTP operation.
> > +#
> > +#  Copyright (c) 2023-2024, NVIDIA CORPORATION & AFFILIATES. All rights
> reserved.
> > +#
> > +#  SPDX-License-Identifier: BSD-2-Clause-Patent
> > +#
> > +##
> > +
> > +[Defines]
> > +  INF_VERSION                    = 0x0001000b
> > +  BASE_NAME                      = RedfishHttpDxe
> > +  FILE_GUID                      = 85ADB2F1-DA93-47D4-AF4F-3D920D9BD2C0
> > +  MODULE_TYPE                    = DXE_DRIVER
> > +  VERSION_STRING                 = 1.0
> > +  ENTRY_POINT                    = RedfishHttpEntryPoint
> > +  UNLOAD_IMAGE                   = RedfishHttpDriverUnload
> > +
> > +#
> > +#  VALID_ARCHITECTURES           = IA32 X64 ARM AARCH64 RISCV64
> > +#
> > +
> > +[Sources]
> > +  RedfishHttpData.c
> > +  RedfishHttpData.h
> > +  RedfishHttpDxe.c
> > +  RedfishHttpDxe.h
> > +  RedfishHttpOperation.c
> > +  RedfishHttpOperation.h
> > +
> > +[Packages]
> > +  MdePkg/MdePkg.dec
> > +  MdeModulePkg/MdeModulePkg.dec
> > +  NetworkPkg/NetworkPkg.dec
> > +  RedfishPkg/RedfishPkg.dec
> > +
> > +[LibraryClasses.ARM]
> > +  ArmSoftFloatLib
> > +
> > +[LibraryClasses]
> > +  BaseLib
> > +  BaseMemoryLib
> > +  RedfishContentCodingLib
> > +  DebugLib
> > +  HttpLib
> > +  JsonLib
> > +  MemoryAllocationLib
> > +  PrintLib
> > +  RedfishDebugLib
> > +  ReportStatusCodeLib
> > +  UefiBootServicesTableLib
> > +  UefiDriverEntryPoint
> > +  UefiLib
> > +
> > +[Protocols]
> > +  gEdkIIRedfishHttpProtocolGuid             ## PRODUCED
> > +  gEdkIIRedfishCredentialProtocolGuid       ## CONSUMES
> > +  gEfiRestExProtocolGuid                    ## CONSUEMS
> > +
> > +[Pcd]
> > +  gEfiRedfishPkgTokenSpaceGuid.PcdHttpGetRetry
> > +  gEfiRedfishPkgTokenSpaceGuid.PcdHttpPutRetry
> > +  gEfiRedfishPkgTokenSpaceGuid.PcdHttpPatchRetry
> > +  gEfiRedfishPkgTokenSpaceGuid.PcdHttpPostRetry
> > +  gEfiRedfishPkgTokenSpaceGuid.PcdHttpDeleteRetry
> > +  gEfiRedfishPkgTokenSpaceGuid.PcdHttpRetryWaitInSecond
> > +  gEfiRedfishPkgTokenSpaceGuid.PcdHttpCacheDisabled
> > +  gEfiRedfishPkgTokenSpaceGuid.PcdRedfishServiceContentEncoding
> > +
> > +[Depex]
> > +  TRUE
> > diff --git a/RedfishPkg/RedfishHttpDxe/RedfishHttpData.h
> b/RedfishPkg/RedfishHttpDxe/RedfishHttpData.h
> > new file mode 100644
> > index 0000000000..6be610142e
> > --- /dev/null
> > +++ b/RedfishPkg/RedfishHttpDxe/RedfishHttpData.h
> > @@ -0,0 +1,256 @@
> > +/** @file
> > +  Definitions of RedfishHttpData
> > +
> > +  Copyright (c) 2023-2024, NVIDIA CORPORATION & AFFILIATES. All rights
> reserved.
> > +
> > +  SPDX-License-Identifier: BSD-2-Clause-Patent
> > +
> > +**/
> > +
> > +#ifndef EDKII_REDFISH_HTTP_DATA_H_
> > +#define EDKII_REDFISH_HTTP_DATA_H_
> > +
> > +#include "RedfishHttpDxe.h"
> > +
> > +#define REDFISH_HTTP_DRIVER_SIGNATURE   SIGNATURE_32 ('r', 'f', 'h', 'p')
> > +#define REDFISH_HTTP_CACHE_SIGNATURE    SIGNATURE_32 ('r', 'f', 'c', 'h')
> > +#define REDFISH_HTTP_SERVICE_SIGNATURE  SIGNATURE_32 ('r', 'f', 's', 'v')
> > +#define REDFISH_HTTP_PAYLOAD_SIGNATURE  SIGNATURE_32 ('r', 'f', 'p', 'l')
> > +#define REDFISH_HTTP_BASIC_AUTH_STR     "Basic "
> > +
> > +///
> > +/// REDFISH_SERVICE_PRIVATE definition.
> > +///
> > +typedef struct {
> > +  UINT32                  Signature;
> > +  CHAR8                   *Host;
> > +  CHAR8                   *HostName;
> > +  CHAR8                   *BasicAuth;
> > +  CHAR8                   *SessionToken;
> > +  EFI_REST_EX_PROTOCOL    *RestEx;
> > +} REDFISH_SERVICE_PRIVATE;
> > +
> > +///
> > +/// REDFISH_PAYLOAD_PRIVATE definition.
> > +///
> > +typedef struct {
> > +  UINT32                     Signature;
> > +  REDFISH_SERVICE_PRIVATE    *Service;
> > +  EDKII_JSON_VALUE           JsonValue;
> > +} REDFISH_PAYLOAD_PRIVATE;
> > +
> > +///
> > +/// Definition of REDFISH_HTTP_CACHE_DATA
> > +///
> > +typedef struct {
> > +  UINT32              Signature;
> > +  LIST_ENTRY          List;
> > +  EFI_STRING          Uri;
> > +  UINTN               HitCount;
> > +  REDFISH_RESPONSE    *Response;
> > +} REDFISH_HTTP_CACHE_DATA;
> > +
> > +#define REDFISH_HTTP_CACHE_FROM_LIST(a)  CR (a,
> REDFISH_HTTP_CACHE_DATA, List, REDFISH_HTTP_CACHE_SIGNATURE)
> > +
> > +///
> > +/// Definition of REDFISH_HTTP_CACHE_LIST
> > +///
> > +typedef struct {
> > +  LIST_ENTRY    Head;
> > +  UINTN         Count;
> > +  UINTN         Capacity;
> > +} REDFISH_HTTP_CACHE_LIST;
> > +
> > +///
> > +/// Definition of REDFISH_HTTP_RETRY_SETTING
> > +///
> > +typedef struct {
> > +  UINT16    MaximumRetryGet;
> > +  UINT16    MaximumRetryPut;
> > +  UINT16    MaximumRetryPost;
> > +  UINT16    MaximumRetryPatch;
> > +  UINT16    MaximumRetryDelete;
> > +  UINTN     RetryWait;
> > +} REDFISH_HTTP_RETRY_SETTING;
> > +
> > +///
> > +/// Definition of REDFISH_HTTP_CACHE_PRIVATE
> > +///
> > +typedef struct {
> > +  UINT32                               Signature;
> > +  EFI_HANDLE                           ImageHandle;
> > +  BOOLEAN                              CacheDisabled;
> > +  EFI_EVENT                            NotifyEvent;
> > +  REDFISH_HTTP_CACHE_LIST              CacheList;
> > +  EDKII_REDFISH_HTTP_PROTOCOL          Protocol;
> > +  EDKII_REDFISH_CREDENTIAL_PROTOCOL    *CredentialProtocol;
> > +  REDFISH_HTTP_RETRY_SETTING           RetrySetting;
> > +} REDFISH_HTTP_CACHE_PRIVATE;
> > +
> > +#define REDFISH_HTTP_CACHE_PRIVATE_FROM_THIS(a)  CR (a,
> REDFISH_HTTP_CACHE_PRIVATE, Protocol, REDFISH_HTTP_DRIVER_SIGNATURE)
> > +
> > +/**
> > +  Search on given ListHeader for given URI string.
> > +
> > +  @param[in]    ListHeader  Target list to search.
> > +  @param[in]    Uri         Target URI to search.
> > +
> > +  @retval REDFISH_HTTP_CACHE_DATA   Target cache data is found.
> > +  @retval NULL                      No cache data with given URI is found.
> > +
> > +**/
> > +REDFISH_HTTP_CACHE_DATA *
> > +FindHttpCacheData (
> > +  IN  LIST_ENTRY  *ListHeader,
> > +  IN  EFI_STRING  Uri
> > +  );
> > +
> > +/**
> > +  This function copy the data in SrcResponse to DstResponse.
> > +
> > +  @param[in]  SrcResponse      Source Response to copy.
> > +  @param[out] DstResponse      Destination Response.
> > +
> > +  @retval     EFI_SUCCESS      Response is copied successfully.
> > +  @retval     Others           Error occurs.
> > +
> > +**/
> > +EFI_STATUS
> > +CopyRedfishResponse (
> > +  IN  REDFISH_RESPONSE  *SrcResponse,
> > +  OUT REDFISH_RESPONSE  *DstResponse
> > +  );
> > +
> > +/**
> > +  Release all cache from list.
> > +
> > +  @param[in]    CacheList    The list to be released.
> > +
> > +  @retval EFI_SUCCESS             All cache data are released.
> > +  @retval EFI_INVALID_PARAMETER   CacheList is NULL.
> > +
> > +**/
> > +EFI_STATUS
> > +ReleaseCacheList (
> > +  IN  REDFISH_HTTP_CACHE_LIST  *CacheList
> > +  );
> > +
> > +/**
> > +  Add new cache by given URI and HTTP response to specify List.
> > +
> > +  @param[in]    List      Target cache list to add.
> > +  @param[in]    Uri       The URI string matching to this cache data.
> > +  @param[in]    Response  HTTP response.
> > +
> > +  @retval EFI_SUCCESS   Cache data is added.
> > +  @retval Others        Fail to add cache data.
> > +
> > +**/
> > +EFI_STATUS
> > +AddHttpCacheData (
> > +  IN  REDFISH_HTTP_CACHE_LIST  *List,
> > +  IN  EFI_STRING               Uri,
> > +  IN  REDFISH_RESPONSE         *Response
> > +  );
> > +
> > +/**
> > +  Delete a cache data by given cache instance.
> > +
> > +  @param[in]    List    Target cache list to be removed.
> > +  @param[in]    Data    Pointer to the instance to be deleted.
> > +
> > +  @retval EFI_SUCCESS   Cache data is removed.
> > +  @retval Others        Fail to remove cache data.
> > +
> > +**/
> > +EFI_STATUS
> > +DeleteHttpCacheData (
> > +  IN  REDFISH_HTTP_CACHE_LIST  *List,
> > +  IN  REDFISH_HTTP_CACHE_DATA  *Data
> > +  );
> > +
> > +/**
> > +  This function release Redfish Payload.
> > +
> > +  @param[in]  Payload         Pointer to payload instance.
> > +
> > +  @retval     EFI_SUCCESS     Payload is released.
> > +  @retval     Others          Error occurs.
> > +
> > +**/
> > +EFI_STATUS
> > +ReleaseRedfishPayload (
> > +  IN REDFISH_PAYLOAD_PRIVATE  *Payload
> > +  );
> > +
> > +/**
> > +  This function creat new payload. Server and JsonObj are
> > +  copied to newly created payload.
> > +
> > +  @param[in]  Service          Pointer to Service instance.
> > +  @param[in]  JsonObj          Pointer to JSON object.
> > +
> > +  @retval     REDFISH_PAYLOAD_PRIVATE  Newly created payload.
> > +  @retval     NULL             Error occurs.
> > +
> > +**/
> > +REDFISH_PAYLOAD_PRIVATE *
> > +CreateRedfishPayload (
> > +  IN REDFISH_SERVICE_PRIVATE  *Service,
> > +  IN EDKII_JSON_VALUE         JsonValue
> > +  );
> > +
> > +/**
> > +  This function release Redfish Service.
> > +
> > +  @param[in]  Service         Pointer to service instance.
> > +
> > +  @retval     EFI_SUCCESS     Service is released.
> > +  @retval     Others          Error occurs.
> > +
> > +**/
> > +EFI_STATUS
> > +ReleaseRedfishService (
> > +  IN REDFISH_SERVICE_PRIVATE  *Service
> > +  );
> > +
> > +/**
> > +  This function creat new service. Host and HostName are copied to
> > +  newly created service instance.
> > +
> > +  @param[in]  Host            Host string.
> > +  @param[in]  HostName        Hostname string.
> > +  @param[in]  BasicAuth       Basic Authorization string.
> > +  @param[in]  SessionToken    Session token string.
> > +  @param[in]  RestEx          Rest EX protocol instance.
> > +
> > +  @retval     REDFISH_PAYLOAD_PRIVATE  Newly created service.
> > +  @retval     NULL             Error occurs.
> > +
> > +**/
> > +REDFISH_SERVICE_PRIVATE *
> > +CreateRedfishService (
> > +  IN CHAR8                 *Host,
> > +  IN CHAR8                 *HostName,
> > +  IN CHAR8                 *BasicAuth OPTIONAL,
> > +  IN CHAR8                 *SessionToken OPTIONAL,
> > +  IN EFI_REST_EX_PROTOCOL  *RestEx
> > +  );
> > +
> > +/**
> > +  This function update session token in Redfish Service.
> > +
> > +  @param[in]  Service         Pointer to service instance.
> > +  @param[in]  Token           Session token.
> > +
> > +  @retval     EFI_SUCCESS     Session token is updated.
> > +  @retval     Others          Error occurs.
> > +
> > +**/
> > +EFI_STATUS
> > +UpdateSessionToken (
> > +  IN REDFISH_SERVICE_PRIVATE  *Service,
> > +  IN CHAR8                    *Token
> > +  );
> > +
> > +#endif
> > diff --git a/RedfishPkg/RedfishHttpDxe/RedfishHttpDxe.h
> b/RedfishPkg/RedfishHttpDxe/RedfishHttpDxe.h
> > new file mode 100644
> > index 0000000000..cf6ba9cb47
> > --- /dev/null
> > +++ b/RedfishPkg/RedfishHttpDxe/RedfishHttpDxe.h
> > @@ -0,0 +1,44 @@
> > +/** @file
> > +  Definitions of RedfishHttpDxe
> > +
> > +  Copyright (c) 2023-2024, NVIDIA CORPORATION & AFFILIATES. All rights
> reserved.
> > +
> > +  SPDX-License-Identifier: BSD-2-Clause-Patent
> > +
> > +**/
> > +
> > +#ifndef EDKII_REDFISH_HTTP_DXE_H_
> > +#define EDKII_REDFISH_HTTP_DXE_H_
> > +
> > +#include <Uefi.h>
> > +#include <IndustryStandard/Http11.h>
> > +
> > +#include <Library/UefiLib.h>
> > +#include <Library/BaseLib.h>
> > +#include <Library/BaseMemoryLib.h>
> > +#include <Library/RedfishContentCodingLib.h>
> > +#include <Library/DebugLib.h>
> > +#include <Library/HttpLib.h>
> > +#include <Library/JsonLib.h>
> > +#include <Library/UefiBootServicesTableLib.h>
> > +#include <Library/MemoryAllocationLib.h>
> > +#include <Library/RedfishDebugLib.h>
> > +#include <Library/ReportStatusCodeLib.h>
> > +#include <Library/PrintLib.h>
> > +
> > +#include <Protocol/Http.h>
> > +#include <Protocol/EdkIIRedfishHttpProtocol.h>
> > +#include <Protocol/EdkIIRedfishCredential.h>
> > +#include <Protocol/RestEx.h>
> > +
> > +#define IS_EMPTY_STRING(a)  ((a) == NULL || (a)[0] == '\0')
> > +#define REDFISH_HTTP_CACHE_LIST_SIZE      0x80
> > +#define REDFISH_ERROR_MSG_MAX             128
> > +#define REDFISH_DEBUG_STRING_LENGTH       200
> > +#define REDFISH_HOST_NAME_MAX             64   // IPv6 maximum length (39)
> + "https://" (8) + port number (maximum 5)
> > +#define REDFISH_HTTP_ERROR_REPORT         "Redfish HTTP %a failure(0x%x):
> %s"
> > +#define REDFISH_HTTP_CACHE_DEBUG          DEBUG_MANAGEABILITY
> > +#define REDFISH_HTTP_CACHE_DEBUG_DUMP     DEBUG_MANAGEABILITY
> > +#define REDFISH_HTTP_CACHE_DEBUG_REQUEST  DEBUG_MANAGEABILITY
> > +
> > +#endif
> > diff --git a/RedfishPkg/RedfishHttpDxe/RedfishHttpOperation.h
> b/RedfishPkg/RedfishHttpDxe/RedfishHttpOperation.h
> > new file mode 100644
> > index 0000000000..d2f7cf4c27
> > --- /dev/null
> > +++ b/RedfishPkg/RedfishHttpDxe/RedfishHttpOperation.h
> > @@ -0,0 +1,76 @@
> > +/** @file
> > +  Definitions of RedfishHttpOperation
> > +
> > +  Copyright (c) 2024, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
> > +
> > +  SPDX-License-Identifier: BSD-2-Clause-Patent
> > +
> > +**/
> > +
> > +#ifndef EDKII_REDFISH_HTTP_OPERATION_H_
> > +#define EDKII_REDFISH_HTTP_OPERATION_H_
> > +
> > +#include "RedfishHttpDxe.h"
> > +
> > +#define REDFISH_CONTENT_LENGTH_SIZE              80
> > +#define REDFISH_COMMON_HEADER_SIZE               5
> > +#define REDFISH_HTTP_HEADER_ODATA_VERSION_STR    "OData-Version"
> > +#define REDFISH_HTTP_HEADER_ODATA_VERSION_VALUE  "4.0"
> > +#define REDFISH_HTTP_HEADER_USER_AGENT_VALUE     "edk2redfish"
> > +#define REDFISH_HTTP_HEADER_CONNECTION_STR       "Connection"
> > +#define REDFISH_HTTP_HEADER_CONNECTION_VALUE     "Keep-Alive"
> > +#define REDFISH_HTTP_CONTENT_ENCODING_NONE       "None"
> > +
> > +/**
> > +  This function free resources in Request. Request is no longer available
> > +  after this function returns successfully.
> > +
> > +  @param[in]  Request      HTTP request to be released.
> > +
> > +  @retval     EFI_SUCCESS     Resrouce is released successfully.
> > +  @retval     Others          Errors occur.
> > +
> > +**/
> > +EFI_STATUS
> > +ReleaseRedfishRequest (
> > +  IN  REDFISH_REQUEST  *Request
> > +  );
> > +
> > +/**
> > +  This function free resources in given Response.
> > +
> > +  @param[in]  Response     HTTP response to be released.
> > +
> > +  @retval     EFI_SUCCESS     Resrouce is released successfully.
> > +  @retval     Others          Errors occur.
> > +
> > +**/
> > +EFI_STATUS
> > +ReleaseRedfishResponse (
> > +  IN  REDFISH_RESPONSE  *Response
> > +  );
> > +
> > +/**
> > +  This function send Redfish request to Redfish service by calling
> > +  Rest Ex protocol.
> > +
> > +  @param[in]   Service       Pointer to Redfish service.
> > +  @param[in]   Uri           Uri of Redfish service.
> > +  @param[in]   Method        HTTP method.
> > +  @param[in]   Request     Request data. This is optional.
> > +  @param[out]  Response    Redfish response data.
> > +
> > +  @retval     EFI_SUCCESS     Request is sent and received successfully.
> > +  @retval     Others          Errors occur.
> > +
> > +**/
> > +EFI_STATUS
> > +HttpSendReceive (
> > +  IN  REDFISH_SERVICE   Service,
> > +  IN  EFI_STRING        Uri,
> > +  IN  EFI_HTTP_METHOD   Method,
> > +  IN  REDFISH_REQUEST   *Request  OPTIONAL,
> > +  OUT REDFISH_RESPONSE  *Response
> > +  );
> > +
> > +#endif
> > diff --git a/RedfishPkg/RedfishHttpDxe/RedfishHttpData.c
> b/RedfishPkg/RedfishHttpDxe/RedfishHttpData.c
> > new file mode 100644
> > index 0000000000..bf95e9f8d4
> > --- /dev/null
> > +++ b/RedfishPkg/RedfishHttpDxe/RedfishHttpData.c
> > @@ -0,0 +1,667 @@
> > +/** @file
> > +  RedfishHttpData handles internal data to support Redfish HTTP protocol.
> > +
> > +  Copyright (c) 2023-2024, NVIDIA CORPORATION & AFFILIATES. All rights
> reserved.
> > +
> > +  SPDX-License-Identifier: BSD-2-Clause-Patent
> > +
> > +**/
> > +
> > +#include "RedfishHttpData.h"
> > +#include "RedfishHttpOperation.h"
> > +
> > +/**
> > +  This function update session token in Redfish Service.
> > +
> > +  @param[in]  Service         Pointer to service instance.
> > +  @param[in]  Token           Session token.
> > +
> > +  @retval     EFI_SUCCESS     Session token is updated.
> > +  @retval     Others          Error occurs.
> > +
> > +**/
> > +EFI_STATUS
> > +UpdateSessionToken (
> > +  IN REDFISH_SERVICE_PRIVATE  *Service,
> > +  IN CHAR8                    *Token
> > +  )
> > +{
> > +  if ((Service == NULL) || IS_EMPTY_STRING (Token)) {
> > +    return EFI_INVALID_PARAMETER;
> > +  }
> > +
> > +  if (Service->SessionToken != NULL) {
> > +    FreePool (Service->SessionToken);
> > +  }
> > +
> > +  Service->SessionToken = AllocateCopyPool (AsciiStrSize (Token), Token);
> > +  if (Service->SessionToken == NULL) {
> > +    return EFI_OUT_OF_RESOURCES;
> > +  }
> > +
> > +  return EFI_SUCCESS;
> > +}
> > +
> > +/**
> > +  This function release Redfish Service.
> > +
> > +  @param[in]  Service         Pointer to service instance.
> > +
> > +  @retval     EFI_SUCCESS     Service is released.
> > +  @retval     Others          Error occurs.
> > +
> > +**/
> > +EFI_STATUS
> > +ReleaseRedfishService (
> > +  IN REDFISH_SERVICE_PRIVATE  *Service
> > +  )
> > +{
> > +  if (Service == NULL) {
> > +    return EFI_INVALID_PARAMETER;
> > +  }
> > +
> > +  if (Service->Host != NULL) {
> > +    FreePool (Service->Host);
> > +  }
> > +
> > +  if (Service->HostName != NULL) {
> > +    FreePool (Service->HostName);
> > +  }
> > +
> > +  if (Service->BasicAuth != NULL) {
> > +    ZeroMem (Service->BasicAuth, AsciiStrSize (Service->BasicAuth));
> > +    FreePool (Service->BasicAuth);
> > +  }
> > +
> > +  if (Service->SessionToken != NULL) {
> > +    ZeroMem (Service->SessionToken, AsciiStrSize (Service->SessionToken));
> > +    FreePool (Service->SessionToken);
> > +  }
> > +
> > +  FreePool (Service);
> > +
> > +  return EFI_SUCCESS;
> > +}
> > +
> > +/**
> > +  This function creat new service. Host and HostName are copied to
> > +  newly created service instance.
> > +
> > +  @param[in]  Host            Host string.
> > +  @param[in]  HostName        Hostname string.
> > +  @param[in]  BasicAuth       Basic Authorization string.
> > +  @param[in]  SessionToken    Session token string.
> > +  @param[in]  RestEx          Rest EX protocol instance.
> > +
> > +  @retval     REDFISH_PAYLOAD_PRIVATE  Newly created service.
> > +  @retval     NULL             Error occurs.
> > +
> > +**/
> > +REDFISH_SERVICE_PRIVATE *
> > +CreateRedfishService (
> > +  IN CHAR8                 *Host,
> > +  IN CHAR8                 *HostName,
> > +  IN CHAR8                 *BasicAuth OPTIONAL,
> > +  IN CHAR8                 *SessionToken OPTIONAL,
> > +  IN EFI_REST_EX_PROTOCOL  *RestEx
> > +  )
> > +{
> > +  REDFISH_SERVICE_PRIVATE  *NewService;
> > +  UINTN                    AuthStrSize;
> > +
> > +  if (IS_EMPTY_STRING (Host) || IS_EMPTY_STRING (HostName) || (RestEx ==
> NULL)) {
> > +    return NULL;
> > +  }
> > +
> > +  NewService = AllocateZeroPool (sizeof (REDFISH_SERVICE_PRIVATE));
> > +  if (NewService == NULL) {
> > +    return NULL;
> > +  }
> > +
> > +  NewService->Signature = REDFISH_HTTP_SERVICE_SIGNATURE;
> > +  NewService->Host      = AllocateCopyPool (AsciiStrSize (Host), Host);
> > +  if (NewService->Host == NULL) {
> > +    goto ON_ERROR;
> > +  }
> > +
> > +  NewService->HostName = AllocateCopyPool (AsciiStrSize (HostName),
> HostName);
> > +  if (NewService->HostName == NULL) {
> > +    goto ON_ERROR;
> > +  }
> > +
> > +  if (!IS_EMPTY_STRING (BasicAuth)) {
> > +    AuthStrSize           = AsciiStrSize (BasicAuth) + AsciiStrLen
> (REDFISH_HTTP_BASIC_AUTH_STR);
> > +    NewService->BasicAuth = AllocateZeroPool (AuthStrSize);
> > +    if (NewService->BasicAuth == NULL) {
> > +      goto ON_ERROR;
> > +    }
> > +
> > +    AsciiSPrint (NewService->BasicAuth, AuthStrSize, "%a%a",
> REDFISH_HTTP_BASIC_AUTH_STR, BasicAuth);
> > +  }
> > +
> > +  if (!IS_EMPTY_STRING (SessionToken)) {
> > +    NewService->SessionToken = AllocateCopyPool (AsciiStrSize (SessionToken),
> SessionToken);
> > +    if (NewService->SessionToken == NULL) {
> > +      goto ON_ERROR;
> > +    }
> > +  }
> > +
> > +  NewService->RestEx = RestEx;
> > +
> > +  return NewService;
> > +
> > +ON_ERROR:
> > +
> > +  ReleaseRedfishService (NewService);
> > +
> > +  return NULL;
> > +}
> > +
> > +/**
> > +  This function release Redfish Payload.
> > +
> > +  @param[in]  Payload         Pointer to payload instance.
> > +
> > +  @retval     EFI_SUCCESS     Payload is released.
> > +  @retval     Others          Error occurs.
> > +
> > +**/
> > +EFI_STATUS
> > +ReleaseRedfishPayload (
> > +  IN REDFISH_PAYLOAD_PRIVATE  *Payload
> > +  )
> > +{
> > +  if (Payload == NULL) {
> > +    return EFI_INVALID_PARAMETER;
> > +  }
> > +
> > +  if (Payload->Service != NULL) {
> > +    ReleaseRedfishService (Payload->Service);
> > +  }
> > +
> > +  if (Payload->JsonValue != NULL) {
> > +    JsonValueFree (Payload->JsonValue);
> > +  }
> > +
> > +  FreePool (Payload);
> > +
> > +  return EFI_SUCCESS;
> > +}
> > +
> > +/**
> > +  This function creat new payload. Server and JsonObj are
> > +  copied to newly created payload.
> > +
> > +  @param[in]  Service          Pointer to Service instance.
> > +  @param[in]  JsonValue        Pointer to JSON value.
> > +
> > +  @retval     REDFISH_PAYLOAD_PRIVATE  Newly created payload.
> > +  @retval     NULL                     Error occurs.
> > +
> > +**/
> > +REDFISH_PAYLOAD_PRIVATE *
> > +CreateRedfishPayload (
> > +  IN REDFISH_SERVICE_PRIVATE  *Service,
> > +  IN EDKII_JSON_VALUE         JsonValue
> > +  )
> > +{
> > +  REDFISH_PAYLOAD_PRIVATE  *NewPayload;
> > +
> > +  if ((Service == NULL) || (JsonValue == NULL)) {
> > +    return NULL;
> > +  }
> > +
> > +  NewPayload = AllocateZeroPool (sizeof (REDFISH_PAYLOAD_PRIVATE));
> > +  if (NewPayload == NULL) {
> > +    return NULL;
> > +  }
> > +
> > +  NewPayload->Signature = REDFISH_HTTP_PAYLOAD_SIGNATURE;
> > +  NewPayload->Service   = CreateRedfishService (Service->Host, Service-
> >HostName, Service->BasicAuth, Service->SessionToken, Service->RestEx);
> > +  if (NewPayload->Service == NULL) {
> > +    goto ON_ERROR;
> > +  }
> > +
> > +  NewPayload->JsonValue = JsonValueClone (JsonValue);
> > +  if (NewPayload->JsonValue == NULL) {
> > +    goto ON_ERROR;
> > +  }
> > +
> > +  return NewPayload;
> > +
> > +ON_ERROR:
> > +
> > +  ReleaseRedfishPayload (NewPayload);
> > +
>
>
> NewPayload->Service  is leaked
>
>
> > +  return NULL;
> > +}
> > +
> > +/**
> > +  This function copy the data in SrcResponse to DstResponse.
> > +
> > +  @param[in]  SrcResponse      Source Response to copy.
> > +  @param[out] DstResponse      Destination Response.
> > +
> > +  @retval     EFI_SUCCESS      Response is copied successfully.
> > +  @retval     Others           Error occurs.
> > +
> > +**/
> > +EFI_STATUS
> > +CopyRedfishResponse (
> > +  IN  REDFISH_RESPONSE  *SrcResponse,
> > +  OUT REDFISH_RESPONSE  *DstResponse
> > +  )
> > +{
> > +  REDFISH_PAYLOAD_PRIVATE  *Payload;
> > +  UINTN                    Index;
> > +
> > +  if ((SrcResponse == NULL) || (DstResponse == NULL)) {
> > +    return EFI_INVALID_PARAMETER;
> > +  }
> > +
> > +  if (SrcResponse == DstResponse) {
> > +    return EFI_SUCCESS;
> > +  }
> > +
> > +  //
> > +  // Status code
> > +  //
> > +  if (SrcResponse->StatusCode != NULL) {
> > +    DstResponse->StatusCode = AllocateCopyPool (sizeof
> (EFI_HTTP_STATUS_CODE), SrcResponse->StatusCode);
> > +    if (DstResponse->StatusCode == NULL) {
> > +      goto ON_ERROR;
> > +    }
> > +  }
> > +
> > +  //
> > +  // Header
> > +  //
> > +  if ((SrcResponse->HeaderCount > 0) && (SrcResponse->Headers != NULL)) {
> > +    DstResponse->HeaderCount = 0;
> > +    DstResponse->Headers     = AllocateZeroPool (sizeof (EFI_HTTP_HEADER) *
> SrcResponse->HeaderCount);
> > +    if (DstResponse->Headers == NULL) {
> > +      goto ON_ERROR;
> > +    }
> > +
> > +    for (Index = 0; Index < SrcResponse->HeaderCount; Index++) {
> > +      DstResponse->Headers[Index].FieldName = AllocateCopyPool (AsciiStrSize
> (SrcResponse->Headers[Index].FieldName), SrcResponse-
> >Headers[Index].FieldName);
> > +      if (DstResponse->Headers[Index].FieldName == NULL) {
> > +        goto ON_ERROR;
> > +      }
> > +
> > +      DstResponse->Headers[Index].FieldValue = AllocateCopyPool (AsciiStrSize
> (SrcResponse->Headers[Index].FieldValue), SrcResponse-
> >Headers[Index].FieldValue);
> > +      if (DstResponse->Headers[Index].FieldValue == NULL) {
> > +        goto ON_ERROR;
> > +      }
> > +
> > +      DstResponse->HeaderCount += 1;
> > +    }
> > +  }
> > +
> > +  //
> > +  // Payload
> > +  //
> > +  if (SrcResponse->Payload != NULL) {
> > +    Payload = (REDFISH_PAYLOAD_PRIVATE *)SrcResponse->Payload;
> > +    if (Payload->Signature != REDFISH_HTTP_PAYLOAD_SIGNATURE) {
> > +      DEBUG ((DEBUG_ERROR, "%a: signature check failure\n", __func__));
> > +      goto ON_ERROR;
> > +    }
> > +
> > +    DstResponse->Payload = CreateRedfishPayload (Payload->Service, Payload-
> >JsonValue);
> > +    if (DstResponse->Payload  == NULL) {
> > +      goto ON_ERROR;
> > +    }
> > +  }
> > +
> > +  return EFI_SUCCESS;
> > +
> > +ON_ERROR:
> > +
> > +  ReleaseRedfishResponse (DstResponse);
> > +
> > +  return EFI_OUT_OF_RESOURCES;
> > +}
> > +
> > +/**
> > +  This function clone input response and return to caller
> > +
> > +  @param[in]  Response      Response to clone.
> > +
> > +  @retval     REDFISH_RESPONSE *  Response is cloned.
> > +  @retval     NULL                Errors occur.
> > +
> > +**/
> > +REDFISH_RESPONSE *
> > +CloneRedfishResponse (
> > +  IN REDFISH_RESPONSE  *Response
> > +  )
> > +{
> > +  EFI_STATUS        Status;
> > +  REDFISH_RESPONSE  *NewResponse;
> > +
> > +  if (Response == NULL) {
> > +    return NULL;
> > +  }
> > +
> > +  NewResponse = AllocateZeroPool (sizeof (REDFISH_RESPONSE));
> > +  if (NewResponse == NULL) {
> > +    return NULL;
> > +  }
> > +
> > +  Status = CopyRedfishResponse (Response, NewResponse);
> > +  if (EFI_ERROR (Status)) {
> > +    FreePool (NewResponse);
> > +    return NULL;
> > +  }
> > +
> > +  return NewResponse;
> > +}
> > +
> > +/**
> > +  Release REDFISH_HTTP_CACHE_DATA resource
> > +
> > +  @param[in]    Data    Pointer to REDFISH_HTTP_CACHE_DATA instance
> > +
> > +  @retval EFI_SUCCESS             REDFISH_HTTP_CACHE_DATA is released
> successfully.
> > +  @retval EFI_INVALID_PARAMETER   Data is NULL
> > +
> > +**/
> > +EFI_STATUS
> > +ReleaseHttpCacheData (
> > +  IN REDFISH_HTTP_CACHE_DATA  *Data
> > +  )
> > +{
> > +  if (Data == NULL) {
> > +    return EFI_INVALID_PARAMETER;
> > +  }
> > +
> > +  if (Data->Uri != NULL) {
> > +    FreePool (Data->Uri);
> > +  }
> > +
> > +  if (Data->Response != NULL) {
> > +    ReleaseRedfishResponse (Data->Response);
> > +    FreePool (Data->Response);
> > +  }
> > +
> > +  FreePool (Data);
> > +
> > +  return EFI_SUCCESS;
> > +}
> > +
> > +/**
> > +  Create new cache data.
> > +
> > +  @param[in]    Uri       The URI string matching to this cache data.
> > +  @param[in]    Response  HTTP response.
> > +
> > +  @retval REDFISH_HTTP_CACHE_DATA *   Pointer to newly created cache
> data.
> > +  @retval NULL                        No memory available.
> > +
> > +**/
> > +REDFISH_HTTP_CACHE_DATA *
> > +NewHttpCacheData (
> > +  IN  EFI_STRING        Uri,
> > +  IN  REDFISH_RESPONSE  *Response
> > +  )
> > +{
> > +  REDFISH_HTTP_CACHE_DATA  *NewData;
> > +  UINTN                    Size;
> > +
> > +  if (IS_EMPTY_STRING (Uri) || (Response == NULL)) {
> > +    return NULL;
> > +  }
> > +
> > +  NewData = AllocateZeroPool (sizeof (REDFISH_HTTP_CACHE_DATA));
> > +  if (NewData == NULL) {
> > +    return NULL;
> > +  }
> > +
> > +  NewData->Signature = REDFISH_HTTP_CACHE_SIGNATURE;
> > +  Size               = StrSize (Uri);
> > +  NewData->Uri       = AllocateCopyPool (Size, Uri);
> > +  if (NewData->Uri == NULL) {
> > +    goto ON_ERROR;
> > +  }
> > +
> > +  NewData->Response = Response;
> > +  NewData->HitCount = 1;
> > +
> > +  return NewData;
> > +
> > +ON_ERROR:
> > +
> > +  if (NewData != NULL) {
> > +    ReleaseHttpCacheData (NewData);
> > +  }
> > +
> > +  return NULL;
> > +}
> > +
> > +/**
> > +  Search on given ListHeader for given URI string.
> > +
> > +  @param[in]    ListHeader  Target list to search.
> > +  @param[in]    Uri         Target URI to search.
> > +
> > +  @retval REDFISH_HTTP_CACHE_DATA   Target cache data is found.
> > +  @retval NULL                      No cache data with given URI is found.
> > +
> > +**/
> > +REDFISH_HTTP_CACHE_DATA *
> > +FindHttpCacheData (
> > +  IN  LIST_ENTRY  *ListHeader,
> > +  IN  EFI_STRING  Uri
> > +  )
> > +{
> > +  LIST_ENTRY               *List;
> > +  REDFISH_HTTP_CACHE_DATA  *Data;
> > +
> > +  if (IS_EMPTY_STRING (Uri)) {
> > +    return NULL;
> > +  }
> > +
> > +  if (IsListEmpty (ListHeader)) {
> > +    return NULL;
> > +  }
> > +
> > +  Data = NULL;
> > +  List = GetFirstNode (ListHeader);
> > +  while (!IsNull (ListHeader, List)) {
> > +    Data = REDFISH_HTTP_CACHE_FROM_LIST (List);
> > +
> > +    if (StrCmp (Data->Uri, Uri) == 0) {
> > +      return Data;
> > +    }
> > +
> > +    List = GetNextNode (ListHeader, List);
> > +  }
> > +
> > +  return NULL;
> > +}
> > +
> > +/**
> > +  Search on given ListHeader and return cache data with minimum hit count.
> > +
> > +  @param[in]    ListHeader  Target list to search.
> > +
> > +  @retval REDFISH_HTTP_CACHE_DATA   Target cache data is returned.
> > +  @retval NULL                      No cache data is found.
> > +
> > +**/
> > +REDFISH_HTTP_CACHE_DATA *
> > +FindUnusedHttpCacheData (
> > +  IN  LIST_ENTRY  *ListHeader
> > +  )
> > +{
> > +  LIST_ENTRY               *List;
> > +  REDFISH_HTTP_CACHE_DATA  *Data;
> > +  REDFISH_HTTP_CACHE_DATA  *UnusedData;
> > +  UINTN                    HitCount;
> > +
> > +  if (IsListEmpty (ListHeader)) {
> > +    return NULL;
> > +  }
> > +
> > +  Data       = NULL;
> > +  UnusedData = NULL;
> > +  HitCount   = 0;
> > +
> > +  List       = GetFirstNode (ListHeader);
> > +  Data       = REDFISH_HTTP_CACHE_FROM_LIST (List);
> > +  UnusedData = Data;
> > +  HitCount   = Data->HitCount;
> > +  List       = GetNextNode (ListHeader, List);
> > +
> > +  while (!IsNull (ListHeader, List)) {
> > +    Data = REDFISH_HTTP_CACHE_FROM_LIST (List);
> > +
> > +    if (Data->HitCount < HitCount) {
> > +      HitCount   = Data->HitCount;
> > +      UnusedData = Data;
> > +    }
> > +
> > +    List = GetNextNode (ListHeader, List);
> > +  }
> > +
> > +  return UnusedData;
> > +}
> > +
> > +/**
> > +  Delete a cache data by given cache instance.
> > +
> > +  @param[in]    List    Target cache list to be removed.
> > +  @param[in]    Data    Pointer to the instance to be deleted.
> > +
> > +  @retval EFI_SUCCESS   Cache data is removed.
> > +  @retval Others        Fail to remove cache data.
> > +
> > +**/
> > +EFI_STATUS
> > +DeleteHttpCacheData (
> > +  IN  REDFISH_HTTP_CACHE_LIST  *List,
> > +  IN  REDFISH_HTTP_CACHE_DATA  *Data
> > +  )
> > +{
> > +  if ((List == NULL) || (Data == NULL)) {
> > +    return EFI_INVALID_PARAMETER;
> > +  }
> > +
> > +  DEBUG ((REDFISH_HTTP_CACHE_DEBUG, "%a: delete: %s\n", __func__,
> Data->Uri));
> > +
> > +  RemoveEntryList (&Data->List);
> > +  --List->Count;
> > +
> > +  return ReleaseHttpCacheData (Data);
> > +}
> > +
> > +/**
> > +  Add new cache by given URI and HTTP response to specify List.
> > +
> > +  @param[in]    List      Target cache list to add.
> > +  @param[in]    Uri       The URI string matching to this cache data.
> > +  @param[in]    Response  HTTP response.
> > +
> > +  @retval EFI_SUCCESS   Cache data is added.
> > +  @retval Others        Fail to add cache data.
> > +
> > +**/
> > +EFI_STATUS
> > +AddHttpCacheData (
> > +  IN  REDFISH_HTTP_CACHE_LIST  *List,
> > +  IN  EFI_STRING               Uri,
> > +  IN  REDFISH_RESPONSE         *Response
> > +  )
> > +{
> > +  REDFISH_HTTP_CACHE_DATA  *NewData;
> > +  REDFISH_HTTP_CACHE_DATA  *OldData;
> > +  REDFISH_HTTP_CACHE_DATA  *UnusedData;
> > +  REDFISH_RESPONSE         *NewResponse;
> > +
> > +  if ((List == NULL) || IS_EMPTY_STRING (Uri) || (Response == NULL)) {
> > +    return EFI_INVALID_PARAMETER;
> > +  }
> > +
> > +  //
> > +  // If same cache data exist, replace it with latest one.
> > +  //
> > +  OldData = FindHttpCacheData (&List->Head, Uri);
> > +  if (OldData != NULL) {
> > +    DeleteHttpCacheData (List, OldData);
> > +  }
> > +
> > +  //
> > +  // Check capacity
> > +  //
> > +  if (List->Count >= List->Capacity) {
> > +    DEBUG ((REDFISH_HTTP_CACHE_DEBUG, "%a: list is full and retire unused
> cache\n", __func__));
> > +    UnusedData = FindUnusedHttpCacheData (&List->Head);
> > +    if (UnusedData == NULL) {
> > +      return EFI_OUT_OF_RESOURCES;
> > +    }
> > +
> > +    DeleteHttpCacheData (List, UnusedData);
> > +  }
> > +
> > +  //
> > +  // Clone a local copy
> > +  //
> > +  NewResponse = CloneRedfishResponse (Response);
> > +  if (NewResponse == NULL) {
> > +    return EFI_OUT_OF_RESOURCES;
> > +  }
> > +
> > +  NewData = NewHttpCacheData (Uri, NewResponse);
> > +  if (NewData == NULL) {
> > +    return EFI_OUT_OF_RESOURCES;
> > +  }
> > +
> > +  InsertTailList (&List->Head, &NewData->List);
> > +  ++List->Count;
> > +
> > +  DEBUG ((REDFISH_HTTP_CACHE_DEBUG, "%a: cache(%d/%d) %s\n",
> __func__, List->Count, List->Capacity, NewData->Uri));
> > +
> > +  return EFI_SUCCESS;
> > +}
> > +
> > +/**
> > +  Release all cache from list.
> > +
> > +  @param[in]    CacheList    The list to be released.
> > +
> > +  @retval EFI_SUCCESS             All cache data are released.
> > +  @retval EFI_INVALID_PARAMETER   CacheList is NULL.
> > +
> > +**/
> > +EFI_STATUS
> > +ReleaseCacheList (
> > +  IN  REDFISH_HTTP_CACHE_LIST  *CacheList
> > +  )
> > +{
> > +  LIST_ENTRY               *List;
> > +  LIST_ENTRY               *Next;
> > +  REDFISH_HTTP_CACHE_DATA  *Data;
> > +
> > +  if (CacheList == NULL) {
> > +    return EFI_INVALID_PARAMETER;
> > +  }
> > +
> > +  if (IsListEmpty (&CacheList->Head)) {
> > +    return EFI_SUCCESS;
> > +  }
> > +
> > +  Data = NULL;
> > +  Next = NULL;
> > +  List = GetFirstNode (&CacheList->Head);
> > +  while (!IsNull (&CacheList->Head, List)) {
> > +    Data = REDFISH_HTTP_CACHE_FROM_LIST (List);
> > +    Next = GetNextNode (&CacheList->Head, List);
> > +
> > +    DeleteHttpCacheData (CacheList, Data);
> > +
> > +    List = Next;
> > +  }
> > +
> > +  return EFI_SUCCESS;
> > +}
> > diff --git a/RedfishPkg/RedfishHttpDxe/RedfishHttpDxe.c
> b/RedfishPkg/RedfishHttpDxe/RedfishHttpDxe.c
> > new file mode 100644
> > index 0000000000..39958d4865
> > --- /dev/null
> > +++ b/RedfishPkg/RedfishHttpDxe/RedfishHttpDxe.c
> > @@ -0,0 +1,1344 @@
> > +/** @file
> > +  RedfishHttpDxe produces EdkIIRedfishHttpProtocol
> > +  for EDK2 Redfish Feature driver to do HTTP operations.
> > +
> > +  Copyright (c) 2023-2024, NVIDIA CORPORATION & AFFILIATES. All rights
> reserved.
> > +
> > +  SPDX-License-Identifier: BSD-2-Clause-Patent
> > +
> > +**/
> > +
> > +#include "RedfishHttpDxe.h"
> > +#include "RedfishHttpData.h"
> > +#include "RedfishHttpOperation.h"
> > +
> > +REDFISH_HTTP_CACHE_PRIVATE  *mRedfishHttpCachePrivate = NULL;
> > +
> > +/**
> > +  Debug output the cache list.
> > +
> > +  @param[in]    Msg            Debug message string.
> > +  @param[in]    ErrorLevel     Output error level.
> > +  @param[in]    CacheList      Target list to dump.
> > +
> > +  @retval EFI_SUCCESS             Debug dump finished.
> > +  @retval EFI_INVALID_PARAMETER   HttpCacheList is NULL.
> > +
> > +**/
> > +EFI_STATUS
> > +DebugPrintHttpCacheList (
> > +  IN  CONST CHAR8              *Msg,
> > +  IN  UINTN                    ErrorLevel,
> > +  IN  REDFISH_HTTP_CACHE_LIST  *CacheList
> > +  )
> > +{
> > +  LIST_ENTRY               *List;
> > +  REDFISH_HTTP_CACHE_DATA  *Data;
> > +  UINTN                    Index;
> > +
> > +  if (CacheList == NULL) {
> > +    return EFI_INVALID_PARAMETER;
> > +  }
> > +
> > +  if (!IS_EMPTY_STRING (Msg)) {
> > +    DEBUG ((ErrorLevel, "%a\n", Msg));
> > +  }
> > +
> > +  if (IsListEmpty (&CacheList->Head)) {
> > +    DEBUG ((ErrorLevel, "list is empty\n"));
> > +    return EFI_NOT_FOUND;
> > +  }
> > +
> > +  DEBUG ((ErrorLevel, "list count: %d capacity: %d\n", CacheList->Count,
> CacheList->Capacity));
> > +  Data  = NULL;
> > +  Index = 0;
> > +  List  = GetFirstNode (&CacheList->Head);
> > +  while (!IsNull (&CacheList->Head, List)) {
> > +    Data = REDFISH_HTTP_CACHE_FROM_LIST (List);
> > +
> > +    DEBUG ((ErrorLevel, "%d) Uri: %s Hit: %d\n", ++Index, Data->Uri, Data-
> >HitCount));
> > +
> > +    List = GetNextNode (&CacheList->Head, List);
> > +  }
> > +
> > +  return EFI_SUCCESS;
> > +}
> > +
> > +/**
> > +
> > +  Check HTTP status code to see if we like to retry HTTP request or not.
> > +
> > +  @param[in]  StatusCode      HTTP status code.
> > +
> > +  @retval     BOOLEAN         Return true when we like to retry request.
> > +                              Return false when we don't want to retry request.
> > +
> > +**/
> > +BOOLEAN
> > +RedfishRetryRequired (
> > +  IN EFI_HTTP_STATUS_CODE  *StatusCode
> > +  )
> > +{
> > +  if (StatusCode == NULL) {
> > +    return TRUE;
> > +  }
> > +
> > +  if ((*StatusCode == HTTP_STATUS_500_INTERNAL_SERVER_ERROR) ||
> > +      (*StatusCode == HTTP_STATUS_UNSUPPORTED_STATUS))
> > +  {
> > +    return TRUE;
> > +  }
> > +
> > +  return FALSE;
> > +}
> > +
> > +/**
> > +
> > +  Convert Unicode string to ASCII string. It's call responsibility to release
> returned buffer.
> > +
> > +  @param[in]  UnicodeStr      Unicode string to convert.
> > +
> > +  @retval     CHAR8 *         ASCII string returned.
> > +  @retval     NULL            Errors occur.
> > +
> > +**/
> > +CHAR8 *
> > +StringUnicodeToAscii (
> > +  IN EFI_STRING  UnicodeStr
> > +  )
> > +{
> > +  CHAR8       *AsciiStr;
> > +  UINTN       AsciiStrSize;
> > +  EFI_STATUS  Status;
> > +
> > +  if (IS_EMPTY_STRING (UnicodeStr)) {
> > +    return NULL;
> > +  }
> > +
> > +  AsciiStrSize = StrLen (UnicodeStr) + 1;
> > +  AsciiStr     = AllocateZeroPool (AsciiStrSize);
> > +  if (AsciiStr == NULL) {
> > +    return NULL;
> > +  }
> > +
> > +  Status = UnicodeStrToAsciiStrS (UnicodeStr, AsciiStr, AsciiStrSize);
> > +  if (EFI_ERROR (Status)) {
> > +    DEBUG ((DEBUG_ERROR, "UnicodeStrToAsciiStrS failed: %r\n", Status));
> > +    FreePool (AsciiStr);
> > +    return NULL;
> > +  }
> > +
> > +  return AsciiStr;
> > +}
> > +
> > +/**
> > +  Return HTTP method in ASCII string. Caller does not need
> > +  to free returned string buffer.
> > +
> > +  @param[in]  Method         HTTP method.
> > +
> > +  @retval CHAR8 *   Method in string.
> > +**/
> > +CHAR8 *
> > +HttpMethodToString (
> > +  IN  EFI_HTTP_METHOD  Method
> > +  )
> > +{
> > +  switch (Method) {
> > +    case HttpMethodGet:
> > +      return HTTP_METHOD_GET;
> > +      break;
> > +    case HttpMethodPost:
> > +      return HTTP_METHOD_POST;
> > +      break;
> > +    case HttpMethodPatch:
> > +      return HTTP_METHOD_PATCH;
> > +      break;
> > +    case HttpMethodPut:
> > +      return HTTP_METHOD_PUT;
> > +      break;
> > +    case HttpMethodDelete:
> > +      return HTTP_METHOD_DELETE;
> > +      break;
> > +    default:
> > +      break;
> > +  }
> > +
> > +  return "Unknown";
> > +}
> > +
> > +/**
> > +  Report HTTP communication error via report status code.
> > +
> > +  @param[in]  Method         HTTP method.
> > +  @param[in]  Uri            The URI which has failure.
> > +  @param[in]  HttpStatusCode HTTP status code.
> > +
> > +**/
> > +VOID
> > +ReportHttpError (
> > +  IN  EFI_HTTP_METHOD       Method,
> > +  IN  EFI_STRING            Uri,
> > +  IN  EFI_HTTP_STATUS_CODE  *HttpStatusCode  OPTIONAL
> > +  )
> > +{
> > +  CHAR8  ErrorMsg[REDFISH_ERROR_MSG_MAX];
> > +
> > +  if (IS_EMPTY_STRING (Uri)) {
> > +    DEBUG ((DEBUG_ERROR, "%a: no URI to report error status\n", __func__));
> > +    return;
> > +  }
> > +
> > +  //
> > +  // Report failure of URI and HTTP status code.
> > +  //
> > +  AsciiSPrint (ErrorMsg, sizeof (ErrorMsg), REDFISH_HTTP_ERROR_REPORT,
> HttpMethodToString (Method), (HttpStatusCode == NULL ?
> HTTP_STATUS_UNSUPPORTED_STATUS : *HttpStatusCode), Uri);
> > +  DEBUG ((DEBUG_ERROR, "%a\n", ErrorMsg));
> > +  //
> > +  // TODO:
> > +  // Below PI status code is approved by PIWG and wait for specification
> published.
> > +  // We will uncomment below report status code after PI status code get
> published.
> > +  // REF:
> https://bugzilla.ti/
> anocore.org%2Fshow_bug.cgi%3Fid%3D4483&data=05%7C02%7Cnicklew%40nvi
> dia.com%7Cf659c54c3edb43527c3608dc3462ab2a%7C43083d15727340c1b7db
> 39efd9ccc17a%7C0%7C0%7C638442845601051396%7CUnknown%7CTWFpbGZs
> b3d8eyJWIjoiMC4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%
> 3D%7C0%7C%7C%7C&sdata=T1bN7KmTa1v49cOFkd9%2F9hlzkdzbHPLebxSiUkp
> VuU4%3D&reserved=0
> > +  //
> > +  // REPORT_STATUS_CODE_WITH_EXTENDED_DATA (
> > +  //  EFI_ERROR_CODE | EFI_ERROR_MAJOR,
> > +  //  EFI_COMPUTING_UNIT_MANAGEABILITY |
> EFI_MANAGEABILITY_EC_REDFISH_COMMUNICATION_ERROR,
> > +  //  ErrorMsg,
> > +  //  AsciiStrSize (ErrorMsg)
> > +  //  );
> > +}
> > +
> > +/**
> > +  This function create Redfish service. It's caller's responsibility to free returned
> > +  Redfish service by calling FreeService ().
> > +
> > +  @param[in]  This                       Pointer to EDKII_REDFISH_HTTP_PROTOCOL
> instance.
> > +  @param[in]  RedfishConfigServiceInfo   Redfish config service information.
> > +
> > +  @retval     REDFISH_SERVICE  Redfish service is created.
> > +  @retval     NULL             Errors occur.
> > +
> > +**/
> > +REDFISH_SERVICE
> > +EFIAPI
> > +RedfishCreateRedfishService (
> > +  IN  EDKII_REDFISH_HTTP_PROTOCOL         *This,
> > +  IN  REDFISH_CONFIG_SERVICE_INFORMATION  *RedfishConfigServiceInfo
> > +  )
> > +{
> > +  EFI_STATUS                  Status;
> > +  REDFISH_HTTP_CACHE_PRIVATE  *Private;
> > +  REDFISH_SERVICE_PRIVATE     *NewService;
> > +  CHAR8                       *AsciiLocation;
> > +  CHAR8                       *Host;
> > +  CHAR8                       *BasicAuthString;
> > +  UINTN                       BasicAuthStrSize;
> > +  CHAR8                       *EncodedAuthString;
> > +  UINTN                       EncodedAuthStrSize;
> > +  EDKII_REDFISH_AUTH_METHOD   AuthMethod;
> > +  CHAR8                       *Username;
> > +  CHAR8                       *Password;
> > +  UINTN                       UsernameSize;
> > +  UINTN                       PasswordSize;
> > +  EFI_REST_EX_PROTOCOL        *RestEx;
> > +
> > +  if ((This == NULL) || (RedfishConfigServiceInfo == NULL)) {
> > +    return NULL;
> > +  }
> > +
> > +  DEBUG ((REDFISH_HTTP_CACHE_DEBUG, "%a: service location: %s\n",
> __func__, RedfishConfigServiceInfo->RedfishServiceLocation));
> > +
> > +  Private            = REDFISH_HTTP_CACHE_PRIVATE_FROM_THIS (This);
> > +  BasicAuthString    = NULL;
> > +  EncodedAuthString  = NULL;
> > +  Username           = NULL;
> > +  Password           = NULL;
> > +  NewService         = NULL;
> > +  AsciiLocation      = NULL;
> > +  Host               = NULL;
> > +  BasicAuthStrSize   = 0;
> > +  EncodedAuthStrSize = 0;
> > +  UsernameSize       = 0;
> > +  PasswordSize       = 0;
> > +
> > +  //
> > +  // Build host and host name from service location
> > +  //
> > +  if (!IS_EMPTY_STRING (RedfishConfigServiceInfo->RedfishServiceLocation)) {
> > +    AsciiLocation = StringUnicodeToAscii (RedfishConfigServiceInfo-
> >RedfishServiceLocation);
> > +    if (AsciiLocation == NULL) {
> > +      goto ON_RELEASE;
> > +    }
> > +
> > +    Host = AllocateZeroPool (REDFISH_HOST_NAME_MAX);
> > +    if (AsciiLocation == NULL) {
> > +      goto ON_RELEASE;
> > +    }
> > +
> > +    if (RedfishConfigServiceInfo->RedfishServiceUseHttps) {
> > +      AsciiSPrint (Host, REDFISH_HOST_NAME_MAX, "https://%a",
> AsciiLocation);
> > +    } else {
> > +      AsciiSPrint (Host, REDFISH_HOST_NAME_MAX, "http://%a", AsciiLocation);
> > +    }
> > +
> > +    DEBUG ((REDFISH_HTTP_CACHE_DEBUG, "%a: Host: %a\n", __func__,
> Host));
> > +  }
> > +
> > +  //
> > +  // Find Rest Ex protocol
> > +  //
> > +  if (RedfishConfigServiceInfo->RedfishServiceRestExHandle != NULL) {
> > +    Status = gBS->HandleProtocol (
> > +                    RedfishConfigServiceInfo->RedfishServiceRestExHandle,
> > +                    &gEfiRestExProtocolGuid,
> > +                    (VOID **)&RestEx
> > +                    );
> > +  } else {
> > +    DEBUG ((DEBUG_ERROR, "%a: Rest Ex protocol is not available\n",
> __func__));
> > +    goto ON_RELEASE;
> > +  }
> > +
> > +  //
> > +  // Get credential
> > +  //
> > +  if (Private->CredentialProtocol == NULL) {
> > +    //
> > +    // No credential available on this system.
> > +    //
> > +    DEBUG ((DEBUG_WARN, "%a: no credential protocol available\n",
> __func__));
> > +  } else {
> > +    Status = Private->CredentialProtocol->GetAuthInfo (
> > +                                            Private->CredentialProtocol,
> > +                                            &AuthMethod,
> > +                                            &Username,
> > +                                            &Password
> > +                                            );
> > +    if (EFI_ERROR (Status) || IS_EMPTY_STRING (Username) ||
> IS_EMPTY_STRING (Password)) {
> > +      DEBUG ((DEBUG_ERROR, "%a: cannot get authentication information:
> %r\n", __func__, Status));
> > +      goto ON_RELEASE;
> > +    } else {
> > +      DEBUG ((REDFISH_HTTP_CACHE_DEBUG, "%a: Auth method: 0x%x
> username: %a password: %a\n", __func__, AuthMethod, Username, Password));
> > +
> > +      //
> > +      // Perform base64 encoding (RFC 7617)
> > +      //
> > +      UsernameSize     = AsciiStrSize (Username);
> > +      PasswordSize     = AsciiStrSize (Password);
> > +      BasicAuthStrSize =  UsernameSize + PasswordSize;  // one byte taken from
> null-terminator for ':'
> > +      BasicAuthString  = AllocateZeroPool (BasicAuthStrSize);
> > +      if (BasicAuthString == NULL) {
> > +        goto ON_RELEASE;
> > +      }
> > +
> > +      AsciiSPrint (
> > +        BasicAuthString,
> > +        BasicAuthStrSize,
> > +        "%a:%a",
> > +        Username,
> > +        Password
> > +        );
> > +
> > +      Status = Base64Encode (
> > +                 (CONST UINT8 *)BasicAuthString,
> > +                 BasicAuthStrSize,
> > +                 EncodedAuthString,
> > +                 &EncodedAuthStrSize
> > +                 );
> > +      if ((Status == EFI_BUFFER_TOO_SMALL) && (EncodedAuthStrSize > 0)) {
> > +        EncodedAuthString = AllocateZeroPool (EncodedAuthStrSize);
> > +        if (EncodedAuthString == NULL) {
> > +          goto ON_RELEASE;
> > +        }
> > +
> > +        Status = Base64Encode (
> > +                   (CONST UINT8 *)BasicAuthString,
> > +                   BasicAuthStrSize,
> > +                   EncodedAuthString,
> > +                   &EncodedAuthStrSize
> > +                   );
> > +        if (EFI_ERROR (Status)) {
> > +          DEBUG ((DEBUG_ERROR, "%a: Base64Encode failure: %r\n", __func__,
> Status));
> > +        }
> > +
> > +        DEBUG ((REDFISH_HTTP_CACHE_DEBUG, "%a: Basic authorization:
> %a\n", __func__, EncodedAuthString));
> > +      } else {
> > +        DEBUG ((DEBUG_ERROR, "%a: Base64Encode failure: %r\n", __func__,
> Status));
> > +        goto ON_RELEASE;
> > +      }
> > +    }
> > +  }
> > +
> > +  NewService = CreateRedfishService (Host, AsciiLocation, EncodedAuthString,
> NULL, RestEx);
> > +  if (NewService == NULL) {
> > +    DEBUG ((DEBUG_ERROR, "%a: CreateRedfishService\n", __func__));
> > +  }
> > +
> > +ON_RELEASE:
> > +
> > +  if (BasicAuthString != NULL) {
> > +    ZeroMem (BasicAuthString, BasicAuthStrSize);
> > +    FreePool (BasicAuthString);
> > +  }
> > +
> > +  if (EncodedAuthString != NULL) {
> > +    ZeroMem (BasicAuthString, EncodedAuthStrSize);
> > +    FreePool (EncodedAuthString);
> > +  }
> > +
> > +  if (Username != NULL) {
> > +    ZeroMem (Username, UsernameSize);
> > +    FreePool (Username);
> > +  }
> > +
> > +  if (Password != NULL) {
> > +    ZeroMem (Password, PasswordSize);
> > +    FreePool (Password);
> > +  }
> > +
> > +  if (AsciiLocation != NULL) {
> > +    FreePool (AsciiLocation);
> > +  }
> > +
> > +  if (Host != NULL) {
> > +    FreePool (Host);
> > +  }
> > +
> > +  return NewService;
> > +}
> > +
> > +/**
> > +  This function free resources in Redfish service. RedfishService is no longer
> available
> > +  after this function returns successfully.
> > +
> > +  @param[in]  This            Pointer to EDKII_REDFISH_HTTP_PROTOCOL
> instance.
> > +  @param[in]  RedfishService  Pointer to Redfish service to be released.
> > +
> > +  @retval     EFI_SUCCESS     Resrouce is released successfully.
> > +  @retval     Others          Errors occur.
> > +
> > +**/
> > +EFI_STATUS
> > +EFIAPI
> > +RedfishFreeRedfishService (
> > +  IN  EDKII_REDFISH_HTTP_PROTOCOL  *This,
> > +  IN  REDFISH_SERVICE              RedfishService
> > +  )
> > +{
> > +  REDFISH_SERVICE_PRIVATE  *Service;
> > +
> > +  if ((This == NULL) || (RedfishService == NULL)) {
> > +    return EFI_INVALID_PARAMETER;
> > +  }
> > +
> > +  Service = (REDFISH_SERVICE_PRIVATE *)RedfishService;
> > +  if (Service->Signature != REDFISH_HTTP_SERVICE_SIGNATURE) {
> > +    DEBUG ((DEBUG_ERROR, "%a: signature check failure\n", __func__));
> > +  }
> > +
> > +  return ReleaseRedfishService (Service);
> > +}
> > +
> > +/**
> > +  This function returns JSON value in given RedfishPayload. Returned JSON
> value
> > +  is a reference to the JSON value in RedfishPayload. Any modification to
> returned
> > +  JSON value will change JSON value in RedfishPayload.
> > +
> > +  @param[in]  This            Pointer to EDKII_REDFISH_HTTP_PROTOCOL
> instance.
> > +  @param[in]  RedfishPayload  Pointer to Redfish payload.
> > +
> > +  @retval     EDKII_JSON_VALUE   JSON value is returned.
> > +  @retval     NULL               Errors occur.
> > +
> > +**/
> > +EDKII_JSON_VALUE
> > +EFIAPI
> > +RedfishJsonInRedfishPayload (
> > +  IN  EDKII_REDFISH_HTTP_PROTOCOL  *This,
> > +  IN  REDFISH_PAYLOAD              RedfishPayload
> > +  )
> > +{
> > +  REDFISH_PAYLOAD_PRIVATE  *Payload;
> > +
> > +  if ((This == NULL) || (RedfishPayload == NULL)) {
> > +    return NULL;
> > +  }
> > +
> > +  Payload = (REDFISH_PAYLOAD_PRIVATE *)RedfishPayload;
> > +  if (Payload->Signature != REDFISH_HTTP_PAYLOAD_SIGNATURE) {
> > +    DEBUG ((DEBUG_ERROR, "%a: signature check failure\n", __func__));
> > +  }
> > +
> > +  return Payload->JsonValue;
> > +}
> > +
> > +/**
> > +  Perform HTTP GET to Get redfish resource from given resource URI with
> > +  cache mechanism supported. It's caller's responsibility to free Response
> > +  by calling FreeResponse ().
> > +
> > +  @param[in]  This          Pointer to EDKII_REDFISH_HTTP_PROTOCOL instance.
> > +  @param[in]  Service       Redfish service instance to perform HTTP GET.
> > +  @param[in]  Uri           Target resource URI.
> > +  @param[in]  Request       Additional request context. This is optional.
> > +  @param[out] Response      HTTP response from redfish service.
> > +  @param[in]  UseCache      If it is TRUE, this function will search for
> > +                            cache first. If it is FALSE, this function
> > +                            will query Redfish URI directly.
> > +
> > +  @retval     EFI_SUCCESS     Resrouce is returned successfully.
> > +  @retval     Others          Errors occur.
> > +
> > +**/
> > +EFI_STATUS
> > +EFIAPI
> > +RedfishGetResource (
> > +  IN  EDKII_REDFISH_HTTP_PROTOCOL  *This,
> > +  IN  REDFISH_SERVICE              Service,
> > +  IN  EFI_STRING                   Uri,
> > +  IN  REDFISH_REQUEST              *Request OPTIONAL,
> > +  OUT REDFISH_RESPONSE             *Response,
> > +  IN  BOOLEAN                      UseCache
> > +  )
> > +{
> > +  EFI_STATUS                  Status;
> > +  REDFISH_HTTP_CACHE_DATA     *CacheData;
> > +  UINTN                       RetryCount;
> > +  REDFISH_HTTP_CACHE_PRIVATE  *Private;
> > +
> > +  if ((This == NULL) || (Service == NULL) || (Response == NULL) ||
> IS_EMPTY_STRING (Uri)) {
> > +    return EFI_INVALID_PARAMETER;
> > +  }
> > +
> > +  DEBUG ((REDFISH_HTTP_CACHE_DEBUG, "%a: Get URI: %s cache: %a\n",
> __func__, Uri, (UseCache ? "true" : "false")));
> > +
> > +  Private    = REDFISH_HTTP_CACHE_PRIVATE_FROM_THIS (This);
> > +  CacheData  = NULL;
> > +  RetryCount = 0;
> > +  ZeroMem (Response, sizeof (REDFISH_RESPONSE));
> > +
> > +  if (Private->CacheDisabled) {
> > +    UseCache = FALSE;
> > +    DEBUG ((REDFISH_HTTP_CACHE_DEBUG, "%a: cache is disabled by
> PCD!\n", __func__));
> > +  }
> > +
> > +  //
> > +  // Search for cache list.
> > +  //
> > +  if (UseCache) {
> > +    CacheData = FindHttpCacheData (&Private->CacheList.Head, Uri);
> > +    if (CacheData != NULL) {
> > +      DEBUG ((REDFISH_HTTP_CACHE_DEBUG_REQUEST, "%a: cache hit! %s\n",
> __func__, Uri));
> > +
> > +      //
> > +      // Copy cached response to caller's buffer.
> > +      //
> > +      Status               = CopyRedfishResponse (CacheData->Response, Response);
> > +      CacheData->HitCount += 1;
> > +      return Status;
> > +    }
> > +  }
> > +
> > +  //
> > +  // Get resource from redfish service.
> > +  //
> > +  do {
> > +    RetryCount += 1;
> > +    Status      = HttpSendReceive (
> > +                    Service,
> > +                    Uri,
> > +                    HttpMethodGet,
> > +                    Request,
> > +                    Response
> > +                    );
> > +    DEBUG ((REDFISH_HTTP_CACHE_DEBUG_REQUEST, "%a: HTTP request:
> %s :%r\n", __func__, Uri, Status));
> > +    if (!EFI_ERROR (Status) || (RetryCount >= Private-
> >RetrySetting.MaximumRetryGet)) {
> > +      break;
> > +    }
> > +
> > +    //
> > +    // Retry when BMC is not ready.
> > +    //
> > +    if ((Response->StatusCode != NULL)) {
> > +      DEBUG_CODE (
> > +        DumpRedfishResponse (NULL, DEBUG_ERROR, Response);
> > +        );
> > +
> > +      if (!RedfishRetryRequired (Response->StatusCode)) {
> > +        break;
> > +      }
> > +
> > +      //
> > +      // Release response for next round of request.
> > +      //
> > +      This->FreeResponse (This, Response);
> > +    }
> > +
> > +    DEBUG ((DEBUG_WARN, "%a: RedfishGetByUriEx failed, retry (%d/%d)\n",
> __func__, RetryCount, Private->RetrySetting.MaximumRetryGet));
> > +    if (Private->RetrySetting.RetryWait > 0) {
> > +      gBS->Stall (Private->RetrySetting.RetryWait);
> > +    }
> > +  } while (TRUE);
> > +
> > +  if (EFI_ERROR (Status)) {
> > +    DEBUG_CODE (
> > +      DumpRedfishResponse (NULL, DEBUG_ERROR, Response);
> > +      );
> > +    //
> > +    // Report status code for Redfish failure
> > +    //
> > +    ReportHttpError (HttpMethodGet, Uri, Response->StatusCode);
> > +    DEBUG ((DEBUG_ERROR, "%a: get %s failed (%d/%d): %r\n", __func__, Uri,
> RetryCount, Private->RetrySetting.MaximumRetryGet, Status));
> > +    goto ON_RELEASE;
> > +  }
> > +
> > +  if (!Private->CacheDisabled) {
> > +    //
> > +    // Keep response in cache list
> > +    //
> > +    Status = AddHttpCacheData (&Private->CacheList, Uri, Response);
> > +    if (EFI_ERROR (Status)) {
> > +      DEBUG ((DEBUG_ERROR, "%a: failed to cache %s: %r\n", __func__, Uri,
> Status));
> > +      goto ON_RELEASE;
> > +    }
> > +
> > +    DEBUG_CODE (
> > +      DebugPrintHttpCacheList (__func__,
> REDFISH_HTTP_CACHE_DEBUG_DUMP, &Private->CacheList);
> > +      );
> > +  }
> > +
> > +ON_RELEASE:
> > +
> > +  return Status;
> > +}
> > +
> > +/**
> > +  This function free resources in Request. Request is no longer available
> > +  after this function returns successfully.
> > +
> > +  @param[in]  This         Pointer to EDKII_REDFISH_HTTP_PROTOCOL instance.
> > +  @param[in]  Request      HTTP request to be released.
> > +
> > +  @retval     EFI_SUCCESS     Resrouce is released successfully.
> > +  @retval     Others          Errors occur.
> > +
> > +**/
> > +EFI_STATUS
> > +EFIAPI
> > +RedfishFreeRequest (
> > +  IN  EDKII_REDFISH_HTTP_PROTOCOL  *This,
> > +  IN  REDFISH_REQUEST              *Request
> > +  )
> > +{
> > +  if ((This == NULL) || (Request == NULL)) {
> > +    return EFI_INVALID_PARAMETER;
> > +  }
> > +
> > +  DEBUG ((REDFISH_HTTP_CACHE_DEBUG, "%a: entry\n", __func__));
> > +
> > +  return ReleaseRedfishRequest (Request);
> > +}
> > +
> > +/**
> > +  This function free resources in given Response.
> > +
> > +  @param[in]  This         Pointer to EDKII_REDFISH_HTTP_PROTOCOL instance.
> > +  @param[in]  Response     HTTP response to be released.
> > +
> > +  @retval     EFI_SUCCESS     Resrouce is released successfully.
> > +  @retval     Others          Errors occur.
> > +
> > +**/
> > +EFI_STATUS
> > +EFIAPI
> > +RedfishFreeResponse (
> > +  IN  EDKII_REDFISH_HTTP_PROTOCOL  *This,
> > +  IN  REDFISH_RESPONSE             *Response
> > +  )
> > +{
> > +  if ((This == NULL) || (Response == NULL)) {
> > +    return EFI_INVALID_PARAMETER;
> > +  }
> > +
> > +  DEBUG ((REDFISH_HTTP_CACHE_DEBUG, "%a: entry\n", __func__));
> > +
> > +  return ReleaseRedfishResponse (Response);
> > +}
> > +
> > +/**
> > +  This function expire the cached response of given URI.
> > +
> > +  @param[in]  This         Pointer to EDKII_REDFISH_HTTP_PROTOCOL instance.
> > +  @param[in]  Uri          Target response of URI.
> > +
> > +  @retval     EFI_SUCCESS     Target response is expired successfully.
> > +  @retval     Others          Errors occur.
> > +
> > +**/
> > +EFI_STATUS
> > +EFIAPI
> > +RedfishExpireResponse (
> > +  IN  EDKII_REDFISH_HTTP_PROTOCOL  *This,
> > +  IN  EFI_STRING                   Uri
> > +  )
> > +{
> > +  REDFISH_HTTP_CACHE_PRIVATE  *Private;
> > +  REDFISH_HTTP_CACHE_DATA     *CacheData;
> > +
> > +  if ((This == NULL) || IS_EMPTY_STRING (Uri)) {
> > +    return EFI_INVALID_PARAMETER;
> > +  }
> > +
> > +  DEBUG ((REDFISH_HTTP_CACHE_DEBUG, "%a: expire URI: %s\n", __func__,
> Uri));
> > +
> > +  Private = REDFISH_HTTP_CACHE_PRIVATE_FROM_THIS (This);
> > +
> > +  CacheData = FindHttpCacheData (&Private->CacheList.Head, Uri);
> > +  if (CacheData == NULL) {
> > +    return EFI_NOT_FOUND;
> > +  }
> > +
> > +  return DeleteHttpCacheData (&Private->CacheList, CacheData);
> > +}
> > +
> > +/**
> > +  Perform HTTP PATCH to send redfish resource to given resource URI.
> > +  It's caller's responsibility to free Response by calling FreeResponse ().
> > +
> > +  @param[in]  This          Pointer to EDKII_REDFISH_HTTP_PROTOCOL instance.
> > +  @param[in]  Service       Redfish service instance to perform HTTP PATCH.
> > +  @param[in]  Uri           Target resource URI.
> > +  @param[in]  Content       Data to patch.
> > +  @param[in]  ContentSize   Size of the Content to be send to Redfish service.
> > +                            This is optional. When ContentSize is 0, ContentSize
> > +                            is the size of Content.
> > +  @param[in]  ContentType   Type of the Content to be send to Redfish service.
> > +                            This is optional. When ContentType is NULL, content
> > +                            type HTTP_CONTENT_TYPE_APP_JSON will be used.
> > +  @param[out] Response      HTTP response from redfish service.
> > +
> > +  @retval     EFI_SUCCESS     Resrouce is returned successfully.
> > +  @retval     Others          Errors occur.
> > +
> > +**/
> > +EFI_STATUS
> > +EFIAPI
> > +RedfishPatchResource (
> > +  IN  EDKII_REDFISH_HTTP_PROTOCOL  *This,
> > +  IN  REDFISH_SERVICE              Service,
> > +  IN  EFI_STRING                   Uri,
> > +  IN  CHAR8                        *Content,
> > +  IN  UINTN                        ContentSize OPTIONAL,
> > +  IN  CHAR8                        *ContentType OPTIONAL,
> > +  OUT REDFISH_RESPONSE             *Response
> > +  )
> > +{
> > +  EFI_STATUS                  Status;
> > +  UINTN                       RetryCount;
> > +  REDFISH_REQUEST             Request;
> > +  REDFISH_HTTP_CACHE_PRIVATE  *Private;
> > +
> > +  if ((This == NULL) || (Service == NULL) || (Response == NULL) ||
> IS_EMPTY_STRING (Uri) || IS_EMPTY_STRING (Content)) {
> > +    return EFI_INVALID_PARAMETER;
> > +  }
> > +
> > +  DEBUG ((REDFISH_HTTP_CACHE_DEBUG, "%a: Patch URI: %s\n", __func__,
> Uri));
> > +
> > +  Private    = REDFISH_HTTP_CACHE_PRIVATE_FROM_THIS (This);
> > +  RetryCount = 0;
> > +  ZeroMem (Response, sizeof (REDFISH_RESPONSE));
> > +  ZeroMem (&Request, sizeof (REDFISH_REQUEST));
> > +
> > +  Request.Content       = Content;
> > +  Request.ContentLength = ContentSize;
> > +  Request.ContentType   = ContentType;
> > +
> > +  //
> > +  // Patch resource to redfish service.
> > +  //
> > +  do {
> > +    RetryCount += 1;
> > +    Status      = HttpSendReceive (
> > +                    Service,
> > +                    Uri,
> > +                    HttpMethodPatch,
> > +                    &Request,
> > +                    Response
> > +                    );
> > +    DEBUG ((REDFISH_HTTP_CACHE_DEBUG_REQUEST, "%a: HTTP request:
> %s :%r\n", __func__, Uri, Status));
> > +    if (!EFI_ERROR (Status) || (RetryCount >= Private-
> >RetrySetting.MaximumRetryPatch)) {
> > +      break;
> > +    }
> > +
> > +    //
> > +    // Retry when BMC is not ready.
> > +    //
> > +    if ((Response->StatusCode != NULL)) {
> > +      DEBUG_CODE (
> > +        DumpRedfishResponse (NULL, DEBUG_ERROR, Response);
> > +        );
> > +
> > +      if (!RedfishRetryRequired (Response->StatusCode)) {
> > +        break;
> > +      }
> > +
> > +      //
> > +      // Release response for next round of request.
> > +      //
> > +      This->FreeResponse (This, Response);
> > +    }
> > +
> > +    DEBUG ((DEBUG_WARN, "%a: RedfishPatchToUriEx failed, retry (%d/%d)\n",
> __func__, RetryCount, Private->RetrySetting.MaximumRetryPatch));
> > +    if (Private->RetrySetting.RetryWait > 0) {
> > +      gBS->Stall (Private->RetrySetting.RetryWait);
> > +    }
> > +  } while (TRUE);
> > +
> > +  //
> > +  // Redfish resource is updated. Automatically expire the cached response
> > +  // so application can directly get resource from Redfish service again.
> > +  //
> > +  DEBUG ((REDFISH_HTTP_CACHE_DEBUG, "%a: Resource is updated, expire
> URI: %s\n", __func__, Uri));
> > +  RedfishExpireResponse (This, Uri);
> > +
> > +  if (EFI_ERROR (Status)) {
> > +    DEBUG_CODE (
> > +      DumpRedfishResponse (NULL, DEBUG_ERROR, Response);
> > +      );
> > +    //
> > +    // Report status code for Redfish failure
> > +    //
> > +    ReportHttpError (HttpMethodPatch, Uri, Response->StatusCode);
> > +    DEBUG ((DEBUG_ERROR, "%a: patch %s failed (%d/%d): %r\n", __func__,
> Uri, RetryCount, Private->RetrySetting.MaximumRetryPatch, Status));
> > +    goto ON_RELEASE;
> > +  }
> > +
> > +ON_RELEASE:
> > +
> > +  return Status;
> > +}
> > +
> > +/**
> > +  Perform HTTP PUT to send redfish resource to given resource URI.
> > +  It's caller's responsibility to free Response by calling FreeResponse ().
> > +
> > +  @param[in]  This          Pointer to EDKII_REDFISH_HTTP_PROTOCOL instance.
> > +  @param[in]  Service       Redfish service instance to perform HTTP PUT.
> > +  @param[in]  Uri           Target resource URI.
> > +  @param[in]  Content       Data to put.
> > +  @param[in]  ContentSize   Size of the Content to be send to Redfish service.
> > +                            This is optional. When ContentSize is 0, ContentSize
> > +                            is the size of Content.
> > +  @param[in]  ContentType   Type of the Content to be send to Redfish service.
> > +                            This is optional. When ContentType is NULL, content
> > +                            type HTTP_CONTENT_TYPE_APP_JSON will be used.
> > +  @param[out] Response      HTTP response from redfish service.
> > +
> > +  @retval     EFI_SUCCESS     Resrouce is returned successfully.
> > +  @retval     Others          Errors occur.
> > +
> > +**/
> > +EFI_STATUS
> > +EFIAPI
> > +RedfishPutResource (
> > +  IN  EDKII_REDFISH_HTTP_PROTOCOL  *This,
> > +  IN  REDFISH_SERVICE              Service,
> > +  IN  EFI_STRING                   Uri,
> > +  IN  CHAR8                        *Content,
> > +  IN  UINTN                        ContentSize OPTIONAL,
> > +  IN  CHAR8                        *ContentType OPTIONAL,
> > +  OUT REDFISH_RESPONSE             *Response
> > +  )
> > +{
> > +  EFI_STATUS                  Status;
> > +  UINTN                       RetryCount;
> > +  REDFISH_REQUEST             Request;
> > +  REDFISH_HTTP_CACHE_PRIVATE  *Private;
> > +
> > +  if ((This == NULL) || (Service == NULL) || (Response == NULL) ||
> IS_EMPTY_STRING (Uri) || IS_EMPTY_STRING (Content)) {
> > +    return EFI_INVALID_PARAMETER;
> > +  }
> > +
> > +  DEBUG ((REDFISH_HTTP_CACHE_DEBUG, "%a: Put URI: %s\n", __func__,
> Uri));
> > +
> > +  Private    = REDFISH_HTTP_CACHE_PRIVATE_FROM_THIS (This);
> > +  RetryCount = 0;
> > +  ZeroMem (Response, sizeof (REDFISH_RESPONSE));
> > +  ZeroMem (&Request, sizeof (REDFISH_REQUEST));
> > +
> > +  Request.Content       = Content;
> > +  Request.ContentLength = ContentSize;
> > +  Request.ContentType   = ContentType;
> > +
> > +  //
> > +  // Patch resource to redfish service.
> > +  //
> > +  do {
> > +    RetryCount += 1;
> > +    Status      = HttpSendReceive (
> > +                    Service,
> > +                    Uri,
> > +                    HttpMethodPut,
> > +                    &Request,
> > +                    Response
> > +                    );
> > +    DEBUG ((REDFISH_HTTP_CACHE_DEBUG_REQUEST, "%a: HTTP request:
> %s :%r\n", __func__, Uri, Status));
> > +    if (!EFI_ERROR (Status) || (RetryCount >= Private-
> >RetrySetting.MaximumRetryPut)) {
> > +      break;
> > +    }
> > +
> > +    //
> > +    // Retry when BMC is not ready.
> > +    //
> > +    if ((Response->StatusCode != NULL)) {
> > +      DEBUG_CODE (
> > +        DumpRedfishResponse (NULL, DEBUG_ERROR, Response);
> > +        );
> > +
> > +      if (!RedfishRetryRequired (Response->StatusCode)) {
> > +        break;
> > +      }
> > +
> > +      //
> > +      // Release response for next round of request.
> > +      //
> > +      This->FreeResponse (This, Response);
> > +    }
> > +
> > +    DEBUG ((DEBUG_WARN, "%a: RedfishPutToUri failed, retry (%d/%d)\n",
> __func__, RetryCount, Private->RetrySetting.MaximumRetryPut));
> > +    if (Private->RetrySetting.RetryWait > 0) {
> > +      gBS->Stall (Private->RetrySetting.RetryWait);
> > +    }
> > +  } while (TRUE);
> > +
> > +  //
> > +  // Redfish resource is updated. Automatically expire the cached response
> > +  // so application can directly get resource from Redfish service again.
> > +  //
> > +  DEBUG ((REDFISH_HTTP_CACHE_DEBUG, "%a: Resource is updated, expire
> URI: %s\n", __func__, Uri));
> > +  RedfishExpireResponse (This, Uri);
> > +
> > +  if (EFI_ERROR (Status)) {
> > +    DEBUG_CODE (
> > +      DumpRedfishResponse (NULL, DEBUG_ERROR, Response);
> > +      );
> > +    //
> > +    // Report status code for Redfish failure
> > +    //
> > +    ReportHttpError (HttpMethodPut, Uri, Response->StatusCode);
> > +    DEBUG ((DEBUG_ERROR, "%a: put %s failed (%d/%d): %r\n", __func__, Uri,
> RetryCount, Private->RetrySetting.MaximumRetryPut, Status));
> > +    goto ON_RELEASE;
> > +  }
> > +
> > +ON_RELEASE:
> > +
> > +  return Status;
> > +}
> > +
> > +/**
> > +  Perform HTTP POST to send redfish resource to given resource URI.
> > +  It's caller's responsibility to free Response by calling FreeResponse ().
> > +
> > +  @param[in]  This          Pointer to EDKII_REDFISH_HTTP_PROTOCOL instance.
> > +  @param[in]  Service       Redfish service instance to perform HTTP POST.
> > +  @param[in]  Uri           Target resource URI.
> > +  @param[in]  Content       Data to post.
> > +  @param[in]  ContentSize   Size of the Content to be send to Redfish service.
> > +                            This is optional. When ContentSize is 0, ContentSize
> > +                            is the size of Content.
> > +  @param[in]  ContentType   Type of the Content to be send to Redfish service.
> > +                            This is optional. When ContentType is NULL, content
> > +                            type HTTP_CONTENT_TYPE_APP_JSON will be used.
> > +  @param[out] Response      HTTP response from redfish service.
> > +
> > +  @retval     EFI_SUCCESS     Resrouce is returned successfully.
> > +  @retval     Others          Errors occur.
> > +
> > +**/
> > +EFI_STATUS
> > +EFIAPI
> > +RedfishPostResource (
> > +  IN  EDKII_REDFISH_HTTP_PROTOCOL  *This,
> > +  IN  REDFISH_SERVICE              Service,
> > +  IN  EFI_STRING                   Uri,
> > +  IN  CHAR8                        *Content,
> > +  IN  UINTN                        ContentSize OPTIONAL,
> > +  IN  CHAR8                        *ContentType OPTIONAL,
> > +  OUT REDFISH_RESPONSE             *Response
> > +  )
> > +{
> > +  EFI_STATUS                  Status;
> > +  UINTN                       RetryCount;
> > +  REDFISH_REQUEST             Request;
> > +  REDFISH_HTTP_CACHE_PRIVATE  *Private;
> > +
> > +  if ((This == NULL) || (Service == NULL) || (Response == NULL) ||
> IS_EMPTY_STRING (Uri) || IS_EMPTY_STRING (Content)) {
> > +    return EFI_INVALID_PARAMETER;
> > +  }
> > +
> > +  DEBUG ((REDFISH_HTTP_CACHE_DEBUG, "%a: Post URI: %s\n", __func__,
> Uri));
> > +
> > +  Private    = REDFISH_HTTP_CACHE_PRIVATE_FROM_THIS (This);
> > +  RetryCount = 0;
> > +  ZeroMem (Response, sizeof (REDFISH_RESPONSE));
> > +  ZeroMem (&Request, sizeof (REDFISH_REQUEST));
> > +
> > +  Request.Content       = Content;
> > +  Request.ContentLength = ContentSize;
> > +  Request.ContentType   = ContentType;
> > +
> > +  //
> > +  // Patch resource to redfish service.
> > +  //
> > +  do {
> > +    RetryCount += 1;
> > +    Status      = HttpSendReceive (
> > +                    Service,
> > +                    Uri,
> > +                    HttpMethodPost,
> > +                    &Request,
> > +                    Response
> > +                    );
> > +    DEBUG ((REDFISH_HTTP_CACHE_DEBUG_REQUEST, "%a: HTTP request:
> %s :%r\n", __func__, Uri, Status));
> > +    if (!EFI_ERROR (Status) || (RetryCount >= Private-
> >RetrySetting.MaximumRetryPost)) {
> > +      break;
> > +    }
> > +
> > +    //
> > +    // Retry when BMC is not ready.
> > +    //
> > +    if ((Response->StatusCode != NULL)) {
> > +      DEBUG_CODE (
> > +        DumpRedfishResponse (NULL, DEBUG_ERROR, Response);
> > +        );
> > +
> > +      if (!RedfishRetryRequired (Response->StatusCode)) {
> > +        break;
> > +      }
> > +
> > +      //
> > +      // Release response for next round of request.
> > +      //
> > +      This->FreeResponse (This, Response);
> > +    }
> > +
> > +    DEBUG ((DEBUG_WARN, "%a: RedfishPostToUri failed, retry (%d/%d)\n",
> __func__, RetryCount, Private->RetrySetting.MaximumRetryPost));
> > +    if (Private->RetrySetting.RetryWait > 0) {
> > +      gBS->Stall (Private->RetrySetting.RetryWait);
> > +    }
> > +  } while (TRUE);
> > +
> > +  //
> > +  // Redfish resource is updated. Automatically expire the cached response
> > +  // so application can directly get resource from Redfish service again.
> > +  //
> > +  DEBUG ((REDFISH_HTTP_CACHE_DEBUG, "%a: Resource is updated, expire
> URI: %s\n", __func__, Uri));
> > +  RedfishExpireResponse (This, Uri);
> > +
> > +  if (EFI_ERROR (Status)) {
> > +    DEBUG_CODE (
> > +      DumpRedfishResponse (NULL, DEBUG_ERROR, Response);
> > +      );
> > +    //
> > +    // Report status code for Redfish failure
> > +    //
> > +    ReportHttpError (HttpMethodPost, Uri, Response->StatusCode);
> > +    DEBUG ((DEBUG_ERROR, "%a: post %s failed (%d/%d): %r\n", __func__, Uri,
> RetryCount, Private->RetrySetting.MaximumRetryPost, Status));
> > +    goto ON_RELEASE;
> > +  }
> > +
> > +ON_RELEASE:
> > +
> > +  return Status;
> > +}
> > +
> > +/**
> > +  Perform HTTP DELETE to delete redfish resource on given resource URI.
> > +  It's caller's responsibility to free Response by calling FreeResponse ().
> > +
> > +  @param[in]  This          Pointer to EDKII_REDFISH_HTTP_PROTOCOL instance.
> > +  @param[in]  Service       Redfish service instance to perform HTTP DELETE.
> > +  @param[in]  Uri           Target resource URI.
> > +  @param[in]  Content       JSON represented properties to be deleted. This is
> > +                            optional.
> > +  @param[in]  ContentSize   Size of the Content to be send to Redfish service.
> > +                            This is optional. When ContentSize is 0, ContentSize
> > +                            is the size of Content if Content is not NULL.
> > +  @param[in]  ContentType   Type of the Content to be send to Redfish service.
> > +                            This is optional. When Content is not NULL and
> > +                            ContentType is NULL, content type
> HTTP_CONTENT_TYPE_APP_JSON
> > +                            will be used.
> > +  @param[out] Response      HTTP response from redfish service.
> > +
> > +  @retval     EFI_SUCCESS     Resrouce is returned successfully.
> > +  @retval     Others          Errors occur.
> > +
> > +**/
> > +EFI_STATUS
> > +EFIAPI
> > +RedfishDeleteResource (
> > +  IN  EDKII_REDFISH_HTTP_PROTOCOL  *This,
> > +  IN  REDFISH_SERVICE              Service,
> > +  IN  EFI_STRING                   Uri,
> > +  IN  CHAR8                        *Content OPTIONAL,
> > +  IN  UINTN                        ContentSize OPTIONAL,
> > +  IN  CHAR8                        *ContentType OPTIONAL,
> > +  OUT REDFISH_RESPONSE             *Response
> > +  )
> > +{
> > +  EFI_STATUS                  Status;
> > +  UINTN                       RetryCount;
> > +  REDFISH_REQUEST             Request;
> > +  REDFISH_HTTP_CACHE_PRIVATE  *Private;
> > +
> > +  if ((This == NULL) || (Service == NULL) || (Response == NULL) ||
> IS_EMPTY_STRING (Uri)) {
> > +    return EFI_INVALID_PARAMETER;
> > +  }
> > +
> > +  DEBUG ((REDFISH_HTTP_CACHE_DEBUG, "%a: Delete URI: %s\n", __func__,
> Uri));
> > +
> > +  Private    = REDFISH_HTTP_CACHE_PRIVATE_FROM_THIS (This);
> > +  RetryCount = 0;
> > +  ZeroMem (Response, sizeof (REDFISH_RESPONSE));
> > +  ZeroMem (&Request, sizeof (REDFISH_REQUEST));
> > +
> > +  Request.Content       = Content;
> > +  Request.ContentLength = ContentSize;
> > +  Request.ContentType   = ContentType;
> > +
> > +  //
> > +  // Patch resource to redfish service.
> > +  //
> > +  do {
> > +    RetryCount += 1;
> > +    Status      = HttpSendReceive (
> > +                    Service,
> > +                    Uri,
> > +                    HttpMethodDelete,
> > +                    &Request,
> > +                    Response
> > +                    );
> > +    DEBUG ((REDFISH_HTTP_CACHE_DEBUG_REQUEST, "%a: HTTP request:
> %s :%r\n", __func__, Uri, Status));
> > +    if (!EFI_ERROR (Status) || (RetryCount >= Private-
> >RetrySetting.MaximumRetryDelete)) {
> > +      break;
> > +    }
> > +
> > +    //
> > +    // Retry when BMC is not ready.
> > +    //
> > +    if ((Response->StatusCode != NULL)) {
> > +      DEBUG_CODE (
> > +        DumpRedfishResponse (NULL, DEBUG_ERROR, Response);
> > +        );
> > +
> > +      if (!RedfishRetryRequired (Response->StatusCode)) {
> > +        break;
> > +      }
> > +
> > +      //
> > +      // Release response for next round of request.
> > +      //
> > +      This->FreeResponse (This, Response);
> > +    }
> > +
> > +    DEBUG ((DEBUG_WARN, "%a: RedfishDeleteByUri failed, retry (%d/%d)\n",
> __func__, RetryCount, Private->RetrySetting.MaximumRetryDelete));
> > +    if (Private->RetrySetting.RetryWait > 0) {
> > +      gBS->Stall (Private->RetrySetting.RetryWait);
> > +    }
> > +  } while (TRUE);
> > +
> > +  //
> > +  // Redfish resource is updated. Automatically expire the cached response
> > +  // so application can directly get resource from Redfish service again.
> > +  //
> > +  DEBUG ((REDFISH_HTTP_CACHE_DEBUG, "%a: Resource is updated, expire
> URI: %s\n", __func__, Uri));
> > +  RedfishExpireResponse (This, Uri);
> > +
> > +  if (EFI_ERROR (Status)) {
> > +    DEBUG_CODE (
> > +      DumpRedfishResponse (NULL, DEBUG_ERROR, Response);
> > +      );
> > +    //
> > +    // Report status code for Redfish failure
> > +    //
> > +    ReportHttpError (HttpMethodDelete, Uri, Response->StatusCode);
> > +    DEBUG ((DEBUG_ERROR, "%a: delete %s failed (%d/%d): %r\n", __func__,
> Uri, RetryCount, Private->RetrySetting.MaximumRetryDelete, Status));
> > +    goto ON_RELEASE;
> > +  }
> > +
> > +ON_RELEASE:
> > +
> > +  return Status;
> > +}
> > +
> > +EDKII_REDFISH_HTTP_PROTOCOL  mEdkIIRedfishHttpProtocol = {
> > +  EDKII_REDFISH_HTTP_PROTOCOL_REVISION,
> > +  RedfishCreateRedfishService,
> > +  RedfishFreeRedfishService,
> > +  RedfishJsonInRedfishPayload,
> > +  RedfishGetResource,
> > +  RedfishPatchResource,
> > +  RedfishPutResource,
> > +  RedfishPostResource,
> > +  RedfishDeleteResource,
> > +  RedfishFreeRequest,
> > +  RedfishFreeResponse,
> > +  RedfishExpireResponse
> > +};
> > +
> > +/**
> > +  Unloads an image.
> > +
> > +  @param[in]  ImageHandle         Handle that identifies the image to be
> unloaded.
> > +
> > +  @retval EFI_SUCCESS             The image has been unloaded.
> > +  @retval EFI_INVALID_PARAMETER   ImageHandle is not a valid image
> handle.
> > +
> > +**/
> > +EFI_STATUS
> > +EFIAPI
> > +RedfishHttpDriverUnload (
> > +  IN EFI_HANDLE  ImageHandle
> > +  )
> > +{
> > +  if (mRedfishHttpCachePrivate == NULL) {
> > +    return EFI_SUCCESS;
> > +  }
> > +
> > +  if (!IsListEmpty (&mRedfishHttpCachePrivate->CacheList.Head)) {
> > +    ReleaseCacheList (&mRedfishHttpCachePrivate->CacheList);
> > +  }
> > +
> > +  gBS->UninstallMultipleProtocolInterfaces (
> > +         ImageHandle,
> > +         &gEdkIIRedfishHttpProtocolGuid,
> > +         &mRedfishHttpCachePrivate->Protocol,
> > +         NULL
> > +         );
> > +
> > +  FreePool (mRedfishHttpCachePrivate);
> > +  mRedfishHttpCachePrivate = NULL;
> > +
> > +  return EFI_SUCCESS;
> > +}
> > +
> > +/**
> > +  This is a EDKII_REDFISH_CREDENTIAL_PROTOCOL notification event handler.
> > +
> > +  @param[in] Event    Event whose notification function is being invoked.
> > +  @param[in] Context  Pointer to the notification function's context.
> > +
> > +**/
> > +VOID
> > +EFIAPI
> > +CredentialProtocolInstalled (
> > +  IN  EFI_EVENT  Event,
> > +  IN  VOID       *Context
> > +  )
> > +{
> > +  EFI_STATUS                  Status;
> > +  REDFISH_HTTP_CACHE_PRIVATE  *Private;
> > +
> > +  Private = (REDFISH_HTTP_CACHE_PRIVATE *)Context;
> > +  if (Private->Signature != REDFISH_HTTP_DRIVER_SIGNATURE) {
> > +    DEBUG ((DEBUG_ERROR, "%a: signature check failure\n", __func__));
> > +    return;
> > +  }
> > +
> > +  //
> > +  // Locate HII database protocol.
> > +  //
> > +  Status = gBS->LocateProtocol (
> > +                  &gEdkIIRedfishCredentialProtocolGuid,
> > +                  NULL,
> > +                  (VOID **)&Private->CredentialProtocol
> > +                  );
> > +  if (EFI_ERROR (Status)) {
> > +    return;
> > +  }
> > +
> > +  gBS->CloseEvent (Event);
> > +}
> > +
> > +/**
> > +  Main entry for this driver.
> > +
> > +  @param[in] ImageHandle     Image handle this driver.
> > +  @param[in] SystemTable     Pointer to SystemTable.
> > +
> > +  @retval EFI_SUCCESS     This function always complete successfully.
> > +
> > +**/
> > +EFI_STATUS
> > +EFIAPI
> > +RedfishHttpEntryPoint (
> > +  IN EFI_HANDLE        ImageHandle,
> > +  IN EFI_SYSTEM_TABLE  *SystemTable
> > +  )
> > +{
> > +  EFI_STATUS  Status;
> > +  VOID        *Registration;
> > +
> > +  if (mRedfishHttpCachePrivate != NULL) {
> > +    return EFI_ALREADY_STARTED;
> > +  }
> > +
> > +  mRedfishHttpCachePrivate = AllocateZeroPool (sizeof
> (REDFISH_HTTP_CACHE_PRIVATE));
> > +  if (mRedfishHttpCachePrivate == NULL) {
> > +    return EFI_OUT_OF_RESOURCES;
> > +  }
> > +
> > +  //
> > +  // Initial cache list and protocol instance.
> > +  //
> > +  mRedfishHttpCachePrivate->Signature   =
> REDFISH_HTTP_DRIVER_SIGNATURE;
> > +  mRedfishHttpCachePrivate->ImageHandle = ImageHandle;
> > +  CopyMem (&mRedfishHttpCachePrivate->Protocol,
> &mEdkIIRedfishHttpProtocol, sizeof (EDKII_REDFISH_HTTP_PROTOCOL));
> > +  mRedfishHttpCachePrivate->CacheList.Capacity =
> REDFISH_HTTP_CACHE_LIST_SIZE;
> > +  mRedfishHttpCachePrivate->CacheList.Count    = 0x00;
> > +  mRedfishHttpCachePrivate->CacheDisabled      = PcdGetBool
> (PcdHttpCacheDisabled);
> > +  InitializeListHead (&mRedfishHttpCachePrivate->CacheList.Head);
> > +
> > +  //
> > +  // Get retry settings
> > +  //
> > +  mRedfishHttpCachePrivate->RetrySetting.MaximumRetryGet    = PcdGet16
> (PcdHttpGetRetry);
> > +  mRedfishHttpCachePrivate->RetrySetting.MaximumRetryPut    = PcdGet16
> (PcdHttpPutRetry);
> > +  mRedfishHttpCachePrivate->RetrySetting.MaximumRetryPatch  = PcdGet16
> (PcdHttpPatchRetry);
> > +  mRedfishHttpCachePrivate->RetrySetting.MaximumRetryPost   = PcdGet16
> (PcdHttpPostRetry);
> > +  mRedfishHttpCachePrivate->RetrySetting.MaximumRetryDelete = PcdGet16
> (PcdHttpDeleteRetry);
> > +  mRedfishHttpCachePrivate->RetrySetting.RetryWait          = PcdGet16
> (PcdHttpRetryWaitInSecond) * 1000000U;
> > +
> > +  //
> > +  // Install the gEdkIIRedfishHttpProtocolGuid onto Handle.
> > +  //
> > +  Status = gBS->InstallMultipleProtocolInterfaces (
> > +                  &mRedfishHttpCachePrivate->ImageHandle,
> > +                  &gEdkIIRedfishHttpProtocolGuid,
> > +                  &mRedfishHttpCachePrivate->Protocol,
> > +                  NULL
> > +                  );
> > +  if (EFI_ERROR (Status)) {
> > +    DEBUG ((DEBUG_ERROR, "%a: cannot install Redfish http protocol: %r\n",
> __func__, Status));
> > +    RedfishHttpDriverUnload (ImageHandle);
> > +    return Status;
> > +  }
> > +
> > +  //
> > +  // Install protocol notification if credential protocol is installed.
> > +  //
> > +  mRedfishHttpCachePrivate->NotifyEvent = EfiCreateProtocolNotifyEvent (
> > +                                            &gEdkIIRedfishCredentialProtocolGuid,
> > +                                            TPL_CALLBACK,
> > +                                            CredentialProtocolInstalled,
> > +                                            mRedfishHttpCachePrivate,
> > +                                            &Registration
> > +                                            );
> > +  if (mRedfishHttpCachePrivate->NotifyEvent == NULL) {
> > +    DEBUG ((DEBUG_ERROR, "%a: failed to create protocol notification for
> gEdkIIRedfishCredentialProtocolGuid\n", __func__));
> > +    ASSERT (FALSE);
> > +    RedfishHttpDriverUnload (ImageHandle);
> > +    return Status;
> > +  }
> > +
> > +  return EFI_SUCCESS;
> > +}
> > diff --git a/RedfishPkg/RedfishHttpDxe/RedfishHttpOperation.c
> b/RedfishPkg/RedfishHttpDxe/RedfishHttpOperation.c
> > new file mode 100644
> > index 0000000000..5652818d16
> > --- /dev/null
> > +++ b/RedfishPkg/RedfishHttpDxe/RedfishHttpOperation.c
> > @@ -0,0 +1,693 @@
> > +/** @file
> > +  RedfishHttpOperation handles HTTP operations.
> > +
> > +  Copyright (c) 2024, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
> > +
> > +  SPDX-License-Identifier: BSD-2-Clause-Patent
> > +
> > +**/
> > +
> > +#include "RedfishHttpOperation.h"
> > +#include "RedfishHttpData.h"
> > +
> > +/**
> > +  This function copies all headers in SrcHeaders to DstHeaders.
> > +  It's call responsibility to release returned DstHeaders.
> > +
> > +  @param[in]  SrcHeaders      Source headers.
> > +  @param[in]  SrcHeaderCount  Number of header in source headers.
> > +  @param[out] DstHeaders      Destination headers.
> > +  @param[out] DstHeaderCount  Number of header in designation headers.
> > +
> > +  @retval     EFI_SUCCESS     Headers are copied successfully.
> > +  @retval     Others          Errors occur.
> > +
> > +**/
> > +EFI_STATUS
> > +CopyHttpHeaders (
> > +  IN  EFI_HTTP_HEADER  *SrcHeaders,
> > +  IN  UINTN            SrcHeaderCount,
> > +  OUT EFI_HTTP_HEADER  **DstHeaders,
> > +  OUT UINTN            *DstHeaderCount
> > +  )
> > +{
> > +  UINTN  Index;
> > +
> > +  if ((SrcHeaders == NULL) || (SrcHeaderCount == 0) || (DstHeaders == NULL)
> || (DstHeaderCount == NULL)) {
> > +    return EFI_INVALID_PARAMETER;
> > +  }
> > +
> > +  *DstHeaderCount = 0;
> > +  *DstHeaders     = AllocateZeroPool (sizeof (EFI_HTTP_HEADER) *
> SrcHeaderCount);
> > +  if (*DstHeaders == NULL) {
> > +    return EFI_OUT_OF_RESOURCES;
> > +  }
> > +
> > +  for (Index = 0; Index < SrcHeaderCount; Index++) {
> > +    (*DstHeaders)[Index].FieldName = AllocateCopyPool (AsciiStrSize
> (SrcHeaders[Index].FieldName), SrcHeaders[Index].FieldName);
> > +    if ((*DstHeaders)[Index].FieldName == NULL) {
> > +      return EFI_OUT_OF_RESOURCES;
> > +    }
> > +
> > +    (*DstHeaders)[Index].FieldValue = AllocateCopyPool (AsciiStrSize
> (SrcHeaders[Index].FieldValue), SrcHeaders[Index].FieldValue);
> > +    if ((*DstHeaders)[Index].FieldValue == NULL) {
> > +      return EFI_OUT_OF_RESOURCES;
>
>
>
> Looks like orevious allocations leaked.
> Didn't you think to implement smth like this
> https://github.co/
> m%2Ftianocore%2Fedk2%2Fblob%2Fmaster%2FOvmfPkg%2FXenBusDxe%2FHelp
> ers.c%23L4&data=05%7C02%7Cnicklew%40nvidia.com%7Cf659c54c3edb43527c
> 3608dc3462ab2a%7C43083d15727340c1b7db39efd9ccc17a%7C0%7C0%7C6384
> 42845601059719%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLjAwMDAiLCJ
> QIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C0%7C%7C%7C&sdata=oYv
> XkfjOpakMOXV1w6nYVphDRuPM7R73lqr8QVqh%2BI4%3D&reserved=0 ?
>
>
> > +    }
> > +
> > +    *DstHeaderCount += 1;
> > +  }
> > +
> > +  return EFI_SUCCESS;
> > +}
> > +
> > +/**
> > +  This function free resources in Request. Request is no longer available
> > +  after this function returns successfully.
> > +
> > +  @param[in]  Request      HTTP request to be released.
> > +
> > +  @retval     EFI_SUCCESS     Resrouce is released successfully.
> > +  @retval     Others          Errors occur.
> > +
> > +**/
> > +EFI_STATUS
> > +ReleaseRedfishRequest (
> > +  IN  REDFISH_REQUEST  *Request
> > +  )
> > +{
> > +  if (Request == NULL) {
> > +    return EFI_INVALID_PARAMETER;
> > +  }
> > +
> > +  if ((Request->Headers != NULL) && (Request->HeaderCount > 0)) {
> > +    HttpFreeHeaderFields (Request->Headers, Request->HeaderCount);
> > +    Request->Headers     = NULL;
> > +    Request->HeaderCount = 0;
> > +  }
> > +
> > +  if (Request->Content != NULL) {
> > +    FreePool (Request->Content);
> > +    Request->Content = NULL;
> > +  }
> > +
> > +  if (Request->ContentType != NULL) {
> > +    FreePool (Request->ContentType);
> > +    Request->ContentType = NULL;
> > +  }
> > +
> > +  Request->ContentLength = 0;
> > +
> > +  return EFI_SUCCESS;
> > +}
> > +
> > +/**
> > +  This function free resources in given Response.
> > +
> > +  @param[in]  Response     HTTP response to be released.
> > +
> > +  @retval     EFI_SUCCESS     Resrouce is released successfully.
> > +  @retval     Others          Errors occur.
> > +
> > +**/
> > +EFI_STATUS
> > +ReleaseRedfishResponse (
> > +  IN  REDFISH_RESPONSE  *Response
> > +  )
> > +{
> > +  if (Response == NULL) {
> > +    return EFI_INVALID_PARAMETER;
> > +  }
> > +
> > +  if ((Response->Headers != NULL) && (Response->HeaderCount > 0)) {
> > +    HttpFreeHeaderFields (Response->Headers, Response->HeaderCount);
> > +    Response->Headers     = NULL;
> > +    Response->HeaderCount = 0;
> > +  }
> > +
> > +  if (Response->Payload != NULL) {
> > +    ReleaseRedfishPayload (Response->Payload);
> > +    Response->Payload = NULL;
> > +  }
> > +
> > +  if (Response->StatusCode != NULL) {
> > +    FreePool (Response->StatusCode);
> > +    Response->StatusCode = NULL;
> > +  }
> > +
> > +  return EFI_SUCCESS;
> > +}
> > +
> > +/**
> > +  This function free resources in given HTTP message.
> > +
> > +  @param[in]  HttpMessage     HTTP message to be released.
> > +  @param[in]  IsRequest       TRUE if this is request type of HTTP message.
> > +                              FALSE if this is response type of HTTP message.
> > +
> > +  @retval     EFI_SUCCESS     Resrouce is released successfully.
> > +  @retval     Others          Errors occur.
> > +
> > +**/
> > +EFI_STATUS
> > +ReleaseHttpMessage (
> > +  IN  EFI_HTTP_MESSAGE  *HttpMessage,
> > +  IN  BOOLEAN           IsRequest
> > +  )
> > +{
> > +  if (HttpMessage == NULL) {
> > +    return EFI_INVALID_PARAMETER;
> > +  }
> > +
> > +  if (IsRequest) {
> > +    if (HttpMessage->Data.Request != NULL) {
> > +      if (HttpMessage->Data.Request->Url != NULL) {
> > +        FreePool (HttpMessage->Data.Request->Url);
> > +      }
> > +
> > +      FreePool (HttpMessage->Data.Request);
> > +      HttpMessage->Data.Request = NULL;
> > +    }
> > +  } else {
> > +    if (HttpMessage->Data.Response != NULL) {
> > +      FreePool (HttpMessage->Data.Response);
> > +      HttpMessage->Data.Response = NULL;
> > +    }
> > +  }
> > +
> > +  if (HttpMessage->Body != NULL) {
> > +    FreePool (HttpMessage->Body);
> > +    HttpMessage->Body = NULL;
> > +  }
> > +
> > +  if (HttpMessage->Headers != NULL) {
> > +    HttpFreeHeaderFields (HttpMessage->Headers, HttpMessage-
> >HeaderCount);
> > +    HttpMessage->Headers     = NULL;
> > +    HttpMessage->HeaderCount = 0;
> > +  }
> > +
> > +  return EFI_SUCCESS;
> > +}
> > +
> > +/**
> > +  This function build Redfish message for sending data to Redfish service.
> > +  It's call responsibility to properly release returned HTTP message by
> > +  calling ReleaseHttpMessage.
> > +
> > +  @param[in]   ServicePrivate    Pointer to Redfish service private data.
> > +  @param[in]   Uri               Redfish service URI.
> > +  @param[in]   Method            HTTP method.
> > +  @param[in]   Request           Additional data to send to Redfish service.
> > +                                 This is optional.
> > +  @param[in]   ContentEncoding   Content encoding method to compress HTTP
> context.
> > +                                 This is optional. When ContentEncoding is NULL,
> > +                                 No compress method will be performed.
> > +
> > +  @retval     EFI_HTTP_MESSAGE *   Pointer to newly created HTTP message.
> > +  @retval     NULL                 Error occurred.
> > +
> > +**/
> > +EFI_HTTP_MESSAGE *
> > +BuildRequestMessage (
> > +  IN REDFISH_SERVICE_PRIVATE  *ServicePrivate,
> > +  IN EFI_STRING               Uri,
> > +  IN EFI_HTTP_METHOD          Method,
> > +  IN REDFISH_REQUEST          *Request OPTIONAL,
> > +  IN CHAR8                    *ContentEncoding OPTIONAL
> > +  )
> > +{
> > +  EFI_STATUS             Status;
> > +  EFI_STRING             Url;
> > +  UINTN                  UrlSize;
> > +  UINTN                  Index;
> > +  EFI_HTTP_MESSAGE       *RequestMsg;
> > +  EFI_HTTP_REQUEST_DATA  *RequestData;
> > +  UINTN                  HeaderCount;
> > +  UINTN                  HeaderIndex;
> > +  EFI_HTTP_HEADER        *Headers;
> > +  CHAR8                  ContentLengthStr[REDFISH_CONTENT_LENGTH_SIZE];
> > +  VOID                   *Content;
> > +  UINTN                  ContentLength;
> > +  BOOLEAN                HasContent;
> > +  BOOLEAN                DoContentEncoding;
> > +
> > +  RequestMsg        = NULL;
> > +  RequestData       = NULL;
> > +  Url               = NULL;
> > +  UrlSize           = 0;
> > +  Content           = NULL;
> > +  ContentLength     = 0;
> > +  HeaderCount       = REDFISH_COMMON_HEADER_SIZE;
> > +  HeaderIndex       = 0;
> > +  Headers           = NULL;
> > +  HasContent        = FALSE;
> > +  DoContentEncoding = FALSE;
> > +
> > +  if ((ServicePrivate == NULL) || (IS_EMPTY_STRING (Uri))) {
> > +    return NULL;
> > +  }
> > +
> > +  if (Method >= HttpMethodMax) {
> > +    return NULL;
> > +  }
> > +
> > +  DEBUG ((REDFISH_HTTP_CACHE_DEBUG_REQUEST, "%a: %s\n", __func__,
> Uri));
> > +
> > +  //
> > +  // Build full URL for HTTP query.
> > +  //
> > +  UrlSize = (AsciiStrLen (ServicePrivate->Host) + StrLen (Uri) + 1) * sizeof
> (CHAR16);
> > +  Url     = AllocateZeroPool (UrlSize);
> > +  if (Url == NULL) {
> > +    return NULL;
> > +  }
> > +
> > +  UnicodeSPrint (Url, UrlSize, L"%a%s", ServicePrivate->Host, Uri);
> > +  DEBUG ((REDFISH_HTTP_CACHE_DEBUG_REQUEST, "%a: Url: %s\n",
> __func__, Url));
> > +
> > +  //
> > +  // Step 1: build the HTTP headers.
> > +  //
> > +  if (!IS_EMPTY_STRING (ServicePrivate->SessionToken) || !IS_EMPTY_STRING
> (ServicePrivate->BasicAuth)) {
> > +    HeaderCount++;
> > +  }
> > +
> > +  if ((Request != NULL) && (Request->HeaderCount > 0)) {
> > +    HeaderCount += Request->HeaderCount;
> > +  }
> > +
> > +  //
> > +  // Check and see if we will do content encoding or not
> > +  //
> > +  if (!IS_EMPTY_STRING (ContentEncoding)) {
> > +    if (AsciiStrCmp (ContentEncoding,
> REDFISH_HTTP_CONTENT_ENCODING_NONE) != 0) {
> > +      DoContentEncoding = TRUE;
> > +    }
> > +  }
> > +
> > +  if ((Request != NULL) && !IS_EMPTY_STRING (Request->Content)) {
> > +    HeaderCount += 2;
> > +    HasContent   = TRUE;
> > +    if (DoContentEncoding) {
> > +      HeaderCount += 1;
> > +    }
> > +  }
> > +
> > +  Headers = AllocateZeroPool (HeaderCount * sizeof (EFI_HTTP_HEADER));
> > +  if (Headers == NULL) {
> > +    goto ON_ERROR;
> > +  }
> > +
> > +  if (!IS_EMPTY_STRING (ServicePrivate->SessionToken)) {
> > +    Status = HttpSetFieldNameAndValue (&Headers[HeaderIndex++],
> HTTP_HEADER_X_AUTH_TOKEN, ServicePrivate->SessionToken);
> > +    if (EFI_ERROR (Status)) {
> > +      goto ON_ERROR;
> > +    }
> > +  } else if (!IS_EMPTY_STRING (ServicePrivate->BasicAuth)) {
> > +    Status = HttpSetFieldNameAndValue (&Headers[HeaderIndex++],
> HTTP_HEADER_AUTHORIZATION, ServicePrivate->BasicAuth);
> > +    if (EFI_ERROR (Status)) {
> > +      goto ON_ERROR;
> > +    }
> > +  }
> > +
> > +  if (Request != NULL) {
> > +    for (Index = 0; Index < Request->HeaderCount; Index++) {
> > +      Status = HttpSetFieldNameAndValue (&Headers[HeaderIndex++], Request-
> >Headers[Index].FieldName, Request->Headers[Index].FieldValue);
> > +      if (EFI_ERROR (Status)) {
> > +        goto ON_ERROR;
> > +      }
> > +    }
> > +  }
> > +
> > +  Status = HttpSetFieldNameAndValue (&Headers[HeaderIndex++],
> HTTP_HEADER_HOST, ServicePrivate->HostName);
> > +  if (EFI_ERROR (Status)) {
> > +    goto ON_ERROR;
> > +  }
> > +
> > +  Status = HttpSetFieldNameAndValue (&Headers[HeaderIndex++],
> REDFISH_HTTP_HEADER_ODATA_VERSION_STR,
> REDFISH_HTTP_HEADER_ODATA_VERSION_VALUE);
> > +  if (EFI_ERROR (Status)) {
> > +    goto ON_ERROR;
> > +  }
> > +
> > +  Status = HttpSetFieldNameAndValue (&Headers[HeaderIndex++],
> HTTP_HEADER_ACCEPT, HTTP_CONTENT_TYPE_APP_JSON);
> > +  if (EFI_ERROR (Status)) {
> > +    goto ON_ERROR;
> > +  }
> > +
> > +  Status = HttpSetFieldNameAndValue (&Headers[HeaderIndex++],
> HTTP_HEADER_USER_AGENT, REDFISH_HTTP_HEADER_USER_AGENT_VALUE);
> > +  if (EFI_ERROR (Status)) {
> > +    goto ON_ERROR;
> > +  }
> > +
> > +  Status = HttpSetFieldNameAndValue (&Headers[HeaderIndex++],
> REDFISH_HTTP_HEADER_CONNECTION_STR,
> REDFISH_HTTP_HEADER_CONNECTION_VALUE);
> > +  if (EFI_ERROR (Status)) {
> > +    goto ON_ERROR;
> > +  }
> > +
> > +  //
> > +  // Handle content header
> > +  //
> > +  if (HasContent) {
> > +    if (Request->ContentType == NULL) {
> > +      Status = HttpSetFieldNameAndValue (&Headers[HeaderIndex++],
> HTTP_HEADER_CONTENT_TYPE, HTTP_CONTENT_TYPE_APP_JSON);
> > +      if (EFI_ERROR (Status)) {
> > +        goto ON_ERROR;
> > +      }
> > +    } else {
> > +      Status = HttpSetFieldNameAndValue (&Headers[HeaderIndex++],
> HTTP_HEADER_CONTENT_TYPE, Request->ContentType);
> > +      if (EFI_ERROR (Status)) {
> > +        goto ON_ERROR;
> > +      }
> > +    }
> > +
> > +    if (Request->ContentLength == 0) {
> > +      Request->ContentLength =  AsciiStrLen (Request->Content);
> > +    }
> > +
> > +    AsciiSPrint (
> > +      ContentLengthStr,
> > +      sizeof (ContentLengthStr),
> > +      "%lu",
> > +      (UINT64)Request->ContentLength
> > +      );
> > +    Status = HttpSetFieldNameAndValue (&Headers[HeaderIndex++],
> HTTP_HEADER_CONTENT_LENGTH, ContentLengthStr);
> > +    if (EFI_ERROR (Status)) {
> > +      goto ON_ERROR;
> > +    }
> > +
> > +    //
> > +    // Encoding
> > +    //
> > +    if (DoContentEncoding) {
> > +      //
> > +      // We currently only support gzip Content-Encoding.
> > +      //
> > +      Status =  RedfishContentEncode (
> > +                  ContentEncoding,
> > +                  Request->Content,
> > +                  Request->ContentLength,
> > +                  &Content,
> > +                  &ContentLength
> > +                  );
> > +      if (Status == EFI_INVALID_PARAMETER) {
> > +        DEBUG ((DEBUG_ERROR, "%a: Error to encode content.\n", __func__));
> > +        goto ON_ERROR;
> > +      } else if (Status == EFI_UNSUPPORTED) {
> > +        DoContentEncoding = FALSE;
> > +        DEBUG ((REDFISH_HTTP_CACHE_DEBUG_REQUEST, "%a: No content
> coding for %a! Use raw data instead.\n", __func__, ContentEncoding));
> > +        Status = HttpSetFieldNameAndValue (&Headers[HeaderIndex++],
> HTTP_HEADER_CONTENT_ENCODING, HTTP_CONTENT_ENCODING_IDENTITY);
> > +        if (EFI_ERROR (Status)) {
> > +          goto ON_ERROR;
> > +        }
> > +      } else {
> > +        Status = HttpSetFieldNameAndValue (&Headers[HeaderIndex++],
> HTTP_HEADER_CONTENT_ENCODING, HTTP_CONTENT_ENCODING_GZIP);
> > +        if (EFI_ERROR (Status)) {
> > +          goto ON_ERROR;
> > +        }
> > +      }
> > +    }
> > +
> > +    //
> > +    // When the content is from caller, we use our own copy so that we properly
> release it later.
> > +    //
> > +    if (!DoContentEncoding) {
> > +      Content = AllocateCopyPool (Request->ContentLength, Request->Content);
> > +      if (Content == NULL) {
> > +        goto ON_ERROR;
> > +      }
> > +
> > +      ContentLength = Request->ContentLength;
> > +    }
> > +  }
> > +
> > +  //
> > +  // Step 2: build the rest of HTTP request info.
> > +  //
> > +  RequestData = AllocateZeroPool (sizeof (EFI_HTTP_REQUEST_DATA));
> > +  if (RequestData == NULL) {
> > +    goto ON_ERROR;
> > +  }
> > +
> > +  RequestData->Method = Method;
> > +  RequestData->Url    = Url;
> > +
> > +  //
> > +  // Step 3: fill in EFI_HTTP_MESSAGE
> > +  //
> > +  RequestMsg = AllocateZeroPool (sizeof (EFI_HTTP_MESSAGE));
> > +  if (RequestMsg == NULL) {
> > +    goto ON_ERROR;
> > +  }
> > +
> > +  ASSERT (HeaderIndex == HeaderCount);
> > +  RequestMsg->Data.Request = RequestData;
> > +  RequestMsg->HeaderCount  = HeaderIndex;
> > +  RequestMsg->Headers      = Headers;
> > +
> > +  if (HasContent) {
> > +    RequestMsg->BodyLength = ContentLength;
> > +    RequestMsg->Body       = Content;
> > +  }
> > +
> > +  return RequestMsg;
> > +
> > +ON_ERROR:
> > +
> > +  if (Headers != NULL) {
> > +    HttpFreeHeaderFields (Headers, HeaderIndex);
> > +  }
> > +
> > +  if (RequestData != NULL) {
> > +    FreePool (RequestData);
> > +  }
> > +
> > +  if (RequestMsg != NULL) {
> > +    FreePool (RequestMsg);
> > +  }
> > +
> > +  if (Url != NULL) {
> > +    FreePool (Url);
> > +  }
> > +
> > +  return NULL;
> > +}
> > +
> > +/**
> > +  This function parse response message from Redfish service, and
> > +  build Redfish response for caller. It's call responsibility to
> > +  properly release Redfish response by calling ReleaseRedfishResponse.
> > +
> > +  @param[in]   ServicePrivate   Pointer to Redfish service private data.
> > +  @param[in]   ResponseMsg      Response message from Redfish service.
> > +  @param[out]  RedfishResponse  Redfish response data.
> > +
> > +  @retval     EFI_SUCCESS     Redfish response is returned successfully.
> > +  @retval     Others          Errors occur.
> > +
> > +**/
> > +EFI_STATUS
> > +ParseResponseMessage (
> > +  IN  REDFISH_SERVICE_PRIVATE  *ServicePrivate,
> > +  IN  EFI_HTTP_MESSAGE         *ResponseMsg,
> > +  OUT REDFISH_RESPONSE         *RedfishResponse
> > +  )
> > +{
> > +  EFI_STATUS        Status;
> > +  EDKII_JSON_VALUE  JsonData;
> > +  EFI_HTTP_HEADER   *ContentEncodedHeader;
> > +  VOID              *DecodedBody;
> > +  UINTN             DecodedLength;
> > +
> > +  if ((ServicePrivate == NULL) || (ResponseMsg == NULL) || (RedfishResponse
> == NULL)) {
> > +    return EFI_INVALID_PARAMETER;
> > +  }
> > +
> > +  DEBUG ((REDFISH_HTTP_CACHE_DEBUG_REQUEST, "%a\n", __func__));
> > +
> > +  //
> > +  // Initialization
> > +  //
> > +  JsonData                     = NULL;
> > +  RedfishResponse->HeaderCount = 0;
> > +  RedfishResponse->Headers     = NULL;
> > +  RedfishResponse->Payload     = NULL;
> > +  RedfishResponse->StatusCode  = NULL;
> > +  DecodedBody                  = NULL;
> > +  DecodedLength                = 0;
> > +
> > +  //
> > +  // Return the HTTP StatusCode.
> > +  //
> > +  if (ResponseMsg->Data.Response != NULL) {
> > +    DEBUG ((REDFISH_HTTP_CACHE_DEBUG_REQUEST, "%a: status: %d\n",
> __func__, ResponseMsg->Data.Response->StatusCode));
> > +    RedfishResponse->StatusCode = AllocateCopyPool (sizeof
> (EFI_HTTP_STATUS_CODE), &ResponseMsg->Data.Response->StatusCode);
> > +    if (RedfishResponse->StatusCode == NULL) {
> > +      DEBUG ((DEBUG_ERROR, "%a: Failed to create status code.\n", __func__));
> > +    }
> > +  }
> > +
> > +  //
> > +  // Return the HTTP headers.
> > +  //
> > +  if (ResponseMsg->Headers != NULL) {
> > +    DEBUG ((REDFISH_HTTP_CACHE_DEBUG_REQUEST, "%a: header count:
> %d\n", __func__, ResponseMsg->HeaderCount));
> > +    Status = CopyHttpHeaders (
> > +               ResponseMsg->Headers,
> > +               ResponseMsg->HeaderCount,
> > +               &RedfishResponse->Headers,
> > +               &RedfishResponse->HeaderCount
> > +               );
> > +    if (EFI_ERROR (Status)) {
> > +      DEBUG ((DEBUG_ERROR, "%a: Failed to copy HTTP headers: %r\n",
> __func__, Status));
> > +    }
> > +  }
> > +
> > +  //
> > +  // Return the HTTP body.
> > +  //
> > +  if ((ResponseMsg->BodyLength != 0) && (ResponseMsg->Body != NULL)) {
> > +    DEBUG ((REDFISH_HTTP_CACHE_DEBUG_REQUEST, "%a: body length:
> %d\n", __func__, ResponseMsg->BodyLength));
> > +    //
> > +    // Check if data is encoded.
> > +    //
> > +    ContentEncodedHeader = HttpFindHeader (RedfishResponse->HeaderCount,
> RedfishResponse->Headers, HTTP_HEADER_CONTENT_ENCODING);
> > +    if (ContentEncodedHeader != NULL) {
> > +      //
> > +      // The content is encoded.
> > +      //
> > +      Status = RedfishContentDecode (
> > +                 ContentEncodedHeader->FieldValue,
> > +                 ResponseMsg->Body,
> > +                 ResponseMsg->BodyLength,
> > +                 &DecodedBody,
> > +                 &DecodedLength
> > +                 );
> > +      if (EFI_ERROR (Status)) {
> > +        DEBUG ((DEBUG_ERROR, "%a: Failed to decompress the response
> content: %r decoding method: %a\n.", __func__, Status, ContentEncodedHeader-
> >FieldValue));
> > +        goto ON_ERROR;
> > +      }
> > +
> > +      JsonData = JsonLoadBuffer (DecodedBody, DecodedLength, 0, NULL);
> > +      FreePool (DecodedBody);
> > +    } else {
> > +      JsonData = JsonLoadBuffer (ResponseMsg->Body, ResponseMsg-
> >BodyLength, 0, NULL);
> > +    }
> > +
> > +    if (!JsonValueIsNull (JsonData)) {
> > +      RedfishResponse->Payload = CreateRedfishPayload (ServicePrivate,
> JsonData);
> > +      if (RedfishResponse->Payload == NULL) {
> > +        DEBUG ((DEBUG_ERROR, "%a: Failed to create payload\n.", __func__));
> > +      }
> > +
> > +      JsonValueFree (JsonData);
> > +    } else {
> > +      DEBUG ((DEBUG_ERROR, "%a: No payload available\n", __func__));
> > +    }
> > +  }
> > +
> > +  return EFI_SUCCESS;
> > +
> > +ON_ERROR:
> > +
> > +  if (RedfishResponse != NULL) {
> > +    ReleaseRedfishResponse (RedfishResponse);
> > +  }
> > +
> > +  return Status;
> > +}
> > +
> > +/**
> > +  This function send Redfish request to Redfish service by calling
> > +  Rest Ex protocol.
> > +
> > +  @param[in]   Service       Pointer to Redfish service.
> > +  @param[in]   Uri           Uri of Redfish service.
> > +  @param[in]   Method        HTTP method.
> > +  @param[in]   Request     Request data. This is optional.
> > +  @param[out]  Response    Redfish response data.
> > +
> > +  @retval     EFI_SUCCESS     Request is sent and received successfully.
> > +  @retval     Others          Errors occur.
> > +
> > +**/
> > +EFI_STATUS
> > +HttpSendReceive (
> > +  IN  REDFISH_SERVICE   Service,
> > +  IN  EFI_STRING        Uri,
> > +  IN  EFI_HTTP_METHOD   Method,
> > +  IN  REDFISH_REQUEST   *Request  OPTIONAL,
> > +  OUT REDFISH_RESPONSE  *Response
> > +  )
> > +{
> > +  EFI_STATUS               Status;
> > +  EFI_STATUS               RestExStatus;
> > +  EFI_HTTP_MESSAGE         *RequestMsg;
> > +  EFI_HTTP_MESSAGE         ResponseMsg;
> > +  REDFISH_SERVICE_PRIVATE  *ServicePrivate;
> > +  EFI_HTTP_HEADER          *XAuthTokenHeader;
> > +  CHAR8                    *HttpContentEncoding;
> > +
> > +  if ((Service == NULL) || IS_EMPTY_STRING (Uri) || (Response == NULL)) {
> > +    return EFI_INVALID_PARAMETER;
> > +  }
> > +
> > +  DEBUG ((REDFISH_HTTP_CACHE_DEBUG_REQUEST, "%a: Method: 0x%x
> %s\n", __func__, Method, Uri));
> > +
> > +  ServicePrivate = (REDFISH_SERVICE_PRIVATE *)Service;
> > +  if (ServicePrivate->Signature != REDFISH_HTTP_SERVICE_SIGNATURE) {
> > +    DEBUG ((DEBUG_ERROR, "%a: signature check failure\n", __func__));
> > +    return EFI_INVALID_PARAMETER;
> > +  }
> > +
> > +  ZeroMem (&ResponseMsg, sizeof (ResponseMsg));
> > +  HttpContentEncoding = (CHAR8 *)PcdGetPtr
> (PcdRedfishServiceContentEncoding);
> > +
> > +  RequestMsg = BuildRequestMessage (Service, Uri, Method, Request,
> HttpContentEncoding);
> > +  if (RequestMsg == NULL) {
> > +    DEBUG ((DEBUG_ERROR, "%a: cannot build request message for %s\n",
> __func__, Uri));
> > +    return EFI_PROTOCOL_ERROR;
> > +  }
> > +
> > +  //
> > +  // call RESTEx to get response from REST service.
> > +  //
> > +  RestExStatus = ServicePrivate->RestEx->SendReceive (ServicePrivate->RestEx,
> RequestMsg, &ResponseMsg);
> > +  if (EFI_ERROR (RestExStatus)) {
> > +    DEBUG ((DEBUG_ERROR, "%a: %s SendReceive failure: %r\n", __func__,
> Uri, RestExStatus));
> > +  }
> > +
> > +  //
> > +  // Return status code, headers and payload to caller as much as possible even
> when RestEx returns failure.
> > +  //
> > +  Status = ParseResponseMessage (ServicePrivate, &ResponseMsg, Response);
> > +  if (EFI_ERROR (Status)) {
> > +    DEBUG ((DEBUG_ERROR, "%a: %s parse response failure: %r\n", __func__,
> Uri, Status));
> > +  } else {
> > +    //
> > +    // Capture session token in header
> > +    //
> > +    if ((Method == HttpMethodPost) &&
> > +        (Response->StatusCode != NULL) &&
> > +        ((*Response->StatusCode == HTTP_STATUS_200_OK) || (*Response-
> >StatusCode == HTTP_STATUS_204_NO_CONTENT)))
> > +    {
> > +      XAuthTokenHeader = HttpFindHeader (ResponseMsg.HeaderCount,
> ResponseMsg.Headers, HTTP_HEADER_X_AUTH_TOKEN);
> > +      if (XAuthTokenHeader != NULL) {
> > +        Status = UpdateSessionToken (ServicePrivate, XAuthTokenHeader-
> >FieldValue);
> > +        if (EFI_ERROR (Status)) {
> > +          DEBUG ((DEBUG_ERROR, "%a: update session token failure: %r\n",
> __func__, Status));
> > +        }
> > +      }
> > +    }
> > +  }
> > +
> > +  //
> > +  // Release resources
> > +  //
> > +  if (RequestMsg != NULL) {
> > +    ReleaseHttpMessage (RequestMsg, TRUE);
> > +    FreePool (RequestMsg);
> > +  }
> > +
> > +  ReleaseHttpMessage (&ResponseMsg, FALSE);
> > +
> > +  return RestExStatus;
> > +}
> > diff --git a/RedfishPkg/Redfish.fdf.inc b/RedfishPkg/Redfish.fdf.inc
> > index 3e5a77766e..5cbe3592fd 100644
> > --- a/RedfishPkg/Redfish.fdf.inc
> > +++ b/RedfishPkg/Redfish.fdf.inc
> > @@ -6,7 +6,7 @@
> > # to be built in the firmware volume.
> > #
> > # (C) Copyright 2020-2021 Hewlett Packard Enterprise Development LP<BR>
> > -# Copyright (c) 2023, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
> > +# Copyright (c) 2023-2024, NVIDIA CORPORATION & AFFILIATES. All rights
> reserved.
> > #
> > #    SPDX-License-Identifier: BSD-2-Clause-Patent
> > #
> > @@ -20,4 +20,5 @@
> >   INF RedfishPkg/RedfishConfigHandler/RedfishConfigHandlerDriver.inf
> >   INF RedfishPkg/RedfishPlatformConfigDxe/RedfishPlatformConfigDxe.inf
> >   INF
> MdeModulePkg/Universal/RegularExpressionDxe/RegularExpressionDxe.inf
> > +  INF RedfishPkg/RedfishHttpDxe/RedfishHttpDxe.inf
> > !endif
> > --
> > 2.34.1
> >
> >
> >
> > 
> >
>
> Regards,
> Mike.
> >


-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#115885): https://edk2.groups.io/g/devel/message/115885
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]
-=-=-=-=-=-=-=-=-=-=-=-



^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [edk2-devel] [PATCH v2 2/6] RedfishPkg: implement Redfish HTTP protocol
  2024-02-23 14:07   ` Nickle Wang via groups.io
@ 2024-02-23 16:04     ` Mike Maslenkin
  2024-02-26 13:43       ` Nickle Wang via groups.io
  0 siblings, 1 reply; 15+ messages in thread
From: Mike Maslenkin @ 2024-02-23 16:04 UTC (permalink / raw)
  To: Nickle Wang
  Cc: devel@edk2.groups.io, Igor Kulchytskyy, Abner Chang, Nick Ramirez

Hi Nickle,

On Fri, Feb 23, 2024 at 5:07 PM Nickle Wang <nicklew@nvidia.com> wrote:
>
> Thanks for your review, Mike.
>
> > %s/Resrouce/Resource/ this comes from RedfishClient autogenerated files...
>
> Typos are Addressed. I will send v3 later.
>
> >> +ON_ERROR:
> >> +
> >> +  ReleaseRedfishPayload (NewPayload);
> >> +
> >
> > NewPayload->Service  is leaked
>
> NewPayload->Service will be released in ReleaseRedfishPayload function.  ReleaseRedfishService() will be called in ReleaseRedfishPayload() when Service is not NULL. Please let me know if I misunderstand your comment.

Oh, I see.
I missed ReleaseRedfishService() call.

>
>
> >> +    (*DstHeaders)[Index].FieldValue = AllocateCopyPool (AsciiStrSize (SrcHeaders[Index].FieldValue), SrcHeaders[Index].FieldValue);
> >> +    if ((*DstHeaders)[Index].FieldValue == NULL) {
> >> +      return EFI_OUT_OF_RESOURCES;
> >
> > Looks like orevious allocations leaked.
> > Didn't you think to implement smth like this ....?
>
> Yes, I can implement AsciiStrDup() here. But this won't fix the allocation leaking, right? To fix allocation leaking, my idea is to call HttpFreeHeaderFields() before returning EFI_OUT_OF_RESOURCES.  HttpFreeHeaderFields() will skip NULL FieldName and FieldValue automatically. Does this sound good to you?
>
> I think I covered all your comments, but I am bad to find review comment in email. If I missed any review comment, please kindly let me know. Thanks!

AsciiStrDup() is not handy here, because it requires preallocated buffer.
I mentioned about function similar to StrDup just to get shorter and
cleaner code.

I think I understood the idea now.
I'm just looking into code and assume that if function returns an
error, it must deallocate/cleanup resources.

So finally we have
HttpFreeHeaderFields (Response->Headers, Response->HeaderCount);
but Response->HeaderCount does not count partially allocated elements. Right?

To fix this, it is required to set
*DstHeaderCount = SrcHeaderCount unconditionally right after
DstHeaders  allocation, and HttpFreeHeaderFields() will do the work
then.

Regards,
Mike.

>
> Regards,
> Nickle
>
> > -----Original Message-----
> > From: Mike Maslenkin <mike.maslenkin@gmail.com>
> > Sent: Friday, February 23, 2024 7:29 PM
> > To: devel@edk2.groups.io; Nickle Wang <nicklew@nvidia.com>
> > Cc: Igor Kulchytskyy <igork@ami.com>; Abner Chang <abner.chang@amd.com>;
> > Nick Ramirez <nramirez@nvidia.com>
> > Subject: Re: [edk2-devel] [PATCH v2 2/6] RedfishPkg: implement Redfish HTTP
> > protocol
> >
> > External email: Use caution opening links or attachments
> >
> >
> > Hi Nickle,
> >
> > %s/Resrouce/Resource/ this comes from RedfishClient autogenerated files...
> > there are thousands of "Resrouce" typos.
> >
> > please, find my minor notes below:
> >
> >
> > On Thu, Feb 22, 2024 at 12:11 PM Nickle Wang via groups.io
> > <nicklew=nvidia.com@groups.io> wrote:
> > >
> > > implement Redfish HTTP protocol driver.
> > >
> > > Signed-off-by: Nickle Wang <nicklew@nvidia.com>
> > > Co-authored-by: Igor Kulchytskyy <igork@ami.com>
> > > Cc: Abner Chang <abner.chang@amd.com>
> > > Cc: Igor Kulchytskyy <igork@ami.com>
> > > Cc: Nick Ramirez <nramirez@nvidia.com>
> > > ---
> > > RedfishPkg/RedfishPkg.dec                     |    7 +-
> > > RedfishPkg/RedfishComponents.dsc.inc          |    3 +-
> > > RedfishPkg/RedfishPkg.dsc                     |    2 +
> > > RedfishPkg/RedfishHttpDxe/RedfishHttpDxe.inf  |   73 +
> > > RedfishPkg/RedfishHttpDxe/RedfishHttpData.h   |  256 ++++
> > > RedfishPkg/RedfishHttpDxe/RedfishHttpDxe.h    |   44 +
> > > .../RedfishHttpDxe/RedfishHttpOperation.h     |   76 +
> > > RedfishPkg/RedfishHttpDxe/RedfishHttpData.c   |  667 ++++++++
> > > RedfishPkg/RedfishHttpDxe/RedfishHttpDxe.c    | 1344 +++++++++++++++++
> > > .../RedfishHttpDxe/RedfishHttpOperation.c     |  693 +++++++++
> > > RedfishPkg/Redfish.fdf.inc                    |    3 +-
> > > 11 files changed, 3164 insertions(+), 4 deletions(-)
> > > create mode 100644 RedfishPkg/RedfishHttpDxe/RedfishHttpDxe.inf
> > > create mode 100644 RedfishPkg/RedfishHttpDxe/RedfishHttpData.h
> > > create mode 100644 RedfishPkg/RedfishHttpDxe/RedfishHttpDxe.h
> > > create mode 100644 RedfishPkg/RedfishHttpDxe/RedfishHttpOperation.h
> > > create mode 100644 RedfishPkg/RedfishHttpDxe/RedfishHttpData.c
> > > create mode 100644 RedfishPkg/RedfishHttpDxe/RedfishHttpDxe.c
> > > create mode 100644 RedfishPkg/RedfishHttpDxe/RedfishHttpOperation.c
> > >
> > > diff --git a/RedfishPkg/RedfishPkg.dec b/RedfishPkg/RedfishPkg.dec
> > > index 9b424efdf3..114f8d2ad8 100644
> > > --- a/RedfishPkg/RedfishPkg.dec
> > > +++ b/RedfishPkg/RedfishPkg.dec
> > > @@ -157,8 +157,11 @@
> > >   # set to EFI_REST_EX_PROTOCOL.
> > >   #
> > >
> > gEfiRedfishPkgTokenSpaceGuid.PcdRedfishSendReceiveTimeout|5000|UINT32|0
> > x00001009
> > > -  ## This is used to enable HTTP content encoding on Redfish communication.
> > > -
> > gEfiRedfishPkgTokenSpaceGuid.PcdRedfishServiceContentEncoding|TRUE|BOOLE
> > AN|0x0000100A
> > > +  #
> > > +  # This PCD string is introduced for platform developer to set the encoding
> > method supported by BMC Redfish.
> > > +  # Currently only "None" and "gzip" are supported.
> > > +  #
> > > +
> > gEfiRedfishPkgTokenSpaceGuid.PcdRedfishServiceContentEncoding|"None"|VOID
> > *|0x0000100A
> > >   #
> > >   # Use below PCDs to control Redfhs HTTP protocol.
> > >   #
> > > diff --git a/RedfishPkg/RedfishComponents.dsc.inc
> > b/RedfishPkg/RedfishComponents.dsc.inc
> > > index 464ffc8606..d6c5b73d7f 100644
> > > --- a/RedfishPkg/RedfishComponents.dsc.inc
> > > +++ b/RedfishPkg/RedfishComponents.dsc.inc
> > > @@ -7,7 +7,7 @@
> > > # "RedfishDefines.dsc.inc".
> > > #
> > > # (C) Copyright 2020-2021 Hewlett Packard Enterprise Development LP<BR>
> > > -# Copyright (c) 2023, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
> > > +# Copyright (c) 2023-2024, NVIDIA CORPORATION & AFFILIATES. All rights
> > reserved.
> > > #
> > > #    SPDX-License-Identifier: BSD-2-Clause-Patent
> > > #
> > > @@ -28,4 +28,5 @@
> > >   RedfishPkg/RedfishConfigHandler/RedfishConfigHandlerDriver.inf
> > >   RedfishPkg/RedfishPlatformConfigDxe/RedfishPlatformConfigDxe.inf
> > >   MdeModulePkg/Universal/RegularExpressionDxe/RegularExpressionDxe.inf
> > > +  RedfishPkg/RedfishHttpDxe/RedfishHttpDxe.inf
> > > !endif
> > > diff --git a/RedfishPkg/RedfishPkg.dsc b/RedfishPkg/RedfishPkg.dsc
> > > index 25ed193182..5849e7cf9e 100644
> > > --- a/RedfishPkg/RedfishPkg.dsc
> > > +++ b/RedfishPkg/RedfishPkg.dsc
> > > @@ -45,6 +45,8 @@
> > >
> > UefiHiiServicesLib|MdeModulePkg/Library/UefiHiiServicesLib/UefiHiiServicesLib.
> > inf
> > >
> > RedfishPlatformCredentialLib|RedfishPkg/Library/PlatformCredentialLibNull/Platf
> > ormCredentialLibNull.inf
> > >
> > RedfishContentCodingLib|RedfishPkg/Library/RedfishContentCodingLibNull/Redfi
> > shContentCodingLibNull.inf
> > > +
> > ReportStatusCodeLib|MdeModulePkg/Library/DxeReportStatusCodeLib/DxeRepo
> > rtStatusCodeLib.inf
> > > +  SortLib|MdeModulePkg/Library/UefiSortLib/UefiSortLib.inf
> > >
> > >   # NULL instance of IPMI related library.
> > >   IpmiLib|MdeModulePkg/Library/BaseIpmiLibNull/BaseIpmiLibNull.inf
> > > diff --git a/RedfishPkg/RedfishHttpDxe/RedfishHttpDxe.inf
> > b/RedfishPkg/RedfishHttpDxe/RedfishHttpDxe.inf
> > > new file mode 100644
> > > index 0000000000..c7dfdffacf
> > > --- /dev/null
> > > +++ b/RedfishPkg/RedfishHttpDxe/RedfishHttpDxe.inf
> > > @@ -0,0 +1,73 @@
> > > +## @file
> > > +#  RedfishHttpDxe is the DXE driver which provides
> > > +#  EdkIIRedfishHttpProtocol to EDK2 Redfish Feature
> > > +#  drivers for HTTP operation.
> > > +#
> > > +#  Copyright (c) 2023-2024, NVIDIA CORPORATION & AFFILIATES. All rights
> > reserved.
> > > +#
> > > +#  SPDX-License-Identifier: BSD-2-Clause-Patent
> > > +#
> > > +##
> > > +
> > > +[Defines]
> > > +  INF_VERSION                    = 0x0001000b
> > > +  BASE_NAME                      = RedfishHttpDxe
> > > +  FILE_GUID                      = 85ADB2F1-DA93-47D4-AF4F-3D920D9BD2C0
> > > +  MODULE_TYPE                    = DXE_DRIVER
> > > +  VERSION_STRING                 = 1.0
> > > +  ENTRY_POINT                    = RedfishHttpEntryPoint
> > > +  UNLOAD_IMAGE                   = RedfishHttpDriverUnload
> > > +
> > > +#
> > > +#  VALID_ARCHITECTURES           = IA32 X64 ARM AARCH64 RISCV64
> > > +#
> > > +
> > > +[Sources]
> > > +  RedfishHttpData.c
> > > +  RedfishHttpData.h
> > > +  RedfishHttpDxe.c
> > > +  RedfishHttpDxe.h
> > > +  RedfishHttpOperation.c
> > > +  RedfishHttpOperation.h
> > > +
> > > +[Packages]
> > > +  MdePkg/MdePkg.dec
> > > +  MdeModulePkg/MdeModulePkg.dec
> > > +  NetworkPkg/NetworkPkg.dec
> > > +  RedfishPkg/RedfishPkg.dec
> > > +
> > > +[LibraryClasses.ARM]
> > > +  ArmSoftFloatLib
> > > +
> > > +[LibraryClasses]
> > > +  BaseLib
> > > +  BaseMemoryLib
> > > +  RedfishContentCodingLib
> > > +  DebugLib
> > > +  HttpLib
> > > +  JsonLib
> > > +  MemoryAllocationLib
> > > +  PrintLib
> > > +  RedfishDebugLib
> > > +  ReportStatusCodeLib
> > > +  UefiBootServicesTableLib
> > > +  UefiDriverEntryPoint
> > > +  UefiLib
> > > +
> > > +[Protocols]
> > > +  gEdkIIRedfishHttpProtocolGuid             ## PRODUCED
> > > +  gEdkIIRedfishCredentialProtocolGuid       ## CONSUMES
> > > +  gEfiRestExProtocolGuid                    ## CONSUEMS
> > > +
> > > +[Pcd]
> > > +  gEfiRedfishPkgTokenSpaceGuid.PcdHttpGetRetry
> > > +  gEfiRedfishPkgTokenSpaceGuid.PcdHttpPutRetry
> > > +  gEfiRedfishPkgTokenSpaceGuid.PcdHttpPatchRetry
> > > +  gEfiRedfishPkgTokenSpaceGuid.PcdHttpPostRetry
> > > +  gEfiRedfishPkgTokenSpaceGuid.PcdHttpDeleteRetry
> > > +  gEfiRedfishPkgTokenSpaceGuid.PcdHttpRetryWaitInSecond
> > > +  gEfiRedfishPkgTokenSpaceGuid.PcdHttpCacheDisabled
> > > +  gEfiRedfishPkgTokenSpaceGuid.PcdRedfishServiceContentEncoding
> > > +
> > > +[Depex]
> > > +  TRUE
> > > diff --git a/RedfishPkg/RedfishHttpDxe/RedfishHttpData.h
> > b/RedfishPkg/RedfishHttpDxe/RedfishHttpData.h
> > > new file mode 100644
> > > index 0000000000..6be610142e
> > > --- /dev/null
> > > +++ b/RedfishPkg/RedfishHttpDxe/RedfishHttpData.h
> > > @@ -0,0 +1,256 @@
> > > +/** @file
> > > +  Definitions of RedfishHttpData
> > > +
> > > +  Copyright (c) 2023-2024, NVIDIA CORPORATION & AFFILIATES. All rights
> > reserved.
> > > +
> > > +  SPDX-License-Identifier: BSD-2-Clause-Patent
> > > +
> > > +**/
> > > +
> > > +#ifndef EDKII_REDFISH_HTTP_DATA_H_
> > > +#define EDKII_REDFISH_HTTP_DATA_H_
> > > +
> > > +#include "RedfishHttpDxe.h"
> > > +
> > > +#define REDFISH_HTTP_DRIVER_SIGNATURE   SIGNATURE_32 ('r', 'f', 'h', 'p')
> > > +#define REDFISH_HTTP_CACHE_SIGNATURE    SIGNATURE_32 ('r', 'f', 'c', 'h')
> > > +#define REDFISH_HTTP_SERVICE_SIGNATURE  SIGNATURE_32 ('r', 'f', 's', 'v')
> > > +#define REDFISH_HTTP_PAYLOAD_SIGNATURE  SIGNATURE_32 ('r', 'f', 'p', 'l')
> > > +#define REDFISH_HTTP_BASIC_AUTH_STR     "Basic "
> > > +
> > > +///
> > > +/// REDFISH_SERVICE_PRIVATE definition.
> > > +///
> > > +typedef struct {
> > > +  UINT32                  Signature;
> > > +  CHAR8                   *Host;
> > > +  CHAR8                   *HostName;
> > > +  CHAR8                   *BasicAuth;
> > > +  CHAR8                   *SessionToken;
> > > +  EFI_REST_EX_PROTOCOL    *RestEx;
> > > +} REDFISH_SERVICE_PRIVATE;
> > > +
> > > +///
> > > +/// REDFISH_PAYLOAD_PRIVATE definition.
> > > +///
> > > +typedef struct {
> > > +  UINT32                     Signature;
> > > +  REDFISH_SERVICE_PRIVATE    *Service;
> > > +  EDKII_JSON_VALUE           JsonValue;
> > > +} REDFISH_PAYLOAD_PRIVATE;
> > > +
> > > +///
> > > +/// Definition of REDFISH_HTTP_CACHE_DATA
> > > +///
> > > +typedef struct {
> > > +  UINT32              Signature;
> > > +  LIST_ENTRY          List;
> > > +  EFI_STRING          Uri;
> > > +  UINTN               HitCount;
> > > +  REDFISH_RESPONSE    *Response;
> > > +} REDFISH_HTTP_CACHE_DATA;
> > > +
> > > +#define REDFISH_HTTP_CACHE_FROM_LIST(a)  CR (a,
> > REDFISH_HTTP_CACHE_DATA, List, REDFISH_HTTP_CACHE_SIGNATURE)
> > > +
> > > +///
> > > +/// Definition of REDFISH_HTTP_CACHE_LIST
> > > +///
> > > +typedef struct {
> > > +  LIST_ENTRY    Head;
> > > +  UINTN         Count;
> > > +  UINTN         Capacity;
> > > +} REDFISH_HTTP_CACHE_LIST;
> > > +
> > > +///
> > > +/// Definition of REDFISH_HTTP_RETRY_SETTING
> > > +///
> > > +typedef struct {
> > > +  UINT16    MaximumRetryGet;
> > > +  UINT16    MaximumRetryPut;
> > > +  UINT16    MaximumRetryPost;
> > > +  UINT16    MaximumRetryPatch;
> > > +  UINT16    MaximumRetryDelete;
> > > +  UINTN     RetryWait;
> > > +} REDFISH_HTTP_RETRY_SETTING;
> > > +
> > > +///
> > > +/// Definition of REDFISH_HTTP_CACHE_PRIVATE
> > > +///
> > > +typedef struct {
> > > +  UINT32                               Signature;
> > > +  EFI_HANDLE                           ImageHandle;
> > > +  BOOLEAN                              CacheDisabled;
> > > +  EFI_EVENT                            NotifyEvent;
> > > +  REDFISH_HTTP_CACHE_LIST              CacheList;
> > > +  EDKII_REDFISH_HTTP_PROTOCOL          Protocol;
> > > +  EDKII_REDFISH_CREDENTIAL_PROTOCOL    *CredentialProtocol;
> > > +  REDFISH_HTTP_RETRY_SETTING           RetrySetting;
> > > +} REDFISH_HTTP_CACHE_PRIVATE;
> > > +
> > > +#define REDFISH_HTTP_CACHE_PRIVATE_FROM_THIS(a)  CR (a,
> > REDFISH_HTTP_CACHE_PRIVATE, Protocol, REDFISH_HTTP_DRIVER_SIGNATURE)
> > > +
> > > +/**
> > > +  Search on given ListHeader for given URI string.
> > > +
> > > +  @param[in]    ListHeader  Target list to search.
> > > +  @param[in]    Uri         Target URI to search.
> > > +
> > > +  @retval REDFISH_HTTP_CACHE_DATA   Target cache data is found.
> > > +  @retval NULL                      No cache data with given URI is found.
> > > +
> > > +**/
> > > +REDFISH_HTTP_CACHE_DATA *
> > > +FindHttpCacheData (
> > > +  IN  LIST_ENTRY  *ListHeader,
> > > +  IN  EFI_STRING  Uri
> > > +  );
> > > +
> > > +/**
> > > +  This function copy the data in SrcResponse to DstResponse.
> > > +
> > > +  @param[in]  SrcResponse      Source Response to copy.
> > > +  @param[out] DstResponse      Destination Response.
> > > +
> > > +  @retval     EFI_SUCCESS      Response is copied successfully.
> > > +  @retval     Others           Error occurs.
> > > +
> > > +**/
> > > +EFI_STATUS
> > > +CopyRedfishResponse (
> > > +  IN  REDFISH_RESPONSE  *SrcResponse,
> > > +  OUT REDFISH_RESPONSE  *DstResponse
> > > +  );
> > > +
> > > +/**
> > > +  Release all cache from list.
> > > +
> > > +  @param[in]    CacheList    The list to be released.
> > > +
> > > +  @retval EFI_SUCCESS             All cache data are released.
> > > +  @retval EFI_INVALID_PARAMETER   CacheList is NULL.
> > > +
> > > +**/
> > > +EFI_STATUS
> > > +ReleaseCacheList (
> > > +  IN  REDFISH_HTTP_CACHE_LIST  *CacheList
> > > +  );
> > > +
> > > +/**
> > > +  Add new cache by given URI and HTTP response to specify List.
> > > +
> > > +  @param[in]    List      Target cache list to add.
> > > +  @param[in]    Uri       The URI string matching to this cache data.
> > > +  @param[in]    Response  HTTP response.
> > > +
> > > +  @retval EFI_SUCCESS   Cache data is added.
> > > +  @retval Others        Fail to add cache data.
> > > +
> > > +**/
> > > +EFI_STATUS
> > > +AddHttpCacheData (
> > > +  IN  REDFISH_HTTP_CACHE_LIST  *List,
> > > +  IN  EFI_STRING               Uri,
> > > +  IN  REDFISH_RESPONSE         *Response
> > > +  );
> > > +
> > > +/**
> > > +  Delete a cache data by given cache instance.
> > > +
> > > +  @param[in]    List    Target cache list to be removed.
> > > +  @param[in]    Data    Pointer to the instance to be deleted.
> > > +
> > > +  @retval EFI_SUCCESS   Cache data is removed.
> > > +  @retval Others        Fail to remove cache data.
> > > +
> > > +**/
> > > +EFI_STATUS
> > > +DeleteHttpCacheData (
> > > +  IN  REDFISH_HTTP_CACHE_LIST  *List,
> > > +  IN  REDFISH_HTTP_CACHE_DATA  *Data
> > > +  );
> > > +
> > > +/**
> > > +  This function release Redfish Payload.
> > > +
> > > +  @param[in]  Payload         Pointer to payload instance.
> > > +
> > > +  @retval     EFI_SUCCESS     Payload is released.
> > > +  @retval     Others          Error occurs.
> > > +
> > > +**/
> > > +EFI_STATUS
> > > +ReleaseRedfishPayload (
> > > +  IN REDFISH_PAYLOAD_PRIVATE  *Payload
> > > +  );
> > > +
> > > +/**
> > > +  This function creat new payload. Server and JsonObj are
> > > +  copied to newly created payload.
> > > +
> > > +  @param[in]  Service          Pointer to Service instance.
> > > +  @param[in]  JsonObj          Pointer to JSON object.
> > > +
> > > +  @retval     REDFISH_PAYLOAD_PRIVATE  Newly created payload.
> > > +  @retval     NULL             Error occurs.
> > > +
> > > +**/
> > > +REDFISH_PAYLOAD_PRIVATE *
> > > +CreateRedfishPayload (
> > > +  IN REDFISH_SERVICE_PRIVATE  *Service,
> > > +  IN EDKII_JSON_VALUE         JsonValue
> > > +  );
> > > +
> > > +/**
> > > +  This function release Redfish Service.
> > > +
> > > +  @param[in]  Service         Pointer to service instance.
> > > +
> > > +  @retval     EFI_SUCCESS     Service is released.
> > > +  @retval     Others          Error occurs.
> > > +
> > > +**/
> > > +EFI_STATUS
> > > +ReleaseRedfishService (
> > > +  IN REDFISH_SERVICE_PRIVATE  *Service
> > > +  );
> > > +
> > > +/**
> > > +  This function creat new service. Host and HostName are copied to
> > > +  newly created service instance.
> > > +
> > > +  @param[in]  Host            Host string.
> > > +  @param[in]  HostName        Hostname string.
> > > +  @param[in]  BasicAuth       Basic Authorization string.
> > > +  @param[in]  SessionToken    Session token string.
> > > +  @param[in]  RestEx          Rest EX protocol instance.
> > > +
> > > +  @retval     REDFISH_PAYLOAD_PRIVATE  Newly created service.
> > > +  @retval     NULL             Error occurs.
> > > +
> > > +**/
> > > +REDFISH_SERVICE_PRIVATE *
> > > +CreateRedfishService (
> > > +  IN CHAR8                 *Host,
> > > +  IN CHAR8                 *HostName,
> > > +  IN CHAR8                 *BasicAuth OPTIONAL,
> > > +  IN CHAR8                 *SessionToken OPTIONAL,
> > > +  IN EFI_REST_EX_PROTOCOL  *RestEx
> > > +  );
> > > +
> > > +/**
> > > +  This function update session token in Redfish Service.
> > > +
> > > +  @param[in]  Service         Pointer to service instance.
> > > +  @param[in]  Token           Session token.
> > > +
> > > +  @retval     EFI_SUCCESS     Session token is updated.
> > > +  @retval     Others          Error occurs.
> > > +
> > > +**/
> > > +EFI_STATUS
> > > +UpdateSessionToken (
> > > +  IN REDFISH_SERVICE_PRIVATE  *Service,
> > > +  IN CHAR8                    *Token
> > > +  );
> > > +
> > > +#endif
> > > diff --git a/RedfishPkg/RedfishHttpDxe/RedfishHttpDxe.h
> > b/RedfishPkg/RedfishHttpDxe/RedfishHttpDxe.h
> > > new file mode 100644
> > > index 0000000000..cf6ba9cb47
> > > --- /dev/null
> > > +++ b/RedfishPkg/RedfishHttpDxe/RedfishHttpDxe.h
> > > @@ -0,0 +1,44 @@
> > > +/** @file
> > > +  Definitions of RedfishHttpDxe
> > > +
> > > +  Copyright (c) 2023-2024, NVIDIA CORPORATION & AFFILIATES. All rights
> > reserved.
> > > +
> > > +  SPDX-License-Identifier: BSD-2-Clause-Patent
> > > +
> > > +**/
> > > +
> > > +#ifndef EDKII_REDFISH_HTTP_DXE_H_
> > > +#define EDKII_REDFISH_HTTP_DXE_H_
> > > +
> > > +#include <Uefi.h>
> > > +#include <IndustryStandard/Http11.h>
> > > +
> > > +#include <Library/UefiLib.h>
> > > +#include <Library/BaseLib.h>
> > > +#include <Library/BaseMemoryLib.h>
> > > +#include <Library/RedfishContentCodingLib.h>
> > > +#include <Library/DebugLib.h>
> > > +#include <Library/HttpLib.h>
> > > +#include <Library/JsonLib.h>
> > > +#include <Library/UefiBootServicesTableLib.h>
> > > +#include <Library/MemoryAllocationLib.h>
> > > +#include <Library/RedfishDebugLib.h>
> > > +#include <Library/ReportStatusCodeLib.h>
> > > +#include <Library/PrintLib.h>
> > > +
> > > +#include <Protocol/Http.h>
> > > +#include <Protocol/EdkIIRedfishHttpProtocol.h>
> > > +#include <Protocol/EdkIIRedfishCredential.h>
> > > +#include <Protocol/RestEx.h>
> > > +
> > > +#define IS_EMPTY_STRING(a)  ((a) == NULL || (a)[0] == '\0')
> > > +#define REDFISH_HTTP_CACHE_LIST_SIZE      0x80
> > > +#define REDFISH_ERROR_MSG_MAX             128
> > > +#define REDFISH_DEBUG_STRING_LENGTH       200
> > > +#define REDFISH_HOST_NAME_MAX             64   // IPv6 maximum length (39)
> > + "https://" (8) + port number (maximum 5)
> > > +#define REDFISH_HTTP_ERROR_REPORT         "Redfish HTTP %a failure(0x%x):
> > %s"
> > > +#define REDFISH_HTTP_CACHE_DEBUG          DEBUG_MANAGEABILITY
> > > +#define REDFISH_HTTP_CACHE_DEBUG_DUMP     DEBUG_MANAGEABILITY
> > > +#define REDFISH_HTTP_CACHE_DEBUG_REQUEST  DEBUG_MANAGEABILITY
> > > +
> > > +#endif
> > > diff --git a/RedfishPkg/RedfishHttpDxe/RedfishHttpOperation.h
> > b/RedfishPkg/RedfishHttpDxe/RedfishHttpOperation.h
> > > new file mode 100644
> > > index 0000000000..d2f7cf4c27
> > > --- /dev/null
> > > +++ b/RedfishPkg/RedfishHttpDxe/RedfishHttpOperation.h
> > > @@ -0,0 +1,76 @@
> > > +/** @file
> > > +  Definitions of RedfishHttpOperation
> > > +
> > > +  Copyright (c) 2024, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
> > > +
> > > +  SPDX-License-Identifier: BSD-2-Clause-Patent
> > > +
> > > +**/
> > > +
> > > +#ifndef EDKII_REDFISH_HTTP_OPERATION_H_
> > > +#define EDKII_REDFISH_HTTP_OPERATION_H_
> > > +
> > > +#include "RedfishHttpDxe.h"
> > > +
> > > +#define REDFISH_CONTENT_LENGTH_SIZE              80
> > > +#define REDFISH_COMMON_HEADER_SIZE               5
> > > +#define REDFISH_HTTP_HEADER_ODATA_VERSION_STR    "OData-Version"
> > > +#define REDFISH_HTTP_HEADER_ODATA_VERSION_VALUE  "4.0"
> > > +#define REDFISH_HTTP_HEADER_USER_AGENT_VALUE     "edk2redfish"
> > > +#define REDFISH_HTTP_HEADER_CONNECTION_STR       "Connection"
> > > +#define REDFISH_HTTP_HEADER_CONNECTION_VALUE     "Keep-Alive"
> > > +#define REDFISH_HTTP_CONTENT_ENCODING_NONE       "None"
> > > +
> > > +/**
> > > +  This function free resources in Request. Request is no longer available
> > > +  after this function returns successfully.
> > > +
> > > +  @param[in]  Request      HTTP request to be released.
> > > +
> > > +  @retval     EFI_SUCCESS     Resrouce is released successfully.
> > > +  @retval     Others          Errors occur.
> > > +
> > > +**/
> > > +EFI_STATUS
> > > +ReleaseRedfishRequest (
> > > +  IN  REDFISH_REQUEST  *Request
> > > +  );
> > > +
> > > +/**
> > > +  This function free resources in given Response.
> > > +
> > > +  @param[in]  Response     HTTP response to be released.
> > > +
> > > +  @retval     EFI_SUCCESS     Resrouce is released successfully.
> > > +  @retval     Others          Errors occur.
> > > +
> > > +**/
> > > +EFI_STATUS
> > > +ReleaseRedfishResponse (
> > > +  IN  REDFISH_RESPONSE  *Response
> > > +  );
> > > +
> > > +/**
> > > +  This function send Redfish request to Redfish service by calling
> > > +  Rest Ex protocol.
> > > +
> > > +  @param[in]   Service       Pointer to Redfish service.
> > > +  @param[in]   Uri           Uri of Redfish service.
> > > +  @param[in]   Method        HTTP method.
> > > +  @param[in]   Request     Request data. This is optional.
> > > +  @param[out]  Response    Redfish response data.
> > > +
> > > +  @retval     EFI_SUCCESS     Request is sent and received successfully.
> > > +  @retval     Others          Errors occur.
> > > +
> > > +**/
> > > +EFI_STATUS
> > > +HttpSendReceive (
> > > +  IN  REDFISH_SERVICE   Service,
> > > +  IN  EFI_STRING        Uri,
> > > +  IN  EFI_HTTP_METHOD   Method,
> > > +  IN  REDFISH_REQUEST   *Request  OPTIONAL,
> > > +  OUT REDFISH_RESPONSE  *Response
> > > +  );
> > > +
> > > +#endif
> > > diff --git a/RedfishPkg/RedfishHttpDxe/RedfishHttpData.c
> > b/RedfishPkg/RedfishHttpDxe/RedfishHttpData.c
> > > new file mode 100644
> > > index 0000000000..bf95e9f8d4
> > > --- /dev/null
> > > +++ b/RedfishPkg/RedfishHttpDxe/RedfishHttpData.c
> > > @@ -0,0 +1,667 @@
> > > +/** @file
> > > +  RedfishHttpData handles internal data to support Redfish HTTP protocol.
> > > +
> > > +  Copyright (c) 2023-2024, NVIDIA CORPORATION & AFFILIATES. All rights
> > reserved.
> > > +
> > > +  SPDX-License-Identifier: BSD-2-Clause-Patent
> > > +
> > > +**/
> > > +
> > > +#include "RedfishHttpData.h"
> > > +#include "RedfishHttpOperation.h"
> > > +
> > > +/**
> > > +  This function update session token in Redfish Service.
> > > +
> > > +  @param[in]  Service         Pointer to service instance.
> > > +  @param[in]  Token           Session token.
> > > +
> > > +  @retval     EFI_SUCCESS     Session token is updated.
> > > +  @retval     Others          Error occurs.
> > > +
> > > +**/
> > > +EFI_STATUS
> > > +UpdateSessionToken (
> > > +  IN REDFISH_SERVICE_PRIVATE  *Service,
> > > +  IN CHAR8                    *Token
> > > +  )
> > > +{
> > > +  if ((Service == NULL) || IS_EMPTY_STRING (Token)) {
> > > +    return EFI_INVALID_PARAMETER;
> > > +  }
> > > +
> > > +  if (Service->SessionToken != NULL) {
> > > +    FreePool (Service->SessionToken);
> > > +  }
> > > +
> > > +  Service->SessionToken = AllocateCopyPool (AsciiStrSize (Token), Token);
> > > +  if (Service->SessionToken == NULL) {
> > > +    return EFI_OUT_OF_RESOURCES;
> > > +  }
> > > +
> > > +  return EFI_SUCCESS;
> > > +}
> > > +
> > > +/**
> > > +  This function release Redfish Service.
> > > +
> > > +  @param[in]  Service         Pointer to service instance.
> > > +
> > > +  @retval     EFI_SUCCESS     Service is released.
> > > +  @retval     Others          Error occurs.
> > > +
> > > +**/
> > > +EFI_STATUS
> > > +ReleaseRedfishService (
> > > +  IN REDFISH_SERVICE_PRIVATE  *Service
> > > +  )
> > > +{
> > > +  if (Service == NULL) {
> > > +    return EFI_INVALID_PARAMETER;
> > > +  }
> > > +
> > > +  if (Service->Host != NULL) {
> > > +    FreePool (Service->Host);
> > > +  }
> > > +
> > > +  if (Service->HostName != NULL) {
> > > +    FreePool (Service->HostName);
> > > +  }
> > > +
> > > +  if (Service->BasicAuth != NULL) {
> > > +    ZeroMem (Service->BasicAuth, AsciiStrSize (Service->BasicAuth));
> > > +    FreePool (Service->BasicAuth);
> > > +  }
> > > +
> > > +  if (Service->SessionToken != NULL) {
> > > +    ZeroMem (Service->SessionToken, AsciiStrSize (Service->SessionToken));
> > > +    FreePool (Service->SessionToken);
> > > +  }
> > > +
> > > +  FreePool (Service);
> > > +
> > > +  return EFI_SUCCESS;
> > > +}
> > > +
> > > +/**
> > > +  This function creat new service. Host and HostName are copied to
> > > +  newly created service instance.
> > > +
> > > +  @param[in]  Host            Host string.
> > > +  @param[in]  HostName        Hostname string.
> > > +  @param[in]  BasicAuth       Basic Authorization string.
> > > +  @param[in]  SessionToken    Session token string.
> > > +  @param[in]  RestEx          Rest EX protocol instance.
> > > +
> > > +  @retval     REDFISH_PAYLOAD_PRIVATE  Newly created service.
> > > +  @retval     NULL             Error occurs.
> > > +
> > > +**/
> > > +REDFISH_SERVICE_PRIVATE *
> > > +CreateRedfishService (
> > > +  IN CHAR8                 *Host,
> > > +  IN CHAR8                 *HostName,
> > > +  IN CHAR8                 *BasicAuth OPTIONAL,
> > > +  IN CHAR8                 *SessionToken OPTIONAL,
> > > +  IN EFI_REST_EX_PROTOCOL  *RestEx
> > > +  )
> > > +{
> > > +  REDFISH_SERVICE_PRIVATE  *NewService;
> > > +  UINTN                    AuthStrSize;
> > > +
> > > +  if (IS_EMPTY_STRING (Host) || IS_EMPTY_STRING (HostName) || (RestEx ==
> > NULL)) {
> > > +    return NULL;
> > > +  }
> > > +
> > > +  NewService = AllocateZeroPool (sizeof (REDFISH_SERVICE_PRIVATE));
> > > +  if (NewService == NULL) {
> > > +    return NULL;
> > > +  }
> > > +
> > > +  NewService->Signature = REDFISH_HTTP_SERVICE_SIGNATURE;
> > > +  NewService->Host      = AllocateCopyPool (AsciiStrSize (Host), Host);
> > > +  if (NewService->Host == NULL) {
> > > +    goto ON_ERROR;
> > > +  }
> > > +
> > > +  NewService->HostName = AllocateCopyPool (AsciiStrSize (HostName),
> > HostName);
> > > +  if (NewService->HostName == NULL) {
> > > +    goto ON_ERROR;
> > > +  }
> > > +
> > > +  if (!IS_EMPTY_STRING (BasicAuth)) {
> > > +    AuthStrSize           = AsciiStrSize (BasicAuth) + AsciiStrLen
> > (REDFISH_HTTP_BASIC_AUTH_STR);
> > > +    NewService->BasicAuth = AllocateZeroPool (AuthStrSize);
> > > +    if (NewService->BasicAuth == NULL) {
> > > +      goto ON_ERROR;
> > > +    }
> > > +
> > > +    AsciiSPrint (NewService->BasicAuth, AuthStrSize, "%a%a",
> > REDFISH_HTTP_BASIC_AUTH_STR, BasicAuth);
> > > +  }
> > > +
> > > +  if (!IS_EMPTY_STRING (SessionToken)) {
> > > +    NewService->SessionToken = AllocateCopyPool (AsciiStrSize (SessionToken),
> > SessionToken);
> > > +    if (NewService->SessionToken == NULL) {
> > > +      goto ON_ERROR;
> > > +    }
> > > +  }
> > > +
> > > +  NewService->RestEx = RestEx;
> > > +
> > > +  return NewService;
> > > +
> > > +ON_ERROR:
> > > +
> > > +  ReleaseRedfishService (NewService);
> > > +
> > > +  return NULL;
> > > +}
> > > +
> > > +/**
> > > +  This function release Redfish Payload.
> > > +
> > > +  @param[in]  Payload         Pointer to payload instance.
> > > +
> > > +  @retval     EFI_SUCCESS     Payload is released.
> > > +  @retval     Others          Error occurs.
> > > +
> > > +**/
> > > +EFI_STATUS
> > > +ReleaseRedfishPayload (
> > > +  IN REDFISH_PAYLOAD_PRIVATE  *Payload
> > > +  )
> > > +{
> > > +  if (Payload == NULL) {
> > > +    return EFI_INVALID_PARAMETER;
> > > +  }
> > > +
> > > +  if (Payload->Service != NULL) {
> > > +    ReleaseRedfishService (Payload->Service);
> > > +  }
> > > +
> > > +  if (Payload->JsonValue != NULL) {
> > > +    JsonValueFree (Payload->JsonValue);
> > > +  }
> > > +
> > > +  FreePool (Payload);
> > > +
> > > +  return EFI_SUCCESS;
> > > +}
> > > +
> > > +/**
> > > +  This function creat new payload. Server and JsonObj are
> > > +  copied to newly created payload.
> > > +
> > > +  @param[in]  Service          Pointer to Service instance.
> > > +  @param[in]  JsonValue        Pointer to JSON value.
> > > +
> > > +  @retval     REDFISH_PAYLOAD_PRIVATE  Newly created payload.
> > > +  @retval     NULL                     Error occurs.
> > > +
> > > +**/
> > > +REDFISH_PAYLOAD_PRIVATE *
> > > +CreateRedfishPayload (
> > > +  IN REDFISH_SERVICE_PRIVATE  *Service,
> > > +  IN EDKII_JSON_VALUE         JsonValue
> > > +  )
> > > +{
> > > +  REDFISH_PAYLOAD_PRIVATE  *NewPayload;
> > > +
> > > +  if ((Service == NULL) || (JsonValue == NULL)) {
> > > +    return NULL;
> > > +  }
> > > +
> > > +  NewPayload = AllocateZeroPool (sizeof (REDFISH_PAYLOAD_PRIVATE));
> > > +  if (NewPayload == NULL) {
> > > +    return NULL;
> > > +  }
> > > +
> > > +  NewPayload->Signature = REDFISH_HTTP_PAYLOAD_SIGNATURE;
> > > +  NewPayload->Service   = CreateRedfishService (Service->Host, Service-
> > >HostName, Service->BasicAuth, Service->SessionToken, Service->RestEx);
> > > +  if (NewPayload->Service == NULL) {
> > > +    goto ON_ERROR;
> > > +  }
> > > +
> > > +  NewPayload->JsonValue = JsonValueClone (JsonValue);
> > > +  if (NewPayload->JsonValue == NULL) {
> > > +    goto ON_ERROR;
> > > +  }
> > > +
> > > +  return NewPayload;
> > > +
> > > +ON_ERROR:
> > > +
> > > +  ReleaseRedfishPayload (NewPayload);
> > > +
> >
> >
> > NewPayload->Service  is leaked
> >
> >
> > > +  return NULL;
> > > +}
> > > +
> > > +/**
> > > +  This function copy the data in SrcResponse to DstResponse.
> > > +
> > > +  @param[in]  SrcResponse      Source Response to copy.
> > > +  @param[out] DstResponse      Destination Response.
> > > +
> > > +  @retval     EFI_SUCCESS      Response is copied successfully.
> > > +  @retval     Others           Error occurs.
> > > +
> > > +**/
> > > +EFI_STATUS
> > > +CopyRedfishResponse (
> > > +  IN  REDFISH_RESPONSE  *SrcResponse,
> > > +  OUT REDFISH_RESPONSE  *DstResponse
> > > +  )
> > > +{
> > > +  REDFISH_PAYLOAD_PRIVATE  *Payload;
> > > +  UINTN                    Index;
> > > +
> > > +  if ((SrcResponse == NULL) || (DstResponse == NULL)) {
> > > +    return EFI_INVALID_PARAMETER;
> > > +  }
> > > +
> > > +  if (SrcResponse == DstResponse) {
> > > +    return EFI_SUCCESS;
> > > +  }
> > > +
> > > +  //
> > > +  // Status code
> > > +  //
> > > +  if (SrcResponse->StatusCode != NULL) {
> > > +    DstResponse->StatusCode = AllocateCopyPool (sizeof
> > (EFI_HTTP_STATUS_CODE), SrcResponse->StatusCode);
> > > +    if (DstResponse->StatusCode == NULL) {
> > > +      goto ON_ERROR;
> > > +    }
> > > +  }
> > > +
> > > +  //
> > > +  // Header
> > > +  //
> > > +  if ((SrcResponse->HeaderCount > 0) && (SrcResponse->Headers != NULL)) {
> > > +    DstResponse->HeaderCount = 0;
> > > +    DstResponse->Headers     = AllocateZeroPool (sizeof (EFI_HTTP_HEADER) *
> > SrcResponse->HeaderCount);
> > > +    if (DstResponse->Headers == NULL) {
> > > +      goto ON_ERROR;
> > > +    }
> > > +
> > > +    for (Index = 0; Index < SrcResponse->HeaderCount; Index++) {
> > > +      DstResponse->Headers[Index].FieldName = AllocateCopyPool (AsciiStrSize
> > (SrcResponse->Headers[Index].FieldName), SrcResponse-
> > >Headers[Index].FieldName);
> > > +      if (DstResponse->Headers[Index].FieldName == NULL) {
> > > +        goto ON_ERROR;
> > > +      }
> > > +
> > > +      DstResponse->Headers[Index].FieldValue = AllocateCopyPool (AsciiStrSize
> > (SrcResponse->Headers[Index].FieldValue), SrcResponse-
> > >Headers[Index].FieldValue);
> > > +      if (DstResponse->Headers[Index].FieldValue == NULL) {
> > > +        goto ON_ERROR;
> > > +      }
> > > +
> > > +      DstResponse->HeaderCount += 1;
> > > +    }
> > > +  }
> > > +
> > > +  //
> > > +  // Payload
> > > +  //
> > > +  if (SrcResponse->Payload != NULL) {
> > > +    Payload = (REDFISH_PAYLOAD_PRIVATE *)SrcResponse->Payload;
> > > +    if (Payload->Signature != REDFISH_HTTP_PAYLOAD_SIGNATURE) {
> > > +      DEBUG ((DEBUG_ERROR, "%a: signature check failure\n", __func__));
> > > +      goto ON_ERROR;
> > > +    }
> > > +
> > > +    DstResponse->Payload = CreateRedfishPayload (Payload->Service, Payload-
> > >JsonValue);
> > > +    if (DstResponse->Payload  == NULL) {
> > > +      goto ON_ERROR;
> > > +    }
> > > +  }
> > > +
> > > +  return EFI_SUCCESS;
> > > +
> > > +ON_ERROR:
> > > +
> > > +  ReleaseRedfishResponse (DstResponse);
> > > +
> > > +  return EFI_OUT_OF_RESOURCES;
> > > +}
> > > +
> > > +/**
> > > +  This function clone input response and return to caller
> > > +
> > > +  @param[in]  Response      Response to clone.
> > > +
> > > +  @retval     REDFISH_RESPONSE *  Response is cloned.
> > > +  @retval     NULL                Errors occur.
> > > +
> > > +**/
> > > +REDFISH_RESPONSE *
> > > +CloneRedfishResponse (
> > > +  IN REDFISH_RESPONSE  *Response
> > > +  )
> > > +{
> > > +  EFI_STATUS        Status;
> > > +  REDFISH_RESPONSE  *NewResponse;
> > > +
> > > +  if (Response == NULL) {
> > > +    return NULL;
> > > +  }
> > > +
> > > +  NewResponse = AllocateZeroPool (sizeof (REDFISH_RESPONSE));
> > > +  if (NewResponse == NULL) {
> > > +    return NULL;
> > > +  }
> > > +
> > > +  Status = CopyRedfishResponse (Response, NewResponse);
> > > +  if (EFI_ERROR (Status)) {
> > > +    FreePool (NewResponse);
> > > +    return NULL;
> > > +  }
> > > +
> > > +  return NewResponse;
> > > +}
> > > +
> > > +/**
> > > +  Release REDFISH_HTTP_CACHE_DATA resource
> > > +
> > > +  @param[in]    Data    Pointer to REDFISH_HTTP_CACHE_DATA instance
> > > +
> > > +  @retval EFI_SUCCESS             REDFISH_HTTP_CACHE_DATA is released
> > successfully.
> > > +  @retval EFI_INVALID_PARAMETER   Data is NULL
> > > +
> > > +**/
> > > +EFI_STATUS
> > > +ReleaseHttpCacheData (
> > > +  IN REDFISH_HTTP_CACHE_DATA  *Data
> > > +  )
> > > +{
> > > +  if (Data == NULL) {
> > > +    return EFI_INVALID_PARAMETER;
> > > +  }
> > > +
> > > +  if (Data->Uri != NULL) {
> > > +    FreePool (Data->Uri);
> > > +  }
> > > +
> > > +  if (Data->Response != NULL) {
> > > +    ReleaseRedfishResponse (Data->Response);
> > > +    FreePool (Data->Response);
> > > +  }
> > > +
> > > +  FreePool (Data);
> > > +
> > > +  return EFI_SUCCESS;
> > > +}
> > > +
> > > +/**
> > > +  Create new cache data.
> > > +
> > > +  @param[in]    Uri       The URI string matching to this cache data.
> > > +  @param[in]    Response  HTTP response.
> > > +
> > > +  @retval REDFISH_HTTP_CACHE_DATA *   Pointer to newly created cache
> > data.
> > > +  @retval NULL                        No memory available.
> > > +
> > > +**/
> > > +REDFISH_HTTP_CACHE_DATA *
> > > +NewHttpCacheData (
> > > +  IN  EFI_STRING        Uri,
> > > +  IN  REDFISH_RESPONSE  *Response
> > > +  )
> > > +{
> > > +  REDFISH_HTTP_CACHE_DATA  *NewData;
> > > +  UINTN                    Size;
> > > +
> > > +  if (IS_EMPTY_STRING (Uri) || (Response == NULL)) {
> > > +    return NULL;
> > > +  }
> > > +
> > > +  NewData = AllocateZeroPool (sizeof (REDFISH_HTTP_CACHE_DATA));
> > > +  if (NewData == NULL) {
> > > +    return NULL;
> > > +  }
> > > +
> > > +  NewData->Signature = REDFISH_HTTP_CACHE_SIGNATURE;
> > > +  Size               = StrSize (Uri);
> > > +  NewData->Uri       = AllocateCopyPool (Size, Uri);
> > > +  if (NewData->Uri == NULL) {
> > > +    goto ON_ERROR;
> > > +  }
> > > +
> > > +  NewData->Response = Response;
> > > +  NewData->HitCount = 1;
> > > +
> > > +  return NewData;
> > > +
> > > +ON_ERROR:
> > > +
> > > +  if (NewData != NULL) {
> > > +    ReleaseHttpCacheData (NewData);
> > > +  }
> > > +
> > > +  return NULL;
> > > +}
> > > +
> > > +/**
> > > +  Search on given ListHeader for given URI string.
> > > +
> > > +  @param[in]    ListHeader  Target list to search.
> > > +  @param[in]    Uri         Target URI to search.
> > > +
> > > +  @retval REDFISH_HTTP_CACHE_DATA   Target cache data is found.
> > > +  @retval NULL                      No cache data with given URI is found.
> > > +
> > > +**/
> > > +REDFISH_HTTP_CACHE_DATA *
> > > +FindHttpCacheData (
> > > +  IN  LIST_ENTRY  *ListHeader,
> > > +  IN  EFI_STRING  Uri
> > > +  )
> > > +{
> > > +  LIST_ENTRY               *List;
> > > +  REDFISH_HTTP_CACHE_DATA  *Data;
> > > +
> > > +  if (IS_EMPTY_STRING (Uri)) {
> > > +    return NULL;
> > > +  }
> > > +
> > > +  if (IsListEmpty (ListHeader)) {
> > > +    return NULL;
> > > +  }
> > > +
> > > +  Data = NULL;
> > > +  List = GetFirstNode (ListHeader);
> > > +  while (!IsNull (ListHeader, List)) {
> > > +    Data = REDFISH_HTTP_CACHE_FROM_LIST (List);
> > > +
> > > +    if (StrCmp (Data->Uri, Uri) == 0) {
> > > +      return Data;
> > > +    }
> > > +
> > > +    List = GetNextNode (ListHeader, List);
> > > +  }
> > > +
> > > +  return NULL;
> > > +}
> > > +
> > > +/**
> > > +  Search on given ListHeader and return cache data with minimum hit count.
> > > +
> > > +  @param[in]    ListHeader  Target list to search.
> > > +
> > > +  @retval REDFISH_HTTP_CACHE_DATA   Target cache data is returned.
> > > +  @retval NULL                      No cache data is found.
> > > +
> > > +**/
> > > +REDFISH_HTTP_CACHE_DATA *
> > > +FindUnusedHttpCacheData (
> > > +  IN  LIST_ENTRY  *ListHeader
> > > +  )
> > > +{
> > > +  LIST_ENTRY               *List;
> > > +  REDFISH_HTTP_CACHE_DATA  *Data;
> > > +  REDFISH_HTTP_CACHE_DATA  *UnusedData;
> > > +  UINTN                    HitCount;
> > > +
> > > +  if (IsListEmpty (ListHeader)) {
> > > +    return NULL;
> > > +  }
> > > +
> > > +  Data       = NULL;
> > > +  UnusedData = NULL;
> > > +  HitCount   = 0;
> > > +
> > > +  List       = GetFirstNode (ListHeader);
> > > +  Data       = REDFISH_HTTP_CACHE_FROM_LIST (List);
> > > +  UnusedData = Data;
> > > +  HitCount   = Data->HitCount;
> > > +  List       = GetNextNode (ListHeader, List);
> > > +
> > > +  while (!IsNull (ListHeader, List)) {
> > > +    Data = REDFISH_HTTP_CACHE_FROM_LIST (List);
> > > +
> > > +    if (Data->HitCount < HitCount) {
> > > +      HitCount   = Data->HitCount;
> > > +      UnusedData = Data;
> > > +    }
> > > +
> > > +    List = GetNextNode (ListHeader, List);
> > > +  }
> > > +
> > > +  return UnusedData;
> > > +}
> > > +
> > > +/**
> > > +  Delete a cache data by given cache instance.
> > > +
> > > +  @param[in]    List    Target cache list to be removed.
> > > +  @param[in]    Data    Pointer to the instance to be deleted.
> > > +
> > > +  @retval EFI_SUCCESS   Cache data is removed.
> > > +  @retval Others        Fail to remove cache data.
> > > +
> > > +**/
> > > +EFI_STATUS
> > > +DeleteHttpCacheData (
> > > +  IN  REDFISH_HTTP_CACHE_LIST  *List,
> > > +  IN  REDFISH_HTTP_CACHE_DATA  *Data
> > > +  )
> > > +{
> > > +  if ((List == NULL) || (Data == NULL)) {
> > > +    return EFI_INVALID_PARAMETER;
> > > +  }
> > > +
> > > +  DEBUG ((REDFISH_HTTP_CACHE_DEBUG, "%a: delete: %s\n", __func__,
> > Data->Uri));
> > > +
> > > +  RemoveEntryList (&Data->List);
> > > +  --List->Count;
> > > +
> > > +  return ReleaseHttpCacheData (Data);
> > > +}
> > > +
> > > +/**
> > > +  Add new cache by given URI and HTTP response to specify List.
> > > +
> > > +  @param[in]    List      Target cache list to add.
> > > +  @param[in]    Uri       The URI string matching to this cache data.
> > > +  @param[in]    Response  HTTP response.
> > > +
> > > +  @retval EFI_SUCCESS   Cache data is added.
> > > +  @retval Others        Fail to add cache data.
> > > +
> > > +**/
> > > +EFI_STATUS
> > > +AddHttpCacheData (
> > > +  IN  REDFISH_HTTP_CACHE_LIST  *List,
> > > +  IN  EFI_STRING               Uri,
> > > +  IN  REDFISH_RESPONSE         *Response
> > > +  )
> > > +{
> > > +  REDFISH_HTTP_CACHE_DATA  *NewData;
> > > +  REDFISH_HTTP_CACHE_DATA  *OldData;
> > > +  REDFISH_HTTP_CACHE_DATA  *UnusedData;
> > > +  REDFISH_RESPONSE         *NewResponse;
> > > +
> > > +  if ((List == NULL) || IS_EMPTY_STRING (Uri) || (Response == NULL)) {
> > > +    return EFI_INVALID_PARAMETER;
> > > +  }
> > > +
> > > +  //
> > > +  // If same cache data exist, replace it with latest one.
> > > +  //
> > > +  OldData = FindHttpCacheData (&List->Head, Uri);
> > > +  if (OldData != NULL) {
> > > +    DeleteHttpCacheData (List, OldData);
> > > +  }
> > > +
> > > +  //
> > > +  // Check capacity
> > > +  //
> > > +  if (List->Count >= List->Capacity) {
> > > +    DEBUG ((REDFISH_HTTP_CACHE_DEBUG, "%a: list is full and retire unused
> > cache\n", __func__));
> > > +    UnusedData = FindUnusedHttpCacheData (&List->Head);
> > > +    if (UnusedData == NULL) {
> > > +      return EFI_OUT_OF_RESOURCES;
> > > +    }
> > > +
> > > +    DeleteHttpCacheData (List, UnusedData);
> > > +  }
> > > +
> > > +  //
> > > +  // Clone a local copy
> > > +  //
> > > +  NewResponse = CloneRedfishResponse (Response);
> > > +  if (NewResponse == NULL) {
> > > +    return EFI_OUT_OF_RESOURCES;
> > > +  }
> > > +
> > > +  NewData = NewHttpCacheData (Uri, NewResponse);
> > > +  if (NewData == NULL) {
> > > +    return EFI_OUT_OF_RESOURCES;
> > > +  }
> > > +
> > > +  InsertTailList (&List->Head, &NewData->List);
> > > +  ++List->Count;
> > > +
> > > +  DEBUG ((REDFISH_HTTP_CACHE_DEBUG, "%a: cache(%d/%d) %s\n",
> > __func__, List->Count, List->Capacity, NewData->Uri));
> > > +
> > > +  return EFI_SUCCESS;
> > > +}
> > > +
> > > +/**
> > > +  Release all cache from list.
> > > +
> > > +  @param[in]    CacheList    The list to be released.
> > > +
> > > +  @retval EFI_SUCCESS             All cache data are released.
> > > +  @retval EFI_INVALID_PARAMETER   CacheList is NULL.
> > > +
> > > +**/
> > > +EFI_STATUS
> > > +ReleaseCacheList (
> > > +  IN  REDFISH_HTTP_CACHE_LIST  *CacheList
> > > +  )
> > > +{
> > > +  LIST_ENTRY               *List;
> > > +  LIST_ENTRY               *Next;
> > > +  REDFISH_HTTP_CACHE_DATA  *Data;
> > > +
> > > +  if (CacheList == NULL) {
> > > +    return EFI_INVALID_PARAMETER;
> > > +  }
> > > +
> > > +  if (IsListEmpty (&CacheList->Head)) {
> > > +    return EFI_SUCCESS;
> > > +  }
> > > +
> > > +  Data = NULL;
> > > +  Next = NULL;
> > > +  List = GetFirstNode (&CacheList->Head);
> > > +  while (!IsNull (&CacheList->Head, List)) {
> > > +    Data = REDFISH_HTTP_CACHE_FROM_LIST (List);
> > > +    Next = GetNextNode (&CacheList->Head, List);
> > > +
> > > +    DeleteHttpCacheData (CacheList, Data);
> > > +
> > > +    List = Next;
> > > +  }
> > > +
> > > +  return EFI_SUCCESS;
> > > +}
> > > diff --git a/RedfishPkg/RedfishHttpDxe/RedfishHttpDxe.c
> > b/RedfishPkg/RedfishHttpDxe/RedfishHttpDxe.c
> > > new file mode 100644
> > > index 0000000000..39958d4865
> > > --- /dev/null
> > > +++ b/RedfishPkg/RedfishHttpDxe/RedfishHttpDxe.c
> > > @@ -0,0 +1,1344 @@
> > > +/** @file
> > > +  RedfishHttpDxe produces EdkIIRedfishHttpProtocol
> > > +  for EDK2 Redfish Feature driver to do HTTP operations.
> > > +
> > > +  Copyright (c) 2023-2024, NVIDIA CORPORATION & AFFILIATES. All rights
> > reserved.
> > > +
> > > +  SPDX-License-Identifier: BSD-2-Clause-Patent
> > > +
> > > +**/
> > > +
> > > +#include "RedfishHttpDxe.h"
> > > +#include "RedfishHttpData.h"
> > > +#include "RedfishHttpOperation.h"
> > > +
> > > +REDFISH_HTTP_CACHE_PRIVATE  *mRedfishHttpCachePrivate = NULL;
> > > +
> > > +/**
> > > +  Debug output the cache list.
> > > +
> > > +  @param[in]    Msg            Debug message string.
> > > +  @param[in]    ErrorLevel     Output error level.
> > > +  @param[in]    CacheList      Target list to dump.
> > > +
> > > +  @retval EFI_SUCCESS             Debug dump finished.
> > > +  @retval EFI_INVALID_PARAMETER   HttpCacheList is NULL.
> > > +
> > > +**/
> > > +EFI_STATUS
> > > +DebugPrintHttpCacheList (
> > > +  IN  CONST CHAR8              *Msg,
> > > +  IN  UINTN                    ErrorLevel,
> > > +  IN  REDFISH_HTTP_CACHE_LIST  *CacheList
> > > +  )
> > > +{
> > > +  LIST_ENTRY               *List;
> > > +  REDFISH_HTTP_CACHE_DATA  *Data;
> > > +  UINTN                    Index;
> > > +
> > > +  if (CacheList == NULL) {
> > > +    return EFI_INVALID_PARAMETER;
> > > +  }
> > > +
> > > +  if (!IS_EMPTY_STRING (Msg)) {
> > > +    DEBUG ((ErrorLevel, "%a\n", Msg));
> > > +  }
> > > +
> > > +  if (IsListEmpty (&CacheList->Head)) {
> > > +    DEBUG ((ErrorLevel, "list is empty\n"));
> > > +    return EFI_NOT_FOUND;
> > > +  }
> > > +
> > > +  DEBUG ((ErrorLevel, "list count: %d capacity: %d\n", CacheList->Count,
> > CacheList->Capacity));
> > > +  Data  = NULL;
> > > +  Index = 0;
> > > +  List  = GetFirstNode (&CacheList->Head);
> > > +  while (!IsNull (&CacheList->Head, List)) {
> > > +    Data = REDFISH_HTTP_CACHE_FROM_LIST (List);
> > > +
> > > +    DEBUG ((ErrorLevel, "%d) Uri: %s Hit: %d\n", ++Index, Data->Uri, Data-
> > >HitCount));
> > > +
> > > +    List = GetNextNode (&CacheList->Head, List);
> > > +  }
> > > +
> > > +  return EFI_SUCCESS;
> > > +}
> > > +
> > > +/**
> > > +
> > > +  Check HTTP status code to see if we like to retry HTTP request or not.
> > > +
> > > +  @param[in]  StatusCode      HTTP status code.
> > > +
> > > +  @retval     BOOLEAN         Return true when we like to retry request.
> > > +                              Return false when we don't want to retry request.
> > > +
> > > +**/
> > > +BOOLEAN
> > > +RedfishRetryRequired (
> > > +  IN EFI_HTTP_STATUS_CODE  *StatusCode
> > > +  )
> > > +{
> > > +  if (StatusCode == NULL) {
> > > +    return TRUE;
> > > +  }
> > > +
> > > +  if ((*StatusCode == HTTP_STATUS_500_INTERNAL_SERVER_ERROR) ||
> > > +      (*StatusCode == HTTP_STATUS_UNSUPPORTED_STATUS))
> > > +  {
> > > +    return TRUE;
> > > +  }
> > > +
> > > +  return FALSE;
> > > +}
> > > +
> > > +/**
> > > +
> > > +  Convert Unicode string to ASCII string. It's call responsibility to release
> > returned buffer.
> > > +
> > > +  @param[in]  UnicodeStr      Unicode string to convert.
> > > +
> > > +  @retval     CHAR8 *         ASCII string returned.
> > > +  @retval     NULL            Errors occur.
> > > +
> > > +**/
> > > +CHAR8 *
> > > +StringUnicodeToAscii (
> > > +  IN EFI_STRING  UnicodeStr
> > > +  )
> > > +{
> > > +  CHAR8       *AsciiStr;
> > > +  UINTN       AsciiStrSize;
> > > +  EFI_STATUS  Status;
> > > +
> > > +  if (IS_EMPTY_STRING (UnicodeStr)) {
> > > +    return NULL;
> > > +  }
> > > +
> > > +  AsciiStrSize = StrLen (UnicodeStr) + 1;
> > > +  AsciiStr     = AllocateZeroPool (AsciiStrSize);
> > > +  if (AsciiStr == NULL) {
> > > +    return NULL;
> > > +  }
> > > +
> > > +  Status = UnicodeStrToAsciiStrS (UnicodeStr, AsciiStr, AsciiStrSize);
> > > +  if (EFI_ERROR (Status)) {
> > > +    DEBUG ((DEBUG_ERROR, "UnicodeStrToAsciiStrS failed: %r\n", Status));
> > > +    FreePool (AsciiStr);
> > > +    return NULL;
> > > +  }
> > > +
> > > +  return AsciiStr;
> > > +}
> > > +
> > > +/**
> > > +  Return HTTP method in ASCII string. Caller does not need
> > > +  to free returned string buffer.
> > > +
> > > +  @param[in]  Method         HTTP method.
> > > +
> > > +  @retval CHAR8 *   Method in string.
> > > +**/
> > > +CHAR8 *
> > > +HttpMethodToString (
> > > +  IN  EFI_HTTP_METHOD  Method
> > > +  )
> > > +{
> > > +  switch (Method) {
> > > +    case HttpMethodGet:
> > > +      return HTTP_METHOD_GET;
> > > +      break;
> > > +    case HttpMethodPost:
> > > +      return HTTP_METHOD_POST;
> > > +      break;
> > > +    case HttpMethodPatch:
> > > +      return HTTP_METHOD_PATCH;
> > > +      break;
> > > +    case HttpMethodPut:
> > > +      return HTTP_METHOD_PUT;
> > > +      break;
> > > +    case HttpMethodDelete:
> > > +      return HTTP_METHOD_DELETE;
> > > +      break;
> > > +    default:
> > > +      break;
> > > +  }
> > > +
> > > +  return "Unknown";
> > > +}
> > > +
> > > +/**
> > > +  Report HTTP communication error via report status code.
> > > +
> > > +  @param[in]  Method         HTTP method.
> > > +  @param[in]  Uri            The URI which has failure.
> > > +  @param[in]  HttpStatusCode HTTP status code.
> > > +
> > > +**/
> > > +VOID
> > > +ReportHttpError (
> > > +  IN  EFI_HTTP_METHOD       Method,
> > > +  IN  EFI_STRING            Uri,
> > > +  IN  EFI_HTTP_STATUS_CODE  *HttpStatusCode  OPTIONAL
> > > +  )
> > > +{
> > > +  CHAR8  ErrorMsg[REDFISH_ERROR_MSG_MAX];
> > > +
> > > +  if (IS_EMPTY_STRING (Uri)) {
> > > +    DEBUG ((DEBUG_ERROR, "%a: no URI to report error status\n", __func__));
> > > +    return;
> > > +  }
> > > +
> > > +  //
> > > +  // Report failure of URI and HTTP status code.
> > > +  //
> > > +  AsciiSPrint (ErrorMsg, sizeof (ErrorMsg), REDFISH_HTTP_ERROR_REPORT,
> > HttpMethodToString (Method), (HttpStatusCode == NULL ?
> > HTTP_STATUS_UNSUPPORTED_STATUS : *HttpStatusCode), Uri);
> > > +  DEBUG ((DEBUG_ERROR, "%a\n", ErrorMsg));
> > > +  //
> > > +  // TODO:
> > > +  // Below PI status code is approved by PIWG and wait for specification
> > published.
> > > +  // We will uncomment below report status code after PI status code get
> > published.
> > > +  // REF:
> > https://bugzilla.ti/
> > anocore.org%2Fshow_bug.cgi%3Fid%3D4483&data=05%7C02%7Cnicklew%40nvi
> > dia.com%7Cf659c54c3edb43527c3608dc3462ab2a%7C43083d15727340c1b7db
> > 39efd9ccc17a%7C0%7C0%7C638442845601051396%7CUnknown%7CTWFpbGZs
> > b3d8eyJWIjoiMC4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%
> > 3D%7C0%7C%7C%7C&sdata=T1bN7KmTa1v49cOFkd9%2F9hlzkdzbHPLebxSiUkp
> > VuU4%3D&reserved=0
> > > +  //
> > > +  // REPORT_STATUS_CODE_WITH_EXTENDED_DATA (
> > > +  //  EFI_ERROR_CODE | EFI_ERROR_MAJOR,
> > > +  //  EFI_COMPUTING_UNIT_MANAGEABILITY |
> > EFI_MANAGEABILITY_EC_REDFISH_COMMUNICATION_ERROR,
> > > +  //  ErrorMsg,
> > > +  //  AsciiStrSize (ErrorMsg)
> > > +  //  );
> > > +}
> > > +
> > > +/**
> > > +  This function create Redfish service. It's caller's responsibility to free returned
> > > +  Redfish service by calling FreeService ().
> > > +
> > > +  @param[in]  This                       Pointer to EDKII_REDFISH_HTTP_PROTOCOL
> > instance.
> > > +  @param[in]  RedfishConfigServiceInfo   Redfish config service information.
> > > +
> > > +  @retval     REDFISH_SERVICE  Redfish service is created.
> > > +  @retval     NULL             Errors occur.
> > > +
> > > +**/
> > > +REDFISH_SERVICE
> > > +EFIAPI
> > > +RedfishCreateRedfishService (
> > > +  IN  EDKII_REDFISH_HTTP_PROTOCOL         *This,
> > > +  IN  REDFISH_CONFIG_SERVICE_INFORMATION  *RedfishConfigServiceInfo
> > > +  )
> > > +{
> > > +  EFI_STATUS                  Status;
> > > +  REDFISH_HTTP_CACHE_PRIVATE  *Private;
> > > +  REDFISH_SERVICE_PRIVATE     *NewService;
> > > +  CHAR8                       *AsciiLocation;
> > > +  CHAR8                       *Host;
> > > +  CHAR8                       *BasicAuthString;
> > > +  UINTN                       BasicAuthStrSize;
> > > +  CHAR8                       *EncodedAuthString;
> > > +  UINTN                       EncodedAuthStrSize;
> > > +  EDKII_REDFISH_AUTH_METHOD   AuthMethod;
> > > +  CHAR8                       *Username;
> > > +  CHAR8                       *Password;
> > > +  UINTN                       UsernameSize;
> > > +  UINTN                       PasswordSize;
> > > +  EFI_REST_EX_PROTOCOL        *RestEx;
> > > +
> > > +  if ((This == NULL) || (RedfishConfigServiceInfo == NULL)) {
> > > +    return NULL;
> > > +  }
> > > +
> > > +  DEBUG ((REDFISH_HTTP_CACHE_DEBUG, "%a: service location: %s\n",
> > __func__, RedfishConfigServiceInfo->RedfishServiceLocation));
> > > +
> > > +  Private            = REDFISH_HTTP_CACHE_PRIVATE_FROM_THIS (This);
> > > +  BasicAuthString    = NULL;
> > > +  EncodedAuthString  = NULL;
> > > +  Username           = NULL;
> > > +  Password           = NULL;
> > > +  NewService         = NULL;
> > > +  AsciiLocation      = NULL;
> > > +  Host               = NULL;
> > > +  BasicAuthStrSize   = 0;
> > > +  EncodedAuthStrSize = 0;
> > > +  UsernameSize       = 0;
> > > +  PasswordSize       = 0;
> > > +
> > > +  //
> > > +  // Build host and host name from service location
> > > +  //
> > > +  if (!IS_EMPTY_STRING (RedfishConfigServiceInfo->RedfishServiceLocation)) {
> > > +    AsciiLocation = StringUnicodeToAscii (RedfishConfigServiceInfo-
> > >RedfishServiceLocation);
> > > +    if (AsciiLocation == NULL) {
> > > +      goto ON_RELEASE;
> > > +    }
> > > +
> > > +    Host = AllocateZeroPool (REDFISH_HOST_NAME_MAX);
> > > +    if (AsciiLocation == NULL) {
> > > +      goto ON_RELEASE;
> > > +    }
> > > +
> > > +    if (RedfishConfigServiceInfo->RedfishServiceUseHttps) {
> > > +      AsciiSPrint (Host, REDFISH_HOST_NAME_MAX, "https://%a",
> > AsciiLocation);
> > > +    } else {
> > > +      AsciiSPrint (Host, REDFISH_HOST_NAME_MAX, "http://%a", AsciiLocation);
> > > +    }
> > > +
> > > +    DEBUG ((REDFISH_HTTP_CACHE_DEBUG, "%a: Host: %a\n", __func__,
> > Host));
> > > +  }
> > > +
> > > +  //
> > > +  // Find Rest Ex protocol
> > > +  //
> > > +  if (RedfishConfigServiceInfo->RedfishServiceRestExHandle != NULL) {
> > > +    Status = gBS->HandleProtocol (
> > > +                    RedfishConfigServiceInfo->RedfishServiceRestExHandle,
> > > +                    &gEfiRestExProtocolGuid,
> > > +                    (VOID **)&RestEx
> > > +                    );
> > > +  } else {
> > > +    DEBUG ((DEBUG_ERROR, "%a: Rest Ex protocol is not available\n",
> > __func__));
> > > +    goto ON_RELEASE;
> > > +  }
> > > +
> > > +  //
> > > +  // Get credential
> > > +  //
> > > +  if (Private->CredentialProtocol == NULL) {
> > > +    //
> > > +    // No credential available on this system.
> > > +    //
> > > +    DEBUG ((DEBUG_WARN, "%a: no credential protocol available\n",
> > __func__));
> > > +  } else {
> > > +    Status = Private->CredentialProtocol->GetAuthInfo (
> > > +                                            Private->CredentialProtocol,
> > > +                                            &AuthMethod,
> > > +                                            &Username,
> > > +                                            &Password
> > > +                                            );
> > > +    if (EFI_ERROR (Status) || IS_EMPTY_STRING (Username) ||
> > IS_EMPTY_STRING (Password)) {
> > > +      DEBUG ((DEBUG_ERROR, "%a: cannot get authentication information:
> > %r\n", __func__, Status));
> > > +      goto ON_RELEASE;
> > > +    } else {
> > > +      DEBUG ((REDFISH_HTTP_CACHE_DEBUG, "%a: Auth method: 0x%x
> > username: %a password: %a\n", __func__, AuthMethod, Username, Password));
> > > +
> > > +      //
> > > +      // Perform base64 encoding (RFC 7617)
> > > +      //
> > > +      UsernameSize     = AsciiStrSize (Username);
> > > +      PasswordSize     = AsciiStrSize (Password);
> > > +      BasicAuthStrSize =  UsernameSize + PasswordSize;  // one byte taken from
> > null-terminator for ':'
> > > +      BasicAuthString  = AllocateZeroPool (BasicAuthStrSize);
> > > +      if (BasicAuthString == NULL) {
> > > +        goto ON_RELEASE;
> > > +      }
> > > +
> > > +      AsciiSPrint (
> > > +        BasicAuthString,
> > > +        BasicAuthStrSize,
> > > +        "%a:%a",
> > > +        Username,
> > > +        Password
> > > +        );
> > > +
> > > +      Status = Base64Encode (
> > > +                 (CONST UINT8 *)BasicAuthString,
> > > +                 BasicAuthStrSize,
> > > +                 EncodedAuthString,
> > > +                 &EncodedAuthStrSize
> > > +                 );
> > > +      if ((Status == EFI_BUFFER_TOO_SMALL) && (EncodedAuthStrSize > 0)) {
> > > +        EncodedAuthString = AllocateZeroPool (EncodedAuthStrSize);
> > > +        if (EncodedAuthString == NULL) {
> > > +          goto ON_RELEASE;
> > > +        }
> > > +
> > > +        Status = Base64Encode (
> > > +                   (CONST UINT8 *)BasicAuthString,
> > > +                   BasicAuthStrSize,
> > > +                   EncodedAuthString,
> > > +                   &EncodedAuthStrSize
> > > +                   );
> > > +        if (EFI_ERROR (Status)) {
> > > +          DEBUG ((DEBUG_ERROR, "%a: Base64Encode failure: %r\n", __func__,
> > Status));
> > > +        }
> > > +
> > > +        DEBUG ((REDFISH_HTTP_CACHE_DEBUG, "%a: Basic authorization:
> > %a\n", __func__, EncodedAuthString));
> > > +      } else {
> > > +        DEBUG ((DEBUG_ERROR, "%a: Base64Encode failure: %r\n", __func__,
> > Status));
> > > +        goto ON_RELEASE;
> > > +      }
> > > +    }
> > > +  }
> > > +
> > > +  NewService = CreateRedfishService (Host, AsciiLocation, EncodedAuthString,
> > NULL, RestEx);
> > > +  if (NewService == NULL) {
> > > +    DEBUG ((DEBUG_ERROR, "%a: CreateRedfishService\n", __func__));
> > > +  }
> > > +
> > > +ON_RELEASE:
> > > +
> > > +  if (BasicAuthString != NULL) {
> > > +    ZeroMem (BasicAuthString, BasicAuthStrSize);
> > > +    FreePool (BasicAuthString);
> > > +  }
> > > +
> > > +  if (EncodedAuthString != NULL) {
> > > +    ZeroMem (BasicAuthString, EncodedAuthStrSize);
> > > +    FreePool (EncodedAuthString);
> > > +  }
> > > +
> > > +  if (Username != NULL) {
> > > +    ZeroMem (Username, UsernameSize);
> > > +    FreePool (Username);
> > > +  }
> > > +
> > > +  if (Password != NULL) {
> > > +    ZeroMem (Password, PasswordSize);
> > > +    FreePool (Password);
> > > +  }
> > > +
> > > +  if (AsciiLocation != NULL) {
> > > +    FreePool (AsciiLocation);
> > > +  }
> > > +
> > > +  if (Host != NULL) {
> > > +    FreePool (Host);
> > > +  }
> > > +
> > > +  return NewService;
> > > +}
> > > +
> > > +/**
> > > +  This function free resources in Redfish service. RedfishService is no longer
> > available
> > > +  after this function returns successfully.
> > > +
> > > +  @param[in]  This            Pointer to EDKII_REDFISH_HTTP_PROTOCOL
> > instance.
> > > +  @param[in]  RedfishService  Pointer to Redfish service to be released.
> > > +
> > > +  @retval     EFI_SUCCESS     Resrouce is released successfully.
> > > +  @retval     Others          Errors occur.
> > > +
> > > +**/
> > > +EFI_STATUS
> > > +EFIAPI
> > > +RedfishFreeRedfishService (
> > > +  IN  EDKII_REDFISH_HTTP_PROTOCOL  *This,
> > > +  IN  REDFISH_SERVICE              RedfishService
> > > +  )
> > > +{
> > > +  REDFISH_SERVICE_PRIVATE  *Service;
> > > +
> > > +  if ((This == NULL) || (RedfishService == NULL)) {
> > > +    return EFI_INVALID_PARAMETER;
> > > +  }
> > > +
> > > +  Service = (REDFISH_SERVICE_PRIVATE *)RedfishService;
> > > +  if (Service->Signature != REDFISH_HTTP_SERVICE_SIGNATURE) {
> > > +    DEBUG ((DEBUG_ERROR, "%a: signature check failure\n", __func__));
> > > +  }
> > > +
> > > +  return ReleaseRedfishService (Service);
> > > +}
> > > +
> > > +/**
> > > +  This function returns JSON value in given RedfishPayload. Returned JSON
> > value
> > > +  is a reference to the JSON value in RedfishPayload. Any modification to
> > returned
> > > +  JSON value will change JSON value in RedfishPayload.
> > > +
> > > +  @param[in]  This            Pointer to EDKII_REDFISH_HTTP_PROTOCOL
> > instance.
> > > +  @param[in]  RedfishPayload  Pointer to Redfish payload.
> > > +
> > > +  @retval     EDKII_JSON_VALUE   JSON value is returned.
> > > +  @retval     NULL               Errors occur.
> > > +
> > > +**/
> > > +EDKII_JSON_VALUE
> > > +EFIAPI
> > > +RedfishJsonInRedfishPayload (
> > > +  IN  EDKII_REDFISH_HTTP_PROTOCOL  *This,
> > > +  IN  REDFISH_PAYLOAD              RedfishPayload
> > > +  )
> > > +{
> > > +  REDFISH_PAYLOAD_PRIVATE  *Payload;
> > > +
> > > +  if ((This == NULL) || (RedfishPayload == NULL)) {
> > > +    return NULL;
> > > +  }
> > > +
> > > +  Payload = (REDFISH_PAYLOAD_PRIVATE *)RedfishPayload;
> > > +  if (Payload->Signature != REDFISH_HTTP_PAYLOAD_SIGNATURE) {
> > > +    DEBUG ((DEBUG_ERROR, "%a: signature check failure\n", __func__));
> > > +  }
> > > +
> > > +  return Payload->JsonValue;
> > > +}
> > > +
> > > +/**
> > > +  Perform HTTP GET to Get redfish resource from given resource URI with
> > > +  cache mechanism supported. It's caller's responsibility to free Response
> > > +  by calling FreeResponse ().
> > > +
> > > +  @param[in]  This          Pointer to EDKII_REDFISH_HTTP_PROTOCOL instance.
> > > +  @param[in]  Service       Redfish service instance to perform HTTP GET.
> > > +  @param[in]  Uri           Target resource URI.
> > > +  @param[in]  Request       Additional request context. This is optional.
> > > +  @param[out] Response      HTTP response from redfish service.
> > > +  @param[in]  UseCache      If it is TRUE, this function will search for
> > > +                            cache first. If it is FALSE, this function
> > > +                            will query Redfish URI directly.
> > > +
> > > +  @retval     EFI_SUCCESS     Resrouce is returned successfully.
> > > +  @retval     Others          Errors occur.
> > > +
> > > +**/
> > > +EFI_STATUS
> > > +EFIAPI
> > > +RedfishGetResource (
> > > +  IN  EDKII_REDFISH_HTTP_PROTOCOL  *This,
> > > +  IN  REDFISH_SERVICE              Service,
> > > +  IN  EFI_STRING                   Uri,
> > > +  IN  REDFISH_REQUEST              *Request OPTIONAL,
> > > +  OUT REDFISH_RESPONSE             *Response,
> > > +  IN  BOOLEAN                      UseCache
> > > +  )
> > > +{
> > > +  EFI_STATUS                  Status;
> > > +  REDFISH_HTTP_CACHE_DATA     *CacheData;
> > > +  UINTN                       RetryCount;
> > > +  REDFISH_HTTP_CACHE_PRIVATE  *Private;
> > > +
> > > +  if ((This == NULL) || (Service == NULL) || (Response == NULL) ||
> > IS_EMPTY_STRING (Uri)) {
> > > +    return EFI_INVALID_PARAMETER;
> > > +  }
> > > +
> > > +  DEBUG ((REDFISH_HTTP_CACHE_DEBUG, "%a: Get URI: %s cache: %a\n",
> > __func__, Uri, (UseCache ? "true" : "false")));
> > > +
> > > +  Private    = REDFISH_HTTP_CACHE_PRIVATE_FROM_THIS (This);
> > > +  CacheData  = NULL;
> > > +  RetryCount = 0;
> > > +  ZeroMem (Response, sizeof (REDFISH_RESPONSE));
> > > +
> > > +  if (Private->CacheDisabled) {
> > > +    UseCache = FALSE;
> > > +    DEBUG ((REDFISH_HTTP_CACHE_DEBUG, "%a: cache is disabled by
> > PCD!\n", __func__));
> > > +  }
> > > +
> > > +  //
> > > +  // Search for cache list.
> > > +  //
> > > +  if (UseCache) {
> > > +    CacheData = FindHttpCacheData (&Private->CacheList.Head, Uri);
> > > +    if (CacheData != NULL) {
> > > +      DEBUG ((REDFISH_HTTP_CACHE_DEBUG_REQUEST, "%a: cache hit! %s\n",
> > __func__, Uri));
> > > +
> > > +      //
> > > +      // Copy cached response to caller's buffer.
> > > +      //
> > > +      Status               = CopyRedfishResponse (CacheData->Response, Response);
> > > +      CacheData->HitCount += 1;
> > > +      return Status;
> > > +    }
> > > +  }
> > > +
> > > +  //
> > > +  // Get resource from redfish service.
> > > +  //
> > > +  do {
> > > +    RetryCount += 1;
> > > +    Status      = HttpSendReceive (
> > > +                    Service,
> > > +                    Uri,
> > > +                    HttpMethodGet,
> > > +                    Request,
> > > +                    Response
> > > +                    );
> > > +    DEBUG ((REDFISH_HTTP_CACHE_DEBUG_REQUEST, "%a: HTTP request:
> > %s :%r\n", __func__, Uri, Status));
> > > +    if (!EFI_ERROR (Status) || (RetryCount >= Private-
> > >RetrySetting.MaximumRetryGet)) {
> > > +      break;
> > > +    }
> > > +
> > > +    //
> > > +    // Retry when BMC is not ready.
> > > +    //
> > > +    if ((Response->StatusCode != NULL)) {
> > > +      DEBUG_CODE (
> > > +        DumpRedfishResponse (NULL, DEBUG_ERROR, Response);
> > > +        );
> > > +
> > > +      if (!RedfishRetryRequired (Response->StatusCode)) {
> > > +        break;
> > > +      }
> > > +
> > > +      //
> > > +      // Release response for next round of request.
> > > +      //
> > > +      This->FreeResponse (This, Response);
> > > +    }
> > > +
> > > +    DEBUG ((DEBUG_WARN, "%a: RedfishGetByUriEx failed, retry (%d/%d)\n",
> > __func__, RetryCount, Private->RetrySetting.MaximumRetryGet));
> > > +    if (Private->RetrySetting.RetryWait > 0) {
> > > +      gBS->Stall (Private->RetrySetting.RetryWait);
> > > +    }
> > > +  } while (TRUE);
> > > +
> > > +  if (EFI_ERROR (Status)) {
> > > +    DEBUG_CODE (
> > > +      DumpRedfishResponse (NULL, DEBUG_ERROR, Response);
> > > +      );
> > > +    //
> > > +    // Report status code for Redfish failure
> > > +    //
> > > +    ReportHttpError (HttpMethodGet, Uri, Response->StatusCode);
> > > +    DEBUG ((DEBUG_ERROR, "%a: get %s failed (%d/%d): %r\n", __func__, Uri,
> > RetryCount, Private->RetrySetting.MaximumRetryGet, Status));
> > > +    goto ON_RELEASE;
> > > +  }
> > > +
> > > +  if (!Private->CacheDisabled) {
> > > +    //
> > > +    // Keep response in cache list
> > > +    //
> > > +    Status = AddHttpCacheData (&Private->CacheList, Uri, Response);
> > > +    if (EFI_ERROR (Status)) {
> > > +      DEBUG ((DEBUG_ERROR, "%a: failed to cache %s: %r\n", __func__, Uri,
> > Status));
> > > +      goto ON_RELEASE;
> > > +    }
> > > +
> > > +    DEBUG_CODE (
> > > +      DebugPrintHttpCacheList (__func__,
> > REDFISH_HTTP_CACHE_DEBUG_DUMP, &Private->CacheList);
> > > +      );
> > > +  }
> > > +
> > > +ON_RELEASE:
> > > +
> > > +  return Status;
> > > +}
> > > +
> > > +/**
> > > +  This function free resources in Request. Request is no longer available
> > > +  after this function returns successfully.
> > > +
> > > +  @param[in]  This         Pointer to EDKII_REDFISH_HTTP_PROTOCOL instance.
> > > +  @param[in]  Request      HTTP request to be released.
> > > +
> > > +  @retval     EFI_SUCCESS     Resrouce is released successfully.
> > > +  @retval     Others          Errors occur.
> > > +
> > > +**/
> > > +EFI_STATUS
> > > +EFIAPI
> > > +RedfishFreeRequest (
> > > +  IN  EDKII_REDFISH_HTTP_PROTOCOL  *This,
> > > +  IN  REDFISH_REQUEST              *Request
> > > +  )
> > > +{
> > > +  if ((This == NULL) || (Request == NULL)) {
> > > +    return EFI_INVALID_PARAMETER;
> > > +  }
> > > +
> > > +  DEBUG ((REDFISH_HTTP_CACHE_DEBUG, "%a: entry\n", __func__));
> > > +
> > > +  return ReleaseRedfishRequest (Request);
> > > +}
> > > +
> > > +/**
> > > +  This function free resources in given Response.
> > > +
> > > +  @param[in]  This         Pointer to EDKII_REDFISH_HTTP_PROTOCOL instance.
> > > +  @param[in]  Response     HTTP response to be released.
> > > +
> > > +  @retval     EFI_SUCCESS     Resrouce is released successfully.
> > > +  @retval     Others          Errors occur.
> > > +
> > > +**/
> > > +EFI_STATUS
> > > +EFIAPI
> > > +RedfishFreeResponse (
> > > +  IN  EDKII_REDFISH_HTTP_PROTOCOL  *This,
> > > +  IN  REDFISH_RESPONSE             *Response
> > > +  )
> > > +{
> > > +  if ((This == NULL) || (Response == NULL)) {
> > > +    return EFI_INVALID_PARAMETER;
> > > +  }
> > > +
> > > +  DEBUG ((REDFISH_HTTP_CACHE_DEBUG, "%a: entry\n", __func__));
> > > +
> > > +  return ReleaseRedfishResponse (Response);
> > > +}
> > > +
> > > +/**
> > > +  This function expire the cached response of given URI.
> > > +
> > > +  @param[in]  This         Pointer to EDKII_REDFISH_HTTP_PROTOCOL instance.
> > > +  @param[in]  Uri          Target response of URI.
> > > +
> > > +  @retval     EFI_SUCCESS     Target response is expired successfully.
> > > +  @retval     Others          Errors occur.
> > > +
> > > +**/
> > > +EFI_STATUS
> > > +EFIAPI
> > > +RedfishExpireResponse (
> > > +  IN  EDKII_REDFISH_HTTP_PROTOCOL  *This,
> > > +  IN  EFI_STRING                   Uri
> > > +  )
> > > +{
> > > +  REDFISH_HTTP_CACHE_PRIVATE  *Private;
> > > +  REDFISH_HTTP_CACHE_DATA     *CacheData;
> > > +
> > > +  if ((This == NULL) || IS_EMPTY_STRING (Uri)) {
> > > +    return EFI_INVALID_PARAMETER;
> > > +  }
> > > +
> > > +  DEBUG ((REDFISH_HTTP_CACHE_DEBUG, "%a: expire URI: %s\n", __func__,
> > Uri));
> > > +
> > > +  Private = REDFISH_HTTP_CACHE_PRIVATE_FROM_THIS (This);
> > > +
> > > +  CacheData = FindHttpCacheData (&Private->CacheList.Head, Uri);
> > > +  if (CacheData == NULL) {
> > > +    return EFI_NOT_FOUND;
> > > +  }
> > > +
> > > +  return DeleteHttpCacheData (&Private->CacheList, CacheData);
> > > +}
> > > +
> > > +/**
> > > +  Perform HTTP PATCH to send redfish resource to given resource URI.
> > > +  It's caller's responsibility to free Response by calling FreeResponse ().
> > > +
> > > +  @param[in]  This          Pointer to EDKII_REDFISH_HTTP_PROTOCOL instance.
> > > +  @param[in]  Service       Redfish service instance to perform HTTP PATCH.
> > > +  @param[in]  Uri           Target resource URI.
> > > +  @param[in]  Content       Data to patch.
> > > +  @param[in]  ContentSize   Size of the Content to be send to Redfish service.
> > > +                            This is optional. When ContentSize is 0, ContentSize
> > > +                            is the size of Content.
> > > +  @param[in]  ContentType   Type of the Content to be send to Redfish service.
> > > +                            This is optional. When ContentType is NULL, content
> > > +                            type HTTP_CONTENT_TYPE_APP_JSON will be used.
> > > +  @param[out] Response      HTTP response from redfish service.
> > > +
> > > +  @retval     EFI_SUCCESS     Resrouce is returned successfully.
> > > +  @retval     Others          Errors occur.
> > > +
> > > +**/
> > > +EFI_STATUS
> > > +EFIAPI
> > > +RedfishPatchResource (
> > > +  IN  EDKII_REDFISH_HTTP_PROTOCOL  *This,
> > > +  IN  REDFISH_SERVICE              Service,
> > > +  IN  EFI_STRING                   Uri,
> > > +  IN  CHAR8                        *Content,
> > > +  IN  UINTN                        ContentSize OPTIONAL,
> > > +  IN  CHAR8                        *ContentType OPTIONAL,
> > > +  OUT REDFISH_RESPONSE             *Response
> > > +  )
> > > +{
> > > +  EFI_STATUS                  Status;
> > > +  UINTN                       RetryCount;
> > > +  REDFISH_REQUEST             Request;
> > > +  REDFISH_HTTP_CACHE_PRIVATE  *Private;
> > > +
> > > +  if ((This == NULL) || (Service == NULL) || (Response == NULL) ||
> > IS_EMPTY_STRING (Uri) || IS_EMPTY_STRING (Content)) {
> > > +    return EFI_INVALID_PARAMETER;
> > > +  }
> > > +
> > > +  DEBUG ((REDFISH_HTTP_CACHE_DEBUG, "%a: Patch URI: %s\n", __func__,
> > Uri));
> > > +
> > > +  Private    = REDFISH_HTTP_CACHE_PRIVATE_FROM_THIS (This);
> > > +  RetryCount = 0;
> > > +  ZeroMem (Response, sizeof (REDFISH_RESPONSE));
> > > +  ZeroMem (&Request, sizeof (REDFISH_REQUEST));
> > > +
> > > +  Request.Content       = Content;
> > > +  Request.ContentLength = ContentSize;
> > > +  Request.ContentType   = ContentType;
> > > +
> > > +  //
> > > +  // Patch resource to redfish service.
> > > +  //
> > > +  do {
> > > +    RetryCount += 1;
> > > +    Status      = HttpSendReceive (
> > > +                    Service,
> > > +                    Uri,
> > > +                    HttpMethodPatch,
> > > +                    &Request,
> > > +                    Response
> > > +                    );
> > > +    DEBUG ((REDFISH_HTTP_CACHE_DEBUG_REQUEST, "%a: HTTP request:
> > %s :%r\n", __func__, Uri, Status));
> > > +    if (!EFI_ERROR (Status) || (RetryCount >= Private-
> > >RetrySetting.MaximumRetryPatch)) {
> > > +      break;
> > > +    }
> > > +
> > > +    //
> > > +    // Retry when BMC is not ready.
> > > +    //
> > > +    if ((Response->StatusCode != NULL)) {
> > > +      DEBUG_CODE (
> > > +        DumpRedfishResponse (NULL, DEBUG_ERROR, Response);
> > > +        );
> > > +
> > > +      if (!RedfishRetryRequired (Response->StatusCode)) {
> > > +        break;
> > > +      }
> > > +
> > > +      //
> > > +      // Release response for next round of request.
> > > +      //
> > > +      This->FreeResponse (This, Response);
> > > +    }
> > > +
> > > +    DEBUG ((DEBUG_WARN, "%a: RedfishPatchToUriEx failed, retry (%d/%d)\n",
> > __func__, RetryCount, Private->RetrySetting.MaximumRetryPatch));
> > > +    if (Private->RetrySetting.RetryWait > 0) {
> > > +      gBS->Stall (Private->RetrySetting.RetryWait);
> > > +    }
> > > +  } while (TRUE);
> > > +
> > > +  //
> > > +  // Redfish resource is updated. Automatically expire the cached response
> > > +  // so application can directly get resource from Redfish service again.
> > > +  //
> > > +  DEBUG ((REDFISH_HTTP_CACHE_DEBUG, "%a: Resource is updated, expire
> > URI: %s\n", __func__, Uri));
> > > +  RedfishExpireResponse (This, Uri);
> > > +
> > > +  if (EFI_ERROR (Status)) {
> > > +    DEBUG_CODE (
> > > +      DumpRedfishResponse (NULL, DEBUG_ERROR, Response);
> > > +      );
> > > +    //
> > > +    // Report status code for Redfish failure
> > > +    //
> > > +    ReportHttpError (HttpMethodPatch, Uri, Response->StatusCode);
> > > +    DEBUG ((DEBUG_ERROR, "%a: patch %s failed (%d/%d): %r\n", __func__,
> > Uri, RetryCount, Private->RetrySetting.MaximumRetryPatch, Status));
> > > +    goto ON_RELEASE;
> > > +  }
> > > +
> > > +ON_RELEASE:
> > > +
> > > +  return Status;
> > > +}
> > > +
> > > +/**
> > > +  Perform HTTP PUT to send redfish resource to given resource URI.
> > > +  It's caller's responsibility to free Response by calling FreeResponse ().
> > > +
> > > +  @param[in]  This          Pointer to EDKII_REDFISH_HTTP_PROTOCOL instance.
> > > +  @param[in]  Service       Redfish service instance to perform HTTP PUT.
> > > +  @param[in]  Uri           Target resource URI.
> > > +  @param[in]  Content       Data to put.
> > > +  @param[in]  ContentSize   Size of the Content to be send to Redfish service.
> > > +                            This is optional. When ContentSize is 0, ContentSize
> > > +                            is the size of Content.
> > > +  @param[in]  ContentType   Type of the Content to be send to Redfish service.
> > > +                            This is optional. When ContentType is NULL, content
> > > +                            type HTTP_CONTENT_TYPE_APP_JSON will be used.
> > > +  @param[out] Response      HTTP response from redfish service.
> > > +
> > > +  @retval     EFI_SUCCESS     Resrouce is returned successfully.
> > > +  @retval     Others          Errors occur.
> > > +
> > > +**/
> > > +EFI_STATUS
> > > +EFIAPI
> > > +RedfishPutResource (
> > > +  IN  EDKII_REDFISH_HTTP_PROTOCOL  *This,
> > > +  IN  REDFISH_SERVICE              Service,
> > > +  IN  EFI_STRING                   Uri,
> > > +  IN  CHAR8                        *Content,
> > > +  IN  UINTN                        ContentSize OPTIONAL,
> > > +  IN  CHAR8                        *ContentType OPTIONAL,
> > > +  OUT REDFISH_RESPONSE             *Response
> > > +  )
> > > +{
> > > +  EFI_STATUS                  Status;
> > > +  UINTN                       RetryCount;
> > > +  REDFISH_REQUEST             Request;
> > > +  REDFISH_HTTP_CACHE_PRIVATE  *Private;
> > > +
> > > +  if ((This == NULL) || (Service == NULL) || (Response == NULL) ||
> > IS_EMPTY_STRING (Uri) || IS_EMPTY_STRING (Content)) {
> > > +    return EFI_INVALID_PARAMETER;
> > > +  }
> > > +
> > > +  DEBUG ((REDFISH_HTTP_CACHE_DEBUG, "%a: Put URI: %s\n", __func__,
> > Uri));
> > > +
> > > +  Private    = REDFISH_HTTP_CACHE_PRIVATE_FROM_THIS (This);
> > > +  RetryCount = 0;
> > > +  ZeroMem (Response, sizeof (REDFISH_RESPONSE));
> > > +  ZeroMem (&Request, sizeof (REDFISH_REQUEST));
> > > +
> > > +  Request.Content       = Content;
> > > +  Request.ContentLength = ContentSize;
> > > +  Request.ContentType   = ContentType;
> > > +
> > > +  //
> > > +  // Patch resource to redfish service.
> > > +  //
> > > +  do {
> > > +    RetryCount += 1;
> > > +    Status      = HttpSendReceive (
> > > +                    Service,
> > > +                    Uri,
> > > +                    HttpMethodPut,
> > > +                    &Request,
> > > +                    Response
> > > +                    );
> > > +    DEBUG ((REDFISH_HTTP_CACHE_DEBUG_REQUEST, "%a: HTTP request:
> > %s :%r\n", __func__, Uri, Status));
> > > +    if (!EFI_ERROR (Status) || (RetryCount >= Private-
> > >RetrySetting.MaximumRetryPut)) {
> > > +      break;
> > > +    }
> > > +
> > > +    //
> > > +    // Retry when BMC is not ready.
> > > +    //
> > > +    if ((Response->StatusCode != NULL)) {
> > > +      DEBUG_CODE (
> > > +        DumpRedfishResponse (NULL, DEBUG_ERROR, Response);
> > > +        );
> > > +
> > > +      if (!RedfishRetryRequired (Response->StatusCode)) {
> > > +        break;
> > > +      }
> > > +
> > > +      //
> > > +      // Release response for next round of request.
> > > +      //
> > > +      This->FreeResponse (This, Response);
> > > +    }
> > > +
> > > +    DEBUG ((DEBUG_WARN, "%a: RedfishPutToUri failed, retry (%d/%d)\n",
> > __func__, RetryCount, Private->RetrySetting.MaximumRetryPut));
> > > +    if (Private->RetrySetting.RetryWait > 0) {
> > > +      gBS->Stall (Private->RetrySetting.RetryWait);
> > > +    }
> > > +  } while (TRUE);
> > > +
> > > +  //
> > > +  // Redfish resource is updated. Automatically expire the cached response
> > > +  // so application can directly get resource from Redfish service again.
> > > +  //
> > > +  DEBUG ((REDFISH_HTTP_CACHE_DEBUG, "%a: Resource is updated, expire
> > URI: %s\n", __func__, Uri));
> > > +  RedfishExpireResponse (This, Uri);
> > > +
> > > +  if (EFI_ERROR (Status)) {
> > > +    DEBUG_CODE (
> > > +      DumpRedfishResponse (NULL, DEBUG_ERROR, Response);
> > > +      );
> > > +    //
> > > +    // Report status code for Redfish failure
> > > +    //
> > > +    ReportHttpError (HttpMethodPut, Uri, Response->StatusCode);
> > > +    DEBUG ((DEBUG_ERROR, "%a: put %s failed (%d/%d): %r\n", __func__, Uri,
> > RetryCount, Private->RetrySetting.MaximumRetryPut, Status));
> > > +    goto ON_RELEASE;
> > > +  }
> > > +
> > > +ON_RELEASE:
> > > +
> > > +  return Status;
> > > +}
> > > +
> > > +/**
> > > +  Perform HTTP POST to send redfish resource to given resource URI.
> > > +  It's caller's responsibility to free Response by calling FreeResponse ().
> > > +
> > > +  @param[in]  This          Pointer to EDKII_REDFISH_HTTP_PROTOCOL instance.
> > > +  @param[in]  Service       Redfish service instance to perform HTTP POST.
> > > +  @param[in]  Uri           Target resource URI.
> > > +  @param[in]  Content       Data to post.
> > > +  @param[in]  ContentSize   Size of the Content to be send to Redfish service.
> > > +                            This is optional. When ContentSize is 0, ContentSize
> > > +                            is the size of Content.
> > > +  @param[in]  ContentType   Type of the Content to be send to Redfish service.
> > > +                            This is optional. When ContentType is NULL, content
> > > +                            type HTTP_CONTENT_TYPE_APP_JSON will be used.
> > > +  @param[out] Response      HTTP response from redfish service.
> > > +
> > > +  @retval     EFI_SUCCESS     Resrouce is returned successfully.
> > > +  @retval     Others          Errors occur.
> > > +
> > > +**/
> > > +EFI_STATUS
> > > +EFIAPI
> > > +RedfishPostResource (
> > > +  IN  EDKII_REDFISH_HTTP_PROTOCOL  *This,
> > > +  IN  REDFISH_SERVICE              Service,
> > > +  IN  EFI_STRING                   Uri,
> > > +  IN  CHAR8                        *Content,
> > > +  IN  UINTN                        ContentSize OPTIONAL,
> > > +  IN  CHAR8                        *ContentType OPTIONAL,
> > > +  OUT REDFISH_RESPONSE             *Response
> > > +  )
> > > +{
> > > +  EFI_STATUS                  Status;
> > > +  UINTN                       RetryCount;
> > > +  REDFISH_REQUEST             Request;
> > > +  REDFISH_HTTP_CACHE_PRIVATE  *Private;
> > > +
> > > +  if ((This == NULL) || (Service == NULL) || (Response == NULL) ||
> > IS_EMPTY_STRING (Uri) || IS_EMPTY_STRING (Content)) {
> > > +    return EFI_INVALID_PARAMETER;
> > > +  }
> > > +
> > > +  DEBUG ((REDFISH_HTTP_CACHE_DEBUG, "%a: Post URI: %s\n", __func__,
> > Uri));
> > > +
> > > +  Private    = REDFISH_HTTP_CACHE_PRIVATE_FROM_THIS (This);
> > > +  RetryCount = 0;
> > > +  ZeroMem (Response, sizeof (REDFISH_RESPONSE));
> > > +  ZeroMem (&Request, sizeof (REDFISH_REQUEST));
> > > +
> > > +  Request.Content       = Content;
> > > +  Request.ContentLength = ContentSize;
> > > +  Request.ContentType   = ContentType;
> > > +
> > > +  //
> > > +  // Patch resource to redfish service.
> > > +  //
> > > +  do {
> > > +    RetryCount += 1;
> > > +    Status      = HttpSendReceive (
> > > +                    Service,
> > > +                    Uri,
> > > +                    HttpMethodPost,
> > > +                    &Request,
> > > +                    Response
> > > +                    );
> > > +    DEBUG ((REDFISH_HTTP_CACHE_DEBUG_REQUEST, "%a: HTTP request:
> > %s :%r\n", __func__, Uri, Status));
> > > +    if (!EFI_ERROR (Status) || (RetryCount >= Private-
> > >RetrySetting.MaximumRetryPost)) {
> > > +      break;
> > > +    }
> > > +
> > > +    //
> > > +    // Retry when BMC is not ready.
> > > +    //
> > > +    if ((Response->StatusCode != NULL)) {
> > > +      DEBUG_CODE (
> > > +        DumpRedfishResponse (NULL, DEBUG_ERROR, Response);
> > > +        );
> > > +
> > > +      if (!RedfishRetryRequired (Response->StatusCode)) {
> > > +        break;
> > > +      }
> > > +
> > > +      //
> > > +      // Release response for next round of request.
> > > +      //
> > > +      This->FreeResponse (This, Response);
> > > +    }
> > > +
> > > +    DEBUG ((DEBUG_WARN, "%a: RedfishPostToUri failed, retry (%d/%d)\n",
> > __func__, RetryCount, Private->RetrySetting.MaximumRetryPost));
> > > +    if (Private->RetrySetting.RetryWait > 0) {
> > > +      gBS->Stall (Private->RetrySetting.RetryWait);
> > > +    }
> > > +  } while (TRUE);
> > > +
> > > +  //
> > > +  // Redfish resource is updated. Automatically expire the cached response
> > > +  // so application can directly get resource from Redfish service again.
> > > +  //
> > > +  DEBUG ((REDFISH_HTTP_CACHE_DEBUG, "%a: Resource is updated, expire
> > URI: %s\n", __func__, Uri));
> > > +  RedfishExpireResponse (This, Uri);
> > > +
> > > +  if (EFI_ERROR (Status)) {
> > > +    DEBUG_CODE (
> > > +      DumpRedfishResponse (NULL, DEBUG_ERROR, Response);
> > > +      );
> > > +    //
> > > +    // Report status code for Redfish failure
> > > +    //
> > > +    ReportHttpError (HttpMethodPost, Uri, Response->StatusCode);
> > > +    DEBUG ((DEBUG_ERROR, "%a: post %s failed (%d/%d): %r\n", __func__, Uri,
> > RetryCount, Private->RetrySetting.MaximumRetryPost, Status));
> > > +    goto ON_RELEASE;
> > > +  }
> > > +
> > > +ON_RELEASE:
> > > +
> > > +  return Status;
> > > +}
> > > +
> > > +/**
> > > +  Perform HTTP DELETE to delete redfish resource on given resource URI.
> > > +  It's caller's responsibility to free Response by calling FreeResponse ().
> > > +
> > > +  @param[in]  This          Pointer to EDKII_REDFISH_HTTP_PROTOCOL instance.
> > > +  @param[in]  Service       Redfish service instance to perform HTTP DELETE.
> > > +  @param[in]  Uri           Target resource URI.
> > > +  @param[in]  Content       JSON represented properties to be deleted. This is
> > > +                            optional.
> > > +  @param[in]  ContentSize   Size of the Content to be send to Redfish service.
> > > +                            This is optional. When ContentSize is 0, ContentSize
> > > +                            is the size of Content if Content is not NULL.
> > > +  @param[in]  ContentType   Type of the Content to be send to Redfish service.
> > > +                            This is optional. When Content is not NULL and
> > > +                            ContentType is NULL, content type
> > HTTP_CONTENT_TYPE_APP_JSON
> > > +                            will be used.
> > > +  @param[out] Response      HTTP response from redfish service.
> > > +
> > > +  @retval     EFI_SUCCESS     Resrouce is returned successfully.
> > > +  @retval     Others          Errors occur.
> > > +
> > > +**/
> > > +EFI_STATUS
> > > +EFIAPI
> > > +RedfishDeleteResource (
> > > +  IN  EDKII_REDFISH_HTTP_PROTOCOL  *This,
> > > +  IN  REDFISH_SERVICE              Service,
> > > +  IN  EFI_STRING                   Uri,
> > > +  IN  CHAR8                        *Content OPTIONAL,
> > > +  IN  UINTN                        ContentSize OPTIONAL,
> > > +  IN  CHAR8                        *ContentType OPTIONAL,
> > > +  OUT REDFISH_RESPONSE             *Response
> > > +  )
> > > +{
> > > +  EFI_STATUS                  Status;
> > > +  UINTN                       RetryCount;
> > > +  REDFISH_REQUEST             Request;
> > > +  REDFISH_HTTP_CACHE_PRIVATE  *Private;
> > > +
> > > +  if ((This == NULL) || (Service == NULL) || (Response == NULL) ||
> > IS_EMPTY_STRING (Uri)) {
> > > +    return EFI_INVALID_PARAMETER;
> > > +  }
> > > +
> > > +  DEBUG ((REDFISH_HTTP_CACHE_DEBUG, "%a: Delete URI: %s\n", __func__,
> > Uri));
> > > +
> > > +  Private    = REDFISH_HTTP_CACHE_PRIVATE_FROM_THIS (This);
> > > +  RetryCount = 0;
> > > +  ZeroMem (Response, sizeof (REDFISH_RESPONSE));
> > > +  ZeroMem (&Request, sizeof (REDFISH_REQUEST));
> > > +
> > > +  Request.Content       = Content;
> > > +  Request.ContentLength = ContentSize;
> > > +  Request.ContentType   = ContentType;
> > > +
> > > +  //
> > > +  // Patch resource to redfish service.
> > > +  //
> > > +  do {
> > > +    RetryCount += 1;
> > > +    Status      = HttpSendReceive (
> > > +                    Service,
> > > +                    Uri,
> > > +                    HttpMethodDelete,
> > > +                    &Request,
> > > +                    Response
> > > +                    );
> > > +    DEBUG ((REDFISH_HTTP_CACHE_DEBUG_REQUEST, "%a: HTTP request:
> > %s :%r\n", __func__, Uri, Status));
> > > +    if (!EFI_ERROR (Status) || (RetryCount >= Private-
> > >RetrySetting.MaximumRetryDelete)) {
> > > +      break;
> > > +    }
> > > +
> > > +    //
> > > +    // Retry when BMC is not ready.
> > > +    //
> > > +    if ((Response->StatusCode != NULL)) {
> > > +      DEBUG_CODE (
> > > +        DumpRedfishResponse (NULL, DEBUG_ERROR, Response);
> > > +        );
> > > +
> > > +      if (!RedfishRetryRequired (Response->StatusCode)) {
> > > +        break;
> > > +      }
> > > +
> > > +      //
> > > +      // Release response for next round of request.
> > > +      //
> > > +      This->FreeResponse (This, Response);
> > > +    }
> > > +
> > > +    DEBUG ((DEBUG_WARN, "%a: RedfishDeleteByUri failed, retry (%d/%d)\n",
> > __func__, RetryCount, Private->RetrySetting.MaximumRetryDelete));
> > > +    if (Private->RetrySetting.RetryWait > 0) {
> > > +      gBS->Stall (Private->RetrySetting.RetryWait);
> > > +    }
> > > +  } while (TRUE);
> > > +
> > > +  //
> > > +  // Redfish resource is updated. Automatically expire the cached response
> > > +  // so application can directly get resource from Redfish service again.
> > > +  //
> > > +  DEBUG ((REDFISH_HTTP_CACHE_DEBUG, "%a: Resource is updated, expire
> > URI: %s\n", __func__, Uri));
> > > +  RedfishExpireResponse (This, Uri);
> > > +
> > > +  if (EFI_ERROR (Status)) {
> > > +    DEBUG_CODE (
> > > +      DumpRedfishResponse (NULL, DEBUG_ERROR, Response);
> > > +      );
> > > +    //
> > > +    // Report status code for Redfish failure
> > > +    //
> > > +    ReportHttpError (HttpMethodDelete, Uri, Response->StatusCode);
> > > +    DEBUG ((DEBUG_ERROR, "%a: delete %s failed (%d/%d): %r\n", __func__,
> > Uri, RetryCount, Private->RetrySetting.MaximumRetryDelete, Status));
> > > +    goto ON_RELEASE;
> > > +  }
> > > +
> > > +ON_RELEASE:
> > > +
> > > +  return Status;
> > > +}
> > > +
> > > +EDKII_REDFISH_HTTP_PROTOCOL  mEdkIIRedfishHttpProtocol = {
> > > +  EDKII_REDFISH_HTTP_PROTOCOL_REVISION,
> > > +  RedfishCreateRedfishService,
> > > +  RedfishFreeRedfishService,
> > > +  RedfishJsonInRedfishPayload,
> > > +  RedfishGetResource,
> > > +  RedfishPatchResource,
> > > +  RedfishPutResource,
> > > +  RedfishPostResource,
> > > +  RedfishDeleteResource,
> > > +  RedfishFreeRequest,
> > > +  RedfishFreeResponse,
> > > +  RedfishExpireResponse
> > > +};
> > > +
> > > +/**
> > > +  Unloads an image.
> > > +
> > > +  @param[in]  ImageHandle         Handle that identifies the image to be
> > unloaded.
> > > +
> > > +  @retval EFI_SUCCESS             The image has been unloaded.
> > > +  @retval EFI_INVALID_PARAMETER   ImageHandle is not a valid image
> > handle.
> > > +
> > > +**/
> > > +EFI_STATUS
> > > +EFIAPI
> > > +RedfishHttpDriverUnload (
> > > +  IN EFI_HANDLE  ImageHandle
> > > +  )
> > > +{
> > > +  if (mRedfishHttpCachePrivate == NULL) {
> > > +    return EFI_SUCCESS;
> > > +  }
> > > +
> > > +  if (!IsListEmpty (&mRedfishHttpCachePrivate->CacheList.Head)) {
> > > +    ReleaseCacheList (&mRedfishHttpCachePrivate->CacheList);
> > > +  }
> > > +
> > > +  gBS->UninstallMultipleProtocolInterfaces (
> > > +         ImageHandle,
> > > +         &gEdkIIRedfishHttpProtocolGuid,
> > > +         &mRedfishHttpCachePrivate->Protocol,
> > > +         NULL
> > > +         );
> > > +
> > > +  FreePool (mRedfishHttpCachePrivate);
> > > +  mRedfishHttpCachePrivate = NULL;
> > > +
> > > +  return EFI_SUCCESS;
> > > +}
> > > +
> > > +/**
> > > +  This is a EDKII_REDFISH_CREDENTIAL_PROTOCOL notification event handler.
> > > +
> > > +  @param[in] Event    Event whose notification function is being invoked.
> > > +  @param[in] Context  Pointer to the notification function's context.
> > > +
> > > +**/
> > > +VOID
> > > +EFIAPI
> > > +CredentialProtocolInstalled (
> > > +  IN  EFI_EVENT  Event,
> > > +  IN  VOID       *Context
> > > +  )
> > > +{
> > > +  EFI_STATUS                  Status;
> > > +  REDFISH_HTTP_CACHE_PRIVATE  *Private;
> > > +
> > > +  Private = (REDFISH_HTTP_CACHE_PRIVATE *)Context;
> > > +  if (Private->Signature != REDFISH_HTTP_DRIVER_SIGNATURE) {
> > > +    DEBUG ((DEBUG_ERROR, "%a: signature check failure\n", __func__));
> > > +    return;
> > > +  }
> > > +
> > > +  //
> > > +  // Locate HII database protocol.
> > > +  //
> > > +  Status = gBS->LocateProtocol (
> > > +                  &gEdkIIRedfishCredentialProtocolGuid,
> > > +                  NULL,
> > > +                  (VOID **)&Private->CredentialProtocol
> > > +                  );
> > > +  if (EFI_ERROR (Status)) {
> > > +    return;
> > > +  }
> > > +
> > > +  gBS->CloseEvent (Event);
> > > +}
> > > +
> > > +/**
> > > +  Main entry for this driver.
> > > +
> > > +  @param[in] ImageHandle     Image handle this driver.
> > > +  @param[in] SystemTable     Pointer to SystemTable.
> > > +
> > > +  @retval EFI_SUCCESS     This function always complete successfully.
> > > +
> > > +**/
> > > +EFI_STATUS
> > > +EFIAPI
> > > +RedfishHttpEntryPoint (
> > > +  IN EFI_HANDLE        ImageHandle,
> > > +  IN EFI_SYSTEM_TABLE  *SystemTable
> > > +  )
> > > +{
> > > +  EFI_STATUS  Status;
> > > +  VOID        *Registration;
> > > +
> > > +  if (mRedfishHttpCachePrivate != NULL) {
> > > +    return EFI_ALREADY_STARTED;
> > > +  }
> > > +
> > > +  mRedfishHttpCachePrivate = AllocateZeroPool (sizeof
> > (REDFISH_HTTP_CACHE_PRIVATE));
> > > +  if (mRedfishHttpCachePrivate == NULL) {
> > > +    return EFI_OUT_OF_RESOURCES;
> > > +  }
> > > +
> > > +  //
> > > +  // Initial cache list and protocol instance.
> > > +  //
> > > +  mRedfishHttpCachePrivate->Signature   =
> > REDFISH_HTTP_DRIVER_SIGNATURE;
> > > +  mRedfishHttpCachePrivate->ImageHandle = ImageHandle;
> > > +  CopyMem (&mRedfishHttpCachePrivate->Protocol,
> > &mEdkIIRedfishHttpProtocol, sizeof (EDKII_REDFISH_HTTP_PROTOCOL));
> > > +  mRedfishHttpCachePrivate->CacheList.Capacity =
> > REDFISH_HTTP_CACHE_LIST_SIZE;
> > > +  mRedfishHttpCachePrivate->CacheList.Count    = 0x00;
> > > +  mRedfishHttpCachePrivate->CacheDisabled      = PcdGetBool
> > (PcdHttpCacheDisabled);
> > > +  InitializeListHead (&mRedfishHttpCachePrivate->CacheList.Head);
> > > +
> > > +  //
> > > +  // Get retry settings
> > > +  //
> > > +  mRedfishHttpCachePrivate->RetrySetting.MaximumRetryGet    = PcdGet16
> > (PcdHttpGetRetry);
> > > +  mRedfishHttpCachePrivate->RetrySetting.MaximumRetryPut    = PcdGet16
> > (PcdHttpPutRetry);
> > > +  mRedfishHttpCachePrivate->RetrySetting.MaximumRetryPatch  = PcdGet16
> > (PcdHttpPatchRetry);
> > > +  mRedfishHttpCachePrivate->RetrySetting.MaximumRetryPost   = PcdGet16
> > (PcdHttpPostRetry);
> > > +  mRedfishHttpCachePrivate->RetrySetting.MaximumRetryDelete = PcdGet16
> > (PcdHttpDeleteRetry);
> > > +  mRedfishHttpCachePrivate->RetrySetting.RetryWait          = PcdGet16
> > (PcdHttpRetryWaitInSecond) * 1000000U;
> > > +
> > > +  //
> > > +  // Install the gEdkIIRedfishHttpProtocolGuid onto Handle.
> > > +  //
> > > +  Status = gBS->InstallMultipleProtocolInterfaces (
> > > +                  &mRedfishHttpCachePrivate->ImageHandle,
> > > +                  &gEdkIIRedfishHttpProtocolGuid,
> > > +                  &mRedfishHttpCachePrivate->Protocol,
> > > +                  NULL
> > > +                  );
> > > +  if (EFI_ERROR (Status)) {
> > > +    DEBUG ((DEBUG_ERROR, "%a: cannot install Redfish http protocol: %r\n",
> > __func__, Status));
> > > +    RedfishHttpDriverUnload (ImageHandle);
> > > +    return Status;
> > > +  }
> > > +
> > > +  //
> > > +  // Install protocol notification if credential protocol is installed.
> > > +  //
> > > +  mRedfishHttpCachePrivate->NotifyEvent = EfiCreateProtocolNotifyEvent (
> > > +                                            &gEdkIIRedfishCredentialProtocolGuid,
> > > +                                            TPL_CALLBACK,
> > > +                                            CredentialProtocolInstalled,
> > > +                                            mRedfishHttpCachePrivate,
> > > +                                            &Registration
> > > +                                            );
> > > +  if (mRedfishHttpCachePrivate->NotifyEvent == NULL) {
> > > +    DEBUG ((DEBUG_ERROR, "%a: failed to create protocol notification for
> > gEdkIIRedfishCredentialProtocolGuid\n", __func__));
> > > +    ASSERT (FALSE);
> > > +    RedfishHttpDriverUnload (ImageHandle);
> > > +    return Status;
> > > +  }
> > > +
> > > +  return EFI_SUCCESS;
> > > +}
> > > diff --git a/RedfishPkg/RedfishHttpDxe/RedfishHttpOperation.c
> > b/RedfishPkg/RedfishHttpDxe/RedfishHttpOperation.c
> > > new file mode 100644
> > > index 0000000000..5652818d16
> > > --- /dev/null
> > > +++ b/RedfishPkg/RedfishHttpDxe/RedfishHttpOperation.c
> > > @@ -0,0 +1,693 @@
> > > +/** @file
> > > +  RedfishHttpOperation handles HTTP operations.
> > > +
> > > +  Copyright (c) 2024, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
> > > +
> > > +  SPDX-License-Identifier: BSD-2-Clause-Patent
> > > +
> > > +**/
> > > +
> > > +#include "RedfishHttpOperation.h"
> > > +#include "RedfishHttpData.h"
> > > +
> > > +/**
> > > +  This function copies all headers in SrcHeaders to DstHeaders.
> > > +  It's call responsibility to release returned DstHeaders.
> > > +
> > > +  @param[in]  SrcHeaders      Source headers.
> > > +  @param[in]  SrcHeaderCount  Number of header in source headers.
> > > +  @param[out] DstHeaders      Destination headers.
> > > +  @param[out] DstHeaderCount  Number of header in designation headers.
> > > +
> > > +  @retval     EFI_SUCCESS     Headers are copied successfully.
> > > +  @retval     Others          Errors occur.
> > > +
> > > +**/
> > > +EFI_STATUS
> > > +CopyHttpHeaders (
> > > +  IN  EFI_HTTP_HEADER  *SrcHeaders,
> > > +  IN  UINTN            SrcHeaderCount,
> > > +  OUT EFI_HTTP_HEADER  **DstHeaders,
> > > +  OUT UINTN            *DstHeaderCount
> > > +  )
> > > +{
> > > +  UINTN  Index;
> > > +
> > > +  if ((SrcHeaders == NULL) || (SrcHeaderCount == 0) || (DstHeaders == NULL)
> > || (DstHeaderCount == NULL)) {
> > > +    return EFI_INVALID_PARAMETER;
> > > +  }
> > > +
> > > +  *DstHeaderCount = 0;
> > > +  *DstHeaders     = AllocateZeroPool (sizeof (EFI_HTTP_HEADER) *
> > SrcHeaderCount);
> > > +  if (*DstHeaders == NULL) {
> > > +    return EFI_OUT_OF_RESOURCES;
> > > +  }
> > > +
> > > +  for (Index = 0; Index < SrcHeaderCount; Index++) {
> > > +    (*DstHeaders)[Index].FieldName = AllocateCopyPool (AsciiStrSize
> > (SrcHeaders[Index].FieldName), SrcHeaders[Index].FieldName);
> > > +    if ((*DstHeaders)[Index].FieldName == NULL) {
> > > +      return EFI_OUT_OF_RESOURCES;
> > > +    }
> > > +
> > > +    (*DstHeaders)[Index].FieldValue = AllocateCopyPool (AsciiStrSize
> > (SrcHeaders[Index].FieldValue), SrcHeaders[Index].FieldValue);
> > > +    if ((*DstHeaders)[Index].FieldValue == NULL) {
> > > +      return EFI_OUT_OF_RESOURCES;
> >
> >
> >
> > Looks like orevious allocations leaked.
> > Didn't you think to implement smth like this
> > https://github.co/
> > m%2Ftianocore%2Fedk2%2Fblob%2Fmaster%2FOvmfPkg%2FXenBusDxe%2FHelp
> > ers.c%23L4&data=05%7C02%7Cnicklew%40nvidia.com%7Cf659c54c3edb43527c
> > 3608dc3462ab2a%7C43083d15727340c1b7db39efd9ccc17a%7C0%7C0%7C6384
> > 42845601059719%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLjAwMDAiLCJ
> > QIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C0%7C%7C%7C&sdata=oYv
> > XkfjOpakMOXV1w6nYVphDRuPM7R73lqr8QVqh%2BI4%3D&reserved=0 ?
> >
> >
> > > +    }
> > > +
> > > +    *DstHeaderCount += 1;
> > > +  }
> > > +
> > > +  return EFI_SUCCESS;
> > > +}
> > > +
> > > +/**
> > > +  This function free resources in Request. Request is no longer available
> > > +  after this function returns successfully.
> > > +
> > > +  @param[in]  Request      HTTP request to be released.
> > > +
> > > +  @retval     EFI_SUCCESS     Resrouce is released successfully.
> > > +  @retval     Others          Errors occur.
> > > +
> > > +**/
> > > +EFI_STATUS
> > > +ReleaseRedfishRequest (
> > > +  IN  REDFISH_REQUEST  *Request
> > > +  )
> > > +{
> > > +  if (Request == NULL) {
> > > +    return EFI_INVALID_PARAMETER;
> > > +  }
> > > +
> > > +  if ((Request->Headers != NULL) && (Request->HeaderCount > 0)) {
> > > +    HttpFreeHeaderFields (Request->Headers, Request->HeaderCount);
> > > +    Request->Headers     = NULL;
> > > +    Request->HeaderCount = 0;
> > > +  }
> > > +
> > > +  if (Request->Content != NULL) {
> > > +    FreePool (Request->Content);
> > > +    Request->Content = NULL;
> > > +  }
> > > +
> > > +  if (Request->ContentType != NULL) {
> > > +    FreePool (Request->ContentType);
> > > +    Request->ContentType = NULL;
> > > +  }
> > > +
> > > +  Request->ContentLength = 0;
> > > +
> > > +  return EFI_SUCCESS;
> > > +}
> > > +
> > > +/**
> > > +  This function free resources in given Response.
> > > +
> > > +  @param[in]  Response     HTTP response to be released.
> > > +
> > > +  @retval     EFI_SUCCESS     Resrouce is released successfully.
> > > +  @retval     Others          Errors occur.
> > > +
> > > +**/
> > > +EFI_STATUS
> > > +ReleaseRedfishResponse (
> > > +  IN  REDFISH_RESPONSE  *Response
> > > +  )
> > > +{
> > > +  if (Response == NULL) {
> > > +    return EFI_INVALID_PARAMETER;
> > > +  }
> > > +
> > > +  if ((Response->Headers != NULL) && (Response->HeaderCount > 0)) {
> > > +    HttpFreeHeaderFields (Response->Headers, Response->HeaderCount);
> > > +    Response->Headers     = NULL;
> > > +    Response->HeaderCount = 0;
> > > +  }
> > > +
> > > +  if (Response->Payload != NULL) {
> > > +    ReleaseRedfishPayload (Response->Payload);
> > > +    Response->Payload = NULL;
> > > +  }
> > > +
> > > +  if (Response->StatusCode != NULL) {
> > > +    FreePool (Response->StatusCode);
> > > +    Response->StatusCode = NULL;
> > > +  }
> > > +
> > > +  return EFI_SUCCESS;
> > > +}
> > > +
> > > +/**
> > > +  This function free resources in given HTTP message.
> > > +
> > > +  @param[in]  HttpMessage     HTTP message to be released.
> > > +  @param[in]  IsRequest       TRUE if this is request type of HTTP message.
> > > +                              FALSE if this is response type of HTTP message.
> > > +
> > > +  @retval     EFI_SUCCESS     Resrouce is released successfully.
> > > +  @retval     Others          Errors occur.
> > > +
> > > +**/
> > > +EFI_STATUS
> > > +ReleaseHttpMessage (
> > > +  IN  EFI_HTTP_MESSAGE  *HttpMessage,
> > > +  IN  BOOLEAN           IsRequest
> > > +  )
> > > +{
> > > +  if (HttpMessage == NULL) {
> > > +    return EFI_INVALID_PARAMETER;
> > > +  }
> > > +
> > > +  if (IsRequest) {
> > > +    if (HttpMessage->Data.Request != NULL) {
> > > +      if (HttpMessage->Data.Request->Url != NULL) {
> > > +        FreePool (HttpMessage->Data.Request->Url);
> > > +      }
> > > +
> > > +      FreePool (HttpMessage->Data.Request);
> > > +      HttpMessage->Data.Request = NULL;
> > > +    }
> > > +  } else {
> > > +    if (HttpMessage->Data.Response != NULL) {
> > > +      FreePool (HttpMessage->Data.Response);
> > > +      HttpMessage->Data.Response = NULL;
> > > +    }
> > > +  }
> > > +
> > > +  if (HttpMessage->Body != NULL) {
> > > +    FreePool (HttpMessage->Body);
> > > +    HttpMessage->Body = NULL;
> > > +  }
> > > +
> > > +  if (HttpMessage->Headers != NULL) {
> > > +    HttpFreeHeaderFields (HttpMessage->Headers, HttpMessage-
> > >HeaderCount);
> > > +    HttpMessage->Headers     = NULL;
> > > +    HttpMessage->HeaderCount = 0;
> > > +  }
> > > +
> > > +  return EFI_SUCCESS;
> > > +}
> > > +
> > > +/**
> > > +  This function build Redfish message for sending data to Redfish service.
> > > +  It's call responsibility to properly release returned HTTP message by
> > > +  calling ReleaseHttpMessage.
> > > +
> > > +  @param[in]   ServicePrivate    Pointer to Redfish service private data.
> > > +  @param[in]   Uri               Redfish service URI.
> > > +  @param[in]   Method            HTTP method.
> > > +  @param[in]   Request           Additional data to send to Redfish service.
> > > +                                 This is optional.
> > > +  @param[in]   ContentEncoding   Content encoding method to compress HTTP
> > context.
> > > +                                 This is optional. When ContentEncoding is NULL,
> > > +                                 No compress method will be performed.
> > > +
> > > +  @retval     EFI_HTTP_MESSAGE *   Pointer to newly created HTTP message.
> > > +  @retval     NULL                 Error occurred.
> > > +
> > > +**/
> > > +EFI_HTTP_MESSAGE *
> > > +BuildRequestMessage (
> > > +  IN REDFISH_SERVICE_PRIVATE  *ServicePrivate,
> > > +  IN EFI_STRING               Uri,
> > > +  IN EFI_HTTP_METHOD          Method,
> > > +  IN REDFISH_REQUEST          *Request OPTIONAL,
> > > +  IN CHAR8                    *ContentEncoding OPTIONAL
> > > +  )
> > > +{
> > > +  EFI_STATUS             Status;
> > > +  EFI_STRING             Url;
> > > +  UINTN                  UrlSize;
> > > +  UINTN                  Index;
> > > +  EFI_HTTP_MESSAGE       *RequestMsg;
> > > +  EFI_HTTP_REQUEST_DATA  *RequestData;
> > > +  UINTN                  HeaderCount;
> > > +  UINTN                  HeaderIndex;
> > > +  EFI_HTTP_HEADER        *Headers;
> > > +  CHAR8                  ContentLengthStr[REDFISH_CONTENT_LENGTH_SIZE];
> > > +  VOID                   *Content;
> > > +  UINTN                  ContentLength;
> > > +  BOOLEAN                HasContent;
> > > +  BOOLEAN                DoContentEncoding;
> > > +
> > > +  RequestMsg        = NULL;
> > > +  RequestData       = NULL;
> > > +  Url               = NULL;
> > > +  UrlSize           = 0;
> > > +  Content           = NULL;
> > > +  ContentLength     = 0;
> > > +  HeaderCount       = REDFISH_COMMON_HEADER_SIZE;
> > > +  HeaderIndex       = 0;
> > > +  Headers           = NULL;
> > > +  HasContent        = FALSE;
> > > +  DoContentEncoding = FALSE;
> > > +
> > > +  if ((ServicePrivate == NULL) || (IS_EMPTY_STRING (Uri))) {
> > > +    return NULL;
> > > +  }
> > > +
> > > +  if (Method >= HttpMethodMax) {
> > > +    return NULL;
> > > +  }
> > > +
> > > +  DEBUG ((REDFISH_HTTP_CACHE_DEBUG_REQUEST, "%a: %s\n", __func__,
> > Uri));
> > > +
> > > +  //
> > > +  // Build full URL for HTTP query.
> > > +  //
> > > +  UrlSize = (AsciiStrLen (ServicePrivate->Host) + StrLen (Uri) + 1) * sizeof
> > (CHAR16);
> > > +  Url     = AllocateZeroPool (UrlSize);
> > > +  if (Url == NULL) {
> > > +    return NULL;
> > > +  }
> > > +
> > > +  UnicodeSPrint (Url, UrlSize, L"%a%s", ServicePrivate->Host, Uri);
> > > +  DEBUG ((REDFISH_HTTP_CACHE_DEBUG_REQUEST, "%a: Url: %s\n",
> > __func__, Url));
> > > +
> > > +  //
> > > +  // Step 1: build the HTTP headers.
> > > +  //
> > > +  if (!IS_EMPTY_STRING (ServicePrivate->SessionToken) || !IS_EMPTY_STRING
> > (ServicePrivate->BasicAuth)) {
> > > +    HeaderCount++;
> > > +  }
> > > +
> > > +  if ((Request != NULL) && (Request->HeaderCount > 0)) {
> > > +    HeaderCount += Request->HeaderCount;
> > > +  }
> > > +
> > > +  //
> > > +  // Check and see if we will do content encoding or not
> > > +  //
> > > +  if (!IS_EMPTY_STRING (ContentEncoding)) {
> > > +    if (AsciiStrCmp (ContentEncoding,
> > REDFISH_HTTP_CONTENT_ENCODING_NONE) != 0) {
> > > +      DoContentEncoding = TRUE;
> > > +    }
> > > +  }
> > > +
> > > +  if ((Request != NULL) && !IS_EMPTY_STRING (Request->Content)) {
> > > +    HeaderCount += 2;
> > > +    HasContent   = TRUE;
> > > +    if (DoContentEncoding) {
> > > +      HeaderCount += 1;
> > > +    }
> > > +  }
> > > +
> > > +  Headers = AllocateZeroPool (HeaderCount * sizeof (EFI_HTTP_HEADER));
> > > +  if (Headers == NULL) {
> > > +    goto ON_ERROR;
> > > +  }
> > > +
> > > +  if (!IS_EMPTY_STRING (ServicePrivate->SessionToken)) {
> > > +    Status = HttpSetFieldNameAndValue (&Headers[HeaderIndex++],
> > HTTP_HEADER_X_AUTH_TOKEN, ServicePrivate->SessionToken);
> > > +    if (EFI_ERROR (Status)) {
> > > +      goto ON_ERROR;
> > > +    }
> > > +  } else if (!IS_EMPTY_STRING (ServicePrivate->BasicAuth)) {
> > > +    Status = HttpSetFieldNameAndValue (&Headers[HeaderIndex++],
> > HTTP_HEADER_AUTHORIZATION, ServicePrivate->BasicAuth);
> > > +    if (EFI_ERROR (Status)) {
> > > +      goto ON_ERROR;
> > > +    }
> > > +  }
> > > +
> > > +  if (Request != NULL) {
> > > +    for (Index = 0; Index < Request->HeaderCount; Index++) {
> > > +      Status = HttpSetFieldNameAndValue (&Headers[HeaderIndex++], Request-
> > >Headers[Index].FieldName, Request->Headers[Index].FieldValue);
> > > +      if (EFI_ERROR (Status)) {
> > > +        goto ON_ERROR;
> > > +      }
> > > +    }
> > > +  }
> > > +
> > > +  Status = HttpSetFieldNameAndValue (&Headers[HeaderIndex++],
> > HTTP_HEADER_HOST, ServicePrivate->HostName);
> > > +  if (EFI_ERROR (Status)) {
> > > +    goto ON_ERROR;
> > > +  }
> > > +
> > > +  Status = HttpSetFieldNameAndValue (&Headers[HeaderIndex++],
> > REDFISH_HTTP_HEADER_ODATA_VERSION_STR,
> > REDFISH_HTTP_HEADER_ODATA_VERSION_VALUE);
> > > +  if (EFI_ERROR (Status)) {
> > > +    goto ON_ERROR;
> > > +  }
> > > +
> > > +  Status = HttpSetFieldNameAndValue (&Headers[HeaderIndex++],
> > HTTP_HEADER_ACCEPT, HTTP_CONTENT_TYPE_APP_JSON);
> > > +  if (EFI_ERROR (Status)) {
> > > +    goto ON_ERROR;
> > > +  }
> > > +
> > > +  Status = HttpSetFieldNameAndValue (&Headers[HeaderIndex++],
> > HTTP_HEADER_USER_AGENT, REDFISH_HTTP_HEADER_USER_AGENT_VALUE);
> > > +  if (EFI_ERROR (Status)) {
> > > +    goto ON_ERROR;
> > > +  }
> > > +
> > > +  Status = HttpSetFieldNameAndValue (&Headers[HeaderIndex++],
> > REDFISH_HTTP_HEADER_CONNECTION_STR,
> > REDFISH_HTTP_HEADER_CONNECTION_VALUE);
> > > +  if (EFI_ERROR (Status)) {
> > > +    goto ON_ERROR;
> > > +  }
> > > +
> > > +  //
> > > +  // Handle content header
> > > +  //
> > > +  if (HasContent) {
> > > +    if (Request->ContentType == NULL) {
> > > +      Status = HttpSetFieldNameAndValue (&Headers[HeaderIndex++],
> > HTTP_HEADER_CONTENT_TYPE, HTTP_CONTENT_TYPE_APP_JSON);
> > > +      if (EFI_ERROR (Status)) {
> > > +        goto ON_ERROR;
> > > +      }
> > > +    } else {
> > > +      Status = HttpSetFieldNameAndValue (&Headers[HeaderIndex++],
> > HTTP_HEADER_CONTENT_TYPE, Request->ContentType);
> > > +      if (EFI_ERROR (Status)) {
> > > +        goto ON_ERROR;
> > > +      }
> > > +    }
> > > +
> > > +    if (Request->ContentLength == 0) {
> > > +      Request->ContentLength =  AsciiStrLen (Request->Content);
> > > +    }
> > > +
> > > +    AsciiSPrint (
> > > +      ContentLengthStr,
> > > +      sizeof (ContentLengthStr),
> > > +      "%lu",
> > > +      (UINT64)Request->ContentLength
> > > +      );
> > > +    Status = HttpSetFieldNameAndValue (&Headers[HeaderIndex++],
> > HTTP_HEADER_CONTENT_LENGTH, ContentLengthStr);
> > > +    if (EFI_ERROR (Status)) {
> > > +      goto ON_ERROR;
> > > +    }
> > > +
> > > +    //
> > > +    // Encoding
> > > +    //
> > > +    if (DoContentEncoding) {
> > > +      //
> > > +      // We currently only support gzip Content-Encoding.
> > > +      //
> > > +      Status =  RedfishContentEncode (
> > > +                  ContentEncoding,
> > > +                  Request->Content,
> > > +                  Request->ContentLength,
> > > +                  &Content,
> > > +                  &ContentLength
> > > +                  );
> > > +      if (Status == EFI_INVALID_PARAMETER) {
> > > +        DEBUG ((DEBUG_ERROR, "%a: Error to encode content.\n", __func__));
> > > +        goto ON_ERROR;
> > > +      } else if (Status == EFI_UNSUPPORTED) {
> > > +        DoContentEncoding = FALSE;
> > > +        DEBUG ((REDFISH_HTTP_CACHE_DEBUG_REQUEST, "%a: No content
> > coding for %a! Use raw data instead.\n", __func__, ContentEncoding));
> > > +        Status = HttpSetFieldNameAndValue (&Headers[HeaderIndex++],
> > HTTP_HEADER_CONTENT_ENCODING, HTTP_CONTENT_ENCODING_IDENTITY);
> > > +        if (EFI_ERROR (Status)) {
> > > +          goto ON_ERROR;
> > > +        }
> > > +      } else {
> > > +        Status = HttpSetFieldNameAndValue (&Headers[HeaderIndex++],
> > HTTP_HEADER_CONTENT_ENCODING, HTTP_CONTENT_ENCODING_GZIP);
> > > +        if (EFI_ERROR (Status)) {
> > > +          goto ON_ERROR;
> > > +        }
> > > +      }
> > > +    }
> > > +
> > > +    //
> > > +    // When the content is from caller, we use our own copy so that we properly
> > release it later.
> > > +    //
> > > +    if (!DoContentEncoding) {
> > > +      Content = AllocateCopyPool (Request->ContentLength, Request->Content);
> > > +      if (Content == NULL) {
> > > +        goto ON_ERROR;
> > > +      }
> > > +
> > > +      ContentLength = Request->ContentLength;
> > > +    }
> > > +  }
> > > +
> > > +  //
> > > +  // Step 2: build the rest of HTTP request info.
> > > +  //
> > > +  RequestData = AllocateZeroPool (sizeof (EFI_HTTP_REQUEST_DATA));
> > > +  if (RequestData == NULL) {
> > > +    goto ON_ERROR;
> > > +  }
> > > +
> > > +  RequestData->Method = Method;
> > > +  RequestData->Url    = Url;
> > > +
> > > +  //
> > > +  // Step 3: fill in EFI_HTTP_MESSAGE
> > > +  //
> > > +  RequestMsg = AllocateZeroPool (sizeof (EFI_HTTP_MESSAGE));
> > > +  if (RequestMsg == NULL) {
> > > +    goto ON_ERROR;
> > > +  }
> > > +
> > > +  ASSERT (HeaderIndex == HeaderCount);
> > > +  RequestMsg->Data.Request = RequestData;
> > > +  RequestMsg->HeaderCount  = HeaderIndex;
> > > +  RequestMsg->Headers      = Headers;
> > > +
> > > +  if (HasContent) {
> > > +    RequestMsg->BodyLength = ContentLength;
> > > +    RequestMsg->Body       = Content;
> > > +  }
> > > +
> > > +  return RequestMsg;
> > > +
> > > +ON_ERROR:
> > > +
> > > +  if (Headers != NULL) {
> > > +    HttpFreeHeaderFields (Headers, HeaderIndex);
> > > +  }
> > > +
> > > +  if (RequestData != NULL) {
> > > +    FreePool (RequestData);
> > > +  }
> > > +
> > > +  if (RequestMsg != NULL) {
> > > +    FreePool (RequestMsg);
> > > +  }
> > > +
> > > +  if (Url != NULL) {
> > > +    FreePool (Url);
> > > +  }
> > > +
> > > +  return NULL;
> > > +}
> > > +
> > > +/**
> > > +  This function parse response message from Redfish service, and
> > > +  build Redfish response for caller. It's call responsibility to
> > > +  properly release Redfish response by calling ReleaseRedfishResponse.
> > > +
> > > +  @param[in]   ServicePrivate   Pointer to Redfish service private data.
> > > +  @param[in]   ResponseMsg      Response message from Redfish service.
> > > +  @param[out]  RedfishResponse  Redfish response data.
> > > +
> > > +  @retval     EFI_SUCCESS     Redfish response is returned successfully.
> > > +  @retval     Others          Errors occur.
> > > +
> > > +**/
> > > +EFI_STATUS
> > > +ParseResponseMessage (
> > > +  IN  REDFISH_SERVICE_PRIVATE  *ServicePrivate,
> > > +  IN  EFI_HTTP_MESSAGE         *ResponseMsg,
> > > +  OUT REDFISH_RESPONSE         *RedfishResponse
> > > +  )
> > > +{
> > > +  EFI_STATUS        Status;
> > > +  EDKII_JSON_VALUE  JsonData;
> > > +  EFI_HTTP_HEADER   *ContentEncodedHeader;
> > > +  VOID              *DecodedBody;
> > > +  UINTN             DecodedLength;
> > > +
> > > +  if ((ServicePrivate == NULL) || (ResponseMsg == NULL) || (RedfishResponse
> > == NULL)) {
> > > +    return EFI_INVALID_PARAMETER;
> > > +  }
> > > +
> > > +  DEBUG ((REDFISH_HTTP_CACHE_DEBUG_REQUEST, "%a\n", __func__));
> > > +
> > > +  //
> > > +  // Initialization
> > > +  //
> > > +  JsonData                     = NULL;
> > > +  RedfishResponse->HeaderCount = 0;
> > > +  RedfishResponse->Headers     = NULL;
> > > +  RedfishResponse->Payload     = NULL;
> > > +  RedfishResponse->StatusCode  = NULL;
> > > +  DecodedBody                  = NULL;
> > > +  DecodedLength                = 0;
> > > +
> > > +  //
> > > +  // Return the HTTP StatusCode.
> > > +  //
> > > +  if (ResponseMsg->Data.Response != NULL) {
> > > +    DEBUG ((REDFISH_HTTP_CACHE_DEBUG_REQUEST, "%a: status: %d\n",
> > __func__, ResponseMsg->Data.Response->StatusCode));
> > > +    RedfishResponse->StatusCode = AllocateCopyPool (sizeof
> > (EFI_HTTP_STATUS_CODE), &ResponseMsg->Data.Response->StatusCode);
> > > +    if (RedfishResponse->StatusCode == NULL) {
> > > +      DEBUG ((DEBUG_ERROR, "%a: Failed to create status code.\n", __func__));
> > > +    }
> > > +  }
> > > +
> > > +  //
> > > +  // Return the HTTP headers.
> > > +  //
> > > +  if (ResponseMsg->Headers != NULL) {
> > > +    DEBUG ((REDFISH_HTTP_CACHE_DEBUG_REQUEST, "%a: header count:
> > %d\n", __func__, ResponseMsg->HeaderCount));
> > > +    Status = CopyHttpHeaders (
> > > +               ResponseMsg->Headers,
> > > +               ResponseMsg->HeaderCount,
> > > +               &RedfishResponse->Headers,
> > > +               &RedfishResponse->HeaderCount
> > > +               );
> > > +    if (EFI_ERROR (Status)) {
> > > +      DEBUG ((DEBUG_ERROR, "%a: Failed to copy HTTP headers: %r\n",
> > __func__, Status));
> > > +    }
> > > +  }
> > > +
> > > +  //
> > > +  // Return the HTTP body.
> > > +  //
> > > +  if ((ResponseMsg->BodyLength != 0) && (ResponseMsg->Body != NULL)) {
> > > +    DEBUG ((REDFISH_HTTP_CACHE_DEBUG_REQUEST, "%a: body length:
> > %d\n", __func__, ResponseMsg->BodyLength));
> > > +    //
> > > +    // Check if data is encoded.
> > > +    //
> > > +    ContentEncodedHeader = HttpFindHeader (RedfishResponse->HeaderCount,
> > RedfishResponse->Headers, HTTP_HEADER_CONTENT_ENCODING);
> > > +    if (ContentEncodedHeader != NULL) {
> > > +      //
> > > +      // The content is encoded.
> > > +      //
> > > +      Status = RedfishContentDecode (
> > > +                 ContentEncodedHeader->FieldValue,
> > > +                 ResponseMsg->Body,
> > > +                 ResponseMsg->BodyLength,
> > > +                 &DecodedBody,
> > > +                 &DecodedLength
> > > +                 );
> > > +      if (EFI_ERROR (Status)) {
> > > +        DEBUG ((DEBUG_ERROR, "%a: Failed to decompress the response
> > content: %r decoding method: %a\n.", __func__, Status, ContentEncodedHeader-
> > >FieldValue));
> > > +        goto ON_ERROR;
> > > +      }
> > > +
> > > +      JsonData = JsonLoadBuffer (DecodedBody, DecodedLength, 0, NULL);
> > > +      FreePool (DecodedBody);
> > > +    } else {
> > > +      JsonData = JsonLoadBuffer (ResponseMsg->Body, ResponseMsg-
> > >BodyLength, 0, NULL);
> > > +    }
> > > +
> > > +    if (!JsonValueIsNull (JsonData)) {
> > > +      RedfishResponse->Payload = CreateRedfishPayload (ServicePrivate,
> > JsonData);
> > > +      if (RedfishResponse->Payload == NULL) {
> > > +        DEBUG ((DEBUG_ERROR, "%a: Failed to create payload\n.", __func__));
> > > +      }
> > > +
> > > +      JsonValueFree (JsonData);
> > > +    } else {
> > > +      DEBUG ((DEBUG_ERROR, "%a: No payload available\n", __func__));
> > > +    }
> > > +  }
> > > +
> > > +  return EFI_SUCCESS;
> > > +
> > > +ON_ERROR:
> > > +
> > > +  if (RedfishResponse != NULL) {
> > > +    ReleaseRedfishResponse (RedfishResponse);
> > > +  }
> > > +
> > > +  return Status;
> > > +}
> > > +
> > > +/**
> > > +  This function send Redfish request to Redfish service by calling
> > > +  Rest Ex protocol.
> > > +
> > > +  @param[in]   Service       Pointer to Redfish service.
> > > +  @param[in]   Uri           Uri of Redfish service.
> > > +  @param[in]   Method        HTTP method.
> > > +  @param[in]   Request     Request data. This is optional.
> > > +  @param[out]  Response    Redfish response data.
> > > +
> > > +  @retval     EFI_SUCCESS     Request is sent and received successfully.
> > > +  @retval     Others          Errors occur.
> > > +
> > > +**/
> > > +EFI_STATUS
> > > +HttpSendReceive (
> > > +  IN  REDFISH_SERVICE   Service,
> > > +  IN  EFI_STRING        Uri,
> > > +  IN  EFI_HTTP_METHOD   Method,
> > > +  IN  REDFISH_REQUEST   *Request  OPTIONAL,
> > > +  OUT REDFISH_RESPONSE  *Response
> > > +  )
> > > +{
> > > +  EFI_STATUS               Status;
> > > +  EFI_STATUS               RestExStatus;
> > > +  EFI_HTTP_MESSAGE         *RequestMsg;
> > > +  EFI_HTTP_MESSAGE         ResponseMsg;
> > > +  REDFISH_SERVICE_PRIVATE  *ServicePrivate;
> > > +  EFI_HTTP_HEADER          *XAuthTokenHeader;
> > > +  CHAR8                    *HttpContentEncoding;
> > > +
> > > +  if ((Service == NULL) || IS_EMPTY_STRING (Uri) || (Response == NULL)) {
> > > +    return EFI_INVALID_PARAMETER;
> > > +  }
> > > +
> > > +  DEBUG ((REDFISH_HTTP_CACHE_DEBUG_REQUEST, "%a: Method: 0x%x
> > %s\n", __func__, Method, Uri));
> > > +
> > > +  ServicePrivate = (REDFISH_SERVICE_PRIVATE *)Service;
> > > +  if (ServicePrivate->Signature != REDFISH_HTTP_SERVICE_SIGNATURE) {
> > > +    DEBUG ((DEBUG_ERROR, "%a: signature check failure\n", __func__));
> > > +    return EFI_INVALID_PARAMETER;
> > > +  }
> > > +
> > > +  ZeroMem (&ResponseMsg, sizeof (ResponseMsg));
> > > +  HttpContentEncoding = (CHAR8 *)PcdGetPtr
> > (PcdRedfishServiceContentEncoding);
> > > +
> > > +  RequestMsg = BuildRequestMessage (Service, Uri, Method, Request,
> > HttpContentEncoding);
> > > +  if (RequestMsg == NULL) {
> > > +    DEBUG ((DEBUG_ERROR, "%a: cannot build request message for %s\n",
> > __func__, Uri));
> > > +    return EFI_PROTOCOL_ERROR;
> > > +  }
> > > +
> > > +  //
> > > +  // call RESTEx to get response from REST service.
> > > +  //
> > > +  RestExStatus = ServicePrivate->RestEx->SendReceive (ServicePrivate->RestEx,
> > RequestMsg, &ResponseMsg);
> > > +  if (EFI_ERROR (RestExStatus)) {
> > > +    DEBUG ((DEBUG_ERROR, "%a: %s SendReceive failure: %r\n", __func__,
> > Uri, RestExStatus));
> > > +  }
> > > +
> > > +  //
> > > +  // Return status code, headers and payload to caller as much as possible even
> > when RestEx returns failure.
> > > +  //
> > > +  Status = ParseResponseMessage (ServicePrivate, &ResponseMsg, Response);
> > > +  if (EFI_ERROR (Status)) {
> > > +    DEBUG ((DEBUG_ERROR, "%a: %s parse response failure: %r\n", __func__,
> > Uri, Status));
> > > +  } else {
> > > +    //
> > > +    // Capture session token in header
> > > +    //
> > > +    if ((Method == HttpMethodPost) &&
> > > +        (Response->StatusCode != NULL) &&
> > > +        ((*Response->StatusCode == HTTP_STATUS_200_OK) || (*Response-
> > >StatusCode == HTTP_STATUS_204_NO_CONTENT)))
> > > +    {
> > > +      XAuthTokenHeader = HttpFindHeader (ResponseMsg.HeaderCount,
> > ResponseMsg.Headers, HTTP_HEADER_X_AUTH_TOKEN);
> > > +      if (XAuthTokenHeader != NULL) {
> > > +        Status = UpdateSessionToken (ServicePrivate, XAuthTokenHeader-
> > >FieldValue);
> > > +        if (EFI_ERROR (Status)) {
> > > +          DEBUG ((DEBUG_ERROR, "%a: update session token failure: %r\n",
> > __func__, Status));
> > > +        }
> > > +      }
> > > +    }
> > > +  }
> > > +
> > > +  //
> > > +  // Release resources
> > > +  //
> > > +  if (RequestMsg != NULL) {
> > > +    ReleaseHttpMessage (RequestMsg, TRUE);
> > > +    FreePool (RequestMsg);
> > > +  }
> > > +
> > > +  ReleaseHttpMessage (&ResponseMsg, FALSE);
> > > +
> > > +  return RestExStatus;
> > > +}
> > > diff --git a/RedfishPkg/Redfish.fdf.inc b/RedfishPkg/Redfish.fdf.inc
> > > index 3e5a77766e..5cbe3592fd 100644
> > > --- a/RedfishPkg/Redfish.fdf.inc
> > > +++ b/RedfishPkg/Redfish.fdf.inc
> > > @@ -6,7 +6,7 @@
> > > # to be built in the firmware volume.
> > > #
> > > # (C) Copyright 2020-2021 Hewlett Packard Enterprise Development LP<BR>
> > > -# Copyright (c) 2023, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
> > > +# Copyright (c) 2023-2024, NVIDIA CORPORATION & AFFILIATES. All rights
> > reserved.
> > > #
> > > #    SPDX-License-Identifier: BSD-2-Clause-Patent
> > > #
> > > @@ -20,4 +20,5 @@
> > >   INF RedfishPkg/RedfishConfigHandler/RedfishConfigHandlerDriver.inf
> > >   INF RedfishPkg/RedfishPlatformConfigDxe/RedfishPlatformConfigDxe.inf
> > >   INF
> > MdeModulePkg/Universal/RegularExpressionDxe/RegularExpressionDxe.inf
> > > +  INF RedfishPkg/RedfishHttpDxe/RedfishHttpDxe.inf
> > > !endif
> > > --
> > > 2.34.1
> > >
> > >
> > >
> > > 
> > >
> >
> > Regards,
> > Mike.
> > >


-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#115889): https://edk2.groups.io/g/devel/message/115889
Mute This Topic: https://groups.io/mt/104505404/7686176
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [rebecca@openfw.io]
-=-=-=-=-=-=-=-=-=-=-=-



^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [edk2-devel] [PATCH v2 2/6] RedfishPkg: implement Redfish HTTP protocol
  2024-02-23 16:04     ` Mike Maslenkin
@ 2024-02-26 13:43       ` Nickle Wang via groups.io
  2024-02-27  0:13         ` Mike Maslenkin
  0 siblings, 1 reply; 15+ messages in thread
From: Nickle Wang via groups.io @ 2024-02-26 13:43 UTC (permalink / raw)
  To: Mike Maslenkin
  Cc: devel@edk2.groups.io, Igor Kulchytskyy, Abner Chang, Nick Ramirez

Hi Mike,

> So finally we have
> HttpFreeHeaderFields (Response->Headers, Response->HeaderCount);
> but Response->HeaderCount does not count partially allocated elements. Right?
>
> To fix this, it is required to set
> *DstHeaderCount = SrcHeaderCount unconditionally right after
> DstHeaders  allocation, and HttpFreeHeaderFields() will do the work
> then.

I follow your suggestion to update DstHeaderCount right after DstHeaders is allocated.  So, HttpFreeHeaderFields can release headers correctly. I also create a macro to implemented AsciiStrCpy. Please check below link to see my changes:
https://github.com/tianocore/edk2/compare/0f391b1c2f988d90a3ac723b314ac28ba7b0b8df..f0fa1b8fdcd933beb52fd3127c2476443c00ef8d

Thanks,
Nickle

> -----Original Message-----
> From: Mike Maslenkin <mike.maslenkin@gmail.com>
> Sent: Saturday, February 24, 2024 12:05 AM
> To: Nickle Wang <nicklew@nvidia.com>
> Cc: devel@edk2.groups.io; Igor Kulchytskyy <igork@ami.com>; Abner Chang
> <abner.chang@amd.com>; Nick Ramirez <nramirez@nvidia.com>
> Subject: Re: [edk2-devel] [PATCH v2 2/6] RedfishPkg: implement Redfish HTTP
> protocol
>
> External email: Use caution opening links or attachments
>
>
> Hi Nickle,
>
> On Fri, Feb 23, 2024 at 5:07 PM Nickle Wang <nicklew@nvidia.com> wrote:
> >
> > Thanks for your review, Mike.
> >
> > > %s/Resrouce/Resource/ this comes from RedfishClient autogenerated files...
> >
> > Typos are Addressed. I will send v3 later.
> >
> > >> +ON_ERROR:
> > >> +
> > >> +  ReleaseRedfishPayload (NewPayload);
> > >> +
> > >
> > > NewPayload->Service  is leaked
> >
> > NewPayload->Service will be released in ReleaseRedfishPayload function.
> ReleaseRedfishService() will be called in ReleaseRedfishPayload() when Service is
> not NULL. Please let me know if I misunderstand your comment.
>
> Oh, I see.
> I missed ReleaseRedfishService() call.
>
> >
> >
> > >> +    (*DstHeaders)[Index].FieldValue = AllocateCopyPool (AsciiStrSize
> (SrcHeaders[Index].FieldValue), SrcHeaders[Index].FieldValue);
> > >> +    if ((*DstHeaders)[Index].FieldValue == NULL) {
> > >> +      return EFI_OUT_OF_RESOURCES;
> > >
> > > Looks like orevious allocations leaked.
> > > Didn't you think to implement smth like this ....?
> >
> > Yes, I can implement AsciiStrDup() here. But this won't fix the allocation leaking,
> right? To fix allocation leaking, my idea is to call HttpFreeHeaderFields() before
> returning EFI_OUT_OF_RESOURCES.  HttpFreeHeaderFields() will skip NULL
> FieldName and FieldValue automatically. Does this sound good to you?
> >
> > I think I covered all your comments, but I am bad to find review comment in
> email. If I missed any review comment, please kindly let me know. Thanks!
>
> AsciiStrDup() is not handy here, because it requires preallocated buffer.
> I mentioned about function similar to StrDup just to get shorter and
> cleaner code.
>
> I think I understood the idea now.
> I'm just looking into code and assume that if function returns an
> error, it must deallocate/cleanup resources.
>
> So finally we have
> HttpFreeHeaderFields (Response->Headers, Response->HeaderCount);
> but Response->HeaderCount does not count partially allocated elements. Right?
>
> To fix this, it is required to set
> *DstHeaderCount = SrcHeaderCount unconditionally right after
> DstHeaders  allocation, and HttpFreeHeaderFields() will do the work
> then.
>
> Regards,
> Mike.
>
> >
> > Regards,
> > Nickle
> >
> > > -----Original Message-----
> > > From: Mike Maslenkin <mike.maslenkin@gmail.com>
> > > Sent: Friday, February 23, 2024 7:29 PM
> > > To: devel@edk2.groups.io; Nickle Wang <nicklew@nvidia.com>
> > > Cc: Igor Kulchytskyy <igork@ami.com>; Abner Chang
> <abner.chang@amd.com>;
> > > Nick Ramirez <nramirez@nvidia.com>
> > > Subject: Re: [edk2-devel] [PATCH v2 2/6] RedfishPkg: implement Redfish HTTP
> > > protocol
> > >
> > > External email: Use caution opening links or attachments
> > >
> > >
> > > Hi Nickle,
> > >
> > > %s/Resrouce/Resource/ this comes from RedfishClient autogenerated files...
> > > there are thousands of "Resrouce" typos.
> > >
> > > please, find my minor notes below:
> > >
> > >
> > > On Thu, Feb 22, 2024 at 12:11 PM Nickle Wang via groups.io
> > > <nicklew=nvidia.com@groups.io> wrote:
> > > >
> > > > implement Redfish HTTP protocol driver.
> > > >
> > > > Signed-off-by: Nickle Wang <nicklew@nvidia.com>
> > > > Co-authored-by: Igor Kulchytskyy <igork@ami.com>
> > > > Cc: Abner Chang <abner.chang@amd.com>
> > > > Cc: Igor Kulchytskyy <igork@ami.com>
> > > > Cc: Nick Ramirez <nramirez@nvidia.com>
> > > > ---
> > > > RedfishPkg/RedfishPkg.dec                     |    7 +-
> > > > RedfishPkg/RedfishComponents.dsc.inc          |    3 +-
> > > > RedfishPkg/RedfishPkg.dsc                     |    2 +
> > > > RedfishPkg/RedfishHttpDxe/RedfishHttpDxe.inf  |   73 +
> > > > RedfishPkg/RedfishHttpDxe/RedfishHttpData.h   |  256 ++++
> > > > RedfishPkg/RedfishHttpDxe/RedfishHttpDxe.h    |   44 +
> > > > .../RedfishHttpDxe/RedfishHttpOperation.h     |   76 +
> > > > RedfishPkg/RedfishHttpDxe/RedfishHttpData.c   |  667 ++++++++
> > > > RedfishPkg/RedfishHttpDxe/RedfishHttpDxe.c    | 1344 +++++++++++++++++
> > > > .../RedfishHttpDxe/RedfishHttpOperation.c     |  693 +++++++++
> > > > RedfishPkg/Redfish.fdf.inc                    |    3 +-
> > > > 11 files changed, 3164 insertions(+), 4 deletions(-)
> > > > create mode 100644 RedfishPkg/RedfishHttpDxe/RedfishHttpDxe.inf
> > > > create mode 100644 RedfishPkg/RedfishHttpDxe/RedfishHttpData.h
> > > > create mode 100644 RedfishPkg/RedfishHttpDxe/RedfishHttpDxe.h
> > > > create mode 100644 RedfishPkg/RedfishHttpDxe/RedfishHttpOperation.h
> > > > create mode 100644 RedfishPkg/RedfishHttpDxe/RedfishHttpData.c
> > > > create mode 100644 RedfishPkg/RedfishHttpDxe/RedfishHttpDxe.c
> > > > create mode 100644 RedfishPkg/RedfishHttpDxe/RedfishHttpOperation.c
> > > >
> > > > diff --git a/RedfishPkg/RedfishPkg.dec b/RedfishPkg/RedfishPkg.dec
> > > > index 9b424efdf3..114f8d2ad8 100644
> > > > --- a/RedfishPkg/RedfishPkg.dec
> > > > +++ b/RedfishPkg/RedfishPkg.dec
> > > > @@ -157,8 +157,11 @@
> > > >   # set to EFI_REST_EX_PROTOCOL.
> > > >   #
> > > >
> > >
> gEfiRedfishPkgTokenSpaceGuid.PcdRedfishSendReceiveTimeout|5000|UINT32|0
> > > x00001009
> > > > -  ## This is used to enable HTTP content encoding on Redfish
> communication.
> > > > -
> > >
> gEfiRedfishPkgTokenSpaceGuid.PcdRedfishServiceContentEncoding|TRUE|BOOLE
> > > AN|0x0000100A
> > > > +  #
> > > > +  # This PCD string is introduced for platform developer to set the encoding
> > > method supported by BMC Redfish.
> > > > +  # Currently only "None" and "gzip" are supported.
> > > > +  #
> > > > +
> > >
> gEfiRedfishPkgTokenSpaceGuid.PcdRedfishServiceContentEncoding|"None"|VOID
> > > *|0x0000100A
> > > >   #
> > > >   # Use below PCDs to control Redfhs HTTP protocol.
> > > >   #
> > > > diff --git a/RedfishPkg/RedfishComponents.dsc.inc
> > > b/RedfishPkg/RedfishComponents.dsc.inc
> > > > index 464ffc8606..d6c5b73d7f 100644
> > > > --- a/RedfishPkg/RedfishComponents.dsc.inc
> > > > +++ b/RedfishPkg/RedfishComponents.dsc.inc
> > > > @@ -7,7 +7,7 @@
> > > > # "RedfishDefines.dsc.inc".
> > > > #
> > > > # (C) Copyright 2020-2021 Hewlett Packard Enterprise Development LP<BR>
> > > > -# Copyright (c) 2023, NVIDIA CORPORATION & AFFILIATES. All rights
> reserved.
> > > > +# Copyright (c) 2023-2024, NVIDIA CORPORATION & AFFILIATES. All rights
> > > reserved.
> > > > #
> > > > #    SPDX-License-Identifier: BSD-2-Clause-Patent
> > > > #
> > > > @@ -28,4 +28,5 @@
> > > >   RedfishPkg/RedfishConfigHandler/RedfishConfigHandlerDriver.inf
> > > >   RedfishPkg/RedfishPlatformConfigDxe/RedfishPlatformConfigDxe.inf
> > > >
> MdeModulePkg/Universal/RegularExpressionDxe/RegularExpressionDxe.inf
> > > > +  RedfishPkg/RedfishHttpDxe/RedfishHttpDxe.inf
> > > > !endif
> > > > diff --git a/RedfishPkg/RedfishPkg.dsc b/RedfishPkg/RedfishPkg.dsc
> > > > index 25ed193182..5849e7cf9e 100644
> > > > --- a/RedfishPkg/RedfishPkg.dsc
> > > > +++ b/RedfishPkg/RedfishPkg.dsc
> > > > @@ -45,6 +45,8 @@
> > > >
> > >
> UefiHiiServicesLib|MdeModulePkg/Library/UefiHiiServicesLib/UefiHiiServicesLib.
> > > inf
> > > >
> > >
> RedfishPlatformCredentialLib|RedfishPkg/Library/PlatformCredentialLibNull/Platf
> > > ormCredentialLibNull.inf
> > > >
> > >
> RedfishContentCodingLib|RedfishPkg/Library/RedfishContentCodingLibNull/Redfi
> > > shContentCodingLibNull.inf
> > > > +
> > >
> ReportStatusCodeLib|MdeModulePkg/Library/DxeReportStatusCodeLib/DxeRepo
> > > rtStatusCodeLib.inf
> > > > +  SortLib|MdeModulePkg/Library/UefiSortLib/UefiSortLib.inf
> > > >
> > > >   # NULL instance of IPMI related library.
> > > >   IpmiLib|MdeModulePkg/Library/BaseIpmiLibNull/BaseIpmiLibNull.inf
> > > > diff --git a/RedfishPkg/RedfishHttpDxe/RedfishHttpDxe.inf
> > > b/RedfishPkg/RedfishHttpDxe/RedfishHttpDxe.inf
> > > > new file mode 100644
> > > > index 0000000000..c7dfdffacf
> > > > --- /dev/null
> > > > +++ b/RedfishPkg/RedfishHttpDxe/RedfishHttpDxe.inf
> > > > @@ -0,0 +1,73 @@
> > > > +## @file
> > > > +#  RedfishHttpDxe is the DXE driver which provides
> > > > +#  EdkIIRedfishHttpProtocol to EDK2 Redfish Feature
> > > > +#  drivers for HTTP operation.
> > > > +#
> > > > +#  Copyright (c) 2023-2024, NVIDIA CORPORATION & AFFILIATES. All rights
> > > reserved.
> > > > +#
> > > > +#  SPDX-License-Identifier: BSD-2-Clause-Patent
> > > > +#
> > > > +##
> > > > +
> > > > +[Defines]
> > > > +  INF_VERSION                    = 0x0001000b
> > > > +  BASE_NAME                      = RedfishHttpDxe
> > > > +  FILE_GUID                      = 85ADB2F1-DA93-47D4-AF4F-3D920D9BD2C0
> > > > +  MODULE_TYPE                    = DXE_DRIVER
> > > > +  VERSION_STRING                 = 1.0
> > > > +  ENTRY_POINT                    = RedfishHttpEntryPoint
> > > > +  UNLOAD_IMAGE                   = RedfishHttpDriverUnload
> > > > +
> > > > +#
> > > > +#  VALID_ARCHITECTURES           = IA32 X64 ARM AARCH64 RISCV64
> > > > +#
> > > > +
> > > > +[Sources]
> > > > +  RedfishHttpData.c
> > > > +  RedfishHttpData.h
> > > > +  RedfishHttpDxe.c
> > > > +  RedfishHttpDxe.h
> > > > +  RedfishHttpOperation.c
> > > > +  RedfishHttpOperation.h
> > > > +
> > > > +[Packages]
> > > > +  MdePkg/MdePkg.dec
> > > > +  MdeModulePkg/MdeModulePkg.dec
> > > > +  NetworkPkg/NetworkPkg.dec
> > > > +  RedfishPkg/RedfishPkg.dec
> > > > +
> > > > +[LibraryClasses.ARM]
> > > > +  ArmSoftFloatLib
> > > > +
> > > > +[LibraryClasses]
> > > > +  BaseLib
> > > > +  BaseMemoryLib
> > > > +  RedfishContentCodingLib
> > > > +  DebugLib
> > > > +  HttpLib
> > > > +  JsonLib
> > > > +  MemoryAllocationLib
> > > > +  PrintLib
> > > > +  RedfishDebugLib
> > > > +  ReportStatusCodeLib
> > > > +  UefiBootServicesTableLib
> > > > +  UefiDriverEntryPoint
> > > > +  UefiLib
> > > > +
> > > > +[Protocols]
> > > > +  gEdkIIRedfishHttpProtocolGuid             ## PRODUCED
> > > > +  gEdkIIRedfishCredentialProtocolGuid       ## CONSUMES
> > > > +  gEfiRestExProtocolGuid                    ## CONSUEMS
> > > > +
> > > > +[Pcd]
> > > > +  gEfiRedfishPkgTokenSpaceGuid.PcdHttpGetRetry
> > > > +  gEfiRedfishPkgTokenSpaceGuid.PcdHttpPutRetry
> > > > +  gEfiRedfishPkgTokenSpaceGuid.PcdHttpPatchRetry
> > > > +  gEfiRedfishPkgTokenSpaceGuid.PcdHttpPostRetry
> > > > +  gEfiRedfishPkgTokenSpaceGuid.PcdHttpDeleteRetry
> > > > +  gEfiRedfishPkgTokenSpaceGuid.PcdHttpRetryWaitInSecond
> > > > +  gEfiRedfishPkgTokenSpaceGuid.PcdHttpCacheDisabled
> > > > +  gEfiRedfishPkgTokenSpaceGuid.PcdRedfishServiceContentEncoding
> > > > +
> > > > +[Depex]
> > > > +  TRUE
> > > > diff --git a/RedfishPkg/RedfishHttpDxe/RedfishHttpData.h
> > > b/RedfishPkg/RedfishHttpDxe/RedfishHttpData.h
> > > > new file mode 100644
> > > > index 0000000000..6be610142e
> > > > --- /dev/null
> > > > +++ b/RedfishPkg/RedfishHttpDxe/RedfishHttpData.h
> > > > @@ -0,0 +1,256 @@
> > > > +/** @file
> > > > +  Definitions of RedfishHttpData
> > > > +
> > > > +  Copyright (c) 2023-2024, NVIDIA CORPORATION & AFFILIATES. All rights
> > > reserved.
> > > > +
> > > > +  SPDX-License-Identifier: BSD-2-Clause-Patent
> > > > +
> > > > +**/
> > > > +
> > > > +#ifndef EDKII_REDFISH_HTTP_DATA_H_
> > > > +#define EDKII_REDFISH_HTTP_DATA_H_
> > > > +
> > > > +#include "RedfishHttpDxe.h"
> > > > +
> > > > +#define REDFISH_HTTP_DRIVER_SIGNATURE   SIGNATURE_32 ('r', 'f', 'h',
> 'p')
> > > > +#define REDFISH_HTTP_CACHE_SIGNATURE    SIGNATURE_32 ('r', 'f', 'c',
> 'h')
> > > > +#define REDFISH_HTTP_SERVICE_SIGNATURE  SIGNATURE_32 ('r', 'f', 's',
> 'v')
> > > > +#define REDFISH_HTTP_PAYLOAD_SIGNATURE  SIGNATURE_32 ('r', 'f', 'p',
> 'l')
> > > > +#define REDFISH_HTTP_BASIC_AUTH_STR     "Basic "
> > > > +
> > > > +///
> > > > +/// REDFISH_SERVICE_PRIVATE definition.
> > > > +///
> > > > +typedef struct {
> > > > +  UINT32                  Signature;
> > > > +  CHAR8                   *Host;
> > > > +  CHAR8                   *HostName;
> > > > +  CHAR8                   *BasicAuth;
> > > > +  CHAR8                   *SessionToken;
> > > > +  EFI_REST_EX_PROTOCOL    *RestEx;
> > > > +} REDFISH_SERVICE_PRIVATE;
> > > > +
> > > > +///
> > > > +/// REDFISH_PAYLOAD_PRIVATE definition.
> > > > +///
> > > > +typedef struct {
> > > > +  UINT32                     Signature;
> > > > +  REDFISH_SERVICE_PRIVATE    *Service;
> > > > +  EDKII_JSON_VALUE           JsonValue;
> > > > +} REDFISH_PAYLOAD_PRIVATE;
> > > > +
> > > > +///
> > > > +/// Definition of REDFISH_HTTP_CACHE_DATA
> > > > +///
> > > > +typedef struct {
> > > > +  UINT32              Signature;
> > > > +  LIST_ENTRY          List;
> > > > +  EFI_STRING          Uri;
> > > > +  UINTN               HitCount;
> > > > +  REDFISH_RESPONSE    *Response;
> > > > +} REDFISH_HTTP_CACHE_DATA;
> > > > +
> > > > +#define REDFISH_HTTP_CACHE_FROM_LIST(a)  CR (a,
> > > REDFISH_HTTP_CACHE_DATA, List, REDFISH_HTTP_CACHE_SIGNATURE)
> > > > +
> > > > +///
> > > > +/// Definition of REDFISH_HTTP_CACHE_LIST
> > > > +///
> > > > +typedef struct {
> > > > +  LIST_ENTRY    Head;
> > > > +  UINTN         Count;
> > > > +  UINTN         Capacity;
> > > > +} REDFISH_HTTP_CACHE_LIST;
> > > > +
> > > > +///
> > > > +/// Definition of REDFISH_HTTP_RETRY_SETTING
> > > > +///
> > > > +typedef struct {
> > > > +  UINT16    MaximumRetryGet;
> > > > +  UINT16    MaximumRetryPut;
> > > > +  UINT16    MaximumRetryPost;
> > > > +  UINT16    MaximumRetryPatch;
> > > > +  UINT16    MaximumRetryDelete;
> > > > +  UINTN     RetryWait;
> > > > +} REDFISH_HTTP_RETRY_SETTING;
> > > > +
> > > > +///
> > > > +/// Definition of REDFISH_HTTP_CACHE_PRIVATE
> > > > +///
> > > > +typedef struct {
> > > > +  UINT32                               Signature;
> > > > +  EFI_HANDLE                           ImageHandle;
> > > > +  BOOLEAN                              CacheDisabled;
> > > > +  EFI_EVENT                            NotifyEvent;
> > > > +  REDFISH_HTTP_CACHE_LIST              CacheList;
> > > > +  EDKII_REDFISH_HTTP_PROTOCOL          Protocol;
> > > > +  EDKII_REDFISH_CREDENTIAL_PROTOCOL    *CredentialProtocol;
> > > > +  REDFISH_HTTP_RETRY_SETTING           RetrySetting;
> > > > +} REDFISH_HTTP_CACHE_PRIVATE;
> > > > +
> > > > +#define REDFISH_HTTP_CACHE_PRIVATE_FROM_THIS(a)  CR (a,
> > > REDFISH_HTTP_CACHE_PRIVATE, Protocol,
> REDFISH_HTTP_DRIVER_SIGNATURE)
> > > > +
> > > > +/**
> > > > +  Search on given ListHeader for given URI string.
> > > > +
> > > > +  @param[in]    ListHeader  Target list to search.
> > > > +  @param[in]    Uri         Target URI to search.
> > > > +
> > > > +  @retval REDFISH_HTTP_CACHE_DATA   Target cache data is found.
> > > > +  @retval NULL                      No cache data with given URI is found.
> > > > +
> > > > +**/
> > > > +REDFISH_HTTP_CACHE_DATA *
> > > > +FindHttpCacheData (
> > > > +  IN  LIST_ENTRY  *ListHeader,
> > > > +  IN  EFI_STRING  Uri
> > > > +  );
> > > > +
> > > > +/**
> > > > +  This function copy the data in SrcResponse to DstResponse.
> > > > +
> > > > +  @param[in]  SrcResponse      Source Response to copy.
> > > > +  @param[out] DstResponse      Destination Response.
> > > > +
> > > > +  @retval     EFI_SUCCESS      Response is copied successfully.
> > > > +  @retval     Others           Error occurs.
> > > > +
> > > > +**/
> > > > +EFI_STATUS
> > > > +CopyRedfishResponse (
> > > > +  IN  REDFISH_RESPONSE  *SrcResponse,
> > > > +  OUT REDFISH_RESPONSE  *DstResponse
> > > > +  );
> > > > +
> > > > +/**
> > > > +  Release all cache from list.
> > > > +
> > > > +  @param[in]    CacheList    The list to be released.
> > > > +
> > > > +  @retval EFI_SUCCESS             All cache data are released.
> > > > +  @retval EFI_INVALID_PARAMETER   CacheList is NULL.
> > > > +
> > > > +**/
> > > > +EFI_STATUS
> > > > +ReleaseCacheList (
> > > > +  IN  REDFISH_HTTP_CACHE_LIST  *CacheList
> > > > +  );
> > > > +
> > > > +/**
> > > > +  Add new cache by given URI and HTTP response to specify List.
> > > > +
> > > > +  @param[in]    List      Target cache list to add.
> > > > +  @param[in]    Uri       The URI string matching to this cache data.
> > > > +  @param[in]    Response  HTTP response.
> > > > +
> > > > +  @retval EFI_SUCCESS   Cache data is added.
> > > > +  @retval Others        Fail to add cache data.
> > > > +
> > > > +**/
> > > > +EFI_STATUS
> > > > +AddHttpCacheData (
> > > > +  IN  REDFISH_HTTP_CACHE_LIST  *List,
> > > > +  IN  EFI_STRING               Uri,
> > > > +  IN  REDFISH_RESPONSE         *Response
> > > > +  );
> > > > +
> > > > +/**
> > > > +  Delete a cache data by given cache instance.
> > > > +
> > > > +  @param[in]    List    Target cache list to be removed.
> > > > +  @param[in]    Data    Pointer to the instance to be deleted.
> > > > +
> > > > +  @retval EFI_SUCCESS   Cache data is removed.
> > > > +  @retval Others        Fail to remove cache data.
> > > > +
> > > > +**/
> > > > +EFI_STATUS
> > > > +DeleteHttpCacheData (
> > > > +  IN  REDFISH_HTTP_CACHE_LIST  *List,
> > > > +  IN  REDFISH_HTTP_CACHE_DATA  *Data
> > > > +  );
> > > > +
> > > > +/**
> > > > +  This function release Redfish Payload.
> > > > +
> > > > +  @param[in]  Payload         Pointer to payload instance.
> > > > +
> > > > +  @retval     EFI_SUCCESS     Payload is released.
> > > > +  @retval     Others          Error occurs.
> > > > +
> > > > +**/
> > > > +EFI_STATUS
> > > > +ReleaseRedfishPayload (
> > > > +  IN REDFISH_PAYLOAD_PRIVATE  *Payload
> > > > +  );
> > > > +
> > > > +/**
> > > > +  This function creat new payload. Server and JsonObj are
> > > > +  copied to newly created payload.
> > > > +
> > > > +  @param[in]  Service          Pointer to Service instance.
> > > > +  @param[in]  JsonObj          Pointer to JSON object.
> > > > +
> > > > +  @retval     REDFISH_PAYLOAD_PRIVATE  Newly created payload.
> > > > +  @retval     NULL             Error occurs.
> > > > +
> > > > +**/
> > > > +REDFISH_PAYLOAD_PRIVATE *
> > > > +CreateRedfishPayload (
> > > > +  IN REDFISH_SERVICE_PRIVATE  *Service,
> > > > +  IN EDKII_JSON_VALUE         JsonValue
> > > > +  );
> > > > +
> > > > +/**
> > > > +  This function release Redfish Service.
> > > > +
> > > > +  @param[in]  Service         Pointer to service instance.
> > > > +
> > > > +  @retval     EFI_SUCCESS     Service is released.
> > > > +  @retval     Others          Error occurs.
> > > > +
> > > > +**/
> > > > +EFI_STATUS
> > > > +ReleaseRedfishService (
> > > > +  IN REDFISH_SERVICE_PRIVATE  *Service
> > > > +  );
> > > > +
> > > > +/**
> > > > +  This function creat new service. Host and HostName are copied to
> > > > +  newly created service instance.
> > > > +
> > > > +  @param[in]  Host            Host string.
> > > > +  @param[in]  HostName        Hostname string.
> > > > +  @param[in]  BasicAuth       Basic Authorization string.
> > > > +  @param[in]  SessionToken    Session token string.
> > > > +  @param[in]  RestEx          Rest EX protocol instance.
> > > > +
> > > > +  @retval     REDFISH_PAYLOAD_PRIVATE  Newly created service.
> > > > +  @retval     NULL             Error occurs.
> > > > +
> > > > +**/
> > > > +REDFISH_SERVICE_PRIVATE *
> > > > +CreateRedfishService (
> > > > +  IN CHAR8                 *Host,
> > > > +  IN CHAR8                 *HostName,
> > > > +  IN CHAR8                 *BasicAuth OPTIONAL,
> > > > +  IN CHAR8                 *SessionToken OPTIONAL,
> > > > +  IN EFI_REST_EX_PROTOCOL  *RestEx
> > > > +  );
> > > > +
> > > > +/**
> > > > +  This function update session token in Redfish Service.
> > > > +
> > > > +  @param[in]  Service         Pointer to service instance.
> > > > +  @param[in]  Token           Session token.
> > > > +
> > > > +  @retval     EFI_SUCCESS     Session token is updated.
> > > > +  @retval     Others          Error occurs.
> > > > +
> > > > +**/
> > > > +EFI_STATUS
> > > > +UpdateSessionToken (
> > > > +  IN REDFISH_SERVICE_PRIVATE  *Service,
> > > > +  IN CHAR8                    *Token
> > > > +  );
> > > > +
> > > > +#endif
> > > > diff --git a/RedfishPkg/RedfishHttpDxe/RedfishHttpDxe.h
> > > b/RedfishPkg/RedfishHttpDxe/RedfishHttpDxe.h
> > > > new file mode 100644
> > > > index 0000000000..cf6ba9cb47
> > > > --- /dev/null
> > > > +++ b/RedfishPkg/RedfishHttpDxe/RedfishHttpDxe.h
> > > > @@ -0,0 +1,44 @@
> > > > +/** @file
> > > > +  Definitions of RedfishHttpDxe
> > > > +
> > > > +  Copyright (c) 2023-2024, NVIDIA CORPORATION & AFFILIATES. All rights
> > > reserved.
> > > > +
> > > > +  SPDX-License-Identifier: BSD-2-Clause-Patent
> > > > +
> > > > +**/
> > > > +
> > > > +#ifndef EDKII_REDFISH_HTTP_DXE_H_
> > > > +#define EDKII_REDFISH_HTTP_DXE_H_
> > > > +
> > > > +#include <Uefi.h>
> > > > +#include <IndustryStandard/Http11.h>
> > > > +
> > > > +#include <Library/UefiLib.h>
> > > > +#include <Library/BaseLib.h>
> > > > +#include <Library/BaseMemoryLib.h>
> > > > +#include <Library/RedfishContentCodingLib.h>
> > > > +#include <Library/DebugLib.h>
> > > > +#include <Library/HttpLib.h>
> > > > +#include <Library/JsonLib.h>
> > > > +#include <Library/UefiBootServicesTableLib.h>
> > > > +#include <Library/MemoryAllocationLib.h>
> > > > +#include <Library/RedfishDebugLib.h>
> > > > +#include <Library/ReportStatusCodeLib.h>
> > > > +#include <Library/PrintLib.h>
> > > > +
> > > > +#include <Protocol/Http.h>
> > > > +#include <Protocol/EdkIIRedfishHttpProtocol.h>
> > > > +#include <Protocol/EdkIIRedfishCredential.h>
> > > > +#include <Protocol/RestEx.h>
> > > > +
> > > > +#define IS_EMPTY_STRING(a)  ((a) == NULL || (a)[0] == '\0')
> > > > +#define REDFISH_HTTP_CACHE_LIST_SIZE      0x80
> > > > +#define REDFISH_ERROR_MSG_MAX             128
> > > > +#define REDFISH_DEBUG_STRING_LENGTH       200
> > > > +#define REDFISH_HOST_NAME_MAX             64   // IPv6 maximum length
> (39)
> > > + "https://" (8) + port number (maximum 5)
> > > > +#define REDFISH_HTTP_ERROR_REPORT         "Redfish HTTP %a
> failure(0x%x):
> > > %s"
> > > > +#define REDFISH_HTTP_CACHE_DEBUG          DEBUG_MANAGEABILITY
> > > > +#define REDFISH_HTTP_CACHE_DEBUG_DUMP
> DEBUG_MANAGEABILITY
> > > > +#define REDFISH_HTTP_CACHE_DEBUG_REQUEST
> DEBUG_MANAGEABILITY
> > > > +
> > > > +#endif
> > > > diff --git a/RedfishPkg/RedfishHttpDxe/RedfishHttpOperation.h
> > > b/RedfishPkg/RedfishHttpDxe/RedfishHttpOperation.h
> > > > new file mode 100644
> > > > index 0000000000..d2f7cf4c27
> > > > --- /dev/null
> > > > +++ b/RedfishPkg/RedfishHttpDxe/RedfishHttpOperation.h
> > > > @@ -0,0 +1,76 @@
> > > > +/** @file
> > > > +  Definitions of RedfishHttpOperation
> > > > +
> > > > +  Copyright (c) 2024, NVIDIA CORPORATION & AFFILIATES. All rights
> reserved.
> > > > +
> > > > +  SPDX-License-Identifier: BSD-2-Clause-Patent
> > > > +
> > > > +**/
> > > > +
> > > > +#ifndef EDKII_REDFISH_HTTP_OPERATION_H_
> > > > +#define EDKII_REDFISH_HTTP_OPERATION_H_
> > > > +
> > > > +#include "RedfishHttpDxe.h"
> > > > +
> > > > +#define REDFISH_CONTENT_LENGTH_SIZE              80
> > > > +#define REDFISH_COMMON_HEADER_SIZE               5
> > > > +#define REDFISH_HTTP_HEADER_ODATA_VERSION_STR    "OData-
> Version"
> > > > +#define REDFISH_HTTP_HEADER_ODATA_VERSION_VALUE  "4.0"
> > > > +#define REDFISH_HTTP_HEADER_USER_AGENT_VALUE     "edk2redfish"
> > > > +#define REDFISH_HTTP_HEADER_CONNECTION_STR       "Connection"
> > > > +#define REDFISH_HTTP_HEADER_CONNECTION_VALUE     "Keep-Alive"
> > > > +#define REDFISH_HTTP_CONTENT_ENCODING_NONE       "None"
> > > > +
> > > > +/**
> > > > +  This function free resources in Request. Request is no longer available
> > > > +  after this function returns successfully.
> > > > +
> > > > +  @param[in]  Request      HTTP request to be released.
> > > > +
> > > > +  @retval     EFI_SUCCESS     Resrouce is released successfully.
> > > > +  @retval     Others          Errors occur.
> > > > +
> > > > +**/
> > > > +EFI_STATUS
> > > > +ReleaseRedfishRequest (
> > > > +  IN  REDFISH_REQUEST  *Request
> > > > +  );
> > > > +
> > > > +/**
> > > > +  This function free resources in given Response.
> > > > +
> > > > +  @param[in]  Response     HTTP response to be released.
> > > > +
> > > > +  @retval     EFI_SUCCESS     Resrouce is released successfully.
> > > > +  @retval     Others          Errors occur.
> > > > +
> > > > +**/
> > > > +EFI_STATUS
> > > > +ReleaseRedfishResponse (
> > > > +  IN  REDFISH_RESPONSE  *Response
> > > > +  );
> > > > +
> > > > +/**
> > > > +  This function send Redfish request to Redfish service by calling
> > > > +  Rest Ex protocol.
> > > > +
> > > > +  @param[in]   Service       Pointer to Redfish service.
> > > > +  @param[in]   Uri           Uri of Redfish service.
> > > > +  @param[in]   Method        HTTP method.
> > > > +  @param[in]   Request     Request data. This is optional.
> > > > +  @param[out]  Response    Redfish response data.
> > > > +
> > > > +  @retval     EFI_SUCCESS     Request is sent and received successfully.
> > > > +  @retval     Others          Errors occur.
> > > > +
> > > > +**/
> > > > +EFI_STATUS
> > > > +HttpSendReceive (
> > > > +  IN  REDFISH_SERVICE   Service,
> > > > +  IN  EFI_STRING        Uri,
> > > > +  IN  EFI_HTTP_METHOD   Method,
> > > > +  IN  REDFISH_REQUEST   *Request  OPTIONAL,
> > > > +  OUT REDFISH_RESPONSE  *Response
> > > > +  );
> > > > +
> > > > +#endif
> > > > diff --git a/RedfishPkg/RedfishHttpDxe/RedfishHttpData.c
> > > b/RedfishPkg/RedfishHttpDxe/RedfishHttpData.c
> > > > new file mode 100644
> > > > index 0000000000..bf95e9f8d4
> > > > --- /dev/null
> > > > +++ b/RedfishPkg/RedfishHttpDxe/RedfishHttpData.c
> > > > @@ -0,0 +1,667 @@
> > > > +/** @file
> > > > +  RedfishHttpData handles internal data to support Redfish HTTP protocol.
> > > > +
> > > > +  Copyright (c) 2023-2024, NVIDIA CORPORATION & AFFILIATES. All rights
> > > reserved.
> > > > +
> > > > +  SPDX-License-Identifier: BSD-2-Clause-Patent
> > > > +
> > > > +**/
> > > > +
> > > > +#include "RedfishHttpData.h"
> > > > +#include "RedfishHttpOperation.h"
> > > > +
> > > > +/**
> > > > +  This function update session token in Redfish Service.
> > > > +
> > > > +  @param[in]  Service         Pointer to service instance.
> > > > +  @param[in]  Token           Session token.
> > > > +
> > > > +  @retval     EFI_SUCCESS     Session token is updated.
> > > > +  @retval     Others          Error occurs.
> > > > +
> > > > +**/
> > > > +EFI_STATUS
> > > > +UpdateSessionToken (
> > > > +  IN REDFISH_SERVICE_PRIVATE  *Service,
> > > > +  IN CHAR8                    *Token
> > > > +  )
> > > > +{
> > > > +  if ((Service == NULL) || IS_EMPTY_STRING (Token)) {
> > > > +    return EFI_INVALID_PARAMETER;
> > > > +  }
> > > > +
> > > > +  if (Service->SessionToken != NULL) {
> > > > +    FreePool (Service->SessionToken);
> > > > +  }
> > > > +
> > > > +  Service->SessionToken = AllocateCopyPool (AsciiStrSize (Token), Token);
> > > > +  if (Service->SessionToken == NULL) {
> > > > +    return EFI_OUT_OF_RESOURCES;
> > > > +  }
> > > > +
> > > > +  return EFI_SUCCESS;
> > > > +}
> > > > +
> > > > +/**
> > > > +  This function release Redfish Service.
> > > > +
> > > > +  @param[in]  Service         Pointer to service instance.
> > > > +
> > > > +  @retval     EFI_SUCCESS     Service is released.
> > > > +  @retval     Others          Error occurs.
> > > > +
> > > > +**/
> > > > +EFI_STATUS
> > > > +ReleaseRedfishService (
> > > > +  IN REDFISH_SERVICE_PRIVATE  *Service
> > > > +  )
> > > > +{
> > > > +  if (Service == NULL) {
> > > > +    return EFI_INVALID_PARAMETER;
> > > > +  }
> > > > +
> > > > +  if (Service->Host != NULL) {
> > > > +    FreePool (Service->Host);
> > > > +  }
> > > > +
> > > > +  if (Service->HostName != NULL) {
> > > > +    FreePool (Service->HostName);
> > > > +  }
> > > > +
> > > > +  if (Service->BasicAuth != NULL) {
> > > > +    ZeroMem (Service->BasicAuth, AsciiStrSize (Service->BasicAuth));
> > > > +    FreePool (Service->BasicAuth);
> > > > +  }
> > > > +
> > > > +  if (Service->SessionToken != NULL) {
> > > > +    ZeroMem (Service->SessionToken, AsciiStrSize (Service->SessionToken));
> > > > +    FreePool (Service->SessionToken);
> > > > +  }
> > > > +
> > > > +  FreePool (Service);
> > > > +
> > > > +  return EFI_SUCCESS;
> > > > +}
> > > > +
> > > > +/**
> > > > +  This function creat new service. Host and HostName are copied to
> > > > +  newly created service instance.
> > > > +
> > > > +  @param[in]  Host            Host string.
> > > > +  @param[in]  HostName        Hostname string.
> > > > +  @param[in]  BasicAuth       Basic Authorization string.
> > > > +  @param[in]  SessionToken    Session token string.
> > > > +  @param[in]  RestEx          Rest EX protocol instance.
> > > > +
> > > > +  @retval     REDFISH_PAYLOAD_PRIVATE  Newly created service.
> > > > +  @retval     NULL             Error occurs.
> > > > +
> > > > +**/
> > > > +REDFISH_SERVICE_PRIVATE *
> > > > +CreateRedfishService (
> > > > +  IN CHAR8                 *Host,
> > > > +  IN CHAR8                 *HostName,
> > > > +  IN CHAR8                 *BasicAuth OPTIONAL,
> > > > +  IN CHAR8                 *SessionToken OPTIONAL,
> > > > +  IN EFI_REST_EX_PROTOCOL  *RestEx
> > > > +  )
> > > > +{
> > > > +  REDFISH_SERVICE_PRIVATE  *NewService;
> > > > +  UINTN                    AuthStrSize;
> > > > +
> > > > +  if (IS_EMPTY_STRING (Host) || IS_EMPTY_STRING (HostName) || (RestEx
> ==
> > > NULL)) {
> > > > +    return NULL;
> > > > +  }
> > > > +
> > > > +  NewService = AllocateZeroPool (sizeof (REDFISH_SERVICE_PRIVATE));
> > > > +  if (NewService == NULL) {
> > > > +    return NULL;
> > > > +  }
> > > > +
> > > > +  NewService->Signature = REDFISH_HTTP_SERVICE_SIGNATURE;
> > > > +  NewService->Host      = AllocateCopyPool (AsciiStrSize (Host), Host);
> > > > +  if (NewService->Host == NULL) {
> > > > +    goto ON_ERROR;
> > > > +  }
> > > > +
> > > > +  NewService->HostName = AllocateCopyPool (AsciiStrSize (HostName),
> > > HostName);
> > > > +  if (NewService->HostName == NULL) {
> > > > +    goto ON_ERROR;
> > > > +  }
> > > > +
> > > > +  if (!IS_EMPTY_STRING (BasicAuth)) {
> > > > +    AuthStrSize           = AsciiStrSize (BasicAuth) + AsciiStrLen
> > > (REDFISH_HTTP_BASIC_AUTH_STR);
> > > > +    NewService->BasicAuth = AllocateZeroPool (AuthStrSize);
> > > > +    if (NewService->BasicAuth == NULL) {
> > > > +      goto ON_ERROR;
> > > > +    }
> > > > +
> > > > +    AsciiSPrint (NewService->BasicAuth, AuthStrSize, "%a%a",
> > > REDFISH_HTTP_BASIC_AUTH_STR, BasicAuth);
> > > > +  }
> > > > +
> > > > +  if (!IS_EMPTY_STRING (SessionToken)) {
> > > > +    NewService->SessionToken = AllocateCopyPool (AsciiStrSize
> (SessionToken),
> > > SessionToken);
> > > > +    if (NewService->SessionToken == NULL) {
> > > > +      goto ON_ERROR;
> > > > +    }
> > > > +  }
> > > > +
> > > > +  NewService->RestEx = RestEx;
> > > > +
> > > > +  return NewService;
> > > > +
> > > > +ON_ERROR:
> > > > +
> > > > +  ReleaseRedfishService (NewService);
> > > > +
> > > > +  return NULL;
> > > > +}
> > > > +
> > > > +/**
> > > > +  This function release Redfish Payload.
> > > > +
> > > > +  @param[in]  Payload         Pointer to payload instance.
> > > > +
> > > > +  @retval     EFI_SUCCESS     Payload is released.
> > > > +  @retval     Others          Error occurs.
> > > > +
> > > > +**/
> > > > +EFI_STATUS
> > > > +ReleaseRedfishPayload (
> > > > +  IN REDFISH_PAYLOAD_PRIVATE  *Payload
> > > > +  )
> > > > +{
> > > > +  if (Payload == NULL) {
> > > > +    return EFI_INVALID_PARAMETER;
> > > > +  }
> > > > +
> > > > +  if (Payload->Service != NULL) {
> > > > +    ReleaseRedfishService (Payload->Service);
> > > > +  }
> > > > +
> > > > +  if (Payload->JsonValue != NULL) {
> > > > +    JsonValueFree (Payload->JsonValue);
> > > > +  }
> > > > +
> > > > +  FreePool (Payload);
> > > > +
> > > > +  return EFI_SUCCESS;
> > > > +}
> > > > +
> > > > +/**
> > > > +  This function creat new payload. Server and JsonObj are
> > > > +  copied to newly created payload.
> > > > +
> > > > +  @param[in]  Service          Pointer to Service instance.
> > > > +  @param[in]  JsonValue        Pointer to JSON value.
> > > > +
> > > > +  @retval     REDFISH_PAYLOAD_PRIVATE  Newly created payload.
> > > > +  @retval     NULL                     Error occurs.
> > > > +
> > > > +**/
> > > > +REDFISH_PAYLOAD_PRIVATE *
> > > > +CreateRedfishPayload (
> > > > +  IN REDFISH_SERVICE_PRIVATE  *Service,
> > > > +  IN EDKII_JSON_VALUE         JsonValue
> > > > +  )
> > > > +{
> > > > +  REDFISH_PAYLOAD_PRIVATE  *NewPayload;
> > > > +
> > > > +  if ((Service == NULL) || (JsonValue == NULL)) {
> > > > +    return NULL;
> > > > +  }
> > > > +
> > > > +  NewPayload = AllocateZeroPool (sizeof (REDFISH_PAYLOAD_PRIVATE));
> > > > +  if (NewPayload == NULL) {
> > > > +    return NULL;
> > > > +  }
> > > > +
> > > > +  NewPayload->Signature = REDFISH_HTTP_PAYLOAD_SIGNATURE;
> > > > +  NewPayload->Service   = CreateRedfishService (Service->Host, Service-
> > > >HostName, Service->BasicAuth, Service->SessionToken, Service->RestEx);
> > > > +  if (NewPayload->Service == NULL) {
> > > > +    goto ON_ERROR;
> > > > +  }
> > > > +
> > > > +  NewPayload->JsonValue = JsonValueClone (JsonValue);
> > > > +  if (NewPayload->JsonValue == NULL) {
> > > > +    goto ON_ERROR;
> > > > +  }
> > > > +
> > > > +  return NewPayload;
> > > > +
> > > > +ON_ERROR:
> > > > +
> > > > +  ReleaseRedfishPayload (NewPayload);
> > > > +
> > >
> > >
> > > NewPayload->Service  is leaked
> > >
> > >
> > > > +  return NULL;
> > > > +}
> > > > +
> > > > +/**
> > > > +  This function copy the data in SrcResponse to DstResponse.
> > > > +
> > > > +  @param[in]  SrcResponse      Source Response to copy.
> > > > +  @param[out] DstResponse      Destination Response.
> > > > +
> > > > +  @retval     EFI_SUCCESS      Response is copied successfully.
> > > > +  @retval     Others           Error occurs.
> > > > +
> > > > +**/
> > > > +EFI_STATUS
> > > > +CopyRedfishResponse (
> > > > +  IN  REDFISH_RESPONSE  *SrcResponse,
> > > > +  OUT REDFISH_RESPONSE  *DstResponse
> > > > +  )
> > > > +{
> > > > +  REDFISH_PAYLOAD_PRIVATE  *Payload;
> > > > +  UINTN                    Index;
> > > > +
> > > > +  if ((SrcResponse == NULL) || (DstResponse == NULL)) {
> > > > +    return EFI_INVALID_PARAMETER;
> > > > +  }
> > > > +
> > > > +  if (SrcResponse == DstResponse) {
> > > > +    return EFI_SUCCESS;
> > > > +  }
> > > > +
> > > > +  //
> > > > +  // Status code
> > > > +  //
> > > > +  if (SrcResponse->StatusCode != NULL) {
> > > > +    DstResponse->StatusCode = AllocateCopyPool (sizeof
> > > (EFI_HTTP_STATUS_CODE), SrcResponse->StatusCode);
> > > > +    if (DstResponse->StatusCode == NULL) {
> > > > +      goto ON_ERROR;
> > > > +    }
> > > > +  }
> > > > +
> > > > +  //
> > > > +  // Header
> > > > +  //
> > > > +  if ((SrcResponse->HeaderCount > 0) && (SrcResponse->Headers != NULL))
> {
> > > > +    DstResponse->HeaderCount = 0;
> > > > +    DstResponse->Headers     = AllocateZeroPool (sizeof (EFI_HTTP_HEADER)
> *
> > > SrcResponse->HeaderCount);
> > > > +    if (DstResponse->Headers == NULL) {
> > > > +      goto ON_ERROR;
> > > > +    }
> > > > +
> > > > +    for (Index = 0; Index < SrcResponse->HeaderCount; Index++) {
> > > > +      DstResponse->Headers[Index].FieldName = AllocateCopyPool
> (AsciiStrSize
> > > (SrcResponse->Headers[Index].FieldName), SrcResponse-
> > > >Headers[Index].FieldName);
> > > > +      if (DstResponse->Headers[Index].FieldName == NULL) {
> > > > +        goto ON_ERROR;
> > > > +      }
> > > > +
> > > > +      DstResponse->Headers[Index].FieldValue = AllocateCopyPool
> (AsciiStrSize
> > > (SrcResponse->Headers[Index].FieldValue), SrcResponse-
> > > >Headers[Index].FieldValue);
> > > > +      if (DstResponse->Headers[Index].FieldValue == NULL) {
> > > > +        goto ON_ERROR;
> > > > +      }
> > > > +
> > > > +      DstResponse->HeaderCount += 1;
> > > > +    }
> > > > +  }
> > > > +
> > > > +  //
> > > > +  // Payload
> > > > +  //
> > > > +  if (SrcResponse->Payload != NULL) {
> > > > +    Payload = (REDFISH_PAYLOAD_PRIVATE *)SrcResponse->Payload;
> > > > +    if (Payload->Signature != REDFISH_HTTP_PAYLOAD_SIGNATURE) {
> > > > +      DEBUG ((DEBUG_ERROR, "%a: signature check failure\n", __func__));
> > > > +      goto ON_ERROR;
> > > > +    }
> > > > +
> > > > +    DstResponse->Payload = CreateRedfishPayload (Payload->Service,
> Payload-
> > > >JsonValue);
> > > > +    if (DstResponse->Payload  == NULL) {
> > > > +      goto ON_ERROR;
> > > > +    }
> > > > +  }
> > > > +
> > > > +  return EFI_SUCCESS;
> > > > +
> > > > +ON_ERROR:
> > > > +
> > > > +  ReleaseRedfishResponse (DstResponse);
> > > > +
> > > > +  return EFI_OUT_OF_RESOURCES;
> > > > +}
> > > > +
> > > > +/**
> > > > +  This function clone input response and return to caller
> > > > +
> > > > +  @param[in]  Response      Response to clone.
> > > > +
> > > > +  @retval     REDFISH_RESPONSE *  Response is cloned.
> > > > +  @retval     NULL                Errors occur.
> > > > +
> > > > +**/
> > > > +REDFISH_RESPONSE *
> > > > +CloneRedfishResponse (
> > > > +  IN REDFISH_RESPONSE  *Response
> > > > +  )
> > > > +{
> > > > +  EFI_STATUS        Status;
> > > > +  REDFISH_RESPONSE  *NewResponse;
> > > > +
> > > > +  if (Response == NULL) {
> > > > +    return NULL;
> > > > +  }
> > > > +
> > > > +  NewResponse = AllocateZeroPool (sizeof (REDFISH_RESPONSE));
> > > > +  if (NewResponse == NULL) {
> > > > +    return NULL;
> > > > +  }
> > > > +
> > > > +  Status = CopyRedfishResponse (Response, NewResponse);
> > > > +  if (EFI_ERROR (Status)) {
> > > > +    FreePool (NewResponse);
> > > > +    return NULL;
> > > > +  }
> > > > +
> > > > +  return NewResponse;
> > > > +}
> > > > +
> > > > +/**
> > > > +  Release REDFISH_HTTP_CACHE_DATA resource
> > > > +
> > > > +  @param[in]    Data    Pointer to REDFISH_HTTP_CACHE_DATA instance
> > > > +
> > > > +  @retval EFI_SUCCESS             REDFISH_HTTP_CACHE_DATA is released
> > > successfully.
> > > > +  @retval EFI_INVALID_PARAMETER   Data is NULL
> > > > +
> > > > +**/
> > > > +EFI_STATUS
> > > > +ReleaseHttpCacheData (
> > > > +  IN REDFISH_HTTP_CACHE_DATA  *Data
> > > > +  )
> > > > +{
> > > > +  if (Data == NULL) {
> > > > +    return EFI_INVALID_PARAMETER;
> > > > +  }
> > > > +
> > > > +  if (Data->Uri != NULL) {
> > > > +    FreePool (Data->Uri);
> > > > +  }
> > > > +
> > > > +  if (Data->Response != NULL) {
> > > > +    ReleaseRedfishResponse (Data->Response);
> > > > +    FreePool (Data->Response);
> > > > +  }
> > > > +
> > > > +  FreePool (Data);
> > > > +
> > > > +  return EFI_SUCCESS;
> > > > +}
> > > > +
> > > > +/**
> > > > +  Create new cache data.
> > > > +
> > > > +  @param[in]    Uri       The URI string matching to this cache data.
> > > > +  @param[in]    Response  HTTP response.
> > > > +
> > > > +  @retval REDFISH_HTTP_CACHE_DATA *   Pointer to newly created cache
> > > data.
> > > > +  @retval NULL                        No memory available.
> > > > +
> > > > +**/
> > > > +REDFISH_HTTP_CACHE_DATA *
> > > > +NewHttpCacheData (
> > > > +  IN  EFI_STRING        Uri,
> > > > +  IN  REDFISH_RESPONSE  *Response
> > > > +  )
> > > > +{
> > > > +  REDFISH_HTTP_CACHE_DATA  *NewData;
> > > > +  UINTN                    Size;
> > > > +
> > > > +  if (IS_EMPTY_STRING (Uri) || (Response == NULL)) {
> > > > +    return NULL;
> > > > +  }
> > > > +
> > > > +  NewData = AllocateZeroPool (sizeof (REDFISH_HTTP_CACHE_DATA));
> > > > +  if (NewData == NULL) {
> > > > +    return NULL;
> > > > +  }
> > > > +
> > > > +  NewData->Signature = REDFISH_HTTP_CACHE_SIGNATURE;
> > > > +  Size               = StrSize (Uri);
> > > > +  NewData->Uri       = AllocateCopyPool (Size, Uri);
> > > > +  if (NewData->Uri == NULL) {
> > > > +    goto ON_ERROR;
> > > > +  }
> > > > +
> > > > +  NewData->Response = Response;
> > > > +  NewData->HitCount = 1;
> > > > +
> > > > +  return NewData;
> > > > +
> > > > +ON_ERROR:
> > > > +
> > > > +  if (NewData != NULL) {
> > > > +    ReleaseHttpCacheData (NewData);
> > > > +  }
> > > > +
> > > > +  return NULL;
> > > > +}
> > > > +
> > > > +/**
> > > > +  Search on given ListHeader for given URI string.
> > > > +
> > > > +  @param[in]    ListHeader  Target list to search.
> > > > +  @param[in]    Uri         Target URI to search.
> > > > +
> > > > +  @retval REDFISH_HTTP_CACHE_DATA   Target cache data is found.
> > > > +  @retval NULL                      No cache data with given URI is found.
> > > > +
> > > > +**/
> > > > +REDFISH_HTTP_CACHE_DATA *
> > > > +FindHttpCacheData (
> > > > +  IN  LIST_ENTRY  *ListHeader,
> > > > +  IN  EFI_STRING  Uri
> > > > +  )
> > > > +{
> > > > +  LIST_ENTRY               *List;
> > > > +  REDFISH_HTTP_CACHE_DATA  *Data;
> > > > +
> > > > +  if (IS_EMPTY_STRING (Uri)) {
> > > > +    return NULL;
> > > > +  }
> > > > +
> > > > +  if (IsListEmpty (ListHeader)) {
> > > > +    return NULL;
> > > > +  }
> > > > +
> > > > +  Data = NULL;
> > > > +  List = GetFirstNode (ListHeader);
> > > > +  while (!IsNull (ListHeader, List)) {
> > > > +    Data = REDFISH_HTTP_CACHE_FROM_LIST (List);
> > > > +
> > > > +    if (StrCmp (Data->Uri, Uri) == 0) {
> > > > +      return Data;
> > > > +    }
> > > > +
> > > > +    List = GetNextNode (ListHeader, List);
> > > > +  }
> > > > +
> > > > +  return NULL;
> > > > +}
> > > > +
> > > > +/**
> > > > +  Search on given ListHeader and return cache data with minimum hit
> count.
> > > > +
> > > > +  @param[in]    ListHeader  Target list to search.
> > > > +
> > > > +  @retval REDFISH_HTTP_CACHE_DATA   Target cache data is returned.
> > > > +  @retval NULL                      No cache data is found.
> > > > +
> > > > +**/
> > > > +REDFISH_HTTP_CACHE_DATA *
> > > > +FindUnusedHttpCacheData (
> > > > +  IN  LIST_ENTRY  *ListHeader
> > > > +  )
> > > > +{
> > > > +  LIST_ENTRY               *List;
> > > > +  REDFISH_HTTP_CACHE_DATA  *Data;
> > > > +  REDFISH_HTTP_CACHE_DATA  *UnusedData;
> > > > +  UINTN                    HitCount;
> > > > +
> > > > +  if (IsListEmpty (ListHeader)) {
> > > > +    return NULL;
> > > > +  }
> > > > +
> > > > +  Data       = NULL;
> > > > +  UnusedData = NULL;
> > > > +  HitCount   = 0;
> > > > +
> > > > +  List       = GetFirstNode (ListHeader);
> > > > +  Data       = REDFISH_HTTP_CACHE_FROM_LIST (List);
> > > > +  UnusedData = Data;
> > > > +  HitCount   = Data->HitCount;
> > > > +  List       = GetNextNode (ListHeader, List);
> > > > +
> > > > +  while (!IsNull (ListHeader, List)) {
> > > > +    Data = REDFISH_HTTP_CACHE_FROM_LIST (List);
> > > > +
> > > > +    if (Data->HitCount < HitCount) {
> > > > +      HitCount   = Data->HitCount;
> > > > +      UnusedData = Data;
> > > > +    }
> > > > +
> > > > +    List = GetNextNode (ListHeader, List);
> > > > +  }
> > > > +
> > > > +  return UnusedData;
> > > > +}
> > > > +
> > > > +/**
> > > > +  Delete a cache data by given cache instance.
> > > > +
> > > > +  @param[in]    List    Target cache list to be removed.
> > > > +  @param[in]    Data    Pointer to the instance to be deleted.
> > > > +
> > > > +  @retval EFI_SUCCESS   Cache data is removed.
> > > > +  @retval Others        Fail to remove cache data.
> > > > +
> > > > +**/
> > > > +EFI_STATUS
> > > > +DeleteHttpCacheData (
> > > > +  IN  REDFISH_HTTP_CACHE_LIST  *List,
> > > > +  IN  REDFISH_HTTP_CACHE_DATA  *Data
> > > > +  )
> > > > +{
> > > > +  if ((List == NULL) || (Data == NULL)) {
> > > > +    return EFI_INVALID_PARAMETER;
> > > > +  }
> > > > +
> > > > +  DEBUG ((REDFISH_HTTP_CACHE_DEBUG, "%a: delete: %s\n", __func__,
> > > Data->Uri));
> > > > +
> > > > +  RemoveEntryList (&Data->List);
> > > > +  --List->Count;
> > > > +
> > > > +  return ReleaseHttpCacheData (Data);
> > > > +}
> > > > +
> > > > +/**
> > > > +  Add new cache by given URI and HTTP response to specify List.
> > > > +
> > > > +  @param[in]    List      Target cache list to add.
> > > > +  @param[in]    Uri       The URI string matching to this cache data.
> > > > +  @param[in]    Response  HTTP response.
> > > > +
> > > > +  @retval EFI_SUCCESS   Cache data is added.
> > > > +  @retval Others        Fail to add cache data.
> > > > +
> > > > +**/
> > > > +EFI_STATUS
> > > > +AddHttpCacheData (
> > > > +  IN  REDFISH_HTTP_CACHE_LIST  *List,
> > > > +  IN  EFI_STRING               Uri,
> > > > +  IN  REDFISH_RESPONSE         *Response
> > > > +  )
> > > > +{
> > > > +  REDFISH_HTTP_CACHE_DATA  *NewData;
> > > > +  REDFISH_HTTP_CACHE_DATA  *OldData;
> > > > +  REDFISH_HTTP_CACHE_DATA  *UnusedData;
> > > > +  REDFISH_RESPONSE         *NewResponse;
> > > > +
> > > > +  if ((List == NULL) || IS_EMPTY_STRING (Uri) || (Response == NULL)) {
> > > > +    return EFI_INVALID_PARAMETER;
> > > > +  }
> > > > +
> > > > +  //
> > > > +  // If same cache data exist, replace it with latest one.
> > > > +  //
> > > > +  OldData = FindHttpCacheData (&List->Head, Uri);
> > > > +  if (OldData != NULL) {
> > > > +    DeleteHttpCacheData (List, OldData);
> > > > +  }
> > > > +
> > > > +  //
> > > > +  // Check capacity
> > > > +  //
> > > > +  if (List->Count >= List->Capacity) {
> > > > +    DEBUG ((REDFISH_HTTP_CACHE_DEBUG, "%a: list is full and retire
> unused
> > > cache\n", __func__));
> > > > +    UnusedData = FindUnusedHttpCacheData (&List->Head);
> > > > +    if (UnusedData == NULL) {
> > > > +      return EFI_OUT_OF_RESOURCES;
> > > > +    }
> > > > +
> > > > +    DeleteHttpCacheData (List, UnusedData);
> > > > +  }
> > > > +
> > > > +  //
> > > > +  // Clone a local copy
> > > > +  //
> > > > +  NewResponse = CloneRedfishResponse (Response);
> > > > +  if (NewResponse == NULL) {
> > > > +    return EFI_OUT_OF_RESOURCES;
> > > > +  }
> > > > +
> > > > +  NewData = NewHttpCacheData (Uri, NewResponse);
> > > > +  if (NewData == NULL) {
> > > > +    return EFI_OUT_OF_RESOURCES;
> > > > +  }
> > > > +
> > > > +  InsertTailList (&List->Head, &NewData->List);
> > > > +  ++List->Count;
> > > > +
> > > > +  DEBUG ((REDFISH_HTTP_CACHE_DEBUG, "%a: cache(%d/%d) %s\n",
> > > __func__, List->Count, List->Capacity, NewData->Uri));
> > > > +
> > > > +  return EFI_SUCCESS;
> > > > +}
> > > > +
> > > > +/**
> > > > +  Release all cache from list.
> > > > +
> > > > +  @param[in]    CacheList    The list to be released.
> > > > +
> > > > +  @retval EFI_SUCCESS             All cache data are released.
> > > > +  @retval EFI_INVALID_PARAMETER   CacheList is NULL.
> > > > +
> > > > +**/
> > > > +EFI_STATUS
> > > > +ReleaseCacheList (
> > > > +  IN  REDFISH_HTTP_CACHE_LIST  *CacheList
> > > > +  )
> > > > +{
> > > > +  LIST_ENTRY               *List;
> > > > +  LIST_ENTRY               *Next;
> > > > +  REDFISH_HTTP_CACHE_DATA  *Data;
> > > > +
> > > > +  if (CacheList == NULL) {
> > > > +    return EFI_INVALID_PARAMETER;
> > > > +  }
> > > > +
> > > > +  if (IsListEmpty (&CacheList->Head)) {
> > > > +    return EFI_SUCCESS;
> > > > +  }
> > > > +
> > > > +  Data = NULL;
> > > > +  Next = NULL;
> > > > +  List = GetFirstNode (&CacheList->Head);
> > > > +  while (!IsNull (&CacheList->Head, List)) {
> > > > +    Data = REDFISH_HTTP_CACHE_FROM_LIST (List);
> > > > +    Next = GetNextNode (&CacheList->Head, List);
> > > > +
> > > > +    DeleteHttpCacheData (CacheList, Data);
> > > > +
> > > > +    List = Next;
> > > > +  }
> > > > +
> > > > +  return EFI_SUCCESS;
> > > > +}
> > > > diff --git a/RedfishPkg/RedfishHttpDxe/RedfishHttpDxe.c
> > > b/RedfishPkg/RedfishHttpDxe/RedfishHttpDxe.c
> > > > new file mode 100644
> > > > index 0000000000..39958d4865
> > > > --- /dev/null
> > > > +++ b/RedfishPkg/RedfishHttpDxe/RedfishHttpDxe.c
> > > > @@ -0,0 +1,1344 @@
> > > > +/** @file
> > > > +  RedfishHttpDxe produces EdkIIRedfishHttpProtocol
> > > > +  for EDK2 Redfish Feature driver to do HTTP operations.
> > > > +
> > > > +  Copyright (c) 2023-2024, NVIDIA CORPORATION & AFFILIATES. All rights
> > > reserved.
> > > > +
> > > > +  SPDX-License-Identifier: BSD-2-Clause-Patent
> > > > +
> > > > +**/
> > > > +
> > > > +#include "RedfishHttpDxe.h"
> > > > +#include "RedfishHttpData.h"
> > > > +#include "RedfishHttpOperation.h"
> > > > +
> > > > +REDFISH_HTTP_CACHE_PRIVATE  *mRedfishHttpCachePrivate = NULL;
> > > > +
> > > > +/**
> > > > +  Debug output the cache list.
> > > > +
> > > > +  @param[in]    Msg            Debug message string.
> > > > +  @param[in]    ErrorLevel     Output error level.
> > > > +  @param[in]    CacheList      Target list to dump.
> > > > +
> > > > +  @retval EFI_SUCCESS             Debug dump finished.
> > > > +  @retval EFI_INVALID_PARAMETER   HttpCacheList is NULL.
> > > > +
> > > > +**/
> > > > +EFI_STATUS
> > > > +DebugPrintHttpCacheList (
> > > > +  IN  CONST CHAR8              *Msg,
> > > > +  IN  UINTN                    ErrorLevel,
> > > > +  IN  REDFISH_HTTP_CACHE_LIST  *CacheList
> > > > +  )
> > > > +{
> > > > +  LIST_ENTRY               *List;
> > > > +  REDFISH_HTTP_CACHE_DATA  *Data;
> > > > +  UINTN                    Index;
> > > > +
> > > > +  if (CacheList == NULL) {
> > > > +    return EFI_INVALID_PARAMETER;
> > > > +  }
> > > > +
> > > > +  if (!IS_EMPTY_STRING (Msg)) {
> > > > +    DEBUG ((ErrorLevel, "%a\n", Msg));
> > > > +  }
> > > > +
> > > > +  if (IsListEmpty (&CacheList->Head)) {
> > > > +    DEBUG ((ErrorLevel, "list is empty\n"));
> > > > +    return EFI_NOT_FOUND;
> > > > +  }
> > > > +
> > > > +  DEBUG ((ErrorLevel, "list count: %d capacity: %d\n", CacheList->Count,
> > > CacheList->Capacity));
> > > > +  Data  = NULL;
> > > > +  Index = 0;
> > > > +  List  = GetFirstNode (&CacheList->Head);
> > > > +  while (!IsNull (&CacheList->Head, List)) {
> > > > +    Data = REDFISH_HTTP_CACHE_FROM_LIST (List);
> > > > +
> > > > +    DEBUG ((ErrorLevel, "%d) Uri: %s Hit: %d\n", ++Index, Data->Uri, Data-
> > > >HitCount));
> > > > +
> > > > +    List = GetNextNode (&CacheList->Head, List);
> > > > +  }
> > > > +
> > > > +  return EFI_SUCCESS;
> > > > +}
> > > > +
> > > > +/**
> > > > +
> > > > +  Check HTTP status code to see if we like to retry HTTP request or not.
> > > > +
> > > > +  @param[in]  StatusCode      HTTP status code.
> > > > +
> > > > +  @retval     BOOLEAN         Return true when we like to retry request.
> > > > +                              Return false when we don't want to retry request.
> > > > +
> > > > +**/
> > > > +BOOLEAN
> > > > +RedfishRetryRequired (
> > > > +  IN EFI_HTTP_STATUS_CODE  *StatusCode
> > > > +  )
> > > > +{
> > > > +  if (StatusCode == NULL) {
> > > > +    return TRUE;
> > > > +  }
> > > > +
> > > > +  if ((*StatusCode == HTTP_STATUS_500_INTERNAL_SERVER_ERROR) ||
> > > > +      (*StatusCode == HTTP_STATUS_UNSUPPORTED_STATUS))
> > > > +  {
> > > > +    return TRUE;
> > > > +  }
> > > > +
> > > > +  return FALSE;
> > > > +}
> > > > +
> > > > +/**
> > > > +
> > > > +  Convert Unicode string to ASCII string. It's call responsibility to release
> > > returned buffer.
> > > > +
> > > > +  @param[in]  UnicodeStr      Unicode string to convert.
> > > > +
> > > > +  @retval     CHAR8 *         ASCII string returned.
> > > > +  @retval     NULL            Errors occur.
> > > > +
> > > > +**/
> > > > +CHAR8 *
> > > > +StringUnicodeToAscii (
> > > > +  IN EFI_STRING  UnicodeStr
> > > > +  )
> > > > +{
> > > > +  CHAR8       *AsciiStr;
> > > > +  UINTN       AsciiStrSize;
> > > > +  EFI_STATUS  Status;
> > > > +
> > > > +  if (IS_EMPTY_STRING (UnicodeStr)) {
> > > > +    return NULL;
> > > > +  }
> > > > +
> > > > +  AsciiStrSize = StrLen (UnicodeStr) + 1;
> > > > +  AsciiStr     = AllocateZeroPool (AsciiStrSize);
> > > > +  if (AsciiStr == NULL) {
> > > > +    return NULL;
> > > > +  }
> > > > +
> > > > +  Status = UnicodeStrToAsciiStrS (UnicodeStr, AsciiStr, AsciiStrSize);
> > > > +  if (EFI_ERROR (Status)) {
> > > > +    DEBUG ((DEBUG_ERROR, "UnicodeStrToAsciiStrS failed: %r\n", Status));
> > > > +    FreePool (AsciiStr);
> > > > +    return NULL;
> > > > +  }
> > > > +
> > > > +  return AsciiStr;
> > > > +}
> > > > +
> > > > +/**
> > > > +  Return HTTP method in ASCII string. Caller does not need
> > > > +  to free returned string buffer.
> > > > +
> > > > +  @param[in]  Method         HTTP method.
> > > > +
> > > > +  @retval CHAR8 *   Method in string.
> > > > +**/
> > > > +CHAR8 *
> > > > +HttpMethodToString (
> > > > +  IN  EFI_HTTP_METHOD  Method
> > > > +  )
> > > > +{
> > > > +  switch (Method) {
> > > > +    case HttpMethodGet:
> > > > +      return HTTP_METHOD_GET;
> > > > +      break;
> > > > +    case HttpMethodPost:
> > > > +      return HTTP_METHOD_POST;
> > > > +      break;
> > > > +    case HttpMethodPatch:
> > > > +      return HTTP_METHOD_PATCH;
> > > > +      break;
> > > > +    case HttpMethodPut:
> > > > +      return HTTP_METHOD_PUT;
> > > > +      break;
> > > > +    case HttpMethodDelete:
> > > > +      return HTTP_METHOD_DELETE;
> > > > +      break;
> > > > +    default:
> > > > +      break;
> > > > +  }
> > > > +
> > > > +  return "Unknown";
> > > > +}
> > > > +
> > > > +/**
> > > > +  Report HTTP communication error via report status code.
> > > > +
> > > > +  @param[in]  Method         HTTP method.
> > > > +  @param[in]  Uri            The URI which has failure.
> > > > +  @param[in]  HttpStatusCode HTTP status code.
> > > > +
> > > > +**/
> > > > +VOID
> > > > +ReportHttpError (
> > > > +  IN  EFI_HTTP_METHOD       Method,
> > > > +  IN  EFI_STRING            Uri,
> > > > +  IN  EFI_HTTP_STATUS_CODE  *HttpStatusCode  OPTIONAL
> > > > +  )
> > > > +{
> > > > +  CHAR8  ErrorMsg[REDFISH_ERROR_MSG_MAX];
> > > > +
> > > > +  if (IS_EMPTY_STRING (Uri)) {
> > > > +    DEBUG ((DEBUG_ERROR, "%a: no URI to report error status\n",
> __func__));
> > > > +    return;
> > > > +  }
> > > > +
> > > > +  //
> > > > +  // Report failure of URI and HTTP status code.
> > > > +  //
> > > > +  AsciiSPrint (ErrorMsg, sizeof (ErrorMsg), REDFISH_HTTP_ERROR_REPORT,
> > > HttpMethodToString (Method), (HttpStatusCode == NULL ?
> > > HTTP_STATUS_UNSUPPORTED_STATUS : *HttpStatusCode), Uri);
> > > > +  DEBUG ((DEBUG_ERROR, "%a\n", ErrorMsg));
> > > > +  //
> > > > +  // TODO:
> > > > +  // Below PI status code is approved by PIWG and wait for specification
> > > published.
> > > > +  // We will uncomment below report status code after PI status code get
> > > published.
> > > > +  // REF:
> > >
> https://bugzilla.ti/
> %2F&data=05%7C02%7Cnicklew%40nvidia.com%7Cb82203c2d6124060850308d
> c34894020%7C43083d15727340c1b7db39efd9ccc17a%7C0%7C0%7C638443011
> 350942592%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLjAwMDAiLCJQIjoiV2
> luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C0%7C%7C%7C&sdata=PbXKoTXf7
> HRXt7q1qhRbtmwEqAisA1qeblTN5GUMPe8%3D&reserved=0
> > >
> anocore.org%2Fshow_bug.cgi%3Fid%3D4483&data=05%7C02%7Cnicklew%40nvi
> > >
> dia.com%7Cf659c54c3edb43527c3608dc3462ab2a%7C43083d15727340c1b7db
> > >
> 39efd9ccc17a%7C0%7C0%7C638442845601051396%7CUnknown%7CTWFpbGZs
> > >
> b3d8eyJWIjoiMC4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%
> > >
> 3D%7C0%7C%7C%7C&sdata=T1bN7KmTa1v49cOFkd9%2F9hlzkdzbHPLebxSiUkp
> > > VuU4%3D&reserved=0
> > > > +  //
> > > > +  // REPORT_STATUS_CODE_WITH_EXTENDED_DATA (
> > > > +  //  EFI_ERROR_CODE | EFI_ERROR_MAJOR,
> > > > +  //  EFI_COMPUTING_UNIT_MANAGEABILITY |
> > > EFI_MANAGEABILITY_EC_REDFISH_COMMUNICATION_ERROR,
> > > > +  //  ErrorMsg,
> > > > +  //  AsciiStrSize (ErrorMsg)
> > > > +  //  );
> > > > +}
> > > > +
> > > > +/**
> > > > +  This function create Redfish service. It's caller's responsibility to free
> returned
> > > > +  Redfish service by calling FreeService ().
> > > > +
> > > > +  @param[in]  This                       Pointer to
> EDKII_REDFISH_HTTP_PROTOCOL
> > > instance.
> > > > +  @param[in]  RedfishConfigServiceInfo   Redfish config service
> information.
> > > > +
> > > > +  @retval     REDFISH_SERVICE  Redfish service is created.
> > > > +  @retval     NULL             Errors occur.
> > > > +
> > > > +**/
> > > > +REDFISH_SERVICE
> > > > +EFIAPI
> > > > +RedfishCreateRedfishService (
> > > > +  IN  EDKII_REDFISH_HTTP_PROTOCOL         *This,
> > > > +  IN  REDFISH_CONFIG_SERVICE_INFORMATION
> *RedfishConfigServiceInfo
> > > > +  )
> > > > +{
> > > > +  EFI_STATUS                  Status;
> > > > +  REDFISH_HTTP_CACHE_PRIVATE  *Private;
> > > > +  REDFISH_SERVICE_PRIVATE     *NewService;
> > > > +  CHAR8                       *AsciiLocation;
> > > > +  CHAR8                       *Host;
> > > > +  CHAR8                       *BasicAuthString;
> > > > +  UINTN                       BasicAuthStrSize;
> > > > +  CHAR8                       *EncodedAuthString;
> > > > +  UINTN                       EncodedAuthStrSize;
> > > > +  EDKII_REDFISH_AUTH_METHOD   AuthMethod;
> > > > +  CHAR8                       *Username;
> > > > +  CHAR8                       *Password;
> > > > +  UINTN                       UsernameSize;
> > > > +  UINTN                       PasswordSize;
> > > > +  EFI_REST_EX_PROTOCOL        *RestEx;
> > > > +
> > > > +  if ((This == NULL) || (RedfishConfigServiceInfo == NULL)) {
> > > > +    return NULL;
> > > > +  }
> > > > +
> > > > +  DEBUG ((REDFISH_HTTP_CACHE_DEBUG, "%a: service location: %s\n",
> > > __func__, RedfishConfigServiceInfo->RedfishServiceLocation));
> > > > +
> > > > +  Private            = REDFISH_HTTP_CACHE_PRIVATE_FROM_THIS (This);
> > > > +  BasicAuthString    = NULL;
> > > > +  EncodedAuthString  = NULL;
> > > > +  Username           = NULL;
> > > > +  Password           = NULL;
> > > > +  NewService         = NULL;
> > > > +  AsciiLocation      = NULL;
> > > > +  Host               = NULL;
> > > > +  BasicAuthStrSize   = 0;
> > > > +  EncodedAuthStrSize = 0;
> > > > +  UsernameSize       = 0;
> > > > +  PasswordSize       = 0;
> > > > +
> > > > +  //
> > > > +  // Build host and host name from service location
> > > > +  //
> > > > +  if (!IS_EMPTY_STRING (RedfishConfigServiceInfo-
> >RedfishServiceLocation)) {
> > > > +    AsciiLocation = StringUnicodeToAscii (RedfishConfigServiceInfo-
> > > >RedfishServiceLocation);
> > > > +    if (AsciiLocation == NULL) {
> > > > +      goto ON_RELEASE;
> > > > +    }
> > > > +
> > > > +    Host = AllocateZeroPool (REDFISH_HOST_NAME_MAX);
> > > > +    if (AsciiLocation == NULL) {
> > > > +      goto ON_RELEASE;
> > > > +    }
> > > > +
> > > > +    if (RedfishConfigServiceInfo->RedfishServiceUseHttps) {
> > > > +      AsciiSPrint (Host, REDFISH_HOST_NAME_MAX, "https://%a",
> > > AsciiLocation);
> > > > +    } else {
> > > > +      AsciiSPrint (Host, REDFISH_HOST_NAME_MAX, "http://%a",
> AsciiLocation);
> > > > +    }
> > > > +
> > > > +    DEBUG ((REDFISH_HTTP_CACHE_DEBUG, "%a: Host: %a\n", __func__,
> > > Host));
> > > > +  }
> > > > +
> > > > +  //
> > > > +  // Find Rest Ex protocol
> > > > +  //
> > > > +  if (RedfishConfigServiceInfo->RedfishServiceRestExHandle != NULL) {
> > > > +    Status = gBS->HandleProtocol (
> > > > +                    RedfishConfigServiceInfo->RedfishServiceRestExHandle,
> > > > +                    &gEfiRestExProtocolGuid,
> > > > +                    (VOID **)&RestEx
> > > > +                    );
> > > > +  } else {
> > > > +    DEBUG ((DEBUG_ERROR, "%a: Rest Ex protocol is not available\n",
> > > __func__));
> > > > +    goto ON_RELEASE;
> > > > +  }
> > > > +
> > > > +  //
> > > > +  // Get credential
> > > > +  //
> > > > +  if (Private->CredentialProtocol == NULL) {
> > > > +    //
> > > > +    // No credential available on this system.
> > > > +    //
> > > > +    DEBUG ((DEBUG_WARN, "%a: no credential protocol available\n",
> > > __func__));
> > > > +  } else {
> > > > +    Status = Private->CredentialProtocol->GetAuthInfo (
> > > > +                                            Private->CredentialProtocol,
> > > > +                                            &AuthMethod,
> > > > +                                            &Username,
> > > > +                                            &Password
> > > > +                                            );
> > > > +    if (EFI_ERROR (Status) || IS_EMPTY_STRING (Username) ||
> > > IS_EMPTY_STRING (Password)) {
> > > > +      DEBUG ((DEBUG_ERROR, "%a: cannot get authentication information:
> > > %r\n", __func__, Status));
> > > > +      goto ON_RELEASE;
> > > > +    } else {
> > > > +      DEBUG ((REDFISH_HTTP_CACHE_DEBUG, "%a: Auth method: 0x%x
> > > username: %a password: %a\n", __func__, AuthMethod, Username,
> Password));
> > > > +
> > > > +      //
> > > > +      // Perform base64 encoding (RFC 7617)
> > > > +      //
> > > > +      UsernameSize     = AsciiStrSize (Username);
> > > > +      PasswordSize     = AsciiStrSize (Password);
> > > > +      BasicAuthStrSize =  UsernameSize + PasswordSize;  // one byte taken
> from
> > > null-terminator for ':'
> > > > +      BasicAuthString  = AllocateZeroPool (BasicAuthStrSize);
> > > > +      if (BasicAuthString == NULL) {
> > > > +        goto ON_RELEASE;
> > > > +      }
> > > > +
> > > > +      AsciiSPrint (
> > > > +        BasicAuthString,
> > > > +        BasicAuthStrSize,
> > > > +        "%a:%a",
> > > > +        Username,
> > > > +        Password
> > > > +        );
> > > > +
> > > > +      Status = Base64Encode (
> > > > +                 (CONST UINT8 *)BasicAuthString,
> > > > +                 BasicAuthStrSize,
> > > > +                 EncodedAuthString,
> > > > +                 &EncodedAuthStrSize
> > > > +                 );
> > > > +      if ((Status == EFI_BUFFER_TOO_SMALL) && (EncodedAuthStrSize > 0)) {
> > > > +        EncodedAuthString = AllocateZeroPool (EncodedAuthStrSize);
> > > > +        if (EncodedAuthString == NULL) {
> > > > +          goto ON_RELEASE;
> > > > +        }
> > > > +
> > > > +        Status = Base64Encode (
> > > > +                   (CONST UINT8 *)BasicAuthString,
> > > > +                   BasicAuthStrSize,
> > > > +                   EncodedAuthString,
> > > > +                   &EncodedAuthStrSize
> > > > +                   );
> > > > +        if (EFI_ERROR (Status)) {
> > > > +          DEBUG ((DEBUG_ERROR, "%a: Base64Encode failure: %r\n",
> __func__,
> > > Status));
> > > > +        }
> > > > +
> > > > +        DEBUG ((REDFISH_HTTP_CACHE_DEBUG, "%a: Basic authorization:
> > > %a\n", __func__, EncodedAuthString));
> > > > +      } else {
> > > > +        DEBUG ((DEBUG_ERROR, "%a: Base64Encode failure: %r\n",
> __func__,
> > > Status));
> > > > +        goto ON_RELEASE;
> > > > +      }
> > > > +    }
> > > > +  }
> > > > +
> > > > +  NewService = CreateRedfishService (Host, AsciiLocation,
> EncodedAuthString,
> > > NULL, RestEx);
> > > > +  if (NewService == NULL) {
> > > > +    DEBUG ((DEBUG_ERROR, "%a: CreateRedfishService\n", __func__));
> > > > +  }
> > > > +
> > > > +ON_RELEASE:
> > > > +
> > > > +  if (BasicAuthString != NULL) {
> > > > +    ZeroMem (BasicAuthString, BasicAuthStrSize);
> > > > +    FreePool (BasicAuthString);
> > > > +  }
> > > > +
> > > > +  if (EncodedAuthString != NULL) {
> > > > +    ZeroMem (BasicAuthString, EncodedAuthStrSize);
> > > > +    FreePool (EncodedAuthString);
> > > > +  }
> > > > +
> > > > +  if (Username != NULL) {
> > > > +    ZeroMem (Username, UsernameSize);
> > > > +    FreePool (Username);
> > > > +  }
> > > > +
> > > > +  if (Password != NULL) {
> > > > +    ZeroMem (Password, PasswordSize);
> > > > +    FreePool (Password);
> > > > +  }
> > > > +
> > > > +  if (AsciiLocation != NULL) {
> > > > +    FreePool (AsciiLocation);
> > > > +  }
> > > > +
> > > > +  if (Host != NULL) {
> > > > +    FreePool (Host);
> > > > +  }
> > > > +
> > > > +  return NewService;
> > > > +}
> > > > +
> > > > +/**
> > > > +  This function free resources in Redfish service. RedfishService is no longer
> > > available
> > > > +  after this function returns successfully.
> > > > +
> > > > +  @param[in]  This            Pointer to EDKII_REDFISH_HTTP_PROTOCOL
> > > instance.
> > > > +  @param[in]  RedfishService  Pointer to Redfish service to be released.
> > > > +
> > > > +  @retval     EFI_SUCCESS     Resrouce is released successfully.
> > > > +  @retval     Others          Errors occur.
> > > > +
> > > > +**/
> > > > +EFI_STATUS
> > > > +EFIAPI
> > > > +RedfishFreeRedfishService (
> > > > +  IN  EDKII_REDFISH_HTTP_PROTOCOL  *This,
> > > > +  IN  REDFISH_SERVICE              RedfishService
> > > > +  )
> > > > +{
> > > > +  REDFISH_SERVICE_PRIVATE  *Service;
> > > > +
> > > > +  if ((This == NULL) || (RedfishService == NULL)) {
> > > > +    return EFI_INVALID_PARAMETER;
> > > > +  }
> > > > +
> > > > +  Service = (REDFISH_SERVICE_PRIVATE *)RedfishService;
> > > > +  if (Service->Signature != REDFISH_HTTP_SERVICE_SIGNATURE) {
> > > > +    DEBUG ((DEBUG_ERROR, "%a: signature check failure\n", __func__));
> > > > +  }
> > > > +
> > > > +  return ReleaseRedfishService (Service);
> > > > +}
> > > > +
> > > > +/**
> > > > +  This function returns JSON value in given RedfishPayload. Returned JSON
> > > value
> > > > +  is a reference to the JSON value in RedfishPayload. Any modification to
> > > returned
> > > > +  JSON value will change JSON value in RedfishPayload.
> > > > +
> > > > +  @param[in]  This            Pointer to EDKII_REDFISH_HTTP_PROTOCOL
> > > instance.
> > > > +  @param[in]  RedfishPayload  Pointer to Redfish payload.
> > > > +
> > > > +  @retval     EDKII_JSON_VALUE   JSON value is returned.
> > > > +  @retval     NULL               Errors occur.
> > > > +
> > > > +**/
> > > > +EDKII_JSON_VALUE
> > > > +EFIAPI
> > > > +RedfishJsonInRedfishPayload (
> > > > +  IN  EDKII_REDFISH_HTTP_PROTOCOL  *This,
> > > > +  IN  REDFISH_PAYLOAD              RedfishPayload
> > > > +  )
> > > > +{
> > > > +  REDFISH_PAYLOAD_PRIVATE  *Payload;
> > > > +
> > > > +  if ((This == NULL) || (RedfishPayload == NULL)) {
> > > > +    return NULL;
> > > > +  }
> > > > +
> > > > +  Payload = (REDFISH_PAYLOAD_PRIVATE *)RedfishPayload;
> > > > +  if (Payload->Signature != REDFISH_HTTP_PAYLOAD_SIGNATURE) {
> > > > +    DEBUG ((DEBUG_ERROR, "%a: signature check failure\n", __func__));
> > > > +  }
> > > > +
> > > > +  return Payload->JsonValue;
> > > > +}
> > > > +
> > > > +/**
> > > > +  Perform HTTP GET to Get redfish resource from given resource URI with
> > > > +  cache mechanism supported. It's caller's responsibility to free Response
> > > > +  by calling FreeResponse ().
> > > > +
> > > > +  @param[in]  This          Pointer to EDKII_REDFISH_HTTP_PROTOCOL
> instance.
> > > > +  @param[in]  Service       Redfish service instance to perform HTTP GET.
> > > > +  @param[in]  Uri           Target resource URI.
> > > > +  @param[in]  Request       Additional request context. This is optional.
> > > > +  @param[out] Response      HTTP response from redfish service.
> > > > +  @param[in]  UseCache      If it is TRUE, this function will search for
> > > > +                            cache first. If it is FALSE, this function
> > > > +                            will query Redfish URI directly.
> > > > +
> > > > +  @retval     EFI_SUCCESS     Resrouce is returned successfully.
> > > > +  @retval     Others          Errors occur.
> > > > +
> > > > +**/
> > > > +EFI_STATUS
> > > > +EFIAPI
> > > > +RedfishGetResource (
> > > > +  IN  EDKII_REDFISH_HTTP_PROTOCOL  *This,
> > > > +  IN  REDFISH_SERVICE              Service,
> > > > +  IN  EFI_STRING                   Uri,
> > > > +  IN  REDFISH_REQUEST              *Request OPTIONAL,
> > > > +  OUT REDFISH_RESPONSE             *Response,
> > > > +  IN  BOOLEAN                      UseCache
> > > > +  )
> > > > +{
> > > > +  EFI_STATUS                  Status;
> > > > +  REDFISH_HTTP_CACHE_DATA     *CacheData;
> > > > +  UINTN                       RetryCount;
> > > > +  REDFISH_HTTP_CACHE_PRIVATE  *Private;
> > > > +
> > > > +  if ((This == NULL) || (Service == NULL) || (Response == NULL) ||
> > > IS_EMPTY_STRING (Uri)) {
> > > > +    return EFI_INVALID_PARAMETER;
> > > > +  }
> > > > +
> > > > +  DEBUG ((REDFISH_HTTP_CACHE_DEBUG, "%a: Get URI: %s cache:
> %a\n",
> > > __func__, Uri, (UseCache ? "true" : "false")));
> > > > +
> > > > +  Private    = REDFISH_HTTP_CACHE_PRIVATE_FROM_THIS (This);
> > > > +  CacheData  = NULL;
> > > > +  RetryCount = 0;
> > > > +  ZeroMem (Response, sizeof (REDFISH_RESPONSE));
> > > > +
> > > > +  if (Private->CacheDisabled) {
> > > > +    UseCache = FALSE;
> > > > +    DEBUG ((REDFISH_HTTP_CACHE_DEBUG, "%a: cache is disabled by
> > > PCD!\n", __func__));
> > > > +  }
> > > > +
> > > > +  //
> > > > +  // Search for cache list.
> > > > +  //
> > > > +  if (UseCache) {
> > > > +    CacheData = FindHttpCacheData (&Private->CacheList.Head, Uri);
> > > > +    if (CacheData != NULL) {
> > > > +      DEBUG ((REDFISH_HTTP_CACHE_DEBUG_REQUEST, "%a: cache hit!
> %s\n",
> > > __func__, Uri));
> > > > +
> > > > +      //
> > > > +      // Copy cached response to caller's buffer.
> > > > +      //
> > > > +      Status               = CopyRedfishResponse (CacheData->Response,
> Response);
> > > > +      CacheData->HitCount += 1;
> > > > +      return Status;
> > > > +    }
> > > > +  }
> > > > +
> > > > +  //
> > > > +  // Get resource from redfish service.
> > > > +  //
> > > > +  do {
> > > > +    RetryCount += 1;
> > > > +    Status      = HttpSendReceive (
> > > > +                    Service,
> > > > +                    Uri,
> > > > +                    HttpMethodGet,
> > > > +                    Request,
> > > > +                    Response
> > > > +                    );
> > > > +    DEBUG ((REDFISH_HTTP_CACHE_DEBUG_REQUEST, "%a: HTTP request:
> > > %s :%r\n", __func__, Uri, Status));
> > > > +    if (!EFI_ERROR (Status) || (RetryCount >= Private-
> > > >RetrySetting.MaximumRetryGet)) {
> > > > +      break;
> > > > +    }
> > > > +
> > > > +    //
> > > > +    // Retry when BMC is not ready.
> > > > +    //
> > > > +    if ((Response->StatusCode != NULL)) {
> > > > +      DEBUG_CODE (
> > > > +        DumpRedfishResponse (NULL, DEBUG_ERROR, Response);
> > > > +        );
> > > > +
> > > > +      if (!RedfishRetryRequired (Response->StatusCode)) {
> > > > +        break;
> > > > +      }
> > > > +
> > > > +      //
> > > > +      // Release response for next round of request.
> > > > +      //
> > > > +      This->FreeResponse (This, Response);
> > > > +    }
> > > > +
> > > > +    DEBUG ((DEBUG_WARN, "%a: RedfishGetByUriEx failed, retry
> (%d/%d)\n",
> > > __func__, RetryCount, Private->RetrySetting.MaximumRetryGet));
> > > > +    if (Private->RetrySetting.RetryWait > 0) {
> > > > +      gBS->Stall (Private->RetrySetting.RetryWait);
> > > > +    }
> > > > +  } while (TRUE);
> > > > +
> > > > +  if (EFI_ERROR (Status)) {
> > > > +    DEBUG_CODE (
> > > > +      DumpRedfishResponse (NULL, DEBUG_ERROR, Response);
> > > > +      );
> > > > +    //
> > > > +    // Report status code for Redfish failure
> > > > +    //
> > > > +    ReportHttpError (HttpMethodGet, Uri, Response->StatusCode);
> > > > +    DEBUG ((DEBUG_ERROR, "%a: get %s failed (%d/%d): %r\n", __func__,
> Uri,
> > > RetryCount, Private->RetrySetting.MaximumRetryGet, Status));
> > > > +    goto ON_RELEASE;
> > > > +  }
> > > > +
> > > > +  if (!Private->CacheDisabled) {
> > > > +    //
> > > > +    // Keep response in cache list
> > > > +    //
> > > > +    Status = AddHttpCacheData (&Private->CacheList, Uri, Response);
> > > > +    if (EFI_ERROR (Status)) {
> > > > +      DEBUG ((DEBUG_ERROR, "%a: failed to cache %s: %r\n", __func__, Uri,
> > > Status));
> > > > +      goto ON_RELEASE;
> > > > +    }
> > > > +
> > > > +    DEBUG_CODE (
> > > > +      DebugPrintHttpCacheList (__func__,
> > > REDFISH_HTTP_CACHE_DEBUG_DUMP, &Private->CacheList);
> > > > +      );
> > > > +  }
> > > > +
> > > > +ON_RELEASE:
> > > > +
> > > > +  return Status;
> > > > +}
> > > > +
> > > > +/**
> > > > +  This function free resources in Request. Request is no longer available
> > > > +  after this function returns successfully.
> > > > +
> > > > +  @param[in]  This         Pointer to EDKII_REDFISH_HTTP_PROTOCOL
> instance.
> > > > +  @param[in]  Request      HTTP request to be released.
> > > > +
> > > > +  @retval     EFI_SUCCESS     Resrouce is released successfully.
> > > > +  @retval     Others          Errors occur.
> > > > +
> > > > +**/
> > > > +EFI_STATUS
> > > > +EFIAPI
> > > > +RedfishFreeRequest (
> > > > +  IN  EDKII_REDFISH_HTTP_PROTOCOL  *This,
> > > > +  IN  REDFISH_REQUEST              *Request
> > > > +  )
> > > > +{
> > > > +  if ((This == NULL) || (Request == NULL)) {
> > > > +    return EFI_INVALID_PARAMETER;
> > > > +  }
> > > > +
> > > > +  DEBUG ((REDFISH_HTTP_CACHE_DEBUG, "%a: entry\n", __func__));
> > > > +
> > > > +  return ReleaseRedfishRequest (Request);
> > > > +}
> > > > +
> > > > +/**
> > > > +  This function free resources in given Response.
> > > > +
> > > > +  @param[in]  This         Pointer to EDKII_REDFISH_HTTP_PROTOCOL
> instance.
> > > > +  @param[in]  Response     HTTP response to be released.
> > > > +
> > > > +  @retval     EFI_SUCCESS     Resrouce is released successfully.
> > > > +  @retval     Others          Errors occur.
> > > > +
> > > > +**/
> > > > +EFI_STATUS
> > > > +EFIAPI
> > > > +RedfishFreeResponse (
> > > > +  IN  EDKII_REDFISH_HTTP_PROTOCOL  *This,
> > > > +  IN  REDFISH_RESPONSE             *Response
> > > > +  )
> > > > +{
> > > > +  if ((This == NULL) || (Response == NULL)) {
> > > > +    return EFI_INVALID_PARAMETER;
> > > > +  }
> > > > +
> > > > +  DEBUG ((REDFISH_HTTP_CACHE_DEBUG, "%a: entry\n", __func__));
> > > > +
> > > > +  return ReleaseRedfishResponse (Response);
> > > > +}
> > > > +
> > > > +/**
> > > > +  This function expire the cached response of given URI.
> > > > +
> > > > +  @param[in]  This         Pointer to EDKII_REDFISH_HTTP_PROTOCOL
> instance.
> > > > +  @param[in]  Uri          Target response of URI.
> > > > +
> > > > +  @retval     EFI_SUCCESS     Target response is expired successfully.
> > > > +  @retval     Others          Errors occur.
> > > > +
> > > > +**/
> > > > +EFI_STATUS
> > > > +EFIAPI
> > > > +RedfishExpireResponse (
> > > > +  IN  EDKII_REDFISH_HTTP_PROTOCOL  *This,
> > > > +  IN  EFI_STRING                   Uri
> > > > +  )
> > > > +{
> > > > +  REDFISH_HTTP_CACHE_PRIVATE  *Private;
> > > > +  REDFISH_HTTP_CACHE_DATA     *CacheData;
> > > > +
> > > > +  if ((This == NULL) || IS_EMPTY_STRING (Uri)) {
> > > > +    return EFI_INVALID_PARAMETER;
> > > > +  }
> > > > +
> > > > +  DEBUG ((REDFISH_HTTP_CACHE_DEBUG, "%a: expire URI: %s\n",
> __func__,
> > > Uri));
> > > > +
> > > > +  Private = REDFISH_HTTP_CACHE_PRIVATE_FROM_THIS (This);
> > > > +
> > > > +  CacheData = FindHttpCacheData (&Private->CacheList.Head, Uri);
> > > > +  if (CacheData == NULL) {
> > > > +    return EFI_NOT_FOUND;
> > > > +  }
> > > > +
> > > > +  return DeleteHttpCacheData (&Private->CacheList, CacheData);
> > > > +}
> > > > +
> > > > +/**
> > > > +  Perform HTTP PATCH to send redfish resource to given resource URI.
> > > > +  It's caller's responsibility to free Response by calling FreeResponse ().
> > > > +
> > > > +  @param[in]  This          Pointer to EDKII_REDFISH_HTTP_PROTOCOL
> instance.
> > > > +  @param[in]  Service       Redfish service instance to perform HTTP PATCH.
> > > > +  @param[in]  Uri           Target resource URI.
> > > > +  @param[in]  Content       Data to patch.
> > > > +  @param[in]  ContentSize   Size of the Content to be send to Redfish
> service.
> > > > +                            This is optional. When ContentSize is 0, ContentSize
> > > > +                            is the size of Content.
> > > > +  @param[in]  ContentType   Type of the Content to be send to Redfish
> service.
> > > > +                            This is optional. When ContentType is NULL, content
> > > > +                            type HTTP_CONTENT_TYPE_APP_JSON will be used.
> > > > +  @param[out] Response      HTTP response from redfish service.
> > > > +
> > > > +  @retval     EFI_SUCCESS     Resrouce is returned successfully.
> > > > +  @retval     Others          Errors occur.
> > > > +
> > > > +**/
> > > > +EFI_STATUS
> > > > +EFIAPI
> > > > +RedfishPatchResource (
> > > > +  IN  EDKII_REDFISH_HTTP_PROTOCOL  *This,
> > > > +  IN  REDFISH_SERVICE              Service,
> > > > +  IN  EFI_STRING                   Uri,
> > > > +  IN  CHAR8                        *Content,
> > > > +  IN  UINTN                        ContentSize OPTIONAL,
> > > > +  IN  CHAR8                        *ContentType OPTIONAL,
> > > > +  OUT REDFISH_RESPONSE             *Response
> > > > +  )
> > > > +{
> > > > +  EFI_STATUS                  Status;
> > > > +  UINTN                       RetryCount;
> > > > +  REDFISH_REQUEST             Request;
> > > > +  REDFISH_HTTP_CACHE_PRIVATE  *Private;
> > > > +
> > > > +  if ((This == NULL) || (Service == NULL) || (Response == NULL) ||
> > > IS_EMPTY_STRING (Uri) || IS_EMPTY_STRING (Content)) {
> > > > +    return EFI_INVALID_PARAMETER;
> > > > +  }
> > > > +
> > > > +  DEBUG ((REDFISH_HTTP_CACHE_DEBUG, "%a: Patch URI: %s\n",
> __func__,
> > > Uri));
> > > > +
> > > > +  Private    = REDFISH_HTTP_CACHE_PRIVATE_FROM_THIS (This);
> > > > +  RetryCount = 0;
> > > > +  ZeroMem (Response, sizeof (REDFISH_RESPONSE));
> > > > +  ZeroMem (&Request, sizeof (REDFISH_REQUEST));
> > > > +
> > > > +  Request.Content       = Content;
> > > > +  Request.ContentLength = ContentSize;
> > > > +  Request.ContentType   = ContentType;
> > > > +
> > > > +  //
> > > > +  // Patch resource to redfish service.
> > > > +  //
> > > > +  do {
> > > > +    RetryCount += 1;
> > > > +    Status      = HttpSendReceive (
> > > > +                    Service,
> > > > +                    Uri,
> > > > +                    HttpMethodPatch,
> > > > +                    &Request,
> > > > +                    Response
> > > > +                    );
> > > > +    DEBUG ((REDFISH_HTTP_CACHE_DEBUG_REQUEST, "%a: HTTP request:
> > > %s :%r\n", __func__, Uri, Status));
> > > > +    if (!EFI_ERROR (Status) || (RetryCount >= Private-
> > > >RetrySetting.MaximumRetryPatch)) {
> > > > +      break;
> > > > +    }
> > > > +
> > > > +    //
> > > > +    // Retry when BMC is not ready.
> > > > +    //
> > > > +    if ((Response->StatusCode != NULL)) {
> > > > +      DEBUG_CODE (
> > > > +        DumpRedfishResponse (NULL, DEBUG_ERROR, Response);
> > > > +        );
> > > > +
> > > > +      if (!RedfishRetryRequired (Response->StatusCode)) {
> > > > +        break;
> > > > +      }
> > > > +
> > > > +      //
> > > > +      // Release response for next round of request.
> > > > +      //
> > > > +      This->FreeResponse (This, Response);
> > > > +    }
> > > > +
> > > > +    DEBUG ((DEBUG_WARN, "%a: RedfishPatchToUriEx failed, retry
> (%d/%d)\n",
> > > __func__, RetryCount, Private->RetrySetting.MaximumRetryPatch));
> > > > +    if (Private->RetrySetting.RetryWait > 0) {
> > > > +      gBS->Stall (Private->RetrySetting.RetryWait);
> > > > +    }
> > > > +  } while (TRUE);
> > > > +
> > > > +  //
> > > > +  // Redfish resource is updated. Automatically expire the cached response
> > > > +  // so application can directly get resource from Redfish service again.
> > > > +  //
> > > > +  DEBUG ((REDFISH_HTTP_CACHE_DEBUG, "%a: Resource is updated,
> expire
> > > URI: %s\n", __func__, Uri));
> > > > +  RedfishExpireResponse (This, Uri);
> > > > +
> > > > +  if (EFI_ERROR (Status)) {
> > > > +    DEBUG_CODE (
> > > > +      DumpRedfishResponse (NULL, DEBUG_ERROR, Response);
> > > > +      );
> > > > +    //
> > > > +    // Report status code for Redfish failure
> > > > +    //
> > > > +    ReportHttpError (HttpMethodPatch, Uri, Response->StatusCode);
> > > > +    DEBUG ((DEBUG_ERROR, "%a: patch %s failed (%d/%d): %r\n",
> __func__,
> > > Uri, RetryCount, Private->RetrySetting.MaximumRetryPatch, Status));
> > > > +    goto ON_RELEASE;
> > > > +  }
> > > > +
> > > > +ON_RELEASE:
> > > > +
> > > > +  return Status;
> > > > +}
> > > > +
> > > > +/**
> > > > +  Perform HTTP PUT to send redfish resource to given resource URI.
> > > > +  It's caller's responsibility to free Response by calling FreeResponse ().
> > > > +
> > > > +  @param[in]  This          Pointer to EDKII_REDFISH_HTTP_PROTOCOL
> instance.
> > > > +  @param[in]  Service       Redfish service instance to perform HTTP PUT.
> > > > +  @param[in]  Uri           Target resource URI.
> > > > +  @param[in]  Content       Data to put.
> > > > +  @param[in]  ContentSize   Size of the Content to be send to Redfish
> service.
> > > > +                            This is optional. When ContentSize is 0, ContentSize
> > > > +                            is the size of Content.
> > > > +  @param[in]  ContentType   Type of the Content to be send to Redfish
> service.
> > > > +                            This is optional. When ContentType is NULL, content
> > > > +                            type HTTP_CONTENT_TYPE_APP_JSON will be used.
> > > > +  @param[out] Response      HTTP response from redfish service.
> > > > +
> > > > +  @retval     EFI_SUCCESS     Resrouce is returned successfully.
> > > > +  @retval     Others          Errors occur.
> > > > +
> > > > +**/
> > > > +EFI_STATUS
> > > > +EFIAPI
> > > > +RedfishPutResource (
> > > > +  IN  EDKII_REDFISH_HTTP_PROTOCOL  *This,
> > > > +  IN  REDFISH_SERVICE              Service,
> > > > +  IN  EFI_STRING                   Uri,
> > > > +  IN  CHAR8                        *Content,
> > > > +  IN  UINTN                        ContentSize OPTIONAL,
> > > > +  IN  CHAR8                        *ContentType OPTIONAL,
> > > > +  OUT REDFISH_RESPONSE             *Response
> > > > +  )
> > > > +{
> > > > +  EFI_STATUS                  Status;
> > > > +  UINTN                       RetryCount;
> > > > +  REDFISH_REQUEST             Request;
> > > > +  REDFISH_HTTP_CACHE_PRIVATE  *Private;
> > > > +
> > > > +  if ((This == NULL) || (Service == NULL) || (Response == NULL) ||
> > > IS_EMPTY_STRING (Uri) || IS_EMPTY_STRING (Content)) {
> > > > +    return EFI_INVALID_PARAMETER;
> > > > +  }
> > > > +
> > > > +  DEBUG ((REDFISH_HTTP_CACHE_DEBUG, "%a: Put URI: %s\n", __func__,
> > > Uri));
> > > > +
> > > > +  Private    = REDFISH_HTTP_CACHE_PRIVATE_FROM_THIS (This);
> > > > +  RetryCount = 0;
> > > > +  ZeroMem (Response, sizeof (REDFISH_RESPONSE));
> > > > +  ZeroMem (&Request, sizeof (REDFISH_REQUEST));
> > > > +
> > > > +  Request.Content       = Content;
> > > > +  Request.ContentLength = ContentSize;
> > > > +  Request.ContentType   = ContentType;
> > > > +
> > > > +  //
> > > > +  // Patch resource to redfish service.
> > > > +  //
> > > > +  do {
> > > > +    RetryCount += 1;
> > > > +    Status      = HttpSendReceive (
> > > > +                    Service,
> > > > +                    Uri,
> > > > +                    HttpMethodPut,
> > > > +                    &Request,
> > > > +                    Response
> > > > +                    );
> > > > +    DEBUG ((REDFISH_HTTP_CACHE_DEBUG_REQUEST, "%a: HTTP request:
> > > %s :%r\n", __func__, Uri, Status));
> > > > +    if (!EFI_ERROR (Status) || (RetryCount >= Private-
> > > >RetrySetting.MaximumRetryPut)) {
> > > > +      break;
> > > > +    }
> > > > +
> > > > +    //
> > > > +    // Retry when BMC is not ready.
> > > > +    //
> > > > +    if ((Response->StatusCode != NULL)) {
> > > > +      DEBUG_CODE (
> > > > +        DumpRedfishResponse (NULL, DEBUG_ERROR, Response);
> > > > +        );
> > > > +
> > > > +      if (!RedfishRetryRequired (Response->StatusCode)) {
> > > > +        break;
> > > > +      }
> > > > +
> > > > +      //
> > > > +      // Release response for next round of request.
> > > > +      //
> > > > +      This->FreeResponse (This, Response);
> > > > +    }
> > > > +
> > > > +    DEBUG ((DEBUG_WARN, "%a: RedfishPutToUri failed, retry (%d/%d)\n",
> > > __func__, RetryCount, Private->RetrySetting.MaximumRetryPut));
> > > > +    if (Private->RetrySetting.RetryWait > 0) {
> > > > +      gBS->Stall (Private->RetrySetting.RetryWait);
> > > > +    }
> > > > +  } while (TRUE);
> > > > +
> > > > +  //
> > > > +  // Redfish resource is updated. Automatically expire the cached response
> > > > +  // so application can directly get resource from Redfish service again.
> > > > +  //
> > > > +  DEBUG ((REDFISH_HTTP_CACHE_DEBUG, "%a: Resource is updated,
> expire
> > > URI: %s\n", __func__, Uri));
> > > > +  RedfishExpireResponse (This, Uri);
> > > > +
> > > > +  if (EFI_ERROR (Status)) {
> > > > +    DEBUG_CODE (
> > > > +      DumpRedfishResponse (NULL, DEBUG_ERROR, Response);
> > > > +      );
> > > > +    //
> > > > +    // Report status code for Redfish failure
> > > > +    //
> > > > +    ReportHttpError (HttpMethodPut, Uri, Response->StatusCode);
> > > > +    DEBUG ((DEBUG_ERROR, "%a: put %s failed (%d/%d): %r\n", __func__,
> Uri,
> > > RetryCount, Private->RetrySetting.MaximumRetryPut, Status));
> > > > +    goto ON_RELEASE;
> > > > +  }
> > > > +
> > > > +ON_RELEASE:
> > > > +
> > > > +  return Status;
> > > > +}
> > > > +
> > > > +/**
> > > > +  Perform HTTP POST to send redfish resource to given resource URI.
> > > > +  It's caller's responsibility to free Response by calling FreeResponse ().
> > > > +
> > > > +  @param[in]  This          Pointer to EDKII_REDFISH_HTTP_PROTOCOL
> instance.
> > > > +  @param[in]  Service       Redfish service instance to perform HTTP POST.
> > > > +  @param[in]  Uri           Target resource URI.
> > > > +  @param[in]  Content       Data to post.
> > > > +  @param[in]  ContentSize   Size of the Content to be send to Redfish
> service.
> > > > +                            This is optional. When ContentSize is 0, ContentSize
> > > > +                            is the size of Content.
> > > > +  @param[in]  ContentType   Type of the Content to be send to Redfish
> service.
> > > > +                            This is optional. When ContentType is NULL, content
> > > > +                            type HTTP_CONTENT_TYPE_APP_JSON will be used.
> > > > +  @param[out] Response      HTTP response from redfish service.
> > > > +
> > > > +  @retval     EFI_SUCCESS     Resrouce is returned successfully.
> > > > +  @retval     Others          Errors occur.
> > > > +
> > > > +**/
> > > > +EFI_STATUS
> > > > +EFIAPI
> > > > +RedfishPostResource (
> > > > +  IN  EDKII_REDFISH_HTTP_PROTOCOL  *This,
> > > > +  IN  REDFISH_SERVICE              Service,
> > > > +  IN  EFI_STRING                   Uri,
> > > > +  IN  CHAR8                        *Content,
> > > > +  IN  UINTN                        ContentSize OPTIONAL,
> > > > +  IN  CHAR8                        *ContentType OPTIONAL,
> > > > +  OUT REDFISH_RESPONSE             *Response
> > > > +  )
> > > > +{
> > > > +  EFI_STATUS                  Status;
> > > > +  UINTN                       RetryCount;
> > > > +  REDFISH_REQUEST             Request;
> > > > +  REDFISH_HTTP_CACHE_PRIVATE  *Private;
> > > > +
> > > > +  if ((This == NULL) || (Service == NULL) || (Response == NULL) ||
> > > IS_EMPTY_STRING (Uri) || IS_EMPTY_STRING (Content)) {
> > > > +    return EFI_INVALID_PARAMETER;
> > > > +  }
> > > > +
> > > > +  DEBUG ((REDFISH_HTTP_CACHE_DEBUG, "%a: Post URI: %s\n",
> __func__,
> > > Uri));
> > > > +
> > > > +  Private    = REDFISH_HTTP_CACHE_PRIVATE_FROM_THIS (This);
> > > > +  RetryCount = 0;
> > > > +  ZeroMem (Response, sizeof (REDFISH_RESPONSE));
> > > > +  ZeroMem (&Request, sizeof (REDFISH_REQUEST));
> > > > +
> > > > +  Request.Content       = Content;
> > > > +  Request.ContentLength = ContentSize;
> > > > +  Request.ContentType   = ContentType;
> > > > +
> > > > +  //
> > > > +  // Patch resource to redfish service.
> > > > +  //
> > > > +  do {
> > > > +    RetryCount += 1;
> > > > +    Status      = HttpSendReceive (
> > > > +                    Service,
> > > > +                    Uri,
> > > > +                    HttpMethodPost,
> > > > +                    &Request,
> > > > +                    Response
> > > > +                    );
> > > > +    DEBUG ((REDFISH_HTTP_CACHE_DEBUG_REQUEST, "%a: HTTP request:
> > > %s :%r\n", __func__, Uri, Status));
> > > > +    if (!EFI_ERROR (Status) || (RetryCount >= Private-
> > > >RetrySetting.MaximumRetryPost)) {
> > > > +      break;
> > > > +    }
> > > > +
> > > > +    //
> > > > +    // Retry when BMC is not ready.
> > > > +    //
> > > > +    if ((Response->StatusCode != NULL)) {
> > > > +      DEBUG_CODE (
> > > > +        DumpRedfishResponse (NULL, DEBUG_ERROR, Response);
> > > > +        );
> > > > +
> > > > +      if (!RedfishRetryRequired (Response->StatusCode)) {
> > > > +        break;
> > > > +      }
> > > > +
> > > > +      //
> > > > +      // Release response for next round of request.
> > > > +      //
> > > > +      This->FreeResponse (This, Response);
> > > > +    }
> > > > +
> > > > +    DEBUG ((DEBUG_WARN, "%a: RedfishPostToUri failed, retry (%d/%d)\n",
> > > __func__, RetryCount, Private->RetrySetting.MaximumRetryPost));
> > > > +    if (Private->RetrySetting.RetryWait > 0) {
> > > > +      gBS->Stall (Private->RetrySetting.RetryWait);
> > > > +    }
> > > > +  } while (TRUE);
> > > > +
> > > > +  //
> > > > +  // Redfish resource is updated. Automatically expire the cached response
> > > > +  // so application can directly get resource from Redfish service again.
> > > > +  //
> > > > +  DEBUG ((REDFISH_HTTP_CACHE_DEBUG, "%a: Resource is updated,
> expire
> > > URI: %s\n", __func__, Uri));
> > > > +  RedfishExpireResponse (This, Uri);
> > > > +
> > > > +  if (EFI_ERROR (Status)) {
> > > > +    DEBUG_CODE (
> > > > +      DumpRedfishResponse (NULL, DEBUG_ERROR, Response);
> > > > +      );
> > > > +    //
> > > > +    // Report status code for Redfish failure
> > > > +    //
> > > > +    ReportHttpError (HttpMethodPost, Uri, Response->StatusCode);
> > > > +    DEBUG ((DEBUG_ERROR, "%a: post %s failed (%d/%d): %r\n", __func__,
> Uri,
> > > RetryCount, Private->RetrySetting.MaximumRetryPost, Status));
> > > > +    goto ON_RELEASE;
> > > > +  }
> > > > +
> > > > +ON_RELEASE:
> > > > +
> > > > +  return Status;
> > > > +}
> > > > +
> > > > +/**
> > > > +  Perform HTTP DELETE to delete redfish resource on given resource URI.
> > > > +  It's caller's responsibility to free Response by calling FreeResponse ().
> > > > +
> > > > +  @param[in]  This          Pointer to EDKII_REDFISH_HTTP_PROTOCOL
> instance.
> > > > +  @param[in]  Service       Redfish service instance to perform HTTP
> DELETE.
> > > > +  @param[in]  Uri           Target resource URI.
> > > > +  @param[in]  Content       JSON represented properties to be deleted. This
> is
> > > > +                            optional.
> > > > +  @param[in]  ContentSize   Size of the Content to be send to Redfish
> service.
> > > > +                            This is optional. When ContentSize is 0, ContentSize
> > > > +                            is the size of Content if Content is not NULL.
> > > > +  @param[in]  ContentType   Type of the Content to be send to Redfish
> service.
> > > > +                            This is optional. When Content is not NULL and
> > > > +                            ContentType is NULL, content type
> > > HTTP_CONTENT_TYPE_APP_JSON
> > > > +                            will be used.
> > > > +  @param[out] Response      HTTP response from redfish service.
> > > > +
> > > > +  @retval     EFI_SUCCESS     Resrouce is returned successfully.
> > > > +  @retval     Others          Errors occur.
> > > > +
> > > > +**/
> > > > +EFI_STATUS
> > > > +EFIAPI
> > > > +RedfishDeleteResource (
> > > > +  IN  EDKII_REDFISH_HTTP_PROTOCOL  *This,
> > > > +  IN  REDFISH_SERVICE              Service,
> > > > +  IN  EFI_STRING                   Uri,
> > > > +  IN  CHAR8                        *Content OPTIONAL,
> > > > +  IN  UINTN                        ContentSize OPTIONAL,
> > > > +  IN  CHAR8                        *ContentType OPTIONAL,
> > > > +  OUT REDFISH_RESPONSE             *Response
> > > > +  )
> > > > +{
> > > > +  EFI_STATUS                  Status;
> > > > +  UINTN                       RetryCount;
> > > > +  REDFISH_REQUEST             Request;
> > > > +  REDFISH_HTTP_CACHE_PRIVATE  *Private;
> > > > +
> > > > +  if ((This == NULL) || (Service == NULL) || (Response == NULL) ||
> > > IS_EMPTY_STRING (Uri)) {
> > > > +    return EFI_INVALID_PARAMETER;
> > > > +  }
> > > > +
> > > > +  DEBUG ((REDFISH_HTTP_CACHE_DEBUG, "%a: Delete URI: %s\n",
> __func__,
> > > Uri));
> > > > +
> > > > +  Private    = REDFISH_HTTP_CACHE_PRIVATE_FROM_THIS (This);
> > > > +  RetryCount = 0;
> > > > +  ZeroMem (Response, sizeof (REDFISH_RESPONSE));
> > > > +  ZeroMem (&Request, sizeof (REDFISH_REQUEST));
> > > > +
> > > > +  Request.Content       = Content;
> > > > +  Request.ContentLength = ContentSize;
> > > > +  Request.ContentType   = ContentType;
> > > > +
> > > > +  //
> > > > +  // Patch resource to redfish service.
> > > > +  //
> > > > +  do {
> > > > +    RetryCount += 1;
> > > > +    Status      = HttpSendReceive (
> > > > +                    Service,
> > > > +                    Uri,
> > > > +                    HttpMethodDelete,
> > > > +                    &Request,
> > > > +                    Response
> > > > +                    );
> > > > +    DEBUG ((REDFISH_HTTP_CACHE_DEBUG_REQUEST, "%a: HTTP request:
> > > %s :%r\n", __func__, Uri, Status));
> > > > +    if (!EFI_ERROR (Status) || (RetryCount >= Private-
> > > >RetrySetting.MaximumRetryDelete)) {
> > > > +      break;
> > > > +    }
> > > > +
> > > > +    //
> > > > +    // Retry when BMC is not ready.
> > > > +    //
> > > > +    if ((Response->StatusCode != NULL)) {
> > > > +      DEBUG_CODE (
> > > > +        DumpRedfishResponse (NULL, DEBUG_ERROR, Response);
> > > > +        );
> > > > +
> > > > +      if (!RedfishRetryRequired (Response->StatusCode)) {
> > > > +        break;
> > > > +      }
> > > > +
> > > > +      //
> > > > +      // Release response for next round of request.
> > > > +      //
> > > > +      This->FreeResponse (This, Response);
> > > > +    }
> > > > +
> > > > +    DEBUG ((DEBUG_WARN, "%a: RedfishDeleteByUri failed, retry
> (%d/%d)\n",
> > > __func__, RetryCount, Private->RetrySetting.MaximumRetryDelete));
> > > > +    if (Private->RetrySetting.RetryWait > 0) {
> > > > +      gBS->Stall (Private->RetrySetting.RetryWait);
> > > > +    }
> > > > +  } while (TRUE);
> > > > +
> > > > +  //
> > > > +  // Redfish resource is updated. Automatically expire the cached response
> > > > +  // so application can directly get resource from Redfish service again.
> > > > +  //
> > > > +  DEBUG ((REDFISH_HTTP_CACHE_DEBUG, "%a: Resource is updated,
> expire
> > > URI: %s\n", __func__, Uri));
> > > > +  RedfishExpireResponse (This, Uri);
> > > > +
> > > > +  if (EFI_ERROR (Status)) {
> > > > +    DEBUG_CODE (
> > > > +      DumpRedfishResponse (NULL, DEBUG_ERROR, Response);
> > > > +      );
> > > > +    //
> > > > +    // Report status code for Redfish failure
> > > > +    //
> > > > +    ReportHttpError (HttpMethodDelete, Uri, Response->StatusCode);
> > > > +    DEBUG ((DEBUG_ERROR, "%a: delete %s failed (%d/%d): %r\n",
> __func__,
> > > Uri, RetryCount, Private->RetrySetting.MaximumRetryDelete, Status));
> > > > +    goto ON_RELEASE;
> > > > +  }
> > > > +
> > > > +ON_RELEASE:
> > > > +
> > > > +  return Status;
> > > > +}
> > > > +
> > > > +EDKII_REDFISH_HTTP_PROTOCOL  mEdkIIRedfishHttpProtocol = {
> > > > +  EDKII_REDFISH_HTTP_PROTOCOL_REVISION,
> > > > +  RedfishCreateRedfishService,
> > > > +  RedfishFreeRedfishService,
> > > > +  RedfishJsonInRedfishPayload,
> > > > +  RedfishGetResource,
> > > > +  RedfishPatchResource,
> > > > +  RedfishPutResource,
> > > > +  RedfishPostResource,
> > > > +  RedfishDeleteResource,
> > > > +  RedfishFreeRequest,
> > > > +  RedfishFreeResponse,
> > > > +  RedfishExpireResponse
> > > > +};
> > > > +
> > > > +/**
> > > > +  Unloads an image.
> > > > +
> > > > +  @param[in]  ImageHandle         Handle that identifies the image to be
> > > unloaded.
> > > > +
> > > > +  @retval EFI_SUCCESS             The image has been unloaded.
> > > > +  @retval EFI_INVALID_PARAMETER   ImageHandle is not a valid image
> > > handle.
> > > > +
> > > > +**/
> > > > +EFI_STATUS
> > > > +EFIAPI
> > > > +RedfishHttpDriverUnload (
> > > > +  IN EFI_HANDLE  ImageHandle
> > > > +  )
> > > > +{
> > > > +  if (mRedfishHttpCachePrivate == NULL) {
> > > > +    return EFI_SUCCESS;
> > > > +  }
> > > > +
> > > > +  if (!IsListEmpty (&mRedfishHttpCachePrivate->CacheList.Head)) {
> > > > +    ReleaseCacheList (&mRedfishHttpCachePrivate->CacheList);
> > > > +  }
> > > > +
> > > > +  gBS->UninstallMultipleProtocolInterfaces (
> > > > +         ImageHandle,
> > > > +         &gEdkIIRedfishHttpProtocolGuid,
> > > > +         &mRedfishHttpCachePrivate->Protocol,
> > > > +         NULL
> > > > +         );
> > > > +
> > > > +  FreePool (mRedfishHttpCachePrivate);
> > > > +  mRedfishHttpCachePrivate = NULL;
> > > > +
> > > > +  return EFI_SUCCESS;
> > > > +}
> > > > +
> > > > +/**
> > > > +  This is a EDKII_REDFISH_CREDENTIAL_PROTOCOL notification event
> handler.
> > > > +
> > > > +  @param[in] Event    Event whose notification function is being invoked.
> > > > +  @param[in] Context  Pointer to the notification function's context.
> > > > +
> > > > +**/
> > > > +VOID
> > > > +EFIAPI
> > > > +CredentialProtocolInstalled (
> > > > +  IN  EFI_EVENT  Event,
> > > > +  IN  VOID       *Context
> > > > +  )
> > > > +{
> > > > +  EFI_STATUS                  Status;
> > > > +  REDFISH_HTTP_CACHE_PRIVATE  *Private;
> > > > +
> > > > +  Private = (REDFISH_HTTP_CACHE_PRIVATE *)Context;
> > > > +  if (Private->Signature != REDFISH_HTTP_DRIVER_SIGNATURE) {
> > > > +    DEBUG ((DEBUG_ERROR, "%a: signature check failure\n", __func__));
> > > > +    return;
> > > > +  }
> > > > +
> > > > +  //
> > > > +  // Locate HII database protocol.
> > > > +  //
> > > > +  Status = gBS->LocateProtocol (
> > > > +                  &gEdkIIRedfishCredentialProtocolGuid,
> > > > +                  NULL,
> > > > +                  (VOID **)&Private->CredentialProtocol
> > > > +                  );
> > > > +  if (EFI_ERROR (Status)) {
> > > > +    return;
> > > > +  }
> > > > +
> > > > +  gBS->CloseEvent (Event);
> > > > +}
> > > > +
> > > > +/**
> > > > +  Main entry for this driver.
> > > > +
> > > > +  @param[in] ImageHandle     Image handle this driver.
> > > > +  @param[in] SystemTable     Pointer to SystemTable.
> > > > +
> > > > +  @retval EFI_SUCCESS     This function always complete successfully.
> > > > +
> > > > +**/
> > > > +EFI_STATUS
> > > > +EFIAPI
> > > > +RedfishHttpEntryPoint (
> > > > +  IN EFI_HANDLE        ImageHandle,
> > > > +  IN EFI_SYSTEM_TABLE  *SystemTable
> > > > +  )
> > > > +{
> > > > +  EFI_STATUS  Status;
> > > > +  VOID        *Registration;
> > > > +
> > > > +  if (mRedfishHttpCachePrivate != NULL) {
> > > > +    return EFI_ALREADY_STARTED;
> > > > +  }
> > > > +
> > > > +  mRedfishHttpCachePrivate = AllocateZeroPool (sizeof
> > > (REDFISH_HTTP_CACHE_PRIVATE));
> > > > +  if (mRedfishHttpCachePrivate == NULL) {
> > > > +    return EFI_OUT_OF_RESOURCES;
> > > > +  }
> > > > +
> > > > +  //
> > > > +  // Initial cache list and protocol instance.
> > > > +  //
> > > > +  mRedfishHttpCachePrivate->Signature   =
> > > REDFISH_HTTP_DRIVER_SIGNATURE;
> > > > +  mRedfishHttpCachePrivate->ImageHandle = ImageHandle;
> > > > +  CopyMem (&mRedfishHttpCachePrivate->Protocol,
> > > &mEdkIIRedfishHttpProtocol, sizeof (EDKII_REDFISH_HTTP_PROTOCOL));
> > > > +  mRedfishHttpCachePrivate->CacheList.Capacity =
> > > REDFISH_HTTP_CACHE_LIST_SIZE;
> > > > +  mRedfishHttpCachePrivate->CacheList.Count    = 0x00;
> > > > +  mRedfishHttpCachePrivate->CacheDisabled      = PcdGetBool
> > > (PcdHttpCacheDisabled);
> > > > +  InitializeListHead (&mRedfishHttpCachePrivate->CacheList.Head);
> > > > +
> > > > +  //
> > > > +  // Get retry settings
> > > > +  //
> > > > +  mRedfishHttpCachePrivate->RetrySetting.MaximumRetryGet    =
> PcdGet16
> > > (PcdHttpGetRetry);
> > > > +  mRedfishHttpCachePrivate->RetrySetting.MaximumRetryPut    =
> PcdGet16
> > > (PcdHttpPutRetry);
> > > > +  mRedfishHttpCachePrivate->RetrySetting.MaximumRetryPatch  =
> PcdGet16
> > > (PcdHttpPatchRetry);
> > > > +  mRedfishHttpCachePrivate->RetrySetting.MaximumRetryPost   =
> PcdGet16
> > > (PcdHttpPostRetry);
> > > > +  mRedfishHttpCachePrivate->RetrySetting.MaximumRetryDelete =
> PcdGet16
> > > (PcdHttpDeleteRetry);
> > > > +  mRedfishHttpCachePrivate->RetrySetting.RetryWait          = PcdGet16
> > > (PcdHttpRetryWaitInSecond) * 1000000U;
> > > > +
> > > > +  //
> > > > +  // Install the gEdkIIRedfishHttpProtocolGuid onto Handle.
> > > > +  //
> > > > +  Status = gBS->InstallMultipleProtocolInterfaces (
> > > > +                  &mRedfishHttpCachePrivate->ImageHandle,
> > > > +                  &gEdkIIRedfishHttpProtocolGuid,
> > > > +                  &mRedfishHttpCachePrivate->Protocol,
> > > > +                  NULL
> > > > +                  );
> > > > +  if (EFI_ERROR (Status)) {
> > > > +    DEBUG ((DEBUG_ERROR, "%a: cannot install Redfish http protocol:
> %r\n",
> > > __func__, Status));
> > > > +    RedfishHttpDriverUnload (ImageHandle);
> > > > +    return Status;
> > > > +  }
> > > > +
> > > > +  //
> > > > +  // Install protocol notification if credential protocol is installed.
> > > > +  //
> > > > +  mRedfishHttpCachePrivate->NotifyEvent = EfiCreateProtocolNotifyEvent (
> > > > +                                            &gEdkIIRedfishCredentialProtocolGuid,
> > > > +                                            TPL_CALLBACK,
> > > > +                                            CredentialProtocolInstalled,
> > > > +                                            mRedfishHttpCachePrivate,
> > > > +                                            &Registration
> > > > +                                            );
> > > > +  if (mRedfishHttpCachePrivate->NotifyEvent == NULL) {
> > > > +    DEBUG ((DEBUG_ERROR, "%a: failed to create protocol notification for
> > > gEdkIIRedfishCredentialProtocolGuid\n", __func__));
> > > > +    ASSERT (FALSE);
> > > > +    RedfishHttpDriverUnload (ImageHandle);
> > > > +    return Status;
> > > > +  }
> > > > +
> > > > +  return EFI_SUCCESS;
> > > > +}
> > > > diff --git a/RedfishPkg/RedfishHttpDxe/RedfishHttpOperation.c
> > > b/RedfishPkg/RedfishHttpDxe/RedfishHttpOperation.c
> > > > new file mode 100644
> > > > index 0000000000..5652818d16
> > > > --- /dev/null
> > > > +++ b/RedfishPkg/RedfishHttpDxe/RedfishHttpOperation.c
> > > > @@ -0,0 +1,693 @@
> > > > +/** @file
> > > > +  RedfishHttpOperation handles HTTP operations.
> > > > +
> > > > +  Copyright (c) 2024, NVIDIA CORPORATION & AFFILIATES. All rights
> reserved.
> > > > +
> > > > +  SPDX-License-Identifier: BSD-2-Clause-Patent
> > > > +
> > > > +**/
> > > > +
> > > > +#include "RedfishHttpOperation.h"
> > > > +#include "RedfishHttpData.h"
> > > > +
> > > > +/**
> > > > +  This function copies all headers in SrcHeaders to DstHeaders.
> > > > +  It's call responsibility to release returned DstHeaders.
> > > > +
> > > > +  @param[in]  SrcHeaders      Source headers.
> > > > +  @param[in]  SrcHeaderCount  Number of header in source headers.
> > > > +  @param[out] DstHeaders      Destination headers.
> > > > +  @param[out] DstHeaderCount  Number of header in designation
> headers.
> > > > +
> > > > +  @retval     EFI_SUCCESS     Headers are copied successfully.
> > > > +  @retval     Others          Errors occur.
> > > > +
> > > > +**/
> > > > +EFI_STATUS
> > > > +CopyHttpHeaders (
> > > > +  IN  EFI_HTTP_HEADER  *SrcHeaders,
> > > > +  IN  UINTN            SrcHeaderCount,
> > > > +  OUT EFI_HTTP_HEADER  **DstHeaders,
> > > > +  OUT UINTN            *DstHeaderCount
> > > > +  )
> > > > +{
> > > > +  UINTN  Index;
> > > > +
> > > > +  if ((SrcHeaders == NULL) || (SrcHeaderCount == 0) || (DstHeaders ==
> NULL)
> > > || (DstHeaderCount == NULL)) {
> > > > +    return EFI_INVALID_PARAMETER;
> > > > +  }
> > > > +
> > > > +  *DstHeaderCount = 0;
> > > > +  *DstHeaders     = AllocateZeroPool (sizeof (EFI_HTTP_HEADER) *
> > > SrcHeaderCount);
> > > > +  if (*DstHeaders == NULL) {
> > > > +    return EFI_OUT_OF_RESOURCES;
> > > > +  }
> > > > +
> > > > +  for (Index = 0; Index < SrcHeaderCount; Index++) {
> > > > +    (*DstHeaders)[Index].FieldName = AllocateCopyPool (AsciiStrSize
> > > (SrcHeaders[Index].FieldName), SrcHeaders[Index].FieldName);
> > > > +    if ((*DstHeaders)[Index].FieldName == NULL) {
> > > > +      return EFI_OUT_OF_RESOURCES;
> > > > +    }
> > > > +
> > > > +    (*DstHeaders)[Index].FieldValue = AllocateCopyPool (AsciiStrSize
> > > (SrcHeaders[Index].FieldValue), SrcHeaders[Index].FieldValue);
> > > > +    if ((*DstHeaders)[Index].FieldValue == NULL) {
> > > > +      return EFI_OUT_OF_RESOURCES;
> > >
> > >
> > >
> > > Looks like orevious allocations leaked.
> > > Didn't you think to implement smth like this
> > >
> https://github.co/
> %2F&data=05%7C02%7Cnicklew%40nvidia.com%7Cb82203c2d6124060850308d
> c34894020%7C43083d15727340c1b7db39efd9ccc17a%7C0%7C0%7C638443011
> 350956245%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLjAwMDAiLCJQIjoiV2
> luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C0%7C%7C%7C&sdata=j7ozA8KXgZ
> LpU1HoE0xsWua7Nzzx66BqdA0QGar1xqA%3D&reserved=0
> > >
> m%2Ftianocore%2Fedk2%2Fblob%2Fmaster%2FOvmfPkg%2FXenBusDxe%2FHelp
> > >
> ers.c%23L4&data=05%7C02%7Cnicklew%40nvidia.com%7Cf659c54c3edb43527c
> > >
> 3608dc3462ab2a%7C43083d15727340c1b7db39efd9ccc17a%7C0%7C0%7C6384
> > >
> 42845601059719%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLjAwMDAiLCJ
> > >
> QIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C0%7C%7C%7C&sdata=oYv
> > > XkfjOpakMOXV1w6nYVphDRuPM7R73lqr8QVqh%2BI4%3D&reserved=0 ?
> > >
> > >
> > > > +    }
> > > > +
> > > > +    *DstHeaderCount += 1;
> > > > +  }
> > > > +
> > > > +  return EFI_SUCCESS;
> > > > +}
> > > > +
> > > > +/**
> > > > +  This function free resources in Request. Request is no longer available
> > > > +  after this function returns successfully.
> > > > +
> > > > +  @param[in]  Request      HTTP request to be released.
> > > > +
> > > > +  @retval     EFI_SUCCESS     Resrouce is released successfully.
> > > > +  @retval     Others          Errors occur.
> > > > +
> > > > +**/
> > > > +EFI_STATUS
> > > > +ReleaseRedfishRequest (
> > > > +  IN  REDFISH_REQUEST  *Request
> > > > +  )
> > > > +{
> > > > +  if (Request == NULL) {
> > > > +    return EFI_INVALID_PARAMETER;
> > > > +  }
> > > > +
> > > > +  if ((Request->Headers != NULL) && (Request->HeaderCount > 0)) {
> > > > +    HttpFreeHeaderFields (Request->Headers, Request->HeaderCount);
> > > > +    Request->Headers     = NULL;
> > > > +    Request->HeaderCount = 0;
> > > > +  }
> > > > +
> > > > +  if (Request->Content != NULL) {
> > > > +    FreePool (Request->Content);
> > > > +    Request->Content = NULL;
> > > > +  }
> > > > +
> > > > +  if (Request->ContentType != NULL) {
> > > > +    FreePool (Request->ContentType);
> > > > +    Request->ContentType = NULL;
> > > > +  }
> > > > +
> > > > +  Request->ContentLength = 0;
> > > > +
> > > > +  return EFI_SUCCESS;
> > > > +}
> > > > +
> > > > +/**
> > > > +  This function free resources in given Response.
> > > > +
> > > > +  @param[in]  Response     HTTP response to be released.
> > > > +
> > > > +  @retval     EFI_SUCCESS     Resrouce is released successfully.
> > > > +  @retval     Others          Errors occur.
> > > > +
> > > > +**/
> > > > +EFI_STATUS
> > > > +ReleaseRedfishResponse (
> > > > +  IN  REDFISH_RESPONSE  *Response
> > > > +  )
> > > > +{
> > > > +  if (Response == NULL) {
> > > > +    return EFI_INVALID_PARAMETER;
> > > > +  }
> > > > +
> > > > +  if ((Response->Headers != NULL) && (Response->HeaderCount > 0)) {
> > > > +    HttpFreeHeaderFields (Response->Headers, Response->HeaderCount);
> > > > +    Response->Headers     = NULL;
> > > > +    Response->HeaderCount = 0;
> > > > +  }
> > > > +
> > > > +  if (Response->Payload != NULL) {
> > > > +    ReleaseRedfishPayload (Response->Payload);
> > > > +    Response->Payload = NULL;
> > > > +  }
> > > > +
> > > > +  if (Response->StatusCode != NULL) {
> > > > +    FreePool (Response->StatusCode);
> > > > +    Response->StatusCode = NULL;
> > > > +  }
> > > > +
> > > > +  return EFI_SUCCESS;
> > > > +}
> > > > +
> > > > +/**
> > > > +  This function free resources in given HTTP message.
> > > > +
> > > > +  @param[in]  HttpMessage     HTTP message to be released.
> > > > +  @param[in]  IsRequest       TRUE if this is request type of HTTP message.
> > > > +                              FALSE if this is response type of HTTP message.
> > > > +
> > > > +  @retval     EFI_SUCCESS     Resrouce is released successfully.
> > > > +  @retval     Others          Errors occur.
> > > > +
> > > > +**/
> > > > +EFI_STATUS
> > > > +ReleaseHttpMessage (
> > > > +  IN  EFI_HTTP_MESSAGE  *HttpMessage,
> > > > +  IN  BOOLEAN           IsRequest
> > > > +  )
> > > > +{
> > > > +  if (HttpMessage == NULL) {
> > > > +    return EFI_INVALID_PARAMETER;
> > > > +  }
> > > > +
> > > > +  if (IsRequest) {
> > > > +    if (HttpMessage->Data.Request != NULL) {
> > > > +      if (HttpMessage->Data.Request->Url != NULL) {
> > > > +        FreePool (HttpMessage->Data.Request->Url);
> > > > +      }
> > > > +
> > > > +      FreePool (HttpMessage->Data.Request);
> > > > +      HttpMessage->Data.Request = NULL;
> > > > +    }
> > > > +  } else {
> > > > +    if (HttpMessage->Data.Response != NULL) {
> > > > +      FreePool (HttpMessage->Data.Response);
> > > > +      HttpMessage->Data.Response = NULL;
> > > > +    }
> > > > +  }
> > > > +
> > > > +  if (HttpMessage->Body != NULL) {
> > > > +    FreePool (HttpMessage->Body);
> > > > +    HttpMessage->Body = NULL;
> > > > +  }
> > > > +
> > > > +  if (HttpMessage->Headers != NULL) {
> > > > +    HttpFreeHeaderFields (HttpMessage->Headers, HttpMessage-
> > > >HeaderCount);
> > > > +    HttpMessage->Headers     = NULL;
> > > > +    HttpMessage->HeaderCount = 0;
> > > > +  }
> > > > +
> > > > +  return EFI_SUCCESS;
> > > > +}
> > > > +
> > > > +/**
> > > > +  This function build Redfish message for sending data to Redfish service.
> > > > +  It's call responsibility to properly release returned HTTP message by
> > > > +  calling ReleaseHttpMessage.
> > > > +
> > > > +  @param[in]   ServicePrivate    Pointer to Redfish service private data.
> > > > +  @param[in]   Uri               Redfish service URI.
> > > > +  @param[in]   Method            HTTP method.
> > > > +  @param[in]   Request           Additional data to send to Redfish service.
> > > > +                                 This is optional.
> > > > +  @param[in]   ContentEncoding   Content encoding method to compress
> HTTP
> > > context.
> > > > +                                 This is optional. When ContentEncoding is NULL,
> > > > +                                 No compress method will be performed.
> > > > +
> > > > +  @retval     EFI_HTTP_MESSAGE *   Pointer to newly created HTTP
> message.
> > > > +  @retval     NULL                 Error occurred.
> > > > +
> > > > +**/
> > > > +EFI_HTTP_MESSAGE *
> > > > +BuildRequestMessage (
> > > > +  IN REDFISH_SERVICE_PRIVATE  *ServicePrivate,
> > > > +  IN EFI_STRING               Uri,
> > > > +  IN EFI_HTTP_METHOD          Method,
> > > > +  IN REDFISH_REQUEST          *Request OPTIONAL,
> > > > +  IN CHAR8                    *ContentEncoding OPTIONAL
> > > > +  )
> > > > +{
> > > > +  EFI_STATUS             Status;
> > > > +  EFI_STRING             Url;
> > > > +  UINTN                  UrlSize;
> > > > +  UINTN                  Index;
> > > > +  EFI_HTTP_MESSAGE       *RequestMsg;
> > > > +  EFI_HTTP_REQUEST_DATA  *RequestData;
> > > > +  UINTN                  HeaderCount;
> > > > +  UINTN                  HeaderIndex;
> > > > +  EFI_HTTP_HEADER        *Headers;
> > > > +  CHAR8                  ContentLengthStr[REDFISH_CONTENT_LENGTH_SIZE];
> > > > +  VOID                   *Content;
> > > > +  UINTN                  ContentLength;
> > > > +  BOOLEAN                HasContent;
> > > > +  BOOLEAN                DoContentEncoding;
> > > > +
> > > > +  RequestMsg        = NULL;
> > > > +  RequestData       = NULL;
> > > > +  Url               = NULL;
> > > > +  UrlSize           = 0;
> > > > +  Content           = NULL;
> > > > +  ContentLength     = 0;
> > > > +  HeaderCount       = REDFISH_COMMON_HEADER_SIZE;
> > > > +  HeaderIndex       = 0;
> > > > +  Headers           = NULL;
> > > > +  HasContent        = FALSE;
> > > > +  DoContentEncoding = FALSE;
> > > > +
> > > > +  if ((ServicePrivate == NULL) || (IS_EMPTY_STRING (Uri))) {
> > > > +    return NULL;
> > > > +  }
> > > > +
> > > > +  if (Method >= HttpMethodMax) {
> > > > +    return NULL;
> > > > +  }
> > > > +
> > > > +  DEBUG ((REDFISH_HTTP_CACHE_DEBUG_REQUEST, "%a: %s\n",
> __func__,
> > > Uri));
> > > > +
> > > > +  //
> > > > +  // Build full URL for HTTP query.
> > > > +  //
> > > > +  UrlSize = (AsciiStrLen (ServicePrivate->Host) + StrLen (Uri) + 1) * sizeof
> > > (CHAR16);
> > > > +  Url     = AllocateZeroPool (UrlSize);
> > > > +  if (Url == NULL) {
> > > > +    return NULL;
> > > > +  }
> > > > +
> > > > +  UnicodeSPrint (Url, UrlSize, L"%a%s", ServicePrivate->Host, Uri);
> > > > +  DEBUG ((REDFISH_HTTP_CACHE_DEBUG_REQUEST, "%a: Url: %s\n",
> > > __func__, Url));
> > > > +
> > > > +  //
> > > > +  // Step 1: build the HTTP headers.
> > > > +  //
> > > > +  if (!IS_EMPTY_STRING (ServicePrivate->SessionToken)
> || !IS_EMPTY_STRING
> > > (ServicePrivate->BasicAuth)) {
> > > > +    HeaderCount++;
> > > > +  }
> > > > +
> > > > +  if ((Request != NULL) && (Request->HeaderCount > 0)) {
> > > > +    HeaderCount += Request->HeaderCount;
> > > > +  }
> > > > +
> > > > +  //
> > > > +  // Check and see if we will do content encoding or not
> > > > +  //
> > > > +  if (!IS_EMPTY_STRING (ContentEncoding)) {
> > > > +    if (AsciiStrCmp (ContentEncoding,
> > > REDFISH_HTTP_CONTENT_ENCODING_NONE) != 0) {
> > > > +      DoContentEncoding = TRUE;
> > > > +    }
> > > > +  }
> > > > +
> > > > +  if ((Request != NULL) && !IS_EMPTY_STRING (Request->Content)) {
> > > > +    HeaderCount += 2;
> > > > +    HasContent   = TRUE;
> > > > +    if (DoContentEncoding) {
> > > > +      HeaderCount += 1;
> > > > +    }
> > > > +  }
> > > > +
> > > > +  Headers = AllocateZeroPool (HeaderCount * sizeof (EFI_HTTP_HEADER));
> > > > +  if (Headers == NULL) {
> > > > +    goto ON_ERROR;
> > > > +  }
> > > > +
> > > > +  if (!IS_EMPTY_STRING (ServicePrivate->SessionToken)) {
> > > > +    Status = HttpSetFieldNameAndValue (&Headers[HeaderIndex++],
> > > HTTP_HEADER_X_AUTH_TOKEN, ServicePrivate->SessionToken);
> > > > +    if (EFI_ERROR (Status)) {
> > > > +      goto ON_ERROR;
> > > > +    }
> > > > +  } else if (!IS_EMPTY_STRING (ServicePrivate->BasicAuth)) {
> > > > +    Status = HttpSetFieldNameAndValue (&Headers[HeaderIndex++],
> > > HTTP_HEADER_AUTHORIZATION, ServicePrivate->BasicAuth);
> > > > +    if (EFI_ERROR (Status)) {
> > > > +      goto ON_ERROR;
> > > > +    }
> > > > +  }
> > > > +
> > > > +  if (Request != NULL) {
> > > > +    for (Index = 0; Index < Request->HeaderCount; Index++) {
> > > > +      Status = HttpSetFieldNameAndValue (&Headers[HeaderIndex++],
> Request-
> > > >Headers[Index].FieldName, Request->Headers[Index].FieldValue);
> > > > +      if (EFI_ERROR (Status)) {
> > > > +        goto ON_ERROR;
> > > > +      }
> > > > +    }
> > > > +  }
> > > > +
> > > > +  Status = HttpSetFieldNameAndValue (&Headers[HeaderIndex++],
> > > HTTP_HEADER_HOST, ServicePrivate->HostName);
> > > > +  if (EFI_ERROR (Status)) {
> > > > +    goto ON_ERROR;
> > > > +  }
> > > > +
> > > > +  Status = HttpSetFieldNameAndValue (&Headers[HeaderIndex++],
> > > REDFISH_HTTP_HEADER_ODATA_VERSION_STR,
> > > REDFISH_HTTP_HEADER_ODATA_VERSION_VALUE);
> > > > +  if (EFI_ERROR (Status)) {
> > > > +    goto ON_ERROR;
> > > > +  }
> > > > +
> > > > +  Status = HttpSetFieldNameAndValue (&Headers[HeaderIndex++],
> > > HTTP_HEADER_ACCEPT, HTTP_CONTENT_TYPE_APP_JSON);
> > > > +  if (EFI_ERROR (Status)) {
> > > > +    goto ON_ERROR;
> > > > +  }
> > > > +
> > > > +  Status = HttpSetFieldNameAndValue (&Headers[HeaderIndex++],
> > > HTTP_HEADER_USER_AGENT,
> REDFISH_HTTP_HEADER_USER_AGENT_VALUE);
> > > > +  if (EFI_ERROR (Status)) {
> > > > +    goto ON_ERROR;
> > > > +  }
> > > > +
> > > > +  Status = HttpSetFieldNameAndValue (&Headers[HeaderIndex++],
> > > REDFISH_HTTP_HEADER_CONNECTION_STR,
> > > REDFISH_HTTP_HEADER_CONNECTION_VALUE);
> > > > +  if (EFI_ERROR (Status)) {
> > > > +    goto ON_ERROR;
> > > > +  }
> > > > +
> > > > +  //
> > > > +  // Handle content header
> > > > +  //
> > > > +  if (HasContent) {
> > > > +    if (Request->ContentType == NULL) {
> > > > +      Status = HttpSetFieldNameAndValue (&Headers[HeaderIndex++],
> > > HTTP_HEADER_CONTENT_TYPE, HTTP_CONTENT_TYPE_APP_JSON);
> > > > +      if (EFI_ERROR (Status)) {
> > > > +        goto ON_ERROR;
> > > > +      }
> > > > +    } else {
> > > > +      Status = HttpSetFieldNameAndValue (&Headers[HeaderIndex++],
> > > HTTP_HEADER_CONTENT_TYPE, Request->ContentType);
> > > > +      if (EFI_ERROR (Status)) {
> > > > +        goto ON_ERROR;
> > > > +      }
> > > > +    }
> > > > +
> > > > +    if (Request->ContentLength == 0) {
> > > > +      Request->ContentLength =  AsciiStrLen (Request->Content);
> > > > +    }
> > > > +
> > > > +    AsciiSPrint (
> > > > +      ContentLengthStr,
> > > > +      sizeof (ContentLengthStr),
> > > > +      "%lu",
> > > > +      (UINT64)Request->ContentLength
> > > > +      );
> > > > +    Status = HttpSetFieldNameAndValue (&Headers[HeaderIndex++],
> > > HTTP_HEADER_CONTENT_LENGTH, ContentLengthStr);
> > > > +    if (EFI_ERROR (Status)) {
> > > > +      goto ON_ERROR;
> > > > +    }
> > > > +
> > > > +    //
> > > > +    // Encoding
> > > > +    //
> > > > +    if (DoContentEncoding) {
> > > > +      //
> > > > +      // We currently only support gzip Content-Encoding.
> > > > +      //
> > > > +      Status =  RedfishContentEncode (
> > > > +                  ContentEncoding,
> > > > +                  Request->Content,
> > > > +                  Request->ContentLength,
> > > > +                  &Content,
> > > > +                  &ContentLength
> > > > +                  );
> > > > +      if (Status == EFI_INVALID_PARAMETER) {
> > > > +        DEBUG ((DEBUG_ERROR, "%a: Error to encode content.\n",
> __func__));
> > > > +        goto ON_ERROR;
> > > > +      } else if (Status == EFI_UNSUPPORTED) {
> > > > +        DoContentEncoding = FALSE;
> > > > +        DEBUG ((REDFISH_HTTP_CACHE_DEBUG_REQUEST, "%a: No content
> > > coding for %a! Use raw data instead.\n", __func__, ContentEncoding));
> > > > +        Status = HttpSetFieldNameAndValue (&Headers[HeaderIndex++],
> > > HTTP_HEADER_CONTENT_ENCODING,
> HTTP_CONTENT_ENCODING_IDENTITY);
> > > > +        if (EFI_ERROR (Status)) {
> > > > +          goto ON_ERROR;
> > > > +        }
> > > > +      } else {
> > > > +        Status = HttpSetFieldNameAndValue (&Headers[HeaderIndex++],
> > > HTTP_HEADER_CONTENT_ENCODING, HTTP_CONTENT_ENCODING_GZIP);
> > > > +        if (EFI_ERROR (Status)) {
> > > > +          goto ON_ERROR;
> > > > +        }
> > > > +      }
> > > > +    }
> > > > +
> > > > +    //
> > > > +    // When the content is from caller, we use our own copy so that we
> properly
> > > release it later.
> > > > +    //
> > > > +    if (!DoContentEncoding) {
> > > > +      Content = AllocateCopyPool (Request->ContentLength, Request-
> >Content);
> > > > +      if (Content == NULL) {
> > > > +        goto ON_ERROR;
> > > > +      }
> > > > +
> > > > +      ContentLength = Request->ContentLength;
> > > > +    }
> > > > +  }
> > > > +
> > > > +  //
> > > > +  // Step 2: build the rest of HTTP request info.
> > > > +  //
> > > > +  RequestData = AllocateZeroPool (sizeof (EFI_HTTP_REQUEST_DATA));
> > > > +  if (RequestData == NULL) {
> > > > +    goto ON_ERROR;
> > > > +  }
> > > > +
> > > > +  RequestData->Method = Method;
> > > > +  RequestData->Url    = Url;
> > > > +
> > > > +  //
> > > > +  // Step 3: fill in EFI_HTTP_MESSAGE
> > > > +  //
> > > > +  RequestMsg = AllocateZeroPool (sizeof (EFI_HTTP_MESSAGE));
> > > > +  if (RequestMsg == NULL) {
> > > > +    goto ON_ERROR;
> > > > +  }
> > > > +
> > > > +  ASSERT (HeaderIndex == HeaderCount);
> > > > +  RequestMsg->Data.Request = RequestData;
> > > > +  RequestMsg->HeaderCount  = HeaderIndex;
> > > > +  RequestMsg->Headers      = Headers;
> > > > +
> > > > +  if (HasContent) {
> > > > +    RequestMsg->BodyLength = ContentLength;
> > > > +    RequestMsg->Body       = Content;
> > > > +  }
> > > > +
> > > > +  return RequestMsg;
> > > > +
> > > > +ON_ERROR:
> > > > +
> > > > +  if (Headers != NULL) {
> > > > +    HttpFreeHeaderFields (Headers, HeaderIndex);
> > > > +  }
> > > > +
> > > > +  if (RequestData != NULL) {
> > > > +    FreePool (RequestData);
> > > > +  }
> > > > +
> > > > +  if (RequestMsg != NULL) {
> > > > +    FreePool (RequestMsg);
> > > > +  }
> > > > +
> > > > +  if (Url != NULL) {
> > > > +    FreePool (Url);
> > > > +  }
> > > > +
> > > > +  return NULL;
> > > > +}
> > > > +
> > > > +/**
> > > > +  This function parse response message from Redfish service, and
> > > > +  build Redfish response for caller. It's call responsibility to
> > > > +  properly release Redfish response by calling ReleaseRedfishResponse.
> > > > +
> > > > +  @param[in]   ServicePrivate   Pointer to Redfish service private data.
> > > > +  @param[in]   ResponseMsg      Response message from Redfish service.
> > > > +  @param[out]  RedfishResponse  Redfish response data.
> > > > +
> > > > +  @retval     EFI_SUCCESS     Redfish response is returned successfully.
> > > > +  @retval     Others          Errors occur.
> > > > +
> > > > +**/
> > > > +EFI_STATUS
> > > > +ParseResponseMessage (
> > > > +  IN  REDFISH_SERVICE_PRIVATE  *ServicePrivate,
> > > > +  IN  EFI_HTTP_MESSAGE         *ResponseMsg,
> > > > +  OUT REDFISH_RESPONSE         *RedfishResponse
> > > > +  )
> > > > +{
> > > > +  EFI_STATUS        Status;
> > > > +  EDKII_JSON_VALUE  JsonData;
> > > > +  EFI_HTTP_HEADER   *ContentEncodedHeader;
> > > > +  VOID              *DecodedBody;
> > > > +  UINTN             DecodedLength;
> > > > +
> > > > +  if ((ServicePrivate == NULL) || (ResponseMsg == NULL) ||
> (RedfishResponse
> > > == NULL)) {
> > > > +    return EFI_INVALID_PARAMETER;
> > > > +  }
> > > > +
> > > > +  DEBUG ((REDFISH_HTTP_CACHE_DEBUG_REQUEST, "%a\n", __func__));
> > > > +
> > > > +  //
> > > > +  // Initialization
> > > > +  //
> > > > +  JsonData                     = NULL;
> > > > +  RedfishResponse->HeaderCount = 0;
> > > > +  RedfishResponse->Headers     = NULL;
> > > > +  RedfishResponse->Payload     = NULL;
> > > > +  RedfishResponse->StatusCode  = NULL;
> > > > +  DecodedBody                  = NULL;
> > > > +  DecodedLength                = 0;
> > > > +
> > > > +  //
> > > > +  // Return the HTTP StatusCode.
> > > > +  //
> > > > +  if (ResponseMsg->Data.Response != NULL) {
> > > > +    DEBUG ((REDFISH_HTTP_CACHE_DEBUG_REQUEST, "%a: status: %d\n",
> > > __func__, ResponseMsg->Data.Response->StatusCode));
> > > > +    RedfishResponse->StatusCode = AllocateCopyPool (sizeof
> > > (EFI_HTTP_STATUS_CODE), &ResponseMsg->Data.Response->StatusCode);
> > > > +    if (RedfishResponse->StatusCode == NULL) {
> > > > +      DEBUG ((DEBUG_ERROR, "%a: Failed to create status code.\n",
> __func__));
> > > > +    }
> > > > +  }
> > > > +
> > > > +  //
> > > > +  // Return the HTTP headers.
> > > > +  //
> > > > +  if (ResponseMsg->Headers != NULL) {
> > > > +    DEBUG ((REDFISH_HTTP_CACHE_DEBUG_REQUEST, "%a: header count:
> > > %d\n", __func__, ResponseMsg->HeaderCount));
> > > > +    Status = CopyHttpHeaders (
> > > > +               ResponseMsg->Headers,
> > > > +               ResponseMsg->HeaderCount,
> > > > +               &RedfishResponse->Headers,
> > > > +               &RedfishResponse->HeaderCount
> > > > +               );
> > > > +    if (EFI_ERROR (Status)) {
> > > > +      DEBUG ((DEBUG_ERROR, "%a: Failed to copy HTTP headers: %r\n",
> > > __func__, Status));
> > > > +    }
> > > > +  }
> > > > +
> > > > +  //
> > > > +  // Return the HTTP body.
> > > > +  //
> > > > +  if ((ResponseMsg->BodyLength != 0) && (ResponseMsg->Body != NULL)) {
> > > > +    DEBUG ((REDFISH_HTTP_CACHE_DEBUG_REQUEST, "%a: body length:
> > > %d\n", __func__, ResponseMsg->BodyLength));
> > > > +    //
> > > > +    // Check if data is encoded.
> > > > +    //
> > > > +    ContentEncodedHeader = HttpFindHeader (RedfishResponse-
> >HeaderCount,
> > > RedfishResponse->Headers, HTTP_HEADER_CONTENT_ENCODING);
> > > > +    if (ContentEncodedHeader != NULL) {
> > > > +      //
> > > > +      // The content is encoded.
> > > > +      //
> > > > +      Status = RedfishContentDecode (
> > > > +                 ContentEncodedHeader->FieldValue,
> > > > +                 ResponseMsg->Body,
> > > > +                 ResponseMsg->BodyLength,
> > > > +                 &DecodedBody,
> > > > +                 &DecodedLength
> > > > +                 );
> > > > +      if (EFI_ERROR (Status)) {
> > > > +        DEBUG ((DEBUG_ERROR, "%a: Failed to decompress the response
> > > content: %r decoding method: %a\n.", __func__, Status,
> ContentEncodedHeader-
> > > >FieldValue));
> > > > +        goto ON_ERROR;
> > > > +      }
> > > > +
> > > > +      JsonData = JsonLoadBuffer (DecodedBody, DecodedLength, 0, NULL);
> > > > +      FreePool (DecodedBody);
> > > > +    } else {
> > > > +      JsonData = JsonLoadBuffer (ResponseMsg->Body, ResponseMsg-
> > > >BodyLength, 0, NULL);
> > > > +    }
> > > > +
> > > > +    if (!JsonValueIsNull (JsonData)) {
> > > > +      RedfishResponse->Payload = CreateRedfishPayload (ServicePrivate,
> > > JsonData);
> > > > +      if (RedfishResponse->Payload == NULL) {
> > > > +        DEBUG ((DEBUG_ERROR, "%a: Failed to create payload\n.",
> __func__));
> > > > +      }
> > > > +
> > > > +      JsonValueFree (JsonData);
> > > > +    } else {
> > > > +      DEBUG ((DEBUG_ERROR, "%a: No payload available\n", __func__));
> > > > +    }
> > > > +  }
> > > > +
> > > > +  return EFI_SUCCESS;
> > > > +
> > > > +ON_ERROR:
> > > > +
> > > > +  if (RedfishResponse != NULL) {
> > > > +    ReleaseRedfishResponse (RedfishResponse);
> > > > +  }
> > > > +
> > > > +  return Status;
> > > > +}
> > > > +
> > > > +/**
> > > > +  This function send Redfish request to Redfish service by calling
> > > > +  Rest Ex protocol.
> > > > +
> > > > +  @param[in]   Service       Pointer to Redfish service.
> > > > +  @param[in]   Uri           Uri of Redfish service.
> > > > +  @param[in]   Method        HTTP method.
> > > > +  @param[in]   Request     Request data. This is optional.
> > > > +  @param[out]  Response    Redfish response data.
> > > > +
> > > > +  @retval     EFI_SUCCESS     Request is sent and received successfully.
> > > > +  @retval     Others          Errors occur.
> > > > +
> > > > +**/
> > > > +EFI_STATUS
> > > > +HttpSendReceive (
> > > > +  IN  REDFISH_SERVICE   Service,
> > > > +  IN  EFI_STRING        Uri,
> > > > +  IN  EFI_HTTP_METHOD   Method,
> > > > +  IN  REDFISH_REQUEST   *Request  OPTIONAL,
> > > > +  OUT REDFISH_RESPONSE  *Response
> > > > +  )
> > > > +{
> > > > +  EFI_STATUS               Status;
> > > > +  EFI_STATUS               RestExStatus;
> > > > +  EFI_HTTP_MESSAGE         *RequestMsg;
> > > > +  EFI_HTTP_MESSAGE         ResponseMsg;
> > > > +  REDFISH_SERVICE_PRIVATE  *ServicePrivate;
> > > > +  EFI_HTTP_HEADER          *XAuthTokenHeader;
> > > > +  CHAR8                    *HttpContentEncoding;
> > > > +
> > > > +  if ((Service == NULL) || IS_EMPTY_STRING (Uri) || (Response == NULL)) {
> > > > +    return EFI_INVALID_PARAMETER;
> > > > +  }
> > > > +
> > > > +  DEBUG ((REDFISH_HTTP_CACHE_DEBUG_REQUEST, "%a: Method: 0x%x
> > > %s\n", __func__, Method, Uri));
> > > > +
> > > > +  ServicePrivate = (REDFISH_SERVICE_PRIVATE *)Service;
> > > > +  if (ServicePrivate->Signature != REDFISH_HTTP_SERVICE_SIGNATURE) {
> > > > +    DEBUG ((DEBUG_ERROR, "%a: signature check failure\n", __func__));
> > > > +    return EFI_INVALID_PARAMETER;
> > > > +  }
> > > > +
> > > > +  ZeroMem (&ResponseMsg, sizeof (ResponseMsg));
> > > > +  HttpContentEncoding = (CHAR8 *)PcdGetPtr
> > > (PcdRedfishServiceContentEncoding);
> > > > +
> > > > +  RequestMsg = BuildRequestMessage (Service, Uri, Method, Request,
> > > HttpContentEncoding);
> > > > +  if (RequestMsg == NULL) {
> > > > +    DEBUG ((DEBUG_ERROR, "%a: cannot build request message for %s\n",
> > > __func__, Uri));
> > > > +    return EFI_PROTOCOL_ERROR;
> > > > +  }
> > > > +
> > > > +  //
> > > > +  // call RESTEx to get response from REST service.
> > > > +  //
> > > > +  RestExStatus = ServicePrivate->RestEx->SendReceive (ServicePrivate-
> >RestEx,
> > > RequestMsg, &ResponseMsg);
> > > > +  if (EFI_ERROR (RestExStatus)) {
> > > > +    DEBUG ((DEBUG_ERROR, "%a: %s SendReceive failure: %r\n", __func__,
> > > Uri, RestExStatus));
> > > > +  }
> > > > +
> > > > +  //
> > > > +  // Return status code, headers and payload to caller as much as possible
> even
> > > when RestEx returns failure.
> > > > +  //
> > > > +  Status = ParseResponseMessage (ServicePrivate, &ResponseMsg,
> Response);
> > > > +  if (EFI_ERROR (Status)) {
> > > > +    DEBUG ((DEBUG_ERROR, "%a: %s parse response failure: %r\n",
> __func__,
> > > Uri, Status));
> > > > +  } else {
> > > > +    //
> > > > +    // Capture session token in header
> > > > +    //
> > > > +    if ((Method == HttpMethodPost) &&
> > > > +        (Response->StatusCode != NULL) &&
> > > > +        ((*Response->StatusCode == HTTP_STATUS_200_OK) || (*Response-
> > > >StatusCode == HTTP_STATUS_204_NO_CONTENT)))
> > > > +    {
> > > > +      XAuthTokenHeader = HttpFindHeader (ResponseMsg.HeaderCount,
> > > ResponseMsg.Headers, HTTP_HEADER_X_AUTH_TOKEN);
> > > > +      if (XAuthTokenHeader != NULL) {
> > > > +        Status = UpdateSessionToken (ServicePrivate, XAuthTokenHeader-
> > > >FieldValue);
> > > > +        if (EFI_ERROR (Status)) {
> > > > +          DEBUG ((DEBUG_ERROR, "%a: update session token failure: %r\n",
> > > __func__, Status));
> > > > +        }
> > > > +      }
> > > > +    }
> > > > +  }
> > > > +
> > > > +  //
> > > > +  // Release resources
> > > > +  //
> > > > +  if (RequestMsg != NULL) {
> > > > +    ReleaseHttpMessage (RequestMsg, TRUE);
> > > > +    FreePool (RequestMsg);
> > > > +  }
> > > > +
> > > > +  ReleaseHttpMessage (&ResponseMsg, FALSE);
> > > > +
> > > > +  return RestExStatus;
> > > > +}
> > > > diff --git a/RedfishPkg/Redfish.fdf.inc b/RedfishPkg/Redfish.fdf.inc
> > > > index 3e5a77766e..5cbe3592fd 100644
> > > > --- a/RedfishPkg/Redfish.fdf.inc
> > > > +++ b/RedfishPkg/Redfish.fdf.inc
> > > > @@ -6,7 +6,7 @@
> > > > # to be built in the firmware volume.
> > > > #
> > > > # (C) Copyright 2020-2021 Hewlett Packard Enterprise Development LP<BR>
> > > > -# Copyright (c) 2023, NVIDIA CORPORATION & AFFILIATES. All rights
> reserved.
> > > > +# Copyright (c) 2023-2024, NVIDIA CORPORATION & AFFILIATES. All rights
> > > reserved.
> > > > #
> > > > #    SPDX-License-Identifier: BSD-2-Clause-Patent
> > > > #
> > > > @@ -20,4 +20,5 @@
> > > >   INF RedfishPkg/RedfishConfigHandler/RedfishConfigHandlerDriver.inf
> > > >   INF RedfishPkg/RedfishPlatformConfigDxe/RedfishPlatformConfigDxe.inf
> > > >   INF
> > > MdeModulePkg/Universal/RegularExpressionDxe/RegularExpressionDxe.inf
> > > > +  INF RedfishPkg/RedfishHttpDxe/RedfishHttpDxe.inf
> > > > !endif
> > > > --
> > > > 2.34.1
> > > >
> > > >
> > > >
> > > > 
> > > >
> > >
> > > Regards,
> > > Mike.
> > > >


-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#115958): https://edk2.groups.io/g/devel/message/115958
Mute This Topic: https://groups.io/mt/104505404/7686176
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [rebecca@openfw.io]
-=-=-=-=-=-=-=-=-=-=-=-



^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [edk2-devel] [PATCH v2 2/6] RedfishPkg: implement Redfish HTTP protocol
  2024-02-26 13:43       ` Nickle Wang via groups.io
@ 2024-02-27  0:13         ` Mike Maslenkin
  2024-02-27  0:48           ` Nickle Wang via groups.io
       [not found]           ` <17B791D5F1D9AF42.14830@groups.io>
  0 siblings, 2 replies; 15+ messages in thread
From: Mike Maslenkin @ 2024-02-27  0:13 UTC (permalink / raw)
  To: Nickle Wang
  Cc: devel@edk2.groups.io, Igor Kulchytskyy, Abner Chang, Nick Ramirez

Hii Nickle,


On Mon, Feb 26, 2024 at 4:44 PM Nickle Wang <nicklew@nvidia.com> wrote:
>
> Hi Mike,
>
> > So finally we have
> > HttpFreeHeaderFields (Response->Headers, Response->HeaderCount);
> > but Response->HeaderCount does not count partially allocated elements. Right?
> >
> > To fix this, it is required to set
> > *DstHeaderCount = SrcHeaderCount unconditionally right after
> > DstHeaders  allocation, and HttpFreeHeaderFields() will do the work
> > then.
>
> I follow your suggestion to update DstHeaderCount right after DstHeaders is allocated.  So, HttpFreeHeaderFields can release headers correctly. I also create a macro to implemented AsciiStrCpy. Please check below link to see my changes:
> https://github.com/tianocore/edk2/compare/0f391b1c2f988d90a3ac723b314ac28ba7b0b8df..f0fa1b8fdcd933beb52fd3127c2476443c00ef8d

These changes looks good. Internal strings
initialization/deinitialization code much cleaner now and possible
leak seems to have been fixed.

Thank you!

Regards,
Mike.


-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#115981): https://edk2.groups.io/g/devel/message/115981
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]
-=-=-=-=-=-=-=-=-=-=-=-



^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [edk2-devel] [PATCH v2 2/6] RedfishPkg: implement Redfish HTTP protocol
  2024-02-27  0:13         ` Mike Maslenkin
@ 2024-02-27  0:48           ` Nickle Wang via groups.io
       [not found]           ` <17B791D5F1D9AF42.14830@groups.io>
  1 sibling, 0 replies; 15+ messages in thread
From: Nickle Wang via groups.io @ 2024-02-27  0:48 UTC (permalink / raw)
  To: Mike Maslenkin
  Cc: devel@edk2.groups.io, Igor Kulchytskyy, Abner Chang, Nick Ramirez

Thanks for your confirmation, Mike!

Version 3 patch set is here: https://edk2.groups.io/g/devel/message/115985

Regards,
Nickle

> -----Original Message-----
> From: Mike Maslenkin <mike.maslenkin@gmail.com>
> Sent: Tuesday, February 27, 2024 8:13 AM
> To: Nickle Wang <nicklew@nvidia.com>
> Cc: devel@edk2.groups.io; Igor Kulchytskyy <igork@ami.com>; Abner Chang
> <abner.chang@amd.com>; Nick Ramirez <nramirez@nvidia.com>
> Subject: Re: [edk2-devel] [PATCH v2 2/6] RedfishPkg: implement Redfish HTTP
> protocol
> 
> External email: Use caution opening links or attachments
> 
> 
> Hii Nickle,
> 
> 
> On Mon, Feb 26, 2024 at 4:44 PM Nickle Wang <nicklew@nvidia.com> wrote:
> >
> > Hi Mike,
> >
> > > So finally we have
> > > HttpFreeHeaderFields (Response->Headers, Response->HeaderCount); but
> > > Response->HeaderCount does not count partially allocated elements. Right?
> > >
> > > To fix this, it is required to set
> > > *DstHeaderCount = SrcHeaderCount unconditionally right after
> > > DstHeaders  allocation, and HttpFreeHeaderFields() will do the work
> > > then.
> >
> > I follow your suggestion to update DstHeaderCount right after DstHeaders is
> allocated.  So, HttpFreeHeaderFields can release headers correctly. I also create a
> macro to implemented AsciiStrCpy. Please check below link to see my changes:
> > https://nam11.safelinks.protection.outlook.com/?url=https%3A%2F%2Fgith
> >
> ub.com%2Ftianocore%2Fedk2%2Fcompare%2F0f391b1c2f988d90a3ac723b314a
> c28b
> >
> a7b0b8df..f0fa1b8fdcd933beb52fd3127c2476443c00ef8d&data=05%7C02%7Cnic
> k
> >
> lew%40nvidia.com%7Cf3870f71360e44f3b4e208dc3728ff87%7C43083d1572734
> 0c1
> >
> b7db39efd9ccc17a%7C0%7C0%7C638445896465360452%7CUnknown%7CTWFp
> bGZsb3d8
> >
> eyJWIjoiMC4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%
> 7C0
> >
> %7C%7C%7C&sdata=K%2FEA2QWpk%2F8NHQ1QhzqkvQqao4db%2BILn1Jt%2BB
> qQ5n1E%3D
> > &reserved=0
> 
> These changes looks good. Internal strings initialization/deinitialization code much
> cleaner now and possible leak seems to have been fixed.
> 
> Thank you!
> 
> Regards,
> Mike.


-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#115991): https://edk2.groups.io/g/devel/message/115991
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]
-=-=-=-=-=-=-=-=-=-=-=-



^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [edk2-devel] [PATCH v2 2/6] RedfishPkg: implement Redfish HTTP protocol
       [not found]           ` <17B791D5F1D9AF42.14830@groups.io>
@ 2024-02-28 11:47             ` Nickle Wang via groups.io
  2024-02-28 17:56               ` Mike Maslenkin
  0 siblings, 1 reply; 15+ messages in thread
From: Nickle Wang via groups.io @ 2024-02-28 11:47 UTC (permalink / raw)
  To: devel@edk2.groups.io, Nickle Wang, Mike Maslenkin
  Cc: Igor Kulchytskyy, Abner Chang, Nick Ramirez

[-- Attachment #1: Type: text/plain, Size: 3738 bytes --]

Hi @Mike Maslenkin<mailto:mike.maslenkin@gmail.com>,



May I have your reviewed-by if version 3 patch set look good to you?



Thanks,

Nickle



> -----Original Message-----

> From: devel@edk2.groups.io <devel@edk2.groups.io> On Behalf Of Nickle Wang

> via groups.io

> Sent: Tuesday, February 27, 2024 8:49 AM

> To: Mike Maslenkin <mike.maslenkin@gmail.com>

> Cc: devel@edk2.groups.io; Igor Kulchytskyy <igork@ami.com>; Abner Chang

> <abner.chang@amd.com>; Nick Ramirez <nramirez@nvidia.com>

> Subject: Re: [edk2-devel] [PATCH v2 2/6] RedfishPkg: implement Redfish HTTP

> protocol

>

> External email: Use caution opening links or attachments

>

>

> Thanks for your confirmation, Mike!

>

> Version 3 patch set is here: https://edk2.groups.io/g/devel/message/115985

>

> Regards,

> Nickle

>

> > -----Original Message-----

> > From: Mike Maslenkin <mike.maslenkin@gmail.com<mailto:mike.maslenkin@gmail.com>>

> > Sent: Tuesday, February 27, 2024 8:13 AM

> > To: Nickle Wang <nicklew@nvidia.com<mailto:nicklew@nvidia.com>>

> > Cc: devel@edk2.groups.io<mailto:devel@edk2.groups.io>; Igor Kulchytskyy <igork@ami.com<mailto:igork@ami.com>>; Abner

> > Chang <abner.chang@amd.com<mailto:abner.chang@amd.com>>; Nick Ramirez <nramirez@nvidia.com<mailto:nramirez@nvidia.com>>

> > Subject: Re: [edk2-devel] [PATCH v2 2/6] RedfishPkg: implement Redfish

> > HTTP protocol

> >

> > External email: Use caution opening links or attachments

> >

> >

> > Hii Nickle,

> >

> >

> > On Mon, Feb 26, 2024 at 4:44 PM Nickle Wang <nicklew@nvidia.com<mailto:nicklew@nvidia.com>> wrote:

> > >

> > > Hi Mike,

> > >

> > > > So finally we have

> > > > HttpFreeHeaderFields (Response->Headers, Response->HeaderCount);

> > > > but

> > > > Response->HeaderCount does not count partially allocated elements. Right?

> > > >

> > > > To fix this, it is required to set *DstHeaderCount =

> > > > SrcHeaderCount unconditionally right after DstHeaders  allocation,

> > > > and HttpFreeHeaderFields() will do the work then.

> > >

> > > I follow your suggestion to update DstHeaderCount right after

> > > DstHeaders is

> > allocated.  So, HttpFreeHeaderFields can release headers correctly. I

> > also create a macro to implemented AsciiStrCpy. Please check below link to see

> my changes:

> > > https://nam11.safelinks.protection.outlook.com/?url=https%3A%2F%2Fgi

> > > th

> > >

> >

> ub.com%2Ftianocore%2Fedk2%2Fcompare%2F0f391b1c2f988d90a3ac723b314a

> > c28b

> > >

> >

> a7b0b8df..f0fa1b8fdcd933beb52fd3127c2476443c00ef8d&data=05%7C02%7Cnic

> > k

> > >

> >

> lew%40nvidia.com%7Cf3870f71360e44f3b4e208dc3728ff87%7C43083d1572734

> > 0c1

> > >

> >

> b7db39efd9ccc17a%7C0%7C0%7C638445896465360452%7CUnknown%7CTWFp

> > bGZsb3d8

> > >

> >

> eyJWIjoiMC4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%

> > 7C0

> > >

> >

> %7C%7C%7C&sdata=K%2FEA2QWpk%2F8NHQ1QhzqkvQqao4db%2BILn1Jt%2BB

> > qQ5n1E%3D

> > > &reserved=0

> >

> > These changes looks good. Internal strings

> > initialization/deinitialization code much cleaner now and possible leak seems to

> have been fixed.

> >

> > Thank you!

> >

> > Regards,

> > Mike.

>

>

> 

>




-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#116114): https://edk2.groups.io/g/devel/message/116114
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]
-=-=-=-=-=-=-=-=-=-=-=-



[-- Attachment #2: Type: text/html, Size: 9988 bytes --]

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [edk2-devel] [PATCH v2 2/6] RedfishPkg: implement Redfish HTTP protocol
  2024-02-28 11:47             ` Nickle Wang via groups.io
@ 2024-02-28 17:56               ` Mike Maslenkin
  2024-02-29  0:11                 ` Nickle Wang via groups.io
  0 siblings, 1 reply; 15+ messages in thread
From: Mike Maslenkin @ 2024-02-28 17:56 UTC (permalink / raw)
  To: Nickle Wang
  Cc: devel@edk2.groups.io, Igor Kulchytskyy, Abner Chang, Nick Ramirez

On Wed, Feb 28, 2024 at 2:47 PM Nickle Wang <nicklew@nvidia.com> wrote:
>
> Hi @Mike Maslenkin,
>
>
>
> May I have your reviewed-by if version 3 patch set look good to you?
>

Sure!

Reviewed-by: Mike Maslenkin <mike.maslenkin@gmail.com>

BTW I'm just curious, there is a mention in patch 2 "We currently only
support gzip Content-Encoding."
But I didn't see any implementation of gzip coding/encoding for edk2.
Do you know of any?

I hope you know that patch 5 breaks edk2-redfish-client compilation
(Instance of library class [RedfishHttpLib] is not found)
But I understand these changes are not atomic for edk2 and edk2-redfish-client.

Regards,
Mike.


>
>
> Thanks,
>
> Nickle
>
>
>
> > -----Original Message-----
>
> > From: devel@edk2.groups.io <devel@edk2.groups.io> On Behalf Of Nickle Wang
>
> > via groups.io
>
> > Sent: Tuesday, February 27, 2024 8:49 AM
>
> > To: Mike Maslenkin <mike.maslenkin@gmail.com>
>
> > Cc: devel@edk2.groups.io; Igor Kulchytskyy <igork@ami.com>; Abner Chang
>
> > <abner.chang@amd.com>; Nick Ramirez <nramirez@nvidia.com>
>
> > Subject: Re: [edk2-devel] [PATCH v2 2/6] RedfishPkg: implement Redfish HTTP
>
> > protocol
>
> >
>
> > External email: Use caution opening links or attachments
>
> >
>
> >
>
> > Thanks for your confirmation, Mike!
>
> >
>
> > Version 3 patch set is here: https://edk2.groups.io/g/devel/message/115985
>
> >
>
> > Regards,
>
> > Nickle
>
> >
>
> > > -----Original Message-----
>
> > > From: Mike Maslenkin <mike.maslenkin@gmail.com>
>
> > > Sent: Tuesday, February 27, 2024 8:13 AM
>
> > > To: Nickle Wang <nicklew@nvidia.com>
>
> > > Cc: devel@edk2.groups.io; Igor Kulchytskyy <igork@ami.com>; Abner
>
> > > Chang <abner.chang@amd.com>; Nick Ramirez <nramirez@nvidia.com>
>
> > > Subject: Re: [edk2-devel] [PATCH v2 2/6] RedfishPkg: implement Redfish
>
> > > HTTP protocol
>
> > >
>
> > > External email: Use caution opening links or attachments
>
> > >
>
> > >
>
> > > Hii Nickle,
>
> > >
>
> > >
>
> > > On Mon, Feb 26, 2024 at 4:44 PM Nickle Wang <nicklew@nvidia.com> wrote:
>
> > > >
>
> > > > Hi Mike,
>
> > > >
>
> > > > > So finally we have
>
> > > > > HttpFreeHeaderFields (Response->Headers, Response->HeaderCount);
>
> > > > > but
>
> > > > > Response->HeaderCount does not count partially allocated elements. Right?
>
> > > > >
>
> > > > > To fix this, it is required to set *DstHeaderCount =
>
> > > > > SrcHeaderCount unconditionally right after DstHeaders  allocation,
>
> > > > > and HttpFreeHeaderFields() will do the work then.
>
> > > >
>
> > > > I follow your suggestion to update DstHeaderCount right after
>
> > > > DstHeaders is
>
> > > allocated.  So, HttpFreeHeaderFields can release headers correctly. I
>
> > > also create a macro to implemented AsciiStrCpy. Please check below link to see
>
> > my changes:
>
> > > > https://nam11.safelinks.protection.outlook.com/?url=https%3A%2F%2Fgi
>
> > > > th
>
> > > >
>
> > >
>
> > ub.com%2Ftianocore%2Fedk2%2Fcompare%2F0f391b1c2f988d90a3ac723b314a
>
> > > c28b
>
> > > >
>
> > >
>
> > a7b0b8df..f0fa1b8fdcd933beb52fd3127c2476443c00ef8d&data=05%7C02%7Cnic
>
> > > k
>
> > > >
>
> > >
>
> > lew%40nvidia.com%7Cf3870f71360e44f3b4e208dc3728ff87%7C43083d1572734
>
> > > 0c1
>
> > > >
>
> > >
>
> > b7db39efd9ccc17a%7C0%7C0%7C638445896465360452%7CUnknown%7CTWFp
>
> > > bGZsb3d8
>
> > > >
>
> > >
>
> > eyJWIjoiMC4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%
>
> > > 7C0
>
> > > >
>
> > >
>
> > %7C%7C%7C&sdata=K%2FEA2QWpk%2F8NHQ1QhzqkvQqao4db%2BILn1Jt%2BB
>
> > > qQ5n1E%3D
>
> > > > &reserved=0
>
> > >
>
> > > These changes looks good. Internal strings
>
> > > initialization/deinitialization code much cleaner now and possible leak seems to
>
> > have been fixed.
>
> > >
>
> > > Thank you!
>
> > >
>
> > > Regards,
>
> > > Mike.
>
> >
>
> >
>
> > 
>
> >
>
>


-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#116126): https://edk2.groups.io/g/devel/message/116126
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]
-=-=-=-=-=-=-=-=-=-=-=-



^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [edk2-devel] [PATCH v2 2/6] RedfishPkg: implement Redfish HTTP protocol
  2024-02-28 17:56               ` Mike Maslenkin
@ 2024-02-29  0:11                 ` Nickle Wang via groups.io
  2024-02-29  0:30                   ` Chang, Abner via groups.io
  0 siblings, 1 reply; 15+ messages in thread
From: Nickle Wang via groups.io @ 2024-02-29  0:11 UTC (permalink / raw)
  To: Mike Maslenkin
  Cc: devel@edk2.groups.io, Igor Kulchytskyy, Abner Chang, Nick Ramirez

> Sure!
> 
> Reviewed-by: Mike Maslenkin <mike.maslenkin@gmail.com>

Thanks, Mike!

> But I didn't see any implementation of gzip coding/encoding for edk2.
> Do you know of any?

I just talked to Aber about this. We are working to see if we can provide gzip implementation in edk2 or not. It seems to me that we need 3rd party library to edk2 for supporting gzip. Anber, please feel free to correct me if I am wrong.

> I hope you know that patch 5 breaks edk2-redfish-client compilation (Instance of
> library class [RedfishHttpLib] is not found) But I understand these changes are not
> atomic for edk2 and edk2-redfish-client.

Yes, I also have patch for edk2-redfish-client to use Redfish HTTP protocol. I had tested Redfish HTTP protocol on edk2-redfish-client. I will send out patch for review after Redfish HTTP protocol gets merged in edk2.

Regards,
Nickle

> -----Original Message-----
> From: Mike Maslenkin <mike.maslenkin@gmail.com>
> Sent: Thursday, February 29, 2024 1:56 AM
> To: Nickle Wang <nicklew@nvidia.com>
> Cc: devel@edk2.groups.io; Igor Kulchytskyy <igork@ami.com>; Abner Chang
> <abner.chang@amd.com>; Nick Ramirez <nramirez@nvidia.com>
> Subject: Re: [edk2-devel] [PATCH v2 2/6] RedfishPkg: implement Redfish HTTP
> protocol
> 
> External email: Use caution opening links or attachments
> 
> 
> On Wed, Feb 28, 2024 at 2:47 PM Nickle Wang <nicklew@nvidia.com> wrote:
> >
> > Hi @Mike Maslenkin,
> >
> >
> >
> > May I have your reviewed-by if version 3 patch set look good to you?
> >
> 
> Sure!
> 
> Reviewed-by: Mike Maslenkin <mike.maslenkin@gmail.com>
> 
> BTW I'm just curious, there is a mention in patch 2 "We currently only support
> gzip Content-Encoding."
> But I didn't see any implementation of gzip coding/encoding for edk2.
> Do you know of any?
> 
> I hope you know that patch 5 breaks edk2-redfish-client compilation (Instance of
> library class [RedfishHttpLib] is not found) But I understand these changes are not
> atomic for edk2 and edk2-redfish-client.
> 
> Regards,
> Mike.
> 
> 
> >
> >
> > Thanks,
> >
> > Nickle
> >
> >
> >
> > > -----Original Message-----
> >
> > > From: devel@edk2.groups.io <devel@edk2.groups.io> On Behalf Of
> > > Nickle Wang
> >
> > > via groups.io
> >
> > > Sent: Tuesday, February 27, 2024 8:49 AM
> >
> > > To: Mike Maslenkin <mike.maslenkin@gmail.com>
> >
> > > Cc: devel@edk2.groups.io; Igor Kulchytskyy <igork@ami.com>; Abner
> > > Chang
> >
> > > <abner.chang@amd.com>; Nick Ramirez <nramirez@nvidia.com>
> >
> > > Subject: Re: [edk2-devel] [PATCH v2 2/6] RedfishPkg: implement
> > > Redfish HTTP
> >
> > > protocol
> >
> > >
> >
> > > External email: Use caution opening links or attachments
> >
> > >
> >
> > >
> >
> > > Thanks for your confirmation, Mike!
> >
> > >
> >
> > > Version 3 patch set is here:
> > > https://nam11.safelinks.protection.outlook.com/?url=https%3A%2F%2Fed
> > >
> k2.groups.io%2Fg%2Fdevel%2Fmessage%2F115985&data=05%7C02%7Cnicklew
> %4
> > >
> 0nvidia.com%7Ca30038f7379c4f8dad3b08dc3886a03b%7C43083d15727340c1b
> 7d
> > >
> b39efd9ccc17a%7C0%7C0%7C638447398077724632%7CUnknown%7CTWFpbG
> Zsb3d8e
> > >
> yJWIjoiMC4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7
> C
> > >
> 0%7C%7C%7C&sdata=0tXBIuafvJuG7AM1DpAgSGGLf1QeUbOOmCq2WQCYpeg%
> 3D&rese
> > > rved=0
> >
> > >
> >
> > > Regards,
> >
> > > Nickle
> >
> > >
> >
> > > > -----Original Message-----
> >
> > > > From: Mike Maslenkin <mike.maslenkin@gmail.com>
> >
> > > > Sent: Tuesday, February 27, 2024 8:13 AM
> >
> > > > To: Nickle Wang <nicklew@nvidia.com>
> >
> > > > Cc: devel@edk2.groups.io; Igor Kulchytskyy <igork@ami.com>; Abner
> >
> > > > Chang <abner.chang@amd.com>; Nick Ramirez <nramirez@nvidia.com>
> >
> > > > Subject: Re: [edk2-devel] [PATCH v2 2/6] RedfishPkg: implement
> > > > Redfish
> >
> > > > HTTP protocol
> >
> > > >
> >
> > > > External email: Use caution opening links or attachments
> >
> > > >
> >
> > > >
> >
> > > > Hii Nickle,
> >
> > > >
> >
> > > >
> >
> > > > On Mon, Feb 26, 2024 at 4:44 PM Nickle Wang <nicklew@nvidia.com>
> wrote:
> >
> > > > >
> >
> > > > > Hi Mike,
> >
> > > > >
> >
> > > > > > So finally we have
> >
> > > > > > HttpFreeHeaderFields (Response->Headers,
> > > > > > Response->HeaderCount);
> >
> > > > > > but
> >
> > > > > > Response->HeaderCount does not count partially allocated elements.
> Right?
> >
> > > > > >
> >
> > > > > > To fix this, it is required to set *DstHeaderCount =
> >
> > > > > > SrcHeaderCount unconditionally right after DstHeaders
> > > > > > allocation,
> >
> > > > > > and HttpFreeHeaderFields() will do the work then.
> >
> > > > >
> >
> > > > > I follow your suggestion to update DstHeaderCount right after
> >
> > > > > DstHeaders is
> >
> > > > allocated.  So, HttpFreeHeaderFields can release headers
> > > > correctly. I
> >
> > > > also create a macro to implemented AsciiStrCpy. Please check below
> > > > link to see
> >
> > > my changes:
> >
> > > > > https://nam11.safelinks.protection.outlook.com/?url=https%3A%2F%
> > > > >
> 2Fgi%2F&data=05%7C02%7Cnicklew%40nvidia.com%7Ca30038f7379c4f8dad
> > > > >
> 3b08dc3886a03b%7C43083d15727340c1b7db39efd9ccc17a%7C0%7C0%7C6384
> > > > >
> 47398077735545%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLjAwMDAiLCJ
> QI
> > > > >
> joiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C0%7C%7C%7C&sdata=dZf
> > > > >
> %2BXZMEyp4%2BC%2BZgFnVCr12fIyXn1ZDsFfk2ejkYGO8%3D&reserved=0
> >
> > > > > th
> >
> > > > >
> >
> > > >
> >
> > >
> ub.com%2Ftianocore%2Fedk2%2Fcompare%2F0f391b1c2f988d90a3ac723b314a
> >
> > > > c28b
> >
> > > > >
> >
> > > >
> >
> > >
> a7b0b8df..f0fa1b8fdcd933beb52fd3127c2476443c00ef8d&data=05%7C02%7Cni
> > > c
> >
> > > > k
> >
> > > > >
> >
> > > >
> >
> > >
> lew%40nvidia.com%7Cf3870f71360e44f3b4e208dc3728ff87%7C43083d1572734
> >
> > > > 0c1
> >
> > > > >
> >
> > > >
> >
> > >
> b7db39efd9ccc17a%7C0%7C0%7C638445896465360452%7CUnknown%7CTWFp
> >
> > > > bGZsb3d8
> >
> > > > >
> >
> > > >
> >
> > >
> eyJWIjoiMC4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%
> >
> > > > 7C0
> >
> > > > >
> >
> > > >
> >
> > >
> %7C%7C%7C&sdata=K%2FEA2QWpk%2F8NHQ1QhzqkvQqao4db%2BILn1Jt%2BB
> >
> > > > qQ5n1E%3D
> >
> > > > > &reserved=0
> >
> > > >
> >
> > > > These changes looks good. Internal strings
> >
> > > > initialization/deinitialization code much cleaner now and possible
> > > > leak seems to
> >
> > > have been fixed.
> >
> > > >
> >
> > > > Thank you!
> >
> > > >
> >
> > > > Regards,
> >
> > > > Mike.
> >
> > >
> >
> > >
> >
> > > 
> >
> > >
> >
> >


-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#116129): https://edk2.groups.io/g/devel/message/116129
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]
-=-=-=-=-=-=-=-=-=-=-=-



^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [edk2-devel] [PATCH v2 2/6] RedfishPkg: implement Redfish HTTP protocol
  2024-02-29  0:11                 ` Nickle Wang via groups.io
@ 2024-02-29  0:30                   ` Chang, Abner via groups.io
  2024-02-29  1:37                     ` Igor Kulchytskyy via groups.io
  0 siblings, 1 reply; 15+ messages in thread
From: Chang, Abner via groups.io @ 2024-02-29  0:30 UTC (permalink / raw)
  To: Nickle Wang, Mike Maslenkin, Igor Kulchytskyy
  Cc: devel@edk2.groups.io, Nick Ramirez

[AMD Official Use Only - General]

> -----Original Message-----
> From: Nickle Wang <nicklew@nvidia.com>
> Sent: Thursday, February 29, 2024 8:11 AM
> To: Mike Maslenkin <mike.maslenkin@gmail.com>
> Cc: devel@edk2.groups.io; Igor Kulchytskyy <igork@ami.com>; Chang, Abner
> <Abner.Chang@amd.com>; Nick Ramirez <nramirez@nvidia.com>
> Subject: RE: [edk2-devel] [PATCH v2 2/6] RedfishPkg: implement Redfish
> HTTP protocol
>
> Caution: This message originated from an External Source. Use proper caution
> when opening attachments, clicking links, or responding.
>
>
> > Sure!
> >
> > Reviewed-by: Mike Maslenkin <mike.maslenkin@gmail.com>
>
> Thanks, Mike!
>
> > But I didn't see any implementation of gzip coding/encoding for edk2.
> > Do you know of any?
>
> I just talked to Aber about this. We are working to see if we can provide gzip
> implementation in edk2 or not. It seems to me that we need 3rd party library
> to edk2 for supporting gzip. Anber, please feel free to correct me if I am wrong.
Yes and we hope someone can provide the implementation. @Igor Kulchytskyy, does AMI has the implementation of gzip? 😊
BTW, we do have a proposal that introduces EFI_SOURCE_CODING_PROTOCOL long time ago while I was worked for HPE. I think we should pick up this one and promote this protocol in UEFI spec, we can work with AMI on this as well.

Thanks
Abner


>
> > I hope you know that patch 5 breaks edk2-redfish-client compilation
> (Instance of
> > library class [RedfishHttpLib] is not found) But I understand these changes
> are not
> > atomic for edk2 and edk2-redfish-client.
>
> Yes, I also have patch for edk2-redfish-client to use Redfish HTTP protocol. I
> had tested Redfish HTTP protocol on edk2-redfish-client. I will send out patch
> for review after Redfish HTTP protocol gets merged in edk2.
>
> Regards,
> Nickle
>
> > -----Original Message-----
> > From: Mike Maslenkin <mike.maslenkin@gmail.com>
> > Sent: Thursday, February 29, 2024 1:56 AM
> > To: Nickle Wang <nicklew@nvidia.com>
> > Cc: devel@edk2.groups.io; Igor Kulchytskyy <igork@ami.com>; Abner Chang
> > <abner.chang@amd.com>; Nick Ramirez <nramirez@nvidia.com>
> > Subject: Re: [edk2-devel] [PATCH v2 2/6] RedfishPkg: implement Redfish
> HTTP
> > protocol
> >
> > External email: Use caution opening links or attachments
> >
> >
> > On Wed, Feb 28, 2024 at 2:47 PM Nickle Wang <nicklew@nvidia.com>
> wrote:
> > >
> > > Hi @Mike Maslenkin,
> > >
> > >
> > >
> > > May I have your reviewed-by if version 3 patch set look good to you?
> > >
> >
> > Sure!
> >
> > Reviewed-by: Mike Maslenkin <mike.maslenkin@gmail.com>
> >
> > BTW I'm just curious, there is a mention in patch 2 "We currently only
> support
> > gzip Content-Encoding."
> > But I didn't see any implementation of gzip coding/encoding for edk2.
> > Do you know of any?
> >
> > I hope you know that patch 5 breaks edk2-redfish-client compilation
> (Instance of
> > library class [RedfishHttpLib] is not found) But I understand these changes
> are not
> > atomic for edk2 and edk2-redfish-client.
> >
> > Regards,
> > Mike.
> >
> >
> > >
> > >
> > > Thanks,
> > >
> > > Nickle
> > >
> > >
> > >
> > > > -----Original Message-----
> > >
> > > > From: devel@edk2.groups.io <devel@edk2.groups.io> On Behalf Of
> > > > Nickle Wang
> > >
> > > > via groups.io
> > >
> > > > Sent: Tuesday, February 27, 2024 8:49 AM
> > >
> > > > To: Mike Maslenkin <mike.maslenkin@gmail.com>
> > >
> > > > Cc: devel@edk2.groups.io; Igor Kulchytskyy <igork@ami.com>; Abner
> > > > Chang
> > >
> > > > <abner.chang@amd.com>; Nick Ramirez <nramirez@nvidia.com>
> > >
> > > > Subject: Re: [edk2-devel] [PATCH v2 2/6] RedfishPkg: implement
> > > > Redfish HTTP
> > >
> > > > protocol
> > >
> > > >
> > >
> > > > External email: Use caution opening links or attachments
> > >
> > > >
> > >
> > > >
> > >
> > > > Thanks for your confirmation, Mike!
> > >
> > > >
> > >
> > > > Version 3 patch set is here:
> > > >
> https://nam11.safelinks.protection.outlook.com/?url=https%3A%2F%2Fed
> > > >
> >
> k2.groups.io%2Fg%2Fdevel%2Fmessage%2F115985&data=05%7C02%7Cnic
> klew
> > %4
> > > >
> >
> 0nvidia.com%7Ca30038f7379c4f8dad3b08dc3886a03b%7C43083d157273
> 40c1b
> > 7d
> > > >
> >
> b39efd9ccc17a%7C0%7C0%7C638447398077724632%7CUnknown%7CTW
> FpbG
> > Zsb3d8e
> > > >
> >
> yJWIjoiMC4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3
> D%7
> > C
> > > >
> >
> 0%7C%7C%7C&sdata=0tXBIuafvJuG7AM1DpAgSGGLf1QeUbOOmCq2WQCY
> peg%
> > 3D&rese
> > > > rved=0
> > >
> > > >
> > >
> > > > Regards,
> > >
> > > > Nickle
> > >
> > > >
> > >
> > > > > -----Original Message-----
> > >
> > > > > From: Mike Maslenkin <mike.maslenkin@gmail.com>
> > >
> > > > > Sent: Tuesday, February 27, 2024 8:13 AM
> > >
> > > > > To: Nickle Wang <nicklew@nvidia.com>
> > >
> > > > > Cc: devel@edk2.groups.io; Igor Kulchytskyy <igork@ami.com>; Abner
> > >
> > > > > Chang <abner.chang@amd.com>; Nick Ramirez
> <nramirez@nvidia.com>
> > >
> > > > > Subject: Re: [edk2-devel] [PATCH v2 2/6] RedfishPkg: implement
> > > > > Redfish
> > >
> > > > > HTTP protocol
> > >
> > > > >
> > >
> > > > > External email: Use caution opening links or attachments
> > >
> > > > >
> > >
> > > > >
> > >
> > > > > Hii Nickle,
> > >
> > > > >
> > >
> > > > >
> > >
> > > > > On Mon, Feb 26, 2024 at 4:44 PM Nickle Wang <nicklew@nvidia.com>
> > wrote:
> > >
> > > > > >
> > >
> > > > > > Hi Mike,
> > >
> > > > > >
> > >
> > > > > > > So finally we have
> > >
> > > > > > > HttpFreeHeaderFields (Response->Headers,
> > > > > > > Response->HeaderCount);
> > >
> > > > > > > but
> > >
> > > > > > > Response->HeaderCount does not count partially allocated
> elements.
> > Right?
> > >
> > > > > > >
> > >
> > > > > > > To fix this, it is required to set *DstHeaderCount =
> > >
> > > > > > > SrcHeaderCount unconditionally right after DstHeaders
> > > > > > > allocation,
> > >
> > > > > > > and HttpFreeHeaderFields() will do the work then.
> > >
> > > > > >
> > >
> > > > > > I follow your suggestion to update DstHeaderCount right after
> > >
> > > > > > DstHeaders is
> > >
> > > > > allocated.  So, HttpFreeHeaderFields can release headers
> > > > > correctly. I
> > >
> > > > > also create a macro to implemented AsciiStrCpy. Please check below
> > > > > link to see
> > >
> > > > my changes:
> > >
> > > > > >
> https://nam11.safelinks.protection.outlook.com/?url=https%3A%2F%
> > > > > >
> >
> 2Fgi%2F&data=05%7C02%7Cnicklew%40nvidia.com%7Ca30038f7379c4f8d
> ad
> > > > > >
> >
> 3b08dc3886a03b%7C43083d15727340c1b7db39efd9ccc17a%7C0%7C0%7
> C6384
> > > > > >
> >
> 47398077735545%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLjAwMD
> AiLCJ
> > QI
> > > > > >
> >
> joiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C0%7C%7C%7C&sdata=d
> Zf
> > > > > >
> > %2BXZMEyp4%2BC%2BZgFnVCr12fIyXn1ZDsFfk2ejkYGO8%3D&reserved=0
> > >
> > > > > > th
> > >
> > > > > >
> > >
> > > > >
> > >
> > > >
> >
> ub.com%2Ftianocore%2Fedk2%2Fcompare%2F0f391b1c2f988d90a3ac723b
> 314a
> > >
> > > > > c28b
> > >
> > > > > >
> > >
> > > > >
> > >
> > > >
> >
> a7b0b8df..f0fa1b8fdcd933beb52fd3127c2476443c00ef8d&data=05%7C02
> %7Cni
> > > > c
> > >
> > > > > k
> > >
> > > > > >
> > >
> > > > >
> > >
> > > >
> >
> lew%40nvidia.com%7Cf3870f71360e44f3b4e208dc3728ff87%7C43083d15
> 72734
> > >
> > > > > 0c1
> > >
> > > > > >
> > >
> > > > >
> > >
> > > >
> >
> b7db39efd9ccc17a%7C0%7C0%7C638445896465360452%7CUnknown%7
> CTWFp
> > >
> > > > > bGZsb3d8
> > >
> > > > > >
> > >
> > > > >
> > >
> > > >
> >
> eyJWIjoiMC4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3
> D%
> > >
> > > > > 7C0
> > >
> > > > > >
> > >
> > > > >
> > >
> > > >
> >
> %7C%7C%7C&sdata=K%2FEA2QWpk%2F8NHQ1QhzqkvQqao4db%2BILn1Jt
> %2BB
> > >
> > > > > qQ5n1E%3D
> > >
> > > > > > &reserved=0
> > >
> > > > >
> > >
> > > > > These changes looks good. Internal strings
> > >
> > > > > initialization/deinitialization code much cleaner now and possible
> > > > > leak seems to
> > >
> > > > have been fixed.
> > >
> > > > >
> > >
> > > > > Thank you!
> > >
> > > > >
> > >
> > > > > Regards,
> > >
> > > > > Mike.
> > >
> > > >
> > >
> > > >
> > >
> > > > 
> > >
> > > >
> > >
> > >


-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#116130): https://edk2.groups.io/g/devel/message/116130
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]
-=-=-=-=-=-=-=-=-=-=-=-



^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [edk2-devel] [PATCH v2 2/6] RedfishPkg: implement Redfish HTTP protocol
  2024-02-29  0:30                   ` Chang, Abner via groups.io
@ 2024-02-29  1:37                     ` Igor Kulchytskyy via groups.io
  2024-02-29  4:01                       ` Chang, Abner via groups.io
  0 siblings, 1 reply; 15+ messages in thread
From: Igor Kulchytskyy via groups.io @ 2024-02-29  1:37 UTC (permalink / raw)
  To: Chang, Abner, Nickle Wang, Mike Maslenkin
  Cc: devel@edk2.groups.io, Nick Ramirez

[-- Attachment #1: Type: text/plain, Size: 12447 bytes --]





-----Original Message-----
From: Chang, Abner <Abner.Chang@amd.com>
Sent: Wednesday, February 28, 2024 7:31 PM
To: Nickle Wang <nicklew@nvidia.com>; Mike Maslenkin <mike.maslenkin@gmail.com>; Igor Kulchytskyy <igork@ami.com>
Cc: devel@edk2.groups.io; Nick Ramirez <nramirez@nvidia.com>
Subject: [EXTERNAL] RE: [edk2-devel] [PATCH v2 2/6] RedfishPkg: implement Redfish HTTP protocol





**CAUTION: The e-mail below is from an external source. Please exercise caution before opening attachments, clicking links, or following guidance.**



[AMD Official Use Only - General]



> -----Original Message-----

> From: Nickle Wang <nicklew@nvidia.com<mailto:nicklew@nvidia.com>>

> Sent: Thursday, February 29, 2024 8:11 AM

> To: Mike Maslenkin <mike.maslenkin@gmail.com<mailto:mike.maslenkin@gmail.com>>

> Cc: devel@edk2.groups.io<mailto:devel@edk2.groups.io>; Igor Kulchytskyy <igork@ami.com<mailto:igork@ami.com>>; Chang, Abner

> <Abner.Chang@amd.com<mailto:Abner.Chang@amd.com>>; Nick Ramirez <nramirez@nvidia.com<mailto:nramirez@nvidia.com>>

> Subject: RE: [edk2-devel] [PATCH v2 2/6] RedfishPkg: implement Redfish

> HTTP protocol

>

> Caution: This message originated from an External Source. Use proper caution

> when opening attachments, clicking links, or responding.

>

>

> > Sure!

> >

> > Reviewed-by: Mike Maslenkin <mike.maslenkin@gmail.com<mailto:mike.maslenkin@gmail.com>>

>

> Thanks, Mike!

>

> > But I didn't see any implementation of gzip coding/encoding for edk2.

> > Do you know of any?

>

> I just talked to Aber about this. We are working to see if we can provide gzip

> implementation in edk2 or not. It seems to me that we need 3rd party library

> to edk2 for supporting gzip. Anber, please feel free to correct me if I am wrong.

Yes and we hope someone can provide the implementation. @Igor Kulchytskyy, does AMI has the implementation of gzip? 😊

BTW, we do have a proposal that introduces EFI_SOURCE_CODING_PROTOCOL long time ago while I was worked for HPE. I think we should pick up this one and promote this protocol in UEFI spec, we can work with AMI on this as well.



Thanks

Abner



Hi Abner,

Unfortunately, AMI does not have the implementation of gzip.

Why do you think AMI has it? 😊

I can investigate the 3rd party libraries to be adopted for using in UEFI environment.

Thank you,

Igor



>

> > I hope you know that patch 5 breaks edk2-redfish-client compilation

> (Instance of

> > library class [RedfishHttpLib] is not found) But I understand these changes

> are not

> > atomic for edk2 and edk2-redfish-client.

>

> Yes, I also have patch for edk2-redfish-client to use Redfish HTTP protocol. I

> had tested Redfish HTTP protocol on edk2-redfish-client. I will send out patch

> for review after Redfish HTTP protocol gets merged in edk2.

>

> Regards,

> Nickle

>

> > -----Original Message-----

> > From: Mike Maslenkin <mike.maslenkin@gmail.com<mailto:mike.maslenkin@gmail.com>>

> > Sent: Thursday, February 29, 2024 1:56 AM

> > To: Nickle Wang <nicklew@nvidia.com<mailto:nicklew@nvidia.com>>

> > Cc: devel@edk2.groups.io<mailto:devel@edk2.groups.io>; Igor Kulchytskyy <igork@ami.com<mailto:igork@ami.com>>; Abner Chang

> > <abner.chang@amd.com<mailto:abner.chang@amd.com>>; Nick Ramirez <nramirez@nvidia.com<mailto:nramirez@nvidia.com>>

> > Subject: Re: [edk2-devel] [PATCH v2 2/6] RedfishPkg: implement Redfish

> HTTP

> > protocol

> >

> > External email: Use caution opening links or attachments

> >

> >

> > On Wed, Feb 28, 2024 at 2:47 PM Nickle Wang <nicklew@nvidia.com<mailto:nicklew@nvidia.com>>

> wrote:

> > >

> > > Hi @Mike Maslenkin,

> > >

> > >

> > >

> > > May I have your reviewed-by if version 3 patch set look good to you?

> > >

> >

> > Sure!

> >

> > Reviewed-by: Mike Maslenkin <mike.maslenkin@gmail.com<mailto:mike.maslenkin@gmail.com>>

> >

> > BTW I'm just curious, there is a mention in patch 2 "We currently only

> support

> > gzip Content-Encoding."

> > But I didn't see any implementation of gzip coding/encoding for edk2.

> > Do you know of any?

> >

> > I hope you know that patch 5 breaks edk2-redfish-client compilation

> (Instance of

> > library class [RedfishHttpLib] is not found) But I understand these changes

> are not

> > atomic for edk2 and edk2-redfish-client.

> >

> > Regards,

> > Mike.

> >

> >

> > >

> > >

> > > Thanks,

> > >

> > > Nickle

> > >

> > >

> > >

> > > > -----Original Message-----

> > >

> > > > From: devel@edk2.groups.io<mailto:devel@edk2.groups.io> <devel@edk2.groups.io<mailto:devel@edk2.groups.io>> On Behalf Of

> > > > Nickle Wang

> > >

> > > > via groups.io

> > >

> > > > Sent: Tuesday, February 27, 2024 8:49 AM

> > >

> > > > To: Mike Maslenkin <mike.maslenkin@gmail.com<mailto:mike.maslenkin@gmail.com>>

> > >

> > > > Cc: devel@edk2.groups.io<mailto:devel@edk2.groups.io>; Igor Kulchytskyy <igork@ami.com<mailto:igork@ami.com>>; Abner

> > > > Chang

> > >

> > > > <abner.chang@amd.com<mailto:abner.chang@amd.com>>; Nick Ramirez <nramirez@nvidia.com<mailto:nramirez@nvidia.com>>

> > >

> > > > Subject: Re: [edk2-devel] [PATCH v2 2/6] RedfishPkg: implement

> > > > Redfish HTTP

> > >

> > > > protocol

> > >

> > > >

> > >

> > > > External email: Use caution opening links or attachments

> > >

> > > >

> > >

> > > >

> > >

> > > > Thanks for your confirmation, Mike!

> > >

> > > >

> > >

> > > > Version 3 patch set is here:

> > > >

> https://nam12.safelinks.protection.outlook.com/?url=https%3A%2F%2Fed%2F&data=05%7C02%7Cigork%40ami.com%7Ca119b05ccbf64656ecd808dc38bda910%7C27e97857e15f486cb58e86c2b3040f93%7C1%7C0%7C638447634515178497%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C0%7C%7C%7C&sdata=%2F7QVT4mZwfDb0zkMILIjWV2u8TldJEwSELjsjIVqkYg%3D&reserved=0<https://ed/>

> > > >

> >

> k2.groups.io%2Fg%2Fdevel%2Fmessage%2F115985&data=05%7C02%7Cnic

> klew

> > %4

> > > >

> >

> 0nvidia.com%7Ca30038f7379c4f8dad3b08dc3886a03b%7C43083d157273

> 40c1b

> > 7d

> > > >

> >

> b39efd9ccc17a%7C0%7C0%7C638447398077724632%7CUnknown%7CTW

> FpbG

> > Zsb3d8e

> > > >

> >

> yJWIjoiMC4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3

> D%7

> > C

> > > >

> >

> 0%7C%7C%7C&sdata=0tXBIuafvJuG7AM1DpAgSGGLf1QeUbOOmCq2WQCY

> peg%

> > 3D&rese

> > > > rved=0

> > >

> > > >

> > >

> > > > Regards,

> > >

> > > > Nickle

> > >

> > > >

> > >

> > > > > -----Original Message-----

> > >

> > > > > From: Mike Maslenkin <mike.maslenkin@gmail.com<mailto:mike.maslenkin@gmail.com>>

> > >

> > > > > Sent: Tuesday, February 27, 2024 8:13 AM

> > >

> > > > > To: Nickle Wang <nicklew@nvidia.com<mailto:nicklew@nvidia.com>>

> > >

> > > > > Cc: devel@edk2.groups.io<mailto:devel@edk2.groups.io>; Igor Kulchytskyy <igork@ami.com<mailto:igork@ami.com>>; Abner

> > >

> > > > > Chang <abner.chang@amd.com<mailto:abner.chang@amd.com>>; Nick Ramirez

> <nramirez@nvidia.com<mailto:nramirez@nvidia.com>>

> > >

> > > > > Subject: Re: [edk2-devel] [PATCH v2 2/6] RedfishPkg: implement

> > > > > Redfish

> > >

> > > > > HTTP protocol

> > >

> > > > >

> > >

> > > > > External email: Use caution opening links or attachments

> > >

> > > > >

> > >

> > > > >

> > >

> > > > > Hii Nickle,

> > >

> > > > >

> > >

> > > > >

> > >

> > > > > On Mon, Feb 26, 2024 at 4:44 PM Nickle Wang <nicklew@nvidia.com<mailto:nicklew@nvidia.com>>

> > wrote:

> > >

> > > > > >

> > >

> > > > > > Hi Mike,

> > >

> > > > > >

> > >

> > > > > > > So finally we have

> > >

> > > > > > > HttpFreeHeaderFields (Response->Headers,

> > > > > > > Response->HeaderCount);

> > >

> > > > > > > but

> > >

> > > > > > > Response->HeaderCount does not count partially allocated

> elements.

> > Right?

> > >

> > > > > > >

> > >

> > > > > > > To fix this, it is required to set *DstHeaderCount =

> > >

> > > > > > > SrcHeaderCount unconditionally right after DstHeaders

> > > > > > > allocation,

> > >

> > > > > > > and HttpFreeHeaderFields() will do the work then.

> > >

> > > > > >

> > >

> > > > > > I follow your suggestion to update DstHeaderCount right after

> > >

> > > > > > DstHeaders is

> > >

> > > > > allocated.  So, HttpFreeHeaderFields can release headers

> > > > > correctly. I

> > >

> > > > > also create a macro to implemented AsciiStrCpy. Please check below

> > > > > link to see

> > >

> > > > my changes:

> > >

> > > > > >

> https://nam12.safelinks.protection.outlook.com/?url=https%3A%2F%2Fnam11.safelinks.protection.outlook.com%2F%3Furl%3Dhttps%253A%252F%2525&data=05%7C02%7Cigork%40ami.com%7Ca119b05ccbf64656ecd808dc38bda910%7C27e97857e15f486cb58e86c2b3040f93%7C1%7C0%7C638447634515186935%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C0%7C%7C%7C&sdata=OrYee0doa%2BgFUm6g0M2AVXq2U0UbEvUzUJ20YU7ykSk%3D&reserved=0<https://nam11.safelinks.protection.outlook.com/?url=https%3A%2F%25>

> > > > > >

> >

> 2Fgi%2F&data=05%7C02%7Cnicklew%40nvidia.com%7Ca30038f7379c4f8d

> ad

> > > > > >

> >

> 3b08dc3886a03b%7C43083d15727340c1b7db39efd9ccc17a%7C0%7C0%7

> C6384

> > > > > >

> >

> 47398077735545%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLjAwMD

> AiLCJ

> > QI

> > > > > >

> >

> joiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C0%7C%7C%7C&sdata=d

> Zf

> > > > > >

> > %2BXZMEyp4%2BC%2BZgFnVCr12fIyXn1ZDsFfk2ejkYGO8%3D&reserved=0

> > >

> > > > > > th

> > >

> > > > > >

> > >

> > > > >

> > >

> > > >

> >

> ub.com%2Ftianocore%2Fedk2%2Fcompare%2F0f391b1c2f988d90a3ac723b

> 314a

> > >

> > > > > c28b

> > >

> > > > > >

> > >

> > > > >

> > >

> > > >

> >

> a7b0b8df..f0fa1b8fdcd933beb52fd3127c2476443c00ef8d&data=05%7C02

> %7Cni

> > > > c

> > >

> > > > > k

> > >

> > > > > >

> > >

> > > > >

> > >

> > > >

> >

> lew%40nvidia.com%7Cf3870f71360e44f3b4e208dc3728ff87%7C43083d15

> 72734

> > >

> > > > > 0c1

> > >

> > > > > >

> > >

> > > > >

> > >

> > > >

> >

> b7db39efd9ccc17a%7C0%7C0%7C638445896465360452%7CUnknown%7

> CTWFp

> > >

> > > > > bGZsb3d8

> > >

> > > > > >

> > >

> > > > >

> > >

> > > >

> >

> eyJWIjoiMC4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3

> D%

> > >

> > > > > 7C0

> > >

> > > > > >

> > >

> > > > >

> > >

> > > >

> >

> %7C%7C%7C&sdata=K%2FEA2QWpk%2F8NHQ1QhzqkvQqao4db%2BILn1Jt

> %2BB

> > >

> > > > > qQ5n1E%3D

> > >

> > > > > > &reserved=0

> > >

> > > > >

> > >

> > > > > These changes looks good. Internal strings

> > >

> > > > > initialization/deinitialization code much cleaner now and possible

> > > > > leak seems to

> > >

> > > > have been fixed.

> > >

> > > > >

> > >

> > > > > Thank you!

> > >

> > > > >

> > >

> > > > > Regards,

> > >

> > > > > Mike.

> > >

> > > >

> > >

> > > >

> > >

> > > > 

> > >

> > > >

> > >

> > >

-The information contained in this message may be confidential and proprietary to American Megatrends (AMI). This communication is intended to be read only by the individual or entity to whom it is addressed or by their designee. If the reader of this message is not the intended recipient, you are on notice that any distribution of this message, in any form, is strictly prohibited. Please promptly notify the sender by reply e-mail or by telephone at 770-246-8600, and then delete or destroy all copies of the transmission.


-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#116131): https://edk2.groups.io/g/devel/message/116131
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]
-=-=-=-=-=-=-=-=-=-=-=-



[-- Attachment #2: Type: text/html, Size: 71850 bytes --]

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [edk2-devel] [PATCH v2 2/6] RedfishPkg: implement Redfish HTTP protocol
  2024-02-29  1:37                     ` Igor Kulchytskyy via groups.io
@ 2024-02-29  4:01                       ` Chang, Abner via groups.io
  0 siblings, 0 replies; 15+ messages in thread
From: Chang, Abner via groups.io @ 2024-02-29  4:01 UTC (permalink / raw)
  To: Igor Kulchytskyy, Nickle Wang, Mike Maslenkin
  Cc: devel@edk2.groups.io, Nick Ramirez

[-- Attachment #1: Type: text/plain, Size: 13248 bytes --]

[AMD Official Use Only - General]



From: Igor Kulchytskyy <igork@ami.com>
Sent: Thursday, February 29, 2024 9:38 AM
To: Chang, Abner <Abner.Chang@amd.com>; Nickle Wang <nicklew@nvidia.com>; Mike Maslenkin <mike.maslenkin@gmail.com>
Cc: devel@edk2.groups.io; Nick Ramirez <nramirez@nvidia.com>
Subject: RE: [EXTERNAL] RE: [edk2-devel] [PATCH v2 2/6] RedfishPkg: implement Redfish HTTP protocol


[AMD Official Use Only - General]

Caution: This message originated from an External Source. Use proper caution when opening attachments, clicking links, or responding.






-----Original Message-----
From: Chang, Abner <Abner.Chang@amd.com>
Sent: Wednesday, February 28, 2024 7:31 PM
To: Nickle Wang <nicklew@nvidia.com>; Mike Maslenkin <mike.maslenkin@gmail.com>; Igor Kulchytskyy <igork@ami.com>
Cc: devel@edk2.groups.io; Nick Ramirez <nramirez@nvidia.com>
Subject: [EXTERNAL] RE: [edk2-devel] [PATCH v2 2/6] RedfishPkg: implement Redfish HTTP protocol





**CAUTION: The e-mail below is from an external source. Please exercise caution before opening attachments, clicking links, or following guidance.**



[AMD Official Use Only - General]



> -----Original Message-----

> From: Nickle Wang <nicklew@nvidia.com<mailto:nicklew@nvidia.com>>

> Sent: Thursday, February 29, 2024 8:11 AM

> To: Mike Maslenkin <mike.maslenkin@gmail.com<mailto:mike.maslenkin@gmail.com>>

> Cc: devel@edk2.groups.io<mailto:devel@edk2.groups.io>; Igor Kulchytskyy <igork@ami.com<mailto:igork@ami.com>>; Chang, Abner

> <Abner.Chang@amd.com<mailto:Abner.Chang@amd.com>>; Nick Ramirez <nramirez@nvidia.com<mailto:nramirez@nvidia.com>>

> Subject: RE: [edk2-devel] [PATCH v2 2/6] RedfishPkg: implement Redfish

> HTTP protocol

>

> Caution: This message originated from an External Source. Use proper caution

> when opening attachments, clicking links, or responding.

>

>

> > Sure!

> >

> > Reviewed-by: Mike Maslenkin <mike.maslenkin@gmail.com<mailto:mike.maslenkin@gmail.com>>

>

> Thanks, Mike!

>

> > But I didn't see any implementation of gzip coding/encoding for edk2.

> > Do you know of any?

>

> I just talked to Aber about this. We are working to see if we can provide gzip

> implementation in edk2 or not. It seems to me that we need 3rd party library

> to edk2 for supporting gzip. Anber, please feel free to correct me if I am wrong.

Yes and we hope someone can provide the implementation. @Igor Kulchytskyy, does AMI has the implementation of gzip? 😊

BTW, we do have a proposal that introduces EFI_SOURCE_CODING_PROTOCOL long time ago while I was worked for HPE. I think we should pick up this one and promote this protocol in UEFI spec, we can work with AMI on this as well.



Thanks

Abner



Hi Abner,

Unfortunately, AMI does not have the implementation of gzip.

Why do you think AMI has it? 😊

I can investigate the 3rd party libraries to be adopted for using in UEFI environment.

Thank you,

Igor



I thought AMI has the implementation as you and Nickle considered the content encoded parameter for the Redfish HTTP protocol. I guess you have gzip implemented in AMI BIOS as Nvidia doesn’t. 😊



Abner



>

> > I hope you know that patch 5 breaks edk2-redfish-client compilation

> (Instance of

> > library class [RedfishHttpLib] is not found) But I understand these changes

> are not

> > atomic for edk2 and edk2-redfish-client.

>

> Yes, I also have patch for edk2-redfish-client to use Redfish HTTP protocol. I

> had tested Redfish HTTP protocol on edk2-redfish-client. I will send out patch

> for review after Redfish HTTP protocol gets merged in edk2.

>

> Regards,

> Nickle

>

> > -----Original Message-----

> > From: Mike Maslenkin <mike.maslenkin@gmail.com<mailto:mike.maslenkin@gmail.com>>

> > Sent: Thursday, February 29, 2024 1:56 AM

> > To: Nickle Wang <nicklew@nvidia.com<mailto:nicklew@nvidia.com>>

> > Cc: devel@edk2.groups.io<mailto:devel@edk2.groups.io>; Igor Kulchytskyy <igork@ami.com<mailto:igork@ami.com>>; Abner Chang

> > <abner.chang@amd.com<mailto:abner.chang@amd.com>>; Nick Ramirez <nramirez@nvidia.com<mailto:nramirez@nvidia.com>>

> > Subject: Re: [edk2-devel] [PATCH v2 2/6] RedfishPkg: implement Redfish

> HTTP

> > protocol

> >

> > External email: Use caution opening links or attachments

> >

> >

> > On Wed, Feb 28, 2024 at 2:47 PM Nickle Wang <nicklew@nvidia.com<mailto:nicklew@nvidia.com>>

> wrote:

> > >

> > > Hi @Mike Maslenkin,

> > >

> > >

> > >

> > > May I have your reviewed-by if version 3 patch set look good to you?

> > >

> >

> > Sure!

> >

> > Reviewed-by: Mike Maslenkin <mike.maslenkin@gmail.com<mailto:mike.maslenkin@gmail.com>>

> >

> > BTW I'm just curious, there is a mention in patch 2 "We currently only

> support

> > gzip Content-Encoding."

> > But I didn't see any implementation of gzip coding/encoding for edk2.

> > Do you know of any?

> >

> > I hope you know that patch 5 breaks edk2-redfish-client compilation

> (Instance of

> > library class [RedfishHttpLib] is not found) But I understand these changes

> are not

> > atomic for edk2 and edk2-redfish-client.

> >

> > Regards,

> > Mike.

> >

> >

> > >

> > >

> > > Thanks,

> > >

> > > Nickle

> > >

> > >

> > >

> > > > -----Original Message-----

> > >

> > > > From: devel@edk2.groups.io<mailto:devel@edk2.groups.io> <devel@edk2.groups.io<mailto:devel@edk2.groups.io>> On Behalf Of

> > > > Nickle Wang

> > >

> > > > via groups.io

> > >

> > > > Sent: Tuesday, February 27, 2024 8:49 AM

> > >

> > > > To: Mike Maslenkin <mike.maslenkin@gmail.com<mailto:mike.maslenkin@gmail.com>>

> > >

> > > > Cc: devel@edk2.groups.io<mailto:devel@edk2.groups.io>; Igor Kulchytskyy <igork@ami.com<mailto:igork@ami.com>>; Abner

> > > > Chang

> > >

> > > > <abner.chang@amd.com<mailto:abner.chang@amd.com>>; Nick Ramirez <nramirez@nvidia.com<mailto:nramirez@nvidia.com>>

> > >

> > > > Subject: Re: [edk2-devel] [PATCH v2 2/6] RedfishPkg: implement

> > > > Redfish HTTP

> > >

> > > > protocol

> > >

> > > >

> > >

> > > > External email: Use caution opening links or attachments

> > >

> > > >

> > >

> > > >

> > >

> > > > Thanks for your confirmation, Mike!

> > >

> > > >

> > >

> > > > Version 3 patch set is here:

> > > >

> https://nam12.safelinks.protection.outlook.com/?url=https%3A%2F%2Fed%2F&data=05%7C02%7Cigork%40ami.com%7Ca119b05ccbf64656ecd808dc38bda910%7C27e97857e15f486cb58e86c2b3040f93%7C1%7C0%7C638447634515178497%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C0%7C%7C%7C&sdata=%2F7QVT4mZwfDb0zkMILIjWV2u8TldJEwSELjsjIVqkYg%3D&reserved=0<https://ed/>

> > > >

> >

> k2.groups.io%2Fg%2Fdevel%2Fmessage%2F115985&data=05%7C02%7Cnic

> klew

> > %4

> > > >

> >

> 0nvidia.com%7Ca30038f7379c4f8dad3b08dc3886a03b%7C43083d157273

> 40c1b

> > 7d

> > > >

> >

> b39efd9ccc17a%7C0%7C0%7C638447398077724632%7CUnknown%7CTW

> FpbG

> > Zsb3d8e

> > > >

> >

> yJWIjoiMC4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3

> D%7

> > C

> > > >

> >

> 0%7C%7C%7C&sdata=0tXBIuafvJuG7AM1DpAgSGGLf1QeUbOOmCq2WQCY

> peg%

> > 3D&rese

> > > > rved=0

> > >

> > > >

> > >

> > > > Regards,

> > >

> > > > Nickle

> > >

> > > >

> > >

> > > > > -----Original Message-----

> > >

> > > > > From: Mike Maslenkin <mike.maslenkin@gmail.com<mailto:mike.maslenkin@gmail.com>>

> > >

> > > > > Sent: Tuesday, February 27, 2024 8:13 AM

> > >

> > > > > To: Nickle Wang <nicklew@nvidia.com<mailto:nicklew@nvidia.com>>

> > >

> > > > > Cc: devel@edk2.groups.io<mailto:devel@edk2.groups.io>; Igor Kulchytskyy <igork@ami.com<mailto:igork@ami.com>>; Abner

> > >

> > > > > Chang <abner.chang@amd.com<mailto:abner.chang@amd.com>>; Nick Ramirez

> <nramirez@nvidia.com<mailto:nramirez@nvidia.com>>

> > >

> > > > > Subject: Re: [edk2-devel] [PATCH v2 2/6] RedfishPkg: implement

> > > > > Redfish

> > >

> > > > > HTTP protocol

> > >

> > > > >

> > >

> > > > > External email: Use caution opening links or attachments

> > >

> > > > >

> > >

> > > > >

> > >

> > > > > Hii Nickle,

> > >

> > > > >

> > >

> > > > >

> > >

> > > > > On Mon, Feb 26, 2024 at 4:44 PM Nickle Wang <nicklew@nvidia.com<mailto:nicklew@nvidia.com>>

> > wrote:

> > >

> > > > > >

> > >

> > > > > > Hi Mike,

> > >

> > > > > >

> > >

> > > > > > > So finally we have

> > >

> > > > > > > HttpFreeHeaderFields (Response->Headers,

> > > > > > > Response->HeaderCount);

> > >

> > > > > > > but

> > >

> > > > > > > Response->HeaderCount does not count partially allocated

> elements.

> > Right?

> > >

> > > > > > >

> > >

> > > > > > > To fix this, it is required to set *DstHeaderCount =

> > >

> > > > > > > SrcHeaderCount unconditionally right after DstHeaders

> > > > > > > allocation,

> > >

> > > > > > > and HttpFreeHeaderFields() will do the work then.

> > >

> > > > > >

> > >

> > > > > > I follow your suggestion to update DstHeaderCount right after

> > >

> > > > > > DstHeaders is

> > >

> > > > > allocated.  So, HttpFreeHeaderFields can release headers

> > > > > correctly. I

> > >

> > > > > also create a macro to implemented AsciiStrCpy. Please check below

> > > > > link to see

> > >

> > > > my changes:

> > >

> > > > > >

> https://nam12.safelinks.protection.outlook.com/?url=https%3A%2F%2Fnam11.safelinks.protection.outlook.com%2F%3Furl%3Dhttps%253A%252F%2525&data=05%7C02%7Cigork%40ami.com%7Ca119b05ccbf64656ecd808dc38bda910%7C27e97857e15f486cb58e86c2b3040f93%7C1%7C0%7C638447634515186935%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C0%7C%7C%7C&sdata=OrYee0doa%2BgFUm6g0M2AVXq2U0UbEvUzUJ20YU7ykSk%3D&reserved=0<https://nam11.safelinks.protection.outlook.com/?url=https%3A%2F%25>

> > > > > >

> >

> 2Fgi%2F&data=05%7C02%7Cnicklew%40nvidia.com%7Ca30038f7379c4f8d

> ad

> > > > > >

> >

> 3b08dc3886a03b%7C43083d15727340c1b7db39efd9ccc17a%7C0%7C0%7

> C6384

> > > > > >

> >

> 47398077735545%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLjAwMD

> AiLCJ

> > QI

> > > > > >

> >

> joiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C0%7C%7C%7C&sdata=d

> Zf

> > > > > >

> > %2BXZMEyp4%2BC%2BZgFnVCr12fIyXn1ZDsFfk2ejkYGO8%3D&reserved=0

> > >

> > > > > > th

> > >

> > > > > >

> > >

> > > > >

> > >

> > > >

> >

> ub.com%2Ftianocore%2Fedk2%2Fcompare%2F0f391b1c2f988d90a3ac723b

> 314a

> > >

> > > > > c28b

> > >

> > > > > >

> > >

> > > > >

> > >

> > > >

> >

> a7b0b8df..f0fa1b8fdcd933beb52fd3127c2476443c00ef8d&data=05%7C02

> %7Cni

> > > > c

> > >

> > > > > k

> > >

> > > > > >

> > >

> > > > >

> > >

> > > >

> >

> lew%40nvidia.com%7Cf3870f71360e44f3b4e208dc3728ff87%7C43083d15

> 72734

> > >

> > > > > 0c1

> > >

> > > > > >

> > >

> > > > >

> > >

> > > >

> >

> b7db39efd9ccc17a%7C0%7C0%7C638445896465360452%7CUnknown%7

> CTWFp

> > >

> > > > > bGZsb3d8

> > >

> > > > > >

> > >

> > > > >

> > >

> > > >

> >

> eyJWIjoiMC4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3

> D%

> > >

> > > > > 7C0

> > >

> > > > > >

> > >

> > > > >

> > >

> > > >

> >

> %7C%7C%7C&sdata=K%2FEA2QWpk%2F8NHQ1QhzqkvQqao4db%2BILn1Jt

> %2BB

> > >

> > > > > qQ5n1E%3D

> > >

> > > > > > &reserved=0

> > >

> > > > >

> > >

> > > > > These changes looks good. Internal strings

> > >

> > > > > initialization/deinitialization code much cleaner now and possible

> > > > > leak seems to

> > >

> > > > have been fixed.

> > >

> > > > >

> > >

> > > > > Thank you!

> > >

> > > > >

> > >

> > > > > Regards,

> > >

> > > > > Mike.

> > >

> > > >

> > >

> > > >

> > >

> > > > 

> > >

> > > >

> > >

> > >
-The information contained in this message may be confidential and proprietary to American Megatrends (AMI). This communication is intended to be read only by the individual or entity to whom it is addressed or by their designee. If the reader of this message is not the intended recipient, you are on notice that any distribution of this message, in any form, is strictly prohibited. Please promptly notify the sender by reply e-mail or by telephone at 770-246-8600, and then delete or destroy all copies of the transmission.


-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#116133): https://edk2.groups.io/g/devel/message/116133
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]
-=-=-=-=-=-=-=-=-=-=-=-



[-- Attachment #2: Type: text/html, Size: 38592 bytes --]

^ permalink raw reply	[flat|nested] 15+ messages in thread

end of thread, other threads:[~2024-02-29  4:01 UTC | newest]

Thread overview: 15+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2024-02-22  9:11 [edk2-devel] [PATCH v2 2/6] RedfishPkg: implement Redfish HTTP protocol Nickle Wang via groups.io
2024-02-22 13:39 ` Chang, Abner via groups.io
2024-02-22 14:17 ` Igor Kulchytskyy via groups.io
2024-02-23 11:29 ` Mike Maslenkin
2024-02-23 14:07   ` Nickle Wang via groups.io
2024-02-23 16:04     ` Mike Maslenkin
2024-02-26 13:43       ` Nickle Wang via groups.io
2024-02-27  0:13         ` Mike Maslenkin
2024-02-27  0:48           ` Nickle Wang via groups.io
     [not found]           ` <17B791D5F1D9AF42.14830@groups.io>
2024-02-28 11:47             ` Nickle Wang via groups.io
2024-02-28 17:56               ` Mike Maslenkin
2024-02-29  0:11                 ` Nickle Wang via groups.io
2024-02-29  0:30                   ` Chang, Abner via groups.io
2024-02-29  1:37                     ` Igor Kulchytskyy via groups.io
2024-02-29  4:01                       ` Chang, Abner via groups.io

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox