Skip to content

Commit 547b4c0

Browse files
author
wuguofeng
committed
fix(upgrade): set Accept header for GitHub asset download
GitHub release asset URLs are API endpoints (api.github.com/repos/.../assets/XXX) that return JSON metadata by default, not the binary. Without `Accept: application/octet-stream`, the downloaded "archive" was actually JSON, causing tar extraction to fail with "Could not find the required path in the archive". self_update::ReleaseUpdate::update() sets this header internally; since we bypass it and use Download directly, we must set it ourselves. Also adds a User-Agent header (GitHub API requires one).
1 parent 3315e05 commit 547b4c0

3 files changed

Lines changed: 29 additions & 1 deletion

File tree

Cargo.lock

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

crates/core/Cargo.toml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,12 @@ tokio = { version = "1", features = ["macros", "signal", "time", "sync"] }
4242
# blocks cross-major upgrades (0.x → 1.0). rustls backend (no OpenSSL).
4343
self_update = { version = "0.42", default-features = false, features = ["archive-tar", "compression-flate2", "rustls"] }
4444

45+
# HTTP header types for the upgrade download. GitHub asset API URLs need
46+
# `Accept: application/octet-stream` to return the binary (not JSON metadata);
47+
# we construct that header via reqwest::header (reqwest is already pulled in
48+
# by self_update, so this adds no new code to the binary).
49+
reqwest = { version = "0.12", default-features = false, features = ["rustls-tls"] }
50+
4551
# Atomic self-replacement of the running binary. Re-exported by self_update as
4652
# `self_update::self_replace`, but depended on directly here for clarity (we
4753
# call it from our own download+replace logic, not from self_update's).

crates/core/src/upgrade_engine.rs

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -201,7 +201,28 @@ impl UpgradeEngine {
201201
let archive_path = tmp_dir.path().join(&asset.name);
202202
let mut archive_file =
203203
std::fs::File::create(&archive_path).map_err(|e| format!("create archive file: {e}"))?;
204-
self_update::Download::from_url(&asset.download_url)
204+
205+
// GitHub release asset URLs are API endpoints (api.github.com/.../assets/XXX)
206+
// that return JSON metadata unless `Accept: application/octet-stream` is sent.
207+
// Without this header, the downloaded "archive" is actually JSON → tar extraction
208+
// fails with "Could not find the required path in the archive". This mirrors what
209+
// self_update::ReleaseUpdate::update() does internally (api_headers + Accept).
210+
let mut download = self_update::Download::from_url(&asset.download_url);
211+
let mut headers = reqwest::header::HeaderMap::new();
212+
headers.insert(
213+
reqwest::header::ACCEPT,
214+
"application/octet-stream"
215+
.parse()
216+
.map_err(|e| format!("invalid accept header: {e}"))?,
217+
);
218+
headers.insert(
219+
reqwest::header::USER_AGENT,
220+
concat!("tailr-upgrade/", env!("CARGO_PKG_VERSION"))
221+
.parse()
222+
.map_err(|e| format!("invalid user-agent header: {e}"))?,
223+
);
224+
download.set_headers(headers);
225+
download
205226
.download_to(&mut archive_file)
206227
.map_err(|e| format!("download failed: {e}"))?;
207228

0 commit comments

Comments
 (0)