/** @file HTTP processing for the web server. Copyright (c) 2011-2012, Intel Corporation. All rights reserved. SPDX-License-Identifier: BSD-2-Clause-Patent **/ #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_in6 LocalAddress; struct sockaddr_in6 RemoteAddress; DBG_ENTER ( ); // // Build the page header // for ( ; ; ) { LengthInBytes = sizeof ( LocalAddress ); RetVal = getsockname ( SocketFD, (struct sockaddr *)&LocalAddress, &LengthInBytes ); if ( 0 == RetVal ) { LengthInBytes = sizeof ( LocalAddress ); RetVal = getpeername ( SocketFD, (struct sockaddr *)&RemoteAddress, &LengthInBytes ); if ( 0 == RetVal ) { // // Seperate the body from the trailer // Status = HttpSendAnsiString ( SocketFD, pPort, "
\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)(UINTN)pData ); if ( EFI_ERROR ( Status )) { break; } // // Separate the address and data // Status = HttpSendByte ( SocketFD, pPort, ':' ); if ( EFI_ERROR ( Status )) { break; } // // Position the starting data correctly // InitialSpaces = (UINTN)pData; InitialSpaces &= BYTES_ON_A_LINE - 1; for ( Index = SPACES_ADDRESS_TO_DATA + (( 2 + SPACES_BETWEEN_BYTES ) * InitialSpaces ); 0 < Index; Index-- ) { Status = HttpSendAnsiString ( SocketFD, pPort, " " ); 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 IP6 address value to the HTML page @param [in] SocketFD Socket file descriptor @param [in] pPort The WSDT_PORT structure address @param [in] Value Value to display @param [in] bFirstValue TRUE if first value @param [in] bLastValue TRUE if last value @param [in] bZeroSuppression TRUE while zeros are being suppressed @param [in] pbZeroSuppression Address to receive TRUE when zero suppression has started, use NULL if next colon value not needed. @retval EFI_SUCCESS Successfully displayed the address **/ EFI_STATUS HttpSendIp6Value ( IN int SocketFD, IN WSDT_PORT * pPort, IN UINT16 Value, IN BOOLEAN bFirstValue, IN BOOLEAN bLastValue, IN BOOLEAN bZeroSuppression, IN BOOLEAN * pbZeroSuppression ) { BOOLEAN bZeroSuppressionStarting; UINT32 Digit; EFI_STATUS Status; // // Use break instead of goto // bZeroSuppressionStarting = FALSE; Status = EFI_SUCCESS; for ( ; ; ) { // // Display the leading colon if necessary // if ( bZeroSuppression && ( bLastValue || ( 0 != Value ))) { Status = HttpSendByte ( SocketFD, pPort, ':' ); if ( EFI_ERROR ( Status )) { break; } } // // Skip over a series of zero values // bZeroSuppressionStarting = (BOOLEAN)( 0 == Value ); if ( !bZeroSuppressionStarting ) { // // Display the value // Digit = ( Value >> 4 ) & 0xf; Status = HttpSendHexValue ( SocketFD, pPort, Digit ); if ( EFI_ERROR ( Status )) { break; } Digit = Value & 0xf; Status = HttpSendHexValue ( SocketFD, pPort, Digit ); if ( EFI_ERROR ( Status )) { break; } Digit = ( Value >> 12 ) & 0xf; Status = HttpSendHexValue ( SocketFD, pPort, Digit ); if ( EFI_ERROR ( Status )) { break; } Digit = ( Value >> 8 ) & 0xf; Status = HttpSendHexValue ( SocketFD, pPort, Digit ); if ( EFI_ERROR ( Status )) { break; } } // // Display the trailing colon if necessary // if (( !bLastValue ) && ( bFirstValue || ( 0 != Value ))) { Status = HttpSendByte ( SocketFD, pPort, ':' ); } break; } // // Return the next colon display if ( NULL != pbZeroSuppression ) { *pbZeroSuppression = bZeroSuppressionStarting; } // // Return the operation status // return Status; } /** Output an IP address to the HTML page @param [in] SocketFD Socket file descriptor @param [in] pPort The WSDT_PORT structure address @param [in] pAddress Address of the socket address @retval EFI_SUCCESS Successfully displayed the address **/ EFI_STATUS HttpSendIpAddress ( IN int SocketFD, IN WSDT_PORT * pPort, IN struct sockaddr_in6 * pAddress ) { BOOLEAN bZeroSuppression; UINT32 Index; struct sockaddr_in * pIpv4; struct sockaddr_in6 * pIpv6; UINT16 PortNumber; EFI_STATUS Status; // // Use break instead of goto // for ( ; ; ) { // // Determine the type of address // if ( AF_INET6 == pAddress->sin6_family ) { pIpv6 = pAddress; // // Display the address in RFC2732 format // bZeroSuppression = FALSE; Status = HttpSendByte ( SocketFD, pPort, '[' ); if ( EFI_ERROR ( Status )) { break; } for ( Index = 0; 8 > Index; Index++ ) { Status = HttpSendIp6Value ( SocketFD, pPort, pIpv6->sin6_addr.__u6_addr.__u6_addr16[ Index ], (BOOLEAN)( 0 == Index ), (BOOLEAN)( 7 == Index ), bZeroSuppression, &bZeroSuppression ); if ( EFI_ERROR ( Status )) { break; } } if ( EFI_ERROR ( Status )) { break; } // // Separate the port number // Status = HttpSendByte ( SocketFD, pPort, ']' ); // // Get the port number // PortNumber = pIpv6->sin6_port; } else { // // Output the IPv4 address // pIpv4 = (struct sockaddr_in *)pAddress; Status = HttpSendValue ( SocketFD, pPort, (UINT8)pIpv4->sin_addr.s_addr ); if ( EFI_ERROR ( Status )) { break; } Status = HttpSendByte ( SocketFD, pPort, '.' ); if ( EFI_ERROR ( Status )) { break; } Status = HttpSendValue ( SocketFD, pPort, (UINT8)( pIpv4->sin_addr.s_addr >> 8 )); if ( EFI_ERROR ( Status )) { break; } Status = HttpSendByte ( SocketFD, pPort, '.' ); if ( EFI_ERROR ( Status )) { break; } Status = HttpSendValue ( SocketFD, pPort, (UINT8)( pIpv4->sin_addr.s_addr >> 16 )); if ( EFI_ERROR ( Status )) { break; } Status = HttpSendByte ( SocketFD, pPort, '.' ); if ( EFI_ERROR ( Status )) { break; } Status = HttpSendValue ( SocketFD, pPort, (UINT8)( pIpv4->sin_addr.s_addr >> 24 )); // // Get the port number // PortNumber = pIpv4->sin_port; } if ( EFI_ERROR ( Status )) { break; } // // Display the port number // Status = HttpSendByte ( SocketFD, pPort, ':' ); if ( EFI_ERROR ( Status )) { break; } Status = HttpSendValue ( SocketFD, pPort, htons ( PortNumber )); break; } // // Return the operation status // return Status; } /** Send a Unicode string @param [in] SocketFD The socket's file descriptor to add to the list. @param [in] pPort The WSDT_PORT structure address @param [in] pString A zero terminated Unicode string @retval EFI_SUCCESS The request was successfully processed **/ EFI_STATUS HttpSendUnicodeString ( IN int SocketFD, IN WSDT_PORT * pPort, IN CONST UINT16 * pString ) { UINT8 Data; UINT16 Character; EFI_STATUS Status; // // Assume success // Status = EFI_SUCCESS; // // Walk the characters in he string // while ( 0 != ( Character = *pString++ )) { // // Convert the character to UTF-8 // if ( 0 != ( Character & 0xf800 )) { // // Send the upper 4 bits // Data = (UINT8)(( Character >> 12 ) & 0xf ); Data |= 0xe0; Status = HttpSendByte ( SocketFD, pPort, Data ); if ( EFI_ERROR ( Status )) { break; } // // Send the next 6 bits // Data = (UINT8)(( Character >> 6 ) & 0x3f ); Data |= 0x80; Status = HttpSendByte ( SocketFD, pPort, Data ); if ( EFI_ERROR ( Status )) { break; } // // Send the last 6 bits // Data = (UINT8)( Character & 0x3f ); Data |= 0x80; } else if ( 0 != ( Character & 0x0780 )) { // // Send the upper 5 bits // Data = (UINT8)(( Character >> 6 ) & 0x1f ); Data |= 0xc0; Status = HttpSendByte ( SocketFD, pPort, Data ); if ( EFI_ERROR ( Status )) { break; } // // Send the last 6 bits // Data = (UINT8)( Character & 0x3f ); Data |= 0x80; } else { Data = (UINT8)( Character & 0x7f ); } // // Send the last data byte // Status = HttpSendByte ( SocketFD, pPort, Data ); if ( EFI_ERROR ( Status )) { break; } } // // Return the operation status // return Status; } /** Output a value to the HTML page @param [in] SocketFD Socket file descriptor @param [in] pPort The WSDT_PORT structure address @param [in] Value Value to display @retval EFI_SUCCESS Successfully displayed the address **/ EFI_STATUS HttpSendValue ( IN int SocketFD, IN WSDT_PORT * pPort, IN UINT64 Value ) { BOOLEAN bDisplayZeros; UINT64 Digit; CONST UINT64 * pEnd; CONST UINT64 * pDivisor; CONST UINT64 pDivisors[ ] = { 10000000000000000000ULL, 1000000000000000000ULL, 100000000000000000ULL, 10000000000000000ULL, 1000000000000000ULL, 100000000000000ULL, 10000000000000ULL, 1000000000000ULL, 100000000000ULL, 10000000000ULL, 1000000000ULL, 100000000ULL, 10000000ULL, 1000000ULL, 100000ULL, 10000ULL, 1000ULL, 100ULL, 10ULL }; EFI_STATUS Status; UINT64 Temp; // // Assume success // Status = EFI_SUCCESS; // // Walk the list of divisors // bDisplayZeros = FALSE; pDivisor = &pDivisors[0]; pEnd = &pDivisor[ sizeof ( pDivisors ) / sizeof ( pDivisors[0])]; while ( pEnd > pDivisor ) { // // Determine the next digit // Digit = Value / *pDivisor; // // Suppress leading zeros // if (( 0 != Digit ) || bDisplayZeros ) { bDisplayZeros = TRUE; // // Display the digit // Status = HttpSendByte ( SocketFD, pPort, (UINT8)( '0' + Digit )); if ( EFI_ERROR ( Status )) { break; } // // Determine the remainder // Temp = *pDivisor * Digit; Value -= Temp; } // // Set the next divisor // pDivisor += 1; } // // Display the final digit // if ( !EFI_ERROR ( Status )) { Status = HttpSendByte ( SocketFD, pPort, (UINT8)( '0' + Value )); } // // Return the operation status // return Status; }