Files
system76-edk2/AppPkg/Applications/Sockets/WebServer/HTTP.c
2019-04-09 10:58:32 -07:00

1730 lines
39 KiB
C

/**
@file
HTTP processing for the web server.
Copyright (c) 2011-2012, Intel Corporation. All rights reserved.
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#include <WebServer.h>
/**
Get a UTF-8 character from the buffer
@param [in] pData The address of the buffer containing the character
@param [out] ppData The address to receive the next character address
@return The character value
**/
INTN
HttpCharGet (
IN UINT8 * pData,
IN UINT8 ** ppData
)
{
INTN Data;
INTN Character;
INTN Control;
INTN Mask;
//
// Verify that there is some data left
//
if ( NULL == pData ) {
//
// No data to return
//
pData = NULL;
Character = 0;
}
else {
//
// Get the first portion of the character
//
Character = *pData++;
Control = Character;
Mask = 0xc0;
//
// Append the rest of the character
//
if ( 0 != ( Control & 0x80 )) {
while ( 0 != ( Control & 0x40 )) {
Character &= Mask;
Mask <<= 5;
Control <<= 1;
Character <<= 6;
Data = *pData++ & 0x3f;
if ( 0x80 != ( Data & 0xc0 )) {
//
// Invalid character
//
pData = NULL;
Character = 0;
break;
}
Character |= Data & 0x3f;
}
}
}
//
// Return the next character location and the character
//
*ppData = pData;
return Character;
}
/**
Transmit a portion of the HTTP response
@param [in] SocketFD The socket's file descriptor to add to the list.
@param [in] pPort The WSDT_PORT structure address
@retval EFI_SUCCESS The request was successfully processed
**/
EFI_STATUS
HttpFlush (
IN int SocketFD,
IN WSDT_PORT * pPort
)
{
INTN LengthInBytes;
UINT8 * pBuffer;
EFI_STATUS Status;
DBG_ENTER ( );
//
// Assume success
//
Status = EFI_SUCCESS;
pBuffer = &pPort->TxBuffer[0];
do {
//
// Attempt to send the data
//
LengthInBytes = send ( SocketFD,
pBuffer,
pPort->TxBytes,
0 );
if ( -1 != LengthInBytes ) {
//
// Account for the data sent
//
pBuffer += LengthInBytes;
pPort->TxBytes -= LengthInBytes;
}
else {
//
// Transmit error
//
Status = EFI_DEVICE_ERROR;
break;
}
} while ( 0 < pPort->TxBytes );
//
// Return the operation status
//
DBG_EXIT_STATUS ( Status );
return Status;
}
/**
Convert the ANSI character to lower case
@param [in] Character The character to convert to lower case.
@return The lower case character
**/
INTN
HttpLowerCase (
IN INTN Character
)
{
//
// Determine if the character is upper case
//
if (( 'A' <= Character ) && ( 'Z' >= Character )) {
Character += 'a' - 'A';
}
//
// Return the lower case value of the character
//
return Character;
}
/**
Match a Unicode string against a UTF-8 string
@param [in] pString A zero terminated Unicode string
@param [in] pData A zero terminated UTF-8 string
@param [in] bIgnoreCase TRUE if case is to be ignored
@return The difference between the last two characters tested.
Returns -1 for error.
**/
INTN
HttpMatch (
IN UINT16 * pString,
IN UINT8 * pData,
IN BOOLEAN bIgnoreCase
)
{
INTN Character1;
INTN Character2;
INTN Difference;
do {
//
// Get the character from the comparison string
//
Character1 = *pString++;
//
// Convert the character to lower case
//
if ( bIgnoreCase ) {
Character1 = HttpLowerCase ( Character1 );
}
//
// Get the character from the request
//
Character2 = HttpCharGet ( pData, &pData );
if ( NULL == pData ) {
//
// Error getting character
//
Difference = -1;
break;
}
//
// Convert the character to lower case
//
if ( bIgnoreCase ) {
Character2 = HttpLowerCase ( Character2 );
}
//
// Compare the characters
//
Difference = Character1 - Character2;
if ( 0 != Difference ) {
return Difference;
}
} while ( 0 != Character1 );
//
// Return the difference
//
return Difference;
}
/**
Buffer the HTTP page header
@param [in] SocketFD The socket's file descriptor to add to the list.
@param [in] pPort The WSDT_PORT structure address
@param [in] pTitle A zero terminated Unicode title string
@retval EFI_SUCCESS The request was successfully processed
**/
EFI_STATUS
HttpPageHeader (
IN int SocketFD,
IN WSDT_PORT * pPort,
IN CONST CHAR16 * pTitle
)
{
EFI_STATUS Status;
DBG_ENTER ( );
//
// Build the page header
//
for ( ; ; ) {
Status = HttpSendAnsiString ( SocketFD,
pPort,
"<!DOCTYPE "
"HTML "
"PUBLIC "
"\"-//W3C//DTD HTML 4.01 Transitional//EN\" "
"\"http://www.w3.org/TR/html4/loose.dtd\">\r\n" );
if ( EFI_ERROR ( Status )) {
break;
}
Status = HttpSendAnsiString ( SocketFD, pPort, "<html lang=\"en-US\">\r\n" );
if ( EFI_ERROR ( Status )) {
break;
}
if ( NULL != pTitle ) {
Status = HttpSendAnsiString ( SocketFD, pPort, " <head>\r\n" );
if ( EFI_ERROR ( Status )) {
break;
}
Status = HttpSendAnsiString ( SocketFD, pPort, " <title>" );
if ( EFI_ERROR ( Status )) {
break;
}
Status = HttpSendUnicodeString ( SocketFD, pPort, pTitle );
if ( EFI_ERROR ( Status )) {
break;
}
Status = HttpSendAnsiString ( SocketFD, pPort, "</title>\r\n" );
if ( EFI_ERROR ( Status )) {
break;
}
Status = HttpSendAnsiString ( SocketFD, pPort, " </head>\r\n" );
if ( EFI_ERROR ( Status )) {
break;
}
}
Status = HttpSendAnsiString ( SocketFD, pPort, " <body>\r\n" );
break;
}
//
// Return the operation status
//
DBG_EXIT_STATUS ( Status );
return Status;
}
/**
Respond with an error indicating that the page was not found
@param [in] SocketFD The socket's file descriptor to add to the list.
@param [in] pPort The WSDT_PORT structure address
@param [out] pbDone Address to receive the request completion status
@retval EFI_SUCCESS The request was successfully processed
**/
EFI_STATUS
HttpPageNotFound (
IN int SocketFD,
IN WSDT_PORT * pPort,
IN BOOLEAN * pbDone
)
{
EFI_STATUS Status;
DBG_ENTER ( );
//
// Send the page not found
//
for ( ; ; ) {
//
// Send the page header
//
Status = HttpPageHeader ( SocketFD, pPort, L"404 Not found" );
if ( EFI_ERROR ( Status )) {
break;
}
//
// Send the page body
//
Status = HttpSendAnsiString ( SocketFD,
pPort,
"ERROR <b>404</b><br />"
"Requested page is not available\r\n" );
if ( EFI_ERROR ( Status )) {
break;
}
//
// Send the page trailer
//
Status = HttpPageTrailer ( SocketFD, pPort, pbDone );
break;
}
//
// Return the operation status
//
DBG_EXIT_STATUS ( Status );
return Status;
}
/**
Buffer and send the HTTP page trailer
@param [in] SocketFD The socket's file descriptor to add to the list.
@param [in] pPort The WSDT_PORT structure address
@param [out] pbDone Address to receive the request completion status
@retval EFI_SUCCESS The request was successfully processed
**/
EFI_STATUS
HttpPageTrailer (
IN int SocketFD,
IN WSDT_PORT * pPort,
IN BOOLEAN * pbDone
)
{
int RetVal;
EFI_STATUS Status;
socklen_t LengthInBytes;
struct sockaddr_in6 LocalAddress;
struct sockaddr_in6 RemoteAddress;
DBG_ENTER ( );
//
// Build the page header
//
for ( ; ; ) {
LengthInBytes = sizeof ( LocalAddress );
RetVal = getsockname ( SocketFD, (struct sockaddr *)&LocalAddress, &LengthInBytes );
if ( 0 == RetVal ) {
LengthInBytes = sizeof ( LocalAddress );
RetVal = getpeername ( SocketFD, (struct sockaddr *)&RemoteAddress, &LengthInBytes );
if ( 0 == RetVal ) {
//
// Seperate the body from the trailer
//
Status = HttpSendAnsiString ( SocketFD, pPort, " <hr>\r\n<code>" );
if ( EFI_ERROR ( Status )) {
break;
}
//
// Display the system addresses and the page transfer direction
//
Status = HttpSendIpAddress ( SocketFD, pPort, &LocalAddress );
if ( EFI_ERROR ( Status )) {
break;
}
Status = HttpSendAnsiString ( SocketFD, pPort, " --> " );
if ( EFI_ERROR ( Status )) {
break;
}
Status = HttpSendIpAddress ( SocketFD, pPort, &RemoteAddress );
if ( EFI_ERROR ( Status )) {
break;
}
Status = HttpSendAnsiString ( SocketFD, pPort, "</code>\r\n" );
if ( EFI_ERROR ( Status )) {
break;
}
}
}
//
// Terminate the page
//
Status = HttpSendAnsiString ( SocketFD, pPort, " </body>\r\n" );
if ( EFI_ERROR ( Status )) {
break;
}
Status = HttpSendAnsiString ( SocketFD, pPort, " </html>\r\n" );
if ( EFI_ERROR ( Status )) {
break;
}
//
// Send the page trailer
//
Status = HttpFlush ( SocketFD, pPort );
if ( EFI_ERROR ( Status )) {
break;
}
//
// Mark the page as complete
//
*pbDone = TRUE;
break;
}
//
// Return the operation status
//
DBG_EXIT_STATUS ( Status );
return Status;
}
/**
Replace a space with a zero
@param [in] pData The request buffer address
@param [in] pEnd End of buffer address
@return The next character location
**/
UINT8 *
HttpReplaceSpace (
IN UINT8 * pData,
IN UINT8 * pEnd
)
{
INTN Character;
UINT8 * pSpace;
pSpace = pData;
while ( pEnd > pData ) {
//
// Get the character from the request
//
Character = HttpCharGet ( pData, &pData );
if ( ' ' == Character ) {
break;
}
pSpace = pData;
}
//
// Replace the space character with zero
//
ZeroMem ( pSpace, pData - pSpace );
//
// Return the next character location
//
return pData;
}
/**
Process an HTTP request
@param [in] SocketFD The socket's file descriptor to add to the list.
@param [in] pPort The WSDT_PORT structure address
@param [out] pbDone Address to receive the request completion status
@retval EFI_SUCCESS The request was successfully processed
**/
EFI_STATUS
HttpRequest (
IN int SocketFD,
IN WSDT_PORT * pPort,
OUT BOOLEAN * pbDone
)
{
UINT8 * pData;
UINT8 * pEnd;
CONST DT_PAGE * pPage;
CONST DT_PAGE * pPageEnd;
UINT8 * pVerb;
UINT8 * pVersion;
UINT8 * pWebPage;
EFI_STATUS Status;
DBG_ENTER ( );
//
// Assume the request is not finished
//
*pbDone = FALSE;
Status = EFI_SUCCESS;
for ( ; ; ) {
//
// Attempt to parse the command
//
pData = &pPort->Request[0];
pEnd = &pData[ pPort->RequestLength ];
pVerb = pData;
pWebPage = HttpReplaceSpace ( pVerb, pEnd );
if ( pEnd <= pWebPage ) {
break;
}
pVersion = HttpReplaceSpace ( pWebPage, pEnd );
if ( pEnd <= pVersion ) {
break;
}
//
// Validate the request
//
if ( 0 != HttpMatch ( L"GET", pVerb, TRUE )) {
//
// Invalid request type
//
DEBUG (( DEBUG_REQUEST,
"HTTP: Invalid verb\r\n" ));
Status = EFI_NOT_FOUND;
break;
}
//
// Walk the page table
//
pPage = &mPageList[0];
pPageEnd = &pPage[ mPageCount ];
while ( pPageEnd > pPage ) {
//
// Determine if the page was located
//
if ( 0 == HttpMatch ( pPage->pPageName, pWebPage, FALSE )) {
break;
}
//
// Set the next page
//
pPage += 1;
}
if ( pPageEnd <= pPage ) {
//
// The page was not found
//
DEBUG (( DEBUG_REQUEST,
"HTTP: Page not found in page table\r\n" ));
Status = EFI_NOT_FOUND;
break;
}
//
// Respond with the page contents
//
Status = pPage->pfnResponse ( SocketFD, pPort, pbDone );
break;
}
//
// Return page not found if necessary
//
if ( EFI_NOT_FOUND == Status ) {
Status = HttpPageNotFound ( SocketFD, pPort, pbDone );
}
//
// Return the operation status
//
DBG_EXIT_STATUS ( Status );
return Status;
}
/**
Buffer data for sending
@param [in] SocketFD The socket's file descriptor to add to the list.
@param [in] pPort The WSDT_PORT structure address
@param [in] LengthInBytes Length of valid data in the buffer
@param [in] pBuffer Buffer of data to send
@retval EFI_SUCCESS The request was successfully processed
**/
EFI_STATUS
HttpSend (
IN int SocketFD,
IN WSDT_PORT * pPort,
IN size_t LengthInBytes,
IN CONST UINT8 * pBuffer
)
{
size_t DataBytes;
size_t MaxBytes;
EFI_STATUS Status;
//
// Assume success
//
Status = EFI_SUCCESS;
do {
//
// Determine how much data fits into the buffer
//
MaxBytes = sizeof ( pPort->TxBuffer );
DataBytes = MaxBytes - pPort->TxBytes;
if ( DataBytes > LengthInBytes ) {
DataBytes = LengthInBytes;
}
//
// Copy the data into the buffer
//
CopyMem ( &pPort->TxBuffer[ pPort->TxBytes ],
pBuffer,
DataBytes );
//
// Account for the data copied
//
pPort->TxBytes += DataBytes;
LengthInBytes -= DataBytes;
//
// Transmit the buffer if it is full
//
if ( MaxBytes <= pPort->TxBytes ) {
Status = HttpFlush ( SocketFD, pPort );
}
} while (( EFI_SUCCESS == Status ) && ( 0 < LengthInBytes ));
//
// Return the operation status
//
return Status;
}
/**
Send an ANSI string
@param [in] SocketFD The socket's file descriptor to add to the list.
@param [in] pPort The WSDT_PORT structure address
@param [in] pString A zero terminated Unicode string
@retval EFI_SUCCESS The request was successfully processed
**/
EFI_STATUS
HttpSendAnsiString (
IN int SocketFD,
IN WSDT_PORT * pPort,
IN CONST char * pString
)
{
CONST char * pData;
EFI_STATUS Status;
//
// Assume success
//
Status = EFI_SUCCESS;
//
// Walk the characters in he string
//
pData = pString;
while ( 0 != *pData ) {
pData += 1;
}
//
// Send the string
//
Status = HttpSend ( SocketFD,
pPort,
pData - pString,
(CONST UINT8 *)pString );
//
// Return the operation status
//
return Status;
}
/**
Buffer a single byte
@param [in] SocketFD The socket's file descriptor to add to the list.
@param [in] pPort The WSDT_PORT structure address
@param [in] Data The data byte to send
@retval EFI_SUCCESS The request was successfully processed
**/
EFI_STATUS
HttpSendByte (
IN int SocketFD,
IN WSDT_PORT * pPort,
IN UINT8 Data
)
{
EFI_STATUS Status;
//
// Send the data byte
//
Status = HttpSend ( SocketFD,
pPort,
1,
&Data );
//
// Return the operation status
//
return Status;
}
/**
Display a character
@param [in] SocketFD The socket's file descriptor to add to the list.
@param [in] pPort The WSDT_PORT structure address
@param [in] Character Character to display
@param [in] pReplacement Replacement character string
@retval EFI_SUCCESS The request was successfully processed
**/
EFI_STATUS
HttpSendCharacter (
IN int SocketFD,
IN WSDT_PORT * pPort,
IN CHAR8 Character,
IN CHAR8 * pReplacement
)
{
EFI_STATUS Status;
//
// Determine if this is a printable character
//
if (( 0x20 <= Character ) && ( 0x7f > Character )) {
if ( '<' == Character ) {
//
// Replace with HTML equivalent
//
Status = HttpSendAnsiString ( SocketFD,
pPort,
"&lt;" );
}
else if ( '>' == Character ) {
//
// Replace with HTML equivalent
//
Status = HttpSendAnsiString ( SocketFD,
pPort,
"&gt;" );
}
else if ( '&' == Character ) {
//
// Replace with HTML equivalent
//
Status = HttpSendAnsiString ( SocketFD,
pPort,
"&amp;" );
}
else if ( '\"' == Character ) {
//
// Replace with HTML equivalent
//
Status = HttpSendAnsiString ( SocketFD,
pPort,
"&quot;" );
}
else {
//
// Display the character
//
Status = HttpSendByte ( SocketFD,
pPort,
Character );
}
}
else {
//
// Not a displayable character
//
Status = HttpSendAnsiString ( SocketFD,
pPort,
pReplacement );
}
//
// Return the operation status
//
return Status;
}
/**
Send a buffer dump
@param [in] SocketFD The socket's file descriptor to add to the list.
@param [in] pPort The WSDT_PORT structure address
@param [in] ByteCount The number of bytes to display
@param [in] pData Address of the byte array
@retval EFI_SUCCESS The request was successfully processed
**/
EFI_STATUS
HttpSendDump (
IN int SocketFD,
IN WSDT_PORT * pPort,
IN UINTN ByteCount,
IN CONST UINT8 * pData
)
{
INTN BytesToDisplay;
UINT8 Character;
INTN Index;
INTN InitialSpaces;
CONST UINT8 * pDataEnd;
CONST UINT8 * pEnd;
CONST UINT8 * pTemp;
EFI_STATUS Status;
//
// Use for/break instead of goto
//
for ( ; ; ) {
//
// Start the field value
//
Status = HttpSendAnsiString ( SocketFD,
pPort,
"<code>" );
if ( EFI_ERROR ( Status )) {
break;
}
//
// Walk the bytes to be displayed
//
pEnd = &pData[ ByteCount ];
while ( pEnd > pData ) {
//
// Display the address
//
Status = HttpSendHexBits ( SocketFD,
pPort,
sizeof ( pData ) * 8,
(UINT64)(UINTN)pData );
if ( EFI_ERROR ( Status )) {
break;
}
//
// Separate the address and data
//
Status = HttpSendByte ( SocketFD, pPort, ':' );
if ( EFI_ERROR ( Status )) {
break;
}
//
// Position the starting data correctly
//
InitialSpaces = (UINTN)pData;
InitialSpaces &= BYTES_ON_A_LINE - 1;
for ( Index = SPACES_ADDRESS_TO_DATA
+ (( 2 + SPACES_BETWEEN_BYTES )
* InitialSpaces );
0 < Index; Index-- ) {
Status = HttpSendAnsiString ( SocketFD,
pPort,
"&nbsp;" );
if ( EFI_ERROR ( Status )) {
break;
}
}
if ( EFI_ERROR ( Status )) {
break;
}
//
// Display the data
//
BytesToDisplay = pEnd - pData;
if (( BYTES_ON_A_LINE - InitialSpaces ) < BytesToDisplay ) {
BytesToDisplay = BYTES_ON_A_LINE - InitialSpaces;
}
pDataEnd = &pData[ BytesToDisplay ];
pTemp = pData;
while ( pDataEnd > pTemp ) {
Status = HttpSendHexBits ( SocketFD,
pPort,
8,
*pTemp++ );
if ( EFI_ERROR ( Status )) {
break;
}
//
// Separate the data bytes
//
for ( Index = SPACES_BETWEEN_BYTES; 0 < Index; Index-- ) {
Status = HttpSendAnsiString ( SocketFD,
pPort,
"&nbsp;" );
if ( EFI_ERROR ( Status )) {
break;
}
}
if ( EFI_ERROR ( Status )) {
break;
}
}
if ( EFI_ERROR ( Status )) {
break;
}
//
// Separate the data from the ASCII display
//
for ( Index = (( 2 + SPACES_BETWEEN_BYTES )
* ( BYTES_ON_A_LINE - BytesToDisplay - InitialSpaces ))
- SPACES_BETWEEN_BYTES
+ SPACES_DATA_TO_ASCII
+ InitialSpaces;
0 < Index; Index-- ) {
Status = HttpSendAnsiString ( SocketFD,
pPort,
"&nbsp;" );
if ( EFI_ERROR ( Status )) {
break;
}
}
if ( EFI_ERROR ( Status )) {
break;
}
//
// Display the ASCII data
//
while ( pDataEnd > pData ) {
Character = *pData++;
Status = HttpSendCharacter ( SocketFD,
pPort,
Character,
"." );
if ( EFI_ERROR ( Status )) {
break;
}
}
if ( EFI_ERROR ( Status )) {
break;
}
//
// Terminate the line
//
Status = HttpSendAnsiString ( SocketFD,
pPort,
"<br/>\r\n" );
if ( EFI_ERROR ( Status )) {
break;
}
}
//
// Terminate the field value and row
//
Status = HttpSendAnsiString ( SocketFD,
pPort,
"</code>\r\n" );
break;
}
//
// Return the operation status
//
return Status;
}
/**
Display a row containing a GUID value
@param [in] SocketFD The socket's file descriptor to add to the list.
@param [in] pPort The WSDT_PORT structure address
@param [in] pGuid Address of the GUID to display
@retval EFI_SUCCESS The request was successfully processed
**/
EFI_STATUS
HttpSendGuid (
IN int SocketFD,
IN WSDT_PORT * pPort,
IN CONST EFI_GUID * pGuid
)
{
UINT32 Index;
EFI_STATUS Status;
DBG_ENTER ( );
//
// Use for/break instead of goto
//
for ( ; ; ) {
//
// Display the GUID in a form found in the code
//
// E.g. 0xca16005f, 0x11ec, 0x4bdc, { 0x99, 0x97, 0x27, 0x2c, 0xa9, 0xba, 0x15, 0xe5 }
//
//
// Display the first 32 bits
//
Status = HttpSendAnsiString ( SocketFD,
pPort,
"0x" );
if ( EFI_ERROR ( Status )) {
break;
}
Status = HttpSendHexBits ( SocketFD,
pPort,
32,
pGuid->Data1 );
if ( EFI_ERROR ( Status )) {
break;
}
//
// Display the second 16 bits
//
Status = HttpSendAnsiString ( SocketFD,
pPort,
", 0x" );
if ( EFI_ERROR ( Status )) {
break;
}
Status = HttpSendHexBits ( SocketFD,
pPort,
16,
pGuid->Data2 );
if ( EFI_ERROR ( Status )) {
break;
}
//
// Display the thrid 16 bits
//
Status = HttpSendAnsiString ( SocketFD,
pPort,
", 0x" );
if ( EFI_ERROR ( Status )) {
break;
}
Status = HttpSendHexBits ( SocketFD,
pPort,
16,
pGuid->Data3 );
if ( EFI_ERROR ( Status )) {
break;
}
//
// Place the last 64 bits in braces
//
Status = HttpSendAnsiString ( SocketFD,
pPort,
", { 0x" );
if ( EFI_ERROR ( Status )) {
break;
}
for ( Index = 0; 7 >= Index; Index++ ) {
//
// Display the next 8 bits
//
Status = HttpSendHexBits ( SocketFD,
pPort,
8,
pGuid->Data4[ Index ]);
if ( EFI_ERROR ( Status )) {
break;
}
//
// Separate the bytes
//
Status = HttpSendAnsiString ( SocketFD,
pPort,
( 7 != Index ) ? ", 0x" : " }" );
if ( EFI_ERROR ( Status )) {
break;
}
}
break;
}
//
// Return the operation status
//
DBG_EXIT_STATUS ( Status );
return Status;
}
/**
Output a hex value to the HTML page
@param [in] SocketFD Socket file descriptor
@param [in] pPort The WSDT_PORT structure address
@param [in] Bits Number of bits to display
@param [in] Value Value to display
@retval EFI_SUCCESS Successfully displayed the address
**/
EFI_STATUS
HttpSendHexBits (
IN int SocketFD,
IN WSDT_PORT * pPort,
IN INT32 Bits,
IN UINT64 Value
)
{
UINT32 Digit;
INT32 Shift;
EFI_STATUS Status;
//
// Assume success
//
Status = EFI_SUCCESS;
//
// Walk the list of divisors
//
Shift = (( Bits + 3 ) & ( ~3 )) - 4;
while ( 0 <= Shift ) {
//
// Determine the next digit
//
Digit = (UINT32)(( Value >> Shift ) & 0xf );
if ( 10 <= Digit ) {
Digit += 'a' - '0' - 10;
}
//
// Display the digit
//
Status = HttpSendByte ( SocketFD, pPort, (UINT8)( '0' + Digit ));
if ( EFI_ERROR ( Status )) {
break;
}
//
// Set the next shift
//
Shift -= 4;
}
//
// Return the operation status
//
return Status;
}
/**
Output a hex value to the HTML page
@param [in] SocketFD Socket file descriptor
@param [in] pPort The WSDT_PORT structure address
@param [in] Value Value to display
@retval EFI_SUCCESS Successfully displayed the address
**/
EFI_STATUS
HttpSendHexValue (
IN int SocketFD,
IN WSDT_PORT * pPort,
IN UINT64 Value
)
{
BOOLEAN bDisplayZeros;
UINT32 Digit;
INT32 Shift;
EFI_STATUS Status;
//
// Assume success
//
Status = EFI_SUCCESS;
//
// Walk the list of divisors
//
bDisplayZeros = FALSE;
Shift = 60;
do {
//
// Determine the next digit
//
Digit = (UINT32)(( Value >> Shift ) & 0xf );
if ( 10 <= Digit ) {
Digit += 'a' - '0' - 10;
}
//
// Suppress leading zeros
//
if (( 0 != Digit ) || bDisplayZeros || ( 0 == Shift )) {
bDisplayZeros = TRUE;
//
// Display the digit
//
Status = HttpSendByte ( SocketFD, pPort, (UINT8)( '0' + Digit ));
if ( EFI_ERROR ( Status )) {
break;
}
}
//
// Set the next shift
//
Shift -= 4;
} while ( 0 <= Shift );
//
// Return the operation status
//
return Status;
}
/**
Output an IP6 address value to the HTML page
@param [in] SocketFD Socket file descriptor
@param [in] pPort The WSDT_PORT structure address
@param [in] Value Value to display
@param [in] bFirstValue TRUE if first value
@param [in] bLastValue TRUE if last value
@param [in] bZeroSuppression TRUE while zeros are being suppressed
@param [in] pbZeroSuppression Address to receive TRUE when zero suppression
has started, use NULL if next colon value not
needed.
@retval EFI_SUCCESS Successfully displayed the address
**/
EFI_STATUS
HttpSendIp6Value (
IN int SocketFD,
IN WSDT_PORT * pPort,
IN UINT16 Value,
IN BOOLEAN bFirstValue,
IN BOOLEAN bLastValue,
IN BOOLEAN bZeroSuppression,
IN BOOLEAN * pbZeroSuppression
)
{
BOOLEAN bZeroSuppressionStarting;
UINT32 Digit;
EFI_STATUS Status;
//
// Use break instead of goto
//
bZeroSuppressionStarting = FALSE;
Status = EFI_SUCCESS;
for ( ; ; ) {
//
// Display the leading colon if necessary
//
if ( bZeroSuppression && ( bLastValue || ( 0 != Value ))) {
Status = HttpSendByte ( SocketFD, pPort, ':' );
if ( EFI_ERROR ( Status )) {
break;
}
}
//
// Skip over a series of zero values
//
bZeroSuppressionStarting = (BOOLEAN)( 0 == Value );
if ( !bZeroSuppressionStarting ) {
//
// Display the value
//
Digit = ( Value >> 4 ) & 0xf;
Status = HttpSendHexValue ( SocketFD,
pPort,
Digit );
if ( EFI_ERROR ( Status )) {
break;
}
Digit = Value & 0xf;
Status = HttpSendHexValue ( SocketFD,
pPort,
Digit );
if ( EFI_ERROR ( Status )) {
break;
}
Digit = ( Value >> 12 ) & 0xf;
Status = HttpSendHexValue ( SocketFD,
pPort,
Digit );
if ( EFI_ERROR ( Status )) {
break;
}
Digit = ( Value >> 8 ) & 0xf;
Status = HttpSendHexValue ( SocketFD,
pPort,
Digit );
if ( EFI_ERROR ( Status )) {
break;
}
}
//
// Display the trailing colon if necessary
//
if (( !bLastValue ) && ( bFirstValue || ( 0 != Value ))) {
Status = HttpSendByte ( SocketFD, pPort, ':' );
}
break;
}
//
// Return the next colon display
if ( NULL != pbZeroSuppression ) {
*pbZeroSuppression = bZeroSuppressionStarting;
}
//
// Return the operation status
//
return Status;
}
/**
Output an IP address to the HTML page
@param [in] SocketFD Socket file descriptor
@param [in] pPort The WSDT_PORT structure address
@param [in] pAddress Address of the socket address
@retval EFI_SUCCESS Successfully displayed the address
**/
EFI_STATUS
HttpSendIpAddress (
IN int SocketFD,
IN WSDT_PORT * pPort,
IN struct sockaddr_in6 * pAddress
)
{
BOOLEAN bZeroSuppression;
UINT32 Index;
struct sockaddr_in * pIpv4;
struct sockaddr_in6 * pIpv6;
UINT16 PortNumber;
EFI_STATUS Status;
//
// Use break instead of goto
//
for ( ; ; ) {
//
// Determine the type of address
//
if ( AF_INET6 == pAddress->sin6_family ) {
pIpv6 = pAddress;
//
// Display the address in RFC2732 format
//
bZeroSuppression = FALSE;
Status = HttpSendByte ( SocketFD, pPort, '[' );
if ( EFI_ERROR ( Status )) {
break;
}
for ( Index = 0; 8 > Index; Index++ ) {
Status = HttpSendIp6Value ( SocketFD,
pPort,
pIpv6->sin6_addr.__u6_addr.__u6_addr16[ Index ],
(BOOLEAN)( 0 == Index ),
(BOOLEAN)( 7 == Index ),
bZeroSuppression,
&bZeroSuppression );
if ( EFI_ERROR ( Status )) {
break;
}
}
if ( EFI_ERROR ( Status )) {
break;
}
//
// Separate the port number
//
Status = HttpSendByte ( SocketFD, pPort, ']' );
//
// Get the port number
//
PortNumber = pIpv6->sin6_port;
}
else {
//
// Output the IPv4 address
//
pIpv4 = (struct sockaddr_in *)pAddress;
Status = HttpSendValue ( SocketFD, pPort, (UINT8)pIpv4->sin_addr.s_addr );
if ( EFI_ERROR ( Status )) {
break;
}
Status = HttpSendByte ( SocketFD, pPort, '.' );
if ( EFI_ERROR ( Status )) {
break;
}
Status = HttpSendValue ( SocketFD, pPort, (UINT8)( pIpv4->sin_addr.s_addr >> 8 ));
if ( EFI_ERROR ( Status )) {
break;
}
Status = HttpSendByte ( SocketFD, pPort, '.' );
if ( EFI_ERROR ( Status )) {
break;
}
Status = HttpSendValue ( SocketFD, pPort, (UINT8)( pIpv4->sin_addr.s_addr >> 16 ));
if ( EFI_ERROR ( Status )) {
break;
}
Status = HttpSendByte ( SocketFD, pPort, '.' );
if ( EFI_ERROR ( Status )) {
break;
}
Status = HttpSendValue ( SocketFD, pPort, (UINT8)( pIpv4->sin_addr.s_addr >> 24 ));
//
// Get the port number
//
PortNumber = pIpv4->sin_port;
}
if ( EFI_ERROR ( Status )) {
break;
}
//
// Display the port number
//
Status = HttpSendByte ( SocketFD, pPort, ':' );
if ( EFI_ERROR ( Status )) {
break;
}
Status = HttpSendValue ( SocketFD, pPort, htons ( PortNumber ));
break;
}
//
// Return the operation status
//
return Status;
}
/**
Send a Unicode string
@param [in] SocketFD The socket's file descriptor to add to the list.
@param [in] pPort The WSDT_PORT structure address
@param [in] pString A zero terminated Unicode string
@retval EFI_SUCCESS The request was successfully processed
**/
EFI_STATUS
HttpSendUnicodeString (
IN int SocketFD,
IN WSDT_PORT * pPort,
IN CONST UINT16 * pString
)
{
UINT8 Data;
UINT16 Character;
EFI_STATUS Status;
//
// Assume success
//
Status = EFI_SUCCESS;
//
// Walk the characters in he string
//
while ( 0 != ( Character = *pString++ )) {
//
// Convert the character to UTF-8
//
if ( 0 != ( Character & 0xf800 )) {
//
// Send the upper 4 bits
//
Data = (UINT8)(( Character >> 12 ) & 0xf );
Data |= 0xe0;
Status = HttpSendByte ( SocketFD,
pPort,
Data );
if ( EFI_ERROR ( Status )) {
break;
}
//
// Send the next 6 bits
//
Data = (UINT8)(( Character >> 6 ) & 0x3f );
Data |= 0x80;
Status = HttpSendByte ( SocketFD,
pPort,
Data );
if ( EFI_ERROR ( Status )) {
break;
}
//
// Send the last 6 bits
//
Data = (UINT8)( Character & 0x3f );
Data |= 0x80;
}
else if ( 0 != ( Character & 0x0780 )) {
//
// Send the upper 5 bits
//
Data = (UINT8)(( Character >> 6 ) & 0x1f );
Data |= 0xc0;
Status = HttpSendByte ( SocketFD,
pPort,
Data );
if ( EFI_ERROR ( Status )) {
break;
}
//
// Send the last 6 bits
//
Data = (UINT8)( Character & 0x3f );
Data |= 0x80;
}
else {
Data = (UINT8)( Character & 0x7f );
}
//
// Send the last data byte
//
Status = HttpSendByte ( SocketFD,
pPort,
Data );
if ( EFI_ERROR ( Status )) {
break;
}
}
//
// Return the operation status
//
return Status;
}
/**
Output a value to the HTML page
@param [in] SocketFD Socket file descriptor
@param [in] pPort The WSDT_PORT structure address
@param [in] Value Value to display
@retval EFI_SUCCESS Successfully displayed the address
**/
EFI_STATUS
HttpSendValue (
IN int SocketFD,
IN WSDT_PORT * pPort,
IN UINT64 Value
)
{
BOOLEAN bDisplayZeros;
UINT64 Digit;
CONST UINT64 * pEnd;
CONST UINT64 * pDivisor;
CONST UINT64 pDivisors[ ] = {
10000000000000000000ULL,
1000000000000000000ULL,
100000000000000000ULL,
10000000000000000ULL,
1000000000000000ULL,
100000000000000ULL,
10000000000000ULL,
1000000000000ULL,
100000000000ULL,
10000000000ULL,
1000000000ULL,
100000000ULL,
10000000ULL,
1000000ULL,
100000ULL,
10000ULL,
1000ULL,
100ULL,
10ULL
};
EFI_STATUS Status;
UINT64 Temp;
//
// Assume success
//
Status = EFI_SUCCESS;
//
// Walk the list of divisors
//
bDisplayZeros = FALSE;
pDivisor = &pDivisors[0];
pEnd = &pDivisor[ sizeof ( pDivisors ) / sizeof ( pDivisors[0])];
while ( pEnd > pDivisor ) {
//
// Determine the next digit
//
Digit = Value / *pDivisor;
//
// Suppress leading zeros
//
if (( 0 != Digit ) || bDisplayZeros ) {
bDisplayZeros = TRUE;
//
// Display the digit
//
Status = HttpSendByte ( SocketFD, pPort, (UINT8)( '0' + Digit ));
if ( EFI_ERROR ( Status )) {
break;
}
//
// Determine the remainder
//
Temp = *pDivisor * Digit;
Value -= Temp;
}
//
// Set the next divisor
//
pDivisor += 1;
}
//
// Display the final digit
//
if ( !EFI_ERROR ( Status )) {
Status = HttpSendByte ( SocketFD, pPort, (UINT8)( '0' + Value ));
}
//
// Return the operation status
//
return Status;
}