VirtualBox

source: vbox/trunk/src/VBox/Devices/EFI/Firmware/RedfishPkg/RedfishHttpDxe/RedfishHttpData.c

Last change on this file was 105670, checked in by vboxsync, 8 months ago

Devices/EFI/FirmwareNew: Merge edk2-stable-202405 and make it build on aarch64, bugref:4643

  • Property svn:eol-style set to native
File size: 15.0 KB
Line 
1/** @file
2 RedfishHttpData handles internal data to support Redfish HTTP protocol.
3
4 Copyright (c) 2023-2024, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
5
6 SPDX-License-Identifier: BSD-2-Clause-Patent
7
8**/
9
10#include "RedfishHttpData.h"
11#include "RedfishHttpOperation.h"
12
13/**
14 This function update session token in Redfish Service.
15
16 @param[in] Service Pointer to service instance.
17 @param[in] Token Session token.
18
19 @retval EFI_SUCCESS Session token is updated.
20 @retval Others Error occurs.
21
22**/
23EFI_STATUS
24UpdateSessionToken (
25 IN REDFISH_SERVICE_PRIVATE *Service,
26 IN CHAR8 *Token
27 )
28{
29 if ((Service == NULL) || IS_EMPTY_STRING (Token)) {
30 return EFI_INVALID_PARAMETER;
31 }
32
33 if (Service->SessionToken != NULL) {
34 FreePool (Service->SessionToken);
35 }
36
37 Service->SessionToken = ASCII_STR_DUPLICATE (Token);
38 if (Service->SessionToken == NULL) {
39 return EFI_OUT_OF_RESOURCES;
40 }
41
42 return EFI_SUCCESS;
43}
44
45/**
46 This function release Redfish Service.
47
48 @param[in] Service Pointer to service instance.
49
50 @retval EFI_SUCCESS Service is released.
51 @retval Others Error occurs.
52
53**/
54EFI_STATUS
55ReleaseRedfishService (
56 IN REDFISH_SERVICE_PRIVATE *Service
57 )
58{
59 if (Service == NULL) {
60 return EFI_INVALID_PARAMETER;
61 }
62
63 if (Service->Host != NULL) {
64 FreePool (Service->Host);
65 }
66
67 if (Service->HostName != NULL) {
68 FreePool (Service->HostName);
69 }
70
71 if (Service->BasicAuth != NULL) {
72 ZeroMem (Service->BasicAuth, AsciiStrSize (Service->BasicAuth));
73 FreePool (Service->BasicAuth);
74 }
75
76 if (Service->SessionToken != NULL) {
77 ZeroMem (Service->SessionToken, AsciiStrSize (Service->SessionToken));
78 FreePool (Service->SessionToken);
79 }
80
81 FreePool (Service);
82
83 return EFI_SUCCESS;
84}
85
86/**
87 This function creat new service. Host and HostName are copied to
88 newly created service instance.
89
90 @param[in] Host Host string.
91 @param[in] HostName Hostname string.
92 @param[in] BasicAuth Basic Authorization string.
93 @param[in] SessionToken Session token string.
94 @param[in] RestEx Rest EX protocol instance.
95
96 @retval REDFISH_PAYLOAD_PRIVATE Newly created service.
97 @retval NULL Error occurs.
98
99**/
100REDFISH_SERVICE_PRIVATE *
101CreateRedfishService (
102 IN CHAR8 *Host,
103 IN CHAR8 *HostName,
104 IN CHAR8 *BasicAuth OPTIONAL,
105 IN CHAR8 *SessionToken OPTIONAL,
106 IN EFI_REST_EX_PROTOCOL *RestEx
107 )
108{
109 REDFISH_SERVICE_PRIVATE *NewService;
110 UINTN AuthStrSize;
111
112 if (IS_EMPTY_STRING (Host) || IS_EMPTY_STRING (HostName) || (RestEx == NULL)) {
113 return NULL;
114 }
115
116 NewService = AllocateZeroPool (sizeof (REDFISH_SERVICE_PRIVATE));
117 if (NewService == NULL) {
118 return NULL;
119 }
120
121 NewService->Signature = REDFISH_HTTP_SERVICE_SIGNATURE;
122 NewService->Host = ASCII_STR_DUPLICATE (Host);
123 if (NewService->Host == NULL) {
124 goto ON_ERROR;
125 }
126
127 NewService->HostName = ASCII_STR_DUPLICATE (HostName);
128 if (NewService->HostName == NULL) {
129 goto ON_ERROR;
130 }
131
132 if (!IS_EMPTY_STRING (BasicAuth)) {
133 AuthStrSize = AsciiStrSize (BasicAuth) + AsciiStrLen (REDFISH_HTTP_BASIC_AUTH_STR);
134 NewService->BasicAuth = AllocateZeroPool (AuthStrSize);
135 if (NewService->BasicAuth == NULL) {
136 goto ON_ERROR;
137 }
138
139 AsciiSPrint (NewService->BasicAuth, AuthStrSize, "%a%a", REDFISH_HTTP_BASIC_AUTH_STR, BasicAuth);
140 }
141
142 if (!IS_EMPTY_STRING (SessionToken)) {
143 NewService->SessionToken = ASCII_STR_DUPLICATE (SessionToken);
144 if (NewService->SessionToken == NULL) {
145 goto ON_ERROR;
146 }
147 }
148
149 NewService->RestEx = RestEx;
150
151 return NewService;
152
153ON_ERROR:
154
155 ReleaseRedfishService (NewService);
156
157 return NULL;
158}
159
160/**
161 This function release Redfish Payload.
162
163 @param[in] Payload Pointer to payload instance.
164
165 @retval EFI_SUCCESS Payload is released.
166 @retval Others Error occurs.
167
168**/
169EFI_STATUS
170ReleaseRedfishPayload (
171 IN REDFISH_PAYLOAD_PRIVATE *Payload
172 )
173{
174 if (Payload == NULL) {
175 return EFI_INVALID_PARAMETER;
176 }
177
178 if (Payload->Service != NULL) {
179 ReleaseRedfishService (Payload->Service);
180 }
181
182 if (Payload->JsonValue != NULL) {
183 JsonValueFree (Payload->JsonValue);
184 }
185
186 FreePool (Payload);
187
188 return EFI_SUCCESS;
189}
190
191/**
192 This function creat new payload. Server and JsonObj are
193 copied to newly created payload.
194
195 @param[in] Service Pointer to Service instance.
196 @param[in] JsonValue Pointer to JSON value.
197
198 @retval REDFISH_PAYLOAD_PRIVATE Newly created payload.
199 @retval NULL Error occurs.
200
201**/
202REDFISH_PAYLOAD_PRIVATE *
203CreateRedfishPayload (
204 IN REDFISH_SERVICE_PRIVATE *Service,
205 IN EDKII_JSON_VALUE JsonValue
206 )
207{
208 REDFISH_PAYLOAD_PRIVATE *NewPayload;
209
210 if ((Service == NULL) || (JsonValue == NULL)) {
211 return NULL;
212 }
213
214 NewPayload = AllocateZeroPool (sizeof (REDFISH_PAYLOAD_PRIVATE));
215 if (NewPayload == NULL) {
216 return NULL;
217 }
218
219 NewPayload->Signature = REDFISH_HTTP_PAYLOAD_SIGNATURE;
220 NewPayload->Service = CreateRedfishService (Service->Host, Service->HostName, Service->BasicAuth, Service->SessionToken, Service->RestEx);
221 if (NewPayload->Service == NULL) {
222 goto ON_ERROR;
223 }
224
225 NewPayload->JsonValue = JsonValueClone (JsonValue);
226 if (NewPayload->JsonValue == NULL) {
227 goto ON_ERROR;
228 }
229
230 return NewPayload;
231
232ON_ERROR:
233
234 ReleaseRedfishPayload (NewPayload);
235
236 return NULL;
237}
238
239/**
240 This function copy the data in SrcResponse to DstResponse.
241
242 @param[in] SrcResponse Source Response to copy.
243 @param[out] DstResponse Destination Response.
244
245 @retval EFI_SUCCESS Response is copied successfully.
246 @retval Others Error occurs.
247
248**/
249EFI_STATUS
250CopyRedfishResponse (
251 IN REDFISH_RESPONSE *SrcResponse,
252 OUT REDFISH_RESPONSE *DstResponse
253 )
254{
255 REDFISH_PAYLOAD_PRIVATE *Payload;
256 UINTN Index;
257
258 if ((SrcResponse == NULL) || (DstResponse == NULL)) {
259 return EFI_INVALID_PARAMETER;
260 }
261
262 if (SrcResponse == DstResponse) {
263 return EFI_SUCCESS;
264 }
265
266 //
267 // Status code
268 //
269 if (SrcResponse->StatusCode != NULL) {
270 DstResponse->StatusCode = AllocateCopyPool (sizeof (EFI_HTTP_STATUS_CODE), SrcResponse->StatusCode);
271 if (DstResponse->StatusCode == NULL) {
272 goto ON_ERROR;
273 }
274 }
275
276 //
277 // Header
278 //
279 if ((SrcResponse->HeaderCount > 0) && (SrcResponse->Headers != NULL)) {
280 DstResponse->HeaderCount = 0;
281 DstResponse->Headers = AllocateZeroPool (sizeof (EFI_HTTP_HEADER) * SrcResponse->HeaderCount);
282 if (DstResponse->Headers == NULL) {
283 goto ON_ERROR;
284 }
285
286 DstResponse->HeaderCount = SrcResponse->HeaderCount;
287
288 for (Index = 0; Index < SrcResponse->HeaderCount; Index++) {
289 DstResponse->Headers[Index].FieldName = ASCII_STR_DUPLICATE (SrcResponse->Headers[Index].FieldName);
290 if (DstResponse->Headers[Index].FieldName == NULL) {
291 goto ON_ERROR;
292 }
293
294 DstResponse->Headers[Index].FieldValue = ASCII_STR_DUPLICATE (SrcResponse->Headers[Index].FieldValue);
295 if (DstResponse->Headers[Index].FieldValue == NULL) {
296 goto ON_ERROR;
297 }
298 }
299 }
300
301 //
302 // Payload
303 //
304 if (SrcResponse->Payload != NULL) {
305 Payload = (REDFISH_PAYLOAD_PRIVATE *)SrcResponse->Payload;
306 if (Payload->Signature != REDFISH_HTTP_PAYLOAD_SIGNATURE) {
307 DEBUG ((DEBUG_ERROR, "%a: signature check failure\n", __func__));
308 goto ON_ERROR;
309 }
310
311 DstResponse->Payload = CreateRedfishPayload (Payload->Service, Payload->JsonValue);
312 if (DstResponse->Payload == NULL) {
313 goto ON_ERROR;
314 }
315 }
316
317 return EFI_SUCCESS;
318
319ON_ERROR:
320
321 ReleaseRedfishResponse (DstResponse);
322
323 return EFI_OUT_OF_RESOURCES;
324}
325
326/**
327 This function clone input response and return to caller
328
329 @param[in] Response Response to clone.
330
331 @retval REDFISH_RESPONSE * Response is cloned.
332 @retval NULL Errors occur.
333
334**/
335REDFISH_RESPONSE *
336CloneRedfishResponse (
337 IN REDFISH_RESPONSE *Response
338 )
339{
340 EFI_STATUS Status;
341 REDFISH_RESPONSE *NewResponse;
342
343 if (Response == NULL) {
344 return NULL;
345 }
346
347 NewResponse = AllocateZeroPool (sizeof (REDFISH_RESPONSE));
348 if (NewResponse == NULL) {
349 return NULL;
350 }
351
352 Status = CopyRedfishResponse (Response, NewResponse);
353 if (EFI_ERROR (Status)) {
354 FreePool (NewResponse);
355 return NULL;
356 }
357
358 return NewResponse;
359}
360
361/**
362 Release REDFISH_HTTP_CACHE_DATA resource
363
364 @param[in] Data Pointer to REDFISH_HTTP_CACHE_DATA instance
365
366 @retval EFI_SUCCESS REDFISH_HTTP_CACHE_DATA is released successfully.
367 @retval EFI_INVALID_PARAMETER Data is NULL
368
369**/
370EFI_STATUS
371ReleaseHttpCacheData (
372 IN REDFISH_HTTP_CACHE_DATA *Data
373 )
374{
375 if (Data == NULL) {
376 return EFI_INVALID_PARAMETER;
377 }
378
379 if (Data->Uri != NULL) {
380 FreePool (Data->Uri);
381 }
382
383 if (Data->Response != NULL) {
384 ReleaseRedfishResponse (Data->Response);
385 FreePool (Data->Response);
386 }
387
388 FreePool (Data);
389
390 return EFI_SUCCESS;
391}
392
393/**
394 Create new cache data.
395
396 @param[in] Uri The URI string matching to this cache data.
397 @param[in] Response HTTP response.
398
399 @retval REDFISH_HTTP_CACHE_DATA * Pointer to newly created cache data.
400 @retval NULL No memory available.
401
402**/
403REDFISH_HTTP_CACHE_DATA *
404NewHttpCacheData (
405 IN EFI_STRING Uri,
406 IN REDFISH_RESPONSE *Response
407 )
408{
409 REDFISH_HTTP_CACHE_DATA *NewData;
410 UINTN Size;
411
412 if (IS_EMPTY_STRING (Uri) || (Response == NULL)) {
413 return NULL;
414 }
415
416 NewData = AllocateZeroPool (sizeof (REDFISH_HTTP_CACHE_DATA));
417 if (NewData == NULL) {
418 return NULL;
419 }
420
421 NewData->Signature = REDFISH_HTTP_CACHE_SIGNATURE;
422 Size = StrSize (Uri);
423 NewData->Uri = AllocateCopyPool (Size, Uri);
424 if (NewData->Uri == NULL) {
425 goto ON_ERROR;
426 }
427
428 NewData->Response = Response;
429 NewData->HitCount = 1;
430
431 return NewData;
432
433ON_ERROR:
434
435 if (NewData != NULL) {
436 ReleaseHttpCacheData (NewData);
437 }
438
439 return NULL;
440}
441
442/**
443 Search on given ListHeader for given URI string.
444
445 @param[in] ListHeader Target list to search.
446 @param[in] Uri Target URI to search.
447
448 @retval REDFISH_HTTP_CACHE_DATA Target cache data is found.
449 @retval NULL No cache data with given URI is found.
450
451**/
452REDFISH_HTTP_CACHE_DATA *
453FindHttpCacheData (
454 IN LIST_ENTRY *ListHeader,
455 IN EFI_STRING Uri
456 )
457{
458 LIST_ENTRY *List;
459 REDFISH_HTTP_CACHE_DATA *Data;
460
461 if (IS_EMPTY_STRING (Uri)) {
462 return NULL;
463 }
464
465 if (IsListEmpty (ListHeader)) {
466 return NULL;
467 }
468
469 Data = NULL;
470 List = GetFirstNode (ListHeader);
471 while (!IsNull (ListHeader, List)) {
472 Data = REDFISH_HTTP_CACHE_FROM_LIST (List);
473
474 if (StrCmp (Data->Uri, Uri) == 0) {
475 return Data;
476 }
477
478 List = GetNextNode (ListHeader, List);
479 }
480
481 return NULL;
482}
483
484/**
485 Search on given ListHeader and return cache data with minimum hit count.
486
487 @param[in] ListHeader Target list to search.
488
489 @retval REDFISH_HTTP_CACHE_DATA Target cache data is returned.
490 @retval NULL No cache data is found.
491
492**/
493REDFISH_HTTP_CACHE_DATA *
494FindUnusedHttpCacheData (
495 IN LIST_ENTRY *ListHeader
496 )
497{
498 LIST_ENTRY *List;
499 REDFISH_HTTP_CACHE_DATA *Data;
500 REDFISH_HTTP_CACHE_DATA *UnusedData;
501 UINTN HitCount;
502
503 if (IsListEmpty (ListHeader)) {
504 return NULL;
505 }
506
507 Data = NULL;
508 UnusedData = NULL;
509 HitCount = 0;
510
511 List = GetFirstNode (ListHeader);
512 Data = REDFISH_HTTP_CACHE_FROM_LIST (List);
513 UnusedData = Data;
514 HitCount = Data->HitCount;
515 List = GetNextNode (ListHeader, List);
516
517 while (!IsNull (ListHeader, List)) {
518 Data = REDFISH_HTTP_CACHE_FROM_LIST (List);
519
520 if (Data->HitCount < HitCount) {
521 HitCount = Data->HitCount;
522 UnusedData = Data;
523 }
524
525 List = GetNextNode (ListHeader, List);
526 }
527
528 return UnusedData;
529}
530
531/**
532 Delete a cache data by given cache instance.
533
534 @param[in] List Target cache list to be removed.
535 @param[in] Data Pointer to the instance to be deleted.
536
537 @retval EFI_SUCCESS Cache data is removed.
538 @retval Others Fail to remove cache data.
539
540**/
541EFI_STATUS
542DeleteHttpCacheData (
543 IN REDFISH_HTTP_CACHE_LIST *List,
544 IN REDFISH_HTTP_CACHE_DATA *Data
545 )
546{
547 if ((List == NULL) || (Data == NULL)) {
548 return EFI_INVALID_PARAMETER;
549 }
550
551 DEBUG ((REDFISH_HTTP_CACHE_DEBUG, "%a: delete: %s\n", __func__, Data->Uri));
552
553 RemoveEntryList (&Data->List);
554 --List->Count;
555
556 return ReleaseHttpCacheData (Data);
557}
558
559/**
560 Add new cache by given URI and HTTP response to specify List.
561
562 @param[in] List Target cache list to add.
563 @param[in] Uri The URI string matching to this cache data.
564 @param[in] Response HTTP response.
565
566 @retval EFI_SUCCESS Cache data is added.
567 @retval Others Fail to add cache data.
568
569**/
570EFI_STATUS
571AddHttpCacheData (
572 IN REDFISH_HTTP_CACHE_LIST *List,
573 IN EFI_STRING Uri,
574 IN REDFISH_RESPONSE *Response
575 )
576{
577 REDFISH_HTTP_CACHE_DATA *NewData;
578 REDFISH_HTTP_CACHE_DATA *OldData;
579 REDFISH_HTTP_CACHE_DATA *UnusedData;
580 REDFISH_RESPONSE *NewResponse;
581
582 if ((List == NULL) || IS_EMPTY_STRING (Uri) || (Response == NULL)) {
583 return EFI_INVALID_PARAMETER;
584 }
585
586 //
587 // If same cache data exist, replace it with latest one.
588 //
589 OldData = FindHttpCacheData (&List->Head, Uri);
590 if (OldData != NULL) {
591 DeleteHttpCacheData (List, OldData);
592 }
593
594 //
595 // Check capacity
596 //
597 if (List->Count >= List->Capacity) {
598 DEBUG ((REDFISH_HTTP_CACHE_DEBUG, "%a: list is full and retire unused cache\n", __func__));
599 UnusedData = FindUnusedHttpCacheData (&List->Head);
600 if (UnusedData == NULL) {
601 return EFI_OUT_OF_RESOURCES;
602 }
603
604 DeleteHttpCacheData (List, UnusedData);
605 }
606
607 //
608 // Clone a local copy
609 //
610 NewResponse = CloneRedfishResponse (Response);
611 if (NewResponse == NULL) {
612 return EFI_OUT_OF_RESOURCES;
613 }
614
615 NewData = NewHttpCacheData (Uri, NewResponse);
616 if (NewData == NULL) {
617 return EFI_OUT_OF_RESOURCES;
618 }
619
620 InsertTailList (&List->Head, &NewData->List);
621 ++List->Count;
622
623 DEBUG ((REDFISH_HTTP_CACHE_DEBUG, "%a: cache(%d/%d) %s\n", __func__, List->Count, List->Capacity, NewData->Uri));
624
625 return EFI_SUCCESS;
626}
627
628/**
629 Release all cache from list.
630
631 @param[in] CacheList The list to be released.
632
633 @retval EFI_SUCCESS All cache data are released.
634 @retval EFI_INVALID_PARAMETER CacheList is NULL.
635
636**/
637EFI_STATUS
638ReleaseCacheList (
639 IN REDFISH_HTTP_CACHE_LIST *CacheList
640 )
641{
642 LIST_ENTRY *List;
643 LIST_ENTRY *Next;
644 REDFISH_HTTP_CACHE_DATA *Data;
645
646 if (CacheList == NULL) {
647 return EFI_INVALID_PARAMETER;
648 }
649
650 if (IsListEmpty (&CacheList->Head)) {
651 return EFI_SUCCESS;
652 }
653
654 Data = NULL;
655 Next = NULL;
656 List = GetFirstNode (&CacheList->Head);
657 while (!IsNull (&CacheList->Head, List)) {
658 Data = REDFISH_HTTP_CACHE_FROM_LIST (List);
659 Next = GetNextNode (&CacheList->Head, List);
660
661 DeleteHttpCacheData (CacheList, Data);
662
663 List = Next;
664 }
665
666 return EFI_SUCCESS;
667}
Note: See TracBrowser for help on using the repository browser.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette