basic.go 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137
  1. // Copyright 2020 The Gogs Authors. All rights reserved.
  2. // Use of this source code is governed by a MIT-style
  3. // license that can be found in the LICENSE file.
  4. package lfs
  5. import (
  6. "encoding/json"
  7. "io"
  8. "io/ioutil"
  9. "net/http"
  10. "os"
  11. "strconv"
  12. "gopkg.in/macaron.v1"
  13. log "unknwon.dev/clog/v2"
  14. "gogs.io/gogs/internal/conf"
  15. "gogs.io/gogs/internal/db"
  16. "gogs.io/gogs/internal/lfsutil"
  17. "gogs.io/gogs/internal/strutil"
  18. )
  19. const transferBasic = "basic"
  20. const (
  21. basicOperationUpload = "upload"
  22. basicOperationDownload = "download"
  23. )
  24. // GET /{owner}/{repo}.git/info/lfs/object/basic/{oid}
  25. func serveBasicDownload(c *macaron.Context, repo *db.Repository, oid lfsutil.OID) {
  26. object, err := db.LFS.GetObjectByOID(repo.ID, oid)
  27. if err != nil {
  28. if db.IsErrLFSObjectNotExist(err) {
  29. responseJSON(c.Resp, http.StatusNotFound, responseError{
  30. Message: "Object does not exist",
  31. })
  32. } else {
  33. internalServerError(c.Resp)
  34. log.Error("Failed to get object [repo_id: %d, oid: %s]: %v", repo.ID, oid, err)
  35. }
  36. return
  37. }
  38. fpath := lfsutil.StorageLocalPath(conf.LFS.ObjectsPath, object.OID)
  39. r, err := os.Open(fpath)
  40. if err != nil {
  41. internalServerError(c.Resp)
  42. log.Error("Failed to open object file [path: %s]: %v", fpath, err)
  43. return
  44. }
  45. defer r.Close()
  46. c.Header().Set("Content-Type", "application/octet-stream")
  47. c.Header().Set("Content-Length", strconv.FormatInt(object.Size, 10))
  48. c.Status(http.StatusOK)
  49. _, err = io.Copy(c.Resp, r)
  50. if err != nil {
  51. log.Error("Failed to copy object file: %v", err)
  52. return
  53. }
  54. }
  55. // PUT /{owner}/{repo}.git/info/lfs/object/basic/{oid}
  56. func serveBasicUpload(c *macaron.Context, repo *db.Repository, oid lfsutil.OID) {
  57. // NOTE: LFS client will retry upload the same object if there was a partial failure,
  58. // therefore we would like to skip ones that already exist.
  59. _, err := db.LFS.GetObjectByOID(repo.ID, oid)
  60. if err == nil {
  61. // Object exists, drain the request body and we're good.
  62. _, _ = io.Copy(ioutil.Discard, c.Req.Request.Body)
  63. c.Req.Request.Body.Close()
  64. c.Status(http.StatusOK)
  65. return
  66. } else if !db.IsErrLFSObjectNotExist(err) {
  67. internalServerError(c.Resp)
  68. log.Error("Failed to get object [repo_id: %d, oid: %s]: %v", repo.ID, oid, err)
  69. return
  70. }
  71. err = db.LFS.CreateObject(repo.ID, oid, c.Req.Request.Body, lfsutil.StorageLocal)
  72. if err != nil {
  73. internalServerError(c.Resp)
  74. log.Error("Failed to create object [repo_id: %d, oid: %s]: %v", repo.ID, oid, err)
  75. return
  76. }
  77. c.Status(http.StatusOK)
  78. log.Trace("[LFS] Object created %q", oid)
  79. }
  80. // POST /{owner}/{repo}.git/info/lfs/object/basic/verify
  81. func serveBasicVerify(c *macaron.Context, repo *db.Repository) {
  82. var request basicVerifyRequest
  83. defer c.Req.Request.Body.Close()
  84. err := json.NewDecoder(c.Req.Request.Body).Decode(&request)
  85. if err != nil {
  86. responseJSON(c.Resp, http.StatusBadRequest, responseError{
  87. Message: strutil.ToUpperFirst(err.Error()),
  88. })
  89. return
  90. }
  91. if !lfsutil.ValidOID(request.Oid) {
  92. responseJSON(c.Resp, http.StatusBadRequest, responseError{
  93. Message: "Invalid oid",
  94. })
  95. return
  96. }
  97. object, err := db.LFS.GetObjectByOID(repo.ID, lfsutil.OID(request.Oid))
  98. if err != nil {
  99. if db.IsErrLFSObjectNotExist(err) {
  100. responseJSON(c.Resp, http.StatusNotFound, responseError{
  101. Message: "Object does not exist",
  102. })
  103. } else {
  104. internalServerError(c.Resp)
  105. log.Error("Failed to get object [repo_id: %d, oid: %s]: %v", repo.ID, request.Oid, err)
  106. }
  107. return
  108. }
  109. if object.Size != request.Size {
  110. responseJSON(c.Resp, http.StatusNotFound, responseError{
  111. Message: "Object size mismatch",
  112. })
  113. return
  114. }
  115. c.Status(http.StatusOK)
  116. }
  117. type basicVerifyRequest struct {
  118. Oid lfsutil.OID `json:"oid"`
  119. Size int64 `json:"size"`
  120. }