Home | History | Annotate | Download | only in WebServer
      1 /**
      2   @file
      3   HTTP processing for the web server.
      4 
      5   Copyright (c) 2011-2012, Intel Corporation
      6   All rights reserved. This program and the accompanying materials
      7   are licensed and made available under the terms and conditions of the BSD License
      8   which accompanies this distribution.  The full text of the license may be found at
      9   http://opensource.org/licenses/bsd-license.php
     10 
     11   THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     12   WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     13 
     14 **/
     15 
     16 #include <WebServer.h>
     17 
     18 
     19 /**
     20   Get a UTF-8 character from the buffer
     21 
     22   @param [in] pData     The address of the buffer containing the character
     23   @param [out] ppData   The address to receive the next character address
     24 
     25   @return     The character value
     26 
     27 **/
     28 INTN
     29 HttpCharGet (
     30   IN UINT8 * pData,
     31   IN UINT8 ** ppData
     32   )
     33 {
     34   INTN Data;
     35   INTN Character;
     36   INTN Control;
     37   INTN Mask;
     38 
     39   //
     40   //  Verify that there is some data left
     41   //
     42   if ( NULL == pData ) {
     43     //
     44     //  No data to return
     45     //
     46     pData = NULL;
     47     Character = 0;
     48   }
     49   else {
     50     //
     51     //  Get the first portion of the character
     52     //
     53     Character = *pData++;
     54     Control = Character;
     55     Mask = 0xc0;
     56 
     57     //
     58     //  Append the rest of the character
     59     //
     60     if ( 0 != ( Control & 0x80 )) {
     61       while ( 0 != ( Control & 0x40 )) {
     62         Character &= Mask;
     63         Mask <<= 5;
     64         Control <<= 1;
     65         Character <<= 6;
     66         Data = *pData++ & 0x3f;
     67         if ( 0x80 != ( Data & 0xc0 )) {
     68           //
     69           //  Invalid character
     70           //
     71           pData = NULL;
     72           Character = 0;
     73           break;
     74         }
     75         Character |= Data & 0x3f;
     76       }
     77     }
     78   }
     79 
     80   //
     81   //  Return the next character location and the character
     82   //
     83   *ppData = pData;
     84   return Character;
     85 }
     86 
     87 
     88 /**
     89   Transmit a portion of the HTTP response
     90 
     91   @param [in] SocketFD      The socket's file descriptor to add to the list.
     92   @param [in] pPort         The WSDT_PORT structure address
     93 
     94   @retval EFI_SUCCESS       The request was successfully processed
     95 
     96 **/
     97 EFI_STATUS
     98 HttpFlush (
     99   IN int SocketFD,
    100   IN WSDT_PORT * pPort
    101   )
    102 {
    103   INTN LengthInBytes;
    104   UINT8 * pBuffer;
    105   EFI_STATUS Status;
    106 
    107   DBG_ENTER ( );
    108 
    109   //
    110   //  Assume success
    111   //
    112   Status = EFI_SUCCESS;
    113   pBuffer = &pPort->TxBuffer[0];
    114   do {
    115     //
    116     //  Attempt to send the data
    117     //
    118     LengthInBytes = send ( SocketFD,
    119                            pBuffer,
    120                            pPort->TxBytes,
    121                            0 );
    122     if ( -1 != LengthInBytes ) {
    123       //
    124       //  Account for the data sent
    125       //
    126       pBuffer += LengthInBytes;
    127       pPort->TxBytes -= LengthInBytes;
    128     }
    129     else {
    130       //
    131       //  Transmit error
    132       //
    133       Status = EFI_DEVICE_ERROR;
    134       break;
    135     }
    136   } while ( 0 < pPort->TxBytes );
    137 
    138   //
    139   //  Return the operation status
    140   //
    141   DBG_EXIT_STATUS ( Status );
    142   return Status;
    143 }
    144 
    145 
    146 /**
    147   Convert the ANSI character to lower case
    148 
    149   @param [in] Character The character to convert to lower case.
    150 
    151   @return   The lower case character
    152 
    153 **/
    154 INTN
    155 HttpLowerCase (
    156   IN INTN Character
    157   )
    158 {
    159   //
    160   //  Determine if the character is upper case
    161   //
    162   if (( 'A' <= Character ) && ( 'Z' >= Character )) {
    163     Character += 'a' - 'A';
    164   }
    165 
    166   //
    167   //  Return the lower case value of the character
    168   //
    169   return Character;
    170 }
    171 
    172 
    173 /**
    174   Match a Unicode string against a UTF-8 string
    175 
    176   @param [in] pString     A zero terminated Unicode string
    177   @param [in] pData       A zero terminated UTF-8 string
    178   @param [in] bIgnoreCase TRUE if case is to be ignored
    179 
    180   @return     The difference between the last two characters tested.
    181               Returns -1 for error.
    182 
    183 **/
    184 INTN
    185 HttpMatch (
    186   IN UINT16 * pString,
    187   IN UINT8 * pData,
    188   IN BOOLEAN bIgnoreCase
    189   )
    190 {
    191   INTN Character1;
    192   INTN Character2;
    193   INTN Difference;
    194 
    195   do {
    196     //
    197     //  Get the character from the comparison string
    198     //
    199     Character1 = *pString++;
    200 
    201     //
    202     //  Convert the character to lower case
    203     //
    204     if ( bIgnoreCase ) {
    205       Character1 = HttpLowerCase ( Character1 );
    206     }
    207 
    208     //
    209     //  Get the character from the request
    210     //
    211     Character2 = HttpCharGet ( pData, &pData );
    212     if ( NULL == pData ) {
    213        //
    214        // Error getting character
    215        //
    216        Difference = -1;
    217        break;
    218     }
    219 
    220     //
    221     //  Convert the character to lower case
    222     //
    223     if ( bIgnoreCase ) {
    224       Character2 = HttpLowerCase ( Character2 );
    225     }
    226 
    227     //
    228     //  Compare the characters
    229     //
    230     Difference = Character1 - Character2;
    231     if ( 0 != Difference ) {
    232       return Difference;
    233     }
    234   } while ( 0 != Character1 );
    235 
    236   //
    237   //  Return the difference
    238   //
    239   return Difference;
    240 }
    241 
    242 
    243 /**
    244   Buffer the HTTP page header
    245 
    246   @param [in] SocketFD      The socket's file descriptor to add to the list.
    247   @param [in] pPort         The WSDT_PORT structure address
    248   @param [in] pTitle        A zero terminated Unicode title string
    249 
    250   @retval EFI_SUCCESS       The request was successfully processed
    251 
    252 **/
    253 EFI_STATUS
    254 HttpPageHeader (
    255   IN int SocketFD,
    256   IN WSDT_PORT * pPort,
    257   IN CONST CHAR16 * pTitle
    258   )
    259 {
    260   EFI_STATUS Status;
    261 
    262   DBG_ENTER ( );
    263 
    264   //
    265   //  Build the page header
    266   //
    267   for ( ; ; ) {
    268     Status = HttpSendAnsiString ( SocketFD,
    269                                   pPort,
    270                                   "<!DOCTYPE "
    271                                   "HTML "
    272                                   "PUBLIC "
    273                                   "\"-//W3C//DTD HTML 4.01 Transitional//EN\" "
    274                                   "\"http://www.w3.org/TR/html4/loose.dtd\">\r\n" );
    275     if ( EFI_ERROR ( Status )) {
    276       break;
    277     }
    278     Status = HttpSendAnsiString ( SocketFD, pPort, "<html lang=\"en-US\">\r\n" );
    279     if ( EFI_ERROR ( Status )) {
    280       break;
    281     }
    282     if ( NULL != pTitle ) {
    283       Status = HttpSendAnsiString ( SocketFD, pPort, "  <head>\r\n" );
    284       if ( EFI_ERROR ( Status )) {
    285         break;
    286       }
    287       Status = HttpSendAnsiString ( SocketFD, pPort, "    <title>" );
    288       if ( EFI_ERROR ( Status )) {
    289         break;
    290       }
    291       Status = HttpSendUnicodeString ( SocketFD, pPort, pTitle );
    292       if ( EFI_ERROR ( Status )) {
    293         break;
    294       }
    295       Status = HttpSendAnsiString ( SocketFD, pPort, "</title>\r\n" );
    296       if ( EFI_ERROR ( Status )) {
    297         break;
    298       }
    299       Status = HttpSendAnsiString ( SocketFD, pPort, "  </head>\r\n" );
    300       if ( EFI_ERROR ( Status )) {
    301         break;
    302       }
    303     }
    304     Status = HttpSendAnsiString ( SocketFD, pPort, "  <body>\r\n" );
    305     break;
    306   }
    307 
    308   //
    309   //  Return the operation status
    310   //
    311   DBG_EXIT_STATUS ( Status );
    312   return Status;
    313 }
    314 
    315 
    316 /**
    317   Respond with an error indicating that the page was not found
    318 
    319   @param [in] SocketFD      The socket's file descriptor to add to the list.
    320   @param [in] pPort         The WSDT_PORT structure address
    321   @param [out] pbDone       Address to receive the request completion status
    322 
    323   @retval EFI_SUCCESS       The request was successfully processed
    324 
    325 **/
    326 EFI_STATUS
    327 HttpPageNotFound (
    328   IN int SocketFD,
    329   IN WSDT_PORT * pPort,
    330   IN BOOLEAN * pbDone
    331   )
    332 {
    333   EFI_STATUS Status;
    334 
    335   DBG_ENTER ( );
    336 
    337   //
    338   //  Send the page not found
    339   //
    340   for ( ; ; ) {
    341     //
    342     //  Send the page header
    343     //
    344     Status = HttpPageHeader ( SocketFD, pPort, L"404 Not found" );
    345     if ( EFI_ERROR ( Status )) {
    346       break;
    347     }
    348 
    349     //
    350     //  Send the page body
    351     //
    352     Status = HttpSendAnsiString ( SocketFD,
    353                                   pPort,
    354                                   "ERROR <b>404</b><br />"
    355                                   "Requested page is not available\r\n" );
    356     if ( EFI_ERROR ( Status )) {
    357       break;
    358     }
    359 
    360     //
    361     //  Send the page trailer
    362     //
    363     Status = HttpPageTrailer ( SocketFD, pPort, pbDone );
    364     break;
    365   }
    366 
    367   //
    368   //  Return the operation status
    369   //
    370   DBG_EXIT_STATUS ( Status );
    371   return Status;
    372 }
    373 
    374 
    375 /**
    376   Buffer and send the HTTP page trailer
    377 
    378   @param [in] SocketFD      The socket's file descriptor to add to the list.
    379   @param [in] pPort         The WSDT_PORT structure address
    380   @param [out] pbDone       Address to receive the request completion status
    381 
    382   @retval EFI_SUCCESS       The request was successfully processed
    383 
    384 **/
    385 EFI_STATUS
    386 HttpPageTrailer (
    387   IN int SocketFD,
    388   IN WSDT_PORT * pPort,
    389   IN BOOLEAN * pbDone
    390   )
    391 {
    392   int RetVal;
    393   EFI_STATUS Status;
    394   socklen_t LengthInBytes;
    395   struct sockaddr_in6 LocalAddress;
    396   struct sockaddr_in6 RemoteAddress;
    397 
    398   DBG_ENTER ( );
    399 
    400   //
    401   //  Build the page header
    402   //
    403   for ( ; ; ) {
    404     LengthInBytes = sizeof ( LocalAddress );
    405     RetVal = getsockname ( SocketFD, (struct sockaddr *)&LocalAddress, &LengthInBytes );
    406     if ( 0 == RetVal ) {
    407       LengthInBytes = sizeof ( LocalAddress );
    408       RetVal = getpeername ( SocketFD, (struct sockaddr *)&RemoteAddress, &LengthInBytes );
    409       if ( 0 == RetVal ) {
    410         //
    411         //  Seperate the body from the trailer
    412         //
    413         Status = HttpSendAnsiString ( SocketFD, pPort, "  <hr>\r\n<code>" );
    414         if ( EFI_ERROR ( Status )) {
    415           break;
    416         }
    417 
    418         //
    419         //  Display the system addresses and the page transfer direction
    420         //
    421         Status = HttpSendIpAddress ( SocketFD, pPort, &LocalAddress );
    422         if ( EFI_ERROR ( Status )) {
    423           break;
    424         }
    425         Status = HttpSendAnsiString ( SocketFD, pPort, "  -->  " );
    426         if ( EFI_ERROR ( Status )) {
    427           break;
    428         }
    429         Status = HttpSendIpAddress ( SocketFD, pPort, &RemoteAddress );
    430         if ( EFI_ERROR ( Status )) {
    431           break;
    432         }
    433         Status = HttpSendAnsiString ( SocketFD, pPort, "</code>\r\n" );
    434         if ( EFI_ERROR ( Status )) {
    435           break;
    436         }
    437       }
    438     }
    439 
    440     //
    441     //  Terminate the page
    442     //
    443     Status = HttpSendAnsiString ( SocketFD, pPort, "  </body>\r\n" );
    444     if ( EFI_ERROR ( Status )) {
    445       break;
    446     }
    447     Status = HttpSendAnsiString ( SocketFD, pPort, "  </html>\r\n" );
    448     if ( EFI_ERROR ( Status )) {
    449       break;
    450     }
    451 
    452     //
    453     //  Send the page trailer
    454     //
    455     Status = HttpFlush ( SocketFD, pPort );
    456     if ( EFI_ERROR ( Status )) {
    457       break;
    458     }
    459 
    460     //
    461     //  Mark the page as complete
    462     //
    463     *pbDone = TRUE;
    464     break;
    465   }
    466 
    467   //
    468   //  Return the operation status
    469   //
    470   DBG_EXIT_STATUS ( Status );
    471   return Status;
    472 }
    473 
    474 
    475 /**
    476   Replace a space with a zero
    477 
    478   @param [in] pData     The request buffer address
    479   @param [in] pEnd      End of buffer address
    480 
    481   @return     The next character location
    482 
    483 **/
    484 UINT8 *
    485 HttpReplaceSpace (
    486   IN UINT8 * pData,
    487   IN UINT8 * pEnd
    488   )
    489 {
    490   INTN Character;
    491   UINT8 * pSpace;
    492 
    493   pSpace = pData;
    494   while ( pEnd > pData ) {
    495     //
    496     //  Get the character from the request
    497     //
    498     Character = HttpCharGet ( pData, &pData );
    499     if ( ' ' == Character ) {
    500       break;
    501     }
    502     pSpace = pData;
    503   }
    504 
    505   //
    506   //  Replace the space character with zero
    507   //
    508   ZeroMem ( pSpace, pData - pSpace );
    509 
    510   //
    511   //  Return the next character location
    512   //
    513   return pData;
    514 }
    515 
    516 
    517 /**
    518   Process an HTTP request
    519 
    520   @param [in] SocketFD      The socket's file descriptor to add to the list.
    521   @param [in] pPort         The WSDT_PORT structure address
    522   @param [out] pbDone       Address to receive the request completion status
    523 
    524   @retval EFI_SUCCESS       The request was successfully processed
    525 
    526 **/
    527 EFI_STATUS
    528 HttpRequest (
    529   IN int SocketFD,
    530   IN WSDT_PORT * pPort,
    531   OUT BOOLEAN * pbDone
    532   )
    533 {
    534   UINT8 * pData;
    535   UINT8 * pEnd;
    536   CONST DT_PAGE * pPage;
    537   CONST DT_PAGE * pPageEnd;
    538   UINT8 * pVerb;
    539   UINT8 * pVersion;
    540   UINT8 * pWebPage;
    541   EFI_STATUS Status;
    542 
    543   DBG_ENTER ( );
    544 
    545   //
    546   //  Assume the request is not finished
    547   //
    548   *pbDone = FALSE;
    549   Status = EFI_SUCCESS;
    550   for ( ; ; ) {
    551 
    552     //
    553     //  Attempt to parse the command
    554     //
    555     pData = &pPort->Request[0];
    556     pEnd = &pData[ pPort->RequestLength ];
    557     pVerb = pData;
    558     pWebPage = HttpReplaceSpace ( pVerb, pEnd );
    559     if ( pEnd <= pWebPage ) {
    560       break;
    561     }
    562     pVersion = HttpReplaceSpace ( pWebPage, pEnd );
    563     if ( pEnd <= pVersion ) {
    564       break;
    565     }
    566 
    567     //
    568     //  Validate the request
    569     //
    570     if ( 0 != HttpMatch ( L"GET", pVerb, TRUE )) {
    571       //
    572       //  Invalid request type
    573       //
    574       DEBUG (( DEBUG_REQUEST,
    575                 "HTTP: Invalid verb\r\n" ));
    576       Status = EFI_NOT_FOUND;
    577       break;
    578     }
    579 
    580     //
    581     //  Walk the page table
    582     //
    583     pPage = &mPageList[0];
    584     pPageEnd = &pPage[ mPageCount ];
    585     while ( pPageEnd > pPage ) {
    586       //
    587       //  Determine if the page was located
    588       //
    589       if ( 0 == HttpMatch ( pPage->pPageName, pWebPage, FALSE )) {
    590         break;
    591       }
    592 
    593       //
    594       //  Set the next page
    595       //
    596       pPage += 1;
    597     }
    598     if ( pPageEnd <= pPage ) {
    599       //
    600       //  The page was not found
    601       //
    602       DEBUG (( DEBUG_REQUEST,
    603                 "HTTP: Page not found in page table\r\n" ));
    604       Status = EFI_NOT_FOUND;
    605       break;
    606     }
    607 
    608     //
    609     //  Respond with the page contents
    610     //
    611     Status = pPage->pfnResponse ( SocketFD, pPort, pbDone );
    612     break;
    613   }
    614 
    615   //
    616   //  Return page not found if necessary
    617   //
    618   if ( EFI_NOT_FOUND == Status ) {
    619     Status = HttpPageNotFound ( SocketFD, pPort, pbDone );
    620   }
    621 
    622   //
    623   //  Return the operation status
    624   //
    625   DBG_EXIT_STATUS ( Status );
    626   return Status;
    627 }
    628 
    629 
    630 /**
    631   Buffer data for sending
    632 
    633   @param [in] SocketFD      The socket's file descriptor to add to the list.
    634   @param [in] pPort         The WSDT_PORT structure address
    635   @param [in] LengthInBytes Length of valid data in the buffer
    636   @param [in] pBuffer       Buffer of data to send
    637 
    638   @retval EFI_SUCCESS       The request was successfully processed
    639 
    640 **/
    641 EFI_STATUS
    642 HttpSend (
    643   IN int SocketFD,
    644   IN WSDT_PORT * pPort,
    645   IN size_t LengthInBytes,
    646   IN CONST UINT8 * pBuffer
    647   )
    648 {
    649   size_t DataBytes;
    650   size_t MaxBytes;
    651   EFI_STATUS Status;
    652 
    653   //
    654   //  Assume success
    655   //
    656   Status = EFI_SUCCESS;
    657   do {
    658     //
    659     //  Determine how much data fits into the buffer
    660     //
    661     MaxBytes = sizeof ( pPort->TxBuffer );
    662     DataBytes = MaxBytes - pPort->TxBytes;
    663     if ( DataBytes > LengthInBytes ) {
    664       DataBytes = LengthInBytes;
    665     }
    666 
    667     //
    668     //  Copy the data into the buffer
    669     //
    670     CopyMem ( &pPort->TxBuffer[ pPort->TxBytes ],
    671               pBuffer,
    672               DataBytes );
    673 
    674     //
    675     //  Account for the data copied
    676     //
    677     pPort->TxBytes += DataBytes;
    678     LengthInBytes -= DataBytes;
    679 
    680     //
    681     //  Transmit the buffer if it is full
    682     //
    683     if ( MaxBytes <= pPort->TxBytes ) {
    684       Status = HttpFlush ( SocketFD, pPort );
    685     }
    686   } while (( EFI_SUCCESS == Status ) && ( 0 < LengthInBytes ));
    687 
    688   //
    689   //  Return the operation status
    690   //
    691   return Status;
    692 }
    693 
    694 
    695 /**
    696   Send an ANSI string
    697 
    698   @param [in] SocketFD      The socket's file descriptor to add to the list.
    699   @param [in] pPort         The WSDT_PORT structure address
    700   @param [in] pString       A zero terminated Unicode string
    701 
    702   @retval EFI_SUCCESS       The request was successfully processed
    703 
    704 **/
    705 EFI_STATUS
    706 HttpSendAnsiString (
    707   IN int SocketFD,
    708   IN WSDT_PORT * pPort,
    709   IN CONST char * pString
    710   )
    711 {
    712   CONST char * pData;
    713   EFI_STATUS Status;
    714 
    715   //
    716   //  Assume success
    717   //
    718   Status = EFI_SUCCESS;
    719 
    720   //
    721   //  Walk the characters in he string
    722   //
    723   pData = pString;
    724   while ( 0 != *pData ) {
    725     pData += 1;
    726   }
    727 
    728   //
    729   //  Send the string
    730   //
    731   Status = HttpSend ( SocketFD,
    732                       pPort,
    733                       pData - pString,
    734                       (CONST UINT8 *)pString );
    735 
    736   //
    737   //  Return the operation status
    738   //
    739   return Status;
    740 }
    741 
    742 
    743 /**
    744   Buffer a single byte
    745 
    746   @param [in] SocketFD      The socket's file descriptor to add to the list.
    747   @param [in] pPort         The WSDT_PORT structure address
    748   @param [in] Data          The data byte to send
    749 
    750   @retval EFI_SUCCESS       The request was successfully processed
    751 
    752 **/
    753 EFI_STATUS
    754 HttpSendByte (
    755   IN int SocketFD,
    756   IN WSDT_PORT * pPort,
    757   IN UINT8 Data
    758   )
    759 {
    760   EFI_STATUS Status;
    761 
    762   //
    763   //  Send the data byte
    764   //
    765   Status = HttpSend ( SocketFD,
    766                       pPort,
    767                       1,
    768                       &Data );
    769 
    770   //
    771   //  Return the operation status
    772   //
    773   return Status;
    774 }
    775 
    776 
    777 /**
    778   Display a character
    779 
    780   @param [in] SocketFD      The socket's file descriptor to add to the list.
    781   @param [in] pPort         The WSDT_PORT structure address
    782   @param [in] Character     Character to display
    783   @param [in] pReplacement  Replacement character string
    784 
    785   @retval EFI_SUCCESS       The request was successfully processed
    786 
    787 **/
    788 EFI_STATUS
    789 HttpSendCharacter (
    790   IN int SocketFD,
    791   IN WSDT_PORT * pPort,
    792   IN CHAR8 Character,
    793   IN CHAR8 * pReplacement
    794   )
    795 {
    796   EFI_STATUS Status;
    797 
    798   //
    799   //  Determine if this is a printable character
    800   //
    801   if (( 0x20 <= Character ) && ( 0x7f > Character )) {
    802     if ( '<' == Character ) {
    803       //
    804       //  Replace with HTML equivalent
    805       //
    806       Status = HttpSendAnsiString ( SocketFD,
    807                                     pPort,
    808                                     "&lt;" );
    809     }
    810     else if ( '>' == Character ) {
    811       //
    812       //  Replace with HTML equivalent
    813       //
    814       Status = HttpSendAnsiString ( SocketFD,
    815                                     pPort,
    816                                     "&gt;" );
    817     }
    818     else if ( '&' == Character ) {
    819       //
    820       //  Replace with HTML equivalent
    821       //
    822       Status = HttpSendAnsiString ( SocketFD,
    823                                     pPort,
    824                                     "&amp;" );
    825     }
    826     else if ( '\"' == Character ) {
    827       //
    828       //  Replace with HTML equivalent
    829       //
    830       Status = HttpSendAnsiString ( SocketFD,
    831                                     pPort,
    832                                     "&quot;" );
    833     }
    834     else {
    835       //
    836       //  Display the character
    837       //
    838       Status = HttpSendByte ( SocketFD,
    839                               pPort,
    840                               Character );
    841     }
    842   }
    843   else {
    844     //
    845     //  Not a displayable character
    846     //
    847     Status = HttpSendAnsiString ( SocketFD,
    848                                   pPort,
    849                                   pReplacement );
    850   }
    851 
    852   //
    853   //  Return the operation status
    854   //
    855   return Status;
    856 }
    857 
    858 
    859 /**
    860   Send a buffer dump
    861 
    862   @param [in] SocketFD      The socket's file descriptor to add to the list.
    863   @param [in] pPort         The WSDT_PORT structure address
    864   @param [in] ByteCount     The number of bytes to display
    865   @param [in] pData         Address of the byte array
    866 
    867   @retval EFI_SUCCESS       The request was successfully processed
    868 
    869 **/
    870 EFI_STATUS
    871 HttpSendDump (
    872   IN int SocketFD,
    873   IN WSDT_PORT * pPort,
    874   IN UINTN ByteCount,
    875   IN CONST UINT8 * pData
    876   )
    877 {
    878   INTN BytesToDisplay;
    879   UINT8 Character;
    880   INTN Index;
    881   INTN InitialSpaces;
    882   CONST UINT8 * pDataEnd;
    883   CONST UINT8 * pEnd;
    884   CONST UINT8 * pTemp;
    885   EFI_STATUS Status;
    886 
    887   //
    888   //  Use for/break instead of goto
    889   //
    890   for ( ; ; ) {
    891     //
    892     //  Start the field value
    893     //
    894     Status = HttpSendAnsiString ( SocketFD,
    895                                   pPort,
    896                                   "<code>" );
    897     if ( EFI_ERROR ( Status )) {
    898       break;
    899     }
    900 
    901     //
    902     //  Walk the bytes to be displayed
    903     //
    904     pEnd = &pData[ ByteCount ];
    905     while ( pEnd > pData ) {
    906       //
    907       //  Display the address
    908       //
    909       Status = HttpSendHexBits ( SocketFD,
    910                                  pPort,
    911                                  sizeof ( pData ) * 8,
    912                                  (UINT64)(UINTN)pData );
    913       if ( EFI_ERROR ( Status )) {
    914         break;
    915       }
    916 
    917       //
    918       //  Separate the address and data
    919       //
    920       Status = HttpSendByte ( SocketFD, pPort, ':' );
    921       if ( EFI_ERROR ( Status )) {
    922         break;
    923       }
    924 
    925       //
    926       //  Position the starting data correctly
    927       //
    928       InitialSpaces = (UINTN)pData;
    929       InitialSpaces &= BYTES_ON_A_LINE - 1;
    930       for ( Index = SPACES_ADDRESS_TO_DATA
    931                   + (( 2 + SPACES_BETWEEN_BYTES )
    932                         * InitialSpaces );
    933             0 < Index; Index-- ) {
    934         Status = HttpSendAnsiString ( SocketFD,
    935                                       pPort,
    936                                       "&nbsp;" );
    937         if ( EFI_ERROR ( Status )) {
    938           break;
    939         }
    940       }
    941       if ( EFI_ERROR ( Status )) {
    942         break;
    943       }
    944 
    945       //
    946       //  Display the data
    947       //
    948       BytesToDisplay = pEnd - pData;
    949       if (( BYTES_ON_A_LINE - InitialSpaces ) < BytesToDisplay ) {
    950         BytesToDisplay = BYTES_ON_A_LINE - InitialSpaces;
    951       }
    952       pDataEnd = &pData[ BytesToDisplay ];
    953       pTemp = pData;
    954       while ( pDataEnd > pTemp ) {
    955         Status = HttpSendHexBits ( SocketFD,
    956                                    pPort,
    957                                    8,
    958                                    *pTemp++ );
    959         if ( EFI_ERROR ( Status )) {
    960           break;
    961         }
    962 
    963         //
    964         //  Separate the data bytes
    965         //
    966         for ( Index = SPACES_BETWEEN_BYTES; 0 < Index; Index-- ) {
    967           Status = HttpSendAnsiString ( SocketFD,
    968                                         pPort,
    969                                         "&nbsp;" );
    970           if ( EFI_ERROR ( Status )) {
    971             break;
    972           }
    973         }
    974         if ( EFI_ERROR ( Status )) {
    975           break;
    976         }
    977       }
    978       if ( EFI_ERROR ( Status )) {
    979         break;
    980       }
    981 
    982       //
    983       //  Separate the data from the ASCII display
    984       //
    985       for ( Index = (( 2 + SPACES_BETWEEN_BYTES )
    986                        * ( BYTES_ON_A_LINE - BytesToDisplay - InitialSpaces ))
    987                   - SPACES_BETWEEN_BYTES
    988                   + SPACES_DATA_TO_ASCII
    989                   + InitialSpaces;
    990             0 < Index; Index-- ) {
    991         Status = HttpSendAnsiString ( SocketFD,
    992                                       pPort,
    993                                       "&nbsp;" );
    994         if ( EFI_ERROR ( Status )) {
    995           break;
    996         }
    997       }
    998       if ( EFI_ERROR ( Status )) {
    999         break;
   1000       }
   1001 
   1002       //
   1003       //  Display the ASCII data
   1004       //
   1005       while ( pDataEnd > pData ) {
   1006         Character = *pData++;
   1007         Status = HttpSendCharacter ( SocketFD,
   1008                                      pPort,
   1009                                      Character,
   1010                                      "." );
   1011         if ( EFI_ERROR ( Status )) {
   1012           break;
   1013         }
   1014       }
   1015       if ( EFI_ERROR ( Status )) {
   1016         break;
   1017       }
   1018 
   1019       //
   1020       //  Terminate the line
   1021       //
   1022       Status = HttpSendAnsiString ( SocketFD,
   1023                                     pPort,
   1024                                     "<br/>\r\n" );
   1025       if ( EFI_ERROR ( Status )) {
   1026         break;
   1027       }
   1028     }
   1029 
   1030     //
   1031     //  Terminate the field value and row
   1032     //
   1033     Status = HttpSendAnsiString ( SocketFD,
   1034                                   pPort,
   1035                                   "</code>\r\n" );
   1036     break;
   1037   }
   1038 
   1039   //
   1040   //  Return the operation status
   1041   //
   1042   return Status;
   1043 }
   1044 
   1045 
   1046 /**
   1047   Display a row containing a GUID value
   1048 
   1049   @param [in] SocketFD      The socket's file descriptor to add to the list.
   1050   @param [in] pPort         The WSDT_PORT structure address
   1051   @param [in] pGuid         Address of the GUID to display
   1052 
   1053   @retval EFI_SUCCESS       The request was successfully processed
   1054 
   1055 **/
   1056 EFI_STATUS
   1057 HttpSendGuid (
   1058   IN int SocketFD,
   1059   IN WSDT_PORT * pPort,
   1060   IN CONST EFI_GUID * pGuid
   1061   )
   1062 {
   1063   UINT32 Index;
   1064   EFI_STATUS Status;
   1065 
   1066   DBG_ENTER ( );
   1067 
   1068   //
   1069   //  Use for/break instead of goto
   1070   //
   1071   for ( ; ; ) {
   1072     //
   1073     //  Display the GUID in a form found in the code
   1074     //
   1075     //  E.g. 0xca16005f, 0x11ec, 0x4bdc, { 0x99, 0x97, 0x27, 0x2c, 0xa9, 0xba, 0x15, 0xe5 }
   1076     //
   1077 
   1078     //
   1079     //  Display the first 32 bits
   1080     //
   1081     Status = HttpSendAnsiString ( SocketFD,
   1082                                   pPort,
   1083                                   "0x" );
   1084     if ( EFI_ERROR ( Status )) {
   1085       break;
   1086     }
   1087     Status = HttpSendHexBits ( SocketFD,
   1088                                pPort,
   1089                                32,
   1090                                pGuid->Data1 );
   1091     if ( EFI_ERROR ( Status )) {
   1092       break;
   1093     }
   1094 
   1095     //
   1096     //  Display the second 16 bits
   1097     //
   1098     Status = HttpSendAnsiString ( SocketFD,
   1099                                   pPort,
   1100                                   ", 0x" );
   1101     if ( EFI_ERROR ( Status )) {
   1102       break;
   1103     }
   1104     Status = HttpSendHexBits ( SocketFD,
   1105                                pPort,
   1106                                16,
   1107                                pGuid->Data2 );
   1108     if ( EFI_ERROR ( Status )) {
   1109       break;
   1110     }
   1111 
   1112     //
   1113     //  Display the thrid 16 bits
   1114     //
   1115     Status = HttpSendAnsiString ( SocketFD,
   1116                                   pPort,
   1117                                   ", 0x" );
   1118     if ( EFI_ERROR ( Status )) {
   1119       break;
   1120     }
   1121     Status = HttpSendHexBits ( SocketFD,
   1122                                pPort,
   1123                                16,
   1124                                pGuid->Data3 );
   1125     if ( EFI_ERROR ( Status )) {
   1126       break;
   1127     }
   1128 
   1129     //
   1130     //  Place the last 64 bits in braces
   1131     //
   1132     Status = HttpSendAnsiString ( SocketFD,
   1133                                   pPort,
   1134                                   ", { 0x" );
   1135     if ( EFI_ERROR ( Status )) {
   1136       break;
   1137     }
   1138     for ( Index = 0; 7 >= Index; Index++ ) {
   1139       //
   1140       //  Display the next 8 bits
   1141       //
   1142       Status = HttpSendHexBits ( SocketFD,
   1143                                  pPort,
   1144                                  8,
   1145                                  pGuid->Data4[ Index ]);
   1146       if ( EFI_ERROR ( Status )) {
   1147         break;
   1148       }
   1149 
   1150       //
   1151       //  Separate the bytes
   1152       //
   1153       Status = HttpSendAnsiString ( SocketFD,
   1154                                     pPort,
   1155                                     ( 7 != Index ) ? ", 0x" : " }" );
   1156       if ( EFI_ERROR ( Status )) {
   1157         break;
   1158       }
   1159     }
   1160     break;
   1161   }
   1162 
   1163   //
   1164   //  Return the operation status
   1165   //
   1166   DBG_EXIT_STATUS ( Status );
   1167   return Status;
   1168 }
   1169 
   1170 
   1171 /**
   1172   Output a hex value to the HTML page
   1173 
   1174   @param [in] SocketFD    Socket file descriptor
   1175   @param [in] pPort       The WSDT_PORT structure address
   1176   @param [in] Bits        Number of bits to display
   1177   @param [in] Value       Value to display
   1178 
   1179   @retval EFI_SUCCESS Successfully displayed the address
   1180 **/
   1181 EFI_STATUS
   1182 HttpSendHexBits (
   1183   IN int SocketFD,
   1184   IN WSDT_PORT * pPort,
   1185   IN INT32 Bits,
   1186   IN UINT64 Value
   1187   )
   1188 {
   1189   UINT32 Digit;
   1190   INT32 Shift;
   1191   EFI_STATUS Status;
   1192 
   1193   //
   1194   //  Assume success
   1195   //
   1196   Status = EFI_SUCCESS;
   1197 
   1198   //
   1199   //  Walk the list of divisors
   1200   //
   1201   Shift = (( Bits + 3 ) & ( ~3 )) - 4;
   1202   while ( 0 <= Shift ) {
   1203     //
   1204     //  Determine the next digit
   1205     //
   1206     Digit = (UINT32)(( Value >> Shift ) & 0xf );
   1207     if ( 10 <= Digit ) {
   1208       Digit += 'a' - '0' - 10;
   1209     }
   1210 
   1211     //
   1212     //  Display the digit
   1213     //
   1214     Status = HttpSendByte ( SocketFD, pPort, (UINT8)( '0' + Digit ));
   1215     if ( EFI_ERROR ( Status )) {
   1216       break;
   1217     }
   1218 
   1219     //
   1220     //  Set the next shift
   1221     //
   1222     Shift -= 4;
   1223   }
   1224 
   1225   //
   1226   //  Return the operation status
   1227   //
   1228   return Status;
   1229 }
   1230 
   1231 
   1232 /**
   1233   Output a hex value to the HTML page
   1234 
   1235   @param [in] SocketFD    Socket file descriptor
   1236   @param [in] pPort       The WSDT_PORT structure address
   1237   @param [in] Value       Value to display
   1238 
   1239   @retval EFI_SUCCESS Successfully displayed the address
   1240 **/
   1241 EFI_STATUS
   1242 HttpSendHexValue (
   1243   IN int SocketFD,
   1244   IN WSDT_PORT * pPort,
   1245   IN UINT64 Value
   1246   )
   1247 {
   1248   BOOLEAN bDisplayZeros;
   1249   UINT32 Digit;
   1250   INT32 Shift;
   1251   EFI_STATUS Status;
   1252 
   1253   //
   1254   //  Assume success
   1255   //
   1256   Status = EFI_SUCCESS;
   1257 
   1258   //
   1259   //  Walk the list of divisors
   1260   //
   1261   bDisplayZeros = FALSE;
   1262   Shift = 60;
   1263   do {
   1264     //
   1265     //  Determine the next digit
   1266     //
   1267     Digit = (UINT32)(( Value >> Shift ) & 0xf );
   1268     if ( 10 <= Digit ) {
   1269       Digit += 'a' - '0' - 10;
   1270     }
   1271 
   1272     //
   1273     //  Suppress leading zeros
   1274     //
   1275     if (( 0 != Digit ) || bDisplayZeros || ( 0 == Shift )) {
   1276       bDisplayZeros = TRUE;
   1277 
   1278       //
   1279       //  Display the digit
   1280       //
   1281       Status = HttpSendByte ( SocketFD, pPort, (UINT8)( '0' + Digit ));
   1282       if ( EFI_ERROR ( Status )) {
   1283         break;
   1284       }
   1285     }
   1286 
   1287     //
   1288     //  Set the next shift
   1289     //
   1290     Shift -= 4;
   1291   } while ( 0 <= Shift );
   1292 
   1293   //
   1294   //  Return the operation status
   1295   //
   1296   return Status;
   1297 }
   1298 
   1299 
   1300 /**
   1301   Output an IP6 address value to the HTML page
   1302 
   1303   @param [in] SocketFD          Socket file descriptor
   1304   @param [in] pPort             The WSDT_PORT structure address
   1305   @param [in] Value             Value to display
   1306   @param [in] bFirstValue       TRUE if first value
   1307   @param [in] bLastValue        TRUE if last value
   1308   @param [in] bZeroSuppression  TRUE while zeros are being suppressed
   1309   @param [in] pbZeroSuppression Address to receive TRUE when zero suppression
   1310                                 has started, use NULL if next colon value not
   1311                                 needed.
   1312 
   1313   @retval EFI_SUCCESS Successfully displayed the address
   1314 **/
   1315 EFI_STATUS
   1316 HttpSendIp6Value (
   1317   IN int SocketFD,
   1318   IN WSDT_PORT * pPort,
   1319   IN UINT16 Value,
   1320   IN BOOLEAN bFirstValue,
   1321   IN BOOLEAN bLastValue,
   1322   IN BOOLEAN bZeroSuppression,
   1323   IN BOOLEAN * pbZeroSuppression
   1324   )
   1325 {
   1326   BOOLEAN bZeroSuppressionStarting;
   1327   UINT32 Digit;
   1328   EFI_STATUS Status;
   1329 
   1330   //
   1331   //  Use break instead of goto
   1332   //
   1333   bZeroSuppressionStarting = FALSE;
   1334   Status = EFI_SUCCESS;
   1335   for ( ; ; ) {
   1336     //
   1337     //  Display the leading colon if necessary
   1338     //
   1339     if ( bZeroSuppression && ( bLastValue || ( 0 != Value ))) {
   1340       Status = HttpSendByte ( SocketFD, pPort, ':' );
   1341       if ( EFI_ERROR ( Status )) {
   1342         break;
   1343       }
   1344     }
   1345 
   1346     //
   1347     //  Skip over a series of zero values
   1348     //
   1349     bZeroSuppressionStarting = (BOOLEAN)( 0 == Value );
   1350     if ( !bZeroSuppressionStarting ) {
   1351       //
   1352       //  Display the value
   1353       //
   1354       Digit = ( Value >> 4 ) & 0xf;
   1355       Status = HttpSendHexValue ( SocketFD,
   1356                                   pPort,
   1357                                   Digit );
   1358       if ( EFI_ERROR ( Status )) {
   1359         break;
   1360       }
   1361       Digit = Value & 0xf;
   1362       Status = HttpSendHexValue ( SocketFD,
   1363                                   pPort,
   1364                                   Digit );
   1365       if ( EFI_ERROR ( Status )) {
   1366         break;
   1367       }
   1368       Digit = ( Value >> 12 ) & 0xf;
   1369       Status = HttpSendHexValue ( SocketFD,
   1370                                   pPort,
   1371                                   Digit );
   1372       if ( EFI_ERROR ( Status )) {
   1373         break;
   1374       }
   1375       Digit = ( Value >> 8 ) & 0xf;
   1376       Status = HttpSendHexValue ( SocketFD,
   1377                                   pPort,
   1378                                   Digit );
   1379       if ( EFI_ERROR ( Status )) {
   1380         break;
   1381       }
   1382     }
   1383 
   1384     //
   1385     //  Display the trailing colon if necessary
   1386     //
   1387     if (( !bLastValue ) && ( bFirstValue || ( 0 != Value ))) {
   1388       Status = HttpSendByte ( SocketFD, pPort, ':' );
   1389     }
   1390     break;
   1391   }
   1392 
   1393   //
   1394   //  Return the next colon display
   1395   if ( NULL != pbZeroSuppression ) {
   1396     *pbZeroSuppression = bZeroSuppressionStarting;
   1397   }
   1398 
   1399   //
   1400   //  Return the operation status
   1401   //
   1402   return Status;
   1403 }
   1404 
   1405 
   1406 /**
   1407   Output an IP address to the HTML page
   1408 
   1409   @param [in] SocketFD    Socket file descriptor
   1410   @param [in] pPort       The WSDT_PORT structure address
   1411   @param [in] pAddress    Address of the socket address
   1412 
   1413   @retval EFI_SUCCESS Successfully displayed the address
   1414 **/
   1415 EFI_STATUS
   1416 HttpSendIpAddress (
   1417   IN int SocketFD,
   1418   IN WSDT_PORT * pPort,
   1419   IN struct sockaddr_in6 * pAddress
   1420   )
   1421 {
   1422   BOOLEAN bZeroSuppression;
   1423   UINT32 Index;
   1424   struct sockaddr_in * pIpv4;
   1425   struct sockaddr_in6 * pIpv6;
   1426   UINT16 PortNumber;
   1427   EFI_STATUS Status;
   1428 
   1429   //
   1430   //  Use break instead of goto
   1431   //
   1432   for ( ; ; ) {
   1433     //
   1434     //  Determine the type of address
   1435     //
   1436     if ( AF_INET6 == pAddress->sin6_family ) {
   1437       pIpv6 = pAddress;
   1438 
   1439       //
   1440       //  Display the address in RFC2732 format
   1441       //
   1442       bZeroSuppression = FALSE;
   1443       Status = HttpSendByte ( SocketFD, pPort, '[' );
   1444       if ( EFI_ERROR ( Status )) {
   1445         break;
   1446       }
   1447       for ( Index = 0; 8 > Index; Index++ ) {
   1448         Status = HttpSendIp6Value ( SocketFD,
   1449                                     pPort,
   1450                                     pIpv6->sin6_addr.__u6_addr.__u6_addr16[ Index ],
   1451                                     (BOOLEAN)( 0 == Index ),
   1452                                     (BOOLEAN)( 7 == Index ),
   1453                                     bZeroSuppression,
   1454                                     &bZeroSuppression );
   1455         if ( EFI_ERROR ( Status )) {
   1456           break;
   1457         }
   1458       }
   1459       if ( EFI_ERROR ( Status )) {
   1460         break;
   1461       }
   1462 
   1463       //
   1464       //  Separate the port number
   1465       //
   1466       Status = HttpSendByte ( SocketFD, pPort, ']' );
   1467 
   1468       //
   1469       //  Get the port number
   1470       //
   1471       PortNumber = pIpv6->sin6_port;
   1472     }
   1473     else {
   1474       //
   1475       //  Output the IPv4 address
   1476       //
   1477       pIpv4 = (struct sockaddr_in *)pAddress;
   1478       Status = HttpSendValue ( SocketFD, pPort, (UINT8)pIpv4->sin_addr.s_addr );
   1479       if ( EFI_ERROR ( Status )) {
   1480         break;
   1481       }
   1482       Status = HttpSendByte ( SocketFD, pPort, '.' );
   1483       if ( EFI_ERROR ( Status )) {
   1484         break;
   1485       }
   1486       Status = HttpSendValue ( SocketFD, pPort, (UINT8)( pIpv4->sin_addr.s_addr >> 8 ));
   1487       if ( EFI_ERROR ( Status )) {
   1488         break;
   1489       }
   1490       Status = HttpSendByte ( SocketFD, pPort, '.' );
   1491       if ( EFI_ERROR ( Status )) {
   1492         break;
   1493       }
   1494       Status = HttpSendValue ( SocketFD, pPort, (UINT8)( pIpv4->sin_addr.s_addr >> 16 ));
   1495       if ( EFI_ERROR ( Status )) {
   1496         break;
   1497       }
   1498       Status = HttpSendByte ( SocketFD, pPort, '.' );
   1499       if ( EFI_ERROR ( Status )) {
   1500         break;
   1501       }
   1502       Status = HttpSendValue ( SocketFD, pPort, (UINT8)( pIpv4->sin_addr.s_addr >> 24 ));
   1503 
   1504       //
   1505       //  Get the port number
   1506       //
   1507       PortNumber = pIpv4->sin_port;
   1508     }
   1509     if ( EFI_ERROR ( Status )) {
   1510       break;
   1511     }
   1512 
   1513     //
   1514     //  Display the port number
   1515     //
   1516     Status = HttpSendByte ( SocketFD, pPort, ':' );
   1517     if ( EFI_ERROR ( Status )) {
   1518       break;
   1519     }
   1520     Status = HttpSendValue ( SocketFD, pPort, htons ( PortNumber ));
   1521     break;
   1522   }
   1523 
   1524   //
   1525   //  Return the operation status
   1526   //
   1527   return Status;
   1528 }
   1529 
   1530 
   1531 /**
   1532   Send a Unicode string
   1533 
   1534   @param [in] SocketFD      The socket's file descriptor to add to the list.
   1535   @param [in] pPort         The WSDT_PORT structure address
   1536   @param [in] pString       A zero terminated Unicode string
   1537 
   1538   @retval EFI_SUCCESS       The request was successfully processed
   1539 
   1540 **/
   1541 EFI_STATUS
   1542 HttpSendUnicodeString (
   1543   IN int SocketFD,
   1544   IN WSDT_PORT * pPort,
   1545   IN CONST UINT16 * pString
   1546   )
   1547 {
   1548   UINT8 Data;
   1549   UINT16 Character;
   1550   EFI_STATUS Status;
   1551 
   1552   //
   1553   //  Assume success
   1554   //
   1555   Status = EFI_SUCCESS;
   1556 
   1557   //
   1558   //  Walk the characters in he string
   1559   //
   1560   while ( 0 != ( Character = *pString++ )) {
   1561     //
   1562     //  Convert the character to UTF-8
   1563     //
   1564     if ( 0 != ( Character & 0xf800 )) {
   1565       //
   1566       //  Send the upper 4 bits
   1567       //
   1568       Data = (UINT8)(( Character >> 12 ) & 0xf );
   1569       Data |= 0xe0;
   1570       Status = HttpSendByte ( SocketFD,
   1571                               pPort,
   1572                               Data );
   1573       if ( EFI_ERROR ( Status )) {
   1574         break;
   1575       }
   1576 
   1577       //
   1578       //  Send the next 6 bits
   1579       //
   1580       Data = (UINT8)(( Character >> 6 ) & 0x3f );
   1581       Data |= 0x80;
   1582       Status = HttpSendByte ( SocketFD,
   1583                               pPort,
   1584                               Data );
   1585       if ( EFI_ERROR ( Status )) {
   1586         break;
   1587       }
   1588 
   1589       //
   1590       //  Send the last 6 bits
   1591       //
   1592       Data = (UINT8)( Character & 0x3f );
   1593       Data |= 0x80;
   1594     }
   1595     else if ( 0 != ( Character & 0x0780 )) {
   1596       //
   1597       //  Send the upper 5 bits
   1598       //
   1599       Data = (UINT8)(( Character >> 6 ) & 0x1f );
   1600       Data |= 0xc0;
   1601       Status = HttpSendByte ( SocketFD,
   1602                               pPort,
   1603                               Data );
   1604       if ( EFI_ERROR ( Status )) {
   1605         break;
   1606       }
   1607 
   1608       //
   1609       //  Send the last 6 bits
   1610       //
   1611       Data = (UINT8)( Character & 0x3f );
   1612       Data |= 0x80;
   1613     }
   1614     else {
   1615       Data = (UINT8)( Character & 0x7f );
   1616     }
   1617 
   1618     //
   1619     //  Send the last data byte
   1620     //
   1621     Status = HttpSendByte ( SocketFD,
   1622                             pPort,
   1623                             Data );
   1624     if ( EFI_ERROR ( Status )) {
   1625       break;
   1626     }
   1627   }
   1628 
   1629   //
   1630   //  Return the operation status
   1631   //
   1632   return Status;
   1633 }
   1634 
   1635 
   1636 /**
   1637   Output a value to the HTML page
   1638 
   1639   @param [in] SocketFD    Socket file descriptor
   1640   @param [in] pPort       The WSDT_PORT structure address
   1641   @param [in] Value       Value to display
   1642 
   1643   @retval EFI_SUCCESS Successfully displayed the address
   1644 **/
   1645 EFI_STATUS
   1646 HttpSendValue (
   1647   IN int SocketFD,
   1648   IN WSDT_PORT * pPort,
   1649   IN UINT64 Value
   1650   )
   1651 {
   1652   BOOLEAN bDisplayZeros;
   1653   UINT64 Digit;
   1654   CONST UINT64 * pEnd;
   1655   CONST UINT64 * pDivisor;
   1656   CONST UINT64 pDivisors[ ] = {
   1657      10000000000000000000ULL,
   1658       1000000000000000000ULL,
   1659        100000000000000000ULL,
   1660         10000000000000000ULL,
   1661          1000000000000000ULL,
   1662           100000000000000ULL,
   1663            10000000000000ULL,
   1664             1000000000000ULL,
   1665              100000000000ULL,
   1666               10000000000ULL,
   1667                1000000000ULL,
   1668                 100000000ULL,
   1669                  10000000ULL,
   1670                   1000000ULL,
   1671                    100000ULL,
   1672                     10000ULL,
   1673                      1000ULL,
   1674                       100ULL,
   1675                        10ULL
   1676   };
   1677   EFI_STATUS Status;
   1678   UINT64 Temp;
   1679 
   1680   //
   1681   //  Assume success
   1682   //
   1683   Status = EFI_SUCCESS;
   1684 
   1685   //
   1686   //  Walk the list of divisors
   1687   //
   1688   bDisplayZeros = FALSE;
   1689   pDivisor = &pDivisors[0];
   1690   pEnd = &pDivisor[ sizeof ( pDivisors ) / sizeof ( pDivisors[0])];
   1691   while ( pEnd > pDivisor ) {
   1692     //
   1693     //  Determine the next digit
   1694     //
   1695     Digit = Value / *pDivisor;
   1696 
   1697     //
   1698     //  Suppress leading zeros
   1699     //
   1700     if (( 0 != Digit ) || bDisplayZeros ) {
   1701       bDisplayZeros = TRUE;
   1702 
   1703       //
   1704       //  Display the digit
   1705       //
   1706       Status = HttpSendByte ( SocketFD, pPort, (UINT8)( '0' + Digit ));
   1707       if ( EFI_ERROR ( Status )) {
   1708         break;
   1709       }
   1710 
   1711       //
   1712       //  Determine the remainder
   1713       //
   1714       Temp = *pDivisor * Digit;
   1715       Value -= Temp;
   1716     }
   1717 
   1718     //
   1719     //  Set the next divisor
   1720     //
   1721     pDivisor += 1;
   1722   }
   1723 
   1724   //
   1725   //  Display the final digit
   1726   //
   1727   if ( !EFI_ERROR ( Status )) {
   1728     Status = HttpSendByte ( SocketFD, pPort, (UINT8)( '0' + Value ));
   1729   }
   1730 
   1731   //
   1732   //  Return the operation status
   1733   //
   1734   return Status;
   1735 }
   1736