From df3ed787e1152e25e8b19c608d38481e745569aa Mon Sep 17 00:00:00 2001 From: Manu Mtz-Almeida Date: Tue, 31 Mar 2015 17:36:13 +0200 Subject: [PATCH] Fixes debug HTML rendering: - Stateless algorithm --- gin.go | 8 ++-- render/html_debug.go | 50 ++++++++++++++++++++++ render/render.go | 98 ++++++++++++++++++-------------------------- 3 files changed, 94 insertions(+), 62 deletions(-) create mode 100644 render/html_debug.go diff --git a/gin.go b/gin.go index a7eb0309..c126ae69 100644 --- a/gin.go +++ b/gin.go @@ -76,8 +76,8 @@ func (engine *Engine) allocateContext() (c *Context) { func (engine *Engine) LoadHTMLGlob(pattern string) { if IsDebugging() { - render.HTMLDebug.AddGlob(pattern) - engine.HTMLRender = render.HTMLDebug + r := &render.HTMLDebugRender{Glob: pattern} + engine.HTMLRender = r } else { templ := template.Must(template.ParseGlob(pattern)) engine.SetHTMLTemplate(templ) @@ -86,8 +86,8 @@ func (engine *Engine) LoadHTMLGlob(pattern string) { func (engine *Engine) LoadHTMLFiles(files ...string) { if IsDebugging() { - render.HTMLDebug.AddFiles(files...) - engine.HTMLRender = render.HTMLDebug + r := &render.HTMLDebugRender{Files: files} + engine.HTMLRender = r } else { templ := template.Must(template.ParseFiles(files...)) engine.SetHTMLTemplate(templ) diff --git a/render/html_debug.go b/render/html_debug.go new file mode 100644 index 00000000..3c6426e7 --- /dev/null +++ b/render/html_debug.go @@ -0,0 +1,50 @@ +// Copyright 2014 Manu Martinez-Almeida. All rights reserved. +// Use of this source code is governed by a MIT style +// license that can be found in the LICENSE file. + +package render + +import ( + "html/template" + "net/http" +) + +type HTMLDebugRender struct { + files []string + globs []string +} + +func (r *HTMLDebugRender) AddGlob(pattern string) { + r.globs = append(r.globs, pattern) +} + +func (r *HTMLDebugRender) AddFiles(files ...string) { + r.files = append(r.files, files...) +} + +func (r *HTMLDebugRender) Render(w http.ResponseWriter, code int, data ...interface{}) error { + WriteHeader(w, code, "text/html") + file := data[0].(string) + obj := data[1] + + if t, err := r.newTemplate(); err == nil { + return t.ExecuteTemplate(w, file, obj) + } else { + return err + } +} + +func (r *HTMLDebugRender) newTemplate() (*template.Template, error) { + t := template.New("") + if len(r.files) > 0 { + if _, err := t.ParseFiles(r.files...); err != nil { + return nil, err + } + } + for _, glob := range r.globs { + if _, err := t.ParseGlob(glob); err != nil { + return nil, err + } + } + return t, nil +} diff --git a/render/render.go b/render/render.go index 09f13f50..ff2fdfc4 100644 --- a/render/render.go +++ b/render/render.go @@ -27,11 +27,6 @@ type ( redirectRender struct{} - htmlDebugRender struct { - files []string - globs []string - } - HTMLRender struct { Template *template.Template } @@ -43,34 +38,26 @@ var ( HTMLPlain = htmlPlainRender{} Plain = plainTextRender{} Redirect = redirectRender{} - HTMLDebug = &htmlDebugRender{} ) -func writeHeader(w http.ResponseWriter, code int, contentType string) { - w.Header().Set("Content-Type", contentType+"; charset=utf-8") - w.WriteHeader(code) -} - -func (_ jsonRender) Render(w http.ResponseWriter, code int, data ...interface{}) error { - writeHeader(w, code, "application/json") - encoder := json.NewEncoder(w) - return encoder.Encode(data[0]) -} - func (_ redirectRender) Render(w http.ResponseWriter, code int, data ...interface{}) error { w.Header().Set("Location", data[0].(string)) w.WriteHeader(code) return nil } +func (_ jsonRender) Render(w http.ResponseWriter, code int, data ...interface{}) error { + WriteHeader(w, code, "application/json") + return json.NewEncoder(w).Encode(data[0]) +} + func (_ xmlRender) Render(w http.ResponseWriter, code int, data ...interface{}) error { - writeHeader(w, code, "application/xml") - encoder := xml.NewEncoder(w) - return encoder.Encode(data[0]) + WriteHeader(w, code, "application/xml") + return xml.NewEncoder(w).Encode(data[0]) } func (_ plainTextRender) Render(w http.ResponseWriter, code int, data ...interface{}) (err error) { - writeHeader(w, code, "text/plain") + WriteHeader(w, code, "text/plain") format := data[0].(string) args := data[1].([]interface{}) if len(args) > 0 { @@ -81,52 +68,47 @@ func (_ plainTextRender) Render(w http.ResponseWriter, code int, data ...interfa return } -func (_ htmlPlainRender) Render(w http.ResponseWriter, code int, data ...interface{}) error { - writeHeader(w, code, "text/html") +func (_ htmlPlainRender) Render(w http.ResponseWriter, code int, data ...interface{}) (err error) { + WriteHeader(w, code, "text/html") format := data[0].(string) args := data[1].([]interface{}) - var err error if len(args) > 0 { _, err = w.Write([]byte(fmt.Sprintf(format, args...))) } else { _, err = w.Write([]byte(format)) } - return err -} - -func (r *htmlDebugRender) AddGlob(pattern string) { - r.globs = append(r.globs, pattern) -} - -func (r *htmlDebugRender) AddFiles(files ...string) { - r.files = append(r.files, files...) -} - -func (r *htmlDebugRender) Render(w http.ResponseWriter, code int, data ...interface{}) error { - writeHeader(w, code, "text/html") - file := data[0].(string) - obj := data[1] - - t := template.New("") - - if len(r.files) > 0 { - if _, err := t.ParseFiles(r.files...); err != nil { - return err - } - } - - for _, glob := range r.globs { - if _, err := t.ParseGlob(glob); err != nil { - return err - } - } - - return t.ExecuteTemplate(w, file, obj) + return } func (html HTMLRender) Render(w http.ResponseWriter, code int, data ...interface{}) error { - writeHeader(w, code, "text/html") + WriteHeader(w, code, "text/html") file := data[0].(string) - obj := data[1] - return html.Template.ExecuteTemplate(w, file, obj) + args := data[1] + return html.Template.ExecuteTemplate(w, file, args) +} + +func WriteHeader(w http.ResponseWriter, code int, contentType string) { + contentType = joinStrings(contentType, "; charset=utf-8") + w.Header().Set("Content-Type", contentType) + w.WriteHeader(code) +} + +func joinStrings(a ...string) string { + if len(a) == 0 { + return "" + } + if len(a) == 1 { + return a[0] + } + n := 0 + for i := 0; i < len(a); i++ { + n += len(a[i]) + } + + b := make([]byte, n) + n = 0 + for _, s := range a { + n += copy(b[n:], s) + } + return string(b) }