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 various 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 various 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 Initialize 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
);
876 HttpInstance
->TlsChildHandle
= NULL
;
879 if (HttpInstance
->Tcp4ChildHandle
!= NULL
) {
881 HttpInstance
->Tcp4ChildHandle
,
882 &gEfiTcp4ProtocolGuid
,
883 HttpInstance
->Service
->Ip4DriverBindingHandle
,
884 HttpInstance
->Service
->ControllerHandle
888 HttpInstance
->Tcp4ChildHandle
,
889 &gEfiTcp4ProtocolGuid
,
890 HttpInstance
->Service
->Ip4DriverBindingHandle
,
894 NetLibDestroyServiceChild (
895 HttpInstance
->Service
->ControllerHandle
,
896 HttpInstance
->Service
->Ip4DriverBindingHandle
,
897 &gEfiTcp4ServiceBindingProtocolGuid
,
898 HttpInstance
->Tcp4ChildHandle
902 if (HttpInstance
->Service
->Tcp4ChildHandle
!= NULL
) {
904 HttpInstance
->Service
->Tcp4ChildHandle
,
905 &gEfiTcp4ProtocolGuid
,
906 HttpInstance
->Service
->Ip4DriverBindingHandle
,
911 if (HttpInstance
->Tcp6ChildHandle
!= NULL
) {
913 HttpInstance
->Tcp6ChildHandle
,
914 &gEfiTcp6ProtocolGuid
,
915 HttpInstance
->Service
->Ip6DriverBindingHandle
,
916 HttpInstance
->Service
->ControllerHandle
920 HttpInstance
->Tcp6ChildHandle
,
921 &gEfiTcp6ProtocolGuid
,
922 HttpInstance
->Service
->Ip6DriverBindingHandle
,
926 NetLibDestroyServiceChild (
927 HttpInstance
->Service
->ControllerHandle
,
928 HttpInstance
->Service
->Ip6DriverBindingHandle
,
929 &gEfiTcp6ServiceBindingProtocolGuid
,
930 HttpInstance
->Tcp6ChildHandle
934 if (HttpInstance
->Service
->Tcp6ChildHandle
!= NULL
) {
936 HttpInstance
->Service
->Tcp6ChildHandle
,
937 &gEfiTcp6ProtocolGuid
,
938 HttpInstance
->Service
->Ip6DriverBindingHandle
,
943 TlsCloseTxRxEvent (HttpInstance
);
947 Establish TCP connection with HTTP server.
949 @param[in] HttpInstance The HTTP instance private data.
951 @retval EFI_SUCCESS The TCP connection is established.
952 @retval Others Other error as indicated.
956 HttpCreateConnection (
957 IN HTTP_PROTOCOL
*HttpInstance
963 // Connect to Http server
965 if (!HttpInstance
->LocalAddressIsIPv6
) {
966 HttpInstance
->IsTcp4ConnDone
= FALSE
;
967 HttpInstance
->Tcp4ConnToken
.CompletionToken
.Status
= EFI_NOT_READY
;
968 Status
= HttpInstance
->Tcp4
->Connect (HttpInstance
->Tcp4
, &HttpInstance
->Tcp4ConnToken
);
969 if (EFI_ERROR (Status
)) {
970 DEBUG ((EFI_D_ERROR
, "HttpCreateConnection: Tcp4->Connect() = %r\n", Status
));
974 while (!HttpInstance
->IsTcp4ConnDone
) {
975 HttpInstance
->Tcp4
->Poll (HttpInstance
->Tcp4
);
978 Status
= HttpInstance
->Tcp4ConnToken
.CompletionToken
.Status
;
981 HttpInstance
->IsTcp6ConnDone
= FALSE
;
982 HttpInstance
->Tcp6ConnToken
.CompletionToken
.Status
= EFI_NOT_READY
;
983 Status
= HttpInstance
->Tcp6
->Connect (HttpInstance
->Tcp6
, &HttpInstance
->Tcp6ConnToken
);
984 if (EFI_ERROR (Status
)) {
985 DEBUG ((EFI_D_ERROR
, "HttpCreateConnection: Tcp6->Connect() = %r\n", Status
));
989 while(!HttpInstance
->IsTcp6ConnDone
) {
990 HttpInstance
->Tcp6
->Poll (HttpInstance
->Tcp6
);
993 Status
= HttpInstance
->Tcp6ConnToken
.CompletionToken
.Status
;
996 if (!EFI_ERROR (Status
)) {
997 HttpInstance
->State
= HTTP_STATE_TCP_CONNECTED
;
1004 Close existing TCP connection.
1006 @param[in] HttpInstance The HTTP instance private data.
1008 @retval EFI_SUCCESS The TCP connection is closed.
1009 @retval Others Other error as indicated.
1013 HttpCloseConnection (
1014 IN HTTP_PROTOCOL
*HttpInstance
1019 if (HttpInstance
->State
== HTTP_STATE_TCP_CONNECTED
) {
1021 if (HttpInstance
->LocalAddressIsIPv6
) {
1022 HttpInstance
->Tcp6CloseToken
.AbortOnClose
= TRUE
;
1023 HttpInstance
->IsTcp6CloseDone
= FALSE
;
1024 Status
= HttpInstance
->Tcp6
->Close (HttpInstance
->Tcp6
, &HttpInstance
->Tcp6CloseToken
);
1025 if (EFI_ERROR (Status
)) {
1029 while (!HttpInstance
->IsTcp6CloseDone
) {
1030 HttpInstance
->Tcp6
->Poll (HttpInstance
->Tcp6
);
1034 HttpInstance
->Tcp4CloseToken
.AbortOnClose
= TRUE
;
1035 HttpInstance
->IsTcp4CloseDone
= FALSE
;
1036 Status
= HttpInstance
->Tcp4
->Close (HttpInstance
->Tcp4
, &HttpInstance
->Tcp4CloseToken
);
1037 if (EFI_ERROR (Status
)) {
1041 while (!HttpInstance
->IsTcp4CloseDone
) {
1042 HttpInstance
->Tcp4
->Poll (HttpInstance
->Tcp4
);
1048 HttpInstance
->State
= HTTP_STATE_TCP_CLOSED
;
1053 Configure TCP4 protocol child.
1055 @param[in] HttpInstance The HTTP instance private data.
1056 @param[in] Wrap The HTTP token's wrap data.
1058 @retval EFI_SUCCESS The TCP4 protocol child is configured.
1059 @retval Others Other error as indicated.
1064 IN HTTP_PROTOCOL
*HttpInstance
,
1065 IN HTTP_TOKEN_WRAP
*Wrap
1069 EFI_TCP4_CONFIG_DATA
*Tcp4CfgData
;
1070 EFI_TCP4_ACCESS_POINT
*Tcp4AP
;
1071 EFI_TCP4_OPTION
*Tcp4Option
;
1073 ASSERT (HttpInstance
!= NULL
);
1076 Tcp4CfgData
= &HttpInstance
->Tcp4CfgData
;
1077 ZeroMem (Tcp4CfgData
, sizeof (EFI_TCP4_CONFIG_DATA
));
1079 Tcp4CfgData
->TypeOfService
= HTTP_TOS_DEAULT
;
1080 Tcp4CfgData
->TimeToLive
= HTTP_TTL_DEAULT
;
1081 Tcp4CfgData
->ControlOption
= &HttpInstance
->Tcp4Option
;
1083 Tcp4AP
= &Tcp4CfgData
->AccessPoint
;
1084 Tcp4AP
->UseDefaultAddress
= HttpInstance
->IPv4Node
.UseDefaultAddress
;
1085 if (!Tcp4AP
->UseDefaultAddress
) {
1086 IP4_COPY_ADDRESS (&Tcp4AP
->StationAddress
, &HttpInstance
->IPv4Node
.LocalAddress
);
1087 IP4_COPY_ADDRESS (&Tcp4AP
->SubnetMask
, &HttpInstance
->IPv4Node
.LocalSubnet
);
1090 Tcp4AP
->StationPort
= HttpInstance
->IPv4Node
.LocalPort
;
1091 Tcp4AP
->RemotePort
= HttpInstance
->RemotePort
;
1092 Tcp4AP
->ActiveFlag
= TRUE
;
1093 IP4_COPY_ADDRESS (&Tcp4AP
->RemoteAddress
, &HttpInstance
->RemoteAddr
);
1095 Tcp4Option
= Tcp4CfgData
->ControlOption
;
1096 Tcp4Option
->ReceiveBufferSize
= HTTP_BUFFER_SIZE_DEAULT
;
1097 Tcp4Option
->SendBufferSize
= HTTP_BUFFER_SIZE_DEAULT
;
1098 Tcp4Option
->MaxSynBackLog
= HTTP_MAX_SYN_BACK_LOG
;
1099 Tcp4Option
->ConnectionTimeout
= HTTP_CONNECTION_TIMEOUT
;
1100 Tcp4Option
->DataRetries
= HTTP_DATA_RETRIES
;
1101 Tcp4Option
->FinTimeout
= HTTP_FIN_TIMEOUT
;
1102 Tcp4Option
->KeepAliveProbes
= HTTP_KEEP_ALIVE_PROBES
;
1103 Tcp4Option
->KeepAliveTime
= HTTP_KEEP_ALIVE_TIME
;
1104 Tcp4Option
->KeepAliveInterval
= HTTP_KEEP_ALIVE_INTERVAL
;
1105 Tcp4Option
->EnableNagle
= TRUE
;
1106 Tcp4CfgData
->ControlOption
= Tcp4Option
;
1108 Status
= HttpInstance
->Tcp4
->Configure (HttpInstance
->Tcp4
, Tcp4CfgData
);
1109 if (EFI_ERROR (Status
)) {
1110 DEBUG ((EFI_D_ERROR
, "HttpConfigureTcp4 - %r\n", Status
));
1114 Status
= HttpCreateTcpConnCloseEvent (HttpInstance
);
1115 if (EFI_ERROR (Status
)) {
1119 Status
= HttpCreateTcpTxEvent (Wrap
);
1120 if (EFI_ERROR (Status
)) {
1124 HttpInstance
->State
= HTTP_STATE_TCP_CONFIGED
;
1130 Configure TCP6 protocol child.
1132 @param[in] HttpInstance The HTTP instance private data.
1133 @param[in] Wrap The HTTP token's wrap data.
1135 @retval EFI_SUCCESS The TCP6 protocol child is configured.
1136 @retval Others Other error as indicated.
1141 IN HTTP_PROTOCOL
*HttpInstance
,
1142 IN HTTP_TOKEN_WRAP
*Wrap
1146 EFI_TCP6_CONFIG_DATA
*Tcp6CfgData
;
1147 EFI_TCP6_ACCESS_POINT
*Tcp6Ap
;
1148 EFI_TCP6_OPTION
*Tcp6Option
;
1150 ASSERT (HttpInstance
!= NULL
);
1152 Tcp6CfgData
= &HttpInstance
->Tcp6CfgData
;
1153 ZeroMem (Tcp6CfgData
, sizeof (EFI_TCP6_CONFIG_DATA
));
1155 Tcp6CfgData
->TrafficClass
= 0;
1156 Tcp6CfgData
->HopLimit
= 255;
1157 Tcp6CfgData
->ControlOption
= &HttpInstance
->Tcp6Option
;
1159 Tcp6Ap
= &Tcp6CfgData
->AccessPoint
;
1160 Tcp6Ap
->ActiveFlag
= TRUE
;
1161 Tcp6Ap
->StationPort
= HttpInstance
->Ipv6Node
.LocalPort
;
1162 Tcp6Ap
->RemotePort
= HttpInstance
->RemotePort
;
1163 IP6_COPY_ADDRESS (&Tcp6Ap
->StationAddress
, &HttpInstance
->Ipv6Node
.LocalAddress
);
1164 IP6_COPY_ADDRESS (&Tcp6Ap
->RemoteAddress
, &HttpInstance
->RemoteIpv6Addr
);
1166 Tcp6Option
= Tcp6CfgData
->ControlOption
;
1167 Tcp6Option
->ReceiveBufferSize
= HTTP_BUFFER_SIZE_DEAULT
;
1168 Tcp6Option
->SendBufferSize
= HTTP_BUFFER_SIZE_DEAULT
;
1169 Tcp6Option
->MaxSynBackLog
= HTTP_MAX_SYN_BACK_LOG
;
1170 Tcp6Option
->ConnectionTimeout
= HTTP_CONNECTION_TIMEOUT
;
1171 Tcp6Option
->DataRetries
= HTTP_DATA_RETRIES
;
1172 Tcp6Option
->FinTimeout
= HTTP_FIN_TIMEOUT
;
1173 Tcp6Option
->KeepAliveProbes
= HTTP_KEEP_ALIVE_PROBES
;
1174 Tcp6Option
->KeepAliveTime
= HTTP_KEEP_ALIVE_TIME
;
1175 Tcp6Option
->KeepAliveInterval
= HTTP_KEEP_ALIVE_INTERVAL
;
1176 Tcp6Option
->EnableNagle
= TRUE
;
1178 Status
= HttpInstance
->Tcp6
->Configure (HttpInstance
->Tcp6
, Tcp6CfgData
);
1179 if (EFI_ERROR (Status
)) {
1180 DEBUG ((EFI_D_ERROR
, "HttpConfigureTcp6 - %r\n", Status
));
1184 Status
= HttpCreateTcpConnCloseEvent (HttpInstance
);
1185 if (EFI_ERROR (Status
)) {
1189 Status
= HttpCreateTcpTxEvent (Wrap
);
1190 if (EFI_ERROR (Status
)) {
1194 HttpInstance
->State
= HTTP_STATE_TCP_CONFIGED
;
1201 Check existing TCP connection, if in error state, recover TCP4 connection. Then,
1202 connect one TLS session if required.
1204 @param[in] HttpInstance The HTTP instance private data.
1206 @retval EFI_SUCCESS The TCP connection is established.
1207 @retval EFI_NOT_READY TCP4 protocol child is not created or configured.
1208 @retval Others Other error as indicated.
1213 IN HTTP_PROTOCOL
*HttpInstance
1217 EFI_TCP4_CONNECTION_STATE Tcp4State
;
1220 if (HttpInstance
->State
< HTTP_STATE_TCP_CONFIGED
|| HttpInstance
->Tcp4
== NULL
) {
1221 return EFI_NOT_READY
;
1224 Status
= HttpInstance
->Tcp4
->GetModeData(
1232 if (EFI_ERROR(Status
)){
1233 DEBUG ((EFI_D_ERROR
, "Tcp4 GetModeData fail - %x\n", Status
));
1237 if (Tcp4State
== Tcp4StateEstablished
) {
1239 } else if (Tcp4State
> Tcp4StateEstablished
) {
1240 HttpCloseConnection(HttpInstance
);
1243 Status
= HttpCreateConnection (HttpInstance
);
1244 if (EFI_ERROR(Status
)){
1245 DEBUG ((EFI_D_ERROR
, "Tcp4 Connection fail - %x\n", Status
));
1250 // Tls session connection.
1252 if (HttpInstance
->UseHttps
) {
1253 if (HttpInstance
->TimeoutEvent
== NULL
) {
1255 // Create TimeoutEvent for TLS connection.
1257 Status
= gBS
->CreateEvent (
1262 &HttpInstance
->TimeoutEvent
1264 if (EFI_ERROR (Status
)) {
1265 TlsCloseTxRxEvent (HttpInstance
);
1271 // Start the timer, and wait Timeout seconds for connection.
1273 Status
= gBS
->SetTimer (HttpInstance
->TimeoutEvent
, TimerRelative
, HTTP_CONNECTION_TIMEOUT
* TICKS_PER_SECOND
);
1274 if (EFI_ERROR (Status
)) {
1275 TlsCloseTxRxEvent (HttpInstance
);
1279 Status
= TlsConnectSession (HttpInstance
, HttpInstance
->TimeoutEvent
);
1281 gBS
->SetTimer (HttpInstance
->TimeoutEvent
, TimerCancel
, 0);
1283 if (EFI_ERROR (Status
)) {
1284 TlsCloseTxRxEvent (HttpInstance
);
1293 Check existing TCP connection, if in error state, recover TCP6 connection. Then,
1294 connect one TLS session if required.
1296 @param[in] HttpInstance The HTTP instance private data.
1298 @retval EFI_SUCCESS The TCP connection is established.
1299 @retval EFI_NOT_READY TCP6 protocol child is not created or configured.
1300 @retval Others Other error as indicated.
1305 IN HTTP_PROTOCOL
*HttpInstance
1309 EFI_TCP6_CONNECTION_STATE Tcp6State
;
1311 if (HttpInstance
->State
< HTTP_STATE_TCP_CONFIGED
|| HttpInstance
->Tcp6
== NULL
) {
1312 return EFI_NOT_READY
;
1315 Status
= HttpInstance
->Tcp6
->GetModeData (
1324 if (EFI_ERROR(Status
)){
1325 DEBUG ((EFI_D_ERROR
, "Tcp6 GetModeData fail - %x\n", Status
));
1329 if (Tcp6State
== Tcp6StateEstablished
) {
1331 } else if (Tcp6State
> Tcp6StateEstablished
) {
1332 HttpCloseConnection(HttpInstance
);
1335 Status
= HttpCreateConnection (HttpInstance
);
1336 if (EFI_ERROR(Status
)){
1337 DEBUG ((EFI_D_ERROR
, "Tcp6 Connection fail - %x\n", Status
));
1342 // Tls session connection.
1344 if (HttpInstance
->UseHttps
) {
1345 if (HttpInstance
->TimeoutEvent
== NULL
) {
1347 // Create TimeoutEvent for TLS connection.
1349 Status
= gBS
->CreateEvent (
1354 &HttpInstance
->TimeoutEvent
1356 if (EFI_ERROR (Status
)) {
1357 TlsCloseTxRxEvent (HttpInstance
);
1363 // Start the timer, and wait Timeout seconds for connection.
1365 Status
= gBS
->SetTimer (HttpInstance
->TimeoutEvent
, TimerRelative
, HTTP_CONNECTION_TIMEOUT
* TICKS_PER_SECOND
);
1366 if (EFI_ERROR (Status
)) {
1367 TlsCloseTxRxEvent (HttpInstance
);
1371 Status
= TlsConnectSession (HttpInstance
, HttpInstance
->TimeoutEvent
);
1373 gBS
->SetTimer (HttpInstance
->TimeoutEvent
, TimerCancel
, 0);
1375 if (EFI_ERROR (Status
)) {
1376 TlsCloseTxRxEvent (HttpInstance
);
1385 Initialize Http session.
1387 @param[in] HttpInstance The HTTP instance private data.
1388 @param[in] Wrap The HTTP token's wrap data.
1389 @param[in] Configure The Flag indicates whether need to initialize session.
1390 @param[in] TlsConfigure The Flag indicates whether it's the new Tls session.
1392 @retval EFI_SUCCESS The initialization of session is done.
1393 @retval Others Other error as indicated.
1398 IN HTTP_PROTOCOL
*HttpInstance
,
1399 IN HTTP_TOKEN_WRAP
*Wrap
,
1400 IN BOOLEAN Configure
,
1401 IN BOOLEAN TlsConfigure
1405 ASSERT (HttpInstance
!= NULL
);
1408 // Configure Tls session.
1411 Status
= TlsConfigureSession (HttpInstance
);
1412 if (EFI_ERROR (Status
)) {
1417 if (!HttpInstance
->LocalAddressIsIPv6
) {
1419 // Configure TCP instance.
1422 Status
= HttpConfigureTcp4 (HttpInstance
, Wrap
);
1423 if (EFI_ERROR (Status
)) {
1431 Status
= HttpConnectTcp4 (HttpInstance
);
1432 if (EFI_ERROR (Status
)) {
1437 // Configure TCP instance.
1440 Status
= HttpConfigureTcp6 (HttpInstance
, Wrap
);
1441 if (EFI_ERROR (Status
)) {
1449 Status
= HttpConnectTcp6 (HttpInstance
);
1450 if (EFI_ERROR (Status
)) {
1460 Send the HTTP or HTTPS message through TCP4 or TCP6.
1462 @param[in] HttpInstance The HTTP instance private data.
1463 @param[in] Wrap The HTTP token's wrap data.
1464 @param[in] TxString Buffer containing the HTTP message string.
1465 @param[in] TxStringLen Length of the HTTP message string in bytes.
1467 @retval EFI_SUCCESS The HTTP message is queued into TCP transmit queue.
1468 @retval Others Other error as indicated.
1473 IN HTTP_PROTOCOL
*HttpInstance
,
1474 IN HTTP_TOKEN_WRAP
*Wrap
,
1476 IN UINTN TxStringLen
1480 EFI_TCP4_IO_TOKEN
*Tx4Token
;
1481 EFI_TCP4_PROTOCOL
*Tcp4
;
1482 EFI_TCP6_IO_TOKEN
*Tx6Token
;
1483 EFI_TCP6_PROTOCOL
*Tcp6
;
1486 NET_FRAGMENT TempFragment
;
1487 NET_FRAGMENT Fragment
;
1491 Status
= EFI_SUCCESS
;
1494 TempFragment
.Len
= 0;
1495 TempFragment
.Bulk
= NULL
;
1497 Fragment
.Bulk
= NULL
;
1502 // Need to encrypt data.
1504 if (HttpInstance
->UseHttps
) {
1506 // Allocate enough buffer for each TLS plaintext records.
1508 TlsRecord
= AllocateZeroPool (TLS_RECORD_HEADER_LENGTH
+ TLS_PLAINTEXT_RECORD_MAX_PAYLOAD_LENGTH
);
1509 if (TlsRecord
== NULL
) {
1510 Status
= EFI_OUT_OF_RESOURCES
;
1515 // Allocate enough buffer for all TLS ciphertext records.
1517 RecordCount
= TxStringLen
/ TLS_PLAINTEXT_RECORD_MAX_PAYLOAD_LENGTH
+ 1;
1518 Fragment
.Bulk
= AllocateZeroPool (RecordCount
* (TLS_RECORD_HEADER_LENGTH
+ TLS_CIPHERTEXT_RECORD_MAX_PAYLOAD_LENGTH
));
1519 if (Fragment
.Bulk
== NULL
) {
1520 Status
= EFI_OUT_OF_RESOURCES
;
1525 // Encrypt each TLS plaintext records.
1527 RemainingLen
= TxStringLen
;
1528 while (RemainingLen
!= 0) {
1529 PayloadSize
= (UINT16
) MIN (TLS_PLAINTEXT_RECORD_MAX_PAYLOAD_LENGTH
, RemainingLen
);
1531 ((TLS_RECORD_HEADER
*) TlsRecord
)->ContentType
= TlsContentTypeApplicationData
;
1532 ((TLS_RECORD_HEADER
*) TlsRecord
)->Version
.Major
= HttpInstance
->TlsConfigData
.Version
.Major
;
1533 ((TLS_RECORD_HEADER
*) TlsRecord
)->Version
.Minor
= HttpInstance
->TlsConfigData
.Version
.Minor
;
1534 ((TLS_RECORD_HEADER
*) TlsRecord
)->Length
= PayloadSize
;
1536 CopyMem (TlsRecord
+ TLS_RECORD_HEADER_LENGTH
, TxString
+ (TxStringLen
- RemainingLen
), PayloadSize
);
1538 Status
= TlsProcessMessage (
1541 TLS_RECORD_HEADER_LENGTH
+ PayloadSize
,
1545 if (EFI_ERROR (Status
)) {
1550 // Record the processed/encrypted Packet.
1552 CopyMem (Fragment
.Bulk
+ Fragment
.Len
, TempFragment
.Bulk
, TempFragment
.Len
);
1553 Fragment
.Len
+= TempFragment
.Len
;
1555 FreePool (TempFragment
.Bulk
);
1556 TempFragment
.Len
= 0;
1557 TempFragment
.Bulk
= NULL
;
1559 RemainingLen
-= (UINTN
) PayloadSize
;
1560 ZeroMem (TlsRecord
, TLS_RECORD_HEADER_LENGTH
+ TLS_PLAINTEXT_RECORD_MAX_PAYLOAD_LENGTH
);
1563 FreePool (TlsRecord
);
1567 if (!HttpInstance
->LocalAddressIsIPv6
) {
1568 Tcp4
= HttpInstance
->Tcp4
;
1569 Tx4Token
= &Wrap
->TcpWrap
.Tx4Token
;
1571 if (HttpInstance
->UseHttps
) {
1572 Tx4Token
->Packet
.TxData
->DataLength
= Fragment
.Len
;
1573 Tx4Token
->Packet
.TxData
->FragmentTable
[0].FragmentLength
= Fragment
.Len
;
1574 Tx4Token
->Packet
.TxData
->FragmentTable
[0].FragmentBuffer
= (VOID
*) Fragment
.Bulk
;
1576 Tx4Token
->Packet
.TxData
->DataLength
= (UINT32
) TxStringLen
;
1577 Tx4Token
->Packet
.TxData
->FragmentTable
[0].FragmentLength
= (UINT32
) TxStringLen
;
1578 Tx4Token
->Packet
.TxData
->FragmentTable
[0].FragmentBuffer
= (VOID
*) TxString
;
1581 Tx4Token
->CompletionToken
.Status
= EFI_NOT_READY
;
1583 Wrap
->TcpWrap
.IsTxDone
= FALSE
;
1584 Status
= Tcp4
->Transmit (Tcp4
, Tx4Token
);
1585 if (EFI_ERROR (Status
)) {
1586 DEBUG ((EFI_D_ERROR
, "Transmit failed: %r\n", Status
));
1591 Tcp6
= HttpInstance
->Tcp6
;
1592 Tx6Token
= &Wrap
->TcpWrap
.Tx6Token
;
1594 if (HttpInstance
->UseHttps
) {
1595 Tx6Token
->Packet
.TxData
->DataLength
= Fragment
.Len
;
1596 Tx6Token
->Packet
.TxData
->FragmentTable
[0].FragmentLength
= Fragment
.Len
;
1597 Tx6Token
->Packet
.TxData
->FragmentTable
[0].FragmentBuffer
= (VOID
*) Fragment
.Bulk
;
1599 Tx6Token
->Packet
.TxData
->DataLength
= (UINT32
) TxStringLen
;
1600 Tx6Token
->Packet
.TxData
->FragmentTable
[0].FragmentLength
= (UINT32
) TxStringLen
;
1601 Tx6Token
->Packet
.TxData
->FragmentTable
[0].FragmentBuffer
= (VOID
*) TxString
;
1604 Tx6Token
->CompletionToken
.Status
= EFI_NOT_READY
;
1606 Wrap
->TcpWrap
.IsTxDone
= FALSE
;
1607 Status
= Tcp6
->Transmit (Tcp6
, Tx6Token
);
1608 if (EFI_ERROR (Status
)) {
1609 DEBUG ((EFI_D_ERROR
, "Transmit failed: %r\n", Status
));
1618 if (HttpInstance
->UseHttps
) {
1619 if (TlsRecord
!= NULL
) {
1620 FreePool (TlsRecord
);
1624 if (Fragment
.Bulk
!= NULL
) {
1625 FreePool (Fragment
.Bulk
);
1626 Fragment
.Bulk
= NULL
;
1634 Check whether the user's token or event has already
1635 been enqueue on HTTP Tx or Rx Token list.
1637 @param[in] Map The container of either user's transmit or receive
1639 @param[in] Item Current item to check against.
1640 @param[in] Context The Token to check against.
1642 @retval EFI_ACCESS_DENIED The token or event has already been enqueued in IP
1643 @retval EFI_SUCCESS The current item isn't the same token/event as the
1651 IN NET_MAP_ITEM
*Item
,
1655 EFI_HTTP_TOKEN
*Token
;
1656 EFI_HTTP_TOKEN
*TokenInItem
;
1658 Token
= (EFI_HTTP_TOKEN
*) Context
;
1659 TokenInItem
= (EFI_HTTP_TOKEN
*) Item
->Key
;
1661 if (Token
== TokenInItem
|| Token
->Event
== TokenInItem
->Event
) {
1662 return EFI_ACCESS_DENIED
;
1669 Check whether the HTTP message associated with Tx4Token or Tx6Token is already sent out.
1671 @param[in] Map The container of Tx4Token or Tx6Token.
1672 @param[in] Item Current item to check against.
1673 @param[in] Context The Token to check against.
1675 @retval EFI_NOT_READY The HTTP message is still queued in the list.
1676 @retval EFI_SUCCESS The HTTP message has been sent out.
1683 IN NET_MAP_ITEM
*Item
,
1687 HTTP_TOKEN_WRAP
*ValueInItem
;
1689 ValueInItem
= (HTTP_TOKEN_WRAP
*) Item
->Value
;
1691 if (!ValueInItem
->TcpWrap
.IsTxDone
) {
1692 return EFI_NOT_READY
;
1699 Transmit the HTTP or HTTPS message by processing the associated HTTP token.
1701 @param[in] Map The container of Tx4Token or Tx6Token.
1702 @param[in] Item Current item to check against.
1703 @param[in] Context The Token to check against.
1705 @retval EFI_OUT_OF_RESOURCES Failed to allocate resources.
1706 @retval EFI_SUCCESS The HTTP message is queued into TCP transmit
1714 IN NET_MAP_ITEM
*Item
,
1718 HTTP_TOKEN_WRAP
*ValueInItem
;
1723 UINTN RequestMsgSize
;
1727 ValueInItem
= (HTTP_TOKEN_WRAP
*) Item
->Value
;
1728 if (ValueInItem
->TcpWrap
.IsTxDone
) {
1733 // Parse the URI of the remote host.
1735 UrlSize
= StrLen (ValueInItem
->HttpToken
->Message
->Data
.Request
->Url
) + 1;
1736 Url
= AllocatePool (UrlSize
);
1738 return EFI_OUT_OF_RESOURCES
;
1741 UnicodeStrToAsciiStrS (ValueInItem
->HttpToken
->Message
->Data
.Request
->Url
, Url
, UrlSize
);
1744 // Create request message.
1746 Status
= HttpGenRequestMessage (
1747 ValueInItem
->HttpToken
->Message
,
1754 if (EFI_ERROR (Status
) || NULL
== RequestMsg
){
1758 ASSERT (RequestMsg
!= NULL
);
1761 // Transmit the request message.
1763 Status
= HttpTransmitTcp (
1764 ValueInItem
->HttpInstance
,
1766 (UINT8
*) RequestMsg
,
1769 FreePool (RequestMsg
);
1774 Receive the HTTP response by processing the associated HTTP token.
1776 @param[in] Map The container of Rx4Token or Rx6Token.
1777 @param[in] Item Current item to check against.
1778 @param[in] Context The Token to check against.
1780 @retval EFI_SUCCESS The HTTP response is queued into TCP receive
1782 @retval Others Other error as indicated.
1789 IN NET_MAP_ITEM
*Item
,
1794 // Process the queued HTTP response.
1796 return HttpResponseWorker ((HTTP_TOKEN_WRAP
*) Item
->Value
);
1800 Receive the HTTP header by processing the associated HTTP token.
1802 @param[in] HttpInstance The HTTP instance private data.
1803 @param[in, out] SizeofHeaders The HTTP header length.
1804 @param[in, out] BufferSize The size of buffer to cache the header message.
1805 @param[in] Timeout The time to wait for receiving the header packet.
1807 @retval EFI_SUCCESS The HTTP header is received.
1808 @retval Others Other errors as indicated.
1812 HttpTcpReceiveHeader (
1813 IN HTTP_PROTOCOL
*HttpInstance
,
1814 IN OUT UINTN
*SizeofHeaders
,
1815 IN OUT UINTN
*BufferSize
,
1816 IN EFI_EVENT Timeout
1820 EFI_TCP4_IO_TOKEN
*Rx4Token
;
1821 EFI_TCP4_PROTOCOL
*Tcp4
;
1822 EFI_TCP6_IO_TOKEN
*Rx6Token
;
1823 EFI_TCP6_PROTOCOL
*Tcp6
;
1824 CHAR8
**EndofHeader
;
1825 CHAR8
**HttpHeaders
;
1827 NET_FRAGMENT Fragment
;
1829 ASSERT (HttpInstance
!= NULL
);
1831 EndofHeader
= HttpInstance
->EndofHeader
;
1832 HttpHeaders
= HttpInstance
->HttpHeaders
;
1833 Tcp4
= HttpInstance
->Tcp4
;
1834 Tcp6
= HttpInstance
->Tcp6
;
1839 Fragment
.Bulk
= NULL
;
1841 if (HttpInstance
->LocalAddressIsIPv6
) {
1842 ASSERT (Tcp6
!= NULL
);
1844 ASSERT (Tcp4
!= NULL
);
1847 if (!HttpInstance
->UseHttps
) {
1848 Status
= HttpCreateTcpRxEventForHeader (HttpInstance
);
1849 if (EFI_ERROR (Status
)) {
1854 if (!HttpInstance
->LocalAddressIsIPv6
) {
1855 if (!HttpInstance
->UseHttps
) {
1856 Rx4Token
= &HttpInstance
->Rx4Token
;
1857 Rx4Token
->Packet
.RxData
->FragmentTable
[0].FragmentBuffer
= AllocateZeroPool (DEF_BUF_LEN
);
1858 if (Rx4Token
->Packet
.RxData
->FragmentTable
[0].FragmentBuffer
== NULL
) {
1859 Status
= EFI_OUT_OF_RESOURCES
;
1865 // Receive the HTTP headers only when EFI_HTTP_RESPONSE_DATA is not NULL.
1867 while (*EndofHeader
== NULL
) {
1868 if (!HttpInstance
->UseHttps
) {
1869 HttpInstance
->IsRxDone
= FALSE
;
1870 Rx4Token
->Packet
.RxData
->DataLength
= DEF_BUF_LEN
;
1871 Rx4Token
->Packet
.RxData
->FragmentTable
[0].FragmentLength
= DEF_BUF_LEN
;
1872 Status
= Tcp4
->Receive (Tcp4
, Rx4Token
);
1873 if (EFI_ERROR (Status
)) {
1874 DEBUG ((EFI_D_ERROR
, "Tcp4 receive failed: %r\n", Status
));
1878 while (!HttpInstance
->IsRxDone
&& ((Timeout
== NULL
) || EFI_ERROR (gBS
->CheckEvent (Timeout
)))) {
1882 if (!HttpInstance
->IsRxDone
) {
1884 // Cancel the Token before close its Event.
1886 Tcp4
->Cancel (HttpInstance
->Tcp4
, &Rx4Token
->CompletionToken
);
1887 gBS
->CloseEvent (Rx4Token
->CompletionToken
.Event
);
1888 Rx4Token
->CompletionToken
.Status
= EFI_TIMEOUT
;
1891 Status
= Rx4Token
->CompletionToken
.Status
;
1892 if (EFI_ERROR (Status
)) {
1896 Fragment
.Len
= Rx4Token
->Packet
.RxData
->FragmentTable
[0].FragmentLength
;
1897 Fragment
.Bulk
= (UINT8
*) Rx4Token
->Packet
.RxData
->FragmentTable
[0].FragmentBuffer
;
1899 if (Fragment
.Bulk
!= NULL
) {
1900 FreePool (Fragment
.Bulk
);
1901 Fragment
.Bulk
= NULL
;
1904 Status
= HttpsReceive (HttpInstance
, &Fragment
, Timeout
);
1905 if (EFI_ERROR (Status
)) {
1906 DEBUG ((EFI_D_ERROR
, "Tcp4 receive failed: %r\n", Status
));
1912 // Append the response string along with a Null-terminator.
1914 *BufferSize
= *SizeofHeaders
+ Fragment
.Len
;
1915 Buffer
= AllocatePool (*BufferSize
+ 1);
1916 if (Buffer
== NULL
) {
1917 Status
= EFI_OUT_OF_RESOURCES
;
1921 if (*HttpHeaders
!= NULL
) {
1922 CopyMem (Buffer
, *HttpHeaders
, *SizeofHeaders
);
1923 FreePool (*HttpHeaders
);
1927 Buffer
+ *SizeofHeaders
,
1931 *(Buffer
+ *BufferSize
) = '\0';
1932 *HttpHeaders
= Buffer
;
1933 *SizeofHeaders
= *BufferSize
;
1936 // Check whether we received end of HTTP headers.
1938 *EndofHeader
= AsciiStrStr (*HttpHeaders
, HTTP_END_OF_HDR_STR
);
1944 if (Rx4Token
!= NULL
&& Rx4Token
->Packet
.RxData
!= NULL
&& Rx4Token
->Packet
.RxData
->FragmentTable
[0].FragmentBuffer
!= NULL
) {
1945 FreePool (Rx4Token
->Packet
.RxData
->FragmentTable
[0].FragmentBuffer
);
1946 Rx4Token
->Packet
.RxData
->FragmentTable
[0].FragmentBuffer
= NULL
;
1947 Fragment
.Bulk
= NULL
;
1950 if (Fragment
.Bulk
!= NULL
) {
1951 FreePool (Fragment
.Bulk
);
1952 Fragment
.Bulk
= NULL
;
1955 if (!HttpInstance
->UseHttps
) {
1956 Rx6Token
= &HttpInstance
->Rx6Token
;
1957 Rx6Token
->Packet
.RxData
->FragmentTable
[0].FragmentBuffer
= AllocateZeroPool (DEF_BUF_LEN
);
1958 if (Rx6Token
->Packet
.RxData
->FragmentTable
[0].FragmentBuffer
== NULL
) {
1959 Status
= EFI_OUT_OF_RESOURCES
;
1965 // Receive the HTTP headers only when EFI_HTTP_RESPONSE_DATA is not NULL.
1967 while (*EndofHeader
== NULL
) {
1968 if (!HttpInstance
->UseHttps
) {
1969 HttpInstance
->IsRxDone
= FALSE
;
1970 Rx6Token
->Packet
.RxData
->DataLength
= DEF_BUF_LEN
;
1971 Rx6Token
->Packet
.RxData
->FragmentTable
[0].FragmentLength
= DEF_BUF_LEN
;
1972 Status
= Tcp6
->Receive (Tcp6
, Rx6Token
);
1973 if (EFI_ERROR (Status
)) {
1974 DEBUG ((EFI_D_ERROR
, "Tcp6 receive failed: %r\n", Status
));
1978 while (!HttpInstance
->IsRxDone
&& ((Timeout
== NULL
) || EFI_ERROR (gBS
->CheckEvent (Timeout
)))) {
1982 if (!HttpInstance
->IsRxDone
) {
1984 // Cancel the Token before close its Event.
1986 Tcp6
->Cancel (HttpInstance
->Tcp6
, &Rx6Token
->CompletionToken
);
1987 gBS
->CloseEvent (Rx6Token
->CompletionToken
.Event
);
1988 Rx6Token
->CompletionToken
.Status
= EFI_TIMEOUT
;
1991 Status
= Rx6Token
->CompletionToken
.Status
;
1992 if (EFI_ERROR (Status
)) {
1996 Fragment
.Len
= Rx6Token
->Packet
.RxData
->FragmentTable
[0].FragmentLength
;
1997 Fragment
.Bulk
= (UINT8
*) Rx6Token
->Packet
.RxData
->FragmentTable
[0].FragmentBuffer
;
1999 if (Fragment
.Bulk
!= NULL
) {
2000 FreePool (Fragment
.Bulk
);
2001 Fragment
.Bulk
= NULL
;
2004 Status
= HttpsReceive (HttpInstance
, &Fragment
, Timeout
);
2005 if (EFI_ERROR (Status
)) {
2006 DEBUG ((EFI_D_ERROR
, "Tcp6 receive failed: %r\n", Status
));
2012 // Append the response string along with a Null-terminator.
2014 *BufferSize
= *SizeofHeaders
+ Fragment
.Len
;
2015 Buffer
= AllocatePool (*BufferSize
+ 1);
2016 if (Buffer
== NULL
) {
2017 Status
= EFI_OUT_OF_RESOURCES
;
2021 if (*HttpHeaders
!= NULL
) {
2022 CopyMem (Buffer
, *HttpHeaders
, *SizeofHeaders
);
2023 FreePool (*HttpHeaders
);
2027 Buffer
+ *SizeofHeaders
,
2031 *(Buffer
+ *BufferSize
) = '\0';
2032 *HttpHeaders
= Buffer
;
2033 *SizeofHeaders
= *BufferSize
;
2036 // Check whether we received end of HTTP headers.
2038 *EndofHeader
= AsciiStrStr (*HttpHeaders
, HTTP_END_OF_HDR_STR
);
2044 if (Rx6Token
!= NULL
&& Rx6Token
->Packet
.RxData
!= NULL
&& Rx6Token
->Packet
.RxData
->FragmentTable
[0].FragmentBuffer
!= NULL
) {
2045 FreePool (Rx6Token
->Packet
.RxData
->FragmentTable
[0].FragmentBuffer
);
2046 Rx6Token
->Packet
.RxData
->FragmentTable
[0].FragmentBuffer
= NULL
;
2047 Fragment
.Bulk
= NULL
;
2050 if (Fragment
.Bulk
!= NULL
) {
2051 FreePool (Fragment
.Bulk
);
2052 Fragment
.Bulk
= NULL
;
2057 // Skip the CRLF after the HTTP headers.
2059 *EndofHeader
= *EndofHeader
+ AsciiStrLen (HTTP_END_OF_HDR_STR
);
2061 *SizeofHeaders
= *EndofHeader
- *HttpHeaders
;
2067 Receive the HTTP body by processing the associated HTTP token.
2069 @param[in] Wrap The HTTP token's wrap data.
2070 @param[in] HttpMsg The HTTP message data.
2072 @retval EFI_SUCCESS The HTTP body is received.
2073 @retval Others Other error as indicated.
2077 HttpTcpReceiveBody (
2078 IN HTTP_TOKEN_WRAP
*Wrap
,
2079 IN EFI_HTTP_MESSAGE
*HttpMsg
2083 HTTP_PROTOCOL
*HttpInstance
;
2084 EFI_TCP6_PROTOCOL
*Tcp6
;
2085 EFI_TCP6_IO_TOKEN
*Rx6Token
;
2086 EFI_TCP4_PROTOCOL
*Tcp4
;
2087 EFI_TCP4_IO_TOKEN
*Rx4Token
;
2089 HttpInstance
= Wrap
->HttpInstance
;
2090 Tcp4
= HttpInstance
->Tcp4
;
2091 Tcp6
= HttpInstance
->Tcp6
;
2095 if (HttpInstance
->LocalAddressIsIPv6
) {
2096 ASSERT (Tcp6
!= NULL
);
2098 ASSERT (Tcp4
!= NULL
);
2101 if (HttpInstance
->LocalAddressIsIPv6
) {
2102 Rx6Token
= &Wrap
->TcpWrap
.Rx6Token
;
2103 Rx6Token
->Packet
.RxData
->DataLength
= (UINT32
) MIN (MAX_UINT32
, HttpMsg
->BodyLength
);
2104 Rx6Token
->Packet
.RxData
->FragmentTable
[0].FragmentLength
= (UINT32
) MIN (MAX_UINT32
, HttpMsg
->BodyLength
);
2105 Rx6Token
->Packet
.RxData
->FragmentTable
[0].FragmentBuffer
= (VOID
*) HttpMsg
->Body
;
2106 Rx6Token
->CompletionToken
.Status
= EFI_NOT_READY
;
2108 Status
= Tcp6
->Receive (Tcp6
, Rx6Token
);
2109 if (EFI_ERROR (Status
)) {
2110 DEBUG ((EFI_D_ERROR
, "Tcp6 receive failed: %r\n", Status
));
2114 Rx4Token
= &Wrap
->TcpWrap
.Rx4Token
;
2115 Rx4Token
->Packet
.RxData
->DataLength
= (UINT32
) MIN (MAX_UINT32
, HttpMsg
->BodyLength
);
2116 Rx4Token
->Packet
.RxData
->FragmentTable
[0].FragmentLength
= (UINT32
) MIN (MAX_UINT32
, HttpMsg
->BodyLength
);
2117 Rx4Token
->Packet
.RxData
->FragmentTable
[0].FragmentBuffer
= (VOID
*) HttpMsg
->Body
;
2119 Rx4Token
->CompletionToken
.Status
= EFI_NOT_READY
;
2120 Status
= Tcp4
->Receive (Tcp4
, Rx4Token
);
2121 if (EFI_ERROR (Status
)) {
2122 DEBUG ((EFI_D_ERROR
, "Tcp4 receive failed: %r\n", Status
));
2132 Clean up Tcp Tokens while the Tcp transmission error occurs.
2134 @param[in] Wrap Pointer to HTTP token's wrap data.
2138 HttpTcpTokenCleanup (
2139 IN HTTP_TOKEN_WRAP
*Wrap
2142 HTTP_PROTOCOL
*HttpInstance
;
2143 EFI_TCP4_IO_TOKEN
*Rx4Token
;
2144 EFI_TCP6_IO_TOKEN
*Rx6Token
;
2146 ASSERT (Wrap
!= NULL
);
2147 HttpInstance
= Wrap
->HttpInstance
;
2151 if (HttpInstance
->LocalAddressIsIPv6
) {
2152 Rx6Token
= &Wrap
->TcpWrap
.Rx6Token
;
2154 if (Rx6Token
->CompletionToken
.Event
!= NULL
) {
2155 gBS
->CloseEvent (Rx6Token
->CompletionToken
.Event
);
2156 Rx6Token
->CompletionToken
.Event
= NULL
;
2161 Rx6Token
= &HttpInstance
->Rx6Token
;
2163 if (Rx6Token
->CompletionToken
.Event
!= NULL
) {
2164 gBS
->CloseEvent (Rx6Token
->CompletionToken
.Event
);
2165 Rx6Token
->CompletionToken
.Event
= NULL
;
2168 if (Rx6Token
->Packet
.RxData
->FragmentTable
[0].FragmentBuffer
!= NULL
) {
2169 FreePool (Rx6Token
->Packet
.RxData
->FragmentTable
[0].FragmentBuffer
);
2170 Rx6Token
->Packet
.RxData
->FragmentTable
[0].FragmentBuffer
= NULL
;
2174 Rx4Token
= &Wrap
->TcpWrap
.Rx4Token
;
2176 if (Rx4Token
->CompletionToken
.Event
!= NULL
) {
2177 gBS
->CloseEvent (Rx4Token
->CompletionToken
.Event
);
2178 Rx4Token
->CompletionToken
.Event
= NULL
;
2183 Rx4Token
= &HttpInstance
->Rx4Token
;
2185 if (Rx4Token
->CompletionToken
.Event
!= NULL
) {
2186 gBS
->CloseEvent (Rx4Token
->CompletionToken
.Event
);
2187 Rx4Token
->CompletionToken
.Event
= NULL
;
2191 if (Rx4Token
->Packet
.RxData
->FragmentTable
[0].FragmentBuffer
!= NULL
) {
2192 FreePool (Rx4Token
->Packet
.RxData
->FragmentTable
[0].FragmentBuffer
);
2193 Rx4Token
->Packet
.RxData
->FragmentTable
[0].FragmentBuffer
= NULL
;