Skip to content

Commit 3876553

Browse files
authored
Revert "Warn on unexpected ZIP compression methods" (#17944)
Reverts #17885
1 parent 5c74d31 commit 3876553

File tree

15 files changed

+43
-180
lines changed

15 files changed

+43
-180
lines changed

Cargo.lock

Lines changed: 0 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/uv-bin-install/src/lib.rs

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -339,14 +339,9 @@ async fn download_and_unpack(
339339

340340
let id = reporter.on_download_start(binary.name(), version, size);
341341
let mut progress_reader = ProgressReader::new(reader, id, reporter);
342-
stream::archive(
343-
DisplaySafeUrl::from_url(download_url.clone()),
344-
&mut progress_reader,
345-
format.into(),
346-
temp_dir.path(),
347-
)
348-
.await
349-
.map_err(|e| Error::Extract { source: e })?;
342+
stream::archive(&mut progress_reader, format.into(), temp_dir.path())
343+
.await
344+
.map_err(|e| Error::Extract { source: e })?;
350345
reporter.on_download_complete(id);
351346

352347
// Find the binary in the extracted files

crates/uv-dev/src/validate_zip.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ pub(crate) async fn validate_zip(
4747

4848
let target = tempfile::TempDir::new()?;
4949

50-
uv_extract::stream::unzip(args.url.to_url(), reader.compat(), target.path()).await?;
50+
uv_extract::stream::unzip(reader.compat(), target.path()).await?;
5151

5252
Ok(())
5353
}

crates/uv-distribution/src/distribution_database.rs

Lines changed: 10 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -608,7 +608,6 @@ impl<'a, Context: BuildContext> DistributionDatabase<'a, Context> {
608608

609609
let download = |response: reqwest::Response| {
610610
async {
611-
let url = response.url().clone();
612611
let size = size.or_else(|| content_length(&response));
613612

614613
let progress = self
@@ -635,13 +634,9 @@ impl<'a, Context: BuildContext> DistributionDatabase<'a, Context> {
635634
let mut reader = ProgressReader::new(&mut hasher, progress, &**reporter);
636635
match extension {
637636
WheelExtension::Whl => {
638-
uv_extract::stream::unzip(
639-
DisplaySafeUrl::from(url),
640-
&mut reader,
641-
temp_dir.path(),
642-
)
643-
.await
644-
.map_err(|err| Error::Extract(filename.to_string(), err))?;
637+
uv_extract::stream::unzip(&mut reader, temp_dir.path())
638+
.await
639+
.map_err(|err| Error::Extract(filename.to_string(), err))?;
645640
}
646641
WheelExtension::WhlZst => {
647642
uv_extract::stream::untar_zst(&mut reader, temp_dir.path())
@@ -652,13 +647,9 @@ impl<'a, Context: BuildContext> DistributionDatabase<'a, Context> {
652647
}
653648
None => match extension {
654649
WheelExtension::Whl => {
655-
uv_extract::stream::unzip(
656-
DisplaySafeUrl::from(url),
657-
&mut hasher,
658-
temp_dir.path(),
659-
)
660-
.await
661-
.map_err(|err| Error::Extract(filename.to_string(), err))?;
650+
uv_extract::stream::unzip(&mut hasher, temp_dir.path())
651+
.await
652+
.map_err(|err| Error::Extract(filename.to_string(), err))?;
662653
}
663654
WheelExtension::WhlZst => {
664655
uv_extract::stream::untar_zst(&mut hasher, temp_dir.path())
@@ -788,7 +779,6 @@ impl<'a, Context: BuildContext> DistributionDatabase<'a, Context> {
788779

789780
let download = |response: reqwest::Response| {
790781
async {
791-
let url = response.url().clone();
792782
let size = size.or_else(|| content_length(&response));
793783

794784
let progress = self
@@ -866,13 +856,9 @@ impl<'a, Context: BuildContext> DistributionDatabase<'a, Context> {
866856

867857
match extension {
868858
WheelExtension::Whl => {
869-
uv_extract::stream::unzip(
870-
DisplaySafeUrl::from(url),
871-
&mut hasher,
872-
temp_dir.path(),
873-
)
874-
.await
875-
.map_err(|err| Error::Extract(filename.to_string(), err))?;
859+
uv_extract::stream::unzip(&mut hasher, temp_dir.path())
860+
.await
861+
.map_err(|err| Error::Extract(filename.to_string(), err))?;
876862
}
877863
WheelExtension::WhlZst => {
878864
uv_extract::stream::untar_zst(&mut hasher, temp_dir.path())
@@ -1060,7 +1046,7 @@ impl<'a, Context: BuildContext> DistributionDatabase<'a, Context> {
10601046
// Unzip the wheel to a temporary directory.
10611047
match extension {
10621048
WheelExtension::Whl => {
1063-
uv_extract::stream::unzip(path.display(), &mut hasher, temp_dir.path())
1049+
uv_extract::stream::unzip(&mut hasher, temp_dir.path())
10641050
.await
10651051
.map_err(|err| Error::Extract(filename.to_string(), err))?;
10661052
}

crates/uv-distribution/src/source/mod.rs

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2301,9 +2301,6 @@ impl<'a, T: BuildContext> SourceDistributionBuilder<'a, T> {
23012301
.bucket(CacheBucket::SourceDistributions),
23022302
)
23032303
.map_err(Error::CacheWrite)?;
2304-
2305-
let url = DisplaySafeUrl::from_url(response.url().clone());
2306-
23072304
let reader = response
23082305
.bytes_stream()
23092306
.map_err(std::io::Error::other)
@@ -2319,7 +2316,7 @@ impl<'a, T: BuildContext> SourceDistributionBuilder<'a, T> {
23192316

23202317
// Download and unzip the source distribution into a temporary directory.
23212318
let span = info_span!("download_source_dist", source_dist = %source);
2322-
uv_extract::stream::archive(url, &mut hasher, ext, temp_dir.path())
2319+
uv_extract::stream::archive(&mut hasher, ext, temp_dir.path())
23232320
.await
23242321
.map_err(|err| Error::Extract(source.to_string(), err))?;
23252322
drop(span);
@@ -2388,7 +2385,7 @@ impl<'a, T: BuildContext> SourceDistributionBuilder<'a, T> {
23882385
let mut hasher = uv_extract::hash::HashReader::new(reader, &mut hashers);
23892386

23902387
// Unzip the archive into a temporary directory.
2391-
uv_extract::stream::archive(path.display(), &mut hasher, ext, &temp_dir.path())
2388+
uv_extract::stream::archive(&mut hasher, ext, &temp_dir.path())
23922389
.await
23932390
.map_err(|err| Error::Extract(temp_dir.path().to_string_lossy().into_owned(), err))?;
23942391

crates/uv-extract/Cargo.toml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@ uv-configuration = { workspace = true }
2020
uv-distribution-filename = { workspace = true }
2121
uv-pypi-types = { workspace = true }
2222
uv-static = { workspace = true }
23-
uv-warnings = { workspace = true }
2423

2524
astral-tokio-tar = { workspace = true }
2625
async-compression = { workspace = true, features = ["bzip2", "gzip", "zstd", "xz"] }

crates/uv-extract/src/stream.rs

Lines changed: 14 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,14 @@
1-
use std::fmt::Display;
21
use std::path::{Component, Path, PathBuf};
32
use std::pin::Pin;
43

54
use async_zip::base::read::cd::Entry;
65
use async_zip::error::ZipError;
7-
use async_zip::{Compression, ZipEntry};
86
use futures::{AsyncReadExt, StreamExt};
97
use rustc_hash::{FxHashMap, FxHashSet};
108
use tokio_util::compat::{FuturesAsyncReadCompatExt, TokioAsyncReadCompatExt};
119
use tracing::{debug, warn};
1210

1311
use uv_distribution_filename::SourceDistExtension;
14-
use uv_warnings::warn_user_once;
1512

1613
use crate::{Error, insecure_no_validate, validate_archive_member_name};
1714

@@ -46,24 +43,10 @@ struct ComputedEntry {
4643
/// This is useful for unzipping files as they're being downloaded. If the archive
4744
/// is already fully on disk, consider using `unzip_archive`, which can use multiple
4845
/// threads to work faster in that case.
49-
///
50-
/// `source_hint` is used for warning messages, to identify the source of the ZIP archive
51-
/// beneath the reader. It might be a URL, a file path, or something else.
52-
pub async fn unzip<D: Display, R: tokio::io::AsyncRead + Unpin>(
53-
source_hint: D,
46+
pub async fn unzip<R: tokio::io::AsyncRead + Unpin>(
5447
reader: R,
5548
target: impl AsRef<Path>,
5649
) -> Result<(), Error> {
57-
/// Returns `true` if the entry uses a well-known compression method.
58-
///
59-
/// This currently means just stored (no compression), DEFLATE, or zstd.
60-
fn entry_has_well_known_compression(entry: &ZipEntry) -> bool {
61-
matches!(
62-
entry.compression(),
63-
Compression::Stored | Compression::Deflate | Compression::Zstd
64-
)
65-
}
66-
6750
/// Ensure the file path is safe to use as a [`Path`].
6851
///
6952
/// See: <https://docs.rs/zip/latest/zip/read/struct.ZipFile.html#method.enclosed_name>
@@ -96,19 +79,8 @@ pub async fn unzip<D: Display, R: tokio::io::AsyncRead + Unpin>(
9679
let mut offset = 0;
9780

9881
while let Some(mut entry) = zip.next_with_entry().await? {
99-
let zip_entry = entry.reader().entry();
100-
101-
// Check for unexpected compression methods.
102-
// A future version of uv will reject instead of warning about these.
103-
if !entry_has_well_known_compression(zip_entry) {
104-
warn_user_once!(
105-
"One or more file entries in '{source_hint}' use the '{compression_method:?}' compression method, which is not widely supported. A future version of uv will reject ZIP archives containing entries compressed with this method.",
106-
compression_method = zip_entry.compression()
107-
);
108-
}
109-
11082
// Construct the (expected) path to the file on-disk.
111-
let path = match zip_entry.filename().as_str() {
83+
let path = match entry.reader().entry().filename().as_str() {
11284
Ok(path) => path,
11385
Err(ZipError::StringNotUtf8) => return Err(Error::LocalHeaderNotUtf8 { offset }),
11486
Err(err) => return Err(err.into()),
@@ -135,14 +107,14 @@ pub async fn unzip<D: Display, R: tokio::io::AsyncRead + Unpin>(
135107
continue;
136108
};
137109

138-
let file_offset = zip_entry.file_offset();
139-
let expected_compressed_size = zip_entry.compressed_size();
140-
let expected_uncompressed_size = zip_entry.uncompressed_size();
141-
let expected_data_descriptor = zip_entry.data_descriptor();
110+
let file_offset = entry.reader().entry().file_offset();
111+
let expected_compressed_size = entry.reader().entry().compressed_size();
112+
let expected_uncompressed_size = entry.reader().entry().uncompressed_size();
113+
let expected_data_descriptor = entry.reader().entry().data_descriptor();
142114

143115
// Either create the directory or write the file to disk.
144116
let path = target.join(&relpath);
145-
let is_dir = zip_entry.dir()?;
117+
let is_dir = entry.reader().entry().dir()?;
146118
let computed = if is_dir {
147119
if directories.insert(path.clone()) {
148120
fs_err::tokio::create_dir_all(path)
@@ -151,23 +123,23 @@ pub async fn unzip<D: Display, R: tokio::io::AsyncRead + Unpin>(
151123
}
152124

153125
// If this is a directory, we expect the CRC32 to be 0.
154-
if zip_entry.crc32() != 0 {
126+
if entry.reader().entry().crc32() != 0 {
155127
if !skip_validation {
156128
return Err(Error::BadCrc32 {
157129
path: relpath.clone(),
158130
computed: 0,
159-
expected: zip_entry.crc32(),
131+
expected: entry.reader().entry().crc32(),
160132
});
161133
}
162134
}
163135

164136
// If this is a directory, we expect the uncompressed size to be 0.
165-
if zip_entry.uncompressed_size() != 0 {
137+
if entry.reader().entry().uncompressed_size() != 0 {
166138
if !skip_validation {
167139
return Err(Error::BadUncompressedSize {
168140
path: relpath.clone(),
169141
computed: 0,
170-
expected: zip_entry.uncompressed_size(),
142+
expected: entry.reader().entry().uncompressed_size(),
171143
});
172144
}
173145
}
@@ -192,7 +164,7 @@ pub async fn unzip<D: Display, R: tokio::io::AsyncRead + Unpin>(
192164
{
193165
Ok(file) => {
194166
// Write the file to disk.
195-
let size = zip_entry.uncompressed_size();
167+
let size = entry.reader().entry().uncompressed_size();
196168
let mut writer = if let Ok(size) = usize::try_from(size) {
197169
tokio::io::BufWriter::with_capacity(std::cmp::min(size, 1024 * 1024), file)
198170
} else {
@@ -772,18 +744,14 @@ pub async fn untar<R: tokio::io::AsyncRead + Unpin>(
772744

773745
/// Unpack a `.zip`, `.tar.gz`, `.tar.bz2`, `.tar.zst`, or `.tar.xz` archive into the target directory,
774746
/// without requiring `Seek`.
775-
///
776-
/// `source_hint` is used for warning messages, to identify the source of the archive
777-
/// beneath the reader. It might be a URL, a file path, or something else.
778-
pub async fn archive<D: Display, R: tokio::io::AsyncRead + Unpin>(
779-
source_hint: D,
747+
pub async fn archive<R: tokio::io::AsyncRead + Unpin>(
780748
reader: R,
781749
ext: SourceDistExtension,
782750
target: impl AsRef<Path>,
783751
) -> Result<(), Error> {
784752
match ext {
785753
SourceDistExtension::Zip => {
786-
unzip(source_hint, reader, target).await?;
754+
unzip(reader, target).await?;
787755
}
788756
SourceDistExtension::Tar => {
789757
untar(reader, target).await?;

crates/uv-extract/src/sync.rs

Lines changed: 6 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,19 @@
11
use std::path::{Path, PathBuf};
22
use std::sync::{LazyLock, Mutex};
33

4-
use crate::vendor::CloneableSeekableReader;
4+
use crate::vendor::{CloneableSeekableReader, HasLength};
55
use crate::{Error, insecure_no_validate, validate_archive_member_name};
66
use rayon::prelude::*;
77
use rustc_hash::FxHashSet;
88
use tracing::warn;
99
use uv_configuration::RAYON_INITIALIZE;
10-
use uv_warnings::warn_user_once;
11-
use zip::{CompressionMethod, ZipArchive};
10+
use zip::ZipArchive;
1211

1312
/// Unzip a `.zip` archive into the target directory.
14-
pub fn unzip(reader: fs_err::File, target: &Path) -> Result<(), Error> {
15-
/// Returns `true` if the entry uses a well-known compression method.
16-
///
17-
/// This currently means just stored (no compression), DEFLATE, or zstd.
18-
fn entry_has_well_known_compression(method: CompressionMethod) -> bool {
19-
matches!(
20-
method,
21-
CompressionMethod::Stored | CompressionMethod::Deflated | CompressionMethod::Zstd
22-
)
23-
}
24-
25-
let (reader, filename) = reader.into_parts();
26-
13+
pub fn unzip<R: Send + std::io::Read + std::io::Seek + HasLength>(
14+
reader: R,
15+
target: &Path,
16+
) -> Result<(), Error> {
2717
// Unzip in parallel.
2818
let reader = std::io::BufReader::new(reader);
2919
let archive = ZipArchive::new(CloneableSeekableReader::new(reader))?;
@@ -37,14 +27,6 @@ pub fn unzip(reader: fs_err::File, target: &Path) -> Result<(), Error> {
3727
let mut archive = archive.clone();
3828
let mut file = archive.by_index(file_number)?;
3929

40-
if !entry_has_well_known_compression(file.compression()) {
41-
warn_user_once!(
42-
"One or more file entries in '{filename}' use the '{compression_method:?}' compression method, which is not widely supported. A future version of uv will reject ZIP archives containing entries compressed with this method.",
43-
filename = filename.display(),
44-
compression_method = file.compression()
45-
);
46-
}
47-
4830
if let Err(e) = validate_archive_member_name(file.name()) {
4931
if !skip_validation {
5032
return Err(e);

crates/uv-extract/src/vendor/cloneable_seekable_reader.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ use std::{
1616
/// A trait to represent some reader which has a total length known in
1717
/// advance. This is roughly equivalent to the nightly
1818
/// [`Seek::stream_len`] API.
19-
pub(crate) trait HasLength {
19+
pub trait HasLength {
2020
/// Return the current total length of this stream.
2121
fn len(&self) -> u64;
2222
}
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
1-
pub(crate) use cloneable_seekable_reader::CloneableSeekableReader;
1+
pub(crate) use cloneable_seekable_reader::{CloneableSeekableReader, HasLength};
22

33
mod cloneable_seekable_reader;

0 commit comments

Comments
 (0)