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