diff --git a/config/module/get_test.go b/config/module/get_test.go index 6b661dc01d..0c6ff020f5 100644 --- a/config/module/get_test.go +++ b/config/module/get_test.go @@ -49,6 +49,10 @@ var testMods = map[string][]testMod{ location: "file:///registry/exists", version: "0.2.0", }}, + "relative/foo/bar": {{ // There is an exception for the "relative/" prefix in the test registry server + location: "/relative-path", + version: "0.2.0", + }}, "test-versions/name/provider": { {version: "2.2.0"}, {version: "2.1.1"}, @@ -103,7 +107,7 @@ func mockRegHandler() http.Handler { mod := versions[0] location := mod.location - if !strings.HasPrefix(location, "file:///") { + if !strings.HasPrefix(matches[0], "relative/") && !strings.HasPrefix(location, "file:///") { // we can't use filepath.Abs because it will clean `//` wd, _ := os.Getwd() location = fmt.Sprintf("file://%s/%s", wd, location) diff --git a/config/module/registry.go b/config/module/registry.go index 3741af2040..3ea31708d4 100644 --- a/config/module/registry.go +++ b/config/module/registry.go @@ -186,5 +186,25 @@ func (s *Storage) lookupModuleLocation(module *regsrc.Module, version string) (s return "", fmt.Errorf("failed to get download URL for %q: %s resp:%s", module, resp.Status, body) } + // If location looks like it's trying to be a relative URL, treat it as + // one. + // + // We don't do this for just _any_ location, since the X-Terraform-Get + // header is a go-getter location rather than a URL, and so not all + // possible values will parse reasonably as URLs.) + // + // When used in conjunction with go-getter we normally require this header + // to be an absolute URL, but we are more liberal here because third-party + // registry implementations may not "know" their own absolute URLs if + // e.g. they are running behind a reverse proxy frontend, or such. + if strings.HasPrefix(location, "/") || strings.HasPrefix(location, "./") || strings.HasPrefix(location, "../") { + locationURL, err := url.Parse(location) + if err != nil { + return "", fmt.Errorf("invalid relative URL for %q: %s", module, err) + } + locationURL = download.ResolveReference(locationURL) + location = locationURL.String() + } + return location, nil } diff --git a/config/module/registry_test.go b/config/module/registry_test.go index ded0040be8..54c8f818ed 100644 --- a/config/module/registry_test.go +++ b/config/module/registry_test.go @@ -93,7 +93,30 @@ func TestRegistryAuth(t *testing.T) { } } +func TestLookupModuleLocationRelative(t *testing.T) { + server := mockRegistry() + defer server.Close() + + regDisco := testDisco(server) + storage := testStorage(t, regDisco) + src := "relative/foo/bar" + mod, err := regsrc.ParseModuleSource(src) + if err != nil { + t.Fatal(err) + } + + got, err := storage.lookupModuleLocation(mod, "0.2.0") + if err != nil { + t.Fatal(err) + } + + want := server.URL + "/relative-path" + if got != want { + t.Errorf("wrong location %s; want %s", got, want) + } + +} func TestAccLookupModuleVersions(t *testing.T) { if os.Getenv("TF_ACC") == "" { t.Skip()