public inbox for devel@edk2.groups.io
 help / color / mirror / Atom feed
From: "Gao, Zhichao" <zhichao.gao@intel.com>
To: "devel@edk2.groups.io" <devel@edk2.groups.io>,
	"vladimir.olovyannikov@broadcom.com"
	<vladimir.olovyannikov@broadcom.com>
Cc: Samer El-Haj-Mahmoud <Samer.El-Haj-Mahmoud@arm.com>,
	Maciej Rabeda <maciej.rabeda@linux.intel.com>,
	"Wu, Jiaxin" <jiaxin.wu@intel.com>,
	"Fu, Siyuan" <siyuan.fu@intel.com>, "Ni, Ray" <ray.ni@intel.com>,
	"Gao, Liming" <liming.gao@intel.com>, Nd <nd@arm.com>
Subject: Re: [edk2-devel] [PATCH v2 1/1] ShellPkg/DynamicCommand: add HttpDynamicCommand
Date: Thu, 2 Jul 2020 05:55:27 +0000	[thread overview]
Message-ID: <DM6PR11MB44255E2CD6D51095D2F66777F66D0@DM6PR11MB4425.namprd11.prod.outlook.com> (raw)
In-Reply-To: <20200511180310.30964-1-vladimir.olovyannikov@broadcom.com>

Hi,

Sorry for the delay. As I said in the V1, the patch required the NetworkPkg maintainers' help to review the network connection implementation part.

Some comments below.
1. for function RunHttp: 
'''
    UINTN  StartSize;
    CHAR16 *Walker;
    CHAR16 *VStr;
'''
The above variable is block scope which is strongly discouraged. See CSS_2_1_Draft Section 5.4.1.1.

2. Some indentations need adjust:
  a) GetResponse function body
  b) "if (!gHttpError) {" section of GetResponse
  c) " ValueStr = ShellCommandLineGetValue (CheckPackage, L"-s");" the if section below this statement

Thanks,
Zhichao

