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**/ 28INTN 29HttpCharGet ( 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**/ 97EFI_STATUS 98HttpFlush ( 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**/ 154INTN 155HttpLowerCase ( 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**/ 184INTN 185HttpMatch ( 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**/ 253EFI_STATUS 254HttpPageHeader ( 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**/ 326EFI_STATUS 327HttpPageNotFound ( 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**/ 385EFI_STATUS 386HttpPageTrailer ( 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**/ 484UINT8 * 485HttpReplaceSpace ( 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**/ 527EFI_STATUS 528HttpRequest ( 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**/ 641EFI_STATUS 642HttpSend ( 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**/ 705EFI_STATUS 706HttpSendAnsiString ( 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**/ 753EFI_STATUS 754HttpSendByte ( 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**/ 788EFI_STATUS 789HttpSendCharacter ( 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**/ 870EFI_STATUS 871HttpSendDump ( 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**/ 1056EFI_STATUS 1057HttpSendGuid ( 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**/ 1181EFI_STATUS 1182HttpSendHexBits ( 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**/ 1241EFI_STATUS 1242HttpSendHexValue ( 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**/ 1315EFI_STATUS 1316HttpSendIp6Value ( 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**/ 1415EFI_STATUS 1416HttpSendIpAddress ( 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**/ 1541EFI_STATUS 1542HttpSendUnicodeString ( 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**/ 1645EFI_STATUS 1646HttpSendValue ( 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