public inbox for devel@edk2.groups.io
 help / color / mirror / Atom feed
From: "Saloni Kasbekar" <saloni.kasbekar@intel.com>
To: devel@edk2.groups.io
Cc: Saloni Kasbekar <saloni.kasbekar@intel.com>,
	Maciej Rabeda <maciej.rabeda@linux.intel.com>,
	Wu Jiaxin <jiaxin.wu@intel.com>, Siyuan Fu <siyuan.fu@intel.com>
Subject: [edk2-staging/HttpProxy PATCH v3 4/7] NetworkPkg: Add Proxy Support to HTTP_PROTOCOL
Date: Fri,  2 Dec 2022 11:12:23 -0800	[thread overview]
Message-ID: <5725304efc9d9463081770ed01fb3d07c405ab2e.1670008048.git.saloni.kasbekar@intel.com> (raw)
In-Reply-To: <cover.1670008048.git.saloni.kasbekar@intel.com>

REF: https://bugzilla.tianocore.org/show_bug.cgi?id=3951

Update HTTP Protocol with variables to support Proxy
Use state machine to call HttpBootGetBootFile()
Add switch/case for EfiHttpRequest request method

Cc: Maciej Rabeda <maciej.rabeda@linux.intel.com>
Cc: Wu Jiaxin <jiaxin.wu@intel.com>
Cc: Siyuan Fu <siyuan.fu@intel.com>
Signed-off-by: Saloni Kasbekar <saloni.kasbekar@intel.com>
---
 NetworkPkg/HttpBootDxe/HttpBootImpl.c | 178 +++++++++++++++++---------
 NetworkPkg/HttpBootDxe/HttpBootImpl.h |   7 +
 NetworkPkg/HttpDxe/HttpImpl.c         |  59 +++++++--
 NetworkPkg/HttpDxe/HttpProto.c        |  18 ++-
 NetworkPkg/HttpDxe/HttpProto.h        |   9 ++
 5 files changed, 199 insertions(+), 72 deletions(-)

diff --git a/NetworkPkg/HttpBootDxe/HttpBootImpl.c b/NetworkPkg/HttpBootDxe/HttpBootImpl.c
index 5735b96d9e..4748de0603 100644
--- a/NetworkPkg/HttpBootDxe/HttpBootImpl.c
+++ b/NetworkPkg/HttpBootDxe/HttpBootImpl.c
@@ -278,6 +278,122 @@ HttpBootDhcp (
   return Status;
 }
 
