public inbox for devel@edk2.groups.io
 help / color / mirror / Atom feed
From: "Nickle Wang" <nickle.wang@hpe.com>
To: devel@edk2.groups.io
Cc: Abner Chang <abner.chang@amd.com>, Yang Atom <Atom.Yang@amd.com>,
	Nick Ramirez <nramirez@nvidia.com>
Subject: [edk2-staging][PATCH v2 09/15] edk2-staging/RedfishClientPkg: Update RedfishLib
Date: Mon, 25 Jul 2022 09:35:49 +0800	[thread overview]
Message-ID: <20220725013555.926-10-nickle.wang@hpe.com> (raw)
In-Reply-To: <20220725013555.926-1-nickle.wang@hpe.com>

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/redfishPayload.h b/RedfishClientPkg/PrivateLibrary/RedfishLib/edk2libredfish/include/redfishPayload.h
index 43149f3c89..be74c64297 100644
--- a/RedfishClientPkg/PrivateLibrary/RedfishLib/edk2libredfish/include/redfishPayload.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/redfishService.h b/RedfishClientPkg/PrivateLibrary/RedfishLib/edk2libredfish/include/redfishService.h
index 0215caccfc..3d87fad85a 100644
--- a/RedfishClientPkg/PrivateLibrary/RedfishLib/edk2libredfish/include/redfishService.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/payload.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/service.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 (Http://0.0.0.0:5000/XXX), so we can't use it as the
+    // parameter of getUriFromService () directly.
+    //
+    HttpHeader = HttpFindHeader (ResponseMsg.HeaderCount, ResponseMsg.Headers, "Location");
+    if (HttpHeader != NULL) {
+      ret = getUriFromService(service, HttpHeader->FieldValue);
+      goto ON_EXIT;
+    }
+    */
+  }
+
+ON_EXIT:
+  if (url != NULL) {
+    free (url);
+  }
+
+  if (HttpIoHeader != NULL) {
+    HttpIoFreeHeader (HttpIoHeader);
+  }
+
+  if (RequestData != NULL) {
+    RestConfigFreeHttpRequestData (RequestData);
+  }
+
+  if (RequestMsg != NULL) {
+    FreePool (RequestMsg);
+  }
+
+  RestConfigFreeHttpMessage (&ResponseMsg, FALSE);
+
+  return ret;
+}
+
 json_t* 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


  parent reply	other threads:[~2022-07-25  1:36 UTC|newest]

Thread overview: 22+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2022-07-25  1:35 [edk2-staging][PATCH v2 00/15] Update RedfishClientpkg Nickle Wang
2022-07-25  1:35 ` [edk2-staging][PATCH v2 01/15] edk2-staging/RedfishClientPkg: Introduce Redfish event library Nickle Wang
2022-07-26  1:40   ` Chang, Abner
2022-07-25  1:35 ` [edk2-staging][PATCH v2 02/15] edk2-staging/RedfishClientPkg: Introduce Redfish version library Nickle Wang
2022-07-26  1:46   ` Chang, Abner
2022-07-25  1:35 ` [edk2-staging][PATCH v2 03/15] edk2-staging/RedfishClientPkg: Update Redfish Resource Config Protocol Nickle Wang
2022-07-26  1:49   ` Chang, Abner
2022-07-25  1:35 ` [edk2-staging][PATCH v2 04/15] edk2-staging/RedfishClientPkg: Introduce Redfish resource config library Nickle Wang
2022-07-26  1:58   ` Chang, Abner
2022-07-25  1:35 ` [edk2-staging][PATCH v2 05/15] edk2-staging/RedfishClientPkg: Introduce resource identify library Nickle Wang
2022-07-26  2:04   ` Chang, Abner
2022-07-27  1:39     ` Nickle Wang
2022-07-25  1:35 ` [edk2-staging][PATCH v2 06/15] edk2-staging/RedfishClientPkg: Introduce RedfishConfigLangMap driver Nickle Wang
2022-07-25  1:35 ` [edk2-staging][PATCH v2 07/15] edk2-staging/RedfishClientPkg: Update ETag driver Nickle Wang
2022-07-25  1:35 ` [edk2-staging][PATCH v2 08/15] edk2-staging/RedfishClientPkg: Update Redfish feature core driver Nickle Wang
2022-07-25  1:35 ` Nickle Wang [this message]
2022-07-25  1:35 ` [edk2-staging][PATCH v2 10/15] edk2-staging/RedfishClientPkg: Update Redfish feature utility library Nickle Wang
2022-07-25  1:35 ` [edk2-staging][PATCH v2 11/15] edk2-staging/RedfishClientPkg: Rename RedfishMemoryCollection driver Nickle Wang
2022-07-25  1:35 ` [edk2-staging][PATCH v2 12/15] edk2-staging/RedfishClientPkg: Rename Memory feature driver Nickle Wang
2022-07-25  1:35 ` [edk2-staging][PATCH v2 13/15] edk2-staging/RedfishClientPkg: Introduce Computer System collection driver Nickle Wang
2022-07-25  1:35 ` [edk2-staging][PATCH v2 14/15] edk2-staging/RedfishClientPkg: Introduce Computer System feature driver Nickle Wang
2022-07-25  1:35 ` [edk2-staging][PATCH v2 15/15] edk2-staging/RedfishClientPkg: Introduce Bios " 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=20220725013555.926-10-nickle.wang@hpe.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