mirror of
https://github.com/astaxie/beego.git
synced 2024-11-25 12:30:54 +00:00
recycling memory buffer in context
This commit is contained in:
parent
48cefc6767
commit
b8ed790858
@ -14,28 +14,28 @@ type BeegoInput struct {
|
|||||||
CruSession session.SessionStore
|
CruSession session.SessionStore
|
||||||
Params map[string]string
|
Params map[string]string
|
||||||
Data map[interface{}]interface{}
|
Data map[interface{}]interface{}
|
||||||
req *http.Request
|
Request *http.Request
|
||||||
RequestBody []byte
|
RequestBody []byte
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewInput(req *http.Request) *BeegoInput {
|
func NewInput(req *http.Request) *BeegoInput {
|
||||||
return &BeegoInput{
|
return &BeegoInput{
|
||||||
Params: make(map[string]string),
|
Params: make(map[string]string),
|
||||||
Data: make(map[interface{}]interface{}),
|
Data: make(map[interface{}]interface{}),
|
||||||
req: req,
|
Request: req,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (input *BeegoInput) Protocol() string {
|
func (input *BeegoInput) Protocol() string {
|
||||||
return input.req.Proto
|
return input.Request.Proto
|
||||||
}
|
}
|
||||||
|
|
||||||
func (input *BeegoInput) Uri() string {
|
func (input *BeegoInput) Uri() string {
|
||||||
return input.req.RequestURI
|
return input.Request.RequestURI
|
||||||
}
|
}
|
||||||
|
|
||||||
func (input *BeegoInput) Url() string {
|
func (input *BeegoInput) Url() string {
|
||||||
return input.req.URL.String()
|
return input.Request.URL.String()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (input *BeegoInput) Site() string {
|
func (input *BeegoInput) Site() string {
|
||||||
@ -43,9 +43,9 @@ func (input *BeegoInput) Site() string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (input *BeegoInput) Scheme() string {
|
func (input *BeegoInput) Scheme() string {
|
||||||
if input.req.URL.Scheme != "" {
|
if input.Request.URL.Scheme != "" {
|
||||||
return input.req.URL.Scheme
|
return input.Request.URL.Scheme
|
||||||
} else if input.req.TLS == nil {
|
} else if input.Request.TLS == nil {
|
||||||
return "http"
|
return "http"
|
||||||
} else {
|
} else {
|
||||||
return "https"
|
return "https"
|
||||||
@ -57,18 +57,18 @@ func (input *BeegoInput) Domain() string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (input *BeegoInput) Host() string {
|
func (input *BeegoInput) Host() string {
|
||||||
if input.req.Host != "" {
|
if input.Request.Host != "" {
|
||||||
hostParts := strings.Split(input.req.Host, ":")
|
hostParts := strings.Split(input.Request.Host, ":")
|
||||||
if len(hostParts) > 0 {
|
if len(hostParts) > 0 {
|
||||||
return hostParts[0]
|
return hostParts[0]
|
||||||
}
|
}
|
||||||
return input.req.Host
|
return input.Request.Host
|
||||||
}
|
}
|
||||||
return "localhost"
|
return "localhost"
|
||||||
}
|
}
|
||||||
|
|
||||||
func (input *BeegoInput) Method() string {
|
func (input *BeegoInput) Method() string {
|
||||||
return input.req.Method
|
return input.Request.Method
|
||||||
}
|
}
|
||||||
|
|
||||||
func (input *BeegoInput) Is(method string) bool {
|
func (input *BeegoInput) Is(method string) bool {
|
||||||
@ -88,7 +88,7 @@ func (input *BeegoInput) IsWebsocket() bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (input *BeegoInput) IsUpload() bool {
|
func (input *BeegoInput) IsUpload() bool {
|
||||||
return input.req.MultipartForm != nil
|
return input.Request.MultipartForm != nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (input *BeegoInput) IP() string {
|
func (input *BeegoInput) IP() string {
|
||||||
@ -96,7 +96,7 @@ func (input *BeegoInput) IP() string {
|
|||||||
if len(ips) > 0 && ips[0] != "" {
|
if len(ips) > 0 && ips[0] != "" {
|
||||||
return ips[0]
|
return ips[0]
|
||||||
}
|
}
|
||||||
ip := strings.Split(input.req.RemoteAddr, ":")
|
ip := strings.Split(input.Request.RemoteAddr, ":")
|
||||||
if len(ip) > 0 {
|
if len(ip) > 0 {
|
||||||
return ip[0]
|
return ip[0]
|
||||||
}
|
}
|
||||||
@ -120,7 +120,7 @@ func (input *BeegoInput) SubDomains() string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (input *BeegoInput) Port() int {
|
func (input *BeegoInput) Port() int {
|
||||||
parts := strings.Split(input.req.Host, ":")
|
parts := strings.Split(input.Request.Host, ":")
|
||||||
if len(parts) == 2 {
|
if len(parts) == 2 {
|
||||||
port, _ := strconv.Atoi(parts[1])
|
port, _ := strconv.Atoi(parts[1])
|
||||||
return port
|
return port
|
||||||
@ -140,16 +140,16 @@ func (input *BeegoInput) Param(key string) string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (input *BeegoInput) Query(key string) string {
|
func (input *BeegoInput) Query(key string) string {
|
||||||
input.req.ParseForm()
|
input.Request.ParseForm()
|
||||||
return input.req.Form.Get(key)
|
return input.Request.Form.Get(key)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (input *BeegoInput) Header(key string) string {
|
func (input *BeegoInput) Header(key string) string {
|
||||||
return input.req.Header.Get(key)
|
return input.Request.Header.Get(key)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (input *BeegoInput) Cookie(key string) string {
|
func (input *BeegoInput) Cookie(key string) string {
|
||||||
ck, err := input.req.Cookie(key)
|
ck, err := input.Request.Cookie(key)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
@ -161,10 +161,10 @@ func (input *BeegoInput) Session(key interface{}) interface{} {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (input *BeegoInput) Body() []byte {
|
func (input *BeegoInput) Body() []byte {
|
||||||
requestbody, _ := ioutil.ReadAll(input.req.Body)
|
requestbody, _ := ioutil.ReadAll(input.Request.Body)
|
||||||
input.req.Body.Close()
|
input.Request.Body.Close()
|
||||||
bf := bytes.NewBuffer(requestbody)
|
bf := bytes.NewBuffer(requestbody)
|
||||||
input.req.Body = ioutil.NopCloser(bf)
|
input.Request.Body = ioutil.NopCloser(bf)
|
||||||
input.RequestBody = requestbody
|
input.RequestBody = requestbody
|
||||||
return requestbody
|
return requestbody
|
||||||
}
|
}
|
||||||
|
@ -21,21 +21,18 @@ type BeegoOutput struct {
|
|||||||
Context *Context
|
Context *Context
|
||||||
Status int
|
Status int
|
||||||
EnableGzip bool
|
EnableGzip bool
|
||||||
res http.ResponseWriter
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewOutput(res http.ResponseWriter) *BeegoOutput {
|
func NewOutput() *BeegoOutput {
|
||||||
return &BeegoOutput{
|
return &BeegoOutput{}
|
||||||
res: res,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (output *BeegoOutput) Header(key, val string) {
|
func (output *BeegoOutput) Header(key, val string) {
|
||||||
output.res.Header().Set(key, val)
|
output.Context.ResponseWriter.Header().Set(key, val)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (output *BeegoOutput) Body(content []byte) {
|
func (output *BeegoOutput) Body(content []byte) {
|
||||||
output_writer := output.res.(io.Writer)
|
output_writer := output.Context.ResponseWriter.(io.Writer)
|
||||||
if output.EnableGzip == true && output.Context.Input.Header("Accept-Encoding") != "" {
|
if output.EnableGzip == true && output.Context.Input.Header("Accept-Encoding") != "" {
|
||||||
splitted := strings.SplitN(output.Context.Input.Header("Accept-Encoding"), ",", -1)
|
splitted := strings.SplitN(output.Context.Input.Header("Accept-Encoding"), ",", -1)
|
||||||
encodings := make([]string, len(splitted))
|
encodings := make([]string, len(splitted))
|
||||||
@ -46,12 +43,12 @@ func (output *BeegoOutput) Body(content []byte) {
|
|||||||
for _, val := range encodings {
|
for _, val := range encodings {
|
||||||
if val == "gzip" {
|
if val == "gzip" {
|
||||||
output.Header("Content-Encoding", "gzip")
|
output.Header("Content-Encoding", "gzip")
|
||||||
output_writer, _ = gzip.NewWriterLevel(output.res, gzip.BestSpeed)
|
output_writer, _ = gzip.NewWriterLevel(output.Context.ResponseWriter, gzip.BestSpeed)
|
||||||
|
|
||||||
break
|
break
|
||||||
} else if val == "deflate" {
|
} else if val == "deflate" {
|
||||||
output.Header("Content-Encoding", "deflate")
|
output.Header("Content-Encoding", "deflate")
|
||||||
output_writer, _ = flate.NewWriter(output.res, flate.BestSpeed)
|
output_writer, _ = flate.NewWriter(output.Context.ResponseWriter, flate.BestSpeed)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -104,7 +101,7 @@ func (output *BeegoOutput) Cookie(name string, value string, others ...interface
|
|||||||
if len(others) > 4 {
|
if len(others) > 4 {
|
||||||
fmt.Fprintf(&b, "; HttpOnly")
|
fmt.Fprintf(&b, "; HttpOnly")
|
||||||
}
|
}
|
||||||
output.res.Header().Add("Set-Cookie", b.String())
|
output.Context.ResponseWriter.Header().Add("Set-Cookie", b.String())
|
||||||
}
|
}
|
||||||
|
|
||||||
var cookieNameSanitizer = strings.NewReplacer("\n", "-", "\r", "-")
|
var cookieNameSanitizer = strings.NewReplacer("\n", "-", "\r", "-")
|
||||||
@ -129,7 +126,7 @@ func (output *BeegoOutput) Json(data interface{}, hasIndent bool, coding bool) e
|
|||||||
content, err = json.Marshal(data)
|
content, err = json.Marshal(data)
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
http.Error(output.res, err.Error(), http.StatusInternalServerError)
|
http.Error(output.Context.ResponseWriter, err.Error(), http.StatusInternalServerError)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if coding {
|
if coding {
|
||||||
@ -149,7 +146,7 @@ func (output *BeegoOutput) Jsonp(data interface{}, hasIndent bool) error {
|
|||||||
content, err = json.Marshal(data)
|
content, err = json.Marshal(data)
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
http.Error(output.res, err.Error(), http.StatusInternalServerError)
|
http.Error(output.Context.ResponseWriter, err.Error(), http.StatusInternalServerError)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
callback := output.Context.Input.Query("callback")
|
callback := output.Context.Input.Query("callback")
|
||||||
@ -174,7 +171,7 @@ func (output *BeegoOutput) Xml(data interface{}, hasIndent bool) error {
|
|||||||
content, err = xml.Marshal(data)
|
content, err = xml.Marshal(data)
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
http.Error(output.res, err.Error(), http.StatusInternalServerError)
|
http.Error(output.Context.ResponseWriter, err.Error(), http.StatusInternalServerError)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
output.Body(content)
|
output.Body(content)
|
||||||
@ -189,7 +186,7 @@ func (output *BeegoOutput) Download(file string) {
|
|||||||
output.Header("Expires", "0")
|
output.Header("Expires", "0")
|
||||||
output.Header("Cache-Control", "must-revalidate")
|
output.Header("Cache-Control", "must-revalidate")
|
||||||
output.Header("Pragma", "public")
|
output.Header("Pragma", "public")
|
||||||
http.ServeFile(output.res, output.Context.Request, file)
|
http.ServeFile(output.Context.ResponseWriter, output.Context.Request, file)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (output *BeegoOutput) ContentType(ext string) {
|
func (output *BeegoOutput) ContentType(ext string) {
|
||||||
@ -203,7 +200,7 @@ func (output *BeegoOutput) ContentType(ext string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (output *BeegoOutput) SetStatus(status int) {
|
func (output *BeegoOutput) SetStatus(status int) {
|
||||||
output.res.WriteHeader(status)
|
output.Context.ResponseWriter.WriteHeader(status)
|
||||||
output.Status = status
|
output.Status = status
|
||||||
}
|
}
|
||||||
|
|
||||||
|
67
router.go
67
router.go
@ -28,7 +28,6 @@ const (
|
|||||||
|
|
||||||
var (
|
var (
|
||||||
HTTPMETHOD = []string{"get", "post", "put", "delete", "patch", "options", "head"}
|
HTTPMETHOD = []string{"get", "post", "put", "delete", "patch", "options", "head"}
|
||||||
errorType = reflect.TypeOf((*error)(nil)).Elem()
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type controllerInfo struct {
|
type controllerInfo struct {
|
||||||
@ -41,19 +40,21 @@ type controllerInfo struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type ControllerRegistor struct {
|
type ControllerRegistor struct {
|
||||||
routers []*controllerInfo
|
routers []*controllerInfo
|
||||||
fixrouters []*controllerInfo
|
fixrouters []*controllerInfo
|
||||||
enableFilter bool
|
enableFilter bool
|
||||||
filters map[int][]*FilterRouter
|
filters map[int][]*FilterRouter
|
||||||
enableAuto bool
|
enableAuto bool
|
||||||
autoRouter map[string]map[string]reflect.Type //key:controller key:method value:reflect.type
|
autoRouter map[string]map[string]reflect.Type //key:controller key:method value:reflect.type
|
||||||
|
contextBuffer chan *beecontext.Context
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewControllerRegistor() *ControllerRegistor {
|
func NewControllerRegistor() *ControllerRegistor {
|
||||||
return &ControllerRegistor{
|
return &ControllerRegistor{
|
||||||
routers: make([]*controllerInfo, 0),
|
routers: make([]*controllerInfo, 0),
|
||||||
autoRouter: make(map[string]map[string]reflect.Type),
|
autoRouter: make(map[string]map[string]reflect.Type),
|
||||||
filters: make(map[int][]*FilterRouter),
|
filters: make(map[int][]*FilterRouter),
|
||||||
|
contextBuffer: make(chan *beecontext.Context, 100),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -433,15 +434,40 @@ func (p *ControllerRegistor) ServeHTTP(rw http.ResponseWriter, r *http.Request)
|
|||||||
|
|
||||||
w := &responseWriter{writer: rw}
|
w := &responseWriter{writer: rw}
|
||||||
w.Header().Set("Server", BeegoServerName)
|
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
|
|
||||||
|
|
||||||
|
// init context
|
||||||
|
var context *beecontext.Context
|
||||||
|
select {
|
||||||
|
case context = <-p.contextBuffer:
|
||||||
|
context.ResponseWriter = w
|
||||||
|
context.Request = r
|
||||||
|
context.Input.Request = r
|
||||||
|
default:
|
||||||
|
context = &beecontext.Context{
|
||||||
|
ResponseWriter: w,
|
||||||
|
Request: r,
|
||||||
|
Input: beecontext.NewInput(r),
|
||||||
|
Output: beecontext.NewOutput(),
|
||||||
|
}
|
||||||
|
context.Output.Context = context
|
||||||
|
context.Output.EnableGzip = EnableGzip
|
||||||
|
}
|
||||||
|
|
||||||
|
defer func() {
|
||||||
|
if context != nil {
|
||||||
|
select {
|
||||||
|
case p.contextBuffer <- context:
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
if context.Input.IsWebsocket() {
|
||||||
|
context.ResponseWriter = rw
|
||||||
|
context.Output = beecontext.NewOutput(rw)
|
||||||
|
}
|
||||||
|
|
||||||
|
// defined filter function
|
||||||
do_filter := func(pos int) (started bool) {
|
do_filter := func(pos int) (started bool) {
|
||||||
if p.enableFilter {
|
if p.enableFilter {
|
||||||
if l, ok := p.filters[pos]; ok {
|
if l, ok := p.filters[pos]; ok {
|
||||||
@ -460,11 +486,6 @@ func (p *ControllerRegistor) ServeHTTP(rw http.ResponseWriter, r *http.Request)
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
if context.Input.IsWebsocket() {
|
|
||||||
context.ResponseWriter = rw
|
|
||||||
context.Output = beecontext.NewOutput(rw)
|
|
||||||
}
|
|
||||||
|
|
||||||
// session init
|
// session init
|
||||||
if SessionOn {
|
if SessionOn {
|
||||||
context.Input.CruSession = GlobalSessions.SessionStart(w, r)
|
context.Input.CruSession = GlobalSessions.SessionStart(w, r)
|
||||||
|
Loading…
Reference in New Issue
Block a user