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