Skip to content

Commit

Permalink
NetworkPkg/HttpBootDxe: Add proxy connect flow to *GetBootFile()
Browse files Browse the repository at this point in the history
- Add HTTP CONNECT flow to connect to Proxy Server
- Provide Proxy URL to HTTP GET/HEAD Requests

Signed-off-by: Saloni Kasbekar <[email protected]>
  • Loading branch information
SaloniKasbekar committed Aug 31, 2024
1 parent 89d297f commit e602645
Show file tree
Hide file tree
Showing 4 changed files with 253 additions and 36 deletions.
257 changes: 222 additions & 35 deletions NetworkPkg/HttpBootDxe/HttpBootClient.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
if (Cache == NULL) {
return;
}

FreePool (Cache->RequestData);
//
// Free the request data
//
if (Cache->RequestData != NULL) {
if (Cache->RequestData->Url != NULL) {
FreePool (Cache->RequestData->Url);
}

//
// 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);
}
if (Cache->RequestData->Method == HttpMethodConnect) {
ConnRequestData = (EFI_HTTP_CONNECT_REQUEST_DATA*)Cache->RequestData;

FreePool (Cache->ResponseData->Headers);
if (ConnRequestData->ProxyUrl != NULL) {
FreePool (ConnRequestData->ProxyUrl);
}
}

//
// 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);
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);
}

RemoveEntryList (&EntityData->Link);
FreePool (EntityData);
FreePool (Cache->ResponseData->Headers);
}
}

FreePool (Cache);
//
// 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);
}

/**
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -1106,8 +1293,8 @@ HttpBootGetBootFile (
goto ERROR_3;
}

RequestData->Method = HeaderOnly ? HttpMethodHead : HttpMethodGet;
RequestData->Url = Url;
RequestData->Method = HeaderOnly ? HttpMethodHead : HttpMethodGet;
RequestData->Url = Url;

//
// 2.3 Record the request info in a temp cache item.
Expand Down
15 changes: 15 additions & 0 deletions NetworkPkg/HttpBootDxe/HttpBootClient.h
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
16 changes: 15 additions & 1 deletion NetworkPkg/HttpBootDxe/HttpBootImpl.c
Original file line number Diff line number Diff line change
Expand Up @@ -310,7 +310,11 @@ HttpBootGetBootFileCaller (
EFI_STATUS Status;

if (Private->BootFileSize == 0) {
State = GetBootFileHead;
if (Private->ProxyUri != NULL) {
State = ConnectToProxy;
} else {
State = GetBootFileHead;
}
} else {
State = LoadBootFile;
}
Expand Down Expand Up @@ -363,6 +367,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;
Expand Down
1 change: 1 addition & 0 deletions NetworkPkg/HttpBootDxe/HttpBootImpl.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ SPDX-License-Identifier: BSD-2-Clause-Patent
typedef enum {
GetBootFileHead,
GetBootFileGet,
ConnectToProxy,
LoadBootFile,
GetBootFileError
} HTTP_GET_BOOT_FILE_STATE;
Expand Down

0 comments on commit e602645

Please sign in to comment.