Fix concurrent map write panic in timeout middleware
- Add thread-safe header wrapper in timeoutWriter - Check context cancellation before writing responses in handlers - Protect header access after timeout with mutex - Prevents race condition when requests timeout while handlers are still running
This commit is contained in:
@@ -108,6 +108,7 @@ type timeoutWriter struct {
|
||||
http.ResponseWriter
|
||||
mu sync.Mutex
|
||||
written bool
|
||||
header http.Header // cached header to prevent concurrent access
|
||||
}
|
||||
|
||||
func (tw *timeoutWriter) Write(b []byte) (int, error) {
|
||||
@@ -133,6 +134,18 @@ func (tw *timeoutWriter) WriteHeader(statusCode int) {
|
||||
}
|
||||
|
||||
func (tw *timeoutWriter) Header() http.Header {
|
||||
tw.mu.Lock()
|
||||
defer tw.mu.Unlock()
|
||||
|
||||
if tw.written {
|
||||
// Return a copy to prevent modifications after timeout
|
||||
if tw.header == nil {
|
||||
tw.header = make(http.Header)
|
||||
}
|
||||
|
||||
return tw.header
|
||||
}
|
||||
|
||||
return tw.ResponseWriter.Header()
|
||||
}
|
||||
|
||||
@@ -153,6 +166,7 @@ func TimeoutMiddleware(timeout time.Duration) func(http.Handler) http.Handler {
|
||||
|
||||
tw := &timeoutWriter{
|
||||
ResponseWriter: w,
|
||||
header: make(http.Header),
|
||||
}
|
||||
|
||||
done := make(chan struct{})
|
||||
@@ -178,8 +192,12 @@ func TimeoutMiddleware(timeout time.Duration) func(http.Handler) http.Handler {
|
||||
tw.markWritten() // Prevent the handler from writing after timeout
|
||||
execTime := time.Since(startTime)
|
||||
|
||||
// Write directly to the underlying writer since we've marked tw as written
|
||||
// This is safe because markWritten() prevents the handler from writing
|
||||
tw.mu.Lock()
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
w.WriteHeader(http.StatusRequestTimeout)
|
||||
tw.mu.Unlock()
|
||||
|
||||
response := map[string]interface{}{
|
||||
"status": "error",
|
||||
|
||||
Reference in New Issue
Block a user