Repository: labstack/echo
Pull request #1706 (2020-12-02 12:57:46)

Add the ability to change the status code using Response beforeFuncs

codecov[bot]: # [Codecov](https://codecov.io/gh/labstack/echo/pull/1706?src=pr&el=h1) Report
> Merging [#1706](https://codecov.io/gh/labstack/echo/pull/1706?src=pr&el=desc) (d08b607) into [master](https://codecov.io/gh/labstack/echo/commit/b90e4e8ea15cbebae3b3a171261ebc20d4cec3ac?el=desc) (b90e4e8) will **not change** coverage.
> The diff coverage is `100.00%`.

[![Impacted file tree graph](https://codecov.io/gh/labstack/echo/pull/1706/graphs/tree.svg?width=650&height=150&src=pr&token=vqnT76l79i)](https://codecov.io/gh/labstack/echo/pull/1706?src=pr&el=tree)

```diff
@@           Coverage Diff           @@
##           master    #1706   +/-   ##
=======================================
  Coverage   84.88%   84.88%           
=======================================
  Files          29       29           
  Lines        1945     1945           
=======================================
  Hits         1651     1651           
  Misses        187      187           
  Partials      107      107           
```


| [Impacted Files](https://codecov.io/gh/labstack/echo/pull/1706?src=pr&el=tree) | Coverage Δ | |
|---|---|---|
| [response.go](https://codecov.io/gh/labstack/echo/pull/1706/diff?src=pr&el=tree#diff-cmVzcG9uc2UuZ28=) | `85.18% <100.00%> (ø)` | |

------

[Continue to review full report at Codecov](https://codecov.io/gh/labstack/echo/pull/1706?src=pr&el=continue).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/labstack/echo/pull/1706?src=pr&el=footer). Last update [b90e4e8...d08b607](https://codecov.io/gh/labstack/echo/pull/1706?src=pr&el=lastupdated). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments).

iambenkay: Any reason for this change?
RashadAnsari: > Any reason for this change?
> If you could link an issue or something

Hi @iambenkay 

We need to change the status code of a request in some situations using the middleware.

For example:

```go
e.Use(func(next echo.HandlerFunc) echo.HandlerFunc {
	return func(c echo.Context) error {
		c.Response().Before(func() {
			if 200 < c.Response().Status && c.Response().Status < 300 {
				c.Response().Status = 200
			}
		})

		return next(c)
	}
})
```


iambenkay: okay I understand. so you need it set before the `beforeFuncs` are called.
makes sense. Nice one.
iambenkay: @lammel 
lammel: @RashadAnsari If we make this an intended behaviour, we should a test for it too, to ensure it stays that way.
Could you a test (like in your example with mapping status 2xx to 200) for it too please.

I will merge then.

Patch:
diff --git a/_fixture/_fixture/README.md b/_fixture/_fixture/README.md
deleted file mode 100644
index 21a7858..0000000
--- a/_fixture/_fixture/README.md
+++ /dev/null
@@ -1,1 +0,0 @@
-This directory is used for the static middleware test
\ No newline at end of file
diff --git a/middleware/jwt.go b/middleware/jwt.go
index da00ea5..bab00c9 100644
--- a/middleware/jwt.go
+++ b/middleware/jwt.go
@@ -57,7 +57,6 @@ type (
 		// - "query:<name>"
 		// - "param:<name>"
 		// - "cookie:<name>"
-		// - "form:<name>"
 		TokenLookup string
 
 		// AuthScheme to be used in the Authorization header.
@@ -168,8 +167,6 @@ func JWTWithConfig(config JWTConfig) echo.MiddlewareFunc {
 		extractor = jwtFromParam(parts[1])
 	case "cookie":
 		extractor = jwtFromCookie(parts[1])
-	case "form":
-		extractor = jwtFromForm(parts[1])
 	}
 
 	return func(next echo.HandlerFunc) echo.HandlerFunc {
@@ -269,14 +266,3 @@ func jwtFromCookie(name string) jwtExtractor {
 		return cookie.Value, nil
 	}
 }
-
-// jwtFromForm returns a `jwtExtractor` that extracts token from the form field.
-func jwtFromForm(name string) jwtExtractor {
-	return func(c echo.Context) (string, error) {
-		field := c.FormValue(name)
-		if field == "" {
-			return "", ErrJWTMissing
-		}
-		return field, nil
-	}
-}
diff --git a/middleware/static.go b/middleware/static.go
index 58b7890..bc2087a 100644
--- a/middleware/static.go
+++ b/middleware/static.go
@@ -36,12 +36,6 @@ type (
 		// Enable directory browsing.
 		// Optional. Default value false.
 		Browse bool `yaml:"browse"`
-
-		// Enable ignoring of the base of the URL path.
-		// Example: when assigning a static middleware to a non root path group,
-		// the filesystem path is not doubled
-		// Optional. Default value false.
-		IgnoreBase bool `yaml:"ignoreBase"`
 	}
 )
 
@@ -169,15 +163,6 @@ func StaticWithConfig(config StaticConfig) echo.MiddlewareFunc {
 			}
 			name := filepath.Join(config.Root, path.Clean("/"+p)) // "/"+ for security
 
-			if config.IgnoreBase {
-				routePath := path.Base(strings.TrimRight(c.Path(), "/*"))
-				baseURLPath := path.Base(p)
-				if baseURLPath == routePath {
-					i := strings.LastIndex(name, routePath)
-					name = name[:i] + strings.Replace(name[i:], routePath, "", 1)
-				}
-			}
-
 			fi, err := os.Stat(name)
 			if err != nil {
 				if os.IsNotExist(err) {
diff --git a/response.go b/response.go
index ca7405c..84f7c9e 100644
--- a/response.go
+++ b/response.go
@@ -56,11 +56,11 @@ func (r *Response) WriteHeader(code int) {
 		r.echo.Logger.Warn("response already committed")
 		return
 	}
+	r.Status = code
 	for _, fn := range r.beforeFuncs {
 		fn()
 	}
-	r.Status = code
-	r.Writer.WriteHeader(code)
+	r.Writer.WriteHeader(r.Status)
 	r.Committed = true
 }
 


Test patch:
diff --git a/middleware/jwt_test.go b/middleware/jwt_test.go
index 205721a..ce44f9c 100644
--- a/middleware/jwt_test.go
+++ b/middleware/jwt_test.go
@@ -3,8 +3,6 @@ package middleware
 import (
 	"net/http"
 	"net/http/httptest"
-	"net/url"
-	"strings"
 	"testing"
 
 	"github.com/dgrijalva/jwt-go"
@@ -77,7 +75,6 @@ func TestJWT(t *testing.T) {
 		reqURL     string // "/" if empty
 		hdrAuth    string
 		hdrCookie  string // test.Request doesn't provide SetCookie(); use name=val
-		formValues map[string]string
 		info       string
 	}{
 		{
@@ -195,48 +192,12 @@ func TestJWT(t *testing.T) {
 			expErrCode: http.StatusBadRequest,
 			info:       "Empty cookie",
 		},
-		{
-			config: JWTConfig{
-				SigningKey:  validKey,
-				TokenLookup: "form:jwt",
-			},
-			formValues: map[string]string{"jwt": token},
-			info:       "Valid form method",
-		},
-		{
-			config: JWTConfig{
-				SigningKey:  validKey,
-				TokenLookup: "form:jwt",
-			},
-			expErrCode: http.StatusUnauthorized,
-			formValues: map[string]string{"jwt": "invalid"},
-			info:       "Invalid token with form method",
-		},
-		{
-			config: JWTConfig{
-				SigningKey:  validKey,
-				TokenLookup: "form:jwt",
-			},
-			expErrCode: http.StatusBadRequest,
-			info:       "Empty form field",
-		},
 	} {
 		if tc.reqURL == "" {
 			tc.reqURL = "/"
 		}
 
-		var req *http.Request
-		if len(tc.formValues) > 0 {
-			form := url.Values{}
-			for k, v := range tc.formValues {
-				form.Set(k, v)
-			}
-			req = httptest.NewRequest(http.MethodPost, tc.reqURL, strings.NewReader(form.Encode()))
-			req.Header.Set(echo.HeaderContentType, "application/x-www-form-urlencoded")
-			req.ParseForm()
-		} else {
-			req = httptest.NewRequest(http.MethodGet, tc.reqURL, nil)
-		}
+		req := httptest.NewRequest(http.MethodGet, tc.reqURL, nil)
 		res := httptest.NewRecorder()
 		req.Header.Set(echo.HeaderAuthorization, tc.hdrAuth)
 		req.Header.Set(echo.HeaderCookie, tc.hdrCookie)
diff --git a/middleware/static_test.go b/middleware/static_test.go
index 407dd15..0d695d3 100644
--- a/middleware/static_test.go
+++ b/middleware/static_test.go
@@ -3,7 +3,6 @@ package middleware
 import (
 	"net/http"
 	"net/http/httptest"
-	"path/filepath"
 	"testing"
 
 	"github.com/labstack/echo/v4"
@@ -68,27 +67,4 @@ func TestStatic(t *testing.T) {
 		assert.Equal(http.StatusOK, rec.Code)
 		assert.Contains(rec.Body.String(), "cert.pem")
 	}
-
-	// IgnoreBase
-	req = httptest.NewRequest(http.MethodGet, "/_fixture", nil)
-	rec = httptest.NewRecorder()
-	config.Root = "../_fixture"
-	config.IgnoreBase = true
-	static = StaticWithConfig(config)
-	c.Echo().Group("_fixture", static)
-	e.ServeHTTP(rec, req)
-
-	assert.Equal(http.StatusOK, rec.Code)
-	assert.Equal(rec.Header().Get(echo.HeaderContentLength), "122")
-
-	req = httptest.NewRequest(http.MethodGet, "/_fixture", nil)
-	rec = httptest.NewRecorder()
-	config.Root = "../_fixture"
-	config.IgnoreBase = false
-	static = StaticWithConfig(config)
-	c.Echo().Group("_fixture", static)
-	e.ServeHTTP(rec, req)
-
-	assert.Equal(http.StatusOK, rec.Code)
-	assert.Contains(rec.Body.String(), filepath.Join("..", "_fixture", "_fixture"))
 }
diff --git a/response_test.go b/response_test.go
index 7a9c51c..d95e079 100644
--- a/response_test.go
+++ b/response_test.go
@@ -56,3 +56,19 @@ func TestResponse_Flush(t *testing.T) {
 	res.Flush()
 	assert.True(t, rec.Flushed)
 }
+
+func TestResponse_ChangeStatusCodeBeforeWrite(t *testing.T) {
+	e := New()
+	rec := httptest.NewRecorder()
+	res := &Response{echo: e, Writer: rec}
+
+	res.Before(func() {
+		if 200 < res.Status && res.Status < 300 {
+			res.Status = 200
+		}
+	})
+
+	res.WriteHeader(209)
+
+	assert.Equal(t, http.StatusOK, rec.Code)
+}