fix: remove Content-Length from 200 responses to avoid RESTEasy buffering
Build & Deploy / build-and-deploy (push) Failing after 27s

RESTEasy Reactive may buffer the entire StreamingOutput when
Content-Length is set (to verify it). For a 1.2GB .jsdos file,
this loads the whole file into heap — hitting the 128MB Xmx
limit at ~10% and stalling via GC thrashing.

Full-file responses now use chunked transfer encoding (no
Content-Length), matching the original behavior. Content-Length
is still set for 206 Partial Content responses where the HTTP
spec requires it.
This commit is contained in:
Hermes Agent
2026-06-03 15:49:49 +02:00
parent 92d85376ac
commit db1879e22d
@@ -80,12 +80,11 @@ public class StaticResource {
return Response.serverError().build(); return Response.serverError().build();
} }
// No Range header — serve the full file (200 OK) // No Range header — serve the full file (200 OK, chunked encoding)
if (rangeHeader == null || rangeHeader.isBlank()) { if (rangeHeader == null || rangeHeader.isBlank()) {
Response.ResponseBuilder rb = Response.ok(new FileStream(file, 0, fileSize)) Response.ResponseBuilder rb = Response.ok(new FileStream(file, 0, fileSize))
.type(contentType) .type(contentType)
.header("Accept-Ranges", "bytes") .header("Accept-Ranges", "bytes");
.header("Content-Length", fileSize);
if (cacheControl != null) { if (cacheControl != null) {
rb.header("Cache-Control", cacheControl); rb.header("Cache-Control", cacheControl);
} }
@@ -131,12 +130,11 @@ public class StaticResource {
return rb.build(); return rb.build();
} }
/** Convenience: full-file 200 response. */ /** Convenience: full-file 200 response (chunked encoding, no Content-Length). */
private Response serveFull(Path file, String contentType, long fileSize, String cacheControl) { private Response serveFull(Path file, String contentType, long fileSize, String cacheControl) {
Response.ResponseBuilder rb = Response.ok(new FileStream(file, 0, fileSize)) Response.ResponseBuilder rb = Response.ok(new FileStream(file, 0, fileSize))
.type(contentType) .type(contentType)
.header("Accept-Ranges", "bytes") .header("Accept-Ranges", "bytes");
.header("Content-Length", fileSize);
if (cacheControl != null) { if (cacheControl != null) {
rb.header("Cache-Control", cacheControl); rb.header("Cache-Control", cacheControl);
} }