Skip to content

Commit 7976f48

Browse files
committed
net/http: improve FileServer error logging
The errors returned during copying the file content in ServeContent, ServeFile and FileServer were ignored to avoid excessive, meaningless logging. This commit introduces error filtering and logging to ensure that the errors occurring during reading the content are logged. Updates #27128
1 parent 6c6ad30 commit 7976f48

File tree

3 files changed

+50
-1
lines changed

3 files changed

+50
-1
lines changed

src/net/http/export_test.go

+1
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ var (
2929
ExportErrRequestCanceledConn = errRequestCanceledConn
3030
ExportErrServerClosedIdle = errServerClosedIdle
3131
ExportServeFile = serveFile
32+
ExportCopyNIgnoreWriteError = copyNIgnoreWriteError
3233
ExportScanETag = scanETag
3334
ExportHttp2ConfigureServer = http2ConfigureServer
3435
Export_shouldCopyHeaderOnRedirect = shouldCopyHeaderOnRedirect

src/net/http/fs.go

+27-1
Original file line numberDiff line numberDiff line change
@@ -295,8 +295,34 @@ func serveContent(w ResponseWriter, r *Request, name string, modtime time.Time,
295295
w.WriteHeader(code)
296296

297297
if r.Method != "HEAD" {
298-
io.CopyN(w, sendContent, sendSize)
298+
if err := copyNIgnoreWriteError(w, sendContent, sendSize); err != nil {
299+
logf(r, "http: error copy content of %s: %v", name, err)
300+
}
301+
}
302+
}
303+
304+
// errorSaverReader wraps an io.Reader and saves the error returned
305+
// by the last invocation of Read in err
306+
type errorSaverReader struct {
307+
r io.Reader
308+
err error
309+
}
310+
311+
func (r *errorSaverReader) Read(b []byte) (int, error) {
312+
var n int
313+
n, r.err = r.r.Read(b)
314+
return n, r.err
315+
}
316+
317+
// copyNIgnoreWriteError copies n bytes (or until an error) from src to dst.
318+
// It returns only the errors encountered during reading from src.
319+
func copyNIgnoreWriteError(dst io.Writer, src io.Reader, n int64) error {
320+
er := &errorSaverReader{r: src}
321+
_, err := io.CopyN(dst, er, n)
322+
if err == io.EOF || err == er.err {
323+
return err
299324
}
325+
return nil
300326
}
301327

302328
// scanETag determines if a syntactically valid ETag is present at s. If so,

src/net/http/fs_test.go

+22
Original file line numberDiff line numberDiff line change
@@ -1285,6 +1285,28 @@ func (d fileServerCleanPathDir) Open(path string) (File, error) {
12851285

12861286
type panicOnSeek struct{ io.ReadSeeker }
12871287

1288+
func Test_copyNIgnoreWriteError(t *testing.T) {
1289+
e := errors.New("io error")
1290+
tests := []struct {
1291+
name string
1292+
w io.Writer
1293+
r io.Reader
1294+
n int64
1295+
wantErr error
1296+
}{
1297+
{"short read", ioutil.Discard, new(bytes.Buffer), 1, io.EOF},
1298+
{"read err", ioutil.Discard, errorReader{e}, 1, e},
1299+
{"no err", ioutil.Discard, strings.NewReader("content"), 3, nil},
1300+
{"write err", &net.IPConn{}, strings.NewReader("content"), 3, nil},
1301+
}
1302+
for _, test := range tests {
1303+
err := ExportCopyNIgnoreWriteError(test.w, test.r, test.n)
1304+
if err != test.wantErr {
1305+
t.Errorf("%s copyNIgnoreWriteError got %v, want %v", test.name, err, test.wantErr)
1306+
}
1307+
}
1308+
}
1309+
12881310
func Test_scanETag(t *testing.T) {
12891311
tests := []struct {
12901312
in string

0 commit comments

Comments
 (0)