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