+/**
+  Issue calls to HttpBootGetBootFile() based on current Boot File State
+
+  @param[in]          Private         The pointer to the driver's private data.
+  @param[in, out]     BufferSize      On input the size of Buffer in bytes. On output with a return
+                                      code of EFI_SUCCESS, the amount of data transferred to
+                                      Buffer. On output with a return code of EFI_BUFFER_TOO_SMALL,
+                                      the size of Buffer required to retrieve the requested file.
+  @param[in]          Buffer          The memory buffer to transfer the file to. If Buffer is NULL,
+                                      then the size of the requested file is returned in
+                                      BufferSize.
+  @param[out]         ImageType       The image type of the downloaded file.
+
+  @retval EFI_SUCCESS              The file was loaded.
+  @retval EFI_INVALID_PARAMETER    BufferSize is NULL or Buffer Size is not NULL but Buffer is NULL.
+  @retval EFI_OUT_OF_RESOURCES     Could not allocate needed resources
+  @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_ACCESS_DENIED        Server authentication failed.
+  @retval Others                   Unexpected error happened.
+
+**/
+EFI_STATUS
+HttpBootGetBootFileCaller (
+  IN     HTTP_BOOT_PRIVATE_DATA  *Private,
+  IN OUT UINTN                   *BufferSize,
+  IN     VOID                    *Buffer        OPTIONAL,
+  OUT HTTP_BOOT_IMAGE_TYPE       *ImageType
+  )
+{
+  HTTP_GET_BOOT_FILE_STATE  State;
+  EFI_STATUS                Status;
+
+  if (Private->BootFileSize == 0) {
+    State = GetBootFileHead;
+  } else {
+    State = LoadBootFile;
+  }
+
+  for ( ; ;) {
+    switch (State) {
+      case GetBootFileHead:
+        //
+        // Try to use HTTP HEAD method.
+        //
+        Status = HttpBootGetBootFile (
+                   Private,
+                   TRUE,
+                   &Private->BootFileSize,
+                   NULL,
+                   &Private->ImageType
+                   );
+        if ((EFI_ERROR (Status)) && (Status != EFI_BUFFER_TOO_SMALL)) {
+          if ((Private->AuthData != NULL) && (Status == EFI_ACCESS_DENIED)) {
+            //
+            // Try to use HTTP HEAD method again since the Authentication information is provided.
+            //
+            State = GetBootFileHead;
+          } else {
+            State = GetBootFileGet;
+          }
+        } else {
+          State = LoadBootFile;
+        }
+
+        break;
+
+      case GetBootFileGet:
+        //
+        // Failed to get file size by HEAD method, may be trunked encoding, try HTTP GET method.
+        //
+        ASSERT (Private->BootFileSize == 0);
+        Status = HttpBootGetBootFile (
+                   Private,
+                   FALSE,
+                   &Private->BootFileSize,
+                   NULL,
+                   &Private->ImageType
+                   );
+        if (EFI_ERROR (Status) && (Status != EFI_BUFFER_TOO_SMALL)) {
+          State = GetBootFileError;
+        } else {
+          State = LoadBootFile;
+        }
+
+        break;
+
+      case LoadBootFile:
+        if (*BufferSize < Private->BootFileSize) {
+          *BufferSize = Private->BootFileSize;
+          *ImageType  = Private->ImageType;
+          Status      = EFI_BUFFER_TOO_SMALL;
+          return Status;
+        }
+
+        //
+        // Load the boot file into Buffer
+        //
+        Status = HttpBootGetBootFile (
+                   Private,
+                   FALSE,
+                   BufferSize,
+                   Buffer,
+                   ImageType
+                   );
+        return Status;
+
+      case GetBootFileError:
+      default:
+        AsciiPrint ("\n  Error: Could not retrieve NBP file size from HTTP server.\n");
+        return Status;
+    }
+  }
+}
+
 /**
   Attempt to download the boot file through HTTP message exchange.
 
@@ -349,68 +465,10 @@ HttpBootLoadFile (
     }
   }
 
-  if (Private->BootFileSize == 0) {
-    //
-    // Discover the information about the bootfile if we haven't.
-    //
-
-    //
-    // Try to use HTTP HEAD method.
-    //
-    Status = HttpBootGetBootFile (
-               Private,
-               TRUE,
-               &Private->BootFileSize,
-               NULL,
-               &Private->ImageType
-               );
-    if ((Private->AuthData != NULL) && (Status == EFI_ACCESS_DENIED)) {
-      //
-      // Try to use HTTP HEAD method again since the Authentication information is provided.
-      //
-      Status = HttpBootGetBootFile (
-                 Private,
-                 TRUE,
-                 &Private->BootFileSize,
-                 NULL,
-                 &Private->ImageType
-                 );
-    } else if ((EFI_ERROR (Status)) && (Status != EFI_BUFFER_TOO_SMALL)) {
-      //
-      // Failed to get file size by HEAD method, may be trunked encoding, try HTTP GET method.
-      //
-      ASSERT (Private->BootFileSize == 0);
-      Status = HttpBootGetBootFile (
-                 Private,
-                 FALSE,
-                 &Private->BootFileSize,
-                 NULL,
-                 &Private->ImageType
-                 );
-      if (EFI_ERROR (Status) && (Status != EFI_BUFFER_TOO_SMALL)) {
-        AsciiPrint ("\n  Error: Could not retrieve NBP file size from HTTP server.\n");
-        goto ON_EXIT;
-      }
-    }
-  }
-
-  if (*BufferSize < Private->BootFileSize) {
-    *BufferSize = Private->BootFileSize;
-    *ImageType  = Private->ImageType;
-    Status      = EFI_BUFFER_TOO_SMALL;
-    goto ON_EXIT;
-  }
-
   //
-  // Load the boot file into Buffer
+  // Load the Boot File
   //
-  Status = HttpBootGetBootFile (
-             Private,
-             FALSE,
-             BufferSize,
-             Buffer,
-             ImageType
-             );
+  Status = HttpBootGetBootFileCaller (Private, BufferSize, Buffer, ImageType);
 
 ON_EXIT:
   HttpBootUninstallCallback (Private);
diff --git a/NetworkPkg/HttpBootDxe/HttpBootImpl.h b/NetworkPkg/HttpBootDxe/HttpBootImpl.h
index 55adc9cb50..33da4fec51 100644
--- a/NetworkPkg/HttpBootDxe/HttpBootImpl.h
+++ b/NetworkPkg/HttpBootDxe/HttpBootImpl.h
@@ -11,6 +11,13 @@ SPDX-License-Identifier: BSD-2-Clause-Patent
 
 #define HTTP_BOOT_CHECK_MEDIA_WAITING_TIME  EFI_TIMER_PERIOD_SECONDS(20)
 
+typedef enum {
+  GetBootFileHead,
+  GetBootFileGet,
+  LoadBootFile,
+  GetBootFileError
+} HTTP_GET_BOOT_FILE_STATE;
+
 /**
   Attempt to complete a DHCPv4 D.O.R.A or DHCPv6 S.R.A.A sequence to retrieve the boot resource information.
 
diff --git a/NetworkPkg/HttpDxe/HttpImpl.c b/NetworkPkg/HttpDxe/HttpImpl.c
index 7c5c925cf7..a761ce3d5d 100644
--- a/NetworkPkg/HttpDxe/HttpImpl.c
+++ b/NetworkPkg/HttpDxe/HttpImpl.c
@@ -162,6 +162,7 @@ EfiHttpConfigure (
     HttpInstance->TimeOutMillisec    = HttpConfigData->TimeOutMillisec;
     HttpInstance->LocalAddressIsIPv6 = HttpConfigData->LocalAddressIsIPv6;
     HttpInstance->ConnectionClose    = FALSE;
+    HttpInstance->ProxyConnected     = FALSE;
 
     if (HttpConfigData->LocalAddressIsIPv6) {
       CopyMem (
@@ -244,6 +245,8 @@ EfiHttpRequest (
   CHAR8                  *RequestMsg;
   CHAR8                  *Url;
   UINTN                  UrlLen;
+  CHAR8                  *ProxyUrl;
+  UINTN                  ProxyUrlLen;
   CHAR16                 *HostNameStr;
   HTTP_TOKEN_WRAP        *Wrap;
   CHAR8                  *FileUrl;
@@ -254,6 +257,7 @@ EfiHttpRequest (
   // Initializations
   //
   Url          = NULL;
+  ProxyUrl     = NULL;
   UrlParser    = NULL;
   RemotePort   = 0;
   HostName     = NULL;
@@ -277,12 +281,18 @@ EfiHttpRequest (
   //
   // Only support GET, HEAD, DELETE, PATCH, PUT and POST method in current implementation.
   //
-  if ((Request != NULL) && (Request->Method != HttpMethodGet) &&
-      (Request->Method != HttpMethodHead) && (Request->Method != HttpMethodDelete) &&
-      (Request->Method != HttpMethodPut) && (Request->Method != HttpMethodPost) &&
-      (Request->Method != HttpMethodPatch))
-  {
-    return EFI_UNSUPPORTED;
+  if (Request != NULL) {
+    switch (Request->Method) {
+      case HttpMethodGet:
+      case HttpMethodHead:
+      case HttpMethodDelete:
+      case HttpMethodPut:
+      case HttpMethodPost:
+      case HttpMethodPatch:
+        break;
+      default:
+        return EFI_UNSUPPORTED;
+    }
   }
 
   HttpInstance = HTTP_INSTANCE_FROM_PROTOCOL (This);
@@ -337,22 +347,49 @@ EfiHttpRequest (
     }
 
     //
-    // Parse the URI of the remote host.
+    // Parse the Request URI.
     //
     Url    = HttpInstance->Url;
     UrlLen = StrLen (Request->Url) + 1;
-    if (UrlLen > HTTP_URL_BUFFER_LEN) {
+    if (UrlLen > HttpInstance->UrlLen) {
       Url = AllocateZeroPool (UrlLen);
       if (Url == NULL) {
         return EFI_OUT_OF_RESOURCES;
       }
 
-      FreePool (HttpInstance->Url);
-      HttpInstance->Url = Url;
+      if (HttpInstance->Url != NULL) {
+        FreePool (HttpInstance->Url);
+      }
+
+      HttpInstance->Url    = Url;
+      HttpInstance->UrlLen = UrlLen;
     }
 
     UnicodeStrToAsciiStrS (Request->Url, Url, UrlLen);
 
+    //
+    // In case of HTTP Connect, parse proxy URI from Request.
+    //
+    if (Request->Method == HttpMethodConnect) {
+      ProxyUrl    = HttpInstance->ProxyUrl;
+      ProxyUrlLen = StrLen (Request->ProxyUrl) + 1;
+      if (ProxyUrlLen > HttpInstance->ProxyUrlLen) {
+        ProxyUrl = AllocateZeroPool (ProxyUrlLen);
+        if (ProxyUrl == NULL) {
+          return EFI_OUT_OF_RESOURCES;
+        }
+
+        if (HttpInstance->ProxyUrl != NULL) {
+          FreePool (HttpInstance->ProxyUrl);
+        }
+
+        HttpInstance->ProxyUrl    = ProxyUrl;
+        HttpInstance->ProxyUrlLen = ProxyUrlLen;
+      }
+
+      UnicodeStrToAsciiStrS (Request->ProxyUrl, ProxyUrl, ProxyUrlLen);
+    }
+
     //
     // From the information in Url, the HTTP instance will
     // be able to determine whether to use http or https.
@@ -395,7 +432,7 @@ EfiHttpRequest (
     }
 
     UrlParser = NULL;
-    Status    = HttpParseUrl (Url, (UINT32)AsciiStrLen (Url), FALSE, &UrlParser);
+    Status = HttpParseUrl (Url, (UINT32)AsciiStrLen (Url), FALSE, &UrlParser);
     if (EFI_ERROR (Status)) {
       goto Error1;
     }
diff --git a/NetworkPkg/HttpDxe/HttpProto.c b/NetworkPkg/HttpDxe/HttpProto.c
index 33ae622c3f..6767d90c7d 100644
--- a/NetworkPkg/HttpDxe/HttpProto.c
+++ b/NetworkPkg/HttpDxe/HttpProto.c
@@ -737,6 +737,8 @@ HttpInitProtocol (
     goto ON_ERROR;
   }
 
+  HttpInstance->UrlLen = HTTP_URL_BUFFER_LEN;
+
   return EFI_SUCCESS;
 
 ON_ERROR:
@@ -846,9 +848,23 @@ HttpCleanProtocol (
 
   if (HttpInstance->Url != NULL) {
     FreePool (HttpInstance->Url);
-    HttpInstance->Url = NULL;
+    HttpInstance->Url    = NULL;
+    HttpInstance->UrlLen = 0;
+  }
+
+  if (HttpInstance->ProxyUrl != NULL) {
+    FreePool (HttpInstance->ProxyUrl);
+    HttpInstance->ProxyUrl    = NULL;
+    HttpInstance->ProxyUrlLen = 0;
   }
 
+  if (HttpInstance->EndPointHostName != NULL) {
+    FreePool (HttpInstance->EndPointHostName);
+    HttpInstance->EndPointHostName = NULL;
+  }
+
+  HttpInstance->ProxyConnected = FALSE;
+
   NetMapClean (&HttpInstance->TxTokens);
   NetMapClean (&HttpInstance->RxTokens);
 
diff --git a/NetworkPkg/HttpDxe/HttpProto.h b/NetworkPkg/HttpDxe/HttpProto.h
index 620eb39158..3e4e86dad9 100644
--- a/NetworkPkg/HttpDxe/HttpProto.h
+++ b/NetworkPkg/HttpDxe/HttpProto.h
@@ -164,6 +164,15 @@ typedef struct _HTTP_PROTOCOL {
   NET_MAP                           RxTokens;
 
   CHAR8                             *Url;
+  UINTN                             UrlLen;
+
+  //
+  // Proxy support
+  //
+  CHAR8                             *ProxyUrl;
+  UINTN                             ProxyUrlLen;
+  BOOLEAN                           ProxyConnected;
+  CHAR8                             *EndPointHostName;
 
   //
   // Https Support
-- 
2.36.1.windows.1


  parent reply	other threads:[~2022-12-02 19:12 UTC|newest]

Thread overview: 8+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2022-12-02 19:12 [edk2-staging/HttpProxy PATCH v3 0/7] Support HTTPS Proxy Server for HTTP Boot Saloni Kasbekar
2022-12-02 19:12 ` [edk2-staging/HttpProxy PATCH v3 1/7] MdeModulePkg/Library: Support multi-URI HTTP Boot device path Saloni Kasbekar
2022-12-02 19:12 ` [edk2-staging/HttpProxy PATCH v3 2/7] MdePkg/Include: Add Proxy Server URL in EFI_HTTP_REQUEST_DATA Saloni Kasbekar
2022-12-02 19:12 ` [edk2-staging/HttpProxy PATCH v3 3/7] NetworkPkg/HttpBootDxe: Update HTTP Boot Driver with parsed Proxy URL Saloni Kasbekar
2022-12-02 19:12 ` Saloni Kasbekar [this message]
2022-12-02 19:12 ` [edk2-staging/HttpProxy PATCH v3 5/7] NetworkPkg: Add support for HTTP CONNECT Method Saloni Kasbekar
2022-12-02 19:12 ` [edk2-staging/HttpProxy PATCH v3 6/7] NetworkPkg/HttpDxe: Support HTTPS EndPoint server with Proxy Saloni Kasbekar
2022-12-02 19:12 ` [edk2-staging/HttpProxy PATCH v3 7/7] NetworkPkg/HttpBootDxe: Add Proxy URI input in setup menu Saloni Kasbekar

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-list from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=5725304efc9d9463081770ed01fb3d07c405ab2e.1670008048.git.saloni.kasbekar@intel.com \
    --to=devel@edk2.groups.io \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox