GH-3974: Fix SftpSession for absolute paths

Fixes https://github.com/spring-projects/spring-integration/issues/3974

* Treat a leading `/` as an indicator of absolute path request in the `SftpSession.doList()`
* Call `sftpClient.canonicalPath()` for path without a leading `/` to resolve it as relative path in the user home
* Add a note in docs for `LS` command
This commit is contained in:
abilan
2022-12-16 12:16:58 -05:00
committed by Gary Russell
parent 7adaaafd40
commit 3a743802c0
5 changed files with 16 additions and 10 deletions

View File

@@ -78,7 +78,7 @@ public class SftpSession implements Session<SftpClient.DirEntry> {
}
public Stream<SftpClient.DirEntry> doList(String path) throws IOException {
String remotePath = StringUtils.trimTrailingCharacter(StringUtils.trimLeadingCharacter(path, '/'), '/');
String remotePath = StringUtils.trimTrailingCharacter(path, '/');
String remoteDir = remotePath;
int lastIndex = remotePath.lastIndexOf('/');
if (lastIndex > 0) {
@@ -96,7 +96,10 @@ public class SftpSession implements Session<SftpClient.DirEntry> {
remoteDir = remotePath;
}
}
remoteDir = remoteDir.length() == 0 ? this.sftpClient.canonicalPath("") : remoteDir;
remoteDir =
remoteDir.length() > 0 && remoteDir.charAt(0) == '/'
? remoteDir
: this.sftpClient.canonicalPath(remoteDir);
return StreamSupport.stream(this.sftpClient.readDir(remoteDir).spliterator(), false)
.filter((entry) -> !isPattern || PatternMatchUtils.simpleMatch(remoteFile, entry.getFilename()));
}

View File

@@ -189,13 +189,14 @@ public class SftpInboundRemoteFileSystemSynchronizerTests {
try {
SftpClient sftpClient = mock(SftpClient.class);
when(sftpClient.canonicalPath("remote-test-dir")).thenReturn("/remote-test-dir");
String[] files = new File("remote-test-dir").list();
for (String fileName : files) {
when(sftpClient.read("remote-test-dir/" + fileName))
.thenReturn(new FileInputStream("remote-test-dir/" + fileName));
}
when(sftpClient.readDir("remote-test-dir")).thenReturn(this.sftpEntries);
when(sftpClient.readDir("/remote-test-dir")).thenReturn(this.sftpEntries);
return SftpTestSessionFactory.createSftpSession(sftpClient);
}

View File

@@ -44,7 +44,7 @@ public class SftpMessageSourceTests extends SftpTestSupport {
private ApplicationContext context;
@Test
public void testMaxFetch() throws Exception {
public void testMaxFetch() {
SftpInboundFileSynchronizingMessageSource messageSource = buildSource();
Message<?> received = messageSource.receive();
assertThat(received).isNotNull();
@@ -52,9 +52,9 @@ public class SftpMessageSourceTests extends SftpTestSupport {
.isIn(" sftpSource1.txt", "sftpSource2.txt");
}
private SftpInboundFileSynchronizingMessageSource buildSource() throws Exception {
private SftpInboundFileSynchronizingMessageSource buildSource() {
SftpInboundFileSynchronizer sync = new SftpInboundFileSynchronizer(sessionFactory());
sync.setRemoteDirectory("sftpSource/");
sync.setRemoteDirectory("/sftpSource/");
sync.setBeanFactory(this.context);
SftpInboundFileSynchronizingMessageSource messageSource = new SftpInboundFileSynchronizingMessageSource(sync);
messageSource.setLocalDirectory(getTargetLocalDirectory());

View File

@@ -174,14 +174,14 @@ public class SftpOutboundTests {
context.close();
}
@Test //INT-2275
@Test
public void testFtpOutboundGatewayInsideChain() {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(
"SftpOutboundInsideChainTests-context.xml", getClass());
MessageChannel channel = context.getBean("outboundGatewayInsideChain", MessageChannel.class);
channel.send(MessageBuilder.withPayload("remote-test-dir").build());
channel.send(MessageBuilder.withPayload("/remote-test-dir").build());
PollableChannel output = context.getBean("replyChannel", PollableChannel.class);
@@ -308,7 +308,7 @@ public class SftpOutboundTests {
Arrays.stream(files)
.map((file) -> new SftpClient.DirEntry(file, file, new SftpClient.Attributes()))
.toList();
when(sftpClient.readDir("remote-test-dir")).thenReturn(dirEntries);
when(sftpClient.readDir("/remote-test-dir")).thenReturn(dirEntries);
return SftpTestSessionFactory.createSftpSession(sftpClient);
}

View File

@@ -945,6 +945,8 @@ When using the recursive option (`-R`), the `fileName` includes any subdirectory
If you use the `-dirs` option, each recursive directory is also returned as an element in the list.
In this case, we recommend that you not use the `-1` option, because you would not be able to distinguish files from directories, which you can do when you use `FileInfo` objects.
If remote path to list starts with a `/` symbol, it is treated by SFTP as an absolute path; without - as a relative path in the current user home.
==== Using `nlst` Command
Version 5 introduced support for the `nlst` command.
@@ -1341,7 +1343,7 @@ Currently, supported events are:
* `PathRemovedEvent` - a file or directory was removed
* `SessionClosedEvent` - the client has disconnected
Each of these is a subclass of `ApacheMinaSftpEvent`; you can configure a single listener to receive all of the event types.
Each of these is a subclass of `ApacheMinaSftpEvent`; you can configure a single listener to receive all the event types.
The `source` property of each event is a `ServerSession`, from which you can obtain information such as the client address; a convenient `getSession()` method is provided on the abstract event.
To configure the server with the listener (which must be a Spring bean), simply add it to the `SftpSubsystemFactory`: