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) }