fix(replay): a truncated index is a 500, not a partial 200

readAll reimplemented io.ReadAll and swallowed every error but fs.ErrInvalid,
returning the bytes it had managed to read with a nil error, so a half-written
index.html was indistinguishable from a whole one. io.ReadAll surfaces the
directory-handle case fs.ErrInvalid covered as well.
This commit is contained in:
pj committed 2026-08-22 21:07:58 +05:30
1 parent dbd57ef989
commit 30febb78b8
2 files changed
+51 -20

No files matched your search

+49
View File
@@ -371,6 +371,55 @@ func TestAssets_FallbackToIndexHTML(t *testing.T) {
}
}
type truncatedIndexFS struct {
prefix []byte
}
func (assets truncatedIndexFS) Open(name string) (fs.File, error) {
if name != "index.html" {
return nil, fs.ErrNotExist
}
return &truncatedIndexFile{prefix: assets.prefix}, nil
}
type truncatedIndexFile struct {
prefix []byte
consumed bool
}
func (file *truncatedIndexFile) Stat() (fs.FileInfo, error) { return nil, fs.ErrInvalid }
func (file *truncatedIndexFile) Read(destination []byte) (int, error) {
if file.consumed {
return 0, io.ErrUnexpectedEOF
}
file.consumed = true
return copy(destination, file.prefix), nil
}
func (file *truncatedIndexFile) Close() error { return nil }
func TestAssets_TruncatedIndexIsNotServedAsOK(t *testing.T) {
prefix := []byte(`<!doctype html><html><body><div id="root">`)
server, err := NewServer(ServerOptions{
RunsDirectory: t.TempDir(),
AssetsFS: truncatedIndexFS{prefix: prefix},
})
if err != nil {
t.Fatal(err)
}
recorder := httptest.NewRecorder()
request := httptest.NewRequest(http.MethodGet, "/", nil)
server.Handler().ServeHTTP(recorder, request)
if recorder.Code != http.StatusInternalServerError {
t.Errorf("status = %d, want 500", recorder.Code)
}
if strings.Contains(recorder.Body.String(), string(prefix)) {
t.Errorf("served the partial index body: %q", recorder.Body.String())
}
}
func TestAssets_API404DoesNotFallThrough(t *testing.T) {
server, _ := newFixtureServer(t)
recorder := httptest.NewRecorder()