]> git.proxmox.com Git - mirror_edk2.git/blobdiff - NetworkPkg/HttpDxe/HttpProto.c
NetworkPkg/HttpDxe: HTTPS support over IPv4 and IPv6
[mirror_edk2.git] / NetworkPkg / HttpDxe / HttpProto.c
index 486b20304f5274be71b35026c09c3f715438914b..36c61e2e997adba39f9b02de8fa4c16eac58646b 100644 (file)
@@ -1,7 +1,7 @@
 /** @file\r
   Miscellaneous routines for HttpDxe driver.\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 2016 Hewlett Packard Enterprise Development LP<BR>\r
 This program and the accompanying materials\r
 are licensed and made available under the terms and conditions of the BSD License\r
@@ -927,7 +927,8 @@ HttpCleanProtocol (
            HttpInstance->Handle\r
            );\r
   }\r
-  \r
+\r
+  TlsCloseTxRxEvent (HttpInstance); \r
 }\r
 \r
 /**\r
@@ -1185,7 +1186,8 @@ HttpConfigureTcp6 (
 }\r
 \r
 /**\r
-  Check existing TCP connection, if in error state, recover TCP4 connection.\r
+  Check existing TCP connection, if in error state, recover TCP4 connection. Then, \r
+  connect one TLS session if required.\r
 \r
   @param[in]  HttpInstance       The HTTP instance private data.\r
 \r
@@ -1226,11 +1228,58 @@ HttpConnectTcp4 (
     HttpCloseConnection(HttpInstance);\r
   }\r
 \r
-  return HttpCreateConnection (HttpInstance);\r
+  Status = HttpCreateConnection (HttpInstance);\r
+  if (EFI_ERROR(Status)){\r
+    DEBUG ((EFI_D_ERROR, "Tcp4 Connection fail - %x\n", Status));\r
+    return Status;\r
+  }\r
+  \r
+  //\r
+  // Tls session connection.\r
+  //\r
+  if (HttpInstance->UseHttps) {\r
+    if (HttpInstance->TimeoutEvent == NULL) {\r
+      //\r
+      // Create TimeoutEvent for TLS connection.\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
+        TlsCloseTxRxEvent (HttpInstance);\r
+        return Status;\r
+      }\r
+    }\r
+\r
+    //\r
+    // Start the timer, and wait Timeout seconds for connection.\r
+    //\r
+    Status = gBS->SetTimer (HttpInstance->TimeoutEvent, TimerRelative, HTTP_CONNECTION_TIMEOUT * TICKS_PER_SECOND);\r
+    if (EFI_ERROR (Status)) {\r
+      TlsCloseTxRxEvent (HttpInstance);\r
+      return Status;\r
+    }\r
+    \r
+    Status = TlsConnectSession (HttpInstance, HttpInstance->TimeoutEvent);\r
+\r
+    gBS->SetTimer (HttpInstance->TimeoutEvent, TimerCancel, 0);\r
+    \r
+    if (EFI_ERROR (Status)) {\r
+      TlsCloseTxRxEvent (HttpInstance);\r
+      return Status;\r
+    }\r
+  }\r
+\r
+  return Status;\r
 }\r
 \r
 /**\r
-  Check existing TCP connection, if in error state, recover TCP6 connection.\r
+  Check existing TCP connection, if in error state, recover TCP6 connection. Then, \r
+  connect one TLS session if required.\r
 \r
   @param[in]  HttpInstance       The HTTP instance private data.\r
 \r
@@ -1271,30 +1320,88 @@ HttpConnectTcp6 (
     HttpCloseConnection(HttpInstance);\r
   }\r
 \r
-  return HttpCreateConnection (HttpInstance);\r
+  Status = HttpCreateConnection (HttpInstance);\r
+  if (EFI_ERROR(Status)){\r
+    DEBUG ((EFI_D_ERROR, "Tcp6 Connection fail - %x\n", Status));\r
+    return Status;\r
+  }\r
+  \r
+  //\r
+  // Tls session connection.\r
+  //\r
+  if (HttpInstance->UseHttps) {\r
+    if (HttpInstance->TimeoutEvent == NULL) {\r
+      //\r
+      // Create TimeoutEvent for TLS connection.\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
+        TlsCloseTxRxEvent (HttpInstance);\r
+        return Status;\r
+      }\r
+    }\r
+\r
+    //\r
+    // Start the timer, and wait Timeout seconds for connection.\r
+    //\r
+    Status = gBS->SetTimer (HttpInstance->TimeoutEvent, TimerRelative, HTTP_CONNECTION_TIMEOUT * TICKS_PER_SECOND);\r
+    if (EFI_ERROR (Status)) {\r
+      TlsCloseTxRxEvent (HttpInstance);\r
+      return Status;\r
+    }\r
+    \r
+    Status = TlsConnectSession (HttpInstance, HttpInstance->TimeoutEvent);\r
+\r
+    gBS->SetTimer (HttpInstance->TimeoutEvent, TimerCancel, 0);\r
+    \r
+    if (EFI_ERROR (Status)) {\r
+      TlsCloseTxRxEvent (HttpInstance);\r
+      return Status;\r
+    }\r
+  }\r
+\r
+  return Status;\r
 }\r
 \r
 /**\r
-  Initialize TCP related data.\r
+  Initialize Http session.\r
 \r
   @param[in]  HttpInstance       The HTTP instance private data.\r
   @param[in]  Wrap               The HTTP token's wrap data.\r
-  @param[in]  Configure          The Flag indicates whether the first time to initialize Tcp.\r
+  @param[in]  Configure          The Flag indicates whether need to initialize session.\r
+  @param[in]  TlsConfigure       The Flag indicates whether it's the new Tls session.\r
 \r
-  @retval EFI_SUCCESS            The initialization of TCP instance is done. \r
+  @retval EFI_SUCCESS            The initialization of session is done. \r
   @retval Others                 Other error as indicated.\r
 \r
 **/\r
 EFI_STATUS\r
