diff --git a/README.md b/README.md index 0ef6eac3..3116cef5 100644 --- a/README.md +++ b/README.md @@ -28,6 +28,8 @@ Powered by some great Go technology: - `GET /index.yaml` - retrieved when you run `helm repo add chartmuseum http://localhost:8080/` - `GET /charts/mychart-0.1.0.tgz` - retrieved when you run `helm install chartmuseum/mychart` - `GET /charts/mychart-0.1.0.tgz.prov` - retrieved when you run `helm install` with the `--verify` flag +- `HEAD` requests for the above routes are also supported; they are **not** used in `helm`, + but they might be used by hubs like JFrog Artifactory ### Chart Manipulation - `POST /api/charts` - upload a new chart version diff --git a/pkg/chartmuseum/server/multitenant/handlers.go b/pkg/chartmuseum/server/multitenant/handlers.go index 6743b82b..b3c99a4c 100644 --- a/pkg/chartmuseum/server/multitenant/handlers.go +++ b/pkg/chartmuseum/server/multitenant/handlers.go @@ -146,17 +146,31 @@ func (server *MultiTenantServer) getArtifactHubFileRequestHandler(c *gin.Context c.Data(200, artifactHubFileContentType, artifactHubFile) } -func (server *MultiTenantServer) getStorageObjectRequestHandler(c *gin.Context) { +func (server *MultiTenantServer) getStorageObjectRequestImpl(c *gin.Context) (*StorageObject, *HTTPError) { repo := c.Param("repo") filename := c.Param("filename") log := server.Logger.ContextLoggingFn(c) - storageObject, err := server.getStorageObject(log, repo, filename) + return server.getStorageObject(log, repo, filename) +} + +func (server *MultiTenantServer) getStorageObjectRequestHandler(c *gin.Context) { + storageObject, err := server.getStorageObjectRequestImpl(c) if err != nil { c.JSON(err.Status, gin.H{"error": err.Message}) return } c.Data(200, storageObject.ContentType, storageObject.Content) } + +func (server *MultiTenantServer) headStorageObjectRequestHandler(c *gin.Context) { + _, err := server.getStorageObjectRequestImpl(c) + if err != nil { + c.Status(err.Status) + return + } + c.Status(200) +} + func (server *MultiTenantServer) getStorageObjectTemplateRequestHandler(c *gin.Context) { repo := c.Param("repo") name := c.Param("name") diff --git a/pkg/chartmuseum/server/multitenant/routes.go b/pkg/chartmuseum/server/multitenant/routes.go index 77a673a4..6e833a59 100644 --- a/pkg/chartmuseum/server/multitenant/routes.go +++ b/pkg/chartmuseum/server/multitenant/routes.go @@ -39,6 +39,7 @@ func (s *MultiTenantServer) Routes() []*cm_router.Route { {Method: "GET", Path: "/:repo/index.yaml", Handler: s.getIndexFileRequestHandler, Action: cm_auth.PullAction}, {Method: "HEAD", Path: "/:repo/index.yaml", Handler: s.headIndexFileRequestHandler, Action: cm_auth.PullAction}, {Method: "GET", Path: "/:repo/charts/:filename", Handler: s.getStorageObjectRequestHandler, Action: cm_auth.PullAction}, + {Method: "HEAD", Path: "/:repo/charts/:filename", Handler: s.headStorageObjectRequestHandler, Action: cm_auth.PullAction}, } chartManipulationRoutes := []*cm_router.Route{ diff --git a/pkg/chartmuseum/server/multitenant/server_test.go b/pkg/chartmuseum/server/multitenant/server_test.go index df713f0c..85e90b53 100644 --- a/pkg/chartmuseum/server/multitenant/server_test.go +++ b/pkg/chartmuseum/server/multitenant/server_test.go @@ -1108,6 +1108,13 @@ func (suite *MultiTenantServerTestSuite) testAllRoutes(repo string, depth int) { res = suite.doRequest(stype, "GET", fmt.Sprintf("%s/charts/fakechart-0.1.0.bad", repoPrefix), nil, "") suite.Equal(500, res.Status(), fmt.Sprintf("500 GET %s/charts/fakechart-0.1.0.bad", repoPrefix)) + // HEAD /:repo/charts/:filename + res = suite.doRequest(stype, "HEAD", fmt.Sprintf("%s/charts/mychart-0.1.0.tgz", repoPrefix), nil, "") + suite.Equal(200, res.Status(), fmt.Sprintf("200 GET %s/charts/mychart-0.1.0.tgz", repoPrefix)) + + res = suite.doRequest(stype, "HEAD", fmt.Sprintf("%s/charts/fakechart-0.1.0.bad", repoPrefix), nil, "") + suite.Equal(500, res.Status(), fmt.Sprintf("500 GET %s/charts/fakechart-0.1.0.bad", repoPrefix)) + apiPrefix := pathutil.Join("/api", repo) // GET /api/:repo/charts