mirror of
https://github.com/git-pkgs/proxy.git
synced 2026-11-09 15:49:16 -05:00
* Use shared archives browser for cached artifacts * Pin archives to combined browser and Hex changes * Use archives v0.9.0 release * Return 404 when browsing archive directories as files
60 lines
2 KiB
Go
60 lines
2 KiB
Go
package server
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"io"
|
|
|
|
"github.com/git-pkgs/archives"
|
|
)
|
|
|
|
// Limits applied when listing or reading a single file. Bodies are streamed
|
|
// rather than retained, so these bound decompression work per request; they
|
|
// match the limits the buffered archive reader enforces.
|
|
const (
|
|
maxBrowseExpandedSize = 512 << 20 // 512 MB across all entries
|
|
maxBrowseEntrySize = 512 << 20 // 512 MB for any one entry
|
|
maxBrowseEntries = 100_000
|
|
)
|
|
|
|
// npmPackagePrefix is the directory npm wraps every tarball's contents in.
|
|
const npmPackagePrefix = "package/"
|
|
|
|
var defaultBrowseLimits = archives.StreamOptions{
|
|
MaxInputBytes: maxBrowseArchiveSize,
|
|
MaxEntryBytes: maxBrowseEntrySize,
|
|
MaxExpandedBytes: maxBrowseExpandedSize,
|
|
MaxEntries: maxBrowseEntries,
|
|
}
|
|
|
|
var errArtifactTooLarge = errors.New("artifact too large for browsing")
|
|
|
|
// isBrowseLimitError reports whether err comes from one of the browse size or
|
|
// entry-count limits rather than a malformed archive.
|
|
func isBrowseLimitError(err error) bool {
|
|
return errors.Is(err, errArtifactTooLarge) ||
|
|
errors.Is(err, archives.ErrInputLimit) ||
|
|
errors.Is(err, archives.ErrEntrySizeLimit) ||
|
|
errors.Is(err, archives.ErrDecompressLimit) ||
|
|
errors.Is(err, archives.ErrEntryLimit)
|
|
}
|
|
|
|
// readBrowseInput reads all of r, failing once it exceeds limit bytes.
|
|
func readBrowseInput(r io.Reader, limit int64) ([]byte, error) {
|
|
data, err := io.ReadAll(io.LimitReader(r, limit+1))
|
|
if err != nil {
|
|
return nil, fmt.Errorf("reading artifact: %w", err)
|
|
}
|
|
if int64(len(data)) > limit {
|
|
return nil, fmt.Errorf("%w (%d bytes)", errArtifactTooLarge, len(data))
|
|
}
|
|
return data, nil
|
|
}
|
|
|
|
func newBrowseArchive(filename, ecosystem string, content io.Reader, reopen func() (io.ReadCloser, error), limits archives.StreamOptions) (*archives.Browser, error) {
|
|
options := archives.BrowseOptions{Limits: limits, DetectRoot: true}
|
|
if ecosystem == "npm" {
|
|
options.StripPrefix = npmPackagePrefix
|
|
}
|
|
return archives.OpenBrowser(filename, content, reopen, options)
|
|
}
|