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