[edk2-devel] [edk2][PATCH 1/1] HttpBoot: handle servers which may FIN after file sizing in HttpBootLoadFile

Andrei Warkentin awarkentin at vmware.com
Tue May 19 01:08:44 UTC 2020


Anyone?

FWIW I've been doing at least 20 boots a day with this, 200-300 MiB at a time. Super stable.

This is also tracked now https://bugzilla.tianocore.org/show_bug.cgi?id=2720

A
________________________________
From: devel at edk2.groups.io <devel at edk2.groups.io> on behalf of Andrei Warkentin via groups.io <andrey.warkentin=gmail.com at groups.io>
Sent: Thursday, May 14, 2020 2:02 AM
To: devel at edk2.groups.io <devel at edk2.groups.io>
Cc: maciej.rabeda at linux.intel.com <maciej.rabeda at linux.intel.com>; jiaxin.wu at intel.com <jiaxin.wu at intel.com>; siyuan.fu at intel.com <siyuan.fu at intel.com>
Subject: [edk2-devel] [edk2][PATCH 1/1] HttpBoot: handle servers which may FIN after file sizing in HttpBootLoadFile

Python http.server seems to FIN after the first HEAD request to size
the loaded file is completed and ACKed. What happens next is interesting.
On low latency connections, the GET request to download may get sent
after the server sends the FIN but before the client has a chance to
process it. The net result is:
- Server ignores GET
- HttpBootLoadFile returns EFI_CONNECTION_FIN. Boot fails.

In the other case, client handles the FIN before attempting the GET,
so there's a proper three-way handshake as part of GET.

The solution is to retry HttpBootLoadFile 2 times if it returns
EFI_CONNECTION_FIN. This is because HttpBootLoadFile may issue up to
3 requests: HEAD/GET to get size and final GET to load. Some servers
may send a FIN after each request. The first request (HEAD) is not
supposed to fail this way, so only the two subsequent GET request
may result in a FIN.

Fixes https://nam04.safelinks.protection.outlook.com/?url=https%3A%2F%2Fbugzilla.tianocore.org%2Fshow_bug.cgi%3Fid%3D2720&data=02%7C01%7Cawarkentin%40vmware.com%7C73254836459946b2441e08d7f7d4c742%7Cb39138ca3cee4b4aa4d6cd83d9dd62f0%7C0%7C0%7C637250365557622212&sdata=HOKwm430VLz1xB9yyrF3T7XKgYipWy5%2FH%2BKbWuIhm24%3D&reserved=0

Signed-off-by: Andrei Warkentin <andrey.warkentin at gmail.com>
---
 NetworkPkg/HttpBootDxe/HttpBootImpl.c | 27 +++++++++++++++++++-
 NetworkPkg/HttpDxe/HttpImpl.c         |  5 ++++
 2 files changed, 31 insertions(+), 1 deletion(-)