-HttpInitTcp (\r
+HttpInitSession (\r
   IN  HTTP_PROTOCOL    *HttpInstance,\r
   IN  HTTP_TOKEN_WRAP  *Wrap,\r
-  IN  BOOLEAN          Configure\r
+  IN  BOOLEAN          Configure,\r
+  IN  BOOLEAN          TlsConfigure\r
   )\r
 {\r
   EFI_STATUS           Status;\r
   ASSERT (HttpInstance != NULL);\r
 \r
+  //\r
+  // Configure Tls session.\r
+  //\r
+  if (TlsConfigure) {\r
+    Status = TlsConfigureSession (HttpInstance);\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+  }\r
+\r
   if (!HttpInstance->LocalAddressIsIPv6) {\r
     //\r
     // Configure TCP instance.\r
@@ -1338,7 +1445,7 @@ HttpInitTcp (
 }\r
 \r
 /**\r
-  Send the HTTP message through TCP4 or TCP6.\r
+  Send the HTTP or HTTPS message through TCP4 or TCP6.\r
 \r
   @param[in]  HttpInstance       The HTTP instance private data.\r
   @param[in]  Wrap               The HTTP token's wrap data.\r
@@ -1362,14 +1469,64 @@ HttpTransmitTcp (
   EFI_TCP4_PROTOCOL             *Tcp4;\r
   EFI_TCP6_IO_TOKEN             *Tx6Token;\r
   EFI_TCP6_PROTOCOL             *Tcp6;\r
+  UINT8                         *Buffer;  \r
+  UINTN                         BufferSize;\r
+  NET_FRAGMENT                  TempFragment;\r
+\r
+  Status                = EFI_SUCCESS;\r
+  Buffer                = NULL;\r
+\r
+  //\r
+  // Need to encrypt data.\r
+  //\r
+  if (HttpInstance->UseHttps) {\r
+    //\r
+    // Build BufferOut data\r
+    //\r
+    BufferSize = sizeof (TLS_RECORD_HEADER) + TxStringLen;\r
+    Buffer     = AllocateZeroPool (BufferSize);\r
+    if (Buffer == NULL) {\r
+      Status = EFI_OUT_OF_RESOURCES;\r
+      return Status;\r
+    }\r
+    ((TLS_RECORD_HEADER *) Buffer)->ContentType = TLS_CONTENT_TYPE_APPLICATION_DATA;\r
+    ((TLS_RECORD_HEADER *) Buffer)->Version.Major = HttpInstance->TlsConfigData.Version.Major;\r
+    ((TLS_RECORD_HEADER *) Buffer)->Version.Minor = HttpInstance->TlsConfigData.Version.Minor;\r
+    ((TLS_RECORD_HEADER *) Buffer)->Length = (UINT16) (TxStringLen);\r
+    CopyMem (Buffer + sizeof (TLS_RECORD_HEADER), TxString, TxStringLen);\r
+    \r
+    //\r
+    // Encrypt Packet.\r
+    //\r
+    Status = TlsProcessMessage (\r
+               HttpInstance, \r
+               Buffer, \r
+               BufferSize, \r
+               EfiTlsEncrypt, \r
+               &TempFragment\r
+               );\r
+    \r
+    FreePool (Buffer);\r
+\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+  }\r
   \r
-  if (!HttpInstance->LocalAddressIsIPv6) {     \r
+  if (!HttpInstance->LocalAddressIsIPv6) {\r
     Tcp4 = HttpInstance->Tcp4;\r
     Tx4Token = &Wrap->TcpWrap.Tx4Token;\r
+\r
+    if (HttpInstance->UseHttps) {\r
+      Tx4Token->Packet.TxData->DataLength = TempFragment.Len;\r
+      Tx4Token->Packet.TxData->FragmentTable[0].FragmentLength = TempFragment.Len;\r
+      Tx4Token->Packet.TxData->FragmentTable[0].FragmentBuffer = (VOID *) TempFragment.Bulk;\r
+    } else {\r
+      Tx4Token->Packet.TxData->DataLength = (UINT32) TxStringLen;\r
+      Tx4Token->Packet.TxData->FragmentTable[0].FragmentLength = (UINT32) TxStringLen;\r
+      Tx4Token->Packet.TxData->FragmentTable[0].FragmentBuffer = (VOID *) TxString;\r
+    }\r
     \r
-    Tx4Token->Packet.TxData->DataLength = (UINT32) TxStringLen;\r
-    Tx4Token->Packet.TxData->FragmentTable[0].FragmentLength = (UINT32) TxStringLen;\r
-    Tx4Token->Packet.TxData->FragmentTable[0].FragmentBuffer = (VOID *) TxString;\r
     Tx4Token->CompletionToken.Status = EFI_NOT_READY;  \r
     \r
     Wrap->TcpWrap.IsTxDone = FALSE;\r
@@ -1382,10 +1539,17 @@ HttpTransmitTcp (
   } else {\r
     Tcp6 = HttpInstance->Tcp6;\r
     Tx6Token = &Wrap->TcpWrap.Tx6Token;\r
-\r
-    Tx6Token->Packet.TxData->DataLength = (UINT32) TxStringLen;\r
-    Tx6Token->Packet.TxData->FragmentTable[0].FragmentLength = (UINT32) TxStringLen;\r
-    Tx6Token->Packet.TxData->FragmentTable[0].FragmentBuffer = (VOID *) TxString;\r
+    \r
+    if (HttpInstance->UseHttps) {\r
+      Tx6Token->Packet.TxData->DataLength = TempFragment.Len;\r
+      Tx6Token->Packet.TxData->FragmentTable[0].FragmentLength = TempFragment.Len;\r
+      Tx6Token->Packet.TxData->FragmentTable[0].FragmentBuffer = (VOID *) TempFragment.Bulk;\r
+    } else {\r
+      Tx6Token->Packet.TxData->DataLength = (UINT32) TxStringLen;\r
+      Tx6Token->Packet.TxData->FragmentTable[0].FragmentLength = (UINT32) TxStringLen;\r
+      Tx6Token->Packet.TxData->FragmentTable[0].FragmentBuffer = (VOID *) TxString;\r
+    }\r
+    \r
     Tx6Token->CompletionToken.Status = EFI_NOT_READY;\r
 \r
     Wrap->TcpWrap.IsTxDone = FALSE;\r
@@ -1396,7 +1560,6 @@ HttpTransmitTcp (
     }\r
   }\r
   \r
-\r
   return Status;\r
 }\r
 \r
@@ -1466,7 +1629,7 @@ HttpTcpNotReady (
 }\r
 \r
 /**\r
-  Transmit the HTTP mssage by processing the associated HTTP token.\r
+  Transmit the HTTP or HTTPS mssage by processing the associated HTTP token.\r
 \r
   @param[in]  Map                The container of Tx4Token or Tx6Token.\r
   @param[in]  Item               Current item to check against.\r
@@ -1489,6 +1652,7 @@ HttpTcpTransmit (
   EFI_STATUS                Status;\r
   CHAR8                     *RequestMsg;\r
   CHAR8                     *Url;\r
+  UINTN                     UrlSize;\r
   UINTN                     RequestMsgSize;\r
 \r
   ValueInItem = (HTTP_TOKEN_WRAP *) Item->Value;\r
@@ -1499,12 +1663,13 @@ HttpTcpTransmit (
   //\r
   // Parse the URI of the remote host.\r
   //\r
-  Url = AllocatePool (StrLen (ValueInItem->HttpToken->Message->Data.Request->Url) + 1);\r
+  UrlSize = StrLen (ValueInItem->HttpToken->Message->Data.Request->Url) + 1;\r
+  Url = AllocatePool (UrlSize);\r
   if (Url == NULL) {\r
     return EFI_OUT_OF_RESOURCES;\r
   }\r
 \r
-  UnicodeStrToAsciiStr (ValueInItem->HttpToken->Message->Data.Request->Url, Url);\r
+  UnicodeStrToAsciiStrS (ValueInItem->HttpToken->Message->Data.Request->Url, Url, UrlSize);\r
 \r
   //\r
   // Create request message.\r
@@ -1588,6 +1753,7 @@ HttpTcpReceiveHeader (
   CHAR8                         **EndofHeader;\r
   CHAR8                         **HttpHeaders;\r
   CHAR8                         *Buffer;\r
+  NET_FRAGMENT                  Fragment;\r
 \r
   ASSERT (HttpInstance != NULL);\r
 \r
@@ -1598,6 +1764,8 @@ HttpTcpReceiveHeader (
   Buffer      = NULL;\r
   Rx4Token    = NULL;\r
   Rx6Token    = NULL;\r
+  Fragment.Len  = 0;\r
+  Fragment.Bulk = NULL;\r
   \r
   if (HttpInstance->LocalAddressIsIPv6) {\r
     ASSERT (Tcp6 != NULL);\r
@@ -1605,146 +1773,211 @@ HttpTcpReceiveHeader (
     ASSERT (Tcp4 != NULL);\r
   }\r
 \r
-  if (!HttpInstance->LocalAddressIsIPv6) {\r
-    Rx4Token = &HttpInstance->Rx4Token;\r
-    Rx4Token->Packet.RxData->FragmentTable[0].FragmentBuffer = AllocateZeroPool (DEF_BUF_LEN);\r
-    if (Rx4Token->Packet.RxData->FragmentTable[0].FragmentBuffer == NULL) {\r
-      Status = EFI_OUT_OF_RESOURCES;\r
+  if (!HttpInstance->UseHttps) {\r
+    Status = HttpCreateTcpRxEventForHeader (HttpInstance);\r
+    if (EFI_ERROR (Status)) {\r
       return Status;\r
     }\r
+  }\r
+\r
+  if (!HttpInstance->LocalAddressIsIPv6) {\r
+    if (!HttpInstance->UseHttps) {\r
+      Rx4Token = &HttpInstance->Rx4Token;\r
+      Rx4Token->Packet.RxData->FragmentTable[0].FragmentBuffer = AllocateZeroPool (DEF_BUF_LEN);\r
+      if (Rx4Token->Packet.RxData->FragmentTable[0].FragmentBuffer == NULL) {\r
+        Status = EFI_OUT_OF_RESOURCES;\r
+        return Status;\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
-      Rx4Token->Packet.RxData->DataLength = DEF_BUF_LEN;\r
-      Rx4Token->Packet.RxData->FragmentTable[0].FragmentLength = DEF_BUF_LEN;\r
-      Status = Tcp4->Receive (Tcp4, Rx4Token);\r
-      if (EFI_ERROR (Status)) {\r
-        DEBUG ((EFI_D_ERROR, "Tcp4 receive failed: %r\n", Status));\r
-        return Status;\r
-      }\r
-      \r
-      while (!HttpInstance->IsRxDone && ((Timeout == NULL) || EFI_ERROR (gBS->CheckEvent (Timeout)))) {\r
-        Tcp4->Poll (Tcp4);\r
+    while (*EndofHeader == NULL) {\r
+      if (!HttpInstance->UseHttps) {\r
+        HttpInstance->IsRxDone = FALSE;\r
+        Rx4Token->Packet.RxData->DataLength = DEF_BUF_LEN;\r
+        Rx4Token->Packet.RxData->FragmentTable[0].FragmentLength = DEF_BUF_LEN;\r
+        Status = Tcp4->Receive (Tcp4, Rx4Token);\r
+        if (EFI_ERROR (Status)) {\r
+          DEBUG ((EFI_D_ERROR, "Tcp4 receive failed: %r\n", Status));\r
+          return Status;\r
+        }\r
+\r
+        while (!HttpInstance->IsRxDone && ((Timeout == NULL) || EFI_ERROR (gBS->CheckEvent (Timeout)))) {\r
+          Tcp4->Poll (Tcp4);\r
+        }\r
+\r
+        if (!HttpInstance->IsRxDone) {\r
+          //\r
+          // Cancle the Token before close its Event.\r
+          //\r
+          Tcp4->Cancel (HttpInstance->Tcp4, &Rx4Token->CompletionToken);\r
+          gBS->CloseEvent (Rx4Token->CompletionToken.Event);\r
+          Rx4Token->CompletionToken.Status = EFI_TIMEOUT;\r
+        }\r
+\r
+        Status = Rx4Token->CompletionToken.Status;\r
+        if (EFI_ERROR (Status)) {\r
+          return Status;\r
+        }\r
+        \r
+        Fragment.Len  = Rx4Token->Packet.RxData->FragmentTable[0].FragmentLength;\r
+        Fragment.Bulk = (UINT8 *) Rx4Token->Packet.RxData->FragmentTable[0].FragmentBuffer;\r
+      } else {\r
+        if (Fragment.Bulk != NULL) {\r
+          FreePool (Fragment.Bulk);\r
+          Fragment.Bulk = NULL;\r
+        }\r
+        \r
+        Status = HttpsReceive (HttpInstance, &Fragment, Timeout);\r
+        if (EFI_ERROR (Status)) {\r
+          DEBUG ((EFI_D_ERROR, "Tcp4 receive failed: %r\n", Status));\r
+          return Status;\r
+        }\r
       }\r
 \r
-      if (!HttpInstance->IsRxDone) {\r
-        //\r
-        // Cancle the Token before close its Event.\r
-        //\r
-        Tcp4->Cancel (HttpInstance->Tcp4, &Rx4Token->CompletionToken);\r
-        gBS->CloseEvent (Rx4Token->CompletionToken.Event);\r
-        Rx4Token->CompletionToken.Status = EFI_TIMEOUT;\r
-      }\r
-  \r
-      Status = Rx4Token->CompletionToken.Status;\r
-      if (EFI_ERROR (Status)) {\r
-        return Status;\r
-      }\r
-  \r
       //\r
       // Append the response string.\r
       //\r
-      *BufferSize = (*SizeofHeaders) + Rx4Token->Packet.RxData->FragmentTable[0].FragmentLength;\r
+      *BufferSize = *SizeofHeaders + Fragment.Len;\r
       Buffer      = AllocateZeroPool (*BufferSize);\r
       if (Buffer == NULL) {\r
         Status = EFI_OUT_OF_RESOURCES;\r
         return Status;\r
       }\r
-  \r
+\r
       if (*HttpHeaders != NULL) {\r
-        CopyMem (Buffer, *HttpHeaders, (*SizeofHeaders));\r
+        CopyMem (Buffer, *HttpHeaders, *SizeofHeaders);\r
         FreePool (*HttpHeaders);\r
       }\r
-  \r
+\r
       CopyMem (\r
-        Buffer + (*SizeofHeaders),\r
-        Rx4Token->Packet.RxData->FragmentTable[0].FragmentBuffer,\r
-        Rx4Token->Packet.RxData->FragmentTable[0].FragmentLength\r
+        Buffer + *SizeofHeaders,\r
+        Fragment.Bulk,\r
+        Fragment.Len\r
         );\r
-      *HttpHeaders    = Buffer;\r
-      *SizeofHeaders  = *BufferSize;\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
-    FreePool (Rx4Token->Packet.RxData->FragmentTable[0].FragmentBuffer);\r
-    Rx4Token->Packet.RxData->FragmentTable[0].FragmentBuffer = NULL;\r
+    };\r
     \r
+    //\r
+    // Free the buffer.\r
+    //\r
+    if (Rx4Token != NULL && Rx4Token->Packet.RxData != NULL && Rx4Token->Packet.RxData->FragmentTable[0].FragmentBuffer != NULL) {\r
+      FreePool (Rx4Token->Packet.RxData->FragmentTable[0].FragmentBuffer);\r
+      Rx4Token->Packet.RxData->FragmentTable[0].FragmentBuffer = NULL;\r
+      Fragment.Bulk = NULL;\r
+    }\r
+\r
+    if (Fragment.Bulk != NULL) {\r
+      FreePool (Fragment.Bulk);\r
+      Fragment.Bulk = NULL;\r
+    } \r
   } else {\r
-    Rx6Token = &HttpInstance->Rx6Token;\r
-    Rx6Token->Packet.RxData->FragmentTable[0].FragmentBuffer = AllocateZeroPool (DEF_BUF_LEN);\r
-    if (Rx6Token->Packet.RxData->FragmentTable[0].FragmentBuffer == NULL) {\r
-      Status = EFI_OUT_OF_RESOURCES;\r
-      return Status;\r
+    if (!HttpInstance->UseHttps) {\r
+      Rx6Token = &HttpInstance->Rx6Token;\r
+      Rx6Token->Packet.RxData->FragmentTable[0].FragmentBuffer = AllocateZeroPool (DEF_BUF_LEN);\r
+      if (Rx6Token->Packet.RxData->FragmentTable[0].FragmentBuffer == NULL) {\r
+        Status = EFI_OUT_OF_RESOURCES;\r
+        return Status;\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
-      Rx6Token->Packet.RxData->DataLength = DEF_BUF_LEN;\r
-      Rx6Token->Packet.RxData->FragmentTable[0].FragmentLength = DEF_BUF_LEN;\r
-      Status = Tcp6->Receive (Tcp6, Rx6Token);\r
-      if (EFI_ERROR (Status)) {\r
-        DEBUG ((EFI_D_ERROR, "Tcp6 receive failed: %r\n", Status));\r
-        return Status;\r
-      }\r
-      \r
-      while (!HttpInstance->IsRxDone && ((Timeout == NULL) || EFI_ERROR (gBS->CheckEvent (Timeout)))) {\r
-        Tcp6->Poll (Tcp6);\r
+    while (*EndofHeader == NULL) {\r
+      if (!HttpInstance->UseHttps) {\r
+        HttpInstance->IsRxDone = FALSE;\r
+        Rx6Token->Packet.RxData->DataLength = DEF_BUF_LEN;\r
+        Rx6Token->Packet.RxData->FragmentTable[0].FragmentLength = DEF_BUF_LEN;\r
+        Status = Tcp6->Receive (Tcp6, Rx6Token);\r
+        if (EFI_ERROR (Status)) {\r
+          DEBUG ((EFI_D_ERROR, "Tcp6 receive failed: %r\n", Status));\r
+          return Status;\r
+        }\r
+\r
+        while (!HttpInstance->IsRxDone && ((Timeout == NULL) || EFI_ERROR (gBS->CheckEvent (Timeout)))) {\r
+          Tcp6->Poll (Tcp6);\r
+        }\r
+\r
+        if (!HttpInstance->IsRxDone) {\r
+          //\r
+          // Cancle the Token before close its Event.\r
+          //\r
+          Tcp6->Cancel (HttpInstance->Tcp6, &Rx6Token->CompletionToken);\r
+          gBS->CloseEvent (Rx6Token->CompletionToken.Event);\r
+          Rx6Token->CompletionToken.Status = EFI_TIMEOUT;\r
+        }\r
+\r
+        Status = Rx6Token->CompletionToken.Status;\r
+        if (EFI_ERROR (Status)) {\r
+          return Status;\r
+        }\r
+        \r
+        Fragment.Len  = Rx6Token->Packet.RxData->FragmentTable[0].FragmentLength;\r
+        Fragment.Bulk = (UINT8 *) Rx6Token->Packet.RxData->FragmentTable[0].FragmentBuffer;\r
+      } else {\r
+        if (Fragment.Bulk != NULL) {\r
+          FreePool (Fragment.Bulk);\r
+          Fragment.Bulk = NULL;\r
+        }\r
+        \r
+        Status = HttpsReceive (HttpInstance, &Fragment, Timeout);\r
+        if (EFI_ERROR (Status)) {\r
+          DEBUG ((EFI_D_ERROR, "Tcp6 receive failed: %r\n", Status));\r
+          return Status;\r
+        }\r
       }\r
 \r
-      if (!HttpInstance->IsRxDone) {\r
-        //\r
-        // Cancle the Token before close its Event.\r
-        //\r
-        Tcp6->Cancel (HttpInstance->Tcp6, &Rx6Token->CompletionToken);\r
-        gBS->CloseEvent (Rx6Token->CompletionToken.Event);\r
-        Rx6Token->CompletionToken.Status = EFI_TIMEOUT;\r
-      }\r
-  \r
-      Status = Rx6Token->CompletionToken.Status;\r
-      if (EFI_ERROR (Status)) {\r
-        return Status;\r
-      }\r
-  \r
       //\r
       // Append the response string.\r
       //\r
-      *BufferSize = (*SizeofHeaders) + Rx6Token->Packet.RxData->FragmentTable[0].FragmentLength;\r
+      *BufferSize = *SizeofHeaders + Fragment.Len;\r
       Buffer      = AllocateZeroPool (*BufferSize);\r
       if (Buffer == NULL) {\r
         Status = EFI_OUT_OF_RESOURCES;\r
         return Status;\r
       }\r
-  \r
+\r
       if (*HttpHeaders != NULL) {\r
-        CopyMem (Buffer, *HttpHeaders, (*SizeofHeaders));\r
+        CopyMem (Buffer, *HttpHeaders, *SizeofHeaders);\r
         FreePool (*HttpHeaders);\r
       }\r
-  \r
+\r
       CopyMem (\r
-        Buffer + (*SizeofHeaders),\r
-        Rx6Token->Packet.RxData->FragmentTable[0].FragmentBuffer,\r
-        Rx6Token->Packet.RxData->FragmentTable[0].FragmentLength\r
+        Buffer + *SizeofHeaders,\r
+        Fragment.Bulk,\r
+        Fragment.Len\r
         );\r
-      *HttpHeaders     = Buffer;\r
-      *SizeofHeaders  = *BufferSize;\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
+      *EndofHeader = AsciiStrStr (*HttpHeaders, HTTP_END_OF_HDR_STR); \r
+    };\r
+\r
+    //\r
+    // Free the buffer.\r
+    //\r
+    if (Rx6Token != NULL && Rx6Token->Packet.RxData != NULL && Rx6Token->Packet.RxData->FragmentTable[0].FragmentBuffer != NULL) {\r
+      FreePool (Rx6Token->Packet.RxData->FragmentTable[0].FragmentBuffer);\r
+      Rx6Token->Packet.RxData->FragmentTable[0].FragmentBuffer = NULL;\r
+      Fragment.Bulk = NULL;\r
+    }\r
+\r
+    if (Fragment.Bulk != NULL) {\r
+      FreePool (Fragment.Bulk);\r
+      Fragment.Bulk = NULL;\r
     }\r
-    FreePool (Rx6Token->Packet.RxData->FragmentTable[0].FragmentBuffer);\r
-    Rx6Token->Packet.RxData->FragmentTable[0].FragmentBuffer = NULL;    \r
   }     \r
 \r
   //\r