gin-contrib / timeout

Timeout middleware for Gin
MIT License
185 stars 38 forks source link

when i download excel, timeout middleware lead to response to failed #38

Open gaozhenyusky opened 2 years ago

gaozhenyusky commented 2 years ago

Description

I use gin and reverse_proxy to make a gateway, as well i use gin-contrib/timeout to Preventing Gateway timeouts.

but when i request to download .xls file, it show me the debug log: '[GIN-debug] [WARNING] Headers were already written. Wanted to override status code 404 with 200'

if i not use gin-contrib/timeout , it`s download excel ok

How to reproduce

I found this code tw.ResponseWriter.WriteHeader(tw.code) will debug log

package middleware

import (
    "github.com/gin-gonic/gin"
)

select {
        case p := <-panicChan:
            tw.FreeBuffer()
            c.Writer = w
            panic(p)

        case <-finish:
            c.Next()
            tw.mu.Lock()
            defer tw.mu.Unlock()
            dst := tw.ResponseWriter.Header()
            for k, vv := range tw.Header() {
                dst[k] = vv
            }
            tw.ResponseWriter.WriteHeader(tw.code)
            if _, err := tw.ResponseWriter.Write(buffer.Bytes()); err != nil {
                panic(err)
            }
            tw.FreeBuffer()
            bufPool.Put(buffer)

        case <-time.After(t.timeout):
            c.Abort()
            tw.mu.Lock()
            defer tw.mu.Unlock()
            tw.timeout = true
            tw.FreeBuffer()
            bufPool.Put(buffer)

            c.Writer = w
            t.response(c)
            c.Writer = tw
        }

And when i download excel file , it flushed, and use func WriteHeaderNow to make w.size = 0, it lead to my request failed with 404 statusCode

package gin

import (
    "bufio"
    "io"
    "net"
    "net/http"
)

const (
    noWritten     = -1
    defaultStatus = http.StatusOK
)

func (w *responseWriter) WriteHeader(code int) {
    if code > 0 && w.status != code {
        if w.Written() {
            debugPrint("[WARNING] Headers were already written. Wanted to override status code %d with %d", w.status, code)
        }
        w.status = code
    }
}

func (w *responseWriter) Written() bool {
    return w.size != noWritten
}

func (w *responseWriter) Flush() {
    w.WriteHeaderNow()
    w.ResponseWriter.(http.Flusher).Flush()
}

func (w *responseWriter) WriteHeaderNow() {
    if !w.Written() {
        w.size = 0
        w.ResponseWriter.WriteHeader(w.status)
    }
}

Expectations

i hope someone can teach me how to solve this problem, thx )

Environment