]> git.proxmox.com Git - mirror_edk2.git/blobdiff - NetworkPkg/HttpDxe/HttpImpl.c
NetworkPkg/TlsAuthConfigDxe: Provide the UI to support TLS auth configuration
[mirror_edk2.git] / NetworkPkg / HttpDxe / HttpImpl.c
index a068cfb76b4af7b57fa741b2cdde767750f53738..6fcb0b7c6e27a0ddfa1fd64ac6bdb2cb16e24c8d 100644 (file)
@@ -2,7 +2,7 @@
   Implementation of EFI_HTTP_PROTOCOL protocol interfaces.\r
 \r
   Copyright (c) 2015 - 2016, Intel Corporation. All rights reserved.<BR>\r
   Implementation of EFI_HTTP_PROTOCOL protocol interfaces.\r
 \r
   Copyright (c) 2015 - 2016, Intel Corporation. All rights reserved.<BR>\r
-  (C) Copyright 2015 Hewlett Packard Enterprise Development LP<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
 \r
   This program and the accompanying materials\r
   are licensed and made available under the terms and conditions of the BSD License\r
@@ -114,7 +114,6 @@ 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
   @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
                                   HttpConfigData->LocalAddressIsIPv6 is FALSE and\r
                                   HttpConfigData->IPv4Node is NULL.\r
                                   HttpConfigData->LocalAddressIsIPv6 is TRUE and\r
@@ -141,9 +140,9 @@ EfiHttpConfigure (
   // Check input parameters.\r
   //\r
   if (This == NULL ||\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
+      (HttpConfigData != NULL && \r
+       ((HttpConfigData->LocalAddressIsIPv6 && HttpConfigData->AccessPoint.IPv6Node == NULL) ||\r
+        (!HttpConfigData->LocalAddressIsIPv6 && HttpConfigData->AccessPoint.IPv4Node == NULL)))) {\r
     return EFI_INVALID_PARAMETER;\r
   }\r
 \r
     return EFI_INVALID_PARAMETER;\r
   }\r
 \r
@@ -176,6 +175,7 @@ EfiHttpConfigure (
         sizeof (HttpInstance->IPv4Node)\r
         );\r
     }\r
         sizeof (HttpInstance->IPv4Node)\r
         );\r
     }\r
+    \r
     //\r
     // Creat Tcp child\r
     //\r
     //\r
     // Creat Tcp child\r
     //\r
@@ -236,161 +236,199 @@ EfiHttpRequest (
   VOID                          *UrlParser;\r
   EFI_STATUS                    Status;\r
   CHAR8                         *HostName;\r
   VOID                          *UrlParser;\r
   EFI_STATUS                    Status;\r
   CHAR8                         *HostName;\r
+  UINTN                         HostNameSize;\r
   UINT16                        RemotePort;\r
   HTTP_PROTOCOL                 *HttpInstance;\r
   BOOLEAN                       Configure;\r
   BOOLEAN                       ReConfigure;\r
   UINT16                        RemotePort;\r
   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
   CHAR8                         *FileUrl;\r
   CHAR8                         *Url;\r
   UINTN                         UrlLen;\r
   CHAR16                        *HostNameStr;\r
   HTTP_TOKEN_WRAP               *Wrap;\r
   CHAR8                         *FileUrl;\r
-  \r
+  UINTN                         RequestMsgSize;\r
+\r
+  //\r
+  // Initializations\r
+  //\r
+  Url = NULL;\r
+  UrlParser = NULL;\r
+  RemotePort = 0;\r
+  HostName = NULL;\r
+  RequestMsg = NULL;\r
+  HostNameStr = NULL;\r
+  Wrap = NULL;\r
+  FileUrl = NULL;\r
+\r
   if ((This == NULL) || (Token == NULL)) {\r
     return EFI_INVALID_PARAMETER;\r
   }\r
 \r
   HttpMsg = Token->Message;\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
+  if (HttpMsg == NULL) {\r
     return EFI_INVALID_PARAMETER;\r
   }\r
 \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
   Request = HttpMsg->Data.Request;\r
-  if ((Request == NULL) || (Request->Url == NULL)) {\r
-    return EFI_INVALID_PARAMETER;\r
-  }\r
 \r
   //\r
 \r
   //\r
-  // Only support GET and HEAD method in current implementation.\r
+  // Only support GET, HEAD, PUT and POST method in current implementation.\r
   //\r
   //\r
-  if ((Request->Method != HttpMethodGet) && (Request->Method != HttpMethodHead)) {\r
+  if ((Request != NULL) && (Request->Method != HttpMethodGet) &&\r
+      (Request->Method != HttpMethodHead) && (Request->Method != HttpMethodPut) && (Request->Method != HttpMethodPost)) {\r
     return EFI_UNSUPPORTED;\r
   }\r
 \r
   HttpInstance = HTTP_INSTANCE_FROM_PROTOCOL (This);\r
   ASSERT (HttpInstance != NULL);\r
 \r
     return EFI_UNSUPPORTED;\r
   }\r
 \r
   HttpInstance = HTTP_INSTANCE_FROM_PROTOCOL (This);\r
   ASSERT (HttpInstance != NULL);\r
 \r
+  //\r
+  // Capture the method into HttpInstance.\r
+  //\r
+  if (Request != NULL) {\r
+    HttpInstance->Method = Request->Method;\r
+  }\r
+\r
   if (HttpInstance->State < HTTP_STATE_HTTP_CONFIGED) {\r
     return EFI_NOT_STARTED;\r
   }\r
 \r
   if (HttpInstance->State < HTTP_STATE_HTTP_CONFIGED) {\r
     return EFI_NOT_STARTED;\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
+  if (Request == NULL) {\r
+    //\r
+    // Request would be NULL only for PUT/POST operation (in the current implementation)\r
+    //\r
+    if ((HttpInstance->Method != HttpMethodPut) && (HttpInstance->Method != HttpMethodPost)) {\r
+      return EFI_INVALID_PARAMETER;\r
+    }\r
 \r
 \r
-  HostName    = NULL;\r
-  Wrap        = NULL;\r
-  HostNameStr = NULL;\r
+    //\r
+    // For PUT/POST, we need to have the TCP already configured. Bail out if it is not!\r
+    //\r
+    if (HttpInstance->State < HTTP_STATE_TCP_CONFIGED) {\r
+      return EFI_INVALID_PARAMETER;\r
+    }\r
 \r
 \r
-  //\r
-  // Parse the URI of the remote host.\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
+    // We need to have the Message Body for sending the HTTP message across in these cases.\r
+    //\r
+    if (HttpMsg->Body == NULL || HttpMsg->BodyLength == 0) {\r
+      return EFI_INVALID_PARAMETER;\r
     }\r
     }\r
-    FreePool (HttpInstance->Url);\r
-    HttpInstance->Url = Url;    \r
-  } \r
 \r
 \r
+    //\r
+    // Use existing TCP instance to transmit the packet.\r
+    //\r
+    Configure   = FALSE;\r
+    ReConfigure = FALSE;\r
+  } else {\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
 \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
+    // Parse the URI of the remote host.\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
-  RequestStr = NULL;\r
-  HostName   = NULL;\r
-  Status     = HttpUrlGetHostName (Url, UrlParser, &HostName);\r
-  if (EFI_ERROR (Status)) {\r
-    goto Error1;\r
-  }\r
 \r
 \r
-  Status = HttpUrlGetPort (Url, UrlParser, &RemotePort);\r
-  if (EFI_ERROR (Status)) {\r
-    RemotePort = HTTP_DEFAULT_PORT;\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
+    UnicodeStrToAsciiStrS (Request->Url, Url, UrlLen);\r
+    UrlParser = NULL;\r
+    Status = HttpParseUrl (Url, (UINT32) AsciiStrLen (Url), FALSE, &UrlParser);\r
+    if (EFI_ERROR (Status)) {\r
+      goto Error1;\r
+    }\r
 \r
 \r
-  if (HttpInstance->RemoteHost == 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
     //\r
-    // Request() is called the first time. \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
     //\r
-    ReConfigure = FALSE;\r
-  } else {\r
-    if ((HttpInstance->RemotePort == RemotePort) &&\r
-        (AsciiStrCmp (HttpInstance->RemoteHost, HostName) == 0)) {\r
+    Configure   = TRUE;\r
+    ReConfigure = TRUE;\r
+\r
+    if (HttpInstance->RemoteHost == NULL) {\r
       //\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
+      // Request() is called the first time.\r
       //\r
       //\r
-      if (EFI_ERROR (NetMapIterate (&HttpInstance->TxTokens, HttpTcpNotReady, NULL))) {\r
+      ReConfigure = FALSE;\r
+    } else {\r
+      if ((HttpInstance->RemotePort == RemotePort) &&\r
+        (AsciiStrCmp (HttpInstance->RemoteHost, HostName) == 0)) {\r
         //\r
         //\r
-        // Wrap the HTTP token in HTTP_TOKEN_WRAP\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
         //\r
-        Wrap = AllocateZeroPool (sizeof (HTTP_TOKEN_WRAP));\r
-        if (Wrap == NULL) {\r
-          Status = EFI_OUT_OF_RESOURCES;\r
-          goto Error1;\r
-        }\r
 \r
 \r
-        Wrap->HttpToken    = Token;\r
-        Wrap->HttpInstance = HttpInstance;\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
 \r
-        Status = HttpCreateTcpTxEvent (Wrap);\r
-        if (EFI_ERROR (Status)) {\r
-          goto Error1;\r
-        }\r
+          Wrap->HttpToken    = Token;\r
+          Wrap->HttpInstance = HttpInstance;\r
 \r
 \r
-        Status = NetMapInsertTail (&HttpInstance->TxTokens, Token, Wrap);\r
-        if (EFI_ERROR (Status)) {\r
-          goto Error1;\r
-        }\r
+          Status = HttpCreateTcpTxEvent (Wrap);\r
+          if (EFI_ERROR (Status)) {\r
+            goto Error1;\r
+          }\r
 \r
 \r
-        Wrap->TcpWrap.Method = Request->Method;\r
+          Status = NetMapInsertTail (&HttpInstance->TxTokens, Token, Wrap);\r
+          if (EFI_ERROR (Status)) {\r
+            goto Error1;\r
+          }\r
 \r
 \r
-        FreePool (HostName);\r
-        \r
-        //\r
-        // Queue the HTTP token and return.\r
-        //\r
-        return EFI_SUCCESS;\r
+          Wrap->TcpWrap.Method = Request->Method;\r
+\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
       } else {\r
         //\r
-        // Use existing TCP instance to transmit the packet.\r
+        // Need close existing TCP instance and create a new TCP instance for data transmit.\r
         //\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
-        HttpInstance->RemotePort = 0;\r
+        if (HttpInstance->RemoteHost != NULL) {\r
+          FreePool (HttpInstance->RemoteHost);\r
+          HttpInstance->RemoteHost = NULL;\r
+          HttpInstance->RemotePort = 0;\r
+        }\r
       }\r
     }\r
   } \r
       }\r
     }\r
   } \r
@@ -406,13 +444,14 @@ EfiHttpRequest (
     }\r
 \r
     if (EFI_ERROR (Status)) {\r
     }\r
 \r
     if (EFI_ERROR (Status)) {\r
-      HostNameStr = AllocateZeroPool ((AsciiStrLen (HostName) + 1) * sizeof (CHAR16));\r
+      HostNameSize = AsciiStrSize (HostName);\r
+      HostNameStr = AllocateZeroPool (HostNameSize * sizeof (CHAR16));\r
       if (HostNameStr == NULL) {\r
         Status = EFI_OUT_OF_RESOURCES;\r
         goto Error1;\r
       }\r
       \r
       if (HostNameStr == NULL) {\r
         Status = EFI_OUT_OF_RESOURCES;\r
         goto Error1;\r
       }\r
       \r
-      AsciiStrToUnicodeStr (HostName, HostNameStr);\r
+      AsciiStrToUnicodeStrS (HostName, HostNameStr, HostNameSize);\r
       if (!HttpInstance->LocalAddressIsIPv6) {\r
         Status = HttpDns4 (HttpInstance, HostNameStr, &HttpInstance->RemoteAddr);\r
       } else {\r
       if (!HttpInstance->LocalAddressIsIPv6) {\r
         Status = HttpDns4 (HttpInstance, HostNameStr, &HttpInstance->RemoteAddr);\r
       } else {\r
@@ -425,7 +464,6 @@ EfiHttpRequest (
       }\r
     }\r
 \r
       }\r
     }\r
 \r
-\r
     //\r
     // Save the RemotePort and RemoteHost.\r
     //\r
     //\r
     // Save the RemotePort and RemoteHost.\r
     //\r
@@ -459,7 +497,9 @@ EfiHttpRequest (
 \r
   Wrap->HttpToken      = Token;\r
   Wrap->HttpInstance   = HttpInstance;\r
 \r
   Wrap->HttpToken      = Token;\r
   Wrap->HttpInstance   = HttpInstance;\r
-  Wrap->TcpWrap.Method = Request->Method;\r
+  if (Request != NULL) {\r
+    Wrap->TcpWrap.Method = Request->Method;\r
+  }\r
 \r
   Status = HttpInitTcp (HttpInstance, Wrap, Configure);\r
   if (EFI_ERROR (Status)) {\r
 \r
   Status = HttpInitTcp (HttpInstance, Wrap, Configure);\r
   if (EFI_ERROR (Status)) {\r
@@ -480,7 +520,7 @@ EfiHttpRequest (
   // Create request message.\r
   //\r
   FileUrl = Url;\r
   // Create request message.\r
   //\r
   FileUrl = Url;\r
-  if (*FileUrl != '/') {\r
+  if (Url != NULL && *FileUrl != '/') {\r
     //\r
     // Convert the absolute-URI to the absolute-path\r
     //\r
     //\r
     // Convert the absolute-URI to the absolute-path\r
     //\r
@@ -497,15 +537,24 @@ EfiHttpRequest (
       goto Error3;\r
     }\r
   }\r
       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
     goto Error3;\r
   }\r
 \r
-  Status = NetMapInsertTail (&HttpInstance->TxTokens, Token, Wrap);\r
-  if (EFI_ERROR (Status)) {\r
-    goto Error4;\r
+  //\r
+  // Every request we insert a TxToken and a response call would remove the TxToken.\r
+  // In cases of PUT/POST, after an initial request-response pair, we would do a\r
+  // continuous request without a response call. So, in such cases, where Request\r
+  // structure is NULL, we would not insert a TxToken.\r
+  //\r
+  if (Request != NULL) {\r
+    Status = NetMapInsertTail (&HttpInstance->TxTokens, Token, Wrap);\r
+    if (EFI_ERROR (Status)) {\r
+      goto Error4;\r
+    }\r
   }\r
 \r
   //\r
   }\r
 \r
   //\r
@@ -514,8 +563,8 @@ EfiHttpRequest (
   Status = HttpTransmitTcp (\r
              HttpInstance,\r
              Wrap,\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
   if (EFI_ERROR (Status)) {\r
     goto Error5;    \r
@@ -530,11 +579,17 @@ EfiHttpRequest (
   return EFI_SUCCESS;\r
 \r
 Error5:\r
   return EFI_SUCCESS;\r
 \r
 Error5:\r
+  //\r
+  // We would have inserted a TxToken only if Request structure is not NULL.\r
+  // Hence check before we do a remove in this error case.\r
+  //\r
+  if (Request != NULL) {\r
     NetMapRemoveTail (&HttpInstance->TxTokens, NULL);\r
     NetMapRemoveTail (&HttpInstance->TxTokens, NULL);\r
+  }\r
 \r
 Error4:\r
 \r
 Error4:\r
-  if (RequestStr != NULL) {\r
-    FreePool (RequestStr);\r
+  if (RequestMsg != NULL) {\r
+    FreePool (RequestMsg);\r
   }  \r
 \r
 Error3:\r
   }  \r
 \r
 Error3:\r
@@ -552,7 +607,6 @@ Error2:
   }\r
 \r
 Error1:\r
   }\r
 \r
 Error1:\r
-\r
   if (HostName != NULL) {\r
     FreePool (HostName);\r
   }\r
   if (HostName != NULL) {\r
     FreePool (HostName);\r
   }\r
@@ -586,7 +640,6 @@ HttpCancelTokens (
   IN VOID                   *Context\r
   )\r
 {\r
   IN VOID                   *Context\r
   )\r
 {\r
-\r
   EFI_HTTP_TOKEN            *Token;\r
   HTTP_TOKEN_WRAP           *Wrap;\r
   HTTP_PROTOCOL             *HttpInstance;\r
   EFI_HTTP_TOKEN            *Token;\r
   HTTP_TOKEN_WRAP           *Wrap;\r
   HTTP_PROTOCOL             *HttpInstance;\r
@@ -604,42 +657,33 @@ HttpCancelTokens (
   Wrap = (HTTP_TOKEN_WRAP *) Item->Value;\r
   ASSERT (Wrap != NULL);\r
   HttpInstance = Wrap->HttpInstance;\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 (!HttpInstance->LocalAddressIsIPv6) {\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
     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
+      // Cancle the Token before close its Event.\r
+      //\r
+      HttpInstance->Tcp4->Cancel (HttpInstance->Tcp4, &Wrap->TcpWrap.Rx4Token.CompletionToken);\r
 \r
 \r
-  } else {\r
-    if (Wrap->TcpWrap.Tx6Token.CompletionToken.Event != NULL) {\r
-      gBS->CloseEvent (Wrap->TcpWrap.Tx6Token.CompletionToken.Event);\r
+      //\r
+      // Dispatch the DPC queued by the NotifyFunction of the canceled token's events.\r
+      //\r
+      DispatchDpc ();\r
     }\r
     }\r
-\r
+  } else {\r
     if (Wrap->TcpWrap.Rx6Token.CompletionToken.Event != NULL) {\r
     if (Wrap->TcpWrap.Rx6Token.CompletionToken.Event != NULL) {\r
-      gBS->CloseEvent (Wrap->TcpWrap.Rx6Token.CompletionToken.Event);\r
-    }\r
+      //\r
+      // Cancle the Token before close its Event.\r
+      //\r
+      HttpInstance->Tcp6->Cancel (HttpInstance->Tcp6, &Wrap->TcpWrap.Rx6Token.CompletionToken);\r
 \r
 \r
-    if (Wrap->TcpWrap.Rx6Token.Packet.RxData->FragmentTable[0].FragmentBuffer != NULL) {\r
-      FreePool (Wrap->TcpWrap.Rx6Token.Packet.RxData->FragmentTable[0].FragmentBuffer);\r
+      //\r
+      // Dispatch the DPC queued by the NotifyFunction of the canceled token's events.\r
+      //\r
+      DispatchDpc ();\r
     }\r
   }\r
 \r
     }\r
   }\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 only one item is to be cancel, return EFI_ABORTED to stop\r
   // iterating the map any more.\r
@@ -854,6 +898,7 @@ HttpResponseWorker (
   SizeofHeaders             = 0;\r
   BufferSize                = 0;\r
   EndofHeader               = NULL;\r
   SizeofHeaders             = 0;\r
   BufferSize                = 0;\r
   EndofHeader               = NULL;\r
+  ValueInItem               = NULL;\r
  \r
   if (HttpMsg->Data.Response != NULL) {\r
     //\r
  \r
   if (HttpMsg->Data.Response != NULL) {\r
     //\r
@@ -895,7 +940,35 @@ HttpResponseWorker (
     HttpInstance->EndofHeader = &EndofHeader;\r
     HttpInstance->HttpHeaders = &HttpHeaders;\r
 \r
     HttpInstance->EndofHeader = &EndofHeader;\r
     HttpInstance->HttpHeaders = &HttpHeaders;\r
 \r
-    Status = HttpTcpReceiveHeader (HttpInstance, &SizeofHeaders, &BufferSize);\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 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
+    Status = HttpTcpReceiveHeader (HttpInstance, &SizeofHeaders, &BufferSize, HttpInstance->TimeoutEvent);\r
+\r
+    gBS->SetTimer (HttpInstance->TimeoutEvent, TimerCancel, 0);\r
+\r
     if (EFI_ERROR (Status)) {\r
       goto Error;\r
     }\r
     if (EFI_ERROR (Status)) {\r
       goto Error;\r
     }\r
@@ -926,6 +999,7 @@ HttpResponseWorker (
     //\r
     StatusCodeStr = HttpHeaders + AsciiStrLen (HTTP_VERSION_STR) + 1;\r
     if (StatusCodeStr == NULL) {\r
     //\r
     StatusCodeStr = HttpHeaders + AsciiStrLen (HTTP_VERSION_STR) + 1;\r
     if (StatusCodeStr == NULL) {\r
+      Status = EFI_NOT_READY;\r
       goto Error;\r
     }\r
 \r
       goto Error;\r
     }\r
 \r
@@ -936,100 +1010,127 @@ HttpResponseWorker (
     //\r
     Tmp = AsciiStrStr (HttpHeaders, HTTP_CRLF_STR);\r
     if (Tmp == NULL) {\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
-    //\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
       Status = EFI_NOT_READY;\r
       goto Error;\r
     }\r
-    \r
+\r
     //\r
     //\r
-    // Parse the HTTP header into array of key/value pairs.\r
+    // We could have response with just a HTTP message and no headers. For Example,\r
+    // "100 Continue". In such cases, we would not want to unnecessarily call a Parse\r
+    // method. A "\r\n" following Tmp string again would indicate an end. Compare and\r
+    // set SizeofHeaders to 0.\r
     //\r
     //\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
+    Tmp = Tmp + AsciiStrLen (HTTP_CRLF_STR);\r
+    if (CompareMem (Tmp, HTTP_CRLF_STR, AsciiStrLen (HTTP_CRLF_STR)) == 0) {\r
+      SizeofHeaders = 0;\r
+    } else {\r
+      SizeofHeaders = SizeofHeaders - (Tmp - HttpHeaders);\r
     }\r
 \r
     }\r
 \r
-    FreePool (HttpHeaders);\r
-    HttpHeaders = NULL;\r
-    \r
     HttpMsg->Data.Response->StatusCode = HttpMappingToStatusCode (StatusCode);\r
     HttpInstance->StatusCode = StatusCode;\r
     HttpMsg->Data.Response->StatusCode = HttpMappingToStatusCode (StatusCode);\r
     HttpInstance->StatusCode = StatusCode;\r
-    //\r
-    // Init message-body parser by header information.  \r
-    //\r
+\r
     Status = EFI_NOT_READY;\r
     ValueInItem = NULL;\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
 \r
     //\r
-    // The first Tx Token not transmitted yet, insert back and return error.\r
+    // In cases of PUT/POST, after an initial request-response pair, we would do a\r
+    // continuous request without a response call. So, we would not do an insert of\r
+    // TxToken. After we have sent the complete file, we will call a response to get\r
+    // a final response from server. In such a case, we would not have any TxTokens.\r
+    // Hence, check that case before doing a NetMapRemoveHead.\r
     //\r
     //\r
-    if (!ValueInItem->TcpWrap.IsTxDone) {\r
-      goto Error2;\r
-    }\r
+    if (!NetMapIsEmpty (&HttpInstance->TxTokens)) {\r
+      NetMapRemoveHead (&HttpInstance->TxTokens, (VOID**) &ValueInItem);\r
+      if (ValueInItem == NULL)  {\r
+        goto Error;\r
+      }\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
+      // The first Tx Token not transmitted yet, insert back and return error.\r
+      //\r
+      if (!ValueInItem->TcpWrap.IsTxDone) {\r
+        goto Error2;\r
+      }\r
     }\r
 \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 (SizeofHeaders != 0) {\r
+      HeaderTmp = AllocateZeroPool (SizeofHeaders);\r
+      if (HeaderTmp == NULL) {\r
+        Status = EFI_OUT_OF_RESOURCES;\r
+        goto Error2;\r
+      }\r
+\r
+      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 Error2;\r
+      }\r
+\r
+      //\r
+      // Parse the HTTP header into array of key/value pairs.\r
+      //\r
+      Status = mHttpUtilities->Parse (\r
+                                 mHttpUtilities,\r
+                                 HttpHeaders,\r
+                                 SizeofHeaders,\r
+                                 &HttpMsg->Headers,\r
+                                 &HttpMsg->HeaderCount\r
+                                 );\r
       if (EFI_ERROR (Status)) {\r
         goto Error2;\r
       }\r
 \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
+      FreePool (HttpHeaders);\r
+      HttpHeaders = NULL;\r
+\r
+\r
+      //\r
+      // Init message-body parser by header information.\r
+      //\r
+      Status = HttpInitMsgParser (\r
+                 HttpInstance->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
 \r
       }\r
     }\r
 \r
-    if ((HttpMsg->Body == NULL) || (HttpMsg->BodyLength == 0)) {    \r
+    if ((HttpMsg->Body == NULL) || (HttpMsg->BodyLength == 0)) {\r
       Status = EFI_SUCCESS;\r
       goto Exit;\r
     }\r
       Status = EFI_SUCCESS;\r
       goto Exit;\r
     }\r
-  }  \r
+  }\r
 \r
   //\r
   // Receive the response body.\r
 \r
   //\r
   // Receive the response body.\r
@@ -1101,7 +1202,7 @@ HttpResponseWorker (
   //\r
   Status = HttpTcpReceiveBody (Wrap, HttpMsg);\r
   if (EFI_ERROR (Status)) {\r
   //\r
   Status = HttpTcpReceiveBody (Wrap, HttpMsg);\r
   if (EFI_ERROR (Status)) {\r
-    goto Error;\r
+    goto Error2;\r
   }\r
 \r
   return Status;\r
   }\r
 \r
   return Status;\r
@@ -1124,9 +1225,16 @@ Exit:
   return Status;\r
 \r
 Error2:\r
   return Status;\r
 \r
 Error2:\r
-  NetMapInsertHead (&HttpInstance->TxTokens, ValueInItem->HttpToken, ValueInItem);\r
+  if (ValueInItem != NULL) {\r
+    NetMapInsertHead (&HttpInstance->TxTokens, ValueInItem->HttpToken, ValueInItem);\r
+  }\r
 \r
 Error:\r
 \r
 Error:\r
+  Item = NetMapFindKey (&Wrap->HttpInstance->RxTokens, Wrap->HttpToken);\r
+  if (Item != NULL) {\r
+    NetMapRemoveItem (&Wrap->HttpInstance->RxTokens, Item, NULL);\r
+  }\r
+  \r
   HttpTcpTokenCleanup (Wrap);\r
   \r
   if (HttpHeaders != NULL) {\r
   HttpTcpTokenCleanup (Wrap);\r
   \r
   if (HttpHeaders != NULL) {\r