mirror of
https://github.com/kataras/iris.git
synced 2025-01-23 02:31:04 +01:00
new Application.SetContextErrorHandler method
This commit is contained in:
parent
73dfabf412
commit
ae828d8db9
|
@ -1,8 +1,9 @@
|
||||||
version: 2
|
version: 3
|
||||||
cli:
|
cli:
|
||||||
server: https://app.fossa.com
|
server: https://app.fossa.com
|
||||||
fetcher: custom
|
fetcher: git
|
||||||
project: https://github.com/kataras/iris.git
|
package: github.com/kataras/iris
|
||||||
|
project: github.com/kataras/iris
|
||||||
analyze:
|
analyze:
|
||||||
modules:
|
modules:
|
||||||
- name: iris
|
- name: iris
|
||||||
|
|
|
@ -28,11 +28,12 @@ The codebase for Dependency Injection, Internationalization and localization and
|
||||||
|
|
||||||
## Fixes and Improvements
|
## Fixes and Improvements
|
||||||
|
|
||||||
|
- Add new `Application.SetContextErrorHandler` to globally customize the default behavior (status code 500 without body) on `JSON`, `JSONP`, `Protobuf`, `MsgPack`, `XML`, `YAML` and `Markdown` method call write errors instead of catching the error on each handler.
|
||||||
- Add new [x/pagination](x/pagination/pagination.go) sub-package which supports generics code (go 1.18+).
|
- Add new [x/pagination](x/pagination/pagination.go) sub-package which supports generics code (go 1.18+).
|
||||||
- Add new [middleware/modrevision](middleware/modrevision) middleware (example at [_examples/project/api/router.go]_examples/project/api/router.go).
|
- Add new [middleware/modrevision](middleware/modrevision) middleware (example at [_examples/project/api/router.go]_examples/project/api/router.go).
|
||||||
- Add `iris.BuildRevision` and `iris.BuildTime` to embrace the new go's 1.18 debug build information.
|
- Add `iris.BuildRevision` and `iris.BuildTime` to embrace the new go's 1.18 debug build information.
|
||||||
|
|
||||||
- Add `Context.SetJSONOptions` to customize on a higher level the JSON options on `Context.JSON` calls.
|
- ~Add `Context.SetJSONOptions` to customize on a higher level the JSON options on `Context.JSON` calls.~ update: remains as it's, per JSON call.
|
||||||
- Add new [auth](auth) sub-package which helps on any user type auth using JWT (access & refresh tokens) and a cookie (optional).
|
- Add new [auth](auth) sub-package which helps on any user type auth using JWT (access & refresh tokens) and a cookie (optional).
|
||||||
|
|
||||||
- Add `Party.EnsureStaticBindings` which, if called, the MVC binder panics if a struct's input binding depends on the HTTP request data instead of a static dependency. This is useful to make sure your API crafted through `Party.PartyConfigure` depends only on struct values you already defined at `Party.RegisterDependency` == will never use reflection at serve-time (maximum performance).
|
- Add `Party.EnsureStaticBindings` which, if called, the MVC binder panics if a struct's input binding depends on the HTTP request data instead of a static dependency. This is useful to make sure your API crafted through `Party.PartyConfigure` depends only on struct values you already defined at `Party.RegisterDependency` == will never use reflection at serve-time (maximum performance).
|
||||||
|
@ -71,7 +72,7 @@ The codebase for Dependency Injection, Internationalization and localization and
|
||||||
|
|
||||||
- New `apps.OnApplicationRegistered` method which listens on new Iris applications hosted under the same binary. Use it on your `init` functions to configure Iris applications by any spot in your project's files.
|
- New `apps.OnApplicationRegistered` method which listens on new Iris applications hosted under the same binary. Use it on your `init` functions to configure Iris applications by any spot in your project's files.
|
||||||
|
|
||||||
- `Context.JSON` respects any object implements the `easyjson.Marshaler` interface and renders the result using the [easyjon](https://github.com/mailru/easyjson)'s writer.
|
- `Context.JSON` respects any object implements the `easyjson.Marshaler` interface and renders the result using the [easyjon](https://github.com/mailru/easyjson)'s writer. **Set** the `Configuration.EnableProtoJSON` and `Configuration.EnableEasyJSON` to true in order to enable this feature.
|
||||||
|
|
||||||
- minor: `Context` structure implements the standard go Context interface now (includes: Deadline, Done, Err and Value methods). Handlers can now just pass the `ctx iris.Context` as a shortcut of `ctx.Request().Context()` when needed.
|
- minor: `Context` structure implements the standard go Context interface now (includes: Deadline, Done, Err and Value methods). Handlers can now just pass the `ctx iris.Context` as a shortcut of `ctx.Request().Context()` when needed.
|
||||||
|
|
||||||
|
|
117
configuration.go
117
configuration.go
|
@ -10,11 +10,11 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/kataras/golog"
|
|
||||||
"github.com/kataras/iris/v12/context"
|
"github.com/kataras/iris/v12/context"
|
||||||
"github.com/kataras/iris/v12/core/netutil"
|
"github.com/kataras/iris/v12/core/netutil"
|
||||||
|
|
||||||
"github.com/BurntSushi/toml"
|
"github.com/BurntSushi/toml"
|
||||||
|
"github.com/kataras/golog"
|
||||||
"github.com/kataras/sitemap"
|
"github.com/kataras/sitemap"
|
||||||
"github.com/kataras/tunnel"
|
"github.com/kataras/tunnel"
|
||||||
"gopkg.in/yaml.v3"
|
"gopkg.in/yaml.v3"
|
||||||
|
@ -317,6 +317,20 @@ var WithOptimizations = func(app *Application) {
|
||||||
app.config.EnableOptimizations = true
|
app.config.EnableOptimizations = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// WithProtoJSON enables the proto marshaler on Context.JSON method.
|
||||||
|
//
|
||||||
|
// See `Configuration` for more.
|
||||||
|
var WithProtoJSON = func(app *Application) {
|
||||||
|
app.config.EnableProtoJSON = true
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithEasyJSON enables the fast easy json marshaler on Context.JSON method.
|
||||||
|
//
|
||||||
|
// See `Configuration` for more.
|
||||||
|
var WithEasyJSON = func(app *Application) {
|
||||||
|
app.config.EnableEasyJSON = true
|
||||||
|
}
|
||||||
|
|
||||||
// WithFireMethodNotAllowed enables the FireMethodNotAllowed setting.
|
// WithFireMethodNotAllowed enables the FireMethodNotAllowed setting.
|
||||||
//
|
//
|
||||||
// See `Configuration`.
|
// See `Configuration`.
|
||||||
|
@ -740,6 +754,17 @@ type Configuration struct {
|
||||||
//
|
//
|
||||||
// Defaults to false.
|
// Defaults to false.
|
||||||
EnableOptimizations bool `ini:"enable_optimizations" json:"enableOptimizations,omitempty" yaml:"EnableOptimizations" toml:"EnableOptimizations"`
|
EnableOptimizations bool `ini:"enable_optimizations" json:"enableOptimizations,omitempty" yaml:"EnableOptimizations" toml:"EnableOptimizations"`
|
||||||
|
// EnableProtoJSON when this field is true
|
||||||
|
// enables the proto marshaler on given proto messages when calling the Context.JSON method.
|
||||||
|
//
|
||||||
|
// Defaults to false.
|
||||||
|
EnableProtoJSON bool `ini:"enable_proto_json" json:"enableProtoJSON,omitempty" yaml:"EnableProtoJSON" toml:"EnableProtoJSON"`
|
||||||
|
// EnableEasyJSON when this field is true
|
||||||
|
// enables the fast easy json marshaler on compatible struct values when calling the Context.JSON method.
|
||||||
|
//
|
||||||
|
// Defaults to false.
|
||||||
|
EnableEasyJSON bool `ini:"enable_easy_json" json:"enableEasyJSON,omitempty" yaml:"EnableEasyJSON" toml:"EnableEasyJSON"`
|
||||||
|
|
||||||
// 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 set to true then it
|
// If set to true then it
|
||||||
// disables the body consumption by the `context.UnmarshalBody/ReadJSON/ReadXML`.
|
// disables the body consumption by the `context.UnmarshalBody/ReadJSON/ReadXML`.
|
||||||
|
@ -915,177 +940,187 @@ type Configuration struct {
|
||||||
var _ context.ConfigurationReadOnly = (*Configuration)(nil)
|
var _ context.ConfigurationReadOnly = (*Configuration)(nil)
|
||||||
|
|
||||||
// GetVHost returns the non-exported vhost config field.
|
// GetVHost returns the non-exported vhost config field.
|
||||||
func (c Configuration) GetVHost() string {
|
func (c *Configuration) GetVHost() string {
|
||||||
return c.vhost
|
return c.vhost
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetLogLevel returns the LogLevel field.
|
// GetLogLevel returns the LogLevel field.
|
||||||
func (c Configuration) GetLogLevel() string {
|
func (c *Configuration) GetLogLevel() string {
|
||||||
return c.vhost
|
return c.vhost
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetSocketSharding returns the SocketSharding field.
|
// GetSocketSharding returns the SocketSharding field.
|
||||||
func (c Configuration) GetSocketSharding() bool {
|
func (c *Configuration) GetSocketSharding() bool {
|
||||||
return c.SocketSharding
|
return c.SocketSharding
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetKeepAlive returns the KeepAlive field.
|
// GetKeepAlive returns the KeepAlive field.
|
||||||
func (c Configuration) GetKeepAlive() time.Duration {
|
func (c *Configuration) GetKeepAlive() time.Duration {
|
||||||
return c.KeepAlive
|
return c.KeepAlive
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetKeepAlive returns the Timeout field.
|
// GetKeepAlive returns the Timeout field.
|
||||||
func (c Configuration) GetTimeout() time.Duration {
|
func (c *Configuration) GetTimeout() time.Duration {
|
||||||
return c.Timeout
|
return c.Timeout
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetKeepAlive returns the TimeoutMessage field.
|
// GetKeepAlive returns the TimeoutMessage field.
|
||||||
func (c Configuration) GetTimeoutMessage() string {
|
func (c *Configuration) GetTimeoutMessage() string {
|
||||||
return c.TimeoutMessage
|
return c.TimeoutMessage
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetDisablePathCorrection returns the DisablePathCorrection field.
|
// GetDisablePathCorrection returns the DisablePathCorrection field.
|
||||||
func (c Configuration) GetDisablePathCorrection() bool {
|
func (c *Configuration) GetDisablePathCorrection() bool {
|
||||||
return c.DisablePathCorrection
|
return c.DisablePathCorrection
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetDisablePathCorrectionRedirection returns the DisablePathCorrectionRedirection field.
|
// GetDisablePathCorrectionRedirection returns the DisablePathCorrectionRedirection field.
|
||||||
func (c Configuration) GetDisablePathCorrectionRedirection() bool {
|
func (c *Configuration) GetDisablePathCorrectionRedirection() bool {
|
||||||
return c.DisablePathCorrectionRedirection
|
return c.DisablePathCorrectionRedirection
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetEnablePathIntelligence returns the EnablePathIntelligence field.
|
// GetEnablePathIntelligence returns the EnablePathIntelligence field.
|
||||||
func (c Configuration) GetEnablePathIntelligence() bool {
|
func (c *Configuration) GetEnablePathIntelligence() bool {
|
||||||
return c.EnablePathIntelligence
|
return c.EnablePathIntelligence
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetEnablePathEscape returns the EnablePathEscape field.
|
// GetEnablePathEscape returns the EnablePathEscape field.
|
||||||
func (c Configuration) GetEnablePathEscape() bool {
|
func (c *Configuration) GetEnablePathEscape() bool {
|
||||||
return c.EnablePathEscape
|
return c.EnablePathEscape
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetForceLowercaseRouting returns the ForceLowercaseRouting field.
|
// GetForceLowercaseRouting returns the ForceLowercaseRouting field.
|
||||||
func (c Configuration) GetForceLowercaseRouting() bool {
|
func (c *Configuration) GetForceLowercaseRouting() bool {
|
||||||
return c.ForceLowercaseRouting
|
return c.ForceLowercaseRouting
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetFireMethodNotAllowed returns the FireMethodNotAllowed field.
|
// GetFireMethodNotAllowed returns the FireMethodNotAllowed field.
|
||||||
func (c Configuration) GetFireMethodNotAllowed() bool {
|
func (c *Configuration) GetFireMethodNotAllowed() bool {
|
||||||
return c.FireMethodNotAllowed
|
return c.FireMethodNotAllowed
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetEnableOptimizations returns the EnableOptimizations.
|
// GetEnableOptimizations returns the EnableOptimizations.
|
||||||
func (c Configuration) GetEnableOptimizations() bool {
|
func (c *Configuration) GetEnableOptimizations() bool {
|
||||||
return c.EnableOptimizations
|
return c.EnableOptimizations
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetEnableProtoJSON returns the EnableProtoJSON field.
|
||||||
|
func (c *Configuration) GetEnableProtoJSON() bool {
|
||||||
|
return c.EnableProtoJSON
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetEnableEasyJSON returns the EnableEasyJSON field.
|
||||||
|
func (c *Configuration) GetEnableEasyJSON() bool {
|
||||||
|
return c.EnableEasyJSON
|
||||||
|
}
|
||||||
|
|
||||||
// GetDisableBodyConsumptionOnUnmarshal returns the DisableBodyConsumptionOnUnmarshal field.
|
// GetDisableBodyConsumptionOnUnmarshal returns the DisableBodyConsumptionOnUnmarshal field.
|
||||||
func (c Configuration) GetDisableBodyConsumptionOnUnmarshal() bool {
|
func (c *Configuration) GetDisableBodyConsumptionOnUnmarshal() bool {
|
||||||
return c.DisableBodyConsumptionOnUnmarshal
|
return c.DisableBodyConsumptionOnUnmarshal
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetFireEmptyFormError returns the DisableBodyConsumptionOnUnmarshal field.
|
// GetFireEmptyFormError returns the DisableBodyConsumptionOnUnmarshal field.
|
||||||
func (c Configuration) GetFireEmptyFormError() bool {
|
func (c *Configuration) GetFireEmptyFormError() bool {
|
||||||
return c.FireEmptyFormError
|
return c.FireEmptyFormError
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetDisableAutoFireStatusCode returns the DisableAutoFireStatusCode field.
|
// GetDisableAutoFireStatusCode returns the DisableAutoFireStatusCode field.
|
||||||
func (c Configuration) GetDisableAutoFireStatusCode() bool {
|
func (c *Configuration) GetDisableAutoFireStatusCode() bool {
|
||||||
return c.DisableAutoFireStatusCode
|
return c.DisableAutoFireStatusCode
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetResetOnFireErrorCode returns ResetOnFireErrorCode field.
|
// GetResetOnFireErrorCode returns ResetOnFireErrorCode field.
|
||||||
func (c Configuration) GetResetOnFireErrorCode() bool {
|
func (c *Configuration) GetResetOnFireErrorCode() bool {
|
||||||
return c.ResetOnFireErrorCode
|
return c.ResetOnFireErrorCode
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetTimeFormat returns the TimeFormat field.
|
// GetTimeFormat returns the TimeFormat field.
|
||||||
func (c Configuration) GetTimeFormat() string {
|
func (c *Configuration) GetTimeFormat() string {
|
||||||
return c.TimeFormat
|
return c.TimeFormat
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetCharset returns the Charset field.
|
// GetCharset returns the Charset field.
|
||||||
func (c Configuration) GetCharset() string {
|
func (c *Configuration) GetCharset() string {
|
||||||
return c.Charset
|
return c.Charset
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetPostMaxMemory returns the PostMaxMemory field.
|
// GetPostMaxMemory returns the PostMaxMemory field.
|
||||||
func (c Configuration) GetPostMaxMemory() int64 {
|
func (c *Configuration) GetPostMaxMemory() int64 {
|
||||||
return c.PostMaxMemory
|
return c.PostMaxMemory
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetLocaleContextKey returns the LocaleContextKey field.
|
// GetLocaleContextKey returns the LocaleContextKey field.
|
||||||
func (c Configuration) GetLocaleContextKey() string {
|
func (c *Configuration) GetLocaleContextKey() string {
|
||||||
return c.LocaleContextKey
|
return c.LocaleContextKey
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetLanguageContextKey returns the LanguageContextKey field.
|
// GetLanguageContextKey returns the LanguageContextKey field.
|
||||||
func (c Configuration) GetLanguageContextKey() string {
|
func (c *Configuration) GetLanguageContextKey() string {
|
||||||
return c.LanguageContextKey
|
return c.LanguageContextKey
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetLanguageInputContextKey returns the LanguageInputContextKey field.
|
// GetLanguageInputContextKey returns the LanguageInputContextKey field.
|
||||||
func (c Configuration) GetLanguageInputContextKey() string {
|
func (c *Configuration) GetLanguageInputContextKey() string {
|
||||||
return c.LanguageInputContextKey
|
return c.LanguageInputContextKey
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetVersionContextKey returns the VersionContextKey field.
|
// GetVersionContextKey returns the VersionContextKey field.
|
||||||
func (c Configuration) GetVersionContextKey() string {
|
func (c *Configuration) GetVersionContextKey() string {
|
||||||
return c.VersionContextKey
|
return c.VersionContextKey
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetVersionAliasesContextKey returns the VersionAliasesContextKey field.
|
// GetVersionAliasesContextKey returns the VersionAliasesContextKey field.
|
||||||
func (c Configuration) GetVersionAliasesContextKey() string {
|
func (c *Configuration) GetVersionAliasesContextKey() string {
|
||||||
return c.VersionAliasesContextKey
|
return c.VersionAliasesContextKey
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetViewEngineContextKey returns the ViewEngineContextKey field.
|
// GetViewEngineContextKey returns the ViewEngineContextKey field.
|
||||||
func (c Configuration) GetViewEngineContextKey() string {
|
func (c *Configuration) GetViewEngineContextKey() string {
|
||||||
return c.ViewEngineContextKey
|
return c.ViewEngineContextKey
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetViewLayoutContextKey returns the ViewLayoutContextKey field.
|
// GetViewLayoutContextKey returns the ViewLayoutContextKey field.
|
||||||
func (c Configuration) GetViewLayoutContextKey() string {
|
func (c *Configuration) GetViewLayoutContextKey() string {
|
||||||
return c.ViewLayoutContextKey
|
return c.ViewLayoutContextKey
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetViewDataContextKey returns the ViewDataContextKey field.
|
// GetViewDataContextKey returns the ViewDataContextKey field.
|
||||||
func (c Configuration) GetViewDataContextKey() string {
|
func (c *Configuration) GetViewDataContextKey() string {
|
||||||
return c.ViewDataContextKey
|
return c.ViewDataContextKey
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetFallbackViewContextKey returns the FallbackViewContextKey field.
|
// GetFallbackViewContextKey returns the FallbackViewContextKey field.
|
||||||
func (c Configuration) GetFallbackViewContextKey() string {
|
func (c *Configuration) GetFallbackViewContextKey() string {
|
||||||
return c.FallbackViewContextKey
|
return c.FallbackViewContextKey
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetRemoteAddrHeaders returns the RemoteAddrHeaders field.
|
// GetRemoteAddrHeaders returns the RemoteAddrHeaders field.
|
||||||
func (c Configuration) GetRemoteAddrHeaders() []string {
|
func (c *Configuration) GetRemoteAddrHeaders() []string {
|
||||||
return c.RemoteAddrHeaders
|
return c.RemoteAddrHeaders
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetRemoteAddrHeadersForce returns RemoteAddrHeadersForce field.
|
// GetRemoteAddrHeadersForce returns RemoteAddrHeadersForce field.
|
||||||
func (c Configuration) GetRemoteAddrHeadersForce() bool {
|
func (c *Configuration) GetRemoteAddrHeadersForce() bool {
|
||||||
return c.RemoteAddrHeadersForce
|
return c.RemoteAddrHeadersForce
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetSSLProxyHeaders returns the SSLProxyHeaders field.
|
// GetSSLProxyHeaders returns the SSLProxyHeaders field.
|
||||||
func (c Configuration) GetSSLProxyHeaders() map[string]string {
|
func (c *Configuration) GetSSLProxyHeaders() map[string]string {
|
||||||
return c.SSLProxyHeaders
|
return c.SSLProxyHeaders
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetRemoteAddrPrivateSubnets returns the RemoteAddrPrivateSubnets field.
|
// GetRemoteAddrPrivateSubnets returns the RemoteAddrPrivateSubnets field.
|
||||||
func (c Configuration) GetRemoteAddrPrivateSubnets() []netutil.IPRange {
|
func (c *Configuration) GetRemoteAddrPrivateSubnets() []netutil.IPRange {
|
||||||
return c.RemoteAddrPrivateSubnets
|
return c.RemoteAddrPrivateSubnets
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetHostProxyHeaders returns the HostProxyHeaders field.
|
// GetHostProxyHeaders returns the HostProxyHeaders field.
|
||||||
func (c Configuration) GetHostProxyHeaders() map[string]bool {
|
func (c *Configuration) GetHostProxyHeaders() map[string]bool {
|
||||||
return c.HostProxyHeaders
|
return c.HostProxyHeaders
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetOther returns the Other field.
|
// GetOther returns the Other field.
|
||||||
func (c Configuration) GetOther() map[string]interface{} {
|
func (c *Configuration) GetOther() map[string]interface{} {
|
||||||
return c.Other
|
return c.Other
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1166,6 +1201,14 @@ func WithConfiguration(c Configuration) Configurator {
|
||||||
main.EnableOptimizations = v
|
main.EnableOptimizations = v
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if v := c.EnableProtoJSON; v {
|
||||||
|
main.EnableProtoJSON = v
|
||||||
|
}
|
||||||
|
|
||||||
|
if v := c.EnableEasyJSON; v {
|
||||||
|
main.EnableEasyJSON = v
|
||||||
|
}
|
||||||
|
|
||||||
if v := c.FireMethodNotAllowed; v {
|
if v := c.FireMethodNotAllowed; v {
|
||||||
main.FireMethodNotAllowed = v
|
main.FireMethodNotAllowed = v
|
||||||
}
|
}
|
||||||
|
@ -1342,6 +1385,8 @@ func DefaultConfiguration() Configuration {
|
||||||
SSLProxyHeaders: make(map[string]string),
|
SSLProxyHeaders: make(map[string]string),
|
||||||
HostProxyHeaders: make(map[string]bool),
|
HostProxyHeaders: make(map[string]bool),
|
||||||
EnableOptimizations: false,
|
EnableOptimizations: false,
|
||||||
|
EnableProtoJSON: false,
|
||||||
|
EnableEasyJSON: false,
|
||||||
Other: make(map[string]interface{}),
|
Other: make(map[string]interface{}),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -52,6 +52,10 @@ type Application interface {
|
||||||
// is hijacked by a third-party middleware and the http handler return too fast.
|
// is hijacked by a third-party middleware and the http handler return too fast.
|
||||||
GetContextPool() *Pool
|
GetContextPool() *Pool
|
||||||
|
|
||||||
|
// GetContextErrorHandler returns the handler which handles errors
|
||||||
|
// on JSON write failures.
|
||||||
|
GetContextErrorHandler() ErrorHandler
|
||||||
|
|
||||||
// ServeHTTPC is the internal router, it's visible because it can be used for advanced use cases,
|
// ServeHTTPC is the internal router, it's visible because it can be used for advanced use cases,
|
||||||
// i.e: routing within a foreign context.
|
// i.e: routing within a foreign context.
|
||||||
//
|
//
|
||||||
|
|
|
@ -43,6 +43,11 @@ type ConfigurationReadOnly interface {
|
||||||
|
|
||||||
// GetEnableOptimizations returns the EnableOptimizations field.
|
// GetEnableOptimizations returns the EnableOptimizations field.
|
||||||
GetEnableOptimizations() bool
|
GetEnableOptimizations() bool
|
||||||
|
// GetEnableProtoJSON returns the EnableProtoJSON field.
|
||||||
|
GetEnableProtoJSON() bool
|
||||||
|
// GetEnableEasyJSON returns the EnableEasyJSON field.
|
||||||
|
GetEnableEasyJSON() bool
|
||||||
|
|
||||||
// GetDisableBodyConsumptionOnUnmarshal returns the DisableBodyConsumptionOnUnmarshal field.
|
// GetDisableBodyConsumptionOnUnmarshal returns the DisableBodyConsumptionOnUnmarshal field.
|
||||||
GetDisableBodyConsumptionOnUnmarshal() bool
|
GetDisableBodyConsumptionOnUnmarshal() bool
|
||||||
// GetFireEmptyFormError returns the FireEmptyFormError field.
|
// GetFireEmptyFormError returns the FireEmptyFormError field.
|
||||||
|
|
|
@ -3046,6 +3046,9 @@ func (ctx *Context) ReadBody(ptr interface{}) error {
|
||||||
// writing the response. However, such behavior may not be supported
|
// writing the response. However, such behavior may not be supported
|
||||||
// by all HTTP/2 clients. Handlers should read before writing if
|
// by all HTTP/2 clients. Handlers should read before writing if
|
||||||
// possible to maximize compatibility.
|
// possible to maximize compatibility.
|
||||||
|
//
|
||||||
|
// It reports any write errors back to the caller, Application.SetContentErrorHandler does NOT apply here
|
||||||
|
// as this is a lower-level method which must be remain as it is.
|
||||||
func (ctx *Context) Write(rawBody []byte) (int, error) {
|
func (ctx *Context) Write(rawBody []byte) (int, error) {
|
||||||
return ctx.writer.Write(rawBody)
|
return ctx.writer.Write(rawBody)
|
||||||
}
|
}
|
||||||
|
@ -3757,38 +3760,20 @@ type ProtoMarshalOptions = protojson.MarshalOptions
|
||||||
// JSON contains the options for the JSON (Context's) Renderer.
|
// JSON contains the options for the JSON (Context's) Renderer.
|
||||||
type JSON struct {
|
type JSON struct {
|
||||||
// http-specific
|
// http-specific
|
||||||
StreamingJSON bool
|
StreamingJSON bool `yaml:"StreamingJSON"`
|
||||||
// content-specific
|
// content-specific
|
||||||
UnescapeHTML bool
|
UnescapeHTML bool `yaml:"UnescapeHTML"`
|
||||||
Indent string
|
Indent string `yaml:"Indent"`
|
||||||
Prefix string
|
Prefix string `yaml:"Prefix"`
|
||||||
ASCII bool // if true writes with unicode to ASCII content.
|
ASCII bool `yaml:"ASCII"` // if true writes with unicode to ASCII content.
|
||||||
Secure bool // if true then it prepends a "while(1);" when Go slice (to JSON Array) value.
|
Secure bool `yaml:"Secure"` // if true then it prepends a "while(1);" when Go slice (to JSON Array) value.
|
||||||
// proto.Message specific marshal options.
|
// proto.Message specific marshal options.
|
||||||
Proto ProtoMarshalOptions
|
Proto ProtoMarshalOptions `yaml:"ProtoMarshalOptions"`
|
||||||
|
|
||||||
// Optional context cancelation of encoder when Iris optimizations field is enabled.
|
|
||||||
// On JSON method this is automatically binded to the request context.
|
|
||||||
Context stdContext.Context
|
|
||||||
|
|
||||||
// ErrorHandler can be optionally registered to fire a customized
|
|
||||||
// error to the client on JSON write failures.
|
|
||||||
ErrorHandler ErrorHandler
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type (
|
// DefaultJSONOptions is the optional settings that are being used
|
||||||
// ErrorHandler describes a context error handler. As for today this is only used
|
// inside `Context.JSON`.
|
||||||
// to globally or per-party or per-route handle JSON writes error.
|
var DefaultJSONOptions = JSON{}
|
||||||
ErrorHandler interface {
|
|
||||||
HandleContextError(ctx *Context, err error)
|
|
||||||
}
|
|
||||||
// ErrorHandlerFunc a function shortcut for ErrorHandler interface.
|
|
||||||
ErrorHandlerFunc func(ctx *Context, err error)
|
|
||||||
)
|
|
||||||
|
|
||||||
func (h ErrorHandlerFunc) HandleContextError(ctx *Context, err error) {
|
|
||||||
h(ctx, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// IsDefault reports whether this JSON options structure holds the default values.
|
// IsDefault reports whether this JSON options structure holds the default values.
|
||||||
func (j *JSON) IsDefault() bool {
|
func (j *JSON) IsDefault() bool {
|
||||||
|
@ -3799,16 +3784,6 @@ func (j *JSON) IsDefault() bool {
|
||||||
j.ASCII == DefaultJSONOptions.ASCII &&
|
j.ASCII == DefaultJSONOptions.ASCII &&
|
||||||
j.Secure == DefaultJSONOptions.Secure &&
|
j.Secure == DefaultJSONOptions.Secure &&
|
||||||
j.Proto == DefaultJSONOptions.Proto
|
j.Proto == DefaultJSONOptions.Proto
|
||||||
// except context and error handler
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetContext returns the option's Context or the HTTP request's one.
|
|
||||||
func (j *JSON) GetContext(ctx *Context) stdContext.Context {
|
|
||||||
if j.Context == nil {
|
|
||||||
return ctx.request.Context()
|
|
||||||
}
|
|
||||||
|
|
||||||
return j.Context
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// JSONP contains the options for the JSONP (Context's) Renderer.
|
// JSONP contains the options for the JSONP (Context's) Renderer.
|
||||||
|
@ -3849,32 +3824,64 @@ var (
|
||||||
secureJSONPrefix = []byte("while(1);")
|
secureJSONPrefix = []byte("while(1);")
|
||||||
)
|
)
|
||||||
|
|
||||||
func handleJSONResponseValue(w io.Writer, v interface{}, options JSON) (bool, int, error) {
|
func (ctx *Context) handleSpecialJSONResponseValue(v interface{}, options *JSON) (bool, int, error) {
|
||||||
|
if ctx.app.ConfigurationReadOnly().GetEnableProtoJSON() {
|
||||||
if m, ok := v.(proto.Message); ok {
|
if m, ok := v.(proto.Message); ok {
|
||||||
result, err := options.Proto.Marshal(m)
|
protoJSON := ProtoMarshalOptions{}
|
||||||
|
if options != nil {
|
||||||
|
protoJSON = options.Proto
|
||||||
|
}
|
||||||
|
|
||||||
|
result, err := protoJSON.Marshal(m)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return true, 0, err
|
return true, 0, err
|
||||||
}
|
}
|
||||||
|
|
||||||
n, err := w.Write(result)
|
n, err := ctx.writer.Write(result)
|
||||||
return true, n, err
|
return true, n, err
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ctx.app.ConfigurationReadOnly().GetEnableEasyJSON() {
|
||||||
if easyObject, ok := v.(easyjson.Marshaler); ok {
|
if easyObject, ok := v.(easyjson.Marshaler); ok {
|
||||||
jw := jwriter.Writer{NoEscapeHTML: !options.UnescapeHTML}
|
noEscapeHTML := false
|
||||||
|
if options != nil {
|
||||||
|
noEscapeHTML = !options.UnescapeHTML
|
||||||
|
}
|
||||||
|
jw := jwriter.Writer{NoEscapeHTML: noEscapeHTML}
|
||||||
easyObject.MarshalEasyJSON(&jw)
|
easyObject.MarshalEasyJSON(&jw)
|
||||||
n, err := jw.DumpTo(w)
|
|
||||||
|
n, err := jw.DumpTo(ctx.writer)
|
||||||
return true, n, err
|
return true, n, err
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return false, 0, nil
|
return false, 0, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// WriteJSON marshals the given interface object and writes the JSON response to the 'writer'.
|
// WriteJSON marshals the given interface object and writes the JSON response to the 'writer'.
|
||||||
// Ignores StatusCode and StreamingJSON options.
|
func WriteJSON(ctx stdContext.Context, writer io.Writer, v interface{}, options *JSON, shouldOptimize bool) (int, error) {
|
||||||
func WriteJSON(writer io.Writer, v interface{}, options JSON, shouldOptimize bool) (int, error) {
|
if options.StreamingJSON {
|
||||||
if handled, n, err := handleJSONResponseValue(writer, v, options); handled {
|
var err error
|
||||||
return n, err
|
if shouldOptimize {
|
||||||
|
// jsoniterConfig := jsoniter.Config{
|
||||||
|
// EscapeHTML: !options.UnescapeHTML,
|
||||||
|
// IndentionStep: 4,
|
||||||
|
// }.Froze()
|
||||||
|
// enc := jsoniterConfig.NewEncoder(ctx.writer)
|
||||||
|
// err = enc.Encode(v)
|
||||||
|
enc := gojson.NewEncoder(writer)
|
||||||
|
enc.SetEscapeHTML(!options.UnescapeHTML)
|
||||||
|
enc.SetIndent(options.Prefix, options.Indent)
|
||||||
|
err = enc.EncodeContext(ctx, v)
|
||||||
|
} else {
|
||||||
|
enc := json.NewEncoder(writer)
|
||||||
|
enc.SetEscapeHTML(!options.UnescapeHTML)
|
||||||
|
enc.SetIndent(options.Prefix, options.Indent)
|
||||||
|
err = enc.Encode(v)
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0, err
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
@ -3899,8 +3906,8 @@ func WriteJSON(writer io.Writer, v interface{}, options JSON, shouldOptimize boo
|
||||||
} else {
|
} else {
|
||||||
if shouldOptimize {
|
if shouldOptimize {
|
||||||
// result, err = jsoniter.ConfigCompatibleWithStandardLibrary.Marshal
|
// result, err = jsoniter.ConfigCompatibleWithStandardLibrary.Marshal
|
||||||
if options.Context != nil {
|
if ctx != nil {
|
||||||
result, err = gojson.MarshalContext(options.Context, v)
|
result, err = gojson.MarshalContext(ctx, v)
|
||||||
} else {
|
} else {
|
||||||
result, err = gojson.Marshal(v)
|
result, err = gojson.Marshal(v)
|
||||||
}
|
}
|
||||||
|
@ -3939,7 +3946,7 @@ func WriteJSON(writer io.Writer, v interface{}, options JSON, shouldOptimize boo
|
||||||
if options.ASCII {
|
if options.ASCII {
|
||||||
if len(result) > 0 {
|
if len(result) > 0 {
|
||||||
buf := new(bytes.Buffer)
|
buf := new(bytes.Buffer)
|
||||||
for _, s := range bytesToString(result) {
|
for _, s := range string(result) {
|
||||||
char := string(s)
|
char := string(s)
|
||||||
if s >= 128 {
|
if s >= 128 {
|
||||||
char = fmt.Sprintf("\\u%04x", int64(s))
|
char = fmt.Sprintf("\\u%04x", int64(s))
|
||||||
|
@ -3967,80 +3974,71 @@ func stringToBytes(s string) []byte {
|
||||||
return *(*[]byte)(unsafe.Pointer(&s))
|
return *(*[]byte)(unsafe.Pointer(&s))
|
||||||
}
|
}
|
||||||
|
|
||||||
// DefaultJSONOptions is the optional settings that are being used
|
type (
|
||||||
// inside `ctx.JSON`.
|
// ErrorHandler describes a context error handler which applies on
|
||||||
var DefaultJSONOptions = JSON{}
|
// JSON, JSONP, Protobuf, MsgPack, XML, YAML and Markdown write errors.
|
||||||
|
|
||||||
const jsonOptionsContextKey = "iris.context.json_options"
|
|
||||||
|
|
||||||
// SetJSONOptions stores the given JSON options to the handler
|
|
||||||
// for any next Context.JSON calls. Note that the Context.JSON's
|
|
||||||
// variadic options have priority over these given options.
|
|
||||||
//
|
//
|
||||||
// Usage Example:
|
// An ErrorHandler can be registered once via Application.SetErrorHandler method to override the default behavior.
|
||||||
|
// The default behavior is to simply send status internal code error
|
||||||
|
// without a body back to the client.
|
||||||
|
ErrorHandler interface {
|
||||||
|
HandleContextError(ctx *Context, err error)
|
||||||
|
}
|
||||||
|
// ErrorHandlerFunc a function shortcut for ErrorHandler interface.
|
||||||
|
ErrorHandlerFunc func(ctx *Context, err error)
|
||||||
|
)
|
||||||
|
|
||||||
|
// HandleContextError completes the ErrorHandler interface.
|
||||||
|
func (h ErrorHandlerFunc) HandleContextError(ctx *Context, err error) {
|
||||||
|
h(ctx, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ctx *Context) handleContextError(err error) {
|
||||||
|
if errHandler := ctx.app.GetContextErrorHandler(); errHandler != nil {
|
||||||
|
errHandler.HandleContextError(ctx, err)
|
||||||
|
} else {
|
||||||
|
ctx.StatusCode(http.StatusInternalServerError)
|
||||||
|
}
|
||||||
|
|
||||||
|
// keep the error non nil so the caller has control over further actions.
|
||||||
|
}
|
||||||
|
|
||||||
|
// JSON marshals the given "v" value to JSON and writes the response to the client.
|
||||||
|
// Look the Configuration.EnableProtoJSON/EnableEasyJSON and EnableOptimizations too.
|
||||||
//
|
//
|
||||||
// type jsonErrorHandler struct{}
|
// It reports any JSON parser or write errors back to the caller.
|
||||||
// func (e *jsonErrorHandler) HandleContextError(ctx iris.Context, err error) {
|
// Look the Application.SetContextErrorHandler to override the
|
||||||
// errors.InvalidArgument.Err(ctx, err)
|
// default status code 500 with a custom error response.
|
||||||
// }
|
//
|
||||||
// ...
|
// It can, optionally, accept the JSON structure which may hold customizations over the
|
||||||
// errHandler := new(jsonErrorHandler)
|
// final JSON response but keep in mind that the caller should NOT modify that JSON options
|
||||||
// srv.Use(func(ctx iris.Context) {
|
// value in another goroutine while JSON method is still running.
|
||||||
// ctx.SetJSONOptions(iris.JSON{
|
|
||||||
// ErrorHandler: errHandler,
|
|
||||||
// })
|
|
||||||
// ctx.Next()
|
|
||||||
// })
|
|
||||||
func (ctx *Context) SetJSONOptions(opts JSON) {
|
|
||||||
ctx.values.Set(jsonOptionsContextKey, opts)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ctx *Context) getJSONOptions() (JSON, bool) {
|
|
||||||
if v := ctx.values.Get(jsonOptionsContextKey); v != nil {
|
|
||||||
opts, ok := v.(JSON)
|
|
||||||
return opts, ok
|
|
||||||
}
|
|
||||||
|
|
||||||
return DefaultJSONOptions, false
|
|
||||||
}
|
|
||||||
|
|
||||||
// JSON marshals the given interface object and writes the JSON response to the client.
|
|
||||||
// If the value is a compatible `proto.Message` one
|
|
||||||
// then it only uses the options.Proto settings to marshal.
|
|
||||||
func (ctx *Context) JSON(v interface{}, opts ...JSON) (n int, err error) {
|
func (ctx *Context) JSON(v interface{}, opts ...JSON) (n int, err error) {
|
||||||
if n, err = ctx.writeJSON(v, opts...); err != nil {
|
var options *JSON
|
||||||
if opts, ok := ctx.getJSONOptions(); ok {
|
if len(opts) > 0 {
|
||||||
opts.ErrorHandler.HandleContextError(ctx, err)
|
options = &opts[0]
|
||||||
} // keep the error so the caller has control over further actions.
|
}
|
||||||
|
|
||||||
|
if n, err = ctx.writeJSON(v, options); err != nil {
|
||||||
|
ctx.handleContextError(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ctx *Context) writeJSON(v interface{}, opts ...JSON) (n int, err error) {
|
func (ctx *Context) writeJSON(v interface{}, options *JSON) (int, error) {
|
||||||
ctx.ContentType(ContentJSONHeaderValue)
|
ctx.ContentType(ContentJSONHeaderValue)
|
||||||
shouldOptimize := ctx.shouldOptimize()
|
|
||||||
|
|
||||||
options := DefaultJSONOptions
|
// After content type given and before everything else, try handle proto or easyjson, no matter the performance mode.
|
||||||
optsLength := len(opts)
|
if handled, n, err := ctx.handleSpecialJSONResponseValue(v, options); handled {
|
||||||
if optsLength > 0 {
|
|
||||||
options = opts[0]
|
|
||||||
} else {
|
|
||||||
if opt, ok := ctx.getJSONOptions(); ok {
|
|
||||||
options = opt
|
|
||||||
if !options.IsDefault() { // keep the next branch valid when only the Context or/and ErrorHandler are modified.
|
|
||||||
optsLength = 1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if shouldOptimize && optsLength == 0 { // if no options given and optimizations are enabled.
|
|
||||||
// try handle proto or easyjson.
|
|
||||||
if handled, n, err := handleJSONResponseValue(ctx, v, options); handled {
|
|
||||||
return n, err
|
return n, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// as soon as possible, use the fast json marshaler with the http request context.
|
shouldOptimize := ctx.shouldOptimize()
|
||||||
|
if options == nil {
|
||||||
|
if shouldOptimize {
|
||||||
|
// If no options given and optimizations are enabled.
|
||||||
|
// write using the fast json marshaler with the http request context as soon as possible.
|
||||||
result, err := gojson.MarshalContext(ctx.request.Context(), v)
|
result, err := gojson.MarshalContext(ctx.request.Context(), v)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
|
@ -4049,41 +4047,11 @@ func (ctx *Context) writeJSON(v interface{}, opts ...JSON) (n int, err error) {
|
||||||
return ctx.Write(result)
|
return ctx.Write(result)
|
||||||
}
|
}
|
||||||
|
|
||||||
if options.StreamingJSON {
|
// Else if no options given neither optimizations are enabled, then safely read the already-initialized object.
|
||||||
if shouldOptimize {
|
options = &DefaultJSONOptions
|
||||||
// jsoniterConfig := jsoniter.Config{
|
|
||||||
// EscapeHTML: !options.UnescapeHTML,
|
|
||||||
// IndentionStep: 4,
|
|
||||||
// }.Froze()
|
|
||||||
// enc := jsoniterConfig.NewEncoder(ctx.writer)
|
|
||||||
// err = enc.Encode(v)
|
|
||||||
enc := gojson.NewEncoder(ctx.writer)
|
|
||||||
enc.SetEscapeHTML(!options.UnescapeHTML)
|
|
||||||
enc.SetIndent(options.Prefix, options.Indent)
|
|
||||||
err = enc.EncodeContext(options.GetContext(ctx), v)
|
|
||||||
} else {
|
|
||||||
enc := json.NewEncoder(ctx.writer)
|
|
||||||
enc.SetEscapeHTML(!options.UnescapeHTML)
|
|
||||||
enc.SetIndent(options.Prefix, options.Indent)
|
|
||||||
err = enc.Encode(v)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if err != nil {
|
return WriteJSON(ctx, ctx.writer, v, options, shouldOptimize)
|
||||||
ctx.app.Logger().Debugf("JSON: %v", err)
|
|
||||||
ctx.StatusCode(http.StatusInternalServerError) // it handles the fallback to normal mode here which also removes any compression headers.
|
|
||||||
return 0, err
|
|
||||||
}
|
|
||||||
return ctx.writer.Written(), err
|
|
||||||
}
|
|
||||||
|
|
||||||
n, err = WriteJSON(ctx.writer, v, options, shouldOptimize)
|
|
||||||
if err != nil {
|
|
||||||
ctx.app.Logger().Debugf("JSON: %v", err)
|
|
||||||
ctx.StatusCode(http.StatusInternalServerError)
|
|
||||||
return 0, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return n, err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var finishCallbackB = []byte(");")
|
var finishCallbackB = []byte(");")
|
||||||
|
@ -4134,24 +4102,23 @@ func WriteJSONP(writer io.Writer, v interface{}, options JSONP, optimize bool) (
|
||||||
// inside `ctx.JSONP`.
|
// inside `ctx.JSONP`.
|
||||||
var DefaultJSONPOptions = JSONP{}
|
var DefaultJSONPOptions = JSONP{}
|
||||||
|
|
||||||
// JSONP marshals the given interface object and writes the JSON response to the client.
|
// JSONP marshals the given "v" value to JSON and sends the response to the client.
|
||||||
func (ctx *Context) JSONP(v interface{}, opts ...JSONP) (int, error) {
|
//
|
||||||
|
// It reports any JSON parser or write errors back to the caller.
|
||||||
|
// Look the Application.SetContextErrorHandler to override the
|
||||||
|
// default status code 500 with a custom error response.
|
||||||
|
func (ctx *Context) JSONP(v interface{}, opts ...JSONP) (n int, err error) {
|
||||||
options := DefaultJSONPOptions
|
options := DefaultJSONPOptions
|
||||||
|
|
||||||
if len(opts) > 0 {
|
if len(opts) > 0 {
|
||||||
options = opts[0]
|
options = opts[0]
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx.ContentType(ContentJavascriptHeaderValue)
|
ctx.ContentType(ContentJavascriptHeaderValue)
|
||||||
|
if n, err = WriteJSONP(ctx.writer, v, options, ctx.shouldOptimize()); err != nil {
|
||||||
n, err := WriteJSONP(ctx.writer, v, options, ctx.shouldOptimize())
|
ctx.handleContextError(err)
|
||||||
if err != nil {
|
|
||||||
ctx.app.Logger().Debugf("JSONP: %v", err)
|
|
||||||
ctx.StatusCode(http.StatusInternalServerError)
|
|
||||||
return 0, err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return n, err
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
type xmlMapEntry struct {
|
type xmlMapEntry struct {
|
||||||
|
@ -4232,29 +4199,28 @@ var DefaultXMLOptions = XML{}
|
||||||
|
|
||||||
// XML marshals the given interface object and writes the XML response to the client.
|
// XML marshals the given interface object and writes the XML response to the client.
|
||||||
// To render maps as XML see the `XMLMap` package-level function.
|
// To render maps as XML see the `XMLMap` package-level function.
|
||||||
func (ctx *Context) XML(v interface{}, opts ...XML) (int, error) {
|
//
|
||||||
|
// It reports any XML parser or write errors back to the caller.
|
||||||
|
// Look the Application.SetContextErrorHandler to override the
|
||||||
|
// default status code 500 with a custom error response.
|
||||||
|
func (ctx *Context) XML(v interface{}, opts ...XML) (n int, err error) {
|
||||||
options := DefaultXMLOptions
|
options := DefaultXMLOptions
|
||||||
|
|
||||||
if len(opts) > 0 {
|
if len(opts) > 0 {
|
||||||
options = opts[0]
|
options = opts[0]
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx.ContentType(ContentXMLHeaderValue)
|
ctx.ContentType(ContentXMLHeaderValue)
|
||||||
|
if n, err = WriteXML(ctx.writer, v, options, ctx.shouldOptimize()); err != nil {
|
||||||
n, err := WriteXML(ctx.writer, v, options, ctx.shouldOptimize())
|
ctx.handleContextError(err)
|
||||||
if err != nil {
|
|
||||||
ctx.app.Logger().Debugf("XML: %v", err)
|
|
||||||
ctx.StatusCode(http.StatusInternalServerError)
|
|
||||||
return 0, err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return n, err
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Problem writes a JSON or XML problem response.
|
// Problem writes a JSON or XML problem response.
|
||||||
// Order of Problem fields are not always rendered the same.
|
// Order of Problem fields are not always rendered the same.
|
||||||
//
|
//
|
||||||
// Behaves exactly like `Context.JSON`
|
// Behaves exactly like the `Context.JSON` method
|
||||||
// but with default ProblemOptions.JSON indent of " " and
|
// but with default ProblemOptions.JSON indent of " " and
|
||||||
// a response content type of "application/problem+json" instead.
|
// a response content type of "application/problem+json" instead.
|
||||||
//
|
//
|
||||||
|
@ -4299,11 +4265,12 @@ func (ctx *Context) Problem(v interface{}, opts ...ProblemOptions) (int, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
// WriteMarkdown parses the markdown to html and writes these contents to the writer.
|
// WriteMarkdown parses the markdown to html and writes these contents to the writer.
|
||||||
func WriteMarkdown(writer io.Writer, markdownB []byte, options Markdown) (int, error) {
|
func WriteMarkdown(writer io.Writer, markdownB []byte, options Markdown) (n int, err error) {
|
||||||
buf := blackfriday.Run(markdownB)
|
buf := blackfriday.Run(markdownB)
|
||||||
if options.Sanitize {
|
if options.Sanitize {
|
||||||
buf = bluemonday.UGCPolicy().SanitizeBytes(buf)
|
buf = bluemonday.UGCPolicy().SanitizeBytes(buf)
|
||||||
}
|
}
|
||||||
|
|
||||||
return writer.Write(buf)
|
return writer.Write(buf)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4312,66 +4279,90 @@ func WriteMarkdown(writer io.Writer, markdownB []byte, options Markdown) (int, e
|
||||||
var DefaultMarkdownOptions = Markdown{}
|
var DefaultMarkdownOptions = Markdown{}
|
||||||
|
|
||||||
// Markdown parses the markdown to html and renders its result to the client.
|
// Markdown parses the markdown to html and renders its result to the client.
|
||||||
func (ctx *Context) Markdown(markdownB []byte, opts ...Markdown) (int, error) {
|
//
|
||||||
|
// It reports any Markdown parser or write errors back to the caller.
|
||||||
|
// Look the Application.SetContextErrorHandler to override the
|
||||||
|
// default status code 500 with a custom error response.
|
||||||
|
func (ctx *Context) Markdown(markdownB []byte, opts ...Markdown) (n int, err error) {
|
||||||
options := DefaultMarkdownOptions
|
options := DefaultMarkdownOptions
|
||||||
|
|
||||||
if len(opts) > 0 {
|
if len(opts) > 0 {
|
||||||
options = opts[0]
|
options = opts[0]
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx.ContentType(ContentHTMLHeaderValue)
|
ctx.ContentType(ContentHTMLHeaderValue)
|
||||||
|
if n, err = WriteMarkdown(ctx.writer, markdownB, options); err != nil {
|
||||||
|
ctx.handleContextError(err)
|
||||||
|
}
|
||||||
|
|
||||||
n, err := WriteMarkdown(ctx.writer, markdownB, options)
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// YAML marshals the given "v" value using the yaml marshaler and writes the result to the client.
|
||||||
|
//
|
||||||
|
// It reports any YAML parser or write errors back to the caller.
|
||||||
|
// Look the Application.SetContextErrorHandler to override the
|
||||||
|
// default status code 500 with a custom error response.
|
||||||
|
func (ctx *Context) YAML(v interface{}) (int, error) {
|
||||||
|
out, err := yaml.Marshal(v)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctx.app.Logger().Debugf("Markdown: %v", err)
|
ctx.handleContextError(err)
|
||||||
ctx.StatusCode(http.StatusInternalServerError)
|
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ctx.ContentType(ContentYAMLHeaderValue)
|
||||||
|
n, err := ctx.Write(out)
|
||||||
|
if err != nil {
|
||||||
|
ctx.handleContextError(err)
|
||||||
|
}
|
||||||
|
|
||||||
return n, err
|
return n, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// YAML marshals the "v" using the yaml marshaler
|
// TextYAML calls the Context.YAML method but with the text/yaml content type instead.
|
||||||
// and sends the result to the client.
|
|
||||||
func (ctx *Context) YAML(v interface{}) (int, error) {
|
|
||||||
out, err := yaml.Marshal(v)
|
|
||||||
if err != nil {
|
|
||||||
ctx.app.Logger().Debugf("YAML: %v", err)
|
|
||||||
ctx.StatusCode(http.StatusInternalServerError)
|
|
||||||
return 0, err
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx.ContentType(ContentYAMLHeaderValue)
|
|
||||||
return ctx.Write(out)
|
|
||||||
}
|
|
||||||
|
|
||||||
// TextYAML marshals the "v" using the yaml marshaler
|
|
||||||
// and renders to the client.
|
|
||||||
func (ctx *Context) TextYAML(v interface{}) (int, error) {
|
func (ctx *Context) TextYAML(v interface{}) (int, error) {
|
||||||
ctx.contentTypeOnce(ContentYAMLTextHeaderValue, "")
|
ctx.contentTypeOnce(ContentYAMLTextHeaderValue, "")
|
||||||
return ctx.YAML(v)
|
return ctx.YAML(v)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Protobuf parses the "v" of proto Message and renders its result to the client.
|
// Protobuf marshals the given "v" value of proto Message and writes its result to the client.
|
||||||
|
//
|
||||||
|
// It reports any protobuf parser or write errors back to the caller.
|
||||||
|
// Look the Application.SetContextErrorHandler to override the
|
||||||
|
// default status code 500 with a custom error response.
|
||||||
func (ctx *Context) Protobuf(v proto.Message) (int, error) {
|
func (ctx *Context) Protobuf(v proto.Message) (int, error) {
|
||||||
out, err := proto.Marshal(v)
|
out, err := proto.Marshal(v)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
ctx.handleContextError(err)
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx.ContentType(ContentProtobufHeaderValue)
|
ctx.ContentType(ContentProtobufHeaderValue)
|
||||||
return ctx.Write(out)
|
n, err := ctx.Write(out)
|
||||||
|
if err != nil {
|
||||||
|
ctx.handleContextError(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// MsgPack parses the "v" of msgpack format and renders its result to the client.
|
return n, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// MsgPack marshals the given "v" value of msgpack format and writes its result to the client.
|
||||||
|
//
|
||||||
|
// It reports any message pack or write errors back to the caller.
|
||||||
|
// Look the Application.SetContextErrorHandler to override the
|
||||||
|
// default status code 500 with a custom error response.
|
||||||
func (ctx *Context) MsgPack(v interface{}) (int, error) {
|
func (ctx *Context) MsgPack(v interface{}) (int, error) {
|
||||||
out, err := msgpack.Marshal(v)
|
out, err := msgpack.Marshal(v)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, err
|
ctx.handleContextError(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx.ContentType(ContentMsgPackHeaderValue)
|
ctx.ContentType(ContentMsgPackHeaderValue)
|
||||||
return ctx.Write(out)
|
n, err := ctx.Write(out)
|
||||||
|
if err != nil {
|
||||||
|
ctx.handleContextError(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return n, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// +-----------------------------------------------------------------------+
|
// +-----------------------------------------------------------------------+
|
||||||
|
|
24
iris.go
24
iris.go
|
@ -59,6 +59,8 @@ type Application struct {
|
||||||
*router.Router
|
*router.Router
|
||||||
router.HTTPErrorHandler // if Router is Downgraded this is nil.
|
router.HTTPErrorHandler // if Router is Downgraded this is nil.
|
||||||
ContextPool *context.Pool
|
ContextPool *context.Pool
|
||||||
|
// See SetContextErrorHandler, defaults to nil.
|
||||||
|
contextErrorHandler context.ErrorHandler
|
||||||
|
|
||||||
// config contains the configuration fields
|
// config contains the configuration fields
|
||||||
// all fields defaults to something that is working, developers don't have to set it.
|
// all fields defaults to something that is working, developers don't have to set it.
|
||||||
|
@ -429,6 +431,28 @@ func (app *Application) GetContextPool() *context.Pool {
|
||||||
return app.ContextPool
|
return app.ContextPool
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SetContextErrorHandler can optionally register a handler to handle
|
||||||
|
// and fire a customized error body to the client on JSON write failures.
|
||||||
|
//
|
||||||
|
// ExampleCode:
|
||||||
|
//
|
||||||
|
// type contextErrorHandler struct{}
|
||||||
|
// func (e *contextErrorHandler) HandleContextError(ctx iris.Context, err error) {
|
||||||
|
// errors.InvalidArgument.Err(ctx, err)
|
||||||
|
// }
|
||||||
|
// ...
|
||||||
|
// app.SetContextErrorHandler(new(contextErrorHandler))
|
||||||
|
func (app *Application) SetContextErrorHandler(errHandler context.ErrorHandler) *Application {
|
||||||
|
app.contextErrorHandler = errHandler
|
||||||
|
return app
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetContextErrorHandler returns the handler which handles errors
|
||||||
|
// on JSON write failures.
|
||||||
|
func (app *Application) GetContextErrorHandler() context.ErrorHandler {
|
||||||
|
return app.contextErrorHandler
|
||||||
|
}
|
||||||
|
|
||||||
// ConfigureHost accepts one or more `host#Configuration`, these configurators functions
|
// ConfigureHost accepts one or more `host#Configuration`, these configurators functions
|
||||||
// can access the host created by `app.Run` or `app.Listen`,
|
// can access the host created by `app.Run` or `app.Listen`,
|
||||||
// they're being executed when application is ready to being served to the public.
|
// they're being executed when application is ready to being served to the public.
|
||||||
|
|
Loading…
Reference in New Issue
Block a user