diff options
| author | Ophestra <cat@gensokyo.uk> | 2026-01-25 16:07:07 +0900 |
|---|---|---|
| committer | Ophestra <cat@gensokyo.uk> | 2026-01-25 16:10:34 +0900 |
| commit | 861801597d800661b26ca03e503cc571537e1304 (patch) | |
| tree | 5b4777b7b160811c2a70f10ddcdd0c931af8567a /internal/pkg/net.go | |
| parent | 334578fddeda6c952b1c2e35829c91c9da72747e (diff) | |
internal/pkg: expose response body
This uses the new measured reader provided by Cache. This should make httpArtifact zero-copy.
Signed-off-by: Ophestra <cat@gensokyo.uk>
Diffstat (limited to 'internal/pkg/net.go')
| -rw-r--r-- | internal/pkg/net.go | 64 |
1 files changed, 13 insertions, 51 deletions
diff --git a/internal/pkg/net.go b/internal/pkg/net.go index 8726fcac..00c2bc61 100644 --- a/internal/pkg/net.go +++ b/internal/pkg/net.go @@ -1,14 +1,11 @@ package pkg import ( - "bytes" - "context" - "crypto/sha512" "fmt" "io" "net/http" "path" - "sync" + "unique" ) // An httpArtifact is an [Artifact] backed by a [http] url string. The method is @@ -18,18 +15,12 @@ type httpArtifact struct { // Caller-supplied url string. url string - // Caller-supplied checksum of the response body. This is validated during - // curing and the first call to Data. - checksum Checksum + // Caller-supplied checksum of the response body. This is validated when + // closing the [io.ReadCloser] returned by Cure. + checksum unique.Handle[Checksum] // doFunc is the Do method of [http.Client] supplied by the caller. doFunc func(req *http.Request) (*http.Response, error) - - // Response body read to EOF. - data []byte - - // Synchronises access to data. - mu sync.Mutex } var _ KnownChecksum = new(httpArtifact) @@ -45,7 +36,7 @@ func NewHTTPGet( if c == nil { c = http.DefaultClient } - return &httpArtifact{url: url, checksum: checksum, doFunc: c.Do} + return &httpArtifact{url: url, checksum: unique.Make(checksum), doFunc: c.Do} } // Kind returns the hardcoded [Kind] constant. @@ -61,7 +52,7 @@ func (a *httpArtifact) Params(ctx *IContext) { func (a *httpArtifact) Dependencies() []Artifact { return nil } // Checksum returns the caller-supplied checksum. -func (a *httpArtifact) Checksum() Checksum { return a.checksum } +func (a *httpArtifact) Checksum() Checksum { return a.checksum.Value() } // String returns [path.Base] over the backing url. func (a *httpArtifact) String() string { return path.Base(a.url) } @@ -74,11 +65,13 @@ func (e ResponseStatusError) Error() string { return "the requested URL returned non-OK status: " + http.StatusText(int(e)) } -// do sends the caller-supplied request on the caller-supplied [http.Client] -// and reads its response body to EOF and returns the resulting bytes. -func (a *httpArtifact) do(ctx context.Context) (data []byte, err error) { +// Cure sends the http request and returns the resulting response body reader +// wrapped to perform checksum validation. It is valid but not encouraged to +// close the resulting [io.ReadCloser] before it is read to EOF, as that causes +// Close to block until all remaining data is consumed and validated. +func (a *httpArtifact) Cure(r *RContext) (rc io.ReadCloser, err error) { var req *http.Request - req, err = http.NewRequestWithContext(ctx, http.MethodGet, a.url, nil) + req, err = http.NewRequestWithContext(r.Unwrap(), http.MethodGet, a.url, nil) if err != nil { return } @@ -93,37 +86,6 @@ func (a *httpArtifact) do(ctx context.Context) (data []byte, err error) { return nil, ResponseStatusError(resp.StatusCode) } - if data, err = io.ReadAll(resp.Body); err != nil { - _ = resp.Body.Close() - return - } - - err = resp.Body.Close() - return -} - -// Cure completes the http request and returns the resulting response body read -// to EOF. Data does not interact with the filesystem. -func (a *httpArtifact) Cure(ctx context.Context) (r io.ReadCloser, err error) { - a.mu.Lock() - defer a.mu.Unlock() - - if a.data != nil { - // validated by cache or a previous call to Cure - return io.NopCloser(bytes.NewReader(a.data)), nil - } - - var data []byte - if data, err = a.do(ctx); err != nil { - return - } - - h := sha512.New384() - h.Write(data) - if got := (Checksum)(h.Sum(nil)); got != a.checksum { - return nil, &ChecksumMismatchError{got, a.checksum} - } - a.data = data - r = io.NopCloser(bytes.NewReader(data)) + rc = r.NewMeasuredReader(resp.Body, a.checksum) return } |
