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
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169
  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. ctx.Resp.Header().Set("Cache-Control", "max-age=0")
  28. name = path.Base(name)
  29. // Google Chrome dislike commas in filenames, so let's change it to a space
  30. name = strings.Replace(name, ",", " ", -1)
  31. name = url.QueryEscape(name)
  32. if base.IsTextFile(buf) || ctx.QueryBool("render") {
  33. cs, err := charset.DetectEncoding(buf)
  34. if err != nil {
  35. log.Error("Detect raw file %s charset failed: %v, using by default utf-8", name, err)
  36. cs = "utf-8"
  37. }
  38. ctx.Resp.Header().Set("Content-Type", "text/plain; charset="+strings.ToLower(cs))
  39. } else if base.IsImageFile(buf) || base.IsPDFFile(buf) {
  40. ctx.Resp.Header().Set("Content-Disposition", fmt.Sprintf(`inline; filename="%s"`, name))
  41. } else {
  42. ctx.Resp.Header().Set("Content-Disposition", fmt.Sprintf(`attachment; filename="%s"`, name))
  43. }
  44. _, err := ctx.Resp.Write(buf)
  45. if err != nil {
  46. return err
  47. }
  48. _, err = io.Copy(ctx.Resp, reader)
  49. return err
  50. }
  51. // ServeBlob download a git.Blob
  52. func ServeBlob(ctx *context.Context, blob *git.Blob) error {
  53. dataRc, err := blob.DataAsync()
  54. if err != nil {
  55. return err
  56. }
  57. defer func() {
  58. if err = dataRc.Close(); err != nil {
  59. log.Error("ServeBlob: Close: %v", err)
  60. }
  61. }()
  62. return ServeData(ctx, ctx.Repo.TreePath, dataRc)
  63. }
  64. // ServeBlobOrLFS download a git.Blob redirecting to LFS if necessary
  65. func ServeBlobOrLFS(ctx *context.Context, blob *git.Blob) error {
  66. dataRc, err := blob.DataAsync()
  67. if err != nil {
  68. return err
  69. }
  70. defer func() {
  71. if err = dataRc.Close(); err != nil {
  72. log.Error("ServeBlobOrLFS: Close: %v", err)
  73. }
  74. }()
  75. if meta, _ := lfs.ReadPointerFile(dataRc); meta != nil {
  76. meta, _ = ctx.Repo.Repository.GetLFSMetaObjectByOid(meta.Oid)
  77. if meta == nil {
  78. return ServeBlob(ctx, blob)
  79. }
  80. lfsDataRc, err := lfs.ReadMetaObject(meta)
  81. if err != nil {
  82. return err
  83. }
  84. defer func() {
  85. if err = lfsDataRc.Close(); err != nil {
  86. log.Error("ServeBlobOrLFS: Close: %v", err)
  87. }
  88. }()
  89. return ServeData(ctx, ctx.Repo.TreePath, lfsDataRc)
  90. }
  91. return ServeBlob(ctx, blob)
  92. }
  93. // SingleDownload download a file by repos path
  94. func SingleDownload(ctx *context.Context) {
  95. blob, err := ctx.Repo.Commit.GetBlobByPath(ctx.Repo.TreePath)
  96. if err != nil {
  97. if git.IsErrNotExist(err) {
  98. ctx.NotFound("GetBlobByPath", nil)
  99. } else {
  100. ctx.ServerError("GetBlobByPath", err)
  101. }
  102. return
  103. }
  104. if err = ServeBlob(ctx, blob); err != nil {
  105. ctx.ServerError("ServeBlob", err)
  106. }
  107. }
  108. // SingleDownloadOrLFS download a file by repos path redirecting to LFS if necessary
  109. func SingleDownloadOrLFS(ctx *context.Context) {
  110. blob, err := ctx.Repo.Commit.GetBlobByPath(ctx.Repo.TreePath)
  111. if err != nil {
  112. if git.IsErrNotExist(err) {
  113. ctx.NotFound("GetBlobByPath", nil)
  114. } else {
  115. ctx.ServerError("GetBlobByPath", err)
  116. }
  117. return
  118. }
  119. if err = ServeBlobOrLFS(ctx, blob); err != nil {
  120. ctx.ServerError("ServeBlobOrLFS", err)
  121. }
  122. }
  123. // DownloadByID download a file by sha1 ID
  124. func DownloadByID(ctx *context.Context) {
  125. blob, err := ctx.Repo.GitRepo.GetBlob(ctx.Params("sha"))
  126. if err != nil {
  127. if git.IsErrNotExist(err) {
  128. ctx.NotFound("GetBlob", nil)
  129. } else {
  130. ctx.ServerError("GetBlob", err)
  131. }
  132. return
  133. }
  134. if err = ServeBlob(ctx, blob); err != nil {
  135. ctx.ServerError("ServeBlob", err)
  136. }
  137. }
  138. // DownloadByIDOrLFS download a file by sha1 ID taking account of LFS
  139. func DownloadByIDOrLFS(ctx *context.Context) {
  140. blob, err := ctx.Repo.GitRepo.GetBlob(ctx.Params("sha"))
  141. if err != nil {
  142. if git.IsErrNotExist(err) {
  143. ctx.NotFound("GetBlob", nil)
  144. } else {
  145. ctx.ServerError("GetBlob", err)
  146. }
  147. return
  148. }
  149. if err = ServeBlobOrLFS(ctx, blob); err != nil {
  150. ctx.ServerError("ServeBlob", err)
  151. }
  152. }