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.vfs2.provider.url;
18  
19  import org.apache.commons.vfs2.FileName;
20  import org.apache.commons.vfs2.FileSystemException;
21  import org.apache.commons.vfs2.provider.AbstractFileNameParser;
22  import org.apache.commons.vfs2.provider.URLFileName;
23  import org.apache.commons.vfs2.provider.URLFileNameParser;
24  import org.apache.commons.vfs2.provider.VfsComponentContext;
25  import org.apache.commons.vfs2.provider.local.GenericFileNameParser;
26  
27  /**
28   * Implementation for any java.net.url based file system.
29   * <p>
30   * Composite of URLFilenameParser and GenericFilenameParser
31   */
32  public class UrlFileNameParser extends AbstractFileNameParser {
33  
34      private final URLFileNameParserParser.html#URLFileNameParser">URLFileNameParser urlFileNameParser = new URLFileNameParser(80);
35      private final GenericFileNameParsermeParser.html#GenericFileNameParser">GenericFileNameParser genericFileNameParser = new GenericFileNameParser();
36  
37      public UrlFileNameParser() {
38      }
39  
40      @Override
41      public boolean encodeCharacter(final char ch) {
42          return super.encodeCharacter(ch) || ch == '?';
43      }
44  
45      /**
46       * Parse a URI.
47       *
48       * @param context The component context.
49       * @param base The base FileName.
50       * @param uri The target file name.
51       * @return The FileName.
52       * @throws FileSystemException if an error occurs
53       */
54      @Override
55      public FileName parseUri(FileNamefinal VfsComponentContext context, final FileName base, final String uri)
56              throws FileSystemException {
57          if (isUrlBased(base, uri)) {
58              return urlFileNameParser.parseUri(context, base, uri);
59          }
60          return genericFileNameParser.parseUri(context, base, uri);
61      }
62  
63      /**
64       * Guess if the given file name is a URL with host or not.
65       * <p>
66       * VFS treats such URLs differently.
67       * </p>
68       * <p>
69       * A file name is URL-based if the base is a {@code URLFileName} or there are only 2 slashes after the scheme. e.g:
70       * {@code http://host/path}, {@code file:/path/to/file}, {@code file:///path/to/file}.
71       * </p>
72       *
73       * @param base The file name is relative to this base.
74       * @param fileName The file name.
75       * @return true if file name contains two slashes or base was URLFileName.
76       */
77      protected boolean isUrlBased(final FileName base, final String fileName) {
78          if (base instanceof URLFileName) {
79              return true;
80          }
81  
82          return countSlashes(fileName) == 2;
83      }
84  
85      /**
86       * This method counts the slashes after the scheme.
87       *
88       * @param fileName The file name.
89       * @return number of slashes
90       */
91      protected int countSlashes(final String fileName) {
92          int state = 0;
93          int nuofSlash = 0;
94          for (int pos = 0; pos < fileName.length(); pos++) {
95              final char c = fileName.charAt(pos);
96              if (state == 0) {
97                  if (c >= 'a' && c <= 'z') {
98                      continue;
99                  }
100                 if (c == ':') {
101                     state++;
102                     continue;
103                 }
104             } else if (state == 1) {
105                 if (c != '/') {
106                     return nuofSlash;
107                 }
108                 nuofSlash++;
109             }
110         }
111         return nuofSlash;
112     }
113 }