1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.commons.vfs2.provider;
18
19 import org.apache.commons.vfs2.FileName;
20 import org.apache.commons.vfs2.FileSystemException;
21 import org.apache.commons.vfs2.FileSystemManager;
22 import org.apache.commons.vfs2.FileType;
23 import org.apache.commons.vfs2.VFS;
24 import org.apache.commons.vfs2.util.Cryptor;
25 import org.apache.commons.vfs2.util.CryptorFactory;
26
27
28
29
30
31
32
33
34
35 public class HostFileNameParser extends AbstractFileNameParser {
36
37
38
39
40 protected static class Authority {
41
42 private String hostName;
43 private String password;
44 private int port;
45 private String scheme;
46 private String userName;
47
48
49
50
51 public Authority() {
52
53 }
54
55
56
57
58
59
60
61 public String getHostName() {
62 return hostName;
63 }
64
65
66
67
68
69
70
71 public String getPassword() {
72 return password;
73 }
74
75
76
77
78
79
80
81 public int getPort() {
82 return port;
83 }
84
85
86
87
88
89
90
91 public String getScheme() {
92 return scheme;
93 }
94
95
96
97
98
99
100
101 public String getUserName() {
102 return userName;
103 }
104
105
106
107
108
109
110
111 public void setHostName(final String hostName) {
112 this.hostName = hostName;
113 }
114
115
116
117
118
119
120
121 public void setPassword(final String password) {
122 this.password = password;
123 }
124
125
126
127
128
129
130
131 public void setPort(final int port) {
132 this.port = port;
133 }
134
135
136
137
138
139
140
141 public void setScheme(final String scheme) {
142 this.scheme = scheme;
143 }
144
145
146
147
148
149
150
151 public void setUserName(final String userName) {
152 this.userName = userName;
153 }
154 }
155
156 private static boolean isHostNameTerminatingChar(final char ch, final boolean isIPv6Host) {
157 if (isIPv6Host) {
158 return ch == ']';
159 }
160
161 return ch == '/' || ch == ';' || ch == '?' || ch == ':' || ch == '@' || ch == '&' || ch == '=' || ch == '+'
162 || ch == '$' || ch == ',';
163 }
164
165 private static boolean isIPv6Host(final String name) {
166 return name.length() > 0 && isIPv6HostHeadingChar(name.charAt(0));
167 }
168
169 private static boolean isIPv6HostHeadingChar(final char ch) {
170 return ch == '[';
171 }
172
173 private final int defaultPort;
174
175
176
177
178
179
180 public HostFileNameParser(final int defaultPort) {
181 this.defaultPort = defaultPort;
182 }
183
184
185
186
187
188
189
190 protected String extractHostName(final StringBuilder name) {
191 final int maxlen = name.length();
192 final boolean isIPv6Host = isIPv6Host(name.toString());
193 int pos = 0;
194 for (; pos < maxlen; pos++) {
195 final char ch = name.charAt(pos);
196 if (isHostNameTerminatingChar(ch, isIPv6Host)) {
197 break;
198 }
199 }
200 if (pos == 0) {
201 return null;
202 }
203
204 if (isIPv6Host && pos < maxlen) {
205 if (pos == 1) {
206 return null;
207 }
208
209 pos++;
210 }
211
212 final String hostname = name.substring(0, pos);
213 name.delete(0, pos);
214 return hostname;
215 }
216
217
218
219
220
221
222
223
224
225
226
227 protected int extractPort(final StringBuilder name, final String uri) throws FileSystemException {
228 if (name.length() < 1 || name.charAt(0) != ':') {
229 return -1;
230 }
231
232 final int maxlen = name.length();
233 int pos = 1;
234 for (; pos < maxlen; pos++) {
235 final char ch = name.charAt(pos);
236 if (ch < '0' || ch > '9') {
237 break;
238 }
239 }
240
241 final String port = name.substring(1, pos);
242 name.delete(0, pos);
243 if (port.isEmpty()) {
244 throw new FileSystemException("vfs.provider/missing-port.error", uri);
245 }
246
247 return Integer.parseInt(port);
248 }
249
250
251
252
253
254
255
256
257
258
259 @Deprecated
260 protected Authority extractToPath(final String uri, final StringBuilder name) throws FileSystemException {
261 return extractToPath(null, uri, name);
262 }
263
264
265
266
267
268
269
270
271
272
273 protected Authority extractToPath(final VfsComponentContext context, final String uri, final StringBuilder name) throws FileSystemException {
274 final Authority auth = new Authority();
275
276 final FileSystemManager fsm;
277 if (context != null) {
278 fsm = context.getFileSystemManager();
279 } else {
280 fsm = VFS.getManager();
281 }
282
283
284 auth.scheme = UriParser.extractScheme(fsm.getSchemes(), uri, name);
285
286
287 if (name.length() < 2 || name.charAt(0) != '/' || name.charAt(1) != '/') {
288 throw new FileSystemException("vfs.provider/missing-double-slashes.error", uri);
289 }
290 name.delete(0, 2);
291
292
293 final String userInfo = extractUserInfo(name);
294 final String userName;
295 final String password;
296 if (userInfo != null) {
297 final int idx = userInfo.indexOf(':');
298 if (idx == -1) {
299 userName = userInfo;
300 password = null;
301 } else {
302 userName = userInfo.substring(0, idx);
303 password = userInfo.substring(idx + 1);
304 }
305 } else {
306 userName = null;
307 password = null;
308 }
309 auth.userName = UriParser.decode(userName);
310 auth.password = UriParser.decode(password);
311
312 if (auth.password != null && auth.password.startsWith("{") && auth.password.endsWith("}")) {
313 try {
314 final Cryptor cryptor = CryptorFactory.getCryptor();
315 auth.password = cryptor.decrypt(auth.password.substring(1, auth.password.length() - 1));
316 } catch (final Exception ex) {
317 throw new FileSystemException("Unable to decrypt password", ex);
318 }
319 }
320
321
322 final String hostName = extractHostName(name);
323 if (hostName == null) {
324 throw new FileSystemException("vfs.provider/missing-hostname.error", uri);
325 }
326 if (isIPv6Host(hostName) && !isHostNameTerminatingChar(hostName.charAt(hostName.length() - 1), true)) {
327 throw new FileSystemException("vfs.provider/unterminated-ipv6-hostname.error", uri);
328 }
329
330 auth.hostName = hostName.toLowerCase();
331
332
333 auth.port = extractPort(name, uri);
334
335
336 if (name.length() > 0 && name.charAt(0) != '/') {
337 throw new FileSystemException("vfs.provider/missing-hostname-path-sep.error", uri);
338 }
339
340 return auth;
341 }
342
343
344
345
346
347
348
349 protected String extractUserInfo(final StringBuilder name) {
350 final int maxlen = name.length();
351 for (int pos = 0; pos < maxlen; pos++) {
352 final char ch = name.charAt(pos);
353 if (ch == '@') {
354
355 final String userInfo = name.substring(0, pos);
356 name.delete(0, pos + 1);
357 return userInfo;
358 }
359 if (ch == '/' || ch == '?') {
360
361 break;
362 }
363 }
364
365
366 return null;
367 }
368
369
370
371
372
373
374 public int getDefaultPort() {
375 return defaultPort;
376 }
377
378 @Override
379 public FileName parseUri(final VfsComponentContext context, final FileName base, final String fileName)
380 throws FileSystemException {
381
382 final StringBuilder name = new StringBuilder();
383
384
385 final Authority auth = extractToPath(context, fileName, name);
386
387
388 UriParser.canonicalizePath(name, 0, name.length(), this);
389 UriParser.fixSeparators(name);
390 final FileType fileType = UriParser.normalisePath(name);
391 final String path = name.toString();
392
393 return new GenericFileName(auth.scheme, auth.hostName, auth.port, defaultPort, auth.userName, auth.password,
394 path, fileType);
395 }
396 }