mirror of
https://github.com/go-gitea/gitea.git
synced 2025-07-18 01:36:17 +03:00
Redirect to a presigned URL of HEAD for HEAD requests (#35088)
Resolves https://github.com/go-gitea/gitea/issues/35086. --------- Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
This commit is contained in:
@ -20,7 +20,7 @@ func IsArtifactV4(art *actions_model.ActionArtifact) bool {
|
|||||||
|
|
||||||
func DownloadArtifactV4ServeDirectOnly(ctx *context.Base, art *actions_model.ActionArtifact) (bool, error) {
|
func DownloadArtifactV4ServeDirectOnly(ctx *context.Base, art *actions_model.ActionArtifact) (bool, error) {
|
||||||
if setting.Actions.ArtifactStorage.ServeDirect() {
|
if setting.Actions.ArtifactStorage.ServeDirect() {
|
||||||
u, err := storage.ActionsArtifacts.URL(art.StoragePath, art.ArtifactPath, nil)
|
u, err := storage.ActionsArtifacts.URL(art.StoragePath, art.ArtifactPath, ctx.Req.Method, nil)
|
||||||
if u != nil && err == nil {
|
if u != nil && err == nil {
|
||||||
ctx.Redirect(u.String(), http.StatusFound)
|
ctx.Redirect(u.String(), http.StatusFound)
|
||||||
return true, nil
|
return true, nil
|
||||||
|
@ -36,8 +36,8 @@ func (s *ContentStore) ShouldServeDirect() bool {
|
|||||||
return setting.Packages.Storage.ServeDirect()
|
return setting.Packages.Storage.ServeDirect()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *ContentStore) GetServeDirectURL(key BlobHash256Key, filename string, reqParams url.Values) (*url.URL, error) {
|
func (s *ContentStore) GetServeDirectURL(key BlobHash256Key, filename, method string, reqParams url.Values) (*url.URL, error) {
|
||||||
return s.store.URL(KeyToRelativePath(key), filename, reqParams)
|
return s.store.URL(KeyToRelativePath(key), filename, method, reqParams)
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME: Workaround to be removed in v1.20
|
// FIXME: Workaround to be removed in v1.20
|
||||||
|
@ -247,7 +247,7 @@ func (a *AzureBlobStorage) Delete(path string) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// URL gets the redirect URL to a file. The presigned link is valid for 5 minutes.
|
// URL gets the redirect URL to a file. The presigned link is valid for 5 minutes.
|
||||||
func (a *AzureBlobStorage) URL(path, name string, reqParams url.Values) (*url.URL, error) {
|
func (a *AzureBlobStorage) URL(path, name, _ string, reqParams url.Values) (*url.URL, error) {
|
||||||
blobClient := a.getBlobClient(path)
|
blobClient := a.getBlobClient(path)
|
||||||
|
|
||||||
startTime := time.Now()
|
startTime := time.Now()
|
||||||
|
@ -30,7 +30,7 @@ func (s discardStorage) Delete(_ string) error {
|
|||||||
return fmt.Errorf("%s", s)
|
return fmt.Errorf("%s", s)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s discardStorage) URL(_, _ string, _ url.Values) (*url.URL, error) {
|
func (s discardStorage) URL(_, _, _ string, _ url.Values) (*url.URL, error) {
|
||||||
return nil, fmt.Errorf("%s", s)
|
return nil, fmt.Errorf("%s", s)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -37,7 +37,7 @@ func Test_discardStorage(t *testing.T) {
|
|||||||
assert.Error(t, err, string(tt))
|
assert.Error(t, err, string(tt))
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
got, err := tt.URL("path", "name", nil)
|
got, err := tt.URL("path", "name", "GET", nil)
|
||||||
assert.Nil(t, got)
|
assert.Nil(t, got)
|
||||||
assert.Errorf(t, err, string(tt))
|
assert.Errorf(t, err, string(tt))
|
||||||
}
|
}
|
||||||
|
@ -114,7 +114,7 @@ func (l *LocalStorage) Delete(path string) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// URL gets the redirect URL to a file
|
// URL gets the redirect URL to a file
|
||||||
func (l *LocalStorage) URL(path, name string, reqParams url.Values) (*url.URL, error) {
|
func (l *LocalStorage) URL(path, name, _ string, reqParams url.Values) (*url.URL, error) {
|
||||||
return nil, ErrURLNotSupported
|
return nil, ErrURLNotSupported
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -279,7 +279,7 @@ func (m *MinioStorage) Delete(path string) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// URL gets the redirect URL to a file. The presigned link is valid for 5 minutes.
|
// URL gets the redirect URL to a file. The presigned link is valid for 5 minutes.
|
||||||
func (m *MinioStorage) URL(path, name string, serveDirectReqParams url.Values) (*url.URL, error) {
|
func (m *MinioStorage) URL(path, name, method string, serveDirectReqParams url.Values) (*url.URL, error) {
|
||||||
// copy serveDirectReqParams
|
// copy serveDirectReqParams
|
||||||
reqParams, err := url.ParseQuery(serveDirectReqParams.Encode())
|
reqParams, err := url.ParseQuery(serveDirectReqParams.Encode())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -287,7 +287,12 @@ func (m *MinioStorage) URL(path, name string, serveDirectReqParams url.Values) (
|
|||||||
}
|
}
|
||||||
// TODO it may be good to embed images with 'inline' like ServeData does, but we don't want to have to read the file, do we?
|
// TODO it may be good to embed images with 'inline' like ServeData does, but we don't want to have to read the file, do we?
|
||||||
reqParams.Set("response-content-disposition", "attachment; filename=\""+quoteEscaper.Replace(name)+"\"")
|
reqParams.Set("response-content-disposition", "attachment; filename=\""+quoteEscaper.Replace(name)+"\"")
|
||||||
u, err := m.client.PresignedGetObject(m.ctx, m.bucket, m.buildMinioPath(path), 5*time.Minute, reqParams)
|
expires := 5 * time.Minute
|
||||||
|
if method == http.MethodHead {
|
||||||
|
u, err := m.client.PresignedHeadObject(m.ctx, m.bucket, m.buildMinioPath(path), expires, reqParams)
|
||||||
|
return u, convertMinioErr(err)
|
||||||
|
}
|
||||||
|
u, err := m.client.PresignedGetObject(m.ctx, m.bucket, m.buildMinioPath(path), expires, reqParams)
|
||||||
return u, convertMinioErr(err)
|
return u, convertMinioErr(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -63,7 +63,7 @@ type ObjectStorage interface {
|
|||||||
Save(path string, r io.Reader, size int64) (int64, error)
|
Save(path string, r io.Reader, size int64) (int64, error)
|
||||||
Stat(path string) (os.FileInfo, error)
|
Stat(path string) (os.FileInfo, error)
|
||||||
Delete(path string) error
|
Delete(path string) error
|
||||||
URL(path, name string, reqParams url.Values) (*url.URL, error)
|
URL(path, name, method string, reqParams url.Values) (*url.URL, error)
|
||||||
IterateObjects(path string, iterator func(path string, obj Object) error) error
|
IterateObjects(path string, iterator func(path string, obj Object) error) error
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -428,7 +428,7 @@ func (ar artifactRoutes) getDownloadArtifactURL(ctx *ArtifactContext) {
|
|||||||
for _, artifact := range artifacts {
|
for _, artifact := range artifacts {
|
||||||
var downloadURL string
|
var downloadURL string
|
||||||
if setting.Actions.ArtifactStorage.ServeDirect() {
|
if setting.Actions.ArtifactStorage.ServeDirect() {
|
||||||
u, err := ar.fs.URL(artifact.StoragePath, artifact.ArtifactName, nil)
|
u, err := ar.fs.URL(artifact.StoragePath, artifact.ArtifactName, ctx.Req.Method, nil)
|
||||||
if err != nil && !errors.Is(err, storage.ErrURLNotSupported) {
|
if err != nil && !errors.Is(err, storage.ErrURLNotSupported) {
|
||||||
log.Error("Error getting serve direct url: %v", err)
|
log.Error("Error getting serve direct url: %v", err)
|
||||||
}
|
}
|
||||||
|
@ -517,7 +517,7 @@ func (r *artifactV4Routes) getSignedArtifactURL(ctx *ArtifactContext) {
|
|||||||
respData := GetSignedArtifactURLResponse{}
|
respData := GetSignedArtifactURLResponse{}
|
||||||
|
|
||||||
if setting.Actions.ArtifactStorage.ServeDirect() {
|
if setting.Actions.ArtifactStorage.ServeDirect() {
|
||||||
u, err := storage.ActionsArtifacts.URL(artifact.StoragePath, artifact.ArtifactPath, nil)
|
u, err := storage.ActionsArtifacts.URL(artifact.StoragePath, artifact.ArtifactPath, ctx.Req.Method, nil)
|
||||||
if u != nil && err == nil {
|
if u != nil && err == nil {
|
||||||
respData.SignedUrl = u.String()
|
respData.SignedUrl = u.String()
|
||||||
}
|
}
|
||||||
|
@ -75,6 +75,7 @@ func GetRepositoryFile(ctx *context.Context) {
|
|||||||
Filename: alpine_service.IndexArchiveFilename,
|
Filename: alpine_service.IndexArchiveFilename,
|
||||||
CompositeKey: fmt.Sprintf("%s|%s|%s", ctx.PathParam("branch"), ctx.PathParam("repository"), ctx.PathParam("architecture")),
|
CompositeKey: fmt.Sprintf("%s|%s|%s", ctx.PathParam("branch"), ctx.PathParam("repository"), ctx.PathParam("architecture")),
|
||||||
},
|
},
|
||||||
|
ctx.Req.Method,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if errors.Is(err, util.ErrNotExist) {
|
if errors.Is(err, util.ErrNotExist) {
|
||||||
@ -216,7 +217,7 @@ func DownloadPackageFile(ctx *context.Context) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
s, u, pf, err := packages_service.OpenFileForDownload(ctx, pfs[0])
|
s, u, pf, err := packages_service.OpenFileForDownload(ctx, pfs[0], ctx.Req.Method)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if errors.Is(err, util.ErrNotExist) {
|
if errors.Is(err, util.ErrNotExist) {
|
||||||
apiError(ctx, http.StatusNotFound, err)
|
apiError(ctx, http.StatusNotFound, err)
|
||||||
|
@ -339,7 +339,7 @@ func CommonRoutes() *web.Router {
|
|||||||
r.Group("/{packagename}/{packageversion}", func() {
|
r.Group("/{packagename}/{packageversion}", func() {
|
||||||
r.Delete("", reqPackageAccess(perm.AccessModeWrite), generic.DeletePackage)
|
r.Delete("", reqPackageAccess(perm.AccessModeWrite), generic.DeletePackage)
|
||||||
r.Group("/{filename}", func() {
|
r.Group("/{filename}", func() {
|
||||||
r.Get("", generic.DownloadPackageFile)
|
r.Methods("HEAD,GET", "", generic.DownloadPackageFile)
|
||||||
r.Group("", func() {
|
r.Group("", func() {
|
||||||
r.Put("", generic.UploadPackage)
|
r.Put("", generic.UploadPackage)
|
||||||
r.Delete("", generic.DeletePackageFile)
|
r.Delete("", generic.DeletePackageFile)
|
||||||
|
@ -239,7 +239,7 @@ func GetPackageOrRepositoryFile(ctx *context.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
s, u, pf, err := packages_service.OpenFileForDownload(ctx, pfs[0])
|
s, u, pf, err := packages_service.OpenFileForDownload(ctx, pfs[0], ctx.Req.Method)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if errors.Is(err, util.ErrNotExist) {
|
if errors.Is(err, util.ErrNotExist) {
|
||||||
apiError(ctx, http.StatusNotFound, err)
|
apiError(ctx, http.StatusNotFound, err)
|
||||||
|
@ -176,6 +176,7 @@ func DownloadPackageFile(ctx *context.Context) {
|
|||||||
&packages_service.PackageFileInfo{
|
&packages_service.PackageFileInfo{
|
||||||
Filename: strings.ToLower(fmt.Sprintf("%s-%s.crate", ctx.PathParam("package"), ctx.PathParam("version"))),
|
Filename: strings.ToLower(fmt.Sprintf("%s-%s.crate", ctx.PathParam("package"), ctx.PathParam("version"))),
|
||||||
},
|
},
|
||||||
|
ctx.Req.Method,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if errors.Is(err, packages_model.ErrPackageNotExist) || errors.Is(err, packages_model.ErrPackageFileNotExist) {
|
if errors.Is(err, packages_model.ErrPackageNotExist) || errors.Is(err, packages_model.ErrPackageFileNotExist) {
|
||||||
|
@ -343,7 +343,7 @@ func DownloadPackage(ctx *context.Context) {
|
|||||||
|
|
||||||
pf := pd.Files[0].File
|
pf := pd.Files[0].File
|
||||||
|
|
||||||
s, u, _, err := packages_service.OpenFileForDownload(ctx, pf)
|
s, u, _, err := packages_service.OpenFileForDownload(ctx, pf, ctx.Req.Method)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
apiError(ctx, http.StatusInternalServerError, err)
|
apiError(ctx, http.StatusInternalServerError, err)
|
||||||
return
|
return
|
||||||
|
@ -171,6 +171,7 @@ func DownloadPackageFile(ctx *context.Context) {
|
|||||||
&packages_service.PackageFileInfo{
|
&packages_service.PackageFileInfo{
|
||||||
Filename: ctx.PathParam("filename"),
|
Filename: ctx.PathParam("filename"),
|
||||||
},
|
},
|
||||||
|
ctx.Req.Method,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if errors.Is(err, packages_model.ErrPackageNotExist) || errors.Is(err, packages_model.ErrPackageFileNotExist) {
|
if errors.Is(err, packages_model.ErrPackageNotExist) || errors.Is(err, packages_model.ErrPackageFileNotExist) {
|
||||||
|
@ -492,6 +492,7 @@ func downloadFile(ctx *context.Context, fileFilter container.Set[string], fileKe
|
|||||||
Filename: filename,
|
Filename: filename,
|
||||||
CompositeKey: fileKey,
|
CompositeKey: fileKey,
|
||||||
},
|
},
|
||||||
|
ctx.Req.Method,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if errors.Is(err, packages_model.ErrPackageNotExist) || errors.Is(err, packages_model.ErrPackageFileNotExist) {
|
if errors.Is(err, packages_model.ErrPackageNotExist) || errors.Is(err, packages_model.ErrPackageFileNotExist) {
|
||||||
|
@ -317,7 +317,7 @@ func DownloadPackageFile(ctx *context.Context) {
|
|||||||
|
|
||||||
pf := pfs[0]
|
pf := pfs[0]
|
||||||
|
|
||||||
s, u, _, err := packages_service.OpenFileForDownload(ctx, pf)
|
s, u, _, err := packages_service.OpenFileForDownload(ctx, pf, ctx.Req.Method)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
apiError(ctx, http.StatusInternalServerError, err)
|
apiError(ctx, http.StatusInternalServerError, err)
|
||||||
return
|
return
|
||||||
|
@ -710,7 +710,7 @@ func DeleteManifest(ctx *context.Context) {
|
|||||||
func serveBlob(ctx *context.Context, pfd *packages_model.PackageFileDescriptor) {
|
func serveBlob(ctx *context.Context, pfd *packages_model.PackageFileDescriptor) {
|
||||||
serveDirectReqParams := make(url.Values)
|
serveDirectReqParams := make(url.Values)
|
||||||
serveDirectReqParams.Set("response-content-type", pfd.Properties.GetByName(container_module.PropertyMediaType))
|
serveDirectReqParams.Set("response-content-type", pfd.Properties.GetByName(container_module.PropertyMediaType))
|
||||||
s, u, _, err := packages_service.OpenBlobForDownload(ctx, pfd.File, pfd.Blob, serveDirectReqParams)
|
s, u, _, err := packages_service.OpenBlobForDownload(ctx, pfd.File, pfd.Blob, ctx.Req.Method, serveDirectReqParams)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
apiError(ctx, http.StatusInternalServerError, err)
|
apiError(ctx, http.StatusInternalServerError, err)
|
||||||
return
|
return
|
||||||
|
@ -250,7 +250,7 @@ func downloadPackageFile(ctx *context.Context, opts *cran_model.SearchOptions) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
s, u, _, err := packages_service.OpenFileForDownload(ctx, pf)
|
s, u, _, err := packages_service.OpenFileForDownload(ctx, pf, ctx.Req.Method)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if errors.Is(err, util.ErrNotExist) {
|
if errors.Is(err, util.ErrNotExist) {
|
||||||
apiError(ctx, http.StatusNotFound, err)
|
apiError(ctx, http.StatusNotFound, err)
|
||||||
|
@ -66,6 +66,7 @@ func GetRepositoryFile(ctx *context.Context) {
|
|||||||
Filename: ctx.PathParam("filename"),
|
Filename: ctx.PathParam("filename"),
|
||||||
CompositeKey: key,
|
CompositeKey: key,
|
||||||
},
|
},
|
||||||
|
ctx.Req.Method,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if errors.Is(err, packages_model.ErrPackageNotExist) || errors.Is(err, packages_model.ErrPackageFileNotExist) {
|
if errors.Is(err, packages_model.ErrPackageNotExist) || errors.Is(err, packages_model.ErrPackageFileNotExist) {
|
||||||
@ -106,7 +107,7 @@ func GetRepositoryFileByHash(ctx *context.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
s, u, pf, err := packages_service.OpenFileForDownload(ctx, pfs[0])
|
s, u, pf, err := packages_service.OpenFileForDownload(ctx, pfs[0], ctx.Req.Method)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if errors.Is(err, util.ErrNotExist) {
|
if errors.Is(err, util.ErrNotExist) {
|
||||||
apiError(ctx, http.StatusNotFound, err)
|
apiError(ctx, http.StatusNotFound, err)
|
||||||
@ -222,6 +223,7 @@ func DownloadPackageFile(ctx *context.Context) {
|
|||||||
Filename: fmt.Sprintf("%s_%s_%s.deb", name, version, ctx.PathParam("architecture")),
|
Filename: fmt.Sprintf("%s_%s_%s.deb", name, version, ctx.PathParam("architecture")),
|
||||||
CompositeKey: fmt.Sprintf("%s|%s", ctx.PathParam("distribution"), ctx.PathParam("component")),
|
CompositeKey: fmt.Sprintf("%s|%s", ctx.PathParam("distribution"), ctx.PathParam("component")),
|
||||||
},
|
},
|
||||||
|
ctx.Req.Method,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if errors.Is(err, util.ErrNotExist) {
|
if errors.Is(err, util.ErrNotExist) {
|
||||||
|
@ -42,6 +42,7 @@ func DownloadPackageFile(ctx *context.Context) {
|
|||||||
&packages_service.PackageFileInfo{
|
&packages_service.PackageFileInfo{
|
||||||
Filename: ctx.PathParam("filename"),
|
Filename: ctx.PathParam("filename"),
|
||||||
},
|
},
|
||||||
|
ctx.Req.Method,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if errors.Is(err, packages_model.ErrPackageNotExist) || errors.Is(err, packages_model.ErrPackageFileNotExist) {
|
if errors.Is(err, packages_model.ErrPackageNotExist) || errors.Is(err, packages_model.ErrPackageFileNotExist) {
|
||||||
|
@ -106,7 +106,7 @@ func DownloadPackageFile(ctx *context.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
s, u, _, err := packages_service.OpenFileForDownload(ctx, pfs[0])
|
s, u, _, err := packages_service.OpenFileForDownload(ctx, pfs[0], ctx.Req.Method)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if errors.Is(err, util.ErrNotExist) {
|
if errors.Is(err, util.ErrNotExist) {
|
||||||
apiError(ctx, http.StatusNotFound, err)
|
apiError(ctx, http.StatusNotFound, err)
|
||||||
|
@ -128,6 +128,7 @@ func DownloadPackageFile(ctx *context.Context) {
|
|||||||
&packages_service.PackageFileInfo{
|
&packages_service.PackageFileInfo{
|
||||||
Filename: filename,
|
Filename: filename,
|
||||||
},
|
},
|
||||||
|
ctx.Req.Method,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if errors.Is(err, packages_model.ErrPackageFileNotExist) {
|
if errors.Is(err, packages_model.ErrPackageFileNotExist) {
|
||||||
|
@ -223,7 +223,7 @@ func servePackageFile(ctx *context.Context, params parameters, serveContent bool
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
s, u, _, err := packages_service.OpenBlobForDownload(ctx, pf, pb, nil)
|
s, u, _, err := packages_service.OpenBlobForDownload(ctx, pf, pb, ctx.Req.Method, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
apiError(ctx, http.StatusInternalServerError, err)
|
apiError(ctx, http.StatusInternalServerError, err)
|
||||||
return
|
return
|
||||||
|
@ -96,6 +96,7 @@ func DownloadPackageFile(ctx *context.Context) {
|
|||||||
&packages_service.PackageFileInfo{
|
&packages_service.PackageFileInfo{
|
||||||
Filename: filename,
|
Filename: filename,
|
||||||
},
|
},
|
||||||
|
ctx.Req.Method,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if errors.Is(err, packages_model.ErrPackageNotExist) || errors.Is(err, packages_model.ErrPackageFileNotExist) {
|
if errors.Is(err, packages_model.ErrPackageNotExist) || errors.Is(err, packages_model.ErrPackageFileNotExist) {
|
||||||
@ -138,6 +139,7 @@ func DownloadPackageFileByName(ctx *context.Context) {
|
|||||||
&packages_service.PackageFileInfo{
|
&packages_service.PackageFileInfo{
|
||||||
Filename: filename,
|
Filename: filename,
|
||||||
},
|
},
|
||||||
|
ctx.Req.Method,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if errors.Is(err, packages_model.ErrPackageFileNotExist) {
|
if errors.Is(err, packages_model.ErrPackageFileNotExist) {
|
||||||
|
@ -416,6 +416,7 @@ func DownloadPackageFile(ctx *context.Context) {
|
|||||||
&packages_service.PackageFileInfo{
|
&packages_service.PackageFileInfo{
|
||||||
Filename: filename,
|
Filename: filename,
|
||||||
},
|
},
|
||||||
|
ctx.Req.Method,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if errors.Is(err, packages_model.ErrPackageNotExist) || errors.Is(err, packages_model.ErrPackageFileNotExist) {
|
if errors.Is(err, packages_model.ErrPackageNotExist) || errors.Is(err, packages_model.ErrPackageFileNotExist) {
|
||||||
@ -669,7 +670,7 @@ func DownloadSymbolFile(ctx *context.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
s, u, pf, err := packages_service.OpenFileForDownload(ctx, pfs[0])
|
s, u, pf, err := packages_service.OpenFileForDownload(ctx, pfs[0], ctx.Req.Method)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if errors.Is(err, packages_model.ErrPackageNotExist) || errors.Is(err, packages_model.ErrPackageFileNotExist) {
|
if errors.Is(err, packages_model.ErrPackageNotExist) || errors.Is(err, packages_model.ErrPackageFileNotExist) {
|
||||||
apiError(ctx, http.StatusNotFound, err)
|
apiError(ctx, http.StatusNotFound, err)
|
||||||
|
@ -274,7 +274,7 @@ func DownloadPackageFile(ctx *context.Context) {
|
|||||||
|
|
||||||
pf := pd.Files[0].File
|
pf := pd.Files[0].File
|
||||||
|
|
||||||
s, u, _, err := packages_service.OpenFileForDownload(ctx, pf)
|
s, u, _, err := packages_service.OpenFileForDownload(ctx, pf, ctx.Req.Method)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
apiError(ctx, http.StatusInternalServerError, err)
|
apiError(ctx, http.StatusInternalServerError, err)
|
||||||
return
|
return
|
||||||
|
@ -93,6 +93,7 @@ func DownloadPackageFile(ctx *context.Context) {
|
|||||||
&packages_service.PackageFileInfo{
|
&packages_service.PackageFileInfo{
|
||||||
Filename: filename,
|
Filename: filename,
|
||||||
},
|
},
|
||||||
|
ctx.Req.Method,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if errors.Is(err, packages_model.ErrPackageNotExist) || errors.Is(err, packages_model.ErrPackageFileNotExist) {
|
if errors.Is(err, packages_model.ErrPackageNotExist) || errors.Is(err, packages_model.ErrPackageFileNotExist) {
|
||||||
|
@ -103,6 +103,7 @@ func GetRepositoryFile(ctx *context.Context) {
|
|||||||
Filename: ctx.PathParam("filename"),
|
Filename: ctx.PathParam("filename"),
|
||||||
CompositeKey: ctx.PathParam("group"),
|
CompositeKey: ctx.PathParam("group"),
|
||||||
},
|
},
|
||||||
|
ctx.Req.Method,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if errors.Is(err, util.ErrNotExist) {
|
if errors.Is(err, util.ErrNotExist) {
|
||||||
@ -232,6 +233,7 @@ func DownloadPackageFile(ctx *context.Context) {
|
|||||||
Filename: fmt.Sprintf("%s-%s.%s.rpm", name, version, ctx.PathParam("architecture")),
|
Filename: fmt.Sprintf("%s-%s.%s.rpm", name, version, ctx.PathParam("architecture")),
|
||||||
CompositeKey: ctx.PathParam("group"),
|
CompositeKey: ctx.PathParam("group"),
|
||||||
},
|
},
|
||||||
|
ctx.Req.Method,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if errors.Is(err, util.ErrNotExist) {
|
if errors.Is(err, util.ErrNotExist) {
|
||||||
|
@ -184,6 +184,7 @@ func DownloadPackageFile(ctx *context.Context) {
|
|||||||
&packages_service.PackageFileInfo{
|
&packages_service.PackageFileInfo{
|
||||||
Filename: filename,
|
Filename: filename,
|
||||||
},
|
},
|
||||||
|
ctx.Req.Method,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if errors.Is(err, packages_model.ErrPackageFileNotExist) {
|
if errors.Is(err, packages_model.ErrPackageFileNotExist) {
|
||||||
|
@ -429,7 +429,7 @@ func DownloadPackageFile(ctx *context.Context) {
|
|||||||
|
|
||||||
pf := pd.Files[0].File
|
pf := pd.Files[0].File
|
||||||
|
|
||||||
s, u, _, err := packages_service.OpenFileForDownload(ctx, pf)
|
s, u, _, err := packages_service.OpenFileForDownload(ctx, pf, ctx.Req.Method)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
apiError(ctx, http.StatusInternalServerError, err)
|
apiError(ctx, http.StatusInternalServerError, err)
|
||||||
return
|
return
|
||||||
|
@ -229,6 +229,7 @@ func DownloadPackageFile(ctx *context.Context) {
|
|||||||
&packages_service.PackageFileInfo{
|
&packages_service.PackageFileInfo{
|
||||||
Filename: ctx.PathParam("provider"),
|
Filename: ctx.PathParam("provider"),
|
||||||
},
|
},
|
||||||
|
ctx.Req.Method,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if errors.Is(err, packages_model.ErrPackageNotExist) || errors.Is(err, packages_model.ErrPackageFileNotExist) {
|
if errors.Is(err, packages_model.ErrPackageNotExist) || errors.Is(err, packages_model.ErrPackageFileNotExist) {
|
||||||
|
@ -210,7 +210,7 @@ func GetRawFileOrLFS(ctx *context.APIContext) {
|
|||||||
|
|
||||||
if setting.LFS.Storage.ServeDirect() {
|
if setting.LFS.Storage.ServeDirect() {
|
||||||
// If we have a signed url (S3, object storage), redirect to this directly.
|
// If we have a signed url (S3, object storage), redirect to this directly.
|
||||||
u, err := storage.LFS.URL(pointer.RelativePath(), blob.Name(), nil)
|
u, err := storage.LFS.URL(pointer.RelativePath(), blob.Name(), ctx.Req.Method, nil)
|
||||||
if u != nil && err == nil {
|
if u != nil && err == nil {
|
||||||
ctx.Redirect(u.String())
|
ctx.Redirect(u.String())
|
||||||
return
|
return
|
||||||
@ -331,7 +331,7 @@ func download(ctx *context.APIContext, archiveName string, archiver *repo_model.
|
|||||||
rPath := archiver.RelativePath()
|
rPath := archiver.RelativePath()
|
||||||
if setting.RepoArchive.Storage.ServeDirect() {
|
if setting.RepoArchive.Storage.ServeDirect() {
|
||||||
// If we have a signed url (S3, object storage), redirect to this directly.
|
// If we have a signed url (S3, object storage), redirect to this directly.
|
||||||
u, err := storage.RepoArchives.URL(rPath, downloadName, nil)
|
u, err := storage.RepoArchives.URL(rPath, downloadName, ctx.Req.Method, nil)
|
||||||
if u != nil && err == nil {
|
if u != nil && err == nil {
|
||||||
ctx.Redirect(u.String())
|
ctx.Redirect(u.String())
|
||||||
return
|
return
|
||||||
|
@ -39,7 +39,7 @@ func avatarStorageHandler(storageSetting *setting.Storage, prefix string, objSto
|
|||||||
rPath := strings.TrimPrefix(req.URL.Path, "/"+prefix+"/")
|
rPath := strings.TrimPrefix(req.URL.Path, "/"+prefix+"/")
|
||||||
rPath = util.PathJoinRelX(rPath)
|
rPath = util.PathJoinRelX(rPath)
|
||||||
|
|
||||||
u, err := objStore.URL(rPath, path.Base(rPath), nil)
|
u, err := objStore.URL(rPath, path.Base(rPath), req.Method, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if os.IsNotExist(err) || errors.Is(err, os.ErrNotExist) {
|
if os.IsNotExist(err) || errors.Is(err, os.ErrNotExist) {
|
||||||
log.Warn("Unable to find %s %s", prefix, rPath)
|
log.Warn("Unable to find %s %s", prefix, rPath)
|
||||||
|
@ -129,7 +129,7 @@ func ServeAttachment(ctx *context.Context, uuid string) {
|
|||||||
|
|
||||||
if setting.Attachment.Storage.ServeDirect() {
|
if setting.Attachment.Storage.ServeDirect() {
|
||||||
// If we have a signed url (S3, object storage), redirect to this directly.
|
// If we have a signed url (S3, object storage), redirect to this directly.
|
||||||
u, err := storage.Attachments.URL(attach.RelativePath(), attach.Name, nil)
|
u, err := storage.Attachments.URL(attach.RelativePath(), attach.Name, ctx.Req.Method, nil)
|
||||||
|
|
||||||
if u != nil && err == nil {
|
if u != nil && err == nil {
|
||||||
ctx.Redirect(u.String())
|
ctx.Redirect(u.String())
|
||||||
|
@ -54,7 +54,7 @@ func ServeBlobOrLFS(ctx *context.Context, blob *git.Blob, lastModified *time.Tim
|
|||||||
|
|
||||||
if setting.LFS.Storage.ServeDirect() {
|
if setting.LFS.Storage.ServeDirect() {
|
||||||
// If we have a signed url (S3, object storage, blob storage), redirect to this directly.
|
// If we have a signed url (S3, object storage, blob storage), redirect to this directly.
|
||||||
u, err := storage.LFS.URL(pointer.RelativePath(), blob.Name(), nil)
|
u, err := storage.LFS.URL(pointer.RelativePath(), blob.Name(), ctx.Req.Method, nil)
|
||||||
if u != nil && err == nil {
|
if u != nil && err == nil {
|
||||||
ctx.Redirect(u.String())
|
ctx.Redirect(u.String())
|
||||||
return nil
|
return nil
|
||||||
|
@ -398,7 +398,7 @@ func download(ctx *context.Context, archiveName string, archiver *repo_model.Rep
|
|||||||
rPath := archiver.RelativePath()
|
rPath := archiver.RelativePath()
|
||||||
if setting.RepoArchive.Storage.ServeDirect() {
|
if setting.RepoArchive.Storage.ServeDirect() {
|
||||||
// If we have a signed url (S3, object storage), redirect to this directly.
|
// If we have a signed url (S3, object storage), redirect to this directly.
|
||||||
u, err := storage.RepoArchives.URL(rPath, downloadName, nil)
|
u, err := storage.RepoArchives.URL(rPath, downloadName, ctx.Req.Method, nil)
|
||||||
if u != nil && err == nil {
|
if u != nil && err == nil {
|
||||||
ctx.Redirect(u.String())
|
ctx.Redirect(u.String())
|
||||||
return
|
return
|
||||||
|
@ -513,7 +513,7 @@ func DownloadPackageFile(ctx *context.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
s, u, _, err := packages_service.OpenFileForDownload(ctx, pf)
|
s, u, _, err := packages_service.OpenFileForDownload(ctx, pf, ctx.Req.Method)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctx.ServerError("OpenFileForDownload", err)
|
ctx.ServerError("OpenFileForDownload", err)
|
||||||
return
|
return
|
||||||
|
@ -43,6 +43,7 @@ type requestContext struct {
|
|||||||
User string
|
User string
|
||||||
Repo string
|
Repo string
|
||||||
Authorization string
|
Authorization string
|
||||||
|
Method string
|
||||||
}
|
}
|
||||||
|
|
||||||
// Claims is a JWT Token Claims
|
// Claims is a JWT Token Claims
|
||||||
@ -397,6 +398,7 @@ func getRequestContext(ctx *context.Context) *requestContext {
|
|||||||
User: ctx.PathParam("username"),
|
User: ctx.PathParam("username"),
|
||||||
Repo: strings.TrimSuffix(ctx.PathParam("reponame"), ".git"),
|
Repo: strings.TrimSuffix(ctx.PathParam("reponame"), ".git"),
|
||||||
Authorization: ctx.Req.Header.Get("Authorization"),
|
Authorization: ctx.Req.Header.Get("Authorization"),
|
||||||
|
Method: ctx.Req.Method,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -465,7 +467,7 @@ func buildObjectResponse(rc *requestContext, pointer lfs_module.Pointer, downloa
|
|||||||
var link *lfs_module.Link
|
var link *lfs_module.Link
|
||||||
if setting.LFS.Storage.ServeDirect() {
|
if setting.LFS.Storage.ServeDirect() {
|
||||||
// If we have a signed url (S3, object storage), redirect to this directly.
|
// If we have a signed url (S3, object storage), redirect to this directly.
|
||||||
u, err := storage.LFS.URL(pointer.RelativePath(), pointer.Oid, nil)
|
u, err := storage.LFS.URL(pointer.RelativePath(), pointer.Oid, rc.Method, nil)
|
||||||
if u != nil && err == nil {
|
if u != nil && err == nil {
|
||||||
// Presigned url does not need the Authorization header
|
// Presigned url does not need the Authorization header
|
||||||
// https://github.com/go-gitea/gitea/issues/21525
|
// https://github.com/go-gitea/gitea/issues/21525
|
||||||
|
@ -9,6 +9,7 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
@ -564,7 +565,7 @@ func DeletePackageFile(ctx context.Context, pf *packages_model.PackageFile) erro
|
|||||||
}
|
}
|
||||||
|
|
||||||
// OpenFileForDownloadByPackageNameAndVersion returns the content of the specific package file and increases the download counter.
|
// OpenFileForDownloadByPackageNameAndVersion returns the content of the specific package file and increases the download counter.
|
||||||
func OpenFileForDownloadByPackageNameAndVersion(ctx context.Context, pvi *PackageInfo, pfi *PackageFileInfo) (io.ReadSeekCloser, *url.URL, *packages_model.PackageFile, error) {
|
func OpenFileForDownloadByPackageNameAndVersion(ctx context.Context, pvi *PackageInfo, pfi *PackageFileInfo, method string) (io.ReadSeekCloser, *url.URL, *packages_model.PackageFile, error) {
|
||||||
log.Trace("Getting package file stream: %v, %v, %s, %s, %s, %s", pvi.Owner.ID, pvi.PackageType, pvi.Name, pvi.Version, pfi.Filename, pfi.CompositeKey)
|
log.Trace("Getting package file stream: %v, %v, %s, %s, %s, %s", pvi.Owner.ID, pvi.PackageType, pvi.Name, pvi.Version, pfi.Filename, pfi.CompositeKey)
|
||||||
|
|
||||||
pv, err := packages_model.GetVersionByNameAndVersion(ctx, pvi.Owner.ID, pvi.PackageType, pvi.Name, pvi.Version)
|
pv, err := packages_model.GetVersionByNameAndVersion(ctx, pvi.Owner.ID, pvi.PackageType, pvi.Name, pvi.Version)
|
||||||
@ -576,27 +577,27 @@ func OpenFileForDownloadByPackageNameAndVersion(ctx context.Context, pvi *Packag
|
|||||||
return nil, nil, nil, err
|
return nil, nil, nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return OpenFileForDownloadByPackageVersion(ctx, pv, pfi)
|
return OpenFileForDownloadByPackageVersion(ctx, pv, pfi, method)
|
||||||
}
|
}
|
||||||
|
|
||||||
// OpenFileForDownloadByPackageVersion returns the content of the specific package file and increases the download counter.
|
// OpenFileForDownloadByPackageVersion returns the content of the specific package file and increases the download counter.
|
||||||
func OpenFileForDownloadByPackageVersion(ctx context.Context, pv *packages_model.PackageVersion, pfi *PackageFileInfo) (io.ReadSeekCloser, *url.URL, *packages_model.PackageFile, error) {
|
func OpenFileForDownloadByPackageVersion(ctx context.Context, pv *packages_model.PackageVersion, pfi *PackageFileInfo, method string) (io.ReadSeekCloser, *url.URL, *packages_model.PackageFile, error) {
|
||||||
pf, err := packages_model.GetFileForVersionByName(ctx, pv.ID, pfi.Filename, pfi.CompositeKey)
|
pf, err := packages_model.GetFileForVersionByName(ctx, pv.ID, pfi.Filename, pfi.CompositeKey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, nil, err
|
return nil, nil, nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return OpenFileForDownload(ctx, pf)
|
return OpenFileForDownload(ctx, pf, method)
|
||||||
}
|
}
|
||||||
|
|
||||||
// OpenFileForDownload returns the content of the specific package file and increases the download counter.
|
// OpenFileForDownload returns the content of the specific package file and increases the download counter.
|
||||||
func OpenFileForDownload(ctx context.Context, pf *packages_model.PackageFile) (io.ReadSeekCloser, *url.URL, *packages_model.PackageFile, error) {
|
func OpenFileForDownload(ctx context.Context, pf *packages_model.PackageFile, method string) (io.ReadSeekCloser, *url.URL, *packages_model.PackageFile, error) {
|
||||||
pb, err := packages_model.GetBlobByID(ctx, pf.BlobID)
|
pb, err := packages_model.GetBlobByID(ctx, pf.BlobID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, nil, err
|
return nil, nil, nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return OpenBlobForDownload(ctx, pf, pb, nil)
|
return OpenBlobForDownload(ctx, pf, pb, method, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
func OpenBlobStream(pb *packages_model.PackageBlob) (io.ReadSeekCloser, error) {
|
func OpenBlobStream(pb *packages_model.PackageBlob) (io.ReadSeekCloser, error) {
|
||||||
@ -607,7 +608,7 @@ func OpenBlobStream(pb *packages_model.PackageBlob) (io.ReadSeekCloser, error) {
|
|||||||
|
|
||||||
// OpenBlobForDownload returns the content of the specific package blob and increases the download counter.
|
// OpenBlobForDownload returns the content of the specific package blob and increases the download counter.
|
||||||
// If the storage supports direct serving and it's enabled, only the direct serving url is returned.
|
// If the storage supports direct serving and it's enabled, only the direct serving url is returned.
|
||||||
func OpenBlobForDownload(ctx context.Context, pf *packages_model.PackageFile, pb *packages_model.PackageBlob, serveDirectReqParams url.Values) (io.ReadSeekCloser, *url.URL, *packages_model.PackageFile, error) {
|
func OpenBlobForDownload(ctx context.Context, pf *packages_model.PackageFile, pb *packages_model.PackageBlob, method string, serveDirectReqParams url.Values) (io.ReadSeekCloser, *url.URL, *packages_model.PackageFile, error) {
|
||||||
key := packages_module.BlobHash256Key(pb.HashSHA256)
|
key := packages_module.BlobHash256Key(pb.HashSHA256)
|
||||||
|
|
||||||
cs := packages_module.NewContentStore()
|
cs := packages_module.NewContentStore()
|
||||||
@ -617,23 +618,24 @@ func OpenBlobForDownload(ctx context.Context, pf *packages_model.PackageFile, pb
|
|||||||
var err error
|
var err error
|
||||||
|
|
||||||
if cs.ShouldServeDirect() {
|
if cs.ShouldServeDirect() {
|
||||||
u, err = cs.GetServeDirectURL(key, pf.Name, serveDirectReqParams)
|
u, err = cs.GetServeDirectURL(key, pf.Name, method, serveDirectReqParams)
|
||||||
if err != nil && !errors.Is(err, storage.ErrURLNotSupported) {
|
if err != nil && !errors.Is(err, storage.ErrURLNotSupported) {
|
||||||
log.Error("Error getting serve direct url: %v", err)
|
log.Error("Error getting serve direct url (fallback to local reader): %v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if u == nil {
|
if u == nil {
|
||||||
s, err = cs.OpenBlob(key)
|
s, err = cs.OpenBlob(key)
|
||||||
}
|
}
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
if err == nil {
|
if pf.IsLead && method == http.MethodGet {
|
||||||
if pf.IsLead {
|
if err := packages_model.IncrementDownloadCounter(ctx, pf.VersionID); err != nil {
|
||||||
if err := packages_model.IncrementDownloadCounter(ctx, pf.VersionID); err != nil {
|
log.Error("Error incrementing download counter: %v", err)
|
||||||
log.Error("Error incrementing download counter: %v", err)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return s, u, pf, err
|
return s, u, pf, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// RemoveAllPackages for User
|
// RemoveAllPackages for User
|
||||||
|
@ -141,37 +141,25 @@ func TestPackageGeneric(t *testing.T) {
|
|||||||
t.Run("ServeDirect", func(t *testing.T) {
|
t.Run("ServeDirect", func(t *testing.T) {
|
||||||
defer tests.PrintCurrentTest(t)()
|
defer tests.PrintCurrentTest(t)()
|
||||||
|
|
||||||
if setting.Packages.Storage.Type != setting.MinioStorageType && setting.Packages.Storage.Type != setting.AzureBlobStorageType {
|
|
||||||
t.Skip("Test skipped for non-Minio-storage and non-AzureBlob-storage.")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if setting.Packages.Storage.Type == setting.MinioStorageType {
|
if setting.Packages.Storage.Type == setting.MinioStorageType {
|
||||||
if !setting.Packages.Storage.MinioConfig.ServeDirect {
|
defer test.MockVariableValue(&setting.Packages.Storage.MinioConfig.ServeDirect, true)()
|
||||||
old := setting.Packages.Storage.MinioConfig.ServeDirect
|
|
||||||
defer func() {
|
|
||||||
setting.Packages.Storage.MinioConfig.ServeDirect = old
|
|
||||||
}()
|
|
||||||
|
|
||||||
setting.Packages.Storage.MinioConfig.ServeDirect = true
|
|
||||||
}
|
|
||||||
} else if setting.Packages.Storage.Type == setting.AzureBlobStorageType {
|
} else if setting.Packages.Storage.Type == setting.AzureBlobStorageType {
|
||||||
if !setting.Packages.Storage.AzureBlobConfig.ServeDirect {
|
defer test.MockVariableValue(&setting.Packages.Storage.AzureBlobConfig.ServeDirect, true)()
|
||||||
old := setting.Packages.Storage.AzureBlobConfig.ServeDirect
|
} else {
|
||||||
defer func() {
|
t.Skip("Test skipped for non-Minio-storage and non-AzureBlob-storage.")
|
||||||
setting.Packages.Storage.AzureBlobConfig.ServeDirect = old
|
|
||||||
}()
|
|
||||||
|
|
||||||
setting.Packages.Storage.AzureBlobConfig.ServeDirect = true
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
req := NewRequest(t, "GET", url+"/"+filename)
|
req = NewRequest(t, "HEAD", url+"/"+filename)
|
||||||
resp := MakeRequest(t, req, http.StatusSeeOther)
|
resp = MakeRequest(t, req, http.StatusSeeOther)
|
||||||
|
location := resp.Header().Get("Location")
|
||||||
|
assert.NotEmpty(t, location)
|
||||||
|
checkDownloadCount(2)
|
||||||
|
|
||||||
|
req = NewRequest(t, "GET", url+"/"+filename)
|
||||||
|
resp = MakeRequest(t, req, http.StatusSeeOther)
|
||||||
checkDownloadCount(3)
|
checkDownloadCount(3)
|
||||||
|
|
||||||
location := resp.Header().Get("Location")
|
location = resp.Header().Get("Location")
|
||||||
assert.NotEmpty(t, location)
|
assert.NotEmpty(t, location)
|
||||||
|
|
||||||
resp2, err := (&http.Client{}).Get(location)
|
resp2, err := (&http.Client{}).Get(location)
|
||||||
|
Reference in New Issue
Block a user