gitea源码

goproxy.go 5.7KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224
  1. // Copyright 2023 The Gitea Authors. All rights reserved.
  2. // SPDX-License-Identifier: MIT
  3. package goproxy
  4. import (
  5. "errors"
  6. "fmt"
  7. "io"
  8. "net/http"
  9. "sort"
  10. "time"
  11. packages_model "code.gitea.io/gitea/models/packages"
  12. "code.gitea.io/gitea/modules/optional"
  13. packages_module "code.gitea.io/gitea/modules/packages"
  14. goproxy_module "code.gitea.io/gitea/modules/packages/goproxy"
  15. "code.gitea.io/gitea/modules/util"
  16. "code.gitea.io/gitea/routers/api/packages/helper"
  17. "code.gitea.io/gitea/services/context"
  18. packages_service "code.gitea.io/gitea/services/packages"
  19. )
  20. func apiError(ctx *context.Context, status int, obj any) {
  21. message := helper.ProcessErrorForUser(ctx, status, obj)
  22. ctx.PlainText(status, message)
  23. }
  24. func EnumeratePackageVersions(ctx *context.Context) {
  25. pvs, err := packages_model.GetVersionsByPackageName(ctx, ctx.Package.Owner.ID, packages_model.TypeGo, ctx.PathParam("name"))
  26. if err != nil {
  27. apiError(ctx, http.StatusInternalServerError, err)
  28. return
  29. }
  30. if len(pvs) == 0 {
  31. apiError(ctx, http.StatusNotFound, err)
  32. return
  33. }
  34. sort.Slice(pvs, func(i, j int) bool {
  35. return pvs[i].CreatedUnix < pvs[j].CreatedUnix
  36. })
  37. ctx.Resp.Header().Set("Content-Type", "text/plain;charset=utf-8")
  38. for _, pv := range pvs {
  39. fmt.Fprintln(ctx.Resp, pv.Version)
  40. }
  41. }
  42. func PackageVersionMetadata(ctx *context.Context) {
  43. pv, err := resolvePackage(ctx, ctx.Package.Owner.ID, ctx.PathParam("name"), ctx.PathParam("version"))
  44. if err != nil {
  45. if errors.Is(err, util.ErrNotExist) {
  46. apiError(ctx, http.StatusNotFound, err)
  47. } else {
  48. apiError(ctx, http.StatusInternalServerError, err)
  49. }
  50. return
  51. }
  52. ctx.JSON(http.StatusOK, struct {
  53. Version string `json:"Version"`
  54. Time time.Time `json:"Time"`
  55. }{
  56. Version: pv.Version,
  57. Time: pv.CreatedUnix.AsLocalTime(),
  58. })
  59. }
  60. func PackageVersionGoModContent(ctx *context.Context) {
  61. pv, err := resolvePackage(ctx, ctx.Package.Owner.ID, ctx.PathParam("name"), ctx.PathParam("version"))
  62. if err != nil {
  63. if errors.Is(err, util.ErrNotExist) {
  64. apiError(ctx, http.StatusNotFound, err)
  65. } else {
  66. apiError(ctx, http.StatusInternalServerError, err)
  67. }
  68. return
  69. }
  70. pps, err := packages_model.GetPropertiesByName(ctx, packages_model.PropertyTypeVersion, pv.ID, goproxy_module.PropertyGoMod)
  71. if err != nil || len(pps) != 1 {
  72. apiError(ctx, http.StatusInternalServerError, err)
  73. return
  74. }
  75. ctx.PlainText(http.StatusOK, pps[0].Value)
  76. }
  77. func DownloadPackageFile(ctx *context.Context) {
  78. pv, err := resolvePackage(ctx, ctx.Package.Owner.ID, ctx.PathParam("name"), ctx.PathParam("version"))
  79. if err != nil {
  80. if errors.Is(err, util.ErrNotExist) {
  81. apiError(ctx, http.StatusNotFound, err)
  82. } else {
  83. apiError(ctx, http.StatusInternalServerError, err)
  84. }
  85. return
  86. }
  87. pfs, err := packages_model.GetFilesByVersionID(ctx, pv.ID)
  88. if err != nil || len(pfs) != 1 {
  89. apiError(ctx, http.StatusInternalServerError, err)
  90. return
  91. }
  92. s, u, _, err := packages_service.OpenFileForDownload(ctx, pfs[0], ctx.Req.Method)
  93. if err != nil {
  94. if errors.Is(err, util.ErrNotExist) {
  95. apiError(ctx, http.StatusNotFound, err)
  96. } else {
  97. apiError(ctx, http.StatusInternalServerError, err)
  98. }
  99. return
  100. }
  101. helper.ServePackageFile(ctx, s, u, pfs[0])
  102. }
  103. func resolvePackage(ctx *context.Context, ownerID int64, name, version string) (*packages_model.PackageVersion, error) {
  104. var pv *packages_model.PackageVersion
  105. if version == "latest" {
  106. pvs, _, err := packages_model.SearchLatestVersions(ctx, &packages_model.PackageSearchOptions{
  107. OwnerID: ownerID,
  108. Type: packages_model.TypeGo,
  109. Name: packages_model.SearchValue{
  110. Value: name,
  111. ExactMatch: true,
  112. },
  113. IsInternal: optional.Some(false),
  114. Sort: packages_model.SortCreatedDesc,
  115. })
  116. if err != nil {
  117. return nil, err
  118. }
  119. if len(pvs) != 1 {
  120. return nil, packages_model.ErrPackageNotExist
  121. }
  122. pv = pvs[0]
  123. } else {
  124. var err error
  125. pv, err = packages_model.GetVersionByNameAndVersion(ctx, ownerID, packages_model.TypeGo, name, version)
  126. if err != nil {
  127. return nil, err
  128. }
  129. }
  130. return pv, nil
  131. }
  132. func UploadPackage(ctx *context.Context) {
  133. upload, needToClose, err := ctx.UploadStream()
  134. if err != nil {
  135. apiError(ctx, http.StatusInternalServerError, err)
  136. return
  137. }
  138. if needToClose {
  139. defer upload.Close()
  140. }
  141. buf, err := packages_module.CreateHashedBufferFromReader(upload)
  142. if err != nil {
  143. apiError(ctx, http.StatusInternalServerError, err)
  144. return
  145. }
  146. defer buf.Close()
  147. pck, err := goproxy_module.ParsePackage(buf, buf.Size())
  148. if err != nil {
  149. if errors.Is(err, util.ErrInvalidArgument) {
  150. apiError(ctx, http.StatusBadRequest, err)
  151. } else {
  152. apiError(ctx, http.StatusInternalServerError, err)
  153. }
  154. return
  155. }
  156. if _, err := buf.Seek(0, io.SeekStart); err != nil {
  157. apiError(ctx, http.StatusInternalServerError, err)
  158. return
  159. }
  160. _, _, err = packages_service.CreatePackageAndAddFile(
  161. ctx,
  162. &packages_service.PackageCreationInfo{
  163. PackageInfo: packages_service.PackageInfo{
  164. Owner: ctx.Package.Owner,
  165. PackageType: packages_model.TypeGo,
  166. Name: pck.Name,
  167. Version: pck.Version,
  168. },
  169. Creator: ctx.Doer,
  170. VersionProperties: map[string]string{
  171. goproxy_module.PropertyGoMod: pck.GoMod,
  172. },
  173. },
  174. &packages_service.PackageFileCreationInfo{
  175. PackageFileInfo: packages_service.PackageFileInfo{
  176. Filename: fmt.Sprintf("%v.zip", pck.Version),
  177. },
  178. Creator: ctx.Doer,
  179. Data: buf,
  180. IsLead: true,
  181. },
  182. )
  183. if err != nil {
  184. switch err {
  185. case packages_model.ErrDuplicatePackageVersion:
  186. apiError(ctx, http.StatusConflict, err)
  187. case packages_service.ErrQuotaTotalCount, packages_service.ErrQuotaTypeSize, packages_service.ErrQuotaTotalSize:
  188. apiError(ctx, http.StatusForbidden, err)
  189. default:
  190. apiError(ctx, http.StatusInternalServerError, err)
  191. }
  192. return
  193. }
  194. ctx.Status(http.StatusCreated)
  195. }