// Escape rewrites each action in the template to guarantee that the output is // HTML-escaped. func Escape(t *template.Template) (*template.Template, os.Error) { c := escapeList(context{}, t.Tree.Root) if c.errStr != "" { return nil, fmt.Errorf("%s:%d: %s", t.Name(), c.errLine, c.errStr) } if c.state != stateText { return nil, fmt.Errorf("%s ends in a non-text context: %v", t.Name(), c) } return t, nil }
// Escape rewrites each action in the template to guarantee that the output is // properly escaped. func Escape(t *template.Template) (*template.Template, os.Error) { var s template.Set s.Add(t) if _, err := EscapeSet(&s, t.Name()); err != nil { return nil, err } // TODO: if s contains cloned dependencies due to self-recursion // cross-context, error out. return t, nil }
// computeOutCtx takes a template and its start context and computes the output // context while storing any inferences in e. func (e *escaper) computeOutCtx(c context, t *template.Template) context { // Propagate context over the body. c1, ok := e.escapeTemplateBody(c, t) if !ok { // Look for a fixed point by assuming c1 as the output context. if c2, ok2 := e.escapeTemplateBody(c1, t); ok2 { c1, ok = c2, true } // Use c1 as the error context if neither assumption worked. } if !ok && c1.state != stateError { return context{ state: stateError, // TODO: Find the first node with a line in t.Tree.Root err: errorf(ErrOutputContext, 0, "cannot compute output context for template %s", t.Name()), } } return c1 }
// escapeTemplateBody escapes the given template assuming the given output // context, and returns the best guess at the output context and whether the // assumption was correct. func (e *escaper) escapeTemplateBody(c context, t *template.Template) (context, bool) { filter := func(e1 *escaper, c1 context) bool { if c1.state == stateError { // Do not update the input escaper, e. return false } if !e1.called[t.Name()] { // If t is not recursively called, then c1 is an // accurate output context. return true } // c1 is accurate if it matches our assumed output context. return c.eq(c1) } // We need to assume an output context so that recursive template calls // take the fast path out of escapeTree instead of infinitely recursing. // Naively assuming that the input context is the same as the output // works >90% of the time. e.output[t.Name()] = c return e.escapeListConditionally(c, t.Tree.Root, filter) }