diff options
Diffstat (limited to 'AppPkg/Applications/Sockets/WebServer/HTTP.c')
-rw-r--r-- | AppPkg/Applications/Sockets/WebServer/HTTP.c | 3140 |
1 files changed, 1570 insertions, 1570 deletions
diff --git a/AppPkg/Applications/Sockets/WebServer/HTTP.c b/AppPkg/Applications/Sockets/WebServer/HTTP.c index a1716b2dbf..314705b68f 100644 --- a/AppPkg/Applications/Sockets/WebServer/HTTP.c +++ b/AppPkg/Applications/Sockets/WebServer/HTTP.c @@ -1,1570 +1,1570 @@ -/*++ - 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 - - @returns 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. - - @returns 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 - - @returns 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 - - @returns 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; -} +/*++
+ 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;
+}
|