]> WPIA git - gigi.git/blob - lib/jetty/org/eclipse/jetty/util/resource/FileResource.java
updating jetty to jetty-9.2.16.v2016040
[gigi.git] / lib / jetty / org / eclipse / jetty / util / resource / FileResource.java
1 //
2 //  ========================================================================
3 //  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
4 //  ------------------------------------------------------------------------
5 //  All rights reserved. This program and the accompanying materials
6 //  are made available under the terms of the Eclipse Public License v1.0
7 //  and Apache License v2.0 which accompanies this distribution.
8 //
9 //      The Eclipse Public License is available at
10 //      http://www.eclipse.org/legal/epl-v10.html
11 //
12 //      The Apache License v2.0 is available at
13 //      http://www.opensource.org/licenses/apache2.0.php
14 //
15 //  You may elect to redistribute this code under either of these licenses.
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 /** File Resource.
45  *
46  * Handle resources of implied or explicit file type.
47  * This class can check for aliasing in the filesystem (eg case
48  * insensitivity).  By default this is turned on, or it can be controlled 
49  * by calling the static method @see FileResource#setCheckAliases(boolean)
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             // Try standard API to convert URL to file.
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                 // Assume that File.toURL produced unencoded chars. So try encoding them.
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                 // Still can't get the file.  Doh! try good old hack!
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         // Is it a URI alias?
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                 // Have to encode the path as File.toURI does not!
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         // The encoded path should be a suffix of the resource (give or take a directory / )
198         URI uri;
199         try
200         {
201             if (_file.isDirectory())
202             {
203                 // treat all paths being added as relative
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      * Returns true if the resource exists.
238      */
239     @Override
240     public boolean exists()
241     {
242         return _file.exists();
243     }
244         
245     /* -------------------------------------------------------- */
246     /**
247      * Returns the last modified time
248      */
249     @Override
250     public long lastModified()
251     {
252         return _file.lastModified();
253     }
254
255     /* -------------------------------------------------------- */
256     /**
257      * Returns true if the resource is a container/directory.
258      */
259     @Override
260     public boolean isDirectory()
261     {
262         return _file.exists() && _file.isDirectory() || _uri.endsWith("/");
263     }
264
265     /* --------------------------------------------------------- */
266     /**
267      * Return the length of the resource
268      */
269     @Override
270     public long length()
271     {
272         return _file.length();
273     }
274         
275
276     /* --------------------------------------------------------- */
277     /**
278      * Returns the name of the resource
279      */
280     @Override
281     public String getName()
282     {
283         return _file.getAbsolutePath();
284     }
285         
286     /* ------------------------------------------------------------ */
287     /**
288      * Returns an File representing the given resource or NULL if this
289      * is not possible.
290      */
291     @Override
292     public File getFile()
293     {
294         return _file;
295     }
296         
297     /* --------------------------------------------------------- */
298     /**
299      * Returns an input stream to the resource
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      * Deletes the given resource
317      */
318     @Override
319     public boolean delete()
320         throws SecurityException
321     {
322         return _file.delete();
323     }
324
325     /* --------------------------------------------------------- */
326     /**
327      * Rename the given resource
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      * Returns a list of resources contained in the given resource
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      * @param o
361      * @return <code>true</code> of the object <code>o</code> is a {@link FileResource} pointing to the same file as this resource. 
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      * @return the hashcode.
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 }