mirror of
https://github.com/kataras/iris.git
synced 2025-01-23 10:41:03 +01:00
add a new 'Context.GzipReader(bool) method and 'iris.GzipReader' middleware as requested at #1528
Former-commit-id: 7665545069bf1784d17a9db1e5f9f5f8df4b0c43
This commit is contained in:
parent
9e5672da25
commit
1079bb8f8b
|
@ -371,7 +371,9 @@ Other Improvements:
|
||||||
|
|
||||||
![DBUG routes](https://iris-go.com/images/v12.2.0-dbug2.png?v=0)
|
![DBUG routes](https://iris-go.com/images/v12.2.0-dbug2.png?v=0)
|
||||||
|
|
||||||
- New builtin [JWT](https://github.com/kataras/iris/tree/master/jwt) middleware based on [square/go-jose](https://github.com/square/go-jose) featured with optional encryption to set claims with sensitive data when necessary.
|
- New builtin [requestid](https://github.com/kataras/iris/tree/master/middleware/requestid) middleware.
|
||||||
|
|
||||||
|
- New builtin [JWT](https://github.com/kataras/iris/tree/master/middleware/jwt) middleware based on [square/go-jose](https://github.com/square/go-jose) featured with optional encryption to set claims with sensitive data when necessary.
|
||||||
|
|
||||||
- `Context.ReadForm` now can return an `iris.ErrEmptyForm` instead of `nil` when the new `Configuration.FireEmptyFormError` is true (or `iris.WithEmptyFormError`) on missing form body to read from.
|
- `Context.ReadForm` now can return an `iris.ErrEmptyForm` instead of `nil` when the new `Configuration.FireEmptyFormError` is true (or `iris.WithEmptyFormError`) on missing form body to read from.
|
||||||
|
|
||||||
|
@ -413,6 +415,7 @@ New Package-level Variables:
|
||||||
|
|
||||||
New Context Methods:
|
New Context Methods:
|
||||||
|
|
||||||
|
- `Context.GzipReader(enable bool)` method and `iris.GzipReader` middleware to enable future request read body calls to decompress data using gzip, [example](_examples/http_request/read-gzip).
|
||||||
- `Context.RegisterDependency(v interface{})` and `Context.RemoveDependency(typ reflect.Type)` to register/remove struct dependencies on serve-time through a middleware.
|
- `Context.RegisterDependency(v interface{})` and `Context.RemoveDependency(typ reflect.Type)` to register/remove struct dependencies on serve-time through a middleware.
|
||||||
- `Context.SetID(id interface{})` and `Context.GetID() interface{}` added to register a custom unique indetifier to the Context, if necessary.
|
- `Context.SetID(id interface{})` and `Context.GetID() interface{}` added to register a custom unique indetifier to the Context, if necessary.
|
||||||
- `Context.GetDomain() string` returns the domain.
|
- `Context.GetDomain() string` returns the domain.
|
||||||
|
|
|
@ -112,6 +112,7 @@
|
||||||
* [Bind Custom per type](http_request/read-custom-per-type/main.go)
|
* [Bind Custom per type](http_request/read-custom-per-type/main.go)
|
||||||
* [Bind Custom via Unmarshaler](http_request/read-custom-via-unmarshaler/main.go)
|
* [Bind Custom via Unmarshaler](http_request/read-custom-via-unmarshaler/main.go)
|
||||||
* [Bind Many times](http_request/read-many/main.go)
|
* [Bind Many times](http_request/read-many/main.go)
|
||||||
|
* [Read/Bind Gzip compressed data](http_request/read-gzip/main.go)
|
||||||
* [Upload/Read File](http_request/upload-file/main.go)
|
* [Upload/Read File](http_request/upload-file/main.go)
|
||||||
* [Upload multiple Files](http_request/upload-files/main.go)
|
* [Upload multiple Files](http_request/upload-files/main.go)
|
||||||
* [Extract Referrer](http_request/extract-referer/main.go)
|
* [Extract Referrer](http_request/extract-referer/main.go)
|
||||||
|
|
|
@ -12,6 +12,9 @@ func main() {
|
||||||
|
|
||||||
func newApp() *iris.Application {
|
func newApp() *iris.Application {
|
||||||
app := iris.New()
|
app := iris.New()
|
||||||
|
// To automatically decompress using gzip:
|
||||||
|
// app.Use(iris.GzipReader)
|
||||||
|
|
||||||
app.Use(setAllowedResponses)
|
app.Use(setAllowedResponses)
|
||||||
|
|
||||||
app.Post("/", readBody)
|
app.Post("/", readBody)
|
||||||
|
|
44
_examples/http_request/read-gzip/main.go
Normal file
44
_examples/http_request/read-gzip/main.go
Normal file
|
@ -0,0 +1,44 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/kataras/iris/v12"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
app := newApp()
|
||||||
|
app.Logger().SetLevel("debug")
|
||||||
|
|
||||||
|
app.Listen(":8080")
|
||||||
|
}
|
||||||
|
|
||||||
|
type payload struct {
|
||||||
|
Message string `json:"message"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func newApp() *iris.Application {
|
||||||
|
app := iris.New()
|
||||||
|
|
||||||
|
// GzipReader is a middleware which enables gzip decompression,
|
||||||
|
// when client sends gzip compressed data.
|
||||||
|
//
|
||||||
|
// A shortcut of:
|
||||||
|
// func(ctx iris.Context) {
|
||||||
|
// ctx.GzipReader(true)
|
||||||
|
// ctx.Next()
|
||||||
|
// }
|
||||||
|
app.Use(iris.GzipReader)
|
||||||
|
|
||||||
|
app.Post("/", func(ctx iris.Context) {
|
||||||
|
// Bind incoming gzip compressed JSON to "p".
|
||||||
|
var p payload
|
||||||
|
if err := ctx.ReadJSON(&p); err != nil {
|
||||||
|
ctx.StopWithError(iris.StatusBadRequest, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Send back the message as plain text.
|
||||||
|
ctx.WriteString(p.Message)
|
||||||
|
})
|
||||||
|
|
||||||
|
return app
|
||||||
|
}
|
38
_examples/http_request/read-gzip/main_test.go
Normal file
38
_examples/http_request/read-gzip/main_test.go
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"compress/gzip"
|
||||||
|
"encoding/json"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/kataras/iris/v12/httptest"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestGzipReader(t *testing.T) {
|
||||||
|
app := newApp()
|
||||||
|
|
||||||
|
expected := payload{Message: "test"}
|
||||||
|
b, err := json.Marshal(expected)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
buf := new(bytes.Buffer)
|
||||||
|
w := gzip.NewWriter(buf)
|
||||||
|
_, err = w.Write(b)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
err = w.Close()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
e := httptest.New(t, app)
|
||||||
|
// send gzip compressed.
|
||||||
|
e.POST("/").WithHeader("Content-Encoding", "gzip").WithHeader("Content-Type", "application/json").
|
||||||
|
WithBytes(buf.Bytes()).Expect().Status(httptest.StatusOK).Body().Equal(expected.Message)
|
||||||
|
// raw.
|
||||||
|
e.POST("/").WithJSON(expected).Expect().Status(httptest.StatusOK).Body().Equal(expected.Message)
|
||||||
|
}
|
|
@ -34,6 +34,7 @@ import (
|
||||||
"github.com/iris-contrib/blackfriday"
|
"github.com/iris-contrib/blackfriday"
|
||||||
"github.com/iris-contrib/schema"
|
"github.com/iris-contrib/schema"
|
||||||
jsoniter "github.com/json-iterator/go"
|
jsoniter "github.com/json-iterator/go"
|
||||||
|
"github.com/klauspost/compress/gzip"
|
||||||
"github.com/microcosm-cc/bluemonday"
|
"github.com/microcosm-cc/bluemonday"
|
||||||
"github.com/vmihailenco/msgpack/v5"
|
"github.com/vmihailenco/msgpack/v5"
|
||||||
"golang.org/x/net/publicsuffix"
|
"golang.org/x/net/publicsuffix"
|
||||||
|
@ -789,6 +790,24 @@ type Context interface {
|
||||||
// supports gzip compression, so the following response data will
|
// supports gzip compression, so the following response data will
|
||||||
// be sent as compressed gzip data to the client.
|
// be sent as compressed gzip data to the client.
|
||||||
Gzip(enable bool)
|
Gzip(enable bool)
|
||||||
|
// GzipReader accepts a boolean, which, if set to true
|
||||||
|
// it wraps the request body reader with a gzip reader one (decompress request data on read).
|
||||||
|
// If the "enable" input argument is false then the request body will reset to the default one.
|
||||||
|
//
|
||||||
|
// Useful when incoming request data are gzip compressed.
|
||||||
|
// All future calls of `ctx.GetBody/ReadXXX/UnmarshalBody` methods will respect this option.
|
||||||
|
//
|
||||||
|
// Usage:
|
||||||
|
// app.Use(func(ctx iris.Context){
|
||||||
|
// ctx.GzipReader(true)
|
||||||
|
// ctx.Next()
|
||||||
|
// })
|
||||||
|
//
|
||||||
|
// If a client request's body is not gzip compressed then
|
||||||
|
// it returns with a `ErrGzipNotSupported` error, which can be safety ignored.
|
||||||
|
//
|
||||||
|
// See `GzipReader` package-level middleware too.
|
||||||
|
GzipReader(enable bool) error
|
||||||
|
|
||||||
// +------------------------------------------------------------+
|
// +------------------------------------------------------------+
|
||||||
// | Rich Body Content Writers/Renderers |
|
// | Rich Body Content Writers/Renderers |
|
||||||
|
@ -1197,6 +1216,18 @@ var Gzip = func(ctx Context) {
|
||||||
ctx.Next()
|
ctx.Next()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GzipReader is a middleware which enables gzip decompression,
|
||||||
|
// when client sends gzip compressed data.
|
||||||
|
//
|
||||||
|
// Similar to: func(ctx iris.Context) {
|
||||||
|
// ctx.GzipReader(true)
|
||||||
|
// ctx.Next()
|
||||||
|
// }
|
||||||
|
var GzipReader = func(ctx Context) {
|
||||||
|
ctx.GzipReader(true)
|
||||||
|
ctx.Next()
|
||||||
|
}
|
||||||
|
|
||||||
// Map is just a type alias of the map[string]interface{} type.
|
// Map is just a type alias of the map[string]interface{} type.
|
||||||
type Map = map[string]interface{}
|
type Map = map[string]interface{}
|
||||||
|
|
||||||
|
@ -3256,7 +3287,7 @@ func (ctx *context) ClientSupportsGzip() bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// ErrGzipNotSupported may be returned from `WriteGzip` methods if
|
// ErrGzipNotSupported may be returned from `WriteGzip` and `GzipReader` methods if
|
||||||
// the client does not support the "gzip" compression.
|
// the client does not support the "gzip" compression.
|
||||||
var ErrGzipNotSupported = errors.New("client does not support gzip compression")
|
var ErrGzipNotSupported = errors.New("client does not support gzip compression")
|
||||||
|
|
||||||
|
@ -3319,6 +3350,62 @@ func (ctx *context) Gzip(enable bool) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type gzipReadCloser struct {
|
||||||
|
requestReader io.ReadCloser
|
||||||
|
gzipReader io.ReadCloser
|
||||||
|
}
|
||||||
|
|
||||||
|
func (rc *gzipReadCloser) Close() error {
|
||||||
|
rc.gzipReader.Close()
|
||||||
|
return rc.requestReader.Close()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (rc *gzipReadCloser) Read(p []byte) (n int, err error) {
|
||||||
|
return rc.gzipReader.Read(p)
|
||||||
|
}
|
||||||
|
|
||||||
|
const gzipEncodingHeaderValue = "gzip"
|
||||||
|
|
||||||
|
// GzipReader accepts a boolean, which, if set to true
|
||||||
|
// it wraps the request body reader with a gzip reader one (decompress request data on read)..
|
||||||
|
// If the "enable" input argument is false then the request body will reset to the default one.
|
||||||
|
//
|
||||||
|
// Useful when incoming request data are gzip compressed.
|
||||||
|
// All future calls of `ctx.GetBody/ReadXXX/UnmarshalBody` methods will respect this option.
|
||||||
|
//
|
||||||
|
// Usage:
|
||||||
|
// app.Use(func(ctx iris.Context){
|
||||||
|
// ctx.GzipReader(true)
|
||||||
|
// ctx.Next()
|
||||||
|
// })
|
||||||
|
//
|
||||||
|
// If a client request's body is not gzip compressed then
|
||||||
|
// it returns with a `ErrGzipNotSupported` error, which can be safety ignored.
|
||||||
|
//
|
||||||
|
// See `GzipReader` package-level middleware too.
|
||||||
|
func (ctx *context) GzipReader(enable bool) error {
|
||||||
|
if enable {
|
||||||
|
if ctx.GetHeader(ContentEncodingHeaderKey) == gzipEncodingHeaderValue {
|
||||||
|
reader, err := gzip.NewReader(ctx.request.Body)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wrap the reader so on Close it will close both request body and gzip reader.
|
||||||
|
ctx.request.Body = &gzipReadCloser{requestReader: ctx.request.Body, gzipReader: reader}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return ErrGzipNotSupported
|
||||||
|
}
|
||||||
|
|
||||||
|
if gzipReader, ok := ctx.request.Body.(*gzipReadCloser); ok {
|
||||||
|
ctx.request.Body = gzipReader.requestReader
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// +------------------------------------------------------------+
|
// +------------------------------------------------------------+
|
||||||
// | Rich Body Content Writers/Renderers |
|
// | Rich Body Content Writers/Renderers |
|
||||||
// +------------------------------------------------------------+
|
// +------------------------------------------------------------+
|
||||||
|
|
6
go.mod
6
go.mod
|
@ -24,8 +24,8 @@ require (
|
||||||
github.com/kataras/neffos v0.0.16
|
github.com/kataras/neffos v0.0.16
|
||||||
github.com/kataras/pio v0.0.6
|
github.com/kataras/pio v0.0.6
|
||||||
github.com/kataras/sitemap v0.0.5
|
github.com/kataras/sitemap v0.0.5
|
||||||
github.com/klauspost/compress v1.10.5
|
github.com/klauspost/compress v1.10.6
|
||||||
github.com/mediocregopher/radix/v3 v3.5.0
|
github.com/mediocregopher/radix/v3 v3.5.1
|
||||||
github.com/microcosm-cc/bluemonday v1.0.2
|
github.com/microcosm-cc/bluemonday v1.0.2
|
||||||
github.com/ryanuber/columnize v2.1.0+incompatible
|
github.com/ryanuber/columnize v2.1.0+incompatible
|
||||||
github.com/schollz/closestmatch v2.1.0+incompatible
|
github.com/schollz/closestmatch v2.1.0+incompatible
|
||||||
|
@ -35,6 +35,6 @@ require (
|
||||||
golang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37
|
golang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37
|
||||||
golang.org/x/text v0.3.2
|
golang.org/x/text v0.3.2
|
||||||
golang.org/x/time v0.0.0-20200416051211-89c76fbcd5d1
|
golang.org/x/time v0.0.0-20200416051211-89c76fbcd5d1
|
||||||
gopkg.in/ini.v1 v1.56.0
|
gopkg.in/ini.v1 v1.57.0
|
||||||
gopkg.in/yaml.v3 v3.0.0-20200506231410-2ff61e1afc86
|
gopkg.in/yaml.v3 v3.0.0-20200506231410-2ff61e1afc86
|
||||||
)
|
)
|
||||||
|
|
10
iris.go
10
iris.go
|
@ -453,6 +453,16 @@ var (
|
||||||
//
|
//
|
||||||
// A shortcut for the `context#Gzip`.
|
// A shortcut for the `context#Gzip`.
|
||||||
Gzip = context.Gzip
|
Gzip = context.Gzip
|
||||||
|
// GzipReader is a middleware which enables gzip decompression,
|
||||||
|
// when client sends gzip compressed data.
|
||||||
|
//
|
||||||
|
// Similar to: func(ctx iris.Context) {
|
||||||
|
// ctx.GzipReader(true)
|
||||||
|
// ctx.Next()
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// A shortcut for the `context#GzipReader`.
|
||||||
|
GzipReader = context.GzipReader
|
||||||
// FromStd converts native http.Handler, http.HandlerFunc & func(w, r, next) to context.Handler.
|
// FromStd converts native http.Handler, http.HandlerFunc & func(w, r, next) to context.Handler.
|
||||||
//
|
//
|
||||||
// Supported form types:
|
// Supported form types:
|
||||||
|
|
Loading…
Reference in New Issue
Block a user