From c35c957e7a6327d1c17577531a61955dda4c6588 Mon Sep 17 00:00:00 2001 From: "gcp-cherry-pick-bot[bot]" <98988430+gcp-cherry-pick-bot[bot]@users.noreply.github.com> Date: Thu, 11 Apr 2024 14:53:36 -0400 Subject: [PATCH] Validate content-length of downloaded extension tar gz files (cherry-pick #10430) (#10440) Cherry-picked 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 Co-authored-by: Max Brunsfeld 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 deb81afd3efd9dc30a49da73e9fd70745cf294eb..3fc53d57e4de160a036ccc9a51028a7411b87bc2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3588,6 +3588,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 df02174e1e410301df2efdd9a7ef3299d96036af..7d6713729af3087d6becb66c7fdc2db4e5f73866 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 4a087b8402a674691bf1d40b0617484b7f66ca02..dcac1d1825aab031f1371796bed4898f98475f33 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| {