Merged socket development branch:
[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_in6 LocalAddress;
405 struct sockaddr_in6 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 LengthInBytes = sizeof ( LocalAddress );
417 RetVal = getpeername ( SocketFD, (struct sockaddr *)&RemoteAddress, &LengthInBytes );
418 if ( 0 == RetVal ) {
419 //
420 // Seperate the body from the trailer
421 //
422 Status = HttpSendAnsiString ( SocketFD, pPort, " <hr>\r\n<code>" );
423 if ( EFI_ERROR ( Status )) {
424 break;
425 }
426
427 //
428 // Display the system addresses and the page transfer direction
429 //
430 Status = HttpSendIpAddress ( SocketFD, pPort, &LocalAddress );
431 if ( EFI_ERROR ( Status )) {
432 break;
433 }
434 Status = HttpSendAnsiString ( SocketFD, pPort, " --> " );
435 if ( EFI_ERROR ( Status )) {
436 break;
437 }
438 Status = HttpSendIpAddress ( SocketFD, pPort, &RemoteAddress );
439 if ( EFI_ERROR ( Status )) {
440 break;
441 }
442 Status = HttpSendAnsiString ( SocketFD, pPort, "</code>\r\n" );
443 if ( EFI_ERROR ( Status )) {
444 break;
445 }
446 }
447 }
448
449 //
450 // Terminate the page
451 //
452 Status = HttpSendAnsiString ( SocketFD, pPort, " </body>\r\n" );
453 if ( EFI_ERROR ( Status )) {
454 break;
455 }
456 Status = HttpSendAnsiString ( SocketFD, pPort, " </html>\r\n" );
457 if ( EFI_ERROR ( Status )) {
458 break;
459 }
460
461 //
462 // Send the page trailer
463 //
464 Status = HttpFlush ( SocketFD, pPort );
465 if ( EFI_ERROR ( Status )) {
466 break;
467 }
468
469 //
470 // Mark the page as complete
471 //
472 *pbDone = TRUE;
473 break;
474 }
475
476 //
477 // Return the operation status
478 //
479 DBG_EXIT_STATUS ( Status );
480 return Status;
481 }
482
483
484 /**
485 Replace a space with a zero
486
487 @param [in] pData The request buffer address
488 @param [in] pEnd End of buffer address
489
490 @return The next character location
491
492 **/
493 UINT8 *
494 HttpReplaceSpace (
495 IN UINT8 * pData,
496 IN UINT8 * pEnd
497 )
498 {
499 INTN Character;
500 UINT8 * pSpace;
501
502 pSpace = pData;
503 while ( pEnd > pData ) {
504 //
505 // Get the character from the request
506 //
507 Character = HttpCharGet ( pData, &pData );
508 if ( ' ' == Character ) {
509 break;
510 }
511 pSpace = pData;
512 }
513
514 //
515 // Replace the space character with zero
516 //
517 ZeroMem ( pSpace, pData - pSpace );
518
519 //
520 // Return the next character location
521 //
522 return pData;
523 }
524
525
526 /**
527 Process an HTTP request
528
529 @param [in] SocketFD The socket's file descriptor to add to the list.
530 @param [in] pPort The WSDT_PORT structure address
531 @param [out] pbDone Address to receive the request completion status
532
533 @retval EFI_SUCCESS The request was successfully processed
534
535 **/
536 EFI_STATUS
537 HttpRequest (
538 IN int SocketFD,
539 IN WSDT_PORT * pPort,
540 OUT BOOLEAN * pbDone
541 )
542 {
543 UINT8 * pData;
544 UINT8 * pEnd;
545 CONST DT_PAGE * pPage;
546 CONST DT_PAGE * pPageEnd;
547 UINT8 * pVerb;
548 UINT8 * pVersion;
549 UINT8 * pWebPage;
550 EFI_STATUS Status;
551
552 DBG_ENTER ( );
553
554 //
555 // Assume the request is not finished
556 //
557 *pbDone = FALSE;
558 Status = EFI_SUCCESS;
559 for ( ; ; ) {
560
561 //
562 // Attempt to parse the command
563 //
564 pData = &pPort->Request[0];
565 pEnd = &pData[ pPort->RequestLength ];
566 pVerb = pData;
567 pWebPage = HttpReplaceSpace ( pVerb, pEnd );
568 if ( pEnd <= pWebPage ) {
569 break;
570 }
571 pVersion = HttpReplaceSpace ( pWebPage, pEnd );
572 if ( pEnd <= pVersion ) {
573 break;
574 }
575
576 //
577 // Validate the request
578 //
579 if ( 0 != HttpMatch ( L"GET", pVerb, TRUE )) {
580 //
581 // Invalid request type
582 //
583 DEBUG (( DEBUG_REQUEST,
584 "HTTP: Invalid verb\r\n" ));
585 Status = EFI_NOT_FOUND;
586 break;
587 }
588
589 //
590 // Walk the page table
591 //
592 pPage = &mPageList[0];
593 pPageEnd = &pPage[ mPageCount ];
594 while ( pPageEnd > pPage ) {
595 //
596 // Determine if the page was located
597 //
598 if ( 0 == HttpMatch ( pPage->pPageName, pWebPage, FALSE )) {
599 break;
600 }
601
602 //
603 // Set the next page
604 //
605 pPage += 1;
606 }
607 if ( pPageEnd <= pPage ) {
608 //
609 // The page was not found
610 //
611 DEBUG (( DEBUG_REQUEST,
612 "HTTP: Page not found in page table\r\n" ));
613 Status = EFI_NOT_FOUND;
614 break;
615 }
616
617 //
618 // Respond with the page contents
619 //
620 Status = pPage->pfnResponse ( SocketFD, pPort, pbDone );
621 break;
622 }
623
624 //
625 // Return page not found if necessary
626 //
627 if ( EFI_NOT_FOUND == Status ) {
628 Status = HttpPageNotFound ( SocketFD, pPort, pbDone );
629 }
630
631 //
632 // Return the operation status
633 //
634 DBG_EXIT_STATUS ( Status );
635 return Status;
636 }
637
638
639 /**
640 Buffer data for sending
641
642 @param [in] SocketFD The socket's file descriptor to add to the list.
643 @param [in] pPort The WSDT_PORT structure address
644 @param [in] LengthInBytes Length of valid data in the buffer
645 @param [in] pBuffer Buffer of data to send
646
647 @retval EFI_SUCCESS The request was successfully processed
648
649 **/
650 EFI_STATUS
651 HttpSend (
652 IN int SocketFD,
653 IN WSDT_PORT * pPort,
654 IN size_t LengthInBytes,
655 IN CONST UINT8 * pBuffer
656 )
657 {
658 size_t DataBytes;
659 size_t MaxBytes;
660 EFI_STATUS Status;
661
662 //
663 // Assume success
664 //
665 Status = EFI_SUCCESS;
666 do {
667 //
668 // Determine how much data fits into the buffer
669 //
670 MaxBytes = sizeof ( pPort->TxBuffer );
671 DataBytes = MaxBytes - pPort->TxBytes;
672 if ( DataBytes > LengthInBytes ) {
673 DataBytes = LengthInBytes;
674 }
675
676 //
677 // Copy the data into the buffer
678 //
679 CopyMem ( &pPort->TxBuffer[ pPort->TxBytes ],
680 pBuffer,
681 DataBytes );
682
683 //
684 // Account for the data copied
685 //
686 pPort->TxBytes += DataBytes;
687 LengthInBytes -= DataBytes;
688
689 //
690 // Transmit the buffer if it is full
691 //
692 if ( MaxBytes <= pPort->TxBytes ) {
693 Status = HttpFlush ( SocketFD, pPort );
694 }
695 } while (( EFI_SUCCESS == Status ) && ( 0 < LengthInBytes ));
696
697 //
698 // Return the operation status
699 //
700 return Status;
701 }
702
703
704 /**
705 Send an ANSI string
706
707 @param [in] SocketFD The socket's file descriptor to add to the list.
708 @param [in] pPort The WSDT_PORT structure address
709 @param [in] pString A zero terminated Unicode string
710
711 @retval EFI_SUCCESS The request was successfully processed
712
713 **/
714 EFI_STATUS
715 HttpSendAnsiString (
716 IN int SocketFD,
717 IN WSDT_PORT * pPort,
718 IN CONST char * pString
719 )
720 {
721 CONST char * pData;
722 EFI_STATUS Status;
723
724 //
725 // Assume success
726 //
727 Status = EFI_SUCCESS;
728
729 //
730 // Walk the characters in he string
731 //
732 pData = pString;
733 while ( 0 != *pData ) {
734 pData += 1;
735 }
736
737 //
738 // Send the string
739 //
740 Status = HttpSend ( SocketFD,
741 pPort,
742 pData - pString,
743 (CONST UINT8 *)pString );
744
745 //
746 // Return the operation status
747 //
748 return Status;
749 }
750
751
752 /**
753 Buffer a single byte
754
755 @param [in] SocketFD The socket's file descriptor to add to the list.
756 @param [in] pPort The WSDT_PORT structure address
757 @param [in] Data The data byte to send
758
759 @retval EFI_SUCCESS The request was successfully processed
760
761 **/
762 EFI_STATUS
763 HttpSendByte (
764 IN int SocketFD,
765 IN WSDT_PORT * pPort,
766 IN UINT8 Data
767 )
768 {
769 EFI_STATUS Status;
770
771 //
772 // Send the data byte
773 //
774 Status = HttpSend ( SocketFD,
775 pPort,
776 1,
777 &Data );
778
779 //
780 // Return the operation status
781 //
782 return Status;
783 }
784
785
786 /**
787 Display a character
788
789 @param [in] SocketFD The socket's file descriptor to add to the list.
790 @param [in] pPort The WSDT_PORT structure address
791 @param [in] Character Character to display
792 @param [in] pReplacement Replacement character string
793
794 @retval EFI_SUCCESS The request was successfully processed
795
796 **/
797 EFI_STATUS
798 HttpSendCharacter (
799 IN int SocketFD,
800 IN WSDT_PORT * pPort,
801 IN CHAR8 Character,
802 IN CHAR8 * pReplacement
803 )
804 {
805 EFI_STATUS Status;
806
807 //
808 // Determine if this is a printable character
809 //
810 if (( 0x20 <= Character ) && ( 0x7f > Character )) {
811 if ( '<' == Character ) {
812 //
813 // Replace with HTML equivalent
814 //
815 Status = HttpSendAnsiString ( SocketFD,
816 pPort,
817 "&lt;" );
818 }
819 else if ( '>' == Character ) {
820 //
821 // Replace with HTML equivalent
822 //
823 Status = HttpSendAnsiString ( SocketFD,
824 pPort,
825 "&gt;" );
826 }
827 else if ( '&' == Character ) {
828 //
829 // Replace with HTML equivalent
830 //
831 Status = HttpSendAnsiString ( SocketFD,
832 pPort,
833 "&amp;" );
834 }
835 else if ( '\"' == Character ) {
836 //
837 // Replace with HTML equivalent
838 //
839 Status = HttpSendAnsiString ( SocketFD,
840 pPort,
841 "&quot;" );
842 }
843 else {
844 //
845 // Display the character
846 //
847 Status = HttpSendByte ( SocketFD,
848 pPort,
849 Character );
850 }
851 }
852 else {
853 //
854 // Not a displayable character
855 //
856 Status = HttpSendAnsiString ( SocketFD,
857 pPort,
858 pReplacement );
859 }
860
861 //
862 // Return the operation status
863 //
864 return Status;
865 }
866
867
868 /**
869 Send a buffer dump
870
871 @param [in] SocketFD The socket's file descriptor to add to the list.
872 @param [in] pPort The WSDT_PORT structure address
873 @param [in] ByteCount The number of bytes to display
874 @param [in] pData Address of the byte array
875
876 @retval EFI_SUCCESS The request was successfully processed
877
878 **/
879 EFI_STATUS
880 HttpSendDump (
881 IN int SocketFD,
882 IN WSDT_PORT * pPort,
883 IN UINTN ByteCount,
884 IN CONST UINT8 * pData
885 )
886 {
887 INTN BytesToDisplay;
888 UINT8 Character;
889 INTN Index;
890 INTN InitialSpaces;
891 CONST UINT8 * pDataEnd;
892 CONST UINT8 * pEnd;
893 CONST UINT8 * pTemp;
894 EFI_STATUS Status;
895
896 //
897 // Use for/break instead of goto
898 //
899 for ( ; ; ) {
900 //
901 // Start the field value
902 //
903 Status = HttpSendAnsiString ( SocketFD,
904 pPort,
905 "<code>" );
906 if ( EFI_ERROR ( Status )) {
907 break;
908 }
909
910 //
911 // Walk the bytes to be displayed
912 //
913 pEnd = &pData[ ByteCount ];
914 while ( pEnd > pData ) {
915 //
916 // Display the address
917 //
918 Status = HttpSendHexBits ( SocketFD,
919 pPort,
920 sizeof ( pData ) * 8,
921 (UINT64)pData );
922 if ( EFI_ERROR ( Status )) {
923 break;
924 }
925
926 //
927 // Separate the address and data
928 //
929 Status = HttpSendByte ( SocketFD, pPort, ':' );
930 if ( EFI_ERROR ( Status )) {
931 break;
932 }
933
934 //
935 // Position the starting data correctly
936 //
937 InitialSpaces = (UINTN)pData;
938 InitialSpaces &= BYTES_ON_A_LINE - 1;
939 for ( Index = SPACES_ADDRESS_TO_DATA
940 + (( 2 + SPACES_BETWEEN_BYTES )
941 * InitialSpaces );
942 0 < Index; Index-- ) {
943 Status = HttpSendAnsiString ( SocketFD,
944 pPort,
945 "&nbsp;" );
946 if ( EFI_ERROR ( Status )) {
947 break;
948 }
949 }
950 if ( EFI_ERROR ( Status )) {
951 break;
952 }
953
954 //
955 // Display the data
956 //
957 BytesToDisplay = pEnd - pData;
958 if (( BYTES_ON_A_LINE - InitialSpaces ) < BytesToDisplay ) {
959 BytesToDisplay = BYTES_ON_A_LINE - InitialSpaces;
960 }
961 pDataEnd = &pData[ BytesToDisplay ];
962 pTemp = pData;
963 while ( pDataEnd > pTemp ) {
964 Status = HttpSendHexBits ( SocketFD,
965 pPort,
966 8,
967 *pTemp++ );
968 if ( EFI_ERROR ( Status )) {
969 break;
970 }
971
972 //
973 // Separate the data bytes
974 //
975 for ( Index = SPACES_BETWEEN_BYTES; 0 < Index; Index-- ) {
976 Status = HttpSendAnsiString ( SocketFD,
977 pPort,
978 "&nbsp;" );
979 if ( EFI_ERROR ( Status )) {
980 break;
981 }
982 }
983 if ( EFI_ERROR ( Status )) {
984 break;
985 }
986 }
987 if ( EFI_ERROR ( Status )) {
988 break;
989 }
990
991 //
992 // Separate the data from the ASCII display
993 //
994 for ( Index = (( 2 + SPACES_BETWEEN_BYTES )
995 * ( BYTES_ON_A_LINE - BytesToDisplay - InitialSpaces ))
996 - SPACES_BETWEEN_BYTES
997 + SPACES_DATA_TO_ASCII
998 + InitialSpaces;
999 0 < Index; Index-- ) {
1000 Status = HttpSendAnsiString ( SocketFD,
1001 pPort,
1002 "&nbsp;" );
1003 if ( EFI_ERROR ( Status )) {
1004 break;
1005 }
1006 }
1007 if ( EFI_ERROR ( Status )) {
1008 break;
1009 }
1010
1011 //
1012 // Display the ASCII data
1013 //
1014 while ( pDataEnd > pData ) {
1015 Character = *pData++;
1016 Status = HttpSendCharacter ( SocketFD,
1017 pPort,
1018 Character,
1019 "." );
1020 if ( EFI_ERROR ( Status )) {
1021 break;
1022 }
1023 }
1024 if ( EFI_ERROR ( Status )) {
1025 break;
1026 }
1027
1028 //
1029 // Terminate the line
1030 //
1031 Status = HttpSendAnsiString ( SocketFD,
1032 pPort,
1033 "<br/>\r\n" );
1034 if ( EFI_ERROR ( Status )) {
1035 break;
1036 }
1037 }
1038
1039 //
1040 // Terminate the field value and row
1041 //
1042 Status = HttpSendAnsiString ( SocketFD,
1043 pPort,
1044 "</code>\r\n" );
1045 break;
1046 }
1047
1048 //
1049 // Return the operation status
1050 //
1051 return Status;
1052 }
1053
1054
1055 /**
1056 Display a row containing a GUID value
1057
1058 @param [in] SocketFD The socket's file descriptor to add to the list.
1059 @param [in] pPort The WSDT_PORT structure address
1060 @param [in] pGuid Address of the GUID to display
1061
1062 @retval EFI_SUCCESS The request was successfully processed
1063
1064 **/
1065 EFI_STATUS
1066 HttpSendGuid (
1067 IN int SocketFD,
1068 IN WSDT_PORT * pPort,
1069 IN CONST EFI_GUID * pGuid
1070 )
1071 {
1072 UINT32 Index;
1073 EFI_STATUS Status;
1074
1075 DBG_ENTER ( );
1076
1077 //
1078 // Use for/break instead of goto
1079 //
1080 for ( ; ; ) {
1081 //
1082 // Display the GUID in a form found in the code
1083 //
1084 // E.g. 0xca16005f, 0x11ec, 0x4bdc, { 0x99, 0x97, 0x27, 0x2c, 0xa9, 0xba, 0x15, 0xe5 }
1085 //
1086
1087 //
1088 // Display the first 32 bits
1089 //
1090 Status = HttpSendAnsiString ( SocketFD,
1091 pPort,
1092 "0x" );
1093 if ( EFI_ERROR ( Status )) {
1094 break;
1095 }
1096 Status = HttpSendHexBits ( SocketFD,
1097 pPort,
1098 32,
1099 pGuid->Data1 );
1100 if ( EFI_ERROR ( Status )) {
1101 break;
1102 }
1103
1104 //
1105 // Display the second 16 bits
1106 //
1107 Status = HttpSendAnsiString ( SocketFD,
1108 pPort,
1109 ", 0x" );
1110 if ( EFI_ERROR ( Status )) {
1111 break;
1112 }
1113 Status = HttpSendHexBits ( SocketFD,
1114 pPort,
1115 16,
1116 pGuid->Data2 );
1117 if ( EFI_ERROR ( Status )) {
1118 break;
1119 }
1120
1121 //
1122 // Display the thrid 16 bits
1123 //
1124 Status = HttpSendAnsiString ( SocketFD,
1125 pPort,
1126 ", 0x" );
1127 if ( EFI_ERROR ( Status )) {
1128 break;
1129 }
1130 Status = HttpSendHexBits ( SocketFD,
1131 pPort,
1132 16,
1133 pGuid->Data3 );
1134 if ( EFI_ERROR ( Status )) {
1135 break;
1136 }
1137
1138 //
1139 // Place the last 64 bits in braces
1140 //
1141 Status = HttpSendAnsiString ( SocketFD,
1142 pPort,
1143 ", { 0x" );
1144 if ( EFI_ERROR ( Status )) {
1145 break;
1146 }
1147 for ( Index = 0; 7 >= Index; Index++ ) {
1148 //
1149 // Display the next 8 bits
1150 //
1151 Status = HttpSendHexBits ( SocketFD,
1152 pPort,
1153 8,
1154 pGuid->Data4[ Index ]);
1155 if ( EFI_ERROR ( Status )) {
1156 break;
1157 }
1158
1159 //
1160 // Separate the bytes
1161 //
1162 Status = HttpSendAnsiString ( SocketFD,
1163 pPort,
1164 ( 7 != Index ) ? ", 0x" : " }" );
1165 if ( EFI_ERROR ( Status )) {
1166 break;
1167 }
1168 }
1169 break;
1170 }
1171
1172 //
1173 // Return the operation status
1174 //
1175 DBG_EXIT_STATUS ( Status );
1176 return Status;
1177 }
1178
1179
1180 /**
1181 Output a hex value to the HTML page
1182
1183 @param [in] SocketFD Socket file descriptor
1184 @param [in] pPort The WSDT_PORT structure address
1185 @param [in] Bits Number of bits to display
1186 @param [in] Value Value to display
1187
1188 @retval EFI_SUCCESS Successfully displayed the address
1189 **/
1190 EFI_STATUS
1191 HttpSendHexBits (
1192 IN int SocketFD,
1193 IN WSDT_PORT * pPort,
1194 IN INT32 Bits,
1195 IN UINT64 Value
1196 )
1197 {
1198 UINT32 Digit;
1199 INT32 Shift;
1200 EFI_STATUS Status;
1201
1202 //
1203 // Assume success
1204 //
1205 Status = EFI_SUCCESS;
1206
1207 //
1208 // Walk the list of divisors
1209 //
1210 Shift = (( Bits + 3 ) & ( ~3 )) - 4;
1211 while ( 0 <= Shift ) {
1212 //
1213 // Determine the next digit
1214 //
1215 Digit = (UINT32)(( Value >> Shift ) & 0xf );
1216 if ( 10 <= Digit ) {
1217 Digit += 'a' - '0' - 10;
1218 }
1219
1220 //
1221 // Display the digit
1222 //
1223 Status = HttpSendByte ( SocketFD, pPort, (UINT8)( '0' + Digit ));
1224 if ( EFI_ERROR ( Status )) {
1225 break;
1226 }
1227
1228 //
1229 // Set the next shift
1230 //
1231 Shift -= 4;
1232 }
1233
1234 //
1235 // Return the operation status
1236 //
1237 return Status;
1238 }
1239
1240
1241 /**
1242 Output a hex value to the HTML page
1243
1244 @param [in] SocketFD Socket file descriptor
1245 @param [in] pPort The WSDT_PORT structure address
1246 @param [in] Value Value to display
1247
1248 @retval EFI_SUCCESS Successfully displayed the address
1249 **/
1250 EFI_STATUS
1251 HttpSendHexValue (
1252 IN int SocketFD,
1253 IN WSDT_PORT * pPort,
1254 IN UINT64 Value
1255 )
1256 {
1257 BOOLEAN bDisplayZeros;
1258 UINT32 Digit;
1259 INT32 Shift;
1260 EFI_STATUS Status;
1261
1262 //
1263 // Assume success
1264 //
1265 Status = EFI_SUCCESS;
1266
1267 //
1268 // Walk the list of divisors
1269 //
1270 bDisplayZeros = FALSE;
1271 Shift = 60;
1272 do {
1273 //
1274 // Determine the next digit
1275 //
1276 Digit = (UINT32)(( Value >> Shift ) & 0xf );
1277 if ( 10 <= Digit ) {
1278 Digit += 'a' - '0' - 10;
1279 }
1280
1281 //
1282 // Suppress leading zeros
1283 //
1284 if (( 0 != Digit ) || bDisplayZeros || ( 0 == Shift )) {
1285 bDisplayZeros = TRUE;
1286
1287 //
1288 // Display the digit
1289 //
1290 Status = HttpSendByte ( SocketFD, pPort, (UINT8)( '0' + Digit ));
1291 if ( EFI_ERROR ( Status )) {
1292 break;
1293 }
1294 }
1295
1296 //
1297 // Set the next shift
1298 //
1299 Shift -= 4;
1300 } while ( 0 <= Shift );
1301
1302 //
1303 // Return the operation status
1304 //
1305 return Status;
1306 }
1307
1308
1309 /**
1310 Output an IP6 address value to the HTML page
1311
1312 @param [in] SocketFD Socket file descriptor
1313 @param [in] pPort The WSDT_PORT structure address
1314 @param [in] Value Value to display
1315 @param [in] bFirstValue TRUE if first value
1316 @param [in] bLastValue TRUE if last value
1317 @param [in] bZeroSuppression TRUE while zeros are being suppressed
1318 @param [in] pbZeroSuppression Address to receive TRUE when zero suppression
1319 has started, use NULL if next colon value not
1320 needed.
1321
1322 @retval EFI_SUCCESS Successfully displayed the address
1323 **/
1324 EFI_STATUS
1325 HttpSendIp6Value (
1326 IN int SocketFD,
1327 IN WSDT_PORT * pPort,
1328 IN UINT16 Value,
1329 IN BOOLEAN bFirstValue,
1330 IN BOOLEAN bLastValue,
1331 IN BOOLEAN bZeroSuppression,
1332 IN BOOLEAN * pbZeroSuppression
1333 )
1334 {
1335 BOOLEAN bZeroSuppressionStarting;
1336 UINT32 Digit;
1337 EFI_STATUS Status;
1338
1339 //
1340 // Use break instead of goto
1341 //
1342 bZeroSuppressionStarting = FALSE;
1343 Status = EFI_SUCCESS;
1344 for ( ; ; ) {
1345 //
1346 // Display the leading colon if necessary
1347 //
1348 if ( bZeroSuppression && ( bLastValue || ( 0 != Value ))) {
1349 Status = HttpSendByte ( SocketFD, pPort, ':' );
1350 if ( EFI_ERROR ( Status )) {
1351 break;
1352 }
1353 }
1354
1355 //
1356 // Skip over a series of zero values
1357 //
1358 bZeroSuppressionStarting = (BOOLEAN)( 0 == Value );
1359 if ( !bZeroSuppressionStarting ) {
1360 //
1361 // Display the value
1362 //
1363 Digit = ( Value >> 4 ) & 0xf;
1364 Status = HttpSendHexValue ( SocketFD,
1365 pPort,
1366 Digit );
1367 if ( EFI_ERROR ( Status )) {
1368 break;
1369 }
1370 Digit = Value & 0xf;
1371 Status = HttpSendHexValue ( SocketFD,
1372 pPort,
1373 Digit );
1374 if ( EFI_ERROR ( Status )) {
1375 break;
1376 }
1377 Digit = ( Value >> 12 ) & 0xf;
1378 Status = HttpSendHexValue ( SocketFD,
1379 pPort,
1380 Digit );
1381 if ( EFI_ERROR ( Status )) {
1382 break;
1383 }
1384 Digit = ( Value >> 8 ) & 0xf;
1385 Status = HttpSendHexValue ( SocketFD,
1386 pPort,
1387 Digit );
1388 if ( EFI_ERROR ( Status )) {
1389 break;
1390 }
1391 }
1392
1393 //
1394 // Display the trailing colon if necessary
1395 //
1396 if (( !bLastValue ) && ( bFirstValue || ( 0 != Value ))) {
1397 Status = HttpSendByte ( SocketFD, pPort, ':' );
1398 }
1399 break;
1400 }
1401
1402 //
1403 // Return the next colon display
1404 if ( NULL != pbZeroSuppression ) {
1405 *pbZeroSuppression = bZeroSuppressionStarting;
1406 }
1407
1408 //
1409 // Return the operation status
1410 //
1411 return Status;
1412 }
1413
1414
1415 /**
1416 Output an IP address to the HTML page
1417
1418 @param [in] SocketFD Socket file descriptor
1419 @param [in] pPort The WSDT_PORT structure address
1420 @param [in] pAddress Address of the socket address
1421
1422 @retval EFI_SUCCESS Successfully displayed the address
1423 **/
1424 EFI_STATUS
1425 HttpSendIpAddress (
1426 IN int SocketFD,
1427 IN WSDT_PORT * pPort,
1428 IN struct sockaddr_in6 * pAddress
1429 )
1430 {
1431 BOOLEAN bZeroSuppression;
1432 UINT32 Index;
1433 struct sockaddr_in * pIpv4;
1434 struct sockaddr_in6 * pIpv6;
1435 UINT16 PortNumber;
1436 EFI_STATUS Status;
1437
1438 //
1439 // Use break instead of goto
1440 //
1441 for ( ; ; ) {
1442 //
1443 // Determine the type of address
1444 //
1445 if ( AF_INET6 == pAddress->sin6_family ) {
1446 pIpv6 = pAddress;
1447
1448 //
1449 // Display the address in RFC2732 format
1450 //
1451 bZeroSuppression = FALSE;
1452 Status = HttpSendByte ( SocketFD, pPort, '[' );
1453 if ( EFI_ERROR ( Status )) {
1454 break;
1455 }
1456 for ( Index = 0; 8 > Index; Index++ ) {
1457 Status = HttpSendIp6Value ( SocketFD,
1458 pPort,
1459 pIpv6->sin6_addr.__u6_addr.__u6_addr16[ Index ],
1460 (BOOLEAN)( 0 == Index ),
1461 (BOOLEAN)( 7 == Index ),
1462 bZeroSuppression,
1463 &bZeroSuppression );
1464 if ( EFI_ERROR ( Status )) {
1465 break;
1466 }
1467 }
1468 if ( EFI_ERROR ( Status )) {
1469 break;
1470 }
1471
1472 //
1473 // Separate the port number
1474 //
1475 Status = HttpSendByte ( SocketFD, pPort, ']' );
1476
1477 //
1478 // Get the port number
1479 //
1480 PortNumber = pIpv6->sin6_port;
1481 }
1482 else {
1483 //
1484 // Output the IPv4 address
1485 //
1486 pIpv4 = (struct sockaddr_in *)pAddress;
1487 Status = HttpSendValue ( SocketFD, pPort, (UINT8)pIpv4->sin_addr.s_addr );
1488 if ( EFI_ERROR ( Status )) {
1489 break;
1490 }
1491 Status = HttpSendByte ( SocketFD, pPort, '.' );
1492 if ( EFI_ERROR ( Status )) {
1493 break;
1494 }
1495 Status = HttpSendValue ( SocketFD, pPort, (UINT8)( pIpv4->sin_addr.s_addr >> 8 ));
1496 if ( EFI_ERROR ( Status )) {
1497 break;
1498 }
1499 Status = HttpSendByte ( SocketFD, pPort, '.' );
1500 if ( EFI_ERROR ( Status )) {
1501 break;
1502 }
1503 Status = HttpSendValue ( SocketFD, pPort, (UINT8)( pIpv4->sin_addr.s_addr >> 16 ));
1504 if ( EFI_ERROR ( Status )) {
1505 break;
1506 }
1507 Status = HttpSendByte ( SocketFD, pPort, '.' );
1508 if ( EFI_ERROR ( Status )) {
1509 break;
1510 }
1511 Status = HttpSendValue ( SocketFD, pPort, (UINT8)( pIpv4->sin_addr.s_addr >> 24 ));
1512
1513 //
1514 // Get the port number
1515 //
1516 PortNumber = pIpv4->sin_port;
1517 }
1518 if ( EFI_ERROR ( Status )) {
1519 break;
1520 }
1521
1522 //
1523 // Display the port number
1524 //
1525 Status = HttpSendByte ( SocketFD, pPort, ':' );
1526 if ( EFI_ERROR ( Status )) {
1527 break;
1528 }
1529 Status = HttpSendValue ( SocketFD, pPort, htons ( PortNumber ));
1530 break;
1531 }
1532
1533 //
1534 // Return the operation status
1535 //
1536 return Status;
1537 }
1538
1539
1540 /**
1541 Send a Unicode string
1542
1543 @param [in] SocketFD The socket's file descriptor to add to the list.
1544 @param [in] pPort The WSDT_PORT structure address
1545 @param [in] pString A zero terminated Unicode string
1546
1547 @retval EFI_SUCCESS The request was successfully processed
1548
1549 **/
1550 EFI_STATUS
1551 HttpSendUnicodeString (
1552 IN int SocketFD,
1553 IN WSDT_PORT * pPort,
1554 IN CONST UINT16 * pString
1555 )
1556 {
1557 UINT8 Data;
1558 UINT16 Character;
1559 EFI_STATUS Status;
1560
1561 //
1562 // Assume success
1563 //
1564 Status = EFI_SUCCESS;
1565
1566 //
1567 // Walk the characters in he string
1568 //
1569 while ( 0 != ( Character = *pString++ )) {
1570 //
1571 // Convert the character to UTF-8
1572 //
1573 if ( 0 != ( Character & 0xf800 )) {
1574 //
1575 // Send the upper 4 bits
1576 //
1577 Data = (UINT8)(( Character >> 12 ) & 0xf );
1578 Data |= 0xe0;
1579 Status = HttpSendByte ( SocketFD,
1580 pPort,
1581 Data );
1582 if ( EFI_ERROR ( Status )) {
1583 break;
1584 }
1585
1586 //
1587 // Send the next 6 bits
1588 //
1589 Data = (UINT8)(( Character >> 6 ) & 0x3f );
1590 Data |= 0x80;
1591 Status = HttpSendByte ( SocketFD,
1592 pPort,
1593 Data );
1594 if ( EFI_ERROR ( Status )) {
1595 break;
1596 }
1597
1598 //
1599 // Send the last 6 bits
1600 //
1601 Data = (UINT8)( Character & 0x3f );
1602 Data |= 0x80;
1603 }
1604 else if ( 0 != ( Character & 0x0780 )) {
1605 //
1606 // Send the upper 5 bits
1607 //
1608 Data = (UINT8)(( Character >> 6 ) & 0x1f );
1609 Data |= 0xc0;
1610 Status = HttpSendByte ( SocketFD,
1611 pPort,
1612 Data );
1613 if ( EFI_ERROR ( Status )) {
1614 break;
1615 }
1616
1617 //
1618 // Send the last 6 bits
1619 //
1620 Data = (UINT8)( Character & 0x3f );
1621 Data |= 0x80;
1622 }
1623 else {
1624 Data = (UINT8)( Character & 0x7f );
1625 }
1626
1627 //
1628 // Send the last data byte
1629 //
1630 Status = HttpSendByte ( SocketFD,
1631 pPort,
1632 Data );
1633 if ( EFI_ERROR ( Status )) {
1634 break;
1635 }
1636 }
1637
1638 //
1639 // Return the operation status
1640 //
1641 return Status;
1642 }
1643
1644
1645 /**
1646 Output a value to the HTML page
1647
1648 @param [in] SocketFD Socket file descriptor
1649 @param [in] pPort The WSDT_PORT structure address
1650 @param [in] Value Value to display
1651
1652 @retval EFI_SUCCESS Successfully displayed the address
1653 **/
1654 EFI_STATUS
1655 HttpSendValue (
1656 IN int SocketFD,
1657 IN WSDT_PORT * pPort,
1658 IN UINT64 Value
1659 )
1660 {
1661 BOOLEAN bDisplayZeros;
1662 UINT64 Digit;
1663 CONST UINT64 * pEnd;
1664 CONST UINT64 * pDivisor;
1665 CONST UINT64 pDivisors[ ] = {
1666 10000000000000000000L,
1667 1000000000000000000L,
1668 100000000000000000L,
1669 10000000000000000L,
1670 1000000000000000L,
1671 100000000000000L,
1672 10000000000000L,
1673 1000000000000L,
1674 100000000000L,
1675 10000000000L,
1676 1000000000L,
1677 100000000L,
1678 10000000L,
1679 1000000L,
1680 100000L,
1681 10000L,
1682 1000L,
1683 100L,
1684 10L
1685 };
1686 EFI_STATUS Status;
1687 UINT64 Temp;
1688
1689 //
1690 // Assume success
1691 //
1692 Status = EFI_SUCCESS;
1693
1694 //
1695 // Walk the list of divisors
1696 //
1697 bDisplayZeros = FALSE;
1698 pDivisor = &pDivisors[0];
1699 pEnd = &pDivisor[ sizeof ( pDivisors ) / sizeof ( pDivisors[0])];
1700 while ( pEnd > pDivisor ) {
1701 //
1702 // Determine the next digit
1703 //
1704 Digit = Value / *pDivisor;
1705
1706 //
1707 // Suppress leading zeros
1708 //
1709 if (( 0 != Digit ) || bDisplayZeros ) {
1710 bDisplayZeros = TRUE;
1711
1712 //
1713 // Display the digit
1714 //
1715 Status = HttpSendByte ( SocketFD, pPort, (UINT8)( '0' + Digit ));
1716 if ( EFI_ERROR ( Status )) {
1717 break;
1718 }
1719
1720 //
1721 // Determine the remainder
1722 //
1723 Temp = *pDivisor * Digit;
1724 Value -= Temp;
1725 }
1726
1727 //
1728 // Set the next divisor
1729 //
1730 pDivisor += 1;
1731 }
1732
1733 //
1734 // Display the final digit
1735 //
1736 if ( !EFI_ERROR ( Status )) {
1737 Status = HttpSendByte ( SocketFD, pPort, (UINT8)( '0' + Value ));
1738 }
1739
1740 //
1741 // Return the operation status
1742 //
1743 return Status;
1744 }