text: // Copyright 2012 The Gorilla Authors. All rights reserved.
  // Use of this source code is governed by a BSD-style
  // license that can be found in the LICENSE file.
  
  package mux
  
  import (
  	"errors"
  	"fmt"
  	"net/http"
  	"path"
  	"regexp"
  
  	"github.com/gorilla/context"
  )
  
  // NewRouter returns a new router instance.
  func NewRouter() *Router {
  	return &Router{namedRoutes: make(map[string]*Route), KeepContext: false}
  }
  
  // Router registers routes to be matched and dispatches a handler.
  //
  // It implements the http.Handler interface, so it can be registered to serve
  // requests:
  //
  //     var router = mux.NewRouter()
  //
  //     func main() {
  //         http.Handle("/", router)
  //     }
  //
  // Or, for Google App Engine, register it in a init() function:
  //
  //     func init() {
  //         http.Handle("/", router)
  //     }
  //
  // This will send all incoming requests to the router.
  type Router struct {
  	// Configurable Handler to be used when no route matches.
  	NotFoundHandler http.Handler
  	// Parent route, if this is a subrouter.
  	parent parentRoute
  	// Routes to be matched, in order.
  	routes []*Route
  	// Routes by name for URL building.
  	namedRoutes map[string]*Route
  	// See Router.StrictSlash(). This defines the flag for new routes.
  	strictSlash bool
  	// See Router.SkipClean(). This defines the flag for new routes.
  	skipClean bool
  	// If true, do not clear the request context after handling the request
  	KeepContext bool
  }
  
  // Match matches registered routes against the request.
  func (r *Router) Match(req *http.Request, match *RouteMatch) bool {
  	for _, route := range r.routes {
  		if route.Match(req, match) {
  			return true
  		}
  	}
  
  	// Closest match for a router (includes sub-routers)
  	if r.NotFoundHandler != nil {
  		match.Handler = r.NotFoundHandler
  		return true
  	}
  	return false
  }
  
  // ServeHTTP dispatches the handler registered in the matched route.
  //
  // When there is a match, the route variables can be retrieved calling
  // mux.Vars(request).
  func (r *Router) ServeHTTP(w http.ResponseWriter, req *http.Request) {
  	if !r.skipClean {
  		// Clean path to canonical form and redirect.
  		if p := cleanPath(req.URL.Path); p != req.URL.Path {
  
  			// Added 3 lines (Philip Schlump) - It was dropping the query string and #whatever from query.
  			// This matches with fix in go 1.2 r.c. 4 for same problem.  Go Issue:
  			// http://code.google.com/p/go/issues/detail?id=5252
  			url := *req.URL
  			url.Path = p
  			p = url.String()
  
  			w.Header().Set("Location", p)
  			w.WriteHeader(http.StatusMovedPermanently)
  			return
  		}
  	}
  	var match RouteMatch
  	var handler http.Handler
  	if r.Match(req, &match) {
  		handler = match.Handler
  		setVars(req, match.Vars)
  		setCurrentRoute(req, match.Route)
  	}
  	if handler == nil {
  		handler = http.NotFoundHandler()
  	}
  	if !r.KeepContext {
  		defer context.Clear(req)
  	}
  	handler.ServeHTTP(w, req)
  }
  
  // Get returns a route registered with the given name.
  func (r *Router) Get(name string) *Route {
  	return r.getNamedRoutes()[name]
  }
  
  // GetRoute returns a route registered with the given name. This method
  // was renamed to Get() and remains here for backwards compatibility.
  func (r *Router) GetRoute(name string) *Route {
  	return r.getNamedRoutes()[name]
  }
  
  // StrictSlash defines the trailing slash behavior for new routes. The initial
  // value is false.
  //
  // When true, if the route path is "/path/", accessing "/path" will redirect
  // to the former and vice versa. In other words, your application will always
  // see the path as specified in the route.
  //
  // When false, if the route path is "/path", accessing "/path/" will not match
  // this route and vice versa.
  //
  // Special case: when a route sets a path prefix using the PathPrefix() method,
  // strict slash is ignored for that route because the redirect behavior can't
  // be determined from a prefix alone. However, any subrouters created from that
  // route inherit the original StrictSlash setting.
  func (r *Router) StrictSlash(value bool) *Router {
  	r.strictSlash = value
  	return r
  }
  
  // SkipClean defines the path cleaning behaviour for new routes. The initial
  // value is false. Users should be careful about which routes are not cleaned
  //
  // When true, if the route path is "/path//to", it will remain with the double
  // slash. This is helpful if you have a route like: /fetch/http://xkcd.com/534/
  //
  // When false, the path will be cleaned, so /fetch/http://xkcd.com/534/ will
  // become /fetch/http/xkcd.com/534
  func (r *Router) SkipClean(value bool) *Router {
  	r.skipClean = value
  	return r
  }
  
  // ----------------------------------------------------------------------------
  // parentRoute
  // ----------------------------------------------------------------------------
  
  // getNamedRoutes returns the map where named routes are registered.
  func (r *Router) getNamedRoutes() map[string]*Route {
  	if r.namedRoutes == nil {
  		if r.parent != nil {
  			r.namedRoutes = r.parent.getNamedRoutes()
  		} else {
  			r.namedRoutes = make(map[string]*Route)
  		}
  	}
  	return r.namedRoutes
  }
  
  // getRegexpGroup returns regexp definitions from the parent route, if any.
  func (r *Router) getRegexpGroup() *routeRegexpGroup {
  	if r.parent != nil {
  		return r.parent.getRegexpGroup()
  	}
  	return nil
  }
  
  func (r *Router) buildVars(m map[string]string) map[string]string {
  	if r.parent != nil {
  		m = r.parent.buildVars(m)
  	}
  	return m
  }
  
  // ----------------------------------------------------------------------------
  // Route factories
  // ----------------------------------------------------------------------------
  
  // NewRoute registers an empty route.
  func (r *Router) NewRoute() *Route {
  	route := &Route{parent: r, strictSlash: r.strictSlash, skipClean: r.skipClean}
  	r.routes = append(r.routes, route)
  	return route
  }
  
  // Handle registers a new route with a matcher for the URL path.
  // See Route.Path() and Route.Handler().
  func (r *Router) Handle(path string, handler http.Handler) *Route {
  	return r.NewRoute().Path(path).Handler(handler)
  }
  
  // HandleFunc registers a new route with a matcher for the URL path.
  // See Route.Path() and Route.HandlerFunc().
  func (r *Router) HandleFunc(path string, f func(http.ResponseWriter,
  	*http.Request)) *Route {
  	return r.NewRoute().Path(path).HandlerFunc(f)
  }
  
  // Headers registers a new route with a matcher for request header values.
  // See Route.Headers().
  func (r *Router) Headers(pairs ...string) *Route {
  	return r.NewRoute().Headers(pairs...)
  }
  
  // Host registers a new route with a matcher for the URL host.
  // See Route.Host().
  func (r *Router) Host(tpl string) *Route {
  	return r.NewRoute().Host(tpl)
  }
  
  // MatcherFunc registers a new route with a custom matcher function.
  // See Route.MatcherFunc().
  func (r *Router) MatcherFunc(f MatcherFunc) *Route {
  	return r.NewRoute().MatcherFunc(f)
  }
  
  // Methods registers a new route with a matcher for HTTP methods.
  // See Route.Methods().
  func (r *Router) Methods(methods ...string) *Route {
  	return r.NewRoute().Methods(methods...)
  }
  
  // Path registers a new route with a matcher for the URL path.
  // See Route.Path().
  func (r *Router) Path(tpl string) *Route {
  	return r.NewRoute().Path(tpl)
  }
  
  // PathPrefix registers a new route with a matcher for the URL path prefix.
  // See Route.PathPrefix().
  func (r *Router) PathPrefix(tpl string) *Route {
  	return r.NewRoute().PathPrefix(tpl)
  }
  
  // Queries registers a new route with a matcher for URL query values.
  // See Route.Queries().
  func (r *Router) Queries(pairs ...string) *Route {
  	return r.NewRoute().Queries(pairs...)
  }
  
  // Schemes registers a new route with a matcher for URL schemes.
  // See Route.Schemes().
  func (r *Router) Schemes(schemes ...string) *Route {
  	return r.NewRoute().Schemes(schemes...)
  }
  
  // BuildVarsFunc registers a new route with a custom function for modifying
  // route variables before building a URL.
  func (r *Router) BuildVarsFunc(f BuildVarsFunc) *Route {
  	return r.NewRoute().BuildVarsFunc(f)
  }
  
  // Walk walks the router and all its sub-routers, calling walkFn for each route
  // in the tree. The routes are walked in the order they were added. Sub-routers
  // are explored depth-first.
  func (r *Router) Walk(walkFn WalkFunc) error {
  	return r.walk(walkFn, []*Route{})
  }
  
  // SkipRouter is used as a return value from WalkFuncs to indicate that the
  // router that walk is about to descend down to should be skipped.
  var SkipRouter = errors.New("skip this router")
  
  // WalkFunc is the type of the function called for each route visited by Walk.
  // At every invocation, it is given the current route, and the current router,
  // and a list of ancestor routes that lead to the current route.
  type WalkFunc func(route *Route, router *Router, ancestors []*Route) error
  
  func (r *Router) walk(walkFn WalkFunc, ancestors []*Route) error {
  	for _, t := range r.routes {
  		if t.regexp == nil || t.regexp.path == nil || t.regexp.path.template == "" {
  			continue
  		}
  
  		err := walkFn(t, r, ancestors)
  		if err == SkipRouter {
  			continue
  		}
  		for _, sr := range t.matchers {
  			if h, ok := sr.(*Router); ok {
  				err := h.walk(walkFn, ancestors)
  				if err != nil {
  					return err
  				}
  			}
  		}
  		if h, ok := t.handler.(*Router); ok {
  			ancestors = append(ancestors, t)
  			err := h.walk(walkFn, ancestors)
  			if err != nil {
  				return err
  			}
  			ancestors = ancestors[:len(ancestors)-1]
  		}
  	}
  	return nil
  }
  
  // ----------------------------------------------------------------------------
  // Context
  // ----------------------------------------------------------------------------
  
  // RouteMatch stores information about a matched route.
  type RouteMatch struct {
  	Route   *Route
  	Handler http.Handler
  	Vars    map[string]string
  }
  
  type contextKey int
  
  const (
  	varsKey contextKey = iota
  	routeKey
  )
  
  // Vars returns the route variables for the current request, if any.
  func Vars(r *http.Request) map[string]string {
  	if rv := context.Get(r, varsKey); rv != nil {
  		return rv.(map[string]string)
  	}
  	return nil
  }
  
  // CurrentRoute returns the matched route for the current request, if any.
  // This only works when called inside the handler of the matched route
  // because the matched route is stored in the request context which is cleared
  // after the handler returns, unless the KeepContext option is set on the
  // Router.
  func CurrentRoute(r *http.Request) *Route {
  	if rv := context.Get(r, routeKey); rv != nil {
  		return rv.(*Route)
  	}
  	return nil
  }
  
  func setVars(r *http.Request, val interface{}) {
  	if val != nil {
  		context.Set(r, varsKey, val)
  	}
  }
  
  func setCurrentRoute(r *http.Request, val interface{}) {
  	if val != nil {
  		context.Set(r, routeKey, val)
  	}
  }
  
  // ----------------------------------------------------------------------------
  // Helpers
  // ----------------------------------------------------------------------------
  
  // cleanPath returns the canonical path for p, eliminating . and .. elements.
  // Borrowed from the net/http package.
  func cleanPath(p string) string {
  	if p == "" {
  		return "/"
  	}
  	if p[0] != '/' {
  		p = "/" + p
  	}
  	np := path.Clean(p)
  	// path.Clean removes trailing slash except for root;
  	// put the trailing slash back if necessary.
  	if p[len(p)-1] == '/' && np != "/" {
  		np += "/"
  	}
  
  	return np
  }
  
  // uniqueVars returns an error if two slices contain duplicated strings.
  func uniqueVars(s1, s2 []string) error {
  	for _, v1 := range s1 {
  		for _, v2 := range s2 {
  			if v1 == v2 {
  				return fmt.Errorf("mux: duplicated route variable %q", v2)
  			}
  		}
  	}
  	return nil
  }
  
  // checkPairs returns the count of strings passed in, and an error if
  // the count is not an even number.
  func checkPairs(pairs ...string) (int, error) {
  	length := len(pairs)
  	if length%2 != 0 {
  		return length, fmt.Errorf(
  			"mux: number of parameters must be multiple of 2, got %v", pairs)
  	}
  	return length, nil
  }
  
  // mapFromPairsToString converts variadic string parameters to a
  // string to string map.
  func mapFromPairsToString(pairs ...string) (map[string]string, error) {
  	length, err := checkPairs(pairs...)
  	if err != nil {
  		return nil, err
  	}
  	m := make(map[string]string, length/2)
  	for i := 0; i < length; i += 2 {
  		m[pairs[i]] = pairs[i+1]
  	}
  	return m, nil
  }
  
  // mapFromPairsToRegex converts variadic string paramers to a
  // string to regex map.
  func mapFromPairsToRegex(pairs ...string) (map[string]*regexp.Regexp, error) {
  	length, err := checkPairs(pairs...)
  	if err != nil {
  		return nil, err
  	}
  	m := make(map[string]*regexp.Regexp, length/2)
  	for i := 0; i < length; i += 2 {
  		regex, err := regexp.Compile(pairs[i+1])
  		if err != nil {
  			return nil, err
  		}
  		m[pairs[i]] = regex
  	}
  	return m, nil
  }
  
  // matchInArray returns true if the given string value is in the array.
  func matchInArray(arr []string, value string) bool {
  	for _, v := range arr {
  		if v == value {
  			return true
  		}
  	}
  	return false
  }
  
  // matchMapWithString returns true if the given key/value pairs exist in a given map.
  func matchMapWithString(toCheck map[string]string, toMatch map[string][]string, canonicalKey bool) bool {
  	for k, v := range toCheck {
  		// Check if key exists.
  		if canonicalKey {
  			k = http.CanonicalHeaderKey(k)
  		}
  		if values := toMatch[k]; values == nil {
  			return false
  		} else if v != "" {
  			// If value was defined as an empty string we only check that the
  			// key exists. Otherwise we also check for equality.
  			valueExists := false
  			for _, value := range values {
  				if v == value {
  					valueExists = true
  					break
  				}
  			}
  			if !valueExists {
  				return false
  			}
  		}
  	}
  	return true
  }
  
  // matchMapWithRegex returns true if the given key/value pairs exist in a given map compiled against
  // the given regex
  func matchMapWithRegex(toCheck map[string]*regexp.Regexp, toMatch map[string][]string, canonicalKey bool) bool {
  	for k, v := range toCheck {
  		// Check if key exists.
  		if canonicalKey {
  			k = http.CanonicalHeaderKey(k)
  		}
  		if values := toMatch[k]; values == nil {
  			return false
  		} else if v != nil {
  			// If value was defined as an empty string we only check that the
  			// key exists. Otherwise we also check for equality.
  			valueExists := false
  			for _, value := range values {
  				if v.MatchString(value) {
  					valueExists = true
  					break
  				}
  			}
  			if !valueExists {
  				return false
  			}
  		}
  	}
  	return true
  }
  