Skip to content

Commit bc471dc

Browse files
authored
Merge pull request #1812 from charlespierce/tarball_compressed_size
Remove extra GET for tarball uncompressed size
2 parents f4bd615 + 796d31e commit bc471dc

File tree

7 files changed

+9
-110
lines changed

7 files changed

+9
-110
lines changed

crates/archive/src/lib.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,6 @@ pub enum Origin {
4242

4343
pub trait Archive {
4444
fn compressed_size(&self) -> u64;
45-
fn uncompressed_size(&self) -> Option<u64>;
4645

4746
/// Unpacks the zip archive to the specified destination folder.
4847
fn unpack(

crates/archive/src/tarball.rs

Lines changed: 5 additions & 94 deletions
Original file line numberDiff line numberDiff line change
@@ -2,25 +2,20 @@
22
//! tarball in Unix operating systems.
33
44
use std::fs::File;
5-
use std::io::{Read, Seek, SeekFrom};
5+
use std::io::Read;
66
use std::path::Path;
77

88
use super::{Archive, ArchiveError, Origin};
99
use attohttpc::header::HeaderMap;
1010
use flate2::read::GzDecoder;
1111
use fs_utils::ensure_containing_dir_exists;
12-
use headers::{AcceptRanges, ContentLength, Header, HeaderMapExt, Range};
12+
use headers::{ContentLength, Header, HeaderMapExt};
1313
use progress_read::ProgressRead;
1414
use tee::TeeReader;
1515

1616
/// A Node installation tarball.
1717
pub struct Tarball {
1818
compressed_size: u64,
19-
// Some servers don't return the right data for byte range queries, so
20-
// getting the uncompressed archive size for tarballs is an Option.
21-
// If the uncompressed size is not available, the compressed size will be
22-
// used for the download/unpack progress indicator, so that will be slightly off.
23-
uncompressed_size: Option<u64>,
2419
data: Box<dyn Read>,
2520
origin: Origin,
2621
}
@@ -36,11 +31,9 @@ fn content_length(headers: &HeaderMap) -> Result<u64, ArchiveError> {
3631

3732
impl Tarball {
3833
/// Loads a tarball from the specified file.
39-
pub fn load(mut source: File) -> Result<Box<dyn Archive>, ArchiveError> {
40-
let uncompressed_size = load_uncompressed_size(&mut source);
34+
pub fn load(source: File) -> Result<Box<dyn Archive>, ArchiveError> {
4135
let compressed_size = source.metadata()?.len();
4236
Ok(Box::new(Tarball {
43-
uncompressed_size,
4437
compressed_size,
4538
data: Box::new(source),
4639
origin: Origin::Local,
@@ -58,18 +51,12 @@ impl Tarball {
5851
}
5952

6053
let compressed_size = content_length(&headers)?;
61-
let uncompressed_size = if accepts_byte_ranges(&headers) {
62-
fetch_uncompressed_size(url, compressed_size)
63-
} else {
64-
None
65-
};
6654

6755
ensure_containing_dir_exists(&cache_file)?;
6856
let file = File::create(cache_file)?;
6957
let data = Box::new(TeeReader::new(response, file));
7058

7159
Ok(Box::new(Tarball {
72-
uncompressed_size,
7360
compressed_size,
7461
data,
7562
origin: Origin::Remote,
@@ -81,16 +68,13 @@ impl Archive for Tarball {
8168
fn compressed_size(&self) -> u64 {
8269
self.compressed_size
8370
}
84-
fn uncompressed_size(&self) -> Option<u64> {
85-
self.uncompressed_size
86-
}
8771
fn unpack(
8872
self: Box<Self>,
8973
dest: &Path,
9074
progress: &mut dyn FnMut(&(), usize),
9175
) -> Result<(), ArchiveError> {
92-
let decoded = GzDecoder::new(self.data);
93-
let mut tarball = tar::Archive::new(ProgressRead::new(decoded, (), progress));
76+
let decoded = GzDecoder::new(ProgressRead::new(self.data, (), progress));
77+
let mut tarball = tar::Archive::new(decoded);
9478
tarball.unpack(dest)?;
9579
Ok(())
9680
}
@@ -99,78 +83,6 @@ impl Archive for Tarball {
9983
}
10084
}
10185

102-
// From http://www.gzip.org/zlib/rfc-gzip.html#member-format
103-
//
104-
// 0 1 2 3 4 5 6 7
105-
// +---+---+---+---+---+---+---+---+
106-
// | CRC32 | ISIZE |
107-
// +---+---+---+---+---+---+---+---+
108-
//
109-
// ISIZE (Input SIZE)
110-
// This contains the size of the original (uncompressed) input data modulo 2^32.
111-
112-
/// Fetches just the `isize` field (the field that indicates the uncompressed size)
113-
/// of a gzip file from a URL. This makes two round-trips to the server but avoids
114-
/// downloading the entire gzip file. For very small files it's unlikely to be
115-
/// more efficient than simply downloading the entire file up front.
116-
fn fetch_isize(url: &str, len: u64) -> Result<[u8; 4], ArchiveError> {
117-
let (status, headers, mut response) = {
118-
let mut request = attohttpc::get(url);
119-
request
120-
.headers_mut()
121-
.typed_insert(Range::bytes(len - 4..len).unwrap());
122-
request.send()?.split()
123-
};
124-
125-
if !status.is_success() {
126-
return Err(ArchiveError::HttpError(status));
127-
}
128-
129-
let actual_length = content_length(&headers)?;
130-
131-
if actual_length != 4 {
132-
return Err(ArchiveError::UnexpectedContentLengthError(actual_length));
133-
}
134-
135-
let mut buf = [0; 4];
136-
response.read_exact(&mut buf)?;
137-
Ok(buf)
138-
}
139-
140-
/// Loads the `isize` field (the field that indicates the uncompressed size)
141-
/// of a gzip file from disk.
142-
fn load_isize(file: &mut File) -> Result<[u8; 4], ArchiveError> {
143-
file.seek(SeekFrom::End(-4))?;
144-
let mut buf = [0; 4];
145-
file.read_exact(&mut buf)?;
146-
file.seek(SeekFrom::Start(0))?;
147-
Ok(buf)
148-
}
149-
150-
fn accepts_byte_ranges(headers: &HeaderMap) -> bool {
151-
headers
152-
.typed_get::<AcceptRanges>()
153-
.is_some_and(|v| v == AcceptRanges::bytes())
154-
}
155-
156-
/// Determines the uncompressed size of a gzip file hosted at the specified
157-
/// URL by fetching just the metadata associated with the file. This makes
158-
/// an extra round-trip to the server, so it's only more efficient than just
159-
/// downloading the file if the file is large enough that downloading it is
160-
/// slower than the extra round trips.
161-
fn fetch_uncompressed_size(url: &str, len: u64) -> Option<u64> {
162-
// if there is an error, we ignore it and return None, instead of failing
163-
fetch_isize(url, len)
164-
.ok()
165-
.map(|s| u32::from_le_bytes(s) as u64)
166-
}
167-
168-
/// Determines the uncompressed size of the specified gzip file on disk.
169-
fn load_uncompressed_size(file: &mut File) -> Option<u64> {
170-
// if there is an error, we ignore it and return None, instead of failing
171-
load_isize(file).ok().map(|s| u32::from_le_bytes(s) as u64)
172-
}
173-
17486
#[cfg(test)]
17587
pub mod tests {
17688

@@ -192,7 +104,6 @@ pub mod tests {
192104
let test_file = File::open(test_file_path).expect("Couldn't open test file");
193105
let tarball = Tarball::load(test_file).expect("Failed to load tarball");
194106

195-
assert_eq!(tarball.uncompressed_size(), Some(10240));
196107
assert_eq!(tarball.compressed_size(), 402);
197108
}
198109
}

crates/archive/src/zip.rs

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -60,9 +60,6 @@ impl Archive for Zip {
6060
fn compressed_size(&self) -> u64 {
6161
self.compressed_size
6262
}
63-
fn uncompressed_size(&self) -> Option<u64> {
64-
None
65-
}
6663
fn unpack(
6764
self: Box<Self>,
6865
dest: &Path,

crates/volta-core/src/tool/node/fetch.rs

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -95,9 +95,7 @@ fn unpack_archive(archive: Box<dyn Archive>, version: &Version) -> Fallible<Node
9595
let progress = progress_bar(
9696
archive.origin(),
9797
&tool_version("node", version),
98-
archive
99-
.uncompressed_size()
100-
.unwrap_or_else(|| archive.compressed_size()),
98+
archive.compressed_size(),
10199
);
102100
let version_string = version.to_string();
103101

crates/volta-core/src/tool/npm/fetch.rs

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -62,9 +62,7 @@ fn unpack_archive(archive: Box<dyn Archive>, version: &Version) -> Fallible<()>
6262
let progress = progress_bar(
6363
archive.origin(),
6464
&tool_version("npm", version),
65-
archive
66-
.uncompressed_size()
67-
.unwrap_or_else(|| archive.compressed_size()),
65+
archive.compressed_size(),
6866
);
6967
let version_string = version.to_string();
7068

crates/volta-core/src/tool/pnpm/fetch.rs

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -64,9 +64,7 @@ fn unpack_archive(archive: Box<dyn Archive>, version: &Version) -> Fallible<()>
6464
let progress = progress_bar(
6565
archive.origin(),
6666
&tool_version("pnpm", version),
67-
archive
68-
.uncompressed_size()
69-
.unwrap_or_else(|| archive.compressed_size()),
67+
archive.compressed_size(),
7068
);
7169
let version_string = version.to_string();
7270

crates/volta-core/src/tool/yarn/fetch.rs

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -66,9 +66,7 @@ fn unpack_archive(archive: Box<dyn Archive>, version: &Version) -> Fallible<()>
6666
let progress = progress_bar(
6767
archive.origin(),
6868
&tool_version("yarn", version),
69-
archive
70-
.uncompressed_size()
71-
.unwrap_or_else(|| archive.compressed_size()),
69+
archive.compressed_size(),
7270
);
7371
let version_string = version.to_string();
7472

0 commit comments

Comments
 (0)