Skip to content

Commit 5b959d1

Browse files
committed
Preserve Go proxy fallback for missing modules
Return the repository-standard not-found response when an upstream module is absent. Constraint: GOPROXY advances to direct only after 404 or 410 responses. Rejected: Preserve a handler-specific response body | sibling handlers consistently use not found. Confidence: high Scope-risk: narrow Directive: Keep missing-artifact responses consistent across registry handlers. Tested: go test ./internal/handler -run TestGoModuleDownloadUpstreamErrors -count=1; prior go test -race ./...; go build ./...; golangci-lint; go vet.
1 parent 18c711b commit 5b959d1

2 files changed

Lines changed: 47 additions & 0 deletions

File tree

internal/handler/go.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,12 @@
11
package handler
22

33
import (
4+
"errors"
45
"fmt"
56
"net/http"
67
"strings"
8+
9+
"github.com/git-pkgs/registries/fetch"
710
)
811

912
const (
@@ -100,6 +103,10 @@ func (h *GoHandler) handleDownload(w http.ResponseWriter, r *http.Request, modul
100103

101104
result, err := h.proxy.GetOrFetchArtifact(r.Context(), "golang", decodedModule, version, filename)
102105
if err != nil {
106+
if errors.Is(err, fetch.ErrNotFound) {
107+
http.Error(w, "not found", http.StatusNotFound)
108+
return
109+
}
103110
h.proxy.Logger.Error("failed to get artifact", "error", err)
104111
http.Error(w, "failed to fetch module", http.StatusBadGateway)
105112
return

internal/handler/go_test.go

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,49 @@
11
package handler
22

33
import (
4+
"errors"
5+
"net/http"
6+
"net/http/httptest"
47
"testing"
8+
9+
"github.com/git-pkgs/registries/fetch"
510
)
611

12+
func TestGoModuleDownloadUpstreamErrors(t *testing.T) {
13+
tests := []struct {
14+
name string
15+
fetchErr error
16+
wantStatus int
17+
}{
18+
{
19+
name: "module not found",
20+
fetchErr: fetch.ErrNotFound,
21+
wantStatus: http.StatusNotFound,
22+
},
23+
{
24+
name: "upstream failure",
25+
fetchErr: errors.New("connection refused"),
26+
wantStatus: http.StatusBadGateway,
27+
},
28+
}
29+
30+
for _, tt := range tests {
31+
t.Run(tt.name, func(t *testing.T) {
32+
proxy, _, _, fetcher := setupTestProxy(t)
33+
fetcher.fetchErr = tt.fetchErr
34+
handler := NewGoHandler(proxy, "http://localhost:8080")
35+
36+
req := httptest.NewRequest(http.MethodGet, "/example.com/mod/@v/v1.0.0.zip", nil)
37+
resp := httptest.NewRecorder()
38+
handler.Routes().ServeHTTP(resp, req)
39+
40+
if resp.Code != tt.wantStatus {
41+
t.Fatalf("status = %d, want %d", resp.Code, tt.wantStatus)
42+
}
43+
})
44+
}
45+
}
46+
747
func TestDecodeGoModule(t *testing.T) {
848
tests := []struct {
949
encoded string

0 commit comments

Comments
 (0)