X-Git-Url: https://git.proxmox.com/?p=mirror_edk2.git;a=blobdiff_plain;f=AppPkg%2FApplications%2FSockets%2FWebServer%2FHTTP.c;h=314705b68f9189ecf9b0e591c490d70a8a58cc2c;hp=a1716b2dbf0632747f6cea4e98933043f953142a;hb=7dc1329100c370992cdd430359512443bd1ee9f2;hpb=59d13433e7cbc810a6268d38141b0d1db353fa6e 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 - -/** - 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, - "\r\n" ); - if ( EFI_ERROR ( Status )) { - break; - } - Status = HttpSendAnsiString ( SocketFD, pPort, "\r\n" ); - if ( EFI_ERROR ( Status )) { - break; - } - if ( NULL != pTitle ) { - Status = HttpSendAnsiString ( SocketFD, pPort, " \r\n" ); - if ( EFI_ERROR ( Status )) { - break; - } - Status = HttpSendAnsiString ( SocketFD, pPort, " " ); - if ( EFI_ERROR ( Status )) { - break; - } - Status = HttpSendUnicodeString ( SocketFD, pPort, pTitle ); - if ( EFI_ERROR ( Status )) { - break; - } - Status = HttpSendAnsiString ( SocketFD, pPort, "\r\n" ); - if ( EFI_ERROR ( Status )) { - break; - } - Status = HttpSendAnsiString ( SocketFD, pPort, " \r\n" ); - if ( EFI_ERROR ( Status )) { - break; - } - } - Status = HttpSendAnsiString ( SocketFD, pPort, " \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 404
" - "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, "
\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, " \r\n" ); - if ( EFI_ERROR ( Status )) { - break; - } - Status = HttpSendAnsiString ( SocketFD, pPort, " \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, - "" ); - 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, - "
\r\n" ); - if ( EFI_ERROR ( Status )) { - break; - } - } - - // - // Terminate the field value and row - // - Status = HttpSendAnsiString ( SocketFD, - pPort, - "
\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 + +/** + 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, + "\r\n" ); + if ( EFI_ERROR ( Status )) { + break; + } + Status = HttpSendAnsiString ( SocketFD, pPort, "\r\n" ); + if ( EFI_ERROR ( Status )) { + break; + } + if ( NULL != pTitle ) { + Status = HttpSendAnsiString ( SocketFD, pPort, " \r\n" ); + if ( EFI_ERROR ( Status )) { + break; + } + Status = HttpSendAnsiString ( SocketFD, pPort, " " ); + if ( EFI_ERROR ( Status )) { + break; + } + Status = HttpSendUnicodeString ( SocketFD, pPort, pTitle ); + if ( EFI_ERROR ( Status )) { + break; + } + Status = HttpSendAnsiString ( SocketFD, pPort, "\r\n" ); + if ( EFI_ERROR ( Status )) { + break; + } + Status = HttpSendAnsiString ( SocketFD, pPort, " \r\n" ); + if ( EFI_ERROR ( Status )) { + break; + } + } + Status = HttpSendAnsiString ( SocketFD, pPort, " \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 404
" + "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, "
\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, " \r\n" ); + if ( EFI_ERROR ( Status )) { + break; + } + Status = HttpSendAnsiString ( SocketFD, pPort, " \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, + "" ); + 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, + "
\r\n" ); + if ( EFI_ERROR ( Status )) { + break; + } + } + + // + // Terminate the field value and row + // + Status = HttpSendAnsiString ( SocketFD, + pPort, + "
\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; +}