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