mirror of
				https://gitlab.com/qemu-project/edk2.git
				synced 2025-11-03 07:59:00 +08:00 
			
		
		
		
	RedfishPkg: implement Redfish HTTP protocol
implement Redfish HTTP protocol driver. Signed-off-by: Nickle Wang <nicklew@nvidia.com> Co-authored-by: Igor Kulchytskyy <igork@ami.com> Cc: Abner Chang <abner.chang@amd.com> Cc: Igor Kulchytskyy <igork@ami.com> Cc: Nick Ramirez <nramirez@nvidia.com> Reviewed-by: Abner Chang <abner.chang@amd.com> Reviewed-by: Igor Kulchytskyy <igork@ami.com> Reviewed-by: Mike Maslenkin <mike.maslenkin@gmail.com>
This commit is contained in:
		
				
					committed by
					
						
						mergify[bot]
					
				
			
			
				
	
			
			
			
						parent
						
							1988f2df29
						
					
				
				
					commit
					0ce2012c6c
				
			@ -6,7 +6,7 @@
 | 
			
		||||
# to be built in the firmware volume.
 | 
			
		||||
#
 | 
			
		||||
# (C) Copyright 2020-2021 Hewlett Packard Enterprise Development LP<BR>
 | 
			
		||||
# Copyright (c) 2023, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
 | 
			
		||||
# Copyright (c) 2023-2024, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
 | 
			
		||||
#
 | 
			
		||||
#    SPDX-License-Identifier: BSD-2-Clause-Patent
 | 
			
		||||
#
 | 
			
		||||
@ -20,4 +20,5 @@
 | 
			
		||||
  INF RedfishPkg/RedfishConfigHandler/RedfishConfigHandlerDriver.inf
 | 
			
		||||
  INF RedfishPkg/RedfishPlatformConfigDxe/RedfishPlatformConfigDxe.inf
 | 
			
		||||
  INF MdeModulePkg/Universal/RegularExpressionDxe/RegularExpressionDxe.inf
 | 
			
		||||
  INF RedfishPkg/RedfishHttpDxe/RedfishHttpDxe.inf
 | 
			
		||||
!endif
 | 
			
		||||
 | 
			
		||||
@ -7,7 +7,7 @@
 | 
			
		||||
# "RedfishDefines.dsc.inc".
 | 
			
		||||
#
 | 
			
		||||
# (C) Copyright 2020-2021 Hewlett Packard Enterprise Development LP<BR>
 | 
			
		||||
# Copyright (c) 2023, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
 | 
			
		||||
# Copyright (c) 2023-2024, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
 | 
			
		||||
#
 | 
			
		||||
#    SPDX-License-Identifier: BSD-2-Clause-Patent
 | 
			
		||||
#
 | 
			
		||||
@ -28,4 +28,5 @@
 | 
			
		||||
  RedfishPkg/RedfishConfigHandler/RedfishConfigHandlerDriver.inf
 | 
			
		||||
  RedfishPkg/RedfishPlatformConfigDxe/RedfishPlatformConfigDxe.inf
 | 
			
		||||
  MdeModulePkg/Universal/RegularExpressionDxe/RegularExpressionDxe.inf
 | 
			
		||||
  RedfishPkg/RedfishHttpDxe/RedfishHttpDxe.inf
 | 
			
		||||
!endif
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										667
									
								
								RedfishPkg/RedfishHttpDxe/RedfishHttpData.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										667
									
								
								RedfishPkg/RedfishHttpDxe/RedfishHttpData.c
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,667 @@
 | 
			
		||||
/** @file
 | 
			
		||||
  RedfishHttpData handles internal data to support Redfish HTTP protocol.
 | 
			
		||||
 | 
			
		||||
  Copyright (c) 2023-2024, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
 | 
			
		||||
 | 
			
		||||
  SPDX-License-Identifier: BSD-2-Clause-Patent
 | 
			
		||||
 | 
			
		||||
**/
 | 
			
		||||
 | 
			
		||||
#include "RedfishHttpData.h"
 | 
			
		||||
#include "RedfishHttpOperation.h"
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
  This function update session token in Redfish Service.
 | 
			
		||||
 | 
			
		||||
  @param[in]  Service         Pointer to service instance.
 | 
			
		||||
  @param[in]  Token           Session token.
 | 
			
		||||
 | 
			
		||||
  @retval     EFI_SUCCESS     Session token is updated.
 | 
			
		||||
  @retval     Others          Error occurs.
 | 
			
		||||
 | 
			
		||||
**/
 | 
			
		||||
EFI_STATUS
 | 
			
		||||
