2022-03-30 11:42:47 +03:00
// Copyright 2022 The Gitea Authors. All rights reserved.
2022-11-27 21:20:29 +03:00
// SPDX-License-Identifier: MIT
2022-03-30 11:42:47 +03:00
package packages
import (
2022-08-28 12:43:25 +03:00
gocontext "context"
2022-03-30 11:42:47 +03:00
"net/http"
"regexp"
"strings"
"code.gitea.io/gitea/models/perm"
"code.gitea.io/gitea/modules/context"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/web"
"code.gitea.io/gitea/routers/api/packages/composer"
"code.gitea.io/gitea/routers/api/packages/conan"
"code.gitea.io/gitea/routers/api/packages/container"
"code.gitea.io/gitea/routers/api/packages/generic"
2022-04-19 19:55:35 +03:00
"code.gitea.io/gitea/routers/api/packages/helm"
2022-03-30 11:42:47 +03:00
"code.gitea.io/gitea/routers/api/packages/maven"
"code.gitea.io/gitea/routers/api/packages/npm"
"code.gitea.io/gitea/routers/api/packages/nuget"
2022-08-07 13:09:54 +03:00
"code.gitea.io/gitea/routers/api/packages/pub"
2022-03-30 11:42:47 +03:00
"code.gitea.io/gitea/routers/api/packages/pypi"
"code.gitea.io/gitea/routers/api/packages/rubygems"
2022-08-29 10:04:45 +03:00
"code.gitea.io/gitea/routers/api/packages/vagrant"
2022-03-30 11:42:47 +03:00
"code.gitea.io/gitea/services/auth"
context_service "code.gitea.io/gitea/services/context"
)
func reqPackageAccess ( accessMode perm . AccessMode ) func ( ctx * context . Context ) {
return func ( ctx * context . Context ) {
if ctx . Package . AccessMode < accessMode && ! ctx . IsUserSiteAdmin ( ) {
ctx . Resp . Header ( ) . Set ( "WWW-Authenticate" , ` Basic realm="Gitea Package API" ` )
ctx . Error ( http . StatusUnauthorized , "reqPackageAccess" , "user should have specific permission or be a site admin" )
return
}
}
}
2022-11-12 21:59:15 +03:00
// CommonRoutes provide endpoints for most package managers (except containers - see below)
// These are mounted on `/api/packages` (not `/api/v1/packages`)
func CommonRoutes ( ctx gocontext . Context ) * web . Route {
2022-03-30 11:42:47 +03:00
r := web . NewRoute ( )
2022-08-28 12:43:25 +03:00
r . Use ( context . PackageContexter ( ctx ) )
2022-03-30 11:42:47 +03:00
authMethods := [ ] auth . Method {
& auth . OAuth2 { } ,
& auth . Basic { } ,
2022-08-09 17:36:49 +03:00
& nuget . Auth { } ,
2022-03-30 11:42:47 +03:00
& conan . Auth { } ,
}
if setting . Service . EnableReverseProxyAuth {
authMethods = append ( authMethods , & auth . ReverseProxy { } )
}
authGroup := auth . NewGroup ( authMethods ... )
r . Use ( func ( ctx * context . Context ) {
ctx . Doer = authGroup . Verify ( ctx . Req , ctx . Resp , ctx , ctx . Session )
2022-10-24 22:23:25 +03:00
ctx . IsSigned = ctx . Doer != nil
2022-03-30 11:42:47 +03:00
} )
r . Group ( "/{username}" , func ( ) {
r . Group ( "/composer" , func ( ) {
r . Get ( "/packages.json" , composer . ServiceIndex )
r . Get ( "/search.json" , composer . SearchPackages )
r . Get ( "/list.json" , composer . EnumeratePackages )
r . Get ( "/p2/{vendorname}/{projectname}~dev.json" , composer . PackageMetadata )
r . Get ( "/p2/{vendorname}/{projectname}.json" , composer . PackageMetadata )
r . Get ( "/files/{package}/{version}/{filename}" , composer . DownloadPackageFile )
r . Put ( "" , reqPackageAccess ( perm . AccessModeWrite ) , composer . UploadPackage )
2022-09-24 18:17:08 +03:00
} , reqPackageAccess ( perm . AccessModeRead ) )
2022-03-30 11:42:47 +03:00
r . Group ( "/conan" , func ( ) {
r . Group ( "/v1" , func ( ) {
r . Get ( "/ping" , conan . Ping )
r . Group ( "/users" , func ( ) {
r . Get ( "/authenticate" , conan . Authenticate )
r . Get ( "/check_credentials" , conan . CheckCredentials )
} )
r . Group ( "/conans" , func ( ) {
r . Get ( "/search" , conan . SearchRecipes )
r . Group ( "/{name}/{version}/{user}/{channel}" , func ( ) {
r . Get ( "" , conan . RecipeSnapshot )
r . Delete ( "" , reqPackageAccess ( perm . AccessModeWrite ) , conan . DeleteRecipeV1 )
r . Get ( "/search" , conan . SearchPackagesV1 )
r . Get ( "/digest" , conan . RecipeDownloadURLs )
r . Post ( "/upload_urls" , reqPackageAccess ( perm . AccessModeWrite ) , conan . RecipeUploadURLs )
r . Get ( "/download_urls" , conan . RecipeDownloadURLs )
r . Group ( "/packages" , func ( ) {
r . Post ( "/delete" , reqPackageAccess ( perm . AccessModeWrite ) , conan . DeletePackageV1 )
r . Group ( "/{package_reference}" , func ( ) {
r . Get ( "" , conan . PackageSnapshot )
r . Get ( "/digest" , conan . PackageDownloadURLs )
r . Post ( "/upload_urls" , reqPackageAccess ( perm . AccessModeWrite ) , conan . PackageUploadURLs )
r . Get ( "/download_urls" , conan . PackageDownloadURLs )
} )
} )
} , conan . ExtractPathParameters )
} )
r . Group ( "/files/{name}/{version}/{user}/{channel}/{recipe_revision}" , func ( ) {
r . Group ( "/recipe/{filename}" , func ( ) {
r . Get ( "" , conan . DownloadRecipeFile )
r . Put ( "" , reqPackageAccess ( perm . AccessModeWrite ) , conan . UploadRecipeFile )
} )
r . Group ( "/package/{package_reference}/{package_revision}/{filename}" , func ( ) {
r . Get ( "" , conan . DownloadPackageFile )
r . Put ( "" , reqPackageAccess ( perm . AccessModeWrite ) , conan . UploadPackageFile )
} )
} , conan . ExtractPathParameters )
} )
r . Group ( "/v2" , func ( ) {
r . Get ( "/ping" , conan . Ping )
r . Group ( "/users" , func ( ) {
r . Get ( "/authenticate" , conan . Authenticate )
r . Get ( "/check_credentials" , conan . CheckCredentials )
} )
r . Group ( "/conans" , func ( ) {
r . Get ( "/search" , conan . SearchRecipes )
r . Group ( "/{name}/{version}/{user}/{channel}" , func ( ) {
r . Delete ( "" , reqPackageAccess ( perm . AccessModeWrite ) , conan . DeleteRecipeV2 )
r . Get ( "/search" , conan . SearchPackagesV2 )
r . Get ( "/latest" , conan . LatestRecipeRevision )
r . Group ( "/revisions" , func ( ) {
r . Get ( "" , conan . ListRecipeRevisions )
r . Group ( "/{recipe_revision}" , func ( ) {
r . Delete ( "" , reqPackageAccess ( perm . AccessModeWrite ) , conan . DeleteRecipeV2 )
r . Get ( "/search" , conan . SearchPackagesV2 )
r . Group ( "/files" , func ( ) {
r . Get ( "" , conan . ListRecipeRevisionFiles )
r . Group ( "/{filename}" , func ( ) {
r . Get ( "" , conan . DownloadRecipeFile )
r . Put ( "" , reqPackageAccess ( perm . AccessModeWrite ) , conan . UploadRecipeFile )
} )
} )
r . Group ( "/packages" , func ( ) {
r . Delete ( "" , reqPackageAccess ( perm . AccessModeWrite ) , conan . DeletePackageV2 )
r . Group ( "/{package_reference}" , func ( ) {
r . Delete ( "" , reqPackageAccess ( perm . AccessModeWrite ) , conan . DeletePackageV2 )
r . Get ( "/latest" , conan . LatestPackageRevision )
r . Group ( "/revisions" , func ( ) {
r . Get ( "" , conan . ListPackageRevisions )
r . Group ( "/{package_revision}" , func ( ) {
r . Delete ( "" , reqPackageAccess ( perm . AccessModeWrite ) , conan . DeletePackageV2 )
r . Group ( "/files" , func ( ) {
r . Get ( "" , conan . ListPackageRevisionFiles )
r . Group ( "/{filename}" , func ( ) {
r . Get ( "" , conan . DownloadPackageFile )
r . Put ( "" , reqPackageAccess ( perm . AccessModeWrite ) , conan . UploadPackageFile )
} )
} )
} )
} )
} )
} )
} )
} )
} , conan . ExtractPathParameters )
} )
} )
2022-09-24 18:17:08 +03:00
} , reqPackageAccess ( perm . AccessModeRead ) )
2022-03-30 11:42:47 +03:00
r . Group ( "/generic" , func ( ) {
2022-08-09 07:39:24 +03:00
r . Group ( "/{packagename}/{packageversion}" , func ( ) {
r . Delete ( "" , reqPackageAccess ( perm . AccessModeWrite ) , generic . DeletePackage )
r . Group ( "/{filename}" , func ( ) {
r . Get ( "" , generic . DownloadPackageFile )
r . Group ( "" , func ( ) {
r . Put ( "" , generic . UploadPackage )
r . Delete ( "" , generic . DeletePackageFile )
} , reqPackageAccess ( perm . AccessModeWrite ) )
} )
2022-03-30 11:42:47 +03:00
} )
2022-09-24 18:17:08 +03:00
} , reqPackageAccess ( perm . AccessModeRead ) )
2022-04-19 19:55:35 +03:00
r . Group ( "/helm" , func ( ) {
r . Get ( "/index.yaml" , helm . Index )
r . Get ( "/{filename}" , helm . DownloadPackageFile )
r . Post ( "/api/charts" , reqPackageAccess ( perm . AccessModeWrite ) , helm . UploadPackage )
2022-09-24 18:17:08 +03:00
} , reqPackageAccess ( perm . AccessModeRead ) )
2022-03-30 11:42:47 +03:00
r . Group ( "/maven" , func ( ) {
r . Put ( "/*" , reqPackageAccess ( perm . AccessModeWrite ) , maven . UploadPackageFile )
r . Get ( "/*" , maven . DownloadPackageFile )
2022-11-24 17:25:13 +03:00
r . Head ( "/*" , maven . ProvidePackageFileHeader )
2022-09-24 18:17:08 +03:00
} , reqPackageAccess ( perm . AccessModeRead ) )
2022-03-30 11:42:47 +03:00
r . Group ( "/nuget" , func ( ) {
2022-10-13 13:19:39 +03:00
r . Group ( "" , func ( ) { // Needs to be unauthenticated for the NuGet client.
r . Get ( "/" , nuget . ServiceIndexV2 )
r . Get ( "/index.json" , nuget . ServiceIndexV3 )
r . Get ( "/$metadata" , nuget . FeedCapabilityResource )
} )
2022-03-30 11:42:47 +03:00
r . Group ( "" , func ( ) {
2022-10-13 13:19:39 +03:00
r . Get ( "/query" , nuget . SearchServiceV3 )
2022-09-24 18:17:08 +03:00
r . Group ( "/registration/{id}" , func ( ) {
r . Get ( "/index.json" , nuget . RegistrationIndex )
2022-10-13 13:19:39 +03:00
r . Get ( "/{version}" , nuget . RegistrationLeafV3 )
2022-09-24 18:17:08 +03:00
} )
r . Group ( "/package/{id}" , func ( ) {
2022-10-13 13:19:39 +03:00
r . Get ( "/index.json" , nuget . EnumeratePackageVersionsV3 )
2022-09-24 18:17:08 +03:00
r . Get ( "/{version}/{filename}" , nuget . DownloadPackageFile )
} )
r . Group ( "" , func ( ) {
r . Put ( "/" , nuget . UploadPackage )
r . Put ( "/symbolpackage" , nuget . UploadSymbolPackage )
r . Delete ( "/{id}/{version}" , nuget . DeletePackage )
} , reqPackageAccess ( perm . AccessModeWrite ) )
2022-10-12 09:53:56 +03:00
r . Get ( "/symbols/{filename}/{guid:[0-9a-fA-F]{32}[fF]{8}}/{filename2}" , nuget . DownloadSymbolFile )
2022-10-13 13:19:39 +03:00
r . Get ( "/Packages(Id='{id:[^']+}',Version='{version:[^']+}')" , nuget . RegistrationLeafV2 )
r . Get ( "/Packages()" , nuget . SearchServiceV2 )
r . Get ( "/FindPackagesById()" , nuget . EnumeratePackageVersionsV2 )
r . Get ( "/Search()" , nuget . SearchServiceV2 )
2022-09-24 18:17:08 +03:00
} , reqPackageAccess ( perm . AccessModeRead ) )
2022-03-30 11:42:47 +03:00
} )
r . Group ( "/npm" , func ( ) {
r . Group ( "/@{scope}/{id}" , func ( ) {
r . Get ( "" , npm . PackageMetadata )
r . Put ( "" , reqPackageAccess ( perm . AccessModeWrite ) , npm . UploadPackage )
2022-08-09 10:23:43 +03:00
r . Group ( "/-/{version}/{filename}" , func ( ) {
r . Get ( "" , npm . DownloadPackageFile )
r . Delete ( "/-rev/{revision}" , reqPackageAccess ( perm . AccessModeWrite ) , npm . DeletePackageVersion )
} )
2022-10-24 16:50:22 +03:00
r . Get ( "/-/{filename}" , npm . DownloadPackageFileByName )
2022-08-09 10:23:43 +03:00
r . Group ( "/-rev/{revision}" , func ( ) {
r . Delete ( "" , npm . DeletePackage )
r . Put ( "" , npm . DeletePreview )
} , reqPackageAccess ( perm . AccessModeWrite ) )
2022-03-30 11:42:47 +03:00
} )
r . Group ( "/{id}" , func ( ) {
r . Get ( "" , npm . PackageMetadata )
r . Put ( "" , reqPackageAccess ( perm . AccessModeWrite ) , npm . UploadPackage )
2022-08-09 10:23:43 +03:00
r . Group ( "/-/{version}/{filename}" , func ( ) {
r . Get ( "" , npm . DownloadPackageFile )
r . Delete ( "/-rev/{revision}" , reqPackageAccess ( perm . AccessModeWrite ) , npm . DeletePackageVersion )
} )
2022-10-24 16:50:22 +03:00
r . Get ( "/-/{filename}" , npm . DownloadPackageFileByName )
2022-08-09 10:23:43 +03:00
r . Group ( "/-rev/{revision}" , func ( ) {
r . Delete ( "" , npm . DeletePackage )
r . Put ( "" , npm . DeletePreview )
} , reqPackageAccess ( perm . AccessModeWrite ) )
2022-03-30 11:42:47 +03:00
} )
r . Group ( "/-/package/@{scope}/{id}/dist-tags" , func ( ) {
r . Get ( "" , npm . ListPackageTags )
r . Group ( "/{tag}" , func ( ) {
r . Put ( "" , npm . AddPackageTag )
r . Delete ( "" , npm . DeletePackageTag )
} , reqPackageAccess ( perm . AccessModeWrite ) )
} )
r . Group ( "/-/package/{id}/dist-tags" , func ( ) {
r . Get ( "" , npm . ListPackageTags )
r . Group ( "/{tag}" , func ( ) {
r . Put ( "" , npm . AddPackageTag )
r . Delete ( "" , npm . DeletePackageTag )
} , reqPackageAccess ( perm . AccessModeWrite ) )
} )
2022-09-24 14:24:33 +03:00
r . Group ( "/-/v1/search" , func ( ) {
r . Get ( "" , npm . PackageSearch )
} )
2022-09-24 18:17:08 +03:00
} , reqPackageAccess ( perm . AccessModeRead ) )
2022-08-07 13:09:54 +03:00
r . Group ( "/pub" , func ( ) {
r . Group ( "/api/packages" , func ( ) {
r . Group ( "/versions/new" , func ( ) {
r . Get ( "" , pub . RequestUpload )
r . Post ( "/upload" , pub . UploadPackageFile )
r . Get ( "/finalize/{id}/{version}" , pub . FinalizePackage )
} , reqPackageAccess ( perm . AccessModeWrite ) )
r . Group ( "/{id}" , func ( ) {
r . Get ( "" , pub . EnumeratePackageVersions )
r . Get ( "/files/{version}" , pub . DownloadPackageFile )
r . Get ( "/{version}" , pub . PackageVersionMetadata )
} )
} )
2022-09-24 18:17:08 +03:00
} , reqPackageAccess ( perm . AccessModeRead ) )
2022-03-30 11:42:47 +03:00
r . Group ( "/pypi" , func ( ) {
r . Post ( "/" , reqPackageAccess ( perm . AccessModeWrite ) , pypi . UploadPackageFile )
r . Get ( "/files/{id}/{version}/{filename}" , pypi . DownloadPackageFile )
r . Get ( "/simple/{id}" , pypi . PackageMetadata )
2022-09-24 18:17:08 +03:00
} , reqPackageAccess ( perm . AccessModeRead ) )
2022-03-30 11:42:47 +03:00
r . Group ( "/rubygems" , func ( ) {
r . Get ( "/specs.4.8.gz" , rubygems . EnumeratePackages )
r . Get ( "/latest_specs.4.8.gz" , rubygems . EnumeratePackagesLatest )
r . Get ( "/prerelease_specs.4.8.gz" , rubygems . EnumeratePackagesPreRelease )
r . Get ( "/quick/Marshal.4.8/{filename}" , rubygems . ServePackageSpecification )
r . Get ( "/gems/{filename}" , rubygems . DownloadPackageFile )
r . Group ( "/api/v1/gems" , func ( ) {
r . Post ( "/" , rubygems . UploadPackageFile )
r . Delete ( "/yank" , rubygems . DeletePackage )
} , reqPackageAccess ( perm . AccessModeWrite ) )
2022-09-24 18:17:08 +03:00
} , reqPackageAccess ( perm . AccessModeRead ) )
2022-08-29 10:04:45 +03:00
r . Group ( "/vagrant" , func ( ) {
r . Group ( "/authenticate" , func ( ) {
r . Get ( "" , vagrant . CheckAuthenticate )
} )
r . Group ( "/{name}" , func ( ) {
r . Head ( "" , vagrant . CheckBoxAvailable )
r . Get ( "" , vagrant . EnumeratePackageVersions )
r . Group ( "/{version}/{provider}" , func ( ) {
r . Get ( "" , vagrant . DownloadPackageFile )
r . Put ( "" , reqPackageAccess ( perm . AccessModeWrite ) , vagrant . UploadPackageFile )
} )
} )
2022-09-24 18:17:08 +03:00
} , reqPackageAccess ( perm . AccessModeRead ) )
} , context_service . UserAssignmentWeb ( ) , context . PackageAssignment ( ) )
2022-03-30 11:42:47 +03:00
return r
}
2022-11-12 21:59:15 +03:00
// ContainerRoutes provides endpoints that implement the OCI API to serve containers
// These have to be mounted on `/v2/...` to comply with the OCI spec:
// https://github.com/opencontainers/distribution-spec/blob/main/spec.md
2022-08-28 12:43:25 +03:00
func ContainerRoutes ( ctx gocontext . Context ) * web . Route {
2022-03-30 11:42:47 +03:00
r := web . NewRoute ( )
2022-08-28 12:43:25 +03:00
r . Use ( context . PackageContexter ( ctx ) )
2022-03-30 11:42:47 +03:00
authMethods := [ ] auth . Method {
& auth . Basic { } ,
& container . Auth { } ,
}
if setting . Service . EnableReverseProxyAuth {
authMethods = append ( authMethods , & auth . ReverseProxy { } )
}
authGroup := auth . NewGroup ( authMethods ... )
r . Use ( func ( ctx * context . Context ) {
ctx . Doer = authGroup . Verify ( ctx . Req , ctx . Resp , ctx , ctx . Session )
2022-10-24 22:23:25 +03:00
ctx . IsSigned = ctx . Doer != nil
2022-03-30 11:42:47 +03:00
} )
r . Get ( "" , container . ReqContainerAccess , container . DetermineSupport )
r . Get ( "/token" , container . Authenticate )
2022-07-28 06:59:39 +03:00
r . Get ( "/_catalog" , container . ReqContainerAccess , container . GetRepositoryList )
2022-03-30 11:42:47 +03:00
r . Group ( "/{username}" , func ( ) {
r . Group ( "/{image}" , func ( ) {
r . Group ( "/blobs/uploads" , func ( ) {
r . Post ( "" , container . InitiateUploadBlob )
r . Group ( "/{uuid}" , func ( ) {
2022-10-07 18:30:59 +03:00
r . Get ( "" , container . GetUploadBlob )
2022-03-30 11:42:47 +03:00
r . Patch ( "" , container . UploadBlob )
r . Put ( "" , container . EndUploadBlob )
2022-10-07 18:30:59 +03:00
r . Delete ( "" , container . CancelUploadBlob )
2022-03-30 11:42:47 +03:00
} )
} , reqPackageAccess ( perm . AccessModeWrite ) )
r . Group ( "/blobs/{digest}" , func ( ) {
r . Head ( "" , container . HeadBlob )
r . Get ( "" , container . GetBlob )
r . Delete ( "" , reqPackageAccess ( perm . AccessModeWrite ) , container . DeleteBlob )
} )
r . Group ( "/manifests/{reference}" , func ( ) {
r . Put ( "" , reqPackageAccess ( perm . AccessModeWrite ) , container . UploadManifest )
r . Head ( "" , container . HeadManifest )
r . Get ( "" , container . GetManifest )
r . Delete ( "" , reqPackageAccess ( perm . AccessModeWrite ) , container . DeleteManifest )
} )
r . Get ( "/tags/list" , container . GetTagList )
} , container . VerifyImageName )
var (
blobsUploadsPattern = regexp . MustCompile ( ` \A(.+)/blobs/uploads/([a-zA-Z0-9-_.=]+)\z ` )
blobsPattern = regexp . MustCompile ( ` \A(.+)/blobs/([^/]+)\z ` )
manifestsPattern = regexp . MustCompile ( ` \A(.+)/manifests/([^/]+)\z ` )
)
// Manual mapping of routes because {image} can contain slashes which chi does not support
r . Route ( "/*" , "HEAD,GET,POST,PUT,PATCH,DELETE" , func ( ctx * context . Context ) {
path := ctx . Params ( "*" )
isHead := ctx . Req . Method == "HEAD"
isGet := ctx . Req . Method == "GET"
isPost := ctx . Req . Method == "POST"
isPut := ctx . Req . Method == "PUT"
isPatch := ctx . Req . Method == "PATCH"
isDelete := ctx . Req . Method == "DELETE"
if isPost && strings . HasSuffix ( path , "/blobs/uploads" ) {
reqPackageAccess ( perm . AccessModeWrite ) ( ctx )
if ctx . Written ( ) {
return
}
ctx . SetParams ( "image" , path [ : len ( path ) - 14 ] )
container . VerifyImageName ( ctx )
if ctx . Written ( ) {
return
}
container . InitiateUploadBlob ( ctx )
return
}
if isGet && strings . HasSuffix ( path , "/tags/list" ) {
ctx . SetParams ( "image" , path [ : len ( path ) - 10 ] )
container . VerifyImageName ( ctx )
if ctx . Written ( ) {
return
}
container . GetTagList ( ctx )
return
}
m := blobsUploadsPattern . FindStringSubmatch ( path )
2022-10-07 18:30:59 +03:00
if len ( m ) == 3 && ( isGet || isPut || isPatch || isDelete ) {
2022-03-30 11:42:47 +03:00
reqPackageAccess ( perm . AccessModeWrite ) ( ctx )
if ctx . Written ( ) {
return
}
ctx . SetParams ( "image" , m [ 1 ] )
container . VerifyImageName ( ctx )
if ctx . Written ( ) {
return
}
ctx . SetParams ( "uuid" , m [ 2 ] )
2022-10-07 18:30:59 +03:00
if isGet {
container . GetUploadBlob ( ctx )
} else if isPatch {
2022-03-30 11:42:47 +03:00
container . UploadBlob ( ctx )
2022-10-07 18:30:59 +03:00
} else if isPut {
2022-03-30 11:42:47 +03:00
container . EndUploadBlob ( ctx )
2022-10-07 18:30:59 +03:00
} else {
container . CancelUploadBlob ( ctx )
2022-03-30 11:42:47 +03:00
}
return
}
m = blobsPattern . FindStringSubmatch ( path )
if len ( m ) == 3 && ( isHead || isGet || isDelete ) {
ctx . SetParams ( "image" , m [ 1 ] )
container . VerifyImageName ( ctx )
if ctx . Written ( ) {
return
}
ctx . SetParams ( "digest" , m [ 2 ] )
if isHead {
container . HeadBlob ( ctx )
} else if isGet {
container . GetBlob ( ctx )
} else {
reqPackageAccess ( perm . AccessModeWrite ) ( ctx )
if ctx . Written ( ) {
return
}
container . DeleteBlob ( ctx )
}
return
}
m = manifestsPattern . FindStringSubmatch ( path )
if len ( m ) == 3 && ( isHead || isGet || isPut || isDelete ) {
ctx . SetParams ( "image" , m [ 1 ] )
container . VerifyImageName ( ctx )
if ctx . Written ( ) {
return
}
ctx . SetParams ( "reference" , m [ 2 ] )
if isHead {
container . HeadManifest ( ctx )
} else if isGet {
container . GetManifest ( ctx )
} else {
reqPackageAccess ( perm . AccessModeWrite ) ( ctx )
if ctx . Written ( ) {
return
}
if isPut {
container . UploadManifest ( ctx )
} else {
container . DeleteManifest ( ctx )
}
}
return
}
ctx . Status ( http . StatusNotFound )
} )
} , container . ReqContainerAccess , context_service . UserAssignmentWeb ( ) , context . PackageAssignment ( ) , reqPackageAccess ( perm . AccessModeRead ) )
return r
}