1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.apache.commons.net.ftp;
19
20 import static org.junit.jupiter.api.Assertions.assertEquals;
21 import static org.junit.jupiter.api.Assertions.assertFalse;
22 import static org.junit.jupiter.api.Assertions.assertNotNull;
23 import static org.junit.jupiter.api.Assertions.assertNotSame;
24 import static org.junit.jupiter.api.Assertions.assertNull;
25 import static org.junit.jupiter.api.Assertions.assertSame;
26
27 import java.io.ByteArrayInputStream;
28 import java.io.ByteArrayOutputStream;
29 import java.io.IOException;
30 import java.net.InetAddress;
31
32 import org.apache.commons.net.ftp.parser.UnixFTPEntryParser;
33 import org.junit.jupiter.api.Test;
34
35 class FTPClientTest {
36
37 private static final class LocalClient extends FTPClient {
38
39 private String systemType;
40
41 @Override
42 public String getSystemType() throws IOException {
43 return systemType;
44 }
45
46 public void setSystemType(final String systemType) {
47 this.systemType = systemType;
48 }
49 }
50
51 private static final class PassiveNatWorkAroundLocalClient extends FTPClient {
52
53 private final String passiveModeServerIP;
54
55 public PassiveNatWorkAroundLocalClient(final String passiveModeServerIP) {
56 this.passiveModeServerIP = passiveModeServerIP;
57 }
58
59 @Override
60 public InetAddress getRemoteAddress() {
61 try {
62 return InetAddress.getByName(passiveModeServerIP);
63 } catch (final Exception e) {
64 throw new IllegalStateException(e);
65 }
66 }
67 }
68
69 private static final String[] TESTS = { "257 /path/without/quotes", "/path/without/quotes",
70
71 "257 \"/path/with/delimiting/quotes/without/commentary\"", "/path/with/delimiting/quotes/without/commentary",
72
73 "257 \"/path/with/quotes\"\" /inside/but/without/commentary\"", "/path/with/quotes\" /inside/but/without/commentary",
74
75 "257 \"/path/with/quotes\"\" /inside/string\" and with commentary", "/path/with/quotes\" /inside/string",
76
77 "257 \"/path/with/quotes\"\" /inside/string\" and with commentary that also \"contains quotes\"", "/path/with/quotes\" /inside/string",
78
79 "257 \"/path/without/trailing/quote",
80 "\"/path/without/trailing/quote",
81
82 "257 root is current directory.",
83 "root is current directory.",
84
85 "257 \"/\"",
86 "/", };
87
88 @Test
89 void testCopyStreamListener() {
90 final FTPClient client = new PassiveNatWorkAroundLocalClient("8.8.8.8");
91 assertNull(client.getCopyStreamListener());
92 }
93
94 @Test
95 void testGetActivePort() {
96 final FTPClient client = new PassiveNatWorkAroundLocalClient("8.8.8.8");
97 assertEquals(0, client.getActivePort());
98 }
99
100 @Test
101 void testGetAutodetectUTF8() {
102 final FTPClient client = new PassiveNatWorkAroundLocalClient("8.8.8.8");
103 assertFalse(client.getAutodetectUTF8());
104 }
105
106 @Test
107 void testGetBufferSize() {
108 final FTPClient client = new PassiveNatWorkAroundLocalClient("8.8.8.8");
109 assertEquals(0, client.getBufferSize());
110 }
111
112 @Test
113 void testGetControlKeepAliveReplyTimeout() {
114 final FTPClient client = new PassiveNatWorkAroundLocalClient("8.8.8.8");
115 assertEquals(1_000, client.getControlKeepAliveReplyTimeout());
116 }
117
118 @Test
119 void testGetControlKeepAliveTimeout() {
120 final FTPClient client = new PassiveNatWorkAroundLocalClient("8.8.8.8");
121 assertEquals(0, client.getControlKeepAliveTimeout());
122 }
123
124 @Test
125 void testGetCslDebug() {
126 final FTPClient client = new PassiveNatWorkAroundLocalClient("8.8.8.8");
127 assertNull(client.getCslDebug());
128 }
129
130 @Test
131 void testGetPassiveLocalIPAddress() {
132 final FTPClient client = new PassiveNatWorkAroundLocalClient("8.8.8.8");
133 assertNull(client.getPassiveLocalIPAddress());
134 }
135
136 @Test
137 void testGetPassivePort() {
138 final FTPClient client = new PassiveNatWorkAroundLocalClient("8.8.8.8");
139 assertEquals(-1, client.getPassivePort());
140 }
141
142 @Test
143 void testLoadResourceProperties() {
144 assertNull(FTPClient.loadResourceProperties(null));
145 assertNull(FTPClient.loadResourceProperties("this/does/not/exist.properties"));
146 assertNull(FTPClient.loadResourceProperties("/this/does/not/exist.properties"));
147 assertNull(FTPClient.loadResourceProperties(FTPClient.SYSTEM_TYPE_PROPERTIES));
148 assertNotNull(FTPClient.loadResourceProperties(""));
149 assertNotNull(FTPClient.loadResourceProperties("/org/apache/commons/net/examples/examples.properties"));
150 assertNotNull(FTPClient.loadResourceProperties("/org/apache/commons/net/test.properties"));
151 }
152
153 @Test
154 void testParseClient() {
155 for (int i = 0; i < TESTS.length; i += 2) {
156 assertEquals(TESTS[i + 1], FTPClient.parsePathname(TESTS[i]), "Failed to parse");
157 }
158 }
159
160 @Test
161 void testParsePassiveModeReplyForLocalAddressWithNatWorkaround() throws Exception {
162 final FTPClient client = new PassiveNatWorkAroundLocalClient("8.8.8.8");
163 client.setIpAddressFromPasvResponse(true);
164 client._parsePassiveModeReply("227 Entering Passive Mode (172,16,204,138,192,22).");
165 assertEquals("8.8.8.8", client.getPassiveHost());
166 client.setIpAddressFromPasvResponse(false);
167 client._parsePassiveModeReply("227 Entering Passive Mode (172,16,204,138,192,22).");
168 assertNull(client.getPassiveHost());
169 }
170
171 @SuppressWarnings("deprecation")
172 @Test
173 void testParsePassiveModeReplyForLocalAddressWithNatWorkaroundDisabled() throws Exception {
174 final FTPClient client = new PassiveNatWorkAroundLocalClient("8.8.8.8");
175 client.setPassiveNatWorkaround(false);
176 client.setIpAddressFromPasvResponse(true);
177 client._parsePassiveModeReply("227 Entering Passive Mode (172,16,204,138,192,22).");
178 assertEquals("172.16.204.138", client.getPassiveHost());
179 client.setIpAddressFromPasvResponse(false);
180 client._parsePassiveModeReply("227 Entering Passive Mode (172,16,204,138,192,22).");
181 assertNull(client.getPassiveHost());
182 }
183
184 @Test
185 void testParsePassiveModeReplyForLocalAddressWithoutNatWorkaroundStrategy() throws Exception {
186 final FTPClient client = new PassiveNatWorkAroundLocalClient("8.8.8.8");
187 client.setPassiveNatWorkaroundStrategy(null);
188 client.setIpAddressFromPasvResponse(true);
189 client._parsePassiveModeReply("227 Entering Passive Mode (172,16,204,138,192,22).");
190 assertEquals("172.16.204.138", client.getPassiveHost());
191 client.setIpAddressFromPasvResponse(false);
192 client._parsePassiveModeReply("227 Entering Passive Mode (172,16,204,138,192,22).");
193 assertNull(client.getPassiveHost());
194 }
195
196 @Test
197 void testParsePassiveModeReplyForLocalAddressWithSimpleNatWorkaroundStrategy() throws Exception {
198 final FTPClient client = new PassiveNatWorkAroundLocalClient("8.8.8.8");
199 client.setPassiveNatWorkaroundStrategy(hostname -> "4.4.4.4");
200 client.setIpAddressFromPasvResponse(true);
201 client._parsePassiveModeReply("227 Entering Passive Mode (172,16,204,138,192,22).");
202 assertEquals("4.4.4.4", client.getPassiveHost());
203 client.setIpAddressFromPasvResponse(false);
204 client._parsePassiveModeReply("227 Entering Passive Mode (172,16,204,138,192,22).");
205 assertNull(client.getPassiveHost());
206 }
207
208 @Test
209 void testParsePassiveModeReplyForNonLocalAddressWithNatWorkaround() throws Exception {
210 final FTPClient client = new PassiveNatWorkAroundLocalClient("8.8.8.8");
211 client.setIpAddressFromPasvResponse(true);
212 client._parsePassiveModeReply("227 Entering Passive Mode (8,8,4,4,192,22).");
213 assertEquals("8.8.4.4", client.getPassiveHost());
214 client.setIpAddressFromPasvResponse(false);
215 client._parsePassiveModeReply("227 Entering Passive Mode (8,8,4,4,192,22).");
216 assertNull(client.getPassiveHost());
217 }
218
219 @SuppressWarnings("deprecation")
220 @Test
221 void testParsePassiveModeReplyForNonLocalAddressWithNatWorkaroundDisabled() throws Exception {
222 final FTPClient client = new PassiveNatWorkAroundLocalClient("8.8.8.8");
223 client.setPassiveNatWorkaround(false);
224 client.setIpAddressFromPasvResponse(true);
225 client._parsePassiveModeReply("227 Entering Passive Mode (8,8,4,4,192,22).");
226 assertEquals("8.8.4.4", client.getPassiveHost());
227 client.setIpAddressFromPasvResponse(false);
228 client._parsePassiveModeReply("227 Entering Passive Mode (8,8,4,4,192,22).");
229 assertNull(client.getPassiveHost());
230 }
231
232 @Test
233 void testParsePassiveModeReplyForNonLocalAddressWithoutNatWorkaroundStrategy() throws Exception {
234 final FTPClient client = new PassiveNatWorkAroundLocalClient("8.8.8.8");
235 client.setPassiveNatWorkaroundStrategy(null);
236 client.setIpAddressFromPasvResponse(true);
237 client._parsePassiveModeReply("227 Entering Passive Mode (8,8,4,4,192,22).");
238 assertEquals("8.8.4.4", client.getPassiveHost());
239 client.setIpAddressFromPasvResponse(false);
240 client._parsePassiveModeReply("227 Entering Passive Mode (8,8,4,4,192,22).");
241 assertNull(client.getPassiveHost());
242 }
243
244 @Test
245 void testParserCachingNullKey() throws Exception {
246 final LocalClient client = new LocalClient();
247 client.setSystemType(FTPClientConfig.SYST_UNIX);
248 assertNull(client.getEntryParser());
249 client.createParser(null);
250 final FTPFileEntryParser entryParser = client.getEntryParser();
251 assertNotNull(entryParser);
252 client.createParser(null);
253 assertSame(entryParser, client.getEntryParser());
254 client.setSystemType(FTPClientConfig.SYST_NT);
255 client.createParser(null);
256 assertSame(entryParser, client.getEntryParser());
257 }
258
259 @Test
260 void testParserCachingWithKey() throws Exception {
261 final FTPClient client = new FTPClient();
262 assertNull(client.getEntryParser());
263 client.createParser(FTPClientConfig.SYST_UNIX);
264 final FTPFileEntryParser entryParserSYST = client.getEntryParser();
265 assertNotNull(entryParserSYST);
266 client.createParser(FTPClientConfig.SYST_UNIX);
267 assertSame(entryParserSYST, client.getEntryParser());
268 client.createParser(FTPClientConfig.SYST_VMS);
269 final FTPFileEntryParser entryParserVMS = client.getEntryParser();
270 assertNotSame(entryParserSYST, entryParserVMS);
271 client.createParser(FTPClientConfig.SYST_VMS);
272 assertSame(entryParserVMS, client.getEntryParser());
273 client.createParser(FTPClientConfig.SYST_UNIX);
274 assertNotSame(entryParserVMS, client.getEntryParser());
275 }
276
277 @Test
278 void testUnparseableFiles() throws Exception {
279 final ByteArrayOutputStream baos = new ByteArrayOutputStream();
280 baos.write("-rwxr-xr-x 2 root root 4096 Mar 2 15:13 zxbox".getBytes());
281 baos.write(new byte[] { '\r', '\n' });
282 baos.write("zrwxr-xr-x 2 root root 4096 Mar 2 15:13 zxbox".getBytes());
283 baos.write(new byte[] { '\r', '\n' });
284 final FTPFileEntryParser parser = new UnixFTPEntryParser();
285 final FTPClientConfig config = new FTPClientConfig();
286 FTPListParseEngine engine = new FTPListParseEngine(parser, config);
287 config.setUnparseableEntries(false);
288 engine.readServerList(new ByteArrayInputStream(baos.toByteArray()), null);
289 FTPFile[] files = engine.getFiles();
290 assertEquals(1, files.length);
291 config.setUnparseableEntries(true);
292 engine = new FTPListParseEngine(parser, config);
293 engine.readServerList(new ByteArrayInputStream(baos.toByteArray()), null);
294 files = engine.getFiles();
295 assertEquals(2, files.length);
296 }
297 }