Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion pkg/apk/apk/implementation.go
Original file line number Diff line number Diff line change
Expand Up @@ -1384,7 +1384,7 @@ func (a *APK) FetchPackage(ctx context.Context, pkg FetchablePackage) (io.ReadCl
}

// This will return a body that retries requests using Range requests if Read() hits an error.
rrt := newRangeRetryTransport(ctx, client)
rrt := NewRangeRetryTransport(client.Transport)
res, err := rrt.RoundTrip(req)
if err != nil {
return nil, fmt.Errorf("unable to get package apk at %s: %w", u, err)
Expand Down
2 changes: 1 addition & 1 deletion pkg/apk/apk/index.go
Original file line number Diff line number Diff line change
Expand Up @@ -321,7 +321,7 @@ func fetchRepositoryIndex(ctx context.Context, u string, etag string, opts *inde
}

// This will return a body that retries requests using Range requests if Read() hits an error.
rrt := newRangeRetryTransport(ctx, client)
rrt := NewRangeRetryTransport(client.Transport)
res, err := rrt.RoundTrip(req)
if err != nil {
return nil, err
Expand Down
44 changes: 17 additions & 27 deletions pkg/apk/apk/transport.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,45 +15,40 @@
package apk

import (
"context"
"errors"
"fmt"
"io"
"net/http"
)

type rangeRetryTransport struct {
client *http.Client
ctx context.Context
base http.RoundTripper
}

func newRangeRetryTransport(ctx context.Context, client *http.Client) *rangeRetryTransport {
return &rangeRetryTransport{
client: client,
ctx: ctx,
// NewRangeRetryTransport returns a transport that retries failed reads using HTTP Range requests.
func NewRangeRetryTransport(base http.RoundTripper) http.RoundTripper {
if base == nil {
base = http.DefaultTransport
}
return &rangeRetryTransport{base: base}
}

func (t *rangeRetryTransport) RoundTrip(req *http.Request) (*http.Response, error) {
r := rangeRetryReader{
client: t.client,
ctx: t.ctx,
req: req,
r := &rangeRetryReader{
base: t.base,
req: req,
}

return r.reset(nil)
}

type rangeRetryReader struct {
client *http.Client
ctx context.Context

req *http.Request
base http.RoundTripper
req *http.Request

body io.ReadCloser

progress int64
total int64
}

func (r *rangeRetryReader) reset(oerr error) (*http.Response, error) {
Expand All @@ -62,14 +57,13 @@ func (r *rangeRetryReader) reset(oerr error) (*http.Response, error) {
_ = r.body.Close()
}

req := r.req.WithContext(r.ctx)
req := r.req.WithContext(r.req.Context())

rangeHeader := fmt.Sprintf("bytes=%d-", r.progress)
if r.progress != 0 {
req.Header.Set("Range", rangeHeader)
req.Header.Set("Range", fmt.Sprintf("bytes=%d-", r.progress))
}

resp, err := r.client.Do(req)
resp, err := r.base.RoundTrip(req)
if err != nil {
return resp, errors.Join(oerr, err)
}
Expand All @@ -78,10 +72,6 @@ func (r *rangeRetryReader) reset(oerr error) (*http.Response, error) {
return resp, nil
}

if r.total == 0 {
r.total = resp.ContentLength
}

if resp.StatusCode == http.StatusOK {
// If the upstream doesn't support Range requests for some reason and only returns 200,
// we need to discard anything we've already Read().
Expand All @@ -91,11 +81,11 @@ func (r *rangeRetryReader) reset(oerr error) (*http.Response, error) {
}
}
} else if resp.StatusCode != http.StatusPartialContent {
if oerr != nil {
return resp, fmt.Errorf("retrying %w: %s %s (Range: %s): unexpected status code: %d", oerr, req.Method, req.URL.String(), rangeHeader, resp.StatusCode)
if r.progress != 0 {
return resp, fmt.Errorf("retrying %w: %s %s (Range: %s): unexpected status code: %d", oerr, req.Method, req.URL.String(), req.Header.Get("Range"), resp.StatusCode)
}

return resp, fmt.Errorf("%s %s (Range: %s): unexpected status code: %d", req.Method, req.URL.String(), rangeHeader, resp.StatusCode)
return resp, fmt.Errorf("%s %s: unexpected status code: %d", req.Method, req.URL.String(), resp.StatusCode)
}

r.body = resp.Body
Expand Down
3 changes: 1 addition & 2 deletions pkg/apk/apk/transport_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ package apk

import (
"bytes"
"context"
"fmt"
"io"
"net/http"
Expand Down Expand Up @@ -166,7 +165,7 @@ func TestTransport(t *testing.T) {
ranges: tc.ranges,
}

rt := newRangeRetryTransport(context.Background(), &http.Client{Transport: tt})
rt := NewRangeRetryTransport(tt)

req := &http.Request{
URL: &url.URL{},
Expand Down
Loading