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  package org.apache.commons.vfs.provider;
18  
19  import org.apache.commons.vfs.FileName;
20  import org.apache.commons.vfs.FileSystemException;
21  import org.apache.commons.vfs.FileType;
22  
23  /***
24   * Implementation for any url based filesystem.<br />
25   * Parses the url into user/password/host/port/path<br />
26   * Does not handle a query string (after ?)
27   *
28   * @author imario@apache.org
29   * @version $Revision: 480428 $ $Date: 2006-11-29 07:15:24 +0100 (Mi, 29 Nov 2006) $
30   * @see URLFileNameParser URLFileNameParser for the implementation which also handles the query string too
31   */
32  public class HostFileNameParser extends AbstractFileNameParser
33  {
34      private final int defaultPort;
35  
36      public HostFileNameParser(final int defaultPort)
37      {
38          this.defaultPort = defaultPort;
39      }
40  
41      public int getDefaultPort()
42      {
43          return defaultPort;
44      }
45  
46      public boolean encodeCharacter(char ch)
47      {
48          return super.encodeCharacter(ch);
49      }
50  
51      public FileName parseUri(final VfsComponentContext context, FileName base, final String filename) throws FileSystemException
52      {
53          // FTP URI are generic URI (as per RFC 2396)
54          final StringBuffer name = new StringBuffer();
55  
56          // Extract the scheme and authority parts
57          final Authority auth = extractToPath(filename, name);
58  
59          // Decode and normalise the file name
60          UriParser.canonicalizePath(name, 0, name.length(), this);
61          UriParser.fixSeparators(name);
62          FileType fileType = UriParser.normalisePath(name);
63          final String path = name.toString();
64  
65          return new GenericFileName(
66              auth.scheme,
67              auth.hostName,
68              auth.port,
69              defaultPort,
70              auth.userName,
71              auth.password,
72              path,
73              fileType);
74      }
75  
76      /***
77       * Extracts the scheme, userinfo, hostname and port components of a
78       * generic URI.
79       *
80       * @param uri  The absolute URI to parse.
81       * @param name Used to return the remainder of the URI.
82       */
83      protected Authority extractToPath(final String uri,
84                                        final StringBuffer name)
85          throws FileSystemException
86      {
87          final Authority auth = new Authority();
88  
89          // Extract the scheme
90          auth.scheme = UriParser.extractScheme(uri, name);
91  
92          // Expecting "//"
93          if (name.length() < 2 || name.charAt(0) != '/' || name.charAt(1) != '/')
94          {
95              throw new FileSystemException("vfs.provider/missing-double-slashes.error", uri);
96          }
97          name.delete(0, 2);
98  
99          // Extract userinfo, and split into username and password
100         final String userInfo = extractUserInfo(name);
101         final String userName;
102         final String password;
103         if (userInfo != null)
104         {
105             int idx = userInfo.indexOf(':');
106             if (idx == -1)
107             {
108                 userName = userInfo;
109                 password = null;
110             }
111             else
112             {
113                 userName = userInfo.substring(0, idx);
114                 password = userInfo.substring(idx + 1);
115             }
116         }
117         else
118         {
119             userName = null;
120             password = null;
121         }
122         auth.userName = UriParser.decode(userName);
123         auth.password = UriParser.decode(password);
124 
125         // Extract hostname, and normalise (lowercase)
126         final String hostName = extractHostName(name);
127         if (hostName == null)
128         {
129             throw new FileSystemException("vfs.provider/missing-hostname.error", uri);
130         }
131         auth.hostName = hostName.toLowerCase();
132 
133         // Extract port
134         auth.port = extractPort(name, uri);
135 
136         // Expecting '/' or empty name
137         if (name.length() > 0 && name.charAt(0) != '/')
138         {
139             throw new FileSystemException("vfs.provider/missing-hostname-path-sep.error", uri);
140         }
141 
142         return auth;
143     }
144 
145     /***
146      * Extracts the user info from a URI.  The scheme:// part has been removed
147      * already.
148      */
149     protected String extractUserInfo(final StringBuffer name)
150     {
151         final int maxlen = name.length();
152         for (int pos = 0; pos < maxlen; pos++)
153         {
154             final char ch = name.charAt(pos);
155             if (ch == '@')
156             {
157                 // Found the end of the user info
158                 String userInfo = name.substring(0, pos);
159                 name.delete(0, pos + 1);
160                 return userInfo;
161             }
162             if (ch == '/' || ch == '?')
163             {
164                 // Not allowed in user info
165                 break;
166             }
167         }
168 
169         // Not found
170         return null;
171     }
172 
173     /***
174      * Extracts the hostname from a URI.  The scheme://userinfo@ part has
175      * been removed.
176      */
177     protected String extractHostName(final StringBuffer name)
178     {
179         final int maxlen = name.length();
180         int pos = 0;
181         for (; pos < maxlen; pos++)
182         {
183             final char ch = name.charAt(pos);
184             if (ch == '/' || ch == ';' || ch == '?' || ch == ':'
185                 || ch == '@' || ch == '&' || ch == '=' || ch == '+'
186                 || ch == '$' || ch == ',')
187             {
188                 break;
189             }
190         }
191         if (pos == 0)
192         {
193             return null;
194         }
195 
196         final String hostname = name.substring(0, pos);
197         name.delete(0, pos);
198         return hostname;
199     }
200 
201     /***
202      * Extracts the port from a URI.  The scheme://userinfo@hostname
203      * part has been removed.
204      *
205      * @return The port, or -1 if the URI does not contain a port.
206      */
207     protected int extractPort(final StringBuffer name, final String uri) throws FileSystemException
208     {
209         if (name.length() < 1 || name.charAt(0) != ':')
210         {
211             return -1;
212         }
213 
214         final int maxlen = name.length();
215         int pos = 1;
216         for (; pos < maxlen; pos++)
217         {
218             final char ch = name.charAt(pos);
219             if (ch < '0' || ch > '9')
220             {
221                 break;
222             }
223         }
224 
225         final String port = name.substring(1, pos);
226         name.delete(0, pos);
227         if (port.length() == 0)
228         {
229             throw new FileSystemException("vfs.provider/missing-port.error", uri);
230         }
231 
232         return Integer.parseInt(port);
233     }
234 
235     /***
236      * Parsed authority info (scheme, hostname, userinfo, port)
237      */
238     protected static class Authority
239     {
240         public String scheme;
241         public String hostName;
242         public String userName;
243         public String password;
244         public int port;
245     }
246 }