diff --git a/src/main/java/sh/rhiobet/lalafin/file/FileServeService.java b/src/main/java/sh/rhiobet/lalafin/file/FileServeService.java index 16bdfda..0397a73 100644 --- a/src/main/java/sh/rhiobet/lalafin/file/FileServeService.java +++ b/src/main/java/sh/rhiobet/lalafin/file/FileServeService.java @@ -46,10 +46,11 @@ public class FileServeService { } public Response serveFile(FileInfo fileInfo, String range) { + FileChannel channel = null; try { Path path = Paths.get(fileApiConfiguration.directory(), URLDecoder.decode(fileInfo.directUrl, StandardCharsets.UTF_8)); - FileChannel channel = FileChannel.open(path); + channel = FileChannel.open(path); ResponseBuilder response; long fileSize = channel.size(); if (range != null) { @@ -64,13 +65,15 @@ public class FileServeService { rangeEnd = Long.parseLong(rangeSplitted[1]); } if (rangeEnd + 1 > fileSize) { + channel.close(); return Response.status( Response.Status.REQUESTED_RANGE_NOT_SATISFIABLE).build(); } - InputStream is = Channels.newInputStream(channel); - is.skip(rangeStart); + response = Response.ok(path.toFile()); - response.entity(is.readNBytes((int) (rangeEnd + 1 - rangeStart))); + response.entity(new FileServeInputStream(Channels.newInputStream(channel), + rangeStart, rangeEnd)); + response.header("Content-Length", Long.toString(rangeEnd + 1 - rangeStart)); response.status(Response.Status.PARTIAL_CONTENT); @@ -79,6 +82,7 @@ public class FileServeService { } else { response = Response.ok(path.toFile()); response.header("Content-Length", Long.toString(fileSize)); + channel.close(); } response.header("Accept-Ranges", "bytes"); response.header("Content-Disposition", @@ -89,8 +93,52 @@ public class FileServeService { } return response.build(); } catch (IOException e) { + try { + channel.close(); + } catch (Exception ignored) {} return Response.status(Response.Status.INTERNAL_SERVER_ERROR).build(); } } } + +class FileServeInputStream extends InputStream { + private InputStream is; + private long remaining; + + public FileServeInputStream(InputStream is, long startRange, long endRange) throws IOException { + this.is = is; + try { + this.is.skip(startRange); + } catch (IOException e) { + try { + this.is.close(); + } catch (Exception ignored) {} + throw e; + } + this.remaining = endRange + 1 - startRange; + } + + @Override + public int read(byte[] buffer) throws IOException { + if (this.remaining == 0) { + this.is.close(); + return -1; + } else { + int read = this.is.read(buffer, 0, (int) Math.min(buffer.length, this.remaining)); + this.remaining -= read; + return read; + } + } + + @Override + public int read() throws IOException { + if (this.remaining > 0) { + this.remaining--; + return this.is.read(); + } else { + this.is.close(); + return -1; + } + } +} \ No newline at end of file