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