public inbox for devel@edk2.groups.io
 help / color / mirror / Atom feed
From: "Chang, Abner" <abner.chang@amd.com>
To: Nickle Wang <nicklew@nvidia.com>,
	"devel@edk2.groups.io" <devel@edk2.groups.io>
Cc: Igor Kulchytskyy <igork@ami.com>
Subject: Re: [edk2-redfish-client][PATCH 7/8] RedfishClientPkg: RedfishLib
Date: Fri, 5 May 2023 01:15:58 +0000	[thread overview]
Message-ID: <MN2PR12MB39664E43693B46F2524DE852EA729@MN2PR12MB3966.namprd12.prod.outlook.com> (raw)
In-Reply-To: <20230504142829.19305-1-nicklew@nvidia.com>

[AMD Official Use Only - General]

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

> -----Original Message-----
> From: Nickle Wang <nicklew@nvidia.com>
> Sent: Thursday, May 4, 2023 10:28 PM
> To: devel@edk2.groups.io
> Cc: Chang, Abner <Abner.Chang@amd.com>; Igor Kulchytskyy
> <igork@ami.com>
> Subject: [edk2-redfish-client][PATCH 7/8] RedfishClientPkg: RedfishLib
> 
> Caution: This message originated from an External Source. Use proper
> caution when opening attachments, clicking links, or responding.
> 
> 
> (This one is the same as RedfishLib under RedfishPkg.
> The one under RedfishPkg will be removed because
> RedfishLib is used by EDKII feature drivers which is belong
> to EDK2 Redfish client implementation)
> 
> EDK2 port of DMTF libredfish project. We clone the necessary files
> from open source project libredfish (https://github.com/DMTF/
> libredfish) tag v1.0.0 and revise it to incorporate with edk2
> firmware code base.
> 
> The reason of cloning the necessary files instead of using extern
> submodule of libredfish project:
> libredfish as a C library which is executed under Windows and
> Linux. It could be binded with other programming languages such as
> java and python. The library uses curl library as the communication
> service with Redfish, which is not easy to be abstracted and
> replaced with EFI specific protocols (e.g. EFI_REST_EX_PROTOCOL or
> payload encode/decode library) and EFI data types. We had the
> conversation with DMTF community and they think edk2 is a firmware
> solution but not the programming language,
> therefore they rejected to have edk2 as a binding to libredfish.
> According to above, we decide to clone the necessary files from
> libredfish modify it to incorporate with edk2.
> 
> Signed-off-by: Nickle Wang <nicklew@nvidia.com>
> Cc: Abner Chang <abner.chang@amd.com>
> Cc: Igor Kulchytskyy <igork@ami.com>
> ---
>  RedfishClientPkg/RedfishClientPkg.dec         |    5 +
>  RedfishClientPkg/RedfishClientLibs.dsc.inc    |    4 +
>  RedfishClientPkg/RedfishClientPkg.dsc         |    1 +
>  .../PrivateLibrary/RedfishLib/RedfishLib.inf  |   62 +
>  .../PrivateLibrary/RedfishLib/RedfishMisc.h   |   82 +
>  .../edk2libredfish/include/redfish.h          |   25 +
>  .../edk2libredfish/include/redfishPayload.h   |  106 ++
>  .../edk2libredfish/include/redfishService.h   |  151 ++
>  .../edk2libredfish/include/redpath.h          |   49 +
>  .../PrivateLibrary/RedfishLib/RedfishLib.c    | 1033 +++++++++++
>  .../PrivateLibrary/RedfishLib/RedfishMisc.c   |  206 +++
>  .../RedfishLib/edk2libredfish/src/payload.c   |  812 +++++++++
>  .../RedfishLib/edk2libredfish/src/redpath.c   |  224 +++
>  .../RedfishLib/edk2libredfish/src/service.c   | 1523 +++++++++++++++++
>  14 files changed, 4283 insertions(+)
>  create mode 100644
> RedfishClientPkg/PrivateLibrary/RedfishLib/RedfishLib.inf
>  create mode 100644
> RedfishClientPkg/PrivateLibrary/RedfishLib/RedfishMisc.h
>  create mode 100644
> RedfishClientPkg/PrivateLibrary/RedfishLib/edk2libredfish/include/redfish.h
>  create mode 100644
> RedfishClientPkg/PrivateLibrary/RedfishLib/edk2libredfish/include/redfishPa
> yload.h
>  create mode 100644
> RedfishClientPkg/PrivateLibrary/RedfishLib/edk2libredfish/include/redfishSe
> rvice.h
>  create mode 100644
> RedfishClientPkg/PrivateLibrary/RedfishLib/edk2libredfish/include/redpath.
> h
>  create mode 100644 RedfishClientPkg/PrivateLibrary/RedfishLib/RedfishLib.c
>  create mode 100644
> RedfishClientPkg/PrivateLibrary/RedfishLib/RedfishMisc.c
>  create mode 100644
> RedfishClientPkg/PrivateLibrary/RedfishLib/edk2libredfish/src/payload.c
>  create mode 100644
> RedfishClientPkg/PrivateLibrary/RedfishLib/edk2libredfish/src/redpath.c
>  create mode 100644
> RedfishClientPkg/PrivateLibrary/RedfishLib/edk2libredfish/src/service.c
> 
> diff --git a/RedfishClientPkg/RedfishClientPkg.dec
> b/RedfishClientPkg/RedfishClientPkg.dec
> index b965f915..09df062d 100644
> --- a/RedfishClientPkg/RedfishClientPkg.dec
> +++ b/RedfishClientPkg/RedfishClientPkg.dec
> @@ -22,6 +22,11 @@
>  [LibraryClasses]
>    RedfishFeatureUtilityLib|Include/Library/RedfishFeatureUtilityLib.h
> 
> +[LibraryClasses.Common.Private]
> +  ##  @libraryclass Redfish Helper Library
> +  #   Library provides Redfish helper functions.
> +  RedfishLib|PrivateInclude/Library/RedfishLib.h
> +
>  [Protocols]
>    ## Include/Protocol/EdkIIRedfishFeature.h
>    gEdkIIRedfishFeatureProtocolGuid        = { 0x785CC694, 0x4930, 0xEFBF,
> { 0x2A, 0xCB, 0xA4, 0xB6, 0xA1, 0xCC, 0xAA, 0x34 } }
> diff --git a/RedfishClientPkg/RedfishClientLibs.dsc.inc
> b/RedfishClientPkg/RedfishClientLibs.dsc.inc
> index a5ae73ca..4655dd70 100644
> --- a/RedfishClientPkg/RedfishClientLibs.dsc.inc
> +++ b/RedfishClientPkg/RedfishClientLibs.dsc.inc
> @@ -14,6 +14,10 @@
>   !include RedfishClientPkg/RedfishJsonStructureLib.dsc.inc
>  !endif
> 
> +  NetLib|NetworkPkg/Library/DxeNetLib/DxeNetLib.inf
> +  HttpLib|NetworkPkg/Library/DxeHttpLib/DxeHttpLib.inf
> +  RedfishLib|RedfishClientPkg/PrivateLibrary/RedfishLib/RedfishLib.inf
> 
> RedfishFeatureUtilityLib|RedfishClientPkg/Library/RedfishFeatureUtilityLib/
> RedfishFeatureUtilityLib.inf
> 
> RedfishPlatformConfigLib|RedfishPkg/Library/RedfishPlatformConfigLib/Red
> fishPlatformConfigLib.inf
> +
> RedfishContentCodingLib|RedfishPkg/Library/RedfishContentCodingLibNull/
> RedfishContentCodingLibNull.inf
> 
> diff --git a/RedfishClientPkg/RedfishClientPkg.dsc
> b/RedfishClientPkg/RedfishClientPkg.dsc
> index 00a963ea..2b2149cc 100644
> --- a/RedfishClientPkg/RedfishClientPkg.dsc
> +++ b/RedfishClientPkg/RedfishClientPkg.dsc
> @@ -48,5 +48,6 @@
>  [Components]
> 
> 
> RedfishClientPkg/Library/RedfishFeatureUtilityLib/RedfishFeatureUtilityLib.i
> nf
> +  RedfishClientPkg/PrivateLibrary/RedfishLib/RedfishLib.inf
> 
>    !include RedfishClientPkg/RedfishClient.dsc.inc
> diff --git a/RedfishClientPkg/PrivateLibrary/RedfishLib/RedfishLib.inf
> b/RedfishClientPkg/PrivateLibrary/RedfishLib/RedfishLib.inf
> new file mode 100644
> index 00000000..a54e397d
> --- /dev/null
> +++ b/RedfishClientPkg/PrivateLibrary/RedfishLib/RedfishLib.inf
> @@ -0,0 +1,62 @@
> +## @file
> +#  RedfishLib Library implementation.
> +#
> +#  Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
> +#  (C) Copyright 2021 Hewlett Packard Enterprise Development LP<BR>
> +#
> +#    SPDX-License-Identifier: BSD-2-Clause-Patent
> +#
> +##
> +
> +[Defines]
> +  INF_VERSION                    = 0x0001001b
> +  BASE_NAME                      = DxeRedfishLib
> +  FILE_GUID                      = 9C2CA9CF-4F79-11E8-A7D1-8CDCD426C973
> +  MODULE_TYPE                    = DXE_DRIVER
> +  VERSION_STRING                 = 1.0
> +  LIBRARY_CLASS                  = RedfishLib| DXE_DRIVER UEFI_APPLICATION
> UEFI_DRIVER
> +
> +#
> +#  VALID_ARCHITECTURES           = IA32 X64 ARM AARCH64 RISCV64
> +#
> +
> +[Sources]
> +  edk2libredfish/src/redpath.c
> +  edk2libredfish/src/service.c
> +  edk2libredfish/src/payload.c
> +  edk2libredfish/include/redfish.h
> +  edk2libredfish/include/redfishPayload.h
> +  edk2libredfish/include/redfishService.h
> +  edk2libredfish/include/redpath.h
> +  RedfishLib.c
> +  RedfishMisc.h
> +  RedfishMisc.c
> +
> +[Packages]
> +  MdePkg/MdePkg.dec
> +  MdeModulePkg/MdeModulePkg.dec
> +  NetworkPkg/NetworkPkg.dec
> +  RedfishPkg/RedfishPkg.dec
> +  RedfishClientPkg/RedfishClientPkg.dec
> +
> +[LibraryClasses]
> +  BaseLib
> +  BaseMemoryLib
> +  DebugLib
> +  JsonLib
> +  HttpLib
> +  MemoryAllocationLib
> +  NetLib
> +  RedfishContentCodingLib
> +  RedfishCrtLib
> +  UefiBootServicesTableLib
> +  UefiLib
> +
> +[Protocols]
> +  gEfiRestExServiceBindingProtocolGuid  ## Consumed
> +  gEfiRestExProtocolGuid                ## Consumed
> +  gEdkIIRedfishCredentialProtocolGuid   ## Consumed
> +
> +[BuildOptions]
> +  MSFT:*_*_*_CC_FLAGS = /U_WIN32 /UWIN64 /U_MSC_VER
> +  GCC:*_*_*_CC_FLAGS = -Wno-unused-function -Wno-unused-but-set-
> variable
> diff --git a/RedfishClientPkg/PrivateLibrary/RedfishLib/RedfishMisc.h
> b/RedfishClientPkg/PrivateLibrary/RedfishLib/RedfishMisc.h
> new file mode 100644
> index 00000000..3b066c11
> --- /dev/null
> +++ b/RedfishClientPkg/PrivateLibrary/RedfishLib/RedfishMisc.h
> @@ -0,0 +1,82 @@
> +/** @file
> +  Internal Functions for RedfishLib.
> +
> +  Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
> +  (C) Copyright 2021 Hewlett Packard Enterprise Development LP<BR>
> +
> +  SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +#ifndef DXE_REDFISH_MISC_LIB_H_
> +#define DXE_REDFISH_MISC_LIB_H_
> +
> +#include <Library/BaseLib.h>
> +#include <Library/BaseMemoryLib.h>
> +#include <Library/DebugLib.h>
> +#include <Library/JsonLib.h>
> +#include <Library/MemoryAllocationLib.h>
> +#include <Library/PrintLib.h>
> +#include <Library/RedfishLib.h>
> +#include <Library/UefiLib.h>
> +#include <Protocol/EdkIIRedfishCredential.h>
> +#include <redfish.h>
> +
> +#define ARRAY_SIZE(Array)  (sizeof (Array) / sizeof ((Array)[0]))
> +
> +/**
> +  Creates a REDFISH_SERVICE which can be later used to access the Redfish
> resources.
> +
> +  This function will configure REST EX child according to parameters
> described in
> +  Redfish network host interface in SMBIOS type 42 record. The service
> enumerator will also
> +  handle the authentication flow automatically if HTTP basic auth or Redfish
> session
> +  login is configured to use.
> +
> +  @param[in]  RedfishConfigServiceInfo Redfish service information the EFI
> Redfish
> +                                       feature driver communicates with.
> +  @param[in]  AuthMethod   None, HTTP basic auth, or Redfish session login.
> +  @param[in]  UserId       User Name used for authentication.
> +  @param[in]  Password     Password used for authentication.
> +
> +  @return     New created Redfish service, or NULL if error happens.
> +
> +**/
> +REDFISH_SERVICE
> +RedfishCreateLibredfishService (
> +  IN REDFISH_CONFIG_SERVICE_INFORMATION  *RedfishConfigServiceInfo,
> +  IN EDKII_REDFISH_AUTH_METHOD           AuthMethod,
> +  IN CHAR8                               *UserId,
> +  IN CHAR8                               *Password
> +  );
> +
> +/**
> +  Retrieve platform's Redfish authentication information.
> +
> +  This functions returns the Redfish authentication method together with
> the user
> +  Id and password.
> +  For AuthMethodNone, UserId and Password will point to NULL which
> means authentication
> +  is not required to access the Redfish service.
> +  For AuthMethodHttpBasic, the UserId and Password could be used for
> +  HTTP header authentication as defined by RFC7235. For
> AuthMethodRedfishSession,
> +  the UserId and Password could be used for Redfish session login as
> defined by
> +  Redfish API specification (DSP0266).
> +
> +  Callers are responsible for freeing the returned string storage pointed by
> UserId
> +  and Password.
> +
> +  @param[out]  AuthMethod          Type of Redfish authentication method.
> +  @param[out]  UserId              The pointer to store the returned UserId
> string.
> +  @param[out]  Password            The pointer to store the returned Password
> string.
> +
> +  @retval EFI_SUCCESS              Get the authentication information
> successfully.
> +  @retval EFI_INVALID_PARAMETER    AuthMethod or UserId or Password is
> NULL.
> +  @retval EFI_UNSUPPORTED          Unsupported authentication method is
> found.
> +**/
> +EFI_STATUS
> +RedfishGetAuthInfo (
> +  OUT  EDKII_REDFISH_AUTH_METHOD  *AuthMethod,
> +  OUT  CHAR8                      **UserId,
> +  OUT  CHAR8                      **Password
> +  );
> +
> +#endif
> diff --git
> a/RedfishClientPkg/PrivateLibrary/RedfishLib/edk2libredfish/include/redfish
> .h
> b/RedfishClientPkg/PrivateLibrary/RedfishLib/edk2libredfish/include/redfish
> .h
> new file mode 100644
> index 00000000..e9b9b3fa
> --- /dev/null
> +++
> b/RedfishClientPkg/PrivateLibrary/RedfishLib/edk2libredfish/include/redfish
> .h
> @@ -0,0 +1,25 @@
> +/** @file
> +  This file is cloned from DMTF libredfish library tag v1.0.0 and maintained
> +  by EDKII.
> +
> +//----------------------------------------------------------------------------
> +// Copyright Notice:
> +// Copyright 2017 Distributed Management Task Force, Inc. All rights
> reserved.
> +// License: BSD 3-Clause License. For full text see link:
> https://github.com/DMTF/libredfish/LICENSE.md
> +//----------------------------------------------------------------------------
> +
> +  Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
> +  (C) Copyright 2021 Hewlett Packard Enterprise Development LP<BR>
> +
> +  SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +#ifndef LIBREDFISH_REDFISH_H_
> +#define LIBREDFISH_REDFISH_H_
> +
> +#include <redfishService.h>
> +#include <redfishPayload.h>
> +#include <redpath.h>
> +
> +#endif
> diff --git
> a/RedfishClientPkg/PrivateLibrary/RedfishLib/edk2libredfish/include/redfish
> Payload.h
> b/RedfishClientPkg/PrivateLibrary/RedfishLib/edk2libredfish/include/redfish
> Payload.h
> new file mode 100644
> index 00000000..44515306
> --- /dev/null
> +++
> b/RedfishClientPkg/PrivateLibrary/RedfishLib/edk2libredfish/include/redfish
> Payload.h
> @@ -0,0 +1,106 @@
> +/** @file
> +  This file is cloned from DMTF libredfish library tag v1.0.0 and maintained
> +  by EDKII.
> +
> +//----------------------------------------------------------------------------
> +// Copyright Notice:
> +// Copyright 2017 Distributed Management Task Force, Inc. All rights
> reserved.
> +// License: BSD 3-Clause License. For full text see link:
> https://github.com/DMTF/libredfish/LICENSE.md
> +//----------------------------------------------------------------------------
> +
> +  Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
> +  (C) Copyright 2021 Hewlett Packard Enterprise Development LP<BR>
> +
> +  SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +#ifndef LIBREDFISH_REDFISH_PAYLOAD_H_
> +#define LIBREDFISH_REDFISH_PAYLOAD_H_
> +
> +#include <Include/Library/RedfishCrtLib.h>
> +
> +#include <jansson.h>
> +#include <redfishService.h>
> +#include <redpath.h>
> +
> +redfishPayload *
> +createRedfishPayload (
> +  json_t          *value,
> +  redfishService  *service
> +  );
> +
> +redfishPayload *
> +getPayloadByNodeName (
> +  redfishPayload        *payload,
> +  const char            *nodeName,
> +  EFI_HTTP_STATUS_CODE  **StatusCode
> +  );
> +
> +redfishPayload *
> +getPayloadByIndex (
> +  redfishPayload        *payload,
> +  size_t                index,
> +  EFI_HTTP_STATUS_CODE  **StatusCode
> +  );
> +
> +redfishPayload *
> +getPayloadForPath (
> +  redfishPayload        *payload,
> +  redPathNode           *redpath,
> +  EFI_HTTP_STATUS_CODE  **StatusCode
> +  );
> +
> +redfishPayload *
> +getPayloadForPathString (
> +  redfishPayload        *payload,
> +  const char            *string,
> +  EFI_HTTP_STATUS_CODE  **StatusCode
> +  );
> +
> +redfishPayload *
> +patchPayload (
> +  redfishPayload        *target,
> +  redfishPayload        *payload,
> +  EFI_HTTP_STATUS_CODE  **StatusCode
> +  );
> +
> +redfishPayload *
> +postContentToPayload (
> +  redfishPayload        *target,
> +  const char            *data,
> +  size_t                dataSize,
> +  const char            *contentType,
> +  EFI_HTTP_STATUS_CODE  **StatusCode
> +  );
> +
> +redfishPayload *
> +postPayload (
> +  redfishPayload        *target,
> +  redfishPayload        *payload,
> +  EFI_HTTP_STATUS_CODE  **StatusCode
> +  );
> +
> +void
> +cleanupPayload (
> +  redfishPayload  *payload
> +  );
> +
> +bool
> +isPayloadCollection (
> +  redfishPayload  *Payload
> +  );
> +
> +size_t
> +getCollectionSize (
> +  redfishPayload  *payload
> +  );
> +
> +redfishPayload *
> +getPayloadByIndex (
> +  redfishPayload        *payload,
> +  size_t                index,
> +  EFI_HTTP_STATUS_CODE  **StatusCode
> +  );
> +
> +#endif
> diff --git
> a/RedfishClientPkg/PrivateLibrary/RedfishLib/edk2libredfish/include/redfish
> Service.h
> b/RedfishClientPkg/PrivateLibrary/RedfishLib/edk2libredfish/include/redfish
> Service.h
> new file mode 100644
> index 00000000..5c13b682
> --- /dev/null
> +++
> b/RedfishClientPkg/PrivateLibrary/RedfishLib/edk2libredfish/include/redfish
> Service.h
> @@ -0,0 +1,151 @@
> +/** @file
> +  This file is cloned from DMTF libredfish library tag v1.0.0 and maintained
> +  by EDKII.
> +
> +//----------------------------------------------------------------------------
> +// Copyright Notice:
> +// Copyright 2017 Distributed Management Task Force, Inc. All rights
> reserved.
> +// License: BSD 3-Clause License. For full text see link:
> https://github.com/DMTF/libredfish/LICENSE.md
> +//----------------------------------------------------------------------------
> +
> +  Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
> +  (C) Copyright 2021 Hewlett Packard Enterprise Development LP<BR>
> +
> +  SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +#ifndef LIBREDFISH_REDFISH_SERVICE_H_
> +#define LIBREDFISH_REDFISH_SERVICE_H_
> +
> +#include <IndustryStandard/Http11.h>
> +
> +#include <Library/BaseLib.h>
> +#include <Library/BaseMemoryLib.h>
> +#include <Library/DebugLib.h>
> +#include <Library/HttpLib.h>
> +#include <Library/MemoryAllocationLib.h>
> +#include <Library/NetLib.h>
> +#include <Library/RedfishContentCodingLib.h>
> +#include <Library/UefiRuntimeServicesTableLib.h>
> +#include <Library/UefiBootServicesTableLib.h>
> +
> +#include <Include/Library/RedfishCrtLib.h>
> +
> +#include <Protocol/EdkIIRedfishConfigHandler.h>
> +#include <Protocol/RestEx.h>
> +
> +#include <jansson.h>
> +
> +typedef struct {
> +  char                    *host;
> +  json_t                  *versions;
> +  unsigned int            flags;
> +  char                    *sessionToken;
> +  char                    *basicAuthStr;
> +  //
> +  // point to the <HOST> part in above "host" field, which will be put into
> +  // the "Host" header of HTTP request message.
> +  //
> +  char                    *HostHeaderValue;
> +  EFI_REST_EX_PROTOCOL    *RestEx;
> +} redfishService;
> +
> +typedef struct {
> +  json_t            *json;
> +  redfishService    *service;
> +} redfishPayload;
> +
> +#define REDFISH_AUTH_BASIC         0
> +#define REDFISH_AUTH_BEARER_TOKEN  1
> +#define REDFISH_AUTH_SESSION       2
> +
> +#define REDFISH_HTTP_RESPONSE_TIMEOUT  5000       /// 5 seconds in uints
> of millisecond.
> +
> +///
> +/// Library class public defines
> +///
> +#define HTTP_FLAG   L"http://"
> +#define HTTPS_FLAG  L"https://"
> +
> +///
> +/// The redfish first URL should be "/redfish/v1/", while we use
> "/redfish/v1" here without "/"
> +/// in the end is to avoid the 301 Perment redirect response from Redfish
> profile simulator.
> +///
> +#define REDFISH_FIRST_URL  L"/redfish/v1"
> +
> +typedef struct {
> +  unsigned int    authType;
> +  union {
> +    struct {
> +      char    *username;
> +      char    *password;
> +    } userPass;
> +    struct {
> +      char    *token;
> +    } authToken;
> +  } authCodes;
> +} enumeratorAuthentication;
> +
> +// Values for flags
> +#define REDFISH_FLAG_SERVICE_NO_VERSION_DOC  0x00000001// The
> Redfish Service lacks the version document (in violation of the Redfish spec)
> +redfishService *
> +createServiceEnumerator (
> +  REDFISH_CONFIG_SERVICE_INFORMATION  *RedfishConfigServiceInfo,
> +  const char                          *rootUri,
> +  enumeratorAuthentication            *auth,
> +  unsigned int                        flags
> +  );
> +
> +json_t *
> +getUriFromService (
> +  redfishService        *service,
> +  const char            *uri,
> +  EFI_HTTP_STATUS_CODE  **StatusCode
> +  );
> +
> +json_t *
> +patchUriFromService (
> +  redfishService        *service,
> +  const char            *uri,
> +  const char            *content,
> +  EFI_HTTP_STATUS_CODE  **StatusCode
> +  );
> +
> +json_t *
> +postUriFromService (
> +  redfishService        *service,
> +  const char            *uri,
> +  const char            *content,
> +  size_t                contentLength,
> +  const char            *contentType,
> +  EFI_HTTP_STATUS_CODE  **StatusCode
> +  );
> +
> +json_t *
> +deleteUriFromService (
> +  redfishService        *service,
> +  const char            *uri,
> +  EFI_HTTP_STATUS_CODE  **StatusCode
> +  );
> +
> +redfishPayload *
> +getRedfishServiceRoot (
> +  redfishService        *service,
> +  const char            *version,
> +  EFI_HTTP_STATUS_CODE  **StatusCode
> +  );
> +
> +redfishPayload *
> +getPayloadByPath (
> +  redfishService        *service,
> +  const char            *path,
> +  EFI_HTTP_STATUS_CODE  **StatusCode
> +  );
> +
> +void
> +cleanupServiceEnumerator (
> +  redfishService  *service
> +  );
> +
> +#endif
> diff --git
> a/RedfishClientPkg/PrivateLibrary/RedfishLib/edk2libredfish/include/redpat
> h.h
> b/RedfishClientPkg/PrivateLibrary/RedfishLib/edk2libredfish/include/redpat
> h.h
> new file mode 100644
> index 00000000..c1a1568b
> --- /dev/null
> +++
> b/RedfishClientPkg/PrivateLibrary/RedfishLib/edk2libredfish/include/redpat
> h.h
> @@ -0,0 +1,49 @@
> +/** @file
> +  This file is cloned from DMTF libredfish library tag v1.0.0 and maintained
> +  by EDKII.
> +
> +//----------------------------------------------------------------------------
> +// Copyright Notice:
> +// Copyright 2017 Distributed Management Task Force, Inc. All rights
> reserved.
> +// License: BSD 3-Clause License. For full text see link:
> https://github.com/DMTF/libredfish/LICENSE.md
> +//----------------------------------------------------------------------------
> +
> +  Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
> +  (C) Copyright 2021 Hewlett Packard Enterprise Development LP<BR>
> +
> +  SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +#ifndef LIBREDFISH_REDPATH_H_
> +#define LIBREDFISH_REDPATH_H_
> +
> +#include <Include/Library/RedfishCrtLib.h>
> +
> +#include <jansson.h>
> +
> +typedef struct _redPathNode {
> +  bool                   isRoot;
> +  bool                   isIndex;
> +
> +  char                   *version;
> +  char                   *nodeName;
> +  size_t                 index;
> +  char                   *op;
> +  char                   *propName;
> +  char                   *value;
> +
> +  struct _redPathNode    *next;
> +} redPathNode;
> +
> +redPathNode *
> +parseRedPath (
> +  const char  *path
> +  );
> +
> +void
> +cleanupRedPath (
> +  redPathNode  *node
> +  );
> +
> +#endif
> diff --git a/RedfishClientPkg/PrivateLibrary/RedfishLib/RedfishLib.c
> b/RedfishClientPkg/PrivateLibrary/RedfishLib/RedfishLib.c
> new file mode 100644
> index 00000000..9f9d3779
> --- /dev/null
> +++ b/RedfishClientPkg/PrivateLibrary/RedfishLib/RedfishLib.c
> @@ -0,0 +1,1033 @@
> +/** @file
> +  Provides a set of utility APIs that allow to create/read/update/delete
> +  (CRUD) Redfish resources and provide basic query.
> +
> +  Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
> +  (C) Copyright 2021 Hewlett Packard Enterprise Development LP<BR>
> +
> +  SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +#include "RedfishMisc.h"
> +
> +/**
> +  This function uses REST EX protocol provided in RedfishConfigServiceInfo.
> +  The service enumerator will also handle the authentication flow
> automatically
> +  if HTTP basic auth or Redfish session login is configured to use.
> +
> +  Callers are responsible for freeing the returned service by
> RedfishCleanupService().
> +
> +  @param[in]  RedfishConfigServiceInfo Redfish service information the EFI
> Redfish
> +                                       feature driver communicates with.
> +
> +  @return     New created Redfish Service, or NULL if error happens.
> +
> +**/
> +REDFISH_SERVICE
> +EFIAPI
> +RedfishCreateService (
> +  IN  REDFISH_CONFIG_SERVICE_INFORMATION  *RedfishConfigServiceInfo
> +  )
> +{
> +  REDFISH_SERVICE            RedfishService;
> +  EDKII_REDFISH_AUTH_METHOD  AuthMethod;
> +  CHAR8                      *UserId;
> +  CHAR8                      *Password;
> +  EFI_STATUS                 Status;
> +
> +  RedfishService = NULL;
> +  UserId         = NULL;
> +  Password       = NULL;
> +
> +  //
> +  // Check Input Parameters.
> +  //
> +  if (RedfishConfigServiceInfo == NULL) {
> +    return NULL;
> +  }
> +
> +  //
> +  // Get Authentication Configuration.
> +  //
> +  Status = RedfishGetAuthInfo (&AuthMethod, &UserId, &Password);
> +  if (EFI_ERROR (Status)) {
> +    goto ON_EXIT;
> +  }
> +
> +  //
> +  // Create a redfish service node based on Redfish network host interface.
> +  //
> +  RedfishService = RedfishCreateLibredfishService (
> +                     RedfishConfigServiceInfo,
> +                     AuthMethod,
> +                     UserId,
> +                     Password
> +                     );
> +
> +ON_EXIT:
> +  if (UserId != NULL) {
> +    FreePool (UserId);
> +  }
> +
> +  if (Password != NULL) {
> +    FreePool (Password);
> +  }
> +
> +  return RedfishService;
> +}
> +
> +/**
> +  Free the Service and all its related resources.
> +
> +  @param[in]    RedfishService     The Service to access the Redfish resources.
> +
> +**/
> +VOID
> +EFIAPI
> +RedfishCleanupService (
> +  IN REDFISH_SERVICE  RedfishService
> +  )
> +{
> +  if (RedfishService == NULL) {
> +    return;
> +  }
> +
> +  cleanupServiceEnumerator (RedfishService);
> +}
> +
> +/**
> +  Create REDFISH_PAYLOAD instance in local with JSON represented
> resource value and
> +  the Redfish Service.
> +
> +  The returned REDFISH_PAYLOAD can be used to create or update Redfish
> resource in
> +  server side.
> +
> +  Callers are responsible for freeing the returned payload by
> RedfishCleanupPayload().
> +
> +  @param[in]    Value                 JSON Value of the redfish resource.
> +  @param[in]    RedfishService        The Service to access the Redfish
> resources.
> +
> +  @return     REDFISH_PAYLOAD instance of the resource, or NULL if error
> happens.
> +
> +**/
> +REDFISH_PAYLOAD
> +EFIAPI
> +RedfishCreatePayload (
> +  IN EDKII_JSON_VALUE  Value,
> +  IN REDFISH_SERVICE   RedfishService
> +  )
> +{
> +  EDKII_JSON_VALUE  CopyValue;
> +
> +  CopyValue = JsonValueClone (Value);
> +  return createRedfishPayload (CopyValue, RedfishService);
> +}
> +
> +/**
> +  Free the RedfishPayload and all its related resources.
> +
> +  @param[in]    Payload        Payload to be freed.
> +
> +**/
> +VOID
> +EFIAPI
> +RedfishCleanupPayload (
> +  IN REDFISH_PAYLOAD  Payload
> +  )
> +{
> +  if (Payload == NULL) {
> +    return;
> +  }
> +
> +  cleanupPayload ((redfishPayload *)Payload);
> +}
> +
> +/**
> +  This function returns the decoded JSON value of a REDFISH_PAYLOAD.
> +
> +  Caller doesn't need to free the returned JSON value because it will be
> released
> +  in corresponding RedfishCleanupPayload() function.
> +
> +  @param[in]    Payload     A REDFISH_PAYLOAD instance.
> +
> +  @return     Decoded JSON value of the payload.
> +
> +**/
> +EDKII_JSON_VALUE
> +EFIAPI
> +RedfishJsonInPayload (
> +  IN REDFISH_PAYLOAD  Payload
> +  )
> +{
> +  if (Payload == NULL) {
> +    return NULL;
> +  }
> +
> +  return ((redfishPayload *)Payload)->json;
> +}
> +
> +/**
> +  Fill the input RedPath string with system UUID from SMBIOS table or use
> the customized
> +  ID if  FromSmbios == FALSE.
> +
> +  This is a helper function to build a RedPath string which can be used to
> address
> +  a Redfish resource for this computer system. The input PathString must
> have a Systems
> +  note in format of "Systems[UUID=%g]" or "Systems[UUID~%g]" to fill the
> UUID value.
> +
> +  Example:
> +    Use "/v1/Systems[UUID=%g]/Bios" to build a RedPath to address the
> "Bios" resource
> +    for this computer system.
> +
> +  @param[in]    RedPath        RedPath format to be build.
> +  @param[in]    FromSmbios     Get system UUID from SMBIOS as computer
> system instance ID.
> +  @param[in]    IdString       The computer system instance ID.
> +
> +  @return     Full RedPath with system UUID inside, or NULL if error happens.
> +
> +**/
> +CHAR8 *
> +EFIAPI
> +RedfishBuildPathWithSystemUuid (
> +  IN CONST CHAR8  *RedPath,
> +  IN BOOLEAN      FromSmbios,
> +  IN CHAR8        *IdString OPTIONAL
> +  )
> +{
> +  UINTN       BufSize;
> +  CHAR8       *RetRedPath;
> +  EFI_GUID    SystemUuid;
> +  EFI_STATUS  Status;
> +
> +  if (RedPath == NULL) {
> +    return NULL;
> +  }
> +
> +  //
> +  // Find system UUID from SMBIOS table.
> +  //
> +  if (FromSmbios) {
> +    Status = NetLibGetSystemGuid (&SystemUuid);
> +    if (EFI_ERROR (Status)) {
> +      return NULL;
> +    }
> +
> +    // AsciiStrLen ("xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx") = 36
> +    BufSize = AsciiStrSize (RedPath) + AsciiStrLen ("XXXXXXXX-XXXX-XXXX-
> XXXX-XXXXXXXXXXXX");
> +  } else {
> +    BufSize = AsciiStrSize (RedPath) + AsciiStrLen (IdString);
> +  }
> +
> +  RetRedPath = AllocateZeroPool (BufSize);
> +  if (RetRedPath == NULL) {
> +    return NULL;
> +  }
> +
> +  if (FromSmbios) {
> +    AsciiSPrint (RetRedPath, BufSize, RedPath, &SystemUuid);
> +  } else {
> +    AsciiSPrint (RetRedPath, BufSize, RedPath, IdString);
> +  }
> +
> +  return RetRedPath;
> +}
> +
> +/**
> +  Get a redfish response addressed by a RedPath string, including HTTP
> StatusCode, Headers
> +  and Payload which record any HTTP response messages.
> +
> +  Callers are responsible for freeing the HTTP StatusCode, Headers and
> Payload returned in
> +  redfish response data.
> +
> +  @param[in]    RedfishService        The Service to access the Redfish
> resources.
> +  @param[in]    RedPath               RedPath string to address a resource, must
> start
> +                                      from the root node.
> +  @param[out]   RedResponse           Pointer to the Redfish response data.
> +
> +  @retval EFI_SUCCESS             The opeartion is successful, indicates the HTTP
> StatusCode is not
> +                                  NULL and the value is 2XX. The corresponding redfish
> resource has
> +                                  been returned in Payload within RedResponse.
> +  @retval EFI_INVALID_PARAMETER   RedfishService, RedPath, or
> RedResponse is NULL.
> +  @retval EFI_DEVICE_ERROR        An unexpected system or network error
> occurred. Callers can get
> +                                  more error info from returned HTTP StatusCode, Headers
> and Payload
> +                                  within RedResponse:
> +                                  1. If the returned Payload is NULL, indicates any error
> happen.
> +                                  2. If the returned StatusCode is NULL, indicates any error
> happen.
> +                                  3. If the returned StatusCode is not 2XX, indicates any error
> happen.
> +**/
> +EFI_STATUS
> +EFIAPI
> +RedfishGetByService (
> +  IN     REDFISH_SERVICE   RedfishService,
> +  IN     CONST CHAR8       *RedPath,
> +  OUT    REDFISH_RESPONSE  *RedResponse
> +  )
> +{
> +  if ((RedfishService == NULL) || (RedPath == NULL) || (RedResponse ==
> NULL)) {
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  ZeroMem (RedResponse, sizeof (REDFISH_RESPONSE));
> +
> +  RedResponse->Payload = (REDFISH_PAYLOAD)getPayloadByPath
> (RedfishService, RedPath, &(RedResponse->StatusCode));
> +
> +  //
> +  // 1. If the returned Payload is NULL, indicates any error happen.
> +  // 2. If the returned StatusCode is NULL, indicates any error happen.
> +  //
> +  if ((RedResponse->Payload == NULL) || (RedResponse->StatusCode ==
> NULL)) {
> +    return EFI_DEVICE_ERROR;
> +  }
> +
> +  //
> +  // 3. If the returned StatusCode is not 2XX, indicates any error happen.
> +  //    NOTE: If there is any error message returned from server, it will be
> returned in
> +  //          Payload within RedResponse.
> +  //
> +  if ((*(RedResponse->StatusCode) < HTTP_STATUS_200_OK) || \
> +      (*(RedResponse->StatusCode) >
> HTTP_STATUS_206_PARTIAL_CONTENT))
> +  {
> +    return EFI_DEVICE_ERROR;
> +  }
> +
> +  return EFI_SUCCESS;
> +}
> +
> +/**
> +  Get a redfish response addressed by URI, including HTTP StatusCode,
> Headers
> +  and Payload which record any HTTP response messages.
> +
> +  Callers are responsible for freeing the HTTP StatusCode, Headers and
> Payload returned in
> +  redfish response data.
> +
> +  @param[in]    RedfishService    The Service to access the URI resources.
> +  @param[in]    Uri               String to address a resource.
> +  @param[out]   RedResponse       Pointer to the Redfish response data.
> +
> +  @retval EFI_SUCCESS             The opeartion is successful, indicates the HTTP
> StatusCode is not
> +                                  NULL and the value is 2XX. The corresponding redfish
> resource has
> +                                  been returned in Payload within RedResponse.
> +  @retval EFI_INVALID_PARAMETER   RedfishService, RedPath, or
> RedResponse is NULL.
> +  @retval EFI_DEVICE_ERROR        An unexpected system or network error
> occurred. Callers can get
> +                                  more error info from returned HTTP StatusCode, Headers
> and Payload
> +                                  within RedResponse:
> +                                  1. If the returned Payload is NULL, indicates any error
> happen.
> +                                  2. If the returned StatusCode is NULL, indicates any error
> happen.
> +                                  3. If the returned StatusCode is not 2XX, indicates any error
> happen.
> +**/
> +EFI_STATUS
> +EFIAPI
> +RedfishGetByUri (
> +  IN     REDFISH_SERVICE   RedfishService,
> +  IN     CONST CHAR8       *Uri,
> +  OUT    REDFISH_RESPONSE  *RedResponse
> +  )
> +{
> +  EDKII_JSON_VALUE  JsonValue;
> +
> +  if ((RedfishService == NULL) || (Uri == NULL) || (RedResponse == NULL)) {
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  ZeroMem (RedResponse, sizeof (REDFISH_RESPONSE));
> +
> +  JsonValue            = getUriFromService (RedfishService, Uri, &RedResponse-
> >StatusCode);
> +  RedResponse->Payload = createRedfishPayload (JsonValue,
> RedfishService);
> +
> +  //
> +  // 1. If the returned Payload is NULL, indicates any error happen.
> +  // 2. If the returned StatusCode is NULL, indicates any error happen.
> +  //
> +  if ((RedResponse->Payload == NULL) || (RedResponse->StatusCode ==
> NULL)) {
> +    return EFI_DEVICE_ERROR;
> +  }
> +
> +  //
> +  // 3. If the returned StatusCode is not 2XX, indicates any error happen.
> +  //    NOTE: If there is any error message returned from server, it will be
> returned in
> +  //          Payload within RedResponse.
> +  //
> +  if ((*(RedResponse->StatusCode) < HTTP_STATUS_200_OK) || \
> +      (*(RedResponse->StatusCode) >
> HTTP_STATUS_206_PARTIAL_CONTENT))
> +  {
> +    return EFI_DEVICE_ERROR;
> +  }
> +
> +  return EFI_SUCCESS;
> +}
> +
> +/**
> +  Get a redfish response addressed by the input Payload and relative
> RedPath string,
> +  including HTTP StatusCode, Headers and Payload which record any HTTP
> response messages.
> +
> +  Callers are responsible for freeing the HTTP StatusCode, Headers and
> Payload returned in
> +  redfish response data.
> +
> +  @param[in]    Payload           A existing REDFISH_PAYLOAD instance.
> +  @param[in]    RedPath           Relative RedPath string to address a resource
> inside Payload.
> +  @param[out]   RedResponse       Pointer to the Redfish response data.
> +
> +  @retval EFI_SUCCESS             The opeartion is successful:
> +                                  1. The HTTP StatusCode is NULL and the returned Payload
> in
> +                                  RedResponse is not NULL, indicates the Redfish resource
> has
> +                                  been parsed from the input payload directly.
> +                                  2. The HTTP StatusCode is not NULL and the value is 2XX,
> +                                  indicates the corresponding redfish resource has been
> returned
> +                                  in Payload within RedResponse.
> +  @retval EFI_INVALID_PARAMETER   Payload, RedPath, or RedResponse is
> NULL.
> +  @retval EFI_DEVICE_ERROR        An unexpected system or network error
> occurred. Callers can get
> +                                  more error info from returned HTTP StatusCode, Headers
> and Payload
> +                                  within RedResponse:
> +                                  1. If the returned Payload is NULL, indicates any error
> happen.
> +                                  2. If StatusCode is not NULL and the returned value of
> StatusCode
> +                                     is not 2XX, indicates any error happen.
> +**/
> +EFI_STATUS
> +EFIAPI
> +RedfishGetByPayload (
> +  IN     REDFISH_PAYLOAD   Payload,
> +  IN     CONST CHAR8       *RedPath,
> +  OUT    REDFISH_RESPONSE  *RedResponse
> +  )
> +{
> +  if ((Payload == NULL) || (RedPath == NULL) || (RedResponse == NULL)) {
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  ZeroMem (RedResponse, sizeof (REDFISH_RESPONSE));
> +
> +  RedResponse->Payload = (REDFISH_PAYLOAD)getPayloadForPathString
> (Payload, RedPath, &(RedResponse->StatusCode));
> +
> +  //
> +  // 1. If the returned Payload is NULL, indicates any error happen.
> +  //
> +  if (RedResponse->Payload == NULL) {
> +    return EFI_DEVICE_ERROR;
> +  }
> +
> +  //
> +  // 2. If StatusCode is not NULL and the returned value of StatusCode is not
> 2XX, indicates any
> +  //    error happen.
> +  //    NOTE: If there is any error message returned from server, it will be
> returned in
> +  //          Payload within RedResponse.
> +  //
> +  if ((RedResponse->StatusCode != NULL) && \
> +      ((*(RedResponse->StatusCode) < HTTP_STATUS_200_OK) || \
> +       (*(RedResponse->StatusCode) >
> HTTP_STATUS_206_PARTIAL_CONTENT)
> +      ))
> +  {
> +    return EFI_DEVICE_ERROR;
> +  }
> +
> +  return EFI_SUCCESS;
> +}
> +
> +/**
> +  Use HTTP PATCH to perform updates on pre-existing Redfish resource.
> +
> +  This function uses the RedfishService to patch a Redfish resource
> addressed by
> +  Uri (only the relative path is required). Changes to one or more properties
> within
> +  the target resource are represented in the input Content, properties not
> specified
> +  in Content won't be changed by this request. The corresponding redfish
> response will
> +  returned, including HTTP StatusCode, Headers and Payload which record
> any HTTP response
> +  messages.
> +
> +  Callers are responsible for freeing the HTTP StatusCode, Headers and
> Payload returned in
> +  redfish response data.
> +
> +  @param[in]    RedfishService        The Service to access the Redfish
> resources.
> +  @param[in]    Uri                   Relative path to address the resource.
> +  @param[in]    Content               JSON represented properties to be update.
> +  @param[out]   RedResponse           Pointer to the Redfish response data.
> +
> +  @retval EFI_SUCCESS             The opeartion is successful, indicates the HTTP
> StatusCode is not
> +                                  NULL and the value is 2XX. The Redfish resource will be
> returned
> +                                  in Payload within RedResponse if server send it back in the
> HTTP
> +                                  response message body.
> +  @retval EFI_INVALID_PARAMETER   RedfishService, Uri, Content, or
> RedResponse is NULL.
> +  @retval EFI_DEVICE_ERROR        An unexpected system or network error
> occurred. Callers can get
> +                                  more error info from returned HTTP StatusCode, Headers
> and Payload
> +                                  within RedResponse:
> +                                  1. If the returned StatusCode is NULL, indicates any error
> happen.
> +                                  2. If the returned StatusCode is not NULL and the value is
> not 2XX,
> +                                     indicates any error happen.
> +**/
> +EFI_STATUS
> +EFIAPI
> +RedfishPatchToUri (
> +  IN     REDFISH_SERVICE   RedfishService,
> +  IN     CONST CHAR8       *Uri,
> +  IN     CONST CHAR8       *Content,
> +  OUT    REDFISH_RESPONSE  *RedResponse
> +  )
> +{
> +  EFI_STATUS        Status;
> +  EDKII_JSON_VALUE  JsonValue;
> +
> +  Status    = EFI_SUCCESS;
> +  JsonValue = NULL;
> +
> +  if ((RedfishService == NULL) || (Uri == NULL) || (Content == NULL) ||
> (RedResponse == NULL)) {
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  ZeroMem (RedResponse, sizeof (REDFISH_RESPONSE));
> +
> +  JsonValue = (EDKII_JSON_VALUE)patchUriFromService (
> +                                  RedfishService,
> +                                  Uri,
> +                                  Content,
> +                                  &(RedResponse->StatusCode)
> +                                  );
> +
> +  //
> +  // 1. If the returned StatusCode is NULL, indicates any error happen.
> +  //
> +  if (RedResponse->StatusCode == NULL) {
> +    Status = EFI_DEVICE_ERROR;
> +    goto ON_EXIT;
> +  }
> +
> +  //
> +  // 2. If the returned StatusCode is not NULL and the value is not 2XX,
> indicates any error happen.
> +  //    NOTE: If there is any error message returned from server, it will be
> returned in
> +  //          Payload within RedResponse.
> +  //
> +  if ((*(RedResponse->StatusCode) < HTTP_STATUS_200_OK) || \
> +      (*(RedResponse->StatusCode) >
> HTTP_STATUS_206_PARTIAL_CONTENT))
> +  {
> +    Status = EFI_DEVICE_ERROR;
> +  }
> +
> +ON_EXIT:
> +  if (JsonValue != NULL) {
> +    RedResponse->Payload = createRedfishPayload (JsonValue,
> RedfishService);
> +    if (RedResponse->Payload == NULL) {
> +      //
> +      // Ignore the error when create RedfishPayload, just free the JsonValue
> since it's not what
> +      // we care about if the returned StatusCode is 2XX.
> +      //
> +      JsonValueFree (JsonValue);
> +    }
> +  }
> +
> +  return Status;
> +}
> +
> +/**
> +  Use HTTP PATCH to perform updates on target payload. Patch to odata.id
> in Payload directly.
> +
> +  This function uses the Payload to patch the Target. Changes to one or
> more properties
> +  within the target resource are represented in the input Payload,
> properties not specified
> +  in Payload won't be changed by this request. The corresponding redfish
> response will
> +  returned, including HTTP StatusCode, Headers and Payload which record
> any HTTP response
> +  messages.
> +
> +  Callers are responsible for freeing the HTTP StatusCode, Headers and
> Payload returned in
> +  redfish response data.
> +
> +  @param[in]    Target           The target payload to be updated.
> +  @param[in]    Payload          Palyoad with properties to be changed.
> +  @param[out]   RedResponse      Pointer to the Redfish response data.
> +
> +  @retval EFI_SUCCESS             The opeartion is successful, indicates the HTTP
> StatusCode is not
> +                                  NULL and the value is 2XX. The Redfish resource will be
> returned
> +                                  in Payload within RedResponse if server send it back in the
> HTTP
> +                                  response message body.
> +  @retval EFI_INVALID_PARAMETER   Target, Payload, or RedResponse is
> NULL.
> +  @retval EFI_DEVICE_ERROR        An unexpected system or network error
> occurred. Callers can get
> +                                  more error info from returned HTTP StatusCode, Headers
> and Payload
> +                                  within RedResponse:
> +                                  1. If the returned StatusCode is NULL, indicates any error
> happen.
> +                                  2. If the returned StatusCode is not NULL and the value is
> not 2XX,
> +                                     indicates any error happen.
> +**/
> +EFI_STATUS
> +EFIAPI
> +RedfishPatchToPayload (
> +  IN     REDFISH_PAYLOAD   Target,
> +  IN     REDFISH_PAYLOAD   Payload,
> +  OUT    REDFISH_RESPONSE  *RedResponse
> +  )
> +{
> +  if ((Target == NULL) || (Payload == NULL) || (RedResponse == NULL)) {
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  ZeroMem (RedResponse, sizeof (REDFISH_RESPONSE));
> +
> +  RedResponse->Payload = (REDFISH_PAYLOAD)patchPayload (
> +                                            Target,
> +                                            Payload,
> +                                            &(RedResponse->StatusCode)
> +                                            );
> +
> +  //
> +  // 1. If the returned StatusCode is NULL, indicates any error happen.
> +  //
> +  if (RedResponse->StatusCode == NULL) {
> +    return EFI_DEVICE_ERROR;
> +  }
> +
> +  //
> +  // 2. If the returned StatusCode is not NULL and the value is not 2XX,
> indicates any error happen.
> +  //    NOTE: If there is any error message returned from server, it will be
> returned in
> +  //          Payload within RedResponse.
> +  //
> +  if ((*(RedResponse->StatusCode) < HTTP_STATUS_200_OK) || \
> +      (*(RedResponse->StatusCode) >
> HTTP_STATUS_206_PARTIAL_CONTENT))
> +  {
> +    return EFI_DEVICE_ERROR;
> +  }
> +
> +  return EFI_SUCCESS;
> +}
> +
> +/**
> +  Use HTTP POST to create a new resource in target payload.
> +
> +  The POST request should be submitted to the Resource Collection in which
> the new resource
> +  is to belong. The Resource Collection is addressed by Target payload. The
> Redfish may
> +  ignore any service controlled properties. The corresponding redfish
> response will returned,
> +  including HTTP StatusCode, Headers and Payload which record any HTTP
> response messages.
> +
> +  Callers are responsible for freeing the HTTP StatusCode, Headers and
> Payload returned in
> +  redfish response data.
> +
> +  @param[in]    Target          Target payload of the Resource Collection.
> +  @param[in]    Payload         The new resource to be created.
> +  @param[out]   RedResponse     Pointer to the Redfish response data.
> +
> +  @retval EFI_SUCCESS             The opeartion is successful, indicates the HTTP
> StatusCode is not
> +                                  NULL and the value is 2XX. The Redfish resource will be
> returned
> +                                  in Payload within RedResponse if server send it back in the
> HTTP
> +                                  response message body.
> +  @retval EFI_INVALID_PARAMETER   Target, Payload, or RedResponse is
> NULL.
> +  @retval EFI_DEVICE_ERROR        An unexpected system or network error
> occurred. Callers can get
> +                                  more error info from returned HTTP StatusCode, Headers
> and Payload
> +                                  within RedResponse:
> +                                  1. If the returned StatusCode is NULL, indicates any error
> happen.
> +                                  2. If the returned StatusCode is not NULL and the value is
> not 2XX,
> +                                     indicates any error happen.
> +**/
> +EFI_STATUS
> +EFIAPI
> +RedfishPostToPayload (
> +  IN     REDFISH_PAYLOAD   Target,
> +  IN     REDFISH_PAYLOAD   Payload,
> +  OUT    REDFISH_RESPONSE  *RedResponse
> +  )
> +{
> +  if ((Target == NULL) || (Payload == NULL) || (RedResponse == NULL)) {
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  ZeroMem (RedResponse, sizeof (REDFISH_RESPONSE));
> +
> +  RedResponse->Payload = (REDFISH_PAYLOAD)postPayload (
> +                                            Target,
> +                                            Payload,
> +                                            &(RedResponse->StatusCode)
> +                                            );
> +
> +  //
> +  // 1. If the returned StatusCode is NULL, indicates any error happen.
> +  //
> +  if (RedResponse->StatusCode == NULL) {
> +    return EFI_DEVICE_ERROR;
> +  }
> +
> +  //
> +  // 2. If the returned StatusCode is not NULL and the value is not 2XX,
> indicates any error happen.
> +  //    NOTE: If there is any error message returned from server, it will be
> returned in
> +  //          Payload within RedResponse.
> +  //
> +  if ((*(RedResponse->StatusCode) < HTTP_STATUS_200_OK) || \
> +      (*(RedResponse->StatusCode) >
> HTTP_STATUS_206_PARTIAL_CONTENT))
> +  {
> +    return EFI_DEVICE_ERROR;
> +  }
> +
> +  return EFI_SUCCESS;
> +}
> +
> +/**
> +  Use HTTP DELETE to remove a resource.
> +
> +  This function uses the RedfishService to remove a Redfish resource which
> is addressed
> +  by input Uri (only the relative path is required). The corresponding redfish
> response will
> +  returned, including HTTP StatusCode, Headers and Payload which record
> any HTTP response
> +  messages.
> +
> +  Callers are responsible for freeing the HTTP StatusCode, Headers and
> Payload returned in
> +  redfish response data.
> +
> +  @param[in]    RedfishService        The Service to access the Redfish
> resources.
> +  @param[in]    Uri                   Relative path to address the resource.
> +  @param[out]   RedResponse           Pointer to the Redfish response data.
> +
> +  @retval EFI_SUCCESS             The opeartion is successful, indicates the HTTP
> StatusCode is not
> +                                  NULL and the value is 2XX, the Redfish resource has been
> removed.
> +                                  If there is any message returned from server, it will be
> returned
> +                                  in Payload within RedResponse.
> +  @retval EFI_INVALID_PARAMETER   RedfishService, Uri, or RedResponse is
> NULL.
> +  @retval EFI_DEVICE_ERROR        An unexpected system or network error
> occurred. Callers can get
> +                                  more error info from returned HTTP StatusCode, Headers
> and Payload
> +                                  within RedResponse:
> +                                  1. If the returned StatusCode is NULL, indicates any error
> happen.
> +                                  2. If the returned StatusCode is not NULL and the value is
> not 2XX,
> +                                     indicates any error happen.
> +**/
> +EFI_STATUS
> +EFIAPI
> +RedfishDeleteByUri (
> +  IN     REDFISH_SERVICE   RedfishService,
> +  IN     CONST CHAR8       *Uri,
> +  OUT    REDFISH_RESPONSE  *RedResponse
> +  )
> +{
> +  EFI_STATUS        Status;
> +  EDKII_JSON_VALUE  JsonValue;
> +
> +  Status    = EFI_SUCCESS;
> +  JsonValue = NULL;
> +
> +  if ((RedfishService == NULL) || (Uri == NULL) || (RedResponse == NULL)) {
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  ZeroMem (RedResponse, sizeof (REDFISH_RESPONSE));
> +
> +  JsonValue = (EDKII_JSON_VALUE)deleteUriFromService (
> +                                  RedfishService,
> +                                  Uri,
> +                                  &(RedResponse->StatusCode)
> +                                  );
> +
> +  //
> +  // 1. If the returned StatusCode is NULL, indicates any error happen.
> +  //
> +  if (RedResponse->StatusCode == NULL) {
> +    Status = EFI_DEVICE_ERROR;
> +    goto ON_EXIT;
> +  }
> +
> +  //
> +  // 2. If the returned StatusCode is not NULL and the value is not 2XX,
> indicates any error happen.
> +  //    NOTE: If there is any error message returned from server, it will be
> returned in
> +  //          Payload within RedResponse.
> +  //
> +  if ((*(RedResponse->StatusCode) < HTTP_STATUS_200_OK) || \
> +      (*(RedResponse->StatusCode) >
> HTTP_STATUS_206_PARTIAL_CONTENT))
> +  {
> +    Status = EFI_DEVICE_ERROR;
> +  }
> +
> +ON_EXIT:
> +  if (JsonValue != NULL) {
> +    RedResponse->Payload = createRedfishPayload (JsonValue,
> RedfishService);
> +    if (RedResponse->Payload == NULL) {
> +      //
> +      // Ignore the error when create RedfishPayload, just free the JsonValue
> since it's not what
> +      // we care about if the returned StatusCode is 2XX.
> +      //
> +      JsonValueFree (JsonValue);
> +    }
> +  }
> +
> +  return Status;
> +}
> +
> +/**
> +  Dump text in fractions.
> +
> +  @param[in]  String   ASCII string to dump.
> +
> +**/
> +VOID
> +RedfishDumpJsonStringFractions (
> +  IN CHAR8  *String
> +  )
> +{
> +  CHAR8  *NextFraction;
> +  UINTN  StringFractionSize;
> +  UINTN  StrLen;
> +  UINTN  Count;
> +  CHAR8  BackupChar;
> +
> +  StringFractionSize = 200;
> +  if (String == NULL) {
> +    return;
> +  }
> +
> +  DEBUG ((DEBUG_INFO, "JSON text:\n"));
> +  NextFraction = String;
> +  StrLen       = AsciiStrLen (String);
> +  if (StrLen == 0) {
> +    return;
> +  }
> +
> +  for (Count = 0; Count < (StrLen / StringFractionSize); Count++) {
> +    BackupChar                           = *(NextFraction + StringFractionSize);
> +    *(NextFraction + StringFractionSize) = 0;
> +    DEBUG ((DEBUG_INFO, "%a", NextFraction));
> +    *(NextFraction + StringFractionSize) = BackupChar;
> +    NextFraction                        += StringFractionSize;
> +  }
> +
> +  if ((StrLen % StringFractionSize) != 0) {
> +    DEBUG ((DEBUG_INFO, "%a\n\n", NextFraction));
> +  }
> +}
> +
> +/**
> +  Dump text in JSON value.
> +
> +  @param[in]  JsonValue       The Redfish JSON value to dump.
> +
> +**/
> +VOID
> +RedfishDumpJson (
> +  IN EDKII_JSON_VALUE  JsonValue
> +  )
> +{
> +  CHAR8  *String;
> +
> +  String = JsonDumpString (JsonValue, 0);
> +  if (String == NULL) {
> +    return;
> +  }
> +
> +  RedfishDumpJsonStringFractions (String);
> +  FreePool (String);
> +}
> +
> +/**
> +  Extract the JSON text content from REDFISH_PAYLOAD and dump to debug
> console.
> +
> +  @param[in]  Payload       The Redfish payload to dump.
> +
> +**/
> +VOID
> +RedfishDumpPayload (
> +  IN REDFISH_PAYLOAD  Payload
> +  )
> +{
> +  EDKII_JSON_VALUE  JsonValue;
> +  CHAR8             *String;
> +
> +  JsonValue = NULL;
> +  String    = NULL;
> +
> +  if (Payload == NULL) {
> +    return;
> +  }
> +
> +  JsonValue = RedfishJsonInPayload (Payload);
> +  if (JsonValue == NULL) {
> +    return;
> +  }
> +
> +  String = JsonDumpString (JsonValue, 0);
> +  if (String == NULL) {
> +    return;
> +  }
> +
> +  RedfishDumpJsonStringFractions (String);
> +  FreePool (String);
> +}
> +
> +/**
> +  This function will cleanup the HTTP header and Redfish payload resources.
> +
> +  @param[in]  StatusCode        The status code in HTTP response message.
> +  @param[in]  HeaderCount       Number of HTTP header structures in
> Headers list.
> +  @param[in]  Headers           Array containing list of HTTP headers.
> +  @param[in]  Payload           The Redfish payload to dump.
> +
> +**/
> +VOID
> +RedfishFreeResponse (
> +  IN EFI_HTTP_STATUS_CODE  *StatusCode,
> +  IN UINTN                 HeaderCount,
> +  IN EFI_HTTP_HEADER       *Headers,
> +  IN REDFISH_PAYLOAD       Payload
> +  )
> +{
> +  if (StatusCode != NULL) {
> +    FreePool (StatusCode);
> +    StatusCode = NULL;
> +  }
> +
> +  if ((HeaderCount != 0) && (Headers != NULL)) {
> +    HttpFreeHeaderFields (Headers, HeaderCount);
> +    Headers = NULL;
> +  }
> +
> +  if (Payload != NULL) {
> +    RedfishCleanupPayload (Payload);
> +    Payload = NULL;
> +  }
> +}
> +
> +/**
> +  Check if the "@odata.type" in Payload is valid or not.
> +
> +  @param[in]  Payload                  The Redfish payload to be checked.
> +  @param[in]  OdataTypeName            OdataType will be retrived from
> mapping list.
> +  @param[in]  OdataTypeMappingList     The list of OdataType.
> +  @param[in]  OdataTypeMappingListSize The number of mapping list
> +
> +  @return TRUE if the "@odata.type" in Payload is valid, otherwise FALSE.
> +
> +**/
> +BOOLEAN
> +RedfishIsValidOdataType (
> +  IN REDFISH_PAYLOAD             Payload,
> +  IN CONST CHAR8                 *OdataTypeName,
> +  IN REDFISH_ODATA_TYPE_MAPPING  *OdataTypeMappingList,
> +  IN UINTN                       OdataTypeMappingListSize
> +  )
> +{
> +  UINTN             Index;
> +  EDKII_JSON_VALUE  OdataType;
> +  EDKII_JSON_VALUE  JsonValue;
> +
> +  if ((Payload == NULL) || (OdataTypeName == NULL)) {
> +    return FALSE;
> +  }
> +
> +  JsonValue = RedfishJsonInPayload (Payload);
> +  if (!JsonValueIsObject (JsonValue)) {
> +    return FALSE;
> +  }
> +
> +  OdataType = JsonObjectGetValue (JsonValueGetObject (JsonValue),
> "@odata.type");
> +  if (!JsonValueIsString (OdataType) || (JsonValueGetAsciiString (OdataType)
> == NULL)) {
> +    return FALSE;
> +  }
> +
> +  for (Index = 0; Index < OdataTypeMappingListSize; Index++) {
> +    if ((AsciiStrCmp (OdataTypeMappingList[Index].OdataTypeName,
> OdataTypeName) == 0) &&
> +        (AsciiStrCmp (OdataTypeMappingList[Index].OdataType,
> JsonValueGetAsciiString (OdataType)) == 0))
> +    {
> +      return TRUE;
> +    }
> +  }
> +
> +  DEBUG ((DEBUG_INFO, "%a: This Odata type is not in the list.\n",
> __FUNCTION__));
> +  return FALSE;
> +}
> +
> +/**
> +  Check if the payload is collection
> +
> +  @param[in]  Payload                  The Redfish payload to be checked.
> +
> +  @return TRUE if the payload is  collection.
> +
> +**/
> +BOOLEAN
> +RedfishIsPayloadCollection (
> +  IN REDFISH_PAYLOAD  Payload
> +  )
> +{
> +  return isPayloadCollection (Payload);
> +}
> +
> +/**
> +  Get collection size.
> +
> +  @param[in]  Payload         The Redfish collection payload
> +  @param[in]  CollectionSize  Size of this collection
> +
> +  @return EFI_SUCCESS              Coolection size is returned in CollectionSize
> +  @return EFI_INVALID_PARAMETER    The payload is not a collection.
> +**/
> +EFI_STATUS
> +RedfishGetCollectionSize (
> +  IN REDFISH_PAYLOAD  Payload,
> +  IN UINTN            *CollectionSize
> +  )
> +{
> +  if ((Payload == NULL) || (CollectionSize == NULL)) {
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  if (!RedfishIsPayloadCollection (Payload)) {
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  *CollectionSize = (UINTN)getCollectionSize (Payload);
> +  return EFI_SUCCESS;
> +}
> +
> +/**
> +  Get Redfish payload of collection member
> +
> +  @param[in]  Payload    The Redfish collection payload
> +  @param[in]  Index      Index of collection member
> +
> +  @return NULL           Fail to get collection member.
> +  @return Non NULL       Payload is returned.
> +**/
> +REDFISH_PAYLOAD
> +RedfishGetPayloadByIndex (
> +  IN REDFISH_PAYLOAD  Payload,
> +  IN UINTN            Index
> +  )
> +{
> +  REDFISH_RESPONSE  RedfishResponse;
> +  REDFISH_PAYLOAD   PayloadReturn;
> +
> +  PayloadReturn = (VOID *)getPayloadByIndex (Payload, Index,
> &RedfishResponse.StatusCode);
> +  if ((PayloadReturn == NULL) ||
> +      ((*(RedfishResponse.StatusCode) < HTTP_STATUS_200_OK) &&
> (*(RedfishResponse.StatusCode) > HTTP_STATUS_206_PARTIAL_CONTENT)))
> +  {
> +    return NULL;
> +  }
> +
> +  return PayloadReturn;
> +}
> +
> +/**
> +  Check and return Redfish resource of the given Redpath.
> +
> +  @param[in]  RedfishService  Pointer to REDFISH_SERVICE
> +  @param[in]  Redpath         Redpath of the resource.
> +  @param[in]  Response        Optional return the resource.
> +
> +  @return EFI_STATUS
> +**/
> +EFI_STATUS
> +RedfishCheckIfRedpathExist (
> +  IN REDFISH_SERVICE   RedfishService,
> +  IN CHAR8             *Redpath,
> +  IN REDFISH_RESPONSE  *Response OPTIONAL
> +  )
> +{
> +  EFI_STATUS        Status;
> +  REDFISH_RESPONSE  TempResponse;
> +
> +  if (Redpath == NULL) {
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  Status = RedfishGetByService (RedfishService, Redpath, &TempResponse);
> +  if (EFI_ERROR (Status)) {
> +    return Status;
> +  }
> +
> +  if (Response == NULL) {
> +    RedfishFreeResponse (
> +      TempResponse.StatusCode,
> +      TempResponse.HeaderCount,
> +      TempResponse.Headers,
> +      TempResponse.Payload
> +      );
> +  } else {
> +    CopyMem ((VOID *)Response, (VOID *)&TempResponse, sizeof
> (REDFISH_RESPONSE));
> +  }
> +
> +  return EFI_SUCCESS;
> +}
> diff --git a/RedfishClientPkg/PrivateLibrary/RedfishLib/RedfishMisc.c
> b/RedfishClientPkg/PrivateLibrary/RedfishLib/RedfishMisc.c
> new file mode 100644
> index 00000000..0eb23196
> --- /dev/null
> +++ b/RedfishClientPkg/PrivateLibrary/RedfishLib/RedfishMisc.c
> @@ -0,0 +1,206 @@
> +/** @file
> +  Internal Functions for RedfishLib.
> +
> +  Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
> +  (C) Copyright 2021 Hewlett Packard Enterprise Development LP<BR>
> +
> +  SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +#include "RedfishMisc.h"
> +
> +EDKII_REDFISH_CREDENTIAL_PROTOCOL  *mCredentialProtocol = NULL;
> +
> +/**
> +  This function returns the string of Redfish service version.
> +
> +  @param[in]   RedfishService Redfish service instance.
> +  @param[out]  ServiceVersionStr   Redfish service string.
> +
> +  @return     EFI_STATUS
> +
> +**/
> +EFI_STATUS
> +RedfishGetServiceVersion (
> +  IN  REDFISH_SERVICE  RedfishService,
> +  OUT CHAR8            **ServiceVersionStr
> +  )
> +{
> +  redfishService  *Redfish;
> +  CHAR8           **KeysArray;
> +  UINTN           KeysNum;
> +
> +  if ((RedfishService == NULL) || (ServiceVersionStr == NULL)) {
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  Redfish = (redfishService *)RedfishService;
> +  if (Redfish->versions == NULL) {
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  KeysArray = JsonObjectGetKeys (Redfish->versions, &KeysNum);
> +  if ((KeysNum == 0) || (KeysArray  == NULL)) {
> +    return EFI_NOT_FOUND;
> +  }
> +
> +  *ServiceVersionStr = *KeysArray;
> +  return EFI_SUCCESS;
> +}
> +
> +/**
> +  Creates a REDFISH_SERVICE which can be later used to access the Redfish
> resources.
> +
> +  This function will configure REST EX child according to parameters
> described in
> +  Redfish network host interface in SMBIOS type 42 record. The service
> enumerator will also
> +  handle the authentication flow automatically if HTTP basic auth or Redfish
> session
> +  login is configured to use.
> +
> +  @param[in]  RedfishConfigServiceInfo Redfish service information the EFI
> Redfish
> +                                       feature driver communicates with.
> +  @param[in]  AuthMethod   None, HTTP basic auth, or Redfish session login.
> +  @param[in]  UserId       User Name used for authentication.
> +  @param[in]  Password     Password used for authentication.
> +
> +  @return     New created Redfish service, or NULL if error happens.
> +
> +**/
> +REDFISH_SERVICE
> +RedfishCreateLibredfishService (
> +  IN  REDFISH_CONFIG_SERVICE_INFORMATION  *RedfishConfigServiceInfo,
> +  IN  EDKII_REDFISH_AUTH_METHOD           AuthMethod,
> +  IN  CHAR8                               *UserId,
> +  IN  CHAR8                               *Password
> +  )
> +{
> +  UINTN                     Flags;
> +  enumeratorAuthentication  Auth;
> +  redfishService            *Redfish;
> +
> +  Redfish = NULL;
> +
> +  ZeroMem (&Auth, sizeof (Auth));
> +  if (AuthMethod == AuthMethodHttpBasic) {
> +    Auth.authType = REDFISH_AUTH_BASIC;
> +  } else if (AuthMethod == AuthMethodRedfishSession) {
> +    Auth.authType = REDFISH_AUTH_SESSION;
> +  }
> +
> +  Auth.authCodes.userPass.username = UserId;
> +  Auth.authCodes.userPass.password = Password;
> +
> +  Flags = REDFISH_FLAG_SERVICE_NO_VERSION_DOC;
> +
> +  if (AuthMethod != AuthMethodNone) {
> +    Redfish = createServiceEnumerator (RedfishConfigServiceInfo, NULL,
> &Auth, (unsigned int)Flags);
> +  } else {
> +    Redfish = createServiceEnumerator (RedfishConfigServiceInfo, NULL,
> NULL, (unsigned int)Flags);
> +  }
> +
> +  //
> +  // Zero the Password after use.
> +  //
> +  if (Password != NULL) {
> +    ZeroMem (Password, AsciiStrLen (Password));
> +  }
> +
> +  return (REDFISH_SERVICE)Redfish;
> +}
> +
> +/**
> +  Retrieve platform's Redfish authentication information.
> +
> +  This functions returns the Redfish authentication method together with
> the user
> +  Id and password.
> +  For AuthMethodNone, UserId and Password will point to NULL which
> means authentication
> +  is not required to access the Redfish service.
> +  For AuthMethodHttpBasic, the UserId and Password could be used for
> +  HTTP header authentication as defined by RFC7235. For
> AuthMethodRedfishSession,
> +  the UserId and Password could be used for Redfish session login as
> defined by
> +  Redfish API specification (DSP0266).
> +
> +  Callers are responsible for freeing the returned string storage pointed by
> UserId
> +  and Password.
> +
> +  @param[out]  AuthMethod          Type of Redfish authentication method.
> +  @param[out]  UserId              The pointer to store the returned UserId
> string.
> +  @param[out]  Password            The pointer to store the returned Password
> string.
> +
> +  @retval EFI_SUCCESS              Get the authentication information
> successfully.
> +  @retval EFI_INVALID_PARAMETER    AuthMethod or UserId or Password is
> NULL.
> +  @retval EFI_UNSUPPORTED          Unsupported authentication method is
> found.
> +**/
> +EFI_STATUS
> +RedfishGetAuthInfo (
> +  OUT  EDKII_REDFISH_AUTH_METHOD  *AuthMethod,
> +  OUT  CHAR8                      **UserId,
> +  OUT  CHAR8                      **Password
> +  )
> +{
> +  EFI_STATUS  Status;
> +
> +  if ((AuthMethod == NULL) || (UserId == NULL) || (Password == NULL)) {
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  //
> +  // Locate Redfish Credential Protocol.
> +  //
> +  if (mCredentialProtocol == NULL) {
> +    Status = gBS->LocateProtocol (&gEdkIIRedfishCredentialProtocolGuid,
> NULL, (VOID **)&mCredentialProtocol);
> +    if (EFI_ERROR (Status)) {
> +      return EFI_UNSUPPORTED;
> +    }
> +  }
> +
> +  ASSERT (mCredentialProtocol != NULL);
> +
> +  Status = mCredentialProtocol->GetAuthInfo (mCredentialProtocol,
> AuthMethod, UserId, Password);
> +  if (EFI_ERROR (Status)) {
> +    DEBUG ((DEBUG_ERROR, "RedfishGetAuthInfo: failed to retrieve Redfish
> credential - %r\n", Status));
> +    return Status;
> +  }
> +
> +  return Status;
> +}
> +
> +/**
> +  This function returns the string of Redfish service version.
> +
> +  @param[in]   ServiceVerisonStr The string of Redfish service version.
> +  @param[in]   Url               The URL to build Redpath with ID.
> +                                 Start with "/", for example "/Registries"
> +  @param[in]   Id                ID string
> +  @param[out]  Redpath           Pointer to retrive Redpath, caller has to free
> +                                 the memory allocated for this string.
> +  @return     EFI_STATUS
> +
> +**/
> +EFI_STATUS
> +RedfishBuildRedpathUseId (
> +  IN  CHAR8  *ServiceVerisonStr,
> +  IN  CHAR8  *Url,
> +  IN  CHAR8  *Id,
> +  OUT CHAR8  **Redpath
> +  )
> +{
> +  UINTN  RedpathSize;
> +
> +  if ((Redpath == NULL) || (ServiceVerisonStr == NULL) || (Url == NULL) ||
> (Id == NULL)) {
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  RedpathSize = AsciiStrLen ("/") +
> +                AsciiStrLen (ServiceVerisonStr) +
> +                AsciiStrLen (Url) +
> +                AsciiStrLen ("[Id=]") +
> +                AsciiStrLen (Id) + 1;
> +  *Redpath = AllocatePool (RedpathSize);
> +  if (*Redpath == NULL) {
> +    return EFI_OUT_OF_RESOURCES;
> +  }
> +
> +  AsciiSPrint (*Redpath, RedpathSize, "/%a%a[Id=%a]", ServiceVerisonStr,
> Url, Id);
> +  return EFI_SUCCESS;
> +}
> diff --git
> a/RedfishClientPkg/PrivateLibrary/RedfishLib/edk2libredfish/src/payload.c
> b/RedfishClientPkg/PrivateLibrary/RedfishLib/edk2libredfish/src/payload.c
> new file mode 100644
> index 00000000..7ceb63ac
> --- /dev/null
> +++
> b/RedfishClientPkg/PrivateLibrary/RedfishLib/edk2libredfish/src/payload.c
> @@ -0,0 +1,812 @@
> +/** @file
> +  This file is cloned from DMTF libredfish library tag v1.0.0 and maintained
> +  by EDKII.
> +
> +//----------------------------------------------------------------------------
> +// Copyright Notice:
> +// Copyright 2017 Distributed Management Task Force, Inc. All rights
> reserved.
> +// License: BSD 3-Clause License. For full text see link:
> https://github.com/DMTF/libredfish/LICENSE.md
> +//----------------------------------------------------------------------------
> +
> +  Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
> +  (C) Copyright 2021 Hewlett Packard Enterprise Development LP<BR>
> +
> +  SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +#include <redfishPayload.h>
> +
> +static redfishPayload *
> +getOpResult (
> +  redfishPayload        *payload,
> +  const char            *propName,
> +  const char            *op,
> +  const char            *value,
> +  EFI_HTTP_STATUS_CODE  **StatusCode
> +  );
> +
> +static redfishPayload *
> +collectionEvalOp (
> +  redfishPayload        *payload,
> +  const char            *propName,
> +  const char            *op,
> +  const char            *value,
> +  EFI_HTTP_STATUS_CODE  **StatusCode
> +  );
> +
> +static redfishPayload *
> +arrayEvalOp (
> +  redfishPayload        *payload,
> +  const char            *propName,
> +  const char            *op,
> +  const char            *value,
> +  EFI_HTTP_STATUS_CODE  **StatusCode
> +  );
> +
> +static redfishPayload *
> +createCollection (
> +  redfishService  *service,
> +  size_t          count,
> +  redfishPayload  **payloads
> +  );
> +
> +static json_t *
> +json_object_get_by_index (
> +  json_t  *json,
> +  size_t  index
> +  );
> +
> +bool
> +isPayloadCollection (
> +  redfishPayload  *payload
> +  )
> +{
> +  json_t  *members;
> +  json_t  *count;
> +
> +  if (!payload || !json_is_object (payload->json)) {
> +    return false;
> +  }
> +
> +  members = json_object_get (payload->json, "Members");
> +  count   = json_object_get (payload->json, "Members@odata.count");
> +  return ((members != NULL) && (count != NULL));
> +}
> +
> +size_t
> +getCollectionSize (
> +  redfishPayload  *payload
> +  )
> +{
> +  json_t  *members;
> +  json_t  *count;
> +
> +  if (!payload || !json_is_object (payload->json)) {
> +    return 0;
> +  }
> +
> +  members = json_object_get (payload->json, "Members");
> +  count   = json_object_get (payload->json, "Members@odata.count");
> +  if (!members || !count) {
> +    return 0;
> +  }
> +
> +  return (size_t)json_integer_value (count);
> +}
> +
> +bool
> +isPayloadArray (
> +  redfishPayload  *payload
> +  )
> +{
> +  if (!payload || !json_is_array (payload->json)) {
> +    return false;
> +  }
> +
> +  return true;
> +}
> +
> +char *
> +payloadToString (
> +  redfishPayload  *payload,
> +  bool            prettyPrint
> +  )
> +{
> +  size_t  flags = 0;
> +
> +  if (!payload) {
> +    return NULL;
> +  }
> +
> +  if (prettyPrint) {
> +    flags = JSON_INDENT (2);
> +  }
> +
> +  return json_dumps (payload->json, flags);
> +}
> +
> +redfishPayload *
> +createRedfishPayload (
> +  json_t          *value,
> +  redfishService  *service
> +  )
> +{
> +  redfishPayload  *payload;
> +
> +  payload = (redfishPayload *)malloc (sizeof (redfishPayload));
> +  if (payload != NULL) {
> +    payload->json    = value;
> +    payload->service = service;
> +  }
> +
> +  return payload;
> +}
> +
> +redfishPayload *
> +getPayloadByNodeName (
> +  redfishPayload        *payload,
> +  const char            *nodeName,
> +  EFI_HTTP_STATUS_CODE  **StatusCode
> +  )
> +{
> +  json_t      *value;
> +  json_t      *odataId;
> +  const char  *uri;
> +
> +  if (!payload || !nodeName || (StatusCode == NULL)) {
> +    return NULL;
> +  }
> +
> +  *StatusCode = NULL;
> +
> +  value = json_object_get (payload->json, nodeName);
> +  if (value == NULL) {
> +    return NULL;
> +  }
> +
> +  json_incref (value);
> +  if (json_object_size (value) == 1) {
> +    odataId = json_object_get (value, "@odata.id");
> +    if (odataId != NULL) {
> +      json_incref (odataId);
> +      uri = json_string_value (odataId);
> +      json_decref (value);
> +      value = getUriFromService (payload->service, uri, StatusCode);
> +      json_decref (odataId);
> +      if ((value == NULL) || (*StatusCode == NULL)) {
> +        return NULL;
> +      }
> +    }
> +  }
> +
> +  if ((*StatusCode == NULL) || ((**StatusCode >= HTTP_STATUS_200_OK)
> && (**StatusCode <= HTTP_STATUS_206_PARTIAL_CONTENT))) {
> +    if (json_is_string (value)) {
> +      odataId = json_object ();
> +      json_object_set (odataId, nodeName, value);
> +      json_decref (value);
> +      value = odataId;
> +    }
> +  }
> +
> +  return createRedfishPayload (value, payload->service);
> +}
> +
> +redfishPayload *
> +getPayloadByIndex (
> +  redfishPayload        *payload,
> +  size_t                index,
> +  EFI_HTTP_STATUS_CODE  **StatusCode
> +  )
> +{
> +  json_t      *value = NULL;
> +  json_t      *odataId;
> +  const char  *uri;
> +  BOOLEAN     FromServerFlag = FALSE;
> +
> +  if (!payload || (StatusCode == NULL)) {
> +    return NULL;
> +  }
> +
> +  *StatusCode = NULL;
> +
> +  if (isPayloadCollection (payload)) {
> +    redfishPayload  *members = getPayloadByNodeName (payload,
> "Members", StatusCode);
> +    if (((*StatusCode == NULL) && (members == NULL)) ||
> +        ((*StatusCode != NULL) && ((**StatusCode < HTTP_STATUS_200_OK)
> || (**StatusCode > HTTP_STATUS_206_PARTIAL_CONTENT))))
> +    {
> +      return members;
> +    }
> +
> +    if (*StatusCode != NULL) {
> +      //
> +      // The Payload (members) are retrived from server.
> +      //
> +      FreePool (*StatusCode);
> +      *StatusCode    = NULL;
> +      FromServerFlag = TRUE;
> +    }
> +
> +    redfishPayload  *ret = getPayloadByIndex (members, index, StatusCode);
> +    if ((*StatusCode == NULL) && (ret != NULL) && FromServerFlag) {
> +      //
> +      // In such a case, the Redfish resource is parsed from the input payload
> (members) directly.
> +      // Since the members are retrived from server, we still return
> HTTP_STATUS_200_OK.
> +      //
> +      *StatusCode = AllocateZeroPool (sizeof (EFI_HTTP_STATUS_CODE));
> +      if (*StatusCode == NULL) {
> +        ret = NULL;
> +      } else {
> +        **StatusCode = HTTP_STATUS_200_OK;
> +      }
> +    }
> +
> +    cleanupPayload (members);
> +    return ret;
> +  }
> +
> +  if (json_is_array (payload->json)) {
> +    //
> +    // The valid range for index is from 0 to the return value of
> json_array_size() minus 1
> +    //
> +    value = json_array_get (payload->json, index);
> +  } else if (json_is_object (payload->json)) {
> +    value = json_object_get_by_index (payload->json, index);
> +  }
> +
> +  if (value == NULL) {
> +    return NULL;
> +  }
> +
> +  json_incref (value);
> +  if (json_object_size (value) == 1) {
> +    odataId = json_object_get (value, "@odata.id");
> +    if (odataId != NULL) {
> +      uri = json_string_value (odataId);
> +      json_decref (value);
> +      value = getUriFromService (payload->service, uri, StatusCode);
> +      if (value == NULL) {
> +        return NULL;
> +      }
> +    }
> +  }
> +
> +  return createRedfishPayload (value, payload->service);
> +}
> +
> +redfishPayload *
> +getPayloadForPath (
> +  redfishPayload        *payload,
> +  redPathNode           *redpath,
> +  EFI_HTTP_STATUS_CODE  **StatusCode
> +  )
> +{
> +  redfishPayload  *ret = NULL;
> +  redfishPayload  *tmp;
> +
> +  if (!payload || !redpath || (StatusCode == NULL)) {
> +    return NULL;
> +  }
> +
> +  *StatusCode = NULL;
> +  BOOLEAN  FromServerFlag = FALSE;
> +
> +  if (redpath->nodeName) {
> +    ret = getPayloadByNodeName (payload, redpath->nodeName,
> StatusCode);
> +    if (((*StatusCode == NULL) && (ret == NULL)) ||
> +        ((*StatusCode != NULL) && ((**StatusCode < HTTP_STATUS_200_OK)
> || (**StatusCode > HTTP_STATUS_206_PARTIAL_CONTENT))))
> +    {
> +      //
> +      // Any error happen, return directly.
> +      //
> +      return ret;
> +    }
> +  } else if (redpath->isIndex) {
> +    ASSERT (redpath->index >= 1);
> +    ret = getPayloadByIndex (payload, redpath->index - 1, StatusCode);
> +    if (((*StatusCode == NULL) && (ret == NULL)) ||
> +        ((*StatusCode != NULL) && ((**StatusCode < HTTP_STATUS_200_OK)
> || (**StatusCode > HTTP_STATUS_206_PARTIAL_CONTENT))))
> +    {
> +      //
> +      // Any error happen, return directly.
> +      //
> +      return ret;
> +    }
> +  } else if (redpath->op) {
> +    ret = getOpResult (payload, redpath->propName, redpath->op, redpath-
> >value, StatusCode);
> +    if (((*StatusCode == NULL) && (ret == NULL)) ||
> +        ((*StatusCode != NULL) && ((**StatusCode < HTTP_STATUS_200_OK)
> || (**StatusCode > HTTP_STATUS_206_PARTIAL_CONTENT))))
> +    {
> +      //
> +      // Any error happen, return directly.
> +      //
> +      return ret;
> +    }
> +  } else {
> +    return NULL;
> +  }
> +
> +  if ((redpath->next == NULL) || (ret == NULL)) {
> +    return ret;
> +  } else {
> +    if (*StatusCode != NULL) {
> +      FreePool (*StatusCode);
> +      *StatusCode    = NULL;
> +      FromServerFlag = TRUE;
> +    }
> +
> +    tmp = getPayloadForPath (ret, redpath->next, StatusCode);
> +    if ((*StatusCode == NULL) && (tmp != NULL) && FromServerFlag) {
> +      //
> +      // In such a case, the Redfish resource is parsed from the input payload
> (ret) directly.
> +      // Since the ret are retrived from server, we still return
> HTTP_STATUS_200_OK.
> +      //
> +      *StatusCode = AllocateZeroPool (sizeof (EFI_HTTP_STATUS_CODE));
> +      if (*StatusCode == NULL) {
> +        tmp = NULL;
> +      } else {
> +        **StatusCode = HTTP_STATUS_200_OK;
> +      }
> +    }
> +
> +    cleanupPayload (ret);
> +    return tmp;
> +  }
> +}
> +
> +redfishPayload *
> +getPayloadForPathString (
> +  redfishPayload        *payload,
> +  const char            *string,
> +  EFI_HTTP_STATUS_CODE  **StatusCode
> +  )
> +{
> +  redPathNode     *redpath;
> +  redfishPayload  *ret;
> +
> +  if (!string || (StatusCode == NULL)) {
> +    return NULL;
> +  }
> +
> +  *StatusCode = NULL;
> +
> +  redpath = parseRedPath (string);
> +  if (redpath == NULL) {
> +    return NULL;
> +  }
> +
> +  ret = getPayloadForPath (payload, redpath, StatusCode);
> +  cleanupRedPath (redpath);
> +  return ret;
> +}
> +
> +redfishPayload *
> +patchPayload (
> +  redfishPayload        *target,
> +  redfishPayload        *payload,
> +  EFI_HTTP_STATUS_CODE  **StatusCode
> +  )
> +{
> +  json_t  *json;
> +  char    *content;
> +  char    *uri;
> +
> +  if (!target || !payload || (StatusCode == NULL)) {
> +    return NULL;
> +  }
> +
> +  *StatusCode = NULL;
> +
> +  json = json_object_get (target->json, "@odata.id");
> +  if (json == NULL) {
> +    return NULL;
> +  }
> +
> +  uri = strdup (json_string_value (json));
> +
> +  content = json_dumps (payload->json, 0);
> +  json_decref (json);
> +
> +  json = patchUriFromService (target->service, uri, content, StatusCode);
> +  free (uri);
> +  free (content);
> +  if (json == NULL) {
> +    return NULL;
> +  }
> +
> +  return createRedfishPayload (json, target->service);
> +}
> +
> +redfishPayload *
> +postContentToPayload (
> +  redfishPayload        *target,
> +  const char            *data,
> +  size_t                dataSize,
> +  const char            *contentType,
> +  EFI_HTTP_STATUS_CODE  **StatusCode
> +  )
> +{
> +  json_t  *json;
> +  char    *uri;
> +
> +  if (!target || !data || (StatusCode == NULL)) {
> +    return NULL;
> +  }
> +
> +  *StatusCode = NULL;
> +
> +  json = json_object_get (target->json, "@odata.id");
> +  if (json == NULL) {
> +    json = json_object_get (target->json, "target");
> +    if (json == NULL) {
> +      return NULL;
> +    }
> +  }
> +
> +  uri  = strdup (json_string_value (json));
> +  json = postUriFromService (target->service, uri, data, dataSize,
> contentType, StatusCode);
> +  free (uri);
> +  if (json == NULL) {
> +    return NULL;
> +  }
> +
> +  return createRedfishPayload (json, target->service);
> +}
> +
> +redfishPayload *
> +postPayload (
> +  redfishPayload        *target,
> +  redfishPayload        *payload,
> +  EFI_HTTP_STATUS_CODE  **StatusCode
> +  )
> +{
> +  char            *content;
> +  redfishPayload  *ret;
> +
> +  if (!target || !payload || (StatusCode == NULL)) {
> +    return NULL;
> +  }
> +
> +  *StatusCode = NULL;
> +
> +  if (!json_is_object (payload->json)) {
> +    return NULL;
> +  }
> +
> +  content = payloadToString (payload, false);
> +  ret     = postContentToPayload (target, content, strlen (content), NULL,
> StatusCode);
> +  free (content);
> +  return ret;
> +}
> +
> +void
> +cleanupPayload (
> +  redfishPayload  *payload
> +  )
> +{
> +  if (!payload) {
> +    return;
> +  }
> +
> +  json_decref (payload->json);
> +  // Don't free payload->service, let the caller handle cleaning up the service
> +  free (payload);
> +}
> +
> +static redfishPayload *
> +getOpResult (
> +  redfishPayload        *payload,
> +  const char            *propName,
> +  const char            *op,
> +  const char            *value,
> +  EFI_HTTP_STATUS_CODE  **StatusCode
> +  )
> +{
> +  const char      *propStr;
> +  json_t          *stringProp;
> +  bool            ret = false;
> +  redfishPayload  *prop;
> +  long long       intVal, intPropVal;
> +  json_type       jsonType;
> +
> +  if (isPayloadCollection (payload)) {
> +    return collectionEvalOp (payload, propName, op, value, StatusCode);
> +  }
> +
> +  if (isPayloadArray (payload)) {
> +    return arrayEvalOp (payload, propName, op, value, StatusCode);
> +  }
> +
> +  prop = getPayloadByNodeName (payload, propName, StatusCode);
> +  if (((*StatusCode == NULL) && (prop == NULL)) ||
> +      ((*StatusCode != NULL) && ((**StatusCode < HTTP_STATUS_200_OK) ||
> (**StatusCode > HTTP_STATUS_206_PARTIAL_CONTENT))))
> +  {
> +    return prop;
> +  }
> +
> +  stringProp = prop->json;
> +  jsonType   =  json_get_type (prop->json);
> +  switch (jsonType) {
> +    case JSON_OBJECT:
> +      stringProp = json_object_get (prop->json, propName);
> +    case JSON_STRING:
> +      if (strcmp (op, "=") == 0) {
> +        propStr = json_string_value (stringProp);
> +        if (propStr == NULL) {
> +          cleanupPayload (prop);
> +          return NULL;
> +        }
> +
> +        ret = (strcmp (propStr, value) == 0);
> +      } else if (strcmp (op, "~") == 0) {
> +        propStr = json_string_value (stringProp);
> +        if (propStr == NULL) {
> +          cleanupPayload (prop);
> +          return NULL;
> +        }
> +
> +        ret = (strcasecmp (propStr, value) == 0);
> +      }
> +
> +      break;
> +    case JSON_TRUE:
> +      if (strcmp (op, "=") == 0) {
> +        ret = (strcmp (value, "true") == 0);
> +      }
> +
> +      break;
> +    case JSON_FALSE:
> +      if (strcmp (op, "=") == 0) {
> +        ret = (strcmp (value, "false") == 0);
> +      }
> +
> +      break;
> +    case JSON_INTEGER:
> +      intPropVal = json_integer_value (prop->json);
> +      intVal     = strtoll (value, NULL, 0);
> +      if (strcmp (op, "=") == 0) {
> +        ret = (intPropVal == intVal);
> +      } else if (strcmp (op, "<") == 0) {
> +        ret = (intPropVal < intVal);
> +      } else if (strcmp (op, ">") == 0) {
> +        ret = (intPropVal > intVal);
> +      } else if (strcmp (op, "<=") == 0) {
> +        ret = (intPropVal <= intVal);
> +      } else if (strcmp (op, ">=") == 0) {
> +        ret = (intPropVal >= intVal);
> +      }
> +
> +      break;
> +    default:
> +      break;
> +  }
> +
> +  cleanupPayload (prop);
> +  if (ret) {
> +    return payload;
> +  } else {
> +    return NULL;
> +  }
> +}
> +
> +static redfishPayload *
> +collectionEvalOp (
> +  redfishPayload        *payload,
> +  const char            *propName,
> +  const char            *op,
> +  const char            *value,
> +  EFI_HTTP_STATUS_CODE  **StatusCode
> +  )
> +{
> +  redfishPayload  *ret;
> +  redfishPayload  *tmp;
> +  redfishPayload  *members;
> +  redfishPayload  **valid;
> +  size_t          validMax;
> +  size_t          validCount = 0;
> +  size_t          i;
> +
> +  validMax = getCollectionSize (payload);
> +  if (validMax == 0) {
> +    return NULL;
> +  }
> +
> +  valid = (redfishPayload **)calloc (validMax, sizeof (redfishPayload *));
> +  if (valid == NULL) {
> +    return NULL;
> +  }
> +
> +  /*Technically getPayloadByIndex would do this, but this optimizes things*/
> +  members = getPayloadByNodeName (payload, "Members", StatusCode);
> +  if (((*StatusCode == NULL) && (members == NULL)) ||
> +      ((*StatusCode != NULL) && ((**StatusCode < HTTP_STATUS_200_OK) ||
> (**StatusCode > HTTP_STATUS_206_PARTIAL_CONTENT))))
> +  {
> +    return members;
> +  }
> +
> +  for (i = 0; i < validMax; i++) {
> +    if (*StatusCode != NULL) {
> +      FreePool (*StatusCode);
> +      *StatusCode = NULL;
> +    }
> +
> +    tmp = getPayloadByIndex (members, i, StatusCode);
> +    if (((*StatusCode == NULL) && (tmp == NULL)) ||
> +        ((*StatusCode != NULL) && ((**StatusCode < HTTP_STATUS_200_OK)
> || (**StatusCode > HTTP_STATUS_206_PARTIAL_CONTENT))))
> +    {
> +      return tmp;
> +    }
> +
> +    if (*StatusCode != NULL) {
> +      FreePool (*StatusCode);
> +      *StatusCode = NULL;
> +    }
> +
> +    valid[validCount] = getOpResult (tmp, propName, op, value, StatusCode);
> +
> +    /*
> +    if ((*StatusCode == NULL && valid[validCount] == NULL) ||
> +        (*StatusCode != NULL && (**StatusCode < HTTP_STATUS_200_OK ||
> **StatusCode > HTTP_STATUS_206_PARTIAL_CONTENT))) {
> +      return valid[validCount];
> +    }
> +    */
> +    if (valid[validCount] != NULL) {
> +      validCount++;
> +    } else {
> +      cleanupPayload (tmp);
> +    }
> +  }
> +
> +  cleanupPayload (members);
> +  if (validCount == 0) {
> +    free (valid);
> +    return NULL;
> +  }
> +
> +  if (validCount == 1) {
> +    ret = valid[0];
> +    free (valid);
> +    return ret;
> +  } else {
> +    ret = createCollection (payload->service, validCount, valid);
> +    free (valid);
> +    return ret;
> +  }
> +}
> +
> +static redfishPayload *
> +arrayEvalOp (
> +  redfishPayload        *payload,
> +  const char            *propName,
> +  const char            *op,
> +  const char            *value,
> +  EFI_HTTP_STATUS_CODE  **StatusCode
> +  )
> +{
> +  redfishPayload  *ret;
> +  redfishPayload  *tmp;
> +  redfishPayload  **valid;
> +  size_t          validMax;
> +  size_t          validCount = 0;
> +  size_t          i;
> +
> +  validMax = json_array_size (payload->json);
> +  if (validMax == 0) {
> +    return NULL;
> +  }
> +
> +  valid = (redfishPayload **)calloc (validMax, sizeof (redfishPayload *));
> +  if (valid == NULL) {
> +    return NULL;
> +  }
> +
> +  for (i = 0; i < validMax; i++) {
> +    if (*StatusCode != NULL) {
> +      FreePool (*StatusCode);
> +      *StatusCode = NULL;
> +    }
> +
> +    tmp = getPayloadByIndex (payload, i, StatusCode);
> +    if (((*StatusCode == NULL) && (tmp == NULL)) ||
> +        ((*StatusCode != NULL) && ((**StatusCode < HTTP_STATUS_200_OK)
> || (**StatusCode > HTTP_STATUS_206_PARTIAL_CONTENT))))
> +    {
> +      return tmp;
> +    }
> +
> +    if (*StatusCode != NULL) {
> +      FreePool (*StatusCode);
> +      *StatusCode = NULL;
> +    }
> +
> +    valid[validCount] = getOpResult (tmp, propName, op, value, StatusCode);
> +
> +    /*
> +    if ((*StatusCode == NULL && valid[validCount] == NULL) ||
> +        (*StatusCode != NULL && (**StatusCode < HTTP_STATUS_200_OK ||
> **StatusCode > HTTP_STATUS_206_PARTIAL_CONTENT))) {
> +      return valid[validCount];
> +    }
> +    */
> +
> +    if (valid[validCount] != NULL) {
> +      validCount++;
> +    } else {
> +      cleanupPayload (tmp);
> +    }
> +  }
> +
> +  if (validCount == 0) {
> +    free (valid);
> +    return NULL;
> +  }
> +
> +  if (validCount == 1) {
> +    ret = valid[0];
> +    free (valid);
> +    return ret;
> +  } else {
> +    ret = createCollection (payload->service, validCount, valid);
> +    free (valid);
> +    return ret;
> +  }
> +}
> +
> +static redfishPayload *
> +createCollection (
> +  redfishService  *service,
> +  size_t          count,
> +  redfishPayload  **payloads
> +  )
> +{
> +  redfishPayload  *ret;
> +  json_t          *collectionJson = json_object ();
> +  json_t          *jcount         = json_integer ((json_int_t)count);
> +  json_t          *members        = json_array ();
> +  size_t          i;
> +
> +  if (!collectionJson) {
> +    return NULL;
> +  }
> +
> +  if (!members) {
> +    json_decref (collectionJson);
> +    return NULL;
> +  }
> +
> +  json_object_set (collectionJson, "Members@odata.count", jcount);
> +  json_decref (jcount);
> +  for (i = 0; i < count; i++) {
> +    json_array_append (members, payloads[i]->json);
> +    cleanupPayload (payloads[i]);
> +  }
> +
> +  json_object_set (collectionJson, "Members", members);
> +  json_decref (members);
> +
> +  ret = createRedfishPayload (collectionJson, service);
> +  return ret;
> +}
> +
> +static json_t *
> +json_object_get_by_index (
> +  json_t  *json,
> +  size_t  index
> +  )
> +{
> +  void    *iter;
> +  size_t  i;
> +
> +  iter = json_object_iter (json);
> +  for (i = 0; i < index; i++) {
> +    iter = json_object_iter_next (json, iter);
> +    if (iter == NULL) {
> +      break;
> +    }
> +  }
> +
> +  if (iter == NULL) {
> +    return NULL;
> +  }
> +
> +  return json_object_iter_value (iter);
> +}
> +
> +/* vim: set tabstop=4 shiftwidth=4 expandtab: */
> diff --git
> a/RedfishClientPkg/PrivateLibrary/RedfishLib/edk2libredfish/src/redpath.c
> b/RedfishClientPkg/PrivateLibrary/RedfishLib/edk2libredfish/src/redpath.c
> new file mode 100644
> index 00000000..cf5ab851
> --- /dev/null
> +++
> b/RedfishClientPkg/PrivateLibrary/RedfishLib/edk2libredfish/src/redpath.c
> @@ -0,0 +1,224 @@
> +/** @file
> +  This file is cloned from DMTF libredfish library tag v1.0.0 and maintained
> +  by EDKII.
> +
> +//----------------------------------------------------------------------------
> +// Copyright Notice:
> +// Copyright 2017 Distributed Management Task Force, Inc. All rights
> reserved.
> +// License: BSD 3-Clause License. For full text see link:
> https://github.com/DMTF/libredfish/LICENSE.md
> +//----------------------------------------------------------------------------
> +
> +  Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
> +  (C) Copyright 2021 Hewlett Packard Enterprise Development LP<BR>
> +
> +  SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +#include <redpath.h>
> +
> +static char *
> +getVersion (
> +  const char  *path,
> +  char        **end
> +  );
> +
> +static void
> +parseNode (
> +  const char   *path,
> +  redPathNode  *node,
> +  redPathNode  **end
> +  );
> +
> +static char *
> +getStringTill (
> +  const char  *string,
> +  const char  *terminator,
> +  char        **retEnd
> +  );
> +
> +redPathNode *
> +parseRedPath (
> +  const char  *path
> +  )
> +{
> +  redPathNode  *node;
> +  redPathNode  *endNode;
> +  char         *curPath;
> +  char         *end;
> +
> +  if (!path || (strlen (path) == 0)) {
> +    return NULL;
> +  }
> +
> +  node = (redPathNode *)calloc (1, sizeof (redPathNode));
> +  if (!node) {
> +    return NULL;
> +  }
> +
> +  if (path[0] == '/') {
> +    node->isRoot = true;
> +    if (path[1] == 'v') {
> +      node->version = getVersion (path+1, &curPath);
> +      if (curPath == NULL) {
> +        return node;
> +      }
> +
> +      if (curPath[0] == '/') {
> +        curPath++;
> +      }
> +
> +      node->next = parseRedPath (curPath);
> +    } else {
> +      node->next = parseRedPath (path+1);
> +    }
> +
> +    return node;
> +  }
> +
> +  node->isRoot = false;
> +  curPath      = getStringTill (path, "/", &end);
> +  endNode      = node;
> +  parseNode (curPath, node, &endNode);
> +  free (curPath);
> +  if (end != NULL) {
> +    endNode->next = parseRedPath (end+1);
> +  }
> +
> +  return node;
> +}
> +
> +void
> +cleanupRedPath (
> +  redPathNode  *node
> +  )
> +{
> +  if (!node) {
> +    return;
> +  }
> +
> +  cleanupRedPath (node->next);
> +  node->next = NULL;
> +  if (node->version) {
> +    free (node->version);
> +  }
> +
> +  if (node->nodeName) {
> +    free (node->nodeName);
> +  }
> +
> +  if (node->op) {
> +    free (node->op);
> +  }
> +
> +  if (node->propName) {
> +    free (node->propName);
> +  }
> +
> +  if (node->value) {
> +    free (node->value);
> +  }
> +
> +  free (node);
> +}
> +
> +static char *
> +getVersion (
> +  const char  *path,
> +  char        **end
> +  )
> +{
> +  return getStringTill (path, "/", end);
> +}
> +
> +static void
> +parseNode (
> +  const char   *path,
> +  redPathNode  *node,
> +  redPathNode  **end
> +  )
> +{
> +  char    *indexStart;
> +  char    *index;
> +  char    *indexEnd;
> +  char    *nodeName = getStringTill (path, "[", &indexStart);
> +  size_t  tmpIndex;
> +  char    *opChars;
> +
> +  node->nodeName = nodeName;
> +  if (indexStart == NULL) {
> +    *end = node;
> +    return;
> +  }
> +
> +  node->next = (redPathNode *)calloc (1, sizeof (redPathNode));
> +  if (!node->next) {
> +    return;
> +  }
> +
> +  // Skip past [
> +  indexStart++;
> +  *end     = node->next;
> +  index    = getStringTill (indexStart, "]", NULL);
> +  tmpIndex = (size_t)strtoull (index, &indexEnd, 0);
> +  if (indexEnd != index) {
> +    free (index);
> +    node->next->index   = tmpIndex;
> +    node->next->isIndex = true;
> +    return;
> +  }
> +
> +  opChars = strpbrk (index, "<>=~");
> +  if (opChars == NULL) {
> +    // TODO handle last() and position()
> +    node->next->op       = strdup ("exists");
> +    node->next->propName = index;
> +    return;
> +  }
> +
> +  node->next->propName = (char *)malloc ((opChars - index)+1);
> +  memcpy (node->next->propName, index, (opChars - index));
> +  node->next->propName[(opChars - index)] = 0;
> +
> +  tmpIndex = 1;
> +  while (1) {
> +    if ((opChars[tmpIndex] == '=') || (opChars[tmpIndex] == '<') ||
> (opChars[tmpIndex] == '>') || (opChars[tmpIndex] == '~')) {
> +      tmpIndex++;
> +      continue;
> +    }
> +
> +    break;
> +  }
> +
> +  node->next->op = (char *)malloc (tmpIndex+1);
> +  memcpy (node->next->op, opChars, tmpIndex);
> +  node->next->op[tmpIndex] = 0;
> +
> +  node->next->value = strdup (opChars+tmpIndex);
> +  free (index);
> +}
> +
> +static char *
> +getStringTill (
> +  const char  *string,
> +  const char  *terminator,
> +  char        **retEnd
> +  )
> +{
> +  char  *ret;
> +  char  *end;
> +
> +  end = strstr ((char *)string, terminator);
> +  if (retEnd) {
> +    *retEnd = end;
> +  }
> +
> +  if (end == NULL) {
> +    // No terminator
> +    return strdup (string);
> +  }
> +
> +  ret = (char *)malloc ((end-string)+1);
> +  memcpy (ret, string, (end-string));
> +  ret[(end-string)] = 0;
> +  return ret;
> +}
> diff --git
> a/RedfishClientPkg/PrivateLibrary/RedfishLib/edk2libredfish/src/service.c
> b/RedfishClientPkg/PrivateLibrary/RedfishLib/edk2libredfish/src/service.c
> new file mode 100644
> index 00000000..969aa5a0
> --- /dev/null
> +++
> b/RedfishClientPkg/PrivateLibrary/RedfishLib/edk2libredfish/src/service.c
> @@ -0,0 +1,1523 @@
> +/** @file
> +  This file is cloned from DMTF libredfish library tag v1.0.0 and maintained
> +  by EDKII.
> +
> +//----------------------------------------------------------------------------
> +// Copyright Notice:
> +// Copyright 2017 Distributed Management Task Force, Inc. All rights
> reserved.
> +// License: BSD 3-Clause License. For full text see link:
> https://github.com/DMTF/libredfish/LICENSE.md
> +//----------------------------------------------------------------------------
> +
> +  Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
> +  (C) Copyright 2021 Hewlett Packard Enterprise Development LP<BR>
> +
> +  SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +#include <redfishService.h>
> +#include <redfishPayload.h>
> +#include <redpath.h>
> +
> +static int
> +initRest (
> +  redfishService  *service,
> +  void            *restProtocol
> +  );
> +
> +static redfishService *
> +createServiceEnumeratorNoAuth (
> +  const char    *host,
> +  const char    *rootUri,
> +  bool          enumerate,
> +  unsigned int  flags,
> +  void          *restProtocol
> +  );
> +
> +static redfishService *
> +createServiceEnumeratorBasicAuth (
> +  const char    *host,
> +  const char    *rootUri,
> +  const char    *username,
> +  const char    *password,
> +  unsigned int  flags,
> +  void          *restProtocol
> +  );
> +
> +static redfishService *
> +createServiceEnumeratorSessionAuth (
> +  const char    *host,
> +  const char    *rootUri,
> +  const char    *username,
> +  const char    *password,
> +  unsigned int  flags,
> +  void          *restProtocol
> +  );
> +
> +static char *
> +makeUrlForService (
> +  redfishService  *service,
> +  const char      *uri
> +  );
> +
> +static json_t *
> +getVersions (
> +  redfishService  *service,
> +  const char      *rootUri
> +  );
> +
> +static void
> +addStringToJsonObject (
> +  json_t      *object,
> +  const char  *key,
> +  const char  *value
> +  );
> +
> +CHAR16 *
> +C8ToC16 (
> +  CHAR8  *AsciiStr
> +  )
> +{
> +  CHAR16  *Str;
> +  UINTN   BufLen;
> +
> +  BufLen = (AsciiStrLen (AsciiStr) + 1) * 2;
> +  Str    = AllocatePool (BufLen);
> +  ASSERT (Str != NULL);
> +
> +  AsciiStrToUnicodeStrS (AsciiStr, Str, AsciiStrLen (AsciiStr) + 1);
> +
> +  return Str;
> +}
> +
> +VOID
> +RestConfigFreeHttpRequestData (
> +  IN EFI_HTTP_REQUEST_DATA  *RequestData
> +  )
> +{
> +  if (RequestData == NULL) {
> +    return;
> +  }
> +
> +  if (RequestData->Url != NULL) {
> +    FreePool (RequestData->Url);
> +  }
> +
> +  FreePool (RequestData);
> +}
> +
> +VOID
> +RestConfigFreeHttpMessage (
> +  IN EFI_HTTP_MESSAGE  *Message,
> +  IN BOOLEAN           IsRequest
> +  )
> +{
> +  if (Message == NULL) {
> +    return;
> +  }
> +
> +  if (IsRequest) {
> +    RestConfigFreeHttpRequestData (Message->Data.Request);
> +    Message->Data.Request = NULL;
> +  } else {
> +    if (Message->Data.Response != NULL) {
> +      FreePool (Message->Data.Response);
> +      Message->Data.Response = NULL;
> +    }
> +  }
> +
> +  if (Message->Headers != NULL) {
> +    FreePool (Message->Headers);
> +    Message->Headers = NULL;
> +  }
> +
> +  if (Message->Body != NULL) {
> +    FreePool (Message->Body);
> +    Message->Body = NULL;
> +  }
> +}
> +
> +/**
> +  Converts the Unicode string to ASCII string to a new allocated buffer.
> +
> +  @param[in]       String       Unicode string to be converted.
> +
> +  @return     Buffer points to ASCII string, or NULL if error happens.
> +
> +**/
> +CHAR8 *
> +UnicodeStrDupToAsciiStr (
> +  CONST CHAR16  *String
> +  )
> +{
> +  CHAR8       *AsciiStr;
> +  UINTN       BufLen;
> +  EFI_STATUS  Status;
> +
> +  BufLen   = StrLen (String) + 1;
> +  AsciiStr = AllocatePool (BufLen);
> +  if (AsciiStr == NULL) {
> +    return NULL;
> +  }
> +
> +  Status = UnicodeStrToAsciiStrS (String, AsciiStr, BufLen);
> +  if (EFI_ERROR (Status)) {
> +    return NULL;
> +  }
> +
> +  return AsciiStr;
> +}
> +
> +/**
> +  This function encodes the content.
> +
> +  @param[in]   ContentEncodedValue   HTTP conent encoded value.
> +  @param[in]   OriginalContent       Original content.
> +  @param[out]  EncodedContent        Pointer to receive encoded content.
> +  @param[out]  EncodedContentLength  Length of encoded content.
> +
> +  @retval EFI_SUCCESS              Content encoded successfully.
> +  @retval EFI_UNSUPPORTED          No source encoding funciton,
> +  @retval EFI_INVALID_PARAMETER    One of the given parameter is invalid.
> +
> +**/
> +EFI_STATUS
> +EncodeRequestContent (
> +  IN CHAR8   *ContentEncodedValue,
> +  IN CHAR8   *OriginalContent,
> +  OUT VOID   **EncodedContent,
> +  OUT UINTN  *EncodedContentLength
> +  )
> +{
> +  EFI_STATUS  Status;
> +  VOID        *EncodedPointer;
> +  UINTN       EncodedLength;
> +
> +  if ((OriginalContent == NULL) || (EncodedContent == NULL) ||
> (EncodedContentLength == NULL)) {
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  Status = RedfishContentEncode (
> +             ContentEncodedValue,
> +             OriginalContent,
> +             AsciiStrLen (OriginalContent),
> +             &EncodedPointer,
> +             &EncodedLength
> +             );
> +  if (Status == EFI_SUCCESS) {
> +    *EncodedContent       = EncodedPointer;
> +    *EncodedContentLength = EncodedLength;
> +    return EFI_SUCCESS;
> +  }
> +
> +  return Status;
> +}
> +
> +/**
> +  This function decodes the content. The Memory block pointed by
> +  ContentPointer would be freed and replaced with the cooked Redfish
> +  payload.
> +
> +  @param[in]        ContentEncodedValue HTTP conent encoded value.
> +  @param[in, out]   ContentPointer      Pointer to encoded content.
> +                                        Pointer of decoded content when out.
> +  @param[in, out]   ContentLength       Pointer to the length of encoded
> content.
> +                                        Length of decoded content when out.
> +
> +  @retval EFI_SUCCESS              Functinos found.
> +  @retval EFI_UNSUPPORTED          No functions found.
> +  @retval EFI_INVALID_PARAMETER    One of the given parameter is invalid.
> +
> +**/
> +EFI_STATUS
> +DecodeResponseContent (
> +  IN CHAR8      *ContentEncodedValue,
> +  IN OUT VOID   **ContentPointer,
> +  IN OUT UINTN  *ContentLength
> +  )
> +{
> +  EFI_STATUS  Status;
> +  VOID        *DecodedPointer;
> +  UINTN       DecodedLength;
> +
> +  if (ContentEncodedValue == NULL) {
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  Status = RedfishContentDecode (
> +             ContentEncodedValue,
> +             *ContentPointer,
> +             *ContentLength,
> +             &DecodedPointer,
> +             &DecodedLength
> +             );
> +  if (Status == EFI_SUCCESS) {
> +    FreePool (*ContentPointer);
> +    *ContentPointer = DecodedPointer;
> +    *ContentLength  = DecodedLength;
> +  }
> +
> +  return Status;
> +}
> +
> +/**
> +  Create a HTTP URL string for specific Redfish resource.
> +
> +  This function build a URL string from the Redfish Host interface record and
> caller specified
> +  relative path of the resource.
> +
> +  Callers are responsible for freeing the returned string storage pointed by
> HttpUrl.
> +
> +  @param[in]   RedfishData         Redfish network host interface record.
> +  @param[in]   RelativePath        Relative path of a resource.
> +  @param[out]  HttpUrl             The pointer to store the returned URL string.
> +
> +  @retval EFI_SUCCESS              Build the URL string successfully.
> +  @retval EFI_INVALID_PARAMETER    RedfishData or HttpUrl is NULL.
> +  @retval EFI_OUT_OF_RESOURCES     There are not enough memory
> resources.
> +
> +**/
> +EFI_STATUS
> +RedfishBuildUrl (
> +  IN  REDFISH_CONFIG_SERVICE_INFORMATION *RedfishConfigServiceInfo,
> +  IN  CHAR16 *RelativePath, OPTIONAL
> +  OUT CHAR16                        **HttpUrl
> +  )
> +{
> +  CHAR16  *Url;
> +  CHAR16  *UrlHead;
> +  UINTN   UrlLength;
> +  UINTN   PathLen;
> +
> +  if ((RedfishConfigServiceInfo == NULL) || (HttpUrl == NULL)) {
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  //
> +  // RFC2616: http_URL = "http(s):" "//" host [ ":" port ] [ abs_path [ "?"
> query ]]
> +  //
> +  if (RelativePath == NULL) {
> +    PathLen = 0;
> +  } else {
> +    PathLen = StrLen (RelativePath);
> +  }
> +
> +  UrlLength = StrLen (HTTPS_FLAG) + StrLen (REDFISH_FIRST_URL) + 1 +
> StrLen (RedfishConfigServiceInfo->RedfishServiceLocation) + PathLen;
> +  Url       = AllocateZeroPool (UrlLength * sizeof (CHAR16));
> +  if (Url == NULL) {
> +    return EFI_OUT_OF_RESOURCES;
> +  }
> +
> +  UrlHead = Url;
> +  //
> +  // Copy "http://" or "https://" according RedfishServiceIpPort.
> +  //
> +  if (!RedfishConfigServiceInfo->RedfishServiceUseHttps) {
> +    StrCpyS (Url, StrLen (HTTPS_FLAG) + 1, HTTP_FLAG);
> +    Url = Url + StrLen (HTTP_FLAG);
> +  } else {
> +    StrCpyS (Url, StrLen (HTTPS_FLAG) + 1, HTTPS_FLAG);
> +    Url = Url + StrLen (HTTPS_FLAG);
> +  }
> +
> +  StrCpyS (Url, StrLen (RedfishConfigServiceInfo->RedfishServiceLocation) +
> 1, RedfishConfigServiceInfo->RedfishServiceLocation);
> +  Url = Url + StrLen (RedfishConfigServiceInfo->RedfishServiceLocation);
> +
> +  //
> +  // Copy abs_path
> +  //
> +  if ((RelativePath != NULL) && (PathLen != 0)) {
> +    StrnCpyS (Url, UrlLength, RelativePath, PathLen);
> +  }
> +
> +  *HttpUrl = UrlHead;
> +  return EFI_SUCCESS;
> +}
> +
> +redfishService *
> +createServiceEnumerator (
> +  REDFISH_CONFIG_SERVICE_INFORMATION  *RedfishConfigServiceInfo,
> +  const char                          *rootUri,
> +  enumeratorAuthentication            *auth,
> +  unsigned int                        flags
> +  )
> +{
> +  EFI_STATUS            Status;
> +  CHAR16                *HttpUrl;
> +  CHAR8                 *AsciiHost;
> +  EFI_REST_EX_PROTOCOL  *RestEx;
> +  redfishService        *ret;
> +
> +  HttpUrl   = NULL;
> +  AsciiHost = NULL;
> +  RestEx    = NULL;
> +  ret       = NULL;
> +
> +  if (RedfishConfigServiceInfo->RedfishServiceRestExHandle == NULL) {
> +    goto ON_EXIT;
> +  }
> +
> +  Status = RedfishBuildUrl (RedfishConfigServiceInfo, NULL, &HttpUrl);
> +  if (EFI_ERROR (Status)) {
> +    goto ON_EXIT;
> +  }
> +
> +  ASSERT (HttpUrl != NULL);
> +
> +  AsciiHost = UnicodeStrDupToAsciiStr (HttpUrl);
> +  if (AsciiHost == NULL) {
> +    goto ON_EXIT;
> +  }
> +
> +  Status = gBS->HandleProtocol (
> +                  RedfishConfigServiceInfo->RedfishServiceRestExHandle,
> +                  &gEfiRestExProtocolGuid,
> +                  (VOID **)&RestEx
> +                  );
> +  if (EFI_ERROR (Status)) {
> +    goto ON_EXIT;
> +  }
> +
> +  if (auth == NULL) {
> +    ret = createServiceEnumeratorNoAuth (AsciiHost, rootUri, true, flags,
> RestEx);
> +  } else if (auth->authType == REDFISH_AUTH_BASIC) {
> +    ret = createServiceEnumeratorBasicAuth (AsciiHost, rootUri, auth-
> >authCodes.userPass.username, auth->authCodes.userPass.password, flags,
> RestEx);
> +  } else if (auth->authType == REDFISH_AUTH_SESSION) {
> +    ret = createServiceEnumeratorSessionAuth (AsciiHost, rootUri, auth-
> >authCodes.userPass.username, auth->authCodes.userPass.password, flags,
> RestEx);
> +  } else {
> +    goto ON_EXIT;
> +  }
> +
> +  ret->RestEx = RestEx;
> +ON_EXIT:
> +  if (HttpUrl != NULL) {
> +    FreePool (HttpUrl);
> +  }
> +
> +  if (AsciiHost != NULL) {
> +    FreePool (AsciiHost);
> +  }
> +
> +  return ret;
> +}
> +
> +json_t *
> +getUriFromService (
> +  redfishService        *service,
> +  const char            *uri,
> +  EFI_HTTP_STATUS_CODE  **StatusCode
> +  )
> +{
> +  char                   *url;
> +  json_t                 *ret;
> +  HTTP_IO_HEADER         *HttpIoHeader = NULL;
> +  EFI_STATUS             Status;
> +  EFI_HTTP_REQUEST_DATA  *RequestData = NULL;
> +  EFI_HTTP_MESSAGE       *RequestMsg  = NULL;
> +  EFI_HTTP_MESSAGE       ResponseMsg;
> +  EFI_HTTP_HEADER        *ContentEncodedHeader;
> +
> +  if ((service == NULL) || (uri == NULL) || (StatusCode == NULL)) {
> +    return NULL;
> +  }
> +
> +  *StatusCode = NULL;
> +
> +  url = makeUrlForService (service, uri);
> +  if (!url) {
> +    return NULL;
> +  }
> +
> +  DEBUG ((DEBUG_INFO, "libredfish: getUriFromService(): %a\n", url));
> +
> +  //
> +  // Step 1: Create HTTP request message with 4 headers:
> +  //
> +  HttpIoHeader = HttpIoCreateHeader ((service->sessionToken || service-
> >basicAuthStr) ? 6 : 5);
> +  if (HttpIoHeader == NULL) {
> +    ret = NULL;
> +    goto ON_EXIT;
> +  }
> +
> +  if (service->sessionToken) {
> +    Status = HttpIoSetHeader (HttpIoHeader, "X-Auth-Token", service-
> >sessionToken);
> +    ASSERT_EFI_ERROR (Status);
> +  } else if (service->basicAuthStr) {
> +    Status = HttpIoSetHeader (HttpIoHeader, "Authorization", service-
> >basicAuthStr);
> +    ASSERT_EFI_ERROR (Status);
> +  }
> +
> +  Status = HttpIoSetHeader (HttpIoHeader, "Host", service-
> >HostHeaderValue);
> +  ASSERT_EFI_ERROR (Status);
> +  Status = HttpIoSetHeader (HttpIoHeader, "OData-Version", "4.0");
> +  ASSERT_EFI_ERROR (Status);
> +  Status = HttpIoSetHeader (HttpIoHeader, "Accept", "application/json");
> +  ASSERT_EFI_ERROR (Status);
> +  Status = HttpIoSetHeader (HttpIoHeader, "User-Agent", "libredfish");
> +  ASSERT_EFI_ERROR (Status);
> +  Status = HttpIoSetHeader (HttpIoHeader, "Connection", "Keep-Alive");
> +  ASSERT_EFI_ERROR (Status);
> +
> +  //
> +  // Step 2: build the rest of HTTP request info.
> +  //
> +  RequestData = AllocateZeroPool (sizeof (EFI_HTTP_REQUEST_DATA));
> +  if (RequestData == NULL) {
> +    ret = NULL;
> +    goto ON_EXIT;
> +  }
> +
> +  RequestData->Method = HttpMethodGet;
> +  RequestData->Url    = C8ToC16 (url);
> +
> +  //
> +  // Step 3: fill in EFI_HTTP_MESSAGE
> +  //
> +  RequestMsg = AllocateZeroPool (sizeof (EFI_HTTP_MESSAGE));
> +  if (RequestMsg == NULL) {
> +    ret = NULL;
> +    goto ON_EXIT;
> +  }
> +
> +  RequestMsg->Data.Request = RequestData;
> +  RequestMsg->HeaderCount  = HttpIoHeader->HeaderCount;
> +  RequestMsg->Headers      = HttpIoHeader->Headers;
> +
> +  ZeroMem (&ResponseMsg, sizeof (ResponseMsg));
> +
> +  //
> +  // Step 4: call RESTEx to get response from REST service.
> +  //
> +  Status = service->RestEx->SendReceive (service->RestEx, RequestMsg,
> &ResponseMsg);
> +  if (EFI_ERROR (Status)) {
> +    ret = NULL;
> +    goto ON_EXIT;
> +  }
> +
> +  //
> +  // Step 5: Return the HTTP StatusCode and Body message.
> +  //
> +  if (ResponseMsg.Data.Response != NULL) {
> +    *StatusCode = AllocateZeroPool (sizeof (EFI_HTTP_STATUS_CODE));
> +    if (*StatusCode == NULL) {
> +      ret = NULL;
> +      goto ON_EXIT;
> +    }
> +
> +    //
> +    // The caller shall take the responsibility to free the buffer.
> +    //
> +    **StatusCode = ResponseMsg.Data.Response->StatusCode;
> +  }
> +
> +  if ((ResponseMsg.BodyLength != 0) && (ResponseMsg.Body != NULL)) {
> +    //
> +    // Check if data is encoded.
> +    //
> +    ContentEncodedHeader = HttpFindHeader (ResponseMsg.HeaderCount,
> ResponseMsg.Headers, HTTP_HEADER_CONTENT_ENCODING);
> +    if (ContentEncodedHeader != NULL) {
> +      //
> +      // The content is encoded.
> +      //
> +      Status = DecodeResponseContent (ContentEncodedHeader->FieldValue,
> &ResponseMsg.Body, &ResponseMsg.BodyLength);
> +      if (EFI_ERROR (Status)) {
> +        DEBUG ((DEBUG_ERROR, "%a: Failed to decompress the response
> content %r\n.", __FUNCTION__, Status));
> +        ret = NULL;
> +        goto ON_EXIT;
> +      }
> +    }
> +
> +    ret = json_loadb (ResponseMsg.Body, ResponseMsg.BodyLength, 0,
> NULL);
> +  } else {
> +    //
> +    // There is no message body returned from server.
> +    //
> +    ret = NULL;
> +  }
> +
> +ON_EXIT:
> +  if (url != NULL) {
> +    free (url);
> +  }
> +
> +  if (HttpIoHeader != NULL) {
> +    HttpIoFreeHeader (HttpIoHeader);
> +  }
> +
> +  if (RequestData != NULL) {
> +    RestConfigFreeHttpRequestData (RequestData);
> +  }
> +
> +  if (RequestMsg != NULL) {
> +    FreePool (RequestMsg);
> +  }
> +
> +  RestConfigFreeHttpMessage (&ResponseMsg, FALSE);
> +
> +  return ret;
> +}
> +
> +json_t *
> +patchUriFromService (
> +  redfishService        *service,
> +  const char            *uri,
> +  const char            *content,
> +  EFI_HTTP_STATUS_CODE  **StatusCode
> +  )
> +{
> +  char                   *url;
> +  json_t                 *ret;
> +  HTTP_IO_HEADER         *HttpIoHeader = NULL;
> +  EFI_STATUS             Status;
> +  EFI_HTTP_REQUEST_DATA  *RequestData = NULL;
> +  EFI_HTTP_MESSAGE       *RequestMsg  = NULL;
> +  EFI_HTTP_MESSAGE       ResponseMsg;
> +  CHAR8                  ContentLengthStr[80];
> +  CHAR8                  *EncodedContent;
> +  UINTN                  EncodedContentLen;
> +
> +  if ((service == NULL) || (uri == NULL) || (content == NULL) || (StatusCode
> == NULL)) {
> +    return NULL;
> +  }
> +
> +  *StatusCode = NULL;
> +
> +  url = makeUrlForService (service, uri);
> +  if (!url) {
> +    return NULL;
> +  }
> +
> +  DEBUG ((DEBUG_INFO, "libredfish: patchUriFromService(): %a\n", url));
> +
> +  //
> +  // Step 1: Create HTTP request message with 4 headers:
> +  //
> +  HttpIoHeader = HttpIoCreateHeader ((service->sessionToken || service-
> >basicAuthStr) ? 9 : 8);
> +  if (HttpIoHeader == NULL) {
> +    ret = NULL;
> +    goto ON_EXIT;
> +  }
> +
> +  if (service->sessionToken) {
> +    Status = HttpIoSetHeader (HttpIoHeader, "X-Auth-Token", service-
> >sessionToken);
> +    ASSERT_EFI_ERROR (Status);
> +  } else if (service->basicAuthStr) {
> +    Status = HttpIoSetHeader (HttpIoHeader, "Authorization", service-
> >basicAuthStr);
> +    ASSERT_EFI_ERROR (Status);
> +  }
> +
> +  Status = HttpIoSetHeader (HttpIoHeader, "Host", service-
> >HostHeaderValue);
> +  ASSERT_EFI_ERROR (Status);
> +  Status = HttpIoSetHeader (HttpIoHeader, "Content-Type",
> "application/json");
> +  ASSERT_EFI_ERROR (Status);
> +  Status = HttpIoSetHeader (HttpIoHeader, "Accept", "application/json");
> +  ASSERT_EFI_ERROR (Status);
> +  Status = HttpIoSetHeader (HttpIoHeader, "User-Agent", "libredfish");
> +  ASSERT_EFI_ERROR (Status);
> +  Status = HttpIoSetHeader (HttpIoHeader, "Connection", "Keep-Alive");
> +  ASSERT_EFI_ERROR (Status);
> +
> +  AsciiSPrint (
> +    ContentLengthStr,
> +    sizeof (ContentLengthStr),
> +    "%lu",
> +    (UINT64)strlen (content)
> +    );
> +  Status = HttpIoSetHeader (HttpIoHeader, "Content-Length",
> ContentLengthStr);
> +  ASSERT_EFI_ERROR (Status);
> +  Status = HttpIoSetHeader (HttpIoHeader, "OData-Version", "4.0");
> +  ASSERT_EFI_ERROR (Status);
> +
> +  //
> +  // Step 2: build the rest of HTTP request info.
> +  //
> +  RequestData = AllocateZeroPool (sizeof (EFI_HTTP_REQUEST_DATA));
> +  if (RequestData == NULL) {
> +    ret = NULL;
> +    goto ON_EXIT;
> +  }
> +
> +  RequestData->Method = HttpMethodPatch;
> +  RequestData->Url    = C8ToC16 (url);
> +
> +  //
> +  // Step 3: fill in EFI_HTTP_MESSAGE
> +  //
> +  RequestMsg = AllocateZeroPool (sizeof (EFI_HTTP_MESSAGE));
> +  if (RequestMsg == NULL) {
> +    ret = NULL;
> +    goto ON_EXIT;
> +  }
> +
> +  EncodedContent    = (CHAR8 *)content;
> +  EncodedContentLen = strlen (content);
> +  //
> +  // We currently only support gzip Content-Encoding.
> +  //
> +  Status = EncodeRequestContent ((CHAR8
> *)HTTP_CONTENT_ENCODING_GZIP, (CHAR8 *)content, (VOID
> **)&EncodedContent, &EncodedContentLen);
> +  if (Status == EFI_INVALID_PARAMETER) {
> +    DEBUG ((DEBUG_ERROR, "%a: Error to encode content.\n",
> __FUNCTION__));
> +    ret = NULL;
> +    goto ON_EXIT;
> +  } else if (Status == EFI_UNSUPPORTED) {
> +    DEBUG ((DEBUG_INFO, "No content coding for %a! Use raw data
> instead.\n", HTTP_CONTENT_ENCODING_GZIP));
> +    Status = HttpIoSetHeader (HttpIoHeader, "Content-Encoding",
> HTTP_CONTENT_ENCODING_IDENTITY);
> +    ASSERT_EFI_ERROR (Status);
> +  } else {
> +    Status = HttpIoSetHeader (HttpIoHeader, "Content-Encoding",
> HTTP_CONTENT_ENCODING_GZIP);
> +    ASSERT_EFI_ERROR (Status);
> +  }
> +
> +  RequestMsg->Data.Request = RequestData;
> +  RequestMsg->HeaderCount  = HttpIoHeader->HeaderCount;
> +  RequestMsg->Headers      = HttpIoHeader->Headers;
> +  RequestMsg->BodyLength   = EncodedContentLen;
> +  RequestMsg->Body         = (VOID *)EncodedContent;
> +
> +  ZeroMem (&ResponseMsg, sizeof (ResponseMsg));
> +
> +  //
> +  // Step 4: call RESTEx to get response from REST service.
> +  //
> +  Status = service->RestEx->SendReceive (service->RestEx, RequestMsg,
> &ResponseMsg);
> +  if (EFI_ERROR (Status)) {
> +    ret = NULL;
> +    goto ON_EXIT;
> +  }
> +
> +  //
> +  // Step 5: Return the HTTP StatusCode and Body message.
> +  //
> +  if (ResponseMsg.Data.Response != NULL) {
> +    *StatusCode = AllocateZeroPool (sizeof (EFI_HTTP_STATUS_CODE));
> +    if (*StatusCode == NULL) {
> +      ret = NULL;
> +      goto ON_EXIT;
> +    }
> +
> +    //
> +    // The caller shall take the responsibility to free the buffer.
> +    //
> +    **StatusCode = ResponseMsg.Data.Response->StatusCode;
> +  }
> +
> +  if (EncodedContent != content) {
> +    FreePool (EncodedContent);
> +  }
> +
> +  if ((ResponseMsg.BodyLength != 0) && (ResponseMsg.Body != NULL)) {
> +    ret = json_loadb (ResponseMsg.Body, ResponseMsg.BodyLength, 0,
> NULL);
> +  } else {
> +    //
> +    // There is no message body returned from server.
> +    //
> +    ret = NULL;
> +  }
> +
> +ON_EXIT:
> +  if (url != NULL) {
> +    free (url);
> +  }
> +
> +  if (HttpIoHeader != NULL) {
> +    HttpIoFreeHeader (HttpIoHeader);
> +  }
> +
> +  if (RequestData != NULL) {
> +    RestConfigFreeHttpRequestData (RequestData);
> +  }
> +
> +  if (RequestMsg != NULL) {
> +    FreePool (RequestMsg);
> +  }
> +
> +  RestConfigFreeHttpMessage (&ResponseMsg, FALSE);
> +
> +  return ret;
> +}
> +
> +json_t *
> +postUriFromService (
> +  redfishService        *service,
> +  const char            *uri,
> +  const char            *content,
> +  size_t                contentLength,
> +  const char            *contentType,
> +  EFI_HTTP_STATUS_CODE  **StatusCode
> +  )
> +{
> +  char                   *url = NULL;
> +  json_t                 *ret;
> +  HTTP_IO_HEADER         *HttpIoHeader = NULL;
> +  EFI_STATUS             Status;
> +  EFI_HTTP_REQUEST_DATA  *RequestData = NULL;
> +  EFI_HTTP_MESSAGE       *RequestMsg  = NULL;
> +  EFI_HTTP_MESSAGE       ResponseMsg;
> +  CHAR8                  ContentLengthStr[80];
> +  EFI_HTTP_HEADER        *HttpHeader = NULL;
> +
> +  ret = NULL;
> +
> +  if ((service == NULL) || (uri == NULL) || (content == NULL) || (StatusCode
> == NULL)) {
> +    return NULL;
> +  }
> +
> +  *StatusCode = NULL;
> +
> +  url = makeUrlForService (service, uri);
> +  if (!url) {
> +    return NULL;
> +  }
> +
> +  DEBUG ((DEBUG_INFO, "libredfish: postUriFromService(): %a\n", url));
> +
> +  if (contentLength == 0) {
> +    contentLength = strlen (content);
> +  }
> +
> +  //
> +  // Step 1: Create HTTP request message with 4 headers:
> +  //
> +  HttpIoHeader = HttpIoCreateHeader ((service->sessionToken || service-
> >basicAuthStr) ? 8 : 7);
> +  if (HttpIoHeader == NULL) {
> +    goto ON_EXIT;
> +  }
> +
> +  if (service->sessionToken) {
> +    Status = HttpIoSetHeader (HttpIoHeader, "X-Auth-Token", service-
> >sessionToken);
> +    ASSERT_EFI_ERROR (Status);
> +  } else if (service->basicAuthStr) {
> +    Status = HttpIoSetHeader (HttpIoHeader, "Authorization", service-
> >basicAuthStr);
> +    ASSERT_EFI_ERROR (Status);
> +  }
> +
> +  if (contentType == NULL) {
> +    Status = HttpIoSetHeader (HttpIoHeader, "Content-Type",
> "application/json");
> +    ASSERT_EFI_ERROR (Status);
> +  } else {
> +    Status = HttpIoSetHeader (HttpIoHeader, "Content-Type", (CHAR8
> *)contentType);
> +    ASSERT_EFI_ERROR (Status);
> +  }
> +
> +  Status = HttpIoSetHeader (HttpIoHeader, "Host", service-
> >HostHeaderValue);
> +  ASSERT_EFI_ERROR (Status);
> +  Status = HttpIoSetHeader (HttpIoHeader, "Accept", "application/json");
> +  ASSERT_EFI_ERROR (Status);
> +  Status = HttpIoSetHeader (HttpIoHeader, "User-Agent", "libredfish");
> +  ASSERT_EFI_ERROR (Status);
> +  Status = HttpIoSetHeader (HttpIoHeader, "Connection", "Keep-Alive");
> +  ASSERT_EFI_ERROR (Status);
> +  AsciiSPrint (
> +    ContentLengthStr,
> +    sizeof (ContentLengthStr),
> +    "%lu",
> +    (UINT64)contentLength
> +    );
> +  Status = HttpIoSetHeader (HttpIoHeader, "Content-Length",
> ContentLengthStr);
> +  ASSERT_EFI_ERROR (Status);
> +  Status = HttpIoSetHeader (HttpIoHeader, "OData-Version", "4.0");
> +  ASSERT_EFI_ERROR (Status);
> +
> +  //
> +  // Step 2: build the rest of HTTP request info.
> +  //
> +  RequestData = AllocateZeroPool (sizeof (EFI_HTTP_REQUEST_DATA));
> +  if (RequestData == NULL) {
> +    goto ON_EXIT;
> +  }
> +
> +  RequestData->Method = HttpMethodPost;
> +  RequestData->Url    = C8ToC16 (url);
> +
> +  //
> +  // Step 3: fill in EFI_HTTP_MESSAGE
> +  //
> +  RequestMsg = AllocateZeroPool (sizeof (EFI_HTTP_MESSAGE));
> +  if (RequestMsg == NULL) {
> +    goto ON_EXIT;
> +  }
> +
> +  RequestMsg->Data.Request = RequestData;
> +  RequestMsg->HeaderCount  = HttpIoHeader->HeaderCount;
> +  RequestMsg->Headers      = HttpIoHeader->Headers;
> +  RequestMsg->BodyLength   = contentLength;
> +  RequestMsg->Body         = (VOID *)content;
> +
> +  ZeroMem (&ResponseMsg, sizeof (ResponseMsg));
> +
> +  //
> +  // Step 4: call RESTEx to get response from REST service.
> +  //
> +  Status = service->RestEx->SendReceive (service->RestEx, RequestMsg,
> &ResponseMsg);
> +  if (EFI_ERROR (Status)) {
> +    goto ON_EXIT;
> +  }
> +
> +  //
> +  // Step 5: Return the HTTP StatusCode and Body message.
> +  //
> +  if (ResponseMsg.Data.Response != NULL) {
> +    *StatusCode = AllocateZeroPool (sizeof (EFI_HTTP_STATUS_CODE));
> +    if (*StatusCode == NULL) {
> +      goto ON_EXIT;
> +    }
> +
> +    //
> +    // The caller shall take the responsibility to free the buffer.
> +    //
> +    **StatusCode = ResponseMsg.Data.Response->StatusCode;
> +  }
> +
> +  if ((ResponseMsg.BodyLength != 0) && (ResponseMsg.Body != NULL)) {
> +    ret = json_loadb (ResponseMsg.Body, ResponseMsg.BodyLength, 0,
> NULL);
> +  }
> +
> +  //
> +  // Step 6: Parsing the HttpHeader to retrive the X-Auth-Token if the HTTP
> StatusCode is correct.
> +  //
> +  if ((ResponseMsg.Data.Response->StatusCode == HTTP_STATUS_200_OK)
> ||
> +      (ResponseMsg.Data.Response->StatusCode ==
> HTTP_STATUS_204_NO_CONTENT))
> +  {
> +    HttpHeader = HttpFindHeader (ResponseMsg.HeaderCount,
> ResponseMsg.Headers, "X-Auth-Token");
> +    if (HttpHeader != NULL) {
> +      if (service->sessionToken) {
> +        free (service->sessionToken);
> +      }
> +
> +      service->sessionToken = AllocateCopyPool (AsciiStrSize (HttpHeader-
> >FieldValue), HttpHeader->FieldValue);
> +    }
> +
> +    /*
> +    //
> +    // Below opeation seems to be unnecessary.
> +    // Besides, the FieldValue for the Location is the full HTTP URI
> (Http://0.0.0.0:5000/XXX), so we can't use it as the
> +    // parameter of getUriFromService () directly.
> +    //
> +    HttpHeader = HttpFindHeader (ResponseMsg.HeaderCount,
> ResponseMsg.Headers, "Location");
> +    if (HttpHeader != NULL) {
> +      ret = getUriFromService(service, HttpHeader->FieldValue);
> +      goto ON_EXIT;
> +    }
> +    */
> +  }
> +
> +ON_EXIT:
> +  if (url != NULL) {
> +    free (url);
> +  }
> +
> +  if (HttpIoHeader != NULL) {
> +    HttpIoFreeHeader (HttpIoHeader);
> +  }
> +
> +  if (RequestData != NULL) {
> +    RestConfigFreeHttpRequestData (RequestData);
> +  }
> +
> +  if (RequestMsg != NULL) {
> +    FreePool (RequestMsg);
> +  }
> +
> +  RestConfigFreeHttpMessage (&ResponseMsg, FALSE);
> +
> +  return ret;
> +}
> +
> +json_t *
> +deleteUriFromService (
> +  redfishService        *service,
> +  const char            *uri,
> +  EFI_HTTP_STATUS_CODE  **StatusCode
> +  )
> +{
> +  char                   *url;
> +  json_t                 *ret;
> +  HTTP_IO_HEADER         *HttpIoHeader = NULL;
> +  EFI_STATUS             Status;
> +  EFI_HTTP_REQUEST_DATA  *RequestData = NULL;
> +  EFI_HTTP_MESSAGE       *RequestMsg  = NULL;
> +  EFI_HTTP_MESSAGE       ResponseMsg;
> +
> +  ret = NULL;
> +
> +  if ((service == NULL) || (uri == NULL) || (StatusCode == NULL)) {
> +    return NULL;
> +  }
> +
> +  *StatusCode = NULL;
> +
> +  url = makeUrlForService (service, uri);
> +  if (!url) {
> +    return NULL;
> +  }
> +
> +  DEBUG ((DEBUG_INFO, "libredfish: deleteUriFromService(): %a\n", url));
> +
> +  //
> +  // Step 1: Create HTTP request message with 4 headers:
> +  //
> +  HttpIoHeader = HttpIoCreateHeader ((service->sessionToken || service-
> >basicAuthStr) ? 5 : 4);
> +  if (HttpIoHeader == NULL) {
> +    ret = NULL;
> +    goto ON_EXIT;
> +  }
> +
> +  if (service->sessionToken) {
> +    Status = HttpIoSetHeader (HttpIoHeader, "X-Auth-Token", service-
> >sessionToken);
> +    ASSERT_EFI_ERROR (Status);
> +  } else if (service->basicAuthStr) {
> +    Status = HttpIoSetHeader (HttpIoHeader, "Authorization", service-
> >basicAuthStr);
> +    ASSERT_EFI_ERROR (Status);
> +  }
> +
> +  Status = HttpIoSetHeader (HttpIoHeader, "Host", service-
> >HostHeaderValue);
> +  ASSERT_EFI_ERROR (Status);
> +  Status = HttpIoSetHeader (HttpIoHeader, "User-Agent", "libredfish");
> +  ASSERT_EFI_ERROR (Status);
> +  Status = HttpIoSetHeader (HttpIoHeader, "OData-Version", "4.0");
> +  ASSERT_EFI_ERROR (Status);
> +  Status = HttpIoSetHeader (HttpIoHeader, "Connection", "Keep-Alive");
> +  ASSERT_EFI_ERROR (Status);
> +
> +  //
> +  // Step 2: build the rest of HTTP request info.
> +  //
> +  RequestData = AllocateZeroPool (sizeof (EFI_HTTP_REQUEST_DATA));
> +  if (RequestData == NULL) {
> +    ret = NULL;
> +    goto ON_EXIT;
> +  }
> +
> +  RequestData->Method = HttpMethodDelete;
> +  RequestData->Url    = C8ToC16 (url);
> +
> +  //
> +  // Step 3: fill in EFI_HTTP_MESSAGE
> +  //
> +  RequestMsg = AllocateZeroPool (sizeof (EFI_HTTP_MESSAGE));
> +  if (RequestMsg == NULL) {
> +    ret = NULL;
> +    goto ON_EXIT;
> +  }
> +
> +  RequestMsg->Data.Request = RequestData;
> +  RequestMsg->HeaderCount  = HttpIoHeader->HeaderCount;
> +  RequestMsg->Headers      = HttpIoHeader->Headers;
> +
> +  ZeroMem (&ResponseMsg, sizeof (ResponseMsg));
> +
> +  //
> +  // Step 4: call RESTEx to get response from REST service.
> +  //
> +  Status = service->RestEx->SendReceive (service->RestEx, RequestMsg,
> &ResponseMsg);
> +  if (EFI_ERROR (Status)) {
> +    ret = NULL;
> +    goto ON_EXIT;
> +  }
> +
> +  //
> +  // Step 5: Return the HTTP StatusCode and Body message.
> +  //
> +  if (ResponseMsg.Data.Response != NULL) {
> +    *StatusCode = AllocateZeroPool (sizeof (EFI_HTTP_STATUS_CODE));
> +    if (*StatusCode == NULL) {
> +      ret = NULL;
> +      goto ON_EXIT;
> +    }
> +
> +    //
> +    // The caller shall take the responsibility to free the buffer.
> +    //
> +    **StatusCode = ResponseMsg.Data.Response->StatusCode;
> +  }
> +
> +  if ((ResponseMsg.BodyLength != 0) && (ResponseMsg.Body != NULL)) {
> +    ret = json_loadb (ResponseMsg.Body, ResponseMsg.BodyLength, 0,
> NULL);
> +  }
> +
> +ON_EXIT:
> +  if (url != NULL) {
> +    free (url);
> +  }
> +
> +  if (HttpIoHeader != NULL) {
> +    HttpIoFreeHeader (HttpIoHeader);
> +  }
> +
> +  if (RequestData != NULL) {
> +    RestConfigFreeHttpRequestData (RequestData);
> +  }
> +
> +  if (RequestMsg != NULL) {
> +    FreePool (RequestMsg);
> +  }
> +
> +  RestConfigFreeHttpMessage (&ResponseMsg, FALSE);
> +
> +  return ret;
> +}
> +
> +redfishPayload *
> +getRedfishServiceRoot (
> +  redfishService        *service,
> +  const char            *version,
> +  EFI_HTTP_STATUS_CODE  **StatusCode
> +  )
> +{
> +  json_t      *value;
> +  json_t      *versionNode;
> +  const char  *verUrl;
> +
> +  if (version == NULL) {
> +    versionNode = json_object_get (service->versions, "v1");
> +  } else {
> +    versionNode = json_object_get (service->versions, version);
> +  }
> +
> +  if (versionNode == NULL) {
> +    return NULL;
> +  }
> +
> +  verUrl = json_string_value (versionNode);
> +  if (verUrl == NULL) {
> +    return NULL;
> +  }
> +
> +  value = getUriFromService (service, verUrl, StatusCode);
> +  if (value == NULL) {
> +    if ((service->flags & REDFISH_FLAG_SERVICE_NO_VERSION_DOC) == 0) {
> +      json_decref (versionNode);
> +    }
> +
> +    return NULL;
> +  }
> +
> +  return createRedfishPayload (value, service);
> +}
> +
> +redfishPayload *
> +getPayloadByPath (
> +  redfishService        *service,
> +  const char            *path,
> +  EFI_HTTP_STATUS_CODE  **StatusCode
> +  )
> +{
> +  redPathNode     *redpath;
> +  redfishPayload  *root;
> +  redfishPayload  *ret;
> +
> +  if (!service || !path || (StatusCode == NULL)) {
> +    return NULL;
> +  }
> +
> +  *StatusCode = NULL;
> +
> +  redpath = parseRedPath (path);
> +  if (!redpath) {
> +    return NULL;
> +  }
> +
> +  if (!redpath->isRoot) {
> +    cleanupRedPath (redpath);
> +    return NULL;
> +  }
> +
> +  root = getRedfishServiceRoot (service, redpath->version, StatusCode);
> +  if ((*StatusCode == NULL) || (**StatusCode < HTTP_STATUS_200_OK) ||
> (**StatusCode > HTTP_STATUS_206_PARTIAL_CONTENT)) {
> +    cleanupRedPath (redpath);
> +    return root;
> +  }
> +
> +  if (redpath->next == NULL) {
> +    cleanupRedPath (redpath);
> +    return root;
> +  }
> +
> +  FreePool (*StatusCode);
> +  *StatusCode = NULL;
> +
> +  ret = getPayloadForPath (root, redpath->next, StatusCode);
> +  if ((*StatusCode == NULL) && (ret != NULL)) {
> +    //
> +    // In such a case, the Redfish resource is parsed from the input payload
> (root) directly.
> +    // So, we still return HTTP_STATUS_200_OK.
> +    //
> +    *StatusCode = AllocateZeroPool (sizeof (EFI_HTTP_STATUS_CODE));
> +    if (*StatusCode == NULL) {
> +      ret = NULL;
> +    } else {
> +      **StatusCode = HTTP_STATUS_200_OK;
> +    }
> +  }
> +
> +  cleanupPayload (root);
> +  cleanupRedPath (redpath);
> +  return ret;
> +}
> +
> +void
> +cleanupServiceEnumerator (
> +  redfishService  *service
> +  )
> +{
> +  if (!service) {
> +    return;
> +  }
> +
> +  free (service->host);
> +  json_decref (service->versions);
> +  if (service->sessionToken != NULL) {
> +    ZeroMem (service->sessionToken, (UINTN)strlen (service-
> >sessionToken));
> +    FreePool (service->sessionToken);
> +  }
> +
> +  if (service->basicAuthStr != NULL) {
> +    ZeroMem (service->basicAuthStr, (UINTN)strlen (service->basicAuthStr));
> +    FreePool (service->basicAuthStr);
> +  }
> +
> +  free (service);
> +}
> +
> +static int
> +initRest (
> +  redfishService  *service,
> +  void            *restProtocol
> +  )
> +{
> +  service->RestEx = restProtocol;
> +  return 0;
> +}
> +
> +static redfishService *
> +createServiceEnumeratorNoAuth (
> +  const char    *host,
> +  const char    *rootUri,
> +  bool          enumerate,
> +  unsigned int  flags,
> +  void          *restProtocol
> +  )
> +{
> +  redfishService  *ret;
> +  char            *HostStart;
> +
> +  ret = (redfishService *)calloc (1, sizeof (redfishService));
> +  ZeroMem (ret, sizeof (redfishService));
> +  if (initRest (ret, restProtocol) != 0) {
> +    free (ret);
> +    return NULL;
> +  }
> +
> +  ret->host  = AllocateCopyPool (AsciiStrSize (host), host);
> +  ret->flags = flags;
> +  if (enumerate) {
> +    ret->versions = getVersions (ret, rootUri);
> +  }
> +
> +  HostStart = strstr (ret->host, "//");
> +  if ((HostStart != NULL) && (*(HostStart + 2) != '\0')) {
> +    ret->HostHeaderValue = HostStart + 2;
> +  }
> +
> +  return ret;
> +}
> +
> +EFI_STATUS
> +createBasicAuthStr (
> +  IN  redfishService  *service,
> +  IN  CONST CHAR8     *UserId,
> +  IN  CONST CHAR8     *Password
> +  )
> +{
> +  EFI_STATUS  Status;
> +  CHAR8       *RawAuthValue;
> +  UINTN       RawAuthBufSize;
> +  CHAR8       *EnAuthValue;
> +  UINTN       EnAuthValueSize;
> +  CHAR8       *BasicWithEnAuthValue;
> +  UINTN       BasicBufSize;
> +
> +  EnAuthValue     = NULL;
> +  EnAuthValueSize = 0;
> +
> +  RawAuthBufSize = AsciiStrLen (UserId) + AsciiStrLen (Password) + 2;
> +  RawAuthValue   = AllocatePool (RawAuthBufSize);
> +  if (RawAuthValue == NULL) {
> +    return EFI_OUT_OF_RESOURCES;
> +  }
> +
> +  //
> +  // Build raw AuthValue (UserId:Password).
> +  //
> +  AsciiSPrint (
> +    RawAuthValue,
> +    RawAuthBufSize,
> +    "%a:%a",
> +    UserId,
> +    Password
> +    );
> +
> +  //
> +  // Encoding RawAuthValue into Base64 format.
> +  //
> +  Status = Base64Encode (
> +             (CONST UINT8 *)RawAuthValue,
> +             AsciiStrLen (RawAuthValue),
> +             EnAuthValue,
> +             &EnAuthValueSize
> +             );
> +  if (Status == EFI_BUFFER_TOO_SMALL) {
> +    EnAuthValue = (CHAR8 *)AllocateZeroPool (EnAuthValueSize);
> +    if (EnAuthValue == NULL) {
> +      Status = EFI_OUT_OF_RESOURCES;
> +      return Status;
> +    }
> +
> +    Status = Base64Encode (
> +               (CONST UINT8 *)RawAuthValue,
> +               AsciiStrLen (RawAuthValue),
> +               EnAuthValue,
> +               &EnAuthValueSize
> +               );
> +  }
> +
> +  if (EFI_ERROR (Status)) {
> +    goto Exit;
> +  }
> +
> +  BasicBufSize         = AsciiStrLen ("Basic ") + AsciiStrLen (EnAuthValue) + 2;
> +  BasicWithEnAuthValue = AllocatePool (BasicBufSize);
> +  if (BasicWithEnAuthValue == NULL) {
> +    Status = EFI_OUT_OF_RESOURCES;
> +    goto Exit;
> +  }
> +
> +  //
> +  // Build encoded EnAuthValue with Basic (Basic EnAuthValue).
> +  //
> +  AsciiSPrint (
> +    BasicWithEnAuthValue,
> +    BasicBufSize,
> +    "%a %a",
> +    "Basic",
> +    EnAuthValue
> +    );
> +
> +  service->basicAuthStr = BasicWithEnAuthValue;
> +
> +Exit:
> +  if (RawAuthValue != NULL) {
> +    ZeroMem (RawAuthValue, RawAuthBufSize);
> +    FreePool (RawAuthValue);
> +  }
> +
> +  if (EnAuthValue != NULL) {
> +    ZeroMem (EnAuthValue, EnAuthValueSize);
> +    FreePool (EnAuthValue);
> +  }
> +
> +  return Status;
> +}
> +
> +static redfishService *
> +createServiceEnumeratorBasicAuth (
> +  const char    *host,
> +  const char    *rootUri,
> +  const char    *username,
> +  const char    *password,
> +  unsigned int  flags,
> +  void          *restProtocol
> +  )
> +{
> +  redfishService  *ret;
> +  EFI_STATUS      Status;
> +
> +  ret = createServiceEnumeratorNoAuth (host, rootUri, false, flags,
> restProtocol);
> +
> +  // add basic auth str
> +  Status = createBasicAuthStr (ret, username, password);
> +  if (EFI_ERROR (Status)) {
> +    cleanupServiceEnumerator (ret);
> +    return NULL;
> +  }
> +
> +  ret->versions = getVersions (ret, rootUri);
> +  return ret;
> +}
> +
> +static redfishService *
> +createServiceEnumeratorSessionAuth (
> +  const char    *host,
> +  const char    *rootUri,
> +  const char    *username,
> +  const char    *password,
> +  unsigned int  flags,
> +  void          *restProtocol
> +  )
> +{
> +  redfishService        *ret;
> +  redfishPayload        *payload;
> +  redfishPayload        *links;
> +  json_t                *sessionPayload;
> +  json_t                *session;
> +  json_t                *odataId;
> +  const char            *uri;
> +  json_t                *post;
> +  char                  *content;
> +  EFI_HTTP_STATUS_CODE  *StatusCode;
> +
> +  content    = NULL;
> +  StatusCode = NULL;
> +
> +  ret = createServiceEnumeratorNoAuth (host, rootUri, true, flags,
> restProtocol);
> +  if (ret == NULL) {
> +    return NULL;
> +  }
> +
> +  payload = getRedfishServiceRoot (ret, NULL, &StatusCode);
> +  if ((StatusCode == NULL) || (*StatusCode < HTTP_STATUS_200_OK) ||
> (*StatusCode > HTTP_STATUS_206_PARTIAL_CONTENT)) {
> +    if (StatusCode != NULL) {
> +      FreePool (StatusCode);
> +    }
> +
> +    if (payload != NULL) {
> +      cleanupPayload (payload);
> +    }
> +
> +    cleanupServiceEnumerator (ret);
> +    return NULL;
> +  }
> +
> +  if (StatusCode != NULL) {
> +    FreePool (StatusCode);
> +    StatusCode = NULL;
> +  }
> +
> +  links = getPayloadByNodeName (payload, "Links", &StatusCode);
> +  cleanupPayload (payload);
> +  if (links == NULL) {
> +    cleanupServiceEnumerator (ret);
> +    return NULL;
> +  }
> +
> +  session = json_object_get (links->json, "Sessions");
> +  if (session == NULL) {
> +    cleanupPayload (links);
> +    cleanupServiceEnumerator (ret);
> +    return NULL;
> +  }
> +
> +  odataId = json_object_get (session, "@odata.id");
> +  if (odataId == NULL) {
> +    cleanupPayload (links);
> +    cleanupServiceEnumerator (ret);
> +    return NULL;
> +  }
> +
> +  uri  = json_string_value (odataId);
> +  post = json_object ();
> +  addStringToJsonObject (post, "UserName", username);
> +  addStringToJsonObject (post, "Password", password);
> +  content = json_dumps (post, 0);
> +  json_decref (post);
> +  sessionPayload = postUriFromService (ret, uri, content, 0, NULL,
> &StatusCode);
> +
> +  if (content != NULL) {
> +    ZeroMem (content, (UINTN)strlen (content));
> +    free (content);
> +  }
> +
> +  if ((sessionPayload == NULL) || (StatusCode == NULL) || (*StatusCode <
> HTTP_STATUS_200_OK) || (*StatusCode >
> HTTP_STATUS_206_PARTIAL_CONTENT)) {
> +    // Failed to create session!
> +
> +    cleanupPayload (links);
> +    cleanupServiceEnumerator (ret);
> +
> +    if (StatusCode != NULL) {
> +      FreePool (StatusCode);
> +    }
> +
> +    if (sessionPayload != NULL) {
> +      json_decref (sessionPayload);
> +    }
> +
> +    return NULL;
> +  }
> +
> +  json_decref (sessionPayload);
> +  cleanupPayload (links);
> +  FreePool (StatusCode);
> +  return ret;
> +}
> +
> +static char *
> +makeUrlForService (
> +  redfishService  *service,
> +  const char      *uri
> +  )
> +{
> +  char  *url;
> +
> +  if (service->host == NULL) {
> +    return NULL;
> +  }
> +
> +  url = (char *)malloc (strlen (service->host)+strlen (uri)+1);
> +  strcpy (url, service->host);
> +  strcat (url, uri);
> +  return url;
> +}
> +
> +static json_t *
> +getVersions (
> +  redfishService  *service,
> +  const char      *rootUri
> +  )
> +{
> +  json_t                *ret        = NULL;
> +  EFI_HTTP_STATUS_CODE  *StatusCode = NULL;
> +
> +  if (service->flags & REDFISH_FLAG_SERVICE_NO_VERSION_DOC) {
> +    service->versions = json_object ();
> +    if (service->versions == NULL) {
> +      return NULL;
> +    }
> +
> +    addStringToJsonObject (service->versions, "v1", "/redfish/v1");
> +    return service->versions;
> +  }
> +
> +  if (rootUri != NULL) {
> +    ret = getUriFromService (service, rootUri, &StatusCode);
> +  } else {
> +    ret = getUriFromService (service, "/redfish", &StatusCode);
> +  }
> +
> +  if ((ret == NULL) || (StatusCode == NULL) || (*StatusCode <
> HTTP_STATUS_200_OK) || (*StatusCode >
> HTTP_STATUS_206_PARTIAL_CONTENT)) {
> +    if (ret != NULL) {
> +      json_decref (ret);
> +    }
> +
> +    ret = NULL;
> +  }
> +
> +  if (StatusCode != NULL) {
> +    FreePool (StatusCode);
> +  }
> +
> +  return ret;
> +}
> +
> +static void
> +addStringToJsonObject (
> +  json_t      *object,
> +  const char  *key,
> +  const char  *value
> +  )
> +{
> +  json_t  *jValue = json_string (value);
> +
> +  json_object_set (object, key, jValue);
> +
> +  json_decref (jValue);
> +}
> --
> 2.17.1

      reply	other threads:[~2023-05-05  1:16 UTC|newest]

Thread overview: 2+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2023-05-04 14:28 [edk2-redfish-client][PATCH 7/8] RedfishClientPkg: RedfishLib Nickle Wang
2023-05-05  1:15 ` Chang, Abner [this message]

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-list from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=MN2PR12MB39664E43693B46F2524DE852EA729@MN2PR12MB3966.namprd12.prod.outlook.com \
    --to=devel@edk2.groups.io \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox