1f3ae3d6 by astaxie

Improve performance

1 parent ca1354e7
Showing 1 changed file with 159 additions and 116 deletions
...@@ -22,6 +22,7 @@ type controllerInfo struct { ...@@ -22,6 +22,7 @@ type controllerInfo struct {
22 params map[int]string 22 params map[int]string
23 controllerType reflect.Type 23 controllerType reflect.Type
24 methods map[string]string 24 methods map[string]string
25 hasMethod bool
25 } 26 }
26 27
27 type userHandler struct { 28 type userHandler struct {
...@@ -34,8 +35,12 @@ type userHandler struct { ...@@ -34,8 +35,12 @@ type userHandler struct {
34 type ControllerRegistor struct { 35 type ControllerRegistor struct {
35 routers []*controllerInfo 36 routers []*controllerInfo
36 fixrouters []*controllerInfo 37 fixrouters []*controllerInfo
38 enableFilter bool
37 filters []http.HandlerFunc 39 filters []http.HandlerFunc
40 afterFilters []http.HandlerFunc
41 enableUser bool
38 userHandlers map[string]*userHandler 42 userHandlers map[string]*userHandler
43 enableAuto bool
39 autoRouter map[string]map[string]reflect.Type //key:controller key:method value:reflect.type 44 autoRouter map[string]map[string]reflect.Type //key:controller key:method value:reflect.type
40 } 45 }
41 46
...@@ -130,6 +135,9 @@ func (p *ControllerRegistor) Add(pattern string, c ControllerInterface, mappingM ...@@ -130,6 +135,9 @@ func (p *ControllerRegistor) Add(pattern string, c ControllerInterface, mappingM
130 route.pattern = pattern 135 route.pattern = pattern
131 route.controllerType = t 136 route.controllerType = t
132 route.methods = methods 137 route.methods = methods
138 if len(methods) > 0 {
139 route.hasMethod = true
140 }
133 p.fixrouters = append(p.fixrouters, route) 141 p.fixrouters = append(p.fixrouters, route)
134 } else { // add regexp routers 142 } else { // add regexp routers
135 //recreate the url pattern, with parameters replaced 143 //recreate the url pattern, with parameters replaced
...@@ -149,12 +157,16 @@ func (p *ControllerRegistor) Add(pattern string, c ControllerInterface, mappingM ...@@ -149,12 +157,16 @@ func (p *ControllerRegistor) Add(pattern string, c ControllerInterface, mappingM
149 route.params = params 157 route.params = params
150 route.pattern = pattern 158 route.pattern = pattern
151 route.methods = methods 159 route.methods = methods
160 if len(methods) > 0 {
161 route.hasMethod = true
162 }
152 route.controllerType = t 163 route.controllerType = t
153 p.routers = append(p.routers, route) 164 p.routers = append(p.routers, route)
154 } 165 }
155 } 166 }
156 167
157 func (p *ControllerRegistor) AddAuto(c ControllerInterface) { 168 func (p *ControllerRegistor) AddAuto(c ControllerInterface) {
169 p.enableAuto = true
158 reflectVal := reflect.ValueOf(c) 170 reflectVal := reflect.ValueOf(c)
159 rt := reflectVal.Type() 171 rt := reflectVal.Type()
160 ct := reflect.Indirect(reflectVal).Type() 172 ct := reflect.Indirect(reflectVal).Type()
...@@ -170,6 +182,7 @@ func (p *ControllerRegistor) AddAuto(c ControllerInterface) { ...@@ -170,6 +182,7 @@ func (p *ControllerRegistor) AddAuto(c ControllerInterface) {
170 } 182 }
171 183
172 func (p *ControllerRegistor) AddHandler(pattern string, c http.Handler) { 184 func (p *ControllerRegistor) AddHandler(pattern string, c http.Handler) {
185 p.enableUser = true
173 parts := strings.Split(pattern, "/") 186 parts := strings.Split(pattern, "/")
174 187
175 j := 0 188 j := 0
...@@ -217,6 +230,7 @@ func (p *ControllerRegistor) AddHandler(pattern string, c http.Handler) { ...@@ -217,6 +230,7 @@ func (p *ControllerRegistor) AddHandler(pattern string, c http.Handler) {
217 230
218 // Filter adds the middleware filter. 231 // Filter adds the middleware filter.
219 func (p *ControllerRegistor) Filter(filter http.HandlerFunc) { 232 func (p *ControllerRegistor) Filter(filter http.HandlerFunc) {
233 p.enableFilter = true
220 p.filters = append(p.filters, filter) 234 p.filters = append(p.filters, filter)
221 } 235 }
222 236
...@@ -332,52 +346,48 @@ func (p *ControllerRegistor) ServeHTTP(rw http.ResponseWriter, r *http.Request) ...@@ -332,52 +346,48 @@ func (p *ControllerRegistor) ServeHTTP(rw http.ResponseWriter, r *http.Request)
332 r.ParseMultipartForm(MaxMemory) 346 r.ParseMultipartForm(MaxMemory)
333 347
334 //user defined Handler 348 //user defined Handler
335 for pattern, c := range p.userHandlers { 349 if p.enableUser {
336 if c.regex == nil && pattern == requestPath { 350 for pattern, c := range p.userHandlers {
337 c.h.ServeHTTP(rw, r) 351 if c.regex == nil && pattern == requestPath {
338 return 352 c.h.ServeHTTP(rw, r)
339 } else if c.regex == nil { 353 return
340 continue 354 } else if c.regex == nil {
341 } 355 continue
356 }
342 357
343 //check if Route pattern matches url 358 //check if Route pattern matches url
344 if !c.regex.MatchString(requestPath) { 359 if !c.regex.MatchString(requestPath) {
345 continue 360 continue
346 } 361 }
347 362
348 //get submatches (params) 363 //get submatches (params)
349 matches := c.regex.FindStringSubmatch(requestPath) 364 matches := c.regex.FindStringSubmatch(requestPath)
350 365
351 //double check that the Route matches the URL pattern. 366 //double check that the Route matches the URL pattern.
352 if len(matches[0]) != len(requestPath) { 367 if len(matches[0]) != len(requestPath) {
353 continue 368 continue
354 } 369 }
355 370
356 if len(c.params) > 0 { 371 if len(c.params) > 0 {
357 //add url parameters to the query param map 372 //add url parameters to the query param map
358 values := r.URL.Query() 373 values := r.URL.Query()
359 for i, match := range matches[1:] { 374 for i, match := range matches[1:] {
360 values.Add(c.params[i], match) 375 values.Add(c.params[i], match)
361 r.Form.Add(c.params[i], match) 376 r.Form.Add(c.params[i], match)
362 params[c.params[i]] = match 377 params[c.params[i]] = match
378 }
379 //reassemble query params and add to RawQuery
380 r.URL.RawQuery = url.Values(values).Encode() + "&" + r.URL.RawQuery
381 //r.URL.RawQuery = url.Values(values).Encode()
363 } 382 }
364 //reassemble query params and add to RawQuery 383 c.h.ServeHTTP(rw, r)
365 r.URL.RawQuery = url.Values(values).Encode() + "&" + r.URL.RawQuery 384 return
366 //r.URL.RawQuery = url.Values(values).Encode()
367 } 385 }
368 c.h.ServeHTTP(rw, r)
369 return
370 } 386 }
371 387
372 //first find path from the fixrouters to Improve Performance 388 //first find path from the fixrouters to Improve Performance
373 for _, route := range p.fixrouters { 389 for _, route := range p.fixrouters {
374 n := len(requestPath) 390 n := len(requestPath)
375 //route like "/"
376 //if n == 1 {
377 // else {
378 // continue
379 // }
380 //}
381 if requestPath == route.pattern { 391 if requestPath == route.pattern {
382 runrouter = route 392 runrouter = route
383 findrouter = true 393 findrouter = true
...@@ -392,6 +402,7 @@ func (p *ControllerRegistor) ServeHTTP(rw http.ResponseWriter, r *http.Request) ...@@ -392,6 +402,7 @@ func (p *ControllerRegistor) ServeHTTP(rw http.ResponseWriter, r *http.Request)
392 } 402 }
393 } 403 }
394 404
405 //find regex's router
395 if !findrouter { 406 if !findrouter {
396 //find a matching Route 407 //find a matching Route
397 for _, route := range p.routers { 408 for _, route := range p.routers {
...@@ -466,64 +477,93 @@ func (p *ControllerRegistor) ServeHTTP(rw http.ResponseWriter, r *http.Request) ...@@ -466,64 +477,93 @@ func (p *ControllerRegistor) ServeHTTP(rw http.ResponseWriter, r *http.Request)
466 //if response has written,yes don't run next 477 //if response has written,yes don't run next
467 if !w.started { 478 if !w.started {
468 if r.Method == "GET" { 479 if r.Method == "GET" {
469 if m, ok := runrouter.methods["get"]; ok { 480 if runrouter.hasMethod {
470 method = vc.MethodByName(m) 481 if m, ok := runrouter.methods["get"]; ok {
471 } else if m, ok = runrouter.methods["*"]; ok { 482 method = vc.MethodByName(m)
472 method = vc.MethodByName(m) 483 } else if m, ok = runrouter.methods["*"]; ok {
484 method = vc.MethodByName(m)
485 } else {
486 method = vc.MethodByName("Get")
487 }
473 } else { 488 } else {
474 method = vc.MethodByName("Get") 489 method = vc.MethodByName("Get")
475 } 490 }
476 method.Call(in) 491 method.Call(in)
477 } else if r.Method == "HEAD" { 492 } else if r.Method == "HEAD" {
478 if m, ok := runrouter.methods["head"]; ok { 493 if runrouter.hasMethod {
479 method = vc.MethodByName(m) 494 if m, ok := runrouter.methods["head"]; ok {
480 } else if m, ok = runrouter.methods["*"]; ok { 495 method = vc.MethodByName(m)
481 method = vc.MethodByName(m) 496 } else if m, ok = runrouter.methods["*"]; ok {
497 method = vc.MethodByName(m)
498 } else {
499 method = vc.MethodByName("Head")
500 }
482 } else { 501 } else {
483 method = vc.MethodByName("Head") 502 method = vc.MethodByName("Head")
484 } 503 }
504
485 method.Call(in) 505 method.Call(in)
486 } else if r.Method == "DELETE" || (r.Method == "POST" && r.Form.Get("_method") == "delete") { 506 } else if r.Method == "DELETE" || (r.Method == "POST" && r.Form.Get("_method") == "delete") {
487 if m, ok := runrouter.methods["delete"]; ok { 507 if runrouter.hasMethod {
488 method = vc.MethodByName(m) 508 if m, ok := runrouter.methods["delete"]; ok {
489 } else if m, ok = runrouter.methods["*"]; ok { 509 method = vc.MethodByName(m)
490 method = vc.MethodByName(m) 510 } else if m, ok = runrouter.methods["*"]; ok {
511 method = vc.MethodByName(m)
512 } else {
513 method = vc.MethodByName("Delete")
514 }
491 } else { 515 } else {
492 method = vc.MethodByName("Delete") 516 method = vc.MethodByName("Delete")
493 } 517 }
494 method.Call(in) 518 method.Call(in)
495 } else if r.Method == "PUT" || (r.Method == "POST" && r.Form.Get("_method") == "put") { 519 } else if r.Method == "PUT" || (r.Method == "POST" && r.Form.Get("_method") == "put") {
496 if m, ok := runrouter.methods["put"]; ok { 520 if runrouter.hasMethod {
497 method = vc.MethodByName(m) 521 if m, ok := runrouter.methods["put"]; ok {
498 } else if m, ok = runrouter.methods["*"]; ok { 522 method = vc.MethodByName(m)
499 method = vc.MethodByName(m) 523 } else if m, ok = runrouter.methods["*"]; ok {
524 method = vc.MethodByName(m)
525 } else {
526 method = vc.MethodByName("Put")
527 }
500 } else { 528 } else {
501 method = vc.MethodByName("Put") 529 method = vc.MethodByName("Put")
502 } 530 }
503 method.Call(in) 531 method.Call(in)
504 } else if r.Method == "POST" { 532 } else if r.Method == "POST" {
505 if m, ok := runrouter.methods["post"]; ok { 533 if runrouter.hasMethod {
506 method = vc.MethodByName(m) 534 if m, ok := runrouter.methods["post"]; ok {
507 } else if m, ok = runrouter.methods["*"]; ok { 535 method = vc.MethodByName(m)
508 method = vc.MethodByName(m) 536 } else if m, ok = runrouter.methods["*"]; ok {
537 method = vc.MethodByName(m)
538 } else {
539 method = vc.MethodByName("Post")
540 }
509 } else { 541 } else {
510 method = vc.MethodByName("Post") 542 method = vc.MethodByName("Post")
511 } 543 }
512 method.Call(in) 544 method.Call(in)
513 } else if r.Method == "PATCH" { 545 } else if r.Method == "PATCH" {
514 if m, ok := runrouter.methods["patch"]; ok { 546 if runrouter.hasMethod {
515 method = vc.MethodByName(m) 547 if m, ok := runrouter.methods["patch"]; ok {
516 } else if m, ok = runrouter.methods["*"]; ok { 548 method = vc.MethodByName(m)
517 method = vc.MethodByName(m) 549 } else if m, ok = runrouter.methods["*"]; ok {
550 method = vc.MethodByName(m)
551 } else {
552 method = vc.MethodByName("Patch")
553 }
518 } else { 554 } else {
519 method = vc.MethodByName("Patch") 555 method = vc.MethodByName("Patch")
520 } 556 }
521 method.Call(in) 557 method.Call(in)
522 } else if r.Method == "OPTIONS" { 558 } else if r.Method == "OPTIONS" {
523 if m, ok := runrouter.methods["options"]; ok { 559 if runrouter.hasMethod {
524 method = vc.MethodByName(m) 560 if m, ok := runrouter.methods["options"]; ok {
525 } else if m, ok = runrouter.methods["*"]; ok { 561 method = vc.MethodByName(m)
526 method = vc.MethodByName(m) 562 } else if m, ok = runrouter.methods["*"]; ok {
563 method = vc.MethodByName(m)
564 } else {
565 method = vc.MethodByName("Options")
566 }
527 } else { 567 } else {
528 method = vc.MethodByName("Options") 568 method = vc.MethodByName("Options")
529 } 569 }
...@@ -553,72 +593,75 @@ func (p *ControllerRegistor) ServeHTTP(rw http.ResponseWriter, r *http.Request) ...@@ -553,72 +593,75 @@ func (p *ControllerRegistor) ServeHTTP(rw http.ResponseWriter, r *http.Request)
553 593
554 //start autorouter 594 //start autorouter
555 595
556 if !findrouter { 596 if p.enableAuto {
557 for cName, methodmap := range p.autoRouter { 597 if !findrouter {
598 for cName, methodmap := range p.autoRouter {
558 599
559 if strings.ToLower(requestPath) == "/"+cName { 600 if strings.ToLower(requestPath) == "/"+cName {
560 http.Redirect(w, r, requestPath+"/", 301) 601 http.Redirect(w, r, requestPath+"/", 301)
561 return 602 return
562 } 603 }
563 604
564 if strings.ToLower(requestPath) == "/"+cName+"/" { 605 if strings.ToLower(requestPath) == "/"+cName+"/" {
565 requestPath = requestPath + "index" 606 requestPath = requestPath + "index"
566 } 607 }
567 if strings.HasPrefix(strings.ToLower(requestPath), "/"+cName+"/") { 608 if strings.HasPrefix(strings.ToLower(requestPath), "/"+cName+"/") {
568 for mName, controllerType := range methodmap { 609 for mName, controllerType := range methodmap {
569 if strings.HasPrefix(strings.ToLower(requestPath), "/"+cName+"/"+strings.ToLower(mName)) { 610 if strings.HasPrefix(strings.ToLower(requestPath), "/"+cName+"/"+strings.ToLower(mName)) {
570 //parse params 611 //parse params
571 otherurl := requestPath[len("/"+cName+"/"+strings.ToLower(mName)):] 612 otherurl := requestPath[len("/"+cName+"/"+strings.ToLower(mName)):]
572 if len(otherurl) > 1 { 613 if len(otherurl) > 1 {
573 plist := strings.Split(otherurl, "/") 614 plist := strings.Split(otherurl, "/")
574 for k, v := range plist[1:] { 615 for k, v := range plist[1:] {
575 params[strconv.Itoa(k)] = v 616 params[strconv.Itoa(k)] = v
617 }
576 } 618 }
577 } 619 //Invoke the request handler
578 //Invoke the request handler 620 vc := reflect.New(controllerType)
579 vc := reflect.New(controllerType) 621
580 622 //call the controller init function
581 //call the controller init function 623 init := vc.MethodByName("Init")
582 init := vc.MethodByName("Init") 624 in := make([]reflect.Value, 2)
583 in := make([]reflect.Value, 2) 625 ct := &Context{ResponseWriter: w, Request: r, Params: params, RequestBody: requestbody}
584 ct := &Context{ResponseWriter: w, Request: r, Params: params, RequestBody: requestbody} 626
585 627 in[0] = reflect.ValueOf(ct)
586 in[0] = reflect.ValueOf(ct) 628 in[1] = reflect.ValueOf(controllerType.Name())
587 in[1] = reflect.ValueOf(controllerType.Name()) 629 init.Call(in)
588 init.Call(in) 630 //call prepare function
589 //call prepare function 631 in = make([]reflect.Value, 0)
590 in = make([]reflect.Value, 0) 632 method := vc.MethodByName("Prepare")
591 method := vc.MethodByName("Prepare") 633 method.Call(in)
592 method.Call(in) 634 method = vc.MethodByName(mName)
593 method = vc.MethodByName(mName)
594 method.Call(in)
595 //if XSRF is Enable then check cookie where there has any cookie in the request's cookie _csrf
596 if EnableXSRF {
597 method = vc.MethodByName("XsrfToken")
598 method.Call(in) 635 method.Call(in)
599 if r.Method == "POST" || r.Method == "DELETE" || r.Method == "PUT" || 636 //if XSRF is Enable then check cookie where there has any cookie in the request's cookie _csrf
600 (r.Method == "POST" && (r.Form.Get("_method") == "delete" || r.Form.Get("_method") == "put")) { 637 if EnableXSRF {
601 method = vc.MethodByName("CheckXsrfCookie") 638 method = vc.MethodByName("XsrfToken")
602 method.Call(in) 639 method.Call(in)
640 if r.Method == "POST" || r.Method == "DELETE" || r.Method == "PUT" ||
641 (r.Method == "POST" && (r.Form.Get("_method") == "delete" || r.Form.Get("_method") == "put")) {
642 method = vc.MethodByName("CheckXsrfCookie")
643 method.Call(in)
644 }
603 } 645 }
604 } 646 if !w.started {
605 if !w.started { 647 if AutoRender {
606 if AutoRender { 648 method = vc.MethodByName("Render")
607 method = vc.MethodByName("Render") 649 method.Call(in)
608 method.Call(in) 650 }
609 } 651 }
652 method = vc.MethodByName("Finish")
653 method.Call(in)
654 method = vc.MethodByName("Destructor")
655 method.Call(in)
656 // set find
657 findrouter = true
610 } 658 }
611 method = vc.MethodByName("Finish")
612 method.Call(in)
613 method = vc.MethodByName("Destructor")
614 method.Call(in)
615 // set find
616 findrouter = true
617 } 659 }
618 } 660 }
619 } 661 }
620 } 662 }
621 } 663 }
664
622 //if no matches to url, throw a not found exception 665 //if no matches to url, throw a not found exception
623 if !findrouter { 666 if !findrouter {
624 if h, ok := ErrorMaps["404"]; ok { 667 if h, ok := ErrorMaps["404"]; ok {
......
Styling with Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!