OSDN Git Service

delete miner
[bytom/vapor.git] / vendor / github.com / go-kit / kit / transport / http / server.go
1 package http
2
3 import (
4         "context"
5         "encoding/json"
6         "net/http"
7
8         "github.com/go-kit/kit/endpoint"
9         "github.com/go-kit/kit/log"
10 )
11
12 // Server wraps an endpoint and implements http.Handler.
13 type Server struct {
14         e            endpoint.Endpoint
15         dec          DecodeRequestFunc
16         enc          EncodeResponseFunc
17         before       []RequestFunc
18         after        []ServerResponseFunc
19         errorEncoder ErrorEncoder
20         finalizer    ServerFinalizerFunc
21         logger       log.Logger
22 }
23
24 // NewServer constructs a new server, which implements http.Handler and wraps
25 // the provided endpoint.
26 func NewServer(
27         e endpoint.Endpoint,
28         dec DecodeRequestFunc,
29         enc EncodeResponseFunc,
30         options ...ServerOption,
31 ) *Server {
32         s := &Server{
33                 e:            e,
34                 dec:          dec,
35                 enc:          enc,
36                 errorEncoder: DefaultErrorEncoder,
37                 logger:       log.NewNopLogger(),
38         }
39         for _, option := range options {
40                 option(s)
41         }
42         return s
43 }
44
45 // ServerOption sets an optional parameter for servers.
46 type ServerOption func(*Server)
47
48 // ServerBefore functions are executed on the HTTP request object before the
49 // request is decoded.
50 func ServerBefore(before ...RequestFunc) ServerOption {
51         return func(s *Server) { s.before = append(s.before, before...) }
52 }
53
54 // ServerAfter functions are executed on the HTTP response writer after the
55 // endpoint is invoked, but before anything is written to the client.
56 func ServerAfter(after ...ServerResponseFunc) ServerOption {
57         return func(s *Server) { s.after = append(s.after, after...) }
58 }
59
60 // ServerErrorEncoder is used to encode errors to the http.ResponseWriter
61 // whenever they're encountered in the processing of a request. Clients can
62 // use this to provide custom error formatting and response codes. By default,
63 // errors will be written with the DefaultErrorEncoder.
64 func ServerErrorEncoder(ee ErrorEncoder) ServerOption {
65         return func(s *Server) { s.errorEncoder = ee }
66 }
67
68 // ServerErrorLogger is used to log non-terminal errors. By default, no errors
69 // are logged. This is intended as a diagnostic measure. Finer-grained control
70 // of error handling, including logging in more detail, should be performed in a
71 // custom ServerErrorEncoder or ServerFinalizer, both of which have access to
72 // the context.
73 func ServerErrorLogger(logger log.Logger) ServerOption {
74         return func(s *Server) { s.logger = logger }
75 }
76
77 // ServerFinalizer is executed at the end of every HTTP request.
78 // By default, no finalizer is registered.
79 func ServerFinalizer(f ServerFinalizerFunc) ServerOption {
80         return func(s *Server) { s.finalizer = f }
81 }
82
83 // ServeHTTP implements http.Handler.
84 func (s Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
85         ctx := r.Context()
86
87         if s.finalizer != nil {
88                 iw := &interceptingWriter{w, http.StatusOK, 0}
89                 defer func() {
90                         ctx = context.WithValue(ctx, ContextKeyResponseHeaders, iw.Header())
91                         ctx = context.WithValue(ctx, ContextKeyResponseSize, iw.written)
92                         s.finalizer(ctx, iw.code, r)
93                 }()
94                 w = iw
95         }
96
97         for _, f := range s.before {
98                 ctx = f(ctx, r)
99         }
100
101         request, err := s.dec(ctx, r)
102         if err != nil {
103                 s.logger.Log("err", err)
104                 s.errorEncoder(ctx, err, w)
105                 return
106         }
107
108         response, err := s.e(ctx, request)
109         if err != nil {
110                 s.logger.Log("err", err)
111                 s.errorEncoder(ctx, err, w)
112                 return
113         }
114
115         for _, f := range s.after {
116                 ctx = f(ctx, w)
117         }
118
119         if err := s.enc(ctx, w, response); err != nil {
120                 s.logger.Log("err", err)
121                 s.errorEncoder(ctx, err, w)
122                 return
123         }
124 }
125
126 // ErrorEncoder is responsible for encoding an error to the ResponseWriter.
127 // Users are encouraged to use custom ErrorEncoders to encode HTTP errors to
128 // their clients, and will likely want to pass and check for their own error
129 // types. See the example shipping/handling service.
130 type ErrorEncoder func(ctx context.Context, err error, w http.ResponseWriter)
131
132 // ServerFinalizerFunc can be used to perform work at the end of an HTTP
133 // request, after the response has been written to the client. The principal
134 // intended use is for request logging. In addition to the response code
135 // provided in the function signature, additional response parameters are
136 // provided in the context under keys with the ContextKeyResponse prefix.
137 type ServerFinalizerFunc func(ctx context.Context, code int, r *http.Request)
138
139 // EncodeJSONResponse is a EncodeResponseFunc that serializes the response as a
140 // JSON object to the ResponseWriter. Many JSON-over-HTTP services can use it as
141 // a sensible default. If the response implements Headerer, the provided headers
142 // will be applied to the response. If the response implements StatusCoder, the
143 // provided StatusCode will be used instead of 200.
144 func EncodeJSONResponse(_ context.Context, w http.ResponseWriter, response interface{}) error {
145         w.Header().Set("Content-Type", "application/json; charset=utf-8")
146         if headerer, ok := response.(Headerer); ok {
147                 for k := range headerer.Headers() {
148                         w.Header().Set(k, headerer.Headers().Get(k))
149                 }
150         }
151         code := http.StatusOK
152         if sc, ok := response.(StatusCoder); ok {
153                 code = sc.StatusCode()
154         }
155         w.WriteHeader(code)
156         if code == http.StatusNoContent {
157                 return nil
158         }
159         return json.NewEncoder(w).Encode(response)
160 }
161
162 // DefaultErrorEncoder writes the error to the ResponseWriter, by default a
163 // content type of text/plain, a body of the plain text of the error, and a
164 // status code of 500. If the error implements Headerer, the provided headers
165 // will be applied to the response. If the error implements json.Marshaler, and
166 // the marshaling succeeds, a content type of application/json and the JSON
167 // encoded form of the error will be used. If the error implements StatusCoder,
168 // the provided StatusCode will be used instead of 500.
169 func DefaultErrorEncoder(_ context.Context, err error, w http.ResponseWriter) {
170         contentType, body := "text/plain; charset=utf-8", []byte(err.Error())
171         if marshaler, ok := err.(json.Marshaler); ok {
172                 if jsonBody, marshalErr := marshaler.MarshalJSON(); marshalErr == nil {
173                         contentType, body = "application/json; charset=utf-8", jsonBody
174                 }
175         }
176         w.Header().Set("Content-Type", contentType)
177         if headerer, ok := err.(Headerer); ok {
178                 for k := range headerer.Headers() {
179                         w.Header().Set(k, headerer.Headers().Get(k))
180                 }
181         }
182         code := http.StatusInternalServerError
183         if sc, ok := err.(StatusCoder); ok {
184                 code = sc.StatusCode()
185         }
186         w.WriteHeader(code)
187         w.Write(body)
188 }
189
190 // StatusCoder is checked by DefaultErrorEncoder. If an error value implements
191 // StatusCoder, the StatusCode will be used when encoding the error. By default,
192 // StatusInternalServerError (500) is used.
193 type StatusCoder interface {
194         StatusCode() int
195 }
196
197 // Headerer is checked by DefaultErrorEncoder. If an error value implements
198 // Headerer, the provided headers will be applied to the response writer, after
199 // the Content-Type is set.
200 type Headerer interface {
201         Headers() http.Header
202 }
203
204 type interceptingWriter struct {
205         http.ResponseWriter
206         code    int
207         written int64
208 }
209
210 // WriteHeader may not be explicitly called, so care must be taken to
211 // initialize w.code to its default value of http.StatusOK.
212 func (w *interceptingWriter) WriteHeader(code int) {
213         w.code = code
214         w.ResponseWriter.WriteHeader(code)
215 }
216
217 func (w *interceptingWriter) Write(p []byte) (int, error) {
218         n, err := w.ResponseWriter.Write(p)
219         w.written += int64(n)
220         return n, err
221 }