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