public inbox for devel@edk2.groups.io
 help / color / mirror / Atom feed
From: "Chang, Abner via groups.io" <abner.chang=amd.com@groups.io>
To: Nickle Wang <nicklew@nvidia.com>,
	"devel@edk2.groups.io" <devel@edk2.groups.io>
Cc: Igor Kulchytskyy <igork@ami.com>, Nick Ramirez <nramirez@nvidia.com>
Subject: Re: [edk2-devel] [edk2-redfish-client][PATCH] RedfishClientPkg/RedfishLib: align with edk2 RedfishLib
Date: Wed, 1 Nov 2023 04:00:05 +0000	[thread overview]
Message-ID: <MN2PR12MB39666004BF48B5E8E16B8907EAA7A@MN2PR12MB3966.namprd12.prod.outlook.com> (raw)
In-Reply-To: <20231026083503.20169-1-nicklew@nvidia.com>

[AMD Official Use Only - General]

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

> -----Original Message-----
> From: Nickle Wang <nicklew@nvidia.com>
> Sent: Thursday, October 26, 2023 4:35 PM
> To: devel@edk2.groups.io
> Cc: Chang, Abner <Abner.Chang@amd.com>; Igor Kulchytskyy
> <igork@ami.com>; Nick Ramirez <nramirez@nvidia.com>
> Subject: [edk2-redfish-client][PATCH] RedfishClientPkg/RedfishLib: align with
> edk2 RedfishLib
>
> Caution: This message originated from an External Source. Use proper caution
> when opening attachments, clicking links, or responding.
>
>
> Update RedfishLib to align with RedfishLib in edk2 repository.
> RedfishLib commits on edk2:
> cf68ff61 RedfishPkg/RedfishLib: introduce new interfaces.
> 1cbdd6e9 RedfishPkg/libredfish: introduce new interfaces.
> 8765f3eb RedfishPkg/RedfishLib: return HTTP headers to caller.
>
> Signed-off-by: Nickle Wang <nicklew@nvidia.com>
> Cc: Abner Chang <abner.chang@amd.com>
> Cc: Igor Kulchytskyy <igork@ami.com>
> Cc: Nick Ramirez <nramirez@nvidia.com>
> ---
>  .../PrivateLibrary/RedfishLib/RedfishLib.inf  |   1 +
>  .../edk2libredfish/include/redfishPayload.h   |  32 +-
>  .../edk2libredfish/include/redfishService.h   |  21 +
>  .../PrivateLibrary/RedfishLib/RedfishLib.c    | 345 +++++++++++-
>  .../PrivateLibrary/RedfishLib/RedfishMisc.c   |  13 +-
>  .../RedfishLib/edk2libredfish/src/payload.c   | 124 +---
>  .../RedfishLib/edk2libredfish/src/service.c   | 531 ++++++------------
>  7 files changed, 527 insertions(+), 540 deletions(-)
>
> diff --git a/RedfishClientPkg/PrivateLibrary/RedfishLib/RedfishLib.inf
> b/RedfishClientPkg/PrivateLibrary/RedfishLib/RedfishLib.inf
> index a54e397d..79d8792f 100644
> --- a/RedfishClientPkg/PrivateLibrary/RedfishLib/RedfishLib.inf
> +++ b/RedfishClientPkg/PrivateLibrary/RedfishLib/RedfishLib.inf
> @@ -3,6 +3,7 @@
>  #
>  #  Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
>  #  (C) Copyright 2021 Hewlett Packard Enterprise Development LP<BR>
> +#  Copyright (c) 2023, NVIDIA CORPORATION & AFFILIATES. All rights
> reserved.
>  #
>  #    SPDX-License-Identifier: BSD-2-Clause-Patent
>  #
> diff --git
> a/RedfishClientPkg/PrivateLibrary/RedfishLib/edk2libredfish/include/redfishP
> ayload.h
> b/RedfishClientPkg/PrivateLibrary/RedfishLib/edk2libredfish/include/redfishP
> ayload.h
> index 8403d693..f7917603 100644
> ---
> a/RedfishClientPkg/PrivateLibrary/RedfishLib/edk2libredfish/include/redfishP
> ayload.h
> +++
> b/RedfishClientPkg/PrivateLibrary/RedfishLib/edk2libredfish/include/redfishP
> ayload.h
> @@ -10,6 +10,7 @@
>
>    Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
>    (C) Copyright 2021-2022 Hewlett Packard Enterprise Development LP<BR>
> +  Copyright (c) 2023, NVIDIA CORPORATION & AFFILIATES. All rights
> reserved.
>
>    SPDX-License-Identifier: BSD-2-Clause-Patent
>
> @@ -19,7 +20,7 @@
>  #define LIBREDFISH_REDFISH_PAYLOAD_H_
>
>  #include <Include/Library/RedfishCrtLib.h>
> -
> +#include <Library/JsonLib.h>
>  #include <jansson.h>
>  #include <redfishService.h>
>  #include <redpath.h>
> @@ -65,15 +66,6 @@ patchPayload (
>    EFI_HTTP_STATUS_CODE  **StatusCode
>    );
>
> -redfishPayload *
> -patchPayloadEx (
> -  redfishPayload        *target,
> -  redfishPayload        *payload,
> -  EFI_HTTP_HEADER       **Headers,
> -  UINTN                 *HeaderCount,
> -  EFI_HTTP_STATUS_CODE  **StatusCode
> -  );
> -
>  redfishPayload *
>  postContentToPayload (
>    redfishPayload        *target,
> @@ -83,17 +75,6 @@ postContentToPayload (
>    EFI_HTTP_STATUS_CODE  **StatusCode
>    );
>
> -redfishPayload *
> -postContentToPayloadEx (
> -  redfishPayload        *target,
> -  const char            *data,
> -  size_t                dataSize,
> -  const char            *contentType,
> -  EFI_HTTP_HEADER       **Headers,
> -  UINTN                 *HeaderCount,
> -  EFI_HTTP_STATUS_CODE  **StatusCode
> -  );
> -
>  redfishPayload *
>  postPayload (
>    redfishPayload        *target,
> @@ -101,15 +82,6 @@ postPayload (
>    EFI_HTTP_STATUS_CODE  **StatusCode
>    );
>
> -redfishPayload *
> -postPayloadEx (
> -  redfishPayload        *target,
> -  redfishPayload        *payload,
> -  EFI_HTTP_HEADER       **Headers,
> -  UINTN                 *HeaderCount,
> -  EFI_HTTP_STATUS_CODE  **StatusCode
> -  );
> -
>  void
>  cleanupPayload (
>    redfishPayload  *payload
> diff --git
> a/RedfishClientPkg/PrivateLibrary/RedfishLib/edk2libredfish/include/redfishS
> ervice.h
> b/RedfishClientPkg/PrivateLibrary/RedfishLib/edk2libredfish/include/redfishS
> ervice.h
> index c41c0d14..c2e0fd32 100644
> ---
> a/RedfishClientPkg/PrivateLibrary/RedfishLib/edk2libredfish/include/redfishS
> ervice.h
> +++
> b/RedfishClientPkg/PrivateLibrary/RedfishLib/edk2libredfish/include/redfishS
> ervice.h
> @@ -10,6 +10,7 @@
>
>    Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
>    (C) Copyright 2021-2022 Hewlett Packard Enterprise Development LP<BR>
> +  Copyright (c) 2023, NVIDIA CORPORATION & AFFILIATES. All rights
> reserved.
>
>    SPDX-License-Identifier: BSD-2-Clause-Patent
>
> @@ -153,6 +154,18 @@ postUriFromServiceEx (
>    EFI_HTTP_STATUS_CODE  **StatusCode
>    );
>
> +json_t *
> +putUriFromServiceEx (
> +  redfishService        *service,
> +  const char            *uri,
> +  const char            *content,
> +  size_t                contentLength,
> +  const char            *contentType,
> +  EFI_HTTP_HEADER       **Headers,
> +  UINTN                 *HeaderCount,
> +  EFI_HTTP_STATUS_CODE  **StatusCode
> +  );
> +
>  json_t *
>  deleteUriFromService (
>    redfishService        *service,
> @@ -160,6 +173,14 @@ deleteUriFromService (
>    EFI_HTTP_STATUS_CODE  **StatusCode
>    );
>
> +json_t *
> +deleteUriFromServiceEx (
> +  redfishService        *service,
> +  const char            *uri,
> +  const char            *content,
> +  EFI_HTTP_STATUS_CODE  **StatusCode
> +  );
> +
>  redfishPayload *
>  getRedfishServiceRoot (
>    redfishService        *service,
> diff --git a/RedfishClientPkg/PrivateLibrary/RedfishLib/RedfishLib.c
> b/RedfishClientPkg/PrivateLibrary/RedfishLib/RedfishLib.c
> index c00b15f6..8a4483b4 100644
> --- a/RedfishClientPkg/PrivateLibrary/RedfishLib/RedfishLib.c
> +++ b/RedfishClientPkg/PrivateLibrary/RedfishLib/RedfishLib.c
> @@ -4,6 +4,7 @@
>
>    Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
>    (C) Copyright 2021-2022 Hewlett Packard Enterprise Development LP<BR>
> +  Copyright (c) 2023, NVIDIA CORPORATION & AFFILIATES. All rights
> reserved.
>
>    SPDX-License-Identifier: BSD-2-Clause-Patent
>
> @@ -167,6 +168,30 @@ RedfishJsonInPayload (
>    return ((redfishPayload *)Payload)->json;
>  }
>
> +/**
> +  This function returns the Redfish service of a REDFISH_PAYLOAD.
> +
> +  Caller doesn't need to free the returned JSON value because it will be
> released
> +  in corresponding RedfishCleanupService() function.
> +
> +  @param[in]    Payload     A REDFISH_PAYLOAD instance.
> +
> +  @return     Redfish service of the payload.
> +
> +**/
> +REDFISH_SERVICE
> +EFIAPI
> +RedfishServiceInPayload (
> +  IN REDFISH_PAYLOAD  Payload
> +  )
> +{
> +  if (Payload == NULL) {
> +    return NULL;
> +  }
> +
> +  return ((redfishPayload *)Payload)->service;
> +}
> +
>  /**
>    Fill the input RedPath string with system UUID from SMBIOS table or use the
> customized
>    ID if  FromSmbios == FALSE.
> @@ -244,7 +269,7 @@ RedfishBuildPathWithSystemUuid (
>                                        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
> +  @retval EFI_SUCCESS             The operation 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.
> @@ -304,7 +329,7 @@ RedfishGetByService (
>    @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
> +  @retval EFI_SUCCESS             The operation 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.
> @@ -367,7 +392,7 @@ RedfishGetByUri (
>    @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:
> +  @retval EFI_SUCCESS             The operation 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.
> @@ -440,7 +465,7 @@ RedfishGetByPayload (
>    @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
> +  @retval EFI_SUCCESS             The operation 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.
> @@ -473,10 +498,12 @@ RedfishPatchToUri (
>
>    ZeroMem (RedResponse, sizeof (REDFISH_RESPONSE));
>
> -  JsonValue = (EDKII_JSON_VALUE)patchUriFromService (
> +  JsonValue = (EDKII_JSON_VALUE)patchUriFromServiceEx (
>                                    RedfishService,
>                                    Uri,
>                                    Content,
> +                                  &(RedResponse->Headers),
> +                                  &(RedResponse->HeaderCount),
>                                    &(RedResponse->StatusCode)
>                                    );
>
> @@ -527,10 +554,10 @@ ON_EXIT:
>    redfish response data.
>
>    @param[in]    Target           The target payload to be updated.
> -  @param[in]    Payload          Palyoad with properties to be changed.
> +  @param[in]    Payload          Payload 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
> +  @retval EFI_SUCCESS             The operation 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.
> @@ -556,11 +583,9 @@ RedfishPatchToPayload (
>
>    ZeroMem (RedResponse, sizeof (REDFISH_RESPONSE));
>
> -  RedResponse->Payload = (REDFISH_PAYLOAD)patchPayloadEx (
> +  RedResponse->Payload = (REDFISH_PAYLOAD)patchPayload (
>                                              Target,
>                                              Payload,
> -                                            &RedResponse->Headers,
> -                                            &RedResponse->HeaderCount,
>                                              &(RedResponse->StatusCode)
>                                              );
>
> @@ -585,6 +610,104 @@ RedfishPatchToPayload (
>    return EFI_SUCCESS;
>  }
>
> +/**
> +  Use HTTP POST to create new Redfish resource in the Resource Collection.
> +
> +  The POST request should be submitted to the Resource Collection in which
> the new resource
> +  is to belong. The Resource Collection is addressed by URI. 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]    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[in]    ContentSize           Size of the Content to be send to Redfish
> service
> +  @param[in]    ContentType           Type of the Content to be send to Redfish
> service
> +  @param[out]   RedResponse           Pointer to the Redfish response data.
> +
> +  @retval EFI_SUCCESS             The operation 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
> +RedfishPostToUri (
> +  IN     REDFISH_SERVICE   RedfishService,
> +  IN     CONST CHAR8       *Uri,
> +  IN     CONST CHAR8       *Content,
> +  IN     UINTN             ContentSize OPTIONAL,
> +  IN     CONST CHAR8       *ContentType OPTIONAL,
> +  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)postUriFromServiceEx (
> +                                  RedfishService,
> +                                  Uri,
> +                                  Content,
> +                                  ContentSize,
> +                                  ContentType,
> +                                  &(RedResponse->Headers),
> +                                  &(RedResponse->HeaderCount),
> +                                  &(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 POST to create a new resource in target payload.
>
> @@ -600,7 +723,7 @@ RedfishPatchToPayload (
>    @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
> +  @retval EFI_SUCCESS             The operation 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.
> @@ -626,11 +749,9 @@ RedfishPostToPayload (
>
>    ZeroMem (RedResponse, sizeof (REDFISH_RESPONSE));
>
> -  RedResponse->Payload = (REDFISH_PAYLOAD)postPayloadEx (
> +  RedResponse->Payload = (REDFISH_PAYLOAD)postPayload (
>                                              Target,
>                                              Payload,
> -                                            &RedResponse->Headers,
> -                                            &RedResponse->HeaderCount,
>                                              &(RedResponse->StatusCode)
>                                              );
>
> @@ -670,7 +791,7 @@ RedfishPostToPayload (
>    @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
> +  @retval EFI_SUCCESS             The operation 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.
> @@ -742,6 +863,96 @@ ON_EXIT:
>    return Status;
>  }
>
> +/**
> +  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[in]    Content               JSON represented properties to be deleted.
> +  @param[out]   RedResponse           Pointer to the Redfish response data.
> +
> +  @retval EFI_SUCCESS             The operation 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
> +RedfishDeleteByUriEx (
> +  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) || (Content == NULL) || (Uri == NULL) ||
> (RedResponse == NULL)) {
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  ZeroMem (RedResponse, sizeof (REDFISH_RESPONSE));
> +
> +  JsonValue = (EDKII_JSON_VALUE)deleteUriFromServiceEx (
> +                                  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;
> +}
> +
>  /**
>    Dump text in fractions.
>
> @@ -878,7 +1089,7 @@ RedfishFreeResponse (
>    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]  OdataTypeName            OdataType will be retrieved from
> mapping list.
>    @param[in]  OdataTypeMappingList     The list of OdataType.
>    @param[in]  OdataTypeMappingListSize The number of mapping list
>
> @@ -945,7 +1156,7 @@ RedfishIsPayloadCollection (
>    @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_SUCCESS              Collection size is returned in CollectionSize
>    @return EFI_INVALID_PARAMETER    The payload is not a collection.
>  **/
>  EFI_STATUS
> @@ -1035,3 +1246,103 @@ RedfishCheckIfRedpathExist (
>
>    return EFI_SUCCESS;
>  }
> +
> +/**
> +  Use HTTP PUT to create new Redfish resource in the Resource Collection.
> +
> +  This function uses the RedfishService to put 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[in]    ContentSize           Size of the Content to be send to Redfish
> service
> +  @param[in]    ContentType           Type of the Content to be send to Redfish
> service
> +  @param[out]   RedResponse           Pointer to the Redfish response data.
> +
> +  @retval EFI_SUCCESS             The operation 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
> +RedfishPutToUri (
> +  IN     REDFISH_SERVICE   RedfishService,
> +  IN     CONST CHAR8       *Uri,
> +  IN     CONST CHAR8       *Content,
> +  IN     UINTN             ContentSize OPTIONAL,
> +  IN     CONST CHAR8       *ContentType OPTIONAL,
> +  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)putUriFromServiceEx (
> +                                  RedfishService,
> +                                  Uri,
> +                                  Content,
> +                                  ContentSize,
> +                                  ContentType,
> +                                  &(RedResponse->Headers),
> +                                  &(RedResponse->HeaderCount),
> +                                  &(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;
> +}
> diff --git a/RedfishClientPkg/PrivateLibrary/RedfishLib/RedfishMisc.c
> b/RedfishClientPkg/PrivateLibrary/RedfishLib/RedfishMisc.c
> index 0eb23196..b6e9a111 100644
> --- a/RedfishClientPkg/PrivateLibrary/RedfishLib/RedfishMisc.c
> +++ b/RedfishClientPkg/PrivateLibrary/RedfishLib/RedfishMisc.c
> @@ -3,6 +3,7 @@
>
>    Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
>    (C) Copyright 2021 Hewlett Packard Enterprise Development LP<BR>
> +  Copyright (c) 2023, NVIDIA CORPORATION & AFFILIATES. All rights
> reserved.
>
>    SPDX-License-Identifier: BSD-2-Clause-Patent
>
> @@ -168,18 +169,18 @@ RedfishGetAuthInfo (
>  /**
>    This function returns the string of Redfish service version.
>
> -  @param[in]   ServiceVerisonStr The string of Redfish service version.
> +  @param[in]   ServiceVersionStr 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
> +  @param[out]  Redpath           Pointer to retrieved Redpath, caller has to free
>                                   the memory allocated for this string.
>    @return     EFI_STATUS
>
>  **/
>  EFI_STATUS
>  RedfishBuildRedpathUseId (
> -  IN  CHAR8  *ServiceVerisonStr,
> +  IN  CHAR8  *ServiceVersionStr,
>    IN  CHAR8  *Url,
>    IN  CHAR8  *Id,
>    OUT CHAR8  **Redpath
> @@ -187,12 +188,12 @@ RedfishBuildRedpathUseId (
>  {
>    UINTN  RedpathSize;
>
> -  if ((Redpath == NULL) || (ServiceVerisonStr == NULL) || (Url == NULL) || (Id
> == NULL)) {
> +  if ((Redpath == NULL) || (ServiceVersionStr == NULL) || (Url == NULL) || (Id
> == NULL)) {
>      return EFI_INVALID_PARAMETER;
>    }
>
>    RedpathSize = AsciiStrLen ("/") +
> -                AsciiStrLen (ServiceVerisonStr) +
> +                AsciiStrLen (ServiceVersionStr) +
>                  AsciiStrLen (Url) +
>                  AsciiStrLen ("[Id=]") +
>                  AsciiStrLen (Id) + 1;
> @@ -201,6 +202,6 @@ RedfishBuildRedpathUseId (
>      return EFI_OUT_OF_RESOURCES;
>    }
>
> -  AsciiSPrint (*Redpath, RedpathSize, "/%a%a[Id=%a]", ServiceVerisonStr, Url,
> Id);
> +  AsciiSPrint (*Redpath, RedpathSize, "/%a%a[Id=%a]", ServiceVersionStr, Url,
> Id);
>    return EFI_SUCCESS;
>  }
> diff --git
> a/RedfishClientPkg/PrivateLibrary/RedfishLib/edk2libredfish/src/payload.c
> b/RedfishClientPkg/PrivateLibrary/RedfishLib/edk2libredfish/src/payload.c
> index 8ec2ed4a..39803575 100644
> --- a/RedfishClientPkg/PrivateLibrary/RedfishLib/edk2libredfish/src/payload.c
> +++
> b/RedfishClientPkg/PrivateLibrary/RedfishLib/edk2libredfish/src/payload.c
> @@ -10,6 +10,7 @@
>
>    Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
>    (C) Copyright 2021-2022 Hewlett Packard Enterprise Development LP<BR>
> +  Copyright (c) 2023, NVIDIA CORPORATION & AFFILIATES. All rights
> reserved.
>
>    SPDX-License-Identifier: BSD-2-Clause-Patent
>
> @@ -379,45 +380,6 @@ getPayloadForPathString (
>    return ret;
>  }
>
> -redfishPayload *
> -patchPayloadEx (
> -  redfishPayload        *target,
> -  redfishPayload        *payload,
> -  EFI_HTTP_HEADER       **Headers,
> -  UINTN                 *HeaderCount,
> -  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 = patchUriFromServiceEx (target->service, uri, content, Headers,
> HeaderCount, StatusCode);
> -  free (uri);
> -  free (content);
> -  if (json == NULL) {
> -    return NULL;
> -  }
> -
> -  return createRedfishPayload (json, target->service);
> -}
> -
>  redfishPayload *
>  patchPayload (
>    redfishPayload        *target,
> @@ -455,44 +417,6 @@ patchPayload (
>    return createRedfishPayload (json, target->service);
>  }
>
> -redfishPayload *
> -postContentToPayloadEx (
> -  redfishPayload        *target,
> -  const char            *data,
> -  size_t                dataSize,
> -  const char            *contentType,
> -  EFI_HTTP_HEADER       **Headers,
> -  UINTN                 *HeaderCount,
> -  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 = postUriFromServiceEx (target->service, uri, data, dataSize,
> contentType, Headers, HeaderCount, StatusCode);
> -  free (uri);
> -  if (json == NULL) {
> -    return NULL;
> -  }
> -
> -  return createRedfishPayload (json, target->service);
> -}
> -
>  redfishPayload *
>  postContentToPayload (
>    redfishPayload        *target,
> @@ -529,34 +453,6 @@ postContentToPayload (
>    return createRedfishPayload (json, target->service);
>  }
>
> -redfishPayload *
> -postPayloadEx (
> -  redfishPayload        *target,
> -  redfishPayload        *payload,
> -  EFI_HTTP_HEADER       **Headers,
> -  UINTN                 *HeaderCount,
> -  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     = postContentToPayloadEx (target, content, strlen (content), NULL,
> Headers, HeaderCount, StatusCode);
> -  free (content);
> -  return ret;
> -}
> -
>  redfishPayload *
>  postPayload (
>    redfishPayload        *target,
> @@ -629,7 +525,7 @@ getOpResult (
>    }
>
>    stringProp = prop->json;
> -  jsonType   =  json_get_type (prop->json);
> +  jsonType   = JsonGetType (prop->json);
>    switch (jsonType) {
>      case JSON_OBJECT:
>        stringProp = json_object_get (prop->json, propName);
> @@ -725,6 +621,7 @@ collectionEvalOp (
>    if (((*StatusCode == NULL) && (members == NULL)) ||
>        ((*StatusCode != NULL) && ((**StatusCode < HTTP_STATUS_200_OK) ||
> (**StatusCode > HTTP_STATUS_206_PARTIAL_CONTENT))))
>    {
> +    free (valid);
>      return members;
>    }
>
> @@ -738,6 +635,7 @@ collectionEvalOp (
>      if (((*StatusCode == NULL) && (tmp == NULL)) ||
>          ((*StatusCode != NULL) && ((**StatusCode < HTTP_STATUS_200_OK) ||
> (**StatusCode > HTTP_STATUS_206_PARTIAL_CONTENT))))
>      {
> +      free (valid);
>        return tmp;
>      }
>
> @@ -763,19 +661,15 @@ collectionEvalOp (
>
>    cleanupPayload (members);
>    if (validCount == 0) {
> -    free (valid);
> -    return NULL;
> -  }
> -
> -  if (validCount == 1) {
> +    ret = NULL;
> +  } else if (validCount == 1) {
>      ret = valid[0];
> -    free (valid);
> -    return ret;
>    } else {
>      ret = createCollection (payload->service, validCount, valid);
> -    free (valid);
> -    return ret;
>    }
> +
> +  free (valid);
> +  return ret;
>  }
>
>  static redfishPayload *
> diff --git
> a/RedfishClientPkg/PrivateLibrary/RedfishLib/edk2libredfish/src/service.c
> b/RedfishClientPkg/PrivateLibrary/RedfishLib/edk2libredfish/src/service.c
> index a38bdfbe..58c23e8c 100644
> --- a/RedfishClientPkg/PrivateLibrary/RedfishLib/edk2libredfish/src/service.c
> +++
> b/RedfishClientPkg/PrivateLibrary/RedfishLib/edk2libredfish/src/service.c
> @@ -10,6 +10,7 @@
>
>    Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
>    (C) Copyright 2021-2022 Hewlett Packard Enterprise Development LP<BR>
> +  Copyright (c) 2023, NVIDIA CORPORATION & AFFILIATES. All rights
> reserved.
>
>    SPDX-License-Identifier: BSD-2-Clause-Patent
>
> @@ -279,9 +280,9 @@ DecodeResponseContent (
>  **/
>  EFI_STATUS
>  RedfishBuildUrl (
> -  IN  REDFISH_CONFIG_SERVICE_INFORMATION *RedfishConfigServiceInfo,
> -  IN  CHAR16 *RelativePath, OPTIONAL
> -  OUT CHAR16                        **HttpUrl
> +  IN  REDFISH_CONFIG_SERVICE_INFORMATION  *RedfishConfigServiceInfo,
> +  IN  CHAR16                              *RelativePath    OPTIONAL,
> +  OUT CHAR16                              **HttpUrl
>    )
>  {
>    CHAR16  *Url;
> @@ -434,8 +435,8 @@ json_t *
>  getUriFromServiceEx (
>    redfishService        *service,
>    const char            *uri,
> -  EFI_HTTP_HEADER       **Headers,
> -  UINTN                 *HeaderCount,
> +  EFI_HTTP_HEADER       **Headers OPTIONAL,
> +  UINTN                 *HeaderCount OPTIONAL,
>    EFI_HTTP_STATUS_CODE  **StatusCode
>    )
>  {
> @@ -448,20 +449,25 @@ getUriFromServiceEx (
>    EFI_HTTP_MESSAGE       ResponseMsg;
>    EFI_HTTP_HEADER        *ContentEncodedHeader;
>
> -  if ((service == NULL) || (uri == NULL) || (Headers == NULL) || (HeaderCount
> == NULL) || (StatusCode == NULL)) {
> +  if ((service == NULL) || (uri == NULL) || (StatusCode == NULL)) {
>      return NULL;
>    }
>
> -  *StatusCode  = NULL;
> -  *HeaderCount = 0;
> -  *Headers     = NULL;
> +  *StatusCode = NULL;
> +  if (HeaderCount != NULL) {
> +    *HeaderCount = 0;
> +  }
> +
> +  if (Headers != NULL) {
> +    *Headers = NULL;
> +  }
>
>    url = makeUrlForService (service, uri);
>    if (!url) {
>      return NULL;
>    }
>
> -  DEBUG ((DEBUG_MANAGEABILITY, "libredfish: getUriFromServiceEx():
> %a\n", url));
> +  DEBUG ((DEBUG_MANAGEABILITY, "%a: %a\n", __func__, url));
>
>    //
>    // Step 1: Create HTTP request message with 4 headers:
> @@ -524,166 +530,23 @@ getUriFromServiceEx (
>    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.
> +    // Deliver status code to caller when error happens so caller can do error
> handling.
>      //
> -    **StatusCode = ResponseMsg.Data.Response->StatusCode;
> -  }
> -
> -  if (ResponseMsg.Headers != NULL) {
> -    *Headers = cloneHttpHeaders (&ResponseMsg, HeaderCount);
> -  }
> -
> -  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.", __func__, Status));
> +    if (ResponseMsg.Data.Response != NULL) {
> +      *StatusCode = AllocateZeroPool (sizeof (EFI_HTTP_STATUS_CODE));
> +      if (*StatusCode == NULL) {
>          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 *
> -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_MANAGEABILITY, "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));
> +      //
> +      // The caller shall take the responsibility to free the buffer.
> +      //
> +      **StatusCode = ResponseMsg.Data.Response->StatusCode;
> +    }
>
> -  //
> -  // 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;
>    }
>
> @@ -703,6 +566,10 @@ getUriFromService (
>      **StatusCode = ResponseMsg.Data.Response->StatusCode;
>    }
>
> +  if ((ResponseMsg.Headers != NULL) && (Headers != NULL) &&
> (HeaderCount != NULL)) {
> +    *Headers = cloneHttpHeaders (&ResponseMsg, HeaderCount);
> +  }
> +
>    if ((ResponseMsg.BodyLength != 0) && (ResponseMsg.Body != NULL)) {
>      //
>      // Check if data is encoded.
> @@ -751,12 +618,14 @@ ON_EXIT:
>  }
>
>  json_t *
> -patchUriFromServiceEx (
> +putUriFromServiceEx (
>    redfishService        *service,
>    const char            *uri,
>    const char            *content,
> -  EFI_HTTP_HEADER       **Headers,
> -  UINTN                 *HeaderCount,
> +  size_t                contentLength,
> +  const char            *contentType,
> +  EFI_HTTP_HEADER       **Headers OPTIONAL,
> +  UINTN                 *HeaderCount OPTIONAL,
>    EFI_HTTP_STATUS_CODE  **StatusCode
>    )
>  {
> @@ -776,18 +645,29 @@ patchUriFromServiceEx (
>    }
>
>    *StatusCode = NULL;
> +  if (HeaderCount != NULL) {
> +    *HeaderCount = 0;
> +  }
> +
> +  if (Headers != NULL) {
> +    *Headers = NULL;
> +  }
>
>    url = makeUrlForService (service, uri);
> -  if (!url) {
> +  if (url == NULL) {
>      return NULL;
>    }
>
> -  DEBUG ((DEBUG_MANAGEABILITY, "libredfish: patchUriFromService():
> %a\n", url));
> +  DEBUG ((DEBUG_MANAGEABILITY, "%a: %a\n", __func__, url));
> +
> +  if (contentLength == 0) {
> +    contentLength = strlen (content);
> +  }
>
>    //
>    // Step 1: Create HTTP request message with 4 headers:
>    //
> -  HttpIoHeader = HttpIoCreateHeader ((service->sessionToken || service-
> >basicAuthStr) ? 9 : 8);
> +  HttpIoHeader = HttpIoCreateHeader ((service->sessionToken != NULL ||
> service->basicAuthStr != NULL) ? 9 : 8);
>    if (HttpIoHeader == NULL) {
>      ret = NULL;
>      goto ON_EXIT;
> @@ -801,6 +681,14 @@ patchUriFromServiceEx (
>      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, "Content-Type",
> "application/json");
> @@ -816,7 +704,7 @@ patchUriFromServiceEx (
>      ContentLengthStr,
>      sizeof (ContentLengthStr),
>      "%lu",
> -    (UINT64)strlen (content)
> +    (UINT64)contentLength
>      );
>    Status = HttpIoSetHeader (HttpIoHeader, "Content-Length",
> ContentLengthStr);
>    ASSERT_EFI_ERROR (Status);
> @@ -832,7 +720,7 @@ patchUriFromServiceEx (
>      goto ON_EXIT;
>    }
>
> -  RequestData->Method = HttpMethodPatch;
> +  RequestData->Method = HttpMethodPut;
>    RequestData->Url    = C8ToC16 (url);
>
>    //
> @@ -845,7 +733,7 @@ patchUriFromServiceEx (
>    }
>
>    EncodedContent    = (CHAR8 *)content;
> -  EncodedContentLen = strlen (content);
> +  EncodedContentLen = contentLength;
>    //
>    // We currently only support gzip Content-Encoding.
>    //
> @@ -896,7 +784,7 @@ patchUriFromServiceEx (
>      **StatusCode = ResponseMsg.Data.Response->StatusCode;
>    }
>
> -  if (ResponseMsg.Headers != NULL) {
> +  if ((ResponseMsg.Headers != NULL) && (Headers != NULL) &&
> (HeaderCount != NULL)) {
>      *Headers = cloneHttpHeaders (&ResponseMsg, HeaderCount);
>    }
>
> @@ -936,10 +824,12 @@ ON_EXIT:
>  }
>
>  json_t *
> -patchUriFromService (
> +patchUriFromServiceEx (
>    redfishService        *service,
>    const char            *uri,
>    const char            *content,
> +  EFI_HTTP_HEADER       **Headers OPTIONAL,
> +  UINTN                 *HeaderCount OPTIONAL,
>    EFI_HTTP_STATUS_CODE  **StatusCode
>    )
>  {
> @@ -959,13 +849,20 @@ patchUriFromService (
>    }
>
>    *StatusCode = NULL;
> +  if (HeaderCount != NULL) {
> +    *HeaderCount = 0;
> +  }
> +
> +  if (Headers != NULL) {
> +    *Headers = NULL;
> +  }
>
>    url = makeUrlForService (service, uri);
>    if (!url) {
>      return NULL;
>    }
>
> -  DEBUG ((DEBUG_MANAGEABILITY, "libredfish: patchUriFromService():
> %a\n", url));
> +  DEBUG ((DEBUG_MANAGEABILITY, "%a: %a\n", __func__, url));
>
>    //
>    // Step 1: Create HTTP request message with 4 headers:
> @@ -1079,6 +976,10 @@ patchUriFromService (
>      **StatusCode = ResponseMsg.Data.Response->StatusCode;
>    }
>
> +  if ((ResponseMsg.Headers != NULL) && (Headers != NULL) &&
> (HeaderCount != NULL)) {
> +    *Headers = cloneHttpHeaders (&ResponseMsg, HeaderCount);
> +  }
> +
>    if (EncodedContent != content) {
>      FreePool (EncodedContent);
>    }
> @@ -1121,8 +1022,8 @@ postUriFromServiceEx (
>    const char            *content,
>    size_t                contentLength,
>    const char            *contentType,
> -  EFI_HTTP_HEADER       **Headers,
> -  UINTN                 *HeaderCount,
> +  EFI_HTTP_HEADER       **Headers OPTIONAL,
> +  UINTN                 *HeaderCount OPTIONAL,
>    EFI_HTTP_STATUS_CODE  **StatusCode
>    )
>  {
> @@ -1143,13 +1044,20 @@ postUriFromServiceEx (
>    }
>
>    *StatusCode = NULL;
> +  if (HeaderCount != NULL) {
> +    *HeaderCount = 0;
> +  }
> +
> +  if (Headers != NULL) {
> +    *Headers = NULL;
> +  }
>
>    url = makeUrlForService (service, uri);
>    if (!url) {
>      return NULL;
>    }
>
> -  DEBUG ((DEBUG_MANAGEABILITY, "libredfish: postUriFromService():
> %a\n", url));
> +  DEBUG ((DEBUG_MANAGEABILITY, "%a: %a\n", __func__, url));
>
>    if (contentLength == 0) {
>      contentLength = strlen (content);
> @@ -1230,7 +1138,12 @@ postUriFromServiceEx (
>    //
>    Status = service->RestEx->SendReceive (service->RestEx, RequestMsg,
> &ResponseMsg);
>    if (EFI_ERROR (Status)) {
> -    goto ON_EXIT;
> +    //
> +    // If there is no response to handle, go to error exit.
> +    //
> +    if (ResponseMsg.Data.Response == NULL) {
> +      goto ON_EXIT;
> +    }
>    }
>
>    //
> @@ -1248,7 +1161,7 @@ postUriFromServiceEx (
>      **StatusCode = ResponseMsg.Data.Response->StatusCode;
>    }
>
> -  if (ResponseMsg.Headers != NULL) {
> +  if ((ResponseMsg.Headers != NULL) && (Headers != NULL) &&
> (HeaderCount != NULL)) {
>      *Headers = cloneHttpHeaders (&ResponseMsg, HeaderCount);
>    }
>
> @@ -1257,10 +1170,11 @@ postUriFromServiceEx (
>    }
>
>    //
> -  // Step 6: Parsing the HttpHeader to retrive the X-Auth-Token if the HTTP
> StatusCode is correct.
> +  // Step 6: Parsing the HttpHeader to retrieve 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))
> +  if ((ResponseMsg.Data.Response != NULL) &&
> +      ((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) {
> @@ -1270,19 +1184,6 @@ postUriFromServiceEx (
>
>        service->sessionToken = AllocateCopyPool (AsciiStrSize (HttpHeader-
> >FieldValue), HttpHeader->FieldValue);
>      }
> -
> -    /*
> -    //
> -    // Below opeation seems to be unnecessary.
> -    // Besides, the FieldValue for the Location is the full HTTP URI
> (Http://0.0.0.0:5000/XXX), so we can't use it as the
> -    // parameter of getUriFromService () directly.
> -    //
> -    HttpHeader = HttpFindHeader (ResponseMsg.HeaderCount,
> ResponseMsg.Headers, "Location");
> -    if (HttpHeader != NULL) {
> -      ret = getUriFromService(service, HttpHeader->FieldValue);
> -      goto ON_EXIT;
> -    }
> -    */
>    }
>
>  ON_EXIT:
> @@ -1307,6 +1208,27 @@ ON_EXIT:
>    return ret;
>  }
>
> +json_t *
> +getUriFromService (
> +  redfishService        *service,
> +  const char            *uri,
> +  EFI_HTTP_STATUS_CODE  **StatusCode
> +  )
> +{
> +  return getUriFromServiceEx (service, uri, NULL, NULL, StatusCode);
> +}
> +
> +json_t *
> +patchUriFromService (
> +  redfishService        *service,
> +  const char            *uri,
> +  const char            *content,
> +  EFI_HTTP_STATUS_CODE  **StatusCode
> +  )
> +{
> +  return patchUriFromServiceEx (service, uri, content, NULL, NULL,
> StatusCode);
> +}
> +
>  json_t *
>  postUriFromService (
>    redfishService        *service,
> @@ -1317,187 +1239,14 @@ postUriFromService (
>    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_MANAGEABILITY, "libredfish: postUriFromService():
> %a\n", url));
> -
> -  if (contentLength == 0) {
> -    contentLength = strlen (content);
> -  }
> -
> -  //
> -  // Step 1: Create HTTP request message with 4 headers:
> -  //
> -  HttpIoHeader = HttpIoCreateHeader ((service->sessionToken || service-
> >basicAuthStr) ? 8 : 7);
> -  if (HttpIoHeader == NULL) {
> -    goto ON_EXIT;
> -  }
> -
> -  if (service->sessionToken) {
> -    Status = HttpIoSetHeader (HttpIoHeader, "X-Auth-Token", service-
> >sessionToken);
> -    ASSERT_EFI_ERROR (Status);
> -  } else if (service->basicAuthStr) {
> -    Status = HttpIoSetHeader (HttpIoHeader, "Authorization", service-
> >basicAuthStr);
> -    ASSERT_EFI_ERROR (Status);
> -  }
> -
> -  if (contentType == NULL) {
> -    Status = HttpIoSetHeader (HttpIoHeader, "Content-Type",
> "application/json");
> -    ASSERT_EFI_ERROR (Status);
> -  } else {
> -    Status = HttpIoSetHeader (HttpIoHeader, "Content-Type", (CHAR8
> *)contentType);
> -    ASSERT_EFI_ERROR (Status);
> -  }
> -
> -  Status = HttpIoSetHeader (HttpIoHeader, "Host", service-
> >HostHeaderValue);
> -  ASSERT_EFI_ERROR (Status);
> -  Status = HttpIoSetHeader (HttpIoHeader, "Accept", "application/json");
> -  ASSERT_EFI_ERROR (Status);
> -  Status = HttpIoSetHeader (HttpIoHeader, "User-Agent", "libredfish");
> -  ASSERT_EFI_ERROR (Status);
> -  Status = HttpIoSetHeader (HttpIoHeader, "Connection", "Keep-Alive");
> -  ASSERT_EFI_ERROR (Status);
> -  AsciiSPrint (
> -    ContentLengthStr,
> -    sizeof (ContentLengthStr),
> -    "%lu",
> -    (UINT64)contentLength
> -    );
> -  Status = HttpIoSetHeader (HttpIoHeader, "Content-Length",
> ContentLengthStr);
> -  ASSERT_EFI_ERROR (Status);
> -  Status = HttpIoSetHeader (HttpIoHeader, "OData-Version", "4.0");
> -  ASSERT_EFI_ERROR (Status);
> -
> -  //
> -  // Step 2: build the rest of HTTP request info.
> -  //
> -  RequestData = AllocateZeroPool (sizeof (EFI_HTTP_REQUEST_DATA));
> -  if (RequestData == NULL) {
> -    goto ON_EXIT;
> -  }
> -
> -  RequestData->Method = HttpMethodPost;
> -  RequestData->Url    = C8ToC16 (url);
> -
> -  //
> -  // Step 3: fill in EFI_HTTP_MESSAGE
> -  //
> -  RequestMsg = AllocateZeroPool (sizeof (EFI_HTTP_MESSAGE));
> -  if (RequestMsg == NULL) {
> -    goto ON_EXIT;
> -  }
> -
> -  RequestMsg->Data.Request = RequestData;
> -  RequestMsg->HeaderCount  = HttpIoHeader->HeaderCount;
> -  RequestMsg->Headers      = HttpIoHeader->Headers;
> -  RequestMsg->BodyLength   = contentLength;
> -  RequestMsg->Body         = (VOID *)content;
> -
> -  ZeroMem (&ResponseMsg, sizeof (ResponseMsg));
> -
> -  //
> -  // Step 4: call RESTEx to get response from REST service.
> -  //
> -  Status = service->RestEx->SendReceive (service->RestEx, RequestMsg,
> &ResponseMsg);
> -  if (EFI_ERROR (Status)) {
> -    goto ON_EXIT;
> -  }
> -
> -  //
> -  // Step 5: Return the HTTP StatusCode and Body message.
> -  //
> -  if (ResponseMsg.Data.Response != NULL) {
> -    *StatusCode = AllocateZeroPool (sizeof (EFI_HTTP_STATUS_CODE));
> -    if (*StatusCode == NULL) {
> -      goto ON_EXIT;
> -    }
> -
> -    //
> -    // The caller shall take the responsibility to free the buffer.
> -    //
> -    **StatusCode = ResponseMsg.Data.Response->StatusCode;
> -  }
> -
> -  if ((ResponseMsg.BodyLength != 0) && (ResponseMsg.Body != NULL)) {
> -    ret = json_loadb (ResponseMsg.Body, ResponseMsg.BodyLength, 0, NULL);
> -  }
> -
> -  //
> -  // Step 6: Parsing the HttpHeader to retrive the X-Auth-Token if the HTTP
> StatusCode is correct.
> -  //
> -  if ((ResponseMsg.Data.Response->StatusCode == HTTP_STATUS_200_OK)
> ||
> -      (ResponseMsg.Data.Response->StatusCode ==
> HTTP_STATUS_204_NO_CONTENT))
> -  {
> -    HttpHeader = HttpFindHeader (ResponseMsg.HeaderCount,
> ResponseMsg.Headers, "X-Auth-Token");
> -    if (HttpHeader != NULL) {
> -      if (service->sessionToken) {
> -        free (service->sessionToken);
> -      }
> -
> -      service->sessionToken = AllocateCopyPool (AsciiStrSize (HttpHeader-
> >FieldValue), HttpHeader->FieldValue);
> -    }
> -
> -    /*
> -    //
> -    // Below opeation seems to be unnecessary.
> -    // Besides, the FieldValue for the Location is the full HTTP URI
> (Http://0.0.0.0:5000/XXX), so we can't use it as the
> -    // parameter of getUriFromService () directly.
> -    //
> -    HttpHeader = HttpFindHeader (ResponseMsg.HeaderCount,
> ResponseMsg.Headers, "Location");
> -    if (HttpHeader != NULL) {
> -      ret = getUriFromService(service, HttpHeader->FieldValue);
> -      goto ON_EXIT;
> -    }
> -    */
> -  }
> -
> -ON_EXIT:
> -  if (url != NULL) {
> -    free (url);
> -  }
> -
> -  if (HttpIoHeader != NULL) {
> -    HttpIoFreeHeader (HttpIoHeader);
> -  }
> -
> -  if (RequestData != NULL) {
> -    RestConfigFreeHttpRequestData (RequestData);
> -  }
> -
> -  if (RequestMsg != NULL) {
> -    FreePool (RequestMsg);
> -  }
> -
> -  RestConfigFreeHttpMessage (&ResponseMsg, FALSE);
> -
> -  return ret;
> +  return postUriFromServiceEx (service, uri, content, contentLength,
> contentType, NULL, NULL, StatusCode);
>  }
>
>  json_t *
> -deleteUriFromService (
> +deleteUriFromServiceEx (
>    redfishService        *service,
>    const char            *uri,
> +  const char            *content,
>    EFI_HTTP_STATUS_CODE  **StatusCode
>    )
>  {
> @@ -1508,6 +1257,8 @@ deleteUriFromService (
>    EFI_HTTP_REQUEST_DATA  *RequestData = NULL;
>    EFI_HTTP_MESSAGE       *RequestMsg  = NULL;
>    EFI_HTTP_MESSAGE       ResponseMsg;
> +  CHAR8                  ContentLengthStr[80];
> +  size_t                 contentLength;
>
>    ret = NULL;
>
> @@ -1527,7 +1278,7 @@ deleteUriFromService (
>    //
>    // Step 1: Create HTTP request message with 4 headers:
>    //
> -  HttpIoHeader = HttpIoCreateHeader ((service->sessionToken || service-
> >basicAuthStr) ? 5 : 4);
> +  HttpIoHeader = HttpIoCreateHeader ((service->sessionToken || service-
> >basicAuthStr) ? 8 : 7);
>    if (HttpIoHeader == NULL) {
>      ret = NULL;
>      goto ON_EXIT;
> @@ -1550,6 +1301,23 @@ deleteUriFromService (
>    Status = HttpIoSetHeader (HttpIoHeader, "Connection", "Keep-Alive");
>    ASSERT_EFI_ERROR (Status);
>
> +  Status = HttpIoSetHeader (HttpIoHeader, "Content-Type",
> "application/json");
> +  ASSERT_EFI_ERROR (Status);
> +
> +  if (content != NULL) {
> +    contentLength = strlen (content);
> +    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.
>    //
> @@ -1575,6 +1343,11 @@ deleteUriFromService (
>    RequestMsg->HeaderCount  = HttpIoHeader->HeaderCount;
>    RequestMsg->Headers      = HttpIoHeader->Headers;
>
> +  if (content != NULL) {
> +    RequestMsg->BodyLength = contentLength;
> +    RequestMsg->Body       = (VOID *)content;
> +  }
> +
>    ZeroMem (&ResponseMsg, sizeof (ResponseMsg));
>
>    //
> @@ -1628,6 +1401,16 @@ ON_EXIT:
>    return ret;
>  }
>
> +json_t *
> +deleteUriFromService (
> +  redfishService        *service,
> +  const char            *uri,
> +  EFI_HTTP_STATUS_CODE  **StatusCode
> +  )
> +{
> +  return deleteUriFromServiceEx (service, uri, NULL, StatusCode);
> +}
> +
>  redfishPayload *
>  getRedfishServiceRoot (
>    redfishService        *service,
> @@ -2034,6 +1817,10 @@ makeUrlForService (
>    }
>
>    url = (char *)malloc (strlen (service->host)+strlen (uri)+1);
> +  if (url == NULL) {
> +    return NULL;
> +  }
> +
>    strcpy (url, service->host);
>    strcat (url, uri);
>    return url;
> --
> 2.17.1



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



      reply	other threads:[~2023-11-01  4:00 UTC|newest]

Thread overview: 2+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2023-10-26  8:35 [edk2-devel] [edk2-redfish-client][PATCH] RedfishClientPkg/RedfishLib: align with edk2 RedfishLib Nickle Wang via groups.io
2023-11-01  4:00 ` Chang, Abner via groups.io [this message]

Reply instructions:

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

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

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

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

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

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

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