From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from NAM12-DM6-obe.outbound.protection.outlook.com (NAM12-DM6-obe.outbound.protection.outlook.com [40.107.243.67]) by mx.groups.io with SMTP id smtpd.web11.17104.1683249364483444136 for ; Thu, 04 May 2023 18:16:04 -0700 Authentication-Results: mx.groups.io; dkim=pass header.i=@amd.com header.s=selector1 header.b=v+1wHe/S; spf=permerror, err=parse error for token &{10 18 %{i}._ip.%{h}._ehlo.%{d}._spf.vali.email}: invalid domain name (domain: amd.com, ip: 40.107.243.67, mailfrom: abner.chang@amd.com) ARC-Seal: i=1; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=none; b=gZEok2u42H11+KSXEMisOgSBPs9kfDlH7xCuYkv+8JYV6aeW3nf2UyoCnNRI7viWVV6Rlw+jm3xmsFG1+8/njRD/NOsiY7s1110cIjgsz6MBh4wHcUe7TetgVlX6ny+vme16OWVeBsxffQ7GpPnc1rQcROhSweQh0x881GdFwp4+5AbDHTgQ5nKcoJu9hVs5DEZKkDm5Aow01HOaEEUtOfNM0HF2JezWiRH9mLBpZS2zSa/UaxbwT47cMnkqvQHV71sWa0SGmqZGP47vdpG/VGdirDoXyxy5Obj7OXfF+8F25mmWPcpE8oCN8BCtFzkrLFLMdq14hoeKWdNnKPi3zA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector9901; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-AntiSpam-MessageData-ChunkCount:X-MS-Exchange-AntiSpam-MessageData-0:X-MS-Exchange-AntiSpam-MessageData-1; bh=OWWGRMsXWX+TIgLGQhKQUd4pz5uIFwoLOTQRAEjMY3I=; b=HSY3bCyNwd9SO1OHIyzyq4sF+PIDwDzVjLs+tPlMdAAmL7UvIQd8SqUxS3+u+BLzvzStak8yfWQ/SoqoPyatS055nDg4UCikuYwOY/LjpPy4aR/N2WZEPktoPcUS35bt9OZGB+0HAImYmN9PudhCoaAII+mjaJY3N1xSIW2mG0COxbZtU+Wf3U8YxIh696VO4jYTNfksCRTArIhXXoxGJ2TaG1ukPVT7L4dZj16ZTu29A6iBm4/X9lTW2bbfalPay3hrhODaj03vdd0P0lPLdmQxGgSHGOhc43RY7/mHxJnPiY1uyDaSz8FS9zB68wdN4H9wzVwMwSUGb7AyNamEzg== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass smtp.mailfrom=amd.com; dmarc=pass action=none header.from=amd.com; dkim=pass header.d=amd.com; arc=none DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=amd.com; s=selector1; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=OWWGRMsXWX+TIgLGQhKQUd4pz5uIFwoLOTQRAEjMY3I=; b=v+1wHe/SirSWm+qVLNk0Eqo/XFW/CF3Xkkrb5WylxT9jRsjGTIvrV2LdQ7a3m8ZVoTRc3aiF4tFUYYbOYgBF1PmJLLM6akH4eUMISep1Z2uyPSRelhAwl/CfEekRpoLAL7vDDHCNvdTleyFB31qjMlkBQxAFKCq+kO+P+XgqKHE= Received: from MN2PR12MB3966.namprd12.prod.outlook.com (2603:10b6:208:165::18) by CY8PR12MB7338.namprd12.prod.outlook.com (2603:10b6:930:52::8) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.6363.26; Fri, 5 May 2023 01:15:58 +0000 Received: from MN2PR12MB3966.namprd12.prod.outlook.com ([fe80::46f1:bdce:a4bc:29e3]) by MN2PR12MB3966.namprd12.prod.outlook.com ([fe80::46f1:bdce:a4bc:29e3%3]) with mapi id 15.20.6363.027; Fri, 5 May 2023 01:15:58 +0000 From: "Chang, Abner" To: Nickle Wang , "devel@edk2.groups.io" CC: Igor Kulchytskyy Subject: Re: [edk2-redfish-client][PATCH 7/8] RedfishClientPkg: RedfishLib Thread-Topic: [edk2-redfish-client][PATCH 7/8] RedfishClientPkg: RedfishLib Thread-Index: AQHZfpTDEljAYSwa0UG7zmgQZAmtTK9K4RoQ Date: Fri, 5 May 2023 01:15:58 +0000 Message-ID: References: <20230504142829.19305-1-nicklew@nvidia.com> In-Reply-To: <20230504142829.19305-1-nicklew@nvidia.com> Accept-Language: zh-CN, en-US X-MS-Has-Attach: X-MS-TNEF-Correlator: msip_labels: MSIP_Label_4342314e-0df4-4b58-84bf-38bed6170a0f_Enabled=true; MSIP_Label_4342314e-0df4-4b58-84bf-38bed6170a0f_SetDate=2023-05-05T01:15:55Z; MSIP_Label_4342314e-0df4-4b58-84bf-38bed6170a0f_Method=Standard; MSIP_Label_4342314e-0df4-4b58-84bf-38bed6170a0f_Name=General; MSIP_Label_4342314e-0df4-4b58-84bf-38bed6170a0f_SiteId=3dd8961f-e488-4e60-8e11-a82d994e183d; MSIP_Label_4342314e-0df4-4b58-84bf-38bed6170a0f_ActionId=4f94c3d6-93be-4fc9-9eb8-102165c94cee; MSIP_Label_4342314e-0df4-4b58-84bf-38bed6170a0f_ContentBits=1 authentication-results: dkim=none (message not signed) header.d=none;dmarc=none action=none header.from=amd.com; x-ms-publictraffictype: Email x-ms-traffictypediagnostic: MN2PR12MB3966:EE_|CY8PR12MB7338:EE_ x-ms-office365-filtering-correlation-id: 8b3e8d66-81b7-4640-938f-08db4d0648af x-ms-exchange-senderadcheck: 1 x-ms-exchange-antispam-relay: 0 x-microsoft-antispam: BCL:0; x-microsoft-antispam-message-info: WsbEJ11L7lvRG3VpqI6HRWASNc3dvIVNOv2NuYSi69czlGJBsPmguhqyJm2GDqNlCAJoxTtCB1ERT+wlxAkS4ioBkTaa1SqCj8gGiMjMKQXs38dbo+LZdG/BufmDJbL7jB/MBkRae86Fc2TTVywa8L7TY1EjM04hm78V6/uLidxGjSnMSXiC6JI3KGJ70pR5OM8myoBBGvL0k1iR+PfMGwyzsNmdkVmd554Gxjq4IzIFvPLzl4EihZhnQkBpOrNL1wJzLU7OtZ9S7zQms/rfbCRdqAe0I0dBtnjB+peJcV75ro1QAfaUxx92YXmk5KzFrgs9KAJJM0d1orALTTy6vUoNqF/4xhXnYpJ4XKcPT1SITDPgtz+ssqjBB3K1M2UvbCkRCN2OVK74kXLATHELKzqjV49PgV0M2jPGjGDcB2RqrqSrdPFBNlHMjXsrNLQ2gWRPzdbFi4piStrnaZo98ms9ha76FNhwGiFZ0K9C0RYkeU7n81SL0zMy/es1uVdWQSL8a9ZBNqhEI0HiGHmaMzIAxmWLxm9YD6bM41mPwessV33Pb/G4sR5FewSpoa+EMz2TeAmaT36g1qKKbF3ZjlUMen3P5GFYu2z/kRGGDGDEP86UYXFRYvgnval38WxN71//PverUHzPaDwCjn1wOIPjivokZW1nQ7UQK6EjWptkSVW11sgKnBqmXHOUrYRd x-forefront-antispam-report: CIP:255.255.255.255;CTRY:;LANG:en;SCL:1;SRV:;IPV:NLI;SFV:NSPM;H:MN2PR12MB3966.namprd12.prod.outlook.com;PTR:;CAT:NONE;SFS:(13230028)(6019001)(4636009)(396003)(366004)(376002)(346002)(39860400002)(136003)(279900001)(451199021)(52536014)(966005)(7696005)(33656002)(122000001)(41300700001)(8936002)(8676002)(86362001)(83380400001)(5660300002)(53546011)(9686003)(4326008)(26005)(6506007)(478600001)(71200400001)(316002)(76116006)(38100700002)(66556008)(66446008)(66476007)(64756008)(66946007)(2906002)(30864003)(38070700005)(186003)(55016003)(110136005)(119570200001)(559001)(579004);DIR:OUT;SFP:1101; x-ms-exchange-antispam-messagedata-chunkcount: 1 x-ms-exchange-antispam-messagedata-0: =?us-ascii?Q?HjlqtmVyPKvuvEmIm8jDWXJGw1fiI1FlqCC4Heo061NCp39EieRM89EjMieh?= =?us-ascii?Q?zZGCP0jf62NSVuXAz3OqakKQwXUNi+PskOFDx+3pAwecJFUNJpWMRscECgya?= =?us-ascii?Q?FXrDnY+Chs5NX6yguH878zrdlGQ7IYStOi0YDjUSwmz3s3CQNiL9W/LZ7Mp+?= =?us-ascii?Q?ilbCoTz4Gr+WGn4mwAHPJeqG6ogLOW776Jd7DrZ9ZNfxwzbzQlq7BInftvYJ?= =?us-ascii?Q?MQktDe5BQW2Vmm4cHm4vb1s9BCZ7U4BMeX1+wu/TkyoURpxkmoeJAk0mSSFv?= =?us-ascii?Q?XyQhx40QdgJXalbUNhpx5/hknYAmr6W37g1dfnKNKiMQKC/dpdWwh5LazTzz?= =?us-ascii?Q?wHdIIYC04ZHhMyE/C3sRcARKWzSANvhl+pgHucyIpKzr3kGLVyciLJ99ONMu?= =?us-ascii?Q?c/yF88EZxBC838un87IFlGKonoCDfivTZpRSZIEjgTjXLrhlPK10NuwWZP3h?= =?us-ascii?Q?+F70ZVA13lEnm+AXOfGhy1+kePTmsCbD8/LtQG4g9Jy3q2pdbvEdeLXFLnmz?= =?us-ascii?Q?EXdEsjCdRk1gsbwH5PeCRWzg6waOPHl7xw1PbIjr0FY2oXswTIBeyE5CqV/C?= =?us-ascii?Q?giR4rsIunQhiDWW7r6ps3HoGmhY55cCcJdlGBI5F/O570ZGnduRDBhIoAJjT?= =?us-ascii?Q?EEiD1V0bi+yG5IX3hoQfN4UzfUGbLse0ivKqy846xjc1PaJJbTLouJjbzNFv?= =?us-ascii?Q?rgKS551X+ToI0BdaY+WpWM4VRsm/B1PFCG4PcIWF/91GHb40tp3SGIbZuNOj?= =?us-ascii?Q?S+ljxEgo5Q173+Q5IU+IL2mxOKesbm+nNJUYed/y8quyFk7pLPFyS6hcwd88?= =?us-ascii?Q?DP/lUa1+qiheVsTeL6EX053QHDIpaYTZF1Rn08i8VuEw4lg1Y5Yc5v5LAUB9?= =?us-ascii?Q?hja/T7SXRznr7YIUGdYXE/yMvibTAjjXA34HoBTYteoD1cvNOEf0znck5H/V?= =?us-ascii?Q?nT+wHRR2Aab5nhVLWbhTqU1Q/VZF8STkag4eZjKcJAOnoEJnQc1Zo2zKHrMu?= =?us-ascii?Q?4V/vNIn86zJf70KnviFIGdKersMR4d8hLW7xQ4oJK9QFkhTcLXekQ+ipOsTb?= =?us-ascii?Q?umyT/QEbthGoYYbeD2XSCRWWGhBF+6Dygd8/JusST2db4oG4YTPT9KeI8xUS?= =?us-ascii?Q?leOaT90Z81bFFIDaPkhaktg041ObvClqXYtSAip9cc48GXfgzMTeqHhSijT7?= =?us-ascii?Q?l10LcE8CTWTl3NQece8e++TmNrXAY3Ljd/96t+DXHxGC1QwItSBWnaHK7lGX?= =?us-ascii?Q?tZN8a9kEBKL5LPgcW+khYxFzZ2th9te3Nh4iRk3J9r6zeS2JN7ZOSpwHgaqi?= =?us-ascii?Q?wwqpD6kH1KkkGyULoWpRok8R7ZFkQnGSwGg/flehY371apNibVZNP7fdykIB?= =?us-ascii?Q?GJQABOOBC5R5K2kxAEaDeeUJztVZF0ChonvRAkVQZSO1BVg0U4GMJmaaSC77?= =?us-ascii?Q?UCE0HBsmje/Du8rrEo7pUF806BwTCeiKGvqHZ4EojVy3YBiU+L3qqXH6BBQw?= =?us-ascii?Q?e00WVpn/aW9CGeRpBXjM/ElpMXYR18/dz+/0btxVNSvuAILYSvfz+wnCdDv4?= =?us-ascii?Q?5TCNaanDCnYcu6FFLDm8o7Vs0LooYk1glG0waEQ/?= MIME-Version: 1.0 X-OriginatorOrg: amd.com X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-AuthSource: MN2PR12MB3966.namprd12.prod.outlook.com X-MS-Exchange-CrossTenant-Network-Message-Id: 8b3e8d66-81b7-4640-938f-08db4d0648af X-MS-Exchange-CrossTenant-originalarrivaltime: 05 May 2023 01:15:58.7619 (UTC) X-MS-Exchange-CrossTenant-fromentityheader: Hosted X-MS-Exchange-CrossTenant-id: 3dd8961f-e488-4e60-8e11-a82d994e183d X-MS-Exchange-CrossTenant-mailboxtype: HOSTED X-MS-Exchange-CrossTenant-userprincipalname: lJ6RM3B0YjedlfKdfhN3odOQgqmUbGiQXwpmkVtsSDPCSCmL3GV0e5o+xqJdIJ7VMjSsckdFZX6c1ZLNdfx9Ig== X-MS-Exchange-Transport-CrossTenantHeadersStamped: CY8PR12MB7338 Content-Language: en-US Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: quoted-printable [AMD Official Use Only - General] Reviewed-by: Abner Chang > -----Original Message----- > From: Nickle Wang > Sent: Thursday, May 4, 2023 10:28 PM > To: devel@edk2.groups.io > Cc: Chang, Abner ; Igor Kulchytskyy > > Subject: [edk2-redfish-client][PATCH 7/8] RedfishClientPkg: RedfishLib >=20 > Caution: This message originated from an External Source. Use proper > caution when opening attachments, clicking links, or responding. >=20 >=20 > (This one is the same as RedfishLib under RedfishPkg. > The one under RedfishPkg will be removed because > RedfishLib is used by EDKII feature drivers which is belong > to EDK2 Redfish client implementation) >=20 > EDK2 port of DMTF libredfish project. We clone the necessary files > from open source project libredfish (https://github.com/DMTF/ > libredfish) tag v1.0.0 and revise it to incorporate with edk2 > firmware code base. >=20 > The reason of cloning the necessary files instead of using extern > submodule of libredfish project: > libredfish as a C library which is executed under Windows and > Linux. It could be binded with other programming languages such as > java and python. The library uses curl library as the communication > service with Redfish, which is not easy to be abstracted and > replaced with EFI specific protocols (e.g. EFI_REST_EX_PROTOCOL or > payload encode/decode library) and EFI data types. We had the > conversation with DMTF community and they think edk2 is a firmware > solution but not the programming language, > therefore they rejected to have edk2 as a binding to libredfish. > According to above, we decide to clone the necessary files from > libredfish modify it to incorporate with edk2. >=20 > Signed-off-by: Nickle Wang > Cc: Abner Chang > Cc: Igor Kulchytskyy > --- > RedfishClientPkg/RedfishClientPkg.dec | 5 + > RedfishClientPkg/RedfishClientLibs.dsc.inc | 4 + > RedfishClientPkg/RedfishClientPkg.dsc | 1 + > .../PrivateLibrary/RedfishLib/RedfishLib.inf | 62 + > .../PrivateLibrary/RedfishLib/RedfishMisc.h | 82 + > .../edk2libredfish/include/redfish.h | 25 + > .../edk2libredfish/include/redfishPayload.h | 106 ++ > .../edk2libredfish/include/redfishService.h | 151 ++ > .../edk2libredfish/include/redpath.h | 49 + > .../PrivateLibrary/RedfishLib/RedfishLib.c | 1033 +++++++++++ > .../PrivateLibrary/RedfishLib/RedfishMisc.c | 206 +++ > .../RedfishLib/edk2libredfish/src/payload.c | 812 +++++++++ > .../RedfishLib/edk2libredfish/src/redpath.c | 224 +++ > .../RedfishLib/edk2libredfish/src/service.c | 1523 +++++++++++++++++ > 14 files changed, 4283 insertions(+) > create mode 100644 > RedfishClientPkg/PrivateLibrary/RedfishLib/RedfishLib.inf > create mode 100644 > RedfishClientPkg/PrivateLibrary/RedfishLib/RedfishMisc.h > create mode 100644 > RedfishClientPkg/PrivateLibrary/RedfishLib/edk2libredfish/include/redfish= .h > create mode 100644 > RedfishClientPkg/PrivateLibrary/RedfishLib/edk2libredfish/include/redfish= Pa > yload.h > create mode 100644 > RedfishClientPkg/PrivateLibrary/RedfishLib/edk2libredfish/include/redfish= Se > rvice.h > create mode 100644 > RedfishClientPkg/PrivateLibrary/RedfishLib/edk2libredfish/include/redpath= . > h > create mode 100644 RedfishClientPkg/PrivateLibrary/RedfishLib/RedfishLib= .c > create mode 100644 > RedfishClientPkg/PrivateLibrary/RedfishLib/RedfishMisc.c > create mode 100644 > RedfishClientPkg/PrivateLibrary/RedfishLib/edk2libredfish/src/payload.c > create mode 100644 > RedfishClientPkg/PrivateLibrary/RedfishLib/edk2libredfish/src/redpath.c > create mode 100644 > RedfishClientPkg/PrivateLibrary/RedfishLib/edk2libredfish/src/service.c >=20 > diff --git a/RedfishClientPkg/RedfishClientPkg.dec > b/RedfishClientPkg/RedfishClientPkg.dec > index b965f915..09df062d 100644 > --- a/RedfishClientPkg/RedfishClientPkg.dec > +++ b/RedfishClientPkg/RedfishClientPkg.dec > @@ -22,6 +22,11 @@ > [LibraryClasses] > RedfishFeatureUtilityLib|Include/Library/RedfishFeatureUtilityLib.h >=20 > +[LibraryClasses.Common.Private] > + ## @libraryclass Redfish Helper Library > + # Library provides Redfish helper functions. > + RedfishLib|PrivateInclude/Library/RedfishLib.h > + > [Protocols] > ## Include/Protocol/EdkIIRedfishFeature.h > gEdkIIRedfishFeatureProtocolGuid =3D { 0x785CC694, 0x4930, 0xEF= BF, > { 0x2A, 0xCB, 0xA4, 0xB6, 0xA1, 0xCC, 0xAA, 0x34 } } > diff --git a/RedfishClientPkg/RedfishClientLibs.dsc.inc > b/RedfishClientPkg/RedfishClientLibs.dsc.inc > index a5ae73ca..4655dd70 100644 > --- a/RedfishClientPkg/RedfishClientLibs.dsc.inc > +++ b/RedfishClientPkg/RedfishClientLibs.dsc.inc > @@ -14,6 +14,10 @@ > !include RedfishClientPkg/RedfishJsonStructureLib.dsc.inc > !endif >=20 > + NetLib|NetworkPkg/Library/DxeNetLib/DxeNetLib.inf > + HttpLib|NetworkPkg/Library/DxeHttpLib/DxeHttpLib.inf > + RedfishLib|RedfishClientPkg/PrivateLibrary/RedfishLib/RedfishLib.inf >=20 > RedfishFeatureUtilityLib|RedfishClientPkg/Library/RedfishFeatureUtilityLi= b/ > RedfishFeatureUtilityLib.inf >=20 > RedfishPlatformConfigLib|RedfishPkg/Library/RedfishPlatformConfigLib/Red > fishPlatformConfigLib.inf > + > RedfishContentCodingLib|RedfishPkg/Library/RedfishContentCodingLibNull/ > RedfishContentCodingLibNull.inf >=20 > diff --git a/RedfishClientPkg/RedfishClientPkg.dsc > b/RedfishClientPkg/RedfishClientPkg.dsc > index 00a963ea..2b2149cc 100644 > --- a/RedfishClientPkg/RedfishClientPkg.dsc > +++ b/RedfishClientPkg/RedfishClientPkg.dsc > @@ -48,5 +48,6 @@ > [Components] >=20 >=20 > RedfishClientPkg/Library/RedfishFeatureUtilityLib/RedfishFeatureUtilityLi= b.i > nf > + RedfishClientPkg/PrivateLibrary/RedfishLib/RedfishLib.inf >=20 > !include RedfishClientPkg/RedfishClient.dsc.inc > diff --git a/RedfishClientPkg/PrivateLibrary/RedfishLib/RedfishLib.inf > b/RedfishClientPkg/PrivateLibrary/RedfishLib/RedfishLib.inf > new file mode 100644 > index 00000000..a54e397d > --- /dev/null > +++ b/RedfishClientPkg/PrivateLibrary/RedfishLib/RedfishLib.inf > @@ -0,0 +1,62 @@ > +## @file > +# RedfishLib Library implementation. > +# > +# Copyright (c) 2019, Intel Corporation. All rights reserved.
> +# (C) Copyright 2021 Hewlett Packard Enterprise Development LP
> +# > +# SPDX-License-Identifier: BSD-2-Clause-Patent > +# > +## > + > +[Defines] > + INF_VERSION =3D 0x0001001b > + BASE_NAME =3D DxeRedfishLib > + FILE_GUID =3D 9C2CA9CF-4F79-11E8-A7D1-8CDCD426C97= 3 > + MODULE_TYPE =3D DXE_DRIVER > + VERSION_STRING =3D 1.0 > + LIBRARY_CLASS =3D RedfishLib| DXE_DRIVER UEFI_APPLICA= TION > UEFI_DRIVER > + > +# > +# VALID_ARCHITECTURES =3D 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 > + RedfishClientPkg/RedfishClientPkg.dec > + > +[LibraryClasses] > + BaseLib > + BaseMemoryLib > + DebugLib > + JsonLib > + HttpLib > + MemoryAllocationLib > + NetLib > + RedfishContentCodingLib > + RedfishCrtLib > + UefiBootServicesTableLib > + UefiLib > + > +[Protocols] > + gEfiRestExServiceBindingProtocolGuid ## Consumed > + gEfiRestExProtocolGuid ## Consumed > + gEdkIIRedfishCredentialProtocolGuid ## Consumed > + > +[BuildOptions] > + MSFT:*_*_*_CC_FLAGS =3D /U_WIN32 /UWIN64 /U_MSC_VER > + GCC:*_*_*_CC_FLAGS =3D -Wno-unused-function -Wno-unused-but-set- > variable > diff --git a/RedfishClientPkg/PrivateLibrary/RedfishLib/RedfishMisc.h > b/RedfishClientPkg/PrivateLibrary/RedfishLib/RedfishMisc.h > new file mode 100644 > index 00000000..3b066c11 > --- /dev/null > +++ b/RedfishClientPkg/PrivateLibrary/RedfishLib/RedfishMisc.h > @@ -0,0 +1,82 @@ > +/** @file > + Internal Functions for RedfishLib. > + > + Copyright (c) 2019, Intel Corporation. All rights reserved.
> + (C) Copyright 2021 Hewlett Packard Enterprise Development LP
> + > + SPDX-License-Identifier: BSD-2-Clause-Patent > + > +**/ > + > +#ifndef DXE_REDFISH_MISC_LIB_H_ > +#define DXE_REDFISH_MISC_LIB_H_ > + > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > + > +#define ARRAY_SIZE(Array) (sizeof (Array) / sizeof ((Array)[0])) > + > +/** > + Creates a REDFISH_SERVICE which can be later used to access the Redfis= h > 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 Red= fish > session > + login is configured to use. > + > + @param[in] RedfishConfigServiceInfo Redfish service information the E= FI > Redfish > + feature driver communicates with. > + @param[in] AuthMethod None, HTTP basic auth, or Redfish session log= in. > + @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 pointe= d by > UserId > + and Password. > + > + @param[out] AuthMethod Type of Redfish authentication method= . > + @param[out] UserId The pointer to store the returned Use= rId > string. > + @param[out] Password The pointer to store the returned Pas= sword > 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/RedfishClientPkg/PrivateLibrary/RedfishLib/edk2libredfish/include/redfi= sh > .h > b/RedfishClientPkg/PrivateLibrary/RedfishLib/edk2libredfish/include/redfi= sh > .h > new file mode 100644 > index 00000000..e9b9b3fa > --- /dev/null > +++ > b/RedfishClientPkg/PrivateLibrary/RedfishLib/edk2libredfish/include/redfi= sh > .h > @@ -0,0 +1,25 @@ > +/** @file > + This file is cloned from DMTF libredfish library tag v1.0.0 and mainta= ined > + 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
> + > + SPDX-License-Identifier: BSD-2-Clause-Patent > + > +**/ > + > +#ifndef LIBREDFISH_REDFISH_H_ > +#define LIBREDFISH_REDFISH_H_ > + > +#include > +#include > +#include > + > +#endif > diff --git > a/RedfishClientPkg/PrivateLibrary/RedfishLib/edk2libredfish/include/redfi= sh > Payload.h > b/RedfishClientPkg/PrivateLibrary/RedfishLib/edk2libredfish/include/redfi= sh > Payload.h > new file mode 100644 > index 00000000..44515306 > --- /dev/null > +++ > b/RedfishClientPkg/PrivateLibrary/RedfishLib/edk2libredfish/include/redfi= sh > Payload.h > @@ -0,0 +1,106 @@ > +/** @file > + This file is cloned from DMTF libredfish library tag v1.0.0 and mainta= ined > + 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
> + > + SPDX-License-Identifier: BSD-2-Clause-Patent > + > +**/ > + > +#ifndef LIBREDFISH_REDFISH_PAYLOAD_H_ > +#define LIBREDFISH_REDFISH_PAYLOAD_H_ > + > +#include > + > +#include > +#include > +#include > + > +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/RedfishClientPkg/PrivateLibrary/RedfishLib/edk2libredfish/include/redfi= sh > Service.h > b/RedfishClientPkg/PrivateLibrary/RedfishLib/edk2libredfish/include/redfi= sh > Service.h > new file mode 100644 > index 00000000..5c13b682 > --- /dev/null > +++ > b/RedfishClientPkg/PrivateLibrary/RedfishLib/edk2libredfish/include/redfi= sh > Service.h > @@ -0,0 +1,151 @@ > +/** @file > + This file is cloned from DMTF libredfish library tag v1.0.0 and mainta= ined > + 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
> + > + SPDX-License-Identifier: BSD-2-Clause-Patent > + > +**/ > + > +#ifndef LIBREDFISH_REDFISH_SERVICE_H_ > +#define LIBREDFISH_REDFISH_SERVICE_H_ > + > +#include > + > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > + > +#include > + > +#include > +#include > + > +#include > + > +typedef struct { > + char *host; > + json_t *versions; > + unsigned int flags; > + char *sessionToken; > + char *basicAuthStr; > + // > + // point to the part in above "host" field, which will be put i= nto > + // 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 Redfis= h > 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 s= pec) > +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/RedfishClientPkg/PrivateLibrary/RedfishLib/edk2libredfish/include/redpa= t > h.h > b/RedfishClientPkg/PrivateLibrary/RedfishLib/edk2libredfish/include/redpa= t > h.h > new file mode 100644 > index 00000000..c1a1568b > --- /dev/null > +++ > b/RedfishClientPkg/PrivateLibrary/RedfishLib/edk2libredfish/include/redpa= t > h.h > @@ -0,0 +1,49 @@ > +/** @file > + This file is cloned from DMTF libredfish library tag v1.0.0 and mainta= ined > + 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
> + > + SPDX-License-Identifier: BSD-2-Clause-Patent > + > +**/ > + > +#ifndef LIBREDFISH_REDPATH_H_ > +#define LIBREDFISH_REDPATH_H_ > + > +#include > + > +#include > + > +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/RedfishClientPkg/PrivateLibrary/RedfishLib/RedfishLib.c > b/RedfishClientPkg/PrivateLibrary/RedfishLib/RedfishLib.c > new file mode 100644 > index 00000000..9f9d3779 > --- /dev/null > +++ b/RedfishClientPkg/PrivateLibrary/RedfishLib/RedfishLib.c > @@ -0,0 +1,1033 @@ > +/** @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.
> + (C) Copyright 2021 Hewlett Packard Enterprise Development LP
> + > + SPDX-License-Identifier: BSD-2-Clause-Patent > + > +**/ > + > +#include "RedfishMisc.h" > + > +/** > + This function uses REST EX protocol provided in RedfishConfigServiceIn= fo. > + 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 E= FI > 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 =3D NULL; > + UserId =3D NULL; > + Password =3D NULL; > + > + // > + // Check Input Parameters. > + // > + if (RedfishConfigServiceInfo =3D=3D NULL) { > + return NULL; > + } > + > + // > + // Get Authentication Configuration. > + // > + Status =3D RedfishGetAuthInfo (&AuthMethod, &UserId, &Password); > + if (EFI_ERROR (Status)) { > + goto ON_EXIT; > + } > + > + // > + // Create a redfish service node based on Redfish network host interfa= ce. > + // > + RedfishService =3D RedfishCreateLibredfishService ( > + RedfishConfigServiceInfo, > + AuthMethod, > + UserId, > + Password > + ); > + > +ON_EXIT: > + if (UserId !=3D NULL) { > + FreePool (UserId); > + } > + > + if (Password !=3D NULL) { > + FreePool (Password); > + } > + > + return RedfishService; > +} > + > +/** > + Free the Service and all its related resources. > + > + @param[in] RedfishService The Service to access the Redfish res= ources. > + > +**/ > +VOID > +EFIAPI > +RedfishCleanupService ( > + IN REDFISH_SERVICE RedfishService > + ) > +{ > + if (RedfishService =3D=3D 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 =3D 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 =3D=3D 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 =3D=3D NULL) { > + return NULL; > + } > + > + return ((redfishPayload *)Payload)->json; > +} > + > +/** > + Fill the input RedPath string with system UUID from SMBIOS table or us= e > the customized > + ID if FromSmbios =3D=3D 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=3D%g]" or "Systems[UUID~%g]" to fill t= he > UUID value. > + > + Example: > + Use "/v1/Systems[UUID=3D%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 hap= pens. > + > +**/ > +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 =3D=3D NULL) { > + return NULL; > + } > + > + // > + // Find system UUID from SMBIOS table. > + // > + if (FromSmbios) { > + Status =3D NetLibGetSystemGuid (&SystemUuid); > + if (EFI_ERROR (Status)) { > + return NULL; > + } > + > + // AsciiStrLen ("xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx") =3D 36 > + BufSize =3D AsciiStrSize (RedPath) + AsciiStrLen ("XXXXXXXX-XXXX-XXX= X- > XXXX-XXXXXXXXXXXX"); > + } else { > + BufSize =3D AsciiStrSize (RedPath) + AsciiStrLen (IdString); > + } > + > + RetRedPath =3D AllocateZeroPool (BufSize); > + if (RetRedPath =3D=3D 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 resour= ce, must > start > + from the root node. > + @param[out] RedResponse Pointer to the Redfish response da= ta. > + > + @retval EFI_SUCCESS The opeartion is successful, indicates= the HTTP > StatusCode is not > + NULL and the value is 2XX. The corresp= onding redfish > resource has > + been returned in Payload within RedRes= ponse. > + @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 Sta= tusCode, Headers > and Payload > + within RedResponse: > + 1. If the returned Payload is NULL, in= dicates any error > happen. > + 2. If the returned StatusCode is NULL,= indicates any error > happen. > + 3. If the returned StatusCode is not 2= XX, indicates any error > happen. > +**/ > +EFI_STATUS > +EFIAPI > +RedfishGetByService ( > + IN REDFISH_SERVICE RedfishService, > + IN CONST CHAR8 *RedPath, > + OUT REDFISH_RESPONSE *RedResponse > + ) > +{ > + if ((RedfishService =3D=3D NULL) || (RedPath =3D=3D NULL) || (RedRespo= nse =3D=3D > NULL)) { > + return EFI_INVALID_PARAMETER; > + } > + > + ZeroMem (RedResponse, sizeof (REDFISH_RESPONSE)); > + > + RedResponse->Payload =3D (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 =3D=3D NULL) || (RedResponse->StatusCode =3D= =3D > NULL)) { > + return EFI_DEVICE_ERROR; > + } > + > + // > + // 3. If the returned StatusCode is not 2XX, indicates any error happe= n. > + // NOTE: If there is any error message returned from server, it wil= l 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 resource= s. > + @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 corresp= onding redfish > resource has > + been returned in Payload within RedRes= ponse. > + @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 Sta= tusCode, Headers > and Payload > + within RedResponse: > + 1. If the returned Payload is NULL, in= dicates any error > happen. > + 2. If the returned StatusCode is NULL,= indicates any error > happen. > + 3. If the returned StatusCode is not 2= XX, 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 =3D=3D NULL) || (Uri =3D=3D NULL) || (RedResponse = =3D=3D NULL)) { > + return EFI_INVALID_PARAMETER; > + } > + > + ZeroMem (RedResponse, sizeof (REDFISH_RESPONSE)); > + > + JsonValue =3D getUriFromService (RedfishService, Uri, &RedR= esponse- > >StatusCode); > + RedResponse->Payload =3D 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 =3D=3D NULL) || (RedResponse->StatusCode =3D= =3D > NULL)) { > + return EFI_DEVICE_ERROR; > + } > + > + // > + // 3. If the returned StatusCode is not 2XX, indicates any error happe= n. > + // NOTE: If there is any error message returned from server, it wil= l 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 r= esource > 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 dir= ectly. > + 2. The HTTP StatusCode is not NULL and= the value is 2XX, > + indicates the corresponding redfish re= source 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 Sta= tusCode, Headers > and Payload > + within RedResponse: > + 1. If the returned Payload is NULL, in= dicates any error > happen. > + 2. If StatusCode is not NULL and the r= eturned value of > StatusCode > + is not 2XX, indicates any error hap= pen. > +**/ > +EFI_STATUS > +EFIAPI > +RedfishGetByPayload ( > + IN REDFISH_PAYLOAD Payload, > + IN CONST CHAR8 *RedPath, > + OUT REDFISH_RESPONSE *RedResponse > + ) > +{ > + if ((Payload =3D=3D NULL) || (RedPath =3D=3D NULL) || (RedResponse =3D= =3D NULL)) { > + return EFI_INVALID_PARAMETER; > + } > + > + ZeroMem (RedResponse, sizeof (REDFISH_RESPONSE)); > + > + RedResponse->Payload =3D (REDFISH_PAYLOAD)getPayloadForPathString > (Payload, RedPath, &(RedResponse->StatusCode)); > + > + // > + // 1. If the returned Payload is NULL, indicates any error happen. > + // > + if (RedResponse->Payload =3D=3D NULL) { > + return EFI_DEVICE_ERROR; > + } > + > + // > + // 2. If StatusCode is not NULL and the returned value of StatusCode i= s not > 2XX, indicates any > + // error happen. > + // NOTE: If there is any error message returned from server, it wil= l be > returned in > + // Payload within RedResponse. > + // > + if ((RedResponse->StatusCode !=3D 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 prope= rties > within > + the target resource are represented in the input Content, properties n= ot > 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 resou= rce. > + @param[in] Content JSON represented properties to be = update. > + @param[out] RedResponse Pointer to the Redfish response da= ta. > + > + @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 serve= r 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 Sta= tusCode, Headers > and Payload > + within RedResponse: > + 1. If the returned StatusCode is NULL,= indicates any error > happen. > + 2. If the returned StatusCode is not N= ULL 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 =3D EFI_SUCCESS; > + JsonValue =3D NULL; > + > + if ((RedfishService =3D=3D NULL) || (Uri =3D=3D NULL) || (Content =3D= =3D NULL) || > (RedResponse =3D=3D NULL)) { > + return EFI_INVALID_PARAMETER; > + } > + > + ZeroMem (RedResponse, sizeof (REDFISH_RESPONSE)); > + > + JsonValue =3D (EDKII_JSON_VALUE)patchUriFromService ( > + RedfishService, > + Uri, > + Content, > + &(RedResponse->StatusCode) > + ); > + > + // > + // 1. If the returned StatusCode is NULL, indicates any error happen. > + // > + if (RedResponse->StatusCode =3D=3D NULL) { > + Status =3D 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 wil= l be > returned in > + // Payload within RedResponse. > + // > + if ((*(RedResponse->StatusCode) < HTTP_STATUS_200_OK) || \ > + (*(RedResponse->StatusCode) > > HTTP_STATUS_206_PARTIAL_CONTENT)) > + { > + Status =3D EFI_DEVICE_ERROR; > + } > + > +ON_EXIT: > + if (JsonValue !=3D NULL) { > + RedResponse->Payload =3D createRedfishPayload (JsonValue, > RedfishService); > + if (RedResponse->Payload =3D=3D NULL) { > + // > + // Ignore the error when create RedfishPayload, just free the Json= Value > 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 serve= r 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 Sta= tusCode, Headers > and Payload > + within RedResponse: > + 1. If the returned StatusCode is NULL,= indicates any error > happen. > + 2. If the returned StatusCode is not N= ULL 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 =3D=3D NULL) || (Payload =3D=3D NULL) || (RedResponse =3D= =3D NULL)) { > + return EFI_INVALID_PARAMETER; > + } > + > + ZeroMem (RedResponse, sizeof (REDFISH_RESPONSE)); > + > + RedResponse->Payload =3D (REDFISH_PAYLOAD)patchPayload ( > + Target, > + Payload, > + &(RedResponse->StatusCode) > + ); > + > + // > + // 1. If the returned StatusCode is NULL, indicates any error happen. > + // > + if (RedResponse->StatusCode =3D=3D 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 wil= l 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 whi= ch > 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 Collectio= n. > + @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 serve= r 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 Sta= tusCode, Headers > and Payload > + within RedResponse: > + 1. If the returned StatusCode is NULL,= indicates any error > happen. > + 2. If the returned StatusCode is not N= ULL 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 =3D=3D NULL) || (Payload =3D=3D NULL) || (RedResponse =3D= =3D NULL)) { > + return EFI_INVALID_PARAMETER; > + } > + > + ZeroMem (RedResponse, sizeof (REDFISH_RESPONSE)); > + > + RedResponse->Payload =3D (REDFISH_PAYLOAD)postPayload ( > + Target, > + Payload, > + &(RedResponse->StatusCode) > + ); > + > + // > + // 1. If the returned StatusCode is NULL, indicates any error happen. > + // > + if (RedResponse->StatusCode =3D=3D 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 wil= l 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 whi= ch > is addressed > + by input Uri (only the relative path is required). The corresponding r= edfish > 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 resou= rce. > + @param[out] RedResponse Pointer to the Redfish response da= ta. > + > + @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 Sta= tusCode, Headers > and Payload > + within RedResponse: > + 1. If the returned StatusCode is NULL,= indicates any error > happen. > + 2. If the returned StatusCode is not N= ULL 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 =3D EFI_SUCCESS; > + JsonValue =3D NULL; > + > + if ((RedfishService =3D=3D NULL) || (Uri =3D=3D NULL) || (RedResponse = =3D=3D NULL)) { > + return EFI_INVALID_PARAMETER; > + } > + > + ZeroMem (RedResponse, sizeof (REDFISH_RESPONSE)); > + > + JsonValue =3D (EDKII_JSON_VALUE)deleteUriFromService ( > + RedfishService, > + Uri, > + &(RedResponse->StatusCode) > + ); > + > + // > + // 1. If the returned StatusCode is NULL, indicates any error happen. > + // > + if (RedResponse->StatusCode =3D=3D NULL) { > + Status =3D 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 wil= l be > returned in > + // Payload within RedResponse. > + // > + if ((*(RedResponse->StatusCode) < HTTP_STATUS_200_OK) || \ > + (*(RedResponse->StatusCode) > > HTTP_STATUS_206_PARTIAL_CONTENT)) > + { > + Status =3D EFI_DEVICE_ERROR; > + } > + > +ON_EXIT: > + if (JsonValue !=3D NULL) { > + RedResponse->Payload =3D createRedfishPayload (JsonValue, > RedfishService); > + if (RedResponse->Payload =3D=3D NULL) { > + // > + // Ignore the error when create RedfishPayload, just free the Json= Value > 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 =3D 200; > + if (String =3D=3D NULL) { > + return; > + } > + > + DEBUG ((DEBUG_INFO, "JSON text:\n")); > + NextFraction =3D String; > + StrLen =3D AsciiStrLen (String); > + if (StrLen =3D=3D 0) { > + return; > + } > + > + for (Count =3D 0; Count < (StrLen / StringFractionSize); Count++) { > + BackupChar =3D *(NextFraction + StringFrac= tionSize); > + *(NextFraction + StringFractionSize) =3D 0; > + DEBUG ((DEBUG_INFO, "%a", NextFraction)); > + *(NextFraction + StringFractionSize) =3D BackupChar; > + NextFraction +=3D StringFractionSize; > + } > + > + if ((StrLen % StringFractionSize) !=3D 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 =3D JsonDumpString (JsonValue, 0); > + if (String =3D=3D 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 =3D NULL; > + String =3D NULL; > + > + if (Payload =3D=3D NULL) { > + return; > + } > + > + JsonValue =3D RedfishJsonInPayload (Payload); > + if (JsonValue =3D=3D NULL) { > + return; > + } > + > + String =3D JsonDumpString (JsonValue, 0); > + if (String =3D=3D NULL) { > + return; > + } > + > + RedfishDumpJsonStringFractions (String); > + FreePool (String); > +} > + > +/** > + This function will cleanup the HTTP header and Redfish payload resourc= es. > + > + @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 !=3D NULL) { > + FreePool (StatusCode); > + StatusCode =3D NULL; > + } > + > + if ((HeaderCount !=3D 0) && (Headers !=3D NULL)) { > + HttpFreeHeaderFields (Headers, HeaderCount); > + Headers =3D NULL; > + } > + > + if (Payload !=3D NULL) { > + RedfishCleanupPayload (Payload); > + Payload =3D 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 =3D=3D NULL) || (OdataTypeName =3D=3D NULL)) { > + return FALSE; > + } > + > + JsonValue =3D RedfishJsonInPayload (Payload); > + if (!JsonValueIsObject (JsonValue)) { > + return FALSE; > + } > + > + OdataType =3D JsonObjectGetValue (JsonValueGetObject (JsonValue), > "@odata.type"); > + if (!JsonValueIsString (OdataType) || (JsonValueGetAsciiString (OdataT= ype) > =3D=3D NULL)) { > + return FALSE; > + } > + > + for (Index =3D 0; Index < OdataTypeMappingListSize; Index++) { > + if ((AsciiStrCmp (OdataTypeMappingList[Index].OdataTypeName, > OdataTypeName) =3D=3D 0) && > + (AsciiStrCmp (OdataTypeMappingList[Index].OdataType, > JsonValueGetAsciiString (OdataType)) =3D=3D 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 Collec= tionSize > + @return EFI_INVALID_PARAMETER The payload is not a collection. > +**/ > +EFI_STATUS > +RedfishGetCollectionSize ( > + IN REDFISH_PAYLOAD Payload, > + IN UINTN *CollectionSize > + ) > +{ > + if ((Payload =3D=3D NULL) || (CollectionSize =3D=3D NULL)) { > + return EFI_INVALID_PARAMETER; > + } > + > + if (!RedfishIsPayloadCollection (Payload)) { > + return EFI_INVALID_PARAMETER; > + } > + > + *CollectionSize =3D (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 =3D (VOID *)getPayloadByIndex (Payload, Index, > &RedfishResponse.StatusCode); > + if ((PayloadReturn =3D=3D 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 =3D=3D NULL) { > + return EFI_INVALID_PARAMETER; > + } > + > + Status =3D RedfishGetByService (RedfishService, Redpath, &TempResponse= ); > + if (EFI_ERROR (Status)) { > + return Status; > + } > + > + if (Response =3D=3D 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/RedfishClientPkg/PrivateLibrary/RedfishLib/RedfishMisc.c > b/RedfishClientPkg/PrivateLibrary/RedfishLib/RedfishMisc.c > new file mode 100644 > index 00000000..0eb23196 > --- /dev/null > +++ b/RedfishClientPkg/PrivateLibrary/RedfishLib/RedfishMisc.c > @@ -0,0 +1,206 @@ > +/** @file > + Internal Functions for RedfishLib. > + > + Copyright (c) 2019, Intel Corporation. All rights reserved.
> + (C) Copyright 2021 Hewlett Packard Enterprise Development LP
> + > + SPDX-License-Identifier: BSD-2-Clause-Patent > + > +**/ > + > +#include "RedfishMisc.h" > + > +EDKII_REDFISH_CREDENTIAL_PROTOCOL *mCredentialProtocol =3D 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 =3D=3D NULL) || (ServiceVersionStr =3D=3D NULL)) { > + return EFI_INVALID_PARAMETER; > + } > + > + Redfish =3D (redfishService *)RedfishService; > + if (Redfish->versions =3D=3D NULL) { > + return EFI_INVALID_PARAMETER; > + } > + > + KeysArray =3D JsonObjectGetKeys (Redfish->versions, &KeysNum); > + if ((KeysNum =3D=3D 0) || (KeysArray =3D=3D NULL)) { > + return EFI_NOT_FOUND; > + } > + > + *ServiceVersionStr =3D *KeysArray; > + return EFI_SUCCESS; > +} > + > +/** > + Creates a REDFISH_SERVICE which can be later used to access the Redfis= h > 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 Red= fish > session > + login is configured to use. > + > + @param[in] RedfishConfigServiceInfo Redfish service information the E= FI > Redfish > + feature driver communicates with. > + @param[in] AuthMethod None, HTTP basic auth, or Redfish session log= in. > + @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 =3D NULL; > + > + ZeroMem (&Auth, sizeof (Auth)); > + if (AuthMethod =3D=3D AuthMethodHttpBasic) { > + Auth.authType =3D REDFISH_AUTH_BASIC; > + } else if (AuthMethod =3D=3D AuthMethodRedfishSession) { > + Auth.authType =3D REDFISH_AUTH_SESSION; > + } > + > + Auth.authCodes.userPass.username =3D UserId; > + Auth.authCodes.userPass.password =3D Password; > + > + Flags =3D REDFISH_FLAG_SERVICE_NO_VERSION_DOC; > + > + if (AuthMethod !=3D AuthMethodNone) { > + Redfish =3D createServiceEnumerator (RedfishConfigServiceInfo, NULL, > &Auth, (unsigned int)Flags); > + } else { > + Redfish =3D createServiceEnumerator (RedfishConfigServiceInfo, NULL, > NULL, (unsigned int)Flags); > + } > + > + // > + // Zero the Password after use. > + // > + if (Password !=3D 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 pointe= d by > UserId > + and Password. > + > + @param[out] AuthMethod Type of Redfish authentication method= . > + @param[out] UserId The pointer to store the returned Use= rId > string. > + @param[out] Password The pointer to store the returned Pas= sword > 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 =3D=3D NULL) || (UserId =3D=3D NULL) || (Password =3D= =3D NULL)) { > + return EFI_INVALID_PARAMETER; > + } > + > + // > + // Locate Redfish Credential Protocol. > + // > + if (mCredentialProtocol =3D=3D NULL) { > + Status =3D gBS->LocateProtocol (&gEdkIIRedfishCredentialProtocolGuid= , > NULL, (VOID **)&mCredentialProtocol); > + if (EFI_ERROR (Status)) { > + return EFI_UNSUPPORTED; > + } > + } > + > + ASSERT (mCredentialProtocol !=3D NULL); > + > + Status =3D 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 "/Registrie= s" > + @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 =3D=3D NULL) || (ServiceVerisonStr =3D=3D NULL) || (Url = =3D=3D NULL) || > (Id =3D=3D NULL)) { > + return EFI_INVALID_PARAMETER; > + } > + > + RedpathSize =3D AsciiStrLen ("/") + > + AsciiStrLen (ServiceVerisonStr) + > + AsciiStrLen (Url) + > + AsciiStrLen ("[Id=3D]") + > + AsciiStrLen (Id) + 1; > + *Redpath =3D AllocatePool (RedpathSize); > + if (*Redpath =3D=3D NULL) { > + return EFI_OUT_OF_RESOURCES; > + } > + > + AsciiSPrint (*Redpath, RedpathSize, "/%a%a[Id=3D%a]", ServiceVerisonSt= r, > Url, Id); > + return EFI_SUCCESS; > +} > diff --git > a/RedfishClientPkg/PrivateLibrary/RedfishLib/edk2libredfish/src/payload.c > b/RedfishClientPkg/PrivateLibrary/RedfishLib/edk2libredfish/src/payload.c > new file mode 100644 > index 00000000..7ceb63ac > --- /dev/null > +++ > b/RedfishClientPkg/PrivateLibrary/RedfishLib/edk2libredfish/src/payload.c > @@ -0,0 +1,812 @@ > +/** @file > + This file is cloned from DMTF libredfish library tag v1.0.0 and mainta= ined > + 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
> + > + SPDX-License-Identifier: BSD-2-Clause-Patent > + > +**/ > +#include > + > +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 =3D json_object_get (payload->json, "Members"); > + count =3D json_object_get (payload->json, "Members@odata.count"); > + return ((members !=3D NULL) && (count !=3D NULL)); > +} > + > +size_t > +getCollectionSize ( > + redfishPayload *payload > + ) > +{ > + json_t *members; > + json_t *count; > + > + if (!payload || !json_is_object (payload->json)) { > + return 0; > + } > + > + members =3D json_object_get (payload->json, "Members"); > + count =3D 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 =3D 0; > + > + if (!payload) { > + return NULL; > + } > + > + if (prettyPrint) { > + flags =3D JSON_INDENT (2); > + } > + > + return json_dumps (payload->json, flags); > +} > + > +redfishPayload * > +createRedfishPayload ( > + json_t *value, > + redfishService *service > + ) > +{ > + redfishPayload *payload; > + > + payload =3D (redfishPayload *)malloc (sizeof (redfishPayload)); > + if (payload !=3D NULL) { > + payload->json =3D value; > + payload->service =3D 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 =3D=3D NULL)) { > + return NULL; > + } > + > + *StatusCode =3D NULL; > + > + value =3D json_object_get (payload->json, nodeName); > + if (value =3D=3D NULL) { > + return NULL; > + } > + > + json_incref (value); > + if (json_object_size (value) =3D=3D 1) { > + odataId =3D json_object_get (value, "@odata.id"); > + if (odataId !=3D NULL) { > + json_incref (odataId); > + uri =3D json_string_value (odataId); > + json_decref (value); > + value =3D getUriFromService (payload->service, uri, StatusCode); > + json_decref (odataId); > + if ((value =3D=3D NULL) || (*StatusCode =3D=3D NULL)) { > + return NULL; > + } > + } > + } > + > + if ((*StatusCode =3D=3D NULL) || ((**StatusCode >=3D HTTP_STATUS_200_O= K) > && (**StatusCode <=3D HTTP_STATUS_206_PARTIAL_CONTENT))) { > + if (json_is_string (value)) { > + odataId =3D json_object (); > + json_object_set (odataId, nodeName, value); > + json_decref (value); > + value =3D odataId; > + } > + } > + > + return createRedfishPayload (value, payload->service); > +} > + > +redfishPayload * > +getPayloadByIndex ( > + redfishPayload *payload, > + size_t index, > + EFI_HTTP_STATUS_CODE **StatusCode > + ) > +{ > + json_t *value =3D NULL; > + json_t *odataId; > + const char *uri; > + BOOLEAN FromServerFlag =3D FALSE; > + > + if (!payload || (StatusCode =3D=3D NULL)) { > + return NULL; > + } > + > + *StatusCode =3D NULL; > + > + if (isPayloadCollection (payload)) { > + redfishPayload *members =3D getPayloadByNodeName (payload, > "Members", StatusCode); > + if (((*StatusCode =3D=3D NULL) && (members =3D=3D NULL)) || > + ((*StatusCode !=3D NULL) && ((**StatusCode < HTTP_STATUS_200_OK) > || (**StatusCode > HTTP_STATUS_206_PARTIAL_CONTENT)))) > + { > + return members; > + } > + > + if (*StatusCode !=3D NULL) { > + // > + // The Payload (members) are retrived from server. > + // > + FreePool (*StatusCode); > + *StatusCode =3D NULL; > + FromServerFlag =3D TRUE; > + } > + > + redfishPayload *ret =3D getPayloadByIndex (members, index, StatusCo= de); > + if ((*StatusCode =3D=3D NULL) && (ret !=3D NULL) && FromServerFlag) = { > + // > + // In such a case, the Redfish resource is parsed from the input p= ayload > (members) directly. > + // Since the members are retrived from server, we still return > HTTP_STATUS_200_OK. > + // > + *StatusCode =3D AllocateZeroPool (sizeof (EFI_HTTP_STATUS_CODE)); > + if (*StatusCode =3D=3D NULL) { > + ret =3D NULL; > + } else { > + **StatusCode =3D 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 =3D json_array_get (payload->json, index); > + } else if (json_is_object (payload->json)) { > + value =3D json_object_get_by_index (payload->json, index); > + } > + > + if (value =3D=3D NULL) { > + return NULL; > + } > + > + json_incref (value); > + if (json_object_size (value) =3D=3D 1) { > + odataId =3D json_object_get (value, "@odata.id"); > + if (odataId !=3D NULL) { > + uri =3D json_string_value (odataId); > + json_decref (value); > + value =3D getUriFromService (payload->service, uri, StatusCode); > + if (value =3D=3D NULL) { > + return NULL; > + } > + } > + } > + > + return createRedfishPayload (value, payload->service); > +} > + > +redfishPayload * > +getPayloadForPath ( > + redfishPayload *payload, > + redPathNode *redpath, > + EFI_HTTP_STATUS_CODE **StatusCode > + ) > +{ > + redfishPayload *ret =3D NULL; > + redfishPayload *tmp; > + > + if (!payload || !redpath || (StatusCode =3D=3D NULL)) { > + return NULL; > + } > + > + *StatusCode =3D NULL; > + BOOLEAN FromServerFlag =3D FALSE; > + > + if (redpath->nodeName) { > + ret =3D getPayloadByNodeName (payload, redpath->nodeName, > StatusCode); > + if (((*StatusCode =3D=3D NULL) && (ret =3D=3D NULL)) || > + ((*StatusCode !=3D 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 >=3D 1); > + ret =3D getPayloadByIndex (payload, redpath->index - 1, StatusCode); > + if (((*StatusCode =3D=3D NULL) && (ret =3D=3D NULL)) || > + ((*StatusCode !=3D NULL) && ((**StatusCode < HTTP_STATUS_200_OK) > || (**StatusCode > HTTP_STATUS_206_PARTIAL_CONTENT)))) > + { > + // > + // Any error happen, return directly. > + // > + return ret; > + } > + } else if (redpath->op) { > + ret =3D getOpResult (payload, redpath->propName, redpath->op, redpat= h- > >value, StatusCode); > + if (((*StatusCode =3D=3D NULL) && (ret =3D=3D NULL)) || > + ((*StatusCode !=3D 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 =3D=3D NULL) || (ret =3D=3D NULL)) { > + return ret; > + } else { > + if (*StatusCode !=3D NULL) { > + FreePool (*StatusCode); > + *StatusCode =3D NULL; > + FromServerFlag =3D TRUE; > + } > + > + tmp =3D getPayloadForPath (ret, redpath->next, StatusCode); > + if ((*StatusCode =3D=3D NULL) && (tmp !=3D NULL) && FromServerFlag) = { > + // > + // In such a case, the Redfish resource is parsed from the input p= ayload > (ret) directly. > + // Since the ret are retrived from server, we still return > HTTP_STATUS_200_OK. > + // > + *StatusCode =3D AllocateZeroPool (sizeof (EFI_HTTP_STATUS_CODE)); > + if (*StatusCode =3D=3D NULL) { > + tmp =3D NULL; > + } else { > + **StatusCode =3D 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 =3D=3D NULL)) { > + return NULL; > + } > + > + *StatusCode =3D NULL; > + > + redpath =3D parseRedPath (string); > + if (redpath =3D=3D NULL) { > + return NULL; > + } > + > + ret =3D 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 =3D=3D NULL)) { > + return NULL; > + } > + > + *StatusCode =3D NULL; > + > + json =3D json_object_get (target->json, "@odata.id"); > + if (json =3D=3D NULL) { > + return NULL; > + } > + > + uri =3D strdup (json_string_value (json)); > + > + content =3D json_dumps (payload->json, 0); > + json_decref (json); > + > + json =3D patchUriFromService (target->service, uri, content, StatusCod= e); > + free (uri); > + free (content); > + if (json =3D=3D 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 =3D=3D NULL)) { > + return NULL; > + } > + > + *StatusCode =3D NULL; > + > + json =3D json_object_get (target->json, "@odata.id"); > + if (json =3D=3D NULL) { > + json =3D json_object_get (target->json, "target"); > + if (json =3D=3D NULL) { > + return NULL; > + } > + } > + > + uri =3D strdup (json_string_value (json)); > + json =3D postUriFromService (target->service, uri, data, dataSize, > contentType, StatusCode); > + free (uri); > + if (json =3D=3D 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 =3D=3D NULL)) { > + return NULL; > + } > + > + *StatusCode =3D NULL; > + > + if (!json_is_object (payload->json)) { > + return NULL; > + } > + > + content =3D payloadToString (payload, false); > + ret =3D postContentToPayload (target, content, strlen (content), N= ULL, > 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 =3D 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 =3D getPayloadByNodeName (payload, propName, StatusCode); > + if (((*StatusCode =3D=3D NULL) && (prop =3D=3D NULL)) || > + ((*StatusCode !=3D NULL) && ((**StatusCode < HTTP_STATUS_200_OK) |= | > (**StatusCode > HTTP_STATUS_206_PARTIAL_CONTENT)))) > + { > + return prop; > + } > + > + stringProp =3D prop->json; > + jsonType =3D json_get_type (prop->json); > + switch (jsonType) { > + case JSON_OBJECT: > + stringProp =3D json_object_get (prop->json, propName); > + case JSON_STRING: > + if (strcmp (op, "=3D") =3D=3D 0) { > + propStr =3D json_string_value (stringProp); > + if (propStr =3D=3D NULL) { > + cleanupPayload (prop); > + return NULL; > + } > + > + ret =3D (strcmp (propStr, value) =3D=3D 0); > + } else if (strcmp (op, "~") =3D=3D 0) { > + propStr =3D json_string_value (stringProp); > + if (propStr =3D=3D NULL) { > + cleanupPayload (prop); > + return NULL; > + } > + > + ret =3D (strcasecmp (propStr, value) =3D=3D 0); > + } > + > + break; > + case JSON_TRUE: > + if (strcmp (op, "=3D") =3D=3D 0) { > + ret =3D (strcmp (value, "true") =3D=3D 0); > + } > + > + break; > + case JSON_FALSE: > + if (strcmp (op, "=3D") =3D=3D 0) { > + ret =3D (strcmp (value, "false") =3D=3D 0); > + } > + > + break; > + case JSON_INTEGER: > + intPropVal =3D json_integer_value (prop->json); > + intVal =3D strtoll (value, NULL, 0); > + if (strcmp (op, "=3D") =3D=3D 0) { > + ret =3D (intPropVal =3D=3D intVal); > + } else if (strcmp (op, "<") =3D=3D 0) { > + ret =3D (intPropVal < intVal); > + } else if (strcmp (op, ">") =3D=3D 0) { > + ret =3D (intPropVal > intVal); > + } else if (strcmp (op, "<=3D") =3D=3D 0) { > + ret =3D (intPropVal <=3D intVal); > + } else if (strcmp (op, ">=3D") =3D=3D 0) { > + ret =3D (intPropVal >=3D 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 =3D 0; > + size_t i; > + > + validMax =3D getCollectionSize (payload); > + if (validMax =3D=3D 0) { > + return NULL; > + } > + > + valid =3D (redfishPayload **)calloc (validMax, sizeof (redfishPayload = *)); > + if (valid =3D=3D NULL) { > + return NULL; > + } > + > + /*Technically getPayloadByIndex would do this, but this optimizes thin= gs*/ > + members =3D getPayloadByNodeName (payload, "Members", StatusCode); > + if (((*StatusCode =3D=3D NULL) && (members =3D=3D NULL)) || > + ((*StatusCode !=3D NULL) && ((**StatusCode < HTTP_STATUS_200_OK) |= | > (**StatusCode > HTTP_STATUS_206_PARTIAL_CONTENT)))) > + { > + return members; > + } > + > + for (i =3D 0; i < validMax; i++) { > + if (*StatusCode !=3D NULL) { > + FreePool (*StatusCode); > + *StatusCode =3D NULL; > + } > + > + tmp =3D getPayloadByIndex (members, i, StatusCode); > + if (((*StatusCode =3D=3D NULL) && (tmp =3D=3D NULL)) || > + ((*StatusCode !=3D NULL) && ((**StatusCode < HTTP_STATUS_200_OK) > || (**StatusCode > HTTP_STATUS_206_PARTIAL_CONTENT)))) > + { > + return tmp; > + } > + > + if (*StatusCode !=3D NULL) { > + FreePool (*StatusCode); > + *StatusCode =3D NULL; > + } > + > + valid[validCount] =3D getOpResult (tmp, propName, op, value, StatusC= ode); > + > + /* > + if ((*StatusCode =3D=3D NULL && valid[validCount] =3D=3D NULL) || > + (*StatusCode !=3D NULL && (**StatusCode < HTTP_STATUS_200_OK || > **StatusCode > HTTP_STATUS_206_PARTIAL_CONTENT))) { > + return valid[validCount]; > + } > + */ > + if (valid[validCount] !=3D NULL) { > + validCount++; > + } else { > + cleanupPayload (tmp); > + } > + } > + > + cleanupPayload (members); > + if (validCount =3D=3D 0) { > + free (valid); > + return NULL; > + } > + > + if (validCount =3D=3D 1) { > + ret =3D valid[0]; > + free (valid); > + return ret; > + } else { > + ret =3D 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 =3D 0; > + size_t i; > + > + validMax =3D json_array_size (payload->json); > + if (validMax =3D=3D 0) { > + return NULL; > + } > + > + valid =3D (redfishPayload **)calloc (validMax, sizeof (redfishPayload = *)); > + if (valid =3D=3D NULL) { > + return NULL; > + } > + > + for (i =3D 0; i < validMax; i++) { > + if (*StatusCode !=3D NULL) { > + FreePool (*StatusCode); > + *StatusCode =3D NULL; > + } > + > + tmp =3D getPayloadByIndex (payload, i, StatusCode); > + if (((*StatusCode =3D=3D NULL) && (tmp =3D=3D NULL)) || > + ((*StatusCode !=3D NULL) && ((**StatusCode < HTTP_STATUS_200_OK) > || (**StatusCode > HTTP_STATUS_206_PARTIAL_CONTENT)))) > + { > + return tmp; > + } > + > + if (*StatusCode !=3D NULL) { > + FreePool (*StatusCode); > + *StatusCode =3D NULL; > + } > + > + valid[validCount] =3D getOpResult (tmp, propName, op, value, StatusC= ode); > + > + /* > + if ((*StatusCode =3D=3D NULL && valid[validCount] =3D=3D NULL) || > + (*StatusCode !=3D NULL && (**StatusCode < HTTP_STATUS_200_OK || > **StatusCode > HTTP_STATUS_206_PARTIAL_CONTENT))) { > + return valid[validCount]; > + } > + */ > + > + if (valid[validCount] !=3D NULL) { > + validCount++; > + } else { > + cleanupPayload (tmp); > + } > + } > + > + if (validCount =3D=3D 0) { > + free (valid); > + return NULL; > + } > + > + if (validCount =3D=3D 1) { > + ret =3D valid[0]; > + free (valid); > + return ret; > + } else { > + ret =3D createCollection (payload->service, validCount, valid); > + free (valid); > + return ret; > + } > +} > + > +static redfishPayload * > +createCollection ( > + redfishService *service, > + size_t count, > + redfishPayload **payloads > + ) > +{ > + redfishPayload *ret; > + json_t *collectionJson =3D json_object (); > + json_t *jcount =3D json_integer ((json_int_t)count); > + json_t *members =3D 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 =3D 0; i < count; i++) { > + json_array_append (members, payloads[i]->json); > + cleanupPayload (payloads[i]); > + } > + > + json_object_set (collectionJson, "Members", members); > + json_decref (members); > + > + ret =3D 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 =3D json_object_iter (json); > + for (i =3D 0; i < index; i++) { > + iter =3D json_object_iter_next (json, iter); > + if (iter =3D=3D NULL) { > + break; > + } > + } > + > + if (iter =3D=3D NULL) { > + return NULL; > + } > + > + return json_object_iter_value (iter); > +} > + > +/* vim: set tabstop=3D4 shiftwidth=3D4 expandtab: */ > diff --git > a/RedfishClientPkg/PrivateLibrary/RedfishLib/edk2libredfish/src/redpath.c > b/RedfishClientPkg/PrivateLibrary/RedfishLib/edk2libredfish/src/redpath.c > new file mode 100644 > index 00000000..cf5ab851 > --- /dev/null > +++ > b/RedfishClientPkg/PrivateLibrary/RedfishLib/edk2libredfish/src/redpath.c > @@ -0,0 +1,224 @@ > +/** @file > + This file is cloned from DMTF libredfish library tag v1.0.0 and mainta= ined > + 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
> + > + SPDX-License-Identifier: BSD-2-Clause-Patent > + > +**/ > +#include > + > +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) =3D=3D 0)) { > + return NULL; > + } > + > + node =3D (redPathNode *)calloc (1, sizeof (redPathNode)); > + if (!node) { > + return NULL; > + } > + > + if (path[0] =3D=3D '/') { > + node->isRoot =3D true; > + if (path[1] =3D=3D 'v') { > + node->version =3D getVersion (path+1, &curPath); > + if (curPath =3D=3D NULL) { > + return node; > + } > + > + if (curPath[0] =3D=3D '/') { > + curPath++; > + } > + > + node->next =3D parseRedPath (curPath); > + } else { > + node->next =3D parseRedPath (path+1); > + } > + > + return node; > + } > + > + node->isRoot =3D false; > + curPath =3D getStringTill (path, "/", &end); > + endNode =3D node; > + parseNode (curPath, node, &endNode); > + free (curPath); > + if (end !=3D NULL) { > + endNode->next =3D parseRedPath (end+1); > + } > + > + return node; > +} > + > +void > +cleanupRedPath ( > + redPathNode *node > + ) > +{ > + if (!node) { > + return; > + } > + > + cleanupRedPath (node->next); > + node->next =3D 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 =3D getStringTill (path, "[", &indexStart); > + size_t tmpIndex; > + char *opChars; > + > + node->nodeName =3D nodeName; > + if (indexStart =3D=3D NULL) { > + *end =3D node; > + return; > + } > + > + node->next =3D (redPathNode *)calloc (1, sizeof (redPathNode)); > + if (!node->next) { > + return; > + } > + > + // Skip past [ > + indexStart++; > + *end =3D node->next; > + index =3D getStringTill (indexStart, "]", NULL); > + tmpIndex =3D (size_t)strtoull (index, &indexEnd, 0); > + if (indexEnd !=3D index) { > + free (index); > + node->next->index =3D tmpIndex; > + node->next->isIndex =3D true; > + return; > + } > + > + opChars =3D strpbrk (index, "<>=3D~"); > + if (opChars =3D=3D NULL) { > + // TODO handle last() and position() > + node->next->op =3D strdup ("exists"); > + node->next->propName =3D index; > + return; > + } > + > + node->next->propName =3D (char *)malloc ((opChars - index)+1); > + memcpy (node->next->propName, index, (opChars - index)); > + node->next->propName[(opChars - index)] =3D 0; > + > + tmpIndex =3D 1; > + while (1) { > + if ((opChars[tmpIndex] =3D=3D '=3D') || (opChars[tmpIndex] =3D=3D '<= ') || > (opChars[tmpIndex] =3D=3D '>') || (opChars[tmpIndex] =3D=3D '~')) { > + tmpIndex++; > + continue; > + } > + > + break; > + } > + > + node->next->op =3D (char *)malloc (tmpIndex+1); > + memcpy (node->next->op, opChars, tmpIndex); > + node->next->op[tmpIndex] =3D 0; > + > + node->next->value =3D strdup (opChars+tmpIndex); > + free (index); > +} > + > +static char * > +getStringTill ( > + const char *string, > + const char *terminator, > + char **retEnd > + ) > +{ > + char *ret; > + char *end; > + > + end =3D strstr ((char *)string, terminator); > + if (retEnd) { > + *retEnd =3D end; > + } > + > + if (end =3D=3D NULL) { > + // No terminator > + return strdup (string); > + } > + > + ret =3D (char *)malloc ((end-string)+1); > + memcpy (ret, string, (end-string)); > + ret[(end-string)] =3D 0; > + return ret; > +} > diff --git > a/RedfishClientPkg/PrivateLibrary/RedfishLib/edk2libredfish/src/service.c > b/RedfishClientPkg/PrivateLibrary/RedfishLib/edk2libredfish/src/service.c > new file mode 100644 > index 00000000..969aa5a0 > --- /dev/null > +++ > b/RedfishClientPkg/PrivateLibrary/RedfishLib/edk2libredfish/src/service.c > @@ -0,0 +1,1523 @@ > +/** @file > + This file is cloned from DMTF libredfish library tag v1.0.0 and mainta= ined > + 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
> + > + 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 =3D (AsciiStrLen (AsciiStr) + 1) * 2; > + Str =3D AllocatePool (BufLen); > + ASSERT (Str !=3D NULL); > + > + AsciiStrToUnicodeStrS (AsciiStr, Str, AsciiStrLen (AsciiStr) + 1); > + > + return Str; > +} > + > +VOID > +RestConfigFreeHttpRequestData ( > + IN EFI_HTTP_REQUEST_DATA *RequestData > + ) > +{ > + if (RequestData =3D=3D NULL) { > + return; > + } > + > + if (RequestData->Url !=3D NULL) { > + FreePool (RequestData->Url); > + } > + > + FreePool (RequestData); > +} > + > +VOID > +RestConfigFreeHttpMessage ( > + IN EFI_HTTP_MESSAGE *Message, > + IN BOOLEAN IsRequest > + ) > +{ > + if (Message =3D=3D NULL) { > + return; > + } > + > + if (IsRequest) { > + RestConfigFreeHttpRequestData (Message->Data.Request); > + Message->Data.Request =3D NULL; > + } else { > + if (Message->Data.Response !=3D NULL) { > + FreePool (Message->Data.Response); > + Message->Data.Response =3D NULL; > + } > + } > + > + if (Message->Headers !=3D NULL) { > + FreePool (Message->Headers); > + Message->Headers =3D NULL; > + } > + > + if (Message->Body !=3D NULL) { > + FreePool (Message->Body); > + Message->Body =3D 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 =3D StrLen (String) + 1; > + AsciiStr =3D AllocatePool (BufLen); > + if (AsciiStr =3D=3D NULL) { > + return NULL; > + } > + > + Status =3D 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 =3D=3D NULL) || (EncodedContent =3D=3D NULL) || > (EncodedContentLength =3D=3D NULL)) { > + return EFI_INVALID_PARAMETER; > + } > + > + Status =3D RedfishContentEncode ( > + ContentEncodedValue, > + OriginalContent, > + AsciiStrLen (OriginalContent), > + &EncodedPointer, > + &EncodedLength > + ); > + if (Status =3D=3D EFI_SUCCESS) { > + *EncodedContent =3D EncodedPointer; > + *EncodedContentLength =3D 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 o= ut. > + > + @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 =3D=3D NULL) { > + return EFI_INVALID_PARAMETER; > + } > + > + Status =3D RedfishContentDecode ( > + ContentEncodedValue, > + *ContentPointer, > + *ContentLength, > + &DecodedPointer, > + &DecodedLength > + ); > + if (Status =3D=3D EFI_SUCCESS) { > + FreePool (*ContentPointer); > + *ContentPointer =3D DecodedPointer; > + *ContentLength =3D DecodedLength; > + } > + > + return Status; > +} > + > +/** > + Create a HTTP URL string for specific Redfish resource. > + > + This function build a URL string from the Redfish Host interface recor= d and > caller specified > + relative path of the resource. > + > + Callers are responsible for freeing the returned string storage pointe= d 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 =3D=3D NULL) || (HttpUrl =3D=3D NULL)) { > + return EFI_INVALID_PARAMETER; > + } > + > + // > + // RFC2616: http_URL =3D "http(s):" "//" host [ ":" port ] [ abs_path = [ "?" > query ]] > + // > + if (RelativePath =3D=3D NULL) { > + PathLen =3D 0; > + } else { > + PathLen =3D StrLen (RelativePath); > + } > + > + UrlLength =3D StrLen (HTTPS_FLAG) + StrLen (REDFISH_FIRST_URL) + 1 + > StrLen (RedfishConfigServiceInfo->RedfishServiceLocation) + PathLen; > + Url =3D AllocateZeroPool (UrlLength * sizeof (CHAR16)); > + if (Url =3D=3D NULL) { > + return EFI_OUT_OF_RESOURCES; > + } > + > + UrlHead =3D Url; > + // > + // Copy "http://" or "https://" according RedfishServiceIpPort. > + // > + if (!RedfishConfigServiceInfo->RedfishServiceUseHttps) { > + StrCpyS (Url, StrLen (HTTPS_FLAG) + 1, HTTP_FLAG); > + Url =3D Url + StrLen (HTTP_FLAG); > + } else { > + StrCpyS (Url, StrLen (HTTPS_FLAG) + 1, HTTPS_FLAG); > + Url =3D Url + StrLen (HTTPS_FLAG); > + } > + > + StrCpyS (Url, StrLen (RedfishConfigServiceInfo->RedfishServiceLocation= ) + > 1, RedfishConfigServiceInfo->RedfishServiceLocation); > + Url =3D Url + StrLen (RedfishConfigServiceInfo->RedfishServiceLocation= ); > + > + // > + // Copy abs_path > + // > + if ((RelativePath !=3D NULL) && (PathLen !=3D 0)) { > + StrnCpyS (Url, UrlLength, RelativePath, PathLen); > + } > + > + *HttpUrl =3D 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 =3D NULL; > + AsciiHost =3D NULL; > + RestEx =3D NULL; > + ret =3D NULL; > + > + if (RedfishConfigServiceInfo->RedfishServiceRestExHandle =3D=3D NULL) = { > + goto ON_EXIT; > + } > + > + Status =3D RedfishBuildUrl (RedfishConfigServiceInfo, NULL, &HttpUrl); > + if (EFI_ERROR (Status)) { > + goto ON_EXIT; > + } > + > + ASSERT (HttpUrl !=3D NULL); > + > + AsciiHost =3D UnicodeStrDupToAsciiStr (HttpUrl); > + if (AsciiHost =3D=3D NULL) { > + goto ON_EXIT; > + } > + > + Status =3D gBS->HandleProtocol ( > + RedfishConfigServiceInfo->RedfishServiceRestExHandle, > + &gEfiRestExProtocolGuid, > + (VOID **)&RestEx > + ); > + if (EFI_ERROR (Status)) { > + goto ON_EXIT; > + } > + > + if (auth =3D=3D NULL) { > + ret =3D createServiceEnumeratorNoAuth (AsciiHost, rootUri, true, fla= gs, > RestEx); > + } else if (auth->authType =3D=3D REDFISH_AUTH_BASIC) { > + ret =3D createServiceEnumeratorBasicAuth (AsciiHost, rootUri, auth- > >authCodes.userPass.username, auth->authCodes.userPass.password, flags, > RestEx); > + } else if (auth->authType =3D=3D REDFISH_AUTH_SESSION) { > + ret =3D createServiceEnumeratorSessionAuth (AsciiHost, rootUri, auth= - > >authCodes.userPass.username, auth->authCodes.userPass.password, flags, > RestEx); > + } else { > + goto ON_EXIT; > + } > + > + ret->RestEx =3D RestEx; > +ON_EXIT: > + if (HttpUrl !=3D NULL) { > + FreePool (HttpUrl); > + } > + > + if (AsciiHost !=3D 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 =3D NULL; > + EFI_STATUS Status; > + EFI_HTTP_REQUEST_DATA *RequestData =3D NULL; > + EFI_HTTP_MESSAGE *RequestMsg =3D NULL; > + EFI_HTTP_MESSAGE ResponseMsg; > + EFI_HTTP_HEADER *ContentEncodedHeader; > + > + if ((service =3D=3D NULL) || (uri =3D=3D NULL) || (StatusCode =3D=3D N= ULL)) { > + return NULL; > + } > + > + *StatusCode =3D NULL; > + > + url =3D 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 =3D HttpIoCreateHeader ((service->sessionToken || service= - > >basicAuthStr) ? 6 : 5); > + if (HttpIoHeader =3D=3D NULL) { > + ret =3D NULL; > + goto ON_EXIT; > + } > + > + if (service->sessionToken) { > + Status =3D HttpIoSetHeader (HttpIoHeader, "X-Auth-Token", service- > >sessionToken); > + ASSERT_EFI_ERROR (Status); > + } else if (service->basicAuthStr) { > + Status =3D HttpIoSetHeader (HttpIoHeader, "Authorization", service- > >basicAuthStr); > + ASSERT_EFI_ERROR (Status); > + } > + > + Status =3D HttpIoSetHeader (HttpIoHeader, "Host", service- > >HostHeaderValue); > + ASSERT_EFI_ERROR (Status); > + Status =3D HttpIoSetHeader (HttpIoHeader, "OData-Version", "4.0"); > + ASSERT_EFI_ERROR (Status); > + Status =3D HttpIoSetHeader (HttpIoHeader, "Accept", "application/json"= ); > + ASSERT_EFI_ERROR (Status); > + Status =3D HttpIoSetHeader (HttpIoHeader, "User-Agent", "libredfish"); > + ASSERT_EFI_ERROR (Status); > + Status =3D HttpIoSetHeader (HttpIoHeader, "Connection", "Keep-Alive"); > + ASSERT_EFI_ERROR (Status); > + > + // > + // Step 2: build the rest of HTTP request info. > + // > + RequestData =3D AllocateZeroPool (sizeof (EFI_HTTP_REQUEST_DATA)); > + if (RequestData =3D=3D NULL) { > + ret =3D NULL; > + goto ON_EXIT; > + } > + > + RequestData->Method =3D HttpMethodGet; > + RequestData->Url =3D C8ToC16 (url); > + > + // > + // Step 3: fill in EFI_HTTP_MESSAGE > + // > + RequestMsg =3D AllocateZeroPool (sizeof (EFI_HTTP_MESSAGE)); > + if (RequestMsg =3D=3D NULL) { > + ret =3D NULL; > + goto ON_EXIT; > + } > + > + RequestMsg->Data.Request =3D RequestData; > + RequestMsg->HeaderCount =3D HttpIoHeader->HeaderCount; > + RequestMsg->Headers =3D HttpIoHeader->Headers; > + > + ZeroMem (&ResponseMsg, sizeof (ResponseMsg)); > + > + // > + // Step 4: call RESTEx to get response from REST service. > + // > + Status =3D service->RestEx->SendReceive (service->RestEx, RequestMsg, > &ResponseMsg); > + if (EFI_ERROR (Status)) { > + ret =3D NULL; > + goto ON_EXIT; > + } > + > + // > + // Step 5: Return the HTTP StatusCode and Body message. > + // > + if (ResponseMsg.Data.Response !=3D NULL) { > + *StatusCode =3D AllocateZeroPool (sizeof (EFI_HTTP_STATUS_CODE)); > + if (*StatusCode =3D=3D NULL) { > + ret =3D NULL; > + goto ON_EXIT; > + } > + > + // > + // The caller shall take the responsibility to free the buffer. > + // > + **StatusCode =3D ResponseMsg.Data.Response->StatusCode; > + } > + > + if ((ResponseMsg.BodyLength !=3D 0) && (ResponseMsg.Body !=3D NULL)) { > + // > + // Check if data is encoded. > + // > + ContentEncodedHeader =3D HttpFindHeader (ResponseMsg.HeaderCount, > ResponseMsg.Headers, HTTP_HEADER_CONTENT_ENCODING); > + if (ContentEncodedHeader !=3D NULL) { > + // > + // The content is encoded. > + // > + Status =3D 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 =3D NULL; > + goto ON_EXIT; > + } > + } > + > + ret =3D json_loadb (ResponseMsg.Body, ResponseMsg.BodyLength, 0, > NULL); > + } else { > + // > + // There is no message body returned from server. > + // > + ret =3D NULL; > + } > + > +ON_EXIT: > + if (url !=3D NULL) { > + free (url); > + } > + > + if (HttpIoHeader !=3D NULL) { > + HttpIoFreeHeader (HttpIoHeader); > + } > + > + if (RequestData !=3D NULL) { > + RestConfigFreeHttpRequestData (RequestData); > + } > + > + if (RequestMsg !=3D 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 =3D NULL; > + EFI_STATUS Status; > + EFI_HTTP_REQUEST_DATA *RequestData =3D NULL; > + EFI_HTTP_MESSAGE *RequestMsg =3D NULL; > + EFI_HTTP_MESSAGE ResponseMsg; > + CHAR8 ContentLengthStr[80]; > + CHAR8 *EncodedContent; > + UINTN EncodedContentLen; > + > + if ((service =3D=3D NULL) || (uri =3D=3D NULL) || (content =3D=3D NULL= ) || (StatusCode > =3D=3D NULL)) { > + return NULL; > + } > + > + *StatusCode =3D NULL; > + > + url =3D 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 =3D HttpIoCreateHeader ((service->sessionToken || service= - > >basicAuthStr) ? 9 : 8); > + if (HttpIoHeader =3D=3D NULL) { > + ret =3D NULL; > + goto ON_EXIT; > + } > + > + if (service->sessionToken) { > + Status =3D HttpIoSetHeader (HttpIoHeader, "X-Auth-Token", service- > >sessionToken); > + ASSERT_EFI_ERROR (Status); > + } else if (service->basicAuthStr) { > + Status =3D HttpIoSetHeader (HttpIoHeader, "Authorization", service- > >basicAuthStr); > + ASSERT_EFI_ERROR (Status); > + } > + > + Status =3D HttpIoSetHeader (HttpIoHeader, "Host", service- > >HostHeaderValue); > + ASSERT_EFI_ERROR (Status); > + Status =3D HttpIoSetHeader (HttpIoHeader, "Content-Type", > "application/json"); > + ASSERT_EFI_ERROR (Status); > + Status =3D HttpIoSetHeader (HttpIoHeader, "Accept", "application/json"= ); > + ASSERT_EFI_ERROR (Status); > + Status =3D HttpIoSetHeader (HttpIoHeader, "User-Agent", "libredfish"); > + ASSERT_EFI_ERROR (Status); > + Status =3D HttpIoSetHeader (HttpIoHeader, "Connection", "Keep-Alive"); > + ASSERT_EFI_ERROR (Status); > + > + AsciiSPrint ( > + ContentLengthStr, > + sizeof (ContentLengthStr), > + "%lu", > + (UINT64)strlen (content) > + ); > + Status =3D HttpIoSetHeader (HttpIoHeader, "Content-Length", > ContentLengthStr); > + ASSERT_EFI_ERROR (Status); > + Status =3D HttpIoSetHeader (HttpIoHeader, "OData-Version", "4.0"); > + ASSERT_EFI_ERROR (Status); > + > + // > + // Step 2: build the rest of HTTP request info. > + // > + RequestData =3D AllocateZeroPool (sizeof (EFI_HTTP_REQUEST_DATA)); > + if (RequestData =3D=3D NULL) { > + ret =3D NULL; > + goto ON_EXIT; > + } > + > + RequestData->Method =3D HttpMethodPatch; > + RequestData->Url =3D C8ToC16 (url); > + > + // > + // Step 3: fill in EFI_HTTP_MESSAGE > + // > + RequestMsg =3D AllocateZeroPool (sizeof (EFI_HTTP_MESSAGE)); > + if (RequestMsg =3D=3D NULL) { > + ret =3D NULL; > + goto ON_EXIT; > + } > + > + EncodedContent =3D (CHAR8 *)content; > + EncodedContentLen =3D strlen (content); > + // > + // We currently only support gzip Content-Encoding. > + // > + Status =3D EncodeRequestContent ((CHAR8 > *)HTTP_CONTENT_ENCODING_GZIP, (CHAR8 *)content, (VOID > **)&EncodedContent, &EncodedContentLen); > + if (Status =3D=3D EFI_INVALID_PARAMETER) { > + DEBUG ((DEBUG_ERROR, "%a: Error to encode content.\n", > __FUNCTION__)); > + ret =3D NULL; > + goto ON_EXIT; > + } else if (Status =3D=3D EFI_UNSUPPORTED) { > + DEBUG ((DEBUG_INFO, "No content coding for %a! Use raw data > instead.\n", HTTP_CONTENT_ENCODING_GZIP)); > + Status =3D HttpIoSetHeader (HttpIoHeader, "Content-Encoding", > HTTP_CONTENT_ENCODING_IDENTITY); > + ASSERT_EFI_ERROR (Status); > + } else { > + Status =3D HttpIoSetHeader (HttpIoHeader, "Content-Encoding", > HTTP_CONTENT_ENCODING_GZIP); > + ASSERT_EFI_ERROR (Status); > + } > + > + RequestMsg->Data.Request =3D RequestData; > + RequestMsg->HeaderCount =3D HttpIoHeader->HeaderCount; > + RequestMsg->Headers =3D HttpIoHeader->Headers; > + RequestMsg->BodyLength =3D EncodedContentLen; > + RequestMsg->Body =3D (VOID *)EncodedContent; > + > + ZeroMem (&ResponseMsg, sizeof (ResponseMsg)); > + > + // > + // Step 4: call RESTEx to get response from REST service. > + // > + Status =3D service->RestEx->SendReceive (service->RestEx, RequestMsg, > &ResponseMsg); > + if (EFI_ERROR (Status)) { > + ret =3D NULL; > + goto ON_EXIT; > + } > + > + // > + // Step 5: Return the HTTP StatusCode and Body message. > + // > + if (ResponseMsg.Data.Response !=3D NULL) { > + *StatusCode =3D AllocateZeroPool (sizeof (EFI_HTTP_STATUS_CODE)); > + if (*StatusCode =3D=3D NULL) { > + ret =3D NULL; > + goto ON_EXIT; > + } > + > + // > + // The caller shall take the responsibility to free the buffer. > + // > + **StatusCode =3D ResponseMsg.Data.Response->StatusCode; > + } > + > + if (EncodedContent !=3D content) { > + FreePool (EncodedContent); > + } > + > + if ((ResponseMsg.BodyLength !=3D 0) && (ResponseMsg.Body !=3D NULL)) { > + ret =3D json_loadb (ResponseMsg.Body, ResponseMsg.BodyLength, 0, > NULL); > + } else { > + // > + // There is no message body returned from server. > + // > + ret =3D NULL; > + } > + > +ON_EXIT: > + if (url !=3D NULL) { > + free (url); > + } > + > + if (HttpIoHeader !=3D NULL) { > + HttpIoFreeHeader (HttpIoHeader); > + } > + > + if (RequestData !=3D NULL) { > + RestConfigFreeHttpRequestData (RequestData); > + } > + > + if (RequestMsg !=3D 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 =3D NULL; > + json_t *ret; > + HTTP_IO_HEADER *HttpIoHeader =3D NULL; > + EFI_STATUS Status; > + EFI_HTTP_REQUEST_DATA *RequestData =3D NULL; > + EFI_HTTP_MESSAGE *RequestMsg =3D NULL; > + EFI_HTTP_MESSAGE ResponseMsg; > + CHAR8 ContentLengthStr[80]; > + EFI_HTTP_HEADER *HttpHeader =3D NULL; > + > + ret =3D NULL; > + > + if ((service =3D=3D NULL) || (uri =3D=3D NULL) || (content =3D=3D NULL= ) || (StatusCode > =3D=3D NULL)) { > + return NULL; > + } > + > + *StatusCode =3D NULL; > + > + url =3D makeUrlForService (service, uri); > + if (!url) { > + return NULL; > + } > + > + DEBUG ((DEBUG_INFO, "libredfish: postUriFromService(): %a\n", url)); > + > + if (contentLength =3D=3D 0) { > + contentLength =3D strlen (content); > + } > + > + // > + // Step 1: Create HTTP request message with 4 headers: > + // > + HttpIoHeader =3D HttpIoCreateHeader ((service->sessionToken || service= - > >basicAuthStr) ? 8 : 7); > + if (HttpIoHeader =3D=3D NULL) { > + goto ON_EXIT; > + } > + > + if (service->sessionToken) { > + Status =3D HttpIoSetHeader (HttpIoHeader, "X-Auth-Token", service- > >sessionToken); > + ASSERT_EFI_ERROR (Status); > + } else if (service->basicAuthStr) { > + Status =3D HttpIoSetHeader (HttpIoHeader, "Authorization", service- > >basicAuthStr); > + ASSERT_EFI_ERROR (Status); > + } > + > + if (contentType =3D=3D NULL) { > + Status =3D HttpIoSetHeader (HttpIoHeader, "Content-Type", > "application/json"); > + ASSERT_EFI_ERROR (Status); > + } else { > + Status =3D HttpIoSetHeader (HttpIoHeader, "Content-Type", (CHAR8 > *)contentType); > + ASSERT_EFI_ERROR (Status); > + } > + > + Status =3D HttpIoSetHeader (HttpIoHeader, "Host", service- > >HostHeaderValue); > + ASSERT_EFI_ERROR (Status); > + Status =3D HttpIoSetHeader (HttpIoHeader, "Accept", "application/json"= ); > + ASSERT_EFI_ERROR (Status); > + Status =3D HttpIoSetHeader (HttpIoHeader, "User-Agent", "libredfish"); > + ASSERT_EFI_ERROR (Status); > + Status =3D HttpIoSetHeader (HttpIoHeader, "Connection", "Keep-Alive"); > + ASSERT_EFI_ERROR (Status); > + AsciiSPrint ( > + ContentLengthStr, > + sizeof (ContentLengthStr), > + "%lu", > + (UINT64)contentLength > + ); > + Status =3D HttpIoSetHeader (HttpIoHeader, "Content-Length", > ContentLengthStr); > + ASSERT_EFI_ERROR (Status); > + Status =3D HttpIoSetHeader (HttpIoHeader, "OData-Version", "4.0"); > + ASSERT_EFI_ERROR (Status); > + > + // > + // Step 2: build the rest of HTTP request info. > + // > + RequestData =3D AllocateZeroPool (sizeof (EFI_HTTP_REQUEST_DATA)); > + if (RequestData =3D=3D NULL) { > + goto ON_EXIT; > + } > + > + RequestData->Method =3D HttpMethodPost; > + RequestData->Url =3D C8ToC16 (url); > + > + // > + // Step 3: fill in EFI_HTTP_MESSAGE > + // > + RequestMsg =3D AllocateZeroPool (sizeof (EFI_HTTP_MESSAGE)); > + if (RequestMsg =3D=3D NULL) { > + goto ON_EXIT; > + } > + > + RequestMsg->Data.Request =3D RequestData; > + RequestMsg->HeaderCount =3D HttpIoHeader->HeaderCount; > + RequestMsg->Headers =3D HttpIoHeader->Headers; > + RequestMsg->BodyLength =3D contentLength; > + RequestMsg->Body =3D (VOID *)content; > + > + ZeroMem (&ResponseMsg, sizeof (ResponseMsg)); > + > + // > + // Step 4: call RESTEx to get response from REST service. > + // > + Status =3D 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 !=3D NULL) { > + *StatusCode =3D AllocateZeroPool (sizeof (EFI_HTTP_STATUS_CODE)); > + if (*StatusCode =3D=3D NULL) { > + goto ON_EXIT; > + } > + > + // > + // The caller shall take the responsibility to free the buffer. > + // > + **StatusCode =3D ResponseMsg.Data.Response->StatusCode; > + } > + > + if ((ResponseMsg.BodyLength !=3D 0) && (ResponseMsg.Body !=3D NULL)) { > + ret =3D json_loadb (ResponseMsg.Body, ResponseMsg.BodyLength, 0, > NULL); > + } > + > + // > + // Step 6: Parsing the HttpHeader to retrive the X-Auth-Token if the H= TTP > StatusCode is correct. > + // > + if ((ResponseMsg.Data.Response->StatusCode =3D=3D HTTP_STATUS_200_OK) > || > + (ResponseMsg.Data.Response->StatusCode =3D=3D > HTTP_STATUS_204_NO_CONTENT)) > + { > + HttpHeader =3D HttpFindHeader (ResponseMsg.HeaderCount, > ResponseMsg.Headers, "X-Auth-Token"); > + if (HttpHeader !=3D NULL) { > + if (service->sessionToken) { > + free (service->sessionToken); > + } > + > + service->sessionToken =3D AllocateCopyPool (AsciiStrSize (HttpHead= er- > >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 =3D HttpFindHeader (ResponseMsg.HeaderCount, > ResponseMsg.Headers, "Location"); > + if (HttpHeader !=3D NULL) { > + ret =3D getUriFromService(service, HttpHeader->FieldValue); > + goto ON_EXIT; > + } > + */ > + } > + > +ON_EXIT: > + if (url !=3D NULL) { > + free (url); > + } > + > + if (HttpIoHeader !=3D NULL) { > + HttpIoFreeHeader (HttpIoHeader); > + } > + > + if (RequestData !=3D NULL) { > + RestConfigFreeHttpRequestData (RequestData); > + } > + > + if (RequestMsg !=3D 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 =3D NULL; > + EFI_STATUS Status; > + EFI_HTTP_REQUEST_DATA *RequestData =3D NULL; > + EFI_HTTP_MESSAGE *RequestMsg =3D NULL; > + EFI_HTTP_MESSAGE ResponseMsg; > + > + ret =3D NULL; > + > + if ((service =3D=3D NULL) || (uri =3D=3D NULL) || (StatusCode =3D=3D N= ULL)) { > + return NULL; > + } > + > + *StatusCode =3D NULL; > + > + url =3D 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 =3D HttpIoCreateHeader ((service->sessionToken || service= - > >basicAuthStr) ? 5 : 4); > + if (HttpIoHeader =3D=3D NULL) { > + ret =3D NULL; > + goto ON_EXIT; > + } > + > + if (service->sessionToken) { > + Status =3D HttpIoSetHeader (HttpIoHeader, "X-Auth-Token", service- > >sessionToken); > + ASSERT_EFI_ERROR (Status); > + } else if (service->basicAuthStr) { > + Status =3D HttpIoSetHeader (HttpIoHeader, "Authorization", service- > >basicAuthStr); > + ASSERT_EFI_ERROR (Status); > + } > + > + Status =3D HttpIoSetHeader (HttpIoHeader, "Host", service- > >HostHeaderValue); > + ASSERT_EFI_ERROR (Status); > + Status =3D HttpIoSetHeader (HttpIoHeader, "User-Agent", "libredfish"); > + ASSERT_EFI_ERROR (Status); > + Status =3D HttpIoSetHeader (HttpIoHeader, "OData-Version", "4.0"); > + ASSERT_EFI_ERROR (Status); > + Status =3D HttpIoSetHeader (HttpIoHeader, "Connection", "Keep-Alive"); > + ASSERT_EFI_ERROR (Status); > + > + // > + // Step 2: build the rest of HTTP request info. > + // > + RequestData =3D AllocateZeroPool (sizeof (EFI_HTTP_REQUEST_DATA)); > + if (RequestData =3D=3D NULL) { > + ret =3D NULL; > + goto ON_EXIT; > + } > + > + RequestData->Method =3D HttpMethodDelete; > + RequestData->Url =3D C8ToC16 (url); > + > + // > + // Step 3: fill in EFI_HTTP_MESSAGE > + // > + RequestMsg =3D AllocateZeroPool (sizeof (EFI_HTTP_MESSAGE)); > + if (RequestMsg =3D=3D NULL) { > + ret =3D NULL; > + goto ON_EXIT; > + } > + > + RequestMsg->Data.Request =3D RequestData; > + RequestMsg->HeaderCount =3D HttpIoHeader->HeaderCount; > + RequestMsg->Headers =3D HttpIoHeader->Headers; > + > + ZeroMem (&ResponseMsg, sizeof (ResponseMsg)); > + > + // > + // Step 4: call RESTEx to get response from REST service. > + // > + Status =3D service->RestEx->SendReceive (service->RestEx, RequestMsg, > &ResponseMsg); > + if (EFI_ERROR (Status)) { > + ret =3D NULL; > + goto ON_EXIT; > + } > + > + // > + // Step 5: Return the HTTP StatusCode and Body message. > + // > + if (ResponseMsg.Data.Response !=3D NULL) { > + *StatusCode =3D AllocateZeroPool (sizeof (EFI_HTTP_STATUS_CODE)); > + if (*StatusCode =3D=3D NULL) { > + ret =3D NULL; > + goto ON_EXIT; > + } > + > + // > + // The caller shall take the responsibility to free the buffer. > + // > + **StatusCode =3D ResponseMsg.Data.Response->StatusCode; > + } > + > + if ((ResponseMsg.BodyLength !=3D 0) && (ResponseMsg.Body !=3D NULL)) { > + ret =3D json_loadb (ResponseMsg.Body, ResponseMsg.BodyLength, 0, > NULL); > + } > + > +ON_EXIT: > + if (url !=3D NULL) { > + free (url); > + } > + > + if (HttpIoHeader !=3D NULL) { > + HttpIoFreeHeader (HttpIoHeader); > + } > + > + if (RequestData !=3D NULL) { > + RestConfigFreeHttpRequestData (RequestData); > + } > + > + if (RequestMsg !=3D 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 =3D=3D NULL) { > + versionNode =3D json_object_get (service->versions, "v1"); > + } else { > + versionNode =3D json_object_get (service->versions, version); > + } > + > + if (versionNode =3D=3D NULL) { > + return NULL; > + } > + > + verUrl =3D json_string_value (versionNode); > + if (verUrl =3D=3D NULL) { > + return NULL; > + } > + > + value =3D getUriFromService (service, verUrl, StatusCode); > + if (value =3D=3D NULL) { > + if ((service->flags & REDFISH_FLAG_SERVICE_NO_VERSION_DOC) =3D=3D 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 =3D=3D NULL)) { > + return NULL; > + } > + > + *StatusCode =3D NULL; > + > + redpath =3D parseRedPath (path); > + if (!redpath) { > + return NULL; > + } > + > + if (!redpath->isRoot) { > + cleanupRedPath (redpath); > + return NULL; > + } > + > + root =3D getRedfishServiceRoot (service, redpath->version, StatusCode)= ; > + if ((*StatusCode =3D=3D NULL) || (**StatusCode < HTTP_STATUS_200_OK) |= | > (**StatusCode > HTTP_STATUS_206_PARTIAL_CONTENT)) { > + cleanupRedPath (redpath); > + return root; > + } > + > + if (redpath->next =3D=3D NULL) { > + cleanupRedPath (redpath); > + return root; > + } > + > + FreePool (*StatusCode); > + *StatusCode =3D NULL; > + > + ret =3D getPayloadForPath (root, redpath->next, StatusCode); > + if ((*StatusCode =3D=3D NULL) && (ret !=3D NULL)) { > + // > + // In such a case, the Redfish resource is parsed from the input pay= load > (root) directly. > + // So, we still return HTTP_STATUS_200_OK. > + // > + *StatusCode =3D AllocateZeroPool (sizeof (EFI_HTTP_STATUS_CODE)); > + if (*StatusCode =3D=3D NULL) { > + ret =3D NULL; > + } else { > + **StatusCode =3D 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 !=3D NULL) { > + ZeroMem (service->sessionToken, (UINTN)strlen (service- > >sessionToken)); > + FreePool (service->sessionToken); > + } > + > + if (service->basicAuthStr !=3D NULL) { > + ZeroMem (service->basicAuthStr, (UINTN)strlen (service->basicAuthStr= )); > + FreePool (service->basicAuthStr); > + } > + > + free (service); > +} > + > +static int > +initRest ( > + redfishService *service, > + void *restProtocol > + ) > +{ > + service->RestEx =3D restProtocol; > + return 0; > +} > + > +static redfishService * > +createServiceEnumeratorNoAuth ( > + const char *host, > + const char *rootUri, > + bool enumerate, > + unsigned int flags, > + void *restProtocol > + ) > +{ > + redfishService *ret; > + char *HostStart; > + > + ret =3D (redfishService *)calloc (1, sizeof (redfishService)); > + ZeroMem (ret, sizeof (redfishService)); > + if (initRest (ret, restProtocol) !=3D 0) { > + free (ret); > + return NULL; > + } > + > + ret->host =3D AllocateCopyPool (AsciiStrSize (host), host); > + ret->flags =3D flags; > + if (enumerate) { > + ret->versions =3D getVersions (ret, rootUri); > + } > + > + HostStart =3D strstr (ret->host, "//"); > + if ((HostStart !=3D NULL) && (*(HostStart + 2) !=3D '\0')) { > + ret->HostHeaderValue =3D 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 =3D NULL; > + EnAuthValueSize =3D 0; > + > + RawAuthBufSize =3D AsciiStrLen (UserId) + AsciiStrLen (Password) + 2; > + RawAuthValue =3D AllocatePool (RawAuthBufSize); > + if (RawAuthValue =3D=3D NULL) { > + return EFI_OUT_OF_RESOURCES; > + } > + > + // > + // Build raw AuthValue (UserId:Password). > + // > + AsciiSPrint ( > + RawAuthValue, > + RawAuthBufSize, > + "%a:%a", > + UserId, > + Password > + ); > + > + // > + // Encoding RawAuthValue into Base64 format. > + // > + Status =3D Base64Encode ( > + (CONST UINT8 *)RawAuthValue, > + AsciiStrLen (RawAuthValue), > + EnAuthValue, > + &EnAuthValueSize > + ); > + if (Status =3D=3D EFI_BUFFER_TOO_SMALL) { > + EnAuthValue =3D (CHAR8 *)AllocateZeroPool (EnAuthValueSize); > + if (EnAuthValue =3D=3D NULL) { > + Status =3D EFI_OUT_OF_RESOURCES; > + return Status; > + } > + > + Status =3D Base64Encode ( > + (CONST UINT8 *)RawAuthValue, > + AsciiStrLen (RawAuthValue), > + EnAuthValue, > + &EnAuthValueSize > + ); > + } > + > + if (EFI_ERROR (Status)) { > + goto Exit; > + } > + > + BasicBufSize =3D AsciiStrLen ("Basic ") + AsciiStrLen (EnAuthV= alue) + 2; > + BasicWithEnAuthValue =3D AllocatePool (BasicBufSize); > + if (BasicWithEnAuthValue =3D=3D NULL) { > + Status =3D EFI_OUT_OF_RESOURCES; > + goto Exit; > + } > + > + // > + // Build encoded EnAuthValue with Basic (Basic EnAuthValue). > + // > + AsciiSPrint ( > + BasicWithEnAuthValue, > + BasicBufSize, > + "%a %a", > + "Basic", > + EnAuthValue > + ); > + > + service->basicAuthStr =3D BasicWithEnAuthValue; > + > +Exit: > + if (RawAuthValue !=3D NULL) { > + ZeroMem (RawAuthValue, RawAuthBufSize); > + FreePool (RawAuthValue); > + } > + > + if (EnAuthValue !=3D 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 =3D createServiceEnumeratorNoAuth (host, rootUri, false, flags, > restProtocol); > + > + // add basic auth str > + Status =3D createBasicAuthStr (ret, username, password); > + if (EFI_ERROR (Status)) { > + cleanupServiceEnumerator (ret); > + return NULL; > + } > + > + ret->versions =3D 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 =3D NULL; > + StatusCode =3D NULL; > + > + ret =3D createServiceEnumeratorNoAuth (host, rootUri, true, flags, > restProtocol); > + if (ret =3D=3D NULL) { > + return NULL; > + } > + > + payload =3D getRedfishServiceRoot (ret, NULL, &StatusCode); > + if ((StatusCode =3D=3D NULL) || (*StatusCode < HTTP_STATUS_200_OK) || > (*StatusCode > HTTP_STATUS_206_PARTIAL_CONTENT)) { > + if (StatusCode !=3D NULL) { > + FreePool (StatusCode); > + } > + > + if (payload !=3D NULL) { > + cleanupPayload (payload); > + } > + > + cleanupServiceEnumerator (ret); > + return NULL; > + } > + > + if (StatusCode !=3D NULL) { > + FreePool (StatusCode); > + StatusCode =3D NULL; > + } > + > + links =3D getPayloadByNodeName (payload, "Links", &StatusCode); > + cleanupPayload (payload); > + if (links =3D=3D NULL) { > + cleanupServiceEnumerator (ret); > + return NULL; > + } > + > + session =3D json_object_get (links->json, "Sessions"); > + if (session =3D=3D NULL) { > + cleanupPayload (links); > + cleanupServiceEnumerator (ret); > + return NULL; > + } > + > + odataId =3D json_object_get (session, "@odata.id"); > + if (odataId =3D=3D NULL) { > + cleanupPayload (links); > + cleanupServiceEnumerator (ret); > + return NULL; > + } > + > + uri =3D json_string_value (odataId); > + post =3D json_object (); > + addStringToJsonObject (post, "UserName", username); > + addStringToJsonObject (post, "Password", password); > + content =3D json_dumps (post, 0); > + json_decref (post); > + sessionPayload =3D postUriFromService (ret, uri, content, 0, NULL, > &StatusCode); > + > + if (content !=3D NULL) { > + ZeroMem (content, (UINTN)strlen (content)); > + free (content); > + } > + > + if ((sessionPayload =3D=3D NULL) || (StatusCode =3D=3D NULL) || (*Stat= usCode < > HTTP_STATUS_200_OK) || (*StatusCode > > HTTP_STATUS_206_PARTIAL_CONTENT)) { > + // Failed to create session! > + > + cleanupPayload (links); > + cleanupServiceEnumerator (ret); > + > + if (StatusCode !=3D NULL) { > + FreePool (StatusCode); > + } > + > + if (sessionPayload !=3D 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 =3D=3D NULL) { > + return NULL; > + } > + > + url =3D (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 =3D NULL; > + EFI_HTTP_STATUS_CODE *StatusCode =3D NULL; > + > + if (service->flags & REDFISH_FLAG_SERVICE_NO_VERSION_DOC) { > + service->versions =3D json_object (); > + if (service->versions =3D=3D NULL) { > + return NULL; > + } > + > + addStringToJsonObject (service->versions, "v1", "/redfish/v1"); > + return service->versions; > + } > + > + if (rootUri !=3D NULL) { > + ret =3D getUriFromService (service, rootUri, &StatusCode); > + } else { > + ret =3D getUriFromService (service, "/redfish", &StatusCode); > + } > + > + if ((ret =3D=3D NULL) || (StatusCode =3D=3D NULL) || (*StatusCode < > HTTP_STATUS_200_OK) || (*StatusCode > > HTTP_STATUS_206_PARTIAL_CONTENT)) { > + if (ret !=3D NULL) { > + json_decref (ret); > + } > + > + ret =3D NULL; > + } > + > + if (StatusCode !=3D NULL) { > + FreePool (StatusCode); > + } > + > + return ret; > +} > + > +static void > +addStringToJsonObject ( > + json_t *object, > + const char *key, > + const char *value > + ) > +{ > + json_t *jValue =3D json_string (value); > + > + json_object_set (object, key, jValue); > + > + json_decref (jValue); > +} > -- > 2.17.1