func (self *CachedView) Render(context *Context, writer *utils.XMLWriter) (err error) { if self.Content == nil { return nil } if Config.DisableCachedViews || len(context.Params) > 0 || context.Request.Method != "GET" { return self.Content.Render(context, writer) } if self.data == nil || time.Now().After(self.validUntil) { xmlBuffer := utils.NewXMLBuffer() err = self.Content.Render(context, &xmlBuffer.XMLWriter) if err != nil { return err } self.data = xmlBuffer.Bytes() self.validUntil = time.Now().Add(self.Duration) } _, err = writer.Write(self.data) return err }
func (self *Page) Render(context *Context, writer *utils.XMLWriter) (err error) { if self.OnPreRender != nil { err = self.OnPreRender(self, context) if err != nil { return err } } var templateContext struct { Title string MetaDescription string MetaViewport string Head string PreCSS string CSS string PostCSS string DynamicStyle string HeadScripts string DynamicHeadScripts string Scripts string DynamicScripts string Favicon16x16URL string Favicon57x57URL string Favicon72x72URL string Favicon114x114URL string Favicon129x129URL string Content string } if self.WriteTitle != nil { var buf bytes.Buffer err := self.WriteTitle(context, &buf) if err != nil { return err } templateContext.Title = html.EscapeString(buf.String()) } if self.WriteMetaDescription != nil { var buf bytes.Buffer err := self.WriteMetaDescription(context, &buf) if err != nil { return err } templateContext.MetaDescription = html.EscapeString(buf.String()) } metaViewport := self.MetaViewport if metaViewport == "" { metaViewport = Config.Page.DefaultMetaViewport } templateContext.MetaViewport = metaViewport writeHead := self.WriteHead if writeHead == nil { writeHead = Config.Page.DefaultWriteHead } if writeHead != nil { var buf bytes.Buffer err := writeHead(context, &buf) if err != nil { return err } templateContext.Head = buf.String() } //templateContext.Meta = self.Meta templateContext.Favicon16x16URL = self.Favicon16x16URL templateContext.Favicon57x57URL = self.Favicon57x57URL templateContext.Favicon72x72URL = self.Favicon72x72URL templateContext.Favicon114x114URL = self.Favicon114x114URL templateContext.Favicon129x129URL = self.Favicon129x129URL if self.WritePreCSS != nil { var buf bytes.Buffer if err = self.WritePreCSS(context, &buf); err != nil { return err } templateContext.PreCSS = buf.String() } if self.CSS != nil { templateContext.CSS = self.CSS.URL(context.PathArgs...) } else { templateContext.CSS = Config.Page.DefaultCSS } if self.WritePostCSS != nil { var buf bytes.Buffer if err = self.WritePostCSS(context, &buf); err != nil { return err } templateContext.PostCSS = buf.String() } writeHeadScripts := self.WriteHeadScripts if writeHeadScripts == nil { writeHeadScripts = Config.Page.DefaultWriteHeadScripts } if writeHeadScripts != nil { var buf bytes.Buffer if err = writeHeadScripts(context, &buf); err != nil { return err } templateContext.HeadScripts = buf.String() } writeScripts := self.WriteScripts if writeScripts == nil { writeScripts = Config.Page.DefaultWriteScripts } if writeScripts != nil { var buf bytes.Buffer if err = writeScripts(context, &buf); err != nil { return err } if Config.Page.PostWriteScripts != nil { if err = Config.Page.PostWriteScripts(context, &buf); err != nil { return err } } templateContext.Scripts = buf.String() } contentHtml := utils.NewXMLBuffer() if self.Content != nil { err = self.Content.Render(context, &contentHtml.XMLWriter) if err != nil { return err } } templateContext.Content = contentHtml.String() // Get dynamic style and scripts after self.Content.Render() // because they are added in Render() templateContext.DynamicStyle = context.dynamicStyle.String() templateContext.DynamicHeadScripts = context.dynamicHeadScripts.String() templateContext.DynamicScripts = context.dynamicScripts.String() self.Template.GetContext = TemplateContext(templateContext) return self.Template.Render(context, writer) }
// Pages and nil views will be registered with a trailing slash at their path // and a permanent redirect from the path without trailing slash // Nil views will be registered as NotFound404 // parentPath always ends with a slash func (self *ViewPath) initAndRegisterViewsRecursive(parentPath string) { if parentPath == "" || parentPath[len(parentPath)-1] != '/' { panic("Parent path must end with a slash: " + parentPath) } if parentPath != "/" && self.Name == "" && self.Args == 0 { panic("Sub path of " + parentPath + " with no Name and Args") } if self.Name != "" && !PathFragmentRegexp.MatchString(self.Name) { panic("Invalid characters in view.ViewPath.Name: " + self.Name) } if self.View != nil && utils.IsDeepNil(self.View) { panic("Nil value wrapped with non nil view.View under parentPath: " + parentPath) } addSlash := self.Args > 0 if self.View == nil { addSlash = true self.View = &NotFoundView{Message: "Invalid URL"} } else if _, isPage := self.View.(*Page); isPage { addSlash = true if self.Auth != nil { if self.NoAuth == nil && Config.LoginSignupPage != nil && *Config.LoginSignupPage != nil { self.NoAuth = IndirectURL(Config.LoginSignupPage) } } } path := parentPath + self.Name if self.Args > 0 { if self.Name != "" { path += "/" } for i := 0; i < self.Args; i++ { path += PathFragmentPattern + "/" } } if addSlash { if path[len(path)-1] != '/' { path += "/" } if path != "/" { web.Get(path[:len(path)-1], func(webContext *web.Context, args ...string) string { webContext.Redirect(http.StatusMovedPermanently, webContext.Request.RequestURI+"/") return "" }) } } if self.Args < 0 { panic("Negative Args at " + path) } if _, pathExists := viewsByPath[path]; pathExists { panic("View with path '" + path + "' already registered") } viewsByPath[path] = self.View if Config.Debug.PrintPaths { debug.Print(path) } //debug.Print(path) self.View.Init(self.View) if viewWithURL, ok := self.View.(ViewWithURL); ok { viewWithURL.SetPath(path) } htmlFunc := func(webContext *web.Context, args ...string) string { // See: http://groups.google.com/group/golang-nuts/browse_thread/thread/ab1971bb9459025d // Slows down the memory leak on 32 bit systems a little bit: defer func() { go runtime.GC() }() context := NewContext(webContext, self.View, args) for _, subdomain := range Config.RedirectSubdomains { if len(subdomain) > 0 { if subdomain[len(subdomain)-1] != '.' { subdomain += "." } host := context.Request.Host if strings.Index(host, subdomain) == 0 { host = host[len(subdomain):] url := "http://" + host + context.Request.URL.Path context.Redirect(http.StatusMovedPermanently, url) return "" } } } handleErr := func(err error) string { switch err.(type) { case NotFound: context.NotFound(err.Error()) case Redirect: if Config.Debug.PrintRedirects { fmt.Printf("%d Redirect: %s\n", http.StatusFound, err.Error()) } context.Redirect(http.StatusFound, err.Error()) case PermanentRedirect: if Config.Debug.PrintRedirects { fmt.Printf("%d Permanent Redirect: %s\n", http.StatusMovedPermanently, err.Error()) } context.Redirect(http.StatusMovedPermanently, err.Error()) case Forbidden: context.Abort(http.StatusForbidden, err.Error()) default: context.Abort(http.StatusInternalServerError, err.Error()) } return "" } handleNoAuth := func(err error) string { switch { case err != nil: return handleErr(err) case self.NoAuth != nil: from := url.QueryEscape(context.Request.RequestURI) to := self.NoAuth.URL(context.PathArgs...) + "?from=" + from return handleErr(Redirect(to)) } return handleErr(Forbidden("403 Forbidden: authentication required")) } if Config.OnPreAuth != nil { if err := Config.OnPreAuth(context); err != nil { return handleErr(err) } } if Config.GlobalAuth != nil { if ok, err := Config.GlobalAuth.Authenticate(context); !ok { return handleNoAuth(err) } } if self.Auth == nil { self.Auth = Config.FallbackAuth } if self.Auth != nil { if ok, err := self.Auth.Authenticate(context); !ok { return handleNoAuth(err) } } // numMiddlewares := len(Config.Middlewares) // for i := 0; i < numMiddlewares; i++ { // if abort := Config.Middlewares[i].PreRender(context); abort { // return "" // } // } xmlBuffer := utils.NewXMLBuffer() err := self.View.Render(context, &xmlBuffer.XMLWriter) // for i := numMiddlewares - 1; i >= 0; i-- { // html, err = Config.Middlewares[i].PostRender(context, html, err) // } if err != nil { return handleErr(err) } return xmlBuffer.String() } web.Get(path, htmlFunc) web.Post(path, htmlFunc) for i := range self.Sub { self.Sub[i].initAndRegisterViewsRecursive(path) } }