audk/AppPkg/Applications/Sockets/WebServer/HTTP.c

1736 lines
39 KiB
C

/**
@file
HTTP processing for the web server.
Copyright (c) 2011-2012, 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.
**/
#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;
}