cmd/go/internal/modfetch: avoid http lookup for non-domain paths

Before, if vgo saw import "appengine" it would incorrectly try to
look up https://appengine?go-get=1. Apply the usual domain-name
restriction (dot before first slash) as in plain "go get".

Because the old network lookup also used to loop incorrectly,
at least according to a bug report, test a nonexistent domain
name too.

Fixes golang/go#23967.

Change-Id: I0deda2e4d1db408f07251856df402028e1a2d9b4
Reviewed-on: https://go-review.googlesource.com/117259
Run-TryBot: Russ Cox <rsc@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Bryan C. Mills <bcmills@google.com>
diff --git a/vendor/cmd/go/internal/modfetch/domain.go b/vendor/cmd/go/internal/modfetch/domain.go
index 633a4da..6e7b327 100644
--- a/vendor/cmd/go/internal/modfetch/domain.go
+++ b/vendor/cmd/go/internal/modfetch/domain.go
@@ -26,6 +26,13 @@
 }
 
 func lookupCustomDomain(path string) (Repo, error) {
+	dom := path
+	if i := strings.Index(dom, "/"); i >= 0 {
+		dom = dom[:i]
+	}
+	if !strings.Contains(dom, ".") {
+		return nil, fmt.Errorf("unknown module %s: not a domain name", path)
+	}
 	var body io.ReadCloser
 	err := web.Get(
 		"https://"+path+"?go-get=1",
diff --git a/vendor/cmd/go/testdata/badmod/go.mod b/vendor/cmd/go/testdata/badmod/go.mod
new file mode 100644
index 0000000..f7f6423
--- /dev/null
+++ b/vendor/cmd/go/testdata/badmod/go.mod
@@ -0,0 +1 @@
+module m
diff --git a/vendor/cmd/go/testdata/badmod/x.go b/vendor/cmd/go/testdata/badmod/x.go
new file mode 100644
index 0000000..579fb08
--- /dev/null
+++ b/vendor/cmd/go/testdata/badmod/x.go
@@ -0,0 +1,4 @@
+package x
+
+import _ "appengine"
+import _ "nonexistent.rsc.io" // domain does not exist
diff --git a/vendor/cmd/go/vgo_test.go b/vendor/cmd/go/vgo_test.go
index f703a70..73daf99 100644
--- a/vendor/cmd/go/vgo_test.go
+++ b/vendor/cmd/go/vgo_test.go
@@ -158,6 +158,22 @@
 	tg.grepStdoutNot(`vendor/`, "must not see vendored packages")
 }
 
+func TestVgoBadDomain(t *testing.T) {
+	tg := testgo(t)
+	defer tg.cleanup()
+	wd, _ := os.Getwd()
+	tg.cd(filepath.Join(wd, "testdata/badmod"))
+
+	tg.runFail("-vgo", "get", "appengine")
+	tg.grepStderr("unknown module appengine: not a domain name", "expected domain error")
+	tg.runFail("-vgo", "get", "x/y.z")
+	tg.grepStderr("unknown module x/y.z: not a domain name", "expected domain error")
+
+	tg.runFail("-vgo", "build")
+	tg.grepStderr("unknown module appengine: not a domain name", "expected domain error")
+	tg.grepStderr("tcp.*nonexistent.rsc.io", "expected error for nonexistent.rsc.io")
+}
+
 func TestFillGoMod(t *testing.T) {
 	testenv.MustHaveExternalNetwork(t)
 	tg := testgo(t)