/* * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ package main import ( "net/http" "path" "regexp" "strings" ) type GoProxyRequestOp int const ( GoProxyRequestNone GoProxyRequestOp = iota GoProxyRequestList GoProxyRequestInfo GoProxyRequestMod GoProxyRequestZip GoProxyRequestLatest ) type GoProxyRequest struct { URI, Module, // The Go module name ImportPath, // Module without major version Host, // The part of the module name resolved in DNS RepoPath, // The URI path of the git repo Repo, // Git repository name; last component of RepoPath Version, // "Canonical" version (e.g. v2.1, v1.0.3, etc.) VersionMajor, // v1, v2, etc. Extension string // .info, .mod, .zip Op GoProxyRequestOp } var Major = regexp.MustCompile(`^v[0-9]+$`) var Version = regexp.MustCompile(`^v[0-9]+((\.[0-9]+)(\.[0-9]+)?)?$`) func parseGoProxyPath( req *http.Request, gpr *GoProxyRequest, ) { // This should be // /go/[/{ @v/{ list | $version.{info|mod|zip} } | @latest }] clean := path.Clean(req.URL.Path) gpr.URI = path.Join(req.Host, clean) gpr.Host = req.Host gpr.Module = req.Host gpr.ImportPath = req.Host gpr.RepoPath = req.Host vector := strings.Split(clean, "/") i := 0 i++ // empty subpath if i < len(vector) && vector[i] == "go" { gpr.Module = path.Join(gpr.Module, vector[i]) i++ } if i < len(vector) { gpr.Repo = vector[i] gpr.Module = path.Join(gpr.Module, gpr.Repo) gpr.ImportPath = gpr.Module gpr.RepoPath = path.Join(gpr.RepoPath, gpr.Repo) i++ } if i < len(vector) && Major.MatchString(vector[i]) { gpr.VersionMajor = vector[i] gpr.Module = path.Join(gpr.Module, gpr.VersionMajor) i++ } if i < len(vector) && vector[i] == "@latest" { gpr.Op = GoProxyRequestLatest return } if i+1 >= len(vector) || vector[i] != "@v" { return } // @v i++ if vector[i] == "list" { gpr.Op = GoProxyRequestList return } ext := path.Ext(vector[i]) tmp := strings.TrimSuffix(vector[i], ext) if !Version.MatchString(tmp) { return } // @version gpr.Version = tmp switch ext { case ".info": gpr.Op = GoProxyRequestInfo gpr.Extension = ext case ".mod": gpr.Op = GoProxyRequestMod gpr.Extension = ext case ".zip": gpr.Op = GoProxyRequestZip gpr.Extension = ext } }