]> git.proxmox.com Git - mirror_edk2.git/blobdiff - NetworkPkg/HttpDxe/HttpImpl.c
MdeModulePkg-DxeCore: rename CoreGetMemoryMapPropertiesTable
[mirror_edk2.git] / NetworkPkg / HttpDxe / HttpImpl.c
index 80e819201ec1b667dbf78d325b380b56df2763b1..7a236f40e020e5da0e2f408c4784f3c6fd9cb047 100644 (file)
@@ -1,7 +1,8 @@
 /** @file\r
   Implementation of EFI_HTTP_PROTOCOL protocol interfaces.\r
 \r
-  Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>\r
+  Copyright (c) 2015 - 2016, Intel Corporation. All rights reserved.<BR>\r
+  (C) Copyright 2015-2016 Hewlett Packard Enterprise Development LP<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
@@ -38,8 +39,11 @@ EFI_HTTP_PROTOCOL  mEfiHttpTemplate = {
   @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
+                                  HttpInstance->LocalAddressIsIPv6 is FALSE and\r
+                                  HttpConfigData->IPv4Node is NULL.\r
+                                  HttpInstance->LocalAddressIsIPv6 is TRUE and\r
+                                  HttpConfigData->IPv6Node is NULL.\r
+  @retval EFI_NOT_STARTED         This EFI HTTP Protocol instance has not been started.\r
 \r
 **/\r
 EFI_STATUS\r
