mirror of
				https://gitlab.com/qemu-project/edk2.git
				synced 2025-10-30 07:56:39 +08:00 
			
		
		
		
	
		
			
				
	
	
		
			669 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			669 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /** @file
 | |
|   RedfishHttpData handles internal data to support Redfish HTTP protocol.
 | |
| 
 | |
|   Copyright (c) 2023-2024, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
 | |
|   Copyright (C) 2025 Advanced Micro Devices, Inc. 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 create 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 create 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;
 | |
| }
 | 
