mirror of
https://github.com/tailscale/tailscale.git
synced 2025-04-16 11:41:39 +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
|
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.
|
// StdHandler converts a ReturnHandler into a standard http.Handler.
|
||||||
// Handled requests are logged using logf, as are any errors. Errors
|
// Handled requests are logged using logf, as are any errors. Errors
|
||||||
// are handled as specified by the Handler interface.
|
// are handled as specified by the Handler interface.
|
||||||
func StdHandler(h ReturnHandler, logf logger.Logf) http.Handler {
|
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
|
// 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
|
// StdHandlerNo200s is like StdHandler, but successfully handled HTTP
|
||||||
// requests don't write an access log entry to logf.
|
// 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 {
|
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 {
|
// StdHandlerOpts converts a ReturnHandler into a standard http.Handler.
|
||||||
return retHandler{h, logf, now, log200s}
|
// 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.
|
// retHandler is an http.Handler that wraps a Handler and handles errors.
|
||||||
type retHandler struct {
|
type retHandler struct {
|
||||||
rh ReturnHandler
|
rh ReturnHandler
|
||||||
logf logger.Logf
|
opts HandlerOptions
|
||||||
timeNow func() time.Time
|
|
||||||
log200s bool
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ServeHTTP implements the http.Handler interface.
|
// ServeHTTP implements the http.Handler interface.
|
||||||
func (h retHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
func (h retHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||||
msg := AccessLogRecord{
|
msg := AccessLogRecord{
|
||||||
When: h.timeNow(),
|
When: h.opts.Now(),
|
||||||
RemoteAddr: r.RemoteAddr,
|
RemoteAddr: r.RemoteAddr,
|
||||||
Proto: r.Proto,
|
Proto: r.Proto,
|
||||||
TLS: r.TLS != nil,
|
TLS: r.TLS != nil,
|
||||||
@ -209,7 +220,7 @@ func (h retHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
|||||||
Referer: r.Referer(),
|
Referer: r.Referer(),
|
||||||
}
|
}
|
||||||
|
|
||||||
lw := &loggingResponseWriter{ResponseWriter: w, logf: h.logf}
|
lw := &loggingResponseWriter{ResponseWriter: w, logf: h.opts.Logf}
|
||||||
err := h.rh.ServeHTTPReturn(lw, r)
|
err := h.rh.ServeHTTPReturn(lw, r)
|
||||||
hErr, hErrOK := err.(HTTPError)
|
hErr, hErrOK := err.(HTTPError)
|
||||||
|
|
||||||
@ -219,7 +230,7 @@ func (h retHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
|||||||
lw.code = 200
|
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.Code = lw.code
|
||||||
msg.Bytes = lw.bytes
|
msg.Bytes = lw.bytes
|
||||||
|
|
||||||
@ -245,12 +256,12 @@ func (h retHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if lw.code != 0 {
|
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
|
break
|
||||||
}
|
}
|
||||||
msg.Code = hErr.Code
|
msg.Code = hErr.Code
|
||||||
if msg.Code == 0 {
|
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
|
msg.Code = http.StatusInternalServerError
|
||||||
}
|
}
|
||||||
http.Error(lw, hErr.Msg, msg.Code)
|
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 {
|
if msg.Code != 200 || !h.opts.Quiet200s {
|
||||||
h.logf("%s", msg)
|
h.opts.Logf("%s", msg)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -248,7 +248,7 @@ func TestStdHandler(t *testing.T) {
|
|||||||
clock.Reset()
|
clock.Reset()
|
||||||
|
|
||||||
rec := noopHijacker{httptest.NewRecorder(), false}
|
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)
|
h.ServeHTTP(&rec, test.r)
|
||||||
res := rec.Result()
|
res := rec.Result()
|
||||||
if res.StatusCode != test.wantCode {
|
if res.StatusCode != test.wantCode {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user