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