fix(web): disable reverse-proxy buffering on SSE /events
Reverse proxies (OpenResty in front of minerva) buffer text/event-stream by default, holding events until the response ends. An SSE stream never ends, so the browser stays silent and WebUI pages never live-reload when reached via app.doctate.de — while a direct minerva.lan:3000 client (bypassing the proxy) works, explaining the desktop/Chromebook split. Emit X-Accel-Buffering: no on the /events response so the proxy streams it unbuffered; a direct client ignores the header. Return type widens from Sse<..> to impl IntoResponse to carry the header tuple. Regression guard: sse_integration asserts the header is present. refs #12
This commit is contained in:
@@ -66,3 +66,27 @@ async fn events_with_session_returns_sse_content_type() {
|
||||
"expected text/event-stream, got {ct:?}"
|
||||
);
|
||||
}
|
||||
|
||||
// Regression guard for #12: reverse proxies (nginx/OpenResty in front of
|
||||
// minerva) buffer `text/event-stream` by default, which holds events in
|
||||
// the proxy until the response ends — but an SSE response never ends, so
|
||||
// the browser stays silent and the page never live-reloads. The
|
||||
// `X-Accel-Buffering: no` response header tells the proxy to stream this
|
||||
// one response unbuffered. A direct client ignores the header harmlessly.
|
||||
#[tokio::test]
|
||||
async fn events_disables_proxy_buffering() {
|
||||
let app = test_app();
|
||||
let cookie = common::login(&app, "alice", "s").await;
|
||||
|
||||
let resp = app
|
||||
.oneshot(get_with_cookie(paths::EVENTS, &cookie))
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(resp.status(), StatusCode::OK);
|
||||
assert_eq!(
|
||||
header_opt(&resp, "x-accel-buffering"),
|
||||
Some("no"),
|
||||
"SSE response must disable reverse-proxy buffering"
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user