Update to 6.0.3: Add an easy way to set a request body size limit per client or globally for newcomers

This commit is contained in:
Gerasimos (Makis) Maropoulos 2017-01-04 21:29:58 +02:00
parent 3b0a8e0f2d
commit d5a9410e2a
5 changed files with 93 additions and 9 deletions

View File

@ -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`. **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 ## 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). - 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).

View File

@ -20,7 +20,7 @@
<br/> <br/>
<a href="https://github.com/kataras/iris/releases"><img src="https://img.shields.io/badge/%20version%20-%206.0.2%20-blue.svg?style=flat-square" alt="Releases"></a> <a href="https://github.com/kataras/iris/releases"><img src="https://img.shields.io/badge/%20version%20-%206.0.3%20-blue.svg?style=flat-square" alt="Releases"></a>
<a href="https://github.com/iris-contrib/examples"><img src="https://img.shields.io/badge/%20examples-repository-3362c2.svg?style=flat-square" alt="Examples"></a> <a href="https://github.com/iris-contrib/examples"><img src="https://img.shields.io/badge/%20examples-repository-3362c2.svg?style=flat-square" alt="Examples"></a>
@ -823,7 +823,7 @@ I recommend writing your API tests using this new library, [httpexpect](https://
Versioning Versioning
------------ ------------
Current: **v6.0.2** Current: **v6.0.3**
Stable: **[v5/fasthttp](https://github.com/kataras/iris/tree/5.0.0)** Stable: **[v5/fasthttp](https://github.com/kataras/iris/tree/5.0.0)**

View File

@ -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 // BodyDecoder is an interface which any struct can implement in order to customize the decode action
// from ReadJSON and ReadXML // from ReadJSON and ReadXML
// //

View File

@ -5,6 +5,7 @@ import (
"encoding/json" "encoding/json"
"encoding/xml" "encoding/xml"
"fmt" "fmt"
"io/ioutil"
"net/http" "net/http"
"net/url" "net/url"
"strconv" "strconv"
@ -766,3 +767,43 @@ func TestTransactions(t *testing.T) {
Body(). Body().
Equal(customErrorTemplateText) 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")
}

19
iris.go
View File

@ -81,7 +81,7 @@ const (
// IsLongTermSupport flag is true when the below version number is a long-term-support version // IsLongTermSupport flag is true when the below version number is a long-term-support version
IsLongTermSupport = false IsLongTermSupport = false
// Version is the current version number of the Iris web framework // Version is the current version number of the Iris web framework
Version = "6.0.2" Version = "6.0.3"
banner = ` _____ _ 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 // 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 // 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) { func UseGlobal(handlers ...Handler) {
Default.UseGlobal(handlers...) Default.UseGlobal(handlers...)
} }
@ -870,7 +870,7 @@ func UseGlobal(handlers ...Handler) {
// UseGlobalFunc registers HandlerFunc middleware to the beginning, prepends them instead of append // 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 // 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) { func UseGlobalFunc(handlersFn ...HandlerFunc) {
Default.UseGlobalFunc(handlersFn...) Default.UseGlobalFunc(handlersFn...)
} }
@ -878,17 +878,22 @@ func UseGlobalFunc(handlersFn ...HandlerFunc) {
// UseGlobal registers Handler middleware to the beginning, prepends them instead of append // 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 // 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) { func (s *Framework) UseGlobal(handlers ...Handler) {
for _, r := range s.mux.lookups { if len(s.mux.lookups) > 0 {
r.middleware = append(handlers, r.middleware...) 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 // 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 // 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) { func (s *Framework) UseGlobalFunc(handlersFn ...HandlerFunc) {
s.UseGlobal(convertToHandlers(handlersFn)...) s.UseGlobal(convertToHandlers(handlersFn)...)
} }