1
0
mirror of https://github.com/astaxie/beego.git synced 2025-06-12 08:10:39 +00:00

use sync.Pool to reuse Context

This commit is contained in:
astaxie
2015-12-10 21:59:54 +08:00
parent f2edfbe7ae
commit f70f338025
6 changed files with 86 additions and 77 deletions

View File

@ -35,6 +35,14 @@ import (
"github.com/astaxie/beego/utils"
)
// NewContext return the Context with Input and Output
func NewContext() *Context {
return &Context{
Input: NewInput(),
Output: NewOutput(),
}
}
// Context Http request context struct including BeegoInput, BeegoOutput, http.Request and http.ResponseWriter.
// BeegoInput and BeegoOutput provides some api to operate request and response more easily.
type Context struct {
@ -45,6 +53,14 @@ type Context struct {
_xsrfToken string
}
// Reset init Context, BeegoInput and BeegoOutput
func (ctx *Context) Reset(rw http.ResponseWriter, r *http.Request) {
ctx.Request = r
ctx.ResponseWriter = rw
ctx.Input.Reset(ctx)
ctx.Output.Reset(ctx)
}
// Redirect does redirection to localurl with http header status code.
// It sends http response header directly.
func (ctx *Context) Redirect(status int, localurl string) {

View File

@ -18,7 +18,6 @@ import (
"bytes"
"errors"
"io/ioutil"
"net/http"
"net/url"
"reflect"
"regexp"
@ -39,37 +38,43 @@ var (
// BeegoInput operates the http request header, data, cookie and body.
// it also contains router params and current session.
type BeegoInput struct {
CruSession session.Store
Params map[string]string
Data map[interface{}]interface{} // store some values in this context when calling context in filter or controller.
Request *http.Request
RequestBody []byte
RunController reflect.Type
RunMethod string
Context *Context
CruSession session.Store
Params map[string]string
Data map[interface{}]interface{} // store some values in this context when calling context in filter or controller.
RequestBody []byte
}
// NewInput return BeegoInput generated by http.Request.
func NewInput(req *http.Request) *BeegoInput {
// NewInput return BeegoInput generated by Context.
func NewInput() *BeegoInput {
return &BeegoInput{
Params: make(map[string]string),
Data: make(map[interface{}]interface{}),
Request: req,
Params: make(map[string]string),
Data: make(map[interface{}]interface{}),
}
}
// Reset init the BeegoInput
func (input *BeegoInput) Reset(ctx *Context) {
input.Context = ctx
input.CruSession = nil
input.Params = make(map[string]string)
input.Data = make(map[interface{}]interface{})
input.RequestBody = []byte{}
}
// Protocol returns request protocol name, such as HTTP/1.1 .
func (input *BeegoInput) Protocol() string {
return input.Request.Proto
return input.Context.Request.Proto
}
// URI returns full request url with query string, fragment.
func (input *BeegoInput) URI() string {
return input.Request.RequestURI
return input.Context.Request.RequestURI
}
// URL returns request url path (without query string, fragment).
func (input *BeegoInput) URL() string {
return input.Request.URL.Path
return input.Context.Request.URL.Path
}
// Site returns base site url as scheme://domain type.
@ -79,10 +84,10 @@ func (input *BeegoInput) Site() string {
// Scheme returns request scheme as "http" or "https".
func (input *BeegoInput) Scheme() string {
if input.Request.URL.Scheme != "" {
return input.Request.URL.Scheme
if input.Context.Request.URL.Scheme != "" {
return input.Context.Request.URL.Scheme
}
if input.Request.TLS == nil {
if input.Context.Request.TLS == nil {
return "http"
}
return "https"
@ -97,19 +102,19 @@ func (input *BeegoInput) Domain() string {
// Host returns host name.
// if no host info in request, return localhost.
func (input *BeegoInput) Host() string {
if input.Request.Host != "" {
hostParts := strings.Split(input.Request.Host, ":")
if input.Context.Request.Host != "" {
hostParts := strings.Split(input.Context.Request.Host, ":")
if len(hostParts) > 0 {
return hostParts[0]
}
return input.Request.Host
return input.Context.Request.Host
}
return "localhost"
}
// Method returns http request method.
func (input *BeegoInput) Method() string {
return input.Request.Method
return input.Context.Request.Method
}
// Is returns boolean of this request is on given method, such as Is("POST").
@ -196,7 +201,7 @@ func (input *BeegoInput) IP() string {
rip := strings.Split(ips[0], ":")
return rip[0]
}
ip := strings.Split(input.Request.RemoteAddr, ":")
ip := strings.Split(input.Context.Request.RemoteAddr, ":")
if len(ip) > 0 {
if ip[0] != "[" {
return ip[0]
@ -236,7 +241,7 @@ func (input *BeegoInput) SubDomains() string {
// Port returns request client port.
// when error or empty, return 80.
func (input *BeegoInput) Port() int {
parts := strings.Split(input.Request.Host, ":")
parts := strings.Split(input.Context.Request.Host, ":")
if len(parts) == 2 {
port, _ := strconv.Atoi(parts[1])
return port
@ -262,22 +267,22 @@ func (input *BeegoInput) Query(key string) string {
if val := input.Param(key); val != "" {
return val
}
if input.Request.Form == nil {
input.Request.ParseForm()
if input.Context.Request.Form == nil {
input.Context.Request.ParseForm()
}
return input.Request.Form.Get(key)
return input.Context.Request.Form.Get(key)
}
// Header returns request header item string by a given string.
// if non-existed, return empty string.
func (input *BeegoInput) Header(key string) string {
return input.Request.Header.Get(key)
return input.Context.Request.Header.Get(key)
}
// Cookie returns request cookie item string by a given key.
// if non-existed, return empty string.
func (input *BeegoInput) Cookie(key string) string {
ck, err := input.Request.Cookie(key)
ck, err := input.Context.Request.Cookie(key)
if err != nil {
return ""
}
@ -292,10 +297,10 @@ func (input *BeegoInput) Session(key interface{}) interface{} {
// CopyBody returns the raw request body data as bytes.
func (input *BeegoInput) CopyBody() []byte {
requestbody, _ := ioutil.ReadAll(input.Request.Body)
input.Request.Body.Close()
requestbody, _ := ioutil.ReadAll(input.Context.Request.Body)
input.Context.Request.Body.Close()
bf := bytes.NewBuffer(requestbody)
input.Request.Body = ioutil.NopCloser(bf)
input.Context.Request.Body = ioutil.NopCloser(bf)
input.RequestBody = requestbody
return requestbody
}
@ -318,10 +323,10 @@ func (input *BeegoInput) SetData(key, val interface{}) {
func (input *BeegoInput) ParseFormOrMulitForm(maxMemory int64) error {
// Parse the body depending on the content type.
if strings.Contains(input.Header("Content-Type"), "multipart/form-data") {
if err := input.Request.ParseMultipartForm(maxMemory); err != nil {
if err := input.Context.Request.ParseMultipartForm(maxMemory); err != nil {
return errors.New("Error parsing request body:" + err.Error())
}
} else if err := input.Request.ParseForm(); err != nil {
} else if err := input.Context.Request.ParseForm(); err != nil {
return errors.New("Error parsing request body:" + err.Error())
}
return nil
@ -386,13 +391,13 @@ func (input *BeegoInput) bind(key string, typ reflect.Type) reflect.Value {
}
rv = input.bindBool(val, typ)
case reflect.Slice:
rv = input.bindSlice(&input.Request.Form, key, typ)
rv = input.bindSlice(&input.Context.Request.Form, key, typ)
case reflect.Struct:
rv = input.bindStruct(&input.Request.Form, key, typ)
rv = input.bindStruct(&input.Context.Request.Form, key, typ)
case reflect.Ptr:
rv = input.bindPoint(key, typ)
case reflect.Map:
rv = input.bindMap(&input.Request.Form, key, typ)
rv = input.bindMap(&input.Context.Request.Form, key, typ)
}
return rv
}

View File

@ -43,6 +43,12 @@ func NewOutput() *BeegoOutput {
return &BeegoOutput{}
}
// Reset init BeegoOutput
func (output *BeegoOutput) Reset(ctx *Context) {
output.Context = ctx
output.Status = 0
}
// Header sets response header item string via given key.
func (output *BeegoOutput) Header(key, val string) {
output.Context.ResponseWriter.Header().Set(key, val)
@ -55,7 +61,7 @@ func (output *BeegoOutput) Body(content []byte) {
var encoding string
var buf = &bytes.Buffer{}
if output.EnableGzip {
encoding = ParseEncoding(output.Context.Input.Request)
encoding = ParseEncoding(output.Context.Request)
}
if b, n, _ := WriteBody(encoding, buf, content); b {
output.Header("Content-Encoding", n)