summaryrefslogtreecommitdiffstats
path: root/routers/common/repo.go
diff options
context:
space:
mode:
authorLunny Xiao <xiaolunwen@gmail.com>2021-06-09 07:33:54 +0800
committerGitHub <noreply@github.com>2021-06-09 01:33:54 +0200
commit1bfb0a24d843e10d6d95c4319a84980485e584ed (patch)
treee4a736f9abee3eaad1270bf3b60ee3bb9401a9dc /routers/common/repo.go
parente03a91a48ef7fb716cc7c8bfb411ca8f332dcfe5 (diff)
downloadgitea-1bfb0a24d843e10d6d95c4319a84980485e584ed.tar.gz
gitea-1bfb0a24d843e10d6d95c4319a84980485e584ed.zip
Refactor routers directory (#15800)
* refactor routers directory * move func used for web and api to common * make corsHandler a function to prohibit side efects * rm unused func Co-authored-by: 6543 <6543@obermui.de>
Diffstat (limited to 'routers/common/repo.go')
-rw-r--r--routers/common/repo.go127
1 files changed, 127 insertions, 0 deletions
diff --git a/routers/common/repo.go b/routers/common/repo.go
new file mode 100644
index 0000000000..c61b5ec57f
--- /dev/null
+++ b/routers/common/repo.go
@@ -0,0 +1,127 @@
+// Copyright 2021 The Gitea Authors. All rights reserved.
+// Use of this source code is governed by a MIT-style
+// license that can be found in the LICENSE file.
+
+package common
+
+import (
+ "fmt"
+ "io"
+ "net/http"
+ "path"
+ "path/filepath"
+ "strings"
+
+ "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/services/archiver"
+)
+
+// ServeBlob download a git.Blob
+func ServeBlob(ctx *context.Context, blob *git.Blob) error {
+ if httpcache.HandleGenericETagCache(ctx.Req, ctx.Resp, `"`+blob.ID.String()+`"`) {
+ 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)
+}
+
+// Download an archive of a repository
+func Download(ctx *context.Context) {
+ uri := ctx.Params("*")
+ aReq := archiver.DeriveRequestFrom(ctx, uri)
+
+ if aReq == nil {
+ ctx.Error(http.StatusNotFound)
+ return
+ }
+
+ downloadName := ctx.Repo.Repository.Name + "-" + aReq.GetArchiveName()
+ complete := aReq.IsComplete()
+ if !complete {
+ aReq = archiver.ArchiveRepository(aReq)
+ complete = aReq.WaitForCompletion(ctx)
+ }
+
+ if complete {
+ ctx.ServeFile(aReq.GetArchivePath(), downloadName)
+ } else {
+ ctx.Error(http.StatusNotFound)
+ }
+}
+
+// ServeData download file from io.Reader
+func ServeData(ctx *context.Context, name string, size int64, reader io.Reader) error {
+ buf := make([]byte, 1024)
+ n, err := reader.Read(buf)
+ if err != nil && err != io.EOF {
+ return err
+ }
+ if n >= 0 {
+ buf = buf[:n]
+ }
+
+ ctx.Resp.Header().Set("Cache-Control", "public,max-age=86400")
+
+ 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", name, size)
+ }
+ name = path.Base(name)
+
+ // Google Chrome dislike commas in filenames, so let's change it to a space
+ name = strings.ReplaceAll(name, ",", " ")
+
+ st := typesniffer.DetectContentType(buf)
+
+ if st.IsText() || ctx.QueryBool("render") {
+ cs, err := charset.DetectEncoding(buf)
+ if err != nil {
+ log.Error("Detect raw file %s charset failed: %v, using by default utf-8", name, err)
+ cs = "utf-8"
+ }
+ ctx.Resp.Header().Set("Content-Type", "text/plain; charset="+strings.ToLower(cs))
+ } else {
+ ctx.Resp.Header().Set("Access-Control-Expose-Headers", "Content-Disposition")
+
+ if (st.IsImage() || st.IsPDF()) && (setting.UI.SVG.Enabled || !st.IsSvgImage()) {
+ ctx.Resp.Header().Set("Content-Disposition", fmt.Sprintf(`inline; filename="%s"`, name))
+ if st.IsSvgImage() {
+ ctx.Resp.Header().Set("Content-Security-Policy", "default-src 'none'; style-src 'unsafe-inline'; sandbox")
+ ctx.Resp.Header().Set("X-Content-Type-Options", "nosniff")
+ ctx.Resp.Header().Set("Content-Type", typesniffer.SvgMimeType)
+ }
+ } else {
+ ctx.Resp.Header().Set("Content-Disposition", fmt.Sprintf(`attachment; filename="%s"`, name))
+ if setting.MimeTypeMap.Enabled {
+ fileExtension := strings.ToLower(filepath.Ext(name))
+ if mimetype, ok := setting.MimeTypeMap.Map[fileExtension]; ok {
+ ctx.Resp.Header().Set("Content-Type", mimetype)
+ }
+ }
+ }
+ }
+
+ _, err = ctx.Resp.Write(buf)
+ if err != nil {
+ return err
+ }
+ _, err = io.Copy(ctx.Resp, reader)
+ return err
+}