-/*++
- 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;
-}
+/*++\r
+ This file contains an 'Intel UEFI Application' and is\r
+ licensed for Intel CPUs and chipsets under the terms of your\r
+ license agreement with Intel or your vendor. This file may\r
+ be modified by the user, subject to additional terms of the\r
+ license agreement\r
+--*/\r
+/*++\r
+\r
+Copyright (c) 2011 Intel Corporation. All rights reserved\r
+This software and associated documentation (if any) is furnished\r
+under a license and may only be used or copied in accordance\r
+with the terms of the license. Except as permitted by such\r
+license, no part of this software or documentation may be\r
+reproduced, stored in a retrieval system, or transmitted in any\r
+form or by any means without the express written consent of\r
+Intel Corporation.\r
+\r
+--*/\r
+\r
+/** @file\r
+ HTTP processing for the web server.\r
+\r
+**/\r
+\r
+#include <WebServer.h>\r
+\r
+/**\r
+ Get a UTF-8 character from the buffer\r
+\r
+ @param [in] pData The address of the buffer containing the character\r
+ @param [out] ppData The address to receive the next character address\r
+\r
+ @return The character value\r
+\r
+**/\r
+INTN\r
+HttpCharGet (\r
+ IN UINT8 * pData,\r
+ IN UINT8 ** ppData\r
+ )\r
+{\r
+ INTN Data;\r
+ INTN Character;\r
+ INTN Control;\r
+ INTN Mask;\r
+\r
+ //\r
+ // Verify that there is some data left\r
+ //\r
+ if ( NULL == pData ) {\r
+ //\r
+ // No data to return\r
+ //\r
+ pData = NULL;\r
+ Character = 0;\r
+ }\r
+ else {\r
+ //\r
+ // Get the first portion of the character\r
+ //\r
+ Character = *pData++;\r
+ Control = Character;\r
+ Mask = 0xc0;\r
+\r
+ //\r
+ // Append the rest of the character\r
+ //\r
+ if ( 0 != ( Control & 0x80 )) {\r
+ while ( 0 != ( Control & 0x40 )) {\r
+ Character &= Mask;\r
+ Mask <<= 5;\r
+ Control <<= 1;\r
+ Character <<= 6;\r
+ Data = *pData++ & 0x3f;\r
+ if ( 0x80 != ( Data & 0xc0 )) {\r
+ //\r
+ // Invalid character\r
+ //\r
+ pData = NULL;\r
+ Character = 0;\r
+ break;\r
+ }\r
+ Character |= Data & 0x3f;\r
+ }\r
+ }\r
+ }\r
+\r
+ //\r
+ // Return the next character location and the character\r
+ //\r
+ *ppData = pData;\r
+ return Character;\r
+}\r
+\r
+\r
+/**\r
+ Transmit a portion of the HTTP response\r
+\r
+ @param [in] SocketFD The socket's file descriptor to add to the list.\r
+ @param [in] pPort The WSDT_PORT structure address\r
+\r
+ @retval EFI_SUCCESS The request was successfully processed\r
+\r
+**/\r
+EFI_STATUS\r
+HttpFlush (\r
+ IN int SocketFD,\r
+ IN WSDT_PORT * pPort\r
+ )\r
+{\r
+ INTN LengthInBytes;\r
+ UINT8 * pBuffer;\r
+ EFI_STATUS Status;\r
+\r
+ DBG_ENTER ( );\r
+\r
+ //\r
+ // Assume success\r
+ //\r
+ Status = EFI_SUCCESS;\r
+ pBuffer = &pPort->TxBuffer[0];\r
+ do {\r
+ //\r
+ // Attempt to send the data\r
+ //\r
+ LengthInBytes = send ( SocketFD,\r
+ pBuffer,\r
+ pPort->TxBytes,\r
+ 0 );\r
+ if ( -1 != LengthInBytes ) {\r
+ //\r
+ // Account for the data sent\r
+ //\r
+ pBuffer += LengthInBytes;\r
+ pPort->TxBytes -= LengthInBytes;\r
+ }\r
+ else {\r
+ //\r
+ // Transmit error\r
+ //\r
+ Status = EFI_DEVICE_ERROR;\r
+ break;\r
+ }\r
+ } while ( 0 < pPort->TxBytes );\r
+\r
+ //\r
+ // Return the operation status\r
+ //\r
+ DBG_EXIT_STATUS ( Status );\r
+ return Status;\r
+}\r
+\r
+\r
+/**\r
+ Convert the ANSI character to lower case\r
+\r
+ @param [in] Character The character to convert to lower case.\r
+\r
+ @return The lower case character\r
+\r
+**/\r
+INTN\r
+HttpLowerCase (\r
+ IN INTN Character\r
+ )\r
+{\r
+ //\r
+ // Determine if the character is upper case\r
+ //\r
+ if (( 'A' <= Character ) && ( 'Z' >= Character )) {\r
+ Character += 'a' - 'A';\r
+ }\r
+\r
+ //\r
+ // Return the lower case value of the character\r
+ //\r
+ return Character;\r
+}\r
+\r
+\r
+/**\r
+ Match a Unicode string against a UTF-8 string\r
+\r
+ @param [in] pString A zero terminated Unicode string\r
+ @param [in] pData A zero terminated UTF-8 string\r
+ @param [in] bIgnoreCase TRUE if case is to be ignored\r
+\r
+ @return The difference between the last two characters tested.\r
+ Returns -1 for error.\r
+\r
+**/\r
+INTN\r
+HttpMatch (\r
+ IN UINT16 * pString,\r
+ IN UINT8 * pData,\r
+ IN BOOLEAN bIgnoreCase\r
+ )\r
+{\r
+ INTN Character1;\r
+ INTN Character2;\r
+ INTN Difference;\r
+\r
+ do {\r
+ //\r
+ // Get the character from the comparison string\r
+ //\r
+ Character1 = *pString++;\r
+\r
+ //\r
+ // Convert the character to lower case\r
+ //\r
+ if ( bIgnoreCase ) {\r
+ Character1 = HttpLowerCase ( Character1 );\r
+ }\r
+\r
+ //\r
+ // Get the character from the request\r
+ //\r
+ Character2 = HttpCharGet ( pData, &pData );\r
+ if ( NULL == pData ) {\r
+ //\r
+ // Error getting character\r
+ //\r
+ Difference = -1;\r
+ break;\r
+ }\r
+\r
+ //\r
+ // Convert the character to lower case\r
+ //\r
+ if ( bIgnoreCase ) {\r
+ Character2 = HttpLowerCase ( Character2 );\r
+ }\r
+\r
+ //\r
+ // Compare the characters\r
+ //\r
+ Difference = Character1 - Character2;\r
+ if ( 0 != Difference ) {\r
+ return Difference;\r
+ }\r
+ } while ( 0 != Character1 );\r
+\r
+ //\r
+ // Return the difference\r
+ //\r
+ return Difference;\r
+}\r
+\r
+\r
+/**\r
+ Buffer the HTTP page header\r
+\r
+ @param [in] SocketFD The socket's file descriptor to add to the list.\r
+ @param [in] pPort The WSDT_PORT structure address\r
+ @param [in] pTitle A zero terminated Unicode title string\r
+\r
+ @retval EFI_SUCCESS The request was successfully processed\r
+\r
+**/\r
+EFI_STATUS\r
+HttpPageHeader (\r
+ IN int SocketFD,\r
+ IN WSDT_PORT * pPort,\r
+ IN CONST CHAR16 * pTitle\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+\r
+ DBG_ENTER ( );\r
+\r
+ //\r
+ // Build the page header\r
+ //\r
+ for ( ; ; ) {\r
+ Status = HttpSendAnsiString ( SocketFD,\r
+ pPort,\r
+ "<!DOCTYPE "\r
+ "HTML "\r
+ "PUBLIC "\r
+ "\"-//W3C//DTD HTML 4.01 Transitional//EN\" "\r
+ "\"http://www.w3.org/TR/html4/loose.dtd\">\r\n" );\r
+ if ( EFI_ERROR ( Status )) {\r
+ break;\r
+ }\r
+ Status = HttpSendAnsiString ( SocketFD, pPort, "<html lang=\"en-US\">\r\n" );\r
+ if ( EFI_ERROR ( Status )) {\r
+ break;\r
+ }\r
+ if ( NULL != pTitle ) {\r
+ Status = HttpSendAnsiString ( SocketFD, pPort, " <head>\r\n" );\r
+ if ( EFI_ERROR ( Status )) {\r
+ break;\r
+ }\r
+ Status = HttpSendAnsiString ( SocketFD, pPort, " <title>" );\r
+ if ( EFI_ERROR ( Status )) {\r
+ break;\r
+ }\r
+ Status = HttpSendUnicodeString ( SocketFD, pPort, pTitle );\r
+ if ( EFI_ERROR ( Status )) {\r
+ break;\r
+ }\r
+ Status = HttpSendAnsiString ( SocketFD, pPort, "</title>\r\n" );\r
+ if ( EFI_ERROR ( Status )) {\r
+ break;\r
+ }\r
+ Status = HttpSendAnsiString ( SocketFD, pPort, " </head>\r\n" );\r
+ if ( EFI_ERROR ( Status )) {\r
+ break;\r
+ }\r
+ }\r
+ Status = HttpSendAnsiString ( SocketFD, pPort, " <body>\r\n" );\r
+ break;\r
+ }\r
+\r
+ //\r
+ // Return the operation status\r
+ //\r
+ DBG_EXIT_STATUS ( Status );\r
+ return Status;\r
+}\r
+\r
+\r
+/**\r
+ Respond with an error indicating that the page was not found\r
+\r
+ @param [in] SocketFD The socket's file descriptor to add to the list.\r
+ @param [in] pPort The WSDT_PORT structure address\r
+ @param [out] pbDone Address to receive the request completion status\r
+\r
+ @retval EFI_SUCCESS The request was successfully processed\r
+\r
+**/\r
+EFI_STATUS\r
+HttpPageNotFound (\r
+ IN int SocketFD,\r
+ IN WSDT_PORT * pPort,\r
+ IN BOOLEAN * pbDone\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+\r
+ DBG_ENTER ( );\r
+\r
+ //\r
+ // Send the page not found\r
+ //\r
+ for ( ; ; ) {\r
+ //\r
+ // Send the page header\r
+ //\r
+ Status = HttpPageHeader ( SocketFD, pPort, L"404 Not found" );\r
+ if ( EFI_ERROR ( Status )) {\r
+ break;\r
+ }\r
+\r
+ //\r
+ // Send the page body\r
+ //\r
+ Status = HttpSendAnsiString ( SocketFD,\r
+ pPort,\r
+ "ERROR <b>404</b><br />"\r
+ "Requested page is not available\r\n" );\r
+ if ( EFI_ERROR ( Status )) {\r
+ break;\r
+ }\r
+\r
+ //\r
+ // Send the page trailer\r
+ //\r
+ Status = HttpPageTrailer ( SocketFD, pPort, pbDone );\r
+ break;\r
+ }\r
+\r
+ //\r
+ // Return the operation status\r
+ //\r
+ DBG_EXIT_STATUS ( Status );\r
+ return Status;\r
+}\r
+\r
+\r
+/**\r
+ Buffer and send the HTTP page trailer\r
+\r
+ @param [in] SocketFD The socket's file descriptor to add to the list.\r
+ @param [in] pPort The WSDT_PORT structure address\r
+ @param [out] pbDone Address to receive the request completion status\r
+\r
+ @retval EFI_SUCCESS The request was successfully processed\r
+\r
+**/\r
+EFI_STATUS\r
+HttpPageTrailer (\r
+ IN int SocketFD,\r
+ IN WSDT_PORT * pPort,\r
+ IN BOOLEAN * pbDone\r
+ )\r
+{\r
+ int RetVal;\r
+ EFI_STATUS Status;\r
+ socklen_t LengthInBytes;\r
+ struct sockaddr_in LocalAddress;\r
+ struct sockaddr_in RemoteAddress;\r
+\r
+ DBG_ENTER ( );\r
+\r
+ //\r
+ // Build the page header\r
+ //\r
+ for ( ; ; ) {\r
+ LengthInBytes = sizeof ( LocalAddress );\r
+ RetVal = getsockname ( SocketFD, (struct sockaddr *)&LocalAddress, &LengthInBytes );\r
+ if ( 0 == RetVal ) {\r
+ RetVal = getpeername ( SocketFD, (struct sockaddr *)&RemoteAddress, &LengthInBytes );\r
+ if ( 0 == RetVal ) {\r
+ //\r
+ // Seperate the body from the trailer\r
+ //\r
+ Status = HttpSendAnsiString ( SocketFD, pPort, " <hr>\r\n" );\r
+ if ( EFI_ERROR ( Status )) {\r
+ break;\r
+ }\r
+\r
+ //\r
+ // Display the system addresses and the page transfer direction\r
+ //\r
+ Status = HttpSendIpAddress ( SocketFD, pPort, &LocalAddress );\r
+ if ( EFI_ERROR ( Status )) {\r
+ break;\r
+ }\r
+ Status = HttpSendAnsiString ( SocketFD, pPort, " --> " );\r
+ if ( EFI_ERROR ( Status )) {\r
+ break;\r
+ }\r
+ Status = HttpSendIpAddress ( SocketFD, pPort, &RemoteAddress );\r
+ if ( EFI_ERROR ( Status )) {\r
+ break;\r
+ }\r
+ Status = HttpSendAnsiString ( SocketFD, pPort, "\r\n" );\r
+ if ( EFI_ERROR ( Status )) {\r
+ break;\r
+ }\r
+ }\r
+ }\r
+\r
+ //\r
+ // Terminate the page\r
+ //\r
+ Status = HttpSendAnsiString ( SocketFD, pPort, " </body>\r\n" );\r
+ if ( EFI_ERROR ( Status )) {\r
+ break;\r
+ }\r
+ Status = HttpSendAnsiString ( SocketFD, pPort, " </html>\r\n" );\r
+ if ( EFI_ERROR ( Status )) {\r
+ break;\r
+ }\r
+\r
+ //\r
+ // Send the page trailer\r
+ //\r
+ Status = HttpFlush ( SocketFD, pPort );\r
+ if ( EFI_ERROR ( Status )) {\r
+ break;\r
+ }\r
+\r
+ //\r
+ // Mark the page as complete\r
+ //\r
+ *pbDone = TRUE;\r
+ break;\r
+ }\r
+\r
+ //\r
+ // Return the operation status\r
+ //\r
+ DBG_EXIT_STATUS ( Status );\r
+ return Status;\r
+}\r
+\r
+\r
+/**\r
+ Replace a space with a zero\r
+\r
+ @param [in] pData The request buffer address\r
+ @param [in] pEnd End of buffer address\r
+\r
+ @return The next character location\r
+\r
+**/\r
+UINT8 *\r
+HttpReplaceSpace (\r
+ IN UINT8 * pData,\r
+ IN UINT8 * pEnd\r
+ )\r
+{\r
+ INTN Character;\r
+ UINT8 * pSpace;\r
+\r
+ pSpace = pData;\r
+ while ( pEnd > pData ) {\r
+ //\r
+ // Get the character from the request\r
+ //\r
+ Character = HttpCharGet ( pData, &pData );\r
+ if ( ' ' == Character ) {\r
+ break;\r
+ }\r
+ pSpace = pData;\r
+ }\r
+\r
+ //\r
+ // Replace the space character with zero\r
+ //\r
+ ZeroMem ( pSpace, pData - pSpace );\r
+\r
+ //\r
+ // Return the next character location\r
+ //\r
+ return pData;\r
+}\r
+\r
+\r
+/**\r
+ Process an HTTP request\r
+\r
+ @param [in] SocketFD The socket's file descriptor to add to the list.\r
+ @param [in] pPort The WSDT_PORT structure address\r
+ @param [out] pbDone Address to receive the request completion status\r
+\r
+ @retval EFI_SUCCESS The request was successfully processed\r
+\r
+**/\r
+EFI_STATUS\r
+HttpRequest (\r
+ IN int SocketFD,\r
+ IN WSDT_PORT * pPort,\r
+ OUT BOOLEAN * pbDone\r
+ )\r
+{\r
+ UINT8 * pData;\r
+ UINT8 * pEnd;\r
+ CONST DT_PAGE * pPage;\r
+ CONST DT_PAGE * pPageEnd;\r
+ UINT8 * pVerb;\r
+ UINT8 * pVersion;\r
+ UINT8 * pWebPage;\r
+ EFI_STATUS Status;\r
+\r
+ DBG_ENTER ( );\r
+\r
+ //\r
+ // Assume the request is not finished\r
+ //\r
+ *pbDone = FALSE;\r
+ Status = EFI_SUCCESS;\r
+ for ( ; ; ) {\r
+\r
+ //\r
+ // Attempt to parse the command\r
+ //\r
+ pData = &pPort->Request[0];\r
+ pEnd = &pData [ pPort->RequestLength ];\r
+ pVerb = pData;\r
+ pWebPage = HttpReplaceSpace ( pVerb, pEnd );\r
+ if ( pEnd <= pWebPage ) {\r
+ break;\r
+ }\r
+ pVersion = HttpReplaceSpace ( pWebPage, pEnd );\r
+ if ( pEnd <= pVersion ) {\r
+ break;\r
+ }\r
+\r
+ //\r
+ // Validate the request\r
+ //\r
+ if ( 0 != HttpMatch ( L"GET", pVerb, TRUE )) {\r
+ //\r
+ // Invalid request type\r
+ //\r
+ DEBUG (( DEBUG_REQUEST,\r
+ "HTTP: Invalid verb\r\n" ));\r
+ Status = EFI_NOT_FOUND;\r
+ break;\r
+ }\r
+\r
+ //\r
+ // Walk the page table\r
+ //\r
+ pPage = &mPageList[0];\r
+ pPageEnd = &pPage [ mPageCount ];\r
+ while ( pPageEnd > pPage ) {\r
+ //\r
+ // Determine if the page was located\r
+ //\r
+ if ( 0 == HttpMatch ( pPage->pPageName, pWebPage, FALSE )) {\r
+ break;\r
+ }\r
+\r
+ //\r
+ // Set the next page\r
+ //\r
+ pPage += 1;\r
+ }\r
+ if ( pPageEnd <= pPage ) {\r
+ //\r
+ // The page was not found\r
+ //\r
+ DEBUG (( DEBUG_REQUEST,\r
+ "HTTP: Page not found in page table\r\n" ));\r
+ Status = EFI_NOT_FOUND;\r
+ break;\r
+ }\r
+\r
+ //\r
+ // Respond with the page contents\r
+ //\r
+ Status = pPage->pfnResponse ( SocketFD, pPort, pbDone );\r
+ break;\r
+ }\r
+\r
+ //\r
+ // Return page not found if necessary\r
+ //\r
+ if ( EFI_NOT_FOUND == Status ) {\r
+ Status = HttpPageNotFound ( SocketFD, pPort, pbDone );\r
+ }\r
+\r
+ //\r
+ // Return the operation status\r
+ //\r
+ DBG_EXIT_STATUS ( Status );\r
+ return Status;\r
+}\r
+\r
+\r
+/**\r
+ Buffer data for sending\r
+\r
+ @param [in] SocketFD The socket's file descriptor to add to the list.\r
+ @param [in] pPort The WSDT_PORT structure address\r
+ @param [in] LengthInBytes Length of valid data in the buffer\r
+ @param [in] pBuffer Buffer of data to send\r
+\r
+ @retval EFI_SUCCESS The request was successfully processed\r
+\r
+**/\r
+EFI_STATUS\r
+HttpSend (\r
+ IN int SocketFD,\r
+ IN WSDT_PORT * pPort,\r
+ IN size_t LengthInBytes,\r
+ IN CONST UINT8 * pBuffer\r
+ )\r
+{\r
+ size_t DataBytes;\r
+ size_t MaxBytes;\r
+ EFI_STATUS Status;\r
+\r
+ //\r
+ // Assume success\r
+ //\r
+ Status = EFI_SUCCESS;\r
+ do {\r
+ //\r
+ // Determine how much data fits into the buffer\r
+ //\r
+ MaxBytes = sizeof ( pPort->TxBuffer );\r
+ DataBytes = MaxBytes - pPort->TxBytes;\r
+ if ( DataBytes > LengthInBytes )\r
+ {\r
+ DataBytes = LengthInBytes;\r
+ }\r
+\r
+ //\r
+ // Copy the data into the buffer\r
+ //\r
+ CopyMem ( &pPort->TxBuffer [ pPort->TxBytes ],\r
+ pBuffer,\r
+ DataBytes );\r
+\r
+ //\r
+ // Account for the data copied\r
+ //\r
+ pPort->TxBytes += DataBytes;\r
+ LengthInBytes -= DataBytes;\r
+\r
+ //\r
+ // Transmit the buffer if it is full\r
+ //\r
+ if ( MaxBytes <= pPort->TxBytes ) {\r
+ Status = HttpFlush ( SocketFD, pPort );\r
+ }\r
+ } while (( EFI_SUCCESS == Status ) && ( 0 < LengthInBytes ));\r
+\r
+ //\r
+ // Return the operation status\r
+ //\r
+ return Status;\r
+}\r
+\r
+\r
+/**\r
+ Send an ANSI string\r
+\r
+ @param [in] SocketFD The socket's file descriptor to add to the list.\r
+ @param [in] pPort The WSDT_PORT structure address\r
+ @param [in] pString A zero terminated Unicode string\r
+\r
+ @retval EFI_SUCCESS The request was successfully processed\r
+\r
+**/\r
+EFI_STATUS\r
+HttpSendAnsiString (\r
+ IN int SocketFD,\r
+ IN WSDT_PORT * pPort,\r
+ IN CONST char * pString\r
+ )\r
+{\r
+ CONST char * pData;\r
+ EFI_STATUS Status;\r
+\r
+ //\r
+ // Assume success\r
+ //\r
+ Status = EFI_SUCCESS;\r
+\r
+ //\r
+ // Walk the characters in he string\r
+ //\r
+ pData = pString;\r
+ while ( 0 != *pData ) {\r
+ pData += 1;\r
+ }\r
+\r
+ //\r
+ // Send the string\r
+ //\r
+ Status = HttpSend ( SocketFD,\r
+ pPort,\r
+ pData - pString,\r
+ (CONST UINT8 *)pString );\r
+\r
+ //\r
+ // Return the operation status\r
+ //\r
+ return Status;\r
+}\r
+\r
+\r
+/**\r
+ Buffer a single byte\r
+\r
+ @param [in] SocketFD The socket's file descriptor to add to the list.\r
+ @param [in] pPort The WSDT_PORT structure address\r
+ @param [in] Data The data byte to send\r
+\r
+ @retval EFI_SUCCESS The request was successfully processed\r
+\r
+**/\r
+EFI_STATUS\r
+HttpSendByte (\r
+ IN int SocketFD,\r
+ IN WSDT_PORT * pPort,\r
+ IN UINT8 Data\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+\r
+ //\r
+ // Send the data byte\r
+ //\r
+ Status = HttpSend ( SocketFD,\r
+ pPort,\r
+ 1,\r
+ &Data );\r
+\r
+ //\r
+ // Return the operation status\r
+ //\r
+ return Status;\r
+}\r
+\r
+\r
+/**\r
+ Display a character\r
+\r
+ @param [in] SocketFD The socket's file descriptor to add to the list.\r
+ @param [in] pPort The WSDT_PORT structure address\r
+ @param [in] Character Character to display\r
+ @param [in] pReplacement Replacement character string\r
+\r
+ @retval EFI_SUCCESS The request was successfully processed\r
+\r
+**/\r
+EFI_STATUS\r
+HttpSendCharacter (\r
+ IN int SocketFD,\r
+ IN WSDT_PORT * pPort,\r
+ IN CHAR8 Character,\r
+ IN CHAR8 * pReplacement\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+\r
+ //\r
+ // Determine if this is a printable character\r
+ //\r
+ if (( 0x20 <= Character ) && ( 0x7f > Character )) {\r
+ if ( '<' == Character ) {\r
+ //\r
+ // Replace with HTML equivalent\r
+ //\r
+ Status = HttpSendAnsiString ( SocketFD,\r
+ pPort,\r
+ "<" );\r
+ }\r
+ else if ( '>' == Character ) {\r
+ //\r
+ // Replace with HTML equivalent\r
+ //\r
+ Status = HttpSendAnsiString ( SocketFD,\r
+ pPort,\r
+ ">" );\r
+ }\r
+ else if ( '&' == Character ) {\r
+ //\r
+ // Replace with HTML equivalent\r
+ //\r
+ Status = HttpSendAnsiString ( SocketFD,\r
+ pPort,\r
+ "&" );\r
+ }\r
+ else if ( '\"' == Character ) {\r
+ //\r
+ // Replace with HTML equivalent\r
+ //\r
+ Status = HttpSendAnsiString ( SocketFD,\r
+ pPort,\r
+ """ );\r
+ }\r
+ else {\r
+ //\r
+ // Display the character\r
+ //\r
+ Status = HttpSendByte ( SocketFD,\r
+ pPort,\r
+ Character );\r
+ }\r
+ }\r
+ else {\r
+ //\r
+ // Not a displayable character\r
+ //\r
+ Status = HttpSendAnsiString ( SocketFD,\r
+ pPort,\r
+ pReplacement );\r
+ }\r
+\r
+ //\r
+ // Return the operation status\r
+ //\r
+ return Status;\r
+}\r
+\r
+\r
+/**\r
+ Send a buffer dump\r
+\r
+ @param [in] SocketFD The socket's file descriptor to add to the list.\r
+ @param [in] pPort The WSDT_PORT structure address\r
+ @param [in] ByteCount The number of bytes to display\r
+ @param [in] pData Address of the byte array\r
+\r
+ @retval EFI_SUCCESS The request was successfully processed\r
+\r
+**/\r
+EFI_STATUS\r
+HttpSendDump (\r
+ IN int SocketFD,\r
+ IN WSDT_PORT * pPort,\r
+ IN UINTN ByteCount,\r
+ IN CONST UINT8 * pData\r
+ )\r
+{\r
+ INTN BytesToDisplay;\r
+ UINT8 Character;\r
+ INTN Index;\r
+ INTN InitialSpaces;\r
+ CONST UINT8 * pDataEnd;\r
+ CONST UINT8 * pEnd;\r
+ CONST UINT8 * pTemp;\r
+ EFI_STATUS Status;\r
+\r
+ //\r
+ // Use for/break instead of goto\r
+ //\r
+ for ( ; ; ) {\r
+ //\r
+ // Start the field value\r
+ //\r
+ Status = HttpSendAnsiString ( SocketFD,\r
+ pPort,\r
+ "<code>" );\r
+ if ( EFI_ERROR ( Status )) {\r
+ break;\r
+ }\r
+\r
+ //\r
+ // Walk the bytes to be displayed\r
+ //\r
+ pEnd = &pData [ ByteCount ];\r
+ while ( pEnd > pData ) {\r
+ //\r
+ // Display the address\r
+ //\r
+ Status = HttpSendHexBits ( SocketFD,\r
+ pPort,\r
+ sizeof ( pData ) * 8,\r
+ (UINT64)pData );\r
+ if ( EFI_ERROR ( Status )) {\r
+ break;\r
+ }\r
+\r
+ //\r
+ // Separate the address and data\r
+ //\r
+ Status = HttpSendByte ( SocketFD, pPort, ':' );\r
+ if ( EFI_ERROR ( Status )) {\r
+ break;\r
+ }\r
+\r
+ //\r
+ // Position the starting data correctly\r
+ //\r
+ InitialSpaces = (UINTN)pData;\r
+ InitialSpaces &= BYTES_ON_A_LINE - 1;\r
+ for ( Index = SPACES_ADDRESS_TO_DATA\r
+ + (( 2 + SPACES_BETWEEN_BYTES )\r
+ * InitialSpaces );\r
+ 0 < Index; Index-- ) {\r
+ Status = HttpSendAnsiString ( SocketFD,\r
+ pPort,\r
+ " " );\r
+ if ( EFI_ERROR ( Status )) {\r
+ break;\r
+ }\r
+ }\r
+ if ( EFI_ERROR ( Status )) {\r
+ break;\r
+ }\r
+\r
+ //\r
+ // Display the data\r
+ //\r
+ BytesToDisplay = pEnd - pData;\r
+ if (( BYTES_ON_A_LINE - InitialSpaces ) < BytesToDisplay ) {\r
+ BytesToDisplay = BYTES_ON_A_LINE - InitialSpaces;\r
+ }\r
+ pDataEnd = &pData [ BytesToDisplay ];\r
+ pTemp = pData;\r
+ while ( pDataEnd > pTemp ) {\r
+ Status = HttpSendHexBits ( SocketFD,\r
+ pPort,\r
+ 8,\r
+ *pTemp++ );\r
+ if ( EFI_ERROR ( Status )) {\r
+ break;\r
+ }\r
+\r
+ //\r
+ // Separate the data bytes\r
+ //\r
+ for ( Index = SPACES_BETWEEN_BYTES; 0 < Index; Index-- ) {\r
+ Status = HttpSendAnsiString ( SocketFD,\r
+ pPort,\r
+ " " );\r
+ if ( EFI_ERROR ( Status )) {\r
+ break;\r
+ }\r
+ }\r
+ if ( EFI_ERROR ( Status )) {\r
+ break;\r
+ }\r
+ }\r
+ if ( EFI_ERROR ( Status )) {\r
+ break;\r
+ }\r
+\r
+ //\r
+ // Separate the data from the ASCII display\r
+ //\r
+ for ( Index = (( 2 + SPACES_BETWEEN_BYTES )\r
+ * ( BYTES_ON_A_LINE - BytesToDisplay - InitialSpaces ))\r
+ - SPACES_BETWEEN_BYTES\r
+ + SPACES_DATA_TO_ASCII\r
+ + InitialSpaces;\r
+ 0 < Index; Index-- ) {\r
+ Status = HttpSendAnsiString ( SocketFD,\r
+ pPort,\r
+ " " );\r
+ if ( EFI_ERROR ( Status )) {\r
+ break;\r
+ }\r
+ }\r
+ if ( EFI_ERROR ( Status )) {\r
+ break;\r
+ }\r
+\r
+ //\r
+ // Display the ASCII data\r
+ //\r
+ while ( pDataEnd > pData ) {\r
+ Character = *pData++;\r
+ Status = HttpSendCharacter ( SocketFD,\r
+ pPort,\r
+ Character,\r
+ "." );\r
+ if ( EFI_ERROR ( Status )) {\r
+ break;\r
+ }\r
+ }\r
+ if ( EFI_ERROR ( Status )) {\r
+ break;\r
+ }\r
+\r
+ //\r
+ // Terminate the line\r
+ //\r
+ Status = HttpSendAnsiString ( SocketFD,\r
+ pPort,\r
+ "<br/>\r\n" );\r
+ if ( EFI_ERROR ( Status )) {\r
+ break;\r
+ }\r
+ }\r
+\r
+ //\r
+ // Terminate the field value and row\r
+ //\r
+ Status = HttpSendAnsiString ( SocketFD,\r
+ pPort,\r
+ "</code>\r\n" );\r
+ break;\r
+ }\r
+\r
+ //\r
+ // Return the operation status\r
+ //\r
+ return Status;\r
+}\r
+\r
+\r
+/**\r
+ Display a row containing a GUID value\r
+\r
+ @param [in] SocketFD The socket's file descriptor to add to the list.\r
+ @param [in] pPort The WSDT_PORT structure address\r
+ @param [in] pGuid Address of the GUID to display\r
+\r
+ @retval EFI_SUCCESS The request was successfully processed\r
+\r
+**/\r
+EFI_STATUS\r
+HttpSendGuid (\r
+ IN int SocketFD,\r
+ IN WSDT_PORT * pPort,\r
+ IN CONST EFI_GUID * pGuid\r
+ )\r
+{\r
+ UINT32 Index;\r
+ EFI_STATUS Status;\r
+\r
+ DBG_ENTER ( );\r
+\r
+ //\r
+ // Use for/break instead of goto\r
+ //\r
+ for ( ; ; ) {\r
+ //\r
+ // Display the GUID in a form found in the code\r
+ //\r
+ // E.g. 0xca16005f, 0x11ec, 0x4bdc, { 0x99, 0x97, 0x27, 0x2c, 0xa9, 0xba, 0x15, 0xe5 }\r
+ //\r
+\r
+ //\r
+ // Display the first 32 bits\r
+ //\r
+ Status = HttpSendAnsiString ( SocketFD,\r
+ pPort,\r
+ "0x" );\r
+ if ( EFI_ERROR ( Status )) {\r
+ break;\r
+ }\r
+ Status = HttpSendHexBits ( SocketFD,\r
+ pPort,\r
+ 32,\r
+ pGuid->Data1 );\r
+ if ( EFI_ERROR ( Status )) {\r
+ break;\r
+ }\r
+\r
+ //\r
+ // Display the second 16 bits\r
+ //\r
+ Status = HttpSendAnsiString ( SocketFD,\r
+ pPort,\r
+ ", 0x" );\r
+ if ( EFI_ERROR ( Status )) {\r
+ break;\r
+ }\r
+ Status = HttpSendHexBits ( SocketFD,\r
+ pPort,\r
+ 16,\r
+ pGuid->Data2 );\r
+ if ( EFI_ERROR ( Status )) {\r
+ break;\r
+ }\r
+\r
+ //\r
+ // Display the thrid 16 bits\r
+ //\r
+ Status = HttpSendAnsiString ( SocketFD,\r
+ pPort,\r
+ ", 0x" );\r
+ if ( EFI_ERROR ( Status )) {\r
+ break;\r
+ }\r
+ Status = HttpSendHexBits ( SocketFD,\r
+ pPort,\r
+ 16,\r
+ pGuid->Data3 );\r
+ if ( EFI_ERROR ( Status )) {\r
+ break;\r
+ }\r
+\r
+ //\r
+ // Place the last 64 bits in braces\r
+ //\r
+ Status = HttpSendAnsiString ( SocketFD,\r
+ pPort,\r
+ ", { 0x" );\r
+ if ( EFI_ERROR ( Status )) {\r
+ break;\r
+ }\r
+ for ( Index = 0; 7 >= Index; Index++ ) {\r
+ //\r
+ // Display the next 8 bits\r
+ //\r
+ Status = HttpSendHexBits ( SocketFD,\r
+ pPort,\r
+ 8,\r
+ pGuid->Data4 [ Index ]);\r
+ if ( EFI_ERROR ( Status )) {\r
+ break;\r
+ }\r
+\r
+ //\r
+ // Separate the bytes\r
+ //\r
+ Status = HttpSendAnsiString ( SocketFD,\r
+ pPort,\r
+ ( 7 != Index ) ? ", 0x" : " }" );\r
+ if ( EFI_ERROR ( Status )) {\r
+ break;\r
+ }\r
+ }\r
+ break;\r
+ }\r
+\r
+ //\r
+ // Return the operation status\r
+ //\r
+ DBG_EXIT_STATUS ( Status );\r
+ return Status;\r
+}\r
+\r
+\r
+/**\r
+ Output a hex value to the HTML page\r
+\r
+ @param [in] SocketFD Socket file descriptor\r
+ @param [in] pPort The WSDT_PORT structure address\r
+ @param [in] Bits Number of bits to display\r
+ @param [in] Value Value to display\r
+\r
+ @retval EFI_SUCCESS Successfully displayed the address\r
+**/\r
+EFI_STATUS\r
+HttpSendHexBits (\r
+ IN int SocketFD,\r
+ IN WSDT_PORT * pPort,\r
+ IN INT32 Bits,\r
+ IN UINT64 Value\r
+ )\r
+{\r
+ UINT32 Digit;\r
+ INT32 Shift;\r
+ EFI_STATUS Status;\r
+\r
+ //\r
+ // Assume success\r
+ //\r
+ Status = EFI_SUCCESS;\r
+\r
+ //\r
+ // Walk the list of divisors\r
+ //\r
+ Shift = (( Bits + 3 ) & ( ~3 )) - 4;\r
+ while ( 0 <= Shift ) {\r
+ //\r
+ // Determine the next digit\r
+ //\r
+ Digit = (UINT32)(( Value >> Shift ) & 0xf );\r
+ if ( 10 <= Digit ) {\r
+ Digit += 'A' - '0' - 10;\r
+ }\r
+\r
+ //\r
+ // Display the digit\r
+ //\r
+ Status = HttpSendByte ( SocketFD, pPort, (UINT8)( '0' + Digit ));\r
+ if ( EFI_ERROR ( Status )) {\r
+ break;\r
+ }\r
+\r
+ //\r
+ // Set the next shift\r
+ //\r
+ Shift -= 4;\r
+ }\r
+\r
+ //\r
+ // Return the operation status\r
+ //\r
+ return Status;\r
+}\r
+\r
+\r
+/**\r
+ Output a hex value to the HTML page\r
+\r
+ @param [in] SocketFD Socket file descriptor\r
+ @param [in] pPort The WSDT_PORT structure address\r
+ @param [in] Value Value to display\r
+\r
+ @retval EFI_SUCCESS Successfully displayed the address\r
+**/\r
+EFI_STATUS\r
+HttpSendHexValue (\r
+ IN int SocketFD,\r
+ IN WSDT_PORT * pPort,\r
+ IN UINT64 Value\r
+ )\r
+{\r
+ BOOLEAN bDisplayZeros;\r
+ UINT32 Digit;\r
+ INT32 Shift;\r
+ EFI_STATUS Status;\r
+\r
+ //\r
+ // Assume success\r
+ //\r
+ Status = EFI_SUCCESS;\r
+\r
+ //\r
+ // Walk the list of divisors\r
+ //\r
+ bDisplayZeros = FALSE;\r
+ Shift = 60;\r
+ do {\r
+ //\r
+ // Determine the next digit\r
+ //\r
+ Digit = (UINT32)(( Value >> Shift ) & 0xf );\r
+ if ( 10 <= Digit ) {\r
+ Digit += 'A' - '0' - 10;\r
+ }\r
+\r
+ //\r
+ // Suppress leading zeros\r
+ //\r
+ if (( 0 != Digit ) || bDisplayZeros || ( 0 == Shift )) {\r
+ bDisplayZeros = TRUE;\r
+\r
+ //\r
+ // Display the digit\r
+ //\r
+ Status = HttpSendByte ( SocketFD, pPort, (UINT8)( '0' + Digit ));\r
+ if ( EFI_ERROR ( Status )) {\r
+ break;\r
+ }\r
+ }\r
+\r
+ //\r
+ // Set the next shift\r
+ //\r
+ Shift -= 4;\r
+ } while ( 0 <= Shift );\r
+\r
+ //\r
+ // Return the operation status\r
+ //\r
+ return Status;\r
+}\r
+\r
+\r
+/**\r
+ Output an IP address to the HTML page\r
+\r
+ @param [in] SocketFD Socket file descriptor\r
+ @param [in] pPort The WSDT_PORT structure address\r
+ @param [in] pAddress Address of the socket address\r
+\r
+ @retval EFI_SUCCESS Successfully displayed the address\r
+**/\r
+EFI_STATUS\r
+HttpSendIpAddress (\r
+ IN int SocketFD,\r
+ IN WSDT_PORT * pPort,\r
+ IN struct sockaddr_in * pAddress\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+\r
+ //\r
+ // Output the IPv4 address\r
+ //\r
+ Status = HttpSendValue ( SocketFD, pPort, (UINT8)pAddress->sin_addr.s_addr );\r
+ if ( !EFI_ERROR ( Status )) {\r
+ Status = HttpSendByte ( SocketFD, pPort, '.' );\r
+ if ( !EFI_ERROR ( Status )) {\r
+ Status = HttpSendValue ( SocketFD, pPort, (UINT8)( pAddress->sin_addr.s_addr >> 8 ));\r
+ if ( !EFI_ERROR ( Status )) {\r
+ Status = HttpSendByte ( SocketFD, pPort, '.' );\r
+ if ( !EFI_ERROR ( Status )) {\r
+ Status = HttpSendValue ( SocketFD, pPort, (UINT8)( pAddress->sin_addr.s_addr >> 16 ));\r
+ if ( !EFI_ERROR ( Status )) {\r
+ Status = HttpSendByte ( SocketFD, pPort, '.' );\r
+ if ( !EFI_ERROR ( Status )) {\r
+ Status = HttpSendValue ( SocketFD, pPort, (UINT8)( pAddress->sin_addr.s_addr >> 24 ));\r
+ if ( !EFI_ERROR ( Status )) {\r
+ //\r
+ // Output the port number\r
+ //\r
+ Status = HttpSendByte ( SocketFD, pPort, ':' );\r
+ if ( !EFI_ERROR ( Status )) {\r
+ Status = HttpSendValue ( SocketFD, pPort, htons ( pAddress->sin_port ));\r
+ }\r
+ }\r
+ }\r
+ }\r
+ }\r
+ }\r
+ }\r
+ }\r
+\r
+ //\r
+ // Return the operation status\r
+ //\r
+ return Status;\r
+}\r
+\r
+\r
+/**\r
+ Send a Unicode string\r
+\r
+ @param [in] SocketFD The socket's file descriptor to add to the list.\r
+ @param [in] pPort The WSDT_PORT structure address\r
+ @param [in] pString A zero terminated Unicode string\r
+\r
+ @retval EFI_SUCCESS The request was successfully processed\r
+\r
+**/\r
+EFI_STATUS\r
+HttpSendUnicodeString (\r
+ IN int SocketFD,\r
+ IN WSDT_PORT * pPort,\r
+ IN CONST UINT16 * pString\r
+ )\r
+{\r
+ UINT8 Data;\r
+ UINT16 Character;\r
+ EFI_STATUS Status;\r
+\r
+ //\r
+ // Assume success\r
+ //\r
+ Status = EFI_SUCCESS;\r
+\r
+ //\r
+ // Walk the characters in he string\r
+ //\r
+ while ( 0 != ( Character = *pString++ )) {\r
+ //\r
+ // Convert the character to UTF-8\r
+ //\r
+ if ( 0 != ( Character & 0xf800 )) {\r
+ //\r
+ // Send the upper 4 bits\r
+ //\r
+ Data = (UINT8)(( Character >> 12 ) & 0xf );\r
+ Data |= 0xe0;\r
+ Status = HttpSendByte ( SocketFD,\r
+ pPort,\r
+ Data );\r
+ if ( EFI_ERROR ( Status )) {\r
+ break;\r
+ }\r
+\r
+ //\r
+ // Send the next 6 bits\r
+ //\r
+ Data = (UINT8)(( Character >> 6 ) & 0x3f );\r
+ Data |= 0x80;\r
+ Status = HttpSendByte ( SocketFD,\r
+ pPort,\r
+ Data );\r
+ if ( EFI_ERROR ( Status )) {\r
+ break;\r
+ }\r
+\r
+ //\r
+ // Send the last 6 bits\r
+ //\r
+ Data = (UINT8)( Character & 0x3f );\r
+ Data |= 0x80;\r
+ }\r
+ else if ( 0 != ( Character & 0x0780 )) {\r
+ //\r
+ // Send the upper 5 bits\r
+ //\r
+ Data = (UINT8)(( Character >> 6 ) & 0x1f );\r
+ Data |= 0xc0;\r
+ Status = HttpSendByte ( SocketFD,\r
+ pPort,\r
+ Data );\r
+ if ( EFI_ERROR ( Status )) {\r
+ break;\r
+ }\r
+\r
+ //\r
+ // Send the last 6 bits\r
+ //\r
+ Data = (UINT8)( Character & 0x3f );\r
+ Data |= 0x80;\r
+ }\r
+ else {\r
+ Data = (UINT8)( Character & 0x7f );\r
+ }\r
+\r
+ //\r
+ // Send the last data byte\r
+ //\r
+ Status = HttpSendByte ( SocketFD,\r
+ pPort,\r
+ Data );\r
+ if ( EFI_ERROR ( Status )) {\r
+ break;\r
+ }\r
+ }\r
+\r
+ //\r
+ // Return the operation status\r
+ //\r
+ return Status;\r
+}\r
+\r
+\r
+/**\r
+ Output a value to the HTML page\r
+\r
+ @param [in] SocketFD Socket file descriptor\r
+ @param [in] pPort The WSDT_PORT structure address\r
+ @param [in] Value Value to display\r
+\r
+ @retval EFI_SUCCESS Successfully displayed the address\r
+**/\r
+EFI_STATUS\r
+HttpSendValue (\r
+ IN int SocketFD,\r
+ IN WSDT_PORT * pPort,\r
+ IN UINT64 Value\r
+ )\r
+{\r
+ BOOLEAN bDisplayZeros;\r
+ UINT64 Digit;\r
+ CONST UINT64 * pEnd;\r
+ CONST UINT64 * pDivisor;\r
+ CONST UINT64 pDivisors [ ] = {\r
+ 10000000000000000000L,\r
+ 1000000000000000000L,\r
+ 100000000000000000L,\r
+ 10000000000000000L,\r
+ 1000000000000000L,\r
+ 100000000000000L,\r
+ 10000000000000L,\r
+ 1000000000000L,\r
+ 100000000000L,\r
+ 10000000000L,\r
+ 1000000000L,\r
+ 100000000L,\r
+ 10000000L,\r
+ 1000000L,\r
+ 100000L,\r
+ 10000L,\r
+ 1000L,\r
+ 100L,\r
+ 10L\r
+ };\r
+ EFI_STATUS Status;\r
+ UINT64 Temp;\r
+\r
+ //\r
+ // Assume success\r
+ //\r
+ Status = EFI_SUCCESS;\r
+\r
+ //\r
+ // Walk the list of divisors\r
+ //\r
+ bDisplayZeros = FALSE;\r
+ pDivisor = &pDivisors[0];\r
+ pEnd = &pDivisor [ sizeof ( pDivisors ) / sizeof ( pDivisors [0])];\r
+ while ( pEnd > pDivisor ) {\r
+ //\r
+ // Determine the next digit\r
+ //\r
+ Digit = Value / *pDivisor;\r
+\r
+ //\r
+ // Suppress leading zeros\r
+ //\r
+ if (( 0 != Digit ) || bDisplayZeros ) {\r
+ bDisplayZeros = TRUE;\r
+\r
+ //\r
+ // Display the digit\r
+ //\r
+ Status = HttpSendByte ( SocketFD, pPort, (UINT8)( '0' + Digit ));\r
+ if ( EFI_ERROR ( Status )) {\r
+ break;\r
+ }\r
+\r
+ //\r
+ // Determine the remainder\r
+ //\r
+ Temp = *pDivisor * Digit;\r
+ Value -= Temp;\r
+ }\r
+\r
+ //\r
+ // Set the next divisor\r
+ //\r
+ pDivisor += 1;\r
+ }\r
+\r
+ //\r
+ // Display the final digit\r
+ //\r
+ if ( !EFI_ERROR ( Status )) {\r
+ Status = HttpSendByte ( SocketFD, pPort, (UINT8)( '0' + Value ));\r
+ }\r
+\r
+ //\r
+ // Return the operation status\r
+ //\r
+ return Status;\r
+}\r