TianoCore EDK2 master
Loading...
Searching...
No Matches
HttpBootClient.c
Go to the documentation of this file.
1
10#include "HttpBootDxe.h"
11
25 )
26{
27 EFI_DEV_PATH *Node;
28 EFI_DEVICE_PATH_PROTOCOL *TmpIpDevicePath;
29 EFI_DEVICE_PATH_PROTOCOL *TmpDnsDevicePath;
30 EFI_DEVICE_PATH_PROTOCOL *NewDevicePath;
31 UINTN Length;
32 EFI_STATUS Status;
33
34 TmpIpDevicePath = NULL;
35 TmpDnsDevicePath = NULL;
36
37 //
38 // Update the IP node with DHCP assigned information.
39 //
40 if (!Private->UsingIpv6) {
41 Node = AllocateZeroPool (sizeof (IPv4_DEVICE_PATH));
42 if (Node == NULL) {
43 return EFI_OUT_OF_RESOURCES;
44 }
45
46 Node->Ipv4.Header.Type = MESSAGING_DEVICE_PATH;
47 Node->Ipv4.Header.SubType = MSG_IPv4_DP;
49 CopyMem (&Node->Ipv4.LocalIpAddress, &Private->StationIp, sizeof (EFI_IPv4_ADDRESS));
50 Node->Ipv4.RemotePort = Private->Port;
51 Node->Ipv4.Protocol = EFI_IP_PROTO_TCP;
52 Node->Ipv4.StaticIpAddress = FALSE;
53 CopyMem (&Node->Ipv4.GatewayIpAddress, &Private->GatewayIp, sizeof (EFI_IPv4_ADDRESS));
54 CopyMem (&Node->Ipv4.SubnetMask, &Private->SubnetMask, sizeof (EFI_IPv4_ADDRESS));
55 } else {
56 Node = AllocateZeroPool (sizeof (IPv6_DEVICE_PATH));
57 if (Node == NULL) {
58 return EFI_OUT_OF_RESOURCES;
59 }
60
61 Node->Ipv6.Header.Type = MESSAGING_DEVICE_PATH;
62 Node->Ipv6.Header.SubType = MSG_IPv6_DP;
64 Node->Ipv6.PrefixLength = IP6_PREFIX_LENGTH;
65 Node->Ipv6.RemotePort = Private->Port;
66 Node->Ipv6.Protocol = EFI_IP_PROTO_TCP;
67 Node->Ipv6.IpAddressOrigin = 0;
68 CopyMem (&Node->Ipv6.LocalIpAddress, &Private->StationIp.v6, sizeof (EFI_IPv6_ADDRESS));
69 CopyMem (&Node->Ipv6.RemoteIpAddress, &Private->ServerIp.v6, sizeof (EFI_IPv6_ADDRESS));
70 CopyMem (&Node->Ipv6.GatewayIpAddress, &Private->GatewayIp.v6, sizeof (EFI_IPv6_ADDRESS));
71 }
72
73 TmpIpDevicePath = AppendDevicePathNode (Private->ParentDevicePath, (EFI_DEVICE_PATH_PROTOCOL *)Node);
74 FreePool (Node);
75 if (TmpIpDevicePath == NULL) {
76 return EFI_OUT_OF_RESOURCES;
77 }
78
79 //
80 // Update the DNS node with DNS server IP list if existed.
81 //
82 if (Private->DnsServerIp != NULL) {
83 Length = sizeof (EFI_DEVICE_PATH_PROTOCOL) + sizeof (Node->Dns.IsIPv6) + Private->DnsServerCount * sizeof (EFI_IP_ADDRESS);
84 Node = AllocatePool (Length);
85 if (Node == NULL) {
86 FreePool (TmpIpDevicePath);
87 return EFI_OUT_OF_RESOURCES;
88 }
89
90 Node->DevPath.Type = MESSAGING_DEVICE_PATH;
91 Node->DevPath.SubType = MSG_DNS_DP;
92 SetDevicePathNodeLength (Node, Length);
93 Node->Dns.IsIPv6 = Private->UsingIpv6 ? 0x01 : 0x00;
94 CopyMem ((UINT8 *)Node + sizeof (EFI_DEVICE_PATH_PROTOCOL) + sizeof (Node->Dns.IsIPv6), Private->DnsServerIp, Private->DnsServerCount * sizeof (EFI_IP_ADDRESS));
95
96 TmpDnsDevicePath = AppendDevicePathNode (TmpIpDevicePath, (EFI_DEVICE_PATH_PROTOCOL *)Node);
97 FreePool (Node);
98 FreePool (TmpIpDevicePath);
99 TmpIpDevicePath = NULL;
100 if (TmpDnsDevicePath == NULL) {
101 return EFI_OUT_OF_RESOURCES;
102 }
103 }
104
105 //
106 // Update the URI node with the boot file URI.
107 //
108 Length = sizeof (EFI_DEVICE_PATH_PROTOCOL) + AsciiStrSize (Private->BootFileUri);
109 Node = AllocatePool (Length);
110 if (Node == NULL) {
111 if (TmpIpDevicePath != NULL) {
112 FreePool (TmpIpDevicePath);
113 }
114
115 if (TmpDnsDevicePath != NULL) {
116 FreePool (TmpDnsDevicePath);
117 }
118
119 return EFI_OUT_OF_RESOURCES;
120 }
121
122 Node->DevPath.Type = MESSAGING_DEVICE_PATH;
123 Node->DevPath.SubType = MSG_URI_DP;
124 SetDevicePathNodeLength (Node, Length);
125 CopyMem ((UINT8 *)Node + sizeof (EFI_DEVICE_PATH_PROTOCOL), Private->BootFileUri, AsciiStrSize (Private->BootFileUri));
126
127 if (TmpDnsDevicePath != NULL) {
128 NewDevicePath = AppendDevicePathNode (TmpDnsDevicePath, (EFI_DEVICE_PATH_PROTOCOL *)Node);
129 FreePool (TmpDnsDevicePath);
130 } else {
131 ASSERT (TmpIpDevicePath != NULL);
132 NewDevicePath = AppendDevicePathNode (TmpIpDevicePath, (EFI_DEVICE_PATH_PROTOCOL *)Node);
133 FreePool (TmpIpDevicePath);
134 }
135
136 FreePool (Node);
137 if (NewDevicePath == NULL) {
138 return EFI_OUT_OF_RESOURCES;
139 }
140
141 if (!Private->UsingIpv6) {
142 //
143 // Reinstall the device path protocol of the child handle.
144 //
145 Status = gBS->ReinstallProtocolInterface (
146 Private->Ip4Nic->Controller,
147 &gEfiDevicePathProtocolGuid,
148 Private->Ip4Nic->DevicePath,
149 NewDevicePath
150 );
151 if (EFI_ERROR (Status)) {
152 return Status;
153 }
154
155 FreePool (Private->Ip4Nic->DevicePath);
156 Private->Ip4Nic->DevicePath = NewDevicePath;
157 } else {
158 //
159 // Reinstall the device path protocol of the child handle.
160 //
161 Status = gBS->ReinstallProtocolInterface (
162 Private->Ip6Nic->Controller,
163 &gEfiDevicePathProtocolGuid,
164 Private->Ip6Nic->DevicePath,
165 NewDevicePath
166 );
167 if (EFI_ERROR (Status)) {
168 return Status;
169 }
170
171 FreePool (Private->Ip6Nic->DevicePath);
172 Private->Ip6Nic->DevicePath = NewDevicePath;
173 }
174
175 return EFI_SUCCESS;
176}
177
190 )
191{
192 HTTP_BOOT_DHCP4_PACKET_CACHE *SelectOffer;
194 UINT32 SelectIndex;
195 UINT32 ProxyIndex;
196 UINT32 DnsServerIndex;
198 EFI_STATUS Status;
199
200 ASSERT (Private != NULL);
201 ASSERT (Private->SelectIndex != 0);
202 SelectIndex = Private->SelectIndex - 1;
203 ASSERT (SelectIndex < HTTP_BOOT_OFFER_MAX_NUM);
204
205 DnsServerIndex = 0;
206
207 Status = EFI_SUCCESS;
208
209 //
210 // SelectOffer contains the IP address configuration and name server configuration.
211 // HttpOffer contains the boot file URL.
212 //
213 SelectOffer = &Private->OfferBuffer[SelectIndex].Dhcp4;
214 if (Private->FilePathUri == NULL) {
215 //
216 // In Corporate environment, we need a HttpOffer.
217 //
218 if ((SelectOffer->OfferType == HttpOfferTypeDhcpIpUri) ||
219 (SelectOffer->OfferType == HttpOfferTypeDhcpIpUriDns) ||
220 (SelectOffer->OfferType == HttpOfferTypeDhcpNameUriDns))
221 {
222 HttpOffer = SelectOffer;
223 } else {
224 ASSERT (Private->SelectProxyType != HttpOfferTypeMax);
225 ProxyIndex = Private->OfferIndex[Private->SelectProxyType][0];
226 HttpOffer = &Private->OfferBuffer[ProxyIndex].Dhcp4;
227 }
228
229 Private->BootFileUriParser = HttpOffer->UriParser;
230 Private->BootFileUri = (CHAR8 *)HttpOffer->OptList[HTTP_BOOT_DHCP4_TAG_INDEX_BOOTFILE]->Data;
231 } else {
232 //
233 // In Home environment the BootFileUri comes from the FilePath.
234 //
235 Private->BootFileUriParser = Private->FilePathUriParser;
236 Private->BootFileUri = Private->FilePathUri;
237 }
238
239 //
240 // Check the URI scheme.
241 //
242 Status = HttpBootCheckUriScheme (Private->BootFileUri);
243 if (EFI_ERROR (Status)) {
244 DEBUG ((DEBUG_ERROR, "HttpBootDhcp4ExtractUriInfo: %r.\n", Status));
245 if (Status == EFI_INVALID_PARAMETER) {
246 AsciiPrint ("\n Error: Invalid URI address.\n");
247 } else if (Status == EFI_ACCESS_DENIED) {
248 AsciiPrint ("\n Error: Access forbidden, only HTTPS connection is allowed.\n");
249 }
250
251 return Status;
252 }
253
254 if ((SelectOffer->OfferType == HttpOfferTypeDhcpNameUriDns) ||
255 (SelectOffer->OfferType == HttpOfferTypeDhcpDns) ||
256 (SelectOffer->OfferType == HttpOfferTypeDhcpIpUriDns))
257 {
258 Option = SelectOffer->OptList[HTTP_BOOT_DHCP4_TAG_INDEX_DNS_SERVER];
259 ASSERT (Option != NULL);
260
261 //
262 // Record the Dns Server address list.
263 //
264 Private->DnsServerCount = (Option->Length) / sizeof (EFI_IPv4_ADDRESS);
265
266 Private->DnsServerIp = AllocateZeroPool (Private->DnsServerCount * sizeof (EFI_IP_ADDRESS));
267 if (Private->DnsServerIp == NULL) {
268 return EFI_OUT_OF_RESOURCES;
269 }
270
271 for (DnsServerIndex = 0; DnsServerIndex < Private->DnsServerCount; DnsServerIndex++) {
272 CopyMem (&(Private->DnsServerIp[DnsServerIndex].v4), &(((EFI_IPv4_ADDRESS *)Option->Data)[DnsServerIndex]), sizeof (EFI_IPv4_ADDRESS));
273 }
274
275 //
276 // Configure the default DNS server if server assigned.
277 //
278 Status = HttpBootRegisterIp4Dns (
279 Private,
280 Option->Length,
281 Option->Data
282 );
283 if (EFI_ERROR (Status)) {
284 FreePool (Private->DnsServerIp);
285 Private->DnsServerIp = NULL;
286 return Status;
287 }
288 }
289
290 //
291 // Extract the port from URL, and use default HTTP port 80 if not provided.
292 //
293 Status = HttpUrlGetPort (
294 Private->BootFileUri,
295 Private->BootFileUriParser,
296 &Private->Port
297 );
298 if (EFI_ERROR (Status) || (Private->Port == 0)) {
299 Private->Port = 80;
300 }
301
302 //
303 // All boot informations are valid here.
304 //
305
306 //
307 // Update the device path to include the boot resource information.
308 //
309 Status = HttpBootUpdateDevicePath (Private);
310 if (EFI_ERROR (Status) && (Private->DnsServerIp != NULL)) {
311 FreePool (Private->DnsServerIp);
312 Private->DnsServerIp = NULL;
313 }
314
315 return Status;
316}
317
330 )
331{
332 HTTP_BOOT_DHCP6_PACKET_CACHE *SelectOffer;
334 UINT32 SelectIndex;
335 UINT32 ProxyIndex;
336 UINT32 DnsServerIndex;
338 EFI_IPv6_ADDRESS IpAddr;
339 CHAR8 *HostName;
340 UINTN HostNameSize;
341 CHAR16 *HostNameStr;
342 EFI_STATUS Status;
343
344 ASSERT (Private != NULL);
345 ASSERT (Private->SelectIndex != 0);
346 SelectIndex = Private->SelectIndex - 1;
347 ASSERT (SelectIndex < HTTP_BOOT_OFFER_MAX_NUM);
348
349 DnsServerIndex = 0;
350
351 Status = EFI_SUCCESS;
352 HostName = NULL;
353 //
354 // SelectOffer contains the IP address configuration and name server configuration.
355 // HttpOffer contains the boot file URL.
356 //
357 SelectOffer = &Private->OfferBuffer[SelectIndex].Dhcp6;
358 if (Private->FilePathUri == NULL) {
359 //
360 // In Corporate environment, we need a HttpOffer.
361 //
362 if ((SelectOffer->OfferType == HttpOfferTypeDhcpIpUri) ||
363 (SelectOffer->OfferType == HttpOfferTypeDhcpIpUriDns) ||
364 (SelectOffer->OfferType == HttpOfferTypeDhcpNameUriDns))
365 {
366 HttpOffer = SelectOffer;
367 } else {
368 ASSERT (Private->SelectProxyType != HttpOfferTypeMax);
369 ProxyIndex = Private->OfferIndex[Private->SelectProxyType][0];
370 HttpOffer = &Private->OfferBuffer[ProxyIndex].Dhcp6;
371 }
372
373 Private->BootFileUriParser = HttpOffer->UriParser;
374 Private->BootFileUri = (CHAR8 *)HttpOffer->OptList[HTTP_BOOT_DHCP6_IDX_BOOT_FILE_URL]->Data;
375 } else {
376 //
377 // In Home environment the BootFileUri comes from the FilePath.
378 //
379 Private->BootFileUriParser = Private->FilePathUriParser;
380 Private->BootFileUri = Private->FilePathUri;
381 }
382
383 //
384 // Check the URI scheme.
385 //
386 Status = HttpBootCheckUriScheme (Private->BootFileUri);
387 if (EFI_ERROR (Status)) {
388 DEBUG ((DEBUG_ERROR, "HttpBootDhcp6ExtractUriInfo: %r.\n", Status));
389 if (Status == EFI_INVALID_PARAMETER) {
390 AsciiPrint ("\n Error: Invalid URI address.\n");
391 } else if (Status == EFI_ACCESS_DENIED) {
392 AsciiPrint ("\n Error: Access forbidden, only HTTPS connection is allowed.\n");
393 }
394
395 return Status;
396 }
397
398 //
399 // Set the Local station address to IP layer.
400 //
401 Status = HttpBootSetIp6Address (Private);
402 if (EFI_ERROR (Status)) {
403 return Status;
404 }
405
406 //
407 // Register the IPv6 gateway address to the network device.
408 //
409 Status = HttpBootSetIp6Gateway (Private);
410 if (EFI_ERROR (Status)) {
411 return Status;
412 }
413
414 if ((SelectOffer->OfferType == HttpOfferTypeDhcpNameUriDns) ||
415 (SelectOffer->OfferType == HttpOfferTypeDhcpDns) ||
416 (SelectOffer->OfferType == HttpOfferTypeDhcpIpUriDns))
417 {
418 Option = SelectOffer->OptList[HTTP_BOOT_DHCP6_IDX_DNS_SERVER];
419 ASSERT (Option != NULL);
420
421 //
422 // Record the Dns Server address list.
423 //
424 Private->DnsServerCount = HTONS (Option->OpLen) / sizeof (EFI_IPv6_ADDRESS);
425
426 Private->DnsServerIp = AllocateZeroPool (Private->DnsServerCount * sizeof (EFI_IP_ADDRESS));
427 if (Private->DnsServerIp == NULL) {
428 return EFI_OUT_OF_RESOURCES;
429 }
430
431 for (DnsServerIndex = 0; DnsServerIndex < Private->DnsServerCount; DnsServerIndex++) {
432 CopyMem (&(Private->DnsServerIp[DnsServerIndex].v6), &(((EFI_IPv6_ADDRESS *)Option->Data)[DnsServerIndex]), sizeof (EFI_IPv6_ADDRESS));
433 }
434
435 //
436 // Configure the default DNS server if server assigned.
437 //
438 Status = HttpBootSetIp6Dns (
439 Private,
440 HTONS (Option->OpLen),
441 Option->Data
442 );
443 if (EFI_ERROR (Status)) {
444 goto Error;
445 }
446 }
447
448 //
449 // Extract the HTTP server Ip from URL. This is used to Check route table
450 // whether can send message to HTTP Server Ip through the GateWay.
451 //
452 Status = HttpUrlGetIp6 (
453 Private->BootFileUri,
454 Private->BootFileUriParser,
455 &IpAddr
456 );
457
458 if (EFI_ERROR (Status)) {
459 //
460 // The Http server address is expressed by Name Ip, so perform DNS resolution
461 //
462 Status = HttpUrlGetHostName (
463 Private->BootFileUri,
464 Private->BootFileUriParser,
465 &HostName
466 );
467 if (EFI_ERROR (Status)) {
468 goto Error;
469 }
470
471 HostNameSize = AsciiStrSize (HostName);
472 HostNameStr = AllocateZeroPool (HostNameSize * sizeof (CHAR16));
473 if (HostNameStr == NULL) {
474 Status = EFI_OUT_OF_RESOURCES;
475 goto Error;
476 }
477
478 AsciiStrToUnicodeStrS (HostName, HostNameStr, HostNameSize);
479
480 if (HostName != NULL) {
481 FreePool (HostName);
482 }
483
484 Status = HttpBootDns (Private, HostNameStr, &IpAddr);
485 FreePool (HostNameStr);
486 if (EFI_ERROR (Status)) {
487 AsciiPrint ("\n Error: Could not retrieve the host address from DNS server.\n");
488 goto Error;
489 }
490 }
491
492 CopyMem (&Private->ServerIp.v6, &IpAddr, sizeof (EFI_IPv6_ADDRESS));
493
494 //
495 // Extract the port from URL, and use default HTTP port 80 if not provided.
496 //
497 Status = HttpUrlGetPort (
498 Private->BootFileUri,
499 Private->BootFileUriParser,
500 &Private->Port
501 );
502 if (EFI_ERROR (Status) || (Private->Port == 0)) {
503 Private->Port = 80;
504 }
505
506 //
507 // All boot informations are valid here.
508 //
509
510 //
511 // Update the device path to include the boot resource information.
512 //
513 Status = HttpBootUpdateDevicePath (Private);
514 if (EFI_ERROR (Status)) {
515 goto Error;
516 }
517
518 return Status;
519
520Error:
521 if (Private->DnsServerIp != NULL) {
522 FreePool (Private->DnsServerIp);
523 Private->DnsServerIp = NULL;
524 }
525
526 return Status;
527}
528
541 )
542{
543 EFI_STATUS Status;
544
545 //
546 // Start D.O.R.A/S.A.R.R exchange to acquire station ip address and
547 // other Http boot information.
548 //
549 Status = HttpBootDhcp (Private);
550 if (EFI_ERROR (Status)) {
551 return Status;
552 }
553
554 if (!Private->UsingIpv6) {
555 Status = HttpBootDhcp4ExtractUriInfo (Private);
556 } else {
557 Status = HttpBootDhcp6ExtractUriInfo (Private);
558 }
559
560 return Status;
561}
562
574EFIAPI
576 IN HTTP_IO_CALLBACK_EVENT EventType,
577 IN EFI_HTTP_MESSAGE *Message,
578 IN VOID *Context
579 )
580{
581 HTTP_BOOT_PRIVATE_DATA *Private;
582 EFI_STATUS Status;
583
584 Private = (HTTP_BOOT_PRIVATE_DATA *)Context;
585 if (Private->HttpBootCallback != NULL) {
586 Status = Private->HttpBootCallback->Callback (
587 Private->HttpBootCallback,
588 EventType == HttpIoRequest ? HttpBootHttpRequest : HttpBootHttpResponse,
589 EventType == HttpIoRequest ? FALSE : TRUE,
590 sizeof (EFI_HTTP_MESSAGE),
591 (VOID *)Message
592 );
593 return Status;
594 }
595
596 return EFI_SUCCESS;
597}
598
611 )
612{
613 HTTP_IO_CONFIG_DATA ConfigData;
614 EFI_STATUS Status;
615 EFI_HANDLE ImageHandle;
616 UINT32 TimeoutValue;
617
618 ASSERT (Private != NULL);
619
620 //
621 // Get HTTP timeout value
622 //
623 TimeoutValue = PcdGet32 (PcdHttpIoTimeout);
624
625 ZeroMem (&ConfigData, sizeof (HTTP_IO_CONFIG_DATA));
626 if (!Private->UsingIpv6) {
627 ConfigData.Config4.HttpVersion = HttpVersion11;
628 ConfigData.Config4.RequestTimeOut = TimeoutValue;
629 IP4_COPY_ADDRESS (&ConfigData.Config4.LocalIp, &Private->StationIp.v4);
630 IP4_COPY_ADDRESS (&ConfigData.Config4.SubnetMask, &Private->SubnetMask.v4);
631 ImageHandle = Private->Ip4Nic->ImageHandle;
632 } else {
633 ConfigData.Config6.HttpVersion = HttpVersion11;
634 ConfigData.Config6.RequestTimeOut = TimeoutValue;
635 IP6_COPY_ADDRESS (&ConfigData.Config6.LocalIp, &Private->StationIp.v6);
636 ImageHandle = Private->Ip6Nic->ImageHandle;
637 }
638
639 Status = HttpIoCreateIo (
640 ImageHandle,
641 Private->Controller,
642 Private->UsingIpv6 ? IP_VERSION_6 : IP_VERSION_4,
643 &ConfigData,
645 (VOID *)Private,
646 &Private->HttpIo
647 );
648 if (EFI_ERROR (Status)) {
649 return Status;
650 }
651
652 Private->HttpCreated = TRUE;
653 return EFI_SUCCESS;
654}
655
662VOID
665 )
666{
667 UINTN Index;
668 LIST_ENTRY *Entry;
669 LIST_ENTRY *NextEntry;
670 HTTP_BOOT_ENTITY_DATA *EntityData;
671
672 if (Cache != NULL) {
673 //
674 // Free the request data
675 //
676 if (Cache->RequestData != NULL) {
677 if (Cache->RequestData->Url != NULL) {
678 FreePool (Cache->RequestData->Url);
679 }
680
681 FreePool (Cache->RequestData);
682 }
683
684 //
685 // Free the response header
686 //
687 if (Cache->ResponseData != NULL) {
688 if (Cache->ResponseData->Headers != NULL) {
689 for (Index = 0; Index < Cache->ResponseData->HeaderCount; Index++) {
690 FreePool (Cache->ResponseData->Headers[Index].FieldName);
691 FreePool (Cache->ResponseData->Headers[Index].FieldValue);
692 }
693
694 FreePool (Cache->ResponseData->Headers);
695 }
696 }
697
698 //
699 // Free the response body
700 //
701 NET_LIST_FOR_EACH_SAFE (Entry, NextEntry, &Cache->EntityDataList) {
702 EntityData = NET_LIST_USER_STRUCT (Entry, HTTP_BOOT_ENTITY_DATA, Link);
703 if (EntityData->Block != NULL) {
704 FreePool (EntityData->Block);
705 }
706
707 RemoveEntryList (&EntityData->Link);
708 FreePool (EntityData);
709 }
710
711 FreePool (Cache);
712 }
713}
714
721VOID
724 )
725{
726 LIST_ENTRY *Entry;
727 LIST_ENTRY *NextEntry;
729
730 NET_LIST_FOR_EACH_SAFE (Entry, NextEntry, &Private->CacheList) {
731 Cache = NET_LIST_USER_STRUCT (Entry, HTTP_BOOT_CACHE_CONTENT, Link);
732 RemoveEntryList (&Cache->Link);
733 HttpBootFreeCache (Cache);
734 }
735}
736
757 IN HTTP_BOOT_PRIVATE_DATA *Private,
758 IN CHAR16 *Uri,
759 IN OUT UINTN *BufferSize,
760 OUT UINT8 *Buffer,
761 OUT HTTP_BOOT_IMAGE_TYPE *ImageType
762 )
763{
764 LIST_ENTRY *Entry;
765 LIST_ENTRY *Entry2;
767 HTTP_BOOT_ENTITY_DATA *EntityData;
768 UINTN CopyedSize;
769
770 if ((Uri == NULL) || (BufferSize == NULL) || (Buffer == NULL) || (ImageType == NULL)) {
771 return EFI_INVALID_PARAMETER;
772 }
773
774 NET_LIST_FOR_EACH (Entry, &Private->CacheList) {
775 Cache = NET_LIST_USER_STRUCT (Entry, HTTP_BOOT_CACHE_CONTENT, Link);
776 //
777 // Compare the URI to see whether we already have a cache for this file.
778 //
779 if ((Cache->RequestData != NULL) &&
780 (Cache->RequestData->Url != NULL) &&
781 (StrCmp (Uri, Cache->RequestData->Url) == 0))
782 {
783 //
784 // Hit in cache, record image type.
785 //
786 *ImageType = Cache->ImageType;
787
788 //
789 // Check buffer size.
790 //
791 if (*BufferSize < Cache->EntityLength) {
792 *BufferSize = Cache->EntityLength;
793 return EFI_BUFFER_TOO_SMALL;
794 }
795
796 //
797 // Fill data to buffer.
798 //
799 CopyedSize = 0;
800 NET_LIST_FOR_EACH (Entry2, &Cache->EntityDataList) {
801 EntityData = NET_LIST_USER_STRUCT (Entry2, HTTP_BOOT_ENTITY_DATA, Link);
802 if (*BufferSize > CopyedSize) {
803 CopyMem (
804 Buffer + CopyedSize,
805 EntityData->DataStart,
806 MIN (EntityData->DataLength, *BufferSize - CopyedSize)
807 );
808 CopyedSize += MIN (EntityData->DataLength, *BufferSize - CopyedSize);
809 }
810 }
811 *BufferSize = CopyedSize;
812 return EFI_SUCCESS;
813 }
814 }
815
816 return EFI_NOT_FOUND;
817}
818
835EFIAPI
837 IN HTTP_BODY_PARSE_EVENT EventType,
838 IN CHAR8 *Data,
839 IN UINTN Length,
840 IN VOID *Context
841 )
842{
843 HTTP_BOOT_CALLBACK_DATA *CallbackData;
844 HTTP_BOOT_ENTITY_DATA *NewEntityData;
845 EFI_STATUS Status;
847
848 //
849 // We only care about the entity data.
850 //
851 if (EventType != BodyParseEventOnData) {
852 return EFI_SUCCESS;
853 }
854
855 CallbackData = (HTTP_BOOT_CALLBACK_DATA *)Context;
856 HttpBootCallback = CallbackData->Private->HttpBootCallback;
857 if (HttpBootCallback != NULL) {
858 Status = HttpBootCallback->Callback (
861 TRUE,
862 (UINT32)Length,
863 Data
864 );
865 if (EFI_ERROR (Status)) {
866 return Status;
867 }
868 }
869
870 //
871 // Copy data if caller has provided a buffer.
872 //
873 if (CallbackData->BufferSize > CallbackData->CopyedSize) {
874 CopyMem (
875 CallbackData->Buffer + CallbackData->CopyedSize,
876 Data,
877 MIN (Length, CallbackData->BufferSize - CallbackData->CopyedSize)
878 );
879 CallbackData->CopyedSize += MIN (Length, CallbackData->BufferSize - CallbackData->CopyedSize);
880 }
881
882 //
883 // The caller doesn't provide a buffer, save the block into cache list.
884 //
885 if (CallbackData->Cache != NULL) {
886 NewEntityData = AllocatePool (sizeof (HTTP_BOOT_ENTITY_DATA));
887 if (NewEntityData == NULL) {
888 return EFI_OUT_OF_RESOURCES;
889 }
890
891 if (CallbackData->NewBlock) {
892 NewEntityData->Block = CallbackData->Block;
893 CallbackData->Block = NULL;
894 }
895
896 NewEntityData->DataLength = Length;
897 NewEntityData->DataStart = (UINT8 *)Data;
898 InsertTailList (&CallbackData->Cache->EntityDataList, &NewEntityData->Link);
899 }
900
901 return EFI_SUCCESS;
902}
903
934 IN HTTP_BOOT_PRIVATE_DATA *Private,
935 IN BOOLEAN HeaderOnly,
936 IN OUT UINTN *BufferSize,
937 OUT UINT8 *Buffer,
938 OUT HTTP_BOOT_IMAGE_TYPE *ImageType
939 )
940{
941 EFI_STATUS Status;
942 EFI_HTTP_STATUS_CODE StatusCode;
943 CHAR8 *HostName;
944 EFI_HTTP_REQUEST_DATA *RequestData;
945 HTTP_IO_RESPONSE_DATA *ResponseData;
946 HTTP_IO_RESPONSE_DATA ResponseBody;
947 HTTP_IO *HttpIo;
948 HTTP_IO_HEADER *HttpIoHeader;
949 VOID *Parser;
951 UINTN ContentLength;
953 UINT8 *Block;
954 UINTN UrlSize;
955 CHAR16 *Url;
956 BOOLEAN IdentityMode;
957 UINTN ReceivedSize;
958 CHAR8 BaseAuthValue[80];
959 EFI_HTTP_HEADER *HttpHeader;
960 CHAR8 *Data;
961 UINTN HeadersCount;
962 BOOLEAN ResumingOperation;
963 CHAR8 *ContentRangeResponseValue;
964 CHAR8 RangeValue[64];
965
966 ASSERT (Private != NULL);
967 ASSERT (Private->HttpCreated);
968
969 if ((BufferSize == NULL) || (ImageType == NULL)) {
970 return EFI_INVALID_PARAMETER;
971 }
972
973 if ((*BufferSize != 0) && (Buffer == NULL)) {
974 return EFI_INVALID_PARAMETER;
975 }
976
977 //
978 // First, check whether we already cached the requested Uri.
979 //
980 UrlSize = AsciiStrSize (Private->BootFileUri);
981 Url = AllocatePool (UrlSize * sizeof (CHAR16));
982 if (Url == NULL) {
983 return EFI_OUT_OF_RESOURCES;
984 }
985
986 AsciiStrToUnicodeStrS (Private->BootFileUri, Url, UrlSize);
987 if (!HeaderOnly && (Buffer != NULL)) {
988 Status = HttpBootGetFileFromCache (Private, Url, BufferSize, Buffer, ImageType);
989 if (Status != EFI_NOT_FOUND) {
990 FreePool (Url);
991 return Status;
992 }
993 }
994
995 // Check if this is a previous download that has failed and need to be resumed
996 if ((!HeaderOnly) &&
997 (Private->PartialTransferredSize > 0) &&
998 (Private->BootFileSize == *BufferSize))
999 {
1000 ResumingOperation = TRUE;
1001 } else {
1002 ResumingOperation = FALSE;
1003 }
1004
1005 //
1006 // Not found in cache, try to download it through HTTP.
1007 //
1008
1009 //
1010 // 1. Create a temp cache item for the requested URI if caller doesn't provide buffer.
1011 //
1012 Cache = NULL;
1013 if ((!HeaderOnly) && (*BufferSize == 0)) {
1014 Cache = AllocateZeroPool (sizeof (HTTP_BOOT_CACHE_CONTENT));
1015 if (Cache == NULL) {
1016 Status = EFI_OUT_OF_RESOURCES;
1017 goto ERROR_1;
1018 }
1019
1020 Cache->ImageType = ImageTypeMax;
1021 InitializeListHead (&Cache->EntityDataList);
1022 }
1023
1024 //
1025 // 2. Send HTTP request message.
1026 //
1027
1028 //
1029 // 2.1 Build HTTP header for the request, 3 header is needed to download a boot file:
1030 // Host
1031 // Accept
1032 // User-Agent
1033 // [Authorization]
1034 // [Range]
1035 // [If-Match]|[If-Unmodified-Since]
1036 //
1037 HeadersCount = 3;
1038 if (Private->AuthData != NULL) {
1039 HeadersCount++;
1040 }
1041
1042 if (ResumingOperation) {
1043 HeadersCount++;
1044 if (Private->LastModifiedOrEtag) {
1045 HeadersCount++;
1046 }
1047 }
1048
1049 HttpIoHeader = HttpIoCreateHeader (HeadersCount);
1050
1051 if (HttpIoHeader == NULL) {
1052 Status = EFI_OUT_OF_RESOURCES;
1053 goto ERROR_2;
1054 }
1055
1056 //
1057 // Add HTTP header field 1: Host
1058 //
1059 HostName = NULL;
1060 Status = HttpUrlGetHostName (
1061 Private->BootFileUri,
1062 Private->BootFileUriParser,
1063 &HostName
1064 );
1065 if (EFI_ERROR (Status)) {
1066 goto ERROR_3;
1067 }
1068
1069 Status = HttpIoSetHeader (
1070 HttpIoHeader,
1072 HostName
1073 );
1074 FreePool (HostName);
1075 if (EFI_ERROR (Status)) {
1076 goto ERROR_3;
1077 }
1078
1079 //
1080 // Add HTTP header field 2: Accept
1081 //
1082 Status = HttpIoSetHeader (
1083 HttpIoHeader,
1085 "*/*"
1086 );
1087 if (EFI_ERROR (Status)) {
1088 goto ERROR_3;
1089 }
1090
1091 //
1092 // Add HTTP header field 3: User-Agent
1093 //
1094 Status = HttpIoSetHeader (
1095 HttpIoHeader,
1097 HTTP_USER_AGENT_EFI_HTTP_BOOT
1098 );
1099 if (EFI_ERROR (Status)) {
1100 goto ERROR_3;
1101 }
1102
1103 //
1104 // Add HTTP header field 4: Authorization
1105 //
1106 if (Private->AuthData != NULL) {
1107 ASSERT (HttpIoHeader->MaxHeaderCount == 4);
1108
1109 if ((Private->AuthScheme != NULL) && (CompareMem (Private->AuthScheme, "Basic", 5) != 0)) {
1110 Status = EFI_UNSUPPORTED;
1111 goto ERROR_3;
1112 }
1113
1114 AsciiSPrint (
1115 BaseAuthValue,
1116 sizeof (BaseAuthValue),
1117 "%a %a",
1118 "Basic",
1119 Private->AuthData
1120 );
1121
1122 Status = HttpIoSetHeader (
1123 HttpIoHeader,
1125 BaseAuthValue
1126 );
1127 if (EFI_ERROR (Status)) {
1128 goto ERROR_3;
1129 }
1130 }
1131
1132 //
1133 // Add HTTP header field 5 (optional): Range
1134 //
1135 if (ResumingOperation) {
1136 // Resuming a failed download. Prepare the HTTP Range Header
1137 Status = AsciiSPrint (
1138 RangeValue,
1139 sizeof (RangeValue),
1140 "bytes=%lu-%lu",
1141 Private->PartialTransferredSize,
1142 Private->BootFileSize - 1
1143 );
1144 if (EFI_ERROR (Status)) {
1145 goto ERROR_3;
1146 }
1147
1148 Status = HttpIoSetHeader (HttpIoHeader, "Range", RangeValue);
1149 if (EFI_ERROR (Status)) {
1150 goto ERROR_3;
1151 }
1152
1153 DEBUG (
1154 (DEBUG_WARN | DEBUG_INFO,
1155 "HttpBootGetBootFile: Resuming failed download. Range: %a\n",
1156 RangeValue)
1157 );
1158
1159 //
1160 // Add HTTP header field 6 (optional): If-Match or If-Unmodified-Since
1161 //
1162 if (Private->LastModifiedOrEtag) {
1163 if (Private->LastModifiedOrEtag[0] == '"') {
1164 // An ETag value starts with "
1165 DEBUG (
1166 (DEBUG_WARN | DEBUG_INFO,
1167 "HttpBootGetBootFile: If-Match=%a\n",
1168 Private->LastModifiedOrEtag)
1169 );
1170 // Add If-Match header with the ETag value got from the first request.
1171 Status = HttpIoSetHeader (HttpIoHeader, HTTP_HEADER_IF_MATCH, Private->LastModifiedOrEtag);
1172 } else {
1173 DEBUG (
1174 (DEBUG_WARN | DEBUG_INFO,
1175 "HttpBootGetBootFile: If-Unmodified-Since=%a\n",
1176 Private->LastModifiedOrEtag)
1177 );
1178 // Add If-Unmodified-Since header with the timestamp value (Last-Modified) got from the first request.
1179 Status = HttpIoSetHeader (HttpIoHeader, HTTP_HEADER_IF_UNMODIFIED_SINCE, Private->LastModifiedOrEtag);
1180 }
1181
1182 if (EFI_ERROR (Status)) {
1183 goto ERROR_3;
1184 }
1185 }
1186 }
1187
1188 //
1189 // 2.2 Build the rest of HTTP request info.
1190 //
1191 RequestData = AllocatePool (sizeof (EFI_HTTP_REQUEST_DATA));
1192 if (RequestData == NULL) {
1193 Status = EFI_OUT_OF_RESOURCES;
1194 goto ERROR_3;
1195 }
1196
1197 RequestData->Method = HeaderOnly ? HttpMethodHead : HttpMethodGet;
1198 RequestData->Url = Url;
1199
1200 //
1201 // 2.3 Record the request info in a temp cache item.
1202 //
1203 if (Cache != NULL) {
1204 Cache->RequestData = RequestData;
1205 }
1206
1207 //
1208 // 2.4 Send out the request to HTTP server.
1209 //
1210 HttpIo = &Private->HttpIo;
1211 Status = HttpIoSendRequest (
1212 HttpIo,
1213 RequestData,
1214 HttpIoHeader->HeaderCount,
1215 HttpIoHeader->Headers,
1216 0,
1217 NULL
1218 );
1219 if (EFI_ERROR (Status)) {
1220 goto ERROR_4;
1221 }
1222
1223 //
1224 // 3. Receive HTTP response message.
1225 //
1226
1227 //
1228 // 3.1 First step, use zero BodyLength to only receive the response headers.
1229 //
1230 ResponseData = AllocateZeroPool (sizeof (HTTP_IO_RESPONSE_DATA));
1231 if (ResponseData == NULL) {
1232 Status = EFI_OUT_OF_RESOURCES;
1233 goto ERROR_4;
1234 }
1235
1236 Data = NULL;
1237 Status = HttpIoRecvResponse (
1238 &Private->HttpIo,
1239 TRUE,
1240 ResponseData
1241 );
1242 if (EFI_ERROR (Status) || EFI_ERROR (ResponseData->Status)) {
1243 if (EFI_ERROR (ResponseData->Status)) {
1244 StatusCode = HttpIo->RspToken.Message->Data.Response->StatusCode;
1245 HttpBootPrintErrorMessage (StatusCode);
1246 Status = ResponseData->Status;
1247 if ((StatusCode == HTTP_STATUS_401_UNAUTHORIZED) || \
1248 (StatusCode == HTTP_STATUS_407_PROXY_AUTHENTICATION_REQUIRED))
1249 {
1250 if ((Private->AuthData != NULL) || (Private->AuthScheme != NULL)) {
1251 if (Private->AuthData != NULL) {
1252 FreePool (Private->AuthData);
1253 Private->AuthData = NULL;
1254 }
1255
1256 if (Private->AuthScheme != NULL) {
1257 FreePool (Private->AuthScheme);
1258 Private->AuthScheme = NULL;
1259 }
1260
1261 Status = EFI_ACCESS_DENIED;
1262 goto ERROR_4;
1263 }
1264
1265 //
1266 // Server indicates the user has to provide a user-id and password as a means of identification.
1267 //
1268 if (Private->HttpBootCallback != NULL) {
1269 Data = AllocateZeroPool (sizeof (CHAR8) * HTTP_BOOT_AUTHENTICATION_INFO_MAX_LEN);
1270 if (Data == NULL) {
1271 Status = EFI_OUT_OF_RESOURCES;
1272 goto ERROR_4;
1273 }
1274
1275 Status = Private->HttpBootCallback->Callback (
1276 Private->HttpBootCallback,
1278 TRUE,
1279 HTTP_BOOT_AUTHENTICATION_INFO_MAX_LEN,
1280 Data
1281 );
1282 if (EFI_ERROR (Status)) {
1283 if (Data != NULL) {
1284 FreePool (Data);
1285 }
1286
1287 goto ERROR_5;
1288 }
1289
1290 Private->AuthData = (CHAR8 *)Data;
1291 }
1292
1293 HttpHeader = HttpFindHeader (
1294 ResponseData->HeaderCount,
1295 ResponseData->Headers,
1297 );
1298 if (HttpHeader != NULL) {
1299 Private->AuthScheme = AllocateZeroPool (AsciiStrLen (HttpHeader->FieldValue) + 1);
1300 if (Private->AuthScheme == NULL) {
1301 return EFI_OUT_OF_RESOURCES;
1302 }
1303
1304 CopyMem (Private->AuthScheme, HttpHeader->FieldValue, AsciiStrLen (HttpHeader->FieldValue));
1305 }
1306
1307 Status = EFI_ACCESS_DENIED;
1308 }
1309 }
1310
1311 goto ERROR_5;
1312 }
1313
1314 //
1315 // Check the image type according to server's response.
1316 //
1317 Status = HttpBootCheckImageType (
1318 Private->BootFileUri,
1319 Private->BootFileUriParser,
1320 ResponseData->HeaderCount,
1321 ResponseData->Headers,
1322 ImageType
1323 );
1324 if (EFI_ERROR (Status)) {
1325 goto ERROR_5;
1326 }
1327
1328 //
1329 // 3.2 Cache the response header.
1330 //
1331 if (Cache != NULL) {
1332 Cache->ResponseData = ResponseData;
1333 Cache->ImageType = *ImageType;
1334 }
1335
1336 // Cache ETag or Last-Modified response header value to
1337 // be used when resuming an interrupted download.
1338 HttpHeader = HttpFindHeader (
1339 ResponseData->HeaderCount,
1340 ResponseData->Headers,
1342 );
1343 if (HttpHeader == NULL) {
1344 HttpHeader = HttpFindHeader (
1345 ResponseData->HeaderCount,
1346 ResponseData->Headers,
1348 );
1349 }
1350
1351 if (HttpHeader) {
1352 if (Private->LastModifiedOrEtag) {
1353 FreePool (Private->LastModifiedOrEtag);
1354 }
1355
1356 Private->LastModifiedOrEtag = AllocateCopyPool (AsciiStrSize (HttpHeader->FieldValue), HttpHeader->FieldValue);
1357 }
1358
1359 //
1360 // 3.2.2 Validate the range response. If operation is being resumed,
1361 // server must respond with Content-Range.
1362 //
1363 if (ResumingOperation) {
1364 HttpHeader = HttpFindHeader (
1365 ResponseData->HeaderCount,
1366 ResponseData->Headers,
1368 );
1369 if ((HttpHeader == NULL) ||
1370 (AsciiStrnCmp (HttpHeader->FieldValue, "bytes", 5) != 0))
1371 {
1372 Status = EFI_UNSUPPORTED;
1373 goto ERROR_5;
1374 }
1375
1376 // Gets the total size of ranged data (Content-Range: <unit> <range-start>-<range-end>/<size>)
1377 // and check if it remains the same
1378 ContentRangeResponseValue = AsciiStrStr (HttpHeader->FieldValue, "/");
1379 if (ContentRangeResponseValue == NULL) {
1380 Status = EFI_INVALID_PARAMETER;
1381 goto ERROR_5;
1382 }
1383
1384 ContentRangeResponseValue++;
1385 ContentLength = AsciiStrDecimalToUintn (ContentRangeResponseValue);
1386 if (ContentLength != *BufferSize) {
1387 Status = EFI_INVALID_PARAMETER;
1388 goto ERROR_5;
1389 }
1390 }
1391
1392 //
1393 // 3.3 Init a message-body parser from the header information.
1394 //
1395 Parser = NULL;
1396 Context.NewBlock = FALSE;
1397 Context.Block = NULL;
1398 Context.CopyedSize = 0;
1399 Context.Buffer = Buffer;
1400 Context.BufferSize = *BufferSize;
1401 Context.Cache = Cache;
1402 Context.Private = Private;
1403 Status = HttpInitMsgParser (
1404 HeaderOnly ? HttpMethodHead : HttpMethodGet,
1405 ResponseData->Response.StatusCode,
1406 ResponseData->HeaderCount,
1407 ResponseData->Headers,
1409 (VOID *)&Context,
1410 &Parser
1411 );
1412 if (EFI_ERROR (Status)) {
1413 goto ERROR_6;
1414 }
1415
1416 //
1417 // 3.4 Continue to receive and parse message-body if needed.
1418 //
1419 Block = NULL;
1420 if (!HeaderOnly) {
1421 //
1422 // 3.4.1, check whether we are in identity transfer-coding.
1423 //
1424 ContentLength = 0;
1425 Status = HttpGetEntityLength (Parser, &ContentLength);
1426 if (!EFI_ERROR (Status)) {
1427 IdentityMode = TRUE;
1428 } else {
1429 IdentityMode = FALSE;
1430 }
1431
1432 //
1433 // 3.4.2, start the message-body download, the identity and chunked transfer-coding
1434 // is handled in different path here.
1435 //
1436 ZeroMem (&ResponseBody, sizeof (HTTP_IO_RESPONSE_DATA));
1437 if (IdentityMode) {
1438 //
1439 // In identity transfer-coding there is no need to parse the message body,
1440 // just download the message body to the user provided buffer directly.
1441 //
1442 if (ResumingOperation && ((ContentLength + Private->PartialTransferredSize) > *BufferSize)) {
1443 Status = EFI_INVALID_PARAMETER;
1444 goto ERROR_6;
1445 }
1446
1447 ReceivedSize = 0;
1448 while (ReceivedSize < ContentLength) {
1449 ResponseBody.Body = (CHAR8 *)Buffer + (ReceivedSize + Private->PartialTransferredSize);
1450 ResponseBody.BodyLength = *BufferSize - (ReceivedSize + Private->PartialTransferredSize);
1451 Status = HttpIoRecvResponse (
1452 &Private->HttpIo,
1453 FALSE,
1454 &ResponseBody
1455 );
1456 if (EFI_ERROR (Status) || EFI_ERROR (ResponseBody.Status)) {
1457 if (EFI_ERROR (ResponseBody.Status)) {
1458 Status = ResponseBody.Status;
1459 }
1460
1461 if ((Status == EFI_TIMEOUT) || (Status == EFI_DEVICE_ERROR)) {
1462 // For EFI_TIMEOUT and EFI_DEVICE_ERROR errors, we may resume the operation.
1463 // We will not check if server sent Accept-Ranges header, because some back-ends
1464 // do not report this header, even when supporting it. Know example: CloudFlare CDN Cache.
1465 Private->PartialTransferredSize = ReceivedSize;
1466 DEBUG (
1467 (
1468 DEBUG_WARN | DEBUG_INFO,
1469 "HttpBootGetBootFile: Transfer error. Bytes transferred so far: %lu.\n",
1470 ReceivedSize
1471 )
1472 );
1473 }
1474
1475 goto ERROR_6;
1476 }
1477
1478 ReceivedSize += ResponseBody.BodyLength;
1479 if (Private->HttpBootCallback != NULL) {
1480 Status = Private->HttpBootCallback->Callback (
1481 Private->HttpBootCallback,
1483 TRUE,
1484 (UINT32)ResponseBody.BodyLength,
1485 ResponseBody.Body
1486 );
1487 if (EFI_ERROR (Status)) {
1488 goto ERROR_6;
1489 }
1490 }
1491 }
1492
1493 // download completed, there is no more partial data
1494 Private->PartialTransferredSize = 0;
1495 } else {
1496 //
1497 // In "chunked" transfer-coding mode, so we need to parse the received
1498 // data to get the real entity content.
1499 //
1500 Block = NULL;
1501 while (!HttpIsMessageComplete (Parser)) {
1502 //
1503 // Allocate a buffer in Block to hold the message-body.
1504 // If caller provides a buffer, this Block will be reused in every HttpIoRecvResponse().
1505 // Otherwise a buffer, the buffer in Block will be cached and we should allocate a new before
1506 // every HttpIoRecvResponse().
1507 //
1508 if ((Block == NULL) || (Context.BufferSize == 0)) {
1509 Block = AllocatePool (HTTP_BOOT_BLOCK_SIZE);
1510 if (Block == NULL) {
1511 Status = EFI_OUT_OF_RESOURCES;
1512 goto ERROR_6;
1513 }
1514
1515 Context.NewBlock = TRUE;
1516 Context.Block = Block;
1517 } else {
1518 Context.NewBlock = FALSE;
1519 }
1520
1521 ResponseBody.Body = (CHAR8 *)Block;
1522 ResponseBody.BodyLength = HTTP_BOOT_BLOCK_SIZE;
1523 Status = HttpIoRecvResponse (
1524 &Private->HttpIo,
1525 FALSE,
1526 &ResponseBody
1527 );
1528 if (EFI_ERROR (Status) || EFI_ERROR (ResponseBody.Status)) {
1529 if (EFI_ERROR (ResponseBody.Status)) {
1530 Status = ResponseBody.Status;
1531 }
1532
1533 goto ERROR_6;
1534 }
1535
1536 //
1537 // Parse the new received block of the message-body, the block will be saved in cache.
1538 //
1539 Status = HttpParseMessageBody (
1540 Parser,
1541 ResponseBody.BodyLength,
1542 ResponseBody.Body
1543 );
1544 if (EFI_ERROR (Status)) {
1545 goto ERROR_6;
1546 }
1547 }
1548 }
1549 }
1550
1551 //
1552 // 3.5 Message-body receive & parse is completed, we should be able to get the file size now.
1553 //
1554 if (!ResumingOperation) {
1555 Status = HttpGetEntityLength (Parser, &ContentLength);
1556 if (EFI_ERROR (Status)) {
1557 goto ERROR_6;
1558 }
1559 } else {
1560 ContentLength = Private->BootFileSize;
1561 }
1562
1563 if (*BufferSize < ContentLength) {
1564 Status = EFI_BUFFER_TOO_SMALL;
1565 } else {
1566 Status = EFI_SUCCESS;
1567 }
1568
1569 *BufferSize = ContentLength;
1570
1571 //
1572 // 4. Save the cache item to driver's cache list and return.
1573 //
1574 if (Cache != NULL) {
1575 Cache->EntityLength = ContentLength;
1576 InsertTailList (&Private->CacheList, &Cache->Link);
1577 }
1578
1579 if (Parser != NULL) {
1580 HttpFreeMsgParser (Parser);
1581 }
1582
1583 return Status;
1584
1585ERROR_6:
1586 if (Parser != NULL) {
1587 HttpFreeMsgParser (Parser);
1588 }
1589
1590 if (Context.Block != NULL) {
1591 FreePool (Context.Block);
1592 }
1593
1594 HttpBootFreeCache (Cache);
1595
1596ERROR_5:
1597 if (ResponseData != NULL) {
1598 FreePool (ResponseData);
1599 }
1600
1601ERROR_4:
1602 if (RequestData != NULL) {
1603 FreePool (RequestData);
1604 }
1605
1606ERROR_3:
1607 HttpIoFreeHeader (HttpIoHeader);
1608ERROR_2:
1609 if (Cache != NULL) {
1610 FreePool (Cache);
1611 }
1612
1613ERROR_1:
1614 if (Url != NULL) {
1615 FreePool (Url);
1616 }
1617
1618 return Status;
1619}
UINT64 UINTN
INTN EFIAPI StrCmp(IN CONST CHAR16 *FirstString, IN CONST CHAR16 *SecondString)
Definition: String.c:109
UINTN EFIAPI AsciiStrLen(IN CONST CHAR8 *String)
Definition: String.c:641
INTN EFIAPI AsciiStrnCmp(IN CONST CHAR8 *FirstString, IN CONST CHAR8 *SecondString, IN UINTN Length)
Definition: String.c:872
UINTN EFIAPI AsciiStrDecimalToUintn(IN CONST CHAR8 *String)
Definition: String.c:1006
LIST_ENTRY *EFIAPI RemoveEntryList(IN CONST LIST_ENTRY *Entry)
Definition: LinkedList.c:590
LIST_ENTRY *EFIAPI InitializeListHead(IN OUT LIST_ENTRY *ListHead)
Definition: LinkedList.c:182
RETURN_STATUS EFIAPI AsciiStrToUnicodeStrS(IN CONST CHAR8 *Source, OUT CHAR16 *Destination, IN UINTN DestMax)
Definition: SafeString.c:2873
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
LIST_ENTRY *EFIAPI InsertTailList(IN OUT LIST_ENTRY *ListHead, IN OUT LIST_ENTRY *Entry)
Definition: LinkedList.c:259
INTN EFIAPI CompareMem(IN CONST VOID *DestinationBuffer, IN CONST VOID *SourceBuffer, IN UINTN Length)
VOID *EFIAPI CopyMem(OUT VOID *DestinationBuffer, IN CONST VOID *SourceBuffer, IN UINTN Length)
VOID *EFIAPI ZeroMem(OUT VOID *Buffer, IN UINTN Length)
#define MSG_IPv6_DP
Definition: DevicePath.h:607
#define MSG_IPv4_DP
Definition: DevicePath.h:566
#define MSG_URI_DP
Definition: DevicePath.h:879
#define MSG_DNS_DP
Definition: DevicePath.h:863
#define MESSAGING_DEVICE_PATH
Definition: DevicePath.h:321
UINT16 EFIAPI SetDevicePathNodeLength(IN OUT VOID *Node, IN UINTN Length)
EFI_DEVICE_PATH_PROTOCOL *EFIAPI AppendDevicePathNode(IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath OPTIONAL, IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePathNode OPTIONAL)
VOID *EFIAPI AllocateZeroPool(IN UINTN AllocationSize)
VOID EFIAPI FreePool(IN VOID *Buffer)
VOID *EFIAPI AllocateCopyPool(IN UINTN AllocationSize, IN CONST VOID *Buffer)
#define HTTP_HEADER_USER_AGENT
Definition: Http11.h:163
#define HTTP_HEADER_AUTHORIZATION
Definition: Http11.h:221
#define HTTP_HEADER_WWW_AUTHENTICATE
Definition: Http11.h:213
#define HTTP_HEADER_ACCEPT
Definition: Http11.h:52
#define HTTP_HEADER_IF_MATCH
Definition: Http11.h:194
#define HTTP_HEADER_ETAG
Definition: Http11.h:228
#define HTTP_HEADER_IF_UNMODIFIED_SINCE
Definition: Http11.h:277
#define HTTP_HEADER_HOST
Definition: Http11.h:171
#define HTTP_HEADER_CONTENT_RANGE
Definition: Http11.h:256
#define HTTP_HEADER_LAST_MODIFIED
Definition: Http11.h:267
@ HttpBootHttpAuthInfo
@ HttpBootHttpRequest
@ HttpBootHttpResponse
@ HttpBootHttpEntityBody
EFI_STATUS HttpBootCreateHttpIo(IN HTTP_BOOT_PRIVATE_DATA *Private)
EFI_STATUS HttpBootDiscoverBootInfo(IN OUT HTTP_BOOT_PRIVATE_DATA *Private)
EFI_STATUS HttpBootGetBootFile(IN HTTP_BOOT_PRIVATE_DATA *Private, IN BOOLEAN HeaderOnly, IN OUT UINTN *BufferSize, OUT UINT8 *Buffer, OUT HTTP_BOOT_IMAGE_TYPE *ImageType)
EFI_STATUS HttpBootDhcp4ExtractUriInfo(IN HTTP_BOOT_PRIVATE_DATA *Private)
EFI_STATUS EFIAPI HttpBootHttpIoCallback(IN HTTP_IO_CALLBACK_EVENT EventType, IN EFI_HTTP_MESSAGE *Message, IN VOID *Context)
EFI_STATUS HttpBootUpdateDevicePath(IN HTTP_BOOT_PRIVATE_DATA *Private)
EFI_STATUS HttpBootGetFileFromCache(IN HTTP_BOOT_PRIVATE_DATA *Private, IN CHAR16 *Uri, IN OUT UINTN *BufferSize, OUT UINT8 *Buffer, OUT HTTP_BOOT_IMAGE_TYPE *ImageType)
VOID HttpBootFreeCacheList(IN HTTP_BOOT_PRIVATE_DATA *Private)
EFI_STATUS HttpBootDhcp6ExtractUriInfo(IN HTTP_BOOT_PRIVATE_DATA *Private)
EFI_STATUS EFIAPI HttpBootGetBootFileCallback(IN HTTP_BODY_PARSE_EVENT EventType, IN CHAR8 *Data, IN UINTN Length, IN VOID *Context)
VOID HttpBootFreeCache(IN HTTP_BOOT_CACHE_CONTENT *Cache)
EFI_STATUS HttpBootRegisterIp4Dns(IN HTTP_BOOT_PRIVATE_DATA *Private, IN UINTN DataLength, IN VOID *DnsServerData)
EFI_STATUS HttpBootSetIp6Gateway(IN HTTP_BOOT_PRIVATE_DATA *Private)
EFI_STATUS HttpBootSetIp6Dns(IN HTTP_BOOT_PRIVATE_DATA *Private, IN UINTN DataLength, IN VOID *DnsServerData)
EFI_STATUS HttpBootSetIp6Address(IN HTTP_BOOT_PRIVATE_DATA *Private)
EFI_STATUS EFIAPI HttpBootCallback(IN EFI_HTTP_BOOT_CALLBACK_PROTOCOL *This, IN EFI_HTTP_BOOT_CALLBACK_DATA_TYPE DataType, IN BOOLEAN Received, IN UINT32 DataLength, IN VOID *Data OPTIONAL)
Definition: HttpBootImpl.c:786
EFI_STATUS HttpBootDhcp(IN HTTP_BOOT_PRIVATE_DATA *Private)
Definition: HttpBootImpl.c:254
EFI_STATUS HttpBootCheckUriScheme(IN CHAR8 *Uri)
EFI_STATUS HttpBootCheckImageType(IN CHAR8 *Uri, IN VOID *UriParser, IN UINTN HeaderCount, IN EFI_HTTP_HEADER *Headers, OUT HTTP_BOOT_IMAGE_TYPE *ImageType)
EFI_STATUS HttpBootDns(IN HTTP_BOOT_PRIVATE_DATA *Private, IN CHAR16 *HostName, OUT EFI_IPv6_ADDRESS *IpAddress)
VOID HttpBootPrintErrorMessage(EFI_HTTP_STATUS_CODE StatusCode)
EFI_STATUS HttpIoCreateIo(IN EFI_HANDLE Image, IN EFI_HANDLE Controller, IN UINT8 IpVersion, IN HTTP_IO_CONFIG_DATA *ConfigData, IN HTTP_IO_CALLBACK Callback, IN VOID *Context, OUT HTTP_IO *HttpIo)
EFI_STATUS HttpIoSendRequest(IN HTTP_IO *HttpIo, IN EFI_HTTP_REQUEST_DATA *Request OPTIONAL, IN UINTN HeaderCount, IN EFI_HTTP_HEADER *Headers OPTIONAL, IN UINTN BodyLength, IN VOID *Body OPTIONAL)
EFI_STATUS HttpIoRecvResponse(IN HTTP_IO *HttpIo, IN BOOLEAN RecvMsgHeader, OUT HTTP_IO_RESPONSE_DATA *ResponseData)
Definition: DxeHttpIoLib.c:366
HTTP_IO_CALLBACK_EVENT
Definition: HttpIoLib.h:25
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 HttpUrlGetPort(IN CHAR8 *Url, IN VOID *UrlParser, OUT UINT16 *Port)
Definition: DxeHttpLib.c:702
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 HttpUrlGetIp6(IN CHAR8 *Url, IN VOID *UrlParser, OUT EFI_IPv6_ADDRESS *Ip6Address)
Definition: DxeHttpLib.c:626
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
EFI_STATUS EFIAPI HttpGetEntityLength(IN VOID *MsgParser, OUT UINTN *ContentLength)
Definition: DxeHttpLib.c:1445
VOID EFIAPI HttpFreeMsgParser(IN VOID *MsgParser)
Definition: DxeHttpLib.c:1474
BOOLEAN EFIAPI HttpIsMessageComplete(IN VOID *MsgParser)
Definition: DxeHttpLib.c:1411
UINTN EFIAPI AsciiSPrint(OUT CHAR8 *StartOfBuffer, IN UINTN BufferSize, IN CONST CHAR8 *FormatString,...)
Definition: PrintLib.c:813
#define NULL
Definition: Base.h:319
#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_STATUS_CODE
Definition: Http.h:59
#define PcdGet32(TokenName)
Definition: PcdLib.h:362
VOID *EFIAPI AllocatePool(IN UINTN AllocationSize)
IPv6_ADDRESS EFI_IPv6_ADDRESS
Definition: UefiBaseType.h:90
RETURN_STATUS EFI_STATUS
Definition: UefiBaseType.h:29
VOID * EFI_HANDLE
Definition: UefiBaseType.h:33
#define EFI_SUCCESS
Definition: UefiBaseType.h:112
EFI_BOOT_SERVICES * gBS
UINTN EFIAPI AsciiPrint(IN CONST CHAR8 *Format,...)
Definition: UefiLibPrint.c:250
CHAR8 * FieldValue
Definition: Http.h:220
union EFI_HTTP_MESSAGE::@577 Data
EFI_HTTP_RESPONSE_DATA * Response
Definition: Http.h:240
CHAR16 * Url
Definition: Http.h:194
EFI_HTTP_METHOD Method
Definition: Http.h:187
EFI_HTTP_STATUS_CODE StatusCode
Definition: Http.h:204
EFI_HTTP_MESSAGE * Message
Definition: Http.h:290
UINT32 RequestTimeOut
In milliseconds.
Definition: HttpIoLib.h:65
UINT32 RequestTimeOut
In milliseconds.
Definition: HttpIoLib.h:78
EFI_IPv4_ADDRESS GatewayIpAddress
Definition: DevicePath.h:597
EFI_IPv4_ADDRESS SubnetMask
Definition: DevicePath.h:601
BOOLEAN StaticIpAddress
Definition: DevicePath.h:593
EFI_IPv4_ADDRESS LocalIpAddress
Definition: DevicePath.h:572
EFI_IPv6_ADDRESS LocalIpAddress
Definition: DevicePath.h:613
UINT8 IpAddressOrigin
Definition: DevicePath.h:637
EFI_IPv6_ADDRESS RemoteIpAddress
Definition: DevicePath.h:617
EFI_IPv6_ADDRESS GatewayIpAddress
Definition: DevicePath.h:645