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