Node->Ipv4.StaticIpAddress = FALSE;\r
CopyMem (&Node->Ipv4.GatewayIpAddress, &Private->GatewayIp, sizeof (EFI_IPv4_ADDRESS));\r
CopyMem (&Node->Ipv4.SubnetMask, &Private->SubnetMask, sizeof (EFI_IPv4_ADDRESS));\r
- \r
- TmpDevicePath = AppendDevicePathNode (Private->ParentDevicePath, (EFI_DEVICE_PATH_PROTOCOL*) Node);\r
- FreePool (Node);\r
- if (TmpDevicePath == NULL) {\r
+ } else {\r
+ Node = AllocateZeroPool (sizeof (IPv6_DEVICE_PATH));\r
+ if (Node == NULL) {\r
return EFI_OUT_OF_RESOURCES;\r
}\r
- } else {\r
- ASSERT (FALSE);\r
+ Node->Ipv6.Header.Type = MESSAGING_DEVICE_PATH;\r
+ Node->Ipv6.Header.SubType = MSG_IPv6_DP;\r
+ SetDevicePathNodeLength (Node, sizeof (IPv6_DEVICE_PATH));\r
+ Node->Ipv6.PrefixLength = IP6_PREFIX_LENGTH;\r
+ Node->Ipv6.RemotePort = Private->Port;\r
+ Node->Ipv6.Protocol = EFI_IP_PROTO_TCP; \r
+ Node->Ipv6.IpAddressOrigin = 0;\r
+ CopyMem (&Node->Ipv6.LocalIpAddress, &Private->StationIp.v6, sizeof (EFI_IPv6_ADDRESS));\r
+ CopyMem (&Node->Ipv6.RemoteIpAddress, &Private->ServerIp.v6, sizeof (EFI_IPv6_ADDRESS));\r
+ CopyMem (&Node->Ipv6.GatewayIpAddress, &Private->GatewayIp.v6, sizeof (EFI_IPv6_ADDRESS));\r
+ }\r
+ \r
+ TmpDevicePath = AppendDevicePathNode (Private->ParentDevicePath, (EFI_DEVICE_PATH_PROTOCOL*) Node);\r
+ FreePool (Node);\r
+ if (TmpDevicePath == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
}\r
\r
//\r
return EFI_OUT_OF_RESOURCES;\r
}\r
\r
- //\r
- // Reinstall the device path protocol of the child handle.\r
- //\r
- Status = gBS->ReinstallProtocolInterface (\r
- Private->ChildHandle,\r
- &gEfiDevicePathProtocolGuid,\r
- Private->DevicePath,\r
- NewDevicePath\r
- );\r
- if (EFI_ERROR (Status)) {\r
- return Status;\r
+ if (!Private->UsingIpv6) {\r
+ //\r
+ // Reinstall the device path protocol of the child handle.\r
+ //\r
+ Status = gBS->ReinstallProtocolInterface (\r
+ Private->Ip4Nic->Controller,\r
+ &gEfiDevicePathProtocolGuid,\r
+ Private->Ip4Nic->DevicePath,\r
+ NewDevicePath\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ \r
+ FreePool (Private->Ip4Nic->DevicePath);\r
+ Private->Ip4Nic->DevicePath = NewDevicePath;\r
+ } else {\r
+ //\r
+ // Reinstall the device path protocol of the child handle.\r
+ //\r
+ Status = gBS->ReinstallProtocolInterface (\r
+ Private->Ip6Nic->Controller,\r
+ &gEfiDevicePathProtocolGuid,\r
+ Private->Ip6Nic->DevicePath,\r
+ NewDevicePath\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ FreePool (Private->Ip6Nic->DevicePath);\r
+ Private->Ip6Nic->DevicePath = NewDevicePath;\r
}\r
\r
- FreePool (Private->DevicePath);\r
- Private->DevicePath = NewDevicePath;\r
return EFI_SUCCESS;\r
}\r
\r
\r
**/\r
EFI_STATUS\r
-HttpBootExtractUriInfo (\r
+HttpBootDhcp4ExtractUriInfo (\r
IN HTTP_BOOT_PRIVATE_DATA *Private\r
)\r
{\r
return Status;\r
}\r
\r
+/**\r
+ Parse the boot file URI information from the selected Dhcp6 offer packet.\r
+\r
+ @param[in] Private The pointer to the driver's private data.\r
+\r
+ @retval EFI_SUCCESS Successfully parsed out all the boot information.\r
+ @retval Others Failed to parse out the boot information.\r
+\r
+**/\r
+EFI_STATUS\r
+HttpBootDhcp6ExtractUriInfo (\r
+ IN HTTP_BOOT_PRIVATE_DATA *Private\r
+ )\r
+{\r
+ HTTP_BOOT_DHCP6_PACKET_CACHE *SelectOffer;\r
+ HTTP_BOOT_DHCP6_PACKET_CACHE *HttpOffer;\r
+ UINT32 SelectIndex;\r
+ UINT32 ProxyIndex;\r
+ EFI_DHCP6_PACKET_OPTION *Option;\r
+ EFI_IPv6_ADDRESS IpAddr;\r
+ CHAR8 *HostName;\r
+ CHAR16 *HostNameStr;\r
+ EFI_STATUS Status;\r
+\r
+ ASSERT (Private != NULL);\r
+ ASSERT (Private->SelectIndex != 0);\r
+ SelectIndex = Private->SelectIndex - 1;\r
+ ASSERT (SelectIndex < HTTP_BOOT_OFFER_MAX_NUM);\r
+\r
+ Status = EFI_SUCCESS;\r
+ HostName = NULL;\r
+ //\r
+ // SelectOffer contains the IP address configuration and name server configuration.\r
+ // HttpOffer contains the boot file URL.\r
+ //\r
+ SelectOffer = &Private->OfferBuffer[SelectIndex].Dhcp6;\r
+ if ((SelectOffer->OfferType == HttpOfferTypeDhcpIpUri) || (SelectOffer->OfferType == HttpOfferTypeDhcpNameUriDns)) {\r
+ HttpOffer = SelectOffer;\r
+ } else {\r
+ ASSERT (Private->SelectProxyType != HttpOfferTypeMax);\r
+ ProxyIndex = Private->OfferIndex[Private->SelectProxyType][0];\r
+ HttpOffer = &Private->OfferBuffer[ProxyIndex].Dhcp6;\r
+ }\r
+\r
+ //\r
+ // Set the Local station address to IP layer.\r
+ //\r
+ Status = HttpBootSetIp6Address (Private);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ \r
+ //\r
+ // Configure the default DNS server if server assigned.\r
+ //\r
+ if ((SelectOffer->OfferType == HttpOfferTypeDhcpNameUriDns) || (SelectOffer->OfferType == HttpOfferTypeDhcpDns)) {\r
+ Option = SelectOffer->OptList[HTTP_BOOT_DHCP6_IDX_DNS_SERVER];\r
+ ASSERT (Option != NULL);\r
+ Status = HttpBootSetIp6Dns (\r
+ Private,\r
+ HTONS (Option->OpLen),\r
+ Option->Data\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ }\r
+ \r
+ //\r
+ // Extract the HTTP server Ip frome URL. This is used to Check route table \r
+ // whether can send message to HTTP Server Ip through the GateWay.\r
+ //\r
+ Status = HttpUrlGetIp6 (\r
+ (CHAR8*) HttpOffer->OptList[HTTP_BOOT_DHCP6_IDX_BOOT_FILE_URL]->Data,\r
+ HttpOffer->UriParser,\r
+ &IpAddr\r
+ );\r
+ \r
+ if (EFI_ERROR (Status)) {\r
+ //\r
+ // The Http server address is expressed by Name Ip, so perform DNS resolution\r
+ //\r
+ Status = HttpUrlGetHostName (\r
+ (CHAR8*) HttpOffer->OptList[HTTP_BOOT_DHCP6_IDX_BOOT_FILE_URL]->Data,\r
+ HttpOffer->UriParser,\r
+ &HostName\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ \r
+ HostNameStr = AllocateZeroPool ((AsciiStrLen (HostName) + 1) * sizeof (CHAR16));\r
+ if (HostNameStr == NULL) {\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ goto Error;\r
+ }\r
+ \r
+ AsciiStrToUnicodeStr (HostName, HostNameStr);\r
+ Status = HttpBootDns (Private, HostNameStr, &IpAddr);\r
+ FreePool (HostNameStr);\r
+ if (EFI_ERROR (Status)) {\r
+ goto Error;\r
+ } \r
+ } \r
+ \r
+ CopyMem (&Private->ServerIp.v6, &IpAddr, sizeof (EFI_IPv6_ADDRESS)); \r
+ \r
+ //\r
+ // register the IPv6 gateway address to the network device.\r
+ //\r
+ Status = HttpBootSetIp6Gateway (Private);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ \r
+ //\r
+ // Extract the port from URL, and use default HTTP port 80 if not provided.\r
+ //\r
+ Status = HttpUrlGetPort (\r
+ (CHAR8*) HttpOffer->OptList[HTTP_BOOT_DHCP6_IDX_BOOT_FILE_URL]->Data,\r
+ HttpOffer->UriParser,\r
+ &Private->Port\r
+ );\r
+ if (EFI_ERROR (Status) || Private->Port == 0) {\r
+ Private->Port = 80;\r
+ }\r
+ \r
+ //\r
+ // Record the URI of boot file from the selected HTTP offer.\r
+ //\r
+ Private->BootFileUriParser = HttpOffer->UriParser;\r
+ Private->BootFileUri = (CHAR8*) HttpOffer->OptList[HTTP_BOOT_DHCP6_IDX_BOOT_FILE_URL]->Data;\r
+\r
+ \r
+ //\r
+ // All boot informations are valid here.\r
+ //\r
+ AsciiPrint ("\n URI: %a", Private->BootFileUri);\r
+ //\r
+ // Update the device path to include the IP and boot URI information.\r
+ //\r
+ Status = HttpBootUpdateDevicePath (Private);\r
+\r
+Error:\r
+ \r
+ if (HostName != NULL) {\r
+ FreePool (HostName);\r
+ }\r
+ \r
+ return Status;\r
+}\r
+\r
+\r
/**\r
Discover all the boot information for boot file.\r
\r
}\r
\r
if (!Private->UsingIpv6) {\r
- Status = HttpBootExtractUriInfo (Private);\r
+ Status = HttpBootDhcp4ExtractUriInfo (Private);\r
} else {\r
- ASSERT (FALSE);\r
+ Status = HttpBootDhcp6ExtractUriInfo (Private);\r
}\r
\r
return Status;\r
\r
ZeroMem (&ConfigData, sizeof (HTTP_IO_CONFIG_DATA));\r
if (!Private->UsingIpv6) {\r
- ConfigData.Config4.HttpVersion = HttpVersion11;\r
+ ConfigData.Config4.HttpVersion = HttpVersion11;\r
ConfigData.Config4.RequestTimeOut = HTTP_BOOT_REQUEST_TIMEOUT;\r
IP4_COPY_ADDRESS (&ConfigData.Config4.LocalIp, &Private->StationIp.v4);\r
IP4_COPY_ADDRESS (&ConfigData.Config4.SubnetMask, &Private->SubnetMask.v4);\r
} else {\r
- ASSERT (FALSE);\r
+ ConfigData.Config6.HttpVersion = HttpVersion11;\r
+ ConfigData.Config6.RequestTimeOut = HTTP_BOOT_REQUEST_TIMEOUT;\r
+ IP6_COPY_ADDRESS (&ConfigData.Config6.LocalIp, &Private->StationIp.v6);\r
}\r
\r
Status = HttpIoCreateIo (\r
return EFI_SUCCESS;\r
}\r
\r
-/**\r
- Get the file content from cached data.\r
-\r
- @param[in] Private The pointer to the driver's private data.\r
- @param[in] Uri Uri of the file to be retrieved from cache.\r
- @param[in, out] BufferSize On input the size of Buffer in bytes. On output with a return\r
- code of EFI_SUCCESS, the amount of data transferred to\r
- Buffer. On output with a return code of EFI_BUFFER_TOO_SMALL,\r
- the size of Buffer required to retrieve the requested file.\r
- @param[out] Buffer The memory buffer to transfer the file to. IF Buffer is NULL,\r
- then the size of the requested file is returned in\r
- BufferSize.\r
-\r
- @retval EFI_SUCCESS Successfully created.\r
- @retval Others Failed to create HttpIo.\r
-\r
-**/\r
-EFI_STATUS\r
-HttpBootGetFileFromCache (\r
- IN HTTP_BOOT_PRIVATE_DATA *Private,\r
- IN CHAR16 *Uri,\r
- IN OUT UINTN *BufferSize,\r
- OUT UINT8 *Buffer\r
- )\r
-{\r
- LIST_ENTRY *Entry;\r
- LIST_ENTRY *Entry2;\r
- HTTP_BOOT_CACHE_CONTENT *Cache;\r
- HTTP_BOOT_ENTITY_DATA *EntityData;\r
- UINTN CopyedSize;\r
- \r
- if (Uri == NULL || BufferSize == 0 || Buffer == NULL) {\r
- return EFI_INVALID_PARAMETER;\r
- }\r
-\r
- NET_LIST_FOR_EACH (Entry, &Private->CacheList) {\r
- Cache = NET_LIST_USER_STRUCT (Entry, HTTP_BOOT_CACHE_CONTENT, Link);\r
- //\r
- // Compare the URI to see whether we already have a cache for this file.\r
- //\r
- if ((Cache->RequestData != NULL) &&\r
- (Cache->RequestData->Url != NULL) &&\r
- (StrCmp (Uri, Cache->RequestData->Url) == 0)) \r
- {\r
- //\r
- // Hit cache, check buffer size.\r
- //\r
- if (*BufferSize < Cache->EntityLength) {\r
- *BufferSize = Cache->EntityLength;\r
- return EFI_BUFFER_TOO_SMALL;\r
- }\r
-\r
- //\r
- // Fill data to buffer.\r
- //\r
- CopyedSize = 0;\r
- NET_LIST_FOR_EACH (Entry2, &Cache->EntityDataList) {\r
- EntityData = NET_LIST_USER_STRUCT (Entry2, HTTP_BOOT_ENTITY_DATA, Link);\r
- if (*BufferSize > CopyedSize) {\r
- CopyMem (\r
- Buffer + CopyedSize,\r
- EntityData->DataStart,\r
- MIN (EntityData->DataLength, *BufferSize - CopyedSize)\r
- );\r
- CopyedSize += MIN (EntityData->DataLength, *BufferSize - CopyedSize);\r
- }\r
- }\r
- *BufferSize = CopyedSize;\r
- return EFI_SUCCESS;\r
- }\r
- }\r
-\r
- return EFI_NOT_FOUND;\r
-}\r
-\r
/**\r
Release all the resource of a cache item.\r
\r
}\r
}\r
\r
+/**\r
+ Get the file content from cached data.\r
+\r
+ @param[in] Private The pointer to the driver's private data.\r
+ @param[in] Uri Uri of the file to be retrieved from cache.\r
+ @param[in, out] BufferSize On input the size of Buffer in bytes. On output with a return\r
+ code of EFI_SUCCESS, the amount of data transferred to\r
+ Buffer. On output with a return code of EFI_BUFFER_TOO_SMALL,\r
+ the size of Buffer required to retrieve the requested file.\r
+ @param[out] Buffer The memory buffer to transfer the file to. IF Buffer is NULL,\r
+ then the size of the requested file is returned in\r
+ BufferSize.\r
+\r
+ @retval EFI_SUCCESS Successfully created.\r
+ @retval Others Failed to create HttpIo.\r
+\r
+**/\r
+EFI_STATUS\r
+HttpBootGetFileFromCache (\r
+ IN HTTP_BOOT_PRIVATE_DATA *Private,\r
+ IN CHAR16 *Uri,\r
+ IN OUT UINTN *BufferSize,\r
+ OUT UINT8 *Buffer\r
+ )\r
+{\r
+ LIST_ENTRY *Entry;\r
+ LIST_ENTRY *Entry2;\r
+ HTTP_BOOT_CACHE_CONTENT *Cache;\r
+ HTTP_BOOT_ENTITY_DATA *EntityData;\r
+ UINTN CopyedSize;\r
+ \r
+ if (Uri == NULL || BufferSize == 0 || Buffer == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ //\r
+ // Search file in the cache list, the cache entry will be released upon a successful\r
+ // match.\r
+ //\r
+ NET_LIST_FOR_EACH (Entry, &Private->CacheList) {\r
+ Cache = NET_LIST_USER_STRUCT (Entry, HTTP_BOOT_CACHE_CONTENT, Link);\r
+ //\r
+ // Compare the URI to see whether we already have a cache for this file.\r
+ //\r
+ if ((Cache->RequestData != NULL) &&\r
+ (Cache->RequestData->Url != NULL) &&\r
+ (StrCmp (Uri, Cache->RequestData->Url) == 0)) \r
+ {\r
+ //\r
+ // Hit cache, check buffer size.\r
+ //\r
+ if (*BufferSize < Cache->EntityLength) {\r
+ *BufferSize = Cache->EntityLength;\r
+ return EFI_BUFFER_TOO_SMALL;\r
+ }\r
+\r
+ //\r
+ // Fill data to buffer.\r
+ //\r
+ CopyedSize = 0;\r
+ NET_LIST_FOR_EACH (Entry2, &Cache->EntityDataList) {\r
+ EntityData = NET_LIST_USER_STRUCT (Entry2, HTTP_BOOT_ENTITY_DATA, Link);\r
+ if (*BufferSize > CopyedSize) {\r
+ CopyMem (\r
+ Buffer + CopyedSize,\r
+ EntityData->DataStart,\r
+ MIN (EntityData->DataLength, *BufferSize - CopyedSize)\r
+ );\r
+ CopyedSize += MIN (EntityData->DataLength, *BufferSize - CopyedSize);\r
+ }\r
+ }\r
+ *BufferSize = CopyedSize;\r
+\r
+ //\r
+ // On success, free the cached data to release the memory resource.\r
+ //\r
+ RemoveEntryList (&Cache->Link);\r
+ HttpBootFreeCache (Cache);\r
+ return EFI_SUCCESS;\r
+ }\r
+ }\r
+\r
+ return EFI_NOT_FOUND;\r
+}\r
+\r
/**\r
A callback function to intercept events during message parser.\r
\r
EFI_STATUS Status;\r
CHAR8 *HostName;\r
EFI_HTTP_REQUEST_DATA *RequestData;\r
- HTTP_IO_RESOPNSE_DATA *ResponseData;\r
- HTTP_IO_RESOPNSE_DATA ResponseBody;\r
+ HTTP_IO_RESPONSE_DATA *ResponseData;\r
+ HTTP_IO_RESPONSE_DATA ResponseBody;\r
HTTP_IO *HttpIo;\r
HTTP_IO_HEADER *HttpIoHeader;\r
VOID *Parser;\r
HTTP_BOOT_CACHE_CONTENT *Cache;\r
UINT8 *Block;\r
CHAR16 *Url;\r
+ BOOLEAN IdentityMode;\r
+ UINTN ReceivedSize;\r
\r
ASSERT (Private != NULL);\r
ASSERT (Private->HttpCreated);\r
//\r
// 3.1 First step, use zero BodyLength to only receive the response headers.\r
//\r
- ResponseData = AllocateZeroPool (sizeof(HTTP_IO_RESOPNSE_DATA));\r
+ ResponseData = AllocateZeroPool (sizeof(HTTP_IO_RESPONSE_DATA));\r
if (ResponseData == NULL) {\r
Status = EFI_OUT_OF_RESOURCES;\r
goto ERROR_4;\r
//\r
Block = NULL;\r
if (!HeaderOnly) {\r
- ZeroMem (&ResponseBody, sizeof (HTTP_IO_RESOPNSE_DATA));\r
- while (!HttpIsMessageComplete (Parser)) {\r
+ //\r
+ // 3.4.1, check whether we are in identity transfer-coding.\r
+ //\r
+ ContentLength = 0;\r
+ Status = HttpGetEntityLength (Parser, &ContentLength);\r
+ if (!EFI_ERROR (Status)) {\r
+ IdentityMode = TRUE;\r
+ } else {\r
+ IdentityMode = FALSE;\r
+ }\r
+\r
+ //\r
+ // 3.4.2, start the message-body download, the identity and chunked transfer-coding\r
+ // is handled in different path here.\r
+ //\r
+ ZeroMem (&ResponseBody, sizeof (HTTP_IO_RESPONSE_DATA));\r
+ if (IdentityMode) {\r
//\r
- // Allocate a block to hold the message-body, if caller doesn't provide\r
- // a buffer, the block will be cached and we will allocate a new one here.\r
+ // In identity transfer-coding there is no need to parse the message body,\r
+ // just download the message body to the user provided buffer directly.\r
//\r
- if (Block == NULL || Context.BufferSize == 0) {\r
- Block = AllocatePool (HTTP_BOOT_BLOCK_SIZE);\r
- if (Block == NULL) {\r
- Status = EFI_OUT_OF_RESOURCES;\r
+ ReceivedSize = 0;\r
+ while (ReceivedSize < ContentLength) {\r
+ ResponseBody.Body = (CHAR8*) Buffer + ReceivedSize;\r
+ ResponseBody.BodyLength = *BufferSize - ReceivedSize;\r
+ Status = HttpIoRecvResponse (\r
+ &Private->HttpIo,\r
+ FALSE,\r
+ &ResponseBody\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
goto ERROR_6;\r
}\r
- Context.NewBlock = TRUE;\r
- Context.Block = Block;\r
- } else {\r
- Context.NewBlock = FALSE;\r
+ ReceivedSize += ResponseBody.BodyLength;\r
}\r
-\r
- ResponseBody.Body = (CHAR8*) Block;\r
- ResponseBody.BodyLength = HTTP_BOOT_BLOCK_SIZE;\r
- Status = HttpIoRecvResponse (\r
- &Private->HttpIo,\r
- FALSE,\r
- &ResponseBody\r
- );\r
- if (EFI_ERROR (Status)) {\r
- goto ERROR_6;\r
- }\r
-\r
+ } else {\r
//\r
- // Parse the new received block of the message-body, the block will be saved in cache.\r
+ // In "chunked" transfer-coding mode, so we need to parse the received\r
+ // data to get the real entity content.\r
//\r
- Status = HttpParseMessageBody (\r
- Parser,\r
- ResponseBody.BodyLength,\r
- ResponseBody.Body\r
- );\r
- if (EFI_ERROR (Status)) {\r
- goto ERROR_6;\r
+ Block = NULL;\r
+ while (!HttpIsMessageComplete (Parser)) {\r
+ //\r
+ // Allocate a buffer in Block to hold the message-body.\r
+ // If caller provides a buffer, this Block will be reused in every HttpIoRecvResponse().\r
+ // Otherwise a buffer, the buffer in Block will be cached and we should allocate a new before\r
+ // every HttpIoRecvResponse().\r
+ //\r
+ if (Block == NULL || Context.BufferSize == 0) {\r
+ Block = AllocatePool (HTTP_BOOT_BLOCK_SIZE);\r
+ if (Block == NULL) {\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ goto ERROR_6;\r
+ }\r
+ Context.NewBlock = TRUE;\r
+ Context.Block = Block;\r
+ } else {\r
+ Context.NewBlock = FALSE;\r
+ }\r
+\r
+ ResponseBody.Body = (CHAR8*) Block;\r
+ ResponseBody.BodyLength = HTTP_BOOT_BLOCK_SIZE;\r
+ Status = HttpIoRecvResponse (\r
+ &Private->HttpIo,\r
+ FALSE,\r
+ &ResponseBody\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ goto ERROR_6;\r
+ }\r
+\r
+ //\r
+ // Parse the new received block of the message-body, the block will be saved in cache.\r
+ //\r
+ Status = HttpParseMessageBody (\r
+ Parser,\r
+ ResponseBody.BodyLength,\r
+ ResponseBody.Body\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ goto ERROR_6;\r
+ }\r
}\r
}\r
}\r
- \r
+\r
//\r
- // 3.5 Message-body receive & parse is completed, get the file size.\r
+ // 3.5 Message-body receive & parse is completed, we should be able to get the file size now.\r
//\r
Status = HttpGetEntityLength (Parser, &ContentLength);\r
if (EFI_ERROR (Status)) {\r