Add support for HEAD requests in Maven registry (#21834)
Related #18543 Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com>
This commit is contained in:
parent
26f941fbda
commit
fc7a2d5a95
|
@ -349,9 +349,11 @@ func (ctx *Context) RespHeader() http.Header {
|
||||||
type ServeHeaderOptions struct {
|
type ServeHeaderOptions struct {
|
||||||
ContentType string // defaults to "application/octet-stream"
|
ContentType string // defaults to "application/octet-stream"
|
||||||
ContentTypeCharset string
|
ContentTypeCharset string
|
||||||
|
ContentLength *int64
|
||||||
Disposition string // defaults to "attachment"
|
Disposition string // defaults to "attachment"
|
||||||
Filename string
|
Filename string
|
||||||
CacheDuration time.Duration // defaults to 5 minutes
|
CacheDuration time.Duration // defaults to 5 minutes
|
||||||
|
LastModified time.Time
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetServeHeaders sets necessary content serve headers
|
// SetServeHeaders sets necessary content serve headers
|
||||||
|
@ -369,6 +371,10 @@ func (ctx *Context) SetServeHeaders(opts *ServeHeaderOptions) {
|
||||||
header.Set("Content-Type", contentType)
|
header.Set("Content-Type", contentType)
|
||||||
header.Set("X-Content-Type-Options", "nosniff")
|
header.Set("X-Content-Type-Options", "nosniff")
|
||||||
|
|
||||||
|
if opts.ContentLength != nil {
|
||||||
|
header.Set("Content-Length", strconv.FormatInt(*opts.ContentLength, 10))
|
||||||
|
}
|
||||||
|
|
||||||
if opts.Filename != "" {
|
if opts.Filename != "" {
|
||||||
disposition := opts.Disposition
|
disposition := opts.Disposition
|
||||||
if disposition == "" {
|
if disposition == "" {
|
||||||
|
@ -385,14 +391,16 @@ func (ctx *Context) SetServeHeaders(opts *ServeHeaderOptions) {
|
||||||
duration = 5 * time.Minute
|
duration = 5 * time.Minute
|
||||||
}
|
}
|
||||||
httpcache.AddCacheControlToHeader(header, duration)
|
httpcache.AddCacheControlToHeader(header, duration)
|
||||||
|
|
||||||
|
if !opts.LastModified.IsZero() {
|
||||||
|
header.Set("Last-Modified", opts.LastModified.UTC().Format(http.TimeFormat))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ServeContent serves content to http request
|
// ServeContent serves content to http request
|
||||||
func (ctx *Context) ServeContent(name string, r io.ReadSeeker, modTime time.Time) {
|
func (ctx *Context) ServeContent(r io.ReadSeeker, opts *ServeHeaderOptions) {
|
||||||
ctx.SetServeHeaders(&ServeHeaderOptions{
|
ctx.SetServeHeaders(opts)
|
||||||
Filename: name,
|
http.ServeContent(ctx.Resp, ctx.Req, opts.Filename, opts.LastModified, r)
|
||||||
})
|
|
||||||
http.ServeContent(ctx.Resp, ctx.Req, name, modTime, r)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// UploadStream returns the request body or the first form file
|
// UploadStream returns the request body or the first form file
|
||||||
|
|
|
@ -181,6 +181,7 @@ func CommonRoutes(ctx gocontext.Context) *web.Route {
|
||||||
r.Group("/maven", func() {
|
r.Group("/maven", func() {
|
||||||
r.Put("/*", reqPackageAccess(perm.AccessModeWrite), maven.UploadPackageFile)
|
r.Put("/*", reqPackageAccess(perm.AccessModeWrite), maven.UploadPackageFile)
|
||||||
r.Get("/*", maven.DownloadPackageFile)
|
r.Get("/*", maven.DownloadPackageFile)
|
||||||
|
r.Head("/*", maven.ProvidePackageFileHeader)
|
||||||
}, reqPackageAccess(perm.AccessModeRead))
|
}, reqPackageAccess(perm.AccessModeRead))
|
||||||
r.Group("/nuget", func() {
|
r.Group("/nuget", func() {
|
||||||
r.Group("", func() { // Needs to be unauthenticated for the NuGet client.
|
r.Group("", func() { // Needs to be unauthenticated for the NuGet client.
|
||||||
|
|
|
@ -184,7 +184,10 @@ func DownloadPackageFile(ctx *context.Context) {
|
||||||
}
|
}
|
||||||
defer s.Close()
|
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
|
// UploadPackage creates a new package
|
||||||
|
|
|
@ -477,7 +477,10 @@ func downloadFile(ctx *context.Context, fileFilter container.Set[string], fileKe
|
||||||
}
|
}
|
||||||
defer s.Close()
|
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)
|
// DeleteRecipeV1 deletes the requested recipe(s)
|
||||||
|
|
|
@ -53,7 +53,10 @@ func DownloadPackageFile(ctx *context.Context) {
|
||||||
}
|
}
|
||||||
defer s.Close()
|
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.
|
// UploadPackage uploads the specific generic package.
|
||||||
|
|
|
@ -138,7 +138,10 @@ func DownloadPackageFile(ctx *context.Context) {
|
||||||
}
|
}
|
||||||
defer s.Close()
|
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
|
// UploadPackage creates a new package
|
||||||
|
|
|
@ -6,7 +6,6 @@ package maven
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/xml"
|
"encoding/xml"
|
||||||
"sort"
|
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
packages_model "code.gitea.io/gitea/models/packages"
|
packages_model "code.gitea.io/gitea/models/packages"
|
||||||
|
@ -23,12 +22,8 @@ type MetadataResponse struct {
|
||||||
Version []string `xml:"versioning>versions>version"`
|
Version []string `xml:"versioning>versions>version"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// pds is expected to be sorted ascending by CreatedUnix
|
||||||
func createMetadataResponse(pds []*packages_model.PackageDescriptor) *MetadataResponse {
|
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
|
var release *packages_model.PackageDescriptor
|
||||||
|
|
||||||
versions := make([]string, 0, len(pds))
|
versions := make([]string, 0, len(pds))
|
||||||
|
|
|
@ -16,6 +16,8 @@ import (
|
||||||
"net/http"
|
"net/http"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"regexp"
|
"regexp"
|
||||||
|
"sort"
|
||||||
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
packages_model "code.gitea.io/gitea/models/packages"
|
packages_model "code.gitea.io/gitea/models/packages"
|
||||||
|
@ -34,6 +36,10 @@ const (
|
||||||
extensionSHA1 = ".sha1"
|
extensionSHA1 = ".sha1"
|
||||||
extensionSHA256 = ".sha256"
|
extensionSHA256 = ".sha256"
|
||||||
extensionSHA512 = ".sha512"
|
extensionSHA512 = ".sha512"
|
||||||
|
extensionPom = ".pom"
|
||||||
|
extensionJar = ".jar"
|
||||||
|
contentTypeJar = "application/java-archive"
|
||||||
|
contentTypeXML = "text/xml"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
@ -49,6 +55,15 @@ func apiError(ctx *context.Context, status int, obj interface{}) {
|
||||||
|
|
||||||
// DownloadPackageFile serves the content of a package
|
// DownloadPackageFile serves the content of a package
|
||||||
func DownloadPackageFile(ctx *context.Context) {
|
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)
|
params, err := extractPathParameters(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
apiError(ctx, http.StatusBadRequest, err)
|
apiError(ctx, http.StatusBadRequest, err)
|
||||||
|
@ -58,7 +73,7 @@ func DownloadPackageFile(ctx *context.Context) {
|
||||||
if params.IsMeta && params.Version == "" {
|
if params.IsMeta && params.Version == "" {
|
||||||
serveMavenMetadata(ctx, params)
|
serveMavenMetadata(ctx, params)
|
||||||
} else {
|
} else {
|
||||||
servePackageFile(ctx, params)
|
servePackageFile(ctx, params, serveContent)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -82,6 +97,11 @@ func serveMavenMetadata(ctx *context.Context, params parameters) {
|
||||||
return
|
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))
|
xmlMetadata, err := xml.Marshal(createMetadataResponse(pds))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
apiError(ctx, http.StatusInternalServerError, err)
|
apiError(ctx, http.StatusInternalServerError, err)
|
||||||
|
@ -89,6 +109,9 @@ func serveMavenMetadata(ctx *context.Context, params parameters) {
|
||||||
}
|
}
|
||||||
xmlMetadataWithHeader := append([]byte(xml.Header), xmlMetadata...)
|
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))
|
ext := strings.ToLower(filepath.Ext(params.Filename))
|
||||||
if isChecksumExtension(ext) {
|
if isChecksumExtension(ext) {
|
||||||
var hash []byte
|
var hash []byte
|
||||||
|
@ -110,10 +133,15 @@ func serveMavenMetadata(ctx *context.Context, params parameters) {
|
||||||
return
|
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
|
packageName := params.GroupID + "-" + params.ArtifactID
|
||||||
|
|
||||||
pv, err := packages_model.GetVersionByNameAndVersion(ctx, ctx.Package.Owner.ID, packages_model.TypeMaven, packageName, params.Version)
|
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
|
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))
|
s, err := packages_module.NewContentStore().Get(packages_module.BlobHash256Key(pb.HashSHA256))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
apiError(ctx, http.StatusInternalServerError, err)
|
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.
|
// 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 it's the package pom file extract the metadata
|
||||||
if ext == ".pom" {
|
if ext == extensionPom {
|
||||||
pfci.IsLead = true
|
pfci.IsLead = true
|
||||||
|
|
||||||
var err error
|
var err error
|
||||||
|
|
|
@ -103,7 +103,10 @@ func DownloadPackageFile(ctx *context.Context) {
|
||||||
}
|
}
|
||||||
defer s.Close()
|
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
|
// DownloadPackageFileByName finds the version and serves the contents of a package
|
||||||
|
@ -146,7 +149,10 @@ func DownloadPackageFileByName(ctx *context.Context) {
|
||||||
}
|
}
|
||||||
defer s.Close()
|
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
|
// UploadPackage creates a new package
|
||||||
|
|
|
@ -342,7 +342,10 @@ func DownloadPackageFile(ctx *context.Context) {
|
||||||
}
|
}
|
||||||
defer s.Close()
|
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
|
// 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()
|
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
|
// DeletePackage hard deletes the package
|
||||||
|
|
|
@ -275,5 +275,8 @@ func DownloadPackageFile(ctx *context.Context) {
|
||||||
}
|
}
|
||||||
defer s.Close()
|
defer s.Close()
|
||||||
|
|
||||||
ctx.ServeContent(pf.Name, s, pf.CreatedUnix.AsLocalTime())
|
ctx.ServeContent(s, &context.ServeHeaderOptions{
|
||||||
|
Filename: pf.Name,
|
||||||
|
LastModified: pf.CreatedUnix.AsLocalTime(),
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -95,7 +95,10 @@ func DownloadPackageFile(ctx *context.Context) {
|
||||||
}
|
}
|
||||||
defer s.Close()
|
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.
|
// UploadPackageFile adds a file to the package. If the package does not exist, it gets created.
|
||||||
|
|
|
@ -192,7 +192,10 @@ func DownloadPackageFile(ctx *context.Context) {
|
||||||
}
|
}
|
||||||
defer s.Close()
|
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.
|
// UploadPackageFile adds a file to the package. If the package does not exist, it gets created.
|
||||||
|
|
|
@ -239,5 +239,8 @@ func DownloadPackageFile(ctx *context.Context) {
|
||||||
}
|
}
|
||||||
defer s.Close()
|
defer s.Close()
|
||||||
|
|
||||||
ctx.ServeContent(pf.Name, s, pf.CreatedUnix.AsLocalTime())
|
ctx.ServeContent(s, &context.ServeHeaderOptions{
|
||||||
|
Filename: pf.Name,
|
||||||
|
LastModified: pf.CreatedUnix.AsLocalTime(),
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -341,7 +341,11 @@ func download(ctx *context.APIContext, archiveName string, archiver *repo_model.
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
defer fr.Close()
|
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
|
// GetEditorconfig get editor config of a repository
|
||||||
|
|
|
@ -5,7 +5,6 @@
|
||||||
package common
|
package common
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"io"
|
"io"
|
||||||
"path"
|
"path"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
@ -52,16 +51,16 @@ func ServeData(ctx *context.Context, filePath string, size int64, reader io.Read
|
||||||
buf = buf[:n]
|
buf = buf[:n]
|
||||||
}
|
}
|
||||||
|
|
||||||
if size >= 0 {
|
|
||||||
ctx.Resp.Header().Set("Content-Length", fmt.Sprintf("%d", size))
|
|
||||||
} else {
|
|
||||||
log.Error("ServeData called to serve data: %s with size < 0: %d", filePath, size)
|
|
||||||
}
|
|
||||||
|
|
||||||
opts := &context.ServeHeaderOptions{
|
opts := &context.ServeHeaderOptions{
|
||||||
Filename: path.Base(filePath),
|
Filename: path.Base(filePath),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if size >= 0 {
|
||||||
|
opts.ContentLength = &size
|
||||||
|
} else {
|
||||||
|
log.Error("ServeData called to serve data: %s with size < 0: %d", filePath, size)
|
||||||
|
}
|
||||||
|
|
||||||
sniffedType := typesniffer.DetectContentType(buf)
|
sniffedType := typesniffer.DetectContentType(buf)
|
||||||
isPlain := sniffedType.IsText() || ctx.FormBool("render")
|
isPlain := sniffedType.IsText() || ctx.FormBool("render")
|
||||||
|
|
||||||
|
|
|
@ -426,7 +426,10 @@ func download(ctx *context.Context, archiveName string, archiver *repo_model.Rep
|
||||||
}
|
}
|
||||||
defer fr.Close()
|
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
|
// InitiateDownload will enqueue an archival request, as needed. It may submit
|
||||||
|
|
|
@ -402,5 +402,8 @@ func DownloadPackageFile(ctx *context.Context) {
|
||||||
}
|
}
|
||||||
defer s.Close()
|
defer s.Close()
|
||||||
|
|
||||||
ctx.ServeContent(pf.Name, s, pf.CreatedUnix.AsLocalTime())
|
ctx.ServeContent(s, &context.ServeHeaderOptions{
|
||||||
|
Filename: pf.Name,
|
||||||
|
LastModified: pf.CreatedUnix.AsLocalTime(),
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,6 +7,7 @@ package integration
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
@ -39,6 +40,12 @@ func TestPackageMaven(t *testing.T) {
|
||||||
MakeRequest(t, req, expectedStatus)
|
MakeRequest(t, req, expectedStatus)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
checkHeaders := func(t *testing.T, h http.Header, contentType string, contentLength int64) {
|
||||||
|
assert.Equal(t, contentType, h.Get("Content-Type"))
|
||||||
|
assert.Equal(t, strconv.FormatInt(contentLength, 10), h.Get("Content-Length"))
|
||||||
|
assert.NotEmpty(t, h.Get("Last-Modified"))
|
||||||
|
}
|
||||||
|
|
||||||
t.Run("Upload", func(t *testing.T) {
|
t.Run("Upload", func(t *testing.T) {
|
||||||
defer tests.PrintCurrentTest(t)()
|
defer tests.PrintCurrentTest(t)()
|
||||||
|
|
||||||
|
@ -77,10 +84,18 @@ func TestPackageMaven(t *testing.T) {
|
||||||
t.Run("Download", func(t *testing.T) {
|
t.Run("Download", func(t *testing.T) {
|
||||||
defer tests.PrintCurrentTest(t)()
|
defer tests.PrintCurrentTest(t)()
|
||||||
|
|
||||||
req := NewRequest(t, "GET", fmt.Sprintf("%s/%s/%s", root, packageVersion, filename))
|
req := NewRequest(t, "HEAD", fmt.Sprintf("%s/%s/%s", root, packageVersion, filename))
|
||||||
req = AddBasicAuthHeader(req, user.Name)
|
req = AddBasicAuthHeader(req, user.Name)
|
||||||
resp := MakeRequest(t, req, http.StatusOK)
|
resp := MakeRequest(t, req, http.StatusOK)
|
||||||
|
|
||||||
|
checkHeaders(t, resp.Header(), "application/java-archive", 4)
|
||||||
|
|
||||||
|
req = NewRequest(t, "GET", fmt.Sprintf("%s/%s/%s", root, packageVersion, filename))
|
||||||
|
req = AddBasicAuthHeader(req, user.Name)
|
||||||
|
resp = MakeRequest(t, req, http.StatusOK)
|
||||||
|
|
||||||
|
checkHeaders(t, resp.Header(), "application/java-archive", 4)
|
||||||
|
|
||||||
assert.Equal(t, []byte("test"), resp.Body.Bytes())
|
assert.Equal(t, []byte("test"), resp.Body.Bytes())
|
||||||
|
|
||||||
pvs, err := packages.GetVersionsByPackageType(db.DefaultContext, user.ID, packages.TypeMaven)
|
pvs, err := packages.GetVersionsByPackageType(db.DefaultContext, user.ID, packages.TypeMaven)
|
||||||
|
@ -150,10 +165,18 @@ func TestPackageMaven(t *testing.T) {
|
||||||
t.Run("DownloadPOM", func(t *testing.T) {
|
t.Run("DownloadPOM", func(t *testing.T) {
|
||||||
defer tests.PrintCurrentTest(t)()
|
defer tests.PrintCurrentTest(t)()
|
||||||
|
|
||||||
req := NewRequest(t, "GET", fmt.Sprintf("%s/%s/%s.pom", root, packageVersion, filename))
|
req := NewRequest(t, "HEAD", fmt.Sprintf("%s/%s/%s.pom", root, packageVersion, filename))
|
||||||
req = AddBasicAuthHeader(req, user.Name)
|
req = AddBasicAuthHeader(req, user.Name)
|
||||||
resp := MakeRequest(t, req, http.StatusOK)
|
resp := MakeRequest(t, req, http.StatusOK)
|
||||||
|
|
||||||
|
checkHeaders(t, resp.Header(), "text/xml", int64(len(pomContent)))
|
||||||
|
|
||||||
|
req = NewRequest(t, "GET", fmt.Sprintf("%s/%s/%s.pom", root, packageVersion, filename))
|
||||||
|
req = AddBasicAuthHeader(req, user.Name)
|
||||||
|
resp = MakeRequest(t, req, http.StatusOK)
|
||||||
|
|
||||||
|
checkHeaders(t, resp.Header(), "text/xml", int64(len(pomContent)))
|
||||||
|
|
||||||
assert.Equal(t, []byte(pomContent), resp.Body.Bytes())
|
assert.Equal(t, []byte(pomContent), resp.Body.Bytes())
|
||||||
|
|
||||||
pvs, err := packages.GetVersionsByPackageType(db.DefaultContext, user.ID, packages.TypeMaven)
|
pvs, err := packages.GetVersionsByPackageType(db.DefaultContext, user.ID, packages.TypeMaven)
|
||||||
|
@ -191,6 +214,9 @@ func TestPackageMaven(t *testing.T) {
|
||||||
resp := MakeRequest(t, req, http.StatusOK)
|
resp := MakeRequest(t, req, http.StatusOK)
|
||||||
|
|
||||||
expectedMetadata := `<?xml version="1.0" encoding="UTF-8"?>` + "\n<metadata><groupId>com.gitea</groupId><artifactId>test-project</artifactId><versioning><release>1.0.1</release><latest>1.0.1</latest><versions><version>1.0.1</version></versions></versioning></metadata>"
|
expectedMetadata := `<?xml version="1.0" encoding="UTF-8"?>` + "\n<metadata><groupId>com.gitea</groupId><artifactId>test-project</artifactId><versioning><release>1.0.1</release><latest>1.0.1</latest><versions><version>1.0.1</version></versions></versioning></metadata>"
|
||||||
|
|
||||||
|
checkHeaders(t, resp.Header(), "text/xml", int64(len(expectedMetadata)))
|
||||||
|
|
||||||
assert.Equal(t, expectedMetadata, resp.Body.String())
|
assert.Equal(t, expectedMetadata, resp.Body.String())
|
||||||
|
|
||||||
for key, checksum := range map[string]string{
|
for key, checksum := range map[string]string{
|
||||||
|
|
Loading…
Reference in New Issue