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