diff --git a/config/security/securityConfig.go b/config/security/securityConfig.go index 66e89fb97..f7d2beac8 100644 --- a/config/security/securityConfig.go +++ b/config/security/securityConfig.go @@ -88,6 +88,9 @@ type HTTP struct { // HTTP methods to allow. Methods Whitelist `json:"methods"` + + // Media types where the Content-Type in the response is used instead of resolving from the file content. + MediaTypes Whitelist `json:"mediaTypes"` } // ToTOML converts c to TOML with [security] as the root. diff --git a/config/security/securityConfig_test.go b/config/security/securityConfig_test.go index 55409e318..edc1737e3 100644 --- a/config/security/securityConfig_test.go +++ b/config/security/securityConfig_test.go @@ -163,8 +163,10 @@ func TestDecodeConfigDefault(t *testing.T) { c.Assert(pc.HTTP.Methods.Accept("GET"), qt.IsTrue) c.Assert(pc.HTTP.Methods.Accept("get"), qt.IsTrue) c.Assert(pc.HTTP.Methods.Accept("DELETE"), qt.IsFalse) + c.Assert(pc.HTTP.MediaTypes.Accept("application/msword"), qt.IsFalse) c.Assert(pc.Exec.OsEnv.Accept("PATH"), qt.IsTrue) c.Assert(pc.Exec.OsEnv.Accept("GOROOT"), qt.IsTrue) c.Assert(pc.Exec.OsEnv.Accept("MYSECRET"), qt.IsFalse) + } diff --git a/hugolib/securitypolicies_test.go b/hugolib/securitypolicies_test.go index aa062bb1f..5b9267b59 100644 --- a/hugolib/securitypolicies_test.go +++ b/hugolib/securitypolicies_test.go @@ -138,9 +138,9 @@ func TestSecurityPolicies(t *testing.T) { } cb := func(b *sitesBuilder) { b.WithConfigFile("toml", ` - [security] - [security.exec] - allow="none" +[security] +[security.exec] +allow="none" `) b.WithTemplatesAdded("index.html", `{{ $scss := "body { color: #333; }" | resources.FromString "foo.scss" | resources.ToCSS (dict "transpiler" "dartsass") }}`) @@ -166,6 +166,28 @@ func TestSecurityPolicies(t *testing.T) { [security] [security.http] urls="none" +`) + }) + }) + + c.Run("resources.GetRemote, fake JSON", func(c *qt.C) { + c.Parallel() + httpTestVariant(c, `{{ $json := resources.GetRemote "%[1]s/fakejson.json" }}{{ $json.Content }}`, `(?s).*failed to resolve media type.*`, + func(b *sitesBuilder) { + b.WithConfigFile("toml", ` +`) + }) + }) + + c.Run("resources.GetRemote, fake JSON whitelisted", func(c *qt.C) { + c.Parallel() + httpTestVariant(c, `{{ $json := resources.GetRemote "%[1]s/fakejson.json" }}{{ $json.Content }}`, ``, + func(b *sitesBuilder) { + b.WithConfigFile("toml", ` +[security] +[security.http] +mediaTypes=["application/json"] + `) }) }) diff --git a/hugolib/testdata/fakejson.json b/hugolib/testdata/fakejson.json new file mode 100644 index 000000000..f191b280c Binary files /dev/null and b/hugolib/testdata/fakejson.json differ diff --git a/resources/resource_factories/create/remote.go b/resources/resource_factories/create/remote.go index 3aae57e8d..73171e570 100644 --- a/resources/resource_factories/create/remote.go +++ b/resources/resource_factories/create/remote.go @@ -171,10 +171,17 @@ func (c *Client) FromRemote(uri string, optionsm map[string]any) (resource.Resou contentType := res.Header.Get("Content-Type") - if isHeadMethod { - // We have no body to work with, so we need to use the Content-Type header. - mediaType, _ = media.FromString(contentType) - } else { + // For HEAD requests we have no body to work with, so we need to use the Content-Type header. + if isHeadMethod || c.rs.ExecHelper.Sec().HTTP.MediaTypes.Accept(contentType) { + var found bool + mediaType, found = c.rs.MediaTypes().GetByType(contentType) + if !found { + // A media type not configured in Hugo, just create one from the content type string. + mediaType, _ = media.FromString(contentType) + } + } + + if mediaType.IsZero() { var extensionHints []string