]> git.proxmox.com Git - mirror_edk2.git/blobdiff - NetworkPkg/HttpDxe/HttpImpl.c
MdeModulePkg-DxeCore: rename CoreGetMemoryMapPropertiesTable
[mirror_edk2.git] / NetworkPkg / HttpDxe / HttpImpl.c
index 2f4ce89ddbd1d05f1168cb66a10890a7787ffd20..7a236f40e020e5da0e2f408c4784f3c6fd9cb047 100644 (file)
@@ -1,8 +1,8 @@
 /** @file\r
   Implementation of EFI_HTTP_PROTOCOL protocol interfaces.\r
 \r
-  Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>\r
-  (C) Copyright 2015 Hewlett Packard Enterprise Development LP<BR>\r
+  Copyright (c) 2015 - 2016, Intel Corporation. All rights reserved.<BR>\r
+  (C) Copyright 2015-2016 Hewlett Packard Enterprise Development LP<BR>\r
 \r
   This program and the accompanying materials\r
   are licensed and made available under the terms and conditions of the BSD License\r
@@ -39,8 +39,11 @@ EFI_HTTP_PROTOCOL  mEfiHttpTemplate = {
   @retval EFI_INVALID_PARAMETER   One or more of the following conditions is TRUE:\r
                                   This is NULL.\r
                                   HttpConfigData is NULL.\r
-                                  HttpConfigData->AccessPoint is NULL.\r
-  @retval EFI_NOT_STARTED         The HTTP instance is not configured.\r
+                                  HttpInstance->LocalAddressIsIPv6 is FALSE and\r
+                                  HttpConfigData->IPv4Node is NULL.\r
+                                  HttpInstance->LocalAddressIsIPv6 is TRUE and\r
+                                  HttpConfigData->IPv6Node is NULL.\r
+  @retval EFI_NOT_STARTED         This EFI HTTP Protocol instance has not been started.\r
 \r
 **/\r
 EFI_STATUS\r
