mirror of
https://github.com/tailscale/tailscale.git
synced 2024-11-25 19:15:34 +00:00
tsweb: add StdHandlerOpts that accepts an options struct
I'm about to add yet another StdHandler option. Time to refactor. Signed-off-by: Josh Bleecher Snyder <josh@tailscale.com>
This commit is contained in:
parent
eab6e9ea4e
commit
e98f2c57d6
@ -157,11 +157,17 @@ type ReturnHandler interface {
|
||||
ServeHTTPReturn(http.ResponseWriter, *http.Request) error
|
||||
}
|
||||
|
||||
type HandlerOptions struct {
|
||||
Quiet200s bool // if set, do not log successfully handled HTTP requests
|
||||
Logf logger.Logf
|
||||
Now func() time.Time // if nil, defaults to time.Now
|
||||
}
|
||||
|
||||
// StdHandler converts a ReturnHandler into a standard http.Handler.
|
||||
// Handled requests are logged using logf, as are any errors. Errors
|
||||
// are handled as specified by the Handler interface.
|
||||
func StdHandler(h ReturnHandler, logf logger.Logf) http.Handler {
|
||||
return stdHandler(h, logf, time.Now, true)
|
||||
return StdHandlerOpts(h, HandlerOptions{Logf: logf, Now: time.Now})
|
||||
}
|
||||
|
||||
// ReturnHandlerFunc is an adapter to allow the use of ordinary
|
||||
@ -178,27 +184,32 @@ func (f ReturnHandlerFunc) ServeHTTPReturn(w http.ResponseWriter, r *http.Reques
|
||||
// StdHandlerNo200s is like StdHandler, but successfully handled HTTP
|
||||
// requests don't write an access log entry to logf.
|
||||
//
|
||||
// TODO(danderson): quick stopgap, probably want ...Options on StdHandler instead?
|
||||
// TODO(josharian): eliminate this and StdHandler in favor of StdHandlerOpts,
|
||||
// rename StdHandlerOpts to StdHandler. Will be a breaking API change.
|
||||
func StdHandlerNo200s(h ReturnHandler, logf logger.Logf) http.Handler {
|
||||
return stdHandler(h, logf, time.Now, false)
|
||||
return StdHandlerOpts(h, HandlerOptions{Logf: logf, Now: time.Now, Quiet200s: true})
|
||||
}
|
||||
|
||||
func stdHandler(h ReturnHandler, logf logger.Logf, now func() time.Time, log200s bool) http.Handler {
|
||||
return retHandler{h, logf, now, log200s}
|
||||
// StdHandlerOpts converts a ReturnHandler into a standard http.Handler.
|
||||
// Handled requests are logged using opts.Logf, as are any errors.
|
||||
// Errors are handled as specified by the Handler interface.
|
||||
func StdHandlerOpts(h ReturnHandler, opts HandlerOptions) http.Handler {
|
||||
if opts.Now == nil {
|
||||
opts.Now = time.Now
|
||||
}
|
||||
return retHandler{h, opts}
|
||||
}
|
||||
|
||||
// retHandler is an http.Handler that wraps a Handler and handles errors.
|
||||
type retHandler struct {
|
||||
rh ReturnHandler
|
||||
logf logger.Logf
|
||||
timeNow func() time.Time
|
||||
log200s bool
|
||||
rh ReturnHandler
|
||||
opts HandlerOptions
|
||||
}
|
||||
|
||||
// ServeHTTP implements the http.Handler interface.
|
||||
func (h retHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
msg := AccessLogRecord{
|
||||
When: h.timeNow(),
|
||||
When: h.opts.Now(),
|
||||
RemoteAddr: r.RemoteAddr,
|
||||
Proto: r.Proto,
|
||||
TLS: r.TLS != nil,
|
||||
@ -209,7 +220,7 @@ func (h retHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
Referer: r.Referer(),
|
||||
}
|
||||
|
||||
lw := &loggingResponseWriter{ResponseWriter: w, logf: h.logf}
|
||||
lw := &loggingResponseWriter{ResponseWriter: w, logf: h.opts.Logf}
|
||||
err := h.rh.ServeHTTPReturn(lw, r)
|
||||
hErr, hErrOK := err.(HTTPError)
|
||||
|
||||
@ -219,7 +230,7 @@ func (h retHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
lw.code = 200
|
||||
}
|
||||
|
||||
msg.Seconds = h.timeNow().Sub(msg.When).Seconds()
|
||||
msg.Seconds = h.opts.Now().Sub(msg.When).Seconds()
|
||||
msg.Code = lw.code
|
||||
msg.Bytes = lw.bytes
|
||||
|
||||
@ -245,12 +256,12 @@ func (h retHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
}
|
||||
if lw.code != 0 {
|
||||
h.logf("[unexpected] handler returned HTTPError %v, but already sent a response with code %d", hErr, lw.code)
|
||||
h.opts.Logf("[unexpected] handler returned HTTPError %v, but already sent a response with code %d", hErr, lw.code)
|
||||
break
|
||||
}
|
||||
msg.Code = hErr.Code
|
||||
if msg.Code == 0 {
|
||||
h.logf("[unexpected] HTTPError %v did not contain an HTTP status code, sending internal server error", hErr)
|
||||
h.opts.Logf("[unexpected] HTTPError %v did not contain an HTTP status code, sending internal server error", hErr)
|
||||
msg.Code = http.StatusInternalServerError
|
||||
}
|
||||
http.Error(lw, hErr.Msg, msg.Code)
|
||||
@ -264,8 +275,9 @@ func (h retHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
}
|
||||
|
||||
if msg.Code != 200 || h.log200s {
|
||||
h.logf("%s", msg)
|
||||
if msg.Code != 200 || !h.opts.Quiet200s {
|
||||
h.opts.Logf("%s", msg)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -248,7 +248,7 @@ func TestStdHandler(t *testing.T) {
|
||||
clock.Reset()
|
||||
|
||||
rec := noopHijacker{httptest.NewRecorder(), false}
|
||||
h := stdHandler(test.rh, logf, clock.Now, true)
|
||||
h := StdHandlerOpts(test.rh, HandlerOptions{Logf: logf, Now: clock.Now})
|
||||
h.ServeHTTP(&rec, test.r)
|
||||
res := rec.Result()
|
||||
if res.StatusCode != test.wantCode {
|
||||
|
Loading…
Reference in New Issue
Block a user