2016-09-09 07:09:03 +02:00
package iris
import (
2017-01-02 20:20:17 +01:00
"crypto/tls"
"net"
"net/http"
2016-09-09 07:09:03 +02:00
"strconv"
"time"
2016-10-11 21:35:12 +02:00
"github.com/imdario/mergo"
"github.com/kataras/go-options"
2016-09-09 07:09:03 +02:00
)
type (
// OptionSetter sets a configuration field to the main configuration
// used to help developers to write less and configure only what they really want and nothing else
// example:
2017-02-15 07:40:43 +01:00
// iris.New(iris.Configuration{Charset: "UTF-8", Gzip:true})
2016-09-09 07:09:03 +02:00
// now can be done also by using iris.Option$FIELD:
2017-02-15 07:40:43 +01:00
// iris.New(iris.OptionCharset("UTF-8"), iris.OptionGzip(true))
2016-09-09 07:09:03 +02:00
// benefits:
2017-02-15 07:40:43 +01:00
// 1. dev has no worries what option to pass,
// he/she can just press iris.Option and all options should be shown to her/his editor's autocomplete-popup window
2016-09-09 07:09:03 +02:00
// 2. can be passed with any order
// 3. Can override previous configuration
OptionSetter interface {
// Set receives a pointer to the global Configuration type and does the job of filling it
Set ( c * Configuration )
}
// OptionSet implements the OptionSetter
OptionSet func ( c * Configuration )
)
// Set is the func which makes the OptionSet an OptionSetter, this is used mostly
func ( o OptionSet ) Set ( c * Configuration ) {
o ( c )
}
2017-02-14 04:54:11 +01:00
// Configuration the whole configuration for an iris instance ($instance.Config) or global iris instance (iris.Default.Config)
2016-09-09 07:09:03 +02:00
// these can be passed via options also, look at the top of this file(configuration.go)
//
2016-09-30 17:48:48 +02:00
// Configuration is also implements the OptionSet so it's a valid option itself, this is brilliant enough
2016-09-09 07:09:03 +02:00
type Configuration struct {
2016-09-27 15:28:38 +02:00
// VHost is the addr or the domain that server listens to, which it's optional
// When to set VHost manually:
// 1. it's automatically setted when you're calling
// $instance.Listen/ListenUNIX/ListenTLS/ListenLETSENCRYPT functions or
// ln,_ := iris.TCP4/UNIX/TLS/LETSENCRYPT; $instance.Serve(ln)
// 2. If you using a balancer, or something like nginx
// then set it in order to have the correct url
// when calling the template helper '{{url }}'
// *keep note that you can use {{urlpath }}) instead*
//
2017-01-02 20:20:17 +01:00
// Note: this is the main's server Host, you can setup unlimited number of net/http servers
2016-09-27 15:28:38 +02:00
// listening to the $instance.Handler after the manually-called $instance.Build
//
2017-02-14 04:54:11 +01:00
// Default comes from iris.Default.Listen/.Serve with iris' listeners (iris.TCP4/UNIX/TLS/LETSENCRYPT)
2016-09-27 15:28:38 +02:00
VHost string
// VScheme is the scheme (http:// or https://) putted at the template function '{{url }}'
// It's an optional field,
// When to set VScheme manually:
// 1. You didn't start the main server using $instance.Listen/ListenTLS/ListenLETSENCRYPT or $instance.Serve($instance.TCP4()/.TLS...)
// 2. if you're using something like nginx and have iris listening with addr only(http://) but the nginx mapper is listening to https://
//
2017-02-14 04:54:11 +01:00
// Default comes from iris.Default.Listen/.Serve with iris' listeners (TCP4,UNIX,TLS,LETSENCRYPT)
2016-09-27 15:28:38 +02:00
VScheme string
2017-01-02 20:20:17 +01:00
ReadTimeout time . Duration // maximum duration before timing out read of the request
WriteTimeout time . Duration // maximum duration before timing out write of the response
// MaxHeaderBytes controls the maximum number of bytes the
// server will read parsing the request header's keys and
// values, including the request line. It does not limit the
// size of the request body.
// If zero, DefaultMaxHeaderBytes is used.
MaxHeaderBytes int
// TLSNextProto optionally specifies a function to take over
// ownership of the provided TLS connection when an NPN/ALPN
// protocol upgrade has occurred. The map key is the protocol
// name negotiated. The Handler argument should be used to
// handle HTTP requests and will initialize the Request's TLS
// and RemoteAddr if not already set. The connection is
// automatically closed when the function returns.
// If TLSNextProto is nil, HTTP/2 support is enabled automatically.
TLSNextProto map [ string ] func ( * http . Server , * tls . Conn , http . Handler )
// ConnState specifies an optional callback function that is
// called when a client connection changes state. See the
// ConnState type and associated constants for details.
ConnState func ( net . Conn , http . ConnState )
2016-09-27 15:28:38 +02:00
2016-09-16 09:02:18 +02:00
// CheckForUpdates will try to search for newer version of Iris based on the https://github.com/kataras/iris/releases
// If a newer version found then the app will ask the he dev/user if want to update the 'x' version
// if 'y' is pressed then the updater will try to install the latest version
// the updater, will notify the dev/user that the update is finished and should restart the App manually.
// Notes:
// 1. Experimental feature
2016-09-17 23:50:10 +02:00
// 2. If setted to true, the app will start the server normally and runs the updater in its own goroutine,
// for a sync operation see CheckForUpdatesSync.
2016-09-16 09:02:18 +02:00
// 3. If you as developer edited the $GOPATH/src/github/kataras or any other Iris' Go dependencies at the past
// then the update process will fail.
//
2017-02-14 04:54:11 +01:00
// Usage: iris.Default.Set(iris.OptionCheckForUpdates(true)) or
// iris.Default.Config.CheckForUpdates = true or
2016-09-16 09:02:18 +02:00
// app := iris.New(iris.OptionCheckForUpdates(true))
// Default is false
CheckForUpdates bool
2016-09-17 23:50:10 +02:00
// CheckForUpdatesSync checks for updates before server starts, it will have a little delay depends on the machine's download's speed
// See CheckForUpdates for more
// Notes:
// 1. you could use the CheckForUpdatesSync while CheckForUpdates is false, set this or CheckForUpdates to true not both
// 2. if both CheckForUpdates and CheckForUpdatesSync are setted to true then the updater will run in sync mode, before server server starts.
//
// Default is false
CheckForUpdatesSync bool
2016-09-16 09:02:18 +02:00
2017-01-10 14:03:02 +01:00
// DisablePathCorrection corrects and redirects the requested path to the registered path
2016-09-09 07:09:03 +02:00
// for example, if /home/ path is requested but no handler for this Route found,
// then the Router checks if /home handler exists, if yes,
// (permant)redirects the client to the correct path /home
//
// Default is false
DisablePathCorrection bool
2017-01-10 07:54:39 +01:00
// EnablePathEscape when is true then its escapes the path, the named parameters (if any).
// Change to false it if you want something like this https://github.com/kataras/iris/issues/135 to work
2016-09-09 07:09:03 +02:00
//
2017-01-10 07:54:39 +01:00
// When do you need to Disable(false) it:
2016-09-09 07:09:03 +02:00
// accepts parameters with slash '/'
// Request: http://localhost:8080/details/Project%2FDelta
// ctx.Param("project") returns the raw named parameter: Project%2FDelta
// which you can escape it manually with net/url:
// projectName, _ := url.QueryUnescape(c.Param("project").
// Look here: https://github.com/kataras/iris/issues/135 for more
//
// Default is false
2017-01-10 07:54:39 +01:00
EnablePathEscape bool
2016-09-09 07:09:03 +02:00
2016-10-11 21:35:12 +02:00
// FireMethodNotAllowed if it's true router checks for StatusMethodNotAllowed(405) and fires the 405 error instead of 404
// Default is false
FireMethodNotAllowed bool
2016-09-09 07:09:03 +02:00
// DisableBanner outputs the iris banner at startup
//
// Default is false
DisableBanner bool
2017-01-30 11:35:43 +01:00
// 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
2017-02-14 04:54:11 +01:00
// DisableTemplateEngines set to true to disable loading the default template engine (html/template) and disallow the use of iris.Default.UseEngine
2016-10-27 02:17:09 +02:00
// Defaults to false
2016-09-09 07:09:03 +02:00
DisableTemplateEngines bool
// TimeFormat time format for any kind of datetime parsing
TimeFormat string
// Charset character encoding for various rendering
// used for templates and the rest of the responses
2016-10-27 02:17:09 +02:00
// Defaults to "UTF-8"
2016-09-09 07:09:03 +02:00
Charset string
// Gzip enables gzip compression on your Render actions, this includes any type of render, templates and pure/raw content
2017-01-10 14:03:02 +01:00
// If you don't want to enable it globally, you could just use the third parameter on context.Render("myfileOrResponse", structBinding{}, iris.RenderOptions{"gzip": true})
2016-10-27 02:17:09 +02:00
// Defaults to false
2016-09-09 07:09:03 +02:00
Gzip bool
// Other are the custom, dynamic options, can be empty
// this fill used only by you to set any app's options you want
// for each of an Iris instance
Other options . Options
}
// Set implements the OptionSetter
func ( c Configuration ) Set ( main * Configuration ) {
2017-02-14 04:54:11 +01:00
// ignore error
2016-09-09 07:09:03 +02:00
mergo . MergeWithOverwrite ( main , c )
}
// All options starts with "Option" preffix in order to be easier to find what dev searching for
var (
2016-09-27 15:28:38 +02:00
// OptionVHost is the addr or the domain that server listens to, which it's optional
// When to set VHost manually:
// 1. it's automatically setted when you're calling
// $instance.Listen/ListenUNIX/ListenTLS/ListenLETSENCRYPT functions or
// ln,_ := iris.TCP4/UNIX/TLS/LETSENCRYPT; $instance.Serve(ln)
// 2. If you using a balancer, or something like nginx
// then set it in order to have the correct url
// when calling the template helper '{{url }}'
// *keep note that you can use {{urlpath }}) instead*
//
2017-01-02 20:20:17 +01:00
// Note: this is the main's server Host, you can setup unlimited number of net/http servers
2016-09-27 15:28:38 +02:00
// listening to the $instance.Handler after the manually-called $instance.Build
//
2017-02-14 04:54:11 +01:00
// Default comes from iris.Default.Listen/.Serve with iris' listeners (iris.TCP4/UNIX/TLS/LETSENCRYPT)
2016-09-27 15:28:38 +02:00
OptionVHost = func ( val string ) OptionSet {
return func ( c * Configuration ) {
c . VHost = val
}
}
// OptionVScheme is the scheme (http:// or https://) putted at the template function '{{url }}'
// It's an optional field,
// When to set Scheme manually:
// 1. You didn't start the main server using $instance.Listen/ListenTLS/ListenLETSENCRYPT or $instance.Serve($instance.TCP4()/.TLS...)
// 2. if you're using something like nginx and have iris listening with addr only(http://) but the nginx mapper is listening to https://
//
2017-02-14 04:54:11 +01:00
// Default comes from iris.Default.Listen/.Serve with iris' listeners (TCP4,UNIX,TLS,LETSENCRYPT)
2016-09-27 15:28:38 +02:00
OptionVScheme = func ( val string ) OptionSet {
return func ( c * Configuration ) {
c . VScheme = val
}
}
2017-01-02 20:20:17 +01:00
// maximum duration before timing out read of the request
2016-09-27 15:28:38 +02:00
OptionReadTimeout = func ( val time . Duration ) OptionSet {
return func ( c * Configuration ) {
c . ReadTimeout = val
}
}
2017-01-02 20:20:17 +01:00
// maximum duration before timing out write of the response
2016-09-27 15:28:38 +02:00
OptionWriteTimeout = func ( val time . Duration ) OptionSet {
return func ( c * Configuration ) {
c . WriteTimeout = val
}
}
2017-01-02 20:20:17 +01:00
// MaxHeaderBytes controls the maximum number of bytes the
// server will read parsing the request header's keys and
// values, including the request line. It does not limit the
// size of the request body.
// If zero, DefaultMaxHeaderBytes(8MB) is used.
OptionMaxHeaderBytes = func ( val int ) OptionSet {
2016-09-27 15:28:38 +02:00
return func ( c * Configuration ) {
2017-01-02 20:20:17 +01:00
c . MaxHeaderBytes = val
2016-09-27 15:28:38 +02:00
}
}
2017-01-02 20:20:17 +01:00
// TLSNextProto optionally specifies a function to take over
// ownership of the provided TLS connection when an NPN/ALPN
// protocol upgrade has occurred. The map key is the protocol
// name negotiated. The Handler argument should be used to
// handle HTTP requests and will initialize the Request's TLS
// and RemoteAddr if not already set. The connection is
// automatically closed when the function returns.
// If TLSNextProto is nil, HTTP/2 support is enabled automatically.
OptionTLSNextProto = func ( val map [ string ] func ( * http . Server , * tls . Conn , http . Handler ) ) OptionSet {
2016-09-27 15:28:38 +02:00
return func ( c * Configuration ) {
2017-01-02 20:20:17 +01:00
c . TLSNextProto = val
}
}
// ConnState specifies an optional callback function that is
// called when a client connection changes state. See the
// ConnState type and associated constants for details.
OptionConnState = func ( val func ( net . Conn , http . ConnState ) ) OptionSet {
return func ( c * Configuration ) {
c . ConnState = val
2016-09-27 15:28:38 +02:00
}
}
2016-09-16 09:02:18 +02:00
// OptionCheckForUpdates will try to search for newer version of Iris based on the https://github.com/kataras/iris/releases
// If a newer version found then the app will ask the he dev/user if want to update the 'x' version
// if 'y' is pressed then the updater will try to install the latest version
// the updater, will notify the dev/user that the update is finished and should restart the App manually.
// Notes:
// 1. Experimental feature
// 2. If setted to true, the app will have a little startup delay
// 3. If you as developer edited the $GOPATH/src/github/kataras or any other Iris' Go dependencies at the past
// then the update process will fail.
//
2017-02-14 04:54:11 +01:00
// Usage: iris.Default.Set(iris.OptionCheckForUpdates(true)) or
// iris.Default.Config.CheckForUpdates = true or
2016-09-16 09:02:18 +02:00
// app := iris.New(iris.OptionCheckForUpdates(true))
// Default is false
OptionCheckForUpdates = func ( val bool ) OptionSet {
return func ( c * Configuration ) {
c . CheckForUpdates = val
}
}
2016-09-17 23:50:10 +02:00
// CheckForUpdatesSync checks for updates before server starts, it will have a little delay depends on the machine's download's speed
// See CheckForUpdates for more
// Notes:
// 1. you could use the CheckForUpdatesSync while CheckForUpdates is false, set this or CheckForUpdates to true not both
// 2. if both CheckForUpdates and CheckForUpdatesSync are setted to true then the updater will run in sync mode, before server server starts.
//
// Default is false
OptionCheckForUpdatesSync = func ( val bool ) OptionSet {
return func ( c * Configuration ) {
c . CheckForUpdatesSync = val
}
}
2016-09-16 09:02:18 +02:00
2017-01-10 14:03:02 +01:00
// OptionDisablePathCorrection corrects and redirects the requested path to the registered path
2016-09-09 07:09:03 +02:00
// for example, if /home/ path is requested but no handler for this Route found,
// then the Router checks if /home handler exists, if yes,
// (permant)redirects the client to the correct path /home
//
// Default is false
OptionDisablePathCorrection = func ( val bool ) OptionSet {
return func ( c * Configuration ) {
c . DisablePathCorrection = val
}
}
2016-09-16 09:02:18 +02:00
2017-01-10 07:54:39 +01:00
// OptionEnablePathEscape when is true then its escapes the path, the named path parameters (if any).
OptionEnablePathEscape = func ( val bool ) OptionSet {
2016-09-09 07:09:03 +02:00
return func ( c * Configuration ) {
2017-01-10 07:54:39 +01:00
c . EnablePathEscape = val
2016-09-09 07:09:03 +02:00
}
}
2016-09-16 09:02:18 +02:00
2016-10-11 21:35:12 +02:00
// FireMethodNotAllowed if it's true router checks for StatusMethodNotAllowed(405) and fires the 405 error instead of 404
// Default is false
OptionFireMethodNotAllowed = func ( val bool ) OptionSet {
return func ( c * Configuration ) {
c . FireMethodNotAllowed = val
}
}
2016-09-09 07:09:03 +02:00
// OptionDisableBanner outputs the iris banner at startup
//
// Default is false
OptionDisableBanner = func ( val bool ) OptionSet {
return func ( c * Configuration ) {
c . DisableBanner = val
}
}
2016-09-16 09:02:18 +02:00
2017-01-30 11:35:43 +01:00
// 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
}
}
2016-09-09 07:09:03 +02:00
// OptionTimeFormat time format for any kind of datetime parsing
OptionTimeFormat = func ( val string ) OptionSet {
return func ( c * Configuration ) {
c . TimeFormat = val
}
}
2016-09-16 09:02:18 +02:00
2016-09-09 07:09:03 +02:00
// OptionCharset character encoding for various rendering
// used for templates and the rest of the responses
// Default is "UTF-8"
OptionCharset = func ( val string ) OptionSet {
return func ( c * Configuration ) {
c . Charset = val
}
}
2016-09-16 09:02:18 +02:00
2016-09-09 07:09:03 +02:00
// OptionGzip enables gzip compression on your Render actions, this includes any type of render, templates and pure/raw content
2017-01-10 14:03:02 +01:00
// If you don't want to enable it globally, you could just use the third parameter on context.Render("myfileOrResponse", structBinding{}, iris.RenderOptions{"gzip": true})
2016-09-09 07:09:03 +02:00
// Default is false
OptionGzip = func ( val bool ) OptionSet {
return func ( c * Configuration ) {
c . Gzip = val
}
}
// OptionOther are the custom, dynamic options, can be empty
// this fill used only by you to set any app's options you want
// for each of an Iris instance
OptionOther = func ( val ... options . Options ) OptionSet {
opts := options . Options { }
for _ , opt := range val {
for k , v := range opt {
opts [ k ] = v
}
}
return func ( c * Configuration ) {
c . Other = opts
}
}
)
var (
// DefaultTimeFormat default time format for any kind of datetime parsing
DefaultTimeFormat = "Mon, 02 Jan 2006 15:04:05 GMT"
// StaticCacheDuration expiration duration for INACTIVE file handlers, it's a global configuration field to all iris instances
StaticCacheDuration = 20 * time . Second
)
// Default values for base Iris conf
const (
DefaultDisablePathCorrection = false
2017-01-10 07:54:39 +01:00
DefaultEnablePathEscape = false
2016-09-09 07:09:03 +02:00
DefaultCharset = "UTF-8"
2016-09-27 15:28:38 +02:00
// Per-connection buffer size for requests' reading.
// This also limits the maximum header size.
//
// Increase this buffer if your clients send multi-KB RequestURIs
// and/or multi-KB headers (for example, BIG cookies).
//
// Default buffer size is 8MB
2017-01-02 20:20:17 +01:00
DefaultMaxHeaderBytes = 8096
2016-09-27 15:28:38 +02:00
2017-01-02 20:20:17 +01:00
// DefaultReadTimeout no read client timeout
DefaultReadTimeout = 0
// DefaultWriteTimeout no serve client timeout
DefaultWriteTimeout = 0
2016-09-09 07:09:03 +02:00
)
// DefaultConfiguration returns the default configuration for an Iris station, fills the main Configuration
func DefaultConfiguration ( ) Configuration {
return Configuration {
2017-01-30 11:35:43 +01:00
VHost : "" ,
VScheme : "" ,
ReadTimeout : DefaultReadTimeout ,
WriteTimeout : DefaultWriteTimeout ,
MaxHeaderBytes : DefaultMaxHeaderBytes ,
CheckForUpdates : false ,
CheckForUpdatesSync : false ,
DisablePathCorrection : DefaultDisablePathCorrection ,
EnablePathEscape : DefaultEnablePathEscape ,
FireMethodNotAllowed : false ,
DisableBanner : false ,
DisableBodyConsumptionOnUnmarshal : false ,
TimeFormat : DefaultTimeFormat ,
Charset : DefaultCharset ,
Gzip : false ,
Other : options . Options { } ,
2016-09-09 07:09:03 +02:00
}
}
// Default values for base Server conf
const (
// DefaultServerHostname returns the default hostname which is 0.0.0.0
DefaultServerHostname = "0.0.0.0"
2016-09-27 15:28:38 +02:00
// DefaultServerPort returns the default port which is 8080, not used
2016-09-09 07:09:03 +02:00
DefaultServerPort = 8080
)
var (
// DefaultServerAddr the default server addr which is: 0.0.0.0:8080
DefaultServerAddr = DefaultServerHostname + ":" + strconv . Itoa ( DefaultServerPort )
)