Permalink
Browse files

Couple of changes: 1) Let the safe filter only apply on strings. 2) F…

…ixing #2 3) Catching any ocurring panic and printing stack trace if debug mode is activated with mytpl.SetDebug(true)
  • Loading branch information...
1 parent 038f286 commit c924d5dbc482cbd7ec5ad287470139328c39972f @flosch committed Sep 10, 2012
Showing with 58 additions and 12 deletions.
  1. +8 −1 expr.go
  2. +6 −2 filters.go
  3. +28 −2 template.go
  4. +16 −7 template_test.go
View
@@ -494,7 +494,14 @@ func (e *expr) evalValue(ctx *Context) (interface{}, error) {
case bool:
return !val, nil
default:
- return nil, errors.New(fmt.Sprintf("Cannot negate '%v' of type %T (maybe you want to add the unsafe-filter; filter history: %v).", value, value, chainCtx.applied_filters))
+ fmt.Printf("%v (type %T)\n", value, value)
+ // If negation of a string, int or something, check whether they equal
+ // their default value. Default behaviour is: empty type evaluates to false (since
+ // this is a negation it must evaluating to true)
+ value = reflect.Zero(reflect.TypeOf(value)).Interface() == value
+
+ // TODO: Not needed anymore?
+ //return nil, errors.New(fmt.Sprintf("Cannot negate '%v' of type %T (maybe you want to add the unsafe-filter; filter history: %v).", value, value, chainCtx.applied_filters))
}
}
View
@@ -65,9 +65,13 @@ func filterSafe(value interface{}, args []interface{}, ctx *FilterChainContext)
return value, nil
}
- output := fmt.Sprintf("%v", value)
+ str, is_str := value.(string)
+ if !is_str {
+ // We don't have to safe non-strings
+ return value, nil
+ }
- output = strings.Replace(output, "&", "&", -1)
+ output := strings.Replace(str, "&", "&", -1)
output = strings.Replace(output, ">", ">", -1)
output = strings.Replace(output, "<", "&lt;", -1)
View
@@ -6,6 +6,7 @@ import (
"io/ioutil"
"net/http"
"path/filepath"
+ "runtime/debug"
"strings"
)
@@ -83,6 +84,9 @@ type Template struct {
// Static content (doesn't change with execution)
cache map[string]interface{}
+
+ // Debugging
+ debug bool
}
type stateFunc func(*Template) stateFunc
@@ -488,7 +492,7 @@ func (tpl *Template) parse() error {
return nil
}
-// Executes the template with the given context and write to http.ResponseWriter
+// Executes the template with the given context and writes to http.ResponseWriter
// on success. Context can be nil. Nothing is written on error; instead the error
// is being returned.
func (tpl *Template) ExecuteRW(w http.ResponseWriter, ctx *Context) error {
@@ -501,10 +505,32 @@ func (tpl *Template) ExecuteRW(w http.ResponseWriter, ctx *Context) error {
}
// Executes the template with the given context (can be nil).
-func (tpl *Template) Execute(ctx *Context) (*string, error) {
+func (tpl *Template) Execute(ctx *Context) (out *string, err error) {
+ defer func() {
+ rerr := recover()
+ if rerr != nil {
+ // Panic recovered
+ out = nil
+ err = errors.New(fmt.Sprintf("Pongo panicked with this error (please report this issue, see console output! You can see the stack trace when activating debugging: tpl.SetDebug(true)): %s", rerr))
+
+ if tpl.debug {
+ fmt.Println("*************************************************************************")
+ fmt.Println("Due to panicking of pongo, I'm printing the error message and stack here.")
+ fmt.Printf("Panic message: %s\n", rerr)
+ fmt.Println("*************************************************************************")
+ debug.PrintStack()
+ fmt.Println("*************************************************************************")
+ }
+ }
+ }()
return tpl.execute(ctx, nil)
}
+// pongo will print out a stacktrace whenever it panics if set to true.
+func (tpl *Template) SetDebug(d bool) {
+ tpl.debug = d
+}
+
func newExecutionContext(tpl *Template, internalContext *Context) *executionContext {
var ctx Context
if internalContext == nil {
View
@@ -102,11 +102,11 @@ var standard_tests = []test{
// Bool (and negation)
{"{{ true }}", "true", nil, ""},
{"{{ false }}", "false", nil, ""},
- {"{{ !5|unsafe }}", "", nil, "Cannot negate '5' of type int"},
- {"{{ !true }}", "", nil, "maybe you want to add the unsafe-filter"},
- {"{{ !false }}", "", nil, "maybe you want to add the unsafe-filter"},
- {"{{ !true|unsafe }}", "false", nil, ""},
- {"{{ !false|unsafe }}", "true", nil, ""},
+ {"{{ !5 }}", "false", nil, ""},
+ {"{{ !0 }}", "true", nil, ""},
+ {"{{ !0.0 }}", "true", nil, ""},
+ {"{{ !true }}", "false", nil, ""},
+ {"{{ !false }}", "true", nil, ""},
// Simple variables
{"{{ foo }}", "", nil, ""},
@@ -243,20 +243,27 @@ var tags_tests = []test{
{"{% if !true || !true || !true || true && true %}Yes{% else %}No{%endif%}", "Yes", nil, ""},
{"{% if false || false || true || false %}Yes{% else %}No{%endif%}", "Yes", nil, ""},
{"{% if false || true %}Yes{% else %}No{%endif%}", "Yes", nil, ""},
+ {"{% if !novalue %}Yes{% else %}No{%endif%}", "Yes", nil, ""},
+ {"{% if person %}Yes{% else %}No{% endif %}", "xxxx", Context{"person": &person}, "Pongo panicked with this error"}, // This one lets pongo panicking in tags.go
+ {"{% if person %}Yes{% else %}No{% endif %}", "xxxx", Context{"person": &person}, "FUTURE"}, // Should be fixed in the future
// ... strings
- {"{% if \"\" %}Yes{% else %}No{%endif%}", "No", nil, ""}, // an empty string evaluates to false
+ {"{% if \"\" %}Yes{% else %}No{%endif%}", "No", nil, ""}, // an empty string evaluates to false
+ {"{% if emptystring %}Yes{% else %}No{%endif%}", "No", Context{"emptystring": ""}, ""}, // an empty string evaluates to false
+ {"{% if !emptystring %}Yes{% else %}No{%endif%}", "Yes", Context{"emptystring": ""}, ""}, // an empty string evaluates to false
{"{% if \"with content\" %}Yes{% else %}No{%endif%}", "Yes", nil, ""},
// ... ints
{"{% if 0 %}Yes{% else %}No{%endif%}", "No", nil, ""}, // 0 evaluates to false
{"{% if zero %}Yes{% else %}No{%endif%}", "No", Context{"zero": 0}, ""},
+ {"{# int #}{% if four %}Yes{% else %}No{%endif%}", "Yes", Context{"four": 4}, ""},
{"{% if 1 %}Yes{% else %}No{%endif%}", "Yes", nil, ""},
{"{% if 919592 %}Yes{% else %}No{%endif%}", "Yes", nil, ""},
// ... floats
{"{% if 0.0 %}Yes{% else %}No{%endif%}", "No", nil, ""}, // 0.0 evaluates to false
{"{% if zero %}Yes{% else %}No{%endif%}", "No", Context{"zero": 0}, ""},
+ {"{# float #}{% if four %}Yes{% else %}No{%endif%}", "Yes", Context{"four": 4.0}, ""},
{"{% if 1 %}Yes{% else %}No{%endif%}", "Yes", nil, ""},
{"{% if 919592 %}Yes{% else %}No{%endif%}", "Yes", nil, ""},
@@ -276,6 +283,8 @@ var tags_tests = []test{
{"{% if name == \"flo==ri&&an\" %}yes{%else%}no{%endif%}", "yes", Context{"name": "flo==ri&&an"}, ""},
// For
+ {"{% for six %}{{ forloop.Counter }}{% endfor %}", "012345", Context{"six": 6}, ""},
+ {"{% for seven %}{{ forloop.Counter }}{% endfor %}", "", Context{"six": "7"}, "For-loop error: Cannot iterate over 'seven'"},
{"{% for 6 %}{{ forloop.Counter }}{% endfor %}", "012345", nil, ""},
{"{% for 6 %}{{ forcounter }}{% endfor %}", "012345", nil, ""},
{"{% for 6 %}{{ forloop.Counter1 }}{% endfor %}", "123456", nil, ""},
@@ -363,7 +372,7 @@ var tags_tests = []test{
{"{% include tpl_name %} How are you today?", "Hello Flo! How are you today?", Context{"name": "flo", "tpl_name": "greetings"}, ""},
{"{% include \"foobar\" %} This and that", "", nil, "Could not find the template"},
{"{% include \"greetings_with_errors\" %} This and that", "", nil, "[Parsing error: greetings_with_errors] [Line 1, Column 27] Filter 'notexistent' not found"},
-
+
// Static include (see comments for static extend above)
{"{% include static \"greetings\" %} How are you today?", "Hello Flo! How are you today?", Context{"name": "flo"}, ""},
{"{% include static tpl_name %} How are you today?", "Hello Flo! How are you today?", Context{"name": "flo", "tpl_name": "greetings"}, "Please provide a propper template filename"},

0 comments on commit c924d5d

Please sign in to comment.