public inbox for devel@edk2.groups.io
 help / color / mirror / Atom feed
From: "Chang, Abner" <abner.chang@amd.com>
To: Nickle Wang <nickle.wang@hpe.com>,
	"devel@edk2.groups.io" <devel@edk2.groups.io>
Cc: "Yang, Atom" <Atom.Yang@amd.com>, Nick Ramirez <nramirez@nvidia.com>
Subject: Re: [edk2-staging][PATCH v3 09/15] edk2-staging/RedfishClientPkg: Update RedfishLib
Date: Thu, 28 Jul 2022 02:51:06 +0000	[thread overview]
Message-ID: <MN2PR12MB396616C8B4D56F72F807D5AAEA969@MN2PR12MB3966.namprd12.prod.outlook.com> (raw)
In-Reply-To: <20220727013802.247-10-nickle.wang@hpe.com>

[AMD Official Use Only - General]

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

> -----Original Message-----
> From: Nickle Wang <nickle.wang@hpe.com>
> Sent: Wednesday, July 27, 2022 9:38 AM
> To: devel@edk2.groups.io
> Cc: Chang, Abner <Abner.Chang@amd.com>; Yang, Atom
> <Atom.Yang@amd.com>; Nick Ramirez <nramirez@nvidia.com>
> Subject: [edk2-staging][PATCH v3 09/15] edk2-staging/RedfishClientPkg:
> Update RedfishLib
> 
> [CAUTION: External Email]
> 
> RedfishLib has no capability to return HTTP header in response.
> However, feature driver needs to know the information like "ETag" or
> "Location" in HTTP response header per Redfish specification. Add
> corresponding function to return HTTP header in response data.
> 
> Signed-off-by: Nickle Wang <nickle.wang@hpe.com>
> Cc: Abner Chang <abner.chang@amd.com>
> Cc: Yang Atom <Atom.Yang@amd.com>
> Cc: Nick Ramirez <nramirez@nvidia.com>
> ---
>  .../PrivateLibrary/RedfishLib/RedfishLib.c    |  12 +-
>  .../edk2libredfish/include/redfishPayload.h   |   5 +-
>  .../edk2libredfish/include/redfishService.h   |   5 +-
>  .../RedfishLib/edk2libredfish/src/payload.c   |  90 ++-
>  .../RedfishLib/edk2libredfish/src/service.c   | 554 +++++++++++++++++-
>  5 files changed, 657 insertions(+), 9 deletions(-)
> 
> diff --git a/RedfishClientPkg/PrivateLibrary/RedfishLib/RedfishLib.c
> b/RedfishClientPkg/PrivateLibrary/RedfishLib/RedfishLib.c
> index 18aa4646e8..b8ca493e24 100644
> --- a/RedfishClientPkg/PrivateLibrary/RedfishLib/RedfishLib.c
> +++ b/RedfishClientPkg/PrivateLibrary/RedfishLib/RedfishLib.c
> @@ -3,7 +3,7 @@
>    (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>
> +  (C) Copyright 2021-2022 Hewlett Packard Enterprise Development LP<BR>
> 
>    SPDX-License-Identifier: BSD-2-Clause-Patent
> 
> @@ -323,7 +323,7 @@ RedfishGetByUri (
> 
>    ZeroMem (RedResponse, sizeof (REDFISH_RESPONSE));
> 
> -  JsonValue = getUriFromService (RedfishService, Uri, &RedResponse-
> >StatusCode);
> +  JsonValue = getUriFromServiceEx (RedfishService, Uri,
> + &RedResponse->Headers, &RedResponse->HeaderCount,
> + &RedResponse->StatusCode);
>    RedResponse->Payload = createRedfishPayload(JsonValue, RedfishService);
> 
>    //
> @@ -541,9 +541,11 @@ RedfishPatchToPayload (
> 
>    ZeroMem (RedResponse, sizeof (REDFISH_RESPONSE));
> 
> -  RedResponse->Payload = (REDFISH_PAYLOAD) patchPayload (
> +  RedResponse->Payload = (REDFISH_PAYLOAD) patchPayloadEx (
>                                               Target,
>                                               Payload,
> +                                             &RedResponse->Headers,
> +                                             &RedResponse->HeaderCount,
>                                               &(RedResponse->StatusCode)
>                                               );
> 
> @@ -607,9 +609,11 @@ RedfishPostToPayload (
> 
>    ZeroMem (RedResponse, sizeof (REDFISH_RESPONSE));
> 
> -  RedResponse->Payload = (REDFISH_PAYLOAD) postPayload (
> +  RedResponse->Payload = (REDFISH_PAYLOAD) postPayloadEx (
>                                               Target,
>                                               Payload,
> +                                             &RedResponse->Headers,
> +                                             &RedResponse->HeaderCount,
>                                               &(RedResponse->StatusCode)
>                                               );
> 
> diff --git
> a/RedfishClientPkg/PrivateLibrary/RedfishLib/edk2libredfish/include/redfish
> Payload.h
> b/RedfishClientPkg/PrivateLibrary/RedfishLib/edk2libredfish/include/redfish
> Payload.h
> index 43149f3c89..be74c64297 100644
> ---
> a/RedfishClientPkg/PrivateLibrary/RedfishLib/edk2libredfish/include/redfish
> Payload.h
> +++ b/RedfishClientPkg/PrivateLibrary/RedfishLib/edk2libredfish/include/
> +++ redfishPayload.h
> @@ -9,7 +9,7 @@
>  //----------------------------------------------------------------------------
> 
>    Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
> -  (C) Copyright 2021 Hewlett Packard Enterprise Development LP<BR>
> +  (C) Copyright 2021-2022 Hewlett Packard Enterprise Development LP<BR>
> 
>    SPDX-License-Identifier: BSD-2-Clause-Patent
> 
> @@ -29,8 +29,11 @@ redfishPayload* getPayloadByIndex(redfishPayload*
> payload, size_t index, EFI_HTT
>  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* patchPayloadEx(redfishPayload* target, redfishPayload*
> +payload, EFI_HTTP_HEADER **Headers, UINTN *HeaderCount,
> +EFI_HTTP_STATUS_CODE** StatusCode);
>  redfishPayload* postContentToPayload(redfishPayload* target, const char*
> data, size_t dataSize, const char* contentType, 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, redfishPayload*
> payload, 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);
>  bool            isPayloadCollection (redfishPayload *Payload);
>  size_t          getCollectionSize(redfishPayload* payload);
> diff --git
> a/RedfishClientPkg/PrivateLibrary/RedfishLib/edk2libredfish/include/redfish
> Service.h
> b/RedfishClientPkg/PrivateLibrary/RedfishLib/edk2libredfish/include/redfish
> Service.h
> index 0215caccfc..3d87fad85a 100644
> ---
> a/RedfishClientPkg/PrivateLibrary/RedfishLib/edk2libredfish/include/redfish
> Service.h
> +++ b/RedfishClientPkg/PrivateLibrary/RedfishLib/edk2libredfish/include/
> +++ redfishService.h
> @@ -9,7 +9,7 @@
>  //----------------------------------------------------------------------------
> 
>    Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
> -  (C) Copyright 2021 Hewlett Packard Enterprise Development LP<BR>
> +  (C) Copyright 2021-2022 Hewlett Packard Enterprise Development LP<BR>
> 
>    SPDX-License-Identifier: BSD-2-Clause-Patent
> 
> @@ -91,8 +91,11 @@ typedef struct {
>  #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* getUriFromServiceEx(redfishService* service, const char* uri,
> +EFI_HTTP_HEADER **Headers, UINTN *HeaderCount,
> EFI_HTTP_STATUS_CODE
> +**StatusCode);
>  json_t* patchUriFromService(redfishService* service, const char* uri, const
> char* content, EFI_HTTP_STATUS_CODE** StatusCode);
> +json_t* patchUriFromServiceEx(redfishService* service, const char* uri,
> +const char* content, EFI_HTTP_HEADER **Headers, UINTN *HeaderCount,
> +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* postUriFromServiceEx(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, 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); diff --git
> a/RedfishClientPkg/PrivateLibrary/RedfishLib/edk2libredfish/src/payload.c
> b/RedfishClientPkg/PrivateLibrary/RedfishLib/edk2libredfish/src/payload.c
> index bd8d143c4e..8b49bec0df 100644
> ---
> a/RedfishClientPkg/PrivateLibrary/RedfishLib/edk2libredfish/src/payload.c
> +++ b/RedfishClientPkg/PrivateLibrary/RedfishLib/edk2libredfish/src/payl
> +++ oad.c
> @@ -9,7 +9,7 @@
>  //----------------------------------------------------------------------------
> 
>    Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
> -  (C) Copyright 2021 Hewlett Packard Enterprise Development LP<BR>
> +  (C) Copyright 2021-2022 Hewlett Packard Enterprise Development LP<BR>
> 
>    SPDX-License-Identifier: BSD-2-Clause-Patent
> 
> @@ -326,6 +326,40 @@ redfishPayload*
> getPayloadForPathString(redfishPayload* payload, const char* str
>      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, redfishPayload*
> payload, EFI_HTTP_STATUS_CODE** StatusCode)  {
>    json_t* json;
> @@ -360,6 +394,38 @@ redfishPayload* patchPayload(redfishPayload*
> target, redfishPayload* payload, EF
>    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, const char*
> data, size_t dataSize, const char* contentType, EFI_HTTP_STATUS_CODE**
> StatusCode)  {
>      json_t* json;
> @@ -392,6 +458,28 @@ redfishPayload*
> postContentToPayload(redfishPayload* target, const char* data, s
>      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, redfishPayload*
> payload, EFI_HTTP_STATUS_CODE** StatusCode)  {
>      char* content;
> diff --git
> a/RedfishClientPkg/PrivateLibrary/RedfishLib/edk2libredfish/src/service.c
> b/RedfishClientPkg/PrivateLibrary/RedfishLib/edk2libredfish/src/service.c
> index 7713f89e6d..450fa78bbd 100644
> --- a/RedfishClientPkg/PrivateLibrary/RedfishLib/edk2libredfish/src/service.c
> +++ b/RedfishClientPkg/PrivateLibrary/RedfishLib/edk2libredfish/src/serv
> +++ ice.c
> @@ -9,7 +9,7 @@
>  //----------------------------------------------------------------------------
> 
>    Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
> -  (C) Copyright 2021 Hewlett Packard Enterprise Development LP<BR>
> +  (C) Copyright 2021-2022 Hewlett Packard Enterprise Development LP<BR>
> 
>    SPDX-License-Identifier: BSD-2-Clause-Patent
> 
> @@ -338,6 +338,190 @@ ON_EXIT:
>    return ret;
>  }
> 
> +EFI_HTTP_HEADER *cloneHttpHeaders(EFI_HTTP_MESSAGE *message,
> UINTN
> +*HeaderCount) {
> +  EFI_HTTP_HEADER *Buffer;
> +  UINTN           Index;
> +
> +  if (message == NULL || HeaderCount == NULL) {
> +    return NULL;
> +  }
> +
> +  *HeaderCount = message->HeaderCount;
> +  Buffer = AllocatePool (sizeof (EFI_HTTP_HEADER) *
> + message->HeaderCount);  if (Buffer == NULL) {
> +    return NULL;
> +  }
> +
> +  for (Index = 0; Index < message->HeaderCount; Index++) {
> +    Buffer[Index].FieldName = AllocateCopyPool (AsciiStrSize (message-
> >Headers[Index].FieldName), message->Headers[Index].FieldName);
> +    ASSERT (Buffer[Index].FieldName != NULL);
> +    Buffer[Index].FieldValue = AllocateCopyPool (AsciiStrSize (message-
> >Headers[Index].FieldValue), message->Headers[Index].FieldValue);
> +    ASSERT (Buffer[Index].FieldValue != NULL);  }
> +
> +  return Buffer;
> +}
> +
> +json_t* getUriFromServiceEx(redfishService* service, const char* uri,
> +EFI_HTTP_HEADER **Headers, UINTN *HeaderCount,
> 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 || Headers == NULL || HeaderCount
> + == NULL ||StatusCode == NULL)  {
> +      return NULL;
> +  }
> +
> +  *StatusCode = NULL;
> +  *HeaderCount = 0;
> +  *Headers = NULL;
> +
> +  url = makeUrlForService(service, uri);
> +  if(!url)
> +  {
> +      return NULL;
> +  }
> +
> +  DEBUG((DEBUG_INFO, "libredfish: getUriFromServiceEx(): %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.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.", __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* getUriFromService(redfishService* service, const char* uri,
> EFI_HTTP_STATUS_CODE** StatusCode)  {
>    char* url;
> @@ -491,7 +675,7 @@ ON_EXIT:
>    return ret;
>  }
> 
> -json_t* patchUriFromService(redfishService* service, const char* uri, const
> char* content, EFI_HTTP_STATUS_CODE** StatusCode)
> +json_t* patchUriFromServiceEx(redfishService* service, const char* uri,
> +const char* content, EFI_HTTP_HEADER **Headers, UINTN *HeaderCount,
> +EFI_HTTP_STATUS_CODE** StatusCode)
>  {
>    char*               url;
>    json_t*             ret;
> @@ -632,6 +816,10 @@ json_t* patchUriFromService(redfishService*
> service, const char* uri, const char
>      **StatusCode = ResponseMsg.Data.Response->StatusCode;
>    }
> 
> +  if (ResponseMsg.Headers != NULL) {
> +    *Headers = cloneHttpHeaders (&ResponseMsg, HeaderCount);  }
> +
>    if (EncodedContent != content) {
>      FreePool (EncodedContent);
>    }
> @@ -668,6 +856,368 @@ ON_EXIT:
>    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* postUriFromServiceEx(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) {
> +  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.Headers != NULL) {
> +    *Headers = cloneHttpHeaders (&ResponseMsg, HeaderCount);  }
> +
> +  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
> (https://nam11.safelinks.protection.outlook.com/?url=http%3A%2F%2F0.0.0
> .0%3A5000%2FXXX&amp;data=05%7C01%7Cabner.chang%40amd.com%7C90
> 03fefe404646f2d91808da6f70b041%7C3dd8961fe4884e608e11a82d994e183d
> %7C0%7C0%7C637944827040099707%7CUnknown%7CTWFpbGZsb3d8eyJWIj
> oiMC4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C3
> 000%7C%7C%7C&amp;sdata=tSmhlKBno3bHdyIGn2N5ESjfCdp%2FYUEYC%2F
> Kqj9azORg%3D&amp;reserved=0), 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* postUriFromService(redfishService* service, const char* uri, const
> char* content, size_t contentLength, const char* contentType,
> EFI_HTTP_STATUS_CODE** StatusCode)  {
>    char*               url = NULL;
> --
> 2.32.0.windows.2

  reply	other threads:[~2022-07-28  2:51 UTC|newest]

Thread overview: 30+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2022-07-27  1:37 [edk2-staging][PATCH v3 00/15] Update RedfishClientpkg Nickle Wang
2022-07-27  1:37 ` [edk2-staging][PATCH v3 01/15] edk2-staging/RedfishClientPkg: Introduce Redfish event library Nickle Wang
2022-07-27  1:37 ` [edk2-staging][PATCH v3 02/15] edk2-staging/RedfishClientPkg: Introduce Redfish version library Nickle Wang
2022-07-27  1:37 ` [edk2-staging][PATCH v3 03/15] edk2-staging/RedfishClientPkg: Update Redfish Resource Config Protocol Nickle Wang
2022-07-27  1:37 ` [edk2-staging][PATCH v3 04/15] edk2-staging/RedfishClientPkg: Introduce Redfish resource config library Nickle Wang
2022-07-28  0:34   ` Chang, Abner
2022-07-27  1:37 ` [edk2-staging][PATCH v3 05/15] edk2-staging/RedfishClientPkg: Introduce resource identify library Nickle Wang
2022-07-27 15:48   ` Chang, Abner
2022-07-27  1:37 ` [edk2-staging][PATCH v3 06/15] edk2-staging/RedfishClientPkg: Introduce RedfishConfigLangMap driver Nickle Wang
2022-07-28  1:44   ` Chang, Abner
2022-07-27  1:37 ` [edk2-staging][PATCH v3 07/15] edk2-staging/RedfishClientPkg: Update ETag driver Nickle Wang
2022-07-28  1:45   ` Chang, Abner
2022-07-27  1:37 ` [edk2-staging][PATCH v3 08/15] edk2-staging/RedfishClientPkg: Update Redfish feature core driver Nickle Wang
2022-07-28  2:25   ` Chang, Abner
2022-07-27  1:37 ` [edk2-staging][PATCH v3 09/15] edk2-staging/RedfishClientPkg: Update RedfishLib Nickle Wang
2022-07-28  2:51   ` Chang, Abner [this message]
2022-07-27  1:37 ` [edk2-staging][PATCH v3 10/15] edk2-staging/RedfishClientPkg: Update Redfish feature utility library Nickle Wang
2022-07-28  3:13   ` Chang, Abner
2022-07-28  3:14     ` Chang, Abner
2022-07-27  1:37 ` [edk2-staging][PATCH v3 11/15] edk2-staging/RedfishClientPkg: Rename RedfishMemoryCollection driver Nickle Wang
2022-07-28  3:41   ` Chang, Abner
2022-07-27  1:37 ` [edk2-staging][PATCH v3 12/15] edk2-staging/RedfishClientPkg: Rename Memory feature driver Nickle Wang
2022-07-28  3:43   ` Chang, Abner
2022-07-27  1:38 ` [edk2-staging][PATCH v3 13/15] edk2-staging/RedfishClientPkg: Introduce Computer System collection driver Nickle Wang
2022-07-28  3:46   ` Chang, Abner
2022-07-27  1:38 ` [edk2-staging][PATCH v3 14/15] edk2-staging/RedfishClientPkg: Introduce Computer System feature driver Nickle Wang
2022-07-28  3:48   ` Chang, Abner
2022-07-27  1:38 ` [edk2-staging][PATCH v3 15/15] edk2-staging/RedfishClientPkg: Introduce Bios " Nickle Wang
2022-07-28  3:48   ` Chang, Abner
2022-07-29  0:29     ` Nickle Wang

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=MN2PR12MB396616C8B4D56F72F807D5AAEA969@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