NetworkPkg/HttpBootDxe: Add proxy connect flow to *GetBootFile()

- Add HTTP CONNECT flow to connect to Proxy Server
- Provide Proxy URL to HTTP GET/HEAD Requests

Implementation based on UEFI Specification v2.11
- Section 24.7.10 to use HTTP CONNECT method to connect to Proxy
Server and use it to forward the HEAD/GET request to Endpoint Server's
BootURI.
- Section 29.6.6 to use EFI_HTTP_CONNECT_REQUEST_DATA structure for
HttpMethodConnect usage in EFI_HTTP_PROTOCOL.Request()

Signed-off-by: Saloni Kasbekar <saloni.kasbekar@intel.com>
This commit is contained in:
Saloni Kasbekar
2022-12-16 19:06:53 +01:00
committed by mergify[bot]
parent 884585818f
commit 80c04eb46f
4 changed files with 262 additions and 45 deletions

View File

@@ -664,52 +664,63 @@ HttpBootFreeCache (
IN HTTP_BOOT_CACHE_CONTENT *Cache
)
{
UINTN Index;
LIST_ENTRY *Entry;
LIST_ENTRY *NextEntry;
HTTP_BOOT_ENTITY_DATA *EntityData;
UINTN Index;
LIST_ENTRY *Entry;
LIST_ENTRY *NextEntry;
HTTP_BOOT_ENTITY_DATA *EntityData;
EFI_HTTP_CONNECT_REQUEST_DATA *ConnRequestData;
if (Cache != NULL) {
//
// Free the request data
//
if (Cache->RequestData != NULL) {
if (Cache->RequestData->Url != NULL) {
FreePool (Cache->RequestData->Url);
}
FreePool (Cache->RequestData);
}
//
// Free the response header
//
if (Cache->ResponseData != NULL) {
if (Cache->ResponseData->Headers != NULL) {
for (Index = 0; Index < Cache->ResponseData->HeaderCount; Index++) {
FreePool (Cache->ResponseData->Headers[Index].FieldName);
FreePool (Cache->ResponseData->Headers[Index].FieldValue);
}
FreePool (Cache->ResponseData->Headers);
}
}
//
// Free the response body
//
NET_LIST_FOR_EACH_SAFE (Entry, NextEntry, &Cache->EntityDataList) {
EntityData = NET_LIST_USER_STRUCT (Entry, HTTP_BOOT_ENTITY_DATA, Link);
if (EntityData->Block != NULL) {
FreePool (EntityData->Block);
}
RemoveEntryList (&EntityData->Link);
FreePool (EntityData);
}
FreePool (Cache);
if (Cache == NULL) {
return;
}
//
// Free the request data
//
if (Cache->RequestData != NULL) {
if (Cache->RequestData->Url != NULL) {
FreePool (Cache->RequestData->Url);
}
if (Cache->RequestData->Method == HttpMethodConnect) {
ConnRequestData = (EFI_HTTP_CONNECT_REQUEST_DATA *)Cache->RequestData;
if (ConnRequestData->ProxyUrl != NULL) {
FreePool (ConnRequestData->ProxyUrl);
}
}
FreePool (Cache->RequestData);
}
//
// Free the response header
//
if (Cache->ResponseData != NULL) {
if (Cache->ResponseData->Headers != NULL) {
for (Index = 0; Index < Cache->ResponseData->HeaderCount; Index++) {
FreePool (Cache->ResponseData->Headers[Index].FieldName);
FreePool (Cache->ResponseData->Headers[Index].FieldValue);
}
FreePool (Cache->ResponseData->Headers);
}
}
//
// Free the response body
//
NET_LIST_FOR_EACH_SAFE (Entry, NextEntry, &Cache->EntityDataList) {
EntityData = NET_LIST_USER_STRUCT (Entry, HTTP_BOOT_ENTITY_DATA, Link);
if (EntityData->Block != NULL) {
FreePool (EntityData->Block);
}
RemoveEntryList (&EntityData->Link);
FreePool (EntityData);
}
FreePool (Cache);
}
/**
@@ -901,6 +912,182 @@ 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_CONNECT_REQUEST_DATA *RequestData;
HTTP_IO_RESPONSE_DATA *ResponseData;
HTTP_IO *HttpIo;
HTTP_IO_HEADER *HttpIoHeader;
CHAR16 *Url;
CHAR16 *ProxyUrl;
UINTN UrlSize;
Url = NULL;
ProxyUrl = 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->ProxyUri);
ProxyUrl = AllocatePool (UrlSize * (sizeof (CHAR16)));
if (ProxyUrl == NULL) {
Status = EFI_OUT_OF_RESOURCES;
goto EXIT;
}
AsciiStrToUnicodeStrS (Private->ProxyUri, ProxyUrl, 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 EXIT;
}
//
// Add HTTP header field 1: Host (EndPoint URI)
//
HostName = NULL;
Status = HttpUrlGetHostName (
Private->BootFileUri,
Private->BootFileUriParser,
&HostName
);
if (EFI_ERROR (Status)) {
goto EXIT;
}
Status = HttpIoSetHeader (
HttpIoHeader,
HTTP_HEADER_HOST,
HostName
);
if (EFI_ERROR (Status)) {
goto EXIT;
}
//
// 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 EXIT;
}
//
// Build the rest of HTTP request info.
//
RequestData = AllocatePool (sizeof (EFI_HTTP_CONNECT_REQUEST_DATA));
if (RequestData == NULL) {
Status = EFI_OUT_OF_RESOURCES;
goto EXIT;
}
RequestData->Base.Method = HttpMethodConnect;
RequestData->Base.Url = Url;
RequestData->ProxyUrl = ProxyUrl;
//
// Send out the request to HTTP server.
//
HttpIo = &Private->HttpIo;
Status = HttpIoSendRequest (
HttpIo,
&RequestData->Base,
HttpIoHeader->HeaderCount,
HttpIoHeader->Headers,
0,
NULL
);
if (EFI_ERROR (Status)) {
goto EXIT;
}
//
// 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 EXIT;
}
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;
}
}
EXIT:
if (ResponseData != NULL) {
FreePool (ResponseData);
}
if (RequestData != NULL) {
FreePool (RequestData);
}
HttpIoFreeHeader (HttpIoHeader);
if (ProxyUrl != NULL) {
FreePool (ProxyUrl);
}
if (Url != NULL) {
FreePool (Url);
}
return Status;
}
/**
This function download the boot file by using UEFI HTTP protocol.

View File

@@ -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.

View File

@@ -319,7 +319,11 @@ HttpBootGetBootFileCaller (
UINT32 Retries;
if (Private->BootFileSize == 0) {
State = GetBootFileHead;
if (Private->ProxyUri != NULL) {
State = ConnectToProxy;
} else {
State = GetBootFileHead;
}
} else {
State = LoadBootFile;
}
@@ -372,6 +376,16 @@ HttpBootGetBootFileCaller (
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;

View File

@@ -14,6 +14,7 @@ SPDX-License-Identifier: BSD-2-Clause-Patent
typedef enum {
GetBootFileHead,
GetBootFileGet,
ConnectToProxy,
LoadBootFile,
GetBootFileError
} HTTP_GET_BOOT_FILE_STATE;