diff --git a/registry/storage/driver/middleware/redirect/middleware.go b/registry/storage/driver/middleware/redirect/middleware.go index 44433e9a1..9e1b303ea 100644 --- a/registry/storage/driver/middleware/redirect/middleware.go +++ b/registry/storage/driver/middleware/redirect/middleware.go @@ -4,6 +4,7 @@ import ( "context" "fmt" "net/url" + "path" storagedriver "github.com/distribution/distribution/v3/registry/storage/driver" storagemiddleware "github.com/distribution/distribution/v3/registry/storage/driver/middleware" @@ -11,8 +12,9 @@ import ( type redirectStorageMiddleware struct { storagedriver.StorageDriver - scheme string - host string + scheme string + host string + basePath string } var _ storagedriver.StorageDriver = &redirectStorageMiddleware{} @@ -37,11 +39,14 @@ func newRedirectStorageMiddleware(sd storagedriver.StorageDriver, options map[st return nil, fmt.Errorf("no host specified for redirect baseurl") } - return &redirectStorageMiddleware{StorageDriver: sd, scheme: u.Scheme, host: u.Host}, nil + return &redirectStorageMiddleware{StorageDriver: sd, scheme: u.Scheme, host: u.Host, basePath: u.Path}, nil } -func (r *redirectStorageMiddleware) URLFor(ctx context.Context, path string, options map[string]interface{}) (string, error) { - u := &url.URL{Scheme: r.scheme, Host: r.host, Path: path} +func (r *redirectStorageMiddleware) URLFor(ctx context.Context, urlPath string, options map[string]interface{}) (string, error) { + if r.basePath != "" { + urlPath = path.Join(r.basePath, urlPath) + } + u := &url.URL{Scheme: r.scheme, Host: r.host, Path: urlPath} return u.String(), nil } diff --git a/registry/storage/driver/middleware/redirect/middleware_test.go b/registry/storage/driver/middleware/redirect/middleware_test.go index afa7bafad..30d0bb192 100644 --- a/registry/storage/driver/middleware/redirect/middleware_test.go +++ b/registry/storage/driver/middleware/redirect/middleware_test.go @@ -57,3 +57,46 @@ func (s *MiddlewareSuite) TestHTTP(c *check.C) { c.Assert(err, check.Equals, nil) c.Assert(url, check.Equals, "http://example.com/morty/data") } + +func (s *MiddlewareSuite) TestPath(c *check.C) { + // basePath: end with no slash + options := make(map[string]interface{}) + options["baseurl"] = "https://example.com/path" + middleware, err := newRedirectStorageMiddleware(nil, options) + c.Assert(err, check.Equals, nil) + + m, ok := middleware.(*redirectStorageMiddleware) + c.Assert(ok, check.Equals, true) + c.Assert(m.scheme, check.Equals, "https") + c.Assert(m.host, check.Equals, "example.com") + c.Assert(m.basePath, check.Equals, "/path") + + // call URLFor() with no leading slash + url, err := middleware.URLFor(context.TODO(), "morty/data", nil) + c.Assert(err, check.Equals, nil) + c.Assert(url, check.Equals, "https://example.com/path/morty/data") + // call URLFor() with leading slash + url, err = middleware.URLFor(context.TODO(), "/morty/data", nil) + c.Assert(err, check.Equals, nil) + c.Assert(url, check.Equals, "https://example.com/path/morty/data") + + // basePath: end with slash + options["baseurl"] = "https://example.com/path/" + middleware, err = newRedirectStorageMiddleware(nil, options) + c.Assert(err, check.Equals, nil) + + m, ok = middleware.(*redirectStorageMiddleware) + c.Assert(ok, check.Equals, true) + c.Assert(m.scheme, check.Equals, "https") + c.Assert(m.host, check.Equals, "example.com") + c.Assert(m.basePath, check.Equals, "/path/") + + // call URLFor() with no leading slash + url, err = middleware.URLFor(context.TODO(), "morty/data", nil) + c.Assert(err, check.Equals, nil) + c.Assert(url, check.Equals, "https://example.com/path/morty/data") + // call URLFor() with leading slash + url, err = middleware.URLFor(context.TODO(), "/morty/data", nil) + c.Assert(err, check.Equals, nil) + c.Assert(url, check.Equals, "https://example.com/path/morty/data") +}