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