Browse code

vendor: github.com/gorilla/mux v1.8.1

full diff: https://github.com/gorilla/mux/compare/v1.8.0...v1.8.1

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>

Sebastiaan van Stijn authored on 2023/12/01 20:48:09
Showing 12 changed files
... ...
@@ -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=
700 701
new file mode 100644
... ...
@@ -0,0 +1 @@
0
+coverage.coverprofile
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
-[![GoDoc](https://godoc.org/github.com/gorilla/mux?status.svg)](https://godoc.org/github.com/gorilla/mux)
4
-[![CircleCI](https://circleci.com/gh/gorilla/mux.svg?style=svg)](https://circleci.com/gh/gorilla/mux)
5
-[![Sourcegraph](https://sourcegraph.com/github.com/gorilla/mux/-/badge.svg)](https://sourcegraph.com/github.com/gorilla/mux?badge)
3
+![testing](https://github.com/gorilla/mux/actions/workflows/test.yml/badge.svg)
4
+[![codecov](https://codecov.io/github/gorilla/mux/branch/main/graph/badge.svg)](https://codecov.io/github/gorilla/mux)
5
+[![godoc](https://godoc.org/github.com/gorilla/mux?status.svg)](https://godoc.org/github.com/gorilla/mux)
6
+[![sourcegraph](https://sourcegraph.com/github.com/gorilla/mux/-/badge.svg)](https://sourcegraph.com/github.com/gorilla/mux?badge)
6 7
 
7
-![Gorilla Logo](https://cloud-cdn.questionable.services/gorilla-icon-64.png)
8 8
 
9
-https://www.gorillatoolkit.org/pkg/mux
9
+![Gorilla Logo](https://github.com/gorilla/.github/assets/53367916/d92caabf-98e0-473e-bfbf-ab554ba435e5)
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