Skip to content

[BUG] LoggingHandler does not count response bytes written through ReadFrom #284

Open

Description

@jgehrcke

Responses served by http.FileServer, http.ServeFile and http.ServeContent may be logged with size 0 when ReadFrom() is involved. These copy the body with io.CopyN, which calls ReadFrom() when the ResponseWriter implements it (as net/http's HTTP/1.x writer does).

The writer from makeLogger comes from httpsnoop.Wrap, which exposes the underlying ReadFrom, so io.Copy calls ReadFrom and bypasses responseLogger.Write.

A repro is below.

ReadFrom is (well, should be :-)) involved e.g. when a server wants to serve the response or parts of the response straight from a file descriptor (On Linux this makes golang use sendfile() which can have significant performance impact; of positive nature).

Possible patch (if we still land patches in this project): add a ReadFrom hook in makeLogger that calls the original ReadFrom with the original reader (and does the right book-keeping otherwise).

#207 proposed this hook in 2020; the stale bot closed it :-). There are still projects out there that use gorilla, and I wonder if we can maybe still patch this. I'd be happy to submit a fresh PR.

Repro

http.ServeContent with a strings.Reader goes down the io.CopyN -> ReadFrom path.

package main

import (
        "fmt"
        "io"
        "net/http"
        "net/http/httptest"
        "os"
        "strings"
        "time"

        "github.com/gorilla/handlers"
)

func main() {
        h := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
                http.ServeContent(w, r, "", time.Time{}, strings.NewReader("hello, world"))
        })
        srv := httptest.NewServer(handlers.LoggingHandler(os.Stdout, h))
        resp, err := http.Get(srv.URL)
        if err != nil {
                panic(err)
        }
        body, _ := io.ReadAll(resp.Body)
        resp.Body.Close()
        srv.Close()
        fmt.Println("body bytes:", len(body))
}

Output, with handlers v1.5.2 and Go 1.26.3:

127.0.0.1 - - [23/Oct/2026:12:51:19 +0000] "GET / HTTP/1.1" 200 0
body bytes: 12
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions