router.go 19.2 KB
Newer Older
A
fix bug  
astaxie 已提交
1 2 3
package beego

import (
A
astaxie 已提交
4
	"fmt"
A
astaxie 已提交
5
	beecontext "github.com/astaxie/beego/context"
A
astaxie 已提交
6
	"github.com/astaxie/beego/middleware"
A
fix bug  
astaxie 已提交
7 8
	"net/http"
	"net/url"
A
fix #81  
astaxie 已提交
9
	"os"
A
fix bug  
astaxie 已提交
10 11 12
	"reflect"
	"regexp"
	"runtime"
A
astaxie 已提交
13
	"strconv"
A
fix bug  
astaxie 已提交
14 15 16
	"strings"
)

A
astaxie 已提交
17 18
var HTTPMETHOD = []string{"get", "post", "put", "delete", "patch", "options", "head"}

A
fix bug  
astaxie 已提交
19 20 21 22 23
type controllerInfo struct {
	pattern        string
	regex          *regexp.Regexp
	params         map[int]string
	controllerType reflect.Type
A
astaxie 已提交
24
	methods        map[string]string
A
astaxie 已提交
25
	hasMethod      bool
A
fix bug  
astaxie 已提交
26 27 28
}

type ControllerRegistor struct {
A
astaxie 已提交
29 30
	routers      []*controllerInfo
	fixrouters   []*controllerInfo
A
astaxie 已提交
31
	enableFilter bool
A
astaxie 已提交
32
	filters      map[string][]*FilterRouter
A
astaxie 已提交
33
	enableAuto   bool
A
astaxie 已提交
34
	autoRouter   map[string]map[string]reflect.Type //key:controller key:method value:reflect.type
A
fix bug  
astaxie 已提交
35 36 37
}

func NewControllerRegistor() *ControllerRegistor {
A
astaxie 已提交
38
	return &ControllerRegistor{
A
astaxie 已提交
39 40 41
		routers:    make([]*controllerInfo, 0),
		autoRouter: make(map[string]map[string]reflect.Type),
		filters:    make(map[string][]*FilterRouter),
A
astaxie 已提交
42
	}
A
fix bug  
astaxie 已提交
43 44
}

