diff options
author | Lunny Xiao <xiaolunwen@gmail.com> | 2021-06-09 07:33:54 +0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-06-09 01:33:54 +0200 |
commit | 1bfb0a24d843e10d6d95c4319a84980485e584ed (patch) | |
tree | e4a736f9abee3eaad1270bf3b60ee3bb9401a9dc /routers/common/repo.go | |
parent | e03a91a48ef7fb716cc7c8bfb411ca8f332dcfe5 (diff) | |
download | gitea-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.go | 127 |
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 +} |