Home | History | Annotate | Download | only in HttpDxe
      1 /** @file
      2   Miscellaneous routines for HttpDxe driver.
      3 
      4 Copyright (c) 2015 - 2016, Intel Corporation. All rights reserved.<BR>
      5 (C) Copyright 2016 Hewlett Packard Enterprise Development LP<BR>
      6 This program and the accompanying materials
      7 are licensed and made available under the terms and conditions of the BSD License
      8 which accompanies this distribution.  The full text of the license may be found at
      9 http://opensource.org/licenses/bsd-license.php
     10 
     11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     13 
     14 **/
     15 
     16 #include "HttpDriver.h"
     17 
     18 /**
     19   The common notify function used in HTTP driver.
     20 
     21   @param[in]  Event   The event signaled.
     22   @param[in]  Context The context.
     23 
     24 **/
     25 VOID
     26 EFIAPI
     27 HttpCommonNotify (
     28   IN EFI_EVENT  Event,
     29   IN VOID       *Context
     30   )
     31 {
     32   if ((Event == NULL) || (Context == NULL)) {
     33     return ;
     34   }
     35 
     36   *((BOOLEAN *) Context) = TRUE;
     37 }
     38 
     39 /**
     40   The notify function associated with Tx4Token for Tcp4->Transmit() or Tx6Token for Tcp6->Transmit().
     41 
     42   @param[in]  Context The context.
     43 
     44 **/
     45 VOID
     46 EFIAPI
     47 HttpTcpTransmitNotifyDpc (
     48   IN VOID       *Context
     49   )
     50 {
     51   HTTP_TOKEN_WRAP          *Wrap;
     52   HTTP_PROTOCOL            *HttpInstance;
     53 
     54   if (Context == NULL) {
     55     return ;
     56   }
     57 
     58   Wrap         = (HTTP_TOKEN_WRAP *) Context;
     59   HttpInstance = Wrap->HttpInstance;
     60 
     61   if (!HttpInstance->LocalAddressIsIPv6) {
     62       Wrap->HttpToken->Status = Wrap->TcpWrap.Tx4Token.CompletionToken.Status;
     63       gBS->SignalEvent (Wrap->HttpToken->Event);
     64 
     65       //
     66       // Free resources.
     67       //
     68       if (Wrap->TcpWrap.Tx4Token.Packet.TxData->FragmentTable[0].FragmentBuffer != NULL) {
     69         FreePool (Wrap->TcpWrap.Tx4Token.Packet.TxData->FragmentTable[0].FragmentBuffer);
     70       }
     71 
     72       if (Wrap->TcpWrap.Tx4Token.CompletionToken.Event != NULL) {
     73         gBS->CloseEvent (Wrap->TcpWrap.Tx4Token.CompletionToken.Event);
     74       }
     75 
     76   } else {
     77     Wrap->HttpToken->Status = Wrap->TcpWrap.Tx6Token.CompletionToken.Status;
     78     gBS->SignalEvent (Wrap->HttpToken->Event);
     79 
     80     //
     81     // Free resources.
     82     //
     83     if (Wrap->TcpWrap.Tx6Token.Packet.TxData->FragmentTable[0].FragmentBuffer != NULL) {
     84       FreePool (Wrap->TcpWrap.Tx6Token.Packet.TxData->FragmentTable[0].FragmentBuffer);
     85     }
     86 
     87     if (Wrap->TcpWrap.Tx6Token.CompletionToken.Event != NULL) {
     88       gBS->CloseEvent (Wrap->TcpWrap.Tx6Token.CompletionToken.Event);
     89     }
     90   }
     91 
     92 
     93   Wrap->TcpWrap.IsTxDone = TRUE;
     94 
     95   //
     96   // Check pending TxTokens and sent out.
     97   //
     98   NetMapIterate (&Wrap->HttpInstance->TxTokens, HttpTcpTransmit, NULL);
     99 
    100 }
    101 
    102 /**
    103   Request HttpTcpTransmitNotifyDpc as a DPC at TPL_CALLBACK.
    104 
    105   @param  Event                 The receive event delivered to TCP for transmit.
    106   @param  Context               Context for the callback.
    107 
    108 **/
    109 VOID
    110 EFIAPI
    111 HttpTcpTransmitNotify (
    112   IN EFI_EVENT                Event,
    113   IN VOID                     *Context
    114   )
    115 {
    116   //
    117   // Request HttpTcpTransmitNotifyDpc as a DPC at TPL_CALLBACK
    118   //
    119   QueueDpc (TPL_CALLBACK, HttpTcpTransmitNotifyDpc, Context);
    120 }
    121 
    122 /**
    123   The notify function associated with Rx4Token for Tcp4->Receive () or Rx6Token for Tcp6->Receive().
    124 
    125   @param[in]  Context The context.
    126 
    127 **/
    128 VOID
    129 EFIAPI
    130 HttpTcpReceiveNotifyDpc (
    131   IN VOID       *Context
    132   )
    133 {
    134   HTTP_TOKEN_WRAP          *Wrap;
    135   NET_MAP_ITEM             *Item;
    136   UINTN                    Length;
    137   EFI_STATUS               Status;
    138   HTTP_PROTOCOL            *HttpInstance;
    139   BOOLEAN                  UsingIpv6;
    140 
    141   if (Context == NULL) {
    142     return ;
    143   }
    144 
    145   Wrap = (HTTP_TOKEN_WRAP *) Context;
    146   HttpInstance = Wrap->HttpInstance;
    147   UsingIpv6    = HttpInstance->LocalAddressIsIPv6;
    148 
    149   if (UsingIpv6) {
    150     gBS->CloseEvent (Wrap->TcpWrap.Rx6Token.CompletionToken.Event);
    151     Wrap->TcpWrap.Rx6Token.CompletionToken.Event = NULL;
    152 
    153     if (EFI_ERROR (Wrap->TcpWrap.Rx6Token.CompletionToken.Status)) {
    154       DEBUG ((EFI_D_ERROR, "HttpTcpReceiveNotifyDpc: %r!\n", Wrap->TcpWrap.Rx6Token.CompletionToken.Status));
    155       Wrap->HttpToken->Status = Wrap->TcpWrap.Rx6Token.CompletionToken.Status;
    156       gBS->SignalEvent (Wrap->HttpToken->Event);
    157 
    158       Item = NetMapFindKey (&HttpInstance->RxTokens, Wrap->HttpToken);
    159       if (Item != NULL) {
    160         NetMapRemoveItem (&HttpInstance->RxTokens, Item, NULL);
    161       }
    162 
    163       FreePool (Wrap);
    164       Wrap = NULL;
    165 
    166       return ;
    167     }
    168 
    169   } else {
    170     gBS->CloseEvent (Wrap->TcpWrap.Rx4Token.CompletionToken.Event);
    171     Wrap->TcpWrap.Rx4Token.CompletionToken.Event = NULL;
    172 
    173     if (EFI_ERROR (Wrap->TcpWrap.Rx4Token.CompletionToken.Status)) {
    174       DEBUG ((EFI_D_ERROR, "HttpTcpReceiveNotifyDpc: %r!\n", Wrap->TcpWrap.Rx4Token.CompletionToken.Status));
    175       Wrap->HttpToken->Status = Wrap->TcpWrap.Rx4Token.CompletionToken.Status;
    176       gBS->SignalEvent (Wrap->HttpToken->Event);
    177 
    178       Item = NetMapFindKey (&HttpInstance->RxTokens, Wrap->HttpToken);
    179       if (Item != NULL) {
    180         NetMapRemoveItem (&HttpInstance->RxTokens, Item, NULL);
    181       }
    182 
    183       FreePool (Wrap);
    184       Wrap = NULL;
    185 
    186       return ;
    187     }
    188   }
    189 
    190   //
    191   // Check whether we receive a complete HTTP message.
    192   //
    193   ASSERT (HttpInstance->MsgParser != NULL);
    194   if (UsingIpv6) {
    195     Length = (UINTN) Wrap->TcpWrap.Rx6Data.FragmentTable[0].FragmentLength;
    196   } else {
    197     Length = (UINTN) Wrap->TcpWrap.Rx4Data.FragmentTable[0].FragmentLength;
    198   }
    199 
    200   Status = HttpParseMessageBody (
    201              HttpInstance->MsgParser,
    202              Length,
    203              Wrap->HttpToken->Message->Body
    204              );
    205   if (EFI_ERROR (Status)) {
    206     return ;
    207   }
    208 
    209   if (HttpIsMessageComplete (HttpInstance->MsgParser)) {
    210     //
    211     // Free the MsgParse since we already have a full HTTP message.
    212     //
    213     HttpFreeMsgParser (HttpInstance->MsgParser);
    214     HttpInstance->MsgParser = NULL;
    215   }
    216 
    217   Wrap->HttpToken->Message->BodyLength = Length;
    218   ASSERT (HttpInstance->CacheBody == NULL);
    219   //
    220   // We receive part of header of next HTTP msg.
    221   //
    222   if (HttpInstance->NextMsg != NULL) {
    223     Wrap->HttpToken->Message->BodyLength = HttpInstance->NextMsg -
    224                                            (CHAR8 *) Wrap->HttpToken->Message->Body;
    225     HttpInstance->CacheLen = Length - Wrap->HttpToken->Message->BodyLength;
    226     if (HttpInstance->CacheLen != 0) {
    227       HttpInstance->CacheBody = AllocateZeroPool (HttpInstance->CacheLen);
    228       if (HttpInstance->CacheBody == NULL) {
    229         return ;
    230       }
    231       CopyMem (HttpInstance->CacheBody, HttpInstance->NextMsg, HttpInstance->CacheLen);
    232       HttpInstance->NextMsg = HttpInstance->CacheBody;
    233       HttpInstance->CacheOffset = 0;
    234     }
    235   }
    236 
    237   Item = NetMapFindKey (&Wrap->HttpInstance->RxTokens, Wrap->HttpToken);
    238   if (Item != NULL) {
    239     NetMapRemoveItem (&Wrap->HttpInstance->RxTokens, Item, NULL);
    240   }
    241 
    242 
    243   Wrap->TcpWrap.IsRxDone = TRUE;
    244   if (UsingIpv6) {
    245     Wrap->HttpToken->Status = Wrap->TcpWrap.Rx6Token.CompletionToken.Status;
    246   } else {
    247     Wrap->HttpToken->Status = Wrap->TcpWrap.Rx4Token.CompletionToken.Status;
    248   }
    249 
    250 
    251   gBS->SignalEvent (Wrap->HttpToken->Event);
    252 
    253   //
    254   // Check pending RxTokens and receive the HTTP message.
    255   //
    256   NetMapIterate (&Wrap->HttpInstance->RxTokens, HttpTcpReceive, NULL);
    257 
    258   FreePool (Wrap);
    259   Wrap = NULL;
    260 }
    261 
    262 /**
    263   Request HttpTcpReceiveNotifyDpc as a DPC at TPL_CALLBACK.
    264 
    265   @param  Event                 The receive event delivered to TCP for receive.
    266   @param  Context               Context for the callback.
    267 
    268 **/
    269 VOID
    270 EFIAPI
    271 HttpTcpReceiveNotify (
    272   IN EFI_EVENT                Event,
    273   IN VOID                     *Context
    274   )
    275 {
    276   //
    277   // Request HttpTcpTransmitNotifyDpc as a DPC at TPL_CALLBACK
    278   //
    279   QueueDpc (TPL_CALLBACK, HttpTcpReceiveNotifyDpc, Context);
    280 }
    281 
    282 /**
    283   Create events for the TCP connection token and TCP close token.
    284 
    285   @param[in]  HttpInstance       Pointer to HTTP_PROTOCOL structure.
    286 
    287   @retval EFI_SUCCESS            The events are created successfully.
    288   @retval others                 Other error as indicated.
    289 
    290 **/
    291 EFI_STATUS
    292 HttpCreateTcpConnCloseEvent (
    293   IN  HTTP_PROTOCOL        *HttpInstance
    294   )
    295 {
    296   EFI_STATUS               Status;
    297 
    298   if (!HttpInstance->LocalAddressIsIPv6) {
    299     //
    300     // Create events for variuos asynchronous operations.
    301     //
    302     Status = gBS->CreateEvent (
    303                     EVT_NOTIFY_SIGNAL,
    304                     TPL_NOTIFY,
    305                     HttpCommonNotify,
    306                     &HttpInstance->IsTcp4ConnDone,
    307                     &HttpInstance->Tcp4ConnToken.CompletionToken.Event
    308                     );
    309     if (EFI_ERROR (Status)) {
    310       goto ERROR;
    311     }
    312 
    313     //
    314     // Initialize Tcp4CloseToken
    315     //
    316     Status = gBS->CreateEvent (
    317                     EVT_NOTIFY_SIGNAL,
    318                     TPL_NOTIFY,
    319                     HttpCommonNotify,
    320                     &HttpInstance->IsTcp4CloseDone,
    321                     &HttpInstance->Tcp4CloseToken.CompletionToken.Event
    322                     );
    323     if (EFI_ERROR (Status)) {
    324       goto ERROR;
    325     }
    326 
    327   } else {
    328     //
    329     // Create events for variuos asynchronous operations.
    330     //
    331     Status = gBS->CreateEvent (
    332                     EVT_NOTIFY_SIGNAL,
    333                     TPL_NOTIFY,
    334                     HttpCommonNotify,
    335                     &HttpInstance->IsTcp6ConnDone,
    336                     &HttpInstance->Tcp6ConnToken.CompletionToken.Event
    337                     );
    338     if (EFI_ERROR (Status)) {
    339       goto ERROR;
    340     }
    341 
    342     //
    343     // Initialize Tcp6CloseToken
    344     //
    345     Status = gBS->CreateEvent (
    346                     EVT_NOTIFY_SIGNAL,
    347                     TPL_NOTIFY,
    348                     HttpCommonNotify,
    349                     &HttpInstance->IsTcp6CloseDone,
    350                     &HttpInstance->Tcp6CloseToken.CompletionToken.Event
    351                     );
    352     if (EFI_ERROR (Status)) {
    353       goto ERROR;
    354     }
    355   }
    356 
    357   return EFI_SUCCESS;
    358 
    359 ERROR:
    360   //
    361   // Error handling
    362   //
    363   HttpCloseTcpConnCloseEvent (HttpInstance);
    364 
    365   return Status;
    366 }
    367 
    368 
    369 /**
    370   Close events in the TCP connection token and TCP close token.
    371 
    372   @param[in]  HttpInstance   Pointer to HTTP_PROTOCOL structure.
    373 
    374 **/
    375 VOID
    376 HttpCloseTcpConnCloseEvent (
    377   IN  HTTP_PROTOCOL        *HttpInstance
    378   )
    379 {
    380   ASSERT (HttpInstance != NULL);
    381 
    382   if (HttpInstance->LocalAddressIsIPv6) {
    383     if (NULL != HttpInstance->Tcp6ConnToken.CompletionToken.Event) {
    384       gBS->CloseEvent (HttpInstance->Tcp6ConnToken.CompletionToken.Event);
    385       HttpInstance->Tcp6ConnToken.CompletionToken.Event = NULL;
    386     }
    387 
    388     if (NULL != HttpInstance->Tcp6CloseToken.CompletionToken.Event) {
    389       gBS->CloseEvent(HttpInstance->Tcp6CloseToken.CompletionToken.Event);
    390       HttpInstance->Tcp6CloseToken.CompletionToken.Event = NULL;
    391     }
    392 
    393   } else {
    394     if (NULL != HttpInstance->Tcp4ConnToken.CompletionToken.Event) {
    395       gBS->CloseEvent (HttpInstance->Tcp4ConnToken.CompletionToken.Event);
    396       HttpInstance->Tcp4ConnToken.CompletionToken.Event = NULL;
    397     }
    398 
    399     if (NULL != HttpInstance->Tcp4CloseToken.CompletionToken.Event) {
    400       gBS->CloseEvent(HttpInstance->Tcp4CloseToken.CompletionToken.Event);
    401       HttpInstance->Tcp4CloseToken.CompletionToken.Event = NULL;
    402     }
    403   }
    404 
    405 }
    406 
    407 /**
    408   Create event for the TCP transmit token.
    409 
    410   @param[in]  Wrap               Point to HTTP token's wrap data.
    411 
    412   @retval EFI_SUCCESS            The events is created successfully.
    413   @retval others                 Other error as indicated.
    414 
    415 **/
    416 EFI_STATUS
    417 HttpCreateTcpTxEvent (
    418   IN  HTTP_TOKEN_WRAP      *Wrap
    419   )
    420 {
    421   EFI_STATUS               Status;
    422   HTTP_PROTOCOL            *HttpInstance;
    423   HTTP_TCP_TOKEN_WRAP      *TcpWrap;
    424 
    425   HttpInstance = Wrap->HttpInstance;
    426   TcpWrap      = &Wrap->TcpWrap;
    427 
    428   if (!HttpInstance->LocalAddressIsIPv6) {
    429     Status = gBS->CreateEvent (
    430                     EVT_NOTIFY_SIGNAL,
    431                     TPL_NOTIFY,
    432                     HttpTcpTransmitNotify,
    433                     Wrap,
    434                     &TcpWrap->Tx4Token.CompletionToken.Event
    435                     );
    436     if (EFI_ERROR (Status)) {
    437       return Status;
    438     }
    439 
    440     TcpWrap->Tx4Data.Push = TRUE;
    441     TcpWrap->Tx4Data.Urgent = FALSE;
    442     TcpWrap->Tx4Data.FragmentCount = 1;
    443     TcpWrap->Tx4Token.Packet.TxData = &Wrap->TcpWrap.Tx4Data;
    444     TcpWrap->Tx4Token.CompletionToken.Status = EFI_NOT_READY;
    445 
    446   } else {
    447     Status = gBS->CreateEvent (
    448                     EVT_NOTIFY_SIGNAL,
    449                     TPL_NOTIFY,
    450                     HttpTcpTransmitNotify,
    451                     Wrap,
    452                     &TcpWrap->Tx6Token.CompletionToken.Event
    453                     );
    454     if (EFI_ERROR (Status)) {
    455       return Status;
    456     }
    457 
    458     TcpWrap->Tx6Data.Push   = TRUE;
    459     TcpWrap->Tx6Data.Urgent = FALSE;
    460     TcpWrap->Tx6Data.FragmentCount  = 1;
    461     TcpWrap->Tx6Token.Packet.TxData = &Wrap->TcpWrap.Tx6Data;
    462     TcpWrap->Tx6Token.CompletionToken.Status =EFI_NOT_READY;
    463 
    464   }
    465 
    466   return EFI_SUCCESS;
    467 }
    468 
    469 /**
    470   Create event for the TCP receive token which is used to receive HTTP header.
    471 
    472   @param[in]  HttpInstance       Pointer to HTTP_PROTOCOL structure.
    473 
    474   @retval EFI_SUCCESS            The events is created successfully.
    475   @retval others                 Other error as indicated.
    476 
    477 **/
    478 EFI_STATUS
    479 HttpCreateTcpRxEventForHeader (
    480   IN  HTTP_PROTOCOL        *HttpInstance
    481   )
    482 {
    483   EFI_STATUS               Status;
    484 
    485   if (!HttpInstance->LocalAddressIsIPv6) {
    486     Status = gBS->CreateEvent (
    487                     EVT_NOTIFY_SIGNAL,
    488                     TPL_NOTIFY,
    489                     HttpCommonNotify,
    490                     &HttpInstance->IsRxDone,
    491                     &HttpInstance->Rx4Token.CompletionToken.Event
    492                     );
    493     if (EFI_ERROR (Status)) {
    494       return Status;
    495     }
    496 
    497     HttpInstance->Rx4Data.FragmentCount = 1;
    498     HttpInstance->Rx4Token.Packet.RxData = &HttpInstance->Rx4Data;
    499     HttpInstance->Rx4Token.CompletionToken.Status = EFI_NOT_READY;
    500 
    501   } else {
    502     Status = gBS->CreateEvent (
    503                     EVT_NOTIFY_SIGNAL,
    504                     TPL_NOTIFY,
    505                     HttpCommonNotify,
    506                     &HttpInstance->IsRxDone,
    507                     &HttpInstance->Rx6Token.CompletionToken.Event
    508                     );
    509     if (EFI_ERROR (Status)) {
    510       return Status;
    511     }
    512 
    513     HttpInstance->Rx6Data.FragmentCount  =1;
    514     HttpInstance->Rx6Token.Packet.RxData = &HttpInstance->Rx6Data;
    515     HttpInstance->Rx6Token.CompletionToken.Status = EFI_NOT_READY;
    516 
    517   }
    518 
    519 
    520   return EFI_SUCCESS;
    521 }
    522 
    523 /**
    524   Create event for the TCP receive token which is used to receive HTTP body.
    525 
    526   @param[in]  Wrap               Point to HTTP token's wrap data.
    527 
    528   @retval EFI_SUCCESS            The events is created successfully.
    529   @retval others                 Other error as indicated.
    530 
    531 **/
    532 EFI_STATUS
    533 HttpCreateTcpRxEvent (
    534   IN  HTTP_TOKEN_WRAP      *Wrap
    535   )
    536 {
    537   EFI_STATUS               Status;
    538   HTTP_PROTOCOL            *HttpInstance;
    539   HTTP_TCP_TOKEN_WRAP      *TcpWrap;
    540 
    541   HttpInstance = Wrap->HttpInstance;
    542   TcpWrap      = &Wrap->TcpWrap;
    543   if (!HttpInstance->LocalAddressIsIPv6) {
    544     Status = gBS->CreateEvent (
    545                     EVT_NOTIFY_SIGNAL,
    546                     TPL_NOTIFY,
    547                     HttpTcpReceiveNotify,
    548                     Wrap,
    549                     &TcpWrap->Rx4Token.CompletionToken.Event
    550                     );
    551     if (EFI_ERROR (Status)) {
    552       return Status;
    553     }
    554 
    555     TcpWrap->Rx4Data.FragmentCount = 1;
    556     TcpWrap->Rx4Token.Packet.RxData = &Wrap->TcpWrap.Rx4Data;
    557     TcpWrap->Rx4Token.CompletionToken.Status = EFI_NOT_READY;
    558 
    559   } else {
    560     Status = gBS->CreateEvent (
    561                     EVT_NOTIFY_SIGNAL,
    562                     TPL_NOTIFY,
    563                     HttpTcpReceiveNotify,
    564                     Wrap,
    565                     &TcpWrap->Rx6Token.CompletionToken.Event
    566                     );
    567     if (EFI_ERROR (Status)) {
    568       return Status;
    569     }
    570 
    571     TcpWrap->Rx6Data.FragmentCount = 1;
    572     TcpWrap->Rx6Token.Packet.RxData = &Wrap->TcpWrap.Rx6Data;
    573     TcpWrap->Rx6Token.CompletionToken.Status = EFI_NOT_READY;
    574   }
    575 
    576   return EFI_SUCCESS;
    577 }
    578 
    579 /**
    580   Close Events for Tcp Receive Tokens for HTTP body and HTTP header.
    581 
    582   @param[in]  Wrap               Pointer to HTTP token's wrap data.
    583 
    584 **/
    585 VOID
    586 HttpCloseTcpRxEvent (
    587   IN  HTTP_TOKEN_WRAP      *Wrap
    588   )
    589 {
    590   HTTP_PROTOCOL            *HttpInstance;
    591 
    592   ASSERT (Wrap != NULL);
    593   HttpInstance   = Wrap->HttpInstance;
    594 
    595   if (HttpInstance->LocalAddressIsIPv6) {
    596     if (Wrap->TcpWrap.Rx6Token.CompletionToken.Event != NULL) {
    597       gBS->CloseEvent (Wrap->TcpWrap.Rx6Token.CompletionToken.Event);
    598     }
    599 
    600     if (HttpInstance->Rx6Token.CompletionToken.Event != NULL) {
    601       gBS->CloseEvent (HttpInstance->Rx6Token.CompletionToken.Event);
    602       HttpInstance->Rx6Token.CompletionToken.Event = NULL;
    603     }
    604   } else {
    605     if (Wrap->TcpWrap.Rx4Token.CompletionToken.Event != NULL) {
    606       gBS->CloseEvent (Wrap->TcpWrap.Rx4Token.CompletionToken.Event);
    607     }
    608 
    609     if (HttpInstance->Rx4Token.CompletionToken.Event != NULL) {
    610       gBS->CloseEvent (HttpInstance->Rx4Token.CompletionToken.Event);
    611       HttpInstance->Rx4Token.CompletionToken.Event = NULL;
    612     }
    613   }
    614 }
    615 
    616 /**
    617   Intiialize the HTTP_PROTOCOL structure to the unconfigured state.
    618 
    619   @param[in, out]  HttpInstance         Pointer to HTTP_PROTOCOL structure.
    620   @param[in]       IpVersion            Indicate us TCP4 protocol or TCP6 protocol.
    621 
    622   @retval EFI_SUCCESS       HTTP_PROTOCOL structure is initialized successfully.
    623   @retval Others            Other error as indicated.
    624 
    625 **/
    626 EFI_STATUS
    627 HttpInitProtocol (
    628   IN OUT HTTP_PROTOCOL           *HttpInstance,
    629   IN     BOOLEAN                 IpVersion
    630   )
    631 {
    632   EFI_STATUS                     Status;
    633   VOID                           *Interface;
    634   BOOLEAN                        UsingIpv6;
    635 
    636   ASSERT (HttpInstance != NULL);
    637   UsingIpv6 = IpVersion;
    638 
    639   if (!UsingIpv6) {
    640     //
    641     // Create TCP4 child.
    642     //
    643     Status = NetLibCreateServiceChild (
    644                HttpInstance->Service->ControllerHandle,
    645                HttpInstance->Service->ImageHandle,
    646                &gEfiTcp4ServiceBindingProtocolGuid,
    647                &HttpInstance->Tcp4ChildHandle
    648                );
    649 
    650     if (EFI_ERROR (Status)) {
    651       goto ON_ERROR;
    652     }
    653 
    654     Status = gBS->OpenProtocol (
    655                     HttpInstance->Tcp4ChildHandle,
    656                     &gEfiTcp4ProtocolGuid,
    657                     (VOID **) &Interface,
    658                     HttpInstance->Service->ImageHandle,
    659                     HttpInstance->Service->ControllerHandle,
    660                     EFI_OPEN_PROTOCOL_BY_DRIVER
    661                     );
    662 
    663     if (EFI_ERROR (Status)) {
    664       goto ON_ERROR;
    665     }
    666 
    667     Status = gBS->OpenProtocol (
    668                     HttpInstance->Tcp4ChildHandle,
    669                     &gEfiTcp4ProtocolGuid,
    670                     (VOID **) &HttpInstance->Tcp4,
    671                     HttpInstance->Service->ImageHandle,
    672                     HttpInstance->Handle,
    673                     EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
    674                     );
    675     if (EFI_ERROR(Status)) {
    676       goto ON_ERROR;
    677     }
    678 
    679     Status = gBS->OpenProtocol (
    680                     HttpInstance->Service->Tcp4ChildHandle,
    681                     &gEfiTcp4ProtocolGuid,
    682                     (VOID **) &Interface,
    683                     HttpInstance->Service->ImageHandle,
    684                     HttpInstance->Handle,
    685                     EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
    686                     );
    687     if (EFI_ERROR(Status)) {
    688       goto ON_ERROR;
    689     }
    690   } else {
    691     //
    692     // Create TCP6 Child.
    693     //
    694     Status = NetLibCreateServiceChild (
    695                HttpInstance->Service->ControllerHandle,
    696                HttpInstance->Service->ImageHandle,
    697                &gEfiTcp6ServiceBindingProtocolGuid,
    698                &HttpInstance->Tcp6ChildHandle
    699                );
    700 
    701     if (EFI_ERROR (Status)) {
    702       goto ON_ERROR;
    703     }
    704 
    705     Status = gBS->OpenProtocol (
    706                     HttpInstance->Tcp6ChildHandle,
    707                     &gEfiTcp6ProtocolGuid,
    708                     (VOID **) &Interface,
    709                     HttpInstance->Service->ImageHandle,
    710                     HttpInstance->Service->ControllerHandle,
    711                     EFI_OPEN_PROTOCOL_BY_DRIVER
    712                     );
    713 
    714     if (EFI_ERROR (Status)) {
    715       goto ON_ERROR;
    716     }
    717 
    718     Status = gBS->OpenProtocol (
    719                     HttpInstance->Tcp6ChildHandle,
    720                     &gEfiTcp6ProtocolGuid,
    721                     (VOID **) &HttpInstance->Tcp6,
    722                     HttpInstance->Service->ImageHandle,
    723                     HttpInstance->Handle,
    724                     EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
    725                     );
    726 
    727     if (EFI_ERROR(Status)) {
    728       goto ON_ERROR;
    729     }
    730 
    731     Status = gBS->OpenProtocol (
    732                     HttpInstance->Service->Tcp6ChildHandle,
    733                     &gEfiTcp6ProtocolGuid,
    734                     (VOID **) &Interface,
    735                     HttpInstance->Service->ImageHandle,
    736                     HttpInstance->Handle,
    737                     EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
    738                     );
    739 
    740     if (EFI_ERROR(Status)) {
    741       goto ON_ERROR;
    742     }
    743   }
    744 
    745   HttpInstance->Url = AllocateZeroPool (HTTP_URL_BUFFER_LEN);
    746   if (HttpInstance->Url == NULL) {
    747     Status = EFI_OUT_OF_RESOURCES;
    748     goto ON_ERROR;
    749   }
    750 
    751   return EFI_SUCCESS;
    752 
    753 ON_ERROR:
    754 
    755   if (HttpInstance->Tcp4ChildHandle != NULL) {
    756     gBS->CloseProtocol (
    757            HttpInstance->Tcp4ChildHandle,
    758            &gEfiTcp4ProtocolGuid,
    759            HttpInstance->Service->ImageHandle,
    760            HttpInstance->Service->ControllerHandle
    761            );
    762 
    763     gBS->CloseProtocol (
    764            HttpInstance->Tcp4ChildHandle,
    765            &gEfiTcp4ProtocolGuid,
    766            HttpInstance->Service->ImageHandle,
    767            HttpInstance->Handle
    768            );
    769 
    770     NetLibDestroyServiceChild (
    771       HttpInstance->Service->ControllerHandle,
    772       HttpInstance->Service->ImageHandle,
    773       &gEfiTcp4ServiceBindingProtocolGuid,
    774       HttpInstance->Tcp4ChildHandle
    775       );
    776   }
    777 
    778   if (HttpInstance->Service->Tcp4ChildHandle != NULL) {
    779     gBS->CloseProtocol (
    780            HttpInstance->Service->Tcp4ChildHandle,
    781            &gEfiTcp4ProtocolGuid,
    782            HttpInstance->Service->ImageHandle,
    783            HttpInstance->Handle
    784            );
    785   }
    786 
    787   if (HttpInstance->Tcp6ChildHandle != NULL) {
    788     gBS->CloseProtocol (
    789            HttpInstance->Tcp6ChildHandle,
    790            &gEfiTcp6ProtocolGuid,
    791            HttpInstance->Service->ImageHandle,
    792            HttpInstance->Service->ControllerHandle
    793            );
    794 
    795     gBS->CloseProtocol (
    796            HttpInstance->Tcp6ChildHandle,
    797            &gEfiTcp6ProtocolGuid,
    798            HttpInstance->Service->ImageHandle,
    799            HttpInstance->Handle
    800            );
    801 
    802     NetLibDestroyServiceChild (
    803       HttpInstance->Service->ControllerHandle,
    804       HttpInstance->Service->ImageHandle,
    805       &gEfiTcp6ServiceBindingProtocolGuid,
    806       HttpInstance->Tcp6ChildHandle
    807       );
    808   }
    809 
    810   if (HttpInstance->Service->Tcp6ChildHandle != NULL) {
    811     gBS->CloseProtocol (
    812            HttpInstance->Service->Tcp6ChildHandle,
    813            &gEfiTcp6ProtocolGuid,
    814            HttpInstance->Service->ImageHandle,
    815            HttpInstance->Handle
    816            );
    817   }
    818 
    819   return EFI_UNSUPPORTED;
    820 
    821 }
    822 
    823 /**
    824   Clean up the HTTP child, release all the resources used by it.
    825 
    826   @param[in]  HttpInstance       The HTTP child to clean up.
    827 
    828 **/
    829 VOID
    830 HttpCleanProtocol (
    831   IN  HTTP_PROTOCOL          *HttpInstance
    832   )
    833 {
    834   HttpCloseConnection (HttpInstance);
    835 
    836   HttpCloseTcpConnCloseEvent (HttpInstance);
    837 
    838   if (HttpInstance->TimeoutEvent != NULL) {
    839     gBS->CloseEvent (HttpInstance->TimeoutEvent);
    840     HttpInstance->TimeoutEvent = NULL;
    841   }
    842 
    843   if (HttpInstance->CacheBody != NULL) {
    844     FreePool (HttpInstance->CacheBody);
    845     HttpInstance->CacheBody = NULL;
    846     HttpInstance->NextMsg   = NULL;
    847   }
    848 
    849   if (HttpInstance->RemoteHost != NULL) {
    850     FreePool (HttpInstance->RemoteHost);
    851     HttpInstance->RemoteHost = NULL;
    852   }
    853 
    854   if (HttpInstance->MsgParser != NULL) {
    855     HttpFreeMsgParser (HttpInstance->MsgParser);
    856     HttpInstance->MsgParser = NULL;
    857   }
    858 
    859   if (HttpInstance->Url != NULL) {
    860     FreePool (HttpInstance->Url);
    861     HttpInstance->Url = NULL;
    862   }
    863 
    864   NetMapClean (&HttpInstance->TxTokens);
    865   NetMapClean (&HttpInstance->RxTokens);
    866 
    867   if (HttpInstance->Tcp4ChildHandle != NULL) {
    868     gBS->CloseProtocol (
    869            HttpInstance->Tcp4ChildHandle,
    870            &gEfiTcp4ProtocolGuid,
    871            HttpInstance->Service->ImageHandle,
    872            HttpInstance->Service->ControllerHandle
    873            );
    874 
    875     gBS->CloseProtocol (
    876            HttpInstance->Tcp4ChildHandle,
    877            &gEfiTcp4ProtocolGuid,
    878            HttpInstance->Service->ImageHandle,
    879            HttpInstance->Handle
    880            );
    881 
    882     NetLibDestroyServiceChild (
    883       HttpInstance->Service->ControllerHandle,
    884       HttpInstance->Service->ImageHandle,
    885       &gEfiTcp4ServiceBindingProtocolGuid,
    886       HttpInstance->Tcp4ChildHandle
    887       );
    888   }
    889 
    890   if (HttpInstance->Service->Tcp4ChildHandle != NULL) {
    891     gBS->CloseProtocol (
    892            HttpInstance->Service->Tcp4ChildHandle,
    893            &gEfiTcp4ProtocolGuid,
    894            HttpInstance->Service->ImageHandle,
    895            HttpInstance->Handle
    896            );
    897   }
    898 
    899   if (HttpInstance->Tcp6ChildHandle != NULL) {
    900     gBS->CloseProtocol (
    901            HttpInstance->Tcp6ChildHandle,
    902            &gEfiTcp6ProtocolGuid,
    903            HttpInstance->Service->ImageHandle,
    904            HttpInstance->Service->ControllerHandle
    905            );
    906 
    907     gBS->CloseProtocol (
    908            HttpInstance->Tcp6ChildHandle,
    909            &gEfiTcp6ProtocolGuid,
    910            HttpInstance->Service->ImageHandle,
    911            HttpInstance->Handle
    912            );
    913 
    914     NetLibDestroyServiceChild (
    915       HttpInstance->Service->ControllerHandle,
    916       HttpInstance->Service->ImageHandle,
    917       &gEfiTcp6ServiceBindingProtocolGuid,
    918       HttpInstance->Tcp6ChildHandle
    919       );
    920   }
    921 
    922   if (HttpInstance->Service->Tcp6ChildHandle != NULL) {
    923     gBS->CloseProtocol (
    924            HttpInstance->Service->Tcp6ChildHandle,
    925            &gEfiTcp6ProtocolGuid,
    926            HttpInstance->Service->ImageHandle,
    927            HttpInstance->Handle
    928            );
    929   }
    930 
    931   TlsCloseTxRxEvent (HttpInstance);
    932 }
    933 
    934 /**
    935   Establish TCP connection with HTTP server.
    936 
    937   @param[in]  HttpInstance       The HTTP instance private data.
    938 
    939   @retval EFI_SUCCESS            The TCP connection is established.
    940   @retval Others                 Other error as indicated.
    941 
    942 **/
    943 EFI_STATUS
    944 HttpCreateConnection (
    945   IN  HTTP_PROTOCOL        *HttpInstance
    946   )
    947 {
    948   EFI_STATUS                    Status;
    949 
    950   //
    951   // Connect to Http server
    952   //
    953   if (!HttpInstance->LocalAddressIsIPv6) {
    954     HttpInstance->IsTcp4ConnDone = FALSE;
    955     HttpInstance->Tcp4ConnToken.CompletionToken.Status = EFI_NOT_READY;
    956     Status = HttpInstance->Tcp4->Connect (HttpInstance->Tcp4, &HttpInstance->Tcp4ConnToken);
    957     if (EFI_ERROR (Status)) {
    958       DEBUG ((EFI_D_ERROR, "HttpCreateConnection: Tcp4->Connect() = %r\n", Status));
    959       return Status;
    960     }
    961 
    962     while (!HttpInstance->IsTcp4ConnDone) {
    963       HttpInstance->Tcp4->Poll (HttpInstance->Tcp4);
    964     }
    965 
    966     Status = HttpInstance->Tcp4ConnToken.CompletionToken.Status;
    967 
    968   } else {
    969     HttpInstance->IsTcp6ConnDone = FALSE;
    970     HttpInstance->Tcp6ConnToken.CompletionToken.Status = EFI_NOT_READY;
    971     Status = HttpInstance->Tcp6->Connect (HttpInstance->Tcp6, &HttpInstance->Tcp6ConnToken);
    972     if (EFI_ERROR (Status)) {
    973       DEBUG ((EFI_D_ERROR, "HttpCreateConnection: Tcp6->Connect() = %r\n", Status));
    974       return Status;
    975     }
    976 
    977     while(!HttpInstance->IsTcp6ConnDone) {
    978       HttpInstance->Tcp6->Poll (HttpInstance->Tcp6);
    979     }
    980 
    981     Status = HttpInstance->Tcp6ConnToken.CompletionToken.Status;
    982   }
    983 
    984   if (!EFI_ERROR (Status)) {
    985     HttpInstance->State = HTTP_STATE_TCP_CONNECTED;
    986   }
    987 
    988   return Status;
    989 }
    990 
    991 /**
    992   Close existing TCP connection.
    993 
    994   @param[in]  HttpInstance       The HTTP instance private data.
    995 
    996   @retval EFI_SUCCESS            The TCP connection is closed.
    997   @retval Others                 Other error as indicated.
    998 
    999 **/
   1000 EFI_STATUS
   1001 HttpCloseConnection (
   1002   IN  HTTP_PROTOCOL        *HttpInstance
   1003   )
   1004 {
   1005   EFI_STATUS                Status;
   1006 
   1007   if (HttpInstance->State == HTTP_STATE_TCP_CONNECTED) {
   1008 
   1009     if (HttpInstance->LocalAddressIsIPv6) {
   1010       HttpInstance->Tcp6CloseToken.AbortOnClose = TRUE;
   1011       HttpInstance->IsTcp6CloseDone             = FALSE;
   1012       Status = HttpInstance->Tcp6->Close (HttpInstance->Tcp6, &HttpInstance->Tcp6CloseToken);
   1013       if (EFI_ERROR (Status)) {
   1014         return Status;
   1015       }
   1016 
   1017       while (!HttpInstance->IsTcp6CloseDone) {
   1018         HttpInstance->Tcp6->Poll (HttpInstance->Tcp6);
   1019       }
   1020 
   1021     } else {
   1022       HttpInstance->Tcp4CloseToken.AbortOnClose = TRUE;
   1023       HttpInstance->IsTcp4CloseDone             = FALSE;
   1024       Status = HttpInstance->Tcp4->Close (HttpInstance->Tcp4, &HttpInstance->Tcp4CloseToken);
   1025       if (EFI_ERROR (Status)) {
   1026         return Status;
   1027       }
   1028 
   1029       while (!HttpInstance->IsTcp4CloseDone) {
   1030         HttpInstance->Tcp4->Poll (HttpInstance->Tcp4);
   1031       }
   1032     }
   1033 
   1034   }
   1035 
   1036   HttpInstance->State = HTTP_STATE_TCP_CLOSED;
   1037   return EFI_SUCCESS;
   1038 }
   1039 
   1040 /**
   1041   Configure TCP4 protocol child.
   1042 
   1043   @param[in]  HttpInstance       The HTTP instance private data.
   1044   @param[in]  Wrap               The HTTP token's wrap data.
   1045 
   1046   @retval EFI_SUCCESS            The TCP4 protocol child is configured.
   1047   @retval Others                 Other error as indicated.
   1048 
   1049 **/
   1050 EFI_STATUS
   1051 HttpConfigureTcp4 (
   1052   IN  HTTP_PROTOCOL        *HttpInstance,
   1053   IN  HTTP_TOKEN_WRAP      *Wrap
   1054   )
   1055 {
   1056   EFI_STATUS                 Status;
   1057   EFI_TCP4_CONFIG_DATA       *Tcp4CfgData;
   1058   EFI_TCP4_ACCESS_POINT      *Tcp4AP;
   1059   EFI_TCP4_OPTION            *Tcp4Option;
   1060 
   1061   ASSERT (HttpInstance != NULL);
   1062 
   1063 
   1064   Tcp4CfgData = &HttpInstance->Tcp4CfgData;
   1065   ZeroMem (Tcp4CfgData, sizeof (EFI_TCP4_CONFIG_DATA));
   1066 
   1067   Tcp4CfgData->TypeOfService = HTTP_TOS_DEAULT;
   1068   Tcp4CfgData->TimeToLive    = HTTP_TTL_DEAULT;
   1069   Tcp4CfgData->ControlOption = &HttpInstance->Tcp4Option;
   1070 
   1071   Tcp4AP = &Tcp4CfgData->AccessPoint;
   1072   Tcp4AP->UseDefaultAddress = HttpInstance->IPv4Node.UseDefaultAddress;
   1073   if (!Tcp4AP->UseDefaultAddress) {
   1074     IP4_COPY_ADDRESS (&Tcp4AP->StationAddress, &HttpInstance->IPv4Node.LocalAddress);
   1075     IP4_COPY_ADDRESS (&Tcp4AP->SubnetMask, &HttpInstance->IPv4Node.LocalSubnet);
   1076   }
   1077 
   1078   Tcp4AP->StationPort = HttpInstance->IPv4Node.LocalPort;
   1079   Tcp4AP->RemotePort  = HttpInstance->RemotePort;
   1080   Tcp4AP->ActiveFlag  = TRUE;
   1081   IP4_COPY_ADDRESS (&Tcp4AP->RemoteAddress, &HttpInstance->RemoteAddr);
   1082 
   1083   Tcp4Option = Tcp4CfgData->ControlOption;
   1084   Tcp4Option->ReceiveBufferSize      = HTTP_BUFFER_SIZE_DEAULT;
   1085   Tcp4Option->SendBufferSize         = HTTP_BUFFER_SIZE_DEAULT;
   1086   Tcp4Option->MaxSynBackLog          = HTTP_MAX_SYN_BACK_LOG;
   1087   Tcp4Option->ConnectionTimeout      = HTTP_CONNECTION_TIMEOUT;
   1088   Tcp4Option->DataRetries            = HTTP_DATA_RETRIES;
   1089   Tcp4Option->FinTimeout             = HTTP_FIN_TIMEOUT;
   1090   Tcp4Option->KeepAliveProbes        = HTTP_KEEP_ALIVE_PROBES;
   1091   Tcp4Option->KeepAliveTime          = HTTP_KEEP_ALIVE_TIME;
   1092   Tcp4Option->KeepAliveInterval      = HTTP_KEEP_ALIVE_INTERVAL;
   1093   Tcp4Option->EnableNagle            = TRUE;
   1094   Tcp4CfgData->ControlOption         = Tcp4Option;
   1095 
   1096   Status = HttpInstance->Tcp4->Configure (HttpInstance->Tcp4, Tcp4CfgData);
   1097   if (EFI_ERROR (Status)) {
   1098     DEBUG ((EFI_D_ERROR, "HttpConfigureTcp4 - %r\n", Status));
   1099     return Status;
   1100   }
   1101 
   1102   Status = HttpCreateTcpConnCloseEvent (HttpInstance);
   1103   if (EFI_ERROR (Status)) {
   1104     return Status;
   1105   }
   1106 
   1107   Status = HttpCreateTcpTxEvent (Wrap);
   1108   if (EFI_ERROR (Status)) {
   1109     return Status;
   1110   }
   1111 
   1112   HttpInstance->State = HTTP_STATE_TCP_CONFIGED;
   1113 
   1114   return EFI_SUCCESS;
   1115 }
   1116 
   1117 /**
   1118   Configure TCP6 protocol child.
   1119 
   1120   @param[in]  HttpInstance       The HTTP instance private data.
   1121   @param[in]  Wrap               The HTTP token's wrap data.
   1122 
   1123   @retval EFI_SUCCESS            The TCP6 protocol child is configured.
   1124   @retval Others                 Other error as indicated.
   1125 
   1126 **/
   1127 EFI_STATUS
   1128 HttpConfigureTcp6 (
   1129   IN  HTTP_PROTOCOL        *HttpInstance,
   1130   IN  HTTP_TOKEN_WRAP      *Wrap
   1131   )
   1132 {
   1133   EFI_STATUS               Status;
   1134   EFI_TCP6_CONFIG_DATA     *Tcp6CfgData;
   1135   EFI_TCP6_ACCESS_POINT    *Tcp6Ap;
   1136   EFI_TCP6_OPTION          *Tcp6Option;
   1137 
   1138   ASSERT (HttpInstance != NULL);
   1139 
   1140   Tcp6CfgData = &HttpInstance->Tcp6CfgData;
   1141   ZeroMem (Tcp6CfgData, sizeof (EFI_TCP6_CONFIG_DATA));
   1142 
   1143   Tcp6CfgData->TrafficClass  = 0;
   1144   Tcp6CfgData->HopLimit      = 255;
   1145   Tcp6CfgData->ControlOption = &HttpInstance->Tcp6Option;
   1146 
   1147   Tcp6Ap  = &Tcp6CfgData->AccessPoint;
   1148   Tcp6Ap->ActiveFlag  = TRUE;
   1149   Tcp6Ap->StationPort = HttpInstance->Ipv6Node.LocalPort;
   1150   Tcp6Ap->RemotePort  = HttpInstance->RemotePort;
   1151   IP6_COPY_ADDRESS (&Tcp6Ap->StationAddress, &HttpInstance->Ipv6Node.LocalAddress);
   1152   IP6_COPY_ADDRESS (&Tcp6Ap->RemoteAddress , &HttpInstance->RemoteIpv6Addr);
   1153 
   1154   Tcp6Option = Tcp6CfgData->ControlOption;
   1155   Tcp6Option->ReceiveBufferSize  = HTTP_BUFFER_SIZE_DEAULT;
   1156   Tcp6Option->SendBufferSize     = HTTP_BUFFER_SIZE_DEAULT;
   1157   Tcp6Option->MaxSynBackLog      = HTTP_MAX_SYN_BACK_LOG;
   1158   Tcp6Option->ConnectionTimeout  = HTTP_CONNECTION_TIMEOUT;
   1159   Tcp6Option->DataRetries        = HTTP_DATA_RETRIES;
   1160   Tcp6Option->FinTimeout         = HTTP_FIN_TIMEOUT;
   1161   Tcp6Option->KeepAliveProbes    = HTTP_KEEP_ALIVE_PROBES;
   1162   Tcp6Option->KeepAliveTime      = HTTP_KEEP_ALIVE_TIME;
   1163   Tcp6Option->KeepAliveInterval  = HTTP_KEEP_ALIVE_INTERVAL;
   1164   Tcp6Option->EnableNagle        = TRUE;
   1165 
   1166   Status = HttpInstance->Tcp6->Configure (HttpInstance->Tcp6, Tcp6CfgData);
   1167   if (EFI_ERROR (Status)) {
   1168     DEBUG ((EFI_D_ERROR, "HttpConfigureTcp6 - %r\n", Status));
   1169     return Status;
   1170   }
   1171 
   1172   Status = HttpCreateTcpConnCloseEvent (HttpInstance);
   1173   if (EFI_ERROR (Status)) {
   1174     return Status;
   1175   }
   1176 
   1177   Status = HttpCreateTcpTxEvent (Wrap);
   1178   if (EFI_ERROR (Status)) {
   1179     return Status;
   1180   }
   1181 
   1182   HttpInstance->State = HTTP_STATE_TCP_CONFIGED;
   1183 
   1184   return EFI_SUCCESS;
   1185 
   1186 }
   1187 
   1188 /**
   1189   Check existing TCP connection, if in error state, recover TCP4 connection. Then,
   1190   connect one TLS session if required.
   1191 
   1192   @param[in]  HttpInstance       The HTTP instance private data.
   1193 
   1194   @retval EFI_SUCCESS            The TCP connection is established.
   1195   @retval EFI_NOT_READY          TCP4 protocol child is not created or configured.
   1196   @retval Others                 Other error as indicated.
   1197 
   1198 **/
   1199 EFI_STATUS
   1200 HttpConnectTcp4 (
   1201   IN  HTTP_PROTOCOL        *HttpInstance
   1202   )
   1203 {
   1204   EFI_STATUS                Status;
   1205   EFI_TCP4_CONNECTION_STATE Tcp4State;
   1206 
   1207 
   1208   if (HttpInstance->State < HTTP_STATE_TCP_CONFIGED || HttpInstance->Tcp4 == NULL) {
   1209     return EFI_NOT_READY;
   1210   }
   1211 
   1212   Status = HttpInstance->Tcp4->GetModeData(
   1213                                  HttpInstance->Tcp4,
   1214                                  &Tcp4State,
   1215                                  NULL,
   1216                                  NULL,
   1217                                  NULL,
   1218                                  NULL
   1219                                  );
   1220   if (EFI_ERROR(Status)){
   1221     DEBUG ((EFI_D_ERROR, "Tcp4 GetModeData fail - %x\n", Status));
   1222     return Status;
   1223   }
   1224 
   1225   if (Tcp4State == Tcp4StateEstablished) {
   1226     return EFI_SUCCESS;
   1227   } else if (Tcp4State > Tcp4StateEstablished ) {
   1228     HttpCloseConnection(HttpInstance);
   1229   }
   1230 
   1231   Status = HttpCreateConnection (HttpInstance);
   1232   if (EFI_ERROR(Status)){
   1233     DEBUG ((EFI_D_ERROR, "Tcp4 Connection fail - %x\n", Status));
   1234     return Status;
   1235   }
   1236 
   1237   //
   1238   // Tls session connection.
   1239   //
   1240   if (HttpInstance->UseHttps) {
   1241     if (HttpInstance->TimeoutEvent == NULL) {
   1242       //
   1243       // Create TimeoutEvent for TLS connection.
   1244       //
   1245       Status = gBS->CreateEvent (
   1246                       EVT_TIMER,
   1247                       TPL_CALLBACK,
   1248                       NULL,
   1249                       NULL,
   1250                       &HttpInstance->TimeoutEvent
   1251                       );
   1252       if (EFI_ERROR (Status)) {
   1253         TlsCloseTxRxEvent (HttpInstance);
   1254         return Status;
   1255       }
   1256     }
   1257 
   1258     //
   1259     // Start the timer, and wait Timeout seconds for connection.
   1260     //
   1261     Status = gBS->SetTimer (HttpInstance->TimeoutEvent, TimerRelative, HTTP_CONNECTION_TIMEOUT * TICKS_PER_SECOND);
   1262     if (EFI_ERROR (Status)) {
   1263       TlsCloseTxRxEvent (HttpInstance);
   1264       return Status;
   1265     }
   1266 
   1267     Status = TlsConnectSession (HttpInstance, HttpInstance->TimeoutEvent);
   1268 
   1269     gBS->SetTimer (HttpInstance->TimeoutEvent, TimerCancel, 0);
   1270 
   1271     if (EFI_ERROR (Status)) {
   1272       TlsCloseTxRxEvent (HttpInstance);
   1273       return Status;
   1274     }
   1275   }
   1276 
   1277   return Status;
   1278 }
   1279 
   1280 /**
   1281   Check existing TCP connection, if in error state, recover TCP6 connection. Then,
   1282   connect one TLS session if required.
   1283 
   1284   @param[in]  HttpInstance       The HTTP instance private data.
   1285 
   1286   @retval EFI_SUCCESS            The TCP connection is established.
   1287   @retval EFI_NOT_READY          TCP6 protocol child is not created or configured.
   1288   @retval Others                 Other error as indicated.
   1289 
   1290 **/
   1291 EFI_STATUS
   1292 HttpConnectTcp6 (
   1293   IN  HTTP_PROTOCOL        *HttpInstance
   1294   )
   1295 {
   1296   EFI_STATUS                Status;
   1297   EFI_TCP6_CONNECTION_STATE Tcp6State;
   1298 
   1299   if (HttpInstance->State < HTTP_STATE_TCP_CONFIGED || HttpInstance->Tcp6 == NULL) {
   1300     return EFI_NOT_READY;
   1301   }
   1302 
   1303   Status = HttpInstance->Tcp6->GetModeData (
   1304                                  HttpInstance->Tcp6,
   1305                                  &Tcp6State,
   1306                                  NULL,
   1307                                  NULL,
   1308                                  NULL,
   1309                                  NULL
   1310                                  );
   1311 
   1312   if (EFI_ERROR(Status)){
   1313      DEBUG ((EFI_D_ERROR, "Tcp6 GetModeData fail - %x\n", Status));
   1314      return Status;
   1315   }
   1316 
   1317   if (Tcp6State == Tcp6StateEstablished) {
   1318     return EFI_SUCCESS;
   1319   } else if (Tcp6State > Tcp6StateEstablished ) {
   1320     HttpCloseConnection(HttpInstance);
   1321   }
   1322 
   1323   Status = HttpCreateConnection (HttpInstance);
   1324   if (EFI_ERROR(Status)){
   1325     DEBUG ((EFI_D_ERROR, "Tcp6 Connection fail - %x\n", Status));
   1326     return Status;
   1327   }
   1328 
   1329   //
   1330   // Tls session connection.
   1331   //
   1332   if (HttpInstance->UseHttps) {
   1333     if (HttpInstance->TimeoutEvent == NULL) {
   1334       //
   1335       // Create TimeoutEvent for TLS connection.
   1336       //
   1337       Status = gBS->CreateEvent (
   1338                       EVT_TIMER,
   1339                       TPL_CALLBACK,
   1340                       NULL,
   1341                       NULL,
   1342                       &HttpInstance->TimeoutEvent
   1343                       );
   1344       if (EFI_ERROR (Status)) {
   1345         TlsCloseTxRxEvent (HttpInstance);
   1346         return Status;
   1347       }
   1348     }
   1349 
   1350     //
   1351     // Start the timer, and wait Timeout seconds for connection.
   1352     //
   1353     Status = gBS->SetTimer (HttpInstance->TimeoutEvent, TimerRelative, HTTP_CONNECTION_TIMEOUT * TICKS_PER_SECOND);
   1354     if (EFI_ERROR (Status)) {
   1355       TlsCloseTxRxEvent (HttpInstance);
   1356       return Status;
   1357     }
   1358 
   1359     Status = TlsConnectSession (HttpInstance, HttpInstance->TimeoutEvent);
   1360 
   1361     gBS->SetTimer (HttpInstance->TimeoutEvent, TimerCancel, 0);
   1362 
   1363     if (EFI_ERROR (Status)) {
   1364       TlsCloseTxRxEvent (HttpInstance);
   1365       return Status;
   1366     }
   1367   }
   1368 
   1369   return Status;
   1370 }
   1371 
   1372 /**
   1373   Initialize Http session.
   1374 
   1375   @param[in]  HttpInstance       The HTTP instance private data.
   1376   @param[in]  Wrap               The HTTP token's wrap data.
   1377   @param[in]  Configure          The Flag indicates whether need to initialize session.
   1378   @param[in]  TlsConfigure       The Flag indicates whether it's the new Tls session.
   1379 
   1380   @retval EFI_SUCCESS            The initialization of session is done.
   1381   @retval Others                 Other error as indicated.
   1382 
   1383 **/
   1384 EFI_STATUS
   1385 HttpInitSession (
   1386   IN  HTTP_PROTOCOL    *HttpInstance,
   1387   IN  HTTP_TOKEN_WRAP  *Wrap,
   1388   IN  BOOLEAN          Configure,
   1389   IN  BOOLEAN          TlsConfigure
   1390   )
   1391 {
   1392   EFI_STATUS           Status;
   1393   ASSERT (HttpInstance != NULL);
   1394 
   1395   //
   1396   // Configure Tls session.
   1397   //
   1398   if (TlsConfigure) {
   1399     Status = TlsConfigureSession (HttpInstance);
   1400     if (EFI_ERROR (Status)) {
   1401       return Status;
   1402     }
   1403   }
   1404 
   1405   if (!HttpInstance->LocalAddressIsIPv6) {
   1406     //
   1407     // Configure TCP instance.
   1408     //
   1409     if (Configure) {
   1410       Status = HttpConfigureTcp4 (HttpInstance, Wrap);
   1411       if (EFI_ERROR (Status)) {
   1412         return Status;
   1413       }
   1414     }
   1415 
   1416     //
   1417     // Connect TCP.
   1418     //
   1419     Status = HttpConnectTcp4 (HttpInstance);
   1420     if (EFI_ERROR (Status)) {
   1421       return Status;
   1422     }
   1423   } else {
   1424     //
   1425     // Configure TCP instance.
   1426     //
   1427     if (Configure) {
   1428       Status = HttpConfigureTcp6 (HttpInstance, Wrap);
   1429       if (EFI_ERROR (Status)) {
   1430         return Status;
   1431       }
   1432     }
   1433 
   1434     //
   1435     // Connect TCP.
   1436     //
   1437     Status = HttpConnectTcp6 (HttpInstance);
   1438     if (EFI_ERROR (Status)) {
   1439       return Status;
   1440     }
   1441   }
   1442 
   1443   return EFI_SUCCESS;
   1444 
   1445 }
   1446 
   1447 /**
   1448   Send the HTTP or HTTPS message through TCP4 or TCP6.
   1449 
   1450   @param[in]  HttpInstance       The HTTP instance private data.
   1451   @param[in]  Wrap               The HTTP token's wrap data.
   1452   @param[in]  TxString           Buffer containing the HTTP message string.
   1453   @param[in]  TxStringLen        Length of the HTTP message string in bytes.
   1454 
   1455   @retval EFI_SUCCESS            The HTTP message is queued into TCP transmit queue.
   1456   @retval Others                 Other error as indicated.
   1457 
   1458 **/
   1459 EFI_STATUS
   1460 HttpTransmitTcp (
   1461   IN  HTTP_PROTOCOL    *HttpInstance,
   1462   IN  HTTP_TOKEN_WRAP  *Wrap,
   1463   IN  UINT8            *TxString,
   1464   IN  UINTN            TxStringLen
   1465   )
   1466 {
   1467   EFI_STATUS                    Status;
   1468   EFI_TCP4_IO_TOKEN             *Tx4Token;
   1469   EFI_TCP4_PROTOCOL             *Tcp4;
   1470   EFI_TCP6_IO_TOKEN             *Tx6Token;
   1471   EFI_TCP6_PROTOCOL             *Tcp6;
   1472   UINT8                         *Buffer;
   1473   UINTN                         BufferSize;
   1474   NET_FRAGMENT                  TempFragment;
   1475 
   1476   Status                = EFI_SUCCESS;
   1477   Buffer                = NULL;
   1478   TempFragment.Len      = 0;
   1479   TempFragment.Bulk     = NULL;
   1480 
   1481   //
   1482   // Need to encrypt data.
   1483   //
   1484   if (HttpInstance->UseHttps) {
   1485     //
   1486     // Build BufferOut data
   1487     //
   1488     BufferSize = sizeof (TLS_RECORD_HEADER) + TxStringLen;
   1489     Buffer     = AllocateZeroPool (BufferSize);
   1490     if (Buffer == NULL) {
   1491       Status = EFI_OUT_OF_RESOURCES;
   1492       return Status;
   1493     }
   1494     ((TLS_RECORD_HEADER *) Buffer)->ContentType = TLS_CONTENT_TYPE_APPLICATION_DATA;
   1495     ((TLS_RECORD_HEADER *) Buffer)->Version.Major = HttpInstance->TlsConfigData.Version.Major;
   1496     ((TLS_RECORD_HEADER *) Buffer)->Version.Minor = HttpInstance->TlsConfigData.Version.Minor;
   1497     ((TLS_RECORD_HEADER *) Buffer)->Length = (UINT16) (TxStringLen);
   1498     CopyMem (Buffer + sizeof (TLS_RECORD_HEADER), TxString, TxStringLen);
   1499 
   1500     //
   1501     // Encrypt Packet.
   1502     //
   1503     Status = TlsProcessMessage (
   1504                HttpInstance,
   1505                Buffer,
   1506                BufferSize,
   1507                EfiTlsEncrypt,
   1508                &TempFragment
   1509                );
   1510 
   1511     FreePool (Buffer);
   1512 
   1513     if (EFI_ERROR (Status)) {
   1514       return Status;
   1515     }
   1516   }
   1517 
   1518   if (!HttpInstance->LocalAddressIsIPv6) {
   1519     Tcp4 = HttpInstance->Tcp4;
   1520     Tx4Token = &Wrap->TcpWrap.Tx4Token;
   1521 
   1522     if (HttpInstance->UseHttps) {
   1523       Tx4Token->Packet.TxData->DataLength = TempFragment.Len;
   1524       Tx4Token->Packet.TxData->FragmentTable[0].FragmentLength = TempFragment.Len;
   1525       Tx4Token->Packet.TxData->FragmentTable[0].FragmentBuffer = (VOID *) TempFragment.Bulk;
   1526     } else {
   1527       Tx4Token->Packet.TxData->DataLength = (UINT32) TxStringLen;
   1528       Tx4Token->Packet.TxData->FragmentTable[0].FragmentLength = (UINT32) TxStringLen;
   1529       Tx4Token->Packet.TxData->FragmentTable[0].FragmentBuffer = (VOID *) TxString;
   1530     }
   1531 
   1532     Tx4Token->CompletionToken.Status = EFI_NOT_READY;
   1533 
   1534     Wrap->TcpWrap.IsTxDone = FALSE;
   1535     Status  = Tcp4->Transmit (Tcp4, Tx4Token);
   1536     if (EFI_ERROR (Status)) {
   1537       DEBUG ((EFI_D_ERROR, "Transmit failed: %r\n", Status));
   1538       return Status;
   1539     }
   1540 
   1541   } else {
   1542     Tcp6 = HttpInstance->Tcp6;
   1543     Tx6Token = &Wrap->TcpWrap.Tx6Token;
   1544 
   1545     if (HttpInstance->UseHttps) {
   1546       Tx6Token->Packet.TxData->DataLength = TempFragment.Len;
   1547       Tx6Token->Packet.TxData->FragmentTable[0].FragmentLength = TempFragment.Len;
   1548       Tx6Token->Packet.TxData->FragmentTable[0].FragmentBuffer = (VOID *) TempFragment.Bulk;
   1549     } else {
   1550       Tx6Token->Packet.TxData->DataLength = (UINT32) TxStringLen;
   1551       Tx6Token->Packet.TxData->FragmentTable[0].FragmentLength = (UINT32) TxStringLen;
   1552       Tx6Token->Packet.TxData->FragmentTable[0].FragmentBuffer = (VOID *) TxString;
   1553     }
   1554 
   1555     Tx6Token->CompletionToken.Status = EFI_NOT_READY;
   1556 
   1557     Wrap->TcpWrap.IsTxDone = FALSE;
   1558     Status = Tcp6->Transmit (Tcp6, Tx6Token);
   1559     if (EFI_ERROR (Status)) {
   1560       DEBUG ((EFI_D_ERROR, "Transmit failed: %r\n", Status));
   1561       return Status;
   1562     }
   1563   }
   1564 
   1565   return Status;
   1566 }
   1567 
   1568 /**
   1569   Check whether the user's token or event has already
   1570   been enqueue on HTTP Tx or Rx Token list.
   1571 
   1572   @param[in]  Map                The container of either user's transmit or receive
   1573                                  token.
   1574   @param[in]  Item               Current item to check against.
   1575   @param[in]  Context            The Token to check againist.
   1576 
   1577   @retval EFI_ACCESS_DENIED      The token or event has already been enqueued in IP
   1578   @retval EFI_SUCCESS            The current item isn't the same token/event as the
   1579                                  context.
   1580 
   1581 **/
   1582 EFI_STATUS
   1583 EFIAPI
   1584 HttpTokenExist (
   1585   IN NET_MAP                *Map,
   1586   IN NET_MAP_ITEM           *Item,
   1587   IN VOID                   *Context
   1588   )
   1589 {
   1590   EFI_HTTP_TOKEN            *Token;
   1591   EFI_HTTP_TOKEN            *TokenInItem;
   1592 
   1593   Token       = (EFI_HTTP_TOKEN *) Context;
   1594   TokenInItem = (EFI_HTTP_TOKEN *) Item->Key;
   1595 
   1596   if (Token == TokenInItem || Token->Event == TokenInItem->Event) {
   1597     return EFI_ACCESS_DENIED;
   1598   }
   1599 
   1600   return EFI_SUCCESS;
   1601 }
   1602 
   1603 /**
   1604   Check whether the HTTP message associated with Tx4Token or Tx6Token is already sent out.
   1605 
   1606   @param[in]  Map                The container of Tx4Token or Tx6Token.
   1607   @param[in]  Item               Current item to check against.
   1608   @param[in]  Context            The Token to check againist.
   1609 
   1610   @retval EFI_NOT_READY          The HTTP message is still queued in the list.
   1611   @retval EFI_SUCCESS            The HTTP message has been sent out.
   1612 
   1613 **/
   1614 EFI_STATUS
   1615 EFIAPI
   1616 HttpTcpNotReady (
   1617   IN NET_MAP                *Map,
   1618   IN NET_MAP_ITEM           *Item,
   1619   IN VOID                   *Context
   1620   )
   1621 {
   1622   HTTP_TOKEN_WRAP           *ValueInItem;
   1623 
   1624   ValueInItem = (HTTP_TOKEN_WRAP *) Item->Value;
   1625 
   1626   if (!ValueInItem->TcpWrap.IsTxDone) {
   1627     return EFI_NOT_READY;
   1628   }
   1629 
   1630   return EFI_SUCCESS;
   1631 }
   1632 
   1633 /**
   1634   Transmit the HTTP or HTTPS mssage by processing the associated HTTP token.
   1635 
   1636   @param[in]  Map                The container of Tx4Token or Tx6Token.
   1637   @param[in]  Item               Current item to check against.
   1638   @param[in]  Context            The Token to check againist.
   1639 
   1640   @retval EFI_OUT_OF_RESOURCES   Failed to allocate resources.
   1641   @retval EFI_SUCCESS            The HTTP message is queued into TCP transmit
   1642                                  queue.
   1643 
   1644 **/
   1645 EFI_STATUS
   1646 EFIAPI
   1647 HttpTcpTransmit (
   1648   IN NET_MAP                *Map,
   1649   IN NET_MAP_ITEM           *Item,
   1650   IN VOID                   *Context
   1651   )
   1652 {
   1653   HTTP_TOKEN_WRAP           *ValueInItem;
   1654   EFI_STATUS                Status;
   1655   CHAR8                     *RequestMsg;
   1656   CHAR8                     *Url;
   1657   UINTN                     UrlSize;
   1658   UINTN                     RequestMsgSize;
   1659 
   1660   RequestMsg = NULL;
   1661 
   1662   ValueInItem = (HTTP_TOKEN_WRAP *) Item->Value;
   1663   if (ValueInItem->TcpWrap.IsTxDone) {
   1664     return EFI_SUCCESS;
   1665   }
   1666 
   1667   //
   1668   // Parse the URI of the remote host.
   1669   //
   1670   UrlSize = StrLen (ValueInItem->HttpToken->Message->Data.Request->Url) + 1;
   1671   Url = AllocatePool (UrlSize);
   1672   if (Url == NULL) {
   1673     return EFI_OUT_OF_RESOURCES;
   1674   }
   1675 
   1676   UnicodeStrToAsciiStrS (ValueInItem->HttpToken->Message->Data.Request->Url, Url, UrlSize);
   1677 
   1678   //
   1679   // Create request message.
   1680   //
   1681   Status = HttpGenRequestMessage (
   1682                  ValueInItem->HttpToken->Message,
   1683                  Url,
   1684                  &RequestMsg,
   1685                  &RequestMsgSize
   1686                  );
   1687   FreePool (Url);
   1688 
   1689   if (EFI_ERROR (Status) || NULL == RequestMsg){
   1690     return Status;
   1691   }
   1692 
   1693   ASSERT (RequestMsg != NULL);
   1694 
   1695   //
   1696   // Transmit the request message.
   1697   //
   1698   Status = HttpTransmitTcp (
   1699              ValueInItem->HttpInstance,
   1700              ValueInItem,
   1701              (UINT8*) RequestMsg,
   1702              RequestMsgSize
   1703              );
   1704   FreePool (RequestMsg);
   1705   return Status;
   1706 }
   1707 
   1708 /**
   1709   Receive the HTTP response by processing the associated HTTP token.
   1710 
   1711   @param[in]  Map                The container of Rx4Token or Rx6Token.
   1712   @param[in]  Item               Current item to check against.
   1713   @param[in]  Context            The Token to check againist.
   1714 
   1715   @retval EFI_SUCCESS            The HTTP response is queued into TCP receive
   1716                                  queue.
   1717   @retval Others                 Other error as indicated.
   1718 
   1719 **/
   1720 EFI_STATUS
   1721 EFIAPI
   1722 HttpTcpReceive (
   1723   IN NET_MAP                *Map,
   1724   IN NET_MAP_ITEM           *Item,
   1725   IN VOID                   *Context
   1726   )
   1727 {
   1728   //
   1729   // Process the queued HTTP response.
   1730   //
   1731   return HttpResponseWorker ((HTTP_TOKEN_WRAP *) Item->Value);
   1732 }
   1733 
   1734 /**
   1735   Receive the HTTP header by processing the associated HTTP token.
   1736 
   1737   @param[in]       HttpInstance     The HTTP instance private data.
   1738   @param[in, out]  SizeofHeaders    The HTTP header length.
   1739   @param[in, out]  BufferSize       The size of buffer to cacahe the header message.
   1740   @param[in]       Timeout          The time to wait for receiving the header packet.
   1741 
   1742   @retval EFI_SUCCESS               The HTTP header is received.
   1743   @retval Others                    Other errors as indicated.
   1744 
   1745 **/
   1746 EFI_STATUS
   1747 HttpTcpReceiveHeader (
   1748   IN  HTTP_PROTOCOL         *HttpInstance,
   1749   IN  OUT UINTN             *SizeofHeaders,
   1750   IN  OUT UINTN             *BufferSize,
   1751   IN  EFI_EVENT             Timeout
   1752   )
   1753 {
   1754   EFI_STATUS                    Status;
   1755   EFI_TCP4_IO_TOKEN             *Rx4Token;
   1756   EFI_TCP4_PROTOCOL             *Tcp4;
   1757   EFI_TCP6_IO_TOKEN             *Rx6Token;
   1758   EFI_TCP6_PROTOCOL             *Tcp6;
   1759   CHAR8                         **EndofHeader;
   1760   CHAR8                         **HttpHeaders;
   1761   CHAR8                         *Buffer;
   1762   NET_FRAGMENT                  Fragment;
   1763 
   1764   ASSERT (HttpInstance != NULL);
   1765 
   1766   EndofHeader = HttpInstance->EndofHeader;
   1767   HttpHeaders = HttpInstance->HttpHeaders;
   1768   Tcp4 = HttpInstance->Tcp4;
   1769   Tcp6 = HttpInstance->Tcp6;
   1770   Buffer      = NULL;
   1771   Rx4Token    = NULL;
   1772   Rx6Token    = NULL;
   1773   Fragment.Len  = 0;
   1774   Fragment.Bulk = NULL;
   1775 
   1776   if (HttpInstance->LocalAddressIsIPv6) {
   1777     ASSERT (Tcp6 != NULL);
   1778   } else {
   1779     ASSERT (Tcp4 != NULL);
   1780   }
   1781 
   1782   if (!HttpInstance->UseHttps) {
   1783     Status = HttpCreateTcpRxEventForHeader (HttpInstance);
   1784     if (EFI_ERROR (Status)) {
   1785       return Status;
   1786     }
   1787   }
   1788 
   1789   if (!HttpInstance->LocalAddressIsIPv6) {
   1790     if (!HttpInstance->UseHttps) {
   1791       Rx4Token = &HttpInstance->Rx4Token;
   1792       Rx4Token->Packet.RxData->FragmentTable[0].FragmentBuffer = AllocateZeroPool (DEF_BUF_LEN);
   1793       if (Rx4Token->Packet.RxData->FragmentTable[0].FragmentBuffer == NULL) {
   1794         Status = EFI_OUT_OF_RESOURCES;
   1795         return Status;
   1796       }
   1797     }
   1798 
   1799     //
   1800     // Receive the HTTP headers only when EFI_HTTP_RESPONSE_DATA is not NULL.
   1801     //
   1802     while (*EndofHeader == NULL) {
   1803       if (!HttpInstance->UseHttps) {
   1804         HttpInstance->IsRxDone = FALSE;
   1805         Rx4Token->Packet.RxData->DataLength = DEF_BUF_LEN;
   1806         Rx4Token->Packet.RxData->FragmentTable[0].FragmentLength = DEF_BUF_LEN;
   1807         Status = Tcp4->Receive (Tcp4, Rx4Token);
   1808         if (EFI_ERROR (Status)) {
   1809           DEBUG ((EFI_D_ERROR, "Tcp4 receive failed: %r\n", Status));
   1810           return Status;
   1811         }
   1812 
   1813         while (!HttpInstance->IsRxDone && ((Timeout == NULL) || EFI_ERROR (gBS->CheckEvent (Timeout)))) {
   1814           Tcp4->Poll (Tcp4);
   1815         }
   1816 
   1817         if (!HttpInstance->IsRxDone) {
   1818           //
   1819           // Cancle the Token before close its Event.
   1820           //
   1821           Tcp4->Cancel (HttpInstance->Tcp4, &Rx4Token->CompletionToken);
   1822           gBS->CloseEvent (Rx4Token->CompletionToken.Event);
   1823           Rx4Token->CompletionToken.Status = EFI_TIMEOUT;
   1824         }
   1825 
   1826         Status = Rx4Token->CompletionToken.Status;
   1827         if (EFI_ERROR (Status)) {
   1828           return Status;
   1829         }
   1830 
   1831         Fragment.Len  = Rx4Token->Packet.RxData->FragmentTable[0].FragmentLength;
   1832         Fragment.Bulk = (UINT8 *) Rx4Token->Packet.RxData->FragmentTable[0].FragmentBuffer;
   1833       } else {
   1834         if (Fragment.Bulk != NULL) {
   1835           FreePool (Fragment.Bulk);
   1836           Fragment.Bulk = NULL;
   1837         }
   1838 
   1839         Status = HttpsReceive (HttpInstance, &Fragment, Timeout);
   1840         if (EFI_ERROR (Status)) {
   1841           DEBUG ((EFI_D_ERROR, "Tcp4 receive failed: %r\n", Status));
   1842           return Status;
   1843         }
   1844       }
   1845 
   1846       //
   1847       // Append the response string.
   1848       //
   1849       *BufferSize = *SizeofHeaders + Fragment.Len;
   1850       Buffer      = AllocateZeroPool (*BufferSize);
   1851       if (Buffer == NULL) {
   1852         Status = EFI_OUT_OF_RESOURCES;
   1853         return Status;
   1854       }
   1855 
   1856       if (*HttpHeaders != NULL) {
   1857         CopyMem (Buffer, *HttpHeaders, *SizeofHeaders);
   1858         FreePool (*HttpHeaders);
   1859       }
   1860 
   1861       CopyMem (
   1862         Buffer + *SizeofHeaders,
   1863         Fragment.Bulk,
   1864         Fragment.Len
   1865         );
   1866       *HttpHeaders   = Buffer;
   1867       *SizeofHeaders = *BufferSize;
   1868 
   1869       //
   1870       // Check whether we received end of HTTP headers.
   1871       //
   1872       *EndofHeader = AsciiStrStr (*HttpHeaders, HTTP_END_OF_HDR_STR);
   1873     };
   1874 
   1875     //
   1876     // Free the buffer.
   1877     //
   1878     if (Rx4Token != NULL && Rx4Token->Packet.RxData != NULL && Rx4Token->Packet.RxData->FragmentTable[0].FragmentBuffer != NULL) {
   1879       FreePool (Rx4Token->Packet.RxData->FragmentTable[0].FragmentBuffer);
   1880       Rx4Token->Packet.RxData->FragmentTable[0].FragmentBuffer = NULL;
   1881       Fragment.Bulk = NULL;
   1882     }
   1883 
   1884     if (Fragment.Bulk != NULL) {
   1885       FreePool (Fragment.Bulk);
   1886       Fragment.Bulk = NULL;
   1887     }
   1888   } else {
   1889     if (!HttpInstance->UseHttps) {
   1890       Rx6Token = &HttpInstance->Rx6Token;
   1891       Rx6Token->Packet.RxData->FragmentTable[0].FragmentBuffer = AllocateZeroPool (DEF_BUF_LEN);
   1892       if (Rx6Token->Packet.RxData->FragmentTable[0].FragmentBuffer == NULL) {
   1893         Status = EFI_OUT_OF_RESOURCES;
   1894         return Status;
   1895       }
   1896     }
   1897 
   1898     //
   1899     // Receive the HTTP headers only when EFI_HTTP_RESPONSE_DATA is not NULL.
   1900     //
   1901     while (*EndofHeader == NULL) {
   1902       if (!HttpInstance->UseHttps) {
   1903         HttpInstance->IsRxDone = FALSE;
   1904         Rx6Token->Packet.RxData->DataLength = DEF_BUF_LEN;
   1905         Rx6Token->Packet.RxData->FragmentTable[0].FragmentLength = DEF_BUF_LEN;
   1906         Status = Tcp6->Receive (Tcp6, Rx6Token);
   1907         if (EFI_ERROR (Status)) {
   1908           DEBUG ((EFI_D_ERROR, "Tcp6 receive failed: %r\n", Status));
   1909           return Status;
   1910         }
   1911 
   1912         while (!HttpInstance->IsRxDone && ((Timeout == NULL) || EFI_ERROR (gBS->CheckEvent (Timeout)))) {
   1913           Tcp6->Poll (Tcp6);
   1914         }
   1915 
   1916         if (!HttpInstance->IsRxDone) {
   1917           //
   1918           // Cancle the Token before close its Event.
   1919           //
   1920           Tcp6->Cancel (HttpInstance->Tcp6, &Rx6Token->CompletionToken);
   1921           gBS->CloseEvent (Rx6Token->CompletionToken.Event);
   1922           Rx6Token->CompletionToken.Status = EFI_TIMEOUT;
   1923         }
   1924 
   1925         Status = Rx6Token->CompletionToken.Status;
   1926         if (EFI_ERROR (Status)) {
   1927           return Status;
   1928         }
   1929 
   1930         Fragment.Len  = Rx6Token->Packet.RxData->FragmentTable[0].FragmentLength;
   1931         Fragment.Bulk = (UINT8 *) Rx6Token->Packet.RxData->FragmentTable[0].FragmentBuffer;
   1932       } else {
   1933         if (Fragment.Bulk != NULL) {
   1934           FreePool (Fragment.Bulk);
   1935           Fragment.Bulk = NULL;
   1936         }
   1937 
   1938         Status = HttpsReceive (HttpInstance, &Fragment, Timeout);
   1939         if (EFI_ERROR (Status)) {
   1940           DEBUG ((EFI_D_ERROR, "Tcp6 receive failed: %r\n", Status));
   1941           return Status;
   1942         }
   1943       }
   1944 
   1945       //
   1946       // Append the response string.
   1947       //
   1948       *BufferSize = *SizeofHeaders + Fragment.Len;
   1949       Buffer      = AllocateZeroPool (*BufferSize);
   1950       if (Buffer == NULL) {
   1951         Status = EFI_OUT_OF_RESOURCES;
   1952         return Status;
   1953       }
   1954 
   1955       if (*HttpHeaders != NULL) {
   1956         CopyMem (Buffer, *HttpHeaders, *SizeofHeaders);
   1957         FreePool (*HttpHeaders);
   1958       }
   1959 
   1960       CopyMem (
   1961         Buffer + *SizeofHeaders,
   1962         Fragment.Bulk,
   1963         Fragment.Len
   1964         );
   1965       *HttpHeaders   = Buffer;
   1966       *SizeofHeaders = *BufferSize;
   1967 
   1968       //
   1969       // Check whether we received end of HTTP headers.
   1970       //
   1971       *EndofHeader = AsciiStrStr (*HttpHeaders, HTTP_END_OF_HDR_STR);
   1972     };
   1973 
   1974     //
   1975     // Free the buffer.
   1976     //
   1977     if (Rx6Token != NULL && Rx6Token->Packet.RxData != NULL && Rx6Token->Packet.RxData->FragmentTable[0].FragmentBuffer != NULL) {
   1978       FreePool (Rx6Token->Packet.RxData->FragmentTable[0].FragmentBuffer);
   1979       Rx6Token->Packet.RxData->FragmentTable[0].FragmentBuffer = NULL;
   1980       Fragment.Bulk = NULL;
   1981     }
   1982 
   1983     if (Fragment.Bulk != NULL) {
   1984       FreePool (Fragment.Bulk);
   1985       Fragment.Bulk = NULL;
   1986     }
   1987   }
   1988 
   1989   //
   1990   // Skip the CRLF after the HTTP headers.
   1991   //
   1992   *EndofHeader = *EndofHeader + AsciiStrLen (HTTP_END_OF_HDR_STR);
   1993 
   1994   return EFI_SUCCESS;
   1995 }
   1996 
   1997 /**
   1998   Receive the HTTP body by processing the associated HTTP token.
   1999 
   2000   @param[in]  Wrap               The HTTP token's wrap data.
   2001   @param[in]  HttpMsg            The HTTP message data.
   2002 
   2003   @retval EFI_SUCCESS            The HTTP body is received.
   2004   @retval Others                 Other error as indicated.
   2005 
   2006 **/
   2007 EFI_STATUS
   2008 HttpTcpReceiveBody (
   2009   IN  HTTP_TOKEN_WRAP       *Wrap,
   2010   IN  EFI_HTTP_MESSAGE      *HttpMsg
   2011   )
   2012 {
   2013   EFI_STATUS                Status;
   2014   HTTP_PROTOCOL             *HttpInstance;
   2015   EFI_TCP6_PROTOCOL         *Tcp6;
   2016   EFI_TCP6_IO_TOKEN         *Rx6Token;
   2017   EFI_TCP4_PROTOCOL         *Tcp4;
   2018   EFI_TCP4_IO_TOKEN         *Rx4Token;
   2019 
   2020   HttpInstance   = Wrap->HttpInstance;
   2021   Tcp4 = HttpInstance->Tcp4;
   2022   Tcp6 = HttpInstance->Tcp6;
   2023   Rx4Token       = NULL;
   2024   Rx6Token       = NULL;
   2025 
   2026   if (HttpInstance->LocalAddressIsIPv6) {
   2027     ASSERT (Tcp6 != NULL);
   2028   } else {
   2029     ASSERT (Tcp4 != NULL);
   2030   }
   2031 
   2032   if (HttpInstance->LocalAddressIsIPv6) {
   2033     Rx6Token = &Wrap->TcpWrap.Rx6Token;
   2034     Rx6Token ->Packet.RxData->DataLength = (UINT32) HttpMsg->BodyLength;
   2035     Rx6Token ->Packet.RxData->FragmentTable[0].FragmentLength = (UINT32) HttpMsg->BodyLength;
   2036     Rx6Token ->Packet.RxData->FragmentTable[0].FragmentBuffer = (VOID *) HttpMsg->Body;
   2037     Rx6Token->CompletionToken.Status = EFI_NOT_READY;
   2038 
   2039     Status = Tcp6->Receive (Tcp6, Rx6Token);
   2040     if (EFI_ERROR (Status)) {
   2041       DEBUG ((EFI_D_ERROR, "Tcp6 receive failed: %r\n", Status));
   2042       return Status;
   2043     }
   2044   } else {
   2045     Rx4Token = &Wrap->TcpWrap.Rx4Token;
   2046     Rx4Token->Packet.RxData->DataLength = (UINT32) HttpMsg->BodyLength;
   2047     Rx4Token->Packet.RxData->FragmentTable[0].FragmentLength = (UINT32) HttpMsg->BodyLength;
   2048     Rx4Token->Packet.RxData->FragmentTable[0].FragmentBuffer = (VOID *) HttpMsg->Body;
   2049 
   2050     Rx4Token->CompletionToken.Status = EFI_NOT_READY;
   2051     Status = Tcp4->Receive (Tcp4, Rx4Token);
   2052     if (EFI_ERROR (Status)) {
   2053       DEBUG ((EFI_D_ERROR, "Tcp4 receive failed: %r\n", Status));
   2054       return Status;
   2055     }
   2056   }
   2057 
   2058   return EFI_SUCCESS;
   2059 
   2060 }
   2061 
   2062 /**
   2063   Clean up Tcp Tokens while the Tcp transmission error occurs.
   2064 
   2065   @param[in]  Wrap               Pointer to HTTP token's wrap data.
   2066 
   2067 **/
   2068 VOID
   2069 HttpTcpTokenCleanup (
   2070   IN  HTTP_TOKEN_WRAP      *Wrap
   2071   )
   2072 {
   2073   HTTP_PROTOCOL            *HttpInstance;
   2074   EFI_TCP4_IO_TOKEN        *Rx4Token;
   2075   EFI_TCP6_IO_TOKEN        *Rx6Token;
   2076 
   2077   ASSERT (Wrap != NULL);
   2078   HttpInstance   = Wrap->HttpInstance;
   2079   Rx4Token       = NULL;
   2080   Rx6Token       = NULL;
   2081 
   2082   if (HttpInstance->LocalAddressIsIPv6) {
   2083     Rx6Token = &Wrap->TcpWrap.Rx6Token;
   2084 
   2085     if (Rx6Token->CompletionToken.Event != NULL) {
   2086       gBS->CloseEvent (Rx6Token->CompletionToken.Event);
   2087       Rx6Token->CompletionToken.Event = NULL;
   2088     }
   2089 
   2090     FreePool (Wrap);
   2091 
   2092     Rx6Token = &HttpInstance->Rx6Token;
   2093 
   2094     if (Rx6Token->CompletionToken.Event != NULL) {
   2095       gBS->CloseEvent (Rx6Token->CompletionToken.Event);
   2096       Rx6Token->CompletionToken.Event = NULL;
   2097     }
   2098 
   2099     if (Rx6Token->Packet.RxData->FragmentTable[0].FragmentBuffer != NULL) {
   2100       FreePool (Rx6Token->Packet.RxData->FragmentTable[0].FragmentBuffer);
   2101       Rx6Token->Packet.RxData->FragmentTable[0].FragmentBuffer = NULL;
   2102     }
   2103 
   2104   } else {
   2105     Rx4Token = &Wrap->TcpWrap.Rx4Token;
   2106 
   2107     if (Rx4Token->CompletionToken.Event != NULL) {
   2108       gBS->CloseEvent (Rx4Token->CompletionToken.Event);
   2109       Rx4Token->CompletionToken.Event = NULL;
   2110     }
   2111 
   2112     FreePool (Wrap);
   2113 
   2114     Rx4Token = &HttpInstance->Rx4Token;
   2115 
   2116     if (Rx4Token->CompletionToken.Event != NULL) {
   2117       gBS->CloseEvent (Rx4Token->CompletionToken.Event);
   2118       Rx4Token->CompletionToken.Event = NULL;
   2119     }
   2120 
   2121 
   2122     if (Rx4Token->Packet.RxData->FragmentTable[0].FragmentBuffer != NULL) {
   2123       FreePool (Rx4Token->Packet.RxData->FragmentTable[0].FragmentBuffer);
   2124       Rx4Token->Packet.RxData->FragmentTable[0].FragmentBuffer = NULL;
   2125     }
   2126   }
   2127 
   2128 }
   2129