diff --git a/HISTORY.md b/HISTORY.md index 55d718f8..3b894a05 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.1.2 -> 6.1.3 + +- Added a configuration field `iris.Config.DisableBodyConsumptionOnUnmarshal` + +```go +// DisableBodyConsumptionOnUnmarshal manages the reading behavior of the context's body readers/binders. +// If setted to true then it +// disables the body consumption by the `context.UnmarshalBody/ReadJSON/ReadXML`. +// +// By-default io.ReadAll` is used to read the body from the `context.Request.Body which is an `io.ReadCloser`, +// if this field setted to true then a new buffer will be created to read from and the request body. +// The body will not be changed and existing data before the context.UnmarshalBody/ReadJSON/ReadXML will be not consumed. +DisableBodyConsumptionOnUnmarshal bool +``` + +If that option is setted to true then you can read more than one times from the same `context.Request.Body`. +Defaults to false because the majority of developers expecting request body to be empty after unmarshal. + + ## 6.1.1 -> 6.1.2 Better internalization and localization support, with ability to change the cookie's key and context's keys. diff --git a/README.md b/README.md index 0f3618e3..b88310e3 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@
-
@@ -20,7 +20,7 @@
-
+
@@ -68,7 +68,7 @@ package main
import (
"github.com/kataras/iris"
"github.com/kataras/go-template/html"
-)
+)
func main(){
@@ -83,34 +83,34 @@ func main(){
//
// Use the html standard engine for all files inside "./views" folder with extension ".html"
iris.UseTemplate(html.New()).Directory("./views", ".html")
-
+
// http://localhost:6111
// Method: "GET"
// Render ./views/index.html
iris.Get("/", func(ctx *iris.Context){
ctx.Render("index.html", nil)
})
-
- // Group routes, optionally: share middleware, template layout and custom http errors.
+
+ // Group routes, optionally: share middleware, template layout and custom http errors.
userAPI := iris.Party("/users", userAPIMiddleware).
Layout("layouts/userLayout.html")
{
- // Fire userNotFoundHandler when Not Found
+ // Fire userNotFoundHandler when Not Found
// inside http://localhost:6111/users/*anything
userAPI.OnError(404, userNotFoundHandler)
-
+
// http://localhost:6111/users
// Method: "GET"
userAPI.Get("/", getAllHandler)
-
+
// http://localhost:6111/users/42
// Method: "GET"
userAPI.Get("/:id", getByIDHandler)
-
+
// http://localhost:6111/users
// Method: "POST"
userAPI.Post("/", saveUserHandler)
- }
+ }
getByIDHandler := func(ctx *iris.Context){
// take the :id from the path, parse to integer
@@ -128,7 +128,7 @@ func main(){
// like the iris.Map{"username" : user.Username}.
ctx.JSON(iris.StatusOK, user)
}
-
+
// Start the server at 0.0.0.0:6111
iris.Listen(":6111")
}
@@ -209,7 +209,7 @@ Besides the fact that we have a [community chat][Chat] for questions or reports
Versioning
------------
-Current: **v6.1.2**
+Current: **v6.1.3**
v5: https://github.com/kataras/iris/tree/5.0.0
diff --git a/configuration.go b/configuration.go
index df2588fa..84c25d7b 100644
--- a/configuration.go
+++ b/configuration.go
@@ -150,6 +150,15 @@ type Configuration struct {
// Default is false
DisableBanner bool
+ // DisableBodyConsumptionOnUnmarshal manages the reading behavior of the context's body readers/binders.
+ // If setted to true then it
+ // disables the body consumption by the `context.UnmarshalBody/ReadJSON/ReadXML`.
+ //
+ // By-default io.ReadAll` is used to read the body from the `context.Request.Body which is an `io.ReadCloser`,
+ // if this field setted to true then a new buffer will be created to read from and the request body.
+ // The body will not be changed and existing data before the context.UnmarshalBody/ReadJSON/ReadXML will be not consumed.
+ DisableBodyConsumptionOnUnmarshal bool
+
// LoggerOut is the destination for output
//
// Default is os.Stdout
@@ -349,6 +358,19 @@ var (
}
}
+ // OptionDisableBodyConsumptionOnUnmarshal manages the reading behavior of the context's body readers/binders.
+ // If setted to true then it
+ // disables the body consumption by the `context.UnmarshalBody/ReadJSON/ReadXML`.
+ //
+ // By-default io.ReadAll` is used to read the body from the `context.Request.Body which is an `io.ReadCloser`,
+ // if this field setted to true then a new buffer will be created to read from and the request body.
+ // The body will not be changed and existing data before the context.UnmarshalBody/ReadJSON/ReadXML will be not consumed.
+ OptionDisableBodyConsumptionOnUnmarshal = func(val bool) OptionSet {
+ return func(c *Configuration) {
+ c.DisableBodyConsumptionOnUnmarshal = val
+ }
+ }
+
// OptionLoggerOut is the destination for output
//
// Default is os.Stdout
@@ -461,27 +483,28 @@ var (
// DefaultConfiguration returns the default configuration for an Iris station, fills the main Configuration
func DefaultConfiguration() Configuration {
return Configuration{
- VHost: "",
- VScheme: "",
- ReadTimeout: DefaultReadTimeout,
- WriteTimeout: DefaultWriteTimeout,
- MaxHeaderBytes: DefaultMaxHeaderBytes,
- CheckForUpdates: false,
- CheckForUpdatesSync: false,
- DisablePathCorrection: DefaultDisablePathCorrection,
- EnablePathEscape: DefaultEnablePathEscape,
- FireMethodNotAllowed: false,
- DisableBanner: false,
- LoggerOut: DefaultLoggerOut,
- LoggerPreffix: DefaultLoggerPreffix,
- DisableTemplateEngines: false,
- IsDevelopment: false,
- TimeFormat: DefaultTimeFormat,
- Charset: DefaultCharset,
- Gzip: false,
- Sessions: DefaultSessionsConfiguration(),
- Websocket: DefaultWebsocketConfiguration(),
- Other: options.Options{},
+ VHost: "",
+ VScheme: "",
+ ReadTimeout: DefaultReadTimeout,
+ WriteTimeout: DefaultWriteTimeout,
+ MaxHeaderBytes: DefaultMaxHeaderBytes,
+ CheckForUpdates: false,
+ CheckForUpdatesSync: false,
+ DisablePathCorrection: DefaultDisablePathCorrection,
+ EnablePathEscape: DefaultEnablePathEscape,
+ FireMethodNotAllowed: false,
+ DisableBanner: false,
+ DisableBodyConsumptionOnUnmarshal: false,
+ LoggerOut: DefaultLoggerOut,
+ LoggerPreffix: DefaultLoggerPreffix,
+ DisableTemplateEngines: false,
+ IsDevelopment: false,
+ TimeFormat: DefaultTimeFormat,
+ Charset: DefaultCharset,
+ Gzip: false,
+ Sessions: DefaultSessionsConfiguration(),
+ Websocket: DefaultWebsocketConfiguration(),
+ Other: options.Options{},
}
}
diff --git a/context.go b/context.go
index 061ca402..e7a9c4b3 100644
--- a/context.go
+++ b/context.go
@@ -548,6 +548,12 @@ func (ctx *Context) UnmarshalBody(v interface{}, unmarshaler Unmarshaler) error
return err
}
+ if ctx.framework.Config.DisableBodyConsumptionOnUnmarshal {
+ // * remember, Request.Body has no Bytes(), we have to consume them first
+ // and after re-set them to the body, this is the only solution.
+ ctx.Request.Body = ioutil.NopCloser(bytes.NewBuffer(rawData))
+ }
+
// check if the v contains its own decode
// in this case the v should be a pointer also,
// but this is up to the user's custom Decode implementation*
diff --git a/context_test.go b/context_test.go
index 5f3360ed..89170653 100644
--- a/context_test.go
+++ b/context_test.go
@@ -251,6 +251,13 @@ func testUnmarshaler(t *testing.T, tb *testBinder,
if write != nil {
write(ctx)
}
+
+ if iris.Config.DisableBodyConsumptionOnUnmarshal {
+ rawData, _ := ioutil.ReadAll(ctx.Request.Body)
+ if len(rawData) == 0 {
+ t.Fatalf("Expected data to NOT BE consumed by the previous UnmarshalBody call but we got empty body.")
+ }
+ }
}
iris.Post("/bind_req_body", h)
@@ -301,7 +308,6 @@ func TestContextBinders(t *testing.T) {
expectedObj.Birth + `