예제 #1
0
파일: namespace.go 프로젝트: kalbasit/beego
// 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
}
예제 #2
0
func serverStaticRouter(ctx *context.Context) {
	if ctx.Input.Method() != "GET" && ctx.Input.Method() != "HEAD" {
		return
	}
	requestPath := path.Clean(ctx.Input.Request.URL.Path)
	for prefix, staticDir := range StaticDir {
		if len(prefix) == 0 {
			continue
		}
		if requestPath == "/favicon.ico" || requestPath == "/robots.txt" {
			file := path.Join(staticDir, requestPath)
			if utils.FileExists(file) {
				http.ServeFile(ctx.ResponseWriter, ctx.Request, file)
				return
			} else {
				http.NotFound(ctx.ResponseWriter, ctx.Request)
				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
		}
	}
}
예제 #3
0
파일: router.go 프로젝트: kalbasit/beego
// 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

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

	// 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 {
		context.Input.CruSession = GlobalSessions.SessionStart(w, r)
		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 {
		if t, ok := p.routers[r.Method]; ok {
			runObject, p := t.Match(r.URL.Path)
			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" && (r.Form.Get("_method") == "delete" || r.Form.Get("_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")
		}
		Debug(devinfo)
	}

	// Call WriteHeader if status code has been set changed
	if context.Output.Status != 0 {
		w.writer.WriteHeader(context.Output.Status)
	}
}