From e248d394d862a9a858042dffe2be72bada72b918 Mon Sep 17 00:00:00 2001 From: Suleiman Dibirov Date: Wed, 22 Oct 2025 20:00:20 +0300 Subject: [PATCH] fixes Signed-off-by: Suleiman Dibirov --- internal/plugin/installer/extractor.go | 11 ++++++-- internal/plugin/installer/gzip.go | 36 +++++++++++++++++++------- internal/plugin/installer/installer.go | 16 +++++++++--- 3 files changed, 47 insertions(+), 16 deletions(-) diff --git a/internal/plugin/installer/extractor.go b/internal/plugin/installer/extractor.go index aadcbfefa..9865bea40 100644 --- a/internal/plugin/installer/extractor.go +++ b/internal/plugin/installer/extractor.go @@ -68,8 +68,15 @@ func NewExtractor(source string) (Extractor, error) { return extractor, nil } } - if strings.HasPrefix(source, "http") && isGzipArchiveFromURL(source) { - return &TarGzExtractor{}, nil + if strings.HasPrefix(source, "http") { + isGzip, err := isGzipArchiveFromURL(source) + if err != nil { + return nil, err + } + + if isGzip { + return &TarGzExtractor{}, nil + } } return nil, fmt.Errorf("no extractor implemented yet for %s", source) diff --git a/internal/plugin/installer/gzip.go b/internal/plugin/installer/gzip.go index d247d542f..0b69d277b 100644 --- a/internal/plugin/installer/gzip.go +++ b/internal/plugin/installer/gzip.go @@ -15,7 +15,13 @@ limitations under the License. package installer -import "net/http" +import ( + "context" + "fmt" + "io" + "net/http" + "time" +) // isGzipArchive checks if data represents a gzip archive by checking the magic bytes func isGzipArchive(data []byte) bool { @@ -23,11 +29,15 @@ func isGzipArchive(data []byte) bool { } // isGzipArchiveFromURL checks if a URL points to a gzip archive by reading the magic bytes -func isGzipArchiveFromURL(url string) bool { +func isGzipArchiveFromURL(url string) (bool, error) { + // Use a short timeout context to avoid hanging on slow servers + ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) + defer cancel() + // Make a GET request to read the first few bytes - req, err := http.NewRequest(http.MethodGet, url, nil) + req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil) if err != nil { - return false + return false, err } // Request only the first 512 bytes to check magic bytes @@ -35,16 +45,22 @@ func isGzipArchiveFromURL(url string) bool { resp, err := http.DefaultClient.Do(req) if err != nil { - return false + return false, err } defer resp.Body.Close() - // Read the first few bytes + // Check for valid status codes early + // 206 = Partial Content (range supported) + // 200 = OK (range not supported, full content returned) + if resp.StatusCode != http.StatusPartialContent && resp.StatusCode != http.StatusOK { + return false, fmt.Errorf("unexpected status code %d when checking gzip archive at %s", resp.StatusCode, url) + } + + // Read exactly 2 bytes for gzip magic number check buf := make([]byte, 2) - n, err := resp.Body.Read(buf) - if err != nil || n < 2 { - return false + if _, err := io.ReadAtLeast(resp.Body, buf, len(buf)); err != nil { + return false, fmt.Errorf("failed to read magic bytes from %s: %w", url, err) } - return isGzipArchive(buf) + return isGzipArchive(buf), nil } diff --git a/internal/plugin/installer/installer.go b/internal/plugin/installer/installer.go index 62654f5ac..f279f26b5 100644 --- a/internal/plugin/installer/installer.go +++ b/internal/plugin/installer/installer.go @@ -196,10 +196,18 @@ func isRemoteHTTPArchive(source string) bool { contentType := res.Header.Get("content-type") foundSuffix, ok := mediaTypeToExtension(contentType) if !ok { - if contentType == "application/octet-stream" && isGzipArchiveFromURL(source) { - // For generic binary content, try to detect the actual file type - // by reading the first few bytes (magic bytes) - return true + if contentType == "application/octet-stream" { + isGzip, err := isGzipArchiveFromURL(source) + if err != nil { + slog.Debug("isGzipArchiveFromURL", slog.Any("error", err)) + return false + } + + if isGzip { + // For generic binary content, try to detect the actual file type + // by reading the first few bytes (magic bytes) + return true + } } return false