]> git.proxmox.com Git - mirror_edk2.git/blame - RedfishPkg/PrivateLibrary/RedfishLib/edk2libredfish/src/service.c
RedfishPkg: Redfish functions for REST requests are not fully spec complied
[mirror_edk2.git] / RedfishPkg / PrivateLibrary / RedfishLib / edk2libredfish / src / service.c
CommitLineData
4751a48a
AC
1/** @file\r
2 This file is cloned from DMTF libredfish library tag v1.0.0 and maintained\r
3 by EDKII.\r
4\r
5//----------------------------------------------------------------------------\r
6// Copyright Notice:\r
7// Copyright 2017 Distributed Management Task Force, Inc. All rights reserved.\r
8// License: BSD 3-Clause License. For full text see link: https://github.com/DMTF/libredfish/LICENSE.md\r
9//----------------------------------------------------------------------------\r
10\r
11 Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>\r
12 (C) Copyright 2021 Hewlett Packard Enterprise Development LP<BR>\r
13\r
14 SPDX-License-Identifier: BSD-2-Clause-Patent\r
15\r
16**/\r
17\r
18#include <redfishService.h>\r
19#include <redfishPayload.h>\r
20#include <redpath.h>\r
21\r
39de741e
MK
22static int\r
23initRest (\r
24 redfishService *service,\r
25 void *restProtocol\r
26 );\r
27\r
28static redfishService *\r
29createServiceEnumeratorNoAuth (\r
30 const char *host,\r
31 const char *rootUri,\r
32 bool enumerate,\r
33 unsigned int flags,\r
34 void *restProtocol\r
35 );\r
36\r
37static redfishService *\r
38createServiceEnumeratorBasicAuth (\r
39 const char *host,\r
40 const char *rootUri,\r
41 const char *username,\r
42 const char *password,\r
43 unsigned int flags,\r
44 void *restProtocol\r
45 );\r
46\r
47static redfishService *\r
48createServiceEnumeratorSessionAuth (\r
49 const char *host,\r
50 const char *rootUri,\r
51 const char *username,\r
52 const char *password,\r
53 unsigned int flags,\r
54 void *restProtocol\r
55 );\r
56\r
57static char *\r
58makeUrlForService (\r
59 redfishService *service,\r
60 const char *uri\r
61 );\r
62\r
63static json_t *\r
64getVersions (\r
65 redfishService *service,\r
66 const char *rootUri\r
67 );\r
68\r
69static void\r
70addStringToJsonObject (\r
71 json_t *object,\r
72 const char *key,\r
73 const char *value\r
74 );\r
75\r
76CHAR16 *\r
77C8ToC16 (\r
78 CHAR8 *AsciiStr\r
79 )\r
4751a48a 80{\r
39de741e 81 CHAR16 *Str;\r
4751a48a
AC
82 UINTN BufLen;\r
83\r
84 BufLen = (AsciiStrLen (AsciiStr) + 1) * 2;\r
39de741e 85 Str = AllocatePool (BufLen);\r
4751a48a
AC
86 ASSERT (Str != NULL);\r
87\r
88 AsciiStrToUnicodeStrS (AsciiStr, Str, AsciiStrLen (AsciiStr) + 1);\r
89\r
90 return Str;\r
91}\r
92\r
93VOID\r
94RestConfigFreeHttpRequestData (\r
39de741e 95 IN EFI_HTTP_REQUEST_DATA *RequestData\r
4751a48a
AC
96 )\r
97{\r
98 if (RequestData == NULL) {\r
39de741e 99 return;\r
4751a48a
AC
100 }\r
101\r
102 if (RequestData->Url != NULL) {\r
103 FreePool (RequestData->Url);\r
104 }\r
105\r
106 FreePool (RequestData);\r
107}\r
108\r
109VOID\r
110RestConfigFreeHttpMessage (\r
39de741e
MK
111 IN EFI_HTTP_MESSAGE *Message,\r
112 IN BOOLEAN IsRequest\r
4751a48a
AC
113 )\r
114{\r
115 if (Message == NULL) {\r
39de741e 116 return;\r
4751a48a
AC
117 }\r
118\r
119 if (IsRequest) {\r
120 RestConfigFreeHttpRequestData (Message->Data.Request);\r
121 Message->Data.Request = NULL;\r
122 } else {\r
123 if (Message->Data.Response != NULL) {\r
124 FreePool (Message->Data.Response);\r
125 Message->Data.Response = NULL;\r
126 }\r
127 }\r
128\r
129 if (Message->Headers != NULL) {\r
130 FreePool (Message->Headers);\r
131 Message->Headers = NULL;\r
132 }\r
39de741e 133\r
4751a48a
AC
134 if (Message->Body != NULL) {\r
135 FreePool (Message->Body);\r
136 Message->Body = NULL;\r
137 }\r
138}\r
139\r
140/**\r
141 Converts the Unicode string to ASCII string to a new allocated buffer.\r
142\r
143 @param[in] String Unicode string to be converted.\r
144\r
145 @return Buffer points to ASCII string, or NULL if error happens.\r
146\r
147**/\r
4751a48a
AC
148CHAR8 *\r
149UnicodeStrDupToAsciiStr (\r
39de741e 150 CONST CHAR16 *String\r
4751a48a
AC
151 )\r
152{\r
39de741e
MK
153 CHAR8 *AsciiStr;\r
154 UINTN BufLen;\r
155 EFI_STATUS Status;\r
4751a48a 156\r
39de741e 157 BufLen = StrLen (String) + 1;\r
4751a48a
AC
158 AsciiStr = AllocatePool (BufLen);\r
159 if (AsciiStr == NULL) {\r
160 return NULL;\r
161 }\r
162\r
163 Status = UnicodeStrToAsciiStrS (String, AsciiStr, BufLen);\r
164 if (EFI_ERROR (Status)) {\r
165 return NULL;\r
166 }\r
167\r
168 return AsciiStr;\r
169}\r
39de741e 170\r
4751a48a
AC
171/**\r
172 This function encodes the content.\r
173\r
174 @param[in] ContentEncodedValue HTTP conent encoded value.\r
175 @param[in] OriginalContent Original content.\r
176 @param[out] EncodedContent Pointer to receive encoded content.\r
177 @param[out] EncodedContentLength Length of encoded content.\r
178\r
179 @retval EFI_SUCCESS Content encoded successfully.\r
180 @retval EFI_UNSUPPORTED No source encoding funciton,\r
181 @retval EFI_INVALID_PARAMETER One of the given parameter is invalid.\r
182\r
183**/\r
184EFI_STATUS\r
185EncodeRequestContent (\r
39de741e
MK
186 IN CHAR8 *ContentEncodedValue,\r
187 IN CHAR8 *OriginalContent,\r
188 OUT VOID **EncodedContent,\r
189 OUT UINTN *EncodedContentLength\r
190 )\r
4751a48a 191{\r
39de741e
MK
192 EFI_STATUS Status;\r
193 VOID *EncodedPointer;\r
194 UINTN EncodedLength;\r
4751a48a 195\r
39de741e 196 if ((OriginalContent == NULL) || (EncodedContent == NULL) || (EncodedContentLength == NULL)) {\r
4751a48a
AC
197 return EFI_INVALID_PARAMETER;\r
198 }\r
39de741e
MK
199\r
200 Status = RedfishContentEncode (\r
4751a48a
AC
201 ContentEncodedValue,\r
202 OriginalContent,\r
203 AsciiStrLen (OriginalContent),\r
204 &EncodedPointer,\r
205 &EncodedLength\r
39de741e 206 );\r
4751a48a 207 if (Status == EFI_SUCCESS) {\r
39de741e 208 *EncodedContent = EncodedPointer;\r
4751a48a
AC
209 *EncodedContentLength = EncodedLength;\r
210 return EFI_SUCCESS;\r
211 }\r
39de741e 212\r
4751a48a
AC
213 return Status;\r
214}\r
215\r
216/**\r
217 This function decodes the content. The Memory block pointed by\r
218 ContentPointer would be freed and replaced with the cooked Redfish\r
219 payload.\r
220\r
221 @param[in] ContentEncodedValue HTTP conent encoded value.\r
222 @param[in, out] ContentPointer Pointer to encoded content.\r
223 Pointer of decoded content when out.\r
224 @param[in, out] ContentLength Pointer to the length of encoded content.\r
225 Length of decoded content when out.\r
226\r
227 @retval EFI_SUCCESS Functinos found.\r
228 @retval EFI_UNSUPPORTED No functions found.\r
229 @retval EFI_INVALID_PARAMETER One of the given parameter is invalid.\r
230\r
231**/\r
232EFI_STATUS\r
233DecodeResponseContent (\r
39de741e
MK
234 IN CHAR8 *ContentEncodedValue,\r
235 IN OUT VOID **ContentPointer,\r
236 IN OUT UINTN *ContentLength\r
237 )\r
4751a48a 238{\r
39de741e
MK
239 EFI_STATUS Status;\r
240 VOID *DecodedPointer;\r
241 UINTN DecodedLength;\r
4751a48a
AC
242\r
243 if (ContentEncodedValue == NULL) {\r
244 return EFI_INVALID_PARAMETER;\r
245 }\r
39de741e 246\r
4751a48a 247 Status = RedfishContentDecode (\r
39de741e
MK
248 ContentEncodedValue,\r
249 *ContentPointer,\r
250 *ContentLength,\r
251 &DecodedPointer,\r
252 &DecodedLength\r
253 );\r
4751a48a
AC
254 if (Status == EFI_SUCCESS) {\r
255 FreePool (*ContentPointer);\r
256 *ContentPointer = DecodedPointer;\r
39de741e 257 *ContentLength = DecodedLength;\r
4751a48a 258 }\r
39de741e 259\r
4751a48a
AC
260 return Status;\r
261}\r
262\r
263/**\r
264 Create a HTTP URL string for specific Redfish resource.\r
265\r
266 This function build a URL string from the Redfish Host interface record and caller specified\r
267 relative path of the resource.\r
268\r
269 Callers are responsible for freeing the returned string storage pointed by HttpUrl.\r
270\r
271 @param[in] RedfishData Redfish network host interface record.\r
272 @param[in] RelativePath Relative path of a resource.\r
273 @param[out] HttpUrl The pointer to store the returned URL string.\r
274\r
275 @retval EFI_SUCCESS Build the URL string successfully.\r
276 @retval EFI_INVALID_PARAMETER RedfishData or HttpUrl is NULL.\r
277 @retval EFI_OUT_OF_RESOURCES There are not enough memory resources.\r
278\r
279**/\r
280EFI_STATUS\r
281RedfishBuildUrl (\r
39de741e
MK
282 IN REDFISH_CONFIG_SERVICE_INFORMATION *RedfishConfigServiceInfo,\r
283 IN CHAR16 *RelativePath OPTIONAL,\r
284 OUT CHAR16 **HttpUrl\r
4751a48a
AC
285 )\r
286{\r
39de741e
MK
287 CHAR16 *Url;\r
288 CHAR16 *UrlHead;\r
289 UINTN UrlLength;\r
290 UINTN PathLen;\r
4751a48a
AC
291\r
292 if ((RedfishConfigServiceInfo == NULL) || (HttpUrl == NULL)) {\r
293 return EFI_INVALID_PARAMETER;\r
294 }\r
295\r
296 //\r
297 // RFC2616: http_URL = "http(s):" "//" host [ ":" port ] [ abs_path [ "?" query ]]\r
298 //\r
299 if (RelativePath == NULL) {\r
300 PathLen = 0;\r
301 } else {\r
302 PathLen = StrLen (RelativePath);\r
303 }\r
39de741e
MK
304\r
305 UrlLength = StrLen (HTTPS_FLAG) + StrLen (REDFISH_FIRST_URL) + 1 + StrLen (RedfishConfigServiceInfo->RedfishServiceLocation) + PathLen;\r
306 Url = AllocateZeroPool (UrlLength * sizeof (CHAR16));\r
4751a48a
AC
307 if (Url == NULL) {\r
308 return EFI_OUT_OF_RESOURCES;\r
309 }\r
310\r
311 UrlHead = Url;\r
312 //\r
313 // Copy "http://" or "https://" according RedfishServiceIpPort.\r
314 //\r
315 if (!RedfishConfigServiceInfo->RedfishServiceUseHttps) {\r
316 StrCpyS (Url, StrLen (HTTPS_FLAG) + 1, HTTP_FLAG);\r
317 Url = Url + StrLen (HTTP_FLAG);\r
318 } else {\r
319 StrCpyS (Url, StrLen (HTTPS_FLAG) + 1, HTTPS_FLAG);\r
320 Url = Url + StrLen (HTTPS_FLAG);\r
321 }\r
322\r
323 StrCpyS (Url, StrLen (RedfishConfigServiceInfo->RedfishServiceLocation) + 1, RedfishConfigServiceInfo->RedfishServiceLocation);\r
324 Url = Url + StrLen (RedfishConfigServiceInfo->RedfishServiceLocation);\r
325\r
326 //\r
327 // Copy abs_path\r
328 //\r
39de741e 329 if ((RelativePath != NULL) && (PathLen != 0)) {\r
4751a48a
AC
330 StrnCpyS (Url, UrlLength, RelativePath, PathLen);\r
331 }\r
39de741e 332\r
4751a48a
AC
333 *HttpUrl = UrlHead;\r
334 return EFI_SUCCESS;\r
335}\r
336\r
39de741e
MK
337redfishService *\r
338createServiceEnumerator (\r
339 REDFISH_CONFIG_SERVICE_INFORMATION *RedfishConfigServiceInfo,\r
340 const char *rootUri,\r
341 enumeratorAuthentication *auth,\r
342 unsigned int flags\r
343 )\r
4751a48a 344{\r
39de741e
MK
345 EFI_STATUS Status;\r
346 CHAR16 *HttpUrl;\r
347 CHAR8 *AsciiHost;\r
348 EFI_REST_EX_PROTOCOL *RestEx;\r
349 redfishService *ret;\r
4751a48a 350\r
39de741e 351 HttpUrl = NULL;\r
4751a48a 352 AsciiHost = NULL;\r
39de741e
MK
353 RestEx = NULL;\r
354 ret = NULL;\r
4751a48a
AC
355\r
356 if (RedfishConfigServiceInfo->RedfishServiceRestExHandle == NULL) {\r
357 goto ON_EXIT;\r
358 }\r
39de741e
MK
359\r
360 Status = RedfishBuildUrl (RedfishConfigServiceInfo, NULL, &HttpUrl);\r
4751a48a
AC
361 if (EFI_ERROR (Status)) {\r
362 goto ON_EXIT;\r
363 }\r
364\r
365 ASSERT (HttpUrl != NULL);\r
366\r
367 AsciiHost = UnicodeStrDupToAsciiStr (HttpUrl);\r
368 if (AsciiHost == NULL) {\r
369 goto ON_EXIT;\r
370 }\r
371\r
372 Status = gBS->HandleProtocol (\r
39de741e
MK
373 RedfishConfigServiceInfo->RedfishServiceRestExHandle,\r
374 &gEfiRestExProtocolGuid,\r
375 (VOID **)&RestEx\r
376 );\r
4751a48a
AC
377 if (EFI_ERROR (Status)) {\r
378 goto ON_EXIT;\r
379 }\r
39de741e
MK
380\r
381 if (auth == NULL) {\r
382 ret = createServiceEnumeratorNoAuth (AsciiHost, rootUri, true, flags, RestEx);\r
383 } else if (auth->authType == REDFISH_AUTH_BASIC) {\r
384 ret = createServiceEnumeratorBasicAuth (AsciiHost, rootUri, auth->authCodes.userPass.username, auth->authCodes.userPass.password, flags, RestEx);\r
385 } else if (auth->authType == REDFISH_AUTH_SESSION) {\r
386 ret = createServiceEnumeratorSessionAuth (AsciiHost, rootUri, auth->authCodes.userPass.username, auth->authCodes.userPass.password, flags, RestEx);\r
4751a48a
AC
387 } else {\r
388 goto ON_EXIT;\r
389 }\r
390\r
391 ret->RestEx = RestEx;\r
392ON_EXIT:\r
393 if (HttpUrl != NULL) {\r
394 FreePool (HttpUrl);\r
395 }\r
396\r
397 if (AsciiHost != NULL) {\r
398 FreePool (AsciiHost);\r
399 }\r
400\r
401 return ret;\r
402}\r
403\r
39de741e
MK
404json_t *\r
405getUriFromService (\r
406 redfishService *service,\r
407 const char *uri,\r
408 EFI_HTTP_STATUS_CODE **StatusCode\r
409 )\r
4751a48a 410{\r
39de741e
MK
411 char *url;\r
412 json_t *ret;\r
413 HTTP_IO_HEADER *HttpIoHeader = NULL;\r
414 EFI_STATUS Status;\r
415 EFI_HTTP_REQUEST_DATA *RequestData = NULL;\r
416 EFI_HTTP_MESSAGE *RequestMsg = NULL;\r
417 EFI_HTTP_MESSAGE ResponseMsg;\r
418 EFI_HTTP_HEADER *ContentEncodedHeader;\r
419\r
420 if ((service == NULL) || (uri == NULL) || (StatusCode == NULL)) {\r
421 return NULL;\r
4751a48a
AC
422 }\r
423\r
424 *StatusCode = NULL;\r
425\r
39de741e
MK
426 url = makeUrlForService (service, uri);\r
427 if (!url) {\r
428 return NULL;\r
4751a48a
AC
429 }\r
430\r
39de741e 431 DEBUG ((DEBUG_INFO, "libredfish: getUriFromService(): %a\n", url));\r
4751a48a
AC
432\r
433 //\r
434 // Step 1: Create HTTP request message with 4 headers:\r
435 //\r
436 HttpIoHeader = HttpIoCreateHeader ((service->sessionToken || service->basicAuthStr) ? 6 : 5);\r
437 if (HttpIoHeader == NULL) {\r
438 ret = NULL;\r
439 goto ON_EXIT;\r
440 }\r
441\r
39de741e 442 if (service->sessionToken) {\r
4751a48a
AC
443 Status = HttpIoSetHeader (HttpIoHeader, "X-Auth-Token", service->sessionToken);\r
444 ASSERT_EFI_ERROR (Status);\r
445 } else if (service->basicAuthStr) {\r
446 Status = HttpIoSetHeader (HttpIoHeader, "Authorization", service->basicAuthStr);\r
447 ASSERT_EFI_ERROR (Status);\r
448 }\r
449\r
450 Status = HttpIoSetHeader (HttpIoHeader, "Host", service->HostHeaderValue);\r
451 ASSERT_EFI_ERROR (Status);\r
452 Status = HttpIoSetHeader (HttpIoHeader, "OData-Version", "4.0");\r
453 ASSERT_EFI_ERROR (Status);\r
454 Status = HttpIoSetHeader (HttpIoHeader, "Accept", "application/json");\r
455 ASSERT_EFI_ERROR (Status);\r
456 Status = HttpIoSetHeader (HttpIoHeader, "User-Agent", "libredfish");\r
457 ASSERT_EFI_ERROR (Status);\r
458 Status = HttpIoSetHeader (HttpIoHeader, "Connection", "Keep-Alive");\r
459 ASSERT_EFI_ERROR (Status);\r
460\r
461 //\r
462 // Step 2: build the rest of HTTP request info.\r
463 //\r
464 RequestData = AllocateZeroPool (sizeof (EFI_HTTP_REQUEST_DATA));\r
465 if (RequestData == NULL) {\r
466 ret = NULL;\r
467 goto ON_EXIT;\r
468 }\r
469\r
470 RequestData->Method = HttpMethodGet;\r
39de741e 471 RequestData->Url = C8ToC16 (url);\r
4751a48a
AC
472\r
473 //\r
474 // Step 3: fill in EFI_HTTP_MESSAGE\r
475 //\r
476 RequestMsg = AllocateZeroPool (sizeof (EFI_HTTP_MESSAGE));\r
477 if (RequestMsg == NULL) {\r
478 ret = NULL;\r
479 goto ON_EXIT;\r
480 }\r
481\r
482 RequestMsg->Data.Request = RequestData;\r
483 RequestMsg->HeaderCount = HttpIoHeader->HeaderCount;\r
484 RequestMsg->Headers = HttpIoHeader->Headers;\r
485\r
486 ZeroMem (&ResponseMsg, sizeof (ResponseMsg));\r
487\r
488 //\r
489 // Step 4: call RESTEx to get response from REST service.\r
490 //\r
491 Status = service->RestEx->SendReceive (service->RestEx, RequestMsg, &ResponseMsg);\r
492 if (EFI_ERROR (Status)) {\r
493 ret = NULL;\r
494 goto ON_EXIT;\r
495 }\r
496\r
497 //\r
498 // Step 5: Return the HTTP StatusCode and Body message.\r
499 //\r
500 if (ResponseMsg.Data.Response != NULL) {\r
501 *StatusCode = AllocateZeroPool (sizeof (EFI_HTTP_STATUS_CODE));\r
502 if (*StatusCode == NULL) {\r
503 ret = NULL;\r
504 goto ON_EXIT;\r
505 }\r
506\r
507 //\r
508 // The caller shall take the responsibility to free the buffer.\r
509 //\r
510 **StatusCode = ResponseMsg.Data.Response->StatusCode;\r
511 }\r
512\r
39de741e 513 if ((ResponseMsg.BodyLength != 0) && (ResponseMsg.Body != NULL)) {\r
4751a48a
AC
514 //\r
515 // Check if data is encoded.\r
516 //\r
517 ContentEncodedHeader = HttpFindHeader (ResponseMsg.HeaderCount, ResponseMsg.Headers, HTTP_HEADER_CONTENT_ENCODING);\r
518 if (ContentEncodedHeader != NULL) {\r
519 //\r
520 // The content is encoded.\r
521 //\r
522 Status = DecodeResponseContent (ContentEncodedHeader->FieldValue, &ResponseMsg.Body, &ResponseMsg.BodyLength);\r
523 if (EFI_ERROR (Status)) {\r
524 DEBUG ((DEBUG_ERROR, "%a: Failed to decompress the response content %r\n.", __FUNCTION__, Status));\r
525 ret = NULL;\r
526 goto ON_EXIT;\r
527 }\r
528 }\r
39de741e 529\r
4751a48a
AC
530 ret = json_loadb (ResponseMsg.Body, ResponseMsg.BodyLength, 0, NULL);\r
531 } else {\r
532 //\r
533 // There is no message body returned from server.\r
534 //\r
535 ret = NULL;\r
536 }\r
537\r
538ON_EXIT:\r
539 if (url != NULL) {\r
540 free (url);\r
541 }\r
542\r
543 if (HttpIoHeader != NULL) {\r
544 HttpIoFreeHeader (HttpIoHeader);\r
545 }\r
546\r
547 if (RequestData != NULL) {\r
548 RestConfigFreeHttpRequestData (RequestData);\r
549 }\r
550\r
551 if (RequestMsg != NULL) {\r
552 FreePool (RequestMsg);\r
553 }\r
554\r
555 RestConfigFreeHttpMessage (&ResponseMsg, FALSE);\r
556\r
557 return ret;\r
558}\r
559\r
39de741e
MK
560json_t *\r
561patchUriFromService (\r
562 redfishService *service,\r
563 const char *uri,\r
564 const char *content,\r
565 EFI_HTTP_STATUS_CODE **StatusCode\r
566 )\r
4751a48a 567{\r
39de741e
MK
568 char *url;\r
569 json_t *ret;\r
570 HTTP_IO_HEADER *HttpIoHeader = NULL;\r
571 EFI_STATUS Status;\r
572 EFI_HTTP_REQUEST_DATA *RequestData = NULL;\r
573 EFI_HTTP_MESSAGE *RequestMsg = NULL;\r
574 EFI_HTTP_MESSAGE ResponseMsg;\r
575 CHAR8 ContentLengthStr[80];\r
576 CHAR8 *EncodedContent;\r
577 UINTN EncodedContentLen;\r
578\r
579 if ((service == NULL) || (uri == NULL) || (content == NULL) || (StatusCode == NULL)) {\r
580 return NULL;\r
4751a48a
AC
581 }\r
582\r
583 *StatusCode = NULL;\r
584\r
39de741e
MK
585 url = makeUrlForService (service, uri);\r
586 if (!url) {\r
587 return NULL;\r
4751a48a
AC
588 }\r
589\r
39de741e 590 DEBUG ((DEBUG_INFO, "libredfish: patchUriFromService(): %a\n", url));\r
4751a48a
AC
591\r
592 //\r
593 // Step 1: Create HTTP request message with 4 headers:\r
594 //\r
595 HttpIoHeader = HttpIoCreateHeader ((service->sessionToken || service->basicAuthStr) ? 9 : 8);\r
596 if (HttpIoHeader == NULL) {\r
597 ret = NULL;\r
598 goto ON_EXIT;\r
599 }\r
600\r
39de741e 601 if (service->sessionToken) {\r
4751a48a
AC
602 Status = HttpIoSetHeader (HttpIoHeader, "X-Auth-Token", service->sessionToken);\r
603 ASSERT_EFI_ERROR (Status);\r
604 } else if (service->basicAuthStr) {\r
605 Status = HttpIoSetHeader (HttpIoHeader, "Authorization", service->basicAuthStr);\r
606 ASSERT_EFI_ERROR (Status);\r
607 }\r
608\r
609 Status = HttpIoSetHeader (HttpIoHeader, "Host", service->HostHeaderValue);\r
610 ASSERT_EFI_ERROR (Status);\r
611 Status = HttpIoSetHeader (HttpIoHeader, "Content-Type", "application/json");\r
612 ASSERT_EFI_ERROR (Status);\r
613 Status = HttpIoSetHeader (HttpIoHeader, "Accept", "application/json");\r
614 ASSERT_EFI_ERROR (Status);\r
615 Status = HttpIoSetHeader (HttpIoHeader, "User-Agent", "libredfish");\r
616 ASSERT_EFI_ERROR (Status);\r
617 Status = HttpIoSetHeader (HttpIoHeader, "Connection", "Keep-Alive");\r
618 ASSERT_EFI_ERROR (Status);\r
619\r
39de741e 620 AsciiSPrint (\r
4751a48a
AC
621 ContentLengthStr,\r
622 sizeof (ContentLengthStr),\r
623 "%lu",\r
39de741e 624 (UINT64)strlen (content)\r
4751a48a
AC
625 );\r
626 Status = HttpIoSetHeader (HttpIoHeader, "Content-Length", ContentLengthStr);\r
627 ASSERT_EFI_ERROR (Status);\r
628 Status = HttpIoSetHeader (HttpIoHeader, "OData-Version", "4.0");\r
629 ASSERT_EFI_ERROR (Status);\r
630\r
631 //\r
632 // Step 2: build the rest of HTTP request info.\r
633 //\r
634 RequestData = AllocateZeroPool (sizeof (EFI_HTTP_REQUEST_DATA));\r
635 if (RequestData == NULL) {\r
636 ret = NULL;\r
637 goto ON_EXIT;\r
638 }\r
639\r
640 RequestData->Method = HttpMethodPatch;\r
39de741e 641 RequestData->Url = C8ToC16 (url);\r
4751a48a
AC
642\r
643 //\r
644 // Step 3: fill in EFI_HTTP_MESSAGE\r
645 //\r
646 RequestMsg = AllocateZeroPool (sizeof (EFI_HTTP_MESSAGE));\r
647 if (RequestMsg == NULL) {\r
648 ret = NULL;\r
649 goto ON_EXIT;\r
650 }\r
651\r
39de741e
MK
652 EncodedContent = (CHAR8 *)content;\r
653 EncodedContentLen = strlen (content);\r
4751a48a
AC
654 //\r
655 // We currently only support gzip Content-Encoding.\r
656 //\r
657 Status = EncodeRequestContent ((CHAR8 *)HTTP_CONTENT_ENCODING_GZIP, (CHAR8 *)content, (VOID **)&EncodedContent, &EncodedContentLen);\r
658 if (Status == EFI_INVALID_PARAMETER) {\r
39de741e 659 DEBUG ((DEBUG_ERROR, "%a: Error to encode content.\n", __FUNCTION__));\r
4751a48a
AC
660 ret = NULL;\r
661 goto ON_EXIT;\r
662 } else if (Status == EFI_UNSUPPORTED) {\r
39de741e 663 DEBUG ((DEBUG_INFO, "No content coding for %a! Use raw data instead.\n", HTTP_CONTENT_ENCODING_GZIP));\r
4751a48a
AC
664 Status = HttpIoSetHeader (HttpIoHeader, "Content-Encoding", HTTP_CONTENT_ENCODING_IDENTITY);\r
665 ASSERT_EFI_ERROR (Status);\r
666 } else {\r
667 Status = HttpIoSetHeader (HttpIoHeader, "Content-Encoding", HTTP_CONTENT_ENCODING_GZIP);\r
668 ASSERT_EFI_ERROR (Status);\r
669 }\r
670\r
671 RequestMsg->Data.Request = RequestData;\r
672 RequestMsg->HeaderCount = HttpIoHeader->HeaderCount;\r
673 RequestMsg->Headers = HttpIoHeader->Headers;\r
674 RequestMsg->BodyLength = EncodedContentLen;\r
39de741e 675 RequestMsg->Body = (VOID *)EncodedContent;\r
4751a48a
AC
676\r
677 ZeroMem (&ResponseMsg, sizeof (ResponseMsg));\r
678\r
679 //\r
680 // Step 4: call RESTEx to get response from REST service.\r
681 //\r
682 Status = service->RestEx->SendReceive (service->RestEx, RequestMsg, &ResponseMsg);\r
683 if (EFI_ERROR (Status)) {\r
684 ret = NULL;\r
685 goto ON_EXIT;\r
686 }\r
687\r
688 //\r
689 // Step 5: Return the HTTP StatusCode and Body message.\r
690 //\r
691 if (ResponseMsg.Data.Response != NULL) {\r
692 *StatusCode = AllocateZeroPool (sizeof (EFI_HTTP_STATUS_CODE));\r
693 if (*StatusCode == NULL) {\r
694 ret = NULL;\r
695 goto ON_EXIT;\r
696 }\r
697\r
698 //\r
699 // The caller shall take the responsibility to free the buffer.\r
700 //\r
701 **StatusCode = ResponseMsg.Data.Response->StatusCode;\r
702 }\r
703\r
704 if (EncodedContent != content) {\r
705 FreePool (EncodedContent);\r
706 }\r
707\r
39de741e 708 if ((ResponseMsg.BodyLength != 0) && (ResponseMsg.Body != NULL)) {\r
4751a48a
AC
709 ret = json_loadb (ResponseMsg.Body, ResponseMsg.BodyLength, 0, NULL);\r
710 } else {\r
711 //\r
712 // There is no message body returned from server.\r
713 //\r
714 ret = NULL;\r
715 }\r
716\r
717ON_EXIT:\r
718 if (url != NULL) {\r
719 free (url);\r
720 }\r
721\r
722 if (HttpIoHeader != NULL) {\r
723 HttpIoFreeHeader (HttpIoHeader);\r
724 }\r
725\r
726 if (RequestData != NULL) {\r
727 RestConfigFreeHttpRequestData (RequestData);\r
728 }\r
729\r
730 if (RequestMsg != NULL) {\r
731 FreePool (RequestMsg);\r
732 }\r
733\r
734 RestConfigFreeHttpMessage (&ResponseMsg, FALSE);\r
735\r
736 return ret;\r
737}\r
738\r
39de741e
MK
739json_t *\r
740postUriFromService (\r
741 redfishService *service,\r
742 const char *uri,\r
743 const char *content,\r
744 size_t contentLength,\r
745 const char *contentType,\r
746 EFI_HTTP_STATUS_CODE **StatusCode\r
747 )\r
4751a48a 748{\r
39de741e
MK
749 char *url = NULL;\r
750 json_t *ret;\r
751 HTTP_IO_HEADER *HttpIoHeader = NULL;\r
752 EFI_STATUS Status;\r
753 EFI_HTTP_REQUEST_DATA *RequestData = NULL;\r
754 EFI_HTTP_MESSAGE *RequestMsg = NULL;\r
755 EFI_HTTP_MESSAGE ResponseMsg;\r
756 CHAR8 ContentLengthStr[80];\r
757 EFI_HTTP_HEADER *HttpHeader = NULL;\r
4751a48a
AC
758\r
759 ret = NULL;\r
760\r
39de741e
MK
761 if ((service == NULL) || (uri == NULL) || (content == NULL) || (StatusCode == NULL)) {\r
762 return NULL;\r
4751a48a
AC
763 }\r
764\r
765 *StatusCode = NULL;\r
766\r
39de741e
MK
767 url = makeUrlForService (service, uri);\r
768 if (!url) {\r
769 return NULL;\r
4751a48a
AC
770 }\r
771\r
39de741e 772 DEBUG ((DEBUG_INFO, "libredfish: postUriFromService(): %a\n", url));\r
4751a48a 773\r
39de741e
MK
774 if (contentLength == 0) {\r
775 contentLength = strlen (content);\r
4751a48a
AC
776 }\r
777\r
778 //\r
779 // Step 1: Create HTTP request message with 4 headers:\r
780 //\r
781 HttpIoHeader = HttpIoCreateHeader ((service->sessionToken || service->basicAuthStr) ? 8 : 7);\r
782 if (HttpIoHeader == NULL) {\r
783 goto ON_EXIT;\r
784 }\r
785\r
39de741e 786 if (service->sessionToken) {\r
4751a48a
AC
787 Status = HttpIoSetHeader (HttpIoHeader, "X-Auth-Token", service->sessionToken);\r
788 ASSERT_EFI_ERROR (Status);\r
789 } else if (service->basicAuthStr) {\r
790 Status = HttpIoSetHeader (HttpIoHeader, "Authorization", service->basicAuthStr);\r
791 ASSERT_EFI_ERROR (Status);\r
792 }\r
793\r
39de741e 794 if (contentType == NULL) {\r
4751a48a
AC
795 Status = HttpIoSetHeader (HttpIoHeader, "Content-Type", "application/json");\r
796 ASSERT_EFI_ERROR (Status);\r
797 } else {\r
39de741e 798 Status = HttpIoSetHeader (HttpIoHeader, "Content-Type", (CHAR8 *)contentType);\r
4751a48a
AC
799 ASSERT_EFI_ERROR (Status);\r
800 }\r
39de741e 801\r
4751a48a
AC
802 Status = HttpIoSetHeader (HttpIoHeader, "Host", service->HostHeaderValue);\r
803 ASSERT_EFI_ERROR (Status);\r
804 Status = HttpIoSetHeader (HttpIoHeader, "Accept", "application/json");\r
805 ASSERT_EFI_ERROR (Status);\r
806 Status = HttpIoSetHeader (HttpIoHeader, "User-Agent", "libredfish");\r
807 ASSERT_EFI_ERROR (Status);\r
808 Status = HttpIoSetHeader (HttpIoHeader, "Connection", "Keep-Alive");\r
809 ASSERT_EFI_ERROR (Status);\r
39de741e 810 AsciiSPrint (\r
4751a48a
AC
811 ContentLengthStr,\r
812 sizeof (ContentLengthStr),\r
813 "%lu",\r
39de741e 814 (UINT64)contentLength\r
4751a48a
AC
815 );\r
816 Status = HttpIoSetHeader (HttpIoHeader, "Content-Length", ContentLengthStr);\r
817 ASSERT_EFI_ERROR (Status);\r
818 Status = HttpIoSetHeader (HttpIoHeader, "OData-Version", "4.0");\r
819 ASSERT_EFI_ERROR (Status);\r
820\r
821 //\r
822 // Step 2: build the rest of HTTP request info.\r
823 //\r
824 RequestData = AllocateZeroPool (sizeof (EFI_HTTP_REQUEST_DATA));\r
825 if (RequestData == NULL) {\r
826 goto ON_EXIT;\r
827 }\r
828\r
829 RequestData->Method = HttpMethodPost;\r
39de741e 830 RequestData->Url = C8ToC16 (url);\r
4751a48a
AC
831\r
832 //\r
833 // Step 3: fill in EFI_HTTP_MESSAGE\r
834 //\r
835 RequestMsg = AllocateZeroPool (sizeof (EFI_HTTP_MESSAGE));\r
836 if (RequestMsg == NULL) {\r
837 goto ON_EXIT;\r
838 }\r
839\r
840 RequestMsg->Data.Request = RequestData;\r
841 RequestMsg->HeaderCount = HttpIoHeader->HeaderCount;\r
842 RequestMsg->Headers = HttpIoHeader->Headers;\r
843 RequestMsg->BodyLength = contentLength;\r
39de741e 844 RequestMsg->Body = (VOID *)content;\r
4751a48a
AC
845\r
846 ZeroMem (&ResponseMsg, sizeof (ResponseMsg));\r
847\r
848 //\r
849 // Step 4: call RESTEx to get response from REST service.\r
850 //\r
851 Status = service->RestEx->SendReceive (service->RestEx, RequestMsg, &ResponseMsg);\r
852 if (EFI_ERROR (Status)) {\r
853 goto ON_EXIT;\r
854 }\r
855\r
856 //\r
857 // Step 5: Return the HTTP StatusCode and Body message.\r
858 //\r
859 if (ResponseMsg.Data.Response != NULL) {\r
860 *StatusCode = AllocateZeroPool (sizeof (EFI_HTTP_STATUS_CODE));\r
861 if (*StatusCode == NULL) {\r
862 goto ON_EXIT;\r
863 }\r
864\r
865 //\r
866 // The caller shall take the responsibility to free the buffer.\r
867 //\r
868 **StatusCode = ResponseMsg.Data.Response->StatusCode;\r
869 }\r
870\r
39de741e 871 if ((ResponseMsg.BodyLength != 0) && (ResponseMsg.Body != NULL)) {\r
4751a48a
AC
872 ret = json_loadb (ResponseMsg.Body, ResponseMsg.BodyLength, 0, NULL);\r
873 }\r
874\r
875 //\r
876 // Step 6: Parsing the HttpHeader to retrive the X-Auth-Token if the HTTP StatusCode is correct.\r
877 //\r
39de741e
MK
878 if ((ResponseMsg.Data.Response->StatusCode == HTTP_STATUS_200_OK) ||\r
879 (ResponseMsg.Data.Response->StatusCode == HTTP_STATUS_204_NO_CONTENT))\r
880 {\r
4751a48a
AC
881 HttpHeader = HttpFindHeader (ResponseMsg.HeaderCount, ResponseMsg.Headers, "X-Auth-Token");\r
882 if (HttpHeader != NULL) {\r
39de741e
MK
883 if (service->sessionToken) {\r
884 free (service->sessionToken);\r
4751a48a 885 }\r
39de741e 886\r
4751a48a
AC
887 service->sessionToken = AllocateCopyPool (AsciiStrSize (HttpHeader->FieldValue), HttpHeader->FieldValue);\r
888 }\r
889\r
890 /*\r
891 //\r
892 // Below opeation seems to be unnecessary.\r
893 // Besides, the FieldValue for the Location is the full HTTP URI (Http://0.0.0.0:5000/XXX), so we can't use it as the\r
894 // parameter of getUriFromService () directly.\r
895 //\r
896 HttpHeader = HttpFindHeader (ResponseMsg.HeaderCount, ResponseMsg.Headers, "Location");\r
897 if (HttpHeader != NULL) {\r
898 ret = getUriFromService(service, HttpHeader->FieldValue);\r
899 goto ON_EXIT;\r
900 }\r
901 */\r
902 }\r
903\r
904ON_EXIT:\r
905 if (url != NULL) {\r
906 free (url);\r
907 }\r
908\r
909 if (HttpIoHeader != NULL) {\r
910 HttpIoFreeHeader (HttpIoHeader);\r
911 }\r
912\r
913 if (RequestData != NULL) {\r
914 RestConfigFreeHttpRequestData (RequestData);\r
915 }\r
916\r
917 if (RequestMsg != NULL) {\r
918 FreePool (RequestMsg);\r
919 }\r
920\r
921 RestConfigFreeHttpMessage (&ResponseMsg, FALSE);\r
922\r
923 return ret;\r
924}\r
925\r
39de741e 926json_t *\r
f2bf043a 927deleteUriFromServiceEx (\r
39de741e
MK
928 redfishService *service,\r
929 const char *uri,\r
f2bf043a 930 const char *content,\r
39de741e
MK
931 EFI_HTTP_STATUS_CODE **StatusCode\r
932 )\r
4751a48a 933{\r
39de741e
MK
934 char *url;\r
935 json_t *ret;\r
936 HTTP_IO_HEADER *HttpIoHeader = NULL;\r
937 EFI_STATUS Status;\r
938 EFI_HTTP_REQUEST_DATA *RequestData = NULL;\r
939 EFI_HTTP_MESSAGE *RequestMsg = NULL;\r
940 EFI_HTTP_MESSAGE ResponseMsg;\r
f2bf043a
AC
941 CHAR8 ContentLengthStr[80];\r
942 size_t contentLength;\r
4751a48a
AC
943\r
944 ret = NULL;\r
945\r
39de741e
MK
946 if ((service == NULL) || (uri == NULL) || (StatusCode == NULL)) {\r
947 return NULL;\r
4751a48a
AC
948 }\r
949\r
950 *StatusCode = NULL;\r
951\r
39de741e
MK
952 url = makeUrlForService (service, uri);\r
953 if (!url) {\r
954 return NULL;\r
4751a48a
AC
955 }\r
956\r
39de741e 957 DEBUG ((DEBUG_INFO, "libredfish: deleteUriFromService(): %a\n", url));\r
4751a48a
AC
958\r
959 //\r
960 // Step 1: Create HTTP request message with 4 headers:\r
961 //\r
f2bf043a 962 HttpIoHeader = HttpIoCreateHeader ((service->sessionToken || service->basicAuthStr) ? 8 : 7);\r
4751a48a
AC
963 if (HttpIoHeader == NULL) {\r
964 ret = NULL;\r
965 goto ON_EXIT;\r
966 }\r
967\r
39de741e 968 if (service->sessionToken) {\r
4751a48a
AC
969 Status = HttpIoSetHeader (HttpIoHeader, "X-Auth-Token", service->sessionToken);\r
970 ASSERT_EFI_ERROR (Status);\r
971 } else if (service->basicAuthStr) {\r
972 Status = HttpIoSetHeader (HttpIoHeader, "Authorization", service->basicAuthStr);\r
973 ASSERT_EFI_ERROR (Status);\r
974 }\r
39de741e 975\r
4751a48a
AC
976 Status = HttpIoSetHeader (HttpIoHeader, "Host", service->HostHeaderValue);\r
977 ASSERT_EFI_ERROR (Status);\r
978 Status = HttpIoSetHeader (HttpIoHeader, "User-Agent", "libredfish");\r
979 ASSERT_EFI_ERROR (Status);\r
980 Status = HttpIoSetHeader (HttpIoHeader, "OData-Version", "4.0");\r
981 ASSERT_EFI_ERROR (Status);\r
982 Status = HttpIoSetHeader (HttpIoHeader, "Connection", "Keep-Alive");\r
983 ASSERT_EFI_ERROR (Status);\r
984\r
f2bf043a
AC
985 Status = HttpIoSetHeader (HttpIoHeader, "Content-Type", "application/json");\r
986 ASSERT_EFI_ERROR (Status);\r
987\r
988 if (content != NULL) {\r
989 contentLength = strlen (content);\r
990 AsciiSPrint (\r
991 ContentLengthStr,\r
992 sizeof (ContentLengthStr),\r
993 "%lu",\r
994 (UINT64)contentLength\r
995 );\r
996 Status = HttpIoSetHeader (HttpIoHeader, "Content-Length", ContentLengthStr);\r
997 ASSERT_EFI_ERROR (Status);\r
998 Status = HttpIoSetHeader (HttpIoHeader, "OData-Version", "4.0");\r
999 ASSERT_EFI_ERROR (Status);\r
1000 }\r
1001\r
4751a48a
AC
1002 //\r
1003 // Step 2: build the rest of HTTP request info.\r
1004 //\r
1005 RequestData = AllocateZeroPool (sizeof (EFI_HTTP_REQUEST_DATA));\r
1006 if (RequestData == NULL) {\r
1007 ret = NULL;\r
1008 goto ON_EXIT;\r
1009 }\r
1010\r
1011 RequestData->Method = HttpMethodDelete;\r
39de741e 1012 RequestData->Url = C8ToC16 (url);\r
4751a48a
AC
1013\r
1014 //\r
1015 // Step 3: fill in EFI_HTTP_MESSAGE\r
1016 //\r
1017 RequestMsg = AllocateZeroPool (sizeof (EFI_HTTP_MESSAGE));\r
1018 if (RequestMsg == NULL) {\r
1019 ret = NULL;\r
1020 goto ON_EXIT;\r
1021 }\r
1022\r
1023 RequestMsg->Data.Request = RequestData;\r
1024 RequestMsg->HeaderCount = HttpIoHeader->HeaderCount;\r
1025 RequestMsg->Headers = HttpIoHeader->Headers;\r
1026\r
f2bf043a
AC
1027 if (content != NULL) {\r
1028 RequestMsg->BodyLength = contentLength;\r
1029 RequestMsg->Body = (VOID *)content;\r
1030 }\r
1031\r
4751a48a
AC
1032 ZeroMem (&ResponseMsg, sizeof (ResponseMsg));\r
1033\r
1034 //\r
1035 // Step 4: call RESTEx to get response from REST service.\r
1036 //\r
1037 Status = service->RestEx->SendReceive (service->RestEx, RequestMsg, &ResponseMsg);\r
1038 if (EFI_ERROR (Status)) {\r
1039 ret = NULL;\r
1040 goto ON_EXIT;\r
1041 }\r
1042\r
1043 //\r
1044 // Step 5: Return the HTTP StatusCode and Body message.\r
1045 //\r
1046 if (ResponseMsg.Data.Response != NULL) {\r
1047 *StatusCode = AllocateZeroPool (sizeof (EFI_HTTP_STATUS_CODE));\r
1048 if (*StatusCode == NULL) {\r
1049 ret = NULL;\r
1050 goto ON_EXIT;\r
1051 }\r
1052\r
1053 //\r
1054 // The caller shall take the responsibility to free the buffer.\r
1055 //\r
1056 **StatusCode = ResponseMsg.Data.Response->StatusCode;\r
1057 }\r
1058\r
39de741e 1059 if ((ResponseMsg.BodyLength != 0) && (ResponseMsg.Body != NULL)) {\r
4751a48a
AC
1060 ret = json_loadb (ResponseMsg.Body, ResponseMsg.BodyLength, 0, NULL);\r
1061 }\r
1062\r
1063ON_EXIT:\r
1064 if (url != NULL) {\r
1065 free (url);\r
1066 }\r
1067\r
1068 if (HttpIoHeader != NULL) {\r
1069 HttpIoFreeHeader (HttpIoHeader);\r
1070 }\r
1071\r
1072 if (RequestData != NULL) {\r
1073 RestConfigFreeHttpRequestData (RequestData);\r
1074 }\r
1075\r
1076 if (RequestMsg != NULL) {\r
1077 FreePool (RequestMsg);\r
1078 }\r
1079\r
1080 RestConfigFreeHttpMessage (&ResponseMsg, FALSE);\r
1081\r
1082 return ret;\r
1083}\r
1084\r
f2bf043a
AC
1085json_t *\r
1086deleteUriFromService (\r
1087 redfishService *service,\r
1088 const char *uri,\r
1089 EFI_HTTP_STATUS_CODE **StatusCode\r
1090 )\r
1091{\r
1092 return deleteUriFromServiceEx (service, uri, NULL, StatusCode);\r
1093}\r
1094\r
39de741e
MK
1095redfishPayload *\r
1096getRedfishServiceRoot (\r
1097 redfishService *service,\r
1098 const char *version,\r
1099 EFI_HTTP_STATUS_CODE **StatusCode\r
1100 )\r
4751a48a 1101{\r
39de741e
MK
1102 json_t *value;\r
1103 json_t *versionNode;\r
1104 const char *verUrl;\r
4751a48a 1105\r
39de741e
MK
1106 if (version == NULL) {\r
1107 versionNode = json_object_get (service->versions, "v1");\r
1108 } else {\r
1109 versionNode = json_object_get (service->versions, version);\r
1110 }\r
1111\r
1112 if (versionNode == NULL) {\r
1113 return NULL;\r
1114 }\r
1115\r
1116 verUrl = json_string_value (versionNode);\r
1117 if (verUrl == NULL) {\r
1118 return NULL;\r
1119 }\r
1120\r
1121 value = getUriFromService (service, verUrl, StatusCode);\r
1122 if (value == NULL) {\r
1123 if ((service->flags & REDFISH_FLAG_SERVICE_NO_VERSION_DOC) == 0) {\r
1124 json_decref (versionNode);\r
4751a48a 1125 }\r
39de741e
MK
1126\r
1127 return NULL;\r
1128 }\r
1129\r
1130 return createRedfishPayload (value, service);\r
4751a48a
AC
1131}\r
1132\r
39de741e
MK
1133redfishPayload *\r
1134getPayloadByPath (\r
1135 redfishService *service,\r
1136 const char *path,\r
1137 EFI_HTTP_STATUS_CODE **StatusCode\r
1138 )\r
4751a48a 1139{\r
39de741e
MK
1140 redPathNode *redpath;\r
1141 redfishPayload *root;\r
1142 redfishPayload *ret;\r
4751a48a 1143\r
39de741e
MK
1144 if (!service || !path || (StatusCode == NULL)) {\r
1145 return NULL;\r
1146 }\r
4751a48a 1147\r
39de741e 1148 *StatusCode = NULL;\r
4751a48a 1149\r
39de741e
MK
1150 redpath = parseRedPath (path);\r
1151 if (!redpath) {\r
1152 return NULL;\r
1153 }\r
4751a48a 1154\r
39de741e
MK
1155 if (!redpath->isRoot) {\r
1156 cleanupRedPath (redpath);\r
1157 return NULL;\r
1158 }\r
4751a48a 1159\r
39de741e
MK
1160 root = getRedfishServiceRoot (service, redpath->version, StatusCode);\r
1161 if ((*StatusCode == NULL) || (**StatusCode < HTTP_STATUS_200_OK) || (**StatusCode > HTTP_STATUS_206_PARTIAL_CONTENT)) {\r
1162 cleanupRedPath (redpath);\r
1163 return root;\r
1164 }\r
4751a48a 1165\r
39de741e
MK
1166 if (redpath->next == NULL) {\r
1167 cleanupRedPath (redpath);\r
1168 return root;\r
1169 }\r
1170\r
1171 FreePool (*StatusCode);\r
1172 *StatusCode = NULL;\r
1173\r
1174 ret = getPayloadForPath (root, redpath->next, StatusCode);\r
1175 if ((*StatusCode == NULL) && (ret != NULL)) {\r
1176 //\r
1177 // In such a case, the Redfish resource is parsed from the input payload (root) directly.\r
1178 // So, we still return HTTP_STATUS_200_OK.\r
1179 //\r
1180 *StatusCode = AllocateZeroPool (sizeof (EFI_HTTP_STATUS_CODE));\r
1181 if (*StatusCode == NULL) {\r
1182 ret = NULL;\r
1183 } else {\r
1184 **StatusCode = HTTP_STATUS_200_OK;\r
4751a48a 1185 }\r
39de741e
MK
1186 }\r
1187\r
1188 cleanupPayload (root);\r
1189 cleanupRedPath (redpath);\r
1190 return ret;\r
4751a48a
AC
1191}\r
1192\r
39de741e
MK
1193void\r
1194cleanupServiceEnumerator (\r
1195 redfishService *service\r
1196 )\r
4751a48a 1197{\r
39de741e
MK
1198 if (!service) {\r
1199 return;\r
4751a48a 1200 }\r
39de741e
MK
1201\r
1202 free (service->host);\r
1203 json_decref (service->versions);\r
1204 if (service->sessionToken != NULL) {\r
1205 ZeroMem (service->sessionToken, (UINTN)strlen (service->sessionToken));\r
1206 FreePool (service->sessionToken);\r
4751a48a 1207 }\r
39de741e 1208\r
4751a48a 1209 if (service->basicAuthStr != NULL) {\r
39de741e
MK
1210 ZeroMem (service->basicAuthStr, (UINTN)strlen (service->basicAuthStr));\r
1211 FreePool (service->basicAuthStr);\r
4751a48a 1212 }\r
39de741e
MK
1213\r
1214 free (service);\r
4751a48a
AC
1215}\r
1216\r
39de741e
MK
1217static int\r
1218initRest (\r
1219 redfishService *service,\r
1220 void *restProtocol\r
1221 )\r
4751a48a
AC
1222{\r
1223 service->RestEx = restProtocol;\r
1224 return 0;\r
1225}\r
1226\r
39de741e
MK
1227static redfishService *\r
1228createServiceEnumeratorNoAuth (\r
1229 const char *host,\r
1230 const char *rootUri,\r
1231 bool enumerate,\r
1232 unsigned int flags,\r
1233 void *restProtocol\r
1234 )\r
4751a48a 1235{\r
39de741e
MK
1236 redfishService *ret;\r
1237 char *HostStart;\r
1238\r
1239 ret = (redfishService *)calloc (1, sizeof (redfishService));\r
1240 ZeroMem (ret, sizeof (redfishService));\r
1241 if (initRest (ret, restProtocol) != 0) {\r
1242 free (ret);\r
1243 return NULL;\r
1244 }\r
1245\r
1246 ret->host = AllocateCopyPool (AsciiStrSize (host), host);\r
1247 ret->flags = flags;\r
1248 if (enumerate) {\r
1249 ret->versions = getVersions (ret, rootUri);\r
1250 }\r
4751a48a 1251\r
39de741e
MK
1252 HostStart = strstr (ret->host, "//");\r
1253 if ((HostStart != NULL) && (*(HostStart + 2) != '\0')) {\r
1254 ret->HostHeaderValue = HostStart + 2;\r
1255 }\r
1256\r
1257 return ret;\r
4751a48a
AC
1258}\r
1259\r
1260EFI_STATUS\r
1261createBasicAuthStr (\r
39de741e
MK
1262 IN redfishService *service,\r
1263 IN CONST CHAR8 *UserId,\r
1264 IN CONST CHAR8 *Password\r
4751a48a
AC
1265 )\r
1266{\r
39de741e
MK
1267 EFI_STATUS Status;\r
1268 CHAR8 *RawAuthValue;\r
1269 UINTN RawAuthBufSize;\r
1270 CHAR8 *EnAuthValue;\r
1271 UINTN EnAuthValueSize;\r
1272 CHAR8 *BasicWithEnAuthValue;\r
1273 UINTN BasicBufSize;\r
4751a48a
AC
1274\r
1275 EnAuthValue = NULL;\r
1276 EnAuthValueSize = 0;\r
1277\r
1278 RawAuthBufSize = AsciiStrLen (UserId) + AsciiStrLen (Password) + 2;\r
39de741e 1279 RawAuthValue = AllocatePool (RawAuthBufSize);\r
4751a48a
AC
1280 if (RawAuthValue == NULL) {\r
1281 return EFI_OUT_OF_RESOURCES;\r
1282 }\r
1283\r
1284 //\r
1285 // Build raw AuthValue (UserId:Password).\r
1286 //\r
1287 AsciiSPrint (\r
1288 RawAuthValue,\r
1289 RawAuthBufSize,\r
1290 "%a:%a",\r
1291 UserId,\r
1292 Password\r
1293 );\r
1294\r
1295 //\r
1296 // Encoding RawAuthValue into Base64 format.\r
1297 //\r
1298 Status = Base64Encode (\r
39de741e 1299 (CONST UINT8 *)RawAuthValue,\r
4751a48a
AC
1300 AsciiStrLen (RawAuthValue),\r
1301 EnAuthValue,\r
1302 &EnAuthValueSize\r
1303 );\r
1304 if (Status == EFI_BUFFER_TOO_SMALL) {\r
39de741e 1305 EnAuthValue = (CHAR8 *)AllocateZeroPool (EnAuthValueSize);\r
4751a48a
AC
1306 if (EnAuthValue == NULL) {\r
1307 Status = EFI_OUT_OF_RESOURCES;\r
1308 return Status;\r
1309 }\r
1310\r
1311 Status = Base64Encode (\r
39de741e 1312 (CONST UINT8 *)RawAuthValue,\r
4751a48a
AC
1313 AsciiStrLen (RawAuthValue),\r
1314 EnAuthValue,\r
1315 &EnAuthValueSize\r
1316 );\r
1317 }\r
1318\r
1319 if (EFI_ERROR (Status)) {\r
1320 goto Exit;\r
1321 }\r
1322\r
39de741e 1323 BasicBufSize = AsciiStrLen ("Basic ") + AsciiStrLen (EnAuthValue) + 2;\r
4751a48a
AC
1324 BasicWithEnAuthValue = AllocatePool (BasicBufSize);\r
1325 if (BasicWithEnAuthValue == NULL) {\r
1326 Status = EFI_OUT_OF_RESOURCES;\r
1327 goto Exit;\r
1328 }\r
1329\r
1330 //\r
1331 // Build encoded EnAuthValue with Basic (Basic EnAuthValue).\r
1332 //\r
1333 AsciiSPrint (\r
1334 BasicWithEnAuthValue,\r
1335 BasicBufSize,\r
1336 "%a %a",\r
1337 "Basic",\r
1338 EnAuthValue\r
1339 );\r
1340\r
1341 service->basicAuthStr = BasicWithEnAuthValue;\r
1342\r
1343Exit:\r
1344 if (RawAuthValue != NULL) {\r
1345 ZeroMem (RawAuthValue, RawAuthBufSize);\r
1346 FreePool (RawAuthValue);\r
1347 }\r
1348\r
1349 if (EnAuthValue != NULL) {\r
1350 ZeroMem (EnAuthValue, EnAuthValueSize);\r
1351 FreePool (EnAuthValue);\r
1352 }\r
1353\r
1354 return Status;\r
1355}\r
1356\r
39de741e
MK
1357static redfishService *\r
1358createServiceEnumeratorBasicAuth (\r
1359 const char *host,\r
1360 const char *rootUri,\r
1361 const char *username,\r
1362 const char *password,\r
1363 unsigned int flags,\r
1364 void *restProtocol\r
1365 )\r
4751a48a 1366{\r
39de741e
MK
1367 redfishService *ret;\r
1368 EFI_STATUS Status;\r
4751a48a 1369\r
39de741e 1370 ret = createServiceEnumeratorNoAuth (host, rootUri, false, flags, restProtocol);\r
4751a48a 1371\r
39de741e
MK
1372 // add basic auth str\r
1373 Status = createBasicAuthStr (ret, username, password);\r
1374 if (EFI_ERROR (Status)) {\r
1375 cleanupServiceEnumerator (ret);\r
1376 return NULL;\r
1377 }\r
4751a48a 1378\r
39de741e
MK
1379 ret->versions = getVersions (ret, rootUri);\r
1380 return ret;\r
4751a48a
AC
1381}\r
1382\r
39de741e
MK
1383static redfishService *\r
1384createServiceEnumeratorSessionAuth (\r
1385 const char *host,\r
1386 const char *rootUri,\r
1387 const char *username,\r
1388 const char *password,\r
1389 unsigned int flags,\r
1390 void *restProtocol\r
1391 )\r
4751a48a 1392{\r
39de741e
MK
1393 redfishService *ret;\r
1394 redfishPayload *payload;\r
1395 redfishPayload *links;\r
1396 json_t *sessionPayload;\r
1397 json_t *session;\r
1398 json_t *odataId;\r
1399 const char *uri;\r
1400 json_t *post;\r
1401 char *content;\r
1402 EFI_HTTP_STATUS_CODE *StatusCode;\r
1403\r
1404 content = NULL;\r
1405 StatusCode = NULL;\r
1406\r
1407 ret = createServiceEnumeratorNoAuth (host, rootUri, true, flags, restProtocol);\r
1408 if (ret == NULL) {\r
1409 return NULL;\r
1410 }\r
4751a48a 1411\r
39de741e
MK
1412 payload = getRedfishServiceRoot (ret, NULL, &StatusCode);\r
1413 if ((StatusCode == NULL) || (*StatusCode < HTTP_STATUS_200_OK) || (*StatusCode > HTTP_STATUS_206_PARTIAL_CONTENT)) {\r
4751a48a
AC
1414 if (StatusCode != NULL) {\r
1415 FreePool (StatusCode);\r
4751a48a
AC
1416 }\r
1417\r
39de741e
MK
1418 if (payload != NULL) {\r
1419 cleanupPayload (payload);\r
4751a48a
AC
1420 }\r
1421\r
39de741e
MK
1422 cleanupServiceEnumerator (ret);\r
1423 return NULL;\r
1424 }\r
1425\r
1426 if (StatusCode != NULL) {\r
1427 FreePool (StatusCode);\r
1428 StatusCode = NULL;\r
1429 }\r
1430\r
1431 links = getPayloadByNodeName (payload, "Links", &StatusCode);\r
1432 cleanupPayload (payload);\r
1433 if (links == NULL) {\r
1434 cleanupServiceEnumerator (ret);\r
1435 return NULL;\r
1436 }\r
4751a48a 1437\r
39de741e
MK
1438 session = json_object_get (links->json, "Sessions");\r
1439 if (session == NULL) {\r
1440 cleanupPayload (links);\r
1441 cleanupServiceEnumerator (ret);\r
1442 return NULL;\r
1443 }\r
4751a48a 1444\r
39de741e
MK
1445 odataId = json_object_get (session, "@odata.id");\r
1446 if (odataId == NULL) {\r
1447 cleanupPayload (links);\r
1448 cleanupServiceEnumerator (ret);\r
1449 return NULL;\r
1450 }\r
1451\r
1452 uri = json_string_value (odataId);\r
1453 post = json_object ();\r
1454 addStringToJsonObject (post, "UserName", username);\r
1455 addStringToJsonObject (post, "Password", password);\r
1456 content = json_dumps (post, 0);\r
1457 json_decref (post);\r
1458 sessionPayload = postUriFromService (ret, uri, content, 0, NULL, &StatusCode);\r
1459\r
1460 if (content != NULL) {\r
1461 ZeroMem (content, (UINTN)strlen (content));\r
1462 free (content);\r
1463 }\r
1464\r
1465 if ((sessionPayload == NULL) || (StatusCode == NULL) || (*StatusCode < HTTP_STATUS_200_OK) || (*StatusCode > HTTP_STATUS_206_PARTIAL_CONTENT)) {\r
1466 // Failed to create session!\r
4751a48a 1467\r
39de741e
MK
1468 cleanupPayload (links);\r
1469 cleanupServiceEnumerator (ret);\r
4751a48a 1470\r
39de741e
MK
1471 if (StatusCode != NULL) {\r
1472 FreePool (StatusCode);\r
4751a48a 1473 }\r
39de741e
MK
1474\r
1475 if (sessionPayload != NULL) {\r
1476 json_decref (sessionPayload);\r
1477 }\r
1478\r
1479 return NULL;\r
1480 }\r
1481\r
1482 json_decref (sessionPayload);\r
1483 cleanupPayload (links);\r
1484 FreePool (StatusCode);\r
1485 return ret;\r
4751a48a
AC
1486}\r
1487\r
39de741e
MK
1488static char *\r
1489makeUrlForService (\r
1490 redfishService *service,\r
1491 const char *uri\r
1492 )\r
4751a48a 1493{\r
39de741e
MK
1494 char *url;\r
1495\r
1496 if (service->host == NULL) {\r
1497 return NULL;\r
1498 }\r
1499\r
1500 url = (char *)malloc (strlen (service->host)+strlen (uri)+1);\r
1501 strcpy (url, service->host);\r
1502 strcat (url, uri);\r
1503 return url;\r
4751a48a
AC
1504}\r
1505\r
39de741e
MK
1506static json_t *\r
1507getVersions (\r
1508 redfishService *service,\r
1509 const char *rootUri\r
1510 )\r
4751a48a 1511{\r
39de741e
MK
1512 json_t *ret = NULL;\r
1513 EFI_HTTP_STATUS_CODE *StatusCode = NULL;\r
4751a48a 1514\r
39de741e
MK
1515 if (service->flags & REDFISH_FLAG_SERVICE_NO_VERSION_DOC) {\r
1516 service->versions = json_object ();\r
1517 if (service->versions == NULL) {\r
1518 return NULL;\r
4751a48a
AC
1519 }\r
1520\r
39de741e
MK
1521 addStringToJsonObject (service->versions, "v1", "/redfish/v1");\r
1522 return service->versions;\r
1523 }\r
1524\r
1525 if (rootUri != NULL) {\r
1526 ret = getUriFromService (service, rootUri, &StatusCode);\r
1527 } else {\r
1528 ret = getUriFromService (service, "/redfish", &StatusCode);\r
1529 }\r
1530\r
1531 if ((ret == NULL) || (StatusCode == NULL) || (*StatusCode < HTTP_STATUS_200_OK) || (*StatusCode > HTTP_STATUS_206_PARTIAL_CONTENT)) {\r
1532 if (ret != NULL) {\r
1533 json_decref (ret);\r
4751a48a
AC
1534 }\r
1535\r
39de741e
MK
1536 ret = NULL;\r
1537 }\r
1538\r
1539 if (StatusCode != NULL) {\r
1540 FreePool (StatusCode);\r
1541 }\r
1542\r
1543 return ret;\r
4751a48a
AC
1544}\r
1545\r
39de741e
MK
1546static void\r
1547addStringToJsonObject (\r
1548 json_t *object,\r
1549 const char *key,\r
1550 const char *value\r
1551 )\r
4751a48a 1552{\r
39de741e 1553 json_t *jValue = json_string (value);\r
4751a48a 1554\r
39de741e 1555 json_object_set (object, key, jValue);\r
4751a48a 1556\r
39de741e 1557 json_decref (jValue);\r
4751a48a 1558}\r