b8ed7908 by astaxie

recycling memory buffer in context

1 parent 48cefc67
...@@ -14,7 +14,7 @@ type BeegoInput struct { ...@@ -14,7 +14,7 @@ type BeegoInput struct {
14 CruSession session.SessionStore 14 CruSession session.SessionStore
15 Params map[string]string 15 Params map[string]string
16 Data map[interface{}]interface{} 16 Data map[interface{}]interface{}
17 req *http.Request 17 Request *http.Request
18 RequestBody []byte 18 RequestBody []byte
19 } 19 }
20 20
...@@ -22,20 +22,20 @@ func NewInput(req *http.Request) *BeegoInput { ...@@ -22,20 +22,20 @@ func NewInput(req *http.Request) *BeegoInput {
22 return &BeegoInput{ 22 return &BeegoInput{
23 Params: make(map[string]string), 23 Params: make(map[string]string),
24 Data: make(map[interface{}]interface{}), 24 Data: make(map[interface{}]interface{}),
25 req: req, 25 Request: req,
26 } 26 }
27 } 27 }
28 28
29 func (input *BeegoInput) Protocol() string { 29 func (input *BeegoInput) Protocol() string {
30 return input.req.Proto 30 return input.Request.Proto
31 } 31 }
32 32
33 func (input *BeegoInput) Uri() string { 33 func (input *BeegoInput) Uri() string {
34 return input.req.RequestURI 34 return input.Request.RequestURI
35 } 35 }
36 36
37 func (input *BeegoInput) Url() string { 37 func (input *BeegoInput) Url() string {
38 return input.req.URL.String() 38 return input.Request.URL.String()
39 } 39 }
40 40
41 func (input *BeegoInput) Site() string { 41 func (input *BeegoInput) Site() string {
...@@ -43,9 +43,9 @@ func (input *BeegoInput) Site() string { ...@@ -43,9 +43,9 @@ func (input *BeegoInput) Site() string {
43 } 43 }
44 44
45 func (input *BeegoInput) Scheme() string { 45 func (input *BeegoInput) Scheme() string {
46 if input.req.URL.Scheme != "" { 46 if input.Request.URL.Scheme != "" {
47 return input.req.URL.Scheme 47 return input.Request.URL.Scheme
48 } else if input.req.TLS == nil { 48 } else if input.Request.TLS == nil {
49 return "http" 49 return "http"
50 } else { 50 } else {
51 return "https" 51 return "https"
...@@ -57,18 +57,18 @@ func (input *BeegoInput) Domain() string { ...@@ -57,18 +57,18 @@ func (input *BeegoInput) Domain() string {
57 } 57 }
58 58
59 func (input *BeegoInput) Host() string { 59 func (input *BeegoInput) Host() string {
60 if input.req.Host != "" { 60 if input.Request.Host != "" {
61 hostParts := strings.Split(input.req.Host, ":") 61 hostParts := strings.Split(input.Request.Host, ":")
62 if len(hostParts) > 0 { 62 if len(hostParts) > 0 {
63 return hostParts[0] 63 return hostParts[0]
64 } 64 }
65 return input.req.Host 65 return input.Request.Host
66 } 66 }
67 return "localhost" 67 return "localhost"
68 } 68 }
69 69
70 func (input *BeegoInput) Method() string { 70 func (input *BeegoInput) Method() string {
71 return input.req.Method 71 return input.Request.Method
72 } 72 }
73 73
74 func (input *BeegoInput) Is(method string) bool { 74 func (input *BeegoInput) Is(method string) bool {
...@@ -88,7 +88,7 @@ func (input *BeegoInput) IsWebsocket() bool { ...@@ -88,7 +88,7 @@ func (input *BeegoInput) IsWebsocket() bool {
88 } 88 }
89 89
90 func (input *BeegoInput) IsUpload() bool { 90 func (input *BeegoInput) IsUpload() bool {
91 return input.req.MultipartForm != nil 91 return input.Request.MultipartForm != nil
92 } 92 }
93 93
94 func (input *BeegoInput) IP() string { 94 func (input *BeegoInput) IP() string {
...@@ -96,7 +96,7 @@ func (input *BeegoInput) IP() string { ...@@ -96,7 +96,7 @@ func (input *BeegoInput) IP() string {
96 if len(ips) > 0 && ips[0] != "" { 96 if len(ips) > 0 && ips[0] != "" {
97 return ips[0] 97 return ips[0]
98 } 98 }
99 ip := strings.Split(input.req.RemoteAddr, ":") 99 ip := strings.Split(input.Request.RemoteAddr, ":")
100 if len(ip) > 0 { 100 if len(ip) > 0 {
101 return ip[0] 101 return ip[0]
102 } 102 }
...@@ -120,7 +120,7 @@ func (input *BeegoInput) SubDomains() string { ...@@ -120,7 +120,7 @@ func (input *BeegoInput) SubDomains() string {
120 } 120 }
121 121
122 func (input *BeegoInput) Port() int { 122 func (input *BeegoInput) Port() int {
123 parts := strings.Split(input.req.Host, ":") 123 parts := strings.Split(input.Request.Host, ":")
124 if len(parts) == 2 { 124 if len(parts) == 2 {
125 port, _ := strconv.Atoi(parts[1]) 125 port, _ := strconv.Atoi(parts[1])
126 return port 126 return port
...@@ -140,16 +140,16 @@ func (input *BeegoInput) Param(key string) string { ...@@ -140,16 +140,16 @@ func (input *BeegoInput) Param(key string) string {
140 } 140 }
141 141
142 func (input *BeegoInput) Query(key string) string { 142 func (input *BeegoInput) Query(key string) string {
143 input.req.ParseForm() 143 input.Request.ParseForm()
144 return input.req.Form.Get(key) 144 return input.Request.Form.Get(key)
145 } 145 }
146 146
147 func (input *BeegoInput) Header(key string) string { 147 func (input *BeegoInput) Header(key string) string {
148 return input.req.Header.Get(key) 148 return input.Request.Header.Get(key)
149 } 149 }
150 150
151 func (input *BeegoInput) Cookie(key string) string { 151 func (input *BeegoInput) Cookie(key string) string {
152 ck, err := input.req.Cookie(key) 152 ck, err := input.Request.Cookie(key)
153 if err != nil { 153 if err != nil {
154 return "" 154 return ""
155 } 155 }
...@@ -161,10 +161,10 @@ func (input *BeegoInput) Session(key interface{}) interface{} { ...@@ -161,10 +161,10 @@ func (input *BeegoInput) Session(key interface{}) interface{} {
161 } 161 }
162 162
163 func (input *BeegoInput) Body() []byte { 163 func (input *BeegoInput) Body() []byte {
164 requestbody, _ := ioutil.ReadAll(input.req.Body) 164 requestbody, _ := ioutil.ReadAll(input.Request.Body)
165 input.req.Body.Close() 165 input.Request.Body.Close()
166 bf := bytes.NewBuffer(requestbody) 166 bf := bytes.NewBuffer(requestbody)
167 input.req.Body = ioutil.NopCloser(bf) 167 input.Request.Body = ioutil.NopCloser(bf)
168 input.RequestBody = requestbody 168 input.RequestBody = requestbody
169 return requestbody 169 return requestbody
170 } 170 }
......
...@@ -21,21 +21,18 @@ type BeegoOutput struct { ...@@ -21,21 +21,18 @@ type BeegoOutput struct {
21 Context *Context 21 Context *Context
22 Status int 22 Status int
23 EnableGzip bool 23 EnableGzip bool
24 res http.ResponseWriter
25 } 24 }
26 25
27 func NewOutput(res http.ResponseWriter) *BeegoOutput { 26 func NewOutput() *BeegoOutput {
28 return &BeegoOutput{ 27 return &BeegoOutput{}
29 res: res,
30 }
31 } 28 }
32 29
33 func (output *BeegoOutput) Header(key, val string) { 30 func (output *BeegoOutput) Header(key, val string) {
34 output.res.Header().Set(key, val) 31 output.Context.ResponseWriter.Header().Set(key, val)
35 } 32 }
36 33
37 func (output *BeegoOutput) Body(content []byte) { 34 func (output *BeegoOutput) Body(content []byte) {
38 output_writer := output.res.(io.Writer) 35 output_writer := output.Context.ResponseWriter.(io.Writer)
39 if output.EnableGzip == true && output.Context.Input.Header("Accept-Encoding") != "" { 36 if output.EnableGzip == true && output.Context.Input.Header("Accept-Encoding") != "" {
40 splitted := strings.SplitN(output.Context.Input.Header("Accept-Encoding"), ",", -1) 37 splitted := strings.SplitN(output.Context.Input.Header("Accept-Encoding"), ",", -1)
41 encodings := make([]string, len(splitted)) 38 encodings := make([]string, len(splitted))
...@@ -46,12 +43,12 @@ func (output *BeegoOutput) Body(content []byte) { ...@@ -46,12 +43,12 @@ func (output *BeegoOutput) Body(content []byte) {
46 for _, val := range encodings { 43 for _, val := range encodings {
47 if val == "gzip" { 44 if val == "gzip" {
48 output.Header("Content-Encoding", "gzip") 45 output.Header("Content-Encoding", "gzip")
49 output_writer, _ = gzip.NewWriterLevel(output.res, gzip.BestSpeed) 46 output_writer, _ = gzip.NewWriterLevel(output.Context.ResponseWriter, gzip.BestSpeed)
50 47
51 break 48 break
52 } else if val == "deflate" { 49 } else if val == "deflate" {
53 output.Header("Content-Encoding", "deflate") 50 output.Header("Content-Encoding", "deflate")
54 output_writer, _ = flate.NewWriter(output.res, flate.BestSpeed) 51 output_writer, _ = flate.NewWriter(output.Context.ResponseWriter, flate.BestSpeed)
55 break 52 break
56 } 53 }
57 } 54 }
...@@ -104,7 +101,7 @@ func (output *BeegoOutput) Cookie(name string, value string, others ...interface ...@@ -104,7 +101,7 @@ func (output *BeegoOutput) Cookie(name string, value string, others ...interface
104 if len(others) > 4 { 101 if len(others) > 4 {
105 fmt.Fprintf(&b, "; HttpOnly") 102 fmt.Fprintf(&b, "; HttpOnly")
106 } 103 }
107 output.res.Header().Add("Set-Cookie", b.String()) 104 output.Context.ResponseWriter.Header().Add("Set-Cookie", b.String())
108 } 105 }
109 106
110 var cookieNameSanitizer = strings.NewReplacer("\n", "-", "\r", "-") 107 var cookieNameSanitizer = strings.NewReplacer("\n", "-", "\r", "-")
...@@ -129,7 +126,7 @@ func (output *BeegoOutput) Json(data interface{}, hasIndent bool, coding bool) e ...@@ -129,7 +126,7 @@ func (output *BeegoOutput) Json(data interface{}, hasIndent bool, coding bool) e
129 content, err = json.Marshal(data) 126 content, err = json.Marshal(data)
130 } 127 }
131 if err != nil { 128 if err != nil {
132 http.Error(output.res, err.Error(), http.StatusInternalServerError) 129 http.Error(output.Context.ResponseWriter, err.Error(), http.StatusInternalServerError)
133 return err 130 return err
134 } 131 }
135 if coding { 132 if coding {
...@@ -149,7 +146,7 @@ func (output *BeegoOutput) Jsonp(data interface{}, hasIndent bool) error { ...@@ -149,7 +146,7 @@ func (output *BeegoOutput) Jsonp(data interface{}, hasIndent bool) error {
149 content, err = json.Marshal(data) 146 content, err = json.Marshal(data)
150 } 147 }
151 if err != nil { 148 if err != nil {
152 http.Error(output.res, err.Error(), http.StatusInternalServerError) 149 http.Error(output.Context.ResponseWriter, err.Error(), http.StatusInternalServerError)
153 return err 150 return err
154 } 151 }
155 callback := output.Context.Input.Query("callback") 152 callback := output.Context.Input.Query("callback")
...@@ -174,7 +171,7 @@ func (output *BeegoOutput) Xml(data interface{}, hasIndent bool) error { ...@@ -174,7 +171,7 @@ func (output *BeegoOutput) Xml(data interface{}, hasIndent bool) error {
174 content, err = xml.Marshal(data) 171 content, err = xml.Marshal(data)
175 } 172 }
176 if err != nil { 173 if err != nil {
177 http.Error(output.res, err.Error(), http.StatusInternalServerError) 174 http.Error(output.Context.ResponseWriter, err.Error(), http.StatusInternalServerError)
178 return err 175 return err
179 } 176 }
180 output.Body(content) 177 output.Body(content)
...@@ -189,7 +186,7 @@ func (output *BeegoOutput) Download(file string) { ...@@ -189,7 +186,7 @@ func (output *BeegoOutput) Download(file string) {
189 output.Header("Expires", "0") 186 output.Header("Expires", "0")
190 output.Header("Cache-Control", "must-revalidate") 187 output.Header("Cache-Control", "must-revalidate")
191 output.Header("Pragma", "public") 188 output.Header("Pragma", "public")
192 http.ServeFile(output.res, output.Context.Request, file) 189 http.ServeFile(output.Context.ResponseWriter, output.Context.Request, file)
193 } 190 }
194 191
195 func (output *BeegoOutput) ContentType(ext string) { 192 func (output *BeegoOutput) ContentType(ext string) {
...@@ -203,7 +200,7 @@ func (output *BeegoOutput) ContentType(ext string) { ...@@ -203,7 +200,7 @@ func (output *BeegoOutput) ContentType(ext string) {
203 } 200 }
204 201
205 func (output *BeegoOutput) SetStatus(status int) { 202 func (output *BeegoOutput) SetStatus(status int) {
206 output.res.WriteHeader(status) 203 output.Context.ResponseWriter.WriteHeader(status)
207 output.Status = status 204 output.Status = status
208 } 205 }
209 206
......
...@@ -28,7 +28,6 @@ const ( ...@@ -28,7 +28,6 @@ const (
28 28
29 var ( 29 var (
30 HTTPMETHOD = []string{"get", "post", "put", "delete", "patch", "options", "head"} 30 HTTPMETHOD = []string{"get", "post", "put", "delete", "patch", "options", "head"}
31 errorType = reflect.TypeOf((*error)(nil)).Elem()
32 ) 31 )
33 32
34 type controllerInfo struct { 33 type controllerInfo struct {
...@@ -47,6 +46,7 @@ type ControllerRegistor struct { ...@@ -47,6 +46,7 @@ type ControllerRegistor struct {
47 filters map[int][]*FilterRouter 46 filters map[int][]*FilterRouter
48 enableAuto bool 47 enableAuto bool
49 autoRouter map[string]map[string]reflect.Type //key:controller key:method value:reflect.type 48 autoRouter map[string]map[string]reflect.Type //key:controller key:method value:reflect.type
49 contextBuffer chan *beecontext.Context
50 } 50 }
51 51
52 func NewControllerRegistor() *ControllerRegistor { 52 func NewControllerRegistor() *ControllerRegistor {
...@@ -54,6 +54,7 @@ func NewControllerRegistor() *ControllerRegistor { ...@@ -54,6 +54,7 @@ func NewControllerRegistor() *ControllerRegistor {
54 routers: make([]*controllerInfo, 0), 54 routers: make([]*controllerInfo, 0),
55 autoRouter: make(map[string]map[string]reflect.Type), 55 autoRouter: make(map[string]map[string]reflect.Type),
56 filters: make(map[int][]*FilterRouter), 56 filters: make(map[int][]*FilterRouter),
57 contextBuffer: make(chan *beecontext.Context, 100),
57 } 58 }
58 } 59 }
59 60
...@@ -433,15 +434,40 @@ func (p *ControllerRegistor) ServeHTTP(rw http.ResponseWriter, r *http.Request) ...@@ -433,15 +434,40 @@ func (p *ControllerRegistor) ServeHTTP(rw http.ResponseWriter, r *http.Request)
433 434
434 w := &responseWriter{writer: rw} 435 w := &responseWriter{writer: rw}
435 w.Header().Set("Server", BeegoServerName) 436 w.Header().Set("Server", BeegoServerName)
436 context := &beecontext.Context{ 437
438 // init context
439 var context *beecontext.Context
440 select {
441 case context = <-p.contextBuffer:
442 context.ResponseWriter = w
443 context.Request = r
444 context.Input.Request = r
445 default:
446 context = &beecontext.Context{
437 ResponseWriter: w, 447 ResponseWriter: w,
438 Request: r, 448 Request: r,
439 Input: beecontext.NewInput(r), 449 Input: beecontext.NewInput(r),
440 Output: beecontext.NewOutput(w), 450 Output: beecontext.NewOutput(),
441 } 451 }
442 context.Output.Context = context 452 context.Output.Context = context
443 context.Output.EnableGzip = EnableGzip 453 context.Output.EnableGzip = EnableGzip
454 }
444 455
456 defer func() {
457 if context != nil {
458 select {
459 case p.contextBuffer <- context:
460 default:
461 }
462 }
463 }()
464
465 if context.Input.IsWebsocket() {
466 context.ResponseWriter = rw
467 context.Output = beecontext.NewOutput(rw)
468 }
469
470 // defined filter function
445 do_filter := func(pos int) (started bool) { 471 do_filter := func(pos int) (started bool) {
446 if p.enableFilter { 472 if p.enableFilter {
447 if l, ok := p.filters[pos]; ok { 473 if l, ok := p.filters[pos]; ok {
...@@ -460,11 +486,6 @@ func (p *ControllerRegistor) ServeHTTP(rw http.ResponseWriter, r *http.Request) ...@@ -460,11 +486,6 @@ func (p *ControllerRegistor) ServeHTTP(rw http.ResponseWriter, r *http.Request)
460 return false 486 return false
461 } 487 }
462 488
463 if context.Input.IsWebsocket() {
464 context.ResponseWriter = rw
465 context.Output = beecontext.NewOutput(rw)
466 }
467
468 // session init 489 // session init
469 if SessionOn { 490 if SessionOn {
470 context.Input.CruSession = GlobalSessions.SessionStart(w, r) 491 context.Input.CruSession = GlobalSessions.SessionStart(w, r)
......
Styling with Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!