func (this *FileDownloadView) Publish(ctxt *web.Context) (err error) { var file *os.File if file, err = os.Open(this.FilePath); err == nil { defer file.Close() fbase := path.Base(this.FilePath) if this.FileName == "" { this.FileName = fbase } header := ctxt.Response.Header() header.Set("Content-Type", this.ContentType(ctxt)) header.Set("Content-Disposition", fmt.Sprintf(`attachment; filename="%s"`, this.FileName)) var modtime time.Time if stat, err := file.Stat(); err == nil { modtime = stat.ModTime() } http.ServeContent(ctxt.Response, ctxt.Request, fbase, modtime, file) } else { ctxt.SetErrorCode(404) } return }
func (this *DynamicHandler) GetControlManager(context *web.Context) (cm *controller.ControlManager) { this.mutex.RLock() var mod, control, act string = this.module, this.controller, this.action this.mutex.RUnlock() var acterr error var action string // if mod is not found, the default mod will be used // this allows user to use shortcut path // especially when there is only one mod if s, err := context.PData.String("module"); err == nil { if this.ctrlgroup.HasModule(s) || !this.ctrlgroup.HasController(mod, s) { mod = s } else { // controller.HasController(mod, s) == true // move {action} to UPath, {controller} to {action}, {mod} to {controller} if tmpact, err := context.PData.String("action"); err == nil { lenupath := len(context.UPath) + 1 tmpupath := make(web.UPath, lenupath) tmpupath[0] = tmpact copy(tmpupath[1:lenupath], context.UPath) context.UPath = tmpupath } if tmpctrl, err := context.PData.String("controller"); err == nil { context.PData["action"] = tmpctrl } context.PData["controller"] = s context.PData["module"] = mod } } if s, err := context.PData.String("controller"); err == nil { control = s } if action, acterr = context.PData.String("action"); acterr == nil { act = action } if act == "" { act = "_" } if ctrl := this.ctrlgroup.Controller(mod, control); ctrl != nil { // allows for shortcut action to index if acterr == nil && act != "_" && !ctrl.HasAction(act) && ctrl.HasAction("index") { act = "_" lenupath := len(context.UPath) + 1 tmpupath := make(web.UPath, lenupath) tmpupath[0] = action copy(tmpupath[1:lenupath], context.UPath) context.UPath = tmpupath delete(context.PData, "action") } cm = controller.NewControlManager(context, ctrl, act) } return }
func (this *HTMLHeadMiddleWare) View(ctxt *web.Context, vw mvc.View) { var head *HTMLHead if dview, ok := vw.(mvc.DataView); ok && ctxt.MapResourceValue("htmlhead", &head) == nil && head != nil { dview.SetData("Htmlhead_Title", head.Title()) dview.SetData("Htmlhead_Css", head.Css()) dview.SetData("Htmlhead_Scripts", head.Scripts()) } }
func (this JsonView) Publish(ctxt *web.Context) error { ctxt.SetHeader("Content-Type", "application/json; charset=utf-8") if this == nil || len(this) == 0 { ctxt.Response.Write([]byte{'{', '}'}) return nil } jsone := json.NewEncoder(ctxt.Response) if err := jsone.Encode(this.getEncodingInterface()); err != nil { return err } return nil }
func GetXReqMethod(ctxt *web.Context) ReqMethod { var xreq = ctxt.XMethod() switch xreq { case "POST": return REQMETHOD_POST case "PUT": return REQMETHOD_PUT case "DELETE": return REQMETHOD_DELETE default: } return REQMETHOD_GET }
func (this *ControllerHandler) GetControlManager(context *web.Context) (cm *controller.ControlManager) { var ( act string = this.action action string acterr error ) if action, acterr = context.PData.String("action"); acterr == nil { act = action } if act == "" { act = "_" } if acterr == nil && act != "_" && !this.controlmeta.HasAction(act) && this.controlmeta.HasAction("index") { act = "_" lenupath := len(context.UPath) + 1 tmpupath := make(web.UPath, lenupath) tmpupath[0] = action copy(tmpupath[1:lenupath], context.UPath) context.UPath = tmpupath delete(context.PData, "action") } cm = controller.NewControlManager(context, this.controlmeta, act) return }
func (this CsrfMiddleWare) View(ctxt *web.Context, vw mvc.View) { var csrftoken CsrfTokenGetter if ctxt.MapResourceValue("csrftoken", &csrftoken) == nil && csrftoken.context != nil { if dview, ok := vw.(mvc.DataView); ok { dview.SetData("Csrftoken_Value", csrftoken.Value()) dview.SetData("Csrftoken_Name", csrftoken.Name()) dview.SetData("Csrftoken_Formtoken", csrftoken.FormToken()) } if fview, ok := vw.(mvc.TmplView); ok { fview.SetViewFunc("URLWToken", func(path string) string { return csrftoken.URLWToken(path) }) fview.SetViewFunc("URLWTokenQ", csrftoken.URLWToken) } } }
func (this *HTMLHeadMiddleWare) Body(ctxt *web.Context) { head := &HTMLHead{ cssbatch: this.cssbatch, scriptbatch: this.scriptbatch, css: make([]string, 0, 1), scripts: make([]string, 0, 1), addedcss: make([]string, 0, 1), addedscript: make([]string, 0, 1), } ctxt.SetResource("htmlhead", head) ctxt.SetTitle_ = head.SetTitle if this.defaultTitle != "" { head.SetTitle(this.defaultTitle) } if this.defaultCss != nil && len(this.defaultCss) > 0 { head.AddCss(this.defaultCss...) } if this.defaultScripts != nil && len(this.defaultScripts) > 0 { head.AddScript(this.defaultScripts...) } }
func (this *ResultView) Render(ctxt *web.Context) (b []byte, err error) { if tmpl, ext, err := this.getTmpl(mvc.GetMvcMeta(ctxt)); err == nil { buf := &bytes.Buffer{} var jsonp string if ext == ".jsonp" { jsonp = ctxt.RequestValue("callback") if jsonp == "" { jsonp = ctxt.RequestValue("jsonp") } jsonp = strings.TrimSpace(jsonp) } if jsonp != "" { writeJsonpStart(jsonp, buf) } tmpl.Execute(buf, this.VM) if jsonp != "" { writeJsonpEnd(jsonp, buf) } b = buf.Bytes() } return }
func (this CacheMiddleWare) Request(ctxt *web.Context) { switch this.profile { case CACHE_PROFILE_NOCACHE: ctxt.PrivateNoCache() case CACHE_PROFILE_NOSTORE: ctxt.PrivateNoStore() case CACHE_PROFILE_PUBLIC: ctxt.PublicCache(0) } }
func (this *SunnyApp) ServeRequestedEndPoint(w http.ResponseWriter, r *http.Request, rep *router.RequestedEndPoint) { atomic.AddInt32(&this.runners, 1) defer this.decrunners() if atomic.LoadInt32(&this.closed) == 1 || w == nil || r == nil { return } sw := &SunnyResponseWriter{ Status: 200, ResponseWriter: w, midwares: nil, } w = sw var sunctxt *web.Context if rep == nil { goto notfound } defer func() { if err := recover(); err != nil { if re, ok := err.(web.Redirection); ok { this.triggerevent(sunctxt, "redirect", map[string]interface{}{"redirection": re}) } else if e, ok := err.(web.ContextError); ok { this.triggerevent(sunctxt, "contexterror", map[string]interface{}{"context.error": e}) handler.ErrorHtml(w, r, e.Code()) } else { log.Println(err) this.triggererror(sunctxt, err) } } if sunctxt != nil { log.Println(fmt.Sprintf("ip: %s; r: %s %s; d: %s; %d", sunctxt.RemoteAddress().String(), r.Method, r.URL.Path, time.Since(sunctxt.StartTime()).String(), w.(*SunnyResponseWriter).Status)) sunctxt.Close() } if r.MultipartForm != nil { r.MultipartForm.RemoveAll() } }() sunctxt = web.NewSunnyContext(w, r, this.id) sunctxt.Event = this.ev.NewSubRouter(event.M{"sunny.context": sunctxt}) sunctxt.UPath = rep.UPath sunctxt.PData = rep.PData sunctxt.Ext = rep.Ext sunctxt.MaxFileSize = this.MaxFileSize sunctxt.ParseRequestData() sw.ctxt = sunctxt for n, f := range this.resources { sunctxt.SetResource(n, f()) } for _, midware := range this.MiddleWares { midware.Request(sunctxt) defer midware.Cleanup(sunctxt) } if router.HandleHeaders(sunctxt, rep.EndPoint, rep.Handler) { return } sw.midwares = this.mwareresp for _, midware := range this.MiddleWares { midware.Body(sunctxt) } if ctrl, ok := rep.Handler.(controller.ControlHandler); ok { ctrlmgr := ctrl.GetControlManager(sunctxt) if ctrlmgr == nil { goto notfound } sunctxt.Module = ctrlmgr.ModuleName() sunctxt.Controller = ctrlmgr.ControllerName() sunctxt.Action = ctrlmgr.ActionName() if err := sunctxt.WaitRequestData(); err != nil { setreqerror(err, w) return } // TODO: Controller should not matter which is called first.. // make it a goroutine once determined sunctxt and ctrlmgr is completely thread-safe for _, midware := range this.MiddleWares { midware.Controller(sunctxt, ctrlmgr) } state, vw := ctrlmgr.PrepareAndExecute() defer ctrlmgr.Cleanup() if vw != nil && !sunctxt.IsRedirecting() && !sunctxt.HasError() { setFuncMap(sunctxt, vw) // TODO: View should not matter which is called first.. // make it a goroutine once determined sunctxt and ctrlmgr is completely thread-safe for _, midware := range this.MiddleWares { midware.View(sunctxt, vw) } if err := ctrlmgr.PublishView(); err != nil { log.Println(err) } } if sunctxt.HasError() { this.triggerevent(sunctxt, "contexterror", map[string]interface{}{"context.error": sunctxt.AppError()}) handler.ErrorHtml(w, r, sunctxt.ErrorCode()) } else if sunctxt.IsRedirecting() { this.triggerevent(sunctxt, "redirect", map[string]interface{}{"redirection": sunctxt.Redirection()}) } else if state != -1 && (state < 200 || state >= 300) { handler.ErrorHtml(w, r, state) } } else { if err := sunctxt.WaitRequestData(); err != nil { setreqerror(err, w) return } if h, ok := rep.Handler.(web.ContextHandler); ok { h.ServeContextHTTP(sunctxt) } else { rep.Handler.ServeHTTP(w, r) } } return notfound: handler.NotFound(w, r) }
func (this *ResultView) Publish(ctxt *web.Context) (err error) { names := mvc.GetMvcMeta(ctxt) if names[mvc.MVC_ACTION] == "" { names[mvc.MVC_ACTION] = "_" } var tmpl *template.Template var ext string /* var mc = memcache.New("127.0.0.1:11211") var item *memcache.Item if item, err = mc.Get(ctxt.Request.RequestURI); err == nil { ctxt.SetHeader("Content-Type", GetContentType(ext)) if ctxt.ReqHeaderHas("Accept-Encoding", "gzip") { ctxt.SetHeader("Content-Encoding", "gzip") } ctxt.Response.Write(item.Value) return } */ tmpl, ext, err = this.getTmpl(names) if err == nil { var isjsonp bool var jsonp string var method = ctxt.Method() if ext == ".jsonp" { jsonp = ctxt.RequestValue("callback") if jsonp == "" { jsonp = ctxt.RequestValue("jsonp") } if (method == "GET" || method == "HEAD") && jsonp != "" && ext == ".jsonp" && validate.IsJSONPCallback(jsonp) { ctxt.SetHeader("Content-Type", "application/javascript") ctxt.SetHeader("Content-Disposition", "attachment; filename=jsonp.jsonp") ctxt.SetHeader("X-Content-Type-Options", "nosniff") isjsonp = true } else { err = errors.New("Invalid jsonp callback") log.Println(err) ctxt.SetErrorCode(403) return } } else { ctxt.SetHeader("Content-Type", GetContentType(ext)) } if method != "HEAD" { var err error var b *bytes.Buffer = bytes.NewBuffer(make([]byte, 0, 5120)) var tw io.Writer = io.MultiWriter(ctxt.Response, b) var gzipwriter *gzip.Writer if ctxt.ReqHeaderHas("Accept-Encoding", "gzip") { ctxt.SetHeader("Content-Encoding", "gzip") gzipwriter, _ = gzip.NewWriterLevel(tw, gzip.BestSpeed) tw = gzipwriter } ctxt.SetHeader("Vary", "Accept-Encoding") ctxt.Response.WriteHeader(200) if isjsonp { writeJsonpStart(jsonp, tw) } err = tmpl.Execute(tw, this.VM) if err != nil { // Header already sent... multiple write headers //panic(err) log.Println(err) } if isjsonp { writeJsonpEnd(jsonp, tw) } if gzipwriter != nil { gzipwriter.Close() } //mc.Set(&memcache.Item{Key: ctxt.Request.RequestURI, Value: b.Bytes(), Expiration: 3600}) if flushw, ok := ctxt.RootResponse().(http.Flusher); ok { flushw.Flush() } } else { ctxt.Response.WriteHeader(200) } } else { log.Println(err) ctxt.SetErrorCode(500) } return }
// TODO: refactor this func setFuncMap(sunctxt *web.Context, vw mvc.View) { if fview, ok := vw.(mvc.TmplView); ok { fview.SetViewFunc("URLQ", sunctxt.URL) fview.SetViewFunc("URL", func(s string) string { return sunctxt.URL(s) }) fview.SetViewFunc("Request", func() *http.Request { return sunctxt.Request }) fview.SetViewFunc("QueryStr", sunctxt.QueryStr) fview.SetViewFunc("TimeNow", sunctxt.StartTime) fview.SetViewFunc("Nl2br", func(s string) template.HTML { s = strings.Replace(s, "\r\n", "\n", -1) s = strings.Replace(s, "\r", "\n", -1) return template.HTML(strings.Replace(template.HTMLEscapeString(s), "\n", "<br>\n", -1)) }) fview.SetViewFunc("SelectOption", func(selected ...string) template.HTMLAttr { if len(selected) == 2 && selected[0] == selected[1] { return " selected " } return "" }) fview.SetViewFunc("SelectMultiOption", func(value []string, selected string) template.HTMLAttr { if validate.IsIn(selected, value...) { return " selected " } return "" }) fview.SetViewFunc("CheckOption", func(selected ...string) template.HTMLAttr { if len(selected) == 2 && selected[0] == selected[1] { return " checked " } return "" }) fview.SetViewFunc("RawHtml", func(s string) template.HTML { return template.HTML(s) }) fview.SetViewFunc("User", func() interface{} { if sunctxt.Session != nil { return sunctxt.Session.AuthUser() } return nil }) fview.SetViewFunc("Session", func() web.SessionManager { if sunctxt.Session != nil { return sunctxt.Session } return nil }) fview.SetViewFunc("Json", func(i interface{}) template.HTML { b, _ := json.Marshal(i) return template.HTML(b) }) fview.SetViewFunc("Implode", func(join string, slice []string) template.HTML { buf := bytes.Buffer{} for _, s := range slice { buf.WriteString(template.HTMLEscapeString(s)) buf.WriteString(join) } if len(slice) > 0 { buf.Truncate(buf.Len() - len(join)) } return template.HTML(buf.String()) }) fview.SetViewFunc("Flashes", sunctxt.AllFlashes) fview.SetViewFunc("CropText", func(s string, l int) string { if len(s) > l { s = s[:l-3] + "..." } return s }) fview.SetViewFunc("IRange", func(i ...int) (arr []int) { count := len(i) switch count { case 0: arr = make([]int, 0) case 1: arr = make([]int, i[0]+1) for k := range arr { arr[k] = k } case 2: arr = make([]int, int(math.Abs(float64(i[1]-i[0])))+1) if i[0] > i[1] { for k := range arr { arr[k] = i[0] i[0]-- } } else { for k := range arr { arr[k] = i[0] i[0]++ } } case 3: if i[0] > i[1] { i[1] = i[1] - 1 } else { i[1] = i[1] + 1 } size := (float64(i[1]) - float64(i[0])) / float64(i[2]) if size < 0 { return } arr = make([]int, int(math.Floor(size+0.5))) for k := range arr { arr[k] = i[0] i[0] = i[0] + i[2] } } return }) fview.SetViewFunc("Limit", func(slice interface{}, limit int) interface{} { refslice := reflect.ValueOf(slice) if (refslice.Kind() == reflect.Slice || refslice.Kind() == reflect.Array) && refslice.Cap() > limit { slice = refslice.Slice(0, limit).Interface() } return slice }) fview.SetViewFunc("Add", func(num1 int, num2 int) int { return num1 + num2 }) fview.SetViewFunc("Sub", func(num1 int, num2 int) int { return num1 - num2 }) } }
func (this *HtmlView) Publish(ctxt *web.Context) (err error) { names := mvc.GetMvcMeta(ctxt) if names[mvc.MVC_ACTION] == "" { names[mvc.MVC_ACTION] = "_" } var tmpl *template.Template tmpl, err = this.getTmpl(names) if err == nil { var method = ctxt.Method() ctxt.SetHeader("Content-Type", "text/html; charset=utf-8") if method != "HEAD" { var err error var tw io.Writer = ctxt.Response var gzipwriter *gzip.Writer if ctxt.ReqHeaderHas("Accept-Encoding", "gzip") { ctxt.SetHeader("Content-Encoding", "gzip") gzipwriter, _ = gzip.NewWriterLevel(ctxt.Response, gzip.BestSpeed) tw = gzipwriter } ctxt.SetHeader("Vary", "Accept-Encoding") ctxt.Response.WriteHeader(200) err = tmpl.Execute(tw, this.VM) if err != nil { // Header already sent... multiple write headers //panic(err) log.Println(err) } if gzipwriter != nil { gzipwriter.Close() } if flushw, ok := ctxt.Response.(http.Flusher); ok { flushw.Flush() } } else { ctxt.Response.WriteHeader(200) } } else { log.Println(err) ctxt.SetErrorCode(500) } return }
func (this CsrfMiddleWare) Controller(ctxt *web.Context, _ *controller.ControlManager) { token := csrfgate.CSRFToken(ctxt.Response, ctxt.Request) csrftoken := CsrfTokenGetter{context: ctxt, token: token} ctxt.SetResource("csrftoken", csrftoken) }
func (this *WebSocketHandler) ServeContextHTTP(context *web.Context) { var ctrlmgr *controller.ControlManager = controller.NewControlManager(context, this.ctrl, "_") if err := context.ToWebSocket(nil, nil); err != nil { context.RaiseAppError("Unable to upgrade to websocket: " + err.Error()) } defer func() { if err := recover(); err != nil { log.Println(err) } }() ctrlmgr.Prepare() var ( ctrler = ctrlmgr.Controller() listen = &methMeta{method: ctrler.MethodByName("Listen_")} methods = make(map[string]*methMeta) meth *methMeta ok bool t reflect.Type ) if listen.method.IsValid() { t = listen.method.Type() if t.NumIn() != 2 || t.In(0) != intType || t.In(1) != retbType { listen.method = reflect.Value{} } } listen.rettype = getRetType(listen.method, t) listen.isvalid = listen.method.IsValid() for { msgT, p, err := context.WebSocket.ReadMessage() if err != nil { if m := ctrler.MethodByName("Error_"); m.IsValid() && m.Type().NumIn() == 1 && m.Type().In(0) == errType { m.Call([]reflect.Value{reflect.ValueOf(err)}) } break } if this.allowcmd && msgT == websocket.TextMessage && len(p) > 0 && p[0] == '/' { args := WSArgs(argSplit.Split(strings.TrimSpace(string(p[1:len(p)])), -1)) cmd := strings.Replace(strings.Title(args[0]), "-", "_", -1) if cmd[len(cmd)-1] != '_' && validCmd.MatchString(cmd) { args = args[1:len(args)] if meth, ok = methods[cmd]; !ok { m := ctrler.MethodByName(cmd) if m.IsValid() { t = m.Type() if t.NumIn() != 1 || t.In(0) != argsType { m = reflect.Value{} } meth = &methMeta{ method: m, rettype: getRetType(m, t), isvalid: m.IsValid(), } } else { meth = &methMeta{ method: m, rettype: 0, isvalid: false, } } methods[cmd] = meth } if meth.isvalid { write(meth, context.WebSocket, meth.method.Call([]reflect.Value{reflect.ValueOf(args)})) continue } } } if listen.isvalid { write(listen, context.WebSocket, listen.method.Call([]reflect.Value{reflect.ValueOf(msgT), reflect.ValueOf(p)})) } } }