2020-12-30 13:18:43 +08:00
|
|
|
// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
|
2019-08-03 15:54:12 +08:00
|
|
|
//
|
|
|
|
// This Source Code Form is subject to the terms of the MIT License.
|
|
|
|
// If a copy of the MIT was not distributed with this file,
|
|
|
|
// You can obtain one at https://github.com/gogf/gf.
|
|
|
|
|
|
|
|
package ghttp
|
|
|
|
|
2019-09-14 22:53:28 +08:00
|
|
|
import (
|
2020-04-28 15:04:07 +08:00
|
|
|
"github.com/gogf/gf/errors/gerror"
|
2019-09-14 22:53:28 +08:00
|
|
|
"net/http"
|
|
|
|
"reflect"
|
|
|
|
|
|
|
|
"github.com/gogf/gf/util/gutil"
|
|
|
|
)
|
2019-08-03 15:54:12 +08:00
|
|
|
|
2021-01-19 19:18:39 +08:00
|
|
|
// middleware is the plugin for request workflow management.
|
|
|
|
type middleware struct {
|
2019-12-04 10:03:03 +08:00
|
|
|
served bool // Is the request served, which is used for checking response status 404.
|
|
|
|
request *Request // The request object pointer.
|
|
|
|
handlerIndex int // Index number for executing sequence purpose for handler items.
|
|
|
|
handlerMDIndex int // Index number for executing sequence purpose for bound middleware of handler item.
|
2019-08-03 15:54:12 +08:00
|
|
|
}
|
|
|
|
|
2019-10-09 15:26:50 +08:00
|
|
|
// Next calls the next workflow handler.
|
2020-04-06 22:31:45 +08:00
|
|
|
// It's an important function controlling the workflow of the server request execution.
|
2021-01-19 19:18:39 +08:00
|
|
|
func (m *middleware) Next() {
|
2019-12-04 10:03:03 +08:00
|
|
|
var item *handlerParsedItem
|
|
|
|
var loop = true
|
2019-09-14 22:53:28 +08:00
|
|
|
for loop {
|
2019-10-09 15:26:50 +08:00
|
|
|
// Check whether the request is exited.
|
2019-12-04 10:03:03 +08:00
|
|
|
if m.request.IsExited() || m.handlerIndex >= len(m.request.handlers) {
|
2019-10-09 15:26:50 +08:00
|
|
|
break
|
2019-08-03 15:54:12 +08:00
|
|
|
}
|
2019-12-04 10:03:03 +08:00
|
|
|
item = m.request.handlers[m.handlerIndex]
|
2019-10-09 15:26:50 +08:00
|
|
|
// Filter the HOOK handlers, which are designed to be called in another standalone procedure.
|
2021-07-19 20:06:44 +08:00
|
|
|
if item.Handler.Type == handlerTypeHook {
|
2019-12-04 10:03:03 +08:00
|
|
|
m.handlerIndex++
|
2019-08-03 15:54:12 +08:00
|
|
|
continue
|
|
|
|
}
|
2019-12-03 17:16:52 +08:00
|
|
|
// Current router switching.
|
2021-07-19 20:06:44 +08:00
|
|
|
m.request.Router = item.Handler.Router
|
2019-10-09 15:26:50 +08:00
|
|
|
|
2020-02-16 22:39:12 +08:00
|
|
|
// Router values switching.
|
2021-07-19 20:06:44 +08:00
|
|
|
m.request.routerMap = item.Values
|
2020-02-16 22:39:12 +08:00
|
|
|
|
2019-09-14 22:53:28 +08:00
|
|
|
gutil.TryCatch(func() {
|
2019-12-04 10:03:03 +08:00
|
|
|
// Execute bound middleware array of the item if it's not empty.
|
2021-07-19 20:06:44 +08:00
|
|
|
if m.handlerMDIndex < len(item.Handler.Middleware) {
|
|
|
|
md := item.Handler.Middleware[m.handlerMDIndex]
|
2019-12-04 10:03:03 +08:00
|
|
|
m.handlerMDIndex++
|
|
|
|
niceCallFunc(func() {
|
|
|
|
md(m.request)
|
|
|
|
})
|
|
|
|
loop = false
|
|
|
|
return
|
|
|
|
}
|
|
|
|
m.handlerIndex++
|
|
|
|
|
2021-07-19 20:06:44 +08:00
|
|
|
switch item.Handler.Type {
|
2019-12-04 10:03:03 +08:00
|
|
|
// Service object.
|
2020-12-14 13:26:48 +08:00
|
|
|
case handlerTypeObject:
|
2019-09-14 22:53:28 +08:00
|
|
|
m.served = true
|
|
|
|
if m.request.IsExited() {
|
|
|
|
break
|
|
|
|
}
|
2021-07-19 20:06:44 +08:00
|
|
|
if item.Handler.InitFunc != nil {
|
2019-09-14 22:53:28 +08:00
|
|
|
niceCallFunc(func() {
|
2021-07-19 20:06:44 +08:00
|
|
|
item.Handler.InitFunc(m.request)
|
2019-09-14 22:53:28 +08:00
|
|
|
})
|
|
|
|
}
|
|
|
|
if !m.request.IsExited() {
|
2021-07-19 20:06:44 +08:00
|
|
|
m.callHandlerFunc(item.Handler.Info)
|
2019-09-14 22:53:28 +08:00
|
|
|
}
|
2021-07-19 20:06:44 +08:00
|
|
|
if !m.request.IsExited() && item.Handler.ShutFunc != nil {
|
2019-09-14 22:53:28 +08:00
|
|
|
niceCallFunc(func() {
|
2021-07-19 20:06:44 +08:00
|
|
|
item.Handler.ShutFunc(m.request)
|
2019-09-14 22:53:28 +08:00
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2019-12-04 10:03:03 +08:00
|
|
|
// Service handler.
|
2020-12-14 13:26:48 +08:00
|
|
|
case handlerTypeHandler:
|
2019-09-14 22:53:28 +08:00
|
|
|
m.served = true
|
|
|
|
if m.request.IsExited() {
|
|
|
|
break
|
|
|
|
}
|
2019-08-03 15:54:12 +08:00
|
|
|
niceCallFunc(func() {
|
2021-07-19 20:06:44 +08:00
|
|
|
m.callHandlerFunc(item.Handler.Info)
|
2019-08-03 15:54:12 +08:00
|
|
|
})
|
2019-09-14 22:53:28 +08:00
|
|
|
|
2019-12-04 10:03:03 +08:00
|
|
|
// Global middleware array.
|
2020-12-14 13:26:48 +08:00
|
|
|
case handlerTypeMiddleware:
|
2019-08-03 15:54:12 +08:00
|
|
|
niceCallFunc(func() {
|
2021-07-19 20:06:44 +08:00
|
|
|
item.Handler.Info.Func(m.request)
|
2019-08-03 15:54:12 +08:00
|
|
|
})
|
2019-10-09 15:26:50 +08:00
|
|
|
// It does not continue calling next middleware after another middleware done.
|
|
|
|
// There should be a "Next" function to be called in the middleware in order to manage the workflow.
|
2019-09-14 22:53:28 +08:00
|
|
|
loop = false
|
2019-08-03 15:54:12 +08:00
|
|
|
}
|
2020-10-20 13:36:43 +08:00
|
|
|
}, func(exception error) {
|
2020-12-10 23:33:24 +08:00
|
|
|
if e, ok := exception.(errorStack); ok {
|
2020-04-29 00:14:29 +08:00
|
|
|
// It's already an error that has stack info.
|
2020-11-23 16:32:57 +08:00
|
|
|
m.request.error = e
|
2020-04-28 15:04:07 +08:00
|
|
|
} else {
|
2020-04-29 00:14:29 +08:00
|
|
|
// Create a new error with stack info.
|
|
|
|
// Note that there's a skip pointing the start stacktrace
|
|
|
|
// of the real error point.
|
2021-07-20 23:02:02 +08:00
|
|
|
m.request.error = gerror.WrapCodeSkip(gerror.CodeInternalError, 1, exception, "")
|
2020-04-28 15:04:07 +08:00
|
|
|
}
|
2019-09-14 22:53:28 +08:00
|
|
|
m.request.Response.WriteStatus(http.StatusInternalServerError, exception)
|
2020-03-04 22:52:56 +08:00
|
|
|
loop = false
|
2019-09-14 22:53:28 +08:00
|
|
|
})
|
2019-08-03 15:54:12 +08:00
|
|
|
}
|
2019-10-11 22:54:25 +08:00
|
|
|
// Check the http status code after all handler and middleware done.
|
2019-12-04 10:03:03 +08:00
|
|
|
if m.request.IsExited() || m.handlerIndex >= len(m.request.handlers) {
|
|
|
|
if m.request.Response.Status == 0 {
|
|
|
|
if m.request.Middleware.served {
|
|
|
|
m.request.Response.WriteHeader(http.StatusOK)
|
|
|
|
} else {
|
|
|
|
m.request.Response.WriteHeader(http.StatusNotFound)
|
|
|
|
}
|
2019-10-09 15:26:50 +08:00
|
|
|
}
|
|
|
|
}
|
2019-08-03 15:54:12 +08:00
|
|
|
}
|
2021-07-13 23:01:31 +08:00
|
|
|
|
|
|
|
func (m *middleware) callHandlerFunc(funcInfo handlerFuncInfo) {
|
|
|
|
niceCallFunc(func() {
|
|
|
|
if funcInfo.Func != nil {
|
|
|
|
funcInfo.Func(m.request)
|
|
|
|
} else {
|
|
|
|
var inputValues = []reflect.Value{
|
2021-07-30 17:17:13 +08:00
|
|
|
reflect.ValueOf(m.request.Context()),
|
2021-07-13 23:01:31 +08:00
|
|
|
}
|
|
|
|
if funcInfo.Type.NumIn() == 2 {
|
|
|
|
var (
|
|
|
|
request reflect.Value
|
|
|
|
)
|
|
|
|
if funcInfo.Type.In(1).Kind() == reflect.Ptr {
|
|
|
|
request = reflect.New(funcInfo.Type.In(1).Elem())
|
|
|
|
m.request.handlerResponse.Error = m.request.Parse(request.Interface())
|
|
|
|
} else {
|
|
|
|
request = reflect.New(funcInfo.Type.In(1).Elem()).Elem()
|
|
|
|
m.request.handlerResponse.Error = m.request.Parse(request.Addr().Interface())
|
|
|
|
}
|
|
|
|
if m.request.handlerResponse.Error != nil {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
inputValues = append(inputValues, request)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Call handler with dynamic created parameter values.
|
|
|
|
results := funcInfo.Value.Call(inputValues)
|
|
|
|
switch len(results) {
|
|
|
|
case 1:
|
|
|
|
m.request.handlerResponse.Error = results[0].Interface().(error)
|
|
|
|
|
|
|
|
case 2:
|
|
|
|
m.request.handlerResponse.Object = results[0].Interface()
|
|
|
|
if !results[1].IsNil() {
|
|
|
|
if v := results[1].Interface(); v != nil {
|
|
|
|
m.request.handlerResponse.Error = v.(error)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|