diff --git a/HISTORY.md b/HISTORY.md index 8a85a794..8b78a32e 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -28,6 +28,10 @@ The codebase for Dependency Injection, Internationalization and localization and ## Fixes and Improvements +- New `Configuration.KeepAlive` and `iris.WithKeepAlive(time.Duration) Configurator` added as helpers to start the server using a tcp listener featured with keep-alive. + +- New `DirOptions.ShowHidden bool` is added by [@tuhao1020](https://github.com/tuhao1020) at [PR #1717](https://github.com/kataras/iris/pull/1717) to show or hide the hidden files when `ShowList` is set to true. + - New `Context.ReadJSONStream` method and `JSONReader` options for `Context.ReadJSON` and `Context.ReadJSONStream`, see the [example](_examples/request-body/read-json-stream/main.go). - New `FallbackView` feature, per-party or per handler chain. Example can be found at: [_examples/view/fallback](_examples/view/fallback). diff --git a/_examples/file-server/basic/main.go b/_examples/file-server/basic/main.go index dc5fc10e..032538e1 100644 --- a/_examples/file-server/basic/main.go +++ b/_examples/file-server/basic/main.go @@ -26,6 +26,8 @@ func newApp() *iris.Application { Compress: false, // List the files inside the current requested directory if `IndexName` not found. ShowList: false, + // When ShowList is true you can configure if you want to show or hide hidden files. + ShowHidden: false, Cache: iris.DirCacheOptions{ // enable in-memory cache and pre-compress the files. Enable: true, diff --git a/_examples/http-server/listen-addr/main.go b/_examples/http-server/listen-addr/main.go index 551fded8..9103f799 100644 --- a/_examples/http-server/listen-addr/main.go +++ b/_examples/http-server/listen-addr/main.go @@ -1,8 +1,6 @@ package main -import ( - "github.com/kataras/iris/v12" -) +import "github.com/kataras/iris/v12" func main() { app := iris.New() @@ -13,5 +11,9 @@ func main() { // http://localhost:8080 // Identical to: app.Run(iris.Addr(":8080")) + app.Listen(":8080") + // To listen using keep alive tcp connection listener, + // set the KeepAlive duration configuration instead: + // app.Listen(":8080", iris.WithKeepAlive(3*time.Minute)) } diff --git a/configuration.go b/configuration.go index 17b9a910..98d9613e 100644 --- a/configuration.go +++ b/configuration.go @@ -8,6 +8,7 @@ import ( "path/filepath" "runtime" "strings" + "time" "github.com/kataras/golog" "github.com/kataras/iris/v12/context" @@ -200,6 +201,13 @@ func WithSocketSharding(app *Application) { app.config.SocketSharding = true } +// WithKeepAlive sets the `Configuration.KeepAlive` field to the given duration. +func WithKeepAlive(keepAliveDur time.Duration) Configurator { + return func(app *Application) { + app.config.KeepAlive = keepAliveDur + } +} + // WithoutServerError will cause to ignore the matched "errors" // from the main application's `Run/Listen` function. // @@ -613,6 +621,12 @@ type Configuration struct { // // Defaults to false. SocketSharding bool `ini:"socket_sharding" json:"socketSharding" yaml:"SocketSharding" toml:"SocketSharding" env:"SOCKET_SHARDING"` + // KeepAlive sets the TCP connection's keep-alive duration. + // If set to greater than zero then a tcp listener featured keep alive + // will be used instead of the simple tcp one. + // + // Defaults to 0. + KeepAlive time.Duration `ini:"keepalive" json:"keepAlive" yaml:"KeepAlive" toml:"KeepAlive" env:"KEEP_ALIVE"` // Tunneling can be optionally set to enable ngrok http(s) tunneling for this Iris app instance. // See the `WithTunneling` Configurator too. Tunneling TunnelingConfiguration `ini:"tunneling" json:"tunneling,omitempty" yaml:"Tunneling" toml:"Tunneling"` @@ -894,6 +908,11 @@ func (c Configuration) GetSocketSharding() bool { return c.SocketSharding } +// GetKeepAlive returns the KeepAlive field. +func (c Configuration) GetKeepAlive() time.Duration { + return c.KeepAlive +} + // GetDisablePathCorrection returns the DisablePathCorrection field. func (c Configuration) GetDisablePathCorrection() bool { return c.DisablePathCorrection @@ -1064,6 +1083,10 @@ func WithConfiguration(c Configuration) Configurator { main.SocketSharding = v } + if v := c.KeepAlive; v > 0 { + main.KeepAlive = v + } + if len(c.Tunneling.Tunnels) > 0 { main.Tunneling = c.Tunneling } @@ -1215,6 +1238,7 @@ func DefaultConfiguration() Configuration { return Configuration{ LogLevel: "info", SocketSharding: false, + KeepAlive: 0, DisableStartupLog: false, DisableInterruptHandler: false, DisablePathCorrection: false, diff --git a/context/configuration.go b/context/configuration.go index 4670666c..9cc03d37 100644 --- a/context/configuration.go +++ b/context/configuration.go @@ -1,6 +1,10 @@ package context -import "github.com/kataras/iris/v12/core/netutil" +import ( + "time" + + "github.com/kataras/iris/v12/core/netutil" +) // ConfigurationReadOnly can be implemented // by Configuration, it's being used inside the Context. @@ -14,6 +18,8 @@ type ConfigurationReadOnly interface { GetLogLevel() string // GetSocketSharding returns the SocketSharding field. GetSocketSharding() bool + // GetKeepAlive returns the KeepAlive field. + GetKeepAlive() time.Duration // GetDisablePathCorrection returns the DisablePathCorrection field GetDisablePathCorrection() bool // GetDisablePathCorrectionRedirection returns the DisablePathCorrectionRedirection field. diff --git a/core/host/supervisor.go b/core/host/supervisor.go index 5c3fef7e..80f34a2b 100644 --- a/core/host/supervisor.go +++ b/core/host/supervisor.go @@ -70,6 +70,9 @@ type Supervisor struct { // See `iris.Configuration.SocketSharding`. SocketSharding bool + // If more than zero then tcp keep alive listener is attached instead of the simple TCP listener. + // See `iris.Configuration.KeepAlive` + KeepAlive time.Duration } // New returns a new host supervisor @@ -141,13 +144,17 @@ func (su *Supervisor) isWaiting() bool { } func (su *Supervisor) newListener() (net.Listener, error) { - // this will not work on "unix" as network - // because UNIX doesn't supports the kind of - // restarts we may want for the server. - // - // User still be able to call .Serve instead. - // l, err := netutil.TCPKeepAlive(su.Server.Addr, su.SocketSharding) - l, err := netutil.TCP(su.Server.Addr, su.SocketSharding) + var ( + l net.Listener + err error + ) + + if su.KeepAlive > 0 { + l, err = netutil.TCPKeepAlive(su.Server.Addr, su.SocketSharding, su.KeepAlive) + } else { + l, err = netutil.TCP(su.Server.Addr, su.SocketSharding) + } + if err != nil { return nil, err } diff --git a/core/netutil/tcp.go b/core/netutil/tcp.go index 8a242424..05e6fe52 100644 --- a/core/netutil/tcp.go +++ b/core/netutil/tcp.go @@ -21,6 +21,7 @@ import ( // A raw copy of standar library. type tcpKeepAliveListener struct { *net.TCPListener + keepAliveDur time.Duration } // Accept accepts tcp connections aka clients. @@ -32,7 +33,7 @@ func (l tcpKeepAliveListener) Accept() (net.Conn, error) { if err = tc.SetKeepAlive(true); err != nil { return tc, err } - if err = tc.SetKeepAlivePeriod(3 * time.Minute); err != nil { + if err = tc.SetKeepAlivePeriod(l.keepAliveDur); err != nil { return tc, err } return tc, nil @@ -49,7 +50,7 @@ func TCP(addr string, reuse bool) (net.Listener, error) { } // TCPKeepAlive returns a new tcp keep alive Listener and an error on failure. -func TCPKeepAlive(addr string, reuse bool) (ln net.Listener, err error) { +func TCPKeepAlive(addr string, reuse bool, keepAliveDur time.Duration) (ln net.Listener, err error) { // if strings.HasPrefix(addr, "127.0.0.1") { // // it's ipv4, use ipv4 tcp listener instead of the default ipv6. Don't. // ln, err = net.Listen("tcp4", addr) @@ -61,7 +62,7 @@ func TCPKeepAlive(addr string, reuse bool) (ln net.Listener, err error) { if err != nil { return nil, err } - return tcpKeepAliveListener{ln.(*net.TCPListener)}, nil + return tcpKeepAliveListener{ln.(*net.TCPListener), keepAliveDur}, nil } // UNIX returns a new unix(file) Listener. diff --git a/core/router/fs.go b/core/router/fs.go index 1192bb3c..ca9b5734 100644 --- a/core/router/fs.go +++ b/core/router/fs.go @@ -106,7 +106,7 @@ type DirOptions struct { // See `DirListRich` package-level function too. DirList DirListFunc - // show hidden files or directories or not when `ShowList` is true + // Show hidden files or directories or not when `ShowList` is true. ShowHidden bool // Files downloaded and saved locally. diff --git a/iris.go b/iris.go index d5a5e714..976c99f4 100644 --- a/iris.go +++ b/iris.go @@ -893,6 +893,7 @@ func (app *Application) Run(serve Runner, withOrWithout ...Configurator) error { app.ConfigureHost(func(host *Supervisor) { host.SocketSharding = app.config.SocketSharding + host.KeepAlive = app.config.KeepAlive }) app.tryStartTunneling()