| 724 | download_output_manager.queue_file_io_task(fileobj, chunk, index) |
| 725 | |
| 726 | def _validate_content_range(self, requested_range, content_range): |
| 727 | if not requested_range or not content_range: |
| 728 | return |
| 729 | # Unparsed `ContentRange` looks like `bytes 0-8388607/39542919`, |
| 730 | # where `0-8388607` is the fetched range and `39542919` is |
| 731 | # the total object size. |
| 732 | response_range, total_size = content_range.split('/') |
| 733 | # Subtract `1` because range is 0-indexed. |
| 734 | final_byte = str(int(total_size) - 1) |
| 735 | # If it's the last part, the requested range will not include |
| 736 | # the final byte, eg `bytes=33554432-`. |
| 737 | if requested_range.endswith('-'): |
| 738 | requested_range += final_byte |
| 739 | # Request looks like `bytes=0-8388607`. |
| 740 | # Parsed response looks like `bytes 0-8388607`. |
| 741 | if requested_range[6:] != response_range[6:]: |
| 742 | raise S3ValidationError( |
| 743 | f"Requested range: `{requested_range[6:]}` does not match " |
| 744 | f"content range in response: `{response_range[6:]}`" |
| 745 | ) |
| 746 | |
| 747 | |
| 748 | class ImmediatelyWriteIOGetObjectTask(GetObjectTask): |