From 47f698d5a34a62fb8376aa30243884d508167e39 Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Thu, 11 Apr 2024 10:24:09 -0700 Subject: [PATCH] Validate content-length of downloaded extension tar gz files (#10430) Release Notes: - Fixed a bug where extension installation would appear to succeed even if the download did not complete due to network interruptions ([#10330](https://github.com/zed-industries/zed/issues/10330)). Co-authored-by: Marshall --- Cargo.lock | 1 + crates/extension/Cargo.toml | 1 + crates/extension/src/extension_store.rs | 18 +++++++++++++++++- 3 files changed, 19 insertions(+), 1 deletion(-) diff --git a/Cargo.lock b/Cargo.lock index 8a1f8c161c..c5c7262cbc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3579,6 +3579,7 @@ dependencies = [ "fs", "futures 0.3.28", "gpui", + "isahc", "language", "log", "lsp", diff --git a/crates/extension/Cargo.toml b/crates/extension/Cargo.toml index df02174e1e..7d6713729a 100644 --- a/crates/extension/Cargo.toml +++ b/crates/extension/Cargo.toml @@ -23,6 +23,7 @@ collections.workspace = true fs.workspace = true futures.workspace = true gpui.workspace = true +isahc.workspace = true language.workspace = true log.workspace = true lsp.workspace = true diff --git a/crates/extension/src/extension_store.rs b/crates/extension/src/extension_store.rs index 4a087b8402..dcac1d1825 100644 --- a/crates/extension/src/extension_store.rs +++ b/crates/extension/src/extension_store.rs @@ -606,7 +606,23 @@ impl ExtensionStore { ) .await?; - let decompressed_bytes = GzipDecoder::new(BufReader::new(response.body_mut())); + let content_length = response + .headers() + .get(isahc::http::header::CONTENT_LENGTH) + .and_then(|value| value.to_str().ok()?.parse::().ok()); + + let mut body = BufReader::new(response.body_mut()); + let mut tgz_bytes = Vec::new(); + body.read_to_end(&mut tgz_bytes).await?; + + if let Some(content_length) = content_length { + let actual_len = tgz_bytes.len(); + if content_length != actual_len { + bail!("downloaded extension size {actual_len} does not match content length {content_length}"); + } + } + let decompressed_bytes = GzipDecoder::new(BufReader::new(tgz_bytes.as_slice())); + // let decompressed_bytes = GzipDecoder::new(BufReader::new(tgz_bytes)); let archive = Archive::new(decompressed_bytes); archive.unpack(extension_dir).await?; this.update(&mut cx, |this, cx| {