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                                    "&lt;" );
809    }
810    else if ( '>' == Character ) {
811      //
812      //  Replace with HTML equivalent
813      //
814      Status = HttpSendAnsiString ( SocketFD,
815                                    pPort,
816                                    "&gt;" );
817    }
818    else if ( '&' == Character ) {
819      //
820      //  Replace with HTML equivalent
821      //
822      Status = HttpSendAnsiString ( SocketFD,
823                                    pPort,
824                                    "&amp;" );
825    }
826    else if ( '\"' == Character ) {
827      //
828      //  Replace with HTML equivalent
829      //
830      Status = HttpSendAnsiString ( SocketFD,
831                                    pPort,
832                                    "&quot;" );
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                                      "&nbsp;" );
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                                        "&nbsp;" );
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                                      "&nbsp;" );
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