mirror of
https://github.com/gin-gonic/gin.git
synced 2025-04-06 03:57:46 +08:00
When the response has been written, the status code saved in `responseWriter` should no longer be changed by subsequent calls to `WriteHeader()`. This fixes for example the logging possibly showing the wrong status code, or any other middleware function checking the status code.
128 lines
2.6 KiB
Go
128 lines
2.6 KiB
Go
// Copyright 2014 Manu Martinez-Almeida. All rights reserved.
|
|
// Use of this source code is governed by a MIT style
|
|
// license that can be found in the LICENSE file.
|
|
|
|
package gin
|
|
|
|
import (
|
|
"bufio"
|
|
"io"
|
|
"net"
|
|
"net/http"
|
|
)
|
|
|
|
const (
|
|
noWritten = -1
|
|
defaultStatus = http.StatusOK
|
|
)
|
|
|
|
// ResponseWriter ...
|
|
type ResponseWriter interface {
|
|
http.ResponseWriter
|
|
http.Hijacker
|
|
http.Flusher
|
|
http.CloseNotifier
|
|
|
|
// Returns the HTTP response status code of the current request.
|
|
Status() int
|
|
|
|
// Returns the number of bytes already written into the response http body.
|
|
// See Written()
|
|
Size() int
|
|
|
|
// Writes the string into the response body.
|
|
WriteString(string) (int, error)
|
|
|
|
// Returns true if the response body was already written.
|
|
Written() bool
|
|
|
|
// Forces to write the http header (status code + headers).
|
|
WriteHeaderNow()
|
|
|
|
// get the http.Pusher for server push
|
|
Pusher() http.Pusher
|
|
}
|
|
|
|
type responseWriter struct {
|
|
http.ResponseWriter
|
|
size int
|
|
status int
|
|
}
|
|
|
|
var _ ResponseWriter = &responseWriter{}
|
|
|
|
func (w *responseWriter) reset(writer http.ResponseWriter) {
|
|
w.ResponseWriter = writer
|
|
w.size = noWritten
|
|
w.status = defaultStatus
|
|
}
|
|
|
|
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)
|
|
return
|
|
}
|
|
w.status = code
|
|
}
|
|
}
|
|
|
|
func (w *responseWriter) WriteHeaderNow() {
|
|
if !w.Written() {
|
|
w.size = 0
|
|
w.ResponseWriter.WriteHeader(w.status)
|
|
}
|
|
}
|
|
|
|
func (w *responseWriter) Write(data []byte) (n int, err error) {
|
|
w.WriteHeaderNow()
|
|
n, err = w.ResponseWriter.Write(data)
|
|
w.size += n
|
|
return
|
|
}
|
|
|
|
func (w *responseWriter) WriteString(s string) (n int, err error) {
|
|
w.WriteHeaderNow()
|
|
n, err = io.WriteString(w.ResponseWriter, s)
|
|
w.size += n
|
|
return
|
|
}
|
|
|
|
func (w *responseWriter) Status() int {
|
|
return w.status
|
|
}
|
|
|
|
func (w *responseWriter) Size() int {
|
|
return w.size
|
|
}
|
|
|
|
func (w *responseWriter) Written() bool {
|
|
return w.size != noWritten
|
|
}
|
|
|
|
// Hijack implements the http.Hijacker interface.
|
|
func (w *responseWriter) Hijack() (net.Conn, *bufio.ReadWriter, error) {
|
|
if w.size < 0 {
|
|
w.size = 0
|
|
}
|
|
return w.ResponseWriter.(http.Hijacker).Hijack()
|
|
}
|
|
|
|
// CloseNotify implements the http.CloseNotify interface.
|
|
func (w *responseWriter) CloseNotify() <-chan bool {
|
|
return w.ResponseWriter.(http.CloseNotifier).CloseNotify()
|
|
}
|
|
|
|
// Flush implements the http.Flush interface.
|
|
func (w *responseWriter) Flush() {
|
|
w.WriteHeaderNow()
|
|
w.ResponseWriter.(http.Flusher).Flush()
|
|
}
|
|
|
|
func (w *responseWriter) Pusher() (pusher http.Pusher) {
|
|
if pusher, ok := w.ResponseWriter.(http.Pusher); ok {
|
|
return pusher
|
|
}
|
|
return nil
|
|
}
|