diff --git a/internal/appherder/source.go b/internal/appherder/source.go index 2f0773a..4304f7e 100644 --- a/internal/appherder/source.go +++ b/internal/appherder/source.go @@ -193,10 +193,12 @@ func matchByName[T any](items []T, pattern string, name func(T) string, kind str return matches[0], nil } +const apiResponseLimit = 4 * 1024 * 1024 // 4 MiB; real API responses are a few KB + // decodeJSON decodes a JSON value from r, wrapping any error with desc. func decodeJSON[T any](r io.Reader, desc string) (T, error) { var value T - if err := json.NewDecoder(r).Decode(&value); err != nil { + if err := json.NewDecoder(io.LimitReader(r, apiResponseLimit)).Decode(&value); err != nil { return value, fmt.Errorf("%s: %w", desc, err) } return value, nil diff --git a/internal/appherder/source_zsync.go b/internal/appherder/source_zsync.go index 788ca40..e216f5f 100644 --- a/internal/appherder/source_zsync.go +++ b/internal/appherder/source_zsync.go @@ -55,7 +55,7 @@ func fetchZsyncHeader(ctx context.Context, zsyncURL string) (map[string]string, } defer resp.Body.Close() - header, err := parseZsyncHeader(resp.Body) + header, err := parseZsyncHeader(io.LimitReader(resp.Body, apiResponseLimit)) if err != nil { return nil, fmt.Errorf("parse zsync control file %s: %w", zsyncURL, err) }