You can not select more than 25 topics Topics must start with a chinese character,a letter or number, can include dashes ('-') and can be up to 35 characters long.

download.go 4.4 kB

10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168
  1. // Copyright 2014 The Gogs Authors. All rights reserved.
  2. // Copyright 2018 The Gitea Authors. All rights reserved.
  3. // Use of this source code is governed by a MIT-style
  4. // license that can be found in the LICENSE file.
  5. package repo
  6. import (
  7. "fmt"
  8. "io"
  9. "net/url"
  10. "path"
  11. "strings"
  12. "code.gitea.io/gitea/modules/base"
  13. "code.gitea.io/gitea/modules/charset"
  14. "code.gitea.io/gitea/modules/context"
  15. "code.gitea.io/gitea/modules/git"
  16. "code.gitea.io/gitea/modules/lfs"
  17. "code.gitea.io/gitea/modules/log"
  18. )
  19. // ServeData download file from io.Reader
  20. func ServeData(ctx *context.Context, name string, reader io.Reader) error {
  21. buf := make([]byte, 1024)
  22. n, _ := reader.Read(buf)
  23. if n >= 0 {
  24. buf = buf[:n]
  25. }
  26. ctx.Resp.Header().Set("Cache-Control", "public,max-age=86400")
  27. name = path.Base(name)
  28. // Google Chrome dislike commas in filenames, so let's change it to a space
  29. name = strings.Replace(name, ",", " ", -1)
  30. name = url.QueryEscape(name)
  31. if base.IsTextFile(buf) || ctx.QueryBool("render") {
  32. cs, err := charset.DetectEncoding(buf)
  33. if err != nil {
  34. log.Error("Detect raw file %s charset failed: %v, using by default utf-8", name, err)
  35. cs = "utf-8"
  36. }
  37. ctx.Resp.Header().Set("Content-Type", "text/plain; charset="+strings.ToLower(cs))
  38. } else if base.IsImageFile(buf) || base.IsPDFFile(buf) {
  39. ctx.Resp.Header().Set("Content-Disposition", fmt.Sprintf(`inline; filename="%s"`, name))
  40. } else {
  41. ctx.Resp.Header().Set("Content-Disposition", fmt.Sprintf(`attachment; filename="%s"`, name))
  42. }
  43. _, err := ctx.Resp.Write(buf)
  44. if err != nil {
  45. return err
  46. }
  47. _, err = io.Copy(ctx.Resp, reader)
  48. return err
  49. }
  50. // ServeBlob download a git.Blob
  51. func ServeBlob(ctx *context.Context, blob *git.Blob) error {
  52. dataRc, err := blob.DataAsync()
  53. if err != nil {
  54. return err
  55. }
  56. defer func() {
  57. if err = dataRc.Close(); err != nil {
  58. log.Error("ServeBlob: Close: %v", err)
  59. }
  60. }()
  61. return ServeData(ctx, ctx.Repo.TreePath, dataRc)
  62. }
  63. // ServeBlobOrLFS download a git.Blob redirecting to LFS if necessary
  64. func ServeBlobOrLFS(ctx *context.Context, blob *git.Blob) error {
  65. dataRc, err := blob.DataAsync()
  66. if err != nil {
  67. return err
  68. }
  69. defer func() {
  70. if err = dataRc.Close(); err != nil {
  71. log.Error("ServeBlobOrLFS: Close: %v", err)
  72. }
  73. }()
  74. if meta, _ := lfs.ReadPointerFile(dataRc); meta != nil {
  75. meta, _ = ctx.Repo.Repository.GetLFSMetaObjectByOid(meta.Oid)
  76. if meta == nil {
  77. return ServeBlob(ctx, blob)
  78. }
  79. lfsDataRc, err := lfs.ReadMetaObject(meta)
  80. if err != nil {
  81. return err
  82. }
  83. defer func() {
  84. if err = lfsDataRc.Close(); err != nil {
  85. log.Error("ServeBlobOrLFS: Close: %v", err)
  86. }
  87. }()
  88. return ServeData(ctx, ctx.Repo.TreePath, lfsDataRc)
  89. }
  90. return ServeBlob(ctx, blob)
  91. }
  92. // SingleDownload download a file by repos path
  93. func SingleDownload(ctx *context.Context) {
  94. blob, err := ctx.Repo.Commit.GetBlobByPath(ctx.Repo.TreePath)
  95. if err != nil {
  96. if git.IsErrNotExist(err) {
  97. ctx.NotFound("GetBlobByPath", nil)
  98. } else {
  99. ctx.ServerError("GetBlobByPath", err)
  100. }
  101. return
  102. }
  103. if err = ServeBlob(ctx, blob); err != nil {
  104. ctx.ServerError("ServeBlob", err)
  105. }
  106. }
  107. // SingleDownloadOrLFS download a file by repos path redirecting to LFS if necessary
  108. func SingleDownloadOrLFS(ctx *context.Context) {
  109. blob, err := ctx.Repo.Commit.GetBlobByPath(ctx.Repo.TreePath)
  110. if err != nil {
  111. if git.IsErrNotExist(err) {
  112. ctx.NotFound("GetBlobByPath", nil)
  113. } else {
  114. ctx.ServerError("GetBlobByPath", err)
  115. }
  116. return
  117. }
  118. if err = ServeBlobOrLFS(ctx, blob); err != nil {
  119. ctx.ServerError("ServeBlobOrLFS", err)
  120. }
  121. }
  122. // DownloadByID download a file by sha1 ID
  123. func DownloadByID(ctx *context.Context) {
  124. blob, err := ctx.Repo.GitRepo.GetBlob(ctx.Params("sha"))
  125. if err != nil {
  126. if git.IsErrNotExist(err) {
  127. ctx.NotFound("GetBlob", nil)
  128. } else {
  129. ctx.ServerError("GetBlob", err)
  130. }
  131. return
  132. }
  133. if err = ServeBlob(ctx, blob); err != nil {
  134. ctx.ServerError("ServeBlob", err)
  135. }
  136. }
  137. // DownloadByIDOrLFS download a file by sha1 ID taking account of LFS
  138. func DownloadByIDOrLFS(ctx *context.Context) {
  139. blob, err := ctx.Repo.GitRepo.GetBlob(ctx.Params("sha"))
  140. if err != nil {
  141. if git.IsErrNotExist(err) {
  142. ctx.NotFound("GetBlob", nil)
  143. } else {
  144. ctx.ServerError("GetBlob", err)
  145. }
  146. return
  147. }
  148. if err = ServeBlobOrLFS(ctx, blob); err != nil {
  149. ctx.ServerError("ServeBlob", err)
  150. }
  151. }