diff options
Diffstat (limited to 'vendor/gopkg.in/macaron.v1/render.go')
-rw-r--r-- | vendor/gopkg.in/macaron.v1/render.go | 725 |
1 files changed, 0 insertions, 725 deletions
diff --git a/vendor/gopkg.in/macaron.v1/render.go b/vendor/gopkg.in/macaron.v1/render.go deleted file mode 100644 index f45e4312..00000000 --- a/vendor/gopkg.in/macaron.v1/render.go +++ /dev/null @@ -1,725 +0,0 @@ -// Copyright 2013 Martini Authors -// Copyright 2014 The Macaron Authors -// -// Licensed under the Apache License, Version 2.0 (the "License"): you may -// not use this file except in compliance with the License. You may obtain -// a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -// License for the specific language governing permissions and limitations -// under the License. - -package macaron - -import ( - "bytes" - "encoding/json" - "encoding/xml" - "fmt" - "html/template" - "io" - "io/ioutil" - "net/http" - "os" - "path" - "path/filepath" - "strings" - "sync" - "time" - - "github.com/Unknwon/com" -) - -const ( - _CONTENT_TYPE = "Content-Type" - _CONTENT_LENGTH = "Content-Length" - _CONTENT_BINARY = "application/octet-stream" - _CONTENT_JSON = "application/json" - _CONTENT_HTML = "text/html" - _CONTENT_PLAIN = "text/plain" - _CONTENT_XHTML = "application/xhtml+xml" - _CONTENT_XML = "text/xml" - _DEFAULT_CHARSET = "UTF-8" -) - -var ( - // Provides a temporary buffer to execute templates into and catch errors. - bufpool = sync.Pool{ - New: func() interface{} { return new(bytes.Buffer) }, - } - - // Included helper functions for use when rendering html - helperFuncs = template.FuncMap{ - "yield": func() (string, error) { - return "", fmt.Errorf("yield called with no layout defined") - }, - "current": func() (string, error) { - return "", nil - }, - } -) - -type ( - // TemplateFile represents a interface of template file that has name and can be read. - TemplateFile interface { - Name() string - Data() []byte - Ext() string - } - // TemplateFileSystem represents a interface of template file system that able to list all files. - TemplateFileSystem interface { - ListFiles() []TemplateFile - Get(string) (io.Reader, error) - } - - // Delims represents a set of Left and Right delimiters for HTML template rendering - Delims struct { - // Left delimiter, defaults to {{ - Left string - // Right delimiter, defaults to }} - Right string - } - - // RenderOptions represents a struct for specifying configuration options for the Render middleware. - RenderOptions struct { - // Directory to load templates. Default is "templates". - Directory string - // Addtional directories to overwite templates. - AppendDirectories []string - // Layout template name. Will not render a layout if "". Default is to "". - Layout string - // Extensions to parse template files from. Defaults are [".tmpl", ".html"]. - Extensions []string - // Funcs is a slice of FuncMaps to apply to the template upon compilation. This is useful for helper functions. Default is []. - Funcs []template.FuncMap - // Delims sets the action delimiters to the specified strings in the Delims struct. - Delims Delims - // Appends the given charset to the Content-Type header. Default is "UTF-8". - Charset string - // Outputs human readable JSON. - IndentJSON bool - // Outputs human readable XML. - IndentXML bool - // Prefixes the JSON output with the given bytes. - PrefixJSON []byte - // Prefixes the XML output with the given bytes. - PrefixXML []byte - // Allows changing of output to XHTML instead of HTML. Default is "text/html" - HTMLContentType string - // TemplateFileSystem is the interface for supporting any implmentation of template file system. - TemplateFileSystem - } - - // HTMLOptions is a struct for overriding some rendering Options for specific HTML call - HTMLOptions struct { - // Layout template name. Overrides Options.Layout. - Layout string - } - - Render interface { - http.ResponseWriter - SetResponseWriter(http.ResponseWriter) - - JSON(int, interface{}) - JSONString(interface{}) (string, error) - RawData(int, []byte) // Serve content as binary - PlainText(int, []byte) // Serve content as plain text - HTML(int, string, interface{}, ...HTMLOptions) - HTMLSet(int, string, string, interface{}, ...HTMLOptions) - HTMLSetString(string, string, interface{}, ...HTMLOptions) (string, error) - HTMLString(string, interface{}, ...HTMLOptions) (string, error) - HTMLSetBytes(string, string, interface{}, ...HTMLOptions) ([]byte, error) - HTMLBytes(string, interface{}, ...HTMLOptions) ([]byte, error) - XML(int, interface{}) - Error(int, ...string) - Status(int) - SetTemplatePath(string, string) - HasTemplateSet(string) bool - } -) - -// TplFile implements TemplateFile interface. -type TplFile struct { - name string - data []byte - ext string -} - -// NewTplFile cerates new template file with given name and data. -func NewTplFile(name string, data []byte, ext string) *TplFile { - return &TplFile{name, data, ext} -} - -func (f *TplFile) Name() string { - return f.name -} - -func (f *TplFile) Data() []byte { - return f.data -} - -func (f *TplFile) Ext() string { - return f.ext -} - -// TplFileSystem implements TemplateFileSystem interface. -type TplFileSystem struct { - files []TemplateFile -} - -// NewTemplateFileSystem creates new template file system with given options. -func NewTemplateFileSystem(opt RenderOptions, omitData bool) TplFileSystem { - fs := TplFileSystem{} - fs.files = make([]TemplateFile, 0, 10) - - // Directories are composed in reverse order because later one overwrites previous ones, - // so once found, we can directly jump out of the loop. - dirs := make([]string, 0, len(opt.AppendDirectories)+1) - for i := len(opt.AppendDirectories) - 1; i >= 0; i-- { - dirs = append(dirs, opt.AppendDirectories[i]) - } - dirs = append(dirs, opt.Directory) - - var err error - for i := range dirs { - // Skip ones that does not exists for symlink test, - // but allow non-symlink ones added after start. - if !com.IsExist(dirs[i]) { - continue - } - - dirs[i], err = filepath.EvalSymlinks(dirs[i]) - if err != nil { - panic("EvalSymlinks(" + dirs[i] + "): " + err.Error()) - } - } - lastDir := dirs[len(dirs)-1] - - // We still walk the last (original) directory because it's non-sense we load templates not exist in original directory. - if err = filepath.Walk(lastDir, func(path string, info os.FileInfo, err error) error { - r, err := filepath.Rel(lastDir, path) - if err != nil { - return err - } - - ext := GetExt(r) - - for _, extension := range opt.Extensions { - if ext != extension { - continue - } - - var data []byte - if !omitData { - // Loop over candidates of directory, break out once found. - // The file always exists because it's inside the walk function, - // and read original file is the worst case. - for i := range dirs { - path = filepath.Join(dirs[i], r) - if !com.IsFile(path) { - continue - } - - data, err = ioutil.ReadFile(path) - if err != nil { - return err - } - break - } - } - - name := filepath.ToSlash((r[0 : len(r)-len(ext)])) - fs.files = append(fs.files, NewTplFile(name, data, ext)) - } - - return nil - }); err != nil { - panic("NewTemplateFileSystem: " + err.Error()) - } - - return fs -} - -func (fs TplFileSystem) ListFiles() []TemplateFile { - return fs.files -} - -func (fs TplFileSystem) Get(name string) (io.Reader, error) { - for i := range fs.files { - if fs.files[i].Name()+fs.files[i].Ext() == name { - return bytes.NewReader(fs.files[i].Data()), nil - } - } - return nil, fmt.Errorf("file '%s' not found", name) -} - -func PrepareCharset(charset string) string { - if len(charset) != 0 { - return "; charset=" + charset - } - - return "; charset=" + _DEFAULT_CHARSET -} - -func GetExt(s string) string { - index := strings.Index(s, ".") - if index == -1 { - return "" - } - return s[index:] -} - -func compile(opt RenderOptions) *template.Template { - t := template.New(opt.Directory) - t.Delims(opt.Delims.Left, opt.Delims.Right) - // Parse an initial template in case we don't have any. - template.Must(t.Parse("Macaron")) - - if opt.TemplateFileSystem == nil { - opt.TemplateFileSystem = NewTemplateFileSystem(opt, false) - } - - for _, f := range opt.TemplateFileSystem.ListFiles() { - tmpl := t.New(f.Name()) - for _, funcs := range opt.Funcs { - tmpl.Funcs(funcs) - } - // Bomb out if parse fails. We don't want any silent server starts. - template.Must(tmpl.Funcs(helperFuncs).Parse(string(f.Data()))) - } - - return t -} - -const ( - DEFAULT_TPL_SET_NAME = "DEFAULT" -) - -// TemplateSet represents a template set of type *template.Template. -type TemplateSet struct { - lock sync.RWMutex - sets map[string]*template.Template - dirs map[string]string -} - -// NewTemplateSet initializes a new empty template set. -func NewTemplateSet() *TemplateSet { - return &TemplateSet{ - sets: make(map[string]*template.Template), - dirs: make(map[string]string), - } -} - -func (ts *TemplateSet) Set(name string, opt *RenderOptions) *template.Template { - t := compile(*opt) - - ts.lock.Lock() - defer ts.lock.Unlock() - - ts.sets[name] = t - ts.dirs[name] = opt.Directory - return t -} - -func (ts *TemplateSet) Get(name string) *template.Template { - ts.lock.RLock() - defer ts.lock.RUnlock() - - return ts.sets[name] -} - -func (ts *TemplateSet) GetDir(name string) string { - ts.lock.RLock() - defer ts.lock.RUnlock() - - return ts.dirs[name] -} - -func prepareRenderOptions(options []RenderOptions) RenderOptions { - var opt RenderOptions - if len(options) > 0 { - opt = options[0] - } - - // Defaults. - if len(opt.Directory) == 0 { - opt.Directory = "templates" - } - if len(opt.Extensions) == 0 { - opt.Extensions = []string{".tmpl", ".html"} - } - if len(opt.HTMLContentType) == 0 { - opt.HTMLContentType = _CONTENT_HTML - } - - return opt -} - -func ParseTplSet(tplSet string) (tplName string, tplDir string) { - tplSet = strings.TrimSpace(tplSet) - if len(tplSet) == 0 { - panic("empty template set argument") - } - infos := strings.Split(tplSet, ":") - if len(infos) == 1 { - tplDir = infos[0] - tplName = path.Base(tplDir) - } else { - tplName = infos[0] - tplDir = infos[1] - } - - if !com.IsDir(tplDir) { - panic("template set path does not exist or is not a directory") - } - return tplName, tplDir -} - -func renderHandler(opt RenderOptions, tplSets []string) Handler { - cs := PrepareCharset(opt.Charset) - ts := NewTemplateSet() - ts.Set(DEFAULT_TPL_SET_NAME, &opt) - - var tmpOpt RenderOptions - for _, tplSet := range tplSets { - tplName, tplDir := ParseTplSet(tplSet) - tmpOpt = opt - tmpOpt.Directory = tplDir - ts.Set(tplName, &tmpOpt) - } - - return func(ctx *Context) { - r := &TplRender{ - ResponseWriter: ctx.Resp, - TemplateSet: ts, - Opt: &opt, - CompiledCharset: cs, - } - ctx.Data["TmplLoadTimes"] = func() string { - if r.startTime.IsZero() { - return "" - } - return fmt.Sprint(time.Since(r.startTime).Nanoseconds()/1e6) + "ms" - } - - ctx.Render = r - ctx.MapTo(r, (*Render)(nil)) - } -} - -// Renderer is a Middleware that maps a macaron.Render service into the Macaron handler chain. -// An single variadic macaron.RenderOptions struct can be optionally provided to configure -// HTML rendering. The default directory for templates is "templates" and the default -// file extension is ".tmpl" and ".html". -// -// If MACARON_ENV is set to "" or "development" then templates will be recompiled on every request. For more performance, set the -// MACARON_ENV environment variable to "production". -func Renderer(options ...RenderOptions) Handler { - return renderHandler(prepareRenderOptions(options), []string{}) -} - -func Renderers(options RenderOptions, tplSets ...string) Handler { - return renderHandler(prepareRenderOptions([]RenderOptions{options}), tplSets) -} - -type TplRender struct { - http.ResponseWriter - *TemplateSet - Opt *RenderOptions - CompiledCharset string - - startTime time.Time -} - -func (r *TplRender) SetResponseWriter(rw http.ResponseWriter) { - r.ResponseWriter = rw -} - -func (r *TplRender) JSON(status int, v interface{}) { - var ( - result []byte - err error - ) - if r.Opt.IndentJSON { - result, err = json.MarshalIndent(v, "", " ") - } else { - result, err = json.Marshal(v) - } - if err != nil { - http.Error(r, err.Error(), 500) - return - } - - // json rendered fine, write out the result - r.Header().Set(_CONTENT_TYPE, _CONTENT_JSON+r.CompiledCharset) - r.WriteHeader(status) - if len(r.Opt.PrefixJSON) > 0 { - r.Write(r.Opt.PrefixJSON) - } - r.Write(result) -} - -func (r *TplRender) JSONString(v interface{}) (string, error) { - var result []byte - var err error - if r.Opt.IndentJSON { - result, err = json.MarshalIndent(v, "", " ") - } else { - result, err = json.Marshal(v) - } - if err != nil { - return "", err - } - return string(result), nil -} - -func (r *TplRender) XML(status int, v interface{}) { - var result []byte - var err error - if r.Opt.IndentXML { - result, err = xml.MarshalIndent(v, "", " ") - } else { - result, err = xml.Marshal(v) - } - if err != nil { - http.Error(r, err.Error(), 500) - return - } - - // XML rendered fine, write out the result - r.Header().Set(_CONTENT_TYPE, _CONTENT_XML+r.CompiledCharset) - r.WriteHeader(status) - if len(r.Opt.PrefixXML) > 0 { - r.Write(r.Opt.PrefixXML) - } - r.Write(result) -} - -func (r *TplRender) data(status int, contentType string, v []byte) { - if r.Header().Get(_CONTENT_TYPE) == "" { - r.Header().Set(_CONTENT_TYPE, contentType) - } - r.WriteHeader(status) - r.Write(v) -} - -func (r *TplRender) RawData(status int, v []byte) { - r.data(status, _CONTENT_BINARY, v) -} - -func (r *TplRender) PlainText(status int, v []byte) { - r.data(status, _CONTENT_PLAIN, v) -} - -func (r *TplRender) execute(t *template.Template, name string, data interface{}) (*bytes.Buffer, error) { - buf := bufpool.Get().(*bytes.Buffer) - return buf, t.ExecuteTemplate(buf, name, data) -} - -func (r *TplRender) addYield(t *template.Template, tplName string, data interface{}) { - funcs := template.FuncMap{ - "yield": func() (template.HTML, error) { - buf, err := r.execute(t, tplName, data) - // return safe html here since we are rendering our own template - return template.HTML(buf.String()), err - }, - "current": func() (string, error) { - return tplName, nil - }, - } - t.Funcs(funcs) -} - -func (r *TplRender) renderBytes(setName, tplName string, data interface{}, htmlOpt ...HTMLOptions) (*bytes.Buffer, error) { - t := r.TemplateSet.Get(setName) - if Env == DEV { - opt := *r.Opt - opt.Directory = r.TemplateSet.GetDir(setName) - t = r.TemplateSet.Set(setName, &opt) - } - if t == nil { - return nil, fmt.Errorf("html/template: template \"%s\" is undefined", tplName) - } - - opt := r.prepareHTMLOptions(htmlOpt) - - if len(opt.Layout) > 0 { - r.addYield(t, tplName, data) - tplName = opt.Layout - } - - out, err := r.execute(t, tplName, data) - if err != nil { - return nil, err - } - - return out, nil -} - -func (r *TplRender) renderHTML(status int, setName, tplName string, data interface{}, htmlOpt ...HTMLOptions) { - r.startTime = time.Now() - - out, err := r.renderBytes(setName, tplName, data, htmlOpt...) - if err != nil { - http.Error(r, err.Error(), http.StatusInternalServerError) - return - } - - r.Header().Set(_CONTENT_TYPE, r.Opt.HTMLContentType+r.CompiledCharset) - r.WriteHeader(status) - - if _, err := out.WriteTo(r); err != nil { - out.Reset() - } - bufpool.Put(out) -} - -func (r *TplRender) HTML(status int, name string, data interface{}, htmlOpt ...HTMLOptions) { - r.renderHTML(status, DEFAULT_TPL_SET_NAME, name, data, htmlOpt...) -} - -func (r *TplRender) HTMLSet(status int, setName, tplName string, data interface{}, htmlOpt ...HTMLOptions) { - r.renderHTML(status, setName, tplName, data, htmlOpt...) -} - -func (r *TplRender) HTMLSetBytes(setName, tplName string, data interface{}, htmlOpt ...HTMLOptions) ([]byte, error) { - out, err := r.renderBytes(setName, tplName, data, htmlOpt...) - if err != nil { - return []byte(""), err - } - return out.Bytes(), nil -} - -func (r *TplRender) HTMLBytes(name string, data interface{}, htmlOpt ...HTMLOptions) ([]byte, error) { - return r.HTMLSetBytes(DEFAULT_TPL_SET_NAME, name, data, htmlOpt...) -} - -func (r *TplRender) HTMLSetString(setName, tplName string, data interface{}, htmlOpt ...HTMLOptions) (string, error) { - p, err := r.HTMLSetBytes(setName, tplName, data, htmlOpt...) - return string(p), err -} - -func (r *TplRender) HTMLString(name string, data interface{}, htmlOpt ...HTMLOptions) (string, error) { - p, err := r.HTMLBytes(name, data, htmlOpt...) - return string(p), err -} - -// Error writes the given HTTP status to the current ResponseWriter -func (r *TplRender) Error(status int, message ...string) { - r.WriteHeader(status) - if len(message) > 0 { - r.Write([]byte(message[0])) - } -} - -func (r *TplRender) Status(status int) { - r.WriteHeader(status) -} - -func (r *TplRender) prepareHTMLOptions(htmlOpt []HTMLOptions) HTMLOptions { - if len(htmlOpt) > 0 { - return htmlOpt[0] - } - - return HTMLOptions{ - Layout: r.Opt.Layout, - } -} - -func (r *TplRender) SetTemplatePath(setName, dir string) { - if len(setName) == 0 { - setName = DEFAULT_TPL_SET_NAME - } - opt := *r.Opt - opt.Directory = dir - r.TemplateSet.Set(setName, &opt) -} - -func (r *TplRender) HasTemplateSet(name string) bool { - return r.TemplateSet.Get(name) != nil -} - -// DummyRender is used when user does not choose any real render to use. -// This way, we can print out friendly message which asks them to register one, -// instead of ugly and confusing 'nil pointer' panic. -type DummyRender struct { - http.ResponseWriter -} - -func renderNotRegistered() { - panic("middleware render hasn't been registered") -} - -func (r *DummyRender) SetResponseWriter(http.ResponseWriter) { - renderNotRegistered() -} - -func (r *DummyRender) JSON(int, interface{}) { - renderNotRegistered() -} - -func (r *DummyRender) JSONString(interface{}) (string, error) { - renderNotRegistered() - return "", nil -} - -func (r *DummyRender) RawData(int, []byte) { - renderNotRegistered() -} - -func (r *DummyRender) PlainText(int, []byte) { - renderNotRegistered() -} - -func (r *DummyRender) HTML(int, string, interface{}, ...HTMLOptions) { - renderNotRegistered() -} - -func (r *DummyRender) HTMLSet(int, string, string, interface{}, ...HTMLOptions) { - renderNotRegistered() -} - -func (r *DummyRender) HTMLSetString(string, string, interface{}, ...HTMLOptions) (string, error) { - renderNotRegistered() - return "", nil -} - -func (r *DummyRender) HTMLString(string, interface{}, ...HTMLOptions) (string, error) { - renderNotRegistered() - return "", nil -} - -func (r *DummyRender) HTMLSetBytes(string, string, interface{}, ...HTMLOptions) ([]byte, error) { - renderNotRegistered() - return nil, nil -} - -func (r *DummyRender) HTMLBytes(string, interface{}, ...HTMLOptions) ([]byte, error) { - renderNotRegistered() - return nil, nil -} - -func (r *DummyRender) XML(int, interface{}) { - renderNotRegistered() -} - -func (r *DummyRender) Error(int, ...string) { - renderNotRegistered() -} - -func (r *DummyRender) Status(int) { - renderNotRegistered() -} - -func (r *DummyRender) SetTemplatePath(string, string) { - renderNotRegistered() -} - -func (r *DummyRender) HasTemplateSet(string) bool { - renderNotRegistered() - return false -} |