]> git.proxmox.com Git - mirror_edk2.git/blobdiff - MdeModulePkg/Library/DxeHttpLib/DxeHttpLib.c
BaseTools:Change the path of the file that Binary Cache
[mirror_edk2.git] / MdeModulePkg / Library / DxeHttpLib / DxeHttpLib.c
index 3b0d9c96045bfc061bfc71ba7b47aad27f5553bf..8b74554cd96157b2cb788b1c32f9c50a6664ef9f 100644 (file)
-/** @file
-  This library is used to share code between UEFI network stack modules.
-  It provides the helper routines to parse the HTTP message byte stream.
-
-Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
-This program and the accompanying materials
-are licensed and made available under the terms and conditions of the BSD License
-which accompanies this distribution.  The full text of the license may be found at<BR>
-http://opensource.org/licenses/bsd-license.php
-
-THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
-WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
-
-**/
-
-#include <Uefi.h>
-#include <Library/NetLib.h>
-#include <Library/HttpLib.h>
-#include <Library/BaseLib.h>
-#include <Library/DebugLib.h>
-#include <Library/MemoryAllocationLib.h>
-#include <Library/UefiBootServicesTableLib.h>
-
-#define BIT(x)  (1 << x)
-
-#define NET_IS_HEX_CHAR(Ch)   \
-  ((('0' <= (Ch)) && ((Ch) <= '9')) ||  \
-   (('A' <= (Ch)) && ((Ch) <= 'F')) ||  \
-   (('a' <= (Ch)) && ((Ch) <= 'f')))
-
-//
-// Field index of the HTTP URL parse result.
-//
-#define   HTTP_URI_FIELD_SCHEME           0
-#define   HTTP_URI_FIELD_AUTHORITY        1
-#define   HTTP_URI_FIELD_PATH             2
-#define   HTTP_URI_FIELD_QUERY            3
-#define   HTTP_URI_FIELD_FRAGMENT         4
-#define   HTTP_URI_FIELD_USERINFO         5
-#define   HTTP_URI_FIELD_HOST             6
-#define   HTTP_URI_FIELD_PORT             7
-#define   HTTP_URI_FIELD_MAX              8
-
-//
-// Structure to store the parse result of a HTTP URL.
-//
-typedef struct {
-    UINT32      Offset;
-    UINT32      Length;
-} HTTP_URL_FILED_DATA;
-
-typedef struct {
-  UINT16                  FieldBitMap;
-  HTTP_URL_FILED_DATA     FieldData[HTTP_URI_FIELD_MAX];
-} HTTP_URL_PARSER;
-
-typedef enum {
-  UrlParserUrlStart,
-  UrlParserScheme,
-  UrlParserSchemeColon,            // ":"
-  UrlParserSchemeColonSlash,       // ":/"
-  UrlParserSchemeColonSlashSlash,  // "://"
-  UrlParserAuthority,
-  UrlParserAtInAuthority,
-  UrlParserPath,
-  UrlParserQueryStart,    // "?"
-  UrlParserQuery,
-  UrlParserFragmentStart, // "#"
-  UrlParserFragment,
-  UrlParserUserInfo,
-  UrlParserHostStart,     // "@"
-  UrlParserHost,
-  UrlParserPortStart,     // ":"
-  UrlParserPort,
-  UrlParserStateMax
-} HTTP_URL_PARSE_STATE;
-
-/**
-  Decode a percent-encoded URI component to the ASCII character.
-  
-  Decode the input component in Buffer according to RFC 3986. The caller is responsible to make 
-  sure ResultBuffer points to a buffer with size equal or greater than ((AsciiStrSize (Buffer))
-  in bytes. 
-
-  @param[in]    Buffer           The pointer to a percent-encoded URI component.
-  @param[in]    BufferLength     Length of Buffer in bytes.
-  @param[out]   ResultBuffer     Point to the buffer to store the decode result.
-  @param[out]   ResultLength     Length of decoded string in ResultBuffer in bytes.
-
-  @retval EFI_SUCCESS            Successfully decoded the URI.
-  @retval EFI_INVALID_PARAMETER  Buffer is not a valid percent-encoded string.
-  
-**/
-EFI_STATUS
-EFIAPI
-UriPercentDecode (
-  IN      CHAR8            *Buffer,
-  IN      UINT32            BufferLength,
-     OUT  CHAR8            *ResultBuffer,
-     OUT  UINT32           *ResultLength
-  )
-{
-  UINTN           Index;
-  UINTN           Offset;
-  CHAR8           HexStr[3];
-
-  if (Buffer == NULL || BufferLength == 0 || ResultBuffer == NULL) {
-    return EFI_INVALID_PARAMETER;
-  }
-  
-  Index = 0;
-  Offset = 0;
-  HexStr[2] = '\0';
-  while (Index < BufferLength) {
-    if (Buffer[Index] == '%') {
-      if (!NET_IS_HEX_CHAR (Buffer[Index+1]) || !NET_IS_HEX_CHAR (Buffer[Index+2])) {
-        return EFI_INVALID_PARAMETER;
-      }
-      HexStr[0] = Buffer[Index+1];
-      HexStr[1] = Buffer[Index+2];
-      ResultBuffer[Offset] = (CHAR8) AsciiStrHexToUintn (HexStr);
-      Index += 3;
-    } else {
-      ResultBuffer[Offset] = Buffer[Index];
-      Index++;
-    }
-    Offset++;
-  }
-
-  *ResultLength = (UINT32) Offset;
-    
-  return EFI_SUCCESS;
-}
-
-/**
-  This function return the updated state accroding to the input state and next character of
-  the authority.
-
-  @param[in]       Char           Next character.
-  @param[in]       State          Current value of the parser state machine.
-
-  @return          Updated state value.
-**/
-HTTP_URL_PARSE_STATE
-NetHttpParseAuthorityChar (
-  IN  CHAR8                  Char,
-  IN  HTTP_URL_PARSE_STATE   State
-  )
-{
-
-  //
-  // RFC 3986:
-  // The authority component is preceded by a double slash ("//") and is
-  // terminated by the next slash ("/"), question mark ("?"), or number
-  // sign ("#") character, or by the end of the URI.
-  //
-  if (Char == ' ' || Char == '\r' || Char == '\n') {
-    return UrlParserStateMax;
-  }
-
-  //
-  // authority   = [ userinfo "@" ] host [ ":" port ]
-  //
-  switch (State) {
-  case UrlParserUserInfo:
-    if (Char == '@') {
-      return UrlParserHostStart;
-    }
-    break;
-
-  case UrlParserHost:
-  case UrlParserHostStart:
-    if (Char == ':') {
-      return UrlParserPortStart;
-    }
-    return UrlParserHost;
-
-  case UrlParserPort:
-  case UrlParserPortStart:
-    return UrlParserPort;
-
-  default:
-    break;
-  }
-
-  return State;
-}
-
-/**
-  This function parse the authority component of the input URL and update the parser.
-
-  @param[in]       Url            The pointer to a HTTP URL string.
-  @param[in]       FoundAt        TRUE if there is an at sign ('@') in the authority component.
-  @param[in, out]  UrlParser      Pointer to the buffer of the parse result.
-
-  @retval EFI_SUCCESS             Successfully parse the authority.
-  @retval Other                   Error happened.
-
-**/
-EFI_STATUS
-NetHttpParseAuthority (
-  IN      CHAR8              *Url,
-  IN      BOOLEAN            FoundAt,
-  IN OUT  HTTP_URL_PARSER    *UrlParser
-  )
-{
-  CHAR8                 *Char;
-  CHAR8                 *Authority;
-  UINT32                Length;
-  HTTP_URL_PARSE_STATE  State;
-  UINT32                Field;
-  UINT32                OldField;
-  
-  ASSERT ((UrlParser->FieldBitMap & BIT (HTTP_URI_FIELD_AUTHORITY)) != 0);
-
-  //
-  // authority   = [ userinfo "@" ] host [ ":" port ]
-  //
-  if (FoundAt) {
-    State = UrlParserUserInfo;
-  } else {
-    State = UrlParserHost;
-  }
-
-  Field = HTTP_URI_FIELD_MAX;
-  OldField = Field;
-  Authority = Url + UrlParser->FieldData[HTTP_URI_FIELD_AUTHORITY].Offset;
-  Length = UrlParser->FieldData[HTTP_URI_FIELD_AUTHORITY].Length;
-  for (Char = Authority; Char < Authority + Length; Char++) {
-    State = NetHttpParseAuthorityChar (*Char, State);
-    switch (State) {
-    case UrlParserStateMax:
-      return EFI_INVALID_PARAMETER;
-
-    case UrlParserHostStart:
-    case UrlParserPortStart:
-      continue;
-
-    case UrlParserUserInfo:
-      Field = HTTP_URI_FIELD_USERINFO;
-      break;
-      
-    case UrlParserHost:
-      Field = HTTP_URI_FIELD_HOST;
-      break;
-      
-    case UrlParserPort:
-      Field = HTTP_URI_FIELD_PORT;
-      break;
-
-    default:
-      ASSERT (FALSE);
-    }
-
-    //
-    // Field not changed, count the length.
-    //
-    ASSERT (Field < HTTP_URI_FIELD_MAX);
-    if (Field == OldField) {
-      UrlParser->FieldData[Field].Length++;
-      continue;
-    }
-
-    //
-    // New field start
-    //
-    UrlParser->FieldBitMap |= BIT (Field);
-    UrlParser->FieldData[Field].Offset = (UINT32) (Char - Url);
-    UrlParser->FieldData[Field].Length = 1;
-    OldField = Field;
-  }
-
-  return EFI_SUCCESS;
-}
-
-/**
-  This function return the updated state accroding to the input state and next character of a URL.
-
-  @param[in]       Char           Next character.
-  @param[in]       State          Current value of the parser state machine.
-
-  @return          Updated state value.
-
-**/
-HTTP_URL_PARSE_STATE
-NetHttpParseUrlChar (
-  IN  CHAR8                  Char,
-  IN  HTTP_URL_PARSE_STATE   State
-  )
-{
-  if (Char == ' ' || Char == '\r' || Char == '\n') {
-    return UrlParserStateMax;
-  }
-  
-  //
-  // http_URL = "http:" "//" host [ ":" port ] [ abs_path [ "?" query ]]
-  // 
-  // Request-URI    = "*" | absolute-URI | path-absolute | authority
-  // 
-  // absolute-URI  = scheme ":" hier-part [ "?" query ]
-  // path-absolute = "/" [ segment-nz *( "/" segment ) ]
-  // authority   = [ userinfo "@" ] host [ ":" port ]
-  //
-  switch (State) {
-  case UrlParserUrlStart:
-    if (Char == '*' || Char == '/') {
-      return UrlParserPath;
-    }
-    return UrlParserScheme;
-
-  case UrlParserScheme:
-    if (Char == ':') {
-      return UrlParserSchemeColon;
-    }
-    break;
-
-  case UrlParserSchemeColon:
-    if (Char == '/') {
-      return UrlParserSchemeColonSlash;
-    }
-    break;
-
-  case UrlParserSchemeColonSlash:
-    if (Char == '/') {
-      return UrlParserSchemeColonSlashSlash;
-    }
-    break;
-
-  case UrlParserAtInAuthority:
-    if (Char == '@') {
-      return UrlParserStateMax;
-    }
-
-  case UrlParserAuthority:
-  case UrlParserSchemeColonSlashSlash:
-    if (Char == '@') {
-      return UrlParserAtInAuthority;
-    }
-    if (Char == '/') {
-      return UrlParserPath;
-    }
-    if (Char == '?') {
-      return UrlParserQueryStart;
-    }
-    if (Char == '#') {
-      return UrlParserFragmentStart;
-    }
-    return UrlParserAuthority;
-
-  case UrlParserPath:
-    if (Char == '?') {
-      return UrlParserQueryStart;
-    }
-    if (Char == '#') {
-      return UrlParserFragmentStart;
-    }
-    break;
-
-  case UrlParserQuery:
-  case UrlParserQueryStart:
-    if (Char == '#') {
-      return UrlParserFragmentStart;
-    }
-    return UrlParserQuery;
-
-  case UrlParserFragmentStart:
-    return UrlParserFragment;
-    
-  default:
-    break;
-  }
-
-  return State;
-}
-/**
-  Create a URL parser for the input URL string.
-
-  This function will parse and dereference the input HTTP URL into it components. The original
-  content of the URL won't be modified and the result will be returned in UrlParser, which can
-  be used in other functions like NetHttpUrlGetHostName().
-
-  @param[in]    Url                The pointer to a HTTP URL string.
-  @param[in]    Length             Length of Url in bytes.
-  @param[in]    IsConnectMethod    Whether the Url is used in HTTP CONNECT method or not.
-  @param[out]   UrlParser          Pointer to the returned buffer to store the parse result.
-
-  @retval EFI_SUCCESS              Successfully dereferenced the HTTP URL.
-  @retval EFI_INVALID_PARAMETER    UrlParser is NULL or Url is not a valid HTTP URL.
-  @retval EFI_OUT_OF_RESOURCES     Could not allocate needed resources.
-
-**/
-EFI_STATUS
-EFIAPI
-HttpParseUrl (
-  IN      CHAR8              *Url,
-  IN      UINT32             Length,
-  IN      BOOLEAN            IsConnectMethod,
-     OUT  VOID               **UrlParser
-  )
-{
-  HTTP_URL_PARSE_STATE  State;
-  CHAR8                 *Char;
-  UINT32                Field;
-  UINT32                OldField;
-  BOOLEAN               FoundAt;
-  EFI_STATUS            Status;
-  HTTP_URL_PARSER       *Parser;
-  
-  if (Url == NULL || Length == 0 || UrlParser == NULL) {
-    return EFI_INVALID_PARAMETER;
-  }
-
-  Parser = AllocateZeroPool (sizeof (HTTP_URL_PARSER));
-  if (Parser == NULL) {
-    return EFI_OUT_OF_RESOURCES;
-  }
-  
-  if (IsConnectMethod) {
-    //
-    // According to RFC 2616, the authority form is only used by the CONNECT method.
-    //
-    State = UrlParserAuthority;
-  } else {
-    State = UrlParserUrlStart;
-  }
-
-  Field = HTTP_URI_FIELD_MAX;
-  OldField = Field;
-  FoundAt = FALSE;
-  for (Char = Url; Char < Url + Length; Char++) {
-    //
-    // Update state machine accoring to next char.
-    //
-    State = NetHttpParseUrlChar (*Char, State);
-
-    switch (State) {
-    case UrlParserStateMax:
-      return EFI_INVALID_PARAMETER;
-      
-    case UrlParserSchemeColon:
-    case UrlParserSchemeColonSlash:
-    case UrlParserSchemeColonSlashSlash:
-    case UrlParserQueryStart:
-    case UrlParserFragmentStart:
-      //
-      // Skip all the delimiting char: "://" "?" "@"
-      //
-      continue;
-    
-    case UrlParserScheme:
-      Field = HTTP_URI_FIELD_SCHEME;
-      break;
-
-    case UrlParserAtInAuthority:
-      FoundAt = TRUE;
-    case UrlParserAuthority:
-      Field = HTTP_URI_FIELD_AUTHORITY;
-      break;
-
-    case UrlParserPath:
-      Field = HTTP_URI_FIELD_PATH;
-      break;
-
-    case UrlParserQuery:
-      Field = HTTP_URI_FIELD_QUERY;
-      break;
-
-    case UrlParserFragment:
-      Field = HTTP_URI_FIELD_FRAGMENT;
-      break;
-
-    default:
-      ASSERT (FALSE);
-    }
-
-    //
-    // Field not changed, count the length.
-    //
-    ASSERT (Field < HTTP_URI_FIELD_MAX);
-    if (Field == OldField) {
-      Parser->FieldData[Field].Length++;
-      continue;
-    }
-
-    //
-    // New field start
-    //
-    Parser->FieldBitMap |= BIT (Field);
-    Parser->FieldData[Field].Offset = (UINT32) (Char - Url);
-    Parser->FieldData[Field].Length = 1;
-    OldField = Field;
-  }
-
-  //
-  // If has authority component, continue to parse the username, host and port.
-  //
-  if ((Parser->FieldBitMap & BIT (HTTP_URI_FIELD_AUTHORITY)) != 0) {
-    Status = NetHttpParseAuthority (Url, FoundAt, Parser);
-    if (EFI_ERROR (Status)) {
-      return Status;
-    }
-  }
-
-  *UrlParser = Parser;
-  return EFI_SUCCESS;  
-}
-
-/**
-  Get the Hostname from a HTTP URL.
-
-  This function will return the HostName according to the Url and previous parse result ,and
-  it is the caller's responsibility to free the buffer returned in *HostName.
-
-  @param[in]    Url                The pointer to a HTTP URL string.
-  @param[in]    UrlParser          URL Parse result returned by NetHttpParseUrl().
-  @param[out]   HostName           Pointer to a buffer to store the HostName.
-
-  @retval EFI_SUCCESS              Successfully get the required component.
-  @retval EFI_INVALID_PARAMETER    Uri is NULL or HostName is NULL or UrlParser is invalid.
-  @retval EFI_NOT_FOUND            No hostName component in the URL.
-  @retval EFI_OUT_OF_RESOURCES     Could not allocate needed resources.
-  
-**/
-EFI_STATUS
-EFIAPI
-HttpUrlGetHostName (
-  IN      CHAR8              *Url,
-  IN      VOID               *UrlParser,
-     OUT  CHAR8              **HostName
-  )
-{
-  CHAR8                *Name;
-  EFI_STATUS           Status;
-  UINT32               ResultLength;
-  HTTP_URL_PARSER      *Parser;
-
-  if (Url == NULL || UrlParser == NULL || HostName == NULL) {
-    return EFI_INVALID_PARAMETER;
-  }
-
-  Parser = (HTTP_URL_PARSER*) UrlParser;
-
-  if ((Parser->FieldBitMap & BIT (HTTP_URI_FIELD_HOST)) == 0) {
-    return EFI_NOT_FOUND;
-  }
-
-  Name = AllocatePool (Parser->FieldData[HTTP_URI_FIELD_HOST].Length + 1);
-  if (Name == NULL) {
-    return EFI_OUT_OF_RESOURCES;
-  }
-  
-  Status = UriPercentDecode (
-             Url + Parser->FieldData[HTTP_URI_FIELD_HOST].Offset,
-             Parser->FieldData[HTTP_URI_FIELD_HOST].Length,
-             Name,
-             &ResultLength
-             );
-  if (EFI_ERROR (Status)) {
-    return Status;
-  }
-
-  Name[ResultLength] = '\0';
-  *HostName = Name;
-  return EFI_SUCCESS;
-}
-
-
-/**
-  Get the IPv4 address from a HTTP URL.
-
-  This function will return the IPv4 address according to the Url and previous parse result.
-
-  @param[in]    Url                The pointer to a HTTP URL string.
-  @param[in]    UrlParser          URL Parse result returned by NetHttpParseUrl().
-  @param[out]   Ip4Address         Pointer to a buffer to store the IP address.
-
-  @retval EFI_SUCCESS              Successfully get the required component.
-  @retval EFI_INVALID_PARAMETER    Uri is NULL or Ip4Address is NULL or UrlParser is invalid.
-  @retval EFI_NOT_FOUND            No IPv4 address component in the URL.
-  @retval EFI_OUT_OF_RESOURCES     Could not allocate needed resources.
-  
-**/
-EFI_STATUS
-EFIAPI
-HttpUrlGetIp4 (
-  IN      CHAR8              *Url,
-  IN      VOID               *UrlParser,
-     OUT  EFI_IPv4_ADDRESS   *Ip4Address
-  )
-{
-  CHAR8                *Ip4String;
-  EFI_STATUS           Status;
-  UINT32               ResultLength;
-  HTTP_URL_PARSER      *Parser;
-  
-  if (Url == NULL || UrlParser == NULL || Ip4Address == NULL) {
-    return EFI_INVALID_PARAMETER;
-  }
-
-  Parser = (HTTP_URL_PARSER*) UrlParser;
-
-  if ((Parser->FieldBitMap & BIT (HTTP_URI_FIELD_HOST)) == 0) {
-    return EFI_INVALID_PARAMETER;
-  }
-
-  Ip4String = AllocatePool (Parser->FieldData[HTTP_URI_FIELD_HOST].Length + 1);
-  if (Ip4String == NULL) {
-    return EFI_OUT_OF_RESOURCES;
-  }
-  
-  Status = UriPercentDecode (
-             Url + Parser->FieldData[HTTP_URI_FIELD_HOST].Offset,
-             Parser->FieldData[HTTP_URI_FIELD_HOST].Length,
-             Ip4String,
-             &ResultLength
-             );
-  if (EFI_ERROR (Status)) {
-    return Status;
-  }
-
-  Ip4String[ResultLength] = '\0';
-  Status = NetLibAsciiStrToIp4 (Ip4String, Ip4Address);
-  FreePool (Ip4String);
-
-  return Status;
-}
-
-/**
-  Get the IPv6 address from a HTTP URL.
-
-  This function will return the IPv6 address according to the Url and previous parse result.
-
-  @param[in]    Url                The pointer to a HTTP URL string.
-  @param[in]    UrlParser          URL Parse result returned by NetHttpParseUrl().
-  @param[out]   Ip6Address         Pointer to a buffer to store the IP address.
-
-  @retval EFI_SUCCESS              Successfully get the required component.
-  @retval EFI_INVALID_PARAMETER    Uri is NULL or Ip6Address is NULL or UrlParser is invalid.
-  @retval EFI_NOT_FOUND            No IPv6 address component in the URL.
-  @retval EFI_OUT_OF_RESOURCES     Could not allocate needed resources.
-  
-**/
-EFI_STATUS
-EFIAPI
-HttpUrlGetIp6 (
-  IN      CHAR8              *Url,
-  IN      VOID               *UrlParser,
-     OUT  EFI_IPv6_ADDRESS   *Ip6Address
-  )
-{
-  CHAR8                *Ip6String;
-  CHAR8                *Ptr;
-  UINT32               Length;
-  EFI_STATUS           Status;
-  UINT32               ResultLength;
-  HTTP_URL_PARSER      *Parser;
-  
-  if (Url == NULL || UrlParser == NULL || Ip6Address == NULL) {
-    return EFI_INVALID_PARAMETER;
-  }
-
-  Parser = (HTTP_URL_PARSER*) UrlParser;
-
-  if ((Parser->FieldBitMap & BIT (HTTP_URI_FIELD_HOST)) == 0) {
-    return EFI_INVALID_PARAMETER;
-  }
-
-  //
-  // IP-literal = "[" ( IPv6address / IPvFuture  ) "]"
-  //
-  Length = Parser->FieldData[HTTP_URI_FIELD_HOST].Length;
-  if (Length < 2) {
-    return EFI_INVALID_PARAMETER;
-  }
-
-  Ptr    = Url + Parser->FieldData[HTTP_URI_FIELD_HOST].Offset;
-  if ((Ptr[0] != '[') || (Ptr[Length - 1] != ']')) {
-    return EFI_INVALID_PARAMETER;
-  }
-
-  Ip6String = AllocatePool (Length);
-  if (Ip6String == NULL) {
-    return EFI_OUT_OF_RESOURCES;
-  }
-  
-  Status = UriPercentDecode (
-             Ptr + 1,
-             Length - 2,
-             Ip6String,
-             &ResultLength
-             );
-  if (EFI_ERROR (Status)) {
-    return Status;
-  }
-  
-  Ip6String[ResultLength] = '\0';
-  Status = NetLibAsciiStrToIp6 (Ip6String, Ip6Address);
-  FreePool (Ip6String);
-
-  return Status;
-}
-
-/**
-  Get the port number from a HTTP URL.
-
-  This function will return the port number according to the Url and previous parse result.
-
-  @param[in]    Url                The pointer to a HTTP URL string.
-  @param[in]    UrlParser          URL Parse result returned by NetHttpParseUrl().
-  @param[out]   Port               Pointer to a buffer to store the port number.
-
-  @retval EFI_SUCCESS              Successfully get the required component.
-  @retval EFI_INVALID_PARAMETER    Uri is NULL or Port is NULL or UrlParser is invalid.
-  @retval EFI_NOT_FOUND            No port number in the URL.
-  @retval EFI_OUT_OF_RESOURCES     Could not allocate needed resources.
-  
-**/
-EFI_STATUS
-EFIAPI
-HttpUrlGetPort (
-  IN      CHAR8              *Url,
-  IN      VOID               *UrlParser,
-     OUT  UINT16             *Port
-  )
-{
-  CHAR8         *PortString;
-  EFI_STATUS    Status;
-  UINT32        ResultLength;
-  HTTP_URL_PARSER      *Parser;
-
-  if (Url == NULL || UrlParser == NULL || Port == NULL) {
-    return EFI_INVALID_PARAMETER;
-  }
-
-  Parser = (HTTP_URL_PARSER*) UrlParser;
-
-  if ((Parser->FieldBitMap & BIT (HTTP_URI_FIELD_PORT)) == 0) {
-    return EFI_INVALID_PARAMETER;
-  }
-
-  PortString = AllocatePool (Parser->FieldData[HTTP_URI_FIELD_PORT].Length + 1);
-  if (PortString == NULL) {
-    return EFI_OUT_OF_RESOURCES;
-  }
-
-  Status = UriPercentDecode (
-             Url + Parser->FieldData[HTTP_URI_FIELD_PORT].Offset,
-             Parser->FieldData[HTTP_URI_FIELD_PORT].Length,
-             PortString,
-             &ResultLength
-             );
-  if (EFI_ERROR (Status)) {
-    return Status;
-  }
-
-  PortString[ResultLength] = '\0';
-  *Port = (UINT16) AsciiStrDecimalToUintn (Url + Parser->FieldData[HTTP_URI_FIELD_PORT].Offset);
-
-  return  EFI_SUCCESS;
-}
-
-/**
-  Release the resource of the URL parser.
-
-  @param[in]    UrlParser            Pointer to the parser.
-  
-**/
-VOID
-EFIAPI
-HttpUrlFreeParser (
-  IN      VOID               *UrlParser
-  )
-{
-  FreePool (UrlParser);
-}
-
-/**
-  Find a specified header field according to the field name.
-
-  @param[in]   HeaderCount      Number of HTTP header structures in Headers list. 
-  @param[in]   Headers          Array containing list of HTTP headers.
-  @param[in]   FieldName        Null terminated string which describes a field name. 
-
-  @return    Pointer to the found header or NULL.
-
-**/
-EFI_HTTP_HEADER *
-HttpIoFindHeader (
-  IN  UINTN                HeaderCount,
-  IN  EFI_HTTP_HEADER      *Headers,
-  IN  CHAR8                *FieldName
-  )
-{
-  UINTN                 Index;
-  
-  if (HeaderCount == 0 || Headers == NULL || FieldName == NULL) {
-    return NULL;
-  }
-
-  for (Index = 0; Index < HeaderCount; Index++){
-    //
-    // Field names are case-insensitive (RFC 2616).
-    //
-    if (AsciiStriCmp (Headers[Index].FieldName, FieldName) == 0) {
-      return &Headers[Index];
-    }
-  }
-  return NULL;
-}
-
-typedef enum {
-  BodyParserBodyStart,
-  BodyParserBodyIdentity,
-  BodyParserChunkSizeStart,
-  BodyParserChunkSize,
-  BodyParserChunkSizeEndCR,
-  BodyParserChunkExtStart,
-  BodyParserChunkDataStart,
-  BodyParserChunkDataEnd,
-  BodyParserChunkDataEndCR,
-  BodyParserComplete,
-  BodyParserStateMax
-} HTTP_BODY_PARSE_STATE;
-
-typedef struct {
-  BOOLEAN                       IgnoreBody;    // "MUST NOT" include a message-body
-  BOOLEAN                       IsChunked;     // "chunked" transfer-coding.
-  BOOLEAN                       ContentLengthIsValid;
-  UINTN                         ContentLength; // Entity length (not the message-body length), invalid until ContentLengthIsValid is TRUE
-  
-  HTTP_BODY_PARSER_CALLBACK     Callback;
-  VOID                          *Context;
-  UINTN                         ParsedBodyLength;
-  HTTP_BODY_PARSE_STATE         State;
-  UINTN                         CurrentChunkSize;
-  UINTN                         CurrentChunkParsedSize;
-} HTTP_BODY_PARSER;
-
-/**
-
-  Convert an Ascii char to its uppercase.
-
-  @param[in]       Char           Ascii character.
-
-  @return          Uppercase value of the input Char.
-
-**/
-CHAR8
-HttpIoCharToUpper (
-  IN      CHAR8                    Char
-  )
-{
-  if (Char >= 'a' && Char <= 'z') {
-    return  Char - ('a' - 'A');
-  }
-
-  return Char;
-}
-
-/**
-  Convert an hexadecimal char to a value of type UINTN.
-
-  @param[in]       Char           Ascii character.
-
-  @return          Value translated from Char.
-
-**/
-UINTN
-HttpIoHexCharToUintn (
-  IN CHAR8           Char
-  )
-{
-  if (Char >= '0' && Char <= '9') {
-    return Char - '0';
-  }
-
-  return (10 + HttpIoCharToUpper (Char) - 'A');
-}
-
-/**
-  Get the value of the content length if there is a "Content-Length" header.
-
-  @param[in]    HeaderCount        Number of HTTP header structures in Headers.
-  @param[in]    Headers            Array containing list of HTTP headers.
-  @param[out]   ContentLength      Pointer to save the value of the content length.
-
-  @retval EFI_SUCCESS              Successfully get the content length.
-  @retval EFI_NOT_FOUND            No "Content-Length" header in the Headers.
-
-**/
-EFI_STATUS
-HttpIoParseContentLengthHeader (
-  IN     UINTN                HeaderCount,
-  IN     EFI_HTTP_HEADER      *Headers,
-     OUT UINTN                *ContentLength
-  )
-{
-  EFI_HTTP_HEADER       *Header;
-  
-  Header = HttpIoFindHeader (HeaderCount, Headers, "Content-Length");
-  if (Header == NULL) {
-    return EFI_NOT_FOUND;
-  }
-
-  *ContentLength = AsciiStrDecimalToUintn (Header->FieldValue);
-  return EFI_SUCCESS;
-}
-
-/**
-
-  Check whether the HTTP message is using the "chunked" transfer-coding.
-
-  @param[in]    HeaderCount        Number of HTTP header structures in Headers.
-  @param[in]    Headers            Array containing list of HTTP headers.
-
-  @return       The message is "chunked" transfer-coding (TRUE) or not (FALSE).
-**/
-BOOLEAN
-HttpIoIsChunked (
-  IN   UINTN                    HeaderCount,
-  IN   EFI_HTTP_HEADER          *Headers
-  )
-{
-  EFI_HTTP_HEADER       *Header;
-
-
-  Header = HttpIoFindHeader (HeaderCount, Headers, "Transfer-Encoding");
-  if (Header == NULL) {
-    return FALSE;
-  }
-
-  if (AsciiStriCmp (Header->FieldValue, "identity") != 0) {
-    return TRUE;
-  }
-
-  return FALSE;
-}
-
-/**
-  Check whether the HTTP message should have a message-body.
-
-  @param[in]    Method             The HTTP method (e.g. GET, POST) for this HTTP message.
-  @param[in]    StatusCode         Response status code returned by the remote host.
-
-  @return       The message should have a message-body (FALSE) or not (TRUE).
-
-**/
-BOOLEAN
-HttpIoNoMessageBody (
-  IN   EFI_HTTP_METHOD          Method,
-  IN   EFI_HTTP_STATUS_CODE     StatusCode
-  )
-{
-  //
-  // RFC 2616:
-  // All responses to the HEAD request method
-  // MUST NOT include a message-body, even though the presence of entity-
-  // header fields might lead one to believe they do. All 1xx
-  // (informational), 204 (no content), and 304 (not modified) responses
-  // MUST NOT include a message-body. All other responses do include a
-  // message-body, although it MAY be of zero length.
-  //
-  if (Method == HttpMethodHead) {
-    return TRUE;
-  }
-
-  if ((StatusCode == HTTP_STATUS_100_CONTINUE) ||
-      (StatusCode == HTTP_STATUS_101_SWITCHING_PROTOCOLS) ||
-      (StatusCode == HTTP_STATUS_204_NO_CONTENT) ||
-      (StatusCode == HTTP_STATUS_304_NOT_MODIFIED))
-  {
-    return TRUE;
-  }
-
-  return FALSE;
-}
-
-/**
-  Initialize a HTTP message-body parser.
-
-  This function will create and initialize a HTTP message parser according to caller provided HTTP message
-  header information. It is the caller's responsibility to free the buffer returned in *UrlParser by HttpFreeMsgParser().
-
-  @param[in]    Method             The HTTP method (e.g. GET, POST) for this HTTP message.
-  @param[in]    StatusCode         Response status code returned by the remote host.
-  @param[in]    HeaderCount        Number of HTTP header structures in Headers.
-  @param[in]    Headers            Array containing list of HTTP headers.
-  @param[in]    Callback           Callback function that is invoked when parsing the HTTP message-body,
-                                   set to NULL to ignore all events.
-  @param[in]    Context            Pointer to the context that will be passed to Callback.
-  @param[out]   MsgParser          Pointer to the returned buffer to store the message parser.
-
-  @retval EFI_SUCCESS              Successfully initialized the parser.
-  @retval EFI_OUT_OF_RESOURCES     Could not allocate needed resources.
-  @retval EFI_INVALID_PARAMETER    MsgParser is NULL or HeaderCount is not NULL but Headers is NULL.
-  @retval Others                   Failed to initialize the parser.
-
-**/
-EFI_STATUS
-EFIAPI
-HttpInitMsgParser (
-  IN     EFI_HTTP_METHOD               Method,
-  IN     EFI_HTTP_STATUS_CODE          StatusCode,
-  IN     UINTN                         HeaderCount,
-  IN     EFI_HTTP_HEADER               *Headers,
-  IN     HTTP_BODY_PARSER_CALLBACK     Callback,
-  IN     VOID                          *Context,
-    OUT  VOID                          **MsgParser
-  )
-{
-  EFI_STATUS            Status;
-  HTTP_BODY_PARSER      *Parser;
-  
-  if (HeaderCount != 0 && Headers == NULL) {
-    return EFI_INVALID_PARAMETER;
-  }
-
-  if (MsgParser == NULL) {
-    return EFI_INVALID_PARAMETER;
-  }
-
-  Parser = AllocateZeroPool (sizeof (HTTP_BODY_PARSER));
-  if (Parser == NULL) {
-    return EFI_OUT_OF_RESOURCES;
-  }
-
-  Parser->State = BodyParserBodyStart;
-  
-  //
-  // Determine the message length accroding to RFC 2616.
-  // 1. Check whether the message "MUST NOT" have a message-body.
-  //
-  Parser->IgnoreBody = HttpIoNoMessageBody (Method, StatusCode);
-  //
-  // 2. Check whether the message using "chunked" transfer-coding.
-  //
-  Parser->IsChunked  = HttpIoIsChunked (HeaderCount, Headers);
-  //
-  // 3. Check whether the message has a Content-Length header field.
-  //
-  Status = HttpIoParseContentLengthHeader (HeaderCount, Headers, &Parser->ContentLength);
-  if (!EFI_ERROR (Status)) {
-    Parser->ContentLengthIsValid = TRUE;
-  }
-  //
-  // 4. Range header is not supported now, so we won't meet media type "multipart/byteranges".
-  // 5. By server closing the connection
-  //
-  
-  //
-  // Set state to skip body parser if the message shouldn't have a message body.
-  //
-  if (Parser->IgnoreBody) {
-    Parser->State = BodyParserComplete;
-  } else {
-    Parser->Callback = Callback;
-    Parser->Context  = Context;
-  }
-
-  *MsgParser = Parser;
-  return EFI_SUCCESS;
-}
-
-/**
-  Parse message body.
-
-  Parse BodyLength of message-body. This function can be called repeatedly to parse the message-body partially.
-
-  @param[in, out]    MsgParser            Pointer to the message parser.
-  @param[in]         BodyLength           Length in bytes of the Body.
-  @param[in]         Body                 Pointer to the buffer of the message-body to be parsed.
-
-  @retval EFI_SUCCESS                Successfully parse the message-body.
-  @retval EFI_INVALID_PARAMETER      MsgParser is NULL or Body is NULL or BodyLength is 0.
-  @retval Others                     Operation aborted.
-
-**/
-EFI_STATUS
-EFIAPI
-HttpParseMessageBody (
-  IN OUT VOID              *MsgParser,
-  IN     UINTN             BodyLength,
-  IN     CHAR8             *Body
-  )
-{
-  CHAR8                 *Char;
-  UINTN                 RemainderLengthInThis;
-  UINTN                 LengthForCallback;
-  EFI_STATUS            Status;
-  HTTP_BODY_PARSER      *Parser;
-  
-  if (BodyLength == 0 || Body == NULL) {
-    return EFI_INVALID_PARAMETER;
-  }
-
-  if (MsgParser == NULL) {
-    return EFI_INVALID_PARAMETER;
-  }
-
-  Parser = (HTTP_BODY_PARSER*) MsgParser;
-
-  if (Parser->IgnoreBody) {
-    Parser->State = BodyParserComplete;
-    if (Parser->Callback != NULL) {
-      Status = Parser->Callback (
-                 BodyParseEventOnComplete,
-                 Body,
-                 0,
-                 Parser->Context
-                 );
-      if (EFI_ERROR (Status)) {
-        return Status;
-      }
-    }
-    return EFI_SUCCESS;
-  }
-
-  if (Parser->State == BodyParserBodyStart) {
-    Parser->ParsedBodyLength = 0;
-    if (Parser->IsChunked) {
-      Parser->State = BodyParserChunkSizeStart;
-    } else {
-      Parser->State = BodyParserBodyIdentity;
-    }
-  }
-
-  //
-  // The message body might be truncated in anywhere, so we need to parse is byte-by-byte.
-  //
-  for (Char = Body; Char < Body + BodyLength; ) {
-
-    switch (Parser->State) {
-    case BodyParserStateMax:
-      return EFI_ABORTED;
-
-    case BodyParserComplete:
-      if (Parser->Callback != NULL) {
-        Status = Parser->Callback (
-                   BodyParseEventOnComplete,
-                   Char,
-                   0,
-                   Parser->Context
-                   );
-        if (EFI_ERROR (Status)) {
-          return Status;
-        }
-      }
-      return EFI_SUCCESS;
-    
-    case BodyParserBodyIdentity:
-      //
-      // Identity transfer-coding, just notify user to save the body data.
-      //
-      if (Parser->Callback != NULL) {
-        Status = Parser->Callback (
-                   BodyParseEventOnData,
-                   Char,
-                   MIN (BodyLength, Parser->ContentLength - Parser->ParsedBodyLength),
-                   Parser->Context
-                   );
-        if (EFI_ERROR (Status)) {
-          return Status;
-        }
-      }
-      Char += MIN (BodyLength, Parser->ContentLength - Parser->ParsedBodyLength);
-      Parser->ParsedBodyLength += MIN (BodyLength, Parser->ContentLength - Parser->ParsedBodyLength);
-      if (Parser->ParsedBodyLength == Parser->ContentLength) {
-        Parser->State = BodyParserComplete;
-      }
-      break;
-
-    case BodyParserChunkSizeStart:
-      //
-      // First byte of chunk-size, the chunk-size might be truncated.
-      //
-      Parser->CurrentChunkSize = 0;
-      Parser->State = BodyParserChunkSize;
-    case BodyParserChunkSize:
-      if (!NET_IS_HEX_CHAR (*Char)) {
-        if (*Char == ';') {
-          Parser->State = BodyParserChunkExtStart;
-          Char++;
-        } else if (*Char == '\r') {
-          Parser->State = BodyParserChunkSizeEndCR;
-          Char++;
-        } else {
-          Parser->State = BodyParserStateMax;
-        }
-        break;
-      }
-
-      if (Parser->CurrentChunkSize > (((~((UINTN) 0)) - 16) / 16)) {
-        return EFI_INVALID_PARAMETER;
-      }
-      Parser->CurrentChunkSize = Parser->CurrentChunkSize * 16 + HttpIoHexCharToUintn (*Char);
-      Char++;
-      break;
-
-    case BodyParserChunkExtStart:
-      //
-      // Ignore all the chunk extensions.
-      //
-      if (*Char == '\r') {
-        Parser->State = BodyParserChunkSizeEndCR;
-       }
-      Char++;
-      break;
-      
-    case BodyParserChunkSizeEndCR:
-      if (*Char != '\n') {
-        Parser->State = BodyParserStateMax;
-        break;
-      }
-      Parser->State = BodyParserChunkDataStart;
-      Parser->CurrentChunkParsedSize = 0;
-      Char++;
-      break;
-
-    case BodyParserChunkDataStart:
-      if (Parser->CurrentChunkSize == 0) {
-        //
-        // This is the last chunk, the trailer header is unsupported.
-        //
-        Parser->ContentLengthIsValid = TRUE;
-        Parser->State = BodyParserComplete;
-        break;
-      }
-      
-      //
-      // First byte of chunk-data, the chunk data also might be truncated.
-      //
-      RemainderLengthInThis = BodyLength - (Char - Body);
-      LengthForCallback = MIN (Parser->CurrentChunkSize - Parser->CurrentChunkParsedSize, RemainderLengthInThis);
-      if (Parser->Callback != NULL) {
-        Status = Parser->Callback (
-                   BodyParseEventOnData,
-                   Char,
-                   LengthForCallback,
-                   Parser->Context
-                   );
-        if (EFI_ERROR (Status)) {
-          return Status;
-        }
-      }
-      Char += LengthForCallback;
-      Parser->ContentLength += LengthForCallback;
-      Parser->CurrentChunkParsedSize += LengthForCallback;
-      if (Parser->CurrentChunkParsedSize == Parser->CurrentChunkSize) {
-        Parser->State = BodyParserChunkDataEnd;
-      }           
-      break;
-
-    case BodyParserChunkDataEnd:
-      if (*Char == '\r') {
-        Parser->State = BodyParserChunkDataEndCR;
-      } else {
-        Parser->State = BodyParserStateMax;
-      }
-      Char++;
-      break;
-
-    case BodyParserChunkDataEndCR:
-      if (*Char != '\n') {
-        Parser->State = BodyParserStateMax;
-        break;
-      }
-      Char++;
-      Parser->State = BodyParserChunkSizeStart;
-      break;     
-
-    default:
-      break;
-    }
-
-  }
-
-  if (Parser->State == BodyParserStateMax) {
-    return EFI_ABORTED;
-  }
-
-  return EFI_SUCCESS;
-}
-
-/**
-  Check whether the message-body is complete or not.
-
-  @param[in]    MsgParser            Pointer to the message parser.
-
-  @retval TRUE                       Message-body is complete.
-  @retval FALSE                      Message-body is not complete.
-
-**/
-BOOLEAN
-EFIAPI
-HttpIsMessageComplete (
-  IN VOID              *MsgParser
-  )
-{
-  HTTP_BODY_PARSER      *Parser;
-
-  Parser = (HTTP_BODY_PARSER*) MsgParser;
-
-  if (Parser->State == BodyParserComplete) {
-    return TRUE;
-  }
-  return FALSE;
-}
-
-/**
-  Get the content length of the entity.
-
-  Note that in trunk transfer, the entity length is not valid until the whole message body is received.
-
-  @param[in]    MsgParser            Pointer to the message parser.
-  @param[out]   ContentLength        Pointer to store the length of the entity.
-
-  @retval EFI_SUCCESS                Successfully to get the entity length.
-  @retval EFI_NOT_READY              Entity length is not valid yet.
-  @retval EFI_INVALID_PARAMETER      MsgParser is NULL or ContentLength is NULL.
-  
-**/
-EFI_STATUS
-EFIAPI
-HttpGetEntityLength (
-  IN  VOID              *MsgParser,
-  OUT UINTN             *ContentLength
-  )
-{
-  HTTP_BODY_PARSER      *Parser;
-
-  if (MsgParser == NULL || ContentLength == NULL) {
-    return EFI_INVALID_PARAMETER;
-  }
-
-  Parser = (HTTP_BODY_PARSER*) MsgParser;
-
-  if (!Parser->ContentLengthIsValid) {
-    return EFI_NOT_READY;
-  }
-
-  *ContentLength = Parser->ContentLength;
-  return EFI_SUCCESS;
-}
-
-/**
-  Release the resource of the message parser.
-
-  @param[in]    MsgParser            Pointer to the message parser.
-  
-**/
-VOID
-EFIAPI
-HttpFreeMsgParser (
-  IN  VOID           *MsgParser
-  )
-{
-  FreePool (MsgParser);
-}
+/** @file\r
+  This library is used to share code between UEFI network stack modules.\r
+  It provides the helper routines to parse the HTTP message byte stream.\r
+\r
+Copyright (c) 2015 - 2019, Intel Corporation. All rights reserved.<BR>\r
+(C) Copyright 2016 Hewlett Packard Enterprise Development LP<BR>\r
+SPDX-License-Identifier: BSD-2-Clause-Patent\r
+\r
+**/\r
+\r
+#include "DxeHttpLib.h"\r
+\r
+\r
+\r
+/**\r
+  Decode a percent-encoded URI component to the ASCII character.\r
+\r
+  Decode the input component in Buffer according to RFC 3986. The caller is responsible to make\r
+  sure ResultBuffer points to a buffer with size equal or greater than ((AsciiStrSize (Buffer))\r
+  in bytes.\r
+\r
+  @param[in]    Buffer           The pointer to a percent-encoded URI component.\r
+  @param[in]    BufferLength     Length of Buffer in bytes.\r
+  @param[out]   ResultBuffer     Point to the buffer to store the decode result.\r
+  @param[out]   ResultLength     Length of decoded string in ResultBuffer in bytes.\r
+\r
+  @retval EFI_SUCCESS            Successfully decoded the URI.\r
+  @retval EFI_INVALID_PARAMETER  Buffer is not a valid percent-encoded string.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+UriPercentDecode (\r
+  IN      CHAR8            *Buffer,\r
+  IN      UINT32            BufferLength,\r
+     OUT  CHAR8            *ResultBuffer,\r
+     OUT  UINT32           *ResultLength\r
+  )\r
+{\r
+  UINTN           Index;\r
+  UINTN           Offset;\r
+  CHAR8           HexStr[3];\r
+\r
+  if (Buffer == NULL || BufferLength == 0 || ResultBuffer == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  Index = 0;\r
+  Offset = 0;\r
+  HexStr[2] = '\0';\r
+  while (Index < BufferLength) {\r
+    if (Buffer[Index] == '%') {\r
+      if (Index + 1 >= BufferLength || Index + 2 >= BufferLength ||\r
+          !NET_IS_HEX_CHAR (Buffer[Index+1]) || !NET_IS_HEX_CHAR (Buffer[Index+2])) {\r
+        return EFI_INVALID_PARAMETER;\r
+      }\r
+      HexStr[0] = Buffer[Index+1];\r
+      HexStr[1] = Buffer[Index+2];\r
+      ResultBuffer[Offset] = (CHAR8) AsciiStrHexToUintn (HexStr);\r
+      Index += 3;\r
+    } else {\r
+      ResultBuffer[Offset] = Buffer[Index];\r
+      Index++;\r
+    }\r
+    Offset++;\r
+  }\r
+\r
+  *ResultLength = (UINT32) Offset;\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  This function return the updated state according to the input state and next character of\r
+  the authority.\r
+\r
+  @param[in]       Char           Next character.\r
+  @param[in]       State          Current value of the parser state machine.\r
+  @param[in]       IsRightBracket TRUE if there is an sign ']' in the authority component and\r
+                                  indicates the next part is ':' before Port.\r
+\r
+  @return          Updated state value.\r
+**/\r
+HTTP_URL_PARSE_STATE\r
+NetHttpParseAuthorityChar (\r
+  IN  CHAR8                  Char,\r
+  IN  HTTP_URL_PARSE_STATE   State,\r
+  IN  BOOLEAN                *IsRightBracket\r
+  )\r
+{\r
+\r
+  //\r
+  // RFC 3986:\r
+  // The authority component is preceded by a double slash ("//") and is\r
+  // terminated by the next slash ("/"), question mark ("?"), or number\r
+  // sign ("#") character, or by the end of the URI.\r
+  //\r
+  if (Char == ' ' || Char == '\r' || Char == '\n') {\r
+    return UrlParserStateMax;\r
+  }\r
+\r
+  //\r
+  // authority   = [ userinfo "@" ] host [ ":" port ]\r
+  //\r
+  switch (State) {\r
+  case UrlParserUserInfo:\r
+    if (Char == '@') {\r
+      return UrlParserHostStart;\r
+    }\r
+    break;\r
+\r
+  case UrlParserHost:\r
+  case UrlParserHostStart:\r
+    if (Char == '[') {\r
+      return UrlParserHostIpv6;\r
+    }\r
+\r
+    if (Char == ':') {\r
+      return UrlParserPortStart;\r
+    }\r
+\r
+    return UrlParserHost;\r
+\r
+  case UrlParserHostIpv6:\r
+    if (Char == ']') {\r
+      *IsRightBracket = TRUE;\r
+    }\r
+\r
+    if (Char == ':' && *IsRightBracket) {\r
+      return UrlParserPortStart;\r
+    }\r
+    return UrlParserHostIpv6;\r
+\r
+  case UrlParserPort:\r
+  case UrlParserPortStart:\r
+    return UrlParserPort;\r
+\r
+  default:\r
+    break;\r
+  }\r
+\r
+  return State;\r
+}\r
+\r
+/**\r
+  This function parse the authority component of the input URL and update the parser.\r
+\r
+  @param[in]       Url            The pointer to a HTTP URL string.\r
+  @param[in]       FoundAt        TRUE if there is an at sign ('@') in the authority component.\r
+  @param[in, out]  UrlParser      Pointer to the buffer of the parse result.\r
+\r
+  @retval EFI_SUCCESS             Successfully parse the authority.\r
+  @retval EFI_INVALID_PARAMETER   The Url is invalid to parse the authority component.\r
+\r
+**/\r
+EFI_STATUS\r
+NetHttpParseAuthority (\r
+  IN      CHAR8              *Url,\r
+  IN      BOOLEAN            FoundAt,\r
+  IN OUT  HTTP_URL_PARSER    *UrlParser\r
+  )\r
+{\r
+  CHAR8                 *Char;\r
+  CHAR8                 *Authority;\r
+  UINT32                Length;\r
+  HTTP_URL_PARSE_STATE  State;\r
+  UINT32                Field;\r
+  UINT32                OldField;\r
+  BOOLEAN               IsrightBracket;\r
+\r
+  ASSERT ((UrlParser->FieldBitMap & BIT (HTTP_URI_FIELD_AUTHORITY)) != 0);\r
+\r
+  //\r
+  // authority   = [ userinfo "@" ] host [ ":" port ]\r
+  //\r
+  if (FoundAt) {\r
+    State = UrlParserUserInfo;\r
+  } else {\r
+    State = UrlParserHost;\r
+  }\r
+\r
+  IsrightBracket = FALSE;\r
+  Field = HTTP_URI_FIELD_MAX;\r
+  OldField = Field;\r
+  Authority = Url + UrlParser->FieldData[HTTP_URI_FIELD_AUTHORITY].Offset;\r
+  Length = UrlParser->FieldData[HTTP_URI_FIELD_AUTHORITY].Length;\r
+  for (Char = Authority; Char < Authority + Length; Char++) {\r
+    State = NetHttpParseAuthorityChar (*Char, State, &IsrightBracket);\r
+    switch (State) {\r
+    case UrlParserStateMax:\r
+      return EFI_INVALID_PARAMETER;\r
+\r
+    case UrlParserHostStart:\r
+    case UrlParserPortStart:\r
+      continue;\r
+\r
+    case UrlParserUserInfo:\r
+      Field = HTTP_URI_FIELD_USERINFO;\r
+      break;\r
+\r
+    case UrlParserHost:\r
+      Field = HTTP_URI_FIELD_HOST;\r
+      break;\r
+\r
+    case UrlParserHostIpv6:\r
+      Field = HTTP_URI_FIELD_HOST;\r
+      break;\r
+\r
+    case UrlParserPort:\r
+      Field = HTTP_URI_FIELD_PORT;\r
+      break;\r
+\r
+    default:\r
+      ASSERT (FALSE);\r
+    }\r
+\r
+    //\r
+    // Field not changed, count the length.\r
+    //\r
+    ASSERT (Field < HTTP_URI_FIELD_MAX);\r
+    if (Field == OldField) {\r
+      UrlParser->FieldData[Field].Length++;\r
+      continue;\r
+    }\r
+\r
+    //\r
+    // New field start\r
+    //\r
+    UrlParser->FieldBitMap |= BIT (Field);\r
+    UrlParser->FieldData[Field].Offset = (UINT32) (Char - Url);\r
+    UrlParser->FieldData[Field].Length = 1;\r
+    OldField = Field;\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  This function return the updated state according to the input state and next character of a URL.\r
+\r
+  @param[in]       Char           Next character.\r
+  @param[in]       State          Current value of the parser state machine.\r
+\r
+  @return          Updated state value.\r
+\r
+**/\r
+HTTP_URL_PARSE_STATE\r
+NetHttpParseUrlChar (\r
+  IN  CHAR8                  Char,\r
+  IN  HTTP_URL_PARSE_STATE   State\r
+  )\r
+{\r
+  if (Char == ' ' || Char == '\r' || Char == '\n') {\r
+    return UrlParserStateMax;\r
+  }\r
+\r
+  //\r
+  // http_URL = "http:" "//" host [ ":" port ] [ abs_path [ "?" query ]]\r
+  //\r
+  // Request-URI    = "*" | absolute-URI | path-absolute | authority\r
+  //\r
+  // absolute-URI  = scheme ":" hier-part [ "?" query ]\r
+  // path-absolute = "/" [ segment-nz *( "/" segment ) ]\r
+  // authority   = [ userinfo "@" ] host [ ":" port ]\r
+  //\r
+  switch (State) {\r
+  case UrlParserUrlStart:\r
+    if (Char == '*' || Char == '/') {\r
+      return UrlParserPath;\r
+    }\r
+    return UrlParserScheme;\r
+\r
+  case UrlParserScheme:\r
+    if (Char == ':') {\r
+      return UrlParserSchemeColon;\r
+    }\r
+    break;\r
+\r
+  case UrlParserSchemeColon:\r
+    if (Char == '/') {\r
+      return UrlParserSchemeColonSlash;\r
+    }\r
+    break;\r
+\r
+  case UrlParserSchemeColonSlash:\r
+    if (Char == '/') {\r
+      return UrlParserSchemeColonSlashSlash;\r
+    }\r
+    break;\r
+\r
+  case UrlParserAtInAuthority:\r
+    if (Char == '@') {\r
+      return UrlParserStateMax;\r
+    }\r
+\r
+  case UrlParserAuthority:\r
+  case UrlParserSchemeColonSlashSlash:\r
+    if (Char == '@') {\r
+      return UrlParserAtInAuthority;\r
+    }\r
+    if (Char == '/') {\r
+      return UrlParserPath;\r
+    }\r
+    if (Char == '?') {\r
+      return UrlParserQueryStart;\r
+    }\r
+    if (Char == '#') {\r
+      return UrlParserFragmentStart;\r
+    }\r
+    return UrlParserAuthority;\r
+\r
+  case UrlParserPath:\r
+    if (Char == '?') {\r
+      return UrlParserQueryStart;\r
+    }\r
+    if (Char == '#') {\r
+      return UrlParserFragmentStart;\r
+    }\r
+    break;\r
+\r
+  case UrlParserQuery:\r
+  case UrlParserQueryStart:\r
+    if (Char == '#') {\r
+      return UrlParserFragmentStart;\r
+    }\r
+    return UrlParserQuery;\r
+\r
+  case UrlParserFragmentStart:\r
+    return UrlParserFragment;\r
+\r
+  default:\r
+    break;\r
+  }\r
+\r
+  return State;\r
+}\r
+/**\r
+  Create a URL parser for the input URL string.\r
+\r
+  This function will parse and dereference the input HTTP URL into it components. The original\r
+  content of the URL won't be modified and the result will be returned in UrlParser, which can\r
+  be used in other functions like NetHttpUrlGetHostName().\r
+\r
+  @param[in]    Url                The pointer to a HTTP URL string.\r
+  @param[in]    Length             Length of Url in bytes.\r
+  @param[in]    IsConnectMethod    Whether the Url is used in HTTP CONNECT method or not.\r
+  @param[out]   UrlParser          Pointer to the returned buffer to store the parse result.\r
+\r
+  @retval EFI_SUCCESS              Successfully dereferenced the HTTP URL.\r
+  @retval EFI_INVALID_PARAMETER    UrlParser is NULL or Url is not a valid HTTP URL.\r
+  @retval EFI_OUT_OF_RESOURCES     Could not allocate needed resources.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+HttpParseUrl (\r
+  IN      CHAR8              *Url,\r
+  IN      UINT32             Length,\r
+  IN      BOOLEAN            IsConnectMethod,\r
+     OUT  VOID               **UrlParser\r
+  )\r
+{\r
+  HTTP_URL_PARSE_STATE  State;\r
+  CHAR8                 *Char;\r
+  UINT32                Field;\r
+  UINT32                OldField;\r
+  BOOLEAN               FoundAt;\r
+  EFI_STATUS            Status;\r
+  HTTP_URL_PARSER       *Parser;\r
+\r
+  Parser = NULL;\r
+\r
+  if (Url == NULL || Length == 0 || UrlParser == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  Parser = AllocateZeroPool (sizeof (HTTP_URL_PARSER));\r
+  if (Parser == NULL) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  if (IsConnectMethod) {\r
+    //\r
+    // According to RFC 2616, the authority form is only used by the CONNECT method.\r
+    //\r
+    State = UrlParserAuthority;\r
+  } else {\r
+    State = UrlParserUrlStart;\r
+  }\r
+\r
+  Field = HTTP_URI_FIELD_MAX;\r
+  OldField = Field;\r
+  FoundAt = FALSE;\r
+  for (Char = Url; Char < Url + Length; Char++) {\r
+    //\r
+    // Update state machine according to next char.\r
+    //\r
+    State = NetHttpParseUrlChar (*Char, State);\r
+\r
+    switch (State) {\r
+    case UrlParserStateMax:\r
+      FreePool (Parser);\r
+      return EFI_INVALID_PARAMETER;\r
+\r
+    case UrlParserSchemeColon:\r
+    case UrlParserSchemeColonSlash:\r
+    case UrlParserSchemeColonSlashSlash:\r
+    case UrlParserQueryStart:\r
+    case UrlParserFragmentStart:\r
+      //\r
+      // Skip all the delimiting char: "://" "?" "@"\r
+      //\r
+      continue;\r
+\r
+    case UrlParserScheme:\r
+      Field = HTTP_URI_FIELD_SCHEME;\r
+      break;\r
+\r
+    case UrlParserAtInAuthority:\r
+      FoundAt = TRUE;\r
+    case UrlParserAuthority:\r
+      Field = HTTP_URI_FIELD_AUTHORITY;\r
+      break;\r
+\r
+    case UrlParserPath:\r
+      Field = HTTP_URI_FIELD_PATH;\r
+      break;\r
+\r
+    case UrlParserQuery:\r
+      Field = HTTP_URI_FIELD_QUERY;\r
+      break;\r
+\r
+    case UrlParserFragment:\r
+      Field = HTTP_URI_FIELD_FRAGMENT;\r
+      break;\r
+\r
+    default:\r
+      ASSERT (FALSE);\r
+    }\r
+\r
+    //\r
+    // Field not changed, count the length.\r
+    //\r
+    ASSERT (Field < HTTP_URI_FIELD_MAX);\r
+    if (Field == OldField) {\r
+      Parser->FieldData[Field].Length++;\r
+      continue;\r
+    }\r
+\r
+    //\r
+    // New field start\r
+    //\r
+    Parser->FieldBitMap |= BIT (Field);\r
+    Parser->FieldData[Field].Offset = (UINT32) (Char - Url);\r
+    Parser->FieldData[Field].Length = 1;\r
+    OldField = Field;\r
+  }\r
+\r
+  //\r
+  // If has authority component, continue to parse the username, host and port.\r
+  //\r
+  if ((Parser->FieldBitMap & BIT (HTTP_URI_FIELD_AUTHORITY)) != 0) {\r
+    Status = NetHttpParseAuthority (Url, FoundAt, Parser);\r
+    if (EFI_ERROR (Status)) {\r
+      FreePool (Parser);\r
+      return Status;\r
+    }\r
+  }\r
+\r
+  *UrlParser = Parser;\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Get the Hostname from a HTTP URL.\r
+\r
+  This function will return the HostName according to the Url and previous parse result ,and\r
+  it is the caller's responsibility to free the buffer returned in *HostName.\r
+\r
+  @param[in]    Url                The pointer to a HTTP URL string.\r
+  @param[in]    UrlParser          URL Parse result returned by NetHttpParseUrl().\r
+  @param[out]   HostName           Pointer to a buffer to store the HostName.\r
+\r
+  @retval EFI_SUCCESS              Successfully get the required component.\r
+  @retval EFI_INVALID_PARAMETER    Uri is NULL or HostName is NULL or UrlParser is invalid.\r
+  @retval EFI_NOT_FOUND            No hostName component in the URL.\r
+  @retval EFI_OUT_OF_RESOURCES     Could not allocate needed resources.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+HttpUrlGetHostName (\r
+  IN      CHAR8              *Url,\r
+  IN      VOID               *UrlParser,\r
+     OUT  CHAR8              **HostName\r
+  )\r
+{\r
+  CHAR8                *Name;\r
+  EFI_STATUS           Status;\r
+  UINT32               ResultLength;\r
+  HTTP_URL_PARSER      *Parser;\r
+\r
+  if (Url == NULL || UrlParser == NULL || HostName == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  Parser = (HTTP_URL_PARSER *) UrlParser;\r
+\r
+  if ((Parser->FieldBitMap & BIT (HTTP_URI_FIELD_HOST)) == 0) {\r
+    return EFI_NOT_FOUND;\r
+  }\r
+\r
+  Name = AllocatePool (Parser->FieldData[HTTP_URI_FIELD_HOST].Length + 1);\r
+  if (Name == NULL) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  Status = UriPercentDecode (\r
+             Url + Parser->FieldData[HTTP_URI_FIELD_HOST].Offset,\r
+             Parser->FieldData[HTTP_URI_FIELD_HOST].Length,\r
+             Name,\r
+             &ResultLength\r
+             );\r
+  if (EFI_ERROR (Status)) {\r
+    FreePool (Name);\r
+    return Status;\r
+  }\r
+\r
+  Name[ResultLength] = '\0';\r
+  *HostName = Name;\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+  Get the IPv4 address from a HTTP URL.\r
+\r
+  This function will return the IPv4 address according to the Url and previous parse result.\r
+\r
+  @param[in]    Url                The pointer to a HTTP URL string.\r
+  @param[in]    UrlParser          URL Parse result returned by NetHttpParseUrl().\r
+  @param[out]   Ip4Address         Pointer to a buffer to store the IP address.\r
+\r
+  @retval EFI_SUCCESS              Successfully get the required component.\r
+  @retval EFI_INVALID_PARAMETER    Uri is NULL or Ip4Address is NULL or UrlParser is invalid.\r
+  @retval EFI_NOT_FOUND            No IPv4 address component in the URL.\r
+  @retval EFI_OUT_OF_RESOURCES     Could not allocate needed resources.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+HttpUrlGetIp4 (\r
+  IN      CHAR8              *Url,\r
+  IN      VOID               *UrlParser,\r
+     OUT  EFI_IPv4_ADDRESS   *Ip4Address\r
+  )\r
+{\r
+  CHAR8                *Ip4String;\r
+  EFI_STATUS           Status;\r
+  UINT32               ResultLength;\r
+  HTTP_URL_PARSER      *Parser;\r
+\r
+  if (Url == NULL || UrlParser == NULL || Ip4Address == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  Parser = (HTTP_URL_PARSER *) UrlParser;\r
+\r
+  if ((Parser->FieldBitMap & BIT (HTTP_URI_FIELD_HOST)) == 0) {\r
+    return EFI_NOT_FOUND;\r
+  }\r
+\r
+  Ip4String = AllocatePool (Parser->FieldData[HTTP_URI_FIELD_HOST].Length + 1);\r
+  if (Ip4String == NULL) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  Status = UriPercentDecode (\r
+             Url + Parser->FieldData[HTTP_URI_FIELD_HOST].Offset,\r
+             Parser->FieldData[HTTP_URI_FIELD_HOST].Length,\r
+             Ip4String,\r
+             &ResultLength\r
+             );\r
+  if (EFI_ERROR (Status)) {\r
+    FreePool (Ip4String);\r
+    return Status;\r
+  }\r
+\r
+  Ip4String[ResultLength] = '\0';\r
+  Status = NetLibAsciiStrToIp4 (Ip4String, Ip4Address);\r
+  FreePool (Ip4String);\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Get the IPv6 address from a HTTP URL.\r
+\r
+  This function will return the IPv6 address according to the Url and previous parse result.\r
+\r
+  @param[in]    Url                The pointer to a HTTP URL string.\r
+  @param[in]    UrlParser          URL Parse result returned by NetHttpParseUrl().\r
+  @param[out]   Ip6Address         Pointer to a buffer to store the IP address.\r
+\r
+  @retval EFI_SUCCESS              Successfully get the required component.\r
+  @retval EFI_INVALID_PARAMETER    Uri is NULL or Ip6Address is NULL or UrlParser is invalid.\r
+  @retval EFI_NOT_FOUND            No IPv6 address component in the URL.\r
+  @retval EFI_OUT_OF_RESOURCES     Could not allocate needed resources.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+HttpUrlGetIp6 (\r
+  IN      CHAR8              *Url,\r
+  IN      VOID               *UrlParser,\r
+     OUT  EFI_IPv6_ADDRESS   *Ip6Address\r
+  )\r
+{\r
+  CHAR8                *Ip6String;\r
+  CHAR8                *Ptr;\r
+  UINT32               Length;\r
+  EFI_STATUS           Status;\r
+  UINT32               ResultLength;\r
+  HTTP_URL_PARSER      *Parser;\r
+\r
+  if (Url == NULL || UrlParser == NULL || Ip6Address == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  Parser = (HTTP_URL_PARSER *) UrlParser;\r
+\r
+  if ((Parser->FieldBitMap & BIT (HTTP_URI_FIELD_HOST)) == 0) {\r
+    return EFI_NOT_FOUND;\r
+  }\r
+\r
+  //\r
+  // IP-literal = "[" ( IPv6address / IPvFuture  ) "]"\r
+  //\r
+  Length = Parser->FieldData[HTTP_URI_FIELD_HOST].Length;\r
+  if (Length < 2) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  Ptr    = Url + Parser->FieldData[HTTP_URI_FIELD_HOST].Offset;\r
+  if ((Ptr[0] != '[') || (Ptr[Length - 1] != ']')) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  Ip6String = AllocatePool (Length);\r
+  if (Ip6String == NULL) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  Status = UriPercentDecode (\r
+             Ptr + 1,\r
+             Length - 2,\r
+             Ip6String,\r
+             &ResultLength\r
+             );\r
+  if (EFI_ERROR (Status)) {\r
+    FreePool (Ip6String);\r
+    return Status;\r
+  }\r
+\r
+  Ip6String[ResultLength] = '\0';\r
+  Status = NetLibAsciiStrToIp6 (Ip6String, Ip6Address);\r
+  FreePool (Ip6String);\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Get the port number from a HTTP URL.\r
+\r
+  This function will return the port number according to the Url and previous parse result.\r
+\r
+  @param[in]    Url                The pointer to a HTTP URL string.\r
+  @param[in]    UrlParser          URL Parse result returned by NetHttpParseUrl().\r
+  @param[out]   Port               Pointer to a buffer to store the port number.\r
+\r
+  @retval EFI_SUCCESS              Successfully get the required component.\r
+  @retval EFI_INVALID_PARAMETER    Uri is NULL or Port is NULL or UrlParser is invalid.\r
+  @retval EFI_NOT_FOUND            No port number in the URL.\r
+  @retval EFI_OUT_OF_RESOURCES     Could not allocate needed resources.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+HttpUrlGetPort (\r
+  IN      CHAR8              *Url,\r
+  IN      VOID               *UrlParser,\r
+     OUT  UINT16             *Port\r
+  )\r
+{\r
+  CHAR8                *PortString;\r
+  EFI_STATUS           Status;\r
+  UINTN                Index;\r
+  UINTN                Data;\r
+  UINT32               ResultLength;\r
+  HTTP_URL_PARSER      *Parser;\r
+\r
+  if (Url == NULL || UrlParser == NULL || Port == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  *Port = 0;\r
+  Index = 0;\r
+\r
+  Parser = (HTTP_URL_PARSER *) UrlParser;\r
+\r
+  if ((Parser->FieldBitMap & BIT (HTTP_URI_FIELD_PORT)) == 0) {\r
+    return EFI_NOT_FOUND;\r
+  }\r
+\r
+  PortString = AllocatePool (Parser->FieldData[HTTP_URI_FIELD_PORT].Length + 1);\r
+  if (PortString == NULL) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  Status = UriPercentDecode (\r
+             Url + Parser->FieldData[HTTP_URI_FIELD_PORT].Offset,\r
+             Parser->FieldData[HTTP_URI_FIELD_PORT].Length,\r
+             PortString,\r
+             &ResultLength\r
+             );\r
+  if (EFI_ERROR (Status)) {\r
+    goto ON_EXIT;\r
+  }\r
+\r
+  PortString[ResultLength] = '\0';\r
+\r
+  while (Index < ResultLength) {\r
+    if (!NET_IS_DIGIT (PortString[Index])) {\r
+      Status = EFI_INVALID_PARAMETER;\r
+      goto ON_EXIT;\r
+    }\r
+    Index ++;\r
+  }\r
+\r
+  Status =  AsciiStrDecimalToUintnS (Url + Parser->FieldData[HTTP_URI_FIELD_PORT].Offset, (CHAR8 **) NULL, &Data);\r
+\r
+  if (Data > HTTP_URI_PORT_MAX_NUM) {\r
+    Status = EFI_INVALID_PARAMETER;\r
+    goto ON_EXIT;\r
+  }\r
+\r
+  *Port = (UINT16) Data;\r
+\r
+ON_EXIT:\r
+  FreePool (PortString);\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Get the Path from a HTTP URL.\r
+\r
+  This function will return the Path according to the Url and previous parse result,and\r
+  it is the caller's responsibility to free the buffer returned in *Path.\r
+\r
+  @param[in]    Url                The pointer to a HTTP URL string.\r
+  @param[in]    UrlParser          URL Parse result returned by NetHttpParseUrl().\r
+  @param[out]   Path               Pointer to a buffer to store the Path.\r
+\r
+  @retval EFI_SUCCESS              Successfully get the required component.\r
+  @retval EFI_INVALID_PARAMETER    Uri is NULL or HostName is NULL or UrlParser is invalid.\r
+  @retval EFI_NOT_FOUND            No hostName component in the URL.\r
+  @retval EFI_OUT_OF_RESOURCES     Could not allocate needed resources.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+HttpUrlGetPath (\r
+  IN      CHAR8              *Url,\r
+  IN      VOID               *UrlParser,\r
+     OUT  CHAR8              **Path\r
+  )\r
+{\r
+  CHAR8                *PathStr;\r
+  EFI_STATUS           Status;\r
+  UINT32               ResultLength;\r
+  HTTP_URL_PARSER      *Parser;\r
+\r
+  if (Url == NULL || UrlParser == NULL || Path == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  Parser = (HTTP_URL_PARSER *) UrlParser;\r
+\r
+  if ((Parser->FieldBitMap & BIT (HTTP_URI_FIELD_PATH)) == 0) {\r
+    return EFI_NOT_FOUND;\r
+  }\r
+\r
+  PathStr = AllocatePool (Parser->FieldData[HTTP_URI_FIELD_PATH].Length + 1);\r
+  if (PathStr == NULL) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  Status = UriPercentDecode (\r
+             Url + Parser->FieldData[HTTP_URI_FIELD_PATH].Offset,\r
+             Parser->FieldData[HTTP_URI_FIELD_PATH].Length,\r
+             PathStr,\r
+             &ResultLength\r
+             );\r
+  if (EFI_ERROR (Status)) {\r
+    FreePool (PathStr);\r
+    return Status;\r
+  }\r
+\r
+  PathStr[ResultLength] = '\0';\r
+  *Path = PathStr;\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Release the resource of the URL parser.\r
+\r
+  @param[in]    UrlParser            Pointer to the parser.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+HttpUrlFreeParser (\r
+  IN      VOID               *UrlParser\r
+  )\r
+{\r
+  FreePool (UrlParser);\r
+}\r
+\r
+/**\r
+  Find a specified header field according to the field name.\r
+\r
+  @param[in]   HeaderCount      Number of HTTP header structures in Headers list.\r
+  @param[in]   Headers          Array containing list of HTTP headers.\r
+  @param[in]   FieldName        Null terminated string which describes a field name.\r
+\r
+  @return    Pointer to the found header or NULL.\r
+\r
+**/\r
+EFI_HTTP_HEADER *\r
+EFIAPI\r
+HttpFindHeader (\r
+  IN  UINTN                HeaderCount,\r
+  IN  EFI_HTTP_HEADER      *Headers,\r
+  IN  CHAR8                *FieldName\r
+  )\r
+{\r
+  UINTN                 Index;\r
+\r
+  if (HeaderCount == 0 || Headers == NULL || FieldName == NULL) {\r
+    return NULL;\r
+  }\r
+\r
+  for (Index = 0; Index < HeaderCount; Index++){\r
+    //\r
+    // Field names are case-insensitive (RFC 2616).\r
+    //\r
+    if (AsciiStriCmp (Headers[Index].FieldName, FieldName) == 0) {\r
+      return &Headers[Index];\r
+    }\r
+  }\r
+  return NULL;\r
+}\r
+\r
+typedef enum {\r
+  BodyParserBodyStart,\r
+  BodyParserBodyIdentity,\r
+  BodyParserChunkSizeStart,\r
+  BodyParserChunkSize,\r
+  BodyParserChunkSizeEndCR,\r
+  BodyParserChunkExtStart,\r
+  BodyParserChunkDataStart,\r
+  BodyParserChunkDataEnd,\r
+  BodyParserChunkDataEndCR,\r
+  BodyParserTrailer,\r
+  BodyParserLastCRLF,\r
+  BodyParserLastCRLFEnd,\r
+  BodyParserComplete,\r
+  BodyParserStateMax\r
+} HTTP_BODY_PARSE_STATE;\r
+\r
+typedef struct {\r
+  BOOLEAN                       IgnoreBody;    // "MUST NOT" include a message-body\r
+  BOOLEAN                       IsChunked;     // "chunked" transfer-coding.\r
+  BOOLEAN                       ContentLengthIsValid;\r
+  UINTN                         ContentLength; // Entity length (not the message-body length), invalid until ContentLengthIsValid is TRUE\r
+\r
+  HTTP_BODY_PARSER_CALLBACK     Callback;\r
+  VOID                          *Context;\r
+  UINTN                         ParsedBodyLength;\r
+  HTTP_BODY_PARSE_STATE         State;\r
+  UINTN                         CurrentChunkSize;\r
+  UINTN                         CurrentChunkParsedSize;\r
+} HTTP_BODY_PARSER;\r
+\r
+/**\r
+  Convert an hexadecimal char to a value of type UINTN.\r
+\r
+  @param[in]       Char           Ascii character.\r
+\r
+  @return          Value translated from Char.\r
+\r
+**/\r
+UINTN\r
+HttpIoHexCharToUintn (\r
+  IN CHAR8           Char\r
+  )\r
+{\r
+  if (Char >= '0' && Char <= '9') {\r
+    return Char - '0';\r
+  }\r
+\r
+  return (10 + AsciiCharToUpper (Char) - 'A');\r
+}\r
+\r
+/**\r
+  Get the value of the content length if there is a "Content-Length" header.\r
+\r
+  @param[in]    HeaderCount        Number of HTTP header structures in Headers.\r
+  @param[in]    Headers            Array containing list of HTTP headers.\r
+  @param[out]   ContentLength      Pointer to save the value of the content length.\r
+\r
+  @retval EFI_SUCCESS              Successfully get the content length.\r
+  @retval EFI_NOT_FOUND            No "Content-Length" header in the Headers.\r
+\r
+**/\r
+EFI_STATUS\r
+HttpIoParseContentLengthHeader (\r
+  IN     UINTN                HeaderCount,\r
+  IN     EFI_HTTP_HEADER      *Headers,\r
+     OUT UINTN                *ContentLength\r
+  )\r
+{\r
+  EFI_HTTP_HEADER       *Header;\r
+\r
+  Header = HttpFindHeader (HeaderCount, Headers, HTTP_HEADER_CONTENT_LENGTH);\r
+  if (Header == NULL) {\r
+    return EFI_NOT_FOUND;\r
+  }\r
+\r
+  return AsciiStrDecimalToUintnS (Header->FieldValue, (CHAR8 **) NULL, ContentLength);\r
+}\r
+\r
+/**\r
+\r
+  Check whether the HTTP message is using the "chunked" transfer-coding.\r
+\r
+  @param[in]    HeaderCount        Number of HTTP header structures in Headers.\r
+  @param[in]    Headers            Array containing list of HTTP headers.\r
+\r
+  @return       The message is "chunked" transfer-coding (TRUE) or not (FALSE).\r
+\r
+**/\r
+BOOLEAN\r
+HttpIoIsChunked (\r
+  IN   UINTN                    HeaderCount,\r
+  IN   EFI_HTTP_HEADER          *Headers\r
+  )\r
+{\r
+  EFI_HTTP_HEADER       *Header;\r
+\r
+\r
+  Header = HttpFindHeader (HeaderCount, Headers, HTTP_HEADER_TRANSFER_ENCODING);\r
+  if (Header == NULL) {\r
+    return FALSE;\r
+  }\r
+\r
+  if (AsciiStriCmp (Header->FieldValue, "identity") != 0) {\r
+    return TRUE;\r
+  }\r
+\r
+  return FALSE;\r
+}\r
+\r
+/**\r
+  Check whether the HTTP message should have a message-body.\r
+\r
+  @param[in]    Method             The HTTP method (e.g. GET, POST) for this HTTP message.\r
+  @param[in]    StatusCode         Response status code returned by the remote host.\r
+\r
+  @return       The message should have a message-body (FALSE) or not (TRUE).\r
+\r
+**/\r
+BOOLEAN\r
+HttpIoNoMessageBody (\r
+  IN   EFI_HTTP_METHOD          Method,\r
+  IN   EFI_HTTP_STATUS_CODE     StatusCode\r
+  )\r
+{\r
+  //\r
+  // RFC 2616:\r
+  // All responses to the HEAD request method\r
+  // MUST NOT include a message-body, even though the presence of entity-\r
+  // header fields might lead one to believe they do. All 1xx\r
+  // (informational), 204 (no content), and 304 (not modified) responses\r
+  // MUST NOT include a message-body. All other responses do include a\r
+  // message-body, although it MAY be of zero length.\r
+  //\r
+  if (Method == HttpMethodHead) {\r
+    return TRUE;\r
+  }\r
+\r
+  if ((StatusCode == HTTP_STATUS_100_CONTINUE) ||\r
+      (StatusCode == HTTP_STATUS_101_SWITCHING_PROTOCOLS) ||\r
+      (StatusCode == HTTP_STATUS_204_NO_CONTENT) ||\r
+      (StatusCode == HTTP_STATUS_304_NOT_MODIFIED))\r
+  {\r
+    return TRUE;\r
+  }\r
+\r
+  return FALSE;\r
+}\r
+\r
+/**\r
+  Initialize a HTTP message-body parser.\r
+\r
+  This function will create and initialize a HTTP message parser according to caller provided HTTP message\r
+  header information. It is the caller's responsibility to free the buffer returned in *UrlParser by HttpFreeMsgParser().\r
+\r
+  @param[in]    Method             The HTTP method (e.g. GET, POST) for this HTTP message.\r
+  @param[in]    StatusCode         Response status code returned by the remote host.\r
+  @param[in]    HeaderCount        Number of HTTP header structures in Headers.\r
+  @param[in]    Headers            Array containing list of HTTP headers.\r
+  @param[in]    Callback           Callback function that is invoked when parsing the HTTP message-body,\r
+                                   set to NULL to ignore all events.\r
+  @param[in]    Context            Pointer to the context that will be passed to Callback.\r
+  @param[out]   MsgParser          Pointer to the returned buffer to store the message parser.\r
+\r
+  @retval EFI_SUCCESS              Successfully initialized the parser.\r
+  @retval EFI_OUT_OF_RESOURCES     Could not allocate needed resources.\r
+  @retval EFI_INVALID_PARAMETER    MsgParser is NULL or HeaderCount is not NULL but Headers is NULL.\r
+  @retval Others                   Failed to initialize the parser.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+HttpInitMsgParser (\r
+  IN     EFI_HTTP_METHOD               Method,\r
+  IN     EFI_HTTP_STATUS_CODE          StatusCode,\r
+  IN     UINTN                         HeaderCount,\r
+  IN     EFI_HTTP_HEADER               *Headers,\r
+  IN     HTTP_BODY_PARSER_CALLBACK     Callback,\r
+  IN     VOID                          *Context,\r
+    OUT  VOID                          **MsgParser\r
+  )\r
+{\r
+  EFI_STATUS            Status;\r
+  HTTP_BODY_PARSER      *Parser;\r
+\r
+  if (HeaderCount != 0 && Headers == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if (MsgParser == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  Parser = AllocateZeroPool (sizeof (HTTP_BODY_PARSER));\r
+  if (Parser == NULL) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  Parser->State = BodyParserBodyStart;\r
+\r
+  //\r
+  // Determine the message length according to RFC 2616.\r
+  // 1. Check whether the message "MUST NOT" have a message-body.\r
+  //\r
+  Parser->IgnoreBody = HttpIoNoMessageBody (Method, StatusCode);\r
+  //\r
+  // 2. Check whether the message using "chunked" transfer-coding.\r
+  //\r
+  Parser->IsChunked  = HttpIoIsChunked (HeaderCount, Headers);\r
+  //\r
+  // 3. Check whether the message has a Content-Length header field.\r
+  //\r
+  Status = HttpIoParseContentLengthHeader (HeaderCount, Headers, &Parser->ContentLength);\r
+  if (!EFI_ERROR (Status)) {\r
+    Parser->ContentLengthIsValid = TRUE;\r
+  }\r
+  //\r
+  // 4. Range header is not supported now, so we won't meet media type "multipart/byteranges".\r
+  // 5. By server closing the connection\r
+  //\r
+\r
+  //\r
+  // Set state to skip body parser if the message shouldn't have a message body.\r
+  //\r
+  if (Parser->IgnoreBody) {\r
+    Parser->State = BodyParserComplete;\r
+  } else {\r
+    Parser->Callback = Callback;\r
+    Parser->Context  = Context;\r
+  }\r
+\r
+  *MsgParser = Parser;\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Parse message body.\r
+\r
+  Parse BodyLength of message-body. This function can be called repeatedly to parse the message-body partially.\r
+\r
+  @param[in, out]    MsgParser            Pointer to the message parser.\r
+  @param[in]         BodyLength           Length in bytes of the Body.\r
+  @param[in]         Body                 Pointer to the buffer of the message-body to be parsed.\r
+\r
+  @retval EFI_SUCCESS                Successfully parse the message-body.\r
+  @retval EFI_INVALID_PARAMETER      MsgParser is NULL or Body is NULL or BodyLength is 0.\r
+  @retval EFI_ABORTED                Operation aborted.\r
+  @retval Other                      Error happened while parsing message body.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+HttpParseMessageBody (\r
+  IN OUT VOID              *MsgParser,\r
+  IN     UINTN             BodyLength,\r
+  IN     CHAR8             *Body\r
+  )\r
+{\r
+  CHAR8                 *Char;\r
+  UINTN                 RemainderLengthInThis;\r
+  UINTN                 LengthForCallback;\r
+  EFI_STATUS            Status;\r
+  HTTP_BODY_PARSER      *Parser;\r
+\r
+  if (BodyLength == 0 || Body == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if (MsgParser == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  Parser = (HTTP_BODY_PARSER *) MsgParser;\r
+\r
+  if (Parser->IgnoreBody) {\r
+    Parser->State = BodyParserComplete;\r
+    if (Parser->Callback != NULL) {\r
+      Status = Parser->Callback (\r
+                         BodyParseEventOnComplete,\r
+                         Body,\r
+                         0,\r
+                         Parser->Context\r
+                         );\r
+      if (EFI_ERROR (Status)) {\r
+        return Status;\r
+      }\r
+    }\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  if (Parser->State == BodyParserBodyStart) {\r
+    Parser->ParsedBodyLength = 0;\r
+    if (Parser->IsChunked) {\r
+      Parser->State = BodyParserChunkSizeStart;\r
+    } else {\r
+      Parser->State = BodyParserBodyIdentity;\r
+    }\r
+  }\r
+\r
+  //\r
+  // The message body might be truncated in anywhere, so we need to parse is byte-by-byte.\r
+  //\r
+  for (Char = Body; Char < Body + BodyLength; ) {\r
+\r
+    switch (Parser->State) {\r
+    case BodyParserStateMax:\r
+      return EFI_ABORTED;\r
+\r
+    case BodyParserBodyIdentity:\r
+      //\r
+      // Identity transfer-coding, just notify user to save the body data.\r
+      //\r
+      if (Parser->Callback != NULL) {\r
+        Status = Parser->Callback (\r
+                           BodyParseEventOnData,\r
+                           Char,\r
+                           MIN (BodyLength, Parser->ContentLength - Parser->ParsedBodyLength),\r
+                           Parser->Context\r
+                           );\r
+        if (EFI_ERROR (Status)) {\r
+          return Status;\r
+        }\r
+      }\r
+      Char += MIN (BodyLength, Parser->ContentLength - Parser->ParsedBodyLength);\r
+      Parser->ParsedBodyLength += MIN (BodyLength, Parser->ContentLength - Parser->ParsedBodyLength);\r
+      if (Parser->ParsedBodyLength == Parser->ContentLength) {\r
+        Parser->State = BodyParserComplete;\r
+        if (Parser->Callback != NULL) {\r
+          Status = Parser->Callback (\r
+                             BodyParseEventOnComplete,\r
+                             Char,\r
+                             0,\r
+                             Parser->Context\r
+                             );\r
+          if (EFI_ERROR (Status)) {\r
+            return Status;\r
+          }\r
+        }\r
+      }\r
+      break;\r
+\r
+    case BodyParserChunkSizeStart:\r
+      //\r
+      // First byte of chunk-size, the chunk-size might be truncated.\r
+      //\r
+      Parser->CurrentChunkSize = 0;\r
+      Parser->State = BodyParserChunkSize;\r
+    case BodyParserChunkSize:\r
+      if (!NET_IS_HEX_CHAR (*Char)) {\r
+        if (*Char == ';') {\r
+          Parser->State = BodyParserChunkExtStart;\r
+          Char++;\r
+        } else if (*Char == '\r') {\r
+          Parser->State = BodyParserChunkSizeEndCR;\r
+          Char++;\r
+        } else {\r
+          Parser->State = BodyParserStateMax;\r
+        }\r
+        break;\r
+      }\r
+\r
+      if (Parser->CurrentChunkSize > (((~((UINTN) 0)) - 16) / 16)) {\r
+        return EFI_INVALID_PARAMETER;\r
+      }\r
+      Parser->CurrentChunkSize = Parser->CurrentChunkSize * 16 + HttpIoHexCharToUintn (*Char);\r
+      Char++;\r
+      break;\r
+\r
+    case BodyParserChunkExtStart:\r
+      //\r
+      // Ignore all the chunk extensions.\r
+      //\r
+      if (*Char == '\r') {\r
+        Parser->State = BodyParserChunkSizeEndCR;\r
+       }\r
+      Char++;\r
+      break;\r
+\r
+    case BodyParserChunkSizeEndCR:\r
+      if (*Char != '\n') {\r
+        Parser->State = BodyParserStateMax;\r
+        break;\r
+      }\r
+      Char++;\r
+      if (Parser->CurrentChunkSize == 0) {\r
+        //\r
+        // The last chunk has been parsed and now assumed the state\r
+        // of HttpBodyParse is ParserLastCRLF. So it need to decide\r
+        // whether the rest message is trailer or last CRLF in the next round.\r
+        //\r
+        Parser->ContentLengthIsValid = TRUE;\r
+        Parser->State = BodyParserLastCRLF;\r
+        break;\r
+      }\r
+      Parser->State = BodyParserChunkDataStart;\r
+      Parser->CurrentChunkParsedSize = 0;\r
+      break;\r
+\r
+    case BodyParserLastCRLF:\r
+      //\r
+      // Judge the byte is belong to the Last CRLF or trailer, and then\r
+      // configure the state of HttpBodyParse to corresponding state.\r
+      //\r
+      if (*Char == '\r') {\r
+        Char++;\r
+        Parser->State = BodyParserLastCRLFEnd;\r
+        break;\r
+      } else {\r
+        Parser->State = BodyParserTrailer;\r
+        break;\r
+      }\r
+\r
+    case BodyParserLastCRLFEnd:\r
+      if (*Char == '\n') {\r
+        Parser->State = BodyParserComplete;\r
+        Char++;\r
+        if (Parser->Callback != NULL) {\r
+          Status = Parser->Callback (\r
+                             BodyParseEventOnComplete,\r
+                             Char,\r
+                             0,\r
+                             Parser->Context\r
+                             );\r
+          if (EFI_ERROR (Status)) {\r
+            return Status;\r
+          }\r
+        }\r
+        break;\r
+      } else {\r
+        Parser->State = BodyParserStateMax;\r
+        break;\r
+      }\r
+\r
+    case BodyParserTrailer:\r
+      if (*Char == '\r') {\r
+        Parser->State = BodyParserChunkSizeEndCR;\r
+      }\r
+      Char++;\r
+      break;\r
+\r
+    case BodyParserChunkDataStart:\r
+      //\r
+      // First byte of chunk-data, the chunk data also might be truncated.\r
+      //\r
+      RemainderLengthInThis = BodyLength - (Char - Body);\r
+      LengthForCallback = MIN (Parser->CurrentChunkSize - Parser->CurrentChunkParsedSize, RemainderLengthInThis);\r
+      if (Parser->Callback != NULL) {\r
+        Status = Parser->Callback (\r
+                           BodyParseEventOnData,\r
+                           Char,\r
+                           LengthForCallback,\r
+                           Parser->Context\r
+                           );\r
+        if (EFI_ERROR (Status)) {\r
+          return Status;\r
+        }\r
+      }\r
+      Char += LengthForCallback;\r
+      Parser->ContentLength += LengthForCallback;\r
+      Parser->CurrentChunkParsedSize += LengthForCallback;\r
+      if (Parser->CurrentChunkParsedSize == Parser->CurrentChunkSize) {\r
+        Parser->State = BodyParserChunkDataEnd;\r
+      }\r
+      break;\r
+\r
+    case BodyParserChunkDataEnd:\r
+      if (*Char == '\r') {\r
+        Parser->State = BodyParserChunkDataEndCR;\r
+      } else {\r
+        Parser->State = BodyParserStateMax;\r
+      }\r
+      Char++;\r
+      break;\r
+\r
+    case BodyParserChunkDataEndCR:\r
+      if (*Char != '\n') {\r
+        Parser->State = BodyParserStateMax;\r
+        break;\r
+      }\r
+      Char++;\r
+      Parser->State = BodyParserChunkSizeStart;\r
+      break;\r
+\r
+    default:\r
+      break;\r
+    }\r
+\r
+  }\r
+\r
+  if (Parser->State == BodyParserStateMax) {\r
+    return EFI_ABORTED;\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Check whether the message-body is complete or not.\r
+\r
+  @param[in]    MsgParser            Pointer to the message parser.\r
+\r
+  @retval TRUE                       Message-body is complete.\r
+  @retval FALSE                      Message-body is not complete.\r
+\r
+**/\r
+BOOLEAN\r
+EFIAPI\r
+HttpIsMessageComplete (\r
+  IN VOID              *MsgParser\r
+  )\r
+{\r
+  HTTP_BODY_PARSER      *Parser;\r
+\r
+  if (MsgParser == NULL) {\r
+    return FALSE;\r
+  }\r
+\r
+  Parser = (HTTP_BODY_PARSER *) MsgParser;\r
+\r
+  if (Parser->State == BodyParserComplete) {\r
+    return TRUE;\r
+  }\r
+  return FALSE;\r
+}\r
+\r
+/**\r
+  Get the content length of the entity.\r
+\r
+  Note that in trunk transfer, the entity length is not valid until the whole message body is received.\r
+\r
+  @param[in]    MsgParser            Pointer to the message parser.\r
+  @param[out]   ContentLength        Pointer to store the length of the entity.\r
+\r
+  @retval EFI_SUCCESS                Successfully to get the entity length.\r
+  @retval EFI_NOT_READY              Entity length is not valid yet.\r
+  @retval EFI_INVALID_PARAMETER      MsgParser is NULL or ContentLength is NULL.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+HttpGetEntityLength (\r
+  IN  VOID              *MsgParser,\r
+  OUT UINTN             *ContentLength\r
+  )\r
+{\r
+  HTTP_BODY_PARSER      *Parser;\r
+\r
+  if (MsgParser == NULL || ContentLength == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  Parser = (HTTP_BODY_PARSER *) MsgParser;\r
+\r
+  if (!Parser->ContentLengthIsValid) {\r
+    return EFI_NOT_READY;\r
+  }\r
+\r
+  *ContentLength = Parser->ContentLength;\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Release the resource of the message parser.\r
+\r
+  @param[in]    MsgParser            Pointer to the message parser.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+HttpFreeMsgParser (\r
+  IN  VOID           *MsgParser\r
+  )\r
+{\r
+  FreePool (MsgParser);\r
+}\r
+\r
+\r
+/**\r
+  Get the next string, which is distinguished by specified separator.\r
+\r
+  @param[in]  String             Pointer to the string.\r
+  @param[in]  Separator          Specified separator used to distinguish where is the beginning\r
+                                 of next string.\r
+\r
+  @return     Pointer to the next string.\r
+  @return     NULL if not find or String is NULL.\r
+\r
+**/\r
+CHAR8 *\r
+AsciiStrGetNextToken (\r
+  IN CONST CHAR8 *String,\r
+  IN       CHAR8 Separator\r
+  )\r
+{\r
+  CONST CHAR8 *Token;\r
+\r
+  Token = String;\r
+  while (TRUE) {\r
+    if (*Token == 0) {\r
+      return NULL;\r
+    }\r
+    if (*Token == Separator) {\r
+      return (CHAR8 *)(Token + 1);\r
+    }\r
+    Token++;\r
+  }\r
+}\r
+\r
+/**\r
+  Set FieldName and FieldValue into specified HttpHeader.\r
+\r
+  @param[in,out]  HttpHeader      Specified HttpHeader.\r
+  @param[in]  FieldName           FieldName of this HttpHeader, a NULL terminated ASCII string.\r
+  @param[in]  FieldValue          FieldValue of this HttpHeader, a NULL terminated ASCII string.\r
+\r
+\r
+  @retval EFI_SUCCESS             The FieldName and FieldValue are set into HttpHeader successfully.\r
+  @retval EFI_INVALID_PARAMETER   The parameter is invalid.\r
+  @retval EFI_OUT_OF_RESOURCES    Failed to allocate resources.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+HttpSetFieldNameAndValue (\r
+  IN  OUT   EFI_HTTP_HEADER       *HttpHeader,\r
+  IN  CONST CHAR8                 *FieldName,\r
+  IN  CONST CHAR8                 *FieldValue\r
+  )\r
+{\r
+  UINTN                       FieldNameSize;\r
+  UINTN                       FieldValueSize;\r
+\r
+  if (HttpHeader == NULL || FieldName == NULL || FieldValue == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if (HttpHeader->FieldName != NULL) {\r
+    FreePool (HttpHeader->FieldName);\r
+  }\r
+  if (HttpHeader->FieldValue != NULL) {\r
+    FreePool (HttpHeader->FieldValue);\r
+  }\r
+\r
+  FieldNameSize = AsciiStrSize (FieldName);\r
+  HttpHeader->FieldName = AllocateZeroPool (FieldNameSize);\r
+  if (HttpHeader->FieldName == NULL) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+  CopyMem (HttpHeader->FieldName, FieldName, FieldNameSize);\r
+  HttpHeader->FieldName[FieldNameSize - 1] = 0;\r
+\r
+  FieldValueSize = AsciiStrSize (FieldValue);\r
+  HttpHeader->FieldValue = AllocateZeroPool (FieldValueSize);\r
+  if (HttpHeader->FieldValue == NULL) {\r
+    FreePool (HttpHeader->FieldName);\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+  CopyMem (HttpHeader->FieldValue, FieldValue, FieldValueSize);\r
+  HttpHeader->FieldValue[FieldValueSize - 1] = 0;\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Get one key/value header pair from the raw string.\r
+\r
+  @param[in]  String             Pointer to the raw string.\r
+  @param[out] FieldName          Points directly to field name within 'HttpHeader'.\r
+  @param[out] FieldValue         Points directly to field value within 'HttpHeader'.\r
+\r
+  @return     Pointer to the next raw string.\r
+  @return     NULL if no key/value header pair from this raw string.\r
+\r
+**/\r
+CHAR8 *\r
+EFIAPI\r
+HttpGetFieldNameAndValue (\r
+  IN     CHAR8   *String,\r
+     OUT CHAR8   **FieldName,\r
+     OUT CHAR8   **FieldValue\r
+  )\r
+{\r
+  CHAR8  *FieldNameStr;\r
+  CHAR8  *FieldValueStr;\r
+  CHAR8  *StrPtr;\r
+  CHAR8  *EndofHeader;\r
+\r
+  if (String == NULL || FieldName == NULL || FieldValue == NULL) {\r
+    return NULL;\r
+  }\r
+\r
+  *FieldName    = NULL;\r
+  *FieldValue   = NULL;\r
+  FieldNameStr  = NULL;\r
+  FieldValueStr = NULL;\r
+  StrPtr        = NULL;\r
+  EndofHeader   = NULL;\r
+\r
+\r
+  //\r
+  // Check whether the raw HTTP header string is valid or not.\r
+  //\r
+  EndofHeader = AsciiStrStr (String, "\r\n\r\n");\r
+  if (EndofHeader == NULL) {\r
+    return NULL;\r
+  }\r
+\r
+  //\r
+  // Each header field consists of a name followed by a colon (":") and the field value.\r
+  // The field value MAY be preceded by any amount of LWS, though a single SP is preferred.\r
+  //\r
+  // message-header = field-name ":" [ field-value ]\r
+  // field-name = token\r
+  // field-value = *( field-content | LWS )\r
+  //\r
+  // Note: "*(element)" allows any number element, including zero; "1*(element)" requires at least one element.\r
+  //       [element] means element is optional.\r
+  //       LWS  = [CRLF] 1*(SP|HT), it can be ' ' or '\t' or '\r\n ' or '\r\n\t'.\r
+  //       CRLF = '\r\n'.\r
+  //       SP   = ' '.\r
+  //       HT   = '\t' (Tab).\r
+  //\r
+  FieldNameStr = String;\r
+  FieldValueStr = AsciiStrGetNextToken (FieldNameStr, ':');\r
+  if (FieldValueStr == NULL) {\r
+    return NULL;\r
+  }\r
+\r
+  //\r
+  // Replace ':' with 0, then FieldName has been retrived from String.\r
+  //\r
+  *(FieldValueStr - 1) = 0;\r
+\r
+  //\r
+  // Handle FieldValueStr, skip all the preceded LWS.\r
+  //\r
+  while (TRUE) {\r
+    if (*FieldValueStr == ' ' || *FieldValueStr == '\t') {\r
+      //\r
+      // Boundary condition check.\r
+      //\r
+      if ((UINTN) EndofHeader - (UINTN) FieldValueStr < 1) {\r
+        //\r
+        // Wrong String format!\r
+        //\r
+        return NULL;\r
+      }\r
+\r
+      FieldValueStr ++;\r
+    } else if (*FieldValueStr == '\r') {\r
+      //\r
+      // Boundary condition check.\r
+      //\r
+      if ((UINTN) EndofHeader - (UINTN) FieldValueStr < 3) {\r
+        //\r
+        // No more preceded LWS, so break here.\r
+        //\r
+        break;\r
+      }\r
+\r
+      if (*(FieldValueStr + 1) == '\n' ) {\r
+        if (*(FieldValueStr + 2) == ' ' || *(FieldValueStr + 2) == '\t') {\r
+          FieldValueStr = FieldValueStr + 3;\r
+        } else {\r
+          //\r
+          // No more preceded LWS, so break here.\r
+          //\r
+          break;\r
+        }\r
+      } else {\r
+        //\r
+        // Wrong String format!\r
+        //\r
+        return NULL;\r
+      }\r
+    } else {\r
+      //\r
+      // No more preceded LWS, so break here.\r
+      //\r
+      break;\r
+    }\r
+  }\r
+\r
+  StrPtr = FieldValueStr;\r
+  do {\r
+    //\r
+    // Handle the LWS within the field value.\r
+    //\r
+    StrPtr = AsciiStrGetNextToken (StrPtr, '\r');\r
+    if (StrPtr == NULL || *StrPtr != '\n') {\r
+      //\r
+      // Wrong String format!\r
+      //\r
+      return NULL;\r
+    }\r
+\r
+    StrPtr++;\r
+  } while (*StrPtr == ' ' || *StrPtr == '\t');\r
+\r
+  //\r
+  // Replace '\r' with 0\r
+  //\r
+  *(StrPtr - 2) = 0;\r
+\r
+  //\r
+  // Get FieldName and FieldValue.\r
+  //\r
+  *FieldName = FieldNameStr;\r
+  *FieldValue = FieldValueStr;\r
+\r
+  return StrPtr;\r
+}\r
+\r
+/**\r
+  Free existing HeaderFields.\r
+\r
+  @param[in]  HeaderFields       Pointer to array of key/value header pairs waitting for free.\r
+  @param[in]  FieldCount         The number of header pairs in HeaderFields.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+HttpFreeHeaderFields (\r
+  IN  EFI_HTTP_HEADER  *HeaderFields,\r
+  IN  UINTN            FieldCount\r
+  )\r
+{\r
+  UINTN                       Index;\r
+\r
+  if (HeaderFields != NULL) {\r
+    for (Index = 0; Index < FieldCount; Index++) {\r
+      if (HeaderFields[Index].FieldName != NULL) {\r
+        FreePool (HeaderFields[Index].FieldName);\r
+      }\r
+      if (HeaderFields[Index].FieldValue != NULL) {\r
+        FreePool (HeaderFields[Index].FieldValue);\r
+      }\r
+    }\r
+\r
+    FreePool (HeaderFields);\r
+  }\r
+}\r
+\r
+/**\r
+  Generate HTTP request message.\r
+\r
+  This function will allocate memory for the whole HTTP message and generate a\r
+  well formatted HTTP Request message in it, include the Request-Line, header\r
+  fields and also the message body. It is the caller's responsibility to free\r
+  the buffer returned in *RequestMsg.\r
+\r
+  @param[in]   Message            Pointer to the EFI_HTTP_MESSAGE structure which\r
+                                  contains the required information to generate\r
+                                  the HTTP request message.\r
+  @param[in]   Url                The URL of a remote host.\r
+  @param[out]  RequestMsg         Pointer to the created HTTP request message.\r
+                                  NULL if any error occured.\r
+  @param[out]  RequestMsgSize     Size of the RequestMsg (in bytes).\r
+\r
+  @retval EFI_SUCCESS             If HTTP request string was created successfully.\r
+  @retval EFI_OUT_OF_RESOURCES    Failed to allocate resources.\r
+  @retval EFI_INVALID_PARAMETER   The input arguments are invalid.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+HttpGenRequestMessage (\r
+  IN     CONST EFI_HTTP_MESSAGE        *Message,\r
+  IN     CONST CHAR8                   *Url,\r
+     OUT CHAR8                         **RequestMsg,\r
+     OUT UINTN                         *RequestMsgSize\r
+  )\r
+{\r
+  EFI_STATUS                       Status;\r
+  UINTN                            StrLength;\r
+  CHAR8                            *RequestPtr;\r
+  UINTN                            HttpHdrSize;\r
+  UINTN                            MsgSize;\r
+  BOOLEAN                          Success;\r
+  VOID                             *HttpHdr;\r
+  EFI_HTTP_HEADER                  **AppendList;\r
+  UINTN                            Index;\r
+  EFI_HTTP_UTILITIES_PROTOCOL      *HttpUtilitiesProtocol;\r
+\r
+  Status                = EFI_SUCCESS;\r
+  HttpHdrSize           = 0;\r
+  MsgSize               = 0;\r
+  Success               = FALSE;\r
+  HttpHdr               = NULL;\r
+  AppendList            = NULL;\r
+  HttpUtilitiesProtocol = NULL;\r
+\r
+  //\r
+  // 1. If we have a Request, we cannot have a NULL Url\r
+  // 2. If we have a Request, HeaderCount can not be non-zero\r
+  // 3. If we do not have a Request, HeaderCount should be zero\r
+  // 4. If we do not have Request and Headers, we need at least a message-body\r
+  //\r
+  if ((Message == NULL || RequestMsg == NULL || RequestMsgSize == NULL) ||\r
+      (Message->Data.Request != NULL && Url == NULL) ||\r
+      (Message->Data.Request != NULL && Message->HeaderCount == 0) ||\r
+      (Message->Data.Request == NULL && Message->HeaderCount != 0) ||\r
+      (Message->Data.Request == NULL && Message->HeaderCount == 0 && Message->BodyLength == 0)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if (Message->HeaderCount != 0) {\r
+    //\r
+    // Locate the HTTP_UTILITIES protocol.\r
+    //\r
+    Status = gBS->LocateProtocol (\r
+                    &gEfiHttpUtilitiesProtocolGuid,\r
+                    NULL,\r
+                    (VOID **) &HttpUtilitiesProtocol\r
+                    );\r
+\r
+    if (EFI_ERROR (Status)) {\r
+      DEBUG ((DEBUG_ERROR,"Failed to locate Http Utilities protocol. Status = %r.\n", Status));\r
+      return Status;\r
+    }\r
+\r
+    //\r
+    // Build AppendList to send into HttpUtilitiesBuild\r
+    //\r
+    AppendList = AllocateZeroPool (sizeof (EFI_HTTP_HEADER *) * (Message->HeaderCount));\r
+    if (AppendList == NULL) {\r
+      return EFI_OUT_OF_RESOURCES;\r
+    }\r
+\r
+    for(Index = 0; Index < Message->HeaderCount; Index++){\r
+      AppendList[Index] = &Message->Headers[Index];\r
+    }\r
+\r
+    //\r
+    // Build raw HTTP Headers\r
+    //\r
+    Status = HttpUtilitiesProtocol->Build (\r
+                                      HttpUtilitiesProtocol,\r
+                                      0,\r
+                                      NULL,\r
+                                      0,\r
+                                      NULL,\r
+                                      Message->HeaderCount,\r
+                                      AppendList,\r
+                                      &HttpHdrSize,\r
+                                      &HttpHdr\r
+                                      );\r
+\r
+    FreePool (AppendList);\r
+\r
+    if (EFI_ERROR (Status) || HttpHdr == NULL){\r
+      return Status;\r
+    }\r
+  }\r
+\r
+  //\r
+  // If we have headers to be sent, account for it.\r
+  //\r
+  if (Message->HeaderCount != 0) {\r
+    MsgSize = HttpHdrSize;\r
+  }\r
+\r
+  //\r
+  // If we have a request line, account for the fields.\r
+  //\r
+  if (Message->Data.Request != NULL) {\r
+    MsgSize += HTTP_METHOD_MAXIMUM_LEN + AsciiStrLen (HTTP_VERSION_CRLF_STR) + AsciiStrLen (Url);\r
+  }\r
+\r
+\r
+  //\r
+  // If we have a message body to be sent, account for it.\r
+  //\r
+  MsgSize += Message->BodyLength;\r
+\r
+  //\r
+  // memory for the string that needs to be sent to TCP\r
+  //\r
+  *RequestMsg = NULL;\r
+  *RequestMsg = AllocateZeroPool (MsgSize);\r
+  if (*RequestMsg == NULL) {\r
+    Status = EFI_OUT_OF_RESOURCES;\r
+    goto Exit;\r
+  }\r
+\r
+  RequestPtr = *RequestMsg;\r
+  //\r
+  // Construct header request\r
+  //\r
+  if (Message->Data.Request != NULL) {\r
+    switch (Message->Data.Request->Method) {\r
+    case HttpMethodGet:\r
+      StrLength = sizeof (HTTP_METHOD_GET) - 1;\r
+      CopyMem (RequestPtr, HTTP_METHOD_GET, StrLength);\r
+      RequestPtr += StrLength;\r
+      break;\r
+    case HttpMethodPut:\r
+      StrLength = sizeof (HTTP_METHOD_PUT) - 1;\r
+      CopyMem (RequestPtr, HTTP_METHOD_PUT, StrLength);\r
+      RequestPtr += StrLength;\r
+      break;\r
+    case HttpMethodPatch:\r
+      StrLength = sizeof (HTTP_METHOD_PATCH) - 1;\r
+      CopyMem (RequestPtr, HTTP_METHOD_PATCH, StrLength);\r
+      RequestPtr += StrLength;\r
+      break;\r
+    case HttpMethodPost:\r
+      StrLength = sizeof (HTTP_METHOD_POST) - 1;\r
+      CopyMem (RequestPtr, HTTP_METHOD_POST, StrLength);\r
+      RequestPtr += StrLength;\r
+      break;\r
+    case HttpMethodHead:\r
+      StrLength = sizeof (HTTP_METHOD_HEAD) - 1;\r
+      CopyMem (RequestPtr, HTTP_METHOD_HEAD, StrLength);\r
+      RequestPtr += StrLength;\r
+      break;\r
+    case HttpMethodDelete:\r
+      StrLength = sizeof (HTTP_METHOD_DELETE) - 1;\r
+      CopyMem (RequestPtr, HTTP_METHOD_DELETE, StrLength);\r
+      RequestPtr += StrLength;\r
+      break;\r
+    default:\r
+      ASSERT (FALSE);\r
+      Status = EFI_INVALID_PARAMETER;\r
+      goto Exit;\r
+    }\r
+\r
+    StrLength = AsciiStrLen(EMPTY_SPACE);\r
+    CopyMem (RequestPtr, EMPTY_SPACE, StrLength);\r
+    RequestPtr += StrLength;\r
+\r
+    StrLength = AsciiStrLen (Url);\r
+    CopyMem (RequestPtr, Url, StrLength);\r
+    RequestPtr += StrLength;\r
+\r
+    StrLength = sizeof (HTTP_VERSION_CRLF_STR) - 1;\r
+    CopyMem (RequestPtr, HTTP_VERSION_CRLF_STR, StrLength);\r
+    RequestPtr += StrLength;\r
+\r
+    if (HttpHdr != NULL) {\r
+      //\r
+      // Construct header\r
+      //\r
+      CopyMem (RequestPtr, HttpHdr, HttpHdrSize);\r
+      RequestPtr += HttpHdrSize;\r
+    }\r
+  }\r
+\r
+  //\r
+  // Construct body\r
+  //\r
+  if (Message->Body != NULL) {\r
+    CopyMem (RequestPtr, Message->Body, Message->BodyLength);\r
+    RequestPtr += Message->BodyLength;\r
+  }\r
+\r
+  //\r
+  // Done\r
+  //\r
+  (*RequestMsgSize) = (UINTN)(RequestPtr) - (UINTN)(*RequestMsg);\r
+  Success     = TRUE;\r
+\r
+Exit:\r
+\r
+  if (!Success) {\r
+    if (*RequestMsg != NULL) {\r
+      FreePool (*RequestMsg);\r
+    }\r
+    *RequestMsg = NULL;\r
+    return Status;\r
+  }\r
+\r
+  if (HttpHdr != NULL) {\r
+    FreePool (HttpHdr);\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Translate the status code in HTTP message to EFI_HTTP_STATUS_CODE defined\r
+  in UEFI 2.5 specification.\r
+\r
+  @param[in]  StatusCode         The status code value in HTTP message.\r
+\r
+  @return                        Value defined in EFI_HTTP_STATUS_CODE .\r
+\r
+**/\r
+EFI_HTTP_STATUS_CODE\r
+EFIAPI\r
+HttpMappingToStatusCode (\r
+  IN UINTN                  StatusCode\r
+  )\r
+{\r
+  switch (StatusCode) {\r
+  case 100:\r
+    return HTTP_STATUS_100_CONTINUE;\r
+  case 101:\r
+    return HTTP_STATUS_101_SWITCHING_PROTOCOLS;\r
+  case 200:\r
+    return HTTP_STATUS_200_OK;\r
+  case 201:\r
+    return HTTP_STATUS_201_CREATED;\r
+  case 202:\r
+    return HTTP_STATUS_202_ACCEPTED;\r
+  case 203:\r
+    return HTTP_STATUS_203_NON_AUTHORITATIVE_INFORMATION;\r
+  case 204:\r
+    return HTTP_STATUS_204_NO_CONTENT;\r
+  case 205:\r
+    return HTTP_STATUS_205_RESET_CONTENT;\r
+  case 206:\r
+    return HTTP_STATUS_206_PARTIAL_CONTENT;\r
+  case 300:\r
+    return HTTP_STATUS_300_MULTIPLE_CHOICES;\r
+  case 301:\r
+    return HTTP_STATUS_301_MOVED_PERMANENTLY;\r
+  case 302:\r
+    return HTTP_STATUS_302_FOUND;\r
+  case 303:\r
+    return HTTP_STATUS_303_SEE_OTHER;\r
+  case 304:\r
+    return HTTP_STATUS_304_NOT_MODIFIED;\r
+  case 305:\r
+    return HTTP_STATUS_305_USE_PROXY;\r
+  case 307:\r
+    return HTTP_STATUS_307_TEMPORARY_REDIRECT;\r
+  case 308:\r
+    return HTTP_STATUS_308_PERMANENT_REDIRECT;\r
+  case 400:\r
+    return HTTP_STATUS_400_BAD_REQUEST;\r
+  case 401:\r
+    return HTTP_STATUS_401_UNAUTHORIZED;\r
+  case 402:\r
+    return HTTP_STATUS_402_PAYMENT_REQUIRED;\r
+  case 403:\r
+    return HTTP_STATUS_403_FORBIDDEN;\r
+  case 404:\r
+    return HTTP_STATUS_404_NOT_FOUND;\r
+  case 405:\r
+    return HTTP_STATUS_405_METHOD_NOT_ALLOWED;\r
+  case 406:\r
+    return HTTP_STATUS_406_NOT_ACCEPTABLE;\r
+  case 407:\r
+    return HTTP_STATUS_407_PROXY_AUTHENTICATION_REQUIRED;\r
+  case 408:\r
+    return HTTP_STATUS_408_REQUEST_TIME_OUT;\r
+  case 409:\r
+    return HTTP_STATUS_409_CONFLICT;\r
+  case 410:\r
+    return HTTP_STATUS_410_GONE;\r
+  case 411:\r
+    return HTTP_STATUS_411_LENGTH_REQUIRED;\r
+  case 412:\r
+    return HTTP_STATUS_412_PRECONDITION_FAILED;\r
+  case 413:\r
+    return HTTP_STATUS_413_REQUEST_ENTITY_TOO_LARGE;\r
+  case 414:\r
+    return HTTP_STATUS_414_REQUEST_URI_TOO_LARGE;\r
+  case 415:\r
+    return HTTP_STATUS_415_UNSUPPORTED_MEDIA_TYPE;\r
+  case 416:\r
+    return HTTP_STATUS_416_REQUESTED_RANGE_NOT_SATISFIED;\r
+  case 417:\r
+    return HTTP_STATUS_417_EXPECTATION_FAILED;\r
+  case 500:\r
+    return HTTP_STATUS_500_INTERNAL_SERVER_ERROR;\r
+  case 501:\r
+    return HTTP_STATUS_501_NOT_IMPLEMENTED;\r
+  case 502:\r
+    return HTTP_STATUS_502_BAD_GATEWAY;\r
+  case 503:\r
+    return HTTP_STATUS_503_SERVICE_UNAVAILABLE;\r
+  case 504:\r
+    return HTTP_STATUS_504_GATEWAY_TIME_OUT;\r
+  case 505:\r
+    return HTTP_STATUS_505_HTTP_VERSION_NOT_SUPPORTED;\r
+\r
+  default:\r
+    return HTTP_STATUS_UNSUPPORTED_STATUS;\r
+  }\r
+}\r
+\r
+/**\r
+  Check whether header field called FieldName is in DeleteList.\r
+\r
+  @param[in]  DeleteList        Pointer to array of key/value header pairs.\r
+  @param[in]  DeleteCount       The number of header pairs.\r
+  @param[in]  FieldName         Pointer to header field's name.\r
+\r
+  @return     TRUE if FieldName is not in DeleteList, that means this header field is valid.\r
+  @return     FALSE if FieldName is in DeleteList, that means this header field is invalid.\r
+\r
+**/\r
+BOOLEAN\r
+EFIAPI\r
+HttpIsValidHttpHeader (\r
+  IN  CHAR8            *DeleteList[],\r
+  IN  UINTN            DeleteCount,\r
+  IN  CHAR8            *FieldName\r
+  )\r
+{\r
+  UINTN                       Index;\r
+\r
+  if (FieldName == NULL) {\r
+    return FALSE;\r
+  }\r
+\r
+  for (Index = 0; Index < DeleteCount; Index++) {\r
+    if (DeleteList[Index] == NULL) {\r
+      continue;\r
+    }\r
+\r
+    if (AsciiStrCmp (FieldName, DeleteList[Index]) == 0) {\r
+      return FALSE;\r
+    }\r
+  }\r
+\r
+  return TRUE;\r
+}\r
+\r