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