/** @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.
(C) Copyright 2021 Hewlett Packard Enterprise Development LP
Copyright (c) 2023, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#include
#include
#include
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;
}
EFI_HTTP_HEADER *
cloneHttpHeaders (
EFI_HTTP_MESSAGE *message,
UINTN *HeaderCount
)
{
EFI_HTTP_HEADER *Buffer;
UINTN Index;
if ((message == NULL) || (HeaderCount == NULL)) {
return NULL;
}
*HeaderCount = message->HeaderCount;
Buffer = AllocatePool (sizeof (EFI_HTTP_HEADER) * message->HeaderCount);
if (Buffer == NULL) {
return NULL;
}
for (Index = 0; Index < message->HeaderCount; Index++) {
Buffer[Index].FieldName = AllocateCopyPool (AsciiStrSize (message->Headers[Index].FieldName), message->Headers[Index].FieldName);
ASSERT (Buffer[Index].FieldName != NULL);
Buffer[Index].FieldValue = AllocateCopyPool (AsciiStrSize (message->Headers[Index].FieldValue), message->Headers[Index].FieldValue);
ASSERT (Buffer[Index].FieldValue != NULL);
}
return Buffer;
}
json_t *
getUriFromServiceEx (
redfishService *service,
const char *uri,
EFI_HTTP_HEADER **Headers OPTIONAL,
UINTN *HeaderCount OPTIONAL,
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;
if (HeaderCount != NULL) {
*HeaderCount = 0;
}
if (Headers != NULL) {
*Headers = NULL;
}
url = makeUrlForService (service, uri);
if (!url) {
return NULL;
}
DEBUG ((DEBUG_MANAGEABILITY, "%a: %a\n", __func__, 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;
//
// Deliver status code to caller when error happens so caller can do error handling.
//
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;
}
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.Headers != NULL) && (Headers != NULL) && (HeaderCount != NULL)) {
*Headers = cloneHttpHeaders (&ResponseMsg, HeaderCount);
}
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.", __func__, 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 *
putUriFromServiceEx (
redfishService *service,
const char *uri,
const char *content,
size_t contentLength,
const char *contentType,
EFI_HTTP_HEADER **Headers OPTIONAL,
UINTN *HeaderCount OPTIONAL,
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;
if (HeaderCount != NULL) {
*HeaderCount = 0;
}
if (Headers != NULL) {
*Headers = NULL;
}
url = makeUrlForService (service, uri);
if (url == NULL) {
return NULL;
}
DEBUG ((DEBUG_MANAGEABILITY, "%a: %a\n", __func__, url));
if (contentLength == 0) {
contentLength = strlen (content);
}
//
// Step 1: Create HTTP request message with 4 headers:
//
HttpIoHeader = HttpIoCreateHeader ((service->sessionToken != NULL || service->basicAuthStr != NULL) ? 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);
}
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, "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)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) {
ret = NULL;
goto ON_EXIT;
}
RequestData->Method = HttpMethodPut;
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 = contentLength;
//
// 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", __func__));
ret = NULL;
goto ON_EXIT;
} else if (Status == EFI_UNSUPPORTED) {
DEBUG ((DEBUG_MANAGEABILITY, "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 ((ResponseMsg.Headers != NULL) && (Headers != NULL) && (HeaderCount != NULL)) {
*Headers = cloneHttpHeaders (&ResponseMsg, HeaderCount);
}
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 *
patchUriFromServiceEx (
redfishService *service,
const char *uri,
const char *content,
EFI_HTTP_HEADER **Headers OPTIONAL,
UINTN *HeaderCount OPTIONAL,
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;
if (HeaderCount != NULL) {
*HeaderCount = 0;
}
if (Headers != NULL) {
*Headers = NULL;
}
url = makeUrlForService (service, uri);
if (!url) {
return NULL;
}
DEBUG ((DEBUG_MANAGEABILITY, "%a: %a\n", __func__, 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", __func__));
ret = NULL;
goto ON_EXIT;
} else if (Status == EFI_UNSUPPORTED) {
DEBUG ((DEBUG_MANAGEABILITY, "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 ((ResponseMsg.Headers != NULL) && (Headers != NULL) && (HeaderCount != NULL)) {
*Headers = cloneHttpHeaders (&ResponseMsg, HeaderCount);
}
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 *
postUriFromServiceEx (
redfishService *service,
const char *uri,
const char *content,
size_t contentLength,
const char *contentType,
EFI_HTTP_HEADER **Headers OPTIONAL,
UINTN *HeaderCount OPTIONAL,
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;
if (HeaderCount != NULL) {
*HeaderCount = 0;
}
if (Headers != NULL) {
*Headers = NULL;
}
url = makeUrlForService (service, uri);
if (!url) {
return NULL;
}
DEBUG ((DEBUG_MANAGEABILITY, "%a: %a\n", __func__, 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)) {
//
// If there is no response to handle, go to error exit.
//
if (ResponseMsg.Data.Response == 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) {
goto ON_EXIT;
}
//
// The caller shall take the responsibility to free the buffer.
//
**StatusCode = ResponseMsg.Data.Response->StatusCode;
}
if ((ResponseMsg.Headers != NULL) && (Headers != NULL) && (HeaderCount != NULL)) {
*Headers = cloneHttpHeaders (&ResponseMsg, HeaderCount);
}
if ((ResponseMsg.BodyLength != 0) && (ResponseMsg.Body != NULL)) {
ret = json_loadb (ResponseMsg.Body, ResponseMsg.BodyLength, 0, NULL);
}
//
// Step 6: Parsing the HttpHeader to retrieve the X-Auth-Token if the HTTP StatusCode is correct.
//
if ((ResponseMsg.Data.Response != NULL) &&
((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);
}
}
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 *
getUriFromService (
redfishService *service,
const char *uri,
EFI_HTTP_STATUS_CODE **StatusCode
)
{
return getUriFromServiceEx (service, uri, NULL, NULL, StatusCode);
}
json_t *
patchUriFromService (
redfishService *service,
const char *uri,
const char *content,
EFI_HTTP_STATUS_CODE **StatusCode
)
{
return patchUriFromServiceEx (service, uri, content, NULL, NULL, StatusCode);
}
json_t *
postUriFromService (
redfishService *service,
const char *uri,
const char *content,
size_t contentLength,
const char *contentType,
EFI_HTTP_STATUS_CODE **StatusCode
)
{
return postUriFromServiceEx (service, uri, content, contentLength, contentType, NULL, NULL, StatusCode);
}
json_t *
deleteUriFromServiceEx (
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];
size_t contentLength;
ret = NULL;
if ((service == NULL) || (uri == NULL) || (StatusCode == NULL)) {
return NULL;
}
*StatusCode = NULL;
url = makeUrlForService (service, uri);
if (!url) {
return NULL;
}
DEBUG ((DEBUG_MANAGEABILITY, "libredfish: deleteUriFromService(): %a\n", url));
//
// Step 1: Create HTTP request message with 4 headers:
//
HttpIoHeader = HttpIoCreateHeader ((service->sessionToken || service->basicAuthStr) ? 8 : 7);
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);
Status = HttpIoSetHeader (HttpIoHeader, "Content-Type", "application/json");
ASSERT_EFI_ERROR (Status);
if (content != NULL) {
contentLength = strlen (content);
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) {
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;
if (content != NULL) {
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)) {
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;
}
json_t *
deleteUriFromService (
redfishService *service,
const char *uri,
EFI_HTTP_STATUS_CODE **StatusCode
)
{
return deleteUriFromServiceEx (service, uri, NULL, StatusCode);
}
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);
if (url == NULL) {
return NULL;
}
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);
}