mirror of
https://github.com/kataras/iris.git
synced 2025-03-15 03:56:27 +01:00
Former-commit-id: 2b48b9b912e9eb8f5f2c6d413907dbfdae857e08
This commit is contained in:
parent
272566950d
commit
0f907a3dae
|
@ -798,7 +798,9 @@ func (api *APIBuilder) Favicon(favPath string, requestPath ...string) *Route {
|
||||||
//
|
//
|
||||||
// As a special case, the returned file server redirects any request
|
// As a special case, the returned file server redirects any request
|
||||||
// ending in "/index.html" to the same path, without the final
|
// ending in "/index.html" to the same path, without the final
|
||||||
// "index.html".
|
// "/index.html", if `index.html` should be served then register a
|
||||||
|
// new route for it, i.e
|
||||||
|
// `app.Get("/static", func(ctx iris.Context){ ctx.ServeFile("./static/index.html", false) })`.
|
||||||
//
|
//
|
||||||
// StaticWeb calls the `StripPrefix(fullpath, NewStaticHandlerBuilder(systemPath).Listing(false).Build())`.
|
// StaticWeb calls the `StripPrefix(fullpath, NewStaticHandlerBuilder(systemPath).Listing(false).Build())`.
|
||||||
//
|
//
|
||||||
|
|
|
@ -127,7 +127,7 @@ func StaticEmbeddedHandler(vdir string, assetFn func(name string) ([]byte, error
|
||||||
// fileserver := iris.StaticHandler("./static_files", false, false)
|
// fileserver := iris.StaticHandler("./static_files", false, false)
|
||||||
// h := router.StripPrefix("/static", fileserver)
|
// h := router.StripPrefix("/static", fileserver)
|
||||||
// /* http://mydomain.com/static/css/style.css */
|
// /* http://mydomain.com/static/css/style.css */
|
||||||
// app.Get("/static", h)
|
// app.Get("/static/{file:path}", h)
|
||||||
// ...
|
// ...
|
||||||
//
|
//
|
||||||
func StaticHandler(systemPath string, showList bool, gzip bool) context.Handler {
|
func StaticHandler(systemPath string, showList bool, gzip bool) context.Handler {
|
||||||
|
|
|
@ -82,7 +82,7 @@ func (h *routerHandler) Build(provider RoutesProvider) error {
|
||||||
registeredRoutes := provider.GetRoutes()
|
registeredRoutes := provider.GetRoutes()
|
||||||
h.trees = h.trees[0:0] // reset, inneed when rebuilding.
|
h.trees = h.trees[0:0] // reset, inneed when rebuilding.
|
||||||
|
|
||||||
// sort, subdomains goes first.
|
// sort, subdomains go first.
|
||||||
sort.Slice(registeredRoutes, func(i, j int) bool {
|
sort.Slice(registeredRoutes, func(i, j int) bool {
|
||||||
first, second := registeredRoutes[i], registeredRoutes[j]
|
first, second := registeredRoutes[i], registeredRoutes[j]
|
||||||
lsub1 := len(first.Subdomain)
|
lsub1 := len(first.Subdomain)
|
||||||
|
|
|
@ -28,7 +28,8 @@ type Route struct {
|
||||||
// temp storage, they're appended to the Handlers on build.
|
// temp storage, they're appended to the Handlers on build.
|
||||||
// Execution happens after Begin and main Handler(s), can be empty.
|
// Execution happens after Begin and main Handler(s), can be empty.
|
||||||
doneHandlers context.Handlers
|
doneHandlers context.Handlers
|
||||||
Path string `json:"path"` // "/api/user/:id"
|
|
||||||
|
Path string `json:"path"` // "/api/user/{id:uint64}"
|
||||||
// FormattedPath all dynamic named parameters (if any) replaced with %v,
|
// FormattedPath all dynamic named parameters (if any) replaced with %v,
|
||||||
// used by Application to validate param values of a Route based on its name.
|
// used by Application to validate param values of a Route based on its name.
|
||||||
FormattedPath string `json:"formattedPath"`
|
FormattedPath string `json:"formattedPath"`
|
||||||
|
|
|
@ -73,6 +73,7 @@ func IndirectValue(v reflect.Value) reflect.Value {
|
||||||
if k := v.Kind(); k == reflect.Ptr { //|| k == reflect.Interface {
|
if k := v.Kind(); k == reflect.Ptr { //|| k == reflect.Interface {
|
||||||
return v.Elem()
|
return v.Elem()
|
||||||
}
|
}
|
||||||
|
|
||||||
return v
|
return v
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -106,6 +107,17 @@ func IndirectType(typ reflect.Type) reflect.Type {
|
||||||
return typ
|
return typ
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// IsNil same as `reflect.IsNil` but a bit safer to use, returns false if not a correct type.
|
||||||
|
func IsNil(v reflect.Value) bool {
|
||||||
|
k := v.Kind()
|
||||||
|
switch k {
|
||||||
|
case reflect.Chan, reflect.Func, reflect.Map, reflect.Ptr, reflect.UnsafePointer, reflect.Interface, reflect.Slice:
|
||||||
|
return v.IsNil()
|
||||||
|
default:
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func goodVal(v reflect.Value) bool {
|
func goodVal(v reflect.Value) bool {
|
||||||
switch v.Kind() {
|
switch v.Kind() {
|
||||||
case reflect.Chan, reflect.Func, reflect.Map, reflect.Ptr, reflect.Interface, reflect.Slice:
|
case reflect.Chan, reflect.Func, reflect.Map, reflect.Ptr, reflect.Interface, reflect.Slice:
|
||||||
|
|
|
@ -211,7 +211,6 @@ func DispatchFuncResult(ctx context.Context, errorHandler ErrorHandler, values [
|
||||||
)
|
)
|
||||||
|
|
||||||
for _, v := range values {
|
for _, v := range values {
|
||||||
|
|
||||||
// order of these checks matters
|
// order of these checks matters
|
||||||
// for example, first we need to check for status code,
|
// for example, first we need to check for status code,
|
||||||
// secondly the string (for content type and content)...
|
// secondly the string (for content type and content)...
|
||||||
|
@ -310,7 +309,10 @@ func DispatchFuncResult(ctx context.Context, errorHandler ErrorHandler, values [
|
||||||
// it's raw content, get the latest
|
// it's raw content, get the latest
|
||||||
content = value
|
content = value
|
||||||
case compatibleErr:
|
case compatibleErr:
|
||||||
if value != nil { // it's always not nil but keep it here.
|
if value == nil || di.IsNil(v) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
if errorHandler != nil {
|
if errorHandler != nil {
|
||||||
errorHandler.HandleError(ctx, value)
|
errorHandler.HandleError(ctx, value)
|
||||||
break
|
break
|
||||||
|
@ -323,14 +325,30 @@ func DispatchFuncResult(ctx context.Context, errorHandler ErrorHandler, values [
|
||||||
break // break on first error, error should be in the end but we
|
break // break on first error, error should be in the end but we
|
||||||
// need to know break the dispatcher if any error.
|
// need to know break the dispatcher if any error.
|
||||||
// at the end; we don't want to write anything to the response if error is not nil.
|
// at the end; we don't want to write anything to the response if error is not nil.
|
||||||
}
|
|
||||||
default:
|
default:
|
||||||
// else it's a custom struct or a dispatcher, we'll decide later
|
// else it's a custom struct or a dispatcher, we'll decide later
|
||||||
// because content type and status code matters
|
// because content type and status code matters
|
||||||
// do that check in order to be able to correctly dispatch:
|
// do that check in order to be able to correctly dispatch:
|
||||||
// (customStruct, error) -> customStruct filled and error is nil
|
// (customStruct, error) -> customStruct filled and error is nil
|
||||||
if custom == nil && f != nil {
|
if custom == nil {
|
||||||
custom = f
|
// if it's a pointer to struct/map.
|
||||||
|
|
||||||
|
if di.IsNil(v) {
|
||||||
|
// if just a ptr to struct with no content type given
|
||||||
|
// then try to get the previous response writer's content type,
|
||||||
|
// and if that is empty too then force-it to application/json
|
||||||
|
// as the default content type we use for structs/maps.
|
||||||
|
contentType = ctx.GetContentType()
|
||||||
|
if contentType == "" {
|
||||||
|
contentType = context.ContentJSONHeaderValue
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if value != nil {
|
||||||
|
custom = value // content type will be take care later on.
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -70,7 +70,7 @@ func GetCustomStructWithContentType() (testCustomStruct, string) {
|
||||||
return testCustomStruct{"Iris", 2}, "text/xml"
|
return testCustomStruct{"Iris", 2}, "text/xml"
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetCustomStructWithError(ctx iris.Context) (s testCustomStruct, err error) {
|
func GetCustomStructWithError(ctx context.Context) (s testCustomStruct, err error) {
|
||||||
s = testCustomStruct{"Iris", 2}
|
s = testCustomStruct{"Iris", 2}
|
||||||
if ctx.URLParamExists("err") {
|
if ctx.URLParamExists("err") {
|
||||||
err = errors.New("omit return of testCustomStruct and fire error")
|
err = errors.New("omit return of testCustomStruct and fire error")
|
||||||
|
@ -86,7 +86,7 @@ type err struct {
|
||||||
Message string `json:"message"`
|
Message string `json:"message"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e err) Dispatch(ctx iris.Context) {
|
func (e err) Dispatch(ctx context.Context) {
|
||||||
// write the status code based on the err's StatusCode.
|
// write the status code based on the err's StatusCode.
|
||||||
ctx.StatusCode(e.Status)
|
ctx.StatusCode(e.Status)
|
||||||
// send to the client the whole object as json
|
// send to the client the whole object as json
|
||||||
|
@ -97,6 +97,22 @@ func GetCustomErrorAsDispatcher() err {
|
||||||
return err{iris.StatusBadRequest, "this is my error as json"}
|
return err{iris.StatusBadRequest, "this is my error as json"}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func GetCustomTypedNilEmptyResponse() iris.Map {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetCustomTypedPtrNilEmptyResponse() *iris.Map {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetCustomMapNilEmptyResponse() map[string]interface{} {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetCustomPtrStructNilEmptyResponse() *testCustomStruct {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func TestFuncResult(t *testing.T) {
|
func TestFuncResult(t *testing.T) {
|
||||||
app := iris.New()
|
app := iris.New()
|
||||||
h := New()
|
h := New()
|
||||||
|
@ -120,6 +136,11 @@ func TestFuncResult(t *testing.T) {
|
||||||
app.Get("/custom/struct/with/error", h.Handler(GetCustomStructWithError))
|
app.Get("/custom/struct/with/error", h.Handler(GetCustomStructWithError))
|
||||||
app.Get("/custom/error/as/dispatcher", h.Handler(GetCustomErrorAsDispatcher))
|
app.Get("/custom/error/as/dispatcher", h.Handler(GetCustomErrorAsDispatcher))
|
||||||
|
|
||||||
|
app.Get("/custom/nil/typed", h.Handler(GetCustomTypedNilEmptyResponse))
|
||||||
|
app.Get("/custom/nil/typed/ptr", h.Handler(GetCustomTypedPtrNilEmptyResponse))
|
||||||
|
app.Get("/custom/nil/map", h.Handler(GetCustomMapNilEmptyResponse))
|
||||||
|
app.Get("/custom/nil/struct", h.Handler(GetCustomPtrStructNilEmptyResponse))
|
||||||
|
|
||||||
e := httptest.New(t, app)
|
e := httptest.New(t, app)
|
||||||
|
|
||||||
e.GET("/text").Expect().Status(iris.StatusOK).
|
e.GET("/text").Expect().Status(iris.StatusOK).
|
||||||
|
@ -172,4 +193,14 @@ func TestFuncResult(t *testing.T) {
|
||||||
// the content should be not JSON it should be the status code's text
|
// the content should be not JSON it should be the status code's text
|
||||||
// it will fire the error's text
|
// it will fire the error's text
|
||||||
JSON().Equal(err{iris.StatusBadRequest, "this is my error as json"})
|
JSON().Equal(err{iris.StatusBadRequest, "this is my error as json"})
|
||||||
|
|
||||||
|
// its result is nil should give an empty response but content-type is set correctly.
|
||||||
|
e.GET("/custom/nil/typed").Expect().
|
||||||
|
Status(iris.StatusOK).ContentType(context.ContentJSONHeaderValue).Body().Empty()
|
||||||
|
e.GET("/custom/nil/typed/ptr").Expect().
|
||||||
|
Status(iris.StatusOK).ContentType(context.ContentJSONHeaderValue).Body().Empty()
|
||||||
|
e.GET("/custom/nil/map").Expect().
|
||||||
|
Status(iris.StatusOK).ContentType(context.ContentJSONHeaderValue).Body().Empty()
|
||||||
|
e.GET("/custom/nil/struct").Expect().
|
||||||
|
Status(iris.StatusOK).ContentType(context.ContentJSONHeaderValue).Body().Empty()
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user