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
10 changes: 10 additions & 0 deletions paramfetch.go
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,12 @@ func (ft *fetch) maybeFetchAsync(ctx context.Context, name string, info paramFil
ft.fetchLk.Lock()
defer ft.fetchLk.Unlock()

// Re-check after acquiring the in-process mutex — another goroutine
// may have already fetched the file while we waited.
if err := ft.checkFile(path, info); err == nil {
return
}

var lockfail bool
var unlocker io.Closer
for {
Expand Down Expand Up @@ -275,6 +281,10 @@ func doFetch(ctx context.Context, out string, info paramFile) error {
}
defer resp.Body.Close()

if resp.StatusCode != http.StatusOK && resp.StatusCode != http.StatusPartialContent {
return xerrors.Errorf("fetching file from %s: %s", url, resp.Status)
}

bar := pb.New64(fStat.Size() + resp.ContentLength).
SetCurrent(fStat.Size()).Start()

Expand Down
46 changes: 46 additions & 0 deletions paramfetch_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,12 @@ package paramfetch
import (
"context"
"encoding/json"
"fmt"
"net/http"
"net/http/httptest"
"os"
"path/filepath"
"strings"
"testing"

logging "github.com/ipfs/go-log/v2"
Expand Down Expand Up @@ -93,3 +97,45 @@ func TestCheckFileIgnoresUntrustableExtension(t *testing.T) {
err = ft.checkFile(filepath.Join(".", "also_check_and_fail.srs"), mockParamInfo)
assert.Error(t, err)
}

func TestDoFetchBadStatusCode(t *testing.T) {
cases := []struct {
name string
code int
}{
{"BadRequest", http.StatusBadRequest},
{"Forbidden", http.StatusForbidden},
{"NotFound", http.StatusNotFound},
{"InternalServerError", http.StatusInternalServerError},
{"BadGateway", http.StatusBadGateway},
{"ServiceUnavailable", http.StatusServiceUnavailable},
}

for _, tc := range cases {
t.Run(tc.name, func(t *testing.T) {
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(tc.code)
}))
defer ts.Close()

t.Setenv("IPFS_GATEWAY", ts.URL+"/ipfs/")

tmpDir := t.TempDir()
outPath := filepath.Join(tmpDir, "test-param-file")

info := paramFile{
Cid: "QmFakeCid",
Digest: "0000000000000000",
}

err := doFetch(context.Background(), outPath, info)
require.Error(t, err)

errMsg := fmt.Sprintf("%v", err)
assert.True(t, strings.Contains(errMsg, fmt.Sprintf("%d", tc.code)),
"error should contain HTTP status code %d, got: %s", tc.code, errMsg)
assert.False(t, strings.Contains(errMsg, "checksum"),
"error should not mention checksum mismatch, got: %s", errMsg)
})
}
}