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