full diff: https://github.com/gorilla/mux/compare/v1.8.0...v1.8.1
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
| ... | ... |
@@ -48,7 +48,7 @@ require ( |
| 48 | 48 |
github.com/golang/protobuf v1.5.3 |
| 49 | 49 |
github.com/google/go-cmp v0.5.9 |
| 50 | 50 |
github.com/google/uuid v1.3.0 |
| 51 |
- github.com/gorilla/mux v1.8.0 |
|
| 51 |
+ github.com/gorilla/mux v1.8.1 |
|
| 52 | 52 |
github.com/grpc-ecosystem/go-grpc-middleware v1.3.0 |
| 53 | 53 |
github.com/hashicorp/go-immutable-radix v1.3.1 |
| 54 | 54 |
github.com/hashicorp/go-memdb v1.3.2 |
| ... | ... |
@@ -692,8 +692,9 @@ github.com/gorilla/handlers v0.0.0-20150720190736-60c7bfde3e33/go.mod h1:Qkdc/uu |
| 692 | 692 |
github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= |
| 693 | 693 |
github.com/gorilla/mux v1.7.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= |
| 694 | 694 |
github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= |
| 695 |
-github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI= |
|
| 696 | 695 |
github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= |
| 696 |
+github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY= |
|
| 697 |
+github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ= |
|
| 697 | 698 |
github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= |
| 698 | 699 |
github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= |
| 699 | 700 |
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= |
| 0 | 1 |
deleted file mode 100644 |
| ... | ... |
@@ -1,8 +0,0 @@ |
| 1 |
-# This is the official list of gorilla/mux authors for copyright purposes. |
|
| 2 |
-# |
|
| 3 |
-# Please keep the list sorted. |
|
| 4 |
- |
|
| 5 |
-Google LLC (https://opensource.google.com/) |
|
| 6 |
-Kamil Kisielk <kamil@kamilkisiel.net> |
|
| 7 |
-Matt Silverlock <matt@eatsleeprepeat.net> |
|
| 8 |
-Rodrigo Moraes (https://github.com/moraes) |
| ... | ... |
@@ -1,4 +1,4 @@ |
| 1 |
-Copyright (c) 2012-2018 The Gorilla Authors. All rights reserved. |
|
| 1 |
+Copyright (c) 2023 The Gorilla Authors. All rights reserved. |
|
| 2 | 2 |
|
| 3 | 3 |
Redistribution and use in source and binary forms, with or without |
| 4 | 4 |
modification, are permitted provided that the following conditions are |
| 5 | 5 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,34 @@ |
| 0 |
+GO_LINT=$(shell which golangci-lint 2> /dev/null || echo '') |
|
| 1 |
+GO_LINT_URI=github.com/golangci/golangci-lint/cmd/golangci-lint@latest |
|
| 2 |
+ |
|
| 3 |
+GO_SEC=$(shell which gosec 2> /dev/null || echo '') |
|
| 4 |
+GO_SEC_URI=github.com/securego/gosec/v2/cmd/gosec@latest |
|
| 5 |
+ |
|
| 6 |
+GO_VULNCHECK=$(shell which govulncheck 2> /dev/null || echo '') |
|
| 7 |
+GO_VULNCHECK_URI=golang.org/x/vuln/cmd/govulncheck@latest |
|
| 8 |
+ |
|
| 9 |
+.PHONY: golangci-lint |
|
| 10 |
+golangci-lint: |
|
| 11 |
+ $(if $(GO_LINT), ,go install $(GO_LINT_URI)) |
|
| 12 |
+ @echo "##### Running golangci-lint" |
|
| 13 |
+ golangci-lint run -v |
|
| 14 |
+ |
|
| 15 |
+.PHONY: gosec |
|
| 16 |
+gosec: |
|
| 17 |
+ $(if $(GO_SEC), ,go install $(GO_SEC_URI)) |
|
| 18 |
+ @echo "##### Running gosec" |
|
| 19 |
+ gosec ./... |
|
| 20 |
+ |
|
| 21 |
+.PHONY: govulncheck |
|
| 22 |
+govulncheck: |
|
| 23 |
+ $(if $(GO_VULNCHECK), ,go install $(GO_VULNCHECK_URI)) |
|
| 24 |
+ @echo "##### Running govulncheck" |
|
| 25 |
+ govulncheck ./... |
|
| 26 |
+ |
|
| 27 |
+.PHONY: verify |
|
| 28 |
+verify: golangci-lint gosec govulncheck |
|
| 29 |
+ |
|
| 30 |
+.PHONY: test |
|
| 31 |
+test: |
|
| 32 |
+ @echo "##### Running tests" |
|
| 33 |
+ go test -race -cover -coverprofile=coverage.coverprofile -covermode=atomic -v ./... |
|
| 0 | 34 |
\ No newline at end of file |
| ... | ... |
@@ -1,12 +1,12 @@ |
| 1 | 1 |
# gorilla/mux |
| 2 | 2 |
|
| 3 |
-[](https://godoc.org/github.com/gorilla/mux) |
|
| 4 |
-[](https://circleci.com/gh/gorilla/mux) |
|
| 5 |
-[](https://sourcegraph.com/github.com/gorilla/mux?badge) |
|
| 3 |
+ |
|
| 4 |
+[](https://codecov.io/github/gorilla/mux) |
|
| 5 |
+[](https://godoc.org/github.com/gorilla/mux) |
|
| 6 |
+[](https://sourcegraph.com/github.com/gorilla/mux?badge) |
|
| 6 | 7 |
|
| 7 |
- |
|
| 8 | 8 |
|
| 9 |
-https://www.gorillatoolkit.org/pkg/mux |
|
| 9 |
+ |
|
| 10 | 10 |
|
| 11 | 11 |
Package `gorilla/mux` implements a request router and dispatcher for matching incoming requests to |
| 12 | 12 |
their respective handler. |
| ... | ... |
@@ -247,32 +247,25 @@ type spaHandler struct {
|
| 247 | 247 |
// file located at the index path on the SPA handler will be served. This |
| 248 | 248 |
// is suitable behavior for serving an SPA (single page application). |
| 249 | 249 |
func (h spaHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
| 250 |
- // get the absolute path to prevent directory traversal |
|
| 251 |
- path, err := filepath.Abs(r.URL.Path) |
|
| 252 |
- if err != nil {
|
|
| 253 |
- // if we failed to get the absolute path respond with a 400 bad request |
|
| 254 |
- // and stop |
|
| 255 |
- http.Error(w, err.Error(), http.StatusBadRequest) |
|
| 256 |
- return |
|
| 257 |
- } |
|
| 258 |
- |
|
| 259 |
- // prepend the path with the path to the static directory |
|
| 260 |
- path = filepath.Join(h.staticPath, path) |
|
| 250 |
+ // Join internally call path.Clean to prevent directory traversal |
|
| 251 |
+ path := filepath.Join(h.staticPath, r.URL.Path) |
|
| 261 | 252 |
|
| 262 |
- // check whether a file exists at the given path |
|
| 263 |
- _, err = os.Stat(path) |
|
| 264 |
- if os.IsNotExist(err) {
|
|
| 265 |
- // file does not exist, serve index.html |
|
| 253 |
+ // check whether a file exists or is a directory at the given path |
|
| 254 |
+ fi, err := os.Stat(path) |
|
| 255 |
+ if os.IsNotExist(err) || fi.IsDir() {
|
|
| 256 |
+ // file does not exist or path is a directory, serve index.html |
|
| 266 | 257 |
http.ServeFile(w, r, filepath.Join(h.staticPath, h.indexPath)) |
| 267 | 258 |
return |
| 268 |
- } else if err != nil {
|
|
| 269 |
- // if we got an error (that wasn't that the file doesn't exist) stating the |
|
| 270 |
- // file, return a 500 internal server error and stop |
|
| 259 |
+ } |
|
| 260 |
+ |
|
| 261 |
+ if err != nil {
|
|
| 262 |
+ // if we got an error (that wasn't that the file doesn't exist) stating the |
|
| 263 |
+ // file, return a 500 internal server error and stop |
|
| 271 | 264 |
http.Error(w, err.Error(), http.StatusInternalServerError) |
| 272 |
- return |
|
| 265 |
+ return |
|
| 273 | 266 |
} |
| 274 | 267 |
|
| 275 |
- // otherwise, use http.FileServer to serve the static dir |
|
| 268 |
+ // otherwise, use http.FileServer to serve the static file |
|
| 276 | 269 |
http.FileServer(http.Dir(h.staticPath)).ServeHTTP(w, r) |
| 277 | 270 |
} |
| 278 | 271 |
|
| ... | ... |
@@ -375,6 +368,19 @@ url, err := r.Get("article").URL("subdomain", "news",
|
| 375 | 375 |
"id", "42") |
| 376 | 376 |
``` |
| 377 | 377 |
|
| 378 |
+To find all the required variables for a given route when calling `URL()`, the method `GetVarNames()` is available: |
|
| 379 |
+```go |
|
| 380 |
+r := mux.NewRouter() |
|
| 381 |
+r.Host("{domain}").
|
|
| 382 |
+ Path("/{group}/{item_id}").
|
|
| 383 |
+ Queries("some_data1", "{some_data1}").
|
|
| 384 |
+ Queries("some_data2", "{some_data2}").
|
|
| 385 |
+ Name("article")
|
|
| 386 |
+ |
|
| 387 |
+// Will print [domain group item_id some_data1 some_data2] <nil> |
|
| 388 |
+fmt.Println(r.Get("article").GetVarNames())
|
|
| 389 |
+ |
|
| 390 |
+``` |
|
| 378 | 391 |
### Walking Routes |
| 379 | 392 |
|
| 380 | 393 |
The `Walk` function on `mux.Router` can be used to visit all of the routes that are registered on a router. For example, |
| ... | ... |
@@ -572,7 +578,7 @@ func (amw *authenticationMiddleware) Middleware(next http.Handler) http.Handler |
| 572 | 572 |
r := mux.NewRouter() |
| 573 | 573 |
r.HandleFunc("/", handler)
|
| 574 | 574 |
|
| 575 |
-amw := authenticationMiddleware{}
|
|
| 575 |
+amw := authenticationMiddleware{tokenUsers: make(map[string]string)}
|
|
| 576 | 576 |
amw.Populate() |
| 577 | 577 |
|
| 578 | 578 |
r.Use(amw.Middleware) |
| ... | ... |
@@ -758,7 +764,8 @@ func TestMetricsHandler(t *testing.T) {
|
| 758 | 758 |
|
| 759 | 759 |
rr := httptest.NewRecorder() |
| 760 | 760 |
|
| 761 |
- // Need to create a router that we can pass the request through so that the vars will be added to the context |
|
| 761 |
+ // To add the vars to the context, |
|
| 762 |
+ // we need to create a router through which we can pass the request. |
|
| 762 | 763 |
router := mux.NewRouter() |
| 763 | 764 |
router.HandleFunc("/metrics/{type}", MetricsHandler)
|
| 764 | 765 |
router.ServeHTTP(rr, req) |
| ... | ... |
@@ -10,18 +10,18 @@ http.ServeMux, mux.Router matches incoming requests against a list of |
| 10 | 10 |
registered routes and calls a handler for the route that matches the URL |
| 11 | 11 |
or other conditions. The main features are: |
| 12 | 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. |
|
| 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 | 25 |
|
| 26 | 26 |
Let's start registering a couple of URL paths and handlers: |
| 27 | 27 |
|
| ... | ... |
@@ -301,6 +301,5 @@ A more complex authentication middleware, which maps session token to users, cou |
| 301 | 301 |
r.Use(amw.Middleware) |
| 302 | 302 |
|
| 303 | 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 | 304 |
*/ |
| 306 | 305 |
package mux |
| ... | ... |
@@ -31,24 +31,26 @@ func NewRouter() *Router {
|
| 31 | 31 |
// It implements the http.Handler interface, so it can be registered to serve |
| 32 | 32 |
// requests: |
| 33 | 33 |
// |
| 34 |
-// var router = mux.NewRouter() |
|
| 34 |
+// var router = mux.NewRouter() |
|
| 35 | 35 |
// |
| 36 |
-// func main() {
|
|
| 37 |
-// http.Handle("/", router)
|
|
| 38 |
-// } |
|
| 36 |
+// func main() {
|
|
| 37 |
+// http.Handle("/", router)
|
|
| 38 |
+// } |
|
| 39 | 39 |
// |
| 40 | 40 |
// Or, for Google App Engine, register it in a init() function: |
| 41 | 41 |
// |
| 42 |
-// func init() {
|
|
| 43 |
-// http.Handle("/", router)
|
|
| 44 |
-// } |
|
| 42 |
+// func init() {
|
|
| 43 |
+// http.Handle("/", router)
|
|
| 44 |
+// } |
|
| 45 | 45 |
// |
| 46 | 46 |
// This will send all incoming requests to the router. |
| 47 | 47 |
type Router struct {
|
| 48 | 48 |
// Configurable Handler to be used when no route matches. |
| 49 |
+ // This can be used to render your own 404 Not Found errors. |
|
| 49 | 50 |
NotFoundHandler http.Handler |
| 50 | 51 |
|
| 51 | 52 |
// Configurable Handler to be used when the request method does not match the route. |
| 53 |
+ // This can be used to render your own 405 Method Not Allowed errors. |
|
| 52 | 54 |
MethodNotAllowedHandler http.Handler |
| 53 | 55 |
|
| 54 | 56 |
// Routes to be matched, in order. |
| ... | ... |
@@ -22,10 +22,10 @@ type routeRegexpOptions struct {
|
| 22 | 22 |
type regexpType int |
| 23 | 23 |
|
| 24 | 24 |
const ( |
| 25 |
- regexpTypePath regexpType = 0 |
|
| 26 |
- regexpTypeHost regexpType = 1 |
|
| 27 |
- regexpTypePrefix regexpType = 2 |
|
| 28 |
- regexpTypeQuery regexpType = 3 |
|
| 25 |
+ regexpTypePath regexpType = iota |
|
| 26 |
+ regexpTypeHost |
|
| 27 |
+ regexpTypePrefix |
|
| 28 |
+ regexpTypeQuery |
|
| 29 | 29 |
) |
| 30 | 30 |
|
| 31 | 31 |
// newRouteRegexp parses a route template and returns a routeRegexp, |
| ... | ... |
@@ -195,7 +195,7 @@ func (r *routeRegexp) Match(req *http.Request, match *RouteMatch) bool {
|
| 195 | 195 |
|
| 196 | 196 |
// url builds a URL part using the given values. |
| 197 | 197 |
func (r *routeRegexp) url(values map[string]string) (string, error) {
|
| 198 |
- urlValues := make([]interface{}, len(r.varsN), len(r.varsN))
|
|
| 198 |
+ urlValues := make([]interface{}, len(r.varsN))
|
|
| 199 | 199 |
for k, v := range r.varsN {
|
| 200 | 200 |
value, ok := values[v] |
| 201 | 201 |
if !ok {
|
| ... | ... |
@@ -64,8 +64,18 @@ func (r *Route) Match(req *http.Request, match *RouteMatch) bool {
|
| 64 | 64 |
match.MatchErr = nil |
| 65 | 65 |
} |
| 66 | 66 |
|
| 67 |
- matchErr = nil |
|
| 67 |
+ matchErr = nil // nolint:ineffassign |
|
| 68 | 68 |
return false |
| 69 |
+ } else {
|
|
| 70 |
+ // Multiple routes may share the same path but use different HTTP methods. For instance: |
|
| 71 |
+ // Route 1: POST "/users/{id}".
|
|
| 72 |
+ // Route 2: GET "/users/{id}", parameters: "id": "[0-9]+".
|
|
| 73 |
+ // |
|
| 74 |
+ // The router must handle these cases correctly. For a GET request to "/users/abc" with "id" as "-2", |
|
| 75 |
+ // The router should return a "Not Found" error as no route fully matches this request. |
|
| 76 |
+ if match.MatchErr == ErrMethodMismatch {
|
|
| 77 |
+ match.MatchErr = nil |
|
| 78 |
+ } |
|
| 69 | 79 |
} |
| 70 | 80 |
} |
| 71 | 81 |
|
| ... | ... |
@@ -230,9 +240,9 @@ func (m headerMatcher) Match(r *http.Request, match *RouteMatch) bool {
|
| 230 | 230 |
// Headers adds a matcher for request header values. |
| 231 | 231 |
// It accepts a sequence of key/value pairs to be matched. For example: |
| 232 | 232 |
// |
| 233 |
-// r := mux.NewRouter() |
|
| 234 |
-// r.Headers("Content-Type", "application/json",
|
|
| 235 |
-// "X-Requested-With", "XMLHttpRequest") |
|
| 233 |
+// r := mux.NewRouter().NewRoute() |
|
| 234 |
+// r.Headers("Content-Type", "application/json",
|
|
| 235 |
+// "X-Requested-With", "XMLHttpRequest") |
|
| 236 | 236 |
// |
| 237 | 237 |
// The above route will only match if both request header values match. |
| 238 | 238 |
// If the value is an empty string, it will match any value if the key is set. |
| ... | ... |
@@ -255,9 +265,9 @@ func (m headerRegexMatcher) Match(r *http.Request, match *RouteMatch) bool {
|
| 255 | 255 |
// HeadersRegexp accepts a sequence of key/value pairs, where the value has regex |
| 256 | 256 |
// support. For example: |
| 257 | 257 |
// |
| 258 |
-// r := mux.NewRouter() |
|
| 259 |
-// r.HeadersRegexp("Content-Type", "application/(text|json)",
|
|
| 260 |
-// "X-Requested-With", "XMLHttpRequest") |
|
| 258 |
+// r := mux.NewRouter().NewRoute() |
|
| 259 |
+// r.HeadersRegexp("Content-Type", "application/(text|json)",
|
|
| 260 |
+// "X-Requested-With", "XMLHttpRequest") |
|
| 261 | 261 |
// |
| 262 | 262 |
// The above route will only match if both the request header matches both regular expressions. |
| 263 | 263 |
// If the value is an empty string, it will match any value if the key is set. |
| ... | ... |
@@ -283,10 +293,10 @@ func (r *Route) HeadersRegexp(pairs ...string) *Route {
|
| 283 | 283 |
// |
| 284 | 284 |
// For example: |
| 285 | 285 |
// |
| 286 |
-// r := mux.NewRouter() |
|
| 287 |
-// r.Host("www.example.com")
|
|
| 288 |
-// r.Host("{subdomain}.domain.com")
|
|
| 289 |
-// r.Host("{subdomain:[a-z]+}.domain.com")
|
|
| 286 |
+// r := mux.NewRouter().NewRoute() |
|
| 287 |
+// r.Host("www.example.com")
|
|
| 288 |
+// r.Host("{subdomain}.domain.com")
|
|
| 289 |
+// r.Host("{subdomain:[a-z]+}.domain.com")
|
|
| 290 | 290 |
// |
| 291 | 291 |
// Variable names must be unique in a given route. They can be retrieved |
| 292 | 292 |
// calling mux.Vars(request). |
| ... | ... |
@@ -342,11 +352,11 @@ func (r *Route) Methods(methods ...string) *Route {
|
| 342 | 342 |
// |
| 343 | 343 |
// For example: |
| 344 | 344 |
// |
| 345 |
-// r := mux.NewRouter() |
|
| 346 |
-// r.Path("/products/").Handler(ProductsHandler)
|
|
| 347 |
-// r.Path("/products/{key}").Handler(ProductsHandler)
|
|
| 348 |
-// r.Path("/articles/{category}/{id:[0-9]+}").
|
|
| 349 |
-// Handler(ArticleHandler) |
|
| 345 |
+// r := mux.NewRouter().NewRoute() |
|
| 346 |
+// r.Path("/products/").Handler(ProductsHandler)
|
|
| 347 |
+// r.Path("/products/{key}").Handler(ProductsHandler)
|
|
| 348 |
+// r.Path("/articles/{category}/{id:[0-9]+}").
|
|
| 349 |
+// Handler(ArticleHandler) |
|
| 350 | 350 |
// |
| 351 | 351 |
// Variable names must be unique in a given route. They can be retrieved |
| 352 | 352 |
// calling mux.Vars(request). |
| ... | ... |
@@ -377,8 +387,8 @@ func (r *Route) PathPrefix(tpl string) *Route {
|
| 377 | 377 |
// It accepts a sequence of key/value pairs. Values may define variables. |
| 378 | 378 |
// For example: |
| 379 | 379 |
// |
| 380 |
-// r := mux.NewRouter() |
|
| 381 |
-// r.Queries("foo", "bar", "id", "{id:[0-9]+}")
|
|
| 380 |
+// r := mux.NewRouter().NewRoute() |
|
| 381 |
+// r.Queries("foo", "bar", "id", "{id:[0-9]+}")
|
|
| 382 | 382 |
// |
| 383 | 383 |
// The above route will only match if the URL contains the defined queries |
| 384 | 384 |
// values, e.g.: ?foo=bar&id=42. |
| ... | ... |
@@ -473,11 +483,11 @@ func (r *Route) BuildVarsFunc(f BuildVarsFunc) *Route {
|
| 473 | 473 |
// |
| 474 | 474 |
// It will test the inner routes only if the parent route matched. For example: |
| 475 | 475 |
// |
| 476 |
-// r := mux.NewRouter() |
|
| 477 |
-// s := r.Host("www.example.com").Subrouter()
|
|
| 478 |
-// s.HandleFunc("/products/", ProductsHandler)
|
|
| 479 |
-// s.HandleFunc("/products/{key}", ProductHandler)
|
|
| 480 |
-// s.HandleFunc("/articles/{category}/{id:[0-9]+}"), ArticleHandler)
|
|
| 476 |
+// r := mux.NewRouter().NewRoute() |
|
| 477 |
+// s := r.Host("www.example.com").Subrouter()
|
|
| 478 |
+// s.HandleFunc("/products/", ProductsHandler)
|
|
| 479 |
+// s.HandleFunc("/products/{key}", ProductHandler)
|
|
| 480 |
+// s.HandleFunc("/articles/{category}/{id:[0-9]+}"), ArticleHandler)
|
|
| 481 | 481 |
// |
| 482 | 482 |
// Here, the routes registered in the subrouter won't be tested if the host |
| 483 | 483 |
// doesn't match. |
| ... | ... |
@@ -497,36 +507,36 @@ func (r *Route) Subrouter() *Router {
|
| 497 | 497 |
// It accepts a sequence of key/value pairs for the route variables. For |
| 498 | 498 |
// example, given this route: |
| 499 | 499 |
// |
| 500 |
-// r := mux.NewRouter() |
|
| 501 |
-// r.HandleFunc("/articles/{category}/{id:[0-9]+}", ArticleHandler).
|
|
| 502 |
-// Name("article")
|
|
| 500 |
+// r := mux.NewRouter() |
|
| 501 |
+// r.HandleFunc("/articles/{category}/{id:[0-9]+}", ArticleHandler).
|
|
| 502 |
+// Name("article")
|
|
| 503 | 503 |
// |
| 504 | 504 |
// ...a URL for it can be built using: |
| 505 | 505 |
// |
| 506 |
-// url, err := r.Get("article").URL("category", "technology", "id", "42")
|
|
| 506 |
+// url, err := r.Get("article").URL("category", "technology", "id", "42")
|
|
| 507 | 507 |
// |
| 508 | 508 |
// ...which will return an url.URL with the following path: |
| 509 | 509 |
// |
| 510 |
-// "/articles/technology/42" |
|
| 510 |
+// "/articles/technology/42" |
|
| 511 | 511 |
// |
| 512 | 512 |
// This also works for host variables: |
| 513 | 513 |
// |
| 514 |
-// r := mux.NewRouter() |
|
| 515 |
-// r.HandleFunc("/articles/{category}/{id:[0-9]+}", ArticleHandler).
|
|
| 516 |
-// Host("{subdomain}.domain.com").
|
|
| 517 |
-// Name("article")
|
|
| 514 |
+// r := mux.NewRouter() |
|
| 515 |
+// r.HandleFunc("/articles/{category}/{id:[0-9]+}", ArticleHandler).
|
|
| 516 |
+// Host("{subdomain}.domain.com").
|
|
| 517 |
+// Name("article")
|
|
| 518 | 518 |
// |
| 519 |
-// // url.String() will be "http://news.domain.com/articles/technology/42" |
|
| 520 |
-// url, err := r.Get("article").URL("subdomain", "news",
|
|
| 521 |
-// "category", "technology", |
|
| 522 |
-// "id", "42") |
|
| 519 |
+// // url.String() will be "http://news.domain.com/articles/technology/42" |
|
| 520 |
+// url, err := r.Get("article").URL("subdomain", "news",
|
|
| 521 |
+// "category", "technology", |
|
| 522 |
+// "id", "42") |
|
| 523 | 523 |
// |
| 524 | 524 |
// The scheme of the resulting url will be the first argument that was passed to Schemes: |
| 525 | 525 |
// |
| 526 |
-// // url.String() will be "https://example.com" |
|
| 527 |
-// r := mux.NewRouter() |
|
| 528 |
-// url, err := r.Host("example.com")
|
|
| 529 |
-// .Schemes("https", "http").URL()
|
|
| 526 |
+// // url.String() will be "https://example.com" |
|
| 527 |
+// r := mux.NewRouter().NewRoute() |
|
| 528 |
+// url, err := r.Host("example.com")
|
|
| 529 |
+// .Schemes("https", "http").URL()
|
|
| 530 | 530 |
// |
| 531 | 531 |
// All variables defined in the route are required, and their values must |
| 532 | 532 |
// conform to the corresponding patterns. |
| ... | ... |
@@ -718,6 +728,25 @@ func (r *Route) GetHostTemplate() (string, error) {
|
| 718 | 718 |
return r.regexp.host.template, nil |
| 719 | 719 |
} |
| 720 | 720 |
|
| 721 |
+// GetVarNames returns the names of all variables added by regexp matchers |
|
| 722 |
+// These can be used to know which route variables should be passed into r.URL() |
|
| 723 |
+func (r *Route) GetVarNames() ([]string, error) {
|
|
| 724 |
+ if r.err != nil {
|
|
| 725 |
+ return nil, r.err |
|
| 726 |
+ } |
|
| 727 |
+ var varNames []string |
|
| 728 |
+ if r.regexp.host != nil {
|
|
| 729 |
+ varNames = append(varNames, r.regexp.host.varsN...) |
|
| 730 |
+ } |
|
| 731 |
+ if r.regexp.path != nil {
|
|
| 732 |
+ varNames = append(varNames, r.regexp.path.varsN...) |
|
| 733 |
+ } |
|
| 734 |
+ for _, regx := range r.regexp.queries {
|
|
| 735 |
+ varNames = append(varNames, regx.varsN...) |
|
| 736 |
+ } |
|
| 737 |
+ return varNames, nil |
|
| 738 |
+} |
|
| 739 |
+ |
|
| 721 | 740 |
// prepareVars converts the route variable pairs into a map. If the route has a |
| 722 | 741 |
// BuildVarsFunc, it is invoked. |
| 723 | 742 |
func (r *Route) prepareVars(pairs ...string) (map[string]string, error) {
|
| ... | ... |
@@ -593,8 +593,8 @@ github.com/googleapis/gax-go/v2 |
| 593 | 593 |
github.com/googleapis/gax-go/v2/apierror |
| 594 | 594 |
github.com/googleapis/gax-go/v2/apierror/internal/proto |
| 595 | 595 |
github.com/googleapis/gax-go/v2/internal |
| 596 |
-# github.com/gorilla/mux v1.8.0 |
|
| 597 |
-## explicit; go 1.12 |
|
| 596 |
+# github.com/gorilla/mux v1.8.1 |
|
| 597 |
+## explicit; go 1.20 |
|
| 598 | 598 |
github.com/gorilla/mux |
| 599 | 599 |
# github.com/grpc-ecosystem/go-grpc-middleware v1.3.0 |
| 600 | 600 |
## explicit; go 1.14 |