From 1a9e2e7d321ed6f62a8648d2ec98b96412f0936b Mon Sep 17 00:00:00 2001 From: Michael Rasmussen Date: Fri, 1 Dec 2023 05:02:28 +0200 Subject: [PATCH] Add Content-Range header to 206 Partial Content file response --- .../server/test/providers/FileTestCase.java | 20 ++++++++++++++++ .../serialisers/ServerFileBodyHandler.java | 23 +++++++++++++------ 2 files changed, 36 insertions(+), 7 deletions(-) diff --git a/extensions/resteasy-reactive/quarkus-resteasy-reactive/deployment/src/test/java/io/quarkus/resteasy/reactive/server/test/providers/FileTestCase.java b/extensions/resteasy-reactive/quarkus-resteasy-reactive/deployment/src/test/java/io/quarkus/resteasy/reactive/server/test/providers/FileTestCase.java index 80f99ddf1105d..a7feae8824879 100644 --- a/extensions/resteasy-reactive/quarkus-resteasy-reactive/deployment/src/test/java/io/quarkus/resteasy/reactive/server/test/providers/FileTestCase.java +++ b/extensions/resteasy-reactive/quarkus-resteasy-reactive/deployment/src/test/java/io/quarkus/resteasy/reactive/server/test/providers/FileTestCase.java @@ -45,17 +45,37 @@ public void testFiles() throws Exception { .then() .statusCode(206) .header(HttpHeaders.CONTENT_LENGTH, "10") + .header("Content-Range", "bytes 0-9/" + contentLength) .body(Matchers.equalTo(content.substring(0, 10))); RestAssured.given().header("Range", "bytes=10-19").get("/providers/file/file") .then() .statusCode(206) .header(HttpHeaders.CONTENT_LENGTH, "10") + .header("Content-Range", "bytes 10-19/" + contentLength) .body(Matchers.equalTo(content.substring(10, 20))); RestAssured.given().header("Range", "bytes=10-").get("/providers/file/file") .then() .statusCode(206) .header(HttpHeaders.CONTENT_LENGTH, String.valueOf(content.length() - 10)) + .header("Content-Range", "bytes 10-" + (content.length() - 1) + "/" + contentLength) .body(Matchers.equalTo(content.substring(10))); + RestAssured.given().header("Range", "bytes=-10").get("/providers/file/file") + .then() + .statusCode(206) + .header(HttpHeaders.CONTENT_LENGTH, "10") + .header("Content-Range", + "bytes " + (content.length() - 10) + "-" + (content.length() - 1) + "/" + contentLength) + .body(Matchers.equalTo(content.substring((content.length() - 10)))); + RestAssured.given().header("Range", "bytes=" + (content.length() + 1) + "-").get("/providers/file/file") + .then() + .statusCode(200) + .header(HttpHeaders.CONTENT_LENGTH, contentLength) + .body(Matchers.equalTo(content)); + RestAssured.given().header("Range", "bytes=0-1, 3-4").get("/providers/file/file") + .then() + .statusCode(200) + .header(HttpHeaders.CONTENT_LENGTH, contentLength) + .body(Matchers.equalTo(content)); RestAssured.get("/providers/file/file-partial") .then() .statusCode(200) diff --git a/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/providers/serialisers/ServerFileBodyHandler.java b/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/providers/serialisers/ServerFileBodyHandler.java index bd33ed659fda6..31158a025c3b4 100644 --- a/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/providers/serialisers/ServerFileBodyHandler.java +++ b/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/providers/serialisers/ServerFileBodyHandler.java @@ -42,16 +42,25 @@ static void sendFile(File file, ServerRequestContext context) { ResteasyReactiveRequestContext ctx = ((ResteasyReactiveRequestContext) context); Object rangeObj = ctx.getHeader("Range", true); ByteRange byteRange = rangeObj == null ? null : ByteRange.parse(rangeObj.toString()); + long fileLength = file.length(); if ((byteRange != null) && (byteRange.ranges.size() == 1)) { ByteRange.Range range = byteRange.ranges.get(0); - long length = range.getEnd() == -1 ? Long.MAX_VALUE : range.getEnd() - range.getStart() + 1; - context.serverResponse() - .setStatusCode(Response.Status.PARTIAL_CONTENT.getStatusCode()) - .sendFile(file.getAbsolutePath(), range.getStart(), length); - } else { - context.serverResponse().sendFile(file.getAbsolutePath(), 0, file.length()); + ByteRange.Range fileRange = (range.getStart() == -1) + ? new ByteRange.Range(fileLength - range.getEnd(), fileLength - 1) + : new ByteRange.Range(range.getStart(), Math.min(fileLength - 1, range.getEnd())); + + if ((fileRange.getStart() >= 0) && (fileRange.getStart() <= fileRange.getEnd())) { + String contentRange = "bytes " + fileRange.getStart() + "-" + fileRange.getEnd() + "/" + fileLength; + long length = fileRange.getEnd() - fileRange.getStart() + 1; + context.serverResponse() + .setStatusCode(Response.Status.PARTIAL_CONTENT.getStatusCode()) + .setResponseHeader("Content-Range", contentRange) + .sendFile(file.getAbsolutePath(), fileRange.getStart(), length); + return; + } } + context.serverResponse().sendFile(file.getAbsolutePath(), 0, fileLength); } /** @@ -138,7 +147,7 @@ public static ByteRange parse(String rangeHeader) { if (index + 1 < part.length()) { end = Long.parseLong(part.substring(index + 1)); } else { - end = -1; + end = Long.MAX_VALUE; } ranges.add(new Range(start, end)); }