From 97cdd79baba55fd114cee883adaa8f7262231e91 Mon Sep 17 00:00:00 2001 From: Nuno Vieira Date: Mon, 28 May 2018 15:40:05 +0100 Subject: [PATCH] added content length header when downloading files via API #1212 --- .../core/common/ConsumesOutputStream.java | 1 - .../org/roda/core/common/DownloadUtils.java | 2 - .../org/roda/core/common/StreamResponse.java | 18 +++++++ .../wui/api/controllers/BrowserHelper.java | 3 +- .../org/roda/wui/api/v1/utils/ApiUtils.java | 51 +++++++++++-------- 5 files changed, 51 insertions(+), 24 deletions(-) diff --git a/roda-core/roda-core/src/main/java/org/roda/core/common/ConsumesOutputStream.java b/roda-core/roda-core/src/main/java/org/roda/core/common/ConsumesOutputStream.java index cb59d2e0f2..dcbc2a3b20 100644 --- a/roda-core/roda-core/src/main/java/org/roda/core/common/ConsumesOutputStream.java +++ b/roda-core/roda-core/src/main/java/org/roda/core/common/ConsumesOutputStream.java @@ -16,5 +16,4 @@ public interface ConsumesOutputStream { String getFileName(); String getMediaType(); - } diff --git a/roda-core/roda-core/src/main/java/org/roda/core/common/DownloadUtils.java b/roda-core/roda-core/src/main/java/org/roda/core/common/DownloadUtils.java index 86addff4ff..dfee782328 100644 --- a/roda-core/roda-core/src/main/java/org/roda/core/common/DownloadUtils.java +++ b/roda-core/roda-core/src/main/java/org/roda/core/common/DownloadUtils.java @@ -139,9 +139,7 @@ public String getFileName() { public String getMediaType() { return BIN_MEDIA_TYPE; } - }; - } return stream; diff --git a/roda-core/roda-core/src/main/java/org/roda/core/common/StreamResponse.java b/roda-core/roda-core/src/main/java/org/roda/core/common/StreamResponse.java index b34792452c..7d74477aec 100644 --- a/roda-core/roda-core/src/main/java/org/roda/core/common/StreamResponse.java +++ b/roda-core/roda-core/src/main/java/org/roda/core/common/StreamResponse.java @@ -10,6 +10,7 @@ public class StreamResponse implements EntityResponse { private String filename; private String mediaType; + private long fileSize = -1; private ConsumesOutputStream stream; public StreamResponse(String filename, String mediaType, ConsumesOutputStream stream) { @@ -19,6 +20,14 @@ public StreamResponse(String filename, String mediaType, ConsumesOutputStream st this.stream = stream; } + public StreamResponse(String filename, String mediaType, long fileSize, ConsumesOutputStream stream) { + super(); + this.filename = filename; + this.mediaType = mediaType; + this.fileSize = fileSize; + this.stream = stream; + } + public String getFilename() { return filename; } @@ -37,6 +46,14 @@ public void setMediaType(String mediaType) { this.mediaType = mediaType; } + public long getFileSize() { + return fileSize; + } + + public void setFileSize(long fileSize) { + this.fileSize = fileSize; + } + public ConsumesOutputStream getStream() { return stream; } @@ -45,4 +62,5 @@ public void setStream(ConsumesOutputStream stream) { this.stream = stream; } + } diff --git a/roda-ui/roda-wui/src/main/java/org/roda/wui/api/controllers/BrowserHelper.java b/roda-ui/roda-wui/src/main/java/org/roda/wui/api/controllers/BrowserHelper.java index 36288328a3..fedd6c87f3 100644 --- a/roda-ui/roda-wui/src/main/java/org/roda/wui/api/controllers/BrowserHelper.java +++ b/roda-ui/roda-wui/src/main/java/org/roda/wui/api/controllers/BrowserHelper.java @@ -1846,7 +1846,8 @@ public void consumeOutputStream(OutputStream out) throws IOException { } } }; - return new StreamResponse(filename, mediaType, stream); + + return new StreamResponse(filename, mediaType, iFile.getSize(), stream); } else if (iFile.isDirectory() && (RodaConstants.API_QUERY_VALUE_ACCEPT_FORMAT_ZIP.equals(acceptFormat) || RodaConstants.API_QUERY_VALUE_ACCEPT_FORMAT_BIN.equals(acceptFormat))) { Directory directory = RodaCoreFactory.getStorageService().getDirectory(filePath); diff --git a/roda-ui/roda-wui/src/main/java/org/roda/wui/api/v1/utils/ApiUtils.java b/roda-ui/roda-wui/src/main/java/org/roda/wui/api/v1/utils/ApiUtils.java index 906c6cc4e6..dad5ea5ce9 100644 --- a/roda-ui/roda-wui/src/main/java/org/roda/wui/api/v1/utils/ApiUtils.java +++ b/roda-ui/roda-wui/src/main/java/org/roda/wui/api/v1/utils/ApiUtils.java @@ -171,17 +171,21 @@ public static Response okResponse(StreamResponse streamResponse, CacheControl ca public static Response okResponse(StreamResponse streamResponse, CacheControl cacheControl, Date lastModifiedDate, boolean inline) { StreamingOutput so = new StreamingOutput() { - @Override public void write(OutputStream output) throws IOException, WebApplicationException { streamResponse.getStream().consumeOutputStream(output); - } }; - return Response.ok(so, streamResponse.getMediaType()) - .header(HttpHeaders.CONTENT_DISPOSITION, - contentDisposition(inline) + CONTENT_DISPOSITION_FILENAME_ARGUMENT + "\"" + streamResponse.getFilename() + "\"") - .cacheControl(cacheControl).lastModified(lastModifiedDate).build(); + + Response.ResponseBuilder response = Response.ok(so, streamResponse.getMediaType()).header( + HttpHeaders.CONTENT_DISPOSITION, + contentDisposition(inline) + CONTENT_DISPOSITION_FILENAME_ARGUMENT + "\"" + streamResponse.getFilename() + "\""); + + if (streamResponse.getFileSize() > 0) { + response.header(HttpHeaders.CONTENT_LENGTH, streamResponse.getFileSize()); + } + + return response.cacheControl(cacheControl).lastModified(lastModifiedDate).build(); } public static Response okResponse(StreamResponse streamResponse, CacheControl cacheControl, EntityTag tag) { @@ -191,17 +195,21 @@ public static Response okResponse(StreamResponse streamResponse, CacheControl ca public static Response okResponse(StreamResponse streamResponse, CacheControl cacheControl, EntityTag tag, boolean inline) { StreamingOutput so = new StreamingOutput() { - @Override public void write(OutputStream output) throws IOException, WebApplicationException { streamResponse.getStream().consumeOutputStream(output); - } }; - return Response.ok(so, streamResponse.getMediaType()) - .header(HttpHeaders.CONTENT_DISPOSITION, - contentDisposition(inline) + CONTENT_DISPOSITION_FILENAME_ARGUMENT + "\"" + streamResponse.getFilename() + "\"") - .cacheControl(cacheControl).tag(tag).build(); + + Response.ResponseBuilder response = Response.ok(so, streamResponse.getMediaType()).header( + HttpHeaders.CONTENT_DISPOSITION, + contentDisposition(inline) + CONTENT_DISPOSITION_FILENAME_ARGUMENT + "\"" + streamResponse.getFilename() + "\""); + + if (streamResponse.getFileSize() > 0) { + response.header(HttpHeaders.CONTENT_LENGTH, streamResponse.getFileSize()); + } + + return response.cacheControl(cacheControl).tag(tag).build(); } public static Response okResponse(StreamResponse streamResponse) { @@ -210,17 +218,21 @@ public static Response okResponse(StreamResponse streamResponse) { public static Response okResponse(StreamResponse streamResponse, boolean inline) { StreamingOutput so = new StreamingOutput() { - @Override public void write(OutputStream output) throws IOException, WebApplicationException { streamResponse.getStream().consumeOutputStream(output); - } }; - return Response.ok(so, streamResponse.getMediaType()) - .header(HttpHeaders.CONTENT_DISPOSITION, - contentDisposition(inline) + CONTENT_DISPOSITION_FILENAME_ARGUMENT + "\"" + streamResponse.getFilename() + "\"") - .build(); + + Response.ResponseBuilder response = Response.ok(so, streamResponse.getMediaType()).header( + HttpHeaders.CONTENT_DISPOSITION, + contentDisposition(inline) + CONTENT_DISPOSITION_FILENAME_ARGUMENT + "\"" + streamResponse.getFilename() + "\""); + + if (streamResponse.getFileSize() > 0) { + response.header(HttpHeaders.CONTENT_LENGTH, streamResponse.getFileSize()); + } + + return response.build(); } private static String contentDisposition(boolean inline) { @@ -247,7 +259,6 @@ public static URI getUriFromRequest(HttpServletRequest request) throws RODAExcep } } - @SuppressWarnings("unchecked") public static RODAObjectList indexedResultToRODAObjectList( Class objectClass, IndexResult result) throws RequestNotValidException, NotFoundException, GenericException, AuthorizationDeniedException { @@ -331,7 +342,7 @@ public static Response okResponse(T indexed, String accept } else if (RodaConstants.API_QUERY_VALUE_ACCEPT_FORMAT_JSON.equals(acceptFormat) || RodaConstants.API_QUERY_VALUE_ACCEPT_FORMAT_XML.equals(acceptFormat)) { AIP aip = RodaCoreFactory.getModelService().retrieveAIP(indexedAIP.getId()); - representation = new ObjectResponse(acceptFormat, aip); + representation = new ObjectResponse<>(acceptFormat, aip); } else { throw new GenericException("Unsupported class: " + acceptFormat); }