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