A
astaxie 已提交
45 46 47 48 49 50 51 52 53 54
//methods support like this:
//default methods is the same name as method
//Add("/user",&UserController{})
//Add("/api/list",&RestController{},"*:ListFood")
//Add("/api/create",&RestController{},"post:CreateFood")
//Add("/api/update",&RestController{},"put:UpdateFood")
//Add("/api/delete",&RestController{},"delete:DeleteFood")
//Add("/api",&RestController{},"get,post:ApiFunc")
//Add("/simple",&SimpleController{},"get:GetFunc;post:PostFunc")
func (p *ControllerRegistor) Add(pattern string, c ControllerInterface, mappingMethods ...string) {
A
fix bug  
astaxie 已提交
55 56 57 58 59 60
	parts := strings.Split(pattern, "/")

	j := 0
	params := make(map[int]string)
	for i, part := range parts {
		if strings.HasPrefix(part, ":") {
A
astaxie 已提交
61
			expr := "(.+)"
A
fix bug  
astaxie 已提交
62
			//a user may choose to override the defult expression
63
			// similar to expressjs: ‘/user/:id([0-9]+)’
A
fix bug  
astaxie 已提交
64 65 66
			if index := strings.Index(part, "("); index != -1 {
				expr = part[index:]
				part = part[:index]
A
astaxie 已提交
67
				//match /user/:id:int ([0-9]+)
A
astaxie 已提交
68
				//match /post/:username:string	([\w]+)
A
astaxie 已提交
69 70
			} else if lindex := strings.LastIndex(part, ":"); lindex != 0 {
				switch part[lindex:] {
A
astaxie 已提交
71
				case ":int":
A
astaxie 已提交
72
					expr = "([0-9]+)"
A
astaxie 已提交
73
					part = part[:lindex]
A
astaxie 已提交
74
				case ":string":
A
astaxie 已提交
75
					expr = `([\w]+)`
A
astaxie 已提交
76
					part = part[:lindex]
A
astaxie 已提交
77
				}
A
fix bug  
astaxie 已提交
78 79 80 81 82
			}
			params[j] = part
			parts[i] = expr
			j++
		}
A
astaxie 已提交
83 84 85 86
		if strings.HasPrefix(part, "*") {
			expr := "(.+)"
			if part == "*.*" {
				params[j] = ":path"
A
astaxie 已提交
87
				parts[i] = "([^.]+).([^.]+)"
A
astaxie 已提交
88 89 90 91 92 93 94 95 96
				j++
				params[j] = ":ext"
				j++
			} else {
				params[j] = ":splat"
				parts[i] = expr
				j++
			}
		}
A
astaxie 已提交
97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137
		//url like someprefix:id(xxx).html
		if strings.Contains(part, ":") && strings.Contains(part, "(") && strings.Contains(part, ")") {
			var out []rune
			var start bool
			var startexp bool
			var param []rune
			var expt []rune
			for _, v := range part {
				if start {
					if v != '(' {
						param = append(param, v)
						continue
					}
				}
				if startexp {
					if v != ')' {
						expt = append(expt, v)
						continue
					}
				}
				if v == ':' {
					param = make([]rune, 0)
					param = append(param, ':')
					start = true
				} else if v == '(' {
					startexp = true
					start = false
					params[j] = string(param)
					j++
					expt = make([]rune, 0)
					expt = append(expt, '(')
				} else if v == ')' {
					startexp = false
					expt = append(expt, ')')
					out = append(out, expt...)
				} else {
					out = append(out, v)
				}
			}
			parts[i] = string(out)
		}
A
fix bug  
astaxie 已提交
138
	}
A
astaxie 已提交
139 140
	reflectVal := reflect.ValueOf(c)
	t := reflect.Indirect(reflectVal).Type()
A
astaxie 已提交
141 142 143 144 145 146 147 148 149 150 151
	methods := make(map[string]string)
	if len(mappingMethods) > 0 {
		semi := strings.Split(mappingMethods[0], ";")
		for _, v := range semi {
			colon := strings.Split(v, ":")
			if len(colon) != 2 {
				panic("method mapping fomate is error")
			}
			comma := strings.Split(colon[0], ",")
			for _, m := range comma {
				if m == "*" || inSlice(strings.ToLower(m), HTTPMETHOD) {
A
astaxie 已提交
152
					if val := reflectVal.MethodByName(colon[1]); val.IsValid() {
A
astaxie 已提交
153 154 155 156 157 158 159 160 161 162
						methods[strings.ToLower(m)] = colon[1]
					} else {
						panic(colon[1] + " method don't exist in the controller " + t.Name())
					}
				} else {
					panic(v + " is an error method mapping,Don't exist method named " + m)
				}
			}
		}
	}
A
fix bug  
astaxie 已提交
163 164 165 166 167
	if j == 0 {
		//now create the Route
		route := &controllerInfo{}
		route.pattern = pattern
		route.controllerType = t
A
astaxie 已提交
168
		route.methods = methods
A
astaxie 已提交
169 170 171
		if len(methods) > 0 {
			route.hasMethod = true
		}
A
fix bug  
astaxie 已提交
172 173 174 175 176 177 178 179 180 181 182 183 184
		p.fixrouters = append(p.fixrouters, route)
	} else { // add regexp routers
		//recreate the url pattern, with parameters replaced
		//by regular expressions. then compile the regex
		pattern = strings.Join(parts, "/")
		regex, regexErr := regexp.Compile(pattern)
		if regexErr != nil {
			//TODO add error handling here to avoid panic
			panic(regexErr)
			return
		}

		//now create the Route
A
astaxie 已提交
185

A
fix bug  
astaxie 已提交
186 187 188 189
		route := &controllerInfo{}
		route.regex = regex
		route.params = params
		route.pattern = pattern
A
astaxie 已提交
190
		route.methods = methods
A
astaxie 已提交
191 192 193
		if len(methods) > 0 {
			route.hasMethod = true
		}
A
fix bug  
astaxie 已提交
194 195 196 197 198
		route.controllerType = t
		p.routers = append(p.routers, route)
	}
}

