public inbox for devel@edk2.groups.io
 help / color / mirror / Atom feed
* Re: [edk2-devel] [PATCH] edk2-staging/RedfishClientPkg: RedfishLib
       [not found] <16B20F2940995F11.9654@groups.io>
@ 2021-10-28  2:00 ` Abner Chang
  0 siblings, 0 replies; only message in thread
From: Abner Chang @ 2021-10-28  2:00 UTC (permalink / raw)
  To: devel@edk2.groups.io, Chang, Abner (HPS SW/FW Technologist)
  Cc: Wang, Nickle (HPS SW), Liming Gao

This patch is sent in behalf of Nickle Wang.

> -----Original Message-----
> From: devel@edk2.groups.io [mailto:devel@edk2.groups.io] On Behalf Of
> Abner Chang
> Sent: Thursday, October 28, 2021 9:58 AM
> To: devel@edk2.groups.io
> Cc: Wang, Nickle (HPS SW) <nickle.wang@hpe.com>; Liming Gao
> <gaoliming@byosoft.com.cn>
> Subject: [edk2-devel] [PATCH] edk2-staging/RedfishClientPkg: RedfishLib
> 
> (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)

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

> 
> 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 <nickle.wang@hpe.com>
> Cc: Abner Chang <abner.chang@hpe.com>
> Cc: Liming Gao <gaoliming@byosoft.com.cn>
> ---
>  RedfishClientPkg/RedfishClientPkg.dec         |    5 +
>  RedfishClientPkg/RedfishClientLibs.dsc.inc    |    4 +
>  RedfishClientPkg/RedfishClientPkg.dsc         |    3 +-
>  .../PrivateLibrary/RedfishLib/RedfishLib.inf  |   62 +
>  .../PrivateLibrary/RedfishLib/RedfishMisc.h   |   82 +
>  .../edk2libredfish/include/redfish.h          |   24 +
>  .../edk2libredfish/include/redfishPayload.h   |   39 +
>  .../edk2libredfish/include/redfishService.h   |  101 ++
>  .../edk2libredfish/include/redpath.h          |   42 +
>  .../PrivateLibrary/RedfishLib/RedfishLib.c    |  993 ++++++++++++
>  .../PrivateLibrary/RedfishLib/RedfishMisc.c   |  201 +++
>  .../RedfishLib/edk2libredfish/src/payload.c   |  732 +++++++++
>  .../RedfishLib/edk2libredfish/src/redpath.c   |  192 +++
>  .../RedfishLib/edk2libredfish/src/service.c   | 1396 +++++++++++++++++
>  14 files changed, 3875 insertions(+), 1 deletion(-)
>  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 b965f915a84..09df062dd36 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 a5ae73cac7f..4655dd7081b 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 00a963eaff1..ddc8cef1fd8 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
> +  !include RedfishClientPkg/RedfishClient.dsc.inc
> \ No newline at end of file
> diff --git a/RedfishClientPkg/PrivateLibrary/RedfishLib/RedfishLib.inf
> b/RedfishClientPkg/PrivateLibrary/RedfishLib/RedfishLib.inf
> new file mode 100644
> index 00000000000..a54e397d190
> --- /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 00000000000..d01a433d1aa
> --- /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 00000000000..de1feb22fbc
> --- /dev/null
> +++
> b/RedfishClientPkg/PrivateLibrary/RedfishLib/edk2libredfish/include/redfish
> .h
> @@ -0,0 +1,24 @@
> +/** @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 00000000000..43149f3c895
> --- /dev/null
> +++
> b/RedfishClientPkg/PrivateLibrary/RedfishLib/edk2libredfish/include/redfish
> Payload.h
> @@ -0,0 +1,39 @@
> +/** @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 00000000000..0215caccfcc
> --- /dev/null
> +++
> b/RedfishClientPkg/PrivateLibrary/RedfishLib/edk2libredfish/include/redfish
> Service.h
> @@ -0,0 +1,101 @@
> +/** @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 00000000000..24413a648a6
> --- /dev/null
> +++
> b/RedfishClientPkg/PrivateLibrary/RedfishLib/edk2libredfish/include/redpat
> h.h
> @@ -0,0 +1,42 @@
> +/** @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 00000000000..18aa4646e86
> --- /dev/null
> +++ b/RedfishClientPkg/PrivateLibrary/RedfishLib/RedfishLib.c
> @@ -0,0 +1,993 @@
> +/** @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 00000000000..7077c371548
> --- /dev/null
> +++ b/RedfishClientPkg/PrivateLibrary/RedfishLib/RedfishMisc.c
> @@ -0,0 +1,201 @@
> +/** @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 00000000000..bd8d143c4e0
> --- /dev/null
> +++
> b/RedfishClientPkg/PrivateLibrary/RedfishLib/edk2libredfish/src/payload.c
> @@ -0,0 +1,732 @@
> +/** @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 00000000000..1fb4346c2b6
> --- /dev/null
> +++
> b/RedfishClientPkg/PrivateLibrary/RedfishLib/edk2libredfish/src/redpath.c
> @@ -0,0 +1,192 @@
> +/** @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 00000000000..7713f89e6df
> --- /dev/null
> +++
> b/RedfishClientPkg/PrivateLibrary/RedfishLib/edk2libredfish/src/service.c
> @@ -0,0 +1,1396 @@
> +/** @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
> iHOsr8SLyeerAbEcgArqMRZeev30bDQRCkl9tuo3i68lbpuzRSqgWU$ ), 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.21.0.windows.1
> 
> 
> 
> 
> 


^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2021-10-28  2:01 UTC | newest]

Thread overview: (only message) (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
     [not found] <16B20F2940995F11.9654@groups.io>
2021-10-28  2:00 ` [edk2-devel] [PATCH] edk2-staging/RedfishClientPkg: RedfishLib Abner Chang

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