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