// escapeActionNode adds a pipeline call to the end that escapes the result // of the expression before it is interpolated into the template output. func escapeActionNode(node *parse.ActionNode) { pipe := node.Pipe cmds := pipe.Cmds nCmds := len(cmds) // If it already has an escaping command, do not interfere. if nCmds != 0 { if lastCmd := cmds[nCmds-1]; len(lastCmd.Args) != 0 { // TODO: Recognize url and js as escaping functions once // we have enough context to know whether additional // escaping is necessary. if arg, ok := lastCmd.Args[0].(*parse.IdentifierNode); ok && arg.Ident == "html" { return } } } htmlEscapeCommand := parse.CommandNode{ NodeType: parse.NodeCommand, Args: []parse.Node{parse.NewIdentifier("html")}, } node.Pipe.Cmds = append(node.Pipe.Cmds, &htmlEscapeCommand) }
// escapeAction escapes an action template node. func escapeAction(c context, n *parse.ActionNode) context { sanitizer := "html" if c.state == stateURL { sanitizer = "urlquery" } // If the pipe already ends with the sanitizer, do not interfere. if m := len(n.Pipe.Cmds); m != 0 { if last := n.Pipe.Cmds[m-1]; len(last.Args) != 0 { if i, ok := last.Args[0].(*parse.IdentifierNode); ok && i.Ident == sanitizer { return c } } } // Otherwise, append the sanitizer. n.Pipe.Cmds = append(n.Pipe.Cmds, &parse.CommandNode{ NodeType: parse.NodeCommand, Args: []parse.Node{parse.NewIdentifier(sanitizer)}, }) return c }
// newIdentCmd produces a command containing a single identifier node. func newIdentCmd(identifier string) *parse.CommandNode { return &parse.CommandNode{ NodeType: parse.NodeCommand, Args: []parse.Node{parse.NewIdentifier(identifier)}, } }