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
HttpCharGet(IN UINT8 * pData,IN UINT8 ** ppData)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
HttpFlush(IN int SocketFD,IN WSDT_PORT * pPort)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
HttpLowerCase(IN INTN Character)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
HttpMatch(IN UINT16 * pString,IN UINT8 * pData,IN BOOLEAN bIgnoreCase)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
HttpPageHeader(IN int SocketFD,IN WSDT_PORT * pPort,IN CONST CHAR16 * pTitle)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
HttpPageNotFound(IN int SocketFD,IN WSDT_PORT * pPort,IN BOOLEAN * pbDone)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
HttpPageTrailer(IN int SocketFD,IN WSDT_PORT * pPort,IN BOOLEAN * pbDone)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 *
HttpReplaceSpace(IN UINT8 * pData,IN UINT8 * pEnd)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
HttpRequest(IN int SocketFD,IN WSDT_PORT * pPort,OUT BOOLEAN * pbDone)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
HttpSend(IN int SocketFD,IN WSDT_PORT * pPort,IN size_t LengthInBytes,IN CONST UINT8 * pBuffer)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
HttpSendAnsiString(IN int SocketFD,IN WSDT_PORT * pPort,IN CONST char * pString)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
HttpSendByte(IN int SocketFD,IN WSDT_PORT * pPort,IN UINT8 Data)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
HttpSendCharacter(IN int SocketFD,IN WSDT_PORT * pPort,IN CHAR8 Character,IN CHAR8 * pReplacement)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
HttpSendDump(IN int SocketFD,IN WSDT_PORT * pPort,IN UINTN ByteCount,IN CONST UINT8 * pData)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
HttpSendGuid(IN int SocketFD,IN WSDT_PORT * pPort,IN CONST EFI_GUID * pGuid)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
HttpSendHexBits(IN int SocketFD,IN WSDT_PORT * pPort,IN INT32 Bits,IN UINT64 Value)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
HttpSendHexValue(IN int SocketFD,IN WSDT_PORT * pPort,IN UINT64 Value)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
HttpSendIp6Value(IN int SocketFD,IN WSDT_PORT * pPort,IN UINT16 Value,IN BOOLEAN bFirstValue,IN BOOLEAN bLastValue,IN BOOLEAN bZeroSuppression,IN BOOLEAN * pbZeroSuppression)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
HttpSendIpAddress(IN int SocketFD,IN WSDT_PORT * pPort,IN struct sockaddr_in6 * pAddress)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
HttpSendUnicodeString(IN int SocketFD,IN WSDT_PORT * pPort,IN CONST UINT16 * pString)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
HttpSendValue(IN int SocketFD,IN WSDT_PORT * pPort,IN UINT64 Value)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