// set condtion function // if cond return true can run this namespace, else can't // usage: // ns.Cond(func (ctx *context.Context) bool{ // if ctx.Input.Domain() == "api.beego.me" { // return true // } // return false // }) // Cond as the first filter func (n *Namespace) Cond(cond namespaceCond) *Namespace { fn := func(ctx *beecontext.Context) { if !cond(ctx) { middleware.Exception("405", ctx.ResponseWriter, ctx.Request, "Method not allowed") } } if v, ok := n.handlers.filters[BeforeRouter]; ok { mr := new(FilterRouter) mr.tree = NewTree() mr.pattern = "*" mr.filterFunc = fn mr.tree.AddRouter("*", true) n.handlers.filters[BeforeRouter] = append([]*FilterRouter{mr}, v...) } else { n.handlers.InsertFilter("*", BeforeRouter, fn) } return n }
// Implement http.Handler interface. func (p *ControllerRegistor) ServeHTTP(rw http.ResponseWriter, r *http.Request) { defer func() { if err := recover(); err != nil { if err == USERSTOPRUN { return } if _, ok := err.(middleware.HTTPException); ok { // catch intented errors, only for HTTP 4XX and 5XX } else { if RunMode == "dev" { if !RecoverPanic { panic(err) } else { if ErrorsShow { if handler, ok := middleware.ErrorMaps[fmt.Sprint(err)]; ok { handler(rw, r) return } } var stack string Critical("the request url is ", r.URL.Path) Critical("Handler crashed with error", err) for i := 1; ; i++ { _, file, line, ok := runtime.Caller(i) if !ok { break } Critical(file, line) stack = stack + fmt.Sprintln(file, line) } middleware.ShowErr(err, rw, r, stack) } } else { if !RecoverPanic { panic(err) } else { // in production model show all infomation if ErrorsShow { handler := p.getErrorHandler(fmt.Sprint(err)) handler(rw, r) return } else { Critical("the request url is ", r.URL.Path) Critical("Handler crashed with error", err) for i := 1; ; i++ { _, file, line, ok := runtime.Caller(i) if !ok { break } Critical(file, line) } } } } } } }() starttime := time.Now() requestPath := r.URL.Path var runrouter reflect.Type var findrouter bool var runMethod string params := make(map[string]string) w := &responseWriter{writer: rw} w.Header().Set("Server", BeegoServerName) // init context context := &beecontext.Context{ ResponseWriter: w, Request: r, Input: beecontext.NewInput(r), Output: beecontext.NewOutput(), } context.Output.Context = context context.Output.EnableGzip = EnableGzip if context.Input.IsWebsocket() { context.ResponseWriter = rw } // defined filter function do_filter := func(pos int) (started bool) { if p.enableFilter { if l, ok := p.filters[pos]; ok { for _, filterR := range l { if ok, p := filterR.ValidRouter(r.URL.Path); ok { context.Input.Params = p filterR.filterFunc(context) if w.started { return true } } } } } return false } // session init if SessionOn { context.Input.CruSession = GlobalSessions.SessionStart(w, r) defer func() { context.Input.CruSession.SessionRelease(w) }() } if !utils.InSlice(strings.ToLower(r.Method), HTTPMETHOD) { http.Error(w, "Method Not Allowed", 405) goto Admin } if do_filter(BeforeRouter) { goto Admin } //static file server for prefix, staticDir := range StaticDir { if r.URL.Path == "/favicon.ico" { file := staticDir + r.URL.Path http.ServeFile(w, r, file) w.started = true goto Admin } if strings.HasPrefix(r.URL.Path, prefix) { file := staticDir + r.URL.Path[len(prefix):] finfo, err := os.Stat(file) if err != nil { if RunMode == "dev" { Warn(err) } http.NotFound(w, r) goto Admin } //if the request is dir and DirectoryIndex is false then if finfo.IsDir() && !DirectoryIndex { middleware.Exception("403", rw, r, "403 Forbidden") goto Admin } //This block obtained from (https://github.com/smithfox/beego) - it should probably get merged into astaxie/beego after a pull request isStaticFileToCompress := false if StaticExtensionsToGzip != nil && len(StaticExtensionsToGzip) > 0 { for _, statExtension := range StaticExtensionsToGzip { if strings.HasSuffix(strings.ToLower(file), strings.ToLower(statExtension)) { isStaticFileToCompress = true break } } } if isStaticFileToCompress { if EnableGzip { w.contentEncoding = GetAcceptEncodingZip(r) } memzipfile, err := OpenMemZipFile(file, w.contentEncoding) if err != nil { return } w.InitHeadContent(finfo.Size()) http.ServeContent(w, r, file, finfo.ModTime(), memzipfile) } else { http.ServeFile(w, r, file) } w.started = true goto Admin } } if do_filter(AfterStatic) { goto Admin } if CopyRequestBody { context.Input.Body() } //first find path from the fixrouters to Improve Performance for _, route := range p.fixrouters { n := len(requestPath) if requestPath == route.pattern { runMethod = p.getRunMethod(r.Method, context, route) if runMethod != "" { runrouter = route.controllerType findrouter = true break } } // pattern /admin url /admin 200 /admin/ 200 // pattern /admin/ url /admin 301 /admin/ 200 if requestPath[n-1] != '/' && requestPath+"/" == route.pattern { http.Redirect(w, r, requestPath+"/", 301) goto Admin } if requestPath[n-1] == '/' && route.pattern+"/" == requestPath { runMethod = p.getRunMethod(r.Method, context, route) if runMethod != "" { runrouter = route.controllerType findrouter = true break } } } //find regex's router if !findrouter { //find a matching Route for _, route := range p.routers { //check if Route pattern matches url if !route.regex.MatchString(requestPath) { continue } //get submatches (params) matches := route.regex.FindStringSubmatch(requestPath) //double check that the Route matches the URL pattern. if len(matches[0]) != len(requestPath) { continue } if len(route.params) > 0 { //add url parameters to the query param map values := r.URL.Query() for i, match := range matches[1:] { values.Add(route.params[i], match) params[route.params[i]] = match } //reassemble query params and add to RawQuery r.URL.RawQuery = url.Values(values).Encode() } runMethod = p.getRunMethod(r.Method, context, route) if runMethod != "" { runrouter = route.controllerType context.Input.Params = params findrouter = true break } } } if !findrouter && p.enableAuto { // deal with url with diffirent ext // /controller/simple // /controller/simple.html // /controller/simple.json // /controller/simple.rss lastindex := strings.LastIndex(requestPath, "/") lastsub := requestPath[lastindex+1:] if subindex := strings.LastIndex(lastsub, "."); subindex != -1 { context.Input.Params[":ext"] = lastsub[subindex+1:] r.URL.Query().Add(":ext", lastsub[subindex+1:]) r.URL.RawQuery = r.URL.Query().Encode() requestPath = requestPath[:len(requestPath)-len(lastsub[subindex:])] } for cName, methodmap := range p.autoRouter { // if prev already find the router break if findrouter { break } if strings.ToLower(requestPath) == "/"+cName { http.Redirect(w, r, requestPath+"/", 301) goto Admin } // if there's no action, set the default action to index if strings.ToLower(requestPath) == "/"+cName+"/" { requestPath = requestPath + "index" } // if the request path start with controllerName if strings.HasPrefix(strings.ToLower(requestPath), "/"+cName+"/") { for mName, controllerType := range methodmap { if strings.ToLower(requestPath) == "/"+cName+"/"+strings.ToLower(mName) || (strings.HasPrefix(strings.ToLower(requestPath), "/"+cName+"/"+strings.ToLower(mName)) && requestPath[len("/"+cName+"/"+strings.ToLower(mName)):len("/"+cName+"/"+strings.ToLower(mName))+1] == "/") { runrouter = controllerType runMethod = mName findrouter = true //parse params otherurl := requestPath[len("/"+cName+"/"+strings.ToLower(mName)):] if len(otherurl) > 1 { plist := strings.Split(otherurl, "/") for k, v := range plist[1:] { context.Input.Params[strconv.Itoa(k)] = v } } break } } } } } //if no matches to url, throw a not found exception if !findrouter { middleware.Exception("404", rw, r, "") goto Admin } if findrouter { if r.Method == "POST" { r.ParseMultipartForm(MaxMemory) } //execute middleware filters if do_filter(BeforeExec) { goto Admin } //Invoke the request handler vc := reflect.New(runrouter) execController, ok := vc.Interface().(ControllerInterface) if !ok { panic("controller is not ControllerInterface") } //call the controller init function execController.Init(context, runrouter.Name(), runMethod, vc.Interface()) //if XSRF is Enable then check cookie where there has any cookie in the request's cookie _csrf if EnableXSRF { execController.XsrfToken() if r.Method == "POST" || r.Method == "DELETE" || r.Method == "PUT" || (r.Method == "POST" && (r.Form.Get("_method") == "delete" || r.Form.Get("_method") == "put")) { execController.CheckXsrfCookie() } } //call prepare function execController.Prepare() if !w.started { //exec main logic switch runMethod { case "Get": execController.Get() case "Post": execController.Post() case "Delete": execController.Delete() case "Put": execController.Put() case "Head": execController.Head() case "Patch": execController.Patch() case "Options": execController.Options() default: in := make([]reflect.Value, 0) method := vc.MethodByName(runMethod) method.Call(in) } //render template if !w.started && !context.Input.IsWebsocket() { if AutoRender { if err := execController.Render(); err != nil { panic(err) } } } } // finish all runrouter. release resource execController.Finish() //execute middleware filters if do_filter(AfterExec) { goto Admin } } Admin: do_filter(FinishRouter) //admin module record QPS if EnableAdmin { timeend := time.Since(starttime) if FilterMonitorFunc(r.Method, requestPath, timeend) { if runrouter != nil { go toolbox.StatisticsMap.AddStatistics(r.Method, requestPath, runrouter.Name(), timeend) } else { go toolbox.StatisticsMap.AddStatistics(r.Method, requestPath, "", timeend) } } } }
// Implement http.Handler interface. func (p *ControllerRegistor) ServeHTTP(rw http.ResponseWriter, r *http.Request) { defer p.recoverPanic(rw, r) starttime := time.Now() var runrouter reflect.Type var findrouter bool var runMethod string var routerInfo *controllerInfo w := &responseWriter{writer: rw} if RunMode == "dev" { w.Header().Set("Server", BeegoServerName) } // init context context := &beecontext.Context{ ResponseWriter: w, Request: r, Input: beecontext.NewInput(r), Output: beecontext.NewOutput(), } context.Output.Context = context context.Output.EnableGzip = EnableGzip var urlPath string if !RouterCaseSensitive { urlPath = strings.ToLower(r.URL.Path) } else { urlPath = r.URL.Path } // defined filter function do_filter := func(pos int) (started bool) { if p.enableFilter { if l, ok := p.filters[pos]; ok { for _, filterR := range l { if ok, p := filterR.ValidRouter(urlPath); ok { context.Input.Params = p filterR.filterFunc(context) if filterR.returnOnOutput && w.started { return true } } } } } return false } // filter wrong httpmethod if _, ok := HTTPMETHOD[r.Method]; !ok { http.Error(w, "Method Not Allowed", 405) goto Admin } // filter for static file if do_filter(BeforeStatic) { goto Admin } serverStaticRouter(context) if w.started { findrouter = true goto Admin } // session init if SessionOn { var err error context.Input.CruSession, err = GlobalSessions.SessionStart(w, r) if err != nil { Error(err) middleware.Exception("503", rw, r, "") return } defer func() { context.Input.CruSession.SessionRelease(w) }() } if r.Method != "GET" && r.Method != "HEAD" { if CopyRequestBody && !context.Input.IsUpload() { context.Input.CopyBody() } context.Input.ParseFormOrMulitForm(MaxMemory) } if do_filter(BeforeRouter) { goto Admin } if context.Input.RunController != nil && context.Input.RunMethod != "" { findrouter = true runMethod = context.Input.RunMethod runrouter = context.Input.RunController } if !findrouter { http_method := r.Method if http_method == "POST" && context.Input.Query("_method") == "PUT" { http_method = "PUT" } if http_method == "POST" && context.Input.Query("_method") == "DELETE" { http_method = "DELETE" } if t, ok := p.routers[http_method]; ok { runObject, p := t.Match(urlPath) if r, ok := runObject.(*controllerInfo); ok { routerInfo = r findrouter = true if splat, ok := p[":splat"]; ok { splatlist := strings.Split(splat, "/") for k, v := range splatlist { p[strconv.Itoa(k)] = v } } context.Input.Params = p } } } //if no matches to url, throw a not found exception if !findrouter { middleware.Exception("404", rw, r, "") goto Admin } if findrouter { //execute middleware filters if do_filter(BeforeExec) { goto Admin } isRunable := false if routerInfo != nil { if routerInfo.routerType == routerTypeRESTFul { if _, ok := routerInfo.methods[r.Method]; ok { isRunable = true routerInfo.runfunction(context) } else { middleware.Exception("405", rw, r, "Method Not Allowed") goto Admin } } else if routerInfo.routerType == routerTypeHandler { isRunable = true routerInfo.handler.ServeHTTP(rw, r) } else { runrouter = routerInfo.controllerType method := r.Method if r.Method == "POST" && context.Input.Query("_method") == "PUT" { method = "PUT" } if r.Method == "POST" && context.Input.Query("_method") == "DELETE" { method = "DELETE" } if m, ok := routerInfo.methods[method]; ok { runMethod = m } else if m, ok = routerInfo.methods["*"]; ok { runMethod = m } else { runMethod = method } } } // also defined runrouter & runMethod from filter if !isRunable { //Invoke the request handler vc := reflect.New(runrouter) execController, ok := vc.Interface().(ControllerInterface) if !ok { panic("controller is not ControllerInterface") } //call the controller init function execController.Init(context, runrouter.Name(), runMethod, vc.Interface()) //call prepare function execController.Prepare() //if XSRF is Enable then check cookie where there has any cookie in the request's cookie _csrf if EnableXSRF { execController.XsrfToken() if r.Method == "POST" || r.Method == "DELETE" || r.Method == "PUT" || (r.Method == "POST" && (context.Input.Query("_method") == "DELETE" || context.Input.Query("_method") == "PUT")) { execController.CheckXsrfCookie() } } execController.URLMapping() if !w.started { //exec main logic switch runMethod { case "GET": execController.Get() case "POST": execController.Post() case "DELETE": execController.Delete() case "PUT": execController.Put() case "HEAD": execController.Head() case "PATCH": execController.Patch() case "OPTIONS": execController.Options() default: if !execController.HandlerFunc(runMethod) { in := make([]reflect.Value, 0) method := vc.MethodByName(runMethod) method.Call(in) } } //render template if !w.started && context.Output.Status == 0 { if AutoRender { if err := execController.Render(); err != nil { panic(err) } } } } // finish all runrouter. release resource execController.Finish() } //execute middleware filters if do_filter(AfterExec) { goto Admin } } do_filter(FinishRouter) Admin: timeend := time.Since(starttime) //admin module record QPS if EnableAdmin { if FilterMonitorFunc(r.Method, r.URL.Path, timeend) { if runrouter != nil { go toolbox.StatisticsMap.AddStatistics(r.Method, r.URL.Path, runrouter.Name(), timeend) } else { go toolbox.StatisticsMap.AddStatistics(r.Method, r.URL.Path, "", timeend) } } } if RunMode == "dev" { var devinfo string if findrouter { if routerInfo != nil { devinfo = fmt.Sprintf("| % -10s | % -40s | % -16s | % -10s | % -40s |", r.Method, r.URL.Path, timeend.String(), "match", routerInfo.pattern) } else { devinfo = fmt.Sprintf("| % -10s | % -40s | % -16s | % -10s |", r.Method, r.URL.Path, timeend.String(), "match") } } else { devinfo = fmt.Sprintf("| % -10s | % -40s | % -16s | % -10s |", r.Method, r.URL.Path, timeend.String(), "notmatch") } if DefaultLogFilter == nil || !DefaultLogFilter.Filter(context) { Debug(devinfo) } } // Call WriteHeader if status code has been set changed if context.Output.Status != 0 { w.writer.WriteHeader(context.Output.Status) } }
// AutoRoute func (p *ControllerRegistor) ServeHTTP(rw http.ResponseWriter, r *http.Request) { defer func() { if err := recover(); err != nil { errstr := fmt.Sprint(err) if handler, ok := middleware.ErrorMaps[errstr]; ok && ErrorsShow { handler(rw, r) } else { if !RecoverPanic { // go back to panic panic(err) } else { var stack string Critical("Handler crashed with error", err) for i := 1; ; i++ { _, file, line, ok := runtime.Caller(i) if !ok { break } Critical(file, line) if RunMode == "dev" { stack = stack + fmt.Sprintln(file, line) } } if RunMode == "dev" { middleware.ShowErr(err, rw, r, stack) } } } } }() w := &responseWriter{writer: rw} w.Header().Set("Server", BeegoServerName) context := &beecontext.Context{ ResponseWriter: w, Request: r, Input: beecontext.NewInput(r), Output: beecontext.NewOutput(w), } context.Output.Context = context context.Output.EnableGzip = EnableGzip if context.Input.IsWebsocket() { context.ResponseWriter = rw context.Output = beecontext.NewOutput(rw) } if SessionOn { context.Input.CruSession = GlobalSessions.SessionStart(w, r) } var runrouter *controllerInfo var findrouter bool params := make(map[string]string) if p.enableFilter { if l, ok := p.filters["BeforRouter"]; ok { for _, filterR := range l { if filterR.ValidRouter(r.URL.Path) { filterR.filterFunc(context) if w.started { return } } } } } //static file server for prefix, staticDir := range StaticDir { if r.URL.Path == "/favicon.ico" { file := staticDir + r.URL.Path http.ServeFile(w, r, file) w.started = true return } if strings.HasPrefix(r.URL.Path, prefix) { file := staticDir + r.URL.Path[len(prefix):] finfo, err := os.Stat(file) if err != nil { return } //if the request is dir and DirectoryIndex is false then if finfo.IsDir() && !DirectoryIndex { middleware.Exception("403", rw, r, "403 Forbidden") return } http.ServeFile(w, r, file) w.started = true return } } if p.enableFilter { if l, ok := p.filters["AfterStatic"]; ok { for _, filterR := range l { if filterR.ValidRouter(r.URL.Path) { filterR.filterFunc(context) if w.started { return } } } } } requestPath := r.URL.Path if CopyRequestBody { context.Input.Body() } //first find path from the fixrouters to Improve Performance for _, route := range p.fixrouters { n := len(requestPath) if requestPath == route.pattern { runrouter = route findrouter = true break } // pattern /admin url /admin 200 /admin/ 404 // pattern /admin/ url /admin 301 /admin/ 200 if requestPath[n-1] != '/' && len(route.pattern) == n+1 && route.pattern[n] == '/' && route.pattern[:n] == requestPath { http.Redirect(w, r, requestPath+"/", 301) return } } //find regex's router if !findrouter { //find a matching Route for _, route := range p.routers { //check if Route pattern matches url if !route.regex.MatchString(requestPath) { continue } //get submatches (params) matches := route.regex.FindStringSubmatch(requestPath) //double check that the Route matches the URL pattern. if len(matches[0]) != len(requestPath) { continue } if len(route.params) > 0 { //add url parameters to the query param map values := r.URL.Query() for i, match := range matches[1:] { values.Add(route.params[i], match) params[route.params[i]] = match } //reassemble query params and add to RawQuery r.URL.RawQuery = url.Values(values).Encode() } runrouter = route findrouter = true break } } context.Input.Param = params if runrouter != nil { if r.Method == "POST" { r.ParseMultipartForm(MaxMemory) } //execute middleware filters if p.enableFilter { if l, ok := p.filters["BeforExec"]; ok { for _, filterR := range l { if filterR.ValidRouter(r.URL.Path) { filterR.filterFunc(context) if w.started { return } } } } } //Invoke the request handler vc := reflect.New(runrouter.controllerType) //call the controller init function method := vc.MethodByName("Init") in := make([]reflect.Value, 3) in[0] = reflect.ValueOf(context) in[1] = reflect.ValueOf(runrouter.controllerType.Name()) in[2] = reflect.ValueOf(vc.Interface()) method.Call(in) //if XSRF is Enable then check cookie where there has any cookie in the request's cookie _csrf if EnableXSRF { in = make([]reflect.Value, 0) method = vc.MethodByName("XsrfToken") method.Call(in) if r.Method == "POST" || r.Method == "DELETE" || r.Method == "PUT" || (r.Method == "POST" && (r.Form.Get("_method") == "delete" || r.Form.Get("_method") == "put")) { method = vc.MethodByName("CheckXsrfCookie") method.Call(in) } } //call prepare function in = make([]reflect.Value, 0) method = vc.MethodByName("Prepare") method.Call(in) //if response has written,yes don't run next if !w.started { if r.Method == "GET" { if runrouter.hasMethod { if m, ok := runrouter.methods["get"]; ok { method = vc.MethodByName(m) } else if m, ok = runrouter.methods["*"]; ok { method = vc.MethodByName(m) } else { method = vc.MethodByName("Get") } } else { method = vc.MethodByName("Get") } method.Call(in) } else if r.Method == "HEAD" { if runrouter.hasMethod { if m, ok := runrouter.methods["head"]; ok { method = vc.MethodByName(m) } else if m, ok = runrouter.methods["*"]; ok { method = vc.MethodByName(m) } else { method = vc.MethodByName("Head") } } else { method = vc.MethodByName("Head") } method.Call(in) } else if r.Method == "DELETE" || (r.Method == "POST" && r.Form.Get("_method") == "delete") { if runrouter.hasMethod { if m, ok := runrouter.methods["delete"]; ok { method = vc.MethodByName(m) } else if m, ok = runrouter.methods["*"]; ok { method = vc.MethodByName(m) } else { method = vc.MethodByName("Delete") } } else { method = vc.MethodByName("Delete") } method.Call(in) } else if r.Method == "PUT" || (r.Method == "POST" && r.Form.Get("_method") == "put") { if runrouter.hasMethod { if m, ok := runrouter.methods["put"]; ok { method = vc.MethodByName(m) } else if m, ok = runrouter.methods["*"]; ok { method = vc.MethodByName(m) } else { method = vc.MethodByName("Put") } } else { method = vc.MethodByName("Put") } method.Call(in) } else if r.Method == "POST" { if runrouter.hasMethod { if m, ok := runrouter.methods["post"]; ok { method = vc.MethodByName(m) } else if m, ok = runrouter.methods["*"]; ok { method = vc.MethodByName(m) } else { method = vc.MethodByName("Post") } } else { method = vc.MethodByName("Post") } method.Call(in) } else if r.Method == "PATCH" { if runrouter.hasMethod { if m, ok := runrouter.methods["patch"]; ok { method = vc.MethodByName(m) } else if m, ok = runrouter.methods["*"]; ok { method = vc.MethodByName(m) } else { method = vc.MethodByName("Patch") } } else { method = vc.MethodByName("Patch") } method.Call(in) } else if r.Method == "OPTIONS" { if runrouter.hasMethod { if m, ok := runrouter.methods["options"]; ok { method = vc.MethodByName(m) } else if m, ok = runrouter.methods["*"]; ok { method = vc.MethodByName(m) } else { method = vc.MethodByName("Options") } } else { method = vc.MethodByName("Options") } method.Call(in) } gotofunc := vc.Elem().FieldByName("gotofunc").String() if gotofunc != "" { method = vc.MethodByName(gotofunc) if method.IsValid() { method.Call(in) } else { panic("gotofunc is exists:" + gotofunc) } } if !w.started && !context.Input.IsWebsocket() { if AutoRender { method = vc.MethodByName("Render") method.Call(in) } } } method = vc.MethodByName("Finish") method.Call(in) //execute middleware filters if p.enableFilter { if l, ok := p.filters["AfterExec"]; ok { for _, filterR := range l { if filterR.ValidRouter(r.URL.Path) { filterR.filterFunc(context) if w.started { return } } } } } method = vc.MethodByName("Destructor") method.Call(in) } //start autorouter if p.enableAuto { if !findrouter { lastindex := strings.LastIndex(requestPath, "/") lastsub := requestPath[lastindex+1:] if subindex := strings.LastIndex(lastsub, "."); subindex != -1 { context.Input.Param[":ext"] = lastsub[subindex+1:] r.URL.Query().Add(":ext", lastsub[subindex+1:]) r.URL.RawQuery = r.URL.Query().Encode() requestPath = requestPath[:len(requestPath)-len(lastsub[subindex:])] } for cName, methodmap := range p.autoRouter { if strings.ToLower(requestPath) == "/"+cName { http.Redirect(w, r, requestPath+"/", 301) return } if strings.ToLower(requestPath) == "/"+cName+"/" { requestPath = requestPath + "index" } if strings.HasPrefix(strings.ToLower(requestPath), "/"+cName+"/") { for mName, controllerType := range methodmap { if strings.HasPrefix(strings.ToLower(requestPath), "/"+cName+"/"+strings.ToLower(mName)) { if r.Method == "POST" { r.ParseMultipartForm(MaxMemory) } //execute middleware filters if p.enableFilter { if l, ok := p.filters["BeforExec"]; ok { for _, filterR := range l { if filterR.ValidRouter(r.URL.Path) { filterR.filterFunc(context) if w.started { return } } } } } //parse params otherurl := requestPath[len("/"+cName+"/"+strings.ToLower(mName)):] if len(otherurl) > 1 { plist := strings.Split(otherurl, "/") for k, v := range plist[1:] { params[strconv.Itoa(k)] = v } } //Invoke the request handler vc := reflect.New(controllerType) //call the controller init function init := vc.MethodByName("Init") in := make([]reflect.Value, 3) in[0] = reflect.ValueOf(context) in[1] = reflect.ValueOf(controllerType.Name()) in[2] = reflect.ValueOf(vc.Interface()) init.Call(in) //call prepare function in = make([]reflect.Value, 0) method := vc.MethodByName("Prepare") method.Call(in) method = vc.MethodByName(mName) method.Call(in) //if XSRF is Enable then check cookie where there has any cookie in the request's cookie _csrf if EnableXSRF { method = vc.MethodByName("XsrfToken") method.Call(in) if r.Method == "POST" || r.Method == "DELETE" || r.Method == "PUT" || (r.Method == "POST" && (r.Form.Get("_method") == "delete" || r.Form.Get("_method") == "put")) { method = vc.MethodByName("CheckXsrfCookie") method.Call(in) } } if !w.started && !context.Input.IsWebsocket() { if AutoRender { method = vc.MethodByName("Render") method.Call(in) } } method = vc.MethodByName("Finish") method.Call(in) //execute middleware filters if p.enableFilter { if l, ok := p.filters["AfterExec"]; ok { for _, filterR := range l { if filterR.ValidRouter(r.URL.Path) { filterR.filterFunc(context) if w.started { return } } } } } method = vc.MethodByName("Destructor") method.Call(in) // set find findrouter = true goto Last } } } } } } Last: //if no matches to url, throw a not found exception if !findrouter { middleware.Exception("404", rw, r, "") } }
func serverStaticRouter(ctx *context.Context) { requestPath := path.Clean(ctx.Input.Request.URL.Path) for prefix, staticDir := range StaticDir { if len(prefix) == 0 { continue } if requestPath == "/favicon.ico" { file := path.Join(staticDir, requestPath) if utils.FileExists(file) { http.ServeFile(ctx.ResponseWriter, ctx.Request, file) return } } if strings.HasPrefix(requestPath, prefix) { if len(requestPath) > len(prefix) && requestPath[len(prefix)] != '/' { continue } file := path.Join(staticDir, requestPath[len(prefix):]) finfo, err := os.Stat(file) if err != nil { if RunMode == "dev" { Warn(err) } http.NotFound(ctx.ResponseWriter, ctx.Request) return } //if the request is dir and DirectoryIndex is false then if finfo.IsDir() && !DirectoryIndex { middleware.Exception("403", ctx.ResponseWriter, ctx.Request, "403 Forbidden") return } //This block obtained from (https://github.com/smithfox/beego) - it should probably get merged into astaxie/beego after a pull request isStaticFileToCompress := false if StaticExtensionsToGzip != nil && len(StaticExtensionsToGzip) > 0 { for _, statExtension := range StaticExtensionsToGzip { if strings.HasSuffix(strings.ToLower(file), strings.ToLower(statExtension)) { isStaticFileToCompress = true break } } } if isStaticFileToCompress { var contentEncoding string if EnableGzip { contentEncoding = getAcceptEncodingZip(ctx.Request) } memzipfile, err := openMemZipFile(file, contentEncoding) if err != nil { return } if contentEncoding == "gzip" { ctx.Output.Header("Content-Encoding", "gzip") } else if contentEncoding == "deflate" { ctx.Output.Header("Content-Encoding", "deflate") } else { ctx.Output.Header("Content-Length", strconv.FormatInt(finfo.Size(), 10)) } http.ServeContent(ctx.ResponseWriter, ctx.Request, file, finfo.ModTime(), memzipfile) } else { http.ServeFile(ctx.ResponseWriter, ctx.Request, file) } return } } }
// AutoRoute func (p *ControllerRegistor) ServeHTTP(rw http.ResponseWriter, r *http.Request) { defer func() { if err := recover(); err != nil { if _, ok := err.(middleware.HTTPException); ok { // catch intented errors, only for HTTP 4XX and 5XX } else { if RunMode == "dev" { if !RecoverPanic { panic(err) } else { var stack string Critical("Handler crashed with error", err) for i := 1; ; i++ { _, file, line, ok := runtime.Caller(i) if !ok { break } Critical(file, line) stack = stack + fmt.Sprintln(file, line) } middleware.ShowErr(err, rw, r, stack) } } else { if ErrorsShow { handler := p.getErrorHandler(fmt.Sprint(err)) handler(rw, r) } else { if !RecoverPanic { panic(err) } else { Critical("Handler crashed with error", err) for i := 1; ; i++ { _, file, line, ok := runtime.Caller(i) if !ok { break } Critical(file, line) } } } } } } }() starttime := time.Now() requestPath := r.URL.Path var runrouter *controllerInfo var findrouter bool params := make(map[string]string) w := &responseWriter{writer: rw} w.Header().Set("Server", BeegoServerName) context := &beecontext.Context{ ResponseWriter: w, Request: r, Input: beecontext.NewInput(r), Output: beecontext.NewOutput(w), } context.Output.Context = context context.Output.EnableGzip = EnableGzip do_filter := func(pos int) (started bool) { if p.enableFilter { if l, ok := p.filters[pos]; ok { for _, filterR := range l { if ok, p := filterR.ValidRouter(r.URL.Path); ok { context.Input.Params = p filterR.filterFunc(context) if w.started { return true } } } } } return false } if context.Input.IsWebsocket() { context.ResponseWriter = rw context.Output = beecontext.NewOutput(rw) } if !utils.InSlice(strings.ToLower(r.Method), HTTPMETHOD) { http.Error(w, "Method Not Allowed", 405) goto Admin } if do_filter(BeforeRouter) { goto Admin } //static file server for prefix, staticDir := range StaticDir { if r.URL.Path == "/favicon.ico" { file := staticDir + r.URL.Path http.ServeFile(w, r, file) w.started = true goto Admin } if strings.HasPrefix(r.URL.Path, prefix) { file := staticDir + r.URL.Path[len(prefix):] finfo, err := os.Stat(file) if err != nil { if RunMode == "dev" { Warn(err) } http.NotFound(w, r) goto Admin } //if the request is dir and DirectoryIndex is false then if finfo.IsDir() && !DirectoryIndex { middleware.Exception("403", rw, r, "403 Forbidden") goto Admin } //This block obtained from (https://github.com/smithfox/beego) - it should probably get merged into astaxie/beego after a pull request isStaticFileToCompress := false if StaticExtensionsToGzip != nil && len(StaticExtensionsToGzip) > 0 { for _, statExtension := range StaticExtensionsToGzip { if strings.HasSuffix(strings.ToLower(file), strings.ToLower(statExtension)) { isStaticFileToCompress = true break } } } if isStaticFileToCompress { if EnableGzip { w.contentEncoding = GetAcceptEncodingZip(r) } memzipfile, err := OpenMemZipFile(file, w.contentEncoding) if err != nil { return } w.InitHeadContent(finfo.Size()) if strings.HasSuffix(file, ".mustache") { w.Header().Set("Content-Type", "text/html; charset=utf-8") //FIXME: hardcode } http.ServeContent(w, r, file, finfo.ModTime(), memzipfile) } else { http.ServeFile(w, r, file) } w.started = true goto Admin } } // session init after static file if SessionOn { context.Input.CruSession = GlobalSessions.SessionStart(w, r) } if do_filter(AfterStatic) { goto Admin } if CopyRequestBody { context.Input.Body() } //first find path from the fixrouters to Improve Performance for _, route := range p.fixrouters { n := len(requestPath) if requestPath == route.pattern { runrouter = route findrouter = true break } // pattern /admin url /admin 200 /admin/ 404 // pattern /admin/ url /admin 301 /admin/ 200 if requestPath[n-1] != '/' && len(route.pattern) == n+1 && route.pattern[n] == '/' && route.pattern[:n] == requestPath { http.Redirect(w, r, requestPath+"/", 301) goto Admin } } //find regex's router if !findrouter { //find a matching Route for _, route := range p.routers { //check if Route pattern matches url if !route.regex.MatchString(requestPath) { continue } //get submatches (params) matches := route.regex.FindStringSubmatch(requestPath) //double check that the Route matches the URL pattern. if len(matches[0]) != len(requestPath) { continue } if len(route.params) > 0 { //add url parameters to the query param map values := r.URL.Query() for i, match := range matches[1:] { values.Add(route.params[i], match) params[route.params[i]] = match } //reassemble query params and add to RawQuery r.URL.RawQuery = url.Values(values).Encode() } runrouter = route findrouter = true break } } context.Input.Params = params if runrouter != nil { if r.Method == "POST" { r.ParseMultipartForm(MaxMemory) } //execute middleware filters if do_filter(BeforeExec) { goto Admin } //Invoke the request handler vc := reflect.New(runrouter.controllerType) //call the controller init function method := vc.MethodByName("Init") in := make([]reflect.Value, 3) in[0] = reflect.ValueOf(context) in[1] = reflect.ValueOf(runrouter.controllerType.Name()) in[2] = reflect.ValueOf(vc.Interface()) method.Call(in) //if XSRF is Enable then check cookie where there has any cookie in the request's cookie _csrf if EnableXSRF { in = make([]reflect.Value, 0) method = vc.MethodByName("XsrfToken") method.Call(in) if r.Method == "POST" || r.Method == "DELETE" || r.Method == "PUT" || (r.Method == "POST" && (r.Form.Get("_method") == "delete" || r.Form.Get("_method") == "put")) { method = vc.MethodByName("CheckXsrfCookie") method.Call(in) } } //call prepare function in = make([]reflect.Value, 0) method = vc.MethodByName("Prepare") method.Call(in) //if response has written,yes don't run next if !w.started { if r.Method == "GET" { if runrouter.hasMethod { if m, ok := runrouter.methods["get"]; ok { method = vc.MethodByName(m) } else if m, ok = runrouter.methods["*"]; ok { method = vc.MethodByName(m) } else { method = vc.MethodByName("Get") } } else { method = vc.MethodByName("Get") } method.Call(in) } else if r.Method == "HEAD" { if runrouter.hasMethod { if m, ok := runrouter.methods["head"]; ok { method = vc.MethodByName(m) } else if m, ok = runrouter.methods["*"]; ok { method = vc.MethodByName(m) } else { method = vc.MethodByName("Head") } } else { method = vc.MethodByName("Head") } method.Call(in) } else if r.Method == "DELETE" || (r.Method == "POST" && r.Form.Get("_method") == "delete") { if runrouter.hasMethod { if m, ok := runrouter.methods["delete"]; ok { method = vc.MethodByName(m) } else if m, ok = runrouter.methods["*"]; ok { method = vc.MethodByName(m) } else { method = vc.MethodByName("Delete") } } else { method = vc.MethodByName("Delete") } method.Call(in) } else if r.Method == "PUT" || (r.Method == "POST" && r.Form.Get("_method") == "put") { if runrouter.hasMethod { if m, ok := runrouter.methods["put"]; ok { method = vc.MethodByName(m) } else if m, ok = runrouter.methods["*"]; ok { method = vc.MethodByName(m) } else { method = vc.MethodByName("Put") } } else { method = vc.MethodByName("Put") } method.Call(in) } else if r.Method == "POST" { if runrouter.hasMethod { if m, ok := runrouter.methods["post"]; ok { method = vc.MethodByName(m) } else if m, ok = runrouter.methods["*"]; ok { method = vc.MethodByName(m) } else { method = vc.MethodByName("Post") } } else { method = vc.MethodByName("Post") } method.Call(in) } else if r.Method == "PATCH" { if runrouter.hasMethod { if m, ok := runrouter.methods["patch"]; ok { method = vc.MethodByName(m) } else if m, ok = runrouter.methods["*"]; ok { method = vc.MethodByName(m) } else { method = vc.MethodByName("Patch") } } else { method = vc.MethodByName("Patch") } method.Call(in) } else if r.Method == "OPTIONS" { if runrouter.hasMethod { if m, ok := runrouter.methods["options"]; ok { method = vc.MethodByName(m) } else if m, ok = runrouter.methods["*"]; ok { method = vc.MethodByName(m) } else { method = vc.MethodByName("Options") } } else { method = vc.MethodByName("Options") } method.Call(in) } gotofunc := vc.Elem().FieldByName("gotofunc").String() if gotofunc != "" { method = vc.MethodByName(gotofunc) if method.IsValid() { method.Call(in) } else { panic("gotofunc is exists:" + gotofunc) } } if !w.started && !context.Input.IsWebsocket() { if AutoRender { method = vc.MethodByName("Render") callMethodWithError(method, in) } } } method = vc.MethodByName("Finish") method.Call(in) //execute middleware filters if do_filter(AfterExec) { goto Admin } method = vc.MethodByName("Destructor") method.Call(in) } //start autorouter if p.enableAuto { if !findrouter { lastindex := strings.LastIndex(requestPath, "/") lastsub := requestPath[lastindex+1:] if subindex := strings.LastIndex(lastsub, "."); subindex != -1 { context.Input.Params[":ext"] = lastsub[subindex+1:] r.URL.Query().Add(":ext", lastsub[subindex+1:]) r.URL.RawQuery = r.URL.Query().Encode() requestPath = requestPath[:len(requestPath)-len(lastsub[subindex:])] } for cName, methodmap := range p.autoRouter { if strings.ToLower(requestPath) == "/"+cName { http.Redirect(w, r, requestPath+"/", 301) goto Admin } if strings.ToLower(requestPath) == "/"+cName+"/" { requestPath = requestPath + "index" } if strings.HasPrefix(strings.ToLower(requestPath), "/"+cName+"/") { for mName, controllerType := range methodmap { if strings.ToLower(requestPath) == "/"+cName+"/"+strings.ToLower(mName) || (strings.HasPrefix(strings.ToLower(requestPath), "/"+cName+"/"+strings.ToLower(mName)) && requestPath[len("/"+cName+"/"+strings.ToLower(mName)):len("/"+cName+"/"+strings.ToLower(mName))+1] == "/") { if r.Method == "POST" { r.ParseMultipartForm(MaxMemory) } // set find findrouter = true //execute middleware filters if do_filter(BeforeExec) { goto Admin } //parse params otherurl := requestPath[len("/"+cName+"/"+strings.ToLower(mName)):] if len(otherurl) > 1 { plist := strings.Split(otherurl, "/") for k, v := range plist[1:] { params[strconv.Itoa(k)] = v } } //Invoke the request handler vc := reflect.New(controllerType) //call the controller init function init := vc.MethodByName("Init") in := make([]reflect.Value, 3) in[0] = reflect.ValueOf(context) in[1] = reflect.ValueOf(controllerType.Name()) in[2] = reflect.ValueOf(vc.Interface()) init.Call(in) //call prepare function in = make([]reflect.Value, 0) method := vc.MethodByName("Prepare") method.Call(in) method = vc.MethodByName(mName) method.Call(in) //if XSRF is Enable then check cookie where there has any cookie in the request's cookie _csrf if EnableXSRF { method = vc.MethodByName("XsrfToken") method.Call(in) if r.Method == "POST" || r.Method == "DELETE" || r.Method == "PUT" || (r.Method == "POST" && (r.Form.Get("_method") == "delete" || r.Form.Get("_method") == "put")) { method = vc.MethodByName("CheckXsrfCookie") method.Call(in) } } if !w.started && !context.Input.IsWebsocket() { if AutoRender { method = vc.MethodByName("Render") callMethodWithError(method, in) } } method = vc.MethodByName("Finish") method.Call(in) //execute middleware filters if do_filter(AfterExec) { goto Admin } method = vc.MethodByName("Destructor") method.Call(in) goto Admin } } } } } } //if no matches to url, throw a not found exception if !findrouter { middleware.Exception("404", rw, r, "") } Admin: do_filter(FinishRouter) //admin module record QPS if EnableAdmin { timeend := time.Since(starttime) if FilterMonitorFunc(r.Method, requestPath, timeend) { if runrouter != nil { go toolbox.StatisticsMap.AddStatistics(r.Method, requestPath, runrouter.controllerType.Name(), timeend) } else { go toolbox.StatisticsMap.AddStatistics(r.Method, requestPath, "", timeend) } } } }