View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *   https://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
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", // invalid syntax, return all after reply code prefix
80              "\"/path/without/trailing/quote",
81  
82              "257 root is current directory.", // NET-442
83              "root is current directory.",
84  
85              "257 \"/\"", // NET-502
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") // testing deprecated code
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") // testing deprecated code
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()); // parser was cached
254         client.setSystemType(FTPClientConfig.SYST_NT);
255         client.createParser(null);
256         assertSame(entryParser, client.getEntryParser()); // parser was cached
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()); // the previous entry was cached
268         client.createParser(FTPClientConfig.SYST_VMS);
269         final FTPFileEntryParser entryParserVMS = client.getEntryParser();
270         assertNotSame(entryParserSYST, entryParserVMS); // the previous entry was replaced
271         client.createParser(FTPClientConfig.SYST_VMS);
272         assertSame(entryParserVMS, client.getEntryParser()); // the previous entry was cached
273         client.createParser(FTPClientConfig.SYST_UNIX); // revert
274         assertNotSame(entryParserVMS, client.getEntryParser()); // the previous entry was replaced
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); // use default encoding
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); // use default encoding
294         files = engine.getFiles();
295         assertEquals(2, files.length);
296     }
297 }