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