001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017: package org.apache.commons.vfs.provider;
018:
019: import org.apache.commons.vfs.FileName;
020: import org.apache.commons.vfs.FileSystemException;
021: import org.apache.commons.vfs.FileType;
022:
023: /**
024: * Implementation for any url based filesystem.<br />
025: * Parses the url into user/password/host/port/path<br />
026: * Does not handle a query string (after ?)
027: *
028: * @author imario@apache.org
029: * @version $Revision: 480428 $ $Date: 2006-11-28 22:15:24 -0800 (Tue, 28 Nov 2006) $
030: * @see URLFileNameParser URLFileNameParser for the implementation which also handles the query string too
031: */
032: public class HostFileNameParser extends AbstractFileNameParser {
033: private final int defaultPort;
034:
035: public HostFileNameParser(final int defaultPort) {
036: this .defaultPort = defaultPort;
037: }
038:
039: public int getDefaultPort() {
040: return defaultPort;
041: }
042:
043: public boolean encodeCharacter(char ch) {
044: return super .encodeCharacter(ch);
045: }
046:
047: public FileName parseUri(final VfsComponentContext context,
048: FileName base, final String filename)
049: throws FileSystemException {
050: // FTP URI are generic URI (as per RFC 2396)
051: final StringBuffer name = new StringBuffer();
052:
053: // Extract the scheme and authority parts
054: final Authority auth = extractToPath(filename, name);
055:
056: // Decode and normalise the file name
057: UriParser.canonicalizePath(name, 0, name.length(), this );
058: UriParser.fixSeparators(name);
059: FileType fileType = UriParser.normalisePath(name);
060: final String path = name.toString();
061:
062: return new GenericFileName(auth.scheme, auth.hostName,
063: auth.port, defaultPort, auth.userName, auth.password,
064: path, fileType);
065: }
066:
067: /**
068: * Extracts the scheme, userinfo, hostname and port components of a
069: * generic URI.
070: *
071: * @param uri The absolute URI to parse.
072: * @param name Used to return the remainder of the URI.
073: */
074: protected Authority extractToPath(final String uri,
075: final StringBuffer name) throws FileSystemException {
076: final Authority auth = new Authority();
077:
078: // Extract the scheme
079: auth.scheme = UriParser.extractScheme(uri, name);
080:
081: // Expecting "//"
082: if (name.length() < 2 || name.charAt(0) != '/'
083: || name.charAt(1) != '/') {
084: throw new FileSystemException(
085: "vfs.provider/missing-double-slashes.error", uri);
086: }
087: name.delete(0, 2);
088:
089: // Extract userinfo, and split into username and password
090: final String userInfo = extractUserInfo(name);
091: final String userName;
092: final String password;
093: if (userInfo != null) {
094: int idx = userInfo.indexOf(':');
095: if (idx == -1) {
096: userName = userInfo;
097: password = null;
098: } else {
099: userName = userInfo.substring(0, idx);
100: password = userInfo.substring(idx + 1);
101: }
102: } else {
103: userName = null;
104: password = null;
105: }
106: auth.userName = UriParser.decode(userName);
107: auth.password = UriParser.decode(password);
108:
109: // Extract hostname, and normalise (lowercase)
110: final String hostName = extractHostName(name);
111: if (hostName == null) {
112: throw new FileSystemException(
113: "vfs.provider/missing-hostname.error", uri);
114: }
115: auth.hostName = hostName.toLowerCase();
116:
117: // Extract port
118: auth.port = extractPort(name, uri);
119:
120: // Expecting '/' or empty name
121: if (name.length() > 0 && name.charAt(0) != '/') {
122: throw new FileSystemException(
123: "vfs.provider/missing-hostname-path-sep.error", uri);
124: }
125:
126: return auth;
127: }
128:
129: /**
130: * Extracts the user info from a URI. The scheme:// part has been removed
131: * already.
132: */
133: protected String extractUserInfo(final StringBuffer name) {
134: final int maxlen = name.length();
135: for (int pos = 0; pos < maxlen; pos++) {
136: final char ch = name.charAt(pos);
137: if (ch == '@') {
138: // Found the end of the user info
139: String userInfo = name.substring(0, pos);
140: name.delete(0, pos + 1);
141: return userInfo;
142: }
143: if (ch == '/' || ch == '?') {
144: // Not allowed in user info
145: break;
146: }
147: }
148:
149: // Not found
150: return null;
151: }
152:
153: /**
154: * Extracts the hostname from a URI. The scheme://userinfo@ part has
155: * been removed.
156: */
157: protected String extractHostName(final StringBuffer name) {
158: final int maxlen = name.length();
159: int pos = 0;
160: for (; pos < maxlen; pos++) {
161: final char ch = name.charAt(pos);
162: if (ch == '/' || ch == ';' || ch == '?' || ch == ':'
163: || ch == '@' || ch == '&' || ch == '=' || ch == '+'
164: || ch == '$' || ch == ',') {
165: break;
166: }
167: }
168: if (pos == 0) {
169: return null;
170: }
171:
172: final String hostname = name.substring(0, pos);
173: name.delete(0, pos);
174: return hostname;
175: }
176:
177: /**
178: * Extracts the port from a URI. The scheme://userinfo@hostname
179: * part has been removed.
180: *
181: * @return The port, or -1 if the URI does not contain a port.
182: */
183: protected int extractPort(final StringBuffer name, final String uri)
184: throws FileSystemException {
185: if (name.length() < 1 || name.charAt(0) != ':') {
186: return -1;
187: }
188:
189: final int maxlen = name.length();
190: int pos = 1;
191: for (; pos < maxlen; pos++) {
192: final char ch = name.charAt(pos);
193: if (ch < '0' || ch > '9') {
194: break;
195: }
196: }
197:
198: final String port = name.substring(1, pos);
199: name.delete(0, pos);
200: if (port.length() == 0) {
201: throw new FileSystemException(
202: "vfs.provider/missing-port.error", uri);
203: }
204:
205: return Integer.parseInt(port);
206: }
207:
208: /**
209: * Parsed authority info (scheme, hostname, userinfo, port)
210: */
211: protected static class Authority {
212: public String scheme;
213: public String hostName;
214: public String userName;
215: public String password;
216: public int port;
217: }
218: }
|