mirror of https://github.com/acidanthera/audk.git
1570 lines
35 KiB
C
1570 lines
35 KiB
C
/*++
|
|
This file contains an 'Intel UEFI Application' and is
|
|
licensed for Intel CPUs and chipsets under the terms of your
|
|
license agreement with Intel or your vendor. This file may
|
|
be modified by the user, subject to additional terms of the
|
|
license agreement
|
|
--*/
|
|
/*++
|
|
|
|
Copyright (c) 2011 Intel Corporation. All rights reserved
|
|
This software and associated documentation (if any) is furnished
|
|
under a license and may only be used or copied in accordance
|
|
with the terms of the license. Except as permitted by such
|
|
license, no part of this software or documentation may be
|
|
reproduced, stored in a retrieval system, or transmitted in any
|
|
form or by any means without the express written consent of
|
|
Intel Corporation.
|
|
|
|
--*/
|
|
|
|
/** @file
|
|
HTTP processing for the web server.
|
|
|
|
**/
|
|
|
|
#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_in LocalAddress;
|
|
struct sockaddr_in RemoteAddress;
|
|
|
|
DBG_ENTER ( );
|
|
|
|
//
|
|
// Build the page header
|
|
//
|
|
for ( ; ; ) {
|
|
LengthInBytes = sizeof ( LocalAddress );
|
|
RetVal = getsockname ( SocketFD, (struct sockaddr *)&LocalAddress, &LengthInBytes );
|
|
if ( 0 == RetVal ) {
|
|
RetVal = getpeername ( SocketFD, (struct sockaddr *)&RemoteAddress, &LengthInBytes );
|
|
if ( 0 == RetVal ) {
|
|
//
|
|
// Seperate the body from the trailer
|
|
//
|
|
Status = HttpSendAnsiString ( SocketFD, pPort, " <hr>\r\n" );
|
|
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, "\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,
|
|
"<" );
|
|
}
|
|
else if ( '>' == Character ) {
|
|
//
|
|
// Replace with HTML equivalent
|
|
//
|
|
Status = HttpSendAnsiString ( SocketFD,
|
|
pPort,
|
|
">" );
|
|
}
|
|
else if ( '&' == Character ) {
|
|
//
|
|
// Replace with HTML equivalent
|
|
//
|
|
Status = HttpSendAnsiString ( SocketFD,
|
|
pPort,
|
|
"&" );
|
|
}
|
|
else if ( '\"' == Character ) {
|
|
//
|
|
// Replace with HTML equivalent
|
|
//
|
|
Status = HttpSendAnsiString ( SocketFD,
|
|
pPort,
|
|
""" );
|
|
}
|
|
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)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,
|
|
" " );
|
|
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,
|
|
" " );
|
|
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,
|
|
" " );
|
|
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 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_in * pAddress
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
|
|
//
|
|
// Output the IPv4 address
|
|
//
|
|
Status = HttpSendValue ( SocketFD, pPort, (UINT8)pAddress->sin_addr.s_addr );
|
|
if ( !EFI_ERROR ( Status )) {
|
|
Status = HttpSendByte ( SocketFD, pPort, '.' );
|
|
if ( !EFI_ERROR ( Status )) {
|
|
Status = HttpSendValue ( SocketFD, pPort, (UINT8)( pAddress->sin_addr.s_addr >> 8 ));
|
|
if ( !EFI_ERROR ( Status )) {
|
|
Status = HttpSendByte ( SocketFD, pPort, '.' );
|
|
if ( !EFI_ERROR ( Status )) {
|
|
Status = HttpSendValue ( SocketFD, pPort, (UINT8)( pAddress->sin_addr.s_addr >> 16 ));
|
|
if ( !EFI_ERROR ( Status )) {
|
|
Status = HttpSendByte ( SocketFD, pPort, '.' );
|
|
if ( !EFI_ERROR ( Status )) {
|
|
Status = HttpSendValue ( SocketFD, pPort, (UINT8)( pAddress->sin_addr.s_addr >> 24 ));
|
|
if ( !EFI_ERROR ( Status )) {
|
|
//
|
|
// Output the port number
|
|
//
|
|
Status = HttpSendByte ( SocketFD, pPort, ':' );
|
|
if ( !EFI_ERROR ( Status )) {
|
|
Status = HttpSendValue ( SocketFD, pPort, htons ( pAddress->sin_port ));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// 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[ ] = {
|
|
10000000000000000000L,
|
|
1000000000000000000L,
|
|
100000000000000000L,
|
|
10000000000000000L,
|
|
1000000000000000L,
|
|
100000000000000L,
|
|
10000000000000L,
|
|
1000000000000L,
|
|
100000000000L,
|
|
10000000000L,
|
|
1000000000L,
|
|
100000000L,
|
|
10000000L,
|
|
1000000L,
|
|
100000L,
|
|
10000L,
|
|
1000L,
|
|
100L,
|
|
10L
|
|
};
|
|
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;
|
|
}
|