From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mail-ej1-f52.google.com (mail-ej1-f52.google.com [209.85.218.52]) by mx.groups.io with SMTP id smtpd.web11.1956.1599242140608788156 for ; Fri, 04 Sep 2020 10:55:41 -0700 Authentication-Results: mx.groups.io; dkim=pass header.i=@broadcom.com header.s=google header.b=A9GGC386; spf=permerror, err=parse error for token &{10 18 %{i}._ip.%{h}._ehlo.%{d}._spf.vali.email}: invalid domain name (domain: broadcom.com, ip: 209.85.218.52, mailfrom: vladimir.olovyannikov@broadcom.com) Received: by mail-ej1-f52.google.com with SMTP id z22so9729117ejl.7 for ; Fri, 04 Sep 2020 10:55:40 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=broadcom.com; s=google; h=from:references:in-reply-to:mime-version:thread-index:date :message-id:subject:to:cc; bh=G2bG7/0PMImJgZx9ojENJKRsd4Rer1VGm82X9AVHFMs=; b=A9GGC386raWuuWqSTR/ItaNfw7ePZHE/DHSga7B0lPnK+sjydw6PBn9ERQQQr2/ToK 9rhk+AK2sJUjsWjui22FOuIr9CtLAuOTa3LA9jbc6jii3qTL/DCF4w1wmuWE2n5nqMEp 2vcc0n22GPd981QCwNHjmH3fonEoBv+tAEUUY= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:references:in-reply-to:mime-version :thread-index:date:message-id:subject:to:cc; bh=G2bG7/0PMImJgZx9ojENJKRsd4Rer1VGm82X9AVHFMs=; b=UzU/ETE3lxxjjZDxaQhEMvxi0RJnREA6IN2Bz4U4ZsTpJadAOHHcTHK4aAmej17xVX +L/C5x5Ucd7EWP2wrevcTP826Hl/vgaSWrjvAdp8L3clF+EGXBLSwOCdoNP4C8zkw9X7 d8Ik0B0Qhn18U3pfotTYPnc6tsHC/W40bNEFBlssIfKdWlgXpVkYs2JAC1n0Lk8Ewoji aPbSjzlf0NAKa8jh5n+fk6ucGXxgeStl0TtIlh2hBbwaPiJ0+SMIPFzdzxtrR0WFV5QD dp0HRXtTfkhXahyT/jyl/fDAVzeNZfU6pBsE5amteeWCFy4xyom3eRHDwGWmoXT6av5T V6yQ== X-Gm-Message-State: AOAM53261GNuSo4AfBmy/JsKUbVhLbvaiSAG7XehTSTWlvPWaHi/2Puc OaalWXxAEAS29FkD/uBb0diSBVFX1wfM0E7osz2auw== X-Google-Smtp-Source: ABdhPJyixuT4QMs6LciX0rKKwMndxMKNpwPN3jPOdnifkGaXEB+lIkwIu2lyVDtfn8U++Xz5vJMYTsaTIHfFg62HT/M= X-Received: by 2002:a17:906:a947:: with SMTP id hh7mr4075007ejb.126.1599242138393; Fri, 04 Sep 2020 10:55:38 -0700 (PDT) From: "Vladimir Olovyannikov" References: <20200902040821.24144-1-vladimir.olovyannikov@broadcom.com> <20200902040821.24144-2-vladimir.olovyannikov@broadcom.com> <30fc1fc2-858f-f0e8-e54f-58b872ad57ae@linux.intel.com> <30233c17-c081-deb6-d0cb-d847c7a9992b@redhat.com> In-Reply-To: <30233c17-c081-deb6-d0cb-d847c7a9992b@redhat.com> MIME-Version: 1.0 X-Mailer: Microsoft Outlook 16.0 Thread-Index: AQIFbDYdE26JdBaZ6E2uQjXRYlN7OAJms9k1ApTVQKkBz5NrEqjEeIBg Date: Fri, 4 Sep 2020 10:55:36 -0700 Message-ID: <20ac79e77049e8756de36f50df1e7f36@mail.gmail.com> Subject: Re: [PATCH v10 1/1] ShellPkg/DynamicCommand: add HttpDynamicCommand To: Laszlo Ersek , "Rabeda, Maciej" , devel@edk2.groups.io, Zhichao Gao , Ray Ni Cc: Samer El-Haj-Mahmoud , Jiaxin Wu , Siyuan Fu , Liming Gao , Nd Content-Type: text/plain; charset="UTF-8" Hi Laszlo, Macieji, Thank you for spotting these. Some comments below. > -----Original Message----- > From: Laszlo Ersek > Sent: Friday, September 4, 2020 8:21 AM > To: Rabeda, Maciej ; Vladimir Olovyannikov > ; devel@edk2.groups.io; Zhichao > Gao ; Ray Ni > Cc: Samer El-Haj-Mahmoud ; Jiaxin Wu > ; Siyuan Fu ; Liming Gao > ; Nd > Subject: Re: [PATCH v10 1/1] ShellPkg/DynamicCommand: add > HttpDynamicCommand > > question for Ray and Zhichao at the bottom > > On 09/04/20 15:10, Rabeda, Maciej wrote: > > Hi Vladimir, > > > > One remark regarding these macros: > > #define SEC_PER_MONTH ((UINTN) > > 2,592,000) > > #define SEC_PER_YEAR ((UINTN) > > 31,536,000) > > > > They are not being used in your code and were most probably taken from > > EmbeddedPkg/Include/Library/TimeBaseLib.h. > > However - using them in a simple example: > > UINTN a = SEC_PER_MONTH > > DebugPrint (EFI_D_INFO, "%d\n", a); > > > > and looking at code listing, 'a' variable will be assigned a value of 0. > > Commas should be removed from macros for them to work as designed. > > > > I leave the decision whether this should be fixed in ShellPkg and > > EmbeddedPkg to the appropriate maintainers. > > I think these macros should be eliminated altogether from edk2. They > date back to commit 0f4386e775c7 > ("ArmPlatformPkg/PL031RealTimeClockLib: > Implement PL031 RTC drive", 2011-06-11) and I can imagine no > circumstance under which they could possibly work. > > For example, SEC_PER_MONTH evaluates to 0 (having type "int"). The > comma > operator has the weakest binding of all operators, so not only is the > value 0, but even the (UINTN) cast applies only to the "2" that stands > to the left of the first comma. > > Bonus: the rightmost 000 is an octal constant. Thank you for spotting these. Indeed, those were taken "as is" from TimeBaseLib.h Copy/paste... There is also another issue with the TimebaseLib: inconsistency in return values of the EfiTimeToEpoch (returns UINT32, should return UINTN, as Zhichao pointed out earlier in the previous HttpDynamicCommand patchset). If this one is fixed, I can just use the TimeBaseLib.h header for constants. > > > For the rest of the code: > > Reviewed-by: Maciej Rabeda > > Thanks. > > Ray, Zhichao, what's your plan for approving / merging this patch? Are > you OK to merge the next version (v11), with the macros removed? > > Asking because I'd like to test the patch one last time, just before > it's merged. > > Thanks! > Laszlo > Thank you, Vladimir > > > > Thanks, > > Maciej > > > > On 02-Sep-20 06:08, Vladimir Olovyannikov wrote: > >> Introduce an http client utilizing EDK2 HTTP protocol, to > >> allow fast image downloading from http/https servers. > >> HTTP download speed is usually faster than tftp. > >> The client is based on the same approach as tftp dynamic command, and > >> uses the same UEFI Shell command line parameters. This makes it easy > >> integrating http into existing UEFI Shell scripts. > >> Note that to enable HTTP download, feature Pcd > >> gEfiNetworkPkgTokenSpaceGuid.PcdAllowHttpConnections must > >> be set to TRUE. > >> BZ: https://bugzilla.tianocore.org/show_bug.cgi?id=2860 > >> > >> Signed-off-by: Vladimir Olovyannikov > > >> Cc: Samer El-Haj-Mahmoud > >> Cc: Laszlo Ersek > >> Cc: Zhichao Gao > >> Cc: Maciej Rabeda > >> Cc: Jiaxin Wu > >> Cc: Siyuan Fu > >> Cc: Ray Ni > >> Cc: Liming Gao > >> Cc: Nd > >> --- > >> ShellPkg/ShellPkg.dec | 1 + > >> ShellPkg/ShellPkg.dsc | 5 + > >> .../HttpDynamicCommand/HttpApp.inf | 58 + > >> .../HttpDynamicCommand/HttpDynamicCommand.inf | 63 + > >> .../DynamicCommand/HttpDynamicCommand/Http.h | 90 + > >> ShellPkg/Include/Guid/ShellLibHiiGuid.h | 5 + > >> .../DynamicCommand/HttpDynamicCommand/Http.c | 1831 > +++++++++++++++++ > >> .../HttpDynamicCommand/HttpApp.c | 61 + > >> .../HttpDynamicCommand/HttpDynamicCommand.c | 137 ++ > >> .../HttpDynamicCommand/Http.uni | 117 ++ > >> 10 files changed, 2368 insertions(+) > >> create mode 100644 > >> ShellPkg/DynamicCommand/HttpDynamicCommand/HttpApp.inf > >> create mode 100644 > >> > ShellPkg/DynamicCommand/HttpDynamicCommand/HttpDynamicCommand > .inf > >> create mode 100644 > ShellPkg/DynamicCommand/HttpDynamicCommand/Http.h > >> create mode 100644 > ShellPkg/DynamicCommand/HttpDynamicCommand/Http.c > >> create mode 100644 > ShellPkg/DynamicCommand/HttpDynamicCommand/HttpApp.c > >> create mode 100644 > >> > ShellPkg/DynamicCommand/HttpDynamicCommand/HttpDynamicCommand > .c > >> create mode 100644 > ShellPkg/DynamicCommand/HttpDynamicCommand/Http.uni > >> > >> diff --git a/ShellPkg/ShellPkg.dec b/ShellPkg/ShellPkg.dec > >> index d0843d338126..7b2d1230bd2c 100644 > >> --- a/ShellPkg/ShellPkg.dec > >> +++ b/ShellPkg/ShellPkg.dec > >> @@ -53,6 +53,7 @@ [Guids] > >> gShellNetwork1HiiGuid = {0xf3d301bb, 0xf4a5, 0x45a8, > >> {0xb0, 0xb7, 0xfa, 0x99, 0x9c, 0x62, 0x37, 0xae}} > >> gShellNetwork2HiiGuid = {0x174b2b5, 0xf505, 0x4b12, > >> {0xaa, 0x60, 0x59, 0xdf, 0xf8, 0xd6, 0xea, 0x37}} > >> gShellTftpHiiGuid = {0x738a9314, 0x82c1, 0x4592, > >> {0x8f, 0xf7, 0xc1, 0xbd, 0xf1, 0xb2, 0x0e, 0xd4}} > >> + gShellHttpHiiGuid = {0x390f84b3, 0x221c, 0x4d9e, > >> {0xb5, 0x06, 0x6d, 0xb9, 0x42, 0x3e, 0x0a, 0x7e}} > >> gShellBcfgHiiGuid = {0x5f5f605d, 0x1583, 0x4a2d, > >> {0xa6, 0xb2, 0xeb, 0x12, 0xda, 0xb4, 0xa2, 0xb6}} > >> gShellAcpiViewHiiGuid = {0xda8ccdf4, 0xed8f, 0x4ffc, > >> {0xb5, 0xef, 0x2e, 0xf5, 0x5e, 0x24, 0x93, 0x2a}} > >> # FILE_GUID as defined in ShellPkg/Application/Shell/Shell.inf > >> diff --git a/ShellPkg/ShellPkg.dsc b/ShellPkg/ShellPkg.dsc > >> index 86e9f1e0040d..c42bc9464a0f 100644 > >> --- a/ShellPkg/ShellPkg.dsc > >> +++ b/ShellPkg/ShellPkg.dsc > >> @@ -139,6 +139,11 @@ [Components] > >> gEfiShellPkgTokenSpaceGuid.PcdShellLibAutoInitialize|FALSE > >> } > >> ShellPkg/DynamicCommand/TftpDynamicCommand/TftpApp.inf > >> > + ShellPkg/DynamicCommand/HttpDynamicCommand/HttpDynamicComma > nd.inf { > >> + > >> + gEfiShellPkgTokenSpaceGuid.PcdShellLibAutoInitialize|FALSE > >> + } > >> + ShellPkg/DynamicCommand/HttpDynamicCommand/HttpApp.inf > >> ShellPkg/DynamicCommand/DpDynamicCommand/DpDynamicComma > nd.inf { > >> > >> gEfiShellPkgTokenSpaceGuid.PcdShellLibAutoInitialize|FALSE > >> diff --git > a/ShellPkg/DynamicCommand/HttpDynamicCommand/HttpApp.inf > >> b/ShellPkg/DynamicCommand/HttpDynamicCommand/HttpApp.inf > >> new file mode 100644 > >> index 000000000000..d08d47fb37d5 > >> --- /dev/null > >> +++ b/ShellPkg/DynamicCommand/HttpDynamicCommand/HttpApp.inf > >> @@ -0,0 +1,58 @@ > >> +## @file > >> +# Provides Shell 'http' standalone application. > >> +# > >> +# Copyright (c) 2010 - 2019, Intel Corporation. All rights reserved. > >>
> >> +# Copyright (c) 2015, ARM Ltd. All rights reserved.
> >> +# Copyright (c) 2020, Broadcom. All rights reserved.
> >> +# > >> +# SPDX-License-Identifier: BSD-2-Clause-Patent > >> +# > >> +# > >> +## > >> + > >> +[Defines] > >> + INF_VERSION = 0x00010006 > >> + BASE_NAME = http > >> + FILE_GUID = > >> 56B00FB7-91D2-869B-CE5C-26CD1A89C73C > >> + MODULE_TYPE = UEFI_APPLICATION > >> + VERSION_STRING = 1.0 > >> + ENTRY_POINT = HttpAppInitialize > >> +# > >> +# This flag specifies whether HII resource section is generated into > >> PE image. > >> +# > >> + UEFI_HII_RESOURCE_SECTION = TRUE > >> + > >> +[Sources.common] > >> + Http.c > >> + HttpApp.c > >> + Http.h > >> + Http.uni > >> + > >> +[Packages] > >> + EmbeddedPkg/EmbeddedPkg.dec > >> + MdeModulePkg/MdeModulePkg.dec > >> + MdePkg/MdePkg.dec > >> + NetworkPkg/NetworkPkg.dec > >> + ShellPkg/ShellPkg.dec > >> + > >> +[LibraryClasses] > >> + BaseLib > >> + BaseMemoryLib > >> + DebugLib > >> + FileHandleLib > >> + HiiLib > >> + HttpLib > >> + MemoryAllocationLib > >> + NetLib > >> + ShellLib > >> + UefiApplicationEntryPoint > >> + UefiBootServicesTableLib > >> + UefiHiiServicesLib > >> + UefiLib > >> + UefiRuntimeServicesTableLib > >> + > >> +[Protocols] > >> + gEfiHiiPackageListProtocolGuid ## CONSUMES > >> + gEfiHttpProtocolGuid ## CONSUMES > >> + gEfiHttpServiceBindingProtocolGuid ## CONSUMES > >> + gEfiManagedNetworkServiceBindingProtocolGuid ## CONSUMES > >> diff --git > >> > a/ShellPkg/DynamicCommand/HttpDynamicCommand/HttpDynamicComma > nd.inf > >> > b/ShellPkg/DynamicCommand/HttpDynamicCommand/HttpDynamicComma > nd.inf > >> new file mode 100644 > >> index 000000000000..5d46ee2384d5 > >> --- /dev/null > >> +++ > b/ShellPkg/DynamicCommand/HttpDynamicCommand/HttpDynamicComma > nd.inf > >> @@ -0,0 +1,63 @@ > >> +## @file > >> +# Provides Shell 'http' dynamic command. > >> +# > >> +# Copyright (c) 2010 - 2019, Intel Corporation. All rights reserved. > >>
> >> +# Copyright (c) 2015, ARM Ltd. All rights reserved.
> >> +# Copyright (c) 2020, Broadcom. All rights reserved.
> >> +# > >> +# SPDX-License-Identifier: BSD-2-Clause-Patent > >> +# > >> +# > >> +## > >> + > >> +[Defines] > >> + INF_VERSION = 0x00010006 > >> + BASE_NAME = httpDynamicCommand > >> + FILE_GUID = > >> 19618BCE-55AE-09C6-37E9-4CE04084C7A1 > >> + MODULE_TYPE = DXE_DRIVER > >> + VERSION_STRING = 1.0 > >> + ENTRY_POINT = HttpCommandInitialize > >> + UNLOAD_IMAGE = HttpUnload > >> +# > >> +# This flag specifies whether HII resource section is generated into > >> PE image. > >> +# > >> + UEFI_HII_RESOURCE_SECTION = TRUE > >> + > >> +[Sources.common] > >> + Http.c > >> + HttpDynamicCommand.c > >> + Http.h > >> + Http.uni > >> + > >> +[Packages] > >> + EmbeddedPkg/EmbeddedPkg.dec > >> + MdePkg/MdePkg.dec > >> + MdeModulePkg/MdeModulePkg.dec > >> + NetworkPkg/NetworkPkg.dec > >> + ShellPkg/ShellPkg.dec > >> + > >> +[LibraryClasses] > >> + BaseLib > >> + BaseMemoryLib > >> + DebugLib > >> + FileHandleLib > >> + HiiLib > >> + HttpLib > >> + MemoryAllocationLib > >> + NetLib > >> + ShellLib > >> + UefiBootServicesTableLib > >> + UefiDriverEntryPoint > >> + UefiHiiServicesLib > >> + UefiLib > >> + UefiRuntimeServicesTableLib > >> + > >> +[Protocols] > >> + gEfiHiiPackageListProtocolGuid ## CONSUMES > >> + gEfiHttpProtocolGuid ## CONSUMES > >> + gEfiHttpServiceBindingProtocolGuid ## CONSUMES > >> + gEfiManagedNetworkServiceBindingProtocolGuid ## CONSUMES > >> + gEfiShellDynamicCommandProtocolGuid ## PRODUCES > >> + > >> +[DEPEX] > >> + TRUE > >> diff --git a/ShellPkg/DynamicCommand/HttpDynamicCommand/Http.h > >> b/ShellPkg/DynamicCommand/HttpDynamicCommand/Http.h > >> new file mode 100644 > >> index 000000000000..c53479b823e7 > >> --- /dev/null > >> +++ b/ShellPkg/DynamicCommand/HttpDynamicCommand/Http.h > >> @@ -0,0 +1,90 @@ > >> +/** @file > >> + Header file for 'http' command functions. > >> + > >> + Copyright (c) 2010 - 2017, Intel Corporation. All rights reserved. > >>
> >> + Copyright (c) 2015, ARM Ltd. All rights reserved.
> >> + Copyright (c) 2020, Broadcom. All rights reserved.
> >> + > >> + SPDX-License-Identifier: BSD-2-Clause-Patent > >> + > >> +**/ > >> + > >> +#ifndef _HTTP_H_ > >> +#define _HTTP_H_ > >> + > >> +#include > >> + > >> +#include > >> +#include > >> +#include > >> +#include > >> +#include > >> +#include > >> +#include > >> +#include > >> +#include > >> +#include > >> +#include > >> +#include > >> +#include > >> + > >> +#include > >> +#include > >> +#include > >> + > >> +#define HTTP_APP_NAME L"http" > >> + > >> +#define REQ_OK 0 > >> +#define REQ_NEED_REPEAT 1 > >> + > >> +// Download Flags > >> +#define DL_FLAG_TIME BIT0 // Show elapsed time. > >> +#define DL_FLAG_KEEP_BAD BIT1 // Keep files even if download failed. > >> + > >> +extern EFI_HII_HANDLE mHttpHiiHandle; > >> + > >> +typedef struct { > >> + UINTN ContentDownloaded; > >> + UINTN ContentLength; > >> + UINTN LastReportedNbOfBytes; > >> + UINTN BufferSize; > >> + UINTN Status; > >> + UINTN Flags; > >> + UINT8 *Buffer; > >> + CHAR16 *ServerAddrAndProto; > >> + CHAR16 *URI; > >> + EFI_HTTP_TOKEN ResponseToken; > >> + EFI_HTTP_TOKEN RequestToken; > >> + EFI_HTTP_PROTOCOL *Http; > >> + EFI_HTTP_CONFIG_DATA HttpConfigData; > >> +} HTTP_DOWNLOAD_CONTEXT; > >> + > >> +/** > >> + Function for 'http' command. > >> + > >> + @param[in] ImageHandle The image handle. > >> + @param[in] SystemTable The system table. > >> + > >> + @retval SHELL_SUCCESS Command completed successfully. > >> + @retval SHELL_INVALID_PARAMETER Command usage error. > >> + @retval SHELL_ABORTED The user aborts the operation. > >> + @retval value Unknown error. > >> +**/ > >> +SHELL_STATUS > >> +RunHttp ( > >> + IN EFI_HANDLE ImageHandle, > >> + IN EFI_SYSTEM_TABLE *SystemTable > >> + ); > >> + > >> +/** > >> + Retrive HII package list from ImageHandle and publish to HII > >> database. > >> + > >> + @param ImageHandle The image handle of the process. > >> + > >> + @return HII handle. > >> +**/ > >> +EFI_HII_HANDLE > >> +InitializeHiiPackage ( > >> + EFI_HANDLE ImageHandle > >> + ); > >> +#endif // _HTTP_H_ > >> diff --git a/ShellPkg/Include/Guid/ShellLibHiiGuid.h > >> b/ShellPkg/Include/Guid/ShellLibHiiGuid.h > >> index 5da9128333a4..6e328b460d8c 100644 > >> --- a/ShellPkg/Include/Guid/ShellLibHiiGuid.h > >> +++ b/ShellPkg/Include/Guid/ShellLibHiiGuid.h > >> @@ -59,6 +59,10 @@ > >> 0x738a9314, 0x82c1, 0x4592, { 0x8f, 0xf7, 0xc1, 0xbd, 0xf1, > >> 0xb2, 0x0e, 0xd4 } \ > >> } > >> +#define SHELL_HTTP_HII_GUID \ > >> + { \ > >> + 0x390f84b3, 0x221c, 0x4d9e, { 0xb5, 0x06, 0x6d, 0xb9, 0x42, 0x3e, > >> 0x0a, 0x7e } \ > >> + } > >> #define SHELL_BCFG_HII_GUID \ > >> { \ > >> @@ -75,6 +79,7 @@ extern EFI_GUID gShellLevel3HiiGuid; > >> extern EFI_GUID gShellNetwork1HiiGuid; > >> extern EFI_GUID gShellNetwork2HiiGuid; > >> extern EFI_GUID gShellTftpHiiGuid; > >> +extern EFI_GUID gShellHttpHiiGuid; > >> extern EFI_GUID gShellBcfgHiiGuid; > >> #endif > >> diff --git a/ShellPkg/DynamicCommand/HttpDynamicCommand/Http.c > >> b/ShellPkg/DynamicCommand/HttpDynamicCommand/Http.c > >> new file mode 100644 > >> index 000000000000..5fc5f63bb763 > >> --- /dev/null > >> +++ b/ShellPkg/DynamicCommand/HttpDynamicCommand/Http.c > >> @@ -0,0 +1,1831 @@ > >> +/** @file > >> + The implementation for the 'http' Shell command. > >> + > >> + Copyright (c) 2015, ARM Ltd. All rights reserved.
> >> + Copyright (c) 2015 - 2018, Intel Corporation. All rights reserved. > >>
> >> + (C) Copyright 2015 Hewlett Packard Enterprise Development LP
> >> + Copyright (c) 2020, Broadcom. All rights reserved.
> >> + > >> + SPDX-License-Identifier: BSD-2-Clause-Patent > >> +**/ > >> + > >> +#include "Http.h" > >> + > >> +#define IP4_CONFIG2_INTERFACE_INFO_NAME_LENGTH 32 > >> + > >> +/* > >> + Constant strings and definitions related to the message > >> + indicating the amount of progress in the dowloading of a HTTP file. > >> +*/ > >> + > >> +// Number of steps in the progression slider > >> +#define HTTP_PROGRESS_SLIDER_STEPS \ > >> + ((sizeof (HTTP_PROGR_FRAME) / sizeof (CHAR16)) - 3) > >> + > >> +// Size in number of characters plus one (final zero) of the message > >> to > >> +// indicate the progress of an HTTP download. The format is > >> "[(progress slider: > >> +// 40 characters)] (nb of KBytes downloaded so far: 7 characters) > >> Kb". There > >> +// are thus the number of characters in HTTP_PROGR_FRAME[] plus 11 > >> characters > >> +// (2 // spaces, "Kb" and seven characters for the number of KBytes). > >> +#define HTTP_PROGRESS_MESSAGE_SIZE \ > >> + ((sizeof (HTTP_PROGR_FRAME) / sizeof (CHAR16)) + 12) > >> + > >> +// > >> +// Buffer size. Note that larger buffer does not mean better speed! > >> +// > >> +#define DEFAULT_BUF_SIZE SIZE_32KB > >> +#define MAX_BUF_SIZE SIZE_4MB > >> + > >> +#define MIN_PARAM_COUNT 2 > >> +#define MAX_PARAM_COUNT 4 > >> +#define NEED_REDIRECTION(Code) \ > >> + (((Code >= HTTP_STATUS_300_MULTIPLE_CHOICES) \ > >> + && (Code <= HTTP_STATUS_307_TEMPORARY_REDIRECT)) \ > >> + || (Code == HTTP_STATUS_308_PERMANENT_REDIRECT)) > >> + > >> +#define CLOSE_HTTP_HANDLE(ControllerHandle,HttpChildHandle) \ > >> + do { \ > >> + if (HttpChildHandle) { \ > >> + CloseProtocolAndDestroyServiceChild ( \ > >> + ControllerHandle, \ > >> + &gEfiHttpServiceBindingProtocolGuid, \ > >> + &gEfiHttpProtocolGuid, \ > >> + HttpChildHandle \ > >> + ); \ > >> + HttpChildHandle = NULL; \ > >> + } \ > >> + } while (0) > >> + > >> +typedef enum { > >> + HDR_HOST, > >> + HDR_CONN, > >> + HDR_AGENT, > >> + HDR_MAX > >> +} HDR_TYPE; > >> + > >> +#define USER_AGENT_HDR "Mozilla/5.0 (EDK2; Linux) Gecko/20100101 > >> Firefox/79.0" > >> + > >> +#define TIMER_MAX_TIMEOUT_S 10 > >> + > >> +// File name to use when URI ends with "/" > >> +#define DEFAULT_HTML_FILE L"index.html" > >> +#define DEFAULT_HTTP_PROTO L"http" > >> + > >> +// String to delete the HTTP progress message to be able to update it > >> : > >> +// (HTTP_PROGRESS_MESSAGE_SIZE-1) '\b' > >> +#define HTTP_PROGRESS_DEL \ > >> + > >> > L"\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\ > b\b\b\ > >> +\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b" > >> + > >> +#define HTTP_KB L"\b\b\b\b\b\b\b\b\b\b" > >> +// Frame for the progression slider > >> +#define HTTP_PROGR_FRAME > >> L"[ ]" > >> + > >> +#define EPOCH_JULIAN_DATE 2440588 > >> +// Seconds per unit > >> +#define SEC_PER_MIN ((UINTN) > >> 60) > >> +#define SEC_PER_HOUR ((UINTN) > >> 3600) > >> +#define SEC_PER_DAY ((UINTN) > >> 86400) > >> +#define SEC_PER_MONTH ((UINTN) > >> 2,592,000) > >> +#define SEC_PER_YEAR ((UINTN) > >> 31,536,000) > >> + > >> +// Improve readability by using these macros > >> +#define PRINT_HII(token,...) \ > >> + ShellPrintHiiEx (\ > >> + -1, -1, NULL, token, mHttpHiiHandle, __VA_ARGS__) > >> + > >> +#define PRINT_HII_APP(token,value) \ > >> + PRINT_HII (token, HTTP_APP_NAME, value) > >> + > >> +// String descriptions for server errors > >> +STATIC CONST CHAR16 *ErrStatusDesc[] = > >> +{ > >> + L"400 Bad Request", > >> + L"401 Unauthorized", > >> + L"402 Payment required", > >> + L"403 Forbidden", > >> + L"404 Not Found", > >> + L"405 Method not allowed", > >> + L"406 Not acceptable", > >> + L"407 Proxy authentication required", > >> + L"408 Request time out", > >> + L"409 Conflict", > >> + L"410 Gone", > >> + L"411 Length required", > >> + L"412 Precondition failed", > >> + L"413 Request entity too large", > >> + L"414 Request URI to large", > >> + L"415 Unsupported media type", > >> + L"416 Requested range not satisfied", > >> + L"417 Expectation failed", > >> + L"500 Internal server error", > >> + L"501 Not implemented", > >> + L"502 Bad gateway", > >> + L"503 Service unavailable", > >> + L"504 Gateway timeout", > >> + L"505 HTTP version not supported" > >> +}; > >> + > >> +STATIC CONST SHELL_PARAM_ITEM ParamList[] = { > >> + {L"-i", TypeValue}, > >> + {L"-k", TypeFlag}, > >> + {L"-l", TypeValue}, > >> + {L"-m", TypeFlag}, > >> + {L"-s", TypeValue}, > >> + {L"-t", TypeValue}, > >> + {NULL , TypeMax} > >> +}; > >> + > >> +// Local File Handle > >> +STATIC SHELL_FILE_HANDLE mFileHandle = NULL; > >> + > >> +// Path of the local file, Unicode encoded > >> +STATIC CONST CHAR16 *mLocalFilePath; > >> + > >> +STATIC BOOLEAN gRequestCallbackComplete = FALSE; > >> +STATIC BOOLEAN gResponseCallbackComplete = FALSE; > >> + > >> +STATIC BOOLEAN gHttpError; > >> + > >> +EFI_HII_HANDLE mHttpHiiHandle; > >> + > >> +// Functions declarations > >> +/** > >> + Check and convert the UINT16 option values of the 'http' command > >> + > >> + @param[in] ValueStr Value as an Unicode encoded string > >> + @param[out] Value UINT16 value > >> + > >> + @return TRUE The value was returned. > >> + @return FALSE A parsing error occured. > >> +**/ > >> +STATIC > >> +BOOLEAN > >> +StringToUint16 ( > >> + IN CONST CHAR16 *ValueStr, > >> + OUT UINT16 *Value > >> + ); > >> + > >> +/** > >> + Get the name of the NIC. > >> + > >> + @param[in] ControllerHandle The network physical device handle. > >> + @param[in] NicNumber The network physical device number. > >> + @param[out] NicName Address where to store the NIC name. > >> + The memory area has to be at least > >> + > >> IP4_CONFIG2_INTERFACE_INFO_NAME_LENGTH > >> + double byte wide. > >> + > >> + @return EFI_SUCCESS The name of the NIC was returned. > >> + @return Others The creation of the child for the Managed > >> + Network Service failed or the opening of > >> + the Managed Network Protocol failed or > >> + the operational parameters for the > >> + Managed Network Protocol could not be > >> + read. > >> +**/ > >> +STATIC > >> +EFI_STATUS > >> +GetNicName ( > >> + IN EFI_HANDLE ControllerHandle, > >> + IN UINTN NicNumber, > >> + OUT CHAR16 *NicName > >> + ); > >> + > >> +/** > >> + Create a child for the service identified by its service binding > >> protocol GUID > >> + and get from the child the interface of the protocol identified by > >> its GUID. > >> + > >> + @param[in] ControllerHandle Controller handle. > >> + @param[in] ServiceBindingProtocolGuid Service binding protocol > >> GUID of the > >> + service to be created. > >> + @param[in] ProtocolGuid GUID of the protocol to be > >> open. > >> + @param[out] ChildHandle Address where the handler > >> of the > >> + created child is returned. > >> NULL is > >> + returned in case of error. > >> + @param[out] Interface Address where a pointer to > >> the > >> + protocol interface is > >> returned in > >> + case of success. > >> + > >> + @return EFI_SUCCESS The child was created and the protocol opened. > >> + @return Others Either the creation of the child or the > >> opening > >> + of the protocol failed. > >> +**/ > >> +STATIC > >> +EFI_STATUS > >> +CreateServiceChildAndOpenProtocol ( > >> + IN EFI_HANDLE ControllerHandle, > >> + IN EFI_GUID *ServiceBindingProtocolGuid, > >> + IN EFI_GUID *ProtocolGuid, > >> + OUT EFI_HANDLE *ChildHandle, > >> + OUT VOID **Interface > >> + ); > >> + > >> +/** > >> + Close the protocol identified by its GUID on the child handle of > >> the service > >> + identified by its service binding protocol GUID, then destroy the > >> child > >> + handle. > >> + > >> + @param[in] ControllerHandle Controller handle. > >> + @param[in] ServiceBindingProtocolGuid Service binding protocol > >> GUID of the > >> + service to be destroyed. > >> + @param[in] ProtocolGuid GUID of the protocol to be > >> closed. > >> + @param[in] ChildHandle Handle of the child to be > >> destroyed. > >> + > >> +**/ > >> +STATIC > >> +VOID > >> +CloseProtocolAndDestroyServiceChild ( > >> + IN EFI_HANDLE ControllerHandle, > >> + IN EFI_GUID *ServiceBindingProtocolGuid, > >> + IN EFI_GUID *ProtocolGuid, > >> + IN EFI_HANDLE ChildHandle > >> + ); > >> + > >> +/** > >> + Worker function that download the data of a file from an HTTP > >> server given > >> + the path of the file and its size. > >> + > >> + @param[in] Context A pointer to the download context. > >> + > >> + @retval EFI_SUCCESS The file was downloaded. > >> + @retval EFI_OUT_OF_RESOURCES A memory allocation failed. > >> + @retval Others The downloading of the file > >> + from the server failed. > >> + > >> +**/ > >> +STATIC > >> +EFI_STATUS > >> +DownloadFile ( > >> + IN HTTP_DOWNLOAD_CONTEXT *Context, > >> + IN EFI_HANDLE ControllerHandle, > >> + IN CHAR16 *NicName > >> + ); > >> + > >> +/** > >> + Cleans off leading and trailing spaces and tabs. > >> + > >> + @param[in] String pointer to the string to trim them off. > >> +**/ > >> +STATIC > >> +EFI_STATUS > >> +TrimSpaces ( > >> + IN CHAR16 *String > >> + ) > >> +{ > >> + CHAR16 *Str; > >> + UINTN Len; > >> + > >> + ASSERT (String != NULL); > >> + > >> + if (!String) { > >> + return EFI_INVALID_PARAMETER; > >> + } > >> + > >> + Str = String; > >> + > >> + // > >> + // Remove any whitespace at the beginning of the Str. > >> + // > >> + while (*Str == L' ' || *Str == L'\t') { > >> + Str++; > >> + } > >> + > >> + // > >> + // Remove any whitespace at the end of the Str. > >> + // > >> + do { > >> + Len = StrLen (Str); > >> + if (!Len || (Str[Len - 1] != L' ' && Str[Len - 1] != '\t')) { > >> + break; > >> + } > >> + > >> + Str[Len - 1] = CHAR_NULL; > >> + } while (Len); > >> + > >> + CopyMem (String, Str, StrSize (Str)); > >> + > >> + return EFI_SUCCESS; > >> +} > >> + > >> + > >> +/* > >> + * Callbacks for request and response. > >> + * We just acknowledge that operation has completed here. > >> + */ > >> +STATIC > >> +VOID > >> +EFIAPI > >> +RequestCallback ( > >> + IN EFI_EVENT Event, > >> + IN VOID *Context > >> + ) > >> +{ > >> + gRequestCallbackComplete = TRUE; > >> +} > >> + > >> +STATIC > >> +VOID > >> +EFIAPI > >> +ResponseCallback ( > >> + IN EFI_EVENT Event, > >> + IN VOID *Context > >> + ) > >> +{ > >> + gResponseCallbackComplete = TRUE; > >> +} > >> + > >> +/** > >> + Calculate Epoch days > >> + **/ > >> +STATIC > >> +UINTN > >> +EfiGetEpochDays ( > >> + IN EFI_TIME *Time > >> + ) > >> +{ > >> + UINTN a; > >> + UINTN y; > >> + UINTN m; > >> + UINTN JulianDate; // Absolute Julian Date representation of the > >> supplied Time > >> + UINTN EpochDays; // Number of days elapsed since > EPOCH_JULIAN_DAY > >> + > >> + a = (14 - Time->Month) / 12 ; > >> + y = Time->Year + 4800 - a; > >> + m = Time->Month + (12 * a) - 3; > >> + > >> + JulianDate = Time->Day + ((153 * m + 2) / 5) + (365 * y) + (y / 4) - > >> + (y / 100) + (y / 400) - 32045; > >> + > >> + ASSERT (JulianDate >= EPOCH_JULIAN_DATE); > >> + EpochDays = JulianDate - EPOCH_JULIAN_DATE; > >> + > >> + return EpochDays; > >> +} > >> + > >> +/** > >> + Converts EFI_TIME to Epoch seconds > >> + (elapsed since 1970 JANUARY 01, 00:00:00 UTC) > >> + **/ > >> +STATIC > >> +UINTN > >> +EfiTimeToEpoch ( > >> + IN EFI_TIME *Time > >> + ) > >> +{ > >> + UINTN EpochDays; // Number of days elapsed since > EPOCH_JULIAN_DAY > >> + UINTN EpochSeconds; > >> + > >> + EpochDays = EfiGetEpochDays (Time); > >> + > >> + EpochSeconds = (EpochDays * SEC_PER_DAY) + > >> + ((UINTN)Time->Hour * SEC_PER_HOUR) + > >> + (Time->Minute * SEC_PER_MIN) + Time->Second; > >> + > >> + return EpochSeconds; > >> +} > >> + > >> +/** > >> + Function for 'http' command. > >> + > >> + @param[in] ImageHandle Handle to the Image (NULL if Internal). > >> + @param[in] SystemTable Pointer to the System Table (NULL if > >> Internal). > >> + > >> + @return SHELL_SUCCESS The 'http' command completed > >> successfully. > >> + @return SHELL_ABORTED The Shell Library initialization > >> failed. > >> + @return SHELL_INVALID_PARAMETER At least one of the command's > >> arguments is > >> + not valid. > >> + @return SHELL_OUT_OF_RESOURCES A memory allocation failed. > >> + @return SHELL_NOT_FOUND Network Interface Card not found. > >> + @return SHELL_UNSUPPORTED Command was valid, but the server > >> returned > >> + a status code indicating some > >> error. > >> + Examine the file requested for > >> error body. > >> + > >> +**/ > >> +SHELL_STATUS > >> +RunHttp ( > >> + IN EFI_HANDLE ImageHandle, > >> + IN EFI_SYSTEM_TABLE *SystemTable > >> + ) > >> +{ > >> + EFI_STATUS Status; > >> + LIST_ENTRY *CheckPackage; > >> + UINTN ParamCount; > >> + UINTN HandleCount; > >> + UINTN NicNumber; > >> + UINTN InitialSize; > >> + UINTN ParamOffset; > >> + UINTN StartSize; > >> + CHAR16 *ProblemParam; > >> + CHAR16 > >> NicName[IP4_CONFIG2_INTERFACE_INFO_NAME_LENGTH]; > >> + CHAR16 *Walker1; > >> + CHAR16 *VStr; > >> + CONST CHAR16 *UserNicName; > >> + CONST CHAR16 *ValueStr; > >> + CONST CHAR16 *RemoteFilePath; > >> + CONST CHAR16 *Walker; > >> + EFI_HTTPv4_ACCESS_POINT IPv4Node; > >> + EFI_HANDLE *Handles; > >> + EFI_HANDLE ControllerHandle; > >> + HTTP_DOWNLOAD_CONTEXT Context; > >> + BOOLEAN NicFound; > >> + > >> + ProblemParam = NULL; > >> + RemoteFilePath = NULL; > >> + NicFound = FALSE; > >> + Handles = NULL; > >> + > >> + // > >> + // Initialize the Shell library (we must be in non-auto-init...) > >> + // > >> + ParamOffset = 0; > >> + gHttpError = FALSE; > >> + > >> + Status = ShellInitialize (); > >> + if (EFI_ERROR (Status)) { > >> + ASSERT_EFI_ERROR (Status); > >> + return SHELL_ABORTED; > >> + } > >> + > >> + ZeroMem (&Context, sizeof (Context)); > >> + > >> + // > >> + // Parse the command line. > >> + // > >> + Status = ShellCommandLineParse ( > >> + ParamList, > >> + &CheckPackage, > >> + &ProblemParam, > >> + TRUE > >> + ); > >> + if (EFI_ERROR (Status)) { > >> + if ((Status == EFI_VOLUME_CORRUPTED) > >> + && (ProblemParam != NULL)) > >> + { > >> + PRINT_HII_APP (STRING_TOKEN (STR_GEN_PROBLEM), > ProblemParam); > >> + SHELL_FREE_NON_NULL (ProblemParam); > >> + } else { > >> + ASSERT (FALSE); > >> + } > >> + > >> + goto Error; > >> + } > >> + > >> + // > >> + // Check the number of parameters > >> + // > >> + Status = EFI_INVALID_PARAMETER; > >> + > >> + ParamCount = ShellCommandLineGetCount (CheckPackage); > >> + if (ParamCount > MAX_PARAM_COUNT) { > >> + PRINT_HII_APP (STRING_TOKEN (STR_GEN_TOO_MANY), NULL); > >> + goto Error; > >> + } > >> + > >> + if (ParamCount < MIN_PARAM_COUNT) { > >> + PRINT_HII_APP (STRING_TOKEN (STR_GEN_TOO_FEW), NULL); > >> + goto Error; > >> + } > >> + > >> + ZeroMem (&Context.HttpConfigData, sizeof > (Context.HttpConfigData)); > >> + ZeroMem (&IPv4Node, sizeof (IPv4Node)); > >> + IPv4Node.UseDefaultAddress = TRUE; > >> + > >> + Context.HttpConfigData.HttpVersion = HttpVersion11; > >> + Context.HttpConfigData.AccessPoint.IPv4Node = &IPv4Node; > >> + > >> + // > >> + // Get the host address (not necessarily IPv4 format) > >> + // > >> + ValueStr = ShellCommandLineGetRawValue (CheckPackage, 1); > >> + if (!ValueStr) { > >> + PRINT_HII_APP (STRING_TOKEN (STR_GEN_PARAM_INV), ValueStr); > >> + goto Error; > >> + } else { > >> + StartSize = 0; > >> + TrimSpaces ((CHAR16 *)ValueStr); > >> + if (!StrStr (ValueStr, L"://")) { > >> + Context.ServerAddrAndProto = StrnCatGrow ( > >> + &Context.ServerAddrAndProto, > >> + &StartSize, > >> + DEFAULT_HTTP_PROTO, > >> + StrLen (DEFAULT_HTTP_PROTO) > >> + ); > >> + Context.ServerAddrAndProto = StrnCatGrow ( > >> + &Context.ServerAddrAndProto, > >> + &StartSize, > >> + L"://", > >> + StrLen (L"://") > >> + ); > >> + VStr = (CHAR16 *)ValueStr; > >> + } else { > >> + VStr = StrStr (ValueStr, L"://") + StrLen (L"://"); > >> + } > >> + > >> + for (Walker1 = VStr; *Walker1; Walker1++) { > >> + if (*Walker1 == L'/') { > >> + break; > >> + } > >> + } > >> + > >> + if (*Walker1 == L'/') { > >> + ParamOffset = 1; > >> + RemoteFilePath = Walker1; > >> + } > >> + > >> + Context.ServerAddrAndProto = StrnCatGrow ( > >> + &Context.ServerAddrAndProto, > >> + &StartSize, > >> + ValueStr, > >> + StrLen (ValueStr) - StrLen > >> (Walker1) > >> + ); > >> + if (!Context.ServerAddrAndProto) { > >> + Status = EFI_OUT_OF_RESOURCES; > >> + goto Error; > >> + } > >> + } > >> + > >> + if (!RemoteFilePath) { > >> + RemoteFilePath = ShellCommandLineGetRawValue (CheckPackage, 2); > >> + if (!RemoteFilePath) { > >> + // If no path given, assume just "/" > >> + RemoteFilePath = L"/"; > >> + } > >> + } > >> + > >> + TrimSpaces ((CHAR16 *)RemoteFilePath); > >> + > >> + if (ParamCount == MAX_PARAM_COUNT - ParamOffset) { > >> + mLocalFilePath = ShellCommandLineGetRawValue ( > >> + CheckPackage, > >> + MAX_PARAM_COUNT - 1 - ParamOffset > >> + ); > >> + } else { > >> + Walker = RemoteFilePath + StrLen (RemoteFilePath); > >> + while ((--Walker) >= RemoteFilePath) { > >> + if ((*Walker == L'\\') || > >> + (*Walker == L'/' ) ) { > >> + break; > >> + } > >> + } > >> + > >> + mLocalFilePath = Walker + 1; > >> + } > >> + > >> + if (!StrLen (mLocalFilePath)) { > >> + mLocalFilePath = DEFAULT_HTML_FILE; > >> + } > >> + > >> + InitialSize = 0; > >> + Context.URI = StrnCatGrow ( > >> + &Context.URI, > >> + &InitialSize, > >> + RemoteFilePath, > >> + StrLen (RemoteFilePath) > >> + ); > >> + if (!Context.URI) { > >> + Status = EFI_OUT_OF_RESOURCES; > >> + goto Error; > >> + } > >> + > >> + // > >> + // Get the name of the Network Interface Card to be used if any. > >> + // > >> + UserNicName = ShellCommandLineGetValue (CheckPackage, L"-i"); > >> + > >> + ValueStr = ShellCommandLineGetValue (CheckPackage, L"-l"); > >> + if ((ValueStr != NULL) > >> + && (!StringToUint16 ( > >> + ValueStr, > >> + &Context.HttpConfigData.AccessPoint.IPv4Node->LocalPort > >> + ) > >> + )) > >> + { > >> + goto Error; > >> + } > >> + > >> + Context.BufferSize = DEFAULT_BUF_SIZE; > >> + > >> + ValueStr = ShellCommandLineGetValue (CheckPackage, L"-s"); > >> + if (ValueStr != NULL) { > >> + Context.BufferSize = ShellStrToUintn (ValueStr); > >> + if (!Context.BufferSize || Context.BufferSize > MAX_BUF_SIZE) { > >> + PRINT_HII_APP (STRING_TOKEN (STR_GEN_PARAM_INV), ValueStr); > >> + goto Error; > >> + } > >> + } > >> + > >> + ValueStr = ShellCommandLineGetValue (CheckPackage, L"-t"); > >> + if (ValueStr != NULL) { > >> + Context.HttpConfigData.TimeOutMillisec = (UINT32)ShellStrToUintn > >> (ValueStr); > >> + } > >> + > >> + // > >> + // Locate all HTTP Service Binding protocols > >> + // > >> + Status = gBS->LocateHandleBuffer ( > >> + ByProtocol, > >> + &gEfiManagedNetworkServiceBindingProtocolGuid, > >> + NULL, > >> + &HandleCount, > >> + &Handles > >> + ); > >> + if (EFI_ERROR (Status) || (HandleCount == 0)) { > >> + PRINT_HII (STRING_TOKEN (STR_HTTP_ERR_NO_NIC), NULL); > >> + if (!EFI_ERROR (Status)) { > >> + Status = EFI_NOT_FOUND; > >> + } > >> + > >> + goto Error; > >> + } > >> + > >> + Status = EFI_NOT_FOUND; > >> + > >> + Context.Flags = 0; > >> + if (ShellCommandLineGetFlag (CheckPackage, L"-m")) { > >> + Context.Flags |= DL_FLAG_TIME; > >> + } > >> + > >> + if (ShellCommandLineGetFlag (CheckPackage, L"-k")) { > >> + Context.Flags |= DL_FLAG_KEEP_BAD; > >> + } > >> + > >> + for (NicNumber = 0; > >> + (NicNumber < HandleCount) && (Status != EFI_SUCCESS); > >> + NicNumber++) > >> + { > >> + ControllerHandle = Handles[NicNumber]; > >> + > >> + Status = GetNicName (ControllerHandle, NicNumber, NicName); > >> + if (EFI_ERROR (Status)) { > >> + PRINT_HII (STRING_TOKEN (STR_HTTP_ERR_NIC_NAME), > NicNumber, > >> Status); > >> + continue; > >> + } > >> + > >> + if (UserNicName != NULL) { > >> + if (StrCmp (NicName, UserNicName) != 0) { > >> + Status = EFI_NOT_FOUND; > >> + continue; > >> + } > >> + > >> + NicFound = TRUE; > >> + } > >> + > >> + Status = DownloadFile (&Context, ControllerHandle, NicName); > >> + PRINT_HII (STRING_TOKEN (STR_GEN_CRLF), NULL); > >> + > >> + if (EFI_ERROR (Status)) { > >> + PRINT_HII ( > >> + STRING_TOKEN (STR_HTTP_ERR_DOWNLOAD), > >> + RemoteFilePath, > >> + NicName, > >> + Status > >> + ); > >> + // If a user aborted the operation, do not try another > >> controller. > >> + if (Status == EFI_ABORTED) { > >> + goto Error; > >> + } > >> + } > >> + > >> + if (gHttpError) { > >> + // > >> + // This is not related to connection, so no need to repeat with > >> + // another interface. > >> + // > >> + break; > >> + } > >> + } > >> + > >> + if ((UserNicName != NULL) && (!NicFound)) { > >> + PRINT_HII (STRING_TOKEN (STR_HTTP_ERR_NIC_NOT_FOUND), > UserNicName); > >> + } > >> + > >> +Error: > >> + ShellCommandLineFreeVarList (CheckPackage); > >> + SHELL_FREE_NON_NULL (Handles); > >> + SHELL_FREE_NON_NULL (Context.ServerAddrAndProto); > >> + SHELL_FREE_NON_NULL (Context.URI); > >> + > >> + return Status & ~MAX_BIT; > >> +} > >> + > >> +/** > >> + Check and convert the UINT16 option values of the 'http' command > >> + > >> + @param[in] ValueStr Value as an Unicode encoded string > >> + @param[out] Value UINT16 value > >> + > >> + @return TRUE The value was returned. > >> + @return FALSE A parsing error occured. > >> +**/ > >> +STATIC > >> +BOOLEAN > >> +StringToUint16 ( > >> + IN CONST CHAR16 *ValueStr, > >> + OUT UINT16 *Value > >> + ) > >> +{ > >> + UINTN Val; > >> + > >> + Val = ShellStrToUintn (ValueStr); > >> + if (Val > MAX_UINT16) { > >> + PRINT_HII_APP (STRING_TOKEN (STR_GEN_PARAM_INV), ValueStr); > >> + return FALSE; > >> + } > >> + > >> + *Value = (UINT16)Val; > >> + return TRUE; > >> +} > >> + > >> +/** > >> + Get the name of the NIC. > >> + > >> + @param[in] ControllerHandle The network physical device handle. > >> + @param[in] NicNumber The network physical device number. > >> + @param[out] NicName Address where to store the NIC name. > >> + The memory area has to be at least > >> + > >> IP4_CONFIG2_INTERFACE_INFO_NAME_LENGTH > >> + double byte wide. > >> + > >> + @return EFI_SUCCESS The name of the NIC was returned. > >> + @return Others The creation of the child for the Managed > >> + Network Service failed or the opening of > >> + the Managed Network Protocol failed or > >> + the operational parameters for the > >> + Managed Network Protocol could not be > >> + read. > >> +**/ > >> +STATIC > >> +EFI_STATUS > >> +GetNicName ( > >> + IN EFI_HANDLE ControllerHandle, > >> + IN UINTN NicNumber, > >> + OUT CHAR16 *NicName > >> + ) > >> +{ > >> + EFI_STATUS Status; > >> + EFI_HANDLE MnpHandle; > >> + EFI_MANAGED_NETWORK_PROTOCOL *Mnp; > >> + EFI_SIMPLE_NETWORK_MODE SnpMode; > >> + > >> + Status = CreateServiceChildAndOpenProtocol ( > >> + ControllerHandle, > >> + &gEfiManagedNetworkServiceBindingProtocolGuid, > >> + &gEfiManagedNetworkProtocolGuid, > >> + &MnpHandle, > >> + (VOID**)&Mnp > >> + ); > >> + if (EFI_ERROR (Status)) { > >> + goto Error; > >> + } > >> + > >> + Status = Mnp->GetModeData (Mnp, NULL, &SnpMode); > >> + if (EFI_ERROR (Status) && (Status != EFI_NOT_STARTED)) { > >> + goto Error; > >> + } > >> + > >> + UnicodeSPrint ( > >> + NicName, > >> + IP4_CONFIG2_INTERFACE_INFO_NAME_LENGTH, > >> + SnpMode.IfType == NET_IFTYPE_ETHERNET ? L"eth%d" : L"unk%d", > >> + NicNumber > >> + ); > >> + > >> + Status = EFI_SUCCESS; > >> + > >> +Error: > >> + > >> + if (MnpHandle != NULL) { > >> + CloseProtocolAndDestroyServiceChild ( > >> + ControllerHandle, > >> + &gEfiManagedNetworkServiceBindingProtocolGuid, > >> + &gEfiManagedNetworkProtocolGuid, > >> + MnpHandle > >> + ); > >> + } > >> + > >> + return Status; > >> +} > >> + > >> +/** > >> + Create a child for the service identified by its service binding > >> protocol GUID > >> + and get from the child the interface of the protocol identified by > >> its GUID. > >> + > >> + @param[in] ControllerHandle Controller handle. > >> + @param[in] ServiceBindingProtocolGuid Service binding protocol > >> GUID of the > >> + service to be created. > >> + @param[in] ProtocolGuid GUID of the protocol to be > >> open. > >> + @param[out] ChildHandle Address where the handler > >> of the > >> + created child is returned. > >> NULL is > >> + returned in case of error. > >> + @param[out] Interface Address where a pointer to > >> the > >> + protocol interface is > >> returned in > >> + case of success. > >> + > >> + @return EFI_SUCCESS The child was created and the protocol opened. > >> + @return Others Either the creation of the child or the > >> opening > >> + of the protocol failed. > >> +**/ > >> +STATIC > >> +EFI_STATUS > >> +CreateServiceChildAndOpenProtocol ( > >> + IN EFI_HANDLE ControllerHandle, > >> + IN EFI_GUID *ServiceBindingProtocolGuid, > >> + IN EFI_GUID *ProtocolGuid, > >> + OUT EFI_HANDLE *ChildHandle, > >> + OUT VOID **Interface > >> + ) > >> +{ > >> + EFI_STATUS Status; > >> + > >> + *ChildHandle = NULL; > >> + Status = NetLibCreateServiceChild ( > >> + ControllerHandle, > >> + gImageHandle, > >> + ServiceBindingProtocolGuid, > >> + ChildHandle > >> + ); > >> + if (!EFI_ERROR (Status)) { > >> + Status = gBS->OpenProtocol ( > >> + *ChildHandle, > >> + ProtocolGuid, > >> + Interface, > >> + gImageHandle, > >> + ControllerHandle, > >> + EFI_OPEN_PROTOCOL_GET_PROTOCOL > >> + ); > >> + if (EFI_ERROR (Status)) { > >> + NetLibDestroyServiceChild ( > >> + ControllerHandle, > >> + gImageHandle, > >> + ServiceBindingProtocolGuid, > >> + *ChildHandle > >> + ); > >> + *ChildHandle = NULL; > >> + } > >> + } > >> + > >> + return Status; > >> +} > >> + > >> +/** > >> + Close the protocol identified by its GUID on the child handle of > >> the service > >> + identified by its service binding protocol GUID, then destroy the > >> child > >> + handle. > >> + > >> + @param[in] ControllerHandle Controller handle. > >> + @param[in] ServiceBindingProtocolGuid Service binding protocol > >> GUID of the > >> + service to be destroyed. > >> + @param[in] ProtocolGuid GUID of the protocol to be > >> closed. > >> + @param[in] ChildHandle Handle of the child to be > >> destroyed. > >> + > >> +**/ > >> +STATIC > >> +VOID > >> +CloseProtocolAndDestroyServiceChild ( > >> + IN EFI_HANDLE ControllerHandle, > >> + IN EFI_GUID *ServiceBindingProtocolGuid, > >> + IN EFI_GUID *ProtocolGuid, > >> + IN EFI_HANDLE ChildHandle > >> + ) > >> +{ > >> + gBS->CloseProtocol ( > >> + ChildHandle, > >> + ProtocolGuid, > >> + gImageHandle, > >> + ControllerHandle > >> + ); > >> + > >> + NetLibDestroyServiceChild ( > >> + ControllerHandle, > >> + gImageHandle, > >> + ServiceBindingProtocolGuid, > >> + ChildHandle > >> + ); > >> +} > >> + > >> +/** > >> + Wait until operation completes. Completion is indicated by > >> + setting of an appropriate variable. > >> + > >> + @param[in] Context A pointer to the HTTP download > >> context. > >> + @param[in] CallBackComplete A pointer to the callback > >> completion > >> + variable set by the callback. > >> + > >> + @return EFI_SUCCESS Callback signalled completion. > >> + @return EFI_TIMEOUT Timed out waiting for completion. > >> + @return Others Error waiting for completion. > >> +**/ > >> +STATIC > >> +EFI_STATUS > >> +WaitForCompletion ( > >> + IN HTTP_DOWNLOAD_CONTEXT *Context, > >> + IN OUT BOOLEAN *CallBackComplete > >> + ) > >> +{ > >> + EFI_STATUS Status; > >> + EFI_EVENT WaitEvt; > >> + > >> + Status = EFI_SUCCESS; > >> + > >> + // Use a timer to measure timeout. Cannot use Stall here! > >> + Status = gBS->CreateEvent ( > >> + EVT_TIMER, > >> + TPL_CALLBACK, > >> + NULL, > >> + NULL, > >> + &WaitEvt > >> + ); > >> + ASSERT_EFI_ERROR (Status); > >> + > >> + if (!EFI_ERROR (Status)) { > >> + Status = gBS->SetTimer ( > >> + WaitEvt, > >> + TimerRelative, > >> + EFI_TIMER_PERIOD_SECONDS (TIMER_MAX_TIMEOUT_S) > >> + ); > >> + > >> + ASSERT_EFI_ERROR (Status); > >> + } > >> + > >> + while (! *CallBackComplete > >> + && (!EFI_ERROR (Status)) > >> + && EFI_ERROR (gBS->CheckEvent (WaitEvt))) > >> + { > >> + Status = Context->Http->Poll (Context->Http); > >> + if (!Context->ContentDownloaded > >> + && CallBackComplete == &gResponseCallbackComplete) > >> + { > >> + // > >> + // An HTTP server may just send a response redirection header. > >> + // In this case, don't wait for the event as > >> + // it might never happen and we waste 10s waiting. > >> + // Note that at this point Response may not has been populated, > >> + // so it needs to be checked first. > >> + // > >> + if (Context->ResponseToken.Message > >> + && Context->ResponseToken.Message->Data.Response > >> + && (NEED_REDIRECTION ( > >> + Context->ResponseToken.Message->Data.Response->StatusCode > >> + ) > >> + )) > >> + { > >> + break; > >> + } > >> + } > >> + } > >> + > >> + gBS->SetTimer (WaitEvt, TimerCancel, 0); > >> + gBS->CloseEvent (WaitEvt); > >> + > >> + if (*CallBackComplete) { > >> + return EFI_SUCCESS; > >> + } > >> + > >> + if (!EFI_ERROR (Status)) { > >> + Status = EFI_TIMEOUT; > >> + } > >> + > >> + return Status; > >> +} > >> + > >> +/** > >> + Generate and send a request to the http server. > >> + > >> + @param[in] Context HTTP download context. > >> + @param[in] DownloadUrl Fully qualified URL to be downloaded. > >> + > >> + @return EFI_SUCCESS Request has been sent successfully. > >> + @return EFI_INVALID_PARAMETER Invalid URL. > >> + @return EFI_OUT_OF_RESOURCES Out of memory. > >> + @return EFI_DEVICE_ERROR If HTTPS is used, this probably > >> + means that TLS support either was not > >> + installed or not configured. > >> + @return Others Error sending the request. > >> +**/ > >> + > >> +STATIC > >> +EFI_STATUS > >> +SendRequest ( > >> + IN HTTP_DOWNLOAD_CONTEXT *Context, > >> + IN CHAR16 *DownloadUrl > >> + ) > >> +{ > >> + EFI_HTTP_REQUEST_DATA RequestData; > >> + EFI_HTTP_HEADER RequestHeader[HDR_MAX]; > >> + EFI_HTTP_MESSAGE RequestMessage; > >> + EFI_STATUS Status; > >> + CHAR16 *Host; > >> + UINTN StringSize; > >> + > >> + ZeroMem (&RequestData, sizeof (RequestData)); > >> + ZeroMem (&RequestHeader, sizeof (RequestHeader)); > >> + ZeroMem (&RequestMessage, sizeof (RequestMessage)); > >> + ZeroMem (&Context->RequestToken, sizeof (Context- > >RequestToken)); > >> + > >> + RequestHeader[HDR_HOST].FieldName = "Host"; > >> + RequestHeader[HDR_CONN].FieldName = "Connection"; > >> + RequestHeader[HDR_AGENT].FieldName = "User-Agent"; > >> + > >> + Host = (CHAR16 *)Context->ServerAddrAndProto; > >> + while (*Host != CHAR_NULL && *Host != L'/') { > >> + Host++; > >> + } > >> + > >> + if (*Host == CHAR_NULL) { > >> + return EFI_INVALID_PARAMETER; > >> + } > >> + > >> + // > >> + // Get the next slash > >> + // > >> + Host++; > >> + // > >> + // And now the host name > >> + // > >> + Host++; > >> + > >> + StringSize = StrLen (Host) + 1; > >> + RequestHeader[HDR_HOST].FieldValue = AllocatePool (StringSize); > >> + if (!RequestHeader[HDR_HOST].FieldValue) { > >> + return EFI_OUT_OF_RESOURCES; > >> + } > >> + > >> + UnicodeStrToAsciiStrS ( > >> + Host, > >> + RequestHeader[HDR_HOST].FieldValue, > >> + StringSize > >> + ); > >> + > >> + RequestHeader[HDR_CONN].FieldValue = "close"; > >> + RequestHeader[HDR_AGENT].FieldValue = USER_AGENT_HDR; > >> + RequestMessage.HeaderCount = HDR_MAX; > >> + > >> + RequestData.Method = HttpMethodGet; > >> + RequestData.Url = DownloadUrl; > >> + > >> + RequestMessage.Data.Request = &RequestData; > >> + RequestMessage.Headers = RequestHeader; > >> + RequestMessage.BodyLength = 0; > >> + RequestMessage.Body = NULL; > >> + Context->RequestToken.Event = NULL; > >> + > >> + // > >> + // Completion callback event to be set when Request completes. > >> + // > >> + Status = gBS->CreateEvent ( > >> + EVT_NOTIFY_SIGNAL, > >> + TPL_CALLBACK, > >> + RequestCallback, > >> + Context, > >> + &Context->RequestToken.Event > >> + ); > >> + ASSERT_EFI_ERROR (Status); > >> + > >> + Context->RequestToken.Status = EFI_SUCCESS; > >> + Context->RequestToken.Message = &RequestMessage; > >> + gRequestCallbackComplete = FALSE; > >> + Status = Context->Http->Request (Context->Http, > >> &Context->RequestToken); > >> + if (EFI_ERROR (Status)) { > >> + goto Error; > >> + } > >> + > >> + Status = WaitForCompletion (Context, &gRequestCallbackComplete); > >> + if (EFI_ERROR (Status)) { > >> + Context->Http->Cancel (Context->Http, &Context->RequestToken); > >> + } > >> + > >> +Error: > >> + SHELL_FREE_NON_NULL (RequestHeader[HDR_HOST].FieldValue); > >> + if (Context->RequestToken.Event) { > >> + gBS->CloseEvent (Context->RequestToken.Event); > >> + ZeroMem (&Context->RequestToken, sizeof (Context- > >RequestToken)); > >> + } > >> + > >> + return Status; > >> +} > >> + > >> +/** > >> + Update the progress of a file download > >> + This procedure is called each time a new HTTP body portion is > >> received. > >> + > >> + @param[in] Context HTTP download context. > >> + @param[in] DownloadLen Portion size, in bytes. > >> + @param[in] Buffer The pointer to the parsed buffer. > >> + > >> + @retval EFI_SUCCESS Portion saved. > >> + @retval Other Error saving the portion. > >> + > >> +**/ > >> +STATIC > >> +EFI_STATUS > >> +EFIAPI > >> +SavePortion ( > >> + IN HTTP_DOWNLOAD_CONTEXT *Context, > >> + IN UINTN DownloadLen, > >> + IN CHAR8 *Buffer > >> + ) > >> +{ > >> + CHAR16 Progress[HTTP_PROGRESS_MESSAGE_SIZE]; > >> + UINTN NbOfKb; > >> + UINTN Index; > >> + UINTN LastStep; > >> + UINTN Step; > >> + EFI_STATUS Status; > >> + > >> + LastStep = 0; > >> + Step = 0; > >> + > >> + ShellSetFilePosition (mFileHandle, Context->LastReportedNbOfBytes); > >> + Status = ShellWriteFile (mFileHandle, &DownloadLen, Buffer); > >> + if (EFI_ERROR (Status)) { > >> + if (Context->ContentDownloaded > 0) { > >> + PRINT_HII (STRING_TOKEN (STR_GEN_CRLF), NULL); > >> + } > >> + > >> + PRINT_HII (STRING_TOKEN (STR_HTTP_ERR_WRITE), mLocalFilePath, > >> Status); > >> + return Status; > >> + } > >> + > >> + if (Context->ContentDownloaded == 0) { > >> + ShellPrintEx (-1, -1, L"%s 0 Kb", HTTP_PROGR_FRAME); > >> + } > >> + > >> + Context->ContentDownloaded += DownloadLen; > >> + NbOfKb = Context->ContentDownloaded >> 10; > >> + > >> + Progress[0] = L'\0'; > >> + if (Context->ContentLength) { > >> + LastStep = (Context->LastReportedNbOfBytes * > >> HTTP_PROGRESS_SLIDER_STEPS) / > >> + Context->ContentLength; > >> + Step = (Context->ContentDownloaded * > >> HTTP_PROGRESS_SLIDER_STEPS) / > >> + Context->ContentLength; > >> + } > >> + > >> + Context->LastReportedNbOfBytes = Context->ContentDownloaded; > >> + > >> + if (Step <= LastStep) { > >> + if (!Context->ContentLength) { > >> + // > >> + // Update downloaded size, there is no length info available. > >> + // > >> + ShellPrintEx (-1, -1, L"%s", HTTP_KB); > >> + ShellPrintEx (-1, -1, L"%7d Kb", NbOfKb); > >> + } > >> + > >> + return EFI_SUCCESS; > >> + } > >> + > >> + ShellPrintEx (-1, -1, L"%s", HTTP_PROGRESS_DEL); > >> + > >> + Status = StrCpyS (Progress, HTTP_PROGRESS_MESSAGE_SIZE, > >> HTTP_PROGR_FRAME); > >> + if (EFI_ERROR (Status)) { > >> + return Status; > >> + } > >> + > >> + for (Index = 1; Index < Step; Index++) { > >> + Progress[Index] = L'='; > >> + } > >> + > >> + if (Step) { > >> + Progress[Step] = L'>'; > >> + } > >> + > >> + UnicodeSPrint ( > >> + Progress + (sizeof (HTTP_PROGR_FRAME) / sizeof (CHAR16)) - 1, > >> + sizeof (Progress) - sizeof (HTTP_PROGR_FRAME), > >> + L" %7d Kb", > >> + NbOfKb > >> + ); > >> + > >> + > >> + ShellPrintEx (-1, -1, L"%s", Progress); > >> + > >> + return EFI_SUCCESS; > >> +} > >> + > >> +/** > >> + Replace the original Host and URI with Host and URI returned by the > >> + HTTP server in 'Location' header (redirection). > >> + > >> + @param[in] Location A pointer to the 'Location' string > >> + provided by HTTP server. > >> + @param[in] Context A pointer to HTTP download context. > >> + @param[in] DownloadUrl Fully qualified HTTP URL. > >> + > >> + @return EFI_SUCCESS Host and URI were successfully set. > >> + @return EFI_OUT_OF_RESOURCES Error setting Host or URI. > >> +**/ > >> + > >> +STATIC > >> +EFI_STATUS > >> +SetHostURI ( > >> + IN CHAR8 *Location, > >> + IN HTTP_DOWNLOAD_CONTEXT *Context, > >> + IN CHAR16 *DownloadUrl > >> + ) > >> +{ > >> + EFI_STATUS Status; > >> + UINTN StringSize; > >> + UINTN FirstStep; > >> + UINTN Idx; > >> + UINTN Step; > >> + CHAR8 *Walker; > >> + CHAR16 *Temp; > >> + CHAR8 *Tmp; > >> + CHAR16 *Url; > >> + BOOLEAN IsAbEmptyUrl; > >> + > >> + Tmp = NULL; > >> + Url = NULL; > >> + IsAbEmptyUrl = FALSE; > >> + FirstStep = 0; > >> + > >> + StringSize = (AsciiStrSize (Location) * sizeof (CHAR16)); > >> + Url = AllocateZeroPool (StringSize); > >> + if (!Url) { > >> + return EFI_OUT_OF_RESOURCES; > >> + } > >> + > >> + Status = AsciiStrToUnicodeStrS ( > >> + (CONST CHAR8 *)Location, > >> + Url, > >> + StringSize > >> + ); > >> + > >> + if (EFI_ERROR (Status)) { > >> + goto Error; > >> + } > >> + > >> + // > >> + // If an HTTP server redirects to the same location more than once, > >> + // then stop attempts and tell it is not reachable. > >> + // > >> + if (!StrCmp (Url, DownloadUrl)) { > >> + Status = EFI_NO_MAPPING; > >> + goto Error; > >> + } > >> + > >> + if (AsciiStrLen (Location) > 2) { > >> + // Some servers return 'Location: //server/resource' > >> + IsAbEmptyUrl = (Location[0] == '/') && (Location[1] == '/'); > >> + if (IsAbEmptyUrl) { > >> + // Skip first "//" > >> + Location += 2; > >> + FirstStep = 1; > >> + } > >> + } > >> + > >> + if (AsciiStrStr (Location, "://") || IsAbEmptyUrl) { > >> + Idx = 0; > >> + Walker = Location; > >> + > >> + for (Step = FirstStep; Step < 2; Step++) { > >> + for (; *Walker != '/' && *Walker != '\0'; Walker++) { > >> + Idx++; > >> + } > >> + > >> + if (!Step) { > >> + // > >> + // Skip "//" > >> + // > >> + Idx += 2; > >> + Walker += 2; > >> + } > >> + } > >> + > >> + Tmp = AllocateZeroPool (Idx + 1); > >> + if (!Tmp) { > >> + Status = EFI_OUT_OF_RESOURCES; > >> + goto Error; > >> + } > >> + > >> + CopyMem (Tmp, Location, Idx); > >> + > >> + // > >> + // Location now points to URI > >> + // > >> + Location += Idx; > >> + StringSize = (Idx + 1) * sizeof (CHAR16); > >> + > >> + SHELL_FREE_NON_NULL (Context->ServerAddrAndProto); > >> + > >> + Temp = AllocateZeroPool (StringSize); > >> + if (!Temp) { > >> + Status = EFI_OUT_OF_RESOURCES; > >> + goto Error; > >> + } > >> + > >> + Status = AsciiStrToUnicodeStrS ( > >> + (CONST CHAR8 *)Tmp, > >> + Temp, > >> + StringSize > >> + ); > >> + if (EFI_ERROR (Status)) { > >> + SHELL_FREE_NON_NULL (Temp); > >> + goto Error; > >> + } > >> + > >> + Idx = 0; > >> + if (IsAbEmptyUrl) { > >> + Context->ServerAddrAndProto = StrnCatGrow ( > >> + &Context->ServerAddrAndProto, > >> + &Idx, > >> + L"http://", > >> + StrLen (L"http://") > >> + ); > >> + } > >> + > >> + Context->ServerAddrAndProto = StrnCatGrow ( > >> + &Context->ServerAddrAndProto, > >> + &Idx, > >> + Temp, > >> + StrLen (Temp) > >> + ); > >> + SHELL_FREE_NON_NULL (Temp); > >> + if (!Context->ServerAddrAndProto) { > >> + Status = EFI_OUT_OF_RESOURCES; > >> + goto Error; > >> + } > >> + } > >> + > >> + SHELL_FREE_NON_NULL (Context->URI); > >> + > >> + StringSize = AsciiStrSize (Location) * sizeof (CHAR16); > >> + Context->URI = AllocateZeroPool (StringSize); > >> + if (!Context->URI) { > >> + Status = EFI_OUT_OF_RESOURCES; > >> + goto Error; > >> + } > >> + > >> + // > >> + // Now make changes to the URI part. > >> + // > >> + Status = AsciiStrToUnicodeStrS ( > >> + (CONST CHAR8 *)Location, > >> + Context->URI, > >> + StringSize > >> + ); > >> +Error: > >> + SHELL_FREE_NON_NULL (Tmp); > >> + SHELL_FREE_NON_NULL (Url); > >> + > >> + return Status; > >> +} > >> + > >> +/** > >> + Message parser callback. > >> + Save a portion of HTTP body. > >> + > >> + @param[in] EventType Type of event. Can be either > >> + OnComplete or OnData. > >> + @param[in] Data A pointer to the buffer with data. > >> + @param[in] Length Data length of this portion. > >> + @param[in] Context A pointer to the HTTP download context. > >> + > >> + @return EFI_SUCCESS The portion was processed successfully. > >> + @return Other Error returned by SavePortion. > >> +**/ > >> + > >> +STATIC > >> +EFI_STATUS > >> +EFIAPI > >> +ParseMsg ( > >> + IN HTTP_BODY_PARSE_EVENT EventType, > >> + IN CHAR8 *Data, > >> + IN UINTN Length, > >> + IN VOID *Context > >> + ) > >> +{ > >> + if (!Data || (EventType == BodyParseEventOnComplete) || !Context) { > >> + return EFI_SUCCESS; > >> + } > >> + > >> + return SavePortion (Context, Length, Data); > >> +} > >> + > >> + > >> +/** > >> + Get HTTP server response and collect the whole body as a file. > >> + Set appropriate status in Context (REQ_OK, REQ_REPEAT, REQ_ERROR). > >> + Note that even if HTTP server returns an error code, it might send > >> + the body as well. This body will be collected in the resultant file. > >> + > >> + @param[in] Context A pointer to the HTTP download context. > >> + @param[in] DownloadedUrl A pointer to the fully qualified URL > >> to download. > >> + > >> + @return EFI_SUCCESS Valid file. Body successfully > >> collected. > >> + @return EFI_HTTP_ERROR Response is a valid HTTP response, but > >> the > >> + HTTP server > >> + indicated an error (HTTP code >= 400). > >> + Response body MAY contain full > >> + HTTP server response. > >> + @return Others Error getting the reponse from the > >> HTTP server. > >> + Response body is not collected. > >> +**/ > >> +STATIC > >> +EFI_STATUS > >> +GetResponse ( > >> + IN HTTP_DOWNLOAD_CONTEXT *Context, > >> + IN CHAR16 *DownloadUrl > >> + ) > >> +{ > >> + EFI_HTTP_RESPONSE_DATA ResponseData; > >> + EFI_HTTP_MESSAGE ResponseMessage; > >> + EFI_HTTP_HEADER *Header; > >> + EFI_STATUS Status; > >> + VOID *MsgParser; > >> + EFI_TIME StartTime; > >> + EFI_TIME EndTime; > >> + CONST CHAR16 *Desc; > >> + UINTN ElapsedSeconds; > >> + BOOLEAN IsTrunked; > >> + BOOLEAN CanMeasureTime; > >> + > >> + ZeroMem (&ResponseData, sizeof (ResponseData)); > >> + ZeroMem (&ResponseMessage, sizeof (ResponseMessage)); > >> + ZeroMem (&Context->ResponseToken, sizeof (Context- > >ResponseToken)); > >> + IsTrunked = FALSE; > >> + > >> + ResponseMessage.Body = Context->Buffer; > >> + Context->ResponseToken.Status = EFI_SUCCESS; > >> + Context->ResponseToken.Message = &ResponseMessage; > >> + Context->ContentLength = 0; > >> + Context->Status = REQ_OK; > >> + MsgParser = NULL; > >> + ResponseData.StatusCode = HTTP_STATUS_UNSUPPORTED_STATUS; > >> + ResponseMessage.Data.Response = &ResponseData; > >> + Context->ResponseToken.Event = NULL; > >> + CanMeasureTime = FALSE; > >> + if (Context->Flags & DL_FLAG_TIME) { > >> + ZeroMem (&StartTime, sizeof (StartTime)); > >> + CanMeasureTime = !EFI_ERROR (gRT->GetTime (&StartTime, NULL)); > >> + } > >> + > >> + do { > >> + SHELL_FREE_NON_NULL (ResponseMessage.Headers); > >> + ResponseMessage.HeaderCount = 0; > >> + gResponseCallbackComplete = FALSE; > >> + ResponseMessage.BodyLength = Context->BufferSize; > >> + > >> + if (ShellGetExecutionBreakFlag ()) { > >> + Status = EFI_ABORTED; > >> + break; > >> + } > >> + > >> + if (!Context->ContentDownloaded && !Context- > >ResponseToken.Event) { > >> + Status = gBS->CreateEvent ( > >> + EVT_NOTIFY_SIGNAL, > >> + TPL_CALLBACK, > >> + ResponseCallback, > >> + Context, > >> + &Context->ResponseToken.Event > >> + ); > >> + ASSERT_EFI_ERROR (Status); > >> + } else { > >> + ResponseMessage.Data.Response = NULL; > >> + } > >> + > >> + if (EFI_ERROR (Status)) { > >> + break; > >> + } > >> + > >> + Status = Context->Http->Response (Context->Http, > >> &Context->ResponseToken); > >> + if (EFI_ERROR (Status)) { > >> + break; > >> + } > >> + > >> + Status = WaitForCompletion (Context, &gResponseCallbackComplete); > >> + if (EFI_ERROR (Status) && ResponseMessage.HeaderCount) { > >> + Status = EFI_SUCCESS; > >> + } > >> + > >> + if (EFI_ERROR (Status)) { > >> + Context->Http->Cancel (Context->Http, &Context->ResponseToken); > >> + break; > >> + } > >> + > >> + if (!Context->ContentDownloaded) { > >> + if (NEED_REDIRECTION (ResponseData.StatusCode)) { > >> + // > >> + // Need to repeat the request with new Location (server > >> redirected). > >> + // > >> + Context->Status = REQ_NEED_REPEAT; > >> + > >> + Header = HttpFindHeader ( > >> + ResponseMessage.HeaderCount, > >> + ResponseMessage.Headers, > >> + "Location" > >> + ); > >> + if (Header) { > >> + Status = SetHostURI (Header->FieldValue, Context, > >> DownloadUrl); > >> + if (Status == EFI_NO_MAPPING) { > >> + PRINT_HII ( > >> + STRING_TOKEN (STR_HTTP_ERR_STATUSCODE), > >> + Context->ServerAddrAndProto, > >> + L"Recursive HTTP server relocation", > >> + Context->URI > >> + ); > >> + } > >> + } else { > >> + // > >> + // Bad reply from the server. Server must specify the > >> location. > >> + // Indicate that resource was not found, and no body > >> collected. > >> + // > >> + Status = EFI_NOT_FOUND; > >> + } > >> + > >> + Context->Http->Cancel (Context->Http, &Context- > >ResponseToken); > >> + break; > >> + } > >> + > >> + // > >> + // Init message-body parser by header information. > >> + // > >> + if (!MsgParser) { > >> + Status = HttpInitMsgParser ( > >> + ResponseMessage.Data.Request->Method, > >> + ResponseData.StatusCode, > >> + ResponseMessage.HeaderCount, > >> + ResponseMessage.Headers, > >> + ParseMsg, > >> + Context, > >> + &MsgParser > >> + ); > >> + if (EFI_ERROR (Status)) { > >> + break; > >> + } > >> + } > >> + > >> + // > >> + // If it is a trunked message, rely on the parser. > >> + // > >> + Header = HttpFindHeader ( > >> + ResponseMessage.HeaderCount, > >> + ResponseMessage.Headers, > >> + "Transfer-Encoding" > >> + ); > >> + IsTrunked = (Header && !AsciiStrCmp (Header->FieldValue, > >> "chunked")); > >> + > >> + HttpGetEntityLength (MsgParser, &Context->ContentLength); > >> + > >> + if (ResponseData.StatusCode >= HTTP_STATUS_400_BAD_REQUEST > >> + && (ResponseData.StatusCode != > >> HTTP_STATUS_308_PERMANENT_REDIRECT)) > >> + { > >> + // > >> + // Server reported an error via Response code. > >> + // Collect the body if any. > >> + // > >> + if (!gHttpError) { > >> + gHttpError = TRUE; > >> + > >> + Desc = ErrStatusDesc[ResponseData.StatusCode - > >> + HTTP_STATUS_400_BAD_REQUEST]; > >> + PRINT_HII ( > >> + STRING_TOKEN (STR_HTTP_ERR_STATUSCODE), > >> + Context->ServerAddrAndProto, > >> + Desc, > >> + Context->URI > >> + ); > >> + > >> + // > >> + // This gives an RFC HTTP error. > >> + // > >> + Context->Status = ShellStrToUintn (Desc); > >> + Status = ENCODE_ERROR (Context->Status); > >> + } > >> + } > >> + } > >> + > >> + // Do NOT try to parse an empty body. > >> + if (ResponseMessage.BodyLength || IsTrunked) { > >> + Status = HttpParseMessageBody ( > >> + MsgParser, > >> + ResponseMessage.BodyLength, > >> + ResponseMessage.Body > >> + ); > >> + } > >> + } while (!HttpIsMessageComplete (MsgParser) > >> + && !EFI_ERROR (Status) > >> + && ResponseMessage.BodyLength); > >> + > >> + if (Context->Status != REQ_NEED_REPEAT > >> + && Status == EFI_SUCCESS > >> + && CanMeasureTime) > >> + { > >> + if (!EFI_ERROR (gRT->GetTime (&EndTime, NULL))) { > >> + ElapsedSeconds = EfiTimeToEpoch (&EndTime) - EfiTimeToEpoch > >> (&StartTime); > >> + Print ( > >> + L",%a%us\n", > >> + ElapsedSeconds ? " " : " < ", > >> + ElapsedSeconds > 1 ? ElapsedSeconds : 1 > >> + ); > >> + } > >> + } > >> + > >> + SHELL_FREE_NON_NULL (MsgParser); > >> + if (Context->ResponseToken.Event) { > >> + gBS->CloseEvent (Context->ResponseToken.Event); > >> + ZeroMem (&Context->ResponseToken, sizeof (Context- > >ResponseToken)); > >> + } > >> + > >> + return Status; > >> +} > >> + > >> +/** > >> + Worker function that downloads the data of a file from an HTTP > >> server given > >> + the path of the file and its size. > >> + > >> + @param[in] Context A pointer to the HTTP download > >> context. > >> + @param[in] Controllerhandle The handle of the network interface > >> controller > >> + @param[in] NicName NIC name > >> + > >> + @retval EFI_SUCCESS The file was downloaded. > >> + @retval EFI_OUT_OF_RESOURCES A memory allocation failed. > >> + #retval EFI_HTTP_ERROR The server returned a valid HTTP > >> error. > >> + Examine the mLocalFilePath file > >> + to get error body. > >> + @retval Others The downloading of the file from the > >> server > >> + failed. > >> + > >> +**/ > >> +STATIC > >> +EFI_STATUS > >> +DownloadFile ( > >> + IN HTTP_DOWNLOAD_CONTEXT *Context, > >> + IN EFI_HANDLE ControllerHandle, > >> + IN CHAR16 *NicName > >> + ) > >> +{ > >> + EFI_STATUS Status; > >> + CHAR16 *DownloadUrl; > >> + UINTN UrlSize; > >> + EFI_HANDLE HttpChildHandle; > >> + > >> + ASSERT (Context); > >> + if (!Context) { > >> + return EFI_INVALID_PARAMETER; > >> + } > >> + > >> + DownloadUrl = NULL; > >> + HttpChildHandle = NULL; > >> + > >> + Context->Buffer = AllocatePool (Context->BufferSize); > >> + if (!Context->Buffer) { > >> + Status = EFI_OUT_OF_RESOURCES; > >> + goto ON_EXIT; > >> + } > >> + > >> + // > >> + // OPEN FILE > >> + // > >> + if (!EFI_ERROR (ShellFileExists (mLocalFilePath))) { > >> + ShellDeleteFileByName (mLocalFilePath); > >> + } > >> + > >> + Status = ShellOpenFileByName ( > >> + mLocalFilePath, > >> + &mFileHandle, > >> + EFI_FILE_MODE_CREATE | > >> + EFI_FILE_MODE_WRITE | > >> + EFI_FILE_MODE_READ, > >> + 0 > >> + ); > >> + if (EFI_ERROR (Status)) { > >> + PRINT_HII_APP (STRING_TOKEN (STR_GEN_FILE_OPEN_FAIL), > >> mLocalFilePath); > >> + goto ON_EXIT; > >> + } > >> + > >> + do { > >> + SHELL_FREE_NON_NULL (DownloadUrl); > >> + > >> + CLOSE_HTTP_HANDLE (ControllerHandle, HttpChildHandle); > >> + > >> + Status = CreateServiceChildAndOpenProtocol ( > >> + ControllerHandle, > >> + &gEfiHttpServiceBindingProtocolGuid, > >> + &gEfiHttpProtocolGuid, > >> + &HttpChildHandle, > >> + (VOID**)&Context->Http > >> + ); > >> + > >> + if (EFI_ERROR (Status)) { > >> + PRINT_HII (STRING_TOKEN (STR_HTTP_ERR_OPEN_PROTOCOL), > NicName, > >> Status); > >> + goto ON_EXIT; > >> + } > >> + > >> + Status = Context->Http->Configure (Context->Http, > >> &Context->HttpConfigData); > >> + if (EFI_ERROR (Status)) { > >> + PRINT_HII (STRING_TOKEN (STR_HTTP_ERR_CONFIGURE), NicName, > >> Status); > >> + goto ON_EXIT; > >> + } > >> + > >> + UrlSize = 0; > >> + DownloadUrl = StrnCatGrow ( > >> + &DownloadUrl, > >> + &UrlSize, > >> + Context->ServerAddrAndProto, > >> + StrLen (Context->ServerAddrAndProto) > >> + ); > >> + if (Context->URI[0] != L'/') { > >> + DownloadUrl = StrnCatGrow ( > >> + &DownloadUrl, > >> + &UrlSize, > >> + L"/", > >> + StrLen (Context->ServerAddrAndProto) > >> + ); > >> + } > >> + > >> + DownloadUrl = StrnCatGrow ( > >> + &DownloadUrl, > >> + &UrlSize, > >> + Context->URI, > >> + StrLen (Context->URI)); > >> + > >> + PRINT_HII (STRING_TOKEN (STR_HTTP_DOWNLOADING), > DownloadUrl); > >> + > >> + Status = SendRequest (Context, DownloadUrl); > >> + if (Status) { > >> + goto ON_EXIT; > >> + } > >> + > >> + Status = GetResponse (Context, DownloadUrl); > >> + > >> + if (Status) { > >> + goto ON_EXIT; > >> + } > >> + > >> + } while (Context->Status == REQ_NEED_REPEAT); > >> + > >> + if (Context->Status) { > >> + Status = ENCODE_ERROR (Context->Status); > >> + } > >> + > >> +ON_EXIT: > >> + // > >> + // CLOSE FILE > >> + // > >> + if (mFileHandle) { > >> + if (EFI_ERROR (Status) && !(Context->Flags & DL_FLAG_KEEP_BAD)) { > >> + ShellDeleteFile (&mFileHandle); > >> + } else { > >> + ShellCloseFile (&mFileHandle); > >> + } > >> + } > >> + > >> + SHELL_FREE_NON_NULL (DownloadUrl); > >> + SHELL_FREE_NON_NULL (Context->Buffer); > >> + > >> + CLOSE_HTTP_HANDLE (ControllerHandle, HttpChildHandle); > >> + > >> + return Status; > >> +} > >> + > >> +/** > >> + Retrive HII package list from ImageHandle and publish to HII > >> database. > >> + > >> + @param ImageHandle The image handle of the process. > >> + > >> + @return HII handle. > >> +**/ > >> +EFI_HII_HANDLE > >> +InitializeHiiPackage ( > >> + EFI_HANDLE ImageHandle > >> + ) > >> +{ > >> + EFI_STATUS Status; > >> + EFI_HII_PACKAGE_LIST_HEADER *PackageList; > >> + EFI_HII_HANDLE HiiHandle; > >> + > >> + // > >> + // Retrieve HII package list from ImageHandle > >> + // > >> + Status = gBS->OpenProtocol ( > >> + ImageHandle, > >> + &gEfiHiiPackageListProtocolGuid, > >> + (VOID **)&PackageList, > >> + ImageHandle, > >> + NULL, > >> + EFI_OPEN_PROTOCOL_GET_PROTOCOL > >> + ); > >> + ASSERT_EFI_ERROR (Status); > >> + if (EFI_ERROR (Status)) { > >> + return NULL; > >> + } > >> + > >> + // > >> + // Publish HII package list to HII Database. > >> + // > >> + Status = gHiiDatabase->NewPackageList ( > >> + gHiiDatabase, > >> + PackageList, > >> + NULL, > >> + &HiiHandle > >> + ); > >> + ASSERT_EFI_ERROR (Status); > >> + if (EFI_ERROR (Status)) { > >> + return NULL; > >> + } > >> + > >> + return HiiHandle; > >> +} > >> diff --git > a/ShellPkg/DynamicCommand/HttpDynamicCommand/HttpApp.c > >> b/ShellPkg/DynamicCommand/HttpDynamicCommand/HttpApp.c > >> new file mode 100644 > >> index 000000000000..a7d2c27191a2 > >> --- /dev/null > >> +++ b/ShellPkg/DynamicCommand/HttpDynamicCommand/HttpApp.c > >> @@ -0,0 +1,61 @@ > >> +/** @file > >> + Entrypoint of "http" shell standalone application. > >> + > >> + Copyright (c) 2010 - 2017, Intel Corporation. All rights reserved. > >>
> >> + Copyright (c) 2015, ARM Ltd. All rights reserved.
> >> + Copyright (c) 2020, Broadcom. All rights reserved.
> >> + > >> + SPDX-License-Identifier: BSD-2-Clause-Patent > >> + > >> +**/ > >> +#include "Http.h" > >> + > >> +/* > >> + * String token ID of help message text. > >> + * Shell supports to find help message in the resource section of an > >> + * application image if * .MAN file is not found. > >> + * This global variable is added to make build tool recognizes > >> + * that the help string is consumed by user and then build tool will > >> + * add the string into the resource section. > >> + * Thus the application can use '-?' option to show help message in > >> Shell. > >> + */ > >> +GLOBAL_REMOVE_IF_UNREFERENCED > >> +EFI_STRING_ID mStringHelpTokenId = STRING_TOKEN > (STR_GET_HELP_HTTP); > >> + > >> +/** > >> + Entry point of Http standalone application. > >> + > >> + @param ImageHandle The image handle of the process. > >> + @param SystemTable The EFI System Table pointer. > >> + > >> + @retval EFI_SUCCESS Http command is executed sucessfully. > >> + @retval EFI_ABORTED HII package was failed to initialize. > >> + @retval others Other errors when executing http > >> command. > >> +**/ > >> +EFI_STATUS > >> +EFIAPI > >> +HttpAppInitialize ( > >> + IN EFI_HANDLE ImageHandle, > >> + IN EFI_SYSTEM_TABLE *SystemTable > >> + ) > >> +{ > >> + EFI_STATUS Status; > >> + SHELL_STATUS ShellStatus; > >> + > >> + mHttpHiiHandle = InitializeHiiPackage (ImageHandle); > >> + if (mHttpHiiHandle == NULL) { > >> + return EFI_ABORTED; > >> + } > >> + > >> + Status = EFI_SUCCESS; > >> + > >> + ShellStatus = RunHttp (ImageHandle, SystemTable); > >> + > >> + HiiRemovePackages (mHttpHiiHandle); > >> + > >> + if (Status != SHELL_SUCCESS) { > >> + Status = ENCODE_ERROR (ShellStatus); > >> + } > >> + > >> + return Status; > >> +} > >> diff --git > >> > a/ShellPkg/DynamicCommand/HttpDynamicCommand/HttpDynamicComma > nd.c > >> > b/ShellPkg/DynamicCommand/HttpDynamicCommand/HttpDynamicComma > nd.c > >> new file mode 100644 > >> index 000000000000..7f59cc74d2a7 > >> --- /dev/null > >> +++ > b/ShellPkg/DynamicCommand/HttpDynamicCommand/HttpDynamicComma > nd.c > >> @@ -0,0 +1,137 @@ > >> +/** @file > >> + Produce "http" shell dynamic command. > >> + > >> + Copyright (c) 2010 - 2017, Intel Corporation. All rights reserved. > >>
> >> + Copyright (c) 2015, ARM Ltd. All rights reserved.
> >> + Copyright (c) 2020, Broadcom. All rights reserved.
> >> + > >> + SPDX-License-Identifier: BSD-2-Clause-Patent > >> + > >> +**/ > >> +#include > >> +#include "Http.h" > >> + > >> +/** > >> + This is the shell command handler function pointer callback type. > >> This > >> + function handles the command when it is invoked in the shell. > >> + > >> + @param[in] This The instance of the > >> + EFI_SHELL_DYNAMIC_COMMAND_PROTOCOL. > >> + @param[in] SystemTable The pointer to the system table. > >> + @param[in] ShellParameters The parameters associated with the > >> command. > >> + @param[in] Shell The instance of the shell protocol > >> used in > >> + the context of processing this > >> command. > >> + > >> + @return EFI_SUCCESS the operation was sucessful > >> + @return other the operation failed. > >> +**/ > >> +SHELL_STATUS > >> +EFIAPI > >> +HttpCommandHandler ( > >> + IN EFI_SHELL_DYNAMIC_COMMAND_PROTOCOL *This, > >> + IN EFI_SYSTEM_TABLE *SystemTable, > >> + IN EFI_SHELL_PARAMETERS_PROTOCOL *ShellParameters, > >> + IN EFI_SHELL_PROTOCOL *Shell > >> + ) > >> +{ > >> + gEfiShellParametersProtocol = ShellParameters; > >> + gEfiShellProtocol = Shell; > >> + > >> + return RunHttp (gImageHandle, SystemTable); > >> +} > >> + > >> +/** > >> + This is the command help handler function pointer callback type. > >> This > >> + function is responsible for displaying help information for the > >> associated > >> + command. > >> + > >> + @param[in] This The instance of the > >> EFI_SHELL_DYNAMIC_COMMAND_PROTOCOL. > >> + @param[in] Language The pointer to the language string to use. > >> + > >> + @return string Pool allocated help string, must be freed by > >> caller > >> +**/ > >> +CHAR16 * > >> +EFIAPI > >> +HttpCommandGetHelp ( > >> + IN EFI_SHELL_DYNAMIC_COMMAND_PROTOCOL *This, > >> + IN CONST CHAR8 *Language > >> + ) > >> +{ > >> + return HiiGetString ( > >> + mHttpHiiHandle, > >> + STRING_TOKEN (STR_GET_HELP_HTTP), > >> + Language > >> + ); > >> +} > >> + > >> +EFI_SHELL_DYNAMIC_COMMAND_PROTOCOL mHttpDynamicCommand > = { > >> + HTTP_APP_NAME, > >> + HttpCommandHandler, > >> + HttpCommandGetHelp > >> +}; > >> + > >> +/** > >> + Entry point of Http Dynamic Command. > >> + > >> + Produce the DynamicCommand protocol to handle "http" command. > >> + > >> + @param ImageHandle The image handle of the process. > >> + @param SystemTable The EFI System Table pointer. > >> + > >> + @retval EFI_SUCCESS Http command is executed sucessfully. > >> + @retval EFI_ABORTED HII package was failed to initialize. > >> + @retval others Other errors when executing http > >> command. > >> +**/ > >> +EFI_STATUS > >> +EFIAPI > >> +HttpCommandInitialize ( > >> + IN EFI_HANDLE ImageHandle, > >> + IN EFI_SYSTEM_TABLE *SystemTable > >> + ) > >> +{ > >> + EFI_STATUS Status; > >> + > >> + mHttpHiiHandle = InitializeHiiPackage (ImageHandle); > >> + if (mHttpHiiHandle == NULL) { > >> + return EFI_ABORTED; > >> + } > >> + > >> + Status = gBS->InstallProtocolInterface ( > >> + &ImageHandle, > >> + &gEfiShellDynamicCommandProtocolGuid, > >> + EFI_NATIVE_INTERFACE, > >> + &mHttpDynamicCommand > >> + ); > >> + ASSERT_EFI_ERROR (Status); > >> + return Status; > >> +} > >> + > >> +/** > >> + Http driver unload handler. > >> + > >> + @param ImageHandle The image handle of the process. > >> + > >> + @retval EFI_SUCCESS The image is unloaded. > >> + @retval Others Failed to unload the image. > >> +**/ > >> +EFI_STATUS > >> +EFIAPI > >> +HttpUnload ( > >> + IN EFI_HANDLE ImageHandle > >> +) > >> +{ > >> + EFI_STATUS Status; > >> + > >> + Status = gBS->UninstallProtocolInterface ( > >> + ImageHandle, > >> + &gEfiShellDynamicCommandProtocolGuid, > >> + &mHttpDynamicCommand > >> + ); > >> + if (EFI_ERROR (Status)) { > >> + return Status; > >> + } > >> + > >> + HiiRemovePackages (mHttpHiiHandle); > >> + > >> + return EFI_SUCCESS; > >> +} > >> diff --git a/ShellPkg/DynamicCommand/HttpDynamicCommand/Http.uni > >> b/ShellPkg/DynamicCommand/HttpDynamicCommand/Http.uni > >> new file mode 100644 > >> index 000000000000..00cf05deeb5c > >> --- /dev/null > >> +++ b/ShellPkg/DynamicCommand/HttpDynamicCommand/Http.uni > >> @@ -0,0 +1,117 @@ > >> +// /** > >> +// > >> +// (C) Copyright 2015-2016 Hewlett Packard Enterprise Development > LP
> >> +// Copyright (c) 2010 - 2018, Intel Corporation. All rights reserved. > >>
> >> +// Copyright (c) 2020, Broadcom. All rights reserved.
> >> +// SPDX-License-Identifier: BSD-2-Clause-Patent > >> +// > >> +// Module Name: > >> +// > >> +// Http.uni > >> +// > >> +// Abstract: > >> +// > >> +// String definitions for UEFI Shell HTTP command > >> +// > >> +// > >> +// **/ > >> + > >> +/=# > >> + > >> +#langdef en-US "english" > >> + > >> +#string STR_GEN_TOO_MANY #language en-US "%H%s%N: Too > many > >> arguments. Try help http.\r\n" > >> +#string STR_GEN_TOO_FEW #language en-US "%H%s%N: Too few > >> arguments. Try help http.\r\n" > >> +#string STR_GEN_PARAM_INV #language en-US "%H%s%N: Invalid > >> argument - '%H%s%N'. Try help http.\r\n" > >> +#string STR_GEN_PROBLEM #language en-US "%H%s%N: > Unknown > >> flag - '%H%s%N'. Try help http.\r\n" > >> +#string STR_GEN_FILE_OPEN_FAIL #language en-US "%H%s%N: > Cannot > >> open file - '%H%s%N'\r\n" > >> +#string STR_GEN_CRLF #language en-US "\r\n" > >> + > >> +#string STR_HTTP_ERR_NO_NIC #language en-US "No network > >> interface card found.\r\n" > >> +#string STR_HTTP_ERR_NIC_NAME #language en-US "Failed to get > the > >> name of the network interface card number %d - %r\r\n" > >> +#string STR_HTTP_ERR_OPEN_PROTOCOL #language en-US "Unable to > open > >> HTTP protocol on '%H%s%N' - %r\r\n" > >> +#string STR_HTTP_ERR_CONFIGURE #language en-US "Unable to > >> configure HTTP protocol on '%H%s%N' - %r\r\n" > >> +#string STR_HTTP_ERR_DOWNLOAD #language en-US "Unable to > >> download the file '%H%s%N' on '%H%s%N' - %r\r\n" > >> +#string STR_HTTP_ERR_WRITE #language en-US "Unable to write > >> into file '%H%s%N' - %r\r\n" > >> +#string STR_HTTP_ERR_NIC_NOT_FOUND #language en-US "Network > Interface > >> Card '%H%s%N' not found.\r\n" > >> +#string STR_HTTP_ERR_STATUSCODE #language en-US "\r'%H%s%N' > >> reports '%s' for '%H%s%N' \r\n" > >> +#string STR_HTTP_DOWNLOADING #language en-US "Downloading > >> '%H%s%N'\r\n" > >> + > >> +#string STR_GET_HELP_HTTP #language en-US "" > >> +".TH http 0 "Download a file from HTTP server."\r\n" > >> +".SH NAME\r\n" > >> +"Download a file from HTTP server.\r\n" > >> +".SH SYNOPSIS\r\n" > >> +" \r\n" > >> +"HTTP [-i interface] [-l port] [-t timeout] [-s size] [-m] [-k]\r\n" > >> +" [localfilepath]\r\n" > >> +".SH OPTIONS\r\n" > >> +" \r\n" > >> +" -i interface - Specifies an adapter name, i.e., eth0.\r\n" > >> +" -k Keep the downloaded file even if there was an > >> error.\r\n" > >> +" If this parameter is not used, the file will be > >> deleted.\r\n" > >> +" -l port - Specifies the local port number. Default value > >> is 0\r\n" > >> +" and the port number is automatically > >> assigned.\r\n" > >> +" -m Measure and report download time (in seconds). > >> \r\n" > >> +" -s size The size of the download buffer for a chunk, in > >> bytes.\r\n" > >> +" Default is 32K. Note that larger buffer does > >> not imply\r\n" > >> +" better speed.\r\n" > >> +" -t timeout - The number of seconds to wait for completion > >> of\r\n" > >> +" requests and responses. Default is 0 which is > >> 'automatic'.\r\n" > >> +" %HURL%N\r\n" > >> +" Two types of providing of URLs are supported:\r\n" > >> +" 1. tftp-like, where host and http_uri are separate > >> parameters\r\n" > >> +" (example: host /host_uri), and\r\n\" > >> +" 2. wget-like, where host and host_uri is one parameter.\r\n" > >> +" (example: host/host_uri)\r\n" > >> +"\r\n" > >> +" host - Specifies HTTP Server address.\r\n > >> + Can be either IPv4 address or 'http (or > >> https)://addr'\r\n > >> + Can use addresses resolvable by DNS as well. > >> \r\n > >> + Port can be specified after ':' if needed. > >> \r\n > >> + By default port 80 is used.\r\n" > >> +" http_uri - HTTP server URI to download the file.\r\n" > >> +"\r\n" > >> +" localfilepath - Local destination file path.\r\n" > >> +".SH DESCRIPTION\r\n" > >> +" \r\n" > >> +"NOTES:\r\n" > >> +" 1. The HTTP command allows geting of the file specified by its > >> 'http_uri'\r\n" > >> +" path from the HTTP server specified by its 'host' IPv4 address. > >> If the\r\n" > >> +" optional 'localfilepath' parameter is provided, the downloaded > >> file is\r\n" > >> +" stored locally using the provided file path. If the local file > >> path is\r\n" > >> +" not specified, the file is stored in the current directory > >> using the file\r\n" > >> +" server's name.\r\n" > >> +" 2. Before using the HTTP command, the network interface intended > >> to be\r\n" > >> +" used to retrieve the file must be configured. This > >> configuration may be\r\n" > >> +" done by means of the 'ifconfig' command.\r\n" > >> +" 3. If a network interface is defined with the '-i' option then > >> only this\r\n" > >> +" interface will be used to retrieve the remote file. Otherwise, > >> all network\r\n" > >> +" interfaces are tried in the order they have been discovered > >> during the\r\n" > >> +" DXE phase.\r\n" > >> +".SH EXAMPLES\r\n" > >> +" \r\n" > >> +"EXAMPLES:\r\n" > >> +" * To get the file "dir1/file1.dat" from the HTTP server > >> 192.168.1.1, port 8080, and\r\n" > >> +" store it as file2.dat in the current directory (use tftp-like > >> URL format) :\r\n" > >> +" fs0:\> http 192.168.1.1:8080 dir1/file1.dat file2.dat\r\n" > >> +" * To get the file /image.bin via HTTPS from server 192.168.1.1 at > >> port 443 \r\n" > >> +" (default HTTPS port), and store it in the current directory: > >> \r\n" > >> +" fs0:\> http https://192.168.1.1 image.bin\r\n" > >> +" To get an index file from http://google.com and place it into > >> the \r\n" > >> +" current directory:\r\n" > >> +" fs0:\> http google.com index.html\r\n" > >> +".SH RETURNVALUES\r\n" > >> +" \r\n" > >> +"RETURN VALUES:\r\n" > >> +" SHELL_SUCCESS The action was completed as > >> requested.\r\n" > >> +" SHELL_INVALID_PARAMETER One of the passed-in parameters was > >> incorrectly\r\n" > >> +" formatted or its value was out of > >> bounds.\r\n" > >> +" HTTP_ERROR No EFI errors, but the server reported a > >> status code\r\n" > >> +" which should be treated as an error. If > >> an error body sent\r\n" > >> +" by the server, and -k parameter is on > >> command line, > >> +" the file wil be saved either as > >> localfilepath filename,\r\n" > >> +" or as an URI name in the current > >> directory.\r\n" > >> +" If '/' is at the end of the URL, and no > >> locafilepath filename\r\n" > >> +" is given on the command line, the file > >> will be retrieved as\r\n" > >> +" index.html.\r\n" > >