]> git.proxmox.com Git - mirror_edk2.git/blame - NetworkPkg/HttpBootDxe/HttpBootSupport.c
NetworkPkg/HttpBootDxe: Correct the parameter check for the usage of HttpBootGetFileF...
[mirror_edk2.git] / NetworkPkg / HttpBootDxe / HttpBootSupport.c
CommitLineData
d933e70a
JW
1/** @file\r
2 Support functions implementation for UEFI HTTP boot driver.\r
3\r
221463c2 4Copyright (c) 2015 - 2017, Intel Corporation. All rights reserved.<BR>\r
f58554fc
GB
5(C) Copyright 2016 Hewlett Packard Enterprise Development LP<BR>\r
6This program and the accompanying materials are licensed and made available under\r
7the terms and conditions of the BSD License that accompanies this distribution.\r
d933e70a
JW
8The 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 "HttpBootDxe.h"\r
17\r
18\r
19/**\r
20 Get the Nic handle using any child handle in the IPv4 stack.\r
21\r
22 @param[in] ControllerHandle Pointer to child handle over IPv4.\r
23\r
24 @return NicHandle The pointer to the Nic handle.\r
25 @return NULL Can't find the Nic handle.\r
26\r
27**/\r
28EFI_HANDLE\r
29HttpBootGetNicByIp4Children (\r
30 IN EFI_HANDLE ControllerHandle\r
31 )\r
32{\r
33 EFI_HANDLE NicHandle;\r
34\r
35 NicHandle = NetLibGetNicHandle (ControllerHandle, &gEfiHttpProtocolGuid);\r
36 if (NicHandle == NULL) {\r
37 NicHandle = NetLibGetNicHandle (ControllerHandle, &gEfiDhcp4ProtocolGuid);\r
38 if (NicHandle == NULL) {\r
39 return NULL;\r
40 }\r
41 }\r
42\r
43 return NicHandle;\r
44}\r
45\r
b659408b
ZL
46/**\r
47 Get the Nic handle using any child handle in the IPv6 stack.\r
48\r
49 @param[in] ControllerHandle Pointer to child handle over IPv6.\r
50\r
51 @return NicHandle The pointer to the Nic handle.\r
52 @return NULL Can't find the Nic handle.\r
53\r
54**/\r
55EFI_HANDLE\r
56HttpBootGetNicByIp6Children (\r
57 IN EFI_HANDLE ControllerHandle\r
58 )\r
59{\r
60 EFI_HANDLE NicHandle;\r
61 NicHandle = NetLibGetNicHandle (ControllerHandle, &gEfiHttpProtocolGuid);\r
62 if (NicHandle == NULL) {\r
63 NicHandle = NetLibGetNicHandle (ControllerHandle, &gEfiDhcp6ProtocolGuid);\r
64 if (NicHandle == NULL) {\r
65 return NULL;\r
66 }\r
67 }\r
68\r
69 return NicHandle;\r
70}\r
d933e70a
JW
71\r
72/**\r
73 This function is to convert UINTN to ASCII string with the required formatting.\r
74\r
75 @param[in] Number Numeric value to be converted.\r
76 @param[in] Buffer The pointer to the buffer for ASCII string.\r
77 @param[in] Length The length of the required format.\r
78\r
79**/\r
80VOID\r
81HttpBootUintnToAscDecWithFormat (\r
82 IN UINTN Number,\r
83 IN UINT8 *Buffer,\r
84 IN INTN Length\r
85 )\r
86{\r
87 UINTN Remainder;\r
88\r
413535bb 89 for (; Length > 0; Length--) {\r
d933e70a
JW
90 Remainder = Number % 10;\r
91 Number /= 10;\r
413535bb 92 Buffer[Length - 1] = (UINT8) ('0' + Remainder);\r
d933e70a
JW
93 }\r
94}\r
95\r
96/**\r
97 This function is to display the IPv4 address.\r
98\r
99 @param[in] Ip The pointer to the IPv4 address.\r
100\r
101**/\r
102VOID\r
103HttpBootShowIp4Addr (\r
104 IN EFI_IPv4_ADDRESS *Ip\r
105 )\r
106{\r
107 UINTN Index;\r
108\r
109 for (Index = 0; Index < 4; Index++) {\r
110 AsciiPrint ("%d", Ip->Addr[Index]);\r
111 if (Index < 3) {\r
112 AsciiPrint (".");\r
113 }\r
114 }\r
115}\r
116\r
b659408b
ZL
117/**\r
118 This function is to display the IPv6 address.\r
119\r
120 @param[in] Ip The pointer to the IPv6 address.\r
121\r
122**/\r
123VOID\r
124HttpBootShowIp6Addr (\r
125 IN EFI_IPv6_ADDRESS *Ip\r
126 )\r
127{\r
128 UINTN Index;\r
129\r
130 for (Index = 0; Index < 16; Index++) {\r
131\r
132 if (Ip->Addr[Index] != 0) {\r
133 AsciiPrint ("%x", Ip->Addr[Index]);\r
134 }\r
135 Index++;\r
136 if (Index > 15) {\r
137 return;\r
138 }\r
139 if (((Ip->Addr[Index] & 0xf0) == 0) && (Ip->Addr[Index - 1] != 0)) {\r
140 AsciiPrint ("0");\r
141 }\r
142 AsciiPrint ("%x", Ip->Addr[Index]);\r
143 if (Index < 15) {\r
144 AsciiPrint (":");\r
145 }\r
146 }\r
147}\r
148\r
62cae351
ZL
149/**\r
150 This function is to display the HTTP error status.\r
151\r
152 @param[in] StatusCode The status code value in HTTP message.\r
153\r
154**/\r
155VOID\r
156HttpBootPrintErrorMessage (\r
157 EFI_HTTP_STATUS_CODE StatusCode\r
158 )\r
159{\r
160 AsciiPrint ("\n");\r
161\r
162 switch (StatusCode) {\r
d58bb59d 163 case HTTP_STATUS_300_MULTIPLE_CHOICES:\r
62cae351
ZL
164 AsciiPrint ("\n Redirection: 300 Multiple Choices");\r
165 break; \r
166 \r
167 case HTTP_STATUS_301_MOVED_PERMANENTLY:\r
168 AsciiPrint ("\n Redirection: 301 Moved Permanently");\r
169 break; \r
170 \r
171 case HTTP_STATUS_302_FOUND:\r
172 AsciiPrint ("\n Redirection: 302 Found");\r
173 break; \r
174 \r
175 case HTTP_STATUS_303_SEE_OTHER:\r
176 AsciiPrint ("\n Redirection: 303 See Other");\r
177 break; \r
178\r
179 case HTTP_STATUS_304_NOT_MODIFIED:\r
180 AsciiPrint ("\n Redirection: 304 Not Modified");\r
181 break; \r
182\r
183 case HTTP_STATUS_305_USE_PROXY:\r
184 AsciiPrint ("\n Redirection: 305 Use Proxy");\r
185 break; \r
186\r
187 case HTTP_STATUS_307_TEMPORARY_REDIRECT:\r
188 AsciiPrint ("\n Redirection: 307 Temporary Redirect");\r
406d1d92 189 break;\r
190\r
191 case HTTP_STATUS_308_PERMANENT_REDIRECT:\r
192 AsciiPrint ("\n Redirection: 308 Permanent Redirect");\r
62cae351
ZL
193 break; \r
194\r
195 case HTTP_STATUS_400_BAD_REQUEST:\r
196 AsciiPrint ("\n Client Error: 400 Bad Request");\r
197 break;\r
198 \r
199 case HTTP_STATUS_401_UNAUTHORIZED:\r
200 AsciiPrint ("\n Client Error: 401 Unauthorized");\r
201 break;\r
202 \r
203 case HTTP_STATUS_402_PAYMENT_REQUIRED:\r
204 AsciiPrint ("\n Client Error: 402 Payment Required");\r
205 break;\r
206\r
207 case HTTP_STATUS_403_FORBIDDEN:\r
208 AsciiPrint ("\n Client Error: 403 Forbidden");\r
209 break;\r
210\r
211 case HTTP_STATUS_404_NOT_FOUND:\r
212 AsciiPrint ("\n Client Error: 404 Not Found");\r
213 break;\r
214\r
215 case HTTP_STATUS_405_METHOD_NOT_ALLOWED:\r
216 AsciiPrint ("\n Client Error: 405 Method Not Allowed");\r
217 break;\r
218\r
219 case HTTP_STATUS_406_NOT_ACCEPTABLE:\r
220 AsciiPrint ("\n Client Error: 406 Not Acceptable");\r
221 break;\r
222\r
223 case HTTP_STATUS_407_PROXY_AUTHENTICATION_REQUIRED:\r
224 AsciiPrint ("\n Client Error: 407 Proxy Authentication Required");\r
225 break;\r
226\r
227 case HTTP_STATUS_408_REQUEST_TIME_OUT:\r
228 AsciiPrint ("\n Client Error: 408 Request Timeout");\r
229 break;\r
230\r
231 case HTTP_STATUS_409_CONFLICT:\r
232 AsciiPrint ("\n Client Error: 409 Conflict");\r
233 break;\r
234\r
235 case HTTP_STATUS_410_GONE:\r
236 AsciiPrint ("\n Client Error: 410 Gone");\r
237 break;\r
238\r
239 case HTTP_STATUS_411_LENGTH_REQUIRED:\r
240 AsciiPrint ("\n Client Error: 411 Length Required");\r
241 break;\r
242\r
243 case HTTP_STATUS_412_PRECONDITION_FAILED:\r
244 AsciiPrint ("\n Client Error: 412 Precondition Failed");\r
245 break;\r
246\r
247 case HTTP_STATUS_413_REQUEST_ENTITY_TOO_LARGE:\r
248 AsciiPrint ("\n Client Error: 413 Request Entity Too Large");\r
249 break;\r
250\r
251 case HTTP_STATUS_414_REQUEST_URI_TOO_LARGE:\r
252 AsciiPrint ("\n Client Error: 414 Request URI Too Long");\r
253 break;\r
254\r
255 case HTTP_STATUS_415_UNSUPPORTED_MEDIA_TYPE:\r
256 AsciiPrint ("\n Client Error: 415 Unsupported Media Type");\r
257 break;\r
258\r
259 case HTTP_STATUS_416_REQUESTED_RANGE_NOT_SATISFIED:\r
260 AsciiPrint ("\n Client Error: 416 Requested Range Not Satisfiable");\r
261 break;\r
262\r
263 case HTTP_STATUS_417_EXPECTATION_FAILED:\r
264 AsciiPrint ("\n Client Error: 417 Expectation Failed");\r
265 break;\r
266\r
267 case HTTP_STATUS_500_INTERNAL_SERVER_ERROR:\r
268 AsciiPrint ("\n Server Error: 500 Internal Server Error");\r
269 break;\r
270\r
271 case HTTP_STATUS_501_NOT_IMPLEMENTED:\r
272 AsciiPrint ("\n Server Error: 501 Not Implemented");\r
273 break;\r
274\r
275 case HTTP_STATUS_502_BAD_GATEWAY:\r
276 AsciiPrint ("\n Server Error: 502 Bad Gateway");\r
277 break;\r
278\r
279 case HTTP_STATUS_503_SERVICE_UNAVAILABLE:\r
280 AsciiPrint ("\n Server Error: 503 Service Unavailable");\r
281 break;\r
282\r
283 case HTTP_STATUS_504_GATEWAY_TIME_OUT:\r
284 AsciiPrint ("\n Server Error: 504 Gateway Timeout");\r
285 break;\r
286\r
287 case HTTP_STATUS_505_HTTP_VERSION_NOT_SUPPORTED:\r
288 AsciiPrint ("\n Server Error: 505 HTTP Version Not Supported");\r
289 break;\r
290\r
291 default: ;\r
292 \r
293 }\r
294}\r
295\r
b659408b
ZL
296/**\r
297 Notify the callback function when an event is triggered.\r
298\r
299 @param[in] Event The triggered event.\r
300 @param[in] Context The opaque parameter to the function.\r
301\r
302**/\r
303VOID\r
304EFIAPI\r
305HttpBootCommonNotify (\r
306 IN EFI_EVENT Event,\r
307 IN VOID *Context\r
308 )\r
309{\r
310 *((BOOLEAN *) Context) = TRUE;\r
311}\r
312\r
313/**\r
314 Retrieve the host address using the EFI_DNS6_PROTOCOL.\r
315\r
316 @param[in] Private The pointer to the driver's private data.\r
317 @param[in] HostName Pointer to buffer containing hostname.\r
318 @param[out] IpAddress On output, pointer to buffer containing IPv6 address.\r
319\r
320 @retval EFI_SUCCESS Operation succeeded.\r
321 @retval EFI_DEVICE_ERROR An unexpected network error occurred.\r
322 @retval Others Other errors as indicated. \r
323**/\r
324EFI_STATUS\r
325HttpBootDns (\r
326 IN HTTP_BOOT_PRIVATE_DATA *Private,\r
327 IN CHAR16 *HostName,\r
328 OUT EFI_IPv6_ADDRESS *IpAddress \r
329 )\r
330{\r
331 EFI_STATUS Status;\r
332 EFI_DNS6_PROTOCOL *Dns6;\r
333 EFI_DNS6_CONFIG_DATA Dns6ConfigData;\r
334 EFI_DNS6_COMPLETION_TOKEN Token;\r
335 EFI_HANDLE Dns6Handle;\r
336 EFI_IP6_CONFIG_PROTOCOL *Ip6Config;\r
337 EFI_IPv6_ADDRESS *DnsServerList;\r
338 UINTN DnsServerListCount;\r
339 UINTN DataSize;\r
340 BOOLEAN IsDone; \r
341 \r
342 DnsServerList = NULL;\r
343 DnsServerListCount = 0;\r
344 Dns6 = NULL;\r
345 Dns6Handle = NULL;\r
346 ZeroMem (&Token, sizeof (EFI_DNS6_COMPLETION_TOKEN));\r
347 \r
348 //\r
349 // Get DNS server list from EFI IPv6 Configuration protocol.\r
350 //\r
351 Status = gBS->HandleProtocol (Private->Controller, &gEfiIp6ConfigProtocolGuid, (VOID **) &Ip6Config);\r
352 if (!EFI_ERROR (Status)) {\r
353 //\r
354 // Get the required size.\r
355 //\r
356 DataSize = 0;\r
357 Status = Ip6Config->GetData (Ip6Config, Ip6ConfigDataTypeDnsServer, &DataSize, NULL);\r
358 if (Status == EFI_BUFFER_TOO_SMALL) {\r
359 DnsServerList = AllocatePool (DataSize);\r
360 if (DnsServerList == NULL) {\r
361 return EFI_OUT_OF_RESOURCES;\r
362 } \r
363\r
364 Status = Ip6Config->GetData (Ip6Config, Ip6ConfigDataTypeDnsServer, &DataSize, DnsServerList);\r
365 if (EFI_ERROR (Status)) {\r
366 FreePool (DnsServerList);\r
367 DnsServerList = NULL;\r
368 } else {\r
369 DnsServerListCount = DataSize / sizeof (EFI_IPv6_ADDRESS);\r
370 }\r
371 }\r
372 }\r
373 //\r
374 // Create a DNSv6 child instance and get the protocol.\r
375 //\r
376 Status = NetLibCreateServiceChild (\r
377 Private->Controller,\r
75372581 378 Private->Ip6Nic->ImageHandle,\r
b659408b
ZL
379 &gEfiDns6ServiceBindingProtocolGuid,\r
380 &Dns6Handle\r
381 );\r
382 if (EFI_ERROR (Status)) {\r
383 goto Exit;\r
384 } \r
385 \r
386 Status = gBS->OpenProtocol (\r
387 Dns6Handle,\r
388 &gEfiDns6ProtocolGuid,\r
389 (VOID **) &Dns6,\r
75372581 390 Private->Ip6Nic->ImageHandle,\r
b659408b
ZL
391 Private->Controller,\r
392 EFI_OPEN_PROTOCOL_BY_DRIVER\r
393 );\r
394 if (EFI_ERROR (Status)) {\r
395 goto Exit;\r
396 }\r
397\r
398 //\r
399 // Configure DNS6 instance for the DNS server address and protocol.\r
400 //\r
401 ZeroMem (&Dns6ConfigData, sizeof (EFI_DNS6_CONFIG_DATA));\r
402 Dns6ConfigData.DnsServerCount = (UINT32)DnsServerListCount;\r
403 Dns6ConfigData.DnsServerList = DnsServerList;\r
404 Dns6ConfigData.EnableDnsCache = TRUE;\r
405 Dns6ConfigData.Protocol = EFI_IP_PROTO_UDP;\r
406 IP6_COPY_ADDRESS (&Dns6ConfigData.StationIp,&Private->StationIp.v6);\r
407 Status = Dns6->Configure (\r
408 Dns6,\r
409 &Dns6ConfigData\r
410 );\r
411 if (EFI_ERROR (Status)) {\r
412 goto Exit;\r
413 }\r
414 \r
415 Token.Status = EFI_NOT_READY;\r
416 IsDone = FALSE;\r
417 //\r
418 // Create event to set the IsDone flag when name resolution is finished.\r
419 //\r
420 Status = gBS->CreateEvent (\r
421 EVT_NOTIFY_SIGNAL,\r
422 TPL_NOTIFY,\r
423 HttpBootCommonNotify,\r
424 &IsDone,\r
425 &Token.Event\r
426 );\r
427 if (EFI_ERROR (Status)) {\r
428 goto Exit;\r
429 }\r
430\r
431 //\r
432 // Start asynchronous name resolution.\r
433 //\r
434 Status = Dns6->HostNameToIp (Dns6, HostName, &Token);\r
435 if (EFI_ERROR (Status)) {\r
436 goto Exit;\r
437 }\r
438\r
439 while (!IsDone) {\r
440 Dns6->Poll (Dns6);\r
441 }\r
442 \r
443 //\r
444 // Name resolution is done, check result.\r
445 //\r
446 Status = Token.Status; \r
447 if (!EFI_ERROR (Status)) {\r
448 if (Token.RspData.H2AData == NULL) {\r
449 Status = EFI_DEVICE_ERROR;\r
450 goto Exit;\r
451 }\r
452 if (Token.RspData.H2AData->IpCount == 0 || Token.RspData.H2AData->IpList == NULL) {\r
453 Status = EFI_DEVICE_ERROR;\r
454 goto Exit;\r
455 }\r
456 //\r
457 // We just return the first IPv6 address from DNS protocol.\r
458 //\r
459 IP6_COPY_ADDRESS (IpAddress, Token.RspData.H2AData->IpList);\r
460 Status = EFI_SUCCESS;\r
461 }\r
462Exit:\r
463\r
464 if (Token.Event != NULL) {\r
465 gBS->CloseEvent (Token.Event);\r
466 }\r
467 if (Token.RspData.H2AData != NULL) {\r
468 if (Token.RspData.H2AData->IpList != NULL) {\r
469 FreePool (Token.RspData.H2AData->IpList);\r
470 }\r
471 FreePool (Token.RspData.H2AData);\r
472 }\r
473\r
474 if (Dns6 != NULL) {\r
475 Dns6->Configure (Dns6, NULL);\r
476 \r
477 gBS->CloseProtocol (\r
478 Dns6Handle,\r
479 &gEfiDns6ProtocolGuid,\r
75372581 480 Private->Ip6Nic->ImageHandle,\r
b659408b
ZL
481 Private->Controller\r
482 );\r
483 }\r
484\r
485 if (Dns6Handle != NULL) {\r
486 NetLibDestroyServiceChild (\r
487 Private->Controller,\r
75372581 488 Private->Ip6Nic->ImageHandle,\r
b659408b
ZL
489 &gEfiDns6ServiceBindingProtocolGuid,\r
490 Dns6Handle\r
491 );\r
492 }\r
493\r
494 if (DnsServerList != NULL) {\r
495 FreePool (DnsServerList);\r
496 }\r
497 \r
498 return Status; \r
499}\r
d933e70a
JW
500/**\r
501 Create a HTTP_IO_HEADER to hold the HTTP header items.\r
502\r
503 @param[in] MaxHeaderCount The maximun number of HTTP header in this holder.\r
504\r
505 @return A pointer of the HTTP header holder or NULL if failed.\r
506 \r
507**/\r
508HTTP_IO_HEADER *\r
509HttpBootCreateHeader (\r
510 UINTN MaxHeaderCount\r
b659408b 511 )\r
d933e70a
JW
512{\r
513 HTTP_IO_HEADER *HttpIoHeader;\r
514\r
515 if (MaxHeaderCount == 0) {\r
516 return NULL;\r
517 }\r
518\r
519 HttpIoHeader = AllocateZeroPool (sizeof (HTTP_IO_HEADER) + MaxHeaderCount * sizeof (EFI_HTTP_HEADER));\r
520 if (HttpIoHeader == NULL) {\r
521 return NULL;\r
522 }\r
523\r
524 HttpIoHeader->MaxHeaderCount = MaxHeaderCount;\r
525 HttpIoHeader->Headers = (EFI_HTTP_HEADER *) (HttpIoHeader + 1);\r
526\r
527 return HttpIoHeader;\r
528}\r
529\r
530/**\r
531 Destroy the HTTP_IO_HEADER and release the resouces. \r
532\r
533 @param[in] HttpIoHeader Point to the HTTP header holder to be destroyed.\r
534\r
535**/\r
536VOID\r
537HttpBootFreeHeader (\r
538 IN HTTP_IO_HEADER *HttpIoHeader\r
539 )\r
540{\r
541 UINTN Index;\r
542 \r
543 if (HttpIoHeader != NULL) {\r
544 if (HttpIoHeader->HeaderCount != 0) {\r
545 for (Index = 0; Index < HttpIoHeader->HeaderCount; Index++) {\r
546 FreePool (HttpIoHeader->Headers[Index].FieldName);\r
547 FreePool (HttpIoHeader->Headers[Index].FieldValue);\r
548 }\r
549 }\r
550 FreePool (HttpIoHeader);\r
551 }\r
552}\r
553\r
d933e70a
JW
554/**\r
555 Set or update a HTTP header with the field name and corresponding value.\r
556\r
557 @param[in] HttpIoHeader Point to the HTTP header holder.\r
f58554fc 558 @param[in] FieldName Null terminated string which describes a field name.\r
d933e70a
JW
559 @param[in] FieldValue Null terminated string which describes the corresponding field value.\r
560\r
561 @retval EFI_SUCCESS The HTTP header has been set or updated.\r
562 @retval EFI_INVALID_PARAMETER Any input parameter is invalid.\r
563 @retval EFI_OUT_OF_RESOURCES Insufficient resource to complete the operation.\r
564 @retval Other Unexpected error happened.\r
565 \r
566**/\r
567EFI_STATUS\r
568HttpBootSetHeader (\r
569 IN HTTP_IO_HEADER *HttpIoHeader,\r
570 IN CHAR8 *FieldName,\r
571 IN CHAR8 *FieldValue\r
572 )\r
573{\r
574 EFI_HTTP_HEADER *Header;\r
575 UINTN StrSize;\r
576 CHAR8 *NewFieldValue;\r
577 \r
578 if (HttpIoHeader == NULL || FieldName == NULL || FieldValue == NULL) {\r
579 return EFI_INVALID_PARAMETER;\r
580 }\r
581\r
f58554fc 582 Header = HttpFindHeader (HttpIoHeader->HeaderCount, HttpIoHeader->Headers, FieldName);\r
d933e70a
JW
583 if (Header == NULL) {\r
584 //\r
585 // Add a new header.\r
586 //\r
587 if (HttpIoHeader->HeaderCount >= HttpIoHeader->MaxHeaderCount) {\r
588 return EFI_OUT_OF_RESOURCES;\r
589 }\r
590 Header = &HttpIoHeader->Headers[HttpIoHeader->HeaderCount];\r
591\r
592 StrSize = AsciiStrSize (FieldName);\r
593 Header->FieldName = AllocatePool (StrSize);\r
594 if (Header->FieldName == NULL) {\r
595 return EFI_OUT_OF_RESOURCES;\r
596 }\r
597 CopyMem (Header->FieldName, FieldName, StrSize);\r
598 Header->FieldName[StrSize -1] = '\0';\r
599\r
600 StrSize = AsciiStrSize (FieldValue);\r
601 Header->FieldValue = AllocatePool (StrSize);\r
602 if (Header->FieldValue == NULL) {\r
603 FreePool (Header->FieldName);\r
604 return EFI_OUT_OF_RESOURCES;\r
605 }\r
606 CopyMem (Header->FieldValue, FieldValue, StrSize);\r
607 Header->FieldValue[StrSize -1] = '\0';\r
608\r
609 HttpIoHeader->HeaderCount++;\r
610 } else {\r
611 //\r
612 // Update an existing one.\r
613 //\r
614 StrSize = AsciiStrSize (FieldValue);\r
615 NewFieldValue = AllocatePool (StrSize);\r
616 if (NewFieldValue == NULL) {\r
617 return EFI_OUT_OF_RESOURCES;\r
618 }\r
619 CopyMem (NewFieldValue, FieldValue, StrSize);\r
620 NewFieldValue[StrSize -1] = '\0';\r
621 \r
622 if (Header->FieldValue != NULL) {\r
623 FreePool (Header->FieldValue);\r
624 }\r
625 Header->FieldValue = NewFieldValue;\r
626 }\r
627\r
628 return EFI_SUCCESS;\r
629}\r
630\r
5e9e151c
JW
631/**\r
632 Notify the callback function when an event is triggered.\r
633\r
634 @param[in] Context The opaque parameter to the function.\r
635\r
636**/\r
637VOID\r
6c6452c6 638EFIAPI\r
5e9e151c
JW
639HttpIoNotifyDpc (\r
640 IN VOID *Context\r
641 )\r
642{\r
643 *((BOOLEAN *) Context) = TRUE;\r
644}\r
645\r
646/**\r
647 Request HttpIoNotifyDpc as a DPC at TPL_CALLBACK.\r
648\r
649 @param[in] Event The event signaled.\r
650 @param[in] Context The opaque parameter to the function.\r
651\r
652**/\r
653VOID\r
6c6452c6 654EFIAPI\r
5e9e151c
JW
655HttpIoNotify (\r
656 IN EFI_EVENT Event,\r
657 IN VOID *Context\r
658 )\r
659{\r
660 //\r
661 // Request HttpIoNotifyDpc as a DPC at TPL_CALLBACK\r
662 //\r
663 QueueDpc (TPL_CALLBACK, HttpIoNotifyDpc, Context);\r
664}\r
665\r
d933e70a
JW
666/**\r
667 Create a HTTP_IO to access the HTTP service. It will create and configure\r
668 a HTTP child handle.\r
669\r
670 @param[in] Image The handle of the driver image.\r
671 @param[in] Controller The handle of the controller.\r
672 @param[in] IpVersion IP_VERSION_4 or IP_VERSION_6.\r
673 @param[in] ConfigData The HTTP_IO configuration data.\r
95b5c32f
FS
674 @param[in] Callback Callback function which will be invoked when specified\r
675 HTTP_IO_CALLBACK_EVENT happened.\r
676 @param[in] Context The Context data which will be passed to the Callback function.\r
d933e70a
JW
677 @param[out] HttpIo The HTTP_IO.\r
678 \r
679 @retval EFI_SUCCESS The HTTP_IO is created and configured.\r
680 @retval EFI_INVALID_PARAMETER One or more parameters are invalid.\r
681 @retval EFI_UNSUPPORTED One or more of the control options are not\r
682 supported in the implementation.\r
683 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.\r
684 @retval Others Failed to create the HTTP_IO or configure it.\r
685\r
686**/\r
687EFI_STATUS\r
688HttpIoCreateIo (\r
689 IN EFI_HANDLE Image,\r
690 IN EFI_HANDLE Controller,\r
691 IN UINT8 IpVersion,\r
692 IN HTTP_IO_CONFIG_DATA *ConfigData,\r
95b5c32f
FS
693 IN HTTP_IO_CALLBACK Callback,\r
694 IN VOID *Context,\r
d933e70a
JW
695 OUT HTTP_IO *HttpIo\r
696 )\r
697{\r
698 EFI_STATUS Status;\r
699 EFI_HTTP_CONFIG_DATA HttpConfigData;\r
700 EFI_HTTPv4_ACCESS_POINT Http4AccessPoint;\r
b659408b 701 EFI_HTTPv6_ACCESS_POINT Http6AccessPoint;\r
d933e70a
JW
702 EFI_HTTP_PROTOCOL *Http;\r
703 EFI_EVENT Event;\r
704 \r
705 if ((Image == NULL) || (Controller == NULL) || (ConfigData == NULL) || (HttpIo == NULL)) {\r
706 return EFI_INVALID_PARAMETER;\r
707 }\r
708\r
709 if (IpVersion != IP_VERSION_4 && IpVersion != IP_VERSION_6) {\r
710 return EFI_UNSUPPORTED;\r
711 }\r
712\r
713 ZeroMem (HttpIo, sizeof (HTTP_IO));\r
714 \r
715 //\r
716 // Create the HTTP child instance and get the HTTP protocol.\r
717 // \r
718 Status = NetLibCreateServiceChild (\r
719 Controller,\r
720 Image,\r
721 &gEfiHttpServiceBindingProtocolGuid,\r
722 &HttpIo->Handle\r
723 );\r
724 if (EFI_ERROR (Status)) {\r
725 return Status;\r
726 }\r
727\r
728 Status = gBS->OpenProtocol (\r
729 HttpIo->Handle,\r
730 &gEfiHttpProtocolGuid,\r
731 (VOID **) &Http,\r
732 Image,\r
733 Controller,\r
734 EFI_OPEN_PROTOCOL_BY_DRIVER\r
735 );\r
736 if (EFI_ERROR (Status) || (Http == NULL)) {\r
737 goto ON_ERROR;\r
738 }\r
739\r
740 //\r
741 // Init the configuration data and configure the HTTP child.\r
742 //\r
743 HttpIo->Image = Image;\r
744 HttpIo->Controller = Controller;\r
745 HttpIo->IpVersion = IpVersion;\r
746 HttpIo->Http = Http;\r
95b5c32f
FS
747 HttpIo->Callback = Callback;\r
748 HttpIo->Context = Context;\r
d933e70a
JW
749\r
750 ZeroMem (&HttpConfigData, sizeof (EFI_HTTP_CONFIG_DATA));\r
751 HttpConfigData.HttpVersion = HttpVersion11;\r
752 HttpConfigData.TimeOutMillisec = ConfigData->Config4.RequestTimeOut;\r
753 if (HttpIo->IpVersion == IP_VERSION_4) {\r
754 HttpConfigData.LocalAddressIsIPv6 = FALSE;\r
755 \r
756 Http4AccessPoint.UseDefaultAddress = ConfigData->Config4.UseDefaultAddress;\r
757 Http4AccessPoint.LocalPort = ConfigData->Config4.LocalPort;\r
758 IP4_COPY_ADDRESS (&Http4AccessPoint.LocalAddress, &ConfigData->Config4.LocalIp);\r
759 IP4_COPY_ADDRESS (&Http4AccessPoint.LocalSubnet, &ConfigData->Config4.SubnetMask);\r
760 HttpConfigData.AccessPoint.IPv4Node = &Http4AccessPoint; \r
761 } else {\r
b659408b
ZL
762 HttpConfigData.LocalAddressIsIPv6 = TRUE;\r
763 Http6AccessPoint.LocalPort = ConfigData->Config6.LocalPort;\r
764 IP6_COPY_ADDRESS (&Http6AccessPoint.LocalAddress, &ConfigData->Config6.LocalIp);\r
765 HttpConfigData.AccessPoint.IPv6Node = &Http6AccessPoint;\r
d933e70a
JW
766 }\r
767 \r
768 Status = Http->Configure (Http, &HttpConfigData);\r
769 if (EFI_ERROR (Status)) {\r
770 goto ON_ERROR;\r
771 }\r
772\r
773 //\r
774 // Create events for variuos asynchronous operations.\r
775 //\r
776 Status = gBS->CreateEvent (\r
777 EVT_NOTIFY_SIGNAL,\r
778 TPL_NOTIFY,\r
5e9e151c 779 HttpIoNotify,\r
d933e70a
JW
780 &HttpIo->IsTxDone,\r
781 &Event\r
782 );\r
783 if (EFI_ERROR (Status)) {\r
784 goto ON_ERROR;\r
785 }\r
786 HttpIo->ReqToken.Event = Event;\r
787 HttpIo->ReqToken.Message = &HttpIo->ReqMessage;\r
788\r
789 Status = gBS->CreateEvent (\r
790 EVT_NOTIFY_SIGNAL,\r
791 TPL_NOTIFY,\r
5e9e151c 792 HttpIoNotify,\r
d933e70a
JW
793 &HttpIo->IsRxDone,\r
794 &Event\r
795 );\r
796 if (EFI_ERROR (Status)) {\r
797 goto ON_ERROR;\r
798 }\r
799 HttpIo->RspToken.Event = Event;\r
800 HttpIo->RspToken.Message = &HttpIo->RspMessage;\r
801\r
7570696c
JW
802 //\r
803 // Create TimeoutEvent for response\r
804 //\r
805 Status = gBS->CreateEvent (\r
806 EVT_TIMER,\r
807 TPL_CALLBACK,\r
808 NULL,\r
809 NULL,\r
810 &Event\r
811 );\r
812 if (EFI_ERROR (Status)) {\r
813 goto ON_ERROR;\r
814 }\r
815 HttpIo->TimeoutEvent = Event;\r
816\r
d933e70a
JW
817 return EFI_SUCCESS;\r
818 \r
819ON_ERROR:\r
820 HttpIoDestroyIo (HttpIo);\r
821\r
822 return Status;\r
823}\r
824\r
825/**\r
826 Destroy the HTTP_IO and release the resouces. \r
827\r
828 @param[in] HttpIo The HTTP_IO which wraps the HTTP service to be destroyed.\r
829\r
830**/\r
831VOID\r
832HttpIoDestroyIo (\r
833 IN HTTP_IO *HttpIo\r
834 )\r
835{\r
836 EFI_HTTP_PROTOCOL *Http;\r
837 EFI_EVENT Event;\r
838\r
839 if (HttpIo == NULL) {\r
840 return;\r
841 }\r
842\r
843 Event = HttpIo->ReqToken.Event;\r
844 if (Event != NULL) {\r
845 gBS->CloseEvent (Event);\r
846 }\r
847\r
848 Event = HttpIo->RspToken.Event;\r
849 if (Event != NULL) {\r
850 gBS->CloseEvent (Event);\r
851 }\r
7570696c
JW
852\r
853 Event = HttpIo->TimeoutEvent;\r
854 if (Event != NULL) {\r
855 gBS->CloseEvent (Event);\r
856 }\r
d933e70a
JW
857 \r
858 Http = HttpIo->Http;\r
859 if (Http != NULL) {\r
860 Http->Configure (Http, NULL);\r
861 gBS->CloseProtocol (\r
862 HttpIo->Handle,\r
863 &gEfiHttpProtocolGuid,\r
864 HttpIo->Image,\r
865 HttpIo->Controller\r
866 );\r
867 }\r
868\r
869 NetLibDestroyServiceChild (\r
870 HttpIo->Controller,\r
871 HttpIo->Image,\r
872 &gEfiHttpServiceBindingProtocolGuid,\r
873 HttpIo->Handle\r
874 );\r
875}\r
876\r
877/**\r
878 Synchronously send a HTTP REQUEST message to the server.\r
879 \r
880 @param[in] HttpIo The HttpIo wrapping the HTTP service.\r
881 @param[in] Request A pointer to storage such data as URL and HTTP method.\r
882 @param[in] HeaderCount Number of HTTP header structures in Headers list. \r
883 @param[in] Headers Array containing list of HTTP headers.\r
884 @param[in] BodyLength Length in bytes of the HTTP body.\r
885 @param[in] Body Body associated with the HTTP request. \r
886 \r
887 @retval EFI_SUCCESS The HTTP request is trasmitted.\r
888 @retval EFI_INVALID_PARAMETER One or more parameters are invalid.\r
889 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.\r
890 @retval EFI_DEVICE_ERROR An unexpected network or system error occurred.\r
891 @retval Others Other errors as indicated.\r
892\r
893**/\r
894EFI_STATUS\r
895HttpIoSendRequest (\r
896 IN HTTP_IO *HttpIo,\r
897 IN EFI_HTTP_REQUEST_DATA *Request,\r
898 IN UINTN HeaderCount,\r
899 IN EFI_HTTP_HEADER *Headers,\r
900 IN UINTN BodyLength,\r
901 IN VOID *Body\r
902 )\r
903{\r
904 EFI_STATUS Status;\r
905 EFI_HTTP_PROTOCOL *Http;\r
906\r
907 if (HttpIo == NULL || HttpIo->Http == NULL) {\r
908 return EFI_INVALID_PARAMETER;\r
909 }\r
910\r
911 HttpIo->ReqToken.Status = EFI_NOT_READY;\r
912 HttpIo->ReqToken.Message->Data.Request = Request;\r
913 HttpIo->ReqToken.Message->HeaderCount = HeaderCount;\r
914 HttpIo->ReqToken.Message->Headers = Headers;\r
915 HttpIo->ReqToken.Message->BodyLength = BodyLength;\r
916 HttpIo->ReqToken.Message->Body = Body;\r
917\r
95b5c32f
FS
918 if (HttpIo->Callback != NULL) {\r
919 Status = HttpIo->Callback (\r
920 HttpIoRequest,\r
921 HttpIo->ReqToken.Message,\r
922 HttpIo->Context\r
923 );\r
924 if (EFI_ERROR (Status)) {\r
925 return Status;\r
926 }\r
927 }\r
928\r
d933e70a
JW
929 //\r
930 // Queue the request token to HTTP instances.\r
931 //\r
932 Http = HttpIo->Http;\r
933 HttpIo->IsTxDone = FALSE;\r
934 Status = Http->Request (\r
935 Http,\r
936 &HttpIo->ReqToken\r
937 );\r
938 if (EFI_ERROR (Status)) {\r
939 return Status;\r
940 }\r
941\r
942 //\r
943 // Poll the network until transmit finish.\r
944 //\r
945 while (!HttpIo->IsTxDone) {\r
946 Http->Poll (Http);\r
947 }\r
948\r
949 return HttpIo->ReqToken.Status;\r
950}\r
951\r
952/**\r
953 Synchronously receive a HTTP RESPONSE message from the server.\r
954 \r
955 @param[in] HttpIo The HttpIo wrapping the HTTP service.\r
956 @param[in] RecvMsgHeader TRUE to receive a new HTTP response (from message header).\r
957 FALSE to continue receive the previous response message.\r
958 @param[out] ResponseData Point to a wrapper of the received response data.\r
959 \r
ef422fc5 960 @retval EFI_SUCCESS The HTTP response is received.\r
d933e70a
JW
961 @retval EFI_INVALID_PARAMETER One or more parameters are invalid.\r
962 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.\r
963 @retval EFI_DEVICE_ERROR An unexpected network or system error occurred.\r
964 @retval Others Other errors as indicated.\r
965\r
966**/\r
967EFI_STATUS\r
968HttpIoRecvResponse (\r
969 IN HTTP_IO *HttpIo,\r
970 IN BOOLEAN RecvMsgHeader,\r
ef422fc5 971 OUT HTTP_IO_RESPONSE_DATA *ResponseData\r
d933e70a
JW
972 )\r
973{\r
974 EFI_STATUS Status;\r
975 EFI_HTTP_PROTOCOL *Http;\r
976\r
977 if (HttpIo == NULL || HttpIo->Http == NULL || ResponseData == NULL) {\r
978 return EFI_INVALID_PARAMETER;\r
979 }\r
980\r
7570696c
JW
981 //\r
982 // Start the timer, and wait Timeout seconds to receive the header packet.\r
983 //\r
984 Status = gBS->SetTimer (HttpIo->TimeoutEvent, TimerRelative, HTTP_BOOT_RESPONSE_TIMEOUT * TICKS_PER_MS);\r
985 if (EFI_ERROR (Status)) {\r
986 return Status;\r
987 }\r
988\r
d933e70a
JW
989 //\r
990 // Queue the response token to HTTP instances.\r
991 //\r
992 HttpIo->RspToken.Status = EFI_NOT_READY;\r
993 if (RecvMsgHeader) {\r
994 HttpIo->RspToken.Message->Data.Response = &ResponseData->Response;\r
995 } else {\r
996 HttpIo->RspToken.Message->Data.Response = NULL;\r
997 }\r
998 HttpIo->RspToken.Message->HeaderCount = 0;\r
999 HttpIo->RspToken.Message->Headers = NULL;\r
1000 HttpIo->RspToken.Message->BodyLength = ResponseData->BodyLength;\r
1001 HttpIo->RspToken.Message->Body = ResponseData->Body;\r
1002\r
1003 Http = HttpIo->Http;\r
1004 HttpIo->IsRxDone = FALSE;\r
1005 Status = Http->Response (\r
1006 Http,\r
1007 &HttpIo->RspToken\r
1008 );\r
1009 \r
1010 if (EFI_ERROR (Status)) {\r
7570696c 1011 gBS->SetTimer (HttpIo->TimeoutEvent, TimerCancel, 0);\r
d933e70a
JW
1012 return Status;\r
1013 }\r
1014\r
1015 //\r
62cae351 1016 // Poll the network until receive finish.\r
d933e70a 1017 //\r
7570696c 1018 while (!HttpIo->IsRxDone && ((HttpIo->TimeoutEvent == NULL) || EFI_ERROR (gBS->CheckEvent (HttpIo->TimeoutEvent)))) {\r
d933e70a
JW
1019 Http->Poll (Http);\r
1020 }\r
1021\r
7570696c
JW
1022 gBS->SetTimer (HttpIo->TimeoutEvent, TimerCancel, 0);\r
1023\r
1024 if (!HttpIo->IsRxDone) {\r
1025 //\r
1026 // Timeout occurs, cancel the response token.\r
1027 //\r
1028 Http->Cancel (Http, &HttpIo->RspToken);\r
1029 \r
1030 Status = EFI_TIMEOUT;\r
1031 \r
1032 return Status;\r
1033 } else {\r
1034 HttpIo->IsRxDone = FALSE;\r
1035 }\r
1036\r
bb4831c0
FS
1037 if ((HttpIo->Callback != NULL) && \r
1038 (HttpIo->RspToken.Status == EFI_SUCCESS || HttpIo->RspToken.Status == EFI_HTTP_ERROR)) {\r
95b5c32f
FS
1039 Status = HttpIo->Callback (\r
1040 HttpIoResponse,\r
1041 HttpIo->RspToken.Message,\r
1042 HttpIo->Context\r
1043 );\r
1044 if (EFI_ERROR (Status)) {\r
1045 return Status;\r
1046 }\r
1047 }\r
1048\r
d933e70a
JW
1049 //\r
1050 // Store the received data into the wrapper.\r
1051 //\r
072289f4
ZL
1052 ResponseData->Status = HttpIo->RspToken.Status;\r
1053 ResponseData->HeaderCount = HttpIo->RspToken.Message->HeaderCount;\r
1054 ResponseData->Headers = HttpIo->RspToken.Message->Headers;\r
1055 ResponseData->BodyLength = HttpIo->RspToken.Message->BodyLength;\r
d933e70a
JW
1056\r
1057 return Status;\r
1058}\r
fa848a40 1059\r
221463c2
JW
1060/**\r
1061 This function checks the HTTP(S) URI scheme.\r
1062\r
1063 @param[in] Uri The pointer to the URI string.\r
1064 \r
1065 @retval EFI_SUCCESS The URI scheme is valid.\r
1066 @retval EFI_INVALID_PARAMETER The URI scheme is not HTTP or HTTPS.\r
1067 @retval EFI_ACCESS_DENIED HTTP is disabled and the URI is HTTP.\r
1068\r
1069**/\r
1070EFI_STATUS\r
1071HttpBootCheckUriScheme (\r
1072 IN CHAR8 *Uri\r
1073 )\r
1074{\r
1075 UINTN Index;\r
1076 EFI_STATUS Status;\r
1077\r
1078 Status = EFI_SUCCESS;\r
1079\r
1080 //\r
1081 // Convert the scheme to all lower case.\r
1082 //\r
1083 for (Index = 0; Index < AsciiStrLen (Uri); Index++) {\r
1084 if (Uri[Index] == ':') {\r
1085 break;\r
1086 }\r
1087 if (Uri[Index] >= 'A' && Uri[Index] <= 'Z') {\r
1088 Uri[Index] -= (CHAR8)('A' - 'a');\r
1089 }\r
1090 }\r
1091\r
1092 //\r
1093 // Return EFI_INVALID_PARAMETER if the URI is not HTTP or HTTPS.\r
1094 //\r
1095 if ((AsciiStrnCmp (Uri, "http://", 7) != 0) && (AsciiStrnCmp (Uri, "https://", 8) != 0)) {\r
1096 DEBUG ((EFI_D_ERROR, "HttpBootCheckUriScheme: Invalid Uri.\n"));\r
1097 return EFI_INVALID_PARAMETER;\r
1098 }\r
1099 \r
1100 //\r
1101 // HTTP is disabled, return EFI_ACCESS_DENIED if the URI is HTTP.\r
1102 //\r
1103 if (!PcdGetBool (PcdAllowHttpConnections) && (AsciiStrnCmp (Uri, "http://", 7) == 0)) {\r
1104 DEBUG ((EFI_D_ERROR, "HttpBootCheckUriScheme: HTTP is disabled.\n"));\r
1105 return EFI_ACCESS_DENIED;\r
1106 }\r
1107\r
1108 return Status;\r
1109}\r
1110\r
fa848a40
FS
1111/**\r
1112 Get the URI address string from the input device path.\r
1113\r
1114 Caller need to free the buffer in the UriAddress pointer.\r
1115 \r
1116 @param[in] FilePath Pointer to the device path which contains a URI device path node.\r
73617fa6 1117 @param[out] UriAddress The URI address string extract from the device path.\r
fa848a40
FS
1118 \r
1119 @retval EFI_SUCCESS The URI string is returned.\r
1120 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.\r
1121\r
1122**/\r
1123EFI_STATUS\r
1124HttpBootParseFilePath (\r
1125 IN EFI_DEVICE_PATH_PROTOCOL *FilePath,\r
1126 OUT CHAR8 **UriAddress\r
1127 )\r
1128{\r
1129 EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;\r
1130 URI_DEVICE_PATH *UriDevicePath;\r
1131 CHAR8 *Uri;\r
1132 UINTN UriStrLength;\r
1133\r
1134 if (FilePath == NULL) {\r
1135 return EFI_INVALID_PARAMETER;\r
1136 }\r
1137\r
1138 *UriAddress = NULL;\r
1139\r
1140 //\r
1141 // Extract the URI address from the FilePath\r
1142 //\r
1143 TempDevicePath = FilePath;\r
1144 while (!IsDevicePathEnd (TempDevicePath)) {\r
1145 if ((DevicePathType (TempDevicePath) == MESSAGING_DEVICE_PATH) &&\r
1146 (DevicePathSubType (TempDevicePath) == MSG_URI_DP)) {\r
1147 UriDevicePath = (URI_DEVICE_PATH*) TempDevicePath;\r
1148 //\r
1149 // UEFI Spec doesn't require the URI to be a NULL-terminated string\r
1150 // So we allocate a new buffer and always append a '\0' to it.\r
1151 //\r
1152 UriStrLength = DevicePathNodeLength (UriDevicePath) - sizeof(EFI_DEVICE_PATH_PROTOCOL);\r
1153 if (UriStrLength == 0) {\r
1154 //\r
1155 // return a NULL UriAddress if it's a empty URI device path node.\r
1156 //\r
1157 break;\r
1158 }\r
1159 Uri = AllocatePool (UriStrLength + 1);\r
1160 if (Uri == NULL) {\r
1161 return EFI_OUT_OF_RESOURCES;\r
1162 }\r
1163 CopyMem (Uri, UriDevicePath->Uri, DevicePathNodeLength (UriDevicePath) - sizeof(EFI_DEVICE_PATH_PROTOCOL));\r
1164 Uri[DevicePathNodeLength (UriDevicePath) - sizeof(EFI_DEVICE_PATH_PROTOCOL)] = '\0';\r
1165\r
1166 *UriAddress = Uri;\r
1167 }\r
1168 TempDevicePath = NextDevicePathNode (TempDevicePath);\r
1169 }\r
1170\r
1171 return EFI_SUCCESS;\r
1172}\r
587d204c
FS
1173\r
1174/**\r
1175 This function returns the image type according to server replied HTTP message\r
1176 and also the image's URI info.\r
1177\r
1178 @param[in] Uri The pointer to the image's URI string.\r
1179 @param[in] UriParser URI Parse result returned by NetHttpParseUrl(). \r
1180 @param[in] HeaderCount Number of HTTP header structures in Headers list. \r
1181 @param[in] Headers Array containing list of HTTP headers.\r
1182 @param[out] ImageType The image type of the downloaded file.\r
1183 \r
1184 @retval EFI_SUCCESS The image type is returned in ImageType.\r
1185 @retval EFI_INVALID_PARAMETER ImageType, Uri or UriParser is NULL.\r
1186 @retval EFI_INVALID_PARAMETER HeaderCount is not zero, and Headers is NULL.\r
1187 @retval EFI_NOT_FOUND Failed to identify the image type.\r
1188 @retval Others Unexpect error happened.\r
1189\r
1190**/\r
1191EFI_STATUS\r
1192HttpBootCheckImageType (\r
1193 IN CHAR8 *Uri,\r
1194 IN VOID *UriParser,\r
1195 IN UINTN HeaderCount,\r
1196 IN EFI_HTTP_HEADER *Headers,\r
1197 OUT HTTP_BOOT_IMAGE_TYPE *ImageType\r
1198 )\r
1199{\r
1200 EFI_STATUS Status;\r
1201 EFI_HTTP_HEADER *Header;\r
1202 CHAR8 *FilePath;\r
1203 CHAR8 *FilePost;\r
1204\r
1205 if (Uri == NULL || UriParser == NULL || ImageType == NULL) {\r
1206 return EFI_INVALID_PARAMETER;\r
1207 }\r
1208\r
1209 if (HeaderCount != 0 && Headers == NULL) {\r
1210 return EFI_INVALID_PARAMETER;\r
1211 }\r
1212\r
1213 //\r
1214 // Determine the image type by the HTTP Content-Type header field first.\r
b173ad78
JW
1215 // "application/efi" -> EFI Image\r
1216 // "application/vnd.efi-iso" -> CD/DVD Image\r
1217 // "application/vnd.efi-img" -> Virtual Disk Image\r
587d204c
FS
1218 //\r
1219 Header = HttpFindHeader (HeaderCount, Headers, HTTP_HEADER_CONTENT_TYPE);\r
1220 if (Header != NULL) {\r
1221 if (AsciiStriCmp (Header->FieldValue, HTTP_CONTENT_TYPE_APP_EFI) == 0) {\r
1222 *ImageType = ImageTypeEfi;\r
1223 return EFI_SUCCESS;\r
b173ad78
JW
1224 } else if (AsciiStriCmp (Header->FieldValue, HTTP_CONTENT_TYPE_APP_ISO) == 0) {\r
1225 *ImageType = ImageTypeVirtualCd;\r
1226 return EFI_SUCCESS;\r
1227 } else if (AsciiStriCmp (Header->FieldValue, HTTP_CONTENT_TYPE_APP_IMG) == 0) {\r
1228 *ImageType = ImageTypeVirtualDisk;\r
1229 return EFI_SUCCESS;\r
587d204c
FS
1230 }\r
1231 }\r
1232\r
1233 //\r
1234 // Determine the image type by file extension:\r
1235 // *.efi -> EFI Image\r
1236 // *.iso -> CD/DVD Image\r
1237 // *.img -> Virtual Disk Image\r
1238 //\r
1239 Status = HttpUrlGetPath (\r
1240 Uri,\r
1241 UriParser,\r
1242 &FilePath\r
1243 );\r
1244 if (EFI_ERROR (Status)) {\r
1245 return Status;\r
1246 }\r
1247\r
1248 FilePost = FilePath + AsciiStrLen (FilePath) - 4;\r
1249 if (AsciiStrCmp (FilePost, ".efi") == 0) {\r
1250 *ImageType = ImageTypeEfi;\r
1251 } else if (AsciiStrCmp (FilePost, ".iso") == 0) {\r
1252 *ImageType = ImageTypeVirtualCd;\r
1253 } else if (AsciiStrCmp (FilePost, ".img") == 0) {\r
1254 *ImageType = ImageTypeVirtualDisk;\r
1255 } else {\r
1256 *ImageType = ImageTypeMax;\r
1257 }\r
1258\r
1259 FreePool (FilePath);\r
1260\r
1261 return (*ImageType < ImageTypeMax) ? EFI_SUCCESS : EFI_NOT_FOUND;\r
1262}\r
1263\r
1264/**\r
1265 This function register the RAM disk info to the system.\r
1266 \r
1267 @param[in] Private The pointer to the driver's private data.\r
1268 @param[in] BufferSize The size of Buffer in bytes.\r
1269 @param[in] Buffer The base address of the RAM disk.\r
1270 @param[in] ImageType The image type of the file in Buffer.\r
1271\r
1272 @retval EFI_SUCCESS The RAM disk has been registered.\r
1273 @retval EFI_NOT_FOUND No RAM disk protocol instances were found.\r
1274 @retval EFI_UNSUPPORTED The ImageType is not supported.\r
1275 @retval Others Unexpected error happened.\r
1276\r
1277**/\r
1278EFI_STATUS\r
1279HttpBootRegisterRamDisk (\r
1280 IN HTTP_BOOT_PRIVATE_DATA *Private,\r
1281 IN UINTN BufferSize,\r
1282 IN VOID *Buffer,\r
1283 IN HTTP_BOOT_IMAGE_TYPE ImageType\r
1284 )\r
1285{\r
1286 EFI_RAM_DISK_PROTOCOL *RamDisk;\r
1287 EFI_STATUS Status;\r
1288 EFI_DEVICE_PATH_PROTOCOL *DevicePath;\r
1289 EFI_GUID *RamDiskType;\r
1290 \r
1291 ASSERT (Private != NULL);\r
1292 ASSERT (Buffer != NULL);\r
1293 ASSERT (BufferSize != 0);\r
1294\r
1295 Status = gBS->LocateProtocol (&gEfiRamDiskProtocolGuid, NULL, (VOID**) &RamDisk);\r
1296 if (EFI_ERROR (Status)) {\r
1297 DEBUG ((EFI_D_ERROR, "HTTP Boot: Couldn't find the RAM Disk protocol - %r\n", Status));\r
1298 return Status;\r
1299 }\r
1300\r
1301 if (ImageType == ImageTypeVirtualCd) {\r
1302 RamDiskType = &gEfiVirtualCdGuid;\r
1303 } else if (ImageType == ImageTypeVirtualDisk) {\r
1304 RamDiskType = &gEfiVirtualDiskGuid;\r
1305 } else {\r
1306 return EFI_UNSUPPORTED;\r
1307 }\r
1308 \r
1309 Status = RamDisk->Register (\r
1310 (UINTN)Buffer,\r
1311 (UINT64)BufferSize,\r
1312 RamDiskType,\r
1313 Private->UsingIpv6 ? Private->Ip6Nic->DevicePath : Private->Ip4Nic->DevicePath,\r
1314 &DevicePath\r
1315 );\r
1316 if (EFI_ERROR (Status)) {\r
1317 DEBUG ((EFI_D_ERROR, "HTTP Boot: Failed to register RAM Disk - %r\n", Status));\r
1318 }\r
1319\r
1320 return Status;\r
1321}\r
1322\r
bb4831c0
FS
1323/**\r
1324 Indicate if the HTTP status code indicates a redirection.\r
1325 \r
1326 @param[in] StatusCode HTTP status code from server.\r
1327\r
1328 @return TRUE if it's redirection.\r
1329\r
1330**/\r
1331BOOLEAN\r
1332HttpBootIsHttpRedirectStatusCode (\r
1333 IN EFI_HTTP_STATUS_CODE StatusCode\r
2913ebb2 1334 )\r
bb4831c0
FS
1335{\r
1336 if (StatusCode == HTTP_STATUS_301_MOVED_PERMANENTLY ||\r
1337 StatusCode == HTTP_STATUS_302_FOUND ||\r
1338 StatusCode == HTTP_STATUS_307_TEMPORARY_REDIRECT ||\r
1339 StatusCode == HTTP_STATUS_308_PERMANENT_REDIRECT) {\r
1340 return TRUE;\r
1341 }\r
1342\r
1343 return FALSE;\r
1344}\r