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