aboutsummaryrefslogtreecommitdiffhomepage
path: root/tpl
diff options
context:
space:
mode:
authorBjørn Erik Pedersen <[email protected]>2023-03-04 18:08:29 +0100
committerBjørn Erik Pedersen <[email protected]>2023-03-04 21:29:05 +0100
commit3bbeb5688c4452a336af07be1e8cec44dac7d6ce (patch)
treef7e9f79839d1c050c148b5265c066f98a088fa8a /tpl
parent184a67ac4704b88083c43a68a5f85800192d7ff1 (diff)
downloadhugo-3bbeb5688c4452a336af07be1e8cec44dac7d6ce.tar.gz
hugo-3bbeb5688c4452a336af07be1e8cec44dac7d6ce.zip
Fix "context canceled" with partial
Make sure the context used for timeouts isn't created based on the incoming context, as we have cases where this can cancel the context prematurely. Fixes #10789
Diffstat (limited to 'tpl')
-rw-r--r--tpl/partials/integration_test.go28
-rw-r--r--tpl/partials/partials.go9
2 files changed, 34 insertions, 3 deletions
diff --git a/tpl/partials/integration_test.go b/tpl/partials/integration_test.go
index fcebe6c05..3dbaf2ce4 100644
--- a/tpl/partials/integration_test.go
+++ b/tpl/partials/integration_test.go
@@ -324,3 +324,31 @@ timeout = '200ms'
b.Assert(err.Error(), qt.Contains, "timed out")
}
+
+// See Issue #10789
+func TestReturnExecuteFromTemplateInPartial(t *testing.T) {
+ t.Parallel()
+
+ files := `
+-- config.toml --
+baseURL = 'http://example.com/'
+-- layouts/index.html --
+{{ $r := partial "foo" }}
+FOO:{{ $r.Content }}
+-- layouts/partials/foo.html --
+{{ $r := §§{{ partial "bar" }}§§ | resources.FromString "bar.html" | resources.ExecuteAsTemplate "bar.html" . }}
+{{ return $r }}
+-- layouts/partials/bar.html --
+BAR
+ `
+
+ b := hugolib.NewIntegrationTestBuilder(
+ hugolib.IntegrationTestConfig{
+ T: t,
+ TxtarString: files,
+ },
+ ).Build()
+
+ b.AssertFileContent("public/index.html", "OO:BAR")
+
+}
diff --git a/tpl/partials/partials.go b/tpl/partials/partials.go
index d9a826aa4..26ce0f5c6 100644
--- a/tpl/partials/partials.go
+++ b/tpl/partials/partials.go
@@ -129,7 +129,10 @@ func (ns *Namespace) Include(ctx context.Context, name string, contextList ...an
}
func (ns *Namespace) includWithTimeout(ctx context.Context, name string, dataList ...any) includeResult {
- ctx, cancel := context.WithTimeout(ctx, ns.deps.Timeout)
+ // There are situation where the ctx we pass on to the partial lives longer than
+ // the partial itself. For example, when the partial returns the result from reosurces.ExecuteAsTemplate.
+ // Because of that, create a completely new context here.
+ timeoutCtx, cancel := context.WithTimeout(context.Background(), ns.deps.Timeout)
defer cancel()
res := make(chan includeResult, 1)
@@ -141,8 +144,8 @@ func (ns *Namespace) includWithTimeout(ctx context.Context, name string, dataLis
select {
case r := <-res:
return r
- case <-ctx.Done():
- err := ctx.Err()
+ case <-timeoutCtx.Done():
+ err := timeoutCtx.Err()
if err == context.DeadlineExceeded {
err = fmt.Errorf("partial %q timed out after %s. This is most likely due to infinite recursion. If this is just a slow template, you can try to increase the 'timeout' config setting.", name, ns.deps.Timeout)
}