From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mga04.intel.com (mga04.intel.com [192.55.52.120]) by mx.groups.io with SMTP id smtpd.web08.392.1663797121780520189 for ; Wed, 21 Sep 2022 14:52:07 -0700 Authentication-Results: mx.groups.io; dkim=fail reason="unable to parse pub key" header.i=@intel.com header.s=intel header.b=Ega7vqE5; spf=pass (domain: intel.com, ip: 192.55.52.120, mailfrom: saloni.kasbekar@intel.com) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1663797127; x=1695333127; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=jQXX1/s9DpJ0DNbrOWYsGkQvIBOrLHzaD362rzMOqeU=; b=Ega7vqE59LBUQOlKzFc6EZs6fWBnKKAmQBL/yZJ/QBm6pYo4n08WnwH6 N2tk4HG4IxEIttgJbZwDXlWQoHyIPPsl/11P4Mm1QBwyghfMR5z92uEOa p6+xzaTWcmwnIxIDKbfhe0Nl8spENrOKuzgtB5Viwe5sLW5L6KPUN3cNF GOGsDhGb5lzeVZvbLRGRhq1tI6e8sdWuL/iHcKJXjXXbUM5w1fMlm2IJv hPDIVlPysO+3zqDH02jxz6CMawU1nsqRcOv6xLLtKx9WJSpJ6HKT50GTC UfRRNp6t0y9h0u0u1rdXr716D484DKgwsZSHdjPXYPNlLmRL9ab+3Z70z w==; X-IronPort-AV: E=McAfee;i="6500,9779,10477"; a="298850832" X-IronPort-AV: E=Sophos;i="5.93,334,1654585200"; d="scan'208";a="298850832" Received: from orsmga006.jf.intel.com ([10.7.209.51]) by fmsmga104.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 21 Sep 2022 14:52:07 -0700 X-IronPort-AV: E=Sophos;i="5.93,334,1654585200"; d="scan'208";a="597172825" Received: from fmbiosdev02.amr.corp.intel.com ([10.80.127.10]) by orsmga006-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 21 Sep 2022 14:52:06 -0700 From: "Saloni Kasbekar" To: devel@edk2.groups.io Cc: Saloni Kasbekar , Maciej Rabeda , Wu Jiaxin , Siyuan Fu Subject: [[edk2-staging/HttpProxy] 3/3] NetworkPkg/HttpBootDxe: Add Support for HTTPS Proxy Server for HTTP Boot Date: Wed, 21 Sep 2022 14:51:51 -0700 Message-Id: <7bec1a6b3b394ebafdd757cb189b7098e5bf7afa.1663795390.git.saloni.kasbekar@intel.com> X-Mailer: git-send-email 2.36.1.windows.1 In-Reply-To: References: MIME-Version: 1.0 Content-Transfer-Encoding: 8bit Add CONNECT HTTP command to create a tunnel from Proxy to EndPoint Server. Process the multi-URI device path in the input FilePath. Cc: Maciej Rabeda Cc: Wu Jiaxin Cc: Siyuan Fu Signed-off-by: Saloni Kasbekar --- NetworkPkg/HttpBootDxe/HttpBootClient.c | 211 ++++++++++++++++- NetworkPkg/HttpBootDxe/HttpBootClient.h | 15 ++ NetworkPkg/HttpBootDxe/HttpBootDxe.h | 6 + NetworkPkg/HttpBootDxe/HttpBootImpl.c | 262 ++++++++++++++++----- NetworkPkg/HttpBootDxe/HttpBootImpl.h | 8 + NetworkPkg/HttpBootDxe/HttpBootSupport.c | 24 +- NetworkPkg/HttpBootDxe/HttpBootSupport.h | 8 +- NetworkPkg/HttpDxe/HttpDriver.h | 2 + NetworkPkg/HttpDxe/HttpDxe.inf | 1 + NetworkPkg/HttpDxe/HttpImpl.c | 139 +++++++++-- NetworkPkg/HttpDxe/HttpProto.c | 41 ++-- NetworkPkg/HttpDxe/HttpProto.h | 14 +- NetworkPkg/HttpDxe/HttpsSupport.c | 14 +- NetworkPkg/Library/DxeHttpLib/DxeHttpLib.c | 5 + 14 files changed, 642 insertions(+), 108 deletions(-) diff --git a/NetworkPkg/HttpBootDxe/HttpBootClient.c b/NetworkPkg/HttpBootDxe/HttpBootClient.c index 40f64fcb6b..bfad4809de 100644 --- a/NetworkPkg/HttpBootDxe/HttpBootClient.c +++ b/NetworkPkg/HttpBootDxe/HttpBootClient.c @@ -678,6 +678,10 @@ HttpBootFreeCache ( FreePool (Cache->RequestData->Url); } + if (Cache->RequestData->EndPointUrl != NULL) { + FreePool (Cache->RequestData->EndPointUrl); + } + FreePool (Cache->RequestData); } @@ -901,6 +905,189 @@ HttpBootGetBootFileCallback ( return EFI_SUCCESS; } +/** + This function establishes a connection through a proxy server + + @param[in] Private The pointer to the driver's private data. + + @retval EFI_SUCCESS Connection successful. + @retval EFI_OUT_OF_RESOURCES Could not allocate needed resources + @retval Others Unexpected error happened. + +**/ +EFI_STATUS +HttpBootConnectProxy ( + IN HTTP_BOOT_PRIVATE_DATA *Private + ) +{ + EFI_STATUS Status; + EFI_HTTP_STATUS_CODE StatusCode; + CHAR8 *HostName; + EFI_HTTP_REQUEST_DATA *RequestData; + HTTP_IO_RESPONSE_DATA *ResponseData; + HTTP_IO *HttpIo; + HTTP_IO_HEADER *HttpIoHeader; + CHAR16 *Url; + CHAR16 *EndPointUrl; + UINTN UrlSize; + VOID *UrlParser; + + Url = NULL; + EndPointUrl = NULL; + RequestData = NULL; + ResponseData = NULL; + HttpIoHeader = NULL; + + UrlSize = AsciiStrSize (Private->BootFileUri); + Url = AllocatePool (UrlSize * sizeof (CHAR16)); + if (Url == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + AsciiStrToUnicodeStrS (Private->BootFileUri, Url, UrlSize); + + UrlSize = AsciiStrSize (Private->EndPointUri); + EndPointUrl = AllocatePool (UrlSize * (sizeof (CHAR16))); + if (EndPointUrl == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto ERROR; + } + + AsciiStrToUnicodeStrS (Private->EndPointUri, EndPointUrl, UrlSize); + + // + // Send HTTP request message. + // + + // + // Build HTTP header for the request, 2 headers are needed to send a CONNECT method: + // Host + // User + // + HttpIoHeader = HttpIoCreateHeader (2); + if (HttpIoHeader == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto ERROR; + } + + // + // Add HTTP header field 1: Host (EndPoint URI) + // + Status = HttpParseUrl (Private->EndPointUri, (UINT32)AsciiStrLen (Private->EndPointUri), FALSE, &UrlParser); + if (EFI_ERROR (Status)) { + goto ERROR; + } + + Status = HttpUrlGetHostName ( + Private->EndPointUri, + UrlParser, + &HostName + ); + if (EFI_ERROR (Status)) { + goto ERROR; + } + + Status = HttpIoSetHeader ( + HttpIoHeader, + HTTP_HEADER_HOST, + HostName + ); + if (EFI_ERROR (Status)) { + goto ERROR; + } + + // + // Add HTTP header field 2: User-Agent + // + Status = HttpIoSetHeader ( + HttpIoHeader, + HTTP_HEADER_USER_AGENT, + HTTP_USER_AGENT_EFI_HTTP_BOOT + ); + if (EFI_ERROR (Status)) { + goto ERROR; + } + + // + // Build the rest of HTTP request info. + // + RequestData = AllocatePool (sizeof (EFI_HTTP_REQUEST_DATA)); + if (RequestData == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto ERROR; + } + + RequestData->Method = HttpMethodConnect; + RequestData->Url = Url; + RequestData->EndPointUrl = EndPointUrl; + + // + // Send out the request to HTTP server. + // + HttpIo = &Private->HttpIo; + Status = HttpIoSendRequest ( + HttpIo, + RequestData, + HttpIoHeader->HeaderCount, + HttpIoHeader->Headers, + 0, + NULL + ); + if (EFI_ERROR (Status)) { + goto ERROR; + } + + // + // Receive HTTP response message. + // + + // + // Use zero BodyLength to only receive the response headers. + // + ResponseData = AllocateZeroPool (sizeof (HTTP_IO_RESPONSE_DATA)); + if (ResponseData == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto ERROR; + } + + Status = HttpIoRecvResponse ( + &Private->HttpIo, + TRUE, + ResponseData + ); + + if (EFI_ERROR (Status) || EFI_ERROR (ResponseData->Status)) { + if (EFI_ERROR (ResponseData->Status)) { + StatusCode = HttpIo->RspToken.Message->Data.Response->StatusCode; + HttpBootPrintErrorMessage (StatusCode); + Status = ResponseData->Status; + } + + goto ERROR; + } + +ERROR: + if (ResponseData != NULL) { + FreePool (ResponseData); + } + + if (RequestData != NULL) { + FreePool (RequestData); + } + + HttpIoFreeHeader (HttpIoHeader); + + if (EndPointUrl != NULL) { + FreePool (EndPointUrl); + } + + if (Url != NULL) { + FreePool (Url); + } + + return Status; +} + /** This function download the boot file by using UEFI HTTP protocol. @@ -950,6 +1137,7 @@ HttpBootGetBootFile ( UINT8 *Block; UINTN UrlSize; CHAR16 *Url; + CHAR16 *EndPointUrl; BOOLEAN IdentityMode; UINTN ReceivedSize; CHAR8 BaseAuthValue[80]; @@ -977,6 +1165,20 @@ HttpBootGetBootFile ( } AsciiStrToUnicodeStrS (Private->BootFileUri, Url, UrlSize); + + if (Private->EndPointUri != NULL) { + UrlSize = AsciiStrSize (Private->EndPointUri); + EndPointUrl = AllocatePool (UrlSize * (sizeof (CHAR16))); + if (EndPointUrl == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto ERROR_1; + } + + AsciiStrToUnicodeStrS (Private->EndPointUri, EndPointUrl, UrlSize); + } else { + EndPointUrl = NULL; + } + if (!HeaderOnly && (Buffer != NULL)) { Status = HttpBootGetFileFromCache (Private, Url, BufferSize, Buffer, ImageType); if (Status != EFI_NOT_FOUND) { @@ -1106,8 +1308,9 @@ HttpBootGetBootFile ( goto ERROR_3; } - RequestData->Method = HeaderOnly ? HttpMethodHead : HttpMethodGet; - RequestData->Url = Url; + RequestData->Method = HeaderOnly ? HttpMethodHead : HttpMethodGet; + RequestData->Url = Url; + RequestData->EndPointUrl = EndPointUrl; // // 2.3 Record the request info in a temp cache item. @@ -1441,6 +1644,10 @@ ERROR_2: } ERROR_1: + if (EndPointUrl != NULL) { + FreePool (EndPointUrl); + } + if (Url != NULL) { FreePool (Url); } diff --git a/NetworkPkg/HttpBootDxe/HttpBootClient.h b/NetworkPkg/HttpBootDxe/HttpBootClient.h index 2fba713679..fcd624f536 100644 --- a/NetworkPkg/HttpBootDxe/HttpBootClient.h +++ b/NetworkPkg/HttpBootDxe/HttpBootClient.h @@ -86,6 +86,21 @@ HttpBootCreateHttpIo ( IN HTTP_BOOT_PRIVATE_DATA *Private ); +/** + This function establishes a connection through a proxy server + + @param[in] Private The pointer to the driver's private data. + + @retval EFI_SUCCESS Connection successful. + @retval EFI_OUT_OF_RESOURCES Could not allocate needed resources + @retval Others Unexpected error happened. + +**/ +EFI_STATUS +HttpBootConnectProxy ( + IN HTTP_BOOT_PRIVATE_DATA *Private + ); + /** This function download the boot file by using UEFI HTTP protocol. diff --git a/NetworkPkg/HttpBootDxe/HttpBootDxe.h b/NetworkPkg/HttpBootDxe/HttpBootDxe.h index 5ff8ad4698..e2eb1ffc45 100644 --- a/NetworkPkg/HttpBootDxe/HttpBootDxe.h +++ b/NetworkPkg/HttpBootDxe/HttpBootDxe.h @@ -223,6 +223,12 @@ struct _HTTP_BOOT_PRIVATE_DATA { CHAR8 *FilePathUri; VOID *FilePathUriParser; + // + // URI string for the endpoint host if BootFileUri contains a proxy + // server in the path + // + CHAR8 *EndPointUri; + // // Cached HTTP data // diff --git a/NetworkPkg/HttpBootDxe/HttpBootImpl.c b/NetworkPkg/HttpBootDxe/HttpBootImpl.c index b4c61925b9..6fafd800bd 100644 --- a/NetworkPkg/HttpBootDxe/HttpBootImpl.c +++ b/NetworkPkg/HttpBootDxe/HttpBootImpl.c @@ -116,8 +116,14 @@ HttpBootStart ( UINTN Index; EFI_STATUS Status; CHAR8 *Uri; + CHAR8 *EndPointUri; + CHAR8 *BootFilePath; + UINTN FilePathUriLen; + UINTN EndPointUriLen; - Uri = NULL; + Uri = NULL; + EndPointUri = NULL; + BootFilePath = NULL; if ((Private == NULL) || (FilePath == NULL)) { return EFI_INVALID_PARAMETER; @@ -127,7 +133,7 @@ HttpBootStart ( // Check the URI in the input FilePath, in order to see whether it is // required to boot from a new specified boot file. // - Status = HttpBootParseFilePath (FilePath, &Uri); + Status = HttpBootParseFilePath (FilePath, &Uri, &EndPointUri); if (EFI_ERROR (Status)) { return EFI_INVALID_PARAMETER; } @@ -154,6 +160,10 @@ HttpBootStart ( FreePool (Uri); } + if (EndPointUri != NULL) { + FreePool (EndPointUri); + } + return Status; } } else { @@ -164,6 +174,10 @@ HttpBootStart ( FreePool (Uri); } + if (EndPointUri != NULL) { + FreePool (EndPointUri); + } + return EFI_ALREADY_STARTED; } } @@ -180,13 +194,63 @@ HttpBootStart ( FreePool (Uri); } + if (EndPointUri != NULL) { + FreePool (EndPointUri); + } + return EFI_UNSUPPORTED; } // // Record the specified URI and prepare the URI parser if needed. // - Private->FilePathUri = Uri; + Private->EndPointUri = EndPointUri; + if (Private->EndPointUri != NULL) { + // + // When a Proxy Server URI is included in the device path, the file path + // is a part of the EndPoint URI. + // Move the file path from EndPointUri to FilePathUri + // + Status = HttpParseUrl ( + Private->EndPointUri, + (UINT32)AsciiStrLen (Private->EndPointUri), + FALSE, + &Private->FilePathUriParser + ); + if (EFI_ERROR (Status)) { + return Status; + } + + Status = HttpUrlGetPath ( + Private->EndPointUri, + Private->FilePathUriParser, + &BootFilePath + ); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Remove the file path from EndPointUri + // + EndPointUriLen = AsciiStrLen (EndPointUri) - AsciiStrLen (BootFilePath) + 1; + Private->EndPointUri = AllocateZeroPool (EndPointUriLen); + AsciiSPrint (Private->EndPointUri, EndPointUriLen, "%a", EndPointUri); + + // + // Add the file path to FilePathUri + // + FilePathUriLen = AsciiStrLen (Uri) + AsciiStrLen (BootFilePath) + 1; + Private->FilePathUri = AllocateZeroPool (FilePathUriLen); + AsciiSPrint (Private->FilePathUri, FilePathUriLen, "%a%a", Uri, BootFilePath); + + FreePool (BootFilePath); + FreePool (Private->FilePathUriParser); + FreePool (EndPointUri); + } else { + Private->FilePathUri = Uri; + } + if (Private->FilePathUri != NULL) { Status = HttpParseUrl ( Private->FilePathUri, @@ -274,6 +338,136 @@ 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) { + if (Private->EndPointUri != NULL) { + State = ConnectToProxy; + } else { + 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 ConnectToProxy: + Status = HttpBootConnectProxy (Private); + if (Status == EFI_SUCCESS) { + State = GetBootFileHead; + } else { + State = GetBootFileError; + } + + 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. @@ -345,68 +539,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..e4ffc3ed48 100644 --- a/NetworkPkg/HttpBootDxe/HttpBootImpl.h +++ b/NetworkPkg/HttpBootDxe/HttpBootImpl.h @@ -11,6 +11,14 @@ SPDX-License-Identifier: BSD-2-Clause-Patent #define HTTP_BOOT_CHECK_MEDIA_WAITING_TIME EFI_TIMER_PERIOD_SECONDS(20) +typedef enum { + GetBootFileHead, + GetBootFileGet, + ConnectToProxy, + 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/HttpBootDxe/HttpBootSupport.c b/NetworkPkg/HttpBootDxe/HttpBootSupport.c index 236ef25931..c857488036 100644 --- a/NetworkPkg/HttpBootDxe/HttpBootSupport.c +++ b/NetworkPkg/HttpBootDxe/HttpBootSupport.c @@ -558,6 +558,7 @@ HttpBootCheckUriScheme ( @param[in] FilePath Pointer to the device path which contains a URI device path node. @param[out] UriAddress The URI address string extract from the device path. + @param[out] EndPointUriAddress The URI address string for the endpoint host if UriAddress contains the address of a proxy server @retval EFI_SUCCESS The URI string is returned. @retval EFI_OUT_OF_RESOURCES Failed to allocate memory. @@ -566,19 +567,24 @@ HttpBootCheckUriScheme ( EFI_STATUS HttpBootParseFilePath ( IN EFI_DEVICE_PATH_PROTOCOL *FilePath, - OUT CHAR8 **UriAddress + OUT CHAR8 **UriAddress, + OUT CHAR8 **EndPointUriAddress ) { EFI_DEVICE_PATH_PROTOCOL *TempDevicePath; URI_DEVICE_PATH *UriDevicePath; CHAR8 *Uri; + CHAR8 *TempUri; UINTN UriStrLength; if (FilePath == NULL) { return EFI_INVALID_PARAMETER; } - *UriAddress = NULL; + Uri = NULL; + *UriAddress = NULL; + *EndPointUriAddress = NULL; + TempUri = NULL; // // Extract the URI address from the FilePath @@ -601,6 +607,15 @@ HttpBootParseFilePath ( break; } + if (Uri != NULL) { + // + // Device Path with Proxy Server will be described as + // ....../Mac(...)[/Vlan(...)][/Wi-Fi(...)]/IPv4(...)[/Dns(...)]/Uri(ProxyServer)/Uri(EndPointServer/FilePath) + // ....../Mac(...)[/Vlan(...)][/Wi-Fi(...)]/IPv6(...)[/Dns(...)]/Uri(ProxyServer)/Uri(EndPointServer/FilePath) + // + TempUri = Uri; + } + Uri = AllocatePool (UriStrLength + 1); if (Uri == NULL) { return EFI_OUT_OF_RESOURCES; @@ -615,6 +630,11 @@ HttpBootParseFilePath ( TempDevicePath = NextDevicePathNode (TempDevicePath); } + if (TempUri != NULL) { + *UriAddress = TempUri; + *EndPointUriAddress = Uri; + } + return EFI_SUCCESS; } diff --git a/NetworkPkg/HttpBootDxe/HttpBootSupport.h b/NetworkPkg/HttpBootDxe/HttpBootSupport.h index 3698e55936..6228f37e36 100644 --- a/NetworkPkg/HttpBootDxe/HttpBootSupport.h +++ b/NetworkPkg/HttpBootDxe/HttpBootSupport.h @@ -138,8 +138,9 @@ HttpBootCheckUriScheme ( Caller need to free the buffer in the UriAddress pointer. - @param[in] FilePath Pointer to the device path which contains a URI device path node. - @param[out] UriAddress The URI address string extract from the device path. + @param[in] FilePath Pointer to the device path which contains a URI device path node. + @param[out] UriAddress The URI address string extract from the device path. + @param[out] EndPointUriAddress The URI address string for the endpoint host if UriAddress contains the address of a proxy server @retval EFI_SUCCESS The URI string is returned. @retval EFI_OUT_OF_RESOURCES Failed to allocate memory. @@ -148,7 +149,8 @@ HttpBootCheckUriScheme ( EFI_STATUS HttpBootParseFilePath ( IN EFI_DEVICE_PATH_PROTOCOL *FilePath, - OUT CHAR8 **UriAddress + OUT CHAR8 **UriAddress, + OUT CHAR8 **EndPointUriAddress ); /** diff --git a/NetworkPkg/HttpDxe/HttpDriver.h b/NetworkPkg/HttpDxe/HttpDriver.h index 01a6bb7f4b..e0917f431e 100644 --- a/NetworkPkg/HttpDxe/HttpDriver.h +++ b/NetworkPkg/HttpDxe/HttpDriver.h @@ -26,6 +26,7 @@ #include #include #include +#include // // UEFI Driver Model Protocols @@ -64,6 +65,7 @@ // Driver Version // #define HTTP_DRIVER_VERSION 0xa +#define URI_STR_MAX_SIZE 255 // // Protocol instances diff --git a/NetworkPkg/HttpDxe/HttpDxe.inf b/NetworkPkg/HttpDxe/HttpDxe.inf index c9502d0bb6..30b7de1951 100644 --- a/NetworkPkg/HttpDxe/HttpDxe.inf +++ b/NetworkPkg/HttpDxe/HttpDxe.inf @@ -47,6 +47,7 @@ NetLib HttpLib DpcLib + PrintLib [Protocols] gEfiHttpServiceBindingProtocolGuid ## BY_START diff --git a/NetworkPkg/HttpDxe/HttpImpl.c b/NetworkPkg/HttpDxe/HttpImpl.c index 7c5c925cf7..24ce87fd7d 100644 --- a/NetworkPkg/HttpDxe/HttpImpl.c +++ b/NetworkPkg/HttpDxe/HttpImpl.c @@ -233,35 +233,45 @@ EfiHttpRequest ( EFI_HTTP_MESSAGE *HttpMsg; EFI_HTTP_REQUEST_DATA *Request; VOID *UrlParser; + VOID *EndPointUrlParser; EFI_STATUS Status; CHAR8 *HostName; + CHAR8 *EndPointHostName; UINTN HostNameSize; UINT16 RemotePort; + UINT16 EndPointRemotePort; HTTP_PROTOCOL *HttpInstance; BOOLEAN Configure; BOOLEAN ReConfigure; BOOLEAN TlsConfigure; CHAR8 *RequestMsg; CHAR8 *Url; + CHAR8 *EndPointUrl; UINTN UrlLen; CHAR16 *HostNameStr; HTTP_TOKEN_WRAP *Wrap; CHAR8 *FileUrl; UINTN RequestMsgSize; EFI_HANDLE ImageHandle; + CHAR8 *EndPointUrlMsg; // // Initializations // - Url = NULL; - UrlParser = NULL; - RemotePort = 0; - HostName = NULL; - RequestMsg = NULL; - HostNameStr = NULL; - Wrap = NULL; - FileUrl = NULL; - TlsConfigure = FALSE; + Url = NULL; + UrlParser = NULL; + EndPointUrlParser = NULL; + RemotePort = 0; + EndPointRemotePort = 0; + HostName = NULL; + EndPointHostName = NULL; + RequestMsg = NULL; + HostNameStr = NULL; + Wrap = NULL; + FileUrl = NULL; + TlsConfigure = FALSE; + EndPointUrl = NULL; + EndPointUrlMsg = NULL; if ((This == NULL) || (Token == NULL)) { return EFI_INVALID_PARAMETER; @@ -275,16 +285,20 @@ EfiHttpRequest ( Request = HttpMsg->Data.Request; // - // Only support GET, HEAD, DELETE, PATCH, PUT and POST method in current implementation. + // Only support GET, HEAD, DELETE, PATCH, PUT, CONNECT 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)) + (Request->Method != HttpMethodPatch) && (Request->Method != HttpMethodConnect)) { return EFI_UNSUPPORTED; } + if ((Request->Method == HttpMethodConnect) && (Request->EndPointUrl == NULL)) { + return EFI_INVALID_PARAMETER; + } + HttpInstance = HTTP_INSTANCE_FROM_PROTOCOL (This); // @@ -353,11 +367,25 @@ EfiHttpRequest ( UnicodeStrToAsciiStrS (Request->Url, Url, UrlLen); + if (Request->EndPointUrl != NULL) { + UrlLen = StrLen (Request->EndPointUrl) + 1; + EndPointUrl = AllocateZeroPool (UrlLen); + if (EndPointUrl == NULL) { + goto Error1; + } + + UnicodeStrToAsciiStrS (Request->EndPointUrl, EndPointUrl, UrlLen); + } + // // From the information in Url, the HTTP instance will // be able to determine whether to use http or https. // - HttpInstance->UseHttps = IsHttpsUrl (Url); + if (HttpInstance->ProxyConnected) { + HttpInstance->UseHttps = IsHttpsUrl (EndPointUrl); + } else { + HttpInstance->UseHttps = IsHttpsUrl (Url); + } // // HTTP is disabled, return directly if the URI is not HTTPS. @@ -444,9 +472,10 @@ EfiHttpRequest ( if ((HttpInstance->ConnectionClose == FALSE) && (HttpInstance->RemotePort == RemotePort) && (AsciiStrCmp (HttpInstance->RemoteHost, HostName) == 0) && - (!HttpInstance->UseHttps || (HttpInstance->UseHttps && - !TlsConfigure && - (HttpInstance->TlsSessionState == EfiTlsSessionDataTransferring)))) + (!HttpInstance->UseHttps || + HttpInstance->ProxyConnected || (HttpInstance->UseHttps && + !TlsConfigure && + (HttpInstance->TlsSessionState == EfiTlsSessionDataTransferring)))) { // // Host Name and port number of the request URL are the same with previous call to Request(). @@ -599,7 +628,7 @@ EfiHttpRequest ( goto Error2; } - if (!Configure && !ReConfigure && !TlsConfigure) { + if ((!Configure && !ReConfigure) && ((HttpInstance->ProxyConnected && TlsConfigure) || (!TlsConfigure))) { // // For the new HTTP token, create TX TCP token events. // @@ -632,7 +661,48 @@ EfiHttpRequest ( } } - Status = HttpGenRequestMessage (HttpMsg, FileUrl, &RequestMsg, &RequestMsgSize); + if (HttpInstance->Method == HttpMethodConnect) { + Status = HttpParseUrl (EndPointUrl, (UINT32)AsciiStrLen (EndPointUrl), FALSE, &EndPointUrlParser); + if (EFI_ERROR (Status)) { + goto Error3; + } + + Status = HttpUrlGetHostName ( + EndPointUrl, + EndPointUrlParser, + &EndPointHostName + ); + if (EFI_ERROR (Status)) { + goto Error3; + } + + Status = HttpUrlGetPort (EndPointUrl, EndPointUrlParser, &EndPointRemotePort); + if (EFI_ERROR (Status)) { + if (IsHttpsUrl (EndPointUrl)) { + EndPointRemotePort = HTTPS_DEFAULT_PORT; + } else { + EndPointRemotePort = HTTP_DEFAULT_PORT; + } + } + + EndPointUrlMsg = AllocateZeroPool (URI_STR_MAX_SIZE); + if (EndPointUrlMsg == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto Error3; + } + + AsciiSPrint ( + EndPointUrlMsg, + URI_STR_MAX_SIZE, + "%a:%d", + EndPointHostName, + EndPointRemotePort + ); + + Status = HttpGenRequestMessage (HttpMsg, EndPointUrlMsg, &RequestMsg, &RequestMsgSize); + } else { + Status = HttpGenRequestMessage (HttpMsg, FileUrl, &RequestMsg, &RequestMsgSize); + } if (EFI_ERROR (Status) || (NULL == RequestMsg)) { goto Error3; @@ -668,6 +738,23 @@ EfiHttpRequest ( DispatchDpc (); + if (HttpInstance->Method == HttpMethodConnect) { + HttpInstance->ProxyConnected = TRUE; + HttpInstance->EndPointRemoteHost = EndPointHostName; + + if (EndPointUrlParser != NULL) { + HttpUrlFreeParser (EndPointUrlParser); + } + } + + if (EndPointUrlMsg != NULL) { + FreePool (EndPointUrlMsg); + } + + if (EndPointUrl != NULL) { + FreePool (EndPointUrl); + } + if (HostName != NULL) { FreePool (HostName); } @@ -698,6 +785,20 @@ Error3: TlsCloseTxRxEvent (HttpInstance); } + if (HttpInstance->Method == HttpMethodConnect) { + if (EndPointHostName != NULL) { + FreePool (EndPointHostName); + } + + if (EndPointUrlParser != NULL) { + HttpUrlFreeParser (EndPointUrlParser); + } + } + + if (EndPointUrlMsg != NULL) { + FreePool (EndPointUrlMsg); + } + Error2: HttpCloseConnection (HttpInstance); @@ -725,6 +826,10 @@ Error1: HttpUrlFreeParser (UrlParser); } + if (EndPointUrl != NULL) { + FreePool (EndPointUrl); + } + return Status; } diff --git a/NetworkPkg/HttpDxe/HttpProto.c b/NetworkPkg/HttpDxe/HttpProto.c index 33ae622c3f..b87fbeeb54 100644 --- a/NetworkPkg/HttpDxe/HttpProto.c +++ b/NetworkPkg/HttpDxe/HttpProto.c @@ -849,6 +849,11 @@ HttpCleanProtocol ( HttpInstance->Url = NULL; } + if (HttpInstance->EndPointRemoteHost != NULL) { + FreePool (HttpInstance->EndPointRemoteHost); + HttpInstance->EndPointRemoteHost = NULL; + } + NetMapClean (&HttpInstance->TxTokens); NetMapClean (&HttpInstance->RxTokens); @@ -1206,6 +1211,7 @@ HttpConfigureTcp6 ( connect one TLS session if required. @param[in] HttpInstance The HTTP instance private data. + @param[in] TlsConfigure The Flag indicates whether it's the new Tls session. @retval EFI_SUCCESS The TCP connection is established. @retval EFI_NOT_READY TCP4 protocol child is not created or configured. @@ -1214,7 +1220,8 @@ HttpConfigureTcp6 ( **/ EFI_STATUS HttpConnectTcp4 ( - IN HTTP_PROTOCOL *HttpInstance + IN HTTP_PROTOCOL *HttpInstance, + IN BOOLEAN TlsConfigure ) { EFI_STATUS Status; @@ -1237,16 +1244,18 @@ HttpConnectTcp4 ( return Status; } - if (Tcp4State == Tcp4StateEstablished) { + if ((Tcp4State == Tcp4StateEstablished) && (!HttpInstance->ProxyConnected || !TlsConfigure)) { return EFI_SUCCESS; } else if (Tcp4State > Tcp4StateEstablished ) { HttpCloseConnection (HttpInstance); } - Status = HttpCreateConnection (HttpInstance); - if (EFI_ERROR (Status)) { - DEBUG ((DEBUG_ERROR, "Tcp4 Connection fail - %x\n", Status)); - return Status; + if (!HttpInstance->ProxyConnected) { + Status = HttpCreateConnection (HttpInstance); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "Tcp4 Connection fail - %x\n", Status)); + return Status; + } } // @@ -1298,6 +1307,7 @@ HttpConnectTcp4 ( connect one TLS session if required. @param[in] HttpInstance The HTTP instance private data. + @param[in] TlsConfigure The Flag indicates whether it's the new Tls session. @retval EFI_SUCCESS The TCP connection is established. @retval EFI_NOT_READY TCP6 protocol child is not created or configured. @@ -1306,7 +1316,8 @@ HttpConnectTcp4 ( **/ EFI_STATUS HttpConnectTcp6 ( - IN HTTP_PROTOCOL *HttpInstance + IN HTTP_PROTOCOL *HttpInstance, + IN BOOLEAN TlsConfigure ) { EFI_STATUS Status; @@ -1330,16 +1341,18 @@ HttpConnectTcp6 ( return Status; } - if (Tcp6State == Tcp6StateEstablished) { + if ((Tcp6State == Tcp6StateEstablished) && (!HttpInstance->ProxyConnected || !TlsConfigure)) { return EFI_SUCCESS; } else if (Tcp6State > Tcp6StateEstablished ) { HttpCloseConnection (HttpInstance); } - Status = HttpCreateConnection (HttpInstance); - if (EFI_ERROR (Status)) { - DEBUG ((DEBUG_ERROR, "Tcp6 Connection fail - %x\n", Status)); - return Status; + if (!HttpInstance->ProxyConnected) { + Status = HttpCreateConnection (HttpInstance); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "Tcp6 Connection fail - %x\n", Status)); + return Status; + } } // @@ -1434,7 +1447,7 @@ HttpInitSession ( // // Connect TCP. // - Status = HttpConnectTcp4 (HttpInstance); + Status = HttpConnectTcp4 (HttpInstance, TlsConfigure); if (EFI_ERROR (Status)) { return Status; } @@ -1452,7 +1465,7 @@ HttpInitSession ( // // Connect TCP. // - Status = HttpConnectTcp6 (HttpInstance); + Status = HttpConnectTcp6 (HttpInstance, TlsConfigure); if (EFI_ERROR (Status)) { return Status; } diff --git a/NetworkPkg/HttpDxe/HttpProto.h b/NetworkPkg/HttpDxe/HttpProto.h index 620eb39158..2e8d516359 100644 --- a/NetworkPkg/HttpDxe/HttpProto.h +++ b/NetworkPkg/HttpDxe/HttpProto.h @@ -165,6 +165,12 @@ typedef struct _HTTP_PROTOCOL { CHAR8 *Url; + // + // Proxy Server Support + // + CHAR8 *EndPointRemoteHost; + BOOLEAN ProxyConnected; + // // Https Support // @@ -398,6 +404,7 @@ HttpConfigureTcp6 ( connect one TLS session if required. @param[in] HttpInstance The HTTP instance private data. + @param[in] TlsConfigure The Flag indicates whether it's the new Tls session. @retval EFI_SUCCESS The TCP connection is established. @retval EFI_NOT_READY TCP4 protocol child is not created or configured. @@ -406,7 +413,8 @@ HttpConfigureTcp6 ( **/ EFI_STATUS HttpConnectTcp4 ( - IN HTTP_PROTOCOL *HttpInstance + IN HTTP_PROTOCOL *HttpInstance, + IN BOOLEAN TlsConfigure ); /** @@ -414,6 +422,7 @@ HttpConnectTcp4 ( connect one TLS session if required. @param[in] HttpInstance The HTTP instance private data. + @param[in] TlsConfigure The Flag indicates whether it's the new Tls session. @retval EFI_SUCCESS The TCP connection is established. @retval EFI_NOT_READY TCP6 protocol child is not created or configured. @@ -422,7 +431,8 @@ HttpConnectTcp4 ( **/ EFI_STATUS HttpConnectTcp6 ( - IN HTTP_PROTOCOL *HttpInstance + IN HTTP_PROTOCOL *HttpInstance, + IN BOOLEAN TlsConfigure ); /** diff --git a/NetworkPkg/HttpDxe/HttpsSupport.c b/NetworkPkg/HttpDxe/HttpsSupport.c index ad611e7c38..7dc2b752ec 100644 --- a/NetworkPkg/HttpDxe/HttpsSupport.c +++ b/NetworkPkg/HttpDxe/HttpsSupport.c @@ -644,11 +644,15 @@ TlsConfigureSession ( // // TlsConfigData initialization // - HttpInstance->TlsConfigData.ConnectionEnd = EfiTlsClient; - HttpInstance->TlsConfigData.VerifyMethod = EFI_TLS_VERIFY_PEER; - HttpInstance->TlsConfigData.VerifyHost.Flags = EFI_TLS_VERIFY_FLAG_NONE; - HttpInstance->TlsConfigData.VerifyHost.HostName = HttpInstance->RemoteHost; - HttpInstance->TlsConfigData.SessionState = EfiTlsSessionNotStarted; + HttpInstance->TlsConfigData.ConnectionEnd = EfiTlsClient; + HttpInstance->TlsConfigData.SessionState = EfiTlsSessionNotStarted; + HttpInstance->TlsConfigData.VerifyMethod = EFI_TLS_VERIFY_PEER; + HttpInstance->TlsConfigData.VerifyHost.Flags = EFI_TLS_VERIFY_FLAG_NONE; + if (HttpInstance->ProxyConnected) { + HttpInstance->TlsConfigData.VerifyHost.HostName = HttpInstance->EndPointRemoteHost; + } else { + HttpInstance->TlsConfigData.VerifyHost.HostName = HttpInstance->RemoteHost; + } // // EfiTlsConnectionEnd, diff --git a/NetworkPkg/Library/DxeHttpLib/DxeHttpLib.c b/NetworkPkg/Library/DxeHttpLib/DxeHttpLib.c index 6a5d78629b..45087a1935 100644 --- a/NetworkPkg/Library/DxeHttpLib/DxeHttpLib.c +++ b/NetworkPkg/Library/DxeHttpLib/DxeHttpLib.c @@ -1927,6 +1927,11 @@ HttpGenRequestMessage ( CopyMem (RequestPtr, HTTP_METHOD_DELETE, StrLength); RequestPtr += StrLength; break; + case HttpMethodConnect: + StrLength = sizeof (HTTP_METHOD_CONNECT) - 1; + CopyMem (RequestPtr, HTTP_METHOD_CONNECT, StrLength); + RequestPtr += StrLength; + break; default: ASSERT (FALSE); Status = EFI_INVALID_PARAMETER; -- 2.36.1.windows.1