summaryrefslogtreecommitdiffstats
path: root/routers
diff options
context:
space:
mode:
authorKN4CK3R <admin@oldschoolhack.me>2022-11-24 15:25:13 +0100
committerGitHub <noreply@github.com>2022-11-24 16:25:13 +0200
commitfc7a2d5a959334f7195571a3e1db669ed7667a28 (patch)
treee03df232ebc29e508680686c396cfecb4eeb0902 /routers
parent26f941fbdac73844a93c902ce6d1144175ff23ed (diff)
downloadgitea-fc7a2d5a959334f7195571a3e1db669ed7667a28.tar.gz
gitea-fc7a2d5a959334f7195571a3e1db669ed7667a28.zip
Add support for HEAD requests in Maven registry (#21834)
Related #18543 Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com>
Diffstat (limited to 'routers')
-rw-r--r--routers/api/packages/api.go1
-rw-r--r--routers/api/packages/composer/composer.go5
-rw-r--r--routers/api/packages/conan/conan.go5
-rw-r--r--routers/api/packages/generic/generic.go5
-rw-r--r--routers/api/packages/helm/helm.go5
-rw-r--r--routers/api/packages/maven/api.go7
-rw-r--r--routers/api/packages/maven/maven.go57
-rw-r--r--routers/api/packages/npm/npm.go10
-rw-r--r--routers/api/packages/nuget/nuget.go10
-rw-r--r--routers/api/packages/pub/pub.go5
-rw-r--r--routers/api/packages/pypi/pypi.go5
-rw-r--r--routers/api/packages/rubygems/rubygems.go5
-rw-r--r--routers/api/packages/vagrant/vagrant.go5
-rw-r--r--routers/api/v1/repo/file.go6
-rw-r--r--routers/common/repo.go11
-rw-r--r--routers/web/repo/repo.go5
-rw-r--r--routers/web/user/package.go5
17 files changed, 120 insertions, 32 deletions
diff --git a/routers/api/packages/api.go b/routers/api/packages/api.go
index 11e7e5d6a6..0d8b9ce61e 100644
--- a/routers/api/packages/api.go
+++ b/routers/api/packages/api.go
@@ -181,6 +181,7 @@ func CommonRoutes(ctx gocontext.Context) *web.Route {
r.Group("/maven", func() {
r.Put("/*", reqPackageAccess(perm.AccessModeWrite), maven.UploadPackageFile)
r.Get("/*", maven.DownloadPackageFile)
+ r.Head("/*", maven.ProvidePackageFileHeader)
}, reqPackageAccess(perm.AccessModeRead))
r.Group("/nuget", func() {
r.Group("", func() { // Needs to be unauthenticated for the NuGet client.
diff --git a/routers/api/packages/composer/composer.go b/routers/api/packages/composer/composer.go
index 92e83dbe79..a19433c6f0 100644
--- a/routers/api/packages/composer/composer.go
+++ b/routers/api/packages/composer/composer.go
@@ -184,7 +184,10 @@ func DownloadPackageFile(ctx *context.Context) {
}
defer s.Close()
- ctx.ServeContent(pf.Name, s, pf.CreatedUnix.AsLocalTime())
+ ctx.ServeContent(s, &context.ServeHeaderOptions{
+ Filename: pf.Name,
+ LastModified: pf.CreatedUnix.AsLocalTime(),
+ })
}
// UploadPackage creates a new package
diff --git a/routers/api/packages/conan/conan.go b/routers/api/packages/conan/conan.go
index 188cfce287..e7c891b35f 100644
--- a/routers/api/packages/conan/conan.go
+++ b/routers/api/packages/conan/conan.go
@@ -477,7 +477,10 @@ func downloadFile(ctx *context.Context, fileFilter container.Set[string], fileKe
}
defer s.Close()
- ctx.ServeContent(pf.Name, s, pf.CreatedUnix.AsLocalTime())
+ ctx.ServeContent(s, &context.ServeHeaderOptions{
+ Filename: pf.Name,
+ LastModified: pf.CreatedUnix.AsLocalTime(),
+ })
}
// DeleteRecipeV1 deletes the requested recipe(s)
diff --git a/routers/api/packages/generic/generic.go b/routers/api/packages/generic/generic.go
index 1bccc6764c..1c233da20f 100644
--- a/routers/api/packages/generic/generic.go
+++ b/routers/api/packages/generic/generic.go
@@ -53,7 +53,10 @@ func DownloadPackageFile(ctx *context.Context) {
}
defer s.Close()
- ctx.ServeContent(pf.Name, s, pf.CreatedUnix.AsLocalTime())
+ ctx.ServeContent(s, &context.ServeHeaderOptions{
+ Filename: pf.Name,
+ LastModified: pf.CreatedUnix.AsLocalTime(),
+ })
}
// UploadPackage uploads the specific generic package.
diff --git a/routers/api/packages/helm/helm.go b/routers/api/packages/helm/helm.go
index 17f0a0d311..11291ca14e 100644
--- a/routers/api/packages/helm/helm.go
+++ b/routers/api/packages/helm/helm.go
@@ -138,7 +138,10 @@ func DownloadPackageFile(ctx *context.Context) {
}
defer s.Close()
- ctx.ServeContent(pf.Name, s, pf.CreatedUnix.AsLocalTime())
+ ctx.ServeContent(s, &context.ServeHeaderOptions{
+ Filename: pf.Name,
+ LastModified: pf.CreatedUnix.AsLocalTime(),
+ })
}
// UploadPackage creates a new package
diff --git a/routers/api/packages/maven/api.go b/routers/api/packages/maven/api.go
index b60a317814..4ca541dd6f 100644
--- a/routers/api/packages/maven/api.go
+++ b/routers/api/packages/maven/api.go
@@ -6,7 +6,6 @@ package maven
import (
"encoding/xml"
- "sort"
"strings"
packages_model "code.gitea.io/gitea/models/packages"
@@ -23,12 +22,8 @@ type MetadataResponse struct {
Version []string `xml:"versioning>versions>version"`
}
+// pds is expected to be sorted ascending by CreatedUnix
func createMetadataResponse(pds []*packages_model.PackageDescriptor) *MetadataResponse {
- sort.Slice(pds, func(i, j int) bool {
- // Maven and Gradle order packages by their creation timestamp and not by their version string
- return pds[i].Version.CreatedUnix < pds[j].Version.CreatedUnix
- })
-
var release *packages_model.PackageDescriptor
versions := make([]string, 0, len(pds))
diff --git a/routers/api/packages/maven/maven.go b/routers/api/packages/maven/maven.go
index de274b2046..3125062b92 100644
--- a/routers/api/packages/maven/maven.go
+++ b/routers/api/packages/maven/maven.go
@@ -16,6 +16,8 @@ import (
"net/http"
"path/filepath"
"regexp"
+ "sort"
+ "strconv"
"strings"
packages_model "code.gitea.io/gitea/models/packages"
@@ -34,6 +36,10 @@ const (
extensionSHA1 = ".sha1"
extensionSHA256 = ".sha256"
extensionSHA512 = ".sha512"
+ extensionPom = ".pom"
+ extensionJar = ".jar"
+ contentTypeJar = "application/java-archive"
+ contentTypeXML = "text/xml"
)
var (
@@ -49,6 +55,15 @@ func apiError(ctx *context.Context, status int, obj interface{}) {
// DownloadPackageFile serves the content of a package
func DownloadPackageFile(ctx *context.Context) {
+ handlePackageFile(ctx, true)
+}
+
+// ProvidePackageFileHeader provides only the headers describing a package
+func ProvidePackageFileHeader(ctx *context.Context) {
+ handlePackageFile(ctx, false)
+}
+
+func handlePackageFile(ctx *context.Context, serveContent bool) {
params, err := extractPathParameters(ctx)
if err != nil {
apiError(ctx, http.StatusBadRequest, err)
@@ -58,7 +73,7 @@ func DownloadPackageFile(ctx *context.Context) {
if params.IsMeta && params.Version == "" {
serveMavenMetadata(ctx, params)
} else {
- servePackageFile(ctx, params)
+ servePackageFile(ctx, params, serveContent)
}
}
@@ -82,6 +97,11 @@ func serveMavenMetadata(ctx *context.Context, params parameters) {
return
}
+ sort.Slice(pds, func(i, j int) bool {
+ // Maven and Gradle order packages by their creation timestamp and not by their version string
+ return pds[i].Version.CreatedUnix < pds[j].Version.CreatedUnix
+ })
+
xmlMetadata, err := xml.Marshal(createMetadataResponse(pds))
if err != nil {
apiError(ctx, http.StatusInternalServerError, err)
@@ -89,6 +109,9 @@ func serveMavenMetadata(ctx *context.Context, params parameters) {
}
xmlMetadataWithHeader := append([]byte(xml.Header), xmlMetadata...)
+ latest := pds[len(pds)-1]
+ ctx.Resp.Header().Set("Last-Modified", latest.Version.CreatedUnix.Format(http.TimeFormat))
+
ext := strings.ToLower(filepath.Ext(params.Filename))
if isChecksumExtension(ext) {
var hash []byte
@@ -110,10 +133,15 @@ func serveMavenMetadata(ctx *context.Context, params parameters) {
return
}
- ctx.PlainTextBytes(http.StatusOK, xmlMetadataWithHeader)
+ ctx.Resp.Header().Set("Content-Length", strconv.Itoa(len(xmlMetadataWithHeader)))
+ ctx.Resp.Header().Set("Content-Type", contentTypeXML)
+
+ if _, err := ctx.Resp.Write(xmlMetadataWithHeader); err != nil {
+ log.Error("write bytes failed: %v", err)
+ }
}
-func servePackageFile(ctx *context.Context, params parameters) {
+func servePackageFile(ctx *context.Context, params parameters, serveContent bool) {
packageName := params.GroupID + "-" + params.ArtifactID
pv, err := packages_model.GetVersionByNameAndVersion(ctx, ctx.Package.Owner.ID, packages_model.TypeMaven, packageName, params.Version)
@@ -165,6 +193,23 @@ func servePackageFile(ctx *context.Context, params parameters) {
return
}
+ opts := &context.ServeHeaderOptions{
+ ContentLength: &pb.Size,
+ LastModified: pf.CreatedUnix.AsLocalTime(),
+ }
+ switch ext {
+ case extensionJar:
+ opts.ContentType = contentTypeJar
+ case extensionPom:
+ opts.ContentType = contentTypeXML
+ }
+
+ if !serveContent {
+ ctx.SetServeHeaders(opts)
+ ctx.Status(http.StatusOK)
+ return
+ }
+
s, err := packages_module.NewContentStore().Get(packages_module.BlobHash256Key(pb.HashSHA256))
if err != nil {
apiError(ctx, http.StatusInternalServerError, err)
@@ -177,7 +222,9 @@ func servePackageFile(ctx *context.Context, params parameters) {
}
}
- ctx.ServeContent(pf.Name, s, pf.CreatedUnix.AsLocalTime())
+ opts.Filename = pf.Name
+
+ ctx.ServeContent(s, opts)
}
// UploadPackageFile adds a file to the package. If the package does not exist, it gets created.
@@ -273,7 +320,7 @@ func UploadPackageFile(ctx *context.Context) {
}
// If it's the package pom file extract the metadata
- if ext == ".pom" {
+ if ext == extensionPom {
pfci.IsLead = true
var err error
diff --git a/routers/api/packages/npm/npm.go b/routers/api/packages/npm/npm.go
index af0e9be56e..6c11286a86 100644
--- a/routers/api/packages/npm/npm.go
+++ b/routers/api/packages/npm/npm.go
@@ -103,7 +103,10 @@ func DownloadPackageFile(ctx *context.Context) {
}
defer s.Close()
- ctx.ServeContent(pf.Name, s, pf.CreatedUnix.AsLocalTime())
+ ctx.ServeContent(s, &context.ServeHeaderOptions{
+ Filename: pf.Name,
+ LastModified: pf.CreatedUnix.AsLocalTime(),
+ })
}
// DownloadPackageFileByName finds the version and serves the contents of a package
@@ -146,7 +149,10 @@ func DownloadPackageFileByName(ctx *context.Context) {
}
defer s.Close()
- ctx.ServeContent(pf.Name, s, pf.CreatedUnix.AsLocalTime())
+ ctx.ServeContent(s, &context.ServeHeaderOptions{
+ Filename: pf.Name,
+ LastModified: pf.CreatedUnix.AsLocalTime(),
+ })
}
// UploadPackage creates a new package
diff --git a/routers/api/packages/nuget/nuget.go b/routers/api/packages/nuget/nuget.go
index 442d94243b..06aaca596d 100644
--- a/routers/api/packages/nuget/nuget.go
+++ b/routers/api/packages/nuget/nuget.go
@@ -342,7 +342,10 @@ func DownloadPackageFile(ctx *context.Context) {
}
defer s.Close()
- ctx.ServeContent(pf.Name, s, pf.CreatedUnix.AsLocalTime())
+ ctx.ServeContent(s, &context.ServeHeaderOptions{
+ Filename: pf.Name,
+ LastModified: pf.CreatedUnix.AsLocalTime(),
+ })
}
// UploadPackage creates a new package with the metadata contained in the uploaded nupgk file
@@ -562,7 +565,10 @@ func DownloadSymbolFile(ctx *context.Context) {
}
defer s.Close()
- ctx.ServeContent(pf.Name, s, pf.CreatedUnix.AsLocalTime())
+ ctx.ServeContent(s, &context.ServeHeaderOptions{
+ Filename: pf.Name,
+ LastModified: pf.CreatedUnix.AsLocalTime(),
+ })
}
// DeletePackage hard deletes the package
diff --git a/routers/api/packages/pub/pub.go b/routers/api/packages/pub/pub.go
index 635147b6d0..26cb9fbb9a 100644
--- a/routers/api/packages/pub/pub.go
+++ b/routers/api/packages/pub/pub.go
@@ -275,5 +275,8 @@ func DownloadPackageFile(ctx *context.Context) {
}
defer s.Close()
- ctx.ServeContent(pf.Name, s, pf.CreatedUnix.AsLocalTime())
+ ctx.ServeContent(s, &context.ServeHeaderOptions{
+ Filename: pf.Name,
+ LastModified: pf.CreatedUnix.AsLocalTime(),
+ })
}
diff --git a/routers/api/packages/pypi/pypi.go b/routers/api/packages/pypi/pypi.go
index 4853e6658b..76801a92e1 100644
--- a/routers/api/packages/pypi/pypi.go
+++ b/routers/api/packages/pypi/pypi.go
@@ -95,7 +95,10 @@ func DownloadPackageFile(ctx *context.Context) {
}
defer s.Close()
- ctx.ServeContent(pf.Name, s, pf.CreatedUnix.AsLocalTime())
+ ctx.ServeContent(s, &context.ServeHeaderOptions{
+ Filename: pf.Name,
+ LastModified: pf.CreatedUnix.AsLocalTime(),
+ })
}
// UploadPackageFile adds a file to the package. If the package does not exist, it gets created.
diff --git a/routers/api/packages/rubygems/rubygems.go b/routers/api/packages/rubygems/rubygems.go
index 4adfb15731..f0b00f42c3 100644
--- a/routers/api/packages/rubygems/rubygems.go
+++ b/routers/api/packages/rubygems/rubygems.go
@@ -192,7 +192,10 @@ func DownloadPackageFile(ctx *context.Context) {
}
defer s.Close()
- ctx.ServeContent(pf.Name, s, pf.CreatedUnix.AsLocalTime())
+ ctx.ServeContent(s, &context.ServeHeaderOptions{
+ Filename: pf.Name,
+ LastModified: pf.CreatedUnix.AsLocalTime(),
+ })
}
// UploadPackageFile adds a file to the package. If the package does not exist, it gets created.
diff --git a/routers/api/packages/vagrant/vagrant.go b/routers/api/packages/vagrant/vagrant.go
index 31ac56a532..746a2b19ba 100644
--- a/routers/api/packages/vagrant/vagrant.go
+++ b/routers/api/packages/vagrant/vagrant.go
@@ -239,5 +239,8 @@ func DownloadPackageFile(ctx *context.Context) {
}
defer s.Close()
- ctx.ServeContent(pf.Name, s, pf.CreatedUnix.AsLocalTime())
+ ctx.ServeContent(s, &context.ServeHeaderOptions{
+ Filename: pf.Name,
+ LastModified: pf.CreatedUnix.AsLocalTime(),
+ })
}
diff --git a/routers/api/v1/repo/file.go b/routers/api/v1/repo/file.go
index 6dead81e6d..aba5b1f9e7 100644
--- a/routers/api/v1/repo/file.go
+++ b/routers/api/v1/repo/file.go
@@ -341,7 +341,11 @@ func download(ctx *context.APIContext, archiveName string, archiver *repo_model.
return
}
defer fr.Close()
- ctx.ServeContent(downloadName, fr, archiver.CreatedUnix.AsLocalTime())
+
+ ctx.ServeContent(fr, &context.ServeHeaderOptions{
+ Filename: downloadName,
+ LastModified: archiver.CreatedUnix.AsLocalTime(),
+ })
}
// GetEditorconfig get editor config of a repository
diff --git a/routers/common/repo.go b/routers/common/repo.go
index f4b813d6b4..340eb1809f 100644
--- a/routers/common/repo.go
+++ b/routers/common/repo.go
@@ -5,7 +5,6 @@
package common
import (
- "fmt"
"io"
"path"
"path/filepath"
@@ -52,16 +51,16 @@ func ServeData(ctx *context.Context, filePath string, size int64, reader io.Read
buf = buf[:n]
}
+ opts := &context.ServeHeaderOptions{
+ Filename: path.Base(filePath),
+ }
+
if size >= 0 {
- ctx.Resp.Header().Set("Content-Length", fmt.Sprintf("%d", size))
+ opts.ContentLength = &size
} else {
log.Error("ServeData called to serve data: %s with size < 0: %d", filePath, size)
}
- opts := &context.ServeHeaderOptions{
- Filename: path.Base(filePath),
- }
-
sniffedType := typesniffer.DetectContentType(buf)
isPlain := sniffedType.IsText() || ctx.FormBool("render")
diff --git a/routers/web/repo/repo.go b/routers/web/repo/repo.go
index 7bcca1d02a..17e600182d 100644
--- a/routers/web/repo/repo.go
+++ b/routers/web/repo/repo.go
@@ -426,7 +426,10 @@ func download(ctx *context.Context, archiveName string, archiver *repo_model.Rep
}
defer fr.Close()
- ctx.ServeContent(downloadName, fr, archiver.CreatedUnix.AsLocalTime())
+ ctx.ServeContent(fr, &context.ServeHeaderOptions{
+ Filename: downloadName,
+ LastModified: archiver.CreatedUnix.AsLocalTime(),
+ })
}
// InitiateDownload will enqueue an archival request, as needed. It may submit
diff --git a/routers/web/user/package.go b/routers/web/user/package.go
index 7179e2df97..7be37b6a50 100644
--- a/routers/web/user/package.go
+++ b/routers/web/user/package.go
@@ -402,5 +402,8 @@ func DownloadPackageFile(ctx *context.Context) {
}
defer s.Close()
- ctx.ServeContent(pf.Name, s, pf.CreatedUnix.AsLocalTime())
+ ctx.ServeContent(s, &context.ServeHeaderOptions{
+ Filename: pf.Name,
+ LastModified: pf.CreatedUnix.AsLocalTime(),
+ })
}