liquid
liquid copied to clipboard
Add FRender to allow rendering into a custom io.Writer
Checklist
- [x] I have searched the issue list
- [ ] I have tested my example against Shopify Liquid. (This isn't necessary if the actual behavior is a panic, or an error for which
IsTemplateError
returns false.)
Expected Behavior
This proposal originated from https://github.com/osteele/liquid/issues/35 but tries to tackle a broader issue, i.e.: Sometimes I might want to have more control over the rendering process, specifically where the renderer writes to.
Example
- I might want to limit the number of bytes written when exposing templating to some untrusted party.
- I might want to set a timeout for the rendering process.
- I might want to render into a file directly.
Actual Behavior
The render
package has a Render(node Node, w io.Writer, vars map[string]interface{}, c Config)
function which takes an io.Writer
, however, this is meant for internal use only. The Template
methods have Render(vars Bindings) ([]byte, SourceError)
and RenderString(b Bindings) (string, SourceError)
which are useful in most circumstances but don't allow for more control as described above.
Detailed Description
Possible Solution
I'd propose a new Template
render method FRender
that allows to pass a custom io.Writer
:
func (t *Template) FRender(w io.Writer, vars Bindings) SourceError
This gives more control over the rendering process when needed, e.g. you might want to set a render timeout to avoid deeple nested loop constructs in a template to cause potential server issues:
type CancelWriter struct {
context.Context
bytes.Buffer
}
func (w *CancelWriter) Write(bs []byte) (int, error) {
if w.Err() != nil {
return w.Len(), context.Cause(w)
}
return w.Buffer.Write(bs)
}
func Render() ([]byte, error) {
wr := &CancelWriter{}
if err := liquid.NewEngine().ParseAndFRender(wr, nil /*untrustworthy template*/, nil /*data*/); err != nil {
return nil, err
}
return wr.Bytes(), nil
}