Home | History | Annotate | Download | only in DxeHttpLib
      1 /** @file
      2   This library is used to share code between UEFI network stack modules.
      3   It provides the helper routines to parse the HTTP message byte stream.
      4 
      5 Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
      6 This program and the accompanying materials
      7 are licensed and made available under the terms and conditions of the BSD License
      8 which accompanies this distribution.  The full text of the license may be found at<BR>
      9 http://opensource.org/licenses/bsd-license.php
     10 
     11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     13 
     14 **/
     15 
     16 #include <Uefi.h>
     17 #include <Library/NetLib.h>
     18 #include <Library/HttpLib.h>
     19 #include <Library/BaseLib.h>
     20 #include <Library/DebugLib.h>
     21 #include <Library/MemoryAllocationLib.h>
     22 #include <Library/UefiBootServicesTableLib.h>
     23 
     24 #define BIT(x)  (1 << x)
     25 
     26 #define NET_IS_HEX_CHAR(Ch)   \
     27   ((('0' <= (Ch)) && ((Ch) <= '9')) ||  \
     28    (('A' <= (Ch)) && ((Ch) <= 'F')) ||  \
     29    (('a' <= (Ch)) && ((Ch) <= 'f')))
     30 
     31 //
     32 // Field index of the HTTP URL parse result.
     33 //
     34 #define   HTTP_URI_FIELD_SCHEME           0
     35 #define   HTTP_URI_FIELD_AUTHORITY        1
     36 #define   HTTP_URI_FIELD_PATH             2
     37 #define   HTTP_URI_FIELD_QUERY            3
     38 #define   HTTP_URI_FIELD_FRAGMENT         4
     39 #define   HTTP_URI_FIELD_USERINFO         5
     40 #define   HTTP_URI_FIELD_HOST             6
     41 #define   HTTP_URI_FIELD_PORT             7
     42 #define   HTTP_URI_FIELD_MAX              8
     43 
     44 //
     45 // Structure to store the parse result of a HTTP URL.
     46 //
     47 typedef struct {
     48     UINT32      Offset;
     49     UINT32      Length;
     50 } HTTP_URL_FILED_DATA;
     51 
     52 typedef struct {
     53   UINT16                  FieldBitMap;
     54   HTTP_URL_FILED_DATA     FieldData[HTTP_URI_FIELD_MAX];
     55 } HTTP_URL_PARSER;
     56 
     57 typedef enum {
     58   UrlParserUrlStart,
     59   UrlParserScheme,
     60   UrlParserSchemeColon,            // ":"
     61   UrlParserSchemeColonSlash,       // ":/"
     62   UrlParserSchemeColonSlashSlash,  // "://"
     63   UrlParserAuthority,
     64   UrlParserAtInAuthority,
     65   UrlParserPath,
     66   UrlParserQueryStart,    // "?"
     67   UrlParserQuery,
     68   UrlParserFragmentStart, // "#"
     69   UrlParserFragment,
     70   UrlParserUserInfo,
     71   UrlParserHostStart,     // "@"
     72   UrlParserHost,
     73   UrlParserHostIpv6,      // "["(Ipv6 address) "]"
     74   UrlParserPortStart,     // ":"
     75   UrlParserPort,
     76   UrlParserStateMax
     77 } HTTP_URL_PARSE_STATE;
     78 
     79 /**
     80   Decode a percent-encoded URI component to the ASCII character.
     81 
     82   Decode the input component in Buffer according to RFC 3986. The caller is responsible to make
     83   sure ResultBuffer points to a buffer with size equal or greater than ((AsciiStrSize (Buffer))
     84   in bytes.
     85 
     86   @param[in]    Buffer           The pointer to a percent-encoded URI component.
     87   @param[in]    BufferLength     Length of Buffer in bytes.
     88   @param[out]   ResultBuffer     Point to the buffer to store the decode result.
     89   @param[out]   ResultLength     Length of decoded string in ResultBuffer in bytes.
     90 
     91   @retval EFI_SUCCESS            Successfully decoded the URI.
     92   @retval EFI_INVALID_PARAMETER  Buffer is not a valid percent-encoded string.
     93 
     94 **/
     95 EFI_STATUS
     96 EFIAPI
     97 UriPercentDecode (
     98   IN      CHAR8            *Buffer,
     99   IN      UINT32            BufferLength,
    100      OUT  CHAR8            *ResultBuffer,
    101      OUT  UINT32           *ResultLength
    102   )
    103 {
    104   UINTN           Index;
    105   UINTN           Offset;
    106   CHAR8           HexStr[3];
    107 
    108   if (Buffer == NULL || BufferLength == 0 || ResultBuffer == NULL) {
    109     return EFI_INVALID_PARAMETER;
    110   }
    111 
    112   Index = 0;
    113   Offset = 0;
    114   HexStr[2] = '\0';
    115   while (Index < BufferLength) {
    116     if (Buffer[Index] == '%') {
    117       if (!NET_IS_HEX_CHAR (Buffer[Index+1]) || !NET_IS_HEX_CHAR (Buffer[Index+2])) {
    118         return EFI_INVALID_PARAMETER;
    119       }
    120       HexStr[0] = Buffer[Index+1];
    121       HexStr[1] = Buffer[Index+2];
    122       ResultBuffer[Offset] = (CHAR8) AsciiStrHexToUintn (HexStr);
    123       Index += 3;
    124     } else {
    125       ResultBuffer[Offset] = Buffer[Index];
    126       Index++;
    127     }
    128     Offset++;
    129   }
    130 
    131   *ResultLength = (UINT32) Offset;
    132 
    133   return EFI_SUCCESS;
    134 }
    135 
    136 /**
    137   This function return the updated state according to the input state and next character of
    138   the authority.
    139 
    140   @param[in]       Char           Next character.
    141   @param[in]       State          Current value of the parser state machine.
    142   @param[in]       IsRightBracket TRUE if there is an sign ']' in the authority component and
    143                                   indicates the next part is ':' before Port.
    144 
    145   @return          Updated state value.
    146 **/
    147 HTTP_URL_PARSE_STATE
    148 NetHttpParseAuthorityChar (
    149   IN  CHAR8                  Char,
    150   IN  HTTP_URL_PARSE_STATE   State,
    151   IN  BOOLEAN                *IsRightBracket
    152   )
    153 {
    154 
    155   //
    156   // RFC 3986:
    157   // The authority component is preceded by a double slash ("//") and is
    158   // terminated by the next slash ("/"), question mark ("?"), or number
    159   // sign ("#") character, or by the end of the URI.
    160   //
    161   if (Char == ' ' || Char == '\r' || Char == '\n') {
    162     return UrlParserStateMax;
    163   }
    164 
    165   //
    166   // authority   = [ userinfo "@" ] host [ ":" port ]
    167   //
    168   switch (State) {
    169   case UrlParserUserInfo:
    170     if (Char == '@') {
    171       return UrlParserHostStart;
    172     }
    173     break;
    174 
    175   case UrlParserHost:
    176   case UrlParserHostStart:
    177     if (Char == '[') {
    178       return UrlParserHostIpv6;
    179     }
    180 
    181     if (Char == ':') {
    182       return UrlParserPortStart;
    183     }
    184 
    185     return UrlParserHost;
    186 
    187   case UrlParserHostIpv6:
    188     if (Char == ']') {
    189       *IsRightBracket = TRUE;
    190     }
    191 
    192     if (Char == ':' && *IsRightBracket) {
    193       return UrlParserPortStart;
    194     }
    195     return UrlParserHostIpv6;
    196 
    197   case UrlParserPort:
    198   case UrlParserPortStart:
    199     return UrlParserPort;
    200 
    201   default:
    202     break;
    203   }
    204 
    205   return State;
    206 }
    207 
    208 /**
    209   This function parse the authority component of the input URL and update the parser.
    210 
    211   @param[in]       Url            The pointer to a HTTP URL string.
    212   @param[in]       FoundAt        TRUE if there is an at sign ('@') in the authority component.
    213   @param[in, out]  UrlParser      Pointer to the buffer of the parse result.
    214 
    215   @retval EFI_SUCCESS             Successfully parse the authority.
    216   @retval Other                   Error happened.
    217 
    218 **/
    219 EFI_STATUS
    220 NetHttpParseAuthority (
    221   IN      CHAR8              *Url,
    222   IN      BOOLEAN            FoundAt,
    223   IN OUT  HTTP_URL_PARSER    *UrlParser
    224   )
    225 {
    226   CHAR8                 *Char;
    227   CHAR8                 *Authority;
    228   UINT32                Length;
    229   HTTP_URL_PARSE_STATE  State;
    230   UINT32                Field;
    231   UINT32                OldField;
    232   BOOLEAN               IsrightBracket;
    233 
    234   ASSERT ((UrlParser->FieldBitMap & BIT (HTTP_URI_FIELD_AUTHORITY)) != 0);
    235 
    236   //
    237   // authority   = [ userinfo "@" ] host [ ":" port ]
    238   //
    239   if (FoundAt) {
    240     State = UrlParserUserInfo;
    241   } else {
    242     State = UrlParserHost;
    243   }
    244 
    245   IsrightBracket = FALSE;
    246   Field = HTTP_URI_FIELD_MAX;
    247   OldField = Field;
    248   Authority = Url + UrlParser->FieldData[HTTP_URI_FIELD_AUTHORITY].Offset;
    249   Length = UrlParser->FieldData[HTTP_URI_FIELD_AUTHORITY].Length;
    250   for (Char = Authority; Char < Authority + Length; Char++) {
    251     State = NetHttpParseAuthorityChar (*Char, State, &IsrightBracket);
    252     switch (State) {
    253     case UrlParserStateMax:
    254       return EFI_INVALID_PARAMETER;
    255 
    256     case UrlParserHostStart:
    257     case UrlParserPortStart:
    258       continue;
    259 
    260     case UrlParserUserInfo:
    261       Field = HTTP_URI_FIELD_USERINFO;
    262       break;
    263 
    264     case UrlParserHost:
    265       Field = HTTP_URI_FIELD_HOST;
    266       break;
    267 
    268     case UrlParserHostIpv6:
    269       Field = HTTP_URI_FIELD_HOST;
    270       break;
    271 
    272     case UrlParserPort:
    273       Field = HTTP_URI_FIELD_PORT;
    274       break;
    275 
    276     default:
    277       ASSERT (FALSE);
    278     }
    279 
    280     //
    281     // Field not changed, count the length.
    282     //
    283     ASSERT (Field < HTTP_URI_FIELD_MAX);
    284     if (Field == OldField) {
    285       UrlParser->FieldData[Field].Length++;
    286       continue;
    287     }
    288 
    289     //
    290     // New field start
    291     //
    292     UrlParser->FieldBitMap |= BIT (Field);
    293     UrlParser->FieldData[Field].Offset = (UINT32) (Char - Url);
    294     UrlParser->FieldData[Field].Length = 1;
    295     OldField = Field;
    296   }
    297 
    298   return EFI_SUCCESS;
    299 }
    300 
    301 /**
    302   This function return the updated state according to the input state and next character of a URL.
    303 
    304   @param[in]       Char           Next character.
    305   @param[in]       State          Current value of the parser state machine.
    306 
    307   @return          Updated state value.
    308 
    309 **/
    310 HTTP_URL_PARSE_STATE
    311 NetHttpParseUrlChar (
    312   IN  CHAR8                  Char,
    313   IN  HTTP_URL_PARSE_STATE   State
    314   )
    315 {
    316   if (Char == ' ' || Char == '\r' || Char == '\n') {
    317     return UrlParserStateMax;
    318   }
    319 
    320   //
    321   // http_URL = "http:" "//" host [ ":" port ] [ abs_path [ "?" query ]]
    322   //
    323   // Request-URI    = "*" | absolute-URI | path-absolute | authority
    324   //
    325   // absolute-URI  = scheme ":" hier-part [ "?" query ]
    326   // path-absolute = "/" [ segment-nz *( "/" segment ) ]
    327   // authority   = [ userinfo "@" ] host [ ":" port ]
    328   //
    329   switch (State) {
    330   case UrlParserUrlStart:
    331     if (Char == '*' || Char == '/') {
    332       return UrlParserPath;
    333     }
    334     return UrlParserScheme;
    335 
    336   case UrlParserScheme:
    337     if (Char == ':') {
    338       return UrlParserSchemeColon;
    339     }
    340     break;
    341 
    342   case UrlParserSchemeColon:
    343     if (Char == '/') {
    344       return UrlParserSchemeColonSlash;
    345     }
    346     break;
    347 
    348   case UrlParserSchemeColonSlash:
    349     if (Char == '/') {
    350       return UrlParserSchemeColonSlashSlash;
    351     }
    352     break;
    353 
    354   case UrlParserAtInAuthority:
    355     if (Char == '@') {
    356       return UrlParserStateMax;
    357     }
    358 
    359   case UrlParserAuthority:
    360   case UrlParserSchemeColonSlashSlash:
    361     if (Char == '@') {
    362       return UrlParserAtInAuthority;
    363     }
    364     if (Char == '/') {
    365       return UrlParserPath;
    366     }
    367     if (Char == '?') {
    368       return UrlParserQueryStart;
    369     }
    370     if (Char == '#') {
    371       return UrlParserFragmentStart;
    372     }
    373     return UrlParserAuthority;
    374 
    375   case UrlParserPath:
    376     if (Char == '?') {
    377       return UrlParserQueryStart;
    378     }
    379     if (Char == '#') {
    380       return UrlParserFragmentStart;
    381     }
    382     break;
    383 
    384   case UrlParserQuery:
    385   case UrlParserQueryStart:
    386     if (Char == '#') {
    387       return UrlParserFragmentStart;
    388     }
    389     return UrlParserQuery;
    390 
    391   case UrlParserFragmentStart:
    392     return UrlParserFragment;
    393 
    394   default:
    395     break;
    396   }
    397 
    398   return State;
    399 }
    400 /**
    401   Create a URL parser for the input URL string.
    402 
    403   This function will parse and dereference the input HTTP URL into it components. The original
    404   content of the URL won't be modified and the result will be returned in UrlParser, which can
    405   be used in other functions like NetHttpUrlGetHostName().
    406 
    407   @param[in]    Url                The pointer to a HTTP URL string.
    408   @param[in]    Length             Length of Url in bytes.
    409   @param[in]    IsConnectMethod    Whether the Url is used in HTTP CONNECT method or not.
    410   @param[out]   UrlParser          Pointer to the returned buffer to store the parse result.
    411 
    412   @retval EFI_SUCCESS              Successfully dereferenced the HTTP URL.
    413   @retval EFI_INVALID_PARAMETER    UrlParser is NULL or Url is not a valid HTTP URL.
    414   @retval EFI_OUT_OF_RESOURCES     Could not allocate needed resources.
    415 
    416 **/
    417 EFI_STATUS
    418 EFIAPI
    419 HttpParseUrl (
    420   IN      CHAR8              *Url,
    421   IN      UINT32             Length,
    422   IN      BOOLEAN            IsConnectMethod,
    423      OUT  VOID               **UrlParser
    424   )
    425 {
    426   HTTP_URL_PARSE_STATE  State;
    427   CHAR8                 *Char;
    428   UINT32                Field;
    429   UINT32                OldField;
    430   BOOLEAN               FoundAt;
    431   EFI_STATUS            Status;
    432   HTTP_URL_PARSER       *Parser;
    433 
    434   if (Url == NULL || Length == 0 || UrlParser == NULL) {
    435     return EFI_INVALID_PARAMETER;
    436   }
    437 
    438   Parser = AllocateZeroPool (sizeof (HTTP_URL_PARSER));
    439   if (Parser == NULL) {
    440     return EFI_OUT_OF_RESOURCES;
    441   }
    442 
    443   if (IsConnectMethod) {
    444     //
    445     // According to RFC 2616, the authority form is only used by the CONNECT method.
    446     //
    447     State = UrlParserAuthority;
    448   } else {
    449     State = UrlParserUrlStart;
    450   }
    451 
    452   Field = HTTP_URI_FIELD_MAX;
    453   OldField = Field;
    454   FoundAt = FALSE;
    455   for (Char = Url; Char < Url + Length; Char++) {
    456     //
    457     // Update state machine accoring to next char.
    458     //
    459     State = NetHttpParseUrlChar (*Char, State);
    460 
    461     switch (State) {
    462     case UrlParserStateMax:
    463       return EFI_INVALID_PARAMETER;
    464 
    465     case UrlParserSchemeColon:
    466     case UrlParserSchemeColonSlash:
    467     case UrlParserSchemeColonSlashSlash:
    468     case UrlParserQueryStart:
    469     case UrlParserFragmentStart:
    470       //
    471       // Skip all the delimiting char: "://" "?" "@"
    472       //
    473       continue;
    474 
    475     case UrlParserScheme:
    476       Field = HTTP_URI_FIELD_SCHEME;
    477       break;
    478 
    479     case UrlParserAtInAuthority:
    480       FoundAt = TRUE;
    481     case UrlParserAuthority:
    482       Field = HTTP_URI_FIELD_AUTHORITY;
    483       break;
    484 
    485     case UrlParserPath:
    486       Field = HTTP_URI_FIELD_PATH;
    487       break;
    488 
    489     case UrlParserQuery:
    490       Field = HTTP_URI_FIELD_QUERY;
    491       break;
    492 
    493     case UrlParserFragment:
    494       Field = HTTP_URI_FIELD_FRAGMENT;
    495       break;
    496 
    497     default:
    498       ASSERT (FALSE);
    499     }
    500 
    501     //
    502     // Field not changed, count the length.
    503     //
    504     ASSERT (Field < HTTP_URI_FIELD_MAX);
    505     if (Field == OldField) {
    506       Parser->FieldData[Field].Length++;
    507       continue;
    508     }
    509 
    510     //
    511     // New field start
    512     //
    513     Parser->FieldBitMap |= BIT (Field);
    514     Parser->FieldData[Field].Offset = (UINT32) (Char - Url);
    515     Parser->FieldData[Field].Length = 1;
    516     OldField = Field;
    517   }
    518 
    519   //
    520   // If has authority component, continue to parse the username, host and port.
    521   //
    522   if ((Parser->FieldBitMap & BIT (HTTP_URI_FIELD_AUTHORITY)) != 0) {
    523     Status = NetHttpParseAuthority (Url, FoundAt, Parser);
    524     if (EFI_ERROR (Status)) {
    525       return Status;
    526     }
    527   }
    528 
    529   *UrlParser = Parser;
    530   return EFI_SUCCESS;
    531 }
    532 
    533 /**
    534   Get the Hostname from a HTTP URL.
    535 
    536   This function will return the HostName according to the Url and previous parse result ,and
    537   it is the caller's responsibility to free the buffer returned in *HostName.
    538 
    539   @param[in]    Url                The pointer to a HTTP URL string.
    540   @param[in]    UrlParser          URL Parse result returned by NetHttpParseUrl().
    541   @param[out]   HostName           Pointer to a buffer to store the HostName.
    542 
    543   @retval EFI_SUCCESS              Successfully get the required component.
    544   @retval EFI_INVALID_PARAMETER    Uri is NULL or HostName is NULL or UrlParser is invalid.
    545   @retval EFI_NOT_FOUND            No hostName component in the URL.
    546   @retval EFI_OUT_OF_RESOURCES     Could not allocate needed resources.
    547 
    548 **/
    549 EFI_STATUS
    550 EFIAPI
    551 HttpUrlGetHostName (
    552   IN      CHAR8              *Url,
    553   IN      VOID               *UrlParser,
    554      OUT  CHAR8              **HostName
    555   )
    556 {
    557   CHAR8                *Name;
    558   EFI_STATUS           Status;
    559   UINT32               ResultLength;
    560   HTTP_URL_PARSER      *Parser;
    561 
    562   if (Url == NULL || UrlParser == NULL || HostName == NULL) {
    563     return EFI_INVALID_PARAMETER;
    564   }
    565 
    566   Parser = (HTTP_URL_PARSER*) UrlParser;
    567 
    568   if ((Parser->FieldBitMap & BIT (HTTP_URI_FIELD_HOST)) == 0) {
    569     return EFI_NOT_FOUND;
    570   }
    571 
    572   Name = AllocatePool (Parser->FieldData[HTTP_URI_FIELD_HOST].Length + 1);
    573   if (Name == NULL) {
    574     return EFI_OUT_OF_RESOURCES;
    575   }
    576 
    577   Status = UriPercentDecode (
    578              Url + Parser->FieldData[HTTP_URI_FIELD_HOST].Offset,
    579              Parser->FieldData[HTTP_URI_FIELD_HOST].Length,
    580              Name,
    581              &ResultLength
    582              );
    583   if (EFI_ERROR (Status)) {
    584     return Status;
    585   }
    586 
    587   Name[ResultLength] = '\0';
    588   *HostName = Name;
    589   return EFI_SUCCESS;
    590 }
    591 
    592 
    593 /**
    594   Get the IPv4 address from a HTTP URL.
    595 
    596   This function will return the IPv4 address according to the Url and previous parse result.
    597 
    598   @param[in]    Url                The pointer to a HTTP URL string.
    599   @param[in]    UrlParser          URL Parse result returned by NetHttpParseUrl().
    600   @param[out]   Ip4Address         Pointer to a buffer to store the IP address.
    601 
    602   @retval EFI_SUCCESS              Successfully get the required component.
    603   @retval EFI_INVALID_PARAMETER    Uri is NULL or Ip4Address is NULL or UrlParser is invalid.
    604   @retval EFI_NOT_FOUND            No IPv4 address component in the URL.
    605   @retval EFI_OUT_OF_RESOURCES     Could not allocate needed resources.
    606 
    607 **/
    608 EFI_STATUS
    609 EFIAPI
    610 HttpUrlGetIp4 (
    611   IN      CHAR8              *Url,
    612   IN      VOID               *UrlParser,
    613      OUT  EFI_IPv4_ADDRESS   *Ip4Address
    614   )
    615 {
    616   CHAR8                *Ip4String;
    617   EFI_STATUS           Status;
    618   UINT32               ResultLength;
    619   HTTP_URL_PARSER      *Parser;
    620 
    621   if (Url == NULL || UrlParser == NULL || Ip4Address == NULL) {
    622     return EFI_INVALID_PARAMETER;
    623   }
    624 
    625   Parser = (HTTP_URL_PARSER*) UrlParser;
    626 
    627   if ((Parser->FieldBitMap & BIT (HTTP_URI_FIELD_HOST)) == 0) {
    628     return EFI_INVALID_PARAMETER;
    629   }
    630 
    631   Ip4String = AllocatePool (Parser->FieldData[HTTP_URI_FIELD_HOST].Length + 1);
    632   if (Ip4String == NULL) {
    633     return EFI_OUT_OF_RESOURCES;
    634   }
    635 
    636   Status = UriPercentDecode (
    637              Url + Parser->FieldData[HTTP_URI_FIELD_HOST].Offset,
    638              Parser->FieldData[HTTP_URI_FIELD_HOST].Length,
    639              Ip4String,
    640              &ResultLength
    641              );
    642   if (EFI_ERROR (Status)) {
    643     return Status;
    644   }
    645 
    646   Ip4String[ResultLength] = '\0';
    647   Status = NetLibAsciiStrToIp4 (Ip4String, Ip4Address);
    648   FreePool (Ip4String);
    649 
    650   return Status;
    651 }
    652 
    653 /**
    654   Get the IPv6 address from a HTTP URL.
    655 
    656   This function will return the IPv6 address according to the Url and previous parse result.
    657 
    658   @param[in]    Url                The pointer to a HTTP URL string.
    659   @param[in]    UrlParser          URL Parse result returned by NetHttpParseUrl().
    660   @param[out]   Ip6Address         Pointer to a buffer to store the IP address.
    661 
    662   @retval EFI_SUCCESS              Successfully get the required component.
    663   @retval EFI_INVALID_PARAMETER    Uri is NULL or Ip6Address is NULL or UrlParser is invalid.
    664   @retval EFI_NOT_FOUND            No IPv6 address component in the URL.
    665   @retval EFI_OUT_OF_RESOURCES     Could not allocate needed resources.
    666 
    667 **/
    668 EFI_STATUS
    669 EFIAPI
    670 HttpUrlGetIp6 (
    671   IN      CHAR8              *Url,
    672   IN      VOID               *UrlParser,
    673      OUT  EFI_IPv6_ADDRESS   *Ip6Address
    674   )
    675 {
    676   CHAR8                *Ip6String;
    677   CHAR8                *Ptr;
    678   UINT32               Length;
    679   EFI_STATUS           Status;
    680   UINT32               ResultLength;
    681   HTTP_URL_PARSER      *Parser;
    682 
    683   if (Url == NULL || UrlParser == NULL || Ip6Address == NULL) {
    684     return EFI_INVALID_PARAMETER;
    685   }
    686 
    687   Parser = (HTTP_URL_PARSER*) UrlParser;
    688 
    689   if ((Parser->FieldBitMap & BIT (HTTP_URI_FIELD_HOST)) == 0) {
    690     return EFI_INVALID_PARAMETER;
    691   }
    692 
    693   //
    694   // IP-literal = "[" ( IPv6address / IPvFuture  ) "]"
    695   //
    696   Length = Parser->FieldData[HTTP_URI_FIELD_HOST].Length;
    697   if (Length < 2) {
    698     return EFI_INVALID_PARAMETER;
    699   }
    700 
    701   Ptr    = Url + Parser->FieldData[HTTP_URI_FIELD_HOST].Offset;
    702   if ((Ptr[0] != '[') || (Ptr[Length - 1] != ']')) {
    703     return EFI_INVALID_PARAMETER;
    704   }
    705 
    706   Ip6String = AllocatePool (Length);
    707   if (Ip6String == NULL) {
    708     return EFI_OUT_OF_RESOURCES;
    709   }
    710 
    711   Status = UriPercentDecode (
    712              Ptr + 1,
    713              Length - 2,
    714              Ip6String,
    715              &ResultLength
    716              );
    717   if (EFI_ERROR (Status)) {
    718     return Status;
    719   }
    720 
    721   Ip6String[ResultLength] = '\0';
    722   Status = NetLibAsciiStrToIp6 (Ip6String, Ip6Address);
    723   FreePool (Ip6String);
    724 
    725   return Status;
    726 }
    727 
    728 /**
    729   Get the port number from a HTTP URL.
    730 
    731   This function will return the port number according to the Url and previous parse result.
    732 
    733   @param[in]    Url                The pointer to a HTTP URL string.
    734   @param[in]    UrlParser          URL Parse result returned by NetHttpParseUrl().
    735   @param[out]   Port               Pointer to a buffer to store the port number.
    736 
    737   @retval EFI_SUCCESS              Successfully get the required component.
    738   @retval EFI_INVALID_PARAMETER    Uri is NULL or Port is NULL or UrlParser is invalid.
    739   @retval EFI_NOT_FOUND            No port number in the URL.
    740   @retval EFI_OUT_OF_RESOURCES     Could not allocate needed resources.
    741 
    742 **/
    743 EFI_STATUS
    744 EFIAPI
    745 HttpUrlGetPort (
    746   IN      CHAR8              *Url,
    747   IN      VOID               *UrlParser,
    748      OUT  UINT16             *Port
    749   )
    750 {
    751   CHAR8         *PortString;
    752   EFI_STATUS    Status;
    753   UINT32        ResultLength;
    754   HTTP_URL_PARSER      *Parser;
    755 
    756   if (Url == NULL || UrlParser == NULL || Port == NULL) {
    757     return EFI_INVALID_PARAMETER;
    758   }
    759 
    760   Parser = (HTTP_URL_PARSER*) UrlParser;
    761 
    762   if ((Parser->FieldBitMap & BIT (HTTP_URI_FIELD_PORT)) == 0) {
    763     return EFI_INVALID_PARAMETER;
    764   }
    765 
    766   PortString = AllocatePool (Parser->FieldData[HTTP_URI_FIELD_PORT].Length + 1);
    767   if (PortString == NULL) {
    768     return EFI_OUT_OF_RESOURCES;
    769   }
    770 
    771   Status = UriPercentDecode (
    772              Url + Parser->FieldData[HTTP_URI_FIELD_PORT].Offset,
    773              Parser->FieldData[HTTP_URI_FIELD_PORT].Length,
    774              PortString,
    775              &ResultLength
    776              );
    777   if (EFI_ERROR (Status)) {
    778     return Status;
    779   }
    780 
    781   PortString[ResultLength] = '\0';
    782   *Port = (UINT16) AsciiStrDecimalToUintn (Url + Parser->FieldData[HTTP_URI_FIELD_PORT].Offset);
    783 
    784   return  EFI_SUCCESS;
    785 }
    786 
    787 /**
    788   Release the resource of the URL parser.
    789 
    790   @param[in]    UrlParser            Pointer to the parser.
    791 
    792 **/
    793 VOID
    794 EFIAPI
    795 HttpUrlFreeParser (
    796   IN      VOID               *UrlParser
    797   )
    798 {
    799   FreePool (UrlParser);
    800 }
    801 
    802 /**
    803   Find a specified header field according to the field name.
    804 
    805   @param[in]   HeaderCount      Number of HTTP header structures in Headers list.
    806   @param[in]   Headers          Array containing list of HTTP headers.
    807   @param[in]   FieldName        Null terminated string which describes a field name.
    808 
    809   @return    Pointer to the found header or NULL.
    810 
    811 **/
    812 EFI_HTTP_HEADER *
    813 HttpIoFindHeader (
    814   IN  UINTN                HeaderCount,
    815   IN  EFI_HTTP_HEADER      *Headers,
    816   IN  CHAR8                *FieldName
    817   )
    818 {
    819   UINTN                 Index;
    820 
    821   if (HeaderCount == 0 || Headers == NULL || FieldName == NULL) {
    822     return NULL;
    823   }
    824 
    825   for (Index = 0; Index < HeaderCount; Index++){
    826     //
    827     // Field names are case-insensitive (RFC 2616).
    828     //
    829     if (AsciiStriCmp (Headers[Index].FieldName, FieldName) == 0) {
    830       return &Headers[Index];
    831     }
    832   }
    833   return NULL;
    834 }
    835 
    836 typedef enum {
    837   BodyParserBodyStart,
    838   BodyParserBodyIdentity,
    839   BodyParserChunkSizeStart,
    840   BodyParserChunkSize,
    841   BodyParserChunkSizeEndCR,
    842   BodyParserChunkExtStart,
    843   BodyParserChunkDataStart,
    844   BodyParserChunkDataEnd,
    845   BodyParserChunkDataEndCR,
    846   BodyParserTrailer,
    847   BodyParserLastCRLF,
    848   BodyParserLastCRLFEnd,
    849   BodyParserComplete,
    850   BodyParserStateMax
    851 } HTTP_BODY_PARSE_STATE;
    852 
    853 typedef struct {
    854   BOOLEAN                       IgnoreBody;    // "MUST NOT" include a message-body
    855   BOOLEAN                       IsChunked;     // "chunked" transfer-coding.
    856   BOOLEAN                       ContentLengthIsValid;
    857   UINTN                         ContentLength; // Entity length (not the message-body length), invalid until ContentLengthIsValid is TRUE
    858 
    859   HTTP_BODY_PARSER_CALLBACK     Callback;
    860   VOID                          *Context;
    861   UINTN                         ParsedBodyLength;
    862   HTTP_BODY_PARSE_STATE         State;
    863   UINTN                         CurrentChunkSize;
    864   UINTN                         CurrentChunkParsedSize;
    865 } HTTP_BODY_PARSER;
    866 
    867 /**
    868 
    869   Convert an Ascii char to its uppercase.
    870 
    871   @param[in]       Char           Ascii character.
    872 
    873   @return          Uppercase value of the input Char.
    874 
    875 **/
    876 CHAR8
    877 HttpIoCharToUpper (
    878   IN      CHAR8                    Char
    879   )
    880 {
    881   if (Char >= 'a' && Char <= 'z') {
    882     return  Char - ('a' - 'A');
    883   }
    884 
    885   return Char;
    886 }
    887 
    888 /**
    889   Convert an hexadecimal char to a value of type UINTN.
    890 
    891   @param[in]       Char           Ascii character.
    892 
    893   @return          Value translated from Char.
    894 
    895 **/
    896 UINTN
    897 HttpIoHexCharToUintn (
    898   IN CHAR8           Char
    899   )
    900 {
    901   if (Char >= '0' && Char <= '9') {
    902     return Char - '0';
    903   }
    904 
    905   return (10 + HttpIoCharToUpper (Char) - 'A');
    906 }
    907 
    908 /**
    909   Get the value of the content length if there is a "Content-Length" header.
    910 
    911   @param[in]    HeaderCount        Number of HTTP header structures in Headers.
    912   @param[in]    Headers            Array containing list of HTTP headers.
    913   @param[out]   ContentLength      Pointer to save the value of the content length.
    914 
    915   @retval EFI_SUCCESS              Successfully get the content length.
    916   @retval EFI_NOT_FOUND            No "Content-Length" header in the Headers.
    917 
    918 **/
    919 EFI_STATUS
    920 HttpIoParseContentLengthHeader (
    921   IN     UINTN                HeaderCount,
    922   IN     EFI_HTTP_HEADER      *Headers,
    923      OUT UINTN                *ContentLength
    924   )
    925 {
    926   EFI_HTTP_HEADER       *Header;
    927 
    928   Header = HttpIoFindHeader (HeaderCount, Headers, "Content-Length");
    929   if (Header == NULL) {
    930     return EFI_NOT_FOUND;
    931   }
    932 
    933   *ContentLength = AsciiStrDecimalToUintn (Header->FieldValue);
    934   return EFI_SUCCESS;
    935 }
    936 
    937 /**
    938 
    939   Check whether the HTTP message is using the "chunked" transfer-coding.
    940 
    941   @param[in]    HeaderCount        Number of HTTP header structures in Headers.
    942   @param[in]    Headers            Array containing list of HTTP headers.
    943 
    944   @return       The message is "chunked" transfer-coding (TRUE) or not (FALSE).
    945 
    946 **/
    947 BOOLEAN
    948 HttpIoIsChunked (
    949   IN   UINTN                    HeaderCount,
    950   IN   EFI_HTTP_HEADER          *Headers
    951   )
    952 {
    953   EFI_HTTP_HEADER       *Header;
    954 
    955 
    956   Header = HttpIoFindHeader (HeaderCount, Headers, "Transfer-Encoding");
    957   if (Header == NULL) {
    958     return FALSE;
    959   }
    960 
    961   if (AsciiStriCmp (Header->FieldValue, "identity") != 0) {
    962     return TRUE;
    963   }
    964 
    965   return FALSE;
    966 }
    967 
    968 /**
    969   Check whether the HTTP message should have a message-body.
    970 
    971   @param[in]    Method             The HTTP method (e.g. GET, POST) for this HTTP message.
    972   @param[in]    StatusCode         Response status code returned by the remote host.
    973 
    974   @return       The message should have a message-body (FALSE) or not (TRUE).
    975 
    976 **/
    977 BOOLEAN
    978 HttpIoNoMessageBody (
    979   IN   EFI_HTTP_METHOD          Method,
    980   IN   EFI_HTTP_STATUS_CODE     StatusCode
    981   )
    982 {
    983   //
    984   // RFC 2616:
    985   // All responses to the HEAD request method
    986   // MUST NOT include a message-body, even though the presence of entity-
    987   // header fields might lead one to believe they do. All 1xx
    988   // (informational), 204 (no content), and 304 (not modified) responses
    989   // MUST NOT include a message-body. All other responses do include a
    990   // message-body, although it MAY be of zero length.
    991   //
    992   if (Method == HttpMethodHead) {
    993     return TRUE;
    994   }
    995 
    996   if ((StatusCode == HTTP_STATUS_100_CONTINUE) ||
    997       (StatusCode == HTTP_STATUS_101_SWITCHING_PROTOCOLS) ||
    998       (StatusCode == HTTP_STATUS_204_NO_CONTENT) ||
    999       (StatusCode == HTTP_STATUS_304_NOT_MODIFIED))
   1000   {
   1001     return TRUE;
   1002   }
   1003 
   1004   return FALSE;
   1005 }
   1006 
   1007 /**
   1008   Initialize a HTTP message-body parser.
   1009 
   1010   This function will create and initialize a HTTP message parser according to caller provided HTTP message
   1011   header information. It is the caller's responsibility to free the buffer returned in *UrlParser by HttpFreeMsgParser().
   1012 
   1013   @param[in]    Method             The HTTP method (e.g. GET, POST) for this HTTP message.
   1014   @param[in]    StatusCode         Response status code returned by the remote host.
   1015   @param[in]    HeaderCount        Number of HTTP header structures in Headers.
   1016   @param[in]    Headers            Array containing list of HTTP headers.
   1017   @param[in]    Callback           Callback function that is invoked when parsing the HTTP message-body,
   1018                                    set to NULL to ignore all events.
   1019   @param[in]    Context            Pointer to the context that will be passed to Callback.
   1020   @param[out]   MsgParser          Pointer to the returned buffer to store the message parser.
   1021 
   1022   @retval EFI_SUCCESS              Successfully initialized the parser.
   1023   @retval EFI_OUT_OF_RESOURCES     Could not allocate needed resources.
   1024   @retval EFI_INVALID_PARAMETER    MsgParser is NULL or HeaderCount is not NULL but Headers is NULL.
   1025   @retval Others                   Failed to initialize the parser.
   1026 
   1027 **/
   1028 EFI_STATUS
   1029 EFIAPI
   1030 HttpInitMsgParser (
   1031   IN     EFI_HTTP_METHOD               Method,
   1032   IN     EFI_HTTP_STATUS_CODE          StatusCode,
   1033   IN     UINTN                         HeaderCount,
   1034   IN     EFI_HTTP_HEADER               *Headers,
   1035   IN     HTTP_BODY_PARSER_CALLBACK     Callback,
   1036   IN     VOID                          *Context,
   1037     OUT  VOID                          **MsgParser
   1038   )
   1039 {
   1040   EFI_STATUS            Status;
   1041   HTTP_BODY_PARSER      *Parser;
   1042 
   1043   if (HeaderCount != 0 && Headers == NULL) {
   1044     return EFI_INVALID_PARAMETER;
   1045   }
   1046 
   1047   if (MsgParser == NULL) {
   1048     return EFI_INVALID_PARAMETER;
   1049   }
   1050 
   1051   Parser = AllocateZeroPool (sizeof (HTTP_BODY_PARSER));
   1052   if (Parser == NULL) {
   1053     return EFI_OUT_OF_RESOURCES;
   1054   }
   1055 
   1056   Parser->State = BodyParserBodyStart;
   1057 
   1058   //
   1059   // Determine the message length according to RFC 2616.
   1060   // 1. Check whether the message "MUST NOT" have a message-body.
   1061   //
   1062   Parser->IgnoreBody = HttpIoNoMessageBody (Method, StatusCode);
   1063   //
   1064   // 2. Check whether the message using "chunked" transfer-coding.
   1065   //
   1066   Parser->IsChunked  = HttpIoIsChunked (HeaderCount, Headers);
   1067   //
   1068   // 3. Check whether the message has a Content-Length header field.
   1069   //
   1070   Status = HttpIoParseContentLengthHeader (HeaderCount, Headers, &Parser->ContentLength);
   1071   if (!EFI_ERROR (Status)) {
   1072     Parser->ContentLengthIsValid = TRUE;
   1073   }
   1074   //
   1075   // 4. Range header is not supported now, so we won't meet media type "multipart/byteranges".
   1076   // 5. By server closing the connection
   1077   //
   1078 
   1079   //
   1080   // Set state to skip body parser if the message shouldn't have a message body.
   1081   //
   1082   if (Parser->IgnoreBody) {
   1083     Parser->State = BodyParserComplete;
   1084   } else {
   1085     Parser->Callback = Callback;
   1086     Parser->Context  = Context;
   1087   }
   1088 
   1089   *MsgParser = Parser;
   1090   return EFI_SUCCESS;
   1091 }
   1092 
   1093 /**
   1094   Parse message body.
   1095 
   1096   Parse BodyLength of message-body. This function can be called repeatedly to parse the message-body partially.
   1097 
   1098   @param[in, out]    MsgParser            Pointer to the message parser.
   1099   @param[in]         BodyLength           Length in bytes of the Body.
   1100   @param[in]         Body                 Pointer to the buffer of the message-body to be parsed.
   1101 
   1102   @retval EFI_SUCCESS                Successfully parse the message-body.
   1103   @retval EFI_INVALID_PARAMETER      MsgParser is NULL or Body is NULL or BodyLength is 0.
   1104   @retval Others                     Operation aborted.
   1105 
   1106 **/
   1107 EFI_STATUS
   1108 EFIAPI
   1109 HttpParseMessageBody (
   1110   IN OUT VOID              *MsgParser,
   1111   IN     UINTN             BodyLength,
   1112   IN     CHAR8             *Body
   1113   )
   1114 {
   1115   CHAR8                 *Char;
   1116   UINTN                 RemainderLengthInThis;
   1117   UINTN                 LengthForCallback;
   1118   EFI_STATUS            Status;
   1119   HTTP_BODY_PARSER      *Parser;
   1120 
   1121   if (BodyLength == 0 || Body == NULL) {
   1122     return EFI_INVALID_PARAMETER;
   1123   }
   1124 
   1125   if (MsgParser == NULL) {
   1126     return EFI_INVALID_PARAMETER;
   1127   }
   1128 
   1129   Parser = (HTTP_BODY_PARSER*) MsgParser;
   1130 
   1131   if (Parser->IgnoreBody) {
   1132     Parser->State = BodyParserComplete;
   1133     if (Parser->Callback != NULL) {
   1134       Status = Parser->Callback (
   1135                  BodyParseEventOnComplete,
   1136                  Body,
   1137                  0,
   1138                  Parser->Context
   1139                  );
   1140       if (EFI_ERROR (Status)) {
   1141         return Status;
   1142       }
   1143     }
   1144     return EFI_SUCCESS;
   1145   }
   1146 
   1147   if (Parser->State == BodyParserBodyStart) {
   1148     Parser->ParsedBodyLength = 0;
   1149     if (Parser->IsChunked) {
   1150       Parser->State = BodyParserChunkSizeStart;
   1151     } else {
   1152       Parser->State = BodyParserBodyIdentity;
   1153     }
   1154   }
   1155 
   1156   //
   1157   // The message body might be truncated in anywhere, so we need to parse is byte-by-byte.
   1158   //
   1159   for (Char = Body; Char < Body + BodyLength; ) {
   1160 
   1161     switch (Parser->State) {
   1162     case BodyParserStateMax:
   1163       return EFI_ABORTED;
   1164 
   1165     case BodyParserBodyIdentity:
   1166       //
   1167       // Identity transfer-coding, just notify user to save the body data.
   1168       //
   1169       if (Parser->Callback != NULL) {
   1170         Status = Parser->Callback (
   1171                    BodyParseEventOnData,
   1172                    Char,
   1173                    MIN (BodyLength, Parser->ContentLength - Parser->ParsedBodyLength),
   1174                    Parser->Context
   1175                    );
   1176         if (EFI_ERROR (Status)) {
   1177           return Status;
   1178         }
   1179       }
   1180       Char += MIN (BodyLength, Parser->ContentLength - Parser->ParsedBodyLength);
   1181       Parser->ParsedBodyLength += MIN (BodyLength, Parser->ContentLength - Parser->ParsedBodyLength);
   1182       if (Parser->ParsedBodyLength == Parser->ContentLength) {
   1183         Parser->State = BodyParserComplete;
   1184         if (Parser->Callback != NULL) {
   1185           Status = Parser->Callback (
   1186                      BodyParseEventOnComplete,
   1187                      Char,
   1188                      0,
   1189                      Parser->Context
   1190                      );
   1191           if (EFI_ERROR (Status)) {
   1192             return Status;
   1193           }
   1194         }
   1195       }
   1196       break;
   1197 
   1198     case BodyParserChunkSizeStart:
   1199       //
   1200       // First byte of chunk-size, the chunk-size might be truncated.
   1201       //
   1202       Parser->CurrentChunkSize = 0;
   1203       Parser->State = BodyParserChunkSize;
   1204     case BodyParserChunkSize:
   1205       if (!NET_IS_HEX_CHAR (*Char)) {
   1206         if (*Char == ';') {
   1207           Parser->State = BodyParserChunkExtStart;
   1208           Char++;
   1209         } else if (*Char == '\r') {
   1210           Parser->State = BodyParserChunkSizeEndCR;
   1211           Char++;
   1212         } else {
   1213           Parser->State = BodyParserStateMax;
   1214         }
   1215         break;
   1216       }
   1217 
   1218       if (Parser->CurrentChunkSize > (((~((UINTN) 0)) - 16) / 16)) {
   1219         return EFI_INVALID_PARAMETER;
   1220       }
   1221       Parser->CurrentChunkSize = Parser->CurrentChunkSize * 16 + HttpIoHexCharToUintn (*Char);
   1222       Char++;
   1223       break;
   1224 
   1225     case BodyParserChunkExtStart:
   1226       //
   1227       // Ignore all the chunk extensions.
   1228       //
   1229       if (*Char == '\r') {
   1230         Parser->State = BodyParserChunkSizeEndCR;
   1231        }
   1232       Char++;
   1233       break;
   1234 
   1235     case BodyParserChunkSizeEndCR:
   1236       if (*Char != '\n') {
   1237         Parser->State = BodyParserStateMax;
   1238         break;
   1239       }
   1240       Char++;
   1241       if (Parser->CurrentChunkSize == 0) {
   1242         //
   1243         // The last chunk has been parsed and now assumed the state
   1244         // of HttpBodyParse is ParserLastCRLF. So it need to decide
   1245         // whether the rest message is trailer or last CRLF in the next round.
   1246         //
   1247         Parser->ContentLengthIsValid = TRUE;
   1248         Parser->State = BodyParserLastCRLF;
   1249         break;
   1250       }
   1251       Parser->State = BodyParserChunkDataStart;
   1252       Parser->CurrentChunkParsedSize = 0;
   1253       break;
   1254 
   1255     case BodyParserLastCRLF:
   1256       //
   1257       // Judge the byte is belong to the Last CRLF or trailer, and then
   1258       // configure the state of HttpBodyParse to corresponding state.
   1259       //
   1260       if (*Char == '\r') {
   1261         Char++;
   1262         Parser->State = BodyParserLastCRLFEnd;
   1263         break;
   1264       } else {
   1265         Parser->State = BodyParserTrailer;
   1266         break;
   1267       }
   1268 
   1269     case BodyParserLastCRLFEnd:
   1270       if (*Char == '\n') {
   1271         Parser->State = BodyParserComplete;
   1272         Char++;
   1273         if (Parser->Callback != NULL) {
   1274           Status = Parser->Callback (
   1275                      BodyParseEventOnComplete,
   1276                      Char,
   1277                      0,
   1278                      Parser->Context
   1279                      );
   1280           if (EFI_ERROR (Status)) {
   1281             return Status;
   1282           }
   1283         }
   1284         break;
   1285       } else {
   1286         Parser->State = BodyParserStateMax;
   1287         break;
   1288       }
   1289 
   1290     case BodyParserTrailer:
   1291       if (*Char == '\r') {
   1292         Parser->State = BodyParserChunkSizeEndCR;
   1293       }
   1294       Char++;
   1295       break;
   1296 
   1297     case BodyParserChunkDataStart:
   1298       //
   1299       // First byte of chunk-data, the chunk data also might be truncated.
   1300       //
   1301       RemainderLengthInThis = BodyLength - (Char - Body);
   1302       LengthForCallback = MIN (Parser->CurrentChunkSize - Parser->CurrentChunkParsedSize, RemainderLengthInThis);
   1303       if (Parser->Callback != NULL) {
   1304         Status = Parser->Callback (
   1305                    BodyParseEventOnData,
   1306                    Char,
   1307                    LengthForCallback,
   1308                    Parser->Context
   1309                    );
   1310         if (EFI_ERROR (Status)) {
   1311           return Status;
   1312         }
   1313       }
   1314       Char += LengthForCallback;
   1315       Parser->ContentLength += LengthForCallback;
   1316       Parser->CurrentChunkParsedSize += LengthForCallback;
   1317       if (Parser->CurrentChunkParsedSize == Parser->CurrentChunkSize) {
   1318         Parser->State = BodyParserChunkDataEnd;
   1319       }
   1320       break;
   1321 
   1322     case BodyParserChunkDataEnd:
   1323       if (*Char == '\r') {
   1324         Parser->State = BodyParserChunkDataEndCR;
   1325       } else {
   1326         Parser->State = BodyParserStateMax;
   1327       }
   1328       Char++;
   1329       break;
   1330 
   1331     case BodyParserChunkDataEndCR:
   1332       if (*Char != '\n') {
   1333         Parser->State = BodyParserStateMax;
   1334         break;
   1335       }
   1336       Char++;
   1337       Parser->State = BodyParserChunkSizeStart;
   1338       break;
   1339 
   1340     default:
   1341       break;
   1342     }
   1343 
   1344   }
   1345 
   1346   if (Parser->State == BodyParserStateMax) {
   1347     return EFI_ABORTED;
   1348   }
   1349 
   1350   return EFI_SUCCESS;
   1351 }
   1352 
   1353 /**
   1354   Check whether the message-body is complete or not.
   1355 
   1356   @param[in]    MsgParser            Pointer to the message parser.
   1357 
   1358   @retval TRUE                       Message-body is complete.
   1359   @retval FALSE                      Message-body is not complete.
   1360 
   1361 **/
   1362 BOOLEAN
   1363 EFIAPI
   1364 HttpIsMessageComplete (
   1365   IN VOID              *MsgParser
   1366   )
   1367 {
   1368   HTTP_BODY_PARSER      *Parser;
   1369 
   1370   Parser = (HTTP_BODY_PARSER*) MsgParser;
   1371 
   1372   if (Parser->State == BodyParserComplete) {
   1373     return TRUE;
   1374   }
   1375   return FALSE;
   1376 }
   1377 
   1378 /**
   1379   Get the content length of the entity.
   1380 
   1381   Note that in trunk transfer, the entity length is not valid until the whole message body is received.
   1382 
   1383   @param[in]    MsgParser            Pointer to the message parser.
   1384   @param[out]   ContentLength        Pointer to store the length of the entity.
   1385 
   1386   @retval EFI_SUCCESS                Successfully to get the entity length.
   1387   @retval EFI_NOT_READY              Entity length is not valid yet.
   1388   @retval EFI_INVALID_PARAMETER      MsgParser is NULL or ContentLength is NULL.
   1389 
   1390 **/
   1391 EFI_STATUS
   1392 EFIAPI
   1393 HttpGetEntityLength (
   1394   IN  VOID              *MsgParser,
   1395   OUT UINTN             *ContentLength
   1396   )
   1397 {
   1398   HTTP_BODY_PARSER      *Parser;
   1399 
   1400   if (MsgParser == NULL || ContentLength == NULL) {
   1401     return EFI_INVALID_PARAMETER;
   1402   }
   1403 
   1404   Parser = (HTTP_BODY_PARSER*) MsgParser;
   1405 
   1406   if (!Parser->ContentLengthIsValid) {
   1407     return EFI_NOT_READY;
   1408   }
   1409 
   1410   *ContentLength = Parser->ContentLength;
   1411   return EFI_SUCCESS;
   1412 }
   1413 
   1414 /**
   1415   Release the resource of the message parser.
   1416 
   1417   @param[in]    MsgParser            Pointer to the message parser.
   1418 
   1419 **/
   1420 VOID
   1421 EFIAPI
   1422 HttpFreeMsgParser (
   1423   IN  VOID           *MsgParser
   1424   )
   1425 {
   1426   FreePool (MsgParser);
   1427 }
   1428