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