]> git.proxmox.com Git - mirror_edk2.git/commitdiff
NetworkPkg: Add HTTP Driver
authorYe Ting <ting.ye@intel.com>
Tue, 7 Jul 2015 09:09:21 +0000 (09:09 +0000)
committertye1 <tye1@Edk2>
Tue, 7 Jul 2015 09:09:21 +0000 (09:09 +0000)
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

15 files changed:
NetworkPkg/HttpDxe/ComponentName.c [new file with mode: 0644]
NetworkPkg/HttpDxe/ComponentName.h [new file with mode: 0644]
NetworkPkg/HttpDxe/HttpDns.c [new file with mode: 0644]
NetworkPkg/HttpDxe/HttpDns.h [new file with mode: 0644]
NetworkPkg/HttpDxe/HttpDriver.c [new file with mode: 0644]
NetworkPkg/HttpDxe/HttpDriver.h [new file with mode: 0644]
NetworkPkg/HttpDxe/HttpDxe.inf [new file with mode: 0644]
NetworkPkg/HttpDxe/HttpDxe.uni [new file with mode: 0644]
NetworkPkg/HttpDxe/HttpDxeExtra.uni [new file with mode: 0644]
NetworkPkg/HttpDxe/HttpImpl.c [new file with mode: 0644]
NetworkPkg/HttpDxe/HttpImpl.h [new file with mode: 0644]
NetworkPkg/HttpDxe/HttpProto.c [new file with mode: 0644]
NetworkPkg/HttpDxe/HttpProto.h [new file with mode: 0644]
NetworkPkg/HttpDxe/HttpUtilities.c [new file with mode: 0644]
NetworkPkg/HttpDxe/HttpUtilities.h [new file with mode: 0644]

