diff --git a/basyx.submodelrepository/basyx.submodelrepository-http/src/main/java/org/eclipse/digitaltwin/basyx/submodelrepository/http/SubmodelRepositoryApiHTTPController.java b/basyx.submodelrepository/basyx.submodelrepository-http/src/main/java/org/eclipse/digitaltwin/basyx/submodelrepository/http/SubmodelRepositoryApiHTTPController.java index c6039bdb5..2fb171111 100644 --- a/basyx.submodelrepository/basyx.submodelrepository-http/src/main/java/org/eclipse/digitaltwin/basyx/submodelrepository/http/SubmodelRepositoryApiHTTPController.java +++ b/basyx.submodelrepository/basyx.submodelrepository-http/src/main/java/org/eclipse/digitaltwin/basyx/submodelrepository/http/SubmodelRepositoryApiHTTPController.java @@ -55,6 +55,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.core.io.FileSystemResource; import org.springframework.core.io.Resource; +import org.springframework.http.HttpHeaders; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.PathVariable; @@ -214,7 +215,11 @@ public ResponseEntity getSubmodelByIdMetadata(Base64UrlEncodedIdentifi public ResponseEntity getFileByPath(Base64UrlEncodedIdentifier submodelIdentifier, String idShortPath) { Resource resource = new FileSystemResource(repository.getFileByPathSubmodel(submodelIdentifier.getIdentifier(), idShortPath)); - return new ResponseEntity(resource, HttpStatus.OK); + String fileName = resource.getFilename(); + + return ResponseEntity.ok() + .header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + fileName + "\"") + .body(resource); } @Override diff --git a/basyx.submodelrepository/basyx.submodelrepository-http/src/test/java/org/eclipse/digitaltwin/basyx/submodelrepository/http/SubmodelRepositorySubmodelHTTPTestSuite.java b/basyx.submodelrepository/basyx.submodelrepository-http/src/test/java/org/eclipse/digitaltwin/basyx/submodelrepository/http/SubmodelRepositorySubmodelHTTPTestSuite.java index 4bc035603..019f099a8 100644 --- a/basyx.submodelrepository/basyx.submodelrepository-http/src/test/java/org/eclipse/digitaltwin/basyx/submodelrepository/http/SubmodelRepositorySubmodelHTTPTestSuite.java +++ b/basyx.submodelrepository/basyx.submodelrepository-http/src/test/java/org/eclipse/digitaltwin/basyx/submodelrepository/http/SubmodelRepositorySubmodelHTTPTestSuite.java @@ -27,6 +27,7 @@ import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; import java.io.FileNotFoundException; import java.io.IOException; @@ -42,6 +43,7 @@ import org.apache.hc.client5.http.impl.classic.CloseableHttpResponse; import org.apache.hc.client5.http.impl.classic.HttpClients; import org.apache.hc.core5.http.ContentType; +import org.apache.hc.core5.http.Header; import org.apache.hc.core5.http.HttpEntity; import org.apache.hc.core5.http.ParseException; import org.apache.hc.core5.http.ProtocolException; @@ -355,6 +357,7 @@ public void deleteFileFromNotExistElement() throws FileNotFoundException, Unsupp @Test public void getFile() throws FileNotFoundException, IOException, ParseException { String fileName = DummySubmodelFactory.FILE_NAME; + String expectedFileName = Base64UrlEncodedIdentifier.encodeIdentifier(DummySubmodelFactory.SUBMODEL_FOR_FILE_TEST) + "-" + DummySubmodelFactory.SUBMODEL_ELEMENT_FILE_ID_SHORT + "-" + fileName; byte[] expectedFile = readBytesFromClasspath(fileName); @@ -363,6 +366,14 @@ public void getFile() throws FileNotFoundException, IOException, ParseException CloseableHttpResponse response = BaSyxHttpTestUtils.executeGetOnURL(createSMEFileGetURL(DummySubmodelFactory.SUBMODEL_FOR_FILE_TEST, DummySubmodelFactory.SUBMODEL_ELEMENT_FILE_ID_SHORT)); assertEquals(HttpStatus.OK.value(), response.getCode()); + Header contentDispositionHeader = response.getFirstHeader("Content-Disposition"); + assertNotNull(contentDispositionHeader); + + String contentDisposition = contentDispositionHeader.getValue(); + String actualFileName = extractFileNameFromContentDisposition(contentDisposition); + + assertEquals(expectedFileName, actualFileName); + byte[] actualFile = EntityUtils.toByteArray(response.getEntity()); response.close(); @@ -384,6 +395,16 @@ public void getFileFromNotExistElement() throws FileNotFoundException, Unsupport assertEquals(HttpStatus.NOT_FOUND.value(), response.getCode()); } + private String extractFileNameFromContentDisposition(String contentDisposition) { + for (String part : contentDisposition.split(";")) { + part = part.trim(); + if (part.startsWith("filename")) { + return part.split("=")[1].replace("\"", "").trim(); + } + } + return null; + } + private String getJSONWithoutCursorInfo(String response) throws JsonMappingException, JsonProcessingException { return BaSyxHttpTestUtils.removeCursorFromJSON(response); }