diff --git a/rest/config.go b/rest/config.go index 9bbd0269..a806b723 100644 --- a/rest/config.go +++ b/rest/config.go @@ -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 diff --git a/rest/engine.go b/rest/engine.go index b022e10e..e0a5a085 100644 --- a/rest/engine.go +++ b/rest/engine.go @@ -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, ) diff --git a/rest/handler/authhandler.go b/rest/handler/authhandler.go index 5d24c4ab..9cb691aa 100644 --- a/rest/handler/authhandler.go +++ b/rest/handler/authhandler.go @@ -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 diff --git a/rest/handler/breakerhandler.go b/rest/handler/breakerhandler.go index 846e68be..47ec62af 100644 --- a/rest/handler/breakerhandler.go +++ b/rest/handler/breakerhandler.go @@ -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 { diff --git a/rest/handler/contentsecurityhandler.go b/rest/handler/contentsecurityhandler.go index ba1f6f83..8eecf463 100644 --- a/rest/handler/contentsecurityhandler.go +++ b/rest/handler/contentsecurityhandler.go @@ -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 { diff --git a/rest/handler/cryptionhandler.go b/rest/handler/cryptionhandler.go index f78dc8b0..beb8700a 100644 --- a/rest/handler/cryptionhandler.go +++ b/rest/handler/cryptionhandler.go @@ -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) { diff --git a/rest/handler/gunziphandler.go b/rest/handler/gunziphandler.go index c7340dbe..08e86cc6 100644 --- a/rest/handler/gunziphandler.go +++ b/rest/handler/gunziphandler.go @@ -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) { diff --git a/rest/handler/loghandler.go b/rest/handler/loghandler.go index 93e3a8b4..3663e274 100644 --- a/rest/handler/loghandler.go +++ b/rest/handler/loghandler.go @@ -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() diff --git a/rest/handler/maxbyteshandler.go b/rest/handler/maxbyteshandler.go index c6e83250..579bd899 100644 --- a/rest/handler/maxbyteshandler.go +++ b/rest/handler/maxbyteshandler.go @@ -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 { diff --git a/rest/handler/maxconnshandler.go b/rest/handler/maxconnshandler.go index cd7bbbd5..8aefb1bc 100644 --- a/rest/handler/maxconnshandler.go +++ b/rest/handler/maxconnshandler.go @@ -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 { diff --git a/rest/handler/metrichandler.go b/rest/handler/metrichandler.go index e738b754..694206bf 100644 --- a/rest/handler/metrichandler.go +++ b/rest/handler/metrichandler.go @@ -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) { diff --git a/rest/handler/prometheushandler.go b/rest/handler/prometheushandler.go index 98253257..43995cd9 100644 --- a/rest/handler/prometheushandler.go +++ b/rest/handler/prometheushandler.go @@ -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() diff --git a/rest/handler/prometheushandler_test.go b/rest/handler/prometheushandler_test.go index 7201363b..720a6356 100644 --- a/rest/handler/prometheushandler_test.go +++ b/rest/handler/prometheushandler_test.go @@ -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) })) diff --git a/rest/handler/recoverhandler.go b/rest/handler/recoverhandler.go index dfcb9282..8ebf1343 100644 --- a/rest/handler/recoverhandler.go +++ b/rest/handler/recoverhandler.go @@ -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() { diff --git a/rest/handler/sheddinghandler.go b/rest/handler/sheddinghandler.go index 568e7887..a6e6bd48 100644 --- a/rest/handler/sheddinghandler.go +++ b/rest/handler/sheddinghandler.go @@ -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 { diff --git a/rest/handler/tracinghandler.go b/rest/handler/tracinghandler.go index ef7ef819..b06cb25f 100644 --- a/rest/handler/tracinghandler.go +++ b/rest/handler/tracinghandler.go @@ -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) diff --git a/rest/httpx/requests.go b/rest/httpx/requests.go index ab5b6d2c..072b9af1 100644 --- a/rest/httpx/requests.go +++ b/rest/httpx/requests.go @@ -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) diff --git a/rest/httpx/responses.go b/rest/httpx/responses.go index 39a7ce06..a9dadeb3 100644 --- a/rest/httpx/responses.go +++ b/rest/httpx/responses.go @@ -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) diff --git a/rest/httpx/router.go b/rest/httpx/router.go index 7d3e32b8..dc58cadb 100644 --- a/rest/httpx/router.go +++ b/rest/httpx/router.go @@ -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 diff --git a/rest/httpx/vars.go b/rest/httpx/vars.go index 3df99c8d..a7cb8f20 100644 --- a/rest/httpx/vars.go +++ b/rest/httpx/vars.go @@ -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 ) diff --git a/rest/internal/context/params.go b/rest/internal/context/params.go index 4890689d..825d3089 100644 --- a/rest/internal/context/params.go +++ b/rest/internal/context/params.go @@ -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)) } diff --git a/rest/internal/log.go b/rest/internal/log.go index 1b4d2f7f..0e100460 100644 --- a/rest/internal/log.go +++ b/rest/internal/log.go @@ -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...)) } diff --git a/rest/internal/security/contentsecurity.go b/rest/internal/security/contentsecurity.go index 95079620..89710d7b 100644 --- a/rest/internal/security/contentsecurity.go +++ b/rest/internal/security/contentsecurity.go @@ -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 { diff --git a/rest/internal/security/withcoderesponsewriter.go b/rest/internal/security/withcoderesponsewriter.go index 0ee496a9..20e77d1e 100644 --- a/rest/internal/security/withcoderesponsewriter.go +++ b/rest/internal/security/withcoderesponsewriter.go @@ -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 diff --git a/rest/internal/starter.go b/rest/internal/starter.go index fba0d449..ddd08f2a 100644 --- a/rest/internal/starter.go +++ b/rest/internal/starter.go @@ -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 diff --git a/rest/router/patrouter.go b/rest/router/patrouter.go index 252b105c..7c15b1f9 100644 --- a/rest/router/patrouter.go +++ b/rest/router/patrouter.go @@ -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), diff --git a/rest/server.go b/rest/server.go index 82f1fdf6..10a32fd1 100644 --- a/rest/server.go +++ b/rest/server.go @@ -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) diff --git a/rest/token/tokenparser.go b/rest/token/tokenparser.go index a0aa7fbe..4326ae80 100644 --- a/rest/token/tokenparser.go +++ b/rest/token/tokenparser.go @@ -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 diff --git a/rest/types.go b/rest/types.go index 81418831..102ce2b3 100644 --- a/rest/types.go +++ b/rest/types.go @@ -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 {