Repository: gorilla/mux
Pull request #431 (2018-12-20 20:17:25)

fix for issue #429
fix for issue #429


maplebed: 💚 thank you for this patch.

Patch:
diff --git a/README.md b/README.md
index 0425bb8..9e99a27 100644
--- a/README.md
+++ b/README.md
@@ -88,7 +88,7 @@ r := mux.NewRouter()
 // Only matches if domain is "www.example.com".
 r.Host("www.example.com")
 // Matches a dynamic subdomain.
-r.Host("{subdomain:[a-z]+}.domain.com")
+r.Host("{subdomain:[a-z]+}.example.com")
 ```
 
 There are several other matchers that can be added. To match path prefixes:
@@ -238,13 +238,13 @@ This also works for host and query value variables:
 
 ```go
 r := mux.NewRouter()
-r.Host("{subdomain}.domain.com").
+r.Host("{subdomain}.example.com").
   Path("/articles/{category}/{id:[0-9]+}").
   Queries("filter", "{filter}").
   HandlerFunc(ArticleHandler).
   Name("article")
 
-// url.String() will be "http://news.domain.com/articles/technology/42?filter=gorilla"
+// url.String() will be "http://news.example.com/articles/technology/42?filter=gorilla"
 url, err := r.Get("article").URL("subdomain", "news",
                                  "category", "technology",
                                  "id", "42",
@@ -264,7 +264,7 @@ r.HeadersRegexp("Content-Type", "application/(text|json)")
 There's also a way to build only the URL host or path for a route: use the methods `URLHost()` or `URLPath()` instead. For the previous route, we would do:
 
 ```go
-// "http://news.domain.com/"
+// "http://news.example.com/"
 host, err := r.Get("article").URLHost("subdomain", "news")
 
 // "/articles/technology/42"
@@ -275,12 +275,12 @@ And if you use subrouters, host and path defined separately can be built as well
 
 ```go
 r := mux.NewRouter()
-s := r.Host("{subdomain}.domain.com").Subrouter()
+s := r.Host("{subdomain}.example.com").Subrouter()
 s.Path("/articles/{category}/{id:[0-9]+}").
   HandlerFunc(ArticleHandler).
   Name("article")
 
-// "http://news.domain.com/articles/technology/42"
+// "http://news.example.com/articles/technology/42"
 url, err := r.Get("article").URL("subdomain", "news",
                                  "category", "technology",
                                  "id", "42")
diff --git a/route.go b/route.go
index acef919..a197096 100644
--- a/route.go
+++ b/route.go
@@ -43,6 +43,11 @@ func (r *Route) Match(req *http.Request, match *RouteMatch) bool {
 		return false
 	}
 
+	// Set MatchErr to nil to prevent
+	// subsequent matching subrouters from failing to run middleware.
+	// If not reset, the middleware would see a non-nil MatchErr and be skipped,
+	// even when there was a matching route.
+	match.MatchErr = nil
 	var matchErr error
 
 	// Match everything.


Test patch:
diff --git a/middleware_test.go b/middleware_test.go
index acf4e16..b708be0 100644
--- a/middleware_test.go
+++ b/middleware_test.go
@@ -375,3 +375,63 @@ func TestCORSMethodMiddleware(t *testing.T) {
 		}
 	}
 }
+
+func TestMiddlewareOnMultiSubrouter(t *testing.T) {
+	first := "first"
+	second := "second"
+	notFound := "404 not found"
+
+	router := NewRouter()
+	firstSubRouter := router.PathPrefix("/").Subrouter()
+	secondSubRouter := router.PathPrefix("/").Subrouter()
+
+	router.NotFoundHandler = http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
+		rw.Write([]byte(notFound))
+	})
+
+	firstSubRouter.HandleFunc("/first", func(w http.ResponseWriter, r *http.Request) {
+
+	})
+
+	secondSubRouter.HandleFunc("/second", func(w http.ResponseWriter, r *http.Request) {
+
+	})
+
+	firstSubRouter.Use(func(h http.Handler) http.Handler {
+		return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+			w.Write([]byte(first))
+			h.ServeHTTP(w, r)
+		})
+	})
+
+	secondSubRouter.Use(func(h http.Handler) http.Handler {
+		return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+			w.Write([]byte(second))
+			h.ServeHTTP(w, r)
+		})
+	})
+
+	rw := NewRecorder()
+	req := newRequest("GET", "/first")
+
+	router.ServeHTTP(rw, req)
+	if rw.Body.String() != first {
+		t.Fatalf("Middleware did not run: expected %s middleware to write a response (got %s)", first, rw.Body.String())
+	}
+
+	rw = NewRecorder()
+	req = newRequest("GET", "/second")
+
+	router.ServeHTTP(rw, req)
+	if rw.Body.String() != second {
+		t.Fatalf("Middleware did not run: expected %s middleware to write a response (got %s)", second, rw.Body.String())
+	}
+
+	rw = NewRecorder()
+	req = newRequest("GET", "/second/not-exist")
+
+	router.ServeHTTP(rw, req)
+	if rw.Body.String() != notFound {
+		t.Fatalf("Notfound handler did not run: expected %s for not-exist, (got %s)", notFound, rw.Body.String())
+	}
+}