aboutsummaryrefslogtreecommitdiffhomepage
path: root/internal/pkg/net.go
diff options
context:
space:
mode:
authorOphestra <cat@gensokyo.uk>2026-01-25 16:07:07 +0900
committerOphestra <cat@gensokyo.uk>2026-01-25 16:10:34 +0900
commit861801597d800661b26ca03e503cc571537e1304 (patch)
tree5b4777b7b160811c2a70f10ddcdd0c931af8567a /internal/pkg/net.go
parent334578fddeda6c952b1c2e35829c91c9da72747e (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.go64
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
}