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