summaryrefslogtreecommitdiff
path: root/NetworkPkg
diff options
context:
space:
mode:
authorYe Ting <ting.ye@intel.com>2015-07-07 09:09:21 +0000
committertye1 <tye1@Edk2>2015-07-07 09:09:21 +0000
commit47f51a064fbb3d3226304380674b2bec3cb33ba1 (patch)
tree44cb073e0aa95990d605a00e6118e3620fd38400 /NetworkPkg
parent99c048ef4aca44589d519946ee6a6c890ad9123b (diff)
downloadedk2-platforms-47f51a064fbb3d3226304380674b2bec3cb33ba1.tar.xz
NetworkPkg: Add HTTP Driver
Add HTTP driver to support HTTP protocols defined in UEFI 2.5 specification. Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Ye Ting <ting.ye@intel.com> Reviewed-by: Samer El-Haj-Mahmoud <elhaj@hp.com> Reviewed-by: Fu Siyuan <siyuan.fu@intel.com> git-svn-id: https://svn.code.sf.net/p/edk2/code/trunk/edk2@17855 6f19259b-4bc3-4df7-8a09-765794883524
Diffstat (limited to 'NetworkPkg')
-rw-r--r--NetworkPkg/HttpDxe/ComponentName.c138
-rw-r--r--NetworkPkg/HttpDxe/ComponentName.h98
-rw-r--r--NetworkPkg/HttpDxe/HttpDns.c218
-rw-r--r--NetworkPkg/HttpDxe/HttpDns.h38
-rw-r--r--NetworkPkg/HttpDxe/HttpDriver.c669
-rw-r--r--NetworkPkg/HttpDxe/HttpDriver.h260
-rw-r--r--NetworkPkg/HttpDxe/HttpDxe.inf64
-rw-r--r--NetworkPkg/HttpDxe/HttpDxe.unibin0 -> 1822 bytes
-rw-r--r--NetworkPkg/HttpDxe/HttpDxeExtra.unibin0 -> 1310 bytes
-rw-r--r--NetworkPkg/HttpDxe/HttpImpl.c1309
-rw-r--r--NetworkPkg/HttpDxe/HttpImpl.h239
-rw-r--r--NetworkPkg/HttpDxe/HttpProto.c1165
-rw-r--r--NetworkPkg/HttpDxe/HttpProto.h457
-rw-r--r--NetworkPkg/HttpDxe/HttpUtilities.c622
-rw-r--r--NetworkPkg/HttpDxe/HttpUtilities.h82
15 files changed, 5359 insertions, 0 deletions
diff --git a/NetworkPkg/HttpDxe/ComponentName.c b/NetworkPkg/HttpDxe/ComponentName.c
new file mode 100644
index 0000000000..fdd2e7f344
--- /dev/null
+++ b/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/NetworkPkg/HttpDxe/ComponentName.h b/NetworkPkg/HttpDxe/ComponentName.h
new file mode 100644
index 0000000000..29a91f2ec1
--- /dev/null
+++ b/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/NetworkPkg/HttpDxe/HttpDns.c b/NetworkPkg/HttpDxe/HttpDns.c
new file mode 100644
index 0000000000..daebc173b5
--- /dev/null
+++ b/NetworkPkg/HttpDxe/HttpDns.c
@@ -0,0 +1,218 @@
+/** @file
+ 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.
+
+**/
+
+#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->ImageHandle,
+ &gEfiDns4ServiceBindingProtocolGuid,
+ &Dns4Handle
+ );
+ if (EFI_ERROR (Status)) {
+ goto Exit;
+ }
+
+ Status = gBS->OpenProtocol (
+ Dns4Handle,
+ &gEfiDns4ProtocolGuid,
+ (VOID **) &Dns4,
+ Service->ImageHandle,
+ 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->ImageHandle,
+ Service->ControllerHandle
+ );
+ }
+
+ if (Dns4Handle != NULL) {
+ NetLibDestroyServiceChild (
+ Service->ControllerHandle,
+ Service->ImageHandle,
+ &gEfiDns4ServiceBindingProtocolGuid,
+ Dns4Handle
+ );
+ }
+
+ if (DnsServerList != NULL) {
+ FreePool (DnsServerList);
+ }
+
+ return Status;
+}
diff --git a/NetworkPkg/HttpDxe/HttpDns.h b/NetworkPkg/HttpDxe/HttpDns.h
new file mode 100644
index 0000000000..0fb418635c
--- /dev/null
+++ b/NetworkPkg/HttpDxe/HttpDns.h
@@ -0,0 +1,38 @@
+/** @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
+ );
+
+#endif \ No newline at end of file
diff --git a/NetworkPkg/HttpDxe/HttpDriver.c b/NetworkPkg/HttpDxe/HttpDriver.c
new file mode 100644
index 0000000000..b65607a4cb
--- /dev/null
+++ b/NetworkPkg/HttpDxe/HttpDriver.c
@@ -0,0 +1,669 @@
+/** @file
+ The driver binding and service binding protocol for HttpDxe driver.
+
+ 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"
+
+///
+/// Driver Binding Protocol instance
+///
+EFI_DRIVER_BINDING_PROTOCOL gHttpDxeDriverBinding = {
+ HttpDxeDriverBindingSupported,
+ HttpDxeDriverBindingStart,
+ HttpDxeDriverBindingStop,
+ 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[in] ImageHandle The HTTP driver's image handle.
+ @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,
+ IN EFI_HANDLE ImageHandle,
+ 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->ImageHandle = ImageHandle;
+ 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 HttpService The HTTP private instance.
+
+**/
+VOID
+HttpCleanService (
+ IN HTTP_SERVICE *HttpService
+ )
+{
+ if (HttpService != NULL) {
+ return ;
+ }
+
+ if (HttpService->TcpChildHandle != NULL) {
+ gBS->CloseProtocol (
+ HttpService->TcpChildHandle,
+ &gEfiTcp4ProtocolGuid,
+ HttpService->ImageHandle,
+ HttpService->ControllerHandle
+ );
+
+ NetLibDestroyServiceChild (
+ HttpService->ControllerHandle,
+ HttpService->ImageHandle,
+ &gEfiTcp4ServiceBindingProtocolGuid,
+ HttpService->TcpChildHandle
+ );
+ }
+}
+
+/**
+ 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
+ )
+{
+ //
+ // Install UEFI Driver Model protocol(s).
+ //
+ return EfiLibInstallDriverBindingComponentName2 (
+ ImageHandle,
+ SystemTable,
+ &gHttpDxeDriverBinding,
+ ImageHandle,
+ &gHttpDxeComponentName,
+ &gHttpDxeComponentName2
+ );
+}
+
+/**
+ 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);
+}
+
+/**
+ 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
+HttpDxeDriverBindingSupported (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+
+ //
+ // Test for the HttpServiceBinding protocol.
+ //
+ Status = gBS->OpenProtocol (
+ ControllerHandle,
+ &gEfiHttpServiceBindingProtocolGuid,
+ NULL,
+ This->DriverBindingHandle,
+ ControllerHandle,
+ EFI_OPEN_PROTOCOL_TEST_PROTOCOL
+ );
+ if (!EFI_ERROR (Status)) {
+ return EFI_ALREADY_STARTED;
+ }
+
+ //
+ // Test for the Tcp4 Protocol
+ //
+ return gBS->OpenProtocol (
+ ControllerHandle,
+ &gEfiTcp4ServiceBindingProtocolGuid,
+ NULL,
+ This->DriverBindingHandle,
+ ControllerHandle,
+ EFI_OPEN_PROTOCOL_TEST_PROTOCOL
+ );
+
+}
+
+/**
+ 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
+HttpDxeDriverBindingStart (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ HTTP_SERVICE *HttpService;
+ VOID *Interface;
+
+ //
+ // Test for the Http service binding protocol
+ //
+ Status = gBS->OpenProtocol (
+ ControllerHandle,
+ &gEfiHttpServiceBindingProtocolGuid,
+ NULL,
+ This->DriverBindingHandle,
+ ControllerHandle,
+ EFI_OPEN_PROTOCOL_TEST_PROTOCOL
+ );
+
+ if (Status == EFI_SUCCESS) {
+ return EFI_ALREADY_STARTED;
+ }
+
+ Status = HttpCreateService (ControllerHandle, This->DriverBindingHandle, &HttpService);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ ASSERT (HttpService != NULL);
+
+ //
+ // Create a TCP child instance, but do not configure it. This will establish the parent-child relationship.
+ //
+ Status = NetLibCreateServiceChild (
+ ControllerHandle,
+ This->DriverBindingHandle,
+ &gEfiTcp4ServiceBindingProtocolGuid,
+ &HttpService->TcpChildHandle
+ );
+
+ if (EFI_ERROR (Status)) {
+ goto ON_ERROR;
+ }
+
+ Status = gBS->OpenProtocol (
+ HttpService->TcpChildHandle,
+ &gEfiTcp4ProtocolGuid,
+ &Interface,
+ This->DriverBindingHandle,
+ ControllerHandle,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+
+ if (EFI_ERROR (Status)) {
+ goto ON_ERROR;
+ }
+
+ //
+ // Install the HttpServiceBinding Protocol onto Controller
+ //
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &ControllerHandle,
+ &gEfiHttpServiceBindingProtocolGuid,
+ &HttpService->ServiceBinding,
+ NULL
+ );
+
+ if (EFI_ERROR (Status)) {
+ goto ON_ERROR;
+ }
+
+ return EFI_SUCCESS;
+
+ON_ERROR:
+
+ if (HttpService != NULL) {
+ HttpCleanService (HttpService);
+ FreePool (HttpService);
+ }
+
+ return Status;
+}
+
+/**
+ 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
+HttpDxeDriverBindingStop (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN UINTN NumberOfChildren,
+ IN EFI_HANDLE *ChildHandleBuffer OPTIONAL
+ )
+{
+ 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;
+
+ //
+ // HTTP driver opens TCP child, So, Controller is a TCP
+ // child handle. Locate the Nic handle first. Then get the
+ // HTTP private data back.
+ //
+ NicHandle = NetLibGetNicHandle (ControllerHandle, &gEfiTcp4ProtocolGuid);
+ 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)) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ HttpService = HTTP_SERVICE_FROM_PROTOCOL (ServiceBinding);
+
+ if (!IsListEmpty (&HttpService->ChildrenList)) {
+ //
+ // 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
+ );
+ }
+
+ if (NumberOfChildren == 0 && IsListEmpty (&HttpService->ChildrenList)) {
+ gBS->UninstallProtocolInterface (
+ NicHandle,
+ &gEfiHttpServiceBindingProtocolGuid,
+ ServiceBinding
+ );
+
+ HttpCleanService (HttpService);
+
+ FreePool (HttpService);
+
+ Status = EFI_SUCCESS;
+ }
+
+ return Status;
+}
+
+/**
+ 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 availabe 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;
+ VOID *Interface;
+ 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;
+ }
+
+ //
+ // Install HTTP protocol onto ChildHandle
+ //
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ ChildHandle,
+ &gEfiHttpProtocolGuid,
+ &HttpInstance->Http,
+ NULL
+ );
+
+ if (EFI_ERROR (Status)) {
+ goto ON_ERROR;
+ }
+
+ HttpInstance->Handle = *ChildHandle;
+
+ Status = HttpInitProtocol (HttpService, HttpInstance);
+ if (EFI_ERROR (Status)) {
+ goto ON_ERROR;
+ }
+
+ //
+ // Open the default Tcp4 protocol by child.
+ //
+ Status = gBS->OpenProtocol (
+ HttpService->TcpChildHandle,
+ &gEfiTcp4ProtocolGuid,
+ (VOID **) &Interface,
+ gHttpDxeDriverBinding.DriverBindingHandle,
+ HttpInstance->Handle,
+ EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
+ );
+ if (EFI_ERROR (Status)) {
+ goto ON_ERROR;
+ }
+
+ //
+ // 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:
+
+ HttpCleanProtocol (HttpInstance);
+ 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,
+ gHttpDxeDriverBinding.DriverBindingHandle,
+ ChildHandle,
+ 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;
+ }
+
+ //
+ // Close the Tcp4 protocol.
+ //
+ gBS->CloseProtocol (
+ HttpService->TcpChildHandle,
+ &gEfiTcp4ProtocolGuid,
+ gHttpDxeDriverBinding.DriverBindingHandle,
+ ChildHandle
+ );
+
+ HttpInstance->InDestroy = TRUE;
+
+ //
+ // Uninstall the HTTP protocol.
+ //
+ Status = gBS->UninstallProtocolInterface (
+ ChildHandle,
+ &gEfiHttpProtocolGuid,
+ Http
+ );
+
+ if (EFI_ERROR (Status)) {
+ HttpInstance->InDestroy = FALSE;
+ return Status;
+ }
+
+ OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
+
+ HttpCleanProtocol (HttpInstance);
+
+ RemoveEntryList (&HttpInstance->Link);
+ HttpService->ChildrenNumber--;
+
+ gBS->RestoreTPL (OldTpl);
+
+ FreePool (HttpInstance);
+ return EFI_SUCCESS;
+}
diff --git a/NetworkPkg/HttpDxe/HttpDriver.h b/NetworkPkg/HttpDxe/HttpDriver.h
new file mode 100644
index 0000000000..5bad7059f3
--- /dev/null
+++ b/NetworkPkg/HttpDxe/HttpDriver.h
@@ -0,0 +1,260 @@
+/** @file
+ The header files of the driver binding and service binding protocol for HttpDxe driver.
+
+ 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_DRIVER_H__
+#define __EFI_HTTP_DRIVER_H__
+
+#include <Uefi.h>
+
+//
+// Libraries
+//
+#include <Library/UefiBootServicesTableLib.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/TcpIoLib.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/Tcp4.h>
+#include <Protocol/Dns4.h>
+#include <Protocol/Ip4Config2.h>
+
+//
+// Produced Protocols
+//
+#include <Protocol/Http.h>
+
+//
+// Driver Version
+//
+#define HTTP_DRIVER_VERSION 0xa
+
+//
+// Protocol instances
+//
+extern EFI_DRIVER_BINDING_PROTOCOL gHttpDxeDriverBinding;
+extern EFI_COMPONENT_NAME2_PROTOCOL gHttpDxeComponentName2;
+extern EFI_COMPONENT_NAME_PROTOCOL gHttpDxeComponentName;
+
+//
+// Include files with function prototypes
+//
+#include "ComponentName.h"
+#include "HttpImpl.h"
+#include "HttpProto.h"
+#include "HttpDns.h"
+#include "HttpUtilities.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
+HttpDxeDriverBindingSupported (
+ 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
+HttpDxeDriverBindingStart (
+ 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
+HttpDxeDriverBindingStop (
+ 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 availabe 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
+ );
+
+
+extern EFI_HTTP_PROTOCOL mEfiHttpProtocolTemplete;
+
+#endif
diff --git a/NetworkPkg/HttpDxe/HttpDxe.inf b/NetworkPkg/HttpDxe/HttpDxe.inf
new file mode 100644
index 0000000000..4632934720
--- /dev/null
+++ b/NetworkPkg/HttpDxe/HttpDxe.inf
@@ -0,0 +1,64 @@
+## @file
+# Implementation of EFI HTTP protocol interfaces.
+#
+# 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.
+#
+#
+##
+
+[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
+
+[Sources]
+ ComponentName.h
+ ComponentName.c
+ HttpDns.h
+ HttpDns.c
+ HttpDriver.h
+ HttpDriver.c
+ HttpImpl.h
+ HttpImpl.c
+ HttpProto.h
+ HttpProto.c
+ HttpUtilities.h
+ HttpUtilities.c
+
+[LibraryClasses]
+ UefiDriverEntryPoint
+ UefiBootServicesTableLib
+ MemoryAllocationLib
+ BaseLib
+ UefiLib
+ DebugLib
+ NetLib
+ HttpLib
+
+[Protocols]
+ gEfiHttpServiceBindingProtocolGuid ## BY_START
+ gEfiHttpProtocolGuid ## BY_START
+ gEfiTcp4ServiceBindingProtocolGuid ## TO_START
+ gEfiTcp4ProtocolGuid ## TO_START
+ gEfiDns4ServiceBindingProtocolGuid ## SOMETIMES_CONSUMES
+ gEfiDns4ProtocolGuid ## SOMETIMES_CONSUMES
+ gEfiIp4Config2ProtocolGuid ## SOMETIMES_CONSUMES
+
+[UserExtensions.TianoCore."ExtraFiles"]
+ HttpDxeExtra.uni \ No newline at end of file
diff --git a/NetworkPkg/HttpDxe/HttpDxe.uni b/NetworkPkg/HttpDxe/HttpDxe.uni
new file mode 100644
index 0000000000..f9c2ac812e
--- /dev/null
+++ b/NetworkPkg/HttpDxe/HttpDxe.uni
Binary files differ
diff --git a/NetworkPkg/HttpDxe/HttpDxeExtra.uni b/NetworkPkg/HttpDxe/HttpDxeExtra.uni
new file mode 100644
index 0000000000..1a06619eee
--- /dev/null
+++ b/NetworkPkg/HttpDxe/HttpDxeExtra.uni
Binary files differ
diff --git a/NetworkPkg/HttpDxe/HttpImpl.c b/NetworkPkg/HttpDxe/HttpImpl.c
new file mode 100644
index 0000000000..4bd4ac884f
--- /dev/null
+++ b/NetworkPkg/HttpDxe/HttpImpl.c
@@ -0,0 +1,1309 @@
+/** @file
+ Implementation of EFI_HTTP_PROTOCOL protocol interfaces.
+
+ 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"
+
+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.
+ HttpConfigData->AccessPoint is NULL.
+ @retval EFI_NOT_STARTED The HTTP instance is not configured.
+
+**/
+EFI_STATUS
+EFIAPI
+EfiHttpGetModeData (
+ IN EFI_HTTP_PROTOCOL *This,
+ OUT EFI_HTTP_CONFIG_DATA *HttpConfigData
+ )
+{
+ HTTP_PROTOCOL *HttpInstance;
+
+ if ((This == NULL) || (HttpConfigData == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ HttpInstance = HTTP_INSTANCE_FROM_PROTOCOL (This);
+ ASSERT (HttpInstance != NULL);
+
+ if (HttpInstance->State < HTTP_STATE_HTTP_CONFIGED) {
+ return EFI_NOT_STARTED;
+ }
+
+ if (HttpConfigData->AccessPoint.IPv4Node == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ HttpConfigData->HttpVersion = HttpInstance->HttpVersion;
+ HttpConfigData->TimeOutMillisec = HttpInstance->TimeOutMillisec;
+ HttpConfigData->LocalAddressIsIPv6 = HttpInstance->LocalAddressIsIPv6;
+
+ 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.
+
+ Except for GetModeData() and Configure(), 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;
+
+ if (This == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ HttpInstance = HTTP_INSTANCE_FROM_PROTOCOL (This);
+ ASSERT (HttpInstance != NULL && HttpInstance->Service != NULL);
+
+ if (HttpConfigData != NULL) {
+ //
+ // Check input parameters.
+ //
+ if (HttpConfigData->LocalAddressIsIPv6) {
+ if (HttpConfigData->AccessPoint.IPv6Node == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+ } else {
+ if (HttpConfigData->AccessPoint.IPv4Node == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+ }
+ //
+ // 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) {
+ return EFI_UNSUPPORTED;
+ } else {
+ CopyMem (
+ &HttpInstance->IPv4Node,
+ HttpConfigData->AccessPoint.IPv4Node,
+ sizeof (HttpInstance->IPv4Node)
+ );
+
+ HttpInstance->State = HTTP_STATE_HTTP_CONFIGED;
+ return EFI_SUCCESS;
+ }
+
+ } else {
+ if (HttpInstance->LocalAddressIsIPv6) {
+ return EFI_UNSUPPORTED;
+ } else {
+ HttpCleanProtocol (HttpInstance);
+ Status = HttpInitProtocol (HttpInstance->Service, HttpInstance);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ 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->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;
+ UINT16 RemotePort;
+ HTTP_PROTOCOL *HttpInstance;
+ BOOLEAN Configure;
+ BOOLEAN ReConfigure;
+ CHAR8 *RequestStr;
+ CHAR8 *Url;
+ CHAR16 *HostNameStr;
+ HTTP_TOKEN_WRAP *Wrap;
+ HTTP_TCP_TOKEN_WRAP *TcpWrap;
+
+ if ((This == NULL) || (Token == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ HttpMsg = Token->Message;
+ if ((HttpMsg == NULL) || (HttpMsg->Headers == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Current implementation does not support POST/PUT method.
+ // If future version supports these two methods, Request could be NULL for a special case that to send large amounts
+ // of data. For this case, the implementation need check whether previous call to Request() has been completed or not.
+ //
+ //
+ Request = HttpMsg->Data.Request;
+ if ((Request == NULL) || (Request->Url == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Only support GET and HEAD method in current implementation.
+ //
+ if ((Request->Method != HttpMethodGet) && (Request->Method != HttpMethodHead)) {
+ return EFI_UNSUPPORTED;
+ }
+
+ HttpInstance = HTTP_INSTANCE_FROM_PROTOCOL (This);
+ ASSERT (HttpInstance != NULL);
+
+ if (HttpInstance->State < HTTP_STATE_HTTP_CONFIGED) {
+ return EFI_NOT_STARTED;
+ }
+
+ if (HttpInstance->LocalAddressIsIPv6) {
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // Check whether the token already existed.
+ //
+ if (EFI_ERROR (NetMapIterate (&HttpInstance->TxTokens, HttpTokenExist, Token))) {
+ return EFI_ACCESS_DENIED;
+ }
+
+ Url = NULL;
+ HostName = NULL;
+ Wrap = NULL;
+ HostNameStr = NULL;
+ TcpWrap = NULL;
+
+ //
+ // Parse the URI of the remote host.
+ //
+ Url = AllocatePool (StrLen (Request->Url) + 1);
+ if (Url == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ UnicodeStrToAsciiStr (Request->Url, Url);
+ UrlParser = NULL;
+ Status = HttpParseUrl (Url, (UINT32) AsciiStrLen (Url), FALSE, &UrlParser);
+ if (EFI_ERROR (Status)) {
+ goto Error1;
+ }
+
+ RequestStr = NULL;
+ HostName = NULL;
+ Status = HttpUrlGetHostName (Url, UrlParser, &HostName);
+ if (EFI_ERROR (Status)) {
+ goto Error1;
+ }
+
+ Status = HttpUrlGetPort (Url, UrlParser, &RemotePort);
+ if (EFI_ERROR (Status)) {
+ RemotePort = HTTP_DEFAULT_PORT;
+ }
+
+ Configure = TRUE;
+ ReConfigure = TRUE;
+
+ if (HttpInstance->RemoteHost == NULL && HttpInstance->RemotePort == 0) {
+ //
+ // Request() is called the first time.
+ //
+ ReConfigure = FALSE;
+ } else {
+ if ((HttpInstance->RemotePort == RemotePort) &&
+ (AsciiStrCmp (HttpInstance->RemoteHost, HostName) == 0)) {
+ //
+ // Host Name and port number of the request URL are the same with previous call to Request().
+ // 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 = HttpCreateTcp4TxEvent (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 (Url);
+ 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;
+ }
+ }
+ }
+
+ if (Configure) {
+ //
+ // Parse Url for IPv4 address, if failed, perform DNS resolution.
+ //
+ Status = NetLibAsciiStrToIp4 (HostName, &HttpInstance->RemoteAddr);
+ if (EFI_ERROR (Status)) {
+ HostNameStr = AllocateZeroPool ((AsciiStrLen (HostName) + 1) * sizeof (UINT16));
+ if (HostNameStr == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Error1;
+ }
+
+ AsciiStrToUnicodeStr (HostName, HostNameStr);
+ Status = HttpDns4 (HttpInstance, HostNameStr, &HttpInstance->RemoteAddr);
+ 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.
+ //
+ ASSERT (HttpInstance->Tcp4 != NULL);
+ 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;
+ Wrap->TcpWrap.Method = Request->Method;
+
+ if (Configure) {
+ //
+ // Configure TCP instance.
+ //
+ Status = HttpConfigureTcp4 (HttpInstance, Wrap);
+ if (EFI_ERROR (Status)) {
+ goto Error1;
+ }
+ //
+ // Connect TCP.
+ //
+ Status = HttpConnectTcp4 (HttpInstance);
+ if (EFI_ERROR (Status)) {
+ goto Error2;
+ }
+ } else {
+ //
+ // For the new HTTP token, create TX TCP token events.
+ //
+ Status = HttpCreateTcp4TxEvent (Wrap);
+ if (EFI_ERROR (Status)) {
+ goto Error1;
+ }
+ }
+
+ //
+ // Create request message.
+ //
+ RequestStr = HttpGenRequestString (HttpInstance, HttpMsg, Url);
+ if (RequestStr == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Error3;
+ }
+
+ Status = NetMapInsertTail (&HttpInstance->TxTokens, Token, Wrap);
+ if (EFI_ERROR (Status)) {
+ goto Error4;
+ }
+
+ FreePool (Url);
+ if (HostName != NULL) {
+ FreePool (HostName);
+ }
+
+ //
+ // Transmit the request message.
+ //
+ Status = HttpTransmitTcp4 (
+ HttpInstance,
+ Wrap,
+ (UINT8*) RequestStr,
+ AsciiStrLen (RequestStr)
+ );
+ if (EFI_ERROR (Status)) {
+ goto Error5;
+ }
+
+ return EFI_SUCCESS;
+
+Error5:
+ NetMapRemoveTail (&HttpInstance->TxTokens, NULL);
+
+Error4:
+ if (RequestStr != NULL) {
+ FreePool (RequestStr);
+ }
+
+Error3:
+ HttpCloseConnection (HttpInstance);
+
+
+Error2:
+ HttpCloseTcp4ConnCloseEvent (HttpInstance);
+ if (NULL != Wrap->TcpWrap.TxToken.CompletionToken.Event) {
+ gBS->CloseEvent (Wrap->TcpWrap.TxToken.CompletionToken.Event);
+ }
+
+Error1:
+ if (Url != NULL) {
+ FreePool (Url);
+ }
+ if (HostName != NULL) {
+ FreePool (HostName);
+ }
+ if (Wrap != NULL) {
+ FreePool (Wrap);
+ }
+ if (UrlParser!= NULL) {
+ HttpUrlFreeParser (UrlParser);
+ }
+
+ return Status;
+
+}
+
+/**
+ Cancel a TxToken or RxToken.
+
+ @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;
+
+ 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);
+
+ //
+ // Free resources.
+ //
+ NetMapRemoveItem (Map, Item, NULL);
+
+ if (Wrap->TcpWrap.TxToken.CompletionToken.Event != NULL) {
+ gBS->CloseEvent (Wrap->TcpWrap.TxToken.CompletionToken.Event);
+ }
+
+ if (Wrap->TcpWrap.RxToken.CompletionToken.Event != NULL) {
+ gBS->CloseEvent (Wrap->TcpWrap.RxToken.CompletionToken.Event);
+ }
+
+ if (Wrap->TcpWrap.RxToken.Packet.RxData->FragmentTable[0].FragmentBuffer != NULL) {
+ FreePool (Wrap->TcpWrap.RxToken.Packet.RxData->FragmentTable[0].FragmentBuffer);
+ }
+
+ FreePool (Wrap);
+
+ //
+ // 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;
+ }
+ }
+
+ //
+ // Then check the tokens queued by EfiHttpResponse().
+ //
+ 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;
+ }
+ }
+
+ 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_NO_MAPPING When using the default address, configuration (DHCP,
+ BOOTP, RARP, etc.) hasn't finished yet.
+ @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;
+
+ if (EventType != BodyParseEventOnComplete) {
+ return EFI_SUCCESS;
+ }
+
+ if (Data == NULL || Length != 0 || Context == NULL) {
+ return EFI_SUCCESS;
+ }
+
+ Wrap = (HTTP_TOKEN_WRAP *) Context;
+ Wrap->HttpInstance->NextMsg = Data;
+
+ //
+ // Free TxToken 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 TxToken.
+
+**/
+EFI_STATUS
+HttpResponseWorker (
+ IN HTTP_TOKEN_WRAP *Wrap
+ )
+{
+ EFI_STATUS Status;
+ EFI_HTTP_MESSAGE *HttpMsg;
+ EFI_TCP4_IO_TOKEN *RxToken;
+ EFI_TCP4_PROTOCOL *Tcp4;
+ CHAR8 *EndofHeader;
+ CHAR8 *HttpHeaders;
+ UINTN SizeofHeaders;
+ CHAR8 *Buffer;
+ 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;
+
+ HttpInstance = Wrap->HttpInstance;
+ Token = Wrap->HttpToken;
+
+ HttpMsg = Token->Message;
+
+ Tcp4 = HttpInstance->Tcp4;
+ ASSERT (Tcp4 != NULL);
+ HttpMsg->Headers = NULL;
+ HttpHeaders = NULL;
+ SizeofHeaders = 0;
+ Buffer = NULL;
+ BufferSize = 0;
+ EndofHeader = NULL;
+
+ if (HttpMsg->Data.Response != NULL) {
+ //
+ // Need receive the HTTP headers, prepare buffer.
+ //
+ Status = HttpCreateTcp4RxEventForHeader (HttpInstance);
+ if (EFI_ERROR (Status)) {
+ goto Error;
+ }
+
+ //
+ // 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);
+ }
+
+ RxToken = &HttpInstance->RxToken;
+ RxToken->Packet.RxData->FragmentTable[0].FragmentBuffer = AllocateZeroPool (DEF_BUF_LEN);
+ if (RxToken->Packet.RxData->FragmentTable[0].FragmentBuffer == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Error;
+ }
+
+ //
+ // Receive the HTTP headers only when EFI_HTTP_RESPONSE_DATA is not NULL.
+ //
+ while (EndofHeader == NULL) {
+ HttpInstance->IsRxDone = FALSE;
+ RxToken->Packet.RxData->DataLength = DEF_BUF_LEN;
+ RxToken->Packet.RxData->FragmentTable[0].FragmentLength = DEF_BUF_LEN;
+ Status = Tcp4->Receive (Tcp4, RxToken);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "Tcp4 receive failed: %r\n", Status));
+ goto Error;
+ }
+
+ while (!HttpInstance->IsRxDone) {
+ Tcp4->Poll (Tcp4);
+ }
+
+ Status = RxToken->CompletionToken.Status;
+ if (EFI_ERROR (Status)) {
+ goto Error;
+ }
+
+ //
+ // Append the response string.
+ //
+ BufferSize = SizeofHeaders + RxToken->Packet.RxData->FragmentTable[0].FragmentLength;
+ Buffer = AllocateZeroPool (BufferSize);
+ if (Buffer == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Error;
+ }
+
+ if (HttpHeaders != NULL) {
+ CopyMem (Buffer, HttpHeaders, SizeofHeaders);
+ FreePool (HttpHeaders);
+ }
+
+ CopyMem (
+ Buffer + SizeofHeaders,
+ RxToken->Packet.RxData->FragmentTable[0].FragmentBuffer,
+ RxToken->Packet.RxData->FragmentTable[0].FragmentLength
+ );
+ HttpHeaders = Buffer;
+ SizeofHeaders = BufferSize;
+
+ //
+ // Check whether we received end of HTTP headers.
+ //
+ EndofHeader = AsciiStrStr (HttpHeaders, HTTP_END_OF_HDR_STR);
+ };
+
+ //
+ // Skip the CRLF after the HTTP headers.
+ //
+ EndofHeader = EndofHeader + AsciiStrLen (HTTP_END_OF_HDR_STR);
+
+ //
+ // 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;
+ }
+
+ FreePool (RxToken->Packet.RxData->FragmentTable[0].FragmentBuffer);
+ RxToken->Packet.RxData->FragmentTable[0].FragmentBuffer = NULL;
+
+ //
+ // Search for Status Code.
+ //
+ StatusCodeStr = HttpHeaders + AsciiStrLen (HTTP_VERSION_STR) + 1;
+ if (StatusCodeStr == NULL) {
+ 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) {
+ goto Error;
+ }
+
+ Tmp = Tmp + AsciiStrLen (HTTP_CRLF_STR);
+ SizeofHeaders = SizeofHeaders - (Tmp - HttpHeaders);
+ HeaderTmp = AllocateZeroPool (SizeofHeaders);
+ if (HeaderTmp == NULL) {
+ goto Error;
+ }
+
+ CopyMem (HeaderTmp, Tmp, SizeofHeaders);
+ FreePool (HttpHeaders);
+ HttpHeaders = HeaderTmp;
+ //
+ // Parse the HTTP header into array of key/value pairs.
+ //
+ Status = HttpUtilitiesParse (HttpHeaders, SizeofHeaders, &HttpMsg->Headers, &HttpMsg->HeaderCount);
+ if (EFI_ERROR (Status)) {
+ goto Error;
+ }
+
+ FreePool (HttpHeaders);
+ HttpHeaders = NULL;
+
+ HttpMsg->Data.Response->StatusCode = HttpMappingToStatusCode (StatusCode);
+
+ //
+ // Init message-body parser by header information.
+ //
+ Status = EFI_NOT_READY;
+ ValueInItem = NULL;
+ NetMapRemoveHead (&HttpInstance->TxTokens, (VOID**) &ValueInItem);
+ if (ValueInItem == NULL) {
+ goto Error;
+ }
+
+ //
+ // The first TxToken not transmitted yet, insert back and return error.
+ //
+ if (!ValueInItem->TcpWrap.IsTxDone) {
+ goto Error2;
+ }
+
+ Status = HttpInitMsgParser (
+ ValueInItem->TcpWrap.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;
+ //
+ RxToken = &Wrap->TcpWrap.RxToken;
+
+ RxToken->Packet.RxData->DataLength = (UINT32) HttpMsg->BodyLength;
+ RxToken->Packet.RxData->FragmentTable[0].FragmentLength = (UINT32) HttpMsg->BodyLength;
+ RxToken->Packet.RxData->FragmentTable[0].FragmentBuffer = (VOID *) HttpMsg->Body;
+
+ RxToken->CompletionToken.Status = EFI_NOT_READY;
+ Status = Tcp4->Receive (Tcp4, RxToken);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "Tcp4 receive failed: %r\n", Status));
+ goto Error;
+ }
+
+ return Status;
+
+Exit:
+ Item = NetMapFindKey (&Wrap->HttpInstance->RxTokens, Wrap->HttpToken);
+ if (Item != NULL) {
+ NetMapRemoveItem (&Wrap->HttpInstance->RxTokens, Item, NULL);
+ }
+ Token->Status = Status;
+ gBS->SignalEvent (Token->Event);
+ FreePool (Wrap);
+ return Status;
+
+Error2:
+ NetMapInsertHead (&HttpInstance->TxTokens, ValueInItem->HttpToken, ValueInItem);
+
+Error:
+ if (Wrap != NULL) {
+ if (Wrap->TcpWrap.RxToken.CompletionToken.Event != NULL) {
+ gBS->CloseEvent (Wrap->TcpWrap.RxToken.CompletionToken.Event);
+ }
+ RxToken = &Wrap->TcpWrap.RxToken;
+ if (RxToken->Packet.RxData->FragmentTable[0].FragmentBuffer != NULL) {
+ FreePool (RxToken->Packet.RxData->FragmentTable[0].FragmentBuffer);
+ RxToken->Packet.RxData->FragmentTable[0].FragmentBuffer = NULL;
+ }
+ FreePool (Wrap);
+ }
+
+ if (HttpInstance->RxToken.CompletionToken.Event != NULL) {
+ gBS->CloseEvent (HttpInstance->RxToken.CompletionToken.Event);
+ HttpInstance->RxToken.CompletionToken.Event = NULL;
+ }
+
+ RxToken = &HttpInstance->RxToken;
+ if (RxToken->Packet.RxData->FragmentTable[0].FragmentBuffer != NULL) {
+ FreePool (RxToken->Packet.RxData->FragmentTable[0].FragmentBuffer);
+ RxToken->Packet.RxData->FragmentTable[0].FragmentBuffer = NULL;
+ }
+
+ if (HttpHeaders != NULL) {
+ FreePool (HttpHeaders);
+ }
+
+ if (HttpMsg->Headers != NULL) {
+ FreePool (HttpMsg->Headers);
+ }
+
+ if (HttpInstance->CacheBody != NULL) {
+ FreePool (HttpInstance->CacheBody);
+ HttpInstance->CacheBody = NULL;
+ }
+
+ 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 request is sent 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;
+ }
+
+ if (HttpInstance->LocalAddressIsIPv6) {
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // 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;
+
+ Status = HttpCreateTcp4RxEvent (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.RxToken.CompletionToken.Event != NULL) {
+ gBS->CloseEvent (Wrap->TcpWrap.RxToken.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
+ )
+{
+ HTTP_PROTOCOL *HttpInstance;
+
+ if (This == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ HttpInstance = HTTP_INSTANCE_FROM_PROTOCOL (This);
+ ASSERT (HttpInstance != NULL);
+
+ if (HttpInstance->LocalAddressIsIPv6) {
+ return EFI_UNSUPPORTED;
+ }
+
+ if (HttpInstance->Tcp4 == NULL || HttpInstance->State != HTTP_STATE_TCP_CONNECTED) {
+ return EFI_NOT_STARTED;
+ }
+
+ return HttpInstance->Tcp4->Poll (HttpInstance->Tcp4);
+}
diff --git a/NetworkPkg/HttpDxe/HttpImpl.h b/NetworkPkg/HttpDxe/HttpImpl.h
new file mode 100644
index 0000000000..49c8af1b21
--- /dev/null
+++ b/NetworkPkg/HttpDxe/HttpImpl.h
@@ -0,0 +1,239 @@
+/** @file
+ The header files of implementation of EFI_HTTP_PROTOCOL protocol interfaces.
+
+ 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_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/1.1"
+#define HTTP_VERSION_CRLF_STR " HTTP/1.1\r\n"
+#define HTTP_GET_STR "GET "
+#define HTTP_HEAD_STR "HEAD "
+//
+// Connect method has maximum length according to EFI_HTTP_METHOD defined in
+// UEFI2.5 spec so use this.
+//
+#define HTTP_MAXIMUM_METHOD_LEN sizeof ("CONNECT")
+
+/**
+ 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.
+ HttpConfigData->AccessPoint is NULL.
+ @retval EFI_NOT_STARTED The HTTP instance is not configured.
+
+**/
+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.
+
+ Except for GetModeData() and Configure(), 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->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_NO_MAPPING When using the default address, configuration (DHCP,
+ BOOTP, RARP, etc.) hasn't finished yet.
+ @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 request is sent 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/NetworkPkg/HttpDxe/HttpProto.c b/NetworkPkg/HttpDxe/HttpProto.c
new file mode 100644
index 0000000000..50ade4c230
--- /dev/null
+++ b/NetworkPkg/HttpDxe/HttpProto.c
@@ -0,0 +1,1165 @@
+/** @file
+ Miscellaneous routines for HttpDxe driver.
+
+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"
+
+/**
+ 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 TxToken for Tcp4->Transmit().
+
+ @param[in] Event The event signaled.
+ @param[in] Context The context.
+
+**/
+VOID
+EFIAPI
+HttpTcpTransmitNotify (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ HTTP_TOKEN_WRAP *Wrap;
+
+ if ((Event == NULL) || (Context == NULL)) {
+ return ;
+ }
+
+ Wrap = (HTTP_TOKEN_WRAP *) Context;
+ Wrap->HttpToken->Status = Wrap->TcpWrap.TxToken.CompletionToken.Status;
+ gBS->SignalEvent (Wrap->HttpToken->Event);
+
+ //
+ // Free resources.
+ //
+ if (Wrap->TcpWrap.TxToken.Packet.TxData->FragmentTable[0].FragmentBuffer != NULL) {
+ FreePool (Wrap->TcpWrap.TxToken.Packet.TxData->FragmentTable[0].FragmentBuffer);
+ }
+
+ if (Wrap->TcpWrap.TxToken.CompletionToken.Event != NULL) {
+ gBS->CloseEvent (Wrap->TcpWrap.TxToken.CompletionToken.Event);
+ }
+
+ Wrap->TcpWrap.IsTxDone = TRUE;
+
+ //
+ // Check pending TxTokens and sent out.
+ //
+ NetMapIterate (&Wrap->HttpInstance->TxTokens, HttpTcpTransmit, NULL);
+
+}
+
+/**
+ The notify function associated with RxToken for Tcp4->Receive ().
+
+ @param[in] Event The event signaled.
+ @param[in] Context The context.
+
+**/
+VOID
+EFIAPI
+HttpTcpReceiveNotify (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ HTTP_TOKEN_WRAP *Wrap;
+ NET_MAP_ITEM *Item;
+ UINTN Length;
+ EFI_STATUS Status;
+ HTTP_PROTOCOL *HttpInstance;
+
+ if ((Event == NULL) || (Context == NULL)) {
+ return ;
+ }
+
+ Wrap = (HTTP_TOKEN_WRAP *) Context;
+ if (EFI_ERROR (Wrap->TcpWrap.RxToken.CompletionToken.Status)) {
+ return ;
+ }
+
+ HttpInstance = Wrap->HttpInstance;
+
+ //
+ // Check whether we receive a complete HTTP message.
+ //
+ ASSERT (HttpInstance->MsgParser != NULL);
+
+ Length = (UINTN) Wrap->TcpWrap.RxData.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;
+ Wrap->HttpToken->Status = Wrap->TcpWrap.RxToken.CompletionToken.Status;
+
+ gBS->SignalEvent (Wrap->HttpToken->Event);
+
+ //
+ // Check pending RxTokens and receive the HTTP message.
+ //
+ NetMapIterate (&Wrap->HttpInstance->RxTokens, HttpTcpReceive, NULL);
+
+ FreePool (Wrap);
+}
+
+/**
+ Create events for the TCP4 connection token and TCP4 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
+HttpCreateTcp4ConnCloseEvent (
+ IN HTTP_PROTOCOL *HttpInstance
+ )
+{
+ EFI_STATUS Status;
+ //
+ // Create events for variuos asynchronous operations.
+ //
+ Status = gBS->CreateEvent (
+ EVT_NOTIFY_SIGNAL,
+ TPL_NOTIFY,
+ HttpCommonNotify,
+ &HttpInstance->IsConnDone,
+ &HttpInstance->ConnToken.CompletionToken.Event
+ );
+ if (EFI_ERROR (Status)) {
+ goto ERROR;
+ }
+
+ //
+ // Initialize CloseToken
+ //
+ Status = gBS->CreateEvent (
+ EVT_NOTIFY_SIGNAL,
+ TPL_NOTIFY,
+ HttpCommonNotify,
+ &HttpInstance->IsCloseDone,
+ &HttpInstance->CloseToken.CompletionToken.Event
+ );
+ if (EFI_ERROR (Status)) {
+ goto ERROR;
+ }
+
+
+ return EFI_SUCCESS;
+
+ERROR:
+ //
+ // Error handling
+ //
+ HttpCloseTcp4ConnCloseEvent (HttpInstance);
+
+ return Status;
+}
+
+
+/**
+ Close events in the TCP4 connection token and TCP4 close token.
+
+ @param[in] HttpInstance Pointer to HTTP_PROTOCOL structure.
+
+**/
+VOID
+HttpCloseTcp4ConnCloseEvent (
+ IN HTTP_PROTOCOL *HttpInstance
+ )
+{
+ ASSERT (HttpInstance != NULL);
+
+ if (NULL != HttpInstance->ConnToken.CompletionToken.Event) {
+ gBS->CloseEvent (HttpInstance->ConnToken.CompletionToken.Event);
+ }
+
+ if (NULL != HttpInstance->CloseToken.CompletionToken.Event) {
+ gBS->CloseEvent(HttpInstance->CloseToken.CompletionToken.Event);
+ }
+}
+
+/**
+ Create event for the TCP4 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
+HttpCreateTcp4TxEvent (
+ IN HTTP_TOKEN_WRAP *Wrap
+ )
+{
+ EFI_STATUS Status;
+ HTTP_PROTOCOL *HttpInstance;
+ HTTP_TCP_TOKEN_WRAP *TcpWrap;
+
+ HttpInstance = Wrap->HttpInstance;
+ TcpWrap = &Wrap->TcpWrap;
+
+ Status = gBS->CreateEvent (
+ EVT_NOTIFY_SIGNAL,
+ TPL_NOTIFY,
+ HttpTcpTransmitNotify,
+ Wrap,
+ &TcpWrap->TxToken.CompletionToken.Event
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ TcpWrap->TxData.Push = TRUE;
+ TcpWrap->TxData.Urgent = FALSE;
+ TcpWrap->TxData.FragmentCount = 1;
+ TcpWrap->TxToken.Packet.TxData = &Wrap->TcpWrap.TxData;
+ TcpWrap->TxToken.CompletionToken.Status = EFI_NOT_READY;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Create event for the TCP4 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
+HttpCreateTcp4RxEventForHeader (
+ IN HTTP_PROTOCOL *HttpInstance
+ )
+{
+ EFI_STATUS Status;
+
+
+ Status = gBS->CreateEvent (
+ EVT_NOTIFY_SIGNAL,
+ TPL_NOTIFY,
+ HttpCommonNotify,
+ &HttpInstance->IsRxDone,
+ &HttpInstance->RxToken.CompletionToken.Event
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ HttpInstance->RxData.FragmentCount = 1;
+ HttpInstance->RxToken.Packet.RxData = &HttpInstance->RxData;
+ HttpInstance->RxToken.CompletionToken.Status = EFI_NOT_READY;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Create event for the TCP4 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
+HttpCreateTcp4RxEvent (
+ IN HTTP_TOKEN_WRAP *Wrap
+ )
+{
+ EFI_STATUS Status;
+ HTTP_PROTOCOL *HttpInstance;
+ HTTP_TCP_TOKEN_WRAP *TcpWrap;
+
+ HttpInstance = Wrap->HttpInstance;
+ TcpWrap = &Wrap->TcpWrap;
+
+ Status = gBS->CreateEvent (
+ EVT_NOTIFY_SIGNAL,
+ TPL_NOTIFY,
+ HttpTcpReceiveNotify,
+ Wrap,
+ &TcpWrap->RxToken.CompletionToken.Event
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ TcpWrap->RxData.FragmentCount = 1;
+ TcpWrap->RxToken.Packet.RxData = &Wrap->TcpWrap.RxData;
+ TcpWrap->RxToken.CompletionToken.Status = EFI_NOT_READY;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Intiialize the HTTP_PROTOCOL structure to the unconfigured state.
+
+ @param[in] HttpSb The HTTP service private instance.
+ @param[in, out] HttpInstance Pointer to HTTP_PROTOCOL structure.
+
+ @retval EFI_SUCCESS HTTP_PROTOCOL structure is initialized successfully.
+ @retval Others Other error as indicated.
+
+**/
+EFI_STATUS
+HttpInitProtocol (
+ IN HTTP_SERVICE *HttpSb,
+ IN OUT HTTP_PROTOCOL *HttpInstance
+ )
+{
+ EFI_STATUS Status;
+ VOID *Interface;
+
+ ASSERT ((HttpSb != NULL) && (HttpInstance != NULL));
+
+ HttpInstance->Signature = HTTP_PROTOCOL_SIGNATURE;
+ CopyMem (&HttpInstance->Http, &mEfiHttpTemplate, sizeof (HttpInstance->Http));
+ HttpInstance->Service = HttpSb;
+
+ //
+ // Create TCP child.
+ //
+ Status = NetLibCreateServiceChild (
+ HttpInstance->Service->ControllerHandle,
+ HttpInstance->Service->ImageHandle,
+ &gEfiTcp4ServiceBindingProtocolGuid,
+ &HttpInstance->TcpChildHandle
+ );
+
+ if (EFI_ERROR (Status)) {
+ goto ON_ERROR;
+ }
+
+ Status = gBS->OpenProtocol (
+ HttpInstance->TcpChildHandle,
+ &gEfiTcp4ProtocolGuid,
+ (VOID **) &Interface,
+ HttpInstance->Service->ImageHandle,
+ HttpInstance->Service->ControllerHandle,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+
+ if (EFI_ERROR (Status)) {
+ goto ON_ERROR;
+ }
+
+ Status = gBS->OpenProtocol (
+ HttpInstance->TcpChildHandle,
+ &gEfiTcp4ProtocolGuid,
+ (VOID **) &HttpInstance->Tcp4,
+ HttpInstance->Service->ImageHandle,
+ HttpInstance->Handle,
+ EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
+ );
+ if (EFI_ERROR(Status)) {
+ goto ON_ERROR;
+ }
+
+ NetMapInit (&HttpInstance->TxTokens);
+ NetMapInit (&HttpInstance->RxTokens);
+
+ return EFI_SUCCESS;
+
+ON_ERROR:
+
+ if (HttpInstance->TcpChildHandle != NULL) {
+ gBS->CloseProtocol (
+ HttpInstance->TcpChildHandle,
+ &gEfiTcp4ProtocolGuid,
+ HttpInstance->Service->ImageHandle,
+ HttpInstance->Service->ControllerHandle
+ );
+
+ gBS->CloseProtocol (
+ HttpInstance->TcpChildHandle,
+ &gEfiTcp4ProtocolGuid,
+ HttpInstance->Service->ImageHandle,
+ HttpInstance->Handle
+ );
+
+ NetLibDestroyServiceChild (
+ HttpInstance->Service->ControllerHandle,
+ HttpInstance->Service->ImageHandle,
+ &gEfiTcp4ServiceBindingProtocolGuid,
+ HttpInstance->TcpChildHandle
+ );
+ }
+
+ return Status;
+
+}
+
+/**
+ 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);
+
+ HttpCloseTcp4ConnCloseEvent (HttpInstance);
+
+ 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;
+ }
+
+ NetMapClean (&HttpInstance->TxTokens);
+ NetMapClean (&HttpInstance->RxTokens);
+
+ if (HttpInstance->TcpChildHandle != NULL) {
+ gBS->CloseProtocol (
+ HttpInstance->TcpChildHandle,
+ &gEfiTcp4ProtocolGuid,
+ HttpInstance->Service->ImageHandle,
+ HttpInstance->Service->ControllerHandle
+ );
+
+ gBS->CloseProtocol (
+ HttpInstance->TcpChildHandle,
+ &gEfiTcp4ProtocolGuid,
+ HttpInstance->Service->ImageHandle,
+ HttpInstance->Handle
+ );
+
+ NetLibDestroyServiceChild (
+ HttpInstance->Service->ControllerHandle,
+ HttpInstance->Service->ImageHandle,
+ &gEfiTcp4ServiceBindingProtocolGuid,
+ HttpInstance->TcpChildHandle
+ );
+ }
+}
+
+/**
+ 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;
+
+ //
+ // Create events for variuos asynchronous operations.
+ //
+ HttpInstance->IsConnDone = FALSE;
+
+ //
+ // Connect to Http server
+ //
+ HttpInstance->ConnToken.CompletionToken.Status = EFI_NOT_READY;
+ Status = HttpInstance->Tcp4->Connect (HttpInstance->Tcp4, &HttpInstance->ConnToken);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "HttpCreateConnection: Tcp4->Connect() = %r\n", Status));
+ return Status;
+ }
+
+ while (!HttpInstance->IsConnDone) {
+ HttpInstance->Tcp4->Poll (HttpInstance->Tcp4);
+ }
+
+ Status = HttpInstance->ConnToken.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;
+
+ HttpInstance->CloseToken.AbortOnClose = TRUE;
+ HttpInstance->IsCloseDone = FALSE;
+
+
+ Status = HttpInstance->Tcp4->Close (HttpInstance->Tcp4, &HttpInstance->CloseToken);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ while (!HttpInstance->IsCloseDone) {
+ HttpInstance->Tcp4->Poll (HttpInstance->Tcp4);
+ }
+
+ HttpInstance->State = HTTP_STATE_TCP_CLOSED;
+ return Status;
+}
+
+/**
+ 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;
+ HTTP_TCP_TOKEN_WRAP *TcpWrap;
+
+ ASSERT (HttpInstance != NULL);
+ TcpWrap = &Wrap->TcpWrap;
+
+
+ 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 = HttpCreateTcp4ConnCloseEvent (HttpInstance);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = HttpCreateTcp4TxEvent (Wrap);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ HttpInstance->State = HTTP_STATE_TCP_CONFIGED;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Check existing TCP connection, if in error state, receover TCP4 connection.
+
+ @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) {
+ HttpCloseConnection(HttpInstance);
+ }
+
+ return HttpCreateConnection (HttpInstance);
+}
+
+/**
+ Send the HTTP message through TCP4.
+
+ @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
+HttpTransmitTcp4 (
+ IN HTTP_PROTOCOL *HttpInstance,
+ IN HTTP_TOKEN_WRAP *Wrap,
+ IN UINT8 *TxString,
+ IN UINTN TxStringLen
+ )
+{
+ EFI_STATUS Status;
+ EFI_TCP4_IO_TOKEN *TxToken;
+ EFI_TCP4_PROTOCOL *Tcp4;
+
+ Tcp4 = HttpInstance->Tcp4;
+ TxToken = &Wrap->TcpWrap.TxToken;
+
+ TxToken->Packet.TxData->DataLength = (UINT32) TxStringLen;
+ TxToken->Packet.TxData->FragmentTable[0].FragmentLength = (UINT32) TxStringLen;
+ TxToken->Packet.TxData->FragmentTable[0].FragmentBuffer = (VOID *) TxString;
+ TxToken->CompletionToken.Status = EFI_NOT_READY;
+
+ Wrap->TcpWrap.IsTxDone = FALSE;
+ Status = Tcp4->Transmit (Tcp4, TxToken);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "Transmit failed: %r\n", Status));
+ return Status;
+ }
+
+ return Status;
+}
+
+/**
+ Translate the status code in HTTP message to EFI_HTTP_STATUS_CODE defined
+ in UEFI 2.5 specification.
+
+ @param[in] StatusCode The status code value in HTTP message.
+
+ @return Value defined in EFI_HTTP_STATUS_CODE .
+
+**/
+EFI_HTTP_STATUS_CODE
+HttpMappingToStatusCode (
+ IN UINTN StatusCode
+ )
+{
+ switch (StatusCode) {
+ case 100:
+ return HTTP_STATUS_100_CONTINUE;
+ case 101:
+ return HTTP_STATUS_101_SWITCHING_PROTOCOLS;
+ case 200:
+ return HTTP_STATUS_200_OK;
+ case 201:
+ return HTTP_STATUS_201_CREATED;
+ case 202:
+ return HTTP_STATUS_202_ACCEPTED;
+ case 203:
+ return HTTP_STATUS_203_NON_AUTHORITATIVE_INFORMATION;
+ case 204:
+ return HTTP_STATUS_204_NO_CONTENT;
+ case 205:
+ return HTTP_STATUS_205_RESET_CONTENT;
+ case 206:
+ return HTTP_STATUS_206_PARTIAL_CONTENT;
+ case 300:
+ return HTTP_STATUS_300_MULTIPLE_CHIOCES;
+ case 301:
+ return HTTP_STATUS_301_MOVED_PERMANENTLY;
+ case 302:
+ return HTTP_STATUS_302_FOUND;
+ case 303:
+ return HTTP_STATUS_303_SEE_OTHER;
+ case 304:
+ return HTTP_STATUS_304_NOT_MODIFIED;
+ case 305:
+ return HTTP_STATUS_305_USE_PROXY;
+ case 307:
+ return HTTP_STATUS_307_TEMPORARY_REDIRECT;
+ case 400:
+ return HTTP_STATUS_400_BAD_REQUEST;
+ case 401:
+ return HTTP_STATUS_401_UNAUTHORIZED;
+ case 402:
+ return HTTP_STATUS_402_PAYMENT_REQUIRED;
+ case 403:
+ return HTTP_STATUS_403_FORBIDDEN;
+ case 404:
+ return HTTP_STATUS_404_NOT_FOUND;
+ case 405:
+ return HTTP_STATUS_405_METHOD_NOT_ALLOWED;
+ case 406:
+ return HTTP_STATUS_406_NOT_ACCEPTABLE;
+ case 407:
+ return HTTP_STATUS_407_PROXY_AUTHENTICATION_REQUIRED;
+ case 408:
+ return HTTP_STATUS_408_REQUEST_TIME_OUT;
+ case 409:
+ return HTTP_STATUS_409_CONFLICT;
+ case 410:
+ return HTTP_STATUS_410_GONE;
+ case 411:
+ return HTTP_STATUS_411_LENGTH_REQUIRED;
+ case 412:
+ return HTTP_STATUS_412_PRECONDITION_FAILED;
+ case 413:
+ return HTTP_STATUS_413_REQUEST_ENTITY_TOO_LARGE;
+ case 414:
+ return HTTP_STATUS_414_REQUEST_URI_TOO_LARGE;
+ case 415:
+ return HTTP_STATUS_415_UNSUPPORETD_MEDIA_TYPE;
+ case 416:
+ return HTTP_STATUS_416_REQUESTED_RANGE_NOT_SATISFIED;
+ case 417:
+ return HTTP_STATUS_417_EXPECTATION_FAILED;
+ case 500:
+ return HTTP_STATUS_500_INTERNAL_SERVER_ERROR;
+ case 501:
+ return HTTP_STATUS_501_NOT_IMIPLEMENTED;
+ case 502:
+ return HTTP_STATUS_502_BAD_GATEWAY;
+ case 503:
+ return HTTP_STATUS_503_SERVICE_UNAVAILABLE;
+ case 504:
+ return HTTP_STATUS_504_GATEWAY_TIME_OUT;
+ case 505:
+ return HTTP_STATUS_505_HTTP_VERSION_NOT_SUPPORTED;
+
+ default:
+ return HTTP_STATUS_UNSUPPORTED_STATUS;
+ }
+}
+
+/**
+ Check whether the user's token or event has already
+ been enqueue on HTTP TxToken or RxToken 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 TxToken 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
+ )
+{
+ HTTP_TOKEN_WRAP *ValueInItem;
+
+ ValueInItem = (HTTP_TOKEN_WRAP *) Item->Value;
+
+ if (!ValueInItem->TcpWrap.IsTxDone) {
+ return EFI_NOT_READY;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Transmit the HTTP mssage by processing the associated HTTP token.
+
+ @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_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 *RequestStr;
+ CHAR8 *Url;
+
+ ValueInItem = (HTTP_TOKEN_WRAP *) Item->Value;
+ if (ValueInItem->TcpWrap.IsTxDone) {
+ return EFI_SUCCESS;
+ }
+
+ //
+ // Parse the URI of the remote host.
+ //
+ Url = AllocatePool (StrLen (ValueInItem->HttpToken->Message->Data.Request->Url) + 1);
+ if (Url == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ UnicodeStrToAsciiStr (ValueInItem->HttpToken->Message->Data.Request->Url, Url);
+
+ //
+ // Create request message.
+ //
+ RequestStr = HttpGenRequestString (
+ ValueInItem->HttpInstance,
+ ValueInItem->HttpToken->Message,
+ Url
+ );
+ FreePool (Url);
+ if (RequestStr == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ //
+ // Transmit the request message.
+ //
+ Status = HttpTransmitTcp4 (
+ ValueInItem->HttpInstance,
+ ValueInItem,
+ (UINT8*) RequestStr,
+ AsciiStrLen (RequestStr)
+ );
+ FreePool (RequestStr);
+ return Status;
+}
+
+/**
+ Receive the HTTP response by processing the associated HTTP token.
+
+ @param[in] Map The container of RxToken.
+ @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);
+}
+
+/**
+ Generate HTTP request string.
+
+ @param[in] HttpInstance Pointer to HTTP_PROTOCOL structure.
+ @param[in] Message Pointer to storage containing HTTP message data.
+ @param[in] Url The URL of a remote host.
+
+ @return Pointer to the created HTTP request string.
+ @return NULL if any error occured.
+
+**/
+CHAR8 *
+HttpGenRequestString (
+ IN HTTP_PROTOCOL *HttpInstance,
+ IN EFI_HTTP_MESSAGE *Message,
+ IN CHAR8 *Url
+ )
+{
+ EFI_STATUS Status;
+ UINTN StrLength;
+ UINT8 *Request;
+ UINT8 *RequestPtr;
+ UINTN HttpHdrSize;
+ UINTN MsgSize;
+ BOOLEAN Success;
+ VOID *HttpHdr;
+ EFI_HTTP_HEADER **AppendList;
+ UINTN Index;
+
+ ASSERT (HttpInstance != NULL);
+ ASSERT (Message != NULL);
+
+ DEBUG ((EFI_D_ERROR, "HttpMethod - %x\n", Message->Data.Request->Method));
+
+ Request = NULL;
+ Success = FALSE;
+ HttpHdr = NULL;
+ AppendList = NULL;
+
+ //
+ // Build AppendList
+ //
+ AppendList = AllocateZeroPool (sizeof (EFI_HTTP_HEADER *) * (Message->HeaderCount));
+ if (AppendList == NULL) {
+ return NULL;
+ }
+
+ for(Index = 0; Index < Message->HeaderCount; Index++){
+ AppendList[Index] = &Message->Headers[Index];
+ }
+
+ //
+ // Build raw unformatted HTTP headers.
+ //
+ Status = HttpUtilitiesBuild (
+ 0,
+ NULL,
+ 0,
+ NULL,
+ Message->HeaderCount,
+ AppendList,
+ &HttpHdrSize,
+ &HttpHdr
+ );
+ FreePool (AppendList);
+ if (EFI_ERROR (Status) || HttpHdr == NULL) {
+ return NULL;
+ }
+
+ //
+ // Calculate HTTP message length.
+ //
+ MsgSize = Message->BodyLength + HTTP_MAXIMUM_METHOD_LEN + AsciiStrLen (Url) +
+ AsciiStrLen (HTTP_VERSION_CRLF_STR) + HttpHdrSize;
+ Request = AllocateZeroPool (MsgSize);
+ if (Request == NULL) {
+ goto Exit;
+ }
+
+ RequestPtr = Request;
+ //
+ // Construct header request
+ //
+ switch (Message->Data.Request->Method) {
+ case HttpMethodGet:
+ StrLength = sizeof (HTTP_GET_STR) - 1;
+ CopyMem (RequestPtr, HTTP_GET_STR, StrLength);
+ RequestPtr += StrLength;
+ break;
+ case HttpMethodHead:
+ StrLength = sizeof (HTTP_HEAD_STR) - 1;
+ CopyMem (RequestPtr, HTTP_HEAD_STR, StrLength);
+ RequestPtr += StrLength;
+ break;
+ default:
+ ASSERT (FALSE);
+ goto Exit;
+ }
+
+ StrLength = AsciiStrLen (Url);
+ CopyMem (RequestPtr, Url, StrLength);
+ RequestPtr += StrLength;
+
+ StrLength = sizeof (HTTP_VERSION_CRLF_STR) - 1;
+ CopyMem (RequestPtr, HTTP_VERSION_CRLF_STR, StrLength);
+ RequestPtr += StrLength;
+
+ //
+ // Construct header
+ //
+ CopyMem (RequestPtr, HttpHdr, HttpHdrSize);
+ RequestPtr += HttpHdrSize;
+
+ //
+ // Construct body
+ //
+ if (Message->Body != NULL) {
+ CopyMem (RequestPtr, Message->Body, Message->BodyLength);
+ RequestPtr += Message->BodyLength;
+ }
+
+ //
+ // Done
+ //
+ *RequestPtr = 0;
+ Success = TRUE;
+
+Exit:
+
+ if (!Success) {
+ if (Request != NULL) {
+ FreePool (Request);
+ }
+
+ Request = NULL;
+ }
+
+ if (HttpHdr != NULL) {
+ FreePool (HttpHdr);
+ }
+
+ return (CHAR8*) Request;
+}
diff --git a/NetworkPkg/HttpDxe/HttpProto.h b/NetworkPkg/HttpDxe/HttpProto.h
new file mode 100644
index 0000000000..ca4b7b6035
--- /dev/null
+++ b/NetworkPkg/HttpDxe/HttpProto.h
@@ -0,0 +1,457 @@
+/** @file
+ The header files of miscellaneous routines for HttpDxe driver.
+
+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_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_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
+
+typedef struct _HTTP_SERVICE {
+ UINT32 Signature;
+ EFI_SERVICE_BINDING_PROTOCOL ServiceBinding;
+ EFI_HANDLE ImageHandle;
+ EFI_HANDLE ControllerHandle;
+ LIST_ENTRY ChildrenList;
+ UINTN ChildrenNumber;
+ EFI_HANDLE TcpChildHandle;
+ INTN State;
+} HTTP_SERVICE;
+
+typedef struct {
+ EFI_TCP4_IO_TOKEN TxToken;
+ EFI_TCP4_TRANSMIT_DATA TxData;
+ BOOLEAN IsTxDone;
+ EFI_TCP4_IO_TOKEN RxToken;
+ EFI_TCP4_RECEIVE_DATA RxData;
+ BOOLEAN IsRxDone;
+ UINTN BodyLen;
+ EFI_HTTP_METHOD Method;
+} HTTP_TCP_TOKEN_WRAP;
+
+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_HANDLE TcpChildHandle;
+ EFI_TCP4_PROTOCOL *Tcp4;
+ EFI_TCP4_CONFIG_DATA Tcp4CfgData;
+ EFI_TCP4_OPTION Tcp4Option;
+
+ EFI_TCP4_CONNECTION_TOKEN ConnToken;
+ BOOLEAN IsConnDone;
+ EFI_TCP4_CLOSE_TOKEN CloseToken;
+ BOOLEAN IsCloseDone;
+
+ CHAR8 *RemoteHost;
+ UINT16 RemotePort;
+ EFI_IPv4_ADDRESS RemoteAddr;
+ //
+ // RxToken used for receiving HTTP header.
+ //
+ EFI_TCP4_IO_TOKEN RxToken;
+ EFI_TCP4_RECEIVE_DATA RxData;
+ BOOLEAN IsRxDone;
+
+ 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;
+
+ NET_MAP TxTokens;
+ NET_MAP RxTokens;
+} 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 TCP4 connection token and TCP4 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
+HttpCreateTcp4ConnCloseEvent (
+ IN HTTP_PROTOCOL *HttpInstance
+ );
+
+/**
+ Close events in the TCP4 connection token and TCP4 close token.
+
+ @param[in] HttpInstance Pointer to HTTP_PROTOCOL structure.
+
+**/
+VOID
+HttpCloseTcp4ConnCloseEvent (
+ IN HTTP_PROTOCOL *HttpInstance
+ );
+
+/**
+ Create event for the TCP4 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
+HttpCreateTcp4TxEvent (
+ IN HTTP_TOKEN_WRAP *Wrap
+ );
+
+/**
+ Create event for the TCP4 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
+HttpCreateTcp4RxEventForHeader (
+ IN HTTP_PROTOCOL *HttpInstance
+ );
+
+/**
+ Create event for the TCP4 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
+HttpCreateTcp4RxEvent (
+ IN HTTP_TOKEN_WRAP *Wrap
+ );
+
+/**
+ Intiialize the HTTP_PROTOCOL structure to the unconfigured state.
+
+ @param[in] HttpSb The HTTP service private instance.
+ @param[in, out] HttpInstance Pointer to HTTP_PROTOCOL structure.
+
+ @retval EFI_SUCCESS HTTP_PROTOCOL structure is initialized successfully.
+ @retval Others Other error as indicated.
+
+**/
+EFI_STATUS
+HttpInitProtocol (
+ IN HTTP_SERVICE *HttpSb,
+ IN OUT HTTP_PROTOCOL *HttpInstance
+ );
+
+/**
+ 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
+ );
+
+/**
+ Check existing TCP connection, if in error state, receover TCP4 connection.
+
+ @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
+ );
+
+/**
+ Send the HTTP message through TCP4.
+
+ @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
+HttpTransmitTcp4 (
+ IN HTTP_PROTOCOL *HttpInstance,
+ IN HTTP_TOKEN_WRAP *Wrap,
+ IN UINT8 *TxString,
+ IN UINTN TxStringLen
+ );
+
+/**
+ Translate the status code in HTTP message to EFI_HTTP_STATUS_CODE defined
+ in UEFI 2.5 specification.
+
+ @param[in] StatusCode The status code value in HTTP message.
+
+ @return Value defined in EFI_HTTP_STATUS_CODE .
+
+**/
+EFI_HTTP_STATUS_CODE
+HttpMappingToStatusCode (
+ IN UINTN StatusCode
+ );
+
+/**
+ Check whether the user's token or event has already
+ been enqueue on HTTP TxToken or RxToken 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 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
+ );
+
+/**
+ Transmit the HTTP mssage by processing the associated HTTP token.
+
+ @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_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 RxToken.
+ @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
+ );
+
+/**
+ Generate HTTP request string.
+
+ @param[in] HttpInstance Pointer to HTTP_PROTOCOL structure.
+ @param[in] Message Pointer to storage containing HTTP message data.
+ @param[in] Url The URL of a remote host.
+
+ @return Pointer to the created HTTP request string.
+ @return NULL if any error occured.
+
+**/
+CHAR8 *
+HttpGenRequestString (
+ IN HTTP_PROTOCOL *HttpInstance,
+ IN EFI_HTTP_MESSAGE *Message,
+ IN CHAR8 *Url
+ );
+
+/**
+ 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/NetworkPkg/HttpDxe/HttpUtilities.c b/NetworkPkg/HttpDxe/HttpUtilities.c
new file mode 100644
index 0000000000..c2a99a40bf
--- /dev/null
+++ b/NetworkPkg/HttpDxe/HttpUtilities.c
@@ -0,0 +1,622 @@
+/** @file
+
+Implementation of help functions to parse HTTP message header.
+
+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"
+
+/**
+ Get the next string, which is distinguished by specified seperator.
+
+ @param[in] String Pointer to the string.
+ @param[in] Seperator Specified seperator used to distinguish where is the beginning
+ of next string.
+
+ @return Pointer to the next string.
+ @return NULL if not find or String is NULL.
+
+**/
+CHAR8 *
+AsciiStrGetNextToken (
+ IN CONST CHAR8 *String,
+ IN CHAR8 Seperator
+ )
+{
+ CONST CHAR8 *Token;
+
+ Token = String;
+ while (TRUE) {
+ if (*Token == 0) {
+ return NULL;
+ }
+ if (*Token == Seperator) {
+ return (CHAR8 *) (Token + 1);
+ }
+ Token++;
+ }
+}
+
+/**
+ Free existing HeaderFields.
+
+ @param[in] HeaderFields Pointer to array of key/value header pairs waitting for free.
+ @param[in] FieldCount The number of header pairs in HeaderFields.
+
+**/
+VOID
+FreeHeaderFields (
+ IN EFI_HTTP_HEADER *HeaderFields,
+ IN UINTN FieldCount
+ )
+{
+ UINTN Index;
+
+ if (HeaderFields != NULL) {
+ for (Index = 0; Index < FieldCount; Index++) {
+ if(HeaderFields[Index].FieldName != NULL) {
+ FreePool (HeaderFields[Index].FieldName);
+ }
+ if(HeaderFields[Index].FieldValue != NULL) {
+ FreePool (HeaderFields[Index].FieldValue);
+ }
+ }
+
+ FreePool (HeaderFields);
+ }
+}
+
+/**
+ Find required header field in HeaderFields.
+
+ @param[in] HeaderFields Pointer to array of key/value header pairs.
+ @param[in] FieldCount The number of header pairs.
+ @param[in] FieldName Pointer to header field's name.
+
+ @return Pointer to the queried header field.
+ @return NULL if not find this required header field.
+
+**/
+EFI_HTTP_HEADER *
+FindHttpHeader (
+ IN EFI_HTTP_HEADER *HeaderFields,
+ IN UINTN FieldCount,
+ IN CHAR8 *FieldName
+ )
+{
+ UINTN Index;
+
+ for (Index = 0; Index < FieldCount; Index++) {
+ if (AsciiStrCmp (FieldName, HeaderFields[Index].FieldName) == 0) {
+ //
+ // Find the required header field.
+ //
+ return &HeaderFields[Index];
+ }
+ }
+ return NULL;
+}
+
+/**
+ Check whether header field called FieldName is in DeleteList.
+
+ @param[in] DeleteList Pointer to array of key/value header pairs.
+ @param[in] DeleteCount The number of header pairs.
+ @param[in] FieldName Pointer to header field's name.
+
+ @return TRUE if FieldName is not in DeleteList, that means this header field is valid.
+ @return FALSE if FieldName is in DeleteList, that means this header field is invalid.
+
+**/
+BOOLEAN
+IsValidHttpHeader (
+ IN CHAR8 *DeleteList[],
+ IN UINTN DeleteCount,
+ IN CHAR8 *FieldName
+ )
+{
+ UINTN Index;
+
+ for (Index = 0; Index < DeleteCount; Index++) {
+ if (AsciiStrCmp (FieldName, DeleteList[Index]) == 0) {
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}
+
+/**
+ Set FieldName and FieldValue into specified HttpHeader.
+
+ @param[in] HttpHeader Specified HttpHeader.
+ @param[in] FieldName FieldName of this HttpHeader.
+ @param[in] FieldValue FieldValue of this HttpHeader.
+
+
+ @retval EFI_SUCCESS The FieldName and FieldValue are set into HttpHeader successfully.
+ @retval EFI_OUT_OF_RESOURCES Failed to allocate resources.
+
+**/
+EFI_STATUS
+SetFieldNameAndValue (
+ IN EFI_HTTP_HEADER *HttpHeader,
+ IN CHAR8 *FieldName,
+ IN CHAR8 *FieldValue
+ )
+{
+ UINTN FieldNameSize;
+ UINTN FieldValueSize;
+
+ if (HttpHeader->FieldName != NULL) {
+ FreePool (HttpHeader->FieldName);
+ }
+ if (HttpHeader->FieldValue != NULL) {
+ FreePool (HttpHeader->FieldValue);
+ }
+
+ FieldNameSize = AsciiStrSize (FieldName);
+ HttpHeader->FieldName = AllocateZeroPool (FieldNameSize);
+ if (HttpHeader->FieldName == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ CopyMem (HttpHeader->FieldName, FieldName, FieldNameSize);
+ HttpHeader->FieldName[FieldNameSize - 1] = 0;
+
+ FieldValueSize = AsciiStrSize (FieldValue);
+ HttpHeader->FieldValue = AllocateZeroPool (FieldValueSize);
+ if (HttpHeader->FieldValue == NULL) {
+ FreePool (HttpHeader->FieldName);
+ return EFI_OUT_OF_RESOURCES;
+ }
+ CopyMem (HttpHeader->FieldValue, FieldValue, FieldValueSize);
+ HttpHeader->FieldValue[FieldValueSize - 1] = 0;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Get one key/value header pair from the raw string.
+
+ @param[in] String Pointer to the raw string.
+ @param[out] FieldName Pointer to header field's name.
+ @param[out] FieldValue Pointer to header field's value.
+
+ @return Pointer to the next raw string.
+ @return NULL if no key/value header pair from this raw string.
+
+**/
+CHAR8 *
+GetFieldNameAndValue (
+ IN CHAR8 *String,
+ OUT CHAR8 **FieldName,
+ OUT CHAR8 **FieldValue
+ )
+{
+ CHAR8 *FieldNameStr;
+ CHAR8 *FieldValueStr;
+ CHAR8 *StrPtr;
+
+ if (String == NULL || FieldName == NULL || FieldValue == NULL) {
+ return NULL;
+ }
+
+ *FieldName = NULL;
+ *FieldValue = NULL;
+ FieldNameStr = NULL;
+ FieldValueStr = NULL;
+ StrPtr = NULL;
+
+ //
+ // Each header field consists of a name followed by a colon (":") and the field value.
+ //
+ FieldNameStr = String;
+ FieldValueStr = AsciiStrGetNextToken (FieldNameStr, ':');
+ if (FieldValueStr == NULL) {
+ return NULL;
+ }
+
+ *(FieldValueStr - 1) = 0; /// Replace ':' with 0
+
+ //
+ // The field value MAY be preceded by any amount of LWS, though a single SP is preferred.
+ //
+ while (TRUE) {
+ if(*FieldValueStr == ' ' || *FieldValueStr == '\t') {
+ FieldValueStr ++;
+ } else if (*FieldValueStr == '\r' && *(FieldValueStr + 1) == '\n' &&
+ (*(FieldValueStr + 2) == ' ' || *(FieldValueStr + 2) == '\t')) {
+ FieldValueStr = FieldValueStr + 3;
+ } else {
+ break;
+ }
+ }
+
+ //
+ // Header fields can be extended over multiple lines by preceding each extra
+ // line with at least one SP or HT.
+ //
+ StrPtr = FieldValueStr;
+ do {
+ StrPtr = AsciiStrGetNextToken (StrPtr, '\r');
+ if (StrPtr == NULL || *StrPtr != '\n') {
+ return NULL;
+ }
+
+ StrPtr++;
+ } while (*StrPtr == ' ' || *StrPtr == '\t');
+
+ //
+ // Replace '\r' with 0.
+ //
+ *(StrPtr - 2) = 0;
+
+ //
+ // Get FieldName and FieldValue.
+ //
+ *FieldName = FieldNameStr;
+ *FieldValue = FieldValueStr;
+
+ return StrPtr;
+}
+
+/**
+ This function is used to manage the headers portion of an HTTP message by providing
+ the ability to add, remove, or replace HTTP headers.
+
+ @param[in] SeedMessageSize Size in bytes of the initial HTTP header. This can be zero.
+ @param[in] SeedMessage Initial raw unformatted HTTP header to be used as a base for
+ building a new unformatted HTTP header. If NULL, SeedMessageSize
+ is ignored. The buffer containing this message will be allocated
+ and released by the caller.
+ @param[in] DeleteCount Number of null-terminated HTTP header field names in DeleteList.
+ @param[in] DeleteList List of null-terminated HTTP header field names to remove from SeedMessage.
+ Only the field names are in this list because the field values are irrelevant
+ to this operation. If NULL, DeleteCount is ignored. The buffer containing the
+ list will be allocated and released by the caller.
+ @param[in] AppendCount Number of header fields in AppendList.
+ @param[in] AppendList List of HTTP headers to populate NewMessage with. If SeedMessage is not NULL,
+ AppendList will be appended to the existing list from SeedMessage in NewMessage.
+ @param[out] NewMessageSize Pointer to the size in bytes of the new unformatted HTTP header in NewMessage.
+ @param[out] NewMessage Pointer to a new unformatted HTTP header. The storage for this NewMessage is
+ allocated by the driver publishing this protocol, and must be freed by the caller.
+
+ @retval EFI_SUCCESS Add, remove, and replace operations succeeded.
+ @retval EFI_OUT_OF_RESOURCES Could not allocate memory for NewMessage.
+
+**/
+EFI_STATUS
+HttpUtilitiesBuild(
+ IN UINTN SeedMessageSize,
+ IN VOID *SeedMessage, OPTIONAL
+ IN UINTN DeleteCount,
+ IN CHAR8 *DeleteList[], OPTIONAL
+ IN UINTN AppendCount,
+ IN EFI_HTTP_HEADER *AppendList[], OPTIONAL
+ OUT UINTN *NewMessageSize,
+ OUT VOID **NewMessage
+ )
+{
+ EFI_STATUS Status;
+ EFI_HTTP_HEADER *SeedHeaderFields;
+ UINTN SeedFieldCount;
+ UINTN Index;
+ EFI_HTTP_HEADER *TempHeaderFields;
+ UINTN TempFieldCount;
+ EFI_HTTP_HEADER *NewHeaderFields;
+ UINTN NewFieldCount;
+ EFI_HTTP_HEADER *HttpHeader;
+ UINTN StrLength;
+ UINT8 *NewMessagePtr;
+
+ SeedHeaderFields = NULL;
+ SeedFieldCount = 0;
+ TempHeaderFields = NULL;
+ TempFieldCount = 0;
+ NewHeaderFields = NULL;
+ NewFieldCount = 0;
+
+ HttpHeader = NULL;
+ StrLength = 0;
+ NewMessagePtr = NULL;
+ *NewMessageSize = 0;
+ Status = EFI_SUCCESS;
+
+ if (SeedMessage != NULL) {
+ Status = HttpUtilitiesParse (
+ SeedMessage,
+ SeedMessageSize,
+ &SeedHeaderFields,
+ &SeedFieldCount
+ );
+ if (EFI_ERROR (Status)){
+ goto ON_EXIT;
+ }
+ }
+
+ //
+ // Handle DeleteList
+ //
+ if(SeedFieldCount != 0 && DeleteCount != 0) {
+ TempHeaderFields = AllocateZeroPool (SeedFieldCount * sizeof(EFI_HTTP_HEADER));
+ if (TempHeaderFields == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto ON_EXIT;
+ }
+
+ for (Index = 0, TempFieldCount = 0; Index < SeedFieldCount; Index++) {
+ //
+ // Check whether each SeedHeaderFields member is in DeleteList
+ //
+ if (IsValidHttpHeader(DeleteList, DeleteCount, SeedHeaderFields[Index].FieldName)) {
+ Status = SetFieldNameAndValue(
+ &TempHeaderFields[TempFieldCount],
+ SeedHeaderFields[Index].FieldName,
+ SeedHeaderFields[Index].FieldValue
+ );
+ if (EFI_ERROR (Status)){
+ goto ON_EXIT;
+ }
+ TempFieldCount++;
+ }
+ }
+ } else {
+ TempHeaderFields = SeedHeaderFields;
+ TempFieldCount = SeedFieldCount;
+ }
+
+ //
+ // Handle AppendList
+ //
+ NewHeaderFields = AllocateZeroPool ((TempFieldCount + AppendCount) * sizeof(EFI_HTTP_HEADER));
+ if (NewHeaderFields == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto ON_EXIT;
+ }
+
+ for (Index = 0; Index < TempFieldCount; Index++) {
+ Status = SetFieldNameAndValue(
+ &NewHeaderFields[Index],
+ TempHeaderFields[Index].FieldName,
+ TempHeaderFields[Index].FieldValue
+ );
+ if (EFI_ERROR (Status)){
+ goto ON_EXIT;
+ }
+ }
+
+ NewFieldCount = TempFieldCount;
+
+ for (Index = 0; Index < AppendCount; Index++) {
+ HttpHeader = FindHttpHeader(NewHeaderFields, NewFieldCount, AppendList[Index]->FieldName);
+ if(HttpHeader != NULL) {
+ Status = SetFieldNameAndValue(
+ HttpHeader,
+ AppendList[Index]->FieldName,
+ AppendList[Index]->FieldValue
+ );
+ if (EFI_ERROR (Status)){
+ goto ON_EXIT;
+ }
+ } else {
+ Status = SetFieldNameAndValue
+ (&NewHeaderFields[NewFieldCount],
+ AppendList[Index]->FieldName,
+ AppendList[Index]->FieldValue
+ );
+ if (EFI_ERROR (Status)){
+ goto ON_EXIT;
+ }
+ NewFieldCount++;
+ }
+ }
+
+ //
+ // Calculate NewMessageSize, then build NewMessage
+ //
+ for (Index = 0; Index < NewFieldCount; Index++) {
+ HttpHeader = &NewHeaderFields[Index];
+
+ StrLength = AsciiStrLen (HttpHeader->FieldName);
+ *NewMessageSize += StrLength;
+
+ StrLength = sizeof(": ") - 1;
+ *NewMessageSize += StrLength;
+
+ StrLength = AsciiStrLen (HttpHeader->FieldValue);
+ *NewMessageSize += StrLength;
+
+ StrLength = sizeof(HTTP_CRLF_STR) - 1;
+ *NewMessageSize += StrLength;
+ }
+ StrLength = sizeof(HTTP_CRLF_STR) - 1;
+ *NewMessageSize += StrLength;
+ //
+ // Final 0 for end flag.
+ //
+ *NewMessageSize += 1;
+
+ *NewMessage = AllocateZeroPool (*NewMessageSize);
+ if (*NewMessage == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto ON_EXIT;
+ }
+
+ NewMessagePtr = (UINT8 *)(*NewMessage);
+
+ for (Index = 0; Index < NewFieldCount; Index++) {
+ HttpHeader = &NewHeaderFields[Index];
+
+ StrLength = AsciiStrLen (HttpHeader->FieldName);
+ CopyMem (NewMessagePtr, HttpHeader->FieldName, StrLength);
+ NewMessagePtr += StrLength;
+
+ StrLength = sizeof(": ") - 1;
+ CopyMem (NewMessagePtr, ": ", StrLength);
+ NewMessagePtr += StrLength;
+
+ StrLength = AsciiStrLen (HttpHeader->FieldValue);
+ CopyMem (NewMessagePtr, HttpHeader->FieldValue, StrLength);
+ NewMessagePtr += StrLength;
+
+ StrLength = sizeof(HTTP_CRLF_STR) - 1;
+ CopyMem (NewMessagePtr, HTTP_CRLF_STR, StrLength);
+ NewMessagePtr += StrLength;
+ }
+ StrLength = sizeof(HTTP_CRLF_STR) - 1;
+ CopyMem (NewMessagePtr, HTTP_CRLF_STR, StrLength);
+ NewMessagePtr += StrLength;
+
+ *NewMessagePtr = 0;
+
+ ASSERT (*NewMessageSize == (UINTN) NewMessagePtr - (UINTN) (*NewMessage) + 1);
+
+ //
+ // Free allocated buffer
+ //
+ON_EXIT:
+ if(SeedHeaderFields != NULL) {
+ FreeHeaderFields(SeedHeaderFields, SeedFieldCount);
+ }
+
+ if(TempHeaderFields != NULL) {
+ FreeHeaderFields(TempHeaderFields, TempFieldCount);
+ }
+
+ if(NewHeaderFields != NULL) {
+ FreeHeaderFields(NewHeaderFields, NewFieldCount);
+ }
+
+ return Status;
+}
+
+/**
+ This function is used to transform data stored in HttpMessage into a list of fields
+ paired with their corresponding values.
+
+ @param[in] HttpMessage Contains raw unformatted HTTP header string. The buffer for this string will
+ be allocated and released by the caller.
+ @param[in] HttpMessageSize Size in bytes of raw unformatted HTTP header.
+ @param[out] HeaderFields Array of key/value header pairs. The storage for all header pairs is allocated
+ by the driver publishing this protocol, and must be freed by the caller.
+ @param[out] FieldCount Number of headers in HeaderFields.
+
+ @retval EFI_SUCCESS Parse HTTP header into array of key/value pairs succeeded.
+ @retval EFI_OUT_OF_RESOURCES Could not allocate memory for NewMessage.
+ @retval EFI_INVALID_PARAMETER One or more of the following conditions is TRUE:
+ HttpMessage is NULL.
+ HeaderFields is NULL.
+ FieldCount is NULL.
+
+**/
+EFI_STATUS
+HttpUtilitiesParse(
+ IN CHAR8 *HttpMessage,
+ IN UINTN HttpMessageSize,
+ OUT EFI_HTTP_HEADER **HeaderFields,
+ OUT UINTN *FieldCount
+ )
+{
+ EFI_STATUS Status;
+ CHAR8 *TempHttpMessage;
+ CHAR8 *Token;
+ CHAR8 *NextToken;
+ CHAR8 *FieldName;
+ CHAR8 *FieldValue;
+ UINTN Index;
+
+ if (HttpMessage == NULL || HeaderFields == NULL || FieldCount == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Status = EFI_SUCCESS;
+ TempHttpMessage = NULL;
+ *FieldCount = 0;
+ Token = NULL;
+ NextToken = NULL;
+ FieldName = NULL;
+ FieldValue = NULL;
+ Index = 0;
+
+ TempHttpMessage = AllocateZeroPool (HttpMessageSize);
+ if (TempHttpMessage == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ CopyMem (TempHttpMessage, HttpMessage, HttpMessageSize);
+
+ //
+ // Get header number
+ //
+ Token = TempHttpMessage;
+ while (TRUE) {
+ FieldName = NULL;
+ FieldValue = NULL;
+ NextToken = GetFieldNameAndValue (Token, &FieldName, &FieldValue);
+ Token = NextToken;
+ if (FieldName == NULL || FieldValue == NULL) {
+ break;
+ }
+
+ (*FieldCount)++;
+ }
+
+ if(*FieldCount == 0) {
+ Status = EFI_INVALID_PARAMETER;
+ goto ON_EXIT;
+ }
+
+ //
+ // Allocate buffer for header
+ //
+ *HeaderFields = AllocateZeroPool ((*FieldCount) * sizeof(EFI_HTTP_HEADER));
+ if (*HeaderFields == NULL) {
+ *FieldCount = 0;
+ Status = EFI_OUT_OF_RESOURCES;
+ goto ON_EXIT;
+ }
+
+ CopyMem (TempHttpMessage, HttpMessage, HttpMessageSize);
+
+ //
+ // Set Field and Value to each header
+ //
+ Token = TempHttpMessage;
+ while (Index < *FieldCount) {
+ FieldName = NULL;
+ FieldValue = NULL;
+ NextToken = GetFieldNameAndValue (Token, &FieldName, &FieldValue);
+ Token = NextToken;
+ if (FieldName == NULL || FieldValue == NULL) {
+ break;
+ }
+
+ Status = SetFieldNameAndValue(&(*HeaderFields)[Index], FieldName, FieldValue);
+ if(EFI_ERROR(Status)){
+ *FieldCount = 0;
+ FreeHeaderFields (*HeaderFields, Index);
+ goto ON_EXIT;
+ }
+
+ Index++;
+ }
+
+ //
+ // Free allocated buffer
+ //
+ON_EXIT:
+ if (TempHttpMessage != NULL) {
+ FreePool(TempHttpMessage);
+ }
+
+ return Status;
+}
diff --git a/NetworkPkg/HttpDxe/HttpUtilities.h b/NetworkPkg/HttpDxe/HttpUtilities.h
new file mode 100644
index 0000000000..bd4ef0b110
--- /dev/null
+++ b/NetworkPkg/HttpDxe/HttpUtilities.h
@@ -0,0 +1,82 @@
+/** @file
+ The header files of HTTP helper functions for HttpDxe driver.
+
+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_UTILITIES_H__
+#define __EFI_HTTP_UTILITIES_H__
+
+/**
+ This function is used to manage the headers portion of an HTTP message by providing
+ the ability to add, remove, or replace HTTP headers.
+
+ @param[in] SeedMessageSize Size in bytes of the initial HTTP header. This can be zero.
+ @param[in] SeedMessage Initial raw unformatted HTTP header to be used as a base for
+ building a new unformatted HTTP header. If NULL, SeedMessageSize
+ is ignored. The buffer containing this message will be allocated
+ and released by the caller.
+ @param[in] DeleteCount Number of null-terminated HTTP header field names in DeleteList.
+ @param[in] DeleteList List of null-terminated HTTP header field names to remove from SeedMessage.
+ Only the field names are in this list because the field values are irrelevant
+ to this operation. If NULL, DeleteCount is ignored. The buffer containing the
+ list will be allocated and released by the caller.
+ @param[in] AppendCount Number of header fields in AppendList.
+ @param[in] AppendList List of HTTP headers to populate NewMessage with. If SeedMessage is not NULL,
+ AppendList will be appended to the existing list from SeedMessage in NewMessage.
+ @param[out] NewMessageSize Pointer to the size in bytes of the new unformatted HTTP header in NewMessage.
+ @param[out] NewMessage Pointer to a new unformatted HTTP header. The storage for this NewMessage is
+ allocated by the driver publishing this protocol, and must be freed by the caller.
+
+ @retval EFI_SUCCESS Add, remove, and replace operations succeeded.
+ @retval EFI_OUT_OF_RESOURCES Could not allocate memory for NewMessage.
+
+**/
+EFI_STATUS
+HttpUtilitiesBuild(
+ IN UINTN SeedMessageSize,
+ IN VOID *SeedMessage, OPTIONAL
+ IN UINTN DeleteCount,
+ IN CHAR8 *DeleteList[], OPTIONAL
+ IN UINTN AppendCount,
+ IN EFI_HTTP_HEADER *AppendList[], OPTIONAL
+ OUT UINTN *NewMessageSize,
+ OUT VOID **NewMessage
+ );
+
+/**
+ This function is used to transform data stored in HttpMessage into a list of fields
+ paired with their corresponding values.
+
+ @param[in] HttpMessage Contains raw unformatted HTTP header string. The buffer for this string will
+ be allocated and released by the caller.
+ @param[in] HttpMessageSize Size in bytes of raw unformatted HTTP header.
+ @param[out] HeaderFields Array of key/value header pairs. The storage for all header pairs is allocated
+ by the driver publishing this protocol, and must be freed by the caller.
+ @param[out] FieldCount Number of headers in HeaderFields.
+
+ @retval EFI_SUCCESS Parse HTTP header into array of key/value pairs succeeded.
+ @retval EFI_OUT_OF_RESOURCES Could not allocate memory for NewMessage.
+ @retval EFI_INVALID_PARAMETER One or more of the following conditions is TRUE:
+ HttpMessage is NULL.
+ HeaderFields is NULL.
+ FieldCount is NULL.
+
+**/
+EFI_STATUS
+HttpUtilitiesParse(
+ IN CHAR8 *HttpMessage,
+ IN UINTN HttpMessageSize,
+ OUT EFI_HTTP_HEADER **HeaderFields,
+ OUT UINTN *FieldCount
+ );
+
+#endif