Loading pom.xml +1 −1 Original line number Original line Diff line number Diff line Loading @@ -5,7 +5,7 @@ <parent> <parent> <groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.2.6.RELEASE</version> <version>2.4.5</version> <relativePath/> <!-- lookup parent from repository --> <relativePath/> <!-- lookup parent from repository --> </parent> </parent> <groupId>it.inaf.ia2</groupId> <groupId>it.inaf.ia2</groupId> Loading src/main/java/it/inaf/ia2/transfer/controller/ArchiveFileController.java +4 −4 Original line number Original line Diff line number Diff line Loading @@ -25,7 +25,7 @@ import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController; @RestController @RestController public class ArchiveFileController { public class ArchiveFileController extends FileController { @Autowired @Autowired private ArchiveService archiveService; private ArchiveService archiveService; Loading @@ -48,7 +48,7 @@ public class ArchiveFileController { job.setVosPaths(archiveRequest.getPaths()); job.setVosPaths(archiveRequest.getPaths()); CompletableFuture.runAsync(() -> { CompletableFuture.runAsync(() -> { archiveService.createArchive(job); handleFileJob(() -> archiveService.createArchive(job), job.getJobId()); }); }); HttpHeaders headers = new HttpHeaders(); HttpHeaders headers = new HttpHeaders(); Loading @@ -57,12 +57,12 @@ public class ArchiveFileController { } } @GetMapping(value = "/archive/{fileName}") @GetMapping(value = "/archive/{fileName}") public ResponseEntity<?> getArchiveFile(@PathVariable("fileName") String fileName) { public void getArchiveFile(@PathVariable("fileName") String fileName) { TokenPrincipal principal = (TokenPrincipal) request.getUserPrincipal(); TokenPrincipal principal = (TokenPrincipal) request.getUserPrincipal(); File file = archiveService.getArchiveParentDir(principal).toPath().resolve(fileName).toFile(); File file = archiveService.getArchiveParentDir(principal).toPath().resolve(fileName).toFile(); return FileResponseUtil.getFileResponse(response, file); FileResponseUtil.getFileResponse(response, file); } } } } src/main/java/it/inaf/ia2/transfer/controller/FileController.java +32 −0 Original line number Original line Diff line number Diff line Loading @@ -5,18 +5,28 @@ */ */ package it.inaf.ia2.transfer.controller; package it.inaf.ia2.transfer.controller; import it.inaf.ia2.transfer.exception.JobException; import it.inaf.ia2.transfer.persistence.JobDAO; import java.net.URLDecoder; import java.net.URLDecoder; import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets; import java.util.Arrays; import java.util.Arrays; import java.util.stream.Collectors; import java.util.stream.Collectors; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest; import net.ivoa.xml.uws.v1.ExecutionPhase; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired; public abstract class FileController { public abstract class FileController { private static final Logger LOG = LoggerFactory.getLogger(FileController.class); @Autowired @Autowired protected HttpServletRequest request; protected HttpServletRequest request; @Autowired private JobDAO jobDAO; public String getPath() { public String getPath() { String uri = request.getRequestURI().substring(request.getContextPath().length()); String uri = request.getRequestURI().substring(request.getContextPath().length()); Loading @@ -26,4 +36,26 @@ public abstract class FileController { .map(p -> URLDecoder.decode(p, StandardCharsets.UTF_8)) .map(p -> URLDecoder.decode(p, StandardCharsets.UTF_8)) .collect(Collectors.toList())); .collect(Collectors.toList())); } } public void handleFileJob(Runnable action, String jobId) { try { action.run(); if (jobId != null) { jobDAO.updateJobPhase(ExecutionPhase.COMPLETED, jobId); } } catch (Throwable t) { JobException jobException; if (t instanceof JobException) { jobException = (JobException) t; } else { LOG.error("Unexpected error happened", t); jobException = new JobException(JobException.Type.FATAL, "Internal Fault") .setErrorDetail("InternalFault: Unexpected error happened"); } if (jobId != null) { jobDAO.setJobError(jobId, jobException); } throw t; } } } } src/main/java/it/inaf/ia2/transfer/controller/FileResponseUtil.java +11 −10 Original line number Original line Diff line number Diff line Loading @@ -5,6 +5,8 @@ */ */ package it.inaf.ia2.transfer.controller; package it.inaf.ia2.transfer.controller; import it.inaf.ia2.transfer.exception.FileNotFoundException; import it.inaf.ia2.transfer.exception.JobException; import java.io.File; import java.io.File; import java.io.FileInputStream; import java.io.FileInputStream; import java.io.IOException; import java.io.IOException; Loading @@ -16,32 +18,32 @@ import java.nio.charset.StandardCharsets; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponse; import org.slf4j.Logger; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory; import static org.springframework.http.HttpStatus.INTERNAL_SERVER_ERROR; import static org.springframework.http.HttpStatus.NOT_FOUND; import org.springframework.http.ResponseEntity; public class FileResponseUtil { public class FileResponseUtil { private static final Logger LOG = LoggerFactory.getLogger(FileResponseUtil.class); private static final Logger LOG = LoggerFactory.getLogger(FileResponseUtil.class); public static ResponseEntity<?> getFileResponse(HttpServletResponse response, File file) { public static void getFileResponse(HttpServletResponse response, File file) { return getFileResponse(response, file, null); getFileResponse(response, file, null); } } public static ResponseEntity<?> getFileResponse(HttpServletResponse response, File file, String fileName) { public static void getFileResponse(HttpServletResponse response, File file, String vosPath) { String fileName = vosPath == null ? file.getName() : vosPath.substring(vosPath.lastIndexOf("/") + 1); if (!file.exists()) { if (!file.exists()) { LOG.error("File not found: " + file.getAbsolutePath()); LOG.error("File not found: " + file.getAbsolutePath()); return new ResponseEntity<>("File " + file.getName() + " not found", NOT_FOUND); throw new FileNotFoundException(vosPath == null ? file.getAbsolutePath() : vosPath); } } if (!file.canRead()) { if (!file.canRead()) { LOG.error("File not readable: " + file.getAbsolutePath()); LOG.error("File not readable: " + file.getAbsolutePath()); return new ResponseEntity<>("File " + file.getName() + " is not readable", INTERNAL_SERVER_ERROR); throw new JobException(JobException.Type.FATAL, "Internal Fault") .setErrorDetail("InternalFault: File " + file.getName() + " is not readable"); } } response.setHeader("Content-Disposition", "attachment; filename=" response.setHeader("Content-Disposition", "attachment; filename=" + URLEncoder.encode(fileName == null ? file.getName() : fileName, StandardCharsets.UTF_8)); + URLEncoder.encode(fileName, StandardCharsets.UTF_8)); response.setHeader("Content-Length", String.valueOf(file.length())); response.setHeader("Content-Length", String.valueOf(file.length())); response.setCharacterEncoding("UTF-8"); response.setCharacterEncoding("UTF-8"); Loading @@ -54,6 +56,5 @@ public class FileResponseUtil { } catch (IOException ex) { } catch (IOException ex) { throw new UncheckedIOException(ex); throw new UncheckedIOException(ex); } } return null; } } } } src/main/java/it/inaf/ia2/transfer/controller/GetFileController.java +30 −19 Original line number Original line Diff line number Diff line Loading @@ -7,7 +7,11 @@ package it.inaf.ia2.transfer.controller; import it.inaf.ia2.transfer.persistence.model.FileInfo; import it.inaf.ia2.transfer.persistence.model.FileInfo; import it.inaf.ia2.transfer.auth.TokenPrincipal; import it.inaf.ia2.transfer.auth.TokenPrincipal; import it.inaf.ia2.transfer.exception.FileNotFoundException; import it.inaf.ia2.transfer.exception.InvalidArgumentException; import it.inaf.ia2.transfer.exception.PermissionDeniedException; import it.inaf.ia2.transfer.persistence.FileDAO; import it.inaf.ia2.transfer.persistence.FileDAO; import it.inaf.ia2.transfer.persistence.JobDAO; import it.inaf.ia2.transfer.service.AuthorizationService; import it.inaf.ia2.transfer.service.AuthorizationService; import java.io.File; import java.io.File; import java.util.Optional; import java.util.Optional; Loading @@ -15,10 +19,8 @@ import javax.servlet.http.HttpServletResponse; import org.slf4j.Logger; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired; import static org.springframework.http.HttpStatus.NOT_FOUND; import static org.springframework.http.HttpStatus.UNAUTHORIZED; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController; @RestController @RestController Loading @@ -29,6 +31,9 @@ public class GetFileController extends FileController { @Autowired @Autowired private FileDAO fileDAO; private FileDAO fileDAO; @Autowired private JobDAO jobDAO; @Autowired @Autowired private AuthorizationService authorizationService; private AuthorizationService authorizationService; Loading @@ -36,12 +41,23 @@ public class GetFileController extends FileController { private HttpServletResponse response; private HttpServletResponse response; @GetMapping("/**") @GetMapping("/**") public ResponseEntity<?> getFile() { public void getFile(@RequestParam(value = "jobId", required = false) String jobId) { String path = getPath(); String path = getPath(); LOG.debug("getFile called for path {}", path); LOG.debug("getFile called for path {}", path); if (jobId == null) { LOG.debug("getFile called for path {}", path); } else { LOG.debug("getFile called for path {} with jobId {}", path, jobId); if (!jobDAO.isJobExisting(jobId)) { throw new InvalidArgumentException("Job " + jobId + " not found"); } } handleFileJob(() -> { Optional<FileInfo> optFileInfo = fileDAO.getFileInfo(path); Optional<FileInfo> optFileInfo = fileDAO.getFileInfo(path); if (optFileInfo.isPresent()) { if (optFileInfo.isPresent()) { Loading @@ -49,19 +65,14 @@ public class GetFileController extends FileController { FileInfo fileInfo = optFileInfo.get(); FileInfo fileInfo = optFileInfo.get(); if (!authorizationService.isDownloadable(fileInfo, (TokenPrincipal) request.getUserPrincipal())) { if (!authorizationService.isDownloadable(fileInfo, (TokenPrincipal) request.getUserPrincipal())) { return new ResponseEntity<>("Unauthorized", UNAUTHORIZED); throw new PermissionDeniedException(path); } } return getFileResponse(fileInfo); File file = new File(fileInfo.getOsPath()); FileResponseUtil.getFileResponse(response, file, path); } else { } else { return new ResponseEntity<>("File " + path + " not found", NOT_FOUND); throw new FileNotFoundException(path); } } } }, jobId); private ResponseEntity<?> getFileResponse(FileInfo fileInfo) { File file = new File(fileInfo.getOsPath()); return FileResponseUtil.getFileResponse(response, file, fileInfo.getVirtualName()); } } } } Loading
pom.xml +1 −1 Original line number Original line Diff line number Diff line Loading @@ -5,7 +5,7 @@ <parent> <parent> <groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.2.6.RELEASE</version> <version>2.4.5</version> <relativePath/> <!-- lookup parent from repository --> <relativePath/> <!-- lookup parent from repository --> </parent> </parent> <groupId>it.inaf.ia2</groupId> <groupId>it.inaf.ia2</groupId> Loading
src/main/java/it/inaf/ia2/transfer/controller/ArchiveFileController.java +4 −4 Original line number Original line Diff line number Diff line Loading @@ -25,7 +25,7 @@ import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController; @RestController @RestController public class ArchiveFileController { public class ArchiveFileController extends FileController { @Autowired @Autowired private ArchiveService archiveService; private ArchiveService archiveService; Loading @@ -48,7 +48,7 @@ public class ArchiveFileController { job.setVosPaths(archiveRequest.getPaths()); job.setVosPaths(archiveRequest.getPaths()); CompletableFuture.runAsync(() -> { CompletableFuture.runAsync(() -> { archiveService.createArchive(job); handleFileJob(() -> archiveService.createArchive(job), job.getJobId()); }); }); HttpHeaders headers = new HttpHeaders(); HttpHeaders headers = new HttpHeaders(); Loading @@ -57,12 +57,12 @@ public class ArchiveFileController { } } @GetMapping(value = "/archive/{fileName}") @GetMapping(value = "/archive/{fileName}") public ResponseEntity<?> getArchiveFile(@PathVariable("fileName") String fileName) { public void getArchiveFile(@PathVariable("fileName") String fileName) { TokenPrincipal principal = (TokenPrincipal) request.getUserPrincipal(); TokenPrincipal principal = (TokenPrincipal) request.getUserPrincipal(); File file = archiveService.getArchiveParentDir(principal).toPath().resolve(fileName).toFile(); File file = archiveService.getArchiveParentDir(principal).toPath().resolve(fileName).toFile(); return FileResponseUtil.getFileResponse(response, file); FileResponseUtil.getFileResponse(response, file); } } } }
src/main/java/it/inaf/ia2/transfer/controller/FileController.java +32 −0 Original line number Original line Diff line number Diff line Loading @@ -5,18 +5,28 @@ */ */ package it.inaf.ia2.transfer.controller; package it.inaf.ia2.transfer.controller; import it.inaf.ia2.transfer.exception.JobException; import it.inaf.ia2.transfer.persistence.JobDAO; import java.net.URLDecoder; import java.net.URLDecoder; import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets; import java.util.Arrays; import java.util.Arrays; import java.util.stream.Collectors; import java.util.stream.Collectors; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest; import net.ivoa.xml.uws.v1.ExecutionPhase; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired; public abstract class FileController { public abstract class FileController { private static final Logger LOG = LoggerFactory.getLogger(FileController.class); @Autowired @Autowired protected HttpServletRequest request; protected HttpServletRequest request; @Autowired private JobDAO jobDAO; public String getPath() { public String getPath() { String uri = request.getRequestURI().substring(request.getContextPath().length()); String uri = request.getRequestURI().substring(request.getContextPath().length()); Loading @@ -26,4 +36,26 @@ public abstract class FileController { .map(p -> URLDecoder.decode(p, StandardCharsets.UTF_8)) .map(p -> URLDecoder.decode(p, StandardCharsets.UTF_8)) .collect(Collectors.toList())); .collect(Collectors.toList())); } } public void handleFileJob(Runnable action, String jobId) { try { action.run(); if (jobId != null) { jobDAO.updateJobPhase(ExecutionPhase.COMPLETED, jobId); } } catch (Throwable t) { JobException jobException; if (t instanceof JobException) { jobException = (JobException) t; } else { LOG.error("Unexpected error happened", t); jobException = new JobException(JobException.Type.FATAL, "Internal Fault") .setErrorDetail("InternalFault: Unexpected error happened"); } if (jobId != null) { jobDAO.setJobError(jobId, jobException); } throw t; } } } }
src/main/java/it/inaf/ia2/transfer/controller/FileResponseUtil.java +11 −10 Original line number Original line Diff line number Diff line Loading @@ -5,6 +5,8 @@ */ */ package it.inaf.ia2.transfer.controller; package it.inaf.ia2.transfer.controller; import it.inaf.ia2.transfer.exception.FileNotFoundException; import it.inaf.ia2.transfer.exception.JobException; import java.io.File; import java.io.File; import java.io.FileInputStream; import java.io.FileInputStream; import java.io.IOException; import java.io.IOException; Loading @@ -16,32 +18,32 @@ import java.nio.charset.StandardCharsets; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponse; import org.slf4j.Logger; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory; import static org.springframework.http.HttpStatus.INTERNAL_SERVER_ERROR; import static org.springframework.http.HttpStatus.NOT_FOUND; import org.springframework.http.ResponseEntity; public class FileResponseUtil { public class FileResponseUtil { private static final Logger LOG = LoggerFactory.getLogger(FileResponseUtil.class); private static final Logger LOG = LoggerFactory.getLogger(FileResponseUtil.class); public static ResponseEntity<?> getFileResponse(HttpServletResponse response, File file) { public static void getFileResponse(HttpServletResponse response, File file) { return getFileResponse(response, file, null); getFileResponse(response, file, null); } } public static ResponseEntity<?> getFileResponse(HttpServletResponse response, File file, String fileName) { public static void getFileResponse(HttpServletResponse response, File file, String vosPath) { String fileName = vosPath == null ? file.getName() : vosPath.substring(vosPath.lastIndexOf("/") + 1); if (!file.exists()) { if (!file.exists()) { LOG.error("File not found: " + file.getAbsolutePath()); LOG.error("File not found: " + file.getAbsolutePath()); return new ResponseEntity<>("File " + file.getName() + " not found", NOT_FOUND); throw new FileNotFoundException(vosPath == null ? file.getAbsolutePath() : vosPath); } } if (!file.canRead()) { if (!file.canRead()) { LOG.error("File not readable: " + file.getAbsolutePath()); LOG.error("File not readable: " + file.getAbsolutePath()); return new ResponseEntity<>("File " + file.getName() + " is not readable", INTERNAL_SERVER_ERROR); throw new JobException(JobException.Type.FATAL, "Internal Fault") .setErrorDetail("InternalFault: File " + file.getName() + " is not readable"); } } response.setHeader("Content-Disposition", "attachment; filename=" response.setHeader("Content-Disposition", "attachment; filename=" + URLEncoder.encode(fileName == null ? file.getName() : fileName, StandardCharsets.UTF_8)); + URLEncoder.encode(fileName, StandardCharsets.UTF_8)); response.setHeader("Content-Length", String.valueOf(file.length())); response.setHeader("Content-Length", String.valueOf(file.length())); response.setCharacterEncoding("UTF-8"); response.setCharacterEncoding("UTF-8"); Loading @@ -54,6 +56,5 @@ public class FileResponseUtil { } catch (IOException ex) { } catch (IOException ex) { throw new UncheckedIOException(ex); throw new UncheckedIOException(ex); } } return null; } } } }
src/main/java/it/inaf/ia2/transfer/controller/GetFileController.java +30 −19 Original line number Original line Diff line number Diff line Loading @@ -7,7 +7,11 @@ package it.inaf.ia2.transfer.controller; import it.inaf.ia2.transfer.persistence.model.FileInfo; import it.inaf.ia2.transfer.persistence.model.FileInfo; import it.inaf.ia2.transfer.auth.TokenPrincipal; import it.inaf.ia2.transfer.auth.TokenPrincipal; import it.inaf.ia2.transfer.exception.FileNotFoundException; import it.inaf.ia2.transfer.exception.InvalidArgumentException; import it.inaf.ia2.transfer.exception.PermissionDeniedException; import it.inaf.ia2.transfer.persistence.FileDAO; import it.inaf.ia2.transfer.persistence.FileDAO; import it.inaf.ia2.transfer.persistence.JobDAO; import it.inaf.ia2.transfer.service.AuthorizationService; import it.inaf.ia2.transfer.service.AuthorizationService; import java.io.File; import java.io.File; import java.util.Optional; import java.util.Optional; Loading @@ -15,10 +19,8 @@ import javax.servlet.http.HttpServletResponse; import org.slf4j.Logger; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired; import static org.springframework.http.HttpStatus.NOT_FOUND; import static org.springframework.http.HttpStatus.UNAUTHORIZED; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController; @RestController @RestController Loading @@ -29,6 +31,9 @@ public class GetFileController extends FileController { @Autowired @Autowired private FileDAO fileDAO; private FileDAO fileDAO; @Autowired private JobDAO jobDAO; @Autowired @Autowired private AuthorizationService authorizationService; private AuthorizationService authorizationService; Loading @@ -36,12 +41,23 @@ public class GetFileController extends FileController { private HttpServletResponse response; private HttpServletResponse response; @GetMapping("/**") @GetMapping("/**") public ResponseEntity<?> getFile() { public void getFile(@RequestParam(value = "jobId", required = false) String jobId) { String path = getPath(); String path = getPath(); LOG.debug("getFile called for path {}", path); LOG.debug("getFile called for path {}", path); if (jobId == null) { LOG.debug("getFile called for path {}", path); } else { LOG.debug("getFile called for path {} with jobId {}", path, jobId); if (!jobDAO.isJobExisting(jobId)) { throw new InvalidArgumentException("Job " + jobId + " not found"); } } handleFileJob(() -> { Optional<FileInfo> optFileInfo = fileDAO.getFileInfo(path); Optional<FileInfo> optFileInfo = fileDAO.getFileInfo(path); if (optFileInfo.isPresent()) { if (optFileInfo.isPresent()) { Loading @@ -49,19 +65,14 @@ public class GetFileController extends FileController { FileInfo fileInfo = optFileInfo.get(); FileInfo fileInfo = optFileInfo.get(); if (!authorizationService.isDownloadable(fileInfo, (TokenPrincipal) request.getUserPrincipal())) { if (!authorizationService.isDownloadable(fileInfo, (TokenPrincipal) request.getUserPrincipal())) { return new ResponseEntity<>("Unauthorized", UNAUTHORIZED); throw new PermissionDeniedException(path); } } return getFileResponse(fileInfo); File file = new File(fileInfo.getOsPath()); FileResponseUtil.getFileResponse(response, file, path); } else { } else { return new ResponseEntity<>("File " + path + " not found", NOT_FOUND); throw new FileNotFoundException(path); } } } }, jobId); private ResponseEntity<?> getFileResponse(FileInfo fileInfo) { File file = new File(fileInfo.getOsPath()); return FileResponseUtil.getFileResponse(response, file, fileInfo.getVirtualName()); } } } }