--- /dev/null
+/** @file\r
+ This library provides a set of utility APIs that allow to create/read/update/delete\r
+ (CRUD) Redfish resources and provide basic query abilities by using [URI/RedPath]\r
+ (https://github.com/DMTF/libredfish).\r
+\r
+ The query language is based on XPath (https://www.w3.org/TR/1999/REC-xpath-19991116/).\r
+ This library and query language essentially treat the entire Redfish Service like it\r
+ was a single JSON document. In other words whenever it encounters an odata.id in JSON\r
+ document, it will retrieve the new JSON document (if needed). We name the path as\r
+ RedPath:\r
+\r
+ Expression Description\r
+\r
+ nodename Selects the JSON entity with the name "nodename".\r
+ If the value of nodename is an object with "@odata.id",\r
+ it will continue get the value from "@odata.id".\r
+\r
+ / Selects from the root node\r
+\r
+ [index] Selects the index number JSON entity from an array or\r
+ object. If the JSON entity is one collection (has\r
+ Members & Members@odata.count), means to get the index\r
+ member in "Members". Index number >=1, 1 means to return\r
+ the first instance.\r
+\r
+ [XXX] Operation on JSON entity.\r
+ If the JSON entity is one collection (has Members &\r
+ Members@odata.count), means to get all elements in\r
+ "Members". If the JSON entity is one array, means to\r
+ get all elements in array. Others will match the nodename\r
+ directly (e.g. JSON_OBJECT, JSON_STRING, JSON_TRUE,\r
+ JSON_FALSE, JSON_INTEGER).\r
+\r
+ [nodename] Selects all the elements from an JSON entity that\r
+ contain a property named "nodename"\r
+\r
+ [name=value] Selects all the elements from an JSON entity where\r
+ the property "name" is equal to "value"\r
+\r
+ [name~value] Selects all the elements from an JSON entity where\r
+ the string property "name" is equal to "value" using\r
+ case insensitive comparison.\r
+\r
+ [name<value] Selects all the elements from an JSON entity where\r
+ the property "name" is less than "value"\r
+\r
+ [name<=value] Selects all the elements from an JSON entity where\r
+ the property "name" is less than or equal to "value"\r
+\r
+ [name>value] Selects all the elements from an JSON entity where\r
+ the property "name" is greater than "value"\r
+\r
+ [name>=value] Selects all the elements from an JSON entity where\r
+ the property "name" is greater than or equal to "value"\r
+\r
+ Some examples:\r
+\r
+ /v1/Chassis[1] - Will return the first Chassis instance.\r
+ /v1/Chassis[SKU=1234] - Will return all Chassis instances with a SKU field equal to 1234.\r
+ /v1/Systems[Storage] - Will return all the System instances that have Storage field populated.\r
+\r
+ Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>\r
+ (C) Copyright 2021 Hewlett Packard Enterprise Development LP<BR>\r
+\r
+ SPDX-License-Identifier: BSD-2-Clause-Patent\r
+\r
+**/\r
+\r
+#ifndef REDFISH_LIB_H_\r
+#define REDFISH_LIB_H_\r
+\r
+#include <Library/JsonLib.h>\r
+\r
+#include <Protocol/Http.h>\r
+#include <Protocol/EdkIIRedfishConfigHandler.h>\r
+\r
+#define ODATA_TYPE_NAME_MAX_SIZE 128\r
+#define ODATA_TYPE_MAX_SIZE 128\r
+\r
+///\r
+/// Library class public defines\r
+///\r
+typedef VOID* REDFISH_SERVICE;\r
+typedef VOID* REDFISH_PAYLOAD;\r
+\r
+///\r
+/// Library class public structures/unions\r
+///\r
+typedef struct {\r
+ EFI_HTTP_STATUS_CODE *StatusCode;\r
+ UINTN HeaderCount;\r
+ EFI_HTTP_HEADER *Headers;\r
+ REDFISH_PAYLOAD Payload;\r
+} REDFISH_RESPONSE;\r
+\r
+///\r
+/// Odata type-name mapping structure.\r
+///\r
+typedef struct {\r
+ CONST CHAR8 OdataTypeName [ODATA_TYPE_NAME_MAX_SIZE];\r
+ CONST CHAR8 OdataType [ODATA_TYPE_MAX_SIZE];\r
+} REDFISH_ODATA_TYPE_MAPPING;\r
+\r
+/**\r
+ This function uses REST EX protocol provided in RedfishConfigServiceInfo.\r
+ The service enumerator will also handle the authentication flow automatically\r
+ if HTTP basic auth or Redfish session login is configured to use.\r
+\r
+ Callers are responsible for freeing the returned service by RedfishCleanupService().\r
+\r
+ @param[in] RedfishConfigServiceInfo Redfish service information the EFI Redfish\r
+ feature driver communicates with.\r
+\r
+ @return New created Redfish Service, or NULL if error happens.\r
+\r
+**/\r
+REDFISH_SERVICE\r
+EFIAPI\r
+RedfishCreateService (\r
+ IN REDFISH_CONFIG_SERVICE_INFORMATION *RedfishConfigServiceInfo\r
+ );\r
+\r
+/**\r
+ Free the Service and all its related resources.\r
+\r
+ @param[in] RedfishService The Service to access the Redfish resources.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+RedfishCleanupService (\r
+ IN REDFISH_SERVICE RedfishService\r
+ );\r
+\r
+/**\r
+ Create REDFISH_PAYLOAD instance in local with JSON represented resource value and\r
+ the Redfish Service.\r
+\r
+ The returned REDFISH_PAYLOAD can be used to create or update Redfish resource in\r
+ server side.\r
+\r
+ Callers are responsible for freeing the returned payload by RedfishCleanupPayload().\r
+\r
+ @param[in] Value JSON Value of the redfish resource.\r
+ @param[in] RedfishService The Service to access the Redfish resources.\r
+\r
+ @return REDFISH_PAYLOAD instance of the resource, or NULL if error happens.\r
+\r
+**/\r
+REDFISH_PAYLOAD\r
+EFIAPI\r
+RedfishCreatePayload (\r
+ IN EDKII_JSON_VALUE Value,\r
+ IN REDFISH_SERVICE RedfishService\r
+ );\r
+\r
+/**\r
+ Free the RedfishPayload and all its related resources.\r
+\r
+ @param[in] Payload Payload to be freed.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+RedfishCleanupPayload (\r
+ IN REDFISH_PAYLOAD Payload\r
+ );\r
+\r
+/**\r
+ This function returns the decoded JSON value of a REDFISH_PAYLOAD.\r
+\r
+ Caller doesn't need to free the returned JSON value because it will be released\r
+ in corresponding RedfishCleanupPayload() function.\r
+\r
+ @param[in] Payload A REDFISH_PAYLOAD instance.\r
+\r
+ @return Decoded JSON value of the payload.\r
+\r
+**/\r
+EDKII_JSON_VALUE\r
+EFIAPI\r
+RedfishJsonInPayload (\r
+ IN REDFISH_PAYLOAD Payload\r
+ );\r
+\r
+/**\r
+ Fill the input RedPath string with system UUID from SMBIOS table or use the customized\r
+ ID if FromSmbios == FALSE.\r
+\r
+ This is a helper function to build a RedPath string which can be used to address\r
+ a Redfish resource for this computer system. The input PathString must have a Systems\r
+ note in format of "Systems[UUID=%g]" or "Systems[UUID~%g]" to fill the UUID value.\r
+\r
+ Example:\r
+ Use "/v1/Systems[UUID=%g]/Bios" to build a RedPath to address the "Bios" resource\r
+ for this computer system.\r
+\r
+ @param[in] RedPath RedPath format to be build.\r
+ @param[in] FromSmbios Get system UUID from SMBIOS as computer system instance ID.\r
+ @param[in] IdString The computer system instance ID.\r
+\r
+ @return Full RedPath with system UUID inside, or NULL if error happens.\r
+\r
+**/\r
+CHAR8 *\r
+EFIAPI\r
+RedfishBuildPathWithSystemUuid (\r
+ IN CONST CHAR8 *RedPath,\r
+ IN BOOLEAN FromSmbios,\r
+ IN CHAR8 *IdString OPTIONAL\r
+ );\r
+\r
+/**\r
+ Get a redfish response addressed by a RedPath string, including HTTP StatusCode, Headers\r
+ and Payload which record any HTTP response messages.\r
+\r
+ Callers are responsible for freeing the HTTP StatusCode, Headers and Payload returned in\r
+ redfish response data.\r
+\r
+ @param[in] RedfishService The Service to access the Redfish resources.\r
+ @param[in] RedPath RedPath string to address a resource, must start\r
+ from the root node.\r
+ @param[out] RedResponse Pointer to the Redfish response data.\r
+\r
+ @retval EFI_SUCCESS The opeartion is successful, indicates the HTTP StatusCode is not\r
+ NULL and the value is 2XX. The corresponding redfish resource has\r
+ been returned in Payload within RedResponse.\r
+ @retval EFI_INVALID_PARAMETER RedfishService, RedPath, or RedResponse is NULL.\r
+ @retval EFI_DEVICE_ERROR An unexpected system or network error occurred. Callers can get\r
+ more error info from returned HTTP StatusCode, Headers and Payload\r
+ within RedResponse:\r
+ 1. If the returned Payload is NULL, indicates any error happen.\r
+ 2. If the returned StatusCode is NULL, indicates any error happen.\r
+ 3. If the returned StatusCode is not 2XX, indicates any error happen.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+RedfishGetByService (\r
+ IN REDFISH_SERVICE RedfishService,\r
+ IN CONST CHAR8 *RedPath,\r
+ OUT REDFISH_RESPONSE *RedResponse\r
+ );\r
+\r
+/**\r
+ Get a redfish response addressed by URI, including HTTP StatusCode, Headers\r
+ and Payload which record any HTTP response messages.\r
+\r
+ Callers are responsible for freeing the HTTP StatusCode, Headers and Payload returned in\r
+ redfish response data.\r
+\r
+ @param[in] RedfishService The Service to access the URI resources.\r
+ @param[in] URI String to address a resource.\r
+ @param[out] RedResponse Pointer to the Redfish response data.\r
+\r
+ @retval EFI_SUCCESS The opeartion is successful, indicates the HTTP StatusCode is not\r
+ NULL and the value is 2XX. The corresponding redfish resource has\r
+ been returned in Payload within RedResponse.\r
+ @retval EFI_INVALID_PARAMETER RedfishService, RedPath, or RedResponse is NULL.\r
+ @retval EFI_DEVICE_ERROR An unexpected system or network error occurred. Callers can get\r
+ more error info from returned HTTP StatusCode, Headers and Payload\r
+ within RedResponse:\r
+ 1. If the returned Payload is NULL, indicates any error happen.\r
+ 2. If the returned StatusCode is NULL, indicates any error happen.\r
+ 3. If the returned StatusCode is not 2XX, indicates any error happen.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+RedfishGetByUri (\r
+ IN REDFISH_SERVICE RedfishService,\r
+ IN CONST CHAR8 *Uri,\r
+ OUT REDFISH_RESPONSE *RedResponse\r
+ );\r
+\r
+/**\r
+ Get a redfish response addressed by the input Payload and relative RedPath string,\r
+ including HTTP StatusCode, Headers and Payload which record any HTTP response messages.\r
+\r
+ Callers are responsible for freeing the HTTP StatusCode, Headers and Payload returned in\r
+ redfish response data.\r
+\r
+ @param[in] Payload A existing REDFISH_PAYLOAD instance.\r
+ @param[in] RedPath Relative RedPath string to address a resource inside Payload.\r
+ @param[out] RedResponse Pointer to the Redfish response data.\r
+\r
+ @retval EFI_SUCCESS The opeartion is successful:\r
+ 1. The HTTP StatusCode is NULL and the returned Payload in\r
+ RedResponse is not NULL, indicates the Redfish resource has\r
+ been parsed from the input payload directly.\r
+ 2. The HTTP StatusCode is not NULL and the value is 2XX,\r
+ indicates the corresponding redfish resource has been returned\r
+ in Payload within RedResponse.\r
+ @retval EFI_INVALID_PARAMETER Payload, RedPath, or RedResponse is NULL.\r
+ @retval EFI_DEVICE_ERROR An unexpected system or network error occurred. Callers can get\r
+ more error info from returned HTTP StatusCode, Headers and Payload\r
+ within RedResponse:\r
+ 1. If the returned Payload is NULL, indicates any error happen.\r
+ 2. If StatusCode is not NULL and the returned value of StatusCode\r
+ is not 2XX, indicates any error happen.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+RedfishGetByPayload (\r
+ IN REDFISH_PAYLOAD Payload,\r
+ IN CONST CHAR8 *RedPath,\r
+ OUT REDFISH_RESPONSE *RedResponse\r
+ );\r
+\r
+/**\r
+ Use HTTP PATCH to perform updates on pre-existing Redfish resource.\r
+\r
+ This function uses the RedfishService to patch a Redfish resource addressed by\r
+ Uri (only the relative path is required). Changes to one or more properties within\r
+ the target resource are represented in the input Content, properties not specified\r
+ in Content won't be changed by this request. The corresponding redfish response will\r
+ returned, including HTTP StatusCode, Headers and Payload which record any HTTP response\r
+ messages.\r
+\r
+ Callers are responsible for freeing the HTTP StatusCode, Headers and Payload returned in\r
+ redfish response data.\r
+\r
+ @param[in] RedfishService The Service to access the Redfish resources.\r
+ @param[in] Uri Relative path to address the resource.\r
+ @param[in] Content JSON represented properties to be update.\r
+ @param[out] RedResponse Pointer to the Redfish response data.\r
+\r
+ @retval EFI_SUCCESS The opeartion is successful, indicates the HTTP StatusCode is not\r
+ NULL and the value is 2XX. The Redfish resource will be returned\r
+ in Payload within RedResponse if server send it back in the HTTP\r
+ response message body.\r
+ @retval EFI_INVALID_PARAMETER RedfishService, Uri, Content, or RedResponse is NULL.\r
+ @retval EFI_DEVICE_ERROR An unexpected system or network error occurred. Callers can get\r
+ more error info from returned HTTP StatusCode, Headers and Payload\r
+ within RedResponse:\r
+ 1. If the returned StatusCode is NULL, indicates any error happen.\r
+ 2. If the returned StatusCode is not NULL and the value is not 2XX,\r
+ indicates any error happen.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+RedfishPatchToUri (\r
+ IN REDFISH_SERVICE RedfishService,\r
+ IN CONST CHAR8 *Uri,\r
+ IN CONST CHAR8 *Content,\r
+ OUT REDFISH_RESPONSE *RedResponse\r
+ );\r
+\r
+/**\r
+ Use HTTP PATCH to perform updates on target payload. Patch to odata.id in Payload directly.\r
+\r
+ This function uses the Payload to patch the Target. Changes to one or more properties\r
+ within the target resource are represented in the input Payload, properties not specified\r
+ in Payload won't be changed by this request. The corresponding redfish response will\r
+ returned, including HTTP StatusCode, Headers and Payload which record any HTTP response\r
+ messages.\r
+\r
+ Callers are responsible for freeing the HTTP StatusCode, Headers and Payload returned in\r
+ redfish response data.\r
+\r
+ @param[in] Target The target payload to be updated.\r
+ @param[in] Payload Palyoad with properties to be changed.\r
+ @param[out] RedResponse Pointer to the Redfish response data.\r
+\r
+ @retval EFI_SUCCESS The opeartion is successful, indicates the HTTP StatusCode is not\r
+ NULL and the value is 2XX. The Redfish resource will be returned\r
+ in Payload within RedResponse if server send it back in the HTTP\r
+ response message body.\r
+ @retval EFI_INVALID_PARAMETER Target, Payload, or RedResponse is NULL.\r
+ @retval EFI_DEVICE_ERROR An unexpected system or network error occurred. Callers can get\r
+ more error info from returned HTTP StatusCode, Headers and Payload\r
+ within RedResponse:\r
+ 1. If the returned StatusCode is NULL, indicates any error happen.\r
+ 2. If the returned StatusCode is not NULL and the value is not 2XX,\r
+ indicates any error happen.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+RedfishPatchToPayload (\r
+ IN REDFISH_PAYLOAD Target,\r
+ IN REDFISH_PAYLOAD Payload,\r
+ OUT REDFISH_RESPONSE *RedResponse\r
+ );\r
+\r
+/**\r
+ Use HTTP POST to create a new resource in target payload.\r
+\r
+ The POST request should be submitted to the Resource Collection in which the new resource\r
+ is to belong. The Resource Collection is addressed by Target payload. The Redfish may\r
+ ignore any service controlled properties. The corresponding redfish response will returned,\r
+ including HTTP StatusCode, Headers and Payload which record any HTTP response messages.\r
+\r
+ Callers are responsible for freeing the HTTP StatusCode, Headers and Payload returned in\r
+ redfish response data.\r
+\r
+ @param[in] Target Target payload of the Resource Collection.\r
+ @param[in] Payload The new resource to be created.\r
+ @param[out] RedResponse Pointer to the Redfish response data.\r
+\r
+ @retval EFI_SUCCESS The opeartion is successful, indicates the HTTP StatusCode is not\r
+ NULL and the value is 2XX. The Redfish resource will be returned\r
+ in Payload within RedResponse if server send it back in the HTTP\r
+ response message body.\r
+ @retval EFI_INVALID_PARAMETER Target, Payload, or RedResponse is NULL.\r
+ @retval EFI_DEVICE_ERROR An unexpected system or network error occurred. Callers can get\r
+ more error info from returned HTTP StatusCode, Headers and Payload\r
+ within RedResponse:\r
+ 1. If the returned StatusCode is NULL, indicates any error happen.\r
+ 2. If the returned StatusCode is not NULL and the value is not 2XX,\r
+ indicates any error happen.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+RedfishPostToPayload (\r
+ IN REDFISH_PAYLOAD Target,\r
+ IN REDFISH_PAYLOAD Payload,\r
+ OUT REDFISH_RESPONSE *RedResponse\r
+ );\r
+\r
+/**\r
+ Use HTTP DELETE to remove a resource.\r
+\r
+ This function uses the RedfishService to remove a Redfish resource which is addressed\r
+ by input Uri (only the relative path is required). The corresponding redfish response will\r
+ returned, including HTTP StatusCode, Headers and Payload which record any HTTP response\r
+ messages.\r
+\r
+ Callers are responsible for freeing the HTTP StatusCode, Headers and Payload returned in\r
+ redfish response data.\r
+\r
+ @param[in] RedfishService The Service to access the Redfish resources.\r
+ @param[in] Uri Relative path to address the resource.\r
+ @param[out] RedResponse Pointer to the Redfish response data.\r
+\r
+ @retval EFI_SUCCESS The opeartion is successful, indicates the HTTP StatusCode is not\r
+ NULL and the value is 2XX, the Redfish resource has been removed.\r
+ If there is any message returned from server, it will be returned\r
+ in Payload within RedResponse.\r
+ @retval EFI_INVALID_PARAMETER RedfishService, Uri, or RedResponse is NULL.\r
+ @retval EFI_DEVICE_ERROR An unexpected system or network error occurred. Callers can get\r
+ more error info from returned HTTP StatusCode, Headers and Payload\r
+ within RedResponse:\r
+ 1. If the returned StatusCode is NULL, indicates any error happen.\r
+ 2. If the returned StatusCode is not NULL and the value is not 2XX,\r
+ indicates any error happen.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+RedfishDeleteByUri (\r
+ IN REDFISH_SERVICE RedfishService,\r
+ IN CONST CHAR8 *Uri,\r
+ OUT REDFISH_RESPONSE *RedResponse\r
+ );\r
+\r
+/**\r
+ Dump text in fractions.\r
+\r
+ @param[in] String ASCII string to dump.\r
+\r
+**/\r
+VOID\r
+RedfishDumpJsonStringFractions (\r
+ IN CHAR8 *String\r
+ );\r
+\r
+/**\r
+ Extract the JSON text content from REDFISH_PAYLOAD and dump to debug console.\r
+\r
+ @param[in] Payload The Redfish payload to dump.\r
+\r
+**/\r
+VOID\r
+RedfishDumpPayload (\r
+ IN REDFISH_PAYLOAD Payload\r
+ );\r
+/**\r
+ Dump text in JSON value.\r
+\r
+ @param[in] JsonValue The Redfish JSON value to dump.\r
+\r
+**/\r
+VOID\r
+RedfishDumpJson (\r
+ IN EDKII_JSON_VALUE JsonValue\r
+ );\r
+/**\r
+ This function will cleanup the HTTP header and Redfish payload resources.\r
+\r
+ @param[in] StatusCode The status code in HTTP response message.\r
+ @param[in] HeaderCount Number of HTTP header structures in Headers list.\r
+ @param[in] Headers Array containing list of HTTP headers.\r
+ @param[in] Payload The Redfish payload to dump.\r
+\r
+**/\r
+VOID\r
+RedfishFreeResponse (\r
+ IN EFI_HTTP_STATUS_CODE *StatusCode,\r
+ IN UINTN HeaderCount,\r
+ IN EFI_HTTP_HEADER *Headers,\r
+ IN REDFISH_PAYLOAD Payload\r
+ );\r
+\r
+/**\r
+ Check if the "@odata.type" in Payload is valid or not.\r
+\r
+ @param[in] Payload The Redfish payload to be checked.\r
+ @param[in] OdataTypeName OdataType will be retrived from mapping list.\r
+ @param[in] OdataTypeMappingList The list of OdataType.\r
+ @param[in] OdataTypeMappingListSize The number of mapping list\r
+\r
+ @return TRUE if the "@odata.type" in Payload is valid, otherwise FALSE.\r
+\r
+**/\r
+BOOLEAN\r
+RedfishIsValidOdataType (\r
+ IN REDFISH_PAYLOAD Payload,\r
+ IN CONST CHAR8 *OdataTypeName,\r
+ IN REDFISH_ODATA_TYPE_MAPPING *OdataTypeMappingList,\r
+ IN UINTN OdataTypeMappingListSize\r
+ );\r
+\r
+/**\r
+ Check if the payload is collection\r
+\r
+ @param[in] Payload The Redfish payload to be checked.\r
+\r
+ @return TRUE if the payload is collection.\r
+\r
+**/\r
+BOOLEAN\r
+RedfishIsPayloadCollection (\r
+ IN REDFISH_PAYLOAD Payload\r
+);\r
+/**\r
+ Get collection size.\r
+\r
+ @param[in] Payload The Redfish collection payload\r
+ @param[in] CollectionSize Size of this collection\r
+\r
+ @return EFI_SUCCESS Coolection size is returned in CollectionSize\r
+ @return EFI_INVALID_PARAMETER The payload is not a collection.\r
+**/\r
+EFI_STATUS\r
+RedfishGetCollectionSize(\r
+ IN REDFISH_PAYLOAD Payload,\r
+ IN UINTN *CollectionSize\r
+);\r
+/**\r
+ Get Redfish payload of collection member\r
+\r
+ @param[in] Payload The Redfish collection payload\r
+ @param[in] Index Index of collection member\r
+\r
+ @return NULL Fail to get collection member.\r
+ @return Non NULL Payload is returned.\r
+**/\r
+REDFISH_PAYLOAD\r
+RedfishGetPayloadByIndex (\r
+ IN REDFISH_PAYLOAD Payload,\r
+ IN UINTN Index\r
+);\r
+\r
+/**\r
+ Check and return Redfish resource of the given Redpath.\r
+\r
+ @param[in] RedfishService Pointer to REDFISH_SERVICE\r
+ @param[in] Redpath Redpath of the resource.\r
+ @param[in] Response Optional return the resource.\r
+\r
+ @return EFI_STATUS\r
+**/\r
+EFI_STATUS\r
+RedfishCheckIfRedpathExist (\r
+ IN REDFISH_SERVICE RedfishService,\r
+ IN CHAR8 *Redpath,\r
+ IN REDFISH_RESPONSE *Response OPTIONAL\r
+);\r
+\r
+/**\r
+ This function returns the string of Redfish service version.\r
+\r
+ @param[in] RedfishService Redfish service instance.\r
+ @param[out] ServiceVersionStr Redfish service string.\r
+\r
+ @return EFI_STATUS\r
+\r
+**/\r
+EFI_STATUS\r
+RedfishGetServiceVersion(\r
+ IN REDFISH_SERVICE RedfishService,\r
+ OUT CHAR8 **ServiceVersionStr\r
+ );\r
+\r
+/**\r
+ This function returns the string of Redfish service version.\r
+\r
+ @param[in] ServiceVerisonStr The string of Redfish service version.\r
+ @param[in] Url The URL to build Redpath with ID.\r
+ Start with "/", for example "/Registries"\r
+ @param[in] Id ID string\r
+ @param[out] Redpath Pointer to retrive Redpath, caller has to free\r
+ the memory allocated for this string.\r
+ @return EFI_STATUS\r
+\r
+**/\r
+EFI_STATUS\r
+RedfishBuildRedpathUseId (\r
+ IN CHAR8 *ServiceVerisonStr,\r
+ IN CHAR8 *Url,\r
+ IN CHAR8 *Id,\r
+ OUT CHAR8 **Redpath\r
+ );\r
+#endif\r
--- /dev/null
+/** @file\r
+ Provides a set of utility APIs that allow to create/read/update/delete\r
+ (CRUD) Redfish resources and provide basic query.\r
+\r
+ Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>\r
+ (C) Copyright 2021 Hewlett Packard Enterprise Development LP<BR>\r
+\r
+ SPDX-License-Identifier: BSD-2-Clause-Patent\r
+\r
+**/\r
+\r
+#include "RedfishMisc.h"\r
+\r
+/**\r
+ This function uses REST EX protocol provided in RedfishConfigServiceInfo.\r
+ The service enumerator will also handle the authentication flow automatically\r
+ if HTTP basic auth or Redfish session login is configured to use.\r
+\r
+ Callers are responsible for freeing the returned service by RedfishCleanupService().\r
+\r
+ @param[in] RedfishConfigServiceInfo Redfish service information the EFI Redfish\r
+ feature driver communicates with.\r
+\r
+ @return New created Redfish Service, or NULL if error happens.\r
+\r
+**/\r
+REDFISH_SERVICE\r
+EFIAPI\r
+RedfishCreateService (\r
+ IN REDFISH_CONFIG_SERVICE_INFORMATION *RedfishConfigServiceInfo\r
+ )\r
+{\r
+ REDFISH_SERVICE RedfishService;\r
+ EDKII_REDFISH_AUTH_METHOD AuthMethod;\r
+ CHAR8 *UserId;\r
+ CHAR8 *Password;\r
+ EFI_STATUS Status;\r
+\r
+ RedfishService = NULL;\r
+ UserId = NULL;\r
+ Password = NULL;\r
+\r
+ //\r
+ // Check Input Parameters.\r
+ //\r
+ if (RedfishConfigServiceInfo == NULL) {\r
+ return NULL;\r
+ }\r
+\r
+ //\r
+ // Get Authentication Configuration.\r
+ //\r
+ Status = RedfishGetAuthInfo (&AuthMethod, &UserId, &Password);\r
+ if (EFI_ERROR (Status)) {\r
+ goto ON_EXIT;\r
+ }\r
+\r
+ //\r
+ // Create a redfish service node based on Redfish network host interface.\r
+ //\r
+ RedfishService = RedfishCreateLibredfishService (\r
+ RedfishConfigServiceInfo,\r
+ AuthMethod,\r
+ UserId,\r
+ Password\r
+ );\r
+\r
+ON_EXIT:\r
+ if (UserId != NULL) {\r
+ FreePool (UserId);\r
+ }\r
+ if (Password!= NULL) {\r
+ FreePool (Password);\r
+ }\r
+\r
+ return RedfishService;\r
+}\r
+\r
+/**\r
+ Free the Service and all its related resources.\r
+\r
+ @param[in] RedfishService The Service to access the Redfish resources.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+RedfishCleanupService (\r
+ IN REDFISH_SERVICE RedfishService\r
+ )\r
+{\r
+ if (RedfishService == NULL) {\r
+ return;\r
+ }\r
+\r
+ cleanupServiceEnumerator (RedfishService);\r
+}\r
+/**\r
+ Create REDFISH_PAYLOAD instance in local with JSON represented resource value and\r
+ the Redfish Service.\r
+\r
+ The returned REDFISH_PAYLOAD can be used to create or update Redfish resource in\r
+ server side.\r
+\r
+ Callers are responsible for freeing the returned payload by RedfishCleanupPayload().\r
+\r
+ @param[in] Value JSON Value of the redfish resource.\r
+ @param[in] RedfishService The Service to access the Redfish resources.\r
+\r
+ @return REDFISH_PAYLOAD instance of the resource, or NULL if error happens.\r
+\r
+**/\r
+REDFISH_PAYLOAD\r
+EFIAPI\r
+RedfishCreatePayload (\r
+ IN EDKII_JSON_VALUE Value,\r
+ IN REDFISH_SERVICE RedfishService\r
+ )\r
+{\r
+ EDKII_JSON_VALUE CopyValue;\r
+\r
+ CopyValue = JsonValueClone (Value);\r
+ return createRedfishPayload (CopyValue, RedfishService);\r
+}\r
+\r
+/**\r
+ Free the RedfishPayload and all its related resources.\r
+\r
+ @param[in] Payload Payload to be freed.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+RedfishCleanupPayload (\r
+ IN REDFISH_PAYLOAD Payload\r
+ )\r
+{\r
+ if (Payload == NULL) {\r
+ return;\r
+ }\r
+\r
+ cleanupPayload ((redfishPayload *) Payload);\r
+}\r
+\r
+/**\r
+ This function returns the decoded JSON value of a REDFISH_PAYLOAD.\r
+\r
+ Caller doesn't need to free the returned JSON value because it will be released\r
+ in corresponding RedfishCleanupPayload() function.\r
+\r
+ @param[in] Payload A REDFISH_PAYLOAD instance.\r
+\r
+ @return Decoded JSON value of the payload.\r
+\r
+**/\r
+EDKII_JSON_VALUE\r
+EFIAPI\r
+RedfishJsonInPayload (\r
+ IN REDFISH_PAYLOAD Payload\r
+ )\r
+{\r
+ if (Payload == NULL) {\r
+ return NULL;\r
+ }\r
+\r
+ return ((redfishPayload*)Payload)->json;\r
+}\r
+\r
+/**\r
+ Fill the input RedPath string with system UUID from SMBIOS table or use the customized\r
+ ID if FromSmbios == FALSE.\r
+\r
+ This is a helper function to build a RedPath string which can be used to address\r
+ a Redfish resource for this computer system. The input PathString must have a Systems\r
+ note in format of "Systems[UUID=%g]" or "Systems[UUID~%g]" to fill the UUID value.\r
+\r
+ Example:\r
+ Use "/v1/Systems[UUID=%g]/Bios" to build a RedPath to address the "Bios" resource\r
+ for this computer system.\r
+\r
+ @param[in] RedPath RedPath format to be build.\r
+ @param[in] FromSmbios Get system UUID from SMBIOS as computer system instance ID.\r
+ @param[in] IdString The computer system instance ID.\r
+\r
+ @return Full RedPath with system UUID inside, or NULL if error happens.\r
+\r
+**/\r
+CHAR8 *\r
+EFIAPI\r
+RedfishBuildPathWithSystemUuid (\r
+ IN CONST CHAR8 *RedPath,\r
+ IN BOOLEAN FromSmbios,\r
+ IN CHAR8 *IdString OPTIONAL\r
+ )\r
+{\r
+ UINTN BufSize;\r
+ CHAR8* RetRedPath;\r
+ EFI_GUID SystemUuid;\r
+ EFI_STATUS Status;\r
+\r
+ if (RedPath == NULL) {\r
+ return NULL;\r
+ }\r
+\r
+ //\r
+ // Find system UUID from SMBIOS table.\r
+ //\r
+ if (FromSmbios) {\r
+ Status = NetLibGetSystemGuid(&SystemUuid);\r
+ if (EFI_ERROR (Status)) {\r
+ return NULL;\r
+ }\r
+ // AsciiStrLen ("xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx") = 36\r
+ BufSize = AsciiStrSize (RedPath) + AsciiStrLen ("XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX");\r
+ } else {\r
+ BufSize = AsciiStrSize (RedPath) + AsciiStrLen (IdString);\r
+ }\r
+\r
+ RetRedPath = AllocateZeroPool (BufSize);\r
+ if (RetRedPath == NULL) {\r
+ return NULL;\r
+ }\r
+ if (FromSmbios) {\r
+ AsciiSPrint (RetRedPath, BufSize, RedPath, &SystemUuid);\r
+ } else {\r
+ AsciiSPrint (RetRedPath, BufSize, RedPath, IdString);\r
+ }\r
+ return RetRedPath;\r
+}\r
+/**\r
+ Get a redfish response addressed by a RedPath string, including HTTP StatusCode, Headers\r
+ and Payload which record any HTTP response messages.\r
+\r
+ Callers are responsible for freeing the HTTP StatusCode, Headers and Payload returned in\r
+ redfish response data.\r
+\r
+ @param[in] RedfishService The Service to access the Redfish resources.\r
+ @param[in] RedPath RedPath string to address a resource, must start\r
+ from the root node.\r
+ @param[out] RedResponse Pointer to the Redfish response data.\r
+\r
+ @retval EFI_SUCCESS The opeartion is successful, indicates the HTTP StatusCode is not\r
+ NULL and the value is 2XX. The corresponding redfish resource has\r
+ been returned in Payload within RedResponse.\r
+ @retval EFI_INVALID_PARAMETER RedfishService, RedPath, or RedResponse is NULL.\r
+ @retval EFI_DEVICE_ERROR An unexpected system or network error occurred. Callers can get\r
+ more error info from returned HTTP StatusCode, Headers and Payload\r
+ within RedResponse:\r
+ 1. If the returned Payload is NULL, indicates any error happen.\r
+ 2. If the returned StatusCode is NULL, indicates any error happen.\r
+ 3. If the returned StatusCode is not 2XX, indicates any error happen.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+RedfishGetByService (\r
+ IN REDFISH_SERVICE RedfishService,\r
+ IN CONST CHAR8 *RedPath,\r
+ OUT REDFISH_RESPONSE *RedResponse\r
+ )\r
+{\r
+ if (RedfishService == NULL || RedPath == NULL || RedResponse == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ ZeroMem (RedResponse, sizeof (REDFISH_RESPONSE));\r
+\r
+ RedResponse->Payload = (REDFISH_PAYLOAD) getPayloadByPath (RedfishService, RedPath, &(RedResponse->StatusCode));\r
+\r
+ //\r
+ // 1. If the returned Payload is NULL, indicates any error happen.\r
+ // 2. If the returned StatusCode is NULL, indicates any error happen.\r
+ //\r
+ if (RedResponse->Payload == NULL || RedResponse->StatusCode == NULL) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ //\r
+ // 3. If the returned StatusCode is not 2XX, indicates any error happen.\r
+ // NOTE: If there is any error message returned from server, it will be returned in\r
+ // Payload within RedResponse.\r
+ //\r
+ if (*(RedResponse->StatusCode) < HTTP_STATUS_200_OK || \\r
+ *(RedResponse->StatusCode) > HTTP_STATUS_206_PARTIAL_CONTENT) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+/**\r
+ Get a redfish response addressed by URI, including HTTP StatusCode, Headers\r
+ and Payload which record any HTTP response messages.\r
+\r
+ Callers are responsible for freeing the HTTP StatusCode, Headers and Payload returned in\r
+ redfish response data.\r
+\r
+ @param[in] RedfishService The Service to access the URI resources.\r
+ @param[in] Uri String to address a resource.\r
+ @param[out] RedResponse Pointer to the Redfish response data.\r
+\r
+ @retval EFI_SUCCESS The opeartion is successful, indicates the HTTP StatusCode is not\r
+ NULL and the value is 2XX. The corresponding redfish resource has\r
+ been returned in Payload within RedResponse.\r
+ @retval EFI_INVALID_PARAMETER RedfishService, RedPath, or RedResponse is NULL.\r
+ @retval EFI_DEVICE_ERROR An unexpected system or network error occurred. Callers can get\r
+ more error info from returned HTTP StatusCode, Headers and Payload\r
+ within RedResponse:\r
+ 1. If the returned Payload is NULL, indicates any error happen.\r
+ 2. If the returned StatusCode is NULL, indicates any error happen.\r
+ 3. If the returned StatusCode is not 2XX, indicates any error happen.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+RedfishGetByUri (\r
+ IN REDFISH_SERVICE RedfishService,\r
+ IN CONST CHAR8 *Uri,\r
+ OUT REDFISH_RESPONSE *RedResponse\r
+ )\r
+{\r
+ EDKII_JSON_VALUE JsonValue;\r
+\r
+ if (RedfishService == NULL || Uri == NULL || RedResponse == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ ZeroMem (RedResponse, sizeof (REDFISH_RESPONSE));\r
+\r
+ JsonValue = getUriFromService (RedfishService, Uri, &RedResponse->StatusCode);\r
+ RedResponse->Payload = createRedfishPayload(JsonValue, RedfishService);\r
+\r
+ //\r
+ // 1. If the returned Payload is NULL, indicates any error happen.\r
+ // 2. If the returned StatusCode is NULL, indicates any error happen.\r
+ //\r
+ if (RedResponse->Payload == NULL || RedResponse->StatusCode == NULL) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ //\r
+ // 3. If the returned StatusCode is not 2XX, indicates any error happen.\r
+ // NOTE: If there is any error message returned from server, it will be returned in\r
+ // Payload within RedResponse.\r
+ //\r
+ if (*(RedResponse->StatusCode) < HTTP_STATUS_200_OK || \\r
+ *(RedResponse->StatusCode) > HTTP_STATUS_206_PARTIAL_CONTENT) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+ return EFI_SUCCESS;\r
+}\r
+/**\r
+ Get a redfish response addressed by the input Payload and relative RedPath string,\r
+ including HTTP StatusCode, Headers and Payload which record any HTTP response messages.\r
+\r
+ Callers are responsible for freeing the HTTP StatusCode, Headers and Payload returned in\r
+ redfish response data.\r
+\r
+ @param[in] Payload A existing REDFISH_PAYLOAD instance.\r
+ @param[in] RedPath Relative RedPath string to address a resource inside Payload.\r
+ @param[out] RedResponse Pointer to the Redfish response data.\r
+\r
+ @retval EFI_SUCCESS The opeartion is successful:\r
+ 1. The HTTP StatusCode is NULL and the returned Payload in\r
+ RedResponse is not NULL, indicates the Redfish resource has\r
+ been parsed from the input payload directly.\r
+ 2. The HTTP StatusCode is not NULL and the value is 2XX,\r
+ indicates the corresponding redfish resource has been returned\r
+ in Payload within RedResponse.\r
+ @retval EFI_INVALID_PARAMETER Payload, RedPath, or RedResponse is NULL.\r
+ @retval EFI_DEVICE_ERROR An unexpected system or network error occurred. Callers can get\r
+ more error info from returned HTTP StatusCode, Headers and Payload\r
+ within RedResponse:\r
+ 1. If the returned Payload is NULL, indicates any error happen.\r
+ 2. If StatusCode is not NULL and the returned value of StatusCode\r
+ is not 2XX, indicates any error happen.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+RedfishGetByPayload (\r
+ IN REDFISH_PAYLOAD Payload,\r
+ IN CONST CHAR8 *RedPath,\r
+ OUT REDFISH_RESPONSE *RedResponse\r
+ )\r
+{\r
+ if (Payload == NULL || RedPath == NULL || RedResponse == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ ZeroMem (RedResponse, sizeof (REDFISH_RESPONSE));\r
+\r
+ RedResponse->Payload = (REDFISH_PAYLOAD) getPayloadForPathString (Payload, RedPath, &(RedResponse->StatusCode));\r
+\r
+ //\r
+ // 1. If the returned Payload is NULL, indicates any error happen.\r
+ //\r
+ if (RedResponse->Payload == NULL) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ //\r
+ // 2. If StatusCode is not NULL and the returned value of StatusCode is not 2XX, indicates any\r
+ // error happen.\r
+ // NOTE: If there is any error message returned from server, it will be returned in\r
+ // Payload within RedResponse.\r
+ //\r
+ if (RedResponse->StatusCode != NULL && \\r
+ (*(RedResponse->StatusCode) < HTTP_STATUS_200_OK || \\r
+ *(RedResponse->StatusCode) > HTTP_STATUS_206_PARTIAL_CONTENT\r
+ )) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+/**\r
+ Use HTTP PATCH to perform updates on pre-existing Redfish resource.\r
+\r
+ This function uses the RedfishService to patch a Redfish resource addressed by\r
+ Uri (only the relative path is required). Changes to one or more properties within\r
+ the target resource are represented in the input Content, properties not specified\r
+ in Content won't be changed by this request. The corresponding redfish response will\r
+ returned, including HTTP StatusCode, Headers and Payload which record any HTTP response\r
+ messages.\r
+\r
+ Callers are responsible for freeing the HTTP StatusCode, Headers and Payload returned in\r
+ redfish response data.\r
+\r
+ @param[in] RedfishService The Service to access the Redfish resources.\r
+ @param[in] Uri Relative path to address the resource.\r
+ @param[in] Content JSON represented properties to be update.\r
+ @param[out] RedResponse Pointer to the Redfish response data.\r
+\r
+ @retval EFI_SUCCESS The opeartion is successful, indicates the HTTP StatusCode is not\r
+ NULL and the value is 2XX. The Redfish resource will be returned\r
+ in Payload within RedResponse if server send it back in the HTTP\r
+ response message body.\r
+ @retval EFI_INVALID_PARAMETER RedfishService, Uri, Content, or RedResponse is NULL.\r
+ @retval EFI_DEVICE_ERROR An unexpected system or network error occurred. Callers can get\r
+ more error info from returned HTTP StatusCode, Headers and Payload\r
+ within RedResponse:\r
+ 1. If the returned StatusCode is NULL, indicates any error happen.\r
+ 2. If the returned StatusCode is not NULL and the value is not 2XX,\r
+ indicates any error happen.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+RedfishPatchToUri (\r
+ IN REDFISH_SERVICE RedfishService,\r
+ IN CONST CHAR8 *Uri,\r
+ IN CONST CHAR8 *Content,\r
+ OUT REDFISH_RESPONSE *RedResponse\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EDKII_JSON_VALUE JsonValue;\r
+\r
+ Status = EFI_SUCCESS;\r
+ JsonValue = NULL;\r
+\r
+ if (RedfishService == NULL || Uri == NULL || Content == NULL || RedResponse == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ ZeroMem (RedResponse, sizeof (REDFISH_RESPONSE));\r
+\r
+ JsonValue = (EDKII_JSON_VALUE) patchUriFromService (\r
+ RedfishService,\r
+ Uri,\r
+ Content,\r
+ &(RedResponse->StatusCode)\r
+ );\r
+\r
+ //\r
+ // 1. If the returned StatusCode is NULL, indicates any error happen.\r
+ //\r
+ if (RedResponse->StatusCode == NULL) {\r
+ Status = EFI_DEVICE_ERROR;\r
+ goto ON_EXIT;\r
+ }\r
+\r
+ //\r
+ // 2. If the returned StatusCode is not NULL and the value is not 2XX, indicates any error happen.\r
+ // NOTE: If there is any error message returned from server, it will be returned in\r
+ // Payload within RedResponse.\r
+ //\r
+ if (*(RedResponse->StatusCode) < HTTP_STATUS_200_OK || \\r
+ *(RedResponse->StatusCode) > HTTP_STATUS_206_PARTIAL_CONTENT) {\r
+ Status = EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ON_EXIT:\r
+ if (JsonValue != NULL) {\r
+ RedResponse->Payload = createRedfishPayload (JsonValue, RedfishService);\r
+ if (RedResponse->Payload == NULL) {\r
+ //\r
+ // Ignore the error when create RedfishPayload, just free the JsonValue since it's not what\r
+ // we care about if the returned StatusCode is 2XX.\r
+ //\r
+ JsonValueFree (JsonValue);\r
+ }\r
+ }\r
+\r
+ return Status;\r
+}\r
+/**\r
+ Use HTTP PATCH to perform updates on target payload. Patch to odata.id in Payload directly.\r
+\r
+ This function uses the Payload to patch the Target. Changes to one or more properties\r
+ within the target resource are represented in the input Payload, properties not specified\r
+ in Payload won't be changed by this request. The corresponding redfish response will\r
+ returned, including HTTP StatusCode, Headers and Payload which record any HTTP response\r
+ messages.\r
+\r
+ Callers are responsible for freeing the HTTP StatusCode, Headers and Payload returned in\r
+ redfish response data.\r
+\r
+ @param[in] Target The target payload to be updated.\r
+ @param[in] Payload Palyoad with properties to be changed.\r
+ @param[out] RedResponse Pointer to the Redfish response data.\r
+\r
+ @retval EFI_SUCCESS The opeartion is successful, indicates the HTTP StatusCode is not\r
+ NULL and the value is 2XX. The Redfish resource will be returned\r
+ in Payload within RedResponse if server send it back in the HTTP\r
+ response message body.\r
+ @retval EFI_INVALID_PARAMETER Target, Payload, or RedResponse is NULL.\r
+ @retval EFI_DEVICE_ERROR An unexpected system or network error occurred. Callers can get\r
+ more error info from returned HTTP StatusCode, Headers and Payload\r
+ within RedResponse:\r
+ 1. If the returned StatusCode is NULL, indicates any error happen.\r
+ 2. If the returned StatusCode is not NULL and the value is not 2XX,\r
+ indicates any error happen.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+RedfishPatchToPayload (\r
+ IN REDFISH_PAYLOAD Target,\r
+ IN REDFISH_PAYLOAD Payload,\r
+ OUT REDFISH_RESPONSE *RedResponse\r
+ )\r
+{\r
+ if (Target == NULL || Payload == NULL || RedResponse == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ ZeroMem (RedResponse, sizeof (REDFISH_RESPONSE));\r
+\r
+ RedResponse->Payload = (REDFISH_PAYLOAD) patchPayload (\r
+ Target,\r
+ Payload,\r
+ &(RedResponse->StatusCode)\r
+ );\r
+\r
+ //\r
+ // 1. If the returned StatusCode is NULL, indicates any error happen.\r
+ //\r
+ if (RedResponse->StatusCode == NULL) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ //\r
+ // 2. If the returned StatusCode is not NULL and the value is not 2XX, indicates any error happen.\r
+ // NOTE: If there is any error message returned from server, it will be returned in\r
+ // Payload within RedResponse.\r
+ //\r
+ if (*(RedResponse->StatusCode) < HTTP_STATUS_200_OK || \\r
+ *(RedResponse->StatusCode) > HTTP_STATUS_206_PARTIAL_CONTENT) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+/**\r
+ Use HTTP POST to create a new resource in target payload.\r
+\r
+ The POST request should be submitted to the Resource Collection in which the new resource\r
+ is to belong. The Resource Collection is addressed by Target payload. The Redfish may\r
+ ignore any service controlled properties. The corresponding redfish response will returned,\r
+ including HTTP StatusCode, Headers and Payload which record any HTTP response messages.\r
+\r
+ Callers are responsible for freeing the HTTP StatusCode, Headers and Payload returned in\r
+ redfish response data.\r
+\r
+ @param[in] Target Target payload of the Resource Collection.\r
+ @param[in] Payload The new resource to be created.\r
+ @param[out] RedResponse Pointer to the Redfish response data.\r
+\r
+ @retval EFI_SUCCESS The opeartion is successful, indicates the HTTP StatusCode is not\r
+ NULL and the value is 2XX. The Redfish resource will be returned\r
+ in Payload within RedResponse if server send it back in the HTTP\r
+ response message body.\r
+ @retval EFI_INVALID_PARAMETER Target, Payload, or RedResponse is NULL.\r
+ @retval EFI_DEVICE_ERROR An unexpected system or network error occurred. Callers can get\r
+ more error info from returned HTTP StatusCode, Headers and Payload\r
+ within RedResponse:\r
+ 1. If the returned StatusCode is NULL, indicates any error happen.\r
+ 2. If the returned StatusCode is not NULL and the value is not 2XX,\r
+ indicates any error happen.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+RedfishPostToPayload (\r
+ IN REDFISH_PAYLOAD Target,\r
+ IN REDFISH_PAYLOAD Payload,\r
+ OUT REDFISH_RESPONSE *RedResponse\r
+ )\r
+{\r
+ if (Target == NULL || Payload == NULL || RedResponse == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ ZeroMem (RedResponse, sizeof (REDFISH_RESPONSE));\r
+\r
+ RedResponse->Payload = (REDFISH_PAYLOAD) postPayload (\r
+ Target,\r
+ Payload,\r
+ &(RedResponse->StatusCode)\r
+ );\r
+\r
+ //\r
+ // 1. If the returned StatusCode is NULL, indicates any error happen.\r
+ //\r
+ if (RedResponse->StatusCode == NULL) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ //\r
+ // 2. If the returned StatusCode is not NULL and the value is not 2XX, indicates any error happen.\r
+ // NOTE: If there is any error message returned from server, it will be returned in\r
+ // Payload within RedResponse.\r
+ //\r
+ if (*(RedResponse->StatusCode) < HTTP_STATUS_200_OK || \\r
+ *(RedResponse->StatusCode) > HTTP_STATUS_206_PARTIAL_CONTENT) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+/**\r
+ Use HTTP DELETE to remove a resource.\r
+\r
+ This function uses the RedfishService to remove a Redfish resource which is addressed\r
+ by input Uri (only the relative path is required). The corresponding redfish response will\r
+ returned, including HTTP StatusCode, Headers and Payload which record any HTTP response\r
+ messages.\r
+\r
+ Callers are responsible for freeing the HTTP StatusCode, Headers and Payload returned in\r
+ redfish response data.\r
+\r
+ @param[in] RedfishService The Service to access the Redfish resources.\r
+ @param[in] Uri Relative path to address the resource.\r
+ @param[out] RedResponse Pointer to the Redfish response data.\r
+\r
+ @retval EFI_SUCCESS The opeartion is successful, indicates the HTTP StatusCode is not\r
+ NULL and the value is 2XX, the Redfish resource has been removed.\r
+ If there is any message returned from server, it will be returned\r
+ in Payload within RedResponse.\r
+ @retval EFI_INVALID_PARAMETER RedfishService, Uri, or RedResponse is NULL.\r
+ @retval EFI_DEVICE_ERROR An unexpected system or network error occurred. Callers can get\r
+ more error info from returned HTTP StatusCode, Headers and Payload\r
+ within RedResponse:\r
+ 1. If the returned StatusCode is NULL, indicates any error happen.\r
+ 2. If the returned StatusCode is not NULL and the value is not 2XX,\r
+ indicates any error happen.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+RedfishDeleteByUri (\r
+ IN REDFISH_SERVICE RedfishService,\r
+ IN CONST CHAR8 *Uri,\r
+ OUT REDFISH_RESPONSE *RedResponse\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EDKII_JSON_VALUE JsonValue;\r
+\r
+ Status = EFI_SUCCESS;\r
+ JsonValue = NULL;\r
+\r
+ if (RedfishService == NULL || Uri == NULL || RedResponse == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ ZeroMem (RedResponse, sizeof (REDFISH_RESPONSE));\r
+\r
+ JsonValue = (EDKII_JSON_VALUE) deleteUriFromService (\r
+ RedfishService,\r
+ Uri,\r
+ &(RedResponse->StatusCode)\r
+ );\r
+\r
+ //\r
+ // 1. If the returned StatusCode is NULL, indicates any error happen.\r
+ //\r
+ if (RedResponse->StatusCode == NULL) {\r
+ Status = EFI_DEVICE_ERROR;\r
+ goto ON_EXIT;\r
+ }\r
+\r
+ //\r
+ // 2. If the returned StatusCode is not NULL and the value is not 2XX, indicates any error happen.\r
+ // NOTE: If there is any error message returned from server, it will be returned in\r
+ // Payload within RedResponse.\r
+ //\r
+ if (*(RedResponse->StatusCode) < HTTP_STATUS_200_OK || \\r
+ *(RedResponse->StatusCode) > HTTP_STATUS_206_PARTIAL_CONTENT) {\r
+ Status = EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ON_EXIT:\r
+ if (JsonValue != NULL) {\r
+ RedResponse->Payload = createRedfishPayload (JsonValue, RedfishService);\r
+ if (RedResponse->Payload == NULL) {\r
+ //\r
+ // Ignore the error when create RedfishPayload, just free the JsonValue since it's not what\r
+ // we care about if the returned StatusCode is 2XX.\r
+ //\r
+ JsonValueFree (JsonValue);\r
+ }\r
+ }\r
+\r
+ return Status;\r
+}\r
+/**\r
+ Dump text in fractions.\r
+\r
+ @param[in] String ASCII string to dump.\r
+\r
+**/\r
+VOID\r
+RedfishDumpJsonStringFractions (\r
+ IN CHAR8 *String\r
+ )\r
+{\r
+ CHAR8 *NextFraction;\r
+ UINTN StringFractionSize;\r
+ UINTN StrLen;\r
+ UINTN Count;\r
+ CHAR8 BackupChar;\r
+\r
+ StringFractionSize = 200;\r
+ if (String == NULL) {\r
+ return ;\r
+ }\r
+\r
+ DEBUG((DEBUG_INFO, "JSON text:\n"));\r
+ NextFraction = String;\r
+ StrLen = AsciiStrLen (String);\r
+ if (StrLen == 0) {\r
+ return;\r
+ }\r
+ for (Count = 0; Count < (StrLen / StringFractionSize); Count++) {\r
+ BackupChar = *(NextFraction + StringFractionSize);\r
+ *(NextFraction + StringFractionSize) = 0;\r
+ DEBUG((DEBUG_INFO, "%a", NextFraction));\r
+ *(NextFraction + StringFractionSize) = BackupChar;\r
+ NextFraction += StringFractionSize;\r
+ }\r
+ if ((StrLen % StringFractionSize) != 0) {\r
+ DEBUG((DEBUG_INFO, "%a\n\n", NextFraction));\r
+ }\r
+}\r
+/**\r
+ Dump text in JSON value.\r
+\r
+ @param[in] JsonValue The Redfish JSON value to dump.\r
+\r
+**/\r
+VOID\r
+RedfishDumpJson (\r
+ IN EDKII_JSON_VALUE JsonValue\r
+ )\r
+{\r
+ CHAR8 *String;\r
+\r
+ String = JsonDumpString (JsonValue, 0);\r
+ if (String == NULL) {\r
+ return;\r
+ }\r
+ RedfishDumpJsonStringFractions (String);\r
+ FreePool(String);\r
+}\r
+/**\r
+ Extract the JSON text content from REDFISH_PAYLOAD and dump to debug console.\r
+\r
+ @param[in] Payload The Redfish payload to dump.\r
+\r
+**/\r
+VOID\r
+RedfishDumpPayload (\r
+ IN REDFISH_PAYLOAD Payload\r
+ )\r
+{\r
+ EDKII_JSON_VALUE JsonValue;\r
+ CHAR8 *String;\r
+\r
+ JsonValue = NULL;\r
+ String = NULL;\r
+\r
+ if (Payload == NULL) {\r
+ return;\r
+ }\r
+\r
+ JsonValue = RedfishJsonInPayload (Payload);\r
+ if (JsonValue == NULL) {\r
+ return;\r
+ }\r
+\r
+ String = JsonDumpString (JsonValue, 0);\r
+ if (String == NULL) {\r
+ return;\r
+ }\r
+\r
+ RedfishDumpJsonStringFractions (String);\r
+ FreePool(String);\r
+}\r
+/**\r
+ This function will cleanup the HTTP header and Redfish payload resources.\r
+\r
+ @param[in] StatusCode The status code in HTTP response message.\r
+ @param[in] HeaderCount Number of HTTP header structures in Headers list.\r
+ @param[in] Headers Array containing list of HTTP headers.\r
+ @param[in] Payload The Redfish payload to dump.\r
+\r
+**/\r
+VOID\r
+RedfishFreeResponse (\r
+ IN EFI_HTTP_STATUS_CODE *StatusCode,\r
+ IN UINTN HeaderCount,\r
+ IN EFI_HTTP_HEADER *Headers,\r
+ IN REDFISH_PAYLOAD Payload\r
+ )\r
+{\r
+ if (StatusCode != NULL) {\r
+ FreePool (StatusCode);\r
+ StatusCode = NULL;\r
+ }\r
+\r
+ if (HeaderCount != 0 && Headers != NULL) {\r
+ HttpFreeHeaderFields(Headers, HeaderCount);\r
+ Headers = NULL;\r
+ }\r
+\r
+ if (Payload != NULL) {\r
+ RedfishCleanupPayload (Payload);\r
+ Payload = NULL;\r
+ }\r
+}\r
+/**\r
+ Check if the "@odata.type" in Payload is valid or not.\r
+\r
+ @param[in] Payload The Redfish payload to be checked.\r
+ @param[in] OdataTypeName OdataType will be retrived from mapping list.\r
+ @param[in] OdataTypeMappingList The list of OdataType.\r
+ @param[in] OdataTypeMappingListSize The number of mapping list\r
+\r
+ @return TRUE if the "@odata.type" in Payload is valid, otherwise FALSE.\r
+\r
+**/\r
+BOOLEAN\r
+RedfishIsValidOdataType (\r
+ IN REDFISH_PAYLOAD Payload,\r
+ IN CONST CHAR8 *OdataTypeName,\r
+ IN REDFISH_ODATA_TYPE_MAPPING *OdataTypeMappingList,\r
+ IN UINTN OdataTypeMappingListSize\r
+ )\r
+{\r
+ UINTN Index;\r
+ EDKII_JSON_VALUE OdataType;\r
+ EDKII_JSON_VALUE JsonValue;\r
+\r
+ if (Payload == NULL || OdataTypeName == NULL) {\r
+ return FALSE;\r
+ }\r
+\r
+ JsonValue = RedfishJsonInPayload (Payload);\r
+ if (!JsonValueIsObject (JsonValue)) {\r
+ return FALSE;\r
+ }\r
+\r
+ OdataType = JsonObjectGetValue (JsonValueGetObject (JsonValue), "@odata.type");\r
+ if (!JsonValueIsString (OdataType) || JsonValueGetAsciiString (OdataType) == NULL) {\r
+ return FALSE;\r
+ }\r
+\r
+ for (Index = 0; Index < OdataTypeMappingListSize; Index ++) {\r
+ if (AsciiStrCmp (OdataTypeMappingList[Index].OdataTypeName, OdataTypeName) == 0 &&\r
+ AsciiStrCmp (OdataTypeMappingList[Index].OdataType, JsonValueGetAsciiString (OdataType)) == 0) {\r
+ return TRUE;\r
+ }\r
+ }\r
+ DEBUG ((DEBUG_INFO, "%a: This Odata type is not in the list.\n", __FUNCTION__));\r
+ return FALSE;\r
+}\r
+/**\r
+ Check if the payload is collection\r
+\r
+ @param[in] Payload The Redfish payload to be checked.\r
+\r
+ @return TRUE if the payload is collection.\r
+\r
+**/\r
+BOOLEAN\r
+RedfishIsPayloadCollection (\r
+ IN REDFISH_PAYLOAD Payload\r
+)\r
+{\r
+ return isPayloadCollection (Payload);\r
+}\r
+/**\r
+ Get collection size.\r
+\r
+ @param[in] Payload The Redfish collection payload\r
+ @param[in] CollectionSize Size of this collection\r
+\r
+ @return EFI_SUCCESS Coolection size is returned in CollectionSize\r
+ @return EFI_INVALID_PARAMETER The payload is not a collection.\r
+**/\r
+EFI_STATUS\r
+RedfishGetCollectionSize(\r
+ IN REDFISH_PAYLOAD Payload,\r
+ IN UINTN *CollectionSize\r
+ )\r
+{\r
+ if (Payload == NULL || CollectionSize == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+ if (!RedfishIsPayloadCollection(Payload)) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ *CollectionSize = (UINTN)getCollectionSize(Payload);\r
+ return EFI_SUCCESS;\r
+}\r
+/**\r
+ Get Redfish payload of collection member\r
+\r
+ @param[in] Payload The Redfish collection payload\r
+ @param[in] Index Index of collection member\r
+\r
+ @return NULL Fail to get collection member.\r
+ @return Non NULL Payload is returned.\r
+**/\r
+REDFISH_PAYLOAD\r
+RedfishGetPayloadByIndex (\r
+ IN REDFISH_PAYLOAD Payload,\r
+ IN UINTN Index\r
+)\r
+{\r
+ REDFISH_RESPONSE RedfishResponse;\r
+ REDFISH_PAYLOAD PayloadReturn;\r
+\r
+ PayloadReturn = (VOID *)getPayloadByIndex (Payload, Index, &RedfishResponse.StatusCode);\r
+ if(PayloadReturn == NULL ||\r
+ (*(RedfishResponse.StatusCode) < HTTP_STATUS_200_OK && *(RedfishResponse.StatusCode) > HTTP_STATUS_206_PARTIAL_CONTENT)){\r
+ return NULL;\r
+ }\r
+ return PayloadReturn;\r
+}\r
+/**\r
+ Check and return Redfish resource of the given Redpath.\r
+\r
+ @param[in] RedfishService Pointer to REDFISH_SERVICE\r
+ @param[in] Redpath Redpath of the resource.\r
+ @param[in] Response Optional return the resource.\r
+\r
+ @return EFI_STATUS\r
+**/\r
+EFI_STATUS\r
+RedfishCheckIfRedpathExist (\r
+ IN REDFISH_SERVICE RedfishService,\r
+ IN CHAR8 *Redpath,\r
+ IN REDFISH_RESPONSE *Response OPTIONAL\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ REDFISH_RESPONSE TempResponse;\r
+\r
+ if (Redpath == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+ Status = RedfishGetByService (RedfishService, Redpath, &TempResponse);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ if (Response == NULL) {\r
+ RedfishFreeResponse(\r
+ TempResponse.StatusCode,\r
+ TempResponse.HeaderCount,\r
+ TempResponse.Headers,\r
+ TempResponse.Payload\r
+ );\r
+ } else {\r
+ CopyMem ((VOID *)Response, (VOID *)&TempResponse, sizeof (REDFISH_RESPONSE));\r
+ }\r
+ return EFI_SUCCESS;\r
+}\r
--- /dev/null
+## @file\r
+# RedfishLib Library implementation.\r
+#\r
+# Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>\r
+# (C) Copyright 2021 Hewlett Packard Enterprise Development LP<BR>\r
+#\r
+# SPDX-License-Identifier: BSD-2-Clause-Patent\r
+#\r
+##\r
+\r
+[Defines]\r
+ INF_VERSION = 0x0001001b\r
+ BASE_NAME = DxeRedfishLib\r
+ FILE_GUID = 9C2CA9CF-4F79-11E8-A7D1-8CDCD426C973\r
+ MODULE_TYPE = DXE_DRIVER\r
+ VERSION_STRING = 1.0\r
+ LIBRARY_CLASS = RedfishLib| DXE_DRIVER UEFI_APPLICATION UEFI_DRIVER\r
+\r
+#\r
+# VALID_ARCHITECTURES = IA32 X64 ARM AARCH64 RISCV64\r
+#\r
+\r
+[Sources]\r
+ edk2libredfish/src/redpath.c\r
+ edk2libredfish/src/service.c\r
+ edk2libredfish/src/payload.c\r
+ edk2libredfish/include/redfish.h\r
+ edk2libredfish/include/redfishPayload.h\r
+ edk2libredfish/include/redfishService.h\r
+ edk2libredfish/include/redpath.h\r
+ RedfishLib.c\r
+ RedfishMisc.h\r
+ RedfishMisc.c\r
+\r
+[Packages]\r
+ MdePkg/MdePkg.dec\r
+ MdeModulePkg/MdeModulePkg.dec\r
+ NetworkPkg/NetworkPkg.dec\r
+ RedfishPkg/RedfishPkg.dec\r
+\r
+[LibraryClasses]\r
+ BaseLib\r
+ BaseMemoryLib\r
+ DebugLib\r
+ HttpLib\r
+ MemoryAllocationLib\r
+ NetLib\r
+ RedfishContentCodingLib\r
+ RedfishCrtLib\r
+ UefiBootServicesTableLib\r
+ UefiLib\r
+\r
+[Protocols]\r
+ gEfiRestExServiceBindingProtocolGuid ## Consumed\r
+ gEfiRestExProtocolGuid ## Consumed\r
+ gEdkIIRedfishCredentialProtocolGuid ## Consumed\r
+\r
+[BuildOptions]\r
+ MSFT:*_*_*_CC_FLAGS = /U_WIN32 /UWIN64 /U_MSC_VER\r
+ GCC:*_*_*_CC_FLAGS = -Wno-unused-function -Wno-unused-but-set-variable\r
--- /dev/null
+/** @file\r
+ Internal Functions for RedfishLib.\r
+\r
+ Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>\r
+ (C) Copyright 2021 Hewlett Packard Enterprise Development LP<BR>\r
+\r
+ SPDX-License-Identifier: BSD-2-Clause-Patent\r
+\r
+**/\r
+\r
+#include "RedfishMisc.h"\r
+\r
+EDKII_REDFISH_CREDENTIAL_PROTOCOL *mCredentialProtocol = NULL;\r
+\r
+/**\r
+ This function returns the string of Redfish service version.\r
+\r
+ @param[in] RedfishService Redfish service instance.\r
+ @param[out] ServiceVersionStr Redfish service string.\r
+\r
+ @return EFI_STATUS\r
+\r
+**/\r
+EFI_STATUS\r
+RedfishGetServiceVersion (\r
+ IN REDFISH_SERVICE RedfishService,\r
+ OUT CHAR8 **ServiceVersionStr\r
+ )\r
+{\r
+ redfishService *Redfish;\r
+ CHAR8 **KeysArray;\r
+ UINTN KeysNum;\r
+\r
+ if (RedfishService == NULL || ServiceVersionStr == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+ Redfish = (redfishService *)RedfishService;\r
+ if (Redfish->versions == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+ KeysArray = JsonObjectGetKeys (Redfish->versions, &KeysNum);\r
+ if (KeysNum == 0 || KeysArray == NULL) {\r
+ return EFI_NOT_FOUND;\r
+ }\r
+ *ServiceVersionStr = *KeysArray;\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Creates a REDFISH_SERVICE which can be later used to access the Redfish resources.\r
+\r
+ This function will configure REST EX child according to parameters described in\r
+ Redfish network host interface in SMBIOS type 42 record. The service enumerator will also\r
+ handle the authentication flow automatically if HTTP basic auth or Redfish session\r
+ login is configured to use.\r
+\r
+ @param[in] RedfishConfigServiceInfo Redfish service information the EFI Redfish\r
+ feature driver communicates with.\r
+ @param[in] AuthMethod None, HTTP basic auth, or Redfish session login.\r
+ @param[in] UserId User Name used for authentication.\r
+ @param[in] Password Password used for authentication.\r
+\r
+ @return New created Redfish service, or NULL if error happens.\r
+\r
+**/\r
+REDFISH_SERVICE\r
+RedfishCreateLibredfishService (\r
+ IN REDFISH_CONFIG_SERVICE_INFORMATION *RedfishConfigServiceInfo,\r
+ IN EDKII_REDFISH_AUTH_METHOD AuthMethod,\r
+ IN CHAR8 *UserId,\r
+ IN CHAR8 *Password\r
+ )\r
+{\r
+\r
+ UINTN Flags;\r
+ enumeratorAuthentication Auth;\r
+ redfishService* Redfish;\r
+\r
+ Redfish = NULL;\r
+\r
+ ZeroMem (&Auth, sizeof (Auth));\r
+ if (AuthMethod == AuthMethodHttpBasic) {\r
+ Auth.authType = REDFISH_AUTH_BASIC;\r
+ } else if (AuthMethod == AuthMethodRedfishSession) {\r
+ Auth.authType = REDFISH_AUTH_SESSION;\r
+ }\r
+ Auth.authCodes.userPass.username = UserId;\r
+ Auth.authCodes.userPass.password = Password;\r
+\r
+ Flags = REDFISH_FLAG_SERVICE_NO_VERSION_DOC;\r
+\r
+ if (AuthMethod != AuthMethodNone) {\r
+ Redfish = createServiceEnumerator(RedfishConfigServiceInfo, NULL, &Auth, (unsigned int ) Flags);\r
+ } else {\r
+ Redfish = createServiceEnumerator(RedfishConfigServiceInfo, NULL, NULL, (unsigned int) Flags);\r
+ }\r
+\r
+ //\r
+ // Zero the Password after use.\r
+ //\r
+ if (Password != NULL) {\r
+ ZeroMem (Password, AsciiStrLen(Password));\r
+ }\r
+\r
+ return (REDFISH_SERVICE) Redfish;\r
+}\r
+\r
+/**\r
+ Retrieve platform's Redfish authentication information.\r
+\r
+ This functions returns the Redfish authentication method together with the user\r
+ Id and password.\r
+ For AuthMethodNone, UserId and Password will point to NULL which means authentication\r
+ is not required to access the Redfish service.\r
+ For AuthMethodHttpBasic, the UserId and Password could be used for\r
+ HTTP header authentication as defined by RFC7235. For AuthMethodRedfishSession,\r
+ the UserId and Password could be used for Redfish session login as defined by\r
+ Redfish API specification (DSP0266).\r
+\r
+ Callers are responsible for freeing the returned string storage pointed by UserId\r
+ and Password.\r
+\r
+ @param[out] AuthMethod Type of Redfish authentication method.\r
+ @param[out] UserId The pointer to store the returned UserId string.\r
+ @param[out] Password The pointer to store the returned Password string.\r
+\r
+ @retval EFI_SUCCESS Get the authentication information successfully.\r
+ @retval EFI_INVALID_PARAMETER AuthMethod or UserId or Password is NULL.\r
+ @retval EFI_UNSUPPORTED Unsupported authentication method is found.\r
+**/\r
+EFI_STATUS\r
+RedfishGetAuthInfo (\r
+ OUT EDKII_REDFISH_AUTH_METHOD *AuthMethod,\r
+ OUT CHAR8 **UserId,\r
+ OUT CHAR8 **Password\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+\r
+ if (AuthMethod == NULL || UserId == NULL || Password == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ //\r
+ // Locate Redfish Credential Protocol.\r
+ //\r
+ if (mCredentialProtocol == NULL) {\r
+ Status = gBS->LocateProtocol (&gEdkIIRedfishCredentialProtocolGuid, NULL, (VOID **)&mCredentialProtocol);\r
+ if (EFI_ERROR (Status)) {\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+ }\r
+\r
+ ASSERT (mCredentialProtocol != NULL);\r
+\r
+ Status = mCredentialProtocol->GetAuthInfo (mCredentialProtocol, AuthMethod, UserId, Password);\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((DEBUG_ERROR, "RedfishGetAuthInfo: failed to retrieve Redfish credential - %r\n", Status));\r
+ return Status;\r
+ }\r
+\r
+ return Status;\r
+}\r
+/**\r
+ This function returns the string of Redfish service version.\r
+\r
+ @param[in] ServiceVerisonStr The string of Redfish service version.\r
+ @param[in] Url The URL to build Redpath with ID.\r
+ Start with "/", for example "/Registries"\r
+ @param[in] Id ID string\r
+ @param[out] Redpath Pointer to retrive Redpath, caller has to free\r
+ the memory allocated for this string.\r
+ @return EFI_STATUS\r
+\r
+**/\r
+EFI_STATUS\r
+RedfishBuildRedpathUseId (\r
+ IN CHAR8 *ServiceVerisonStr,\r
+ IN CHAR8 *Url,\r
+ IN CHAR8 *Id,\r
+ OUT CHAR8 **Redpath\r
+ )\r
+{\r
+ UINTN RedpathSize;\r
+\r
+ if (Redpath == NULL || ServiceVerisonStr == NULL || Url == NULL || Id == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ RedpathSize = AsciiStrLen ("/") +\r
+ AsciiStrLen (ServiceVerisonStr) +\r
+ AsciiStrLen (Url) +\r
+ AsciiStrLen ("[Id=]") +\r
+ AsciiStrLen (Id) + 1;\r
+ *Redpath = AllocatePool(RedpathSize);\r
+ if (*Redpath == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+ AsciiSPrint (*Redpath, RedpathSize, "/%a%a[Id=%a]", ServiceVerisonStr, Url, Id);\r
+ return EFI_SUCCESS;\r
+}\r
--- /dev/null
+/** @file\r
+ Internal Functions for RedfishLib.\r
+\r
+ Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>\r
+ (C) Copyright 2021 Hewlett Packard Enterprise Development LP<BR>\r
+\r
+ SPDX-License-Identifier: BSD-2-Clause-Patent\r
+\r
+**/\r
+\r
+#ifndef DXE_REDFISH_MISC_LIB_H_\r
+#define DXE_REDFISH_MISC_LIB_H_\r
+\r
+#include <Library/BaseLib.h>\r
+#include <Library/BaseMemoryLib.h>\r
+#include <Library/DebugLib.h>\r
+#include <Library/JsonLib.h>\r
+#include <Library/MemoryAllocationLib.h>\r
+#include <Library/PrintLib.h>\r
+#include <Library/RedfishLib.h>\r
+#include <Library/UefiLib.h>\r
+#include <Protocol/EdkIIRedfishCredential.h>\r
+#include <redfish.h>\r
+\r
+#define ARRAY_SIZE(Array) (sizeof (Array) / sizeof ((Array)[0]))\r
+\r
+/**\r
+ Creates a REDFISH_SERVICE which can be later used to access the Redfish resources.\r
+\r
+ This function will configure REST EX child according to parameters described in\r
+ Redfish network host interface in SMBIOS type 42 record. The service enumerator will also\r
+ handle the authentication flow automatically if HTTP basic auth or Redfish session\r
+ login is configured to use.\r
+\r
+ @param[in] RedfishConfigServiceInfo Redfish service information the EFI Redfish\r
+ feature driver communicates with.\r
+ @param[in] AuthMethod None, HTTP basic auth, or Redfish session login.\r
+ @param[in] UserId User Name used for authentication.\r
+ @param[in] Password Password used for authentication.\r
+\r
+ @return New created Redfish service, or NULL if error happens.\r
+\r
+**/\r
+REDFISH_SERVICE\r
+RedfishCreateLibredfishService (\r
+ IN REDFISH_CONFIG_SERVICE_INFORMATION *RedfishConfigServiceInfo,\r
+ IN EDKII_REDFISH_AUTH_METHOD AuthMethod,\r
+ IN CHAR8 *UserId,\r
+ IN CHAR8 *Password\r
+ );\r
+\r
+/**\r
+ Retrieve platform's Redfish authentication information.\r
+\r
+ This functions returns the Redfish authentication method together with the user\r
+ Id and password.\r
+ For AuthMethodNone, UserId and Password will point to NULL which means authentication\r
+ is not required to access the Redfish service.\r
+ For AuthMethodHttpBasic, the UserId and Password could be used for\r
+ HTTP header authentication as defined by RFC7235. For AuthMethodRedfishSession,\r
+ the UserId and Password could be used for Redfish session login as defined by\r
+ Redfish API specification (DSP0266).\r
+\r
+ Callers are responsible for freeing the returned string storage pointed by UserId\r
+ and Password.\r
+\r
+ @param[out] AuthMethod Type of Redfish authentication method.\r
+ @param[out] UserId The pointer to store the returned UserId string.\r
+ @param[out] Password The pointer to store the returned Password string.\r
+\r
+ @retval EFI_SUCCESS Get the authentication information successfully.\r
+ @retval EFI_INVALID_PARAMETER AuthMethod or UserId or Password is NULL.\r
+ @retval EFI_UNSUPPORTED Unsupported authentication method is found.\r
+**/\r
+EFI_STATUS\r
+RedfishGetAuthInfo (\r
+ OUT EDKII_REDFISH_AUTH_METHOD *AuthMethod,\r
+ OUT CHAR8 **UserId,\r
+ OUT CHAR8 **Password\r
+ );\r
+\r
+#endif\r
--- /dev/null
+/** @file\r
+ This file is cloned from DMTF libredfish library tag v1.0.0 and maintained\r
+ by EDKII.\r
+\r
+//----------------------------------------------------------------------------\r
+// Copyright Notice:\r
+// Copyright 2017 Distributed Management Task Force, Inc. All rights reserved.\r
+// License: BSD 3-Clause License. For full text see link: https://github.com/DMTF/libredfish/LICENSE.md\r
+//----------------------------------------------------------------------------\r
+\r
+ Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>\r
+ (C) Copyright 2021 Hewlett Packard Enterprise Development LP<BR>\r
+\r
+ SPDX-License-Identifier: BSD-2-Clause-Patent\r
+\r
+**/\r
+#ifndef LIBREDFISH_REDFISH_H_\r
+#define LIBREDFISH_REDFISH_H_\r
+\r
+#include <redfishService.h>\r
+#include <redfishPayload.h>\r
+#include <redpath.h>\r
+\r
+#endif\r
--- /dev/null
+/** @file\r
+ This file is cloned from DMTF libredfish library tag v1.0.0 and maintained\r
+ by EDKII.\r
+\r
+//----------------------------------------------------------------------------\r
+// Copyright Notice:\r
+// Copyright 2017 Distributed Management Task Force, Inc. All rights reserved.\r
+// License: BSD 3-Clause License. For full text see link: https://github.com/DMTF/libredfish/LICENSE.md\r
+//----------------------------------------------------------------------------\r
+\r
+ Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>\r
+ (C) Copyright 2021 Hewlett Packard Enterprise Development LP<BR>\r
+\r
+ SPDX-License-Identifier: BSD-2-Clause-Patent\r
+\r
+**/\r
+#ifndef LIBREDFISH_REDFISH_PAYLOAD_H_\r
+#define LIBREDFISH_REDFISH_PAYLOAD_H_\r
+\r
+#include <PrivateInclude/Library/RedfishCrtLib.h>\r
+\r
+#include <jansson.h>\r
+#include <redfishService.h>\r
+#include <redpath.h>\r
+\r
+redfishPayload* createRedfishPayload(json_t* value, redfishService* service);\r
+redfishPayload* getPayloadByNodeName(redfishPayload* payload, const char* nodeName, EFI_HTTP_STATUS_CODE** StatusCode);\r
+redfishPayload* getPayloadByIndex(redfishPayload* payload, size_t index, EFI_HTTP_STATUS_CODE** StatusCode);\r
+redfishPayload* getPayloadForPath(redfishPayload* payload, redPathNode* redpath, EFI_HTTP_STATUS_CODE** StatusCode);\r
+redfishPayload* getPayloadForPathString(redfishPayload* payload, const char* string, EFI_HTTP_STATUS_CODE** StatusCode);\r
+redfishPayload* patchPayload(redfishPayload* target, redfishPayload* payload, EFI_HTTP_STATUS_CODE** StatusCode);\r
+redfishPayload* postContentToPayload(redfishPayload* target, const char* data, size_t dataSize, const char* contentType, EFI_HTTP_STATUS_CODE** StatusCode);\r
+redfishPayload* postPayload(redfishPayload* target, redfishPayload* payload, EFI_HTTP_STATUS_CODE** StatusCode);\r
+void cleanupPayload(redfishPayload* payload);\r
+bool isPayloadCollection (redfishPayload *Payload);\r
+size_t getCollectionSize(redfishPayload* payload);\r
+redfishPayload* getPayloadByIndex (redfishPayload* payload, size_t index, EFI_HTTP_STATUS_CODE** StatusCode);\r
+\r
+#endif\r
--- /dev/null
+/** @file\r
+ This file is cloned from DMTF libredfish library tag v1.0.0 and maintained\r
+ by EDKII.\r
+\r
+//----------------------------------------------------------------------------\r
+// Copyright Notice:\r
+// Copyright 2017 Distributed Management Task Force, Inc. All rights reserved.\r
+// License: BSD 3-Clause License. For full text see link: https://github.com/DMTF/libredfish/LICENSE.md\r
+//----------------------------------------------------------------------------\r
+\r
+ Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>\r
+ (C) Copyright 2021 Hewlett Packard Enterprise Development LP<BR>\r
+\r
+ SPDX-License-Identifier: BSD-2-Clause-Patent\r
+\r
+**/\r
+\r
+#ifndef LIBREDFISH_REDFISH_SERVICE_H_\r
+#define LIBREDFISH_REDFISH_SERVICE_H_\r
+\r
+#include <IndustryStandard/Http11.h>\r
+\r
+#include <Library/BaseLib.h>\r
+#include <Library/BaseMemoryLib.h>\r
+#include <Library/DebugLib.h>\r
+#include <Library/HttpLib.h>\r
+#include <Library/MemoryAllocationLib.h>\r
+#include <Library/NetLib.h>\r
+#include <Library/RedfishContentCodingLib.h>\r
+#include <Library/UefiRuntimeServicesTableLib.h>\r
+#include <Library/UefiBootServicesTableLib.h>\r
+\r
+#include <PrivateInclude/Library/RedfishCrtLib.h>\r
+\r
+#include <Protocol/EdkIIRedfishConfigHandler.h>\r
+#include <Protocol/RestEx.h>\r
+\r
+#include <jansson.h>\r
+\r
+typedef struct {\r
+ char* host;\r
+ json_t* versions;\r
+ unsigned int flags;\r
+ char* sessionToken;\r
+ char* basicAuthStr;\r
+ //\r
+ // point to the <HOST> part in above "host" field, which will be put into\r
+ // the "Host" header of HTTP request message.\r
+ //\r
+ char* HostHeaderValue;\r
+ EFI_REST_EX_PROTOCOL *RestEx;\r
+} redfishService;\r
+\r
+typedef struct {\r
+ json_t* json;\r
+ redfishService* service;\r
+} redfishPayload;\r
+\r
+#define REDFISH_AUTH_BASIC 0\r
+#define REDFISH_AUTH_BEARER_TOKEN 1\r
+#define REDFISH_AUTH_SESSION 2\r
+\r
+#define REDFISH_HTTP_RESPONSE_TIMEOUT 5000 /// 5 seconds in uints of millisecond.\r
+\r
+///\r
+/// Library class public defines\r
+///\r
+#define HTTP_FLAG L"http://"\r
+#define HTTPS_FLAG L"https://"\r
+\r
+///\r
+/// The redfish first URL should be "/redfish/v1/", while we use "/redfish/v1" here without "/"\r
+/// in the end is to avoid the 301 Perment redirect response from Redfish profile simulator.\r
+///\r
+#define REDFISH_FIRST_URL L"/redfish/v1"\r
+\r
+typedef struct {\r
+ unsigned int authType;\r
+ union {\r
+ struct {\r
+ char* username;\r
+ char* password;\r
+ } userPass;\r
+ struct {\r
+ char* token;\r
+ } authToken;\r
+ } authCodes;\r
+} enumeratorAuthentication;\r
+\r
+//Values for flags\r
+#define REDFISH_FLAG_SERVICE_NO_VERSION_DOC 0x00000001 //The Redfish Service lacks the version document (in violation of the Redfish spec)\r
+redfishService* createServiceEnumerator(REDFISH_CONFIG_SERVICE_INFORMATION *RedfishConfigServiceInfo, const char* rootUri, enumeratorAuthentication* auth, unsigned int flags);\r
+json_t* getUriFromService(redfishService* service, const char* uri, EFI_HTTP_STATUS_CODE** StatusCode);\r
+json_t* patchUriFromService(redfishService* service, const char* uri, const char* content, EFI_HTTP_STATUS_CODE** StatusCode);\r
+json_t* postUriFromService(redfishService* service, const char* uri, const char* content, size_t contentLength, const char* contentType, EFI_HTTP_STATUS_CODE** StatusCode);\r
+json_t* deleteUriFromService(redfishService* service, const char* uri, EFI_HTTP_STATUS_CODE** StatusCode);\r
+redfishPayload* getRedfishServiceRoot(redfishService* service, const char* version, EFI_HTTP_STATUS_CODE** StatusCode);\r
+redfishPayload* getPayloadByPath(redfishService* service, const char* path, EFI_HTTP_STATUS_CODE** StatusCode);\r
+void cleanupServiceEnumerator(redfishService* service);\r
+\r
+#endif\r
--- /dev/null
+/** @file\r
+ This file is cloned from DMTF libredfish library tag v1.0.0 and maintained\r
+ by EDKII.\r
+\r
+//----------------------------------------------------------------------------\r
+// Copyright Notice:\r
+// Copyright 2017 Distributed Management Task Force, Inc. All rights reserved.\r
+// License: BSD 3-Clause License. For full text see link: https://github.com/DMTF/libredfish/LICENSE.md\r
+//----------------------------------------------------------------------------\r
+\r
+ Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>\r
+ (C) Copyright 2021 Hewlett Packard Enterprise Development LP<BR>\r
+\r
+ SPDX-License-Identifier: BSD-2-Clause-Patent\r
+\r
+**/\r
+#ifndef LIBREDFISH_REDPATH_H_\r
+#define LIBREDFISH_REDPATH_H_\r
+\r
+#include <PrivateInclude/Library/RedfishCrtLib.h>\r
+\r
+#include <jansson.h>\r
+\r
+typedef struct _redPathNode\r
+{\r
+ bool isRoot;\r
+ bool isIndex;\r
+\r
+ char* version;\r
+ char* nodeName;\r
+ size_t index;\r
+ char* op;\r
+ char* propName;\r
+ char* value;\r
+\r
+ struct _redPathNode* next;\r
+} redPathNode;\r
+\r
+redPathNode* parseRedPath(const char* path);\r
+void cleanupRedPath(redPathNode* node);\r
+\r
+#endif\r
--- /dev/null
+/** @file\r
+ This file is cloned from DMTF libredfish library tag v1.0.0 and maintained\r
+ by EDKII.\r
+\r
+//----------------------------------------------------------------------------\r
+// Copyright Notice:\r
+// Copyright 2017 Distributed Management Task Force, Inc. All rights reserved.\r
+// License: BSD 3-Clause License. For full text see link: https://github.com/DMTF/libredfish/LICENSE.md\r
+//----------------------------------------------------------------------------\r
+\r
+ Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>\r
+ (C) Copyright 2021 Hewlett Packard Enterprise Development LP<BR>\r
+\r
+ SPDX-License-Identifier: BSD-2-Clause-Patent\r
+\r
+**/\r
+#include <redfishPayload.h>\r
+\r
+static redfishPayload* getOpResult(redfishPayload* payload, const char* propName, const char* op, const char* value, EFI_HTTP_STATUS_CODE** StatusCode);\r
+static redfishPayload* collectionEvalOp(redfishPayload* payload, const char* propName, const char* op, const char* value, EFI_HTTP_STATUS_CODE** StatusCode);\r
+static redfishPayload* arrayEvalOp(redfishPayload* payload, const char* propName, const char* op, const char* value, EFI_HTTP_STATUS_CODE** StatusCode);\r
+static redfishPayload* createCollection(redfishService* service, size_t count, redfishPayload** payloads);\r
+static json_t* json_object_get_by_index(json_t* json, size_t index);\r
+\r
+bool isPayloadCollection(redfishPayload* payload)\r
+{\r
+ json_t* members;\r
+ json_t* count;\r
+\r
+ if(!payload || !json_is_object(payload->json))\r
+ {\r
+ return false;\r
+ }\r
+ members = json_object_get(payload->json, "Members");\r
+ count = json_object_get(payload->json, "Members@odata.count");\r
+ return ((members != NULL) && (count != NULL));\r
+}\r
+\r
+size_t getCollectionSize(redfishPayload* payload)\r
+{\r
+ json_t* members;\r
+ json_t* count;\r
+\r
+ if(!payload || !json_is_object(payload->json))\r
+ {\r
+ return 0;\r
+ }\r
+ members = json_object_get(payload->json, "Members");\r
+ count = json_object_get(payload->json, "Members@odata.count");\r
+ if(!members || !count)\r
+ {\r
+ return 0;\r
+ }\r
+ return (size_t)json_integer_value(count);\r
+}\r
+\r
+bool isPayloadArray(redfishPayload* payload)\r
+{\r
+ if(!payload || !json_is_array(payload->json))\r
+ {\r
+ return false;\r
+ }\r
+ return true;\r
+}\r
+\r
+char* payloadToString(redfishPayload* payload, bool prettyPrint)\r
+{\r
+ size_t flags = 0;\r
+ if(!payload)\r
+ {\r
+ return NULL;\r
+ }\r
+ if(prettyPrint)\r
+ {\r
+ flags = JSON_INDENT(2);\r
+ }\r
+ return json_dumps(payload->json, flags);\r
+}\r
+\r
+redfishPayload* createRedfishPayload(json_t* value, redfishService* service)\r
+{\r
+ redfishPayload* payload;\r
+ payload = (redfishPayload*)malloc(sizeof(redfishPayload));\r
+ if(payload != NULL)\r
+ {\r
+ payload->json = value;\r
+ payload->service = service;\r
+ }\r
+ return payload;\r
+}\r
+\r
+redfishPayload* getPayloadByNodeName(redfishPayload* payload, const char* nodeName, EFI_HTTP_STATUS_CODE** StatusCode)\r
+{\r
+ json_t* value;\r
+ json_t* odataId;\r
+ const char* uri;\r
+\r
+ if(!payload || !nodeName || StatusCode == NULL)\r
+ {\r
+ return NULL;\r
+ }\r
+\r
+ *StatusCode = NULL;\r
+\r
+ value = json_object_get(payload->json, nodeName);\r
+ if(value == NULL)\r
+ {\r
+ return NULL;\r
+ }\r
+ json_incref(value);\r
+ if(json_object_size(value) == 1)\r
+ {\r
+ odataId = json_object_get(value, "@odata.id");\r
+ if(odataId != NULL)\r
+ {\r
+ json_incref(odataId);\r
+ uri = json_string_value(odataId);\r
+ json_decref(value);\r
+ value = getUriFromService(payload->service, uri, StatusCode);\r
+ json_decref(odataId);\r
+ if(value == NULL || *StatusCode == NULL)\r
+ {\r
+ return NULL;\r
+ }\r
+ }\r
+ }\r
+ if (*StatusCode == NULL || (**StatusCode >= HTTP_STATUS_200_OK && **StatusCode <= HTTP_STATUS_206_PARTIAL_CONTENT)) {\r
+ if(json_is_string(value))\r
+ {\r
+ odataId = json_object();\r
+ json_object_set(odataId, nodeName, value);\r
+ json_decref(value);\r
+ value = odataId;\r
+ }\r
+ }\r
+\r
+ return createRedfishPayload(value, payload->service);\r
+}\r
+\r
+redfishPayload* getPayloadByIndex(redfishPayload* payload, size_t index, EFI_HTTP_STATUS_CODE** StatusCode)\r
+{\r
+ json_t* value = NULL;\r
+ json_t* odataId;\r
+ const char* uri;\r
+ BOOLEAN FromServerFlag = FALSE;\r
+\r
+ if(!payload || StatusCode == NULL)\r
+ {\r
+ return NULL;\r
+ }\r
+\r
+ *StatusCode = NULL;\r
+\r
+ if(isPayloadCollection(payload))\r
+ {\r
+ redfishPayload* members = getPayloadByNodeName(payload, "Members", StatusCode);\r
+ if ((*StatusCode == NULL && members == NULL) ||\r
+ (*StatusCode != NULL && (**StatusCode < HTTP_STATUS_200_OK || **StatusCode > HTTP_STATUS_206_PARTIAL_CONTENT))) {\r
+ return members;\r
+ }\r
+\r
+ if (*StatusCode != NULL) {\r
+ //\r
+ // The Payload (members) are retrived from server.\r
+ //\r
+ FreePool (*StatusCode);\r
+ *StatusCode = NULL;\r
+ FromServerFlag = TRUE;\r
+ }\r
+\r
+ redfishPayload* ret = getPayloadByIndex(members, index, StatusCode);\r
+ if (*StatusCode == NULL && ret != NULL && FromServerFlag) {\r
+ //\r
+ // In such a case, the Redfish resource is parsed from the input payload (members) directly.\r
+ // Since the members are retrived from server, we still return HTTP_STATUS_200_OK.\r
+ //\r
+ *StatusCode = AllocateZeroPool (sizeof (EFI_HTTP_STATUS_CODE));\r
+ if (*StatusCode == NULL) {\r
+ ret = NULL;\r
+ } else {\r
+ **StatusCode = HTTP_STATUS_200_OK;\r
+ }\r
+ }\r
+\r
+ cleanupPayload(members);\r
+ return ret;\r
+ }\r
+\r
+ if(json_is_array(payload->json))\r
+ {\r
+ //\r
+ // The valid range for index is from 0 to the return value of json_array_size() minus 1\r
+ //\r
+ value = json_array_get(payload->json, index);\r
+ }\r
+ else if(json_is_object(payload->json))\r
+ {\r
+ value = json_object_get_by_index(payload->json, index);\r
+ }\r
+\r
+ if(value == NULL)\r
+ {\r
+ return NULL;\r
+ }\r
+\r
+ json_incref(value);\r
+ if(json_object_size(value) == 1)\r
+ {\r
+ odataId = json_object_get(value, "@odata.id");\r
+ if(odataId != NULL)\r
+ {\r
+ uri = json_string_value(odataId);\r
+ json_decref(value);\r
+ value = getUriFromService(payload->service, uri, StatusCode);\r
+ if(value == NULL)\r
+ {\r
+ return NULL;\r
+ }\r
+ }\r
+ }\r
+ return createRedfishPayload(value, payload->service);\r
+}\r
+\r
+redfishPayload* getPayloadForPath(redfishPayload* payload, redPathNode* redpath, EFI_HTTP_STATUS_CODE** StatusCode)\r
+{\r
+ redfishPayload* ret = NULL;\r
+ redfishPayload* tmp;\r
+\r
+ if(!payload || !redpath || StatusCode == NULL)\r
+ {\r
+ return NULL;\r
+ }\r
+\r
+ *StatusCode = NULL;\r
+ BOOLEAN FromServerFlag = FALSE;\r
+\r
+ if(redpath->nodeName)\r
+ {\r
+ ret = getPayloadByNodeName(payload, redpath->nodeName, StatusCode);\r
+ if ((*StatusCode == NULL && ret == NULL) ||\r
+ (*StatusCode != NULL && (**StatusCode < HTTP_STATUS_200_OK || **StatusCode > HTTP_STATUS_206_PARTIAL_CONTENT))) {\r
+ //\r
+ // Any error happen, return directly.\r
+ //\r
+ return ret;\r
+ }\r
+ }\r
+ else if(redpath->isIndex)\r
+ {\r
+ ASSERT (redpath->index >= 1);\r
+ ret = getPayloadByIndex(payload, redpath->index - 1, StatusCode);\r
+ if ((*StatusCode == NULL && ret == NULL) ||\r
+ (*StatusCode != NULL && (**StatusCode < HTTP_STATUS_200_OK || **StatusCode > HTTP_STATUS_206_PARTIAL_CONTENT))) {\r
+ //\r
+ // Any error happen, return directly.\r
+ //\r
+ return ret;\r
+ }\r
+ }\r
+ else if(redpath->op)\r
+ {\r
+ ret = getOpResult(payload, redpath->propName, redpath->op, redpath->value, StatusCode);\r
+ if ((*StatusCode == NULL && ret == NULL) ||\r
+ (*StatusCode != NULL && (**StatusCode < HTTP_STATUS_200_OK || **StatusCode > HTTP_STATUS_206_PARTIAL_CONTENT))) {\r
+ //\r
+ // Any error happen, return directly.\r
+ //\r
+ return ret;\r
+ }\r
+ }\r
+ else\r
+ {\r
+ return NULL;\r
+ }\r
+\r
+ if(redpath->next == NULL || ret == NULL)\r
+ {\r
+ return ret;\r
+ }\r
+ else\r
+ {\r
+ if (*StatusCode != NULL) {\r
+ FreePool (*StatusCode);\r
+ *StatusCode = NULL;\r
+ FromServerFlag = TRUE;\r
+ }\r
+\r
+ tmp = getPayloadForPath(ret, redpath->next, StatusCode);\r
+ if (*StatusCode == NULL && tmp != NULL && FromServerFlag) {\r
+ //\r
+ // In such a case, the Redfish resource is parsed from the input payload (ret) directly.\r
+ // Since the ret are retrived from server, we still return HTTP_STATUS_200_OK.\r
+ //\r
+ *StatusCode = AllocateZeroPool (sizeof (EFI_HTTP_STATUS_CODE));\r
+ if (*StatusCode == NULL) {\r
+ tmp = NULL;\r
+ } else {\r
+ **StatusCode = HTTP_STATUS_200_OK;\r
+ }\r
+ }\r
+\r
+ cleanupPayload(ret);\r
+ return tmp;\r
+ }\r
+}\r
+\r
+redfishPayload* getPayloadForPathString(redfishPayload* payload, const char* string, EFI_HTTP_STATUS_CODE** StatusCode)\r
+{\r
+ redPathNode* redpath;\r
+ redfishPayload* ret;\r
+\r
+ if(!string || StatusCode == NULL)\r
+ {\r
+ return NULL;\r
+ }\r
+\r
+ *StatusCode = NULL;\r
+\r
+ redpath = parseRedPath(string);\r
+ if(redpath == NULL)\r
+ {\r
+ return NULL;\r
+ }\r
+ ret = getPayloadForPath(payload, redpath, StatusCode);\r
+ cleanupRedPath(redpath);\r
+ return ret;\r
+}\r
+\r
+redfishPayload* patchPayload(redfishPayload* target, redfishPayload* payload, EFI_HTTP_STATUS_CODE** StatusCode)\r
+{\r
+ json_t* json;\r
+ char* content;\r
+ char* uri;\r
+\r
+ if(!target || !payload || StatusCode == NULL)\r
+ {\r
+ return NULL;\r
+ }\r
+\r
+ *StatusCode = NULL;\r
+\r
+ json = json_object_get(target->json, "@odata.id");\r
+ if(json == NULL)\r
+ {\r
+ return NULL;\r
+ }\r
+ uri = strdup(json_string_value(json));\r
+\r
+ content = json_dumps(payload->json, 0);\r
+ json_decref(json);\r
+\r
+ json = patchUriFromService(target->service, uri, content, StatusCode);\r
+ free(uri);\r
+ free(content);\r
+ if(json == NULL)\r
+ {\r
+ return NULL;\r
+ }\r
+\r
+ return createRedfishPayload(json, target->service);\r
+}\r
+\r
+redfishPayload* postContentToPayload(redfishPayload* target, const char* data, size_t dataSize, const char* contentType, EFI_HTTP_STATUS_CODE** StatusCode)\r
+{\r
+ json_t* json;\r
+ char* uri;\r
+\r
+ if(!target || !data || StatusCode == NULL)\r
+ {\r
+ return NULL;\r
+ }\r
+\r
+ *StatusCode = NULL;\r
+\r
+ json = json_object_get(target->json, "@odata.id");\r
+ if(json == NULL)\r
+ {\r
+ json = json_object_get(target->json, "target");\r
+ if(json == NULL)\r
+ {\r
+ return NULL;\r
+ }\r
+ }\r
+ uri = strdup(json_string_value(json));\r
+ json = postUriFromService(target->service, uri, data, dataSize, contentType, StatusCode);\r
+ free(uri);\r
+ if(json == NULL)\r
+ {\r
+ return NULL;\r
+ }\r
+\r
+ return createRedfishPayload(json, target->service);\r
+}\r
+\r
+redfishPayload* postPayload(redfishPayload* target, redfishPayload* payload, EFI_HTTP_STATUS_CODE** StatusCode)\r
+{\r
+ char* content;\r
+ redfishPayload* ret;\r
+\r
+ if(!target || !payload || StatusCode == NULL)\r
+ {\r
+ return NULL;\r
+ }\r
+\r
+ *StatusCode = NULL;\r
+\r
+ if(!json_is_object(payload->json))\r
+ {\r
+ return NULL;\r
+ }\r
+ content = payloadToString(payload, false);\r
+ ret = postContentToPayload(target, content, strlen(content), NULL, StatusCode);\r
+ free(content);\r
+ return ret;\r
+}\r
+\r
+void cleanupPayload(redfishPayload* payload)\r
+{\r
+ if(!payload)\r
+ {\r
+ return;\r
+ }\r
+ json_decref(payload->json);\r
+ //Don't free payload->service, let the caller handle cleaning up the service\r
+ free(payload);\r
+}\r
+\r
+static redfishPayload* getOpResult(redfishPayload* payload, const char* propName, const char* op, const char* value, EFI_HTTP_STATUS_CODE** StatusCode)\r
+{\r
+ const char* propStr;\r
+ json_t* stringProp;\r
+ bool ret = false;\r
+ redfishPayload* prop;\r
+ long long intVal, intPropVal;\r
+ json_type jsonType;\r
+\r
+ if(isPayloadCollection(payload))\r
+ {\r
+ return collectionEvalOp(payload, propName, op, value, StatusCode);\r
+ }\r
+ if(isPayloadArray(payload))\r
+ {\r
+ return arrayEvalOp(payload, propName, op, value, StatusCode);\r
+ }\r
+\r
+ prop = getPayloadByNodeName(payload, propName, StatusCode);\r
+ if ((*StatusCode == NULL && prop == NULL) ||\r
+ (*StatusCode != NULL && (**StatusCode < HTTP_STATUS_200_OK || **StatusCode > HTTP_STATUS_206_PARTIAL_CONTENT))) {\r
+ return prop;\r
+ }\r
+ stringProp = prop->json;\r
+ jsonType = prop->json->type;\r
+ switch(jsonType)\r
+ {\r
+ case JSON_OBJECT:\r
+ stringProp = json_object_get(prop->json, propName);\r
+ case JSON_STRING:\r
+ if(strcmp(op, "=") == 0)\r
+ {\r
+ propStr = json_string_value(stringProp);\r
+ if(propStr == NULL)\r
+ {\r
+ cleanupPayload(prop);\r
+ return NULL;\r
+ }\r
+ ret = (strcmp(propStr, value) == 0);\r
+ } else if(strcmp(op, "~") == 0)\r
+ {\r
+ propStr = json_string_value(stringProp);\r
+ if(propStr == NULL)\r
+ {\r
+ cleanupPayload(prop);\r
+ return NULL;\r
+ }\r
+ ret = (strcasecmp(propStr, value) == 0);\r
+ }\r
+ break;\r
+ case JSON_TRUE:\r
+ if(strcmp(op, "=") == 0)\r
+ {\r
+ ret = (strcmp(value, "true") == 0);\r
+ }\r
+ break;\r
+ case JSON_FALSE:\r
+ if(strcmp(op, "=") == 0)\r
+ {\r
+ ret = (strcmp(value, "false") == 0);\r
+ }\r
+ break;\r
+ case JSON_INTEGER:\r
+ intPropVal = json_integer_value(prop->json);\r
+ intVal = strtoll(value, NULL, 0);\r
+ if(strcmp(op, "=") == 0)\r
+ {\r
+ ret = (intPropVal == intVal);\r
+ }\r
+ else if(strcmp(op, "<") == 0)\r
+ {\r
+ ret = (intPropVal < intVal);\r
+ }\r
+ else if(strcmp(op, ">") == 0)\r
+ {\r
+ ret = (intPropVal > intVal);\r
+ }\r
+ else if(strcmp(op, "<=") == 0)\r
+ {\r
+ ret = (intPropVal <= intVal);\r
+ }\r
+ else if(strcmp(op, ">=") == 0)\r
+ {\r
+ ret = (intPropVal >= intVal);\r
+ }\r
+ break;\r
+ default:\r
+ break;\r
+ }\r
+ cleanupPayload(prop);\r
+ if(ret)\r
+ {\r
+ return payload;\r
+ }\r
+ else\r
+ {\r
+ return NULL;\r
+ }\r
+}\r
+\r
+static redfishPayload* collectionEvalOp(redfishPayload* payload, const char* propName, const char* op, const char* value, EFI_HTTP_STATUS_CODE** StatusCode)\r
+{\r
+ redfishPayload* ret;\r
+ redfishPayload* tmp;\r
+ redfishPayload* members;\r
+ redfishPayload** valid;\r
+ size_t validMax;\r
+ size_t validCount = 0;\r
+ size_t i;\r
+\r
+ validMax = getCollectionSize(payload);\r
+ if(validMax == 0)\r
+ {\r
+ return NULL;\r
+ }\r
+\r
+ valid = (redfishPayload**)calloc(validMax, sizeof(redfishPayload*));\r
+ if(valid == NULL)\r
+ {\r
+ return NULL;\r
+ }\r
+ /*Technically getPayloadByIndex would do this, but this optimizes things*/\r
+ members = getPayloadByNodeName(payload, "Members", StatusCode);\r
+ if ((*StatusCode == NULL && members == NULL) ||\r
+ (*StatusCode != NULL && (**StatusCode < HTTP_STATUS_200_OK || **StatusCode > HTTP_STATUS_206_PARTIAL_CONTENT))) {\r
+ return members;\r
+ }\r
+\r
+ for(i = 0; i < validMax; i++)\r
+ {\r
+ if (*StatusCode != NULL) {\r
+ FreePool (*StatusCode);\r
+ *StatusCode = NULL;\r
+ }\r
+\r
+ tmp = getPayloadByIndex(members, i, StatusCode);\r
+ if ((*StatusCode == NULL && tmp == NULL) ||\r
+ (*StatusCode != NULL && (**StatusCode < HTTP_STATUS_200_OK || **StatusCode > HTTP_STATUS_206_PARTIAL_CONTENT))) {\r
+ return tmp;\r
+ }\r
+\r
+ if (*StatusCode != NULL) {\r
+ FreePool (*StatusCode);\r
+ *StatusCode = NULL;\r
+ }\r
+\r
+ valid[validCount] = getOpResult(tmp, propName, op, value, StatusCode);\r
+ /*\r
+ if ((*StatusCode == NULL && valid[validCount] == NULL) ||\r
+ (*StatusCode != NULL && (**StatusCode < HTTP_STATUS_200_OK || **StatusCode > HTTP_STATUS_206_PARTIAL_CONTENT))) {\r
+ return valid[validCount];\r
+ }\r
+ */\r
+ if(valid[validCount] != NULL)\r
+ {\r
+ validCount++;\r
+ }\r
+ else\r
+ {\r
+ cleanupPayload(tmp);\r
+ }\r
+ }\r
+ cleanupPayload(members);\r
+ if(validCount == 0)\r
+ {\r
+ free(valid);\r
+ return NULL;\r
+ }\r
+ if(validCount == 1)\r
+ {\r
+ ret = valid[0];\r
+ free(valid);\r
+ return ret;\r
+ }\r
+ else\r
+ {\r
+ ret = createCollection(payload->service, validCount, valid);\r
+ free(valid);\r
+ return ret;\r
+ }\r
+}\r
+\r
+static redfishPayload* arrayEvalOp(redfishPayload* payload, const char* propName, const char* op, const char* value, EFI_HTTP_STATUS_CODE** StatusCode)\r
+{\r
+ redfishPayload* ret;\r
+ redfishPayload* tmp;\r
+ redfishPayload** valid;\r
+ size_t validMax;\r
+ size_t validCount = 0;\r
+ size_t i;\r
+\r
+ validMax = json_array_size(payload->json);\r
+ if(validMax == 0)\r
+ {\r
+ return NULL;\r
+ }\r
+\r
+ valid = (redfishPayload**)calloc(validMax, sizeof(redfishPayload*));\r
+ if(valid == NULL)\r
+ {\r
+ return NULL;\r
+ }\r
+ for(i = 0; i < validMax; i++)\r
+ {\r
+ if (*StatusCode != NULL) {\r
+ FreePool (*StatusCode);\r
+ *StatusCode = NULL;\r
+ }\r
+\r
+ tmp = getPayloadByIndex(payload, i, StatusCode);\r
+ if ((*StatusCode == NULL && tmp == NULL) ||\r
+ (*StatusCode != NULL && (**StatusCode < HTTP_STATUS_200_OK || **StatusCode > HTTP_STATUS_206_PARTIAL_CONTENT))) {\r
+ return tmp;\r
+ }\r
+\r
+ if (*StatusCode != NULL) {\r
+ FreePool (*StatusCode);\r
+ *StatusCode = NULL;\r
+ }\r
+\r
+ valid[validCount] = getOpResult(tmp, propName, op, value, StatusCode);\r
+ /*\r
+ if ((*StatusCode == NULL && valid[validCount] == NULL) ||\r
+ (*StatusCode != NULL && (**StatusCode < HTTP_STATUS_200_OK || **StatusCode > HTTP_STATUS_206_PARTIAL_CONTENT))) {\r
+ return valid[validCount];\r
+ }\r
+ */\r
+\r
+ if(valid[validCount] != NULL)\r
+ {\r
+ validCount++;\r
+ }\r
+ else\r
+ {\r
+ cleanupPayload(tmp);\r
+ }\r
+ }\r
+ if(validCount == 0)\r
+ {\r
+ free(valid);\r
+ return NULL;\r
+ }\r
+ if(validCount == 1)\r
+ {\r
+ ret = valid[0];\r
+ free(valid);\r
+ return ret;\r
+ }\r
+ else\r
+ {\r
+ ret = createCollection(payload->service, validCount, valid);\r
+ free(valid);\r
+ return ret;\r
+ }\r
+}\r
+\r
+static redfishPayload* createCollection(redfishService* service, size_t count, redfishPayload** payloads)\r
+{\r
+ redfishPayload* ret;\r
+ json_t* collectionJson = json_object();\r
+ json_t* jcount = json_integer((json_int_t)count);\r
+ json_t* members = json_array();\r
+ size_t i;\r
+\r
+ if(!collectionJson)\r
+ {\r
+ return NULL;\r
+ }\r
+ if(!members)\r
+ {\r
+ json_decref(collectionJson);\r
+ return NULL;\r
+ }\r
+ json_object_set(collectionJson, "Members@odata.count", jcount);\r
+ json_decref(jcount);\r
+ for(i = 0; i < count; i++)\r
+ {\r
+ json_array_append(members, payloads[i]->json);\r
+ cleanupPayload(payloads[i]);\r
+ }\r
+ json_object_set(collectionJson, "Members", members);\r
+ json_decref(members);\r
+\r
+ ret = createRedfishPayload(collectionJson, service);\r
+ return ret;\r
+}\r
+\r
+static json_t* json_object_get_by_index(json_t* json, size_t index)\r
+{\r
+ void* iter;\r
+ size_t i;\r
+\r
+ iter = json_object_iter(json);\r
+ for(i = 0; i < index; i++)\r
+ {\r
+ iter = json_object_iter_next(json, iter);\r
+ if(iter == NULL) break;\r
+ }\r
+ if(iter == NULL)\r
+ {\r
+ return NULL;\r
+ }\r
+ return json_object_iter_value(iter);\r
+}\r
+/* vim: set tabstop=4 shiftwidth=4 expandtab: */\r
--- /dev/null
+/** @file\r
+ This file is cloned from DMTF libredfish library tag v1.0.0 and maintained\r
+ by EDKII.\r
+\r
+//----------------------------------------------------------------------------\r
+// Copyright Notice:\r
+// Copyright 2017 Distributed Management Task Force, Inc. All rights reserved.\r
+// License: BSD 3-Clause License. For full text see link: https://github.com/DMTF/libredfish/LICENSE.md\r
+//----------------------------------------------------------------------------\r
+\r
+ Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>\r
+ (C) Copyright 2021 Hewlett Packard Enterprise Development LP<BR>\r
+\r
+ SPDX-License-Identifier: BSD-2-Clause-Patent\r
+\r
+**/\r
+#include <redpath.h>\r
+\r
+static char* getVersion(const char* path, char** end);\r
+static void parseNode(const char* path, redPathNode* node, redPathNode** end);\r
+\r
+static char* getStringTill(const char* string, const char* terminator, char** retEnd);\r
+\r
+redPathNode* parseRedPath(const char* path)\r
+{\r
+ redPathNode* node;\r
+ redPathNode* endNode;\r
+ char* curPath;\r
+ char* end;\r
+\r
+ if(!path || strlen(path) == 0)\r
+ {\r
+ return NULL;\r
+ }\r
+\r
+ node = (redPathNode*)calloc(1, sizeof(redPathNode));\r
+ if(!node)\r
+ {\r
+ return NULL;\r
+ }\r
+ if(path[0] == '/')\r
+ {\r
+ node->isRoot = true;\r
+ if(path[1] == 'v')\r
+ {\r
+ node->version = getVersion(path+1, &curPath);\r
+ if(curPath == NULL)\r
+ {\r
+ return node;\r
+ }\r
+ if(curPath[0] == '/')\r
+ {\r
+ curPath++;\r
+ }\r
+ node->next = parseRedPath(curPath);\r
+ }\r
+ else\r
+ {\r
+ node->next = parseRedPath(path+1);\r
+ }\r
+ return node;\r
+ }\r
+ node->isRoot = false;\r
+ curPath = getStringTill(path, "/", &end);\r
+ endNode = node;\r
+ parseNode(curPath, node, &endNode);\r
+ free(curPath);\r
+ if(end != NULL)\r
+ {\r
+ endNode->next = parseRedPath(end+1);\r
+ }\r
+ return node;\r
+}\r
+\r
+void cleanupRedPath(redPathNode* node)\r
+{\r
+ if(!node)\r
+ {\r
+ return;\r
+ }\r
+ cleanupRedPath(node->next);\r
+ node->next = NULL;\r
+ if(node->version)\r
+ {\r
+ free(node->version);\r
+ }\r
+ if(node->nodeName)\r
+ {\r
+ free(node->nodeName);\r
+ }\r
+ if(node->op)\r
+ {\r
+ free(node->op);\r
+ }\r
+ if(node->propName)\r
+ {\r
+ free(node->propName);\r
+ }\r
+ if(node->value)\r
+ {\r
+ free(node->value);\r
+ }\r
+ free(node);\r
+}\r
+\r
+static char* getVersion(const char* path, char** end)\r
+{\r
+ return getStringTill(path, "/", end);\r
+}\r
+\r
+static void parseNode(const char* path, redPathNode* node, redPathNode** end)\r
+{\r
+ char* indexStart;\r
+ char* index;\r
+ char* indexEnd;\r
+ char* nodeName = getStringTill(path, "[", &indexStart);\r
+ size_t tmpIndex;\r
+ char* opChars;\r
+\r
+ node->nodeName = nodeName;\r
+ if(indexStart == NULL)\r
+ {\r
+ *end = node;\r
+ return;\r
+ }\r
+ node->next = (redPathNode*)calloc(1, sizeof(redPathNode));\r
+ if(!node->next)\r
+ {\r
+ return;\r
+ }\r
+ //Skip past [\r
+ indexStart++;\r
+ *end = node->next;\r
+ index = getStringTill(indexStart, "]", NULL);\r
+ tmpIndex = (size_t)strtoull(index, &indexEnd, 0);\r
+ if(indexEnd != index)\r
+ {\r
+ free(index);\r
+ node->next->index = tmpIndex;\r
+ node->next->isIndex = true;\r
+ return;\r
+ }\r
+ opChars = strpbrk(index, "<>=~");\r
+ if(opChars == NULL)\r
+ {\r
+ //TODO handle last() and position()\r
+ node->next->op = strdup("exists");\r
+ node->next->propName = index;\r
+ return;\r
+ }\r
+ node->next->propName = (char*)malloc((opChars - index)+1);\r
+ memcpy(node->next->propName, index, (opChars - index));\r
+ node->next->propName[(opChars - index)] = 0;\r
+\r
+ tmpIndex = 1;\r
+ while(1)\r
+ {\r
+ if(opChars[tmpIndex] == '=' || opChars[tmpIndex] == '<' || opChars[tmpIndex] == '>' || opChars[tmpIndex] == '~')\r
+ {\r
+ tmpIndex++;\r
+ continue;\r
+ }\r
+ break;\r
+ }\r
+\r
+ node->next->op = (char*)malloc(tmpIndex+1);\r
+ memcpy(node->next->op, opChars, tmpIndex);\r
+ node->next->op[tmpIndex] = 0;\r
+\r
+ node->next->value = strdup(opChars+tmpIndex);\r
+ free(index);\r
+}\r
+\r
+static char* getStringTill(const char* string, const char* terminator, char** retEnd)\r
+{\r
+ char* ret;\r
+ char* end;\r
+ end = strstr((char*)string, terminator);\r
+ if(retEnd)\r
+ {\r
+ *retEnd = end;\r
+ }\r
+ if(end == NULL)\r
+ {\r
+ //No terminator\r
+ return strdup(string);\r
+ }\r
+ ret = (char*)malloc((end-string)+1);\r
+ memcpy(ret, string, (end-string));\r
+ ret[(end-string)] = 0;\r
+ return ret;\r
+}\r
--- /dev/null
+/** @file\r
+ This file is cloned from DMTF libredfish library tag v1.0.0 and maintained\r
+ by EDKII.\r
+\r
+//----------------------------------------------------------------------------\r
+// Copyright Notice:\r
+// Copyright 2017 Distributed Management Task Force, Inc. All rights reserved.\r
+// License: BSD 3-Clause License. For full text see link: https://github.com/DMTF/libredfish/LICENSE.md\r
+//----------------------------------------------------------------------------\r
+\r
+ Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>\r
+ (C) Copyright 2021 Hewlett Packard Enterprise Development LP<BR>\r
+\r
+ SPDX-License-Identifier: BSD-2-Clause-Patent\r
+\r
+**/\r
+\r
+#include <redfishService.h>\r
+#include <redfishPayload.h>\r
+#include <redpath.h>\r
+\r
+static int initRest(redfishService* service, void * restProtocol);\r
+static redfishService* createServiceEnumeratorNoAuth(const char* host, const char* rootUri, bool enumerate, unsigned int flags, void * restProtocol);\r
+static redfishService* createServiceEnumeratorBasicAuth(const char* host, const char* rootUri, const char* username, const char* password, unsigned int flags, void * restProtocol);\r
+static redfishService* createServiceEnumeratorSessionAuth(const char* host, const char* rootUri, const char* username, const char* password, unsigned int flags, void * restProtocol);\r
+static char* makeUrlForService(redfishService* service, const char* uri);\r
+static json_t* getVersions(redfishService* service, const char* rootUri);\r
+static void addStringToJsonObject(json_t* object, const char* key, const char* value);\r
+\r
+CHAR16*\r
+C8ToC16 (CHAR8 *AsciiStr)\r
+{\r
+ CHAR16 *Str;\r
+ UINTN BufLen;\r
+\r
+ BufLen = (AsciiStrLen (AsciiStr) + 1) * 2;\r
+ Str = AllocatePool (BufLen);\r
+ ASSERT (Str != NULL);\r
+\r
+ AsciiStrToUnicodeStrS (AsciiStr, Str, AsciiStrLen (AsciiStr) + 1);\r
+\r
+ return Str;\r
+}\r
+\r
+VOID\r
+RestConfigFreeHttpRequestData (\r
+ IN EFI_HTTP_REQUEST_DATA *RequestData\r
+ )\r
+{\r
+ if (RequestData == NULL) {\r
+ return ;\r
+ }\r
+\r
+ if (RequestData->Url != NULL) {\r
+ FreePool (RequestData->Url);\r
+ }\r
+\r
+ FreePool (RequestData);\r
+}\r
+\r
+VOID\r
+RestConfigFreeHttpMessage (\r
+ IN EFI_HTTP_MESSAGE *Message,\r
+ IN BOOLEAN IsRequest\r
+ )\r
+{\r
+ if (Message == NULL) {\r
+ return ;\r
+ }\r
+\r
+ if (IsRequest) {\r
+ RestConfigFreeHttpRequestData (Message->Data.Request);\r
+ Message->Data.Request = NULL;\r
+ } else {\r
+ if (Message->Data.Response != NULL) {\r
+ FreePool (Message->Data.Response);\r
+ Message->Data.Response = NULL;\r
+ }\r
+ }\r
+\r
+ if (Message->Headers != NULL) {\r
+ FreePool (Message->Headers);\r
+ Message->Headers = NULL;\r
+ }\r
+ if (Message->Body != NULL) {\r
+ FreePool (Message->Body);\r
+ Message->Body = NULL;\r
+ }\r
+}\r
+\r
+/**\r
+ Converts the Unicode string to ASCII string to a new allocated buffer.\r
+\r
+ @param[in] String Unicode string to be converted.\r
+\r
+ @return Buffer points to ASCII string, or NULL if error happens.\r
+\r
+**/\r
+\r
+CHAR8 *\r
+UnicodeStrDupToAsciiStr (\r
+ CONST CHAR16 *String\r
+ )\r
+{\r
+ CHAR8 *AsciiStr;\r
+ UINTN BufLen;\r
+ EFI_STATUS Status;\r
+\r
+ BufLen = StrLen (String) + 1;\r
+ AsciiStr = AllocatePool (BufLen);\r
+ if (AsciiStr == NULL) {\r
+ return NULL;\r
+ }\r
+\r
+ Status = UnicodeStrToAsciiStrS (String, AsciiStr, BufLen);\r
+ if (EFI_ERROR (Status)) {\r
+ return NULL;\r
+ }\r
+\r
+ return AsciiStr;\r
+}\r
+/**\r
+ This function encodes the content.\r
+\r
+ @param[in] ContentEncodedValue HTTP conent encoded value.\r
+ @param[in] OriginalContent Original content.\r
+ @param[out] EncodedContent Pointer to receive encoded content.\r
+ @param[out] EncodedContentLength Length of encoded content.\r
+\r
+ @retval EFI_SUCCESS Content encoded successfully.\r
+ @retval EFI_UNSUPPORTED No source encoding funciton,\r
+ @retval EFI_INVALID_PARAMETER One of the given parameter is invalid.\r
+\r
+**/\r
+EFI_STATUS\r
+EncodeRequestContent (\r
+ IN CHAR8 *ContentEncodedValue,\r
+ IN CHAR8 *OriginalContent,\r
+ OUT VOID **EncodedContent,\r
+ OUT UINTN *EncodedContentLength\r
+)\r
+{\r
+ EFI_STATUS Status;\r
+ VOID *EncodedPointer;\r
+ UINTN EncodedLength;\r
+\r
+ if (OriginalContent == NULL || EncodedContent == NULL || EncodedContentLength == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+ Status = RedfishContentEncode (\r
+ ContentEncodedValue,\r
+ OriginalContent,\r
+ AsciiStrLen (OriginalContent),\r
+ &EncodedPointer,\r
+ &EncodedLength\r
+ );\r
+ if (Status == EFI_SUCCESS) {\r
+ *EncodedContent = EncodedPointer;\r
+ *EncodedContentLength = EncodedLength;\r
+ return EFI_SUCCESS;\r
+ }\r
+ return Status;\r
+}\r
+\r
+/**\r
+ This function decodes the content. The Memory block pointed by\r
+ ContentPointer would be freed and replaced with the cooked Redfish\r
+ payload.\r
+\r
+ @param[in] ContentEncodedValue HTTP conent encoded value.\r
+ @param[in, out] ContentPointer Pointer to encoded content.\r
+ Pointer of decoded content when out.\r
+ @param[in, out] ContentLength Pointer to the length of encoded content.\r
+ Length of decoded content when out.\r
+\r
+ @retval EFI_SUCCESS Functinos found.\r
+ @retval EFI_UNSUPPORTED No functions found.\r
+ @retval EFI_INVALID_PARAMETER One of the given parameter is invalid.\r
+\r
+**/\r
+EFI_STATUS\r
+DecodeResponseContent (\r
+ IN CHAR8 *ContentEncodedValue,\r
+ IN OUT VOID **ContentPointer,\r
+ IN OUT UINTN *ContentLength\r
+)\r
+{\r
+ EFI_STATUS Status;\r
+ VOID *DecodedPointer;\r
+ UINTN DecodedLength;\r
+\r
+ if (ContentEncodedValue == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+ Status = RedfishContentDecode (\r
+ ContentEncodedValue,\r
+ *ContentPointer,\r
+ *ContentLength,\r
+ &DecodedPointer,\r
+ &DecodedLength\r
+ );\r
+ if (Status == EFI_SUCCESS) {\r
+ FreePool (*ContentPointer);\r
+ *ContentPointer = DecodedPointer;\r
+ *ContentLength = DecodedLength;\r
+ }\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Create a HTTP URL string for specific Redfish resource.\r
+\r
+ This function build a URL string from the Redfish Host interface record and caller specified\r
+ relative path of the resource.\r
+\r
+ Callers are responsible for freeing the returned string storage pointed by HttpUrl.\r
+\r
+ @param[in] RedfishData Redfish network host interface record.\r
+ @param[in] RelativePath Relative path of a resource.\r
+ @param[out] HttpUrl The pointer to store the returned URL string.\r
+\r
+ @retval EFI_SUCCESS Build the URL string successfully.\r
+ @retval EFI_INVALID_PARAMETER RedfishData or HttpUrl is NULL.\r
+ @retval EFI_OUT_OF_RESOURCES There are not enough memory resources.\r
+\r
+**/\r
+EFI_STATUS\r
+RedfishBuildUrl (\r
+ IN REDFISH_CONFIG_SERVICE_INFORMATION *RedfishConfigServiceInfo,\r
+ IN CHAR16 *RelativePath, OPTIONAL\r
+ OUT CHAR16 **HttpUrl\r
+ )\r
+{\r
+ CHAR16 *Url;\r
+ CHAR16 *UrlHead;\r
+ UINTN UrlLength;\r
+ UINTN PathLen;\r
+\r
+ if ((RedfishConfigServiceInfo == NULL) || (HttpUrl == NULL)) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ //\r
+ // RFC2616: http_URL = "http(s):" "//" host [ ":" port ] [ abs_path [ "?" query ]]\r
+ //\r
+ if (RelativePath == NULL) {\r
+ PathLen = 0;\r
+ } else {\r
+ PathLen = StrLen (RelativePath);\r
+ }\r
+ UrlLength = StrLen (HTTPS_FLAG) + StrLen (REDFISH_FIRST_URL) + 1 + StrLen(RedfishConfigServiceInfo->RedfishServiceLocation) + PathLen;\r
+ Url = AllocateZeroPool (UrlLength * sizeof (CHAR16));\r
+ if (Url == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ UrlHead = Url;\r
+ //\r
+ // Copy "http://" or "https://" according RedfishServiceIpPort.\r
+ //\r
+ if (!RedfishConfigServiceInfo->RedfishServiceUseHttps) {\r
+ StrCpyS (Url, StrLen (HTTPS_FLAG) + 1, HTTP_FLAG);\r
+ Url = Url + StrLen (HTTP_FLAG);\r
+ } else {\r
+ StrCpyS (Url, StrLen (HTTPS_FLAG) + 1, HTTPS_FLAG);\r
+ Url = Url + StrLen (HTTPS_FLAG);\r
+ }\r
+\r
+ StrCpyS (Url, StrLen (RedfishConfigServiceInfo->RedfishServiceLocation) + 1, RedfishConfigServiceInfo->RedfishServiceLocation);\r
+ Url = Url + StrLen (RedfishConfigServiceInfo->RedfishServiceLocation);\r
+\r
+ //\r
+ // Copy abs_path\r
+ //\r
+ if (RelativePath != NULL && PathLen != 0 ) {\r
+ StrnCpyS (Url, UrlLength, RelativePath, PathLen);\r
+ }\r
+ *HttpUrl = UrlHead;\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+redfishService* createServiceEnumerator(REDFISH_CONFIG_SERVICE_INFORMATION *RedfishConfigServiceInfo, const char* rootUri, enumeratorAuthentication* auth, unsigned int flags)\r
+{\r
+ EFI_STATUS Status;\r
+ CHAR16 *HttpUrl;\r
+ CHAR8 *AsciiHost;\r
+ EFI_REST_EX_PROTOCOL *RestEx;\r
+ redfishService *ret;\r
+\r
+ HttpUrl = NULL;\r
+ AsciiHost = NULL;\r
+ RestEx = NULL;\r
+ ret = NULL;\r
+\r
+ if (RedfishConfigServiceInfo->RedfishServiceRestExHandle == NULL) {\r
+ goto ON_EXIT;\r
+ }\r
+ Status = RedfishBuildUrl(RedfishConfigServiceInfo, NULL, &HttpUrl);\r
+ if (EFI_ERROR (Status)) {\r
+ goto ON_EXIT;\r
+ }\r
+\r
+ ASSERT (HttpUrl != NULL);\r
+\r
+ AsciiHost = UnicodeStrDupToAsciiStr (HttpUrl);\r
+ if (AsciiHost == NULL) {\r
+ goto ON_EXIT;\r
+ }\r
+\r
+ Status = gBS->HandleProtocol (\r
+ RedfishConfigServiceInfo->RedfishServiceRestExHandle,\r
+ &gEfiRestExProtocolGuid,\r
+ (VOID **)&RestEx\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ goto ON_EXIT;\r
+ }\r
+ if(auth == NULL) {\r
+ ret = createServiceEnumeratorNoAuth(AsciiHost, rootUri, true, flags, RestEx);\r
+ } else if(auth->authType == REDFISH_AUTH_BASIC) {\r
+ ret = createServiceEnumeratorBasicAuth(AsciiHost, rootUri, auth->authCodes.userPass.username, auth->authCodes.userPass.password, flags, RestEx);\r
+ } else if(auth->authType == REDFISH_AUTH_SESSION) {\r
+ ret = createServiceEnumeratorSessionAuth(AsciiHost, rootUri, auth->authCodes.userPass.username, auth->authCodes.userPass.password, flags, RestEx);\r
+ } else {\r
+ goto ON_EXIT;\r
+ }\r
+\r
+ ret->RestEx = RestEx;\r
+ON_EXIT:\r
+ if (HttpUrl != NULL) {\r
+ FreePool (HttpUrl);\r
+ }\r
+\r
+ if (AsciiHost != NULL) {\r
+ FreePool (AsciiHost);\r
+ }\r
+\r
+ return ret;\r
+}\r
+\r
+json_t* getUriFromService(redfishService* service, const char* uri, EFI_HTTP_STATUS_CODE** StatusCode)\r
+{\r
+ char* url;\r
+ json_t* ret;\r
+ HTTP_IO_HEADER *HttpIoHeader = NULL;\r
+ EFI_STATUS Status;\r
+ EFI_HTTP_REQUEST_DATA *RequestData = NULL;\r
+ EFI_HTTP_MESSAGE *RequestMsg = NULL;\r
+ EFI_HTTP_MESSAGE ResponseMsg;\r
+ EFI_HTTP_HEADER *ContentEncodedHeader;\r
+\r
+ if(service == NULL || uri == NULL || StatusCode == NULL)\r
+ {\r
+ return NULL;\r
+ }\r
+\r
+ *StatusCode = NULL;\r
+\r
+ url = makeUrlForService(service, uri);\r
+ if(!url)\r
+ {\r
+ return NULL;\r
+ }\r
+\r
+ DEBUG((DEBUG_INFO, "libredfish: getUriFromService(): %a\n", url));\r
+\r
+ //\r
+ // Step 1: Create HTTP request message with 4 headers:\r
+ //\r
+ HttpIoHeader = HttpIoCreateHeader ((service->sessionToken || service->basicAuthStr) ? 6 : 5);\r
+ if (HttpIoHeader == NULL) {\r
+ ret = NULL;\r
+ goto ON_EXIT;\r
+ }\r
+\r
+ if(service->sessionToken)\r
+ {\r
+ Status = HttpIoSetHeader (HttpIoHeader, "X-Auth-Token", service->sessionToken);\r
+ ASSERT_EFI_ERROR (Status);\r
+ } else if (service->basicAuthStr) {\r
+ Status = HttpIoSetHeader (HttpIoHeader, "Authorization", service->basicAuthStr);\r
+ ASSERT_EFI_ERROR (Status);\r
+ }\r
+\r
+ Status = HttpIoSetHeader (HttpIoHeader, "Host", service->HostHeaderValue);\r
+ ASSERT_EFI_ERROR (Status);\r
+ Status = HttpIoSetHeader (HttpIoHeader, "OData-Version", "4.0");\r
+ ASSERT_EFI_ERROR (Status);\r
+ Status = HttpIoSetHeader (HttpIoHeader, "Accept", "application/json");\r
+ ASSERT_EFI_ERROR (Status);\r
+ Status = HttpIoSetHeader (HttpIoHeader, "User-Agent", "libredfish");\r
+ ASSERT_EFI_ERROR (Status);\r
+ Status = HttpIoSetHeader (HttpIoHeader, "Connection", "Keep-Alive");\r
+ ASSERT_EFI_ERROR (Status);\r
+\r
+ //\r
+ // Step 2: build the rest of HTTP request info.\r
+ //\r
+ RequestData = AllocateZeroPool (sizeof (EFI_HTTP_REQUEST_DATA));\r
+ if (RequestData == NULL) {\r
+ ret = NULL;\r
+ goto ON_EXIT;\r
+ }\r
+\r
+ RequestData->Method = HttpMethodGet;\r
+ RequestData->Url = C8ToC16 (url);\r
+\r
+ //\r
+ // Step 3: fill in EFI_HTTP_MESSAGE\r
+ //\r
+ RequestMsg = AllocateZeroPool (sizeof (EFI_HTTP_MESSAGE));\r
+ if (RequestMsg == NULL) {\r
+ ret = NULL;\r
+ goto ON_EXIT;\r
+ }\r
+\r
+ RequestMsg->Data.Request = RequestData;\r
+ RequestMsg->HeaderCount = HttpIoHeader->HeaderCount;\r
+ RequestMsg->Headers = HttpIoHeader->Headers;\r
+\r
+ ZeroMem (&ResponseMsg, sizeof (ResponseMsg));\r
+\r
+ //\r
+ // Step 4: call RESTEx to get response from REST service.\r
+ //\r
+ Status = service->RestEx->SendReceive (service->RestEx, RequestMsg, &ResponseMsg);\r
+ if (EFI_ERROR (Status)) {\r
+ ret = NULL;\r
+ goto ON_EXIT;\r
+ }\r
+\r
+ //\r
+ // Step 5: Return the HTTP StatusCode and Body message.\r
+ //\r
+ if (ResponseMsg.Data.Response != NULL) {\r
+ *StatusCode = AllocateZeroPool (sizeof (EFI_HTTP_STATUS_CODE));\r
+ if (*StatusCode == NULL) {\r
+ ret = NULL;\r
+ goto ON_EXIT;\r
+ }\r
+\r
+ //\r
+ // The caller shall take the responsibility to free the buffer.\r
+ //\r
+ **StatusCode = ResponseMsg.Data.Response->StatusCode;\r
+ }\r
+\r
+ if (ResponseMsg.BodyLength != 0 && ResponseMsg.Body != NULL) {\r
+ //\r
+ // Check if data is encoded.\r
+ //\r
+ ContentEncodedHeader = HttpFindHeader (ResponseMsg.HeaderCount, ResponseMsg.Headers, HTTP_HEADER_CONTENT_ENCODING);\r
+ if (ContentEncodedHeader != NULL) {\r
+ //\r
+ // The content is encoded.\r
+ //\r
+ Status = DecodeResponseContent (ContentEncodedHeader->FieldValue, &ResponseMsg.Body, &ResponseMsg.BodyLength);\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((DEBUG_ERROR, "%a: Failed to decompress the response content %r\n.", __FUNCTION__, Status));\r
+ ret = NULL;\r
+ goto ON_EXIT;\r
+ }\r
+ }\r
+ ret = json_loadb (ResponseMsg.Body, ResponseMsg.BodyLength, 0, NULL);\r
+ } else {\r
+ //\r
+ // There is no message body returned from server.\r
+ //\r
+ ret = NULL;\r
+ }\r
+\r
+ON_EXIT:\r
+ if (url != NULL) {\r
+ free (url);\r
+ }\r
+\r
+ if (HttpIoHeader != NULL) {\r
+ HttpIoFreeHeader (HttpIoHeader);\r
+ }\r
+\r
+ if (RequestData != NULL) {\r
+ RestConfigFreeHttpRequestData (RequestData);\r
+ }\r
+\r
+ if (RequestMsg != NULL) {\r
+ FreePool (RequestMsg);\r
+ }\r
+\r
+ RestConfigFreeHttpMessage (&ResponseMsg, FALSE);\r
+\r
+ return ret;\r
+}\r
+\r
+json_t* patchUriFromService(redfishService* service, const char* uri, const char* content, EFI_HTTP_STATUS_CODE** StatusCode)\r
+{\r
+ char* url;\r
+ json_t* ret;\r
+ HTTP_IO_HEADER *HttpIoHeader = NULL;\r
+ EFI_STATUS Status;\r
+ EFI_HTTP_REQUEST_DATA *RequestData = NULL;\r
+ EFI_HTTP_MESSAGE *RequestMsg = NULL;\r
+ EFI_HTTP_MESSAGE ResponseMsg;\r
+ CHAR8 ContentLengthStr[80];\r
+ CHAR8 *EncodedContent;\r
+ UINTN EncodedContentLen;\r
+\r
+ if(service == NULL || uri == NULL || content == NULL || StatusCode == NULL)\r
+ {\r
+ return NULL;\r
+ }\r
+\r
+ *StatusCode = NULL;\r
+\r
+ url = makeUrlForService(service, uri);\r
+ if(!url)\r
+ {\r
+ return NULL;\r
+ }\r
+\r
+ DEBUG((DEBUG_INFO, "libredfish: patchUriFromService(): %a\n", url));\r
+\r
+ //\r
+ // Step 1: Create HTTP request message with 4 headers:\r
+ //\r
+ HttpIoHeader = HttpIoCreateHeader ((service->sessionToken || service->basicAuthStr) ? 9 : 8);\r
+ if (HttpIoHeader == NULL) {\r
+ ret = NULL;\r
+ goto ON_EXIT;\r
+ }\r
+\r
+ if(service->sessionToken)\r
+ {\r
+ Status = HttpIoSetHeader (HttpIoHeader, "X-Auth-Token", service->sessionToken);\r
+ ASSERT_EFI_ERROR (Status);\r
+ } else if (service->basicAuthStr) {\r
+ Status = HttpIoSetHeader (HttpIoHeader, "Authorization", service->basicAuthStr);\r
+ ASSERT_EFI_ERROR (Status);\r
+ }\r
+\r
+ Status = HttpIoSetHeader (HttpIoHeader, "Host", service->HostHeaderValue);\r
+ ASSERT_EFI_ERROR (Status);\r
+ Status = HttpIoSetHeader (HttpIoHeader, "Content-Type", "application/json");\r
+ ASSERT_EFI_ERROR (Status);\r
+ Status = HttpIoSetHeader (HttpIoHeader, "Accept", "application/json");\r
+ ASSERT_EFI_ERROR (Status);\r
+ Status = HttpIoSetHeader (HttpIoHeader, "User-Agent", "libredfish");\r
+ ASSERT_EFI_ERROR (Status);\r
+ Status = HttpIoSetHeader (HttpIoHeader, "Connection", "Keep-Alive");\r
+ ASSERT_EFI_ERROR (Status);\r
+\r
+ AsciiSPrint(\r
+ ContentLengthStr,\r
+ sizeof (ContentLengthStr),\r
+ "%lu",\r
+ (UINT64) strlen(content)\r
+ );\r
+ Status = HttpIoSetHeader (HttpIoHeader, "Content-Length", ContentLengthStr);\r
+ ASSERT_EFI_ERROR (Status);\r
+ Status = HttpIoSetHeader (HttpIoHeader, "OData-Version", "4.0");\r
+ ASSERT_EFI_ERROR (Status);\r
+\r
+ //\r
+ // Step 2: build the rest of HTTP request info.\r
+ //\r
+ RequestData = AllocateZeroPool (sizeof (EFI_HTTP_REQUEST_DATA));\r
+ if (RequestData == NULL) {\r
+ ret = NULL;\r
+ goto ON_EXIT;\r
+ }\r
+\r
+ RequestData->Method = HttpMethodPatch;\r
+ RequestData->Url = C8ToC16 (url);\r
+\r
+ //\r
+ // Step 3: fill in EFI_HTTP_MESSAGE\r
+ //\r
+ RequestMsg = AllocateZeroPool (sizeof (EFI_HTTP_MESSAGE));\r
+ if (RequestMsg == NULL) {\r
+ ret = NULL;\r
+ goto ON_EXIT;\r
+ }\r
+\r
+ EncodedContent = (CHAR8 *)content;\r
+ EncodedContentLen = strlen(content);\r
+ //\r
+ // We currently only support gzip Content-Encoding.\r
+ //\r
+ Status = EncodeRequestContent ((CHAR8 *)HTTP_CONTENT_ENCODING_GZIP, (CHAR8 *)content, (VOID **)&EncodedContent, &EncodedContentLen);\r
+ if (Status == EFI_INVALID_PARAMETER) {\r
+ DEBUG((DEBUG_ERROR, "%a: Error to encode content.\n", __FUNCTION__));\r
+ ret = NULL;\r
+ goto ON_EXIT;\r
+ } else if (Status == EFI_UNSUPPORTED) {\r
+ DEBUG((DEBUG_INFO, "No content coding for %a! Use raw data instead.\n", HTTP_CONTENT_ENCODING_GZIP));\r
+ Status = HttpIoSetHeader (HttpIoHeader, "Content-Encoding", HTTP_CONTENT_ENCODING_IDENTITY);\r
+ ASSERT_EFI_ERROR (Status);\r
+ } else {\r
+ Status = HttpIoSetHeader (HttpIoHeader, "Content-Encoding", HTTP_CONTENT_ENCODING_GZIP);\r
+ ASSERT_EFI_ERROR (Status);\r
+ }\r
+\r
+ RequestMsg->Data.Request = RequestData;\r
+ RequestMsg->HeaderCount = HttpIoHeader->HeaderCount;\r
+ RequestMsg->Headers = HttpIoHeader->Headers;\r
+ RequestMsg->BodyLength = EncodedContentLen;\r
+ RequestMsg->Body = (VOID*) EncodedContent;\r
+\r
+ ZeroMem (&ResponseMsg, sizeof (ResponseMsg));\r
+\r
+ //\r
+ // Step 4: call RESTEx to get response from REST service.\r
+ //\r
+ Status = service->RestEx->SendReceive (service->RestEx, RequestMsg, &ResponseMsg);\r
+ if (EFI_ERROR (Status)) {\r
+ ret = NULL;\r
+ goto ON_EXIT;\r
+ }\r
+\r
+ //\r
+ // Step 5: Return the HTTP StatusCode and Body message.\r
+ //\r
+ if (ResponseMsg.Data.Response != NULL) {\r
+ *StatusCode = AllocateZeroPool (sizeof (EFI_HTTP_STATUS_CODE));\r
+ if (*StatusCode == NULL) {\r
+ ret = NULL;\r
+ goto ON_EXIT;\r
+ }\r
+\r
+ //\r
+ // The caller shall take the responsibility to free the buffer.\r
+ //\r
+ **StatusCode = ResponseMsg.Data.Response->StatusCode;\r
+ }\r
+\r
+ if (EncodedContent != content) {\r
+ FreePool (EncodedContent);\r
+ }\r
+\r
+\r
+ if (ResponseMsg.BodyLength != 0 && ResponseMsg.Body != NULL) {\r
+ ret = json_loadb (ResponseMsg.Body, ResponseMsg.BodyLength, 0, NULL);\r
+ } else {\r
+ //\r
+ // There is no message body returned from server.\r
+ //\r
+ ret = NULL;\r
+ }\r
+\r
+ON_EXIT:\r
+ if (url != NULL) {\r
+ free (url);\r
+ }\r
+\r
+ if (HttpIoHeader != NULL) {\r
+ HttpIoFreeHeader (HttpIoHeader);\r
+ }\r
+\r
+ if (RequestData != NULL) {\r
+ RestConfigFreeHttpRequestData (RequestData);\r
+ }\r
+\r
+ if (RequestMsg != NULL) {\r
+ FreePool (RequestMsg);\r
+ }\r
+\r
+ RestConfigFreeHttpMessage (&ResponseMsg, FALSE);\r
+\r
+ return ret;\r
+}\r
+\r
+json_t* postUriFromService(redfishService* service, const char* uri, const char* content, size_t contentLength, const char* contentType, EFI_HTTP_STATUS_CODE** StatusCode)\r
+{\r
+ char* url = NULL;\r
+ json_t* ret;\r
+ HTTP_IO_HEADER *HttpIoHeader = NULL;\r
+ EFI_STATUS Status;\r
+ EFI_HTTP_REQUEST_DATA *RequestData = NULL;\r
+ EFI_HTTP_MESSAGE *RequestMsg = NULL;\r
+ EFI_HTTP_MESSAGE ResponseMsg;\r
+ CHAR8 ContentLengthStr[80];\r
+ EFI_HTTP_HEADER *HttpHeader = NULL;\r
+\r
+ ret = NULL;\r
+\r
+ if(service == NULL || uri == NULL || content == NULL || StatusCode == NULL)\r
+ {\r
+ return NULL;\r
+ }\r
+\r
+ *StatusCode = NULL;\r
+\r
+ url = makeUrlForService(service, uri);\r
+ if(!url)\r
+ {\r
+ return NULL;\r
+ }\r
+\r
+ DEBUG((DEBUG_INFO, "libredfish: postUriFromService(): %a\n", url));\r
+\r
+ if(contentLength == 0)\r
+ {\r
+ contentLength = strlen(content);\r
+ }\r
+\r
+ //\r
+ // Step 1: Create HTTP request message with 4 headers:\r
+ //\r
+ HttpIoHeader = HttpIoCreateHeader ((service->sessionToken || service->basicAuthStr) ? 8 : 7);\r
+ if (HttpIoHeader == NULL) {\r
+ goto ON_EXIT;\r
+ }\r
+\r
+ if(service->sessionToken)\r
+ {\r
+ Status = HttpIoSetHeader (HttpIoHeader, "X-Auth-Token", service->sessionToken);\r
+ ASSERT_EFI_ERROR (Status);\r
+ } else if (service->basicAuthStr) {\r
+ Status = HttpIoSetHeader (HttpIoHeader, "Authorization", service->basicAuthStr);\r
+ ASSERT_EFI_ERROR (Status);\r
+ }\r
+\r
+ if(contentType == NULL) {\r
+ Status = HttpIoSetHeader (HttpIoHeader, "Content-Type", "application/json");\r
+ ASSERT_EFI_ERROR (Status);\r
+ } else {\r
+ Status = HttpIoSetHeader (HttpIoHeader, "Content-Type", (CHAR8 *) contentType);\r
+ ASSERT_EFI_ERROR (Status);\r
+ }\r
+ Status = HttpIoSetHeader (HttpIoHeader, "Host", service->HostHeaderValue);\r
+ ASSERT_EFI_ERROR (Status);\r
+ Status = HttpIoSetHeader (HttpIoHeader, "Accept", "application/json");\r
+ ASSERT_EFI_ERROR (Status);\r
+ Status = HttpIoSetHeader (HttpIoHeader, "User-Agent", "libredfish");\r
+ ASSERT_EFI_ERROR (Status);\r
+ Status = HttpIoSetHeader (HttpIoHeader, "Connection", "Keep-Alive");\r
+ ASSERT_EFI_ERROR (Status);\r
+ AsciiSPrint(\r
+ ContentLengthStr,\r
+ sizeof (ContentLengthStr),\r
+ "%lu",\r
+ (UINT64) contentLength\r
+ );\r
+ Status = HttpIoSetHeader (HttpIoHeader, "Content-Length", ContentLengthStr);\r
+ ASSERT_EFI_ERROR (Status);\r
+ Status = HttpIoSetHeader (HttpIoHeader, "OData-Version", "4.0");\r
+ ASSERT_EFI_ERROR (Status);\r
+\r
+ //\r
+ // Step 2: build the rest of HTTP request info.\r
+ //\r
+ RequestData = AllocateZeroPool (sizeof (EFI_HTTP_REQUEST_DATA));\r
+ if (RequestData == NULL) {\r
+ goto ON_EXIT;\r
+ }\r
+\r
+ RequestData->Method = HttpMethodPost;\r
+ RequestData->Url = C8ToC16 (url);\r
+\r
+ //\r
+ // Step 3: fill in EFI_HTTP_MESSAGE\r
+ //\r
+ RequestMsg = AllocateZeroPool (sizeof (EFI_HTTP_MESSAGE));\r
+ if (RequestMsg == NULL) {\r
+ goto ON_EXIT;\r
+ }\r
+\r
+ RequestMsg->Data.Request = RequestData;\r
+ RequestMsg->HeaderCount = HttpIoHeader->HeaderCount;\r
+ RequestMsg->Headers = HttpIoHeader->Headers;\r
+ RequestMsg->BodyLength = contentLength;\r
+ RequestMsg->Body = (VOID*) content;\r
+\r
+ ZeroMem (&ResponseMsg, sizeof (ResponseMsg));\r
+\r
+ //\r
+ // Step 4: call RESTEx to get response from REST service.\r
+ //\r
+ Status = service->RestEx->SendReceive (service->RestEx, RequestMsg, &ResponseMsg);\r
+ if (EFI_ERROR (Status)) {\r
+ goto ON_EXIT;\r
+ }\r
+\r
+ //\r
+ // Step 5: Return the HTTP StatusCode and Body message.\r
+ //\r
+ if (ResponseMsg.Data.Response != NULL) {\r
+ *StatusCode = AllocateZeroPool (sizeof (EFI_HTTP_STATUS_CODE));\r
+ if (*StatusCode == NULL) {\r
+ goto ON_EXIT;\r
+ }\r
+\r
+ //\r
+ // The caller shall take the responsibility to free the buffer.\r
+ //\r
+ **StatusCode = ResponseMsg.Data.Response->StatusCode;\r
+ }\r
+\r
+ if (ResponseMsg.BodyLength != 0 && ResponseMsg.Body != NULL) {\r
+ ret = json_loadb (ResponseMsg.Body, ResponseMsg.BodyLength, 0, NULL);\r
+ }\r
+\r
+ //\r
+ // Step 6: Parsing the HttpHeader to retrive the X-Auth-Token if the HTTP StatusCode is correct.\r
+ //\r
+ if (ResponseMsg.Data.Response->StatusCode == HTTP_STATUS_200_OK ||\r
+ ResponseMsg.Data.Response->StatusCode == HTTP_STATUS_204_NO_CONTENT) {\r
+ HttpHeader = HttpFindHeader (ResponseMsg.HeaderCount, ResponseMsg.Headers, "X-Auth-Token");\r
+ if (HttpHeader != NULL) {\r
+ if(service->sessionToken)\r
+ {\r
+ free(service->sessionToken);\r
+ }\r
+ service->sessionToken = AllocateCopyPool (AsciiStrSize (HttpHeader->FieldValue), HttpHeader->FieldValue);\r
+ }\r
+\r
+ /*\r
+ //\r
+ // Below opeation seems to be unnecessary.\r
+ // 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
+ // parameter of getUriFromService () directly.\r
+ //\r
+ HttpHeader = HttpFindHeader (ResponseMsg.HeaderCount, ResponseMsg.Headers, "Location");\r
+ if (HttpHeader != NULL) {\r
+ ret = getUriFromService(service, HttpHeader->FieldValue);\r
+ goto ON_EXIT;\r
+ }\r
+ */\r
+ }\r
+\r
+ON_EXIT:\r
+ if (url != NULL) {\r
+ free (url);\r
+ }\r
+\r
+ if (HttpIoHeader != NULL) {\r
+ HttpIoFreeHeader (HttpIoHeader);\r
+ }\r
+\r
+ if (RequestData != NULL) {\r
+ RestConfigFreeHttpRequestData (RequestData);\r
+ }\r
+\r
+ if (RequestMsg != NULL) {\r
+ FreePool (RequestMsg);\r
+ }\r
+\r
+ RestConfigFreeHttpMessage (&ResponseMsg, FALSE);\r
+\r
+ return ret;\r
+}\r
+\r
+json_t* deleteUriFromService(redfishService* service, const char* uri, EFI_HTTP_STATUS_CODE** StatusCode)\r
+{\r
+ char* url;\r
+ json_t* ret;\r
+ HTTP_IO_HEADER *HttpIoHeader = NULL;\r
+ EFI_STATUS Status;\r
+ EFI_HTTP_REQUEST_DATA *RequestData = NULL;\r
+ EFI_HTTP_MESSAGE *RequestMsg = NULL;\r
+ EFI_HTTP_MESSAGE ResponseMsg;\r
+\r
+ ret = NULL;\r
+\r
+ if(service == NULL || uri == NULL || StatusCode == NULL)\r
+ {\r
+ return NULL;\r
+ }\r
+\r
+ *StatusCode = NULL;\r
+\r
+ url = makeUrlForService(service, uri);\r
+ if(!url)\r
+ {\r
+ return NULL;\r
+ }\r
+\r
+ DEBUG((DEBUG_INFO, "libredfish: deleteUriFromService(): %a\n", url));\r
+\r
+ //\r
+ // Step 1: Create HTTP request message with 4 headers:\r
+ //\r
+ HttpIoHeader = HttpIoCreateHeader ((service->sessionToken || service->basicAuthStr) ? 5 : 4);\r
+ if (HttpIoHeader == NULL) {\r
+ ret = NULL;\r
+ goto ON_EXIT;\r
+ }\r
+\r
+ if(service->sessionToken)\r
+ {\r
+ Status = HttpIoSetHeader (HttpIoHeader, "X-Auth-Token", service->sessionToken);\r
+ ASSERT_EFI_ERROR (Status);\r
+ } else if (service->basicAuthStr) {\r
+ Status = HttpIoSetHeader (HttpIoHeader, "Authorization", service->basicAuthStr);\r
+ ASSERT_EFI_ERROR (Status);\r
+ }\r
+ Status = HttpIoSetHeader (HttpIoHeader, "Host", service->HostHeaderValue);\r
+ ASSERT_EFI_ERROR (Status);\r
+ Status = HttpIoSetHeader (HttpIoHeader, "User-Agent", "libredfish");\r
+ ASSERT_EFI_ERROR (Status);\r
+ Status = HttpIoSetHeader (HttpIoHeader, "OData-Version", "4.0");\r
+ ASSERT_EFI_ERROR (Status);\r
+ Status = HttpIoSetHeader (HttpIoHeader, "Connection", "Keep-Alive");\r
+ ASSERT_EFI_ERROR (Status);\r
+\r
+ //\r
+ // Step 2: build the rest of HTTP request info.\r
+ //\r
+ RequestData = AllocateZeroPool (sizeof (EFI_HTTP_REQUEST_DATA));\r
+ if (RequestData == NULL) {\r
+ ret = NULL;\r
+ goto ON_EXIT;\r
+ }\r
+\r
+ RequestData->Method = HttpMethodDelete;\r
+ RequestData->Url = C8ToC16 (url);\r
+\r
+ //\r
+ // Step 3: fill in EFI_HTTP_MESSAGE\r
+ //\r
+ RequestMsg = AllocateZeroPool (sizeof (EFI_HTTP_MESSAGE));\r
+ if (RequestMsg == NULL) {\r
+ ret = NULL;\r
+ goto ON_EXIT;\r
+ }\r
+\r
+ RequestMsg->Data.Request = RequestData;\r
+ RequestMsg->HeaderCount = HttpIoHeader->HeaderCount;\r
+ RequestMsg->Headers = HttpIoHeader->Headers;\r
+\r
+ ZeroMem (&ResponseMsg, sizeof (ResponseMsg));\r
+\r
+ //\r
+ // Step 4: call RESTEx to get response from REST service.\r
+ //\r
+ Status = service->RestEx->SendReceive (service->RestEx, RequestMsg, &ResponseMsg);\r
+ if (EFI_ERROR (Status)) {\r
+ ret = NULL;\r
+ goto ON_EXIT;\r
+ }\r
+\r
+ //\r
+ // Step 5: Return the HTTP StatusCode and Body message.\r
+ //\r
+ if (ResponseMsg.Data.Response != NULL) {\r
+ *StatusCode = AllocateZeroPool (sizeof (EFI_HTTP_STATUS_CODE));\r
+ if (*StatusCode == NULL) {\r
+ ret = NULL;\r
+ goto ON_EXIT;\r
+ }\r
+\r
+ //\r
+ // The caller shall take the responsibility to free the buffer.\r
+ //\r
+ **StatusCode = ResponseMsg.Data.Response->StatusCode;\r
+ }\r
+\r
+ if (ResponseMsg.BodyLength != 0 && ResponseMsg.Body != NULL) {\r
+ ret = json_loadb (ResponseMsg.Body, ResponseMsg.BodyLength, 0, NULL);\r
+ }\r
+\r
+ON_EXIT:\r
+ if (url != NULL) {\r
+ free (url);\r
+ }\r
+\r
+ if (HttpIoHeader != NULL) {\r
+ HttpIoFreeHeader (HttpIoHeader);\r
+ }\r
+\r
+ if (RequestData != NULL) {\r
+ RestConfigFreeHttpRequestData (RequestData);\r
+ }\r
+\r
+ if (RequestMsg != NULL) {\r
+ FreePool (RequestMsg);\r
+ }\r
+\r
+ RestConfigFreeHttpMessage (&ResponseMsg, FALSE);\r
+\r
+ return ret;\r
+}\r
+\r
+redfishPayload* getRedfishServiceRoot(redfishService* service, const char* version, EFI_HTTP_STATUS_CODE** StatusCode)\r
+{\r
+ json_t* value;\r
+ json_t* versionNode;\r
+ const char* verUrl;\r
+\r
+ if(version == NULL)\r
+ {\r
+ versionNode = json_object_get(service->versions, "v1");\r
+ }\r
+ else\r
+ {\r
+ versionNode = json_object_get(service->versions, version);\r
+ }\r
+ if(versionNode == NULL)\r
+ {\r
+ return NULL;\r
+ }\r
+ verUrl = json_string_value(versionNode);\r
+ if(verUrl == NULL)\r
+ {\r
+ return NULL;\r
+ }\r
+ value = getUriFromService(service, verUrl, StatusCode);\r
+ if(value == NULL)\r
+ {\r
+ if((service->flags & REDFISH_FLAG_SERVICE_NO_VERSION_DOC) == 0)\r
+ {\r
+ json_decref(versionNode);\r
+ }\r
+ return NULL;\r
+ }\r
+ return createRedfishPayload(value, service);\r
+}\r
+\r
+redfishPayload* getPayloadByPath(redfishService* service, const char* path, EFI_HTTP_STATUS_CODE** StatusCode)\r
+{\r
+ redPathNode* redpath;\r
+ redfishPayload* root;\r
+ redfishPayload* ret;\r
+\r
+ if(!service || !path || StatusCode == NULL)\r
+ {\r
+ return NULL;\r
+ }\r
+\r
+ *StatusCode = NULL;\r
+\r
+ redpath = parseRedPath(path);\r
+ if(!redpath)\r
+ {\r
+ return NULL;\r
+ }\r
+ if(!redpath->isRoot)\r
+ {\r
+ cleanupRedPath(redpath);\r
+ return NULL;\r
+ }\r
+ root = getRedfishServiceRoot(service, redpath->version, StatusCode);\r
+ if (*StatusCode == NULL || **StatusCode < HTTP_STATUS_200_OK || **StatusCode > HTTP_STATUS_206_PARTIAL_CONTENT) {\r
+ cleanupRedPath(redpath);\r
+ return root;\r
+ }\r
+\r
+ if(redpath->next == NULL)\r
+ {\r
+ cleanupRedPath(redpath);\r
+ return root;\r
+ }\r
+\r
+ FreePool (*StatusCode);\r
+ *StatusCode = NULL;\r
+\r
+ ret = getPayloadForPath(root, redpath->next, StatusCode);\r
+ if (*StatusCode == NULL && ret != NULL) {\r
+ //\r
+ // In such a case, the Redfish resource is parsed from the input payload (root) directly.\r
+ // So, we still return HTTP_STATUS_200_OK.\r
+ //\r
+ *StatusCode = AllocateZeroPool (sizeof (EFI_HTTP_STATUS_CODE));\r
+ if (*StatusCode == NULL) {\r
+ ret = NULL;\r
+ } else {\r
+ **StatusCode = HTTP_STATUS_200_OK;\r
+ }\r
+ }\r
+ cleanupPayload(root);\r
+ cleanupRedPath(redpath);\r
+ return ret;\r
+}\r
+\r
+void cleanupServiceEnumerator(redfishService* service)\r
+{\r
+ if(!service)\r
+ {\r
+ return;\r
+ }\r
+ free(service->host);\r
+ json_decref(service->versions);\r
+ if(service->sessionToken != NULL)\r
+ {\r
+ ZeroMem (service->sessionToken, (UINTN)strlen(service->sessionToken));\r
+ FreePool(service->sessionToken);\r
+ }\r
+ if (service->basicAuthStr != NULL) {\r
+ ZeroMem (service->basicAuthStr, (UINTN)strlen(service->basicAuthStr));\r
+ FreePool (service->basicAuthStr);\r
+ }\r
+ free(service);\r
+}\r
+\r
+static int initRest(redfishService* service, void * restProtocol)\r
+{\r
+ service->RestEx = restProtocol;\r
+ return 0;\r
+}\r
+\r
+static redfishService* createServiceEnumeratorNoAuth(const char* host, const char* rootUri, bool enumerate, unsigned int flags, void * restProtocol)\r
+{\r
+ redfishService* ret;\r
+ char *HostStart;\r
+\r
+ ret = (redfishService*)calloc(1, sizeof(redfishService));\r
+ ZeroMem (ret, sizeof(redfishService));\r
+ if(initRest(ret, restProtocol) != 0)\r
+ {\r
+ free(ret);\r
+ return NULL;\r
+ }\r
+ ret->host = AllocateCopyPool(AsciiStrSize(host), host);\r
+ ret->flags = flags;\r
+ if(enumerate)\r
+ {\r
+ ret->versions = getVersions(ret, rootUri);\r
+ }\r
+ HostStart = strstr (ret->host, "//");\r
+ if (HostStart != NULL && (*(HostStart + 2) != '\0')) {\r
+ ret->HostHeaderValue = HostStart + 2;\r
+ }\r
+\r
+ return ret;\r
+}\r
+\r
+EFI_STATUS\r
+createBasicAuthStr (\r
+ IN redfishService* service,\r
+ IN CONST CHAR8 *UserId,\r
+ IN CONST CHAR8 *Password\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ CHAR8 *RawAuthValue;\r
+ UINTN RawAuthBufSize;\r
+ CHAR8 *EnAuthValue;\r
+ UINTN EnAuthValueSize;\r
+ CHAR8 *BasicWithEnAuthValue;\r
+ UINTN BasicBufSize;\r
+\r
+ EnAuthValue = NULL;\r
+ EnAuthValueSize = 0;\r
+\r
+ RawAuthBufSize = AsciiStrLen (UserId) + AsciiStrLen (Password) + 2;\r
+ RawAuthValue = AllocatePool (RawAuthBufSize);\r
+ if (RawAuthValue == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ //\r
+ // Build raw AuthValue (UserId:Password).\r
+ //\r
+ AsciiSPrint (\r
+ RawAuthValue,\r
+ RawAuthBufSize,\r
+ "%a:%a",\r
+ UserId,\r
+ Password\r
+ );\r
+\r
+ //\r
+ // Encoding RawAuthValue into Base64 format.\r
+ //\r
+ Status = Base64Encode (\r
+ (CONST UINT8 *) RawAuthValue,\r
+ AsciiStrLen (RawAuthValue),\r
+ EnAuthValue,\r
+ &EnAuthValueSize\r
+ );\r
+ if (Status == EFI_BUFFER_TOO_SMALL) {\r
+ EnAuthValue = (CHAR8 *) AllocateZeroPool (EnAuthValueSize);\r
+ if (EnAuthValue == NULL) {\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ return Status;\r
+ }\r
+\r
+ Status = Base64Encode (\r
+ (CONST UINT8 *) RawAuthValue,\r
+ AsciiStrLen (RawAuthValue),\r
+ EnAuthValue,\r
+ &EnAuthValueSize\r
+ );\r
+ }\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ goto Exit;\r
+ }\r
+\r
+ BasicBufSize = AsciiStrLen ("Basic ") + AsciiStrLen(EnAuthValue) + 2;\r
+ BasicWithEnAuthValue = AllocatePool (BasicBufSize);\r
+ if (BasicWithEnAuthValue == NULL) {\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ goto Exit;\r
+ }\r
+\r
+ //\r
+ // Build encoded EnAuthValue with Basic (Basic EnAuthValue).\r
+ //\r
+ AsciiSPrint (\r
+ BasicWithEnAuthValue,\r
+ BasicBufSize,\r
+ "%a %a",\r
+ "Basic",\r
+ EnAuthValue\r
+ );\r
+\r
+ service->basicAuthStr = BasicWithEnAuthValue;\r
+\r
+Exit:\r
+ if (RawAuthValue != NULL) {\r
+ ZeroMem (RawAuthValue, RawAuthBufSize);\r
+ FreePool (RawAuthValue);\r
+ }\r
+\r
+ if (EnAuthValue != NULL) {\r
+ ZeroMem (EnAuthValue, EnAuthValueSize);\r
+ FreePool (EnAuthValue);\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+static redfishService* createServiceEnumeratorBasicAuth(const char* host, const char* rootUri, const char* username, const char* password, unsigned int flags, void * restProtocol)\r
+{\r
+ redfishService* ret;\r
+ EFI_STATUS Status;\r
+\r
+ ret = createServiceEnumeratorNoAuth(host, rootUri, false, flags, restProtocol);\r
+\r
+ // add basic auth str\r
+ Status = createBasicAuthStr (ret, username, password);\r
+ if (EFI_ERROR(Status)) {\r
+ cleanupServiceEnumerator (ret);\r
+ return NULL;\r
+ }\r
+\r
+ ret->versions = getVersions(ret, rootUri);\r
+ return ret;\r
+}\r
+\r
+static redfishService* createServiceEnumeratorSessionAuth(const char* host, const char* rootUri, const char* username, const char* password, unsigned int flags, void * restProtocol)\r
+{\r
+ redfishService* ret;\r
+ redfishPayload* payload;\r
+ redfishPayload* links;\r
+ json_t* sessionPayload;\r
+ json_t* session;\r
+ json_t* odataId;\r
+ const char* uri;\r
+ json_t* post;\r
+ char* content;\r
+ EFI_HTTP_STATUS_CODE *StatusCode;\r
+\r
+ content = NULL;\r
+ StatusCode = NULL;\r
+\r
+ ret = createServiceEnumeratorNoAuth(host, rootUri, true, flags, restProtocol);\r
+ if(ret == NULL)\r
+ {\r
+ return NULL;\r
+ }\r
+ payload = getRedfishServiceRoot(ret, NULL, &StatusCode);\r
+ if(StatusCode == NULL || *StatusCode < HTTP_STATUS_200_OK || *StatusCode > HTTP_STATUS_206_PARTIAL_CONTENT)\r
+ {\r
+ if (StatusCode != NULL) {\r
+ FreePool (StatusCode);\r
+ }\r
+\r
+ if (payload != NULL) {\r
+ cleanupPayload(payload);\r
+ }\r
+ cleanupServiceEnumerator(ret);\r
+ return NULL;\r
+ }\r
+\r
+ if (StatusCode != NULL) {\r
+ FreePool (StatusCode);\r
+ StatusCode = NULL;\r
+ }\r
+\r
+ links = getPayloadByNodeName(payload, "Links", &StatusCode);\r
+ cleanupPayload(payload);\r
+ if(links == NULL)\r
+ {\r
+ cleanupServiceEnumerator(ret);\r
+ return NULL;\r
+ }\r
+ session = json_object_get(links->json, "Sessions");\r
+ if(session == NULL)\r
+ {\r
+ cleanupPayload(links);\r
+ cleanupServiceEnumerator(ret);\r
+ return NULL;\r
+ }\r
+ odataId = json_object_get(session, "@odata.id");\r
+ if(odataId == NULL)\r
+ {\r
+ cleanupPayload(links);\r
+ cleanupServiceEnumerator(ret);\r
+ return NULL;\r
+ }\r
+ uri = json_string_value(odataId);\r
+ post = json_object();\r
+ addStringToJsonObject(post, "UserName", username);\r
+ addStringToJsonObject(post, "Password", password);\r
+ content = json_dumps(post, 0);\r
+ json_decref(post);\r
+ sessionPayload = postUriFromService(ret, uri, content, 0, NULL, &StatusCode);\r
+\r
+ if (content != NULL) {\r
+ ZeroMem (content, (UINTN)strlen(content));\r
+ free(content);\r
+ }\r
+\r
+ if(sessionPayload == NULL || StatusCode == NULL || *StatusCode < HTTP_STATUS_200_OK || *StatusCode > HTTP_STATUS_206_PARTIAL_CONTENT)\r
+ {\r
+ //Failed to create session!\r
+\r
+ cleanupPayload(links);\r
+ cleanupServiceEnumerator(ret);\r
+\r
+ if (StatusCode != NULL) {\r
+ FreePool (StatusCode);\r
+ }\r
+\r
+ if (sessionPayload != NULL) {\r
+ json_decref(sessionPayload);\r
+ }\r
+\r
+ return NULL;\r
+ }\r
+ json_decref(sessionPayload);\r
+ cleanupPayload(links);\r
+ FreePool (StatusCode);\r
+ return ret;\r
+}\r
+\r
+static char* makeUrlForService(redfishService* service, const char* uri)\r
+{\r
+ char* url;\r
+ if(service->host == NULL)\r
+ {\r
+ return NULL;\r
+ }\r
+ url = (char*)malloc(strlen(service->host)+strlen(uri)+1);\r
+ strcpy(url, service->host);\r
+ strcat(url, uri);\r
+ return url;\r
+}\r
+\r
+static json_t* getVersions(redfishService* service, const char* rootUri)\r
+{\r
+ json_t* ret = NULL;\r
+ EFI_HTTP_STATUS_CODE* StatusCode = NULL;\r
+\r
+ if(service->flags & REDFISH_FLAG_SERVICE_NO_VERSION_DOC)\r
+ {\r
+ service->versions = json_object();\r
+ if(service->versions == NULL)\r
+ {\r
+ return NULL;\r
+ }\r
+ addStringToJsonObject(service->versions, "v1", "/redfish/v1");\r
+ return service->versions;\r
+ }\r
+ if(rootUri != NULL)\r
+ {\r
+ ret = getUriFromService(service, rootUri, &StatusCode);\r
+ }\r
+ else\r
+ {\r
+ ret = getUriFromService(service, "/redfish", &StatusCode);\r
+ }\r
+\r
+ if (ret == NULL || StatusCode == NULL || *StatusCode < HTTP_STATUS_200_OK || *StatusCode > HTTP_STATUS_206_PARTIAL_CONTENT) {\r
+ if (ret != NULL) {\r
+ json_decref(ret);\r
+ }\r
+ ret = NULL;\r
+ }\r
+\r
+ if (StatusCode != NULL) {\r
+ FreePool (StatusCode);\r
+ }\r
+\r
+ return ret;\r
+}\r
+\r
+static void addStringToJsonObject(json_t* object, const char* key, const char* value)\r
+{\r
+ json_t* jValue = json_string(value);\r
+\r
+ json_object_set(object, key, jValue);\r
+\r
+ json_decref(jValue);\r
+}\r
# by using "!include RedfishPkg/RedfisLibs.dsc.inc" to specify the library instances\r
# of EDKII network library classes.\r
#\r
-# (C) Copyright 2020 Hewlett Packard Enterprise Development LP<BR>\r
+# (C) Copyright 2021 Hewlett Packard Enterprise Development LP<BR>\r
#\r
# SPDX-License-Identifier: BSD-2-Clause-Patent\r
#\r
BaseSortLib|MdeModulePkg/Library/BaseSortLib/BaseSortLib.inf\r
RedfishCrtLib|RedfishPkg/PrivateLibrary/RedfishCrtLib/RedfishCrtLib.inf\r
JsonLib|RedfishPkg/Library/JsonLib/JsonLib.inf\r
+ RedfishLib|RedfishPkg/PrivateLibrary/RedfishLib/RedfishLib.inf\r
!endif\r
\r
## @file\r
# CI configuration for NetworkPkg\r
#\r
-# (C) Copyright 2020 Hewlett Packard Enterprise Development LP<BR>\r
+# (C) Copyright 2021 Hewlett Packard Enterprise Development LP<BR>\r
# SPDX-License-Identifier: BSD-2-Clause-Patent\r
##\r
{\r
## load.c is overrided from open source.\r
"Library/JsonLib/load.c",\r
"Library/JsonLib/jansson_config.h",\r
- "Library/JsonLib/jansson_private_config.h"\r
+ "Library/JsonLib/jansson_private_config.h",\r
+ ##\r
+ ## For libredfish open source\r
+ ## The files under edk2libredfish are cloned\r
+ ## from DMTF open source\r
+ "PrivateLibrary/RedfishLib/edk2libredfish/include/redfish.h",\r
+ "PrivateLibrary/RedfishLib/edk2libredfish/include/redfishPayload.h",\r
+ "PrivateLibrary/RedfishLib/edk2libredfish/include/redfishService.h",\r
+ "PrivateLibrary/RedfishLib/edk2libredfish/include/redpath.h",\r
+ "PrivateLibrary/RedfishLib/edk2libredfish/src/payload.c",\r
+ "PrivateLibrary/RedfishLib/edk2libredfish/src/redpath.c",\r
+ "PrivateLibrary/RedfishLib/edk2libredfish/src/service.c"\r
]\r
},\r
"CompilerPlugin": {\r
# project).\r
RedfishCrtLib|PrivateInclude/Library/RedfishCrtLib.h\r
\r
+ ## @libraryclass Redfish Helper Library\r
+ # Library provides Redfish helper functions.\r
+ RedfishLib|PrivateInclude/Library/RedfishLib.h\r
+\r
[Protocols]\r
## Include/Protocol/RedfishDiscover.h\r
gEfiRedfishDiscoverProtocolGuid = { 0x5db12509, 0x4550, 0x4347, { 0x96, 0xb3, 0x73, 0xc0, 0xff, 0x6e, 0x86, 0x9f }}\r
RedfishPkg/Library/BaseUcs2Utf8Lib/BaseUcs2Utf8Lib.inf\r
RedfishPkg/PrivateLibrary/RedfishCrtLib/RedfishCrtLib.inf\r
RedfishPkg/Library/JsonLib/JsonLib.inf\r
+ RedfishPkg/PrivateLibrary/RedfishLib/RedfishLib.inf\r
\r
!include RedfishPkg/Redfish.dsc.inc\r