goproxy.go 2.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105
  1. /*
  2. * This Source Code Form is subject to the terms of the Mozilla Public
  3. * License, v. 2.0. If a copy of the MPL was not distributed with this
  4. * file, You can obtain one at https://mozilla.org/MPL/2.0/.
  5. */
  6. package main
  7. import (
  8. "net/http"
  9. "path"
  10. "regexp"
  11. "strings"
  12. )
  13. type GoProxyRequestOp int
  14. const (
  15. GoProxyRequestNone GoProxyRequestOp = iota
  16. GoProxyRequestList
  17. GoProxyRequestInfo
  18. GoProxyRequestMod
  19. GoProxyRequestZip
  20. GoProxyRequestLatest
  21. )
  22. type GoProxyRequest struct {
  23. URI,
  24. Module, // The Go module name
  25. ImportPath, // Module without major version
  26. Host, // The part of the module name resolved in DNS
  27. RepoPath, // The URI path of the git repo
  28. Repo, // Git repository name; last component of RepoPath
  29. Version, // "Canonical" version (e.g. v2.1, v1.0.3, etc.)
  30. VersionMajor, // v1, v2, etc.
  31. Extension string // .info, .mod, .zip
  32. Op GoProxyRequestOp
  33. }
  34. var Major = regexp.MustCompile(`^v[0-9]+$`)
  35. var Version = regexp.MustCompile(`^v[0-9]+((\.[0-9]+)(\.[0-9]+)?)?$`)
  36. func parseGoProxyPath(
  37. req *http.Request,
  38. gpr *GoProxyRequest,
  39. ) {
  40. // This should be
  41. // /go/<module>[/{ @v/{ list | $version.{info|mod|zip} } | @latest }]
  42. clean := path.Clean(req.URL.Path)
  43. gpr.URI = path.Join(req.Host, clean)
  44. gpr.Host = req.Host
  45. gpr.Module = req.Host
  46. gpr.ImportPath = req.Host
  47. gpr.RepoPath = req.Host
  48. vector := strings.Split(clean, "/")
  49. i := 0
  50. i++ // empty subpath
  51. if i < len(vector) && vector[i] == "go" {
  52. gpr.Module = path.Join(gpr.Module, vector[i])
  53. i++
  54. }
  55. if i < len(vector) {
  56. gpr.Repo = vector[i]
  57. gpr.Module = path.Join(gpr.Module, gpr.Repo)
  58. gpr.ImportPath = gpr.Module
  59. gpr.RepoPath = path.Join(gpr.RepoPath, gpr.Repo)
  60. i++
  61. }
  62. if i < len(vector) && Major.MatchString(vector[i]) {
  63. gpr.VersionMajor = vector[i]
  64. gpr.Module = path.Join(gpr.Module, gpr.VersionMajor)
  65. i++
  66. }
  67. if i < len(vector) && vector[i] == "@latest" {
  68. gpr.Op = GoProxyRequestLatest
  69. return
  70. }
  71. if i+1 >= len(vector) || vector[i] != "@v" {
  72. return
  73. }
  74. // @v
  75. i++
  76. if vector[i] == "list" {
  77. gpr.Op = GoProxyRequestList
  78. return
  79. }
  80. ext := path.Ext(vector[i])
  81. tmp := strings.TrimSuffix(vector[i], ext)
  82. if !Version.MatchString(tmp) {
  83. return
  84. }
  85. // @version
  86. gpr.Version = tmp
  87. switch ext {
  88. case ".info":
  89. gpr.Op = GoProxyRequestInfo
  90. gpr.Extension = ext
  91. case ".mod":
  92. gpr.Op = GoProxyRequestMod
  93. gpr.Extension = ext
  94. case ".zip":
  95. gpr.Op = GoProxyRequestZip
  96. gpr.Extension = ext
  97. }
  98. }