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