77 lines
1.7 KiB
Go
77 lines
1.7 KiB
Go
|
package missinggo
|
||
|
|
||
|
// todo move to httptoo as ResponseRecorder
|
||
|
|
||
|
import (
|
||
|
"bufio"
|
||
|
"net"
|
||
|
"net/http"
|
||
|
"time"
|
||
|
)
|
||
|
|
||
|
// A http.ResponseWriter that tracks the status of the response. The status
|
||
|
// code, and number of bytes written for example.
|
||
|
type StatusResponseWriter struct {
|
||
|
http.ResponseWriter
|
||
|
Code int
|
||
|
BytesWritten int64
|
||
|
Started time.Time
|
||
|
TimeToFirstByte time.Duration // Time to first byte
|
||
|
GotFirstByte bool
|
||
|
WroteHeader Event
|
||
|
Hijacked bool
|
||
|
}
|
||
|
|
||
|
var _ interface {
|
||
|
http.ResponseWriter
|
||
|
http.Hijacker
|
||
|
} = (*StatusResponseWriter)(nil)
|
||
|
|
||
|
func (me *StatusResponseWriter) Write(b []byte) (n int, err error) {
|
||
|
// Exactly how it's done in the standard library. This ensures Code is
|
||
|
// correct.
|
||
|
if !me.WroteHeader.IsSet() {
|
||
|
me.WriteHeader(http.StatusOK)
|
||
|
}
|
||
|
if me.Started.IsZero() {
|
||
|
panic("Started was not initialized")
|
||
|
}
|
||
|
timeBeforeWrite := time.Now()
|
||
|
n, err = me.ResponseWriter.Write(b)
|
||
|
if n > 0 && !me.GotFirstByte {
|
||
|
me.TimeToFirstByte = timeBeforeWrite.Sub(me.Started)
|
||
|
me.GotFirstByte = true
|
||
|
}
|
||
|
me.BytesWritten += int64(n)
|
||
|
return
|
||
|
}
|
||
|
|
||
|
func (me *StatusResponseWriter) WriteHeader(code int) {
|
||
|
me.ResponseWriter.WriteHeader(code)
|
||
|
if !me.WroteHeader.IsSet() {
|
||
|
me.Code = code
|
||
|
me.WroteHeader.Set()
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func (me *StatusResponseWriter) Hijack() (c net.Conn, b *bufio.ReadWriter, err error) {
|
||
|
me.Hijacked = true
|
||
|
c, b, err = me.ResponseWriter.(http.Hijacker).Hijack()
|
||
|
if b.Writer.Buffered() != 0 {
|
||
|
panic("unexpected buffered writes")
|
||
|
}
|
||
|
c = responseConn{c, me}
|
||
|
return
|
||
|
}
|
||
|
|
||
|
type responseConn struct {
|
||
|
net.Conn
|
||
|
s *StatusResponseWriter
|
||
|
}
|
||
|
|
||
|
func (me responseConn) Write(b []byte) (n int, err error) {
|
||
|
n, err = me.Conn.Write(b)
|
||
|
me.s.BytesWritten += int64(n)
|
||
|
return
|
||
|
}
|