mirror of
https://github.com/zeromicro/go-zero.git
synced 2025-01-23 09:00:20 +08:00
fix golint issues in rest (#529)
This commit is contained in:
parent
d894b88c3e
commit
655ae8034c
@ -7,22 +7,25 @@ import (
|
||||
)
|
||||
|
||||
type (
|
||||
// A PrivateKeyConf is a private key config.
|
||||
PrivateKeyConf struct {
|
||||
Fingerprint string
|
||||
KeyFile string
|
||||
}
|
||||
|
||||
// A SignatureConf is a signature config.
|
||||
SignatureConf struct {
|
||||
Strict bool `json:",default=false"`
|
||||
Expiry time.Duration `json:",default=1h"`
|
||||
PrivateKeys []PrivateKeyConf
|
||||
}
|
||||
|
||||
// A RestConf is a http service config.
|
||||
// Why not name it as Conf, because we need to consider usage like:
|
||||
// type Config struct {
|
||||
// type Config struct {
|
||||
// zrpc.RpcConf
|
||||
// rest.RestConf
|
||||
// }
|
||||
// }
|
||||
// if with the name Conf, there will be two Conf inside Config.
|
||||
RestConf struct {
|
||||
service.ServiceConf
|
||||
|
@ -19,6 +19,7 @@ import (
|
||||
// use 1000m to represent 100%
|
||||
const topCpuUsage = 1000
|
||||
|
||||
// ErrSignatureConfig is an error that indicates bad config for signature.
|
||||
var ErrSignatureConfig = errors.New("bad config for Signature")
|
||||
|
||||
type engine struct {
|
||||
@ -114,7 +115,7 @@ func (s *engine) bindRoute(fr featuredRoutes, router httpx.Router, metrics *stat
|
||||
handler.TimeoutHandler(time.Duration(s.conf.Timeout)*time.Millisecond),
|
||||
handler.RecoverHandler,
|
||||
handler.MetricHandler(metrics),
|
||||
handler.PromethousHandler(route.Path),
|
||||
handler.PrometheusHandler(route.Path),
|
||||
handler.MaxBytesHandler(s.conf.MaxBytes),
|
||||
handler.GunzipHandler,
|
||||
)
|
||||
|
@ -28,15 +28,19 @@ var (
|
||||
)
|
||||
|
||||
type (
|
||||
// A AuthorizeOptions is authorize options.
|
||||
AuthorizeOptions struct {
|
||||
PrevSecret string
|
||||
Callback UnauthorizedCallback
|
||||
}
|
||||
|
||||
// UnauthorizedCallback defines the method of unauthorized callback.
|
||||
UnauthorizedCallback func(w http.ResponseWriter, r *http.Request, err error)
|
||||
AuthorizeOption func(opts *AuthorizeOptions)
|
||||
// AuthorizeOption defines the method to customize an AuthorizeOptions.
|
||||
AuthorizeOption func(opts *AuthorizeOptions)
|
||||
)
|
||||
|
||||
// Authorize returns an authorize middleware.
|
||||
func Authorize(secret string, opts ...AuthorizeOption) func(http.Handler) http.Handler {
|
||||
var authOpts AuthorizeOptions
|
||||
for _, opt := range opts {
|
||||
@ -78,12 +82,14 @@ func Authorize(secret string, opts ...AuthorizeOption) func(http.Handler) http.H
|
||||
}
|
||||
}
|
||||
|
||||
// WithPrevSecret returns an AuthorizeOption with setting previous secret.
|
||||
func WithPrevSecret(secret string) AuthorizeOption {
|
||||
return func(opts *AuthorizeOptions) {
|
||||
opts.PrevSecret = secret
|
||||
}
|
||||
}
|
||||
|
||||
// WithUnauthorizedCallback returns an AuthorizeOption with setting unauthorized callback.
|
||||
func WithUnauthorizedCallback(callback UnauthorizedCallback) AuthorizeOption {
|
||||
return func(opts *AuthorizeOptions) {
|
||||
opts.Callback = callback
|
||||
|
@ -14,6 +14,7 @@ import (
|
||||
|
||||
const breakerSeparator = "://"
|
||||
|
||||
// BreakerHandler returns a break circuit middleware.
|
||||
func BreakerHandler(method, path string, metrics *stat.Metrics) func(http.Handler) http.Handler {
|
||||
brk := breaker.NewBreaker(breaker.WithName(strings.Join([]string{method, path}, breakerSeparator)))
|
||||
return func(next http.Handler) http.Handler {
|
||||
|
@ -12,8 +12,10 @@ import (
|
||||
|
||||
const contentSecurity = "X-Content-Security"
|
||||
|
||||
// UnsignedCallback defines the method of the unsigned callback.
|
||||
type UnsignedCallback func(w http.ResponseWriter, r *http.Request, next http.Handler, strict bool, code int)
|
||||
|
||||
// ContentSecurityHandler returns a middleware to verify content security.
|
||||
func ContentSecurityHandler(decrypters map[string]codec.RsaDecrypter, tolerance time.Duration,
|
||||
strict bool, callbacks ...UnsignedCallback) func(http.Handler) http.Handler {
|
||||
if len(callbacks) == 0 {
|
||||
|
@ -16,6 +16,7 @@ const maxBytes = 1 << 20 // 1 MiB
|
||||
|
||||
var errContentLengthExceeded = errors.New("content length exceeded")
|
||||
|
||||
// CryptionHandler returns a middleware to handle cryption.
|
||||
func CryptionHandler(key []byte) func(http.Handler) http.Handler {
|
||||
return func(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
|
@ -10,6 +10,7 @@ import (
|
||||
|
||||
const gzipEncoding = "gzip"
|
||||
|
||||
// GunzipHandler returns a middleware to gunzip http request body.
|
||||
func GunzipHandler(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
if strings.Contains(r.Header.Get(httpx.ContentEncoding), gzipEncoding) {
|
||||
|
@ -19,36 +19,37 @@ import (
|
||||
|
||||
const slowThreshold = time.Millisecond * 500
|
||||
|
||||
type LoggedResponseWriter struct {
|
||||
type loggedResponseWriter struct {
|
||||
w http.ResponseWriter
|
||||
r *http.Request
|
||||
code int
|
||||
}
|
||||
|
||||
func (w *LoggedResponseWriter) Header() http.Header {
|
||||
func (w *loggedResponseWriter) Header() http.Header {
|
||||
return w.w.Header()
|
||||
}
|
||||
|
||||
func (w *LoggedResponseWriter) Write(bytes []byte) (int, error) {
|
||||
func (w *loggedResponseWriter) Write(bytes []byte) (int, error) {
|
||||
return w.w.Write(bytes)
|
||||
}
|
||||
|
||||
func (w *LoggedResponseWriter) WriteHeader(code int) {
|
||||
func (w *loggedResponseWriter) WriteHeader(code int) {
|
||||
w.w.WriteHeader(code)
|
||||
w.code = code
|
||||
}
|
||||
|
||||
func (w *LoggedResponseWriter) Flush() {
|
||||
func (w *loggedResponseWriter) Flush() {
|
||||
if flusher, ok := w.w.(http.Flusher); ok {
|
||||
flusher.Flush()
|
||||
}
|
||||
}
|
||||
|
||||
// LogHandler returns a middleware that logs http request and response.
|
||||
func LogHandler(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
timer := utils.NewElapsedTimer()
|
||||
logs := new(internal.LogCollector)
|
||||
lrw := LoggedResponseWriter{
|
||||
lrw := loggedResponseWriter{
|
||||
w: w,
|
||||
r: r,
|
||||
code: http.StatusOK,
|
||||
@ -62,40 +63,41 @@ func LogHandler(next http.Handler) http.Handler {
|
||||
})
|
||||
}
|
||||
|
||||
type DetailLoggedResponseWriter struct {
|
||||
writer *LoggedResponseWriter
|
||||
type detailLoggedResponseWriter struct {
|
||||
writer *loggedResponseWriter
|
||||
buf *bytes.Buffer
|
||||
}
|
||||
|
||||
func newDetailLoggedResponseWriter(writer *LoggedResponseWriter, buf *bytes.Buffer) *DetailLoggedResponseWriter {
|
||||
return &DetailLoggedResponseWriter{
|
||||
func newDetailLoggedResponseWriter(writer *loggedResponseWriter, buf *bytes.Buffer) *detailLoggedResponseWriter {
|
||||
return &detailLoggedResponseWriter{
|
||||
writer: writer,
|
||||
buf: buf,
|
||||
}
|
||||
}
|
||||
|
||||
func (w *DetailLoggedResponseWriter) Flush() {
|
||||
func (w *detailLoggedResponseWriter) Flush() {
|
||||
w.writer.Flush()
|
||||
}
|
||||
|
||||
func (w *DetailLoggedResponseWriter) Header() http.Header {
|
||||
func (w *detailLoggedResponseWriter) Header() http.Header {
|
||||
return w.writer.Header()
|
||||
}
|
||||
|
||||
func (w *DetailLoggedResponseWriter) Write(bs []byte) (int, error) {
|
||||
func (w *detailLoggedResponseWriter) Write(bs []byte) (int, error) {
|
||||
w.buf.Write(bs)
|
||||
return w.writer.Write(bs)
|
||||
}
|
||||
|
||||
func (w *DetailLoggedResponseWriter) WriteHeader(code int) {
|
||||
func (w *detailLoggedResponseWriter) WriteHeader(code int) {
|
||||
w.writer.WriteHeader(code)
|
||||
}
|
||||
|
||||
// DetailedLogHandler returns a middleware that logs http request and response in details.
|
||||
func DetailedLogHandler(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
timer := utils.NewElapsedTimer()
|
||||
var buf bytes.Buffer
|
||||
lrw := newDetailLoggedResponseWriter(&LoggedResponseWriter{
|
||||
lrw := newDetailLoggedResponseWriter(&loggedResponseWriter{
|
||||
w: w,
|
||||
r: r,
|
||||
code: http.StatusOK,
|
||||
@ -146,7 +148,7 @@ func logBrief(r *http.Request, code int, timer *utils.ElapsedTimer, logs *intern
|
||||
}
|
||||
}
|
||||
|
||||
func logDetails(r *http.Request, response *DetailLoggedResponseWriter, timer *utils.ElapsedTimer,
|
||||
func logDetails(r *http.Request, response *detailLoggedResponseWriter, timer *utils.ElapsedTimer,
|
||||
logs *internal.LogCollector) {
|
||||
var buf bytes.Buffer
|
||||
duration := timer.Duration()
|
||||
|
@ -6,6 +6,7 @@ import (
|
||||
"github.com/tal-tech/go-zero/rest/internal"
|
||||
)
|
||||
|
||||
// MaxBytesHandler returns a middleware that limit reading of http request body.
|
||||
func MaxBytesHandler(n int64) func(http.Handler) http.Handler {
|
||||
if n <= 0 {
|
||||
return func(next http.Handler) http.Handler {
|
||||
|
@ -8,6 +8,7 @@ import (
|
||||
"github.com/tal-tech/go-zero/rest/internal"
|
||||
)
|
||||
|
||||
// MaxConns returns a middleware that limit the concurrent connections.
|
||||
func MaxConns(n int) func(http.Handler) http.Handler {
|
||||
if n <= 0 {
|
||||
return func(next http.Handler) http.Handler {
|
||||
|
@ -7,6 +7,7 @@ import (
|
||||
"github.com/tal-tech/go-zero/core/timex"
|
||||
)
|
||||
|
||||
// MetricHandler returns a middleware that stat the metrics.
|
||||
func MetricHandler(metrics *stat.Metrics) func(http.Handler) http.Handler {
|
||||
return func(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
|
@ -31,7 +31,8 @@ var (
|
||||
})
|
||||
)
|
||||
|
||||
func PromethousHandler(path string) func(http.Handler) http.Handler {
|
||||
// PrometheusHandler returns a middleware that reports stats to prometheus.
|
||||
func PrometheusHandler(path string) func(http.Handler) http.Handler {
|
||||
return func(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
startTime := timex.Now()
|
||||
|
@ -9,7 +9,7 @@ import (
|
||||
)
|
||||
|
||||
func TestPromMetricHandler(t *testing.T) {
|
||||
promMetricHandler := PromethousHandler("/user/login")
|
||||
promMetricHandler := PrometheusHandler("/user/login")
|
||||
handler := promMetricHandler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
w.WriteHeader(http.StatusOK)
|
||||
}))
|
||||
|
@ -8,6 +8,7 @@ import (
|
||||
"github.com/tal-tech/go-zero/rest/internal"
|
||||
)
|
||||
|
||||
// RecoverHandler returns a middleware that recovers if panic happens.
|
||||
func RecoverHandler(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
defer func() {
|
||||
|
@ -18,6 +18,7 @@ var (
|
||||
lock sync.Mutex
|
||||
)
|
||||
|
||||
// SheddingHandler returns a middleware that does load shedding.
|
||||
func SheddingHandler(shedder load.Shedder, metrics *stat.Metrics) func(http.Handler) http.Handler {
|
||||
if shedder == nil {
|
||||
return func(next http.Handler) http.Handler {
|
||||
|
@ -8,6 +8,7 @@ import (
|
||||
"github.com/tal-tech/go-zero/core/trace"
|
||||
)
|
||||
|
||||
// TracingHandler returns a middleware that traces the request.
|
||||
func TracingHandler(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
carrier, err := trace.Extract(trace.HttpFormat, r.Header)
|
||||
|
@ -60,6 +60,7 @@ func ParseForm(r *http.Request, v interface{}) error {
|
||||
return formUnmarshaler.Unmarshal(params, v)
|
||||
}
|
||||
|
||||
// ParseHeader parses the request header and returns a map.
|
||||
func ParseHeader(headerValue string) map[string]string {
|
||||
ret := make(map[string]string)
|
||||
fields := strings.Split(headerValue, separator)
|
||||
|
@ -13,6 +13,7 @@ var (
|
||||
lock sync.RWMutex
|
||||
)
|
||||
|
||||
// Error writes err into w.
|
||||
func Error(w http.ResponseWriter, err error) {
|
||||
lock.RLock()
|
||||
handler := errorHandler
|
||||
@ -32,20 +33,24 @@ func Error(w http.ResponseWriter, err error) {
|
||||
}
|
||||
}
|
||||
|
||||
// Ok writes HTTP 200 OK into w.
|
||||
func Ok(w http.ResponseWriter) {
|
||||
w.WriteHeader(http.StatusOK)
|
||||
}
|
||||
|
||||
// OkJson writes v into w with 200 OK.
|
||||
func OkJson(w http.ResponseWriter, v interface{}) {
|
||||
WriteJson(w, http.StatusOK, v)
|
||||
}
|
||||
|
||||
// SetErrorHandler sets the error handler, which is called on calling Error.
|
||||
func SetErrorHandler(handler func(error) (int, interface{})) {
|
||||
lock.Lock()
|
||||
defer lock.Unlock()
|
||||
errorHandler = handler
|
||||
}
|
||||
|
||||
// WriteJson writes v as json string into w with code.
|
||||
func WriteJson(w http.ResponseWriter, code int, v interface{}) {
|
||||
w.Header().Set(ContentType, ApplicationJson)
|
||||
w.WriteHeader(code)
|
||||
|
@ -2,6 +2,7 @@ package httpx
|
||||
|
||||
import "net/http"
|
||||
|
||||
// Router interface represents a http router that handles http requests.
|
||||
type Router interface {
|
||||
http.Handler
|
||||
Handle(method string, path string, handler http.Handler) error
|
||||
|
@ -1,19 +1,31 @@
|
||||
package httpx
|
||||
|
||||
const (
|
||||
// ApplicationJson means application/json.
|
||||
ApplicationJson = "application/json"
|
||||
// ContentEncoding means Content-Encoding.
|
||||
ContentEncoding = "Content-Encoding"
|
||||
// ContentSecurity means X-Content-Security.
|
||||
ContentSecurity = "X-Content-Security"
|
||||
ContentType = "Content-Type"
|
||||
KeyField = "key"
|
||||
SecretField = "secret"
|
||||
TypeField = "type"
|
||||
CryptionType = 1
|
||||
// ContentType means Content-Type.
|
||||
ContentType = "Content-Type"
|
||||
// KeyField means key.
|
||||
KeyField = "key"
|
||||
// SecretField means secret.
|
||||
SecretField = "secret"
|
||||
// TypeField means type.
|
||||
TypeField = "type"
|
||||
// CryptionType means cryption.
|
||||
CryptionType = 1
|
||||
)
|
||||
|
||||
const (
|
||||
// CodeSignaturePass means signature verification passed.
|
||||
CodeSignaturePass = iota
|
||||
// CodeSignatureInvalidHeader means invalid header in signature.
|
||||
CodeSignatureInvalidHeader
|
||||
// CodeSignatureWrongTime means wrong timestamp in signature.
|
||||
CodeSignatureWrongTime
|
||||
// CodeSignatureInvalidToken means invalid token in signature.
|
||||
CodeSignatureInvalidToken
|
||||
)
|
||||
|
@ -7,6 +7,7 @@ import (
|
||||
|
||||
var pathVars = contextKey("pathVars")
|
||||
|
||||
// Vars parses path variables and returns a map.
|
||||
func Vars(r *http.Request) map[string]string {
|
||||
vars, ok := r.Context().Value(pathVars).(map[string]string)
|
||||
if ok {
|
||||
@ -16,6 +17,7 @@ func Vars(r *http.Request) map[string]string {
|
||||
return nil
|
||||
}
|
||||
|
||||
// WithPathVars writes params into given r and returns a new http.Request.
|
||||
func WithPathVars(r *http.Request, params map[string]string) *http.Request {
|
||||
return r.WithContext(context.WithValue(r.Context(), pathVars, params))
|
||||
}
|
||||
|
@ -10,19 +10,23 @@ import (
|
||||
"github.com/tal-tech/go-zero/rest/httpx"
|
||||
)
|
||||
|
||||
// LogContext is a context key.
|
||||
var LogContext = contextKey("request_logs")
|
||||
|
||||
// A LogCollector is used to collect logs.
|
||||
type LogCollector struct {
|
||||
Messages []string
|
||||
lock sync.Mutex
|
||||
}
|
||||
|
||||
// Append appends msg into log context.
|
||||
func (lc *LogCollector) Append(msg string) {
|
||||
lc.lock.Lock()
|
||||
lc.Messages = append(lc.Messages, msg)
|
||||
lc.lock.Unlock()
|
||||
}
|
||||
|
||||
// Flush flushes collected logs.
|
||||
func (lc *LogCollector) Flush() string {
|
||||
var buffer bytes.Buffer
|
||||
|
||||
@ -48,18 +52,22 @@ func (lc *LogCollector) takeAll() []string {
|
||||
return messages
|
||||
}
|
||||
|
||||
// Error logs the given v along with r in error log.
|
||||
func Error(r *http.Request, v ...interface{}) {
|
||||
logx.ErrorCaller(1, format(r, v...))
|
||||
}
|
||||
|
||||
// Errorf logs the given v with format along with r in error log.
|
||||
func Errorf(r *http.Request, format string, v ...interface{}) {
|
||||
logx.ErrorCaller(1, formatf(r, format, v...))
|
||||
}
|
||||
|
||||
// Info logs the given v along with r in access log.
|
||||
func Info(r *http.Request, v ...interface{}) {
|
||||
appendLog(r, format(r, v...))
|
||||
}
|
||||
|
||||
// Infof logs the given v with format along with r in access log.
|
||||
func Infof(r *http.Request, format string, v ...interface{}) {
|
||||
appendLog(r, formatf(r, format, v...))
|
||||
}
|
||||
|
@ -25,13 +25,19 @@ const (
|
||||
)
|
||||
|
||||
var (
|
||||
// ErrInvalidContentType is an error that indicates invalid content type.
|
||||
ErrInvalidContentType = errors.New("invalid content type")
|
||||
ErrInvalidHeader = errors.New("invalid X-Content-Security header")
|
||||
ErrInvalidKey = errors.New("invalid key")
|
||||
ErrInvalidPublicKey = errors.New("invalid public key")
|
||||
ErrInvalidSecret = errors.New("invalid secret")
|
||||
// ErrInvalidHeader is an error that indicates invalid X-Content-Security header.
|
||||
ErrInvalidHeader = errors.New("invalid X-Content-Security header")
|
||||
// ErrInvalidKey is an error that indicates invalid key.
|
||||
ErrInvalidKey = errors.New("invalid key")
|
||||
// ErrInvalidPublicKey is an error that indicates invalid public key.
|
||||
ErrInvalidPublicKey = errors.New("invalid public key")
|
||||
// ErrInvalidSecret is an error that indicates invalid secret.
|
||||
ErrInvalidSecret = errors.New("invalid secret")
|
||||
)
|
||||
|
||||
// A ContentSecurityHeader is a content security header.
|
||||
type ContentSecurityHeader struct {
|
||||
Key []byte
|
||||
Timestamp string
|
||||
@ -39,10 +45,12 @@ type ContentSecurityHeader struct {
|
||||
Signature string
|
||||
}
|
||||
|
||||
// Encrypted checks if it's a crypted request.
|
||||
func (h *ContentSecurityHeader) Encrypted() bool {
|
||||
return h.ContentType == httpx.CryptionType
|
||||
}
|
||||
|
||||
// ParseContentSecurity parses content security settings in give r.
|
||||
func ParseContentSecurity(decrypters map[string]codec.RsaDecrypter, r *http.Request) (
|
||||
*ContentSecurityHeader, error) {
|
||||
contentSecurity := r.Header.Get(httpx.ContentSecurity)
|
||||
@ -88,6 +96,7 @@ func ParseContentSecurity(decrypters map[string]codec.RsaDecrypter, r *http.Requ
|
||||
}, nil
|
||||
}
|
||||
|
||||
// VerifySignature verifies the signature in given r.
|
||||
func VerifySignature(r *http.Request, securityHeader *ContentSecurityHeader, tolerance time.Duration) int {
|
||||
seconds, err := strconv.ParseInt(securityHeader.Timestamp, 10, 64)
|
||||
if err != nil {
|
||||
|
@ -2,25 +2,30 @@ package security
|
||||
|
||||
import "net/http"
|
||||
|
||||
// A WithCodeResponseWriter is a helper to delay sealing a http.ResponseWriter on writing code.
|
||||
type WithCodeResponseWriter struct {
|
||||
Writer http.ResponseWriter
|
||||
Code int
|
||||
}
|
||||
|
||||
// Flush flushes the response writer.
|
||||
func (w *WithCodeResponseWriter) Flush() {
|
||||
if flusher, ok := w.Writer.(http.Flusher); ok {
|
||||
flusher.Flush()
|
||||
}
|
||||
}
|
||||
|
||||
// Header returns the http header.
|
||||
func (w *WithCodeResponseWriter) Header() http.Header {
|
||||
return w.Writer.Header()
|
||||
}
|
||||
|
||||
// Write writes bytes into w.
|
||||
func (w *WithCodeResponseWriter) Write(bytes []byte) (int, error) {
|
||||
return w.Writer.Write(bytes)
|
||||
}
|
||||
|
||||
// WriteHeader writes code into w, and not sealing the writer.
|
||||
func (w *WithCodeResponseWriter) WriteHeader(code int) {
|
||||
w.Writer.WriteHeader(code)
|
||||
w.Code = code
|
||||
|
@ -8,12 +8,14 @@ import (
|
||||
"github.com/tal-tech/go-zero/core/proc"
|
||||
)
|
||||
|
||||
// StartHttp starts a http server.
|
||||
func StartHttp(host string, port int, handler http.Handler) error {
|
||||
return start(host, port, handler, func(srv *http.Server) error {
|
||||
return srv.ListenAndServe()
|
||||
})
|
||||
}
|
||||
|
||||
// StartHttps starts a https server.
|
||||
func StartHttps(host string, port int, certFile, keyFile string, handler http.Handler) error {
|
||||
return start(host, port, handler, func(srv *http.Server) error {
|
||||
// certFile and keyFile are set in buildHttpsServer
|
||||
|
@ -17,8 +17,10 @@ const (
|
||||
)
|
||||
|
||||
var (
|
||||
// ErrInvalidMethod is an error that indicates not a valid http method.
|
||||
ErrInvalidMethod = errors.New("not a valid http method")
|
||||
ErrInvalidPath = errors.New("path must begin with '/'")
|
||||
// ErrInvalidPath is an error that indicates path is not start with /.
|
||||
ErrInvalidPath = errors.New("path must begin with '/'")
|
||||
)
|
||||
|
||||
type patRouter struct {
|
||||
@ -27,6 +29,7 @@ type patRouter struct {
|
||||
notAllowed http.Handler
|
||||
}
|
||||
|
||||
// NewRouter returns a httpx.Router.
|
||||
func NewRouter() httpx.Router {
|
||||
return &patRouter{
|
||||
trees: make(map[string]*search.Tree),
|
||||
|
@ -15,8 +15,10 @@ type (
|
||||
start func(*engine) error
|
||||
}
|
||||
|
||||
// RunOption defines the method to customize a Server.
|
||||
RunOption func(*Server)
|
||||
|
||||
// A Server is a http server.
|
||||
Server struct {
|
||||
ngin *engine
|
||||
opts runOptions
|
||||
@ -58,6 +60,7 @@ func NewServer(c RestConf, opts ...RunOption) (*Server, error) {
|
||||
return server, nil
|
||||
}
|
||||
|
||||
// AddRoutes add given routes into the Server.
|
||||
func (e *Server) AddRoutes(rs []Route, opts ...RouteOption) {
|
||||
r := featuredRoutes{
|
||||
routes: rs,
|
||||
@ -68,28 +71,34 @@ func (e *Server) AddRoutes(rs []Route, opts ...RouteOption) {
|
||||
e.ngin.AddRoutes(r)
|
||||
}
|
||||
|
||||
// AddRoute adds given route into the Server.
|
||||
func (e *Server) AddRoute(r Route, opts ...RouteOption) {
|
||||
e.AddRoutes([]Route{r}, opts...)
|
||||
}
|
||||
|
||||
// Start starts the Server.
|
||||
func (e *Server) Start() {
|
||||
handleError(e.opts.start(e.ngin))
|
||||
}
|
||||
|
||||
// Stop stops the Server.
|
||||
func (e *Server) Stop() {
|
||||
logx.Close()
|
||||
}
|
||||
|
||||
// Use adds the given middleware in the Server.
|
||||
func (e *Server) Use(middleware Middleware) {
|
||||
e.ngin.use(middleware)
|
||||
}
|
||||
|
||||
// ToMiddleware converts the given handler to a Middleware.
|
||||
func ToMiddleware(handler func(next http.Handler) http.Handler) Middleware {
|
||||
return func(handle http.HandlerFunc) http.HandlerFunc {
|
||||
return handler(handle).ServeHTTP
|
||||
}
|
||||
}
|
||||
|
||||
// WithJwt returns a func to enable jwt authentication in given route.
|
||||
func WithJwt(secret string) RouteOption {
|
||||
return func(r *featuredRoutes) {
|
||||
validateSecret(secret)
|
||||
@ -98,6 +107,8 @@ func WithJwt(secret string) RouteOption {
|
||||
}
|
||||
}
|
||||
|
||||
// WithJwtTransition returns a func to enable jwt authentication as well as jwt secret transition.
|
||||
// Which means old and new jwt secrets work together for a peroid.
|
||||
func WithJwtTransition(secret, prevSecret string) RouteOption {
|
||||
return func(r *featuredRoutes) {
|
||||
// why not validate prevSecret, because prevSecret is an already used one,
|
||||
@ -109,6 +120,7 @@ func WithJwtTransition(secret, prevSecret string) RouteOption {
|
||||
}
|
||||
}
|
||||
|
||||
// WithMiddlewares adds given middlewares to given routes.
|
||||
func WithMiddlewares(ms []Middleware, rs ...Route) []Route {
|
||||
for i := len(ms) - 1; i >= 0; i-- {
|
||||
rs = WithMiddleware(ms[i], rs...)
|
||||
@ -116,6 +128,7 @@ func WithMiddlewares(ms []Middleware, rs ...Route) []Route {
|
||||
return rs
|
||||
}
|
||||
|
||||
// WithMiddleware adds given middleware to given route.
|
||||
func WithMiddleware(middleware Middleware, rs ...Route) []Route {
|
||||
routes := make([]Route, len(rs))
|
||||
|
||||
@ -131,24 +144,28 @@ func WithMiddleware(middleware Middleware, rs ...Route) []Route {
|
||||
return routes
|
||||
}
|
||||
|
||||
// WithNotFoundHandler returns a RunOption with not found handler set to given handler.
|
||||
func WithNotFoundHandler(handler http.Handler) RunOption {
|
||||
rt := router.NewRouter()
|
||||
rt.SetNotFoundHandler(handler)
|
||||
return WithRouter(rt)
|
||||
}
|
||||
|
||||
// WithNotAllowedHandler returns a RunOption with not allowed handler set to given handler.
|
||||
func WithNotAllowedHandler(handler http.Handler) RunOption {
|
||||
rt := router.NewRouter()
|
||||
rt.SetNotAllowedHandler(handler)
|
||||
return WithRouter(rt)
|
||||
}
|
||||
|
||||
// WithPriority returns a RunOption with priority.
|
||||
func WithPriority() RouteOption {
|
||||
return func(r *featuredRoutes) {
|
||||
r.priority = true
|
||||
}
|
||||
}
|
||||
|
||||
// WithRouter returns a RunOption that make server run with given router.
|
||||
func WithRouter(router httpx.Router) RunOption {
|
||||
return func(server *Server) {
|
||||
server.opts.start = func(srv *engine) error {
|
||||
@ -157,6 +174,7 @@ func WithRouter(router httpx.Router) RunOption {
|
||||
}
|
||||
}
|
||||
|
||||
// WithSignature returns a RouteOption to enable signature verification.
|
||||
func WithSignature(signature SignatureConf) RouteOption {
|
||||
return func(r *featuredRoutes) {
|
||||
r.signature.enabled = true
|
||||
@ -166,12 +184,14 @@ func WithSignature(signature SignatureConf) RouteOption {
|
||||
}
|
||||
}
|
||||
|
||||
// WithUnauthorizedCallback returns a RunOption that with given unauthorized callback set.
|
||||
func WithUnauthorizedCallback(callback handler.UnauthorizedCallback) RunOption {
|
||||
return func(engine *Server) {
|
||||
engine.ngin.SetUnauthorizedCallback(callback)
|
||||
}
|
||||
}
|
||||
|
||||
// WithUnsignedCallback returns a RunOption that with given unsigned callback set.
|
||||
func WithUnsignedCallback(callback handler.UnsignedCallback) RunOption {
|
||||
return func(engine *Server) {
|
||||
engine.ngin.SetUnsignedCallback(callback)
|
||||
|
@ -14,8 +14,10 @@ import (
|
||||
const claimHistoryResetDuration = time.Hour * 24
|
||||
|
||||
type (
|
||||
// ParseOption defines the method to customize a TokenParser.
|
||||
ParseOption func(parser *TokenParser)
|
||||
|
||||
// A TokenParser is used to parse tokens.
|
||||
TokenParser struct {
|
||||
resetTime time.Duration
|
||||
resetDuration time.Duration
|
||||
@ -23,6 +25,7 @@ type (
|
||||
}
|
||||
)
|
||||
|
||||
// NewTokenParser returns a TokenParser.
|
||||
func NewTokenParser(opts ...ParseOption) *TokenParser {
|
||||
parser := &TokenParser{
|
||||
resetTime: timex.Now(),
|
||||
@ -36,6 +39,7 @@ func NewTokenParser(opts ...ParseOption) *TokenParser {
|
||||
return parser
|
||||
}
|
||||
|
||||
// ParseToken parses token from given r, with passed in secret and prevSecret.
|
||||
func (tp *TokenParser) ParseToken(r *http.Request, secret, prevSecret string) (*jwt.Token, error) {
|
||||
var token *jwt.Token
|
||||
var err error
|
||||
@ -108,6 +112,7 @@ func (tp *TokenParser) loadCount(secret string) uint64 {
|
||||
return 0
|
||||
}
|
||||
|
||||
// WithResetDuration returns a func to customize a TokenParser with reset duration.
|
||||
func WithResetDuration(duration time.Duration) ParseOption {
|
||||
return func(parser *TokenParser) {
|
||||
parser.resetDuration = duration
|
||||
|
@ -3,14 +3,17 @@ package rest
|
||||
import "net/http"
|
||||
|
||||
type (
|
||||
// Middleware defines the middleware method.
|
||||
Middleware func(next http.HandlerFunc) http.HandlerFunc
|
||||
|
||||
// A Route is a http route.
|
||||
Route struct {
|
||||
Method string
|
||||
Path string
|
||||
Handler http.HandlerFunc
|
||||
}
|
||||
|
||||
// RouteOption defines the method to customize a featured route.
|
||||
RouteOption func(r *featuredRoutes)
|
||||
|
||||
jwtSetting struct {
|
||||
|
Loading…
Reference in New Issue
Block a user