mirror of
https://github.com/FiloSottile/age.git
synced 2026-08-29 12:17:19 +00:00
internal/inspect: handle reads after EOF in trackReader
trackReader.Read panicked if called again after a read returned io.EOF, which can happen with readers that do not return EOF consistently, such as a terminal after Ctrl-D. Latch the EOF instead, per the io.Reader contract, so count stays consistent with the file size. Fixes #719 Co-authored-by: Filippo Valsorda <hi@filippo.io>
This commit is contained in:
committed by
Filippo Valsorda
co-authored by
Filippo Valsorda
parent
6d29a923f3
commit
933c44d4d5
@@ -103,12 +103,13 @@ type trackReader struct {
|
||||
}
|
||||
|
||||
func (tr *trackReader) Read(p []byte) (int, error) {
|
||||
if tr.done {
|
||||
return 0, io.EOF
|
||||
}
|
||||
n, err := tr.r.Read(p)
|
||||
tr.count += int64(n)
|
||||
if err == io.EOF {
|
||||
tr.done = true
|
||||
} else if tr.done {
|
||||
panic("non-EOF read after EOF")
|
||||
}
|
||||
return n, err
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ package inspect
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"testing"
|
||||
|
||||
"filippo.io/age/internal/format"
|
||||
@@ -52,6 +53,44 @@ func TestInspectTagStanzas(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// readAfterEOFReader returns io.EOF along with the last of its data, and then
|
||||
// more data from subsequent Reads, like a terminal that received Ctrl-D
|
||||
// followed by more input.
|
||||
type readAfterEOFReader struct {
|
||||
data []byte
|
||||
eof bool
|
||||
}
|
||||
|
||||
func (r *readAfterEOFReader) Read(p []byte) (int, error) {
|
||||
if r.eof {
|
||||
return copy(p, "\n"), nil
|
||||
}
|
||||
n := copy(p, r.data)
|
||||
r.data = r.data[n:]
|
||||
if len(r.data) == 0 {
|
||||
r.eof = true
|
||||
return n, io.EOF
|
||||
}
|
||||
return n, nil
|
||||
}
|
||||
|
||||
func TestInspectReadAfterEOF(t *testing.T) {
|
||||
f := buildFile(t, "X25519")
|
||||
r := &readAfterEOFReader{data: f}
|
||||
md, err := Inspect(r, -1)
|
||||
if err != nil {
|
||||
t.Fatalf("Inspect: %v", err)
|
||||
}
|
||||
if md.Version != "age-encryption.org/v1" {
|
||||
t.Errorf("Version = %q, want age-encryption.org/v1", md.Version)
|
||||
}
|
||||
// If the reads after EOF were counted towards the file size, the extra
|
||||
// bytes would show up in the payload size.
|
||||
if md.Sizes.MinPayload != 0 {
|
||||
t.Errorf("MinPayload = %d, want 0", md.Sizes.MinPayload)
|
||||
}
|
||||
}
|
||||
|
||||
func TestStreamOverhead(t *testing.T) {
|
||||
tests := []struct {
|
||||
payloadSize int64
|
||||
|
||||
Reference in New Issue
Block a user