A
astaxie 已提交
199
func (p *ControllerRegistor) AddAuto(c ControllerInterface) {
A
astaxie 已提交
200
	p.enableAuto = true
A
astaxie 已提交
201 202 203 204 205 206 207 208 209 210 211 212 213 214
	reflectVal := reflect.ValueOf(c)
	rt := reflectVal.Type()
	ct := reflect.Indirect(reflectVal).Type()
	firstParam := strings.ToLower(strings.TrimSuffix(ct.Name(), "Controller"))
	if _, ok := p.autoRouter[firstParam]; ok {
		return
	} else {
		p.autoRouter[firstParam] = make(map[string]reflect.Type)
	}
	for i := 0; i < rt.NumMethod(); i++ {
		p.autoRouter[firstParam][rt.Method(i).Name] = ct
	}
}

A
astaxie 已提交
215 216 217 218 219
// Filter adds the middleware filter.
func (p *ControllerRegistor) AddFilter(pattern, action string, filter FilterFunc) {
	p.enableFilter = true
	mr := new(FilterRouter)
	mr.filterFunc = filter
A
astaxie 已提交
220

A
astaxie 已提交
221
	parts := strings.Split(pattern, "/")
A
astaxie 已提交
222 223 224
	j := 0
	for i, part := range parts {
		if strings.HasPrefix(part, ":") {
A
astaxie 已提交
225
			expr := "(.+)"
A
astaxie 已提交
226
			//a user may choose to override the defult expression
227
			// similar to expressjs: ‘/user/:id([0-9]+)’
A
astaxie 已提交
228 229 230
			if index := strings.Index(part, "("); index != -1 {
				expr = part[index:]
				part = part[:index]
A
astaxie 已提交
231 232 233 234 235 236 237 238 239 240 241
				//match /user/:id:int ([0-9]+)
				//match /post/:username:string	([\w]+)
			} else if lindex := strings.LastIndex(part, ":"); lindex != 0 {
				switch part[lindex:] {
				case ":int":
					expr = "([0-9]+)"
					part = part[:lindex]
				case ":string":
					expr = `([\w]+)`
					part = part[:lindex]
				}
A
astaxie 已提交
242 243 244 245 246
			}
			parts[i] = expr
			j++
		}
	}
A
astaxie 已提交
247
	if j != 0 {
A
astaxie 已提交
248 249 250 251 252 253 254
		pattern = strings.Join(parts, "/")
		regex, regexErr := regexp.Compile(pattern)
		if regexErr != nil {
			//TODO add error handling here to avoid panic
			panic(regexErr)
			return
		}
A
astaxie 已提交
255 256
		mr.regex = regex
		mr.hasregex = true
A
astaxie 已提交
257
	}
A
astaxie 已提交
258 259
	mr.pattern = pattern
	p.filters[action] = append(p.filters[action], mr)
A
astaxie 已提交
260 261
}

