diff --git a/src/server/middleware/middleware.go b/src/server/middleware/middleware.go new file mode 100644 index 000000000..dfbe1714c --- /dev/null +++ b/src/server/middleware/middleware.go @@ -0,0 +1,22 @@ +// Copyright Project Harbor Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package middleware + +import "net/http" + +// Middleware receives a handler and returns another handler +// the returned handler can do some customized task according to +// the requirement +type Middleware func(http.Handler) http.Handler diff --git a/src/server/v2.0/registry/catalog/catalog.go b/src/server/v2.0/registry/catalog/catalog.go new file mode 100644 index 000000000..44882df00 --- /dev/null +++ b/src/server/v2.0/registry/catalog/catalog.go @@ -0,0 +1,32 @@ +// Copyright Project Harbor Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package catalog + +import "net/http" + +// NewHandler returns the handler to handler catalog request +func NewHandler() http.Handler { + return &handler{} +} + +type handler struct{} + +func (h *handler) ServeHTTP(w http.ResponseWriter, req *http.Request) { + // TODO implement +} + +type catalogResponse struct { + Repositories []string `json:"repositories"` +} diff --git a/src/server/v2.0/registry/handler.go b/src/server/v2.0/registry/handler.go new file mode 100644 index 000000000..25980236e --- /dev/null +++ b/src/server/v2.0/registry/handler.go @@ -0,0 +1,65 @@ +// Copyright Project Harbor Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package registry + +import ( + "net/http" + "net/http/httputil" + "net/url" + + "github.com/goharbor/harbor/src/server/v2.0/registry/catalog" + "github.com/goharbor/harbor/src/server/v2.0/registry/manifest" + "github.com/goharbor/harbor/src/server/v2.0/registry/tag" + "github.com/gorilla/mux" +) + +// New return the registry instance to handle the registry APIs +func New(url *url.URL) http.Handler { + // TODO add a director to add the basic auth for docker registry + // TODO customize the reverse proxy to improve the performance? + proxy := httputil.NewSingleHostReverseProxy(url) + + // create the root rooter + rootRouter := mux.NewRouter() + rootRouter.StrictSlash(true) + + // handle catalog + rootRouter.Path("/v2/_catalog").Methods(http.MethodGet).Handler(catalog.NewHandler()) + + // handle list tag + rootRouter.Path("/v2/{name}/tags/list").Methods(http.MethodGet).Handler(tag.NewHandler()) + + // handle manifest + // TODO maybe we should split it into several sub routers based on the method + manifestRouter := rootRouter.Path("/v2/{name}/manifests/{reference}").Subrouter() + manifestRouter.NewRoute().Methods(http.MethodGet, http.MethodHead, http.MethodPut, http.MethodDelete). + Handler(manifest.NewHandler(proxy)) + + // handle blob + // as we need to apply middleware to the blob requests, so create a sub router to handle the blob APIs + blobRouter := rootRouter.Path("/v2/{name}/blobs/").Subrouter() + blobRouter.NewRoute().Methods(http.MethodGet, http.MethodHead, http.MethodPost, http.MethodPut, http.MethodPatch, http.MethodDelete). + Handler(proxy) + + // all other APIs are proxy to the backend docker registry + rootRouter.PathPrefix("/").Handler(proxy) + + // register middlewares + // TODO add auth middleware + // TODO apply the existing middlewares + // rootRouter.Use(mux.MiddlewareFunc(middleware)) + + return rootRouter +} diff --git a/src/server/v2.0/registry/manifest/manifest.go b/src/server/v2.0/registry/manifest/manifest.go new file mode 100644 index 000000000..7011ac320 --- /dev/null +++ b/src/server/v2.0/registry/manifest/manifest.go @@ -0,0 +1,64 @@ +// Copyright Project Harbor Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package manifest + +import ( + "net/http" + "net/http/httputil" +) + +// NewHandler returns the handler to handler manifest requests +func NewHandler(proxy *httputil.ReverseProxy) http.Handler { + return &handler{ + proxy: proxy, + } +} + +type handler struct { + proxy *httputil.ReverseProxy +} + +func (h *handler) ServeHTTP(w http.ResponseWriter, req *http.Request) { + switch req.Method { + case http.MethodHead: + h.head(w, req) + case http.MethodGet: + h.get(w, req) + case http.MethodDelete: + h.delete(w, req) + case http.MethodPut: + h.put(w, req) + } +} + +// make sure the artifact exist before proxying the request to the backend registry +func (h *handler) head(w http.ResponseWriter, req *http.Request) { + // TODO check the existence + h.proxy.ServeHTTP(w, req) +} + +// make sure the artifact exist before proxying the request to the backend registry +func (h *handler) get(w http.ResponseWriter, req *http.Request) { + // TODO check the existence + h.proxy.ServeHTTP(w, req) +} + +func (h *handler) delete(w http.ResponseWriter, req *http.Request) { + // TODO implement, just delete from database +} + +func (h *handler) put(w http.ResponseWriter, req *http.Request) { + h.proxy.ServeHTTP(w, req) +} diff --git a/src/server/v2.0/registry/tag/tag.go b/src/server/v2.0/registry/tag/tag.go new file mode 100644 index 000000000..d7ae2ab8c --- /dev/null +++ b/src/server/v2.0/registry/tag/tag.go @@ -0,0 +1,36 @@ +// Copyright Project Harbor Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package tag + +import ( + "net/http" +) + +// NewHandler returns the handler to handle listing tag request +func NewHandler() http.Handler { + return &handler{} +} + +type handler struct{} + +func (h *handler) ServeHTTP(w http.ResponseWriter, req *http.Request) { + // TODO implement + // support pagination, this is required for OCI registry spec +} + +type listTagResponse struct { + Name string `json:"name"` + Tags []string `json:"tags"` +}