]> git.proxmox.com Git - mirror_edk2.git/blob - AppPkg/Applications/Sockets/WebServer/HTTP.c
Add Socket Library applications.
[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 @returns 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 @returns 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 @returns 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 @returns 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 {
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 IP address to the HTML page
1311
1312 @param [in] SocketFD Socket file descriptor
1313 @param [in] pPort The WSDT_PORT structure address
1314 @param [in] pAddress Address of the socket address
1315
1316 @retval EFI_SUCCESS Successfully displayed the address
1317 **/
1318 EFI_STATUS
1319 HttpSendIpAddress (
1320 IN int SocketFD,
1321 IN WSDT_PORT * pPort,
1322 IN struct sockaddr_in * pAddress
1323 )
1324 {
1325 EFI_STATUS Status;
1326
1327 //
1328 // Output the IPv4 address
1329 //
1330 Status = HttpSendValue ( SocketFD, pPort, (UINT8)pAddress->sin_addr.s_addr );
1331 if ( !EFI_ERROR ( Status )) {
1332 Status = HttpSendByte ( SocketFD, pPort, '.' );
1333 if ( !EFI_ERROR ( Status )) {
1334 Status = HttpSendValue ( SocketFD, pPort, (UINT8)( pAddress->sin_addr.s_addr >> 8 ));
1335 if ( !EFI_ERROR ( Status )) {
1336 Status = HttpSendByte ( SocketFD, pPort, '.' );
1337 if ( !EFI_ERROR ( Status )) {
1338 Status = HttpSendValue ( SocketFD, pPort, (UINT8)( pAddress->sin_addr.s_addr >> 16 ));
1339 if ( !EFI_ERROR ( Status )) {
1340 Status = HttpSendByte ( SocketFD, pPort, '.' );
1341 if ( !EFI_ERROR ( Status )) {
1342 Status = HttpSendValue ( SocketFD, pPort, (UINT8)( pAddress->sin_addr.s_addr >> 24 ));
1343 if ( !EFI_ERROR ( Status )) {
1344 //
1345 // Output the port number
1346 //
1347 Status = HttpSendByte ( SocketFD, pPort, ':' );
1348 if ( !EFI_ERROR ( Status )) {
1349 Status = HttpSendValue ( SocketFD, pPort, htons ( pAddress->sin_port ));
1350 }
1351 }
1352 }
1353 }
1354 }
1355 }
1356 }
1357 }
1358
1359 //
1360 // Return the operation status
1361 //
1362 return Status;
1363 }
1364
1365
1366 /**
1367 Send a Unicode string
1368
1369 @param [in] SocketFD The socket's file descriptor to add to the list.
1370 @param [in] pPort The WSDT_PORT structure address
1371 @param [in] pString A zero terminated Unicode string
1372
1373 @retval EFI_SUCCESS The request was successfully processed
1374
1375 **/
1376 EFI_STATUS
1377 HttpSendUnicodeString (
1378 IN int SocketFD,
1379 IN WSDT_PORT * pPort,
1380 IN CONST UINT16 * pString
1381 )
1382 {
1383 UINT8 Data;
1384 UINT16 Character;
1385 EFI_STATUS Status;
1386
1387 //
1388 // Assume success
1389 //
1390 Status = EFI_SUCCESS;
1391
1392 //
1393 // Walk the characters in he string
1394 //
1395 while ( 0 != ( Character = *pString++ )) {
1396 //
1397 // Convert the character to UTF-8
1398 //
1399 if ( 0 != ( Character & 0xf800 )) {
1400 //
1401 // Send the upper 4 bits
1402 //
1403 Data = (UINT8)(( Character >> 12 ) & 0xf );
1404 Data |= 0xe0;
1405 Status = HttpSendByte ( SocketFD,
1406 pPort,
1407 Data );
1408 if ( EFI_ERROR ( Status )) {
1409 break;
1410 }
1411
1412 //
1413 // Send the next 6 bits
1414 //
1415 Data = (UINT8)(( Character >> 6 ) & 0x3f );
1416 Data |= 0x80;
1417 Status = HttpSendByte ( SocketFD,
1418 pPort,
1419 Data );
1420 if ( EFI_ERROR ( Status )) {
1421 break;
1422 }
1423
1424 //
1425 // Send the last 6 bits
1426 //
1427 Data = (UINT8)( Character & 0x3f );
1428 Data |= 0x80;
1429 }
1430 else if ( 0 != ( Character & 0x0780 )) {
1431 //
1432 // Send the upper 5 bits
1433 //
1434 Data = (UINT8)(( Character >> 6 ) & 0x1f );
1435 Data |= 0xc0;
1436 Status = HttpSendByte ( SocketFD,
1437 pPort,
1438 Data );
1439 if ( EFI_ERROR ( Status )) {
1440 break;
1441 }
1442
1443 //
1444 // Send the last 6 bits
1445 //
1446 Data = (UINT8)( Character & 0x3f );
1447 Data |= 0x80;
1448 }
1449 else {
1450 Data = (UINT8)( Character & 0x7f );
1451 }
1452
1453 //
1454 // Send the last data byte
1455 //
1456 Status = HttpSendByte ( SocketFD,
1457 pPort,
1458 Data );
1459 if ( EFI_ERROR ( Status )) {
1460 break;
1461 }
1462 }
1463
1464 //
1465 // Return the operation status
1466 //
1467 return Status;
1468 }
1469
1470
1471 /**
1472 Output a value to the HTML page
1473
1474 @param [in] SocketFD Socket file descriptor
1475 @param [in] pPort The WSDT_PORT structure address
1476 @param [in] Value Value to display
1477
1478 @retval EFI_SUCCESS Successfully displayed the address
1479 **/
1480 EFI_STATUS
1481 HttpSendValue (
1482 IN int SocketFD,
1483 IN WSDT_PORT * pPort,
1484 IN UINT64 Value
1485 )
1486 {
1487 BOOLEAN bDisplayZeros;
1488 UINT64 Digit;
1489 CONST UINT64 * pEnd;
1490 CONST UINT64 * pDivisor;
1491 CONST UINT64 pDivisors [ ] = {
1492 10000000000000000000L,
1493 1000000000000000000L,
1494 100000000000000000L,
1495 10000000000000000L,
1496 1000000000000000L,
1497 100000000000000L,
1498 10000000000000L,
1499 1000000000000L,
1500 100000000000L,
1501 10000000000L,
1502 1000000000L,
1503 100000000L,
1504 10000000L,
1505 1000000L,
1506 100000L,
1507 10000L,
1508 1000L,
1509 100L,
1510 10L
1511 };
1512 EFI_STATUS Status;
1513 UINT64 Temp;
1514
1515 //
1516 // Assume success
1517 //
1518 Status = EFI_SUCCESS;
1519
1520 //
1521 // Walk the list of divisors
1522 //
1523 bDisplayZeros = FALSE;
1524 pDivisor = &pDivisors[0];
1525 pEnd = &pDivisor [ sizeof ( pDivisors ) / sizeof ( pDivisors [0])];
1526 while ( pEnd > pDivisor ) {
1527 //
1528 // Determine the next digit
1529 //
1530 Digit = Value / *pDivisor;
1531
1532 //
1533 // Suppress leading zeros
1534 //
1535 if (( 0 != Digit ) || bDisplayZeros ) {
1536 bDisplayZeros = TRUE;
1537
1538 //
1539 // Display the digit
1540 //
1541 Status = HttpSendByte ( SocketFD, pPort, (UINT8)( '0' + Digit ));
1542 if ( EFI_ERROR ( Status )) {
1543 break;
1544 }
1545
1546 //
1547 // Determine the remainder
1548 //
1549 Temp = *pDivisor * Digit;
1550 Value -= Temp;
1551 }
1552
1553 //
1554 // Set the next divisor
1555 //
1556 pDivisor += 1;
1557 }
1558
1559 //
1560 // Display the final digit
1561 //
1562 if ( !EFI_ERROR ( Status )) {
1563 Status = HttpSendByte ( SocketFD, pPort, (UINT8)( '0' + Value ));
1564 }
1565
1566 //
1567 // Return the operation status
1568 //
1569 return Status;
1570 }