mirror of
https://github.com/kataras/iris.git
synced 2025-01-23 10:41:03 +01:00
Add the ability to use .yaml/yml files for the Configuration.
Former-commit-id: 0c49eb04d991aabf67970fe7f7b3ed969a36a708
This commit is contained in:
parent
40b62f2958
commit
dd1d6837d9
|
@ -2,3 +2,5 @@ language: go
|
||||||
|
|
||||||
go:
|
go:
|
||||||
- go1.7
|
- go1.7
|
||||||
|
|
||||||
|
go_import_path: gopkg.in/kataras/iris.v6
|
||||||
|
|
|
@ -14,7 +14,7 @@ to adapt the new changes to your application, it contains an overview of the new
|
||||||
- Template engines (two lines to add, same features as before, except their easier configuration)
|
- Template engines (two lines to add, same features as before, except their easier configuration)
|
||||||
- Basic middleware, that have been written by me, are transfared to the main repository[/middleware](https://github.com/kataras/iris/tree/master/middleware) with a lot of improvements to the `recover middleware` (see the next)
|
- Basic middleware, that have been written by me, are transfared to the main repository[/middleware](https://github.com/kataras/iris/tree/master/middleware) with a lot of improvements to the `recover middleware` (see the next)
|
||||||
- `func(http.ResponseWriter, r *http.Request, next http.HandlerFunc)` signature is fully compatible using `iris.ToHandler` helper wrapper func, without any need of custom boilerplate code. So all net/http middleware out there are supported, no need to re-invert the world here, search to the internet and you'll find a suitable to your case.
|
- `func(http.ResponseWriter, r *http.Request, next http.HandlerFunc)` signature is fully compatible using `iris.ToHandler` helper wrapper func, without any need of custom boilerplate code. So all net/http middleware out there are supported, no need to re-invert the world here, search to the internet and you'll find a suitable to your case.
|
||||||
|
- Developers can use a `yaml` files for the configuration using the `iris.YAML` function: `app := iris.New(iris.YAML("myconfiguration.yaml"))`
|
||||||
|
|
||||||
Fixes:
|
Fixes:
|
||||||
|
|
||||||
|
|
116
configuration.go
116
configuration.go
|
@ -1,13 +1,13 @@
|
||||||
package iris
|
package iris
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"crypto/tls"
|
"io/ioutil"
|
||||||
"net"
|
"path/filepath"
|
||||||
"net/http"
|
|
||||||
"strconv"
|
"strconv"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/imdario/mergo"
|
"github.com/imdario/mergo"
|
||||||
|
"gopkg.in/yaml.v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
type (
|
type (
|
||||||
|
@ -39,6 +39,39 @@ func (o OptionSet) Set(c *Configuration) {
|
||||||
o(c)
|
o(c)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// YAML reads Configuration from a file.yml.
|
||||||
|
//
|
||||||
|
// Accepts the absolute path of the file.yml.
|
||||||
|
// An error will be shown to the user via panic with the error message.
|
||||||
|
// Error may occur when the file.yml doesn't exists or is not formatted correctly.
|
||||||
|
//
|
||||||
|
// Usage:
|
||||||
|
// 1. `app := iris.New(YAML("myfile.yml"))`
|
||||||
|
// 2. `app.Set(YAML("myfile.yml"))`
|
||||||
|
func YAML(filename string) Configuration {
|
||||||
|
c := DefaultConfiguration()
|
||||||
|
|
||||||
|
// get the abs
|
||||||
|
// which will try to find the 'filename' from current workind dir too.
|
||||||
|
yamlAbsPath, err := filepath.Abs(filename)
|
||||||
|
if err != nil {
|
||||||
|
panic("FATAL ERROR .yml.filename to absolute: " + err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
// read the raw contents of the file
|
||||||
|
data, err := ioutil.ReadFile(yamlAbsPath)
|
||||||
|
if err != nil {
|
||||||
|
panic("FATAL ERROR .yml.ReadFile: " + err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
// put the file's contents as yaml to the default configuration(c)
|
||||||
|
if err := yaml.Unmarshal(data, &c); err != nil {
|
||||||
|
panic("FATAL ERROR .yml.Unmarshal: " + err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
|
||||||
// Configuration the whole configuration for an Iris station instance
|
// Configuration the whole configuration for an Iris station instance
|
||||||
// these can be passed via options also, look at the top of this file(configuration.go).
|
// these can be passed via options also, look at the top of this file(configuration.go).
|
||||||
// Configuration is a valid OptionSetter.
|
// Configuration is a valid OptionSetter.
|
||||||
|
@ -57,7 +90,7 @@ type Configuration struct {
|
||||||
// listening to the $instance.Handler after the manually-called $instance.Build
|
// listening to the $instance.Handler after the manually-called $instance.Build
|
||||||
//
|
//
|
||||||
// Default comes from iris.Default.Listen/.Serve with iris' listeners (iris.TCP4/UNIX/TLS/LETSENCRYPT).
|
// Default comes from iris.Default.Listen/.Serve with iris' listeners (iris.TCP4/UNIX/TLS/LETSENCRYPT).
|
||||||
VHost string
|
VHost string `yaml:"vHost"`
|
||||||
|
|
||||||
// VScheme is the scheme (http:// or https://) putted at the template function '{{url }}'
|
// VScheme is the scheme (http:// or https://) putted at the template function '{{url }}'
|
||||||
// It's an optional field,
|
// It's an optional field,
|
||||||
|
@ -68,34 +101,20 @@ type Configuration struct {
|
||||||
// addr only(http://) but the nginx mapper is listening to https://
|
// addr only(http://) but the nginx mapper is listening to https://
|
||||||
//
|
//
|
||||||
// Default comes from iris.Default.Listen/.Serve with iris' listeners (TCP4,UNIX,TLS,LETSENCRYPT).
|
// Default comes from iris.Default.Listen/.Serve with iris' listeners (TCP4,UNIX,TLS,LETSENCRYPT).
|
||||||
VScheme string
|
VScheme string `yaml:"vScheme"`
|
||||||
|
|
||||||
// ReadTimeout is the maximum duration before timing out read of the request.
|
// ReadTimeout is the maximum duration before timing out read of the request.
|
||||||
ReadTimeout time.Duration
|
ReadTimeout time.Duration `yaml:"readTimeout"`
|
||||||
|
|
||||||
// WriteTimeout is the maximum duration before timing out write of the response.
|
// WriteTimeout is the maximum duration before timing out write of the response.
|
||||||
WriteTimeout time.Duration
|
WriteTimeout time.Duration `yaml:"writeTimeout"`
|
||||||
|
|
||||||
// MaxHeaderBytes controls the maximum number of bytes the
|
// MaxHeaderBytes controls the maximum number of bytes the
|
||||||
// server will read parsing the request header's keys and
|
// server will read parsing the request header's keys and
|
||||||
// values, including the request line. It does not limit the
|
// values, including the request line. It does not limit the
|
||||||
// size of the request body.
|
// size of the request body.
|
||||||
// If zero, DefaultMaxHeaderBytes is used.
|
// If zero, DefaultMaxHeaderBytes is used.
|
||||||
MaxHeaderBytes int
|
MaxHeaderBytes int `yaml:"maxHeaderBytes"`
|
||||||
|
|
||||||
// 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)
|
|
||||||
|
|
||||||
// CheckForUpdates will try to search for newer version of Iris based on the https://github.com/kataras/iris/releases
|
// 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 a newer version found then the app will ask the he dev/user if want to update the 'x' version
|
||||||
|
@ -111,7 +130,7 @@ type Configuration struct {
|
||||||
// Usage: app := iris.New(iris.Configuration{CheckForUpdates: true})
|
// Usage: app := iris.New(iris.Configuration{CheckForUpdates: true})
|
||||||
//
|
//
|
||||||
// Defaults to false.
|
// Defaults to false.
|
||||||
CheckForUpdates bool
|
CheckForUpdates bool `yaml:"checkForUpdates"`
|
||||||
|
|
||||||
// DisablePathCorrection corrects and redirects the requested path to the registered path
|
// DisablePathCorrection corrects and redirects the requested path to the registered path
|
||||||
// for example, if /home/ path is requested but no handler for this Route found,
|
// for example, if /home/ path is requested but no handler for this Route found,
|
||||||
|
@ -119,7 +138,7 @@ type Configuration struct {
|
||||||
// (permant)redirects the client to the correct path /home
|
// (permant)redirects the client to the correct path /home
|
||||||
//
|
//
|
||||||
// Defaults to false.
|
// Defaults to false.
|
||||||
DisablePathCorrection bool
|
DisablePathCorrection bool `yaml:"disablePathCorrection"`
|
||||||
|
|
||||||
// EnablePathEscape when is true then its escapes the path, the named parameters (if any).
|
// 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
|
// Change to false it if you want something like this https://github.com/kataras/iris/issues/135 to work
|
||||||
|
@ -132,17 +151,17 @@ type Configuration struct {
|
||||||
// projectName, _ := url.QueryUnescape(c.Param("project").
|
// projectName, _ := url.QueryUnescape(c.Param("project").
|
||||||
//
|
//
|
||||||
// Defaults to false.
|
// Defaults to false.
|
||||||
EnablePathEscape bool
|
EnablePathEscape bool `yaml:"enablePathEscape"`
|
||||||
|
|
||||||
// FireMethodNotAllowed if it's true router checks for StatusMethodNotAllowed(405) and
|
// FireMethodNotAllowed if it's true router checks for StatusMethodNotAllowed(405) and
|
||||||
// fires the 405 error instead of 404
|
// fires the 405 error instead of 404
|
||||||
// Defaults to false.
|
// Defaults to false.
|
||||||
FireMethodNotAllowed bool
|
FireMethodNotAllowed bool `yaml:"fireMethodNotAllowed"`
|
||||||
|
|
||||||
// DisableBanner outputs the iris banner at startup
|
// DisableBanner outputs the iris banner at startup
|
||||||
//
|
//
|
||||||
// Defaults to false.
|
// Defaults to false.
|
||||||
DisableBanner bool
|
DisableBanner bool `yaml:"disableBanner"`
|
||||||
|
|
||||||
// DisableBodyConsumptionOnUnmarshal manages the reading behavior of the context's body readers/binders.
|
// DisableBodyConsumptionOnUnmarshal manages the reading behavior of the context's body readers/binders.
|
||||||
// If setted to true then it
|
// If setted to true then it
|
||||||
|
@ -152,34 +171,36 @@ type Configuration struct {
|
||||||
// if this field setted to true then a new buffer will be created to read from and the request body.
|
// 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
|
// The body will not be changed and existing data before the
|
||||||
// context.UnmarshalBody/ReadJSON/ReadXML will be not consumed.
|
// context.UnmarshalBody/ReadJSON/ReadXML will be not consumed.
|
||||||
DisableBodyConsumptionOnUnmarshal bool
|
DisableBodyConsumptionOnUnmarshal bool `yaml:"disableBodyConsumptionOnUnmarshal"`
|
||||||
|
|
||||||
// TimeFormat time format for any kind of datetime parsing
|
// TimeFormat time format for any kind of datetime parsing
|
||||||
// Defauls to "Mon, 02 Jan 2006 15:04:05 GMT".
|
// Defauls to "Mon, 02 Jan 2006 15:04:05 GMT".
|
||||||
TimeFormat string
|
TimeFormat string `yaml:"timeFormat"`
|
||||||
|
|
||||||
// Charset character encoding for various rendering
|
// Charset character encoding for various rendering
|
||||||
// used for templates and the rest of the responses
|
// used for templates and the rest of the responses
|
||||||
// Defaults to "UTF-8".
|
// Defaults to "UTF-8".
|
||||||
Charset string
|
Charset string `yaml:"charset"`
|
||||||
|
|
||||||
// Gzip enables gzip compression on your Render actions, this includes any type of render,
|
// Gzip enables gzip compression on your Render actions, this includes any type of render,
|
||||||
// templates and pure/raw content
|
// templates and pure/raw content
|
||||||
// If you don't want to enable it globally, you could just use the third parameter
|
// 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})
|
// on context.Render("myfileOrResponse", structBinding{}, iris.RenderOptions{"gzip": true})
|
||||||
// Defaults to false.
|
// Defaults to false.
|
||||||
Gzip bool
|
Gzip bool `yaml:"gzip"`
|
||||||
|
|
||||||
// Other are the custom, dynamic options, can be empty.
|
// Other are the custom, dynamic options, can be empty.
|
||||||
// This field used only by you to set any app's options you want
|
// This field used only by you to set any app's options you want
|
||||||
// or by custom adaptors, it's a way to simple communicate between your adaptors (if any)
|
// or by custom adaptors, it's a way to simple communicate between your adaptors (if any)
|
||||||
// Defaults to a non-nil empty map.
|
// Defaults to a non-nil empty map.
|
||||||
Other map[string]interface{}
|
Other map[string]interface{} `yaml:"other"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set implements the OptionSetter
|
// Set implements the OptionSetter
|
||||||
func (c Configuration) Set(main *Configuration) {
|
func (c Configuration) Set(main *Configuration) {
|
||||||
mergo.MergeWithOverwrite(main, c)
|
if err := mergo.MergeWithOverwrite(main, c); err != nil {
|
||||||
|
panic("FATAL ERROR .Configuration as OptionSetter: " + err.Error())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// All options starts with "Option" preffix in order to be easier to find what dev searching for
|
// All options starts with "Option" preffix in order to be easier to find what dev searching for
|
||||||
|
@ -245,29 +266,6 @@ var (
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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 {
|
|
||||||
return func(c *Configuration) {
|
|
||||||
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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// OptionCheckForUpdates will try to search for newer version of Iris based on the https://github.com/kataras/iris/releases
|
// 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 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
|
// if 'y' is pressed then the updater will try to install the latest version
|
||||||
|
@ -407,8 +405,8 @@ const (
|
||||||
)
|
)
|
||||||
|
|
||||||
// DefaultConfiguration returns the default configuration for an Iris station, fills the main Configuration
|
// DefaultConfiguration returns the default configuration for an Iris station, fills the main Configuration
|
||||||
func DefaultConfiguration() *Configuration {
|
func DefaultConfiguration() Configuration {
|
||||||
return &Configuration{
|
return Configuration{
|
||||||
VHost: "",
|
VHost: "",
|
||||||
VScheme: "",
|
VScheme: "",
|
||||||
ReadTimeout: DefaultReadTimeout,
|
ReadTimeout: DefaultReadTimeout,
|
||||||
|
|
198
configuration_test.go
Normal file
198
configuration_test.go
Normal file
|
@ -0,0 +1,198 @@
|
||||||
|
// Black-box Testing
|
||||||
|
package iris_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io/ioutil"
|
||||||
|
"os"
|
||||||
|
"reflect"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
. "gopkg.in/kataras/iris.v6"
|
||||||
|
)
|
||||||
|
|
||||||
|
// go test -v -run TestConfiguration*
|
||||||
|
|
||||||
|
func TestConfigurationStatic(t *testing.T) {
|
||||||
|
def := DefaultConfiguration()
|
||||||
|
|
||||||
|
app := New(def)
|
||||||
|
afterNew := *app.Config
|
||||||
|
|
||||||
|
if !reflect.DeepEqual(def, afterNew) {
|
||||||
|
t.Fatalf("Default configuration is not the same after NewFromConfig expected:\n %#v \ngot:\n %#v", def, afterNew)
|
||||||
|
}
|
||||||
|
|
||||||
|
afterNew.Charset = "changed"
|
||||||
|
|
||||||
|
if reflect.DeepEqual(def, afterNew) {
|
||||||
|
t.Fatalf("Configuration should be not equal, got: %#v", afterNew)
|
||||||
|
}
|
||||||
|
|
||||||
|
app = New(Configuration{DisableBanner: true})
|
||||||
|
|
||||||
|
afterNew = *app.Config
|
||||||
|
|
||||||
|
if app.Config.DisableBanner == false {
|
||||||
|
t.Fatalf("Passing a Configuration field as Option fails, expected DisableBanner to be true but was false")
|
||||||
|
}
|
||||||
|
|
||||||
|
app = New() // empty , means defaults so
|
||||||
|
if !reflect.DeepEqual(def, *app.Config) {
|
||||||
|
t.Fatalf("Default configuration is not the same after NewFromConfig expected:\n %#v \ngot:\n %#v", def, *app.Config)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestConfigurationOptions(t *testing.T) {
|
||||||
|
charset := "MYCHARSET"
|
||||||
|
disableBanner := true
|
||||||
|
|
||||||
|
app := New(OptionCharset(charset), OptionDisableBanner(disableBanner))
|
||||||
|
|
||||||
|
if got := app.Config.Charset; got != charset {
|
||||||
|
t.Fatalf("Expected configuration Charset to be: %s but got: %s", charset, got)
|
||||||
|
}
|
||||||
|
|
||||||
|
if got := app.Config.DisableBanner; got != disableBanner {
|
||||||
|
t.Fatalf("Expected configuration DisableBanner to be: %#v but got: %#v", disableBanner, got)
|
||||||
|
}
|
||||||
|
|
||||||
|
// now check if other default values are setted (should be setted automatically)
|
||||||
|
|
||||||
|
expected := DefaultConfiguration()
|
||||||
|
expected.Charset = charset
|
||||||
|
expected.DisableBanner = disableBanner
|
||||||
|
|
||||||
|
has := *app.Config
|
||||||
|
if !reflect.DeepEqual(has, expected) {
|
||||||
|
t.Fatalf("Default configuration is not the same after New expected:\n %#v \ngot:\n %#v", expected, has)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestConfigurationOptionsDeep(t *testing.T) {
|
||||||
|
charset := "MYCHARSET"
|
||||||
|
disableBanner := true
|
||||||
|
vhost := "mydomain.com"
|
||||||
|
// first charset,disableBanner and profilepath, no canonical order.
|
||||||
|
app := New(OptionCharset(charset), OptionDisableBanner(disableBanner), OptionVHost(vhost))
|
||||||
|
|
||||||
|
expected := DefaultConfiguration()
|
||||||
|
expected.Charset = charset
|
||||||
|
expected.DisableBanner = disableBanner
|
||||||
|
expected.VHost = vhost
|
||||||
|
|
||||||
|
has := *app.Config
|
||||||
|
|
||||||
|
if !reflect.DeepEqual(has, expected) {
|
||||||
|
t.Fatalf("DEEP configuration is not the same after New expected:\n %#v \ngot:\n %#v", expected, has)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestConfigurationYAML(t *testing.T) {
|
||||||
|
// create the key and cert files on the fly, and delete them when this test finished
|
||||||
|
yamlFile, ferr := ioutil.TempFile("", "configuration.yml")
|
||||||
|
|
||||||
|
if ferr != nil {
|
||||||
|
t.Fatal(ferr)
|
||||||
|
}
|
||||||
|
|
||||||
|
defer func() {
|
||||||
|
yamlFile.Close()
|
||||||
|
time.Sleep(50 * time.Millisecond)
|
||||||
|
os.Remove(yamlFile.Name())
|
||||||
|
}()
|
||||||
|
|
||||||
|
yamlConfigurationContents := `
|
||||||
|
vHost: iris-go.com
|
||||||
|
|
||||||
|
vScheme: https://
|
||||||
|
|
||||||
|
readTimeout: 0
|
||||||
|
|
||||||
|
writeTimeout: 5s
|
||||||
|
|
||||||
|
maxHeaderBytes: 8096
|
||||||
|
|
||||||
|
checkForUpdates: true
|
||||||
|
|
||||||
|
disablePathCorrection: false
|
||||||
|
|
||||||
|
enablePathEscape: false
|
||||||
|
|
||||||
|
fireMethodNotAllowed: true
|
||||||
|
|
||||||
|
disableBanner: true
|
||||||
|
|
||||||
|
disableBodyConsumptionOnUnmarshal: true
|
||||||
|
|
||||||
|
timeFormat: Mon, 01 Jan 2006 15:04:05 GMT
|
||||||
|
|
||||||
|
charset: UTF-8
|
||||||
|
|
||||||
|
gzip: true
|
||||||
|
|
||||||
|
`
|
||||||
|
yamlFile.WriteString(yamlConfigurationContents)
|
||||||
|
filename := yamlFile.Name()
|
||||||
|
app := New(YAML(filename))
|
||||||
|
|
||||||
|
c := app.Config
|
||||||
|
|
||||||
|
if expected := "iris-go.com"; c.VHost != expected {
|
||||||
|
t.Fatalf("error on TestConfigurationYAML: Expected VHost %s but got %s", expected, c.VHost)
|
||||||
|
}
|
||||||
|
|
||||||
|
if expected := "https://"; c.VScheme != expected {
|
||||||
|
t.Fatalf("error on TestConfigurationYAML: Expected VScheme %s but got %s", expected, c.VScheme)
|
||||||
|
}
|
||||||
|
|
||||||
|
if expected := 0; c.ReadTimeout != time.Duration(expected) {
|
||||||
|
t.Fatalf("error on TestConfigurationYAML: Expected ReadTimeout %s but got %s", expected, c.ReadTimeout)
|
||||||
|
}
|
||||||
|
|
||||||
|
if expected := time.Duration(5 * time.Second); c.WriteTimeout != expected {
|
||||||
|
t.Fatalf("error on TestConfigurationYAML: Expected WriteTimeout %s but got %s", expected, c.WriteTimeout)
|
||||||
|
}
|
||||||
|
|
||||||
|
if expected := 8096; c.MaxHeaderBytes != expected {
|
||||||
|
t.Fatalf("error on TestConfigurationYAML: Expected MaxHeaderBytes %s but got %s", expected, c.MaxHeaderBytes)
|
||||||
|
}
|
||||||
|
|
||||||
|
if expected := true; c.CheckForUpdates != expected {
|
||||||
|
t.Fatalf("error on TestConfigurationYAML: Expected checkForUpdates %v but got %v", expected, c.CheckForUpdates)
|
||||||
|
}
|
||||||
|
|
||||||
|
if expected := false; c.DisablePathCorrection != expected {
|
||||||
|
t.Fatalf("error on TestConfigurationYAML: Expected DisablePathCorrection %v but got %v", expected, c.DisablePathCorrection)
|
||||||
|
}
|
||||||
|
|
||||||
|
if expected := false; c.EnablePathEscape != expected {
|
||||||
|
t.Fatalf("error on TestConfigurationYAML: Expected EnablePathEscape %v but got %v", expected, c.EnablePathEscape)
|
||||||
|
}
|
||||||
|
|
||||||
|
if expected := true; c.FireMethodNotAllowed != expected {
|
||||||
|
t.Fatalf("error on TestConfigurationYAML: Expected FireMethodNotAllowed %v but got %v", expected, c.FireMethodNotAllowed)
|
||||||
|
}
|
||||||
|
|
||||||
|
if expected := true; c.DisableBanner != expected {
|
||||||
|
t.Fatalf("error on TestConfigurationYAML: Expected DisableBanner %v but got %v", expected, c.DisableBanner)
|
||||||
|
}
|
||||||
|
|
||||||
|
if expected := true; c.DisableBodyConsumptionOnUnmarshal != expected {
|
||||||
|
t.Fatalf("error on TestConfigurationYAML: Expected DisableBodyConsumptionOnUnmarshal %v but got %v",
|
||||||
|
expected, c.DisableBodyConsumptionOnUnmarshal)
|
||||||
|
}
|
||||||
|
|
||||||
|
if expected := "Mon, 01 Jan 2006 15:04:05 GMT"; c.TimeFormat != expected {
|
||||||
|
t.Fatalf("error on TestConfigurationYAML: Expected TimeFormat %s but got %s", expected, c.TimeFormat)
|
||||||
|
}
|
||||||
|
|
||||||
|
if expected := "UTF-8"; c.Charset != expected {
|
||||||
|
t.Fatalf("error on TestConfigurationYAML: Expected Charset %s but got %s", expected, c.Charset)
|
||||||
|
}
|
||||||
|
|
||||||
|
if expected := true; c.Gzip != expected {
|
||||||
|
t.Fatalf("error on TestConfigurationYAML: Expected != %v but got %v", expected, c.Gzip)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
32
iris.go
32
iris.go
|
@ -9,6 +9,7 @@
|
||||||
package iris
|
package iris
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"crypto/tls"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"log"
|
"log"
|
||||||
|
@ -67,6 +68,20 @@ type Framework struct {
|
||||||
// HTTP Server runtime fields is the iris' defined main server, developer can use unlimited number of servers
|
// HTTP Server runtime fields is the iris' defined main server, developer can use unlimited number of servers
|
||||||
// note: they're available after .Build, and .Serve/Listen/ListenTLS/ListenLETSENCRYPT/ListenUNIX
|
// note: they're available after .Build, and .Serve/Listen/ListenTLS/ListenLETSENCRYPT/ListenUNIX
|
||||||
ln net.Listener
|
ln net.Listener
|
||||||
|
// 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)
|
||||||
|
|
||||||
closedManually bool
|
closedManually bool
|
||||||
|
|
||||||
once sync.Once
|
once sync.Once
|
||||||
|
@ -92,13 +107,14 @@ func DevLogger() LoggerPolicy {
|
||||||
// New creates and returns a fresh Iris *Framework instance
|
// New creates and returns a fresh Iris *Framework instance
|
||||||
// with the default configuration if no 'setters' parameters passed.
|
// with the default configuration if no 'setters' parameters passed.
|
||||||
func New(setters ...OptionSetter) *Framework {
|
func New(setters ...OptionSetter) *Framework {
|
||||||
s := &Framework{Config: DefaultConfiguration()}
|
cfg := DefaultConfiguration()
|
||||||
|
s := &Framework{Config: &cfg}
|
||||||
|
|
||||||
// +------------------------------------------------------------+
|
// +------------------------------------------------------------+
|
||||||
// | Set the config passed from setters |
|
// | Set the config passed from setters |
|
||||||
// | or use the default one |
|
// | or use the default one |
|
||||||
// +------------------------------------------------------------+
|
// +------------------------------------------------------------+
|
||||||
s.Set(setters...)
|
s.Set(setters...)
|
||||||
|
|
||||||
{
|
{
|
||||||
// +------------------------------------------------------------+
|
// +------------------------------------------------------------+
|
||||||
// | Module Name: Logger |
|
// | Module Name: Logger |
|
||||||
|
@ -389,19 +405,13 @@ func (s *Framework) Serve(ln net.Listener) error {
|
||||||
ReadTimeout: s.Config.ReadTimeout,
|
ReadTimeout: s.Config.ReadTimeout,
|
||||||
WriteTimeout: s.Config.WriteTimeout,
|
WriteTimeout: s.Config.WriteTimeout,
|
||||||
MaxHeaderBytes: s.Config.MaxHeaderBytes,
|
MaxHeaderBytes: s.Config.MaxHeaderBytes,
|
||||||
TLSNextProto: s.Config.TLSNextProto,
|
TLSNextProto: s.TLSNextProto,
|
||||||
ConnState: s.Config.ConnState,
|
ConnState: s.ConnState,
|
||||||
Addr: s.Config.VHost,
|
Addr: s.Config.VHost,
|
||||||
ErrorLog: s.policies.LoggerPolicy.ToLogger(log.LstdFlags),
|
ErrorLog: s.policies.LoggerPolicy.ToLogger(log.LstdFlags),
|
||||||
Handler: s.Router,
|
Handler: s.Router,
|
||||||
}
|
}
|
||||||
|
|
||||||
if s.Config.TLSNextProto != nil {
|
|
||||||
srv.TLSNextProto = s.Config.TLSNextProto
|
|
||||||
}
|
|
||||||
if s.Config.ConnState != nil {
|
|
||||||
srv.ConnState = s.Config.ConnState
|
|
||||||
}
|
|
||||||
// print the banner and wait for system channel interrupt
|
// print the banner and wait for system channel interrupt
|
||||||
go s.postServe()
|
go s.postServe()
|
||||||
// finally return the error or block here, remember,
|
// finally return the error or block here, remember,
|
||||||
|
@ -535,7 +545,9 @@ func (s *Framework) isRunning() bool {
|
||||||
|
|
||||||
// Close is not working propetly but it releases the host:port.
|
// Close is not working propetly but it releases the host:port.
|
||||||
func (s *Framework) Close() error {
|
func (s *Framework) Close() error {
|
||||||
|
|
||||||
if s.isRunning() {
|
if s.isRunning() {
|
||||||
|
s.closedManually = true
|
||||||
///TODO:
|
///TODO:
|
||||||
// This code below doesn't works without custom net listener which will work in a stop channel which will cost us performance.
|
// This code below doesn't works without custom net listener which will work in a stop channel which will cost us performance.
|
||||||
// This will work on go v1.8 BUT FOR NOW make unexported reserve/reboot/restart in order to be non confusual for the user.
|
// This will work on go v1.8 BUT FOR NOW make unexported reserve/reboot/restart in order to be non confusual for the user.
|
||||||
|
|
Loading…
Reference in New Issue
Block a user