fix(files): beschaedigte Downloads werden gemeldet und abgebrochen
Die Pruefsumme wurde beim Ausliefern mitgerechnet und das Ergebnis weggeworfen -- ein gekipptes Bit wurde erkannt und verschwiegen. Jetzt: Logeintrag mit Datei-ID, Speicherschluessel, erwarteter und gelesener Summe, dazu panic(http.ErrAbortHandler), den chis Recoverer ausdruecklich durchreicht. Damit das wirkt, werden die letzten 32 KiB zurueckgehalten. Sonst waere die Datei beim Erkennen laengst vollstaendig beim Empfaenger und der Abbruch kaeme zu spaet. Erst wenn die Summe stimmt, darf der Schluss hinterher; sonst bekommt die Gegenstelle weniger Bytes als angekuendigt und wertet das als Fehler statt als Datei. scripts/pruefsumme-selbsttest.py, 14 Pruefungen: kippt ein Bit auf der Platte (nicht im Programm), in der Mitte der Datei, damit es nicht schon an der Laenge auffaellt; zwei Groessen ueber und unter den 32 KiB; und zuerst die Gegenprobe, dass eine heile Datei durchkommt. **Dabei gefunden:** Der neue Logeintrag blieb aus, obwohl der Abbruch funktionierte. zerolog.Ctx liefert einen *abgeschalteten* Logger, wenn im Kontext keiner steckt -- und Aether legte nie einen hinein. Alle 34 log.Ctx-Aufrufe im Baum schrieben ins Nichts, darunter die Warnung ueber verwaiste Blobs beim Zurueckrollen einer Fassung. Behoben zweifach: zerolog.DefaultContextLogger beim Start (deckt auch Hintergrundarbeit ab) und ein Logger mit request_id im Anfragekontext. Zwei Tests halten es fest. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
c26bcba012
commit
2cc02941b9
7 files changed
+501
-10
No files matched your search
@@ -4,6 +4,8 @@ import (
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
chimiddleware "github.com/go-chi/chi/v5/middleware"
|
||||
|
||||
"github.com/rs/zerolog"
|
||||
"github.com/rs/zerolog/log"
|
||||
)
|
||||
@@ -13,6 +15,17 @@ func Logger(next http.Handler) http.Handler {
|
||||
start := time.Now()
|
||||
ww := &responseWriter{ResponseWriter: w, status: http.StatusOK}
|
||||
|
||||
// Den Logger in den Kontext hängen, damit log.Ctx(r.Context()) in den
|
||||
// Handlern etwas findet – und damit jede Zeile aus einer Anfrage die
|
||||
// Kennung dieser Anfrage trägt. Ohne das schreibt log.Ctx gar nicht
|
||||
// (zerolog gibt dann einen abgeschalteten Logger zurück), und mit
|
||||
// einem globalen Standard allein ließe sich nicht mehr zuordnen,
|
||||
// welche Meldung zu welchem Aufruf gehört.
|
||||
l := log.Logger.With().
|
||||
Str("request_id", chimiddleware.GetReqID(r.Context())).
|
||||
Logger()
|
||||
r = r.WithContext(l.WithContext(r.Context()))
|
||||
|
||||
next.ServeHTTP(ww, r)
|
||||
|
||||
level := zerolog.InfoLevel
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
package middleware
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/rs/zerolog"
|
||||
"github.com/rs/zerolog/log"
|
||||
)
|
||||
|
||||
// Der Test, der gefehlt hat.
|
||||
//
|
||||
// zerolog.Ctx liefert einen **abgeschalteten** Logger, wenn im Kontext keiner
|
||||
// steckt. 34 Aufrufe von log.Ctx(...) im Baum schrieben deshalb ins Nichts –
|
||||
// darunter Warnungen über verwaiste Blobs und beschädigte Dateien. Der Aufruf
|
||||
// sieht dabei völlig richtig aus; auffallen kann es nur, wenn man den Fehler
|
||||
// herbeiführt, den er melden soll.
|
||||
func TestLoggerHaengtLoggerInDenKontext(t *testing.T) {
|
||||
var aus bytes.Buffer
|
||||
alt := log.Logger
|
||||
log.Logger = zerolog.New(&aus)
|
||||
defer func() { log.Logger = alt }()
|
||||
|
||||
h := Logger(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
// Genau der Aufruf, der überall im Baum steht.
|
||||
log.Ctx(r.Context()).Error().Msg("kaputte-datei")
|
||||
}))
|
||||
|
||||
h.ServeHTTP(httptest.NewRecorder(), httptest.NewRequest("GET", "/x", nil))
|
||||
|
||||
if !strings.Contains(aus.String(), "kaputte-datei") {
|
||||
t.Fatalf("log.Ctx im Handler schrieb nichts. Ausgabe: %q", aus.String())
|
||||
}
|
||||
}
|
||||
|
||||
// Jede Zeile aus einer Anfrage soll deren Kennung tragen – sonst weiß man bei
|
||||
// zwei gleichzeitigen Downloads nicht, welche Meldung zu welchem gehört.
|
||||
func TestZeilenTragenDieAnfrageKennung(t *testing.T) {
|
||||
var aus bytes.Buffer
|
||||
alt := log.Logger
|
||||
log.Logger = zerolog.New(&aus)
|
||||
defer func() { log.Logger = alt }()
|
||||
|
||||
h := Logger(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
log.Ctx(r.Context()).Error().Msg("x")
|
||||
}))
|
||||
h.ServeHTTP(httptest.NewRecorder(), httptest.NewRequest("GET", "/x", nil))
|
||||
|
||||
if !strings.Contains(aus.String(), "request_id") {
|
||||
t.Fatalf("keine request_id in der Zeile: %q", aus.String())
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user