| // |
| // ======================================================================== |
| // Copyright (c) 1995-2017 Mort Bay Consulting Pty. Ltd. |
| // ------------------------------------------------------------------------ |
| // All rights reserved. This program and the accompanying materials |
| // are made available under the terms of the Eclipse Public License v1.0 |
| // and Apache License v2.0 which accompanies this distribution. |
| // |
| // The Eclipse Public License is available at |
| // http://www.eclipse.org/legal/epl-v10.html |
| // |
| // The Apache License v2.0 is available at |
| // http://www.opensource.org/licenses/apache2.0.php |
| // |
| // You may elect to redistribute this code under either of these licenses. |
| // ======================================================================== |
| // |
| |
| package org.eclipse.jetty.util.resource; |
| |
| import java.io.File; |
| import java.io.FileInputStream; |
| import java.io.IOException; |
| import java.io.InputStream; |
| import java.net.MalformedURLException; |
| import java.net.URI; |
| import java.net.URISyntaxException; |
| import java.net.URL; |
| import java.net.URLConnection; |
| import java.nio.channels.FileChannel; |
| import java.nio.channels.ReadableByteChannel; |
| import java.nio.file.InvalidPathException; |
| import java.nio.file.StandardOpenOption; |
| import java.security.Permission; |
| |
| import org.eclipse.jetty.util.IO; |
| import org.eclipse.jetty.util.StringUtil; |
| import org.eclipse.jetty.util.URIUtil; |
| import org.eclipse.jetty.util.log.Log; |
| import org.eclipse.jetty.util.log.Logger; |
| |
| |
| /* ------------------------------------------------------------ */ |
| /** File Resource. |
| * |
| * Handle resources of implied or explicit file type. |
| * This class can check for aliasing in the filesystem (eg case |
| * insensitivity). By default this is turned on, or it can be controlled |
| * by calling the static method @see FileResource#setCheckAliases(boolean) |
| * |
| * @deprecated Use {@link PathResource} |
| */ |
| @Deprecated |
| public class FileResource extends Resource |
| { |
| private static final Logger LOG = Log.getLogger(FileResource.class); |
| |
| /* ------------------------------------------------------------ */ |
| private final File _file; |
| private final URI _uri; |
| private final URI _alias; |
| |
| /* -------------------------------------------------------- */ |
| public FileResource(URL url) |
| throws IOException, URISyntaxException |
| { |
| File file; |
| try |
| { |
| // Try standard API to convert URL to file. |
| file =new File(url.toURI()); |
| assertValidPath(file.toString()); |
| } |
| catch (URISyntaxException e) |
| { |
| throw e; |
| } |
| catch (Exception e) |
| { |
| if (!url.toString().startsWith("file:")) |
| throw new IllegalArgumentException("!file:"); |
| |
| LOG.ignore(e); |
| try |
| { |
| // Assume that File.toURL produced unencoded chars. So try encoding them. |
| String file_url="file:"+URIUtil.encodePath(url.toString().substring(5)); |
| URI uri = new URI(file_url); |
| if (uri.getAuthority()==null) |
| file = new File(uri); |
| else |
| file = new File("//"+uri.getAuthority()+URIUtil.decodePath(url.getFile())); |
| } |
| catch (Exception e2) |
| { |
| LOG.ignore(e2); |
| // Still can't get the file. Doh! try good old hack! |
| URLConnection connection=url.openConnection(); |
| Permission perm = connection.getPermission(); |
| file = new File(perm==null?url.getFile():perm.getName()); |
| } |
| } |
| |
| _file=file; |
| _uri=normalizeURI(_file,url.toURI()); |
| _alias=checkFileAlias(_uri,_file); |
| } |
| |
| /* -------------------------------------------------------- */ |
| public FileResource(URI uri) |
| { |
| File file=new File(uri); |
| _file=file; |
| try |
| { |
| URI file_uri = _file.toURI(); |
| _uri = normalizeURI(_file, uri); |
| assertValidPath(file.toString()); |
| |
| // Is it a URI alias? |
| if (!URIUtil.equalsIgnoreEncodings(_uri.toASCIIString(), file_uri.toString())) |
| _alias = _file.toURI(); |
| else |
| _alias = checkFileAlias(_uri, _file); |
| } |
| catch (URISyntaxException e) |
| { |
| throw new InvalidPathException(_file.toString(), e.getMessage()) |
| { |
| { |
| initCause(e); |
| } |
| }; |
| } |
| } |
| |
| /* -------------------------------------------------------- */ |
| public FileResource(File file) |
| { |
| assertValidPath(file.toString()); |
| _file=file; |
| try |
| { |
| _uri = normalizeURI(_file, _file.toURI()); |
| } |
| catch (URISyntaxException e) |
| { |
| throw new InvalidPathException(_file.toString(), e.getMessage()) |
| { |
| { |
| initCause(e); |
| } |
| }; |
| } |
| _alias=checkFileAlias(_uri,_file); |
| } |
| |
| /* -------------------------------------------------------- */ |
| public FileResource(File base, String childPath) |
| { |
| String encoded = URIUtil.encodePath(childPath); |
| |
| _file = new File(base, childPath); |
| |
| // The encoded path should be a suffix of the resource (give or take a directory / ) |
| URI uri; |
| try |
| { |
| if (base.isDirectory()) |
| { |
| // treat all paths being added as relative |
| uri=new URI(URIUtil.addEncodedPaths(base.toURI().toASCIIString(),encoded)); |
| } |
| else |
| { |
| uri=new URI(base.toURI().toASCIIString()+encoded); |
| } |
| } |
| catch (final URISyntaxException e) |
| { |
| throw new InvalidPathException(base.toString() + childPath, e.getMessage()) |
| { |
| { |
| initCause(e); |
| } |
| }; |
| } |
| |
| _uri=uri; |
| _alias=checkFileAlias(_uri,_file); |
| } |
| |
| /* -------------------------------------------------------- */ |
| private static URI normalizeURI(File file, URI uri) throws URISyntaxException { |
| String u =uri.toASCIIString(); |
| if (file.isDirectory()) |
| { |
| if(!u.endsWith("/")) |
| u+="/"; |
| } |
| else if (file.exists() && u.endsWith("/")) |
| u=u.substring(0,u.length()-1); |
| return new URI(u); |
| } |
| |
| /* -------------------------------------------------------- */ |
| private static URI checkFileAlias(final URI uri, final File file) |
| { |
| try |
| { |
| if (!URIUtil.equalsIgnoreEncodings(uri,file.toURI())) |
| { |
| // Return alias pointing to Java File normalized URI |
| return new File(uri).getAbsoluteFile().toURI(); |
| } |
| |
| String abs=file.getAbsolutePath(); |
| String can=file.getCanonicalPath(); |
| |
| if (!abs.equals(can)) |
| { |
| if (LOG.isDebugEnabled()) |
| LOG.debug("ALIAS abs={} can={}",abs,can); |
| |
| URI alias=new File(can).toURI(); |
| // Have to encode the path as File.toURI does not! |
| return new URI("file://"+URIUtil.encodePath(alias.getPath())); |
| } |
| } |
| catch(Exception e) |
| { |
| LOG.warn("bad alias for {}: {}",file,e.toString()); |
| LOG.debug(e); |
| try |
| { |
| return new URI("http://eclipse.org/bad/canonical/alias"); |
| } |
| catch(Exception e2) |
| { |
| LOG.ignore(e2); |
| throw new RuntimeException(e); |
| } |
| } |
| |
| return null; |
| } |
| |
| /* -------------------------------------------------------- */ |
| @Override |
| public Resource addPath(String path) |
| throws IOException, MalformedURLException |
| { |
| assertValidPath(path); |
| path = org.eclipse.jetty.util.URIUtil.canonicalPath(path); |
| |
| if (path==null) |
| throw new MalformedURLException(); |
| |
| if ("/".equals(path)) |
| return this; |
| |
| return new FileResource(_file, path); |
| } |
| |
| private void assertValidPath(String path) |
| { |
| int idx = StringUtil.indexOfControlChars(path); |
| if (idx >= 0) |
| { |
| throw new InvalidPathException(path, "Invalid Character at index " + idx); |
| } |
| } |
| |
| /* ------------------------------------------------------------ */ |
| @Override |
| public URI getAlias() |
| { |
| return _alias; |
| } |
| |
| /* -------------------------------------------------------- */ |
| /** |
| * Returns true if the resource exists. |
| */ |
| @Override |
| public boolean exists() |
| { |
| return _file.exists(); |
| } |
| |
| /* -------------------------------------------------------- */ |
| /** |
| * Returns the last modified time |
| */ |
| @Override |
| public long lastModified() |
| { |
| return _file.lastModified(); |
| } |
| |
| /* -------------------------------------------------------- */ |
| /** |
| * Returns true if the resource is a container/directory. |
| */ |
| @Override |
| public boolean isDirectory() |
| { |
| return _file.exists() && _file.isDirectory() || _uri.toASCIIString().endsWith("/"); |
| } |
| |
| /* --------------------------------------------------------- */ |
| /** |
| * Return the length of the resource |
| */ |
| @Override |
| public long length() |
| { |
| return _file.length(); |
| } |
| |
| |
| /* --------------------------------------------------------- */ |
| /** |
| * Returns the name of the resource |
| */ |
| @Override |
| public String getName() |
| { |
| return _file.getAbsolutePath(); |
| } |
| |
| /* ------------------------------------------------------------ */ |
| /** |
| * Returns an File representing the given resource or NULL if this |
| * is not possible. |
| */ |
| @Override |
| public File getFile() |
| { |
| return _file; |
| } |
| |
| /* --------------------------------------------------------- */ |
| /** |
| * Returns an input stream to the resource |
| */ |
| @Override |
| public InputStream getInputStream() throws IOException |
| { |
| return new FileInputStream(_file); |
| } |
| |
| /* ------------------------------------------------------------ */ |
| @Override |
| public ReadableByteChannel getReadableByteChannel() throws IOException |
| { |
| return FileChannel.open(_file.toPath(),StandardOpenOption.READ); |
| } |
| |
| /* --------------------------------------------------------- */ |
| /** |
| * Deletes the given resource |
| */ |
| @Override |
| public boolean delete() |
| throws SecurityException |
| { |
| return _file.delete(); |
| } |
| |
| /* --------------------------------------------------------- */ |
| /** |
| * Rename the given resource |
| */ |
| @Override |
| public boolean renameTo( Resource dest) |
| throws SecurityException |
| { |
| if( dest instanceof FileResource) |
| return _file.renameTo( ((FileResource)dest)._file); |
| else |
| return false; |
| } |
| |
| /* --------------------------------------------------------- */ |
| /** |
| * Returns a list of resources contained in the given resource |
| */ |
| @Override |
| public String[] list() |
| { |
| String[] list =_file.list(); |
| if (list==null) |
| return null; |
| for (int i=list.length;i-->0;) |
| { |
| if (new File(_file,list[i]).isDirectory() && |
| !list[i].endsWith("/")) |
| list[i]+="/"; |
| } |
| return list; |
| } |
| |
| /* ------------------------------------------------------------ */ |
| /** |
| * @param o the object to compare against this instance |
| * @return <code>true</code> of the object <code>o</code> is a {@link FileResource} pointing to the same file as this resource. |
| */ |
| @Override |
| public boolean equals( Object o) |
| { |
| if (this == o) |
| return true; |
| |
| if (null == o || ! (o instanceof FileResource)) |
| return false; |
| |
| FileResource f=(FileResource)o; |
| return f._file == _file || (null != _file && _file.equals(f._file)); |
| } |
| |
| /* ------------------------------------------------------------ */ |
| /** |
| * @return the hashcode. |
| */ |
| @Override |
| public int hashCode() |
| { |
| return null == _file ? super.hashCode() : _file.hashCode(); |
| } |
| |
| /* ------------------------------------------------------------ */ |
| @Override |
| public void copyTo(File destination) |
| throws IOException |
| { |
| if (isDirectory()) |
| { |
| IO.copyDir(getFile(),destination); |
| } |
| else |
| { |
| if (destination.exists()) |
| throw new IllegalArgumentException(destination+" exists"); |
| IO.copy(getFile(),destination); |
| } |
| } |
| |
| @Override |
| public boolean isContainedIn(Resource r) throws MalformedURLException |
| { |
| return false; |
| } |
| |
| @Override |
| public void close() |
| { |
| } |
| |
| @Override |
| public URL getURL() |
| { |
| try |
| { |
| return _uri.toURL(); |
| } |
| catch (MalformedURLException e) |
| { |
| throw new IllegalStateException(e); |
| } |
| } |
| |
| @Override |
| public URI getURI() |
| { |
| return _uri; |
| } |
| |
| @Override |
| public String toString() |
| { |
| return _uri.toString(); |
| } |
| } |