diff --git a/echo.go b/echo.go index 6a6191d9..08d9a231 100644 --- a/echo.go +++ b/echo.go @@ -45,6 +45,7 @@ import ( stdLog "log" "net" "net/http" + "net/url" "path" "path/filepath" "reflect" @@ -434,7 +435,11 @@ func (e *Echo) Static(prefix, root string) { func static(i i, prefix, root string) { h := func(c Context) error { - name := filepath.Join(root, path.Clean("/"+c.Param("*"))) // "/"+ for security + p, err := url.PathUnescape(c.Param("*")) + if err != nil { + return err + } + name := filepath.Join(root, path.Clean("/"+p)) // "/"+ for security return c.File(name) } i.GET(prefix, h) @@ -542,7 +547,10 @@ func (e *Echo) ServeHTTP(w http.ResponseWriter, r *http.Request) { // Middleware h := func(c Context) error { method := r.Method - path := r.URL.Path + path := r.URL.RawPath + if path == "" { + path = r.URL.Path + } e.router.Find(method, path, c) h := c.Handler() for i := len(e.middleware) - 1; i >= 0; i-- { diff --git a/echo_test.go b/echo_test.go index 7ee26eb6..f9e56e8c 100644 --- a/echo_test.go +++ b/echo_test.go @@ -304,6 +304,17 @@ func TestEchoRoutes(t *testing.T) { } } +func TestEchoEncodedPath(t *testing.T) { + e := New() + e.GET("/:id", func(c Context) error { + return c.NoContent(http.StatusOK) + }) + req := httptest.NewRequest(GET, "/with%2Fslash", nil) + rec := httptest.NewRecorder() + e.ServeHTTP(rec, req) + assert.Equal(t, http.StatusOK, rec.Code) +} + func TestEchoGroup(t *testing.T) { e := New() buf := new(bytes.Buffer) diff --git a/middleware/static.go b/middleware/static.go index e715c1c4..f992773a 100644 --- a/middleware/static.go +++ b/middleware/static.go @@ -2,6 +2,7 @@ package middleware import ( "fmt" + "net/url" "os" "path" "path/filepath" @@ -66,7 +67,7 @@ func StaticWithConfig(config StaticConfig) echo.MiddlewareFunc { } return func(next echo.HandlerFunc) echo.HandlerFunc { - return func(c echo.Context) error { + return func(c echo.Context) (err error) { if config.Skipper(c) { return next(c) } @@ -75,6 +76,10 @@ func StaticWithConfig(config StaticConfig) echo.MiddlewareFunc { if strings.HasSuffix(c.Path(), "*") { // When serving from a group, e.g. `/static*`. p = c.Param("*") } + p, err = url.PathUnescape(p) + if err != nil { + return err + } name := filepath.Join(config.Root, path.Clean("/"+p)) // "/"+ for security fi, err := os.Stat(name)