summaryrefslogtreecommitdiffstats
path: root/RedfishPkg/RedfishHttpDxe/RedfishHttpOperation.c
diff options
context:
space:
mode:
Diffstat (limited to 'RedfishPkg/RedfishHttpDxe/RedfishHttpOperation.c')
-rw-r--r--RedfishPkg/RedfishHttpDxe/RedfishHttpOperation.c692
1 files changed, 692 insertions, 0 deletions
diff --git a/RedfishPkg/RedfishHttpDxe/RedfishHttpOperation.c b/RedfishPkg/RedfishHttpDxe/RedfishHttpOperation.c
new file mode 100644
index 0000000000..8110985add
--- /dev/null
+++ b/RedfishPkg/RedfishHttpDxe/RedfishHttpOperation.c
@@ -0,0 +1,692 @@
+/** @file
+ RedfishHttpOperation handles HTTP operations.
+
+ Copyright (c) 2024, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "RedfishHttpOperation.h"
+#include "RedfishHttpData.h"
+
+/**
+ This function copies all headers in SrcHeaders to DstHeaders.
+ It's call responsibility to release returned DstHeaders.
+
+ @param[in] SrcHeaders Source headers.
+ @param[in] SrcHeaderCount Number of header in source headers.
+ @param[out] DstHeaders Destination headers.
+ @param[out] DstHeaderCount Number of header in designation headers.
+
+ @retval EFI_SUCCESS Headers are copied successfully.
+ @retval Others Errors occur.
+
+**/
+EFI_STATUS
+CopyHttpHeaders (
+ IN EFI_HTTP_HEADER *SrcHeaders,
+ IN UINTN SrcHeaderCount,
+ OUT EFI_HTTP_HEADER **DstHeaders,
+ OUT UINTN *DstHeaderCount
+ )
+{
+ UINTN Index;
+
+ if ((SrcHeaders == NULL) || (SrcHeaderCount == 0) || (DstHeaders == NULL) || (DstHeaderCount == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ *DstHeaderCount = 0;
+ *DstHeaders = AllocateZeroPool (sizeof (EFI_HTTP_HEADER) * SrcHeaderCount);
+ if (*DstHeaders == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ *DstHeaderCount = SrcHeaderCount;
+ for (Index = 0; Index < SrcHeaderCount; Index++) {
+ (*DstHeaders)[Index].FieldName = ASCII_STR_DUPLICATE (SrcHeaders[Index].FieldName);
+ if ((*DstHeaders)[Index].FieldName == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ (*DstHeaders)[Index].FieldValue = ASCII_STR_DUPLICATE (SrcHeaders[Index].FieldValue);
+ if ((*DstHeaders)[Index].FieldValue == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ This function free resources in Request. Request is no longer available
+ after this function returns successfully.
+
+ @param[in] Request HTTP request to be released.
+
+ @retval EFI_SUCCESS Resource is released successfully.
+ @retval Others Errors occur.
+
+**/
+EFI_STATUS
+ReleaseRedfishRequest (
+ IN REDFISH_REQUEST *Request
+ )
+{
+ if (Request == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ((Request->Headers != NULL) && (Request->HeaderCount > 0)) {
+ HttpFreeHeaderFields (Request->Headers, Request->HeaderCount);
+ Request->Headers = NULL;
+ Request->HeaderCount = 0;
+ }
+
+ if (Request->Content != NULL) {
+ FreePool (Request->Content);
+ Request->Content = NULL;
+ }
+
+ if (Request->ContentType != NULL) {
+ FreePool (Request->ContentType);
+ Request->ContentType = NULL;
+ }
+
+ Request->ContentLength = 0;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ This function free resources in given Response.
+
+ @param[in] Response HTTP response to be released.
+
+ @retval EFI_SUCCESS Resource is released successfully.
+ @retval Others Errors occur.
+
+**/
+EFI_STATUS
+ReleaseRedfishResponse (
+ IN REDFISH_RESPONSE *Response
+ )
+{
+ if (Response == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ((Response->Headers != NULL) && (Response->HeaderCount > 0)) {
+ HttpFreeHeaderFields (Response->Headers, Response->HeaderCount);
+ Response->Headers = NULL;
+ Response->HeaderCount = 0;
+ }
+
+ if (Response->Payload != NULL) {
+ ReleaseRedfishPayload (Response->Payload);
+ Response->Payload = NULL;
+ }
+
+ if (Response->StatusCode != NULL) {
+ FreePool (Response->StatusCode);
+ Response->StatusCode = NULL;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ This function free resources in given HTTP message.
+
+ @param[in] HttpMessage HTTP message to be released.
+ @param[in] IsRequest TRUE if this is request type of HTTP message.
+ FALSE if this is response type of HTTP message.
+
+ @retval EFI_SUCCESS Resource is released successfully.
+ @retval Others Errors occur.
+
+**/
+EFI_STATUS
+ReleaseHttpMessage (
+ IN EFI_HTTP_MESSAGE *HttpMessage,
+ IN BOOLEAN IsRequest
+ )
+{
+ if (HttpMessage == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (IsRequest) {
+ if (HttpMessage->Data.Request != NULL) {
+ if (HttpMessage->Data.Request->Url != NULL) {
+ FreePool (HttpMessage->Data.Request->Url);
+ }
+
+ FreePool (HttpMessage->Data.Request);
+ HttpMessage->Data.Request = NULL;
+ }
+ } else {
+ if (HttpMessage->Data.Response != NULL) {
+ FreePool (HttpMessage->Data.Response);
+ HttpMessage->Data.Response = NULL;
+ }
+ }
+
+ if (HttpMessage->Body != NULL) {
+ FreePool (HttpMessage->Body);
+ HttpMessage->Body = NULL;
+ }
+
+ if (HttpMessage->Headers != NULL) {
+ HttpFreeHeaderFields (HttpMessage->Headers, HttpMessage->HeaderCount);
+ HttpMessage->Headers = NULL;
+ HttpMessage->HeaderCount = 0;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ This function build Redfish message for sending data to Redfish service.
+ It's call responsibility to properly release returned HTTP message by
+ calling ReleaseHttpMessage.
+
+ @param[in] ServicePrivate Pointer to Redfish service private data.
+ @param[in] Uri Redfish service URI.
+ @param[in] Method HTTP method.
+ @param[in] Request Additional data to send to Redfish service.
+ This is optional.
+ @param[in] ContentEncoding Content encoding method to compress HTTP context.
+ This is optional. When ContentEncoding is NULL,
+ No compress method will be performed.
+
+ @retval EFI_HTTP_MESSAGE * Pointer to newly created HTTP message.
+ @retval NULL Error occurred.
+
+**/
+EFI_HTTP_MESSAGE *
+BuildRequestMessage (
+ IN REDFISH_SERVICE_PRIVATE *ServicePrivate,
+ IN EFI_STRING Uri,
+ IN EFI_HTTP_METHOD Method,
+ IN REDFISH_REQUEST *Request OPTIONAL,
+ IN CHAR8 *ContentEncoding OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ EFI_STRING Url;
+ UINTN UrlSize;
+ UINTN Index;
+ EFI_HTTP_MESSAGE *RequestMsg;
+ EFI_HTTP_REQUEST_DATA *RequestData;
+ UINTN HeaderCount;
+ UINTN HeaderIndex;
+ EFI_HTTP_HEADER *Headers;
+ CHAR8 ContentLengthStr[REDFISH_CONTENT_LENGTH_SIZE];
+ VOID *Content;
+ UINTN ContentLength;
+ BOOLEAN HasContent;
+ BOOLEAN DoContentEncoding;
+
+ RequestMsg = NULL;
+ RequestData = NULL;
+ Url = NULL;
+ UrlSize = 0;
+ Content = NULL;
+ ContentLength = 0;
+ HeaderCount = REDFISH_COMMON_HEADER_SIZE;
+ HeaderIndex = 0;
+ Headers = NULL;
+ HasContent = FALSE;
+ DoContentEncoding = FALSE;
+
+ if ((ServicePrivate == NULL) || (IS_EMPTY_STRING (Uri))) {
+ return NULL;
+ }
+
+ if (Method >= HttpMethodMax) {
+ return NULL;
+ }
+
+ DEBUG ((REDFISH_HTTP_CACHE_DEBUG_REQUEST, "%a: %s\n", __func__, Uri));
+
+ //
+ // Build full URL for HTTP query.
+ //
+ UrlSize = (AsciiStrLen (ServicePrivate->Host) + StrLen (Uri) + 1) * sizeof (CHAR16);
+ Url = AllocateZeroPool (UrlSize);
+ if (Url == NULL) {
+ return NULL;
+ }
+
+ UnicodeSPrint (Url, UrlSize, L"%a%s", ServicePrivate->Host, Uri);
+ DEBUG ((REDFISH_HTTP_CACHE_DEBUG_REQUEST, "%a: Url: %s\n", __func__, Url));
+
+ //
+ // Step 1: build the HTTP headers.
+ //
+ if (!IS_EMPTY_STRING (ServicePrivate->SessionToken) || !IS_EMPTY_STRING (ServicePrivate->BasicAuth)) {
+ HeaderCount++;
+ }
+
+ if ((Request != NULL) && (Request->HeaderCount > 0)) {
+ HeaderCount += Request->HeaderCount;
+ }
+
+ //
+ // Check and see if we will do content encoding or not
+ //
+ if (!IS_EMPTY_STRING (ContentEncoding)) {
+ if (AsciiStrCmp (ContentEncoding, REDFISH_HTTP_CONTENT_ENCODING_NONE) != 0) {
+ DoContentEncoding = TRUE;
+ }
+ }
+
+ if ((Request != NULL) && !IS_EMPTY_STRING (Request->Content)) {
+ HeaderCount += 2;
+ HasContent = TRUE;
+ if (DoContentEncoding) {
+ HeaderCount += 1;
+ }
+ }
+
+ Headers = AllocateZeroPool (HeaderCount * sizeof (EFI_HTTP_HEADER));
+ if (Headers == NULL) {
+ goto ON_ERROR;
+ }
+
+ if (!IS_EMPTY_STRING (ServicePrivate->SessionToken)) {
+ Status = HttpSetFieldNameAndValue (&Headers[HeaderIndex++], HTTP_HEADER_X_AUTH_TOKEN, ServicePrivate->SessionToken);
+ if (EFI_ERROR (Status)) {
+ goto ON_ERROR;
+ }
+ } else if (!IS_EMPTY_STRING (ServicePrivate->BasicAuth)) {
+ Status = HttpSetFieldNameAndValue (&Headers[HeaderIndex++], HTTP_HEADER_AUTHORIZATION, ServicePrivate->BasicAuth);
+ if (EFI_ERROR (Status)) {
+ goto ON_ERROR;
+ }
+ }
+
+ if (Request != NULL) {
+ for (Index = 0; Index < Request->HeaderCount; Index++) {
+ Status = HttpSetFieldNameAndValue (&Headers[HeaderIndex++], Request->Headers[Index].FieldName, Request->Headers[Index].FieldValue);
+ if (EFI_ERROR (Status)) {
+ goto ON_ERROR;
+ }
+ }
+ }
+
+ Status = HttpSetFieldNameAndValue (&Headers[HeaderIndex++], HTTP_HEADER_HOST, ServicePrivate->HostName);
+ if (EFI_ERROR (Status)) {
+ goto ON_ERROR;
+ }
+
+ Status = HttpSetFieldNameAndValue (&Headers[HeaderIndex++], REDFISH_HTTP_HEADER_ODATA_VERSION_STR, REDFISH_HTTP_HEADER_ODATA_VERSION_VALUE);
+ if (EFI_ERROR (Status)) {
+ goto ON_ERROR;
+ }
+
+ Status = HttpSetFieldNameAndValue (&Headers[HeaderIndex++], HTTP_HEADER_ACCEPT, HTTP_CONTENT_TYPE_APP_JSON);
+ if (EFI_ERROR (Status)) {
+ goto ON_ERROR;
+ }
+
+ Status = HttpSetFieldNameAndValue (&Headers[HeaderIndex++], HTTP_HEADER_USER_AGENT, REDFISH_HTTP_HEADER_USER_AGENT_VALUE);
+ if (EFI_ERROR (Status)) {
+ goto ON_ERROR;
+ }
+
+ Status = HttpSetFieldNameAndValue (&Headers[HeaderIndex++], REDFISH_HTTP_HEADER_CONNECTION_STR, REDFISH_HTTP_HEADER_CONNECTION_VALUE);
+ if (EFI_ERROR (Status)) {
+ goto ON_ERROR;
+ }
+
+ //
+ // Handle content header
+ //
+ if (HasContent) {
+ if (Request->ContentType == NULL) {
+ Status = HttpSetFieldNameAndValue (&Headers[HeaderIndex++], HTTP_HEADER_CONTENT_TYPE, HTTP_CONTENT_TYPE_APP_JSON);
+ if (EFI_ERROR (Status)) {
+ goto ON_ERROR;
+ }
+ } else {
+ Status = HttpSetFieldNameAndValue (&Headers[HeaderIndex++], HTTP_HEADER_CONTENT_TYPE, Request->ContentType);
+ if (EFI_ERROR (Status)) {
+ goto ON_ERROR;
+ }
+ }
+
+ if (Request->ContentLength == 0) {
+ Request->ContentLength = AsciiStrLen (Request->Content);
+ }
+
+ AsciiSPrint (
+ ContentLengthStr,
+ sizeof (ContentLengthStr),
+ "%lu",
+ (UINT64)Request->ContentLength
+ );
+ Status = HttpSetFieldNameAndValue (&Headers[HeaderIndex++], HTTP_HEADER_CONTENT_LENGTH, ContentLengthStr);
+ if (EFI_ERROR (Status)) {
+ goto ON_ERROR;
+ }
+
+ //
+ // Encoding
+ //
+ if (DoContentEncoding) {
+ //
+ // We currently only support gzip Content-Encoding.
+ //
+ Status = RedfishContentEncode (
+ ContentEncoding,
+ Request->Content,
+ Request->ContentLength,
+ &Content,
+ &ContentLength
+ );
+ if (Status == EFI_INVALID_PARAMETER) {
+ DEBUG ((DEBUG_ERROR, "%a: Error to encode content.\n", __func__));
+ goto ON_ERROR;
+ } else if (Status == EFI_UNSUPPORTED) {
+ DoContentEncoding = FALSE;
+ DEBUG ((REDFISH_HTTP_CACHE_DEBUG_REQUEST, "%a: No content coding for %a! Use raw data instead.\n", __func__, ContentEncoding));
+ Status = HttpSetFieldNameAndValue (&Headers[HeaderIndex++], HTTP_HEADER_CONTENT_ENCODING, HTTP_CONTENT_ENCODING_IDENTITY);
+ if (EFI_ERROR (Status)) {
+ goto ON_ERROR;
+ }
+ } else {
+ Status = HttpSetFieldNameAndValue (&Headers[HeaderIndex++], HTTP_HEADER_CONTENT_ENCODING, HTTP_CONTENT_ENCODING_GZIP);
+ if (EFI_ERROR (Status)) {
+ goto ON_ERROR;
+ }
+ }
+ }
+
+ //
+ // When the content is from caller, we use our own copy so that we properly release it later.
+ //
+ if (!DoContentEncoding) {
+ Content = AllocateCopyPool (Request->ContentLength, Request->Content);
+ if (Content == NULL) {
+ goto ON_ERROR;
+ }
+
+ ContentLength = Request->ContentLength;
+ }
+ }
+
+ //
+ // Step 2: build the rest of HTTP request info.
+ //
+ RequestData = AllocateZeroPool (sizeof (EFI_HTTP_REQUEST_DATA));
+ if (RequestData == NULL) {
+ goto ON_ERROR;
+ }
+
+ RequestData->Method = Method;
+ RequestData->Url = Url;
+
+ //
+ // Step 3: fill in EFI_HTTP_MESSAGE
+ //
+ RequestMsg = AllocateZeroPool (sizeof (EFI_HTTP_MESSAGE));
+ if (RequestMsg == NULL) {
+ goto ON_ERROR;
+ }
+
+ ASSERT (HeaderIndex == HeaderCount);
+ RequestMsg->Data.Request = RequestData;
+ RequestMsg->HeaderCount = HeaderIndex;
+ RequestMsg->Headers = Headers;
+
+ if (HasContent) {
+ RequestMsg->BodyLength = ContentLength;
+ RequestMsg->Body = Content;
+ }
+
+ return RequestMsg;
+
+ON_ERROR:
+
+ if (Headers != NULL) {
+ HttpFreeHeaderFields (Headers, HeaderIndex);
+ }
+
+ if (RequestData != NULL) {
+ FreePool (RequestData);
+ }
+
+ if (RequestMsg != NULL) {
+ FreePool (RequestMsg);
+ }
+
+ if (Url != NULL) {
+ FreePool (Url);
+ }
+
+ return NULL;
+}
+
+/**
+ This function parse response message from Redfish service, and
+ build Redfish response for caller. It's call responsibility to
+ properly release Redfish response by calling ReleaseRedfishResponse.
+
+ @param[in] ServicePrivate Pointer to Redfish service private data.
+ @param[in] ResponseMsg Response message from Redfish service.
+ @param[out] RedfishResponse Redfish response data.
+
+ @retval EFI_SUCCESS Redfish response is returned successfully.
+ @retval Others Errors occur.
+
+**/
+EFI_STATUS
+ParseResponseMessage (
+ IN REDFISH_SERVICE_PRIVATE *ServicePrivate,
+ IN EFI_HTTP_MESSAGE *ResponseMsg,
+ OUT REDFISH_RESPONSE *RedfishResponse
+ )
+{
+ EFI_STATUS Status;
+ EDKII_JSON_VALUE JsonData;
+ EFI_HTTP_HEADER *ContentEncodedHeader;
+ VOID *DecodedBody;
+ UINTN DecodedLength;
+
+ if ((ServicePrivate == NULL) || (ResponseMsg == NULL) || (RedfishResponse == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ DEBUG ((REDFISH_HTTP_CACHE_DEBUG_REQUEST, "%a\n", __func__));
+
+ //
+ // Initialization
+ //
+ JsonData = NULL;
+ RedfishResponse->HeaderCount = 0;
+ RedfishResponse->Headers = NULL;
+ RedfishResponse->Payload = NULL;
+ RedfishResponse->StatusCode = NULL;
+ DecodedBody = NULL;
+ DecodedLength = 0;
+
+ //
+ // Return the HTTP StatusCode.
+ //
+ if (ResponseMsg->Data.Response != NULL) {
+ DEBUG ((REDFISH_HTTP_CACHE_DEBUG_REQUEST, "%a: status: %d\n", __func__, ResponseMsg->Data.Response->StatusCode));
+ RedfishResponse->StatusCode = AllocateCopyPool (sizeof (EFI_HTTP_STATUS_CODE), &ResponseMsg->Data.Response->StatusCode);
+ if (RedfishResponse->StatusCode == NULL) {
+ DEBUG ((DEBUG_ERROR, "%a: Failed to create status code.\n", __func__));
+ }
+ }
+
+ //
+ // Return the HTTP headers.
+ //
+ if (ResponseMsg->Headers != NULL) {
+ DEBUG ((REDFISH_HTTP_CACHE_DEBUG_REQUEST, "%a: header count: %d\n", __func__, ResponseMsg->HeaderCount));
+ Status = CopyHttpHeaders (
+ ResponseMsg->Headers,
+ ResponseMsg->HeaderCount,
+ &RedfishResponse->Headers,
+ &RedfishResponse->HeaderCount
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "%a: Failed to copy HTTP headers: %r\n", __func__, Status));
+ }
+ }
+
+ //
+ // Return the HTTP body.
+ //
+ if ((ResponseMsg->BodyLength != 0) && (ResponseMsg->Body != NULL)) {
+ DEBUG ((REDFISH_HTTP_CACHE_DEBUG_REQUEST, "%a: body length: %d\n", __func__, ResponseMsg->BodyLength));
+ //
+ // Check if data is encoded.
+ //
+ ContentEncodedHeader = HttpFindHeader (RedfishResponse->HeaderCount, RedfishResponse->Headers, HTTP_HEADER_CONTENT_ENCODING);
+ if (ContentEncodedHeader != NULL) {
+ //
+ // The content is encoded.
+ //
+ Status = RedfishContentDecode (
+ ContentEncodedHeader->FieldValue,
+ ResponseMsg->Body,
+ ResponseMsg->BodyLength,
+ &DecodedBody,
+ &DecodedLength
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "%a: Failed to decompress the response content: %r decoding method: %a\n.", __func__, Status, ContentEncodedHeader->FieldValue));
+ goto ON_ERROR;
+ }
+
+ JsonData = JsonLoadBuffer (DecodedBody, DecodedLength, 0, NULL);
+ FreePool (DecodedBody);
+ } else {
+ JsonData = JsonLoadBuffer (ResponseMsg->Body, ResponseMsg->BodyLength, 0, NULL);
+ }
+
+ if (!JsonValueIsNull (JsonData)) {
+ RedfishResponse->Payload = CreateRedfishPayload (ServicePrivate, JsonData);
+ if (RedfishResponse->Payload == NULL) {
+ DEBUG ((DEBUG_ERROR, "%a: Failed to create payload\n.", __func__));
+ }
+
+ JsonValueFree (JsonData);
+ } else {
+ DEBUG ((DEBUG_ERROR, "%a: No payload available\n", __func__));
+ }
+ }
+
+ return EFI_SUCCESS;
+
+ON_ERROR:
+
+ if (RedfishResponse != NULL) {
+ ReleaseRedfishResponse (RedfishResponse);
+ }
+
+ return Status;
+}
+
+/**
+ This function send Redfish request to Redfish service by calling
+ Rest Ex protocol.
+
+ @param[in] Service Pointer to Redfish service.
+ @param[in] Uri Uri of Redfish service.
+ @param[in] Method HTTP method.
+ @param[in] Request Request data. This is optional.
+ @param[out] Response Redfish response data.
+
+ @retval EFI_SUCCESS Request is sent and received successfully.
+ @retval Others Errors occur.
+
+**/
+EFI_STATUS
+HttpSendReceive (
+ IN REDFISH_SERVICE Service,
+ IN EFI_STRING Uri,
+ IN EFI_HTTP_METHOD Method,
+ IN REDFISH_REQUEST *Request OPTIONAL,
+ OUT REDFISH_RESPONSE *Response
+ )
+{
+ EFI_STATUS Status;
+ EFI_STATUS RestExStatus;
+ EFI_HTTP_MESSAGE *RequestMsg;
+ EFI_HTTP_MESSAGE ResponseMsg;
+ REDFISH_SERVICE_PRIVATE *ServicePrivate;
+ EFI_HTTP_HEADER *XAuthTokenHeader;
+ CHAR8 *HttpContentEncoding;
+
+ if ((Service == NULL) || IS_EMPTY_STRING (Uri) || (Response == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ DEBUG ((REDFISH_HTTP_CACHE_DEBUG_REQUEST, "%a: Method: 0x%x %s\n", __func__, Method, Uri));
+
+ ServicePrivate = (REDFISH_SERVICE_PRIVATE *)Service;
+ if (ServicePrivate->Signature != REDFISH_HTTP_SERVICE_SIGNATURE) {
+ DEBUG ((DEBUG_ERROR, "%a: signature check failure\n", __func__));
+ return EFI_INVALID_PARAMETER;
+ }
+
+ ZeroMem (&ResponseMsg, sizeof (ResponseMsg));
+ HttpContentEncoding = (CHAR8 *)PcdGetPtr (PcdRedfishServiceContentEncoding);
+
+ RequestMsg = BuildRequestMessage (Service, Uri, Method, Request, HttpContentEncoding);
+ if (RequestMsg == NULL) {
+ DEBUG ((DEBUG_ERROR, "%a: cannot build request message for %s\n", __func__, Uri));
+ return EFI_PROTOCOL_ERROR;
+ }
+
+ //
+ // call RESTEx to get response from REST service.
+ //
+ RestExStatus = ServicePrivate->RestEx->SendReceive (ServicePrivate->RestEx, RequestMsg, &ResponseMsg);
+ if (EFI_ERROR (RestExStatus)) {
+ DEBUG ((DEBUG_ERROR, "%a: %s SendReceive failure: %r\n", __func__, Uri, RestExStatus));
+ }
+
+ //
+ // Return status code, headers and payload to caller as much as possible even when RestEx returns failure.
+ //
+ Status = ParseResponseMessage (ServicePrivate, &ResponseMsg, Response);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "%a: %s parse response failure: %r\n", __func__, Uri, Status));
+ } else {
+ //
+ // Capture session token in header
+ //
+ if ((Method == HttpMethodPost) &&
+ (Response->StatusCode != NULL) &&
+ ((*Response->StatusCode == HTTP_STATUS_200_OK) || (*Response->StatusCode == HTTP_STATUS_204_NO_CONTENT)))
+ {
+ XAuthTokenHeader = HttpFindHeader (ResponseMsg.HeaderCount, ResponseMsg.Headers, HTTP_HEADER_X_AUTH_TOKEN);
+ if (XAuthTokenHeader != NULL) {
+ Status = UpdateSessionToken (ServicePrivate, XAuthTokenHeader->FieldValue);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "%a: update session token failure: %r\n", __func__, Status));
+ }
+ }
+ }
+ }
+
+ //
+ // Release resources
+ //
+ if (RequestMsg != NULL) {
+ ReleaseHttpMessage (RequestMsg, TRUE);
+ FreePool (RequestMsg);
+ }
+
+ ReleaseHttpMessage (&ResponseMsg, FALSE);
+
+ return RestExStatus;
+}