2 Miscellaneous routines for HttpDxe driver.
4 Copyright (c) 2015 - 2018, Intel Corporation. All rights reserved.<BR>
5 (C) Copyright 2016 Hewlett Packard Enterprise Development LP<BR>
6 SPDX-License-Identifier: BSD-2-Clause-Patent
10 #include "HttpDriver.h"
13 The common notify function used in HTTP driver.
15 @param[in] Event The event signaled.
16 @param[in] Context The context.
26 if ((Event
== NULL
) || (Context
== NULL
)) {
30 *((BOOLEAN
*) Context
) = TRUE
;
34 The notify function associated with Tx4Token for Tcp4->Transmit() or Tx6Token for Tcp6->Transmit().
36 @param[in] Context The context.
41 HttpTcpTransmitNotifyDpc (
45 HTTP_TOKEN_WRAP
*Wrap
;
46 HTTP_PROTOCOL
*HttpInstance
;
48 if (Context
== NULL
) {
52 Wrap
= (HTTP_TOKEN_WRAP
*) Context
;
53 HttpInstance
= Wrap
->HttpInstance
;
55 if (!HttpInstance
->LocalAddressIsIPv6
) {
56 Wrap
->HttpToken
->Status
= Wrap
->TcpWrap
.Tx4Token
.CompletionToken
.Status
;
57 gBS
->SignalEvent (Wrap
->HttpToken
->Event
);
62 if (Wrap
->TcpWrap
.Tx4Token
.Packet
.TxData
->FragmentTable
[0].FragmentBuffer
!= NULL
) {
63 FreePool (Wrap
->TcpWrap
.Tx4Token
.Packet
.TxData
->FragmentTable
[0].FragmentBuffer
);
66 if (Wrap
->TcpWrap
.Tx4Token
.CompletionToken
.Event
!= NULL
) {
67 gBS
->CloseEvent (Wrap
->TcpWrap
.Tx4Token
.CompletionToken
.Event
);
71 Wrap
->HttpToken
->Status
= Wrap
->TcpWrap
.Tx6Token
.CompletionToken
.Status
;
72 gBS
->SignalEvent (Wrap
->HttpToken
->Event
);
77 if (Wrap
->TcpWrap
.Tx6Token
.Packet
.TxData
->FragmentTable
[0].FragmentBuffer
!= NULL
) {
78 FreePool (Wrap
->TcpWrap
.Tx6Token
.Packet
.TxData
->FragmentTable
[0].FragmentBuffer
);
81 if (Wrap
->TcpWrap
.Tx6Token
.CompletionToken
.Event
!= NULL
) {
82 gBS
->CloseEvent (Wrap
->TcpWrap
.Tx6Token
.CompletionToken
.Event
);
87 Wrap
->TcpWrap
.IsTxDone
= TRUE
;
90 // Check pending TxTokens and sent out.
92 NetMapIterate (&Wrap
->HttpInstance
->TxTokens
, HttpTcpTransmit
, NULL
);
97 Request HttpTcpTransmitNotifyDpc as a DPC at TPL_CALLBACK.
99 @param Event The receive event delivered to TCP for transmit.
100 @param Context Context for the callback.
105 HttpTcpTransmitNotify (
111 // Request HttpTcpTransmitNotifyDpc as a DPC at TPL_CALLBACK
113 QueueDpc (TPL_CALLBACK
, HttpTcpTransmitNotifyDpc
, Context
);
117 The notify function associated with Rx4Token for Tcp4->Receive () or Rx6Token for Tcp6->Receive().
119 @param[in] Context The context.
124 HttpTcpReceiveNotifyDpc (
128 HTTP_TOKEN_WRAP
*Wrap
;
132 HTTP_PROTOCOL
*HttpInstance
;
135 if (Context
== NULL
) {
139 Wrap
= (HTTP_TOKEN_WRAP
*) Context
;
140 HttpInstance
= Wrap
->HttpInstance
;
141 UsingIpv6
= HttpInstance
->LocalAddressIsIPv6
;
144 gBS
->CloseEvent (Wrap
->TcpWrap
.Rx6Token
.CompletionToken
.Event
);
145 Wrap
->TcpWrap
.Rx6Token
.CompletionToken
.Event
= NULL
;
147 if (EFI_ERROR (Wrap
->TcpWrap
.Rx6Token
.CompletionToken
.Status
)) {
148 DEBUG ((EFI_D_ERROR
, "HttpTcpReceiveNotifyDpc: %r!\n", Wrap
->TcpWrap
.Rx6Token
.CompletionToken
.Status
));
149 Wrap
->HttpToken
->Status
= Wrap
->TcpWrap
.Rx6Token
.CompletionToken
.Status
;
150 gBS
->SignalEvent (Wrap
->HttpToken
->Event
);
152 Item
= NetMapFindKey (&HttpInstance
->RxTokens
, Wrap
->HttpToken
);
154 NetMapRemoveItem (&HttpInstance
->RxTokens
, Item
, NULL
);
164 gBS
->CloseEvent (Wrap
->TcpWrap
.Rx4Token
.CompletionToken
.Event
);
165 Wrap
->TcpWrap
.Rx4Token
.CompletionToken
.Event
= NULL
;
167 if (EFI_ERROR (Wrap
->TcpWrap
.Rx4Token
.CompletionToken
.Status
)) {
168 DEBUG ((EFI_D_ERROR
, "HttpTcpReceiveNotifyDpc: %r!\n", Wrap
->TcpWrap
.Rx4Token
.CompletionToken
.Status
));
169 Wrap
->HttpToken
->Status
= Wrap
->TcpWrap
.Rx4Token
.CompletionToken
.Status
;
170 gBS
->SignalEvent (Wrap
->HttpToken
->Event
);
172 Item
= NetMapFindKey (&HttpInstance
->RxTokens
, Wrap
->HttpToken
);
174 NetMapRemoveItem (&HttpInstance
->RxTokens
, Item
, NULL
);
185 // Check whether we receive a complete HTTP message.
187 ASSERT (HttpInstance
->MsgParser
!= NULL
);
189 Length
= (UINTN
) Wrap
->TcpWrap
.Rx6Data
.FragmentTable
[0].FragmentLength
;
191 Length
= (UINTN
) Wrap
->TcpWrap
.Rx4Data
.FragmentTable
[0].FragmentLength
;
195 // Record the CallbackData data.
197 HttpInstance
->CallbackData
.Wrap
= (VOID
*) Wrap
;
198 HttpInstance
->CallbackData
.ParseData
= Wrap
->HttpToken
->Message
->Body
;
199 HttpInstance
->CallbackData
.ParseDataLength
= Length
;
202 // Parse Body with CallbackData data.
204 Status
= HttpParseMessageBody (
205 HttpInstance
->MsgParser
,
207 Wrap
->HttpToken
->Message
->Body
209 if (EFI_ERROR (Status
)) {
213 if (HttpIsMessageComplete (HttpInstance
->MsgParser
)) {
215 // Free the MsgParse since we already have a full HTTP message.
217 HttpFreeMsgParser (HttpInstance
->MsgParser
);
218 HttpInstance
->MsgParser
= NULL
;
221 Wrap
->HttpToken
->Message
->BodyLength
= Length
;
222 ASSERT (HttpInstance
->CacheBody
== NULL
);
224 // We receive part of header of next HTTP msg.
226 if (HttpInstance
->NextMsg
!= NULL
) {
227 Wrap
->HttpToken
->Message
->BodyLength
= HttpInstance
->NextMsg
-
228 (CHAR8
*) Wrap
->HttpToken
->Message
->Body
;
229 HttpInstance
->CacheLen
= Length
- Wrap
->HttpToken
->Message
->BodyLength
;
230 if (HttpInstance
->CacheLen
!= 0) {
231 HttpInstance
->CacheBody
= AllocateZeroPool (HttpInstance
->CacheLen
);
232 if (HttpInstance
->CacheBody
== NULL
) {
235 CopyMem (HttpInstance
->CacheBody
, HttpInstance
->NextMsg
, HttpInstance
->CacheLen
);
236 HttpInstance
->NextMsg
= HttpInstance
->CacheBody
;
237 HttpInstance
->CacheOffset
= 0;
241 Item
= NetMapFindKey (&Wrap
->HttpInstance
->RxTokens
, Wrap
->HttpToken
);
243 NetMapRemoveItem (&Wrap
->HttpInstance
->RxTokens
, Item
, NULL
);
247 Wrap
->TcpWrap
.IsRxDone
= TRUE
;
249 Wrap
->HttpToken
->Status
= Wrap
->TcpWrap
.Rx6Token
.CompletionToken
.Status
;
251 Wrap
->HttpToken
->Status
= Wrap
->TcpWrap
.Rx4Token
.CompletionToken
.Status
;
255 gBS
->SignalEvent (Wrap
->HttpToken
->Event
);
258 // Check pending RxTokens and receive the HTTP message.
260 NetMapIterate (&Wrap
->HttpInstance
->RxTokens
, HttpTcpReceive
, NULL
);
267 Request HttpTcpReceiveNotifyDpc as a DPC at TPL_CALLBACK.
269 @param Event The receive event delivered to TCP for receive.
270 @param Context Context for the callback.
275 HttpTcpReceiveNotify (
281 // Request HttpTcpTransmitNotifyDpc as a DPC at TPL_CALLBACK
283 QueueDpc (TPL_CALLBACK
, HttpTcpReceiveNotifyDpc
, Context
);
287 Create events for the TCP connection token and TCP close token.
289 @param[in] HttpInstance Pointer to HTTP_PROTOCOL structure.
291 @retval EFI_SUCCESS The events are created successfully.
292 @retval others Other error as indicated.
296 HttpCreateTcpConnCloseEvent (
297 IN HTTP_PROTOCOL
*HttpInstance
302 if (!HttpInstance
->LocalAddressIsIPv6
) {
304 // Create events for variuos asynchronous operations.
306 Status
= gBS
->CreateEvent (
310 &HttpInstance
->IsTcp4ConnDone
,
311 &HttpInstance
->Tcp4ConnToken
.CompletionToken
.Event
313 if (EFI_ERROR (Status
)) {
318 // Initialize Tcp4CloseToken
320 Status
= gBS
->CreateEvent (
324 &HttpInstance
->IsTcp4CloseDone
,
325 &HttpInstance
->Tcp4CloseToken
.CompletionToken
.Event
327 if (EFI_ERROR (Status
)) {
333 // Create events for variuos asynchronous operations.
335 Status
= gBS
->CreateEvent (
339 &HttpInstance
->IsTcp6ConnDone
,
340 &HttpInstance
->Tcp6ConnToken
.CompletionToken
.Event
342 if (EFI_ERROR (Status
)) {
347 // Initialize Tcp6CloseToken
349 Status
= gBS
->CreateEvent (
353 &HttpInstance
->IsTcp6CloseDone
,
354 &HttpInstance
->Tcp6CloseToken
.CompletionToken
.Event
356 if (EFI_ERROR (Status
)) {
367 HttpCloseTcpConnCloseEvent (HttpInstance
);
374 Close events in the TCP connection token and TCP close token.
376 @param[in] HttpInstance Pointer to HTTP_PROTOCOL structure.
380 HttpCloseTcpConnCloseEvent (
381 IN HTTP_PROTOCOL
*HttpInstance
384 ASSERT (HttpInstance
!= NULL
);
386 if (HttpInstance
->LocalAddressIsIPv6
) {
387 if (NULL
!= HttpInstance
->Tcp6ConnToken
.CompletionToken
.Event
) {
388 gBS
->CloseEvent (HttpInstance
->Tcp6ConnToken
.CompletionToken
.Event
);
389 HttpInstance
->Tcp6ConnToken
.CompletionToken
.Event
= NULL
;
392 if (NULL
!= HttpInstance
->Tcp6CloseToken
.CompletionToken
.Event
) {
393 gBS
->CloseEvent(HttpInstance
->Tcp6CloseToken
.CompletionToken
.Event
);
394 HttpInstance
->Tcp6CloseToken
.CompletionToken
.Event
= NULL
;
398 if (NULL
!= HttpInstance
->Tcp4ConnToken
.CompletionToken
.Event
) {
399 gBS
->CloseEvent (HttpInstance
->Tcp4ConnToken
.CompletionToken
.Event
);
400 HttpInstance
->Tcp4ConnToken
.CompletionToken
.Event
= NULL
;
403 if (NULL
!= HttpInstance
->Tcp4CloseToken
.CompletionToken
.Event
) {
404 gBS
->CloseEvent(HttpInstance
->Tcp4CloseToken
.CompletionToken
.Event
);
405 HttpInstance
->Tcp4CloseToken
.CompletionToken
.Event
= NULL
;
412 Create event for the TCP transmit token.
414 @param[in] Wrap Point to HTTP token's wrap data.
416 @retval EFI_SUCCESS The events is created successfully.
417 @retval others Other error as indicated.
421 HttpCreateTcpTxEvent (
422 IN HTTP_TOKEN_WRAP
*Wrap
426 HTTP_PROTOCOL
*HttpInstance
;
427 HTTP_TCP_TOKEN_WRAP
*TcpWrap
;
429 HttpInstance
= Wrap
->HttpInstance
;
430 TcpWrap
= &Wrap
->TcpWrap
;
432 if (!HttpInstance
->LocalAddressIsIPv6
) {
433 Status
= gBS
->CreateEvent (
436 HttpTcpTransmitNotify
,
438 &TcpWrap
->Tx4Token
.CompletionToken
.Event
440 if (EFI_ERROR (Status
)) {
444 TcpWrap
->Tx4Data
.Push
= TRUE
;
445 TcpWrap
->Tx4Data
.Urgent
= FALSE
;
446 TcpWrap
->Tx4Data
.FragmentCount
= 1;
447 TcpWrap
->Tx4Token
.Packet
.TxData
= &Wrap
->TcpWrap
.Tx4Data
;
448 TcpWrap
->Tx4Token
.CompletionToken
.Status
= EFI_NOT_READY
;
451 Status
= gBS
->CreateEvent (
454 HttpTcpTransmitNotify
,
456 &TcpWrap
->Tx6Token
.CompletionToken
.Event
458 if (EFI_ERROR (Status
)) {
462 TcpWrap
->Tx6Data
.Push
= TRUE
;
463 TcpWrap
->Tx6Data
.Urgent
= FALSE
;
464 TcpWrap
->Tx6Data
.FragmentCount
= 1;
465 TcpWrap
->Tx6Token
.Packet
.TxData
= &Wrap
->TcpWrap
.Tx6Data
;
466 TcpWrap
->Tx6Token
.CompletionToken
.Status
=EFI_NOT_READY
;
474 Create event for the TCP receive token which is used to receive HTTP header.
476 @param[in] HttpInstance Pointer to HTTP_PROTOCOL structure.
478 @retval EFI_SUCCESS The events is created successfully.
479 @retval others Other error as indicated.
483 HttpCreateTcpRxEventForHeader (
484 IN HTTP_PROTOCOL
*HttpInstance
489 if (!HttpInstance
->LocalAddressIsIPv6
) {
490 Status
= gBS
->CreateEvent (
494 &HttpInstance
->IsRxDone
,
495 &HttpInstance
->Rx4Token
.CompletionToken
.Event
497 if (EFI_ERROR (Status
)) {
501 HttpInstance
->Rx4Data
.FragmentCount
= 1;
502 HttpInstance
->Rx4Token
.Packet
.RxData
= &HttpInstance
->Rx4Data
;
503 HttpInstance
->Rx4Token
.CompletionToken
.Status
= EFI_NOT_READY
;
506 Status
= gBS
->CreateEvent (
510 &HttpInstance
->IsRxDone
,
511 &HttpInstance
->Rx6Token
.CompletionToken
.Event
513 if (EFI_ERROR (Status
)) {
517 HttpInstance
->Rx6Data
.FragmentCount
=1;
518 HttpInstance
->Rx6Token
.Packet
.RxData
= &HttpInstance
->Rx6Data
;
519 HttpInstance
->Rx6Token
.CompletionToken
.Status
= EFI_NOT_READY
;
528 Create event for the TCP receive token which is used to receive HTTP body.
530 @param[in] Wrap Point to HTTP token's wrap data.
532 @retval EFI_SUCCESS The events is created successfully.
533 @retval others Other error as indicated.
537 HttpCreateTcpRxEvent (
538 IN HTTP_TOKEN_WRAP
*Wrap
542 HTTP_PROTOCOL
*HttpInstance
;
543 HTTP_TCP_TOKEN_WRAP
*TcpWrap
;
545 HttpInstance
= Wrap
->HttpInstance
;
546 TcpWrap
= &Wrap
->TcpWrap
;
547 if (!HttpInstance
->LocalAddressIsIPv6
) {
548 Status
= gBS
->CreateEvent (
551 HttpTcpReceiveNotify
,
553 &TcpWrap
->Rx4Token
.CompletionToken
.Event
555 if (EFI_ERROR (Status
)) {
559 TcpWrap
->Rx4Data
.FragmentCount
= 1;
560 TcpWrap
->Rx4Token
.Packet
.RxData
= &Wrap
->TcpWrap
.Rx4Data
;
561 TcpWrap
->Rx4Token
.CompletionToken
.Status
= EFI_NOT_READY
;
564 Status
= gBS
->CreateEvent (
567 HttpTcpReceiveNotify
,
569 &TcpWrap
->Rx6Token
.CompletionToken
.Event
571 if (EFI_ERROR (Status
)) {
575 TcpWrap
->Rx6Data
.FragmentCount
= 1;
576 TcpWrap
->Rx6Token
.Packet
.RxData
= &Wrap
->TcpWrap
.Rx6Data
;
577 TcpWrap
->Rx6Token
.CompletionToken
.Status
= EFI_NOT_READY
;
584 Close Events for Tcp Receive Tokens for HTTP body and HTTP header.
586 @param[in] Wrap Pointer to HTTP token's wrap data.
590 HttpCloseTcpRxEvent (
591 IN HTTP_TOKEN_WRAP
*Wrap
594 HTTP_PROTOCOL
*HttpInstance
;
596 ASSERT (Wrap
!= NULL
);
597 HttpInstance
= Wrap
->HttpInstance
;
599 if (HttpInstance
->LocalAddressIsIPv6
) {
600 if (Wrap
->TcpWrap
.Rx6Token
.CompletionToken
.Event
!= NULL
) {
601 gBS
->CloseEvent (Wrap
->TcpWrap
.Rx6Token
.CompletionToken
.Event
);
604 if (HttpInstance
->Rx6Token
.CompletionToken
.Event
!= NULL
) {
605 gBS
->CloseEvent (HttpInstance
->Rx6Token
.CompletionToken
.Event
);
606 HttpInstance
->Rx6Token
.CompletionToken
.Event
= NULL
;
609 if (Wrap
->TcpWrap
.Rx4Token
.CompletionToken
.Event
!= NULL
) {
610 gBS
->CloseEvent (Wrap
->TcpWrap
.Rx4Token
.CompletionToken
.Event
);
613 if (HttpInstance
->Rx4Token
.CompletionToken
.Event
!= NULL
) {
614 gBS
->CloseEvent (HttpInstance
->Rx4Token
.CompletionToken
.Event
);
615 HttpInstance
->Rx4Token
.CompletionToken
.Event
= NULL
;
621 Intiialize the HTTP_PROTOCOL structure to the unconfigured state.
623 @param[in, out] HttpInstance Pointer to HTTP_PROTOCOL structure.
624 @param[in] IpVersion Indicate us TCP4 protocol or TCP6 protocol.
626 @retval EFI_SUCCESS HTTP_PROTOCOL structure is initialized successfully.
627 @retval Others Other error as indicated.
632 IN OUT HTTP_PROTOCOL
*HttpInstance
,
640 ASSERT (HttpInstance
!= NULL
);
641 UsingIpv6
= IpVersion
;
645 // Create TCP4 child.
647 Status
= NetLibCreateServiceChild (
648 HttpInstance
->Service
->ControllerHandle
,
649 HttpInstance
->Service
->Ip4DriverBindingHandle
,
650 &gEfiTcp4ServiceBindingProtocolGuid
,
651 &HttpInstance
->Tcp4ChildHandle
654 if (EFI_ERROR (Status
)) {
658 Status
= gBS
->OpenProtocol (
659 HttpInstance
->Tcp4ChildHandle
,
660 &gEfiTcp4ProtocolGuid
,
661 (VOID
**) &Interface
,
662 HttpInstance
->Service
->Ip4DriverBindingHandle
,
663 HttpInstance
->Service
->ControllerHandle
,
664 EFI_OPEN_PROTOCOL_BY_DRIVER
667 if (EFI_ERROR (Status
)) {
671 Status
= gBS
->OpenProtocol (
672 HttpInstance
->Tcp4ChildHandle
,
673 &gEfiTcp4ProtocolGuid
,
674 (VOID
**) &HttpInstance
->Tcp4
,
675 HttpInstance
->Service
->Ip4DriverBindingHandle
,
676 HttpInstance
->Handle
,
677 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
679 if (EFI_ERROR(Status
)) {
683 Status
= gBS
->OpenProtocol (
684 HttpInstance
->Service
->Tcp4ChildHandle
,
685 &gEfiTcp4ProtocolGuid
,
686 (VOID
**) &Interface
,
687 HttpInstance
->Service
->Ip4DriverBindingHandle
,
688 HttpInstance
->Handle
,
689 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
691 if (EFI_ERROR(Status
)) {
696 // Create TCP6 Child.
698 Status
= NetLibCreateServiceChild (
699 HttpInstance
->Service
->ControllerHandle
,
700 HttpInstance
->Service
->Ip6DriverBindingHandle
,
701 &gEfiTcp6ServiceBindingProtocolGuid
,
702 &HttpInstance
->Tcp6ChildHandle
705 if (EFI_ERROR (Status
)) {
709 Status
= gBS
->OpenProtocol (
710 HttpInstance
->Tcp6ChildHandle
,
711 &gEfiTcp6ProtocolGuid
,
712 (VOID
**) &Interface
,
713 HttpInstance
->Service
->Ip6DriverBindingHandle
,
714 HttpInstance
->Service
->ControllerHandle
,
715 EFI_OPEN_PROTOCOL_BY_DRIVER
718 if (EFI_ERROR (Status
)) {
722 Status
= gBS
->OpenProtocol (
723 HttpInstance
->Tcp6ChildHandle
,
724 &gEfiTcp6ProtocolGuid
,
725 (VOID
**) &HttpInstance
->Tcp6
,
726 HttpInstance
->Service
->Ip6DriverBindingHandle
,
727 HttpInstance
->Handle
,
728 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
731 if (EFI_ERROR(Status
)) {
735 Status
= gBS
->OpenProtocol (
736 HttpInstance
->Service
->Tcp6ChildHandle
,
737 &gEfiTcp6ProtocolGuid
,
738 (VOID
**) &Interface
,
739 HttpInstance
->Service
->Ip6DriverBindingHandle
,
740 HttpInstance
->Handle
,
741 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
744 if (EFI_ERROR(Status
)) {
749 HttpInstance
->Url
= AllocateZeroPool (HTTP_URL_BUFFER_LEN
);
750 if (HttpInstance
->Url
== NULL
) {
751 Status
= EFI_OUT_OF_RESOURCES
;
759 if (HttpInstance
->Tcp4ChildHandle
!= NULL
) {
761 HttpInstance
->Tcp4ChildHandle
,
762 &gEfiTcp4ProtocolGuid
,
763 HttpInstance
->Service
->Ip4DriverBindingHandle
,
764 HttpInstance
->Service
->ControllerHandle
768 HttpInstance
->Tcp4ChildHandle
,
769 &gEfiTcp4ProtocolGuid
,
770 HttpInstance
->Service
->Ip4DriverBindingHandle
,
774 NetLibDestroyServiceChild (
775 HttpInstance
->Service
->ControllerHandle
,
776 HttpInstance
->Service
->Ip4DriverBindingHandle
,
777 &gEfiTcp4ServiceBindingProtocolGuid
,
778 HttpInstance
->Tcp4ChildHandle
782 if (HttpInstance
->Service
->Tcp4ChildHandle
!= NULL
) {
784 HttpInstance
->Service
->Tcp4ChildHandle
,
785 &gEfiTcp4ProtocolGuid
,
786 HttpInstance
->Service
->Ip4DriverBindingHandle
,
791 if (HttpInstance
->Tcp6ChildHandle
!= NULL
) {
793 HttpInstance
->Tcp6ChildHandle
,
794 &gEfiTcp6ProtocolGuid
,
795 HttpInstance
->Service
->Ip6DriverBindingHandle
,
796 HttpInstance
->Service
->ControllerHandle
800 HttpInstance
->Tcp6ChildHandle
,
801 &gEfiTcp6ProtocolGuid
,
802 HttpInstance
->Service
->Ip6DriverBindingHandle
,
806 NetLibDestroyServiceChild (
807 HttpInstance
->Service
->ControllerHandle
,
808 HttpInstance
->Service
->Ip6DriverBindingHandle
,
809 &gEfiTcp6ServiceBindingProtocolGuid
,
810 HttpInstance
->Tcp6ChildHandle
814 if (HttpInstance
->Service
->Tcp6ChildHandle
!= NULL
) {
816 HttpInstance
->Service
->Tcp6ChildHandle
,
817 &gEfiTcp6ProtocolGuid
,
818 HttpInstance
->Service
->Ip6DriverBindingHandle
,
823 return EFI_UNSUPPORTED
;
828 Clean up the HTTP child, release all the resources used by it.
830 @param[in] HttpInstance The HTTP child to clean up.
835 IN HTTP_PROTOCOL
*HttpInstance
838 HttpCloseConnection (HttpInstance
);
840 HttpCloseTcpConnCloseEvent (HttpInstance
);
842 if (HttpInstance
->TimeoutEvent
!= NULL
) {
843 gBS
->CloseEvent (HttpInstance
->TimeoutEvent
);
844 HttpInstance
->TimeoutEvent
= NULL
;
847 if (HttpInstance
->CacheBody
!= NULL
) {
848 FreePool (HttpInstance
->CacheBody
);
849 HttpInstance
->CacheBody
= NULL
;
850 HttpInstance
->NextMsg
= NULL
;
853 if (HttpInstance
->RemoteHost
!= NULL
) {
854 FreePool (HttpInstance
->RemoteHost
);
855 HttpInstance
->RemoteHost
= NULL
;
858 if (HttpInstance
->MsgParser
!= NULL
) {
859 HttpFreeMsgParser (HttpInstance
->MsgParser
);
860 HttpInstance
->MsgParser
= NULL
;
863 if (HttpInstance
->Url
!= NULL
) {
864 FreePool (HttpInstance
->Url
);
865 HttpInstance
->Url
= NULL
;
868 NetMapClean (&HttpInstance
->TxTokens
);
869 NetMapClean (&HttpInstance
->RxTokens
);
871 if (HttpInstance
->TlsSb
!= NULL
&& HttpInstance
->TlsChildHandle
!= NULL
) {
873 // Destroy the TLS instance.
875 HttpInstance
->TlsSb
->DestroyChild (HttpInstance
->TlsSb
, HttpInstance
->TlsChildHandle
);
878 if (HttpInstance
->Tcp4ChildHandle
!= NULL
) {
880 HttpInstance
->Tcp4ChildHandle
,
881 &gEfiTcp4ProtocolGuid
,
882 HttpInstance
->Service
->Ip4DriverBindingHandle
,
883 HttpInstance
->Service
->ControllerHandle
887 HttpInstance
->Tcp4ChildHandle
,
888 &gEfiTcp4ProtocolGuid
,
889 HttpInstance
->Service
->Ip4DriverBindingHandle
,
893 NetLibDestroyServiceChild (
894 HttpInstance
->Service
->ControllerHandle
,
895 HttpInstance
->Service
->Ip4DriverBindingHandle
,
896 &gEfiTcp4ServiceBindingProtocolGuid
,
897 HttpInstance
->Tcp4ChildHandle
901 if (HttpInstance
->Service
->Tcp4ChildHandle
!= NULL
) {
903 HttpInstance
->Service
->Tcp4ChildHandle
,
904 &gEfiTcp4ProtocolGuid
,
905 HttpInstance
->Service
->Ip4DriverBindingHandle
,
910 if (HttpInstance
->Tcp6ChildHandle
!= NULL
) {
912 HttpInstance
->Tcp6ChildHandle
,
913 &gEfiTcp6ProtocolGuid
,
914 HttpInstance
->Service
->Ip6DriverBindingHandle
,
915 HttpInstance
->Service
->ControllerHandle
919 HttpInstance
->Tcp6ChildHandle
,
920 &gEfiTcp6ProtocolGuid
,
921 HttpInstance
->Service
->Ip6DriverBindingHandle
,
925 NetLibDestroyServiceChild (
926 HttpInstance
->Service
->ControllerHandle
,
927 HttpInstance
->Service
->Ip6DriverBindingHandle
,
928 &gEfiTcp6ServiceBindingProtocolGuid
,
929 HttpInstance
->Tcp6ChildHandle
933 if (HttpInstance
->Service
->Tcp6ChildHandle
!= NULL
) {
935 HttpInstance
->Service
->Tcp6ChildHandle
,
936 &gEfiTcp6ProtocolGuid
,
937 HttpInstance
->Service
->Ip6DriverBindingHandle
,
942 TlsCloseTxRxEvent (HttpInstance
);
946 Establish TCP connection with HTTP server.
948 @param[in] HttpInstance The HTTP instance private data.
950 @retval EFI_SUCCESS The TCP connection is established.
951 @retval Others Other error as indicated.
955 HttpCreateConnection (
956 IN HTTP_PROTOCOL
*HttpInstance
962 // Connect to Http server
964 if (!HttpInstance
->LocalAddressIsIPv6
) {
965 HttpInstance
->IsTcp4ConnDone
= FALSE
;
966 HttpInstance
->Tcp4ConnToken
.CompletionToken
.Status
= EFI_NOT_READY
;
967 Status
= HttpInstance
->Tcp4
->Connect (HttpInstance
->Tcp4
, &HttpInstance
->Tcp4ConnToken
);
968 if (EFI_ERROR (Status
)) {
969 DEBUG ((EFI_D_ERROR
, "HttpCreateConnection: Tcp4->Connect() = %r\n", Status
));
973 while (!HttpInstance
->IsTcp4ConnDone
) {
974 HttpInstance
->Tcp4
->Poll (HttpInstance
->Tcp4
);
977 Status
= HttpInstance
->Tcp4ConnToken
.CompletionToken
.Status
;
980 HttpInstance
->IsTcp6ConnDone
= FALSE
;
981 HttpInstance
->Tcp6ConnToken
.CompletionToken
.Status
= EFI_NOT_READY
;
982 Status
= HttpInstance
->Tcp6
->Connect (HttpInstance
->Tcp6
, &HttpInstance
->Tcp6ConnToken
);
983 if (EFI_ERROR (Status
)) {
984 DEBUG ((EFI_D_ERROR
, "HttpCreateConnection: Tcp6->Connect() = %r\n", Status
));
988 while(!HttpInstance
->IsTcp6ConnDone
) {
989 HttpInstance
->Tcp6
->Poll (HttpInstance
->Tcp6
);
992 Status
= HttpInstance
->Tcp6ConnToken
.CompletionToken
.Status
;
995 if (!EFI_ERROR (Status
)) {
996 HttpInstance
->State
= HTTP_STATE_TCP_CONNECTED
;
1003 Close existing TCP connection.
1005 @param[in] HttpInstance The HTTP instance private data.
1007 @retval EFI_SUCCESS The TCP connection is closed.
1008 @retval Others Other error as indicated.
1012 HttpCloseConnection (
1013 IN HTTP_PROTOCOL
*HttpInstance
1018 if (HttpInstance
->State
== HTTP_STATE_TCP_CONNECTED
) {
1020 if (HttpInstance
->LocalAddressIsIPv6
) {
1021 HttpInstance
->Tcp6CloseToken
.AbortOnClose
= TRUE
;
1022 HttpInstance
->IsTcp6CloseDone
= FALSE
;
1023 Status
= HttpInstance
->Tcp6
->Close (HttpInstance
->Tcp6
, &HttpInstance
->Tcp6CloseToken
);
1024 if (EFI_ERROR (Status
)) {
1028 while (!HttpInstance
->IsTcp6CloseDone
) {
1029 HttpInstance
->Tcp6
->Poll (HttpInstance
->Tcp6
);
1033 HttpInstance
->Tcp4CloseToken
.AbortOnClose
= TRUE
;
1034 HttpInstance
->IsTcp4CloseDone
= FALSE
;
1035 Status
= HttpInstance
->Tcp4
->Close (HttpInstance
->Tcp4
, &HttpInstance
->Tcp4CloseToken
);
1036 if (EFI_ERROR (Status
)) {
1040 while (!HttpInstance
->IsTcp4CloseDone
) {
1041 HttpInstance
->Tcp4
->Poll (HttpInstance
->Tcp4
);
1047 HttpInstance
->State
= HTTP_STATE_TCP_CLOSED
;
1052 Configure TCP4 protocol child.
1054 @param[in] HttpInstance The HTTP instance private data.
1055 @param[in] Wrap The HTTP token's wrap data.
1057 @retval EFI_SUCCESS The TCP4 protocol child is configured.
1058 @retval Others Other error as indicated.
1063 IN HTTP_PROTOCOL
*HttpInstance
,
1064 IN HTTP_TOKEN_WRAP
*Wrap
1068 EFI_TCP4_CONFIG_DATA
*Tcp4CfgData
;
1069 EFI_TCP4_ACCESS_POINT
*Tcp4AP
;
1070 EFI_TCP4_OPTION
*Tcp4Option
;
1072 ASSERT (HttpInstance
!= NULL
);
1075 Tcp4CfgData
= &HttpInstance
->Tcp4CfgData
;
1076 ZeroMem (Tcp4CfgData
, sizeof (EFI_TCP4_CONFIG_DATA
));
1078 Tcp4CfgData
->TypeOfService
= HTTP_TOS_DEAULT
;
1079 Tcp4CfgData
->TimeToLive
= HTTP_TTL_DEAULT
;
1080 Tcp4CfgData
->ControlOption
= &HttpInstance
->Tcp4Option
;
1082 Tcp4AP
= &Tcp4CfgData
->AccessPoint
;
1083 Tcp4AP
->UseDefaultAddress
= HttpInstance
->IPv4Node
.UseDefaultAddress
;
1084 if (!Tcp4AP
->UseDefaultAddress
) {
1085 IP4_COPY_ADDRESS (&Tcp4AP
->StationAddress
, &HttpInstance
->IPv4Node
.LocalAddress
);
1086 IP4_COPY_ADDRESS (&Tcp4AP
->SubnetMask
, &HttpInstance
->IPv4Node
.LocalSubnet
);
1089 Tcp4AP
->StationPort
= HttpInstance
->IPv4Node
.LocalPort
;
1090 Tcp4AP
->RemotePort
= HttpInstance
->RemotePort
;
1091 Tcp4AP
->ActiveFlag
= TRUE
;
1092 IP4_COPY_ADDRESS (&Tcp4AP
->RemoteAddress
, &HttpInstance
->RemoteAddr
);
1094 Tcp4Option
= Tcp4CfgData
->ControlOption
;
1095 Tcp4Option
->ReceiveBufferSize
= HTTP_BUFFER_SIZE_DEAULT
;
1096 Tcp4Option
->SendBufferSize
= HTTP_BUFFER_SIZE_DEAULT
;
1097 Tcp4Option
->MaxSynBackLog
= HTTP_MAX_SYN_BACK_LOG
;
1098 Tcp4Option
->ConnectionTimeout
= HTTP_CONNECTION_TIMEOUT
;
1099 Tcp4Option
->DataRetries
= HTTP_DATA_RETRIES
;
1100 Tcp4Option
->FinTimeout
= HTTP_FIN_TIMEOUT
;
1101 Tcp4Option
->KeepAliveProbes
= HTTP_KEEP_ALIVE_PROBES
;
1102 Tcp4Option
->KeepAliveTime
= HTTP_KEEP_ALIVE_TIME
;
1103 Tcp4Option
->KeepAliveInterval
= HTTP_KEEP_ALIVE_INTERVAL
;
1104 Tcp4Option
->EnableNagle
= TRUE
;
1105 Tcp4CfgData
->ControlOption
= Tcp4Option
;
1107 Status
= HttpInstance
->Tcp4
->Configure (HttpInstance
->Tcp4
, Tcp4CfgData
);
1108 if (EFI_ERROR (Status
)) {
1109 DEBUG ((EFI_D_ERROR
, "HttpConfigureTcp4 - %r\n", Status
));
1113 Status
= HttpCreateTcpConnCloseEvent (HttpInstance
);
1114 if (EFI_ERROR (Status
)) {
1118 Status
= HttpCreateTcpTxEvent (Wrap
);
1119 if (EFI_ERROR (Status
)) {
1123 HttpInstance
->State
= HTTP_STATE_TCP_CONFIGED
;
1129 Configure TCP6 protocol child.
1131 @param[in] HttpInstance The HTTP instance private data.
1132 @param[in] Wrap The HTTP token's wrap data.
1134 @retval EFI_SUCCESS The TCP6 protocol child is configured.
1135 @retval Others Other error as indicated.
1140 IN HTTP_PROTOCOL
*HttpInstance
,
1141 IN HTTP_TOKEN_WRAP
*Wrap
1145 EFI_TCP6_CONFIG_DATA
*Tcp6CfgData
;
1146 EFI_TCP6_ACCESS_POINT
*Tcp6Ap
;
1147 EFI_TCP6_OPTION
*Tcp6Option
;
1149 ASSERT (HttpInstance
!= NULL
);
1151 Tcp6CfgData
= &HttpInstance
->Tcp6CfgData
;
1152 ZeroMem (Tcp6CfgData
, sizeof (EFI_TCP6_CONFIG_DATA
));
1154 Tcp6CfgData
->TrafficClass
= 0;
1155 Tcp6CfgData
->HopLimit
= 255;
1156 Tcp6CfgData
->ControlOption
= &HttpInstance
->Tcp6Option
;
1158 Tcp6Ap
= &Tcp6CfgData
->AccessPoint
;
1159 Tcp6Ap
->ActiveFlag
= TRUE
;
1160 Tcp6Ap
->StationPort
= HttpInstance
->Ipv6Node
.LocalPort
;
1161 Tcp6Ap
->RemotePort
= HttpInstance
->RemotePort
;
1162 IP6_COPY_ADDRESS (&Tcp6Ap
->StationAddress
, &HttpInstance
->Ipv6Node
.LocalAddress
);
1163 IP6_COPY_ADDRESS (&Tcp6Ap
->RemoteAddress
, &HttpInstance
->RemoteIpv6Addr
);
1165 Tcp6Option
= Tcp6CfgData
->ControlOption
;
1166 Tcp6Option
->ReceiveBufferSize
= HTTP_BUFFER_SIZE_DEAULT
;
1167 Tcp6Option
->SendBufferSize
= HTTP_BUFFER_SIZE_DEAULT
;
1168 Tcp6Option
->MaxSynBackLog
= HTTP_MAX_SYN_BACK_LOG
;
1169 Tcp6Option
->ConnectionTimeout
= HTTP_CONNECTION_TIMEOUT
;
1170 Tcp6Option
->DataRetries
= HTTP_DATA_RETRIES
;
1171 Tcp6Option
->FinTimeout
= HTTP_FIN_TIMEOUT
;
1172 Tcp6Option
->KeepAliveProbes
= HTTP_KEEP_ALIVE_PROBES
;
1173 Tcp6Option
->KeepAliveTime
= HTTP_KEEP_ALIVE_TIME
;
1174 Tcp6Option
->KeepAliveInterval
= HTTP_KEEP_ALIVE_INTERVAL
;
1175 Tcp6Option
->EnableNagle
= TRUE
;
1177 Status
= HttpInstance
->Tcp6
->Configure (HttpInstance
->Tcp6
, Tcp6CfgData
);
1178 if (EFI_ERROR (Status
)) {
1179 DEBUG ((EFI_D_ERROR
, "HttpConfigureTcp6 - %r\n", Status
));
1183 Status
= HttpCreateTcpConnCloseEvent (HttpInstance
);
1184 if (EFI_ERROR (Status
)) {
1188 Status
= HttpCreateTcpTxEvent (Wrap
);
1189 if (EFI_ERROR (Status
)) {
1193 HttpInstance
->State
= HTTP_STATE_TCP_CONFIGED
;
1200 Check existing TCP connection, if in error state, recover TCP4 connection. Then,
1201 connect one TLS session if required.
1203 @param[in] HttpInstance The HTTP instance private data.
1205 @retval EFI_SUCCESS The TCP connection is established.
1206 @retval EFI_NOT_READY TCP4 protocol child is not created or configured.
1207 @retval Others Other error as indicated.
1212 IN HTTP_PROTOCOL
*HttpInstance
1216 EFI_TCP4_CONNECTION_STATE Tcp4State
;
1219 if (HttpInstance
->State
< HTTP_STATE_TCP_CONFIGED
|| HttpInstance
->Tcp4
== NULL
) {
1220 return EFI_NOT_READY
;
1223 Status
= HttpInstance
->Tcp4
->GetModeData(
1231 if (EFI_ERROR(Status
)){
1232 DEBUG ((EFI_D_ERROR
, "Tcp4 GetModeData fail - %x\n", Status
));
1236 if (Tcp4State
== Tcp4StateEstablished
) {
1238 } else if (Tcp4State
> Tcp4StateEstablished
) {
1239 HttpCloseConnection(HttpInstance
);
1242 Status
= HttpCreateConnection (HttpInstance
);
1243 if (EFI_ERROR(Status
)){
1244 DEBUG ((EFI_D_ERROR
, "Tcp4 Connection fail - %x\n", Status
));
1249 // Tls session connection.
1251 if (HttpInstance
->UseHttps
) {
1252 if (HttpInstance
->TimeoutEvent
== NULL
) {
1254 // Create TimeoutEvent for TLS connection.
1256 Status
= gBS
->CreateEvent (
1261 &HttpInstance
->TimeoutEvent
1263 if (EFI_ERROR (Status
)) {
1264 TlsCloseTxRxEvent (HttpInstance
);
1270 // Start the timer, and wait Timeout seconds for connection.
1272 Status
= gBS
->SetTimer (HttpInstance
->TimeoutEvent
, TimerRelative
, HTTP_CONNECTION_TIMEOUT
* TICKS_PER_SECOND
);
1273 if (EFI_ERROR (Status
)) {
1274 TlsCloseTxRxEvent (HttpInstance
);
1278 Status
= TlsConnectSession (HttpInstance
, HttpInstance
->TimeoutEvent
);
1280 gBS
->SetTimer (HttpInstance
->TimeoutEvent
, TimerCancel
, 0);
1282 if (EFI_ERROR (Status
)) {
1283 TlsCloseTxRxEvent (HttpInstance
);
1292 Check existing TCP connection, if in error state, recover TCP6 connection. Then,
1293 connect one TLS session if required.
1295 @param[in] HttpInstance The HTTP instance private data.
1297 @retval EFI_SUCCESS The TCP connection is established.
1298 @retval EFI_NOT_READY TCP6 protocol child is not created or configured.
1299 @retval Others Other error as indicated.
1304 IN HTTP_PROTOCOL
*HttpInstance
1308 EFI_TCP6_CONNECTION_STATE Tcp6State
;
1310 if (HttpInstance
->State
< HTTP_STATE_TCP_CONFIGED
|| HttpInstance
->Tcp6
== NULL
) {
1311 return EFI_NOT_READY
;
1314 Status
= HttpInstance
->Tcp6
->GetModeData (
1323 if (EFI_ERROR(Status
)){
1324 DEBUG ((EFI_D_ERROR
, "Tcp6 GetModeData fail - %x\n", Status
));
1328 if (Tcp6State
== Tcp6StateEstablished
) {
1330 } else if (Tcp6State
> Tcp6StateEstablished
) {
1331 HttpCloseConnection(HttpInstance
);
1334 Status
= HttpCreateConnection (HttpInstance
);
1335 if (EFI_ERROR(Status
)){
1336 DEBUG ((EFI_D_ERROR
, "Tcp6 Connection fail - %x\n", Status
));
1341 // Tls session connection.
1343 if (HttpInstance
->UseHttps
) {
1344 if (HttpInstance
->TimeoutEvent
== NULL
) {
1346 // Create TimeoutEvent for TLS connection.
1348 Status
= gBS
->CreateEvent (
1353 &HttpInstance
->TimeoutEvent
1355 if (EFI_ERROR (Status
)) {
1356 TlsCloseTxRxEvent (HttpInstance
);
1362 // Start the timer, and wait Timeout seconds for connection.
1364 Status
= gBS
->SetTimer (HttpInstance
->TimeoutEvent
, TimerRelative
, HTTP_CONNECTION_TIMEOUT
* TICKS_PER_SECOND
);
1365 if (EFI_ERROR (Status
)) {
1366 TlsCloseTxRxEvent (HttpInstance
);
1370 Status
= TlsConnectSession (HttpInstance
, HttpInstance
->TimeoutEvent
);
1372 gBS
->SetTimer (HttpInstance
->TimeoutEvent
, TimerCancel
, 0);
1374 if (EFI_ERROR (Status
)) {
1375 TlsCloseTxRxEvent (HttpInstance
);
1384 Initialize Http session.
1386 @param[in] HttpInstance The HTTP instance private data.
1387 @param[in] Wrap The HTTP token's wrap data.
1388 @param[in] Configure The Flag indicates whether need to initialize session.
1389 @param[in] TlsConfigure The Flag indicates whether it's the new Tls session.
1391 @retval EFI_SUCCESS The initialization of session is done.
1392 @retval Others Other error as indicated.
1397 IN HTTP_PROTOCOL
*HttpInstance
,
1398 IN HTTP_TOKEN_WRAP
*Wrap
,
1399 IN BOOLEAN Configure
,
1400 IN BOOLEAN TlsConfigure
1404 ASSERT (HttpInstance
!= NULL
);
1407 // Configure Tls session.
1410 Status
= TlsConfigureSession (HttpInstance
);
1411 if (EFI_ERROR (Status
)) {
1416 if (!HttpInstance
->LocalAddressIsIPv6
) {
1418 // Configure TCP instance.
1421 Status
= HttpConfigureTcp4 (HttpInstance
, Wrap
);
1422 if (EFI_ERROR (Status
)) {
1430 Status
= HttpConnectTcp4 (HttpInstance
);
1431 if (EFI_ERROR (Status
)) {
1436 // Configure TCP instance.
1439 Status
= HttpConfigureTcp6 (HttpInstance
, Wrap
);
1440 if (EFI_ERROR (Status
)) {
1448 Status
= HttpConnectTcp6 (HttpInstance
);
1449 if (EFI_ERROR (Status
)) {
1459 Send the HTTP or HTTPS message through TCP4 or TCP6.
1461 @param[in] HttpInstance The HTTP instance private data.
1462 @param[in] Wrap The HTTP token's wrap data.
1463 @param[in] TxString Buffer containing the HTTP message string.
1464 @param[in] TxStringLen Length of the HTTP message string in bytes.
1466 @retval EFI_SUCCESS The HTTP message is queued into TCP transmit queue.
1467 @retval Others Other error as indicated.
1472 IN HTTP_PROTOCOL
*HttpInstance
,
1473 IN HTTP_TOKEN_WRAP
*Wrap
,
1475 IN UINTN TxStringLen
1479 EFI_TCP4_IO_TOKEN
*Tx4Token
;
1480 EFI_TCP4_PROTOCOL
*Tcp4
;
1481 EFI_TCP6_IO_TOKEN
*Tx6Token
;
1482 EFI_TCP6_PROTOCOL
*Tcp6
;
1485 NET_FRAGMENT TempFragment
;
1486 NET_FRAGMENT Fragment
;
1490 Status
= EFI_SUCCESS
;
1493 TempFragment
.Len
= 0;
1494 TempFragment
.Bulk
= NULL
;
1496 Fragment
.Bulk
= NULL
;
1501 // Need to encrypt data.
1503 if (HttpInstance
->UseHttps
) {
1505 // Allocate enough buffer for each TLS plaintext records.
1507 TlsRecord
= AllocateZeroPool (TLS_RECORD_HEADER_LENGTH
+ TLS_PLAINTEXT_RECORD_MAX_PAYLOAD_LENGTH
);
1508 if (TlsRecord
== NULL
) {
1509 Status
= EFI_OUT_OF_RESOURCES
;
1514 // Allocate enough buffer for all TLS ciphertext records.
1516 RecordCount
= TxStringLen
/ TLS_PLAINTEXT_RECORD_MAX_PAYLOAD_LENGTH
+ 1;
1517 Fragment
.Bulk
= AllocateZeroPool (RecordCount
* (TLS_RECORD_HEADER_LENGTH
+ TLS_CIPHERTEXT_RECORD_MAX_PAYLOAD_LENGTH
));
1518 if (Fragment
.Bulk
== NULL
) {
1519 Status
= EFI_OUT_OF_RESOURCES
;
1524 // Encrypt each TLS plaintext records.
1526 RemainingLen
= TxStringLen
;
1527 while (RemainingLen
!= 0) {
1528 PayloadSize
= (UINT16
) MIN (TLS_PLAINTEXT_RECORD_MAX_PAYLOAD_LENGTH
, RemainingLen
);
1530 ((TLS_RECORD_HEADER
*) TlsRecord
)->ContentType
= TlsContentTypeApplicationData
;
1531 ((TLS_RECORD_HEADER
*) TlsRecord
)->Version
.Major
= HttpInstance
->TlsConfigData
.Version
.Major
;
1532 ((TLS_RECORD_HEADER
*) TlsRecord
)->Version
.Minor
= HttpInstance
->TlsConfigData
.Version
.Minor
;
1533 ((TLS_RECORD_HEADER
*) TlsRecord
)->Length
= PayloadSize
;
1535 CopyMem (TlsRecord
+ TLS_RECORD_HEADER_LENGTH
, TxString
+ (TxStringLen
- RemainingLen
), PayloadSize
);
1537 Status
= TlsProcessMessage (
1540 TLS_RECORD_HEADER_LENGTH
+ PayloadSize
,
1544 if (EFI_ERROR (Status
)) {
1549 // Record the processed/encrypted Packet.
1551 CopyMem (Fragment
.Bulk
+ Fragment
.Len
, TempFragment
.Bulk
, TempFragment
.Len
);
1552 Fragment
.Len
+= TempFragment
.Len
;
1554 FreePool (TempFragment
.Bulk
);
1555 TempFragment
.Len
= 0;
1556 TempFragment
.Bulk
= NULL
;
1558 RemainingLen
-= (UINTN
) PayloadSize
;
1559 ZeroMem (TlsRecord
, TLS_RECORD_HEADER_LENGTH
+ TLS_PLAINTEXT_RECORD_MAX_PAYLOAD_LENGTH
);
1562 FreePool (TlsRecord
);
1566 if (!HttpInstance
->LocalAddressIsIPv6
) {
1567 Tcp4
= HttpInstance
->Tcp4
;
1568 Tx4Token
= &Wrap
->TcpWrap
.Tx4Token
;
1570 if (HttpInstance
->UseHttps
) {
1571 Tx4Token
->Packet
.TxData
->DataLength
= Fragment
.Len
;
1572 Tx4Token
->Packet
.TxData
->FragmentTable
[0].FragmentLength
= Fragment
.Len
;
1573 Tx4Token
->Packet
.TxData
->FragmentTable
[0].FragmentBuffer
= (VOID
*) Fragment
.Bulk
;
1575 Tx4Token
->Packet
.TxData
->DataLength
= (UINT32
) TxStringLen
;
1576 Tx4Token
->Packet
.TxData
->FragmentTable
[0].FragmentLength
= (UINT32
) TxStringLen
;
1577 Tx4Token
->Packet
.TxData
->FragmentTable
[0].FragmentBuffer
= (VOID
*) TxString
;
1580 Tx4Token
->CompletionToken
.Status
= EFI_NOT_READY
;
1582 Wrap
->TcpWrap
.IsTxDone
= FALSE
;
1583 Status
= Tcp4
->Transmit (Tcp4
, Tx4Token
);
1584 if (EFI_ERROR (Status
)) {
1585 DEBUG ((EFI_D_ERROR
, "Transmit failed: %r\n", Status
));
1590 Tcp6
= HttpInstance
->Tcp6
;
1591 Tx6Token
= &Wrap
->TcpWrap
.Tx6Token
;
1593 if (HttpInstance
->UseHttps
) {
1594 Tx6Token
->Packet
.TxData
->DataLength
= Fragment
.Len
;
1595 Tx6Token
->Packet
.TxData
->FragmentTable
[0].FragmentLength
= Fragment
.Len
;
1596 Tx6Token
->Packet
.TxData
->FragmentTable
[0].FragmentBuffer
= (VOID
*) Fragment
.Bulk
;
1598 Tx6Token
->Packet
.TxData
->DataLength
= (UINT32
) TxStringLen
;
1599 Tx6Token
->Packet
.TxData
->FragmentTable
[0].FragmentLength
= (UINT32
) TxStringLen
;
1600 Tx6Token
->Packet
.TxData
->FragmentTable
[0].FragmentBuffer
= (VOID
*) TxString
;
1603 Tx6Token
->CompletionToken
.Status
= EFI_NOT_READY
;
1605 Wrap
->TcpWrap
.IsTxDone
= FALSE
;
1606 Status
= Tcp6
->Transmit (Tcp6
, Tx6Token
);
1607 if (EFI_ERROR (Status
)) {
1608 DEBUG ((EFI_D_ERROR
, "Transmit failed: %r\n", Status
));
1617 if (HttpInstance
->UseHttps
) {
1618 if (TlsRecord
!= NULL
) {
1619 FreePool (TlsRecord
);
1623 if (Fragment
.Bulk
!= NULL
) {
1624 FreePool (Fragment
.Bulk
);
1625 Fragment
.Bulk
= NULL
;
1633 Check whether the user's token or event has already
1634 been enqueue on HTTP Tx or Rx Token list.
1636 @param[in] Map The container of either user's transmit or receive
1638 @param[in] Item Current item to check against.
1639 @param[in] Context The Token to check againist.
1641 @retval EFI_ACCESS_DENIED The token or event has already been enqueued in IP
1642 @retval EFI_SUCCESS The current item isn't the same token/event as the
1650 IN NET_MAP_ITEM
*Item
,
1654 EFI_HTTP_TOKEN
*Token
;
1655 EFI_HTTP_TOKEN
*TokenInItem
;
1657 Token
= (EFI_HTTP_TOKEN
*) Context
;
1658 TokenInItem
= (EFI_HTTP_TOKEN
*) Item
->Key
;
1660 if (Token
== TokenInItem
|| Token
->Event
== TokenInItem
->Event
) {
1661 return EFI_ACCESS_DENIED
;
1668 Check whether the HTTP message associated with Tx4Token or Tx6Token is already sent out.
1670 @param[in] Map The container of Tx4Token or Tx6Token.
1671 @param[in] Item Current item to check against.
1672 @param[in] Context The Token to check againist.
1674 @retval EFI_NOT_READY The HTTP message is still queued in the list.
1675 @retval EFI_SUCCESS The HTTP message has been sent out.
1682 IN NET_MAP_ITEM
*Item
,
1686 HTTP_TOKEN_WRAP
*ValueInItem
;
1688 ValueInItem
= (HTTP_TOKEN_WRAP
*) Item
->Value
;
1690 if (!ValueInItem
->TcpWrap
.IsTxDone
) {
1691 return EFI_NOT_READY
;
1698 Transmit the HTTP or HTTPS mssage by processing the associated HTTP token.
1700 @param[in] Map The container of Tx4Token or Tx6Token.
1701 @param[in] Item Current item to check against.
1702 @param[in] Context The Token to check againist.
1704 @retval EFI_OUT_OF_RESOURCES Failed to allocate resources.
1705 @retval EFI_SUCCESS The HTTP message is queued into TCP transmit
1713 IN NET_MAP_ITEM
*Item
,
1717 HTTP_TOKEN_WRAP
*ValueInItem
;
1722 UINTN RequestMsgSize
;
1726 ValueInItem
= (HTTP_TOKEN_WRAP
*) Item
->Value
;
1727 if (ValueInItem
->TcpWrap
.IsTxDone
) {
1732 // Parse the URI of the remote host.
1734 UrlSize
= StrLen (ValueInItem
->HttpToken
->Message
->Data
.Request
->Url
) + 1;
1735 Url
= AllocatePool (UrlSize
);
1737 return EFI_OUT_OF_RESOURCES
;
1740 UnicodeStrToAsciiStrS (ValueInItem
->HttpToken
->Message
->Data
.Request
->Url
, Url
, UrlSize
);
1743 // Create request message.
1745 Status
= HttpGenRequestMessage (
1746 ValueInItem
->HttpToken
->Message
,
1753 if (EFI_ERROR (Status
) || NULL
== RequestMsg
){
1757 ASSERT (RequestMsg
!= NULL
);
1760 // Transmit the request message.
1762 Status
= HttpTransmitTcp (
1763 ValueInItem
->HttpInstance
,
1765 (UINT8
*) RequestMsg
,
1768 FreePool (RequestMsg
);
1773 Receive the HTTP response by processing the associated HTTP token.
1775 @param[in] Map The container of Rx4Token or Rx6Token.
1776 @param[in] Item Current item to check against.
1777 @param[in] Context The Token to check againist.
1779 @retval EFI_SUCCESS The HTTP response is queued into TCP receive
1781 @retval Others Other error as indicated.
1788 IN NET_MAP_ITEM
*Item
,
1793 // Process the queued HTTP response.
1795 return HttpResponseWorker ((HTTP_TOKEN_WRAP
*) Item
->Value
);
1799 Receive the HTTP header by processing the associated HTTP token.
1801 @param[in] HttpInstance The HTTP instance private data.
1802 @param[in, out] SizeofHeaders The HTTP header length.
1803 @param[in, out] BufferSize The size of buffer to cacahe the header message.
1804 @param[in] Timeout The time to wait for receiving the header packet.
1806 @retval EFI_SUCCESS The HTTP header is received.
1807 @retval Others Other errors as indicated.
1811 HttpTcpReceiveHeader (
1812 IN HTTP_PROTOCOL
*HttpInstance
,
1813 IN OUT UINTN
*SizeofHeaders
,
1814 IN OUT UINTN
*BufferSize
,
1815 IN EFI_EVENT Timeout
1819 EFI_TCP4_IO_TOKEN
*Rx4Token
;
1820 EFI_TCP4_PROTOCOL
*Tcp4
;
1821 EFI_TCP6_IO_TOKEN
*Rx6Token
;
1822 EFI_TCP6_PROTOCOL
*Tcp6
;
1823 CHAR8
**EndofHeader
;
1824 CHAR8
**HttpHeaders
;
1826 NET_FRAGMENT Fragment
;
1828 ASSERT (HttpInstance
!= NULL
);
1830 EndofHeader
= HttpInstance
->EndofHeader
;
1831 HttpHeaders
= HttpInstance
->HttpHeaders
;
1832 Tcp4
= HttpInstance
->Tcp4
;
1833 Tcp6
= HttpInstance
->Tcp6
;
1838 Fragment
.Bulk
= NULL
;
1840 if (HttpInstance
->LocalAddressIsIPv6
) {
1841 ASSERT (Tcp6
!= NULL
);
1843 ASSERT (Tcp4
!= NULL
);
1846 if (!HttpInstance
->UseHttps
) {
1847 Status
= HttpCreateTcpRxEventForHeader (HttpInstance
);
1848 if (EFI_ERROR (Status
)) {
1853 if (!HttpInstance
->LocalAddressIsIPv6
) {
1854 if (!HttpInstance
->UseHttps
) {
1855 Rx4Token
= &HttpInstance
->Rx4Token
;
1856 Rx4Token
->Packet
.RxData
->FragmentTable
[0].FragmentBuffer
= AllocateZeroPool (DEF_BUF_LEN
);
1857 if (Rx4Token
->Packet
.RxData
->FragmentTable
[0].FragmentBuffer
== NULL
) {
1858 Status
= EFI_OUT_OF_RESOURCES
;
1864 // Receive the HTTP headers only when EFI_HTTP_RESPONSE_DATA is not NULL.
1866 while (*EndofHeader
== NULL
) {
1867 if (!HttpInstance
->UseHttps
) {
1868 HttpInstance
->IsRxDone
= FALSE
;
1869 Rx4Token
->Packet
.RxData
->DataLength
= DEF_BUF_LEN
;
1870 Rx4Token
->Packet
.RxData
->FragmentTable
[0].FragmentLength
= DEF_BUF_LEN
;
1871 Status
= Tcp4
->Receive (Tcp4
, Rx4Token
);
1872 if (EFI_ERROR (Status
)) {
1873 DEBUG ((EFI_D_ERROR
, "Tcp4 receive failed: %r\n", Status
));
1877 while (!HttpInstance
->IsRxDone
&& ((Timeout
== NULL
) || EFI_ERROR (gBS
->CheckEvent (Timeout
)))) {
1881 if (!HttpInstance
->IsRxDone
) {
1883 // Cancle the Token before close its Event.
1885 Tcp4
->Cancel (HttpInstance
->Tcp4
, &Rx4Token
->CompletionToken
);
1886 gBS
->CloseEvent (Rx4Token
->CompletionToken
.Event
);
1887 Rx4Token
->CompletionToken
.Status
= EFI_TIMEOUT
;
1890 Status
= Rx4Token
->CompletionToken
.Status
;
1891 if (EFI_ERROR (Status
)) {
1895 Fragment
.Len
= Rx4Token
->Packet
.RxData
->FragmentTable
[0].FragmentLength
;
1896 Fragment
.Bulk
= (UINT8
*) Rx4Token
->Packet
.RxData
->FragmentTable
[0].FragmentBuffer
;
1898 if (Fragment
.Bulk
!= NULL
) {
1899 FreePool (Fragment
.Bulk
);
1900 Fragment
.Bulk
= NULL
;
1903 Status
= HttpsReceive (HttpInstance
, &Fragment
, Timeout
);
1904 if (EFI_ERROR (Status
)) {
1905 DEBUG ((EFI_D_ERROR
, "Tcp4 receive failed: %r\n", Status
));
1911 // Append the response string along with a Null-terminator.
1913 *BufferSize
= *SizeofHeaders
+ Fragment
.Len
;
1914 Buffer
= AllocatePool (*BufferSize
+ 1);
1915 if (Buffer
== NULL
) {
1916 Status
= EFI_OUT_OF_RESOURCES
;
1920 if (*HttpHeaders
!= NULL
) {
1921 CopyMem (Buffer
, *HttpHeaders
, *SizeofHeaders
);
1922 FreePool (*HttpHeaders
);
1926 Buffer
+ *SizeofHeaders
,
1930 *(Buffer
+ *BufferSize
) = '\0';
1931 *HttpHeaders
= Buffer
;
1932 *SizeofHeaders
= *BufferSize
;
1935 // Check whether we received end of HTTP headers.
1937 *EndofHeader
= AsciiStrStr (*HttpHeaders
, HTTP_END_OF_HDR_STR
);
1943 if (Rx4Token
!= NULL
&& Rx4Token
->Packet
.RxData
!= NULL
&& Rx4Token
->Packet
.RxData
->FragmentTable
[0].FragmentBuffer
!= NULL
) {
1944 FreePool (Rx4Token
->Packet
.RxData
->FragmentTable
[0].FragmentBuffer
);
1945 Rx4Token
->Packet
.RxData
->FragmentTable
[0].FragmentBuffer
= NULL
;
1946 Fragment
.Bulk
= NULL
;
1949 if (Fragment
.Bulk
!= NULL
) {
1950 FreePool (Fragment
.Bulk
);
1951 Fragment
.Bulk
= NULL
;
1954 if (!HttpInstance
->UseHttps
) {
1955 Rx6Token
= &HttpInstance
->Rx6Token
;
1956 Rx6Token
->Packet
.RxData
->FragmentTable
[0].FragmentBuffer
= AllocateZeroPool (DEF_BUF_LEN
);
1957 if (Rx6Token
->Packet
.RxData
->FragmentTable
[0].FragmentBuffer
== NULL
) {
1958 Status
= EFI_OUT_OF_RESOURCES
;
1964 // Receive the HTTP headers only when EFI_HTTP_RESPONSE_DATA is not NULL.
1966 while (*EndofHeader
== NULL
) {
1967 if (!HttpInstance
->UseHttps
) {
1968 HttpInstance
->IsRxDone
= FALSE
;
1969 Rx6Token
->Packet
.RxData
->DataLength
= DEF_BUF_LEN
;
1970 Rx6Token
->Packet
.RxData
->FragmentTable
[0].FragmentLength
= DEF_BUF_LEN
;
1971 Status
= Tcp6
->Receive (Tcp6
, Rx6Token
);
1972 if (EFI_ERROR (Status
)) {
1973 DEBUG ((EFI_D_ERROR
, "Tcp6 receive failed: %r\n", Status
));
1977 while (!HttpInstance
->IsRxDone
&& ((Timeout
== NULL
) || EFI_ERROR (gBS
->CheckEvent (Timeout
)))) {
1981 if (!HttpInstance
->IsRxDone
) {
1983 // Cancle the Token before close its Event.
1985 Tcp6
->Cancel (HttpInstance
->Tcp6
, &Rx6Token
->CompletionToken
);
1986 gBS
->CloseEvent (Rx6Token
->CompletionToken
.Event
);
1987 Rx6Token
->CompletionToken
.Status
= EFI_TIMEOUT
;
1990 Status
= Rx6Token
->CompletionToken
.Status
;
1991 if (EFI_ERROR (Status
)) {
1995 Fragment
.Len
= Rx6Token
->Packet
.RxData
->FragmentTable
[0].FragmentLength
;
1996 Fragment
.Bulk
= (UINT8
*) Rx6Token
->Packet
.RxData
->FragmentTable
[0].FragmentBuffer
;
1998 if (Fragment
.Bulk
!= NULL
) {
1999 FreePool (Fragment
.Bulk
);
2000 Fragment
.Bulk
= NULL
;
2003 Status
= HttpsReceive (HttpInstance
, &Fragment
, Timeout
);
2004 if (EFI_ERROR (Status
)) {
2005 DEBUG ((EFI_D_ERROR
, "Tcp6 receive failed: %r\n", Status
));
2011 // Append the response string along with a Null-terminator.
2013 *BufferSize
= *SizeofHeaders
+ Fragment
.Len
;
2014 Buffer
= AllocatePool (*BufferSize
+ 1);
2015 if (Buffer
== NULL
) {
2016 Status
= EFI_OUT_OF_RESOURCES
;
2020 if (*HttpHeaders
!= NULL
) {
2021 CopyMem (Buffer
, *HttpHeaders
, *SizeofHeaders
);
2022 FreePool (*HttpHeaders
);
2026 Buffer
+ *SizeofHeaders
,
2030 *(Buffer
+ *BufferSize
) = '\0';
2031 *HttpHeaders
= Buffer
;
2032 *SizeofHeaders
= *BufferSize
;
2035 // Check whether we received end of HTTP headers.
2037 *EndofHeader
= AsciiStrStr (*HttpHeaders
, HTTP_END_OF_HDR_STR
);
2043 if (Rx6Token
!= NULL
&& Rx6Token
->Packet
.RxData
!= NULL
&& Rx6Token
->Packet
.RxData
->FragmentTable
[0].FragmentBuffer
!= NULL
) {
2044 FreePool (Rx6Token
->Packet
.RxData
->FragmentTable
[0].FragmentBuffer
);
2045 Rx6Token
->Packet
.RxData
->FragmentTable
[0].FragmentBuffer
= NULL
;
2046 Fragment
.Bulk
= NULL
;
2049 if (Fragment
.Bulk
!= NULL
) {
2050 FreePool (Fragment
.Bulk
);
2051 Fragment
.Bulk
= NULL
;
2056 // Skip the CRLF after the HTTP headers.
2058 *EndofHeader
= *EndofHeader
+ AsciiStrLen (HTTP_END_OF_HDR_STR
);
2060 *SizeofHeaders
= *EndofHeader
- *HttpHeaders
;
2066 Receive the HTTP body by processing the associated HTTP token.
2068 @param[in] Wrap The HTTP token's wrap data.
2069 @param[in] HttpMsg The HTTP message data.
2071 @retval EFI_SUCCESS The HTTP body is received.
2072 @retval Others Other error as indicated.
2076 HttpTcpReceiveBody (
2077 IN HTTP_TOKEN_WRAP
*Wrap
,
2078 IN EFI_HTTP_MESSAGE
*HttpMsg
2082 HTTP_PROTOCOL
*HttpInstance
;
2083 EFI_TCP6_PROTOCOL
*Tcp6
;
2084 EFI_TCP6_IO_TOKEN
*Rx6Token
;
2085 EFI_TCP4_PROTOCOL
*Tcp4
;
2086 EFI_TCP4_IO_TOKEN
*Rx4Token
;
2088 HttpInstance
= Wrap
->HttpInstance
;
2089 Tcp4
= HttpInstance
->Tcp4
;
2090 Tcp6
= HttpInstance
->Tcp6
;
2094 if (HttpInstance
->LocalAddressIsIPv6
) {
2095 ASSERT (Tcp6
!= NULL
);
2097 ASSERT (Tcp4
!= NULL
);
2100 if (HttpInstance
->LocalAddressIsIPv6
) {
2101 Rx6Token
= &Wrap
->TcpWrap
.Rx6Token
;
2102 Rx6Token
->Packet
.RxData
->DataLength
= (UINT32
) MIN (MAX_UINT32
, HttpMsg
->BodyLength
);
2103 Rx6Token
->Packet
.RxData
->FragmentTable
[0].FragmentLength
= (UINT32
) MIN (MAX_UINT32
, HttpMsg
->BodyLength
);
2104 Rx6Token
->Packet
.RxData
->FragmentTable
[0].FragmentBuffer
= (VOID
*) HttpMsg
->Body
;
2105 Rx6Token
->CompletionToken
.Status
= EFI_NOT_READY
;
2107 Status
= Tcp6
->Receive (Tcp6
, Rx6Token
);
2108 if (EFI_ERROR (Status
)) {
2109 DEBUG ((EFI_D_ERROR
, "Tcp6 receive failed: %r\n", Status
));
2113 Rx4Token
= &Wrap
->TcpWrap
.Rx4Token
;
2114 Rx4Token
->Packet
.RxData
->DataLength
= (UINT32
) MIN (MAX_UINT32
, HttpMsg
->BodyLength
);
2115 Rx4Token
->Packet
.RxData
->FragmentTable
[0].FragmentLength
= (UINT32
) MIN (MAX_UINT32
, HttpMsg
->BodyLength
);
2116 Rx4Token
->Packet
.RxData
->FragmentTable
[0].FragmentBuffer
= (VOID
*) HttpMsg
->Body
;
2118 Rx4Token
->CompletionToken
.Status
= EFI_NOT_READY
;
2119 Status
= Tcp4
->Receive (Tcp4
, Rx4Token
);
2120 if (EFI_ERROR (Status
)) {
2121 DEBUG ((EFI_D_ERROR
, "Tcp4 receive failed: %r\n", Status
));
2131 Clean up Tcp Tokens while the Tcp transmission error occurs.
2133 @param[in] Wrap Pointer to HTTP token's wrap data.
2137 HttpTcpTokenCleanup (
2138 IN HTTP_TOKEN_WRAP
*Wrap
2141 HTTP_PROTOCOL
*HttpInstance
;
2142 EFI_TCP4_IO_TOKEN
*Rx4Token
;
2143 EFI_TCP6_IO_TOKEN
*Rx6Token
;
2145 ASSERT (Wrap
!= NULL
);
2146 HttpInstance
= Wrap
->HttpInstance
;
2150 if (HttpInstance
->LocalAddressIsIPv6
) {
2151 Rx6Token
= &Wrap
->TcpWrap
.Rx6Token
;
2153 if (Rx6Token
->CompletionToken
.Event
!= NULL
) {
2154 gBS
->CloseEvent (Rx6Token
->CompletionToken
.Event
);
2155 Rx6Token
->CompletionToken
.Event
= NULL
;
2160 Rx6Token
= &HttpInstance
->Rx6Token
;
2162 if (Rx6Token
->CompletionToken
.Event
!= NULL
) {
2163 gBS
->CloseEvent (Rx6Token
->CompletionToken
.Event
);
2164 Rx6Token
->CompletionToken
.Event
= NULL
;
2167 if (Rx6Token
->Packet
.RxData
->FragmentTable
[0].FragmentBuffer
!= NULL
) {
2168 FreePool (Rx6Token
->Packet
.RxData
->FragmentTable
[0].FragmentBuffer
);
2169 Rx6Token
->Packet
.RxData
->FragmentTable
[0].FragmentBuffer
= NULL
;
2173 Rx4Token
= &Wrap
->TcpWrap
.Rx4Token
;
2175 if (Rx4Token
->CompletionToken
.Event
!= NULL
) {
2176 gBS
->CloseEvent (Rx4Token
->CompletionToken
.Event
);
2177 Rx4Token
->CompletionToken
.Event
= NULL
;
2182 Rx4Token
= &HttpInstance
->Rx4Token
;
2184 if (Rx4Token
->CompletionToken
.Event
!= NULL
) {
2185 gBS
->CloseEvent (Rx4Token
->CompletionToken
.Event
);
2186 Rx4Token
->CompletionToken
.Event
= NULL
;
2190 if (Rx4Token
->Packet
.RxData
->FragmentTable
[0].FragmentBuffer
!= NULL
) {
2191 FreePool (Rx4Token
->Packet
.RxData
->FragmentTable
[0].FragmentBuffer
);
2192 Rx4Token
->Packet
.RxData
->FragmentTable
[0].FragmentBuffer
= NULL
;