* [edk2-redfish-client][PATCH 3/4] RedfishClientPkg: Update RedfishLib
@ 2023-05-10 8:23 Nickle Wang
2023-05-10 8:26 ` Chang, Abner
0 siblings, 1 reply; 2+ messages in thread
From: Nickle Wang @ 2023-05-10 8:23 UTC (permalink / raw)
To: devel; +Cc: Abner Chang, Igor Kulchytskyy
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 <nicklew@nvidia.com>
Cc: Abner Chang <abner.chang@amd.com>
Cc: Igor Kulchytskyy <igork@ami.com>
---
.../edk2libredfish/include/redfishPayload.h | 31 +-
.../edk2libredfish/include/redfishService.h | 33 +-
.../PrivateLibrary/RedfishLib/RedfishLib.c | 12 +-
.../RedfishLib/edk2libredfish/src/payload.c | 107 +++-
.../RedfishLib/edk2libredfish/src/service.c | 575 +++++++++++++++++-
5 files changed, 749 insertions(+), 9 deletions(-)
diff --git a/RedfishClientPkg/PrivateLibrary/RedfishLib/edk2libredfish/include/redfishPayload.h b/RedfishClientPkg/PrivateLibrary/RedfishLib/edk2libredfish/include/redfishPayload.h
index 44515306..8403d693 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
@@ -65,6 +65,15 @@ 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,
@@ -74,6 +83,17 @@ 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,
@@ -81,6 +101,15 @@ 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/redfishService.h b/RedfishClientPkg/PrivateLibrary/RedfishLib/edk2libredfish/include/redfishService.h
index 5c13b682..c41c0d14 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
@@ -104,6 +104,15 @@ getUriFromService (
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,
@@ -112,6 +121,16 @@ patchUriFromService (
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,
@@ -122,6 +141,18 @@ postUriFromService (
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,
diff --git a/RedfishClientPkg/PrivateLibrary/RedfishLib/RedfishLib.c b/RedfishClientPkg/PrivateLibrary/RedfishLib/RedfishLib.c
index 9f9d3779..2050d3b2 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
@@ -331,7 +331,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);
//
@@ -556,9 +556,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)
);
@@ -624,9 +626,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/src/payload.c b/RedfishClientPkg/PrivateLibrary/RedfishLib/edk2libredfish/src/payload.c
index 7ceb63ac..8ec2ed4a 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
@@ -379,6 +379,45 @@ 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,
@@ -416,6 +455,44 @@ 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,
@@ -452,6 +529,34 @@ 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,
diff --git a/RedfishClientPkg/PrivateLibrary/RedfishLib/edk2libredfish/src/service.c b/RedfishClientPkg/PrivateLibrary/RedfishLib/edk2libredfish/src/service.c
index 969aa5a0..9bcbfa10 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
@@ -401,6 +401,199 @@ 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,
@@ -558,10 +751,12 @@ ON_EXIT:
}
json_t *
-patchUriFromService (
+patchUriFromServiceEx (
redfishService *service,
const char *uri,
const char *content,
+ EFI_HTTP_HEADER **Headers,
+ UINTN *HeaderCount,
EFI_HTTP_STATUS_CODE **StatusCode
)
{
@@ -701,6 +896,10 @@ patchUriFromService (
**StatusCode = ResponseMsg.Data.Response->StatusCode;
}
+ if (ResponseMsg.Headers != NULL) {
+ *Headers = cloneHttpHeaders (&ResponseMsg, HeaderCount);
+ }
+
if (EncodedContent != content) {
FreePool (EncodedContent);
}
@@ -736,6 +935,378 @@ 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,
--
2.17.1
^ permalink raw reply related [flat|nested] 2+ messages in thread
* Re: [edk2-redfish-client][PATCH 3/4] RedfishClientPkg: Update RedfishLib
2023-05-10 8:23 [edk2-redfish-client][PATCH 3/4] RedfishClientPkg: Update RedfishLib Nickle Wang
@ 2023-05-10 8:26 ` Chang, Abner
0 siblings, 0 replies; 2+ messages in thread
From: Chang, Abner @ 2023-05-10 8:26 UTC (permalink / raw)
To: Nickle Wang, devel@edk2.groups.io; +Cc: Igor Kulchytskyy
[AMD Official Use Only - General]
Reviewed-by: Abner Chang <abner.chang@amd.com>
> -----Original Message-----
> From: Nickle Wang <nicklew@nvidia.com>
> Sent: Wednesday, May 10, 2023 4:24 PM
> To: devel@edk2.groups.io
> Cc: Chang, Abner <Abner.Chang@amd.com>; Igor Kulchytskyy
> <igork@ami.com>
> Subject: [edk2-redfish-client][PATCH 3/4] RedfishClientPkg: Update
> RedfishLib
>
> Caution: This message originated from an External Source. Use proper
> caution when opening attachments, clicking links, or responding.
>
>
> 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 <nicklew@nvidia.com>
> Cc: Abner Chang <abner.chang@amd.com>
> Cc: Igor Kulchytskyy <igork@ami.com>
> ---
> .../edk2libredfish/include/redfishPayload.h | 31 +-
> .../edk2libredfish/include/redfishService.h | 33 +-
> .../PrivateLibrary/RedfishLib/RedfishLib.c | 12 +-
> .../RedfishLib/edk2libredfish/src/payload.c | 107 +++-
> .../RedfishLib/edk2libredfish/src/service.c | 575 +++++++++++++++++-
> 5 files changed, 749 insertions(+), 9 deletions(-)
>
> diff --git
> a/RedfishClientPkg/PrivateLibrary/RedfishLib/edk2libredfish/include/redfish
> Payload.h
> b/RedfishClientPkg/PrivateLibrary/RedfishLib/edk2libredfish/include/redfish
> Payload.h
> index 44515306..8403d693 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
>
> @@ -65,6 +65,15 @@ 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,
> @@ -74,6 +83,17 @@ 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,
> @@ -81,6 +101,15 @@ 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/redfish
> Service.h
> b/RedfishClientPkg/PrivateLibrary/RedfishLib/edk2libredfish/include/redfish
> Service.h
> index 5c13b682..c41c0d14 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
>
> @@ -104,6 +104,15 @@ getUriFromService (
> 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,
> @@ -112,6 +121,16 @@ patchUriFromService (
> 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,
> @@ -122,6 +141,18 @@ postUriFromService (
> 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,
> diff --git a/RedfishClientPkg/PrivateLibrary/RedfishLib/RedfishLib.c
> b/RedfishClientPkg/PrivateLibrary/RedfishLib/RedfishLib.c
> index 9f9d3779..2050d3b2 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
>
> @@ -331,7 +331,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);
>
> //
> @@ -556,9 +556,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)
> );
>
> @@ -624,9 +626,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/src/payload.c
> b/RedfishClientPkg/PrivateLibrary/RedfishLib/edk2libredfish/src/payload.c
> index 7ceb63ac..8ec2ed4a 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
>
> @@ -379,6 +379,45 @@ 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,
> @@ -416,6 +455,44 @@ 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,
> @@ -452,6 +529,34 @@ 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,
> diff --git
> a/RedfishClientPkg/PrivateLibrary/RedfishLib/edk2libredfish/src/service.c
> b/RedfishClientPkg/PrivateLibrary/RedfishLib/edk2libredfish/src/service.c
> index 969aa5a0..9bcbfa10 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
>
> @@ -401,6 +401,199 @@ 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,
> @@ -558,10 +751,12 @@ ON_EXIT:
> }
>
> json_t *
> -patchUriFromService (
> +patchUriFromServiceEx (
> redfishService *service,
> const char *uri,
> const char *content,
> + EFI_HTTP_HEADER **Headers,
> + UINTN *HeaderCount,
> EFI_HTTP_STATUS_CODE **StatusCode
> )
> {
> @@ -701,6 +896,10 @@ patchUriFromService (
> **StatusCode = ResponseMsg.Data.Response->StatusCode;
> }
>
> + if (ResponseMsg.Headers != NULL) {
> + *Headers = cloneHttpHeaders (&ResponseMsg, HeaderCount); }
> +
> if (EncodedContent != content) {
> FreePool (EncodedContent);
> }
> @@ -736,6 +935,378 @@ 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,
> --
> 2.17.1
^ permalink raw reply [flat|nested] 2+ messages in thread
end of thread, other threads:[~2023-05-10 8:26 UTC | newest]
Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2023-05-10 8:23 [edk2-redfish-client][PATCH 3/4] RedfishClientPkg: Update RedfishLib Nickle Wang
2023-05-10 8:26 ` Chang, Abner
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox