2021-02-02 16:13:39 +03:00
|
|
|
package http
|
|
|
|
|
2021-02-07 13:27:28 +03:00
|
|
|
import (
|
|
|
|
"context"
|
2021-02-25 14:16:55 +03:00
|
|
|
"fmt"
|
2021-02-07 13:27:28 +03:00
|
|
|
"net/http"
|
|
|
|
|
2023-08-12 13:53:04 +03:00
|
|
|
"go.unistack.org/micro/v4/options"
|
2021-02-07 13:27:28 +03:00
|
|
|
)
|
2021-02-02 16:13:39 +03:00
|
|
|
|
2021-03-01 20:23:22 +03:00
|
|
|
// SetError pass error to caller
|
2021-02-25 14:16:55 +03:00
|
|
|
func SetError(err interface{}) error {
|
|
|
|
return &Error{err: err}
|
|
|
|
}
|
|
|
|
|
2021-08-31 23:56:28 +03:00
|
|
|
// GetError return underline error
|
|
|
|
func GetError(err interface{}) interface{} {
|
|
|
|
if verr, ok := err.(*Error); ok {
|
|
|
|
return verr.err
|
|
|
|
}
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2021-03-01 20:23:22 +03:00
|
|
|
// Error struct holds error
|
2021-02-25 14:16:55 +03:00
|
|
|
type Error struct {
|
|
|
|
err interface{}
|
|
|
|
}
|
|
|
|
|
2021-03-01 20:23:22 +03:00
|
|
|
// Error func for error interface
|
2021-02-25 14:16:55 +03:00
|
|
|
func (err *Error) Error() string {
|
|
|
|
return fmt.Sprintf("%v", err.err)
|
|
|
|
}
|
|
|
|
|
2021-04-26 00:43:06 +03:00
|
|
|
type (
|
|
|
|
rspCodeKey struct{}
|
|
|
|
rspCodeVal struct {
|
|
|
|
code int
|
|
|
|
}
|
|
|
|
)
|
|
|
|
|
2023-02-11 01:18:16 +03:00
|
|
|
type (
|
|
|
|
rspHeaderKey struct{}
|
|
|
|
rspHeaderVal struct {
|
|
|
|
h http.Header
|
|
|
|
}
|
|
|
|
)
|
|
|
|
|
|
|
|
// SetRspHeader add response headers
|
|
|
|
func SetRspHeader(ctx context.Context, h http.Header) {
|
|
|
|
if rsp, ok := ctx.Value(rspHeaderKey{}).(*rspHeaderVal); ok {
|
|
|
|
rsp.h = h
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-02-02 16:13:39 +03:00
|
|
|
// SetRspCode saves response code in context, must be used by handler to specify http code
|
|
|
|
func SetRspCode(ctx context.Context, code int) {
|
|
|
|
if rsp, ok := ctx.Value(rspCodeKey{}).(*rspCodeVal); ok {
|
|
|
|
rsp.code = code
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-02-11 01:18:16 +03:00
|
|
|
// getRspHeader get http.Header from context
|
|
|
|
func getRspHeader(ctx context.Context) http.Header {
|
|
|
|
if rsp, ok := ctx.Value(rspHeaderKey{}).(*rspHeaderVal); ok {
|
|
|
|
return rsp.h
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2021-02-02 16:13:39 +03:00
|
|
|
// GetRspCode used internally by generated http server handler
|
|
|
|
func GetRspCode(ctx context.Context) int {
|
|
|
|
var code int
|
|
|
|
if rsp, ok := ctx.Value(rspCodeKey{}).(*rspCodeVal); ok {
|
|
|
|
code = rsp.code
|
|
|
|
}
|
|
|
|
return code
|
|
|
|
}
|
2021-02-07 13:27:28 +03:00
|
|
|
|
|
|
|
type middlewareKey struct{}
|
|
|
|
|
2021-03-01 20:23:22 +03:00
|
|
|
// Middleware passes http middlewares
|
2023-08-12 13:53:04 +03:00
|
|
|
func Middleware(mw ...func(http.Handler) http.Handler) options.Option {
|
|
|
|
return options.ContextOption(middlewareKey{}, mw)
|
2021-02-07 13:27:28 +03:00
|
|
|
}
|
2021-02-07 19:03:38 +03:00
|
|
|
|
|
|
|
type serverKey struct{}
|
|
|
|
|
2023-05-09 18:47:56 +03:00
|
|
|
// HTTPServer provide ability to pass *http.Server
|
2023-08-12 13:53:04 +03:00
|
|
|
func HTTPServer(hs *http.Server) options.Option {
|
|
|
|
return options.ContextOption(serverKey{}, hs)
|
2021-02-07 19:03:38 +03:00
|
|
|
}
|
2021-03-01 20:23:22 +03:00
|
|
|
|
2023-08-12 13:53:04 +03:00
|
|
|
type errorHandler func(ctx context.Context, s interface{}, w http.ResponseWriter, r *http.Request, err error, status int)
|
2023-01-23 09:23:38 +03:00
|
|
|
|
2021-03-01 20:23:22 +03:00
|
|
|
type errorHandlerKey struct{}
|
|
|
|
|
|
|
|
// ErrorHandler specifies handler for errors
|
2023-08-12 13:53:04 +03:00
|
|
|
func ErrorHandler(fn errorHandler) options.Option {
|
|
|
|
return options.ContextOption(errorHandlerKey{}, fn)
|
2021-03-01 20:23:22 +03:00
|
|
|
}
|
2021-03-24 15:22:20 +03:00
|
|
|
|
2021-04-26 00:43:06 +03:00
|
|
|
type (
|
|
|
|
pathHandlerKey struct{}
|
|
|
|
pathHandlerVal struct {
|
2022-01-22 01:10:24 +03:00
|
|
|
h map[string]map[string]http.HandlerFunc
|
2021-04-26 00:43:06 +03:00
|
|
|
}
|
|
|
|
)
|
2021-04-13 11:32:56 +03:00
|
|
|
|
|
|
|
// PathHandler specifies http handler for path regexp
|
2023-08-12 13:53:04 +03:00
|
|
|
func PathHandler(method, path string, handler http.HandlerFunc) options.Option {
|
|
|
|
return func(src interface{}) error {
|
|
|
|
vctx, err := options.Get(src, ".Context")
|
|
|
|
if err != nil {
|
|
|
|
return err
|
2021-04-13 11:32:56 +03:00
|
|
|
}
|
2023-08-12 13:53:04 +03:00
|
|
|
ctx, ok := vctx.(context.Context)
|
|
|
|
if !ok {
|
|
|
|
return fmt.Errorf("invalid option")
|
|
|
|
}
|
|
|
|
|
|
|
|
v, ok := ctx.Value(pathHandlerKey{}).(*pathHandlerVal)
|
2021-04-13 11:32:56 +03:00
|
|
|
if !ok {
|
2022-01-22 01:10:24 +03:00
|
|
|
v = &pathHandlerVal{h: make(map[string]map[string]http.HandlerFunc)}
|
2021-04-13 11:32:56 +03:00
|
|
|
}
|
2022-01-22 01:10:24 +03:00
|
|
|
m, ok := v.h[method]
|
2021-04-13 23:42:33 +03:00
|
|
|
if !ok {
|
2022-01-22 01:10:24 +03:00
|
|
|
m = make(map[string]http.HandlerFunc)
|
|
|
|
v.h[method] = m
|
2021-04-13 23:42:33 +03:00
|
|
|
}
|
2023-08-12 13:53:04 +03:00
|
|
|
ctx = context.WithValue(ctx, pathHandlerKey{}, v)
|
2022-01-22 01:10:24 +03:00
|
|
|
m[path] = handler
|
2023-08-12 13:53:04 +03:00
|
|
|
return options.Set(src, ctx, ".Context")
|
2021-04-13 23:42:33 +03:00
|
|
|
}
|
|
|
|
}
|
2021-07-14 13:43:45 +03:00
|
|
|
|
|
|
|
type registerRPCHandlerKey struct{}
|
|
|
|
|
|
|
|
// RegisterRPCHandler registers compatibility endpoints with /ServiceName.ServiceEndpoint method POST
|
2023-08-12 13:53:04 +03:00
|
|
|
func RegisterRPCHandler(b bool) options.Option {
|
|
|
|
return options.ContextOption(registerRPCHandlerKey{}, b)
|
2021-07-14 13:43:45 +03:00
|
|
|
}
|
2021-10-26 22:36:04 +03:00
|
|
|
|
2023-02-21 23:56:07 +03:00
|
|
|
type handlerEndpointsKey struct{}
|
2023-02-13 23:36:50 +03:00
|
|
|
|
2023-02-21 23:56:07 +03:00
|
|
|
type EndpointMetadata struct {
|
|
|
|
Name string
|
|
|
|
Path string
|
|
|
|
Method string
|
|
|
|
Body string
|
|
|
|
Stream bool
|
|
|
|
}
|
|
|
|
|
2023-08-12 13:53:04 +03:00
|
|
|
func HandlerEndpoints(md []EndpointMetadata) options.Option {
|
|
|
|
return options.ContextOption(handlerEndpointsKey{}, md)
|
2023-02-13 23:36:50 +03:00
|
|
|
}
|
|
|
|
|
2021-10-26 22:36:04 +03:00
|
|
|
type handlerOptions struct {
|
|
|
|
headers []string
|
|
|
|
cookies []string
|
|
|
|
}
|
|
|
|
|
|
|
|
type FillRequestOption func(*handlerOptions)
|
|
|
|
|
|
|
|
func Header(headers ...string) FillRequestOption {
|
|
|
|
return func(o *handlerOptions) {
|
|
|
|
o.headers = append(o.headers, headers...)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func Cookie(cookies ...string) FillRequestOption {
|
|
|
|
return func(o *handlerOptions) {
|
|
|
|
o.cookies = append(o.cookies, cookies...)
|
|
|
|
}
|
|
|
|
}
|