diff --git a/NetworkPkg/HttpDxe/ComponentName.c b/NetworkPkg/HttpDxe/ComponentName.c
new file mode 100644 (file)
index 0000000..fdd2e7f
--- /dev/null
@@ -0,0 +1,138 @@
+/** @file\r
+  Implementation of EFI_COMPONENT_NAME_PROTOCOL and\r
+  EFI_COMPONENT_NAME2_PROTOCOL protocol.\r
+\r
+  Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>\r
+\r
+  This program and the accompanying materials\r
+  are licensed and made available under the terms and conditions of the BSD License\r
+  which accompanies this distribution.  The full text of the license may be found at\r
+  http://opensource.org/licenses/bsd-license.php.\r
+\r
+  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "HttpDriver.h"\r
+\r
+///\r
+/// Component Name Protocol instance\r
+///\r
+GLOBAL_REMOVE_IF_UNREFERENCED \r
+EFI_COMPONENT_NAME_PROTOCOL  gHttpDxeComponentName = {\r
+  (EFI_COMPONENT_NAME_GET_DRIVER_NAME)     HttpDxeComponentNameGetDriverName,\r
+  (EFI_COMPONENT_NAME_GET_CONTROLLER_NAME) HttpDxeComponentNameGetControllerName,\r
+  "eng"\r
+};\r
+\r
+///\r
+/// Component Name 2 Protocol instance\r
+///\r
+GLOBAL_REMOVE_IF_UNREFERENCED \r
+EFI_COMPONENT_NAME2_PROTOCOL  gHttpDxeComponentName2 = {\r
+  HttpDxeComponentNameGetDriverName,\r
+  HttpDxeComponentNameGetControllerName,\r
+  "en"\r
+};\r
+\r
+///\r
+/// Table of driver names\r
+///\r
+GLOBAL_REMOVE_IF_UNREFERENCED \r
+EFI_UNICODE_STRING_TABLE mHttpDxeDriverNameTable[] = {\r
+  { "eng;en", (CHAR16 *) L"HttpDxe" },\r
+  { NULL, NULL }\r
+};\r
+\r
+/**\r
+  Retrieves a Unicode string that is the user-readable name of the EFI Driver.\r
+\r
+  @param  This       A pointer to the EFI_COMPONENT_NAME_PROTOCOL instance.\r
+  @param  Language   A pointer to a three-character ISO 639-2 language identifier.\r
+                     This is the language of the driver name that that the caller\r
+                     is requesting, and it must match one of the languages specified\r
+                     in SupportedLanguages.  The number of languages supported by a\r
+                     driver is up to the driver writer.\r
+  @param  DriverName A pointer to the Unicode string to return.  This Unicode string\r
+                     is the name of the driver specified by This in the language\r
+                     specified by Language.\r
+\r
+  @retval EFI_SUCCESS           The Unicode string for the Driver specified by This\r
+                                and the language specified by Language was returned\r
+                                in DriverName.\r
+  @retval EFI_INVALID_PARAMETER Language is NULL.\r
+  @retval EFI_INVALID_PARAMETER DriverName is NULL.\r
+  @retval EFI_UNSUPPORTED       The driver specified by This does not support the\r
+                                language specified by Language.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+HttpDxeComponentNameGetDriverName (\r
+  IN EFI_COMPONENT_NAME2_PROTOCOL  *This,\r
+  IN  CHAR8                        *Language,\r
+  OUT CHAR16                       **DriverName\r
+  )\r
+{\r
+  return LookupUnicodeString2 (\r
+           Language,\r
+           This->SupportedLanguages,\r
+           mHttpDxeDriverNameTable,\r
+           DriverName,\r
+           (BOOLEAN)(This != &gHttpDxeComponentName2)\r
+           );\r
+}\r
+\r
+/**\r
+  Retrieves a Unicode string that is the user readable name of the controller\r
+  that is being managed by an EFI Driver.\r
+\r
+  @param  This             A pointer to the EFI_COMPONENT_NAME_PROTOCOL instance.\r
+  @param  ControllerHandle The handle of a controller that the driver specified by\r
+                           This is managing.  This handle specifies the controller\r
+                           whose name is to be returned.\r
+  @param  ChildHandle      The handle of the child controller to retrieve the name\r
+                           of.  This is an optional parameter that may be NULL.  It\r
+                           will be NULL for device drivers.  It will also be NULL\r
+                           for a bus drivers that wish to retrieve the name of the\r
+                           bus controller.  It will not be NULL for a bus driver\r
+                           that wishes to retrieve the name of a child controller.\r
+  @param  Language         A pointer to a three character ISO 639-2 language\r
+                           identifier.  This is the language of the controller name\r
+                           that the caller is requesting, and it must match one\r
+                           of the languages specified in SupportedLanguages.  The\r
+                           number of languages supported by a driver is up to the\r
+                           driver writer.\r
+  @param  ControllerName   A pointer to the Unicode string to return.  This Unicode\r
+                           string is the name of the controller specified by\r
+                           ControllerHandle and ChildHandle in the language specified\r
+                           by Language, from the point of view of the driver specified\r
+                           by This.\r
+\r
+  @retval EFI_SUCCESS           The Unicode string for the user-readable name in the\r
+                                language specified by Language for the driver\r
+                                specified by This was returned in DriverName.\r
+  @retval EFI_INVALID_PARAMETER ControllerHandle is NULL.\r
+  @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid EFI_HANDLE.\r
+  @retval EFI_INVALID_PARAMETER Language is NULL.\r
+  @retval EFI_INVALID_PARAMETER ControllerName is NULL.\r
+  @retval EFI_UNSUPPORTED       The driver specified by This is not currently managing\r
+                                the controller specified by ControllerHandle and\r
+                                ChildHandle.\r
+  @retval EFI_UNSUPPORTED       The driver specified by This does not support the\r
+                                language specified by Language.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+HttpDxeComponentNameGetControllerName (\r
+  IN  EFI_COMPONENT_NAME2_PROTOCOL  *This,\r
+  IN  EFI_HANDLE                    ControllerHandle,\r
+  IN  EFI_HANDLE                    ChildHandle        OPTIONAL,\r
+  IN  CHAR8                         *Language,\r
+  OUT CHAR16                        **ControllerName\r
+  )\r
+{\r
+  return EFI_UNSUPPORTED;\r
+}\r
diff --git a/NetworkPkg/HttpDxe/ComponentName.h b/NetworkPkg/HttpDxe/ComponentName.h
new file mode 100644 (file)
index 0000000..29a91f2
--- /dev/null
@@ -0,0 +1,98 @@
+/** @file\r
+  Header file for implementation of UEFI Component Name(2) protocol.\r
+\r
+Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution.  The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#ifndef __EFI_HTTP_COMPONENT_NAME_H__\r
+#define __EFI_HTTP_COMPONENT_NAME_H__\r
+\r
+/**\r
+  Retrieves a Unicode string that is the user-readable name of the EFI Driver.\r
+\r
+  @param  This       A pointer to the EFI_COMPONENT_NAME_PROTOCOL instance.\r
+  @param  Language   A pointer to a three-character ISO 639-2 language identifier.\r
+                     This is the language of the driver name that that the caller\r
+                     is requesting, and it must match one of the languages specified\r
+                     in SupportedLanguages.  The number of languages supported by a\r
+                     driver is up to the driver writer.\r
+  @param  DriverName A pointer to the Unicode string to return.  This Unicode string\r
+                     is the name of the driver specified by This in the language\r
+                     specified by Language.\r
+\r
+  @retval EFI_SUCCESS           The Unicode string for the Driver specified by This\r
+                                and the language specified by Language was returned\r
+                                in DriverName.\r
+  @retval EFI_INVALID_PARAMETER Language is NULL.\r
+  @retval EFI_INVALID_PARAMETER DriverName is NULL.\r
+  @retval EFI_UNSUPPORTED       The driver specified by This does not support the\r
+                                language specified by Language.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+HttpDxeComponentNameGetDriverName (\r
+  IN EFI_COMPONENT_NAME2_PROTOCOL  *This,\r
+  IN  CHAR8                        *Language,\r
+  OUT CHAR16                       **DriverName\r
+  );\r
+\r
+/**\r
+  Retrieves a Unicode string that is the user readable name of the controller\r
+  that is being managed by an EFI Driver.\r
+\r
+  @param  This             A pointer to the EFI_COMPONENT_NAME_PROTOCOL instance.\r
+  @param  ControllerHandle The handle of a controller that the driver specified by\r
+                           This is managing.  This handle specifies the controller\r
+                           whose name is to be returned.\r
+  @param  ChildHandle      The handle of the child controller to retrieve the name\r
+                           of.  This is an optional parameter that may be NULL.  It\r
+                           will be NULL for device drivers.  It will also be NULL\r
+                           for a bus drivers that wish to retrieve the name of the\r
+                           bus controller.  It will not be NULL for a bus driver\r
+                           that wishes to retrieve the name of a child controller.\r
+  @param  Language         A pointer to a three character ISO 639-2 language\r
+                           identifier.  This is the language of the controller name\r
+                           that the caller is requesting, and it must match one\r
+                           of the languages specified in SupportedLanguages.  The\r
+                           number of languages supported by a driver is up to the\r
+                           driver writer.\r
+  @param  ControllerName   A pointer to the Unicode string to return.  This Unicode\r
+                           string is the name of the controller specified by\r
+                           ControllerHandle and ChildHandle in the language specified\r
+                           by Language, from the point of view of the driver specified\r
+                           by This.\r
+\r
+  @retval EFI_SUCCESS           The Unicode string for the user-readable name in the\r
+                                language specified by Language for the driver\r
+                                specified by This was returned in DriverName.\r
+  @retval EFI_INVALID_PARAMETER ControllerHandle is NULL.\r
+  @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid EFI_HANDLE.\r
+  @retval EFI_INVALID_PARAMETER Language is NULL.\r
+  @retval EFI_INVALID_PARAMETER ControllerName is NULL.\r
+  @retval EFI_UNSUPPORTED       The driver specified by This is not currently managing\r
+                                the controller specified by ControllerHandle and\r
+                                ChildHandle.\r
+  @retval EFI_UNSUPPORTED       The driver specified by This does not support the\r
+                                language specified by Language.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+HttpDxeComponentNameGetControllerName (\r
+  IN  EFI_COMPONENT_NAME2_PROTOCOL  *This,\r
+  IN  EFI_HANDLE                    ControllerHandle,\r
+  IN  EFI_HANDLE                    ChildHandle        OPTIONAL,\r
+  IN  CHAR8                         *Language,\r
+  OUT CHAR16                        **ControllerName\r
+  );\r
+\r
+#endif\r
diff --git a/NetworkPkg/HttpDxe/HttpDns.c b/NetworkPkg/HttpDxe/HttpDns.c
new file mode 100644 (file)
index 0000000..daebc17
--- /dev/null
@@ -0,0 +1,218 @@
+/** @file\r
+  Routines for HttpDxe driver to perform DNS resolution based on UEFI DNS protocols.\r
+\r
+Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution.  The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "HttpDriver.h"\r
+\r
+/**\r
+  Retrieve the host address using the EFI_DNS4_PROTOCOL.\r
+\r
+  @param[in]  HttpInstance        Pointer to HTTP_PROTOCOL instance.\r
+  @param[in]  HostName            Pointer to buffer containing hostname.\r
+  @param[out] IpAddress           On output, pointer to buffer containing IPv4 address.\r
+\r
+  @retval EFI_SUCCESS             Operation succeeded.\r
+  @retval EFI_OUT_OF_RESOURCES    Failed to allocate needed resources.\r
+  @retval EFI_DEVICE_ERROR        An unexpected network error occurred.\r
+  @retval Others                  Other errors as indicated.\r
+  \r
+**/\r
+EFI_STATUS\r
+HttpDns4 (\r
+  IN     HTTP_PROTOCOL            *HttpInstance,\r
+  IN     CHAR16                   *HostName,\r
+     OUT EFI_IPv4_ADDRESS         *IpAddress                \r
+  )\r
+{\r
+  EFI_STATUS                      Status;\r
+  EFI_DNS4_PROTOCOL               *Dns4;\r
+  EFI_DNS4_CONFIG_DATA            Dns4CfgData;\r
+  EFI_DNS4_COMPLETION_TOKEN       Token;\r
+  BOOLEAN                         IsDone;\r
+  HTTP_SERVICE                    *Service;\r
+  EFI_HANDLE                      Dns4Handle;\r
+  EFI_IP4_CONFIG2_PROTOCOL        *Ip4Config2;\r
+  UINTN                           DnsServerListCount;\r
+  EFI_IPv4_ADDRESS                *DnsServerList;\r
+  UINTN                           DataSize;\r
+  \r
+\r
+  Service = HttpInstance->Service;\r
+  ASSERT (Service != NULL);\r
+\r
+  DnsServerList      = NULL;\r
+  DnsServerListCount = 0;\r
+  ZeroMem (&Token, sizeof (EFI_DNS4_COMPLETION_TOKEN));\r
+\r
+  //\r
+  // Get DNS server list from EFI IPv4 Configuration II protocol.\r
+  //\r
+  Status = gBS->HandleProtocol (Service->ControllerHandle, &gEfiIp4Config2ProtocolGuid, (VOID **) &Ip4Config2);\r
+  if (!EFI_ERROR (Status)) {\r
+    //\r
+    // Get the required size.\r
+    //\r
+    DataSize = 0;\r
+    Status   = Ip4Config2->GetData (Ip4Config2, Ip4Config2DataTypeDnsServer, &DataSize, NULL);\r
+    if (Status == EFI_BUFFER_TOO_SMALL) {\r
+      DnsServerList = AllocatePool (DataSize);\r
+      if (DnsServerList == NULL) {\r
+        return EFI_OUT_OF_RESOURCES;\r
+      }\r
+\r
+      Status   = Ip4Config2->GetData (Ip4Config2, Ip4Config2DataTypeDnsServer, &DataSize, DnsServerList);\r
+      if (EFI_ERROR (Status)) {\r
+        FreePool (DnsServerList);\r
+        DnsServerList = NULL;\r
+      } else {\r
+        DnsServerListCount = DataSize / sizeof (EFI_IPv4_ADDRESS);\r
+      }\r
+    }\r
+  }\r
+\r
+  Dns4Handle = NULL;\r
+  Dns4       = NULL;\r
+  \r
+  //\r
+  // Create a DNS child instance and get the protocol.\r
+  //\r
+  Status = NetLibCreateServiceChild (\r
+             Service->ControllerHandle,\r
+             Service->ImageHandle,\r
+             &gEfiDns4ServiceBindingProtocolGuid,\r
+             &Dns4Handle\r
+             );\r
+  if (EFI_ERROR (Status)) {\r
+    goto Exit;\r
+  }  \r
+\r
+  Status = gBS->OpenProtocol (\r
+                  Dns4Handle,\r
+                  &gEfiDns4ProtocolGuid,\r
+                  (VOID **) &Dns4,\r
+                  Service->ImageHandle,\r
+                  Service->ControllerHandle,\r
+                  EFI_OPEN_PROTOCOL_BY_DRIVER\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    goto Exit;\r
+  }\r
+\r
+  //\r
+  // Configure DNS4 instance for the DNS server address and protocol.\r
+  //\r
+  ZeroMem (&Dns4CfgData, sizeof (Dns4CfgData));\r
+  Dns4CfgData.DnsServerListCount = DnsServerListCount;\r
+  Dns4CfgData.DnsServerList      = DnsServerList;\r
+  Dns4CfgData.UseDefaultSetting  = HttpInstance->IPv4Node.UseDefaultAddress;\r
+  if (!Dns4CfgData.UseDefaultSetting) {\r
+    IP4_COPY_ADDRESS (&Dns4CfgData.StationIp, &HttpInstance->IPv4Node.LocalAddress);\r
+    IP4_COPY_ADDRESS (&Dns4CfgData.SubnetMask, &HttpInstance->IPv4Node.LocalSubnet);\r
+  }\r
+  Dns4CfgData.EnableDnsCache     = TRUE;\r
+  Dns4CfgData.Protocol           = EFI_IP_PROTO_UDP;\r
+  Status = Dns4->Configure (\r
+                   Dns4,\r
+                   &Dns4CfgData\r
+                   );\r
+  if (EFI_ERROR (Status)) {\r
+    goto Exit;\r
+  }\r
+  \r
+  //\r
+  // Create event to set the is done flag when name resolution is finished.\r
+  //\r
+  ZeroMem (&Token, sizeof (Token));\r
+  Status = gBS->CreateEvent (\r
+                  EVT_NOTIFY_SIGNAL,\r
+                  TPL_NOTIFY,\r
+                  HttpCommonNotify,\r
+                  &IsDone,\r
+                  &Token.Event\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    goto Exit;\r
+  }\r
+\r
+  //\r
+  // Start asynchronous name resolution.\r
+  //\r
+  Token.Status = EFI_NOT_READY;\r
+  IsDone       = FALSE;\r
+  Status = Dns4->HostNameToIp (Dns4, HostName, &Token);\r
+  if (EFI_ERROR (Status)) {\r
+    goto Exit;\r
+  }\r
+\r
+  while (!IsDone) {\r
+    Dns4->Poll (Dns4);\r
+  }\r
+\r
+  //\r
+  // Name resolution is done, check result.\r
+  //\r
+  Status = Token.Status;  \r
+  if (!EFI_ERROR (Status)) {\r
+    if (Token.RspData.H2AData == NULL) {\r
+      Status = EFI_DEVICE_ERROR;\r
+      goto Exit;\r
+    }\r
+    if (Token.RspData.H2AData->IpCount == 0 || Token.RspData.H2AData->IpList == NULL) {\r
+      Status = EFI_DEVICE_ERROR;\r
+      goto Exit;\r
+    }\r
+    //\r
+    // We just return the first IP address from DNS protocol.\r
+    //\r
+    IP4_COPY_ADDRESS (IpAddress, Token.RspData.H2AData->IpList);\r
+    Status = EFI_SUCCESS;\r
+  }\r
+\r
+Exit:\r
+  \r
+  if (Token.Event != NULL) {\r
+    gBS->CloseEvent (Token.Event);\r
+  }\r
+  if (Token.RspData.H2AData != NULL) {\r
+    if (Token.RspData.H2AData->IpList != NULL) {\r
+      FreePool (Token.RspData.H2AData->IpList);\r
+    }\r
+    FreePool (Token.RspData.H2AData);\r
+  }\r
+\r
+  if (Dns4 != NULL) {\r
+    Dns4->Configure (Dns4, NULL);\r
+    \r
+    gBS->CloseProtocol (\r
+          Dns4Handle,\r
+          &gEfiDns4ProtocolGuid,\r
+          Service->ImageHandle,\r
+          Service->ControllerHandle\r
+          );\r
+  }\r
+\r
+  if (Dns4Handle != NULL) {\r
+    NetLibDestroyServiceChild (\r
+      Service->ControllerHandle,\r
+      Service->ImageHandle,\r
+      &gEfiDns4ServiceBindingProtocolGuid,\r
+      Dns4Handle\r
+      );\r
+  }\r
+\r
+  if (DnsServerList != NULL) {\r
+    FreePool (DnsServerList);\r
+  }\r
+  \r
+  return Status;\r
+}\r
diff --git a/NetworkPkg/HttpDxe/HttpDns.h b/NetworkPkg/HttpDxe/HttpDns.h
new file mode 100644 (file)
index 0000000..0fb4186
--- /dev/null
@@ -0,0 +1,38 @@
+/** @file\r
+  The header file of routines for HttpDxe driver to perform DNS resolution based on UEFI DNS protocols.\r
+\r
+Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution.  The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#ifndef __EFI_HTTP_DNS_H__\r
+#define __EFI_HTTP_DNS_H__\r
+\r
+/**\r
+  Retrieve the host address using the EFI_DNS4_PROTOCOL.\r
+\r
+  @param[in]  HttpInstance        Pointer to HTTP_PROTOCOL instance.\r
+  @param[in]  HostName            Pointer to buffer containing hostname.\r
+  @param[out] IpAddress           On output, pointer to buffer containing IPv4 address.\r
+\r
+  @retval EFI_SUCCESS             Operation succeeded.\r
+  @retval EFI_OUT_OF_RESOURCES    Failed to allocate needed resources.\r
+  @retval EFI_DEVICE_ERROR        An unexpected network error occurred.\r
+  @retval Others                  Other errors as indicated.\r
+  \r
+**/\r
+EFI_STATUS\r
+HttpDns4 (\r
+  IN     HTTP_PROTOCOL            *HttpInstance,\r
+  IN     CHAR16                   *HostName,\r
+     OUT EFI_IPv4_ADDRESS         *IpAddress                \r
+  );\r
+\r
+#endif
\ No newline at end of file
diff --git a/NetworkPkg/HttpDxe/HttpDriver.c b/NetworkPkg/HttpDxe/HttpDriver.c
new file mode 100644 (file)
index 0000000..b65607a
--- /dev/null
@@ -0,0 +1,669 @@
+/** @file\r
+  The driver binding and service binding protocol for HttpDxe driver.\r
+\r
+  Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>\r
+\r
+  This program and the accompanying materials\r
+  are licensed and made available under the terms and conditions of the BSD License\r
+  which accompanies this distribution.  The full text of the license may be found at\r
+  http://opensource.org/licenses/bsd-license.php.\r
+\r
+  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "HttpDriver.h"\r
+\r
+///\r
+/// Driver Binding Protocol instance\r
+///\r
+EFI_DRIVER_BINDING_PROTOCOL gHttpDxeDriverBinding = {\r
+  HttpDxeDriverBindingSupported,\r
+  HttpDxeDriverBindingStart,\r
+  HttpDxeDriverBindingStop,\r
+  HTTP_DRIVER_VERSION,\r
+  NULL,\r
+  NULL\r
+};\r
+\r
+/**\r
+  Create a HTTP driver service binding private instance.\r
+\r
+  @param[in]  Controller         The controller that has TCP4 service binding\r
+                                 installed.\r
+  @param[in]  ImageHandle        The HTTP driver's image handle.\r
+  @param[out] ServiceData        Point to HTTP driver private instance.\r
+\r
+  @retval EFI_OUT_OF_RESOURCES   Failed to allocate some resources.\r
+  @retval EFI_SUCCESS            A new HTTP driver private instance is created.\r
+\r
+**/\r
+EFI_STATUS\r
+HttpCreateService (\r
+  IN  EFI_HANDLE            Controller,\r
+  IN  EFI_HANDLE            ImageHandle,\r
+  OUT HTTP_SERVICE          **ServiceData\r
+  )\r
+{\r
+  HTTP_SERVICE     *HttpService;\r
+\r
+  ASSERT (ServiceData != NULL);\r
+  *ServiceData = NULL;\r
+\r
+  HttpService = AllocateZeroPool (sizeof (HTTP_SERVICE));\r
+  if (HttpService == NULL) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  HttpService->Signature = HTTP_SERVICE_SIGNATURE;\r
+  HttpService->ServiceBinding.CreateChild = HttpServiceBindingCreateChild;\r
+  HttpService->ServiceBinding.DestroyChild = HttpServiceBindingDestroyChild;\r
+  HttpService->ImageHandle = ImageHandle;\r
+  HttpService->ControllerHandle = Controller;\r
+  HttpService->ChildrenNumber = 0;\r
+  InitializeListHead (&HttpService->ChildrenList);\r
+  \r
+  *ServiceData = HttpService;\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Release all the resource used the HTTP service binding instance.\r
+\r
+  @param  HttpService        The HTTP private instance.\r
+\r
+**/\r
+VOID\r
+HttpCleanService (\r
+  IN HTTP_SERVICE     *HttpService\r
+  )\r
+{\r
+  if (HttpService != NULL) {\r
+    return ;\r
+  }\r
+\r
+  if (HttpService->TcpChildHandle != NULL) {\r
+    gBS->CloseProtocol (\r
+           HttpService->TcpChildHandle,\r
+           &gEfiTcp4ProtocolGuid,\r
+           HttpService->ImageHandle,\r
+           HttpService->ControllerHandle\r
+           );\r
+\r
+    NetLibDestroyServiceChild (\r
+      HttpService->ControllerHandle,\r
+      HttpService->ImageHandle,\r
+      &gEfiTcp4ServiceBindingProtocolGuid,\r
+      HttpService->TcpChildHandle\r
+      );\r
+  }\r
+}\r
+\r
+/**\r
+  This is the declaration of an EFI image entry point. This entry point is\r
+  the same for UEFI Applications, UEFI OS Loaders, and UEFI Drivers including\r
+  both device drivers and bus drivers.\r
+\r
+  @param  ImageHandle           The firmware allocated handle for the UEFI image.\r
+  @param  SystemTable           A pointer to the EFI System Table.\r
+\r
+  @retval EFI_SUCCESS           The operation completed successfully.\r
+  @retval Others                An unexpected error occurred.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+HttpDxeDriverEntryPoint (\r
+  IN EFI_HANDLE        ImageHandle,\r
+  IN EFI_SYSTEM_TABLE  *SystemTable\r
+  )\r
+{\r
+  //\r
+  // Install UEFI Driver Model protocol(s).\r
+  //\r
+  return EfiLibInstallDriverBindingComponentName2 (\r
+           ImageHandle,\r
+           SystemTable,\r
+           &gHttpDxeDriverBinding,\r
+           ImageHandle,\r
+           &gHttpDxeComponentName,\r
+           &gHttpDxeComponentName2\r
+           );\r
+}\r
+\r
+/**\r
+  Callback function which provided by user to remove one node in NetDestroyLinkList process.\r
+  \r
+  @param[in]    Entry           The entry to be removed.\r
+  @param[in]    Context         Pointer to the callback context corresponds to the Context in NetDestroyLinkList.\r
+\r
+  @retval EFI_INVALID_PARAMETER Any input parameter is NULL.\r
+  @retval EFI_SUCCESS           The entry has been removed successfully.\r
+  @retval Others                Fail to remove the entry.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+HttpDestroyChildEntryInHandleBuffer (\r
+  IN LIST_ENTRY         *Entry,\r
+  IN VOID               *Context\r
+  )\r
+{\r
+  HTTP_PROTOCOL                 *HttpInstance;\r
+  EFI_SERVICE_BINDING_PROTOCOL  *ServiceBinding;\r
+  UINTN                         NumberOfChildren;\r
+  EFI_HANDLE                    *ChildHandleBuffer;\r
+\r
+  if (Entry == NULL || Context == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  HttpInstance = NET_LIST_USER_STRUCT_S (Entry, HTTP_PROTOCOL, Link, HTTP_PROTOCOL_SIGNATURE);\r
+  ServiceBinding    = ((HTTP_DESTROY_CHILD_IN_HANDLE_BUF_CONTEXT *) Context)->ServiceBinding;\r
+  NumberOfChildren  = ((HTTP_DESTROY_CHILD_IN_HANDLE_BUF_CONTEXT *) Context)->NumberOfChildren;\r
+  ChildHandleBuffer = ((HTTP_DESTROY_CHILD_IN_HANDLE_BUF_CONTEXT *) Context)->ChildHandleBuffer;\r
+\r
+  if (!NetIsInHandleBuffer (HttpInstance->Handle, NumberOfChildren, ChildHandleBuffer)) {\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  return ServiceBinding->DestroyChild (ServiceBinding, HttpInstance->Handle);\r
+}\r
+\r
+/**\r
+  Tests to see if this driver supports a given controller. If a child device is provided, \r
+  it further tests to see if this driver supports creating a handle for the specified child device.\r
+\r
+  This function checks to see if the driver specified by This supports the device specified by \r
+  ControllerHandle. Drivers will typically use the device path attached to \r
+  ControllerHandle and/or the services from the bus I/O abstraction attached to \r
+  ControllerHandle to determine if the driver supports ControllerHandle. This function \r
+  may be called many times during platform initialization. In order to reduce boot times, the tests \r
+  performed by this function must be very small, and take as little time as possible to execute. This \r
+  function must not change the state of any hardware devices, and this function must be aware that the \r
+  device specified by ControllerHandle may already be managed by the same driver or a \r
+  different driver. This function must match its calls to AllocatePages() with FreePages(), \r
+  AllocatePool() with FreePool(), and OpenProtocol() with CloseProtocol().  \r
+  Because ControllerHandle may have been previously started by the same driver, if a protocol is \r
+  already in the opened state, then it must not be closed with CloseProtocol(). This is required \r
+  to guarantee the state of ControllerHandle is not modified by this function.\r
+\r
+  @param[in]  This                 A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.\r
+  @param[in]  ControllerHandle     The handle of the controller to test. This handle \r
+                                   must support a protocol interface that supplies \r
+                                   an I/O abstraction to the driver.\r
+  @param[in]  RemainingDevicePath  A pointer to the remaining portion of a device path.  This \r
+                                   parameter is ignored by device drivers, and is optional for bus \r
+                                   drivers. For bus drivers, if this parameter is not NULL, then \r
+                                   the bus driver must determine if the bus controller specified \r
+                                   by ControllerHandle and the child controller specified \r
+                                   by RemainingDevicePath are both supported by this \r
+                                   bus driver.\r
+\r
+  @retval EFI_SUCCESS              The device specified by ControllerHandle and\r
+                                   RemainingDevicePath is supported by the driver specified by This.\r
+  @retval EFI_ALREADY_STARTED      The device specified by ControllerHandle and\r
+                                   RemainingDevicePath is already being managed by the driver\r
+                                   specified by This.\r
+  @retval EFI_ACCESS_DENIED        The device specified by ControllerHandle and\r
+                                   RemainingDevicePath is already being managed by a different\r
+                                   driver or an application that requires exclusive access.\r
+                                   Currently not implemented.\r
+  @retval EFI_UNSUPPORTED          The device specified by ControllerHandle and\r
+                                   RemainingDevicePath is not supported by the driver specified by This.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+HttpDxeDriverBindingSupported (\r
+  IN EFI_DRIVER_BINDING_PROTOCOL  *This,\r
+  IN EFI_HANDLE                   ControllerHandle,\r
+  IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath OPTIONAL\r
+  )\r
+{\r
+  EFI_STATUS       Status;\r
+\r
+  //\r
+  // Test for the HttpServiceBinding protocol.\r
+  //\r
+  Status = gBS->OpenProtocol (\r
+                  ControllerHandle,\r
+                  &gEfiHttpServiceBindingProtocolGuid,\r
+                  NULL,\r
+                  This->DriverBindingHandle,\r
+                  ControllerHandle,\r
+                  EFI_OPEN_PROTOCOL_TEST_PROTOCOL\r
+                  );\r
+  if (!EFI_ERROR (Status)) {\r
+    return EFI_ALREADY_STARTED;\r
+  }\r
+\r
+  //\r
+  // Test for the Tcp4 Protocol\r
+  //\r
+  return gBS->OpenProtocol (\r
+                ControllerHandle,\r
+                &gEfiTcp4ServiceBindingProtocolGuid,\r
+                NULL,\r
+                This->DriverBindingHandle,\r
+                ControllerHandle,\r
+                EFI_OPEN_PROTOCOL_TEST_PROTOCOL\r
+                );\r
+  \r
+}\r
+\r
+/**\r
+  Starts a device controller or a bus controller.\r
+\r
+  The Start() function is designed to be invoked from the EFI boot service ConnectController().\r
+  As a result, much of the error checking on the parameters to Start() has been moved into this \r
+  common boot service. It is legal to call Start() from other locations, \r
+  but the following calling restrictions must be followed, or the system behavior will not be deterministic.\r
+  1. ControllerHandle must be a valid EFI_HANDLE.\r
+  2. If RemainingDevicePath is not NULL, then it must be a pointer to a naturally aligned\r
+     EFI_DEVICE_PATH_PROTOCOL.\r
+  3. Prior to calling Start(), the Supported() function for the driver specified by This must\r
+     have been called with the same calling parameters, and Supported() must have returned EFI_SUCCESS.  \r
+\r
+  @param[in]  This                 A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.\r
+  @param[in]  ControllerHandle     The handle of the controller to start. This handle \r
+                                   must support a protocol interface that supplies \r
+                                   an I/O abstraction to the driver.\r
+  @param[in]  RemainingDevicePath  A pointer to the remaining portion of a device path.  This \r
+                                   parameter is ignored by device drivers, and is optional for bus \r
+                                   drivers. For a bus driver, if this parameter is NULL, then handles \r
+                                   for all the children of Controller are created by this driver.  \r
+                                   If this parameter is not NULL and the first Device Path Node is \r
+                                   not the End of Device Path Node, then only the handle for the \r
+                                   child device specified by the first Device Path Node of \r
+                                   RemainingDevicePath is created by this driver.\r
+                                   If the first Device Path Node of RemainingDevicePath is \r
+                                   the End of Device Path Node, no child handle is created by this\r
+                                   driver.\r
+\r
+  @retval EFI_SUCCESS              The device was started.\r
+  @retval EFI_ALREADY_STARTED      This device is already running on ControllerHandle.\r
+  @retval EFI_DEVICE_ERROR         The device could not be started due to a device error.Currently not implemented.\r
+  @retval EFI_OUT_OF_RESOURCES     The request could not be completed due to a lack of resources.\r
+  @retval Others                   The driver failded to start the device.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+HttpDxeDriverBindingStart (\r
+  IN EFI_DRIVER_BINDING_PROTOCOL  *This,\r
+  IN EFI_HANDLE                   ControllerHandle,\r
+  IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath OPTIONAL\r
+  )\r
+{\r
+  EFI_STATUS                      Status;\r
+  HTTP_SERVICE                    *HttpService;\r
+  VOID                            *Interface;\r
+  \r
+  //\r
+  // Test for the Http service binding protocol\r
+  //\r
+  Status = gBS->OpenProtocol (\r
+                  ControllerHandle,\r
+                  &gEfiHttpServiceBindingProtocolGuid,\r
+                  NULL,\r
+                  This->DriverBindingHandle,\r
+                  ControllerHandle,\r
+                  EFI_OPEN_PROTOCOL_TEST_PROTOCOL\r
+                  );\r
+\r
+  if (Status == EFI_SUCCESS) {\r
+    return EFI_ALREADY_STARTED;\r
+  }\r
+\r
+  Status = HttpCreateService (ControllerHandle, This->DriverBindingHandle, &HttpService);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  ASSERT (HttpService != NULL);\r
+\r
+  //\r
+  // Create a TCP child instance, but do not configure it. This will establish the parent-child relationship.\r
+  //\r
+  Status = NetLibCreateServiceChild (\r
+             ControllerHandle,\r
+             This->DriverBindingHandle,\r
+             &gEfiTcp4ServiceBindingProtocolGuid,\r
+             &HttpService->TcpChildHandle\r
+             );\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    goto ON_ERROR;\r
+  }\r
+\r
+  Status = gBS->OpenProtocol (\r
+                  HttpService->TcpChildHandle,\r
+                  &gEfiTcp4ProtocolGuid,\r
+                  &Interface,\r
+                  This->DriverBindingHandle,\r
+                  ControllerHandle,\r
+                  EFI_OPEN_PROTOCOL_BY_DRIVER\r
+                  );\r
+                  \r
+  if (EFI_ERROR (Status)) {\r
+    goto ON_ERROR;\r
+  }\r
+\r
+  //\r
+  // Install the HttpServiceBinding Protocol onto Controller\r
+  //\r
+  Status = gBS->InstallMultipleProtocolInterfaces (\r
+                  &ControllerHandle,\r
+                  &gEfiHttpServiceBindingProtocolGuid,\r
+                  &HttpService->ServiceBinding,\r
+                  NULL\r
+                  );\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    goto ON_ERROR;\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+\r
+ON_ERROR:\r
+\r
+  if (HttpService != NULL) {\r
+    HttpCleanService (HttpService);\r
+    FreePool (HttpService);\r
+  }\r
+  \r
+  return Status;\r
+}\r
+\r
+/**\r
+  Stops a device controller or a bus controller.\r
+  \r
+  The Stop() function is designed to be invoked from the EFI boot service DisconnectController(). \r
+  As a result, much of the error checking on the parameters to Stop() has been moved \r
+  into this common boot service. It is legal to call Stop() from other locations, \r
+  but the following calling restrictions must be followed, or the system behavior will not be deterministic.\r
+  1. ControllerHandle must be a valid EFI_HANDLE that was used on a previous call to this\r
+     same driver's Start() function.\r
+  2. The first NumberOfChildren handles of ChildHandleBuffer must all be a valid\r
+     EFI_HANDLE. In addition, all of these handles must have been created in this driver's\r
+     Start() function, and the Start() function must have called OpenProtocol() on\r
+     ControllerHandle with an Attribute of EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER.\r
+  \r
+  @param[in]  This              A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.\r
+  @param[in]  ControllerHandle  A handle to the device being stopped. The handle must \r
+                                support a bus specific I/O protocol for the driver \r
+                                to use to stop the device.\r
+  @param[in]  NumberOfChildren  The number of child device handles in ChildHandleBuffer.\r
+  @param[in]  ChildHandleBuffer An array of child handles to be freed. May be NULL \r
+                                if NumberOfChildren is 0.\r
+\r
+  @retval EFI_SUCCESS           The device was stopped.\r
+  @retval EFI_DEVICE_ERROR      The device could not be stopped due to a device error.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+HttpDxeDriverBindingStop (\r
+  IN EFI_DRIVER_BINDING_PROTOCOL  *This,\r
+  IN EFI_HANDLE                   ControllerHandle,\r
+  IN UINTN                        NumberOfChildren,\r
+  IN EFI_HANDLE                   *ChildHandleBuffer OPTIONAL\r
+  )\r
+{\r
+  EFI_HANDLE                                 NicHandle;\r
+  EFI_STATUS                                 Status;\r
+  EFI_SERVICE_BINDING_PROTOCOL               *ServiceBinding;\r
+  HTTP_SERVICE                               *HttpService;\r
+  LIST_ENTRY                                 *List;\r
+  HTTP_DESTROY_CHILD_IN_HANDLE_BUF_CONTEXT   Context;\r
+  \r
+  //\r
+  // HTTP driver opens TCP child, So, Controller is a TCP\r
+  // child handle. Locate the Nic handle first. Then get the\r
+  // HTTP private data back.\r
+  //\r
+  NicHandle = NetLibGetNicHandle (ControllerHandle, &gEfiTcp4ProtocolGuid);\r
+  if (NicHandle == NULL) {\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  Status = gBS->OpenProtocol (\r
+                  NicHandle,\r
+                  &gEfiHttpServiceBindingProtocolGuid,\r
+                  (VOID **) &ServiceBinding,\r
+                  This->DriverBindingHandle,\r
+                  NicHandle,\r
+                  EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
+                  );\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+\r
+  HttpService = HTTP_SERVICE_FROM_PROTOCOL (ServiceBinding);\r
+\r
+  if (!IsListEmpty (&HttpService->ChildrenList)) {\r
+    //\r
+    // Destroy the HTTP child instance in ChildHandleBuffer.\r
+    //\r
+    List = &HttpService->ChildrenList;\r
+    Context.ServiceBinding    = ServiceBinding;\r
+    Context.NumberOfChildren  = NumberOfChildren;\r
+    Context.ChildHandleBuffer = ChildHandleBuffer;\r
+    Status = NetDestroyLinkList (\r
+               List,\r
+               HttpDestroyChildEntryInHandleBuffer,\r
+               &Context,\r
+               NULL\r
+               );\r
+  }\r
+\r
+  if (NumberOfChildren == 0 && IsListEmpty (&HttpService->ChildrenList)) {\r
+    gBS->UninstallProtocolInterface (\r
+           NicHandle,\r
+           &gEfiHttpServiceBindingProtocolGuid,\r
+           ServiceBinding\r
+           );\r
+\r
+    HttpCleanService (HttpService);\r
+   \r
+    FreePool (HttpService);\r
+\r
+    Status = EFI_SUCCESS;\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Creates a child handle and installs a protocol.\r
+\r
+  The CreateChild() function installs a protocol on ChildHandle.\r
+  If ChildHandle is a pointer to NULL, then a new handle is created and returned in ChildHandle.\r
+  If ChildHandle is not a pointer to NULL, then the protocol installs on the existing ChildHandle.\r
+\r
+  @param  This        Pointer to the EFI_SERVICE_BINDING_PROTOCOL instance.\r
+  @param  ChildHandle Pointer to the handle of the child to create. If it is NULL,\r
+                      then a new handle is created. If it is a pointer to an existing UEFI handle,\r
+                      then the protocol is added to the existing UEFI handle.\r
+\r
+  @retval EFI_SUCCES            The protocol was added to ChildHandle.\r
+  @retval EFI_INVALID_PARAMETER This is NULL, or ChildHandle is NULL.\r
+  @retval EFI_OUT_OF_RESOURCES  There are not enough resources availabe to create\r
+                                the child.\r
+  @retval other                 The child handle was not created.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+HttpServiceBindingCreateChild (\r
+  IN EFI_SERVICE_BINDING_PROTOCOL  *This,\r
+  IN OUT EFI_HANDLE                *ChildHandle\r
+  )\r
+{\r
+  HTTP_SERVICE         *HttpService;\r
+  HTTP_PROTOCOL        *HttpInstance;\r
+  EFI_STATUS           Status;\r
+  VOID                 *Interface;\r
+  EFI_TPL              OldTpl;\r
+\r
+  if ((This == NULL) || (ChildHandle == NULL)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  HttpService  = HTTP_SERVICE_FROM_PROTOCOL (This);\r
+  HttpInstance = AllocateZeroPool (sizeof (HTTP_PROTOCOL));\r
+  if (HttpInstance == NULL) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  //\r
+  // Install HTTP protocol onto ChildHandle\r
+  //\r
+  Status = gBS->InstallMultipleProtocolInterfaces (\r
+                  ChildHandle,\r
+                  &gEfiHttpProtocolGuid,\r
+                  &HttpInstance->Http,\r
+                  NULL\r
+                  );\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    goto ON_ERROR;\r
+  }\r
+\r
+  HttpInstance->Handle = *ChildHandle;\r
+\r
+  Status = HttpInitProtocol (HttpService, HttpInstance);\r
+  if (EFI_ERROR (Status)) {\r
+    goto ON_ERROR;\r
+  }\r
+\r
+  //\r
+  // Open the default Tcp4 protocol by child.\r
+  //\r
+  Status = gBS->OpenProtocol (\r
+                  HttpService->TcpChildHandle,\r
+                  &gEfiTcp4ProtocolGuid,\r
+                  (VOID **) &Interface,\r
+                  gHttpDxeDriverBinding.DriverBindingHandle,\r
+                  HttpInstance->Handle,\r
+                  EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    goto ON_ERROR;\r
+  }\r
+\r
+  //\r
+  // Add it to the HTTP service's child list.\r
+  //\r
+  OldTpl = gBS->RaiseTPL (TPL_CALLBACK);\r
+\r
+  InsertTailList (&HttpService->ChildrenList, &HttpInstance->Link);\r
+  HttpService->ChildrenNumber++;\r
+\r
+  gBS->RestoreTPL (OldTpl);\r
+\r
+  return EFI_SUCCESS;\r
+  \r
+ON_ERROR:\r
+\r
+  HttpCleanProtocol (HttpInstance);\r
+  FreePool (HttpInstance);\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Destroys a child handle with a protocol installed on it.\r
+\r
+  The DestroyChild() function does the opposite of CreateChild(). It removes a protocol\r
+  that was installed by CreateChild() from ChildHandle. If the removed protocol is the\r
+  last protocol on ChildHandle, then ChildHandle is destroyed.\r
+\r
+  @param  This        Pointer to the EFI_SERVICE_BINDING_PROTOCOL instance.\r
+  @param  ChildHandle Handle of the child to destroy\r
+\r
+  @retval EFI_SUCCES            The protocol was removed from ChildHandle.\r
+  @retval EFI_UNSUPPORTED       ChildHandle does not support the protocol that is being removed.\r
+  @retval EFI_INVALID_PARAMETER Child handle is NULL.\r
+  @retval other                 The child handle was not destroyed\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+HttpServiceBindingDestroyChild (\r
+  IN EFI_SERVICE_BINDING_PROTOCOL  *This,\r
+  IN EFI_HANDLE                    ChildHandle\r
+  )\r
+{\r
+  HTTP_SERVICE             *HttpService;\r
+  HTTP_PROTOCOL            *HttpInstance;\r
+  EFI_HTTP_PROTOCOL        *Http;\r
+  EFI_STATUS                Status;\r
+  EFI_TPL                   OldTpl;\r
+  \r
+  if ((This == NULL) || (ChildHandle == NULL)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  HttpService = HTTP_SERVICE_FROM_PROTOCOL (This);\r
+  Status = gBS->OpenProtocol (\r
+                  ChildHandle,\r
+                  &gEfiHttpProtocolGuid,\r
+                  (VOID **) &Http,\r
+                  gHttpDxeDriverBinding.DriverBindingHandle,\r
+                  ChildHandle,\r
+                  EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    return EFI_UNSUPPORTED;\r
+  }\r
+  \r
+  HttpInstance = HTTP_INSTANCE_FROM_PROTOCOL (Http);\r
+  if (HttpInstance->Service != HttpService) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if (HttpInstance->InDestroy) {\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  //\r
+  // Close the Tcp4 protocol.\r
+  //\r
+  gBS->CloseProtocol (\r
+         HttpService->TcpChildHandle,\r
+         &gEfiTcp4ProtocolGuid,\r
+         gHttpDxeDriverBinding.DriverBindingHandle,\r
+         ChildHandle\r
+         );\r
+  \r
+  HttpInstance->InDestroy = TRUE;\r
+\r
+  //\r
+  // Uninstall the HTTP protocol.\r
+  //\r
+  Status = gBS->UninstallProtocolInterface (\r
+                  ChildHandle,\r
+                  &gEfiHttpProtocolGuid,\r
+                  Http\r
+                  );\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    HttpInstance->InDestroy = FALSE;\r
+    return Status;\r
+  }\r
+\r
+  OldTpl = gBS->RaiseTPL (TPL_CALLBACK);\r
+\r
+  HttpCleanProtocol (HttpInstance);\r
+\r
+  RemoveEntryList (&HttpInstance->Link);\r
+  HttpService->ChildrenNumber--;\r
+\r
+  gBS->RestoreTPL (OldTpl);\r
+  \r
+  FreePool (HttpInstance);\r
+  return EFI_SUCCESS;\r
+}\r
diff --git a/NetworkPkg/HttpDxe/HttpDriver.h b/NetworkPkg/HttpDxe/HttpDriver.h
new file mode 100644 (file)
index 0000000..5bad705
--- /dev/null
@@ -0,0 +1,260 @@
+/** @file\r
+  The header files of the driver binding and service binding protocol for HttpDxe driver.\r
+\r
+  Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>\r
+\r
+  This program and the accompanying materials\r
+  are licensed and made available under the terms and conditions of the BSD License\r
+  which accompanies this distribution.  The full text of the license may be found at\r
+  http://opensource.org/licenses/bsd-license.php.\r
+\r
+  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#ifndef __EFI_HTTP_DRIVER_H__\r
+#define __EFI_HTTP_DRIVER_H__\r
+\r
+#include <Uefi.h>\r
+\r
+//\r
+// Libraries\r
+//\r
+#include <Library/UefiBootServicesTableLib.h>\r
+#include <Library/MemoryAllocationLib.h>\r
+#include <Library/BaseLib.h>\r
+#include <Library/UefiLib.h>\r
+#include <Library/DebugLib.h>\r
+#include <Library/NetLib.h>\r
+#include <Library/HttpLib.h>\r
+#include <Library/TcpIoLib.h>\r
+\r
+//\r
+// UEFI Driver Model Protocols\r
+//\r
+#include <Protocol/DriverBinding.h>\r
+#include <Protocol/ServiceBinding.h>\r
+#include <Protocol/ComponentName2.h>\r
+#include <Protocol/ComponentName.h>\r
+\r
+//\r
+// Consumed Protocols\r
+//\r
+#include <Protocol/Tcp4.h>\r
+#include <Protocol/Dns4.h>\r
+#include <Protocol/Ip4Config2.h>\r
+\r
+//\r
+// Produced Protocols\r
+//\r
+#include <Protocol/Http.h>\r
+\r
+//\r
+// Driver Version\r
+//\r
+#define HTTP_DRIVER_VERSION 0xa\r
+\r
+//\r
+// Protocol instances\r
+//\r
+extern EFI_DRIVER_BINDING_PROTOCOL  gHttpDxeDriverBinding;\r
+extern EFI_COMPONENT_NAME2_PROTOCOL gHttpDxeComponentName2;\r
+extern EFI_COMPONENT_NAME_PROTOCOL  gHttpDxeComponentName;\r
+\r
+//\r
+// Include files with function prototypes\r
+//\r
+#include "ComponentName.h"\r
+#include "HttpImpl.h"\r
+#include "HttpProto.h"\r
+#include "HttpDns.h"\r
+#include "HttpUtilities.h"\r
+\r
+typedef struct {\r
+  EFI_SERVICE_BINDING_PROTOCOL  *ServiceBinding;\r
+  UINTN                         NumberOfChildren;\r
+  EFI_HANDLE                    *ChildHandleBuffer;\r
+} HTTP_DESTROY_CHILD_IN_HANDLE_BUF_CONTEXT;\r
+\r
+/**\r
+  Tests to see if this driver supports a given controller. If a child device is provided, \r
+  it further tests to see if this driver supports creating a handle for the specified child device.\r
+\r
+  This function checks to see if the driver specified by This supports the device specified by \r
+  ControllerHandle. Drivers will typically use the device path attached to \r
+  ControllerHandle and/or the services from the bus I/O abstraction attached to \r
+  ControllerHandle to determine if the driver supports ControllerHandle. This function \r
+  may be called many times during platform initialization. In order to reduce boot times, the tests \r
+  performed by this function must be very small, and take as little time as possible to execute. This \r
+  function must not change the state of any hardware devices, and this function must be aware that the \r
+  device specified by ControllerHandle may already be managed by the same driver or a \r
+  different driver. This function must match its calls to AllocatePages() with FreePages(), \r
+  AllocatePool() with FreePool(), and OpenProtocol() with CloseProtocol().  \r
+  Because ControllerHandle may have been previously started by the same driver, if a protocol is \r
+  already in the opened state, then it must not be closed with CloseProtocol(). This is required \r
+  to guarantee the state of ControllerHandle is not modified by this function.\r
+\r
+  @param[in]  This                 A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.\r
+  @param[in]  ControllerHandle     The handle of the controller to test. This handle \r
+                                   must support a protocol interface that supplies \r
+                                   an I/O abstraction to the driver.\r
+  @param[in]  RemainingDevicePath  A pointer to the remaining portion of a device path.  This \r
+                                   parameter is ignored by device drivers, and is optional for bus \r
+                                   drivers. For bus drivers, if this parameter is not NULL, then \r
+                                   the bus driver must determine if the bus controller specified \r
+                                   by ControllerHandle and the child controller specified \r
+                                   by RemainingDevicePath are both supported by this \r
+                                   bus driver.\r
+\r
+  @retval EFI_SUCCESS              The device specified by ControllerHandle and\r
+                                   RemainingDevicePath is supported by the driver specified by This.\r
+  @retval EFI_ALREADY_STARTED      The device specified by ControllerHandle and\r
+                                   RemainingDevicePath is already being managed by the driver\r
+                                   specified by This.\r
+  @retval EFI_ACCESS_DENIED        The device specified by ControllerHandle and\r
+                                   RemainingDevicePath is already being managed by a different\r
+                                   driver or an application that requires exclusive access.\r
+                                   Currently not implemented.\r
+  @retval EFI_UNSUPPORTED          The device specified by ControllerHandle and\r
+                                   RemainingDevicePath is not supported by the driver specified by This.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+HttpDxeDriverBindingSupported (\r
+  IN EFI_DRIVER_BINDING_PROTOCOL  *This,\r
+  IN EFI_HANDLE                   ControllerHandle,\r
+  IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath OPTIONAL\r
+  );\r
+\r
+/**\r
+  Starts a device controller or a bus controller.\r
+\r
+  The Start() function is designed to be invoked from the EFI boot service ConnectController().\r
+  As a result, much of the error checking on the parameters to Start() has been moved into this \r
+  common boot service. It is legal to call Start() from other locations, \r
+  but the following calling restrictions must be followed, or the system behavior will not be deterministic.\r
+  1. ControllerHandle must be a valid EFI_HANDLE.\r
+  2. If RemainingDevicePath is not NULL, then it must be a pointer to a naturally aligned\r
+     EFI_DEVICE_PATH_PROTOCOL.\r
+  3. Prior to calling Start(), the Supported() function for the driver specified by This must\r
+     have been called with the same calling parameters, and Supported() must have returned EFI_SUCCESS.  \r
+\r
+  @param[in]  This                 A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.\r
+  @param[in]  ControllerHandle     The handle of the controller to start. This handle \r
+                                   must support a protocol interface that supplies \r
+                                   an I/O abstraction to the driver.\r
+  @param[in]  RemainingDevicePath  A pointer to the remaining portion of a device path.  This \r
+                                   parameter is ignored by device drivers, and is optional for bus \r
+                                   drivers. For a bus driver, if this parameter is NULL, then handles \r
+                                   for all the children of Controller are created by this driver.  \r
+                                   If this parameter is not NULL and the first Device Path Node is \r
+                                   not the End of Device Path Node, then only the handle for the \r
+                                   child device specified by the first Device Path Node of \r
+                                   RemainingDevicePath is created by this driver.\r
+                                   If the first Device Path Node of RemainingDevicePath is \r
+                                   the End of Device Path Node, no child handle is created by this\r
+                                   driver.\r
+\r
+  @retval EFI_SUCCESS              The device was started.\r
+  @retval EFI_DEVICE_ERROR         The device could not be started due to a device error.Currently not implemented.\r
+  @retval EFI_OUT_OF_RESOURCES     The request could not be completed due to a lack of resources.\r
+  @retval Others                   The driver failded to start the device.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+HttpDxeDriverBindingStart (\r
+  IN EFI_DRIVER_BINDING_PROTOCOL  *This,\r
+  IN EFI_HANDLE                   ControllerHandle,\r
+  IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath OPTIONAL\r
+  );\r
+\r
+/**\r
+  Stops a device controller or a bus controller.\r
+  \r
+  The Stop() function is designed to be invoked from the EFI boot service DisconnectController(). \r
+  As a result, much of the error checking on the parameters to Stop() has been moved \r
+  into this common boot service. It is legal to call Stop() from other locations, \r
+  but the following calling restrictions must be followed, or the system behavior will not be deterministic.\r
+  1. ControllerHandle must be a valid EFI_HANDLE that was used on a previous call to this\r
+     same driver's Start() function.\r
+  2. The first NumberOfChildren handles of ChildHandleBuffer must all be a valid\r
+     EFI_HANDLE. In addition, all of these handles must have been created in this driver's\r
+     Start() function, and the Start() function must have called OpenProtocol() on\r
+     ControllerHandle with an Attribute of EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER.\r
+  \r
+  @param[in]  This              A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.\r
+  @param[in]  ControllerHandle  A handle to the device being stopped. The handle must \r
+                                support a bus specific I/O protocol for the driver \r
+                                to use to stop the device.\r
+  @param[in]  NumberOfChildren  The number of child device handles in ChildHandleBuffer.\r
+  @param[in]  ChildHandleBuffer An array of child handles to be freed. May be NULL \r
+                                if NumberOfChildren is 0.\r
+\r
+  @retval EFI_SUCCESS           The device was stopped.\r
+  @retval EFI_DEVICE_ERROR      The device could not be stopped due to a device error.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+HttpDxeDriverBindingStop (\r
+  IN EFI_DRIVER_BINDING_PROTOCOL  *This,\r
+  IN  EFI_HANDLE                  ControllerHandle,\r
+  IN  UINTN                       NumberOfChildren,\r
+  IN  EFI_HANDLE                  *ChildHandleBuffer OPTIONAL\r
+  );\r
+\r
+/**\r
+  Creates a child handle and installs a protocol.\r
+\r
+  The CreateChild() function installs a protocol on ChildHandle.\r
+  If ChildHandle is a pointer to NULL, then a new handle is created and returned in ChildHandle.\r
+  If ChildHandle is not a pointer to NULL, then the protocol installs on the existing ChildHandle.\r
+\r
+  @param  This        Pointer to the EFI_SERVICE_BINDING_PROTOCOL instance.\r
+  @param  ChildHandle Pointer to the handle of the child to create. If it is NULL,\r
+                      then a new handle is created. If it is a pointer to an existing UEFI handle,\r
+                      then the protocol is added to the existing UEFI handle.\r
+\r
+  @retval EFI_SUCCES            The protocol was added to ChildHandle.\r
+  @retval EFI_INVALID_PARAMETER This is NULL, or ChildHandle is NULL.\r
+  @retval EFI_OUT_OF_RESOURCES  There are not enough resources availabe to create\r
+                                the child.\r
+  @retval other                 The child handle was not created.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+HttpServiceBindingCreateChild (\r
+  IN EFI_SERVICE_BINDING_PROTOCOL  *This,\r
+  IN OUT EFI_HANDLE                *ChildHandle\r
+  );\r
+\r
+/**\r
+  Destroys a child handle with a protocol installed on it.\r
+\r
+  The DestroyChild() function does the opposite of CreateChild(). It removes a protocol\r
+  that was installed by CreateChild() from ChildHandle. If the removed protocol is the\r
+  last protocol on ChildHandle, then ChildHandle is destroyed.\r
+\r
+  @param  This        Pointer to the EFI_SERVICE_BINDING_PROTOCOL instance.\r
+  @param  ChildHandle Handle of the child to destroy\r
+\r
+  @retval EFI_SUCCES            The protocol was removed from ChildHandle.\r
+  @retval EFI_UNSUPPORTED       ChildHandle does not support the protocol that is being removed.\r
+  @retval EFI_INVALID_PARAMETER Child handle is NULL.\r
+  @retval other                 The child handle was not destroyed\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+HttpServiceBindingDestroyChild (\r
+  IN EFI_SERVICE_BINDING_PROTOCOL  *This,\r
+  IN EFI_HANDLE                    ChildHandle\r
+  );\r
+\r
+\r
+extern EFI_HTTP_PROTOCOL  mEfiHttpProtocolTemplete;\r
+\r
+#endif\r
diff --git a/NetworkPkg/HttpDxe/HttpDxe.inf b/NetworkPkg/HttpDxe/HttpDxe.inf
new file mode 100644 (file)
index 0000000..4632934
--- /dev/null
@@ -0,0 +1,64 @@
+## @file\r
+#  Implementation of EFI HTTP protocol interfaces.\r
+#\r
+#  Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>\r
+#\r
+#  This program and the accompanying materials\r
+#  are licensed and made available under the terms and conditions of the BSD License\r
+#  which accompanies this distribution. The full text of the license may be found at\r
+#  http://opensource.org/licenses/bsd-license.php.\r
+#  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+#  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+#\r
+#\r
+##\r
+\r
+[Defines]\r
+  INF_VERSION               = 0x00010005\r
+  BASE_NAME                 = HttpDxe\r
+  FILE_GUID                 = 2366c20f-e15a-11e3-8bf1-e4115b28bc50\r
+  MODULE_TYPE               = UEFI_DRIVER\r
+  VERSION_STRING            = 1.0\r
+  ENTRY_POINT               = HttpDxeDriverEntryPoint\r
+  UNLOAD_IMAGE              = NetLibDefaultUnload\r
+  MODULE_UNI_FILE           = HttpDxe.uni\r
+\r
+[Packages]\r
+  MdePkg/MdePkg.dec\r
+  MdeModulePkg/MdeModulePkg.dec\r
+\r
+[Sources]\r
+  ComponentName.h\r
+  ComponentName.c\r
+  HttpDns.h\r
+  HttpDns.c\r
+  HttpDriver.h\r
+  HttpDriver.c\r
+  HttpImpl.h\r
+  HttpImpl.c\r
+  HttpProto.h\r
+  HttpProto.c\r
+  HttpUtilities.h\r
+  HttpUtilities.c\r
+\r
+[LibraryClasses]\r
+  UefiDriverEntryPoint\r
+  UefiBootServicesTableLib\r
+  MemoryAllocationLib\r
+  BaseLib\r
+  UefiLib\r
+  DebugLib\r
+  NetLib\r
+  HttpLib\r
+\r
+[Protocols]\r
+  gEfiHttpServiceBindingProtocolGuid               ## BY_START\r
+  gEfiHttpProtocolGuid                             ## BY_START\r
+  gEfiTcp4ServiceBindingProtocolGuid               ## TO_START\r
+  gEfiTcp4ProtocolGuid                             ## TO_START\r
+  gEfiDns4ServiceBindingProtocolGuid               ## SOMETIMES_CONSUMES\r
+  gEfiDns4ProtocolGuid                             ## SOMETIMES_CONSUMES\r
+  gEfiIp4Config2ProtocolGuid                       ## SOMETIMES_CONSUMES\r
+\r
+[UserExtensions.TianoCore."ExtraFiles"]\r
+  HttpDxeExtra.uni
\ No newline at end of file
diff --git a/NetworkPkg/HttpDxe/HttpDxe.uni b/NetworkPkg/HttpDxe/HttpDxe.uni
new file mode 100644 (file)
index 0000000..f9c2ac8
Binary files /dev/null and b/NetworkPkg/HttpDxe/HttpDxe.uni differ
diff --git a/NetworkPkg/HttpDxe/HttpDxeExtra.uni b/NetworkPkg/HttpDxe/HttpDxeExtra.uni
new file mode 100644 (file)
index 0000000..1a06619
Binary files /dev/null and b/NetworkPkg/HttpDxe/HttpDxeExtra.uni differ
diff --git a/NetworkPkg/HttpDxe/HttpImpl.c b/NetworkPkg/HttpDxe/HttpImpl.c
new file mode 100644 (file)
index 0000000..4bd4ac8
--- /dev/null
@@ -0,0 +1,1309 @@
+/** @file\r
+  Implementation of EFI_HTTP_PROTOCOL protocol interfaces.\r
+\r
+  Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>\r
+\r
+  This program and the accompanying materials\r
+  are licensed and made available under the terms and conditions of the BSD License\r
+  which accompanies this distribution.  The full text of the license may be found at\r
+  http://opensource.org/licenses/bsd-license.php.\r
+\r
+  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "HttpDriver.h"\r
+\r
+EFI_HTTP_PROTOCOL  mEfiHttpTemplate = {\r
+  EfiHttpGetModeData,\r
+  EfiHttpConfigure,\r
+  EfiHttpRequest,\r
+  EfiHttpCancel,\r
+  EfiHttpResponse,\r
+  EfiHttpPoll\r
+};\r
+\r
+/**\r
+  Returns the operational parameters for the current HTTP child instance.\r
+\r
+  The GetModeData() function is used to read the current mode data (operational\r
+  parameters) for this HTTP protocol instance.\r
+\r
+  @param[in]  This                Pointer to EFI_HTTP_PROTOCOL instance.\r
+  @param[out] HttpConfigData      Point to buffer for operational parameters of this\r
+                                  HTTP instance.\r
+\r
+  @retval EFI_SUCCESS             Operation succeeded.\r
+  @retval EFI_INVALID_PARAMETER   One or more of the following conditions is TRUE:\r
+                                  This is NULL.\r
+                                  HttpConfigData is NULL.\r
+                                  HttpConfigData->AccessPoint is NULL.\r
+  @retval EFI_NOT_STARTED         The HTTP instance is not configured.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EfiHttpGetModeData (\r
+  IN  EFI_HTTP_PROTOCOL         *This,\r
+  OUT EFI_HTTP_CONFIG_DATA      *HttpConfigData\r
+  )\r
+{\r
+  HTTP_PROTOCOL                 *HttpInstance;\r
+\r
+  if ((This == NULL) || (HttpConfigData == NULL)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+  \r
+  HttpInstance = HTTP_INSTANCE_FROM_PROTOCOL (This);\r
+  ASSERT (HttpInstance != NULL);\r
+\r
+  if (HttpInstance->State < HTTP_STATE_HTTP_CONFIGED) {\r
+    return EFI_NOT_STARTED;\r
+  }\r
+\r
+  if (HttpConfigData->AccessPoint.IPv4Node == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  HttpConfigData->HttpVersion        = HttpInstance->HttpVersion;\r
+  HttpConfigData->TimeOutMillisec    = HttpInstance->TimeOutMillisec;\r
+  HttpConfigData->LocalAddressIsIPv6 = HttpInstance->LocalAddressIsIPv6;\r
+\r
+  CopyMem (\r
+    HttpConfigData->AccessPoint.IPv4Node,\r
+    &HttpInstance->IPv4Node,\r
+    sizeof (HttpInstance->IPv4Node)\r
+    );\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Initialize or brutally reset the operational parameters for this EFI HTTP instance.\r
+\r
+  The Configure() function does the following:\r
+  When HttpConfigData is not NULL Initialize this EFI HTTP instance by configuring\r
+  timeout, local address, port, etc.\r
+  When HttpConfigData is NULL, reset this EFI HTTP instance by closing all active\r
+  connections with remote hosts, canceling all asynchronous tokens, and flush request\r
+  and response buffers without informing the appropriate hosts.\r
+\r
+  Except for GetModeData() and Configure(), No other EFI HTTP function can be executed\r
+  by this instance until the Configure() function is executed and returns successfully.\r
+\r
+  @param[in]  This                Pointer to EFI_HTTP_PROTOCOL instance.\r
+  @param[in]  HttpConfigData      Pointer to the configure data to configure the instance.\r
+\r
+  @retval EFI_SUCCESS             Operation succeeded.\r
+  @retval EFI_INVALID_PARAMETER   One or more of the following conditions is TRUE:\r
+                                  This is NULL.\r
+                                  HttpConfigData->LocalAddressIsIPv6 is FALSE and\r
+                                  HttpConfigData->IPv4Node is NULL.\r
+                                  HttpConfigData->LocalAddressIsIPv6 is TRUE and\r
+                                  HttpConfigData->IPv6Node is NULL.\r
+  @retval EFI_ALREADY_STARTED     Reinitialize this HTTP instance without calling\r
+                                  Configure() with NULL to reset it.\r
+  @retval EFI_DEVICE_ERROR        An unexpected system or network error occurred.\r
+  @retval EFI_OUT_OF_RESOURCES    Could not allocate enough system resources when\r
+                                  executing Configure().\r
+  @retval EFI_UNSUPPORTED         One or more options in HttpConfigData are not supported\r
+                                  in the implementation.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EfiHttpConfigure (\r
+  IN  EFI_HTTP_PROTOCOL         *This,\r
+  IN  EFI_HTTP_CONFIG_DATA      *HttpConfigData\r
+  ) \r
+{\r
+  HTTP_PROTOCOL                 *HttpInstance;\r
+  EFI_STATUS                    Status;\r
+\r
+  if (This == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  HttpInstance = HTTP_INSTANCE_FROM_PROTOCOL (This);\r
+  ASSERT (HttpInstance != NULL && HttpInstance->Service != NULL);\r
+\r
+  if (HttpConfigData != NULL) {\r
+    //\r
+    // Check input parameters.\r
+    //\r
+    if (HttpConfigData->LocalAddressIsIPv6) {\r
+      if (HttpConfigData->AccessPoint.IPv6Node == NULL) {\r
+        return EFI_INVALID_PARAMETER;\r
+      }\r
+    } else {\r
+      if (HttpConfigData->AccessPoint.IPv4Node == NULL) {\r
+        return EFI_INVALID_PARAMETER;\r
+      }\r
+    }\r
+    //\r
+    // Now configure this HTTP instance.\r
+    //\r
+    if (HttpInstance->State != HTTP_STATE_UNCONFIGED) {\r
+      return EFI_ALREADY_STARTED;\r
+    }\r
+\r
+    HttpInstance->HttpVersion        = HttpConfigData->HttpVersion;\r
+    HttpInstance->TimeOutMillisec    = HttpConfigData->TimeOutMillisec;\r
+    HttpInstance->LocalAddressIsIPv6 = HttpConfigData->LocalAddressIsIPv6;\r
+\r
+    if (HttpConfigData->LocalAddressIsIPv6) {\r
+      return EFI_UNSUPPORTED;\r
+    } else {\r
+      CopyMem (\r
+        &HttpInstance->IPv4Node,\r
+        HttpConfigData->AccessPoint.IPv4Node,\r
+        sizeof (HttpInstance->IPv4Node)\r
+        );\r
+\r
+      HttpInstance->State = HTTP_STATE_HTTP_CONFIGED;\r
+      return EFI_SUCCESS;\r
+    }\r
+\r
+  } else {\r
+    if (HttpInstance->LocalAddressIsIPv6) {\r
+      return EFI_UNSUPPORTED;\r
+    } else {\r
+      HttpCleanProtocol (HttpInstance);\r
+      Status = HttpInitProtocol (HttpInstance->Service, HttpInstance);\r
+      if (EFI_ERROR (Status)) {\r
+        return Status;\r
+      }\r
+\r
+      HttpInstance->State = HTTP_STATE_UNCONFIGED;\r
+      return EFI_SUCCESS;\r
+    }\r
+  }\r
+}\r
\r
+\r
+/**\r
+  The Request() function queues an HTTP request to this HTTP instance.\r
+\r
+  Similar to Transmit() function in the EFI TCP driver. When the HTTP request is sent\r
+  successfully, or if there is an error, Status in token will be updated and Event will\r
+  be signaled.\r
+\r
+  @param[in]  This                Pointer to EFI_HTTP_PROTOCOL instance.\r
+  @param[in]  Token               Pointer to storage containing HTTP request token.\r
+\r
+  @retval EFI_SUCCESS             Outgoing data was processed.\r
+  @retval EFI_NOT_STARTED         This EFI HTTP Protocol instance has not been started.\r
+  @retval EFI_DEVICE_ERROR        An unexpected system or network error occurred.\r
+  @retval EFI_TIMEOUT             Data was dropped out of the transmit or receive queue.\r
+  @retval EFI_OUT_OF_RESOURCES    Could not allocate enough system resources.\r
+  @retval EFI_UNSUPPORTED         The HTTP method is not supported in current\r
+                                  implementation.\r
+  @retval EFI_INVALID_PARAMETER   One or more of the following conditions is TRUE:\r
+                                  This is NULL.\r
+                                  Token->Message is NULL.\r
+                                  Token->Message->Body is not NULL,\r
+                                  Token->Message->BodyLength is non-zero, and\r
+                                  Token->Message->Data is NULL, but a previous call to\r
+                                  Request()has not been completed successfully.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EfiHttpRequest (\r
+  IN  EFI_HTTP_PROTOCOL         *This,\r
+  IN  EFI_HTTP_TOKEN            *Token\r
+  )\r
+{\r
+  EFI_HTTP_MESSAGE              *HttpMsg;\r
+  EFI_HTTP_REQUEST_DATA         *Request;\r
+  VOID                          *UrlParser;\r
+  EFI_STATUS                    Status;\r
+  CHAR8                         *HostName;\r
+  UINT16                        RemotePort;\r
+  HTTP_PROTOCOL                 *HttpInstance;\r
+  BOOLEAN                       Configure;\r
+  BOOLEAN                       ReConfigure;\r
+  CHAR8                         *RequestStr;\r
+  CHAR8                         *Url;\r
+  CHAR16                        *HostNameStr;\r
+  HTTP_TOKEN_WRAP               *Wrap;\r
+  HTTP_TCP_TOKEN_WRAP           *TcpWrap;\r
+\r
+  if ((This == NULL) || (Token == NULL)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  HttpMsg = Token->Message;\r
+  if ((HttpMsg == NULL) || (HttpMsg->Headers == NULL)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  //\r
+  // Current implementation does not support POST/PUT method.\r
+  // If future version supports these two methods, Request could be NULL for a special case that to send large amounts\r
+  // of data. For this case, the implementation need check whether previous call to Request() has been completed or not.\r
+  // \r
+  //\r
+  Request = HttpMsg->Data.Request;\r
+  if ((Request == NULL) || (Request->Url == NULL)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  //\r
+  // Only support GET and HEAD method in current implementation.\r
+  //\r
+  if ((Request->Method != HttpMethodGet) && (Request->Method != HttpMethodHead)) {\r
+    return EFI_UNSUPPORTED;\r
+  }\r
+\r
+  HttpInstance = HTTP_INSTANCE_FROM_PROTOCOL (This);\r
+  ASSERT (HttpInstance != NULL);\r
+\r
+  if (HttpInstance->State < HTTP_STATE_HTTP_CONFIGED) {\r
+    return EFI_NOT_STARTED;\r
+  }\r
+\r
+  if (HttpInstance->LocalAddressIsIPv6) {\r
+    return EFI_UNSUPPORTED;\r
+  }\r
+\r
+  //\r
+  // Check whether the token already existed.\r
+  //\r
+  if (EFI_ERROR (NetMapIterate (&HttpInstance->TxTokens, HttpTokenExist, Token))) {\r
+    return EFI_ACCESS_DENIED;   \r
+  }  \r
+\r
+  Url         = NULL;\r
+  HostName    = NULL;\r
+  Wrap        = NULL;\r
+  HostNameStr = NULL;\r
+  TcpWrap     = NULL;\r
+\r
+  //\r
+  // Parse the URI of the remote host.\r
+  //\r
+  Url = AllocatePool (StrLen (Request->Url) + 1);\r
+  if (Url == NULL) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  UnicodeStrToAsciiStr (Request->Url, Url);\r
+  UrlParser = NULL;\r
+  Status = HttpParseUrl (Url, (UINT32) AsciiStrLen (Url), FALSE, &UrlParser);\r
+  if (EFI_ERROR (Status)) {\r
+    goto Error1;\r
+  }\r
+\r
+  RequestStr = NULL;\r
+  HostName   = NULL;\r
+  Status     = HttpUrlGetHostName (Url, UrlParser, &HostName);\r
+  if (EFI_ERROR (Status)) {\r
+    goto Error1;\r
+  }\r
+\r
+  Status = HttpUrlGetPort (Url, UrlParser, &RemotePort);\r
+  if (EFI_ERROR (Status)) {\r
+    RemotePort = HTTP_DEFAULT_PORT;\r
+  }\r
+\r
+  Configure   = TRUE;\r
+  ReConfigure = TRUE;  \r
+\r
+  if (HttpInstance->RemoteHost == NULL && HttpInstance->RemotePort == 0) {\r
+    //\r
+    // Request() is called the first time. \r
+    //\r
+    ReConfigure = FALSE;\r
+  } else {\r
+    if ((HttpInstance->RemotePort == RemotePort) &&\r
+        (AsciiStrCmp (HttpInstance->RemoteHost, HostName) == 0)) {\r
+      //\r
+      // Host Name and port number of the request URL are the same with previous call to Request().\r
+      // Check whether previous TCP packet sent out.\r
+      //\r
+      if (EFI_ERROR (NetMapIterate (&HttpInstance->TxTokens, HttpTcpNotReady, NULL))) {\r
+        //\r
+        // Wrap the HTTP token in HTTP_TOKEN_WRAP\r
+        //\r
+        Wrap = AllocateZeroPool (sizeof (HTTP_TOKEN_WRAP));\r
+        if (Wrap == NULL) {\r
+          Status = EFI_OUT_OF_RESOURCES;\r
+          goto Error1;\r
+        }\r
+\r
+        Wrap->HttpToken    = Token;\r
+        Wrap->HttpInstance = HttpInstance;\r
+\r
+        Status = HttpCreateTcp4TxEvent (Wrap);\r
+        if (EFI_ERROR (Status)) {\r
+          goto Error1;\r
+        }\r
+\r
+        Status = NetMapInsertTail (&HttpInstance->TxTokens, Token, Wrap);\r
+        if (EFI_ERROR (Status)) {\r
+          goto Error1;\r
+        }\r
+\r
+        Wrap->TcpWrap.Method = Request->Method;\r
+\r
+        FreePool (Url);\r
+        FreePool (HostName);\r
+        \r
+        //\r
+        // Queue the HTTP token and return.\r
+        //\r
+        return EFI_SUCCESS;\r
+      } else {\r
+        //\r
+        // Use existing TCP instance to transmit the packet.\r
+        //\r
+        Configure   = FALSE;\r
+        ReConfigure = FALSE;\r
+      }\r
+    } else {\r
+      //\r
+      // Need close existing TCP instance and create a new TCP instance for data transmit.\r
+      //\r
+      if (HttpInstance->RemoteHost != NULL) {\r
+        FreePool (HttpInstance->RemoteHost);\r
+        HttpInstance->RemoteHost = NULL;\r
+      }\r
+    }\r
+  } \r
+\r
+  if (Configure) {\r
+    //\r
+    // Parse Url for IPv4 address, if failed, perform DNS resolution.\r
+    //\r
+    Status = NetLibAsciiStrToIp4 (HostName, &HttpInstance->RemoteAddr);\r
+    if (EFI_ERROR (Status)) {\r
+      HostNameStr = AllocateZeroPool ((AsciiStrLen (HostName) + 1) * sizeof (UINT16));\r
+      if (HostNameStr == NULL) {\r
+        Status = EFI_OUT_OF_RESOURCES;\r
+        goto Error1;\r
+      }\r
+\r
+      AsciiStrToUnicodeStr (HostName, HostNameStr);\r
+      Status = HttpDns4 (HttpInstance, HostNameStr, &HttpInstance->RemoteAddr);\r
+      FreePool (HostNameStr);\r
+      if (EFI_ERROR (Status)) {\r
+        goto Error1;\r
+      }\r
+    }\r
+\r
+    //\r
+    // Save the RemotePort and RemoteHost.\r
+    //\r
+    ASSERT (HttpInstance->RemoteHost == NULL);\r
+    HttpInstance->RemotePort = RemotePort;\r
+    HttpInstance->RemoteHost = HostName;\r
+    HostName = NULL;\r
+  }\r
+\r
+  if (ReConfigure) {\r
+    //\r
+    // The request URL is different from previous calls to Request(), close existing TCP instance.\r
+    //\r
+    ASSERT (HttpInstance->Tcp4 != NULL);\r
+    HttpCloseConnection (HttpInstance);\r
+    EfiHttpCancel (This, NULL);\r
+  }\r
+\r
+  //\r
+  // Wrap the HTTP token in HTTP_TOKEN_WRAP\r
+  //\r
+  Wrap = AllocateZeroPool (sizeof (HTTP_TOKEN_WRAP));\r
+  if (Wrap == NULL) {\r
+    Status = EFI_OUT_OF_RESOURCES;\r
+    goto Error1;\r
+  }\r
+\r
+  Wrap->HttpToken      = Token;\r
+  Wrap->HttpInstance   = HttpInstance;\r
+  Wrap->TcpWrap.Method = Request->Method;\r
+\r
+  if (Configure) {\r
+    //\r
+    // Configure TCP instance.\r
+    //\r
+    Status = HttpConfigureTcp4 (HttpInstance, Wrap);\r
+    if (EFI_ERROR (Status)) {\r
+      goto Error1;\r
+    }\r
+    //\r
+    // Connect TCP.\r
+    //\r
+    Status = HttpConnectTcp4 (HttpInstance);\r
+    if (EFI_ERROR (Status)) {\r
+      goto Error2;\r
+    }\r
+  } else {\r
+    //\r
+    // For the new HTTP token, create TX TCP token events.    \r
+    //\r
+    Status = HttpCreateTcp4TxEvent (Wrap);\r
+    if (EFI_ERROR (Status)) {\r
+      goto Error1;\r
+    }\r
+  }\r
+\r
+  //\r
+  // Create request message.\r
+  //\r
+  RequestStr = HttpGenRequestString (HttpInstance, HttpMsg, Url);\r
+  if (RequestStr == NULL) {\r
+    Status = EFI_OUT_OF_RESOURCES;\r
+    goto Error3;\r
+  }\r
+\r
+  Status = NetMapInsertTail (&HttpInstance->TxTokens, Token, Wrap);\r
+  if (EFI_ERROR (Status)) {\r
+    goto Error4;\r
+  }\r
+\r
+  FreePool (Url);\r
+  if (HostName != NULL) {\r
+    FreePool (HostName);\r
+  }\r
+\r
+  //\r
+  // Transmit the request message.\r
+  //\r
+  Status = HttpTransmitTcp4 (\r
+             HttpInstance,\r
+             Wrap,\r
+             (UINT8*) RequestStr,\r
+             AsciiStrLen (RequestStr)\r
+             );\r
+  if (EFI_ERROR (Status)) {\r
+    goto Error5;    \r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+\r
+Error5:\r
+    NetMapRemoveTail (&HttpInstance->TxTokens, NULL);\r
+\r
+Error4:\r
+  if (RequestStr != NULL) {\r
+    FreePool (RequestStr);\r
+  }  \r
+\r
+Error3:\r
+  HttpCloseConnection (HttpInstance);\r
+\r
+\r
+Error2:\r
+  HttpCloseTcp4ConnCloseEvent (HttpInstance);\r
+  if (NULL != Wrap->TcpWrap.TxToken.CompletionToken.Event) {\r
+    gBS->CloseEvent (Wrap->TcpWrap.TxToken.CompletionToken.Event);\r
+  }\r
+\r
+Error1:\r
+  if (Url != NULL) {\r
+    FreePool (Url);\r
+  }\r
+  if (HostName != NULL) {\r
+    FreePool (HostName);\r
+  }\r
+  if (Wrap != NULL) {\r
+    FreePool (Wrap);\r
+  }\r
+  if (UrlParser!= NULL) {\r
+    HttpUrlFreeParser (UrlParser);\r
+  }\r
+\r
+  return Status;\r
+  \r
+}\r
+\r
+/**\r
+  Cancel a TxToken or RxToken. \r
\r
+  @param[in]  Map                The HTTP instance's token queue.\r
+  @param[in]  Item               Object container for one HTTP token and token's wrap.\r
+  @param[in]  Context            The user's token to cancel.\r
+\r
+  @retval EFI_SUCCESS            Continue to check the next Item.\r
+  @retval EFI_ABORTED            The user's Token (Token != NULL) is cancelled.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+HttpCancelTokens (\r
+  IN NET_MAP                *Map,\r
+  IN NET_MAP_ITEM           *Item,\r
+  IN VOID                   *Context\r
+  )\r
+{\r
+\r
+  EFI_HTTP_TOKEN            *Token;\r
+  HTTP_TOKEN_WRAP           *Wrap;\r
+\r
+  Token = (EFI_HTTP_TOKEN *) Context;\r
+\r
+  //\r
+  // Return EFI_SUCCESS to check the next item in the map if\r
+  // this one doesn't match.\r
+  //\r
+  if ((Token != NULL) && (Token != Item->Key)) {\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  Wrap = (HTTP_TOKEN_WRAP *) Item->Value;\r
+  ASSERT (Wrap != NULL);\r
+\r
+  //\r
+  // Free resources.\r
+  //\r
+  NetMapRemoveItem (Map, Item, NULL); \r
+  \r
+  if (Wrap->TcpWrap.TxToken.CompletionToken.Event != NULL) {\r
+    gBS->CloseEvent (Wrap->TcpWrap.TxToken.CompletionToken.Event);\r
+  }\r
+\r
+  if (Wrap->TcpWrap.RxToken.CompletionToken.Event != NULL) {\r
+    gBS->CloseEvent (Wrap->TcpWrap.RxToken.CompletionToken.Event);\r
+  }\r
+\r
+  if (Wrap->TcpWrap.RxToken.Packet.RxData->FragmentTable[0].FragmentBuffer != NULL) {\r
+    FreePool (Wrap->TcpWrap.RxToken.Packet.RxData->FragmentTable[0].FragmentBuffer);\r
+  }\r
+\r
+  FreePool (Wrap);\r
+\r
+  //\r
+  // If only one item is to be cancel, return EFI_ABORTED to stop\r
+  // iterating the map any more.\r
+  //\r
+  if (Token != NULL) {\r
+    return EFI_ABORTED;\r
+  }\r
+\r
+  return EFI_SUCCESS; \r
+}\r
+\r
+/**\r
+  Cancel the user's receive/transmit request. It is the worker function of\r
+  EfiHttpCancel API. If a matching token is found, it will call HttpCancelTokens to cancel the\r
+  token.\r
+\r
+  @param[in]  HttpInstance       Pointer to HTTP_PROTOCOL structure.\r
+  @param[in]  Token              The token to cancel. If NULL, all token will be\r
+                                 cancelled.\r
+\r
+  @retval EFI_SUCCESS            The token is cancelled.\r
+  @retval EFI_NOT_FOUND          The asynchronous request or response token is not found.                                 \r
+  @retval Others                 Other error as indicated.\r
+\r
+**/\r
+EFI_STATUS\r
+HttpCancel (\r
+  IN  HTTP_PROTOCOL             *HttpInstance,\r
+  IN  EFI_HTTP_TOKEN            *Token\r
+  )\r
+{\r
+  EFI_STATUS                    Status;\r
+\r
+  //\r
+  // First check the tokens queued by EfiHttpRequest().\r
+  //\r
+  Status = NetMapIterate (&HttpInstance->TxTokens, HttpCancelTokens, Token);\r
+  if (EFI_ERROR (Status)) {\r
+    if (Token != NULL) {\r
+      if (Status == EFI_ABORTED) {\r
+        return EFI_SUCCESS;\r
+      } \r
+    } else {\r
+      return Status;\r
+    }\r
+  }\r
+\r
+  //\r
+  // Then check the tokens queued by EfiHttpResponse().\r
+  //\r
+  Status = NetMapIterate (&HttpInstance->RxTokens, HttpCancelTokens, Token);\r
+  if (EFI_ERROR (Status)) {\r
+    if (Token != NULL) {\r
+      if (Status == EFI_ABORTED) {\r
+        return EFI_SUCCESS;\r
+      } else {\r
+        return EFI_NOT_FOUND;\r
+      }\r
+    } else {\r
+      return Status;\r
+    }\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+  Abort an asynchronous HTTP request or response token.\r
+\r
+  The Cancel() function aborts a pending HTTP request or response transaction. If\r
+  Token is not NULL and the token is in transmit or receive queues when it is being\r
+  cancelled, its Token->Status will be set to EFI_ABORTED and then Token->Event will\r
+  be signaled. If the token is not in one of the queues, which usually means that the\r
+  asynchronous operation has completed, EFI_NOT_FOUND is returned. If Token is NULL,\r
+  all asynchronous tokens issued by Request() or Response() will be aborted.\r
+\r
+  @param[in]  This                Pointer to EFI_HTTP_PROTOCOL instance.\r
+  @param[in]  Token               Point to storage containing HTTP request or response\r
+                                  token.\r
+\r
+  @retval EFI_SUCCESS             Request and Response queues are successfully flushed.\r
+  @retval EFI_INVALID_PARAMETER   This is NULL.\r
+  @retval EFI_NOT_STARTED         This instance hasn't been configured.\r
+  @retval EFI_NO_MAPPING          When using the default address, configuration (DHCP,\r
+                                  BOOTP, RARP, etc.) hasn't finished yet.\r
+  @retval EFI_NOT_FOUND           The asynchronous request or response token is not\r
+                                  found.\r
+  @retval EFI_UNSUPPORTED         The implementation does not support this function.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EfiHttpCancel (\r
+  IN  EFI_HTTP_PROTOCOL         *This,\r
+  IN  EFI_HTTP_TOKEN            *Token\r
+  )\r
+{\r
+  HTTP_PROTOCOL                 *HttpInstance;\r
+\r
+  if (This == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  HttpInstance = HTTP_INSTANCE_FROM_PROTOCOL (This);\r
+  ASSERT (HttpInstance != NULL);\r
+\r
+  if (HttpInstance->State != HTTP_STATE_TCP_CONNECTED) {\r
+    return EFI_NOT_STARTED;\r
+  }\r
+\r
+  return HttpCancel (HttpInstance, Token);\r
+\r
+}\r
+\r
+/**\r
+  A callback function to intercept events during message parser.\r
+\r
+  This function will be invoked during HttpParseMessageBody() with various events type. An error\r
+  return status of the callback function will cause the HttpParseMessageBody() aborted.\r
+\r
+  @param[in]    EventType          Event type of this callback call.\r
+  @param[in]    Data               A pointer to data buffer.\r
+  @param[in]    Length             Length in bytes of the Data.\r
+  @param[in]    Context            Callback context set by HttpInitMsgParser().\r
+\r
+  @retval EFI_SUCCESS              Continue to parser the message body.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+HttpBodyParserCallback (\r
+  IN HTTP_BODY_PARSE_EVENT      EventType,\r
+  IN CHAR8                      *Data,\r
+  IN UINTN                      Length,\r
+  IN VOID                       *Context\r
+  )\r
+{\r
+  HTTP_TOKEN_WRAP               *Wrap;\r
+\r
+  if (EventType != BodyParseEventOnComplete) {\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  if (Data == NULL || Length != 0 || Context == NULL) {\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  Wrap = (HTTP_TOKEN_WRAP *) Context;\r
+  Wrap->HttpInstance->NextMsg = Data;\r
+\r
+  //\r
+  // Free TxToken since already received corrsponding HTTP response.\r
+  //\r
+  FreePool (Wrap);\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  The work function of EfiHttpResponse().\r
+\r
+  @param[in]  Wrap                Pointer to HTTP token's wrap data.\r
+\r
+  @retval EFI_SUCCESS             Allocation succeeded.\r
+  @retval EFI_OUT_OF_RESOURCES    Failed to complete the opration due to lack of resources.\r
+  @retval EFI_NOT_READY           Can't find a corresponding TxToken.\r
+\r
+**/\r
+EFI_STATUS\r
+HttpResponseWorker (\r
+  IN  HTTP_TOKEN_WRAP           *Wrap\r
+  )\r
+{\r
+  EFI_STATUS                    Status;\r
+  EFI_HTTP_MESSAGE              *HttpMsg;\r
+  EFI_TCP4_IO_TOKEN             *RxToken;\r
+  EFI_TCP4_PROTOCOL             *Tcp4;\r
+  CHAR8                         *EndofHeader;\r
+  CHAR8                         *HttpHeaders;\r
+  UINTN                         SizeofHeaders;\r
+  CHAR8                         *Buffer;\r
+  UINTN                         BufferSize;\r
+  UINTN                         StatusCode;\r
+  CHAR8                         *Tmp;\r
+  CHAR8                         *HeaderTmp;\r
+  CHAR8                         *StatusCodeStr;\r
+  UINTN                         BodyLen;\r
+  HTTP_PROTOCOL                 *HttpInstance;\r
+  EFI_HTTP_TOKEN                *Token;\r
+  NET_MAP_ITEM                  *Item;\r
+  HTTP_TOKEN_WRAP               *ValueInItem;\r
+  UINTN                         HdrLen;\r
+\r
+  HttpInstance = Wrap->HttpInstance;\r
+  Token = Wrap->HttpToken;\r
+\r
+  HttpMsg = Token->Message;\r
+\r
+  Tcp4 = HttpInstance->Tcp4;\r
+  ASSERT (Tcp4 != NULL);\r
+  HttpMsg->Headers = NULL;\r
+  HttpHeaders   = NULL;\r
+  SizeofHeaders = 0;\r
+  Buffer        = NULL;\r
+  BufferSize    = 0;\r
+  EndofHeader   = NULL;\r
\r
+  if (HttpMsg->Data.Response != NULL) {\r
+    //\r
+    // Need receive the HTTP headers, prepare buffer.\r
+    //\r
+    Status = HttpCreateTcp4RxEventForHeader (HttpInstance);\r
+    if (EFI_ERROR (Status)) {\r
+      goto Error;\r
+    }\r
+\r
+    //\r
+    // Check whether we have cached header from previous call.\r
+    //\r
+    if ((HttpInstance->CacheBody != NULL) && (HttpInstance->NextMsg != NULL)) {\r
+      //\r
+      // The data is stored at [NextMsg, CacheBody + CacheLen].\r
+      //\r
+      HdrLen = HttpInstance->CacheBody + HttpInstance->CacheLen - HttpInstance->NextMsg;\r
+      HttpHeaders = AllocateZeroPool (HdrLen);\r
+      if (HttpHeaders == NULL) {\r
+        Status = EFI_OUT_OF_RESOURCES;\r
+        goto Error;\r
+      }\r
+\r
+      CopyMem (HttpHeaders, HttpInstance->NextMsg, HdrLen);\r
+      FreePool (HttpInstance->CacheBody);\r
+      HttpInstance->CacheBody   = NULL;\r
+      HttpInstance->NextMsg     = NULL;\r
+      HttpInstance->CacheOffset = 0;\r
+      SizeofHeaders = HdrLen;\r
+      BufferSize = HttpInstance->CacheLen;\r
+\r
+      //\r
+      // Check whether we cached the whole HTTP headers.\r
+      //\r
+      EndofHeader = AsciiStrStr (HttpHeaders, HTTP_END_OF_HDR_STR); \r
+    }\r
+    \r
+    RxToken = &HttpInstance->RxToken;\r
+    RxToken->Packet.RxData->FragmentTable[0].FragmentBuffer = AllocateZeroPool (DEF_BUF_LEN);\r
+    if (RxToken->Packet.RxData->FragmentTable[0].FragmentBuffer == NULL) {\r
+      Status = EFI_OUT_OF_RESOURCES;\r
+      goto Error;\r
+    }\r
+\r
+    //\r
+    // Receive the HTTP headers only when EFI_HTTP_RESPONSE_DATA is not NULL.\r
+    //\r
+    while (EndofHeader == NULL) {   \r
+      HttpInstance->IsRxDone = FALSE;\r
+      RxToken->Packet.RxData->DataLength = DEF_BUF_LEN;\r
+      RxToken->Packet.RxData->FragmentTable[0].FragmentLength = DEF_BUF_LEN;\r
+      Status = Tcp4->Receive (Tcp4, RxToken);\r
+      if (EFI_ERROR (Status)) {\r
+        DEBUG ((EFI_D_ERROR, "Tcp4 receive failed: %r\n", Status));\r
+        goto Error;\r
+      }\r
+      \r
+      while (!HttpInstance->IsRxDone) {\r
+       Tcp4->Poll (Tcp4);\r
+      }    \r
+\r
+      Status = RxToken->CompletionToken.Status;\r
+      if (EFI_ERROR (Status)) {\r
+        goto Error;\r
+      }\r
+\r
+      //\r
+      // Append the response string.\r
+      //\r
+      BufferSize = SizeofHeaders + RxToken->Packet.RxData->FragmentTable[0].FragmentLength;\r
+      Buffer = AllocateZeroPool (BufferSize);\r
+      if (Buffer == NULL) {\r
+        Status = EFI_OUT_OF_RESOURCES;\r
+        goto Error;\r
+      }\r
+\r
+      if (HttpHeaders != NULL) {\r
+        CopyMem (Buffer, HttpHeaders, SizeofHeaders);\r
+        FreePool (HttpHeaders);\r
+      }\r
+\r
+      CopyMem (\r
+        Buffer + SizeofHeaders,\r
+        RxToken->Packet.RxData->FragmentTable[0].FragmentBuffer,\r
+        RxToken->Packet.RxData->FragmentTable[0].FragmentLength\r
+        );\r
+      HttpHeaders   = Buffer;\r
+      SizeofHeaders = BufferSize;\r
+\r
+      //\r
+      // Check whether we received end of HTTP headers.\r
+      //\r
+      EndofHeader = AsciiStrStr (HttpHeaders, HTTP_END_OF_HDR_STR); \r
+    };\r
+\r
+    //\r
+    // Skip the CRLF after the HTTP headers.\r
+    //\r
+    EndofHeader = EndofHeader + AsciiStrLen (HTTP_END_OF_HDR_STR);\r
+\r
+    //\r
+    // Cache the part of body.\r
+    //\r
+    BodyLen = BufferSize - (EndofHeader - HttpHeaders);\r
+    if (BodyLen > 0) {\r
+      if (HttpInstance->CacheBody != NULL) {\r
+        FreePool (HttpInstance->CacheBody);\r
+      }\r
+\r
+      HttpInstance->CacheBody = AllocateZeroPool (BodyLen);\r
+      if (HttpInstance->CacheBody == NULL) {\r
+        Status = EFI_OUT_OF_RESOURCES;\r
+        goto Error;\r
+      }\r
+\r
+      CopyMem (HttpInstance->CacheBody, EndofHeader, BodyLen);\r
+      HttpInstance->CacheLen = BodyLen;\r
+    }\r
+\r
+    FreePool (RxToken->Packet.RxData->FragmentTable[0].FragmentBuffer);\r
+    RxToken->Packet.RxData->FragmentTable[0].FragmentBuffer = NULL;\r
+\r
+    //\r
+    // Search for Status Code.\r
+    //\r
+    StatusCodeStr = HttpHeaders + AsciiStrLen (HTTP_VERSION_STR) + 1;\r
+    if (StatusCodeStr == NULL) {\r
+      goto Error;\r
+    }\r
+\r
+    StatusCode = AsciiStrDecimalToUintn (StatusCodeStr);\r
+\r
+    //\r
+    // Remove the first line of HTTP message, e.g. "HTTP/1.1 200 OK\r\n".\r
+    //\r
+    Tmp = AsciiStrStr (HttpHeaders, HTTP_CRLF_STR);\r
+    if (Tmp == NULL) {\r
+      goto Error;\r
+    }\r
+\r
+    Tmp = Tmp + AsciiStrLen (HTTP_CRLF_STR);\r
+    SizeofHeaders = SizeofHeaders - (Tmp - HttpHeaders);\r
+    HeaderTmp = AllocateZeroPool (SizeofHeaders);\r
+    if (HeaderTmp == NULL) {\r
+      goto Error;\r
+    }\r
+\r
+    CopyMem (HeaderTmp, Tmp, SizeofHeaders);\r
+    FreePool (HttpHeaders);\r
+    HttpHeaders = HeaderTmp;\r
+    //\r
+    // Parse the HTTP header into array of key/value pairs.\r
+    //\r
+    Status = HttpUtilitiesParse (HttpHeaders, SizeofHeaders, &HttpMsg->Headers, &HttpMsg->HeaderCount);\r
+    if (EFI_ERROR (Status)) {\r
+      goto Error;\r
+    }\r
+\r
+    FreePool (HttpHeaders);\r
+    HttpHeaders = NULL;\r
+    \r
+    HttpMsg->Data.Response->StatusCode = HttpMappingToStatusCode (StatusCode);\r
+\r
+    //\r
+    // Init message-body parser by header information.  \r
+    //\r
+    Status = EFI_NOT_READY;\r
+    ValueInItem = NULL;\r
+    NetMapRemoveHead (&HttpInstance->TxTokens, (VOID**) &ValueInItem);\r
+    if (ValueInItem == NULL)  {\r
+      goto Error;\r
+    }\r
+\r
+    //\r
+    // The first TxToken not transmitted yet, insert back and return error.\r
+    //\r
+    if (!ValueInItem->TcpWrap.IsTxDone) {\r
+      goto Error2;\r
+    }\r
+\r
+    Status = HttpInitMsgParser (\r
+               ValueInItem->TcpWrap.Method,\r
+               HttpMsg->Data.Response->StatusCode,\r
+               HttpMsg->HeaderCount,\r
+               HttpMsg->Headers,\r
+               HttpBodyParserCallback,\r
+               (VOID *) ValueInItem,\r
+               &HttpInstance->MsgParser\r
+               );\r
+    if (EFI_ERROR (Status)) {       \r
+      goto Error2;\r
+    }\r
+\r
+    //\r
+    // Check whether we received a complete HTTP message.\r
+    //\r
+    if (HttpInstance->CacheBody != NULL) {\r
+      Status = HttpParseMessageBody (HttpInstance->MsgParser, HttpInstance->CacheLen, HttpInstance->CacheBody);\r
+      if (EFI_ERROR (Status)) {\r
+        goto Error2;\r
+      }\r
+\r
+      if (HttpIsMessageComplete (HttpInstance->MsgParser)) {\r
+        //\r
+        // Free the MsgParse since we already have a full HTTP message.\r
+        //\r
+        HttpFreeMsgParser (HttpInstance->MsgParser);\r
+        HttpInstance->MsgParser = NULL;\r
+      }\r
+    }\r
+\r
+    if ((HttpMsg->Body == NULL) || (HttpMsg->BodyLength == 0)) {    \r
+      Status = EFI_SUCCESS;\r
+      goto Exit;\r
+    }\r
+  }  \r
+\r
+  //\r
+  // Receive the response body.\r
+  //\r
+  BodyLen = 0;\r
+\r
+  //\r
+  // First check whether we cached some data.\r
+  //\r
+  if (HttpInstance->CacheBody != NULL) {\r
+    //\r
+    // Calculate the length of the cached data.\r
+    //\r
+    if (HttpInstance->NextMsg != NULL) {\r
+      //\r
+      // We have a cached HTTP message which includes a part of HTTP header of next message.\r
+      //\r
+      BodyLen = HttpInstance->NextMsg - (HttpInstance->CacheBody + HttpInstance->CacheOffset);      \r
+    } else {\r
+      BodyLen = HttpInstance->CacheLen - HttpInstance->CacheOffset;\r
+    }\r
+\r
+    if (BodyLen > 0) {\r
+      //\r
+      // We have some cached data. Just copy the data and return.\r
+      //\r
+      if (HttpMsg->BodyLength < BodyLen) {\r
+        CopyMem (HttpMsg->Body, HttpInstance->CacheBody + HttpInstance->CacheOffset, HttpMsg->BodyLength);\r
+        HttpInstance->CacheOffset = HttpInstance->CacheOffset + HttpMsg->BodyLength;\r
+      } else {\r
+        //\r
+        // Copy all cached data out.\r
+        //\r
+        CopyMem (HttpMsg->Body, HttpInstance->CacheBody + HttpInstance->CacheOffset, BodyLen);\r
+        HttpInstance->CacheOffset = BodyLen + HttpInstance->CacheOffset;\r
+        HttpMsg->BodyLength = BodyLen;\r
+\r
+        if (HttpInstance->NextMsg == NULL) {\r
+          //\r
+          // There is no HTTP header of next message. Just free the cache buffer.\r
+          //\r
+          FreePool (HttpInstance->CacheBody);\r
+          HttpInstance->CacheBody   = NULL;\r
+          HttpInstance->NextMsg     = NULL;\r
+          HttpInstance->CacheOffset = 0;\r
+        }\r
+      }\r
+      //\r
+      // Return since we aready received required data.\r
+      //\r
+      Status = EFI_SUCCESS;\r
+      goto Exit;\r
+    } \r
+\r
+    if (BodyLen == 0 && HttpInstance->MsgParser == NULL) {\r
+      //\r
+      // We received a complete HTTP message, and we don't have more data to return to caller.\r
+      //\r
+      HttpMsg->BodyLength = 0;\r
+      Status = EFI_SUCCESS;\r
+      goto Exit;      \r
+    }    \r
+  }\r
+\r
+  ASSERT (HttpInstance->MsgParser != NULL);\r
+\r
+  //\r
+  // We still need receive more data when there is no cache data and MsgParser is not NULL;\r
+  //\r
+  RxToken = &Wrap->TcpWrap.RxToken;\r
+\r
+  RxToken->Packet.RxData->DataLength = (UINT32) HttpMsg->BodyLength;\r
+  RxToken->Packet.RxData->FragmentTable[0].FragmentLength = (UINT32) HttpMsg->BodyLength;\r
+  RxToken->Packet.RxData->FragmentTable[0].FragmentBuffer = (VOID *) HttpMsg->Body;\r
+\r
+  RxToken->CompletionToken.Status = EFI_NOT_READY;\r
+  Status = Tcp4->Receive (Tcp4, RxToken);\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG ((EFI_D_ERROR, "Tcp4 receive failed: %r\n", Status));\r
+    goto Error;\r
+  }\r
+\r
+  return Status;\r
+\r
+Exit:\r
+  Item = NetMapFindKey (&Wrap->HttpInstance->RxTokens, Wrap->HttpToken);\r
+  if (Item != NULL) {\r
+    NetMapRemoveItem (&Wrap->HttpInstance->RxTokens, Item, NULL);\r
+  }\r
+  Token->Status = Status;\r
+  gBS->SignalEvent (Token->Event);\r
+  FreePool (Wrap);\r
+  return Status;\r
+\r
+Error2:\r
+  NetMapInsertHead (&HttpInstance->TxTokens, ValueInItem->HttpToken, ValueInItem);\r
+\r
+Error:\r
+  if (Wrap != NULL) {\r
+    if (Wrap->TcpWrap.RxToken.CompletionToken.Event != NULL) {\r
+      gBS->CloseEvent (Wrap->TcpWrap.RxToken.CompletionToken.Event);\r
+    }\r
+    RxToken = &Wrap->TcpWrap.RxToken;\r
+    if (RxToken->Packet.RxData->FragmentTable[0].FragmentBuffer != NULL) {\r
+      FreePool (RxToken->Packet.RxData->FragmentTable[0].FragmentBuffer);\r
+      RxToken->Packet.RxData->FragmentTable[0].FragmentBuffer = NULL;\r
+    }\r
+    FreePool (Wrap);\r
+  }\r
+\r
+  if (HttpInstance->RxToken.CompletionToken.Event != NULL) {\r
+    gBS->CloseEvent (HttpInstance->RxToken.CompletionToken.Event);\r
+    HttpInstance->RxToken.CompletionToken.Event = NULL;\r
+  }\r
+\r
+  RxToken = &HttpInstance->RxToken;\r
+  if (RxToken->Packet.RxData->FragmentTable[0].FragmentBuffer != NULL) {\r
+    FreePool (RxToken->Packet.RxData->FragmentTable[0].FragmentBuffer);\r
+    RxToken->Packet.RxData->FragmentTable[0].FragmentBuffer = NULL;\r
+  }\r
+  \r
+  if (HttpHeaders != NULL) {\r
+    FreePool (HttpHeaders);\r
+  }\r
+\r
+  if (HttpMsg->Headers != NULL) {\r
+    FreePool (HttpMsg->Headers);\r
+  }\r
+\r
+  if (HttpInstance->CacheBody != NULL) {\r
+    FreePool (HttpInstance->CacheBody);\r
+    HttpInstance->CacheBody = NULL;\r
+  }\r
+\r
+  Token->Status = Status;\r
+  gBS->SignalEvent (Token->Event);\r
+\r
+  return Status;  \r
+\r
+}\r
+\r
+\r
+/**\r
+  The Response() function queues an HTTP response to this HTTP instance, similar to\r
+  Receive() function in the EFI TCP driver. When the HTTP request is sent successfully,\r
+  or if there is an error, Status in token will be updated and Event will be signaled.\r
+\r
+  The HTTP driver will queue a receive token to the underlying TCP instance. When data\r
+  is received in the underlying TCP instance, the data will be parsed and Token will\r
+  be populated with the response data. If the data received from the remote host\r
+  contains an incomplete or invalid HTTP header, the HTTP driver will continue waiting\r
+  (asynchronously) for more data to be sent from the remote host before signaling\r
+  Event in Token.\r
+\r
+  It is the responsibility of the caller to allocate a buffer for Body and specify the\r
+  size in BodyLength. If the remote host provides a response that contains a content\r
+  body, up to BodyLength bytes will be copied from the receive buffer into Body and\r
+  BodyLength will be updated with the amount of bytes received and copied to Body. This\r
+  allows the client to download a large file in chunks instead of into one contiguous\r
+  block of memory. Similar to HTTP request, if Body is not NULL and BodyLength is\r
+  non-zero and all other fields are NULL or 0, the HTTP driver will queue a receive\r
+  token to underlying TCP instance. If data arrives in the receive buffer, up to\r
+  BodyLength bytes of data will be copied to Body. The HTTP driver will then update\r
+  BodyLength with the amount of bytes received and copied to Body.\r
+\r
+  If the HTTP driver does not have an open underlying TCP connection with the host\r
+  specified in the response URL, Request() will return EFI_ACCESS_DENIED. This is\r
+  consistent with RFC 2616 recommendation that HTTP clients should attempt to maintain\r
+  an open TCP connection between client and host.\r
+\r
+  @param[in]  This                Pointer to EFI_HTTP_PROTOCOL instance.\r
+  @param[in]  Token               Pointer to storage containing HTTP response token.\r
+\r
+  @retval EFI_SUCCESS             Allocation succeeded.\r
+  @retval EFI_NOT_STARTED         This EFI HTTP Protocol instance has not been\r
+                                  initialized.\r
+  @retval EFI_INVALID_PARAMETER   One or more of the following conditions is TRUE:\r
+                                  This is NULL.\r
+                                  Token is NULL.\r
+                                  Token->Message->Headers is NULL.\r
+                                  Token->Message is NULL.\r
+                                  Token->Message->Body is not NULL,\r
+                                  Token->Message->BodyLength is non-zero, and\r
+                                  Token->Message->Data is NULL, but a previous call to\r
+                                  Response() has not been completed successfully.\r
+  @retval EFI_OUT_OF_RESOURCES    Could not allocate enough system resources.\r
+  @retval EFI_ACCESS_DENIED       An open TCP connection is not present with the host\r
+                                  specified by response URL.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EfiHttpResponse (\r
+  IN  EFI_HTTP_PROTOCOL         *This,\r
+  IN  EFI_HTTP_TOKEN            *Token\r
+  )\r
+{\r
+  EFI_STATUS                    Status;\r
+  EFI_HTTP_MESSAGE              *HttpMsg;\r
+  HTTP_PROTOCOL                 *HttpInstance;\r
+  HTTP_TOKEN_WRAP               *Wrap;\r
+\r
+  if ((This == NULL) || (Token == NULL)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  HttpMsg = Token->Message;\r
+  if (HttpMsg == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+  \r
+  HttpInstance = HTTP_INSTANCE_FROM_PROTOCOL (This);\r
+  ASSERT (HttpInstance != NULL);\r
+\r
+  if (HttpInstance->State != HTTP_STATE_TCP_CONNECTED) {\r
+    return EFI_NOT_STARTED;\r
+  }\r
+\r
+  if (HttpInstance->LocalAddressIsIPv6) {\r
+    return EFI_UNSUPPORTED;\r
+  }  \r
+\r
+  //\r
+  // Check whether the token already existed.\r
+  //\r
+  if (EFI_ERROR (NetMapIterate (&HttpInstance->RxTokens, HttpTokenExist, Token))) {\r
+    return EFI_ACCESS_DENIED;   \r
+  }\r
+\r
+  Wrap = AllocateZeroPool (sizeof (HTTP_TOKEN_WRAP));\r
+  if (Wrap == NULL) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  Wrap->HttpInstance = HttpInstance;\r
+  Wrap->HttpToken    = Token;\r
+\r
+  Status = HttpCreateTcp4RxEvent (Wrap);\r
+  if (EFI_ERROR (Status)) {\r
+    goto Error;\r
+  }\r
+\r
+  Status = NetMapInsertTail (&HttpInstance->RxTokens, Token, Wrap);\r
+  if (EFI_ERROR (Status)) {\r
+    goto Error;\r
+  }\r
+\r
+  //\r
+  // If already have pending RxTokens, return directly.\r
+  //\r
+  if (NetMapGetCount (&HttpInstance->RxTokens) > 1) {\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  return HttpResponseWorker (Wrap);\r
+\r
+Error:\r
+  if (Wrap != NULL) {\r
+    if (Wrap->TcpWrap.RxToken.CompletionToken.Event != NULL) {\r
+      gBS->CloseEvent (Wrap->TcpWrap.RxToken.CompletionToken.Event);\r
+    }\r
+    FreePool (Wrap);\r
+  }  \r
+\r
+  return Status;  \r
+}\r
+\r
+/**\r
+  The Poll() function can be used by network drivers and applications to increase the\r
+  rate that data packets are moved between the communication devices and the transmit\r
+  and receive queues.\r
+\r
+  In some systems, the periodic timer event in the managed network driver may not poll\r
+  the underlying communications device fast enough to transmit and/or receive all data\r
+  packets without missing incoming packets or dropping outgoing packets. Drivers and\r
+  applications that are experiencing packet loss should try calling the Poll() function\r
+  more often.\r
+\r
+  @param[in]  This                Pointer to EFI_HTTP_PROTOCOL instance.\r
+\r
+  @retval EFI_SUCCESS             Incoming or outgoing data was processed.\r
+  @retval EFI_DEVICE_ERROR        An unexpected system or network error occurred.\r
+  @retval EFI_INVALID_PARAMETER   This is NULL.\r
+  @retval EFI_NOT_READY           No incoming or outgoing data is processed.\r
+  @retval EFI_NOT_STARTED         This EFI HTTP Protocol instance has not been started.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EfiHttpPoll (\r
+  IN  EFI_HTTP_PROTOCOL         *This\r
+  )\r
+{\r
+  HTTP_PROTOCOL                 *HttpInstance;\r
+\r
+  if (This == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  HttpInstance = HTTP_INSTANCE_FROM_PROTOCOL (This);\r
+  ASSERT (HttpInstance != NULL);\r
+\r
+  if (HttpInstance->LocalAddressIsIPv6) {\r
+    return EFI_UNSUPPORTED;\r
+  }\r
+\r
+  if (HttpInstance->Tcp4 == NULL || HttpInstance->State != HTTP_STATE_TCP_CONNECTED) {\r
+    return EFI_NOT_STARTED;\r
+  }\r
+\r
+  return HttpInstance->Tcp4->Poll (HttpInstance->Tcp4);\r
+}\r
diff --git a/NetworkPkg/HttpDxe/HttpImpl.h b/NetworkPkg/HttpDxe/HttpImpl.h
new file mode 100644 (file)
index 0000000..49c8af1
--- /dev/null
@@ -0,0 +1,239 @@
+/** @file\r
+  The header files of implementation of EFI_HTTP_PROTOCOL protocol interfaces.\r
+\r
+  Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>\r
+\r
+  This program and the accompanying materials\r
+  are licensed and made available under the terms and conditions of the BSD License\r
+  which accompanies this distribution.  The full text of the license may be found at\r
+  http://opensource.org/licenses/bsd-license.php.\r
+\r
+  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#ifndef __EFI_HTTP_IMPL_H__\r
+#define __EFI_HTTP_IMPL_H__\r
+\r
+#define HTTP_DEFAULT_PORT        80\r
+#define HTTP_END_OF_HDR_STR      "\r\n\r\n"\r
+#define HTTP_CRLF_STR            "\r\n"\r
+#define HTTP_VERSION_STR         "HTTP/1.1"\r
+#define HTTP_VERSION_CRLF_STR    " HTTP/1.1\r\n"\r
+#define HTTP_GET_STR             "GET "\r
+#define HTTP_HEAD_STR            "HEAD "\r
+//\r
+// Connect method has maximum length according to EFI_HTTP_METHOD defined in\r
+// UEFI2.5 spec so use this.\r
+//\r
+#define HTTP_MAXIMUM_METHOD_LEN  sizeof ("CONNECT")\r
+\r
+/**\r
+  Returns the operational parameters for the current HTTP child instance.\r
+\r
+  The GetModeData() function is used to read the current mode data (operational\r
+  parameters) for this HTTP protocol instance.\r
+\r
+  @param[in]  This                Pointer to EFI_HTTP_PROTOCOL instance.\r
+  @param[out] HttpConfigData      Point to buffer for operational parameters of this\r
+                                  HTTP instance.\r
+\r
+  @retval EFI_SUCCESS             Operation succeeded.\r
+  @retval EFI_INVALID_PARAMETER   One or more of the following conditions is TRUE:\r
+                                  This is NULL.\r
+                                  HttpConfigData is NULL.\r
+                                  HttpConfigData->AccessPoint is NULL.\r
+  @retval EFI_NOT_STARTED         The HTTP instance is not configured.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EfiHttpGetModeData (\r
+  IN  EFI_HTTP_PROTOCOL         *This,\r
+  OUT EFI_HTTP_CONFIG_DATA      *HttpConfigData\r
+  );\r
+\r
+/**\r
+  Initialize or brutally reset the operational parameters for this EFI HTTP instance.\r
+\r
+  The Configure() function does the following:\r
+  When HttpConfigData is not NULL Initialize this EFI HTTP instance by configuring\r
+  timeout, local address, port, etc.\r
+  When HttpConfigData is NULL, reset this EFI HTTP instance by closing all active\r
+  connections with remote hosts, canceling all asynchronous tokens, and flush request\r
+  and response buffers without informing the appropriate hosts.\r
+\r
+  Except for GetModeData() and Configure(), No other EFI HTTP function can be executed\r
+  by this instance until the Configure() function is executed and returns successfully.\r
+\r
+  @param[in]  This                Pointer to EFI_HTTP_PROTOCOL instance.\r
+  @param[in]  HttpConfigData      Pointer to the configure data to configure the instance.\r
+\r
+  @retval EFI_SUCCESS             Operation succeeded.\r
+  @retval EFI_INVALID_PARAMETER   One or more of the following conditions is TRUE:\r
+                                  This is NULL.\r
+                                  HttpConfigData->LocalAddressIsIPv6 is FALSE and\r
+                                  HttpConfigData->IPv4Node is NULL.\r
+                                  HttpConfigData->LocalAddressIsIPv6 is TRUE and\r
+                                  HttpConfigData->IPv6Node is NULL.\r
+  @retval EFI_ALREADY_STARTED     Reinitialize this HTTP instance without calling\r
+                                  Configure() with NULL to reset it.\r
+  @retval EFI_DEVICE_ERROR        An unexpected system or network error occurred.\r
+  @retval EFI_OUT_OF_RESOURCES    Could not allocate enough system resources when\r
+                                  executing Configure().\r
+  @retval EFI_UNSUPPORTED         One or more options in ConfigData are not supported\r
+                                  in the implementation.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EfiHttpConfigure (\r
+  IN  EFI_HTTP_PROTOCOL         *This,\r
+  IN  EFI_HTTP_CONFIG_DATA      *HttpConfigData\r
+  );\r
+\r
+/**\r
+  The Request() function queues an HTTP request to this HTTP instance.\r
+\r
+  Similar to Transmit() function in the EFI TCP driver. When the HTTP request is sent\r
+  successfully, or if there is an error, Status in token will be updated and Event will\r
+  be signaled.\r
+\r
+  @param[in]  This                Pointer to EFI_HTTP_PROTOCOL instance.\r
+  @param[in]  Token               Pointer to storage containing HTTP request token.\r
+\r
+  @retval EFI_SUCCESS             Outgoing data was processed.\r
+  @retval EFI_NOT_STARTED         This EFI HTTP Protocol instance has not been started.\r
+  @retval EFI_DEVICE_ERROR        An unexpected system or network error occurred.\r
+  @retval EFI_TIMEOUT             Data was dropped out of the transmit or receive queue.\r
+  @retval EFI_OUT_OF_RESOURCES    Could not allocate enough system resources.\r
+  @retval EFI_UNSUPPORTED         The HTTP method is not supported in current\r
+                                  implementation.\r
+  @retval EFI_INVALID_PARAMETER   One or more of the following conditions is TRUE:\r
+                                  This is NULL.\r
+                                  Token->Message is NULL.\r
+                                  Token->Message->Body is not NULL,\r
+                                  Token->Message->BodyLength is non-zero, and\r
+                                  Token->Message->Data is NULL, but a previous call to\r
+                                  Request()has not been completed successfully.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EfiHttpRequest (\r
+  IN  EFI_HTTP_PROTOCOL         *This,\r
+  IN  EFI_HTTP_TOKEN            *Token\r
+  );\r
+\r
+/**\r
+  Abort an asynchronous HTTP request or response token.\r
+\r
+  The Cancel() function aborts a pending HTTP request or response transaction. If\r
+  Token is not NULL and the token is in transmit or receive queues when it is being\r
+  cancelled, its Token->Status will be set to EFI_ABORTED and then Token->Event will\r
+  be signaled. If the token is not in one of the queues, which usually means that the\r
+  asynchronous operation has completed, EFI_NOT_FOUND is returned. If Token is NULL,\r
+  all asynchronous tokens issued by Request() or Response() will be aborted.\r
+\r
+  @param[in]  This                Pointer to EFI_HTTP_PROTOCOL instance.\r
+  @param[in]  Token               Point to storage containing HTTP request or response\r
+                                  token.\r
+\r
+  @retval EFI_SUCCESS             Request and Response queues are successfully flushed.\r
+  @retval EFI_INVALID_PARAMETER   This is NULL.\r
+  @retval EFI_NOT_STARTED         This instance hasn't been configured.\r
+  @retval EFI_NO_MAPPING          When using the default address, configuration (DHCP,\r
+                                  BOOTP, RARP, etc.) hasn't finished yet.\r
+  @retval EFI_NOT_FOUND           The asynchronous request or response token is not\r
+                                  found.\r
+  @retval EFI_UNSUPPORTED         The implementation does not support this function.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EfiHttpCancel (\r
+  IN  EFI_HTTP_PROTOCOL         *This,\r
+  IN  EFI_HTTP_TOKEN            *Token\r
+  );\r
+\r
+/**\r
+  The Response() function queues an HTTP response to this HTTP instance, similar to\r
+  Receive() function in the EFI TCP driver. When the HTTP request is sent successfully,\r
+  or if there is an error, Status in token will be updated and Event will be signaled.\r
+\r
+  The HTTP driver will queue a receive token to the underlying TCP instance. When data\r
+  is received in the underlying TCP instance, the data will be parsed and Token will\r
+  be populated with the response data. If the data received from the remote host\r
+  contains an incomplete or invalid HTTP header, the HTTP driver will continue waiting\r
+  (asynchronously) for more data to be sent from the remote host before signaling\r
+  Event in Token.\r
+\r
+  It is the responsibility of the caller to allocate a buffer for Body and specify the\r
+  size in BodyLength. If the remote host provides a response that contains a content\r
+  body, up to BodyLength bytes will be copied from the receive buffer into Body and\r
+  BodyLength will be updated with the amount of bytes received and copied to Body. This\r
+  allows the client to download a large file in chunks instead of into one contiguous\r
+  block of memory. Similar to HTTP request, if Body is not NULL and BodyLength is\r
+  non-zero and all other fields are NULL or 0, the HTTP driver will queue a receive\r
+  token to underlying TCP instance. If data arrives in the receive buffer, up to\r
+  BodyLength bytes of data will be copied to Body. The HTTP driver will then update\r
+  BodyLength with the amount of bytes received and copied to Body.\r
+\r
+  If the HTTP driver does not have an open underlying TCP connection with the host\r
+  specified in the response URL, Request() will return EFI_ACCESS_DENIED. This is\r
+  consistent with RFC 2616 recommendation that HTTP clients should attempt to maintain\r
+  an open TCP connection between client and host.\r
+\r
+  @param[in]  This                Pointer to EFI_HTTP_PROTOCOL instance.\r
+  @param[in]  Token               Pointer to storage containing HTTP response token.\r
+\r
+  @retval EFI_SUCCESS             Allocation succeeded.\r
+  @retval EFI_NOT_STARTED         This EFI HTTP Protocol instance has not been\r
+                                  initialized.\r
+  @retval EFI_INVALID_PARAMETER   One or more of the following conditions is TRUE:\r
+                                  This is NULL.\r
+                                  Token is NULL.\r
+                                  Token->Message->Headers is NULL.\r
+                                  Token->Message is NULL.\r
+                                  Token->Message->Body is not NULL,\r
+                                  Token->Message->BodyLength is non-zero, and\r
+                                  Token->Message->Data is NULL, but a previous call to\r
+                                  Response() has not been completed successfully.\r
+  @retval EFI_OUT_OF_RESOURCES    Could not allocate enough system resources.\r
+  @retval EFI_ACCESS_DENIED       An open TCP connection is not present with the host\r
+                                  specified by response URL.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EfiHttpResponse (\r
+  IN  EFI_HTTP_PROTOCOL         *This,\r
+  IN  EFI_HTTP_TOKEN            *Token\r
+  );\r
+\r
+/**\r
+  The Poll() function can be used by network drivers and applications to increase the\r
+  rate that data packets are moved between the communication devices and the transmit\r
+  and receive queues.\r
+\r
+  In some systems, the periodic timer event in the managed network driver may not poll\r
+  the underlying communications device fast enough to transmit and/or receive all data\r
+  packets without missing incoming packets or dropping outgoing packets. Drivers and\r
+  applications that are experiencing packet loss should try calling the Poll() function\r
+  more often.\r
+\r
+  @param[in]  This                Pointer to EFI_HTTP_PROTOCOL instance.\r
+\r
+  @retval EFI_SUCCESS             Incoming or outgoing data was processed.\r
+  @retval EFI_DEVICE_ERROR        An unexpected system or network error occurred.\r
+  @retval EFI_INVALID_PARAMETER   This is NULL.\r
+  @retval EFI_NOT_READY           No incoming or outgoing data is processed.\r
+  @retval EFI_NOT_STARTED         This EFI HTTP Protocol instance has not been started.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EfiHttpPoll (\r
+  IN  EFI_HTTP_PROTOCOL         *This\r
+  );\r
+\r
+extern EFI_HTTP_PROTOCOL  mEfiHttpTemplate;\r
+\r
+#endif\r
diff --git a/NetworkPkg/HttpDxe/HttpProto.c b/NetworkPkg/HttpDxe/HttpProto.c
new file mode 100644 (file)
index 0000000..50ade4c
--- /dev/null
@@ -0,0 +1,1165 @@
+/** @file\r
+  Miscellaneous routines for HttpDxe driver.\r
+\r
+Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution.  The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "HttpDriver.h"\r
+\r
+/**\r
+  The common notify function used in HTTP driver. \r
+\r
+  @param[in]  Event   The event signaled.\r
+  @param[in]  Context The context.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+HttpCommonNotify (\r
+  IN EFI_EVENT  Event,\r
+  IN VOID       *Context\r
+  )\r
+{\r
+  if ((Event == NULL) || (Context == NULL)) {\r
+    return ;\r
+  }\r
+\r
+  *((BOOLEAN *) Context) = TRUE;\r
+}\r
+\r
+/**\r
+  The notify function associated with TxToken for Tcp4->Transmit().\r
+\r
+  @param[in]  Event   The event signaled.\r
+  @param[in]  Context The context.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+HttpTcpTransmitNotify (\r
+  IN EFI_EVENT  Event,\r
+  IN VOID       *Context\r
+  )\r
+{\r
+  HTTP_TOKEN_WRAP          *Wrap;\r
+\r
+  if ((Event == NULL) || (Context == NULL)) {\r
+    return ;\r
+  }\r
+\r
+  Wrap = (HTTP_TOKEN_WRAP *) Context;\r
+  Wrap->HttpToken->Status = Wrap->TcpWrap.TxToken.CompletionToken.Status;\r
+  gBS->SignalEvent (Wrap->HttpToken->Event);\r
+\r
+  //\r
+  // Free resources.\r
+  //\r
+  if (Wrap->TcpWrap.TxToken.Packet.TxData->FragmentTable[0].FragmentBuffer != NULL) {\r
+    FreePool (Wrap->TcpWrap.TxToken.Packet.TxData->FragmentTable[0].FragmentBuffer);\r
+  }\r
+\r
+  if (Wrap->TcpWrap.TxToken.CompletionToken.Event != NULL) {\r
+    gBS->CloseEvent (Wrap->TcpWrap.TxToken.CompletionToken.Event);\r
+  }\r
+\r
+  Wrap->TcpWrap.IsTxDone = TRUE;\r
+\r
+  //\r
+  // Check pending TxTokens and sent out.\r
+  //\r
+  NetMapIterate (&Wrap->HttpInstance->TxTokens, HttpTcpTransmit, NULL);\r
+\r
+}\r
+\r
+/**\r
+  The notify function associated with RxToken for Tcp4->Receive ().\r
+\r
+  @param[in]  Event   The event signaled.\r
+  @param[in]  Context The context.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+HttpTcpReceiveNotify (\r
+  IN EFI_EVENT  Event,\r
+  IN VOID       *Context\r
+  )\r
+{\r
+  HTTP_TOKEN_WRAP          *Wrap;\r
+  NET_MAP_ITEM             *Item;\r
+  UINTN                    Length;\r
+  EFI_STATUS               Status;\r
+  HTTP_PROTOCOL            *HttpInstance;\r
+\r
+  if ((Event == NULL) || (Context == NULL)) {\r
+    return ;\r
+  }\r
+\r
+  Wrap = (HTTP_TOKEN_WRAP *) Context;\r
+  if (EFI_ERROR (Wrap->TcpWrap.RxToken.CompletionToken.Status)) {\r
+    return ;\r
+  }\r
+\r
+  HttpInstance = Wrap->HttpInstance;\r
+\r
+  //\r
+  // Check whether we receive a complete HTTP message.\r
+  //\r
+  ASSERT (HttpInstance->MsgParser != NULL);\r
+\r
+  Length = (UINTN) Wrap->TcpWrap.RxData.FragmentTable[0].FragmentLength;\r
+  Status = HttpParseMessageBody (\r
+             HttpInstance->MsgParser,\r
+             Length,\r
+             Wrap->HttpToken->Message->Body\r
+             );\r
+  if (EFI_ERROR (Status)) {\r
+    return ;\r
+  }\r
+\r
+  if (HttpIsMessageComplete (HttpInstance->MsgParser)) {\r
+    //\r
+    // Free the MsgParse since we already have a full HTTP message.\r
+    //\r
+    HttpFreeMsgParser (HttpInstance->MsgParser);\r
+    HttpInstance->MsgParser = NULL;\r
+  }\r
+\r
+  Wrap->HttpToken->Message->BodyLength = Length;\r
+  ASSERT (HttpInstance->CacheBody == NULL);\r
+  //\r
+  // We receive part of header of next HTTP msg.\r
+  //\r
+  if (HttpInstance->NextMsg != NULL) {\r
+    Wrap->HttpToken->Message->BodyLength = HttpInstance->NextMsg - \r
+                                           (CHAR8 *) Wrap->HttpToken->Message->Body;\r
+    HttpInstance->CacheLen = Length - Wrap->HttpToken->Message->BodyLength;\r
+    if (HttpInstance->CacheLen != 0) {\r
+      HttpInstance->CacheBody = AllocateZeroPool (HttpInstance->CacheLen);\r
+      if (HttpInstance->CacheBody == NULL) {\r
+        return ;\r
+      }\r
+      CopyMem (HttpInstance->CacheBody, HttpInstance->NextMsg, HttpInstance->CacheLen);\r
+      HttpInstance->NextMsg = HttpInstance->CacheBody;\r
+      HttpInstance->CacheOffset = 0;\r
+    }\r
+  }\r
+\r
+  Item = NetMapFindKey (&Wrap->HttpInstance->RxTokens, Wrap->HttpToken);\r
+  if (Item != NULL) {\r
+    NetMapRemoveItem (&Wrap->HttpInstance->RxTokens, Item, NULL);\r
+  }\r
+\r
+\r
+  Wrap->TcpWrap.IsRxDone = TRUE;\r
+  Wrap->HttpToken->Status = Wrap->TcpWrap.RxToken.CompletionToken.Status;\r
+\r
+  gBS->SignalEvent (Wrap->HttpToken->Event);\r
+\r
+  //\r
+  // Check pending RxTokens and receive the HTTP message.\r
+  //\r
+  NetMapIterate (&Wrap->HttpInstance->RxTokens, HttpTcpReceive, NULL);\r
+  \r
+  FreePool (Wrap);\r
+}\r
+\r
+/**\r
+  Create events for the TCP4 connection token and TCP4 close token.\r
+\r
+  @param[in]  HttpInstance       Pointer to HTTP_PROTOCOL structure.\r
+\r
+  @retval EFI_SUCCESS            The events are created successfully.\r
+  @retval others                 Other error as indicated.\r
+\r
+**/\r
+EFI_STATUS\r
+HttpCreateTcp4ConnCloseEvent (\r
+  IN  HTTP_PROTOCOL        *HttpInstance\r
+  )\r
+{\r
+  EFI_STATUS               Status;\r
+    //\r
+    // Create events for variuos asynchronous operations.\r
+    //\r
+    Status = gBS->CreateEvent (\r
+                    EVT_NOTIFY_SIGNAL,\r
+                    TPL_NOTIFY,\r
+                    HttpCommonNotify,\r
+                    &HttpInstance->IsConnDone,\r
+                    &HttpInstance->ConnToken.CompletionToken.Event\r
+                    );\r
+    if (EFI_ERROR (Status)) {\r
+      goto ERROR;\r
+    }\r
+\r
+    //\r
+    // Initialize CloseToken\r
+    //\r
+    Status = gBS->CreateEvent (\r
+                    EVT_NOTIFY_SIGNAL,\r
+                    TPL_NOTIFY,\r
+                    HttpCommonNotify,\r
+                    &HttpInstance->IsCloseDone,\r
+                    &HttpInstance->CloseToken.CompletionToken.Event\r
+                    );\r
+    if (EFI_ERROR (Status)) {\r
+      goto ERROR;\r
+    }\r
+\r
\r
+  return EFI_SUCCESS;\r
+\r
+ERROR:\r
+  //\r
+  // Error handling\r
+  //\r
+  HttpCloseTcp4ConnCloseEvent (HttpInstance);\r
+\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Close events in the TCP4 connection token and TCP4 close token.\r
+\r
+  @param[in]  HttpInstance   Pointer to HTTP_PROTOCOL structure.\r
+\r
+**/\r
+VOID\r
+HttpCloseTcp4ConnCloseEvent (\r
+  IN  HTTP_PROTOCOL        *HttpInstance\r
+  )\r
+{\r
+  ASSERT (HttpInstance != NULL);\r
+\r
+  if (NULL != HttpInstance->ConnToken.CompletionToken.Event) {\r
+    gBS->CloseEvent (HttpInstance->ConnToken.CompletionToken.Event);\r
+  }\r
+\r
+  if (NULL != HttpInstance->CloseToken.CompletionToken.Event) {\r
+    gBS->CloseEvent(HttpInstance->CloseToken.CompletionToken.Event);\r
+  }  \r
+}\r
+\r
+/**\r
+  Create event for the TCP4 transmit token.\r
+\r
+  @param[in]  Wrap               Point to HTTP token's wrap data.\r
+\r
+  @retval EFI_SUCCESS            The events is created successfully.\r
+  @retval others                 Other error as indicated.\r
+\r
+**/\r
+EFI_STATUS\r
+HttpCreateTcp4TxEvent (\r
+  IN  HTTP_TOKEN_WRAP      *Wrap\r
+  )\r
+{\r
+  EFI_STATUS               Status;\r
+  HTTP_PROTOCOL            *HttpInstance;\r
+  HTTP_TCP_TOKEN_WRAP      *TcpWrap;\r
+\r
+  HttpInstance = Wrap->HttpInstance;\r
+  TcpWrap      = &Wrap->TcpWrap;\r
+\r
+  Status = gBS->CreateEvent (\r
+                  EVT_NOTIFY_SIGNAL,\r
+                  TPL_NOTIFY,\r
+                  HttpTcpTransmitNotify,\r
+                  Wrap,\r
+                  &TcpWrap->TxToken.CompletionToken.Event\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  TcpWrap->TxData.Push = TRUE;\r
+  TcpWrap->TxData.Urgent = FALSE;\r
+  TcpWrap->TxData.FragmentCount = 1;\r
+  TcpWrap->TxToken.Packet.TxData = &Wrap->TcpWrap.TxData;\r
+  TcpWrap->TxToken.CompletionToken.Status = EFI_NOT_READY;\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Create event for the TCP4 receive token which is used to receive HTTP header.\r
+\r
+  @param[in]  HttpInstance       Pointer to HTTP_PROTOCOL structure.\r
+\r
+  @retval EFI_SUCCESS            The events is created successfully.\r
+  @retval others                 Other error as indicated.\r
+\r
+**/\r
+EFI_STATUS\r
+HttpCreateTcp4RxEventForHeader (\r
+  IN  HTTP_PROTOCOL        *HttpInstance\r
+  )\r
+{\r
+  EFI_STATUS               Status;\r
+\r
+\r
+  Status = gBS->CreateEvent (\r
+                  EVT_NOTIFY_SIGNAL,\r
+                  TPL_NOTIFY,\r
+                  HttpCommonNotify,\r
+                  &HttpInstance->IsRxDone,\r
+                  &HttpInstance->RxToken.CompletionToken.Event\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  HttpInstance->RxData.FragmentCount = 1;\r
+  HttpInstance->RxToken.Packet.RxData = &HttpInstance->RxData;\r
+  HttpInstance->RxToken.CompletionToken.Status = EFI_NOT_READY;\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Create event for the TCP4 receive token which is used to receive HTTP body.\r
+\r
+  @param[in]  Wrap               Point to HTTP token's wrap data.\r
+\r
+  @retval EFI_SUCCESS            The events is created successfully.\r
+  @retval others                 Other error as indicated.\r
+\r
+**/\r
+EFI_STATUS\r
+HttpCreateTcp4RxEvent (\r
+  IN  HTTP_TOKEN_WRAP      *Wrap \r
+  )\r
+{\r
+  EFI_STATUS               Status;\r
+  HTTP_PROTOCOL            *HttpInstance;\r
+  HTTP_TCP_TOKEN_WRAP      *TcpWrap;\r
+\r
+  HttpInstance = Wrap->HttpInstance;\r
+  TcpWrap      = &Wrap->TcpWrap;\r
+\r
+  Status = gBS->CreateEvent (\r
+                  EVT_NOTIFY_SIGNAL,\r
+                  TPL_NOTIFY,\r
+                  HttpTcpReceiveNotify,\r
+                  Wrap,\r
+                  &TcpWrap->RxToken.CompletionToken.Event\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  TcpWrap->RxData.FragmentCount = 1;\r
+  TcpWrap->RxToken.Packet.RxData = &Wrap->TcpWrap.RxData;\r
+  TcpWrap->RxToken.CompletionToken.Status = EFI_NOT_READY;\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Intiialize the HTTP_PROTOCOL structure to the unconfigured state.\r
+\r
+  @param[in]       HttpSb               The HTTP service private instance.\r
+  @param[in, out]  HttpInstance         Pointer to HTTP_PROTOCOL structure.\r
+\r
+  @retval EFI_SUCCESS       HTTP_PROTOCOL structure is initialized successfully.                                          \r
+  @retval Others            Other error as indicated.\r
+\r
+**/\r
+EFI_STATUS\r
+HttpInitProtocol (\r
+  IN     HTTP_SERVICE            *HttpSb,\r
+  IN OUT HTTP_PROTOCOL           *HttpInstance\r
+  )\r
+{\r
+  EFI_STATUS                     Status;\r
+  VOID                           *Interface;\r
+\r
+  ASSERT ((HttpSb != NULL) && (HttpInstance != NULL));\r
+\r
+  HttpInstance->Signature = HTTP_PROTOCOL_SIGNATURE;\r
+  CopyMem (&HttpInstance->Http, &mEfiHttpTemplate, sizeof (HttpInstance->Http));\r
+  HttpInstance->Service = HttpSb;\r
+\r
+  //\r
+  // Create TCP child.\r
+  //\r
+  Status = NetLibCreateServiceChild (\r
+             HttpInstance->Service->ControllerHandle,\r
+             HttpInstance->Service->ImageHandle,\r
+             &gEfiTcp4ServiceBindingProtocolGuid,\r
+             &HttpInstance->TcpChildHandle\r
+             );\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    goto ON_ERROR;\r
+  }\r
+\r
+  Status = gBS->OpenProtocol (\r
+                  HttpInstance->TcpChildHandle,\r
+                  &gEfiTcp4ProtocolGuid,\r
+                  (VOID **) &Interface,\r
+                  HttpInstance->Service->ImageHandle,\r
+                  HttpInstance->Service->ControllerHandle,\r
+                  EFI_OPEN_PROTOCOL_BY_DRIVER\r
+                  );\r
+                  \r
+  if (EFI_ERROR (Status)) {\r
+    goto ON_ERROR;\r
+  }\r
+\r
+  Status = gBS->OpenProtocol (\r
+                  HttpInstance->TcpChildHandle,\r
+                  &gEfiTcp4ProtocolGuid,\r
+                  (VOID **) &HttpInstance->Tcp4,\r
+                  HttpInstance->Service->ImageHandle,\r
+                  HttpInstance->Handle,\r
+                  EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER\r
+                  );\r
+  if (EFI_ERROR(Status)) {\r
+    goto ON_ERROR;\r
+  }\r
+\r
+  NetMapInit (&HttpInstance->TxTokens);\r
+  NetMapInit (&HttpInstance->RxTokens);\r
+\r
+  return EFI_SUCCESS;\r
+\r
+ON_ERROR:\r
+  \r
+  if (HttpInstance->TcpChildHandle != NULL) {\r
+    gBS->CloseProtocol (\r
+           HttpInstance->TcpChildHandle,\r
+           &gEfiTcp4ProtocolGuid,\r
+           HttpInstance->Service->ImageHandle,\r
+           HttpInstance->Service->ControllerHandle\r
+           );\r
+\r
+    gBS->CloseProtocol (\r
+           HttpInstance->TcpChildHandle,\r
+           &gEfiTcp4ProtocolGuid,\r
+           HttpInstance->Service->ImageHandle,\r
+           HttpInstance->Handle\r
+           );\r
+    \r
+    NetLibDestroyServiceChild (\r
+      HttpInstance->Service->ControllerHandle,\r
+      HttpInstance->Service->ImageHandle,\r
+      &gEfiTcp4ServiceBindingProtocolGuid,\r
+      HttpInstance->TcpChildHandle\r
+      );\r
+  }\r
+\r
+  return Status;\r
+  \r
+}\r
+\r
+/**\r
+  Clean up the HTTP child, release all the resources used by it.\r
+\r
+  @param[in]  HttpInstance       The HTTP child to clean up.\r
+\r
+**/\r
+VOID\r
+HttpCleanProtocol (\r
+  IN  HTTP_PROTOCOL          *HttpInstance\r
+  )\r
+{\r
+  HttpCloseConnection (HttpInstance);\r
+  \r
+  HttpCloseTcp4ConnCloseEvent (HttpInstance);\r
+\r
+  if (HttpInstance->CacheBody != NULL) {\r
+    FreePool (HttpInstance->CacheBody);\r
+    HttpInstance->CacheBody = NULL;\r
+    HttpInstance->NextMsg   = NULL;\r
+  }\r
+\r
+  if (HttpInstance->RemoteHost != NULL) {\r
+    FreePool (HttpInstance->RemoteHost);\r
+    HttpInstance->RemoteHost = NULL;\r
+  }\r
+\r
+  if (HttpInstance->MsgParser != NULL) {\r
+    HttpFreeMsgParser (HttpInstance->MsgParser);\r
+    HttpInstance->MsgParser = NULL;\r
+  }\r
+\r
+  NetMapClean (&HttpInstance->TxTokens);\r
+  NetMapClean (&HttpInstance->RxTokens);\r
+\r
+  if (HttpInstance->TcpChildHandle != NULL) {\r
+    gBS->CloseProtocol (\r
+           HttpInstance->TcpChildHandle,\r
+           &gEfiTcp4ProtocolGuid,\r
+           HttpInstance->Service->ImageHandle,\r
+           HttpInstance->Service->ControllerHandle\r
+           );\r
+\r
+    gBS->CloseProtocol (\r
+           HttpInstance->TcpChildHandle,\r
+           &gEfiTcp4ProtocolGuid,\r
+           HttpInstance->Service->ImageHandle,\r
+           HttpInstance->Handle\r
+           );\r
+    \r
+    NetLibDestroyServiceChild (\r
+      HttpInstance->Service->ControllerHandle,\r
+      HttpInstance->Service->ImageHandle,\r
+      &gEfiTcp4ServiceBindingProtocolGuid,\r
+      HttpInstance->TcpChildHandle\r
+      );\r
+  }\r
+}\r
+\r
+/**\r
+  Establish TCP connection with HTTP server.\r
+\r
+  @param[in]  HttpInstance       The HTTP instance private data.\r
+\r
+  @retval EFI_SUCCESS            The TCP connection is established.\r
+  @retval Others                 Other error as indicated.\r
+\r
+**/\r
+EFI_STATUS\r
+HttpCreateConnection (\r
+  IN  HTTP_PROTOCOL        *HttpInstance\r
+  )\r
+{\r
+  EFI_STATUS                    Status;\r
+\r
+  //\r
+  // Create events for variuos asynchronous operations.\r
+  //\r
+  HttpInstance->IsConnDone = FALSE;\r
+\r
+  //\r
+  // Connect to Http server\r
+  //\r
+  HttpInstance->ConnToken.CompletionToken.Status = EFI_NOT_READY;\r
+  Status = HttpInstance->Tcp4->Connect (HttpInstance->Tcp4, &HttpInstance->ConnToken);\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG ((EFI_D_ERROR, "HttpCreateConnection: Tcp4->Connect() = %r\n", Status));\r
+    return Status;\r
+  }\r
+\r
+  while (!HttpInstance->IsConnDone) {\r
+    HttpInstance->Tcp4->Poll (HttpInstance->Tcp4);\r
+  }\r
+\r
+  Status = HttpInstance->ConnToken.CompletionToken.Status;\r
+\r
+  if (!EFI_ERROR (Status)) {\r
+    HttpInstance->State = HTTP_STATE_TCP_CONNECTED;\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Close existing TCP connection.\r
+\r
+  @param[in]  HttpInstance       The HTTP instance private data.\r
+\r
+  @retval EFI_SUCCESS            The TCP connection is closed.\r
+  @retval Others                 Other error as indicated.\r
+\r
+**/\r
+EFI_STATUS\r
+HttpCloseConnection (\r
+  IN  HTTP_PROTOCOL        *HttpInstance\r
+  )\r
+{\r
+  EFI_STATUS                Status;\r
+\r
+  HttpInstance->CloseToken.AbortOnClose = TRUE;\r
+  HttpInstance->IsCloseDone             = FALSE;\r
+  \r
+\r
+  Status = HttpInstance->Tcp4->Close (HttpInstance->Tcp4, &HttpInstance->CloseToken);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  while (!HttpInstance->IsCloseDone) {\r
+    HttpInstance->Tcp4->Poll (HttpInstance->Tcp4);\r
+  }\r
+\r
+  HttpInstance->State = HTTP_STATE_TCP_CLOSED;\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Configure TCP4 protocol child.\r
+\r
+  @param[in]  HttpInstance       The HTTP instance private data.\r
+  @param[in]  Wrap               The HTTP token's wrap data.\r
+\r
+  @retval EFI_SUCCESS            The TCP4 protocol child is configured.\r
+  @retval Others                 Other error as indicated.\r
+\r
+**/\r
+EFI_STATUS\r
+HttpConfigureTcp4 (\r
+  IN  HTTP_PROTOCOL        *HttpInstance,\r
+  IN  HTTP_TOKEN_WRAP      *Wrap\r
+  )\r
+{\r
+  EFI_STATUS                 Status;\r
+  EFI_TCP4_CONFIG_DATA       *Tcp4CfgData;\r
+  EFI_TCP4_ACCESS_POINT      *Tcp4AP;\r
+  EFI_TCP4_OPTION            *Tcp4Option;\r
+  HTTP_TCP_TOKEN_WRAP        *TcpWrap;\r
+\r
+  ASSERT (HttpInstance != NULL);\r
+  TcpWrap = &Wrap->TcpWrap;\r
+\r
+\r
+  Tcp4CfgData = &HttpInstance->Tcp4CfgData;\r
+  ZeroMem (Tcp4CfgData, sizeof (EFI_TCP4_CONFIG_DATA));\r
+  \r
+  Tcp4CfgData->TypeOfService = HTTP_TOS_DEAULT;\r
+  Tcp4CfgData->TimeToLive    = HTTP_TTL_DEAULT;\r
+  Tcp4CfgData->ControlOption = &HttpInstance->Tcp4Option;\r
+\r
+  Tcp4AP = &Tcp4CfgData->AccessPoint;\r
+  Tcp4AP->UseDefaultAddress = HttpInstance->IPv4Node.UseDefaultAddress;\r
+  if (!Tcp4AP->UseDefaultAddress) {\r
+    IP4_COPY_ADDRESS (&Tcp4AP->StationAddress, &HttpInstance->IPv4Node.LocalAddress);\r
+    IP4_COPY_ADDRESS (&Tcp4AP->SubnetMask, &HttpInstance->IPv4Node.LocalSubnet);\r
+  }\r
+  \r
+  Tcp4AP->StationPort = HttpInstance->IPv4Node.LocalPort;\r
+  Tcp4AP->RemotePort  = HttpInstance->RemotePort;\r
+  Tcp4AP->ActiveFlag  = TRUE;\r
+  IP4_COPY_ADDRESS (&Tcp4AP->RemoteAddress, &HttpInstance->RemoteAddr);\r
+\r
+  Tcp4Option = Tcp4CfgData->ControlOption;\r
+  Tcp4Option->ReceiveBufferSize      = HTTP_BUFFER_SIZE_DEAULT;\r
+  Tcp4Option->SendBufferSize         = HTTP_BUFFER_SIZE_DEAULT;\r
+  Tcp4Option->MaxSynBackLog          = HTTP_MAX_SYN_BACK_LOG;\r
+  Tcp4Option->ConnectionTimeout      = HTTP_CONNECTION_TIMEOUT;\r
+  Tcp4Option->DataRetries            = HTTP_DATA_RETRIES;\r
+  Tcp4Option->FinTimeout             = HTTP_FIN_TIMEOUT;\r
+  Tcp4Option->KeepAliveProbes        = HTTP_KEEP_ALIVE_PROBES;\r
+  Tcp4Option->KeepAliveTime          = HTTP_KEEP_ALIVE_TIME;\r
+  Tcp4Option->KeepAliveInterval      = HTTP_KEEP_ALIVE_INTERVAL;\r
+  Tcp4Option->EnableNagle            = TRUE;\r
+  Tcp4CfgData->ControlOption         = Tcp4Option;\r
+\r
+  Status = HttpInstance->Tcp4->Configure (HttpInstance->Tcp4, Tcp4CfgData);\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG ((EFI_D_ERROR, "HttpConfigureTcp4 - %r\n", Status));\r
+    return Status;\r
+  }\r
+\r
+  Status = HttpCreateTcp4ConnCloseEvent (HttpInstance);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  Status = HttpCreateTcp4TxEvent (Wrap);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  HttpInstance->State = HTTP_STATE_TCP_CONFIGED;\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Check existing TCP connection, if in error state, receover TCP4 connection.\r
+\r
+  @param[in]  HttpInstance       The HTTP instance private data.\r
+\r
+  @retval EFI_SUCCESS            The TCP connection is established.\r
+  @retval EFI_NOT_READY          TCP4 protocol child is not created or configured.\r
+  @retval Others                 Other error as indicated.\r
+\r
+**/\r
+EFI_STATUS\r
+HttpConnectTcp4 (\r
+  IN  HTTP_PROTOCOL        *HttpInstance\r
+  )\r
+{\r
+  EFI_STATUS                Status;\r
+  EFI_TCP4_CONNECTION_STATE Tcp4State;\r
+\r
+\r
+  if (HttpInstance->State != HTTP_STATE_TCP_CONFIGED || HttpInstance->Tcp4 == NULL) {\r
+    return EFI_NOT_READY;\r
+  }\r
+\r
+  Status = HttpInstance->Tcp4->GetModeData(\r
+                                 HttpInstance->Tcp4, \r
+                                 &Tcp4State, \r
+                                 NULL,\r
+                                 NULL,\r
+                                 NULL,\r
+                                 NULL\r
+                                 );\r
+  if (EFI_ERROR(Status)){\r
+    DEBUG ((EFI_D_ERROR, "Tcp4 GetModeData fail - %x\n", Status));\r
+    return Status;\r
+  }\r
+\r
+  if (Tcp4State > Tcp4StateEstablished) {\r
+    HttpCloseConnection(HttpInstance);\r
+  }  \r
+\r
+  return HttpCreateConnection (HttpInstance);\r
+}\r
+\r
+/**\r
+  Send the HTTP message through TCP4.\r
+\r
+  @param[in]  HttpInstance       The HTTP instance private data.\r
+  @param[in]  Wrap               The HTTP token's wrap data.\r
+  @param[in]  TxString           Buffer containing the HTTP message string.\r
+  @param[in]  TxStringLen        Length of the HTTP message string in bytes.\r
+\r
+  @retval EFI_SUCCESS            The HTTP message is queued into TCP transmit queue.\r
+  @retval Others                 Other error as indicated.\r
+\r
+**/\r
+EFI_STATUS\r
+HttpTransmitTcp4 (\r
+  IN  HTTP_PROTOCOL    *HttpInstance,\r
+  IN  HTTP_TOKEN_WRAP  *Wrap,\r
+  IN  UINT8            *TxString,\r
+  IN  UINTN            TxStringLen\r
+  )\r
+{\r
+  EFI_STATUS                    Status;\r
+  EFI_TCP4_IO_TOKEN             *TxToken;\r
+  EFI_TCP4_PROTOCOL             *Tcp4;\r
+  \r
+  Tcp4 = HttpInstance->Tcp4;\r
+  TxToken = &Wrap->TcpWrap.TxToken;\r
+\r
+  TxToken->Packet.TxData->DataLength = (UINT32) TxStringLen;\r
+  TxToken->Packet.TxData->FragmentTable[0].FragmentLength = (UINT32) TxStringLen;\r
+  TxToken->Packet.TxData->FragmentTable[0].FragmentBuffer = (VOID *) TxString;\r
+  TxToken->CompletionToken.Status = EFI_NOT_READY;  \r
+\r
+  Wrap->TcpWrap.IsTxDone = FALSE;\r
+  Status  = Tcp4->Transmit (Tcp4, TxToken);\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG ((EFI_D_ERROR, "Transmit failed: %r\n", Status));\r
+    return Status;\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Translate the status code in HTTP message to EFI_HTTP_STATUS_CODE defined \r
+  in UEFI 2.5 specification.\r
+\r
+  @param[in]  StatusCode         The status code value in HTTP message.\r
+\r
+  @return                        Value defined in EFI_HTTP_STATUS_CODE .\r
+\r
+**/\r
+EFI_HTTP_STATUS_CODE\r
+HttpMappingToStatusCode (\r
+  IN UINTN                  StatusCode\r
+  )  \r
+{\r
+  switch (StatusCode) {\r
+  case 100:\r
+    return HTTP_STATUS_100_CONTINUE;\r
+  case 101:\r
+    return HTTP_STATUS_101_SWITCHING_PROTOCOLS;\r
+  case 200:\r
+    return HTTP_STATUS_200_OK;\r
+  case 201:\r
+    return HTTP_STATUS_201_CREATED;\r
+  case 202:\r
+    return HTTP_STATUS_202_ACCEPTED;\r
+  case 203:\r
+    return HTTP_STATUS_203_NON_AUTHORITATIVE_INFORMATION;\r
+  case 204:\r
+    return HTTP_STATUS_204_NO_CONTENT;\r
+  case 205:\r
+    return HTTP_STATUS_205_RESET_CONTENT;\r
+  case 206:\r
+    return HTTP_STATUS_206_PARTIAL_CONTENT;\r
+  case 300:\r
+    return HTTP_STATUS_300_MULTIPLE_CHIOCES;\r
+  case 301:\r
+    return HTTP_STATUS_301_MOVED_PERMANENTLY;\r
+  case 302:\r
+    return HTTP_STATUS_302_FOUND;\r
+  case 303:\r
+    return HTTP_STATUS_303_SEE_OTHER;\r
+  case 304:\r
+    return HTTP_STATUS_304_NOT_MODIFIED;\r
+  case 305:\r
+    return HTTP_STATUS_305_USE_PROXY;\r
+  case 307:\r
+    return HTTP_STATUS_307_TEMPORARY_REDIRECT;\r
+  case 400:\r
+    return HTTP_STATUS_400_BAD_REQUEST;\r
+  case 401:\r
+    return HTTP_STATUS_401_UNAUTHORIZED;\r
+  case 402:\r
+    return HTTP_STATUS_402_PAYMENT_REQUIRED;\r
+  case 403:\r
+    return HTTP_STATUS_403_FORBIDDEN;\r
+  case 404:\r
+    return HTTP_STATUS_404_NOT_FOUND;\r
+  case 405:\r
+    return HTTP_STATUS_405_METHOD_NOT_ALLOWED;\r
+  case 406:\r
+    return HTTP_STATUS_406_NOT_ACCEPTABLE;\r
+  case 407:\r
+    return HTTP_STATUS_407_PROXY_AUTHENTICATION_REQUIRED;\r
+  case 408:\r
+    return HTTP_STATUS_408_REQUEST_TIME_OUT;\r
+  case 409:\r
+    return HTTP_STATUS_409_CONFLICT;\r
+  case 410:\r
+    return HTTP_STATUS_410_GONE;\r
+  case 411:\r
+    return HTTP_STATUS_411_LENGTH_REQUIRED;\r
+  case 412:\r
+    return HTTP_STATUS_412_PRECONDITION_FAILED;\r
+  case 413:\r
+    return HTTP_STATUS_413_REQUEST_ENTITY_TOO_LARGE;\r
+  case 414:\r
+    return HTTP_STATUS_414_REQUEST_URI_TOO_LARGE;\r
+  case 415:\r
+    return HTTP_STATUS_415_UNSUPPORETD_MEDIA_TYPE;\r
+  case 416:\r
+    return HTTP_STATUS_416_REQUESTED_RANGE_NOT_SATISFIED;\r
+  case 417:\r
+    return HTTP_STATUS_417_EXPECTATION_FAILED;\r
+  case 500:\r
+    return HTTP_STATUS_500_INTERNAL_SERVER_ERROR;\r
+  case 501:\r
+    return HTTP_STATUS_501_NOT_IMIPLEMENTED;\r
+  case 502:\r
+    return HTTP_STATUS_502_BAD_GATEWAY;\r
+  case 503:\r
+    return HTTP_STATUS_503_SERVICE_UNAVAILABLE;\r
+  case 504:\r
+    return HTTP_STATUS_504_GATEWAY_TIME_OUT;\r
+  case 505:\r
+    return HTTP_STATUS_505_HTTP_VERSION_NOT_SUPPORTED;\r
+\r
+  default:\r
+    return HTTP_STATUS_UNSUPPORTED_STATUS;\r
+  }\r
+}\r
+\r
+/**\r
+  Check whether the user's token or event has already\r
+  been enqueue on HTTP TxToken or RxToken list.\r
+\r
+  @param[in]  Map                The container of either user's transmit or receive\r
+                                 token.\r
+  @param[in]  Item               Current item to check against.\r
+  @param[in]  Context            The Token to check againist.\r
+\r
+  @retval EFI_ACCESS_DENIED      The token or event has already been enqueued in IP\r
+  @retval EFI_SUCCESS            The current item isn't the same token/event as the\r
+                                 context.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+HttpTokenExist (\r
+  IN NET_MAP                *Map,\r
+  IN NET_MAP_ITEM           *Item,\r
+  IN VOID                   *Context\r
+  )\r
+{\r
+  EFI_HTTP_TOKEN            *Token;\r
+  EFI_HTTP_TOKEN            *TokenInItem;\r
+\r
+  Token       = (EFI_HTTP_TOKEN *) Context;\r
+  TokenInItem = (EFI_HTTP_TOKEN *) Item->Key;\r
+\r
+  if (Token == TokenInItem || Token->Event == TokenInItem->Event) {\r
+    return EFI_ACCESS_DENIED;\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Check whether the HTTP message associated with TxToken is already sent out.\r
+\r
+  @param[in]  Map                The container of TxToken.\r
+  @param[in]  Item               Current item to check against.\r
+  @param[in]  Context            The Token to check againist.\r
+\r
+  @retval EFI_NOT_READY          The HTTP message is still queued in the list.\r
+  @retval EFI_SUCCESS            The HTTP message has been sent out.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+HttpTcpNotReady (\r
+  IN NET_MAP                *Map,\r
+  IN NET_MAP_ITEM           *Item,\r
+  IN VOID                   *Context\r
+  )\r
+{\r
+  HTTP_TOKEN_WRAP           *ValueInItem;\r
+\r
+  ValueInItem = (HTTP_TOKEN_WRAP *) Item->Value;\r
+\r
+  if (!ValueInItem->TcpWrap.IsTxDone) {\r
+    return EFI_NOT_READY;\r
+  }\r
+  \r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Transmit the HTTP mssage by processing the associated HTTP token.\r
+\r
+  @param[in]  Map                The container of TxToken.\r
+  @param[in]  Item               Current item to check against.\r
+  @param[in]  Context            The Token to check againist.\r
+\r
+  @retval EFI_OUT_OF_RESOURCES   Failed to allocate resources.\r
+  @retval EFI_SUCCESS            The HTTP message is queued into TCP transmit\r
+                                 queue.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+HttpTcpTransmit (\r
+  IN NET_MAP                *Map,\r
+  IN NET_MAP_ITEM           *Item,\r
+  IN VOID                   *Context\r
+  )\r
+{\r
+  HTTP_TOKEN_WRAP           *ValueInItem;\r
+  EFI_STATUS                Status;\r
+  CHAR8                     *RequestStr;\r
+  CHAR8                     *Url;\r
+\r
+  ValueInItem = (HTTP_TOKEN_WRAP *) Item->Value;\r
+  if (ValueInItem->TcpWrap.IsTxDone) {\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  //\r
+  // Parse the URI of the remote host.\r
+  //\r
+  Url = AllocatePool (StrLen (ValueInItem->HttpToken->Message->Data.Request->Url) + 1);\r
+  if (Url == NULL) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  UnicodeStrToAsciiStr (ValueInItem->HttpToken->Message->Data.Request->Url, Url);\r
+\r
+  //\r
+  // Create request message.\r
+  //\r
+  RequestStr = HttpGenRequestString (\r
+                 ValueInItem->HttpInstance,\r
+                 ValueInItem->HttpToken->Message,\r
+                 Url\r
+                 );\r
+  FreePool (Url);\r
+  if (RequestStr == NULL) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  //\r
+  // Transmit the request message.\r
+  //\r
+  Status = HttpTransmitTcp4 (\r
+             ValueInItem->HttpInstance,\r
+             ValueInItem,\r
+             (UINT8*) RequestStr,\r
+             AsciiStrLen (RequestStr)\r
+             );\r
+  FreePool (RequestStr);\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Receive the HTTP response by processing the associated HTTP token.\r
+\r
+  @param[in]  Map                The container of RxToken.\r
+  @param[in]  Item               Current item to check against.\r
+  @param[in]  Context            The Token to check againist.\r
+\r
+  @retval EFI_SUCCESS            The HTTP response is queued into TCP receive\r
+                                 queue.\r
+  @retval Others                 Other error as indicated.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+HttpTcpReceive (\r
+  IN NET_MAP                *Map,\r
+  IN NET_MAP_ITEM           *Item,\r
+  IN VOID                   *Context\r
+  )\r
+{\r
+  //\r
+  // Process the queued HTTP response.\r
+  //\r
+  return HttpResponseWorker ((HTTP_TOKEN_WRAP *) Item->Value);\r
+}\r
+\r
+/**\r
+  Generate HTTP request string.\r
+\r
+  @param[in]  HttpInstance       Pointer to HTTP_PROTOCOL structure.\r
+  @param[in]  Message            Pointer to storage containing HTTP message data.\r
+  @param[in]  Url                The URL of a remote host.\r
+\r
+  @return     Pointer to the created HTTP request string.\r
+  @return     NULL if any error occured.\r
+\r
+**/\r
+CHAR8 *\r
+HttpGenRequestString (\r
+  IN  HTTP_PROTOCOL        *HttpInstance,\r
+  IN  EFI_HTTP_MESSAGE     *Message,\r
+  IN  CHAR8                *Url\r
+  )\r
+{\r
+  EFI_STATUS                  Status;\r
+  UINTN                       StrLength;\r
+  UINT8                       *Request;\r
+  UINT8                       *RequestPtr;\r
+  UINTN                       HttpHdrSize;\r
+  UINTN                       MsgSize;\r
+  BOOLEAN                     Success;\r
+  VOID                        *HttpHdr;\r
+  EFI_HTTP_HEADER             **AppendList; \r
+  UINTN                       Index;\r
+  \r
+  ASSERT (HttpInstance != NULL);\r
+  ASSERT (Message != NULL);\r
+\r
+  DEBUG ((EFI_D_ERROR, "HttpMethod - %x\n", Message->Data.Request->Method));\r
+\r
+  Request = NULL;\r
+  Success = FALSE;\r
+  HttpHdr = NULL;\r
+  AppendList = NULL;\r
+\r
+  //\r
+  // Build AppendList\r
+  //\r
+  AppendList = AllocateZeroPool (sizeof (EFI_HTTP_HEADER *) * (Message->HeaderCount));\r
+  if (AppendList == NULL) {\r
+    return NULL;\r
+  }\r
+\r
+  for(Index = 0; Index < Message->HeaderCount; Index++){\r
+    AppendList[Index] = &Message->Headers[Index];\r
+  }\r
+\r
+  //\r
+  // Build raw unformatted HTTP headers.\r
+  //  \r
+  Status = HttpUtilitiesBuild (\r
+             0,\r
+             NULL,\r
+             0,\r
+             NULL,\r
+             Message->HeaderCount,\r
+             AppendList,\r
+             &HttpHdrSize,\r
+             &HttpHdr\r
+             );\r
+  FreePool (AppendList);\r
+  if (EFI_ERROR (Status) || HttpHdr == NULL) {\r
+    return NULL;\r
+  }\r
+\r
+  //\r
+  // Calculate HTTP message length.\r
+  //\r
+  MsgSize = Message->BodyLength + HTTP_MAXIMUM_METHOD_LEN + AsciiStrLen (Url) + \r
+            AsciiStrLen (HTTP_VERSION_CRLF_STR) + HttpHdrSize;\r
+  Request = AllocateZeroPool (MsgSize);\r
+  if (Request == NULL) {\r
+    goto Exit;\r
+  }  \r
+\r
+  RequestPtr = Request;\r
+  //\r
+  // Construct header request\r
+  //\r
+  switch (Message->Data.Request->Method) {\r
+  case HttpMethodGet:\r
+    StrLength = sizeof (HTTP_GET_STR) - 1;\r
+    CopyMem (RequestPtr, HTTP_GET_STR, StrLength);\r
+    RequestPtr += StrLength;\r
+    break;\r
+  case HttpMethodHead:\r
+    StrLength = sizeof (HTTP_HEAD_STR) - 1;\r
+    CopyMem (RequestPtr, HTTP_HEAD_STR, StrLength);\r
+    RequestPtr += StrLength;\r
+    break;\r
+  default:\r
+    ASSERT (FALSE);\r
+    goto Exit;\r
+  }\r
+\r
+  StrLength = AsciiStrLen (Url);\r
+  CopyMem (RequestPtr, Url, StrLength);\r
+  RequestPtr += StrLength;\r
+\r
+  StrLength = sizeof (HTTP_VERSION_CRLF_STR) - 1;\r
+  CopyMem (RequestPtr, HTTP_VERSION_CRLF_STR, StrLength);\r
+  RequestPtr += StrLength;\r
+\r
+  //\r
+  // Construct header\r
+  //\r
+  CopyMem (RequestPtr, HttpHdr, HttpHdrSize);\r
+  RequestPtr += HttpHdrSize;\r
+\r
+  //\r
+  // Construct body\r
+  //\r
+  if (Message->Body != NULL) {\r
+    CopyMem (RequestPtr, Message->Body, Message->BodyLength);\r
+    RequestPtr += Message->BodyLength;\r
+  }\r
+\r
+  //\r
+  // Done\r
+  //\r
+  *RequestPtr = 0;\r
+  Success     = TRUE;\r
+  \r
+Exit:\r
+\r
+  if (!Success) {\r
+    if (Request != NULL) {\r
+      FreePool (Request);\r
+    }\r
+\r
+    Request = NULL;\r
+  }\r
+\r
+  if (HttpHdr != NULL) {\r
+    FreePool (HttpHdr);\r
+  }\r
+\r
+  return (CHAR8*) Request;\r
+}\r
diff --git a/NetworkPkg/HttpDxe/HttpProto.h b/NetworkPkg/HttpDxe/HttpProto.h
new file mode 100644 (file)
index 0000000..ca4b7b6
--- /dev/null
@@ -0,0 +1,457 @@
+/** @file\r
+  The header files of miscellaneous routines for HttpDxe driver.\r
+\r
+Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution.  The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#ifndef __EFI_HTTP_PROTO_H__\r
+#define __EFI_HTTP_PROTO_H__\r
+\r
+#define DEF_BUF_LEN                         2048\r
+\r
+#define HTTP_SERVICE_SIGNATURE  SIGNATURE_32('H', 't', 't', 'S')\r
+\r
+#define HTTP_SERVICE_FROM_PROTOCOL(a) \\r
+  CR ( \\r
+  (a), \\r
+  HTTP_SERVICE, \\r
+  ServiceBinding, \\r
+  HTTP_SERVICE_SIGNATURE \\r
+  )\r
+\r
+//\r
+// The state of HTTP protocol. It starts from UNCONFIGED.\r
+//\r
+#define HTTP_STATE_UNCONFIGED        0\r
+#define HTTP_STATE_HTTP_CONFIGED     1\r
+#define HTTP_STATE_TCP_CONFIGED      2\r
+#define HTTP_STATE_TCP_UNCONFIGED    3\r
+#define HTTP_STATE_TCP_CONNECTED     4\r
+#define HTTP_STATE_TCP_CLOSED        5\r
+\r
+//\r
+// TCP configured data.\r
+//\r
+#define HTTP_TOS_DEAULT              8\r
+#define HTTP_TTL_DEAULT              255\r
+#define HTTP_BUFFER_SIZE_DEAULT      65535\r
+#define HTTP_MAX_SYN_BACK_LOG        5\r
+#define HTTP_CONNECTION_TIMEOUT      60\r
+#define HTTP_DATA_RETRIES            12\r
+#define HTTP_FIN_TIMEOUT             2\r
+#define HTTP_KEEP_ALIVE_PROBES       6\r
+#define HTTP_KEEP_ALIVE_TIME         7200\r
+#define HTTP_KEEP_ALIVE_INTERVAL     30\r
+\r
+typedef struct _HTTP_SERVICE {\r
+  UINT32                        Signature;\r
+  EFI_SERVICE_BINDING_PROTOCOL  ServiceBinding;\r
+  EFI_HANDLE                    ImageHandle;\r
+  EFI_HANDLE                    ControllerHandle;\r
+  LIST_ENTRY                    ChildrenList;\r
+  UINTN                         ChildrenNumber;\r
+  EFI_HANDLE                    TcpChildHandle;\r
+  INTN                          State;\r
+} HTTP_SERVICE;\r
+\r
+typedef struct {\r
+  EFI_TCP4_IO_TOKEN             TxToken;\r
+  EFI_TCP4_TRANSMIT_DATA        TxData;\r
+  BOOLEAN                       IsTxDone;\r
+  EFI_TCP4_IO_TOKEN             RxToken;\r
+  EFI_TCP4_RECEIVE_DATA         RxData;\r
+  BOOLEAN                       IsRxDone;\r
+  UINTN                         BodyLen;\r
+  EFI_HTTP_METHOD               Method;\r
+} HTTP_TCP_TOKEN_WRAP;\r
+\r
+typedef struct _HTTP_PROTOCOL {\r
+  UINT32                        Signature;\r
+  EFI_HTTP_PROTOCOL             Http;\r
+  EFI_HANDLE                    Handle;\r
+  HTTP_SERVICE                  *Service;\r
+  LIST_ENTRY                    Link;   // Link to all HTTP instance from the service.\r
+  BOOLEAN                       InDestroy;\r
+  INTN                          State;\r
+\r
+  EFI_HANDLE                    TcpChildHandle;\r
+  EFI_TCP4_PROTOCOL             *Tcp4;\r
+  EFI_TCP4_CONFIG_DATA          Tcp4CfgData;\r
+  EFI_TCP4_OPTION               Tcp4Option;\r
+\r
+  EFI_TCP4_CONNECTION_TOKEN     ConnToken;\r
+  BOOLEAN                       IsConnDone;\r
+  EFI_TCP4_CLOSE_TOKEN          CloseToken;\r
+  BOOLEAN                       IsCloseDone;\r
+\r
+  CHAR8                         *RemoteHost;\r
+  UINT16                        RemotePort;\r
+  EFI_IPv4_ADDRESS              RemoteAddr;\r
+  //\r
+  // RxToken used for receiving HTTP header.\r
+  //\r
+  EFI_TCP4_IO_TOKEN             RxToken;\r
+  EFI_TCP4_RECEIVE_DATA         RxData;\r
+  BOOLEAN                       IsRxDone;\r
+\r
+  CHAR8                         *CacheBody;\r
+  CHAR8                         *NextMsg;\r
+  UINTN                         CacheLen;\r
+  UINTN                         CacheOffset;\r
+\r
+  //\r
+  // HTTP message-body parser.\r
+  //\r
+  VOID                          *MsgParser;\r
+  \r
+  EFI_HTTP_VERSION              HttpVersion;\r
+  UINT32                        TimeOutMillisec;\r
+  BOOLEAN                       LocalAddressIsIPv6;\r
+\r
+  EFI_HTTPv4_ACCESS_POINT       IPv4Node;\r
+\r
+  NET_MAP                       TxTokens;\r
+  NET_MAP                       RxTokens;\r
+} HTTP_PROTOCOL;\r
+\r
+typedef struct {\r
+  EFI_HTTP_TOKEN                *HttpToken;\r
+  HTTP_PROTOCOL                 *HttpInstance;\r
+  HTTP_TCP_TOKEN_WRAP           TcpWrap;\r
+} HTTP_TOKEN_WRAP;\r
+\r
+\r
+#define HTTP_PROTOCOL_SIGNATURE  SIGNATURE_32('H', 't', 't', 'P')\r
+\r
+#define HTTP_INSTANCE_FROM_PROTOCOL(a) \\r
+  CR ( \\r
+  (a), \\r
+  HTTP_PROTOCOL, \\r
+  Http, \\r
+  HTTP_PROTOCOL_SIGNATURE \\r
+  )\r
+\r
+/**\r
+  The common notify function used in HTTP driver. \r
+\r
+  @param[in]  Event   The event signaled.\r
+  @param[in]  Context The context.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+HttpCommonNotify (\r
+  IN EFI_EVENT  Event,\r
+  IN VOID       *Context\r
+  );\r
+\r
+/**\r
+  Create events for the TCP4 connection token and TCP4 close token.\r
+\r
+  @param[in]  HttpInstance       Pointer to HTTP_PROTOCOL structure.\r
+\r
+  @retval EFI_SUCCESS            The events are created successfully.\r
+  @retval others                 Other error as indicated.\r
+\r
+**/\r
+EFI_STATUS\r
+HttpCreateTcp4ConnCloseEvent (\r
+  IN  HTTP_PROTOCOL        *HttpInstance\r
+  );\r
+\r
+/**\r
+  Close events in the TCP4 connection token and TCP4 close token.\r
+\r
+  @param[in]  HttpInstance   Pointer to HTTP_PROTOCOL structure.\r
+\r
+**/\r
+VOID\r
+HttpCloseTcp4ConnCloseEvent (\r
+  IN  HTTP_PROTOCOL        *HttpInstance\r
+  );\r
+\r
+/**\r
+  Create event for the TCP4 transmit token.\r
+\r
+  @param[in]  Wrap               Point to HTTP token's wrap data.\r
+\r
+  @retval EFI_SUCCESS            The events is created successfully.\r
+  @retval others                 Other error as indicated.\r
+\r
+**/\r
+EFI_STATUS\r
+HttpCreateTcp4TxEvent (\r
+  IN  HTTP_TOKEN_WRAP      *Wrap\r
+  );\r
+\r
+/**\r
+  Create event for the TCP4 receive token which is used to receive HTTP header.\r
+\r
+  @param[in]  HttpInstance       Pointer to HTTP_PROTOCOL structure.\r
+\r
+  @retval EFI_SUCCESS            The events is created successfully.\r
+  @retval others                 Other error as indicated.\r
+\r
+**/\r
+EFI_STATUS\r
+HttpCreateTcp4RxEventForHeader (\r
+  IN  HTTP_PROTOCOL        *HttpInstance\r
+  );\r
+\r
+/**\r
+  Create event for the TCP4 receive token which is used to receive HTTP body.\r
+\r
+  @param[in]  Wrap               Point to HTTP token's wrap data.\r
+\r
+  @retval EFI_SUCCESS            The events is created successfully.\r
+  @retval others                 Other error as indicated.\r
+\r
+**/\r
+EFI_STATUS\r
+HttpCreateTcp4RxEvent (\r
+  IN  HTTP_TOKEN_WRAP      *Wrap \r
+  );\r
+\r
+/**\r
+  Intiialize the HTTP_PROTOCOL structure to the unconfigured state.\r
+\r
+  @param[in]       HttpSb               The HTTP service private instance.\r
+  @param[in, out]  HttpInstance         Pointer to HTTP_PROTOCOL structure.\r
+\r
+  @retval EFI_SUCCESS       HTTP_PROTOCOL structure is initialized successfully.                                          \r
+  @retval Others            Other error as indicated.\r
+\r
+**/\r
+EFI_STATUS\r
+HttpInitProtocol (\r
+  IN     HTTP_SERVICE            *HttpSb,\r
+  IN OUT HTTP_PROTOCOL           *HttpInstance\r
+  );\r
+\r
+/**\r
+  Clean up the HTTP child, release all the resources used by it.\r
+\r
+  @param[in]  HttpInstance       The HTTP child to clean up.\r
+\r
+**/\r
+VOID\r
+HttpCleanProtocol (\r
+  IN  HTTP_PROTOCOL          *HttpInstance\r
+  );\r
+\r
+/**\r
+  Establish TCP connection with HTTP server.\r
+\r
+  @param[in]  HttpInstance       The HTTP instance private data.\r
+\r
+  @retval EFI_SUCCESS            The TCP connection is established.\r
+  @retval Others                 Other error as indicated.\r
+\r
+**/\r
+EFI_STATUS\r
+HttpCreateConnection (\r
+  IN  HTTP_PROTOCOL        *HttpInstance\r
+  );\r
+\r
+/**\r
+  Close existing TCP connection.\r
+\r
+  @param[in]  HttpInstance       The HTTP instance private data.\r
+\r
+  @retval EFI_SUCCESS            The TCP connection is closed.\r
+  @retval Others                 Other error as indicated.\r
+\r
+**/\r
+EFI_STATUS\r
+HttpCloseConnection (\r
+  IN  HTTP_PROTOCOL        *HttpInstance\r
+  );\r
+\r
+/**\r
+  Configure TCP4 protocol child.\r
+\r
+  @param[in]  HttpInstance       The HTTP instance private data.\r
+  @param[in]  Wrap               The HTTP token's wrap data.\r
+\r
+  @retval EFI_SUCCESS            The TCP4 protocol child is configured.\r
+  @retval Others                 Other error as indicated.\r
+\r
+**/\r
+EFI_STATUS\r
+HttpConfigureTcp4 (\r
+  IN  HTTP_PROTOCOL        *HttpInstance,\r
+  IN  HTTP_TOKEN_WRAP      *Wrap\r
+  );\r
+\r
+/**\r
+  Check existing TCP connection, if in error state, receover TCP4 connection.\r
+\r
+  @param[in]  HttpInstance       The HTTP instance private data.\r
+\r
+  @retval EFI_SUCCESS            The TCP connection is established.\r
+  @retval EFI_NOT_READY          TCP4 protocol child is not created or configured.\r
+  @retval Others                 Other error as indicated.\r
+\r
+**/\r
+EFI_STATUS\r
+HttpConnectTcp4 (\r
+  IN  HTTP_PROTOCOL        *HttpInstance\r
+  );\r
+\r
+/**\r
+  Send the HTTP message through TCP4.\r
+\r
+  @param[in]  HttpInstance       The HTTP instance private data.\r
+  @param[in]  Wrap               The HTTP token's wrap data.\r
+  @param[in]  TxString           Buffer containing the HTTP message string.\r
+  @param[in]  TxStringLen        Length of the HTTP message string in bytes.\r
+\r
+  @retval EFI_SUCCESS            The HTTP message is queued into TCP transmit queue.\r
+  @retval Others                 Other error as indicated.\r
+\r
+**/\r
+EFI_STATUS\r
+HttpTransmitTcp4 (\r
+  IN  HTTP_PROTOCOL    *HttpInstance,\r
+  IN  HTTP_TOKEN_WRAP  *Wrap,\r
+  IN  UINT8            *TxString,\r
+  IN  UINTN            TxStringLen\r
+  );\r
+\r
+/**\r
+  Translate the status code in HTTP message to EFI_HTTP_STATUS_CODE defined \r
+  in UEFI 2.5 specification.\r
+\r
+  @param[in]  StatusCode         The status code value in HTTP message.\r
+\r
+  @return                        Value defined in EFI_HTTP_STATUS_CODE .\r
+\r
+**/\r
+EFI_HTTP_STATUS_CODE\r
+HttpMappingToStatusCode (\r
+  IN UINTN                  StatusCode\r
+  );\r
+\r
+/**\r
+  Check whether the user's token or event has already\r
+  been enqueue on HTTP TxToken or RxToken list.\r
+\r
+  @param[in]  Map                The container of either user's transmit or receive\r
+                                 token.\r
+  @param[in]  Item               Current item to check against.\r
+  @param[in]  Context            The Token to check againist.\r
+\r
+  @retval EFI_ACCESS_DENIED      The token or event has already been enqueued in IP\r
+  @retval EFI_SUCCESS            The current item isn't the same token/event as the\r
+                                 context.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+HttpTokenExist (\r
+  IN NET_MAP                *Map,\r
+  IN NET_MAP_ITEM           *Item,\r
+  IN VOID                   *Context\r
+  );\r
+\r
+/**\r
+  Check whether the HTTP message associated with TxToken is already sent out.\r
+\r
+  @param[in]  Map                The container of TxToken.\r
+  @param[in]  Item               Current item to check against.\r
+  @param[in]  Context            The Token to check againist.\r
+\r
+  @retval EFI_NOT_READY          The HTTP message is still queued in the list.\r
+  @retval EFI_SUCCESS            The HTTP message has been sent out.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+HttpTcpNotReady (\r
+  IN NET_MAP                *Map,\r
+  IN NET_MAP_ITEM           *Item,\r
+  IN VOID                   *Context\r
+  );\r
+\r
+/**\r
+  Transmit the HTTP mssage by processing the associated HTTP token.\r
+\r
+  @param[in]  Map                The container of TxToken.\r
+  @param[in]  Item               Current item to check against.\r
+  @param[in]  Context            The Token to check againist.\r
+\r
+  @retval EFI_OUT_OF_RESOURCES   Failed to allocate resources.\r
+  @retval EFI_SUCCESS            The HTTP message is queued into TCP transmit\r
+                                 queue.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+HttpTcpTransmit (\r
+  IN NET_MAP                *Map,\r
+  IN NET_MAP_ITEM           *Item,\r
+  IN VOID                   *Context\r
+  );\r
+\r
+/**\r
+  Receive the HTTP response by processing the associated HTTP token.\r
+\r
+  @param[in]  Map                The container of RxToken.\r
+  @param[in]  Item               Current item to check against.\r
+  @param[in]  Context            The Token to check againist.\r
+\r
+  @retval EFI_SUCCESS            The HTTP response is queued into TCP receive\r
+                                 queue.\r
+  @retval Others                 Other error as indicated.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+HttpTcpReceive (\r
+  IN NET_MAP                *Map,\r
+  IN NET_MAP_ITEM           *Item,\r
+  IN VOID                   *Context\r
+  );\r
+\r
+/**\r
+  Generate HTTP request string.\r
+\r
+  @param[in]  HttpInstance       Pointer to HTTP_PROTOCOL structure.\r
+  @param[in]  Message            Pointer to storage containing HTTP message data.\r
+  @param[in]  Url                The URL of a remote host.\r
+\r
+  @return     Pointer to the created HTTP request string.\r
+  @return     NULL if any error occured.\r
+\r
+**/\r
+CHAR8 *\r
+HttpGenRequestString (\r
+  IN  HTTP_PROTOCOL        *HttpInstance,\r
+  IN  EFI_HTTP_MESSAGE     *Message,\r
+  IN  CHAR8                *Url\r
+  );\r
+\r
+/**\r
+  The work function of EfiHttpResponse().\r
+\r
+  @param[in]  Wrap                Pointer to HTTP token's wrap data.\r
+\r
+  @retval EFI_SUCCESS             Allocation succeeded.\r
+  @retval EFI_OUT_OF_RESOURCES    Failed to complete the opration due to lack of resources.\r
+  @retval EFI_NOT_READY           Can't find a corresponding TxToken.\r
+\r
+**/\r
+EFI_STATUS\r
+HttpResponseWorker (\r
+  IN  HTTP_TOKEN_WRAP           *Wrap\r
+  );\r
+\r
+#endif\r
diff --git a/NetworkPkg/HttpDxe/HttpUtilities.c b/NetworkPkg/HttpDxe/HttpUtilities.c
new file mode 100644 (file)
index 0000000..c2a99a4
--- /dev/null
@@ -0,0 +1,622 @@
+/** @file\r
+\r
+Implementation of help functions to parse HTTP message header.\r
+\r
+Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution.  The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "HttpDriver.h"\r
+\r
+/**\r
+  Get the next string, which is distinguished by specified seperator. \r
+\r
+  @param[in]  String             Pointer to the string.\r
+  @param[in]  Seperator          Specified seperator used to distinguish where is the beginning \r
+                                 of next string.\r
+\r
+  @return     Pointer to the next string.\r
+  @return     NULL if not find or String is NULL.\r
+\r
+**/\r
+CHAR8 *\r
+AsciiStrGetNextToken (\r
+  IN CONST CHAR8 *String,\r
+  IN       CHAR8 Seperator\r
+  )\r
+{\r
+  CONST CHAR8 *Token;\r
+\r
+  Token = String;\r
+  while (TRUE) {\r
+    if (*Token == 0) {\r
+      return NULL;\r
+    }\r
+    if (*Token == Seperator) {\r
+      return (CHAR8 *) (Token + 1);\r
+    }\r
+    Token++;\r
+  }\r
+}\r
+\r
+/**\r
+  Free existing HeaderFields.\r
+\r
+  @param[in]  HeaderFields       Pointer to array of key/value header pairs waitting for free.\r
+  @param[in]  FieldCount         The number of header pairs in HeaderFields.\r
+\r
+**/\r
+VOID\r
+FreeHeaderFields (\r
+  IN  EFI_HTTP_HEADER  *HeaderFields,\r
+  IN  UINTN            FieldCount\r
+  )\r
+{\r
+  UINTN                       Index;\r
+  \r
+  if (HeaderFields != NULL) {\r
+    for (Index = 0; Index < FieldCount; Index++) {\r
+      if(HeaderFields[Index].FieldName != NULL) {\r
+        FreePool (HeaderFields[Index].FieldName);\r
+      }\r
+      if(HeaderFields[Index].FieldValue != NULL) {\r
+        FreePool (HeaderFields[Index].FieldValue);\r
+      }\r
+    }\r
+\r
+    FreePool (HeaderFields);\r
+  }\r
+}\r
+\r
+/**\r
+  Find required header field in HeaderFields.\r
+\r
+  @param[in]  HeaderFields        Pointer to array of key/value header pairs.\r
+  @param[in]  FieldCount          The number of header pairs.\r
+  @param[in]  FieldName           Pointer to header field's name.\r
+\r
+  @return     Pointer to the queried header field.\r
+  @return     NULL if not find this required header field.\r
+\r
+**/\r
+EFI_HTTP_HEADER *\r
+FindHttpHeader (\r
+  IN  EFI_HTTP_HEADER  *HeaderFields,\r
+  IN  UINTN            FieldCount,\r
+  IN  CHAR8            *FieldName\r
+  )\r
+{\r
+  UINTN                       Index;\r
+\r
+  for (Index = 0; Index < FieldCount; Index++) {\r
+    if (AsciiStrCmp (FieldName, HeaderFields[Index].FieldName) == 0) {\r
+      //\r
+      // Find the required header field.\r
+      //\r
+      return &HeaderFields[Index];\r
+    }\r
+  }\r
+  return NULL;\r
+}\r
+\r
+/**\r
+  Check whether header field called FieldName is in DeleteList.\r
+\r
+  @param[in]  DeleteList        Pointer to array of key/value header pairs.\r
+  @param[in]  DeleteCount       The number of header pairs.\r
+  @param[in]  FieldName         Pointer to header field's name.\r
+\r
+  @return     TRUE if FieldName is not in DeleteList, that means this header field is valid.\r
+  @return     FALSE if FieldName is in DeleteList, that means this header field is invalid.\r
+\r
+**/\r
+BOOLEAN\r
+IsValidHttpHeader (\r
+  IN  CHAR8            *DeleteList[],\r
+  IN  UINTN            DeleteCount,\r
+  IN  CHAR8            *FieldName\r
+  )\r
+{\r
+  UINTN                       Index;\r
+\r
+  for (Index = 0; Index < DeleteCount; Index++) {\r
+    if (AsciiStrCmp (FieldName, DeleteList[Index]) == 0) {\r
+      return FALSE;\r
+    }\r
+  }\r
+  \r
+  return TRUE;\r
+}\r
+\r
+/**\r
+  Set FieldName and FieldValue into specified HttpHeader.\r
+\r
+  @param[in]  HttpHeader          Specified HttpHeader.\r
+  @param[in]  FieldName           FieldName of this HttpHeader.\r
+  @param[in]  FieldValue          FieldValue of this HttpHeader.\r
+\r
+\r
+  @retval EFI_SUCCESS             The FieldName and FieldValue are set into HttpHeader successfully.\r
+  @retval EFI_OUT_OF_RESOURCES    Failed to allocate resources.\r
+\r
+**/\r
+EFI_STATUS\r
+SetFieldNameAndValue (\r
+  IN  EFI_HTTP_HEADER     *HttpHeader,\r
+  IN  CHAR8               *FieldName, \r
+  IN  CHAR8               *FieldValue\r
+  )\r
+{  \r
+  UINTN                       FieldNameSize;\r
+  UINTN                       FieldValueSize;\r
+\r
+  if (HttpHeader->FieldName != NULL) {\r
+    FreePool (HttpHeader->FieldName);\r
+  }\r
+  if (HttpHeader->FieldValue != NULL) {\r
+    FreePool (HttpHeader->FieldValue);\r
+  }\r
+\r
+  FieldNameSize = AsciiStrSize (FieldName);\r
+  HttpHeader->FieldName = AllocateZeroPool (FieldNameSize);\r
+  if (HttpHeader->FieldName == NULL) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+  CopyMem (HttpHeader->FieldName, FieldName, FieldNameSize);\r
+  HttpHeader->FieldName[FieldNameSize - 1] = 0;\r
+\r
+  FieldValueSize = AsciiStrSize (FieldValue);\r
+  HttpHeader->FieldValue = AllocateZeroPool (FieldValueSize);\r
+  if (HttpHeader->FieldValue == NULL) {\r
+    FreePool (HttpHeader->FieldName);\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+  CopyMem (HttpHeader->FieldValue, FieldValue, FieldValueSize);\r
+  HttpHeader->FieldValue[FieldValueSize - 1] = 0;\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Get one key/value header pair from the raw string.\r
+\r
+  @param[in]  String             Pointer to the raw string.\r
+  @param[out] FieldName          Pointer to header field's name.\r
+  @param[out] FieldValue         Pointer to header field's value.\r
+\r
+  @return     Pointer to the next raw string.\r
+  @return     NULL if no key/value header pair from this raw string.\r
+\r
+**/\r
+CHAR8 *\r
+GetFieldNameAndValue (\r
+  IN  CHAR8   *String,\r
+  OUT CHAR8   **FieldName,\r
+  OUT CHAR8   **FieldValue\r
+  )\r
+{\r
+  CHAR8  *FieldNameStr;\r
+  CHAR8  *FieldValueStr;\r
+  CHAR8  *StrPtr;\r
+\r
+  if (String == NULL || FieldName == NULL || FieldValue == NULL) {\r
+    return NULL;\r
+  }\r
+  \r
+  *FieldName    = NULL;\r
+  *FieldValue   = NULL;\r
+  FieldNameStr  = NULL;\r
+  FieldValueStr = NULL;\r
+  StrPtr        = NULL;\r
+\r
+  //\r
+  // Each header field consists of a name followed by a colon (":") and the field value.\r
+  //\r
+  FieldNameStr = String;\r
+  FieldValueStr = AsciiStrGetNextToken (FieldNameStr, ':');\r
+  if (FieldValueStr == NULL) {\r
+    return NULL;\r
+  }\r
+  \r
+  *(FieldValueStr - 1) = 0; /// Replace ':' with 0\r
+  \r
+  //\r
+  // The field value MAY be preceded by any amount of LWS, though a single SP is preferred.\r
+  //\r
+  while (TRUE) {\r
+    if(*FieldValueStr == ' ' || *FieldValueStr == '\t') {\r
+      FieldValueStr ++;\r
+    } else if (*FieldValueStr == '\r' && *(FieldValueStr + 1) == '\n' && \r
+               (*(FieldValueStr + 2) == ' ' || *(FieldValueStr + 2) == '\t')) {\r
+      FieldValueStr = FieldValueStr + 3;\r
+    } else {\r
+      break;\r
+    }\r
+  }\r
+\r
+  //\r
+  // Header fields can be extended over multiple lines by preceding each extra\r
+  // line with at least one SP or HT.\r
+  //\r
+  StrPtr = FieldValueStr;\r
+  do {\r
+    StrPtr = AsciiStrGetNextToken (StrPtr, '\r');\r
+    if (StrPtr == NULL || *StrPtr != '\n') {\r
+      return NULL;\r
+    }\r
+    \r
+    StrPtr++;\r
+  } while (*StrPtr == ' ' || *StrPtr == '\t');\r
+\r
+  //\r
+  // Replace '\r' with 0.\r
+  //\r
+  *(StrPtr - 2) = 0;\r
+\r
+  //\r
+  // Get FieldName and FieldValue.\r
+  //\r
+  *FieldName = FieldNameStr;\r
+  *FieldValue = FieldValueStr;\r
+    \r
+  return StrPtr;\r
+}\r
+\r
+/**\r
+  This function is used to manage the headers portion of an HTTP message by providing \r
+  the ability to add, remove, or replace HTTP headers.\r
+\r
+  @param[in]   SeedMessageSize       Size in bytes of the initial HTTP header. This can be zero.  \r
+  @param[in]   SeedMessage           Initial raw unformatted HTTP header to be used as a base for \r
+                                     building a new unformatted HTTP header. If NULL, SeedMessageSize \r
+                                     is ignored. The buffer containing this message will be allocated \r
+                                     and released by the caller.           \r
+  @param[in]   DeleteCount           Number of null-terminated HTTP header field names in DeleteList.\r
+  @param[in]   DeleteList            List of null-terminated HTTP header field names to remove from SeedMessage. \r
+                                     Only the field names are in this list because the field values are irrelevant \r
+                                     to this operation. If NULL, DeleteCount is ignored. The buffer containing the \r
+                                     list will be allocated and released by the caller.\r
+  @param[in]   AppendCount           Number of header fields in AppendList. \r
+  @param[in]   AppendList            List of HTTP headers to populate NewMessage with. If SeedMessage is not NULL, \r
+                                     AppendList will be appended to the existing list from SeedMessage in NewMessage.\r
+  @param[out]  NewMessageSize        Pointer to the size in bytes of the new unformatted HTTP header in NewMessage.       \r
+  @param[out]  NewMessage            Pointer to a new unformatted HTTP header. The storage for this NewMessage is \r
+                                     allocated by the driver publishing this protocol, and must be freed by the caller. \r
+  \r
+  @retval EFI_SUCCESS                Add, remove, and replace operations succeeded.\r
+  @retval EFI_OUT_OF_RESOURCES       Could not allocate memory for NewMessage.\r
+  \r
+**/\r
+EFI_STATUS\r
+HttpUtilitiesBuild(\r
+  IN     UINTN                       SeedMessageSize,\r
+  IN     VOID                        *SeedMessage, OPTIONAL\r
+  IN     UINTN                       DeleteCount,\r
+  IN     CHAR8                       *DeleteList[], OPTIONAL\r
+  IN     UINTN                       AppendCount,\r
+  IN     EFI_HTTP_HEADER             *AppendList[], OPTIONAL\r
+     OUT UINTN                       *NewMessageSize,\r
+     OUT VOID                        **NewMessage\r
+  )\r
+{\r
+  EFI_STATUS                Status;  \r
+  EFI_HTTP_HEADER           *SeedHeaderFields;\r
+  UINTN                     SeedFieldCount;\r
+  UINTN                     Index;\r
+  EFI_HTTP_HEADER           *TempHeaderFields;\r
+  UINTN                     TempFieldCount;\r
+  EFI_HTTP_HEADER           *NewHeaderFields;\r
+  UINTN                     NewFieldCount;\r
+  EFI_HTTP_HEADER           *HttpHeader;\r
+  UINTN                     StrLength;\r
+  UINT8                     *NewMessagePtr;\r
+\r
+  SeedHeaderFields = NULL;\r
+  SeedFieldCount   = 0;\r
+  TempHeaderFields = NULL;\r
+  TempFieldCount   = 0;\r
+  NewHeaderFields  = NULL;\r
+  NewFieldCount    = 0;\r
+\r
+  HttpHeader       = NULL;  \r
+  StrLength        = 0;\r
+  NewMessagePtr    = NULL;\r
+  *NewMessageSize  = 0;\r
+  Status           = EFI_SUCCESS;\r
+\r
+  if (SeedMessage != NULL) {\r
+    Status = HttpUtilitiesParse (\r
+              SeedMessage,\r
+              SeedMessageSize,\r
+              &SeedHeaderFields,\r
+              &SeedFieldCount\r
+              );\r
+    if (EFI_ERROR (Status)){\r
+      goto ON_EXIT;\r
+    }\r
+  }\r
+\r
+  //\r
+  // Handle DeleteList\r
+  //\r
+  if(SeedFieldCount != 0 && DeleteCount != 0) {\r
+    TempHeaderFields = AllocateZeroPool (SeedFieldCount * sizeof(EFI_HTTP_HEADER));\r
+    if (TempHeaderFields == NULL) {\r
+      Status = EFI_OUT_OF_RESOURCES;\r
+      goto ON_EXIT;\r
+    }\r
+    \r
+    for (Index = 0, TempFieldCount = 0; Index < SeedFieldCount; Index++) {\r
+      //\r
+      // Check whether each SeedHeaderFields member is in DeleteList\r
+      //\r
+      if (IsValidHttpHeader(DeleteList, DeleteCount, SeedHeaderFields[Index].FieldName)) {\r
+        Status = SetFieldNameAndValue(\r
+                   &TempHeaderFields[TempFieldCount],\r
+                   SeedHeaderFields[Index].FieldName,\r
+                   SeedHeaderFields[Index].FieldValue\r
+                   );\r
+        if (EFI_ERROR (Status)){\r
+          goto ON_EXIT;\r
+        }\r
+        TempFieldCount++;\r
+      }\r
+    }\r
+  } else {\r
+    TempHeaderFields = SeedHeaderFields;\r
+    TempFieldCount = SeedFieldCount;\r
+  }\r
+\r
+  //\r
+  // Handle AppendList\r
+  //\r
+  NewHeaderFields = AllocateZeroPool ((TempFieldCount + AppendCount) * sizeof(EFI_HTTP_HEADER));\r
+  if (NewHeaderFields == NULL) {\r
+    Status = EFI_OUT_OF_RESOURCES;\r
+    goto ON_EXIT;\r
+  }\r
+\r
+  for (Index = 0; Index < TempFieldCount; Index++) {\r
+    Status = SetFieldNameAndValue(\r
+               &NewHeaderFields[Index],\r
+               TempHeaderFields[Index].FieldName,\r
+               TempHeaderFields[Index].FieldValue\r
+               );\r
+    if (EFI_ERROR (Status)){\r
+      goto ON_EXIT;\r
+    }\r
+  }\r
+  \r
+  NewFieldCount = TempFieldCount;\r
+\r
+  for (Index = 0; Index < AppendCount; Index++) {\r
+    HttpHeader = FindHttpHeader(NewHeaderFields, NewFieldCount, AppendList[Index]->FieldName);\r
+    if(HttpHeader != NULL) {\r
+      Status = SetFieldNameAndValue(\r
+                 HttpHeader,\r
+                 AppendList[Index]->FieldName,\r
+                 AppendList[Index]->FieldValue\r
+                 );\r
+      if (EFI_ERROR (Status)){\r
+        goto ON_EXIT;\r
+      }\r
+    } else {\r
+      Status = SetFieldNameAndValue\r
+                 (&NewHeaderFields[NewFieldCount],\r
+                 AppendList[Index]->FieldName,\r
+                 AppendList[Index]->FieldValue\r
+                 );\r
+      if (EFI_ERROR (Status)){\r
+        goto ON_EXIT;\r
+      }\r
+      NewFieldCount++;\r
+    }\r
+  }\r
+\r
+  //\r
+  // Calculate NewMessageSize, then build NewMessage\r
+  //\r
+  for (Index = 0; Index < NewFieldCount; Index++) {\r
+    HttpHeader = &NewHeaderFields[Index];\r
+\r
+    StrLength = AsciiStrLen (HttpHeader->FieldName);\r
+    *NewMessageSize += StrLength;\r
+\r
+    StrLength = sizeof(": ") - 1;\r
+    *NewMessageSize += StrLength;\r
+\r
+    StrLength = AsciiStrLen (HttpHeader->FieldValue);\r
+    *NewMessageSize += StrLength;\r
+\r
+    StrLength = sizeof(HTTP_CRLF_STR) - 1;\r
+    *NewMessageSize += StrLength;\r
+  }\r
+  StrLength = sizeof(HTTP_CRLF_STR) - 1;\r
+  *NewMessageSize += StrLength;\r
+  //\r
+  // Final 0 for end flag.\r
+  //\r
+  *NewMessageSize += 1;\r
+\r
+  *NewMessage = AllocateZeroPool (*NewMessageSize);\r
+  if (*NewMessage == NULL) {\r
+    Status = EFI_OUT_OF_RESOURCES;\r
+    goto ON_EXIT;\r
+  }\r
+\r
+  NewMessagePtr = (UINT8 *)(*NewMessage);\r
+\r
+  for (Index = 0; Index < NewFieldCount; Index++) {\r
+    HttpHeader = &NewHeaderFields[Index];\r
+\r
+    StrLength = AsciiStrLen (HttpHeader->FieldName);\r
+    CopyMem (NewMessagePtr, HttpHeader->FieldName, StrLength);\r
+    NewMessagePtr += StrLength;\r
+\r
+    StrLength = sizeof(": ") - 1;\r
+    CopyMem (NewMessagePtr, ": ", StrLength);\r
+    NewMessagePtr += StrLength;\r
+\r
+    StrLength = AsciiStrLen (HttpHeader->FieldValue);\r
+    CopyMem (NewMessagePtr, HttpHeader->FieldValue, StrLength);\r
+    NewMessagePtr += StrLength;\r
+\r
+    StrLength = sizeof(HTTP_CRLF_STR) - 1;\r
+    CopyMem (NewMessagePtr, HTTP_CRLF_STR, StrLength);\r
+    NewMessagePtr += StrLength;\r
+  }\r
+  StrLength = sizeof(HTTP_CRLF_STR) - 1;\r
+  CopyMem (NewMessagePtr, HTTP_CRLF_STR, StrLength);\r
+  NewMessagePtr += StrLength;\r
+\r
+  *NewMessagePtr = 0;\r
+\r
+  ASSERT (*NewMessageSize == (UINTN) NewMessagePtr - (UINTN) (*NewMessage) + 1);\r
+\r
+  //\r
+  // Free allocated buffer \r
+  //\r
+ON_EXIT:\r
+  if(SeedHeaderFields != NULL) {\r
+    FreeHeaderFields(SeedHeaderFields, SeedFieldCount);\r
+  }\r
+  \r
+  if(TempHeaderFields != NULL) {\r
+    FreeHeaderFields(TempHeaderFields, TempFieldCount);\r
+  }\r
+\r
+  if(NewHeaderFields != NULL) {\r
+    FreeHeaderFields(NewHeaderFields, NewFieldCount);\r
+  }\r
+  \r
+  return Status;\r
+}\r
+\r
+/**\r
+  This function is used to transform data stored in HttpMessage into a list of fields \r
+  paired with their corresponding values.\r
+\r
+  @param[in]   HttpMessage           Contains raw unformatted HTTP header string. The buffer for this string will \r
+                                     be allocated and released by the caller.\r
+  @param[in]   HttpMessageSize       Size in bytes of raw unformatted HTTP header.      \r
+  @param[out]  HeaderFields          Array of key/value header pairs. The storage for all header pairs is allocated\r
+                                     by the driver publishing this protocol, and must be freed by the caller. \r
+  @param[out]  FieldCount            Number of headers in HeaderFields.\r
+  \r
+  @retval EFI_SUCCESS                Parse HTTP header into array of key/value pairs succeeded.\r
+  @retval EFI_OUT_OF_RESOURCES       Could not allocate memory for NewMessage.\r
+  @retval EFI_INVALID_PARAMETER      One or more of the following conditions is TRUE:\r
+                                     HttpMessage is NULL.\r
+                                     HeaderFields is NULL.\r
+                                     FieldCount is NULL.\r
+  \r
+**/\r
+EFI_STATUS\r
+HttpUtilitiesParse(\r
+  IN  CHAR8                        *HttpMessage,\r
+  IN  UINTN                        HttpMessageSize,\r
+  OUT EFI_HTTP_HEADER              **HeaderFields,\r
+  OUT UINTN                        *FieldCount\r
+  )\r
+{\r
+  EFI_STATUS                Status;\r
+  CHAR8                     *TempHttpMessage;\r
+  CHAR8                     *Token;\r
+  CHAR8                     *NextToken;\r
+  CHAR8                     *FieldName;\r
+  CHAR8                     *FieldValue;\r
+  UINTN                     Index;\r
+\r
+  if (HttpMessage == NULL || HeaderFields == NULL || FieldCount == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
\r
+  Status          = EFI_SUCCESS;\r
+  TempHttpMessage = NULL;\r
+  *FieldCount     = 0;\r
+  Token           = NULL;\r
+  NextToken       = NULL;\r
+  FieldName       = NULL;\r
+  FieldValue      = NULL;\r
+  Index           = 0;  \r
+\r
+  TempHttpMessage = AllocateZeroPool (HttpMessageSize);\r
+  if (TempHttpMessage == NULL) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  CopyMem (TempHttpMessage, HttpMessage, HttpMessageSize);\r
+  \r
+  //\r
+  // Get header number\r
+  //\r
+  Token = TempHttpMessage;\r
+  while (TRUE) {\r
+    FieldName     = NULL;\r
+    FieldValue    = NULL;\r
+    NextToken = GetFieldNameAndValue (Token, &FieldName, &FieldValue);\r
+    Token     = NextToken;\r
+    if (FieldName == NULL || FieldValue == NULL) {\r
+      break;\r
+    }\r
+\r
+    (*FieldCount)++;\r
+  }\r
+\r
+  if(*FieldCount == 0) {\r
+    Status =  EFI_INVALID_PARAMETER;\r
+    goto ON_EXIT;\r
+  }\r
+  \r
+  //\r
+  // Allocate buffer for header\r
+  //\r
+  *HeaderFields = AllocateZeroPool ((*FieldCount) * sizeof(EFI_HTTP_HEADER));\r
+  if (*HeaderFields == NULL) {\r
+    *FieldCount = 0;\r
+    Status = EFI_OUT_OF_RESOURCES;\r
+    goto ON_EXIT;\r
+  }\r
+  \r
+  CopyMem (TempHttpMessage, HttpMessage, HttpMessageSize);\r
+  \r
+  //\r
+  // Set Field and Value to each header\r
+  //\r
+  Token = TempHttpMessage;\r
+  while (Index < *FieldCount) {\r
+    FieldName     = NULL;\r
+    FieldValue    = NULL;\r
+    NextToken = GetFieldNameAndValue (Token, &FieldName, &FieldValue);\r
+    Token     = NextToken;\r
+    if (FieldName == NULL || FieldValue == NULL) {\r
+      break;\r
+    }\r
+\r
+    Status = SetFieldNameAndValue(&(*HeaderFields)[Index], FieldName, FieldValue);\r
+    if(EFI_ERROR(Status)){\r
+      *FieldCount = 0;\r
+      FreeHeaderFields (*HeaderFields, Index);\r
+      goto ON_EXIT;\r
+    }\r
+    \r
+    Index++;\r
+  }\r
+\r
+  //\r
+  // Free allocated buffer \r
+  //\r
+ON_EXIT:\r
+  if (TempHttpMessage != NULL) {\r
+    FreePool(TempHttpMessage);\r
+  }\r
+  \r
+  return Status;\r
+}\r
diff --git a/NetworkPkg/HttpDxe/HttpUtilities.h b/NetworkPkg/HttpDxe/HttpUtilities.h
new file mode 100644 (file)
index 0000000..bd4ef0b
--- /dev/null
@@ -0,0 +1,82 @@
+/** @file\r
+  The header files of HTTP helper functions for HttpDxe driver.\r
+\r
+Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution.  The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#ifndef __EFI_HTTP_UTILITIES_H__\r
+#define __EFI_HTTP_UTILITIES_H__\r
+\r
+/**\r
+  This function is used to manage the headers portion of an HTTP message by providing \r
+  the ability to add, remove, or replace HTTP headers.\r
+\r
+  @param[in]   SeedMessageSize       Size in bytes of the initial HTTP header. This can be zero.  \r
+  @param[in]   SeedMessage           Initial raw unformatted HTTP header to be used as a base for \r
+                                     building a new unformatted HTTP header. If NULL, SeedMessageSize \r
+                                     is ignored. The buffer containing this message will be allocated \r
+                                     and released by the caller.           \r
+  @param[in]   DeleteCount           Number of null-terminated HTTP header field names in DeleteList.\r
+  @param[in]   DeleteList            List of null-terminated HTTP header field names to remove from SeedMessage. \r
+                                     Only the field names are in this list because the field values are irrelevant \r
+                                     to this operation. If NULL, DeleteCount is ignored. The buffer containing the \r
+                                     list will be allocated and released by the caller.\r
+  @param[in]   AppendCount           Number of header fields in AppendList. \r
+  @param[in]   AppendList            List of HTTP headers to populate NewMessage with. If SeedMessage is not NULL, \r
+                                     AppendList will be appended to the existing list from SeedMessage in NewMessage.\r
+  @param[out]  NewMessageSize        Pointer to the size in bytes of the new unformatted HTTP header in NewMessage.       \r
+  @param[out]  NewMessage            Pointer to a new unformatted HTTP header. The storage for this NewMessage is \r
+                                     allocated by the driver publishing this protocol, and must be freed by the caller. \r
+  \r
+  @retval EFI_SUCCESS                Add, remove, and replace operations succeeded.\r
+  @retval EFI_OUT_OF_RESOURCES       Could not allocate memory for NewMessage.\r
+  \r
+**/\r
+EFI_STATUS\r
+HttpUtilitiesBuild(\r
+  IN     UINTN                       SeedMessageSize,\r
+  IN     VOID                        *SeedMessage, OPTIONAL\r
+  IN     UINTN                       DeleteCount,\r
+  IN     CHAR8                       *DeleteList[], OPTIONAL\r
+  IN     UINTN                       AppendCount,\r
+  IN     EFI_HTTP_HEADER             *AppendList[], OPTIONAL\r
+     OUT UINTN                       *NewMessageSize,\r
+     OUT VOID                        **NewMessage\r
+  );\r
+\r
+/**\r
+  This function is used to transform data stored in HttpMessage into a list of fields \r
+  paired with their corresponding values.\r
+\r
+  @param[in]   HttpMessage           Contains raw unformatted HTTP header string. The buffer for this string will \r
+                                     be allocated and released by the caller.\r
+  @param[in]   HttpMessageSize       Size in bytes of raw unformatted HTTP header.      \r
+  @param[out]  HeaderFields          Array of key/value header pairs. The storage for all header pairs is allocated\r
+                                     by the driver publishing this protocol, and must be freed by the caller. \r
+  @param[out]  FieldCount            Number of headers in HeaderFields.\r
+  \r
+  @retval EFI_SUCCESS                Parse HTTP header into array of key/value pairs succeeded.\r
+  @retval EFI_OUT_OF_RESOURCES       Could not allocate memory for NewMessage.\r
+  @retval EFI_INVALID_PARAMETER      One or more of the following conditions is TRUE:\r
+                                     HttpMessage is NULL.\r
+                                     HeaderFields is NULL.\r
+                                     FieldCount is NULL.\r
+  \r
+**/\r
+EFI_STATUS\r
+HttpUtilitiesParse(\r
+  IN  CHAR8                        *HttpMessage,\r
+  IN  UINTN                        HttpMessageSize,\r
+  OUT EFI_HTTP_HEADER              **HeaderFields,\r
+  OUT UINTN                        *FieldCount\r
+  );\r
+\r
+#endif\r