Commit 8771634f authored by JessonChan's avatar JessonChan

Merge remote-tracking branch 'remotes/upstream/develop' into develop

parents ccc008c2 2aa50c24
......@@ -17,6 +17,7 @@ package context
import (
"bytes"
"errors"
"io"
"io/ioutil"
"net/url"
"reflect"
......@@ -33,6 +34,7 @@ var (
acceptsHTMLRegex = regexp.MustCompile(`(text/html|application/xhtml\+xml)(?:,|$)`)
acceptsXMLRegex = regexp.MustCompile(`(application/xml|text/xml)(?:,|$)`)
acceptsJSONRegex = regexp.MustCompile(`(application/json)(?:,|$)`)
maxParam = 50
)
// BeegoInput operates the http request header, data, cookie and body.
......@@ -40,16 +42,18 @@ var (
type BeegoInput struct {
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.
pnames []string
pvalues []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 Context.
func NewInput() *BeegoInput {
return &BeegoInput{
Params: make(map[string]string),
Data: make(map[interface{}]interface{}),
pnames: make([]string, 0, maxParam),
pvalues: make([]string, 0, maxParam),
data: make(map[interface{}]interface{}),
}
}
......@@ -57,8 +61,9 @@ func NewInput() *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.pnames = input.pnames[:0]
input.pvalues = input.pvalues[:0]
input.data = nil
input.RequestBody = []byte{}
}
......@@ -254,14 +259,27 @@ func (input *BeegoInput) UserAgent() string {
return input.Header("User-Agent")
}
// ParamsLen return the length of the params
func (input *BeegoInput) ParamsLen() int {
return len(input.pnames)
}
// Param returns router param by a given key.
func (input *BeegoInput) Param(key string) string {
if v, ok := input.Params[key]; ok {
return v
for i, v := range input.pnames {
if v == key && i <= len(input.pvalues) {
return input.pvalues[i]
}
}
return ""
}
// SetParam will set the param with key and value
func (input *BeegoInput) SetParam(key, val string) {
input.pvalues = append(input.pvalues, val)
input.pnames = append(input.pnames, key)
}
// Query returns input data item string by a given string.
func (input *BeegoInput) Query(key string) string {
if val := input.Param(key); val != "" {
......@@ -296,8 +314,9 @@ 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.Context.Request.Body)
func (input *BeegoInput) CopyBody(MaxMemory int64) []byte {
safe := &io.LimitedReader{R:input.Context.Request.Body, N:MaxMemory}
requestbody, _ := ioutil.ReadAll(safe)
input.Context.Request.Body.Close()
bf := bytes.NewBuffer(requestbody)
input.Context.Request.Body = ioutil.NopCloser(bf)
......@@ -305,9 +324,17 @@ func (input *BeegoInput) CopyBody() []byte {
return requestbody
}
// Data return the implicit data in the input
func (input *BeegoInput) Data() map[interface{}]interface{} {
if input.data == nil {
input.data = make(map[interface{}]interface{})
}
return input.data
}
// GetData returns the stored data in this context.
func (input *BeegoInput) GetData(key interface{}) interface{} {
if v, ok := input.Data[key]; ok {
if v, ok := input.data[key]; ok {
return v
}
return nil
......@@ -316,7 +343,10 @@ func (input *BeegoInput) GetData(key interface{}) interface{} {
// SetData stores data with given key in this context.
// This data are only available in this context.
func (input *BeegoInput) SetData(key, val interface{}) {
input.Data[key] = val
if input.data == nil {
input.data = make(map[interface{}]interface{})
}
input.data[key] = val
}
// ParseFormOrMulitForm parseForm or parseMultiForm based on Content-type
......
......@@ -105,7 +105,7 @@ func (c *Controller) Init(ctx *context.Context, controllerName, actionName strin
c.AppController = app
c.EnableRender = true
c.EnableXSRF = true
c.Data = ctx.Input.Data
c.Data = ctx.Input.Data()
c.methodMapping = make(map[string]func())
}
......
......@@ -21,7 +21,8 @@ import (
)
func TestGetInt(t *testing.T) {
i := &context.BeegoInput{Params: map[string]string{"age": "40"}}
i := context.NewInput()
i.SetParam("age", "40")
ctx := &context.Context{Input: i}
ctrlr := Controller{Ctx: ctx}
val, _ := ctrlr.GetInt("age")
......@@ -31,7 +32,8 @@ func TestGetInt(t *testing.T) {
}
func TestGetInt8(t *testing.T) {
i := &context.BeegoInput{Params: map[string]string{"age": "40"}}
i := context.NewInput()
i.SetParam("age", "40")
ctx := &context.Context{Input: i}
ctrlr := Controller{Ctx: ctx}
val, _ := ctrlr.GetInt8("age")
......@@ -42,7 +44,8 @@ func TestGetInt8(t *testing.T) {
}
func TestGetInt16(t *testing.T) {
i := &context.BeegoInput{Params: map[string]string{"age": "40"}}
i := context.NewInput()
i.SetParam("age", "40")
ctx := &context.Context{Input: i}
ctrlr := Controller{Ctx: ctx}
val, _ := ctrlr.GetInt16("age")
......@@ -52,7 +55,8 @@ func TestGetInt16(t *testing.T) {
}
func TestGetInt32(t *testing.T) {
i := &context.BeegoInput{Params: map[string]string{"age": "40"}}
i := context.NewInput()
i.SetParam("age", "40")
ctx := &context.Context{Input: i}
ctrlr := Controller{Ctx: ctx}
val, _ := ctrlr.GetInt32("age")
......@@ -62,7 +66,8 @@ func TestGetInt32(t *testing.T) {
}
func TestGetInt64(t *testing.T) {
i := &context.BeegoInput{Params: map[string]string{"age": "40"}}
i := context.NewInput()
i.SetParam("age", "40")
ctx := &context.Context{Input: i}
ctrlr := Controller{Ctx: ctx}
val, _ := ctrlr.GetInt64("age")
......
......@@ -32,13 +32,13 @@ type FilterRouter struct {
// ValidRouter checks if the current request is matched by this filter.
// If the request is matched, the values of the URL parameters defined
// by the filter pattern are also returned.
func (f *FilterRouter) ValidRouter(url string) (bool, map[string]string) {
isok, params := f.tree.Match(url)
func (f *FilterRouter) ValidRouter(url string, ctx *context.Context) bool {
isok := f.tree.Match(url, ctx)
if isok == nil {
return false, nil
return false
}
if isok, ok := isok.(bool); ok {
return isok, params
return isok
}
return false, nil
return false
}
......@@ -29,7 +29,7 @@ func init() {
}
var FilterUser = func(ctx *context.Context) {
ctx.Output.Body([]byte("i am " + ctx.Input.Params[":last"] + ctx.Input.Params[":first"]))
ctx.Output.Body([]byte("i am " + ctx.Input.Param(":last") + ctx.Input.Param(":first")))
}
func TestFilter(t *testing.T) {
......
......@@ -466,8 +466,8 @@ func (p *ControllerRegister) URLFor(endpoint string, values ...interface{}) stri
}
func (p *ControllerRegister) geturl(t *Tree, url, controllName, methodName string, params map[string]string, httpMethod string) (bool, string) {
for k, subtree := range t.fixrouters {
u := path.Join(url, k)
for _, subtree := range t.fixrouters {
u := path.Join(url, subtree.prefix)
ok, u := p.geturl(subtree, u, controllName, methodName, params, httpMethod)
if ok {
return ok, u
......@@ -583,13 +583,7 @@ func (p *ControllerRegister) execFilter(context *beecontext.Context, pos int, ur
if filterR.returnOnOutput && context.ResponseWriter.Started {
return true
}
if ok, params := filterR.ValidRouter(urlPath); ok {
for k, v := range params {
if context.Input.Params == nil {
context.Input.Params = make(map[string]string)
}
context.Input.Params[k] = v
}
if ok := filterR.ValidRouter(urlPath, context); ok {
filterR.filterFunc(context)
}
if filterR.returnOnOutput && context.ResponseWriter.Started {
......@@ -659,7 +653,7 @@ func (p *ControllerRegister) ServeHTTP(rw http.ResponseWriter, r *http.Request)
if r.Method != "GET" && r.Method != "HEAD" {
if BConfig.CopyRequestBody && !context.Input.IsUpload() {
context.Input.CopyBody()
context.Input.CopyBody(BConfig.MaxMemory)
}
context.Input.ParseFormOrMulitForm(BConfig.MaxMemory)
}
......@@ -677,19 +671,16 @@ func (p *ControllerRegister) ServeHTTP(rw http.ResponseWriter, r *http.Request)
httpMethod = "DELETE"
}
if t, ok := p.routers[httpMethod]; ok {
runObject, p := t.Match(urlPath)
runObject := t.Match(urlPath, context)
if r, ok := runObject.(*controllerInfo); ok {
routerInfo = r
findrouter = true
if splat, ok := p[":splat"]; ok {
if splat := context.Input.Param(":splat"); splat != "" {
splatlist := strings.Split(splat, "/")
for k, v := range splatlist {
p[strconv.Itoa(k)] = v
context.Input.SetParam(strconv.Itoa(k), v)
}
}
if p != nil {
context.Input.Params = p
}
}
}
......
......@@ -45,7 +45,7 @@ func (tc *TestController) List() {
}
func (tc *TestController) Params() {
tc.Ctx.Output.Body([]byte(tc.Ctx.Input.Params["0"] + tc.Ctx.Input.Params["1"] + tc.Ctx.Input.Params["2"]))
tc.Ctx.Output.Body([]byte(tc.Ctx.Input.Param("0") + tc.Ctx.Input.Param("1") + tc.Ctx.Input.Param("2")))
}
func (tc *TestController) Myext() {
......
This diff is collapsed.
......@@ -14,7 +14,11 @@
package beego
import "testing"
import (
"testing"
"github.com/astaxie/beego/context"
)
type testinfo struct {
url string
......@@ -27,11 +31,11 @@ var routers []testinfo
func init() {
routers = make([]testinfo, 0)
routers = append(routers, testinfo{"/topic/?:auth:int", "/topic", nil})
routers = append(routers, testinfo{"/topic/?:auth:int", "/topic/123", map[string]string{":auth":"123"}})
routers = append(routers, testinfo{"/topic/?:auth:int", "/topic/123", map[string]string{":auth": "123"}})
routers = append(routers, testinfo{"/topic/:id/?:auth", "/topic/1", map[string]string{":id": "1"}})
routers = append(routers, testinfo{"/topic/:id/?:auth", "/topic/1/2", map[string]string{":id": "1",":auth":"2"}})
routers = append(routers, testinfo{"/topic/:id/?:auth", "/topic/1/2", map[string]string{":id": "1", ":auth": "2"}})
routers = append(routers, testinfo{"/topic/:id/?:auth:int", "/topic/1", map[string]string{":id": "1"}})
routers = append(routers, testinfo{"/topic/:id/?:auth:int", "/topic/1/123", map[string]string{":id": "1",":auth":"123"}})
routers = append(routers, testinfo{"/topic/:id/?:auth:int", "/topic/1/123", map[string]string{":id": "1", ":auth": "123"}})
routers = append(routers, testinfo{"/:id", "/123", map[string]string{":id": "123"}})
routers = append(routers, testinfo{"/hello/?:id", "/hello", map[string]string{":id": ""}})
routers = append(routers, testinfo{"/", "/", nil})
......@@ -41,6 +45,7 @@ func init() {
routers = append(routers, testinfo{"/*", "/customer/2009/12/11", map[string]string{":splat": "customer/2009/12/11"}})
routers = append(routers, testinfo{"/aa/*/bb", "/aa/2009/bb", map[string]string{":splat": "2009"}})
routers = append(routers, testinfo{"/cc/*/dd", "/cc/2009/11/dd", map[string]string{":splat": "2009/11"}})
routers = append(routers, testinfo{"/cc/:id/*", "/cc/2009/11/dd", map[string]string{":id": "2009", ":splat": "11/dd"}})
routers = append(routers, testinfo{"/ee/:year/*/ff", "/ee/2009/11/ff", map[string]string{":year": "2009", ":splat": "11"}})
routers = append(routers, testinfo{"/thumbnail/:size/uploads/*",
"/thumbnail/100x100/uploads/items/2014/04/20/dPRCdChkUd651t1Hvs18.jpg",
......@@ -69,16 +74,17 @@ func TestTreeRouters(t *testing.T) {
for _, r := range routers {
tr := NewTree()
tr.AddRouter(r.url, "astaxie")
obj, param := tr.Match(r.requesturl)
ctx := context.NewContext()
obj := tr.Match(r.requesturl, ctx)
if obj == nil || obj.(string) != "astaxie" {
t.Fatal(r.url + " can't get obj ")
t.Fatal(r.url+" can't get obj, Expect ", r.requesturl)
}
if r.params != nil {
for k, v := range r.params {
if vv, ok := param[k]; !ok {
if vv := ctx.Input.Param(k); vv != v {
t.Fatal("The Rule: " + r.url + "\nThe RequestURL:" + r.requesturl + "\nThe Key is " + k + ", The Value should be: " + v + ", but get: " + vv)
} else if vv == "" && v != "" {
t.Fatal(r.url + " " + r.requesturl + " get param empty:" + k)
} else if vv != v {
t.Fatal(r.url + " " + r.requesturl + " should be:" + v + " get param:" + vv)
}
}
}
......@@ -91,47 +97,51 @@ func TestAddTree(t *testing.T) {
tr.AddRouter("/shop/:sd/ttt_:id(.+)_:page(.+).html", "astaxie")
t1 := NewTree()
t1.AddTree("/v1/zl", tr)
obj, param := t1.Match("/v1/zl/shop/123/account")
ctx := context.NewContext()
obj := t1.Match("/v1/zl/shop/123/account", ctx)
if obj == nil || obj.(string) != "astaxie" {
t.Fatal("/v1/zl/shop/:id/account can't get obj ")
}
if param == nil {
if ctx.Input.ParamsLen() == 0 {
t.Fatal("get param error")
}
if param[":id"] != "123" {
if ctx.Input.Param(":id") != "123" {
t.Fatal("get :id param error")
}
obj, param = t1.Match("/v1/zl/shop/123/ttt_1_12.html")
ctx.Input.Reset(ctx)
obj = t1.Match("/v1/zl/shop/123/ttt_1_12.html", ctx)
if obj == nil || obj.(string) != "astaxie" {
t.Fatal("/v1/zl//shop/:sd/ttt_:id(.+)_:page(.+).html can't get obj ")
}
if param == nil {
if ctx.Input.ParamsLen() == 0 {
t.Fatal("get param error")
}
if param[":sd"] != "123" || param[":id"] != "1" || param[":page"] != "12" {
if ctx.Input.Param(":sd") != "123" || ctx.Input.Param(":id") != "1" || ctx.Input.Param(":page") != "12" {
t.Fatal("get :sd :id :page param error")
}
t2 := NewTree()
t2.AddTree("/v1/:shopid", tr)
obj, param = t2.Match("/v1/zl/shop/123/account")
ctx.Input.Reset(ctx)
obj = t2.Match("/v1/zl/shop/123/account", ctx)
if obj == nil || obj.(string) != "astaxie" {
t.Fatal("/v1/:shopid/shop/:id/account can't get obj ")
}
if param == nil {
if ctx.Input.ParamsLen() == 0 {
t.Fatal("get param error")
}
if param[":id"] != "123" || param[":shopid"] != "zl" {
if ctx.Input.Param(":id") != "123" || ctx.Input.Param(":shopid") != "zl" {
t.Fatal("get :id :shopid param error")
}
obj, param = t2.Match("/v1/zl/shop/123/ttt_1_12.html")
ctx.Input.Reset(ctx)
obj = t2.Match("/v1/zl/shop/123/ttt_1_12.html", ctx)
if obj == nil || obj.(string) != "astaxie" {
t.Fatal("/v1/:shopid/shop/:sd/ttt_:id(.+)_:page(.+).html can't get obj ")
}
if param == nil {
if ctx.Input.ParamsLen() == 0 {
t.Fatal("get :shopid param error")
}
if param[":sd"] != "123" || param[":id"] != "1" || param[":page"] != "12" || param[":shopid"] != "zl" {
if ctx.Input.Param(":sd") != "123" || ctx.Input.Param(":id") != "1" || ctx.Input.Param(":page") != "12" || ctx.Input.Param(":shopid") != "zl" {
t.Fatal("get :sd :id :page :shopid param error")
}
}
......@@ -142,14 +152,15 @@ func TestAddTree2(t *testing.T) {
tr.AddRouter("/shop/:sd/ttt_:id(.+)_:page(.+).html", "astaxie")
t3 := NewTree()
t3.AddTree("/:version(v1|v2)/:prefix", tr)
obj, param := t3.Match("/v1/zl/shop/123/account")
ctx := context.NewContext()
obj := t3.Match("/v1/zl/shop/123/account", ctx)
if obj == nil || obj.(string) != "astaxie" {
t.Fatal("/:version(v1|v2)/:prefix/shop/:id/account can't get obj ")
}
if param == nil {
if ctx.Input.ParamsLen() == 0 {
t.Fatal("get param error")
}
if param[":id"] != "123" || param[":prefix"] != "zl" || param[":version"] != "v1" {
if ctx.Input.Param(":id") != "123" || ctx.Input.Param(":prefix") != "zl" || ctx.Input.Param(":version") != "v1" {
t.Fatal("get :id :prefix :version param error")
}
}
......@@ -160,17 +171,19 @@ func TestAddTree3(t *testing.T) {
tr.AddRouter("/shop/:sd/account", "astaxie")
t3 := NewTree()
t3.AddTree("/table/:num", tr)
obj, param := t3.Match("/table/123/shop/123/account")
ctx := context.NewContext()
obj := t3.Match("/table/123/shop/123/account", ctx)
if obj == nil || obj.(string) != "astaxie" {
t.Fatal("/table/:num/shop/:sd/account can't get obj ")
}
if param == nil {
if ctx.Input.ParamsLen() == 0 {
t.Fatal("get param error")
}
if param[":num"] != "123" || param[":sd"] != "123" {
if ctx.Input.Param(":num") != "123" || ctx.Input.Param(":sd") != "123" {
t.Fatal("get :num :sd param error")
}
obj, param = t3.Match("/table/123/create")
ctx.Input.Reset(ctx)
obj = t3.Match("/table/123/create", ctx)
if obj == nil || obj.(string) != "astaxie" {
t.Fatal("/table/:num/create can't get obj ")
}
......@@ -182,17 +195,21 @@ func TestAddTree4(t *testing.T) {
tr.AddRouter("/shop/:sd/:account", "astaxie")
t4 := NewTree()
t4.AddTree("/:info:int/:num/:id", tr)
obj, param := t4.Match("/12/123/456/shop/123/account")
ctx := context.NewContext()
obj := t4.Match("/12/123/456/shop/123/account", ctx)
if obj == nil || obj.(string) != "astaxie" {
t.Fatal("/:info:int/:num/:id/shop/:sd/:account can't get obj ")
}
if param == nil {
if ctx.Input.ParamsLen() == 0 {
t.Fatal("get param error")
}
if param[":info"] != "12" || param[":num"] != "123" || param[":id"] != "456" || param[":sd"] != "123" || param[":account"] != "account" {
if ctx.Input.Param(":info") != "12" || ctx.Input.Param(":num") != "123" ||
ctx.Input.Param(":id") != "456" || ctx.Input.Param(":sd") != "123" ||
ctx.Input.Param(":account") != "account" {
t.Fatal("get :info :num :id :sd :account param error")
}
obj, param = t4.Match("/12/123/456/create")
ctx.Input.Reset(ctx)
obj = t4.Match("/12/123/456/create", ctx)
if obj == nil || obj.(string) != "astaxie" {
t.Fatal("/:info:int/:num/:id/create can't get obj ")
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment