diff --git a/.travis.yml b/.travis.yml index e37a72fb..ee408409 100644 --- a/.travis.yml +++ b/.travis.yml @@ -15,18 +15,6 @@ after_script: - cd ./_examples - go get ./... - go test -v -cover ./... - # cache examples - - cd ../cache/_examples - - go get ./... - - go test -v -cover ./... - # sessions examples - - cd ../../sessions/_examples - - go get ./... - - go test -v -cover ./... - # websocket examples - - cd ../../websocket/_examples - - go get ./... - - go test -v -cover ./... # typescript examples - cd ../../typescript/_examples - go get ./... diff --git a/ACQUIRED_HISTORY.md b/ACQUIRED_HISTORY.md index 10e911cd..844f3975 100644 --- a/ACQUIRED_HISTORY.md +++ b/ACQUIRED_HISTORY.md @@ -11,11 +11,11 @@ ## 🔥 Reborn -As you may have heard I have huge responsibilities on my new position at Dubai nowdays, therefore I don't have the needed time to work on this project anymore. +As you may have heard I have huge responsibilities on my new position at Dubai nowadays, therefore I don't have the needed time to work on this project anymore. After almost a month of negotiations and searching I succeed to find a decent software engineer to continue my work on the open source community. -The leadership of this, open-source, repository was transfered to [hiveminded](https://github.com/hiveminded). +The leadership of this, open-source, repository was transferred to [hiveminded](https://github.com/hiveminded). These types of projects need heart and sacrifices to continue offer the best developer experience like a paid software, please do support him as you did with me! diff --git a/HISTORY.md b/HISTORY.md index e5373289..68312b07 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -23,7 +23,7 @@ No API Changes. ### Django view engine -@corebreaker pushed a [PR](https://github.com/kataras/iris/pull/682) to solve the [Problem for {%extends%} in Django Engine with embedded files](dhttps://github.com/kataras/iris/issues/681). +@corebreaker pushed a [PR](https://github.com/kataras/iris/pull/682) to solve the [Problem for {%extends%} in Django Engine with embedded files](https://github.com/kataras/iris/issues/681). ### Logger @@ -248,11 +248,11 @@ Despite the deflamations, the clickbait articles, the removed posts of mine at r ## 🔥 Reborn -As you may have heard I have huge responsibilities on my new position at Dubai nowdays, therefore I don't have the needed time to work on this project anymore. +As you may have heard I have huge responsibilities on my new position at Dubai nowadays, therefore I don't have the needed time to work on this project anymore. After a month of negotiations and searching I succeed to find a decent software engineer to continue my work on the open source community. -The leadership of this, open-source, repository was transfered to [hiveminded](https://github.com/hiveminded), the author of iris-based [get-ion/ion](https://github.com/get-ion/ion), he actually did an excellent job on the framework, he kept the code as minimal as possible and at the same time added more features, examples and middleware(s). +The leadership of this, open-source, repository was transferred to [hiveminded](https://github.com/hiveminded), the author of iris-based [get-ion/ion](https://github.com/get-ion/ion), he actually did an excellent job on the framework, he kept the code as minimal as possible and at the same time added more features, examples and middleware(s). These types of projects need heart and sacrifices to continue offer the best developer experience like a paid software, please do support him as you did with me! diff --git a/README.md b/README.md index c58a0988..6bf10658 100644 --- a/README.md +++ b/README.md @@ -61,11 +61,11 @@ Iris is a fast, simple and efficient micro web framework for Go. It provides a b ### 🔥 Reborn -As you may have heard I have huge responsibilities on my new position at Dubai nowdays, therefore I don't have the needed time to work on this project anymore. +As you may have heard I have huge responsibilities on my new position at Dubai nowadays, therefore I don't have the needed time to work on this project anymore. After almost a month of negotiations and searching I succeed to find a decent software engineer to continue my work on the open source community. -The leadership of this, open-source, repository was transfered to [hiveminded](https://github.com/hiveminded). +The leadership of this, open-source, repository was transferred to [hiveminded](https://github.com/hiveminded). These types of projects need heart and sacrifices to continue offer the best developer experience like a paid software, please do support him as you did with me! @@ -158,7 +158,7 @@ We expect Go version 1.9 to be released in August, however you can install Go 1. ### Installing Go 1.9beta2 1. Go to https://golang.org/dl/#go1.9beta2 -2. Download a compatible, with your OS, archieve, i.e `go1.9beta2.windows-amd64.zip` +2. Download a compatible, with your OS, archive, i.e `go1.9beta2.windows-amd64.zip` 3. Unzip the contents of `go1.9beta2.windows-amd64.zip/go` folder to your $GOROOT, i.e `C:\Go` 4. Open a terminal and execute `go version`, it should output the go1.9beta2 version, i.e: ```sh @@ -282,7 +282,7 @@ Compared to the rest open source projects, this one is very active and you get a * JWT - Server * Automatically install and serve certificates from https://letsencrypt.org when serving via TLS - * Gracefuly shutdown by-default + * Gracefully shutdown by-default * Register on shutdown, error or interrupt events * Attach more than one server, fully compatible with `net/http#Server` - View system: supporting 5 template engines. Fully compatible with `html/template` diff --git a/_examples/README.md b/_examples/README.md index 5d416203..fe6ad8ca 100644 --- a/_examples/README.md +++ b/_examples/README.md @@ -179,17 +179,32 @@ The `httptest` package is your way for end-to-end HTTP testing, it uses the http ### Caching -iris cache library lives on its own package: [https://github.com/kataras/iris/tree/master/cache](https://github.com/kataras/iris/tree/master/cache) **it contains examples** +iris cache library lives on its own [package](https://github.com/kataras/iris/tree/master/cache). + +- [Simple](cache/simple/main.go) + +> You're free to use your own favourite caching package if you'd like so. ### Sessions +iris session manager lives on its own [package](https://github.com/kataras/iris/tree/master/sessions). -iris session manager lives on its own package: [https://github.com/kataras/iris/tree/master/sessions](https://github.com/kataras/iris/tree/master/sessions) **it contains examples** +- [Overview](sessions/overview/main.go) +- [Standalone](sessions/standalone/main.go) +- [Secure Cookie](sessions/securecookie/main.go) +- [Flash Messages](sessions/flash-messages/main.go) +- [Database](sessions/database/main.go) > You're free to use your own favourite sessions package if you'd like so. ### Websockets -iris websocket library lives on its own package: [https://github.com/kataras/iris/tree/master/websocket](https://github.com/kataras/iris/tree/master/websocket) **it contains examples** +iris websocket library lives on its own [package](https://github.com/kataras/iris/tree/master/websocket). + +- [Chat](websocket/chat/main.go) +- [Native Messages](websocket/native-messages/main.go) +- [Connection List](websocket/connectionlist/main.go) +- [TLS Enabled](websocket/secure/main.go) +- [Custom Raw Go Client](websocket/custom-go-client/main.go) > You're free to use your own favourite websockets package if you'd like so. diff --git a/cache/_examples/simple/main.go b/_examples/cache/simple/main.go similarity index 100% rename from cache/_examples/simple/main.go rename to _examples/cache/simple/main.go diff --git a/_examples/http_responsewriter/write-rest/main.go b/_examples/http_responsewriter/write-rest/main.go index 9443230c..d3d35d71 100644 --- a/_examples/http_responsewriter/write-rest/main.go +++ b/_examples/http_responsewriter/write-rest/main.go @@ -42,7 +42,6 @@ func main() { Age: 25, } - ctx.StatusCode(iris.StatusOK) // Manually setting a content type: ctx.ContentType("application/javascript") ctx.JSON(peter) }) @@ -83,5 +82,13 @@ func main() { // http://localhost:8080/jsonp // http://localhost:8080/xml // http://localhost:8080/markdown - app.Run(iris.Addr(":8080")) + // + // `iris.WithOptimizations` is an optional configurator, + // if passed to the `Run` then it will ensure that the application + // response to the client as fast as possible. + // + // + // `iris.WithoutServerError` is an optional configurator, + // if passed to the `Run` then it will not print its passed error as an actual server error. + app.Run(iris.Addr(":8080"), iris.WithoutServerError(iris.ErrServerClosed), iris.WithOptimizations) } diff --git a/sessions/_examples/database/main.go b/_examples/sessions/database/main.go similarity index 100% rename from sessions/_examples/database/main.go rename to _examples/sessions/database/main.go diff --git a/sessions/_examples/flash-messages/main.go b/_examples/sessions/flash-messages/main.go similarity index 100% rename from sessions/_examples/flash-messages/main.go rename to _examples/sessions/flash-messages/main.go diff --git a/sessions/_examples/overview/main.go b/_examples/sessions/overview/main.go similarity index 100% rename from sessions/_examples/overview/main.go rename to _examples/sessions/overview/main.go diff --git a/sessions/_examples/securecookie/main.go b/_examples/sessions/securecookie/main.go similarity index 100% rename from sessions/_examples/securecookie/main.go rename to _examples/sessions/securecookie/main.go diff --git a/sessions/_examples/securecookie/main_test.go b/_examples/sessions/securecookie/main_test.go similarity index 100% rename from sessions/_examples/securecookie/main_test.go rename to _examples/sessions/securecookie/main_test.go diff --git a/sessions/_examples/standalone/main.go b/_examples/sessions/standalone/main.go similarity index 100% rename from sessions/_examples/standalone/main.go rename to _examples/sessions/standalone/main.go diff --git a/websocket/_examples/chat/main.go b/_examples/websocket/chat/main.go similarity index 100% rename from websocket/_examples/chat/main.go rename to _examples/websocket/chat/main.go diff --git a/websocket/_examples/chat/websockets.html b/_examples/websocket/chat/websockets.html similarity index 100% rename from websocket/_examples/chat/websockets.html rename to _examples/websocket/chat/websockets.html diff --git a/websocket/_examples/connectionlist/main.go b/_examples/websocket/connectionlist/main.go similarity index 100% rename from websocket/_examples/connectionlist/main.go rename to _examples/websocket/connectionlist/main.go diff --git a/websocket/_examples/connectionlist/static/js/chat.js b/_examples/websocket/connectionlist/static/js/chat.js similarity index 100% rename from websocket/_examples/connectionlist/static/js/chat.js rename to _examples/websocket/connectionlist/static/js/chat.js diff --git a/websocket/_examples/connectionlist/templates/client.html b/_examples/websocket/connectionlist/templates/client.html similarity index 100% rename from websocket/_examples/connectionlist/templates/client.html rename to _examples/websocket/connectionlist/templates/client.html diff --git a/websocket/_examples/custom-go-client/main.go b/_examples/websocket/custom-go-client/main.go similarity index 100% rename from websocket/_examples/custom-go-client/main.go rename to _examples/websocket/custom-go-client/main.go diff --git a/websocket/_examples/native-messages/main.go b/_examples/websocket/native-messages/main.go similarity index 100% rename from websocket/_examples/native-messages/main.go rename to _examples/websocket/native-messages/main.go diff --git a/websocket/_examples/native-messages/static/js/chat.js b/_examples/websocket/native-messages/static/js/chat.js similarity index 100% rename from websocket/_examples/native-messages/static/js/chat.js rename to _examples/websocket/native-messages/static/js/chat.js diff --git a/websocket/_examples/native-messages/templates/client.html b/_examples/websocket/native-messages/templates/client.html similarity index 100% rename from websocket/_examples/native-messages/templates/client.html rename to _examples/websocket/native-messages/templates/client.html diff --git a/websocket/_examples/secure/main.go b/_examples/websocket/secure/main.go similarity index 100% rename from websocket/_examples/secure/main.go rename to _examples/websocket/secure/main.go diff --git a/websocket/_examples/secure/static/js/chat.js b/_examples/websocket/secure/static/js/chat.js similarity index 100% rename from websocket/_examples/secure/static/js/chat.js rename to _examples/websocket/secure/static/js/chat.js diff --git a/websocket/_examples/secure/templates/client.html b/_examples/websocket/secure/templates/client.html similarity index 100% rename from websocket/_examples/secure/templates/client.html rename to _examples/websocket/secure/templates/client.html diff --git a/cache/README.md b/cache/README.md deleted file mode 100644 index 5637d4f6..00000000 --- a/cache/README.md +++ /dev/null @@ -1,7 +0,0 @@ -# Cache - -Fast HTTP Cache support for the [iris](https://github.com/kataras/iris) web framework. - -## Table of contents - -* [Simple](_examples/simple/main.go) \ No newline at end of file diff --git a/configuration.go b/configuration.go index 305ff707..a697b9f3 100644 --- a/configuration.go +++ b/configuration.go @@ -15,9 +15,9 @@ var errConfigurationDecode = errors.New("error while trying to decode configurat // YAML reads Configuration from a configuration.yml file. // -// Accepts the absolute path of the configuration.yml. +// Accepts the absolute path of the cfg.yml. // An error will be shown to the user via panic with the error message. -// Error may occur when the configuration.yml doesn't exists or is not formatted correctly. +// Error may occur when the cfg.yml doesn't exists or is not formatted correctly. // // Usage: // app := iris.Run(iris.Addr(":8080"), iris.WithConfiguration(iris.YAML("myconfig.yml"))) @@ -138,42 +138,49 @@ var WithoutInterruptHandler = func(app *Application) { // WithoutPathCorrection disables the PathCorrection setting. // -// See` Configuration`. +// See `Configuration`. var WithoutPathCorrection = func(app *Application) { app.config.DisablePathCorrection = true } // WithoutBodyConsumptionOnUnmarshal disables BodyConsumptionOnUnmarshal setting. // -// See` Configuration`. +// See `Configuration`. var WithoutBodyConsumptionOnUnmarshal = func(app *Application) { app.config.DisableBodyConsumptionOnUnmarshal = true } // WithoutAutoFireStatusCode disables the AutoFireStatusCode setting. // -// See` Configuration`. +// See `Configuration`. var WithoutAutoFireStatusCode = func(app *Application) { app.config.DisableAutoFireStatusCode = true } // WithPathEscape enanbles the PathEscape setting. // -// See` Configuration`. +// See `Configuration`. var WithPathEscape = func(app *Application) { app.config.EnablePathEscape = true } +// WithOptimizations can force the application to optimize for the best performance where is possible. +// +// See `Configuration`. +var WithOptimizations = func(app *Application) { + app.config.EnableOptimizations = true +} + // WithFireMethodNotAllowed enanbles the FireMethodNotAllowed setting. // -// See` Configuration`. +// See `Configuration`. var WithFireMethodNotAllowed = func(app *Application) { app.config.FireMethodNotAllowed = true } // WithTimeFormat sets the TimeFormat setting. // -// See` Configuration`. +// See `Configuration`. func WithTimeFormat(timeformat string) Configurator { return func(app *Application) { app.config.TimeFormat = timeformat @@ -182,7 +189,7 @@ func WithTimeFormat(timeformat string) Configurator { // WithCharset sets the Charset setting. // -// See` Configuration`. +// See `Configuration`. func WithCharset(charset string) Configurator { return func(app *Application) { app.config.Charset = charset @@ -227,7 +234,7 @@ func WithoutRemoteAddrHeader(headerName string) Configurator { // WithOtherValue adds a value based on a key to the Other setting. // -// See` Configuration`. +// See `Configuration`. func WithOtherValue(key string, val interface{}) Configurator { return func(app *Application) { if app.config.Other == nil { @@ -290,6 +297,11 @@ type Configuration struct { // Defaults to false. EnablePathEscape bool `yaml:"EnablePathEscape" toml:"EnablePathEscape"` + // EnableOptimization when this field is true + // then the application tries to optimize for the best performance where is possible. + // + // Defaults to false. + EnableOptimizations bool `yaml:"EnableOptimizations" toml:"EnableOptimizations"` // FireMethodNotAllowed if it's true router checks for StatusMethodNotAllowed(405) and // fires the 405 error instead of 404 // Defaults to false. @@ -366,10 +378,11 @@ type Configuration struct { // // Look `context.RemoteAddr()` for more. RemoteAddrHeaders map[string]bool `yaml:"RemoteAddrHeaders" toml:"RemoteAddrHeaders"` + // Other are the custom, dynamic options, can be empty. // 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) - // Defaults to a non-nil empty map + // Defaults to a non-nil empty map. Other map[string]interface{} `yaml:"Other" toml:"Other"` } @@ -384,7 +397,7 @@ func (c Configuration) GetVHost() string { return c.vhost } -// GetDisablePathCorrection returns the configuration.DisablePathCorrection, +// GetDisablePathCorrection returns the Configuration#DisablePathCorrection, // 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, // then the Router checks if /home handler exists, if yes, @@ -393,18 +406,24 @@ func (c Configuration) GetDisablePathCorrection() bool { return c.DisablePathCorrection } -// GetEnablePathEscape is the configuration.EnablePathEscape, +// GetEnablePathEscape is the Configuration#EnablePathEscape, // returns true when its escapes the path, the named parameters (if any). func (c Configuration) GetEnablePathEscape() bool { return c.EnablePathEscape } -// GetFireMethodNotAllowed returns the configuration.FireMethodNotAllowed. +// GetEnableOptimizations returns whether +// the application has performance optimizations enabled. +func (c Configuration) GetEnableOptimizations() bool { + return c.EnableOptimizations +} + +// GetFireMethodNotAllowed returns the Configuration#FireMethodNotAllowed. func (c Configuration) GetFireMethodNotAllowed() bool { return c.FireMethodNotAllowed } -// GetDisableBodyConsumptionOnUnmarshal returns the configuration.GetDisableBodyConsumptionOnUnmarshal, +// GetDisableBodyConsumptionOnUnmarshal returns the Configuration#GetDisableBodyConsumptionOnUnmarshal, // manages the reading behavior of the context's body readers/binders. // If returns true then the body consumption by the `context.UnmarshalBody/ReadJSON/ReadXML` // is disabled. @@ -417,19 +436,19 @@ func (c Configuration) GetDisableBodyConsumptionOnUnmarshal() bool { return c.DisableBodyConsumptionOnUnmarshal } -// GetDisableAutoFireStatusCode returns the configuration.DisableAutoFireStatusCode. +// GetDisableAutoFireStatusCode returns the Configuration#DisableAutoFireStatusCode. // Returns true when the http error status code handler automatic execution turned off. func (c Configuration) GetDisableAutoFireStatusCode() bool { return c.DisableAutoFireStatusCode } -// GetTimeFormat returns the configuration.TimeFormat, +// GetTimeFormat returns the Configuration#TimeFormat, // format for any kind of datetime parsing. func (c Configuration) GetTimeFormat() string { return c.TimeFormat } -// GetCharset returns the configuration.Charset, +// GetCharset returns the Configuration#Charset, // the character encoding for various rendering // used for templates and the rest of the responses. func (c Configuration) GetCharset() string { @@ -476,7 +495,7 @@ func (c Configuration) GetRemoteAddrHeaders() map[string]bool { return c.RemoteAddrHeaders } -// GetOther returns the configuration.Other map. +// GetOther returns the Configuration#Other map. func (c Configuration) GetOther() map[string]interface{} { return c.Other } @@ -513,6 +532,10 @@ func WithConfiguration(c Configuration) Configurator { main.EnablePathEscape = v } + if v := c.EnableOptimizations; v { + main.EnableOptimizations = v + } + if v := c.FireMethodNotAllowed; v { main.FireMethodNotAllowed = v } @@ -590,6 +613,7 @@ func DefaultConfiguration() Configuration { "X-Forwarded-For": false, "CF-Connecting-IP": false, }, - Other: make(map[string]interface{}, 0), + EnableOptimizations: false, + Other: make(map[string]interface{}, 0), } } diff --git a/context/configuration.go b/context/configuration.go index 3d157014..4ad53ef8 100644 --- a/context/configuration.go +++ b/context/configuration.go @@ -24,6 +24,10 @@ type ConfigurationReadOnly interface { // returns true when its escapes the path, the named parameters (if any). GetEnablePathEscape() bool + // GetEnableOptimizations returns whether + // the application has performance optimizations enabled. + GetEnableOptimizations() bool + // GetFireMethodNotAllowed returns the configuration.FireMethodNotAllowed. GetFireMethodNotAllowed() bool // GetDisableBodyConsumptionOnUnmarshal returns the configuration.GetDisableBodyConsumptionOnUnmarshal, diff --git a/context/context.go b/context/context.go index e91111a4..cc3bc659 100644 --- a/context/context.go +++ b/context/context.go @@ -23,6 +23,7 @@ import ( "time" "github.com/fatih/structs" + "github.com/json-iterator/go" "github.com/microcosm-cc/bluemonday" "github.com/monoculum/formam" "github.com/russross/blackfriday" @@ -1344,16 +1345,22 @@ func (ctx *context) UnmarshalBody(v interface{}, unmarshaler Unmarshaler) error return unmarshaler.Unmarshal(rawData, &v) } +func (ctx *context) shouldOptimize() bool { + return ctx.Application().ConfigurationReadOnly().GetEnableOptimizations() +} + // ReadJSON reads JSON from request's body and binds it to a value of any json-valid type. func (ctx *context) ReadJSON(jsonObject interface{}) error { - return ctx.UnmarshalBody(jsonObject, UnmarshalerFunc(json.Unmarshal)) - + var unmarshaler = json.Unmarshal + if ctx.shouldOptimize() { + unmarshaler = jsoniter.Unmarshal + } + return ctx.UnmarshalBody(jsonObject, UnmarshalerFunc(unmarshaler)) } // ReadXML reads XML from request's body and binds it to a value of any xml-valid type. func (ctx *context) ReadXML(xmlObject interface{}) error { return ctx.UnmarshalBody(xmlObject, UnmarshalerFunc(xml.Unmarshal)) - } var ( @@ -1780,15 +1787,28 @@ var ( // WriteJSON marshals the given interface object and writes the JSON response to the 'writer'. // Ignores StatusCode, Gzip, StreamingJSON options. -func WriteJSON(writer io.Writer, v interface{}, options JSON) (int, error) { - var result []byte - var err error +func WriteJSON(writer io.Writer, v interface{}, options JSON, enableOptimization ...bool) (int, error) { + var ( + result []byte + err error + optimize = len(enableOptimization) > 0 && enableOptimization[0] + ) if indent := options.Indent; indent != "" { - result, err = json.MarshalIndent(v, "", indent) + marshalIndent := json.MarshalIndent + if optimize { + marshalIndent = jsoniter.ConfigCompatibleWithStandardLibrary.MarshalIndent + } + + result, err = marshalIndent(v, "", indent) result = append(result, newLineB...) } else { - result, err = json.Marshal(v) + marshal := json.Marshal + if optimize { + marshal = jsoniter.ConfigCompatibleWithStandardLibrary.Marshal + } + + result, err = marshal(v) } if err != nil { @@ -1811,20 +1831,32 @@ func WriteJSON(writer io.Writer, v interface{}, options JSON) (int, error) { var defaultJSONOptions = JSON{} // JSON marshals the given interface object and writes the JSON response to the client. -func (ctx *context) JSON(v interface{}, opts ...JSON) (int, error) { +func (ctx *context) JSON(v interface{}, opts ...JSON) (n int, err error) { options := defaultJSONOptions if len(opts) > 0 { options = opts[0] } + optimize := ctx.shouldOptimize() + ctx.ContentType(contentJSONHeaderValue) if options.StreamingJSON { - enc := json.NewEncoder(ctx.writer) - enc.SetEscapeHTML(!options.UnescapeHTML) - enc.SetIndent(options.Prefix, options.Indent) - err := enc.Encode(v) + if optimize { + var jsoniterConfig = jsoniter.Config{ + EscapeHTML: !options.UnescapeHTML, + IndentionStep: 4, + }.Froze() + enc := jsoniterConfig.NewEncoder(ctx.writer) + err = enc.Encode(v) + } else { + enc := json.NewEncoder(ctx.writer) + enc.SetEscapeHTML(!options.UnescapeHTML) + enc.SetIndent(options.Prefix, options.Indent) + err = enc.Encode(v) + } + if err != nil { ctx.StatusCode(http.StatusInternalServerError) // it handles the fallback to normal mode here which also removes the gzip headers. return 0, err @@ -1832,7 +1864,7 @@ func (ctx *context) JSON(v interface{}, opts ...JSON) (int, error) { return ctx.writer.Written(), err } - n, err := WriteJSON(ctx.writer, v, options) + n, err = WriteJSON(ctx.writer, v, options, optimize) if err != nil { ctx.StatusCode(http.StatusInternalServerError) return 0, err @@ -1846,14 +1878,21 @@ var ( ) // WriteJSONP marshals the given interface object and writes the JSON response to the writer. -func WriteJSONP(writer io.Writer, v interface{}, options JSONP) (int, error) { +func WriteJSONP(writer io.Writer, v interface{}, options JSONP, enableOptimization ...bool) (int, error) { if callback := options.Callback; callback != "" { writer.Write([]byte(callback + "(")) defer writer.Write(finishCallbackB) } + optimize := len(enableOptimization) > 0 && enableOptimization[0] + if indent := options.Indent; indent != "" { - result, err := json.MarshalIndent(v, "", indent) + marshalIndent := json.MarshalIndent + if optimize { + marshalIndent = jsoniter.ConfigCompatibleWithStandardLibrary.MarshalIndent + } + + result, err := marshalIndent(v, "", indent) if err != nil { return 0, err } @@ -1861,7 +1900,12 @@ func WriteJSONP(writer io.Writer, v interface{}, options JSONP) (int, error) { return writer.Write(result) } - result, err := json.Marshal(v) + marshal := json.Marshal + if optimize { + marshal = jsoniter.ConfigCompatibleWithStandardLibrary.Marshal + } + + result, err := marshal(v) if err != nil { return 0, err } @@ -1880,7 +1924,7 @@ func (ctx *context) JSONP(v interface{}, opts ...JSONP) (int, error) { ctx.ContentType(contentJavascriptHeaderValue) - n, err := WriteJSONP(ctx.writer, v, options) + n, err := WriteJSONP(ctx.writer, v, options, ctx.shouldOptimize()) if err != nil { ctx.StatusCode(http.StatusInternalServerError) return 0, err diff --git a/core/host/supervisor.go b/core/host/supervisor.go index cddf2ff7..3def0a9f 100644 --- a/core/host/supervisor.go +++ b/core/host/supervisor.go @@ -105,7 +105,7 @@ func (su *Supervisor) newListener() (net.Listener, error) { return l, nil } -// RegisterOnError registers a function to call when errors occured by the underline http server. +// RegisterOnError registers a function to call when errors occurred by the underline http server. func (su *Supervisor) RegisterOnError(cb func(error)) { su.mu.Lock() su.onErr = append(su.onErr, cb) diff --git a/core/host/task.go b/core/host/task.go index 7eca97cb..d00bcd51 100644 --- a/core/host/task.go +++ b/core/host/task.go @@ -33,7 +33,7 @@ func WriteStartupLogOnServe(w io.Writer) func(TaskHost) { } // ShutdownOnInterrupt terminates the supervisor and its underline server when CMD+C/CTRL+C pressed. -// This function should be registerd on Interrupt. +// This function should be registered on Interrupt. func ShutdownOnInterrupt(su *Supervisor, shutdownTimeout time.Duration) func() { return func() { ctx, cancel := context.WithTimeout(context.TODO(), shutdownTimeout) diff --git a/core/router/node/node.go b/core/router/node/node.go index d8cb9438..5c04c2a6 100644 --- a/core/router/node/node.go +++ b/core/router/node/node.go @@ -301,6 +301,11 @@ func (nodes Nodes) findChild(path string, params []string) (*node, []string) { if n.rootWildcard { // println("return from n.rootWildcard") // single root wildcard + if len(path) < 2 { + // do not remove that, it seems useless but it's not, + // we had an error while production, this fixes that. + path = "/" + path + } return n, append(params, path[1:]) } diff --git a/doc.go b/doc.go index 49626a10..c7c95e8d 100644 --- a/doc.go +++ b/doc.go @@ -261,7 +261,7 @@ Example code: That's all with listening, you have the full control when you need it. -Let's continue by learning how to catch CONTROL+C/COMMAND+C or unix kill command and shutdown the server gracefuly. +Let's continue by learning how to catch CONTROL+C/COMMAND+C or unix kill command and shutdown the server gracefully. Gracefully Shutdown on CONTROL+C/COMMAND+C or when kill command sent is ENABLED BY-DEFAULT. diff --git a/middleware/logger/config.go b/middleware/logger/config.go index 6a3bacc4..7cedb8a6 100644 --- a/middleware/logger/config.go +++ b/middleware/logger/config.go @@ -32,7 +32,7 @@ type Config struct { // Columns will display the logs as well formatted columns (bool). // If custom `LogFunc` has been provided then this field is useless and users should - // use the `Columinize` function of the logger to get the ouput result as columns. + // use the `Columinize` function of the logger to get the output result as columns. // // Defaults to true. Columns bool diff --git a/sessions/README.md b/sessions/README.md deleted file mode 100644 index aa465ee1..00000000 --- a/sessions/README.md +++ /dev/null @@ -1,11 +0,0 @@ -# Sessions - -Fast HTTP Sessions for the [iris](https://github.com/kataras/iris) web framework. - -## Table of contents - -* [Overview](_examples/overview/main.go) -* [Standalone](_examples/standalone/main.go) -* [Secure Cookie](_examples/securecookie/main.go) -* [Flash Messages](_examples/flash-messages/main.go) -* [Database](_examples/database/main.go) \ No newline at end of file diff --git a/websocket/README.md b/websocket/README.md deleted file mode 100644 index 1dd2af53..00000000 --- a/websocket/README.md +++ /dev/null @@ -1,11 +0,0 @@ -# Websocket - -Rich websocket support for the [iris](https://github.com/kataras/iris) web framework. - -## Table of contents - -* [Chat](_examples/chat/main.go) -* [Native Messages](_examples/native-messages/main.go) -* [Connection List](_examples/connectionlist/main.go) -* [TLS Enabled](_examples/secure/main.go) -* [Custom Raw Go Client](_examples/custom-go-client/main.go) \ No newline at end of file