Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

log response size for websocket request #5140

Merged
merged 2 commits into from Feb 6, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
35 changes: 30 additions & 5 deletions modules/caddyhttp/responsewriter.go
Expand Up @@ -211,11 +211,7 @@ func (rr *responseRecorder) ReadFrom(r io.Reader) (int64, error) {
var n int64
var err error
if rr.stream {
if rf, ok := rr.ResponseWriter.(io.ReaderFrom); ok {
n, err = rf.ReadFrom(r)
} else {
n, err = io.Copy(rr.ResponseWriter, r)
}
n, err = rr.ResponseWriterWrapper.ReadFrom(r)
} else {
n, err = rr.buf.ReadFrom(r)
}
Expand Down Expand Up @@ -260,6 +256,35 @@ func (rr *responseRecorder) WriteResponse() error {
return err
}

func (rr *responseRecorder) Hijack() (net.Conn, *bufio.ReadWriter, error) {
conn, brw, err := rr.ResponseWriterWrapper.Hijack()
if err != nil {
return nil, nil, err
}
// Per http documentation, returned bufio.Writer is empty, but bufio.Read maybe not
conn = &hijackedConn{conn, rr}
brw.Writer.Reset(conn)
return conn, brw, nil
}

// used to track the size of hijacked response writers
type hijackedConn struct {
net.Conn
rr *responseRecorder
}

func (hc *hijackedConn) Write(p []byte) (int, error) {
n, err := hc.Conn.Write(p)
hc.rr.size += n
return n, err
}

func (hc *hijackedConn) ReadFrom(r io.Reader) (int64, error) {
n, err := io.Copy(hc.Conn, r)
hc.rr.size += int(n)
return n, err
}

// ResponseRecorder is a http.ResponseWriter that records
// responses instead of writing them to the client. See
// docs for NewResponseRecorder for proper usage.
Expand Down
15 changes: 6 additions & 9 deletions modules/caddyhttp/reverseproxy/streaming.go
Expand Up @@ -73,27 +73,24 @@ func (h Handler) handleUpgradeResponse(logger *zap.Logger, rw http.ResponseWrite
}()
defer close(backConnCloseCh)

// write header first, response headers should not be counted in size
// like the rest of handler chain.
copyHeader(rw.Header(), res.Header)
rw.WriteHeader(res.StatusCode)

logger.Debug("upgrading connection")
conn, brw, err := hj.Hijack()
if err != nil {
h.logger.Error("hijack failed on protocol switch", zap.Error(err))
return
}
defer conn.Close()

start := time.Now()
defer func() {
conn.Close()
logger.Debug("connection closed", zap.Duration("duration", time.Since(start)))
}()

copyHeader(rw.Header(), res.Header)

res.Header = rw.Header()
res.Body = nil // so res.Write only writes the headers; we have res.Body in backConn above
if err := res.Write(brw); err != nil {
h.logger.Debug("response write", zap.Error(err))
return
}
if err := brw.Flush(); err != nil {
h.logger.Debug("response flush", zap.Error(err))
return
Expand Down