X-Git-Url: https://git.proxmox.com/?p=mirror_edk2.git;a=blobdiff_plain;f=MdeModulePkg%2FLibrary%2FDxeHttpLib%2FDxeHttpLib.c;h=8b74554cd96157b2cb788b1c32f9c50a6664ef9f;hp=49fa80ba8c30d6a6bae20c299e90141b8b7c97d1;hb=c0fd7f734e2d33e22215899b40a47b843129541d;hpb=b8b65a0320c7f8ec797171b335dfda2456528d57
diff --git a/MdeModulePkg/Library/DxeHttpLib/DxeHttpLib.c b/MdeModulePkg/Library/DxeHttpLib/DxeHttpLib.c
index 49fa80ba8c..8b74554cd9 100644
--- a/MdeModulePkg/Library/DxeHttpLib/DxeHttpLib.c
+++ b/MdeModulePkg/Library/DxeHttpLib/DxeHttpLib.c
@@ -2,86 +2,22 @@
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.
-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
-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.
+Copyright (c) 2015 - 2019, Intel Corporation. All rights reserved.
+(C) Copyright 2016 Hewlett Packard Enterprise Development LP
+SPDX-License-Identifier: BSD-2-Clause-Patent
**/
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-
-#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;
+#include "DxeHttpLib.h"
-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,
- UrlParserHostIpv6, // "["(Ipv6 address) "]"
- 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
+
+ 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.
+ in bytes.
@param[in] Buffer The pointer to a percent-encoded URI component.
@param[in] BufferLength Length of Buffer in bytes.
@@ -90,7 +26,7 @@ typedef enum {
@retval EFI_SUCCESS Successfully decoded the URI.
@retval EFI_INVALID_PARAMETER Buffer is not a valid percent-encoded string.
-
+
**/
EFI_STATUS
EFIAPI
@@ -108,13 +44,14 @@ UriPercentDecode (
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])) {
+ if (Index + 1 >= BufferLength || Index + 2 >= BufferLength ||
+ !NET_IS_HEX_CHAR (Buffer[Index+1]) || !NET_IS_HEX_CHAR (Buffer[Index+2])) {
return EFI_INVALID_PARAMETER;
}
HexStr[0] = Buffer[Index+1];
@@ -129,18 +66,18 @@ UriPercentDecode (
}
*ResultLength = (UINT32) Offset;
-
+
return EFI_SUCCESS;
}
/**
- This function return the updated state accroding to the input state and next character of
+ This function return the updated state according 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.
- @param[in] IsRightBracket TRUE if there is an sign ']' in the authority component and
- indicates the next part is ':' before Port.
+ @param[in] IsRightBracket TRUE if there is an sign ']' in the authority component and
+ indicates the next part is ':' before Port.
@return Updated state value.
**/
@@ -173,27 +110,27 @@ NetHttpParseAuthorityChar (
break;
case UrlParserHost:
- case UrlParserHostStart:
+ case UrlParserHostStart:
if (Char == '[') {
return UrlParserHostIpv6;
}
-
+
if (Char == ':') {
return UrlParserPortStart;
}
-
+
return UrlParserHost;
-
- case UrlParserHostIpv6:
+
+ case UrlParserHostIpv6:
if (Char == ']') {
*IsRightBracket = TRUE;
}
-
+
if (Char == ':' && *IsRightBracket) {
return UrlParserPortStart;
}
return UrlParserHostIpv6;
-
+
case UrlParserPort:
case UrlParserPortStart:
return UrlParserPort;
@@ -213,7 +150,7 @@ NetHttpParseAuthorityChar (
@param[in, out] UrlParser Pointer to the buffer of the parse result.
@retval EFI_SUCCESS Successfully parse the authority.
- @retval Other Error happened.
+ @retval EFI_INVALID_PARAMETER The Url is invalid to parse the authority component.
**/
EFI_STATUS
@@ -230,7 +167,7 @@ NetHttpParseAuthority (
UINT32 Field;
UINT32 OldField;
BOOLEAN IsrightBracket;
-
+
ASSERT ((UrlParser->FieldBitMap & BIT (HTTP_URI_FIELD_AUTHORITY)) != 0);
//
@@ -260,7 +197,7 @@ NetHttpParseAuthority (
case UrlParserUserInfo:
Field = HTTP_URI_FIELD_USERINFO;
break;
-
+
case UrlParserHost:
Field = HTTP_URI_FIELD_HOST;
break;
@@ -268,7 +205,7 @@ NetHttpParseAuthority (
case UrlParserHostIpv6:
Field = HTTP_URI_FIELD_HOST;
break;
-
+
case UrlParserPort:
Field = HTTP_URI_FIELD_PORT;
break;
@@ -299,7 +236,7 @@ NetHttpParseAuthority (
}
/**
- This function return the updated state accroding to the input state and next character of a URL.
+ This function return the updated state according 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.
@@ -316,12 +253,12 @@ NetHttpParseUrlChar (
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 ]
@@ -390,7 +327,7 @@ NetHttpParseUrlChar (
case UrlParserFragmentStart:
return UrlParserFragment;
-
+
default:
break;
}
@@ -430,7 +367,9 @@ HttpParseUrl (
BOOLEAN FoundAt;
EFI_STATUS Status;
HTTP_URL_PARSER *Parser;
-
+
+ Parser = NULL;
+
if (Url == NULL || Length == 0 || UrlParser == NULL) {
return EFI_INVALID_PARAMETER;
}
@@ -439,7 +378,7 @@ HttpParseUrl (
if (Parser == NULL) {
return EFI_OUT_OF_RESOURCES;
}
-
+
if (IsConnectMethod) {
//
// According to RFC 2616, the authority form is only used by the CONNECT method.
@@ -454,14 +393,15 @@ HttpParseUrl (
FoundAt = FALSE;
for (Char = Url; Char < Url + Length; Char++) {
//
- // Update state machine accoring to next char.
+ // Update state machine according to next char.
//
State = NetHttpParseUrlChar (*Char, State);
switch (State) {
case UrlParserStateMax:
+ FreePool (Parser);
return EFI_INVALID_PARAMETER;
-
+
case UrlParserSchemeColon:
case UrlParserSchemeColonSlash:
case UrlParserSchemeColonSlashSlash:
@@ -471,7 +411,7 @@ HttpParseUrl (
// Skip all the delimiting char: "://" "?" "@"
//
continue;
-
+
case UrlParserScheme:
Field = HTTP_URI_FIELD_SCHEME;
break;
@@ -522,12 +462,13 @@ HttpParseUrl (
if ((Parser->FieldBitMap & BIT (HTTP_URI_FIELD_AUTHORITY)) != 0) {
Status = NetHttpParseAuthority (Url, FoundAt, Parser);
if (EFI_ERROR (Status)) {
+ FreePool (Parser);
return Status;
}
}
*UrlParser = Parser;
- return EFI_SUCCESS;
+ return EFI_SUCCESS;
}
/**
@@ -544,7 +485,7 @@ HttpParseUrl (
@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
@@ -563,7 +504,7 @@ HttpUrlGetHostName (
return EFI_INVALID_PARAMETER;
}
- Parser = (HTTP_URL_PARSER*) UrlParser;
+ Parser = (HTTP_URL_PARSER *) UrlParser;
if ((Parser->FieldBitMap & BIT (HTTP_URI_FIELD_HOST)) == 0) {
return EFI_NOT_FOUND;
@@ -573,7 +514,7 @@ HttpUrlGetHostName (
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,
@@ -581,6 +522,7 @@ HttpUrlGetHostName (
&ResultLength
);
if (EFI_ERROR (Status)) {
+ FreePool (Name);
return Status;
}
@@ -603,7 +545,7 @@ HttpUrlGetHostName (
@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
@@ -617,22 +559,22 @@ HttpUrlGetIp4 (
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;
+ Parser = (HTTP_URL_PARSER *) UrlParser;
if ((Parser->FieldBitMap & BIT (HTTP_URI_FIELD_HOST)) == 0) {
- return EFI_INVALID_PARAMETER;
+ return EFI_NOT_FOUND;
}
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,
@@ -640,6 +582,7 @@ HttpUrlGetIp4 (
&ResultLength
);
if (EFI_ERROR (Status)) {
+ FreePool (Ip4String);
return Status;
}
@@ -663,7 +606,7 @@ HttpUrlGetIp4 (
@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
@@ -679,15 +622,15 @@ HttpUrlGetIp6 (
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;
+ Parser = (HTTP_URL_PARSER *) UrlParser;
if ((Parser->FieldBitMap & BIT (HTTP_URI_FIELD_HOST)) == 0) {
- return EFI_INVALID_PARAMETER;
+ return EFI_NOT_FOUND;
}
//
@@ -707,7 +650,7 @@ HttpUrlGetIp6 (
if (Ip6String == NULL) {
return EFI_OUT_OF_RESOURCES;
}
-
+
Status = UriPercentDecode (
Ptr + 1,
Length - 2,
@@ -715,9 +658,10 @@ HttpUrlGetIp6 (
&ResultLength
);
if (EFI_ERROR (Status)) {
+ FreePool (Ip6String);
return Status;
}
-
+
Ip6String[ResultLength] = '\0';
Status = NetLibAsciiStrToIp6 (Ip6String, Ip6Address);
FreePool (Ip6String);
@@ -738,7 +682,7 @@ HttpUrlGetIp6 (
@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
@@ -748,19 +692,24 @@ HttpUrlGetPort (
OUT UINT16 *Port
)
{
- CHAR8 *PortString;
- EFI_STATUS Status;
- UINT32 ResultLength;
+ CHAR8 *PortString;
+ EFI_STATUS Status;
+ UINTN Index;
+ UINTN Data;
+ UINT32 ResultLength;
HTTP_URL_PARSER *Parser;
if (Url == NULL || UrlParser == NULL || Port == NULL) {
return EFI_INVALID_PARAMETER;
}
- Parser = (HTTP_URL_PARSER*) UrlParser;
+ *Port = 0;
+ Index = 0;
+
+ Parser = (HTTP_URL_PARSER *) UrlParser;
if ((Parser->FieldBitMap & BIT (HTTP_URI_FIELD_PORT)) == 0) {
- return EFI_INVALID_PARAMETER;
+ return EFI_NOT_FOUND;
}
PortString = AllocatePool (Parser->FieldData[HTTP_URI_FIELD_PORT].Length + 1);
@@ -775,20 +724,98 @@ HttpUrlGetPort (
&ResultLength
);
if (EFI_ERROR (Status)) {
- return Status;
+ goto ON_EXIT;
}
PortString[ResultLength] = '\0';
- *Port = (UINT16) AsciiStrDecimalToUintn (Url + Parser->FieldData[HTTP_URI_FIELD_PORT].Offset);
- return EFI_SUCCESS;
+ while (Index < ResultLength) {
+ if (!NET_IS_DIGIT (PortString[Index])) {
+ Status = EFI_INVALID_PARAMETER;
+ goto ON_EXIT;
+ }
+ Index ++;
+ }
+
+ Status = AsciiStrDecimalToUintnS (Url + Parser->FieldData[HTTP_URI_FIELD_PORT].Offset, (CHAR8 **) NULL, &Data);
+
+ if (Data > HTTP_URI_PORT_MAX_NUM) {
+ Status = EFI_INVALID_PARAMETER;
+ goto ON_EXIT;
+ }
+
+ *Port = (UINT16) Data;
+
+ON_EXIT:
+ FreePool (PortString);
+ return Status;
+}
+
+/**
+ Get the Path from a HTTP URL.
+
+ This function will return the Path according to the Url and previous parse result,and
+ it is the caller's responsibility to free the buffer returned in *Path.
+
+ @param[in] Url The pointer to a HTTP URL string.
+ @param[in] UrlParser URL Parse result returned by NetHttpParseUrl().
+ @param[out] Path Pointer to a buffer to store the Path.
+
+ @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
+HttpUrlGetPath (
+ IN CHAR8 *Url,
+ IN VOID *UrlParser,
+ OUT CHAR8 **Path
+ )
+{
+ CHAR8 *PathStr;
+ EFI_STATUS Status;
+ UINT32 ResultLength;
+ HTTP_URL_PARSER *Parser;
+
+ if (Url == NULL || UrlParser == NULL || Path == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Parser = (HTTP_URL_PARSER *) UrlParser;
+
+ if ((Parser->FieldBitMap & BIT (HTTP_URI_FIELD_PATH)) == 0) {
+ return EFI_NOT_FOUND;
+ }
+
+ PathStr = AllocatePool (Parser->FieldData[HTTP_URI_FIELD_PATH].Length + 1);
+ if (PathStr == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ Status = UriPercentDecode (
+ Url + Parser->FieldData[HTTP_URI_FIELD_PATH].Offset,
+ Parser->FieldData[HTTP_URI_FIELD_PATH].Length,
+ PathStr,
+ &ResultLength
+ );
+ if (EFI_ERROR (Status)) {
+ FreePool (PathStr);
+ return Status;
+ }
+
+ PathStr[ResultLength] = '\0';
+ *Path = PathStr;
+ return EFI_SUCCESS;
}
/**
Release the resource of the URL parser.
@param[in] UrlParser Pointer to the parser.
-
+
**/
VOID
EFIAPI
@@ -802,22 +829,23 @@ HttpUrlFreeParser (
/**
Find a specified header field according to the field name.
- @param[in] HeaderCount Number of HTTP header structures in Headers list.
+ @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.
+ @param[in] FieldName Null terminated string which describes a field name.
@return Pointer to the found header or NULL.
**/
EFI_HTTP_HEADER *
-HttpIoFindHeader (
+EFIAPI
+HttpFindHeader (
IN UINTN HeaderCount,
IN EFI_HTTP_HEADER *Headers,
IN CHAR8 *FieldName
)
{
UINTN Index;
-
+
if (HeaderCount == 0 || Headers == NULL || FieldName == NULL) {
return NULL;
}
@@ -855,7 +883,7 @@ typedef struct {
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;
@@ -864,27 +892,6 @@ typedef struct {
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.
@@ -902,7 +909,7 @@ HttpIoHexCharToUintn (
return Char - '0';
}
- return (10 + HttpIoCharToUpper (Char) - 'A');
+ return (10 + AsciiCharToUpper (Char) - 'A');
}
/**
@@ -924,14 +931,13 @@ HttpIoParseContentLengthHeader (
)
{
EFI_HTTP_HEADER *Header;
-
- Header = HttpIoFindHeader (HeaderCount, Headers, "Content-Length");
+
+ Header = HttpFindHeader (HeaderCount, Headers, HTTP_HEADER_CONTENT_LENGTH);
if (Header == NULL) {
return EFI_NOT_FOUND;
}
- *ContentLength = AsciiStrDecimalToUintn (Header->FieldValue);
- return EFI_SUCCESS;
+ return AsciiStrDecimalToUintnS (Header->FieldValue, (CHAR8 **) NULL, ContentLength);
}
/**
@@ -942,7 +948,7 @@ HttpIoParseContentLengthHeader (
@param[in] Headers Array containing list of HTTP headers.
@return The message is "chunked" transfer-coding (TRUE) or not (FALSE).
-
+
**/
BOOLEAN
HttpIoIsChunked (
@@ -953,7 +959,7 @@ HttpIoIsChunked (
EFI_HTTP_HEADER *Header;
- Header = HttpIoFindHeader (HeaderCount, Headers, "Transfer-Encoding");
+ Header = HttpFindHeader (HeaderCount, Headers, HTTP_HEADER_TRANSFER_ENCODING);
if (Header == NULL) {
return FALSE;
}
@@ -1039,7 +1045,7 @@ HttpInitMsgParser (
{
EFI_STATUS Status;
HTTP_BODY_PARSER *Parser;
-
+
if (HeaderCount != 0 && Headers == NULL) {
return EFI_INVALID_PARAMETER;
}
@@ -1054,9 +1060,9 @@ HttpInitMsgParser (
}
Parser->State = BodyParserBodyStart;
-
+
//
- // Determine the message length accroding to RFC 2616.
+ // Determine the message length according to RFC 2616.
// 1. Check whether the message "MUST NOT" have a message-body.
//
Parser->IgnoreBody = HttpIoNoMessageBody (Method, StatusCode);
@@ -1075,7 +1081,7 @@ HttpInitMsgParser (
// 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.
//
@@ -1101,7 +1107,8 @@ HttpInitMsgParser (
@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.
+ @retval EFI_ABORTED Operation aborted.
+ @retval Other Error happened while parsing message body.
**/
EFI_STATUS
@@ -1117,7 +1124,7 @@ HttpParseMessageBody (
UINTN LengthForCallback;
EFI_STATUS Status;
HTTP_BODY_PARSER *Parser;
-
+
if (BodyLength == 0 || Body == NULL) {
return EFI_INVALID_PARAMETER;
}
@@ -1126,17 +1133,17 @@ HttpParseMessageBody (
return EFI_INVALID_PARAMETER;
}
- Parser = (HTTP_BODY_PARSER*) MsgParser;
+ Parser = (HTTP_BODY_PARSER *) MsgParser;
if (Parser->IgnoreBody) {
Parser->State = BodyParserComplete;
if (Parser->Callback != NULL) {
Status = Parser->Callback (
- BodyParseEventOnComplete,
- Body,
- 0,
- Parser->Context
- );
+ BodyParseEventOnComplete,
+ Body,
+ 0,
+ Parser->Context
+ );
if (EFI_ERROR (Status)) {
return Status;
}
@@ -1162,31 +1169,17 @@ HttpParseMessageBody (
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
- );
+ BodyParseEventOnData,
+ Char,
+ MIN (BodyLength, Parser->ContentLength - Parser->ParsedBodyLength),
+ Parser->Context
+ );
if (EFI_ERROR (Status)) {
return Status;
}
@@ -1195,6 +1188,17 @@ HttpParseMessageBody (
Parser->ParsedBodyLength += MIN (BodyLength, Parser->ContentLength - Parser->ParsedBodyLength);
if (Parser->ParsedBodyLength == Parser->ContentLength) {
Parser->State = BodyParserComplete;
+ if (Parser->Callback != NULL) {
+ Status = Parser->Callback (
+ BodyParseEventOnComplete,
+ Char,
+ 0,
+ Parser->Context
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
}
break;
@@ -1234,7 +1238,7 @@ HttpParseMessageBody (
}
Char++;
break;
-
+
case BodyParserChunkSizeEndCR:
if (*Char != '\n') {
Parser->State = BodyParserStateMax;
@@ -1243,7 +1247,7 @@ HttpParseMessageBody (
Char++;
if (Parser->CurrentChunkSize == 0) {
//
- // The last chunk has been parsed and now assumed the state
+ // The last chunk has been parsed and now assumed the state
// of HttpBodyParse is ParserLastCRLF. So it need to decide
// whether the rest message is trailer or last CRLF in the next round.
//
@@ -1254,10 +1258,10 @@ HttpParseMessageBody (
Parser->State = BodyParserChunkDataStart;
Parser->CurrentChunkParsedSize = 0;
break;
-
+
case BodyParserLastCRLF:
//
- // Judge the byte is belong to the Last CRLF or trailer, and then
+ // Judge the byte is belong to the Last CRLF or trailer, and then
// configure the state of HttpBodyParse to corresponding state.
//
if (*Char == '\r') {
@@ -1268,22 +1272,34 @@ HttpParseMessageBody (
Parser->State = BodyParserTrailer;
break;
}
-
+
case BodyParserLastCRLFEnd:
if (*Char == '\n') {
Parser->State = BodyParserComplete;
+ Char++;
+ if (Parser->Callback != NULL) {
+ Status = Parser->Callback (
+ BodyParseEventOnComplete,
+ Char,
+ 0,
+ Parser->Context
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
break;
} else {
Parser->State = BodyParserStateMax;
break;
}
-
+
case BodyParserTrailer:
if (*Char == '\r') {
Parser->State = BodyParserChunkSizeEndCR;
}
Char++;
- break;
+ break;
case BodyParserChunkDataStart:
//
@@ -1293,11 +1309,11 @@ HttpParseMessageBody (
LengthForCallback = MIN (Parser->CurrentChunkSize - Parser->CurrentChunkParsedSize, RemainderLengthInThis);
if (Parser->Callback != NULL) {
Status = Parser->Callback (
- BodyParseEventOnData,
- Char,
- LengthForCallback,
- Parser->Context
- );
+ BodyParseEventOnData,
+ Char,
+ LengthForCallback,
+ Parser->Context
+ );
if (EFI_ERROR (Status)) {
return Status;
}
@@ -1307,7 +1323,7 @@ HttpParseMessageBody (
Parser->CurrentChunkParsedSize += LengthForCallback;
if (Parser->CurrentChunkParsedSize == Parser->CurrentChunkSize) {
Parser->State = BodyParserChunkDataEnd;
- }
+ }
break;
case BodyParserChunkDataEnd:
@@ -1326,7 +1342,7 @@ HttpParseMessageBody (
}
Char++;
Parser->State = BodyParserChunkSizeStart;
- break;
+ break;
default:
break;
@@ -1358,7 +1374,11 @@ HttpIsMessageComplete (
{
HTTP_BODY_PARSER *Parser;
- Parser = (HTTP_BODY_PARSER*) MsgParser;
+ if (MsgParser == NULL) {
+ return FALSE;
+ }
+
+ Parser = (HTTP_BODY_PARSER *) MsgParser;
if (Parser->State == BodyParserComplete) {
return TRUE;
@@ -1377,7 +1397,7 @@ HttpIsMessageComplete (
@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
@@ -1392,7 +1412,7 @@ HttpGetEntityLength (
return EFI_INVALID_PARAMETER;
}
- Parser = (HTTP_BODY_PARSER*) MsgParser;
+ Parser = (HTTP_BODY_PARSER *) MsgParser;
if (!Parser->ContentLengthIsValid) {
return EFI_NOT_READY;
@@ -1406,7 +1426,7 @@ HttpGetEntityLength (
Release the resource of the message parser.
@param[in] MsgParser Pointer to the message parser.
-
+
**/
VOID
EFIAPI
@@ -1416,3 +1436,649 @@ HttpFreeMsgParser (
{
FreePool (MsgParser);
}
+
+
+/**
+ Get the next string, which is distinguished by specified separator.
+
+ @param[in] String Pointer to the string.
+ @param[in] Separator Specified separator used to distinguish where is the beginning
+ of next string.
+
+ @return Pointer to the next string.
+ @return NULL if not find or String is NULL.
+
+**/
+CHAR8 *
+AsciiStrGetNextToken (
+ IN CONST CHAR8 *String,
+ IN CHAR8 Separator
+ )
+{
+ CONST CHAR8 *Token;
+
+ Token = String;
+ while (TRUE) {
+ if (*Token == 0) {
+ return NULL;
+ }
+ if (*Token == Separator) {
+ return (CHAR8 *)(Token + 1);
+ }
+ Token++;
+ }
+}
+
+/**
+ Set FieldName and FieldValue into specified HttpHeader.
+
+ @param[in,out] HttpHeader Specified HttpHeader.
+ @param[in] FieldName FieldName of this HttpHeader, a NULL terminated ASCII string.
+ @param[in] FieldValue FieldValue of this HttpHeader, a NULL terminated ASCII string.
+
+
+ @retval EFI_SUCCESS The FieldName and FieldValue are set into HttpHeader successfully.
+ @retval EFI_INVALID_PARAMETER The parameter is invalid.
+ @retval EFI_OUT_OF_RESOURCES Failed to allocate resources.
+
+**/
+EFI_STATUS
+EFIAPI
+HttpSetFieldNameAndValue (
+ IN OUT EFI_HTTP_HEADER *HttpHeader,
+ IN CONST CHAR8 *FieldName,
+ IN CONST CHAR8 *FieldValue
+ )
+{
+ UINTN FieldNameSize;
+ UINTN FieldValueSize;
+
+ if (HttpHeader == NULL || FieldName == NULL || FieldValue == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (HttpHeader->FieldName != NULL) {
+ FreePool (HttpHeader->FieldName);
+ }
+ if (HttpHeader->FieldValue != NULL) {
+ FreePool (HttpHeader->FieldValue);
+ }
+
+ FieldNameSize = AsciiStrSize (FieldName);
+ HttpHeader->FieldName = AllocateZeroPool (FieldNameSize);
+ if (HttpHeader->FieldName == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ CopyMem (HttpHeader->FieldName, FieldName, FieldNameSize);
+ HttpHeader->FieldName[FieldNameSize - 1] = 0;
+
+ FieldValueSize = AsciiStrSize (FieldValue);
+ HttpHeader->FieldValue = AllocateZeroPool (FieldValueSize);
+ if (HttpHeader->FieldValue == NULL) {
+ FreePool (HttpHeader->FieldName);
+ return EFI_OUT_OF_RESOURCES;
+ }
+ CopyMem (HttpHeader->FieldValue, FieldValue, FieldValueSize);
+ HttpHeader->FieldValue[FieldValueSize - 1] = 0;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Get one key/value header pair from the raw string.
+
+ @param[in] String Pointer to the raw string.
+ @param[out] FieldName Points directly to field name within 'HttpHeader'.
+ @param[out] FieldValue Points directly to field value within 'HttpHeader'.
+
+ @return Pointer to the next raw string.
+ @return NULL if no key/value header pair from this raw string.
+
+**/
+CHAR8 *
+EFIAPI
+HttpGetFieldNameAndValue (
+ IN CHAR8 *String,
+ OUT CHAR8 **FieldName,
+ OUT CHAR8 **FieldValue
+ )
+{
+ CHAR8 *FieldNameStr;
+ CHAR8 *FieldValueStr;
+ CHAR8 *StrPtr;
+ CHAR8 *EndofHeader;
+
+ if (String == NULL || FieldName == NULL || FieldValue == NULL) {
+ return NULL;
+ }
+
+ *FieldName = NULL;
+ *FieldValue = NULL;
+ FieldNameStr = NULL;
+ FieldValueStr = NULL;
+ StrPtr = NULL;
+ EndofHeader = NULL;
+
+
+ //
+ // Check whether the raw HTTP header string is valid or not.
+ //
+ EndofHeader = AsciiStrStr (String, "\r\n\r\n");
+ if (EndofHeader == NULL) {
+ return NULL;
+ }
+
+ //
+ // Each header field consists of a name followed by a colon (":") and the field value.
+ // The field value MAY be preceded by any amount of LWS, though a single SP is preferred.
+ //
+ // message-header = field-name ":" [ field-value ]
+ // field-name = token
+ // field-value = *( field-content | LWS )
+ //
+ // Note: "*(element)" allows any number element, including zero; "1*(element)" requires at least one element.
+ // [element] means element is optional.
+ // LWS = [CRLF] 1*(SP|HT), it can be ' ' or '\t' or '\r\n ' or '\r\n\t'.
+ // CRLF = '\r\n'.
+ // SP = ' '.
+ // HT = '\t' (Tab).
+ //
+ FieldNameStr = String;
+ FieldValueStr = AsciiStrGetNextToken (FieldNameStr, ':');
+ if (FieldValueStr == NULL) {
+ return NULL;
+ }
+
+ //
+ // Replace ':' with 0, then FieldName has been retrived from String.
+ //
+ *(FieldValueStr - 1) = 0;
+
+ //
+ // Handle FieldValueStr, skip all the preceded LWS.
+ //
+ while (TRUE) {
+ if (*FieldValueStr == ' ' || *FieldValueStr == '\t') {
+ //
+ // Boundary condition check.
+ //
+ if ((UINTN) EndofHeader - (UINTN) FieldValueStr < 1) {
+ //
+ // Wrong String format!
+ //
+ return NULL;
+ }
+
+ FieldValueStr ++;
+ } else if (*FieldValueStr == '\r') {
+ //
+ // Boundary condition check.
+ //
+ if ((UINTN) EndofHeader - (UINTN) FieldValueStr < 3) {
+ //
+ // No more preceded LWS, so break here.
+ //
+ break;
+ }
+
+ if (*(FieldValueStr + 1) == '\n' ) {
+ if (*(FieldValueStr + 2) == ' ' || *(FieldValueStr + 2) == '\t') {
+ FieldValueStr = FieldValueStr + 3;
+ } else {
+ //
+ // No more preceded LWS, so break here.
+ //
+ break;
+ }
+ } else {
+ //
+ // Wrong String format!
+ //
+ return NULL;
+ }
+ } else {
+ //
+ // No more preceded LWS, so break here.
+ //
+ break;
+ }
+ }
+
+ StrPtr = FieldValueStr;
+ do {
+ //
+ // Handle the LWS within the field value.
+ //
+ StrPtr = AsciiStrGetNextToken (StrPtr, '\r');
+ if (StrPtr == NULL || *StrPtr != '\n') {
+ //
+ // Wrong String format!
+ //
+ return NULL;
+ }
+
+ StrPtr++;
+ } while (*StrPtr == ' ' || *StrPtr == '\t');
+
+ //
+ // Replace '\r' with 0
+ //
+ *(StrPtr - 2) = 0;
+
+ //
+ // Get FieldName and FieldValue.
+ //
+ *FieldName = FieldNameStr;
+ *FieldValue = FieldValueStr;
+
+ return StrPtr;
+}
+
+/**
+ Free existing HeaderFields.
+
+ @param[in] HeaderFields Pointer to array of key/value header pairs waitting for free.
+ @param[in] FieldCount The number of header pairs in HeaderFields.
+
+**/
+VOID
+EFIAPI
+HttpFreeHeaderFields (
+ IN EFI_HTTP_HEADER *HeaderFields,
+ IN UINTN FieldCount
+ )
+{
+ UINTN Index;
+
+ if (HeaderFields != NULL) {
+ for (Index = 0; Index < FieldCount; Index++) {
+ if (HeaderFields[Index].FieldName != NULL) {
+ FreePool (HeaderFields[Index].FieldName);
+ }
+ if (HeaderFields[Index].FieldValue != NULL) {
+ FreePool (HeaderFields[Index].FieldValue);
+ }
+ }
+
+ FreePool (HeaderFields);
+ }
+}
+
+/**
+ Generate HTTP request message.
+
+ This function will allocate memory for the whole HTTP message and generate a
+ well formatted HTTP Request message in it, include the Request-Line, header
+ fields and also the message body. It is the caller's responsibility to free
+ the buffer returned in *RequestMsg.
+
+ @param[in] Message Pointer to the EFI_HTTP_MESSAGE structure which
+ contains the required information to generate
+ the HTTP request message.
+ @param[in] Url The URL of a remote host.
+ @param[out] RequestMsg Pointer to the created HTTP request message.
+ NULL if any error occured.
+ @param[out] RequestMsgSize Size of the RequestMsg (in bytes).
+
+ @retval EFI_SUCCESS If HTTP request string was created successfully.
+ @retval EFI_OUT_OF_RESOURCES Failed to allocate resources.
+ @retval EFI_INVALID_PARAMETER The input arguments are invalid.
+
+**/
+EFI_STATUS
+EFIAPI
+HttpGenRequestMessage (
+ IN CONST EFI_HTTP_MESSAGE *Message,
+ IN CONST CHAR8 *Url,
+ OUT CHAR8 **RequestMsg,
+ OUT UINTN *RequestMsgSize
+ )
+{
+ EFI_STATUS Status;
+ UINTN StrLength;
+ CHAR8 *RequestPtr;
+ UINTN HttpHdrSize;
+ UINTN MsgSize;
+ BOOLEAN Success;
+ VOID *HttpHdr;
+ EFI_HTTP_HEADER **AppendList;
+ UINTN Index;
+ EFI_HTTP_UTILITIES_PROTOCOL *HttpUtilitiesProtocol;
+
+ Status = EFI_SUCCESS;
+ HttpHdrSize = 0;
+ MsgSize = 0;
+ Success = FALSE;
+ HttpHdr = NULL;
+ AppendList = NULL;
+ HttpUtilitiesProtocol = NULL;
+
+ //
+ // 1. If we have a Request, we cannot have a NULL Url
+ // 2. If we have a Request, HeaderCount can not be non-zero
+ // 3. If we do not have a Request, HeaderCount should be zero
+ // 4. If we do not have Request and Headers, we need at least a message-body
+ //
+ if ((Message == NULL || RequestMsg == NULL || RequestMsgSize == NULL) ||
+ (Message->Data.Request != NULL && Url == NULL) ||
+ (Message->Data.Request != NULL && Message->HeaderCount == 0) ||
+ (Message->Data.Request == NULL && Message->HeaderCount != 0) ||
+ (Message->Data.Request == NULL && Message->HeaderCount == 0 && Message->BodyLength == 0)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (Message->HeaderCount != 0) {
+ //
+ // Locate the HTTP_UTILITIES protocol.
+ //
+ Status = gBS->LocateProtocol (
+ &gEfiHttpUtilitiesProtocolGuid,
+ NULL,
+ (VOID **) &HttpUtilitiesProtocol
+ );
+
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR,"Failed to locate Http Utilities protocol. Status = %r.\n", Status));
+ return Status;
+ }
+
+ //
+ // Build AppendList to send into HttpUtilitiesBuild
+ //
+ AppendList = AllocateZeroPool (sizeof (EFI_HTTP_HEADER *) * (Message->HeaderCount));
+ if (AppendList == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ for(Index = 0; Index < Message->HeaderCount; Index++){
+ AppendList[Index] = &Message->Headers[Index];
+ }
+
+ //
+ // Build raw HTTP Headers
+ //
+ Status = HttpUtilitiesProtocol->Build (
+ HttpUtilitiesProtocol,
+ 0,
+ NULL,
+ 0,
+ NULL,
+ Message->HeaderCount,
+ AppendList,
+ &HttpHdrSize,
+ &HttpHdr
+ );
+
+ FreePool (AppendList);
+
+ if (EFI_ERROR (Status) || HttpHdr == NULL){
+ return Status;
+ }
+ }
+
+ //
+ // If we have headers to be sent, account for it.
+ //
+ if (Message->HeaderCount != 0) {
+ MsgSize = HttpHdrSize;
+ }
+
+ //
+ // If we have a request line, account for the fields.
+ //
+ if (Message->Data.Request != NULL) {
+ MsgSize += HTTP_METHOD_MAXIMUM_LEN + AsciiStrLen (HTTP_VERSION_CRLF_STR) + AsciiStrLen (Url);
+ }
+
+
+ //
+ // If we have a message body to be sent, account for it.
+ //
+ MsgSize += Message->BodyLength;
+
+ //
+ // memory for the string that needs to be sent to TCP
+ //
+ *RequestMsg = NULL;
+ *RequestMsg = AllocateZeroPool (MsgSize);
+ if (*RequestMsg == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Exit;
+ }
+
+ RequestPtr = *RequestMsg;
+ //
+ // Construct header request
+ //
+ if (Message->Data.Request != NULL) {
+ switch (Message->Data.Request->Method) {
+ case HttpMethodGet:
+ StrLength = sizeof (HTTP_METHOD_GET) - 1;
+ CopyMem (RequestPtr, HTTP_METHOD_GET, StrLength);
+ RequestPtr += StrLength;
+ break;
+ case HttpMethodPut:
+ StrLength = sizeof (HTTP_METHOD_PUT) - 1;
+ CopyMem (RequestPtr, HTTP_METHOD_PUT, StrLength);
+ RequestPtr += StrLength;
+ break;
+ case HttpMethodPatch:
+ StrLength = sizeof (HTTP_METHOD_PATCH) - 1;
+ CopyMem (RequestPtr, HTTP_METHOD_PATCH, StrLength);
+ RequestPtr += StrLength;
+ break;
+ case HttpMethodPost:
+ StrLength = sizeof (HTTP_METHOD_POST) - 1;
+ CopyMem (RequestPtr, HTTP_METHOD_POST, StrLength);
+ RequestPtr += StrLength;
+ break;
+ case HttpMethodHead:
+ StrLength = sizeof (HTTP_METHOD_HEAD) - 1;
+ CopyMem (RequestPtr, HTTP_METHOD_HEAD, StrLength);
+ RequestPtr += StrLength;
+ break;
+ case HttpMethodDelete:
+ StrLength = sizeof (HTTP_METHOD_DELETE) - 1;
+ CopyMem (RequestPtr, HTTP_METHOD_DELETE, StrLength);
+ RequestPtr += StrLength;
+ break;
+ default:
+ ASSERT (FALSE);
+ Status = EFI_INVALID_PARAMETER;
+ goto Exit;
+ }
+
+ StrLength = AsciiStrLen(EMPTY_SPACE);
+ CopyMem (RequestPtr, EMPTY_SPACE, StrLength);
+ RequestPtr += StrLength;
+
+ StrLength = AsciiStrLen (Url);
+ CopyMem (RequestPtr, Url, StrLength);
+ RequestPtr += StrLength;
+
+ StrLength = sizeof (HTTP_VERSION_CRLF_STR) - 1;
+ CopyMem (RequestPtr, HTTP_VERSION_CRLF_STR, StrLength);
+ RequestPtr += StrLength;
+
+ if (HttpHdr != NULL) {
+ //
+ // Construct header
+ //
+ CopyMem (RequestPtr, HttpHdr, HttpHdrSize);
+ RequestPtr += HttpHdrSize;
+ }
+ }
+
+ //
+ // Construct body
+ //
+ if (Message->Body != NULL) {
+ CopyMem (RequestPtr, Message->Body, Message->BodyLength);
+ RequestPtr += Message->BodyLength;
+ }
+
+ //
+ // Done
+ //
+ (*RequestMsgSize) = (UINTN)(RequestPtr) - (UINTN)(*RequestMsg);
+ Success = TRUE;
+
+Exit:
+
+ if (!Success) {
+ if (*RequestMsg != NULL) {
+ FreePool (*RequestMsg);
+ }
+ *RequestMsg = NULL;
+ return Status;
+ }
+
+ if (HttpHdr != NULL) {
+ FreePool (HttpHdr);
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Translate the status code in HTTP message to EFI_HTTP_STATUS_CODE defined
+ in UEFI 2.5 specification.
+
+ @param[in] StatusCode The status code value in HTTP message.
+
+ @return Value defined in EFI_HTTP_STATUS_CODE .
+
+**/
+EFI_HTTP_STATUS_CODE
+EFIAPI
+HttpMappingToStatusCode (
+ IN UINTN StatusCode
+ )
+{
+ switch (StatusCode) {
+ case 100:
+ return HTTP_STATUS_100_CONTINUE;
+ case 101:
+ return HTTP_STATUS_101_SWITCHING_PROTOCOLS;
+ case 200:
+ return HTTP_STATUS_200_OK;
+ case 201:
+ return HTTP_STATUS_201_CREATED;
+ case 202:
+ return HTTP_STATUS_202_ACCEPTED;
+ case 203:
+ return HTTP_STATUS_203_NON_AUTHORITATIVE_INFORMATION;
+ case 204:
+ return HTTP_STATUS_204_NO_CONTENT;
+ case 205:
+ return HTTP_STATUS_205_RESET_CONTENT;
+ case 206:
+ return HTTP_STATUS_206_PARTIAL_CONTENT;
+ case 300:
+ return HTTP_STATUS_300_MULTIPLE_CHOICES;
+ case 301:
+ return HTTP_STATUS_301_MOVED_PERMANENTLY;
+ case 302:
+ return HTTP_STATUS_302_FOUND;
+ case 303:
+ return HTTP_STATUS_303_SEE_OTHER;
+ case 304:
+ return HTTP_STATUS_304_NOT_MODIFIED;
+ case 305:
+ return HTTP_STATUS_305_USE_PROXY;
+ case 307:
+ return HTTP_STATUS_307_TEMPORARY_REDIRECT;
+ case 308:
+ return HTTP_STATUS_308_PERMANENT_REDIRECT;
+ case 400:
+ return HTTP_STATUS_400_BAD_REQUEST;
+ case 401:
+ return HTTP_STATUS_401_UNAUTHORIZED;
+ case 402:
+ return HTTP_STATUS_402_PAYMENT_REQUIRED;
+ case 403:
+ return HTTP_STATUS_403_FORBIDDEN;
+ case 404:
+ return HTTP_STATUS_404_NOT_FOUND;
+ case 405:
+ return HTTP_STATUS_405_METHOD_NOT_ALLOWED;
+ case 406:
+ return HTTP_STATUS_406_NOT_ACCEPTABLE;
+ case 407:
+ return HTTP_STATUS_407_PROXY_AUTHENTICATION_REQUIRED;
+ case 408:
+ return HTTP_STATUS_408_REQUEST_TIME_OUT;
+ case 409:
+ return HTTP_STATUS_409_CONFLICT;
+ case 410:
+ return HTTP_STATUS_410_GONE;
+ case 411:
+ return HTTP_STATUS_411_LENGTH_REQUIRED;
+ case 412:
+ return HTTP_STATUS_412_PRECONDITION_FAILED;
+ case 413:
+ return HTTP_STATUS_413_REQUEST_ENTITY_TOO_LARGE;
+ case 414:
+ return HTTP_STATUS_414_REQUEST_URI_TOO_LARGE;
+ case 415:
+ return HTTP_STATUS_415_UNSUPPORTED_MEDIA_TYPE;
+ case 416:
+ return HTTP_STATUS_416_REQUESTED_RANGE_NOT_SATISFIED;
+ case 417:
+ return HTTP_STATUS_417_EXPECTATION_FAILED;
+ case 500:
+ return HTTP_STATUS_500_INTERNAL_SERVER_ERROR;
+ case 501:
+ return HTTP_STATUS_501_NOT_IMPLEMENTED;
+ case 502:
+ return HTTP_STATUS_502_BAD_GATEWAY;
+ case 503:
+ return HTTP_STATUS_503_SERVICE_UNAVAILABLE;
+ case 504:
+ return HTTP_STATUS_504_GATEWAY_TIME_OUT;
+ case 505:
+ return HTTP_STATUS_505_HTTP_VERSION_NOT_SUPPORTED;
+
+ default:
+ return HTTP_STATUS_UNSUPPORTED_STATUS;
+ }
+}
+
+/**
+ Check whether header field called FieldName is in DeleteList.
+
+ @param[in] DeleteList Pointer to array of key/value header pairs.
+ @param[in] DeleteCount The number of header pairs.
+ @param[in] FieldName Pointer to header field's name.
+
+ @return TRUE if FieldName is not in DeleteList, that means this header field is valid.
+ @return FALSE if FieldName is in DeleteList, that means this header field is invalid.
+
+**/
+BOOLEAN
+EFIAPI
+HttpIsValidHttpHeader (
+ IN CHAR8 *DeleteList[],
+ IN UINTN DeleteCount,
+ IN CHAR8 *FieldName
+ )
+{
+ UINTN Index;
+
+ if (FieldName == NULL) {
+ return FALSE;
+ }
+
+ for (Index = 0; Index < DeleteCount; Index++) {
+ if (DeleteList[Index] == NULL) {
+ continue;
+ }
+
+ if (AsciiStrCmp (FieldName, DeleteList[Index]) == 0) {
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}
+