mirror of https://github.com/harness/drone.git
feat: [AH-783]: Added middleware for original URL (#3221)
* [AH-783]: Updated method names * [AH-783]: Lint fixed * [AH-783]: Added middleware for original URLBT-10437
parent
dec251e385
commit
0ac9a3aac1
|
@ -17,7 +17,6 @@ package oci
|
|||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strings"
|
||||
|
||||
usercontroller "github.com/harness/gitness/app/api/controller/user"
|
||||
|
@ -27,11 +26,13 @@ import (
|
|||
urlprovider "github.com/harness/gitness/app/url"
|
||||
"github.com/harness/gitness/registry/app/api/controller/metadata"
|
||||
"github.com/harness/gitness/registry/app/api/openapi/contracts/artifact"
|
||||
"github.com/harness/gitness/registry/app/common"
|
||||
"github.com/harness/gitness/registry/app/dist_temp/dcontext"
|
||||
"github.com/harness/gitness/registry/app/dist_temp/errcode"
|
||||
"github.com/harness/gitness/registry/app/pkg"
|
||||
"github.com/harness/gitness/registry/app/pkg/commons"
|
||||
"github.com/harness/gitness/registry/app/pkg/docker"
|
||||
"github.com/harness/gitness/registry/request"
|
||||
|
||||
v2 "github.com/distribution/distribution/v3/registry/api/v2"
|
||||
"github.com/opencontainers/go-digest"
|
||||
|
@ -110,16 +111,6 @@ func getRouteType(url string) routeType {
|
|||
return Invalid
|
||||
}
|
||||
|
||||
func GetQueryParamMap(queryParams url.Values) map[string]string {
|
||||
queryMap := make(map[string]string)
|
||||
for key, values := range queryParams {
|
||||
if len(values) > 0 {
|
||||
queryMap[key] = values[0]
|
||||
}
|
||||
}
|
||||
return queryMap
|
||||
}
|
||||
|
||||
// ExtractPathVars extracts registry, image, reference, digest and tag from the path
|
||||
// Path format: /v2/:rootSpace/:registry/:image/manifests/:reference (for ex:
|
||||
// /v2/myRootSpace/reg1/alpine/blobs/sha256:a258b2a6b59a7aa244d8ceab095c7f8df726f27075a69fca7ad8490f3f63148a).
|
||||
|
@ -178,11 +169,24 @@ func handleErrors(ctx context.Context, errors errcode.Errors, w http.ResponseWri
|
|||
}
|
||||
}
|
||||
|
||||
func getPathRoot(ctx context.Context) string {
|
||||
originalURL := request.OriginalURLFrom(ctx)
|
||||
pathRoot := ""
|
||||
if originalURL != "" {
|
||||
originalURL = strings.Trim(originalURL, "/")
|
||||
segments := strings.Split(originalURL, "/")
|
||||
if len(segments) > 1 {
|
||||
pathRoot = segments[1]
|
||||
}
|
||||
}
|
||||
return pathRoot
|
||||
}
|
||||
|
||||
func (h *Handler) GetRegistryInfo(r *http.Request, remoteSupport bool) (pkg.RegistryInfo, error) {
|
||||
ctx := r.Context()
|
||||
queryParams := r.URL.Query()
|
||||
path := r.URL.Path
|
||||
paramMap := GetQueryParamMap(queryParams)
|
||||
paramMap := common.ExtractFirstQueryParams(queryParams)
|
||||
rootIdentifier, registryIdentifier, image, ref, dgst, tag := ExtractPathVars(path, paramMap)
|
||||
if err := metadata.ValidateIdentifier(rootIdentifier); err != nil {
|
||||
return pkg.RegistryInfo{}, err
|
||||
|
@ -207,9 +211,12 @@ func (h *Handler) GetRegistryInfo(r *http.Request, remoteSupport bool) (pkg.Regi
|
|||
return pkg.RegistryInfo{}, errcode.ErrCodeParentNotFound
|
||||
}
|
||||
|
||||
pathRoot := getPathRoot(r.Context())
|
||||
|
||||
info := &pkg.RegistryInfo{
|
||||
ArtifactInfo: &pkg.ArtifactInfo{
|
||||
BaseInfo: &pkg.BaseInfo{
|
||||
PathRoot: pathRoot,
|
||||
RootIdentifier: rootIdentifier,
|
||||
RootParentID: rootSpace.ID,
|
||||
ParentID: registry.ParentID,
|
||||
|
|
|
@ -101,7 +101,7 @@ func getScope(r *http.Request) string {
|
|||
var scope string
|
||||
path := r.URL.Path
|
||||
if path != "/v2/" && path != "/v2/token" {
|
||||
paramMap := oci.GetQueryParamMap(r.URL.Query())
|
||||
paramMap := common.ExtractFirstQueryParams(r.URL.Query())
|
||||
rootIdentifier, registryIdentifier, _, _, _, _ := oci.ExtractPathVars(path, paramMap)
|
||||
var access []registryauth.Access
|
||||
access = registryauth.AppendAccess(access, r.Method, rootIdentifier+"/"+registryIdentifier)
|
||||
|
|
|
@ -0,0 +1,29 @@
|
|||
// Copyright 2023 Harness, Inc.
|
||||
//
|
||||
// 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"
|
||||
|
||||
"github.com/harness/gitness/registry/request"
|
||||
)
|
||||
|
||||
// StoreOriginalURL stores the original URL in the context.
|
||||
func StoreOriginalURL(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
ctx := request.WithOriginalURL(r.Context(), r.URL.Path)
|
||||
next.ServeHTTP(w, r.WithContext(ctx))
|
||||
})
|
||||
}
|
|
@ -71,7 +71,9 @@ func NewOCIHandler(handlerV2 *oci.Handler) RegistryOCIHandler {
|
|||
http.MethodGet: NewHandlerBlock2(handlerV2.GetReferrers, false),
|
||||
},
|
||||
}
|
||||
|
||||
r.Route("/v2", func(r chi.Router) {
|
||||
r.Use(middleware.StoreOriginalURL)
|
||||
r.Use(middlewareauthn.Attempt(handlerV2.Authenticator))
|
||||
r.Get("/token", func(w http.ResponseWriter, req *http.Request) {
|
||||
handlerV2.GetToken(w, req)
|
||||
|
|
|
@ -70,3 +70,13 @@ func TrimURLScheme(urlStr string) string {
|
|||
// Reconstruct the URL string without the scheme
|
||||
return strings.TrimPrefix(u.String(), "//")
|
||||
}
|
||||
|
||||
func ExtractFirstQueryParams(queryParams url.Values) map[string]string {
|
||||
queryMap := make(map[string]string)
|
||||
for key, values := range queryParams {
|
||||
if len(values) > 0 {
|
||||
queryMap[key] = values[0]
|
||||
}
|
||||
}
|
||||
return queryMap
|
||||
}
|
||||
|
|
|
@ -19,6 +19,7 @@ import (
|
|||
)
|
||||
|
||||
type BaseInfo struct {
|
||||
PathRoot string
|
||||
ParentID int64
|
||||
RootIdentifier string
|
||||
RootParentID int64
|
||||
|
|
|
@ -776,7 +776,7 @@ func (r *LocalRegistry) PutManifest(
|
|||
}
|
||||
|
||||
// Construct a canonical url for the uploaded manifest.
|
||||
name, _ := reference.WithName(fmt.Sprintf("%s/%s", artInfo.RegIdentifier, artInfo.Image))
|
||||
name, _ := reference.WithName(fmt.Sprintf("%s/%s/%s", artInfo.PathRoot, artInfo.RegIdentifier, artInfo.Image))
|
||||
canonicalRef, err := reference.WithDigest(name, d)
|
||||
if err != nil {
|
||||
errs = append(errs, errcode.ErrCodeUnknown.WithDetail(err))
|
||||
|
@ -1414,7 +1414,7 @@ func writeBlobCreatedHeaders(
|
|||
headers *commons.ResponseHeaders,
|
||||
info pkg.RegistryInfo,
|
||||
) error {
|
||||
path, err := reference.WithName(fmt.Sprintf("%s/%s/%s", info.RootIdentifier, info.RegIdentifier, info.Image))
|
||||
path, err := reference.WithName(fmt.Sprintf("%s/%s/%s", info.PathRoot, info.RegIdentifier, info.Image))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -1458,7 +1458,7 @@ func blobUploadResponse(
|
|||
return err
|
||||
}
|
||||
image := info.Image
|
||||
path, err := reference.WithName(fmt.Sprintf("%s/%s/%s", info.RootIdentifier, repoKey, image))
|
||||
path, err := reference.WithName(fmt.Sprintf("%s/%s/%s", info.PathRoot, repoKey, image))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -213,7 +213,7 @@ func (r *RemoteRegistry) ManifestExist(
|
|||
localRegistryIdentifier := ExtractRegistryIdentifierFromPath(artInfo.Path)
|
||||
responseHeaders.Code = http.StatusMovedPermanently
|
||||
responseHeaders.Headers = map[string]string{
|
||||
"Location": defaultManifestURL(artInfo.RootIdentifier, localRegistryIdentifier, artInfo.Image,
|
||||
"Location": defaultManifestURL(artInfo.PathRoot, localRegistryIdentifier, artInfo.Image,
|
||||
registryInfo),
|
||||
}
|
||||
return responseHeaders, descriptor, manifestResult, errs
|
||||
|
@ -304,7 +304,7 @@ func (r *RemoteRegistry) PullManifest(
|
|||
localRegistryIdentifier := ExtractRegistryIdentifierFromPath(artInfo.Path)
|
||||
responseHeaders.Code = http.StatusMovedPermanently
|
||||
responseHeaders.Headers = map[string]string{
|
||||
"Location": defaultManifestURL(artInfo.RootIdentifier, localRegistryIdentifier, artInfo.Image,
|
||||
"Location": defaultManifestURL(artInfo.PathRoot, localRegistryIdentifier, artInfo.Image,
|
||||
registryInfo),
|
||||
}
|
||||
return responseHeaders, descriptor, manifestResult, errs
|
||||
|
@ -424,7 +424,7 @@ func (r *RemoteRegistry) fetchBlobInternal(
|
|||
localRegistryIdentifier := ExtractRegistryIdentifierFromPath(info.Path)
|
||||
responseHeaders.Code = http.StatusMovedPermanently
|
||||
responseHeaders.Headers = map[string]string{
|
||||
"Location": defaultBlobURL(info.RootIdentifier, localRegistryIdentifier, info.Image, info.Digest),
|
||||
"Location": defaultBlobURL(info.PathRoot, localRegistryIdentifier, info.Image, info.Digest),
|
||||
}
|
||||
return responseHeaders, fr, size, readCloser, redirectURL, errs
|
||||
}
|
||||
|
|
|
@ -0,0 +1,37 @@
|
|||
// Copyright 2023 Harness, Inc.
|
||||
//
|
||||
// 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 request
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/rs/zerolog/log"
|
||||
)
|
||||
|
||||
type contextKey string
|
||||
|
||||
const OriginalURLKey contextKey = "originalURL"
|
||||
|
||||
func OriginalURLFrom(ctx context.Context) string {
|
||||
originalURL, ok := ctx.Value(OriginalURLKey).(string)
|
||||
if !ok {
|
||||
log.Ctx(ctx).Warn().Msg("Original URL not found in context")
|
||||
}
|
||||
return originalURL
|
||||
}
|
||||
|
||||
func WithOriginalURL(parent context.Context, originalURL string) context.Context {
|
||||
return context.WithValue(parent, OriginalURLKey, originalURL)
|
||||
}
|
Loading…
Reference in New Issue