From 8e311847dbf2e5fb26e8ea83bb08ada6129a3cdd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mislav=20Marohni=C4=87?= Date: Tue, 30 Nov 2021 15:33:06 +0100 Subject: [PATCH] Ensure that we never download "legacy" archive formats The `zipball_url` and `tarball_url` fields on the Release API payload always link to "legacy" archives that are of a different format than those one would get if they downloaded an archive from a Release using the web interface. The GitHub API does not seem to publish links to non-legacy archives. This adds a redirect hack to turn "legacy" Codeload URLs into non-legacy ones with the goal of ensuring the consistency of user experience when downloading archives. --- pkg/cmd/release/download/download.go | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/pkg/cmd/release/download/download.go b/pkg/cmd/release/download/download.go index f410bae7b..eeaa06642 100644 --- a/pkg/cmd/release/download/download.go +++ b/pkg/cmd/release/download/download.go @@ -8,6 +8,7 @@ import ( "net/http" "os" "path/filepath" + "regexp" "github.com/MakeNowJust/heredoc" "github.com/cli/cli/v2/api" @@ -228,9 +229,19 @@ func downloadAsset(httpClient *http.Client, assetURL, destinationDir string, fil } req.Header.Set("Accept", "application/octet-stream") - // adding application/json to Accept header due to a bug in the zipball/tarball API endpoint that makes it mandatory if isArchive { + // adding application/json to Accept header due to a bug in the zipball/tarball API endpoint that makes it mandatory req.Header.Set("Accept", "application/octet-stream, application/json") + + // override HTTP redirect logic to avoid "legacy" Codeload resources + oldClient := *httpClient + httpClient = &oldClient + httpClient.CheckRedirect = func(req *http.Request, via []*http.Request) error { + if len(via) == 1 { + req.URL.Path = removeLegacyFromCodeloadPath(req.URL.Path) + } + return nil + } } resp, err := httpClient.Do(req) @@ -268,3 +279,16 @@ func downloadAsset(httpClient *http.Client, assetURL, destinationDir string, fil _, err = io.Copy(f, resp.Body) return err } + +var codeloadLegacyRE = regexp.MustCompile(`^(/[^/]+/[^/]+/)legacy\.`) + +// removeLegacyFromCodeloadPath converts URLs for "legacy" Codeload archives into ones that match the format +// when you choose to download "Source code (zip/tar.gz)" from a tagged release on the web. The legacy URLs +// look like this: +// +// https://codeload.github.com/OWNER/REPO/legacy.zip/refs/tags/TAGNAME +// +// Removing the "legacy." part results in a valid Codeload URL for our desired archive format. +func removeLegacyFromCodeloadPath(p string) string { + return codeloadLegacyRE.ReplaceAllString(p, "$1") +}