]> git.proxmox.com Git - mirror_edk2.git/blob - NetworkPkg/HttpDxe/HttpProto.c
NetworkPkg: Add HTTP Additional Event Notifications
[mirror_edk2.git] / NetworkPkg / HttpDxe / HttpProto.c
1 /** @file
2 Miscellaneous routines for HttpDxe driver.
3
4 Copyright (c) 2015 - 2021, Intel Corporation. All rights reserved.<BR>
5 (C) Copyright 2016 Hewlett Packard Enterprise Development LP<BR>
6 SPDX-License-Identifier: BSD-2-Clause-Patent
7
8 **/
9
10 #include "HttpDriver.h"
11
12 /**
13 The common notify function used in HTTP driver.
14
15 @param[in] Event The event signaled.
16 @param[in] Context The context.
17
18 **/
19 VOID
20 EFIAPI
21 HttpCommonNotify (
22 IN EFI_EVENT Event,
23 IN VOID *Context
24 )
25 {
26 if ((Event == NULL) || (Context == NULL)) {
27 return ;
28 }
29
30 *((BOOLEAN *) Context) = TRUE;
31 }
32
33 /**
34 The notify function associated with Tx4Token for Tcp4->Transmit() or Tx6Token for Tcp6->Transmit().
35
36 @param[in] Context The context.
37
38 **/
39 VOID
40 EFIAPI
41 HttpTcpTransmitNotifyDpc (
42 IN VOID *Context
43 )
44 {
45 HTTP_TOKEN_WRAP *Wrap;
46 HTTP_PROTOCOL *HttpInstance;
47
48 if (Context == NULL) {
49 return ;
50 }
51
52 Wrap = (HTTP_TOKEN_WRAP *) Context;
53 HttpInstance = Wrap->HttpInstance;
54
55 if (!HttpInstance->LocalAddressIsIPv6) {
56 Wrap->HttpToken->Status = Wrap->TcpWrap.Tx4Token.CompletionToken.Status;
57 gBS->SignalEvent (Wrap->HttpToken->Event);
58
59 //
60 // Free resources.
61 //
62 if (Wrap->TcpWrap.Tx4Token.Packet.TxData->FragmentTable[0].FragmentBuffer != NULL) {
63 FreePool (Wrap->TcpWrap.Tx4Token.Packet.TxData->FragmentTable[0].FragmentBuffer);
64 }
65
66 if (Wrap->TcpWrap.Tx4Token.CompletionToken.Event != NULL) {
67 gBS->CloseEvent (Wrap->TcpWrap.Tx4Token.CompletionToken.Event);
68 }
69
70 } else {
71 Wrap->HttpToken->Status = Wrap->TcpWrap.Tx6Token.CompletionToken.Status;
72 gBS->SignalEvent (Wrap->HttpToken->Event);
73
74 //
75 // Free resources.
76 //
77 if (Wrap->TcpWrap.Tx6Token.Packet.TxData->FragmentTable[0].FragmentBuffer != NULL) {
78 FreePool (Wrap->TcpWrap.Tx6Token.Packet.TxData->FragmentTable[0].FragmentBuffer);
79 }
80
81 if (Wrap->TcpWrap.Tx6Token.CompletionToken.Event != NULL) {
82 gBS->CloseEvent (Wrap->TcpWrap.Tx6Token.CompletionToken.Event);
83 }
84 }
85
86
87 Wrap->TcpWrap.IsTxDone = TRUE;
88
89 //
90 // Check pending TxTokens and sent out.
91 //
92 NetMapIterate (&Wrap->HttpInstance->TxTokens, HttpTcpTransmit, NULL);
93
94 }
95
96 /**
97 Request HttpTcpTransmitNotifyDpc as a DPC at TPL_CALLBACK.
98
99 @param Event The receive event delivered to TCP for transmit.
100 @param Context Context for the callback.
101
102 **/
103 VOID
104 EFIAPI
105 HttpTcpTransmitNotify (
106 IN EFI_EVENT Event,
107 IN VOID *Context
108 )
109 {
110 //
111 // Request HttpTcpTransmitNotifyDpc as a DPC at TPL_CALLBACK
112 //
113 QueueDpc (TPL_CALLBACK, HttpTcpTransmitNotifyDpc, Context);
114 }
115
116 /**
117 The notify function associated with Rx4Token for Tcp4->Receive () or Rx6Token for Tcp6->Receive().
118
119 @param[in] Context The context.
120
121 **/
122 VOID
123 EFIAPI
124 HttpTcpReceiveNotifyDpc (
125 IN VOID *Context
126 )
127 {
128 HTTP_TOKEN_WRAP *Wrap;
129 NET_MAP_ITEM *Item;
130 UINTN Length;
131 EFI_STATUS Status;
132 HTTP_PROTOCOL *HttpInstance;
133 BOOLEAN UsingIpv6;
134
135 if (Context == NULL) {
136 return ;
137 }
138
139 Wrap = (HTTP_TOKEN_WRAP *) Context;
140 HttpInstance = Wrap->HttpInstance;
141 UsingIpv6 = HttpInstance->LocalAddressIsIPv6;
142
143 if (UsingIpv6) {
144 gBS->CloseEvent (Wrap->TcpWrap.Rx6Token.CompletionToken.Event);
145 Wrap->TcpWrap.Rx6Token.CompletionToken.Event = NULL;
146
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);
151
152 Item = NetMapFindKey (&HttpInstance->RxTokens, Wrap->HttpToken);
153 if (Item != NULL) {
154 NetMapRemoveItem (&HttpInstance->RxTokens, Item, NULL);
155 }
156
157 FreePool (Wrap);
158 Wrap = NULL;
159
160 return ;
161 }
162
163 } else {
164 gBS->CloseEvent (Wrap->TcpWrap.Rx4Token.CompletionToken.Event);
165 Wrap->TcpWrap.Rx4Token.CompletionToken.Event = NULL;
166
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);
171
172 Item = NetMapFindKey (&HttpInstance->RxTokens, Wrap->HttpToken);
173 if (Item != NULL) {
174 NetMapRemoveItem (&HttpInstance->RxTokens, Item, NULL);
175 }
176
177 FreePool (Wrap);
178 Wrap = NULL;
179
180 return ;
181 }
182 }
183
184 //
185 // Check whether we receive a complete HTTP message.
186 //
187 ASSERT (HttpInstance->MsgParser != NULL);
188 if (UsingIpv6) {
189 Length = (UINTN) Wrap->TcpWrap.Rx6Data.FragmentTable[0].FragmentLength;
190 } else {
191 Length = (UINTN) Wrap->TcpWrap.Rx4Data.FragmentTable[0].FragmentLength;
192 }
193
194 //
195 // Record the CallbackData data.
196 //
197 HttpInstance->CallbackData.Wrap = (VOID *) Wrap;
198 HttpInstance->CallbackData.ParseData = Wrap->HttpToken->Message->Body;
199 HttpInstance->CallbackData.ParseDataLength = Length;
200
201 //
202 // Parse Body with CallbackData data.
203 //
204 Status = HttpParseMessageBody (
205 HttpInstance->MsgParser,
206 Length,
207 Wrap->HttpToken->Message->Body
208 );
209 if (EFI_ERROR (Status)) {
210 return ;
211 }
212
213 if (HttpIsMessageComplete (HttpInstance->MsgParser)) {
214 //
215 // Free the MsgParse since we already have a full HTTP message.
216 //
217 HttpFreeMsgParser (HttpInstance->MsgParser);
218 HttpInstance->MsgParser = NULL;
219 }
220
221 Wrap->HttpToken->Message->BodyLength = Length;
222 ASSERT (HttpInstance->CacheBody == NULL);
223 //
224 // We receive part of header of next HTTP msg.
225 //
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) {
233 return ;
234 }
235 CopyMem (HttpInstance->CacheBody, HttpInstance->NextMsg, HttpInstance->CacheLen);
236 HttpInstance->NextMsg = HttpInstance->CacheBody;
237 HttpInstance->CacheOffset = 0;
238 }
239 }
240
241 Item = NetMapFindKey (&Wrap->HttpInstance->RxTokens, Wrap->HttpToken);
242 if (Item != NULL) {
243 NetMapRemoveItem (&Wrap->HttpInstance->RxTokens, Item, NULL);
244 }
245
246
247 Wrap->TcpWrap.IsRxDone = TRUE;
248 if (UsingIpv6) {
249 Wrap->HttpToken->Status = Wrap->TcpWrap.Rx6Token.CompletionToken.Status;
250 } else {
251 Wrap->HttpToken->Status = Wrap->TcpWrap.Rx4Token.CompletionToken.Status;
252 }
253
254
255 gBS->SignalEvent (Wrap->HttpToken->Event);
256
257 //
258 // Check pending RxTokens and receive the HTTP message.
259 //
260 NetMapIterate (&Wrap->HttpInstance->RxTokens, HttpTcpReceive, NULL);
261
262 FreePool (Wrap);
263 Wrap = NULL;
264 }
265
266 /**
267 Request HttpTcpReceiveNotifyDpc as a DPC at TPL_CALLBACK.
268
269 @param Event The receive event delivered to TCP for receive.
270 @param Context Context for the callback.
271
272 **/
273 VOID
274 EFIAPI
275 HttpTcpReceiveNotify (
276 IN EFI_EVENT Event,
277 IN VOID *Context
278 )
279 {
280 //
281 // Request HttpTcpTransmitNotifyDpc as a DPC at TPL_CALLBACK
282 //
283 QueueDpc (TPL_CALLBACK, HttpTcpReceiveNotifyDpc, Context);
284 }
285
286 /**
287 Create events for the TCP connection token and TCP close token.
288
289 @param[in] HttpInstance Pointer to HTTP_PROTOCOL structure.
290
291 @retval EFI_SUCCESS The events are created successfully.
292 @retval others Other error as indicated.
293
294 **/
295 EFI_STATUS
296 HttpCreateTcpConnCloseEvent (
297 IN HTTP_PROTOCOL *HttpInstance
298 )
299 {
300 EFI_STATUS Status;
301
302 if (!HttpInstance->LocalAddressIsIPv6) {
303 //
304 // Create events for various asynchronous operations.
305 //
306 Status = gBS->CreateEvent (
307 EVT_NOTIFY_SIGNAL,
308 TPL_NOTIFY,
309 HttpCommonNotify,
310 &HttpInstance->IsTcp4ConnDone,
311 &HttpInstance->Tcp4ConnToken.CompletionToken.Event
312 );
313 if (EFI_ERROR (Status)) {
314 goto ERROR;
315 }
316
317 //
318 // Initialize Tcp4CloseToken
319 //
320 Status = gBS->CreateEvent (
321 EVT_NOTIFY_SIGNAL,
322 TPL_NOTIFY,
323 HttpCommonNotify,
324 &HttpInstance->IsTcp4CloseDone,
325 &HttpInstance->Tcp4CloseToken.CompletionToken.Event
326 );
327 if (EFI_ERROR (Status)) {
328 goto ERROR;
329 }
330
331 } else {
332 //
333 // Create events for various asynchronous operations.
334 //
335 Status = gBS->CreateEvent (
336 EVT_NOTIFY_SIGNAL,
337 TPL_NOTIFY,
338 HttpCommonNotify,
339 &HttpInstance->IsTcp6ConnDone,
340 &HttpInstance->Tcp6ConnToken.CompletionToken.Event
341 );
342 if (EFI_ERROR (Status)) {
343 goto ERROR;
344 }
345
346 //
347 // Initialize Tcp6CloseToken
348 //
349 Status = gBS->CreateEvent (
350 EVT_NOTIFY_SIGNAL,
351 TPL_NOTIFY,
352 HttpCommonNotify,
353 &HttpInstance->IsTcp6CloseDone,
354 &HttpInstance->Tcp6CloseToken.CompletionToken.Event
355 );
356 if (EFI_ERROR (Status)) {
357 goto ERROR;
358 }
359 }
360
361 return EFI_SUCCESS;
362
363 ERROR:
364 //
365 // Error handling
366 //
367 HttpCloseTcpConnCloseEvent (HttpInstance);
368
369 return Status;
370 }
371
372
373 /**
374 Close events in the TCP connection token and TCP close token.
375
376 @param[in] HttpInstance Pointer to HTTP_PROTOCOL structure.
377
378 **/
379 VOID
380 HttpCloseTcpConnCloseEvent (
381 IN HTTP_PROTOCOL *HttpInstance
382 )
383 {
384 ASSERT (HttpInstance != NULL);
385
386 if (HttpInstance->LocalAddressIsIPv6) {
387 if (NULL != HttpInstance->Tcp6ConnToken.CompletionToken.Event) {
388 gBS->CloseEvent (HttpInstance->Tcp6ConnToken.CompletionToken.Event);
389 HttpInstance->Tcp6ConnToken.CompletionToken.Event = NULL;
390 }
391
392 if (NULL != HttpInstance->Tcp6CloseToken.CompletionToken.Event) {
393 gBS->CloseEvent(HttpInstance->Tcp6CloseToken.CompletionToken.Event);
394 HttpInstance->Tcp6CloseToken.CompletionToken.Event = NULL;
395 }
396
397 } else {
398 if (NULL != HttpInstance->Tcp4ConnToken.CompletionToken.Event) {
399 gBS->CloseEvent (HttpInstance->Tcp4ConnToken.CompletionToken.Event);
400 HttpInstance->Tcp4ConnToken.CompletionToken.Event = NULL;
401 }
402
403 if (NULL != HttpInstance->Tcp4CloseToken.CompletionToken.Event) {
404 gBS->CloseEvent(HttpInstance->Tcp4CloseToken.CompletionToken.Event);
405 HttpInstance->Tcp4CloseToken.CompletionToken.Event = NULL;
406 }
407 }
408
409 }
410
411 /**
412 Create event for the TCP transmit token.
413
414 @param[in] Wrap Point to HTTP token's wrap data.
415
416 @retval EFI_SUCCESS The events is created successfully.
417 @retval others Other error as indicated.
418
419 **/
420 EFI_STATUS
421 HttpCreateTcpTxEvent (
422 IN HTTP_TOKEN_WRAP *Wrap
423 )
424 {
425 EFI_STATUS Status;
426 HTTP_PROTOCOL *HttpInstance;
427 HTTP_TCP_TOKEN_WRAP *TcpWrap;
428
429 HttpInstance = Wrap->HttpInstance;
430 TcpWrap = &Wrap->TcpWrap;
431
432 if (!HttpInstance->LocalAddressIsIPv6) {
433 Status = gBS->CreateEvent (
434 EVT_NOTIFY_SIGNAL,
435 TPL_NOTIFY,
436 HttpTcpTransmitNotify,
437 Wrap,
438 &TcpWrap->Tx4Token.CompletionToken.Event
439 );
440 if (EFI_ERROR (Status)) {
441 return Status;
442 }
443
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;
449
450 } else {
451 Status = gBS->CreateEvent (
452 EVT_NOTIFY_SIGNAL,
453 TPL_NOTIFY,
454 HttpTcpTransmitNotify,
455 Wrap,
456 &TcpWrap->Tx6Token.CompletionToken.Event
457 );
458 if (EFI_ERROR (Status)) {
459 return Status;
460 }
461
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;
467
468 }
469
470 return EFI_SUCCESS;
471 }
472
473 /**
474 Create event for the TCP receive token which is used to receive HTTP header.
475
476 @param[in] HttpInstance Pointer to HTTP_PROTOCOL structure.
477
478 @retval EFI_SUCCESS The events is created successfully.
479 @retval others Other error as indicated.
480
481 **/
482 EFI_STATUS
483 HttpCreateTcpRxEventForHeader (
484 IN HTTP_PROTOCOL *HttpInstance
485 )
486 {
487 EFI_STATUS Status;
488
489 if (!HttpInstance->LocalAddressIsIPv6) {
490 Status = gBS->CreateEvent (
491 EVT_NOTIFY_SIGNAL,
492 TPL_NOTIFY,
493 HttpCommonNotify,
494 &HttpInstance->IsRxDone,
495 &HttpInstance->Rx4Token.CompletionToken.Event
496 );
497 if (EFI_ERROR (Status)) {
498 return Status;
499 }
500
501 HttpInstance->Rx4Data.FragmentCount = 1;
502 HttpInstance->Rx4Token.Packet.RxData = &HttpInstance->Rx4Data;
503 HttpInstance->Rx4Token.CompletionToken.Status = EFI_NOT_READY;
504
505 } else {
506 Status = gBS->CreateEvent (
507 EVT_NOTIFY_SIGNAL,
508 TPL_NOTIFY,
509 HttpCommonNotify,
510 &HttpInstance->IsRxDone,
511 &HttpInstance->Rx6Token.CompletionToken.Event
512 );
513 if (EFI_ERROR (Status)) {
514 return Status;
515 }
516
517 HttpInstance->Rx6Data.FragmentCount =1;
518 HttpInstance->Rx6Token.Packet.RxData = &HttpInstance->Rx6Data;
519 HttpInstance->Rx6Token.CompletionToken.Status = EFI_NOT_READY;
520
521 }
522
523
524 return EFI_SUCCESS;
525 }
526
527 /**
528 Create event for the TCP receive token which is used to receive HTTP body.
529
530 @param[in] Wrap Point to HTTP token's wrap data.
531
532 @retval EFI_SUCCESS The events is created successfully.
533 @retval others Other error as indicated.
534
535 **/
536 EFI_STATUS
537 HttpCreateTcpRxEvent (
538 IN HTTP_TOKEN_WRAP *Wrap
539 )
540 {
541 EFI_STATUS Status;
542 HTTP_PROTOCOL *HttpInstance;
543 HTTP_TCP_TOKEN_WRAP *TcpWrap;
544
545 HttpInstance = Wrap->HttpInstance;
546 TcpWrap = &Wrap->TcpWrap;
547 if (!HttpInstance->LocalAddressIsIPv6) {
548 Status = gBS->CreateEvent (
549 EVT_NOTIFY_SIGNAL,
550 TPL_NOTIFY,
551 HttpTcpReceiveNotify,
552 Wrap,
553 &TcpWrap->Rx4Token.CompletionToken.Event
554 );
555 if (EFI_ERROR (Status)) {
556 return Status;
557 }
558
559 TcpWrap->Rx4Data.FragmentCount = 1;
560 TcpWrap->Rx4Token.Packet.RxData = &Wrap->TcpWrap.Rx4Data;
561 TcpWrap->Rx4Token.CompletionToken.Status = EFI_NOT_READY;
562
563 } else {
564 Status = gBS->CreateEvent (
565 EVT_NOTIFY_SIGNAL,
566 TPL_NOTIFY,
567 HttpTcpReceiveNotify,
568 Wrap,
569 &TcpWrap->Rx6Token.CompletionToken.Event
570 );
571 if (EFI_ERROR (Status)) {
572 return Status;
573 }
574
575 TcpWrap->Rx6Data.FragmentCount = 1;
576 TcpWrap->Rx6Token.Packet.RxData = &Wrap->TcpWrap.Rx6Data;
577 TcpWrap->Rx6Token.CompletionToken.Status = EFI_NOT_READY;
578 }
579
580 return EFI_SUCCESS;
581 }
582
583 /**
584 Close Events for Tcp Receive Tokens for HTTP body and HTTP header.
585
586 @param[in] Wrap Pointer to HTTP token's wrap data.
587
588 **/
589 VOID
590 HttpCloseTcpRxEvent (
591 IN HTTP_TOKEN_WRAP *Wrap
592 )
593 {
594 HTTP_PROTOCOL *HttpInstance;
595
596 ASSERT (Wrap != NULL);
597 HttpInstance = Wrap->HttpInstance;
598
599 if (HttpInstance->LocalAddressIsIPv6) {
600 if (Wrap->TcpWrap.Rx6Token.CompletionToken.Event != NULL) {
601 gBS->CloseEvent (Wrap->TcpWrap.Rx6Token.CompletionToken.Event);
602 }
603
604 if (HttpInstance->Rx6Token.CompletionToken.Event != NULL) {
605 gBS->CloseEvent (HttpInstance->Rx6Token.CompletionToken.Event);
606 HttpInstance->Rx6Token.CompletionToken.Event = NULL;
607 }
608 } else {
609 if (Wrap->TcpWrap.Rx4Token.CompletionToken.Event != NULL) {
610 gBS->CloseEvent (Wrap->TcpWrap.Rx4Token.CompletionToken.Event);
611 }
612
613 if (HttpInstance->Rx4Token.CompletionToken.Event != NULL) {
614 gBS->CloseEvent (HttpInstance->Rx4Token.CompletionToken.Event);
615 HttpInstance->Rx4Token.CompletionToken.Event = NULL;
616 }
617 }
618 }
619
620 /**
621 Initialize the HTTP_PROTOCOL structure to the unconfigured state.
622
623 @param[in, out] HttpInstance Pointer to HTTP_PROTOCOL structure.
624 @param[in] IpVersion Indicate us TCP4 protocol or TCP6 protocol.
625
626 @retval EFI_SUCCESS HTTP_PROTOCOL structure is initialized successfully.
627 @retval Others Other error as indicated.
628
629 **/
630 EFI_STATUS
631 HttpInitProtocol (
632 IN OUT HTTP_PROTOCOL *HttpInstance,
633 IN BOOLEAN IpVersion
634 )
635 {
636 EFI_STATUS Status;
637 VOID *Interface;
638 BOOLEAN UsingIpv6;
639
640 ASSERT (HttpInstance != NULL);
641 UsingIpv6 = IpVersion;
642
643 if (!UsingIpv6) {
644 //
645 // Create TCP4 child.
646 //
647 Status = NetLibCreateServiceChild (
648 HttpInstance->Service->ControllerHandle,
649 HttpInstance->Service->Ip4DriverBindingHandle,
650 &gEfiTcp4ServiceBindingProtocolGuid,
651 &HttpInstance->Tcp4ChildHandle
652 );
653
654 if (EFI_ERROR (Status)) {
655 goto ON_ERROR;
656 }
657
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
665 );
666
667 if (EFI_ERROR (Status)) {
668 goto ON_ERROR;
669 }
670
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
678 );
679 if (EFI_ERROR(Status)) {
680 goto ON_ERROR;
681 }
682
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
690 );
691 if (EFI_ERROR(Status)) {
692 goto ON_ERROR;
693 }
694 } else {
695 //
696 // Create TCP6 Child.
697 //
698 Status = NetLibCreateServiceChild (
699 HttpInstance->Service->ControllerHandle,
700 HttpInstance->Service->Ip6DriverBindingHandle,
701 &gEfiTcp6ServiceBindingProtocolGuid,
702 &HttpInstance->Tcp6ChildHandle
703 );
704
705 if (EFI_ERROR (Status)) {
706 goto ON_ERROR;
707 }
708
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
716 );
717
718 if (EFI_ERROR (Status)) {
719 goto ON_ERROR;
720 }
721
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
729 );
730
731 if (EFI_ERROR(Status)) {
732 goto ON_ERROR;
733 }
734
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
742 );
743
744 if (EFI_ERROR(Status)) {
745 goto ON_ERROR;
746 }
747 }
748
749 HttpInstance->Url = AllocateZeroPool (HTTP_URL_BUFFER_LEN);
750 if (HttpInstance->Url == NULL) {
751 Status = EFI_OUT_OF_RESOURCES;
752 goto ON_ERROR;
753 }
754
755 return EFI_SUCCESS;
756
757 ON_ERROR:
758
759 if (HttpInstance->Tcp4ChildHandle != NULL) {
760 gBS->CloseProtocol (
761 HttpInstance->Tcp4ChildHandle,
762 &gEfiTcp4ProtocolGuid,
763 HttpInstance->Service->Ip4DriverBindingHandle,
764 HttpInstance->Service->ControllerHandle
765 );
766
767 gBS->CloseProtocol (
768 HttpInstance->Tcp4ChildHandle,
769 &gEfiTcp4ProtocolGuid,
770 HttpInstance->Service->Ip4DriverBindingHandle,
771 HttpInstance->Handle
772 );
773
774 NetLibDestroyServiceChild (
775 HttpInstance->Service->ControllerHandle,
776 HttpInstance->Service->Ip4DriverBindingHandle,
777 &gEfiTcp4ServiceBindingProtocolGuid,
778 HttpInstance->Tcp4ChildHandle
779 );
780 }
781
782 if (HttpInstance->Service->Tcp4ChildHandle != NULL) {
783 gBS->CloseProtocol (
784 HttpInstance->Service->Tcp4ChildHandle,
785 &gEfiTcp4ProtocolGuid,
786 HttpInstance->Service->Ip4DriverBindingHandle,
787 HttpInstance->Handle
788 );
789 }
790
791 if (HttpInstance->Tcp6ChildHandle != NULL) {
792 gBS->CloseProtocol (
793 HttpInstance->Tcp6ChildHandle,
794 &gEfiTcp6ProtocolGuid,
795 HttpInstance->Service->Ip6DriverBindingHandle,
796 HttpInstance->Service->ControllerHandle
797 );
798
799 gBS->CloseProtocol (
800 HttpInstance->Tcp6ChildHandle,
801 &gEfiTcp6ProtocolGuid,
802 HttpInstance->Service->Ip6DriverBindingHandle,
803 HttpInstance->Handle
804 );
805
806 NetLibDestroyServiceChild (
807 HttpInstance->Service->ControllerHandle,
808 HttpInstance->Service->Ip6DriverBindingHandle,
809 &gEfiTcp6ServiceBindingProtocolGuid,
810 HttpInstance->Tcp6ChildHandle
811 );
812 }
813
814 if (HttpInstance->Service->Tcp6ChildHandle != NULL) {
815 gBS->CloseProtocol (
816 HttpInstance->Service->Tcp6ChildHandle,
817 &gEfiTcp6ProtocolGuid,
818 HttpInstance->Service->Ip6DriverBindingHandle,
819 HttpInstance->Handle
820 );
821 }
822
823 return EFI_UNSUPPORTED;
824
825 }
826
827 /**
828 Clean up the HTTP child, release all the resources used by it.
829
830 @param[in] HttpInstance The HTTP child to clean up.
831
832 **/
833 VOID
834 HttpCleanProtocol (
835 IN HTTP_PROTOCOL *HttpInstance
836 )
837 {
838 HttpCloseConnection (HttpInstance);
839
840 HttpCloseTcpConnCloseEvent (HttpInstance);
841
842 if (HttpInstance->TimeoutEvent != NULL) {
843 gBS->CloseEvent (HttpInstance->TimeoutEvent);
844 HttpInstance->TimeoutEvent = NULL;
845 }
846
847 if (HttpInstance->CacheBody != NULL) {
848 FreePool (HttpInstance->CacheBody);
849 HttpInstance->CacheBody = NULL;
850 HttpInstance->NextMsg = NULL;
851 }
852
853 if (HttpInstance->RemoteHost != NULL) {
854 FreePool (HttpInstance->RemoteHost);
855 HttpInstance->RemoteHost = NULL;
856 }
857
858 if (HttpInstance->MsgParser != NULL) {
859 HttpFreeMsgParser (HttpInstance->MsgParser);
860 HttpInstance->MsgParser = NULL;
861 }
862
863 if (HttpInstance->Url != NULL) {
864 FreePool (HttpInstance->Url);
865 HttpInstance->Url = NULL;
866 }
867
868 NetMapClean (&HttpInstance->TxTokens);
869 NetMapClean (&HttpInstance->RxTokens);
870
871 if (HttpInstance->TlsSb != NULL && HttpInstance->TlsChildHandle != NULL) {
872 //
873 // Destroy the TLS instance.
874 //
875 HttpInstance->TlsSb->DestroyChild (HttpInstance->TlsSb, HttpInstance->TlsChildHandle);
876 HttpInstance->TlsChildHandle = NULL;
877 }
878
879 if (HttpInstance->Tcp4ChildHandle != NULL) {
880 gBS->CloseProtocol (
881 HttpInstance->Tcp4ChildHandle,
882 &gEfiTcp4ProtocolGuid,
883 HttpInstance->Service->Ip4DriverBindingHandle,
884 HttpInstance->Service->ControllerHandle
885 );
886
887 gBS->CloseProtocol (
888 HttpInstance->Tcp4ChildHandle,
889 &gEfiTcp4ProtocolGuid,
890 HttpInstance->Service->Ip4DriverBindingHandle,
891 HttpInstance->Handle
892 );
893
894 NetLibDestroyServiceChild (
895 HttpInstance->Service->ControllerHandle,
896 HttpInstance->Service->Ip4DriverBindingHandle,
897 &gEfiTcp4ServiceBindingProtocolGuid,
898 HttpInstance->Tcp4ChildHandle
899 );
900 }
901
902 if (HttpInstance->Service->Tcp4ChildHandle != NULL) {
903 gBS->CloseProtocol (
904 HttpInstance->Service->Tcp4ChildHandle,
905 &gEfiTcp4ProtocolGuid,
906 HttpInstance->Service->Ip4DriverBindingHandle,
907 HttpInstance->Handle
908 );
909 }
910
911 if (HttpInstance->Tcp6ChildHandle != NULL) {
912 gBS->CloseProtocol (
913 HttpInstance->Tcp6ChildHandle,
914 &gEfiTcp6ProtocolGuid,
915 HttpInstance->Service->Ip6DriverBindingHandle,
916 HttpInstance->Service->ControllerHandle
917 );
918
919 gBS->CloseProtocol (
920 HttpInstance->Tcp6ChildHandle,
921 &gEfiTcp6ProtocolGuid,
922 HttpInstance->Service->Ip6DriverBindingHandle,
923 HttpInstance->Handle
924 );
925
926 NetLibDestroyServiceChild (
927 HttpInstance->Service->ControllerHandle,
928 HttpInstance->Service->Ip6DriverBindingHandle,
929 &gEfiTcp6ServiceBindingProtocolGuid,
930 HttpInstance->Tcp6ChildHandle
931 );
932 }
933
934 if (HttpInstance->Service->Tcp6ChildHandle != NULL) {
935 gBS->CloseProtocol (
936 HttpInstance->Service->Tcp6ChildHandle,
937 &gEfiTcp6ProtocolGuid,
938 HttpInstance->Service->Ip6DriverBindingHandle,
939 HttpInstance->Handle
940 );
941 }
942
943 TlsCloseTxRxEvent (HttpInstance);
944 }
945
946 /**
947 Establish TCP connection with HTTP server.
948
949 @param[in] HttpInstance The HTTP instance private data.
950
951 @retval EFI_SUCCESS The TCP connection is established.
952 @retval Others Other error as indicated.
953
954 **/
955 EFI_STATUS
956 HttpCreateConnection (
957 IN HTTP_PROTOCOL *HttpInstance
958 )
959 {
960 EFI_STATUS Status;
961
962 //
963 // Connect to Http server
964 //
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 HttpNotify (HttpEventConnectTcp, Status);
970 if (EFI_ERROR (Status)) {
971 DEBUG ((EFI_D_ERROR, "HttpCreateConnection: Tcp4->Connect() = %r\n", Status));
972 return Status;
973 }
974
975 while (!HttpInstance->IsTcp4ConnDone) {
976 HttpInstance->Tcp4->Poll (HttpInstance->Tcp4);
977 }
978
979 Status = HttpInstance->Tcp4ConnToken.CompletionToken.Status;
980
981 } else {
982 HttpInstance->IsTcp6ConnDone = FALSE;
983 HttpInstance->Tcp6ConnToken.CompletionToken.Status = EFI_NOT_READY;
984 Status = HttpInstance->Tcp6->Connect (HttpInstance->Tcp6, &HttpInstance->Tcp6ConnToken);
985 HttpNotify (HttpEventConnectTcp, Status);
986 if (EFI_ERROR (Status)) {
987 DEBUG ((EFI_D_ERROR, "HttpCreateConnection: Tcp6->Connect() = %r\n", Status));
988 return Status;
989 }
990
991 while(!HttpInstance->IsTcp6ConnDone) {
992 HttpInstance->Tcp6->Poll (HttpInstance->Tcp6);
993 }
994
995 Status = HttpInstance->Tcp6ConnToken.CompletionToken.Status;
996 }
997
998 if (!EFI_ERROR (Status)) {
999 HttpInstance->State = HTTP_STATE_TCP_CONNECTED;
1000 }
1001
1002 return Status;
1003 }
1004
1005 /**
1006 Close existing TCP connection.
1007
1008 @param[in] HttpInstance The HTTP instance private data.
1009
1010 @retval EFI_SUCCESS The TCP connection is closed.
1011 @retval Others Other error as indicated.
1012
1013 **/
1014 EFI_STATUS
1015 HttpCloseConnection (
1016 IN HTTP_PROTOCOL *HttpInstance
1017 )
1018 {
1019 EFI_STATUS Status;
1020
1021 if (HttpInstance->State == HTTP_STATE_TCP_CONNECTED) {
1022
1023 if (HttpInstance->LocalAddressIsIPv6) {
1024 HttpInstance->Tcp6CloseToken.AbortOnClose = TRUE;
1025 HttpInstance->IsTcp6CloseDone = FALSE;
1026 Status = HttpInstance->Tcp6->Close (HttpInstance->Tcp6, &HttpInstance->Tcp6CloseToken);
1027 if (EFI_ERROR (Status)) {
1028 return Status;
1029 }
1030
1031 while (!HttpInstance->IsTcp6CloseDone) {
1032 HttpInstance->Tcp6->Poll (HttpInstance->Tcp6);
1033 }
1034
1035 } else {
1036 HttpInstance->Tcp4CloseToken.AbortOnClose = TRUE;
1037 HttpInstance->IsTcp4CloseDone = FALSE;
1038 Status = HttpInstance->Tcp4->Close (HttpInstance->Tcp4, &HttpInstance->Tcp4CloseToken);
1039 if (EFI_ERROR (Status)) {
1040 return Status;
1041 }
1042
1043 while (!HttpInstance->IsTcp4CloseDone) {
1044 HttpInstance->Tcp4->Poll (HttpInstance->Tcp4);
1045 }
1046 }
1047
1048 }
1049
1050 HttpInstance->State = HTTP_STATE_TCP_CLOSED;
1051 return EFI_SUCCESS;
1052 }
1053
1054 /**
1055 Configure TCP4 protocol child.
1056
1057 @param[in] HttpInstance The HTTP instance private data.
1058 @param[in] Wrap The HTTP token's wrap data.
1059
1060 @retval EFI_SUCCESS The TCP4 protocol child is configured.
1061 @retval Others Other error as indicated.
1062
1063 **/
1064 EFI_STATUS
1065 HttpConfigureTcp4 (
1066 IN HTTP_PROTOCOL *HttpInstance,
1067 IN HTTP_TOKEN_WRAP *Wrap
1068 )
1069 {
1070 EFI_STATUS Status;
1071 EFI_TCP4_CONFIG_DATA *Tcp4CfgData;
1072 EFI_TCP4_ACCESS_POINT *Tcp4AP;
1073 EFI_TCP4_OPTION *Tcp4Option;
1074
1075 ASSERT (HttpInstance != NULL);
1076
1077
1078 Tcp4CfgData = &HttpInstance->Tcp4CfgData;
1079 ZeroMem (Tcp4CfgData, sizeof (EFI_TCP4_CONFIG_DATA));
1080
1081 Tcp4CfgData->TypeOfService = HTTP_TOS_DEAULT;
1082 Tcp4CfgData->TimeToLive = HTTP_TTL_DEAULT;
1083 Tcp4CfgData->ControlOption = &HttpInstance->Tcp4Option;
1084
1085 Tcp4AP = &Tcp4CfgData->AccessPoint;
1086 Tcp4AP->UseDefaultAddress = HttpInstance->IPv4Node.UseDefaultAddress;
1087 if (!Tcp4AP->UseDefaultAddress) {
1088 IP4_COPY_ADDRESS (&Tcp4AP->StationAddress, &HttpInstance->IPv4Node.LocalAddress);
1089 IP4_COPY_ADDRESS (&Tcp4AP->SubnetMask, &HttpInstance->IPv4Node.LocalSubnet);
1090 }
1091
1092 Tcp4AP->StationPort = HttpInstance->IPv4Node.LocalPort;
1093 Tcp4AP->RemotePort = HttpInstance->RemotePort;
1094 Tcp4AP->ActiveFlag = TRUE;
1095 IP4_COPY_ADDRESS (&Tcp4AP->RemoteAddress, &HttpInstance->RemoteAddr);
1096
1097 Tcp4Option = Tcp4CfgData->ControlOption;
1098 Tcp4Option->ReceiveBufferSize = HTTP_BUFFER_SIZE_DEAULT;
1099 Tcp4Option->SendBufferSize = HTTP_BUFFER_SIZE_DEAULT;
1100 Tcp4Option->MaxSynBackLog = HTTP_MAX_SYN_BACK_LOG;
1101 Tcp4Option->ConnectionTimeout = HTTP_CONNECTION_TIMEOUT;
1102 Tcp4Option->DataRetries = HTTP_DATA_RETRIES;
1103 Tcp4Option->FinTimeout = HTTP_FIN_TIMEOUT;
1104 Tcp4Option->KeepAliveProbes = HTTP_KEEP_ALIVE_PROBES;
1105 Tcp4Option->KeepAliveTime = HTTP_KEEP_ALIVE_TIME;
1106 Tcp4Option->KeepAliveInterval = HTTP_KEEP_ALIVE_INTERVAL;
1107 Tcp4Option->EnableNagle = TRUE;
1108 Tcp4CfgData->ControlOption = Tcp4Option;
1109
1110 Status = HttpInstance->Tcp4->Configure (HttpInstance->Tcp4, Tcp4CfgData);
1111 if (EFI_ERROR (Status)) {
1112 DEBUG ((EFI_D_ERROR, "HttpConfigureTcp4 - %r\n", Status));
1113 return Status;
1114 }
1115
1116 Status = HttpCreateTcpConnCloseEvent (HttpInstance);
1117 if (EFI_ERROR (Status)) {
1118 return Status;
1119 }
1120
1121 Status = HttpCreateTcpTxEvent (Wrap);
1122 if (EFI_ERROR (Status)) {
1123 return Status;
1124 }
1125
1126 HttpInstance->State = HTTP_STATE_TCP_CONFIGED;
1127
1128 return EFI_SUCCESS;
1129 }
1130
1131 /**
1132 Configure TCP6 protocol child.
1133
1134 @param[in] HttpInstance The HTTP instance private data.
1135 @param[in] Wrap The HTTP token's wrap data.
1136
1137 @retval EFI_SUCCESS The TCP6 protocol child is configured.
1138 @retval Others Other error as indicated.
1139
1140 **/
1141 EFI_STATUS
1142 HttpConfigureTcp6 (
1143 IN HTTP_PROTOCOL *HttpInstance,
1144 IN HTTP_TOKEN_WRAP *Wrap
1145 )
1146 {
1147 EFI_STATUS Status;
1148 EFI_TCP6_CONFIG_DATA *Tcp6CfgData;
1149 EFI_TCP6_ACCESS_POINT *Tcp6Ap;
1150 EFI_TCP6_OPTION *Tcp6Option;
1151
1152 ASSERT (HttpInstance != NULL);
1153
1154 Tcp6CfgData = &HttpInstance->Tcp6CfgData;
1155 ZeroMem (Tcp6CfgData, sizeof (EFI_TCP6_CONFIG_DATA));
1156
1157 Tcp6CfgData->TrafficClass = 0;
1158 Tcp6CfgData->HopLimit = 255;
1159 Tcp6CfgData->ControlOption = &HttpInstance->Tcp6Option;
1160
1161 Tcp6Ap = &Tcp6CfgData->AccessPoint;
1162 Tcp6Ap->ActiveFlag = TRUE;
1163 Tcp6Ap->StationPort = HttpInstance->Ipv6Node.LocalPort;
1164 Tcp6Ap->RemotePort = HttpInstance->RemotePort;
1165 IP6_COPY_ADDRESS (&Tcp6Ap->StationAddress, &HttpInstance->Ipv6Node.LocalAddress);
1166 IP6_COPY_ADDRESS (&Tcp6Ap->RemoteAddress , &HttpInstance->RemoteIpv6Addr);
1167
1168 Tcp6Option = Tcp6CfgData->ControlOption;
1169 Tcp6Option->ReceiveBufferSize = HTTP_BUFFER_SIZE_DEAULT;
1170 Tcp6Option->SendBufferSize = HTTP_BUFFER_SIZE_DEAULT;
1171 Tcp6Option->MaxSynBackLog = HTTP_MAX_SYN_BACK_LOG;
1172 Tcp6Option->ConnectionTimeout = HTTP_CONNECTION_TIMEOUT;
1173 Tcp6Option->DataRetries = HTTP_DATA_RETRIES;
1174 Tcp6Option->FinTimeout = HTTP_FIN_TIMEOUT;
1175 Tcp6Option->KeepAliveProbes = HTTP_KEEP_ALIVE_PROBES;
1176 Tcp6Option->KeepAliveTime = HTTP_KEEP_ALIVE_TIME;
1177 Tcp6Option->KeepAliveInterval = HTTP_KEEP_ALIVE_INTERVAL;
1178 Tcp6Option->EnableNagle = TRUE;
1179
1180 Status = HttpInstance->Tcp6->Configure (HttpInstance->Tcp6, Tcp6CfgData);
1181 if (EFI_ERROR (Status)) {
1182 DEBUG ((EFI_D_ERROR, "HttpConfigureTcp6 - %r\n", Status));
1183 return Status;
1184 }
1185
1186 Status = HttpCreateTcpConnCloseEvent (HttpInstance);
1187 if (EFI_ERROR (Status)) {
1188 return Status;
1189 }
1190
1191 Status = HttpCreateTcpTxEvent (Wrap);
1192 if (EFI_ERROR (Status)) {
1193 return Status;
1194 }
1195
1196 HttpInstance->State = HTTP_STATE_TCP_CONFIGED;
1197
1198 return EFI_SUCCESS;
1199
1200 }
1201
1202 /**
1203 Check existing TCP connection, if in error state, recover TCP4 connection. Then,
1204 connect one TLS session if required.
1205
1206 @param[in] HttpInstance The HTTP instance private data.
1207
1208 @retval EFI_SUCCESS The TCP connection is established.
1209 @retval EFI_NOT_READY TCP4 protocol child is not created or configured.
1210 @retval Others Other error as indicated.
1211
1212 **/
1213 EFI_STATUS
1214 HttpConnectTcp4 (
1215 IN HTTP_PROTOCOL *HttpInstance
1216 )
1217 {
1218 EFI_STATUS Status;
1219 EFI_TCP4_CONNECTION_STATE Tcp4State;
1220
1221
1222 if (HttpInstance->State < HTTP_STATE_TCP_CONFIGED || HttpInstance->Tcp4 == NULL) {
1223 return EFI_NOT_READY;
1224 }
1225
1226 Status = HttpInstance->Tcp4->GetModeData(
1227 HttpInstance->Tcp4,
1228 &Tcp4State,
1229 NULL,
1230 NULL,
1231 NULL,
1232 NULL
1233 );
1234 if (EFI_ERROR(Status)){
1235 DEBUG ((EFI_D_ERROR, "Tcp4 GetModeData fail - %x\n", Status));
1236 return Status;
1237 }
1238
1239 if (Tcp4State == Tcp4StateEstablished) {
1240 return EFI_SUCCESS;
1241 } else if (Tcp4State > Tcp4StateEstablished ) {
1242 HttpCloseConnection(HttpInstance);
1243 }
1244
1245 Status = HttpCreateConnection (HttpInstance);
1246 if (EFI_ERROR(Status)){
1247 DEBUG ((EFI_D_ERROR, "Tcp4 Connection fail - %x\n", Status));
1248 return Status;
1249 }
1250
1251 //
1252 // Tls session connection.
1253 //
1254 if (HttpInstance->UseHttps) {
1255 if (HttpInstance->TimeoutEvent == NULL) {
1256 //
1257 // Create TimeoutEvent for TLS connection.
1258 //
1259 Status = gBS->CreateEvent (
1260 EVT_TIMER,
1261 TPL_CALLBACK,
1262 NULL,
1263 NULL,
1264 &HttpInstance->TimeoutEvent
1265 );
1266 if (EFI_ERROR (Status)) {
1267 TlsCloseTxRxEvent (HttpInstance);
1268 return Status;
1269 }
1270 }
1271
1272 //
1273 // Start the timer, and wait Timeout seconds for connection.
1274 //
1275 Status = gBS->SetTimer (HttpInstance->TimeoutEvent, TimerRelative, HTTP_CONNECTION_TIMEOUT * TICKS_PER_SECOND);
1276 if (EFI_ERROR (Status)) {
1277 TlsCloseTxRxEvent (HttpInstance);
1278 return Status;
1279 }
1280
1281 Status = TlsConnectSession (HttpInstance, HttpInstance->TimeoutEvent);
1282 HttpNotify (HttpEventTlsConnectSession, Status);
1283
1284 gBS->SetTimer (HttpInstance->TimeoutEvent, TimerCancel, 0);
1285
1286 if (EFI_ERROR (Status)) {
1287 TlsCloseTxRxEvent (HttpInstance);
1288 return Status;
1289 }
1290 }
1291
1292 return Status;
1293 }
1294
1295 /**
1296 Check existing TCP connection, if in error state, recover TCP6 connection. Then,
1297 connect one TLS session if required.
1298
1299 @param[in] HttpInstance The HTTP instance private data.
1300
1301 @retval EFI_SUCCESS The TCP connection is established.
1302 @retval EFI_NOT_READY TCP6 protocol child is not created or configured.
1303 @retval Others Other error as indicated.
1304
1305 **/
1306 EFI_STATUS
1307 HttpConnectTcp6 (
1308 IN HTTP_PROTOCOL *HttpInstance
1309 )
1310 {
1311 EFI_STATUS Status;
1312 EFI_TCP6_CONNECTION_STATE Tcp6State;
1313
1314 if (HttpInstance->State < HTTP_STATE_TCP_CONFIGED || HttpInstance->Tcp6 == NULL) {
1315 return EFI_NOT_READY;
1316 }
1317
1318 Status = HttpInstance->Tcp6->GetModeData (
1319 HttpInstance->Tcp6,
1320 &Tcp6State,
1321 NULL,
1322 NULL,
1323 NULL,
1324 NULL
1325 );
1326
1327 if (EFI_ERROR(Status)){
1328 DEBUG ((EFI_D_ERROR, "Tcp6 GetModeData fail - %x\n", Status));
1329 return Status;
1330 }
1331
1332 if (Tcp6State == Tcp6StateEstablished) {
1333 return EFI_SUCCESS;
1334 } else if (Tcp6State > Tcp6StateEstablished ) {
1335 HttpCloseConnection(HttpInstance);
1336 }
1337
1338 Status = HttpCreateConnection (HttpInstance);
1339 if (EFI_ERROR(Status)){
1340 DEBUG ((EFI_D_ERROR, "Tcp6 Connection fail - %x\n", Status));
1341 return Status;
1342 }
1343
1344 //
1345 // Tls session connection.
1346 //
1347 if (HttpInstance->UseHttps) {
1348 if (HttpInstance->TimeoutEvent == NULL) {
1349 //
1350 // Create TimeoutEvent for TLS connection.
1351 //
1352 Status = gBS->CreateEvent (
1353 EVT_TIMER,
1354 TPL_CALLBACK,
1355 NULL,
1356 NULL,
1357 &HttpInstance->TimeoutEvent
1358 );
1359 if (EFI_ERROR (Status)) {
1360 TlsCloseTxRxEvent (HttpInstance);
1361 return Status;
1362 }
1363 }
1364
1365 //
1366 // Start the timer, and wait Timeout seconds for connection.
1367 //
1368 Status = gBS->SetTimer (HttpInstance->TimeoutEvent, TimerRelative, HTTP_CONNECTION_TIMEOUT * TICKS_PER_SECOND);
1369 if (EFI_ERROR (Status)) {
1370 TlsCloseTxRxEvent (HttpInstance);
1371 return Status;
1372 }
1373
1374 Status = TlsConnectSession (HttpInstance, HttpInstance->TimeoutEvent);
1375 HttpNotify (HttpEventTlsConnectSession, Status);
1376
1377 gBS->SetTimer (HttpInstance->TimeoutEvent, TimerCancel, 0);
1378
1379 if (EFI_ERROR (Status)) {
1380 TlsCloseTxRxEvent (HttpInstance);
1381 return Status;
1382 }
1383 }
1384
1385 return Status;
1386 }
1387
1388 /**
1389 Initialize Http session.
1390
1391 @param[in] HttpInstance The HTTP instance private data.
1392 @param[in] Wrap The HTTP token's wrap data.
1393 @param[in] Configure The Flag indicates whether need to initialize session.
1394 @param[in] TlsConfigure The Flag indicates whether it's the new Tls session.
1395
1396 @retval EFI_SUCCESS The initialization of session is done.
1397 @retval Others Other error as indicated.
1398
1399 **/
1400 EFI_STATUS
1401 HttpInitSession (
1402 IN HTTP_PROTOCOL *HttpInstance,
1403 IN HTTP_TOKEN_WRAP *Wrap,
1404 IN BOOLEAN Configure,
1405 IN BOOLEAN TlsConfigure
1406 )
1407 {
1408 EFI_STATUS Status;
1409 ASSERT (HttpInstance != NULL);
1410
1411 //
1412 // Configure Tls session.
1413 //
1414 if (TlsConfigure) {
1415 Status = TlsConfigureSession (HttpInstance);
1416 if (EFI_ERROR (Status)) {
1417 return Status;
1418 }
1419 }
1420
1421 if (!HttpInstance->LocalAddressIsIPv6) {
1422 //
1423 // Configure TCP instance.
1424 //
1425 if (Configure) {
1426 Status = HttpConfigureTcp4 (HttpInstance, Wrap);
1427 if (EFI_ERROR (Status)) {
1428 return Status;
1429 }
1430 }
1431
1432 //
1433 // Connect TCP.
1434 //
1435 Status = HttpConnectTcp4 (HttpInstance);
1436 if (EFI_ERROR (Status)) {
1437 return Status;
1438 }
1439 } else {
1440 //
1441 // Configure TCP instance.
1442 //
1443 if (Configure) {
1444 Status = HttpConfigureTcp6 (HttpInstance, Wrap);
1445 if (EFI_ERROR (Status)) {
1446 return Status;
1447 }
1448 }
1449
1450 //
1451 // Connect TCP.
1452 //
1453 Status = HttpConnectTcp6 (HttpInstance);
1454 if (EFI_ERROR (Status)) {
1455 return Status;
1456 }
1457 }
1458
1459 return EFI_SUCCESS;
1460
1461 }
1462
1463 /**
1464 Send the HTTP or HTTPS message through TCP4 or TCP6.
1465
1466 @param[in] HttpInstance The HTTP instance private data.
1467 @param[in] Wrap The HTTP token's wrap data.
1468 @param[in] TxString Buffer containing the HTTP message string.
1469 @param[in] TxStringLen Length of the HTTP message string in bytes.
1470
1471 @retval EFI_SUCCESS The HTTP message is queued into TCP transmit queue.
1472 @retval Others Other error as indicated.
1473
1474 **/
1475 EFI_STATUS
1476 HttpTransmitTcp (
1477 IN HTTP_PROTOCOL *HttpInstance,
1478 IN HTTP_TOKEN_WRAP *Wrap,
1479 IN UINT8 *TxString,
1480 IN UINTN TxStringLen
1481 )
1482 {
1483 EFI_STATUS Status;
1484 EFI_TCP4_IO_TOKEN *Tx4Token;
1485 EFI_TCP4_PROTOCOL *Tcp4;
1486 EFI_TCP6_IO_TOKEN *Tx6Token;
1487 EFI_TCP6_PROTOCOL *Tcp6;
1488 UINT8 *TlsRecord;
1489 UINT16 PayloadSize;
1490 NET_FRAGMENT TempFragment;
1491 NET_FRAGMENT Fragment;
1492 UINTN RecordCount;
1493 UINTN RemainingLen;
1494
1495 Status = EFI_SUCCESS;
1496 TlsRecord = NULL;
1497 PayloadSize = 0;
1498 TempFragment.Len = 0;
1499 TempFragment.Bulk = NULL;
1500 Fragment.Len = 0;
1501 Fragment.Bulk = NULL;
1502 RecordCount = 0;
1503 RemainingLen = 0;
1504
1505 //
1506 // Need to encrypt data.
1507 //
1508 if (HttpInstance->UseHttps) {
1509 //
1510 // Allocate enough buffer for each TLS plaintext records.
1511 //
1512 TlsRecord = AllocateZeroPool (TLS_RECORD_HEADER_LENGTH + TLS_PLAINTEXT_RECORD_MAX_PAYLOAD_LENGTH);
1513 if (TlsRecord == NULL) {
1514 Status = EFI_OUT_OF_RESOURCES;
1515 return Status;
1516 }
1517
1518 //
1519 // Allocate enough buffer for all TLS ciphertext records.
1520 //
1521 RecordCount = TxStringLen / TLS_PLAINTEXT_RECORD_MAX_PAYLOAD_LENGTH + 1;
1522 Fragment.Bulk = AllocateZeroPool (RecordCount * (TLS_RECORD_HEADER_LENGTH + TLS_CIPHERTEXT_RECORD_MAX_PAYLOAD_LENGTH));
1523 if (Fragment.Bulk == NULL) {
1524 Status = EFI_OUT_OF_RESOURCES;
1525 goto ON_ERROR;
1526 }
1527
1528 //
1529 // Encrypt each TLS plaintext records.
1530 //
1531 RemainingLen = TxStringLen;
1532 while (RemainingLen != 0) {
1533 PayloadSize = (UINT16) MIN (TLS_PLAINTEXT_RECORD_MAX_PAYLOAD_LENGTH, RemainingLen);
1534
1535 ((TLS_RECORD_HEADER *) TlsRecord)->ContentType = TlsContentTypeApplicationData;
1536 ((TLS_RECORD_HEADER *) TlsRecord)->Version.Major = HttpInstance->TlsConfigData.Version.Major;
1537 ((TLS_RECORD_HEADER *) TlsRecord)->Version.Minor = HttpInstance->TlsConfigData.Version.Minor;
1538 ((TLS_RECORD_HEADER *) TlsRecord)->Length = PayloadSize;
1539
1540 CopyMem (TlsRecord + TLS_RECORD_HEADER_LENGTH, TxString + (TxStringLen - RemainingLen), PayloadSize);
1541
1542 Status = TlsProcessMessage (
1543 HttpInstance,
1544 TlsRecord,
1545 TLS_RECORD_HEADER_LENGTH + PayloadSize,
1546 EfiTlsEncrypt,
1547 &TempFragment
1548 );
1549 if (EFI_ERROR (Status)) {
1550 goto ON_ERROR;
1551 }
1552
1553 //
1554 // Record the processed/encrypted Packet.
1555 //
1556 CopyMem (Fragment.Bulk + Fragment.Len, TempFragment.Bulk, TempFragment.Len);
1557 Fragment.Len += TempFragment.Len;
1558
1559 FreePool (TempFragment.Bulk);
1560 TempFragment.Len = 0;
1561 TempFragment.Bulk = NULL;
1562
1563 RemainingLen -= (UINTN) PayloadSize;
1564 ZeroMem (TlsRecord, TLS_RECORD_HEADER_LENGTH + TLS_PLAINTEXT_RECORD_MAX_PAYLOAD_LENGTH);
1565 }
1566
1567 FreePool (TlsRecord);
1568 TlsRecord = NULL;
1569 }
1570
1571 if (!HttpInstance->LocalAddressIsIPv6) {
1572 Tcp4 = HttpInstance->Tcp4;
1573 Tx4Token = &Wrap->TcpWrap.Tx4Token;
1574
1575 if (HttpInstance->UseHttps) {
1576 Tx4Token->Packet.TxData->DataLength = Fragment.Len;
1577 Tx4Token->Packet.TxData->FragmentTable[0].FragmentLength = Fragment.Len;
1578 Tx4Token->Packet.TxData->FragmentTable[0].FragmentBuffer = (VOID *) Fragment.Bulk;
1579 } else {
1580 Tx4Token->Packet.TxData->DataLength = (UINT32) TxStringLen;
1581 Tx4Token->Packet.TxData->FragmentTable[0].FragmentLength = (UINT32) TxStringLen;
1582 Tx4Token->Packet.TxData->FragmentTable[0].FragmentBuffer = (VOID *) TxString;
1583 }
1584
1585 Tx4Token->CompletionToken.Status = EFI_NOT_READY;
1586
1587 Wrap->TcpWrap.IsTxDone = FALSE;
1588 Status = Tcp4->Transmit (Tcp4, Tx4Token);
1589 if (EFI_ERROR (Status)) {
1590 DEBUG ((EFI_D_ERROR, "Transmit failed: %r\n", Status));
1591 goto ON_ERROR;
1592 }
1593
1594 } else {
1595 Tcp6 = HttpInstance->Tcp6;
1596 Tx6Token = &Wrap->TcpWrap.Tx6Token;
1597
1598 if (HttpInstance->UseHttps) {
1599 Tx6Token->Packet.TxData->DataLength = Fragment.Len;
1600 Tx6Token->Packet.TxData->FragmentTable[0].FragmentLength = Fragment.Len;
1601 Tx6Token->Packet.TxData->FragmentTable[0].FragmentBuffer = (VOID *) Fragment.Bulk;
1602 } else {
1603 Tx6Token->Packet.TxData->DataLength = (UINT32) TxStringLen;
1604 Tx6Token->Packet.TxData->FragmentTable[0].FragmentLength = (UINT32) TxStringLen;
1605 Tx6Token->Packet.TxData->FragmentTable[0].FragmentBuffer = (VOID *) TxString;
1606 }
1607
1608 Tx6Token->CompletionToken.Status = EFI_NOT_READY;
1609
1610 Wrap->TcpWrap.IsTxDone = FALSE;
1611 Status = Tcp6->Transmit (Tcp6, Tx6Token);
1612 if (EFI_ERROR (Status)) {
1613 DEBUG ((EFI_D_ERROR, "Transmit failed: %r\n", Status));
1614 goto ON_ERROR;
1615 }
1616 }
1617
1618 return Status;
1619
1620 ON_ERROR:
1621
1622 if (HttpInstance->UseHttps) {
1623 if (TlsRecord != NULL) {
1624 FreePool (TlsRecord);
1625 TlsRecord = NULL;
1626 }
1627
1628 if (Fragment.Bulk != NULL) {
1629 FreePool (Fragment.Bulk);
1630 Fragment.Bulk = NULL;
1631 }
1632 }
1633
1634 return Status;
1635 }
1636
1637 /**
1638 Check whether the user's token or event has already
1639 been enqueue on HTTP Tx or Rx Token list.
1640
1641 @param[in] Map The container of either user's transmit or receive
1642 token.
1643 @param[in] Item Current item to check against.
1644 @param[in] Context The Token to check against.
1645
1646 @retval EFI_ACCESS_DENIED The token or event has already been enqueued in IP
1647 @retval EFI_SUCCESS The current item isn't the same token/event as the
1648 context.
1649
1650 **/
1651 EFI_STATUS
1652 EFIAPI
1653 HttpTokenExist (
1654 IN NET_MAP *Map,
1655 IN NET_MAP_ITEM *Item,
1656 IN VOID *Context
1657 )
1658 {
1659 EFI_HTTP_TOKEN *Token;
1660 EFI_HTTP_TOKEN *TokenInItem;
1661
1662 Token = (EFI_HTTP_TOKEN *) Context;
1663 TokenInItem = (EFI_HTTP_TOKEN *) Item->Key;
1664
1665 if (Token == TokenInItem || Token->Event == TokenInItem->Event) {
1666 return EFI_ACCESS_DENIED;
1667 }
1668
1669 return EFI_SUCCESS;
1670 }
1671
1672 /**
1673 Check whether the HTTP message associated with Tx4Token or Tx6Token is already sent out.
1674
1675 @param[in] Map The container of Tx4Token or Tx6Token.
1676 @param[in] Item Current item to check against.
1677 @param[in] Context The Token to check against.
1678
1679 @retval EFI_NOT_READY The HTTP message is still queued in the list.
1680 @retval EFI_SUCCESS The HTTP message has been sent out.
1681
1682 **/
1683 EFI_STATUS
1684 EFIAPI
1685 HttpTcpNotReady (
1686 IN NET_MAP *Map,
1687 IN NET_MAP_ITEM *Item,
1688 IN VOID *Context
1689 )
1690 {
1691 HTTP_TOKEN_WRAP *ValueInItem;
1692
1693 ValueInItem = (HTTP_TOKEN_WRAP *) Item->Value;
1694
1695 if (!ValueInItem->TcpWrap.IsTxDone) {
1696 return EFI_NOT_READY;
1697 }
1698
1699 return EFI_SUCCESS;
1700 }
1701
1702 /**
1703 Transmit the HTTP or HTTPS message by processing the associated HTTP token.
1704
1705 @param[in] Map The container of Tx4Token or Tx6Token.
1706 @param[in] Item Current item to check against.
1707 @param[in] Context The Token to check against.
1708
1709 @retval EFI_OUT_OF_RESOURCES Failed to allocate resources.
1710 @retval EFI_SUCCESS The HTTP message is queued into TCP transmit
1711 queue.
1712
1713 **/
1714 EFI_STATUS
1715 EFIAPI
1716 HttpTcpTransmit (
1717 IN NET_MAP *Map,
1718 IN NET_MAP_ITEM *Item,
1719 IN VOID *Context
1720 )
1721 {
1722 HTTP_TOKEN_WRAP *ValueInItem;
1723 EFI_STATUS Status;
1724 CHAR8 *RequestMsg;
1725 CHAR8 *Url;
1726 UINTN UrlSize;
1727 UINTN RequestMsgSize;
1728
1729 RequestMsg = NULL;
1730
1731 ValueInItem = (HTTP_TOKEN_WRAP *) Item->Value;
1732 if (ValueInItem->TcpWrap.IsTxDone) {
1733 return EFI_SUCCESS;
1734 }
1735
1736 //
1737 // Parse the URI of the remote host.
1738 //
1739 UrlSize = StrLen (ValueInItem->HttpToken->Message->Data.Request->Url) + 1;
1740 Url = AllocatePool (UrlSize);
1741 if (Url == NULL) {
1742 return EFI_OUT_OF_RESOURCES;
1743 }
1744
1745 UnicodeStrToAsciiStrS (ValueInItem->HttpToken->Message->Data.Request->Url, Url, UrlSize);
1746
1747 //
1748 // Create request message.
1749 //
1750 Status = HttpGenRequestMessage (
1751 ValueInItem->HttpToken->Message,
1752 Url,
1753 &RequestMsg,
1754 &RequestMsgSize
1755 );
1756 FreePool (Url);
1757
1758 if (EFI_ERROR (Status) || NULL == RequestMsg){
1759 return Status;
1760 }
1761
1762 ASSERT (RequestMsg != NULL);
1763
1764 //
1765 // Transmit the request message.
1766 //
1767 Status = HttpTransmitTcp (
1768 ValueInItem->HttpInstance,
1769 ValueInItem,
1770 (UINT8*) RequestMsg,
1771 RequestMsgSize
1772 );
1773 FreePool (RequestMsg);
1774 return Status;
1775 }
1776
1777 /**
1778 Receive the HTTP response by processing the associated HTTP token.
1779
1780 @param[in] Map The container of Rx4Token or Rx6Token.
1781 @param[in] Item Current item to check against.
1782 @param[in] Context The Token to check against.
1783
1784 @retval EFI_SUCCESS The HTTP response is queued into TCP receive
1785 queue.
1786 @retval Others Other error as indicated.
1787
1788 **/
1789 EFI_STATUS
1790 EFIAPI
1791 HttpTcpReceive (
1792 IN NET_MAP *Map,
1793 IN NET_MAP_ITEM *Item,
1794 IN VOID *Context
1795 )
1796 {
1797 //
1798 // Process the queued HTTP response.
1799 //
1800 return HttpResponseWorker ((HTTP_TOKEN_WRAP *) Item->Value);
1801 }
1802
1803 /**
1804 Receive the HTTP header by processing the associated HTTP token.
1805
1806 @param[in] HttpInstance The HTTP instance private data.
1807 @param[in, out] SizeofHeaders The HTTP header length.
1808 @param[in, out] BufferSize The size of buffer to cache the header message.
1809 @param[in] Timeout The time to wait for receiving the header packet.
1810
1811 @retval EFI_SUCCESS The HTTP header is received.
1812 @retval Others Other errors as indicated.
1813
1814 **/
1815 EFI_STATUS
1816 HttpTcpReceiveHeader (
1817 IN HTTP_PROTOCOL *HttpInstance,
1818 IN OUT UINTN *SizeofHeaders,
1819 IN OUT UINTN *BufferSize,
1820 IN EFI_EVENT Timeout
1821 )
1822 {
1823 EFI_STATUS Status;
1824 EFI_TCP4_IO_TOKEN *Rx4Token;
1825 EFI_TCP4_PROTOCOL *Tcp4;
1826 EFI_TCP6_IO_TOKEN *Rx6Token;
1827 EFI_TCP6_PROTOCOL *Tcp6;
1828 CHAR8 **EndofHeader;
1829 CHAR8 **HttpHeaders;
1830 CHAR8 *Buffer;
1831 NET_FRAGMENT Fragment;
1832
1833 ASSERT (HttpInstance != NULL);
1834
1835 EndofHeader = HttpInstance->EndofHeader;
1836 HttpHeaders = HttpInstance->HttpHeaders;
1837 Tcp4 = HttpInstance->Tcp4;
1838 Tcp6 = HttpInstance->Tcp6;
1839 Buffer = NULL;
1840 Rx4Token = NULL;
1841 Rx6Token = NULL;
1842 Fragment.Len = 0;
1843 Fragment.Bulk = NULL;
1844
1845 if (HttpInstance->LocalAddressIsIPv6) {
1846 ASSERT (Tcp6 != NULL);
1847 } else {
1848 ASSERT (Tcp4 != NULL);
1849 }
1850
1851 if (!HttpInstance->UseHttps) {
1852 Status = HttpCreateTcpRxEventForHeader (HttpInstance);
1853 if (EFI_ERROR (Status)) {
1854 return Status;
1855 }
1856 }
1857
1858 if (!HttpInstance->LocalAddressIsIPv6) {
1859 if (!HttpInstance->UseHttps) {
1860 Rx4Token = &HttpInstance->Rx4Token;
1861 Rx4Token->Packet.RxData->FragmentTable[0].FragmentBuffer = AllocateZeroPool (DEF_BUF_LEN);
1862 if (Rx4Token->Packet.RxData->FragmentTable[0].FragmentBuffer == NULL) {
1863 Status = EFI_OUT_OF_RESOURCES;
1864 return Status;
1865 }
1866 }
1867
1868 //
1869 // Receive the HTTP headers only when EFI_HTTP_RESPONSE_DATA is not NULL.
1870 //
1871 while (*EndofHeader == NULL) {
1872 if (!HttpInstance->UseHttps) {
1873 HttpInstance->IsRxDone = FALSE;
1874 Rx4Token->Packet.RxData->DataLength = DEF_BUF_LEN;
1875 Rx4Token->Packet.RxData->FragmentTable[0].FragmentLength = DEF_BUF_LEN;
1876 Status = Tcp4->Receive (Tcp4, Rx4Token);
1877 if (EFI_ERROR (Status)) {
1878 DEBUG ((EFI_D_ERROR, "Tcp4 receive failed: %r\n", Status));
1879 return Status;
1880 }
1881
1882 while (!HttpInstance->IsRxDone && ((Timeout == NULL) || EFI_ERROR (gBS->CheckEvent (Timeout)))) {
1883 Tcp4->Poll (Tcp4);
1884 }
1885
1886 if (!HttpInstance->IsRxDone) {
1887 //
1888 // Cancel the Token before close its Event.
1889 //
1890 Tcp4->Cancel (HttpInstance->Tcp4, &Rx4Token->CompletionToken);
1891 gBS->CloseEvent (Rx4Token->CompletionToken.Event);
1892 Rx4Token->CompletionToken.Status = EFI_TIMEOUT;
1893 }
1894
1895 Status = Rx4Token->CompletionToken.Status;
1896 if (EFI_ERROR (Status)) {
1897 return Status;
1898 }
1899
1900 Fragment.Len = Rx4Token->Packet.RxData->FragmentTable[0].FragmentLength;
1901 Fragment.Bulk = (UINT8 *) Rx4Token->Packet.RxData->FragmentTable[0].FragmentBuffer;
1902 } else {
1903 if (Fragment.Bulk != NULL) {
1904 FreePool (Fragment.Bulk);
1905 Fragment.Bulk = NULL;
1906 }
1907
1908 Status = HttpsReceive (HttpInstance, &Fragment, Timeout);
1909 if (EFI_ERROR (Status)) {
1910 DEBUG ((EFI_D_ERROR, "Tcp4 receive failed: %r\n", Status));
1911 return Status;
1912 }
1913 }
1914
1915 //
1916 // Append the response string along with a Null-terminator.
1917 //
1918 *BufferSize = *SizeofHeaders + Fragment.Len;
1919 Buffer = AllocatePool (*BufferSize + 1);
1920 if (Buffer == NULL) {
1921 Status = EFI_OUT_OF_RESOURCES;
1922 return Status;
1923 }
1924
1925 if (*HttpHeaders != NULL) {
1926 CopyMem (Buffer, *HttpHeaders, *SizeofHeaders);
1927 FreePool (*HttpHeaders);
1928 }
1929
1930 CopyMem (
1931 Buffer + *SizeofHeaders,
1932 Fragment.Bulk,
1933 Fragment.Len
1934 );
1935 *(Buffer + *BufferSize) = '\0';
1936 *HttpHeaders = Buffer;
1937 *SizeofHeaders = *BufferSize;
1938
1939 //
1940 // Check whether we received end of HTTP headers.
1941 //
1942 *EndofHeader = AsciiStrStr (*HttpHeaders, HTTP_END_OF_HDR_STR);
1943 };
1944
1945 //
1946 // Free the buffer.
1947 //
1948 if (Rx4Token != NULL && Rx4Token->Packet.RxData != NULL && Rx4Token->Packet.RxData->FragmentTable[0].FragmentBuffer != NULL) {
1949 FreePool (Rx4Token->Packet.RxData->FragmentTable[0].FragmentBuffer);
1950 Rx4Token->Packet.RxData->FragmentTable[0].FragmentBuffer = NULL;
1951 Fragment.Bulk = NULL;
1952 }
1953
1954 if (Fragment.Bulk != NULL) {
1955 FreePool (Fragment.Bulk);
1956 Fragment.Bulk = NULL;
1957 }
1958 } else {
1959 if (!HttpInstance->UseHttps) {
1960 Rx6Token = &HttpInstance->Rx6Token;
1961 Rx6Token->Packet.RxData->FragmentTable[0].FragmentBuffer = AllocateZeroPool (DEF_BUF_LEN);
1962 if (Rx6Token->Packet.RxData->FragmentTable[0].FragmentBuffer == NULL) {
1963 Status = EFI_OUT_OF_RESOURCES;
1964 return Status;
1965 }
1966 }
1967
1968 //
1969 // Receive the HTTP headers only when EFI_HTTP_RESPONSE_DATA is not NULL.
1970 //
1971 while (*EndofHeader == NULL) {
1972 if (!HttpInstance->UseHttps) {
1973 HttpInstance->IsRxDone = FALSE;
1974 Rx6Token->Packet.RxData->DataLength = DEF_BUF_LEN;
1975 Rx6Token->Packet.RxData->FragmentTable[0].FragmentLength = DEF_BUF_LEN;
1976 Status = Tcp6->Receive (Tcp6, Rx6Token);
1977 if (EFI_ERROR (Status)) {
1978 DEBUG ((EFI_D_ERROR, "Tcp6 receive failed: %r\n", Status));
1979 return Status;
1980 }
1981
1982 while (!HttpInstance->IsRxDone && ((Timeout == NULL) || EFI_ERROR (gBS->CheckEvent (Timeout)))) {
1983 Tcp6->Poll (Tcp6);
1984 }
1985
1986 if (!HttpInstance->IsRxDone) {
1987 //
1988 // Cancel the Token before close its Event.
1989 //
1990 Tcp6->Cancel (HttpInstance->Tcp6, &Rx6Token->CompletionToken);
1991 gBS->CloseEvent (Rx6Token->CompletionToken.Event);
1992 Rx6Token->CompletionToken.Status = EFI_TIMEOUT;
1993 }
1994
1995 Status = Rx6Token->CompletionToken.Status;
1996 if (EFI_ERROR (Status)) {
1997 return Status;
1998 }
1999
2000 Fragment.Len = Rx6Token->Packet.RxData->FragmentTable[0].FragmentLength;
2001 Fragment.Bulk = (UINT8 *) Rx6Token->Packet.RxData->FragmentTable[0].FragmentBuffer;
2002 } else {
2003 if (Fragment.Bulk != NULL) {
2004 FreePool (Fragment.Bulk);
2005 Fragment.Bulk = NULL;
2006 }
2007
2008 Status = HttpsReceive (HttpInstance, &Fragment, Timeout);
2009 if (EFI_ERROR (Status)) {
2010 DEBUG ((EFI_D_ERROR, "Tcp6 receive failed: %r\n", Status));
2011 return Status;
2012 }
2013 }
2014
2015 //
2016 // Append the response string along with a Null-terminator.
2017 //
2018 *BufferSize = *SizeofHeaders + Fragment.Len;
2019 Buffer = AllocatePool (*BufferSize + 1);
2020 if (Buffer == NULL) {
2021 Status = EFI_OUT_OF_RESOURCES;
2022 return Status;
2023 }
2024
2025 if (*HttpHeaders != NULL) {
2026 CopyMem (Buffer, *HttpHeaders, *SizeofHeaders);
2027 FreePool (*HttpHeaders);
2028 }
2029
2030 CopyMem (
2031 Buffer + *SizeofHeaders,
2032 Fragment.Bulk,
2033 Fragment.Len
2034 );
2035 *(Buffer + *BufferSize) = '\0';
2036 *HttpHeaders = Buffer;
2037 *SizeofHeaders = *BufferSize;
2038
2039 //
2040 // Check whether we received end of HTTP headers.
2041 //
2042 *EndofHeader = AsciiStrStr (*HttpHeaders, HTTP_END_OF_HDR_STR);
2043 };
2044
2045 //
2046 // Free the buffer.
2047 //
2048 if (Rx6Token != NULL && Rx6Token->Packet.RxData != NULL && Rx6Token->Packet.RxData->FragmentTable[0].FragmentBuffer != NULL) {
2049 FreePool (Rx6Token->Packet.RxData->FragmentTable[0].FragmentBuffer);
2050 Rx6Token->Packet.RxData->FragmentTable[0].FragmentBuffer = NULL;
2051 Fragment.Bulk = NULL;
2052 }
2053
2054 if (Fragment.Bulk != NULL) {
2055 FreePool (Fragment.Bulk);
2056 Fragment.Bulk = NULL;
2057 }
2058 }
2059
2060 //
2061 // Skip the CRLF after the HTTP headers.
2062 //
2063 *EndofHeader = *EndofHeader + AsciiStrLen (HTTP_END_OF_HDR_STR);
2064
2065 *SizeofHeaders = *EndofHeader - *HttpHeaders;
2066
2067 return EFI_SUCCESS;
2068 }
2069
2070 /**
2071 Receive the HTTP body by processing the associated HTTP token.
2072
2073 @param[in] Wrap The HTTP token's wrap data.
2074 @param[in] HttpMsg The HTTP message data.
2075
2076 @retval EFI_SUCCESS The HTTP body is received.
2077 @retval Others Other error as indicated.
2078
2079 **/
2080 EFI_STATUS
2081 HttpTcpReceiveBody (
2082 IN HTTP_TOKEN_WRAP *Wrap,
2083 IN EFI_HTTP_MESSAGE *HttpMsg
2084 )
2085 {
2086 EFI_STATUS Status;
2087 HTTP_PROTOCOL *HttpInstance;
2088 EFI_TCP6_PROTOCOL *Tcp6;
2089 EFI_TCP6_IO_TOKEN *Rx6Token;
2090 EFI_TCP4_PROTOCOL *Tcp4;
2091 EFI_TCP4_IO_TOKEN *Rx4Token;
2092
2093 HttpInstance = Wrap->HttpInstance;
2094 Tcp4 = HttpInstance->Tcp4;
2095 Tcp6 = HttpInstance->Tcp6;
2096 Rx4Token = NULL;
2097 Rx6Token = NULL;
2098
2099 if (HttpInstance->LocalAddressIsIPv6) {
2100 ASSERT (Tcp6 != NULL);
2101 } else {
2102 ASSERT (Tcp4 != NULL);
2103 }
2104
2105 if (HttpInstance->LocalAddressIsIPv6) {
2106 Rx6Token = &Wrap->TcpWrap.Rx6Token;
2107 Rx6Token ->Packet.RxData->DataLength = (UINT32) MIN (MAX_UINT32, HttpMsg->BodyLength);
2108 Rx6Token ->Packet.RxData->FragmentTable[0].FragmentLength = (UINT32) MIN (MAX_UINT32, HttpMsg->BodyLength);
2109 Rx6Token ->Packet.RxData->FragmentTable[0].FragmentBuffer = (VOID *) HttpMsg->Body;
2110 Rx6Token->CompletionToken.Status = EFI_NOT_READY;
2111
2112 Status = Tcp6->Receive (Tcp6, Rx6Token);
2113 if (EFI_ERROR (Status)) {
2114 DEBUG ((EFI_D_ERROR, "Tcp6 receive failed: %r\n", Status));
2115 return Status;
2116 }
2117 } else {
2118 Rx4Token = &Wrap->TcpWrap.Rx4Token;
2119 Rx4Token->Packet.RxData->DataLength = (UINT32) MIN (MAX_UINT32, HttpMsg->BodyLength);
2120 Rx4Token->Packet.RxData->FragmentTable[0].FragmentLength = (UINT32) MIN (MAX_UINT32, HttpMsg->BodyLength);
2121 Rx4Token->Packet.RxData->FragmentTable[0].FragmentBuffer = (VOID *) HttpMsg->Body;
2122
2123 Rx4Token->CompletionToken.Status = EFI_NOT_READY;
2124 Status = Tcp4->Receive (Tcp4, Rx4Token);
2125 if (EFI_ERROR (Status)) {
2126 DEBUG ((EFI_D_ERROR, "Tcp4 receive failed: %r\n", Status));
2127 return Status;
2128 }
2129 }
2130
2131 return EFI_SUCCESS;
2132
2133 }
2134
2135 /**
2136 Clean up Tcp Tokens while the Tcp transmission error occurs.
2137
2138 @param[in] Wrap Pointer to HTTP token's wrap data.
2139
2140 **/
2141 VOID
2142 HttpTcpTokenCleanup (
2143 IN HTTP_TOKEN_WRAP *Wrap
2144 )
2145 {
2146 HTTP_PROTOCOL *HttpInstance;
2147 EFI_TCP4_IO_TOKEN *Rx4Token;
2148 EFI_TCP6_IO_TOKEN *Rx6Token;
2149
2150 ASSERT (Wrap != NULL);
2151 HttpInstance = Wrap->HttpInstance;
2152 Rx4Token = NULL;
2153 Rx6Token = NULL;
2154
2155 if (HttpInstance->LocalAddressIsIPv6) {
2156 Rx6Token = &Wrap->TcpWrap.Rx6Token;
2157
2158 if (Rx6Token->CompletionToken.Event != NULL) {
2159 gBS->CloseEvent (Rx6Token->CompletionToken.Event);
2160 Rx6Token->CompletionToken.Event = NULL;
2161 }
2162
2163 FreePool (Wrap);
2164
2165 Rx6Token = &HttpInstance->Rx6Token;
2166
2167 if (Rx6Token->CompletionToken.Event != NULL) {
2168 gBS->CloseEvent (Rx6Token->CompletionToken.Event);
2169 Rx6Token->CompletionToken.Event = NULL;
2170 }
2171
2172 if (Rx6Token->Packet.RxData->FragmentTable[0].FragmentBuffer != NULL) {
2173 FreePool (Rx6Token->Packet.RxData->FragmentTable[0].FragmentBuffer);
2174 Rx6Token->Packet.RxData->FragmentTable[0].FragmentBuffer = NULL;
2175 }
2176
2177 } else {
2178 Rx4Token = &Wrap->TcpWrap.Rx4Token;
2179
2180 if (Rx4Token->CompletionToken.Event != NULL) {
2181 gBS->CloseEvent (Rx4Token->CompletionToken.Event);
2182 Rx4Token->CompletionToken.Event = NULL;
2183 }
2184
2185 FreePool (Wrap);
2186
2187 Rx4Token = &HttpInstance->Rx4Token;
2188
2189 if (Rx4Token->CompletionToken.Event != NULL) {
2190 gBS->CloseEvent (Rx4Token->CompletionToken.Event);
2191 Rx4Token->CompletionToken.Event = NULL;
2192 }
2193
2194
2195 if (Rx4Token->Packet.RxData->FragmentTable[0].FragmentBuffer != NULL) {
2196 FreePool (Rx4Token->Packet.RxData->FragmentTable[0].FragmentBuffer);
2197 Rx4Token->Packet.RxData->FragmentTable[0].FragmentBuffer = NULL;
2198 }
2199 }
2200
2201 }
2202
2203 /**
2204 Send Events via EDKII_HTTP_CALLBACK_PROTOCOL.
2205
2206 @param[in] Event The event that occurs in the current state.
2207 @param[in] EventStatus The Status of Event, EFI_SUCCESS or other errors.
2208
2209 **/
2210 VOID
2211 HttpNotify (
2212 IN EDKII_HTTP_CALLBACK_EVENT Event,
2213 IN EFI_STATUS EventStatus
2214 )
2215 {
2216 EFI_STATUS Status;
2217 EFI_HANDLE *Handles;
2218 UINTN Index;
2219 UINTN HandleCount;
2220 EFI_HANDLE Handle;
2221 EDKII_HTTP_CALLBACK_PROTOCOL *HttpCallback;
2222
2223 DEBUG ((DEBUG_INFO, "HttpNotify: Event - %d, EventStatus - %r\n", Event, EventStatus));
2224
2225 Handles = NULL;
2226 HandleCount = 0;
2227 Status = gBS->LocateHandleBuffer (
2228 ByProtocol,
2229 &gEdkiiHttpCallbackProtocolGuid,
2230 NULL,
2231 &HandleCount,
2232 &Handles
2233 );
2234 if (Status == EFI_SUCCESS) {
2235 for (Index = 0; Index < HandleCount; Index++) {
2236 Handle = Handles[Index];
2237 Status = gBS->HandleProtocol (
2238 Handle,
2239 &gEdkiiHttpCallbackProtocolGuid,
2240 (VOID **) &HttpCallback
2241 );
2242 if (Status == EFI_SUCCESS) {
2243 DEBUG ((DEBUG_INFO, "HttpNotify: Notifying %p\n", HttpCallback));
2244 HttpCallback->Callback (
2245 HttpCallback,
2246 Event,
2247 EventStatus
2248 );
2249 }
2250 }
2251 FreePool (Handles);
2252 }
2253 }