Mercurial Hosting > luan
diff src/org/eclipse/jetty/util/resource/Resource.java @ 825:7fb7c1915788
remove jetty.util.B64Code
author | Franklin Schmidt <fschmidt@gmail.com> |
---|---|
date | Wed, 14 Sep 2016 16:38:33 -0600 |
parents | 8e9db0bbf4f9 |
children | f89abbfb3a8f |
line wrap: on
line diff
--- a/src/org/eclipse/jetty/util/resource/Resource.java Wed Sep 14 15:49:23 2016 -0600 +++ b/src/org/eclipse/jetty/util/resource/Resource.java Wed Sep 14 16:38:33 2016 -0600 @@ -31,7 +31,7 @@ import java.util.Arrays; import java.util.Date; -import org.eclipse.jetty.util.B64Code; +import java.util.Base64; import org.eclipse.jetty.util.IO; import org.eclipse.jetty.util.Loader; import org.eclipse.jetty.util.StringUtil; @@ -46,633 +46,626 @@ */ public abstract class Resource implements ResourceFactory { - private static final Logger LOG = LoggerFactory.getLogger(Resource.class); - public static boolean __defaultUseCaches = true; - volatile Object _associate; + private static final Logger LOG = LoggerFactory.getLogger(Resource.class); + public static boolean __defaultUseCaches = true; + volatile Object _associate; - /* ------------------------------------------------------------ */ - /** - * Change the default setting for url connection caches. - * Subsequent URLConnections will use this default. - * @param useCaches - */ - public static void setDefaultUseCaches (boolean useCaches) - { - __defaultUseCaches=useCaches; - } + /* ------------------------------------------------------------ */ + /** + * Change the default setting for url connection caches. + * Subsequent URLConnections will use this default. + * @param useCaches + */ + public static void setDefaultUseCaches (boolean useCaches) + { + __defaultUseCaches=useCaches; + } - /* ------------------------------------------------------------ */ - public static boolean getDefaultUseCaches () - { - return __defaultUseCaches; - } - - /* ------------------------------------------------------------ */ - /** Construct a resource from a uri. - * @param uri A URI. - * @return A Resource object. - * @throws IOException Problem accessing URI - */ - public static Resource newResource(URI uri) - throws IOException - { - return newResource(uri.toURL()); - } - - /* ------------------------------------------------------------ */ - /** Construct a resource from a url. - * @param url A URL. - * @return A Resource object. - * @throws IOException Problem accessing URL - */ - public static Resource newResource(URL url) - throws IOException - { - return newResource(url, __defaultUseCaches); - } - - /* ------------------------------------------------------------ */ - /** - * Construct a resource from a url. - * @param url the url for which to make the resource - * @param useCaches true enables URLConnection caching if applicable to the type of resource - * @return - */ - static Resource newResource(URL url, boolean useCaches) - { - if (url==null) - return null; + /* ------------------------------------------------------------ */ + public static boolean getDefaultUseCaches () + { + return __defaultUseCaches; + } + + /* ------------------------------------------------------------ */ + /** Construct a resource from a uri. + * @param uri A URI. + * @return A Resource object. + * @throws IOException Problem accessing URI + */ + public static Resource newResource(URI uri) + throws IOException + { + return newResource(uri.toURL()); + } + + /* ------------------------------------------------------------ */ + /** Construct a resource from a url. + * @param url A URL. + * @return A Resource object. + * @throws IOException Problem accessing URL + */ + public static Resource newResource(URL url) + throws IOException + { + return newResource(url, __defaultUseCaches); + } + + /* ------------------------------------------------------------ */ + /** + * Construct a resource from a url. + * @param url the url for which to make the resource + * @param useCaches true enables URLConnection caching if applicable to the type of resource + * @return + */ + static Resource newResource(URL url, boolean useCaches) + { + if (url==null) + return null; - String url_string=url.toExternalForm(); - if( url_string.startsWith( "file:")) - { - try - { - FileResource fileResource= new FileResource(url); - return fileResource; - } - catch(Exception e) - { - LOG.debug("EXCEPTION",e); - return new BadResource(url,e.toString()); - } - } - else if( url_string.startsWith( "jar:file:")) - { - return new JarFileResource(url, useCaches); - } - else if( url_string.startsWith( "jar:")) - { - return new JarResource(url, useCaches); - } + String url_string=url.toExternalForm(); + if( url_string.startsWith( "file:")) + { + try + { + FileResource fileResource= new FileResource(url); + return fileResource; + } + catch(Exception e) + { + LOG.debug("EXCEPTION",e); + return new BadResource(url,e.toString()); + } + } + else if( url_string.startsWith( "jar:file:")) + { + return new JarFileResource(url, useCaches); + } + else if( url_string.startsWith( "jar:")) + { + return new JarResource(url, useCaches); + } - return new URLResource(url,null,useCaches); - } + return new URLResource(url,null,useCaches); + } - - - /* ------------------------------------------------------------ */ - /** Construct a resource from a string. - * @param resource A URL or filename. - * @return A Resource object. - */ - public static Resource newResource(String resource) - throws MalformedURLException, IOException - { - return newResource(resource, __defaultUseCaches); - } - - /* ------------------------------------------------------------ */ - /** Construct a resource from a string. - * @param resource A URL or filename. - * @param useCaches controls URLConnection caching - * @return A Resource object. - */ - public static Resource newResource (String resource, boolean useCaches) - throws MalformedURLException, IOException - { - URL url=null; - try - { - // Try to format as a URL? - url = new URL(resource); - } - catch(MalformedURLException e) - { - if(!resource.startsWith("ftp:") && - !resource.startsWith("file:") && - !resource.startsWith("jar:")) - { - try - { - // It's a file. - if (resource.startsWith("./")) - resource=resource.substring(2); - - File file=new File(resource).getCanonicalFile(); - url=Resource.toURL(file); - - URLConnection connection=url.openConnection(); - connection.setUseCaches(useCaches); - return new FileResource(url,connection,file); - } - catch(Exception e2) - { - LOG.debug("EXCEPTION",e2); - throw e; - } - } - else - { - LOG.warn("Bad Resource: "+resource); - throw e; - } - } + + + /* ------------------------------------------------------------ */ + /** Construct a resource from a string. + * @param resource A URL or filename. + * @return A Resource object. + */ + public static Resource newResource(String resource) + throws MalformedURLException, IOException + { + return newResource(resource, __defaultUseCaches); + } + + /* ------------------------------------------------------------ */ + /** Construct a resource from a string. + * @param resource A URL or filename. + * @param useCaches controls URLConnection caching + * @return A Resource object. + */ + public static Resource newResource (String resource, boolean useCaches) + throws MalformedURLException, IOException + { + URL url=null; + try + { + // Try to format as a URL? + url = new URL(resource); + } + catch(MalformedURLException e) + { + if(!resource.startsWith("ftp:") && + !resource.startsWith("file:") && + !resource.startsWith("jar:")) + { + try + { + // It's a file. + if (resource.startsWith("./")) + resource=resource.substring(2); + + File file=new File(resource).getCanonicalFile(); + url=Resource.toURL(file); + + URLConnection connection=url.openConnection(); + connection.setUseCaches(useCaches); + return new FileResource(url,connection,file); + } + catch(Exception e2) + { + LOG.debug("EXCEPTION",e2); + throw e; + } + } + else + { + LOG.warn("Bad Resource: "+resource); + throw e; + } + } - return newResource(url); - } + return newResource(url); + } - /* ------------------------------------------------------------ */ - public static Resource newResource (File file) - throws MalformedURLException, IOException - { - file = file.getCanonicalFile(); - URL url = Resource.toURL(file); + /* ------------------------------------------------------------ */ + public static Resource newResource (File file) + throws MalformedURLException, IOException + { + file = file.getCanonicalFile(); + URL url = Resource.toURL(file); - URLConnection connection = url.openConnection(); - FileResource fileResource = new FileResource(url, connection, file); - return fileResource; - } + URLConnection connection = url.openConnection(); + FileResource fileResource = new FileResource(url, connection, file); + return fileResource; + } - /* ------------------------------------------------------------ */ - /** Construct a system resource from a string. - * The resource is tried as classloader resource before being - * treated as a normal resource. - * @param resource Resource as string representation - * @return The new Resource - * @throws IOException Problem accessing resource. - */ - public static Resource newSystemResource(String resource) - throws IOException - { - URL url=null; - // Try to format as a URL? - ClassLoader loader=Thread.currentThread().getContextClassLoader(); - if (loader!=null) - { - try - { - url = loader.getResource(resource); - if (url == null && resource.startsWith("/")) - url = loader.getResource(resource.substring(1)); - } - catch (IllegalArgumentException e) - { - // Catches scenario where a bad Windows path like "C:\dev" is - // improperly escaped, which various downstream classloaders - // tend to have a problem with - url = null; - } - } - if (url==null) - { - loader=Resource.class.getClassLoader(); - if (loader!=null) - { - url=loader.getResource(resource); - if (url==null && resource.startsWith("/")) - url=loader.getResource(resource.substring(1)); - } - } - - if (url==null) - { - url=ClassLoader.getSystemResource(resource); - if (url==null && resource.startsWith("/")) - url=ClassLoader.getSystemResource(resource.substring(1)); - } - - if (url==null) - return null; - - return newResource(url); - } + /* ------------------------------------------------------------ */ + /** Construct a system resource from a string. + * The resource is tried as classloader resource before being + * treated as a normal resource. + * @param resource Resource as string representation + * @return The new Resource + * @throws IOException Problem accessing resource. + */ + public static Resource newSystemResource(String resource) + throws IOException + { + URL url=null; + // Try to format as a URL? + ClassLoader loader=Thread.currentThread().getContextClassLoader(); + if (loader!=null) + { + try + { + url = loader.getResource(resource); + if (url == null && resource.startsWith("/")) + url = loader.getResource(resource.substring(1)); + } + catch (IllegalArgumentException e) + { + // Catches scenario where a bad Windows path like "C:\dev" is + // improperly escaped, which various downstream classloaders + // tend to have a problem with + url = null; + } + } + if (url==null) + { + loader=Resource.class.getClassLoader(); + if (loader!=null) + { + url=loader.getResource(resource); + if (url==null && resource.startsWith("/")) + url=loader.getResource(resource.substring(1)); + } + } + + if (url==null) + { + url=ClassLoader.getSystemResource(resource); + if (url==null && resource.startsWith("/")) + url=ClassLoader.getSystemResource(resource.substring(1)); + } + + if (url==null) + return null; + + return newResource(url); + } - /* ------------------------------------------------------------ */ - /** Find a classpath resource. - */ - public static Resource newClassPathResource(String resource) - { - return newClassPathResource(resource,true,false); - } + /* ------------------------------------------------------------ */ + /** Find a classpath resource. + */ + public static Resource newClassPathResource(String resource) + { + return newClassPathResource(resource,true,false); + } - /* ------------------------------------------------------------ */ - /** Find a classpath resource. - * The {@link java.lang.Class#getResource(String)} method is used to lookup the resource. If it is not - * found, then the {@link Loader#getResource(Class, String, boolean)} method is used. - * If it is still not found, then {@link ClassLoader#getSystemResource(String)} is used. - * Unlike {@link ClassLoader#getSystemResource(String)} this method does not check for normal resources. - * @param name The relative name of the resource - * @param useCaches True if URL caches are to be used. - * @param checkParents True if forced searching of parent Classloaders is performed to work around - * loaders with inverted priorities - * @return Resource or null - */ - public static Resource newClassPathResource(String name,boolean useCaches,boolean checkParents) - { - URL url=Resource.class.getResource(name); - - if (url==null) - url=Loader.getResource(Resource.class,name,checkParents); - if (url==null) - return null; - return newResource(url,useCaches); - } - - /* ------------------------------------------------------------ */ - public static boolean isContainedIn (Resource r, Resource containingResource) throws MalformedURLException - { - return r.isContainedIn(containingResource); - } + /* ------------------------------------------------------------ */ + /** Find a classpath resource. + * The {@link java.lang.Class#getResource(String)} method is used to lookup the resource. If it is not + * found, then the {@link Loader#getResource(Class, String, boolean)} method is used. + * If it is still not found, then {@link ClassLoader#getSystemResource(String)} is used. + * Unlike {@link ClassLoader#getSystemResource(String)} this method does not check for normal resources. + * @param name The relative name of the resource + * @param useCaches True if URL caches are to be used. + * @param checkParents True if forced searching of parent Classloaders is performed to work around + * loaders with inverted priorities + * @return Resource or null + */ + public static Resource newClassPathResource(String name,boolean useCaches,boolean checkParents) + { + URL url=Resource.class.getResource(name); + + if (url==null) + url=Loader.getResource(Resource.class,name,checkParents); + if (url==null) + return null; + return newResource(url,useCaches); + } + + /* ------------------------------------------------------------ */ + public static boolean isContainedIn (Resource r, Resource containingResource) throws MalformedURLException + { + return r.isContainedIn(containingResource); + } - /* ------------------------------------------------------------ */ - @Override - protected void finalize() - { - release(); - } - - /* ------------------------------------------------------------ */ - public abstract boolean isContainedIn (Resource r) throws MalformedURLException; - - - /* ------------------------------------------------------------ */ - /** Release any temporary resources held by the resource. - */ - public abstract void release(); - + /* ------------------------------------------------------------ */ + @Override + protected void finalize() + { + release(); + } + + /* ------------------------------------------------------------ */ + public abstract boolean isContainedIn (Resource r) throws MalformedURLException; + + + /* ------------------------------------------------------------ */ + /** Release any temporary resources held by the resource. + */ + public abstract void release(); + - /* ------------------------------------------------------------ */ - /** - * Returns true if the respresened resource exists. - */ - public abstract boolean exists(); - + /* ------------------------------------------------------------ */ + /** + * Returns true if the respresened resource exists. + */ + public abstract boolean exists(); + - /* ------------------------------------------------------------ */ - /** - * Returns true if the respresenetd resource is a container/directory. - * If the resource is not a file, resources ending with "/" are - * considered directories. - */ - public abstract boolean isDirectory(); + /* ------------------------------------------------------------ */ + /** + * Returns true if the respresenetd resource is a container/directory. + * If the resource is not a file, resources ending with "/" are + * considered directories. + */ + public abstract boolean isDirectory(); - /* ------------------------------------------------------------ */ - /** - * Returns the last modified time - */ - public abstract long lastModified(); + /* ------------------------------------------------------------ */ + /** + * Returns the last modified time + */ + public abstract long lastModified(); - /* ------------------------------------------------------------ */ - /** - * Return the length of the resource - */ - public abstract long length(); - + /* ------------------------------------------------------------ */ + /** + * Return the length of the resource + */ + public abstract long length(); + - /* ------------------------------------------------------------ */ - /** - * Returns an URL representing the given resource - */ - public abstract URL getURL(); + /* ------------------------------------------------------------ */ + /** + * Returns an URL representing the given resource + */ + public abstract URL getURL(); - /* ------------------------------------------------------------ */ - /** - * Returns an URI representing the given resource - */ - public URI getURI() - { - try - { - return getURL().toURI(); - } - catch(Exception e) - { - throw new RuntimeException(e); - } - } - + /* ------------------------------------------------------------ */ + /** + * Returns an URI representing the given resource + */ + public URI getURI() + { + try + { + return getURL().toURI(); + } + catch(Exception e) + { + throw new RuntimeException(e); + } + } + - /* ------------------------------------------------------------ */ - /** - * Returns an File representing the given resource or NULL if this - * is not possible. - */ - public abstract File getFile() - throws IOException; - + /* ------------------------------------------------------------ */ + /** + * Returns an File representing the given resource or NULL if this + * is not possible. + */ + public abstract File getFile() + throws IOException; + - /* ------------------------------------------------------------ */ - /** - * Returns the name of the resource - */ - public abstract String getName(); - + /* ------------------------------------------------------------ */ + /** + * Returns the name of the resource + */ + public abstract String getName(); + - /* ------------------------------------------------------------ */ - /** - * Returns an input stream to the resource - */ - public abstract InputStream getInputStream() - throws java.io.IOException; + /* ------------------------------------------------------------ */ + /** + * Returns an input stream to the resource + */ + public abstract InputStream getInputStream() + throws java.io.IOException; - /* ------------------------------------------------------------ */ - /** - * Returns an output stream to the resource - */ - public abstract OutputStream getOutputStream() - throws java.io.IOException, SecurityException; - - /* ------------------------------------------------------------ */ - /** - * Deletes the given resource - */ - public abstract boolean delete() - throws SecurityException; - - /* ------------------------------------------------------------ */ - /** - * Rename the given resource - */ - public abstract boolean renameTo( Resource dest) - throws SecurityException; - - /* ------------------------------------------------------------ */ - /** - * Returns a list of resource names contained in the given resource - * The resource names are not URL encoded. - */ - public abstract String[] list(); + /* ------------------------------------------------------------ */ + /** + * Returns an output stream to the resource + */ + public abstract OutputStream getOutputStream() + throws java.io.IOException, SecurityException; + + /* ------------------------------------------------------------ */ + /** + * Deletes the given resource + */ + public abstract boolean delete() + throws SecurityException; + + /* ------------------------------------------------------------ */ + /** + * Rename the given resource + */ + public abstract boolean renameTo( Resource dest) + throws SecurityException; + + /* ------------------------------------------------------------ */ + /** + * Returns a list of resource names contained in the given resource + * The resource names are not URL encoded. + */ + public abstract String[] list(); - /* ------------------------------------------------------------ */ - /** - * Returns the resource contained inside the current resource with the - * given name. - * @param path The path segment to add, which should be encoded by the - * encode method. - */ - public abstract Resource addPath(String path) - throws IOException,MalformedURLException; + /* ------------------------------------------------------------ */ + /** + * Returns the resource contained inside the current resource with the + * given name. + * @param path The path segment to add, which should be encoded by the + * encode method. + */ + public abstract Resource addPath(String path) + throws IOException,MalformedURLException; - /* ------------------------------------------------------------ */ - /** Get a resource from withing this resource. - * <p> - * This method is essentially an alias for {@link #addPath(String)}, but without checked exceptions. - * This method satisfied the {@link ResourceFactory} interface. - * @see org.eclipse.jetty.util.resource.ResourceFactory#getResource(java.lang.String) - */ - public Resource getResource(String path) - { - try - { - return addPath(path); - } - catch(Exception e) - { - LOG.debug("",e); - return null; - } - } + /* ------------------------------------------------------------ */ + /** Get a resource from withing this resource. + * <p> + * This method is essentially an alias for {@link #addPath(String)}, but without checked exceptions. + * This method satisfied the {@link ResourceFactory} interface. + * @see org.eclipse.jetty.util.resource.ResourceFactory#getResource(java.lang.String) + */ + public Resource getResource(String path) + { + try + { + return addPath(path); + } + catch(Exception e) + { + LOG.debug("",e); + return null; + } + } - /* ------------------------------------------------------------ */ - /** Encode according to this resource type. - * The default implementation calls URI.encodePath(uri) - * @param uri - * @return String encoded for this resource type. - */ - public String encode(String uri) - { - return URIUtil.encodePath(uri); - } - - /* ------------------------------------------------------------ */ - public Object getAssociate() - { - return _associate; - } + /* ------------------------------------------------------------ */ + /** Encode according to this resource type. + * The default implementation calls URI.encodePath(uri) + * @param uri + * @return String encoded for this resource type. + */ + public String encode(String uri) + { + return URIUtil.encodePath(uri); + } + + /* ------------------------------------------------------------ */ + public Object getAssociate() + { + return _associate; + } - /* ------------------------------------------------------------ */ - public void setAssociate(Object o) - { - _associate=o; - } - - /* ------------------------------------------------------------ */ - /** - * @return The canonical Alias of this resource or null if none. - */ - public URL getAlias() - { - return null; - } - - /* ------------------------------------------------------------ */ - /** Get the resource list as a HTML directory listing. - * @param base The base URL - * @param parent True if the parent directory should be included - * @return String of HTML - */ - public String getListHTML(String base,boolean parent) - throws IOException - { - base=URIUtil.canonicalPath(base); - if (base==null || !isDirectory()) - return null; - - String[] ls = list(); - if (ls==null) - return null; - Arrays.sort(ls); - - String decodedBase = URIUtil.decodePath(base); - String title = "Directory: "+deTag(decodedBase); + /* ------------------------------------------------------------ */ + public void setAssociate(Object o) + { + _associate=o; + } + + /* ------------------------------------------------------------ */ + /** + * @return The canonical Alias of this resource or null if none. + */ + public URL getAlias() + { + return null; + } + + /* ------------------------------------------------------------ */ + /** Get the resource list as a HTML directory listing. + * @param base The base URL + * @param parent True if the parent directory should be included + * @return String of HTML + */ + public String getListHTML(String base,boolean parent) + throws IOException + { + base=URIUtil.canonicalPath(base); + if (base==null || !isDirectory()) + return null; + + String[] ls = list(); + if (ls==null) + return null; + Arrays.sort(ls); + + String decodedBase = URIUtil.decodePath(base); + String title = "Directory: "+deTag(decodedBase); - StringBuilder buf=new StringBuilder(4096); - buf.append("<HTML><HEAD>"); - buf.append("<LINK HREF=\"").append("jetty-dir.css").append("\" REL=\"stylesheet\" TYPE=\"text/css\"/><TITLE>"); - buf.append(title); - buf.append("</TITLE></HEAD><BODY>\n<H1>"); - buf.append(title); - buf.append("</H1>\n<TABLE BORDER=0>\n"); - - if (parent) - { - buf.append("<TR><TD><A HREF=\""); - buf.append(URIUtil.addPaths(base,"../")); - buf.append("\">Parent Directory</A></TD><TD></TD><TD></TD></TR>\n"); - } - - String encodedBase = hrefEncodeURI(base); - - DateFormat dfmt=DateFormat.getDateTimeInstance(DateFormat.MEDIUM, - DateFormat.MEDIUM); - for (int i=0 ; i< ls.length ; i++) - { - Resource item = addPath(ls[i]); - - buf.append("\n<TR><TD><A HREF=\""); - String path=URIUtil.addPaths(encodedBase,URIUtil.encodePath(ls[i])); - - buf.append(path); - - if (item.isDirectory() && !path.endsWith("/")) - buf.append(URIUtil.SLASH); - - // URIUtil.encodePath(buf,path); - buf.append("\">"); - buf.append(deTag(ls[i])); - buf.append(" "); - buf.append("</A></TD><TD ALIGN=right>"); - buf.append(item.length()); - buf.append(" bytes </TD><TD>"); - buf.append(dfmt.format(new Date(item.lastModified()))); - buf.append("</TD></TR>"); - } - buf.append("</TABLE>\n"); + StringBuilder buf=new StringBuilder(4096); + buf.append("<HTML><HEAD>"); + buf.append("<LINK HREF=\"").append("jetty-dir.css").append("\" REL=\"stylesheet\" TYPE=\"text/css\"/><TITLE>"); + buf.append(title); + buf.append("</TITLE></HEAD><BODY>\n<H1>"); + buf.append(title); + buf.append("</H1>\n<TABLE BORDER=0>\n"); + + if (parent) + { + buf.append("<TR><TD><A HREF=\""); + buf.append(URIUtil.addPaths(base,"../")); + buf.append("\">Parent Directory</A></TD><TD></TD><TD></TD></TR>\n"); + } + + String encodedBase = hrefEncodeURI(base); + + DateFormat dfmt=DateFormat.getDateTimeInstance(DateFormat.MEDIUM, + DateFormat.MEDIUM); + for (int i=0 ; i< ls.length ; i++) + { + Resource item = addPath(ls[i]); + + buf.append("\n<TR><TD><A HREF=\""); + String path=URIUtil.addPaths(encodedBase,URIUtil.encodePath(ls[i])); + + buf.append(path); + + if (item.isDirectory() && !path.endsWith("/")) + buf.append(URIUtil.SLASH); + + // URIUtil.encodePath(buf,path); + buf.append("\">"); + buf.append(deTag(ls[i])); + buf.append(" "); + buf.append("</A></TD><TD ALIGN=right>"); + buf.append(item.length()); + buf.append(" bytes </TD><TD>"); + buf.append(dfmt.format(new Date(item.lastModified()))); + buf.append("</TD></TR>"); + } + buf.append("</TABLE>\n"); buf.append("</BODY></HTML>\n"); - - return buf.toString(); - } - - /** - * Encode any characters that could break the URI string in an HREF. - * Such as <a href="/path/to;<script>Window.alert("XSS"+'%20'+"here");</script>">Link</a> - * - * The above example would parse incorrectly on various browsers as the "<" or '"' characters - * would end the href attribute value string prematurely. - * - * @param raw the raw text to encode. - * @return the defanged text. - */ - private static String hrefEncodeURI(String raw) - { - StringBuffer buf = null; + + return buf.toString(); + } + + /** + * Encode any characters that could break the URI string in an HREF. + * Such as <a href="/path/to;<script>Window.alert("XSS"+'%20'+"here");</script>">Link</a> + * + * The above example would parse incorrectly on various browsers as the "<" or '"' characters + * would end the href attribute value string prematurely. + * + * @param raw the raw text to encode. + * @return the defanged text. + */ + private static String hrefEncodeURI(String raw) + { + StringBuffer buf = null; - loop: - for (int i=0;i<raw.length();i++) - { - char c=raw.charAt(i); - switch(c) - { - case '\'': - case '"': - case '<': - case '>': - buf=new StringBuffer(raw.length()<<1); - break loop; - } - } - if (buf==null) - return raw; + loop: + for (int i=0;i<raw.length();i++) + { + char c=raw.charAt(i); + switch(c) + { + case '\'': + case '"': + case '<': + case '>': + buf=new StringBuffer(raw.length()<<1); + break loop; + } + } + if (buf==null) + return raw; - for (int i=0;i<raw.length();i++) - { - char c=raw.charAt(i); - switch(c) - { - case '"': - buf.append("%22"); - continue; - case '\'': - buf.append("%27"); - continue; - case '<': - buf.append("%3C"); - continue; - case '>': - buf.append("%3E"); - continue; - default: - buf.append(c); - continue; - } - } + for (int i=0;i<raw.length();i++) + { + char c=raw.charAt(i); + switch(c) + { + case '"': + buf.append("%22"); + continue; + case '\'': + buf.append("%27"); + continue; + case '<': + buf.append("%3C"); + continue; + case '>': + buf.append("%3E"); + continue; + default: + buf.append(c); + continue; + } + } - return buf.toString(); - } - - private static String deTag(String raw) - { - return StringUtil.replace( StringUtil.replace(raw,"<","<"), ">", ">"); - } - - /* ------------------------------------------------------------ */ - /** - * @param out - * @param start First byte to write - * @param count Bytes to write or -1 for all of them. - */ - public void writeTo(OutputStream out,long start,long count) - throws IOException - { - InputStream in = getInputStream(); - try - { - in.skip(start); - if (count<0) - IO.copy(in,out); - else - IO.copy(in,out,count); - } - finally - { - in.close(); - } - } - - /* ------------------------------------------------------------ */ - public void copyTo(File destination) - throws IOException - { - if (destination.exists()) - throw new IllegalArgumentException(destination+" exists"); - writeTo(new FileOutputStream(destination),0,-1); - } + return buf.toString(); + } + + private static String deTag(String raw) + { + return StringUtil.replace( StringUtil.replace(raw,"<","<"), ">", ">"); + } + + /* ------------------------------------------------------------ */ + /** + * @param out + * @param start First byte to write + * @param count Bytes to write or -1 for all of them. + */ + public void writeTo(OutputStream out,long start,long count) + throws IOException + { + InputStream in = getInputStream(); + try + { + in.skip(start); + if (count<0) + IO.copy(in,out); + else + IO.copy(in,out,count); + } + finally + { + in.close(); + } + } + + /* ------------------------------------------------------------ */ + public void copyTo(File destination) + throws IOException + { + if (destination.exists()) + throw new IllegalArgumentException(destination+" exists"); + writeTo(new FileOutputStream(destination),0,-1); + } - /* ------------------------------------------------------------ */ - public String getWeakETag() - { - try - { - StringBuilder b = new StringBuilder(32); - b.append("W/\""); - - String name=getName(); - int length=name.length(); - long lhash=0; - for (int i=0; i<length;i++) - lhash=31*lhash+name.charAt(i); - - B64Code.encode(lastModified()^lhash,b); - B64Code.encode(length()^lhash,b); - b.append('"'); - return b.toString(); - } - catch (IOException e) - { - throw new RuntimeException(e); - } - } - - /* ------------------------------------------------------------ */ - /** Generate a properly encoded URL from a {@link File} instance. - * @param file Target file. - * @return URL of the target file. - * @throws MalformedURLException - */ - public static URL toURL(File file) throws MalformedURLException - { - return file.toURI().toURL(); - } + /* ------------------------------------------------------------ */ + public String getWeakETag() + { + StringBuilder b = new StringBuilder(32); + b.append("W/\""); + + long lhash = lastModified() ^ getName().hashCode() ^ length(); + byte[] a = new byte[Long.BYTES]; + for( int i=0; i<a.length; i++ ) { + a[i] = (byte)lhash; + lhash >>= 8; + } + b.append( Base64.getEncoder().encodeToString(a) ); + + b.append('"'); + return b.toString(); + } + + /* ------------------------------------------------------------ */ + /** Generate a properly encoded URL from a {@link File} instance. + * @param file Target file. + * @return URL of the target file. + * @throws MalformedURLException + */ + public static URL toURL(File file) throws MalformedURLException + { + return file.toURI().toURL(); + } }