diff --git a/src/main/java/it/inaf/oats/vospace/CreateNodeController.java b/src/main/java/it/inaf/oats/vospace/CreateNodeController.java index 4cd2860cf793f73eb7c04a0e4243e3db7f835573..7a6e047ffbf0461fe2bbe4e1300834005e3f92a4 100644 --- a/src/main/java/it/inaf/oats/vospace/CreateNodeController.java +++ b/src/main/java/it/inaf/oats/vospace/CreateNodeController.java @@ -6,7 +6,6 @@ package it.inaf.oats.vospace; import it.inaf.ia2.aa.data.User; -import it.inaf.oats.vospace.exception.InvalidURIException; import net.ivoa.xml.vospace.v2.LinkNode; import net.ivoa.xml.vospace.v2.Node; import org.springframework.http.MediaType; diff --git a/src/main/java/it/inaf/oats/vospace/URIUtils.java b/src/main/java/it/inaf/oats/vospace/URIUtils.java index 0250050fd271a772725b8a1097f4a63a367c1f94..36bd239aff98a538cf34d445f402d049577c0465 100644 --- a/src/main/java/it/inaf/oats/vospace/URIUtils.java +++ b/src/main/java/it/inaf/oats/vospace/URIUtils.java @@ -18,6 +18,13 @@ public class URIUtils { // Slashes are treated separately private static final Pattern FORBIDDEN_CHARS = Pattern.compile("[\\x00\\x08\\x0B\\x0C\\x0E-\\x1F" + Pattern.quote("<>?\":\\|'`*") + "]"); private static final String SCHEME = "vos"; + + public static boolean isURIInternal(String URI) { + if(URI == null) + throw new IllegalArgumentException("URI can't be null"); + + return URI.toLowerCase().startsWith(SCHEME); + } public static String returnURIFromVosPath(String vosPath, String authority) { String result = null; diff --git a/src/main/java/it/inaf/oats/vospace/UriService.java b/src/main/java/it/inaf/oats/vospace/UriService.java index 056aa04248b782adcbdd0576ecb876e8d7256b46..6f78cb11d4273cd6d8e3790df6a21a71a6eb43e8 100644 --- a/src/main/java/it/inaf/oats/vospace/UriService.java +++ b/src/main/java/it/inaf/oats/vospace/UriService.java @@ -19,6 +19,7 @@ import it.inaf.oats.vospace.exception.NodeNotFoundException; import it.inaf.oats.vospace.exception.PermissionDeniedException; import it.inaf.oats.vospace.exception.ProtocolNotSupportedException; import it.inaf.oats.vospace.exception.NodeBusyException; +import it.inaf.oats.vospace.persistence.LinkedServiceDAO; import it.inaf.oats.vospace.persistence.LocationDAO; import it.inaf.oats.vospace.persistence.NodeDAO; import it.inaf.oats.vospace.persistence.model.Location; @@ -58,6 +59,9 @@ public class UriService { @Autowired private LocationDAO locationDAO; + @Autowired + private LinkedServiceDAO linkedServiceDAO; + @Autowired private HttpServletRequest servletRequest; @@ -168,7 +172,7 @@ public class UriService { JobService.JobDirection jobType = JobDirection.getJobDirectionEnumFromTransfer(transfer); Node node = this.getEndpointNode(relativePath, jobType, user); - + switch (jobType) { case pushToVoSpace: case pullToVoSpace: @@ -178,7 +182,7 @@ public class UriService { break; case pullFromVoSpace: - // Refresh relative path: it can differ in case of links + // Refresh relative path: it can differ in case of links followed relativePath = NodeUtils.getVosPath(node); if (!NodeUtils.checkIfReadable(node, creator, groups)) { throw PermissionDeniedException.forPath(relativePath); @@ -197,24 +201,36 @@ public class UriService { return fileServiceClient.startArchiveJob(transfer, job.getJobId()); } - Location location = locationDAO.getNodeLocation(relativePath).orElse(null); + boolean isLinkNode = node instanceof LinkNode; String endpoint; - if (location != null && location.getType() == LocationType.PORTAL) { - String fileName = nodeDao.getNodeOsName(relativePath); - endpoint = "http://" + location.getSource().getHostname() + location.getSource().getBaseUrl(); - if (!endpoint.endsWith("/")) { - endpoint += "/"; - } - endpoint += fileName; + if (isLinkNode) { + endpoint = ((LinkNode) node).getTarget(); } else { - endpoint = fileServiceUrl + urlEncodePath(relativePath); + + Location location = locationDAO.getNodeLocation(relativePath).orElse(null); + + if (location != null && location.getType() == LocationType.PORTAL) { + String fileName = nodeDao.getNodeOsName(relativePath); + endpoint = "http://" + location.getSource().getHostname() + location.getSource().getBaseUrl(); + if (!endpoint.endsWith("/")) { + endpoint += "/"; + } + endpoint += fileName; + } else { + endpoint = fileServiceUrl + urlEncodePath(relativePath); + } } endpoint += "?jobId=" + job.getJobId(); - if (!"true".equals(NodeProperties.getNodePropertyByURI(node, NodeProperties.PUBLIC_READ_URI))) { + if (isLinkNode) { + String linkTarget = ((LinkNode) node).getTarget(); + if (linkedServiceDAO.isLinkedServiceUrl(linkTarget)) { + endpoint += "&token=" + getEndpointToken(linkTarget); + } + } else if (!"true".equals(NodeProperties.getNodePropertyByURI(node, NodeProperties.PUBLIC_READ_URI))) { endpoint += "&token=" + getEndpointToken(fileServiceUrl + relativePath); } @@ -287,21 +303,27 @@ public class UriService { } private Node followLinkRecursive(LinkNode linkNode, int depth) { - - if(depth >= linkMaxDepth) { - throw new InternalFaultException("Max link depth reached at link node: " + + if (depth >= linkMaxDepth) { + throw new InternalFaultException("Max link depth reached at link node: " + NodeUtils.getVosPath(linkNode)); } - - String targetPath = URIUtils.returnVosPathFromNodeURI(linkNode.getTarget(), authority); - - Optional<Node> targetNodeOpt = nodeDao.listNode(targetPath); - Node targetNode = targetNodeOpt.orElseThrow(() -> new InternalFaultException("Broken Link to target: " + targetPath)); - - if(targetNode instanceof LinkNode) { - return this.followLinkRecursive(linkNode, ++depth); - } else { - return targetNode; + + String linkTarget = linkNode.getTarget(); + + if (URIUtils.isURIInternal(linkTarget)) { + return linkNode; + } else { + String targetPath = URIUtils.returnVosPathFromNodeURI(linkTarget, authority); + + Optional<Node> targetNodeOpt = nodeDao.listNode(targetPath); + Node targetNode = targetNodeOpt.orElseThrow(() -> new InternalFaultException("Broken Link to target: " + targetPath)); + + if (targetNode instanceof LinkNode) { + return this.followLinkRecursive(linkNode, ++depth); + } else { + return targetNode; + } } } } diff --git a/src/main/java/it/inaf/oats/vospace/persistence/LinkedServiceDAO.java b/src/main/java/it/inaf/oats/vospace/persistence/LinkedServiceDAO.java index e8adf2f3a9601978222645e1e160f5a31df21016..5af99100e53f21cfb02d046e1bd765aea3419065 100644 --- a/src/main/java/it/inaf/oats/vospace/persistence/LinkedServiceDAO.java +++ b/src/main/java/it/inaf/oats/vospace/persistence/LinkedServiceDAO.java @@ -27,7 +27,7 @@ public class LinkedServiceDAO { jdbcTemplate = new JdbcTemplate(dataSource); } - boolean isLinkedServiceUrl(String targetUrl) { + public boolean isLinkedServiceUrl(String targetUrl) { String sql = " SELECT COUNT(*) > 0\n" + "FROM linked_service\n" + "WHERE ? LIKE service_base_url || '%'"; diff --git a/src/test/java/it/inaf/oats/vospace/URIUtilsTest.java b/src/test/java/it/inaf/oats/vospace/URIUtilsTest.java index d630f85de6e0161d6216227d8613799dc3b80beb..6897ae542576e46865db1b494bbb116433f54849 100644 --- a/src/test/java/it/inaf/oats/vospace/URIUtilsTest.java +++ b/src/test/java/it/inaf/oats/vospace/URIUtilsTest.java @@ -8,7 +8,9 @@ package it.inaf.oats.vospace; import it.inaf.oats.vospace.exception.InvalidURIException; import java.net.URISyntaxException; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; import org.junit.jupiter.api.Test; public class URIUtilsTest { @@ -84,6 +86,12 @@ public class URIUtilsTest { String test3 = URIUtils.returnURIFromVosPath("/test1/te# !?st2", authority); assertEquals("vos://"+authority+"/test1/te%23%20!%3Fst2", test3); } + + @Test + public void testIsURIInternal() { + assertTrue(URIUtils.isURIInternal("vos://"+authority+"/test1/test2")); + assertFalse(URIUtils.isURIInternal("http://host.ia2.inaf.it/test1/test2")); + } }