Skip to content

Commit

Permalink
add context#StatusCodeNotSuccessful for customize even the most custo…
Browse files Browse the repository at this point in the history
…mized clients that are not compatible with the standards and fix the `SPA` if static file serve handlers are passed as its `AssetHandler` as reported at the chat.iris-go.com
  • Loading branch information
kataras committed Jan 31, 2018
1 parent 0fbf1d4 commit c56b7a3
Show file tree
Hide file tree
Showing 12 changed files with 213 additions and 164 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ func newApp() *iris.Application {
})

// or just serve index.html as it is:
// app.Get("/", func(ctx iris.Context) {
// app.Get("/{f:path}", func(ctx iris.Context) {
// ctx.ServeFile("index.html", false)
// })

Expand Down
3 changes: 2 additions & 1 deletion _examples/routing/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -611,7 +611,8 @@ func main(){
app := iris.New()
app.OnErrorCode(iris.StatusNotFound, notFound)
app.OnErrorCode(iris.StatusInternalServerError, internalServerError)
// to register a handler for all status codes >=400:
// to register a handler for all "error" status codes(context.StatusCodeNotSuccessful)
// defaults to < 200 || >= 400:
// app.OnAnyErrorCode(handler)
app.Get("/", index)
app.Run(iris.Addr(":8080"))
Expand Down
3 changes: 2 additions & 1 deletion _examples/structuring/bootstrap/bootstrap/bootstrapper.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,8 @@ func (b *Bootstrapper) SetupWebsockets(endpoint string, onConnection websocket.C
})
}

