TianoCore EDK2 master
Loading...
Searching...
No Matches
DxeHttpLib.c
Go to the documentation of this file.
1
11#include "DxeHttpLib.h"
12
30EFIAPI
32 IN CHAR8 *Buffer,
33 IN UINT32 BufferLength,
34 OUT CHAR8 *ResultBuffer,
35 OUT UINT32 *ResultLength
36 )
37{
38 UINTN Index;
39 UINTN Offset;
40 CHAR8 HexStr[3];
41
42 if ((Buffer == NULL) || (BufferLength == 0) || (ResultBuffer == NULL)) {
43 return EFI_INVALID_PARAMETER;
44 }
45
46 Index = 0;
47 Offset = 0;
48 HexStr[2] = '\0';
49 while (Index < BufferLength) {
50 if (Buffer[Index] == '%') {
51 if ((Index + 1 >= BufferLength) || (Index + 2 >= BufferLength) ||
52 !NET_IS_HEX_CHAR (Buffer[Index+1]) || !NET_IS_HEX_CHAR (Buffer[Index+2]))
53 {
54 return EFI_INVALID_PARAMETER;
55 }
56
57 HexStr[0] = Buffer[Index+1];
58 HexStr[1] = Buffer[Index+2];
59 ResultBuffer[Offset] = (CHAR8)AsciiStrHexToUintn (HexStr);
60 Index += 3;
61 } else {
62 ResultBuffer[Offset] = Buffer[Index];
63 Index++;
64 }
65
66 Offset++;
67 }
68
69 *ResultLength = (UINT32)Offset;
70
71 return EFI_SUCCESS;
72}
73
85HTTP_URL_PARSE_STATE
87 IN CHAR8 Char,
88 IN HTTP_URL_PARSE_STATE State,
89 IN BOOLEAN *IsRightBracket
90 )
91{
92 //
93 // RFC 3986:
94 // The authority component is preceded by a double slash ("//") and is
95 // terminated by the next slash ("/"), question mark ("?"), or number
96 // sign ("#") character, or by the end of the URI.
97 //
98 if ((Char == ' ') || (Char == '\r') || (Char == '\n')) {
99 return UrlParserStateMax;
100 }
101
102 //
103 // authority = [ userinfo "@" ] host [ ":" port ]
104 //
105 switch (State) {
106 case UrlParserUserInfo:
107 if (Char == '@') {
108 return UrlParserHostStart;
109 }
110
111 break;
112
113 case UrlParserHost:
114 case UrlParserHostStart:
115 if (Char == '[') {
116 return UrlParserHostIpv6;
117 }
118
119 if (Char == ':') {
120 return UrlParserPortStart;
121 }
122
123 return UrlParserHost;
124
125 case UrlParserHostIpv6:
126 if (Char == ']') {
127 *IsRightBracket = TRUE;
128 }
129
130 if ((Char == ':') && *IsRightBracket) {
131 return UrlParserPortStart;
132 }
133
134 return UrlParserHostIpv6;
135
136 case UrlParserPort:
137 case UrlParserPortStart:
138 return UrlParserPort;
139
140 default:
141 break;
142 }
143
144 return State;
145}
146
160 IN CHAR8 *Url,
161 IN BOOLEAN FoundAt,
162 IN OUT HTTP_URL_PARSER *UrlParser
163 )
164{
165 CHAR8 *Char;
166 CHAR8 *Authority;
167 UINT32 Length;
168 HTTP_URL_PARSE_STATE State;
169 UINT32 Field;
170 UINT32 OldField;
171 BOOLEAN IsrightBracket;
172
173 ASSERT ((UrlParser->FieldBitMap & BIT (HTTP_URI_FIELD_AUTHORITY)) != 0);
174
175 //
176 // authority = [ userinfo "@" ] host [ ":" port ]
177 //
178 if (FoundAt) {
179 State = UrlParserUserInfo;
180 } else {
181 State = UrlParserHost;
182 }
183
184 IsrightBracket = FALSE;
185 Field = HTTP_URI_FIELD_MAX;
186 OldField = Field;
187 Authority = Url + UrlParser->FieldData[HTTP_URI_FIELD_AUTHORITY].Offset;
188 Length = UrlParser->FieldData[HTTP_URI_FIELD_AUTHORITY].Length;
189 for (Char = Authority; Char < Authority + Length; Char++) {
190 State = NetHttpParseAuthorityChar (*Char, State, &IsrightBracket);
191 switch (State) {
192 case UrlParserStateMax:
193 return EFI_INVALID_PARAMETER;
194
195 case UrlParserHostStart:
196 case UrlParserPortStart:
197 continue;
198
199 case UrlParserUserInfo:
200 Field = HTTP_URI_FIELD_USERINFO;
201 break;
202
203 case UrlParserHost:
204 Field = HTTP_URI_FIELD_HOST;
205 break;
206
207 case UrlParserHostIpv6:
208 Field = HTTP_URI_FIELD_HOST;
209 break;
210
211 case UrlParserPort:
212 Field = HTTP_URI_FIELD_PORT;
213 break;
214
215 default:
216 ASSERT (FALSE);
217 }
218
219 //
220 // Field not changed, count the length.
221 //
222 ASSERT (Field < HTTP_URI_FIELD_MAX);
223 if (Field == OldField) {
224 UrlParser->FieldData[Field].Length++;
225 continue;
226 }
227
228 //
229 // New field start
230 //
231 UrlParser->FieldBitMap |= BIT (Field);
232 UrlParser->FieldData[Field].Offset = (UINT32)(Char - Url);
233 UrlParser->FieldData[Field].Length = 1;
234 OldField = Field;
235 }
236
237 return EFI_SUCCESS;
238}
239
249HTTP_URL_PARSE_STATE
251 IN CHAR8 Char,
252 IN HTTP_URL_PARSE_STATE State
253 )
254{
255 if ((Char == ' ') || (Char == '\r') || (Char == '\n')) {
256 return UrlParserStateMax;
257 }
258
259 //
260 // http_URL = "http:" "//" host [ ":" port ] [ abs_path [ "?" query ]]
261 //
262 // Request-URI = "*" | absolute-URI | path-absolute | authority
263 //
264 // absolute-URI = scheme ":" hier-part [ "?" query ]
265 // path-absolute = "/" [ segment-nz *( "/" segment ) ]
266 // authority = [ userinfo "@" ] host [ ":" port ]
267 //
268 switch (State) {
269 case UrlParserUrlStart:
270 if ((Char == '*') || (Char == '/')) {
271 return UrlParserPath;
272 }
273
274 return UrlParserScheme;
275
276 case UrlParserScheme:
277 if (Char == ':') {
278 return UrlParserSchemeColon;
279 }
280
281 break;
282
283 case UrlParserSchemeColon:
284 if (Char == '/') {
285 return UrlParserSchemeColonSlash;
286 }
287
288 break;
289
290 case UrlParserSchemeColonSlash:
291 if (Char == '/') {
292 return UrlParserSchemeColonSlashSlash;
293 }
294
295 break;
296
297 case UrlParserAtInAuthority:
298 if (Char == '@') {
299 return UrlParserStateMax;
300 }
301
302 case UrlParserAuthority:
303 case UrlParserSchemeColonSlashSlash:
304 if (Char == '@') {
305 return UrlParserAtInAuthority;
306 }
307
308 if (Char == '/') {
309 return UrlParserPath;
310 }
311
312 if (Char == '?') {
313 return UrlParserQueryStart;
314 }
315
316 if (Char == '#') {
317 return UrlParserFragmentStart;
318 }
319
320 return UrlParserAuthority;
321
322 case UrlParserPath:
323 if (Char == '?') {
324 return UrlParserQueryStart;
325 }
326
327 if (Char == '#') {
328 return UrlParserFragmentStart;
329 }
330
331 break;
332
333 case UrlParserQuery:
334 case UrlParserQueryStart:
335 if (Char == '#') {
336 return UrlParserFragmentStart;
337 }
338
339 return UrlParserQuery;
340
341 case UrlParserFragmentStart:
342 return UrlParserFragment;
343
344 default:
345 break;
346 }
347
348 return State;
349}
350
369EFIAPI
371 IN CHAR8 *Url,
372 IN UINT32 Length,
373 IN BOOLEAN IsConnectMethod,
374 OUT VOID **UrlParser
375 )
376{
377 HTTP_URL_PARSE_STATE State;
378 CHAR8 *Char;
379 UINT32 Field;
380 UINT32 OldField;
381 BOOLEAN FoundAt;
382 EFI_STATUS Status;
383 HTTP_URL_PARSER *Parser;
384
385 Parser = NULL;
386
387 if ((Url == NULL) || (Length == 0) || (UrlParser == NULL)) {
388 return EFI_INVALID_PARAMETER;
389 }
390
391 Parser = AllocateZeroPool (sizeof (HTTP_URL_PARSER));
392 if (Parser == NULL) {
393 return EFI_OUT_OF_RESOURCES;
394 }
395
396 if (IsConnectMethod) {
397 //
398 // According to RFC 2616, the authority form is only used by the CONNECT method.
399 //
400 State = UrlParserAuthority;
401 } else {
402 State = UrlParserUrlStart;
403 }
404
405 Field = HTTP_URI_FIELD_MAX;
406 OldField = Field;
407 FoundAt = FALSE;
408 for (Char = Url; Char < Url + Length; Char++) {
409 //
410 // Update state machine according to next char.
411 //
412 State = NetHttpParseUrlChar (*Char, State);
413
414 switch (State) {
415 case UrlParserStateMax:
416 FreePool (Parser);
417 return EFI_INVALID_PARAMETER;
418
419 case UrlParserSchemeColon:
420 case UrlParserSchemeColonSlash:
421 case UrlParserSchemeColonSlashSlash:
422 case UrlParserQueryStart:
423 case UrlParserFragmentStart:
424 //
425 // Skip all the delimiting char: "://" "?" "@"
426 //
427 continue;
428
429 case UrlParserScheme:
430 Field = HTTP_URI_FIELD_SCHEME;
431 break;
432
433 case UrlParserAtInAuthority:
434 FoundAt = TRUE;
435 case UrlParserAuthority:
436 Field = HTTP_URI_FIELD_AUTHORITY;
437 break;
438
439 case UrlParserPath:
440 Field = HTTP_URI_FIELD_PATH;
441 break;
442
443 case UrlParserQuery:
444 Field = HTTP_URI_FIELD_QUERY;
445 break;
446
447 case UrlParserFragment:
448 Field = HTTP_URI_FIELD_FRAGMENT;
449 break;
450
451 default:
452 ASSERT (FALSE);
453 }
454
455 //
456 // Field not changed, count the length.
457 //
458 ASSERT (Field < HTTP_URI_FIELD_MAX);
459 if (Field == OldField) {
460 Parser->FieldData[Field].Length++;
461 continue;
462 }
463
464 //
465 // New field start
466 //
467 Parser->FieldBitMap |= BIT (Field);
468 Parser->FieldData[Field].Offset = (UINT32)(Char - Url);
469 Parser->FieldData[Field].Length = 1;
470 OldField = Field;
471 }
472
473 //
474 // If has authority component, continue to parse the username, host and port.
475 //
476 if ((Parser->FieldBitMap & BIT (HTTP_URI_FIELD_AUTHORITY)) != 0) {
477 Status = NetHttpParseAuthority (Url, FoundAt, Parser);
478 if (EFI_ERROR (Status)) {
479 FreePool (Parser);
480 return Status;
481 }
482 }
483
484 *UrlParser = Parser;
485 return EFI_SUCCESS;
486}
487
505EFIAPI
507 IN CHAR8 *Url,
508 IN VOID *UrlParser,
509 OUT CHAR8 **HostName
510 )
511{
512 CHAR8 *Name;
513 EFI_STATUS Status;
514 UINT32 ResultLength;
515 HTTP_URL_PARSER *Parser;
516
517 if ((Url == NULL) || (UrlParser == NULL) || (HostName == NULL)) {
518 return EFI_INVALID_PARAMETER;
519 }
520
521 Parser = (HTTP_URL_PARSER *)UrlParser;
522
523 if ((Parser->FieldBitMap & BIT (HTTP_URI_FIELD_HOST)) == 0) {
524 return EFI_NOT_FOUND;
525 }
526
527 Name = AllocatePool (Parser->FieldData[HTTP_URI_FIELD_HOST].Length + 1);
528 if (Name == NULL) {
529 return EFI_OUT_OF_RESOURCES;
530 }
531
532 Status = UriPercentDecode (
533 Url + Parser->FieldData[HTTP_URI_FIELD_HOST].Offset,
534 Parser->FieldData[HTTP_URI_FIELD_HOST].Length,
535 Name,
536 &ResultLength
537 );
538 if (EFI_ERROR (Status)) {
539 FreePool (Name);
540 return Status;
541 }
542
543 Name[ResultLength] = '\0';
544 *HostName = Name;
545 return EFI_SUCCESS;
546}
547
564EFIAPI
566 IN CHAR8 *Url,
567 IN VOID *UrlParser,
568 OUT EFI_IPv4_ADDRESS *Ip4Address
569 )
570{
571 CHAR8 *Ip4String;
572 EFI_STATUS Status;
573 UINT32 ResultLength;
574 HTTP_URL_PARSER *Parser;
575
576 if ((Url == NULL) || (UrlParser == NULL) || (Ip4Address == NULL)) {
577 return EFI_INVALID_PARAMETER;
578 }
579
580 Parser = (HTTP_URL_PARSER *)UrlParser;
581
582 if ((Parser->FieldBitMap & BIT (HTTP_URI_FIELD_HOST)) == 0) {
583 return EFI_NOT_FOUND;
584 }
585
586 Ip4String = AllocatePool (Parser->FieldData[HTTP_URI_FIELD_HOST].Length + 1);
587 if (Ip4String == NULL) {
588 return EFI_OUT_OF_RESOURCES;
589 }
590
591 Status = UriPercentDecode (
592 Url + Parser->FieldData[HTTP_URI_FIELD_HOST].Offset,
593 Parser->FieldData[HTTP_URI_FIELD_HOST].Length,
594 Ip4String,
595 &ResultLength
596 );
597 if (EFI_ERROR (Status)) {
598 FreePool (Ip4String);
599 return Status;
600 }
601
602 Ip4String[ResultLength] = '\0';
603 Status = NetLibAsciiStrToIp4 (Ip4String, Ip4Address);
604 FreePool (Ip4String);
605
606 return Status;
607}
608
625EFIAPI
627 IN CHAR8 *Url,
628 IN VOID *UrlParser,
629 OUT EFI_IPv6_ADDRESS *Ip6Address
630 )
631{
632 CHAR8 *Ip6String;
633 CHAR8 *Ptr;
634 UINT32 Length;
635 EFI_STATUS Status;
636 UINT32 ResultLength;
637 HTTP_URL_PARSER *Parser;
638
639 if ((Url == NULL) || (UrlParser == NULL) || (Ip6Address == NULL)) {
640 return EFI_INVALID_PARAMETER;
641 }
642
643 Parser = (HTTP_URL_PARSER *)UrlParser;
644
645 if ((Parser->FieldBitMap & BIT (HTTP_URI_FIELD_HOST)) == 0) {
646 return EFI_NOT_FOUND;
647 }
648
649 //
650 // IP-literal = "[" ( IPv6address / IPvFuture ) "]"
651 //
652 Length = Parser->FieldData[HTTP_URI_FIELD_HOST].Length;
653 if (Length < 2) {
654 return EFI_INVALID_PARAMETER;
655 }
656
657 Ptr = Url + Parser->FieldData[HTTP_URI_FIELD_HOST].Offset;
658 if ((Ptr[0] != '[') || (Ptr[Length - 1] != ']')) {
659 return EFI_INVALID_PARAMETER;
660 }
661
662 Ip6String = AllocatePool (Length);
663 if (Ip6String == NULL) {
664 return EFI_OUT_OF_RESOURCES;
665 }
666
667 Status = UriPercentDecode (
668 Ptr + 1,
669 Length - 2,
670 Ip6String,
671 &ResultLength
672 );
673 if (EFI_ERROR (Status)) {
674 FreePool (Ip6String);
675 return Status;
676 }
677
678 Ip6String[ResultLength] = '\0';
679 Status = NetLibAsciiStrToIp6 (Ip6String, Ip6Address);
680 FreePool (Ip6String);
681
682 return Status;
683}
684
701EFIAPI
703 IN CHAR8 *Url,
704 IN VOID *UrlParser,
705 OUT UINT16 *Port
706 )
707{
708 CHAR8 *PortString;
709 EFI_STATUS Status;
710 UINTN Index;
711 UINTN Data;
712 UINT32 ResultLength;
713 HTTP_URL_PARSER *Parser;
714
715 if ((Url == NULL) || (UrlParser == NULL) || (Port == NULL)) {
716 return EFI_INVALID_PARAMETER;
717 }
718
719 *Port = 0;
720 Index = 0;
721
722 Parser = (HTTP_URL_PARSER *)UrlParser;
723
724 if ((Parser->FieldBitMap & BIT (HTTP_URI_FIELD_PORT)) == 0) {
725 return EFI_NOT_FOUND;
726 }
727
728 PortString = AllocatePool (Parser->FieldData[HTTP_URI_FIELD_PORT].Length + 1);
729 if (PortString == NULL) {
730 return EFI_OUT_OF_RESOURCES;
731 }
732
733 Status = UriPercentDecode (
734 Url + Parser->FieldData[HTTP_URI_FIELD_PORT].Offset,
735 Parser->FieldData[HTTP_URI_FIELD_PORT].Length,
736 PortString,
737 &ResultLength
738 );
739 if (EFI_ERROR (Status)) {
740 goto ON_EXIT;
741 }
742
743 PortString[ResultLength] = '\0';
744
745 while (Index < ResultLength) {
746 if (!NET_IS_DIGIT (PortString[Index])) {
747 Status = EFI_INVALID_PARAMETER;
748 goto ON_EXIT;
749 }
750
751 Index++;
752 }
753
754 Status = AsciiStrDecimalToUintnS (Url + Parser->FieldData[HTTP_URI_FIELD_PORT].Offset, (CHAR8 **)NULL, &Data);
755
756 if (EFI_ERROR (Status) || (Data > HTTP_URI_PORT_MAX_NUM)) {
757 Status = EFI_INVALID_PARAMETER;
758 goto ON_EXIT;
759 }
760
761 *Port = (UINT16)Data;
762
763ON_EXIT:
764 FreePool (PortString);
765 return Status;
766}
767
785EFIAPI
787 IN CHAR8 *Url,
788 IN VOID *UrlParser,
789 OUT CHAR8 **Path
790 )
791{
792 CHAR8 *PathStr;
793 EFI_STATUS Status;
794 UINT32 ResultLength;
795 HTTP_URL_PARSER *Parser;
796
797 if ((Url == NULL) || (UrlParser == NULL) || (Path == NULL)) {
798 return EFI_INVALID_PARAMETER;
799 }
800
801 Parser = (HTTP_URL_PARSER *)UrlParser;
802
803 if ((Parser->FieldBitMap & BIT (HTTP_URI_FIELD_PATH)) == 0) {
804 return EFI_NOT_FOUND;
805 }
806
807 PathStr = AllocatePool (Parser->FieldData[HTTP_URI_FIELD_PATH].Length + 1);
808 if (PathStr == NULL) {
809 return EFI_OUT_OF_RESOURCES;
810 }
811
812 Status = UriPercentDecode (
813 Url + Parser->FieldData[HTTP_URI_FIELD_PATH].Offset,
814 Parser->FieldData[HTTP_URI_FIELD_PATH].Length,
815 PathStr,
816 &ResultLength
817 );
818 if (EFI_ERROR (Status)) {
819 FreePool (PathStr);
820 return Status;
821 }
822
823 PathStr[ResultLength] = '\0';
824 *Path = PathStr;
825 return EFI_SUCCESS;
826}
827
834VOID
835EFIAPI
837 IN VOID *UrlParser
838 )
839{
840 FreePool (UrlParser);
841}
842
854EFIAPI
856 IN UINTN HeaderCount,
857 IN EFI_HTTP_HEADER *Headers,
858 IN CHAR8 *FieldName
859 )
860{
861 UINTN Index;
862
863 if ((HeaderCount == 0) || (Headers == NULL) || (FieldName == NULL)) {
864 return NULL;
865 }
866
867 for (Index = 0; Index < HeaderCount; Index++) {
868 //
869 // Field names are case-insensitive (RFC 2616).
870 //
871 if (AsciiStriCmp (Headers[Index].FieldName, FieldName) == 0) {
872 return &Headers[Index];
873 }
874 }
875
876 return NULL;
877}
878
879typedef enum {
880 BodyParserBodyStart,
881 BodyParserBodyIdentity,
882 BodyParserChunkSizeStart,
883 BodyParserChunkSize,
884 BodyParserChunkSizeEndCR,
885 BodyParserChunkExtStart,
886 BodyParserChunkDataStart,
887 BodyParserChunkDataEnd,
888 BodyParserChunkDataEndCR,
889 BodyParserTrailer,
890 BodyParserLastCRLF,
891 BodyParserLastCRLFEnd,
892 BodyParserComplete,
893 BodyParserStateMax
894} HTTP_BODY_PARSE_STATE;
895
896typedef struct {
897 BOOLEAN IgnoreBody; // "MUST NOT" include a message-body
898 BOOLEAN IsChunked; // "chunked" transfer-coding.
899 BOOLEAN ContentLengthIsValid;
900 UINTN ContentLength; // Entity length (not the message-body length), invalid until ContentLengthIsValid is TRUE
901
903 VOID *Context;
904 UINTN ParsedBodyLength;
905 HTTP_BODY_PARSE_STATE State;
906 UINTN CurrentChunkSize;
907 UINTN CurrentChunkParsedSize;
909
918UINTN
920 IN CHAR8 Char
921 )
922{
923 if ((Char >= '0') && (Char <= '9')) {
924 return Char - '0';
925 }
926
927 return (10 + AsciiCharToUpper (Char) - 'A');
928}
929
943 IN UINTN HeaderCount,
944 IN EFI_HTTP_HEADER *Headers,
945 OUT UINTN *ContentLength
946 )
947{
948 EFI_HTTP_HEADER *Header;
949
950 Header = HttpFindHeader (HeaderCount, Headers, HTTP_HEADER_CONTENT_LENGTH);
951 if (Header == NULL) {
952 return EFI_NOT_FOUND;
953 }
954
955 return AsciiStrDecimalToUintnS (Header->FieldValue, (CHAR8 **)NULL, ContentLength);
956}
957
968BOOLEAN
970 IN UINTN HeaderCount,
971 IN EFI_HTTP_HEADER *Headers
972 )
973{
974 EFI_HTTP_HEADER *Header;
975
976 Header = HttpFindHeader (HeaderCount, Headers, HTTP_HEADER_TRANSFER_ENCODING);
977 if (Header == NULL) {
978 return FALSE;
979 }
980
981 if (AsciiStriCmp (Header->FieldValue, "identity") != 0) {
982 return TRUE;
983 }
984
985 return FALSE;
986}
987
997BOOLEAN
999 IN EFI_HTTP_METHOD Method,
1000 IN EFI_HTTP_STATUS_CODE StatusCode
1001 )
1002{
1003 //
1004 // RFC 2616:
1005 // All responses to the HEAD request method
1006 // MUST NOT include a message-body, even though the presence of entity-
1007 // header fields might lead one to believe they do. All 1xx
1008 // (informational), 204 (no content), and 304 (not modified) responses
1009 // MUST NOT include a message-body. All other responses do include a
1010 // message-body, although it MAY be of zero length.
1011 //
1012 if (Method == HttpMethodHead) {
1013 return TRUE;
1014 }
1015
1016 if ((StatusCode == HTTP_STATUS_100_CONTINUE) ||
1017 (StatusCode == HTTP_STATUS_101_SWITCHING_PROTOCOLS) ||
1018 (StatusCode == HTTP_STATUS_204_NO_CONTENT) ||
1019 (StatusCode == HTTP_STATUS_304_NOT_MODIFIED))
1020 {
1021 return TRUE;
1022 }
1023
1024 return FALSE;
1025}
1026
1049EFIAPI
1051 IN EFI_HTTP_METHOD Method,
1052 IN EFI_HTTP_STATUS_CODE StatusCode,
1053 IN UINTN HeaderCount,
1054 IN EFI_HTTP_HEADER *Headers,
1056 IN VOID *Context,
1057 OUT VOID **MsgParser
1058 )
1059{
1060 EFI_STATUS Status;
1061 HTTP_BODY_PARSER *Parser;
1062
1063 if ((HeaderCount != 0) && (Headers == NULL)) {
1064 return EFI_INVALID_PARAMETER;
1065 }
1066
1067 if (MsgParser == NULL) {
1068 return EFI_INVALID_PARAMETER;
1069 }
1070
1071 Parser = AllocateZeroPool (sizeof (HTTP_BODY_PARSER));
1072 if (Parser == NULL) {
1073 return EFI_OUT_OF_RESOURCES;
1074 }
1075
1076 Parser->State = BodyParserBodyStart;
1077
1078 //
1079 // Determine the message length according to RFC 2616.
1080 // 1. Check whether the message "MUST NOT" have a message-body.
1081 //
1082 Parser->IgnoreBody = HttpIoNoMessageBody (Method, StatusCode);
1083 //
1084 // 2. Check whether the message using "chunked" transfer-coding.
1085 //
1086 Parser->IsChunked = HttpIoIsChunked (HeaderCount, Headers);
1087 //
1088 // 3. Check whether the message has a Content-Length header field.
1089 //
1090 Status = HttpIoParseContentLengthHeader (HeaderCount, Headers, &Parser->ContentLength);
1091 if (!EFI_ERROR (Status)) {
1092 Parser->ContentLengthIsValid = TRUE;
1093 }
1094
1095 //
1096 // 4. Range header is not supported now, so we won't meet media type "multipart/byteranges".
1097 // 5. By server closing the connection
1098 //
1099
1100 //
1101 // Set state to skip body parser if the message shouldn't have a message body.
1102 //
1103 if (Parser->IgnoreBody) {
1104 Parser->State = BodyParserComplete;
1105 } else {
1106 Parser->Callback = Callback;
1107 Parser->Context = Context;
1108 }
1109
1110 *MsgParser = Parser;
1111 return EFI_SUCCESS;
1112}
1113
1130EFIAPI
1132 IN OUT VOID *MsgParser,
1133 IN UINTN BodyLength,
1134 IN CHAR8 *Body
1135 )
1136{
1137 CHAR8 *Char;
1138 UINTN RemainderLengthInThis;
1139 UINTN LengthForCallback;
1140 UINTN PortionLength;
1141 EFI_STATUS Status;
1142 HTTP_BODY_PARSER *Parser;
1143
1144 if ((BodyLength == 0) || (Body == NULL)) {
1145 return EFI_INVALID_PARAMETER;
1146 }
1147
1148 if (MsgParser == NULL) {
1149 return EFI_INVALID_PARAMETER;
1150 }
1151
1152 Parser = (HTTP_BODY_PARSER *)MsgParser;
1153
1154 if (Parser->IgnoreBody) {
1155 Parser->State = BodyParserComplete;
1156 if (Parser->Callback != NULL) {
1157 Status = Parser->Callback (
1158 BodyParseEventOnComplete,
1159 Body,
1160 0,
1161 Parser->Context
1162 );
1163 if (EFI_ERROR (Status)) {
1164 return Status;
1165 }
1166 }
1167
1168 return EFI_SUCCESS;
1169 }
1170
1171 if (Parser->State == BodyParserBodyStart) {
1172 Parser->ParsedBodyLength = 0;
1173 if (Parser->IsChunked) {
1174 Parser->State = BodyParserChunkSizeStart;
1175 } else {
1176 Parser->State = BodyParserBodyIdentity;
1177 }
1178 }
1179
1180 //
1181 // The message body might be truncated in anywhere, so we need to parse is byte-by-byte.
1182 //
1183 for (Char = Body; Char < Body + BodyLength; ) {
1184 switch (Parser->State) {
1185 case BodyParserStateMax:
1186 return EFI_ABORTED;
1187
1188 case BodyParserBodyIdentity:
1189 //
1190 // Identity transfer-coding, just notify user to save the body data.
1191 //
1192 PortionLength = MIN (
1193 BodyLength,
1194 Parser->ContentLength - Parser->ParsedBodyLength
1195 );
1196 if (PortionLength == 0) {
1197 //
1198 // Got BodyLength, but no ContentLength. Use BodyLength.
1199 //
1200 PortionLength = BodyLength;
1201 Parser->ContentLength = PortionLength;
1202 }
1203
1204 if (Parser->Callback != NULL) {
1205 Status = Parser->Callback (
1206 BodyParseEventOnData,
1207 Char,
1208 PortionLength,
1209 Parser->Context
1210 );
1211 if (EFI_ERROR (Status)) {
1212 return Status;
1213 }
1214 }
1215
1216 Char += PortionLength;
1217 Parser->ParsedBodyLength += PortionLength;
1218 if (Parser->ParsedBodyLength == Parser->ContentLength) {
1219 Parser->State = BodyParserComplete;
1220 if (Parser->Callback != NULL) {
1221 Status = Parser->Callback (
1222 BodyParseEventOnComplete,
1223 Char,
1224 0,
1225 Parser->Context
1226 );
1227 if (EFI_ERROR (Status)) {
1228 return Status;
1229 }
1230 }
1231 }
1232
1233 break;
1234
1235 case BodyParserChunkSizeStart:
1236 //
1237 // First byte of chunk-size, the chunk-size might be truncated.
1238 //
1239 Parser->CurrentChunkSize = 0;
1240 Parser->State = BodyParserChunkSize;
1241 case BodyParserChunkSize:
1242 if (!NET_IS_HEX_CHAR (*Char)) {
1243 if (*Char == ';') {
1244 Parser->State = BodyParserChunkExtStart;
1245 Char++;
1246 } else if (*Char == '\r') {
1247 Parser->State = BodyParserChunkSizeEndCR;
1248 Char++;
1249 } else {
1250 Parser->State = BodyParserStateMax;
1251 }
1252
1253 break;
1254 }
1255
1256 if (Parser->CurrentChunkSize > (((~((UINTN)0)) - 16) / 16)) {
1257 return EFI_INVALID_PARAMETER;
1258 }
1259
1260 Parser->CurrentChunkSize = Parser->CurrentChunkSize * 16 + HttpIoHexCharToUintn (*Char);
1261 Char++;
1262 break;
1263
1264 case BodyParserChunkExtStart:
1265 //
1266 // Ignore all the chunk extensions.
1267 //
1268 if (*Char == '\r') {
1269 Parser->State = BodyParserChunkSizeEndCR;
1270 }
1271
1272 Char++;
1273 break;
1274
1275 case BodyParserChunkSizeEndCR:
1276 if (*Char != '\n') {
1277 Parser->State = BodyParserStateMax;
1278 break;
1279 }
1280
1281 Char++;
1282 if (Parser->CurrentChunkSize == 0) {
1283 //
1284 // The last chunk has been parsed and now assumed the state
1285 // of HttpBodyParse is ParserLastCRLF. So it need to decide
1286 // whether the rest message is trailer or last CRLF in the next round.
1287 //
1288 Parser->ContentLengthIsValid = TRUE;
1289 Parser->State = BodyParserLastCRLF;
1290 break;
1291 }
1292
1293 Parser->State = BodyParserChunkDataStart;
1294 Parser->CurrentChunkParsedSize = 0;
1295 break;
1296
1297 case BodyParserLastCRLF:
1298 //
1299 // Judge the byte is belong to the Last CRLF or trailer, and then
1300 // configure the state of HttpBodyParse to corresponding state.
1301 //
1302 if (*Char == '\r') {
1303 Char++;
1304 Parser->State = BodyParserLastCRLFEnd;
1305 break;
1306 } else {
1307 Parser->State = BodyParserTrailer;
1308 break;
1309 }
1310
1311 case BodyParserLastCRLFEnd:
1312 if (*Char == '\n') {
1313 Parser->State = BodyParserComplete;
1314 Char++;
1315 if (Parser->Callback != NULL) {
1316 Status = Parser->Callback (
1317 BodyParseEventOnComplete,
1318 Char,
1319 0,
1320 Parser->Context
1321 );
1322 if (EFI_ERROR (Status)) {
1323 return Status;
1324 }
1325 }
1326
1327 break;
1328 } else {
1329 Parser->State = BodyParserStateMax;
1330 break;
1331 }
1332
1333 case BodyParserTrailer:
1334 if (*Char == '\r') {
1335 Parser->State = BodyParserChunkSizeEndCR;
1336 }
1337
1338 Char++;
1339 break;
1340
1341 case BodyParserChunkDataStart:
1342 //
1343 // First byte of chunk-data, the chunk data also might be truncated.
1344 //
1345 RemainderLengthInThis = BodyLength - (Char - Body);
1346 LengthForCallback = MIN (Parser->CurrentChunkSize - Parser->CurrentChunkParsedSize, RemainderLengthInThis);
1347 if (Parser->Callback != NULL) {
1348 Status = Parser->Callback (
1349 BodyParseEventOnData,
1350 Char,
1351 LengthForCallback,
1352 Parser->Context
1353 );
1354 if (EFI_ERROR (Status)) {
1355 return Status;
1356 }
1357 }
1358
1359 Char += LengthForCallback;
1360 Parser->ContentLength += LengthForCallback;
1361 Parser->CurrentChunkParsedSize += LengthForCallback;
1362 if (Parser->CurrentChunkParsedSize == Parser->CurrentChunkSize) {
1363 Parser->State = BodyParserChunkDataEnd;
1364 }
1365
1366 break;
1367
1368 case BodyParserChunkDataEnd:
1369 if (*Char == '\r') {
1370 Parser->State = BodyParserChunkDataEndCR;
1371 } else {
1372 Parser->State = BodyParserStateMax;
1373 }
1374
1375 Char++;
1376 break;
1377
1378 case BodyParserChunkDataEndCR:
1379 if (*Char != '\n') {
1380 Parser->State = BodyParserStateMax;
1381 break;
1382 }
1383
1384 Char++;
1385 Parser->State = BodyParserChunkSizeStart;
1386 break;
1387
1388 default:
1389 break;
1390 }
1391 }
1392
1393 if (Parser->State == BodyParserStateMax) {
1394 return EFI_ABORTED;
1395 }
1396
1397 return EFI_SUCCESS;
1398}
1399
1409BOOLEAN
1410EFIAPI
1412 IN VOID *MsgParser
1413 )
1414{
1415 HTTP_BODY_PARSER *Parser;
1416
1417 if (MsgParser == NULL) {
1418 return FALSE;
1419 }
1420
1421 Parser = (HTTP_BODY_PARSER *)MsgParser;
1422
1423 if (Parser->State == BodyParserComplete) {
1424 return TRUE;
1425 }
1426
1427 return FALSE;
1428}
1429
1444EFIAPI
1446 IN VOID *MsgParser,
1447 OUT UINTN *ContentLength
1448 )
1449{
1450 HTTP_BODY_PARSER *Parser;
1451
1452 if ((MsgParser == NULL) || (ContentLength == NULL)) {
1453 return EFI_INVALID_PARAMETER;
1454 }
1455
1456 Parser = (HTTP_BODY_PARSER *)MsgParser;
1457
1458 if (!Parser->ContentLengthIsValid) {
1459 return EFI_NOT_READY;
1460 }
1461
1462 *ContentLength = Parser->ContentLength;
1463 return EFI_SUCCESS;
1464}
1465
1472VOID
1473EFIAPI
1475 IN VOID *MsgParser
1476 )
1477{
1478 FreePool (MsgParser);
1479}
1480
1492CHAR8 *
1494 IN CONST CHAR8 *String,
1495 IN CHAR8 Separator
1496 )
1497{
1498 CONST CHAR8 *Token;
1499
1500 Token = String;
1501 while (TRUE) {
1502 if (*Token == 0) {
1503 return NULL;
1504 }
1505
1506 if (*Token == Separator) {
1507 return (CHAR8 *)(Token + 1);
1508 }
1509
1510 Token++;
1511 }
1512}
1513
1528EFIAPI
1530 IN OUT EFI_HTTP_HEADER *HttpHeader,
1531 IN CONST CHAR8 *FieldName,
1532 IN CONST CHAR8 *FieldValue
1533 )
1534{
1535 UINTN FieldNameSize;
1536 UINTN FieldValueSize;
1537
1538 if ((HttpHeader == NULL) || (FieldName == NULL) || (FieldValue == NULL)) {
1539 return EFI_INVALID_PARAMETER;
1540 }
1541
1542 if (HttpHeader->FieldName != NULL) {
1543 FreePool (HttpHeader->FieldName);
1544 }
1545
1546 if (HttpHeader->FieldValue != NULL) {
1547 FreePool (HttpHeader->FieldValue);
1548 }
1549
1550 FieldNameSize = AsciiStrSize (FieldName);
1551 HttpHeader->FieldName = AllocateZeroPool (FieldNameSize);
1552 if (HttpHeader->FieldName == NULL) {
1553 return EFI_OUT_OF_RESOURCES;
1554 }
1555
1556 CopyMem (HttpHeader->FieldName, FieldName, FieldNameSize);
1557 HttpHeader->FieldName[FieldNameSize - 1] = 0;
1558
1559 FieldValueSize = AsciiStrSize (FieldValue);
1560 HttpHeader->FieldValue = AllocateZeroPool (FieldValueSize);
1561 if (HttpHeader->FieldValue == NULL) {
1562 FreePool (HttpHeader->FieldName);
1563 return EFI_OUT_OF_RESOURCES;
1564 }
1565
1566 CopyMem (HttpHeader->FieldValue, FieldValue, FieldValueSize);
1567 HttpHeader->FieldValue[FieldValueSize - 1] = 0;
1568
1569 return EFI_SUCCESS;
1570}
1571
1583CHAR8 *
1584EFIAPI
1586 IN CHAR8 *String,
1587 OUT CHAR8 **FieldName,
1588 OUT CHAR8 **FieldValue
1589 )
1590{
1591 CHAR8 *FieldNameStr;
1592 CHAR8 *FieldValueStr;
1593 CHAR8 *StrPtr;
1594 CHAR8 *EndofHeader;
1595
1596 if ((String == NULL) || (FieldName == NULL) || (FieldValue == NULL)) {
1597 return NULL;
1598 }
1599
1600 *FieldName = NULL;
1601 *FieldValue = NULL;
1602 FieldNameStr = NULL;
1603 FieldValueStr = NULL;
1604 StrPtr = NULL;
1605 EndofHeader = NULL;
1606
1607 //
1608 // Check whether the raw HTTP header string is valid or not.
1609 //
1610 EndofHeader = AsciiStrStr (String, "\r\n\r\n");
1611 if (EndofHeader == NULL) {
1612 return NULL;
1613 }
1614
1615 //
1616 // Each header field consists of a name followed by a colon (":") and the field value.
1617 // The field value MAY be preceded by any amount of LWS, though a single SP is preferred.
1618 //
1619 // message-header = field-name ":" [ field-value ]
1620 // field-name = token
1621 // field-value = *( field-content | LWS )
1622 //
1623 // Note: "*(element)" allows any number element, including zero; "1*(element)" requires at least one element.
1624 // [element] means element is optional.
1625 // LWS = [CRLF] 1*(SP|HT), it can be ' ' or '\t' or '\r\n ' or '\r\n\t'.
1626 // CRLF = '\r\n'.
1627 // SP = ' '.
1628 // HT = '\t' (Tab).
1629 //
1630 FieldNameStr = String;
1631 FieldValueStr = AsciiStrGetNextToken (FieldNameStr, ':');
1632 if (FieldValueStr == NULL) {
1633 return NULL;
1634 }
1635
1636 //
1637 // Replace ':' with 0, then FieldName has been retrived from String.
1638 //
1639 *(FieldValueStr - 1) = 0;
1640
1641 //
1642 // Handle FieldValueStr, skip all the preceded LWS.
1643 //
1644 while (TRUE) {
1645 if ((*FieldValueStr == ' ') || (*FieldValueStr == '\t')) {
1646 //
1647 // Boundary condition check.
1648 //
1649 if ((UINTN)EndofHeader - (UINTN)FieldValueStr < 1) {
1650 //
1651 // Wrong String format!
1652 //
1653 return NULL;
1654 }
1655
1656 FieldValueStr++;
1657 } else if (*FieldValueStr == '\r') {
1658 //
1659 // Boundary condition check.
1660 //
1661 if ((UINTN)EndofHeader - (UINTN)FieldValueStr < 3) {
1662 //
1663 // No more preceded LWS, so break here.
1664 //
1665 break;
1666 }
1667
1668 if (*(FieldValueStr + 1) == '\n' ) {
1669 if ((*(FieldValueStr + 2) == ' ') || (*(FieldValueStr + 2) == '\t')) {
1670 FieldValueStr = FieldValueStr + 3;
1671 } else {
1672 //
1673 // No more preceded LWS, so break here.
1674 //
1675 break;
1676 }
1677 } else {
1678 //
1679 // Wrong String format!
1680 //
1681 return NULL;
1682 }
1683 } else {
1684 //
1685 // No more preceded LWS, so break here.
1686 //
1687 break;
1688 }
1689 }
1690
1691 StrPtr = FieldValueStr;
1692 do {
1693 //
1694 // Handle the LWS within the field value.
1695 //
1696 StrPtr = AsciiStrGetNextToken (StrPtr, '\r');
1697 if ((StrPtr == NULL) || (*StrPtr != '\n')) {
1698 //
1699 // Wrong String format!
1700 //
1701 return NULL;
1702 }
1703
1704 StrPtr++;
1705 } while (*StrPtr == ' ' || *StrPtr == '\t');
1706
1707 //
1708 // Replace '\r' with 0
1709 //
1710 *(StrPtr - 2) = 0;
1711
1712 //
1713 // Get FieldName and FieldValue.
1714 //
1715 *FieldName = FieldNameStr;
1716 *FieldValue = FieldValueStr;
1717
1718 return StrPtr;
1719}
1720
1728VOID
1729EFIAPI
1731 IN EFI_HTTP_HEADER *HeaderFields,
1732 IN UINTN FieldCount
1733 )
1734{
1735 UINTN Index;
1736
1737 if (HeaderFields != NULL) {
1738 for (Index = 0; Index < FieldCount; Index++) {
1739 if (HeaderFields[Index].FieldName != NULL) {
1740 FreePool (HeaderFields[Index].FieldName);
1741 }
1742
1743 if (HeaderFields[Index].FieldValue != NULL) {
1744 FreePool (HeaderFields[Index].FieldValue);
1745 }
1746 }
1747
1748 FreePool (HeaderFields);
1749 }
1750}
1751
1774EFIAPI
1776 IN CONST EFI_HTTP_MESSAGE *Message,
1777 IN CONST CHAR8 *Url,
1778 OUT CHAR8 **RequestMsg,
1779 OUT UINTN *RequestMsgSize
1780 )
1781{
1782 EFI_STATUS Status;
1783 UINTN StrLength;
1784 CHAR8 *RequestPtr;
1785 UINTN HttpHdrSize;
1786 UINTN MsgSize;
1787 BOOLEAN Success;
1788 VOID *HttpHdr;
1789 EFI_HTTP_HEADER **AppendList;
1790 UINTN Index;
1791 EFI_HTTP_UTILITIES_PROTOCOL *HttpUtilitiesProtocol;
1792
1793 Status = EFI_SUCCESS;
1794 HttpHdrSize = 0;
1795 MsgSize = 0;
1796 Success = FALSE;
1797 HttpHdr = NULL;
1798 AppendList = NULL;
1799 HttpUtilitiesProtocol = NULL;
1800
1801 //
1802 // 1. If we have a Request, we cannot have a NULL Url
1803 // 2. If we have a Request, HeaderCount can not be non-zero
1804 // 3. If we do not have a Request, HeaderCount should be zero
1805 // 4. If we do not have Request and Headers, we need at least a message-body
1806 //
1807 if (((Message == NULL) || (RequestMsg == NULL) || (RequestMsgSize == NULL)) ||
1808 ((Message->Data.Request != NULL) && (Url == NULL)) ||
1809 ((Message->Data.Request != NULL) && (Message->HeaderCount == 0)) ||
1810 ((Message->Data.Request == NULL) && (Message->HeaderCount != 0)) ||
1811 ((Message->Data.Request == NULL) && (Message->HeaderCount == 0) && (Message->BodyLength == 0)))
1812 {
1813 return EFI_INVALID_PARAMETER;
1814 }
1815
1816 if (Message->HeaderCount != 0) {
1817 //
1818 // Locate the HTTP_UTILITIES protocol.
1819 //
1820 Status = gBS->LocateProtocol (
1821 &gEfiHttpUtilitiesProtocolGuid,
1822 NULL,
1823 (VOID **)&HttpUtilitiesProtocol
1824 );
1825
1826 if (EFI_ERROR (Status)) {
1827 DEBUG ((DEBUG_ERROR, "Failed to locate Http Utilities protocol. Status = %r.\n", Status));
1828 return Status;
1829 }
1830
1831 //
1832 // Build AppendList to send into HttpUtilitiesBuild
1833 //
1834 AppendList = AllocateZeroPool (sizeof (EFI_HTTP_HEADER *) * (Message->HeaderCount));
1835 if (AppendList == NULL) {
1836 return EFI_OUT_OF_RESOURCES;
1837 }
1838
1839 for (Index = 0; Index < Message->HeaderCount; Index++) {
1840 AppendList[Index] = &Message->Headers[Index];
1841 }
1842
1843 //
1844 // Build raw HTTP Headers
1845 //
1846 Status = HttpUtilitiesProtocol->Build (
1847 HttpUtilitiesProtocol,
1848 0,
1849 NULL,
1850 0,
1851 NULL,
1852 Message->HeaderCount,
1853 AppendList,
1854 &HttpHdrSize,
1855 &HttpHdr
1856 );
1857
1858 FreePool (AppendList);
1859
1860 if (EFI_ERROR (Status) || (HttpHdr == NULL)) {
1861 return Status;
1862 }
1863 }
1864
1865 //
1866 // If we have headers to be sent, account for it.
1867 //
1868 if (Message->HeaderCount != 0) {
1869 MsgSize = HttpHdrSize;
1870 }
1871
1872 //
1873 // If we have a request line, account for the fields.
1874 //
1875 if (Message->Data.Request != NULL) {
1876 MsgSize += HTTP_METHOD_MAXIMUM_LEN + AsciiStrLen (HTTP_VERSION_CRLF_STR) + AsciiStrLen (Url);
1877 }
1878
1879 //
1880 // If we have a message body to be sent, account for it.
1881 //
1882 MsgSize += Message->BodyLength;
1883
1884 //
1885 // memory for the string that needs to be sent to TCP
1886 //
1887 *RequestMsg = NULL;
1888 *RequestMsg = AllocateZeroPool (MsgSize);
1889 if (*RequestMsg == NULL) {
1890 Status = EFI_OUT_OF_RESOURCES;
1891 goto Exit;
1892 }
1893
1894 RequestPtr = *RequestMsg;
1895 //
1896 // Construct header request
1897 //
1898 if (Message->Data.Request != NULL) {
1899 switch (Message->Data.Request->Method) {
1900 case HttpMethodGet:
1901 StrLength = sizeof (HTTP_METHOD_GET) - 1;
1902 CopyMem (RequestPtr, HTTP_METHOD_GET, StrLength);
1903 RequestPtr += StrLength;
1904 break;
1905 case HttpMethodPut:
1906 StrLength = sizeof (HTTP_METHOD_PUT) - 1;
1907 CopyMem (RequestPtr, HTTP_METHOD_PUT, StrLength);
1908 RequestPtr += StrLength;
1909 break;
1910 case HttpMethodPatch:
1911 StrLength = sizeof (HTTP_METHOD_PATCH) - 1;
1912 CopyMem (RequestPtr, HTTP_METHOD_PATCH, StrLength);
1913 RequestPtr += StrLength;
1914 break;
1915 case HttpMethodPost:
1916 StrLength = sizeof (HTTP_METHOD_POST) - 1;
1917 CopyMem (RequestPtr, HTTP_METHOD_POST, StrLength);
1918 RequestPtr += StrLength;
1919 break;
1920 case HttpMethodHead:
1921 StrLength = sizeof (HTTP_METHOD_HEAD) - 1;
1922 CopyMem (RequestPtr, HTTP_METHOD_HEAD, StrLength);
1923 RequestPtr += StrLength;
1924 break;
1925 case HttpMethodDelete:
1926 StrLength = sizeof (HTTP_METHOD_DELETE) - 1;
1927 CopyMem (RequestPtr, HTTP_METHOD_DELETE, StrLength);
1928 RequestPtr += StrLength;
1929 break;
1930 case HttpMethodConnect:
1931 StrLength = sizeof (HTTP_METHOD_CONNECT) - 1;
1932 CopyMem (RequestPtr, HTTP_METHOD_CONNECT, StrLength);
1933 RequestPtr += StrLength;
1934 break;
1935 default:
1936 ASSERT (FALSE);
1937 Status = EFI_INVALID_PARAMETER;
1938 goto Exit;
1939 }
1940
1941 StrLength = AsciiStrLen (EMPTY_SPACE);
1942 CopyMem (RequestPtr, EMPTY_SPACE, StrLength);
1943 RequestPtr += StrLength;
1944
1945 StrLength = AsciiStrLen (Url);
1946 CopyMem (RequestPtr, Url, StrLength);
1947 RequestPtr += StrLength;
1948
1949 StrLength = sizeof (HTTP_VERSION_CRLF_STR) - 1;
1950 CopyMem (RequestPtr, HTTP_VERSION_CRLF_STR, StrLength);
1951 RequestPtr += StrLength;
1952
1953 if (HttpHdr != NULL) {
1954 //
1955 // Construct header
1956 //
1957 CopyMem (RequestPtr, HttpHdr, HttpHdrSize);
1958 RequestPtr += HttpHdrSize;
1959 }
1960 }
1961
1962 //
1963 // Construct body
1964 //
1965 if (Message->Body != NULL) {
1966 CopyMem (RequestPtr, Message->Body, Message->BodyLength);
1967 RequestPtr += Message->BodyLength;
1968 }
1969
1970 //
1971 // Done
1972 //
1973 (*RequestMsgSize) = (UINTN)(RequestPtr) - (UINTN)(*RequestMsg);
1974 Success = TRUE;
1975
1976Exit:
1977
1978 if (!Success) {
1979 if (*RequestMsg != NULL) {
1980 FreePool (*RequestMsg);
1981 }
1982
1983 *RequestMsg = NULL;
1984 return Status;
1985 }
1986
1987 if (HttpHdr != NULL) {
1988 FreePool (HttpHdr);
1989 }
1990
1991 return EFI_SUCCESS;
1992}
1993
2007EFIAPI
2009 IN UINTN StatusCode
2010 )
2011{
2012 switch (StatusCode) {
2013 case 100:
2014 return HTTP_STATUS_100_CONTINUE;
2015 case 101:
2016 return HTTP_STATUS_101_SWITCHING_PROTOCOLS;
2017 case 200:
2018 return HTTP_STATUS_200_OK;
2019 case 201:
2020 return HTTP_STATUS_201_CREATED;
2021 case 202:
2022 return HTTP_STATUS_202_ACCEPTED;
2023 case 203:
2024 return HTTP_STATUS_203_NON_AUTHORITATIVE_INFORMATION;
2025 case 204:
2026 return HTTP_STATUS_204_NO_CONTENT;
2027 case 205:
2028 return HTTP_STATUS_205_RESET_CONTENT;
2029 case 206:
2030 return HTTP_STATUS_206_PARTIAL_CONTENT;
2031 case 300:
2032 return HTTP_STATUS_300_MULTIPLE_CHOICES;
2033 case 301:
2034 return HTTP_STATUS_301_MOVED_PERMANENTLY;
2035 case 302:
2036 return HTTP_STATUS_302_FOUND;
2037 case 303:
2038 return HTTP_STATUS_303_SEE_OTHER;
2039 case 304:
2040 return HTTP_STATUS_304_NOT_MODIFIED;
2041 case 305:
2042 return HTTP_STATUS_305_USE_PROXY;
2043 case 307:
2044 return HTTP_STATUS_307_TEMPORARY_REDIRECT;
2045 case 308:
2046 return HTTP_STATUS_308_PERMANENT_REDIRECT;
2047 case 400:
2048 return HTTP_STATUS_400_BAD_REQUEST;
2049 case 401:
2050 return HTTP_STATUS_401_UNAUTHORIZED;
2051 case 402:
2052 return HTTP_STATUS_402_PAYMENT_REQUIRED;
2053 case 403:
2054 return HTTP_STATUS_403_FORBIDDEN;
2055 case 404:
2056 return HTTP_STATUS_404_NOT_FOUND;
2057 case 405:
2058 return HTTP_STATUS_405_METHOD_NOT_ALLOWED;
2059 case 406:
2060 return HTTP_STATUS_406_NOT_ACCEPTABLE;
2061 case 407:
2062 return HTTP_STATUS_407_PROXY_AUTHENTICATION_REQUIRED;
2063 case 408:
2064 return HTTP_STATUS_408_REQUEST_TIME_OUT;
2065 case 409:
2066 return HTTP_STATUS_409_CONFLICT;
2067 case 410:
2068 return HTTP_STATUS_410_GONE;
2069 case 411:
2070 return HTTP_STATUS_411_LENGTH_REQUIRED;
2071 case 412:
2072 return HTTP_STATUS_412_PRECONDITION_FAILED;
2073 case 413:
2074 return HTTP_STATUS_413_REQUEST_ENTITY_TOO_LARGE;
2075 case 414:
2076 return HTTP_STATUS_414_REQUEST_URI_TOO_LARGE;
2077 case 415:
2078 return HTTP_STATUS_415_UNSUPPORTED_MEDIA_TYPE;
2079 case 416:
2080 return HTTP_STATUS_416_REQUESTED_RANGE_NOT_SATISFIED;
2081 case 417:
2082 return HTTP_STATUS_417_EXPECTATION_FAILED;
2083 case 429:
2084 return HTTP_STATUS_429_TOO_MANY_REQUESTS;
2085 case 500:
2086 return HTTP_STATUS_500_INTERNAL_SERVER_ERROR;
2087 case 501:
2088 return HTTP_STATUS_501_NOT_IMPLEMENTED;
2089 case 502:
2090 return HTTP_STATUS_502_BAD_GATEWAY;
2091 case 503:
2092 return HTTP_STATUS_503_SERVICE_UNAVAILABLE;
2093 case 504:
2094 return HTTP_STATUS_504_GATEWAY_TIME_OUT;
2095 case 505:
2096 return HTTP_STATUS_505_HTTP_VERSION_NOT_SUPPORTED;
2097
2098 default:
2099 return HTTP_STATUS_UNSUPPORTED_STATUS;
2100 }
2101}
2102
2114BOOLEAN
2115EFIAPI
2117 IN CHAR8 *DeleteList[],
2118 IN UINTN DeleteCount,
2119 IN CHAR8 *FieldName
2120 )
2121{
2122 UINTN Index;
2123
2124 if (FieldName == NULL) {
2125 return FALSE;
2126 }
2127
2128 for (Index = 0; Index < DeleteCount; Index++) {
2129 if (DeleteList[Index] == NULL) {
2130 continue;
2131 }
2132
2133 if (AsciiStrCmp (FieldName, DeleteList[Index]) == 0) {
2134 return FALSE;
2135 }
2136 }
2137
2138 return TRUE;
2139}
2140
2151 UINTN MaxHeaderCount
2152 )
2153{
2154 HTTP_IO_HEADER *HttpIoHeader;
2155
2156 if (MaxHeaderCount == 0) {
2157 return NULL;
2158 }
2159
2160 HttpIoHeader = AllocateZeroPool (sizeof (HTTP_IO_HEADER) + MaxHeaderCount * sizeof (EFI_HTTP_HEADER));
2161 if (HttpIoHeader == NULL) {
2162 return NULL;
2163 }
2164
2165 HttpIoHeader->MaxHeaderCount = MaxHeaderCount;
2166 HttpIoHeader->Headers = (EFI_HTTP_HEADER *)(HttpIoHeader + 1);
2167
2168 return HttpIoHeader;
2169}
2170
2177VOID
2179 IN HTTP_IO_HEADER *HttpIoHeader
2180 )
2181{
2182 UINTN Index;
2183
2184 if (HttpIoHeader != NULL) {
2185 if (HttpIoHeader->HeaderCount != 0) {
2186 for (Index = 0; Index < HttpIoHeader->HeaderCount; Index++) {
2187 FreePool (HttpIoHeader->Headers[Index].FieldName);
2188 ZeroMem (HttpIoHeader->Headers[Index].FieldValue, AsciiStrSize (HttpIoHeader->Headers[Index].FieldValue));
2189 FreePool (HttpIoHeader->Headers[Index].FieldValue);
2190 }
2191 }
2192
2193 FreePool (HttpIoHeader);
2194 }
2195}
2196
2212 IN HTTP_IO_HEADER *HttpIoHeader,
2213 IN CHAR8 *FieldName,
2214 IN CHAR8 *FieldValue
2215 )
2216{
2217 EFI_HTTP_HEADER *Header;
2218 UINTN StrSize;
2219 CHAR8 *NewFieldValue;
2220
2221 if ((HttpIoHeader == NULL) || (FieldName == NULL) || (FieldValue == NULL)) {
2222 return EFI_INVALID_PARAMETER;
2223 }
2224
2225 Header = HttpFindHeader (HttpIoHeader->HeaderCount, HttpIoHeader->Headers, FieldName);
2226 if (Header == NULL) {
2227 //
2228 // Add a new header.
2229 //
2230 if (HttpIoHeader->HeaderCount >= HttpIoHeader->MaxHeaderCount) {
2231 return EFI_OUT_OF_RESOURCES;
2232 }
2233
2234 Header = &HttpIoHeader->Headers[HttpIoHeader->HeaderCount];
2235
2236 StrSize = AsciiStrSize (FieldName);
2237 Header->FieldName = AllocatePool (StrSize);
2238 if (Header->FieldName == NULL) {
2239 return EFI_OUT_OF_RESOURCES;
2240 }
2241
2242 CopyMem (Header->FieldName, FieldName, StrSize);
2243 Header->FieldName[StrSize -1] = '\0';
2244
2245 StrSize = AsciiStrSize (FieldValue);
2246 Header->FieldValue = AllocatePool (StrSize);
2247 if (Header->FieldValue == NULL) {
2248 FreePool (Header->FieldName);
2249 return EFI_OUT_OF_RESOURCES;
2250 }
2251
2252 CopyMem (Header->FieldValue, FieldValue, StrSize);
2253 Header->FieldValue[StrSize -1] = '\0';
2254
2255 HttpIoHeader->HeaderCount++;
2256 } else {
2257 //
2258 // Update an existing one.
2259 //
2260 StrSize = AsciiStrSize (FieldValue);
2261 NewFieldValue = AllocatePool (StrSize);
2262 if (NewFieldValue == NULL) {
2263 return EFI_OUT_OF_RESOURCES;
2264 }
2265
2266 CopyMem (NewFieldValue, FieldValue, StrSize);
2267 NewFieldValue[StrSize -1] = '\0';
2268
2269 if (Header->FieldValue != NULL) {
2270 FreePool (Header->FieldValue);
2271 }
2272
2273 Header->FieldValue = NewFieldValue;
2274 }
2275
2276 return EFI_SUCCESS;
2277}
UINT64 UINTN
INTN EFIAPI AsciiStriCmp(IN CONST CHAR8 *FirstString, IN CONST CHAR8 *SecondString)
Definition: String.c:814
UINTN EFIAPI StrSize(IN CONST CHAR16 *String)
Definition: String.c:72
UINTN EFIAPI AsciiStrLen(IN CONST CHAR8 *String)
Definition: String.c:641
INTN EFIAPI AsciiStrCmp(IN CONST CHAR8 *FirstString, IN CONST CHAR8 *SecondString)
Definition: String.c:716
RETURN_STATUS EFIAPI AsciiStrDecimalToUintnS(IN CONST CHAR8 *String, OUT CHAR8 **EndPointer OPTIONAL, OUT UINTN *Data)
Definition: SafeString.c:2179
UINTN EFIAPI AsciiStrHexToUintn(IN CONST CHAR8 *String)
Definition: String.c:1104
UINTN EFIAPI AsciiStrSize(IN CONST CHAR8 *String)
Definition: String.c:681
CHAR8 *EFIAPI AsciiStrStr(IN CONST CHAR8 *String, IN CONST CHAR8 *SearchString)
Definition: String.c:931
CHAR8 EFIAPI AsciiCharToUpper(IN CHAR8 Chr)
Definition: String.c:750
VOID *EFIAPI CopyMem(OUT VOID *DestinationBuffer, IN CONST VOID *SourceBuffer, IN UINTN Length)
VOID *EFIAPI ZeroMem(OUT VOID *Buffer, IN UINTN Length)
UINTN HttpIoHexCharToUintn(IN CHAR8 Char)
Definition: DxeHttpLib.c:919
EFI_STATUS EFIAPI HttpSetFieldNameAndValue(IN OUT EFI_HTTP_HEADER *HttpHeader, IN CONST CHAR8 *FieldName, IN CONST CHAR8 *FieldValue)
Definition: DxeHttpLib.c:1529
BOOLEAN HttpIoNoMessageBody(IN EFI_HTTP_METHOD Method, IN EFI_HTTP_STATUS_CODE StatusCode)
Definition: DxeHttpLib.c:998
EFI_STATUS EFIAPI HttpUrlGetHostName(IN CHAR8 *Url, IN VOID *UrlParser, OUT CHAR8 **HostName)
Definition: DxeHttpLib.c:506
EFI_STATUS EFIAPI HttpInitMsgParser(IN EFI_HTTP_METHOD Method, IN EFI_HTTP_STATUS_CODE StatusCode, IN UINTN HeaderCount, IN EFI_HTTP_HEADER *Headers, IN HTTP_BODY_PARSER_CALLBACK Callback, IN VOID *Context, OUT VOID **MsgParser)
Definition: DxeHttpLib.c:1050
VOID HttpIoFreeHeader(IN HTTP_IO_HEADER *HttpIoHeader)
Definition: DxeHttpLib.c:2178
EFI_STATUS EFIAPI UriPercentDecode(IN CHAR8 *Buffer, IN UINT32 BufferLength, OUT CHAR8 *ResultBuffer, OUT UINT32 *ResultLength)
Definition: DxeHttpLib.c:31
EFI_STATUS EFIAPI HttpUrlGetPort(IN CHAR8 *Url, IN VOID *UrlParser, OUT UINT16 *Port)
Definition: DxeHttpLib.c:702
HTTP_URL_PARSE_STATE NetHttpParseAuthorityChar(IN CHAR8 Char, IN HTTP_URL_PARSE_STATE State, IN BOOLEAN *IsRightBracket)
Definition: DxeHttpLib.c:86
BOOLEAN HttpIoIsChunked(IN UINTN HeaderCount, IN EFI_HTTP_HEADER *Headers)
Definition: DxeHttpLib.c:969
EFI_STATUS NetHttpParseAuthority(IN CHAR8 *Url, IN BOOLEAN FoundAt, IN OUT HTTP_URL_PARSER *UrlParser)
Definition: DxeHttpLib.c:159
HTTP_URL_PARSE_STATE NetHttpParseUrlChar(IN CHAR8 Char, IN HTTP_URL_PARSE_STATE State)
Definition: DxeHttpLib.c:250
HTTP_IO_HEADER * HttpIoCreateHeader(UINTN MaxHeaderCount)
Definition: DxeHttpLib.c:2150
EFI_HTTP_HEADER *EFIAPI HttpFindHeader(IN UINTN HeaderCount, IN EFI_HTTP_HEADER *Headers, IN CHAR8 *FieldName)
Definition: DxeHttpLib.c:855
EFI_STATUS EFIAPI HttpUrlGetPath(IN CHAR8 *Url, IN VOID *UrlParser, OUT CHAR8 **Path)
Definition: DxeHttpLib.c:786
VOID EFIAPI HttpFreeHeaderFields(IN EFI_HTTP_HEADER *HeaderFields, IN UINTN FieldCount)
Definition: DxeHttpLib.c:1730
CHAR8 *EFIAPI HttpGetFieldNameAndValue(IN CHAR8 *String, OUT CHAR8 **FieldName, OUT CHAR8 **FieldValue)
Definition: DxeHttpLib.c:1585
EFI_STATUS EFIAPI HttpUrlGetIp4(IN CHAR8 *Url, IN VOID *UrlParser, OUT EFI_IPv4_ADDRESS *Ip4Address)
Definition: DxeHttpLib.c:565
EFI_STATUS EFIAPI HttpUrlGetIp6(IN CHAR8 *Url, IN VOID *UrlParser, OUT EFI_IPv6_ADDRESS *Ip6Address)
Definition: DxeHttpLib.c:626
EFI_STATUS EFIAPI HttpGenRequestMessage(IN CONST EFI_HTTP_MESSAGE *Message, IN CONST CHAR8 *Url, OUT CHAR8 **RequestMsg, OUT UINTN *RequestMsgSize)
Definition: DxeHttpLib.c:1775
EFI_STATUS EFIAPI HttpParseMessageBody(IN OUT VOID *MsgParser, IN UINTN BodyLength, IN CHAR8 *Body)
Definition: DxeHttpLib.c:1131
EFI_STATUS HttpIoSetHeader(IN HTTP_IO_HEADER *HttpIoHeader, IN CHAR8 *FieldName, IN CHAR8 *FieldValue)
Definition: DxeHttpLib.c:2211
BOOLEAN EFIAPI HttpIsValidHttpHeader(IN CHAR8 *DeleteList[], IN UINTN DeleteCount, IN CHAR8 *FieldName)
Definition: DxeHttpLib.c:2116
CHAR8 * AsciiStrGetNextToken(IN CONST CHAR8 *String, IN CHAR8 Separator)
Definition: DxeHttpLib.c:1493
EFI_STATUS EFIAPI HttpGetEntityLength(IN VOID *MsgParser, OUT UINTN *ContentLength)
Definition: DxeHttpLib.c:1445
EFI_STATUS HttpIoParseContentLengthHeader(IN UINTN HeaderCount, IN EFI_HTTP_HEADER *Headers, OUT UINTN *ContentLength)
Definition: DxeHttpLib.c:942
VOID EFIAPI HttpFreeMsgParser(IN VOID *MsgParser)
Definition: DxeHttpLib.c:1474
VOID EFIAPI HttpUrlFreeParser(IN VOID *UrlParser)
Definition: DxeHttpLib.c:836
EFI_STATUS EFIAPI HttpParseUrl(IN CHAR8 *Url, IN UINT32 Length, IN BOOLEAN IsConnectMethod, OUT VOID **UrlParser)
Definition: DxeHttpLib.c:370
BOOLEAN EFIAPI HttpIsMessageComplete(IN VOID *MsgParser)
Definition: DxeHttpLib.c:1411
EFI_HTTP_STATUS_CODE EFIAPI HttpMappingToStatusCode(IN UINTN StatusCode)
Definition: DxeHttpLib.c:2008
VOID *EFIAPI AllocateZeroPool(IN UINTN AllocationSize)
VOID EFIAPI FreePool(IN VOID *Buffer)
#define HTTP_HEADER_CONTENT_LENGTH
Definition: Http11.h:135
#define HTTP_HEADER_TRANSFER_ENCODING
Definition: Http11.h:144
#define HTTP_METHOD_MAXIMUM_LEN
Definition: Http11.h:43
EFI_STATUS(EFIAPI * HTTP_BODY_PARSER_CALLBACK)(IN HTTP_BODY_PARSE_EVENT EventType, IN CHAR8 *Data, IN UINTN Length, IN VOID *Context)
Definition: HttpLib.h:231
#define NULL
Definition: Base.h:319
#define CONST
Definition: Base.h:259
#define MIN(a, b)
Definition: Base.h:1007
#define TRUE
Definition: Base.h:301
#define FALSE
Definition: Base.h:307
#define IN
Definition: Base.h:279
#define OUT
Definition: Base.h:284
#define DEBUG(Expression)
Definition: DebugLib.h:434
EFI_HTTP_METHOD
Definition: Http.h:43
EFI_HTTP_STATUS_CODE
Definition: Http.h:59
EFI_STATUS EFIAPI NetLibAsciiStrToIp4(IN CONST CHAR8 *String, OUT EFI_IPv4_ADDRESS *Ip4Address)
Definition: DxeNetLib.c:3068
EFI_STATUS EFIAPI NetLibAsciiStrToIp6(IN CONST CHAR8 *String, OUT EFI_IPv6_ADDRESS *Ip6Address)
Definition: DxeNetLib.c:3097
VOID *EFIAPI AllocatePool(IN UINTN AllocationSize)
VOID EFIAPI Exit(IN EFI_STATUS Status)
RETURN_STATUS EFI_STATUS
Definition: UefiBaseType.h:29
#define EFI_SUCCESS
Definition: UefiBaseType.h:112
EFI_BOOT_SERVICES * gBS