diff --git a/NetworkPkg/HttpBootDxe/HttpBootClient.c b/NetworkPkg/HttpBootDxe/HttpBootClient.c index 40f64fcb6bf8..0108dc07f392 100644 --- a/NetworkPkg/HttpBootDxe/HttpBootClient.c +++ b/NetworkPkg/HttpBootDxe/HttpBootClient.c @@ -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); } /** @@ -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. @@ -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. diff --git a/NetworkPkg/HttpBootDxe/HttpBootClient.h b/NetworkPkg/HttpBootDxe/HttpBootClient.h index 86a28bc91aa2..36613a47d6e0 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/HttpBootImpl.c b/NetworkPkg/HttpBootDxe/HttpBootImpl.c index 29084407ad51..52337ba9ab0d 100644 --- a/NetworkPkg/HttpBootDxe/HttpBootImpl.c +++ b/NetworkPkg/HttpBootDxe/HttpBootImpl.c @@ -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; } @@ -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; diff --git a/NetworkPkg/HttpBootDxe/HttpBootImpl.h b/NetworkPkg/HttpBootDxe/HttpBootImpl.h index 33da4fec5123..e4ffc3ed48e5 100644 --- a/NetworkPkg/HttpBootDxe/HttpBootImpl.h +++ b/NetworkPkg/HttpBootDxe/HttpBootImpl.h @@ -14,6 +14,7 @@ SPDX-License-Identifier: BSD-2-Clause-Patent typedef enum { GetBootFileHead, GetBootFileGet, + ConnectToProxy, LoadBootFile, GetBootFileError } HTTP_GET_BOOT_FILE_STATE;