diff --git a/HISTORY.md b/HISTORY.md
index f0f3b702..21c6f621 100644
--- a/HISTORY.md
+++ b/HISTORY.md
@@ -2,6 +2,25 @@
**How to upgrade**: remove your `$GOPATH/src/github.com/kataras` folder, open your command-line and execute this command: `go get -u github.com/kataras/iris/iris`.
+## 6.0.2 -> 6.0.3
+
+- Give the users an easy to way to set a limit to the body size comes from the client, globally or per-route (useful when you want to disable/enable limit on certain clients).
+
+```go
+// ...
+const maxBodySize = 1 << 20
+// ...
+
+api := iris.New()
+
+api.Use(iris.LimitRequestBodySize(maxBodySize))
+// or do it manually under certain situations,
+// inside the route's handler:
+// ctx.SetMaxRequestBodySize(maxBodySize)
+
+// routes after
+```
+
## 6.0.1 -> 6.0.2
- Fix subdomains (silly fix by checking the Request.Host vs Request.URL.Host) and add a more realistic test, as reported [here](https://github.com/kataras/iris/issues/574).
diff --git a/README.md b/README.md
index 18d0420d..466c7605 100644
--- a/README.md
+++ b/README.md
@@ -20,7 +20,7 @@
-
+
@@ -823,7 +823,7 @@ I recommend writing your API tests using this new library, [httpexpect](https://
Versioning
------------
-Current: **v6.0.2**
+Current: **v6.0.3**
Stable: **[v5/fasthttp](https://github.com/kataras/iris/tree/5.0.0)**
diff --git a/context.go b/context.go
index 7df6d055..dc637357 100644
--- a/context.go
+++ b/context.go
@@ -390,6 +390,25 @@ func (ctx *Context) FormFile(key string) (multipart.File, *multipart.FileHeader,
// -------------------------------------------------------------------------------------
// -------------------------------------------------------------------------------------
+// NOTE: No default max body size http package has some built'n protection for DoS attacks
+// See iris.Config.MaxBytesReader, https://github.com/golang/go/issues/2093#issuecomment-66057813
+// and https://github.com/golang/go/issues/2093#issuecomment-66057824
+
+// LimitRequestBodySize is a middleware which sets a request body size limit for all next handlers
+// should be registered before all other handlers
+var LimitRequestBodySize = func(maxRequestBodySizeBytes int64) HandlerFunc {
+ return func(ctx *Context) {
+ ctx.SetMaxRequestBodySize(maxRequestBodySizeBytes)
+ ctx.Next()
+ }
+}
+
+// SetMaxRequestBodySize sets a limit to the request body size
+// should be called before reading the request body from the client
+func (ctx *Context) SetMaxRequestBodySize(limitOverBytes int64) {
+ ctx.Request.Body = http.MaxBytesReader(ctx.ResponseWriter, ctx.Request.Body, limitOverBytes)
+}
+
// BodyDecoder is an interface which any struct can implement in order to customize the decode action
// from ReadJSON and ReadXML
//
diff --git a/context_test.go b/context_test.go
index c9bf836d..f42a2922 100644
--- a/context_test.go
+++ b/context_test.go
@@ -5,6 +5,7 @@ import (
"encoding/json"
"encoding/xml"
"fmt"
+ "io/ioutil"
"net/http"
"net/url"
"strconv"
@@ -766,3 +767,43 @@ func TestTransactions(t *testing.T) {
Body().
Equal(customErrorTemplateText)
}
+
+func TestLimitRequestBodySize(t *testing.T) {
+ const maxBodySize = 1 << 20
+
+ api := iris.New()
+
+ // or inside handler: ctx.SetMaxRequestBodySize(int64(maxBodySize))
+ api.Use(iris.LimitRequestBodySize(maxBodySize))
+
+ api.Post("/", func(ctx *iris.Context) {
+ b, err := ioutil.ReadAll(ctx.Request.Body)
+ if len(b) > maxBodySize {
+ // this is a fatal error it should never happened.
+ t.Fatalf("body is larger (%d) than maxBodySize (%d) even if we add the LimitRequestBodySize middleware", len(b), maxBodySize)
+ }
+ // if is larger then send a bad request status
+ if err != nil {
+ ctx.WriteHeader(iris.StatusBadRequest)
+ ctx.Writef(err.Error())
+ return
+ }
+
+ ctx.Write(b)
+ })
+
+ // UseGlobal should be called at the end used to prepend handlers
+ // api.UseGlobal(iris.LimitRequestBodySize(int64(maxBodySize)))
+
+ e := httptest.New(api, t)
+
+ // test with small body
+ e.POST("/").WithBytes([]byte("ok")).Expect().Status(iris.StatusOK).Body().Equal("ok")
+ // test with equal to max body size limit
+ bsent := make([]byte, maxBodySize, maxBodySize)
+ e.POST("/").WithBytes(bsent).Expect().Status(iris.StatusOK).Body().Length().Equal(len(bsent))
+ // test with larger body sent and wait for the custom response
+ largerBSent := make([]byte, maxBodySize+1, maxBodySize+1)
+ e.POST("/").WithBytes(largerBSent).Expect().Status(iris.StatusBadRequest).Body().Equal("http: request body too large")
+
+}
diff --git a/iris.go b/iris.go
index db5f8108..9e428a67 100644
--- a/iris.go
+++ b/iris.go
@@ -81,7 +81,7 @@ const (
// IsLongTermSupport flag is true when the below version number is a long-term-support version
IsLongTermSupport = false
// Version is the current version number of the Iris web framework
- Version = "6.0.2"
+ Version = "6.0.3"
banner = ` _____ _
|_ _| (_)
@@ -862,7 +862,7 @@ func (s *Framework) UseTemplate(e template.Engine) *template.Loader {
// UseGlobal registers Handler middleware to the beginning, prepends them instead of append
//
// Use it when you want to add a global middleware to all parties, to all routes in all subdomains
-// It can be called after other, (but before .Listen of course)
+// It should be called right before Listen functions
func UseGlobal(handlers ...Handler) {
Default.UseGlobal(handlers...)
}
@@ -870,7 +870,7 @@ func UseGlobal(handlers ...Handler) {
// UseGlobalFunc registers HandlerFunc middleware to the beginning, prepends them instead of append
//
// Use it when you want to add a global middleware to all parties, to all routes in all subdomains
-// It can be called after other, (but before .Listen of course)
+// It should be called right before Listen functions
func UseGlobalFunc(handlersFn ...HandlerFunc) {
Default.UseGlobalFunc(handlersFn...)
}
@@ -878,17 +878,22 @@ func UseGlobalFunc(handlersFn ...HandlerFunc) {
// UseGlobal registers Handler middleware to the beginning, prepends them instead of append
//
// Use it when you want to add a global middleware to all parties, to all routes in all subdomains
-// It can be called after other, (but before .Listen of course)
+// It should be called right before Listen functions
func (s *Framework) UseGlobal(handlers ...Handler) {
- for _, r := range s.mux.lookups {
- r.middleware = append(handlers, r.middleware...)
+ if len(s.mux.lookups) > 0 {
+ for _, r := range s.mux.lookups {
+ r.middleware = append(handlers, r.middleware...)
+ }
+ return
}
+
+ s.Use(handlers...)
}
// UseGlobalFunc registers HandlerFunc middleware to the beginning, prepends them instead of append
//
// Use it when you want to add a global middleware to all parties, to all routes in all subdomains
-// It can be called after other, (but before .Listen of course)
+// It should be called right before Listen functions
func (s *Framework) UseGlobalFunc(handlersFn ...HandlerFunc) {
s.UseGlobal(convertToHandlers(handlersFn)...)
}