Not deterministic escaping of parameters extracted from path



I think, i’ve found a bug which causes not deterministic encoding/decoding of parameters extracted from path. Here is simple test:

import (

func TestEchoPathParam(t *testing.T) {
	for _, testCase := range []struct {
		path              string
		expectedNameValue string
		{path: "/resource/test1", expectedNameValue: "test1"},
		{path: "/resource/test%20test%2Ctest", expectedNameValue: "test%20test%2Ctest"},
		{path: "/resource/test%20test", expectedNameValue: "test%20test"},
	} {
		t.Logf("Testing path %s", testCase.path)
		req, _ := http.NewRequest("GET", testCase.path, nil)

		rw := httptest.NewRecorder()
		e := echo.New()
		var name string
		e.GET("/resource/:name", func(c echo.Context) error {
			name = c.Param("name")
			return c.String(http.StatusOK, "Hello, World!")
		e.ServeHTTP(rw, req)
		if rw.Code != 200 {
			t.Fatal("Expected 200 OK")
		if name != testCase.expectedNameValue {
			t.Fatalf("Expected name to be equal to '%s' but got '%s'", testCase.expectedNameValue, name)

It fails on third test (path="/resource/test%20test") because nameValue is in decoded form. So in the end we have situation when some of values are in encoded form and other are in decoded.

The root of the problem is using url.RawPath instead of url.EscapePath() in ServeHTTP method ( url.RawPath is only a hint for EscapePath and it’s filled with data only when go generates different form of encoded path comparing to original raw path. Golang documentation says: “In general, code should call EscapedPath instead of reading u.RawPath directly.”

Unfortunately i don’t know how to fix this issue without introducing “breaking change”.