mirror of
https://github.com/kataras/iris.git
synced 2025-02-02 15:30:36 +01:00
add iris.Minify middleware and Context.OnCloseErr/OnConnectionCloseErr
This commit is contained in:
parent
ab226d925a
commit
ef7d365e81
|
@ -395,6 +395,10 @@ func main() {
|
|||
}
|
||||
```
|
||||
|
||||
- `iris.Minify` middleware to minify responses based on their media/content-type.
|
||||
|
||||
- `Context.OnCloseErr` and `Context.OnConnectionCloseErr` - to call a function of `func() error` instead of an `iris.Handler` when request is closed or manually canceled.
|
||||
|
||||
- `Party.UseError(...Handler)` - to register handlers to run before the `OnErrorCode/OnAnyErrorCode` ones.
|
||||
|
||||
- `Party.UseRouter(...Handler)` - to register handlers before the main router, useful on handlers that should control whether the router itself should ran or not. Independently of the incoming request's method and path values. These handlers will be executed ALWAYS against ALL incoming matched requests. Example of use-case: CORS.
|
||||
|
|
5
NOTICE
5
NOTICE
|
@ -6,7 +6,7 @@
|
|||
|
||||
The following 3rd-party software packages may be used by or distributed with iris. This document was automatically generated by FOSSA on 2020-5-8; any information relevant to third-party vendors listed below are collected using common, reasonable means.
|
||||
|
||||
Revision ID: 46a3a99adf457d30ea4aeb13ada45e895130d718
|
||||
Revision ID: ab226d925aa394ccecf01e515ea8479367e0961c
|
||||
|
||||
----------------- ----------------- ------------------------------------------
|
||||
Package Version Website
|
||||
|
@ -68,6 +68,9 @@ Revision ID: 46a3a99adf457d30ea4aeb13ada45e895130d718
|
|||
msgpack 911bfe50493ebbc https://github.com/vmihailenco/msgpack
|
||||
b6e0af9e6f36451
|
||||
255746ff46
|
||||
minify 119ab8b676c60a6 https://github.com/tdewolff/minify
|
||||
12b9cc824e6a84a
|
||||
865191aabb
|
||||
neffos f1431864185db0b https://github.com/kataras/neffos
|
||||
334b82e3817eb03
|
||||
bd957f9fda
|
||||
|
|
|
@ -14,6 +14,7 @@ func newApp() *iris.Application {
|
|||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
app.I18n.Subdomain
|
||||
// app.I18n.LoadAssets for go-bindata.
|
||||
|
||||
// Default values:
|
||||
|
@ -29,7 +30,6 @@ func newApp() *iris.Application {
|
|||
|
||||
app.Get("/", func(ctx iris.Context) {
|
||||
hi := ctx.Tr("hi", "iris")
|
||||
|
||||
locale := ctx.GetLocale()
|
||||
|
||||
ctx.Writef("From the language %s translated output: %s", locale.Language(), hi)
|
||||
|
|
|
@ -9,11 +9,18 @@ func main() {
|
|||
func newApp() *iris.Application {
|
||||
app := iris.New()
|
||||
|
||||
// Create the "test.mydomain.com" subdomain.
|
||||
test := app.Subdomain("test")
|
||||
// Register views for the test subdomain.
|
||||
test.RegisterView(iris.HTML("./views", ".html").
|
||||
Layout("layouts/test.layout.html"))
|
||||
|
||||
// Optionally, to minify the HTML5 error response.
|
||||
// Note that minification might be slower, caching is advised.
|
||||
test.UseError(iris.Minify)
|
||||
// Register error code 404 handler.
|
||||
test.OnErrorCode(iris.StatusNotFound, handleNotFoundTestSubdomain)
|
||||
|
||||
test.Get("/", testIndex)
|
||||
|
||||
return app
|
||||
|
|
40
_examples/routing/subdomains/http-errors-view/main_test.go
Normal file
40
_examples/routing/subdomains/http-errors-view/main_test.go
Normal file
|
@ -0,0 +1,40 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/kataras/iris/v12/httptest"
|
||||
)
|
||||
|
||||
func TestSubdomainsHTTPErrorsView(t *testing.T) {
|
||||
app := newApp()
|
||||
// hard coded.
|
||||
expectedHTMLResponse := `<html>
|
||||
<head>
|
||||
<title>Test Subdomain</title>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div style="background-color: black; color: red">
|
||||
<h1>Oups, you've got an error!</h1>
|
||||
|
||||
|
||||
<div style="background-color: white; color: red">
|
||||
<h1>Not Found</h1>
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
</body>
|
||||
</html>`
|
||||
|
||||
e := httptest.New(t, app)
|
||||
got := e.GET("/not_found").WithURL("http://test.mydomain.com").Expect().Status(httptest.StatusNotFound).
|
||||
ContentType("text/html", "utf-8").Body().Raw()
|
||||
|
||||
if expected, _ := app.Minifier().String("text/html", expectedHTMLResponse); expected != got {
|
||||
t.Fatalf("expected:\n'%s'\nbut got:\n'%s'", expected, got)
|
||||
}
|
||||
}
|
17
aliases.go
17
aliases.go
|
@ -244,6 +244,23 @@ var (
|
|||
ctx.Next()
|
||||
}
|
||||
|
||||
// Minify is a middleware which minifies the responses
|
||||
// based on the response content type.
|
||||
// Note that minification might be slower, caching is advised.
|
||||
// Customize the minifier through `Application.Minifier()`.
|
||||
Minify = func(ctx Context) {
|
||||
w := ctx.Application().Minifier().ResponseWriter(ctx.ResponseWriter().Naive(), ctx.Request())
|
||||
// Note(@kataras):
|
||||
// We don't use defer w.Close()
|
||||
// because this response writer holds a sync.WaitGroup under the hoods
|
||||
// and we MUST be sure that its wg.Wait is called on request cancelation
|
||||
// and not in the end of handlers chain execution
|
||||
// (which if running a time-consuming task it will delay its resource release).
|
||||
ctx.OnCloseErr(w.Close)
|
||||
ctx.ResponseWriter().SetWriter(w)
|
||||
ctx.Next()
|
||||
}
|
||||
|
||||
// MatchImagesAssets is a simple regex expression
|
||||
// that can be passed to the DirOptions.Cache.CompressIgnore field
|
||||
// in order to skip compression on already-compressed file types
|
||||
|
|
|
@ -6,6 +6,7 @@ import (
|
|||
"net/http"
|
||||
|
||||
"github.com/kataras/golog"
|
||||
"github.com/tdewolff/minify/v2"
|
||||
)
|
||||
|
||||
// Application is the context's owner.
|
||||
|
@ -25,6 +26,14 @@ type Application interface {
|
|||
// the failure reason if not.
|
||||
Validate(interface{}) error
|
||||
|
||||
// Minifier returns the minifier instance.
|
||||
// By default it can minifies:
|
||||
// - text/html
|
||||
// - text/css
|
||||
// - image/svg+xml
|
||||
// - application/text(javascript, ecmascript, json, xml).
|
||||
// Use that instance to add custom Minifiers before server ran.
|
||||
Minifier() *minify.M
|
||||
// View executes and write the result of a template file to the writer.
|
||||
//
|
||||
// Use context.View to render templates to the client instead.
|
||||
|
|
|
@ -259,6 +259,35 @@ func (ctx *Context) OnConnectionClose(cb Handler) bool {
|
|||
return true
|
||||
}
|
||||
|
||||
// OnConnectionCloseErr same as `OnConnectionClose` but instead it
|
||||
// receives a function which returns an error.
|
||||
// If error is not nil, it will be logged as a debug message.
|
||||
func (ctx *Context) OnConnectionCloseErr(cb func() error) bool {
|
||||
if cb == nil {
|
||||
return false
|
||||
}
|
||||
|
||||
reqCtx := ctx.Request().Context()
|
||||
if reqCtx == nil {
|
||||
return false
|
||||
}
|
||||
|
||||
notifyClose := reqCtx.Done()
|
||||
if notifyClose == nil {
|
||||
return false
|
||||
}
|
||||
|
||||
go func() {
|
||||
<-notifyClose
|
||||
if err := cb(); err != nil {
|
||||
// Can be ignored.
|
||||
ctx.app.Logger().Debugf("OnConnectionCloseErr: received error: %v", err)
|
||||
}
|
||||
}()
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
// OnClose registers a callback which
|
||||
// will be fired when the underlying connection has gone away(request canceled)
|
||||
// on its own goroutine or in the end of the request-response lifecylce
|
||||
|
@ -297,6 +326,36 @@ func (ctx *Context) OnClose(cb Handler) {
|
|||
ctx.writer.SetBeforeFlush(onFlush)
|
||||
}
|
||||
|
||||
// OnCloseErr same as `OnClose` but instead it
|
||||
// receives a function which returns an error.
|
||||
// If error is not nil, it will be logged as a debug message.
|
||||
func (ctx *Context) OnCloseErr(cb func() error) {
|
||||
if cb == nil {
|
||||
return
|
||||
}
|
||||
|
||||
var executed uint32
|
||||
|
||||
callback := func() error {
|
||||
if atomic.CompareAndSwapUint32(&executed, 0, 1) {
|
||||
return cb()
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
ctx.OnConnectionCloseErr(callback)
|
||||
|
||||
onFlush := func() {
|
||||
if err := callback(); err != nil {
|
||||
// Can be ignored.
|
||||
ctx.app.Logger().Debugf("OnClose: SetBeforeFlush: received error: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
ctx.writer.SetBeforeFlush(onFlush)
|
||||
}
|
||||
|
||||
/* Note(@kataras): just leave end-developer decide.
|
||||
const goroutinesContextKey = "iris.goroutines"
|
||||
|
||||
|
@ -795,7 +854,7 @@ func GetHost(r *http.Request) string {
|
|||
// Subdomain returns the subdomain of this request, if any.
|
||||
// Note that this is a fast method which does not cover all cases.
|
||||
func (ctx *Context) Subdomain() (subdomain string) {
|
||||
host := ctx.request.URL.Host // ctx.Host()
|
||||
host := ctx.Host()
|
||||
if index := strings.IndexByte(host, '.'); index > 0 {
|
||||
subdomain = host[0:index]
|
||||
}
|
||||
|
|
1
go.mod
1
go.mod
|
@ -32,6 +32,7 @@ require (
|
|||
github.com/ryanuber/columnize v2.1.0+incompatible
|
||||
github.com/schollz/closestmatch v2.1.0+incompatible
|
||||
github.com/square/go-jose/v3 v3.0.0-20200630053402-0a67ce9b0693
|
||||
github.com/tdewolff/minify/v2 v2.8.0
|
||||
github.com/vmihailenco/msgpack/v5 v5.0.0-beta.1
|
||||
github.com/yosssi/ace v0.0.5
|
||||
go.etcd.io/bbolt v1.3.5
|
||||
|
|
34
iris.go
34
iris.go
|
@ -9,6 +9,7 @@ import (
|
|||
"net"
|
||||
"net/http"
|
||||
"os"
|
||||
"regexp"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
@ -25,6 +26,14 @@ import (
|
|||
|
||||
"github.com/kataras/golog"
|
||||
"github.com/kataras/tunnel"
|
||||
|
||||
"github.com/tdewolff/minify/v2"
|
||||
"github.com/tdewolff/minify/v2/css"
|
||||
"github.com/tdewolff/minify/v2/html"
|
||||
"github.com/tdewolff/minify/v2/js"
|
||||
"github.com/tdewolff/minify/v2/json"
|
||||
"github.com/tdewolff/minify/v2/svg"
|
||||
"github.com/tdewolff/minify/v2/xml"
|
||||
)
|
||||
|
||||
// Version is the current version number of the Iris Web Framework.
|
||||
|
@ -65,6 +74,8 @@ type Application struct {
|
|||
|
||||
// Validator is the request body validator, defaults to nil.
|
||||
Validator context.Validator
|
||||
// Minifier to minify responses.
|
||||
minifier *minify.M
|
||||
|
||||
// view engine
|
||||
view view.View
|
||||
|
@ -92,6 +103,7 @@ func New() *Application {
|
|||
app := &Application{
|
||||
config: &config,
|
||||
logger: golog.Default,
|
||||
minifier: newMinifier(),
|
||||
I18n: i18n.New(),
|
||||
APIBuilder: router.NewAPIBuilder(),
|
||||
Router: router.NewRouter(),
|
||||
|
@ -250,6 +262,28 @@ func (app *Application) Validate(v interface{}) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func newMinifier() *minify.M {
|
||||
m := minify.New()
|
||||
m.AddFunc("text/css", css.Minify)
|
||||
m.AddFunc("text/html", html.Minify)
|
||||
m.AddFunc("image/svg+xml", svg.Minify)
|
||||
m.AddFuncRegexp(regexp.MustCompile("^(application|text)/(x-)?(java|ecma)script$"), js.Minify)
|
||||
m.AddFuncRegexp(regexp.MustCompile("[/+]json$"), json.Minify)
|
||||
m.AddFuncRegexp(regexp.MustCompile("[/+]xml$"), xml.Minify)
|
||||
return m
|
||||
}
|
||||
|
||||
// Minifier returns the minifier instance.
|
||||
// By default it can minifies:
|
||||
// - text/html
|
||||
// - text/css
|
||||
// - image/svg+xml
|
||||
// - application/text(javascript, ecmascript, json, xml).
|
||||
// Use that instance to add custom Minifiers before server ran.
|
||||
func (app *Application) Minifier() *minify.M {
|
||||
return app.minifier
|
||||
}
|
||||
|
||||
// RegisterView should be used to register view engines mapping to a root directory
|
||||
// and the template file(s) extension.
|
||||
func (app *Application) RegisterView(viewEngine view.Engine) {
|
||||
|
|
Loading…
Reference in New Issue
Block a user