public inbox for devel@edk2.groups.io
 help / color / mirror / Atom feed
From: "Vladimir Olovyannikov" <vladimir.olovyannikov@broadcom.com>
To: Laszlo Ersek <lersek@redhat.com>,
	"Rabeda, Maciej" <maciej.rabeda@linux.intel.com>,
	 devel@edk2.groups.io, Zhichao Gao <zhichao.gao@intel.com>,
	Ray Ni <ray.ni@intel.com>
Cc: Samer El-Haj-Mahmoud <Samer.El-Haj-Mahmoud@arm.com>,
	Jiaxin Wu <jiaxin.wu@intel.com>,  Siyuan Fu <siyuan.fu@intel.com>,
	Liming Gao <liming.gao@intel.com>, Nd <nd@arm.com>
Subject: Re: [PATCH v10 1/1] ShellPkg/DynamicCommand: add HttpDynamicCommand
Date: Fri, 4 Sep 2020 10:55:36 -0700	[thread overview]
Message-ID: <20ac79e77049e8756de36f50df1e7f36@mail.gmail.com> (raw)
In-Reply-To: <30233c17-c081-deb6-d0cb-d847c7a9992b@redhat.com>

Hi Laszlo, Macieji,

Thank you for spotting these.
Some comments below.
> -----Original Message-----
> From: Laszlo Ersek <lersek@redhat.com>
> Sent: Friday, September 4, 2020 8:21 AM
> To: Rabeda, Maciej <maciej.rabeda@linux.intel.com>; Vladimir Olovyannikov
> <vladimir.olovyannikov@broadcom.com>; devel@edk2.groups.io; Zhichao
> Gao <zhichao.gao@intel.com>; Ray Ni <ray.ni@intel.com>
> Cc: Samer El-Haj-Mahmoud <Samer.El-Haj-Mahmoud@arm.com>; Jiaxin Wu
> <jiaxin.wu@intel.com>; Siyuan Fu <siyuan.fu@intel.com>; Liming Gao
> <liming.gao@intel.com>; Nd <nd@arm.com>
> 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 <maciej.rabeda@linux.intel.com>
>
> 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
> <vladimir.olovyannikov@broadcom.com>
> >> Cc: Samer El-Haj-Mahmoud <Samer.El-Haj-Mahmoud@arm.com>
> >> Cc: Laszlo Ersek <lersek@redhat.com>
> >> Cc: Zhichao Gao <zhichao.gao@intel.com>
> >> Cc: Maciej Rabeda <maciej.rabeda@linux.intel.com>
> >> Cc: Jiaxin Wu <jiaxin.wu@intel.com>
> >> Cc: Siyuan Fu <siyuan.fu@intel.com>
> >> Cc: Ray Ni <ray.ni@intel.com>
> >> Cc: Liming Gao <liming.gao@intel.com>
> >> Cc: Nd <nd@arm.com>
> >> ---
> >>   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 {
> >> +    <PcdsFixedAtBuild>
> >> +      gEfiShellPkgTokenSpaceGuid.PcdShellLibAutoInitialize|FALSE
> >> +  }
> >> +  ShellPkg/DynamicCommand/HttpDynamicCommand/HttpApp.inf
> >>     ShellPkg/DynamicCommand/DpDynamicCommand/DpDynamicComma
> nd.inf {
> >>       <PcdsFixedAtBuild>
> >>         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.
> >> <BR>
> >> +# Copyright (c) 2015, ARM Ltd. All rights reserved.<BR>
> >> +# Copyright (c) 2020, Broadcom. All rights reserved.<BR>
> >> +#
> >> +#  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.
> >> <BR>
> >> +# Copyright (c) 2015, ARM Ltd. All rights reserved.<BR>
> >> +# Copyright (c) 2020, Broadcom. All rights reserved.<BR>
> >> +#
> >> +#  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.
> >> <BR>
> >> +  Copyright (c) 2015, ARM Ltd. All rights reserved.<BR>
> >> +  Copyright (c) 2020, Broadcom. All rights reserved.<BR>
> >> +
> >> +  SPDX-License-Identifier: BSD-2-Clause-Patent
> >> +
> >> +**/
> >> +
> >> +#ifndef _HTTP_H_
> >> +#define _HTTP_H_
> >> +
> >> +#include <Uefi.h>
> >> +
> >> +#include <Library/BaseLib.h>
> >> +#include <Library/BaseMemoryLib.h>
> >> +#include <Library/DebugLib.h>
> >> +#include <Library/HiiLib.h>
> >> +#include <Library/HttpLib.h>
> >> +#include <Library/MemoryAllocationLib.h>
> >> +#include <Library/NetLib.h>
> >> +#include <Library/PrintLib.h>
> >> +#include <Library/ShellLib.h>
> >> +#include <Library/UefiBootServicesTableLib.h>
> >> +#include <Library/UefiHiiServicesLib.h>
> >> +#include <Library/UefiLib.h>
> >> +#include <Library/UefiRuntimeServicesTableLib.h>
> >> +
> >> +#include <Protocol/HiiPackageList.h>
> >> +#include <Protocol/HttpUtilities.h>
> >> +#include <Protocol/ServiceBinding.h>
> >> +
> >> +#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.<BR>
> >> +  Copyright (c) 2015 - 2018, Intel Corporation. All rights reserved.
> >> <BR>
> >> +  (C) Copyright 2015 Hewlett Packard Enterprise Development LP<BR>
> >> +  Copyright (c) 2020, Broadcom. All rights reserved. <BR>
> >> +
> >> +  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.
> >> <BR>
> >> +  Copyright (c) 2015, ARM Ltd. All rights reserved.<BR>
> >> +  Copyright (c) 2020, Broadcom. All rights reserved.<BR>
> >> +
> >> +  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.
> >> <BR>
> >> +  Copyright (c) 2015, ARM Ltd. All rights reserved.<BR>
> >> +  Copyright (c) 2020, Broadcom. All rights reserved.<BR>
> >> +
> >> +  SPDX-License-Identifier: BSD-2-Clause-Patent
> >> +
> >> +**/
> >> +#include <Protocol/ShellDynamicCommand.h>
> >> +#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<BR>
> >> +// Copyright (c) 2010 - 2018, Intel Corporation. All rights reserved.
> >> <BR>
> >> +// Copyright (c) 2020, Broadcom. All rights reserved.<BR>
> >> +// 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"
> >> +"      <URL> [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"
> >

  reply	other threads:[~2020-09-04 17:55 UTC|newest]

Thread overview: 10+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2020-09-02  4:08 [PATCH v10 0/1] ShellPkg/DynamicCommand: add HttpDynamicCommand Vladimir Olovyannikov
2020-09-02  4:08 ` [PATCH v10 1/1] " Vladimir Olovyannikov
2020-09-04 13:10   ` Maciej Rabeda
2020-09-04 15:20     ` Laszlo Ersek
2020-09-04 17:55       ` Vladimir Olovyannikov [this message]
2020-09-07  9:36         ` Laszlo Ersek
2020-09-08 21:04           ` Vladimir Olovyannikov
2020-09-09 10:50             ` Laszlo Ersek
2020-09-09 17:15               ` Vladimir Olovyannikov
2020-09-10  6:25                 ` [edk2-devel] " Laszlo Ersek

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-list from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20ac79e77049e8756de36f50df1e7f36@mail.gmail.com \
    --to=devel@edk2.groups.io \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox