From 2f46e6a43cd50e673b99c20d61c6d699ae9bcdb9 Mon Sep 17 00:00:00 2001 From: Binlogo Date: Mon, 24 Nov 2025 18:51:45 +0800 Subject: [PATCH] http_client: Support `GITHUB_TOKEN` env to auth GitHub requests (#42623) Closes #33903 Release Notes: - Ensured Zed reuses `GITHUB_TOKEN` env variable when querying GitHub --- Before fixing: - The `crates-lsp` extension request captured: ``` curl 'https://api.github.com/repos/MathiasPius/crates-lsp/releases' \ -H 'accept: */*' \ -H 'user-agent: Zed/0.212.3 (macos; aarch64)' \ -H 'host: api.github.com' \ ``` - `crates-lsp` extension error: ``` Language server crates-lsp: from extension "Crates LSP" version 0.2.0: status error 403, response: "{\"message\":\"API rate limit exceeded for x.x.x.x. (But here's the good news: Authenticated requests get a higher rate limit. Check out the documentation for more details.)\",\"documentation_url\":\"https://docs.github.com/rest/overview/resources-in-the-rest-api#rate-limiting\"}\n" ``` After fixing: ``` export GITHUB_TOKEN=$(gh auth token) cargo run ``` - The `crates-lsp` extension request captured: ``` curl 'https://api.github.com/repos/MathiasPius/crates-lsp/releases' \ -H 'authorization: Bearer gho_Nt*****************2KXLw2' \ -H 'accept: */*' \ -H 'user-agent: Zed/0.214.0 (macos; aarch64)' \ -H 'host: api.github.com' \ ``` The API rate limitation is resolved. --- This isn't a perfect solution, but it enables users to avoid the noise. --- crates/http_client/src/github.rs | 35 ++++++++++++++++++++++---------- 1 file changed, 24 insertions(+), 11 deletions(-) diff --git a/crates/http_client/src/github.rs b/crates/http_client/src/github.rs index 32efed8e727330d3ac1c2fb6d8ea5d57fdd66dd4..e52e2f1d2555de477cd4597826bc3bd8308faf89 100644 --- a/crates/http_client/src/github.rs +++ b/crates/http_client/src/github.rs @@ -1,10 +1,13 @@ -use crate::HttpClient; +use crate::{HttpClient, HttpRequestExt}; use anyhow::{Context as _, Result, anyhow, bail}; use futures::AsyncReadExt; +use http::Request; use serde::Deserialize; use std::sync::Arc; use url::Url; +const GITHUB_API_URL: &str = "https://api.github.com"; + pub struct GitHubLspBinaryVersion { pub name: String, pub url: String, @@ -34,12 +37,17 @@ pub async fn latest_github_release( pre_release: bool, http: Arc, ) -> anyhow::Result { + let url = format!("{GITHUB_API_URL}/repos/{repo_name_with_owner}/releases"); + + let request = Request::get(&url) + .follow_redirects(crate::RedirectPolicy::FollowAll) + .when_some(std::env::var("GITHUB_TOKEN").ok(), |builder, token| { + builder.header("Authorization", format!("Bearer {}", token)) + }) + .body(Default::default())?; + let mut response = http - .get( - format!("https://api.github.com/repos/{repo_name_with_owner}/releases").as_str(), - Default::default(), - true, - ) + .send(request) .await .context("error fetching latest release")?; @@ -91,12 +99,17 @@ pub async fn get_release_by_tag_name( tag: &str, http: Arc, ) -> anyhow::Result { + let url = format!("{GITHUB_API_URL}/repos/{repo_name_with_owner}/releases/tags/{tag}"); + + let request = Request::get(&url) + .follow_redirects(crate::RedirectPolicy::FollowAll) + .when_some(std::env::var("GITHUB_TOKEN").ok(), |builder, token| { + builder.header("Authorization", format!("Bearer {}", token)) + }) + .body(Default::default())?; + let mut response = http - .get( - &format!("https://api.github.com/repos/{repo_name_with_owner}/releases/tags/{tag}"), - Default::default(), - true, - ) + .send(request) .await .context("error fetching latest release")?;