]> git.proxmox.com Git - mirror_edk2.git/blame_incremental - AppPkg/Applications/Sockets/WebServer/HTTP.c
Merged socket development branch:
[mirror_edk2.git] / AppPkg / Applications / Sockets / WebServer / HTTP.c
... / ...
CommitLineData
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 DataBytes = LengthInBytes;\r
673 }\r
674\r
675 //\r
676 // Copy the data into the buffer\r
677 //\r
678 CopyMem ( &pPort->TxBuffer[ pPort->TxBytes ],\r
679 pBuffer,\r
680 DataBytes );\r
681\r
682 //\r
683 // Account for the data copied\r
684 //\r
685 pPort->TxBytes += DataBytes;\r
686 LengthInBytes -= DataBytes;\r
687\r
688 //\r
689 // Transmit the buffer if it is full\r
690 //\r
691 if ( MaxBytes <= pPort->TxBytes ) {\r
692 Status = HttpFlush ( SocketFD, pPort );\r
693 }\r
694 } while (( EFI_SUCCESS == Status ) && ( 0 < LengthInBytes ));\r
695\r
696 //\r
697 // Return the operation status\r
698 //\r
699 return Status;\r
700}\r
701\r
702\r
703/**\r
704 Send an ANSI string\r
705\r
706 @param [in] SocketFD The socket's file descriptor to add to the list.\r
707 @param [in] pPort The WSDT_PORT structure address\r
708 @param [in] pString A zero terminated Unicode string\r
709\r
710 @retval EFI_SUCCESS The request was successfully processed\r
711\r
712**/\r
713EFI_STATUS\r
714HttpSendAnsiString (\r
715 IN int SocketFD,\r
716 IN WSDT_PORT * pPort,\r
717 IN CONST char * pString\r
718 )\r
719{\r
720 CONST char * pData;\r
721 EFI_STATUS Status;\r
722\r
723 //\r
724 // Assume success\r
725 //\r
726 Status = EFI_SUCCESS;\r
727\r
728 //\r
729 // Walk the characters in he string\r
730 //\r
731 pData = pString;\r
732 while ( 0 != *pData ) {\r
733 pData += 1;\r
734 }\r
735\r
736 //\r
737 // Send the string\r
738 //\r
739 Status = HttpSend ( SocketFD,\r
740 pPort,\r
741 pData - pString,\r
742 (CONST UINT8 *)pString );\r
743\r
744 //\r
745 // Return the operation status\r
746 //\r
747 return Status;\r
748}\r
749\r
750\r
751/**\r
752 Buffer a single byte\r
753\r
754 @param [in] SocketFD The socket's file descriptor to add to the list.\r
755 @param [in] pPort The WSDT_PORT structure address\r
756 @param [in] Data The data byte to send\r
757\r
758 @retval EFI_SUCCESS The request was successfully processed\r
759\r
760**/\r
761EFI_STATUS\r
762HttpSendByte (\r
763 IN int SocketFD,\r
764 IN WSDT_PORT * pPort,\r
765 IN UINT8 Data\r
766 )\r
767{\r
768 EFI_STATUS Status;\r
769\r
770 //\r
771 // Send the data byte\r
772 //\r
773 Status = HttpSend ( SocketFD,\r
774 pPort,\r
775 1,\r
776 &Data );\r
777\r
778 //\r
779 // Return the operation status\r
780 //\r
781 return Status;\r
782}\r
783\r
784\r
785/**\r
786 Display a character\r
787\r
788 @param [in] SocketFD The socket's file descriptor to add to the list.\r
789 @param [in] pPort The WSDT_PORT structure address\r
790 @param [in] Character Character to display\r
791 @param [in] pReplacement Replacement character string\r
792\r
793 @retval EFI_SUCCESS The request was successfully processed\r
794\r
795**/\r
796EFI_STATUS\r
797HttpSendCharacter (\r
798 IN int SocketFD,\r
799 IN WSDT_PORT * pPort,\r
800 IN CHAR8 Character,\r
801 IN CHAR8 * pReplacement\r
802 )\r
803{\r
804 EFI_STATUS Status;\r
805\r
806 //\r
807 // Determine if this is a printable character\r
808 //\r
809 if (( 0x20 <= Character ) && ( 0x7f > Character )) {\r
810 if ( '<' == Character ) {\r
811 //\r
812 // Replace with HTML equivalent\r
813 //\r
814 Status = HttpSendAnsiString ( SocketFD,\r
815 pPort,\r
816 "&lt;" );\r
817 }\r
818 else if ( '>' == Character ) {\r
819 //\r
820 // Replace with HTML equivalent\r
821 //\r
822 Status = HttpSendAnsiString ( SocketFD,\r
823 pPort,\r
824 "&gt;" );\r
825 }\r
826 else if ( '&' == Character ) {\r
827 //\r
828 // Replace with HTML equivalent\r
829 //\r
830 Status = HttpSendAnsiString ( SocketFD,\r
831 pPort,\r
832 "&amp;" );\r
833 }\r
834 else if ( '\"' == Character ) {\r
835 //\r
836 // Replace with HTML equivalent\r
837 //\r
838 Status = HttpSendAnsiString ( SocketFD,\r
839 pPort,\r
840 "&quot;" );\r
841 }\r
842 else {\r
843 //\r
844 // Display the character\r
845 //\r
846 Status = HttpSendByte ( SocketFD,\r
847 pPort,\r
848 Character );\r
849 }\r
850 }\r
851 else {\r
852 //\r
853 // Not a displayable character\r
854 //\r
855 Status = HttpSendAnsiString ( SocketFD,\r
856 pPort,\r
857 pReplacement );\r
858 }\r
859\r
860 //\r
861 // Return the operation status\r
862 //\r
863 return Status;\r
864}\r
865\r
866\r
867/**\r
868 Send a buffer dump\r
869\r
870 @param [in] SocketFD The socket's file descriptor to add to the list.\r
871 @param [in] pPort The WSDT_PORT structure address\r
872 @param [in] ByteCount The number of bytes to display\r
873 @param [in] pData Address of the byte array\r
874\r
875 @retval EFI_SUCCESS The request was successfully processed\r
876\r
877**/\r
878EFI_STATUS\r
879HttpSendDump (\r
880 IN int SocketFD,\r
881 IN WSDT_PORT * pPort,\r
882 IN UINTN ByteCount,\r
883 IN CONST UINT8 * pData\r
884 )\r
885{\r
886 INTN BytesToDisplay;\r
887 UINT8 Character;\r
888 INTN Index;\r
889 INTN InitialSpaces;\r
890 CONST UINT8 * pDataEnd;\r
891 CONST UINT8 * pEnd;\r
892 CONST UINT8 * pTemp;\r
893 EFI_STATUS Status;\r
894\r
895 //\r
896 // Use for/break instead of goto\r
897 //\r
898 for ( ; ; ) {\r
899 //\r
900 // Start the field value\r
901 //\r
902 Status = HttpSendAnsiString ( SocketFD,\r
903 pPort,\r
904 "<code>" );\r
905 if ( EFI_ERROR ( Status )) {\r
906 break;\r
907 }\r
908\r
909 //\r
910 // Walk the bytes to be displayed\r
911 //\r
912 pEnd = &pData[ ByteCount ];\r
913 while ( pEnd > pData ) {\r
914 //\r
915 // Display the address\r
916 //\r
917 Status = HttpSendHexBits ( SocketFD,\r
918 pPort,\r
919 sizeof ( pData ) * 8,\r
920 (UINT64)pData );\r
921 if ( EFI_ERROR ( Status )) {\r
922 break;\r
923 }\r
924\r
925 //\r
926 // Separate the address and data\r
927 //\r
928 Status = HttpSendByte ( SocketFD, pPort, ':' );\r
929 if ( EFI_ERROR ( Status )) {\r
930 break;\r
931 }\r
932\r
933 //\r
934 // Position the starting data correctly\r
935 //\r
936 InitialSpaces = (UINTN)pData;\r
937 InitialSpaces &= BYTES_ON_A_LINE - 1;\r
938 for ( Index = SPACES_ADDRESS_TO_DATA\r
939 + (( 2 + SPACES_BETWEEN_BYTES )\r
940 * InitialSpaces );\r
941 0 < Index; Index-- ) {\r
942 Status = HttpSendAnsiString ( SocketFD,\r
943 pPort,\r
944 "&nbsp;" );\r
945 if ( EFI_ERROR ( Status )) {\r
946 break;\r
947 }\r
948 }\r
949 if ( EFI_ERROR ( Status )) {\r
950 break;\r
951 }\r
952\r
953 //\r
954 // Display the data\r
955 //\r
956 BytesToDisplay = pEnd - pData;\r
957 if (( BYTES_ON_A_LINE - InitialSpaces ) < BytesToDisplay ) {\r
958 BytesToDisplay = BYTES_ON_A_LINE - InitialSpaces;\r
959 }\r
960 pDataEnd = &pData[ BytesToDisplay ];\r
961 pTemp = pData;\r
962 while ( pDataEnd > pTemp ) {\r
963 Status = HttpSendHexBits ( SocketFD,\r
964 pPort,\r
965 8,\r
966 *pTemp++ );\r
967 if ( EFI_ERROR ( Status )) {\r
968 break;\r
969 }\r
970\r
971 //\r
972 // Separate the data bytes\r
973 //\r
974 for ( Index = SPACES_BETWEEN_BYTES; 0 < Index; Index-- ) {\r
975 Status = HttpSendAnsiString ( SocketFD,\r
976 pPort,\r
977 "&nbsp;" );\r
978 if ( EFI_ERROR ( Status )) {\r
979 break;\r
980 }\r
981 }\r
982 if ( EFI_ERROR ( Status )) {\r
983 break;\r
984 }\r
985 }\r
986 if ( EFI_ERROR ( Status )) {\r
987 break;\r
988 }\r
989\r
990 //\r
991 // Separate the data from the ASCII display\r
992 //\r
993 for ( Index = (( 2 + SPACES_BETWEEN_BYTES )\r
994 * ( BYTES_ON_A_LINE - BytesToDisplay - InitialSpaces ))\r
995 - SPACES_BETWEEN_BYTES\r
996 + SPACES_DATA_TO_ASCII\r
997 + InitialSpaces;\r
998 0 < Index; Index-- ) {\r
999 Status = HttpSendAnsiString ( SocketFD,\r
1000 pPort,\r
1001 "&nbsp;" );\r
1002 if ( EFI_ERROR ( Status )) {\r
1003 break;\r
1004 }\r
1005 }\r
1006 if ( EFI_ERROR ( Status )) {\r
1007 break;\r
1008 }\r
1009\r
1010 //\r
1011 // Display the ASCII data\r
1012 //\r
1013 while ( pDataEnd > pData ) {\r
1014 Character = *pData++;\r
1015 Status = HttpSendCharacter ( SocketFD,\r
1016 pPort,\r
1017 Character,\r
1018 "." );\r
1019 if ( EFI_ERROR ( Status )) {\r
1020 break;\r
1021 }\r
1022 }\r
1023 if ( EFI_ERROR ( Status )) {\r
1024 break;\r
1025 }\r
1026\r
1027 //\r
1028 // Terminate the line\r
1029 //\r
1030 Status = HttpSendAnsiString ( SocketFD,\r
1031 pPort,\r
1032 "<br/>\r\n" );\r
1033 if ( EFI_ERROR ( Status )) {\r
1034 break;\r
1035 }\r
1036 }\r
1037\r
1038 //\r
1039 // Terminate the field value and row\r
1040 //\r
1041 Status = HttpSendAnsiString ( SocketFD,\r
1042 pPort,\r
1043 "</code>\r\n" );\r
1044 break;\r
1045 }\r
1046\r
1047 //\r
1048 // Return the operation status\r
1049 //\r
1050 return Status;\r
1051}\r
1052\r
1053\r
1054/**\r
1055 Display a row containing a GUID value\r
1056\r
1057 @param [in] SocketFD The socket's file descriptor to add to the list.\r
1058 @param [in] pPort The WSDT_PORT structure address\r
1059 @param [in] pGuid Address of the GUID to display\r
1060\r
1061 @retval EFI_SUCCESS The request was successfully processed\r
1062\r
1063**/\r
1064EFI_STATUS\r
1065HttpSendGuid (\r
1066 IN int SocketFD,\r
1067 IN WSDT_PORT * pPort,\r
1068 IN CONST EFI_GUID * pGuid\r
1069 )\r
1070{\r
1071 UINT32 Index;\r
1072 EFI_STATUS Status;\r
1073\r
1074 DBG_ENTER ( );\r
1075\r
1076 //\r
1077 // Use for/break instead of goto\r
1078 //\r
1079 for ( ; ; ) {\r
1080 //\r
1081 // Display the GUID in a form found in the code\r
1082 //\r
1083 // E.g. 0xca16005f, 0x11ec, 0x4bdc, { 0x99, 0x97, 0x27, 0x2c, 0xa9, 0xba, 0x15, 0xe5 }\r
1084 //\r
1085\r
1086 //\r
1087 // Display the first 32 bits\r
1088 //\r
1089 Status = HttpSendAnsiString ( SocketFD,\r
1090 pPort,\r
1091 "0x" );\r
1092 if ( EFI_ERROR ( Status )) {\r
1093 break;\r
1094 }\r
1095 Status = HttpSendHexBits ( SocketFD,\r
1096 pPort,\r
1097 32,\r
1098 pGuid->Data1 );\r
1099 if ( EFI_ERROR ( Status )) {\r
1100 break;\r
1101 }\r
1102\r
1103 //\r
1104 // Display the second 16 bits\r
1105 //\r
1106 Status = HttpSendAnsiString ( SocketFD,\r
1107 pPort,\r
1108 ", 0x" );\r
1109 if ( EFI_ERROR ( Status )) {\r
1110 break;\r
1111 }\r
1112 Status = HttpSendHexBits ( SocketFD,\r
1113 pPort,\r
1114 16,\r
1115 pGuid->Data2 );\r
1116 if ( EFI_ERROR ( Status )) {\r
1117 break;\r
1118 }\r
1119\r
1120 //\r
1121 // Display the thrid 16 bits\r
1122 //\r
1123 Status = HttpSendAnsiString ( SocketFD,\r
1124 pPort,\r
1125 ", 0x" );\r
1126 if ( EFI_ERROR ( Status )) {\r
1127 break;\r
1128 }\r
1129 Status = HttpSendHexBits ( SocketFD,\r
1130 pPort,\r
1131 16,\r
1132 pGuid->Data3 );\r
1133 if ( EFI_ERROR ( Status )) {\r
1134 break;\r
1135 }\r
1136\r
1137 //\r
1138 // Place the last 64 bits in braces\r
1139 //\r
1140 Status = HttpSendAnsiString ( SocketFD,\r
1141 pPort,\r
1142 ", { 0x" );\r
1143 if ( EFI_ERROR ( Status )) {\r
1144 break;\r
1145 }\r
1146 for ( Index = 0; 7 >= Index; Index++ ) {\r
1147 //\r
1148 // Display the next 8 bits\r
1149 //\r
1150 Status = HttpSendHexBits ( SocketFD,\r
1151 pPort,\r
1152 8,\r
1153 pGuid->Data4[ Index ]);\r
1154 if ( EFI_ERROR ( Status )) {\r
1155 break;\r
1156 }\r
1157\r
1158 //\r
1159 // Separate the bytes\r
1160 //\r
1161 Status = HttpSendAnsiString ( SocketFD,\r
1162 pPort,\r
1163 ( 7 != Index ) ? ", 0x" : " }" );\r
1164 if ( EFI_ERROR ( Status )) {\r
1165 break;\r
1166 }\r
1167 }\r
1168 break;\r
1169 }\r
1170\r
1171 //\r
1172 // Return the operation status\r
1173 //\r
1174 DBG_EXIT_STATUS ( Status );\r
1175 return Status;\r
1176}\r
1177\r
1178\r
1179/**\r
1180 Output a hex value to the HTML page\r
1181\r
1182 @param [in] SocketFD Socket file descriptor\r
1183 @param [in] pPort The WSDT_PORT structure address\r
1184 @param [in] Bits Number of bits to display\r
1185 @param [in] Value Value to display\r
1186\r
1187 @retval EFI_SUCCESS Successfully displayed the address\r
1188**/\r
1189EFI_STATUS\r
1190HttpSendHexBits (\r
1191 IN int SocketFD,\r
1192 IN WSDT_PORT * pPort,\r
1193 IN INT32 Bits,\r
1194 IN UINT64 Value\r
1195 )\r
1196{\r
1197 UINT32 Digit;\r
1198 INT32 Shift;\r
1199 EFI_STATUS Status;\r
1200\r
1201 //\r
1202 // Assume success\r
1203 //\r
1204 Status = EFI_SUCCESS;\r
1205\r
1206 //\r
1207 // Walk the list of divisors\r
1208 //\r
1209 Shift = (( Bits + 3 ) & ( ~3 )) - 4;\r
1210 while ( 0 <= Shift ) {\r
1211 //\r
1212 // Determine the next digit\r
1213 //\r
1214 Digit = (UINT32)(( Value >> Shift ) & 0xf );\r
1215 if ( 10 <= Digit ) {\r
1216 Digit += 'A' - '0' - 10;\r
1217 }\r
1218\r
1219 //\r
1220 // Display the digit\r
1221 //\r
1222 Status = HttpSendByte ( SocketFD, pPort, (UINT8)( '0' + Digit ));\r
1223 if ( EFI_ERROR ( Status )) {\r
1224 break;\r
1225 }\r
1226\r
1227 //\r
1228 // Set the next shift\r
1229 //\r
1230 Shift -= 4;\r
1231 }\r
1232\r
1233 //\r
1234 // Return the operation status\r
1235 //\r
1236 return Status;\r
1237}\r
1238\r
1239\r
1240/**\r
1241 Output a hex value to the HTML page\r
1242\r
1243 @param [in] SocketFD Socket file descriptor\r
1244 @param [in] pPort The WSDT_PORT structure address\r
1245 @param [in] Value Value to display\r
1246\r
1247 @retval EFI_SUCCESS Successfully displayed the address\r
1248**/\r
1249EFI_STATUS\r
1250HttpSendHexValue (\r
1251 IN int SocketFD,\r
1252 IN WSDT_PORT * pPort,\r
1253 IN UINT64 Value\r
1254 )\r
1255{\r
1256 BOOLEAN bDisplayZeros;\r
1257 UINT32 Digit;\r
1258 INT32 Shift;\r
1259 EFI_STATUS Status;\r
1260\r
1261 //\r
1262 // Assume success\r
1263 //\r
1264 Status = EFI_SUCCESS;\r
1265\r
1266 //\r
1267 // Walk the list of divisors\r
1268 //\r
1269 bDisplayZeros = FALSE;\r
1270 Shift = 60;\r
1271 do {\r
1272 //\r
1273 // Determine the next digit\r
1274 //\r
1275 Digit = (UINT32)(( Value >> Shift ) & 0xf );\r
1276 if ( 10 <= Digit ) {\r
1277 Digit += 'A' - '0' - 10;\r
1278 }\r
1279\r
1280 //\r
1281 // Suppress leading zeros\r
1282 //\r
1283 if (( 0 != Digit ) || bDisplayZeros || ( 0 == Shift )) {\r
1284 bDisplayZeros = TRUE;\r
1285\r
1286 //\r
1287 // Display the digit\r
1288 //\r
1289 Status = HttpSendByte ( SocketFD, pPort, (UINT8)( '0' + Digit ));\r
1290 if ( EFI_ERROR ( Status )) {\r
1291 break;\r
1292 }\r
1293 }\r
1294\r
1295 //\r
1296 // Set the next shift\r
1297 //\r
1298 Shift -= 4;\r
1299 } while ( 0 <= Shift );\r
1300\r
1301 //\r
1302 // Return the operation status\r
1303 //\r
1304 return Status;\r
1305}\r
1306\r
1307\r
1308/**\r
1309 Output an IP address to the HTML page\r
1310\r
1311 @param [in] SocketFD Socket file descriptor\r
1312 @param [in] pPort The WSDT_PORT structure address\r
1313 @param [in] pAddress Address of the socket address\r
1314\r
1315 @retval EFI_SUCCESS Successfully displayed the address\r
1316**/\r
1317EFI_STATUS\r
1318HttpSendIpAddress (\r
1319 IN int SocketFD,\r
1320 IN WSDT_PORT * pPort,\r
1321 IN struct sockaddr_in * pAddress\r
1322 )\r
1323{\r
1324 EFI_STATUS Status;\r
1325\r
1326 //\r
1327 // Output the IPv4 address\r
1328 //\r
1329 Status = HttpSendValue ( SocketFD, pPort, (UINT8)pAddress->sin_addr.s_addr );\r
1330 if ( !EFI_ERROR ( Status )) {\r
1331 Status = HttpSendByte ( SocketFD, pPort, '.' );\r
1332 if ( !EFI_ERROR ( Status )) {\r
1333 Status = HttpSendValue ( SocketFD, pPort, (UINT8)( pAddress->sin_addr.s_addr >> 8 ));\r
1334 if ( !EFI_ERROR ( Status )) {\r
1335 Status = HttpSendByte ( SocketFD, pPort, '.' );\r
1336 if ( !EFI_ERROR ( Status )) {\r
1337 Status = HttpSendValue ( SocketFD, pPort, (UINT8)( pAddress->sin_addr.s_addr >> 16 ));\r
1338 if ( !EFI_ERROR ( Status )) {\r
1339 Status = HttpSendByte ( SocketFD, pPort, '.' );\r
1340 if ( !EFI_ERROR ( Status )) {\r
1341 Status = HttpSendValue ( SocketFD, pPort, (UINT8)( pAddress->sin_addr.s_addr >> 24 ));\r
1342 if ( !EFI_ERROR ( Status )) {\r
1343 //\r
1344 // Output the port number\r
1345 //\r
1346 Status = HttpSendByte ( SocketFD, pPort, ':' );\r
1347 if ( !EFI_ERROR ( Status )) {\r
1348 Status = HttpSendValue ( SocketFD, pPort, htons ( pAddress->sin_port ));\r
1349 }\r
1350 }\r
1351 }\r
1352 }\r
1353 }\r
1354 }\r
1355 }\r
1356 }\r
1357\r
1358 //\r
1359 // Return the operation status\r
1360 //\r
1361 return Status;\r
1362}\r
1363\r
1364\r
1365/**\r
1366 Send a Unicode string\r
1367\r
1368 @param [in] SocketFD The socket's file descriptor to add to the list.\r
1369 @param [in] pPort The WSDT_PORT structure address\r
1370 @param [in] pString A zero terminated Unicode string\r
1371\r
1372 @retval EFI_SUCCESS The request was successfully processed\r
1373\r
1374**/\r
1375EFI_STATUS\r
1376HttpSendUnicodeString (\r
1377 IN int SocketFD,\r
1378 IN WSDT_PORT * pPort,\r
1379 IN CONST UINT16 * pString\r
1380 )\r
1381{\r
1382 UINT8 Data;\r
1383 UINT16 Character;\r
1384 EFI_STATUS Status;\r
1385\r
1386 //\r
1387 // Assume success\r
1388 //\r
1389 Status = EFI_SUCCESS;\r
1390\r
1391 //\r
1392 // Walk the characters in he string\r
1393 //\r
1394 while ( 0 != ( Character = *pString++ )) {\r
1395 //\r
1396 // Convert the character to UTF-8\r
1397 //\r
1398 if ( 0 != ( Character & 0xf800 )) {\r
1399 //\r
1400 // Send the upper 4 bits\r
1401 //\r
1402 Data = (UINT8)(( Character >> 12 ) & 0xf );\r
1403 Data |= 0xe0;\r
1404 Status = HttpSendByte ( SocketFD,\r
1405 pPort,\r
1406 Data );\r
1407 if ( EFI_ERROR ( Status )) {\r
1408 break;\r
1409 }\r
1410\r
1411 //\r
1412 // Send the next 6 bits\r
1413 //\r
1414 Data = (UINT8)(( Character >> 6 ) & 0x3f );\r
1415 Data |= 0x80;\r
1416 Status = HttpSendByte ( SocketFD,\r
1417 pPort,\r
1418 Data );\r
1419 if ( EFI_ERROR ( Status )) {\r
1420 break;\r
1421 }\r
1422\r
1423 //\r
1424 // Send the last 6 bits\r
1425 //\r
1426 Data = (UINT8)( Character & 0x3f );\r
1427 Data |= 0x80;\r
1428 }\r
1429 else if ( 0 != ( Character & 0x0780 )) {\r
1430 //\r
1431 // Send the upper 5 bits\r
1432 //\r
1433 Data = (UINT8)(( Character >> 6 ) & 0x1f );\r
1434 Data |= 0xc0;\r
1435 Status = HttpSendByte ( SocketFD,\r
1436 pPort,\r
1437 Data );\r
1438 if ( EFI_ERROR ( Status )) {\r
1439 break;\r
1440 }\r
1441\r
1442 //\r
1443 // Send the last 6 bits\r
1444 //\r
1445 Data = (UINT8)( Character & 0x3f );\r
1446 Data |= 0x80;\r
1447 }\r
1448 else {\r
1449 Data = (UINT8)( Character & 0x7f );\r
1450 }\r
1451\r
1452 //\r
1453 // Send the last data byte\r
1454 //\r
1455 Status = HttpSendByte ( SocketFD,\r
1456 pPort,\r
1457 Data );\r
1458 if ( EFI_ERROR ( Status )) {\r
1459 break;\r
1460 }\r
1461 }\r
1462\r
1463 //\r
1464 // Return the operation status\r
1465 //\r
1466 return Status;\r
1467}\r
1468\r
1469\r
1470/**\r
1471 Output a value to the HTML page\r
1472\r
1473 @param [in] SocketFD Socket file descriptor\r
1474 @param [in] pPort The WSDT_PORT structure address\r
1475 @param [in] Value Value to display\r
1476\r
1477 @retval EFI_SUCCESS Successfully displayed the address\r
1478**/\r
1479EFI_STATUS\r
1480HttpSendValue (\r
1481 IN int SocketFD,\r
1482 IN WSDT_PORT * pPort,\r
1483 IN UINT64 Value\r
1484 )\r
1485{\r
1486 BOOLEAN bDisplayZeros;\r
1487 UINT64 Digit;\r
1488 CONST UINT64 * pEnd;\r
1489 CONST UINT64 * pDivisor;\r
1490 CONST UINT64 pDivisors[ ] = {\r
1491 10000000000000000000L,\r
1492 1000000000000000000L,\r
1493 100000000000000000L,\r
1494 10000000000000000L,\r
1495 1000000000000000L,\r
1496 100000000000000L,\r
1497 10000000000000L,\r
1498 1000000000000L,\r
1499 100000000000L,\r
1500 10000000000L,\r
1501 1000000000L,\r
1502 100000000L,\r
1503 10000000L,\r
1504 1000000L,\r
1505 100000L,\r
1506 10000L,\r
1507 1000L,\r
1508 100L,\r
1509 10L\r
1510 };\r
1511 EFI_STATUS Status;\r
1512 UINT64 Temp;\r
1513\r
1514 //\r
1515 // Assume success\r
1516 //\r
1517 Status = EFI_SUCCESS;\r
1518\r
1519 //\r
1520 // Walk the list of divisors\r
1521 //\r
1522 bDisplayZeros = FALSE;\r
1523 pDivisor = &pDivisors[0];\r
1524 pEnd = &pDivisor[ sizeof ( pDivisors ) / sizeof ( pDivisors[0])];\r
1525 while ( pEnd > pDivisor ) {\r
1526 //\r
1527 // Determine the next digit\r
1528 //\r
1529 Digit = Value / *pDivisor;\r
1530\r
1531 //\r
1532 // Suppress leading zeros\r
1533 //\r
1534 if (( 0 != Digit ) || bDisplayZeros ) {\r
1535 bDisplayZeros = TRUE;\r
1536\r
1537 //\r
1538 // Display the digit\r
1539 //\r
1540 Status = HttpSendByte ( SocketFD, pPort, (UINT8)( '0' + Digit ));\r
1541 if ( EFI_ERROR ( Status )) {\r
1542 break;\r
1543 }\r
1544\r
1545 //\r
1546 // Determine the remainder\r
1547 //\r
1548 Temp = *pDivisor * Digit;\r
1549 Value -= Temp;\r
1550 }\r
1551\r
1552 //\r
1553 // Set the next divisor\r
1554 //\r
1555 pDivisor += 1;\r
1556 }\r
1557\r
1558 //\r
1559 // Display the final digit\r
1560 //\r
1561 if ( !EFI_ERROR ( Status )) {\r
1562 Status = HttpSendByte ( SocketFD, pPort, (UINT8)( '0' + Value ));\r
1563 }\r
1564\r
1565 //\r
1566 // Return the operation status\r
1567 //\r
1568 return Status;\r
1569}\r