incusd/response: Abort piped exports that fail mid-stream

The PipeResponse mechanism would always send an early header, then
process the piped data. That's done to avoid hitting a header submission
timeout.

The problem with that is that a failure is now being interpreted as
success by the client as there is no way to go back and change the HTTP
status code.

Instead, use a bit of a hack by aborting the connection entirely.

This is done through a scary panic() call which is intercepted by the Go
HTTP server and will cause the underlying connection to be terminated
without affecting the rest of the daemon.

Signed-off-by: Stéphane Graber <stgraber@stgraber.org>
This commit is contained in:
Stéphane Graber 2026-06-02 14:05:33 -04:00
parent 89c7b49297
commit 4ff2b98385
No known key found for this signature in database
GPG Key ID: C638974D64792D67

View File

@ -758,7 +758,14 @@ func (r *pipeResponse) Render(w http.ResponseWriter) error {
}
_, err := util.SafeCopy(w, r.reader)
return err
if err != nil {
// It's too late to send a clean error back to the client, so
// instead use the Go HTTP ErrAbortHandler logic to terminate the
// connection. This does not cause the daemon itself to panic.
panic(http.ErrAbortHandler)
}
return nil
}
// String returns a quick description of the response.