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 }