summaryrefslogtreecommitdiff
path: root/Core/NetworkPkg/HttpDxe
diff options
context:
space:
mode:
authorGuo Mang <mang.guo@intel.com>2017-04-27 11:16:34 +0800
committerGuo Mang <mang.guo@intel.com>2017-04-27 11:16:34 +0800
commit098f8621634f1cbdd1253c9957eed09a505223f5 (patch)
tree13783836f52f77e37b32fc982cd82a1ee5888676 /Core/NetworkPkg/HttpDxe
parent9f72a84180605527643891f5c27b8f9f31c43006 (diff)
downloadedk2-platforms-098f8621634f1cbdd1253c9957eed09a505223f5.tar.xz
NetWorkPkg: Move to new location
Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Guo Mang <mang.guo@intel.com>
Diffstat (limited to 'Core/NetworkPkg/HttpDxe')
-rw-r--r--Core/NetworkPkg/HttpDxe/ComponentName.c138
-rw-r--r--Core/NetworkPkg/HttpDxe/ComponentName.h98
-rw-r--r--Core/NetworkPkg/HttpDxe/HttpDns.c415
-rw-r--r--Core/NetworkPkg/HttpDxe/HttpDns.h58
-rw-r--r--Core/NetworkPkg/HttpDxe/HttpDriver.c1067
-rw-r--r--Core/NetworkPkg/HttpDxe/HttpDriver.h404
-rw-r--r--Core/NetworkPkg/HttpDxe/HttpDxe.inf82
-rw-r--r--Core/NetworkPkg/HttpDxe/HttpDxe.uni23
-rw-r--r--Core/NetworkPkg/HttpDxe/HttpDxeExtra.uni20
-rw-r--r--Core/NetworkPkg/HttpDxe/HttpImpl.c1648
-rw-r--r--Core/NetworkPkg/HttpDxe/HttpImpl.h237
-rw-r--r--Core/NetworkPkg/HttpDxe/HttpProto.c2128
-rw-r--r--Core/NetworkPkg/HttpDxe/HttpProto.h606
-rw-r--r--Core/NetworkPkg/HttpDxe/HttpsSupport.c1720
-rw-r--r--Core/NetworkPkg/HttpDxe/HttpsSupport.h261
15 files changed, 8905 insertions, 0 deletions
diff --git a/Core/NetworkPkg/HttpDxe/ComponentName.c b/Core/NetworkPkg/HttpDxe/ComponentName.c
new file mode 100644
index 0000000000..fdd2e7f344
--- /dev/null
+++ b/Core/NetworkPkg/HttpDxe/ComponentName.c
@@ -0,0 +1,138 @@
+/** @file
+ Implementation of EFI_COMPONENT_NAME_PROTOCOL and
+ EFI_COMPONENT_NAME2_PROTOCOL protocol.
+
+ Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
+
+ This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php.
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "HttpDriver.h"
+
+///
+/// Component Name Protocol instance
+///
+GLOBAL_REMOVE_IF_UNREFERENCED
+EFI_COMPONENT_NAME_PROTOCOL gHttpDxeComponentName = {
+ (EFI_COMPONENT_NAME_GET_DRIVER_NAME) HttpDxeComponentNameGetDriverName,
+ (EFI_COMPONENT_NAME_GET_CONTROLLER_NAME) HttpDxeComponentNameGetControllerName,
+ "eng"
+};
+
+///
+/// Component Name 2 Protocol instance
+///
+GLOBAL_REMOVE_IF_UNREFERENCED
+EFI_COMPONENT_NAME2_PROTOCOL gHttpDxeComponentName2 = {
+ HttpDxeComponentNameGetDriverName,
+ HttpDxeComponentNameGetControllerName,
+ "en"
+};
+
+///
+/// Table of driver names
+///
+GLOBAL_REMOVE_IF_UNREFERENCED
+EFI_UNICODE_STRING_TABLE mHttpDxeDriverNameTable[] = {
+ { "eng;en", (CHAR16 *) L"HttpDxe" },
+ { NULL, NULL }
+};
+
+/**
+ Retrieves a Unicode string that is the user-readable name of the EFI Driver.
+
+ @param This A pointer to the EFI_COMPONENT_NAME_PROTOCOL instance.
+ @param Language A pointer to a three-character ISO 639-2 language identifier.
+ This is the language of the driver name that that the caller
+ is requesting, and it must match one of the languages specified
+ in SupportedLanguages. The number of languages supported by a
+ driver is up to the driver writer.
+ @param DriverName A pointer to the Unicode string to return. This Unicode string
+ is the name of the driver specified by This in the language
+ specified by Language.
+
+ @retval EFI_SUCCESS The Unicode string for the Driver specified by This
+ and the language specified by Language was returned
+ in DriverName.
+ @retval EFI_INVALID_PARAMETER Language is NULL.
+ @retval EFI_INVALID_PARAMETER DriverName is NULL.
+ @retval EFI_UNSUPPORTED The driver specified by This does not support the
+ language specified by Language.
+
+**/
+EFI_STATUS
+EFIAPI
+HttpDxeComponentNameGetDriverName (
+ IN EFI_COMPONENT_NAME2_PROTOCOL *This,
+ IN CHAR8 *Language,
+ OUT CHAR16 **DriverName
+ )
+{
+ return LookupUnicodeString2 (
+ Language,
+ This->SupportedLanguages,
+ mHttpDxeDriverNameTable,
+ DriverName,
+ (BOOLEAN)(This != &gHttpDxeComponentName2)
+ );
+}
+
+/**
+ Retrieves a Unicode string that is the user readable name of the controller
+ that is being managed by an EFI Driver.
+
+ @param This A pointer to the EFI_COMPONENT_NAME_PROTOCOL instance.
+ @param ControllerHandle The handle of a controller that the driver specified by
+ This is managing. This handle specifies the controller
+ whose name is to be returned.
+ @param ChildHandle The handle of the child controller to retrieve the name
+ of. This is an optional parameter that may be NULL. It
+ will be NULL for device drivers. It will also be NULL
+ for a bus drivers that wish to retrieve the name of the
+ bus controller. It will not be NULL for a bus driver
+ that wishes to retrieve the name of a child controller.
+ @param Language A pointer to a three character ISO 639-2 language
+ identifier. This is the language of the controller name
+ that the caller is requesting, and it must match one
+ of the languages specified in SupportedLanguages. The
+ number of languages supported by a driver is up to the
+ driver writer.
+ @param ControllerName A pointer to the Unicode string to return. This Unicode
+ string is the name of the controller specified by
+ ControllerHandle and ChildHandle in the language specified
+ by Language, from the point of view of the driver specified
+ by This.
+
+ @retval EFI_SUCCESS The Unicode string for the user-readable name in the
+ language specified by Language for the driver
+ specified by This was returned in DriverName.
+ @retval EFI_INVALID_PARAMETER ControllerHandle is NULL.
+ @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid EFI_HANDLE.
+ @retval EFI_INVALID_PARAMETER Language is NULL.
+ @retval EFI_INVALID_PARAMETER ControllerName is NULL.
+ @retval EFI_UNSUPPORTED The driver specified by This is not currently managing
+ the controller specified by ControllerHandle and
+ ChildHandle.
+ @retval EFI_UNSUPPORTED The driver specified by This does not support the
+ language specified by Language.
+
+**/
+EFI_STATUS
+EFIAPI
+HttpDxeComponentNameGetControllerName (
+ IN EFI_COMPONENT_NAME2_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_HANDLE ChildHandle OPTIONAL,
+ IN CHAR8 *Language,
+ OUT CHAR16 **ControllerName
+ )
+{
+ return EFI_UNSUPPORTED;
+}
diff --git a/Core/NetworkPkg/HttpDxe/ComponentName.h b/Core/NetworkPkg/HttpDxe/ComponentName.h
new file mode 100644
index 0000000000..29a91f2ec1
--- /dev/null
+++ b/Core/NetworkPkg/HttpDxe/ComponentName.h
@@ -0,0 +1,98 @@
+/** @file
+ Header file for implementation of UEFI Component Name(2) protocol.
+
+Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef __EFI_HTTP_COMPONENT_NAME_H__
+#define __EFI_HTTP_COMPONENT_NAME_H__
+
+/**
+ Retrieves a Unicode string that is the user-readable name of the EFI Driver.
+
+ @param This A pointer to the EFI_COMPONENT_NAME_PROTOCOL instance.
+ @param Language A pointer to a three-character ISO 639-2 language identifier.
+ This is the language of the driver name that that the caller
+ is requesting, and it must match one of the languages specified
+ in SupportedLanguages. The number of languages supported by a
+ driver is up to the driver writer.
+ @param DriverName A pointer to the Unicode string to return. This Unicode string
+ is the name of the driver specified by This in the language
+ specified by Language.
+
+ @retval EFI_SUCCESS The Unicode string for the Driver specified by This
+ and the language specified by Language was returned
+ in DriverName.
+ @retval EFI_INVALID_PARAMETER Language is NULL.
+ @retval EFI_INVALID_PARAMETER DriverName is NULL.
+ @retval EFI_UNSUPPORTED The driver specified by This does not support the
+ language specified by Language.
+
+**/
+EFI_STATUS
+EFIAPI
+HttpDxeComponentNameGetDriverName (
+ IN EFI_COMPONENT_NAME2_PROTOCOL *This,
+ IN CHAR8 *Language,
+ OUT CHAR16 **DriverName
+ );
+
+/**
+ Retrieves a Unicode string that is the user readable name of the controller
+ that is being managed by an EFI Driver.
+
+ @param This A pointer to the EFI_COMPONENT_NAME_PROTOCOL instance.
+ @param ControllerHandle The handle of a controller that the driver specified by
+ This is managing. This handle specifies the controller
+ whose name is to be returned.
+ @param ChildHandle The handle of the child controller to retrieve the name
+ of. This is an optional parameter that may be NULL. It
+ will be NULL for device drivers. It will also be NULL
+ for a bus drivers that wish to retrieve the name of the
+ bus controller. It will not be NULL for a bus driver
+ that wishes to retrieve the name of a child controller.
+ @param Language A pointer to a three character ISO 639-2 language
+ identifier. This is the language of the controller name
+ that the caller is requesting, and it must match one
+ of the languages specified in SupportedLanguages. The
+ number of languages supported by a driver is up to the
+ driver writer.
+ @param ControllerName A pointer to the Unicode string to return. This Unicode
+ string is the name of the controller specified by
+ ControllerHandle and ChildHandle in the language specified
+ by Language, from the point of view of the driver specified
+ by This.
+
+ @retval EFI_SUCCESS The Unicode string for the user-readable name in the
+ language specified by Language for the driver
+ specified by This was returned in DriverName.
+ @retval EFI_INVALID_PARAMETER ControllerHandle is NULL.
+ @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid EFI_HANDLE.
+ @retval EFI_INVALID_PARAMETER Language is NULL.
+ @retval EFI_INVALID_PARAMETER ControllerName is NULL.
+ @retval EFI_UNSUPPORTED The driver specified by This is not currently managing
+ the controller specified by ControllerHandle and
+ ChildHandle.
+ @retval EFI_UNSUPPORTED The driver specified by This does not support the
+ language specified by Language.
+
+**/
+EFI_STATUS
+EFIAPI
+HttpDxeComponentNameGetControllerName (
+ IN EFI_COMPONENT_NAME2_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_HANDLE ChildHandle OPTIONAL,
+ IN CHAR8 *Language,
+ OUT CHAR16 **ControllerName
+ );
+
+#endif
diff --git a/Core/NetworkPkg/HttpDxe/HttpDns.c b/Core/NetworkPkg/HttpDxe/HttpDns.c
new file mode 100644
index 0000000000..59cd7b3251
--- /dev/null
+++ b/Core/NetworkPkg/HttpDxe/HttpDns.c
@@ -0,0 +1,415 @@
+/** @file
+ Routines for HttpDxe driver to perform DNS resolution based on UEFI DNS protocols.
+
+Copyright (c) 2017, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "HttpDriver.h"
+
+/**
+ Retrieve the host address using the EFI_DNS4_PROTOCOL.
+
+ @param[in] HttpInstance Pointer to HTTP_PROTOCOL instance.
+ @param[in] HostName Pointer to buffer containing hostname.
+ @param[out] IpAddress On output, pointer to buffer containing IPv4 address.
+
+ @retval EFI_SUCCESS Operation succeeded.
+ @retval EFI_OUT_OF_RESOURCES Failed to allocate needed resources.
+ @retval EFI_DEVICE_ERROR An unexpected network error occurred.
+ @retval Others Other errors as indicated.
+
+**/
+EFI_STATUS
+HttpDns4 (
+ IN HTTP_PROTOCOL *HttpInstance,
+ IN CHAR16 *HostName,
+ OUT EFI_IPv4_ADDRESS *IpAddress
+ )
+{
+ EFI_STATUS Status;
+ EFI_DNS4_PROTOCOL *Dns4;
+ EFI_DNS4_CONFIG_DATA Dns4CfgData;
+ EFI_DNS4_COMPLETION_TOKEN Token;
+ BOOLEAN IsDone;
+ HTTP_SERVICE *Service;
+ EFI_HANDLE Dns4Handle;
+ EFI_IP4_CONFIG2_PROTOCOL *Ip4Config2;
+ UINTN DnsServerListCount;
+ EFI_IPv4_ADDRESS *DnsServerList;
+ UINTN DataSize;
+
+
+ Service = HttpInstance->Service;
+ ASSERT (Service != NULL);
+
+ DnsServerList = NULL;
+ DnsServerListCount = 0;
+ ZeroMem (&Token, sizeof (EFI_DNS4_COMPLETION_TOKEN));
+
+ //
+ // Get DNS server list from EFI IPv4 Configuration II protocol.
+ //
+ Status = gBS->HandleProtocol (Service->ControllerHandle, &gEfiIp4Config2ProtocolGuid, (VOID **) &Ip4Config2);
+ if (!EFI_ERROR (Status)) {
+ //
+ // Get the required size.
+ //
+ DataSize = 0;
+ Status = Ip4Config2->GetData (Ip4Config2, Ip4Config2DataTypeDnsServer, &DataSize, NULL);
+ if (Status == EFI_BUFFER_TOO_SMALL) {
+ DnsServerList = AllocatePool (DataSize);
+ if (DnsServerList == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ Status = Ip4Config2->GetData (Ip4Config2, Ip4Config2DataTypeDnsServer, &DataSize, DnsServerList);
+ if (EFI_ERROR (Status)) {
+ FreePool (DnsServerList);
+ DnsServerList = NULL;
+ } else {
+ DnsServerListCount = DataSize / sizeof (EFI_IPv4_ADDRESS);
+ }
+ }
+ }
+
+ Dns4Handle = NULL;
+ Dns4 = NULL;
+
+ //
+ // Create a DNS child instance and get the protocol.
+ //
+ Status = NetLibCreateServiceChild (
+ Service->ControllerHandle,
+ Service->Ip4DriverBindingHandle,
+ &gEfiDns4ServiceBindingProtocolGuid,
+ &Dns4Handle
+ );
+ if (EFI_ERROR (Status)) {
+ goto Exit;
+ }
+
+ Status = gBS->OpenProtocol (
+ Dns4Handle,
+ &gEfiDns4ProtocolGuid,
+ (VOID **) &Dns4,
+ Service->Ip4DriverBindingHandle,
+ Service->ControllerHandle,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+ if (EFI_ERROR (Status)) {
+ goto Exit;
+ }
+
+ //
+ // Configure DNS4 instance for the DNS server address and protocol.
+ //
+ ZeroMem (&Dns4CfgData, sizeof (Dns4CfgData));
+ Dns4CfgData.DnsServerListCount = DnsServerListCount;
+ Dns4CfgData.DnsServerList = DnsServerList;
+ Dns4CfgData.UseDefaultSetting = HttpInstance->IPv4Node.UseDefaultAddress;
+ if (!Dns4CfgData.UseDefaultSetting) {
+ IP4_COPY_ADDRESS (&Dns4CfgData.StationIp, &HttpInstance->IPv4Node.LocalAddress);
+ IP4_COPY_ADDRESS (&Dns4CfgData.SubnetMask, &HttpInstance->IPv4Node.LocalSubnet);
+ }
+ Dns4CfgData.EnableDnsCache = TRUE;
+ Dns4CfgData.Protocol = EFI_IP_PROTO_UDP;
+ Status = Dns4->Configure (
+ Dns4,
+ &Dns4CfgData
+ );
+ if (EFI_ERROR (Status)) {
+ goto Exit;
+ }
+
+ //
+ // Create event to set the is done flag when name resolution is finished.
+ //
+ ZeroMem (&Token, sizeof (Token));
+ Status = gBS->CreateEvent (
+ EVT_NOTIFY_SIGNAL,
+ TPL_NOTIFY,
+ HttpCommonNotify,
+ &IsDone,
+ &Token.Event
+ );
+ if (EFI_ERROR (Status)) {
+ goto Exit;
+ }
+
+ //
+ // Start asynchronous name resolution.
+ //
+ Token.Status = EFI_NOT_READY;
+ IsDone = FALSE;
+ Status = Dns4->HostNameToIp (Dns4, HostName, &Token);
+ if (EFI_ERROR (Status)) {
+ goto Exit;
+ }
+
+ while (!IsDone) {
+ Dns4->Poll (Dns4);
+ }
+
+ //
+ // Name resolution is done, check result.
+ //
+ Status = Token.Status;
+ if (!EFI_ERROR (Status)) {
+ if (Token.RspData.H2AData == NULL) {
+ Status = EFI_DEVICE_ERROR;
+ goto Exit;
+ }
+ if (Token.RspData.H2AData->IpCount == 0 || Token.RspData.H2AData->IpList == NULL) {
+ Status = EFI_DEVICE_ERROR;
+ goto Exit;
+ }
+ //
+ // We just return the first IP address from DNS protocol.
+ //
+ IP4_COPY_ADDRESS (IpAddress, Token.RspData.H2AData->IpList);
+ Status = EFI_SUCCESS;
+ }
+
+Exit:
+
+ if (Token.Event != NULL) {
+ gBS->CloseEvent (Token.Event);
+ }
+ if (Token.RspData.H2AData != NULL) {
+ if (Token.RspData.H2AData->IpList != NULL) {
+ FreePool (Token.RspData.H2AData->IpList);
+ }
+ FreePool (Token.RspData.H2AData);
+ }
+
+ if (Dns4 != NULL) {
+ Dns4->Configure (Dns4, NULL);
+
+ gBS->CloseProtocol (
+ Dns4Handle,
+ &gEfiDns4ProtocolGuid,
+ Service->Ip4DriverBindingHandle,
+ Service->ControllerHandle
+ );
+ }
+
+ if (Dns4Handle != NULL) {
+ NetLibDestroyServiceChild (
+ Service->ControllerHandle,
+ Service->Ip4DriverBindingHandle,
+ &gEfiDns4ServiceBindingProtocolGuid,
+ Dns4Handle
+ );
+ }
+
+ if (DnsServerList != NULL) {
+ FreePool (DnsServerList);
+ }
+
+ return Status;
+}
+
+/**
+ Retrieve the host address using the EFI_DNS6_PROTOCOL.
+
+ @param[in] HttpInstance Pointer to HTTP_PROTOCOL instance.
+ @param[in] HostName Pointer to buffer containing hostname.
+ @param[out] IpAddress On output, pointer to buffer containing IPv6 address.
+
+ @retval EFI_SUCCESS Operation succeeded.
+ @retval EFI_OUT_OF_RESOURCES Failed to allocate needed resources.
+ @retval EFI_DEVICE_ERROR An unexpected network error occurred.
+ @retval Others Other errors as indicated.
+
+**/
+EFI_STATUS
+HttpDns6 (
+ IN HTTP_PROTOCOL *HttpInstance,
+ IN CHAR16 *HostName,
+ OUT EFI_IPv6_ADDRESS *IpAddress
+ )
+{
+ EFI_STATUS Status;
+ HTTP_SERVICE *Service;
+ EFI_DNS6_PROTOCOL *Dns6;
+ EFI_DNS6_CONFIG_DATA Dns6ConfigData;
+ EFI_DNS6_COMPLETION_TOKEN Token;
+ EFI_HANDLE Dns6Handle;
+ EFI_IP6_CONFIG_PROTOCOL *Ip6Config;
+ EFI_IPv6_ADDRESS *DnsServerList;
+ UINTN DnsServerListCount;
+ UINTN DataSize;
+ BOOLEAN IsDone;
+
+
+ Service = HttpInstance->Service;
+ ASSERT (Service != NULL);
+
+ DnsServerList = NULL;
+ DnsServerListCount = 0;
+ Dns6 = NULL;
+ Dns6Handle = NULL;
+ ZeroMem (&Token, sizeof (EFI_DNS6_COMPLETION_TOKEN));
+
+ //
+ // Get DNS server list from EFI IPv6 Configuration protocol.
+ //
+ Status = gBS->HandleProtocol (Service->ControllerHandle, &gEfiIp6ConfigProtocolGuid, (VOID **) &Ip6Config);
+ if (!EFI_ERROR (Status)) {
+ //
+ // Get the required size.
+ //
+ DataSize = 0;
+ Status = Ip6Config->GetData (Ip6Config, Ip6ConfigDataTypeDnsServer, &DataSize, NULL);
+ if (Status == EFI_BUFFER_TOO_SMALL) {
+ DnsServerList = AllocatePool (DataSize);
+ if (DnsServerList == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ Status = Ip6Config->GetData (Ip6Config, Ip6ConfigDataTypeDnsServer, &DataSize, DnsServerList);
+ if (EFI_ERROR (Status)) {
+ FreePool (DnsServerList);
+ DnsServerList = NULL;
+ } else {
+ DnsServerListCount = DataSize / sizeof (EFI_IPv6_ADDRESS);
+ }
+ }
+ }
+
+ //
+ // Create a DNSv6 child instance and get the protocol.
+ //
+ Status = NetLibCreateServiceChild (
+ Service->ControllerHandle,
+ Service->Ip6DriverBindingHandle,
+ &gEfiDns6ServiceBindingProtocolGuid,
+ &Dns6Handle
+ );
+ if (EFI_ERROR (Status)) {
+ goto Exit;
+ }
+
+ Status = gBS->OpenProtocol (
+ Dns6Handle,
+ &gEfiDns6ProtocolGuid,
+ (VOID **) &Dns6,
+ Service->Ip6DriverBindingHandle,
+ Service->ControllerHandle,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+ if (EFI_ERROR (Status)) {
+ goto Exit;
+ }
+
+ //
+ // Configure DNS6 instance for the DNS server address and protocol.
+ //
+ ZeroMem (&Dns6ConfigData, sizeof (EFI_DNS6_CONFIG_DATA));
+ Dns6ConfigData.DnsServerCount = (UINT32)DnsServerListCount;
+ Dns6ConfigData.DnsServerList = DnsServerList;
+ Dns6ConfigData.EnableDnsCache = TRUE;
+ Dns6ConfigData.Protocol = EFI_IP_PROTO_UDP;
+ IP6_COPY_ADDRESS (&Dns6ConfigData.StationIp, &HttpInstance->Ipv6Node.LocalAddress);
+ Status = Dns6->Configure (
+ Dns6,
+ &Dns6ConfigData
+ );
+ if (EFI_ERROR (Status)) {
+ goto Exit;
+ }
+
+ Token.Status = EFI_NOT_READY;
+ IsDone = FALSE;
+ //
+ // Create event to set the IsDone flag when name resolution is finished.
+ //
+ Status = gBS->CreateEvent (
+ EVT_NOTIFY_SIGNAL,
+ TPL_NOTIFY,
+ HttpCommonNotify,
+ &IsDone,
+ &Token.Event
+ );
+ if (EFI_ERROR (Status)) {
+ goto Exit;
+ }
+
+ //
+ // Start asynchronous name resolution.
+ //
+ Status = Dns6->HostNameToIp (Dns6, HostName, &Token);
+ if (EFI_ERROR (Status)) {
+ goto Exit;
+ }
+
+ while (!IsDone) {
+ Dns6->Poll (Dns6);
+ }
+
+ //
+ // Name resolution is done, check result.
+ //
+ Status = Token.Status;
+ if (!EFI_ERROR (Status)) {
+ if (Token.RspData.H2AData == NULL) {
+ Status = EFI_DEVICE_ERROR;
+ goto Exit;
+ }
+ if (Token.RspData.H2AData->IpCount == 0 || Token.RspData.H2AData->IpList == NULL) {
+ Status = EFI_DEVICE_ERROR;
+ goto Exit;
+ }
+ //
+ // We just return the first IPv6 address from DNS protocol.
+ //
+ IP6_COPY_ADDRESS (IpAddress, Token.RspData.H2AData->IpList);
+ Status = EFI_SUCCESS;
+ }
+
+Exit:
+
+ if (Token.Event != NULL) {
+ gBS->CloseEvent (Token.Event);
+ }
+ if (Token.RspData.H2AData != NULL) {
+ if (Token.RspData.H2AData->IpList != NULL) {
+ FreePool (Token.RspData.H2AData->IpList);
+ }
+ FreePool (Token.RspData.H2AData);
+ }
+
+ if (Dns6 != NULL) {
+ Dns6->Configure (Dns6, NULL);
+
+ gBS->CloseProtocol (
+ Dns6Handle,
+ &gEfiDns6ProtocolGuid,
+ Service->Ip6DriverBindingHandle,
+ Service->ControllerHandle
+ );
+ }
+
+ if (Dns6Handle != NULL) {
+ NetLibDestroyServiceChild (
+ Service->ControllerHandle,
+ Service->Ip6DriverBindingHandle,
+ &gEfiDns6ServiceBindingProtocolGuid,
+ Dns6Handle
+ );
+ }
+
+ if (DnsServerList != NULL) {
+ FreePool (DnsServerList);
+ }
+
+ return Status;
+}
diff --git a/Core/NetworkPkg/HttpDxe/HttpDns.h b/Core/NetworkPkg/HttpDxe/HttpDns.h
new file mode 100644
index 0000000000..fa0c8f4a99
--- /dev/null
+++ b/Core/NetworkPkg/HttpDxe/HttpDns.h
@@ -0,0 +1,58 @@
+/** @file
+ The header file of routines for HttpDxe driver to perform DNS resolution based on UEFI DNS protocols.
+
+Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef __EFI_HTTP_DNS_H__
+#define __EFI_HTTP_DNS_H__
+
+/**
+ Retrieve the host address using the EFI_DNS4_PROTOCOL.
+
+ @param[in] HttpInstance Pointer to HTTP_PROTOCOL instance.
+ @param[in] HostName Pointer to buffer containing hostname.
+ @param[out] IpAddress On output, pointer to buffer containing IPv4 address.
+
+ @retval EFI_SUCCESS Operation succeeded.
+ @retval EFI_OUT_OF_RESOURCES Failed to allocate needed resources.
+ @retval EFI_DEVICE_ERROR An unexpected network error occurred.
+ @retval Others Other errors as indicated.
+
+**/
+EFI_STATUS
+HttpDns4 (
+ IN HTTP_PROTOCOL *HttpInstance,
+ IN CHAR16 *HostName,
+ OUT EFI_IPv4_ADDRESS *IpAddress
+ );
+
+/**
+ Retrieve the host address using the EFI_DNS6_PROTOCOL.
+
+ @param[in] HttpInstance Pointer to HTTP_PROTOCOL instance.
+ @param[in] HostName Pointer to buffer containing hostname.
+ @param[out] IpAddress On output, pointer to buffer containing IPv6 address.
+
+ @retval EFI_SUCCESS Operation succeeded.
+ @retval EFI_OUT_OF_RESOURCES Failed to allocate needed resources.
+ @retval EFI_DEVICE_ERROR An unexpected network error occurred.
+ @retval Others Other errors as indicated.
+
+**/
+EFI_STATUS
+HttpDns6 (
+ IN HTTP_PROTOCOL *HttpInstance,
+ IN CHAR16 *HostName,
+ OUT EFI_IPv6_ADDRESS *IpAddress
+ );
+
+#endif \ No newline at end of file
diff --git a/Core/NetworkPkg/HttpDxe/HttpDriver.c b/Core/NetworkPkg/HttpDxe/HttpDriver.c
new file mode 100644
index 0000000000..5727526273
--- /dev/null
+++ b/Core/NetworkPkg/HttpDxe/HttpDriver.c
@@ -0,0 +1,1067 @@
+/** @file
+ The driver binding and service binding protocol for HttpDxe driver.
+
+ Copyright (c) 2015 - 2017, Intel Corporation. All rights reserved.<BR>
+ (C) Copyright 2016 Hewlett Packard Enterprise Development LP<BR>
+
+ This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php.
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "HttpDriver.h"
+
+EFI_HTTP_UTILITIES_PROTOCOL *mHttpUtilities = NULL;
+
+///
+/// Driver Binding Protocol instance
+///
+EFI_DRIVER_BINDING_PROTOCOL gHttpDxeIp4DriverBinding = {
+ HttpDxeIp4DriverBindingSupported,
+ HttpDxeIp4DriverBindingStart,
+ HttpDxeIp4DriverBindingStop,
+ HTTP_DRIVER_VERSION,
+ NULL,
+ NULL
+};
+
+EFI_DRIVER_BINDING_PROTOCOL gHttpDxeIp6DriverBinding = {
+ HttpDxeIp6DriverBindingSupported,
+ HttpDxeIp6DriverBindingStart,
+ HttpDxeIp6DriverBindingStop,
+ HTTP_DRIVER_VERSION,
+ NULL,
+ NULL
+};
+
+
+/**
+ Create a HTTP driver service binding private instance.
+
+ @param[in] Controller The controller that has TCP4 service binding
+ installed.
+ @param[out] ServiceData Point to HTTP driver private instance.
+
+ @retval EFI_OUT_OF_RESOURCES Failed to allocate some resources.
+ @retval EFI_SUCCESS A new HTTP driver private instance is created.
+
+**/
+EFI_STATUS
+HttpCreateService (
+ IN EFI_HANDLE Controller,
+ OUT HTTP_SERVICE **ServiceData
+ )
+{
+ HTTP_SERVICE *HttpService;
+
+ ASSERT (ServiceData != NULL);
+ *ServiceData = NULL;
+
+ HttpService = AllocateZeroPool (sizeof (HTTP_SERVICE));
+ if (HttpService == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ HttpService->Signature = HTTP_SERVICE_SIGNATURE;
+ HttpService->ServiceBinding.CreateChild = HttpServiceBindingCreateChild;
+ HttpService->ServiceBinding.DestroyChild = HttpServiceBindingDestroyChild;
+ HttpService->ControllerHandle = Controller;
+ HttpService->ChildrenNumber = 0;
+ InitializeListHead (&HttpService->ChildrenList);
+
+ *ServiceData = HttpService;
+ return EFI_SUCCESS;
+}
+
+/**
+ Release all the resource used the HTTP service binding instance.
+
+ @param[in] HttpService The HTTP private instance.
+ @param[in] UsingIpv6 Indicate use TCP4 protocol or TCP6 protocol.
+ if TRUE, use Tcp6 protocol.
+ if FALSE, use Tcp4 protocl.
+**/
+VOID
+HttpCleanService (
+ IN HTTP_SERVICE *HttpService,
+ IN BOOLEAN UsingIpv6
+ )
+{
+
+ if (HttpService == NULL) {
+ return ;
+ }
+ if (!UsingIpv6) {
+ if (HttpService->Tcp4ChildHandle != NULL) {
+ gBS->CloseProtocol (
+ HttpService->Tcp4ChildHandle,
+ &gEfiTcp4ProtocolGuid,
+ HttpService->Ip4DriverBindingHandle,
+ HttpService->ControllerHandle
+ );
+
+ NetLibDestroyServiceChild (
+ HttpService->ControllerHandle,
+ HttpService->Ip4DriverBindingHandle,
+ &gEfiTcp4ServiceBindingProtocolGuid,
+ HttpService->Tcp4ChildHandle
+ );
+
+ HttpService->Tcp4ChildHandle = NULL;
+ }
+ } else {
+ if (HttpService->Tcp6ChildHandle != NULL) {
+ gBS->CloseProtocol (
+ HttpService->Tcp6ChildHandle,
+ &gEfiTcp6ProtocolGuid,
+ HttpService->Ip6DriverBindingHandle,
+ HttpService->ControllerHandle
+ );
+
+ NetLibDestroyServiceChild (
+ HttpService->ControllerHandle,
+ HttpService->Ip6DriverBindingHandle,
+ &gEfiTcp6ServiceBindingProtocolGuid,
+ HttpService->Tcp6ChildHandle
+ );
+
+ HttpService->Tcp6ChildHandle = NULL;
+ }
+ }
+
+}
+
+/**
+ The event process routine when the http utilities protocol is installed
+ in the system.
+
+ @param[in] Event Not used.
+ @param[in] Context The pointer to the IP4 config2 instance data or IP6 Config instance data.
+
+**/
+VOID
+EFIAPI
+HttpUtilitiesInstalledCallback (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ gBS->LocateProtocol (
+ &gEfiHttpUtilitiesProtocolGuid,
+ NULL,
+ (VOID **) &mHttpUtilities
+ );
+
+ //
+ // Close the event if Http utilities protocol is loacted.
+ //
+ if (mHttpUtilities != NULL && Event != NULL) {
+ gBS->CloseEvent (Event);
+ }
+}
+
+/**
+ This is the declaration of an EFI image entry point. This entry point is
+ the same for UEFI Applications, UEFI OS Loaders, and UEFI Drivers including
+ both device drivers and bus drivers.
+
+ @param ImageHandle The firmware allocated handle for the UEFI image.
+ @param SystemTable A pointer to the EFI System Table.
+
+ @retval EFI_SUCCESS The operation completed successfully.
+ @retval Others An unexpected error occurred.
+
+**/
+EFI_STATUS
+EFIAPI
+HttpDxeDriverEntryPoint (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+ VOID *Registration;
+
+ gBS->LocateProtocol (
+ &gEfiHttpUtilitiesProtocolGuid,
+ NULL,
+ (VOID **) &mHttpUtilities
+ );
+
+ if (mHttpUtilities == NULL) {
+ //
+ // No Http utilities protocol, register a notify.
+ //
+ EfiCreateProtocolNotifyEvent (
+ &gEfiHttpUtilitiesProtocolGuid,
+ TPL_CALLBACK,
+ HttpUtilitiesInstalledCallback,
+ NULL,
+ &Registration
+ );
+ }
+
+ //
+ // Install UEFI Driver Model protocol(s).
+ //
+ Status = EfiLibInstallDriverBindingComponentName2 (
+ ImageHandle,
+ SystemTable,
+ &gHttpDxeIp4DriverBinding,
+ ImageHandle,
+ &gHttpDxeComponentName,
+ &gHttpDxeComponentName2
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = EfiLibInstallDriverBindingComponentName2 (
+ ImageHandle,
+ SystemTable,
+ &gHttpDxeIp6DriverBinding,
+ NULL,
+ &gHttpDxeComponentName,
+ &gHttpDxeComponentName2
+ );
+ if (EFI_ERROR (Status)) {
+ gBS->UninstallMultipleProtocolInterfaces (
+ ImageHandle,
+ &gEfiDriverBindingProtocolGuid,
+ &gHttpDxeIp4DriverBinding,
+ &gEfiComponentName2ProtocolGuid,
+ &gHttpDxeComponentName2,
+ &gEfiComponentNameProtocolGuid,
+ &gHttpDxeComponentName,
+ NULL
+ );
+ }
+ return Status;
+}
+
+/**
+ Callback function which provided by user to remove one node in NetDestroyLinkList process.
+
+ @param[in] Entry The entry to be removed.
+ @param[in] Context Pointer to the callback context corresponds to the Context in NetDestroyLinkList.
+
+ @retval EFI_INVALID_PARAMETER Any input parameter is NULL.
+ @retval EFI_SUCCESS The entry has been removed successfully.
+ @retval Others Fail to remove the entry.
+
+**/
+EFI_STATUS
+EFIAPI
+HttpDestroyChildEntryInHandleBuffer (
+ IN LIST_ENTRY *Entry,
+ IN VOID *Context
+ )
+{
+ HTTP_PROTOCOL *HttpInstance;
+ EFI_SERVICE_BINDING_PROTOCOL *ServiceBinding;
+ UINTN NumberOfChildren;
+ EFI_HANDLE *ChildHandleBuffer;
+
+ if (Entry == NULL || Context == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ HttpInstance = NET_LIST_USER_STRUCT_S (Entry, HTTP_PROTOCOL, Link, HTTP_PROTOCOL_SIGNATURE);
+ ServiceBinding = ((HTTP_DESTROY_CHILD_IN_HANDLE_BUF_CONTEXT *) Context)->ServiceBinding;
+ NumberOfChildren = ((HTTP_DESTROY_CHILD_IN_HANDLE_BUF_CONTEXT *) Context)->NumberOfChildren;
+ ChildHandleBuffer = ((HTTP_DESTROY_CHILD_IN_HANDLE_BUF_CONTEXT *) Context)->ChildHandleBuffer;
+
+ if (!NetIsInHandleBuffer (HttpInstance->Handle, NumberOfChildren, ChildHandleBuffer)) {
+ return EFI_SUCCESS;
+ }
+
+ return ServiceBinding->DestroyChild (ServiceBinding, HttpInstance->Handle);
+}
+
+/**
+ Test to see if this driver supports ControllerHandle. This is the worker function for
+ HttpDxeIp4(6)DriverBindingSupported.
+
+ @param[in] This The pointer to the driver binding protocol.
+ @param[in] ControllerHandle The handle of device to be tested.
+ @param[in] RemainingDevicePath Optional parameter used to pick a specific child
+ device to be started.
+ @param[in] IpVersion IP_VERSION_4 or IP_VERSION_6.
+
+ @retval EFI_SUCCESS This driver supports this device.
+ @retval EFI_UNSUPPORTED This driver does not support this device.
+
+**/
+EFI_STATUS
+EFIAPI
+HttpDxeSupported (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL,
+ IN UINT8 IpVersion
+ )
+{
+ EFI_STATUS Status;
+ EFI_GUID *TcpServiceBindingProtocolGuid;
+
+ if (IpVersion == IP_VERSION_4) {
+ TcpServiceBindingProtocolGuid = &gEfiTcp4ServiceBindingProtocolGuid;
+ } else {
+ TcpServiceBindingProtocolGuid = &gEfiTcp6ServiceBindingProtocolGuid;
+ }
+
+ Status = gBS->OpenProtocol (
+ ControllerHandle,
+ TcpServiceBindingProtocolGuid,
+ NULL,
+ This->DriverBindingHandle,
+ ControllerHandle,
+ EFI_OPEN_PROTOCOL_TEST_PROTOCOL
+ );
+
+ if (EFI_ERROR (Status)) {
+ return EFI_UNSUPPORTED;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Start this driver on ControllerHandle. This is the worker function for
+ HttpDxeIp4(6)DriverBindingStart.
+
+ @param[in] This The pointer to the driver binding protocol.
+ @param[in] ControllerHandle The handle of device to be started.
+ @param[in] RemainingDevicePath Optional parameter used to pick a specific child
+ device to be started.
+ @param[in] IpVersion IP_VERSION_4 or IP_VERSION_6.
+
+
+ @retval EFI_SUCCESS This driver is installed to ControllerHandle.
+ @retval EFI_ALREADY_STARTED This driver is already running on ControllerHandle.
+ @retval other This driver does not support this device.
+
+**/
+EFI_STATUS
+EFIAPI
+HttpDxeStart (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL,
+ IN UINT8 IpVersion
+ )
+{
+ EFI_STATUS Status;
+ EFI_SERVICE_BINDING_PROTOCOL *ServiceBinding;
+ HTTP_SERVICE *HttpService;
+ VOID *Interface;
+ BOOLEAN UsingIpv6;
+
+ UsingIpv6 = FALSE;
+
+ //
+ // Test for the Http service binding protocol
+ //
+ Status = gBS->OpenProtocol (
+ ControllerHandle,
+ &gEfiHttpServiceBindingProtocolGuid,
+ (VOID **) &ServiceBinding,
+ This->DriverBindingHandle,
+ ControllerHandle,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+
+ if (!EFI_ERROR (Status)) {
+ HttpService = HTTP_SERVICE_FROM_PROTOCOL (ServiceBinding);
+ } else {
+ Status = HttpCreateService (ControllerHandle, &HttpService);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ ASSERT (HttpService != NULL);
+
+ //
+ // Install the HttpServiceBinding Protocol onto Controller
+ //
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &ControllerHandle,
+ &gEfiHttpServiceBindingProtocolGuid,
+ &HttpService->ServiceBinding,
+ NULL
+ );
+
+ if (EFI_ERROR (Status)) {
+ goto ON_ERROR;
+ }
+ }
+
+ if (IpVersion == IP_VERSION_4) {
+ HttpService->Ip4DriverBindingHandle = This->DriverBindingHandle;
+
+ if (HttpService->Tcp4ChildHandle == NULL) {
+ //
+ // Create a TCP4 child instance, but do not configure it. This will establish the parent-child relationship.
+ //
+ Status = NetLibCreateServiceChild (
+ ControllerHandle,
+ This->DriverBindingHandle,
+ &gEfiTcp4ServiceBindingProtocolGuid,
+ &HttpService->Tcp4ChildHandle
+ );
+
+ if (EFI_ERROR (Status)) {
+ goto ON_ERROR;
+ }
+
+ Status = gBS->OpenProtocol (
+ HttpService->Tcp4ChildHandle,
+ &gEfiTcp4ProtocolGuid,
+ &Interface,
+ This->DriverBindingHandle,
+ ControllerHandle,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+
+ if (EFI_ERROR (Status)) {
+ goto ON_ERROR;
+ }
+
+ } else {
+ return EFI_ALREADY_STARTED;
+ }
+
+ } else {
+ UsingIpv6 = TRUE;
+ HttpService->Ip6DriverBindingHandle = This->DriverBindingHandle;
+
+ if (HttpService->Tcp6ChildHandle == NULL) {
+ //
+ // Create a TCP6 child instance, but do not configure it. This will establish the parent-child relationship.
+ //
+ Status = NetLibCreateServiceChild (
+ ControllerHandle,
+ This->DriverBindingHandle,
+ &gEfiTcp6ServiceBindingProtocolGuid,
+ &HttpService->Tcp6ChildHandle
+ );
+
+ if (EFI_ERROR (Status)) {
+ goto ON_ERROR;
+ }
+
+ Status = gBS->OpenProtocol (
+ HttpService->Tcp6ChildHandle,
+ &gEfiTcp6ProtocolGuid,
+ &Interface,
+ This->DriverBindingHandle,
+ ControllerHandle,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+
+ if (EFI_ERROR (Status)) {
+ goto ON_ERROR;
+ }
+
+ } else {
+ return EFI_ALREADY_STARTED;
+ }
+
+ }
+
+ return EFI_SUCCESS;
+
+ON_ERROR:
+
+ if (HttpService != NULL) {
+ HttpCleanService (HttpService, UsingIpv6);
+ if (HttpService->Tcp4ChildHandle == NULL && HttpService->Tcp6ChildHandle == NULL) {
+ FreePool (HttpService);
+ }
+ }
+
+ return Status;
+
+
+}
+
+/**
+ Stop this driver on ControllerHandle. This is the worker function for
+ HttpDxeIp4(6)DriverBindingStop.
+
+ @param[in] This Protocol instance pointer.
+ @param[in] ControllerHandle Handle of device to stop driver on.
+ @param[in] NumberOfChildren Number of Handles in ChildHandleBuffer. If number of
+ children is zero stop the entire bus driver.
+ @param[in] ChildHandleBuffer List of Child Handles to Stop.
+ @param[in] IpVersion IP_VERSION_4 or IP_VERSION_6.
+
+ @retval EFI_SUCCESS This driver was removed ControllerHandle.
+ @retval EFI_DEVICE_ERROR An unexpected system or network error occurred.
+ @retval Others This driver was not removed from this device
+
+**/
+EFI_STATUS
+EFIAPI
+HttpDxeStop (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN UINTN NumberOfChildren,
+ IN EFI_HANDLE *ChildHandleBuffer,
+ IN UINT8 IpVersion
+ )
+{
+ EFI_HANDLE NicHandle;
+ EFI_STATUS Status;
+ EFI_SERVICE_BINDING_PROTOCOL *ServiceBinding;
+ HTTP_SERVICE *HttpService;
+ LIST_ENTRY *List;
+ HTTP_DESTROY_CHILD_IN_HANDLE_BUF_CONTEXT Context;
+ BOOLEAN UsingIpv6;
+
+ //
+ // HTTP driver opens TCP4(6) child, So, Controller is a TCP4(6)
+ // child handle. Locate the Nic handle first. Then get the
+ // HTTP private data back.
+ //
+ if (IpVersion == IP_VERSION_4) {
+ UsingIpv6 = FALSE;
+ NicHandle = NetLibGetNicHandle (ControllerHandle, &gEfiTcp4ProtocolGuid);
+ } else {
+ UsingIpv6 = TRUE;
+ NicHandle = NetLibGetNicHandle (ControllerHandle, &gEfiTcp6ProtocolGuid);
+ }
+
+ if (NicHandle == NULL) {
+ return EFI_SUCCESS;
+ }
+
+ Status = gBS->OpenProtocol (
+ NicHandle,
+ &gEfiHttpServiceBindingProtocolGuid,
+ (VOID **) &ServiceBinding,
+ This->DriverBindingHandle,
+ NicHandle,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+
+ if (!EFI_ERROR (Status)) {
+
+ HttpService = HTTP_SERVICE_FROM_PROTOCOL (ServiceBinding);
+
+ if (NumberOfChildren != 0) {
+ //
+ // Destroy the HTTP child instance in ChildHandleBuffer.
+ //
+ List = &HttpService->ChildrenList;
+ Context.ServiceBinding = ServiceBinding;
+ Context.NumberOfChildren = NumberOfChildren;
+ Context.ChildHandleBuffer = ChildHandleBuffer;
+ Status = NetDestroyLinkList (
+ List,
+ HttpDestroyChildEntryInHandleBuffer,
+ &Context,
+ NULL
+ );
+ } else {
+
+ HttpCleanService (HttpService, UsingIpv6);
+
+ if (HttpService->Tcp4ChildHandle == NULL && HttpService->Tcp6ChildHandle == NULL) {
+ gBS->UninstallProtocolInterface (
+ NicHandle,
+ &gEfiHttpServiceBindingProtocolGuid,
+ ServiceBinding
+ );
+ FreePool (HttpService);
+ }
+ Status = EFI_SUCCESS;
+ }
+ }
+
+ return Status;
+
+}
+
+/**
+ Tests to see if this driver supports a given controller. If a child device is provided,
+ it further tests to see if this driver supports creating a handle for the specified child device.
+
+ This function checks to see if the driver specified by This supports the device specified by
+ ControllerHandle. Drivers will typically use the device path attached to
+ ControllerHandle and/or the services from the bus I/O abstraction attached to
+ ControllerHandle to determine if the driver supports ControllerHandle. This function
+ may be called many times during platform initialization. In order to reduce boot times, the tests
+ performed by this function must be very small, and take as little time as possible to execute. This
+ function must not change the state of any hardware devices, and this function must be aware that the
+ device specified by ControllerHandle may already be managed by the same driver or a
+ different driver. This function must match its calls to AllocatePages() with FreePages(),
+ AllocatePool() with FreePool(), and OpenProtocol() with CloseProtocol().
+ Because ControllerHandle may have been previously started by the same driver, if a protocol is
+ already in the opened state, then it must not be closed with CloseProtocol(). This is required
+ to guarantee the state of ControllerHandle is not modified by this function.
+
+ @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
+ @param[in] ControllerHandle The handle of the controller to test. This handle
+ must support a protocol interface that supplies
+ an I/O abstraction to the driver.
+ @param[in] RemainingDevicePath A pointer to the remaining portion of a device path. This
+ parameter is ignored by device drivers, and is optional for bus
+ drivers. For bus drivers, if this parameter is not NULL, then
+ the bus driver must determine if the bus controller specified
+ by ControllerHandle and the child controller specified
+ by RemainingDevicePath are both supported by this
+ bus driver.
+
+ @retval EFI_SUCCESS The device specified by ControllerHandle and
+ RemainingDevicePath is supported by the driver specified by This.
+ @retval EFI_ALREADY_STARTED The device specified by ControllerHandle and
+ RemainingDevicePath is already being managed by the driver
+ specified by This.
+ @retval EFI_ACCESS_DENIED The device specified by ControllerHandle and
+ RemainingDevicePath is already being managed by a different
+ driver or an application that requires exclusive access.
+ Currently not implemented.
+ @retval EFI_UNSUPPORTED The device specified by ControllerHandle and
+ RemainingDevicePath is not supported by the driver specified by This.
+**/
+EFI_STATUS
+EFIAPI
+HttpDxeIp4DriverBindingSupported (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL
+ )
+{
+ return HttpDxeSupported (
+ This,
+ ControllerHandle,
+ RemainingDevicePath,
+ IP_VERSION_4
+ );
+}
+
+/**
+ Starts a device controller or a bus controller.
+
+ The Start() function is designed to be invoked from the EFI boot service ConnectController().
+ As a result, much of the error checking on the parameters to Start() has been moved into this
+ common boot service. It is legal to call Start() from other locations,
+ but the following calling restrictions must be followed, or the system behavior will not be deterministic.
+ 1. ControllerHandle must be a valid EFI_HANDLE.
+ 2. If RemainingDevicePath is not NULL, then it must be a pointer to a naturally aligned
+ EFI_DEVICE_PATH_PROTOCOL.
+ 3. Prior to calling Start(), the Supported() function for the driver specified by This must
+ have been called with the same calling parameters, and Supported() must have returned EFI_SUCCESS.
+
+ @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
+ @param[in] ControllerHandle The handle of the controller to start. This handle
+ must support a protocol interface that supplies
+ an I/O abstraction to the driver.
+ @param[in] RemainingDevicePath A pointer to the remaining portion of a device path. This
+ parameter is ignored by device drivers, and is optional for bus
+ drivers. For a bus driver, if this parameter is NULL, then handles
+ for all the children of Controller are created by this driver.
+ If this parameter is not NULL and the first Device Path Node is
+ not the End of Device Path Node, then only the handle for the
+ child device specified by the first Device Path Node of
+ RemainingDevicePath is created by this driver.
+ If the first Device Path Node of RemainingDevicePath is
+ the End of Device Path Node, no child handle is created by this
+ driver.
+
+ @retval EFI_SUCCESS The device was started.
+ @retval EFI_ALREADY_STARTED This device is already running on ControllerHandle.
+ @retval EFI_DEVICE_ERROR The device could not be started due to a device error.Currently not implemented.
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
+ @retval Others The driver failded to start the device.
+
+**/
+EFI_STATUS
+EFIAPI
+HttpDxeIp4DriverBindingStart (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL
+ )
+{
+ return HttpDxeStart (
+ This,
+ ControllerHandle,
+ RemainingDevicePath,
+ IP_VERSION_4
+ );
+}
+
+/**
+ Stops a device controller or a bus controller.
+
+ The Stop() function is designed to be invoked from the EFI boot service DisconnectController().
+ As a result, much of the error checking on the parameters to Stop() has been moved
+ into this common boot service. It is legal to call Stop() from other locations,
+ but the following calling restrictions must be followed, or the system behavior will not be deterministic.
+ 1. ControllerHandle must be a valid EFI_HANDLE that was used on a previous call to this
+ same driver's Start() function.
+ 2. The first NumberOfChildren handles of ChildHandleBuffer must all be a valid
+ EFI_HANDLE. In addition, all of these handles must have been created in this driver's
+ Start() function, and the Start() function must have called OpenProtocol() on
+ ControllerHandle with an Attribute of EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER.
+
+ @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
+ @param[in] ControllerHandle A handle to the device being stopped. The handle must
+ support a bus specific I/O protocol for the driver
+ to use to stop the device.
+ @param[in] NumberOfChildren The number of child device handles in ChildHandleBuffer.
+ @param[in] ChildHandleBuffer An array of child handles to be freed. May be NULL
+ if NumberOfChildren is 0.
+
+ @retval EFI_SUCCESS The device was stopped.
+ @retval EFI_DEVICE_ERROR The device could not be stopped due to a device error.
+
+**/
+EFI_STATUS
+EFIAPI
+HttpDxeIp4DriverBindingStop (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN UINTN NumberOfChildren,
+ IN EFI_HANDLE *ChildHandleBuffer OPTIONAL
+ )
+{
+ return HttpDxeStop (
+ This,
+ ControllerHandle,
+ NumberOfChildren,
+ ChildHandleBuffer,
+ IP_VERSION_4
+ );
+}
+
+/**
+ Tests to see if this driver supports a given controller. If a child device is provided,
+ it further tests to see if this driver supports creating a handle for the specified child device.
+
+ This function checks to see if the driver specified by This supports the device specified by
+ ControllerHandle. Drivers will typically use the device path attached to
+ ControllerHandle and/or the services from the bus I/O abstraction attached to
+ ControllerHandle to determine if the driver supports ControllerHandle. This function
+ may be called many times during platform initialization. In order to reduce boot times, the tests
+ performed by this function must be very small, and take as little time as possible to execute. This
+ function must not change the state of any hardware devices, and this function must be aware that the
+ device specified by ControllerHandle may already be managed by the same driver or a
+ different driver. This function must match its calls to AllocatePages() with FreePages(),
+ AllocatePool() with FreePool(), and OpenProtocol() with CloseProtocol().
+ Because ControllerHandle may have been previously started by the same driver, if a protocol is
+ already in the opened state, then it must not be closed with CloseProtocol(). This is required
+ to guarantee the state of ControllerHandle is not modified by this function.
+
+ @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
+ @param[in] ControllerHandle The handle of the controller to test. This handle
+ must support a protocol interface that supplies
+ an I/O abstraction to the driver.
+ @param[in] RemainingDevicePath A pointer to the remaining portion of a device path. This
+ parameter is ignored by device drivers, and is optional for bus
+ drivers. For bus drivers, if this parameter is not NULL, then
+ the bus driver must determine if the bus controller specified
+ by ControllerHandle and the child controller specified
+ by RemainingDevicePath are both supported by this
+ bus driver.
+
+ @retval EFI_SUCCESS The device specified by ControllerHandle and
+ RemainingDevicePath is supported by the driver specified by This.
+ @retval EFI_ALREADY_STARTED The device specified by ControllerHandle and
+ RemainingDevicePath is already being managed by the driver
+ specified by This.
+ @retval EFI_ACCESS_DENIED The device specified by ControllerHandle and
+ RemainingDevicePath is already being managed by a different
+ driver or an application that requires exclusive access.
+ Currently not implemented.
+ @retval EFI_UNSUPPORTED The device specified by ControllerHandle and
+ RemainingDevicePath is not supported by the driver specified by This.
+**/
+EFI_STATUS
+EFIAPI
+HttpDxeIp6DriverBindingSupported (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL
+ )
+{
+ return HttpDxeSupported (
+ This,
+ ControllerHandle,
+ RemainingDevicePath,
+ IP_VERSION_6
+ );
+
+}
+
+/**
+ Starts a device controller or a bus controller.
+
+ The Start() function is designed to be invoked from the EFI boot service ConnectController().
+ As a result, much of the error checking on the parameters to Start() has been moved into this
+ common boot service. It is legal to call Start() from other locations,
+ but the following calling restrictions must be followed, or the system behavior will not be deterministic.
+ 1. ControllerHandle must be a valid EFI_HANDLE.
+ 2. If RemainingDevicePath is not NULL, then it must be a pointer to a naturally aligned
+ EFI_DEVICE_PATH_PROTOCOL.
+ 3. Prior to calling Start(), the Supported() function for the driver specified by This must
+ have been called with the same calling parameters, and Supported() must have returned EFI_SUCCESS.
+
+ @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
+ @param[in] ControllerHandle The handle of the controller to start. This handle
+ must support a protocol interface that supplies
+ an I/O abstraction to the driver.
+ @param[in] RemainingDevicePath A pointer to the remaining portion of a device path. This
+ parameter is ignored by device drivers, and is optional for bus
+ drivers. For a bus driver, if this parameter is NULL, then handles
+ for all the children of Controller are created by this driver.
+ If this parameter is not NULL and the first Device Path Node is
+ not the End of Device Path Node, then only the handle for the
+ child device specified by the first Device Path Node of
+ RemainingDevicePath is created by this driver.
+ If the first Device Path Node of RemainingDevicePath is
+ the End of Device Path Node, no child handle is created by this
+ driver.
+
+ @retval EFI_SUCCESS The device was started.
+ @retval EFI_ALREADY_STARTED This device is already running on ControllerHandle.
+ @retval EFI_DEVICE_ERROR The device could not be started due to a device error.Currently not implemented.
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
+ @retval Others The driver failded to start the device.
+
+**/
+EFI_STATUS
+EFIAPI
+HttpDxeIp6DriverBindingStart (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL
+ )
+{
+ return HttpDxeStart (
+ This,
+ ControllerHandle,
+ RemainingDevicePath,
+ IP_VERSION_6
+ );
+}
+
+/**
+ Stops a device controller or a bus controller.
+
+ The Stop() function is designed to be invoked from the EFI boot service DisconnectController().
+ As a result, much of the error checking on the parameters to Stop() has been moved
+ into this common boot service. It is legal to call Stop() from other locations,
+ but the following calling restrictions must be followed, or the system behavior will not be deterministic.
+ 1. ControllerHandle must be a valid EFI_HANDLE that was used on a previous call to this
+ same driver's Start() function.
+ 2. The first NumberOfChildren handles of ChildHandleBuffer must all be a valid
+ EFI_HANDLE. In addition, all of these handles must have been created in this driver's
+ Start() function, and the Start() function must have called OpenProtocol() on
+ ControllerHandle with an Attribute of EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER.
+
+ @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
+ @param[in] ControllerHandle A handle to the device being stopped. The handle must
+ support a bus specific I/O protocol for the driver
+ to use to stop the device.
+ @param[in] NumberOfChildren The number of child device handles in ChildHandleBuffer.
+ @param[in] ChildHandleBuffer An array of child handles to be freed. May be NULL
+ if NumberOfChildren is 0.
+
+ @retval EFI_SUCCESS The device was stopped.
+ @retval EFI_DEVICE_ERROR The device could not be stopped due to a device error.
+
+**/
+EFI_STATUS
+EFIAPI
+HttpDxeIp6DriverBindingStop (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN UINTN NumberOfChildren,
+ IN EFI_HANDLE *ChildHandleBuffer OPTIONAL
+ )
+{
+ return HttpDxeStop (
+ This,
+ ControllerHandle,
+ NumberOfChildren,
+ ChildHandleBuffer,
+ IP_VERSION_6
+ );
+}
+/**
+ Creates a child handle and installs a protocol.
+
+ The CreateChild() function installs a protocol on ChildHandle.
+ If ChildHandle is a pointer to NULL, then a new handle is created and returned in ChildHandle.
+ If ChildHandle is not a pointer to NULL, then the protocol installs on the existing ChildHandle.
+
+ @param This Pointer to the EFI_SERVICE_BINDING_PROTOCOL instance.
+ @param ChildHandle Pointer to the handle of the child to create. If it is NULL,
+ then a new handle is created. If it is a pointer to an existing UEFI handle,
+ then the protocol is added to the existing UEFI handle.
+
+ @retval EFI_SUCCES The protocol was added to ChildHandle.
+ @retval EFI_INVALID_PARAMETER This is NULL, or ChildHandle is NULL.
+ @retval EFI_OUT_OF_RESOURCES There are not enough resources available to create
+ the child.
+ @retval other The child handle was not created.
+
+**/
+EFI_STATUS
+EFIAPI
+HttpServiceBindingCreateChild (
+ IN EFI_SERVICE_BINDING_PROTOCOL *This,
+ IN OUT EFI_HANDLE *ChildHandle
+ )
+{
+ HTTP_SERVICE *HttpService;
+ HTTP_PROTOCOL *HttpInstance;
+ EFI_STATUS Status;
+ EFI_TPL OldTpl;
+
+ if ((This == NULL) || (ChildHandle == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ HttpService = HTTP_SERVICE_FROM_PROTOCOL (This);
+ HttpInstance = AllocateZeroPool (sizeof (HTTP_PROTOCOL));
+ if (HttpInstance == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ HttpInstance->Signature = HTTP_PROTOCOL_SIGNATURE;
+ HttpInstance->Service = HttpService;
+ HttpInstance->Method = HttpMethodMax;
+
+ CopyMem (&HttpInstance->Http, &mEfiHttpTemplate, sizeof (HttpInstance->Http));
+ NetMapInit (&HttpInstance->TxTokens);
+ NetMapInit (&HttpInstance->RxTokens);
+
+ //
+ // Install HTTP protocol onto ChildHandle
+ //
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ ChildHandle,
+ &gEfiHttpProtocolGuid,
+ &HttpInstance->Http,
+ NULL
+ );
+
+ if (EFI_ERROR (Status)) {
+ goto ON_ERROR;
+ }
+
+ HttpInstance->Handle = *ChildHandle;
+
+ //
+ // Add it to the HTTP service's child list.
+ //
+ OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
+
+ InsertTailList (&HttpService->ChildrenList, &HttpInstance->Link);
+ HttpService->ChildrenNumber++;
+
+ gBS->RestoreTPL (OldTpl);
+
+ return EFI_SUCCESS;
+
+ON_ERROR:
+
+ NetMapClean (&HttpInstance->TxTokens);
+ NetMapClean (&HttpInstance->RxTokens);
+ FreePool (HttpInstance);
+
+ return Status;
+}
+
+/**
+ Destroys a child handle with a protocol installed on it.
+
+ The DestroyChild() function does the opposite of CreateChild(). It removes a protocol
+ that was installed by CreateChild() from ChildHandle. If the removed protocol is the
+ last protocol on ChildHandle, then ChildHandle is destroyed.
+
+ @param This Pointer to the EFI_SERVICE_BINDING_PROTOCOL instance.
+ @param ChildHandle Handle of the child to destroy
+
+ @retval EFI_SUCCES The protocol was removed from ChildHandle.
+ @retval EFI_UNSUPPORTED ChildHandle does not support the protocol that is being removed.
+ @retval EFI_INVALID_PARAMETER Child handle is NULL.
+ @retval other The child handle was not destroyed
+
+**/
+EFI_STATUS
+EFIAPI
+HttpServiceBindingDestroyChild (
+ IN EFI_SERVICE_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE ChildHandle
+ )
+{
+ HTTP_SERVICE *HttpService;
+ HTTP_PROTOCOL *HttpInstance;
+ EFI_HTTP_PROTOCOL *Http;
+ EFI_STATUS Status;
+ EFI_TPL OldTpl;
+
+ if ((This == NULL) || (ChildHandle == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ HttpService = HTTP_SERVICE_FROM_PROTOCOL (This);
+ Status = gBS->OpenProtocol (
+ ChildHandle,
+ &gEfiHttpProtocolGuid,
+ (VOID **) &Http,
+ NULL,
+ NULL,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_UNSUPPORTED;
+ }
+
+ HttpInstance = HTTP_INSTANCE_FROM_PROTOCOL (Http);
+ if (HttpInstance->Service != HttpService) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (HttpInstance->InDestroy) {
+ return EFI_SUCCESS;
+ }
+
+ HttpInstance->InDestroy = TRUE;
+
+ //
+ // Uninstall the HTTP protocol.
+ //
+ Status = gBS->UninstallProtocolInterface (
+ ChildHandle,
+ &gEfiHttpProtocolGuid,
+ Http
+ );
+
+ if (EFI_ERROR (Status)) {
+ HttpInstance->InDestroy = FALSE;
+ return Status;
+ }
+
+ HttpCleanProtocol (HttpInstance);
+
+ OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
+
+ RemoveEntryList (&HttpInstance->Link);
+ HttpService->ChildrenNumber--;
+
+ gBS->RestoreTPL (OldTpl);
+
+ FreePool (HttpInstance);
+ return EFI_SUCCESS;
+}
diff --git a/Core/NetworkPkg/HttpDxe/HttpDriver.h b/Core/NetworkPkg/HttpDxe/HttpDriver.h
new file mode 100644
index 0000000000..93a412ae2f
--- /dev/null
+++ b/Core/NetworkPkg/HttpDxe/HttpDriver.h
@@ -0,0 +1,404 @@
+/** @file
+ The header files of the driver binding and service binding protocol for HttpDxe driver.
+
+ Copyright (c) 2015 - 2016, Intel Corporation. All rights reserved.<BR>
+ (C) Copyright 2016 Hewlett Packard Enterprise Development LP<BR>
+
+ This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php.
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef __EFI_HTTP_DRIVER_H__
+#define __EFI_HTTP_DRIVER_H__
+
+#include <Uefi.h>
+#include <IndustryStandard/Http11.h>
+
+//
+// Libraries
+//
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/BaseLib.h>
+#include <Library/UefiLib.h>
+#include <Library/DebugLib.h>
+#include <Library/NetLib.h>
+#include <Library/HttpLib.h>
+#include <Library/DpcLib.h>
+
+//
+// UEFI Driver Model Protocols
+//
+#include <Protocol/DriverBinding.h>
+#include <Protocol/ServiceBinding.h>
+#include <Protocol/ComponentName2.h>
+#include <Protocol/ComponentName.h>
+
+//
+// Consumed Protocols
+//
+#include <Protocol/HttpUtilities.h>
+#include <Protocol/Tcp4.h>
+#include <Protocol/Tcp6.h>
+#include <Protocol/Dns4.h>
+#include <Protocol/Dns6.h>
+#include <Protocol/Ip4Config2.h>
+#include <Protocol/Ip6Config.h>
+#include <Protocol/Tls.h>
+#include <Protocol/TlsConfig.h>
+
+#include <Guid/ImageAuthentication.h>
+//
+// Produced Protocols
+//
+#include <Protocol/Http.h>
+
+#include <Guid/TlsAuthentication.h>
+
+#include <IndustryStandard/Tls1.h>
+
+//
+// Driver Version
+//
+#define HTTP_DRIVER_VERSION 0xa
+
+//
+// Protocol instances
+//
+extern EFI_DRIVER_BINDING_PROTOCOL gHttpDxeIp4DriverBinding;
+extern EFI_DRIVER_BINDING_PROTOCOL gHttpDxeIp6DriverBinding;
+
+extern EFI_COMPONENT_NAME2_PROTOCOL gHttpDxeComponentName2;
+extern EFI_COMPONENT_NAME_PROTOCOL gHttpDxeComponentName;
+
+extern EFI_HTTP_UTILITIES_PROTOCOL *mHttpUtilities;
+
+//
+// Include files with function prototypes
+//
+#include "ComponentName.h"
+#include "HttpImpl.h"
+#include "HttpProto.h"
+#include "HttpsSupport.h"
+#include "HttpDns.h"
+
+typedef struct {
+ EFI_SERVICE_BINDING_PROTOCOL *ServiceBinding;
+ UINTN NumberOfChildren;
+ EFI_HANDLE *ChildHandleBuffer;
+} HTTP_DESTROY_CHILD_IN_HANDLE_BUF_CONTEXT;
+
+/**
+ Tests to see if this driver supports a given controller. If a child device is provided,
+ it further tests to see if this driver supports creating a handle for the specified child device.
+
+ This function checks to see if the driver specified by This supports the device specified by
+ ControllerHandle. Drivers will typically use the device path attached to
+ ControllerHandle and/or the services from the bus I/O abstraction attached to
+ ControllerHandle to determine if the driver supports ControllerHandle. This function
+ may be called many times during platform initialization. In order to reduce boot times, the tests
+ performed by this function must be very small, and take as little time as possible to execute. This
+ function must not change the state of any hardware devices, and this function must be aware that the
+ device specified by ControllerHandle may already be managed by the same driver or a
+ different driver. This function must match its calls to AllocatePages() with FreePages(),
+ AllocatePool() with FreePool(), and OpenProtocol() with CloseProtocol().
+ Because ControllerHandle may have been previously started by the same driver, if a protocol is
+ already in the opened state, then it must not be closed with CloseProtocol(). This is required
+ to guarantee the state of ControllerHandle is not modified by this function.
+
+ @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
+ @param[in] ControllerHandle The handle of the controller to test. This handle
+ must support a protocol interface that supplies
+ an I/O abstraction to the driver.
+ @param[in] RemainingDevicePath A pointer to the remaining portion of a device path. This
+ parameter is ignored by device drivers, and is optional for bus
+ drivers. For bus drivers, if this parameter is not NULL, then
+ the bus driver must determine if the bus controller specified
+ by ControllerHandle and the child controller specified
+ by RemainingDevicePath are both supported by this
+ bus driver.
+
+ @retval EFI_SUCCESS The device specified by ControllerHandle and
+ RemainingDevicePath is supported by the driver specified by This.
+ @retval EFI_ALREADY_STARTED The device specified by ControllerHandle and
+ RemainingDevicePath is already being managed by the driver
+ specified by This.
+ @retval EFI_ACCESS_DENIED The device specified by ControllerHandle and
+ RemainingDevicePath is already being managed by a different
+ driver or an application that requires exclusive access.
+ Currently not implemented.
+ @retval EFI_UNSUPPORTED The device specified by ControllerHandle and
+ RemainingDevicePath is not supported by the driver specified by This.
+**/
+EFI_STATUS
+EFIAPI
+HttpDxeIp4DriverBindingSupported (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL
+ );
+
+/**
+ Starts a device controller or a bus controller.
+
+ The Start() function is designed to be invoked from the EFI boot service ConnectController().
+ As a result, much of the error checking on the parameters to Start() has been moved into this
+ common boot service. It is legal to call Start() from other locations,
+ but the following calling restrictions must be followed, or the system behavior will not be deterministic.
+ 1. ControllerHandle must be a valid EFI_HANDLE.
+ 2. If RemainingDevicePath is not NULL, then it must be a pointer to a naturally aligned
+ EFI_DEVICE_PATH_PROTOCOL.
+ 3. Prior to calling Start(), the Supported() function for the driver specified by This must
+ have been called with the same calling parameters, and Supported() must have returned EFI_SUCCESS.
+
+ @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
+ @param[in] ControllerHandle The handle of the controller to start. This handle
+ must support a protocol interface that supplies
+ an I/O abstraction to the driver.
+ @param[in] RemainingDevicePath A pointer to the remaining portion of a device path. This
+ parameter is ignored by device drivers, and is optional for bus
+ drivers. For a bus driver, if this parameter is NULL, then handles
+ for all the children of Controller are created by this driver.
+ If this parameter is not NULL and the first Device Path Node is
+ not the End of Device Path Node, then only the handle for the
+ child device specified by the first Device Path Node of
+ RemainingDevicePath is created by this driver.
+ If the first Device Path Node of RemainingDevicePath is
+ the End of Device Path Node, no child handle is created by this
+ driver.
+
+ @retval EFI_SUCCESS The device was started.
+ @retval EFI_DEVICE_ERROR The device could not be started due to a device error.Currently not implemented.
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
+ @retval Others The driver failded to start the device.
+
+**/
+EFI_STATUS
+EFIAPI
+HttpDxeIp4DriverBindingStart (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL
+ );
+
+/**
+ Stops a device controller or a bus controller.
+
+ The Stop() function is designed to be invoked from the EFI boot service DisconnectController().
+ As a result, much of the error checking on the parameters to Stop() has been moved
+ into this common boot service. It is legal to call Stop() from other locations,
+ but the following calling restrictions must be followed, or the system behavior will not be deterministic.
+ 1. ControllerHandle must be a valid EFI_HANDLE that was used on a previous call to this
+ same driver's Start() function.
+ 2. The first NumberOfChildren handles of ChildHandleBuffer must all be a valid
+ EFI_HANDLE. In addition, all of these handles must have been created in this driver's
+ Start() function, and the Start() function must have called OpenProtocol() on
+ ControllerHandle with an Attribute of EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER.
+
+ @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
+ @param[in] ControllerHandle A handle to the device being stopped. The handle must
+ support a bus specific I/O protocol for the driver
+ to use to stop the device.
+ @param[in] NumberOfChildren The number of child device handles in ChildHandleBuffer.
+ @param[in] ChildHandleBuffer An array of child handles to be freed. May be NULL
+ if NumberOfChildren is 0.
+
+ @retval EFI_SUCCESS The device was stopped.
+ @retval EFI_DEVICE_ERROR The device could not be stopped due to a device error.
+
+**/
+EFI_STATUS
+EFIAPI
+HttpDxeIp4DriverBindingStop (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN UINTN NumberOfChildren,
+ IN EFI_HANDLE *ChildHandleBuffer OPTIONAL
+ );
+
+/**
+ Tests to see if this driver supports a given controller. If a child device is provided,
+ it further tests to see if this driver supports creating a handle for the specified child device.
+
+ This function checks to see if the driver specified by This supports the device specified by
+ ControllerHandle. Drivers will typically use the device path attached to
+ ControllerHandle and/or the services from the bus I/O abstraction attached to
+ ControllerHandle to determine if the driver supports ControllerHandle. This function
+ may be called many times during platform initialization. In order to reduce boot times, the tests
+ performed by this function must be very small, and take as little time as possible to execute. This
+ function must not change the state of any hardware devices, and this function must be aware that the
+ device specified by ControllerHandle may already be managed by the same driver or a
+ different driver. This function must match its calls to AllocatePages() with FreePages(),
+ AllocatePool() with FreePool(), and OpenProtocol() with CloseProtocol().
+ Because ControllerHandle may have been previously started by the same driver, if a protocol is
+ already in the opened state, then it must not be closed with CloseProtocol(). This is required
+ to guarantee the state of ControllerHandle is not modified by this function.
+
+ @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
+ @param[in] ControllerHandle The handle of the controller to test. This handle
+ must support a protocol interface that supplies
+ an I/O abstraction to the driver.
+ @param[in] RemainingDevicePath A pointer to the remaining portion of a device path. This
+ parameter is ignored by device drivers, and is optional for bus
+ drivers. For bus drivers, if this parameter is not NULL, then
+ the bus driver must determine if the bus controller specified
+ by ControllerHandle and the child controller specified
+ by RemainingDevicePath are both supported by this
+ bus driver.
+
+ @retval EFI_SUCCESS The device specified by ControllerHandle and
+ RemainingDevicePath is supported by the driver specified by This.
+ @retval EFI_ALREADY_STARTED The device specified by ControllerHandle and
+ RemainingDevicePath is already being managed by the driver
+ specified by This.
+ @retval EFI_ACCESS_DENIED The device specified by ControllerHandle and
+ RemainingDevicePath is already being managed by a different
+ driver or an application that requires exclusive access.
+ Currently not implemented.
+ @retval EFI_UNSUPPORTED The device specified by ControllerHandle and
+ RemainingDevicePath is not supported by the driver specified by This.
+**/
+EFI_STATUS
+EFIAPI
+HttpDxeIp6DriverBindingSupported (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL
+ );
+
+/**
+ Starts a device controller or a bus controller.
+
+ The Start() function is designed to be invoked from the EFI boot service ConnectController().
+ As a result, much of the error checking on the parameters to Start() has been moved into this
+ common boot service. It is legal to call Start() from other locations,
+ but the following calling restrictions must be followed, or the system behavior will not be deterministic.
+ 1. ControllerHandle must be a valid EFI_HANDLE.
+ 2. If RemainingDevicePath is not NULL, then it must be a pointer to a naturally aligned
+ EFI_DEVICE_PATH_PROTOCOL.
+ 3. Prior to calling Start(), the Supported() function for the driver specified by This must
+ have been called with the same calling parameters, and Supported() must have returned EFI_SUCCESS.
+
+ @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
+ @param[in] ControllerHandle The handle of the controller to start. This handle
+ must support a protocol interface that supplies
+ an I/O abstraction to the driver.
+ @param[in] RemainingDevicePath A pointer to the remaining portion of a device path. This
+ parameter is ignored by device drivers, and is optional for bus
+ drivers. For a bus driver, if this parameter is NULL, then handles
+ for all the children of Controller are created by this driver.
+ If this parameter is not NULL and the first Device Path Node is
+ not the End of Device Path Node, then only the handle for the
+ child device specified by the first Device Path Node of
+ RemainingDevicePath is created by this driver.
+ If the first Device Path Node of RemainingDevicePath is
+ the End of Device Path Node, no child handle is created by this
+ driver.
+
+ @retval EFI_SUCCESS The device was started.
+ @retval EFI_ALREADY_STARTED This device is already running on ControllerHandle.
+ @retval EFI_DEVICE_ERROR The device could not be started due to a device error.Currently not implemented.
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
+ @retval Others The driver failded to start the device.
+
+**/
+EFI_STATUS
+EFIAPI
+HttpDxeIp6DriverBindingStart (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL
+ );
+
+/**
+ Stops a device controller or a bus controller.
+
+ The Stop() function is designed to be invoked from the EFI boot service DisconnectController().
+ As a result, much of the error checking on the parameters to Stop() has been moved
+ into this common boot service. It is legal to call Stop() from other locations,
+ but the following calling restrictions must be followed, or the system behavior will not be deterministic.
+ 1. ControllerHandle must be a valid EFI_HANDLE that was used on a previous call to this
+ same driver's Start() function.
+ 2. The first NumberOfChildren handles of ChildHandleBuffer must all be a valid
+ EFI_HANDLE. In addition, all of these handles must have been created in this driver's
+ Start() function, and the Start() function must have called OpenProtocol() on
+ ControllerHandle with an Attribute of EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER.
+
+ @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
+ @param[in] ControllerHandle A handle to the device being stopped. The handle must
+ support a bus specific I/O protocol for the driver
+ to use to stop the device.
+ @param[in] NumberOfChildren The number of child device handles in ChildHandleBuffer.
+ @param[in] ChildHandleBuffer An array of child handles to be freed. May be NULL
+ if NumberOfChildren is 0.
+
+ @retval EFI_SUCCESS The device was stopped.
+ @retval EFI_DEVICE_ERROR The device could not be stopped due to a device error.
+
+**/
+EFI_STATUS
+EFIAPI
+HttpDxeIp6DriverBindingStop (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN UINTN NumberOfChildren,
+ IN EFI_HANDLE *ChildHandleBuffer OPTIONAL
+ );
+
+/**
+ Creates a child handle and installs a protocol.
+
+ The CreateChild() function installs a protocol on ChildHandle.
+ If ChildHandle is a pointer to NULL, then a new handle is created and returned in ChildHandle.
+ If ChildHandle is not a pointer to NULL, then the protocol installs on the existing ChildHandle.
+
+ @param This Pointer to the EFI_SERVICE_BINDING_PROTOCOL instance.
+ @param ChildHandle Pointer to the handle of the child to create. If it is NULL,
+ then a new handle is created. If it is a pointer to an existing UEFI handle,
+ then the protocol is added to the existing UEFI handle.
+
+ @retval EFI_SUCCES The protocol was added to ChildHandle.
+ @retval EFI_INVALID_PARAMETER This is NULL, or ChildHandle is NULL.
+ @retval EFI_OUT_OF_RESOURCES There are not enough resources available to create
+ the child.
+ @retval other The child handle was not created.
+
+**/
+EFI_STATUS
+EFIAPI
+HttpServiceBindingCreateChild (
+ IN EFI_SERVICE_BINDING_PROTOCOL *This,
+ IN OUT EFI_HANDLE *ChildHandle
+ );
+
+/**
+ Destroys a child handle with a protocol installed on it.
+
+ The DestroyChild() function does the opposite of CreateChild(). It removes a protocol
+ that was installed by CreateChild() from ChildHandle. If the removed protocol is the
+ last protocol on ChildHandle, then ChildHandle is destroyed.
+
+ @param This Pointer to the EFI_SERVICE_BINDING_PROTOCOL instance.
+ @param ChildHandle Handle of the child to destroy
+
+ @retval EFI_SUCCES The protocol was removed from ChildHandle.
+ @retval EFI_UNSUPPORTED ChildHandle does not support the protocol that is being removed.
+ @retval EFI_INVALID_PARAMETER Child handle is NULL.
+ @retval other The child handle was not destroyed
+
+**/
+EFI_STATUS
+EFIAPI
+HttpServiceBindingDestroyChild (
+ IN EFI_SERVICE_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE ChildHandle
+ );
+
+#endif
diff --git a/Core/NetworkPkg/HttpDxe/HttpDxe.inf b/Core/NetworkPkg/HttpDxe/HttpDxe.inf
new file mode 100644
index 0000000000..df2efdc257
--- /dev/null
+++ b/Core/NetworkPkg/HttpDxe/HttpDxe.inf
@@ -0,0 +1,82 @@
+## @file
+# Implementation of EFI HTTP protocol interfaces.
+#
+# Copyright (c) 2015 - 2017, Intel Corporation. All rights reserved.<BR>
+#
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php.
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = HttpDxe
+ FILE_GUID = 2366c20f-e15a-11e3-8bf1-e4115b28bc50
+ MODULE_TYPE = UEFI_DRIVER
+ VERSION_STRING = 1.0
+ ENTRY_POINT = HttpDxeDriverEntryPoint
+ UNLOAD_IMAGE = NetLibDefaultUnload
+ MODULE_UNI_FILE = HttpDxe.uni
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ NetworkPkg/NetworkPkg.dec
+
+[Sources]
+ ComponentName.h
+ ComponentName.c
+ HttpDns.h
+ HttpDns.c
+ HttpDriver.h
+ HttpDriver.c
+ HttpImpl.h
+ HttpImpl.c
+ HttpProto.h
+ HttpProto.c
+ HttpsSupport.h
+ HttpsSupport.c
+
+[LibraryClasses]
+ UefiDriverEntryPoint
+ UefiBootServicesTableLib
+ UefiRuntimeServicesTableLib
+ MemoryAllocationLib
+ BaseLib
+ UefiLib
+ DebugLib
+ NetLib
+ HttpLib
+ DpcLib
+
+[Protocols]
+ gEfiHttpServiceBindingProtocolGuid ## BY_START
+ gEfiHttpProtocolGuid ## BY_START
+ gEfiHttpUtilitiesProtocolGuid ## CONSUMES
+ gEfiTcp4ServiceBindingProtocolGuid ## TO_START
+ gEfiTcp4ProtocolGuid ## TO_START
+ gEfiTcp6ServiceBindingProtocolGuid ## TO_START
+ gEfiTcp6ProtocolGuid ## TO_START
+ gEfiDns4ServiceBindingProtocolGuid ## SOMETIMES_CONSUMES
+ gEfiDns4ProtocolGuid ## SOMETIMES_CONSUMES
+ gEfiDns6ServiceBindingProtocolGuid ## SOMETIMES_CONSUMES
+ gEfiDns6ProtocolGuid ## SOMETIMES_CONSUMES
+ gEfiIp4Config2ProtocolGuid ## SOMETIMES_CONSUMES
+ gEfiIp6ConfigProtocolGuid ## SOMETIMES_CONSUMES
+ gEfiTlsServiceBindingProtocolGuid ## SOMETIMES_CONSUMES
+ gEfiTlsProtocolGuid ## SOMETIMES_CONSUMES
+ gEfiTlsConfigurationProtocolGuid ## SOMETIMES_CONSUMES
+
+[Guids]
+ gEfiTlsCaCertificateGuid ## CONSUMES ## GUID
+
+[Pcd]
+ gEfiNetworkPkgTokenSpaceGuid.PcdAllowHttpConnections ## CONSUMES
+
+[UserExtensions.TianoCore."ExtraFiles"]
+ HttpDxeExtra.uni \ No newline at end of file
diff --git a/Core/NetworkPkg/HttpDxe/HttpDxe.uni b/Core/NetworkPkg/HttpDxe/HttpDxe.uni
new file mode 100644
index 0000000000..8aee8f72a6
--- /dev/null
+++ b/Core/NetworkPkg/HttpDxe/HttpDxe.uni
@@ -0,0 +1,23 @@
+// /** @file
+// UEFI HTTP DXE Driver.
+//
+// This driver provides UEFI 2.5 HTTP protocols. It could work with an IPv4 or IPv6 stack.
+//
+//
+// Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
+//
+// This program and the accompanying materials
+// are licensed and made available under the terms and conditions of the BSD License
+// which accompanies this distribution. The full text of the license may be found at
+// http://opensource.org/licenses/bsd-license.php.
+//
+// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "UEFI HTTP service"
+
+#string STR_MODULE_DESCRIPTION #language en-US "This driver provides EFI HTTP Protocol and EFI HTTP Service Binding Protocol. It could work with an IPv4 or IPv6 stack."
+
diff --git a/Core/NetworkPkg/HttpDxe/HttpDxeExtra.uni b/Core/NetworkPkg/HttpDxe/HttpDxeExtra.uni
new file mode 100644
index 0000000000..2e96fc8aa5
--- /dev/null
+++ b/Core/NetworkPkg/HttpDxe/HttpDxeExtra.uni
@@ -0,0 +1,20 @@
+// /** @file
+// HttpDxe Localized Strings and Content
+//
+// Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
+//
+// This program and the accompanying materials
+// are licensed and made available under the terms and conditions of the BSD License
+// which accompanies this distribution. The full text of the license may be found at
+// http://opensource.org/licenses/bsd-license.php.
+//
+// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+//
+// **/
+
+#string STR_PROPERTIES_MODULE_NAME
+#language en-US
+"UEFI HTTP DXE"
+
+
diff --git a/Core/NetworkPkg/HttpDxe/HttpImpl.c b/Core/NetworkPkg/HttpDxe/HttpImpl.c
new file mode 100644
index 0000000000..1f7a4fa52a
--- /dev/null
+++ b/Core/NetworkPkg/HttpDxe/HttpImpl.c
@@ -0,0 +1,1648 @@
+/** @file
+ Implementation of EFI_HTTP_PROTOCOL protocol interfaces.
+
+ Copyright (c) 2015 - 2017, Intel Corporation. All rights reserved.<BR>
+ (C) Copyright 2015-2016 Hewlett Packard Enterprise Development LP<BR>
+
+ This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php.
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "HttpDriver.h"
+
+EFI_HTTP_PROTOCOL mEfiHttpTemplate = {
+ EfiHttpGetModeData,
+ EfiHttpConfigure,
+ EfiHttpRequest,
+ EfiHttpCancel,
+ EfiHttpResponse,
+ EfiHttpPoll
+};
+
+/**
+ Returns the operational parameters for the current HTTP child instance.
+
+ The GetModeData() function is used to read the current mode data (operational
+ parameters) for this HTTP protocol instance.
+
+ @param[in] This Pointer to EFI_HTTP_PROTOCOL instance.
+ @param[out] HttpConfigData Point to buffer for operational parameters of this
+ HTTP instance.
+
+ @retval EFI_SUCCESS Operation succeeded.
+ @retval EFI_INVALID_PARAMETER One or more of the following conditions is TRUE:
+ This is NULL.
+ HttpConfigData is NULL.
+ HttpInstance->LocalAddressIsIPv6 is FALSE and
+ HttpConfigData->IPv4Node is NULL.
+ HttpInstance->LocalAddressIsIPv6 is TRUE and
+ HttpConfigData->IPv6Node is NULL.
+ @retval EFI_NOT_STARTED This EFI HTTP Protocol instance has not been started.
+
+**/
+EFI_STATUS
+EFIAPI
+EfiHttpGetModeData (
+ IN EFI_HTTP_PROTOCOL *This,
+ OUT EFI_HTTP_CONFIG_DATA *HttpConfigData
+ )
+{
+ HTTP_PROTOCOL *HttpInstance;
+
+ //
+ // Check input parameters.
+ //
+ if ((This == NULL) || (HttpConfigData == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ HttpInstance = HTTP_INSTANCE_FROM_PROTOCOL (This);
+ ASSERT (HttpInstance != NULL);
+
+ if ((HttpInstance->LocalAddressIsIPv6 && HttpConfigData->AccessPoint.IPv6Node == NULL) ||
+ (!HttpInstance->LocalAddressIsIPv6 && HttpConfigData->AccessPoint.IPv4Node == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (HttpInstance->State < HTTP_STATE_HTTP_CONFIGED) {
+ return EFI_NOT_STARTED;
+ }
+
+ HttpConfigData->HttpVersion = HttpInstance->HttpVersion;
+ HttpConfigData->TimeOutMillisec = HttpInstance->TimeOutMillisec;
+ HttpConfigData->LocalAddressIsIPv6 = HttpInstance->LocalAddressIsIPv6;
+
+ if (HttpInstance->LocalAddressIsIPv6) {
+ CopyMem (
+ HttpConfigData->AccessPoint.IPv6Node,
+ &HttpInstance->Ipv6Node,
+ sizeof (HttpInstance->Ipv6Node)
+ );
+ } else {
+ CopyMem (
+ HttpConfigData->AccessPoint.IPv4Node,
+ &HttpInstance->IPv4Node,
+ sizeof (HttpInstance->IPv4Node)
+ );
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Initialize or brutally reset the operational parameters for this EFI HTTP instance.
+
+ The Configure() function does the following:
+ When HttpConfigData is not NULL Initialize this EFI HTTP instance by configuring
+ timeout, local address, port, etc.
+ When HttpConfigData is NULL, reset this EFI HTTP instance by closing all active
+ connections with remote hosts, canceling all asynchronous tokens, and flush request
+ and response buffers without informing the appropriate hosts.
+
+ No other EFI HTTP function can be executed by this instance until the Configure()
+ function is executed and returns successfully.
+
+ @param[in] This Pointer to EFI_HTTP_PROTOCOL instance.
+ @param[in] HttpConfigData Pointer to the configure data to configure the instance.
+
+ @retval EFI_SUCCESS Operation succeeded.
+ @retval EFI_INVALID_PARAMETER One or more of the following conditions is TRUE:
+ This is NULL.
+ HttpConfigData->LocalAddressIsIPv6 is FALSE and
+ HttpConfigData->IPv4Node is NULL.
+ HttpConfigData->LocalAddressIsIPv6 is TRUE and
+ HttpConfigData->IPv6Node is NULL.
+ @retval EFI_ALREADY_STARTED Reinitialize this HTTP instance without calling
+ Configure() with NULL to reset it.
+ @retval EFI_DEVICE_ERROR An unexpected system or network error occurred.
+ @retval EFI_OUT_OF_RESOURCES Could not allocate enough system resources when
+ executing Configure().
+ @retval EFI_UNSUPPORTED One or more options in HttpConfigData are not supported
+ in the implementation.
+**/
+EFI_STATUS
+EFIAPI
+EfiHttpConfigure (
+ IN EFI_HTTP_PROTOCOL *This,
+ IN EFI_HTTP_CONFIG_DATA *HttpConfigData
+ )
+{
+ HTTP_PROTOCOL *HttpInstance;
+ EFI_STATUS Status;
+
+ //
+ // Check input parameters.
+ //
+ if (This == NULL ||
+ (HttpConfigData != NULL &&
+ ((HttpConfigData->LocalAddressIsIPv6 && HttpConfigData->AccessPoint.IPv6Node == NULL) ||
+ (!HttpConfigData->LocalAddressIsIPv6 && HttpConfigData->AccessPoint.IPv4Node == NULL)))) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ HttpInstance = HTTP_INSTANCE_FROM_PROTOCOL (This);
+ ASSERT (HttpInstance != NULL && HttpInstance->Service != NULL);
+
+ if (HttpConfigData != NULL) {
+
+ //
+ // Now configure this HTTP instance.
+ //
+ if (HttpInstance->State != HTTP_STATE_UNCONFIGED) {
+ return EFI_ALREADY_STARTED;
+ }
+
+ HttpInstance->HttpVersion = HttpConfigData->HttpVersion;
+ HttpInstance->TimeOutMillisec = HttpConfigData->TimeOutMillisec;
+ HttpInstance->LocalAddressIsIPv6 = HttpConfigData->LocalAddressIsIPv6;
+
+ if (HttpConfigData->LocalAddressIsIPv6) {
+ CopyMem (
+ &HttpInstance->Ipv6Node,
+ HttpConfigData->AccessPoint.IPv6Node,
+ sizeof (HttpInstance->Ipv6Node)
+ );
+ } else {
+ CopyMem (
+ &HttpInstance->IPv4Node,
+ HttpConfigData->AccessPoint.IPv4Node,
+ sizeof (HttpInstance->IPv4Node)
+ );
+ }
+
+ //
+ // Creat Tcp child
+ //
+ Status = HttpInitProtocol (HttpInstance, HttpInstance->LocalAddressIsIPv6);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ HttpInstance->State = HTTP_STATE_HTTP_CONFIGED;
+ return EFI_SUCCESS;
+
+ } else {
+ //
+ // Reset all the resources related to HttpInsance.
+ //
+ HttpCleanProtocol (HttpInstance);
+ HttpInstance->State = HTTP_STATE_UNCONFIGED;
+ return EFI_SUCCESS;
+ }
+}
+
+
+/**
+ The Request() function queues an HTTP request to this HTTP instance.
+
+ Similar to Transmit() function in the EFI TCP driver. When the HTTP request is sent
+ successfully, or if there is an error, Status in token will be updated and Event will
+ be signaled.
+
+ @param[in] This Pointer to EFI_HTTP_PROTOCOL instance.
+ @param[in] Token Pointer to storage containing HTTP request token.
+
+ @retval EFI_SUCCESS Outgoing data was processed.
+ @retval EFI_NOT_STARTED This EFI HTTP Protocol instance has not been started.
+ @retval EFI_DEVICE_ERROR An unexpected system or network error occurred.
+ @retval EFI_TIMEOUT Data was dropped out of the transmit or receive queue.
+ @retval EFI_OUT_OF_RESOURCES Could not allocate enough system resources.
+ @retval EFI_UNSUPPORTED The HTTP method is not supported in current
+ implementation.
+ @retval EFI_INVALID_PARAMETER One or more of the following conditions is TRUE:
+ This is NULL.
+ Token is NULL.
+ Token->Message is NULL.
+ Token->Message->Body is not NULL,
+ Token->Message->BodyLength is non-zero, and
+ Token->Message->Data is NULL, but a previous call to
+ Request()has not been completed successfully.
+**/
+EFI_STATUS
+EFIAPI
+EfiHttpRequest (
+ IN EFI_HTTP_PROTOCOL *This,
+ IN EFI_HTTP_TOKEN *Token
+ )
+{
+ EFI_HTTP_MESSAGE *HttpMsg;
+ EFI_HTTP_REQUEST_DATA *Request;
+ VOID *UrlParser;
+ EFI_STATUS Status;
+ CHAR8 *HostName;
+ UINTN HostNameSize;
+ UINT16 RemotePort;
+ HTTP_PROTOCOL *HttpInstance;
+ BOOLEAN Configure;
+ BOOLEAN ReConfigure;
+ BOOLEAN TlsConfigure;
+ CHAR8 *RequestMsg;
+ CHAR8 *Url;
+ UINTN UrlLen;
+ CHAR16 *HostNameStr;
+ HTTP_TOKEN_WRAP *Wrap;
+ CHAR8 *FileUrl;
+ UINTN RequestMsgSize;
+ EFI_HANDLE ImageHandle;
+
+ //
+ // Initializations
+ //
+ Url = NULL;
+ UrlParser = NULL;
+ RemotePort = 0;
+ HostName = NULL;
+ RequestMsg = NULL;
+ HostNameStr = NULL;
+ Wrap = NULL;
+ FileUrl = NULL;
+ TlsConfigure = FALSE;
+
+ if ((This == NULL) || (Token == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ HttpMsg = Token->Message;
+ if (HttpMsg == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Request = HttpMsg->Data.Request;
+
+ //
+ // Only support GET, HEAD, PUT and POST method in current implementation.
+ //
+ if ((Request != NULL) && (Request->Method != HttpMethodGet) &&
+ (Request->Method != HttpMethodHead) && (Request->Method != HttpMethodPut) && (Request->Method != HttpMethodPost)) {
+ return EFI_UNSUPPORTED;
+ }
+
+ HttpInstance = HTTP_INSTANCE_FROM_PROTOCOL (This);
+ ASSERT (HttpInstance != NULL);
+
+ //
+ // Capture the method into HttpInstance.
+ //
+ if (Request != NULL) {
+ HttpInstance->Method = Request->Method;
+ }
+
+ if (HttpInstance->State < HTTP_STATE_HTTP_CONFIGED) {
+ return EFI_NOT_STARTED;
+ }
+
+ if (Request == NULL) {
+ //
+ // Request would be NULL only for PUT/POST operation (in the current implementation)
+ //
+ if ((HttpInstance->Method != HttpMethodPut) && (HttpInstance->Method != HttpMethodPost)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // For PUT/POST, we need to have the TCP already configured. Bail out if it is not!
+ //
+ if (HttpInstance->State < HTTP_STATE_TCP_CONFIGED) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // We need to have the Message Body for sending the HTTP message across in these cases.
+ //
+ if (HttpMsg->Body == NULL || HttpMsg->BodyLength == 0) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Use existing TCP instance to transmit the packet.
+ //
+ Configure = FALSE;
+ ReConfigure = FALSE;
+ } else {
+ //
+ // Check whether the token already existed.
+ //
+ if (EFI_ERROR (NetMapIterate (&HttpInstance->TxTokens, HttpTokenExist, Token))) {
+ return EFI_ACCESS_DENIED;
+ }
+
+ //
+ // Parse the URI of the remote host.
+ //
+ Url = HttpInstance->Url;
+ UrlLen = StrLen (Request->Url) + 1;
+ if (UrlLen > HTTP_URL_BUFFER_LEN) {
+ Url = AllocateZeroPool (UrlLen);
+ if (Url == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ FreePool (HttpInstance->Url);
+ HttpInstance->Url = Url;
+ }
+
+
+ UnicodeStrToAsciiStrS (Request->Url, Url, UrlLen);
+
+ //
+ // From the information in Url, the HTTP instance will
+ // be able to determine whether to use http or https.
+ //
+ HttpInstance->UseHttps = IsHttpsUrl (Url);
+
+ //
+ // HTTP is disabled, return directly if the URI is not HTTPS.
+ //
+ if (!PcdGetBool (PcdAllowHttpConnections) && !(HttpInstance->UseHttps)) {
+
+ DEBUG ((EFI_D_ERROR, "EfiHttpRequest: HTTP is disabled.\n"));
+
+ return EFI_ACCESS_DENIED;
+ }
+
+ //
+ // Check whether we need to create Tls child and open the TLS protocol.
+ //
+ if (HttpInstance->UseHttps && HttpInstance->TlsChildHandle == NULL) {
+ //
+ // Use TlsSb to create Tls child and open the TLS protocol.
+ //
+ if (HttpInstance->LocalAddressIsIPv6) {
+ ImageHandle = HttpInstance->Service->Ip6DriverBindingHandle;
+ } else {
+ ImageHandle = HttpInstance->Service->Ip4DriverBindingHandle;
+ }
+
+ HttpInstance->TlsChildHandle = TlsCreateChild (
+ ImageHandle,
+ &(HttpInstance->Tls),
+ &(HttpInstance->TlsConfiguration)
+ );
+ if (HttpInstance->TlsChildHandle == NULL) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ TlsConfigure = TRUE;
+ }
+
+ UrlParser = NULL;
+ Status = HttpParseUrl (Url, (UINT32) AsciiStrLen (Url), FALSE, &UrlParser);
+ if (EFI_ERROR (Status)) {
+ goto Error1;
+ }
+
+ HostName = NULL;
+ Status = HttpUrlGetHostName (Url, UrlParser, &HostName);
+ if (EFI_ERROR (Status)) {
+ goto Error1;
+ }
+
+ Status = HttpUrlGetPort (Url, UrlParser, &RemotePort);
+ if (EFI_ERROR (Status)) {
+ if (HttpInstance->UseHttps) {
+ RemotePort = HTTPS_DEFAULT_PORT;
+ } else {
+ RemotePort = HTTP_DEFAULT_PORT;
+ }
+ }
+ //
+ // If Configure is TRUE, it indicates the first time to call Request();
+ // If ReConfigure is TRUE, it indicates the request URL is not same
+ // with the previous call to Request();
+ //
+ Configure = TRUE;
+ ReConfigure = TRUE;
+
+ if (HttpInstance->RemoteHost == NULL) {
+ //
+ // Request() is called the first time.
+ //
+ ReConfigure = FALSE;
+ } else {
+ if ((HttpInstance->RemotePort == RemotePort) &&
+ (AsciiStrCmp (HttpInstance->RemoteHost, HostName) == 0) &&
+ (!HttpInstance->UseHttps || (HttpInstance->UseHttps &&
+ !TlsConfigure &&
+ HttpInstance->TlsSessionState == EfiTlsSessionDataTransferring))) {
+ //
+ // Host Name and port number of the request URL are the same with previous call to Request().
+ // If Https protocol used, the corresponding SessionState is EfiTlsSessionDataTransferring.
+ // Check whether previous TCP packet sent out.
+ //
+
+ if (EFI_ERROR (NetMapIterate (&HttpInstance->TxTokens, HttpTcpNotReady, NULL))) {
+ //
+ // Wrap the HTTP token in HTTP_TOKEN_WRAP
+ //
+ Wrap = AllocateZeroPool (sizeof (HTTP_TOKEN_WRAP));
+ if (Wrap == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Error1;
+ }
+
+ Wrap->HttpToken = Token;
+ Wrap->HttpInstance = HttpInstance;
+
+ Status = HttpCreateTcpTxEvent (Wrap);
+ if (EFI_ERROR (Status)) {
+ goto Error1;
+ }
+
+ Status = NetMapInsertTail (&HttpInstance->TxTokens, Token, Wrap);
+ if (EFI_ERROR (Status)) {
+ goto Error1;
+ }
+
+ Wrap->TcpWrap.Method = Request->Method;
+
+ FreePool (HostName);
+
+ //
+ // Queue the HTTP token and return.
+ //
+ return EFI_SUCCESS;
+ } else {
+ //
+ // Use existing TCP instance to transmit the packet.
+ //
+ Configure = FALSE;
+ ReConfigure = FALSE;
+ }
+ } else {
+ //
+ // Need close existing TCP instance and create a new TCP instance for data transmit.
+ //
+ if (HttpInstance->RemoteHost != NULL) {
+ FreePool (HttpInstance->RemoteHost);
+ HttpInstance->RemoteHost = NULL;
+ HttpInstance->RemotePort = 0;
+ }
+ }
+ }
+ }
+
+ if (Configure) {
+ //
+ // Parse Url for IPv4 or IPv6 address, if failed, perform DNS resolution.
+ //
+ if (!HttpInstance->LocalAddressIsIPv6) {
+ Status = NetLibAsciiStrToIp4 (HostName, &HttpInstance->RemoteAddr);
+ } else {
+ Status = HttpUrlGetIp6 (Url, UrlParser, &HttpInstance->RemoteIpv6Addr);
+ }
+
+ if (EFI_ERROR (Status)) {
+ HostNameSize = AsciiStrSize (HostName);
+ HostNameStr = AllocateZeroPool (HostNameSize * sizeof (CHAR16));
+ if (HostNameStr == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Error1;
+ }
+
+ AsciiStrToUnicodeStrS (HostName, HostNameStr, HostNameSize);
+ if (!HttpInstance->LocalAddressIsIPv6) {
+ Status = HttpDns4 (HttpInstance, HostNameStr, &HttpInstance->RemoteAddr);
+ } else {
+ Status = HttpDns6 (HttpInstance, HostNameStr, &HttpInstance->RemoteIpv6Addr);
+ }
+
+ FreePool (HostNameStr);
+ if (EFI_ERROR (Status)) {
+ goto Error1;
+ }
+ }
+
+ //
+ // Save the RemotePort and RemoteHost.
+ //
+ ASSERT (HttpInstance->RemoteHost == NULL);
+ HttpInstance->RemotePort = RemotePort;
+ HttpInstance->RemoteHost = HostName;
+ HostName = NULL;
+ }
+
+ if (ReConfigure) {
+ //
+ // The request URL is different from previous calls to Request(), close existing TCP instance.
+ //
+ if (!HttpInstance->LocalAddressIsIPv6) {
+ ASSERT (HttpInstance->Tcp4 != NULL);
+ } else {
+ ASSERT (HttpInstance->Tcp6 != NULL);
+ }
+
+ if (HttpInstance->UseHttps && !TlsConfigure) {
+ Status = TlsCloseSession (HttpInstance);
+ if (EFI_ERROR (Status)) {
+ goto Error1;
+ }
+
+ TlsCloseTxRxEvent (HttpInstance);
+ }
+
+ HttpCloseConnection (HttpInstance);
+ EfiHttpCancel (This, NULL);
+ }
+
+ //
+ // Wrap the HTTP token in HTTP_TOKEN_WRAP
+ //
+ Wrap = AllocateZeroPool (sizeof (HTTP_TOKEN_WRAP));
+ if (Wrap == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Error1;
+ }
+
+ Wrap->HttpToken = Token;
+ Wrap->HttpInstance = HttpInstance;
+ if (Request != NULL) {
+ Wrap->TcpWrap.Method = Request->Method;
+ }
+
+ Status = HttpInitSession (
+ HttpInstance,
+ Wrap,
+ Configure || ReConfigure,
+ TlsConfigure
+ );
+ if (EFI_ERROR (Status)) {
+ goto Error2;
+ }
+
+ if (!Configure && !ReConfigure && !TlsConfigure) {
+ //
+ // For the new HTTP token, create TX TCP token events.
+ //
+ Status = HttpCreateTcpTxEvent (Wrap);
+ if (EFI_ERROR (Status)) {
+ goto Error1;
+ }
+ }
+
+ //
+ // Create request message.
+ //
+ FileUrl = Url;
+ if (Url != NULL && *FileUrl != '/') {
+ //
+ // Convert the absolute-URI to the absolute-path
+ //
+ while (*FileUrl != ':') {
+ FileUrl++;
+ }
+ if ((*(FileUrl+1) == '/') && (*(FileUrl+2) == '/')) {
+ FileUrl += 3;
+ while (*FileUrl != '/') {
+ FileUrl++;
+ }
+ } else {
+ Status = EFI_INVALID_PARAMETER;
+ goto Error3;
+ }
+ }
+
+ Status = HttpGenRequestMessage (HttpMsg, FileUrl, &RequestMsg, &RequestMsgSize);
+
+ if (EFI_ERROR (Status) || NULL == RequestMsg) {
+ goto Error3;
+ }
+
+ ASSERT (RequestMsg != NULL);
+
+ //
+ // Every request we insert a TxToken and a response call would remove the TxToken.
+ // In cases of PUT/POST, after an initial request-response pair, we would do a
+ // continuous request without a response call. So, in such cases, where Request
+ // structure is NULL, we would not insert a TxToken.
+ //
+ if (Request != NULL) {
+ Status = NetMapInsertTail (&HttpInstance->TxTokens, Token, Wrap);
+ if (EFI_ERROR (Status)) {
+ goto Error4;
+ }
+ }
+
+ //
+ // Transmit the request message.
+ //
+ Status = HttpTransmitTcp (
+ HttpInstance,
+ Wrap,
+ (UINT8*) RequestMsg,
+ RequestMsgSize
+ );
+ if (EFI_ERROR (Status)) {
+ goto Error5;
+ }
+
+ DispatchDpc ();
+
+ if (HostName != NULL) {
+ FreePool (HostName);
+ }
+
+ return EFI_SUCCESS;
+
+Error5:
+ //
+ // We would have inserted a TxToken only if Request structure is not NULL.
+ // Hence check before we do a remove in this error case.
+ //
+ if (Request != NULL) {
+ NetMapRemoveTail (&HttpInstance->TxTokens, NULL);
+ }
+
+Error4:
+ if (RequestMsg != NULL) {
+ FreePool (RequestMsg);
+ }
+
+Error3:
+ if (HttpInstance->UseHttps) {
+ TlsCloseSession (HttpInstance);
+ TlsCloseTxRxEvent (HttpInstance);
+ }
+
+Error2:
+ HttpCloseConnection (HttpInstance);
+
+ HttpCloseTcpConnCloseEvent (HttpInstance);
+ if (NULL != Wrap->TcpWrap.Tx4Token.CompletionToken.Event) {
+ gBS->CloseEvent (Wrap->TcpWrap.Tx4Token.CompletionToken.Event);
+ Wrap->TcpWrap.Tx4Token.CompletionToken.Event = NULL;
+ }
+ if (NULL != Wrap->TcpWrap.Tx6Token.CompletionToken.Event) {
+ gBS->CloseEvent (Wrap->TcpWrap.Tx6Token.CompletionToken.Event);
+ Wrap->TcpWrap.Tx6Token.CompletionToken.Event = NULL;
+ }
+
+Error1:
+ if (HostName != NULL) {
+ FreePool (HostName);
+ }
+ if (Wrap != NULL) {
+ FreePool (Wrap);
+ }
+ if (UrlParser!= NULL) {
+ HttpUrlFreeParser (UrlParser);
+ }
+
+ return Status;
+
+}
+
+/**
+ Cancel a user's Token.
+
+ @param[in] Map The HTTP instance's token queue.
+ @param[in] Item Object container for one HTTP token and token's wrap.
+ @param[in] Context The user's token to cancel.
+
+ @retval EFI_SUCCESS Continue to check the next Item.
+ @retval EFI_ABORTED The user's Token (Token != NULL) is cancelled.
+
+**/
+EFI_STATUS
+EFIAPI
+HttpCancelTokens (
+ IN NET_MAP *Map,
+ IN NET_MAP_ITEM *Item,
+ IN VOID *Context
+ )
+{
+ EFI_HTTP_TOKEN *Token;
+ HTTP_TOKEN_WRAP *Wrap;
+ HTTP_PROTOCOL *HttpInstance;
+
+ Token = (EFI_HTTP_TOKEN *) Context;
+
+ //
+ // Return EFI_SUCCESS to check the next item in the map if
+ // this one doesn't match.
+ //
+ if ((Token != NULL) && (Token != Item->Key)) {
+ return EFI_SUCCESS;
+ }
+
+ Wrap = (HTTP_TOKEN_WRAP *) Item->Value;
+ ASSERT (Wrap != NULL);
+ HttpInstance = Wrap->HttpInstance;
+
+ if (!HttpInstance->LocalAddressIsIPv6) {
+ if (Wrap->TcpWrap.Rx4Token.CompletionToken.Event != NULL) {
+ //
+ // Cancle the Token before close its Event.
+ //
+ HttpInstance->Tcp4->Cancel (HttpInstance->Tcp4, &Wrap->TcpWrap.Rx4Token.CompletionToken);
+
+ //
+ // Dispatch the DPC queued by the NotifyFunction of the canceled token's events.
+ //
+ DispatchDpc ();
+ }
+ } else {
+ if (Wrap->TcpWrap.Rx6Token.CompletionToken.Event != NULL) {
+ //
+ // Cancle the Token before close its Event.
+ //
+ HttpInstance->Tcp6->Cancel (HttpInstance->Tcp6, &Wrap->TcpWrap.Rx6Token.CompletionToken);
+
+ //
+ // Dispatch the DPC queued by the NotifyFunction of the canceled token's events.
+ //
+ DispatchDpc ();
+ }
+ }
+
+ //
+ // If only one item is to be cancel, return EFI_ABORTED to stop
+ // iterating the map any more.
+ //
+ if (Token != NULL) {
+ return EFI_ABORTED;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Cancel the user's receive/transmit request. It is the worker function of
+ EfiHttpCancel API. If a matching token is found, it will call HttpCancelTokens to cancel the
+ token.
+
+ @param[in] HttpInstance Pointer to HTTP_PROTOCOL structure.
+ @param[in] Token The token to cancel. If NULL, all token will be
+ cancelled.
+
+ @retval EFI_SUCCESS The token is cancelled.
+ @retval EFI_NOT_FOUND The asynchronous request or response token is not found.
+ @retval Others Other error as indicated.
+
+**/
+EFI_STATUS
+HttpCancel (
+ IN HTTP_PROTOCOL *HttpInstance,
+ IN EFI_HTTP_TOKEN *Token
+ )
+{
+ EFI_STATUS Status;
+
+ //
+ // First check the tokens queued by EfiHttpRequest().
+ //
+ Status = NetMapIterate (&HttpInstance->TxTokens, HttpCancelTokens, Token);
+ if (EFI_ERROR (Status)) {
+ if (Token != NULL) {
+ if (Status == EFI_ABORTED) {
+ return EFI_SUCCESS;
+ }
+ } else {
+ return Status;
+ }
+ }
+
+ if (!HttpInstance->UseHttps) {
+ //
+ // Then check the tokens queued by EfiHttpResponse(), except for Https.
+ //
+ Status = NetMapIterate (&HttpInstance->RxTokens, HttpCancelTokens, Token);
+ if (EFI_ERROR (Status)) {
+ if (Token != NULL) {
+ if (Status == EFI_ABORTED) {
+ return EFI_SUCCESS;
+ } else {
+ return EFI_NOT_FOUND;
+ }
+ } else {
+ return Status;
+ }
+ }
+ } else {
+ if (!HttpInstance->LocalAddressIsIPv6) {
+ HttpInstance->Tcp4->Cancel (HttpInstance->Tcp4, &HttpInstance->Tcp4TlsRxToken.CompletionToken);
+ } else {
+ HttpInstance->Tcp6->Cancel (HttpInstance->Tcp6, &HttpInstance->Tcp6TlsRxToken.CompletionToken);
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Abort an asynchronous HTTP request or response token.
+
+ The Cancel() function aborts a pending HTTP request or response transaction. If
+ Token is not NULL and the token is in transmit or receive queues when it is being
+ cancelled, its Token->Status will be set to EFI_ABORTED and then Token->Event will
+ be signaled. If the token is not in one of the queues, which usually means that the
+ asynchronous operation has completed, EFI_NOT_FOUND is returned. If Token is NULL,
+ all asynchronous tokens issued by Request() or Response() will be aborted.
+
+ @param[in] This Pointer to EFI_HTTP_PROTOCOL instance.
+ @param[in] Token Point to storage containing HTTP request or response
+ token.
+
+ @retval EFI_SUCCESS Request and Response queues are successfully flushed.
+ @retval EFI_INVALID_PARAMETER This is NULL.
+ @retval EFI_NOT_STARTED This instance hasn't been configured.
+ @retval EFI_NOT_FOUND The asynchronous request or response token is not
+ found.
+ @retval EFI_UNSUPPORTED The implementation does not support this function.
+
+**/
+EFI_STATUS
+EFIAPI
+EfiHttpCancel (
+ IN EFI_HTTP_PROTOCOL *This,
+ IN EFI_HTTP_TOKEN *Token
+ )
+{
+ HTTP_PROTOCOL *HttpInstance;
+
+ if (This == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ HttpInstance = HTTP_INSTANCE_FROM_PROTOCOL (This);
+ ASSERT (HttpInstance != NULL);
+
+ if (HttpInstance->State != HTTP_STATE_TCP_CONNECTED) {
+ return EFI_NOT_STARTED;
+ }
+
+ return HttpCancel (HttpInstance, Token);
+
+}
+
+/**
+ A callback function to intercept events during message parser.
+
+ This function will be invoked during HttpParseMessageBody() with various events type. An error
+ return status of the callback function will cause the HttpParseMessageBody() aborted.
+
+ @param[in] EventType Event type of this callback call.
+ @param[in] Data A pointer to data buffer.
+ @param[in] Length Length in bytes of the Data.
+ @param[in] Context Callback context set by HttpInitMsgParser().
+
+ @retval EFI_SUCCESS Continue to parser the message body.
+
+**/
+EFI_STATUS
+EFIAPI
+HttpBodyParserCallback (
+ IN HTTP_BODY_PARSE_EVENT EventType,
+ IN CHAR8 *Data,
+ IN UINTN Length,
+ IN VOID *Context
+ )
+{
+ HTTP_TOKEN_WRAP *Wrap;
+ UINTN BodyLength;
+ CHAR8 *Body;
+
+ if (EventType != BodyParseEventOnComplete) {
+ return EFI_SUCCESS;
+ }
+
+ if (Data == NULL || Length != 0 || Context == NULL) {
+ return EFI_SUCCESS;
+ }
+
+ Wrap = (HTTP_TOKEN_WRAP *) Context;
+ Body = Wrap->HttpToken->Message->Body;
+ BodyLength = Wrap->HttpToken->Message->BodyLength;
+ if (Data < Body + BodyLength) {
+ Wrap->HttpInstance->NextMsg = Data;
+ } else {
+ Wrap->HttpInstance->NextMsg = NULL;
+ }
+
+
+ //
+ // Free Tx4Token or Tx6Token since already received corrsponding HTTP response.
+ //
+ FreePool (Wrap);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ The work function of EfiHttpResponse().
+
+ @param[in] Wrap Pointer to HTTP token's wrap data.
+
+ @retval EFI_SUCCESS Allocation succeeded.
+ @retval EFI_OUT_OF_RESOURCES Failed to complete the opration due to lack of resources.
+ @retval EFI_NOT_READY Can't find a corresponding Tx4Token/Tx6Token or
+ the EFI_HTTP_UTILITIES_PROTOCOL is not available.
+
+**/
+EFI_STATUS
+HttpResponseWorker (
+ IN HTTP_TOKEN_WRAP *Wrap
+ )
+{
+ EFI_STATUS Status;
+ EFI_HTTP_MESSAGE *HttpMsg;
+ CHAR8 *EndofHeader;
+ CHAR8 *HttpHeaders;
+ UINTN SizeofHeaders;
+ UINTN BufferSize;
+ UINTN StatusCode;
+ CHAR8 *Tmp;
+ CHAR8 *HeaderTmp;
+ CHAR8 *StatusCodeStr;
+ UINTN BodyLen;
+ HTTP_PROTOCOL *HttpInstance;
+ EFI_HTTP_TOKEN *Token;
+ NET_MAP_ITEM *Item;
+ HTTP_TOKEN_WRAP *ValueInItem;
+ UINTN HdrLen;
+ NET_FRAGMENT Fragment;
+
+ if (Wrap == NULL || Wrap->HttpInstance == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ HttpInstance = Wrap->HttpInstance;
+ Token = Wrap->HttpToken;
+ HttpMsg = Token->Message;
+
+ HttpInstance->EndofHeader = NULL;
+ HttpInstance->HttpHeaders = NULL;
+ HttpMsg->Headers = NULL;
+ HttpHeaders = NULL;
+ SizeofHeaders = 0;
+ BufferSize = 0;
+ EndofHeader = NULL;
+ ValueInItem = NULL;
+ Fragment.Len = 0;
+ Fragment.Bulk = NULL;
+
+ if (HttpMsg->Data.Response != NULL) {
+ //
+ // Check whether we have cached header from previous call.
+ //
+ if ((HttpInstance->CacheBody != NULL) && (HttpInstance->NextMsg != NULL)) {
+ //
+ // The data is stored at [NextMsg, CacheBody + CacheLen].
+ //
+ HdrLen = HttpInstance->CacheBody + HttpInstance->CacheLen - HttpInstance->NextMsg;
+ HttpHeaders = AllocateZeroPool (HdrLen);
+ if (HttpHeaders == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Error;
+ }
+
+ CopyMem (HttpHeaders, HttpInstance->NextMsg, HdrLen);
+ FreePool (HttpInstance->CacheBody);
+ HttpInstance->CacheBody = NULL;
+ HttpInstance->NextMsg = NULL;
+ HttpInstance->CacheOffset = 0;
+ SizeofHeaders = HdrLen;
+ BufferSize = HttpInstance->CacheLen;
+
+ //
+ // Check whether we cached the whole HTTP headers.
+ //
+ EndofHeader = AsciiStrStr (HttpHeaders, HTTP_END_OF_HDR_STR);
+ }
+
+ HttpInstance->EndofHeader = &EndofHeader;
+ HttpInstance->HttpHeaders = &HttpHeaders;
+
+
+ if (HttpInstance->TimeoutEvent == NULL) {
+ //
+ // Create TimeoutEvent for response
+ //
+ Status = gBS->CreateEvent (
+ EVT_TIMER,
+ TPL_CALLBACK,
+ NULL,
+ NULL,
+ &HttpInstance->TimeoutEvent
+ );
+ if (EFI_ERROR (Status)) {
+ goto Error;
+ }
+ }
+
+ //
+ // Start the timer, and wait Timeout seconds to receive the header packet.
+ //
+ Status = gBS->SetTimer (HttpInstance->TimeoutEvent, TimerRelative, HTTP_RESPONSE_TIMEOUT * TICKS_PER_SECOND);
+ if (EFI_ERROR (Status)) {
+ goto Error;
+ }
+
+ Status = HttpTcpReceiveHeader (HttpInstance, &SizeofHeaders, &BufferSize, HttpInstance->TimeoutEvent);
+
+ gBS->SetTimer (HttpInstance->TimeoutEvent, TimerCancel, 0);
+
+ if (EFI_ERROR (Status)) {
+ goto Error;
+ }
+
+ ASSERT (HttpHeaders != NULL);
+
+ //
+ // Cache the part of body.
+ //
+ BodyLen = BufferSize - (EndofHeader - HttpHeaders);
+ if (BodyLen > 0) {
+ if (HttpInstance->CacheBody != NULL) {
+ FreePool (HttpInstance->CacheBody);
+ }
+
+ HttpInstance->CacheBody = AllocateZeroPool (BodyLen);
+ if (HttpInstance->CacheBody == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Error;
+ }
+
+ CopyMem (HttpInstance->CacheBody, EndofHeader, BodyLen);
+ HttpInstance->CacheLen = BodyLen;
+ }
+
+ //
+ // Search for Status Code.
+ //
+ StatusCodeStr = HttpHeaders + AsciiStrLen (HTTP_VERSION_STR) + 1;
+ if (StatusCodeStr == NULL) {
+ Status = EFI_NOT_READY;
+ goto Error;
+ }
+
+ StatusCode = AsciiStrDecimalToUintn (StatusCodeStr);
+
+ //
+ // Remove the first line of HTTP message, e.g. "HTTP/1.1 200 OK\r\n".
+ //
+ Tmp = AsciiStrStr (HttpHeaders, HTTP_CRLF_STR);
+ if (Tmp == NULL) {
+ Status = EFI_NOT_READY;
+ goto Error;
+ }
+
+ //
+ // We could have response with just a HTTP message and no headers. For Example,
+ // "100 Continue". In such cases, we would not want to unnecessarily call a Parse
+ // method. A "\r\n" following Tmp string again would indicate an end. Compare and
+ // set SizeofHeaders to 0.
+ //
+ Tmp = Tmp + AsciiStrLen (HTTP_CRLF_STR);
+ if (CompareMem (Tmp, HTTP_CRLF_STR, AsciiStrLen (HTTP_CRLF_STR)) == 0) {
+ SizeofHeaders = 0;
+ } else {
+ SizeofHeaders = SizeofHeaders - (Tmp - HttpHeaders);
+ }
+
+ HttpMsg->Data.Response->StatusCode = HttpMappingToStatusCode (StatusCode);
+ HttpInstance->StatusCode = StatusCode;
+
+ Status = EFI_NOT_READY;
+ ValueInItem = NULL;
+
+ //
+ // In cases of PUT/POST, after an initial request-response pair, we would do a
+ // continuous request without a response call. So, we would not do an insert of
+ // TxToken. After we have sent the complete file, we will call a response to get
+ // a final response from server. In such a case, we would not have any TxTokens.
+ // Hence, check that case before doing a NetMapRemoveHead.
+ //
+ if (!NetMapIsEmpty (&HttpInstance->TxTokens)) {
+ NetMapRemoveHead (&HttpInstance->TxTokens, (VOID**) &ValueInItem);
+ if (ValueInItem == NULL) {
+ goto Error;
+ }
+
+ //
+ // The first Tx Token not transmitted yet, insert back and return error.
+ //
+ if (!ValueInItem->TcpWrap.IsTxDone) {
+ goto Error2;
+ }
+ }
+
+ if (SizeofHeaders != 0) {
+ HeaderTmp = AllocateZeroPool (SizeofHeaders);
+ if (HeaderTmp == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Error2;
+ }
+
+ CopyMem (HeaderTmp, Tmp, SizeofHeaders);
+ FreePool (HttpHeaders);
+ HttpHeaders = HeaderTmp;
+
+ //
+ // Check whether the EFI_HTTP_UTILITIES_PROTOCOL is available.
+ //
+ if (mHttpUtilities == NULL) {
+ Status = EFI_NOT_READY;
+ goto Error2;
+ }
+
+ //
+ // Parse the HTTP header into array of key/value pairs.
+ //
+ Status = mHttpUtilities->Parse (
+ mHttpUtilities,
+ HttpHeaders,
+ SizeofHeaders,
+ &HttpMsg->Headers,
+ &HttpMsg->HeaderCount
+ );
+ if (EFI_ERROR (Status)) {
+ goto Error2;
+ }
+
+ FreePool (HttpHeaders);
+ HttpHeaders = NULL;
+
+
+ //
+ // Init message-body parser by header information.
+ //
+ Status = HttpInitMsgParser (
+ HttpInstance->Method,
+ HttpMsg->Data.Response->StatusCode,
+ HttpMsg->HeaderCount,
+ HttpMsg->Headers,
+ HttpBodyParserCallback,
+ (VOID *) ValueInItem,
+ &HttpInstance->MsgParser
+ );
+ if (EFI_ERROR (Status)) {
+ goto Error2;
+ }
+
+ //
+ // Check whether we received a complete HTTP message.
+ //
+ if (HttpInstance->CacheBody != NULL) {
+ Status = HttpParseMessageBody (HttpInstance->MsgParser, HttpInstance->CacheLen, HttpInstance->CacheBody);
+ if (EFI_ERROR (Status)) {
+ goto Error2;
+ }
+
+ if (HttpIsMessageComplete (HttpInstance->MsgParser)) {
+ //
+ // Free the MsgParse since we already have a full HTTP message.
+ //
+ HttpFreeMsgParser (HttpInstance->MsgParser);
+ HttpInstance->MsgParser = NULL;
+ }
+ }
+ }
+
+ if ((HttpMsg->Body == NULL) || (HttpMsg->BodyLength == 0)) {
+ Status = EFI_SUCCESS;
+ goto Exit;
+ }
+ }
+
+ //
+ // Receive the response body.
+ //
+ BodyLen = 0;
+
+ //
+ // First check whether we cached some data.
+ //
+ if (HttpInstance->CacheBody != NULL) {
+ //
+ // Calculate the length of the cached data.
+ //
+ if (HttpInstance->NextMsg != NULL) {
+ //
+ // We have a cached HTTP message which includes a part of HTTP header of next message.
+ //
+ BodyLen = HttpInstance->NextMsg - (HttpInstance->CacheBody + HttpInstance->CacheOffset);
+ } else {
+ BodyLen = HttpInstance->CacheLen - HttpInstance->CacheOffset;
+ }
+
+ if (BodyLen > 0) {
+ //
+ // We have some cached data. Just copy the data and return.
+ //
+ if (HttpMsg->BodyLength < BodyLen) {
+ CopyMem (HttpMsg->Body, HttpInstance->CacheBody + HttpInstance->CacheOffset, HttpMsg->BodyLength);
+ HttpInstance->CacheOffset = HttpInstance->CacheOffset + HttpMsg->BodyLength;
+ } else {
+ //
+ // Copy all cached data out.
+ //
+ CopyMem (HttpMsg->Body, HttpInstance->CacheBody + HttpInstance->CacheOffset, BodyLen);
+ HttpInstance->CacheOffset = BodyLen + HttpInstance->CacheOffset;
+ HttpMsg->BodyLength = BodyLen;
+
+ if (HttpInstance->NextMsg == NULL) {
+ //
+ // There is no HTTP header of next message. Just free the cache buffer.
+ //
+ FreePool (HttpInstance->CacheBody);
+ HttpInstance->CacheBody = NULL;
+ HttpInstance->NextMsg = NULL;
+ HttpInstance->CacheOffset = 0;
+ }
+ }
+ //
+ // Return since we aready received required data.
+ //
+ Status = EFI_SUCCESS;
+ goto Exit;
+ }
+
+ if (BodyLen == 0 && HttpInstance->MsgParser == NULL) {
+ //
+ // We received a complete HTTP message, and we don't have more data to return to caller.
+ //
+ HttpMsg->BodyLength = 0;
+ Status = EFI_SUCCESS;
+ goto Exit;
+ }
+ }
+
+ ASSERT (HttpInstance->MsgParser != NULL);
+
+ //
+ // We still need receive more data when there is no cache data and MsgParser is not NULL;
+ //
+ if (!HttpInstance->UseHttps) {
+ Status = HttpTcpReceiveBody (Wrap, HttpMsg);
+
+ if (EFI_ERROR (Status)) {
+ goto Error2;
+ }
+
+ } else {
+ if (HttpInstance->TimeoutEvent == NULL) {
+ //
+ // Create TimeoutEvent for response
+ //
+ Status = gBS->CreateEvent (
+ EVT_TIMER,
+ TPL_CALLBACK,
+ NULL,
+ NULL,
+ &HttpInstance->TimeoutEvent
+ );
+ if (EFI_ERROR (Status)) {
+ goto Error2;
+ }
+ }
+
+ //
+ // Start the timer, and wait Timeout seconds to receive the body packet.
+ //
+ Status = gBS->SetTimer (HttpInstance->TimeoutEvent, TimerRelative, HTTP_RESPONSE_TIMEOUT * TICKS_PER_SECOND);
+ if (EFI_ERROR (Status)) {
+ goto Error2;
+ }
+
+ Status = HttpsReceive (HttpInstance, &Fragment, HttpInstance->TimeoutEvent);
+
+ gBS->SetTimer (HttpInstance->TimeoutEvent, TimerCancel, 0);
+
+ if (EFI_ERROR (Status)) {
+ goto Error2;
+ }
+
+ //
+ // Check whether we receive a complete HTTP message.
+ //
+ Status = HttpParseMessageBody (
+ HttpInstance->MsgParser,
+ (UINTN) Fragment.Len,
+ (CHAR8 *) Fragment.Bulk
+ );
+ if (EFI_ERROR (Status)) {
+ goto Error2;
+ }
+
+ if (HttpIsMessageComplete (HttpInstance->MsgParser)) {
+ //
+ // Free the MsgParse since we already have a full HTTP message.
+ //
+ HttpFreeMsgParser (HttpInstance->MsgParser);
+ HttpInstance->MsgParser = NULL;
+ }
+
+ //
+ // We receive part of header of next HTTP msg.
+ //
+ if (HttpInstance->NextMsg != NULL) {
+ HttpMsg->BodyLength = MIN ((UINTN) HttpInstance->NextMsg - (UINTN) Fragment.Bulk, HttpMsg->BodyLength);
+ CopyMem (HttpMsg->Body, Fragment.Bulk, HttpMsg->BodyLength);
+
+ HttpInstance->CacheLen = Fragment.Len - HttpMsg->BodyLength;
+ if (HttpInstance->CacheLen != 0) {
+ if (HttpInstance->CacheBody != NULL) {
+ FreePool (HttpInstance->CacheBody);
+ }
+
+ HttpInstance->CacheBody = AllocateZeroPool (HttpInstance->CacheLen);
+ if (HttpInstance->CacheBody == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Error2;
+ }
+
+ CopyMem (HttpInstance->CacheBody, Fragment.Bulk + HttpMsg->BodyLength, HttpInstance->CacheLen);
+ HttpInstance->CacheOffset = 0;
+
+ HttpInstance->NextMsg = HttpInstance->CacheBody + ((UINTN) HttpInstance->NextMsg - (UINTN) (Fragment.Bulk + HttpMsg->BodyLength));
+ }
+ } else {
+ HttpMsg->BodyLength = MIN (Fragment.Len, (UINT32) HttpMsg->BodyLength);
+ CopyMem (HttpMsg->Body, Fragment.Bulk, HttpMsg->BodyLength);
+ HttpInstance->CacheLen = Fragment.Len - HttpMsg->BodyLength;
+ if (HttpInstance->CacheLen != 0) {
+ if (HttpInstance->CacheBody != NULL) {
+ FreePool (HttpInstance->CacheBody);
+ }
+
+ HttpInstance->CacheBody = AllocateZeroPool (HttpInstance->CacheLen);
+ if (HttpInstance->CacheBody == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Error2;
+ }
+
+ CopyMem (HttpInstance->CacheBody, Fragment.Bulk + HttpMsg->BodyLength, HttpInstance->CacheLen);
+ HttpInstance->CacheOffset = 0;
+ }
+ }
+
+ if (Fragment.Bulk != NULL) {
+ FreePool (Fragment.Bulk);
+ Fragment.Bulk = NULL;
+ }
+
+ goto Exit;
+ }
+
+ return Status;
+
+Exit:
+ Item = NetMapFindKey (&Wrap->HttpInstance->RxTokens, Wrap->HttpToken);
+ if (Item != NULL) {
+ NetMapRemoveItem (&Wrap->HttpInstance->RxTokens, Item, NULL);
+ }
+
+ if (HttpInstance->StatusCode >= HTTP_ERROR_OR_NOT_SUPPORT_STATUS_CODE) {
+ Token->Status = EFI_HTTP_ERROR;
+ } else {
+ Token->Status = Status;
+ }
+
+ gBS->SignalEvent (Token->Event);
+ HttpCloseTcpRxEvent (Wrap);
+ FreePool (Wrap);
+ return Status;
+
+Error2:
+ if (ValueInItem != NULL) {
+ NetMapInsertHead (&HttpInstance->TxTokens, ValueInItem->HttpToken, ValueInItem);
+ }
+
+Error:
+ Item = NetMapFindKey (&Wrap->HttpInstance->RxTokens, Wrap->HttpToken);
+ if (Item != NULL) {
+ NetMapRemoveItem (&Wrap->HttpInstance->RxTokens, Item, NULL);
+ }
+
+ if (!HttpInstance->UseHttps) {
+ HttpTcpTokenCleanup (Wrap);
+ } else {
+ FreePool (Wrap);
+ }
+
+ if (HttpHeaders != NULL) {
+ FreePool (HttpHeaders);
+ HttpHeaders = NULL;
+ }
+
+ if (Fragment.Bulk != NULL) {
+ FreePool (Fragment.Bulk);
+ Fragment.Bulk = NULL;
+ }
+
+ if (HttpMsg->Headers != NULL) {
+ FreePool (HttpMsg->Headers);
+ HttpMsg->Headers = NULL;
+ }
+
+ if (HttpInstance->CacheBody != NULL) {
+ FreePool (HttpInstance->CacheBody);
+ HttpInstance->CacheBody = NULL;
+ }
+
+ if (HttpInstance->StatusCode >= HTTP_ERROR_OR_NOT_SUPPORT_STATUS_CODE) {
+ Token->Status = EFI_HTTP_ERROR;
+ } else {
+ Token->Status = Status;
+ }
+
+ gBS->SignalEvent (Token->Event);
+
+ return Status;
+
+}
+
+
+/**
+ The Response() function queues an HTTP response to this HTTP instance, similar to
+ Receive() function in the EFI TCP driver. When the HTTP response is received successfully,
+ or if there is an error, Status in token will be updated and Event will be signaled.
+
+ The HTTP driver will queue a receive token to the underlying TCP instance. When data
+ is received in the underlying TCP instance, the data will be parsed and Token will
+ be populated with the response data. If the data received from the remote host
+ contains an incomplete or invalid HTTP header, the HTTP driver will continue waiting
+ (asynchronously) for more data to be sent from the remote host before signaling
+ Event in Token.
+
+ It is the responsibility of the caller to allocate a buffer for Body and specify the
+ size in BodyLength. If the remote host provides a response that contains a content
+ body, up to BodyLength bytes will be copied from the receive buffer into Body and
+ BodyLength will be updated with the amount of bytes received and copied to Body. This
+ allows the client to download a large file in chunks instead of into one contiguous
+ block of memory. Similar to HTTP request, if Body is not NULL and BodyLength is
+ non-zero and all other fields are NULL or 0, the HTTP driver will queue a receive
+ token to underlying TCP instance. If data arrives in the receive buffer, up to
+ BodyLength bytes of data will be copied to Body. The HTTP driver will then update
+ BodyLength with the amount of bytes received and copied to Body.
+
+ If the HTTP driver does not have an open underlying TCP connection with the host
+ specified in the response URL, Request() will return EFI_ACCESS_DENIED. This is
+ consistent with RFC 2616 recommendation that HTTP clients should attempt to maintain
+ an open TCP connection between client and host.
+
+ @param[in] This Pointer to EFI_HTTP_PROTOCOL instance.
+ @param[in] Token Pointer to storage containing HTTP response token.
+
+ @retval EFI_SUCCESS Allocation succeeded.
+ @retval EFI_NOT_STARTED This EFI HTTP Protocol instance has not been
+ initialized.
+ @retval EFI_INVALID_PARAMETER One or more of the following conditions is TRUE:
+ This is NULL.
+ Token is NULL.
+ Token->Message->Headers is NULL.
+ Token->Message is NULL.
+ Token->Message->Body is not NULL,
+ Token->Message->BodyLength is non-zero, and
+ Token->Message->Data is NULL, but a previous call to
+ Response() has not been completed successfully.
+ @retval EFI_OUT_OF_RESOURCES Could not allocate enough system resources.
+ @retval EFI_ACCESS_DENIED An open TCP connection is not present with the host
+ specified by response URL.
+**/
+EFI_STATUS
+EFIAPI
+EfiHttpResponse (
+ IN EFI_HTTP_PROTOCOL *This,
+ IN EFI_HTTP_TOKEN *Token
+ )
+{
+ EFI_STATUS Status;
+ EFI_HTTP_MESSAGE *HttpMsg;
+ HTTP_PROTOCOL *HttpInstance;
+ HTTP_TOKEN_WRAP *Wrap;
+
+ if ((This == NULL) || (Token == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ HttpMsg = Token->Message;
+ if (HttpMsg == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ HttpInstance = HTTP_INSTANCE_FROM_PROTOCOL (This);
+ ASSERT (HttpInstance != NULL);
+
+ if (HttpInstance->State != HTTP_STATE_TCP_CONNECTED) {
+ return EFI_NOT_STARTED;
+ }
+
+ //
+ // Check whether the token already existed.
+ //
+ if (EFI_ERROR (NetMapIterate (&HttpInstance->RxTokens, HttpTokenExist, Token))) {
+ return EFI_ACCESS_DENIED;
+ }
+
+ Wrap = AllocateZeroPool (sizeof (HTTP_TOKEN_WRAP));
+ if (Wrap == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ Wrap->HttpInstance = HttpInstance;
+ Wrap->HttpToken = Token;
+
+ //
+ // Notes: For Https, receive token wrapped in HTTP_TOKEN_WRAP is not used to
+ // receive the https response. A special TlsRxToken is used for receiving TLS
+ // related messages. It should be a blocking response.
+ //
+ if (!HttpInstance->UseHttps) {
+ Status = HttpCreateTcpRxEvent (Wrap);
+ if (EFI_ERROR (Status)) {
+ goto Error;
+ }
+ }
+
+ Status = NetMapInsertTail (&HttpInstance->RxTokens, Token, Wrap);
+ if (EFI_ERROR (Status)) {
+ goto Error;
+ }
+
+ //
+ // If already have pending RxTokens, return directly.
+ //
+ if (NetMapGetCount (&HttpInstance->RxTokens) > 1) {
+ return EFI_SUCCESS;
+ }
+
+ return HttpResponseWorker (Wrap);
+
+Error:
+ if (Wrap != NULL) {
+ if (Wrap->TcpWrap.Rx4Token.CompletionToken.Event != NULL) {
+ gBS->CloseEvent (Wrap->TcpWrap.Rx4Token.CompletionToken.Event);
+ }
+
+ if (Wrap->TcpWrap.Rx6Token.CompletionToken.Event != NULL) {
+ gBS->CloseEvent (Wrap->TcpWrap.Rx6Token.CompletionToken.Event);
+ }
+ FreePool (Wrap);
+ }
+
+ return Status;
+}
+
+/**
+ The Poll() function can be used by network drivers and applications to increase the
+ rate that data packets are moved between the communication devices and the transmit
+ and receive queues.
+
+ In some systems, the periodic timer event in the managed network driver may not poll
+ the underlying communications device fast enough to transmit and/or receive all data
+ packets without missing incoming packets or dropping outgoing packets. Drivers and
+ applications that are experiencing packet loss should try calling the Poll() function
+ more often.
+
+ @param[in] This Pointer to EFI_HTTP_PROTOCOL instance.
+
+ @retval EFI_SUCCESS Incoming or outgoing data was processed.
+ @retval EFI_DEVICE_ERROR An unexpected system or network error occurred.
+ @retval EFI_INVALID_PARAMETER This is NULL.
+ @retval EFI_NOT_READY No incoming or outgoing data is processed.
+ @retval EFI_NOT_STARTED This EFI HTTP Protocol instance has not been started.
+
+**/
+EFI_STATUS
+EFIAPI
+EfiHttpPoll (
+ IN EFI_HTTP_PROTOCOL *This
+ )
+{
+ EFI_STATUS Status;
+ HTTP_PROTOCOL *HttpInstance;
+
+ if (This == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ HttpInstance = HTTP_INSTANCE_FROM_PROTOCOL (This);
+ ASSERT (HttpInstance != NULL);
+
+ if (HttpInstance->State != HTTP_STATE_TCP_CONNECTED) {
+ return EFI_NOT_STARTED;
+ }
+
+ if (HttpInstance->LocalAddressIsIPv6) {
+ if (HttpInstance->Tcp6 == NULL) {
+ return EFI_NOT_STARTED;
+ }
+ Status = HttpInstance->Tcp6->Poll (HttpInstance->Tcp6);
+ } else {
+ if (HttpInstance->Tcp4 == NULL) {
+ return EFI_NOT_STARTED;
+ }
+ Status = HttpInstance->Tcp4->Poll (HttpInstance->Tcp4);
+ }
+
+ DispatchDpc ();
+
+ return Status;
+}
diff --git a/Core/NetworkPkg/HttpDxe/HttpImpl.h b/Core/NetworkPkg/HttpDxe/HttpImpl.h
new file mode 100644
index 0000000000..40b25048bc
--- /dev/null
+++ b/Core/NetworkPkg/HttpDxe/HttpImpl.h
@@ -0,0 +1,237 @@
+/** @file
+ The header files of implementation of EFI_HTTP_PROTOCOL protocol interfaces.
+
+ Copyright (c) 2015 - 2016, Intel Corporation. All rights reserved.<BR>
+ (C) Copyright 2016 Hewlett Packard Enterprise Development LP<BR>
+
+ This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php.
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef __EFI_HTTP_IMPL_H__
+#define __EFI_HTTP_IMPL_H__
+
+#define HTTP_DEFAULT_PORT 80
+#define HTTP_END_OF_HDR_STR "\r\n\r\n"
+#define HTTP_CRLF_STR "\r\n"
+#define HTTP_VERSION_STR HTTP_VERSION
+#define HTTP_VERSION_CRLF_STR " HTTP/1.1\r\n"
+#define HTTP_ERROR_OR_NOT_SUPPORT_STATUS_CODE 300
+
+
+/**
+ Returns the operational parameters for the current HTTP child instance.
+
+ The GetModeData() function is used to read the current mode data (operational
+ parameters) for this HTTP protocol instance.
+
+ @param[in] This Pointer to EFI_HTTP_PROTOCOL instance.
+ @param[out] HttpConfigData Point to buffer for operational parameters of this
+ HTTP instance.
+
+ @retval EFI_SUCCESS Operation succeeded.
+ @retval EFI_INVALID_PARAMETER One or more of the following conditions is TRUE:
+ This is NULL.
+ HttpConfigData is NULL.
+ HttpInstance->LocalAddressIsIPv6 is FALSE and
+ HttpConfigData->IPv4Node is NULL.
+ HttpInstance->LocalAddressIsIPv6 is TRUE and
+ HttpConfigData->IPv6Node is NULL.
+ @retval EFI_NOT_STARTED This EFI HTTP Protocol instance has not been started.
+
+**/
+EFI_STATUS
+EFIAPI
+EfiHttpGetModeData (
+ IN EFI_HTTP_PROTOCOL *This,
+ OUT EFI_HTTP_CONFIG_DATA *HttpConfigData
+ );
+
+/**
+ Initialize or brutally reset the operational parameters for this EFI HTTP instance.
+
+ The Configure() function does the following:
+ When HttpConfigData is not NULL Initialize this EFI HTTP instance by configuring
+ timeout, local address, port, etc.
+ When HttpConfigData is NULL, reset this EFI HTTP instance by closing all active
+ connections with remote hosts, canceling all asynchronous tokens, and flush request
+ and response buffers without informing the appropriate hosts.
+
+ No other EFI HTTP function can be executed by this instance until the Configure()
+ function is executed and returns successfully.
+
+ @param[in] This Pointer to EFI_HTTP_PROTOCOL instance.
+ @param[in] HttpConfigData Pointer to the configure data to configure the instance.
+
+ @retval EFI_SUCCESS Operation succeeded.
+ @retval EFI_INVALID_PARAMETER One or more of the following conditions is TRUE:
+ This is NULL.
+ HttpConfigData->LocalAddressIsIPv6 is FALSE and
+ HttpConfigData->IPv4Node is NULL.
+ HttpConfigData->LocalAddressIsIPv6 is TRUE and
+ HttpConfigData->IPv6Node is NULL.
+ @retval EFI_ALREADY_STARTED Reinitialize this HTTP instance without calling
+ Configure() with NULL to reset it.
+ @retval EFI_DEVICE_ERROR An unexpected system or network error occurred.
+ @retval EFI_OUT_OF_RESOURCES Could not allocate enough system resources when
+ executing Configure().
+ @retval EFI_UNSUPPORTED One or more options in ConfigData are not supported
+ in the implementation.
+**/
+EFI_STATUS
+EFIAPI
+EfiHttpConfigure (
+ IN EFI_HTTP_PROTOCOL *This,
+ IN EFI_HTTP_CONFIG_DATA *HttpConfigData
+ );
+
+/**
+ The Request() function queues an HTTP request to this HTTP instance.
+
+ Similar to Transmit() function in the EFI TCP driver. When the HTTP request is sent
+ successfully, or if there is an error, Status in token will be updated and Event will
+ be signaled.
+
+ @param[in] This Pointer to EFI_HTTP_PROTOCOL instance.
+ @param[in] Token Pointer to storage containing HTTP request token.
+
+ @retval EFI_SUCCESS Outgoing data was processed.
+ @retval EFI_NOT_STARTED This EFI HTTP Protocol instance has not been started.
+ @retval EFI_DEVICE_ERROR An unexpected system or network error occurred.
+ @retval EFI_TIMEOUT Data was dropped out of the transmit or receive queue.
+ @retval EFI_OUT_OF_RESOURCES Could not allocate enough system resources.
+ @retval EFI_UNSUPPORTED The HTTP method is not supported in current
+ implementation.
+ @retval EFI_INVALID_PARAMETER One or more of the following conditions is TRUE:
+ This is NULL.
+ Token is NULL.
+ Token->Message is NULL.
+ Token->Message->Body is not NULL,
+ Token->Message->BodyLength is non-zero, and
+ Token->Message->Data is NULL, but a previous call to
+ Request()has not been completed successfully.
+**/
+EFI_STATUS
+EFIAPI
+EfiHttpRequest (
+ IN EFI_HTTP_PROTOCOL *This,
+ IN EFI_HTTP_TOKEN *Token
+ );
+
+/**
+ Abort an asynchronous HTTP request or response token.
+
+ The Cancel() function aborts a pending HTTP request or response transaction. If
+ Token is not NULL and the token is in transmit or receive queues when it is being
+ cancelled, its Token->Status will be set to EFI_ABORTED and then Token->Event will
+ be signaled. If the token is not in one of the queues, which usually means that the
+ asynchronous operation has completed, EFI_NOT_FOUND is returned. If Token is NULL,
+ all asynchronous tokens issued by Request() or Response() will be aborted.
+
+ @param[in] This Pointer to EFI_HTTP_PROTOCOL instance.
+ @param[in] Token Point to storage containing HTTP request or response
+ token.
+
+ @retval EFI_SUCCESS Request and Response queues are successfully flushed.
+ @retval EFI_INVALID_PARAMETER This is NULL.
+ @retval EFI_NOT_STARTED This instance hasn't been configured.
+ @retval EFI_NOT_FOUND The asynchronous request or response token is not
+ found.
+ @retval EFI_UNSUPPORTED The implementation does not support this function.
+**/
+EFI_STATUS
+EFIAPI
+EfiHttpCancel (
+ IN EFI_HTTP_PROTOCOL *This,
+ IN EFI_HTTP_TOKEN *Token
+ );
+
+/**
+ The Response() function queues an HTTP response to this HTTP instance, similar to
+ Receive() function in the EFI TCP driver. When the HTTP response is received successfully,
+ or if there is an error, Status in token will be updated and Event will be signaled.
+
+ The HTTP driver will queue a receive token to the underlying TCP instance. When data
+ is received in the underlying TCP instance, the data will be parsed and Token will
+ be populated with the response data. If the data received from the remote host
+ contains an incomplete or invalid HTTP header, the HTTP driver will continue waiting
+ (asynchronously) for more data to be sent from the remote host before signaling
+ Event in Token.
+
+ It is the responsibility of the caller to allocate a buffer for Body and specify the
+ size in BodyLength. If the remote host provides a response that contains a content
+ body, up to BodyLength bytes will be copied from the receive buffer into Body and
+ BodyLength will be updated with the amount of bytes received and copied to Body. This
+ allows the client to download a large file in chunks instead of into one contiguous
+ block of memory. Similar to HTTP request, if Body is not NULL and BodyLength is
+ non-zero and all other fields are NULL or 0, the HTTP driver will queue a receive
+ token to underlying TCP instance. If data arrives in the receive buffer, up to
+ BodyLength bytes of data will be copied to Body. The HTTP driver will then update
+ BodyLength with the amount of bytes received and copied to Body.
+
+ If the HTTP driver does not have an open underlying TCP connection with the host
+ specified in the response URL, Request() will return EFI_ACCESS_DENIED. This is
+ consistent with RFC 2616 recommendation that HTTP clients should attempt to maintain
+ an open TCP connection between client and host.
+
+ @param[in] This Pointer to EFI_HTTP_PROTOCOL instance.
+ @param[in] Token Pointer to storage containing HTTP response token.
+
+ @retval EFI_SUCCESS Allocation succeeded.
+ @retval EFI_NOT_STARTED This EFI HTTP Protocol instance has not been
+ initialized.
+ @retval EFI_INVALID_PARAMETER One or more of the following conditions is TRUE:
+ This is NULL.
+ Token is NULL.
+ Token->Message->Headers is NULL.
+ Token->Message is NULL.
+ Token->Message->Body is not NULL,
+ Token->Message->BodyLength is non-zero, and
+ Token->Message->Data is NULL, but a previous call to
+ Response() has not been completed successfully.
+ @retval EFI_OUT_OF_RESOURCES Could not allocate enough system resources.
+ @retval EFI_ACCESS_DENIED An open TCP connection is not present with the host
+ specified by response URL.
+**/
+EFI_STATUS
+EFIAPI
+EfiHttpResponse (
+ IN EFI_HTTP_PROTOCOL *This,
+ IN EFI_HTTP_TOKEN *Token
+ );
+
+/**
+ The Poll() function can be used by network drivers and applications to increase the
+ rate that data packets are moved between the communication devices and the transmit
+ and receive queues.
+
+ In some systems, the periodic timer event in the managed network driver may not poll
+ the underlying communications device fast enough to transmit and/or receive all data
+ packets without missing incoming packets or dropping outgoing packets. Drivers and
+ applications that are experiencing packet loss should try calling the Poll() function
+ more often.
+
+ @param[in] This Pointer to EFI_HTTP_PROTOCOL instance.
+
+ @retval EFI_SUCCESS Incoming or outgoing data was processed.
+ @retval EFI_DEVICE_ERROR An unexpected system or network error occurred.
+ @retval EFI_INVALID_PARAMETER This is NULL.
+ @retval EFI_NOT_READY No incoming or outgoing data is processed.
+ @retval EFI_NOT_STARTED This EFI HTTP Protocol instance has not been started.
+
+**/
+EFI_STATUS
+EFIAPI
+EfiHttpPoll (
+ IN EFI_HTTP_PROTOCOL *This
+ );
+
+extern EFI_HTTP_PROTOCOL mEfiHttpTemplate;
+
+#endif
diff --git a/Core/NetworkPkg/HttpDxe/HttpProto.c b/Core/NetworkPkg/HttpDxe/HttpProto.c
new file mode 100644
index 0000000000..3d61ba2ae1
--- /dev/null
+++ b/Core/NetworkPkg/HttpDxe/HttpProto.c
@@ -0,0 +1,2128 @@
+/** @file
+ Miscellaneous routines for HttpDxe driver.
+
+Copyright (c) 2015 - 2017, Intel Corporation. All rights reserved.<BR>
+(C) Copyright 2016 Hewlett Packard Enterprise Development LP<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "HttpDriver.h"
+
+/**
+ The common notify function used in HTTP driver.
+
+ @param[in] Event The event signaled.
+ @param[in] Context The context.
+
+**/
+VOID
+EFIAPI
+HttpCommonNotify (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ if ((Event == NULL) || (Context == NULL)) {
+ return ;
+ }
+
+ *((BOOLEAN *) Context) = TRUE;
+}
+
+/**
+ The notify function associated with Tx4Token for Tcp4->Transmit() or Tx6Token for Tcp6->Transmit().
+
+ @param[in] Context The context.
+
+**/
+VOID
+EFIAPI
+HttpTcpTransmitNotifyDpc (
+ IN VOID *Context
+ )
+{
+ HTTP_TOKEN_WRAP *Wrap;
+ HTTP_PROTOCOL *HttpInstance;
+
+ if (Context == NULL) {
+ return ;
+ }
+
+ Wrap = (HTTP_TOKEN_WRAP *) Context;
+ HttpInstance = Wrap->HttpInstance;
+
+ if (!HttpInstance->LocalAddressIsIPv6) {
+ Wrap->HttpToken->Status = Wrap->TcpWrap.Tx4Token.CompletionToken.Status;
+ gBS->SignalEvent (Wrap->HttpToken->Event);
+
+ //
+ // Free resources.
+ //
+ if (Wrap->TcpWrap.Tx4Token.Packet.TxData->FragmentTable[0].FragmentBuffer != NULL) {
+ FreePool (Wrap->TcpWrap.Tx4Token.Packet.TxData->FragmentTable[0].FragmentBuffer);
+ }
+
+ if (Wrap->TcpWrap.Tx4Token.CompletionToken.Event != NULL) {
+ gBS->CloseEvent (Wrap->TcpWrap.Tx4Token.CompletionToken.Event);
+ }
+
+ } else {
+ Wrap->HttpToken->Status = Wrap->TcpWrap.Tx6Token.CompletionToken.Status;
+ gBS->SignalEvent (Wrap->HttpToken->Event);
+
+ //
+ // Free resources.
+ //
+ if (Wrap->TcpWrap.Tx6Token.Packet.TxData->FragmentTable[0].FragmentBuffer != NULL) {
+ FreePool (Wrap->TcpWrap.Tx6Token.Packet.TxData->FragmentTable[0].FragmentBuffer);
+ }
+
+ if (Wrap->TcpWrap.Tx6Token.CompletionToken.Event != NULL) {
+ gBS->CloseEvent (Wrap->TcpWrap.Tx6Token.CompletionToken.Event);
+ }
+ }
+
+
+ Wrap->TcpWrap.IsTxDone = TRUE;
+
+ //
+ // Check pending TxTokens and sent out.
+ //
+ NetMapIterate (&Wrap->HttpInstance->TxTokens, HttpTcpTransmit, NULL);
+
+}
+
+/**
+ Request HttpTcpTransmitNotifyDpc as a DPC at TPL_CALLBACK.
+
+ @param Event The receive event delivered to TCP for transmit.
+ @param Context Context for the callback.
+
+**/
+VOID
+EFIAPI
+HttpTcpTransmitNotify (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ //
+ // Request HttpTcpTransmitNotifyDpc as a DPC at TPL_CALLBACK
+ //
+ QueueDpc (TPL_CALLBACK, HttpTcpTransmitNotifyDpc, Context);
+}
+
+/**
+ The notify function associated with Rx4Token for Tcp4->Receive () or Rx6Token for Tcp6->Receive().
+
+ @param[in] Context The context.
+
+**/
+VOID
+EFIAPI
+HttpTcpReceiveNotifyDpc (
+ IN VOID *Context
+ )
+{
+ HTTP_TOKEN_WRAP *Wrap;
+ NET_MAP_ITEM *Item;
+ UINTN Length;
+ EFI_STATUS Status;
+ HTTP_PROTOCOL *HttpInstance;
+ BOOLEAN UsingIpv6;
+
+ if (Context == NULL) {
+ return ;
+ }
+
+ Wrap = (HTTP_TOKEN_WRAP *) Context;
+ HttpInstance = Wrap->HttpInstance;
+ UsingIpv6 = HttpInstance->LocalAddressIsIPv6;
+
+ if (UsingIpv6) {
+ gBS->CloseEvent (Wrap->TcpWrap.Rx6Token.CompletionToken.Event);
+ Wrap->TcpWrap.Rx6Token.CompletionToken.Event = NULL;
+
+ if (EFI_ERROR (Wrap->TcpWrap.Rx6Token.CompletionToken.Status)) {
+ DEBUG ((EFI_D_ERROR, "HttpTcpReceiveNotifyDpc: %r!\n", Wrap->TcpWrap.Rx6Token.CompletionToken.Status));
+ Wrap->HttpToken->Status = Wrap->TcpWrap.Rx6Token.CompletionToken.Status;
+ gBS->SignalEvent (Wrap->HttpToken->Event);
+
+ Item = NetMapFindKey (&HttpInstance->RxTokens, Wrap->HttpToken);
+ if (Item != NULL) {
+ NetMapRemoveItem (&HttpInstance->RxTokens, Item, NULL);
+ }
+
+ FreePool (Wrap);
+ Wrap = NULL;
+
+ return ;
+ }
+
+ } else {
+ gBS->CloseEvent (Wrap->TcpWrap.Rx4Token.CompletionToken.Event);
+ Wrap->TcpWrap.Rx4Token.CompletionToken.Event = NULL;
+
+ if (EFI_ERROR (Wrap->TcpWrap.Rx4Token.CompletionToken.Status)) {
+ DEBUG ((EFI_D_ERROR, "HttpTcpReceiveNotifyDpc: %r!\n", Wrap->TcpWrap.Rx4Token.CompletionToken.Status));
+ Wrap->HttpToken->Status = Wrap->TcpWrap.Rx4Token.CompletionToken.Status;
+ gBS->SignalEvent (Wrap->HttpToken->Event);
+
+ Item = NetMapFindKey (&HttpInstance->RxTokens, Wrap->HttpToken);
+ if (Item != NULL) {
+ NetMapRemoveItem (&HttpInstance->RxTokens, Item, NULL);
+ }
+
+ FreePool (Wrap);
+ Wrap = NULL;
+
+ return ;
+ }
+ }
+
+ //
+ // Check whether we receive a complete HTTP message.
+ //
+ ASSERT (HttpInstance->MsgParser != NULL);
+ if (UsingIpv6) {
+ Length = (UINTN) Wrap->TcpWrap.Rx6Data.FragmentTable[0].FragmentLength;
+ } else {
+ Length = (UINTN) Wrap->TcpWrap.Rx4Data.FragmentTable[0].FragmentLength;
+ }
+
+ Status = HttpParseMessageBody (
+ HttpInstance->MsgParser,
+ Length,
+ Wrap->HttpToken->Message->Body
+ );
+ if (EFI_ERROR (Status)) {
+ return ;
+ }
+
+ if (HttpIsMessageComplete (HttpInstance->MsgParser)) {
+ //
+ // Free the MsgParse since we already have a full HTTP message.
+ //
+ HttpFreeMsgParser (HttpInstance->MsgParser);
+ HttpInstance->MsgParser = NULL;
+ }
+
+ Wrap->HttpToken->Message->BodyLength = Length;
+ ASSERT (HttpInstance->CacheBody == NULL);
+ //
+ // We receive part of header of next HTTP msg.
+ //
+ if (HttpInstance->NextMsg != NULL) {
+ Wrap->HttpToken->Message->BodyLength = HttpInstance->NextMsg -
+ (CHAR8 *) Wrap->HttpToken->Message->Body;
+ HttpInstance->CacheLen = Length - Wrap->HttpToken->Message->BodyLength;
+ if (HttpInstance->CacheLen != 0) {
+ HttpInstance->CacheBody = AllocateZeroPool (HttpInstance->CacheLen);
+ if (HttpInstance->CacheBody == NULL) {
+ return ;
+ }
+ CopyMem (HttpInstance->CacheBody, HttpInstance->NextMsg, HttpInstance->CacheLen);
+ HttpInstance->NextMsg = HttpInstance->CacheBody;
+ HttpInstance->CacheOffset = 0;
+ }
+ }
+
+ Item = NetMapFindKey (&Wrap->HttpInstance->RxTokens, Wrap->HttpToken);
+ if (Item != NULL) {
+ NetMapRemoveItem (&Wrap->HttpInstance->RxTokens, Item, NULL);
+ }
+
+
+ Wrap->TcpWrap.IsRxDone = TRUE;
+ if (UsingIpv6) {
+ Wrap->HttpToken->Status = Wrap->TcpWrap.Rx6Token.CompletionToken.Status;
+ } else {
+ Wrap->HttpToken->Status = Wrap->TcpWrap.Rx4Token.CompletionToken.Status;
+ }
+
+
+ gBS->SignalEvent (Wrap->HttpToken->Event);
+
+ //
+ // Check pending RxTokens and receive the HTTP message.
+ //
+ NetMapIterate (&Wrap->HttpInstance->RxTokens, HttpTcpReceive, NULL);
+
+ FreePool (Wrap);
+ Wrap = NULL;
+}
+
+/**
+ Request HttpTcpReceiveNotifyDpc as a DPC at TPL_CALLBACK.
+
+ @param Event The receive event delivered to TCP for receive.
+ @param Context Context for the callback.
+
+**/
+VOID
+EFIAPI
+HttpTcpReceiveNotify (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ //
+ // Request HttpTcpTransmitNotifyDpc as a DPC at TPL_CALLBACK
+ //
+ QueueDpc (TPL_CALLBACK, HttpTcpReceiveNotifyDpc, Context);
+}
+
+/**
+ Create events for the TCP connection token and TCP close token.
+
+ @param[in] HttpInstance Pointer to HTTP_PROTOCOL structure.
+
+ @retval EFI_SUCCESS The events are created successfully.
+ @retval others Other error as indicated.
+
+**/
+EFI_STATUS
+HttpCreateTcpConnCloseEvent (
+ IN HTTP_PROTOCOL *HttpInstance
+ )
+{
+ EFI_STATUS Status;
+
+ if (!HttpInstance->LocalAddressIsIPv6) {
+ //
+ // Create events for variuos asynchronous operations.
+ //
+ Status = gBS->CreateEvent (
+ EVT_NOTIFY_SIGNAL,
+ TPL_NOTIFY,
+ HttpCommonNotify,
+ &HttpInstance->IsTcp4ConnDone,
+ &HttpInstance->Tcp4ConnToken.CompletionToken.Event
+ );
+ if (EFI_ERROR (Status)) {
+ goto ERROR;
+ }
+
+ //
+ // Initialize Tcp4CloseToken
+ //
+ Status = gBS->CreateEvent (
+ EVT_NOTIFY_SIGNAL,
+ TPL_NOTIFY,
+ HttpCommonNotify,
+ &HttpInstance->IsTcp4CloseDone,
+ &HttpInstance->Tcp4CloseToken.CompletionToken.Event
+ );
+ if (EFI_ERROR (Status)) {
+ goto ERROR;
+ }
+
+ } else {
+ //
+ // Create events for variuos asynchronous operations.
+ //
+ Status = gBS->CreateEvent (
+ EVT_NOTIFY_SIGNAL,
+ TPL_NOTIFY,
+ HttpCommonNotify,
+ &HttpInstance->IsTcp6ConnDone,
+ &HttpInstance->Tcp6ConnToken.CompletionToken.Event
+ );
+ if (EFI_ERROR (Status)) {
+ goto ERROR;
+ }
+
+ //
+ // Initialize Tcp6CloseToken
+ //
+ Status = gBS->CreateEvent (
+ EVT_NOTIFY_SIGNAL,
+ TPL_NOTIFY,
+ HttpCommonNotify,
+ &HttpInstance->IsTcp6CloseDone,
+ &HttpInstance->Tcp6CloseToken.CompletionToken.Event
+ );
+ if (EFI_ERROR (Status)) {
+ goto ERROR;
+ }
+ }
+
+ return EFI_SUCCESS;
+
+ERROR:
+ //
+ // Error handling
+ //
+ HttpCloseTcpConnCloseEvent (HttpInstance);
+
+ return Status;
+}
+
+
+/**
+ Close events in the TCP connection token and TCP close token.
+
+ @param[in] HttpInstance Pointer to HTTP_PROTOCOL structure.
+
+**/
+VOID
+HttpCloseTcpConnCloseEvent (
+ IN HTTP_PROTOCOL *HttpInstance
+ )
+{
+ ASSERT (HttpInstance != NULL);
+
+ if (HttpInstance->LocalAddressIsIPv6) {
+ if (NULL != HttpInstance->Tcp6ConnToken.CompletionToken.Event) {
+ gBS->CloseEvent (HttpInstance->Tcp6ConnToken.CompletionToken.Event);
+ HttpInstance->Tcp6ConnToken.CompletionToken.Event = NULL;
+ }
+
+ if (NULL != HttpInstance->Tcp6CloseToken.CompletionToken.Event) {
+ gBS->CloseEvent(HttpInstance->Tcp6CloseToken.CompletionToken.Event);
+ HttpInstance->Tcp6CloseToken.CompletionToken.Event = NULL;
+ }
+
+ } else {
+ if (NULL != HttpInstance->Tcp4ConnToken.CompletionToken.Event) {
+ gBS->CloseEvent (HttpInstance->Tcp4ConnToken.CompletionToken.Event);
+ HttpInstance->Tcp4ConnToken.CompletionToken.Event = NULL;
+ }
+
+ if (NULL != HttpInstance->Tcp4CloseToken.CompletionToken.Event) {
+ gBS->CloseEvent(HttpInstance->Tcp4CloseToken.CompletionToken.Event);
+ HttpInstance->Tcp4CloseToken.CompletionToken.Event = NULL;
+ }
+ }
+
+}
+
+/**
+ Create event for the TCP transmit token.
+
+ @param[in] Wrap Point to HTTP token's wrap data.
+
+ @retval EFI_SUCCESS The events is created successfully.
+ @retval others Other error as indicated.
+
+**/
+EFI_STATUS
+HttpCreateTcpTxEvent (
+ IN HTTP_TOKEN_WRAP *Wrap
+ )
+{
+ EFI_STATUS Status;
+ HTTP_PROTOCOL *HttpInstance;
+ HTTP_TCP_TOKEN_WRAP *TcpWrap;
+
+ HttpInstance = Wrap->HttpInstance;
+ TcpWrap = &Wrap->TcpWrap;
+
+ if (!HttpInstance->LocalAddressIsIPv6) {
+ Status = gBS->CreateEvent (
+ EVT_NOTIFY_SIGNAL,
+ TPL_NOTIFY,
+ HttpTcpTransmitNotify,
+ Wrap,
+ &TcpWrap->Tx4Token.CompletionToken.Event
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ TcpWrap->Tx4Data.Push = TRUE;
+ TcpWrap->Tx4Data.Urgent = FALSE;
+ TcpWrap->Tx4Data.FragmentCount = 1;
+ TcpWrap->Tx4Token.Packet.TxData = &Wrap->TcpWrap.Tx4Data;
+ TcpWrap->Tx4Token.CompletionToken.Status = EFI_NOT_READY;
+
+ } else {
+ Status = gBS->CreateEvent (
+ EVT_NOTIFY_SIGNAL,
+ TPL_NOTIFY,
+ HttpTcpTransmitNotify,
+ Wrap,
+ &TcpWrap->Tx6Token.CompletionToken.Event
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ TcpWrap->Tx6Data.Push = TRUE;
+ TcpWrap->Tx6Data.Urgent = FALSE;
+ TcpWrap->Tx6Data.FragmentCount = 1;
+ TcpWrap->Tx6Token.Packet.TxData = &Wrap->TcpWrap.Tx6Data;
+ TcpWrap->Tx6Token.CompletionToken.Status =EFI_NOT_READY;
+
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Create event for the TCP receive token which is used to receive HTTP header.
+
+ @param[in] HttpInstance Pointer to HTTP_PROTOCOL structure.
+
+ @retval EFI_SUCCESS The events is created successfully.
+ @retval others Other error as indicated.
+
+**/
+EFI_STATUS
+HttpCreateTcpRxEventForHeader (
+ IN HTTP_PROTOCOL *HttpInstance
+ )
+{
+ EFI_STATUS Status;
+
+ if (!HttpInstance->LocalAddressIsIPv6) {
+ Status = gBS->CreateEvent (
+ EVT_NOTIFY_SIGNAL,
+ TPL_NOTIFY,
+ HttpCommonNotify,
+ &HttpInstance->IsRxDone,
+ &HttpInstance->Rx4Token.CompletionToken.Event
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ HttpInstance->Rx4Data.FragmentCount = 1;
+ HttpInstance->Rx4Token.Packet.RxData = &HttpInstance->Rx4Data;
+ HttpInstance->Rx4Token.CompletionToken.Status = EFI_NOT_READY;
+
+ } else {
+ Status = gBS->CreateEvent (
+ EVT_NOTIFY_SIGNAL,
+ TPL_NOTIFY,
+ HttpCommonNotify,
+ &HttpInstance->IsRxDone,
+ &HttpInstance->Rx6Token.CompletionToken.Event
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ HttpInstance->Rx6Data.FragmentCount =1;
+ HttpInstance->Rx6Token.Packet.RxData = &HttpInstance->Rx6Data;
+ HttpInstance->Rx6Token.CompletionToken.Status = EFI_NOT_READY;
+
+ }
+
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Create event for the TCP receive token which is used to receive HTTP body.
+
+ @param[in] Wrap Point to HTTP token's wrap data.
+
+ @retval EFI_SUCCESS The events is created successfully.
+ @retval others Other error as indicated.
+
+**/
+EFI_STATUS
+HttpCreateTcpRxEvent (
+ IN HTTP_TOKEN_WRAP *Wrap
+ )
+{
+ EFI_STATUS Status;
+ HTTP_PROTOCOL *HttpInstance;
+ HTTP_TCP_TOKEN_WRAP *TcpWrap;
+
+ HttpInstance = Wrap->HttpInstance;
+ TcpWrap = &Wrap->TcpWrap;
+ if (!HttpInstance->LocalAddressIsIPv6) {
+ Status = gBS->CreateEvent (
+ EVT_NOTIFY_SIGNAL,
+ TPL_NOTIFY,
+ HttpTcpReceiveNotify,
+ Wrap,
+ &TcpWrap->Rx4Token.CompletionToken.Event
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ TcpWrap->Rx4Data.FragmentCount = 1;
+ TcpWrap->Rx4Token.Packet.RxData = &Wrap->TcpWrap.Rx4Data;
+ TcpWrap->Rx4Token.CompletionToken.Status = EFI_NOT_READY;
+
+ } else {
+ Status = gBS->CreateEvent (
+ EVT_NOTIFY_SIGNAL,
+ TPL_NOTIFY,
+ HttpTcpReceiveNotify,
+ Wrap,
+ &TcpWrap->Rx6Token.CompletionToken.Event
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ TcpWrap->Rx6Data.FragmentCount = 1;
+ TcpWrap->Rx6Token.Packet.RxData = &Wrap->TcpWrap.Rx6Data;
+ TcpWrap->Rx6Token.CompletionToken.Status = EFI_NOT_READY;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Close Events for Tcp Receive Tokens for HTTP body and HTTP header.
+
+ @param[in] Wrap Pointer to HTTP token's wrap data.
+
+**/
+VOID
+HttpCloseTcpRxEvent (
+ IN HTTP_TOKEN_WRAP *Wrap
+ )
+{
+ HTTP_PROTOCOL *HttpInstance;
+
+ ASSERT (Wrap != NULL);
+ HttpInstance = Wrap->HttpInstance;
+
+ if (HttpInstance->LocalAddressIsIPv6) {
+ if (Wrap->TcpWrap.Rx6Token.CompletionToken.Event != NULL) {
+ gBS->CloseEvent (Wrap->TcpWrap.Rx6Token.CompletionToken.Event);
+ }
+
+ if (HttpInstance->Rx6Token.CompletionToken.Event != NULL) {
+ gBS->CloseEvent (HttpInstance->Rx6Token.CompletionToken.Event);
+ HttpInstance->Rx6Token.CompletionToken.Event = NULL;
+ }
+ } else {
+ if (Wrap->TcpWrap.Rx4Token.CompletionToken.Event != NULL) {
+ gBS->CloseEvent (Wrap->TcpWrap.Rx4Token.CompletionToken.Event);
+ }
+
+ if (HttpInstance->Rx4Token.CompletionToken.Event != NULL) {
+ gBS->CloseEvent (HttpInstance->Rx4Token.CompletionToken.Event);
+ HttpInstance->Rx4Token.CompletionToken.Event = NULL;
+ }
+ }
+}
+
+/**
+ Intiialize the HTTP_PROTOCOL structure to the unconfigured state.
+
+ @param[in, out] HttpInstance Pointer to HTTP_PROTOCOL structure.
+ @param[in] IpVersion Indicate us TCP4 protocol or TCP6 protocol.
+
+ @retval EFI_SUCCESS HTTP_PROTOCOL structure is initialized successfully.
+ @retval Others Other error as indicated.
+
+**/
+EFI_STATUS
+HttpInitProtocol (
+ IN OUT HTTP_PROTOCOL *HttpInstance,
+ IN BOOLEAN IpVersion
+ )
+{
+ EFI_STATUS Status;
+ VOID *Interface;
+ BOOLEAN UsingIpv6;
+
+ ASSERT (HttpInstance != NULL);
+ UsingIpv6 = IpVersion;
+
+ if (!UsingIpv6) {
+ //
+ // Create TCP4 child.
+ //
+ Status = NetLibCreateServiceChild (
+ HttpInstance->Service->ControllerHandle,
+ HttpInstance->Service->Ip4DriverBindingHandle,
+ &gEfiTcp4ServiceBindingProtocolGuid,
+ &HttpInstance->Tcp4ChildHandle
+ );
+
+ if (EFI_ERROR (Status)) {
+ goto ON_ERROR;
+ }
+
+ Status = gBS->OpenProtocol (
+ HttpInstance->Tcp4ChildHandle,
+ &gEfiTcp4ProtocolGuid,
+ (VOID **) &Interface,
+ HttpInstance->Service->Ip4DriverBindingHandle,
+ HttpInstance->Service->ControllerHandle,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+
+ if (EFI_ERROR (Status)) {
+ goto ON_ERROR;
+ }
+
+ Status = gBS->OpenProtocol (
+ HttpInstance->Tcp4ChildHandle,
+ &gEfiTcp4ProtocolGuid,
+ (VOID **) &HttpInstance->Tcp4,
+ HttpInstance->Service->Ip4DriverBindingHandle,
+ HttpInstance->Handle,
+ EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
+ );
+ if (EFI_ERROR(Status)) {
+ goto ON_ERROR;
+ }
+
+ Status = gBS->OpenProtocol (
+ HttpInstance->Service->Tcp4ChildHandle,
+ &gEfiTcp4ProtocolGuid,
+ (VOID **) &Interface,
+ HttpInstance->Service->Ip4DriverBindingHandle,
+ HttpInstance->Handle,
+ EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
+ );
+ if (EFI_ERROR(Status)) {
+ goto ON_ERROR;
+ }
+ } else {
+ //
+ // Create TCP6 Child.
+ //
+ Status = NetLibCreateServiceChild (
+ HttpInstance->Service->ControllerHandle,
+ HttpInstance->Service->Ip6DriverBindingHandle,
+ &gEfiTcp6ServiceBindingProtocolGuid,
+ &HttpInstance->Tcp6ChildHandle
+ );
+
+ if (EFI_ERROR (Status)) {
+ goto ON_ERROR;
+ }
+
+ Status = gBS->OpenProtocol (
+ HttpInstance->Tcp6ChildHandle,
+ &gEfiTcp6ProtocolGuid,
+ (VOID **) &Interface,
+ HttpInstance->Service->Ip6DriverBindingHandle,
+ HttpInstance->Service->ControllerHandle,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+
+ if (EFI_ERROR (Status)) {
+ goto ON_ERROR;
+ }
+
+ Status = gBS->OpenProtocol (
+ HttpInstance->Tcp6ChildHandle,
+ &gEfiTcp6ProtocolGuid,
+ (VOID **) &HttpInstance->Tcp6,
+ HttpInstance->Service->Ip6DriverBindingHandle,
+ HttpInstance->Handle,
+ EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
+ );
+
+ if (EFI_ERROR(Status)) {
+ goto ON_ERROR;
+ }
+
+ Status = gBS->OpenProtocol (
+ HttpInstance->Service->Tcp6ChildHandle,
+ &gEfiTcp6ProtocolGuid,
+ (VOID **) &Interface,
+ HttpInstance->Service->Ip6DriverBindingHandle,
+ HttpInstance->Handle,
+ EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
+ );
+
+ if (EFI_ERROR(Status)) {
+ goto ON_ERROR;
+ }
+ }
+
+ HttpInstance->Url = AllocateZeroPool (HTTP_URL_BUFFER_LEN);
+ if (HttpInstance->Url == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto ON_ERROR;
+ }
+
+ return EFI_SUCCESS;
+
+ON_ERROR:
+
+ if (HttpInstance->Tcp4ChildHandle != NULL) {
+ gBS->CloseProtocol (
+ HttpInstance->Tcp4ChildHandle,
+ &gEfiTcp4ProtocolGuid,
+ HttpInstance->Service->Ip4DriverBindingHandle,
+ HttpInstance->Service->ControllerHandle
+ );
+
+ gBS->CloseProtocol (
+ HttpInstance->Tcp4ChildHandle,
+ &gEfiTcp4ProtocolGuid,
+ HttpInstance->Service->Ip4DriverBindingHandle,
+ HttpInstance->Handle
+ );
+
+ NetLibDestroyServiceChild (
+ HttpInstance->Service->ControllerHandle,
+ HttpInstance->Service->Ip4DriverBindingHandle,
+ &gEfiTcp4ServiceBindingProtocolGuid,
+ HttpInstance->Tcp4ChildHandle
+ );
+ }
+
+ if (HttpInstance->Service->Tcp4ChildHandle != NULL) {
+ gBS->CloseProtocol (
+ HttpInstance->Service->Tcp4ChildHandle,
+ &gEfiTcp4ProtocolGuid,
+ HttpInstance->Service->Ip4DriverBindingHandle,
+ HttpInstance->Handle
+ );
+ }
+
+ if (HttpInstance->Tcp6ChildHandle != NULL) {
+ gBS->CloseProtocol (
+ HttpInstance->Tcp6ChildHandle,
+ &gEfiTcp6ProtocolGuid,
+ HttpInstance->Service->Ip6DriverBindingHandle,
+ HttpInstance->Service->ControllerHandle
+ );
+
+ gBS->CloseProtocol (
+ HttpInstance->Tcp6ChildHandle,
+ &gEfiTcp6ProtocolGuid,
+ HttpInstance->Service->Ip6DriverBindingHandle,
+ HttpInstance->Handle
+ );
+
+ NetLibDestroyServiceChild (
+ HttpInstance->Service->ControllerHandle,
+ HttpInstance->Service->Ip6DriverBindingHandle,
+ &gEfiTcp6ServiceBindingProtocolGuid,
+ HttpInstance->Tcp6ChildHandle
+ );
+ }
+
+ if (HttpInstance->Service->Tcp6ChildHandle != NULL) {
+ gBS->CloseProtocol (
+ HttpInstance->Service->Tcp6ChildHandle,
+ &gEfiTcp6ProtocolGuid,
+ HttpInstance->Service->Ip6DriverBindingHandle,
+ HttpInstance->Handle
+ );
+ }
+
+ return EFI_UNSUPPORTED;
+
+}
+
+/**
+ Clean up the HTTP child, release all the resources used by it.
+
+ @param[in] HttpInstance The HTTP child to clean up.
+
+**/
+VOID
+HttpCleanProtocol (
+ IN HTTP_PROTOCOL *HttpInstance
+ )
+{
+ HttpCloseConnection (HttpInstance);
+
+ HttpCloseTcpConnCloseEvent (HttpInstance);
+
+ if (HttpInstance->TimeoutEvent != NULL) {
+ gBS->CloseEvent (HttpInstance->TimeoutEvent);
+ HttpInstance->TimeoutEvent = NULL;
+ }
+
+ if (HttpInstance->CacheBody != NULL) {
+ FreePool (HttpInstance->CacheBody);
+ HttpInstance->CacheBody = NULL;
+ HttpInstance->NextMsg = NULL;
+ }
+
+ if (HttpInstance->RemoteHost != NULL) {
+ FreePool (HttpInstance->RemoteHost);
+ HttpInstance->RemoteHost = NULL;
+ }
+
+ if (HttpInstance->MsgParser != NULL) {
+ HttpFreeMsgParser (HttpInstance->MsgParser);
+ HttpInstance->MsgParser = NULL;
+ }
+
+ if (HttpInstance->Url != NULL) {
+ FreePool (HttpInstance->Url);
+ HttpInstance->Url = NULL;
+ }
+
+ NetMapClean (&HttpInstance->TxTokens);
+ NetMapClean (&HttpInstance->RxTokens);
+
+ if (HttpInstance->Tcp4ChildHandle != NULL) {
+ gBS->CloseProtocol (
+ HttpInstance->Tcp4ChildHandle,
+ &gEfiTcp4ProtocolGuid,
+ HttpInstance->Service->Ip4DriverBindingHandle,
+ HttpInstance->Service->ControllerHandle
+ );
+
+ gBS->CloseProtocol (
+ HttpInstance->Tcp4ChildHandle,
+ &gEfiTcp4ProtocolGuid,
+ HttpInstance->Service->Ip4DriverBindingHandle,
+ HttpInstance->Handle
+ );
+
+ NetLibDestroyServiceChild (
+ HttpInstance->Service->ControllerHandle,
+ HttpInstance->Service->Ip4DriverBindingHandle,
+ &gEfiTcp4ServiceBindingProtocolGuid,
+ HttpInstance->Tcp4ChildHandle
+ );
+ }
+
+ if (HttpInstance->Service->Tcp4ChildHandle != NULL) {
+ gBS->CloseProtocol (
+ HttpInstance->Service->Tcp4ChildHandle,
+ &gEfiTcp4ProtocolGuid,
+ HttpInstance->Service->Ip4DriverBindingHandle,
+ HttpInstance->Handle
+ );
+ }
+
+ if (HttpInstance->Tcp6ChildHandle != NULL) {
+ gBS->CloseProtocol (
+ HttpInstance->Tcp6ChildHandle,
+ &gEfiTcp6ProtocolGuid,
+ HttpInstance->Service->Ip6DriverBindingHandle,
+ HttpInstance->Service->ControllerHandle
+ );
+
+ gBS->CloseProtocol (
+ HttpInstance->Tcp6ChildHandle,
+ &gEfiTcp6ProtocolGuid,
+ HttpInstance->Service->Ip6DriverBindingHandle,
+ HttpInstance->Handle
+ );
+
+ NetLibDestroyServiceChild (
+ HttpInstance->Service->ControllerHandle,
+ HttpInstance->Service->Ip6DriverBindingHandle,
+ &gEfiTcp6ServiceBindingProtocolGuid,
+ HttpInstance->Tcp6ChildHandle
+ );
+ }
+
+ if (HttpInstance->Service->Tcp6ChildHandle != NULL) {
+ gBS->CloseProtocol (
+ HttpInstance->Service->Tcp6ChildHandle,
+ &gEfiTcp6ProtocolGuid,
+ HttpInstance->Service->Ip6DriverBindingHandle,
+ HttpInstance->Handle
+ );
+ }
+
+ TlsCloseTxRxEvent (HttpInstance);
+}
+
+/**
+ Establish TCP connection with HTTP server.
+
+ @param[in] HttpInstance The HTTP instance private data.
+
+ @retval EFI_SUCCESS The TCP connection is established.
+ @retval Others Other error as indicated.
+
+**/
+EFI_STATUS
+HttpCreateConnection (
+ IN HTTP_PROTOCOL *HttpInstance
+ )
+{
+ EFI_STATUS Status;
+
+ //
+ // Connect to Http server
+ //
+ if (!HttpInstance->LocalAddressIsIPv6) {
+ HttpInstance->IsTcp4ConnDone = FALSE;
+ HttpInstance->Tcp4ConnToken.CompletionToken.Status = EFI_NOT_READY;
+ Status = HttpInstance->Tcp4->Connect (HttpInstance->Tcp4, &HttpInstance->Tcp4ConnToken);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "HttpCreateConnection: Tcp4->Connect() = %r\n", Status));
+ return Status;
+ }
+
+ while (!HttpInstance->IsTcp4ConnDone) {
+ HttpInstance->Tcp4->Poll (HttpInstance->Tcp4);
+ }
+
+ Status = HttpInstance->Tcp4ConnToken.CompletionToken.Status;
+
+ } else {
+ HttpInstance->IsTcp6ConnDone = FALSE;
+ HttpInstance->Tcp6ConnToken.CompletionToken.Status = EFI_NOT_READY;
+ Status = HttpInstance->Tcp6->Connect (HttpInstance->Tcp6, &HttpInstance->Tcp6ConnToken);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "HttpCreateConnection: Tcp6->Connect() = %r\n", Status));
+ return Status;
+ }
+
+ while(!HttpInstance->IsTcp6ConnDone) {
+ HttpInstance->Tcp6->Poll (HttpInstance->Tcp6);
+ }
+
+ Status = HttpInstance->Tcp6ConnToken.CompletionToken.Status;
+ }
+
+ if (!EFI_ERROR (Status)) {
+ HttpInstance->State = HTTP_STATE_TCP_CONNECTED;
+ }
+
+ return Status;
+}
+
+/**
+ Close existing TCP connection.
+
+ @param[in] HttpInstance The HTTP instance private data.
+
+ @retval EFI_SUCCESS The TCP connection is closed.
+ @retval Others Other error as indicated.
+
+**/
+EFI_STATUS
+HttpCloseConnection (
+ IN HTTP_PROTOCOL *HttpInstance
+ )
+{
+ EFI_STATUS Status;
+
+ if (HttpInstance->State == HTTP_STATE_TCP_CONNECTED) {
+
+ if (HttpInstance->LocalAddressIsIPv6) {
+ HttpInstance->Tcp6CloseToken.AbortOnClose = TRUE;
+ HttpInstance->IsTcp6CloseDone = FALSE;
+ Status = HttpInstance->Tcp6->Close (HttpInstance->Tcp6, &HttpInstance->Tcp6CloseToken);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ while (!HttpInstance->IsTcp6CloseDone) {
+ HttpInstance->Tcp6->Poll (HttpInstance->Tcp6);
+ }
+
+ } else {
+ HttpInstance->Tcp4CloseToken.AbortOnClose = TRUE;
+ HttpInstance->IsTcp4CloseDone = FALSE;
+ Status = HttpInstance->Tcp4->Close (HttpInstance->Tcp4, &HttpInstance->Tcp4CloseToken);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ while (!HttpInstance->IsTcp4CloseDone) {
+ HttpInstance->Tcp4->Poll (HttpInstance->Tcp4);
+ }
+ }
+
+ }
+
+ HttpInstance->State = HTTP_STATE_TCP_CLOSED;
+ return EFI_SUCCESS;
+}
+
+/**
+ Configure TCP4 protocol child.
+
+ @param[in] HttpInstance The HTTP instance private data.
+ @param[in] Wrap The HTTP token's wrap data.
+
+ @retval EFI_SUCCESS The TCP4 protocol child is configured.
+ @retval Others Other error as indicated.
+
+**/
+EFI_STATUS
+HttpConfigureTcp4 (
+ IN HTTP_PROTOCOL *HttpInstance,
+ IN HTTP_TOKEN_WRAP *Wrap
+ )
+{
+ EFI_STATUS Status;
+ EFI_TCP4_CONFIG_DATA *Tcp4CfgData;
+ EFI_TCP4_ACCESS_POINT *Tcp4AP;
+ EFI_TCP4_OPTION *Tcp4Option;
+
+ ASSERT (HttpInstance != NULL);
+
+
+ Tcp4CfgData = &HttpInstance->Tcp4CfgData;
+ ZeroMem (Tcp4CfgData, sizeof (EFI_TCP4_CONFIG_DATA));
+
+ Tcp4CfgData->TypeOfService = HTTP_TOS_DEAULT;
+ Tcp4CfgData->TimeToLive = HTTP_TTL_DEAULT;
+ Tcp4CfgData->ControlOption = &HttpInstance->Tcp4Option;
+
+ Tcp4AP = &Tcp4CfgData->AccessPoint;
+ Tcp4AP->UseDefaultAddress = HttpInstance->IPv4Node.UseDefaultAddress;
+ if (!Tcp4AP->UseDefaultAddress) {
+ IP4_COPY_ADDRESS (&Tcp4AP->StationAddress, &HttpInstance->IPv4Node.LocalAddress);
+ IP4_COPY_ADDRESS (&Tcp4AP->SubnetMask, &HttpInstance->IPv4Node.LocalSubnet);
+ }
+
+ Tcp4AP->StationPort = HttpInstance->IPv4Node.LocalPort;
+ Tcp4AP->RemotePort = HttpInstance->RemotePort;
+ Tcp4AP->ActiveFlag = TRUE;
+ IP4_COPY_ADDRESS (&Tcp4AP->RemoteAddress, &HttpInstance->RemoteAddr);
+
+ Tcp4Option = Tcp4CfgData->ControlOption;
+ Tcp4Option->ReceiveBufferSize = HTTP_BUFFER_SIZE_DEAULT;
+ Tcp4Option->SendBufferSize = HTTP_BUFFER_SIZE_DEAULT;
+ Tcp4Option->MaxSynBackLog = HTTP_MAX_SYN_BACK_LOG;
+ Tcp4Option->ConnectionTimeout = HTTP_CONNECTION_TIMEOUT;
+ Tcp4Option->DataRetries = HTTP_DATA_RETRIES;
+ Tcp4Option->FinTimeout = HTTP_FIN_TIMEOUT;
+ Tcp4Option->KeepAliveProbes = HTTP_KEEP_ALIVE_PROBES;
+ Tcp4Option->KeepAliveTime = HTTP_KEEP_ALIVE_TIME;
+ Tcp4Option->KeepAliveInterval = HTTP_KEEP_ALIVE_INTERVAL;
+ Tcp4Option->EnableNagle = TRUE;
+ Tcp4CfgData->ControlOption = Tcp4Option;
+
+ Status = HttpInstance->Tcp4->Configure (HttpInstance->Tcp4, Tcp4CfgData);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "HttpConfigureTcp4 - %r\n", Status));
+ return Status;
+ }
+
+ Status = HttpCreateTcpConnCloseEvent (HttpInstance);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = HttpCreateTcpTxEvent (Wrap);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ HttpInstance->State = HTTP_STATE_TCP_CONFIGED;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Configure TCP6 protocol child.
+
+ @param[in] HttpInstance The HTTP instance private data.
+ @param[in] Wrap The HTTP token's wrap data.
+
+ @retval EFI_SUCCESS The TCP6 protocol child is configured.
+ @retval Others Other error as indicated.
+
+**/
+EFI_STATUS
+HttpConfigureTcp6 (
+ IN HTTP_PROTOCOL *HttpInstance,
+ IN HTTP_TOKEN_WRAP *Wrap
+ )
+{
+ EFI_STATUS Status;
+ EFI_TCP6_CONFIG_DATA *Tcp6CfgData;
+ EFI_TCP6_ACCESS_POINT *Tcp6Ap;
+ EFI_TCP6_OPTION *Tcp6Option;
+
+ ASSERT (HttpInstance != NULL);
+
+ Tcp6CfgData = &HttpInstance->Tcp6CfgData;
+ ZeroMem (Tcp6CfgData, sizeof (EFI_TCP6_CONFIG_DATA));
+
+ Tcp6CfgData->TrafficClass = 0;
+ Tcp6CfgData->HopLimit = 255;
+ Tcp6CfgData->ControlOption = &HttpInstance->Tcp6Option;
+
+ Tcp6Ap = &Tcp6CfgData->AccessPoint;
+ Tcp6Ap->ActiveFlag = TRUE;
+ Tcp6Ap->StationPort = HttpInstance->Ipv6Node.LocalPort;
+ Tcp6Ap->RemotePort = HttpInstance->RemotePort;
+ IP6_COPY_ADDRESS (&Tcp6Ap->StationAddress, &HttpInstance->Ipv6Node.LocalAddress);
+ IP6_COPY_ADDRESS (&Tcp6Ap->RemoteAddress , &HttpInstance->RemoteIpv6Addr);
+
+ Tcp6Option = Tcp6CfgData->ControlOption;
+ Tcp6Option->ReceiveBufferSize = HTTP_BUFFER_SIZE_DEAULT;
+ Tcp6Option->SendBufferSize = HTTP_BUFFER_SIZE_DEAULT;
+ Tcp6Option->MaxSynBackLog = HTTP_MAX_SYN_BACK_LOG;
+ Tcp6Option->ConnectionTimeout = HTTP_CONNECTION_TIMEOUT;
+ Tcp6Option->DataRetries = HTTP_DATA_RETRIES;
+ Tcp6Option->FinTimeout = HTTP_FIN_TIMEOUT;
+ Tcp6Option->KeepAliveProbes = HTTP_KEEP_ALIVE_PROBES;
+ Tcp6Option->KeepAliveTime = HTTP_KEEP_ALIVE_TIME;
+ Tcp6Option->KeepAliveInterval = HTTP_KEEP_ALIVE_INTERVAL;
+ Tcp6Option->EnableNagle = TRUE;
+
+ Status = HttpInstance->Tcp6->Configure (HttpInstance->Tcp6, Tcp6CfgData);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "HttpConfigureTcp6 - %r\n", Status));
+ return Status;
+ }
+
+ Status = HttpCreateTcpConnCloseEvent (HttpInstance);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = HttpCreateTcpTxEvent (Wrap);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ HttpInstance->State = HTTP_STATE_TCP_CONFIGED;
+
+ return EFI_SUCCESS;
+
+}
+
+/**
+ Check existing TCP connection, if in error state, recover TCP4 connection. Then,
+ connect one TLS session if required.
+
+ @param[in] HttpInstance The HTTP instance private data.
+
+ @retval EFI_SUCCESS The TCP connection is established.
+ @retval EFI_NOT_READY TCP4 protocol child is not created or configured.
+ @retval Others Other error as indicated.
+
+**/
+EFI_STATUS
+HttpConnectTcp4 (
+ IN HTTP_PROTOCOL *HttpInstance
+ )
+{
+ EFI_STATUS Status;
+ EFI_TCP4_CONNECTION_STATE Tcp4State;
+
+
+ if (HttpInstance->State < HTTP_STATE_TCP_CONFIGED || HttpInstance->Tcp4 == NULL) {
+ return EFI_NOT_READY;
+ }
+
+ Status = HttpInstance->Tcp4->GetModeData(
+ HttpInstance->Tcp4,
+ &Tcp4State,
+ NULL,
+ NULL,
+ NULL,
+ NULL
+ );
+ if (EFI_ERROR(Status)){
+ DEBUG ((EFI_D_ERROR, "Tcp4 GetModeData fail - %x\n", Status));
+ return Status;
+ }
+
+ if (Tcp4State == Tcp4StateEstablished) {
+ return EFI_SUCCESS;
+ } else if (Tcp4State > Tcp4StateEstablished ) {
+ HttpCloseConnection(HttpInstance);
+ }
+
+ Status = HttpCreateConnection (HttpInstance);
+ if (EFI_ERROR(Status)){
+ DEBUG ((EFI_D_ERROR, "Tcp4 Connection fail - %x\n", Status));
+ return Status;
+ }
+
+ //
+ // Tls session connection.
+ //
+ if (HttpInstance->UseHttps) {
+ if (HttpInstance->TimeoutEvent == NULL) {
+ //
+ // Create TimeoutEvent for TLS connection.
+ //
+ Status = gBS->CreateEvent (
+ EVT_TIMER,
+ TPL_CALLBACK,
+ NULL,
+ NULL,
+ &HttpInstance->TimeoutEvent
+ );
+ if (EFI_ERROR (Status)) {
+ TlsCloseTxRxEvent (HttpInstance);
+ return Status;
+ }
+ }
+
+ //
+ // Start the timer, and wait Timeout seconds for connection.
+ //
+ Status = gBS->SetTimer (HttpInstance->TimeoutEvent, TimerRelative, HTTP_CONNECTION_TIMEOUT * TICKS_PER_SECOND);
+ if (EFI_ERROR (Status)) {
+ TlsCloseTxRxEvent (HttpInstance);
+ return Status;
+ }
+
+ Status = TlsConnectSession (HttpInstance, HttpInstance->TimeoutEvent);
+
+ gBS->SetTimer (HttpInstance->TimeoutEvent, TimerCancel, 0);
+
+ if (EFI_ERROR (Status)) {
+ TlsCloseTxRxEvent (HttpInstance);
+ return Status;
+ }
+ }
+
+ return Status;
+}
+
+/**
+ Check existing TCP connection, if in error state, recover TCP6 connection. Then,
+ connect one TLS session if required.
+
+ @param[in] HttpInstance The HTTP instance private data.
+
+ @retval EFI_SUCCESS The TCP connection is established.
+ @retval EFI_NOT_READY TCP6 protocol child is not created or configured.
+ @retval Others Other error as indicated.
+
+**/
+EFI_STATUS
+HttpConnectTcp6 (
+ IN HTTP_PROTOCOL *HttpInstance
+ )
+{
+ EFI_STATUS Status;
+ EFI_TCP6_CONNECTION_STATE Tcp6State;
+
+ if (HttpInstance->State < HTTP_STATE_TCP_CONFIGED || HttpInstance->Tcp6 == NULL) {
+ return EFI_NOT_READY;
+ }
+
+ Status = HttpInstance->Tcp6->GetModeData (
+ HttpInstance->Tcp6,
+ &Tcp6State,
+ NULL,
+ NULL,
+ NULL,
+ NULL
+ );
+
+ if (EFI_ERROR(Status)){
+ DEBUG ((EFI_D_ERROR, "Tcp6 GetModeData fail - %x\n", Status));
+ return Status;
+ }
+
+ if (Tcp6State == Tcp6StateEstablished) {
+ return EFI_SUCCESS;
+ } else if (Tcp6State > Tcp6StateEstablished ) {
+ HttpCloseConnection(HttpInstance);
+ }
+
+ Status = HttpCreateConnection (HttpInstance);
+ if (EFI_ERROR(Status)){
+ DEBUG ((EFI_D_ERROR, "Tcp6 Connection fail - %x\n", Status));
+ return Status;
+ }
+
+ //
+ // Tls session connection.
+ //
+ if (HttpInstance->UseHttps) {
+ if (HttpInstance->TimeoutEvent == NULL) {
+ //
+ // Create TimeoutEvent for TLS connection.
+ //
+ Status = gBS->CreateEvent (
+ EVT_TIMER,
+ TPL_CALLBACK,
+ NULL,
+ NULL,
+ &HttpInstance->TimeoutEvent
+ );
+ if (EFI_ERROR (Status)) {
+ TlsCloseTxRxEvent (HttpInstance);
+ return Status;
+ }
+ }
+
+ //
+ // Start the timer, and wait Timeout seconds for connection.
+ //
+ Status = gBS->SetTimer (HttpInstance->TimeoutEvent, TimerRelative, HTTP_CONNECTION_TIMEOUT * TICKS_PER_SECOND);
+ if (EFI_ERROR (Status)) {
+ TlsCloseTxRxEvent (HttpInstance);
+ return Status;
+ }
+
+ Status = TlsConnectSession (HttpInstance, HttpInstance->TimeoutEvent);
+
+ gBS->SetTimer (HttpInstance->TimeoutEvent, TimerCancel, 0);
+
+ if (EFI_ERROR (Status)) {
+ TlsCloseTxRxEvent (HttpInstance);
+ return Status;
+ }
+ }
+
+ return Status;
+}
+
+/**
+ Initialize Http session.
+
+ @param[in] HttpInstance The HTTP instance private data.
+ @param[in] Wrap The HTTP token's wrap data.
+ @param[in] Configure The Flag indicates whether need to initialize session.
+ @param[in] TlsConfigure The Flag indicates whether it's the new Tls session.
+
+ @retval EFI_SUCCESS The initialization of session is done.
+ @retval Others Other error as indicated.
+
+**/
+EFI_STATUS
+HttpInitSession (
+ IN HTTP_PROTOCOL *HttpInstance,
+ IN HTTP_TOKEN_WRAP *Wrap,
+ IN BOOLEAN Configure,
+ IN BOOLEAN TlsConfigure
+ )
+{
+ EFI_STATUS Status;
+ ASSERT (HttpInstance != NULL);
+
+ //
+ // Configure Tls session.
+ //
+ if (TlsConfigure) {
+ Status = TlsConfigureSession (HttpInstance);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+
+ if (!HttpInstance->LocalAddressIsIPv6) {
+ //
+ // Configure TCP instance.
+ //
+ if (Configure) {
+ Status = HttpConfigureTcp4 (HttpInstance, Wrap);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+
+ //
+ // Connect TCP.
+ //
+ Status = HttpConnectTcp4 (HttpInstance);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ } else {
+ //
+ // Configure TCP instance.
+ //
+ if (Configure) {
+ Status = HttpConfigureTcp6 (HttpInstance, Wrap);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+
+ //
+ // Connect TCP.
+ //
+ Status = HttpConnectTcp6 (HttpInstance);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+
+ return EFI_SUCCESS;
+
+}
+
+/**
+ Send the HTTP or HTTPS message through TCP4 or TCP6.
+
+ @param[in] HttpInstance The HTTP instance private data.
+ @param[in] Wrap The HTTP token's wrap data.
+ @param[in] TxString Buffer containing the HTTP message string.
+ @param[in] TxStringLen Length of the HTTP message string in bytes.
+
+ @retval EFI_SUCCESS The HTTP message is queued into TCP transmit queue.
+ @retval Others Other error as indicated.
+
+**/
+EFI_STATUS
+HttpTransmitTcp (
+ IN HTTP_PROTOCOL *HttpInstance,
+ IN HTTP_TOKEN_WRAP *Wrap,
+ IN UINT8 *TxString,
+ IN UINTN TxStringLen
+ )
+{
+ EFI_STATUS Status;
+ EFI_TCP4_IO_TOKEN *Tx4Token;
+ EFI_TCP4_PROTOCOL *Tcp4;
+ EFI_TCP6_IO_TOKEN *Tx6Token;
+ EFI_TCP6_PROTOCOL *Tcp6;
+ UINT8 *Buffer;
+ UINTN BufferSize;
+ NET_FRAGMENT TempFragment;
+
+ Status = EFI_SUCCESS;
+ Buffer = NULL;
+ TempFragment.Len = 0;
+ TempFragment.Bulk = NULL;
+
+ //
+ // Need to encrypt data.
+ //
+ if (HttpInstance->UseHttps) {
+ //
+ // Build BufferOut data
+ //
+ BufferSize = sizeof (TLS_RECORD_HEADER) + TxStringLen;
+ Buffer = AllocateZeroPool (BufferSize);
+ if (Buffer == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ return Status;
+ }
+ ((TLS_RECORD_HEADER *) Buffer)->ContentType = TlsContentTypeApplicationData;
+ ((TLS_RECORD_HEADER *) Buffer)->Version.Major = HttpInstance->TlsConfigData.Version.Major;
+ ((TLS_RECORD_HEADER *) Buffer)->Version.Minor = HttpInstance->TlsConfigData.Version.Minor;
+ ((TLS_RECORD_HEADER *) Buffer)->Length = (UINT16) (TxStringLen);
+ CopyMem (Buffer + sizeof (TLS_RECORD_HEADER), TxString, TxStringLen);
+
+ //
+ // Encrypt Packet.
+ //
+ Status = TlsProcessMessage (
+ HttpInstance,
+ Buffer,
+ BufferSize,
+ EfiTlsEncrypt,
+ &TempFragment
+ );
+
+ FreePool (Buffer);
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+
+ if (!HttpInstance->LocalAddressIsIPv6) {
+ Tcp4 = HttpInstance->Tcp4;
+ Tx4Token = &Wrap->TcpWrap.Tx4Token;
+
+ if (HttpInstance->UseHttps) {
+ Tx4Token->Packet.TxData->DataLength = TempFragment.Len;
+ Tx4Token->Packet.TxData->FragmentTable[0].FragmentLength = TempFragment.Len;
+ Tx4Token->Packet.TxData->FragmentTable[0].FragmentBuffer = (VOID *) TempFragment.Bulk;
+ } else {
+ Tx4Token->Packet.TxData->DataLength = (UINT32) TxStringLen;
+ Tx4Token->Packet.TxData->FragmentTable[0].FragmentLength = (UINT32) TxStringLen;
+ Tx4Token->Packet.TxData->FragmentTable[0].FragmentBuffer = (VOID *) TxString;
+ }
+
+ Tx4Token->CompletionToken.Status = EFI_NOT_READY;
+
+ Wrap->TcpWrap.IsTxDone = FALSE;
+ Status = Tcp4->Transmit (Tcp4, Tx4Token);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "Transmit failed: %r\n", Status));
+ return Status;
+ }
+
+ } else {
+ Tcp6 = HttpInstance->Tcp6;
+ Tx6Token = &Wrap->TcpWrap.Tx6Token;
+
+ if (HttpInstance->UseHttps) {
+ Tx6Token->Packet.TxData->DataLength = TempFragment.Len;
+ Tx6Token->Packet.TxData->FragmentTable[0].FragmentLength = TempFragment.Len;
+ Tx6Token->Packet.TxData->FragmentTable[0].FragmentBuffer = (VOID *) TempFragment.Bulk;
+ } else {
+ Tx6Token->Packet.TxData->DataLength = (UINT32) TxStringLen;
+ Tx6Token->Packet.TxData->FragmentTable[0].FragmentLength = (UINT32) TxStringLen;
+ Tx6Token->Packet.TxData->FragmentTable[0].FragmentBuffer = (VOID *) TxString;
+ }
+
+ Tx6Token->CompletionToken.Status = EFI_NOT_READY;
+
+ Wrap->TcpWrap.IsTxDone = FALSE;
+ Status = Tcp6->Transmit (Tcp6, Tx6Token);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "Transmit failed: %r\n", Status));
+ return Status;
+ }
+ }
+
+ return Status;
+}
+
+/**
+ Check whether the user's token or event has already
+ been enqueue on HTTP Tx or Rx Token list.
+
+ @param[in] Map The container of either user's transmit or receive
+ token.
+ @param[in] Item Current item to check against.
+ @param[in] Context The Token to check againist.
+
+ @retval EFI_ACCESS_DENIED The token or event has already been enqueued in IP
+ @retval EFI_SUCCESS The current item isn't the same token/event as the
+ context.
+
+**/
+EFI_STATUS
+EFIAPI
+HttpTokenExist (
+ IN NET_MAP *Map,
+ IN NET_MAP_ITEM *Item,
+ IN VOID *Context
+ )
+{
+ EFI_HTTP_TOKEN *Token;
+ EFI_HTTP_TOKEN *TokenInItem;
+
+ Token = (EFI_HTTP_TOKEN *) Context;
+ TokenInItem = (EFI_HTTP_TOKEN *) Item->Key;
+
+ if (Token == TokenInItem || Token->Event == TokenInItem->Event) {
+ return EFI_ACCESS_DENIED;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Check whether the HTTP message associated with Tx4Token or Tx6Token is already sent out.
+
+ @param[in] Map The container of Tx4Token or Tx6Token.
+ @param[in] Item Current item to check against.
+ @param[in] Context The Token to check againist.
+
+ @retval EFI_NOT_READY The HTTP message is still queued in the list.
+ @retval EFI_SUCCESS The HTTP message has been sent out.
+
+**/
+EFI_STATUS
+EFIAPI
+HttpTcpNotReady (
+ IN NET_MAP *Map,
+ IN NET_MAP_ITEM *Item,
+ IN VOID *Context
+ )
+{
+ HTTP_TOKEN_WRAP *ValueInItem;
+
+ ValueInItem = (HTTP_TOKEN_WRAP *) Item->Value;
+
+ if (!ValueInItem->TcpWrap.IsTxDone) {
+ return EFI_NOT_READY;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Transmit the HTTP or HTTPS mssage by processing the associated HTTP token.
+
+ @param[in] Map The container of Tx4Token or Tx6Token.
+ @param[in] Item Current item to check against.
+ @param[in] Context The Token to check againist.
+
+ @retval EFI_OUT_OF_RESOURCES Failed to allocate resources.
+ @retval EFI_SUCCESS The HTTP message is queued into TCP transmit
+ queue.
+
+**/
+EFI_STATUS
+EFIAPI
+HttpTcpTransmit (
+ IN NET_MAP *Map,
+ IN NET_MAP_ITEM *Item,
+ IN VOID *Context
+ )
+{
+ HTTP_TOKEN_WRAP *ValueInItem;
+ EFI_STATUS Status;
+ CHAR8 *RequestMsg;
+ CHAR8 *Url;
+ UINTN UrlSize;
+ UINTN RequestMsgSize;
+
+ RequestMsg = NULL;
+
+ ValueInItem = (HTTP_TOKEN_WRAP *) Item->Value;
+ if (ValueInItem->TcpWrap.IsTxDone) {
+ return EFI_SUCCESS;
+ }
+
+ //
+ // Parse the URI of the remote host.
+ //
+ UrlSize = StrLen (ValueInItem->HttpToken->Message->Data.Request->Url) + 1;
+ Url = AllocatePool (UrlSize);
+ if (Url == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ UnicodeStrToAsciiStrS (ValueInItem->HttpToken->Message->Data.Request->Url, Url, UrlSize);
+
+ //
+ // Create request message.
+ //
+ Status = HttpGenRequestMessage (
+ ValueInItem->HttpToken->Message,
+ Url,
+ &RequestMsg,
+ &RequestMsgSize
+ );
+ FreePool (Url);
+
+ if (EFI_ERROR (Status) || NULL == RequestMsg){
+ return Status;
+ }
+
+ ASSERT (RequestMsg != NULL);
+
+ //
+ // Transmit the request message.
+ //
+ Status = HttpTransmitTcp (
+ ValueInItem->HttpInstance,
+ ValueInItem,
+ (UINT8*) RequestMsg,
+ RequestMsgSize
+ );
+ FreePool (RequestMsg);
+ return Status;
+}
+
+/**
+ Receive the HTTP response by processing the associated HTTP token.
+
+ @param[in] Map The container of Rx4Token or Rx6Token.
+ @param[in] Item Current item to check against.
+ @param[in] Context The Token to check againist.
+
+ @retval EFI_SUCCESS The HTTP response is queued into TCP receive
+ queue.
+ @retval Others Other error as indicated.
+
+**/
+EFI_STATUS
+EFIAPI
+HttpTcpReceive (
+ IN NET_MAP *Map,
+ IN NET_MAP_ITEM *Item,
+ IN VOID *Context
+ )
+{
+ //
+ // Process the queued HTTP response.
+ //
+ return HttpResponseWorker ((HTTP_TOKEN_WRAP *) Item->Value);
+}
+
+/**
+ Receive the HTTP header by processing the associated HTTP token.
+
+ @param[in] HttpInstance The HTTP instance private data.
+ @param[in, out] SizeofHeaders The HTTP header length.
+ @param[in, out] BufferSize The size of buffer to cacahe the header message.
+ @param[in] Timeout The time to wait for receiving the header packet.
+
+ @retval EFI_SUCCESS The HTTP header is received.
+ @retval Others Other errors as indicated.
+
+**/
+EFI_STATUS
+HttpTcpReceiveHeader (
+ IN HTTP_PROTOCOL *HttpInstance,
+ IN OUT UINTN *SizeofHeaders,
+ IN OUT UINTN *BufferSize,
+ IN EFI_EVENT Timeout
+ )
+{
+ EFI_STATUS Status;
+ EFI_TCP4_IO_TOKEN *Rx4Token;
+ EFI_TCP4_PROTOCOL *Tcp4;
+ EFI_TCP6_IO_TOKEN *Rx6Token;
+ EFI_TCP6_PROTOCOL *Tcp6;
+ CHAR8 **EndofHeader;
+ CHAR8 **HttpHeaders;
+ CHAR8 *Buffer;
+ NET_FRAGMENT Fragment;
+
+ ASSERT (HttpInstance != NULL);
+
+ EndofHeader = HttpInstance->EndofHeader;
+ HttpHeaders = HttpInstance->HttpHeaders;
+ Tcp4 = HttpInstance->Tcp4;
+ Tcp6 = HttpInstance->Tcp6;
+ Buffer = NULL;
+ Rx4Token = NULL;
+ Rx6Token = NULL;
+ Fragment.Len = 0;
+ Fragment.Bulk = NULL;
+
+ if (HttpInstance->LocalAddressIsIPv6) {
+ ASSERT (Tcp6 != NULL);
+ } else {
+ ASSERT (Tcp4 != NULL);
+ }
+
+ if (!HttpInstance->UseHttps) {
+ Status = HttpCreateTcpRxEventForHeader (HttpInstance);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+
+ if (!HttpInstance->LocalAddressIsIPv6) {
+ if (!HttpInstance->UseHttps) {
+ Rx4Token = &HttpInstance->Rx4Token;
+ Rx4Token->Packet.RxData->FragmentTable[0].FragmentBuffer = AllocateZeroPool (DEF_BUF_LEN);
+ if (Rx4Token->Packet.RxData->FragmentTable[0].FragmentBuffer == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ return Status;
+ }
+ }
+
+ //
+ // Receive the HTTP headers only when EFI_HTTP_RESPONSE_DATA is not NULL.
+ //
+ while (*EndofHeader == NULL) {
+ if (!HttpInstance->UseHttps) {
+ HttpInstance->IsRxDone = FALSE;
+ Rx4Token->Packet.RxData->DataLength = DEF_BUF_LEN;
+ Rx4Token->Packet.RxData->FragmentTable[0].FragmentLength = DEF_BUF_LEN;
+ Status = Tcp4->Receive (Tcp4, Rx4Token);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "Tcp4 receive failed: %r\n", Status));
+ return Status;
+ }
+
+ while (!HttpInstance->IsRxDone && ((Timeout == NULL) || EFI_ERROR (gBS->CheckEvent (Timeout)))) {
+ Tcp4->Poll (Tcp4);
+ }
+
+ if (!HttpInstance->IsRxDone) {
+ //
+ // Cancle the Token before close its Event.
+ //
+ Tcp4->Cancel (HttpInstance->Tcp4, &Rx4Token->CompletionToken);
+ gBS->CloseEvent (Rx4Token->CompletionToken.Event);
+ Rx4Token->CompletionToken.Status = EFI_TIMEOUT;
+ }
+
+ Status = Rx4Token->CompletionToken.Status;
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Fragment.Len = Rx4Token->Packet.RxData->FragmentTable[0].FragmentLength;
+ Fragment.Bulk = (UINT8 *) Rx4Token->Packet.RxData->FragmentTable[0].FragmentBuffer;
+ } else {
+ if (Fragment.Bulk != NULL) {
+ FreePool (Fragment.Bulk);
+ Fragment.Bulk = NULL;
+ }
+
+ Status = HttpsReceive (HttpInstance, &Fragment, Timeout);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "Tcp4 receive failed: %r\n", Status));
+ return Status;
+ }
+ }
+
+ //
+ // Append the response string.
+ //
+ *BufferSize = *SizeofHeaders + Fragment.Len;
+ Buffer = AllocateZeroPool (*BufferSize);
+ if (Buffer == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ return Status;
+ }
+
+ if (*HttpHeaders != NULL) {
+ CopyMem (Buffer, *HttpHeaders, *SizeofHeaders);
+ FreePool (*HttpHeaders);
+ }
+
+ CopyMem (
+ Buffer + *SizeofHeaders,
+ Fragment.Bulk,
+ Fragment.Len
+ );
+ *HttpHeaders = Buffer;
+ *SizeofHeaders = *BufferSize;
+
+ //
+ // Check whether we received end of HTTP headers.
+ //
+ *EndofHeader = AsciiStrStr (*HttpHeaders, HTTP_END_OF_HDR_STR);
+ };
+
+ //
+ // Free the buffer.
+ //
+ if (Rx4Token != NULL && Rx4Token->Packet.RxData != NULL && Rx4Token->Packet.RxData->FragmentTable[0].FragmentBuffer != NULL) {
+ FreePool (Rx4Token->Packet.RxData->FragmentTable[0].FragmentBuffer);
+ Rx4Token->Packet.RxData->FragmentTable[0].FragmentBuffer = NULL;
+ Fragment.Bulk = NULL;
+ }
+
+ if (Fragment.Bulk != NULL) {
+ FreePool (Fragment.Bulk);
+ Fragment.Bulk = NULL;
+ }
+ } else {
+ if (!HttpInstance->UseHttps) {
+ Rx6Token = &HttpInstance->Rx6Token;
+ Rx6Token->Packet.RxData->FragmentTable[0].FragmentBuffer = AllocateZeroPool (DEF_BUF_LEN);
+ if (Rx6Token->Packet.RxData->FragmentTable[0].FragmentBuffer == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ return Status;
+ }
+ }
+
+ //
+ // Receive the HTTP headers only when EFI_HTTP_RESPONSE_DATA is not NULL.
+ //
+ while (*EndofHeader == NULL) {
+ if (!HttpInstance->UseHttps) {
+ HttpInstance->IsRxDone = FALSE;
+ Rx6Token->Packet.RxData->DataLength = DEF_BUF_LEN;
+ Rx6Token->Packet.RxData->FragmentTable[0].FragmentLength = DEF_BUF_LEN;
+ Status = Tcp6->Receive (Tcp6, Rx6Token);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "Tcp6 receive failed: %r\n", Status));
+ return Status;
+ }
+
+ while (!HttpInstance->IsRxDone && ((Timeout == NULL) || EFI_ERROR (gBS->CheckEvent (Timeout)))) {
+ Tcp6->Poll (Tcp6);
+ }
+
+ if (!HttpInstance->IsRxDone) {
+ //
+ // Cancle the Token before close its Event.
+ //
+ Tcp6->Cancel (HttpInstance->Tcp6, &Rx6Token->CompletionToken);
+ gBS->CloseEvent (Rx6Token->CompletionToken.Event);
+ Rx6Token->CompletionToken.Status = EFI_TIMEOUT;
+ }
+
+ Status = Rx6Token->CompletionToken.Status;
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Fragment.Len = Rx6Token->Packet.RxData->FragmentTable[0].FragmentLength;
+ Fragment.Bulk = (UINT8 *) Rx6Token->Packet.RxData->FragmentTable[0].FragmentBuffer;
+ } else {
+ if (Fragment.Bulk != NULL) {
+ FreePool (Fragment.Bulk);
+ Fragment.Bulk = NULL;
+ }
+
+ Status = HttpsReceive (HttpInstance, &Fragment, Timeout);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "Tcp6 receive failed: %r\n", Status));
+ return Status;
+ }
+ }
+
+ //
+ // Append the response string.
+ //
+ *BufferSize = *SizeofHeaders + Fragment.Len;
+ Buffer = AllocateZeroPool (*BufferSize);
+ if (Buffer == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ return Status;
+ }
+
+ if (*HttpHeaders != NULL) {
+ CopyMem (Buffer, *HttpHeaders, *SizeofHeaders);
+ FreePool (*HttpHeaders);
+ }
+
+ CopyMem (
+ Buffer + *SizeofHeaders,
+ Fragment.Bulk,
+ Fragment.Len
+ );
+ *HttpHeaders = Buffer;
+ *SizeofHeaders = *BufferSize;
+
+ //
+ // Check whether we received end of HTTP headers.
+ //
+ *EndofHeader = AsciiStrStr (*HttpHeaders, HTTP_END_OF_HDR_STR);
+ };
+
+ //
+ // Free the buffer.
+ //
+ if (Rx6Token != NULL && Rx6Token->Packet.RxData != NULL && Rx6Token->Packet.RxData->FragmentTable[0].FragmentBuffer != NULL) {
+ FreePool (Rx6Token->Packet.RxData->FragmentTable[0].FragmentBuffer);
+ Rx6Token->Packet.RxData->FragmentTable[0].FragmentBuffer = NULL;
+ Fragment.Bulk = NULL;
+ }
+
+ if (Fragment.Bulk != NULL) {
+ FreePool (Fragment.Bulk);
+ Fragment.Bulk = NULL;
+ }
+ }
+
+ //
+ // Skip the CRLF after the HTTP headers.
+ //
+ *EndofHeader = *EndofHeader + AsciiStrLen (HTTP_END_OF_HDR_STR);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Receive the HTTP body by processing the associated HTTP token.
+
+ @param[in] Wrap The HTTP token's wrap data.
+ @param[in] HttpMsg The HTTP message data.
+
+ @retval EFI_SUCCESS The HTTP body is received.
+ @retval Others Other error as indicated.
+
+**/
+EFI_STATUS
+HttpTcpReceiveBody (
+ IN HTTP_TOKEN_WRAP *Wrap,
+ IN EFI_HTTP_MESSAGE *HttpMsg
+ )
+{
+ EFI_STATUS Status;
+ HTTP_PROTOCOL *HttpInstance;
+ EFI_TCP6_PROTOCOL *Tcp6;
+ EFI_TCP6_IO_TOKEN *Rx6Token;
+ EFI_TCP4_PROTOCOL *Tcp4;
+ EFI_TCP4_IO_TOKEN *Rx4Token;
+
+ HttpInstance = Wrap->HttpInstance;
+ Tcp4 = HttpInstance->Tcp4;
+ Tcp6 = HttpInstance->Tcp6;
+ Rx4Token = NULL;
+ Rx6Token = NULL;
+
+ if (HttpInstance->LocalAddressIsIPv6) {
+ ASSERT (Tcp6 != NULL);
+ } else {
+ ASSERT (Tcp4 != NULL);
+ }
+
+ if (HttpInstance->LocalAddressIsIPv6) {
+ Rx6Token = &Wrap->TcpWrap.Rx6Token;
+ Rx6Token ->Packet.RxData->DataLength = (UINT32) HttpMsg->BodyLength;
+ Rx6Token ->Packet.RxData->FragmentTable[0].FragmentLength = (UINT32) HttpMsg->BodyLength;
+ Rx6Token ->Packet.RxData->FragmentTable[0].FragmentBuffer = (VOID *) HttpMsg->Body;
+ Rx6Token->CompletionToken.Status = EFI_NOT_READY;
+
+ Status = Tcp6->Receive (Tcp6, Rx6Token);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "Tcp6 receive failed: %r\n", Status));
+ return Status;
+ }
+ } else {
+ Rx4Token = &Wrap->TcpWrap.Rx4Token;
+ Rx4Token->Packet.RxData->DataLength = (UINT32) HttpMsg->BodyLength;
+ Rx4Token->Packet.RxData->FragmentTable[0].FragmentLength = (UINT32) HttpMsg->BodyLength;
+ Rx4Token->Packet.RxData->FragmentTable[0].FragmentBuffer = (VOID *) HttpMsg->Body;
+
+ Rx4Token->CompletionToken.Status = EFI_NOT_READY;
+ Status = Tcp4->Receive (Tcp4, Rx4Token);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "Tcp4 receive failed: %r\n", Status));
+ return Status;
+ }
+ }
+
+ return EFI_SUCCESS;
+
+}
+
+/**
+ Clean up Tcp Tokens while the Tcp transmission error occurs.
+
+ @param[in] Wrap Pointer to HTTP token's wrap data.
+
+**/
+VOID
+HttpTcpTokenCleanup (
+ IN HTTP_TOKEN_WRAP *Wrap
+ )
+{
+ HTTP_PROTOCOL *HttpInstance;
+ EFI_TCP4_IO_TOKEN *Rx4Token;
+ EFI_TCP6_IO_TOKEN *Rx6Token;
+
+ ASSERT (Wrap != NULL);
+ HttpInstance = Wrap->HttpInstance;
+ Rx4Token = NULL;
+ Rx6Token = NULL;
+
+ if (HttpInstance->LocalAddressIsIPv6) {
+ Rx6Token = &Wrap->TcpWrap.Rx6Token;
+
+ if (Rx6Token->CompletionToken.Event != NULL) {
+ gBS->CloseEvent (Rx6Token->CompletionToken.Event);
+ Rx6Token->CompletionToken.Event = NULL;
+ }
+
+ FreePool (Wrap);
+
+ Rx6Token = &HttpInstance->Rx6Token;
+
+ if (Rx6Token->CompletionToken.Event != NULL) {
+ gBS->CloseEvent (Rx6Token->CompletionToken.Event);
+ Rx6Token->CompletionToken.Event = NULL;
+ }
+
+ if (Rx6Token->Packet.RxData->FragmentTable[0].FragmentBuffer != NULL) {
+ FreePool (Rx6Token->Packet.RxData->FragmentTable[0].FragmentBuffer);
+ Rx6Token->Packet.RxData->FragmentTable[0].FragmentBuffer = NULL;
+ }
+
+ } else {
+ Rx4Token = &Wrap->TcpWrap.Rx4Token;
+
+ if (Rx4Token->CompletionToken.Event != NULL) {
+ gBS->CloseEvent (Rx4Token->CompletionToken.Event);
+ Rx4Token->CompletionToken.Event = NULL;
+ }
+
+ FreePool (Wrap);
+
+ Rx4Token = &HttpInstance->Rx4Token;
+
+ if (Rx4Token->CompletionToken.Event != NULL) {
+ gBS->CloseEvent (Rx4Token->CompletionToken.Event);
+ Rx4Token->CompletionToken.Event = NULL;
+ }
+
+
+ if (Rx4Token->Packet.RxData->FragmentTable[0].FragmentBuffer != NULL) {
+ FreePool (Rx4Token->Packet.RxData->FragmentTable[0].FragmentBuffer);
+ Rx4Token->Packet.RxData->FragmentTable[0].FragmentBuffer = NULL;
+ }
+ }
+
+}
diff --git a/Core/NetworkPkg/HttpDxe/HttpProto.h b/Core/NetworkPkg/HttpDxe/HttpProto.h
new file mode 100644
index 0000000000..95fb4843ce
--- /dev/null
+++ b/Core/NetworkPkg/HttpDxe/HttpProto.h
@@ -0,0 +1,606 @@
+/** @file
+ The header files of miscellaneous routines for HttpDxe driver.
+
+Copyright (c) 2015 - 2017, Intel Corporation. All rights reserved.<BR>
+(C) Copyright 2016 Hewlett Packard Enterprise Development LP<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef __EFI_HTTP_PROTO_H__
+#define __EFI_HTTP_PROTO_H__
+
+#define DEF_BUF_LEN 2048
+
+#define HTTP_SERVICE_SIGNATURE SIGNATURE_32('H', 't', 't', 'S')
+
+#define HTTP_SERVICE_FROM_PROTOCOL(a) \
+ CR ( \
+ (a), \
+ HTTP_SERVICE, \
+ ServiceBinding, \
+ HTTP_SERVICE_SIGNATURE \
+ )
+
+
+//
+// The state of HTTP protocol. It starts from UNCONFIGED.
+//
+#define HTTP_STATE_UNCONFIGED 0
+#define HTTP_STATE_HTTP_CONFIGED 1
+#define HTTP_STATE_TCP_CONFIGED 2
+#define HTTP_STATE_TCP_UNCONFIGED 3
+#define HTTP_STATE_TCP_CONNECTED 4
+#define HTTP_STATE_TCP_CLOSED 5
+
+//
+// TCP configured data.
+//
+#define HTTP_TOS_DEAULT 8
+#define HTTP_TTL_DEAULT 255
+#define HTTP_BUFFER_SIZE_DEAULT 65535
+#define HTTP_MAX_SYN_BACK_LOG 5
+#define HTTP_CONNECTION_TIMEOUT 60
+#define HTTP_RESPONSE_TIMEOUT 5
+#define HTTP_DATA_RETRIES 12
+#define HTTP_FIN_TIMEOUT 2
+#define HTTP_KEEP_ALIVE_PROBES 6
+#define HTTP_KEEP_ALIVE_TIME 7200
+#define HTTP_KEEP_ALIVE_INTERVAL 30
+
+#define HTTP_URL_BUFFER_LEN 4096
+
+typedef struct _HTTP_SERVICE {
+ UINT32 Signature;
+ EFI_SERVICE_BINDING_PROTOCOL ServiceBinding;
+ EFI_HANDLE Ip4DriverBindingHandle;
+ EFI_HANDLE Ip6DriverBindingHandle;
+ EFI_HANDLE ControllerHandle;
+ EFI_HANDLE Tcp4ChildHandle;
+ EFI_HANDLE Tcp6ChildHandle;
+ LIST_ENTRY ChildrenList;
+ UINTN ChildrenNumber;
+ INTN State;
+} HTTP_SERVICE;
+
+typedef struct {
+ EFI_TCP4_IO_TOKEN Tx4Token;
+ EFI_TCP4_TRANSMIT_DATA Tx4Data;
+ EFI_TCP6_IO_TOKEN Tx6Token;
+ EFI_TCP6_TRANSMIT_DATA Tx6Data;
+ EFI_TCP4_IO_TOKEN Rx4Token;
+ EFI_TCP4_RECEIVE_DATA Rx4Data;
+ EFI_TCP6_IO_TOKEN Rx6Token;
+ EFI_TCP6_RECEIVE_DATA Rx6Data;
+ BOOLEAN IsTxDone;
+ BOOLEAN IsRxDone;
+ UINTN BodyLen;
+ EFI_HTTP_METHOD Method;
+} HTTP_TCP_TOKEN_WRAP;
+
+typedef struct {
+ EFI_TLS_VERSION Version;
+ EFI_TLS_CONNECTION_END ConnectionEnd;
+ EFI_TLS_VERIFY VerifyMethod;
+ EFI_TLS_SESSION_STATE SessionState;
+} TLS_CONFIG_DATA;
+
+typedef struct _HTTP_PROTOCOL {
+ UINT32 Signature;
+ EFI_HTTP_PROTOCOL Http;
+ EFI_HANDLE Handle;
+ HTTP_SERVICE *Service;
+ LIST_ENTRY Link; // Link to all HTTP instance from the service.
+ BOOLEAN InDestroy;
+ INTN State;
+ EFI_HTTP_METHOD Method;
+
+ UINTN StatusCode;
+
+ EFI_EVENT TimeoutEvent;
+
+ EFI_HANDLE Tcp4ChildHandle;
+ EFI_TCP4_PROTOCOL *Tcp4;
+ EFI_TCP4_CONFIG_DATA Tcp4CfgData;
+ EFI_TCP4_OPTION Tcp4Option;
+
+ EFI_TCP4_CONNECTION_TOKEN Tcp4ConnToken;
+ BOOLEAN IsTcp4ConnDone;
+ EFI_TCP4_CLOSE_TOKEN Tcp4CloseToken;
+ BOOLEAN IsTcp4CloseDone;
+ CHAR8 *RemoteHost;
+ UINT16 RemotePort;
+ EFI_IPv4_ADDRESS RemoteAddr;
+
+ EFI_HANDLE Tcp6ChildHandle;
+ EFI_TCP6_PROTOCOL *Tcp6;
+ EFI_TCP6_CONFIG_DATA Tcp6CfgData;
+ EFI_TCP6_OPTION Tcp6Option;
+
+ EFI_TCP6_CONNECTION_TOKEN Tcp6ConnToken;
+ BOOLEAN IsTcp6ConnDone;
+ EFI_TCP6_CLOSE_TOKEN Tcp6CloseToken;
+ BOOLEAN IsTcp6CloseDone;
+ EFI_IPv6_ADDRESS RemoteIpv6Addr;
+
+ //
+ // Rx4Token or Rx6Token used for receiving HTTP header.
+ //
+ EFI_TCP4_IO_TOKEN Rx4Token;
+ EFI_TCP4_RECEIVE_DATA Rx4Data;
+ EFI_TCP6_IO_TOKEN Rx6Token;
+ EFI_TCP6_RECEIVE_DATA Rx6Data;
+ BOOLEAN IsRxDone;
+
+ CHAR8 **EndofHeader;
+ CHAR8 **HttpHeaders;
+ CHAR8 *CacheBody;
+ CHAR8 *NextMsg;
+ UINTN CacheLen;
+ UINTN CacheOffset;
+
+ //
+ // HTTP message-body parser.
+ //
+ VOID *MsgParser;
+
+ EFI_HTTP_VERSION HttpVersion;
+ UINT32 TimeOutMillisec;
+ BOOLEAN LocalAddressIsIPv6;
+
+ EFI_HTTPv4_ACCESS_POINT IPv4Node;
+ EFI_HTTPv6_ACCESS_POINT Ipv6Node;
+
+ NET_MAP TxTokens;
+ NET_MAP RxTokens;
+
+ CHAR8 *Url;
+
+ //
+ // Https Support
+ //
+ BOOLEAN UseHttps;
+
+ EFI_HANDLE TlsChildHandle; /// Tls ChildHandle
+ TLS_CONFIG_DATA TlsConfigData;
+ EFI_TLS_PROTOCOL *Tls;
+ EFI_TLS_CONFIGURATION_PROTOCOL *TlsConfiguration;
+ EFI_TLS_SESSION_STATE TlsSessionState;
+
+ //
+ // TlsTxData used for transmitting TLS related messages.
+ //
+ EFI_TCP4_IO_TOKEN Tcp4TlsTxToken;
+ EFI_TCP4_TRANSMIT_DATA Tcp4TlsTxData;
+ EFI_TCP6_IO_TOKEN Tcp6TlsTxToken;
+ EFI_TCP6_TRANSMIT_DATA Tcp6TlsTxData;
+ BOOLEAN TlsIsTxDone;
+
+ //
+ // TlsRxData used for receiving TLS related messages.
+ //
+ EFI_TCP4_IO_TOKEN Tcp4TlsRxToken;
+ EFI_TCP4_RECEIVE_DATA Tcp4TlsRxData;
+ EFI_TCP6_IO_TOKEN Tcp6TlsRxToken;
+ EFI_TCP6_RECEIVE_DATA Tcp6TlsRxData;
+ BOOLEAN TlsIsRxDone;
+} HTTP_PROTOCOL;
+
+typedef struct {
+ EFI_HTTP_TOKEN *HttpToken;
+ HTTP_PROTOCOL *HttpInstance;
+ HTTP_TCP_TOKEN_WRAP TcpWrap;
+} HTTP_TOKEN_WRAP;
+
+
+#define HTTP_PROTOCOL_SIGNATURE SIGNATURE_32('H', 't', 't', 'P')
+
+#define HTTP_INSTANCE_FROM_PROTOCOL(a) \
+ CR ( \
+ (a), \
+ HTTP_PROTOCOL, \
+ Http, \
+ HTTP_PROTOCOL_SIGNATURE \
+ )
+
+/**
+ The common notify function used in HTTP driver.
+
+ @param[in] Event The event signaled.
+ @param[in] Context The context.
+
+**/
+VOID
+EFIAPI
+HttpCommonNotify (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ );
+
+/**
+ Create events for the TCP connection token and TCP close token.
+
+ @param[in] HttpInstance Pointer to HTTP_PROTOCOL structure.
+
+ @retval EFI_SUCCESS The events are created successfully.
+ @retval others Other error as indicated.
+
+**/
+EFI_STATUS
+HttpCreateTcpConnCloseEvent (
+ IN HTTP_PROTOCOL *HttpInstance
+ );
+
+/**
+ Close events in the TCP connection token and TCP close token.
+
+ @param[in] HttpInstance Pointer to HTTP_PROTOCOL structure.
+
+**/
+VOID
+HttpCloseTcpConnCloseEvent (
+ IN HTTP_PROTOCOL *HttpInstance
+ );
+
+/**
+ Create event for the TCP transmit token.
+
+ @param[in] Wrap Point to HTTP token's wrap data.
+
+ @retval EFI_SUCCESS The events is created successfully.
+ @retval others Other error as indicated.
+
+**/
+EFI_STATUS
+HttpCreateTcpTxEvent (
+ IN HTTP_TOKEN_WRAP *Wrap
+ );
+
+/**
+ Create event for the TCP receive token which is used to receive HTTP header.
+
+ @param[in] HttpInstance Pointer to HTTP_PROTOCOL structure.
+
+ @retval EFI_SUCCESS The events is created successfully.
+ @retval others Other error as indicated.
+
+**/
+EFI_STATUS
+HttpCreateTcpRxEventForHeader (
+ IN HTTP_PROTOCOL *HttpInstance
+ );
+
+/**
+ Create event for the TCP receive token which is used to receive HTTP body.
+
+ @param[in] Wrap Point to HTTP token's wrap data.
+
+ @retval EFI_SUCCESS The events is created successfully.
+ @retval others Other error as indicated.
+
+**/
+EFI_STATUS
+HttpCreateTcpRxEvent (
+ IN HTTP_TOKEN_WRAP *Wrap
+ );
+
+/**
+ Close Events for Tcp Receive Tokens for HTTP body and HTTP header.
+
+ @param[in] Wrap Pointer to HTTP token's wrap data.
+
+**/
+VOID
+HttpCloseTcpRxEvent (
+ IN HTTP_TOKEN_WRAP *Wrap
+ );
+
+/**
+ Intiialize the HTTP_PROTOCOL structure to the unconfigured state.
+
+ @param[in, out] HttpInstance Pointer to HTTP_PROTOCOL structure.
+ @param[in] IpVersion Indicate us TCP4 protocol or TCP6 protocol.
+
+ @retval EFI_SUCCESS HTTP_PROTOCOL structure is initialized successfully.
+ @retval Others Other error as indicated.
+
+**/
+EFI_STATUS
+HttpInitProtocol (
+ IN OUT HTTP_PROTOCOL *HttpInstance,
+ IN BOOLEAN IpVersion
+ );
+
+/**
+ Clean up the HTTP child, release all the resources used by it.
+
+ @param[in] HttpInstance The HTTP child to clean up.
+
+**/
+VOID
+HttpCleanProtocol (
+ IN HTTP_PROTOCOL *HttpInstance
+ );
+
+/**
+ Establish TCP connection with HTTP server.
+
+ @param[in] HttpInstance The HTTP instance private data.
+
+ @retval EFI_SUCCESS The TCP connection is established.
+ @retval Others Other error as indicated.
+
+**/
+EFI_STATUS
+HttpCreateConnection (
+ IN HTTP_PROTOCOL *HttpInstance
+ );
+
+/**
+ Close existing TCP connection.
+
+ @param[in] HttpInstance The HTTP instance private data.
+
+ @retval EFI_SUCCESS The TCP connection is closed.
+ @retval Others Other error as indicated.
+
+**/
+EFI_STATUS
+HttpCloseConnection (
+ IN HTTP_PROTOCOL *HttpInstance
+ );
+
+/**
+ Configure TCP4 protocol child.
+
+ @param[in] HttpInstance The HTTP instance private data.
+ @param[in] Wrap The HTTP token's wrap data.
+
+ @retval EFI_SUCCESS The TCP4 protocol child is configured.
+ @retval Others Other error as indicated.
+
+**/
+EFI_STATUS
+HttpConfigureTcp4 (
+ IN HTTP_PROTOCOL *HttpInstance,
+ IN HTTP_TOKEN_WRAP *Wrap
+ );
+
+/**
+ Configure TCP6 protocol child.
+
+ @param[in] HttpInstance The HTTP instance private data.
+ @param[in] Wrap The HTTP token's wrap data.
+
+ @retval EFI_SUCCESS The TCP6 protocol child is configured.
+ @retval Others Other error as indicated.
+
+**/
+EFI_STATUS
+HttpConfigureTcp6 (
+ IN HTTP_PROTOCOL *HttpInstance,
+ IN HTTP_TOKEN_WRAP *Wrap
+ );
+
+/**
+ Check existing TCP connection, if in error state, recover TCP4 connection. Then,
+ connect one TLS session if required.
+
+ @param[in] HttpInstance The HTTP instance private data.
+
+ @retval EFI_SUCCESS The TCP connection is established.
+ @retval EFI_NOT_READY TCP4 protocol child is not created or configured.
+ @retval Others Other error as indicated.
+
+**/
+EFI_STATUS
+HttpConnectTcp4 (
+ IN HTTP_PROTOCOL *HttpInstance
+ );
+
+/**
+ Check existing TCP connection, if in error state, recover TCP6 connection. Then,
+ connect one TLS session if required.
+
+ @param[in] HttpInstance The HTTP instance private data.
+
+ @retval EFI_SUCCESS The TCP connection is established.
+ @retval EFI_NOT_READY TCP6 protocol child is not created or configured.
+ @retval Others Other error as indicated.
+
+**/
+EFI_STATUS
+HttpConnectTcp6 (
+ IN HTTP_PROTOCOL *HttpInstance
+ );
+
+/**
+ Send the HTTP or HTTPS message through TCP4 or TCP6.
+
+ @param[in] HttpInstance The HTTP instance private data.
+ @param[in] Wrap The HTTP token's wrap data.
+ @param[in] TxString Buffer containing the HTTP message string.
+ @param[in] TxStringLen Length of the HTTP message string in bytes.
+
+ @retval EFI_SUCCESS The HTTP message is queued into TCP transmit queue.
+ @retval Others Other error as indicated.
+
+**/
+EFI_STATUS
+HttpTransmitTcp (
+ IN HTTP_PROTOCOL *HttpInstance,
+ IN HTTP_TOKEN_WRAP *Wrap,
+ IN UINT8 *TxString,
+ IN UINTN TxStringLen
+ );
+
+/**
+ Check whether the user's token or event has already
+ been enqueue on HTTP Tx or Rx Token list.
+
+ @param[in] Map The container of either user's transmit or receive
+ token.
+ @param[in] Item Current item to check against.
+ @param[in] Context The Token to check againist.
+
+ @retval EFI_ACCESS_DENIED The token or event has already been enqueued in IP
+ @retval EFI_SUCCESS The current item isn't the same token/event as the
+ context.
+
+**/
+EFI_STATUS
+EFIAPI
+HttpTokenExist (
+ IN NET_MAP *Map,
+ IN NET_MAP_ITEM *Item,
+ IN VOID *Context
+ );
+
+/**
+ Check whether the HTTP message associated with TxToken or Tx6Token is already sent out.
+
+ @param[in] Map The container of TxToken.
+ @param[in] Item Current item to check against.
+ @param[in] Context The Token to check againist.
+
+ @retval EFI_NOT_READY The HTTP message is still queued in the list.
+ @retval EFI_SUCCESS The HTTP message has been sent out.
+
+**/
+EFI_STATUS
+EFIAPI
+HttpTcpNotReady (
+ IN NET_MAP *Map,
+ IN NET_MAP_ITEM *Item,
+ IN VOID *Context
+ );
+
+/**
+ Initialize Http session.
+
+ @param[in] HttpInstance The HTTP instance private data.
+ @param[in] Wrap The HTTP token's wrap data.
+ @param[in] Configure The Flag indicates whether need to initialize session.
+ @param[in] TlsConfigure The Flag indicates whether it's the new Tls session.
+
+ @retval EFI_SUCCESS The initialization of session is done.
+ @retval Others Other error as indicated.
+
+**/
+EFI_STATUS
+HttpInitSession (
+ IN HTTP_PROTOCOL *HttpInstance,
+ IN HTTP_TOKEN_WRAP *Wrap,
+ IN BOOLEAN Configure,
+ IN BOOLEAN TlsConfigure
+ );
+
+/**
+ Transmit the HTTP or HTTPS mssage by processing the associated HTTP token.
+
+ @param[in] Map The container of TxToken or Tx6Token.
+ @param[in] Item Current item to check against.
+ @param[in] Context The Token to check againist.
+
+ @retval EFI_OUT_OF_RESOURCES Failed to allocate resources.
+ @retval EFI_SUCCESS The HTTP message is queued into TCP transmit
+ queue.
+
+**/
+EFI_STATUS
+EFIAPI
+HttpTcpTransmit (
+ IN NET_MAP *Map,
+ IN NET_MAP_ITEM *Item,
+ IN VOID *Context
+ );
+
+/**
+ Receive the HTTP response by processing the associated HTTP token.
+
+ @param[in] Map The container of Rx4Token or Rx6Token.
+ @param[in] Item Current item to check against.
+ @param[in] Context The Token to check againist.
+
+ @retval EFI_SUCCESS The HTTP response is queued into TCP receive
+ queue.
+ @retval Others Other error as indicated.
+
+**/
+EFI_STATUS
+EFIAPI
+HttpTcpReceive (
+ IN NET_MAP *Map,
+ IN NET_MAP_ITEM *Item,
+ IN VOID *Context
+ );
+
+/**
+ Receive the HTTP header by processing the associated HTTP token.
+
+ @param[in] HttpInstance The HTTP instance private data.
+ @param[in, out] SizeofHeaders The HTTP header length.
+ @param[in, out] BufferSize The size of buffer to cacahe the header message.
+ @param[in] Timeout The time to wait for receiving the header packet.
+
+ @retval EFI_SUCCESS The HTTP header is received.
+ @retval Others Other errors as indicated.
+
+**/
+EFI_STATUS
+HttpTcpReceiveHeader (
+ IN HTTP_PROTOCOL *HttpInstance,
+ IN OUT UINTN *SizeofHeaders,
+ IN OUT UINTN *BufferSize,
+ IN EFI_EVENT Timeout
+ );
+
+/**
+ Receive the HTTP body by processing the associated HTTP token.
+
+ @param[in] Wrap The HTTP token's wrap data.
+ @param[in] HttpMsg The HTTP message data.
+
+ @retval EFI_SUCCESS The HTTP body is received.
+ @retval Others Other error as indicated.
+
+**/
+EFI_STATUS
+HttpTcpReceiveBody (
+ IN HTTP_TOKEN_WRAP *Wrap,
+ IN EFI_HTTP_MESSAGE *HttpMsg
+ );
+
+/**
+ Clean up Tcp Tokens while the Tcp transmission error occurs.
+
+ @param[in] Wrap Pointer to HTTP token's wrap data.
+
+**/
+VOID
+HttpTcpTokenCleanup (
+ IN HTTP_TOKEN_WRAP *Wrap
+ );
+
+/**
+ The work function of EfiHttpResponse().
+
+ @param[in] Wrap Pointer to HTTP token's wrap data.
+
+ @retval EFI_SUCCESS Allocation succeeded.
+ @retval EFI_OUT_OF_RESOURCES Failed to complete the opration due to lack of resources.
+ @retval EFI_NOT_READY Can't find a corresponding TxToken.
+
+**/
+EFI_STATUS
+HttpResponseWorker (
+ IN HTTP_TOKEN_WRAP *Wrap
+ );
+
+#endif
diff --git a/Core/NetworkPkg/HttpDxe/HttpsSupport.c b/Core/NetworkPkg/HttpDxe/HttpsSupport.c
new file mode 100644
index 0000000000..e4d9a37bee
--- /dev/null
+++ b/Core/NetworkPkg/HttpDxe/HttpsSupport.c
@@ -0,0 +1,1720 @@
+/** @file
+ Miscellaneous routines specific to Https for HttpDxe driver.
+
+Copyright (c) 2016 - 2017, Intel Corporation. All rights reserved.<BR>
+(C) Copyright 2016 Hewlett Packard Enterprise Development LP<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "HttpDriver.h"
+
+/**
+ Returns the first occurrence of a Null-terminated ASCII sub-string in a Null-terminated
+ ASCII string and ignore case during the search process.
+
+ This function scans the contents of the ASCII string specified by String
+ and returns the first occurrence of SearchString and ignore case during the search process.
+ If SearchString is not found in String, then NULL is returned. If the length of SearchString
+ is zero, then String is returned.
+
+ If String is NULL, then ASSERT().
+ If SearchString is NULL, then ASSERT().
+
+ @param[in] String A pointer to a Null-terminated ASCII string.
+ @param[in] SearchString A pointer to a Null-terminated ASCII string to search for.
+
+ @retval NULL If the SearchString does not appear in String.
+ @retval others If there is a match return the first occurrence of SearchingString.
+ If the length of SearchString is zero,return String.
+
+**/
+CHAR8 *
+AsciiStrCaseStr (
+ IN CONST CHAR8 *String,
+ IN CONST CHAR8 *SearchString
+ )
+{
+ CONST CHAR8 *FirstMatch;
+ CONST CHAR8 *SearchStringTmp;
+
+ CHAR8 Src;
+ CHAR8 Dst;
+
+ //
+ // ASSERT both strings are less long than PcdMaximumAsciiStringLength
+ //
+ ASSERT (AsciiStrSize (String) != 0);
+ ASSERT (AsciiStrSize (SearchString) != 0);
+
+ if (*SearchString == '\0') {
+ return (CHAR8 *) String;
+ }
+
+ while (*String != '\0') {
+ SearchStringTmp = SearchString;
+ FirstMatch = String;
+
+ while ((*SearchStringTmp != '\0')
+ && (*String != '\0')) {
+ Src = *String;
+ Dst = *SearchStringTmp;
+
+ if ((Src >= 'A') && (Src <= 'Z')) {
+ Src -= ('A' - 'a');
+ }
+
+ if ((Dst >= 'A') && (Dst <= 'Z')) {
+ Dst -= ('A' - 'a');
+ }
+
+ if (Src != Dst) {
+ break;
+ }
+
+ String++;
+ SearchStringTmp++;
+ }
+
+ if (*SearchStringTmp == '\0') {
+ return (CHAR8 *) FirstMatch;
+ }
+
+ String = FirstMatch + 1;
+ }
+
+ return NULL;
+}
+
+/**
+ The callback function to free the net buffer list.
+
+ @param[in] Arg The opaque parameter.
+
+**/
+VOID
+EFIAPI
+FreeNbufList (
+ IN VOID *Arg
+ )
+{
+ ASSERT (Arg != NULL);
+
+ NetbufFreeList ((LIST_ENTRY *) Arg);
+ FreePool (Arg);
+}
+
+/**
+ Check whether the Url is from Https.
+
+ @param[in] Url The pointer to a HTTP or HTTPS URL string.
+
+ @retval TRUE The Url is from HTTPS.
+ @retval FALSE The Url is from HTTP.
+
+**/
+BOOLEAN
+IsHttpsUrl (
+ IN CHAR8 *Url
+ )
+{
+ CHAR8 *Tmp;
+
+ Tmp = NULL;
+
+ Tmp = AsciiStrCaseStr (Url, HTTPS_FLAG);
+ if (Tmp != NULL && Tmp == Url) {
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+/**
+ Creates a Tls child handle, open EFI_TLS_PROTOCOL and EFI_TLS_CONFIGURATION_PROTOCOL.
+
+ @param[in] ImageHandle The firmware allocated handle for the UEFI image.
+ @param[out] TlsProto Pointer to the EFI_TLS_PROTOCOL instance.
+ @param[out] TlsConfiguration Pointer to the EFI_TLS_CONFIGURATION_PROTOCOL instance.
+
+ @return The child handle with opened EFI_TLS_PROTOCOL and EFI_TLS_CONFIGURATION_PROTOCOL.
+
+**/
+EFI_HANDLE
+EFIAPI
+TlsCreateChild (
+ IN EFI_HANDLE ImageHandle,
+ OUT EFI_TLS_PROTOCOL **TlsProto,
+ OUT EFI_TLS_CONFIGURATION_PROTOCOL **TlsConfiguration
+ )
+{
+ EFI_STATUS Status;
+ EFI_SERVICE_BINDING_PROTOCOL *TlsSb;
+ EFI_HANDLE TlsChildHandle;
+
+ TlsSb = NULL;
+ TlsChildHandle = 0;
+
+ //
+ // Locate TlsServiceBinding protocol.
+ //
+ gBS->LocateProtocol (
+ &gEfiTlsServiceBindingProtocolGuid,
+ NULL,
+ (VOID **) &TlsSb
+ );
+ if (TlsSb == NULL) {
+ return NULL;
+ }
+
+ Status = TlsSb->CreateChild (TlsSb, &TlsChildHandle);
+ if (EFI_ERROR (Status)) {
+ return NULL;
+ }
+
+ Status = gBS->OpenProtocol (
+ TlsChildHandle,
+ &gEfiTlsProtocolGuid,
+ (VOID **) TlsProto,
+ ImageHandle,
+ TlsChildHandle,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+ if (EFI_ERROR (Status)) {
+ TlsSb->DestroyChild (TlsSb, TlsChildHandle);
+ return NULL;
+ }
+
+ Status = gBS->OpenProtocol (
+ TlsChildHandle,
+ &gEfiTlsConfigurationProtocolGuid,
+ (VOID **) TlsConfiguration,
+ ImageHandle,
+ TlsChildHandle,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+ if (EFI_ERROR (Status)) {
+ TlsSb->DestroyChild (TlsSb, TlsChildHandle);
+ return NULL;
+ }
+
+ return TlsChildHandle;
+}
+
+/**
+ Create event for the TLS receive and transmit tokens which are used to receive and
+ transmit TLS related messages.
+
+ @param[in, out] HttpInstance Pointer to HTTP_PROTOCOL structure.
+
+ @retval EFI_SUCCESS The events are created successfully.
+ @retval others Other error as indicated.
+
+**/
+EFI_STATUS
+EFIAPI
+TlsCreateTxRxEvent (
+ IN OUT HTTP_PROTOCOL *HttpInstance
+ )
+{
+ EFI_STATUS Status;
+
+ if (!HttpInstance->LocalAddressIsIPv6) {
+ //
+ // For Tcp4TlsTxToken.
+ //
+ Status = gBS->CreateEvent (
+ EVT_NOTIFY_SIGNAL,
+ TPL_NOTIFY,
+ HttpCommonNotify,
+ &HttpInstance->TlsIsTxDone,
+ &HttpInstance->Tcp4TlsTxToken.CompletionToken.Event
+ );
+ if (EFI_ERROR (Status)) {
+ goto ERROR;
+ }
+
+ HttpInstance->Tcp4TlsTxData.Push = TRUE;
+ HttpInstance->Tcp4TlsTxData.Urgent = FALSE;
+ HttpInstance->Tcp4TlsTxData.DataLength = 0;
+ HttpInstance->Tcp4TlsTxData.FragmentCount = 1;
+ HttpInstance->Tcp4TlsTxData.FragmentTable[0].FragmentLength = HttpInstance->Tcp4TlsTxData.DataLength;
+ HttpInstance->Tcp4TlsTxData.FragmentTable[0].FragmentBuffer = NULL;
+ HttpInstance->Tcp4TlsTxToken.Packet.TxData = &HttpInstance->Tcp4TlsTxData;
+ HttpInstance->Tcp4TlsTxToken.CompletionToken.Status = EFI_NOT_READY;
+
+ //
+ // For Tcp4TlsRxToken.
+ //
+ Status = gBS->CreateEvent (
+ EVT_NOTIFY_SIGNAL,
+ TPL_NOTIFY,
+ HttpCommonNotify,
+ &HttpInstance->TlsIsRxDone,
+ &HttpInstance->Tcp4TlsRxToken.CompletionToken.Event
+ );
+ if (EFI_ERROR (Status)) {
+ goto ERROR;
+ }
+
+ HttpInstance->Tcp4TlsRxData.DataLength = 0;
+ HttpInstance->Tcp4TlsRxData.FragmentCount = 1;
+ HttpInstance->Tcp4TlsRxData.FragmentTable[0].FragmentLength = HttpInstance->Tcp4TlsRxData.DataLength ;
+ HttpInstance->Tcp4TlsRxData.FragmentTable[0].FragmentBuffer = NULL;
+ HttpInstance->Tcp4TlsRxToken.Packet.RxData = &HttpInstance->Tcp4TlsRxData;
+ HttpInstance->Tcp4TlsRxToken.CompletionToken.Status = EFI_NOT_READY;
+ } else {
+ //
+ // For Tcp6TlsTxToken.
+ //
+ Status = gBS->CreateEvent (
+ EVT_NOTIFY_SIGNAL,
+ TPL_NOTIFY,
+ HttpCommonNotify,
+ &HttpInstance->TlsIsTxDone,
+ &HttpInstance->Tcp6TlsTxToken.CompletionToken.Event
+ );
+ if (EFI_ERROR (Status)) {
+ goto ERROR;
+ }
+
+ HttpInstance->Tcp6TlsTxData.Push = TRUE;
+ HttpInstance->Tcp6TlsTxData.Urgent = FALSE;
+ HttpInstance->Tcp6TlsTxData.DataLength = 0;
+ HttpInstance->Tcp6TlsTxData.FragmentCount = 1;
+ HttpInstance->Tcp6TlsTxData.FragmentTable[0].FragmentLength = HttpInstance->Tcp6TlsTxData.DataLength;
+ HttpInstance->Tcp6TlsTxData.FragmentTable[0].FragmentBuffer = NULL;
+ HttpInstance->Tcp6TlsTxToken.Packet.TxData = &HttpInstance->Tcp6TlsTxData;
+ HttpInstance->Tcp6TlsTxToken.CompletionToken.Status = EFI_NOT_READY;
+
+ //
+ // For Tcp6TlsRxToken.
+ //
+ Status = gBS->CreateEvent (
+ EVT_NOTIFY_SIGNAL,
+ TPL_NOTIFY,
+ HttpCommonNotify,
+ &HttpInstance->TlsIsRxDone,
+ &HttpInstance->Tcp6TlsRxToken.CompletionToken.Event
+ );
+ if (EFI_ERROR (Status)) {
+ goto ERROR;
+ }
+
+ HttpInstance->Tcp6TlsRxData.DataLength = 0;
+ HttpInstance->Tcp6TlsRxData.FragmentCount = 1;
+ HttpInstance->Tcp6TlsRxData.FragmentTable[0].FragmentLength = HttpInstance->Tcp6TlsRxData.DataLength ;
+ HttpInstance->Tcp6TlsRxData.FragmentTable[0].FragmentBuffer = NULL;
+ HttpInstance->Tcp6TlsRxToken.Packet.RxData = &HttpInstance->Tcp6TlsRxData;
+ HttpInstance->Tcp6TlsRxToken.CompletionToken.Status = EFI_NOT_READY;
+ }
+
+ return Status;
+
+ERROR:
+ //
+ // Error handling
+ //
+ TlsCloseTxRxEvent (HttpInstance);
+
+ return Status;
+}
+
+/**
+ Close events in the TlsTxToken and TlsRxToken.
+
+ @param[in] HttpInstance Pointer to HTTP_PROTOCOL structure.
+
+**/
+VOID
+EFIAPI
+TlsCloseTxRxEvent (
+ IN HTTP_PROTOCOL *HttpInstance
+ )
+{
+ ASSERT (HttpInstance != NULL);
+ if (!HttpInstance->LocalAddressIsIPv6) {
+ if (NULL != HttpInstance->Tcp4TlsTxToken.CompletionToken.Event) {
+ gBS->CloseEvent(HttpInstance->Tcp4TlsTxToken.CompletionToken.Event);
+ HttpInstance->Tcp4TlsTxToken.CompletionToken.Event = NULL;
+ }
+
+ if (NULL != HttpInstance->Tcp4TlsRxToken.CompletionToken.Event) {
+ gBS->CloseEvent (HttpInstance->Tcp4TlsRxToken.CompletionToken.Event);
+ HttpInstance->Tcp4TlsRxToken.CompletionToken.Event = NULL;
+ }
+ } else {
+ if (NULL != HttpInstance->Tcp6TlsTxToken.CompletionToken.Event) {
+ gBS->CloseEvent(HttpInstance->Tcp6TlsTxToken.CompletionToken.Event);
+ HttpInstance->Tcp6TlsTxToken.CompletionToken.Event = NULL;
+ }
+
+ if (NULL != HttpInstance->Tcp6TlsRxToken.CompletionToken.Event) {
+ gBS->CloseEvent (HttpInstance->Tcp6TlsRxToken.CompletionToken.Event);
+ HttpInstance->Tcp6TlsRxToken.CompletionToken.Event = NULL;
+ }
+ }
+}
+
+/**
+ Read the TlsCaCertificate variable and configure it.
+
+ @param[in, out] HttpInstance The HTTP instance private data.
+
+ @retval EFI_SUCCESS TlsCaCertificate is configured.
+ @retval EFI_OUT_OF_RESOURCES Can't allocate memory resources.
+ @retval EFI_NOT_FOUND Fail to get 'TlsCaCertificate' variable.
+ @retval Others Other error as indicated.
+
+**/
+EFI_STATUS
+TlsConfigCertificate (
+ IN OUT HTTP_PROTOCOL *HttpInstance
+ )
+{
+ EFI_STATUS Status;
+ UINT8 *CACert;
+ UINTN CACertSize;
+ UINT32 Index;
+ EFI_SIGNATURE_LIST *CertList;
+ EFI_SIGNATURE_DATA *Cert;
+ UINTN CertCount;
+ UINT32 ItemDataSize;
+
+ CACert = NULL;
+ CACertSize = 0;
+
+ //
+ // Try to read the TlsCaCertificate variable.
+ //
+ Status = gRT->GetVariable (
+ EFI_TLS_CA_CERTIFICATE_VARIABLE,
+ &gEfiTlsCaCertificateGuid,
+ NULL,
+ &CACertSize,
+ NULL
+ );
+
+ if (EFI_ERROR (Status) && Status != EFI_BUFFER_TOO_SMALL) {
+ return Status;
+ }
+
+ //
+ // Allocate buffer and read the config variable.
+ //
+ CACert = AllocatePool (CACertSize);
+ if (CACert == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ Status = gRT->GetVariable (
+ EFI_TLS_CA_CERTIFICATE_VARIABLE,
+ &gEfiTlsCaCertificateGuid,
+ NULL,
+ &CACertSize,
+ CACert
+ );
+ if (EFI_ERROR (Status)) {
+ //
+ // GetVariable still error or the variable is corrupted.
+ // Fall back to the default value.
+ //
+ FreePool (CACert);
+
+ return EFI_NOT_FOUND;
+ }
+
+ ASSERT (CACert != NULL);
+
+ //
+ // Enumerate all data and erasing the target item.
+ //
+ ItemDataSize = (UINT32) CACertSize;
+ CertList = (EFI_SIGNATURE_LIST *) CACert;
+ while ((ItemDataSize > 0) && (ItemDataSize >= CertList->SignatureListSize)) {
+ Cert = (EFI_SIGNATURE_DATA *) ((UINT8 *) CertList + sizeof (EFI_SIGNATURE_LIST) + CertList->SignatureHeaderSize);
+ CertCount = (CertList->SignatureListSize - sizeof (EFI_SIGNATURE_LIST) - CertList->SignatureHeaderSize) / CertList->SignatureSize;
+ for (Index = 0; Index < CertCount; Index++) {
+ //
+ // EfiTlsConfigDataTypeCACertificate
+ //
+ Status = HttpInstance->TlsConfiguration->SetData (
+ HttpInstance->TlsConfiguration,
+ EfiTlsConfigDataTypeCACertificate,
+ Cert->SignatureData,
+ CertList->SignatureSize - sizeof (Cert->SignatureOwner)
+ );
+ if (EFI_ERROR (Status)) {
+ FreePool (CACert);
+ return Status;
+ }
+
+ Cert = (EFI_SIGNATURE_DATA *) ((UINT8 *) Cert + CertList->SignatureSize);
+ }
+
+ ItemDataSize -= CertList->SignatureListSize;
+ CertList = (EFI_SIGNATURE_LIST *) ((UINT8 *) CertList + CertList->SignatureListSize);
+ }
+
+ FreePool (CACert);
+ return Status;
+}
+
+/**
+ Configure TLS session data.
+
+ @param[in, out] HttpInstance The HTTP instance private data.
+
+ @retval EFI_SUCCESS TLS session data is configured.
+ @retval Others Other error as indicated.
+
+**/
+EFI_STATUS
+EFIAPI
+TlsConfigureSession (
+ IN OUT HTTP_PROTOCOL *HttpInstance
+ )
+{
+ EFI_STATUS Status;
+
+ //
+ // TlsConfigData initialization
+ //
+ HttpInstance->TlsConfigData.ConnectionEnd = EfiTlsClient;
+ HttpInstance->TlsConfigData.VerifyMethod = EFI_TLS_VERIFY_PEER;
+ HttpInstance->TlsConfigData.SessionState = EfiTlsSessionNotStarted;
+
+ //
+ // EfiTlsConnectionEnd,
+ // EfiTlsVerifyMethod
+ // EfiTlsSessionState
+ //
+ Status = HttpInstance->Tls->SetSessionData (
+ HttpInstance->Tls,
+ EfiTlsConnectionEnd,
+ &(HttpInstance->TlsConfigData.ConnectionEnd),
+ sizeof (EFI_TLS_CONNECTION_END)
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = HttpInstance->Tls->SetSessionData (
+ HttpInstance->Tls,
+ EfiTlsVerifyMethod,
+ &HttpInstance->TlsConfigData.VerifyMethod,
+ sizeof (EFI_TLS_VERIFY)
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = HttpInstance->Tls->SetSessionData (
+ HttpInstance->Tls,
+ EfiTlsSessionState,
+ &(HttpInstance->TlsConfigData.SessionState),
+ sizeof (EFI_TLS_SESSION_STATE)
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Tls Config Certificate
+ //
+ Status = TlsConfigCertificate (HttpInstance);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "TLS Certificate Config Error!\n"));
+ return Status;
+ }
+
+ //
+ // TlsCreateTxRxEvent
+ //
+ Status = TlsCreateTxRxEvent (HttpInstance);
+ if (EFI_ERROR (Status)) {
+ goto ERROR;
+ }
+
+ return Status;
+
+ERROR:
+ TlsCloseTxRxEvent (HttpInstance);
+
+ return Status;
+}
+
+/**
+ Transmit the Packet by processing the associated HTTPS token.
+
+ @param[in, out] HttpInstance Pointer to HTTP_PROTOCOL structure.
+ @param[in] Packet The packet to transmit.
+
+ @retval EFI_SUCCESS The packet is transmitted.
+ @retval EFI_INVALID_PARAMETER HttpInstance is NULL or Packet is NULL.
+ @retval EFI_OUT_OF_RESOURCES Can't allocate memory resources.
+ @retval EFI_DEVICE_ERROR An unexpected system or network error occurred.
+ @retval Others Other errors as indicated.
+
+**/
+EFI_STATUS
+EFIAPI
+TlsCommonTransmit (
+ IN OUT HTTP_PROTOCOL *HttpInstance,
+ IN NET_BUF *Packet
+ )
+{
+ EFI_STATUS Status;
+ VOID *Data;
+ UINTN Size;
+
+ if ((HttpInstance == NULL) || (Packet == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (!HttpInstance->LocalAddressIsIPv6) {
+ Size = sizeof (EFI_TCP4_TRANSMIT_DATA) +
+ (Packet->BlockOpNum - 1) * sizeof (EFI_TCP4_FRAGMENT_DATA);
+ } else {
+ Size = sizeof (EFI_TCP6_TRANSMIT_DATA) +
+ (Packet->BlockOpNum - 1) * sizeof (EFI_TCP6_FRAGMENT_DATA);
+ }
+
+ Data = AllocatePool (Size);
+ if (Data == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ if (!HttpInstance->LocalAddressIsIPv6) {
+ ((EFI_TCP4_TRANSMIT_DATA *) Data)->Push = TRUE;
+ ((EFI_TCP4_TRANSMIT_DATA *) Data)->Urgent = FALSE;
+ ((EFI_TCP4_TRANSMIT_DATA *) Data)->DataLength = Packet->TotalSize;
+
+ //
+ // Build the fragment table.
+ //
+ ((EFI_TCP4_TRANSMIT_DATA *) Data)->FragmentCount = Packet->BlockOpNum;
+
+ NetbufBuildExt (
+ Packet,
+ (NET_FRAGMENT *) &((EFI_TCP4_TRANSMIT_DATA *) Data)->FragmentTable[0],
+ &((EFI_TCP4_TRANSMIT_DATA *) Data)->FragmentCount
+ );
+
+ HttpInstance->Tcp4TlsTxToken.Packet.TxData = (EFI_TCP4_TRANSMIT_DATA *) Data;
+
+ Status = EFI_DEVICE_ERROR;
+
+ //
+ // Transmit the packet.
+ //
+ Status = HttpInstance->Tcp4->Transmit (HttpInstance->Tcp4, &HttpInstance->Tcp4TlsTxToken);
+ if (EFI_ERROR (Status)) {
+ goto ON_EXIT;
+ }
+
+ while (!HttpInstance->TlsIsTxDone) {
+ HttpInstance->Tcp4->Poll (HttpInstance->Tcp4);
+ }
+
+ HttpInstance->TlsIsTxDone = FALSE;
+ Status = HttpInstance->Tcp4TlsTxToken.CompletionToken.Status;
+ } else {
+ ((EFI_TCP6_TRANSMIT_DATA *) Data)->Push = TRUE;
+ ((EFI_TCP6_TRANSMIT_DATA *) Data)->Urgent = FALSE;
+ ((EFI_TCP6_TRANSMIT_DATA *) Data)->DataLength = Packet->TotalSize;
+
+ //
+ // Build the fragment table.
+ //
+ ((EFI_TCP6_TRANSMIT_DATA *) Data)->FragmentCount = Packet->BlockOpNum;
+
+ NetbufBuildExt (
+ Packet,
+ (NET_FRAGMENT *) &((EFI_TCP6_TRANSMIT_DATA *) Data)->FragmentTable[0],
+ &((EFI_TCP6_TRANSMIT_DATA *) Data)->FragmentCount
+ );
+
+ HttpInstance->Tcp6TlsTxToken.Packet.TxData = (EFI_TCP6_TRANSMIT_DATA *) Data;
+
+ Status = EFI_DEVICE_ERROR;
+
+ //
+ // Transmit the packet.
+ //
+ Status = HttpInstance->Tcp6->Transmit (HttpInstance->Tcp6, &HttpInstance->Tcp6TlsTxToken);
+ if (EFI_ERROR (Status)) {
+ goto ON_EXIT;
+ }
+
+ while (!HttpInstance->TlsIsTxDone) {
+ HttpInstance->Tcp6->Poll (HttpInstance->Tcp6);
+ }
+
+ HttpInstance->TlsIsTxDone = FALSE;
+ Status = HttpInstance->Tcp6TlsTxToken.CompletionToken.Status;
+ }
+
+ON_EXIT:
+ FreePool (Data);
+
+ return Status;
+}
+
+/**
+ Receive the Packet by processing the associated HTTPS token.
+
+ @param[in, out] HttpInstance Pointer to HTTP_PROTOCOL structure.
+ @param[in] Packet The packet to transmit.
+ @param[in] Timeout The time to wait for connection done.
+
+ @retval EFI_SUCCESS The Packet is received.
+ @retval EFI_INVALID_PARAMETER HttpInstance is NULL or Packet is NULL.
+ @retval EFI_OUT_OF_RESOURCES Can't allocate memory resources.
+ @retval EFI_TIMEOUT The operation is time out.
+ @retval Others Other error as indicated.
+
+**/
+EFI_STATUS
+EFIAPI
+TlsCommonReceive (
+ IN OUT HTTP_PROTOCOL *HttpInstance,
+ IN NET_BUF *Packet,
+ IN EFI_EVENT Timeout
+ )
+{
+ EFI_TCP4_RECEIVE_DATA *Tcp4RxData;
+ EFI_TCP6_RECEIVE_DATA *Tcp6RxData;
+ EFI_STATUS Status;
+ NET_FRAGMENT *Fragment;
+ UINT32 FragmentCount;
+ UINT32 CurrentFragment;
+
+ Tcp4RxData = NULL;
+ Tcp6RxData = NULL;
+
+ if ((HttpInstance == NULL) || (Packet == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ FragmentCount = Packet->BlockOpNum;
+ Fragment = AllocatePool (FragmentCount * sizeof (NET_FRAGMENT));
+ if (Fragment == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto ON_EXIT;
+ }
+
+ //
+ // Build the fragment table.
+ //
+ NetbufBuildExt (Packet, Fragment, &FragmentCount);
+
+ if (!HttpInstance->LocalAddressIsIPv6) {
+ Tcp4RxData = HttpInstance->Tcp4TlsRxToken.Packet.RxData;
+ if (Tcp4RxData == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+ Tcp4RxData->FragmentCount = 1;
+ } else {
+ Tcp6RxData = HttpInstance->Tcp6TlsRxToken.Packet.RxData;
+ if (Tcp6RxData == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+ Tcp6RxData->FragmentCount = 1;
+ }
+
+ CurrentFragment = 0;
+ Status = EFI_SUCCESS;
+
+ while (CurrentFragment < FragmentCount) {
+ if (!HttpInstance->LocalAddressIsIPv6) {
+ Tcp4RxData->DataLength = Fragment[CurrentFragment].Len;
+ Tcp4RxData->FragmentTable[0].FragmentLength = Fragment[CurrentFragment].Len;
+ Tcp4RxData->FragmentTable[0].FragmentBuffer = Fragment[CurrentFragment].Bulk;
+ Status = HttpInstance->Tcp4->Receive (HttpInstance->Tcp4, &HttpInstance->Tcp4TlsRxToken);
+ } else {
+ Tcp6RxData->DataLength = Fragment[CurrentFragment].Len;
+ Tcp6RxData->FragmentTable[0].FragmentLength = Fragment[CurrentFragment].Len;
+ Tcp6RxData->FragmentTable[0].FragmentBuffer = Fragment[CurrentFragment].Bulk;
+ Status = HttpInstance->Tcp6->Receive (HttpInstance->Tcp6, &HttpInstance->Tcp6TlsRxToken);
+ }
+ if (EFI_ERROR (Status)) {
+ goto ON_EXIT;
+ }
+
+ while (!HttpInstance->TlsIsRxDone && ((Timeout == NULL) || EFI_ERROR (gBS->CheckEvent (Timeout)))) {
+ //
+ // Poll until some data is received or an error occurs.
+ //
+ if (!HttpInstance->LocalAddressIsIPv6) {
+ HttpInstance->Tcp4->Poll (HttpInstance->Tcp4);
+ } else {
+ HttpInstance->Tcp6->Poll (HttpInstance->Tcp6);
+ }
+ }
+
+ if (!HttpInstance->TlsIsRxDone) {
+ //
+ // Timeout occurs, cancel the receive request.
+ //
+ if (!HttpInstance->LocalAddressIsIPv6) {
+ HttpInstance->Tcp4->Cancel (HttpInstance->Tcp4, &HttpInstance->Tcp4TlsRxToken.CompletionToken);
+ } else {
+ HttpInstance->Tcp6->Cancel (HttpInstance->Tcp6, &HttpInstance->Tcp6TlsRxToken.CompletionToken);
+ }
+
+ Status = EFI_TIMEOUT;
+ goto ON_EXIT;
+ } else {
+ HttpInstance->TlsIsRxDone = FALSE;
+ }
+
+ if (!HttpInstance->LocalAddressIsIPv6) {
+ Status = HttpInstance->Tcp4TlsRxToken.CompletionToken.Status;
+ if (EFI_ERROR (Status)) {
+ goto ON_EXIT;
+ }
+
+ Fragment[CurrentFragment].Len -= Tcp4RxData->FragmentTable[0].FragmentLength;
+ if (Fragment[CurrentFragment].Len == 0) {
+ CurrentFragment++;
+ } else {
+ Fragment[CurrentFragment].Bulk += Tcp4RxData->FragmentTable[0].FragmentLength;
+ }
+ } else {
+ Status = HttpInstance->Tcp6TlsRxToken.CompletionToken.Status;
+ if (EFI_ERROR (Status)) {
+ goto ON_EXIT;
+ }
+
+ Fragment[CurrentFragment].Len -= Tcp6RxData->FragmentTable[0].FragmentLength;
+ if (Fragment[CurrentFragment].Len == 0) {
+ CurrentFragment++;
+ } else {
+ Fragment[CurrentFragment].Bulk += Tcp6RxData->FragmentTable[0].FragmentLength;
+ }
+ }
+ }
+
+ON_EXIT:
+
+ if (Fragment != NULL) {
+ FreePool (Fragment);
+ }
+
+ return Status;
+}
+
+/**
+ Receive one TLS PDU. An TLS PDU contains an TLS record header and it's
+ corresponding record data. These two parts will be put into two blocks of buffers in the
+ net buffer.
+
+ @param[in, out] HttpInstance Pointer to HTTP_PROTOCOL structure.
+ @param[out] Pdu The received TLS PDU.
+ @param[in] Timeout The time to wait for connection done.
+
+ @retval EFI_SUCCESS An TLS PDU is received.
+ @retval EFI_OUT_OF_RESOURCES Can't allocate memory resources.
+ @retval EFI_PROTOCOL_ERROR An unexpected TLS packet was received.
+ @retval Others Other errors as indicated.
+
+**/
+EFI_STATUS
+EFIAPI
+TlsReceiveOnePdu (
+ IN OUT HTTP_PROTOCOL *HttpInstance,
+ OUT NET_BUF **Pdu,
+ IN EFI_EVENT Timeout
+ )
+{
+ EFI_STATUS Status;
+
+ LIST_ENTRY *NbufList;
+
+ UINT32 Len;
+
+ NET_BUF *PduHdr;
+ UINT8 *Header;
+ TLS_RECORD_HEADER RecordHeader;
+
+ NET_BUF *DataSeg;
+
+ NbufList = NULL;
+ PduHdr = NULL;
+ Header = NULL;
+ DataSeg = NULL;
+
+ NbufList = AllocatePool (sizeof (LIST_ENTRY));
+ if (NbufList == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ InitializeListHead (NbufList);
+
+ //
+ // Allocate buffer to receive one TLS header.
+ //
+ Len = sizeof (TLS_RECORD_HEADER);
+ PduHdr = NetbufAlloc (Len);
+ if (PduHdr == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto ON_EXIT;
+ }
+
+ Header = NetbufAllocSpace (PduHdr, Len, NET_BUF_TAIL);
+ if (Header == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto ON_EXIT;
+ }
+
+ //
+ // First step, receive one TLS header.
+ //
+ Status = TlsCommonReceive (HttpInstance, PduHdr, Timeout);
+ if (EFI_ERROR (Status)) {
+ goto ON_EXIT;
+ }
+
+ RecordHeader = *(TLS_RECORD_HEADER *) Header;
+ if ((RecordHeader.ContentType == TlsContentTypeHandshake ||
+ RecordHeader.ContentType == TlsContentTypeAlert ||
+ RecordHeader.ContentType == TlsContentTypeChangeCipherSpec ||
+ RecordHeader.ContentType == TlsContentTypeApplicationData) &&
+ (RecordHeader.Version.Major == 0x03) && /// Major versions are same.
+ (RecordHeader.Version.Minor == TLS10_PROTOCOL_VERSION_MINOR ||
+ RecordHeader.Version.Minor ==TLS11_PROTOCOL_VERSION_MINOR ||
+ RecordHeader.Version.Minor == TLS12_PROTOCOL_VERSION_MINOR)
+ ) {
+ InsertTailList (NbufList, &PduHdr->List);
+ } else {
+ Status = EFI_PROTOCOL_ERROR;
+ goto ON_EXIT;
+ }
+
+ Len = SwapBytes16(RecordHeader.Length);
+ if (Len == 0) {
+ //
+ // No TLS payload.
+ //
+ goto FORM_PDU;
+ }
+
+ //
+ // Allocate buffer to receive one TLS payload.
+ //
+ DataSeg = NetbufAlloc (Len);
+ if (DataSeg == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto ON_EXIT;
+ }
+
+ NetbufAllocSpace (DataSeg, Len, NET_BUF_TAIL);
+
+ //
+ // Second step, receive one TLS payload.
+ //
+ Status = TlsCommonReceive (HttpInstance, DataSeg, Timeout);
+ if (EFI_ERROR (Status)) {
+ goto ON_EXIT;
+ }
+
+ InsertTailList (NbufList, &DataSeg->List);
+
+FORM_PDU:
+ //
+ // Form the PDU from a list of PDU.
+ //
+ *Pdu = NetbufFromBufList (NbufList, 0, 0, FreeNbufList, NbufList);
+ if (*Pdu == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ }
+
+ON_EXIT:
+
+ if (EFI_ERROR (Status)) {
+ //
+ // Free the Nbufs in this NbufList and the NbufList itself.
+ //
+ FreeNbufList (NbufList);
+ }
+
+ return Status;
+}
+
+/**
+ Connect one TLS session by finishing the TLS handshake process.
+
+ @param[in] HttpInstance The HTTP instance private data.
+ @param[in] Timeout The time to wait for connection done.
+
+ @retval EFI_SUCCESS The TLS session is established.
+ @retval EFI_OUT_OF_RESOURCES Can't allocate memory resources.
+ @retval EFI_ABORTED TLS session state is incorrect.
+ @retval Others Other error as indicated.
+
+**/
+EFI_STATUS
+EFIAPI
+TlsConnectSession (
+ IN HTTP_PROTOCOL *HttpInstance,
+ IN EFI_EVENT Timeout
+ )
+{
+ EFI_STATUS Status;
+ UINT8 *BufferOut;
+ UINTN BufferOutSize;
+ NET_BUF *PacketOut;
+ UINT8 *DataOut;
+ NET_BUF *Pdu;
+ UINT8 *BufferIn;
+ UINTN BufferInSize;
+ UINT8 *GetSessionDataBuffer;
+ UINTN GetSessionDataBufferSize;
+
+ BufferOut = NULL;
+ PacketOut = NULL;
+ DataOut = NULL;
+ Pdu = NULL;
+ BufferIn = NULL;
+
+ //
+ // Initialize TLS state.
+ //
+ HttpInstance->TlsSessionState = EfiTlsSessionNotStarted;
+ Status = HttpInstance->Tls->SetSessionData (
+ HttpInstance->Tls,
+ EfiTlsSessionState,
+ &(HttpInstance->TlsSessionState),
+ sizeof (EFI_TLS_SESSION_STATE)
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Create ClientHello
+ //
+ BufferOutSize = DEF_BUF_LEN;
+ BufferOut = AllocateZeroPool (BufferOutSize);
+ if (BufferOut == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ return Status;
+ }
+
+ Status = HttpInstance->Tls->BuildResponsePacket (
+ HttpInstance->Tls,
+ NULL,
+ 0,
+ BufferOut,
+ &BufferOutSize
+ );
+ if (Status == EFI_BUFFER_TOO_SMALL) {
+ FreePool (BufferOut);
+ BufferOut = AllocateZeroPool (BufferOutSize);
+ if (BufferOut == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ return Status;
+ }
+
+ Status = HttpInstance->Tls->BuildResponsePacket (
+ HttpInstance->Tls,
+ NULL,
+ 0,
+ BufferOut,
+ &BufferOutSize
+ );
+ }
+ if (EFI_ERROR (Status)) {
+ FreePool (BufferOut);
+ return Status;
+ }
+
+ //
+ // Transmit ClientHello
+ //
+ PacketOut = NetbufAlloc ((UINT32) BufferOutSize);
+ DataOut = NetbufAllocSpace (PacketOut, (UINT32) BufferOutSize, NET_BUF_TAIL);
+ if (DataOut == NULL) {
+ FreePool (BufferOut);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ CopyMem (DataOut, BufferOut, BufferOutSize);
+ Status = TlsCommonTransmit (HttpInstance, PacketOut);
+
+ FreePool (BufferOut);
+ NetbufFree (PacketOut);
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ while(HttpInstance->TlsSessionState != EfiTlsSessionDataTransferring && \
+ ((Timeout == NULL) || EFI_ERROR (gBS->CheckEvent (Timeout)))) {
+ //
+ // Receive one TLS record.
+ //
+ Status = TlsReceiveOnePdu (HttpInstance, &Pdu, Timeout);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ BufferInSize = Pdu->TotalSize;
+ BufferIn = AllocateZeroPool (BufferInSize);
+ if (BufferIn == NULL) {
+ NetbufFree (Pdu);
+ Status = EFI_OUT_OF_RESOURCES;
+ return Status;
+ }
+
+ NetbufCopy (Pdu, 0, (UINT32)BufferInSize, BufferIn);
+
+ NetbufFree (Pdu);
+
+ //
+ // Handle Receive data.
+ //
+ BufferOutSize = DEF_BUF_LEN;
+ BufferOut = AllocateZeroPool (BufferOutSize);
+ if (BufferOut == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ return Status;
+ }
+
+ Status = HttpInstance->Tls->BuildResponsePacket (
+ HttpInstance->Tls,
+ BufferIn,
+ BufferInSize,
+ BufferOut,
+ &BufferOutSize
+ );
+ if (Status == EFI_BUFFER_TOO_SMALL) {
+ FreePool (BufferOut);
+ BufferOut = AllocateZeroPool (BufferOutSize);
+ if (BufferOut == NULL) {
+ FreePool (BufferIn);
+ Status = EFI_OUT_OF_RESOURCES;
+ return Status;
+ }
+
+ Status = HttpInstance->Tls->BuildResponsePacket (
+ HttpInstance->Tls,
+ BufferIn,
+ BufferInSize,
+ BufferOut,
+ &BufferOutSize
+ );
+ }
+
+ FreePool (BufferIn);
+
+ if (EFI_ERROR (Status)) {
+ FreePool (BufferOut);
+ return Status;
+ }
+
+ if (BufferOutSize != 0) {
+ //
+ // Transmit the response packet.
+ //
+ PacketOut = NetbufAlloc ((UINT32) BufferOutSize);
+ DataOut = NetbufAllocSpace (PacketOut, (UINT32) BufferOutSize, NET_BUF_TAIL);
+ if (DataOut == NULL) {
+ FreePool (BufferOut);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ CopyMem (DataOut, BufferOut, BufferOutSize);
+
+ Status = TlsCommonTransmit (HttpInstance, PacketOut);
+
+ NetbufFree (PacketOut);
+
+ if (EFI_ERROR (Status)) {
+ FreePool (BufferOut);
+ return Status;
+ }
+ }
+
+ FreePool (BufferOut);
+
+ //
+ // Get the session state, then decide whether need to continue handle received packet.
+ //
+ GetSessionDataBufferSize = DEF_BUF_LEN;
+ GetSessionDataBuffer = AllocateZeroPool (GetSessionDataBufferSize);
+ if (GetSessionDataBuffer == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ return Status;
+ }
+
+ Status = HttpInstance->Tls->GetSessionData (
+ HttpInstance->Tls,
+ EfiTlsSessionState,
+ GetSessionDataBuffer,
+ &GetSessionDataBufferSize
+ );
+ if (Status == EFI_BUFFER_TOO_SMALL) {
+ FreePool (GetSessionDataBuffer);
+ GetSessionDataBuffer = AllocateZeroPool (GetSessionDataBufferSize);
+ if (GetSessionDataBuffer == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ return Status;
+ }
+
+ Status = HttpInstance->Tls->GetSessionData (
+ HttpInstance->Tls,
+ EfiTlsSessionState,
+ GetSessionDataBuffer,
+ &GetSessionDataBufferSize
+ );
+ }
+ if (EFI_ERROR (Status)) {
+ FreePool(GetSessionDataBuffer);
+ return Status;
+ }
+
+ ASSERT(GetSessionDataBufferSize == sizeof (EFI_TLS_SESSION_STATE));
+ HttpInstance->TlsSessionState = *(EFI_TLS_SESSION_STATE *) GetSessionDataBuffer;
+
+ FreePool (GetSessionDataBuffer);
+
+ if(HttpInstance->TlsSessionState == EfiTlsSessionError) {
+ return EFI_ABORTED;
+ }
+ }
+
+ if (HttpInstance->TlsSessionState != EfiTlsSessionDataTransferring) {
+ Status = EFI_ABORTED;
+ }
+
+ return Status;
+}
+
+/**
+ Close the TLS session and send out the close notification message.
+
+ @param[in] HttpInstance The HTTP instance private data.
+
+ @retval EFI_SUCCESS The TLS session is closed.
+ @retval EFI_INVALID_PARAMETER HttpInstance is NULL.
+ @retval EFI_OUT_OF_RESOURCES Can't allocate memory resources.
+ @retval Others Other error as indicated.
+
+**/
+EFI_STATUS
+EFIAPI
+TlsCloseSession (
+ IN HTTP_PROTOCOL *HttpInstance
+ )
+{
+ EFI_STATUS Status;
+
+ UINT8 *BufferOut;
+ UINTN BufferOutSize;
+
+ NET_BUF *PacketOut;
+ UINT8 *DataOut;
+
+ Status = EFI_SUCCESS;
+ BufferOut = NULL;
+ PacketOut = NULL;
+ DataOut = NULL;
+
+ if (HttpInstance == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ HttpInstance->TlsSessionState = EfiTlsSessionClosing;
+
+ Status = HttpInstance->Tls->SetSessionData (
+ HttpInstance->Tls,
+ EfiTlsSessionState,
+ &(HttpInstance->TlsSessionState),
+ sizeof (EFI_TLS_SESSION_STATE)
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ BufferOutSize = DEF_BUF_LEN;
+ BufferOut = AllocateZeroPool (BufferOutSize);
+ if (BufferOut == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ return Status;
+ }
+
+ Status = HttpInstance->Tls->BuildResponsePacket (
+ HttpInstance->Tls,
+ NULL,
+ 0,
+ BufferOut,
+ &BufferOutSize
+ );
+ if (Status == EFI_BUFFER_TOO_SMALL) {
+ FreePool (BufferOut);
+ BufferOut = AllocateZeroPool (BufferOutSize);
+ if (BufferOut == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ return Status;
+ }
+
+ Status = HttpInstance->Tls->BuildResponsePacket (
+ HttpInstance->Tls,
+ NULL,
+ 0,
+ BufferOut,
+ &BufferOutSize
+ );
+ }
+
+ if (EFI_ERROR (Status)) {
+ FreePool (BufferOut);
+ return Status;
+ }
+
+ PacketOut = NetbufAlloc ((UINT32) BufferOutSize);
+ DataOut = NetbufAllocSpace (PacketOut, (UINT32) BufferOutSize, NET_BUF_TAIL);
+ if (DataOut == NULL) {
+ FreePool (BufferOut);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ CopyMem (DataOut, BufferOut, BufferOutSize);
+
+ Status = TlsCommonTransmit (HttpInstance, PacketOut);
+
+ FreePool (BufferOut);
+ NetbufFree (PacketOut);
+
+ return Status;
+}
+
+/**
+ Process one message according to the CryptMode.
+
+ @param[in] HttpInstance Pointer to HTTP_PROTOCOL structure.
+ @param[in] Message Pointer to the message buffer needed to processed.
+ @param[in] MessageSize Pointer to the message buffer size.
+ @param[in] ProcessMode Process mode.
+ @param[in, out] Fragment Only one Fragment returned after the Message is
+ processed successfully.
+
+ @retval EFI_SUCCESS Message is processed successfully.
+ @retval EFI_OUT_OF_RESOURCES Can't allocate memory resources.
+ @retval Others Other errors as indicated.
+
+**/
+EFI_STATUS
+EFIAPI
+TlsProcessMessage (
+ IN HTTP_PROTOCOL *HttpInstance,
+ IN UINT8 *Message,
+ IN UINTN MessageSize,
+ IN EFI_TLS_CRYPT_MODE ProcessMode,
+ IN OUT NET_FRAGMENT *Fragment
+ )
+{
+ EFI_STATUS Status;
+ UINT8 *Buffer;
+ UINT32 BufferSize;
+ UINT32 BytesCopied;
+ EFI_TLS_FRAGMENT_DATA *FragmentTable;
+ UINT32 FragmentCount;
+ EFI_TLS_FRAGMENT_DATA *OriginalFragmentTable;
+ UINTN Index;
+
+ Status = EFI_SUCCESS;
+ Buffer = NULL;
+ BufferSize = 0;
+ BytesCopied = 0;
+ FragmentTable = NULL;
+ OriginalFragmentTable = NULL;
+
+ //
+ // Rebuild fragment table from BufferIn.
+ //
+ FragmentCount = 1;
+ FragmentTable = AllocateZeroPool (FragmentCount * sizeof (EFI_TLS_FRAGMENT_DATA));
+ if (FragmentTable == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto ON_EXIT;
+ }
+
+ FragmentTable->FragmentLength = (UINT32) MessageSize;
+ FragmentTable->FragmentBuffer = Message;
+
+ //
+ // Record the original FragmentTable.
+ //
+ OriginalFragmentTable = FragmentTable;
+
+ //
+ // Process the Message.
+ //
+ Status = HttpInstance->Tls->ProcessPacket (
+ HttpInstance->Tls,
+ &FragmentTable,
+ &FragmentCount,
+ ProcessMode
+ );
+ if (EFI_ERROR (Status)) {
+ goto ON_EXIT;
+ }
+
+ //
+ // Calculate the size according to FragmentTable.
+ //
+ for (Index = 0; Index < FragmentCount; Index++) {
+ BufferSize += FragmentTable[Index].FragmentLength;
+ }
+
+ //
+ // Allocate buffer for processed data.
+ //
+ Buffer = AllocateZeroPool (BufferSize);
+ if (Buffer == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto ON_EXIT;
+ }
+
+ //
+ // Copy the new FragmentTable buffer into Buffer.
+ //
+ for (Index = 0; Index < FragmentCount; Index++) {
+ CopyMem (
+ (Buffer + BytesCopied),
+ FragmentTable[Index].FragmentBuffer,
+ FragmentTable[Index].FragmentLength
+ );
+ BytesCopied += FragmentTable[Index].FragmentLength;
+
+ //
+ // Free the FragmentBuffer since it has been copied.
+ //
+ FreePool (FragmentTable[Index].FragmentBuffer);
+ }
+
+ Fragment->Len = BufferSize;
+ Fragment->Bulk = Buffer;
+
+ON_EXIT:
+
+ if (OriginalFragmentTable != NULL) {
+ FreePool (OriginalFragmentTable);
+ OriginalFragmentTable = NULL;
+ }
+
+ //
+ // Caller has the responsibility to free the FragmentTable.
+ //
+ if (FragmentTable != NULL) {
+ FreePool (FragmentTable);
+ FragmentTable = NULL;
+ }
+
+ return Status;
+}
+
+/**
+ Receive one fragment decrypted from one TLS record.
+
+ @param[in] HttpInstance Pointer to HTTP_PROTOCOL structure.
+ @param[in, out] Fragment The received Fragment.
+ @param[in] Timeout The time to wait for connection done.
+
+ @retval EFI_SUCCESS One fragment is received.
+ @retval EFI_OUT_OF_RESOURCES Can't allocate memory resources.
+ @retval EFI_ABORTED Something wrong decryption the message.
+ @retval Others Other errors as indicated.
+
+**/
+EFI_STATUS
+EFIAPI
+HttpsReceive (
+ IN HTTP_PROTOCOL *HttpInstance,
+ IN OUT NET_FRAGMENT *Fragment,
+ IN EFI_EVENT Timeout
+ )
+{
+ EFI_STATUS Status;
+ NET_BUF *Pdu;
+ TLS_RECORD_HEADER RecordHeader;
+ UINT8 *BufferIn;
+ UINTN BufferInSize;
+ NET_FRAGMENT TempFragment;
+ UINT8 *BufferOut;
+ UINTN BufferOutSize;
+ NET_BUF *PacketOut;
+ UINT8 *DataOut;
+ UINT8 *GetSessionDataBuffer;
+ UINTN GetSessionDataBufferSize;
+
+ Status = EFI_SUCCESS;
+ Pdu = NULL;
+ BufferIn = NULL;
+ BufferInSize = 0;
+ BufferOut = NULL;
+ BufferOutSize = 0;
+ PacketOut = NULL;
+ DataOut = NULL;
+ GetSessionDataBuffer = NULL;
+ GetSessionDataBufferSize = 0;
+
+ //
+ // Receive only one TLS record
+ //
+ Status = TlsReceiveOnePdu (HttpInstance, &Pdu, Timeout);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ BufferInSize = Pdu->TotalSize;
+ BufferIn = AllocateZeroPool (BufferInSize);
+ if (BufferIn == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ NetbufFree (Pdu);
+ return Status;
+ }
+
+ NetbufCopy (Pdu, 0, (UINT32) BufferInSize, BufferIn);
+
+ NetbufFree (Pdu);
+
+ //
+ // Handle Receive data.
+ //
+ RecordHeader = *(TLS_RECORD_HEADER *) BufferIn;
+
+ if ((RecordHeader.ContentType == TlsContentTypeApplicationData) &&
+ (RecordHeader.Version.Major == 0x03) &&
+ (RecordHeader.Version.Minor == TLS10_PROTOCOL_VERSION_MINOR ||
+ RecordHeader.Version.Minor == TLS11_PROTOCOL_VERSION_MINOR ||
+ RecordHeader.Version.Minor == TLS12_PROTOCOL_VERSION_MINOR)
+ ) {
+ //
+ // Decrypt Packet.
+ //
+ Status = TlsProcessMessage (
+ HttpInstance,
+ BufferIn,
+ BufferInSize,
+ EfiTlsDecrypt,
+ &TempFragment
+ );
+
+ FreePool (BufferIn);
+
+ if (EFI_ERROR (Status)) {
+ if (Status == EFI_ABORTED) {
+ //
+ // Something wrong decryption the message.
+ // BuildResponsePacket() will be called to generate Error Alert message and send it out.
+ //
+ BufferOutSize = DEF_BUF_LEN;
+ BufferOut = AllocateZeroPool (BufferOutSize);
+ if (BufferOut == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ return Status;
+ }
+
+ Status = HttpInstance->Tls->BuildResponsePacket (
+ HttpInstance->Tls,
+ NULL,
+ 0,
+ BufferOut,
+ &BufferOutSize
+ );
+ if (Status == EFI_BUFFER_TOO_SMALL) {
+ FreePool (BufferOut);
+ BufferOut = AllocateZeroPool (BufferOutSize);
+ if (BufferOut == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ return Status;
+ }
+
+ Status = HttpInstance->Tls->BuildResponsePacket (
+ HttpInstance->Tls,
+ NULL,
+ 0,
+ BufferOut,
+ &BufferOutSize
+ );
+ }
+ if (EFI_ERROR (Status)) {
+ FreePool(BufferOut);
+ return Status;
+ }
+
+ if (BufferOutSize != 0) {
+ PacketOut = NetbufAlloc ((UINT32)BufferOutSize);
+ DataOut = NetbufAllocSpace (PacketOut, (UINT32) BufferOutSize, NET_BUF_TAIL);
+ if (DataOut == NULL) {
+ FreePool (BufferOut);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ CopyMem (DataOut, BufferOut, BufferOutSize);
+
+ Status = TlsCommonTransmit (HttpInstance, PacketOut);
+
+ NetbufFree (PacketOut);
+ }
+
+ FreePool(BufferOut);
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ return EFI_ABORTED;
+ }
+
+ return Status;
+ }
+
+ //
+ // Parsing buffer.
+ //
+ ASSERT (((TLS_RECORD_HEADER *) (TempFragment.Bulk))->ContentType == TlsContentTypeApplicationData);
+
+ BufferInSize = ((TLS_RECORD_HEADER *) (TempFragment.Bulk))->Length;
+ BufferIn = AllocateZeroPool (BufferInSize);
+ if (BufferIn == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ return Status;
+ }
+
+ CopyMem (BufferIn, TempFragment.Bulk + sizeof (TLS_RECORD_HEADER), BufferInSize);
+
+ //
+ // Free the buffer in TempFragment.
+ //
+ FreePool (TempFragment.Bulk);
+
+ } else if ((RecordHeader.ContentType == TlsContentTypeAlert) &&
+ (RecordHeader.Version.Major == 0x03) &&
+ (RecordHeader.Version.Minor == TLS10_PROTOCOL_VERSION_MINOR ||
+ RecordHeader.Version.Minor == TLS11_PROTOCOL_VERSION_MINOR ||
+ RecordHeader.Version.Minor == TLS12_PROTOCOL_VERSION_MINOR)
+ ) {
+ BufferOutSize = DEF_BUF_LEN;
+ BufferOut = AllocateZeroPool (BufferOutSize);
+ if (BufferOut == NULL) {
+ FreePool (BufferIn);
+ Status = EFI_OUT_OF_RESOURCES;
+ return Status;
+ }
+
+ Status = HttpInstance->Tls->BuildResponsePacket (
+ HttpInstance->Tls,
+ BufferIn,
+ BufferInSize,
+ BufferOut,
+ &BufferOutSize
+ );
+ if (Status == EFI_BUFFER_TOO_SMALL) {
+ FreePool (BufferOut);
+ BufferOut = AllocateZeroPool (BufferOutSize);
+ if (BufferOut == NULL) {
+ FreePool (BufferIn);
+ Status = EFI_OUT_OF_RESOURCES;
+ return Status;
+ }
+
+ Status = HttpInstance->Tls->BuildResponsePacket (
+ HttpInstance->Tls,
+ BufferIn,
+ BufferInSize,
+ BufferOut,
+ &BufferOutSize
+ );
+ }
+
+ FreePool (BufferIn);
+
+ if (EFI_ERROR (Status)) {
+ FreePool (BufferOut);
+ return Status;
+ }
+
+ if (BufferOutSize != 0) {
+ PacketOut = NetbufAlloc ((UINT32) BufferOutSize);
+ DataOut = NetbufAllocSpace (PacketOut, (UINT32) BufferOutSize, NET_BUF_TAIL);
+ if (DataOut == NULL) {
+ FreePool (BufferOut);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ CopyMem (DataOut, BufferOut, BufferOutSize);
+
+ Status = TlsCommonTransmit (HttpInstance, PacketOut);
+
+ NetbufFree (PacketOut);
+ }
+
+ FreePool (BufferOut);
+
+ //
+ // Get the session state.
+ //
+ GetSessionDataBufferSize = DEF_BUF_LEN;
+ GetSessionDataBuffer = AllocateZeroPool (GetSessionDataBufferSize);
+ if (GetSessionDataBuffer == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ return Status;
+ }
+
+ Status = HttpInstance->Tls->GetSessionData (
+ HttpInstance->Tls,
+ EfiTlsSessionState,
+ GetSessionDataBuffer,
+ &GetSessionDataBufferSize
+ );
+ if (Status == EFI_BUFFER_TOO_SMALL) {
+ FreePool (GetSessionDataBuffer);
+ GetSessionDataBuffer = AllocateZeroPool (GetSessionDataBufferSize);
+ if (GetSessionDataBuffer == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ return Status;
+ }
+
+ Status = HttpInstance->Tls->GetSessionData (
+ HttpInstance->Tls,
+ EfiTlsSessionState,
+ GetSessionDataBuffer,
+ &GetSessionDataBufferSize
+ );
+ }
+ if (EFI_ERROR (Status)) {
+ FreePool (GetSessionDataBuffer);
+ return Status;
+ }
+
+ ASSERT(GetSessionDataBufferSize == sizeof (EFI_TLS_SESSION_STATE));
+ HttpInstance->TlsSessionState = *(EFI_TLS_SESSION_STATE *) GetSessionDataBuffer;
+
+ FreePool (GetSessionDataBuffer);
+
+ if(HttpInstance->TlsSessionState == EfiTlsSessionError) {
+ DEBUG ((EFI_D_ERROR, "TLS Session State Error!\n"));
+ return EFI_ABORTED;
+ }
+
+ BufferIn = NULL;
+ BufferInSize = 0;
+ }
+
+ Fragment->Bulk = BufferIn;
+ Fragment->Len = (UINT32) BufferInSize;
+
+ return Status;
+}
+
diff --git a/Core/NetworkPkg/HttpDxe/HttpsSupport.h b/Core/NetworkPkg/HttpDxe/HttpsSupport.h
new file mode 100644
index 0000000000..68a6073ceb
--- /dev/null
+++ b/Core/NetworkPkg/HttpDxe/HttpsSupport.h
@@ -0,0 +1,261 @@
+/** @file
+ The header files of miscellaneous routines specific to Https for HttpDxe driver.
+
+Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef __EFI_HTTPS_SUPPORT_H__
+#define __EFI_HTTPS_SUPPORT_H__
+
+#define HTTPS_DEFAULT_PORT 443
+
+#define HTTPS_FLAG "https://"
+
+/**
+ Check whether the Url is from Https.
+
+ @param[in] Url The pointer to a HTTP or HTTPS URL string.
+
+ @retval TRUE The Url is from HTTPS.
+ @retval FALSE The Url is from HTTP.
+
+**/
+BOOLEAN
+IsHttpsUrl (
+ IN CHAR8 *Url
+ );
+
+/**
+ Creates a Tls child handle, open EFI_TLS_PROTOCOL and EFI_TLS_CONFIGURATION_PROTOCOL.
+
+ @param[in] ImageHandle The firmware allocated handle for the UEFI image.
+ @param[out] TlsProto Pointer to the EFI_TLS_PROTOCOL instance.
+ @param[out] TlsConfiguration Pointer to the EFI_TLS_CONFIGURATION_PROTOCOL instance.
+
+ @return The child handle with opened EFI_TLS_PROTOCOL and EFI_TLS_CONFIGURATION_PROTOCOL.
+
+**/
+EFI_HANDLE
+EFIAPI
+TlsCreateChild (
+ IN EFI_HANDLE ImageHandle,
+ OUT EFI_TLS_PROTOCOL **TlsProto,
+ OUT EFI_TLS_CONFIGURATION_PROTOCOL **TlsConfiguration
+ );
+
+/**
+ Create event for the TLS receive and transmit tokens which are used to receive and
+ transmit TLS related messages.
+
+ @param[in, out] HttpInstance Pointer to HTTP_PROTOCOL structure.
+
+ @retval EFI_SUCCESS The events are created successfully.
+ @retval others Other error as indicated.
+
+**/
+EFI_STATUS
+EFIAPI
+TlsCreateTxRxEvent (
+ IN OUT HTTP_PROTOCOL *HttpInstance
+ );
+
+/**
+ Close events in the TlsTxToken and TlsRxToken.
+
+ @param[in] HttpInstance Pointer to HTTP_PROTOCOL structure.
+
+**/
+VOID
+EFIAPI
+TlsCloseTxRxEvent (
+ IN HTTP_PROTOCOL *HttpInstance
+ );
+
+/**
+ Read the TlsCaCertificate variable and configure it.
+
+ @param[in, out] HttpInstance The HTTP instance private data.
+
+ @retval EFI_SUCCESS TlsCaCertificate is configured.
+ @retval EFI_OUT_OF_RESOURCES Can't allocate memory resources.
+ @retval EFI_NOT_FOUND Fail to get "TlsCaCertificate" variable.
+ @retval Others Other error as indicated.
+
+**/
+EFI_STATUS
+TlsConfigCertificate (
+ IN OUT HTTP_PROTOCOL *HttpInstance
+ );
+
+/**
+ Configure TLS session data.
+
+ @param[in, out] HttpInstance The HTTP instance private data.
+
+ @retval EFI_SUCCESS TLS session data is configured.
+ @retval Others Other error as indicated.
+
+**/
+EFI_STATUS
+EFIAPI
+TlsConfigureSession (
+ IN OUT HTTP_PROTOCOL *HttpInstance
+ );
+
+/**
+ Transmit the Packet by processing the associated HTTPS token.
+
+ @param[in, out] HttpInstance Pointer to HTTP_PROTOCOL structure.
+ @param[in] Packet The packet to transmit.
+
+ @retval EFI_SUCCESS The packet is transmitted.
+ @retval EFI_INVALID_PARAMETER HttpInstance is NULL or Packet is NULL.
+ @retval EFI_OUT_OF_RESOURCES Can't allocate memory resources.
+ @retval EFI_DEVICE_ERROR An unexpected system or network error occurred.
+ @retval Others Other errors as indicated.
+
+**/
+EFI_STATUS
+EFIAPI
+TlsCommonTransmit (
+ IN OUT HTTP_PROTOCOL *HttpInstance,
+ IN NET_BUF *Packet
+ );
+
+/**
+ Receive the Packet by processing the associated HTTPS token.
+
+ @param[in, out] HttpInstance Pointer to HTTP_PROTOCOL structure.
+ @param[in] Packet The packet to transmit.
+ @param[in] Timeout The time to wait for connection done.
+
+ @retval EFI_SUCCESS The Packet is received.
+ @retval EFI_INVALID_PARAMETER HttpInstance is NULL or Packet is NULL.
+ @retval EFI_OUT_OF_RESOURCES Can't allocate memory resources.
+ @retval EFI_TIMEOUT The operation is time out.
+ @retval Others Other error as indicated.
+
+**/
+EFI_STATUS
+EFIAPI
+TlsCommonReceive (
+ IN OUT HTTP_PROTOCOL *HttpInstance,
+ IN NET_BUF *Packet,
+ IN EFI_EVENT Timeout
+ );
+
+/**
+ Receive one TLS PDU. An TLS PDU contains an TLS record header and it's
+ corresponding record data. These two parts will be put into two blocks of buffers in the
+ net buffer.
+
+ @param[in, out] HttpInstance Pointer to HTTP_PROTOCOL structure.
+ @param[out] Pdu The received TLS PDU.
+ @param[in] Timeout The time to wait for connection done.
+
+ @retval EFI_SUCCESS An TLS PDU is received.
+ @retval EFI_OUT_OF_RESOURCES Can't allocate memory resources.
+ @retval EFI_PROTOCOL_ERROR An unexpected TLS packet was received.
+ @retval Others Other errors as indicated.
+
+**/
+EFI_STATUS
+EFIAPI
+TlsReceiveOnePdu (
+ IN OUT HTTP_PROTOCOL *HttpInstance,
+ OUT NET_BUF **Pdu,
+ IN EFI_EVENT Timeout
+ );
+
+/**
+ Connect one TLS session by finishing the TLS handshake process.
+
+ @param[in] HttpInstance The HTTP instance private data.
+ @param[in] Timeout The time to wait for connection done.
+
+ @retval EFI_SUCCESS The TLS session is established.
+ @retval EFI_OUT_OF_RESOURCES Can't allocate memory resources.
+ @retval EFI_ABORTED TLS session state is incorrect.
+ @retval Others Other error as indicated.
+
+**/
+EFI_STATUS
+EFIAPI
+TlsConnectSession (
+ IN HTTP_PROTOCOL *HttpInstance,
+ IN EFI_EVENT Timeout
+ );
+
+/**
+ Close the TLS session and send out the close notification message.
+
+ @param[in] HttpInstance The HTTP instance private data.
+
+ @retval EFI_SUCCESS The TLS session is closed.
+ @retval EFI_INVALID_PARAMETER HttpInstance is NULL or Packet is NULL.
+ @retval EFI_OUT_OF_RESOURCES Can't allocate memory resources.
+ @retval Others Other error as indicated.
+
+**/
+EFI_STATUS
+EFIAPI
+TlsCloseSession (
+ IN HTTP_PROTOCOL *HttpInstance
+ );
+
+/**
+ Process one message according to the CryptMode.
+
+ @param[in] HttpInstance Pointer to HTTP_PROTOCOL structure.
+ @param[in] Message Pointer to the message buffer needed to processed.
+ @param[in] MessageSize Pointer to the message buffer size.
+ @param[in] ProcessMode Process mode.
+ @param[in, out] Fragment Only one Fragment returned after the Message is
+ processed successfully.
+
+ @retval EFI_SUCCESS Message is processed successfully.
+ @retval EFI_OUT_OF_RESOURCES Can't allocate memory resources.
+ @retval Others Other errors as indicated.
+
+**/
+EFI_STATUS
+EFIAPI
+TlsProcessMessage (
+ IN HTTP_PROTOCOL *HttpInstance,
+ IN UINT8 *Message,
+ IN UINTN MessageSize,
+ IN EFI_TLS_CRYPT_MODE ProcessMode,
+ IN OUT NET_FRAGMENT *Fragment
+ );
+
+/**
+ Receive one fragment decrypted from one TLS record.
+
+ @param[in] HttpInstance Pointer to HTTP_PROTOCOL structure.
+ @param[in, out] Fragment The received Fragment.
+ @param[in] Timeout The time to wait for connection done.
+
+ @retval EFI_SUCCESS One fragment is received.
+ @retval EFI_OUT_OF_RESOURCES Can't allocate memory resources.
+ @retval EFI_ABORTED Something wrong decryption the message.
+ @retval Others Other errors as indicated.
+
+**/
+EFI_STATUS
+EFIAPI
+HttpsReceive (
+ IN HTTP_PROTOCOL *HttpInstance,
+ IN OUT NET_FRAGMENT *Fragment,
+ IN EFI_EVENT Timeout
+ );
+
+#endif
+