@@ -51,30 +55,42 @@ EfiHttpGetModeData (
 {\r
   HTTP_PROTOCOL                 *HttpInstance;\r
 \r
+  //\r
+  // Check input parameters.\r
+  //\r
   if ((This == NULL) || (HttpConfigData == NULL)) {\r
     return EFI_INVALID_PARAMETER;\r
   }\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
+  if ((HttpInstance->LocalAddressIsIPv6 && HttpConfigData->AccessPoint.IPv6Node == NULL) ||\r
+      (!HttpInstance->LocalAddressIsIPv6 && HttpConfigData->AccessPoint.IPv4Node == NULL)) {\r
+    return EFI_INVALID_PARAMETER;\r
   }\r
 \r
-  if (HttpConfigData->AccessPoint.IPv4Node == NULL) {\r
-    return EFI_INVALID_PARAMETER;\r
+  if (HttpInstance->State < HTTP_STATE_HTTP_CONFIGED) {\r
+    return EFI_NOT_STARTED;\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
+  if (HttpInstance->LocalAddressIsIPv6) {\r
+    CopyMem (\r
+      HttpConfigData->AccessPoint.IPv6Node,\r
+      &HttpInstance->Ipv6Node,\r
+      sizeof (HttpInstance->Ipv6Node)\r
     );\r
+  } else {\r
+    CopyMem (\r
+      HttpConfigData->AccessPoint.IPv4Node,\r
+      &HttpInstance->IPv4Node,\r
+      sizeof (HttpInstance->IPv4Node)\r
+      );\r
+  }\r
 \r
   return EFI_SUCCESS;\r
 }\r
@@ -89,8 +105,8 @@ EfiHttpGetModeData (
   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
+  No other EFI HTTP function can be executed by this instance until the Configure()\r
+  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
@@ -98,6 +114,7 @@ EfiHttpGetModeData (
   @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->LocalAddressIsIPv6 is FALSE and\r
                                   HttpConfigData->IPv4Node is NULL.\r
                                   HttpConfigData->LocalAddressIsIPv6 is TRUE and\r
@@ -119,8 +136,14 @@ EfiHttpConfigure (
 {\r
   HTTP_PROTOCOL                 *HttpInstance;\r
   EFI_STATUS                    Status;\r
-\r
-  if (This == NULL) {\r
+  \r
+  //\r
+  // Check input parameters.\r
+  //\r
+  if (This == NULL ||\r
+      HttpConfigData == NULL ||\r
+     ((HttpConfigData->LocalAddressIsIPv6 && HttpConfigData->AccessPoint.IPv6Node == NULL) ||\r
+     (!HttpConfigData->LocalAddressIsIPv6 && HttpConfigData->AccessPoint.IPv4Node == NULL))) {\r
     return EFI_INVALID_PARAMETER;\r
   }\r
 \r
@@ -128,18 +151,7 @@ EfiHttpConfigure (
   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
     //\r
     // Now configure this HTTP instance.\r
     //\r
@@ -150,33 +162,39 @@ EfiHttpConfigure (
     HttpInstance->HttpVersion        = HttpConfigData->HttpVersion;\r
     HttpInstance->TimeOutMillisec    = HttpConfigData->TimeOutMillisec;\r
     HttpInstance->LocalAddressIsIPv6 = HttpConfigData->LocalAddressIsIPv6;\r
-\r
-    if (HttpConfigData->LocalAddressIsIPv6) {\r
-      return EFI_UNSUPPORTED;\r
+    \r
+    if (HttpConfigData->LocalAddressIsIPv6) { \r
+      CopyMem (\r
+        &HttpInstance->Ipv6Node,\r
+        HttpConfigData->AccessPoint.IPv6Node,\r
+        sizeof (HttpInstance->Ipv6Node)\r
+        );\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
+    //\r
+    // Creat Tcp child\r
+    //\r
+    Status = HttpInitProtocol (HttpInstance, HttpInstance->LocalAddressIsIPv6);\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+    \r
+    HttpInstance->State = HTTP_STATE_HTTP_CONFIGED;\r
+    return EFI_SUCCESS;\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
+    // Reset all the resources related to HttpInsance.\r
+    //\r
+    HttpCleanProtocol (HttpInstance);\r
+    HttpInstance->State = HTTP_STATE_UNCONFIGED;\r
+    return EFI_SUCCESS;\r
   }\r
 }\r
  \r
@@ -200,6 +218,7 @@ EfiHttpConfigure (
                                   implementation.\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 is NULL.\r
                                   Token->Message->Body is not NULL,\r
                                   Token->Message->BodyLength is non-zero, and\r
@@ -222,12 +241,13 @@ EfiHttpRequest (
   HTTP_PROTOCOL                 *HttpInstance;\r
   BOOLEAN                       Configure;\r
   BOOLEAN                       ReConfigure;\r
-  CHAR8                         *RequestStr;\r
+  CHAR8                         *RequestMsg;\r
   CHAR8                         *Url;\r
+  UINTN                         UrlLen;\r
   CHAR16                        *HostNameStr;\r
   HTTP_TOKEN_WRAP               *Wrap;\r
-  HTTP_TCP_TOKEN_WRAP           *TcpWrap;\r
   CHAR8                         *FileUrl;\r
+  UINTN                         RequestMsgSize;\r
   \r
   if ((This == NULL) || (Token == NULL)) {\r
     return EFI_INVALID_PARAMETER;\r
@@ -263,10 +283,6 @@ EfiHttpRequest (
     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
@@ -274,19 +290,24 @@ EfiHttpRequest (
     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
+  Url = HttpInstance->Url;\r
+  UrlLen = StrLen (Request->Url) + 1;\r
+  if (UrlLen > HTTP_URL_BUFFER_LEN) {\r
+    Url = AllocateZeroPool (UrlLen);\r
+    if (Url == NULL) {\r
+      return EFI_OUT_OF_RESOURCES;\r
+    }\r
+    FreePool (HttpInstance->Url);\r
+    HttpInstance->Url = Url;    \r
+  } \r
+\r
 \r
   UnicodeStrToAsciiStr (Request->Url, Url);\r
   UrlParser = NULL;\r
@@ -295,7 +316,7 @@ EfiHttpRequest (
     goto Error1;\r
   }\r
 \r
-  RequestStr = NULL;\r
+  RequestMsg = NULL;\r
   HostName   = NULL;\r
   Status     = HttpUrlGetHostName (Url, UrlParser, &HostName);\r
   if (EFI_ERROR (Status)) {\r
@@ -306,11 +327,15 @@ EfiHttpRequest (
   if (EFI_ERROR (Status)) {\r
     RemotePort = HTTP_DEFAULT_PORT;\r
   }\r
-\r
+  //\r
+  // If Configure is TRUE, it indicates the first time to call Request();\r
+  // If ReConfigure is TRUE, it indicates the request URL is not same\r
+  // with the previous call to Request();\r
+  //\r
   Configure   = TRUE;\r
   ReConfigure = TRUE;  \r
 \r
-  if (HttpInstance->RemoteHost == NULL && HttpInstance->RemotePort == 0) {\r
+  if (HttpInstance->RemoteHost == NULL) {\r
     //\r
     // Request() is called the first time. \r
     //\r
@@ -335,7 +360,7 @@ EfiHttpRequest (
         Wrap->HttpToken    = Token;\r
         Wrap->HttpInstance = HttpInstance;\r
 \r
-        Status = HttpCreateTcp4TxEvent (Wrap);\r
+        Status = HttpCreateTcpTxEvent (Wrap);\r
         if (EFI_ERROR (Status)) {\r
           goto Error1;\r
         }\r
@@ -347,7 +372,6 @@ EfiHttpRequest (
 \r
         Wrap->TcpWrap.Method = Request->Method;\r
 \r
-        FreePool (Url);\r
         FreePool (HostName);\r
         \r
         //\r
@@ -368,30 +392,42 @@ EfiHttpRequest (
       if (HttpInstance->RemoteHost != NULL) {\r
         FreePool (HttpInstance->RemoteHost);\r
         HttpInstance->RemoteHost = NULL;\r
+        HttpInstance->RemotePort = 0;\r
       }\r
     }\r
   } \r
 \r
   if (Configure) {\r
     //\r
-    // Parse Url for IPv4 address, if failed, perform DNS resolution.\r
+    // Parse Url for IPv4 or IPv6 address, if failed, perform DNS resolution.\r
     //\r
-    Status = NetLibAsciiStrToIp4 (HostName, &HttpInstance->RemoteAddr);\r
+    if (!HttpInstance->LocalAddressIsIPv6) {\r
+      Status = NetLibAsciiStrToIp4 (HostName, &HttpInstance->RemoteAddr);\r
+    } else {\r
+      Status = HttpUrlGetIp6 (Url, UrlParser, &HttpInstance->RemoteIpv6Addr);\r
+    }\r
+\r
     if (EFI_ERROR (Status)) {\r
-      HostNameStr = AllocateZeroPool ((AsciiStrLen (HostName) + 1) * sizeof (UINT16));\r
+      HostNameStr = AllocateZeroPool ((AsciiStrLen (HostName) + 1) * sizeof (CHAR16));\r
       if (HostNameStr == NULL) {\r
         Status = EFI_OUT_OF_RESOURCES;\r
         goto Error1;\r
       }\r
-\r
+      \r
       AsciiStrToUnicodeStr (HostName, HostNameStr);\r
-      Status = HttpDns4 (HttpInstance, HostNameStr, &HttpInstance->RemoteAddr);\r
+      if (!HttpInstance->LocalAddressIsIPv6) {\r
+        Status = HttpDns4 (HttpInstance, HostNameStr, &HttpInstance->RemoteAddr);\r
+      } else {\r
+        Status = HttpDns6 (HttpInstance, HostNameStr, &HttpInstance->RemoteIpv6Addr);\r
+      }\r
+      \r
       FreePool (HostNameStr);\r
       if (EFI_ERROR (Status)) {\r
         goto Error1;\r
       }\r
     }\r
 \r
+\r
     //\r
     // Save the RemotePort and RemoteHost.\r
     //\r
@@ -405,7 +441,11 @@ EfiHttpRequest (
     //\r
     // The request URL is different from previous calls to Request(), close existing TCP instance.\r
     //\r
-    ASSERT (HttpInstance->Tcp4 != NULL);\r
+    if (!HttpInstance->LocalAddressIsIPv6) {\r
+      ASSERT (HttpInstance->Tcp4 != NULL);\r
+    } else {\r
+      ASSERT (HttpInstance->Tcp6 != NULL);\r
+    }\r
     HttpCloseConnection (HttpInstance);\r
     EfiHttpCancel (This, NULL);\r
   }\r
@@ -423,31 +463,21 @@ EfiHttpRequest (
   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
+  Status = HttpInitTcp (HttpInstance, Wrap, Configure);\r
+  if (EFI_ERROR (Status)) {\r
+    goto Error2;\r
+  }  \r
+\r
+  if (!Configure) {\r
     //\r
     // For the new HTTP token, create TX TCP token events.    \r
     //\r
-    Status = HttpCreateTcp4TxEvent (Wrap);\r
+    Status = HttpCreateTcpTxEvent (Wrap);\r
     if (EFI_ERROR (Status)) {\r
       goto Error1;\r
     }\r
   }\r
-\r
+  \r
   //\r
   // Create request message.\r
   //\r
@@ -469,9 +499,10 @@ EfiHttpRequest (
       goto Error3;\r
     }\r
   }\r
-  RequestStr = HttpGenRequestString (HttpInstance, HttpMsg, FileUrl);\r
-  if (RequestStr == NULL) {\r
-    Status = EFI_OUT_OF_RESOURCES;\r
+\r
+  Status = HttpGenRequestMessage (HttpMsg, FileUrl, &RequestMsg, &RequestMsgSize);\r
+\r
+  if (EFI_ERROR (Status)) {\r
     goto Error3;\r
   }\r
 \r
@@ -480,48 +511,51 @@ EfiHttpRequest (
     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
+  Status = HttpTransmitTcp (\r
              HttpInstance,\r
              Wrap,\r
-             (UINT8*) RequestStr,\r
-             AsciiStrLen (RequestStr)\r
+             (UINT8*) RequestMsg,\r
+             RequestMsgSize\r
              );\r
   if (EFI_ERROR (Status)) {\r
     goto Error5;    \r
   }\r
 \r
+  DispatchDpc ();\r
+  \r
+  if (HostName != NULL) {\r
+    FreePool (HostName);\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
+  if (RequestMsg != NULL) {\r
+    FreePool (RequestMsg);\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
+  HttpCloseTcpConnCloseEvent (HttpInstance);\r
+  if (NULL != Wrap->TcpWrap.Tx4Token.CompletionToken.Event) {\r
+    gBS->CloseEvent (Wrap->TcpWrap.Tx4Token.CompletionToken.Event);\r
+    Wrap->TcpWrap.Tx4Token.CompletionToken.Event = NULL;\r
+  }\r
+  if (NULL != Wrap->TcpWrap.Tx6Token.CompletionToken.Event) {\r
+    gBS->CloseEvent (Wrap->TcpWrap.Tx6Token.CompletionToken.Event);\r
+    Wrap->TcpWrap.Tx6Token.CompletionToken.Event = NULL;\r
   }\r
 \r
 Error1:\r
-  if (Url != NULL) {\r
-    FreePool (Url);\r
-  }\r
+\r
   if (HostName != NULL) {\r
     FreePool (HostName);\r
   }\r
@@ -537,7 +571,7 @@ Error1:
 }\r
 \r
 /**\r
-  Cancel a TxToken or RxToken. \r
+  Cancel a user's Token. \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
@@ -558,6 +592,7 @@ HttpCancelTokens (
 \r
   EFI_HTTP_TOKEN            *Token;\r
   HTTP_TOKEN_WRAP           *Wrap;\r
+  HTTP_PROTOCOL             *HttpInstance;\r
 \r
   Token = (EFI_HTTP_TOKEN *) Context;\r
 \r
@@ -571,24 +606,41 @@ HttpCancelTokens (
 \r
   Wrap = (HTTP_TOKEN_WRAP *) Item->Value;\r
   ASSERT (Wrap != NULL);\r
+  HttpInstance = Wrap->HttpInstance;\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
+  if (!HttpInstance->LocalAddressIsIPv6) {\r
+    if (Wrap->TcpWrap.Tx4Token.CompletionToken.Event != NULL) {\r
+      gBS->CloseEvent (Wrap->TcpWrap.Tx4Token.CompletionToken.Event);\r
+    }\r
+    \r
+    if (Wrap->TcpWrap.Rx4Token.CompletionToken.Event != NULL) {\r
+      gBS->CloseEvent (Wrap->TcpWrap.Rx4Token.CompletionToken.Event);\r
+    }\r
+    \r
+    if (Wrap->TcpWrap.Rx4Token.Packet.RxData->FragmentTable[0].FragmentBuffer != NULL) {\r
+      FreePool (Wrap->TcpWrap.Rx4Token.Packet.RxData->FragmentTable[0].FragmentBuffer);\r
+    }\r
 \r
-  if (Wrap->TcpWrap.RxToken.CompletionToken.Event != NULL) {\r
-    gBS->CloseEvent (Wrap->TcpWrap.RxToken.CompletionToken.Event);\r
-  }\r
+  } else {\r
+    if (Wrap->TcpWrap.Tx6Token.CompletionToken.Event != NULL) {\r
+      gBS->CloseEvent (Wrap->TcpWrap.Tx6Token.CompletionToken.Event);\r
+    }\r
+\r
+    if (Wrap->TcpWrap.Rx6Token.CompletionToken.Event != NULL) {\r
+      gBS->CloseEvent (Wrap->TcpWrap.Rx6Token.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
+    if (Wrap->TcpWrap.Rx6Token.Packet.RxData->FragmentTable[0].FragmentBuffer != NULL) {\r
+      FreePool (Wrap->TcpWrap.Rx6Token.Packet.RxData->FragmentTable[0].FragmentBuffer);\r
+    }\r
   }\r
 \r
+\r
   FreePool (Wrap);\r
 \r
   //\r
@@ -675,8 +727,6 @@ HttpCancel (
   @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
@@ -730,6 +780,8 @@ HttpBodyParserCallback (
   )\r
 {\r
   HTTP_TOKEN_WRAP               *Wrap;\r
+  UINTN                         BodyLength;\r
+  CHAR8                         *Body;\r
 \r
   if (EventType != BodyParseEventOnComplete) {\r
     return EFI_SUCCESS;\r
@@ -740,10 +792,17 @@ HttpBodyParserCallback (
   }\r
 \r
   Wrap = (HTTP_TOKEN_WRAP *) Context;\r
-  Wrap->HttpInstance->NextMsg = Data;\r
+  Body = Wrap->HttpToken->Message->Body;\r
+  BodyLength = Wrap->HttpToken->Message->BodyLength;\r
+  if (Data < Body + BodyLength) {\r
+    Wrap->HttpInstance->NextMsg = Data;\r
+  } else {\r
+    Wrap->HttpInstance->NextMsg = NULL;\r
+  }\r
+  \r
 \r
   //\r
-  // Free TxToken since already received corrsponding HTTP response.\r
+  // Free Tx4Token or Tx6Token since already received corrsponding HTTP response.\r
   //\r
   FreePool (Wrap);\r
 \r
@@ -757,7 +816,8 @@ HttpBodyParserCallback (
 \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
+  @retval EFI_NOT_READY           Can't find a corresponding Tx4Token/Tx6Token or \r
+                                  the EFI_HTTP_UTILITIES_PROTOCOL is not available.\r
 \r
 **/\r
 EFI_STATUS\r
@@ -767,12 +827,9 @@ HttpResponseWorker (
 {\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
@@ -791,23 +848,21 @@ HttpResponseWorker (
   \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
+  HttpInstance->EndofHeader = NULL;\r
+  HttpInstance->HttpHeaders = NULL;\r
+  HttpMsg->Headers          = NULL;\r
+  HttpHeaders               = NULL;\r
+  SizeofHeaders             = 0;\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
+    Status = HttpCreateTcpRxEventForHeader (HttpInstance);\r
     if (EFI_ERROR (Status)) {\r
       goto Error;\r
     }\r
@@ -838,70 +893,45 @@ HttpResponseWorker (
       // 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
-    //\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
+    HttpInstance->EndofHeader = &EndofHeader;\r
+    HttpInstance->HttpHeaders = &HttpHeaders;\r
 \r
-      Status = RxToken->CompletionToken.Status;\r
-      if (EFI_ERROR (Status)) {\r
-        goto Error;\r
-      }\r
 \r
+    if (HttpInstance->TimeoutEvent == NULL) {\r
       //\r
-      // Append the response string.\r
+      // Create TimeoutEvent for response\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
+      Status = gBS->CreateEvent (\r
+                      EVT_TIMER,\r
+                      TPL_CALLBACK,\r
+                      NULL,\r
+                      NULL,\r
+                      &HttpInstance->TimeoutEvent\r
+                      );\r
+      if (EFI_ERROR (Status)) {\r
         goto Error;\r
       }\r
+    }\r
 \r
-      if (HttpHeaders != NULL) {\r
-        CopyMem (Buffer, HttpHeaders, SizeofHeaders);\r
-        FreePool (HttpHeaders);\r
-      }\r
+    //\r
+    // Start the timer, and wait Timeout seconds to receive the header packet.\r
+    //\r
+    Status = gBS->SetTimer (HttpInstance->TimeoutEvent, TimerRelative, HTTP_RESPONSE_TIMEOUT * TICKS_PER_SECOND);\r
+    if (EFI_ERROR (Status)) {\r
+      goto Error;\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
+    Status = HttpTcpReceiveHeader (HttpInstance, &SizeofHeaders, &BufferSize, HttpInstance->TimeoutEvent);\r
 \r
-      //\r
-      // Check whether we received end of HTTP headers.\r
-      //\r
-      EndofHeader = AsciiStrStr (HttpHeaders, HTTP_END_OF_HDR_STR); \r
-    };\r
+    gBS->SetTimer (HttpInstance->TimeoutEvent, TimerCancel, 0);\r
 \r
-    //\r
-    // Skip the CRLF after the HTTP headers.\r
-    //\r
-    EndofHeader = EndofHeader + AsciiStrLen (HTTP_END_OF_HDR_STR);\r
+    if (EFI_ERROR (Status)) {\r
+      goto Error;\r
+    }\r
+\r
+    ASSERT (HttpHeaders != NULL);\r
 \r
     //\r
     // Cache the part of body.\r
@@ -922,9 +952,6 @@ HttpResponseWorker (
       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
@@ -953,10 +980,25 @@ HttpResponseWorker (
     CopyMem (HeaderTmp, Tmp, SizeofHeaders);\r
     FreePool (HttpHeaders);\r
     HttpHeaders = HeaderTmp;\r
+\r
+    //\r
+    // Check whether the EFI_HTTP_UTILITIES_PROTOCOL is available.\r
+    //\r
+    if (mHttpUtilities == NULL) {\r
+      Status = EFI_NOT_READY;\r
+      goto Error;\r
+    }\r
+    \r
     //\r
     // Parse the HTTP header into array of key/value pairs.\r
     //\r
-    Status = HttpUtilitiesParse (HttpHeaders, SizeofHeaders, &HttpMsg->Headers, &HttpMsg->HeaderCount);\r
+    Status = mHttpUtilities->Parse (\r
+                               mHttpUtilities, \r
+                               HttpHeaders, \r
+                               SizeofHeaders, \r
+                               &HttpMsg->Headers, \r
+                               &HttpMsg->HeaderCount\r
+                               );\r
     if (EFI_ERROR (Status)) {\r
       goto Error;\r
     }\r
@@ -965,7 +1007,7 @@ HttpResponseWorker (
     HttpHeaders = NULL;\r
     \r
     HttpMsg->Data.Response->StatusCode = HttpMappingToStatusCode (StatusCode);\r
-\r
+    HttpInstance->StatusCode = StatusCode;\r
     //\r
     // Init message-body parser by header information.  \r
     //\r
@@ -977,7 +1019,7 @@ HttpResponseWorker (
     }\r
 \r
     //\r
-    // The first TxToken not transmitted yet, insert back and return error.\r
+    // The first Tx Token not transmitted yet, insert back and return error.\r
     //\r
     if (!ValueInItem->TcpWrap.IsTxDone) {\r
       goto Error2;\r
@@ -1085,19 +1127,38 @@ HttpResponseWorker (
 \r
   ASSERT (HttpInstance->MsgParser != NULL);\r
 \r
+  if (HttpInstance->TimeoutEvent == NULL) {\r
+    //\r
+    // Create TimeoutEvent for response\r
+    //\r
+    Status = gBS->CreateEvent (\r
+                    EVT_TIMER,\r
+                    TPL_CALLBACK,\r
+                    NULL,\r
+                    NULL,\r
+                    &HttpInstance->TimeoutEvent\r
+                    );\r
+    if (EFI_ERROR (Status)) {\r
+      goto Error;\r
+    }\r
+  }\r
+\r
+  //\r
+  // Start the timer, and wait Timeout seconds to receive the body packet.\r
+  //\r
+  Status = gBS->SetTimer (HttpInstance->TimeoutEvent, TimerRelative, HTTP_RESPONSE_TIMEOUT * TICKS_PER_SECOND);\r
+  if (EFI_ERROR (Status)) {\r
+    goto Error;\r
+  }\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
+  Status = HttpTcpReceiveBody (Wrap, HttpMsg, HttpInstance->TimeoutEvent);\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
+  gBS->SetTimer (HttpInstance->TimeoutEvent, TimerCancel, 0);\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
@@ -1108,8 +1169,15 @@ Exit:
   if (Item != NULL) {\r
     NetMapRemoveItem (&Wrap->HttpInstance->RxTokens, Item, NULL);\r
   }\r
-  Token->Status = Status;\r
+\r
+  if (HttpInstance->StatusCode >= HTTP_ERROR_OR_NOT_SUPPORT_STATUS_CODE) {\r
+    Token->Status = EFI_HTTP_ERROR;\r
+  } else {\r
+    Token->Status = Status;\r
+  }\r
+\r
   gBS->SignalEvent (Token->Event);\r
+  HttpCloseTcpRxEvent (Wrap);\r
   FreePool (Wrap);\r
   return Status;\r
 \r
@@ -1117,28 +1185,7 @@ Error2:
   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
+  HttpTcpTokenCleanup (Wrap);\r
   \r
   if (HttpHeaders != NULL) {\r
     FreePool (HttpHeaders);\r
@@ -1153,7 +1200,12 @@ Error:
     HttpInstance->CacheBody = NULL;\r
   }\r
 \r
-  Token->Status = Status;\r
+  if (HttpInstance->StatusCode >= HTTP_ERROR_OR_NOT_SUPPORT_STATUS_CODE) {\r
+    Token->Status = EFI_HTTP_ERROR;\r
+  } else {\r
+    Token->Status = Status;\r
+  }\r
+\r
   gBS->SignalEvent (Token->Event);\r
 \r
   return Status;  \r
@@ -1163,7 +1215,7 @@ Error:
 \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
+  Receive() function in the EFI TCP driver. When the HTTP response is received 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
@@ -1236,10 +1288,6 @@ EfiHttpResponse (
     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
@@ -1255,7 +1303,7 @@ EfiHttpResponse (
   Wrap->HttpInstance = HttpInstance;\r
   Wrap->HttpToken    = Token;\r
 \r
-  Status = HttpCreateTcp4RxEvent (Wrap);\r
+  Status = HttpCreateTcpRxEvent (Wrap);\r
   if (EFI_ERROR (Status)) {\r
     goto Error;\r
   }\r
@@ -1276,8 +1324,12 @@ EfiHttpResponse (
 \r
 Error:\r
   if (Wrap != NULL) {\r
-    if (Wrap->TcpWrap.RxToken.CompletionToken.Event != NULL) {\r
-      gBS->CloseEvent (Wrap->TcpWrap.RxToken.CompletionToken.Event);\r
+    if (Wrap->TcpWrap.Rx4Token.CompletionToken.Event != NULL) {\r
+      gBS->CloseEvent (Wrap->TcpWrap.Rx4Token.CompletionToken.Event);\r
+    }\r
+\r
+    if (Wrap->TcpWrap.Rx6Token.CompletionToken.Event != NULL) {\r
+      gBS->CloseEvent (Wrap->TcpWrap.Rx6Token.CompletionToken.Event);\r
     }\r
     FreePool (Wrap);\r
   }  \r
@@ -1311,6 +1363,7 @@ EfiHttpPoll (
   IN  EFI_HTTP_PROTOCOL         *This\r
   )\r
 {\r
+  EFI_STATUS                    Status;\r
   HTTP_PROTOCOL                 *HttpInstance;\r
 \r
   if (This == NULL) {\r
@@ -1320,13 +1373,23 @@ EfiHttpPoll (
   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
+  if (HttpInstance->State != HTTP_STATE_TCP_CONNECTED) {\r
     return EFI_NOT_STARTED;\r
   }\r
-\r
-  return HttpInstance->Tcp4->Poll (HttpInstance->Tcp4);\r
+  \r
+  if (HttpInstance->LocalAddressIsIPv6) {\r
+    if (HttpInstance->Tcp6 == NULL) {\r
+      return EFI_NOT_STARTED;\r
+    }\r
+    Status = HttpInstance->Tcp6->Poll (HttpInstance->Tcp6);\r
+  } else {\r
+    if (HttpInstance->Tcp4 == NULL) {\r
+      return EFI_NOT_STARTED;\r
+    }\r
+    Status = HttpInstance->Tcp4->Poll (HttpInstance->Tcp4);\r
+  }\r
+  \r
+  DispatchDpc ();\r
\r
+  return Status;\r
 }\r