ipn/localapi: fix panic after handler returns

Change-Id: I612f9ebf78d962e094bff908670b3ffd89f756e5
Signed-off-by: Andrew Dunham <andrew@du.nham.ca>
This commit is contained in:
Andrew Dunham 2023-03-04 13:03:03 -05:00
parent 1a30b2d73f
commit 69f9c17555

View File

@ -637,7 +637,10 @@ func (h *Handler) serveDebugPortmap(w http.ResponseWriter, r *http.Request) {
return return
} }
var logLock sync.Mutex var (
logLock sync.Mutex
handlerDone bool
)
logf := func(format string, args ...any) { logf := func(format string, args ...any) {
if !strings.HasSuffix(format, "\n") { if !strings.HasSuffix(format, "\n") {
format = format + "\n" format = format + "\n"
@ -646,12 +649,25 @@ func (h *Handler) serveDebugPortmap(w http.ResponseWriter, r *http.Request) {
logLock.Lock() logLock.Lock()
defer logLock.Unlock() defer logLock.Unlock()
// The portmapper can call this log function after the HTTP
// handler returns, which is not allowed and can cause a panic.
// If this happens, ignore the log lines since this typically
// occurs due to a client disconnect.
if handlerDone {
return
}
// Write and flush each line to the client so that output is streamed // Write and flush each line to the client so that output is streamed
fmt.Fprintf(w, format, args...) fmt.Fprintf(w, format, args...)
if f, ok := w.(http.Flusher); ok { if f, ok := w.(http.Flusher); ok {
f.Flush() f.Flush()
} }
} }
defer func() {
logLock.Lock()
handlerDone = true
logLock.Unlock()
}()
ctx, cancel := context.WithTimeout(r.Context(), dur) ctx, cancel := context.WithTimeout(r.Context(), dur)
defer cancel() defer cancel()