mirror of https://github.com/goproxyio/goproxy
parent
dca1b629da
commit
ffdf9f23eb
|
@ -1,7 +1,6 @@
|
||||||
package proxy
|
package proxy
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
@ -13,6 +12,7 @@ import (
|
||||||
"github.com/goproxyio/goproxy/internal/cfg"
|
"github.com/goproxyio/goproxy/internal/cfg"
|
||||||
"github.com/goproxyio/goproxy/internal/modfetch"
|
"github.com/goproxyio/goproxy/internal/modfetch"
|
||||||
"github.com/goproxyio/goproxy/internal/modfetch/codehost"
|
"github.com/goproxyio/goproxy/internal/modfetch/codehost"
|
||||||
|
"github.com/goproxyio/goproxy/internal/modload"
|
||||||
"github.com/goproxyio/goproxy/internal/module"
|
"github.com/goproxyio/goproxy/internal/module"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -39,20 +39,61 @@ func NewProxy(cache string) http.Handler {
|
||||||
|
|
||||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
log.Printf("goproxy: %s request %s\n", r.RemoteAddr, r.URL.Path)
|
log.Printf("goproxy: %s request %s\n", r.RemoteAddr, r.URL.Path)
|
||||||
if _, err := os.Stat(filepath.Join(cacheDir, r.URL.Path)); err != nil {
|
|
||||||
info, err := parseModInfoFromUrl(r.URL.Path)
|
info, err := parseModInfoFromUrl(r.URL.Path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ReturnBadRequest(w, err)
|
ReturnBadRequest(w, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
switch suf := info.suf; suf {
|
switch suf := info.suf; suf {
|
||||||
case "":
|
case ".info", ".mod", ".zip":
|
||||||
// ignore the error, incorrect tag may be given
|
{
|
||||||
// forward to inner.ServeHTTP
|
if _, err := os.Stat(filepath.Join(cacheDir, r.URL.Path)); err == nil {
|
||||||
if err := downloadMod(info.Path, info.Version.Version); err != nil {
|
// cache files exist on disk
|
||||||
errLogger.Printf("goproxy: download %s@%s get err %s", info.Path, info.Version.Version, err)
|
innerHandle.ServeHTTP(w, r)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
realMod, err := getQuery(info.Version.Path, info.Version.Version)
|
||||||
|
if err != nil {
|
||||||
|
errLogger.Printf("goproxy: lookup %s@%s get err %s", info.Path, info.Version.Version, err)
|
||||||
|
ReturnBadRequest(w, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
switch suf {
|
||||||
|
case ".info":
|
||||||
|
{
|
||||||
|
if revInfo, err := modfetch.Stat(realMod.Path, realMod.Version); err != nil {
|
||||||
|
// use Stat instead of InfoFile, because when query-version is master, no infoFile here, maybe bug of go
|
||||||
|
// TODO(hxzhao527): check whether InfoFile have a bug?
|
||||||
|
errLogger.Printf("goproxy: fetch info %s@%s get err %s", info.Path, info.Version.Version, err)
|
||||||
|
ReturnBadRequest(w, err)
|
||||||
|
} else {
|
||||||
|
ReturnJsonData(w, revInfo)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case ".mod":
|
||||||
|
{
|
||||||
|
if modFile, err := modfetch.GoModFile(realMod.Path, realMod.Version); err != nil {
|
||||||
|
errLogger.Printf("goproxy: fetch modfile %s@%s get err %s", info.Path, info.Version.Version, err)
|
||||||
|
ReturnBadRequest(w, err)
|
||||||
|
} else {
|
||||||
|
http.ServeFile(w, r, modFile)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case ".zip":
|
||||||
|
{
|
||||||
|
mod := module.Version{Path: realMod.Path, Version: realMod.Version}
|
||||||
|
if zipFile, err := modfetch.DownloadZip(mod); err != nil {
|
||||||
|
errLogger.Printf("goproxy: download zip %s@%s get err %s", info.Path, info.Version.Version, err)
|
||||||
|
ReturnBadRequest(w, err)
|
||||||
|
} else {
|
||||||
|
http.ServeFile(w, r, zipFile)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
}
|
}
|
||||||
case "/@v/list", "/@latest":
|
case "/@v/list", "/@latest":
|
||||||
|
{
|
||||||
repo, err := modfetch.Lookup(info.Path)
|
repo, err := modfetch.Lookup(info.Path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errLogger.Printf("goproxy: lookup failed: %v", err)
|
errLogger.Printf("goproxy: lookup failed: %v", err)
|
||||||
|
@ -61,31 +102,23 @@ func NewProxy(cache string) http.Handler {
|
||||||
}
|
}
|
||||||
switch suf {
|
switch suf {
|
||||||
case "/@v/list":
|
case "/@v/list":
|
||||||
info, err := repo.Versions("")
|
if info, err := repo.Versions(""); err != nil {
|
||||||
if err != nil {
|
|
||||||
ReturnInternalServerError(w, err)
|
ReturnInternalServerError(w, err)
|
||||||
return
|
} else {
|
||||||
}
|
|
||||||
data := strings.Join(info, "\n")
|
data := strings.Join(info, "\n")
|
||||||
ReturnSuccess(w, []byte(data))
|
ReturnSuccess(w, []byte(data))
|
||||||
return
|
}
|
||||||
case "/@latest":
|
case "/@latest":
|
||||||
info, err := repo.Latest()
|
modLatestInfo, err := repo.Latest()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ReturnInternalServerError(w, err)
|
ReturnInternalServerError(w, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
data, err := json.Marshal(info)
|
ReturnJsonData(w, modLatestInfo)
|
||||||
if err != nil {
|
|
||||||
// ignore
|
|
||||||
errLogger.Printf("goproxy: marshal mod version info get error: %s", err)
|
|
||||||
}
|
}
|
||||||
ReturnSuccess(w, data)
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
innerHandle.ServeHTTP(w, r)
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -108,13 +141,13 @@ func parseModInfoFromUrl(url string) (*modInfo, error) {
|
||||||
// /golang.org/x/net/@v/v0.0.0-20181220203305-927f97764cc3.info
|
// /golang.org/x/net/@v/v0.0.0-20181220203305-927f97764cc3.info
|
||||||
// /golang.org/x/net/@v/v0.0.0-20181220203305-927f97764cc3.mod
|
// /golang.org/x/net/@v/v0.0.0-20181220203305-927f97764cc3.mod
|
||||||
// /golang.org/x/net/@v/v0.0.0-20181220203305-927f97764cc3.zip
|
// /golang.org/x/net/@v/v0.0.0-20181220203305-927f97764cc3.zip
|
||||||
ext := path.Ext(url)
|
suf = path.Ext(url)
|
||||||
tmp := strings.Split(url, "/@v/")
|
tmp := strings.Split(url, "/@v/")
|
||||||
if len(tmp) != 2 {
|
if len(tmp) != 2 {
|
||||||
return nil, fmt.Errorf("bad module path:%s", url)
|
return nil, fmt.Errorf("bad module path:%s", url)
|
||||||
}
|
}
|
||||||
modPath = strings.Trim(tmp[0], "/")
|
modPath = strings.Trim(tmp[0], "/")
|
||||||
modVersion = strings.TrimSuffix(tmp[1], ext)
|
modVersion = strings.TrimSuffix(tmp[1], suf)
|
||||||
|
|
||||||
modVersion, err = module.DecodeVersion(modVersion)
|
modVersion, err = module.DecodeVersion(modVersion)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -132,24 +165,20 @@ func parseModInfoFromUrl(url string) (*modInfo, error) {
|
||||||
return &modInfo{module.Version{Path: modPath, Version: modVersion}, suf}, nil
|
return &modInfo{module.Version{Path: modPath, Version: modVersion}, suf}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func downloadMod(modPath, version string) error {
|
// getQuery evaluates the given package path, version pair
|
||||||
if _, err := modfetch.InfoFile(modPath, version); err != nil {
|
// to determine the underlying module version being requested.
|
||||||
return err
|
// If forceModulePath is set, getQuery must interpret path
|
||||||
|
// as a module path.
|
||||||
|
func getQuery(path, vers string) (module.Version, error) {
|
||||||
|
|
||||||
|
// First choice is always to assume path is a module path.
|
||||||
|
// If that works out, we're done.
|
||||||
|
info, err := modload.Query(path, vers, modload.Allowed)
|
||||||
|
if err == nil {
|
||||||
|
return module.Version{Path: path, Version: info.Version}, nil
|
||||||
}
|
}
|
||||||
if _, err := modfetch.GoModFile(modPath, version); err != nil {
|
|
||||||
return err
|
// Otherwise, try a package path.
|
||||||
}
|
m, _, err := modload.QueryPackage(path, vers, modload.Allowed)
|
||||||
if _, err := modfetch.GoModSum(modPath, version); err != nil {
|
return m, err
|
||||||
return err
|
|
||||||
}
|
|
||||||
mod := module.Version{Path: modPath, Version: version}
|
|
||||||
if _, err := modfetch.DownloadZip(mod); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if a, err := modfetch.Download(mod); err != nil {
|
|
||||||
return err
|
|
||||||
} else {
|
|
||||||
log.Printf("goproxy: download %s@%s to dir %s\n", modPath, version, a)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,20 +29,21 @@ func TestMain(m *testing.M) {
|
||||||
}
|
}
|
||||||
defer os.RemoveAll(tmpdir)
|
defer os.RemoveAll(tmpdir)
|
||||||
_handle = NewProxy(tmpdir)
|
_handle = NewProxy(tmpdir)
|
||||||
os.Exit(m.Run())
|
m.Run()
|
||||||
}
|
}
|
||||||
|
|
||||||
var _modInfoTests = []struct {
|
var _modInfoTests = []struct {
|
||||||
path string
|
path string
|
||||||
version string
|
query string // query
|
||||||
|
version string // want
|
||||||
latest bool
|
latest bool
|
||||||
time time.Time
|
time time.Time
|
||||||
gomod string
|
gomod string
|
||||||
zip []string
|
zip []string
|
||||||
versions []string
|
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
path: "gopkg.in/check.v1",
|
path: "gopkg.in/check.v1",
|
||||||
|
query: "v0.0.0-20161208181325-20d25e280405",
|
||||||
version: "v0.0.0-20161208181325-20d25e280405",
|
version: "v0.0.0-20161208181325-20d25e280405",
|
||||||
time: time.Date(2016, 12, 8, 18, 13, 25, 0, time.UTC),
|
time: time.Date(2016, 12, 8, 18, 13, 25, 0, time.UTC),
|
||||||
gomod: "module gopkg.in/check.v1\n",
|
gomod: "module gopkg.in/check.v1\n",
|
||||||
|
@ -74,6 +75,7 @@ var _modInfoTests = []struct {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: "github.com/PuerkitoBio/goquery",
|
path: "github.com/PuerkitoBio/goquery",
|
||||||
|
query: "v0.0.0-20181014175806-2af3d16e2bb8",
|
||||||
version: "v0.0.0-20181014175806-2af3d16e2bb8",
|
version: "v0.0.0-20181014175806-2af3d16e2bb8",
|
||||||
time: time.Date(2018, 10, 14, 17, 58, 6, 0, time.UTC),
|
time: time.Date(2018, 10, 14, 17, 58, 6, 0, time.UTC),
|
||||||
gomod: "module github.com/PuerkitoBio/goquery\n",
|
gomod: "module github.com/PuerkitoBio/goquery\n",
|
||||||
|
@ -139,10 +141,21 @@ var _modInfoTests = []struct {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: "github.com/rsc/vgotest1",
|
path: "github.com/rsc/vgotest1",
|
||||||
|
query: "v0.0.0-20180219223237-a08abb797a67",
|
||||||
version: "v0.0.0-20180219223237-a08abb797a67",
|
version: "v0.0.0-20180219223237-a08abb797a67",
|
||||||
latest: true,
|
latest: true,
|
||||||
time: time.Date(2018, 02, 19, 22, 32, 37, 0, time.UTC),
|
time: time.Date(2018, 02, 19, 22, 32, 37, 0, time.UTC),
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path: "github.com/hxzhao527/legacytest",
|
||||||
|
query: "master",
|
||||||
|
version: "v2.0.1+incompatible",
|
||||||
|
time: time.Date(2018, 07, 17, 16, 42, 53, 0, time.UTC),
|
||||||
|
gomod: "module github.com/hxzhao527/legacytest\n",
|
||||||
|
zip: []string{
|
||||||
|
"x.go",
|
||||||
|
},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
var _modListTests = []struct {
|
var _modListTests = []struct {
|
||||||
|
@ -159,7 +172,7 @@ func TestFetchInfo(t *testing.T) {
|
||||||
testenv.MustHaveExternalNetwork(t)
|
testenv.MustHaveExternalNetwork(t)
|
||||||
|
|
||||||
for _, mod := range _modInfoTests {
|
for _, mod := range _modInfoTests {
|
||||||
req := buildRequest(mod.path, mod.version, ".info")
|
req := buildRequest(mod.path, mod.query, ".info")
|
||||||
|
|
||||||
rr, err := basicCheck(req)
|
rr, err := basicCheck(req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -189,7 +202,7 @@ func TestFetchModFile(t *testing.T) {
|
||||||
if len(mod.gomod) == 0 {
|
if len(mod.gomod) == 0 {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
req := buildRequest(mod.path, mod.version, ".mod")
|
req := buildRequest(mod.path, mod.query, ".mod")
|
||||||
|
|
||||||
rr, err := basicCheck(req)
|
rr, err := basicCheck(req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -209,7 +222,7 @@ func TestFetchZip(t *testing.T) {
|
||||||
if len(mod.zip) == 0 {
|
if len(mod.zip) == 0 {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
req := buildRequest(mod.path, mod.version, ".zip")
|
req := buildRequest(mod.path, mod.query, ".zip")
|
||||||
|
|
||||||
rr, err := basicCheck(req)
|
rr, err := basicCheck(req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package proxy
|
package proxy
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
@ -27,3 +28,12 @@ func ReturnSuccess(w http.ResponseWriter, data []byte) {
|
||||||
w.WriteHeader(http.StatusOK)
|
w.WriteHeader(http.StatusOK)
|
||||||
_, _ = w.Write(data)
|
_, _ = w.Write(data)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func ReturnJsonData(w http.ResponseWriter, data interface{}) {
|
||||||
|
js, err := json.Marshal(data)
|
||||||
|
if err != nil {
|
||||||
|
ReturnInternalServerError(w, err)
|
||||||
|
} else {
|
||||||
|
ReturnSuccess(w, js)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue