From dc0253b0637bbf367ad330612900e780c6b2b0e6 Mon Sep 17 00:00:00 2001
From: KN4CK3R <admin@oldschoolhack.me>
Date: Thu, 25 Aug 2022 18:05:21 +0200
Subject: [PATCH] Replace `ServeStream` with `ServeContent` (#20903)

* Replace ServeStream with ServeContent.

* Update modules/timeutil/timestamp.go

Co-authored-by: delvh <dev.lh@web.de>

Co-authored-by: delvh <dev.lh@web.de>
Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com>
Co-authored-by: techknowlogick <techknowlogick@gitea.io>
---
 modules/context/context.go                | 18 +-----------------
 modules/timeutil/timestamp.go             |  5 +++++
 routers/api/packages/composer/api.go      |  2 +-
 routers/api/packages/composer/composer.go |  2 +-
 routers/api/packages/conan/conan.go       |  8 ++++----
 routers/api/packages/generic/generic.go   |  2 +-
 routers/api/packages/helm/helm.go         |  2 +-
 routers/api/packages/maven/maven.go       |  2 +-
 routers/api/packages/npm/npm.go           |  2 +-
 routers/api/packages/nuget/api.go         |  2 +-
 routers/api/packages/nuget/nuget.go       |  6 +++---
 routers/api/packages/pub/pub.go           |  4 ++--
 routers/api/packages/pypi/pypi.go         |  2 +-
 routers/api/packages/rubygems/rubygems.go |  2 +-
 routers/web/repo/repo.go                  |  3 ++-
 routers/web/user/package.go               |  2 +-
 services/packages/packages.go             |  8 ++++----
 17 files changed, 31 insertions(+), 41 deletions(-)

diff --git a/modules/context/context.go b/modules/context/context.go
index 0b9898acef..45f1978e97 100644
--- a/modules/context/context.go
+++ b/modules/context/context.go
@@ -358,14 +358,7 @@ func (ctx *Context) SetServeHeaders(filename string) {
 }
 
 // ServeContent serves content to http request
-func (ctx *Context) ServeContent(name string, r io.ReadSeeker, params ...interface{}) {
-	modTime := time.Now()
-	for _, p := range params {
-		switch v := p.(type) {
-		case time.Time:
-			modTime = v
-		}
-	}
+func (ctx *Context) ServeContent(name string, r io.ReadSeeker, modTime time.Time) {
 	ctx.SetServeHeaders(name)
 	http.ServeContent(ctx.Resp, ctx.Req, name, modTime, r)
 }
@@ -382,15 +375,6 @@ func (ctx *Context) ServeFile(file string, names ...string) {
 	http.ServeFile(ctx.Resp, ctx.Req, file)
 }
 
-// ServeStream serves file via io stream
-func (ctx *Context) ServeStream(rd io.Reader, name string) {
-	ctx.SetServeHeaders(name)
-	_, err := io.Copy(ctx.Resp, rd)
-	if err != nil {
-		ctx.ServerError("Download file failed", err)
-	}
-}
-
 // UploadStream returns the request body or the first form file
 // Only form files need to get closed.
 func (ctx *Context) UploadStream() (rd io.ReadCloser, needToClose bool, err error) {
diff --git a/modules/timeutil/timestamp.go b/modules/timeutil/timestamp.go
index 88008d1fad..40fcb8603f 100644
--- a/modules/timeutil/timestamp.go
+++ b/modules/timeutil/timestamp.go
@@ -54,6 +54,11 @@ func (ts TimeStamp) AsTime() (tm time.Time) {
 	return ts.AsTimeInLocation(setting.DefaultUILocation)
 }
 
+// AsLocalTime convert timestamp as time.Time in local location
+func (ts TimeStamp) AsLocalTime() time.Time {
+	return time.Unix(int64(ts), 0)
+}
+
 // AsTimeInLocation convert timestamp as time.Time in Local locale
 func (ts TimeStamp) AsTimeInLocation(loc *time.Location) (tm time.Time) {
 	tm = time.Unix(int64(ts), 0).In(loc)
diff --git a/routers/api/packages/composer/api.go b/routers/api/packages/composer/api.go
index 45bb7eae1c..ed52d16513 100644
--- a/routers/api/packages/composer/api.go
+++ b/routers/api/packages/composer/api.go
@@ -99,7 +99,7 @@ func createPackageMetadataResponse(registryURL string, pds []*packages_model.Pac
 			Name:     pd.Package.Name,
 			Version:  pd.Version.Version,
 			Type:     packageType,
-			Created:  time.Unix(int64(pd.Version.CreatedUnix), 0),
+			Created:  pd.Version.CreatedUnix.AsLocalTime(),
 			Metadata: pd.Metadata.(*composer_module.Metadata),
 			Dist: Dist{
 				Type:     "zip",
diff --git a/routers/api/packages/composer/composer.go b/routers/api/packages/composer/composer.go
index 81cef39f1c..86ef7cbd9a 100644
--- a/routers/api/packages/composer/composer.go
+++ b/routers/api/packages/composer/composer.go
@@ -184,7 +184,7 @@ func DownloadPackageFile(ctx *context.Context) {
 	}
 	defer s.Close()
 
-	ctx.ServeStream(s, pf.Name)
+	ctx.ServeContent(pf.Name, s, 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 04b0bb6cdd..90924c7c4b 100644
--- a/routers/api/packages/conan/conan.go
+++ b/routers/api/packages/conan/conan.go
@@ -475,7 +475,7 @@ func downloadFile(ctx *context.Context, fileFilter stringSet, fileKey string) {
 	}
 	defer s.Close()
 
-	ctx.ServeStream(s, pf.Name)
+	ctx.ServeContent(pf.Name, s, pf.CreatedUnix.AsLocalTime())
 }
 
 // DeleteRecipeV1 deletes the requested recipe(s)
@@ -723,7 +723,7 @@ func listRevisions(ctx *context.Context, revisions []*conan_model.PropertyValue)
 
 	revs := make([]*revisionInfo, 0, len(revisions))
 	for _, rev := range revisions {
-		revs = append(revs, &revisionInfo{Revision: rev.Value, Time: time.Unix(int64(rev.CreatedUnix), 0)})
+		revs = append(revs, &revisionInfo{Revision: rev.Value, Time: rev.CreatedUnix.AsLocalTime()})
 	}
 
 	jsonResponse(ctx, http.StatusOK, &RevisionList{revs})
@@ -743,7 +743,7 @@ func LatestRecipeRevision(ctx *context.Context) {
 		return
 	}
 
-	jsonResponse(ctx, http.StatusOK, &revisionInfo{Revision: revision.Value, Time: time.Unix(int64(revision.CreatedUnix), 0)})
+	jsonResponse(ctx, http.StatusOK, &revisionInfo{Revision: revision.Value, Time: revision.CreatedUnix.AsLocalTime()})
 }
 
 // LatestPackageRevision gets the latest package revision
@@ -760,7 +760,7 @@ func LatestPackageRevision(ctx *context.Context) {
 		return
 	}
 
-	jsonResponse(ctx, http.StatusOK, &revisionInfo{Revision: revision.Value, Time: time.Unix(int64(revision.CreatedUnix), 0)})
+	jsonResponse(ctx, http.StatusOK, &revisionInfo{Revision: revision.Value, Time: revision.CreatedUnix.AsLocalTime()})
 }
 
 // ListRecipeRevisionFiles gets a list of all recipe revision files
diff --git a/routers/api/packages/generic/generic.go b/routers/api/packages/generic/generic.go
index 79e5afb03c..81891bec26 100644
--- a/routers/api/packages/generic/generic.go
+++ b/routers/api/packages/generic/generic.go
@@ -53,7 +53,7 @@ func DownloadPackageFile(ctx *context.Context) {
 	}
 	defer s.Close()
 
-	ctx.ServeStream(s, pf.Name)
+	ctx.ServeContent(pf.Name, s, 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 f59cfc7c7b..9c85e0874f 100644
--- a/routers/api/packages/helm/helm.go
+++ b/routers/api/packages/helm/helm.go
@@ -138,7 +138,7 @@ func DownloadPackageFile(ctx *context.Context) {
 	}
 	defer s.Close()
 
-	ctx.ServeStream(s, pf.Name)
+	ctx.ServeContent(pf.Name, s, pf.CreatedUnix.AsLocalTime())
 }
 
 // UploadPackage creates a new package
diff --git a/routers/api/packages/maven/maven.go b/routers/api/packages/maven/maven.go
index 072a15f95c..bf00c199f5 100644
--- a/routers/api/packages/maven/maven.go
+++ b/routers/api/packages/maven/maven.go
@@ -177,7 +177,7 @@ func servePackageFile(ctx *context.Context, params parameters) {
 		}
 	}
 
-	ctx.ServeStream(s, pf.Name)
+	ctx.ServeContent(pf.Name, s, 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/npm/npm.go b/routers/api/packages/npm/npm.go
index d5ba70f964..66b999d47e 100644
--- a/routers/api/packages/npm/npm.go
+++ b/routers/api/packages/npm/npm.go
@@ -103,7 +103,7 @@ func DownloadPackageFile(ctx *context.Context) {
 	}
 	defer s.Close()
 
-	ctx.ServeStream(s, pf.Name)
+	ctx.ServeContent(pf.Name, s, pf.CreatedUnix.AsLocalTime())
 }
 
 // UploadPackage creates a new package
diff --git a/routers/api/packages/nuget/api.go b/routers/api/packages/nuget/api.go
index b449cfc5bb..964e05f926 100644
--- a/routers/api/packages/nuget/api.go
+++ b/routers/api/packages/nuget/api.go
@@ -176,7 +176,7 @@ func createRegistrationLeafResponse(l *linkBuilder, pd *packages_model.PackageDe
 	return &RegistrationLeafResponse{
 		Type:                 []string{"Package", "http://schema.nuget.org/catalog#Permalink"},
 		Listed:               true,
-		Published:            time.Unix(int64(pd.Version.CreatedUnix), 0),
+		Published:            pd.Version.CreatedUnix.AsLocalTime(),
 		RegistrationLeafURL:  l.GetRegistrationLeafURL(pd.Package.Name, pd.Version.Version),
 		PackageContentURL:    l.GetPackageDownloadURL(pd.Package.Name, pd.Version.Version),
 		RegistrationIndexURL: l.GetRegistrationIndexURL(pd.Package.Name),
diff --git a/routers/api/packages/nuget/nuget.go b/routers/api/packages/nuget/nuget.go
index 81ea28bcad..eadf7486a5 100644
--- a/routers/api/packages/nuget/nuget.go
+++ b/routers/api/packages/nuget/nuget.go
@@ -179,7 +179,7 @@ func DownloadPackageFile(ctx *context.Context) {
 	}
 	defer s.Close()
 
-	ctx.ServeStream(s, pf.Name)
+	ctx.ServeContent(pf.Name, s, pf.CreatedUnix.AsLocalTime())
 }
 
 // UploadPackage creates a new package with the metadata contained in the uploaded nupgk file
@@ -378,7 +378,7 @@ func DownloadSymbolFile(ctx *context.Context) {
 		return
 	}
 
-	s, _, err := packages_service.GetPackageFileStream(ctx, pfs[0])
+	s, pf, err := packages_service.GetPackageFileStream(ctx, pfs[0])
 	if err != nil {
 		if err == packages_model.ErrPackageNotExist || err == packages_model.ErrPackageFileNotExist {
 			apiError(ctx, http.StatusNotFound, err)
@@ -389,7 +389,7 @@ func DownloadSymbolFile(ctx *context.Context) {
 	}
 	defer s.Close()
 
-	ctx.ServeStream(s, pfs[0].Name)
+	ctx.ServeContent(pf.Name, s, 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 470f446238..9af0ceeb0e 100644
--- a/routers/api/packages/pub/pub.go
+++ b/routers/api/packages/pub/pub.go
@@ -69,7 +69,7 @@ func packageDescriptorToMetadata(baseURL string, pd *packages_model.PackageDescr
 	return &versionMetadata{
 		Version:    pd.Version.Version,
 		ArchiveURL: fmt.Sprintf("%s/files/%s.tar.gz", baseURL, url.PathEscape(pd.Version.Version)),
-		Published:  time.Unix(int64(pd.Version.CreatedUnix), 0),
+		Published:  pd.Version.CreatedUnix.AsLocalTime(),
 		Pubspec:    pd.Metadata.(*pub_module.Metadata).Pubspec,
 	}
 }
@@ -271,5 +271,5 @@ func DownloadPackageFile(ctx *context.Context) {
 	}
 	defer s.Close()
 
-	ctx.ServeStream(s, pf.Name)
+	ctx.ServeContent(pf.Name, s, pf.CreatedUnix.AsLocalTime())
 }
diff --git a/routers/api/packages/pypi/pypi.go b/routers/api/packages/pypi/pypi.go
index 9209c4edd5..3909074504 100644
--- a/routers/api/packages/pypi/pypi.go
+++ b/routers/api/packages/pypi/pypi.go
@@ -90,7 +90,7 @@ func DownloadPackageFile(ctx *context.Context) {
 	}
 	defer s.Close()
 
-	ctx.ServeStream(s, pf.Name)
+	ctx.ServeContent(pf.Name, s, 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 4f066a8303..319c94b91f 100644
--- a/routers/api/packages/rubygems/rubygems.go
+++ b/routers/api/packages/rubygems/rubygems.go
@@ -188,7 +188,7 @@ func DownloadPackageFile(ctx *context.Context) {
 	}
 	defer s.Close()
 
-	ctx.ServeStream(s, pf.Name)
+	ctx.ServeContent(pf.Name, s, pf.CreatedUnix.AsLocalTime())
 }
 
 // UploadPackageFile adds a file to the package. If the package does not exist, it gets created.
diff --git a/routers/web/repo/repo.go b/routers/web/repo/repo.go
index fe95d1e478..ae0351a219 100644
--- a/routers/web/repo/repo.go
+++ b/routers/web/repo/repo.go
@@ -468,7 +468,8 @@ func download(ctx *context.Context, archiveName string, archiver *repo_model.Rep
 		return
 	}
 	defer fr.Close()
-	ctx.ServeStream(fr, downloadName)
+
+	ctx.ServeContent(downloadName, fr, 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 59aaf07ff2..20d8e32d29 100644
--- a/routers/web/user/package.go
+++ b/routers/web/user/package.go
@@ -393,5 +393,5 @@ func DownloadPackageFile(ctx *context.Context) {
 	}
 	defer s.Close()
 
-	ctx.ServeStream(s, pf.Name)
+	ctx.ServeContent(pf.Name, s, pf.CreatedUnix.AsLocalTime())
 }
diff --git a/services/packages/packages.go b/services/packages/packages.go
index 4bc31a34e8..96132eac09 100644
--- a/services/packages/packages.go
+++ b/services/packages/packages.go
@@ -402,7 +402,7 @@ func Cleanup(unused context.Context, olderThan time.Duration) error {
 }
 
 // GetFileStreamByPackageNameAndVersion returns the content of the specific package file
-func GetFileStreamByPackageNameAndVersion(ctx context.Context, pvi *PackageInfo, pfi *PackageFileInfo) (io.ReadCloser, *packages_model.PackageFile, error) {
+func GetFileStreamByPackageNameAndVersion(ctx context.Context, pvi *PackageInfo, pfi *PackageFileInfo) (io.ReadSeekCloser, *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)
 
 	pv, err := packages_model.GetVersionByNameAndVersion(ctx, pvi.Owner.ID, pvi.PackageType, pvi.Name, pvi.Version)
@@ -418,7 +418,7 @@ func GetFileStreamByPackageNameAndVersion(ctx context.Context, pvi *PackageInfo,
 }
 
 // GetFileStreamByPackageVersionAndFileID returns the content of the specific package file
-func GetFileStreamByPackageVersionAndFileID(ctx context.Context, owner *user_model.User, versionID, fileID int64) (io.ReadCloser, *packages_model.PackageFile, error) {
+func GetFileStreamByPackageVersionAndFileID(ctx context.Context, owner *user_model.User, versionID, fileID int64) (io.ReadSeekCloser, *packages_model.PackageFile, error) {
 	log.Trace("Getting package file stream: %v, %v, %v", owner.ID, versionID, fileID)
 
 	pv, err := packages_model.GetVersionByID(ctx, versionID)
@@ -449,7 +449,7 @@ func GetFileStreamByPackageVersionAndFileID(ctx context.Context, owner *user_mod
 }
 
 // GetFileStreamByPackageVersion returns the content of the specific package file
-func GetFileStreamByPackageVersion(ctx context.Context, pv *packages_model.PackageVersion, pfi *PackageFileInfo) (io.ReadCloser, *packages_model.PackageFile, error) {
+func GetFileStreamByPackageVersion(ctx context.Context, pv *packages_model.PackageVersion, pfi *PackageFileInfo) (io.ReadSeekCloser, *packages_model.PackageFile, error) {
 	pf, err := packages_model.GetFileForVersionByName(ctx, pv.ID, pfi.Filename, pfi.CompositeKey)
 	if err != nil {
 		return nil, nil, err
@@ -459,7 +459,7 @@ func GetFileStreamByPackageVersion(ctx context.Context, pv *packages_model.Packa
 }
 
 // GetPackageFileStream returns the content of the specific package file
-func GetPackageFileStream(ctx context.Context, pf *packages_model.PackageFile) (io.ReadCloser, *packages_model.PackageFile, error) {
+func GetPackageFileStream(ctx context.Context, pf *packages_model.PackageFile) (io.ReadSeekCloser, *packages_model.PackageFile, error) {
 	pb, err := packages_model.GetBlobByID(ctx, pf.BlobID)
 	if err != nil {
 		return nil, nil, err