--- /dev/null
+/** @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
--- /dev/null
+/** @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
--- /dev/null
+/** @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
--- /dev/null
+/** @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
--- /dev/null
+/** @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
--- /dev/null
+/** @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
--- /dev/null
+## @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
--- /dev/null
+/** @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
--- /dev/null
+/** @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
--- /dev/null
+/** @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
--- /dev/null
+/** @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
--- /dev/null
+/** @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
--- /dev/null
+/** @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