// SetupErrorHandlers prepares the http error handlers (>=400).
// SetupErrorHandlers prepares the http error handlers
// `(context.StatusCodeNotSuccessful`, which defaults to < 200 || >= 400 but you can change it).
func (b *Bootstrapper) SetupErrorHandlers() {
b.OnAnyErrorCode(func(ctx iris.Context) {
err := iris.Map{
Expand Down
7 changes: 4 additions & 3 deletions configuration.go
Original file line number Diff line number Diff line change
Expand Up @@ -460,13 +460,14 @@ type Configuration struct {
DisableBodyConsumptionOnUnmarshal bool `json:"disableBodyConsumptionOnUnmarshal,omitempty" yaml:"DisableBodyConsumptionOnUnmarshal" toml:"DisableBodyConsumptionOnUnmarshal"`

// DisableAutoFireStatusCode if true then it turns off the http error status code handler automatic execution
// from "context.StatusCode(>=400)" and instead app should manually call the "context.FireStatusCode(>=400)".
// from (`context.StatusCodeNotSuccessful`, defaults to < 200 || >= 400).
// If that is false then for a direct error firing, then call the "context#FireStatusCode(statusCode)" manually.
//
// By-default a custom http error handler will be fired when "context.StatusCode(code)" called,
// code should be >=400 in order to be received as an "http error handler".
// code should be equal with the result of the the `context.StatusCodeNotSuccessful` in order to be received as an "http error handler".
//
// Developer may want this option to setted as true in order to manually call the
// error handlers when needed via "context.FireStatusCode(>=400)".
// error handlers when needed via "context#FireStatusCode(< 200 || >= 400)".
// HTTP Custom error handlers are being registered via app.OnErrorCode(code, handler)".
//
// Defaults to false.
Expand Down
17 changes: 16 additions & 1 deletion context/context.go
Original file line number Diff line number Diff line change
Expand Up @@ -1042,14 +1042,29 @@ func (ctx *context) BeginRequest(w http.ResponseWriter, r *http.Request) {
ctx.writer.BeginResponse(w)
}

// StatusCodeNotSuccessful defines if a specific "statusCode" is not
// a valid status code for a successful response.
// It defaults to < 200 || >= 400
//
// Read more at `iris#DisableAutoFireStatusCode`, `iris/core/router#ErrorCodeHandler`
// and `iris/core/router#OnAnyErrorCode` for relative information.
//
// Do NOT change it.
//
// It's exported for extreme situations--special needs only, when the Iris server and the client
// is not following the RFC: https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html
var StatusCodeNotSuccessful = func(statusCode int) bool {
return statusCode < 200 || statusCode >= 400
}

// EndRequest is executing once after a response to the request was sent and this context is useless or released.
//
// To follow the iris' flow, developer should:
// 1. flush the response writer's result
// 2. release the response writer
// and any other optional steps, depends on dev's application type.
func (ctx *context) EndRequest() {
if ctx.GetStatusCode() >= 400 &&
if StatusCodeNotSuccessful(ctx.GetStatusCode()) &&
!ctx.Application().ConfigurationReadOnly().GetDisableAutoFireStatusCode() {
// author's note:
// if recording, the error handler can handle
Expand Down
2 changes: 1 addition & 1 deletion context/response_recorder.go
Original file line number Diff line number Diff line change
Expand Up @@ -189,7 +189,7 @@ func (w *ResponseRecorder) WriteTo(res ResponseWriter) {

if to, ok := res.(*ResponseRecorder); ok {

// set the status code, to is first ( probably an error >=400)
// set the status code, to is first ( probably an error? (context.StatusCodeNotSuccessful, defaults to < 200 || >= 400).
if statusCode := w.ResponseWriter.StatusCode(); statusCode == defaultStatusCode {
to.WriteHeader(statusCode)
}
Expand Down
2 changes: 1 addition & 1 deletion context/transaction.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ func (err TransactionErrResult) Error() string {

// IsFailure returns true if this is an actual error
func (err TransactionErrResult) IsFailure() bool {
return err.StatusCode >= 400
return StatusCodeNotSuccessful(err.StatusCode)
}

// NewTransactionErrResult returns a new transaction result with the given error message,
Expand Down
69 changes: 10 additions & 59 deletions core/router/api_builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -686,24 +686,14 @@ func (api *APIBuilder) StaticWeb(requestPath string, systemPath string) *Route {

handler := func(ctx context.Context) {
h(ctx)
// if ctx.GetStatusCode() >= 200 && ctx.GetStatusCode() < 400 {
// // re-check the content type here for any case,
// // although the new code does it automatically but it's good to have it here.
// if _, exists := ctx.ResponseWriter().Header()["Content-Type"]; !exists {
// if fname := ctx.Params().Get(paramName); fname != "" {
// cType := TypeByFilename(fname)
// ctx.ContentType(cType)
// }
// }
// }
}

requestPath = joinPath(requestPath, WildcardParam(paramName))
return api.registerResourceRoute(requestPath, handler)
}

// OnErrorCode registers an error http status code
// based on the "statusCode" >= 400.
// based on the "statusCode" < 200 || >= 400 (came from `context.StatusCodeNotSuccessful`).
// The handler is being wrapepd by a generic
// handler which will try to reset
// the body if recorder was enabled
Expand All @@ -718,55 +708,16 @@ func (api *APIBuilder) OnErrorCode(statusCode int, handlers ...context.Handler)
}

// OnAnyErrorCode registers a handler which called when error status code written.
// Same as `OnErrorCode` but registers all http error codes.
// See: http://www.iana.org/assignments/http-status-codes/http-status-codes.xhtml
// Same as `OnErrorCode` but registers all http error codes based on the `context.StatusCodeNotSuccessful`
// which defaults to < 200 || >= 400 for an error code, any previos error code will be overriden,
// so call it first if you want to use any custom handler for a specific error status code.
//
// Read more at: http://www.iana.org/assignments/http-status-codes/http-status-codes.xhtml
func (api *APIBuilder) OnAnyErrorCode(handlers ...context.Handler) {
// we could register all >=400 and <=511 but this way
// could override custom status codes that iris developers can register for their
// web apps whenever needed.
// There fore these are the hard coded http error statuses:
var errStatusCodes = []int{
http.StatusBadRequest,
http.StatusUnauthorized,
http.StatusPaymentRequired,
http.StatusForbidden,
http.StatusNotFound,
http.StatusMethodNotAllowed,
http.StatusNotAcceptable,
http.StatusProxyAuthRequired,
http.StatusRequestTimeout,
http.StatusConflict,
http.StatusGone,
http.StatusLengthRequired,
http.StatusPreconditionFailed,
http.StatusRequestEntityTooLarge,
http.StatusRequestURITooLong,
http.StatusUnsupportedMediaType,
http.StatusRequestedRangeNotSatisfiable,
http.StatusExpectationFailed,
http.StatusTeapot,
http.StatusUnprocessableEntity,
http.StatusLocked,
http.StatusFailedDependency,
http.StatusUpgradeRequired,
http.StatusPreconditionRequired,
http.StatusTooManyRequests,
http.StatusRequestHeaderFieldsTooLarge,
http.StatusUnavailableForLegalReasons,
http.StatusInternalServerError,
http.StatusNotImplemented,
http.StatusBadGateway,
http.StatusServiceUnavailable,
http.StatusGatewayTimeout,
http.StatusHTTPVersionNotSupported,
http.StatusVariantAlsoNegotiates,
http.StatusInsufficientStorage,
http.StatusLoopDetected,
http.StatusNotExtended,
http.StatusNetworkAuthenticationRequired}

for _, statusCode := range errStatusCodes {
api.OnErrorCode(statusCode, handlers...)
for code := 100; code <= 511; code++ {
if context.StatusCodeNotSuccessful(code) {
api.OnErrorCode(code, handlers...)
}
}
}

Expand Down
2 changes: 1 addition & 1 deletion core/router/fs.go
Original file line number Diff line number Diff line change
Expand Up @@ -254,7 +254,7 @@ func (w *fsHandler) Build() context.Handler {
gzipEnabled)

// check for any http errors after the file handler executed
if prevStatusCode >= 400 { // error found (404 or 400 or 500 usually)
if context.StatusCodeNotSuccessful(prevStatusCode) { // error found (404 or 400 or 500 usually)
if writer, ok := ctx.ResponseWriter().(*context.GzipResponseWriter); ok && writer != nil {
writer.ResetBody()
writer.Disable()
Expand Down
91 changes: 0 additions & 91 deletions core/router/router_spa_wrapper.go

This file was deleted.

Loading

0 comments on commit c56b7a3

Please sign in to comment.