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