Changeset 108794 in vbox for trunk/src/VBox/Devices/EFI/FirmwareNew/NetworkPkg/HttpBootDxe/HttpBootClient.c
- Timestamp:
- Mar 31, 2025 11:31:09 AM (2 weeks ago)
- svn:sync-xref-src-repo-rev:
- 168237
- Location:
- trunk/src/VBox/Devices/EFI/FirmwareNew
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Devices/EFI/FirmwareNew
-
Property svn:mergeinfo
changed from (toggle deleted branches)
to (toggle deleted branches)/vendor/edk2/current 103735-103757,103769-103776,129194-164365 /vendor/edk2/current 103735-103757,103769-103776,129194-168232
-
Property svn:mergeinfo
changed from (toggle deleted branches)
-
trunk/src/VBox/Devices/EFI/FirmwareNew/NetworkPkg/HttpBootDxe/HttpBootClient.c
r99404 r108794 924 924 the request. 925 925 @retval EFI_ACCESS_DENIED The server needs to authenticate the client. 926 @retval EFI_NOT_READY Data transfer has timed-out, call HttpBootGetBootFile again to resume 927 the download operation using HTTP Range headers. 928 @retval EFI_UNSUPPORTED Some HTTP response header is not supported. 926 929 @retval Others Unexpected error happened. 927 930 … … 956 959 EFI_HTTP_HEADER *HttpHeader; 957 960 CHAR8 *Data; 961 UINTN HeadersCount; 962 BOOLEAN ResumingOperation; 963 CHAR8 *ContentRangeResponseValue; 964 CHAR8 RangeValue[64]; 958 965 959 966 ASSERT (Private != NULL); … … 986 993 } 987 994 995 // Check if this is a previous download that has failed and need to be resumed 996 if ((!HeaderOnly) && 997 (Private->PartialTransferredSize > 0) && 998 (Private->BootFileSize == *BufferSize)) 999 { 1000 ResumingOperation = TRUE; 1001 } else { 1002 ResumingOperation = FALSE; 1003 } 1004 988 1005 // 989 1006 // Not found in cache, try to download it through HTTP. … … 1015 1032 // User-Agent 1016 1033 // [Authorization] 1017 // 1018 HttpIoHeader = HttpIoCreateHeader ((Private->AuthData != NULL) ? 4 : 3); 1034 // [Range] 1035 // [If-Match]|[If-Unmodified-Since] 1036 // 1037 HeadersCount = 3; 1038 if (Private->AuthData != NULL) { 1039 HeadersCount++; 1040 } 1041 1042 if (ResumingOperation) { 1043 HeadersCount++; 1044 if (Private->LastModifiedOrEtag) { 1045 HeadersCount++; 1046 } 1047 } 1048 1049 HttpIoHeader = HttpIoCreateHeader (HeadersCount); 1050 1019 1051 if (HttpIoHeader == NULL) { 1020 1052 Status = EFI_OUT_OF_RESOURCES; … … 1095 1127 if (EFI_ERROR (Status)) { 1096 1128 goto ERROR_3; 1129 } 1130 } 1131 1132 // 1133 // Add HTTP header field 5 (optional): Range 1134 // 1135 if (ResumingOperation) { 1136 // Resuming a failed download. Prepare the HTTP Range Header 1137 Status = AsciiSPrint ( 1138 RangeValue, 1139 sizeof (RangeValue), 1140 "bytes=%lu-%lu", 1141 Private->PartialTransferredSize, 1142 Private->BootFileSize - 1 1143 ); 1144 if (EFI_ERROR (Status)) { 1145 goto ERROR_3; 1146 } 1147 1148 Status = HttpIoSetHeader (HttpIoHeader, "Range", RangeValue); 1149 if (EFI_ERROR (Status)) { 1150 goto ERROR_3; 1151 } 1152 1153 DEBUG ( 1154 (DEBUG_WARN | DEBUG_INFO, 1155 "HttpBootGetBootFile: Resuming failed download. Range: %a\n", 1156 RangeValue) 1157 ); 1158 1159 // 1160 // Add HTTP header field 6 (optional): If-Match or If-Unmodified-Since 1161 // 1162 if (Private->LastModifiedOrEtag) { 1163 if (Private->LastModifiedOrEtag[0] == '"') { 1164 // An ETag value starts with " 1165 DEBUG ( 1166 (DEBUG_WARN | DEBUG_INFO, 1167 "HttpBootGetBootFile: If-Match=%a\n", 1168 Private->LastModifiedOrEtag) 1169 ); 1170 // Add If-Match header with the ETag value got from the first request. 1171 Status = HttpIoSetHeader (HttpIoHeader, HTTP_HEADER_IF_MATCH, Private->LastModifiedOrEtag); 1172 } else { 1173 DEBUG ( 1174 (DEBUG_WARN | DEBUG_INFO, 1175 "HttpBootGetBootFile: If-Unmodified-Since=%a\n", 1176 Private->LastModifiedOrEtag) 1177 ); 1178 // Add If-Unmodified-Since header with the timestamp value (Last-Modified) got from the first request. 1179 Status = HttpIoSetHeader (HttpIoHeader, HTTP_HEADER_IF_UNMODIFIED_SINCE, Private->LastModifiedOrEtag); 1180 } 1181 1182 if (EFI_ERROR (Status)) { 1183 goto ERROR_3; 1184 } 1097 1185 } 1098 1186 } … … 1246 1334 } 1247 1335 1336 // Cache ETag or Last-Modified response header value to 1337 // be used when resuming an interrupted download. 1338 HttpHeader = HttpFindHeader ( 1339 ResponseData->HeaderCount, 1340 ResponseData->Headers, 1341 HTTP_HEADER_ETAG 1342 ); 1343 if (HttpHeader == NULL) { 1344 HttpHeader = HttpFindHeader ( 1345 ResponseData->HeaderCount, 1346 ResponseData->Headers, 1347 HTTP_HEADER_LAST_MODIFIED 1348 ); 1349 } 1350 1351 if (HttpHeader) { 1352 if (Private->LastModifiedOrEtag) { 1353 FreePool (Private->LastModifiedOrEtag); 1354 } 1355 1356 Private->LastModifiedOrEtag = AllocateCopyPool (AsciiStrSize (HttpHeader->FieldValue), HttpHeader->FieldValue); 1357 } 1358 1359 // 1360 // 3.2.2 Validate the range response. If operation is being resumed, 1361 // server must respond with Content-Range. 1362 // 1363 if (ResumingOperation) { 1364 HttpHeader = HttpFindHeader ( 1365 ResponseData->HeaderCount, 1366 ResponseData->Headers, 1367 HTTP_HEADER_CONTENT_RANGE 1368 ); 1369 if ((HttpHeader == NULL) || 1370 (AsciiStrnCmp (HttpHeader->FieldValue, "bytes", 5) != 0)) 1371 { 1372 Status = EFI_UNSUPPORTED; 1373 goto ERROR_5; 1374 } 1375 1376 // Gets the total size of ranged data (Content-Range: <unit> <range-start>-<range-end>/<size>) 1377 // and check if it remains the same 1378 ContentRangeResponseValue = AsciiStrStr (HttpHeader->FieldValue, "/"); 1379 if (ContentRangeResponseValue == NULL) { 1380 Status = EFI_INVALID_PARAMETER; 1381 goto ERROR_5; 1382 } 1383 1384 ContentRangeResponseValue++; 1385 ContentLength = AsciiStrDecimalToUintn (ContentRangeResponseValue); 1386 if (ContentLength != *BufferSize) { 1387 Status = EFI_INVALID_PARAMETER; 1388 goto ERROR_5; 1389 } 1390 } 1391 1248 1392 // 1249 1393 // 3.3 Init a message-body parser from the header information. … … 1296 1440 // just download the message body to the user provided buffer directly. 1297 1441 // 1442 if (ResumingOperation && ((ContentLength + Private->PartialTransferredSize) > *BufferSize)) { 1443 Status = EFI_INVALID_PARAMETER; 1444 goto ERROR_6; 1445 } 1446 1298 1447 ReceivedSize = 0; 1299 1448 while (ReceivedSize < ContentLength) { 1300 ResponseBody.Body = (CHAR8 *)Buffer + ReceivedSize;1301 ResponseBody.BodyLength = *BufferSize - ReceivedSize;1449 ResponseBody.Body = (CHAR8 *)Buffer + (ReceivedSize + Private->PartialTransferredSize); 1450 ResponseBody.BodyLength = *BufferSize - (ReceivedSize + Private->PartialTransferredSize); 1302 1451 Status = HttpIoRecvResponse ( 1303 1452 &Private->HttpIo, … … 1308 1457 if (EFI_ERROR (ResponseBody.Status)) { 1309 1458 Status = ResponseBody.Status; 1459 } 1460 1461 if ((Status == EFI_TIMEOUT) || (Status == EFI_DEVICE_ERROR)) { 1462 // For EFI_TIMEOUT and EFI_DEVICE_ERROR errors, we may resume the operation. 1463 // We will not check if server sent Accept-Ranges header, because some back-ends 1464 // do not report this header, even when supporting it. Know example: CloudFlare CDN Cache. 1465 Private->PartialTransferredSize = ReceivedSize; 1466 DEBUG ( 1467 ( 1468 DEBUG_WARN | DEBUG_INFO, 1469 "HttpBootGetBootFile: Transfer error. Bytes transferred so far: %lu.\n", 1470 ReceivedSize 1471 ) 1472 ); 1310 1473 } 1311 1474 … … 1327 1490 } 1328 1491 } 1492 1493 // download completed, there is no more partial data 1494 Private->PartialTransferredSize = 0; 1329 1495 } else { 1330 1496 // … … 1386 1552 // 3.5 Message-body receive & parse is completed, we should be able to get the file size now. 1387 1553 // 1388 Status = HttpGetEntityLength (Parser, &ContentLength); 1389 if (EFI_ERROR (Status)) { 1390 goto ERROR_6; 1554 if (!ResumingOperation) { 1555 Status = HttpGetEntityLength (Parser, &ContentLength); 1556 if (EFI_ERROR (Status)) { 1557 goto ERROR_6; 1558 } 1559 } else { 1560 ContentLength = Private->BootFileSize; 1391 1561 } 1392 1562
Note:
See TracChangeset
for help on using the changeset viewer.