8a995912 by astaxie

fix bug

1 parent d5626878
Showing 1 changed file with 284 additions and 283 deletions
1 package beego 1 package beego
2 2
3 import ( 3 import (
4 "net/http" 4 "net/http"
5 "net/url" 5 "net/url"
6 "reflect" 6 "reflect"
7 "regexp" 7 "regexp"
8 "runtime" 8 "runtime"
9 "strings" 9 "strings"
10 ) 10 )
11 11
12 type controllerInfo struct { 12 type controllerInfo struct {
13 pattern string 13 pattern string
14 regex *regexp.Regexp 14 regex *regexp.Regexp
15 params map[int]string 15 params map[int]string
16 controllerType reflect.Type 16 controllerType reflect.Type
17 } 17 }
18 18
19 type ControllerRegistor struct { 19 type ControllerRegistor struct {
20 routers []*controllerInfo 20 routers []*controllerInfo
21 fixrouters []*controllerInfo 21 fixrouters []*controllerInfo
22 filters []http.HandlerFunc 22 filters []http.HandlerFunc
23 } 23 }
24 24
25 func NewControllerRegistor() *ControllerRegistor { 25 func NewControllerRegistor() *ControllerRegistor {
26 return &ControllerRegistor{routers: make([]*controllerInfo, 0)} 26 return &ControllerRegistor{routers: make([]*controllerInfo, 0)}
27 } 27 }
28 28
29 func (p *ControllerRegistor) Add(pattern string, c ControllerInterface) { 29 func (p *ControllerRegistor) Add(pattern string, c ControllerInterface) {
30 parts := strings.Split(pattern, "/") 30 parts := strings.Split(pattern, "/")
31 31
32 j := 0 32 j := 0
33 params := make(map[int]string) 33 params := make(map[int]string)
34 for i, part := range parts { 34 for i, part := range parts {
35 if strings.HasPrefix(part, ":") { 35 if strings.HasPrefix(part, ":") {
36 expr := "([^/]+)" 36 expr := "([^/]+)"
37 //a user may choose to override the defult expression 37 //a user may choose to override the defult expression
38 // similar to expressjs: ‘/user/:id([0-9]+)’ 38 // similar to expressjs: ‘/user/:id([0-9]+)’
39 if index := strings.Index(part, "("); index != -1 { 39 if index := strings.Index(part, "("); index != -1 {
40 expr = part[index:] 40 expr = part[index:]
41 part = part[:index] 41 part = part[:index]
42 } 42 }
43 params[j] = part 43 params[j] = part
44 parts[i] = expr 44 parts[i] = expr
45 j++ 45 j++
46 } 46 }
47 } 47 }
48 if j == 0 { 48 if j == 0 {
49 //now create the Route 49 //now create the Route
50 t := reflect.Indirect(reflect.ValueOf(c)).Type() 50 t := reflect.Indirect(reflect.ValueOf(c)).Type()
51 route := &controllerInfo{} 51 route := &controllerInfo{}
52 route.pattern = pattern 52 route.pattern = pattern
53 route.controllerType = t 53 route.controllerType = t
54 54
55 p.fixrouters = append(p.fixrouters, route) 55 p.fixrouters = append(p.fixrouters, route)
56 } else { // add regexp routers 56 } else { // add regexp routers
57 //recreate the url pattern, with parameters replaced 57 //recreate the url pattern, with parameters replaced
58 //by regular expressions. then compile the regex 58 //by regular expressions. then compile the regex
59 pattern = strings.Join(parts, "/") 59 pattern = strings.Join(parts, "/")
60 regex, regexErr := regexp.Compile(pattern) 60 regex, regexErr := regexp.Compile(pattern)
61 if regexErr != nil { 61 if regexErr != nil {
62 //TODO add error handling here to avoid panic 62 //TODO add error handling here to avoid panic
63 panic(regexErr) 63 panic(regexErr)
64 return 64 return
65 } 65 }
66 66
67 //now create the Route 67 //now create the Route
68 t := reflect.Indirect(reflect.ValueOf(c)).Type() 68 t := reflect.Indirect(reflect.ValueOf(c)).Type()
69 route := &controllerInfo{} 69 route := &controllerInfo{}
70 route.regex = regex 70 route.regex = regex
71 route.params = params 71 route.params = params
72 route.controllerType = t 72 route.pattern = pattern
73 73 route.controllerType = t
74 p.routers = append(p.routers, route) 74
75 } 75 p.routers = append(p.routers, route)
76 76 }
77 } 77
78 78 }
79 // Filter adds the middleware filter. 79
80 func (p *ControllerRegistor) Filter(filter http.HandlerFunc) { 80 // Filter adds the middleware filter.
81 p.filters = append(p.filters, filter) 81 func (p *ControllerRegistor) Filter(filter http.HandlerFunc) {
82 } 82 p.filters = append(p.filters, filter)
83 83 }
84 // FilterParam adds the middleware filter if the REST URL parameter exists. 84
85 func (p *ControllerRegistor) FilterParam(param string, filter http.HandlerFunc) { 85 // FilterParam adds the middleware filter if the REST URL parameter exists.
86 if !strings.HasPrefix(param, ":") { 86 func (p *ControllerRegistor) FilterParam(param string, filter http.HandlerFunc) {
87 param = ":" + param 87 if !strings.HasPrefix(param, ":") {
88 } 88 param = ":" + param
89 89 }
90 p.Filter(func(w http.ResponseWriter, r *http.Request) { 90
91 p := r.URL.Query().Get(param) 91 p.Filter(func(w http.ResponseWriter, r *http.Request) {
92 if len(p) > 0 { 92 p := r.URL.Query().Get(param)
93 filter(w, r) 93 if len(p) > 0 {
94 } 94 filter(w, r)
95 }) 95 }
96 } 96 })
97 97 }
98 // FilterPrefixPath adds the middleware filter if the prefix path exists. 98
99 func (p *ControllerRegistor) FilterPrefixPath(path string, filter http.HandlerFunc) { 99 // FilterPrefixPath adds the middleware filter if the prefix path exists.
100 p.Filter(func(w http.ResponseWriter, r *http.Request) { 100 func (p *ControllerRegistor) FilterPrefixPath(path string, filter http.HandlerFunc) {
101 if strings.HasPrefix(r.URL.Path, path) { 101 p.Filter(func(w http.ResponseWriter, r *http.Request) {
102 filter(w, r) 102 if strings.HasPrefix(r.URL.Path, path) {
103 } 103 filter(w, r)
104 }) 104 }
105 } 105 })
106 106 }
107 // AutoRoute 107
108 func (p *ControllerRegistor) ServeHTTP(rw http.ResponseWriter, r *http.Request) { 108 // AutoRoute
109 defer func() { 109 func (p *ControllerRegistor) ServeHTTP(rw http.ResponseWriter, r *http.Request) {
110 if err := recover(); err != nil { 110 defer func() {
111 if !RecoverPanic { 111 if err := recover(); err != nil {
112 // go back to panic 112 if !RecoverPanic {
113 panic(err) 113 // go back to panic
114 } else { 114 panic(err)
115 Critical("Handler crashed with error", err) 115 } else {
116 for i := 1; ; i += 1 { 116 Critical("Handler crashed with error", err)
117 _, file, line, ok := runtime.Caller(i) 117 for i := 1; ; i += 1 {
118 if !ok { 118 _, file, line, ok := runtime.Caller(i)
119 break 119 if !ok {
120 } 120 break
121 Critical(file, line) 121 }
122 } 122 Critical(file, line)
123 } 123 }
124 } 124 }
125 }() 125 }
126 w := &responseWriter{writer: rw} 126 }()
127 127 w := &responseWriter{writer: rw}
128 var runrouter *controllerInfo 128
129 var findrouter bool 129 var runrouter *controllerInfo
130 130 var findrouter bool
131 params := make(map[string]string) 131
132 132 params := make(map[string]string)
133 //static file server 133
134 for prefix, staticDir := range StaticDir { 134 //static file server
135 if strings.HasPrefix(r.URL.Path, prefix) { 135 for prefix, staticDir := range StaticDir {
136 file := staticDir + r.URL.Path[len(prefix):] 136 if strings.HasPrefix(r.URL.Path, prefix) {
137 http.ServeFile(w, r, file) 137 file := staticDir + r.URL.Path[len(prefix):]
138 w.started = true 138 http.ServeFile(w, r, file)
139 return 139 w.started = true
140 } 140 return
141 } 141 }
142 142 }
143 requestPath := r.URL.Path 143
144 144 requestPath := r.URL.Path
145 //first find path from the fixrouters to Improve Performance 145
146 for _, route := range p.fixrouters { 146 //first find path from the fixrouters to Improve Performance
147 n := len(requestPath) 147 for _, route := range p.fixrouters {
148 if (requestPath[n-1] != '/' && route.pattern == requestPath) || 148 n := len(requestPath)
149 (len(route.pattern) >= n && requestPath[0:n] == route.pattern) { 149 if (requestPath[n-1] != '/' && route.pattern == requestPath) ||
150 runrouter = route 150 (len(route.pattern) >= n && requestPath[0:n-1] == route.pattern) {
151 findrouter = true 151 runrouter = route
152 break 152 findrouter = true
153 } 153 break
154 } 154 }
155 155 }
156 if !findrouter { 156
157 //find a matching Route 157 if !findrouter {
158 for _, route := range p.routers { 158 //find a matching Route
159 159 for _, route := range p.routers {
160 //check if Route pattern matches url 160
161 if !route.regex.MatchString(requestPath) { 161 //check if Route pattern matches url
162 continue 162 if !route.regex.MatchString(requestPath) {
163 } 163 continue
164 164 }
165 //get submatches (params) 165
166 matches := route.regex.FindStringSubmatch(requestPath) 166 //get submatches (params)
167 167 matches := route.regex.FindStringSubmatch(requestPath)
168 //double check that the Route matches the URL pattern. 168
169 if len(matches[0]) != len(requestPath) { 169 //double check that the Route matches the URL pattern.
170 continue 170 if len(matches[0]) != len(requestPath) {
171 } 171 continue
172 172 }
173 if len(route.params) > 0 { 173
174 //add url parameters to the query param map 174 if len(route.params) > 0 {
175 values := r.URL.Query() 175 //add url parameters to the query param map
176 for i, match := range matches[1:] { 176 values := r.URL.Query()
177 values.Add(route.params[i], match) 177 for i, match := range matches[1:] {
178 params[route.params[i]] = match 178 values.Add(route.params[i], match)
179 } 179 params[route.params[i]] = match
180 //reassemble query params and add to RawQuery 180 }
181 r.URL.RawQuery = url.Values(values).Encode() + "&" + r.URL.RawQuery 181 //reassemble query params and add to RawQuery
182 //r.URL.RawQuery = url.Values(values).Encode() 182 r.URL.RawQuery = url.Values(values).Encode() + "&" + r.URL.RawQuery
183 } 183 //r.URL.RawQuery = url.Values(values).Encode()
184 runrouter = route 184 }
185 findrouter = true 185 runrouter = route
186 break 186 findrouter = true
187 } 187 break
188 } 188 }
189 189 }
190 if runrouter != nil { 190
191 //execute middleware filters 191 if runrouter != nil {
192 for _, filter := range p.filters { 192 //execute middleware filters
193 filter(w, r) 193 for _, filter := range p.filters {
194 if w.started { 194 filter(w, r)
195 return 195 if w.started {
196 } 196 return
197 } 197 }
198 198 }
199 //Invoke the request handler 199
200 vc := reflect.New(runrouter.controllerType) 200 //Invoke the request handler
201 201 vc := reflect.New(runrouter.controllerType)
202 //call the controller init function 202
203 init := vc.MethodByName("Init") 203 //call the controller init function
204 in := make([]reflect.Value, 2) 204 init := vc.MethodByName("Init")
205 ct := &Context{ResponseWriter: w, Request: r, Params: params} 205 in := make([]reflect.Value, 2)
206 in[0] = reflect.ValueOf(ct) 206 ct := &Context{ResponseWriter: w, Request: r, Params: params}
207 in[1] = reflect.ValueOf(runrouter.controllerType.Name()) 207 in[0] = reflect.ValueOf(ct)
208 init.Call(in) 208 in[1] = reflect.ValueOf(runrouter.controllerType.Name())
209 //call prepare function 209 init.Call(in)
210 in = make([]reflect.Value, 0) 210 //call prepare function
211 method := vc.MethodByName("Prepare") 211 in = make([]reflect.Value, 0)
212 method.Call(in) 212 method := vc.MethodByName("Prepare")
213 213 method.Call(in)
214 //if response has written,yes don't run next 214
215 if !w.started { 215 //if response has written,yes don't run next
216 if r.Method == "GET" { 216 if !w.started {
217 method = vc.MethodByName("Get") 217 if r.Method == "GET" {
218 method.Call(in) 218 method = vc.MethodByName("Get")
219 } else if r.Method == "POST" { 219 method.Call(in)
220 method = vc.MethodByName("Post") 220 } else if r.Method == "POST" {
221 method.Call(in) 221 method = vc.MethodByName("Post")
222 } else if r.Method == "HEAD" { 222 method.Call(in)
223 method = vc.MethodByName("Head") 223 } else if r.Method == "HEAD" {
224 method.Call(in) 224 method = vc.MethodByName("Head")
225 } else if r.Method == "DELETE" { 225 method.Call(in)
226 method = vc.MethodByName("Delete") 226 } else if r.Method == "DELETE" {
227 method.Call(in) 227 method = vc.MethodByName("Delete")
228 } else if r.Method == "PUT" { 228 method.Call(in)
229 method = vc.MethodByName("Put") 229 } else if r.Method == "PUT" {
230 method.Call(in) 230 method = vc.MethodByName("Put")
231 } else if r.Method == "PATCH" { 231 method.Call(in)
232 method = vc.MethodByName("Patch") 232 } else if r.Method == "PATCH" {
233 method.Call(in) 233 method = vc.MethodByName("Patch")
234 } else if r.Method == "OPTIONS" { 234 method.Call(in)
235 method = vc.MethodByName("Options") 235 } else if r.Method == "OPTIONS" {
236 method.Call(in) 236 method = vc.MethodByName("Options")
237 } 237 method.Call(in)
238 if !w.started { 238 }
239 if AutoRender { 239 if !w.started {
240 method = vc.MethodByName("Render") 240 if AutoRender {
241 method.Call(in) 241 method = vc.MethodByName("Render")
242 } 242 method.Call(in)
243 if !w.started { 243 }
244 method = vc.MethodByName("Finish") 244 if !w.started {
245 method.Call(in) 245 method = vc.MethodByName("Finish")
246 } 246 method.Call(in)
247 } 247 }
248 } 248 }
249 } 249 }
250 250 }
251 //if no matches to url, throw a not found exception 251
252 if w.started == false { 252 //if no matches to url, throw a not found exception
253 http.NotFound(w, r) 253 if w.started == false {
254 } 254 http.NotFound(w, r)
255 } 255 }
256 256 }
257 //responseWriter is a wrapper for the http.ResponseWriter 257
258 //started set to true if response was written to then don't execute other handler 258 //responseWriter is a wrapper for the http.ResponseWriter
259 type responseWriter struct { 259 //started set to true if response was written to then don't execute other handler
260 writer http.ResponseWriter 260 type responseWriter struct {
261 started bool 261 writer http.ResponseWriter
262 status int 262 started bool
263 } 263 status int
264 264 }
265 // Header returns the header map that will be sent by WriteHeader. 265
266 func (w *responseWriter) Header() http.Header { 266 // Header returns the header map that will be sent by WriteHeader.
267 return w.writer.Header() 267 func (w *responseWriter) Header() http.Header {
268 } 268 return w.writer.Header()
269 269 }
270 // Write writes the data to the connection as part of an HTTP reply, 270
271 // and sets `started` to true 271 // Write writes the data to the connection as part of an HTTP reply,
272 func (w *responseWriter) Write(p []byte) (int, error) { 272 // and sets `started` to true
273 w.started = true 273 func (w *responseWriter) Write(p []byte) (int, error) {
274 return w.writer.Write(p) 274 w.started = true
275 } 275 return w.writer.Write(p)
276 276 }
277 // WriteHeader sends an HTTP response header with status code, 277
278 // and sets `started` to true 278 // WriteHeader sends an HTTP response header with status code,
279 func (w *responseWriter) WriteHeader(code int) { 279 // and sets `started` to true
280 w.status = code 280 func (w *responseWriter) WriteHeader(code int) {
281 w.started = true 281 w.status = code
282 w.writer.WriteHeader(code) 282 w.started = true
283 } 283 w.writer.WriteHeader(code)
284 }
......
Styling with Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!