github.com/hellobchain/third_party@v0.0.0-20230331131523-deb0478a2e52/gorilla/mux/mux.go (about) 1 // Copyright 2012 The Gorilla Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package mux 6 7 import ( 8 "errors" 9 "fmt" 10 "github.com/hellobchain/newcryptosm/http" 11 12 "path" 13 "regexp" 14 ) 15 16 var ( 17 // ErrMethodMismatch is returned when the method in the request does not match 18 // the method defined against the route. 19 ErrMethodMismatch = errors.New("method is not allowed") 20 // ErrNotFound is returned when no route match is found. 21 ErrNotFound = errors.New("no matching route was found") 22 ) 23 24 // NewRouter returns a new router instance. 25 func NewRouter() *Router { 26 return &Router{namedRoutes: make(map[string]*Route)} 27 } 28 29 // Router registers routes to be matched and dispatches a handler. 30 // 31 // It implements the http.Handler interface, so it can be registered to serve 32 // requests: 33 // 34 // var router = mux.NewRouter() 35 // 36 // func main() { 37 // http.Handle("/", router) 38 // } 39 // 40 // Or, for Google App Engine, register it in a init() function: 41 // 42 // func init() { 43 // http.Handle("/", router) 44 // } 45 // 46 // This will send all incoming requests to the router. 47 type Router struct { 48 // Configurable Handler to be used when no route matches. 49 NotFoundHandler http.Handler 50 51 // Configurable Handler to be used when the request method does not match the route. 52 MethodNotAllowedHandler http.Handler 53 54 // Routes to be matched, in order. 55 routes []*Route 56 57 // Routes by name for URL building. 58 namedRoutes map[string]*Route 59 60 // If true, do not clear the request context after handling the request. 61 // 62 // Deprecated: No effect when go1.7+ is used, since the context is stored 63 // on the request itself. 64 KeepContext bool 65 66 // Slice of middlewares to be called after a match is found 67 middlewares []middleware 68 69 // configuration shared with `Route` 70 routeConf 71 } 72 73 // common route configuration shared between `Router` and `Route` 74 type routeConf struct { 75 // If true, "/path/foo%2Fbar/to" will match the path "/path/{var}/to" 76 useEncodedPath bool 77 78 // If true, when the path pattern is "/path/", accessing "/path" will 79 // redirect to the former and vice versa. 80 strictSlash bool 81 82 // If true, when the path pattern is "/path//to", accessing "/path//to" 83 // will not redirect 84 skipClean bool 85 86 // Manager for the variables from host and path. 87 regexp routeRegexpGroup 88 89 // List of matchers. 90 matchers []matcher 91 92 // The scheme used when building URLs. 93 buildScheme string 94 95 buildVarsFunc BuildVarsFunc 96 } 97 98 // returns an effective deep copy of `routeConf` 99 func copyRouteConf(r routeConf) routeConf { 100 c := r 101 102 if r.regexp.path != nil { 103 c.regexp.path = copyRouteRegexp(r.regexp.path) 104 } 105 106 if r.regexp.host != nil { 107 c.regexp.host = copyRouteRegexp(r.regexp.host) 108 } 109 110 c.regexp.queries = make([]*routeRegexp, 0, len(r.regexp.queries)) 111 for _, q := range r.regexp.queries { 112 c.regexp.queries = append(c.regexp.queries, copyRouteRegexp(q)) 113 } 114 115 c.matchers = make([]matcher, 0, len(r.matchers)) 116 for _, m := range r.matchers { 117 c.matchers = append(c.matchers, m) 118 } 119 120 return c 121 } 122 123 func copyRouteRegexp(r *routeRegexp) *routeRegexp { 124 c := *r 125 return &c 126 } 127 128 // Match attempts to match the given request against the router's registered routes. 129 // 130 // If the request matches a route of this router or one of its subrouters the Route, 131 // Handler, and Vars fields of the the match argument are filled and this function 132 // returns true. 133 // 134 // If the request does not match any of this router's or its subrouters' routes 135 // then this function returns false. If available, a reason for the match failure 136 // will be filled in the match argument's MatchErr field. If the match failure type 137 // (eg: not found) has a registered handler, the handler is assigned to the Handler 138 // field of the match argument. 139 func (r *Router) Match(req *http.Request, match *RouteMatch) bool { 140 for _, route := range r.routes { 141 if route.Match(req, match) { 142 // Build middleware chain if no error was found 143 if match.MatchErr == nil { 144 for i := len(r.middlewares) - 1; i >= 0; i-- { 145 match.Handler = r.middlewares[i].Middleware(match.Handler) 146 } 147 } 148 return true 149 } 150 } 151 152 if match.MatchErr == ErrMethodMismatch { 153 if r.MethodNotAllowedHandler != nil { 154 match.Handler = r.MethodNotAllowedHandler 155 return true 156 } 157 158 return false 159 } 160 161 // Closest match for a router (includes sub-routers) 162 if r.NotFoundHandler != nil { 163 match.Handler = r.NotFoundHandler 164 match.MatchErr = ErrNotFound 165 return true 166 } 167 168 match.MatchErr = ErrNotFound 169 return false 170 } 171 172 // ServeHTTP dispatches the handler registered in the matched route. 173 // 174 // When there is a match, the route variables can be retrieved calling 175 // mux.Vars(request). 176 func (r *Router) ServeHTTP(w http.ResponseWriter, req *http.Request) { 177 if !r.skipClean { 178 path := req.URL.Path 179 if r.useEncodedPath { 180 path = req.URL.EscapedPath() 181 } 182 // Clean path to canonical form and redirect. 183 if p := cleanPath(path); p != path { 184 185 // Added 3 lines (Philip Schlump) - It was dropping the query string and #whatever from query. 186 // This matches with fix in go 1.2 r.c. 4 for same problem. Go Issue: 187 // http://code.google.com/p/go/issues/detail?id=5252 188 url := *req.URL 189 url.Path = p 190 p = url.String() 191 192 w.Header().Set("Location", p) 193 w.WriteHeader(http.StatusMovedPermanently) 194 return 195 } 196 } 197 var match RouteMatch 198 var handler http.Handler 199 if r.Match(req, &match) { 200 handler = match.Handler 201 req = setVars(req, match.Vars) 202 req = setCurrentRoute(req, match.Route) 203 } 204 205 if handler == nil && match.MatchErr == ErrMethodMismatch { 206 handler = methodNotAllowedHandler() 207 } 208 209 if handler == nil { 210 handler = http.NotFoundHandler() 211 } 212 213 handler.ServeHTTP(w, req) 214 } 215 216 // Get returns a route registered with the given name. 217 func (r *Router) Get(name string) *Route { 218 return r.namedRoutes[name] 219 } 220 221 // GetRoute returns a route registered with the given name. This method 222 // was renamed to Get() and remains here for backwards compatibility. 223 func (r *Router) GetRoute(name string) *Route { 224 return r.namedRoutes[name] 225 } 226 227 // StrictSlash defines the trailing slash behavior for new routes. The initial 228 // value is false. 229 // 230 // When true, if the route path is "/path/", accessing "/path" will perform a redirect 231 // to the former and vice versa. In other words, your application will always 232 // see the path as specified in the route. 233 // 234 // When false, if the route path is "/path", accessing "/path/" will not match 235 // this route and vice versa. 236 // 237 // The re-direct is a HTTP 301 (Moved Permanently). Note that when this is set for 238 // routes with a non-idempotent method (e.g. POST, PUT), the subsequent re-directed 239 // request will be made as a GET by most clients. Use middleware or client settings 240 // to modify this behaviour as needed. 241 // 242 // Special case: when a route sets a path prefix using the PathPrefix() method, 243 // strict slash is ignored for that route because the redirect behavior can't 244 // be determined from a prefix alone. However, any subrouters created from that 245 // route inherit the original StrictSlash setting. 246 func (r *Router) StrictSlash(value bool) *Router { 247 r.strictSlash = value 248 return r 249 } 250 251 // SkipClean defines the path cleaning behaviour for new routes. The initial 252 // value is false. Users should be careful about which routes are not cleaned 253 // 254 // When true, if the route path is "/path//to", it will remain with the double 255 // slash. This is helpful if you have a route like: /fetch/http://xkcd.com/534/ 256 // 257 // When false, the path will be cleaned, so /fetch/http://xkcd.com/534/ will 258 // become /fetch/http/xkcd.com/534 259 func (r *Router) SkipClean(value bool) *Router { 260 r.skipClean = value 261 return r 262 } 263 264 // UseEncodedPath tells the router to match the encoded original path 265 // to the routes. 266 // For eg. "/path/foo%2Fbar/to" will match the path "/path/{var}/to". 267 // 268 // If not called, the router will match the unencoded path to the routes. 269 // For eg. "/path/foo%2Fbar/to" will match the path "/path/foo/bar/to" 270 func (r *Router) UseEncodedPath() *Router { 271 r.useEncodedPath = true 272 return r 273 } 274 275 // ---------------------------------------------------------------------------- 276 // Route factories 277 // ---------------------------------------------------------------------------- 278 279 // NewRoute registers an empty route. 280 func (r *Router) NewRoute() *Route { 281 // initialize a route with a copy of the parent router's configuration 282 route := &Route{routeConf: copyRouteConf(r.routeConf), namedRoutes: r.namedRoutes} 283 r.routes = append(r.routes, route) 284 return route 285 } 286 287 // Handle registers a new route with a matcher for the URL path. 288 // See Route.Path() and Route.Handler(). 289 func (r *Router) Handle(path string, handler http.Handler) *Route { 290 return r.NewRoute().Path(path).Handler(handler) 291 } 292 293 // HandleFunc registers a new route with a matcher for the URL path. 294 // See Route.Path() and Route.HandlerFunc(). 295 func (r *Router) HandleFunc(path string, f func(http.ResponseWriter, 296 *http.Request)) *Route { 297 return r.NewRoute().Path(path).HandlerFunc(f) 298 } 299 300 // Headers registers a new route with a matcher for request header values. 301 // See Route.Headers(). 302 func (r *Router) Headers(pairs ...string) *Route { 303 return r.NewRoute().Headers(pairs...) 304 } 305 306 // Host registers a new route with a matcher for the URL host. 307 // See Route.Host(). 308 func (r *Router) Host(tpl string) *Route { 309 return r.NewRoute().Host(tpl) 310 } 311 312 // MatcherFunc registers a new route with a custom matcher function. 313 // See Route.MatcherFunc(). 314 func (r *Router) MatcherFunc(f MatcherFunc) *Route { 315 return r.NewRoute().MatcherFunc(f) 316 } 317 318 // Methods registers a new route with a matcher for HTTP methods. 319 // See Route.Methods(). 320 func (r *Router) Methods(methods ...string) *Route { 321 return r.NewRoute().Methods(methods...) 322 } 323 324 // Path registers a new route with a matcher for the URL path. 325 // See Route.Path(). 326 func (r *Router) Path(tpl string) *Route { 327 return r.NewRoute().Path(tpl) 328 } 329 330 // PathPrefix registers a new route with a matcher for the URL path prefix. 331 // See Route.PathPrefix(). 332 func (r *Router) PathPrefix(tpl string) *Route { 333 return r.NewRoute().PathPrefix(tpl) 334 } 335 336 // Queries registers a new route with a matcher for URL query values. 337 // See Route.Queries(). 338 func (r *Router) Queries(pairs ...string) *Route { 339 return r.NewRoute().Queries(pairs...) 340 } 341 342 // Schemes registers a new route with a matcher for URL schemes. 343 // See Route.Schemes(). 344 func (r *Router) Schemes(schemes ...string) *Route { 345 return r.NewRoute().Schemes(schemes...) 346 } 347 348 // BuildVarsFunc registers a new route with a custom function for modifying 349 // route variables before building a URL. 350 func (r *Router) BuildVarsFunc(f BuildVarsFunc) *Route { 351 return r.NewRoute().BuildVarsFunc(f) 352 } 353 354 // Walk walks the router and all its sub-routers, calling walkFn for each route 355 // in the tree. The routes are walked in the order they were added. Sub-routers 356 // are explored depth-first. 357 func (r *Router) Walk(walkFn WalkFunc) error { 358 return r.walk(walkFn, []*Route{}) 359 } 360 361 // SkipRouter is used as a return value from WalkFuncs to indicate that the 362 // router that walk is about to descend down to should be skipped. 363 var SkipRouter = errors.New("skip this router") 364 365 // WalkFunc is the type of the function called for each route visited by Walk. 366 // At every invocation, it is given the current route, and the current router, 367 // and a list of ancestor routes that lead to the current route. 368 type WalkFunc func(route *Route, router *Router, ancestors []*Route) error 369 370 func (r *Router) walk(walkFn WalkFunc, ancestors []*Route) error { 371 for _, t := range r.routes { 372 err := walkFn(t, r, ancestors) 373 if err == SkipRouter { 374 continue 375 } 376 if err != nil { 377 return err 378 } 379 for _, sr := range t.matchers { 380 if h, ok := sr.(*Router); ok { 381 ancestors = append(ancestors, t) 382 err := h.walk(walkFn, ancestors) 383 if err != nil { 384 return err 385 } 386 ancestors = ancestors[:len(ancestors)-1] 387 } 388 } 389 if h, ok := t.handler.(*Router); ok { 390 ancestors = append(ancestors, t) 391 err := h.walk(walkFn, ancestors) 392 if err != nil { 393 return err 394 } 395 ancestors = ancestors[:len(ancestors)-1] 396 } 397 } 398 return nil 399 } 400 401 // ---------------------------------------------------------------------------- 402 // Context 403 // ---------------------------------------------------------------------------- 404 405 // RouteMatch stores information about a matched route. 406 type RouteMatch struct { 407 Route *Route 408 Handler http.Handler 409 Vars map[string]string 410 411 // MatchErr is set to appropriate matching error 412 // It is set to ErrMethodMismatch if there is a mismatch in 413 // the request method and route method 414 MatchErr error 415 } 416 417 type contextKey int 418 419 const ( 420 varsKey contextKey = iota 421 routeKey 422 ) 423 424 // Vars returns the route variables for the current request, if any. 425 func Vars(r *http.Request) map[string]string { 426 if rv := contextGet(r, varsKey); rv != nil { 427 return rv.(map[string]string) 428 } 429 return nil 430 } 431 432 // CurrentRoute returns the matched route for the current request, if any. 433 // This only works when called inside the handler of the matched route 434 // because the matched route is stored in the request context which is cleared 435 // after the handler returns, unless the KeepContext option is set on the 436 // Router. 437 func CurrentRoute(r *http.Request) *Route { 438 if rv := contextGet(r, routeKey); rv != nil { 439 return rv.(*Route) 440 } 441 return nil 442 } 443 444 func setVars(r *http.Request, val interface{}) *http.Request { 445 return contextSet(r, varsKey, val) 446 } 447 448 func setCurrentRoute(r *http.Request, val interface{}) *http.Request { 449 return contextSet(r, routeKey, val) 450 } 451 452 // ---------------------------------------------------------------------------- 453 // Helpers 454 // ---------------------------------------------------------------------------- 455 456 // cleanPath returns the canonical path for p, eliminating . and .. elements. 457 // Borrowed from the net/http package. 458 func cleanPath(p string) string { 459 if p == "" { 460 return "/" 461 } 462 if p[0] != '/' { 463 p = "/" + p 464 } 465 np := path.Clean(p) 466 // path.Clean removes trailing slash except for root; 467 // put the trailing slash back if necessary. 468 if p[len(p)-1] == '/' && np != "/" { 469 np += "/" 470 } 471 472 return np 473 } 474 475 // uniqueVars returns an error if two slices contain duplicated strings. 476 func uniqueVars(s1, s2 []string) error { 477 for _, v1 := range s1 { 478 for _, v2 := range s2 { 479 if v1 == v2 { 480 return fmt.Errorf("mux: duplicated route variable %q", v2) 481 } 482 } 483 } 484 return nil 485 } 486 487 // checkPairs returns the count of strings passed in, and an error if 488 // the count is not an even number. 489 func checkPairs(pairs ...string) (int, error) { 490 length := len(pairs) 491 if length%2 != 0 { 492 return length, fmt.Errorf( 493 "mux: number of parameters must be multiple of 2, got %v", pairs) 494 } 495 return length, nil 496 } 497 498 // mapFromPairsToString converts variadic string parameters to a 499 // string to string map. 500 func mapFromPairsToString(pairs ...string) (map[string]string, error) { 501 length, err := checkPairs(pairs...) 502 if err != nil { 503 return nil, err 504 } 505 m := make(map[string]string, length/2) 506 for i := 0; i < length; i += 2 { 507 m[pairs[i]] = pairs[i+1] 508 } 509 return m, nil 510 } 511 512 // mapFromPairsToRegex converts variadic string parameters to a 513 // string to regex map. 514 func mapFromPairsToRegex(pairs ...string) (map[string]*regexp.Regexp, error) { 515 length, err := checkPairs(pairs...) 516 if err != nil { 517 return nil, err 518 } 519 m := make(map[string]*regexp.Regexp, length/2) 520 for i := 0; i < length; i += 2 { 521 regex, err := regexp.Compile(pairs[i+1]) 522 if err != nil { 523 return nil, err 524 } 525 m[pairs[i]] = regex 526 } 527 return m, nil 528 } 529 530 // matchInArray returns true if the given string value is in the array. 531 func matchInArray(arr []string, value string) bool { 532 for _, v := range arr { 533 if v == value { 534 return true 535 } 536 } 537 return false 538 } 539 540 // matchMapWithString returns true if the given key/value pairs exist in a given map. 541 func matchMapWithString(toCheck map[string]string, toMatch map[string][]string, canonicalKey bool) bool { 542 for k, v := range toCheck { 543 // Check if key exists. 544 if canonicalKey { 545 k = http.CanonicalHeaderKey(k) 546 } 547 if values := toMatch[k]; values == nil { 548 return false 549 } else if v != "" { 550 // If value was defined as an empty string we only check that the 551 // key exists. Otherwise we also check for equality. 552 valueExists := false 553 for _, value := range values { 554 if v == value { 555 valueExists = true 556 break 557 } 558 } 559 if !valueExists { 560 return false 561 } 562 } 563 } 564 return true 565 } 566 567 // matchMapWithRegex returns true if the given key/value pairs exist in a given map compiled against 568 // the given regex 569 func matchMapWithRegex(toCheck map[string]*regexp.Regexp, toMatch map[string][]string, canonicalKey bool) bool { 570 for k, v := range toCheck { 571 // Check if key exists. 572 if canonicalKey { 573 k = http.CanonicalHeaderKey(k) 574 } 575 if values := toMatch[k]; values == nil { 576 return false 577 } else if v != nil { 578 // If value was defined as an empty string we only check that the 579 // key exists. Otherwise we also check for equality. 580 valueExists := false 581 for _, value := range values { 582 if v.MatchString(value) { 583 valueExists = true 584 break 585 } 586 } 587 if !valueExists { 588 return false 589 } 590 } 591 } 592 return true 593 } 594 595 // methodNotAllowed replies to the request with an HTTP status code 405. 596 func methodNotAllowed(w http.ResponseWriter, r *http.Request) { 597 w.WriteHeader(http.StatusMethodNotAllowed) 598 } 599 600 // methodNotAllowedHandler returns a simple request handler 601 // that replies to each request with a status code 405. 602 func methodNotAllowedHandler() http.Handler { return http.HandlerFunc(methodNotAllowed) }