Repository: gin-gonic/gin (go)

Issue:
Multiple slashes in path is not working
## Description

Multiple slashes in path can't be routed!

In stdlib http, the [ServeMux](https://golang.org/src/net/http/server.go?s=40985:41006#L2313) use `cleanPath` on `path`. 

![image](https://user-images.githubusercontent.com/1881126/48471233-65de3080-e82e-11e8-9b52-61f5d58c1292.png)

## Screenshots

![image](https://user-images.githubusercontent.com/1881126/48470955-ca4cc000-e82d-11e8-84f4-fbcd51103e68.png)




Pull request description:
Clean the Request Path early
This will reduce the number of times we have to do a redirect
and allow multiple slashes in path to be routed!
fixes #1644

Patch:
diff --git a/gin.go b/gin.go
index 2d24092..4dbe983 100644
--- a/gin.go
+++ b/gin.go
@@ -372,6 +372,7 @@ func (engine *Engine) handleHTTPRequest(c *Context) {
 		rPath = c.Request.URL.RawPath
 		unescape = engine.UnescapePathValues
 	}
+	rPath = cleanPath(rPath)
 
 	// Find root of the tree for the given HTTP method
 	t := engine.trees


Test patch:
diff --git a/routes_test.go b/routes_test.go
index de363a8..e16c137 100644
--- a/routes_test.go
+++ b/routes_test.go
@@ -22,7 +22,7 @@ type header struct {
 }
 
 func performRequest(r http.Handler, method, path string, headers ...header) *httptest.ResponseRecorder {
-	req, _ := http.NewRequest(method, path, nil)
+	req := httptest.NewRequest(method, path, nil)
 	for _, h := range headers {
 		req.Header.Add(h.Key, h.Value)
 	}
@@ -257,6 +257,39 @@ func TestRouteParamsByName(t *testing.T) {
 	assert.Equal(t, "/is/super/great", wild)
 }
 
+// TestContextParamsGet tests that a parameter can be parsed from the URL even with extra slashes.
+func TestRouteParamsByNameWithExtraSlash(t *testing.T) {
+	name := ""
+	lastName := ""
+	wild := ""
+	router := New()
+	router.GET("/test/:name/:last_name/*wild", func(c *Context) {
+		name = c.Params.ByName("name")
+		lastName = c.Params.ByName("last_name")
+		var ok bool
+		wild, ok = c.Params.Get("wild")
+
+		assert.True(t, ok)
+		assert.Equal(t, name, c.Param("name"))
+		assert.Equal(t, name, c.Param("name"))
+		assert.Equal(t, lastName, c.Param("last_name"))
+
+		assert.Empty(t, c.Param("wtf"))
+		assert.Empty(t, c.Params.ByName("wtf"))
+
+		wtf, ok := c.Params.Get("wtf")
+		assert.Empty(t, wtf)
+		assert.False(t, ok)
+	})
+
+	w := performRequest(router, "GET", "//test//john//smith//is//super//great")
+
+	assert.Equal(t, http.StatusOK, w.Code)
+	assert.Equal(t, "john", name)
+	assert.Equal(t, "smith", lastName)
+	assert.Equal(t, "/is/super/great", wild)
+}
+
 // TestHandleStaticFile - ensure the static file handles properly
 func TestRouteStaticFile(t *testing.T) {
 	// SETUP file
@@ -386,15 +419,14 @@ func TestRouterNotFound(t *testing.T) {
 		code     int
 		location string
 	}{
-		{"/path/", http.StatusMovedPermanently, "/path"},   // TSR -/
-		{"/dir", http.StatusMovedPermanently, "/dir/"},     // TSR +/
-		{"", http.StatusMovedPermanently, "/"},             // TSR +/
-		{"/PATH", http.StatusMovedPermanently, "/path"},    // Fixed Case
-		{"/DIR/", http.StatusMovedPermanently, "/dir/"},    // Fixed Case
-		{"/PATH/", http.StatusMovedPermanently, "/path"},   // Fixed Case -/
-		{"/DIR", http.StatusMovedPermanently, "/dir/"},     // Fixed Case +/
-		{"/../path", http.StatusMovedPermanently, "/path"}, // CleanPath
-		{"/nope", http.StatusNotFound, ""},                 // NotFound
+		{"/path/", http.StatusMovedPermanently, "/path"}, // TSR -/
+		{"/dir", http.StatusMovedPermanently, "/dir/"},   // TSR +/
+		{"/PATH", http.StatusMovedPermanently, "/path"},  // Fixed Case
+		{"/DIR/", http.StatusMovedPermanently, "/dir/"},  // Fixed Case
+		{"/PATH/", http.StatusMovedPermanently, "/path"}, // Fixed Case -/
+		{"/DIR", http.StatusMovedPermanently, "/dir/"},   // Fixed Case +/
+		{"/../path", http.StatusOK, ""},                  // CleanPath
+		{"/nope", http.StatusNotFound, ""},               // NotFound
 	}
 	for _, tr := range testRoutes {
 		w := performRequest(router, "GET", tr.route)