recycling memory buffer in context
Showing
3 changed files
with
63 additions
and
45 deletions
| ... | @@ -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) | ... | ... |
-
Please register or sign in to post a comment