> -----Original Message-----
> From: devel@edk2.groups.io <devel@edk2.groups.io> On Behalf Of Vladimir
> Olovyannikov via groups.io
> Sent: Tuesday, May 12, 2020 2:03 AM
> To: devel@edk2.groups.io
> Cc: Vladimir Olovyannikov <vladimir.olovyannikov@broadcom.com>; Samer El-
> Haj-Mahmoud <Samer.El-Haj-Mahmoud@arm.com>; Gao, Zhichao
> <zhichao.gao@intel.com>; Maciej Rabeda <maciej.rabeda@linux.intel.com>; Wu,
> Jiaxin <jiaxin.wu@intel.com>; Fu, Siyuan <siyuan.fu@intel.com>; Ni, Ray
> <ray.ni@intel.com>; Gao, Liming <liming.gao@intel.com>; Nd <nd@arm.com>
> Subject: [edk2-devel] [PATCH v2 1/1] ShellPkg/DynamicCommand: add
> HttpDynamicCommand
> 
> 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.
> 
> Signed-off-by: Vladimir Olovyannikov <vladimir.olovyannikov@broadcom.com>
> Tested-By: Samer El-Haj-Mahmoud <Samer.El-Haj-Mahmoud@arm.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>
> ---
>  .../DynamicCommand/HttpDynamicCommand/Http.c  | 1701
> +++++++++++++++++
>  .../DynamicCommand/HttpDynamicCommand/Http.h  |   84 +
>  .../HttpDynamicCommand/Http.uni               |  113 ++
>  .../HttpDynamicCommand/HttpApp.c              |   53 +
>  .../HttpDynamicCommand/HttpApp.inf            |   58 +
>  .../HttpDynamicCommand/HttpDynamicCommand.c   |  134 ++
>  .../HttpDynamicCommand/HttpDynamicCommand.inf |   63 +
>  ShellPkg/Include/Guid/ShellLibHiiGuid.h       |    5 +
>  ShellPkg/ShellPkg.dec                         |    1 +
>  ShellPkg/ShellPkg.dsc                         |    5 +
>  10 files changed, 2217 insertions(+)
>  create mode 100644 ShellPkg/DynamicCommand/HttpDynamicCommand/Http.c
>  create mode 100644
> ShellPkg/DynamicCommand/HttpDynamicCommand/Http.h
>  create mode 100644
> ShellPkg/DynamicCommand/HttpDynamicCommand/Http.uni
>  create mode 100644
> ShellPkg/DynamicCommand/HttpDynamicCommand/HttpApp.c
>  create mode 100644
> ShellPkg/DynamicCommand/HttpDynamicCommand/HttpApp.inf
>  create mode 100644
> ShellPkg/DynamicCommand/HttpDynamicCommand/HttpDynamicCommand.c
>  create mode 100644
> ShellPkg/DynamicCommand/HttpDynamicCommand/HttpDynamicCommand.inf
> 
> diff --git a/ShellPkg/DynamicCommand/HttpDynamicCommand/Http.c
> b/ShellPkg/DynamicCommand/HttpDynamicCommand/Http.c
> new file mode 100644
> index 000000000000..7238cc6a07cc
> --- /dev/null
> +++ b/ShellPkg/DynamicCommand/HttpDynamicCommand/Http.c
> @@ -0,0 +1,1701 @@
> +/** @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
> 
> +EFI_HII_HANDLE   mHttpHiiHandle;
> 
> +
> 
> +/*
> 
> +   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 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"[                                        ]"
> 
> +
> 
> +// 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"
> 
> +};
> 
> +
> 
> +// 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;
> 
> +
> 
> +/**
> 
> +  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
> 
> +  )
> 
> +{
> 
> +  ASSERT(String != NULL);
> 
> +  ASSERT(*String!= NULL);
> 
> +  //
> 
> +  // Remove any spaces and tabs at the beginning of the (*String).
> 
> +  //
> 
> +  while (((*String)[0] == L' ') || ((*String)[0] == L'\t')) {
> 
> +    CopyMem (
> 
> +      (*String),
> 
> +      (*String) + 1,
> 
> +      StrSize ((*String)) - sizeof((*String)[0])
> 
> +      );
> 
> +  }
> 
> +
> 
> +  //
> 
> +  // Remove any spaces and tabs at the end of the (*String).
> 
> +  //
> 
> +  while ((StrLen (*String) > 0) &&
> 
> +         (((*String)[StrLen ((*String)) - 1] == L' ') ||
> 
> +         ((*String)[StrLen ((*String)) - 1] == L'\t'))
> 
> +        ) {
> 
> +    (*String)[StrLen ((*String)) - 1] = CHAR_NULL;
> 
> +  }
> 
> +
> 
> +  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;
> 
> +}
> 
> +
> 
> +
> 
> +/**
> 
> +  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   DOWNLOAD_CONTEXT   *Context
> 
> +  );
> 
> +
> 
> +STATIC CONST SHELL_PARAM_ITEM ParamList[] = {
> 
> +  {L"-i", TypeValue},
> 
> +  {L"-l", TypeValue},
> 
> +  {L"-s", TypeValue},
> 
> +  {L"-t", TypeValue},
> 
> +  {NULL , TypeMax}
> 
> +  };
> 
> +
> 
> +/**
> 
> +  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;
> 
> +  CHAR16                  *ProblemParam;
> 
> +  UINTN                   ParamCount;
> 
> +  CONST CHAR16            *UserNicName;
> 
> +  BOOLEAN                 NicFound;
> 
> +  CONST CHAR16            *ValueStr;
> 
> +  CONST CHAR16            *RemoteFilePath;
> 
> +  CONST CHAR16            *Walker;
> 
> +  EFI_HTTP_CONFIG_DATA    HttpConfigData;
> 
> +  EFI_HTTPv4_ACCESS_POINT IPv4Node;
> 
> +  EFI_HANDLE              *Handles;
> 
> +  UINTN                   HandleCount;
> 
> +  UINTN                   NicNumber;
> 
> +  UINTN                   InitialSize;
> 
> +  UINTN                   ParamOffset;
> 
> +  CHAR16                  NicName[IP4_CONFIG2_INTERFACE_INFO_NAME_LENGTH];
> 
> +  EFI_HANDLE              ControllerHandle;
> 
> +  EFI_HANDLE              HttpChildHandle;
> 
> +  DOWNLOAD_CONTEXT        Context;
> 
> +
> 
> +  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) ) {
> 
> +      ShellPrintHiiEx (
> 
> +        -1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM), mHttpHiiHandle,
> 
> +        HTTP_APP_NAME, 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) {
> 
> +    ShellPrintHiiEx (
> 
> +      -1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_MANY),
> 
> +      mHttpHiiHandle, HTTP_APP_NAME
> 
> +      );
> 
> +    goto Error;
> 
> +  }
> 
> +
> 
> +  if (ParamCount < MIN_PARAM_COUNT) {
> 
> +    ShellPrintHiiEx (
> 
> +      -1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_FEW),
> 
> +      mHttpHiiHandle, HTTP_APP_NAME
> 
> +      );
> 
> +    goto Error;
> 
> +  }
> 
> +
> 
> +  ZeroMem (&HttpConfigData, sizeof (HttpConfigData));
> 
> +  ZeroMem (&IPv4Node, sizeof (IPv4Node));
> 
> +  IPv4Node.UseDefaultAddress = TRUE;
> 
> +
> 
> +  HttpConfigData.HttpVersion = HttpVersion11;
> 
> +  HttpConfigData.AccessPoint.IPv4Node = &IPv4Node;
> 
> +
> 
> +  //
> 
> +  // Get the host address (not necessarily IPv4 format)
> 
> +  //
> 
> +  ValueStr = ShellCommandLineGetRawValue (CheckPackage, 1);
> 
> +  if (!ValueStr) {
> 
> +    ShellPrintHiiEx (
> 
> +      -1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), mHttpHiiHandle,
> 
> +      HTTP_APP_NAME, ValueStr
> 
> +      );
> 
> +    goto Error;
> 
> +  } else {
> 
> +    UINTN  StartSize;
> 
> +    CHAR16 *Walker;
> 
> +    CHAR16 *VStr;
> 
> +
> 
> +    StartSize = 0;
> 
> +    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 (Walker = VStr; *Walker; Walker++) {
> 
> +      if (*Walker == L'/') {
> 
> +        break;
> 
> +      }
> 
> +    }
> 
> +
> 
> +    if (*Walker == L'/') {
> 
> +      ParamOffset = 1;
> 
> +      RemoteFilePath = Walker;
> 
> +    }
> 
> +
> 
> +    Context.ServerAddrAndProto = StrnCatGrow (
> 
> +                                   &Context.ServerAddrAndProto,
> 
> +                                   &StartSize,
> 
> +                                   ValueStr,
> 
> +                                   StrLen (ValueStr) - StrLen (Walker)
> 
> +                                   );
> 
> +    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) {
> 
> +    if (!StringToUint16 (
> 
> +         ValueStr,
> 
> +         &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) {
> 
> +        ShellPrintHiiEx (
> 
> +          -1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV),
> 
> +          mHttpHiiHandle, HTTP_APP_NAME, ValueStr
> 
> +          );
> 
> +        goto Error;
> 
> +      }
> 
> +    }
> 
> +
> 
> +  ValueStr = ShellCommandLineGetValue (CheckPackage, L"-t");
> 
> +  if (ValueStr != NULL) {
> 
> +    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)) {
> 
> +    ShellPrintHiiEx (
> 
> +      -1, -1, NULL, STRING_TOKEN (STR_HTTP_ERR_NO_NIC), mHttpHiiHandle
> 
> +      );
> 
> +    if (!EFI_ERROR (Status)) {
> 
> +      Status = EFI_NOT_FOUND;
> 
> +    }
> 
> +
> 
> +    goto Error;
> 
> +  }
> 
> +
> 
> +  Status = EFI_NOT_FOUND;
> 
> +
> 
> +  for (NicNumber = 0;
> 
> +       (NicNumber < HandleCount) && (Status != EFI_SUCCESS);
> 
> +       NicNumber++) {
> 
> +    ControllerHandle = Handles[NicNumber];
> 
> +
> 
> +    Status = GetNicName (ControllerHandle, NicNumber, NicName);
> 
> +    if (EFI_ERROR (Status)) {
> 
> +      ShellPrintHiiEx (
> 
> +        -1, -1, NULL, STRING_TOKEN (STR_HTTP_ERR_NIC_NAME),
> 
> +        mHttpHiiHandle, NicNumber, Status
> 
> +      );
> 
> +      continue;
> 
> +    }
> 
> +
> 
> +    if (UserNicName != NULL) {
> 
> +      if (StrCmp (NicName, UserNicName) != 0) {
> 
> +        continue;
> 
> +      }
> 
> +      NicFound = TRUE;
> 
> +    }
> 
> +
> 
> +    Status = CreateServiceChildAndOpenProtocol (
> 
> +               ControllerHandle,
> 
> +               &gEfiHttpServiceBindingProtocolGuid,
> 
> +               &gEfiHttpProtocolGuid,
> 
> +               &HttpChildHandle,
> 
> +               (VOID**)&Context.Http
> 
> +             );
> 
> +    if (EFI_ERROR (Status)) {
> 
> +      ShellPrintHiiEx (
> 
> +        -1, -1, NULL, STRING_TOKEN (STR_HTTP_ERR_OPEN_PROTOCOL),
> 
> +        mHttpHiiHandle, NicName, Status
> 
> +        );
> 
> +      continue;
> 
> +    }
> 
> +
> 
> +    Status = Context.Http->Configure (Context.Http, &HttpConfigData);
> 
> +    if (EFI_ERROR (Status)) {
> 
> +      ShellPrintHiiEx (
> 
> +        -1, -1, NULL, STRING_TOKEN (STR_HTTP_ERR_CONFIGURE),
> 
> +        mHttpHiiHandle, NicName, Status
> 
> +        );
> 
> +      continue;
> 
> +    }
> 
> +
> 
> +    Status = DownloadFile (&Context);
> 
> +
> 
> +    ShellPrintHiiEx (
> 
> +      -1, -1, NULL, STRING_TOKEN (STR_GEN_CRLF), mHttpHiiHandle
> 
> +      );
> 
> +
> 
> +    CloseProtocolAndDestroyServiceChild (
> 
> +      ControllerHandle,
> 
> +      &gEfiHttpServiceBindingProtocolGuid,
> 
> +      &gEfiHttpProtocolGuid,
> 
> +      HttpChildHandle
> 
> +      );
> 
> +
> 
> +    if (EFI_ERROR (Status)) {
> 
> +      ShellPrintHiiEx (
> 
> +        -1, -1, NULL, STRING_TOKEN (STR_HTTP_ERR_DOWNLOAD),
> 
> +        mHttpHiiHandle, 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)) {
> 
> +    ShellPrintHiiEx (
> 
> +      -1, -1, NULL, STRING_TOKEN (STR_HTTP_ERR_NIC_NOT_FOUND),
> 
> +      mHttpHiiHandle, 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) {
> 
> +    ShellPrintHiiEx (
> 
> +      -1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV),
> 
> +      mHttpHiiHandle, HTTP_APP_NAME, 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 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);
> 
> +  }
> 
> +
> 
> +  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 DOWNLOAD_CONTEXT  *Context,
> 
> +  IN CHAR16            *DownloadUrl
> 
> +  )
> 
> +{
> 
> +    EFI_HTTP_REQUEST_DATA       RequestData;
> 
> +    EFI_HTTP_HEADER             RequestHeader;
> 
> +    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.FieldName = "Host";
> 
> +
> 
> +    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.FieldValue = AllocatePool (StringSize);
> 
> +    if (!RequestHeader.FieldValue) {
> 
> +      return EFI_OUT_OF_RESOURCES;
> 
> +    }
> 
> +
> 
> +    UnicodeStrToAsciiStrS (Host, RequestHeader.FieldValue, StringSize);
> 
> +
> 
> +    RequestMessage.HeaderCount++;
> 
> +
> 
> +    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.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 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) {
> 
> +      ShellPrintHiiEx (
> 
> +        -1, -1, NULL, STRING_TOKEN (STR_GEN_CRLF), mHttpHiiHandle
> 
> +        );
> 
> +    }
> 
> +
> 
> +    ShellPrintHiiEx (
> 
> +      -1, -1, NULL, STRING_TOKEN (STR_HTTP_ERR_WRITE),
> 
> +      mHttpHiiHandle, 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 DOWNLOAD_CONTEXT *Context,
> 
> +  IN CHAR16           *DownloadUrl
> 
> +  )
> 
> +{
> 
> +  EFI_STATUS Status;
> 
> +  UINTN      StringSize;
> 
> +  UINTN      FirstStep;
> 
> +  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 redirect 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) {
> 
> +    CHAR8      *Walker;
> 
> +    CHAR16     *Temp;
> 
> +    UINTN      Idx;
> 
> +    UINTN      Step;
> 
> +
> 
> +    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 DOWNLOAD_CONTEXT *Context,
> 
> +  IN CHAR16           *DownloadUrl
> 
> +  )
> 
> +{
> 
> +    EFI_HTTP_RESPONSE_DATA      ResponseData;
> 
> +    EFI_HTTP_MESSAGE            ResponseMessage;
> 
> +    EFI_STATUS                  Status;
> 
> +    VOID                        *MsgParser;
> 
> +    BOOLEAN                     IsTrunked;
> 
> +
> 
> +    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;
> 
> +
> 
> +    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) {
> 
> +        EFI_HTTP_HEADER *Header;
> 
> +        BOOLEAN         Redirection;
> 
> +
> 
> +        Redirection =
> 
> +          ((ResponseData.StatusCode >= HTTP_STATUS_300_MULTIPLE_CHOICES)
> &&
> 
> +           (ResponseData.StatusCode <=
> HTTP_STATUS_307_TEMPORARY_REDIRECT)
> 
> +          ) ||
> 
> +          (ResponseData.StatusCode ==
> HTTP_STATUS_308_PERMANENT_REDIRECT);
> 
> +
> 
> +        if (Redirection) {
> 
> +          //
> 
> +          // 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) {
> 
> +              ShellPrintHiiEx (
> 
> +                -1, -1, NULL, STRING_TOKEN (STR_HTTP_ERR_STATUSCODE),
> 
> +                mHttpHiiHandle, 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) {
> 
> +                 CONST CHAR16 *Desc;
> 
> +
> 
> +                 gHttpError = TRUE;
> 
> +
> 
> +                 Desc = ErrStatusDesc[ResponseData.StatusCode -
> 
> +                                      HTTP_STATUS_400_BAD_REQUEST];
> 
> +                 ShellPrintHiiEx (
> 
> +                   -1, -1, NULL, STRING_TOKEN (STR_HTTP_ERR_STATUSCODE),
> 
> +                   mHttpHiiHandle, Context->ServerAddrAndProto,
> 
> +                   Desc,
> 
> +                   Context->URI
> 
> +                   );
> 
> +
> 
> +                 //
> 
> +                 // This gives an RFC HTTP error.
> 
> +                 //
> 
> +                 Context->Status = ShellStrToUintn (Desc);
> 
> +                }
> 
> +            }
> 
> +      }
> 
> +
> 
> +      // 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
> 
> +             );
> 
> +
> 
> +    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.
> 
> +
> 
> +  @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   DOWNLOAD_CONTEXT   *Context
> 
> +  )
> 
> +{
> 
> +  EFI_STATUS            Status;
> 
> +  CHAR16                *DownloadUrl;
> 
> +  UINTN                 UrlSize;
> 
> +
> 
> +  ASSERT (Context);
> 
> +
> 
> +  DownloadUrl = 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)) {
> 
> +    ShellPrintHiiEx (
> 
> +      -1, -1, NULL, STRING_TOKEN (STR_GEN_FILE_OPEN_FAIL),
> 
> +      mHttpHiiHandle, HTTP_APP_NAME, mLocalFilePath
> 
> +      );
> 
> +    goto ON_EXIT;
> 
> +  }
> 
> +
> 
> +  do {
> 
> +    SHELL_FREE_NON_NULL (DownloadUrl);
> 
> +    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));
> 
> +
> 
> +    ShellPrintHiiEx (
> 
> +      -1, -1, NULL, STRING_TOKEN (STR_HTTP_DOWNLOADING),
> 
> +      mHttpHiiHandle, 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) {
> 
> +    ShellCloseFile (&mFileHandle);
> 
> +  }
> 
> +
> 
> +  SHELL_FREE_NON_NULL (DownloadUrl);
> 
> +  SHELL_FREE_NON_NULL (Context->Buffer);
> 
> +
> 
> +  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/Http.h
> b/ShellPkg/DynamicCommand/HttpDynamicCommand/Http.h
> new file mode 100644
> index 000000000000..a142b96f6ad2
> --- /dev/null
> +++ b/ShellPkg/DynamicCommand/HttpDynamicCommand/Http.h
> @@ -0,0 +1,84 @@
> +/** @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
> 
> +
> 
> +extern EFI_HII_HANDLE mHttpHiiHandle;
> 
> +
> 
> +typedef struct {
> 
> +  UINTN                 ContentDownloaded;
> 
> +  UINTN                 ContentLength;
> 
> +  UINTN                 LastReportedNbOfBytes;
> 
> +  UINTN                 BufferSize;
> 
> +  UINTN                 Status;
> 
> +  UINT8                 *Buffer;
> 
> +  CHAR16                *ServerAddrAndProto;
> 
> +  CHAR16                *URI;
> 
> +  EFI_HTTP_TOKEN        ResponseToken;
> 
> +  EFI_HTTP_TOKEN        RequestToken;
> 
> +  EFI_HTTP_PROTOCOL     *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/DynamicCommand/HttpDynamicCommand/Http.uni
> b/ShellPkg/DynamicCommand/HttpDynamicCommand/Http.uni
> new file mode 100644
> index 000000000000..efe50e25819c
> --- /dev/null
> +++ b/ShellPkg/DynamicCommand/HttpDynamicCommand/Http.uni
> @@ -0,0 +1,113 @@
> +// /**
> 
> +//
> 
> +// (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]\r\n"
> 
> +"      <URL> [localfilepath]\r\n"
> 
> +".SH OPTIONS\r\n"
> 
> +" \r\n"
> 
> +"  -i interface     - Specifies an adapter name, i.e., eth0.\r\n"
> 
> +"  -l port          - Specifies the local port number. Default value is 0\r\n"
> 
> +"                     and the port number is automatically assigned.\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 :\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"
> 
> +".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"
> 
> +"  SHELL_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, it would be saved either as\r\n
> 
> +                             localfilepath filename, 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."
> 
> diff --git a/ShellPkg/DynamicCommand/HttpDynamicCommand/HttpApp.c
> b/ShellPkg/DynamicCommand/HttpDynamicCommand/HttpApp.c
> new file mode 100644
> index 000000000000..7bd5b46d3997
> --- /dev/null
> +++ b/ShellPkg/DynamicCommand/HttpDynamicCommand/HttpApp.c
> @@ -0,0 +1,53 @@
> +/** @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;
> 
> +  mHttpHiiHandle = InitializeHiiPackage (ImageHandle);
> 
> +  if (mHttpHiiHandle == NULL) {
> 
> +    return EFI_ABORTED;
> 
> +  }
> 
> +
> 
> +  Status = (EFI_STATUS)RunHttp (ImageHandle, SystemTable);
> 
> +
> 
> +  HiiRemovePackages (mHttpHiiHandle);
> 
> +
> 
> +  return Status;
> 
> +}
> 
> 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/HttpDynamicCommand.c
> b/ShellPkg/DynamicCommand/HttpDynamicCommand/HttpDynamicCommand.c
> new file mode 100644
> index 000000000000..ba654749a075
> --- /dev/null
> +++
> b/ShellPkg/DynamicCommand/HttpDynamicCommand/HttpDynamicCommand.c
> @@ -0,0 +1,134 @@
> +/** @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/HttpDynamicCommand.in
> f
> b/ShellPkg/DynamicCommand/HttpDynamicCommand/HttpDynamicCommand.in
> f
> new file mode 100644
> index 000000000000..5d46ee2384d5
> --- /dev/null
> +++
> b/ShellPkg/DynamicCommand/HttpDynamicCommand/HttpDynamicCommand.in
> f
> @@ -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/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/ShellPkg.dec b/ShellPkg/ShellPkg.dec
> index c17e358d15ed..f80a2962dfd1 100644
> --- a/ShellPkg/ShellPkg.dec
> +++ b/ShellPkg/ShellPkg.dec
> @@ -50,6 +50,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 b7ee856b3a16..58aa6e12bea3 100644
> --- a/ShellPkg/ShellPkg.dsc
> +++ b/ShellPkg/ShellPkg.dsc
> @@ -138,6 +138,11 @@ [Components]
>        gEfiShellPkgTokenSpaceGuid.PcdShellLibAutoInitialize|FALSE
> 
>    }
> 
>    ShellPkg/DynamicCommand/TftpDynamicCommand/TftpApp.inf
> 
> +
> ShellPkg/DynamicCommand/HttpDynamicCommand/HttpDynamicCommand.inf {
> 
> +    <PcdsFixedAtBuild>
> 
> +      gEfiShellPkgTokenSpaceGuid.PcdShellLibAutoInitialize|FALSE
> 
> +  }
> 
> +  ShellPkg/DynamicCommand/HttpDynamicCommand/HttpApp.inf
> 
>    ShellPkg/DynamicCommand/DpDynamicCommand/DpDynamicCommand.inf {
> 
>      <PcdsFixedAtBuild>
> 
>        gEfiShellPkgTokenSpaceGuid.PcdShellLibAutoInitialize|FALSE
> 
> --
> 2.26.2.266.ge870325ee8
> 
> 
> -=-=-=-=-=-=
> Groups.io Links: You receive all messages sent to this group.
> 
> View/Reply Online (#59160): https://edk2.groups.io/g/devel/message/59160
> Mute This Topic: https://groups.io/mt/74141905/1768756
> Group Owner: devel+owner@edk2.groups.io
> Unsubscribe: https://edk2.groups.io/g/devel/unsub  [zhichao.gao@intel.com]
> -=-=-=-=-=-=


  reply	other threads:[~2020-07-02  5:55 UTC|newest]

Thread overview: 3+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2020-05-11 18:03 [PATCH v2 1/1] ShellPkg/DynamicCommand: add HttpDynamicCommand Vladimir Olovyannikov
2020-07-02  5:55 ` Gao, Zhichao [this message]
2020-07-03  3:47   ` [edk2-devel] " Vladimir Olovyannikov

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=DM6PR11MB44255E2CD6D51095D2F66777F66D0@DM6PR11MB4425.namprd11.prod.outlook.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