diff --git a/NetworkPkg/HttpBootDxe/HttpBootImpl.c b/NetworkPkg/HttpBootDxe/HttpBootImpl.c
index 4a51f35cdd..2d74d5f293 100644
--- a/NetworkPkg/HttpBootDxe/HttpBootImpl.c
+++ b/NetworkPkg/HttpBootDxe/HttpBootImpl.c
@@ -288,6 +288,7 @@ HttpBootDhcp (
   @retval EFI_NOT_STARTED             The driver is in stopped state.
   @retval EFI_BUFFER_TOO_SMALL        The BufferSize is too small to read the boot file. BufferSize has
                                       been updated with the size needed to complete the request.
+  @retval EFI_CONNECTION_FIN          Server had closed the connection while we were waiting downloading.
   @retval EFI_DEVICE_ERROR            An unexpected network error occurred.
   @retval Others                      Other errors as indicated.

@@ -535,6 +536,7 @@ HttpBootStop (
   @retval EFI_BUFFER_TOO_SMALL  The BufferSize is too small to read the current directory entry.
                                 BufferSize has been updated with the size needed to complete
                                 the request.
+  @retval EFI_CONNECTION_FIN    Server had closed the connection while we were waiting for a response.

 **/
 EFI_STATUS
@@ -553,6 +555,7 @@ HttpBootDxeLoadFile (
   BOOLEAN                       UsingIpv6;
   EFI_STATUS                    Status;
   HTTP_BOOT_IMAGE_TYPE          ImageType;
+  UINTN                         MaxTries;

   if (This == NULL || BufferSize == NULL || FilePath == NULL) {
     return EFI_INVALID_PARAMETER;
@@ -598,7 +601,29 @@ HttpBootDxeLoadFile (
   // Load the boot file.
   //
   ImageType = ImageTypeMax;
-  Status = HttpBootLoadFile (Private, BufferSize, Buffer, &ImageType);
+  //
+  // HttpBootLoadFile may issue up to 2 requests: HEAD/GET to get
+  // size and final GET to load. Some servers may send a FIN after
+  // each request. The first request (HEAD) is not supposed to
+  // fail this way, so only the two possible GETs need the special
+  // handling.
+  //
+  MaxTries = 2;
+  do {
+    Status = HttpBootLoadFile (Private, BufferSize, Buffer, &ImageType);
+    if (Status == EFI_CONNECTION_FIN) {
+      if (Private->HttpCreated) {
+        //
+        // Tear down HTTP/TCP state entirely. Http->Configure (NULL) is not
+        // sufficient (EFI_ACCESS_DENIED from TCP stack on subsequent
+        // HttpBootLoadFile.
+        //
+        HttpIoDestroyIo (&Private->HttpIo);
+        Private->HttpCreated = FALSE;
+      }
+    }
+  } while (MaxTries-- && Status == EFI_CONNECTION_FIN);
+
   if (EFI_ERROR (Status)) {
     if (Status == EFI_BUFFER_TOO_SMALL && (ImageType == ImageTypeVirtualCd || ImageType == ImageTypeVirtualDisk)) {
       Status = EFI_WARN_FILE_SYSTEM;
diff --git a/NetworkPkg/HttpDxe/HttpImpl.c b/NetworkPkg/HttpDxe/HttpImpl.c
index 5a6ecbc9d9..34a33b09f7 100644
--- a/NetworkPkg/HttpDxe/HttpImpl.c
+++ b/NetworkPkg/HttpDxe/HttpImpl.c
@@ -959,6 +959,8 @@ HttpBodyParserCallback (
   @retval EFI_OUT_OF_RESOURCES    Failed to complete the operation due to lack of resources.
   @retval EFI_NOT_READY           Can't find a corresponding Tx4Token/Tx6Token or
                                   the EFI_HTTP_UTILITIES_PROTOCOL is not available.
+  @retval EFI_CONNECTION_FIN      Server had closed the connection while we were waiting for
+                                  a response.

 **/
 EFI_STATUS
@@ -1528,6 +1530,9 @@ Error:
   @retval EFI_OUT_OF_RESOURCES    Could not allocate enough system resources.
   @retval EFI_ACCESS_DENIED       An open TCP connection is not present with the host
                                   specified by response URL.
+
+  @retval EFI_CONNECTION_FIN      Server had closed the connection while we were waiting for
+                                  a response.
 **/
 EFI_STATUS
 EFIAPI
--
2.17.1





-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.

View/Reply Online (#59772): https://edk2.groups.io/g/devel/message/59772
Mute This Topic: https://groups.io/mt/74200034/1813853
Group Owner: devel+owner at edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub  [edk2-devel-archive at redhat.com]
-=-=-=-=-=-=-=-=-=-=-=-

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://listman.redhat.com/archives/edk2-devel-archive/attachments/20200519/57fe0a0e/attachment.htm>


More information about the edk2-devel-archive mailing list