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    *   http://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 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 type) {
41              systemType = type;
42          }
43      }
44  
45      private static class PassiveNatWorkAroundLocalClient extends FTPClient {
46          private final String passiveModeServerIP;
47  
48          public PassiveNatWorkAroundLocalClient(final String passiveModeServerIP) {
49              this.passiveModeServerIP = passiveModeServerIP;
50          }
51  
52          @Override
53          public InetAddress getRemoteAddress() {
54              try {
55                  return InetAddress.getByName(passiveModeServerIP);
56              } catch (final Exception e) {
57                  throw new IllegalStateException(e);
58              }
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 testParseClient() {
87          for (int i = 0; i < TESTS.length; i += 2) {
88              assertEquals("Failed to parse", TESTS[i + 1], FTPClient.parsePathname(TESTS[i]));
89          }
90      }
91  
92      public void testParsePassiveModeReplyForLocalAddressWithNatWorkaround() throws Exception {
93          final FTPClient client = new PassiveNatWorkAroundLocalClient("8.8.8.8");
94          client.setIpAddressFromPasvResponse(true);
95          client._parsePassiveModeReply("227 Entering Passive Mode (172,16,204,138,192,22).");
96          assertEquals("8.8.8.8", client.getPassiveHost());
97          client.setIpAddressFromPasvResponse(false);
98          client._parsePassiveModeReply("227 Entering Passive Mode (172,16,204,138,192,22).");
99          assertNull(client.getPassiveHost());
100     }
101 
102     @SuppressWarnings("deprecation") // testing deprecated code
103     public void testParsePassiveModeReplyForLocalAddressWithNatWorkaroundDisabled() throws Exception {
104         final FTPClient client = new PassiveNatWorkAroundLocalClient("8.8.8.8");
105         client.setPassiveNatWorkaround(false);
106         client.setIpAddressFromPasvResponse(true);
107         client._parsePassiveModeReply("227 Entering Passive Mode (172,16,204,138,192,22).");
108         assertEquals("172.16.204.138", client.getPassiveHost());
109         client.setIpAddressFromPasvResponse(false);
110         client._parsePassiveModeReply("227 Entering Passive Mode (172,16,204,138,192,22).");
111         assertNull(client.getPassiveHost());
112     }
113 
114     public void testParsePassiveModeReplyForLocalAddressWithoutNatWorkaroundStrategy() throws Exception {
115         final FTPClient client = new PassiveNatWorkAroundLocalClient("8.8.8.8");
116         client.setPassiveNatWorkaroundStrategy(null);
117         client.setIpAddressFromPasvResponse(true);
118         client._parsePassiveModeReply("227 Entering Passive Mode (172,16,204,138,192,22).");
119         assertEquals("172.16.204.138", client.getPassiveHost());
120         client.setIpAddressFromPasvResponse(false);
121         client._parsePassiveModeReply("227 Entering Passive Mode (172,16,204,138,192,22).");
122         assertNull(client.getPassiveHost());
123     }
124 
125     public void testParsePassiveModeReplyForLocalAddressWithSimpleNatWorkaroundStrategy() throws Exception {
126         final FTPClient client = new PassiveNatWorkAroundLocalClient("8.8.8.8");
127         client.setPassiveNatWorkaroundStrategy(hostname -> "4.4.4.4");
128         client.setIpAddressFromPasvResponse(true);
129         client._parsePassiveModeReply("227 Entering Passive Mode (172,16,204,138,192,22).");
130         assertEquals("4.4.4.4", client.getPassiveHost());
131         client.setIpAddressFromPasvResponse(false);
132         client._parsePassiveModeReply("227 Entering Passive Mode (172,16,204,138,192,22).");
133         assertNull(client.getPassiveHost());
134     }
135 
136     public void testParsePassiveModeReplyForNonLocalAddressWithNatWorkaround() throws Exception {
137         final FTPClient client = new PassiveNatWorkAroundLocalClient("8.8.8.8");
138         client.setIpAddressFromPasvResponse(true);
139         client._parsePassiveModeReply("227 Entering Passive Mode (8,8,4,4,192,22).");
140         assertEquals("8.8.4.4", client.getPassiveHost());
141         client.setIpAddressFromPasvResponse(false);
142         client._parsePassiveModeReply("227 Entering Passive Mode (8,8,4,4,192,22).");
143         assertNull(client.getPassiveHost());
144     }
145 
146     @SuppressWarnings("deprecation") // testing deprecated code
147     public void testParsePassiveModeReplyForNonLocalAddressWithNatWorkaroundDisabled() throws Exception {
148         final FTPClient client = new PassiveNatWorkAroundLocalClient("8.8.8.8");
149         client.setPassiveNatWorkaround(false);
150         client.setIpAddressFromPasvResponse(true);
151         client._parsePassiveModeReply("227 Entering Passive Mode (8,8,4,4,192,22).");
152         assertEquals("8.8.4.4", client.getPassiveHost());
153         client.setIpAddressFromPasvResponse(false);
154         client._parsePassiveModeReply("227 Entering Passive Mode (8,8,4,4,192,22).");
155         assertNull(client.getPassiveHost());
156     }
157 
158     public void testParsePassiveModeReplyForNonLocalAddressWithoutNatWorkaroundStrategy() throws Exception {
159         final FTPClient client = new PassiveNatWorkAroundLocalClient("8.8.8.8");
160         client.setPassiveNatWorkaroundStrategy(null);
161         client.setIpAddressFromPasvResponse(true);
162         client._parsePassiveModeReply("227 Entering Passive Mode (8,8,4,4,192,22).");
163         assertEquals("8.8.4.4", client.getPassiveHost());
164         client.setIpAddressFromPasvResponse(false);
165         client._parsePassiveModeReply("227 Entering Passive Mode (8,8,4,4,192,22).");
166         assertNull(client.getPassiveHost());
167     }
168 
169     public void testParserCachingNullKey() throws Exception {
170         final LocalClient client = new LocalClient();
171         client.setSystemType(FTPClientConfig.SYST_UNIX);
172         assertNull(client.getEntryParser());
173         client.createParser(null);
174         final FTPFileEntryParser entryParser = client.getEntryParser();
175         assertNotNull(entryParser);
176         client.createParser(null);
177         assertSame(entryParser, client.getEntryParser()); // parser was cached
178         client.setSystemType(FTPClientConfig.SYST_NT);
179         client.createParser(null);
180         assertSame(entryParser, client.getEntryParser()); // parser was cached
181     }
182 
183     public void testParserCachingWithKey() throws Exception {
184         final FTPClient client = new FTPClient();
185         assertNull(client.getEntryParser());
186         client.createParser(FTPClientConfig.SYST_UNIX);
187         final FTPFileEntryParser entryParserSYST = client.getEntryParser();
188         assertNotNull(entryParserSYST);
189         client.createParser(FTPClientConfig.SYST_UNIX);
190         assertSame(entryParserSYST, client.getEntryParser()); // the previous entry was cached
191         client.createParser(FTPClientConfig.SYST_VMS);
192         final FTPFileEntryParser entryParserVMS = client.getEntryParser();
193         assertNotSame(entryParserSYST, entryParserVMS); // the previous entry was replaced
194         client.createParser(FTPClientConfig.SYST_VMS);
195         assertSame(entryParserVMS, client.getEntryParser()); // the previous entry was cached
196         client.createParser(FTPClientConfig.SYST_UNIX); // revert
197         assertNotSame(entryParserVMS, client.getEntryParser()); // the previous entry was replaced
198     }
199 
200     public void testUnparseableFiles() throws Exception {
201         final ByteArrayOutputStream baos = new ByteArrayOutputStream();
202         baos.write("-rwxr-xr-x   2 root     root         4096 Mar  2 15:13 zxbox".getBytes());
203         baos.write(new byte[] { '\r', '\n' });
204         baos.write("zrwxr-xr-x   2 root     root         4096 Mar  2 15:13 zxbox".getBytes());
205         baos.write(new byte[] { '\r', '\n' });
206         final FTPFileEntryParser parser = new UnixFTPEntryParser();
207         final FTPClientConfig config = new FTPClientConfig();
208         FTPListParseEngine engine = new FTPListParseEngine(parser, config);
209         config.setUnparseableEntries(false);
210         engine.readServerList(new ByteArrayInputStream(baos.toByteArray()), null); // use default encoding
211         FTPFile[] files = engine.getFiles();
212         assertEquals(1, files.length);
213         config.setUnparseableEntries(true);
214         engine = new FTPListParseEngine(parser, config);
215         engine.readServerList(new ByteArrayInputStream(baos.toByteArray()), null); // use default encoding
216         files = engine.getFiles();
217         assertEquals(2, files.length);
218     }
219 }