UpdateSessionToken (
 | 
			
		||||
  IN REDFISH_SERVICE_PRIVATE  *Service,
 | 
			
		||||
  IN CHAR8                    *Token
 | 
			
		||||
  )
 | 
			
		||||
{
 | 
			
		||||
  if ((Service == NULL) || IS_EMPTY_STRING (Token)) {
 | 
			
		||||
    return EFI_INVALID_PARAMETER;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  if (Service->SessionToken != NULL) {
 | 
			
		||||
    FreePool (Service->SessionToken);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  Service->SessionToken = ASCII_STR_DUPLICATE (Token);
 | 
			
		||||
  if (Service->SessionToken == NULL) {
 | 
			
		||||
    return EFI_OUT_OF_RESOURCES;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  return EFI_SUCCESS;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
  This function release Redfish Service.
 | 
			
		||||
 | 
			
		||||
  @param[in]  Service         Pointer to service instance.
 | 
			
		||||
 | 
			
		||||
  @retval     EFI_SUCCESS     Service is released.
 | 
			
		||||
  @retval     Others          Error occurs.
 | 
			
		||||
 | 
			
		||||
**/
 | 
			
		||||
EFI_STATUS
 | 
			
		||||
ReleaseRedfishService (
 | 
			
		||||
  IN REDFISH_SERVICE_PRIVATE  *Service
 | 
			
		||||
  )
 | 
			
		||||
{
 | 
			
		||||
  if (Service == NULL) {
 | 
			
		||||
    return EFI_INVALID_PARAMETER;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  if (Service->Host != NULL) {
 | 
			
		||||
    FreePool (Service->Host);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  if (Service->HostName != NULL) {
 | 
			
		||||
    FreePool (Service->HostName);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  if (Service->BasicAuth != NULL) {
 | 
			
		||||
    ZeroMem (Service->BasicAuth, AsciiStrSize (Service->BasicAuth));
 | 
			
		||||
    FreePool (Service->BasicAuth);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  if (Service->SessionToken != NULL) {
 | 
			
		||||
    ZeroMem (Service->SessionToken, AsciiStrSize (Service->SessionToken));
 | 
			
		||||
    FreePool (Service->SessionToken);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  FreePool (Service);
 | 
			
		||||
 | 
			
		||||
  return EFI_SUCCESS;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
  This function creat new service. Host and HostName are copied to
 | 
			
		||||
  newly created service instance.
 | 
			
		||||
 | 
			
		||||
  @param[in]  Host            Host string.
 | 
			
		||||
  @param[in]  HostName        Hostname string.
 | 
			
		||||
  @param[in]  BasicAuth       Basic Authorization string.
 | 
			
		||||
  @param[in]  SessionToken    Session token string.
 | 
			
		||||
  @param[in]  RestEx          Rest EX protocol instance.
 | 
			
		||||
 | 
			
		||||
  @retval     REDFISH_PAYLOAD_PRIVATE  Newly created service.
 | 
			
		||||
  @retval     NULL             Error occurs.
 | 
			
		||||
 | 
			
		||||
**/
 | 
			
		||||
REDFISH_SERVICE_PRIVATE *
 | 
			
		||||
CreateRedfishService (
 | 
			
		||||
  IN CHAR8                 *Host,
 | 
			
		||||
  IN CHAR8                 *HostName,
 | 
			
		||||
  IN CHAR8                 *BasicAuth OPTIONAL,
 | 
			
		||||
  IN CHAR8                 *SessionToken OPTIONAL,
 | 
			
		||||
  IN EFI_REST_EX_PROTOCOL  *RestEx
 | 
			
		||||
  )
 | 
			
		||||
{
 | 
			
		||||
  REDFISH_SERVICE_PRIVATE  *NewService;
 | 
			
		||||
  UINTN                    AuthStrSize;
 | 
			
		||||
 | 
			
		||||
  if (IS_EMPTY_STRING (Host) || IS_EMPTY_STRING (HostName) || (RestEx == NULL)) {
 | 
			
		||||
    return NULL;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  NewService = AllocateZeroPool (sizeof (REDFISH_SERVICE_PRIVATE));
 | 
			
		||||
  if (NewService == NULL) {
 | 
			
		||||
    return NULL;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  NewService->Signature = REDFISH_HTTP_SERVICE_SIGNATURE;
 | 
			
		||||
  NewService->Host      = ASCII_STR_DUPLICATE (Host);
 | 
			
		||||
  if (NewService->Host == NULL) {
 | 
			
		||||
    goto ON_ERROR;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  NewService->HostName = ASCII_STR_DUPLICATE (HostName);
 | 
			
		||||
  if (NewService->HostName == NULL) {
 | 
			
		||||
    goto ON_ERROR;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  if (!IS_EMPTY_STRING (BasicAuth)) {
 | 
			
		||||
    AuthStrSize           = AsciiStrSize (BasicAuth) + AsciiStrLen (REDFISH_HTTP_BASIC_AUTH_STR);
 | 
			
		||||
    NewService->BasicAuth = AllocateZeroPool (AuthStrSize);
 | 
			
		||||
    if (NewService->BasicAuth == NULL) {
 | 
			
		||||
      goto ON_ERROR;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    AsciiSPrint (NewService->BasicAuth, AuthStrSize, "%a%a", REDFISH_HTTP_BASIC_AUTH_STR, BasicAuth);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  if (!IS_EMPTY_STRING (SessionToken)) {
 | 
			
		||||
    NewService->SessionToken = ASCII_STR_DUPLICATE (SessionToken);
 | 
			
		||||
    if (NewService->SessionToken == NULL) {
 | 
			
		||||
      goto ON_ERROR;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  NewService->RestEx = RestEx;
 | 
			
		||||
 | 
			
		||||
  return NewService;
 | 
			
		||||
 | 
			
		||||
ON_ERROR:
 | 
			
		||||
 | 
			
		||||
  ReleaseRedfishService (NewService);
 | 
			
		||||
 | 
			
		||||
  return NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
  This function release Redfish Payload.
 | 
			
		||||
 | 
			
		||||
  @param[in]  Payload         Pointer to payload instance.
 | 
			
		||||
 | 
			
		||||
  @retval     EFI_SUCCESS     Payload is released.
 | 
			
		||||
  @retval     Others          Error occurs.
 | 
			
		||||
 | 
			
		||||
**/
 | 
			
		||||
EFI_STATUS
 | 
			
		||||
ReleaseRedfishPayload (
 | 
			
		||||
  IN REDFISH_PAYLOAD_PRIVATE  *Payload
 | 
			
		||||
  )
 | 
			
		||||
{
 | 
			
		||||
  if (Payload == NULL) {
 | 
			
		||||
    return EFI_INVALID_PARAMETER;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  if (Payload->Service != NULL) {
 | 
			
		||||
    ReleaseRedfishService (Payload->Service);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  if (Payload->JsonValue != NULL) {
 | 
			
		||||
    JsonValueFree (Payload->JsonValue);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  FreePool (Payload);
 | 
			
		||||
 | 
			
		||||
  return EFI_SUCCESS;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
  This function creat new payload. Server and JsonObj are
 | 
			
		||||
  copied to newly created payload.
 | 
			
		||||
 | 
			
		||||
  @param[in]  Service          Pointer to Service instance.
 | 
			
		||||
  @param[in]  JsonValue        Pointer to JSON value.
 | 
			
		||||
 | 
			
		||||
  @retval     REDFISH_PAYLOAD_PRIVATE  Newly created payload.
 | 
			
		||||
  @retval     NULL                     Error occurs.
 | 
			
		||||
 | 
			
		||||
**/
 | 
			
		||||
REDFISH_PAYLOAD_PRIVATE *
 | 
			
		||||
CreateRedfishPayload (
 | 
			
		||||
  IN REDFISH_SERVICE_PRIVATE  *Service,
 | 
			
		||||
  IN EDKII_JSON_VALUE         JsonValue
 | 
			
		||||
  )
 | 
			
		||||
{
 | 
			
		||||
  REDFISH_PAYLOAD_PRIVATE  *NewPayload;
 | 
			
		||||
 | 
			
		||||
  if ((Service == NULL) || (JsonValue == NULL)) {
 | 
			
		||||
    return NULL;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  NewPayload = AllocateZeroPool (sizeof (REDFISH_PAYLOAD_PRIVATE));
 | 
			
		||||
  if (NewPayload == NULL) {
 | 
			
		||||
    return NULL;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  NewPayload->Signature = REDFISH_HTTP_PAYLOAD_SIGNATURE;
 | 
			
		||||
  NewPayload->Service   = CreateRedfishService (Service->Host, Service->HostName, Service->BasicAuth, Service->SessionToken, Service->RestEx);
 | 
			
		||||
  if (NewPayload->Service == NULL) {
 | 
			
		||||
    goto ON_ERROR;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  NewPayload->JsonValue = JsonValueClone (JsonValue);
 | 
			
		||||
  if (NewPayload->JsonValue == NULL) {
 | 
			
		||||
    goto ON_ERROR;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  return NewPayload;
 | 
			
		||||
 | 
			
		||||
ON_ERROR:
 | 
			
		||||
 | 
			
		||||
  ReleaseRedfishPayload (NewPayload);
 | 
			
		||||
 | 
			
		||||
  return NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
  This function copy the data in SrcResponse to DstResponse.
 | 
			
		||||
 | 
			
		||||
  @param[in]  SrcResponse      Source Response to copy.
 | 
			
		||||
  @param[out] DstResponse      Destination Response.
 | 
			
		||||
 | 
			
		||||
  @retval     EFI_SUCCESS      Response is copied successfully.
 | 
			
		||||
  @retval     Others           Error occurs.
 | 
			
		||||
 | 
			
		||||
**/
 | 
			
		||||
EFI_STATUS
 | 
			
		||||
CopyRedfishResponse (
 | 
			
		||||
  IN  REDFISH_RESPONSE  *SrcResponse,
 | 
			
		||||
  OUT REDFISH_RESPONSE  *DstResponse
 | 
			
		||||
  )
 | 
			
		||||
{
 | 
			
		||||
  REDFISH_PAYLOAD_PRIVATE  *Payload;
 | 
			
		||||
  UINTN                    Index;
 | 
			
		||||
 | 
			
		||||
  if ((SrcResponse == NULL) || (DstResponse == NULL)) {
 | 
			
		||||
    return EFI_INVALID_PARAMETER;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  if (SrcResponse == DstResponse) {
 | 
			
		||||
    return EFI_SUCCESS;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  //
 | 
			
		||||
  // Status code
 | 
			
		||||
  //
 | 
			
		||||
  if (SrcResponse->StatusCode != NULL) {
 | 
			
		||||
    DstResponse->StatusCode = AllocateCopyPool (sizeof (EFI_HTTP_STATUS_CODE), SrcResponse->StatusCode);
 | 
			
		||||
    if (DstResponse->StatusCode == NULL) {
 | 
			
		||||
      goto ON_ERROR;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  //
 | 
			
		||||
  // Header
 | 
			
		||||
  //
 | 
			
		||||
  if ((SrcResponse->HeaderCount > 0) && (SrcResponse->Headers != NULL)) {
 | 
			
		||||
    DstResponse->HeaderCount = 0;
 | 
			
		||||
    DstResponse->Headers     = AllocateZeroPool (sizeof (EFI_HTTP_HEADER) * SrcResponse->HeaderCount);
 | 
			
		||||
    if (DstResponse->Headers == NULL) {
 | 
			
		||||
      goto ON_ERROR;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    DstResponse->HeaderCount = SrcResponse->HeaderCount;
 | 
			
		||||
 | 
			
		||||
    for (Index = 0; Index < SrcResponse->HeaderCount; Index++) {
 | 
			
		||||
      DstResponse->Headers[Index].FieldName = ASCII_STR_DUPLICATE (SrcResponse->Headers[Index].FieldName);
 | 
			
		||||
      if (DstResponse->Headers[Index].FieldName == NULL) {
 | 
			
		||||
        goto ON_ERROR;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      DstResponse->Headers[Index].FieldValue = ASCII_STR_DUPLICATE (SrcResponse->Headers[Index].FieldValue);
 | 
			
		||||
      if (DstResponse->Headers[Index].FieldValue == NULL) {
 | 
			
		||||
        goto ON_ERROR;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  //
 | 
			
		||||
  // Payload
 | 
			
		||||
  //
 | 
			
		||||
  if (SrcResponse->Payload != NULL) {
 | 
			
		||||
    Payload = (REDFISH_PAYLOAD_PRIVATE *)SrcResponse->Payload;
 | 
			
		||||
    if (Payload->Signature != REDFISH_HTTP_PAYLOAD_SIGNATURE) {
 | 
			
		||||
      DEBUG ((DEBUG_ERROR, "%a: signature check failure\n", __func__));
 | 
			
		||||
      goto ON_ERROR;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    DstResponse->Payload = CreateRedfishPayload (Payload->Service, Payload->JsonValue);
 | 
			
		||||
    if (DstResponse->Payload  == NULL) {
 | 
			
		||||
      goto ON_ERROR;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  return EFI_SUCCESS;
 | 
			
		||||
 | 
			
		||||
ON_ERROR:
 | 
			
		||||
 | 
			
		||||
  ReleaseRedfishResponse (DstResponse);
 | 
			
		||||
 | 
			
		||||
  return EFI_OUT_OF_RESOURCES;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
  This function clone input response and return to caller
 | 
			
		||||
 | 
			
		||||
  @param[in]  Response      Response to clone.
 | 
			
		||||
 | 
			
		||||
  @retval     REDFISH_RESPONSE *  Response is cloned.
 | 
			
		||||
  @retval     NULL                Errors occur.
 | 
			
		||||
 | 
			
		||||
**/
 | 
			
		||||
REDFISH_RESPONSE *
 | 
			
		||||
CloneRedfishResponse (
 | 
			
		||||
  IN REDFISH_RESPONSE  *Response
 | 
			
		||||
  )
 | 
			
		||||
{
 | 
			
		||||
  EFI_STATUS        Status;
 | 
			
		||||
  REDFISH_RESPONSE  *NewResponse;
 | 
			
		||||
 | 
			
		||||
  if (Response == NULL) {
 | 
			
		||||
    return NULL;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  NewResponse = AllocateZeroPool (sizeof (REDFISH_RESPONSE));
 | 
			
		||||
  if (NewResponse == NULL) {
 | 
			
		||||
    return NULL;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  Status = CopyRedfishResponse (Response, NewResponse);
 | 
			
		||||
  if (EFI_ERROR (Status)) {
 | 
			
		||||
    FreePool (NewResponse);
 | 
			
		||||
    return NULL;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  return NewResponse;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
  Release REDFISH_HTTP_CACHE_DATA resource
 | 
			
		||||
 | 
			
		||||
  @param[in]    Data    Pointer to REDFISH_HTTP_CACHE_DATA instance
 | 
			
		||||
 | 
			
		||||
  @retval EFI_SUCCESS             REDFISH_HTTP_CACHE_DATA is released successfully.
 | 
			
		||||
  @retval EFI_INVALID_PARAMETER   Data is NULL
 | 
			
		||||
 | 
			
		||||
**/
 | 
			
		||||
EFI_STATUS
 | 
			
		||||
ReleaseHttpCacheData (
 | 
			
		||||
  IN REDFISH_HTTP_CACHE_DATA  *Data
 | 
			
		||||
  )
 | 
			
		||||
{
 | 
			
		||||
  if (Data == NULL) {
 | 
			
		||||
    return EFI_INVALID_PARAMETER;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  if (Data->Uri != NULL) {
 | 
			
		||||
    FreePool (Data->Uri);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  if (Data->Response != NULL) {
 | 
			
		||||
    ReleaseRedfishResponse (Data->Response);
 | 
			
		||||
    FreePool (Data->Response);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  FreePool (Data);
 | 
			
		||||
 | 
			
		||||
  return EFI_SUCCESS;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
  Create new cache data.
 | 
			
		||||
 | 
			
		||||
  @param[in]    Uri       The URI string matching to this cache data.
 | 
			
		||||
  @param[in]    Response  HTTP response.
 | 
			
		||||
 | 
			
		||||
  @retval REDFISH_HTTP_CACHE_DATA *   Pointer to newly created cache data.
 | 
			
		||||
  @retval NULL                        No memory available.
 | 
			
		||||
 | 
			
		||||
**/
 | 
			
		||||
REDFISH_HTTP_CACHE_DATA *
 | 
			
		||||
NewHttpCacheData (
 | 
			
		||||
  IN  EFI_STRING        Uri,
 | 
			
		||||
  IN  REDFISH_RESPONSE  *Response
 | 
			
		||||
  )
 | 
			
		||||
{
 | 
			
		||||
  REDFISH_HTTP_CACHE_DATA  *NewData;
 | 
			
		||||
  UINTN                    Size;
 | 
			
		||||
 | 
			
		||||
  if (IS_EMPTY_STRING (Uri) || (Response == NULL)) {
 | 
			
		||||
    return NULL;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  NewData = AllocateZeroPool (sizeof (REDFISH_HTTP_CACHE_DATA));
 | 
			
		||||
  if (NewData == NULL) {
 | 
			
		||||
    return NULL;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  NewData->Signature = REDFISH_HTTP_CACHE_SIGNATURE;
 | 
			
		||||
  Size               = StrSize (Uri);
 | 
			
		||||
  NewData->Uri       = AllocateCopyPool (Size, Uri);
 | 
			
		||||
  if (NewData->Uri == NULL) {
 | 
			
		||||
    goto ON_ERROR;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  NewData->Response = Response;
 | 
			
		||||
  NewData->HitCount = 1;
 | 
			
		||||
 | 
			
		||||
  return NewData;
 | 
			
		||||
 | 
			
		||||
ON_ERROR:
 | 
			
		||||
 | 
			
		||||
  if (NewData != NULL) {
 | 
			
		||||
    ReleaseHttpCacheData (NewData);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  return NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
  Search on given ListHeader for given URI string.
 | 
			
		||||
 | 
			
		||||
  @param[in]    ListHeader  Target list to search.
 | 
			
		||||
  @param[in]    Uri         Target URI to search.
 | 
			
		||||
 | 
			
		||||
  @retval REDFISH_HTTP_CACHE_DATA   Target cache data is found.
 | 
			
		||||
  @retval NULL                      No cache data with given URI is found.
 | 
			
		||||
 | 
			
		||||
**/
 | 
			
		||||
REDFISH_HTTP_CACHE_DATA *
 | 
			
		||||
FindHttpCacheData (
 | 
			
		||||
  IN  LIST_ENTRY  *ListHeader,
 | 
			
		||||
  IN  EFI_STRING  Uri
 | 
			
		||||
  )
 | 
			
		||||
{
 | 
			
		||||
  LIST_ENTRY               *List;
 | 
			
		||||
  REDFISH_HTTP_CACHE_DATA  *Data;
 | 
			
		||||
 | 
			
		||||
  if (IS_EMPTY_STRING (Uri)) {
 | 
			
		||||
    return NULL;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  if (IsListEmpty (ListHeader)) {
 | 
			
		||||
    return NULL;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  Data = NULL;
 | 
			
		||||
  List = GetFirstNode (ListHeader);
 | 
			
		||||
  while (!IsNull (ListHeader, List)) {
 | 
			
		||||
    Data = REDFISH_HTTP_CACHE_FROM_LIST (List);
 | 
			
		||||
 | 
			
		||||
    if (StrCmp (Data->Uri, Uri) == 0) {
 | 
			
		||||
      return Data;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    List = GetNextNode (ListHeader, List);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  return NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
  Search on given ListHeader and return cache data with minimum hit count.
 | 
			
		||||
 | 
			
		||||
  @param[in]    ListHeader  Target list to search.
 | 
			
		||||
 | 
			
		||||
  @retval REDFISH_HTTP_CACHE_DATA   Target cache data is returned.
 | 
			
		||||
  @retval NULL                      No cache data is found.
 | 
			
		||||
 | 
			
		||||
**/
 | 
			
		||||
REDFISH_HTTP_CACHE_DATA *
 | 
			
		||||
FindUnusedHttpCacheData (
 | 
			
		||||
  IN  LIST_ENTRY  *ListHeader
 | 
			
		||||
  )
 | 
			
		||||
{
 | 
			
		||||
  LIST_ENTRY               *List;
 | 
			
		||||
  REDFISH_HTTP_CACHE_DATA  *Data;
 | 
			
		||||
  REDFISH_HTTP_CACHE_DATA  *UnusedData;
 | 
			
		||||
  UINTN                    HitCount;
 | 
			
		||||
 | 
			
		||||
  if (IsListEmpty (ListHeader)) {
 | 
			
		||||
    return NULL;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  Data       = NULL;
 | 
			
		||||
  UnusedData = NULL;
 | 
			
		||||
  HitCount   = 0;
 | 
			
		||||
 | 
			
		||||
  List       = GetFirstNode (ListHeader);
 | 
			
		||||
  Data       = REDFISH_HTTP_CACHE_FROM_LIST (List);
 | 
			
		||||
  UnusedData = Data;
 | 
			
		||||
  HitCount   = Data->HitCount;
 | 
			
		||||
  List       = GetNextNode (ListHeader, List);
 | 
			
		||||
 | 
			
		||||
  while (!IsNull (ListHeader, List)) {
 | 
			
		||||
    Data = REDFISH_HTTP_CACHE_FROM_LIST (List);
 | 
			
		||||
 | 
			
		||||
    if (Data->HitCount < HitCount) {
 | 
			
		||||
      HitCount   = Data->HitCount;
 | 
			
		||||
      UnusedData = Data;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    List = GetNextNode (ListHeader, List);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  return UnusedData;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
  Delete a cache data by given cache instance.
 | 
			
		||||
 | 
			
		||||
  @param[in]    List    Target cache list to be removed.
 | 
			
		||||
  @param[in]    Data    Pointer to the instance to be deleted.
 | 
			
		||||
 | 
			
		||||
  @retval EFI_SUCCESS   Cache data is removed.
 | 
			
		||||
  @retval Others        Fail to remove cache data.
 | 
			
		||||
 | 
			
		||||
**/
 | 
			
		||||
EFI_STATUS
 | 
			
		||||
DeleteHttpCacheData (
 | 
			
		||||
  IN  REDFISH_HTTP_CACHE_LIST  *List,
 | 
			
		||||
  IN  REDFISH_HTTP_CACHE_DATA  *Data
 | 
			
		||||
  )
 | 
			
		||||
{
 | 
			
		||||
  if ((List == NULL) || (Data == NULL)) {
 | 
			
		||||
    return EFI_INVALID_PARAMETER;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  DEBUG ((REDFISH_HTTP_CACHE_DEBUG, "%a: delete: %s\n", __func__, Data->Uri));
 | 
			
		||||
 | 
			
		||||
  RemoveEntryList (&Data->List);
 | 
			
		||||
  --List->Count;
 | 
			
		||||
 | 
			
		||||
  return ReleaseHttpCacheData (Data);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
  Add new cache by given URI and HTTP response to specify List.
 | 
			
		||||
 | 
			
		||||
  @param[in]    List      Target cache list to add.
 | 
			
		||||
  @param[in]    Uri       The URI string matching to this cache data.
 | 
			
		||||
  @param[in]    Response  HTTP response.
 | 
			
		||||
 | 
			
		||||
  @retval EFI_SUCCESS   Cache data is added.
 | 
			
		||||
  @retval Others        Fail to add cache data.
 | 
			
		||||
 | 
			
		||||
**/
 | 
			
		||||
EFI_STATUS
 | 
			
		||||
AddHttpCacheData (
 | 
			
		||||
  IN  REDFISH_HTTP_CACHE_LIST  *List,
 | 
			
		||||
  IN  EFI_STRING               Uri,
 | 
			
		||||
  IN  REDFISH_RESPONSE         *Response
 | 
			
		||||
  )
 | 
			
		||||
{
 | 
			
		||||
  REDFISH_HTTP_CACHE_DATA  *NewData;
 | 
			
		||||
  REDFISH_HTTP_CACHE_DATA  *OldData;
 | 
			
		||||
  REDFISH_HTTP_CACHE_DATA  *UnusedData;
 | 
			
		||||
  REDFISH_RESPONSE         *NewResponse;
 | 
			
		||||
 | 
			
		||||
  if ((List == NULL) || IS_EMPTY_STRING (Uri) || (Response == NULL)) {
 | 
			
		||||
    return EFI_INVALID_PARAMETER;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  //
 | 
			
		||||
  // If same cache data exist, replace it with latest one.
 | 
			
		||||
  //
 | 
			
		||||
  OldData = FindHttpCacheData (&List->Head, Uri);
 | 
			
		||||
  if (OldData != NULL) {
 | 
			
		||||
    DeleteHttpCacheData (List, OldData);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  //
 | 
			
		||||
  // Check capacity
 | 
			
		||||
  //
 | 
			
		||||
  if (List->Count >= List->Capacity) {
 | 
			
		||||
    DEBUG ((REDFISH_HTTP_CACHE_DEBUG, "%a: list is full and retire unused cache\n", __func__));
 | 
			
		||||
    UnusedData = FindUnusedHttpCacheData (&List->Head);
 | 
			
		||||
    if (UnusedData == NULL) {
 | 
			
		||||
      return EFI_OUT_OF_RESOURCES;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    DeleteHttpCacheData (List, UnusedData);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  //
 | 
			
		||||
  // Clone a local copy
 | 
			
		||||
  //
 | 
			
		||||
  NewResponse = CloneRedfishResponse (Response);
 | 
			
		||||
  if (NewResponse == NULL) {
 | 
			
		||||
    return EFI_OUT_OF_RESOURCES;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  NewData = NewHttpCacheData (Uri, NewResponse);
 | 
			
		||||
  if (NewData == NULL) {
 | 
			
		||||
    return EFI_OUT_OF_RESOURCES;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  InsertTailList (&List->Head, &NewData->List);
 | 
			
		||||
  ++List->Count;
 | 
			
		||||
 | 
			
		||||
  DEBUG ((REDFISH_HTTP_CACHE_DEBUG, "%a: cache(%d/%d) %s\n", __func__, List->Count, List->Capacity, NewData->Uri));
 | 
			
		||||
 | 
			
		||||
  return EFI_SUCCESS;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
  Release all cache from list.
 | 
			
		||||
 | 
			
		||||
  @param[in]    CacheList    The list to be released.
 | 
			
		||||
 | 
			
		||||
  @retval EFI_SUCCESS             All cache data are released.
 | 
			
		||||
  @retval EFI_INVALID_PARAMETER   CacheList is NULL.
 | 
			
		||||
 | 
			
		||||
**/
 | 
			
		||||
EFI_STATUS
 | 
			
		||||
ReleaseCacheList (
 | 
			
		||||
  IN  REDFISH_HTTP_CACHE_LIST  *CacheList
 | 
			
		||||
  )
 | 
			
		||||
{
 | 
			
		||||
  LIST_ENTRY               *List;
 | 
			
		||||
  LIST_ENTRY               *Next;
 | 
			
		||||
  REDFISH_HTTP_CACHE_DATA  *Data;
 | 
			
		||||
 | 
			
		||||
  if (CacheList == NULL) {
 | 
			
		||||
    return EFI_INVALID_PARAMETER;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  if (IsListEmpty (&CacheList->Head)) {
 | 
			
		||||
    return EFI_SUCCESS;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  Data = NULL;
 | 
			
		||||
  Next = NULL;
 | 
			
		||||
  List = GetFirstNode (&CacheList->Head);
 | 
			
		||||
  while (!IsNull (&CacheList->Head, List)) {
 | 
			
		||||
    Data = REDFISH_HTTP_CACHE_FROM_LIST (List);
 | 
			
		||||
    Next = GetNextNode (&CacheList->Head, List);
 | 
			
		||||
 | 
			
		||||
    DeleteHttpCacheData (CacheList, Data);
 | 
			
		||||
 | 
			
		||||
    List = Next;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  return EFI_SUCCESS;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										256
									
								
								RedfishPkg/RedfishHttpDxe/RedfishHttpData.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										256
									
								
								RedfishPkg/RedfishHttpDxe/RedfishHttpData.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,256 @@
 | 
			
		||||
/** @file
 | 
			
		||||
  Definitions of RedfishHttpData
 | 
			
		||||
 | 
			
		||||
  Copyright (c) 2023-2024, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
 | 
			
		||||
 | 
			
		||||
  SPDX-License-Identifier: BSD-2-Clause-Patent
 | 
			
		||||
 | 
			
		||||
**/
 | 
			
		||||
 | 
			
		||||
#ifndef EDKII_REDFISH_HTTP_DATA_H_
 | 
			
		||||
#define EDKII_REDFISH_HTTP_DATA_H_
 | 
			
		||||
 | 
			
		||||
#include "RedfishHttpDxe.h"
 | 
			
		||||
 | 
			
		||||
#define REDFISH_HTTP_DRIVER_SIGNATURE   SIGNATURE_32 ('r', 'f', 'h', 'p')
 | 
			
		||||
#define REDFISH_HTTP_CACHE_SIGNATURE    SIGNATURE_32 ('r', 'f', 'c', 'h')
 | 
			
		||||
#define REDFISH_HTTP_SERVICE_SIGNATURE  SIGNATURE_32 ('r', 'f', 's', 'v')
 | 
			
		||||
#define REDFISH_HTTP_PAYLOAD_SIGNATURE  SIGNATURE_32 ('r', 'f', 'p', 'l')
 | 
			
		||||
#define REDFISH_HTTP_BASIC_AUTH_STR     "Basic "
 | 
			
		||||
 | 
			
		||||
///
 | 
			
		||||
/// REDFISH_SERVICE_PRIVATE definition.
 | 
			
		||||
///
 | 
			
		||||
typedef struct {
 | 
			
		||||
  UINT32                  Signature;
 | 
			
		||||
  CHAR8                   *Host;
 | 
			
		||||
  CHAR8                   *HostName;
 | 
			
		||||
  CHAR8                   *BasicAuth;
 | 
			
		||||
  CHAR8                   *SessionToken;
 | 
			
		||||
  EFI_REST_EX_PROTOCOL    *RestEx;
 | 
			
		||||
} REDFISH_SERVICE_PRIVATE;
 | 
			
		||||
 | 
			
		||||
///
 | 
			
		||||
/// REDFISH_PAYLOAD_PRIVATE definition.
 | 
			
		||||
///
 | 
			
		||||
typedef struct {
 | 
			
		||||
  UINT32                     Signature;
 | 
			
		||||
  REDFISH_SERVICE_PRIVATE    *Service;
 | 
			
		||||
  EDKII_JSON_VALUE           JsonValue;
 | 
			
		||||
} REDFISH_PAYLOAD_PRIVATE;
 | 
			
		||||
 | 
			
		||||
///
 | 
			
		||||
/// Definition of REDFISH_HTTP_CACHE_DATA
 | 
			
		||||
///
 | 
			
		||||
typedef struct {
 | 
			
		||||
  UINT32              Signature;
 | 
			
		||||
  LIST_ENTRY          List;
 | 
			
		||||
  EFI_STRING          Uri;
 | 
			
		||||
  UINTN               HitCount;
 | 
			
		||||
  REDFISH_RESPONSE    *Response;
 | 
			
		||||
} REDFISH_HTTP_CACHE_DATA;
 | 
			
		||||
 | 
			
		||||
#define REDFISH_HTTP_CACHE_FROM_LIST(a)  CR (a, REDFISH_HTTP_CACHE_DATA, List, REDFISH_HTTP_CACHE_SIGNATURE)
 | 
			
		||||
 | 
			
		||||
///
 | 
			
		||||
/// Definition of REDFISH_HTTP_CACHE_LIST
 | 
			
		||||
///
 | 
			
		||||
typedef struct {
 | 
			
		||||
  LIST_ENTRY    Head;
 | 
			
		||||
  UINTN         Count;
 | 
			
		||||
  UINTN         Capacity;
 | 
			
		||||
} REDFISH_HTTP_CACHE_LIST;
 | 
			
		||||
 | 
			
		||||
///
 | 
			
		||||
/// Definition of REDFISH_HTTP_RETRY_SETTING
 | 
			
		||||
///
 | 
			
		||||
typedef struct {
 | 
			
		||||
  UINT16    MaximumRetryGet;
 | 
			
		||||
  UINT16    MaximumRetryPut;
 | 
			
		||||
  UINT16    MaximumRetryPost;
 | 
			
		||||
  UINT16    MaximumRetryPatch;
 | 
			
		||||
  UINT16    MaximumRetryDelete;
 | 
			
		||||
  UINTN     RetryWait;
 | 
			
		||||
} REDFISH_HTTP_RETRY_SETTING;
 | 
			
		||||
 | 
			
		||||
///
 | 
			
		||||
/// Definition of REDFISH_HTTP_CACHE_PRIVATE
 | 
			
		||||
///
 | 
			
		||||
typedef struct {
 | 
			
		||||
  UINT32                               Signature;
 | 
			
		||||
  EFI_HANDLE                           ImageHandle;
 | 
			
		||||
  BOOLEAN                              CacheDisabled;
 | 
			
		||||
  EFI_EVENT                            NotifyEvent;
 | 
			
		||||
  REDFISH_HTTP_CACHE_LIST              CacheList;
 | 
			
		||||
  EDKII_REDFISH_HTTP_PROTOCOL          Protocol;
 | 
			
		||||
  EDKII_REDFISH_CREDENTIAL_PROTOCOL    *CredentialProtocol;
 | 
			
		||||
  REDFISH_HTTP_RETRY_SETTING           RetrySetting;
 | 
			
		||||
} REDFISH_HTTP_CACHE_PRIVATE;
 | 
			
		||||
 | 
			
		||||
#define REDFISH_HTTP_CACHE_PRIVATE_FROM_THIS(a)  CR (a, REDFISH_HTTP_CACHE_PRIVATE, Protocol, REDFISH_HTTP_DRIVER_SIGNATURE)
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
  Search on given ListHeader for given URI string.
 | 
			
		||||
 | 
			
		||||
  @param[in]    ListHeader  Target list to search.
 | 
			
		||||
  @param[in]    Uri         Target URI to search.
 | 
			
		||||
 | 
			
		||||
  @retval REDFISH_HTTP_CACHE_DATA   Target cache data is found.
 | 
			
		||||
  @retval NULL                      No cache data with given URI is found.
 | 
			
		||||
 | 
			
		||||
**/
 | 
			
		||||
REDFISH_HTTP_CACHE_DATA *
 | 
			
		||||
FindHttpCacheData (
 | 
			
		||||
  IN  LIST_ENTRY  *ListHeader,
 | 
			
		||||
  IN  EFI_STRING  Uri
 | 
			
		||||
  );
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
  This function copy the data in SrcResponse to DstResponse.
 | 
			
		||||
 | 
			
		||||
  @param[in]  SrcResponse      Source Response to copy.
 | 
			
		||||
  @param[out] DstResponse      Destination Response.
 | 
			
		||||
 | 
			
		||||
  @retval     EFI_SUCCESS      Response is copied successfully.
 | 
			
		||||
  @retval     Others           Error occurs.
 | 
			
		||||
 | 
			
		||||
**/
 | 
			
		||||
EFI_STATUS
 | 
			
		||||
CopyRedfishResponse (
 | 
			
		||||
  IN  REDFISH_RESPONSE  *SrcResponse,
 | 
			
		||||
  OUT REDFISH_RESPONSE  *DstResponse
 | 
			
		||||
  );
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
  Release all cache from list.
 | 
			
		||||
 | 
			
		||||
  @param[in]    CacheList    The list to be released.
 | 
			
		||||
 | 
			
		||||
  @retval EFI_SUCCESS             All cache data are released.
 | 
			
		||||
  @retval EFI_INVALID_PARAMETER   CacheList is NULL.
 | 
			
		||||
 | 
			
		||||
**/
 | 
			
		||||
EFI_STATUS
 | 
			
		||||
ReleaseCacheList (
 | 
			
		||||
  IN  REDFISH_HTTP_CACHE_LIST  *CacheList
 | 
			
		||||
  );
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
  Add new cache by given URI and HTTP response to specify List.
 | 
			
		||||
 | 
			
		||||
  @param[in]    List      Target cache list to add.
 | 
			
		||||
  @param[in]    Uri       The URI string matching to this cache data.
 | 
			
		||||
  @param[in]    Response  HTTP response.
 | 
			
		||||
 | 
			
		||||
  @retval EFI_SUCCESS   Cache data is added.
 | 
			
		||||
  @retval Others        Fail to add cache data.
 | 
			
		||||
 | 
			
		||||
**/
 | 
			
		||||
EFI_STATUS
 | 
			
		||||
AddHttpCacheData (
 | 
			
		||||
  IN  REDFISH_HTTP_CACHE_LIST  *List,
 | 
			
		||||
  IN  EFI_STRING               Uri,
 | 
			
		||||
  IN  REDFISH_RESPONSE         *Response
 | 
			
		||||
  );
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
  Delete a cache data by given cache instance.
 | 
			
		||||
 | 
			
		||||
  @param[in]    List    Target cache list to be removed.
 | 
			
		||||
  @param[in]    Data    Pointer to the instance to be deleted.
 | 
			
		||||
 | 
			
		||||
  @retval EFI_SUCCESS   Cache data is removed.
 | 
			
		||||
  @retval Others        Fail to remove cache data.
 | 
			
		||||
 | 
			
		||||
**/
 | 
			
		||||
EFI_STATUS
 | 
			
		||||
DeleteHttpCacheData (
 | 
			
		||||
  IN  REDFISH_HTTP_CACHE_LIST  *List,
 | 
			
		||||
  IN  REDFISH_HTTP_CACHE_DATA  *Data
 | 
			
		||||
  );
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
  This function release Redfish Payload.
 | 
			
		||||
 | 
			
		||||
  @param[in]  Payload         Pointer to payload instance.
 | 
			
		||||
 | 
			
		||||
  @retval     EFI_SUCCESS     Payload is released.
 | 
			
		||||
  @retval     Others          Error occurs.
 | 
			
		||||
 | 
			
		||||
**/
 | 
			
		||||
EFI_STATUS
 | 
			
		||||
ReleaseRedfishPayload (
 | 
			
		||||
  IN REDFISH_PAYLOAD_PRIVATE  *Payload
 | 
			
		||||
  );
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
  This function creat new payload. Server and JsonObj are
 | 
			
		||||
  copied to newly created payload.
 | 
			
		||||
 | 
			
		||||
  @param[in]  Service          Pointer to Service instance.
 | 
			
		||||
  @param[in]  JsonObj          Pointer to JSON object.
 | 
			
		||||
 | 
			
		||||
  @retval     REDFISH_PAYLOAD_PRIVATE  Newly created payload.
 | 
			
		||||
  @retval     NULL             Error occurs.
 | 
			
		||||
 | 
			
		||||
**/
 | 
			
		||||
REDFISH_PAYLOAD_PRIVATE *
 | 
			
		||||
CreateRedfishPayload (
 | 
			
		||||
  IN REDFISH_SERVICE_PRIVATE  *Service,
 | 
			
		||||
  IN EDKII_JSON_VALUE         JsonValue
 | 
			
		||||
  );
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
  This function release Redfish Service.
 | 
			
		||||
 | 
			
		||||
  @param[in]  Service         Pointer to service instance.
 | 
			
		||||
 | 
			
		||||
  @retval     EFI_SUCCESS     Service is released.
 | 
			
		||||
  @retval     Others          Error occurs.
 | 
			
		||||
 | 
			
		||||
**/
 | 
			
		||||
EFI_STATUS
 | 
			
		||||
ReleaseRedfishService (
 | 
			
		||||
  IN REDFISH_SERVICE_PRIVATE  *Service
 | 
			
		||||
  );
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
  This function creat new service. Host and HostName are copied to
 | 
			
		||||
  newly created service instance.
 | 
			
		||||
 | 
			
		||||
  @param[in]  Host            Host string.
 | 
			
		||||
  @param[in]  HostName        Hostname string.
 | 
			
		||||
  @param[in]  BasicAuth       Basic Authorization string.
 | 
			
		||||
  @param[in]  SessionToken    Session token string.
 | 
			
		||||
  @param[in]  RestEx          Rest EX protocol instance.
 | 
			
		||||
 | 
			
		||||
  @retval     REDFISH_PAYLOAD_PRIVATE  Newly created service.
 | 
			
		||||
  @retval     NULL             Error occurs.
 | 
			
		||||
 | 
			
		||||
**/
 | 
			
		||||
REDFISH_SERVICE_PRIVATE *
 | 
			
		||||
CreateRedfishService (
 | 
			
		||||
  IN CHAR8                 *Host,
 | 
			
		||||
  IN CHAR8                 *HostName,
 | 
			
		||||
  IN CHAR8                 *BasicAuth OPTIONAL,
 | 
			
		||||
  IN CHAR8                 *SessionToken OPTIONAL,
 | 
			
		||||
  IN EFI_REST_EX_PROTOCOL  *RestEx
 | 
			
		||||
  );
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
  This function update session token in Redfish Service.
 | 
			
		||||
 | 
			
		||||
  @param[in]  Service         Pointer to service instance.
 | 
			
		||||
  @param[in]  Token           Session token.
 | 
			
		||||
 | 
			
		||||
  @retval     EFI_SUCCESS     Session token is updated.
 | 
			
		||||
  @retval     Others          Error occurs.
 | 
			
		||||
 | 
			
		||||
**/
 | 
			
		||||
EFI_STATUS
 | 
			
		||||
UpdateSessionToken (
 | 
			
		||||
  IN REDFISH_SERVICE_PRIVATE  *Service,
 | 
			
		||||
  IN CHAR8                    *Token
 | 
			
		||||
  );
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
							
								
								
									
										1344
									
								
								RedfishPkg/RedfishHttpDxe/RedfishHttpDxe.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1344
									
								
								RedfishPkg/RedfishHttpDxe/RedfishHttpDxe.c
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										44
									
								
								RedfishPkg/RedfishHttpDxe/RedfishHttpDxe.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										44
									
								
								RedfishPkg/RedfishHttpDxe/RedfishHttpDxe.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,44 @@
 | 
			
		||||
/** @file
 | 
			
		||||
  Definitions of RedfishHttpDxe
 | 
			
		||||
 | 
			
		||||
  Copyright (c) 2023-2024, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
 | 
			
		||||
 | 
			
		||||
  SPDX-License-Identifier: BSD-2-Clause-Patent
 | 
			
		||||
 | 
			
		||||
**/
 | 
			
		||||
 | 
			
		||||
#ifndef EDKII_REDFISH_HTTP_DXE_H_
 | 
			
		||||
#define EDKII_REDFISH_HTTP_DXE_H_
 | 
			
		||||
 | 
			
		||||
#include <Uefi.h>
 | 
			
		||||
#include <IndustryStandard/Http11.h>
 | 
			
		||||
 | 
			
		||||
#include <Library/UefiLib.h>
 | 
			
		||||
#include <Library/BaseLib.h>
 | 
			
		||||
#include <Library/BaseMemoryLib.h>
 | 
			
		||||
#include <Library/RedfishContentCodingLib.h>
 | 
			
		||||
#include <Library/DebugLib.h>
 | 
			
		||||
#include <Library/HttpLib.h>
 | 
			
		||||
#include <Library/JsonLib.h>
 | 
			
		||||
#include <Library/UefiBootServicesTableLib.h>
 | 
			
		||||
#include <Library/MemoryAllocationLib.h>
 | 
			
		||||
#include <Library/RedfishDebugLib.h>
 | 
			
		||||
#include <Library/ReportStatusCodeLib.h>
 | 
			
		||||
#include <Library/PrintLib.h>
 | 
			
		||||
 | 
			
		||||
#include <Protocol/Http.h>
 | 
			
		||||
#include <Protocol/EdkIIRedfishHttpProtocol.h>
 | 
			
		||||
#include <Protocol/EdkIIRedfishCredential.h>
 | 
			
		||||
#include <Protocol/RestEx.h>
 | 
			
		||||
 | 
			
		||||
#define IS_EMPTY_STRING(a)  ((a) == NULL || (a)[0] == '\0')
 | 
			
		||||
#define REDFISH_HTTP_CACHE_LIST_SIZE      0x80
 | 
			
		||||
#define REDFISH_ERROR_MSG_MAX             128
 | 
			
		||||
#define REDFISH_DEBUG_STRING_LENGTH       200
 | 
			
		||||
#define REDFISH_HOST_NAME_MAX             64   // IPv6 maximum length (39) + "https://" (8) + port number (maximum 5)
 | 
			
		||||
#define REDFISH_HTTP_ERROR_REPORT         "Redfish HTTP %a failure(0x%x): %s"
 | 
			
		||||
#define REDFISH_HTTP_CACHE_DEBUG          DEBUG_MANAGEABILITY
 | 
			
		||||
#define REDFISH_HTTP_CACHE_DEBUG_DUMP     DEBUG_MANAGEABILITY
 | 
			
		||||
#define REDFISH_HTTP_CACHE_DEBUG_REQUEST  DEBUG_MANAGEABILITY
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
							
								
								
									
										73
									
								
								RedfishPkg/RedfishHttpDxe/RedfishHttpDxe.inf
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										73
									
								
								RedfishPkg/RedfishHttpDxe/RedfishHttpDxe.inf
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,73 @@
 | 
			
		||||
## @file
 | 
			
		||||
#  RedfishHttpDxe is the DXE driver which provides
 | 
			
		||||
#  EdkIIRedfishHttpProtocol to EDK2 Redfish Feature
 | 
			
		||||
#  drivers for HTTP operation.
 | 
			
		||||
#
 | 
			
		||||
#  Copyright (c) 2023-2024, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
 | 
			
		||||
#
 | 
			
		||||
#  SPDX-License-Identifier: BSD-2-Clause-Patent
 | 
			
		||||
#
 | 
			
		||||
##
 | 
			
		||||
 | 
			
		||||
[Defines]
 | 
			
		||||
  INF_VERSION                    = 0x0001000b
 | 
			
		||||
  BASE_NAME                      = RedfishHttpDxe
 | 
			
		||||
  FILE_GUID                      = 85ADB2F1-DA93-47D4-AF4F-3D920D9BD2C0
 | 
			
		||||
  MODULE_TYPE                    = DXE_DRIVER
 | 
			
		||||
  VERSION_STRING                 = 1.0
 | 
			
		||||
  ENTRY_POINT                    = RedfishHttpEntryPoint
 | 
			
		||||
  UNLOAD_IMAGE                   = RedfishHttpDriverUnload
 | 
			
		||||
 | 
			
		||||
#
 | 
			
		||||
#  VALID_ARCHITECTURES           = IA32 X64 ARM AARCH64 RISCV64
 | 
			
		||||
#
 | 
			
		||||
 | 
			
		||||
[Sources]
 | 
			
		||||
  RedfishHttpData.c
 | 
			
		||||
  RedfishHttpData.h
 | 
			
		||||
  RedfishHttpDxe.c
 | 
			
		||||
  RedfishHttpDxe.h
 | 
			
		||||
  RedfishHttpOperation.c
 | 
			
		||||
  RedfishHttpOperation.h
 | 
			
		||||
 | 
			
		||||
[Packages]
 | 
			
		||||
  MdePkg/MdePkg.dec
 | 
			
		||||
  MdeModulePkg/MdeModulePkg.dec
 | 
			
		||||
  NetworkPkg/NetworkPkg.dec
 | 
			
		||||
  RedfishPkg/RedfishPkg.dec
 | 
			
		||||
 | 
			
		||||
[LibraryClasses.ARM]
 | 
			
		||||
  ArmSoftFloatLib
 | 
			
		||||
 | 
			
		||||
[LibraryClasses]
 | 
			
		||||
  BaseLib
 | 
			
		||||
  BaseMemoryLib
 | 
			
		||||
  RedfishContentCodingLib
 | 
			
		||||
  DebugLib
 | 
			
		||||
  HttpLib
 | 
			
		||||
  JsonLib
 | 
			
		||||
  MemoryAllocationLib
 | 
			
		||||
  PrintLib
 | 
			
		||||
  RedfishDebugLib
 | 
			
		||||
  ReportStatusCodeLib
 | 
			
		||||
  UefiBootServicesTableLib
 | 
			
		||||
  UefiDriverEntryPoint
 | 
			
		||||
  UefiLib
 | 
			
		||||
 | 
			
		||||
[Protocols]
 | 
			
		||||
  gEdkIIRedfishHttpProtocolGuid             ## PRODUCED
 | 
			
		||||
  gEdkIIRedfishCredentialProtocolGuid       ## CONSUMES
 | 
			
		||||
  gEfiRestExProtocolGuid                    ## CONSUEMS
 | 
			
		||||
 | 
			
		||||
[Pcd]
 | 
			
		||||
  gEfiRedfishPkgTokenSpaceGuid.PcdHttpGetRetry
 | 
			
		||||
  gEfiRedfishPkgTokenSpaceGuid.PcdHttpPutRetry
 | 
			
		||||
  gEfiRedfishPkgTokenSpaceGuid.PcdHttpPatchRetry
 | 
			
		||||
  gEfiRedfishPkgTokenSpaceGuid.PcdHttpPostRetry
 | 
			
		||||
  gEfiRedfishPkgTokenSpaceGuid.PcdHttpDeleteRetry
 | 
			
		||||
  gEfiRedfishPkgTokenSpaceGuid.PcdHttpRetryWaitInSecond
 | 
			
		||||
  gEfiRedfishPkgTokenSpaceGuid.PcdHttpCacheDisabled
 | 
			
		||||
  gEfiRedfishPkgTokenSpaceGuid.PcdRedfishServiceContentEncoding
 | 
			
		||||
 | 
			
		||||
[Depex]
 | 
			
		||||
  TRUE
 | 
			
		||||
							
								
								
									
										692
									
								
								RedfishPkg/RedfishHttpDxe/RedfishHttpOperation.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										692
									
								
								RedfishPkg/RedfishHttpDxe/RedfishHttpOperation.c
									
									
									
									
									
										Normal file
									
								
							@ -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;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										77
									
								
								RedfishPkg/RedfishHttpDxe/RedfishHttpOperation.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										77
									
								
								RedfishPkg/RedfishHttpDxe/RedfishHttpOperation.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,77 @@
 | 
			
		||||
/** @file
 | 
			
		||||
  Definitions of RedfishHttpOperation
 | 
			
		||||
 | 
			
		||||
  Copyright (c) 2024, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
 | 
			
		||||
 | 
			
		||||
  SPDX-License-Identifier: BSD-2-Clause-Patent
 | 
			
		||||
 | 
			
		||||
**/
 | 
			
		||||
 | 
			
		||||
#ifndef EDKII_REDFISH_HTTP_OPERATION_H_
 | 
			
		||||
#define EDKII_REDFISH_HTTP_OPERATION_H_
 | 
			
		||||
 | 
			
		||||
#include "RedfishHttpDxe.h"
 | 
			
		||||
 | 
			
		||||
#define REDFISH_CONTENT_LENGTH_SIZE              80
 | 
			
		||||
#define REDFISH_COMMON_HEADER_SIZE               5
 | 
			
		||||
#define REDFISH_HTTP_HEADER_ODATA_VERSION_STR    "OData-Version"
 | 
			
		||||
#define REDFISH_HTTP_HEADER_ODATA_VERSION_VALUE  "4.0"
 | 
			
		||||
#define REDFISH_HTTP_HEADER_USER_AGENT_VALUE     "edk2redfish"
 | 
			
		||||
#define REDFISH_HTTP_HEADER_CONNECTION_STR       "Connection"
 | 
			
		||||
#define REDFISH_HTTP_HEADER_CONNECTION_VALUE     "Keep-Alive"
 | 
			
		||||
#define REDFISH_HTTP_CONTENT_ENCODING_NONE       "None"
 | 
			
		||||
#define ASCII_STR_DUPLICATE(a)  (AllocateCopyPool (AsciiStrSize ((a)), (a)))
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
  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
 | 
			
		||||
  );
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
  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
 | 
			
		||||
  );
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
  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
 | 
			
		||||
  );
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
@ -157,8 +157,11 @@
 | 
			
		||||
  # set to EFI_REST_EX_PROTOCOL.
 | 
			
		||||
  #
 | 
			
		||||
  gEfiRedfishPkgTokenSpaceGuid.PcdRedfishSendReceiveTimeout|5000|UINT32|0x00001009
 | 
			
		||||
  ## This is used to enable HTTP content encoding on Redfish communication.
 | 
			
		||||
  gEfiRedfishPkgTokenSpaceGuid.PcdRedfishServiceContentEncoding|TRUE|BOOLEAN|0x0000100A
 | 
			
		||||
  #
 | 
			
		||||
  # This PCD string is introduced for platform developer to set the encoding method supported by BMC Redfish.
 | 
			
		||||
  # Currently only "None" and "gzip" are supported.
 | 
			
		||||
  #
 | 
			
		||||
  gEfiRedfishPkgTokenSpaceGuid.PcdRedfishServiceContentEncoding|"None"|VOID*|0x0000100A
 | 
			
		||||
  #
 | 
			
		||||
  # Use below PCDs to control Redfhs HTTP protocol.
 | 
			
		||||
  #
 | 
			
		||||
 | 
			
		||||
@ -45,6 +45,8 @@
 | 
			
		||||
  UefiHiiServicesLib|MdeModulePkg/Library/UefiHiiServicesLib/UefiHiiServicesLib.inf
 | 
			
		||||
  RedfishPlatformCredentialLib|RedfishPkg/Library/PlatformCredentialLibNull/PlatformCredentialLibNull.inf
 | 
			
		||||
  RedfishContentCodingLib|RedfishPkg/Library/RedfishContentCodingLibNull/RedfishContentCodingLibNull.inf
 | 
			
		||||
  ReportStatusCodeLib|MdeModulePkg/Library/DxeReportStatusCodeLib/DxeReportStatusCodeLib.inf
 | 
			
		||||
  SortLib|MdeModulePkg/Library/UefiSortLib/UefiSortLib.inf
 | 
			
		||||
 | 
			
		||||
  # NULL instance of IPMI related library.
 | 
			
		||||
  IpmiLib|MdeModulePkg/Library/BaseIpmiLibNull/BaseIpmiLibNull.inf
 | 
			
		||||
 | 
			
		||||
		Reference in New Issue
	
	Block a user