taldir

Directory service to resolve wallet mailboxes by messenger addresses
Log | Files | Refs | Submodules | README | LICENSE

doc.go (11238B)


      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 /*
      6 Package mux implements a request router and dispatcher.
      7 
      8 The name mux stands for "HTTP request multiplexer". Like the standard
      9 http.ServeMux, mux.Router matches incoming requests against a list of
     10 registered routes and calls a handler for the route that matches the URL
     11 or other conditions. The main features are:
     12 
     13   - Requests can be matched based on URL host, path, path prefix, schemes,
     14     header and query values, HTTP methods or using custom matchers.
     15   - URL hosts, paths and query values can have variables with an optional
     16     regular expression.
     17   - Registered URLs can be built, or "reversed", which helps maintaining
     18     references to resources.
     19   - Routes can be used as subrouters: nested routes are only tested if the
     20     parent route matches. This is useful to define groups of routes that
     21     share common conditions like a host, a path prefix or other repeated
     22     attributes. As a bonus, this optimizes request matching.
     23   - It implements the http.Handler interface so it is compatible with the
     24     standard http.ServeMux.
     25 
     26 Let's start registering a couple of URL paths and handlers:
     27 
     28 	func main() {
     29 		r := mux.NewRouter()
     30 		r.HandleFunc("/", HomeHandler)
     31 		r.HandleFunc("/products", ProductsHandler)
     32 		r.HandleFunc("/articles", ArticlesHandler)
     33 		http.Handle("/", r)
     34 	}
     35 
     36 Here we register three routes mapping URL paths to handlers. This is
     37 equivalent to how http.HandleFunc() works: if an incoming request URL matches
     38 one of the paths, the corresponding handler is called passing
     39 (http.ResponseWriter, *http.Request) as parameters.
     40 
     41 Paths can have variables. They are defined using the format {name} or
     42 {name:pattern}. If a regular expression pattern is not defined, the matched
     43 variable will be anything until the next slash. For example:
     44 
     45 	r := mux.NewRouter()
     46 	r.HandleFunc("/products/{key}", ProductHandler)
     47 	r.HandleFunc("/articles/{category}/", ArticlesCategoryHandler)
     48 	r.HandleFunc("/articles/{category}/{id:[0-9]+}", ArticleHandler)
     49 
     50 Groups can be used inside patterns, as long as they are non-capturing (?:re). For example:
     51 
     52 	r.HandleFunc("/articles/{category}/{sort:(?:asc|desc|new)}", ArticlesCategoryHandler)
     53 
     54 The names are used to create a map of route variables which can be retrieved
     55 calling mux.Vars():
     56 
     57 	vars := mux.Vars(request)
     58 	category := vars["category"]
     59 
     60 Note that if any capturing groups are present, mux will panic() during parsing. To prevent
     61 this, convert any capturing groups to non-capturing, e.g. change "/{sort:(asc|desc)}" to
     62 "/{sort:(?:asc|desc)}". This is a change from prior versions which behaved unpredictably
     63 when capturing groups were present.
     64 
     65 And this is all you need to know about the basic usage. More advanced options
     66 are explained below.
     67 
     68 Routes can also be restricted to a domain or subdomain. Just define a host
     69 pattern to be matched. They can also have variables:
     70 
     71 	r := mux.NewRouter()
     72 	// Only matches if domain is "www.example.com".
     73 	r.Host("www.example.com")
     74 	// Matches a dynamic subdomain.
     75 	r.Host("{subdomain:[a-z]+}.domain.com")
     76 
     77 There are several other matchers that can be added. To match path prefixes:
     78 
     79 	r.PathPrefix("/products/")
     80 
     81 ...or HTTP methods:
     82 
     83 	r.Methods("GET", "POST")
     84 
     85 ...or URL schemes:
     86 
     87 	r.Schemes("https")
     88 
     89 ...or header values:
     90 
     91 	r.Headers("X-Requested-With", "XMLHttpRequest")
     92 
     93 ...or query values:
     94 
     95 	r.Queries("key", "value")
     96 
     97 ...or to use a custom matcher function:
     98 
     99 	r.MatcherFunc(func(r *http.Request, rm *RouteMatch) bool {
    100 		return r.ProtoMajor == 0
    101 	})
    102 
    103 ...and finally, it is possible to combine several matchers in a single route:
    104 
    105 	r.HandleFunc("/products", ProductsHandler).
    106 	  Host("www.example.com").
    107 	  Methods("GET").
    108 	  Schemes("http")
    109 
    110 Setting the same matching conditions again and again can be boring, so we have
    111 a way to group several routes that share the same requirements.
    112 We call it "subrouting".
    113 
    114 For example, let's say we have several URLs that should only match when the
    115 host is "www.example.com". Create a route for that host and get a "subrouter"
    116 from it:
    117 
    118 	r := mux.NewRouter()
    119 	s := r.Host("www.example.com").Subrouter()
    120 
    121 Then register routes in the subrouter:
    122 
    123 	s.HandleFunc("/products/", ProductsHandler)
    124 	s.HandleFunc("/products/{key}", ProductHandler)
    125 	s.HandleFunc("/articles/{category}/{id:[0-9]+}"), ArticleHandler)
    126 
    127 The three URL paths we registered above will only be tested if the domain is
    128 "www.example.com", because the subrouter is tested first. This is not
    129 only convenient, but also optimizes request matching. You can create
    130 subrouters combining any attribute matchers accepted by a route.
    131 
    132 Subrouters can be used to create domain or path "namespaces": you define
    133 subrouters in a central place and then parts of the app can register its
    134 paths relatively to a given subrouter.
    135 
    136 There's one more thing about subroutes. When a subrouter has a path prefix,
    137 the inner routes use it as base for their paths:
    138 
    139 	r := mux.NewRouter()
    140 	s := r.PathPrefix("/products").Subrouter()
    141 	// "/products/"
    142 	s.HandleFunc("/", ProductsHandler)
    143 	// "/products/{key}/"
    144 	s.HandleFunc("/{key}/", ProductHandler)
    145 	// "/products/{key}/details"
    146 	s.HandleFunc("/{key}/details", ProductDetailsHandler)
    147 
    148 Note that the path provided to PathPrefix() represents a "wildcard": calling
    149 PathPrefix("/static/").Handler(...) means that the handler will be passed any
    150 request that matches "/static/*". This makes it easy to serve static files with mux:
    151 
    152 	func main() {
    153 		var dir string
    154 
    155 		flag.StringVar(&dir, "dir", ".", "the directory to serve files from. Defaults to the current dir")
    156 		flag.Parse()
    157 		r := mux.NewRouter()
    158 
    159 		// This will serve files under http://localhost:8000/static/<filename>
    160 		r.PathPrefix("/static/").Handler(http.StripPrefix("/static/", http.FileServer(http.Dir(dir))))
    161 
    162 		srv := &http.Server{
    163 			Handler:      r,
    164 			Addr:         "127.0.0.1:8000",
    165 			// Good practice: enforce timeouts for servers you create!
    166 			WriteTimeout: 15 * time.Second,
    167 			ReadTimeout:  15 * time.Second,
    168 		}
    169 
    170 		log.Fatal(srv.ListenAndServe())
    171 	}
    172 
    173 Now let's see how to build registered URLs.
    174 
    175 Routes can be named. All routes that define a name can have their URLs built,
    176 or "reversed". We define a name calling Name() on a route. For example:
    177 
    178 	r := mux.NewRouter()
    179 	r.HandleFunc("/articles/{category}/{id:[0-9]+}", ArticleHandler).
    180 	  Name("article")
    181 
    182 To build a URL, get the route and call the URL() method, passing a sequence of
    183 key/value pairs for the route variables. For the previous route, we would do:
    184 
    185 	url, err := r.Get("article").URL("category", "technology", "id", "42")
    186 
    187 ...and the result will be a url.URL with the following path:
    188 
    189 	"/articles/technology/42"
    190 
    191 This also works for host and query value variables:
    192 
    193 	r := mux.NewRouter()
    194 	r.Host("{subdomain}.domain.com").
    195 	  Path("/articles/{category}/{id:[0-9]+}").
    196 	  Queries("filter", "{filter}").
    197 	  HandlerFunc(ArticleHandler).
    198 	  Name("article")
    199 
    200 	// url.String() will be "http://news.domain.com/articles/technology/42?filter=gorilla"
    201 	url, err := r.Get("article").URL("subdomain", "news",
    202 	                                 "category", "technology",
    203 	                                 "id", "42",
    204 	                                 "filter", "gorilla")
    205 
    206 All variables defined in the route are required, and their values must
    207 conform to the corresponding patterns. These requirements guarantee that a
    208 generated URL will always match a registered route -- the only exception is
    209 for explicitly defined "build-only" routes which never match.
    210 
    211 Regex support also exists for matching Headers within a route. For example, we could do:
    212 
    213 	r.HeadersRegexp("Content-Type", "application/(text|json)")
    214 
    215 ...and the route will match both requests with a Content-Type of `application/json` as well as
    216 `application/text`
    217 
    218 There's also a way to build only the URL host or path for a route:
    219 use the methods URLHost() or URLPath() instead. For the previous route,
    220 we would do:
    221 
    222 	// "http://news.domain.com/"
    223 	host, err := r.Get("article").URLHost("subdomain", "news")
    224 
    225 	// "/articles/technology/42"
    226 	path, err := r.Get("article").URLPath("category", "technology", "id", "42")
    227 
    228 And if you use subrouters, host and path defined separately can be built
    229 as well:
    230 
    231 	r := mux.NewRouter()
    232 	s := r.Host("{subdomain}.domain.com").Subrouter()
    233 	s.Path("/articles/{category}/{id:[0-9]+}").
    234 	  HandlerFunc(ArticleHandler).
    235 	  Name("article")
    236 
    237 	// "http://news.domain.com/articles/technology/42"
    238 	url, err := r.Get("article").URL("subdomain", "news",
    239 	                                 "category", "technology",
    240 	                                 "id", "42")
    241 
    242 Mux supports the addition of middlewares to a Router, which are executed in the order they are added if a match is found, including its subrouters. Middlewares are (typically) small pieces of code which take one request, do something with it, and pass it down to another middleware or the final handler. Some common use cases for middleware are request logging, header manipulation, or ResponseWriter hijacking.
    243 
    244 	type MiddlewareFunc func(http.Handler) http.Handler
    245 
    246 Typically, the returned handler is a closure which does something with the http.ResponseWriter and http.Request passed to it, and then calls the handler passed as parameter to the MiddlewareFunc (closures can access variables from the context where they are created).
    247 
    248 A very basic middleware which logs the URI of the request being handled could be written as:
    249 
    250 	func simpleMw(next http.Handler) http.Handler {
    251 		return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
    252 			// Do stuff here
    253 			log.Println(r.RequestURI)
    254 			// Call the next handler, which can be another middleware in the chain, or the final handler.
    255 			next.ServeHTTP(w, r)
    256 		})
    257 	}
    258 
    259 Middlewares can be added to a router using `Router.Use()`:
    260 
    261 	r := mux.NewRouter()
    262 	r.HandleFunc("/", handler)
    263 	r.Use(simpleMw)
    264 
    265 A more complex authentication middleware, which maps session token to users, could be written as:
    266 
    267 	// Define our struct
    268 	type authenticationMiddleware struct {
    269 		tokenUsers map[string]string
    270 	}
    271 
    272 	// Initialize it somewhere
    273 	func (amw *authenticationMiddleware) Populate() {
    274 		amw.tokenUsers["00000000"] = "user0"
    275 		amw.tokenUsers["aaaaaaaa"] = "userA"
    276 		amw.tokenUsers["05f717e5"] = "randomUser"
    277 		amw.tokenUsers["deadbeef"] = "user0"
    278 	}
    279 
    280 	// Middleware function, which will be called for each request
    281 	func (amw *authenticationMiddleware) Middleware(next http.Handler) http.Handler {
    282 		return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
    283 			token := r.Header.Get("X-Session-Token")
    284 
    285 			if user, found := amw.tokenUsers[token]; found {
    286 				// We found the token in our map
    287 				log.Printf("Authenticated user %s\n", user)
    288 				next.ServeHTTP(w, r)
    289 			} else {
    290 				http.Error(w, "Forbidden", http.StatusForbidden)
    291 			}
    292 		})
    293 	}
    294 
    295 	r := mux.NewRouter()
    296 	r.HandleFunc("/", handler)
    297 
    298 	amw := authenticationMiddleware{tokenUsers: make(map[string]string)}
    299 	amw.Populate()
    300 
    301 	r.Use(amw.Middleware)
    302 
    303 Note: The handler chain will be stopped if your middleware doesn't call `next.ServeHTTP()` with the corresponding parameters. This can be used to abort a request if the middleware writer wants to.
    304 */
    305 package mux