A
fix bug  
astaxie 已提交
262 263 264 265
// AutoRoute
func (p *ControllerRegistor) ServeHTTP(rw http.ResponseWriter, r *http.Request) {
	defer func() {
		if err := recover(); err != nil {
A
fix #16  
astaxie 已提交
266
			errstr := fmt.Sprint(err)
A
astaxie 已提交
267
			if handler, ok := middleware.ErrorMaps[errstr]; ok && ErrorsShow {
A
fix #16  
astaxie 已提交
268
				handler(rw, r)
A
fix bug  
astaxie 已提交
269
			} else {
A
fix #16  
astaxie 已提交
270 271 272 273 274 275 276 277 278 279 280 281 282 283 284
				if !RecoverPanic {
					// go back to panic
					panic(err)
				} else {
					var stack string
					Critical("Handler crashed with error", err)
					for i := 1; ; i++ {
						_, file, line, ok := runtime.Caller(i)
						if !ok {
							break
						}
						Critical(file, line)
						if RunMode == "dev" {
							stack = stack + fmt.Sprintln(file, line)
						}
A
fix bug  
astaxie 已提交
285
					}
A
astaxie 已提交
286
					if RunMode == "dev" {
A
astaxie 已提交
287
						middleware.ShowErr(err, rw, r, stack)
A
astaxie 已提交
288 289
					}
				}
A
fix bug  
astaxie 已提交
290 291 292
			}
		}
	}()
A
astaxie 已提交
293

A
fix bug  
astaxie 已提交
294
	w := &responseWriter{writer: rw}
A
astaxie 已提交
295
	w.Header().Set("Server", "beegoServer")
A
astaxie 已提交
296 297 298 299 300 301 302
	context := &beecontext.Context{
		ResponseWriter: w,
		Request:        r,
		Input:          beecontext.NewInput(r),
		Output:         beecontext.NewOutput(w),
	}
	context.Output.Context = context
A
astaxie 已提交
303
	context.Output.EnableGzip = EnableGzip
A
astaxie 已提交
304 305 306 307 308 309

	if context.Input.IsWebsocket() {
		context.ResponseWriter = rw
		context.Output = beecontext.NewOutput(rw)
	}

310 311 312 313
	if SessionOn {
		context.Input.CruSession = GlobalSessions.SessionStart(w, r)
	}

A
fix bug  
astaxie 已提交
314 315 316 317 318
	var runrouter *controllerInfo
	var findrouter bool

	params := make(map[string]string)

A
astaxie 已提交
319 320 321 322 323
	if p.enableFilter {
		if l, ok := p.filters["BeforRouter"]; ok {
			for _, filterR := range l {
				if filterR.ValidRouter(r.URL.Path) {
					filterR.filterFunc(context)
A
astaxie 已提交
324 325 326
					if w.started {
						return
					}
A
astaxie 已提交
327 328 329 330 331
				}
			}
		}
	}

A
fix bug  
astaxie 已提交
332 333
	//static file server
	for prefix, staticDir := range StaticDir {
334 335 336 337 338 339
		if r.URL.Path == "/favicon.ico" {
			file := staticDir + r.URL.Path
			http.ServeFile(w, r, file)
			w.started = true
			return
		}
A
fix bug  
astaxie 已提交
340 341
		if strings.HasPrefix(r.URL.Path, prefix) {
			file := staticDir + r.URL.Path[len(prefix):]
A
fix #81  
astaxie 已提交
342 343 344 345 346 347
			finfo, err := os.Stat(file)
			if err != nil {
				return
			}
			//if the request is dir and DirectoryIndex is false then
			if finfo.IsDir() && !DirectoryIndex {
A
astaxie 已提交
348 349
				middleware.Exception("403", rw, r, "403 Forbidden")
				return
A
fix #81  
astaxie 已提交
350
			}
A
fix bug  
astaxie 已提交
351 352 353 354 355 356
			http.ServeFile(w, r, file)
			w.started = true
			return
		}
	}

A
astaxie 已提交
357 358 359 360 361
	if p.enableFilter {
		if l, ok := p.filters["AfterStatic"]; ok {
			for _, filterR := range l {
				if filterR.ValidRouter(r.URL.Path) {
					filterR.filterFunc(context)
A
astaxie 已提交
362 363 364
					if w.started {
						return
					}
A
astaxie 已提交
365 366 367 368
				}
			}
		}
	}
A
fix bug  
astaxie 已提交
369 370
	requestPath := r.URL.Path

A
astaxie 已提交
371
	if CopyRequestBody {
A
astaxie 已提交
372
		context.Input.Body()
A
astaxie 已提交
373 374
	}

A
fix bug  
astaxie 已提交
375 376 377
	//first find path from the fixrouters to Improve Performance
	for _, route := range p.fixrouters {
		n := len(requestPath)
A
astaxie 已提交
378 379 380 381
		if requestPath == route.pattern {
			runrouter = route
			findrouter = true
			break
382
		}
A
astaxie 已提交
383 384 385
		// pattern /admin   url /admin 200  /admin/ 404
		// pattern /admin/  url /admin 301  /admin/ 200
		if requestPath[n-1] != '/' && len(route.pattern) == n+1 &&
A
astaxie 已提交
386
			route.pattern[n] == '/' && route.pattern[:n] == requestPath {
A
astaxie 已提交
387 388
			http.Redirect(w, r, requestPath+"/", 301)
			return
A
fix bug  
astaxie 已提交
389 390 391
		}
	}

A
astaxie 已提交
392
	//find regex's router
A
fix bug  
astaxie 已提交
393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417
	if !findrouter {
		//find a matching Route
		for _, route := range p.routers {

			//check if Route pattern matches url
			if !route.regex.MatchString(requestPath) {
				continue
			}

			//get submatches (params)
			matches := route.regex.FindStringSubmatch(requestPath)

			//double check that the Route matches the URL pattern.
			if len(matches[0]) != len(requestPath) {
				continue
			}

			if len(route.params) > 0 {
				//add url parameters to the query param map
				values := r.URL.Query()
				for i, match := range matches[1:] {
					values.Add(route.params[i], match)
					params[route.params[i]] = match
				}
				//reassemble query params and add to RawQuery
A
astaxie 已提交
418
				r.URL.RawQuery = url.Values(values).Encode()
A
fix bug  
astaxie 已提交
419 420 421 422 423 424
			}
			runrouter = route
			findrouter = true
			break
		}
	}
A
astaxie 已提交
425
	context.Input.Param = params
A
fix bug  
astaxie 已提交
426 427

	if runrouter != nil {
A
astaxie 已提交
428 429 430
		if r.Method == "POST" {
			r.ParseMultipartForm(MaxMemory)
		}
A
fix bug  
astaxie 已提交
431
		//execute middleware filters
A
astaxie 已提交
432
		if p.enableFilter {
A
astaxie 已提交
433 434 435 436
			if l, ok := p.filters["BeforExec"]; ok {
				for _, filterR := range l {
					if filterR.ValidRouter(r.URL.Path) {
						filterR.filterFunc(context)
A
astaxie 已提交
437 438 439
						if w.started {
							return
						}
A
astaxie 已提交
440
					}
A
astaxie 已提交
441
				}
A
fix bug  
astaxie 已提交
442 443 444 445 446 447
			}
		}
		//Invoke the request handler
		vc := reflect.New(runrouter.controllerType)

		//call the controller init function
A
astaxie 已提交
448
		method := vc.MethodByName("Init")
A
astaxie 已提交
449
		in := make([]reflect.Value, 3)
A
astaxie 已提交
450
		in[0] = reflect.ValueOf(context)
A
fix bug  
astaxie 已提交
451
		in[1] = reflect.ValueOf(runrouter.controllerType.Name())
A
astaxie 已提交
452
		in[2] = reflect.ValueOf(vc.Interface())
A
fix bug  
astaxie 已提交
453 454
		method.Call(in)

A
astaxie 已提交
455 456
		//if XSRF is Enable then check cookie where there has any cookie in the  request's cookie _csrf
		if EnableXSRF {
A
astaxie 已提交
457
			in = make([]reflect.Value, 0)
A
astaxie 已提交
458 459 460 461 462 463 464 465 466
			method = vc.MethodByName("XsrfToken")
			method.Call(in)
			if r.Method == "POST" || r.Method == "DELETE" || r.Method == "PUT" ||
				(r.Method == "POST" && (r.Form.Get("_method") == "delete" || r.Form.Get("_method") == "put")) {
				method = vc.MethodByName("CheckXsrfCookie")
				method.Call(in)
			}
		}

A
astaxie 已提交
467 468 469 470 471
		//call prepare function
		in = make([]reflect.Value, 0)
		method = vc.MethodByName("Prepare")
		method.Call(in)

A
fix bug  
astaxie 已提交
472 473 474
		//if response has written,yes don't run next
		if !w.started {
			if r.Method == "GET" {
A
astaxie 已提交
475 476 477 478 479 480 481 482
				if runrouter.hasMethod {
					if m, ok := runrouter.methods["get"]; ok {
						method = vc.MethodByName(m)
					} else if m, ok = runrouter.methods["*"]; ok {
						method = vc.MethodByName(m)
					} else {
						method = vc.MethodByName("Get")
					}
A
astaxie 已提交
483 484 485
				} else {
					method = vc.MethodByName("Get")
				}
A
fix bug  
astaxie 已提交
486 487
				method.Call(in)
			} else if r.Method == "HEAD" {
A
astaxie 已提交
488 489 490 491 492 493 494 495
				if runrouter.hasMethod {
					if m, ok := runrouter.methods["head"]; ok {
						method = vc.MethodByName(m)
					} else if m, ok = runrouter.methods["*"]; ok {
						method = vc.MethodByName(m)
					} else {
						method = vc.MethodByName("Head")
					}
A
astaxie 已提交
496 497 498
				} else {
					method = vc.MethodByName("Head")
				}
A
astaxie 已提交
499

A
fix bug  
astaxie 已提交
500
				method.Call(in)
A
astaxie 已提交
501
			} else if r.Method == "DELETE" || (r.Method == "POST" && r.Form.Get("_method") == "delete") {
A
astaxie 已提交
502 503 504 505 506 507 508 509
				if runrouter.hasMethod {
					if m, ok := runrouter.methods["delete"]; ok {
						method = vc.MethodByName(m)
					} else if m, ok = runrouter.methods["*"]; ok {
						method = vc.MethodByName(m)
					} else {
						method = vc.MethodByName("Delete")
					}
A
astaxie 已提交
510 511 512
				} else {
					method = vc.MethodByName("Delete")
				}
A
fix bug  
astaxie 已提交
513
				method.Call(in)
A
astaxie 已提交
514
			} else if r.Method == "PUT" || (r.Method == "POST" && r.Form.Get("_method") == "put") {
A
astaxie 已提交
515 516 517 518 519 520 521 522
				if runrouter.hasMethod {
					if m, ok := runrouter.methods["put"]; ok {
						method = vc.MethodByName(m)
					} else if m, ok = runrouter.methods["*"]; ok {
						method = vc.MethodByName(m)
					} else {
						method = vc.MethodByName("Put")
					}
A
astaxie 已提交
523 524 525
				} else {
					method = vc.MethodByName("Put")
				}
A
fix bug  
astaxie 已提交
526
				method.Call(in)
A
astaxie 已提交
527
			} else if r.Method == "POST" {
A
astaxie 已提交
528 529 530 531 532 533 534 535
				if runrouter.hasMethod {
					if m, ok := runrouter.methods["post"]; ok {
						method = vc.MethodByName(m)
					} else if m, ok = runrouter.methods["*"]; ok {
						method = vc.MethodByName(m)
					} else {
						method = vc.MethodByName("Post")
					}
A
astaxie 已提交
536 537 538
				} else {
					method = vc.MethodByName("Post")
				}
A
astaxie 已提交
539
				method.Call(in)
A
fix bug  
astaxie 已提交
540
			} else if r.Method == "PATCH" {
A
astaxie 已提交
541 542 543 544 545 546 547 548
				if runrouter.hasMethod {
					if m, ok := runrouter.methods["patch"]; ok {
						method = vc.MethodByName(m)
					} else if m, ok = runrouter.methods["*"]; ok {
						method = vc.MethodByName(m)
					} else {
						method = vc.MethodByName("Patch")
					}
A
astaxie 已提交
549 550 551
				} else {
					method = vc.MethodByName("Patch")
				}
A
fix bug  
astaxie 已提交
552 553
				method.Call(in)
			} else if r.Method == "OPTIONS" {
A
astaxie 已提交
554 555 556 557 558 559 560 561
				if runrouter.hasMethod {
					if m, ok := runrouter.methods["options"]; ok {
						method = vc.MethodByName(m)
					} else if m, ok = runrouter.methods["*"]; ok {
						method = vc.MethodByName(m)
					} else {
						method = vc.MethodByName("Options")
					}
A
astaxie 已提交
562 563 564
				} else {
					method = vc.MethodByName("Options")
				}
A
fix bug  
astaxie 已提交
565 566
				method.Call(in)
			}
A
fix #18  
astaxie 已提交
567 568 569 570 571 572 573 574 575
			gotofunc := vc.Elem().FieldByName("gotofunc").String()
			if gotofunc != "" {
				method = vc.MethodByName(gotofunc)
				if method.IsValid() {
					method.Call(in)
				} else {
					panic("gotofunc is exists:" + gotofunc)
				}
			}
A
astaxie 已提交
576
			if !w.started && !context.Input.IsWebsocket() {
A
fix bug  
astaxie 已提交
577 578 579 580 581 582
				if AutoRender {
					method = vc.MethodByName("Render")
					method.Call(in)
				}
			}
		}
A
astaxie 已提交
583

A
astaxie 已提交
584 585
		method = vc.MethodByName("Finish")
		method.Call(in)
A
astaxie 已提交
586
		//execute middleware filters
A
astaxie 已提交
587 588 589 590 591
		if p.enableFilter {
			if l, ok := p.filters["AfterExec"]; ok {
				for _, filterR := range l {
					if filterR.ValidRouter(r.URL.Path) {
						filterR.filterFunc(context)
A
astaxie 已提交
592 593 594
						if w.started {
							return
						}
A
astaxie 已提交
595
					}
A
astaxie 已提交
596 597 598
				}
			}
		}
A
astaxie 已提交
599 600
		method = vc.MethodByName("Destructor")
		method.Call(in)
A
fix bug  
astaxie 已提交
601 602
	}

A
astaxie 已提交
603 604
	//start autorouter

A
astaxie 已提交
605 606
	if p.enableAuto {
		if !findrouter {
A
astaxie 已提交
607 608 609 610 611 612 613 614
			lastindex := strings.LastIndex(requestPath, "/")
			lastsub := requestPath[lastindex+1:]
			if subindex := strings.LastIndex(lastsub, "."); subindex != -1 {
				context.Input.Param[":ext"] = lastsub[subindex+1:]
				r.URL.Query().Add(":ext", lastsub[subindex+1:])
				r.URL.RawQuery = r.URL.Query().Encode()
				requestPath = requestPath[:len(requestPath)-len(lastsub[subindex:])]
			}
A
astaxie 已提交
615
			for cName, methodmap := range p.autoRouter {
A
astaxie 已提交
616

A
astaxie 已提交
617 618 619 620
				if strings.ToLower(requestPath) == "/"+cName {
					http.Redirect(w, r, requestPath+"/", 301)
					return
				}
A
astaxie 已提交
621

A
astaxie 已提交
622 623 624 625 626 627
				if strings.ToLower(requestPath) == "/"+cName+"/" {
					requestPath = requestPath + "index"
				}
				if strings.HasPrefix(strings.ToLower(requestPath), "/"+cName+"/") {
					for mName, controllerType := range methodmap {
						if strings.HasPrefix(strings.ToLower(requestPath), "/"+cName+"/"+strings.ToLower(mName)) {
A
astaxie 已提交
628 629 630
							if r.Method == "POST" {
								r.ParseMultipartForm(MaxMemory)
							}
A
astaxie 已提交
631 632
							//execute middleware filters
							if p.enableFilter {
A
astaxie 已提交
633 634 635 636
								if l, ok := p.filters["BeforExec"]; ok {
									for _, filterR := range l {
										if filterR.ValidRouter(r.URL.Path) {
											filterR.filterFunc(context)
A
astaxie 已提交
637 638 639
											if w.started {
												return
											}
A
astaxie 已提交
640
										}
A
astaxie 已提交
641 642 643
									}
								}
							}
A
astaxie 已提交
644 645 646 647 648 649 650
							//parse params
							otherurl := requestPath[len("/"+cName+"/"+strings.ToLower(mName)):]
							if len(otherurl) > 1 {
								plist := strings.Split(otherurl, "/")
								for k, v := range plist[1:] {
									params[strconv.Itoa(k)] = v
								}
A
astaxie 已提交
651
							}
A
astaxie 已提交
652 653 654 655 656
							//Invoke the request handler
							vc := reflect.New(controllerType)

							//call the controller init function
							init := vc.MethodByName("Init")
A
astaxie 已提交
657
							in := make([]reflect.Value, 3)
A
astaxie 已提交
658
							in[0] = reflect.ValueOf(context)
A
astaxie 已提交
659
							in[1] = reflect.ValueOf(controllerType.Name())
A
astaxie 已提交
660
							in[2] = reflect.ValueOf(vc.Interface())
A
astaxie 已提交
661 662 663 664 665 666
							init.Call(in)
							//call prepare function
							in = make([]reflect.Value, 0)
							method := vc.MethodByName("Prepare")
							method.Call(in)
							method = vc.MethodByName(mName)
A
astaxie 已提交
667
							method.Call(in)
A
astaxie 已提交
668 669 670
							//if XSRF is Enable then check cookie where there has any cookie in the  request's cookie _csrf
							if EnableXSRF {
								method = vc.MethodByName("XsrfToken")
A
astaxie 已提交
671
								method.Call(in)
A
astaxie 已提交
672 673 674 675 676
								if r.Method == "POST" || r.Method == "DELETE" || r.Method == "PUT" ||
									(r.Method == "POST" && (r.Form.Get("_method") == "delete" || r.Form.Get("_method") == "put")) {
									method = vc.MethodByName("CheckXsrfCookie")
									method.Call(in)
								}
A
astaxie 已提交
677
							}
A
astaxie 已提交
678
							if !w.started && !context.Input.IsWebsocket() {
A
astaxie 已提交
679 680 681 682
								if AutoRender {
									method = vc.MethodByName("Render")
									method.Call(in)
								}
A
astaxie 已提交
683
							}
A
astaxie 已提交
684 685
							method = vc.MethodByName("Finish")
							method.Call(in)
A
astaxie 已提交
686
							//execute middleware filters
A
astaxie 已提交
687 688 689 690 691
							if p.enableFilter {
								if l, ok := p.filters["AfterExec"]; ok {
									for _, filterR := range l {
										if filterR.ValidRouter(r.URL.Path) {
											filterR.filterFunc(context)
A
astaxie 已提交
692 693 694
											if w.started {
												return
											}
A
astaxie 已提交
695
										}
A
astaxie 已提交
696 697 698
									}
								}
							}
A
astaxie 已提交
699 700 701 702
							method = vc.MethodByName("Destructor")
							method.Call(in)
							// set find
							findrouter = true
A
astaxie 已提交
703
							goto Last
A
astaxie 已提交
704 705 706 707 708 709
						}
					}
				}
			}
		}
	}
A
astaxie 已提交
710

A
astaxie 已提交
711
Last:
A
fix bug  
astaxie 已提交
712
	//if no matches to url, throw a not found exception
A
astaxie 已提交
713
	if !findrouter {
A
astaxie 已提交
714
		middleware.Exception("404", rw, r, "")
A
fix bug  
astaxie 已提交
715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744
	}
}

//responseWriter is a wrapper for the http.ResponseWriter
//started set to true if response was written to then don't execute other handler
type responseWriter struct {
	writer  http.ResponseWriter
	started bool
	status  int
}

// Header returns the header map that will be sent by WriteHeader.
func (w *responseWriter) Header() http.Header {
	return w.writer.Header()
}

// Write writes the data to the connection as part of an HTTP reply,
// and sets `started` to true
func (w *responseWriter) Write(p []byte) (int, error) {
	w.started = true
	return w.writer.Write(p)
}

// WriteHeader sends an HTTP response header with status code,
// and sets `started` to true
func (w *responseWriter) WriteHeader(code int) {
	w.status = code
	w.started = true
	w.writer.WriteHeader(code)
}