1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.eclipse.jetty.util.resource;
20
21 import java.io.File;
22 import java.io.FileInputStream;
23 import java.io.IOException;
24 import java.io.InputStream;
25 import java.net.MalformedURLException;
26 import java.net.URI;
27 import java.net.URISyntaxException;
28 import java.net.URL;
29 import java.net.URLConnection;
30 import java.nio.channels.FileChannel;
31 import java.nio.channels.ReadableByteChannel;
32 import java.nio.file.InvalidPathException;
33 import java.nio.file.StandardOpenOption;
34 import java.security.Permission;
35
36 import org.eclipse.jetty.util.IO;
37 import org.eclipse.jetty.util.StringUtil;
38 import org.eclipse.jetty.util.URIUtil;
39 import org.eclipse.jetty.util.log.Log;
40 import org.eclipse.jetty.util.log.Logger;
41
42
43
44
45
46
47
48
49
50
51
52 public class FileResource extends Resource
53 {
54 private static final Logger LOG = Log.getLogger(FileResource.class);
55
56
57 private final File _file;
58 private final String _uri;
59 private final URI _alias;
60
61
62 public FileResource(URL url)
63 throws IOException, URISyntaxException
64 {
65 File file;
66 try
67 {
68
69 file =new File(url.toURI());
70 assertValidPath(file.toString());
71 }
72 catch (URISyntaxException e)
73 {
74 throw e;
75 }
76 catch (Exception e)
77 {
78 if (!url.toString().startsWith("file:"))
79 throw new IllegalArgumentException("!file:");
80
81 LOG.ignore(e);
82 try
83 {
84
85 String file_url="file:"+URIUtil.encodePath(url.toString().substring(5));
86 URI uri = new URI(file_url);
87 if (uri.getAuthority()==null)
88 file = new File(uri);
89 else
90 file = new File("//"+uri.getAuthority()+URIUtil.decodePath(url.getFile()));
91 }
92 catch (Exception e2)
93 {
94 LOG.ignore(e2);
95
96 URLConnection connection=url.openConnection();
97 Permission perm = connection.getPermission();
98 file = new File(perm==null?url.getFile():perm.getName());
99 }
100 }
101
102 _file=file;
103 _uri=normalizeURI(_file,url.toURI());
104 _alias=checkFileAlias(_file);
105 }
106
107
108 public FileResource(URI uri)
109 {
110 File file=new File(uri);
111 _file=file;
112 URI file_uri=_file.toURI();
113 _uri=normalizeURI(_file,uri);
114 assertValidPath(file.toString());
115
116
117 if (!URIUtil.equalsIgnoreEncodings(_uri,file_uri.toString()))
118 _alias=_file.toURI();
119 else
120 _alias=checkFileAlias(_file);
121 }
122
123
124 FileResource(File file)
125 {
126 assertValidPath(file.toString());
127 _file=file;
128 _uri=normalizeURI(_file,_file.toURI());
129 _alias=checkFileAlias(_file);
130 }
131
132
133 private static String normalizeURI(File file, URI uri)
134 {
135 String u =uri.toASCIIString();
136 if (file.isDirectory())
137 {
138 if(!u.endsWith("/"))
139 u+="/";
140 }
141 else if (file.exists() && u.endsWith("/"))
142 u=u.substring(0,u.length()-1);
143 return u;
144 }
145
146
147 private static URI checkFileAlias(File file)
148 {
149 try
150 {
151 String abs=file.getAbsolutePath();
152 String can=file.getCanonicalPath();
153
154 if (!abs.equals(can))
155 {
156 if (LOG.isDebugEnabled())
157 LOG.debug("ALIAS abs={} can={}",abs,can);
158
159 URI alias=new File(can).toURI();
160
161 return new URI("file://"+URIUtil.encodePath(alias.getPath()));
162 }
163 }
164 catch(Exception e)
165 {
166 LOG.warn("bad alias for {}: {}",file,e.toString());
167 LOG.debug(e);
168 try
169 {
170 return new URI("http://eclipse.org/bad/canonical/alias");
171 }
172 catch(Exception e2)
173 {
174 LOG.ignore(e2);
175 throw new RuntimeException(e);
176 }
177 }
178
179 return null;
180 }
181
182
183 @Override
184 public Resource addPath(String path)
185 throws IOException,MalformedURLException
186 {
187 assertValidPath(path);
188 path = org.eclipse.jetty.util.URIUtil.canonicalPath(path);
189
190 if (path==null)
191 throw new MalformedURLException();
192
193 if ("/".equals(path))
194 return this;
195
196 path=URIUtil.encodePath(path);
197
198 URI uri;
199 try
200 {
201 if (_file.isDirectory())
202 {
203
204 uri=new URI(URIUtil.addPaths(_uri,path));
205 }
206 else
207 {
208 uri=new URI(_uri+path);
209 }
210 }
211 catch(final URISyntaxException e)
212 {
213 throw new InvalidPathException(path, e.getMessage());
214 }
215
216 return new FileResource(uri);
217 }
218
219 private void assertValidPath(String path)
220 {
221 int idx = StringUtil.indexOfControlChars(path);
222 if (idx >= 0)
223 {
224 throw new InvalidPathException(path, "Invalid Character at index " + idx);
225 }
226 }
227
228
229 @Override
230 public URI getAlias()
231 {
232 return _alias;
233 }
234
235
236
237
238
239 @Override
240 public boolean exists()
241 {
242 return _file.exists();
243 }
244
245
246
247
248
249 @Override
250 public long lastModified()
251 {
252 return _file.lastModified();
253 }
254
255
256
257
258
259 @Override
260 public boolean isDirectory()
261 {
262 return _file.exists() && _file.isDirectory() || _uri.endsWith("/");
263 }
264
265
266
267
268
269 @Override
270 public long length()
271 {
272 return _file.length();
273 }
274
275
276
277
278
279
280 @Override
281 public String getName()
282 {
283 return _file.getAbsolutePath();
284 }
285
286
287
288
289
290
291 @Override
292 public File getFile()
293 {
294 return _file;
295 }
296
297
298
299
300
301 @Override
302 public InputStream getInputStream() throws IOException
303 {
304 return new FileInputStream(_file);
305 }
306
307
308 @Override
309 public ReadableByteChannel getReadableByteChannel() throws IOException
310 {
311 return FileChannel.open(_file.toPath(),StandardOpenOption.READ);
312 }
313
314
315
316
317
318 @Override
319 public boolean delete()
320 throws SecurityException
321 {
322 return _file.delete();
323 }
324
325
326
327
328
329 @Override
330 public boolean renameTo( Resource dest)
331 throws SecurityException
332 {
333 if( dest instanceof FileResource)
334 return _file.renameTo( ((FileResource)dest)._file);
335 else
336 return false;
337 }
338
339
340
341
342
343 @Override
344 public String[] list()
345 {
346 String[] list =_file.list();
347 if (list==null)
348 return null;
349 for (int i=list.length;i-->0;)
350 {
351 if (new File(_file,list[i]).isDirectory() &&
352 !list[i].endsWith("/"))
353 list[i]+="/";
354 }
355 return list;
356 }
357
358
359
360
361
362
363 @Override
364 public boolean equals( Object o)
365 {
366 if (this == o)
367 return true;
368
369 if (null == o || ! (o instanceof FileResource))
370 return false;
371
372 FileResource f=(FileResource)o;
373 return f._file == _file || (null != _file && _file.equals(f._file));
374 }
375
376
377
378
379
380 @Override
381 public int hashCode()
382 {
383 return null == _file ? super.hashCode() : _file.hashCode();
384 }
385
386
387 @Override
388 public void copyTo(File destination)
389 throws IOException
390 {
391 if (isDirectory())
392 {
393 IO.copyDir(getFile(),destination);
394 }
395 else
396 {
397 if (destination.exists())
398 throw new IllegalArgumentException(destination+" exists");
399 IO.copy(getFile(),destination);
400 }
401 }
402
403 @Override
404 public boolean isContainedIn(Resource r) throws MalformedURLException
405 {
406 return false;
407 }
408
409 @Override
410 public void close()
411 {
412 }
413
414 @Override
415 public URL getURL()
416 {
417 try
418 {
419 return new URL(_uri);
420 }
421 catch (MalformedURLException e)
422 {
423 throw new IllegalStateException(e);
424 }
425 }
426
427 @Override
428 public URI getURI()
429 {
430 return _file.toURI();
431 }
432
433 @Override
434 public String toString()
435 {
436 return _uri;
437 }
438
439 }