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