]> git.proxmox.com Git - mirror_edk2.git/blame - NetworkPkg/HttpDxe/HttpImpl.c
NetworkPkg:Enable Http Boot over Ipv6 stack
[mirror_edk2.git] / NetworkPkg / HttpDxe / HttpImpl.c
CommitLineData
47f51a06
YT
1/** @file\r
2 Implementation of EFI_HTTP_PROTOCOL protocol interfaces.\r
3\r
4 Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>\r
c5a693ce 5 (C) Copyright 2015 Hewlett Packard Enterprise Development LP<BR>\r
47f51a06
YT
6\r
7 This program and the accompanying materials\r
8 are licensed and made available under the terms and conditions of the BSD License\r
9 which accompanies this distribution. The full text of the license may be found at\r
10 http://opensource.org/licenses/bsd-license.php.\r
11\r
12 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
13 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
14\r
15**/\r
16\r
17#include "HttpDriver.h"\r
18\r
19EFI_HTTP_PROTOCOL mEfiHttpTemplate = {\r
20 EfiHttpGetModeData,\r
21 EfiHttpConfigure,\r
22 EfiHttpRequest,\r
23 EfiHttpCancel,\r
24 EfiHttpResponse,\r
25 EfiHttpPoll\r
26};\r
27\r
28/**\r
29 Returns the operational parameters for the current HTTP child instance.\r
30\r
31 The GetModeData() function is used to read the current mode data (operational\r
32 parameters) for this HTTP protocol instance.\r
33\r
34 @param[in] This Pointer to EFI_HTTP_PROTOCOL instance.\r
35 @param[out] HttpConfigData Point to buffer for operational parameters of this\r
36 HTTP instance.\r
37\r
38 @retval EFI_SUCCESS Operation succeeded.\r
39 @retval EFI_INVALID_PARAMETER One or more of the following conditions is TRUE:\r
40 This is NULL.\r
41 HttpConfigData is NULL.\r
42 HttpConfigData->AccessPoint is NULL.\r
43 @retval EFI_NOT_STARTED The HTTP instance is not configured.\r
44\r
45**/\r
46EFI_STATUS\r
47EFIAPI\r
48EfiHttpGetModeData (\r
49 IN EFI_HTTP_PROTOCOL *This,\r
50 OUT EFI_HTTP_CONFIG_DATA *HttpConfigData\r
51 )\r
52{\r
53 HTTP_PROTOCOL *HttpInstance;\r
b659408b
ZL
54 EFI_HTTPv4_ACCESS_POINT *Http4AccessPoint;\r
55 EFI_HTTPv6_ACCESS_POINT *Http6AccessPoint;\r
47f51a06
YT
56\r
57 if ((This == NULL) || (HttpConfigData == NULL)) {\r
58 return EFI_INVALID_PARAMETER;\r
59 }\r
60 \r
61 HttpInstance = HTTP_INSTANCE_FROM_PROTOCOL (This);\r
62 ASSERT (HttpInstance != NULL);\r
b659408b 63 \r
47f51a06
YT
64 if (HttpInstance->State < HTTP_STATE_HTTP_CONFIGED) {\r
65 return EFI_NOT_STARTED;\r
66 }\r
67\r
47f51a06
YT
68 HttpConfigData->HttpVersion = HttpInstance->HttpVersion;\r
69 HttpConfigData->TimeOutMillisec = HttpInstance->TimeOutMillisec;\r
70 HttpConfigData->LocalAddressIsIPv6 = HttpInstance->LocalAddressIsIPv6;\r
71\r
b659408b
ZL
72 if (HttpInstance->LocalAddressIsIPv6) {\r
73 Http6AccessPoint = AllocateZeroPool (sizeof (EFI_HTTPv6_ACCESS_POINT));\r
74 CopyMem (\r
75 Http6AccessPoint,\r
76 &HttpInstance->Ipv6Node,\r
77 sizeof (HttpInstance->Ipv6Node)\r
47f51a06 78 );\r
b659408b
ZL
79 HttpConfigData->AccessPoint.IPv6Node = Http6AccessPoint;\r
80 } else {\r
81 Http4AccessPoint = AllocateZeroPool (sizeof (EFI_HTTPv4_ACCESS_POINT));\r
82 CopyMem (\r
83 Http4AccessPoint,\r
84 &HttpInstance->IPv4Node,\r
85 sizeof (HttpInstance->IPv4Node)\r
86 );\r
87 HttpConfigData->AccessPoint.IPv4Node = Http4AccessPoint;\r
88 }\r
47f51a06
YT
89\r
90 return EFI_SUCCESS;\r
91}\r
92\r
93/**\r
94 Initialize or brutally reset the operational parameters for this EFI HTTP instance.\r
95\r
96 The Configure() function does the following:\r
97 When HttpConfigData is not NULL Initialize this EFI HTTP instance by configuring\r
98 timeout, local address, port, etc.\r
99 When HttpConfigData is NULL, reset this EFI HTTP instance by closing all active\r
100 connections with remote hosts, canceling all asynchronous tokens, and flush request\r
101 and response buffers without informing the appropriate hosts.\r
102\r
103 Except for GetModeData() and Configure(), No other EFI HTTP function can be executed\r
104 by this instance until the Configure() function is executed and returns successfully.\r
105\r
106 @param[in] This Pointer to EFI_HTTP_PROTOCOL instance.\r
107 @param[in] HttpConfigData Pointer to the configure data to configure the instance.\r
108\r
109 @retval EFI_SUCCESS Operation succeeded.\r
110 @retval EFI_INVALID_PARAMETER One or more of the following conditions is TRUE:\r
111 This is NULL.\r
112 HttpConfigData->LocalAddressIsIPv6 is FALSE and\r
113 HttpConfigData->IPv4Node is NULL.\r
114 HttpConfigData->LocalAddressIsIPv6 is TRUE and\r
115 HttpConfigData->IPv6Node is NULL.\r
116 @retval EFI_ALREADY_STARTED Reinitialize this HTTP instance without calling\r
117 Configure() with NULL to reset it.\r
118 @retval EFI_DEVICE_ERROR An unexpected system or network error occurred.\r
119 @retval EFI_OUT_OF_RESOURCES Could not allocate enough system resources when\r
120 executing Configure().\r
121 @retval EFI_UNSUPPORTED One or more options in HttpConfigData are not supported\r
122 in the implementation.\r
123**/\r
124EFI_STATUS\r
125EFIAPI\r
126EfiHttpConfigure (\r
127 IN EFI_HTTP_PROTOCOL *This,\r
128 IN EFI_HTTP_CONFIG_DATA *HttpConfigData\r
129 ) \r
130{\r
131 HTTP_PROTOCOL *HttpInstance;\r
132 EFI_STATUS Status;\r
b659408b
ZL
133 \r
134 //\r
135 // Check input parameters.\r
136 //\r
137 if (This == NULL || \r
138 (HttpConfigData != NULL && ((HttpConfigData->LocalAddressIsIPv6 && HttpConfigData->AccessPoint.IPv6Node == NULL) ||\r
139 (!HttpConfigData->LocalAddressIsIPv6 && HttpConfigData->AccessPoint.IPv4Node == NULL)))) {\r
47f51a06
YT
140 return EFI_INVALID_PARAMETER;\r
141 }\r
142\r
143 HttpInstance = HTTP_INSTANCE_FROM_PROTOCOL (This);\r
144 ASSERT (HttpInstance != NULL && HttpInstance->Service != NULL);\r
145\r
146 if (HttpConfigData != NULL) {\r
b659408b 147\r
47f51a06
YT
148 //\r
149 // Now configure this HTTP instance.\r
150 //\r
151 if (HttpInstance->State != HTTP_STATE_UNCONFIGED) {\r
152 return EFI_ALREADY_STARTED;\r
153 }\r
154\r
155 HttpInstance->HttpVersion = HttpConfigData->HttpVersion;\r
156 HttpInstance->TimeOutMillisec = HttpConfigData->TimeOutMillisec;\r
157 HttpInstance->LocalAddressIsIPv6 = HttpConfigData->LocalAddressIsIPv6;\r
b659408b
ZL
158 \r
159 if (HttpConfigData->LocalAddressIsIPv6) { \r
160 CopyMem (\r
161 &HttpInstance->Ipv6Node,\r
162 HttpConfigData->AccessPoint.IPv6Node,\r
163 sizeof (HttpInstance->Ipv6Node)\r
164 );\r
47f51a06
YT
165 } else {\r
166 CopyMem (\r
167 &HttpInstance->IPv4Node,\r
168 HttpConfigData->AccessPoint.IPv4Node,\r
169 sizeof (HttpInstance->IPv4Node)\r
170 );\r
47f51a06 171 }\r
b659408b
ZL
172 //\r
173 // Creat Tcp child\r
174 //\r
175 Status = HttpInitProtocol (HttpInstance, HttpInstance->LocalAddressIsIPv6);\r
176 if (EFI_ERROR (Status)) {\r
177 return Status;\r
178 }\r
179 \r
180 HttpInstance->State = HTTP_STATE_HTTP_CONFIGED;\r
181 return EFI_SUCCESS;\r
47f51a06
YT
182\r
183 } else {\r
b659408b
ZL
184 //\r
185 // Reset all the resources related to HttpInsance.\r
186 //\r
187 HttpCleanProtocol (HttpInstance);\r
188 HttpInstance->State = HTTP_STATE_UNCONFIGED;\r
189 return EFI_SUCCESS;\r
47f51a06
YT
190 }\r
191}\r
192 \r
193\r
194/**\r
195 The Request() function queues an HTTP request to this HTTP instance.\r
196\r
197 Similar to Transmit() function in the EFI TCP driver. When the HTTP request is sent\r
198 successfully, or if there is an error, Status in token will be updated and Event will\r
199 be signaled.\r
200\r
201 @param[in] This Pointer to EFI_HTTP_PROTOCOL instance.\r
202 @param[in] Token Pointer to storage containing HTTP request token.\r
203\r
204 @retval EFI_SUCCESS Outgoing data was processed.\r
205 @retval EFI_NOT_STARTED This EFI HTTP Protocol instance has not been started.\r
206 @retval EFI_DEVICE_ERROR An unexpected system or network error occurred.\r
207 @retval EFI_TIMEOUT Data was dropped out of the transmit or receive queue.\r
208 @retval EFI_OUT_OF_RESOURCES Could not allocate enough system resources.\r
209 @retval EFI_UNSUPPORTED The HTTP method is not supported in current\r
210 implementation.\r
211 @retval EFI_INVALID_PARAMETER One or more of the following conditions is TRUE:\r
212 This is NULL.\r
213 Token->Message is NULL.\r
214 Token->Message->Body is not NULL,\r
215 Token->Message->BodyLength is non-zero, and\r
216 Token->Message->Data is NULL, but a previous call to\r
217 Request()has not been completed successfully.\r
218**/\r
219EFI_STATUS\r
220EFIAPI\r
221EfiHttpRequest (\r
222 IN EFI_HTTP_PROTOCOL *This,\r
223 IN EFI_HTTP_TOKEN *Token\r
224 )\r
225{\r
226 EFI_HTTP_MESSAGE *HttpMsg;\r
227 EFI_HTTP_REQUEST_DATA *Request;\r
228 VOID *UrlParser;\r
229 EFI_STATUS Status;\r
230 CHAR8 *HostName;\r
231 UINT16 RemotePort;\r
232 HTTP_PROTOCOL *HttpInstance;\r
233 BOOLEAN Configure;\r
234 BOOLEAN ReConfigure;\r
235 CHAR8 *RequestStr;\r
236 CHAR8 *Url;\r
51b0450e 237 UINTN UrlLen;\r
47f51a06
YT
238 CHAR16 *HostNameStr;\r
239 HTTP_TOKEN_WRAP *Wrap;\r
b199d941
GCPL
240 CHAR8 *FileUrl;\r
241 \r
47f51a06
YT
242 if ((This == NULL) || (Token == NULL)) {\r
243 return EFI_INVALID_PARAMETER;\r
244 }\r
245\r
246 HttpMsg = Token->Message;\r
247 if ((HttpMsg == NULL) || (HttpMsg->Headers == NULL)) {\r
248 return EFI_INVALID_PARAMETER;\r
249 }\r
250\r
251 //\r
252 // Current implementation does not support POST/PUT method.\r
253 // If future version supports these two methods, Request could be NULL for a special case that to send large amounts\r
254 // of data. For this case, the implementation need check whether previous call to Request() has been completed or not.\r
255 // \r
256 //\r
257 Request = HttpMsg->Data.Request;\r
258 if ((Request == NULL) || (Request->Url == NULL)) {\r
259 return EFI_INVALID_PARAMETER;\r
260 }\r
261\r
262 //\r
263 // Only support GET and HEAD method in current implementation.\r
264 //\r
265 if ((Request->Method != HttpMethodGet) && (Request->Method != HttpMethodHead)) {\r
266 return EFI_UNSUPPORTED;\r
267 }\r
268\r
269 HttpInstance = HTTP_INSTANCE_FROM_PROTOCOL (This);\r
270 ASSERT (HttpInstance != NULL);\r
271\r
272 if (HttpInstance->State < HTTP_STATE_HTTP_CONFIGED) {\r
273 return EFI_NOT_STARTED;\r
274 }\r
275\r
47f51a06
YT
276 //\r
277 // Check whether the token already existed.\r
278 //\r
279 if (EFI_ERROR (NetMapIterate (&HttpInstance->TxTokens, HttpTokenExist, Token))) {\r
280 return EFI_ACCESS_DENIED; \r
281 } \r
282\r
47f51a06
YT
283 HostName = NULL;\r
284 Wrap = NULL;\r
285 HostNameStr = NULL;\r
47f51a06
YT
286\r
287 //\r
288 // Parse the URI of the remote host.\r
289 //\r
7ef0690f 290 Url = HttpInstance->Url;\r
51b0450e
FS
291 UrlLen = StrLen (Request->Url) + 1;\r
292 if (UrlLen > HTTP_URL_BUFFER_LEN) {\r
293 Url = AllocateZeroPool (UrlLen);\r
294 if (Url == NULL) {\r
295 return EFI_OUT_OF_RESOURCES;\r
296 }\r
297 FreePool (HttpInstance->Url);\r
298 HttpInstance->Url = Url; \r
b659408b
ZL
299 } \r
300\r
47f51a06
YT
301\r
302 UnicodeStrToAsciiStr (Request->Url, Url);\r
303 UrlParser = NULL;\r
304 Status = HttpParseUrl (Url, (UINT32) AsciiStrLen (Url), FALSE, &UrlParser);\r
305 if (EFI_ERROR (Status)) {\r
306 goto Error1;\r
307 }\r
308\r
309 RequestStr = NULL;\r
310 HostName = NULL;\r
311 Status = HttpUrlGetHostName (Url, UrlParser, &HostName);\r
312 if (EFI_ERROR (Status)) {\r
313 goto Error1;\r
314 }\r
315\r
316 Status = HttpUrlGetPort (Url, UrlParser, &RemotePort);\r
317 if (EFI_ERROR (Status)) {\r
318 RemotePort = HTTP_DEFAULT_PORT;\r
319 }\r
320\r
321 Configure = TRUE;\r
322 ReConfigure = TRUE; \r
323\r
a8706acb 324 if (HttpInstance->RemoteHost == NULL) {\r
47f51a06
YT
325 //\r
326 // Request() is called the first time. \r
327 //\r
328 ReConfigure = FALSE;\r
329 } else {\r
330 if ((HttpInstance->RemotePort == RemotePort) &&\r
331 (AsciiStrCmp (HttpInstance->RemoteHost, HostName) == 0)) {\r
332 //\r
333 // Host Name and port number of the request URL are the same with previous call to Request().\r
334 // Check whether previous TCP packet sent out.\r
335 //\r
336 if (EFI_ERROR (NetMapIterate (&HttpInstance->TxTokens, HttpTcpNotReady, NULL))) {\r
337 //\r
338 // Wrap the HTTP token in HTTP_TOKEN_WRAP\r
339 //\r
340 Wrap = AllocateZeroPool (sizeof (HTTP_TOKEN_WRAP));\r
341 if (Wrap == NULL) {\r
342 Status = EFI_OUT_OF_RESOURCES;\r
343 goto Error1;\r
344 }\r
345\r
346 Wrap->HttpToken = Token;\r
347 Wrap->HttpInstance = HttpInstance;\r
348\r
b659408b 349 Status = HttpCreateTcpTxEvent (Wrap);\r
47f51a06
YT
350 if (EFI_ERROR (Status)) {\r
351 goto Error1;\r
352 }\r
353\r
354 Status = NetMapInsertTail (&HttpInstance->TxTokens, Token, Wrap);\r
355 if (EFI_ERROR (Status)) {\r
356 goto Error1;\r
357 }\r
358\r
359 Wrap->TcpWrap.Method = Request->Method;\r
360\r
47f51a06
YT
361 FreePool (HostName);\r
362 \r
363 //\r
364 // Queue the HTTP token and return.\r
365 //\r
366 return EFI_SUCCESS;\r
367 } else {\r
368 //\r
369 // Use existing TCP instance to transmit the packet.\r
370 //\r
371 Configure = FALSE;\r
372 ReConfigure = FALSE;\r
373 }\r
374 } else {\r
375 //\r
376 // Need close existing TCP instance and create a new TCP instance for data transmit.\r
377 //\r
378 if (HttpInstance->RemoteHost != NULL) {\r
379 FreePool (HttpInstance->RemoteHost);\r
380 HttpInstance->RemoteHost = NULL;\r
a8706acb 381 HttpInstance->RemotePort = 0;\r
47f51a06
YT
382 }\r
383 }\r
384 } \r
385\r
386 if (Configure) {\r
387 //\r
b659408b 388 // Parse Url for IPv4 or IPv6 address, if failed, perform DNS resolution.\r
47f51a06 389 //\r
b659408b
ZL
390 if (!HttpInstance->LocalAddressIsIPv6) {\r
391 Status = NetLibAsciiStrToIp4 (HostName, &HttpInstance->RemoteAddr);\r
392 } else {\r
393 Status = NetLibAsciiStrToIp6 (HostName, &HttpInstance->RemoteIpv6Addr);\r
394 }\r
395\r
47f51a06 396 if (EFI_ERROR (Status)) {\r
b659408b 397 HostNameStr = AllocateZeroPool ((AsciiStrLen (HostName) + 1) * sizeof (CHAR16));\r
47f51a06
YT
398 if (HostNameStr == NULL) {\r
399 Status = EFI_OUT_OF_RESOURCES;\r
400 goto Error1;\r
401 }\r
b659408b 402 \r
47f51a06 403 AsciiStrToUnicodeStr (HostName, HostNameStr);\r
b659408b
ZL
404 if (!HttpInstance->LocalAddressIsIPv6) {\r
405 Status = HttpDns4 (HttpInstance, HostNameStr, &HttpInstance->RemoteAddr);\r
406 } else {\r
407 Status = HttpDns6 (HttpInstance, HostNameStr, &HttpInstance->RemoteIpv6Addr);\r
408 }\r
409 \r
47f51a06
YT
410 FreePool (HostNameStr);\r
411 if (EFI_ERROR (Status)) {\r
412 goto Error1;\r
413 }\r
414 }\r
415\r
b659408b 416\r
47f51a06
YT
417 //\r
418 // Save the RemotePort and RemoteHost.\r
419 //\r
420 ASSERT (HttpInstance->RemoteHost == NULL);\r
421 HttpInstance->RemotePort = RemotePort;\r
422 HttpInstance->RemoteHost = HostName;\r
423 HostName = NULL;\r
424 }\r
425\r
426 if (ReConfigure) {\r
427 //\r
428 // The request URL is different from previous calls to Request(), close existing TCP instance.\r
429 //\r
b659408b 430 ASSERT (HttpInstance->Tcp4 != NULL &&HttpInstance->Tcp6 != NULL);\r
47f51a06
YT
431 HttpCloseConnection (HttpInstance);\r
432 EfiHttpCancel (This, NULL);\r
433 }\r
434\r
435 //\r
436 // Wrap the HTTP token in HTTP_TOKEN_WRAP\r
437 //\r
438 Wrap = AllocateZeroPool (sizeof (HTTP_TOKEN_WRAP));\r
439 if (Wrap == NULL) {\r
440 Status = EFI_OUT_OF_RESOURCES;\r
441 goto Error1;\r
442 }\r
443\r
444 Wrap->HttpToken = Token;\r
445 Wrap->HttpInstance = HttpInstance;\r
446 Wrap->TcpWrap.Method = Request->Method;\r
447\r
448 if (Configure) {\r
b659408b 449 Status = HttpInitTcp (HttpInstance, Wrap);\r
47f51a06
YT
450 if (EFI_ERROR (Status)) {\r
451 goto Error2;\r
452 }\r
b659408b 453\r
47f51a06
YT
454 } else {\r
455 //\r
456 // For the new HTTP token, create TX TCP token events. \r
457 //\r
b659408b 458 Status = HttpCreateTcpTxEvent (Wrap);\r
47f51a06
YT
459 if (EFI_ERROR (Status)) {\r
460 goto Error1;\r
461 }\r
462 }\r
463\r
464 //\r
465 // Create request message.\r
466 //\r
b199d941
GCPL
467 FileUrl = Url;\r
468 if (*FileUrl != '/') {\r
469 //\r
470 // Convert the absolute-URI to the absolute-path\r
471 //\r
472 while (*FileUrl != ':') {\r
473 FileUrl++;\r
474 }\r
475 if ((*(FileUrl+1) == '/') && (*(FileUrl+2) == '/')) {\r
476 FileUrl += 3;\r
477 while (*FileUrl != '/') {\r
478 FileUrl++;\r
479 }\r
480 } else {\r
481 Status = EFI_INVALID_PARAMETER;\r
482 goto Error3;\r
483 }\r
484 }\r
485 RequestStr = HttpGenRequestString (HttpInstance, HttpMsg, FileUrl);\r
47f51a06
YT
486 if (RequestStr == NULL) {\r
487 Status = EFI_OUT_OF_RESOURCES;\r
488 goto Error3;\r
489 }\r
490\r
491 Status = NetMapInsertTail (&HttpInstance->TxTokens, Token, Wrap);\r
492 if (EFI_ERROR (Status)) {\r
493 goto Error4;\r
494 }\r
495\r
47f51a06
YT
496 //\r
497 // Transmit the request message.\r
498 //\r
b659408b 499 Status = HttpTransmitTcp (\r
47f51a06
YT
500 HttpInstance,\r
501 Wrap,\r
502 (UINT8*) RequestStr,\r
503 AsciiStrLen (RequestStr)\r
504 );\r
505 if (EFI_ERROR (Status)) {\r
506 goto Error5; \r
507 }\r
508\r
49c9f74c 509 DispatchDpc ();\r
b659408b 510 \r
cdf8c32e
NH
511 if (HostName != NULL) {\r
512 FreePool (HostName);\r
513 }\r
b659408b 514 \r
47f51a06
YT
515 return EFI_SUCCESS;\r
516\r
517Error5:\r
518 NetMapRemoveTail (&HttpInstance->TxTokens, NULL);\r
519\r
520Error4:\r
521 if (RequestStr != NULL) {\r
522 FreePool (RequestStr);\r
523 } \r
524\r
525Error3:\r
526 HttpCloseConnection (HttpInstance);\r
527\r
47f51a06 528Error2:\r
b659408b
ZL
529 HttpCloseTcpConnCloseEvent (HttpInstance);\r
530 if (NULL != Wrap->TcpWrap.Tx4Token.CompletionToken.Event) {\r
531 gBS->CloseEvent (Wrap->TcpWrap.Tx4Token.CompletionToken.Event);\r
532 Wrap->TcpWrap.Tx4Token.CompletionToken.Event = NULL;\r
533 }\r
534 if (NULL != Wrap->TcpWrap.Tx6Token.CompletionToken.Event) {\r
535 gBS->CloseEvent (Wrap->TcpWrap.Tx6Token.CompletionToken.Event);\r
536 Wrap->TcpWrap.Tx6Token.CompletionToken.Event = NULL;\r
47f51a06
YT
537 }\r
538\r
539Error1:\r
b659408b 540\r
47f51a06
YT
541 if (HostName != NULL) {\r
542 FreePool (HostName);\r
543 }\r
544 if (Wrap != NULL) {\r
545 FreePool (Wrap);\r
546 }\r
547 if (UrlParser!= NULL) {\r
548 HttpUrlFreeParser (UrlParser);\r
549 }\r
550\r
551 return Status;\r
552 \r
553}\r
554\r
555/**\r
b659408b 556 Cancel a user's Token. \r
47f51a06
YT
557 \r
558 @param[in] Map The HTTP instance's token queue.\r
559 @param[in] Item Object container for one HTTP token and token's wrap.\r
560 @param[in] Context The user's token to cancel.\r
561\r
562 @retval EFI_SUCCESS Continue to check the next Item.\r
563 @retval EFI_ABORTED The user's Token (Token != NULL) is cancelled.\r
564\r
565**/\r
566EFI_STATUS\r
567EFIAPI\r
568HttpCancelTokens (\r
569 IN NET_MAP *Map,\r
570 IN NET_MAP_ITEM *Item,\r
571 IN VOID *Context\r
572 )\r
573{\r
574\r
575 EFI_HTTP_TOKEN *Token;\r
576 HTTP_TOKEN_WRAP *Wrap;\r
b659408b 577 HTTP_PROTOCOL *HttpInstance;\r
47f51a06
YT
578\r
579 Token = (EFI_HTTP_TOKEN *) Context;\r
580\r
581 //\r
582 // Return EFI_SUCCESS to check the next item in the map if\r
583 // this one doesn't match.\r
584 //\r
585 if ((Token != NULL) && (Token != Item->Key)) {\r
586 return EFI_SUCCESS;\r
587 }\r
588\r
589 Wrap = (HTTP_TOKEN_WRAP *) Item->Value;\r
590 ASSERT (Wrap != NULL);\r
b659408b 591 HttpInstance = Wrap->HttpInstance;\r
47f51a06
YT
592\r
593 //\r
594 // Free resources.\r
595 //\r
596 NetMapRemoveItem (Map, Item, NULL); \r
597 \r
b659408b
ZL
598 if (!HttpInstance->LocalAddressIsIPv6) {\r
599 if (Wrap->TcpWrap.Tx4Token.CompletionToken.Event != NULL) {\r
600 gBS->CloseEvent (Wrap->TcpWrap.Tx4Token.CompletionToken.Event);\r
601 }\r
602 \r
603 if (Wrap->TcpWrap.Rx4Token.CompletionToken.Event != NULL) {\r
604 gBS->CloseEvent (Wrap->TcpWrap.Rx4Token.CompletionToken.Event);\r
605 }\r
606 \r
607 if (Wrap->TcpWrap.Rx4Token.Packet.RxData->FragmentTable[0].FragmentBuffer != NULL) {\r
608 FreePool (Wrap->TcpWrap.Rx4Token.Packet.RxData->FragmentTable[0].FragmentBuffer);\r
609 }\r
47f51a06 610\r
b659408b
ZL
611 } else {\r
612 if (Wrap->TcpWrap.Tx6Token.CompletionToken.Event != NULL) {\r
613 gBS->CloseEvent (Wrap->TcpWrap.Tx6Token.CompletionToken.Event);\r
614 }\r
615\r
616 if (Wrap->TcpWrap.Rx6Token.CompletionToken.Event != NULL) {\r
617 gBS->CloseEvent (Wrap->TcpWrap.Rx6Token.CompletionToken.Event);\r
618 }\r
47f51a06 619\r
b659408b
ZL
620 if (Wrap->TcpWrap.Rx6Token.Packet.RxData->FragmentTable[0].FragmentBuffer != NULL) {\r
621 FreePool (Wrap->TcpWrap.Rx6Token.Packet.RxData->FragmentTable[0].FragmentBuffer);\r
622 }\r
47f51a06
YT
623 }\r
624\r
b659408b 625\r
47f51a06
YT
626 FreePool (Wrap);\r
627\r
628 //\r
629 // If only one item is to be cancel, return EFI_ABORTED to stop\r
630 // iterating the map any more.\r
631 //\r
632 if (Token != NULL) {\r
633 return EFI_ABORTED;\r
634 }\r
635\r
636 return EFI_SUCCESS; \r
637}\r
638\r
639/**\r
640 Cancel the user's receive/transmit request. It is the worker function of\r
641 EfiHttpCancel API. If a matching token is found, it will call HttpCancelTokens to cancel the\r
642 token.\r
643\r
644 @param[in] HttpInstance Pointer to HTTP_PROTOCOL structure.\r
645 @param[in] Token The token to cancel. If NULL, all token will be\r
646 cancelled.\r
647\r
648 @retval EFI_SUCCESS The token is cancelled.\r
649 @retval EFI_NOT_FOUND The asynchronous request or response token is not found. \r
650 @retval Others Other error as indicated.\r
651\r
652**/\r
653EFI_STATUS\r
654HttpCancel (\r
655 IN HTTP_PROTOCOL *HttpInstance,\r
656 IN EFI_HTTP_TOKEN *Token\r
657 )\r
658{\r
659 EFI_STATUS Status;\r
660\r
661 //\r
662 // First check the tokens queued by EfiHttpRequest().\r
663 //\r
664 Status = NetMapIterate (&HttpInstance->TxTokens, HttpCancelTokens, Token);\r
665 if (EFI_ERROR (Status)) {\r
666 if (Token != NULL) {\r
667 if (Status == EFI_ABORTED) {\r
668 return EFI_SUCCESS;\r
669 } \r
670 } else {\r
671 return Status;\r
672 }\r
673 }\r
674\r
675 //\r
676 // Then check the tokens queued by EfiHttpResponse().\r
677 //\r
678 Status = NetMapIterate (&HttpInstance->RxTokens, HttpCancelTokens, Token);\r
679 if (EFI_ERROR (Status)) {\r
680 if (Token != NULL) {\r
681 if (Status == EFI_ABORTED) {\r
682 return EFI_SUCCESS;\r
683 } else {\r
684 return EFI_NOT_FOUND;\r
685 }\r
686 } else {\r
687 return Status;\r
688 }\r
689 }\r
690\r
691 return EFI_SUCCESS;\r
692}\r
693\r
694\r
695/**\r
696 Abort an asynchronous HTTP request or response token.\r
697\r
698 The Cancel() function aborts a pending HTTP request or response transaction. If\r
699 Token is not NULL and the token is in transmit or receive queues when it is being\r
700 cancelled, its Token->Status will be set to EFI_ABORTED and then Token->Event will\r
701 be signaled. If the token is not in one of the queues, which usually means that the\r
702 asynchronous operation has completed, EFI_NOT_FOUND is returned. If Token is NULL,\r
703 all asynchronous tokens issued by Request() or Response() will be aborted.\r
704\r
705 @param[in] This Pointer to EFI_HTTP_PROTOCOL instance.\r
706 @param[in] Token Point to storage containing HTTP request or response\r
707 token.\r
708\r
709 @retval EFI_SUCCESS Request and Response queues are successfully flushed.\r
710 @retval EFI_INVALID_PARAMETER This is NULL.\r
711 @retval EFI_NOT_STARTED This instance hasn't been configured.\r
712 @retval EFI_NO_MAPPING When using the default address, configuration (DHCP,\r
713 BOOTP, RARP, etc.) hasn't finished yet.\r
714 @retval EFI_NOT_FOUND The asynchronous request or response token is not\r
715 found.\r
716 @retval EFI_UNSUPPORTED The implementation does not support this function.\r
717\r
718**/\r
719EFI_STATUS\r
720EFIAPI\r
721EfiHttpCancel (\r
722 IN EFI_HTTP_PROTOCOL *This,\r
723 IN EFI_HTTP_TOKEN *Token\r
724 )\r
725{\r
726 HTTP_PROTOCOL *HttpInstance;\r
727\r
728 if (This == NULL) {\r
729 return EFI_INVALID_PARAMETER;\r
730 }\r
731\r
732 HttpInstance = HTTP_INSTANCE_FROM_PROTOCOL (This);\r
733 ASSERT (HttpInstance != NULL);\r
734\r
735 if (HttpInstance->State != HTTP_STATE_TCP_CONNECTED) {\r
736 return EFI_NOT_STARTED;\r
737 }\r
738\r
739 return HttpCancel (HttpInstance, Token);\r
740\r
741}\r
742\r
743/**\r
744 A callback function to intercept events during message parser.\r
745\r
746 This function will be invoked during HttpParseMessageBody() with various events type. An error\r
747 return status of the callback function will cause the HttpParseMessageBody() aborted.\r
748\r
749 @param[in] EventType Event type of this callback call.\r
750 @param[in] Data A pointer to data buffer.\r
751 @param[in] Length Length in bytes of the Data.\r
752 @param[in] Context Callback context set by HttpInitMsgParser().\r
753\r
754 @retval EFI_SUCCESS Continue to parser the message body.\r
755\r
756**/\r
757EFI_STATUS\r
758EFIAPI\r
759HttpBodyParserCallback (\r
760 IN HTTP_BODY_PARSE_EVENT EventType,\r
761 IN CHAR8 *Data,\r
762 IN UINTN Length,\r
763 IN VOID *Context\r
764 )\r
765{\r
766 HTTP_TOKEN_WRAP *Wrap;\r
767\r
768 if (EventType != BodyParseEventOnComplete) {\r
769 return EFI_SUCCESS;\r
770 }\r
771\r
772 if (Data == NULL || Length != 0 || Context == NULL) {\r
773 return EFI_SUCCESS;\r
774 }\r
775\r
776 Wrap = (HTTP_TOKEN_WRAP *) Context;\r
777 Wrap->HttpInstance->NextMsg = Data;\r
778\r
779 //\r
b659408b 780 // Free Tx4Token or Tx6Token since already received corrsponding HTTP response.\r
47f51a06
YT
781 //\r
782 FreePool (Wrap);\r
783\r
784 return EFI_SUCCESS;\r
785}\r
786\r
787/**\r
788 The work function of EfiHttpResponse().\r
789\r
790 @param[in] Wrap Pointer to HTTP token's wrap data.\r
791\r
792 @retval EFI_SUCCESS Allocation succeeded.\r
793 @retval EFI_OUT_OF_RESOURCES Failed to complete the opration due to lack of resources.\r
b659408b 794 @retval EFI_NOT_READY Can't find a corresponding Tx4Token/Tx6Token or \r
5ca29abe 795 the EFI_HTTP_UTILITIES_PROTOCOL is not available.\r
47f51a06
YT
796\r
797**/\r
798EFI_STATUS\r
799HttpResponseWorker (\r
800 IN HTTP_TOKEN_WRAP *Wrap\r
801 )\r
802{\r
803 EFI_STATUS Status;\r
804 EFI_HTTP_MESSAGE *HttpMsg;\r
47f51a06
YT
805 CHAR8 *EndofHeader;\r
806 CHAR8 *HttpHeaders;\r
807 UINTN SizeofHeaders;\r
47f51a06
YT
808 UINTN BufferSize;\r
809 UINTN StatusCode;\r
810 CHAR8 *Tmp;\r
811 CHAR8 *HeaderTmp;\r
812 CHAR8 *StatusCodeStr;\r
813 UINTN BodyLen;\r
814 HTTP_PROTOCOL *HttpInstance;\r
815 EFI_HTTP_TOKEN *Token;\r
816 NET_MAP_ITEM *Item;\r
817 HTTP_TOKEN_WRAP *ValueInItem;\r
818 UINTN HdrLen;\r
819\r
3fd7bd08 820 if (Wrap == NULL || Wrap->HttpInstance == NULL) {\r
821 return EFI_INVALID_PARAMETER;\r
822 }\r
823 \r
47f51a06
YT
824 HttpInstance = Wrap->HttpInstance;\r
825 Token = Wrap->HttpToken;\r
47f51a06
YT
826 HttpMsg = Token->Message;\r
827\r
b659408b
ZL
828 HttpInstance->EndofHeader = NULL;\r
829 HttpInstance->HttpHeaders = NULL;\r
830 HttpMsg->Headers = NULL;\r
831 HttpHeaders = NULL;\r
832 SizeofHeaders = 0;\r
833 BufferSize = 0;\r
834 EndofHeader = NULL;\r
47f51a06
YT
835 \r
836 if (HttpMsg->Data.Response != NULL) {\r
837 //\r
838 // Need receive the HTTP headers, prepare buffer.\r
839 //\r
b659408b 840 Status = HttpCreateTcpRxEventForHeader (HttpInstance);\r
47f51a06
YT
841 if (EFI_ERROR (Status)) {\r
842 goto Error;\r
843 }\r
844\r
845 //\r
846 // Check whether we have cached header from previous call.\r
847 //\r
848 if ((HttpInstance->CacheBody != NULL) && (HttpInstance->NextMsg != NULL)) {\r
849 //\r
850 // The data is stored at [NextMsg, CacheBody + CacheLen].\r
851 //\r
852 HdrLen = HttpInstance->CacheBody + HttpInstance->CacheLen - HttpInstance->NextMsg;\r
853 HttpHeaders = AllocateZeroPool (HdrLen);\r
854 if (HttpHeaders == NULL) {\r
855 Status = EFI_OUT_OF_RESOURCES;\r
856 goto Error;\r
857 }\r
858\r
859 CopyMem (HttpHeaders, HttpInstance->NextMsg, HdrLen);\r
860 FreePool (HttpInstance->CacheBody);\r
861 HttpInstance->CacheBody = NULL;\r
862 HttpInstance->NextMsg = NULL;\r
863 HttpInstance->CacheOffset = 0;\r
864 SizeofHeaders = HdrLen;\r
865 BufferSize = HttpInstance->CacheLen;\r
866\r
867 //\r
868 // Check whether we cached the whole HTTP headers.\r
869 //\r
870 EndofHeader = AsciiStrStr (HttpHeaders, HTTP_END_OF_HDR_STR); \r
b659408b 871 } \r
47f51a06 872\r
b659408b
ZL
873 HttpInstance->EndofHeader = &EndofHeader;\r
874 HttpInstance->HttpHeaders = &HttpHeaders;\r
47f51a06 875\r
b659408b
ZL
876 Status = HttpTcpReceiveHeader (HttpInstance, &SizeofHeaders, &BufferSize);\r
877 if (EFI_ERROR (Status)) {\r
878 goto Error;\r
879 }\r
47f51a06
YT
880\r
881 //\r
882 // Cache the part of body.\r
883 //\r
884 BodyLen = BufferSize - (EndofHeader - HttpHeaders);\r
885 if (BodyLen > 0) {\r
886 if (HttpInstance->CacheBody != NULL) {\r
887 FreePool (HttpInstance->CacheBody);\r
888 }\r
889\r
890 HttpInstance->CacheBody = AllocateZeroPool (BodyLen);\r
891 if (HttpInstance->CacheBody == NULL) {\r
892 Status = EFI_OUT_OF_RESOURCES;\r
893 goto Error;\r
894 }\r
895\r
896 CopyMem (HttpInstance->CacheBody, EndofHeader, BodyLen);\r
897 HttpInstance->CacheLen = BodyLen;\r
898 }\r
899\r
47f51a06
YT
900 //\r
901 // Search for Status Code.\r
902 //\r
903 StatusCodeStr = HttpHeaders + AsciiStrLen (HTTP_VERSION_STR) + 1;\r
904 if (StatusCodeStr == NULL) {\r
905 goto Error;\r
906 }\r
907\r
908 StatusCode = AsciiStrDecimalToUintn (StatusCodeStr);\r
909\r
910 //\r
911 // Remove the first line of HTTP message, e.g. "HTTP/1.1 200 OK\r\n".\r
912 //\r
913 Tmp = AsciiStrStr (HttpHeaders, HTTP_CRLF_STR);\r
914 if (Tmp == NULL) {\r
915 goto Error;\r
916 }\r
917\r
918 Tmp = Tmp + AsciiStrLen (HTTP_CRLF_STR);\r
919 SizeofHeaders = SizeofHeaders - (Tmp - HttpHeaders);\r
920 HeaderTmp = AllocateZeroPool (SizeofHeaders);\r
921 if (HeaderTmp == NULL) {\r
922 goto Error;\r
923 }\r
924\r
925 CopyMem (HeaderTmp, Tmp, SizeofHeaders);\r
926 FreePool (HttpHeaders);\r
927 HttpHeaders = HeaderTmp;\r
5ca29abe
JW
928\r
929 //\r
930 // Check whether the EFI_HTTP_UTILITIES_PROTOCOL is available.\r
931 //\r
932 if (mHttpUtilities == NULL) {\r
933 Status = EFI_NOT_READY;\r
934 goto Error;\r
935 }\r
936 \r
47f51a06
YT
937 //\r
938 // Parse the HTTP header into array of key/value pairs.\r
939 //\r
5ca29abe
JW
940 Status = mHttpUtilities->Parse (\r
941 mHttpUtilities, \r
942 HttpHeaders, \r
943 SizeofHeaders, \r
944 &HttpMsg->Headers, \r
945 &HttpMsg->HeaderCount\r
946 );\r
47f51a06
YT
947 if (EFI_ERROR (Status)) {\r
948 goto Error;\r
949 }\r
950\r
951 FreePool (HttpHeaders);\r
952 HttpHeaders = NULL;\r
953 \r
954 HttpMsg->Data.Response->StatusCode = HttpMappingToStatusCode (StatusCode);\r
955\r
956 //\r
957 // Init message-body parser by header information. \r
958 //\r
959 Status = EFI_NOT_READY;\r
960 ValueInItem = NULL;\r
961 NetMapRemoveHead (&HttpInstance->TxTokens, (VOID**) &ValueInItem);\r
962 if (ValueInItem == NULL) {\r
963 goto Error;\r
964 }\r
965\r
966 //\r
b659408b 967 // The first Tx Token not transmitted yet, insert back and return error.\r
47f51a06
YT
968 //\r
969 if (!ValueInItem->TcpWrap.IsTxDone) {\r
970 goto Error2;\r
971 }\r
972\r
973 Status = HttpInitMsgParser (\r
974 ValueInItem->TcpWrap.Method,\r
975 HttpMsg->Data.Response->StatusCode,\r
976 HttpMsg->HeaderCount,\r
977 HttpMsg->Headers,\r
978 HttpBodyParserCallback,\r
979 (VOID *) ValueInItem,\r
980 &HttpInstance->MsgParser\r
981 );\r
982 if (EFI_ERROR (Status)) { \r
983 goto Error2;\r
984 }\r
985\r
986 //\r
987 // Check whether we received a complete HTTP message.\r
988 //\r
989 if (HttpInstance->CacheBody != NULL) {\r
990 Status = HttpParseMessageBody (HttpInstance->MsgParser, HttpInstance->CacheLen, HttpInstance->CacheBody);\r
991 if (EFI_ERROR (Status)) {\r
992 goto Error2;\r
993 }\r
994\r
995 if (HttpIsMessageComplete (HttpInstance->MsgParser)) {\r
996 //\r
997 // Free the MsgParse since we already have a full HTTP message.\r
998 //\r
999 HttpFreeMsgParser (HttpInstance->MsgParser);\r
1000 HttpInstance->MsgParser = NULL;\r
1001 }\r
1002 }\r
1003\r
1004 if ((HttpMsg->Body == NULL) || (HttpMsg->BodyLength == 0)) { \r
1005 Status = EFI_SUCCESS;\r
1006 goto Exit;\r
1007 }\r
1008 } \r
1009\r
1010 //\r
1011 // Receive the response body.\r
1012 //\r
1013 BodyLen = 0;\r
1014\r
1015 //\r
1016 // First check whether we cached some data.\r
1017 //\r
1018 if (HttpInstance->CacheBody != NULL) {\r
1019 //\r
1020 // Calculate the length of the cached data.\r
1021 //\r
1022 if (HttpInstance->NextMsg != NULL) {\r
1023 //\r
1024 // We have a cached HTTP message which includes a part of HTTP header of next message.\r
1025 //\r
1026 BodyLen = HttpInstance->NextMsg - (HttpInstance->CacheBody + HttpInstance->CacheOffset); \r
1027 } else {\r
1028 BodyLen = HttpInstance->CacheLen - HttpInstance->CacheOffset;\r
1029 }\r
1030\r
1031 if (BodyLen > 0) {\r
1032 //\r
1033 // We have some cached data. Just copy the data and return.\r
1034 //\r
1035 if (HttpMsg->BodyLength < BodyLen) {\r
1036 CopyMem (HttpMsg->Body, HttpInstance->CacheBody + HttpInstance->CacheOffset, HttpMsg->BodyLength);\r
1037 HttpInstance->CacheOffset = HttpInstance->CacheOffset + HttpMsg->BodyLength;\r
1038 } else {\r
1039 //\r
1040 // Copy all cached data out.\r
1041 //\r
1042 CopyMem (HttpMsg->Body, HttpInstance->CacheBody + HttpInstance->CacheOffset, BodyLen);\r
1043 HttpInstance->CacheOffset = BodyLen + HttpInstance->CacheOffset;\r
1044 HttpMsg->BodyLength = BodyLen;\r
1045\r
1046 if (HttpInstance->NextMsg == NULL) {\r
1047 //\r
1048 // There is no HTTP header of next message. Just free the cache buffer.\r
1049 //\r
1050 FreePool (HttpInstance->CacheBody);\r
1051 HttpInstance->CacheBody = NULL;\r
1052 HttpInstance->NextMsg = NULL;\r
1053 HttpInstance->CacheOffset = 0;\r
1054 }\r
1055 }\r
1056 //\r
1057 // Return since we aready received required data.\r
1058 //\r
1059 Status = EFI_SUCCESS;\r
1060 goto Exit;\r
1061 } \r
1062\r
1063 if (BodyLen == 0 && HttpInstance->MsgParser == NULL) {\r
1064 //\r
1065 // We received a complete HTTP message, and we don't have more data to return to caller.\r
1066 //\r
1067 HttpMsg->BodyLength = 0;\r
1068 Status = EFI_SUCCESS;\r
1069 goto Exit; \r
1070 } \r
1071 }\r
1072\r
1073 ASSERT (HttpInstance->MsgParser != NULL);\r
1074\r
1075 //\r
1076 // We still need receive more data when there is no cache data and MsgParser is not NULL;\r
1077 //\r
b659408b 1078 Status = HttpTcpReceiveBody (Wrap, HttpMsg);\r
47f51a06 1079 if (EFI_ERROR (Status)) {\r
47f51a06
YT
1080 goto Error;\r
1081 }\r
1082\r
1083 return Status;\r
1084\r
1085Exit:\r
1086 Item = NetMapFindKey (&Wrap->HttpInstance->RxTokens, Wrap->HttpToken);\r
1087 if (Item != NULL) {\r
1088 NetMapRemoveItem (&Wrap->HttpInstance->RxTokens, Item, NULL);\r
1089 }\r
1090 Token->Status = Status;\r
1091 gBS->SignalEvent (Token->Event);\r
b659408b 1092 HttpCloseTcpRxEvent (Wrap);\r
47f51a06
YT
1093 FreePool (Wrap);\r
1094 return Status;\r
1095\r
1096Error2:\r
1097 NetMapInsertHead (&HttpInstance->TxTokens, ValueInItem->HttpToken, ValueInItem);\r
1098\r
1099Error:\r
b659408b 1100 HttpTcpTokenCleanup (Wrap);\r
47f51a06
YT
1101 \r
1102 if (HttpHeaders != NULL) {\r
1103 FreePool (HttpHeaders);\r
1104 }\r
1105\r
1106 if (HttpMsg->Headers != NULL) {\r
1107 FreePool (HttpMsg->Headers);\r
1108 }\r
1109\r
1110 if (HttpInstance->CacheBody != NULL) {\r
1111 FreePool (HttpInstance->CacheBody);\r
1112 HttpInstance->CacheBody = NULL;\r
1113 }\r
1114\r
1115 Token->Status = Status;\r
1116 gBS->SignalEvent (Token->Event);\r
1117\r
1118 return Status; \r
1119\r
1120}\r
1121\r
1122\r
1123/**\r
1124 The Response() function queues an HTTP response to this HTTP instance, similar to\r
1125 Receive() function in the EFI TCP driver. When the HTTP request is sent successfully,\r
1126 or if there is an error, Status in token will be updated and Event will be signaled.\r
1127\r
1128 The HTTP driver will queue a receive token to the underlying TCP instance. When data\r
1129 is received in the underlying TCP instance, the data will be parsed and Token will\r
1130 be populated with the response data. If the data received from the remote host\r
1131 contains an incomplete or invalid HTTP header, the HTTP driver will continue waiting\r
1132 (asynchronously) for more data to be sent from the remote host before signaling\r
1133 Event in Token.\r
1134\r
1135 It is the responsibility of the caller to allocate a buffer for Body and specify the\r
1136 size in BodyLength. If the remote host provides a response that contains a content\r
1137 body, up to BodyLength bytes will be copied from the receive buffer into Body and\r
1138 BodyLength will be updated with the amount of bytes received and copied to Body. This\r
1139 allows the client to download a large file in chunks instead of into one contiguous\r
1140 block of memory. Similar to HTTP request, if Body is not NULL and BodyLength is\r
1141 non-zero and all other fields are NULL or 0, the HTTP driver will queue a receive\r
1142 token to underlying TCP instance. If data arrives in the receive buffer, up to\r
1143 BodyLength bytes of data will be copied to Body. The HTTP driver will then update\r
1144 BodyLength with the amount of bytes received and copied to Body.\r
1145\r
1146 If the HTTP driver does not have an open underlying TCP connection with the host\r
1147 specified in the response URL, Request() will return EFI_ACCESS_DENIED. This is\r
1148 consistent with RFC 2616 recommendation that HTTP clients should attempt to maintain\r
1149 an open TCP connection between client and host.\r
1150\r
1151 @param[in] This Pointer to EFI_HTTP_PROTOCOL instance.\r
1152 @param[in] Token Pointer to storage containing HTTP response token.\r
1153\r
1154 @retval EFI_SUCCESS Allocation succeeded.\r
1155 @retval EFI_NOT_STARTED This EFI HTTP Protocol instance has not been\r
1156 initialized.\r
1157 @retval EFI_INVALID_PARAMETER One or more of the following conditions is TRUE:\r
1158 This is NULL.\r
1159 Token is NULL.\r
1160 Token->Message->Headers is NULL.\r
1161 Token->Message is NULL.\r
1162 Token->Message->Body is not NULL,\r
1163 Token->Message->BodyLength is non-zero, and\r
1164 Token->Message->Data is NULL, but a previous call to\r
1165 Response() has not been completed successfully.\r
1166 @retval EFI_OUT_OF_RESOURCES Could not allocate enough system resources.\r
1167 @retval EFI_ACCESS_DENIED An open TCP connection is not present with the host\r
1168 specified by response URL.\r
1169**/\r
1170EFI_STATUS\r
1171EFIAPI\r
1172EfiHttpResponse (\r
1173 IN EFI_HTTP_PROTOCOL *This,\r
1174 IN EFI_HTTP_TOKEN *Token\r
1175 )\r
1176{\r
1177 EFI_STATUS Status;\r
1178 EFI_HTTP_MESSAGE *HttpMsg;\r
1179 HTTP_PROTOCOL *HttpInstance;\r
1180 HTTP_TOKEN_WRAP *Wrap;\r
1181\r
1182 if ((This == NULL) || (Token == NULL)) {\r
1183 return EFI_INVALID_PARAMETER;\r
1184 }\r
1185\r
1186 HttpMsg = Token->Message;\r
1187 if (HttpMsg == NULL) {\r
1188 return EFI_INVALID_PARAMETER;\r
1189 }\r
1190 \r
1191 HttpInstance = HTTP_INSTANCE_FROM_PROTOCOL (This);\r
1192 ASSERT (HttpInstance != NULL);\r
1193\r
1194 if (HttpInstance->State != HTTP_STATE_TCP_CONNECTED) {\r
1195 return EFI_NOT_STARTED;\r
1196 }\r
1197\r
47f51a06
YT
1198 //\r
1199 // Check whether the token already existed.\r
1200 //\r
1201 if (EFI_ERROR (NetMapIterate (&HttpInstance->RxTokens, HttpTokenExist, Token))) {\r
1202 return EFI_ACCESS_DENIED; \r
1203 }\r
1204\r
1205 Wrap = AllocateZeroPool (sizeof (HTTP_TOKEN_WRAP));\r
1206 if (Wrap == NULL) {\r
1207 return EFI_OUT_OF_RESOURCES;\r
1208 }\r
1209\r
1210 Wrap->HttpInstance = HttpInstance;\r
1211 Wrap->HttpToken = Token;\r
1212\r
b659408b 1213 Status = HttpCreateTcpRxEvent (Wrap);\r
47f51a06
YT
1214 if (EFI_ERROR (Status)) {\r
1215 goto Error;\r
1216 }\r
1217\r
1218 Status = NetMapInsertTail (&HttpInstance->RxTokens, Token, Wrap);\r
1219 if (EFI_ERROR (Status)) {\r
1220 goto Error;\r
1221 }\r
1222\r
1223 //\r
1224 // If already have pending RxTokens, return directly.\r
1225 //\r
1226 if (NetMapGetCount (&HttpInstance->RxTokens) > 1) {\r
1227 return EFI_SUCCESS;\r
1228 }\r
1229\r
1230 return HttpResponseWorker (Wrap);\r
1231\r
1232Error:\r
1233 if (Wrap != NULL) {\r
b659408b
ZL
1234 if (Wrap->TcpWrap.Rx4Token.CompletionToken.Event != NULL) {\r
1235 gBS->CloseEvent (Wrap->TcpWrap.Rx4Token.CompletionToken.Event);\r
1236 }\r
1237\r
1238 if (Wrap->TcpWrap.Rx6Token.CompletionToken.Event != NULL) {\r
1239 gBS->CloseEvent (Wrap->TcpWrap.Rx6Token.CompletionToken.Event);\r
47f51a06
YT
1240 }\r
1241 FreePool (Wrap);\r
1242 } \r
1243\r
1244 return Status; \r
1245}\r
1246\r
1247/**\r
1248 The Poll() function can be used by network drivers and applications to increase the\r
1249 rate that data packets are moved between the communication devices and the transmit\r
1250 and receive queues.\r
1251\r
1252 In some systems, the periodic timer event in the managed network driver may not poll\r
1253 the underlying communications device fast enough to transmit and/or receive all data\r
1254 packets without missing incoming packets or dropping outgoing packets. Drivers and\r
1255 applications that are experiencing packet loss should try calling the Poll() function\r
1256 more often.\r
1257\r
1258 @param[in] This Pointer to EFI_HTTP_PROTOCOL instance.\r
1259\r
1260 @retval EFI_SUCCESS Incoming or outgoing data was processed.\r
1261 @retval EFI_DEVICE_ERROR An unexpected system or network error occurred.\r
1262 @retval EFI_INVALID_PARAMETER This is NULL.\r
1263 @retval EFI_NOT_READY No incoming or outgoing data is processed.\r
1264 @retval EFI_NOT_STARTED This EFI HTTP Protocol instance has not been started.\r
1265\r
1266**/\r
1267EFI_STATUS\r
1268EFIAPI\r
1269EfiHttpPoll (\r
1270 IN EFI_HTTP_PROTOCOL *This\r
1271 )\r
1272{\r
49c9f74c 1273 EFI_STATUS Status;\r
b659408b 1274 HTTP_PROTOCOL *HttpInstance;\r
47f51a06
YT
1275\r
1276 if (This == NULL) {\r
1277 return EFI_INVALID_PARAMETER;\r
1278 }\r
1279\r
1280 HttpInstance = HTTP_INSTANCE_FROM_PROTOCOL (This);\r
1281 ASSERT (HttpInstance != NULL);\r
1282\r
b659408b
ZL
1283 if (HttpInstance->State != HTTP_STATE_TCP_CONNECTED || (HttpInstance->Tcp4 == NULL && \r
1284 HttpInstance->Tcp6 == NULL)) {\r
47f51a06
YT
1285 return EFI_NOT_STARTED;\r
1286 }\r
b659408b
ZL
1287 \r
1288 if (HttpInstance->LocalAddressIsIPv6) {\r
1289 Status = HttpInstance->Tcp6->Poll (HttpInstance->Tcp6);\r
1290 } else {\r
1291 Status = HttpInstance->Tcp4->Poll (HttpInstance->Tcp4);\r
1292 }\r
1293 \r
49c9f74c 1294 DispatchDpc ();\r
b659408b 1295 \r
49c9f74c 1296 return Status;\r
47f51a06 1297}\r