]> git.proxmox.com Git - mirror_edk2.git/blob - NetworkPkg/HttpDxe/HttpProto.c
NetworkPkg: Update Http driver to use DPC mechanism.
[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 This program and the accompanying materials
6 are licensed and made available under the terms and conditions of the BSD License
7 which accompanies this distribution. The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php
9
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
12
13 **/
14
15 #include "HttpDriver.h"
16
17 /**
18 The common notify function used in HTTP driver.
19
20 @param[in] Event The event signaled.
21 @param[in] Context The context.
22
23 **/
24 VOID
25 EFIAPI
26 HttpCommonNotify (
27 IN EFI_EVENT Event,
28 IN VOID *Context
29 )
30 {
31 if ((Event == NULL) || (Context == NULL)) {
32 return ;
33 }
34
35 *((BOOLEAN *) Context) = TRUE;
36 }
37
38 /**
39 The notify function associated with TxToken for Tcp4->Transmit().
40
41 @param[in] Context The context.
42
43 **/
44 VOID
45 EFIAPI
46 HttpTcpTransmitNotifyDpc (
47 IN VOID *Context
48 )
49 {
50 HTTP_TOKEN_WRAP *Wrap;
51
52 if (Context == NULL) {
53 return ;
54 }
55
56 Wrap = (HTTP_TOKEN_WRAP *) Context;
57 Wrap->HttpToken->Status = Wrap->TcpWrap.TxToken.CompletionToken.Status;
58 gBS->SignalEvent (Wrap->HttpToken->Event);
59
60 //
61 // Free resources.
62 //
63 if (Wrap->TcpWrap.TxToken.Packet.TxData->FragmentTable[0].FragmentBuffer != NULL) {
64 FreePool (Wrap->TcpWrap.TxToken.Packet.TxData->FragmentTable[0].FragmentBuffer);
65 }
66
67 if (Wrap->TcpWrap.TxToken.CompletionToken.Event != NULL) {
68 gBS->CloseEvent (Wrap->TcpWrap.TxToken.CompletionToken.Event);
69 }
70
71 Wrap->TcpWrap.IsTxDone = TRUE;
72
73 //
74 // Check pending TxTokens and sent out.
75 //
76 NetMapIterate (&Wrap->HttpInstance->TxTokens, HttpTcpTransmit, NULL);
77
78 }
79
80 /**
81 Request HttpTcpTransmitNotifyDpc as a DPC at TPL_CALLBACK.
82
83 @param Event The receive event delivered to TCP for transmit.
84 @param Context Context for the callback.
85
86 **/
87 VOID
88 EFIAPI
89 HttpTcpTransmitNotify (
90 IN EFI_EVENT Event,
91 IN VOID *Context
92 )
93 {
94 //
95 // Request HttpTcpTransmitNotifyDpc as a DPC at TPL_CALLBACK
96 //
97 QueueDpc (TPL_CALLBACK, HttpTcpTransmitNotifyDpc, Context);
98 }
99
100
101 /**
102 The notify function associated with RxToken for Tcp4->Receive ().
103
104 @param[in] Context The context.
105
106 **/
107 VOID
108 EFIAPI
109 HttpTcpReceiveNotifyDpc (
110 IN VOID *Context
111 )
112 {
113 HTTP_TOKEN_WRAP *Wrap;
114 NET_MAP_ITEM *Item;
115 UINTN Length;
116 EFI_STATUS Status;
117 HTTP_PROTOCOL *HttpInstance;
118
119 if (Context == NULL) {
120 return ;
121 }
122
123 Wrap = (HTTP_TOKEN_WRAP *) Context;
124 gBS->CloseEvent (Wrap->TcpWrap.RxToken.CompletionToken.Event);
125 if (EFI_ERROR (Wrap->TcpWrap.RxToken.CompletionToken.Status)) {
126 return ;
127 }
128
129 HttpInstance = Wrap->HttpInstance;
130
131 //
132 // Check whether we receive a complete HTTP message.
133 //
134 ASSERT (HttpInstance->MsgParser != NULL);
135
136 Length = (UINTN) Wrap->TcpWrap.RxData.FragmentTable[0].FragmentLength;
137 Status = HttpParseMessageBody (
138 HttpInstance->MsgParser,
139 Length,
140 Wrap->HttpToken->Message->Body
141 );
142 if (EFI_ERROR (Status)) {
143 return ;
144 }
145
146 if (HttpIsMessageComplete (HttpInstance->MsgParser)) {
147 //
148 // Free the MsgParse since we already have a full HTTP message.
149 //
150 HttpFreeMsgParser (HttpInstance->MsgParser);
151 HttpInstance->MsgParser = NULL;
152 }
153
154 Wrap->HttpToken->Message->BodyLength = Length;
155 ASSERT (HttpInstance->CacheBody == NULL);
156 //
157 // We receive part of header of next HTTP msg.
158 //
159 if (HttpInstance->NextMsg != NULL) {
160 Wrap->HttpToken->Message->BodyLength = HttpInstance->NextMsg -
161 (CHAR8 *) Wrap->HttpToken->Message->Body;
162 HttpInstance->CacheLen = Length - Wrap->HttpToken->Message->BodyLength;
163 if (HttpInstance->CacheLen != 0) {
164 HttpInstance->CacheBody = AllocateZeroPool (HttpInstance->CacheLen);
165 if (HttpInstance->CacheBody == NULL) {
166 return ;
167 }
168 CopyMem (HttpInstance->CacheBody, HttpInstance->NextMsg, HttpInstance->CacheLen);
169 HttpInstance->NextMsg = HttpInstance->CacheBody;
170 HttpInstance->CacheOffset = 0;
171 }
172 }
173
174 Item = NetMapFindKey (&Wrap->HttpInstance->RxTokens, Wrap->HttpToken);
175 if (Item != NULL) {
176 NetMapRemoveItem (&Wrap->HttpInstance->RxTokens, Item, NULL);
177 }
178
179
180 Wrap->TcpWrap.IsRxDone = TRUE;
181 Wrap->HttpToken->Status = Wrap->TcpWrap.RxToken.CompletionToken.Status;
182
183 gBS->SignalEvent (Wrap->HttpToken->Event);
184
185 //
186 // Check pending RxTokens and receive the HTTP message.
187 //
188 NetMapIterate (&Wrap->HttpInstance->RxTokens, HttpTcpReceive, NULL);
189
190 FreePool (Wrap);
191 }
192
193 /**
194 Request HttpTcpReceiveNotifyDpc as a DPC at TPL_CALLBACK.
195
196 @param Event The receive event delivered to TCP for receive.
197 @param Context Context for the callback.
198
199 **/
200 VOID
201 EFIAPI
202 HttpTcpReceiveNotify (
203 IN EFI_EVENT Event,
204 IN VOID *Context
205 )
206 {
207 //
208 // Request HttpTcpTransmitNotifyDpc as a DPC at TPL_CALLBACK
209 //
210 QueueDpc (TPL_CALLBACK, HttpTcpReceiveNotifyDpc, Context);
211 }
212
213
214 /**
215 Create events for the TCP4 connection token and TCP4 close token.
216
217 @param[in] HttpInstance Pointer to HTTP_PROTOCOL structure.
218
219 @retval EFI_SUCCESS The events are created successfully.
220 @retval others Other error as indicated.
221
222 **/
223 EFI_STATUS
224 HttpCreateTcp4ConnCloseEvent (
225 IN HTTP_PROTOCOL *HttpInstance
226 )
227 {
228 EFI_STATUS Status;
229 //
230 // Create events for variuos asynchronous operations.
231 //
232 Status = gBS->CreateEvent (
233 EVT_NOTIFY_SIGNAL,
234 TPL_NOTIFY,
235 HttpCommonNotify,
236 &HttpInstance->IsConnDone,
237 &HttpInstance->ConnToken.CompletionToken.Event
238 );
239 if (EFI_ERROR (Status)) {
240 goto ERROR;
241 }
242
243 //
244 // Initialize CloseToken
245 //
246 Status = gBS->CreateEvent (
247 EVT_NOTIFY_SIGNAL,
248 TPL_NOTIFY,
249 HttpCommonNotify,
250 &HttpInstance->IsCloseDone,
251 &HttpInstance->CloseToken.CompletionToken.Event
252 );
253 if (EFI_ERROR (Status)) {
254 goto ERROR;
255 }
256
257
258 return EFI_SUCCESS;
259
260 ERROR:
261 //
262 // Error handling
263 //
264 HttpCloseTcp4ConnCloseEvent (HttpInstance);
265
266 return Status;
267 }
268
269
270 /**
271 Close events in the TCP4 connection token and TCP4 close token.
272
273 @param[in] HttpInstance Pointer to HTTP_PROTOCOL structure.
274
275 **/
276 VOID
277 HttpCloseTcp4ConnCloseEvent (
278 IN HTTP_PROTOCOL *HttpInstance
279 )
280 {
281 ASSERT (HttpInstance != NULL);
282
283 if (NULL != HttpInstance->ConnToken.CompletionToken.Event) {
284 gBS->CloseEvent (HttpInstance->ConnToken.CompletionToken.Event);
285 HttpInstance->ConnToken.CompletionToken.Event = NULL;
286 }
287
288 if (NULL != HttpInstance->CloseToken.CompletionToken.Event) {
289 gBS->CloseEvent(HttpInstance->CloseToken.CompletionToken.Event);
290 HttpInstance->CloseToken.CompletionToken.Event = NULL;
291 }
292 }
293
294 /**
295 Create event for the TCP4 transmit token.
296
297 @param[in] Wrap Point to HTTP token's wrap data.
298
299 @retval EFI_SUCCESS The events is created successfully.
300 @retval others Other error as indicated.
301
302 **/
303 EFI_STATUS
304 HttpCreateTcp4TxEvent (
305 IN HTTP_TOKEN_WRAP *Wrap
306 )
307 {
308 EFI_STATUS Status;
309 HTTP_PROTOCOL *HttpInstance;
310 HTTP_TCP_TOKEN_WRAP *TcpWrap;
311
312 HttpInstance = Wrap->HttpInstance;
313 TcpWrap = &Wrap->TcpWrap;
314
315 Status = gBS->CreateEvent (
316 EVT_NOTIFY_SIGNAL,
317 TPL_NOTIFY,
318 HttpTcpTransmitNotify,
319 Wrap,
320 &TcpWrap->TxToken.CompletionToken.Event
321 );
322 if (EFI_ERROR (Status)) {
323 return Status;
324 }
325
326 TcpWrap->TxData.Push = TRUE;
327 TcpWrap->TxData.Urgent = FALSE;
328 TcpWrap->TxData.FragmentCount = 1;
329 TcpWrap->TxToken.Packet.TxData = &Wrap->TcpWrap.TxData;
330 TcpWrap->TxToken.CompletionToken.Status = EFI_NOT_READY;
331
332 return EFI_SUCCESS;
333 }
334
335 /**
336 Create event for the TCP4 receive token which is used to receive HTTP header.
337
338 @param[in] HttpInstance Pointer to HTTP_PROTOCOL structure.
339
340 @retval EFI_SUCCESS The events is created successfully.
341 @retval others Other error as indicated.
342
343 **/
344 EFI_STATUS
345 HttpCreateTcp4RxEventForHeader (
346 IN HTTP_PROTOCOL *HttpInstance
347 )
348 {
349 EFI_STATUS Status;
350
351
352 Status = gBS->CreateEvent (
353 EVT_NOTIFY_SIGNAL,
354 TPL_NOTIFY,
355 HttpCommonNotify,
356 &HttpInstance->IsRxDone,
357 &HttpInstance->RxToken.CompletionToken.Event
358 );
359 if (EFI_ERROR (Status)) {
360 return Status;
361 }
362
363 HttpInstance->RxData.FragmentCount = 1;
364 HttpInstance->RxToken.Packet.RxData = &HttpInstance->RxData;
365 HttpInstance->RxToken.CompletionToken.Status = EFI_NOT_READY;
366
367 return EFI_SUCCESS;
368 }
369
370 /**
371 Create event for the TCP4 receive token which is used to receive HTTP body.
372
373 @param[in] Wrap Point to HTTP token's wrap data.
374
375 @retval EFI_SUCCESS The events is created successfully.
376 @retval others Other error as indicated.
377
378 **/
379 EFI_STATUS
380 HttpCreateTcp4RxEvent (
381 IN HTTP_TOKEN_WRAP *Wrap
382 )
383 {
384 EFI_STATUS Status;
385 HTTP_PROTOCOL *HttpInstance;
386 HTTP_TCP_TOKEN_WRAP *TcpWrap;
387
388 HttpInstance = Wrap->HttpInstance;
389 TcpWrap = &Wrap->TcpWrap;
390
391 Status = gBS->CreateEvent (
392 EVT_NOTIFY_SIGNAL,
393 TPL_NOTIFY,
394 HttpTcpReceiveNotify,
395 Wrap,
396 &TcpWrap->RxToken.CompletionToken.Event
397 );
398 if (EFI_ERROR (Status)) {
399 return Status;
400 }
401
402 TcpWrap->RxData.FragmentCount = 1;
403 TcpWrap->RxToken.Packet.RxData = &Wrap->TcpWrap.RxData;
404 TcpWrap->RxToken.CompletionToken.Status = EFI_NOT_READY;
405
406 return EFI_SUCCESS;
407 }
408
409 /**
410 Intiialize the HTTP_PROTOCOL structure to the unconfigured state.
411
412 @param[in] HttpSb The HTTP service private instance.
413 @param[in, out] HttpInstance Pointer to HTTP_PROTOCOL structure.
414
415 @retval EFI_SUCCESS HTTP_PROTOCOL structure is initialized successfully.
416 @retval Others Other error as indicated.
417
418 **/
419 EFI_STATUS
420 HttpInitProtocol (
421 IN HTTP_SERVICE *HttpSb,
422 IN OUT HTTP_PROTOCOL *HttpInstance
423 )
424 {
425 EFI_STATUS Status;
426 VOID *Interface;
427
428 ASSERT ((HttpSb != NULL) && (HttpInstance != NULL));
429
430 HttpInstance->Signature = HTTP_PROTOCOL_SIGNATURE;
431 CopyMem (&HttpInstance->Http, &mEfiHttpTemplate, sizeof (HttpInstance->Http));
432 HttpInstance->Service = HttpSb;
433
434 //
435 // Create TCP child.
436 //
437 Status = NetLibCreateServiceChild (
438 HttpInstance->Service->ControllerHandle,
439 HttpInstance->Service->ImageHandle,
440 &gEfiTcp4ServiceBindingProtocolGuid,
441 &HttpInstance->TcpChildHandle
442 );
443
444 if (EFI_ERROR (Status)) {
445 goto ON_ERROR;
446 }
447
448 Status = gBS->OpenProtocol (
449 HttpInstance->TcpChildHandle,
450 &gEfiTcp4ProtocolGuid,
451 (VOID **) &Interface,
452 HttpInstance->Service->ImageHandle,
453 HttpInstance->Service->ControllerHandle,
454 EFI_OPEN_PROTOCOL_BY_DRIVER
455 );
456
457 if (EFI_ERROR (Status)) {
458 goto ON_ERROR;
459 }
460
461 Status = gBS->OpenProtocol (
462 HttpInstance->TcpChildHandle,
463 &gEfiTcp4ProtocolGuid,
464 (VOID **) &HttpInstance->Tcp4,
465 HttpInstance->Service->ImageHandle,
466 HttpInstance->Handle,
467 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
468 );
469 if (EFI_ERROR(Status)) {
470 goto ON_ERROR;
471 }
472
473 HttpInstance->Url = AllocateZeroPool (HTTP_URL_BUFFER_LEN);
474 if (HttpInstance->Url == NULL) {
475 Status = EFI_OUT_OF_RESOURCES;
476 goto ON_ERROR;
477 }
478
479 NetMapInit (&HttpInstance->TxTokens);
480 NetMapInit (&HttpInstance->RxTokens);
481
482 return EFI_SUCCESS;
483
484 ON_ERROR:
485
486 if (HttpInstance->TcpChildHandle != NULL) {
487 gBS->CloseProtocol (
488 HttpInstance->TcpChildHandle,
489 &gEfiTcp4ProtocolGuid,
490 HttpInstance->Service->ImageHandle,
491 HttpInstance->Service->ControllerHandle
492 );
493
494 gBS->CloseProtocol (
495 HttpInstance->TcpChildHandle,
496 &gEfiTcp4ProtocolGuid,
497 HttpInstance->Service->ImageHandle,
498 HttpInstance->Handle
499 );
500
501 NetLibDestroyServiceChild (
502 HttpInstance->Service->ControllerHandle,
503 HttpInstance->Service->ImageHandle,
504 &gEfiTcp4ServiceBindingProtocolGuid,
505 HttpInstance->TcpChildHandle
506 );
507 }
508
509 return Status;
510
511 }
512
513 /**
514 Clean up the HTTP child, release all the resources used by it.
515
516 @param[in] HttpInstance The HTTP child to clean up.
517
518 **/
519 VOID
520 HttpCleanProtocol (
521 IN HTTP_PROTOCOL *HttpInstance
522 )
523 {
524 HttpCloseConnection (HttpInstance);
525
526 HttpCloseTcp4ConnCloseEvent (HttpInstance);
527
528 if (HttpInstance->CacheBody != NULL) {
529 FreePool (HttpInstance->CacheBody);
530 HttpInstance->CacheBody = NULL;
531 HttpInstance->NextMsg = NULL;
532 }
533
534 if (HttpInstance->RemoteHost != NULL) {
535 FreePool (HttpInstance->RemoteHost);
536 HttpInstance->RemoteHost = NULL;
537 }
538
539 if (HttpInstance->MsgParser != NULL) {
540 HttpFreeMsgParser (HttpInstance->MsgParser);
541 HttpInstance->MsgParser = NULL;
542 }
543
544 if (HttpInstance->Url != NULL) {
545 FreePool (HttpInstance->Url);
546 HttpInstance->Url = NULL;
547 }
548
549 NetMapClean (&HttpInstance->TxTokens);
550 NetMapClean (&HttpInstance->RxTokens);
551
552 if (HttpInstance->TcpChildHandle != NULL) {
553 gBS->CloseProtocol (
554 HttpInstance->TcpChildHandle,
555 &gEfiTcp4ProtocolGuid,
556 HttpInstance->Service->ImageHandle,
557 HttpInstance->Service->ControllerHandle
558 );
559
560 gBS->CloseProtocol (
561 HttpInstance->TcpChildHandle,
562 &gEfiTcp4ProtocolGuid,
563 HttpInstance->Service->ImageHandle,
564 HttpInstance->Handle
565 );
566
567 NetLibDestroyServiceChild (
568 HttpInstance->Service->ControllerHandle,
569 HttpInstance->Service->ImageHandle,
570 &gEfiTcp4ServiceBindingProtocolGuid,
571 HttpInstance->TcpChildHandle
572 );
573 }
574 }
575
576 /**
577 Establish TCP connection with HTTP server.
578
579 @param[in] HttpInstance The HTTP instance private data.
580
581 @retval EFI_SUCCESS The TCP connection is established.
582 @retval Others Other error as indicated.
583
584 **/
585 EFI_STATUS
586 HttpCreateConnection (
587 IN HTTP_PROTOCOL *HttpInstance
588 )
589 {
590 EFI_STATUS Status;
591
592 //
593 // Create events for variuos asynchronous operations.
594 //
595 HttpInstance->IsConnDone = FALSE;
596
597 //
598 // Connect to Http server
599 //
600 HttpInstance->ConnToken.CompletionToken.Status = EFI_NOT_READY;
601 Status = HttpInstance->Tcp4->Connect (HttpInstance->Tcp4, &HttpInstance->ConnToken);
602 if (EFI_ERROR (Status)) {
603 DEBUG ((EFI_D_ERROR, "HttpCreateConnection: Tcp4->Connect() = %r\n", Status));
604 return Status;
605 }
606
607 while (!HttpInstance->IsConnDone) {
608 HttpInstance->Tcp4->Poll (HttpInstance->Tcp4);
609 }
610
611 Status = HttpInstance->ConnToken.CompletionToken.Status;
612
613 if (!EFI_ERROR (Status)) {
614 HttpInstance->State = HTTP_STATE_TCP_CONNECTED;
615 }
616
617 return Status;
618 }
619
620 /**
621 Close existing TCP connection.
622
623 @param[in] HttpInstance The HTTP instance private data.
624
625 @retval EFI_SUCCESS The TCP connection is closed.
626 @retval Others Other error as indicated.
627
628 **/
629 EFI_STATUS
630 HttpCloseConnection (
631 IN HTTP_PROTOCOL *HttpInstance
632 )
633 {
634 EFI_STATUS Status;
635
636 if (HttpInstance->State == HTTP_STATE_TCP_CONNECTED) {
637 HttpInstance->CloseToken.AbortOnClose = TRUE;
638 HttpInstance->IsCloseDone = FALSE;
639
640 Status = HttpInstance->Tcp4->Close (HttpInstance->Tcp4, &HttpInstance->CloseToken);
641 if (EFI_ERROR (Status)) {
642 return Status;
643 }
644
645 while (!HttpInstance->IsCloseDone) {
646 HttpInstance->Tcp4->Poll (HttpInstance->Tcp4);
647 }
648 }
649
650 HttpInstance->State = HTTP_STATE_TCP_CLOSED;
651 return EFI_SUCCESS;
652 }
653
654 /**
655 Configure TCP4 protocol child.
656
657 @param[in] HttpInstance The HTTP instance private data.
658 @param[in] Wrap The HTTP token's wrap data.
659
660 @retval EFI_SUCCESS The TCP4 protocol child is configured.
661 @retval Others Other error as indicated.
662
663 **/
664 EFI_STATUS
665 HttpConfigureTcp4 (
666 IN HTTP_PROTOCOL *HttpInstance,
667 IN HTTP_TOKEN_WRAP *Wrap
668 )
669 {
670 EFI_STATUS Status;
671 EFI_TCP4_CONFIG_DATA *Tcp4CfgData;
672 EFI_TCP4_ACCESS_POINT *Tcp4AP;
673 EFI_TCP4_OPTION *Tcp4Option;
674 HTTP_TCP_TOKEN_WRAP *TcpWrap;
675
676 ASSERT (HttpInstance != NULL);
677 TcpWrap = &Wrap->TcpWrap;
678
679
680 Tcp4CfgData = &HttpInstance->Tcp4CfgData;
681 ZeroMem (Tcp4CfgData, sizeof (EFI_TCP4_CONFIG_DATA));
682
683 Tcp4CfgData->TypeOfService = HTTP_TOS_DEAULT;
684 Tcp4CfgData->TimeToLive = HTTP_TTL_DEAULT;
685 Tcp4CfgData->ControlOption = &HttpInstance->Tcp4Option;
686
687 Tcp4AP = &Tcp4CfgData->AccessPoint;
688 Tcp4AP->UseDefaultAddress = HttpInstance->IPv4Node.UseDefaultAddress;
689 if (!Tcp4AP->UseDefaultAddress) {
690 IP4_COPY_ADDRESS (&Tcp4AP->StationAddress, &HttpInstance->IPv4Node.LocalAddress);
691 IP4_COPY_ADDRESS (&Tcp4AP->SubnetMask, &HttpInstance->IPv4Node.LocalSubnet);
692 }
693
694 Tcp4AP->StationPort = HttpInstance->IPv4Node.LocalPort;
695 Tcp4AP->RemotePort = HttpInstance->RemotePort;
696 Tcp4AP->ActiveFlag = TRUE;
697 IP4_COPY_ADDRESS (&Tcp4AP->RemoteAddress, &HttpInstance->RemoteAddr);
698
699 Tcp4Option = Tcp4CfgData->ControlOption;
700 Tcp4Option->ReceiveBufferSize = HTTP_BUFFER_SIZE_DEAULT;
701 Tcp4Option->SendBufferSize = HTTP_BUFFER_SIZE_DEAULT;
702 Tcp4Option->MaxSynBackLog = HTTP_MAX_SYN_BACK_LOG;
703 Tcp4Option->ConnectionTimeout = HTTP_CONNECTION_TIMEOUT;
704 Tcp4Option->DataRetries = HTTP_DATA_RETRIES;
705 Tcp4Option->FinTimeout = HTTP_FIN_TIMEOUT;
706 Tcp4Option->KeepAliveProbes = HTTP_KEEP_ALIVE_PROBES;
707 Tcp4Option->KeepAliveTime = HTTP_KEEP_ALIVE_TIME;
708 Tcp4Option->KeepAliveInterval = HTTP_KEEP_ALIVE_INTERVAL;
709 Tcp4Option->EnableNagle = TRUE;
710 Tcp4CfgData->ControlOption = Tcp4Option;
711
712 Status = HttpInstance->Tcp4->Configure (HttpInstance->Tcp4, Tcp4CfgData);
713 if (EFI_ERROR (Status)) {
714 DEBUG ((EFI_D_ERROR, "HttpConfigureTcp4 - %r\n", Status));
715 return Status;
716 }
717
718 Status = HttpCreateTcp4ConnCloseEvent (HttpInstance);
719 if (EFI_ERROR (Status)) {
720 return Status;
721 }
722
723 Status = HttpCreateTcp4TxEvent (Wrap);
724 if (EFI_ERROR (Status)) {
725 return Status;
726 }
727
728 HttpInstance->State = HTTP_STATE_TCP_CONFIGED;
729
730 return EFI_SUCCESS;
731 }
732
733 /**
734 Check existing TCP connection, if in error state, receover TCP4 connection.
735
736 @param[in] HttpInstance The HTTP instance private data.
737
738 @retval EFI_SUCCESS The TCP connection is established.
739 @retval EFI_NOT_READY TCP4 protocol child is not created or configured.
740 @retval Others Other error as indicated.
741
742 **/
743 EFI_STATUS
744 HttpConnectTcp4 (
745 IN HTTP_PROTOCOL *HttpInstance
746 )
747 {
748 EFI_STATUS Status;
749 EFI_TCP4_CONNECTION_STATE Tcp4State;
750
751
752 if (HttpInstance->State != HTTP_STATE_TCP_CONFIGED || HttpInstance->Tcp4 == NULL) {
753 return EFI_NOT_READY;
754 }
755
756 Status = HttpInstance->Tcp4->GetModeData(
757 HttpInstance->Tcp4,
758 &Tcp4State,
759 NULL,
760 NULL,
761 NULL,
762 NULL
763 );
764 if (EFI_ERROR(Status)){
765 DEBUG ((EFI_D_ERROR, "Tcp4 GetModeData fail - %x\n", Status));
766 return Status;
767 }
768
769 if (Tcp4State > Tcp4StateEstablished) {
770 HttpCloseConnection(HttpInstance);
771 }
772
773 return HttpCreateConnection (HttpInstance);
774 }
775
776 /**
777 Send the HTTP message through TCP4.
778
779 @param[in] HttpInstance The HTTP instance private data.
780 @param[in] Wrap The HTTP token's wrap data.
781 @param[in] TxString Buffer containing the HTTP message string.
782 @param[in] TxStringLen Length of the HTTP message string in bytes.
783
784 @retval EFI_SUCCESS The HTTP message is queued into TCP transmit queue.
785 @retval Others Other error as indicated.
786
787 **/
788 EFI_STATUS
789 HttpTransmitTcp4 (
790 IN HTTP_PROTOCOL *HttpInstance,
791 IN HTTP_TOKEN_WRAP *Wrap,
792 IN UINT8 *TxString,
793 IN UINTN TxStringLen
794 )
795 {
796 EFI_STATUS Status;
797 EFI_TCP4_IO_TOKEN *TxToken;
798 EFI_TCP4_PROTOCOL *Tcp4;
799
800 Tcp4 = HttpInstance->Tcp4;
801 TxToken = &Wrap->TcpWrap.TxToken;
802
803 TxToken->Packet.TxData->DataLength = (UINT32) TxStringLen;
804 TxToken->Packet.TxData->FragmentTable[0].FragmentLength = (UINT32) TxStringLen;
805 TxToken->Packet.TxData->FragmentTable[0].FragmentBuffer = (VOID *) TxString;
806 TxToken->CompletionToken.Status = EFI_NOT_READY;
807
808 Wrap->TcpWrap.IsTxDone = FALSE;
809 Status = Tcp4->Transmit (Tcp4, TxToken);
810 if (EFI_ERROR (Status)) {
811 DEBUG ((EFI_D_ERROR, "Transmit failed: %r\n", Status));
812 return Status;
813 }
814
815 return Status;
816 }
817
818 /**
819 Translate the status code in HTTP message to EFI_HTTP_STATUS_CODE defined
820 in UEFI 2.5 specification.
821
822 @param[in] StatusCode The status code value in HTTP message.
823
824 @return Value defined in EFI_HTTP_STATUS_CODE .
825
826 **/
827 EFI_HTTP_STATUS_CODE
828 HttpMappingToStatusCode (
829 IN UINTN StatusCode
830 )
831 {
832 switch (StatusCode) {
833 case 100:
834 return HTTP_STATUS_100_CONTINUE;
835 case 101:
836 return HTTP_STATUS_101_SWITCHING_PROTOCOLS;
837 case 200:
838 return HTTP_STATUS_200_OK;
839 case 201:
840 return HTTP_STATUS_201_CREATED;
841 case 202:
842 return HTTP_STATUS_202_ACCEPTED;
843 case 203:
844 return HTTP_STATUS_203_NON_AUTHORITATIVE_INFORMATION;
845 case 204:
846 return HTTP_STATUS_204_NO_CONTENT;
847 case 205:
848 return HTTP_STATUS_205_RESET_CONTENT;
849 case 206:
850 return HTTP_STATUS_206_PARTIAL_CONTENT;
851 case 300:
852 return HTTP_STATUS_300_MULTIPLE_CHIOCES;
853 case 301:
854 return HTTP_STATUS_301_MOVED_PERMANENTLY;
855 case 302:
856 return HTTP_STATUS_302_FOUND;
857 case 303:
858 return HTTP_STATUS_303_SEE_OTHER;
859 case 304:
860 return HTTP_STATUS_304_NOT_MODIFIED;
861 case 305:
862 return HTTP_STATUS_305_USE_PROXY;
863 case 307:
864 return HTTP_STATUS_307_TEMPORARY_REDIRECT;
865 case 400:
866 return HTTP_STATUS_400_BAD_REQUEST;
867 case 401:
868 return HTTP_STATUS_401_UNAUTHORIZED;
869 case 402:
870 return HTTP_STATUS_402_PAYMENT_REQUIRED;
871 case 403:
872 return HTTP_STATUS_403_FORBIDDEN;
873 case 404:
874 return HTTP_STATUS_404_NOT_FOUND;
875 case 405:
876 return HTTP_STATUS_405_METHOD_NOT_ALLOWED;
877 case 406:
878 return HTTP_STATUS_406_NOT_ACCEPTABLE;
879 case 407:
880 return HTTP_STATUS_407_PROXY_AUTHENTICATION_REQUIRED;
881 case 408:
882 return HTTP_STATUS_408_REQUEST_TIME_OUT;
883 case 409:
884 return HTTP_STATUS_409_CONFLICT;
885 case 410:
886 return HTTP_STATUS_410_GONE;
887 case 411:
888 return HTTP_STATUS_411_LENGTH_REQUIRED;
889 case 412:
890 return HTTP_STATUS_412_PRECONDITION_FAILED;
891 case 413:
892 return HTTP_STATUS_413_REQUEST_ENTITY_TOO_LARGE;
893 case 414:
894 return HTTP_STATUS_414_REQUEST_URI_TOO_LARGE;
895 case 415:
896 return HTTP_STATUS_415_UNSUPPORETD_MEDIA_TYPE;
897 case 416:
898 return HTTP_STATUS_416_REQUESTED_RANGE_NOT_SATISFIED;
899 case 417:
900 return HTTP_STATUS_417_EXPECTATION_FAILED;
901 case 500:
902 return HTTP_STATUS_500_INTERNAL_SERVER_ERROR;
903 case 501:
904 return HTTP_STATUS_501_NOT_IMIPLEMENTED;
905 case 502:
906 return HTTP_STATUS_502_BAD_GATEWAY;
907 case 503:
908 return HTTP_STATUS_503_SERVICE_UNAVAILABLE;
909 case 504:
910 return HTTP_STATUS_504_GATEWAY_TIME_OUT;
911 case 505:
912 return HTTP_STATUS_505_HTTP_VERSION_NOT_SUPPORTED;
913
914 default:
915 return HTTP_STATUS_UNSUPPORTED_STATUS;
916 }
917 }
918
919 /**
920 Check whether the user's token or event has already
921 been enqueue on HTTP TxToken or RxToken list.
922
923 @param[in] Map The container of either user's transmit or receive
924 token.
925 @param[in] Item Current item to check against.
926 @param[in] Context The Token to check againist.
927
928 @retval EFI_ACCESS_DENIED The token or event has already been enqueued in IP
929 @retval EFI_SUCCESS The current item isn't the same token/event as the
930 context.
931
932 **/
933 EFI_STATUS
934 EFIAPI
935 HttpTokenExist (
936 IN NET_MAP *Map,
937 IN NET_MAP_ITEM *Item,
938 IN VOID *Context
939 )
940 {
941 EFI_HTTP_TOKEN *Token;
942 EFI_HTTP_TOKEN *TokenInItem;
943
944 Token = (EFI_HTTP_TOKEN *) Context;
945 TokenInItem = (EFI_HTTP_TOKEN *) Item->Key;
946
947 if (Token == TokenInItem || Token->Event == TokenInItem->Event) {
948 return EFI_ACCESS_DENIED;
949 }
950
951 return EFI_SUCCESS;
952 }
953
954 /**
955 Check whether the HTTP message associated with TxToken is already sent out.
956
957 @param[in] Map The container of TxToken.
958 @param[in] Item Current item to check against.
959 @param[in] Context The Token to check againist.
960
961 @retval EFI_NOT_READY The HTTP message is still queued in the list.
962 @retval EFI_SUCCESS The HTTP message has been sent out.
963
964 **/
965 EFI_STATUS
966 EFIAPI
967 HttpTcpNotReady (
968 IN NET_MAP *Map,
969 IN NET_MAP_ITEM *Item,
970 IN VOID *Context
971 )
972 {
973 HTTP_TOKEN_WRAP *ValueInItem;
974
975 ValueInItem = (HTTP_TOKEN_WRAP *) Item->Value;
976
977 if (!ValueInItem->TcpWrap.IsTxDone) {
978 return EFI_NOT_READY;
979 }
980
981 return EFI_SUCCESS;
982 }
983
984 /**
985 Transmit the HTTP mssage by processing the associated HTTP token.
986
987 @param[in] Map The container of TxToken.
988 @param[in] Item Current item to check against.
989 @param[in] Context The Token to check againist.
990
991 @retval EFI_OUT_OF_RESOURCES Failed to allocate resources.
992 @retval EFI_SUCCESS The HTTP message is queued into TCP transmit
993 queue.
994
995 **/
996 EFI_STATUS
997 EFIAPI
998 HttpTcpTransmit (
999 IN NET_MAP *Map,
1000 IN NET_MAP_ITEM *Item,
1001 IN VOID *Context
1002 )
1003 {
1004 HTTP_TOKEN_WRAP *ValueInItem;
1005 EFI_STATUS Status;
1006 CHAR8 *RequestStr;
1007 CHAR8 *Url;
1008
1009 ValueInItem = (HTTP_TOKEN_WRAP *) Item->Value;
1010 if (ValueInItem->TcpWrap.IsTxDone) {
1011 return EFI_SUCCESS;
1012 }
1013
1014 //
1015 // Parse the URI of the remote host.
1016 //
1017 Url = AllocatePool (StrLen (ValueInItem->HttpToken->Message->Data.Request->Url) + 1);
1018 if (Url == NULL) {
1019 return EFI_OUT_OF_RESOURCES;
1020 }
1021
1022 UnicodeStrToAsciiStr (ValueInItem->HttpToken->Message->Data.Request->Url, Url);
1023
1024 //
1025 // Create request message.
1026 //
1027 RequestStr = HttpGenRequestString (
1028 ValueInItem->HttpInstance,
1029 ValueInItem->HttpToken->Message,
1030 Url
1031 );
1032 FreePool (Url);
1033 if (RequestStr == NULL) {
1034 return EFI_OUT_OF_RESOURCES;
1035 }
1036
1037 //
1038 // Transmit the request message.
1039 //
1040 Status = HttpTransmitTcp4 (
1041 ValueInItem->HttpInstance,
1042 ValueInItem,
1043 (UINT8*) RequestStr,
1044 AsciiStrLen (RequestStr)
1045 );
1046 FreePool (RequestStr);
1047 return Status;
1048 }
1049
1050 /**
1051 Receive the HTTP response by processing the associated HTTP token.
1052
1053 @param[in] Map The container of RxToken.
1054 @param[in] Item Current item to check against.
1055 @param[in] Context The Token to check againist.
1056
1057 @retval EFI_SUCCESS The HTTP response is queued into TCP receive
1058 queue.
1059 @retval Others Other error as indicated.
1060
1061 **/
1062 EFI_STATUS
1063 EFIAPI
1064 HttpTcpReceive (
1065 IN NET_MAP *Map,
1066 IN NET_MAP_ITEM *Item,
1067 IN VOID *Context
1068 )
1069 {
1070 //
1071 // Process the queued HTTP response.
1072 //
1073 return HttpResponseWorker ((HTTP_TOKEN_WRAP *) Item->Value);
1074 }
1075
1076 /**
1077 Generate HTTP request string.
1078
1079 @param[in] HttpInstance Pointer to HTTP_PROTOCOL structure.
1080 @param[in] Message Pointer to storage containing HTTP message data.
1081 @param[in] Url The URL of a remote host.
1082
1083 @return Pointer to the created HTTP request string.
1084 @return NULL if any error occured.
1085
1086 **/
1087 CHAR8 *
1088 HttpGenRequestString (
1089 IN HTTP_PROTOCOL *HttpInstance,
1090 IN EFI_HTTP_MESSAGE *Message,
1091 IN CHAR8 *Url
1092 )
1093 {
1094 EFI_STATUS Status;
1095 UINTN StrLength;
1096 UINT8 *Request;
1097 UINT8 *RequestPtr;
1098 UINTN HttpHdrSize;
1099 UINTN MsgSize;
1100 BOOLEAN Success;
1101 VOID *HttpHdr;
1102 EFI_HTTP_HEADER **AppendList;
1103 UINTN Index;
1104
1105 ASSERT (HttpInstance != NULL);
1106 ASSERT (Message != NULL);
1107
1108 DEBUG ((EFI_D_ERROR, "HttpMethod - %x\n", Message->Data.Request->Method));
1109
1110 Request = NULL;
1111 Success = FALSE;
1112 HttpHdr = NULL;
1113 AppendList = NULL;
1114
1115 //
1116 // Build AppendList
1117 //
1118 AppendList = AllocateZeroPool (sizeof (EFI_HTTP_HEADER *) * (Message->HeaderCount));
1119 if (AppendList == NULL) {
1120 return NULL;
1121 }
1122
1123 for(Index = 0; Index < Message->HeaderCount; Index++){
1124 AppendList[Index] = &Message->Headers[Index];
1125 }
1126
1127 //
1128 // Check whether the EFI_HTTP_UTILITIES_PROTOCOL is available.
1129 //
1130 if (mHttpUtilities == NULL) {
1131 return NULL;
1132 }
1133
1134 //
1135 // Build raw unformatted HTTP headers.
1136 //
1137 Status = mHttpUtilities->Build (
1138 mHttpUtilities,
1139 0,
1140 NULL,
1141 0,
1142 NULL,
1143 Message->HeaderCount,
1144 AppendList,
1145 &HttpHdrSize,
1146 &HttpHdr
1147 );
1148 FreePool (AppendList);
1149 if (EFI_ERROR (Status) || HttpHdr == NULL) {
1150 return NULL;
1151 }
1152
1153 //
1154 // Calculate HTTP message length.
1155 //
1156 MsgSize = Message->BodyLength + HTTP_MAXIMUM_METHOD_LEN + AsciiStrLen (Url) +
1157 AsciiStrLen (HTTP_VERSION_CRLF_STR) + HttpHdrSize;
1158 Request = AllocateZeroPool (MsgSize);
1159 if (Request == NULL) {
1160 goto Exit;
1161 }
1162
1163 RequestPtr = Request;
1164 //
1165 // Construct header request
1166 //
1167 switch (Message->Data.Request->Method) {
1168 case HttpMethodGet:
1169 StrLength = sizeof (HTTP_GET_STR) - 1;
1170 CopyMem (RequestPtr, HTTP_GET_STR, StrLength);
1171 RequestPtr += StrLength;
1172 break;
1173 case HttpMethodHead:
1174 StrLength = sizeof (HTTP_HEAD_STR) - 1;
1175 CopyMem (RequestPtr, HTTP_HEAD_STR, StrLength);
1176 RequestPtr += StrLength;
1177 break;
1178 default:
1179 ASSERT (FALSE);
1180 goto Exit;
1181 }
1182
1183 StrLength = AsciiStrLen (Url);
1184 CopyMem (RequestPtr, Url, StrLength);
1185 RequestPtr += StrLength;
1186
1187 StrLength = sizeof (HTTP_VERSION_CRLF_STR) - 1;
1188 CopyMem (RequestPtr, HTTP_VERSION_CRLF_STR, StrLength);
1189 RequestPtr += StrLength;
1190
1191 //
1192 // Construct header
1193 //
1194 CopyMem (RequestPtr, HttpHdr, HttpHdrSize);
1195 RequestPtr += HttpHdrSize;
1196
1197 //
1198 // Construct body
1199 //
1200 if (Message->Body != NULL) {
1201 CopyMem (RequestPtr, Message->Body, Message->BodyLength);
1202 RequestPtr += Message->BodyLength;
1203 }
1204
1205 //
1206 // Done
1207 //
1208 *RequestPtr = 0;
1209 Success = TRUE;
1210
1211 Exit:
1212
1213 if (!Success) {
1214 if (Request != NULL) {
1215 FreePool (Request);
1216 }
1217
1218 Request = NULL;
1219 }
1220
1221 if (HttpHdr != NULL) {
1222 FreePool (HttpHdr);
1223 }
1224
1225 return (CHAR8*) Request;
1226 }