aboutsummaryrefslogtreecommitdiffstats
path: root/routers
diff options
context:
space:
mode:
authorwxiaoguang <wxiaoguang@gmail.com>2023-05-09 15:34:36 +0800
committerGitHub <noreply@github.com>2023-05-09 15:34:36 +0800
commit023a048f52b5bf8c4b715285245a129f04e05a8c (patch)
tree2ea5c0d940a9439e9760b00f735d869444d87165 /routers
parentc090f87a8db5b51e0aa9c7278b38ddc862c048ac (diff)
downloadgitea-023a048f52b5bf8c4b715285245a129f04e05a8c.tar.gz
gitea-023a048f52b5bf8c4b715285245a129f04e05a8c.zip
Make repository response support HTTP range request (#24592)
Replace #20480 Replace #18448 Close #16414
Diffstat (limited to 'routers')
-rw-r--r--routers/api/v1/repo/file.go19
-rw-r--r--routers/common/repo.go116
-rw-r--r--routers/common/serve.go43
-rw-r--r--routers/web/repo/attachment.go5
-rw-r--r--routers/web/repo/download.go3
5 files changed, 53 insertions, 133 deletions
diff --git a/routers/api/v1/repo/file.go b/routers/api/v1/repo/file.go
index 5f7ed255bc..eb63dda590 100644
--- a/routers/api/v1/repo/file.go
+++ b/routers/api/v1/repo/file.go
@@ -150,6 +150,7 @@ func GetRawFileOrLFS(ctx *context.APIContext) {
return
}
+ // FIXME: code from #19689, what if the file is large ... OOM ...
buf, err := io.ReadAll(dataRc)
if err != nil {
_ = dataRc.Close()
@@ -164,7 +165,7 @@ func GetRawFileOrLFS(ctx *context.APIContext) {
// Check if the blob represents a pointer
pointer, _ := lfs.ReadPointer(bytes.NewReader(buf))
- // if its not a pointer just serve the data directly
+ // if it's not a pointer, just serve the data directly
if !pointer.IsValid() {
// First handle caching for the blob
if httpcache.HandleGenericETagTimeCache(ctx.Req, ctx.Resp, `"`+blob.ID.String()+`"`, lastModified) {
@@ -172,25 +173,21 @@ func GetRawFileOrLFS(ctx *context.APIContext) {
}
// OK not cached - serve!
- if err := common.ServeData(ctx.Context, ctx.Repo.TreePath, blob.Size(), bytes.NewReader(buf)); err != nil {
- ctx.ServerError("ServeBlob", err)
- }
+ common.ServeContentByReader(ctx.Context, ctx.Repo.TreePath, blob.Size(), bytes.NewReader(buf))
return
}
- // Now check if there is a meta object for this pointer
+ // Now check if there is a MetaObject for this pointer
meta, err := git_model.GetLFSMetaObjectByOid(ctx, ctx.Repo.Repository.ID, pointer.Oid)
- // If there isn't one just serve the data directly
+ // If there isn't one, just serve the data directly
if err == git_model.ErrLFSObjectNotExist {
// Handle caching for the blob SHA (not the LFS object OID)
if httpcache.HandleGenericETagTimeCache(ctx.Req, ctx.Resp, `"`+blob.ID.String()+`"`, lastModified) {
return
}
- if err := common.ServeData(ctx.Context, ctx.Repo.TreePath, blob.Size(), bytes.NewReader(buf)); err != nil {
- ctx.ServerError("ServeBlob", err)
- }
+ common.ServeContentByReader(ctx.Context, ctx.Repo.TreePath, blob.Size(), bytes.NewReader(buf))
return
} else if err != nil {
ctx.ServerError("GetLFSMetaObjectByOid", err)
@@ -218,9 +215,7 @@ func GetRawFileOrLFS(ctx *context.APIContext) {
}
defer lfsDataRc.Close()
- if err := common.ServeData(ctx.Context, ctx.Repo.TreePath, meta.Size, lfsDataRc); err != nil {
- ctx.ServerError("ServeData", err)
- }
+ common.ServeContentByReadSeeker(ctx.Context, ctx.Repo.TreePath, lastModified, lfsDataRc)
}
func getBlobForEntry(ctx *context.APIContext) (blob *git.Blob, entry *git.TreeEntry, lastModified time.Time) {
diff --git a/routers/common/repo.go b/routers/common/repo.go
deleted file mode 100644
index 4b04ddae34..0000000000
--- a/routers/common/repo.go
+++ /dev/null
@@ -1,116 +0,0 @@
-// Copyright 2021 The Gitea Authors. All rights reserved.
-// SPDX-License-Identifier: MIT
-
-package common
-
-import (
- "io"
- "path"
- "path/filepath"
- "strings"
- "time"
-
- charsetModule "code.gitea.io/gitea/modules/charset"
- "code.gitea.io/gitea/modules/context"
- "code.gitea.io/gitea/modules/git"
- "code.gitea.io/gitea/modules/httpcache"
- "code.gitea.io/gitea/modules/log"
- "code.gitea.io/gitea/modules/setting"
- "code.gitea.io/gitea/modules/typesniffer"
- "code.gitea.io/gitea/modules/util"
-)
-
-// ServeBlob download a git.Blob
-func ServeBlob(ctx *context.Context, blob *git.Blob, lastModified time.Time) error {
- if httpcache.HandleGenericETagTimeCache(ctx.Req, ctx.Resp, `"`+blob.ID.String()+`"`, lastModified) {
- return nil
- }
-
- dataRc, err := blob.DataAsync()
- if err != nil {
- return err
- }
- defer func() {
- if err = dataRc.Close(); err != nil {
- log.Error("ServeBlob: Close: %v", err)
- }
- }()
-
- return ServeData(ctx, ctx.Repo.TreePath, blob.Size(), dataRc)
-}
-
-// ServeData download file from io.Reader
-func ServeData(ctx *context.Context, filePath string, size int64, reader io.Reader) error {
- buf := make([]byte, 1024)
- n, err := util.ReadAtMost(reader, buf)
- if err != nil {
- return err
- }
- if n >= 0 {
- buf = buf[:n]
- }
-
- opts := &context.ServeHeaderOptions{
- 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)
- isPlain := sniffedType.IsText() || ctx.FormBool("render")
-
- if setting.MimeTypeMap.Enabled {
- fileExtension := strings.ToLower(filepath.Ext(filePath))
- opts.ContentType = setting.MimeTypeMap.Map[fileExtension]
- }
-
- if opts.ContentType == "" {
- if sniffedType.IsBrowsableBinaryType() {
- opts.ContentType = sniffedType.GetMimeType()
- } else if isPlain {
- opts.ContentType = "text/plain"
- } else {
- opts.ContentType = typesniffer.ApplicationOctetStream
- }
- }
-
- if isPlain {
- var charset string
- charset, err = charsetModule.DetectEncoding(buf)
- if err != nil {
- log.Error("Detect raw file %s charset failed: %v, using by default utf-8", filePath, err)
- charset = "utf-8"
- }
- opts.ContentTypeCharset = strings.ToLower(charset)
- }
-
- isSVG := sniffedType.IsSvgImage()
-
- // serve types that can present a security risk with CSP
- if isSVG {
- ctx.Resp.Header().Set("Content-Security-Policy", "default-src 'none'; style-src 'unsafe-inline'; sandbox")
- } else if sniffedType.IsPDF() {
- // no sandbox attribute for pdf as it breaks rendering in at least safari. this
- // should generally be safe as scripts inside PDF can not escape the PDF document
- // see https://bugs.chromium.org/p/chromium/issues/detail?id=413851 for more discussion
- ctx.Resp.Header().Set("Content-Security-Policy", "default-src 'none'; style-src 'unsafe-inline'")
- }
-
- opts.Disposition = "inline"
- if isSVG && !setting.UI.SVG.Enabled {
- opts.Disposition = "attachment"
- }
-
- ctx.SetServeHeaders(opts)
-
- _, err = ctx.Resp.Write(buf)
- if err != nil {
- return err
- }
- _, err = io.Copy(ctx.Resp, reader)
- return err
-}
diff --git a/routers/common/serve.go b/routers/common/serve.go
new file mode 100644
index 0000000000..59b993328e
--- /dev/null
+++ b/routers/common/serve.go
@@ -0,0 +1,43 @@
+// Copyright 2021 The Gitea Authors. All rights reserved.
+// SPDX-License-Identifier: MIT
+
+package common
+
+import (
+ "io"
+ "time"
+
+ "code.gitea.io/gitea/modules/context"
+ "code.gitea.io/gitea/modules/git"
+ "code.gitea.io/gitea/modules/httpcache"
+ "code.gitea.io/gitea/modules/httplib"
+ "code.gitea.io/gitea/modules/log"
+)
+
+// ServeBlob download a git.Blob
+func ServeBlob(ctx *context.Context, blob *git.Blob, lastModified time.Time) error {
+ if httpcache.HandleGenericETagTimeCache(ctx.Req, ctx.Resp, `"`+blob.ID.String()+`"`, lastModified) {
+ return nil
+ }
+
+ dataRc, err := blob.DataAsync()
+ if err != nil {
+ return err
+ }
+ defer func() {
+ if err = dataRc.Close(); err != nil {
+ log.Error("ServeBlob: Close: %v", err)
+ }
+ }()
+
+ httplib.ServeContentByReader(ctx.Req, ctx.Resp, ctx.Repo.TreePath, blob.Size(), dataRc)
+ return nil
+}
+
+func ServeContentByReader(ctx *context.Context, filePath string, size int64, reader io.Reader) {
+ httplib.ServeContentByReader(ctx.Req, ctx.Resp, filePath, size, reader)
+}
+
+func ServeContentByReadSeeker(ctx *context.Context, filePath string, modTime time.Time, reader io.ReadSeeker) {
+ httplib.ServeContentByReadSeeker(ctx.Req, ctx.Resp, filePath, modTime, reader)
+}
diff --git a/routers/web/repo/attachment.go b/routers/web/repo/attachment.go
index c6ea4e3cdb..c46ec29841 100644
--- a/routers/web/repo/attachment.go
+++ b/routers/web/repo/attachment.go
@@ -153,10 +153,7 @@ func ServeAttachment(ctx *context.Context, uuid string) {
}
defer fr.Close()
- if err = common.ServeData(ctx, attach.Name, attach.Size, fr); err != nil {
- ctx.ServerError("ServeData", err)
- return
- }
+ common.ServeContentByReadSeeker(ctx, attach.Name, attach.CreatedUnix.AsTime(), fr)
}
// GetAttachment serve attachments
diff --git a/routers/web/repo/download.go b/routers/web/repo/download.go
index 9e95f9dd0c..1c87f9bed7 100644
--- a/routers/web/repo/download.go
+++ b/routers/web/repo/download.go
@@ -71,7 +71,8 @@ func ServeBlobOrLFS(ctx *context.Context, blob *git.Blob, lastModified time.Time
log.Error("ServeBlobOrLFS: Close: %v", err)
}
}()
- return common.ServeData(ctx, ctx.Repo.TreePath, meta.Size, lfsDataRc)
+ common.ServeContentByReadSeeker(ctx, ctx.Repo.TreePath, lastModified, lfsDataRc)
+ return nil
}
if err = dataRc.Close(); err != nil {
log.Error("ServeBlobOrLFS: Close: %v", err)