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