@@ -51,16 +54,22 @@ EfiHttpGetModeData (
   )\r
 {\r
   HTTP_PROTOCOL                 *HttpInstance;\r
-  EFI_HTTPv4_ACCESS_POINT       *Http4AccessPoint;\r
-  EFI_HTTPv6_ACCESS_POINT       *Http6AccessPoint;\r
 \r
+  //\r
+  // Check input parameters.\r
+  //\r
   if ((This == NULL) || (HttpConfigData == NULL)) {\r
     return EFI_INVALID_PARAMETER;\r
   }\r
-  \r
+\r
   HttpInstance = HTTP_INSTANCE_FROM_PROTOCOL (This);\r
   ASSERT (HttpInstance != NULL);\r
-  \r
+\r
+  if ((HttpInstance->LocalAddressIsIPv6 && HttpConfigData->AccessPoint.IPv6Node == NULL) ||\r
+      (!HttpInstance->LocalAddressIsIPv6 && HttpConfigData->AccessPoint.IPv4Node == NULL)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
   if (HttpInstance->State < HTTP_STATE_HTTP_CONFIGED) {\r
     return EFI_NOT_STARTED;\r
   }\r
@@ -70,21 +79,17 @@ EfiHttpGetModeData (
   HttpConfigData->LocalAddressIsIPv6 = HttpInstance->LocalAddressIsIPv6;\r
 \r
   if (HttpInstance->LocalAddressIsIPv6) {\r
-    Http6AccessPoint = AllocateZeroPool (sizeof (EFI_HTTPv6_ACCESS_POINT));\r
     CopyMem (\r
-      Http6AccessPoint,\r
+      HttpConfigData->AccessPoint.IPv6Node,\r
       &HttpInstance->Ipv6Node,\r
       sizeof (HttpInstance->Ipv6Node)\r
     );\r
-    HttpConfigData->AccessPoint.IPv6Node = Http6AccessPoint;\r
   } else {\r
-    Http4AccessPoint = AllocateZeroPool (sizeof (EFI_HTTPv4_ACCESS_POINT));\r
     CopyMem (\r
-      Http4AccessPoint,\r
+      HttpConfigData->AccessPoint.IPv4Node,\r
       &HttpInstance->IPv4Node,\r
       sizeof (HttpInstance->IPv4Node)\r
       );\r
-    HttpConfigData->AccessPoint.IPv4Node = Http4AccessPoint;\r
   }\r
 \r
   return EFI_SUCCESS;\r
@@ -100,8 +105,8 @@ EfiHttpGetModeData (
   connections with remote hosts, canceling all asynchronous tokens, and flush request\r
   and response buffers without informing the appropriate hosts.\r
 \r
-  Except for GetModeData() and Configure(), No other EFI HTTP function can be executed\r
-  by this instance until the Configure() function is executed and returns successfully.\r
+  No other EFI HTTP function can be executed by this instance until the Configure()\r
+  function is executed and returns successfully.\r
 \r
   @param[in]  This                Pointer to EFI_HTTP_PROTOCOL instance.\r
   @param[in]  HttpConfigData      Pointer to the configure data to configure the instance.\r
@@ -109,6 +114,7 @@ EfiHttpGetModeData (
   @retval EFI_SUCCESS             Operation succeeded.\r
   @retval EFI_INVALID_PARAMETER   One or more of the following conditions is TRUE:\r
                                   This is NULL.\r
+                                  HttpConfigData is NULL.\r
                                   HttpConfigData->LocalAddressIsIPv6 is FALSE and\r
                                   HttpConfigData->IPv4Node is NULL.\r
                                   HttpConfigData->LocalAddressIsIPv6 is TRUE and\r
@@ -134,9 +140,10 @@ EfiHttpConfigure (
   //\r
   // Check input parameters.\r
   //\r
-  if (This == NULL || \r
-     (HttpConfigData != NULL && ((HttpConfigData->LocalAddressIsIPv6 && HttpConfigData->AccessPoint.IPv6Node == NULL) ||\r
-                                 (!HttpConfigData->LocalAddressIsIPv6 && HttpConfigData->AccessPoint.IPv4Node == NULL)))) {\r
+  if (This == NULL ||\r
+      HttpConfigData == NULL ||\r
+     ((HttpConfigData->LocalAddressIsIPv6 && HttpConfigData->AccessPoint.IPv6Node == NULL) ||\r
+     (!HttpConfigData->LocalAddressIsIPv6 && HttpConfigData->AccessPoint.IPv4Node == NULL))) {\r
     return EFI_INVALID_PARAMETER;\r
   }\r
 \r
@@ -169,6 +176,7 @@ EfiHttpConfigure (
         sizeof (HttpInstance->IPv4Node)\r
         );\r
     }\r
+    \r
     //\r
     // Creat Tcp child\r
     //\r
@@ -210,6 +218,7 @@ EfiHttpConfigure (
                                   implementation.\r
   @retval EFI_INVALID_PARAMETER   One or more of the following conditions is TRUE:\r
                                   This is NULL.\r
+                                  Token is NULL.\r
                                   Token->Message is NULL.\r
                                   Token->Message->Body is not NULL,\r
                                   Token->Message->BodyLength is non-zero, and\r
@@ -232,12 +241,13 @@ EfiHttpRequest (
   HTTP_PROTOCOL                 *HttpInstance;\r
   BOOLEAN                       Configure;\r
   BOOLEAN                       ReConfigure;\r
-  CHAR8                         *RequestStr;\r
+  CHAR8                         *RequestMsg;\r
   CHAR8                         *Url;\r
   UINTN                         UrlLen;\r
   CHAR16                        *HostNameStr;\r
   HTTP_TOKEN_WRAP               *Wrap;\r
   CHAR8                         *FileUrl;\r
+  UINTN                         RequestMsgSize;\r
   \r
   if ((This == NULL) || (Token == NULL)) {\r
     return EFI_INVALID_PARAMETER;\r
@@ -306,7 +316,7 @@ EfiHttpRequest (
     goto Error1;\r
   }\r
 \r
-  RequestStr = NULL;\r
+  RequestMsg = NULL;\r
   HostName   = NULL;\r
   Status     = HttpUrlGetHostName (Url, UrlParser, &HostName);\r
   if (EFI_ERROR (Status)) {\r
@@ -317,7 +327,11 @@ EfiHttpRequest (
   if (EFI_ERROR (Status)) {\r
     RemotePort = HTTP_DEFAULT_PORT;\r
   }\r
-\r
+  //\r
+  // If Configure is TRUE, it indicates the first time to call Request();\r
+  // If ReConfigure is TRUE, it indicates the request URL is not same\r
+  // with the previous call to Request();\r
+  //\r
   Configure   = TRUE;\r
   ReConfigure = TRUE;  \r
 \r
@@ -427,7 +441,11 @@ EfiHttpRequest (
     //\r
     // The request URL is different from previous calls to Request(), close existing TCP instance.\r
     //\r
-    ASSERT (HttpInstance->Tcp4 != NULL &&HttpInstance->Tcp6 != NULL);\r
+    if (!HttpInstance->LocalAddressIsIPv6) {\r
+      ASSERT (HttpInstance->Tcp4 != NULL);\r
+    } else {\r
+      ASSERT (HttpInstance->Tcp6 != NULL);\r
+    }\r
     HttpCloseConnection (HttpInstance);\r
     EfiHttpCancel (This, NULL);\r
   }\r
@@ -445,13 +463,12 @@ EfiHttpRequest (
   Wrap->HttpInstance   = HttpInstance;\r
   Wrap->TcpWrap.Method = Request->Method;\r
 \r
-  if (Configure) {\r
-    Status = HttpInitTcp (HttpInstance, Wrap);\r
-    if (EFI_ERROR (Status)) {\r
-      goto Error2;\r
-    }\r
+  Status = HttpInitTcp (HttpInstance, Wrap, Configure);\r
+  if (EFI_ERROR (Status)) {\r
+    goto Error2;\r
+  }  \r
 \r
-  } else {\r
+  if (!Configure) {\r
     //\r
     // For the new HTTP token, create TX TCP token events.    \r
     //\r
@@ -460,7 +477,7 @@ EfiHttpRequest (
       goto Error1;\r
     }\r
   }\r
-\r
+  \r
   //\r
   // Create request message.\r
   //\r
@@ -482,9 +499,10 @@ EfiHttpRequest (
       goto Error3;\r
     }\r
   }\r
-  RequestStr = HttpGenRequestString (HttpInstance, HttpMsg, FileUrl);\r
-  if (RequestStr == NULL) {\r
-    Status = EFI_OUT_OF_RESOURCES;\r
+\r
+  Status = HttpGenRequestMessage (HttpMsg, FileUrl, &RequestMsg, &RequestMsgSize);\r
+\r
+  if (EFI_ERROR (Status)) {\r
     goto Error3;\r
   }\r
 \r
@@ -499,8 +517,8 @@ EfiHttpRequest (
   Status = HttpTransmitTcp (\r
              HttpInstance,\r
              Wrap,\r
-             (UINT8*) RequestStr,\r
-             AsciiStrLen (RequestStr)\r
+             (UINT8*) RequestMsg,\r
+             RequestMsgSize\r
              );\r
   if (EFI_ERROR (Status)) {\r
     goto Error5;    \r
@@ -518,8 +536,8 @@ Error5:
     NetMapRemoveTail (&HttpInstance->TxTokens, NULL);\r
 \r
 Error4:\r
-  if (RequestStr != NULL) {\r
-    FreePool (RequestStr);\r
+  if (RequestMsg != NULL) {\r
+    FreePool (RequestMsg);\r
   }  \r
 \r
 Error3:\r
@@ -709,8 +727,6 @@ HttpCancel (
   @retval EFI_SUCCESS             Request and Response queues are successfully flushed.\r
   @retval EFI_INVALID_PARAMETER   This is NULL.\r
   @retval EFI_NOT_STARTED         This instance hasn't been configured.\r
-  @retval EFI_NO_MAPPING          When using the default address, configuration (DHCP,\r
-                                  BOOTP, RARP, etc.) hasn't finished yet.\r
   @retval EFI_NOT_FOUND           The asynchronous request or response token is not\r
                                   found.\r
   @retval EFI_UNSUPPORTED         The implementation does not support this function.\r
@@ -764,6 +780,8 @@ HttpBodyParserCallback (
   )\r
 {\r
   HTTP_TOKEN_WRAP               *Wrap;\r
+  UINTN                         BodyLength;\r
+  CHAR8                         *Body;\r
 \r
   if (EventType != BodyParseEventOnComplete) {\r
     return EFI_SUCCESS;\r
@@ -774,7 +792,14 @@ HttpBodyParserCallback (
   }\r
 \r
   Wrap = (HTTP_TOKEN_WRAP *) Context;\r
-  Wrap->HttpInstance->NextMsg = Data;\r
+  Body = Wrap->HttpToken->Message->Body;\r
+  BodyLength = Wrap->HttpToken->Message->BodyLength;\r
+  if (Data < Body + BodyLength) {\r
+    Wrap->HttpInstance->NextMsg = Data;\r
+  } else {\r
+    Wrap->HttpInstance->NextMsg = NULL;\r
+  }\r
+  \r
 \r
   //\r
   // Free Tx4Token or Tx6Token since already received corrsponding HTTP response.\r
@@ -873,11 +898,41 @@ HttpResponseWorker (
     HttpInstance->EndofHeader = &EndofHeader;\r
     HttpInstance->HttpHeaders = &HttpHeaders;\r
 \r
-    Status = HttpTcpReceiveHeader (HttpInstance, &SizeofHeaders, &BufferSize);\r
+\r
+    if (HttpInstance->TimeoutEvent == NULL) {\r
+      //\r
+      // Create TimeoutEvent for response\r
+      //\r
+      Status = gBS->CreateEvent (\r
+                      EVT_TIMER,\r
+                      TPL_CALLBACK,\r
+                      NULL,\r
+                      NULL,\r
+                      &HttpInstance->TimeoutEvent\r
+                      );\r
+      if (EFI_ERROR (Status)) {\r
+        goto Error;\r
+      }\r
+    }\r
+\r
+    //\r
+    // Start the timer, and wait Timeout seconds to receive the header packet.\r
+    //\r
+    Status = gBS->SetTimer (HttpInstance->TimeoutEvent, TimerRelative, HTTP_RESPONSE_TIMEOUT * TICKS_PER_SECOND);\r
+    if (EFI_ERROR (Status)) {\r
+      goto Error;\r
+    }\r
+\r
+    Status = HttpTcpReceiveHeader (HttpInstance, &SizeofHeaders, &BufferSize, HttpInstance->TimeoutEvent);\r
+\r
+    gBS->SetTimer (HttpInstance->TimeoutEvent, TimerCancel, 0);\r
+\r
     if (EFI_ERROR (Status)) {\r
       goto Error;\r
     }\r
 \r
+    ASSERT (HttpHeaders != NULL);\r
+\r
     //\r
     // Cache the part of body.\r
     //\r
@@ -952,7 +1007,7 @@ HttpResponseWorker (
     HttpHeaders = NULL;\r
     \r
     HttpMsg->Data.Response->StatusCode = HttpMappingToStatusCode (StatusCode);\r
-\r
+    HttpInstance->StatusCode = StatusCode;\r
     //\r
     // Init message-body parser by header information.  \r
     //\r
@@ -1072,10 +1127,37 @@ HttpResponseWorker (
 \r
   ASSERT (HttpInstance->MsgParser != NULL);\r
 \r
+  if (HttpInstance->TimeoutEvent == NULL) {\r
+    //\r
+    // Create TimeoutEvent for response\r
+    //\r
+    Status = gBS->CreateEvent (\r
+                    EVT_TIMER,\r
+                    TPL_CALLBACK,\r
+                    NULL,\r
+                    NULL,\r
+                    &HttpInstance->TimeoutEvent\r
+                    );\r
+    if (EFI_ERROR (Status)) {\r
+      goto Error;\r
+    }\r
+  }\r
+\r
+  //\r
+  // Start the timer, and wait Timeout seconds to receive the body packet.\r
+  //\r
+  Status = gBS->SetTimer (HttpInstance->TimeoutEvent, TimerRelative, HTTP_RESPONSE_TIMEOUT * TICKS_PER_SECOND);\r
+  if (EFI_ERROR (Status)) {\r
+    goto Error;\r
+  }\r
+\r
   //\r
   // We still need receive more data when there is no cache data and MsgParser is not NULL;\r
   //\r
-  Status = HttpTcpReceiveBody (Wrap, HttpMsg);\r
+  Status = HttpTcpReceiveBody (Wrap, HttpMsg, HttpInstance->TimeoutEvent);\r
+\r
+  gBS->SetTimer (HttpInstance->TimeoutEvent, TimerCancel, 0);\r
+\r
   if (EFI_ERROR (Status)) {\r
     goto Error;\r
   }\r
@@ -1087,7 +1169,13 @@ Exit:
   if (Item != NULL) {\r
     NetMapRemoveItem (&Wrap->HttpInstance->RxTokens, Item, NULL);\r
   }\r
-  Token->Status = Status;\r
+\r
+  if (HttpInstance->StatusCode >= HTTP_ERROR_OR_NOT_SUPPORT_STATUS_CODE) {\r
+    Token->Status = EFI_HTTP_ERROR;\r
+  } else {\r
+    Token->Status = Status;\r
+  }\r
+\r
   gBS->SignalEvent (Token->Event);\r
   HttpCloseTcpRxEvent (Wrap);\r
   FreePool (Wrap);\r
@@ -1112,7 +1200,12 @@ Error:
     HttpInstance->CacheBody = NULL;\r
   }\r
 \r
-  Token->Status = Status;\r
+  if (HttpInstance->StatusCode >= HTTP_ERROR_OR_NOT_SUPPORT_STATUS_CODE) {\r
+    Token->Status = EFI_HTTP_ERROR;\r
+  } else {\r
+    Token->Status = Status;\r
+  }\r
+\r
   gBS->SignalEvent (Token->Event);\r
 \r
   return Status;  \r
@@ -1122,7 +1215,7 @@ Error:
 \r
 /**\r
   The Response() function queues an HTTP response to this HTTP instance, similar to\r
-  Receive() function in the EFI TCP driver. When the HTTP request is sent successfully,\r
+  Receive() function in the EFI TCP driver. When the HTTP response is received successfully,\r
   or if there is an error, Status in token will be updated and Event will be signaled.\r
 \r
   The HTTP driver will queue a receive token to the underlying TCP instance. When data\r
@@ -1280,14 +1373,19 @@ EfiHttpPoll (
   HttpInstance = HTTP_INSTANCE_FROM_PROTOCOL (This);\r
   ASSERT (HttpInstance != NULL);\r
 \r
-  if (HttpInstance->State != HTTP_STATE_TCP_CONNECTED || (HttpInstance->Tcp4 == NULL && \r
-                                                          HttpInstance->Tcp6 == NULL)) {\r
+  if (HttpInstance->State != HTTP_STATE_TCP_CONNECTED) {\r
     return EFI_NOT_STARTED;\r
   }\r
   \r
   if (HttpInstance->LocalAddressIsIPv6) {\r
+    if (HttpInstance->Tcp6 == NULL) {\r
+      return EFI_NOT_STARTED;\r
+    }\r
     Status = HttpInstance->Tcp6->Poll (HttpInstance->Tcp6);\r
   } else {\r
+    if (HttpInstance->Tcp4 == NULL) {\r
+      return EFI_NOT_STARTED;\r
+    }\r
     Status = HttpInstance->Tcp4->Poll (HttpInstance->Tcp4);\r
   }\r
   \r