Merge branch `jetty-9.3.x` into `jetty-9.4.x`

Signed-off-by: Joakim Erdfelt <joakim.erdfelt@gmail.com>

# Conflicts:
#	Jenkinsfile
#	VERSION.txt
#	aggregates/jetty-all-compact3/pom.xml
#	aggregates/jetty-all/pom.xml
#	apache-jsp/pom.xml
#	apache-jstl/pom.xml
#	examples/async-rest/async-rest-jar/pom.xml
#	examples/async-rest/async-rest-webapp/pom.xml
#	examples/async-rest/pom.xml
#	examples/embedded/pom.xml
#	examples/pom.xml
#	jetty-alpn/jetty-alpn-client/pom.xml
#	jetty-alpn/jetty-alpn-java-client/pom.xml
#	jetty-alpn/jetty-alpn-java-server/pom.xml
#	jetty-alpn/jetty-alpn-server/pom.xml
#	jetty-alpn/pom.xml
#	jetty-annotations/pom.xml
#	jetty-ant/pom.xml
#	jetty-bom/pom.xml
#	jetty-cdi/cdi-core/pom.xml
#	jetty-cdi/cdi-full-servlet/pom.xml
#	jetty-cdi/cdi-servlet/pom.xml
#	jetty-cdi/cdi-websocket/pom.xml
#	jetty-cdi/pom.xml
#	jetty-cdi/test-cdi-webapp/pom.xml
#	jetty-client/pom.xml
#	jetty-continuation/pom.xml
#	jetty-deploy/pom.xml
#	jetty-distribution/pom.xml
#	jetty-documentation/pom.xml
#	jetty-fcgi/fcgi-client/pom.xml
#	jetty-fcgi/fcgi-server/pom.xml
#	jetty-fcgi/pom.xml
#	jetty-gcloud/jetty-gcloud-memcached-session-manager/pom.xml
#	jetty-gcloud/jetty-gcloud-session-manager/pom.xml
#	jetty-gcloud/pom.xml
#	jetty-hazelcast/pom.xml
#	jetty-http-spi/pom.xml
#	jetty-http-spi/src/main/java/org/eclipse/jetty/http/spi/HttpSpiContextHandler.java
#	jetty-http-spi/src/main/java/org/eclipse/jetty/http/spi/JettyHttpContext.java
#	jetty-http-spi/src/main/java/org/eclipse/jetty/http/spi/JettyHttpExchangeDelegate.java
#	jetty-http-spi/src/main/java/org/eclipse/jetty/http/spi/JettyHttpServerProvider.java
#	jetty-http/pom.xml
#	jetty-http2/http2-alpn-tests/pom.xml
#	jetty-http2/http2-client/pom.xml
#	jetty-http2/http2-common/pom.xml
#	jetty-http2/http2-hpack/pom.xml
#	jetty-http2/http2-http-client-transport/pom.xml
#	jetty-http2/http2-server/pom.xml
#	jetty-http2/pom.xml
#	jetty-infinispan/pom.xml
#	jetty-io/pom.xml
#	jetty-jaas/pom.xml
#	jetty-jaspi/pom.xml
#	jetty-jmx/pom.xml
#	jetty-jndi/pom.xml
#	jetty-jspc-maven-plugin/pom.xml
#	jetty-maven-plugin/pom.xml
#	jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/JettyDeployWar.java
#	jetty-monitor/pom.xml
#	jetty-nosql/pom.xml
#	jetty-osgi/jetty-osgi-alpn/pom.xml
#	jetty-osgi/jetty-osgi-boot-jsp/pom.xml
#	jetty-osgi/jetty-osgi-boot-warurl/pom.xml
#	jetty-osgi/jetty-osgi-boot/pom.xml
#	jetty-osgi/jetty-osgi-httpservice/pom.xml
#	jetty-osgi/pom.xml
#	jetty-osgi/test-jetty-osgi-context/pom.xml
#	jetty-osgi/test-jetty-osgi-fragment/pom.xml
#	jetty-osgi/test-jetty-osgi-webapp/pom.xml
#	jetty-osgi/test-jetty-osgi/pom.xml
#	jetty-plus/pom.xml
#	jetty-proxy/pom.xml
#	jetty-quickstart/pom.xml
#	jetty-rewrite/pom.xml
#	jetty-runner/pom.xml
#	jetty-security/pom.xml
#	jetty-security/src/test/java/org/eclipse/jetty/security/AliasedConstraintTest.java
#	jetty-server/pom.xml
#	jetty-server/src/main/java/org/eclipse/jetty/server/handler/ResourceHandler.java
#	jetty-servlet/pom.xml
#	jetty-servlet/src/main/java/org/eclipse/jetty/servlet/DefaultServlet.java
#	jetty-servlet/src/test/java/org/eclipse/jetty/servlet/DefaultServletTest.java
#	jetty-servlets/pom.xml
#	jetty-servlets/src/test/java/org/eclipse/jetty/servlets/ThreadStarvationTest.java
#	jetty-spring/pom.xml
#	jetty-start/pom.xml
#	jetty-start/src/test/java/org/eclipse/jetty/start/BaseHomeTest.java
#	jetty-start/src/test/java/org/eclipse/jetty/start/ConfigurationAssert.java
#	jetty-util-ajax/pom.xml
#	jetty-util/pom.xml
#	jetty-util/src/main/java/org/eclipse/jetty/util/resource/Resource.java
#	jetty-webapp/pom.xml
#	jetty-websocket/javax-websocket-client-impl/pom.xml
#	jetty-websocket/javax-websocket-server-impl/pom.xml
#	jetty-websocket/pom.xml
#	jetty-websocket/websocket-api/pom.xml
#	jetty-websocket/websocket-client/pom.xml
#	jetty-websocket/websocket-common/pom.xml
#	jetty-websocket/websocket-server/pom.xml
#	jetty-websocket/websocket-servlet/pom.xml
#	jetty-xml/pom.xml
#	pom.xml
#	tests/pom.xml
#	tests/test-continuation/pom.xml
#	tests/test-http-client-transport/pom.xml
#	tests/test-integration/pom.xml
#	tests/test-jmx/jmx-webapp-it/pom.xml
#	tests/test-jmx/jmx-webapp/pom.xml
#	tests/test-jmx/pom.xml
#	tests/test-loginservice/pom.xml
#	tests/test-quickstart/pom.xml
#	tests/test-sessions/pom.xml
#	tests/test-sessions/test-file-sessions/pom.xml
#	tests/test-sessions/test-gcloud-sessions/pom.xml
#	tests/test-sessions/test-infinispan-sessions/pom.xml
#	tests/test-sessions/test-jdbc-sessions/pom.xml
#	tests/test-sessions/test-memcached-sessions/pom.xml
#	tests/test-sessions/test-mongodb-sessions/pom.xml
#	tests/test-sessions/test-sessions-common/pom.xml
#	tests/test-webapps/pom.xml
#	tests/test-webapps/test-jaas-webapp/pom.xml
#	tests/test-webapps/test-jetty-webapp/pom.xml
#	tests/test-webapps/test-jndi-webapp/pom.xml
#	tests/test-webapps/test-mock-resources/pom.xml
#	tests/test-webapps/test-proxy-webapp/pom.xml
#	tests/test-webapps/test-servlet-spec/pom.xml
#	tests/test-webapps/test-servlet-spec/test-container-initializer/pom.xml
#	tests/test-webapps/test-servlet-spec/test-spec-webapp/pom.xml
#	tests/test-webapps/test-servlet-spec/test-web-fragment/pom.xml
#	tests/test-webapps/test-webapp-rfc2616/pom.xml
This commit is contained in:
Joakim Erdfelt 2019-04-03 17:47:18 -05:00
commit 7478c04351
9 changed files with 402 additions and 102 deletions

View File

@ -25,7 +25,6 @@ import java.nio.ByteBuffer;
import java.nio.channels.FileChannel; import java.nio.channels.FileChannel;
import java.nio.channels.FileChannel.MapMode; import java.nio.channels.FileChannel.MapMode;
import java.nio.file.StandardOpenOption; import java.nio.file.StandardOpenOption;
import javax.servlet.AsyncContext; import javax.servlet.AsyncContext;
import javax.servlet.ServletException; import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
@ -116,7 +115,8 @@ public class FastFileServer
} }
String listing = Resource.newResource(file).getListHTML( String listing = Resource.newResource(file).getListHTML(
request.getRequestURI(), request.getRequestURI(),
request.getPathInfo().lastIndexOf("/") > 0); request.getPathInfo().lastIndexOf("/") > 0,
request.getQueryString());
response.setContentType("text/html; charset=utf-8"); response.setContentType("text/html; charset=utf-8");
response.getWriter().println(listing); response.getWriter().println(listing);
return; return;

View File

@ -22,7 +22,6 @@ import java.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.List; import java.util.List;
import javax.servlet.ServletException; import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponse;
@ -102,7 +101,7 @@ public class ResourceHandler extends HandlerWrapper implements ResourceFactory,W
return null; return null;
} }
/* ------------------------------------------------------------ */ /* ------------------------------------------------------------ */
@Override @Override
public void doStart() throws Exception public void doStart() throws Exception
@ -156,7 +155,7 @@ public class ResourceHandler extends HandlerWrapper implements ResourceFactory,W
/* ------------------------------------------------------------ */ /* ------------------------------------------------------------ */
/** /**
* Get the minimum content length for async handling. * Get the minimum content length for async handling.
* *
* @return The minimum size in bytes of the content before asynchronous handling is used, or -1 for no async handling or 0 (default) for using * @return The minimum size in bytes of the content before asynchronous handling is used, or -1 for no async handling or 0 (default) for using
* {@link HttpServletResponse#getBufferSize()} as the minimum length. * {@link HttpServletResponse#getBufferSize()} as the minimum length.
*/ */
@ -169,7 +168,7 @@ public class ResourceHandler extends HandlerWrapper implements ResourceFactory,W
/* ------------------------------------------------------------ */ /* ------------------------------------------------------------ */
/** /**
* Get minimum memory mapped file content length. * Get minimum memory mapped file content length.
* *
* @return the minimum size in bytes of a file resource that will be served using a memory mapped buffer, or -1 (default) for no memory mapped buffers. * @return the minimum size in bytes of a file resource that will be served using a memory mapped buffer, or -1 (default) for no memory mapped buffers.
*/ */
@Deprecated @Deprecated
@ -303,7 +302,7 @@ public class ResourceHandler extends HandlerWrapper implements ResourceFactory,W
/* ------------------------------------------------------------ */ /* ------------------------------------------------------------ */
/** /**
* Get the directory option. * Get the directory option.
* *
* @return true if directories are listed. * @return true if directories are listed.
*/ */
public boolean isDirectoriesListed() public boolean isDirectoriesListed()
@ -319,7 +318,7 @@ public class ResourceHandler extends HandlerWrapper implements ResourceFactory,W
{ {
return _resourceService.isEtags(); return _resourceService.isEtags();
} }
/* ------------------------------------------------------------ */ /* ------------------------------------------------------------ */
/** /**
* @return If set to true, then static content will be served as gzip content encoded if a matching resource is found ending with ".gz" * @return If set to true, then static content will be served as gzip content encoded if a matching resource is found ending with ".gz"
@ -403,7 +402,7 @@ public class ResourceHandler extends HandlerWrapper implements ResourceFactory,W
/* ------------------------------------------------------------ */ /* ------------------------------------------------------------ */
/** /**
* Set the directory. * Set the directory.
* *
* @param directory * @param directory
* true if directories are listed. * true if directories are listed.
*/ */
@ -461,7 +460,7 @@ public class ResourceHandler extends HandlerWrapper implements ResourceFactory,W
/* ------------------------------------------------------------ */ /* ------------------------------------------------------------ */
/** /**
* Set the minimum content length for async handling. * Set the minimum content length for async handling.
* *
* @param minAsyncContentLength * @param minAsyncContentLength
* The minimum size in bytes of the content before asynchronous handling is used, or -1 for no async handling or 0 for using * The minimum size in bytes of the content before asynchronous handling is used, or -1 for no async handling or 0 for using
* {@link HttpServletResponse#getBufferSize()} as the minimum length. * {@link HttpServletResponse#getBufferSize()} as the minimum length.
@ -474,7 +473,7 @@ public class ResourceHandler extends HandlerWrapper implements ResourceFactory,W
/* ------------------------------------------------------------ */ /* ------------------------------------------------------------ */
/** /**
* Set minimum memory mapped file content length. * Set minimum memory mapped file content length.
* *
* @param minMemoryMappedFileSize * @param minMemoryMappedFileSize
* the minimum size in bytes of a file resource that will be served using a memory mapped buffer, or -1 for no memory mapped buffers. * the minimum size in bytes of a file resource that will be served using a memory mapped buffer, or -1 for no memory mapped buffers.
*/ */

View File

@ -23,7 +23,6 @@ import java.net.URL;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.StringTokenizer; import java.util.StringTokenizer;
import javax.servlet.ServletContext; import javax.servlet.ServletContext;
import javax.servlet.ServletException; import javax.servlet.ServletException;
import javax.servlet.UnavailableException; import javax.servlet.UnavailableException;
@ -48,8 +47,7 @@ import org.eclipse.jetty.util.log.Logger;
import org.eclipse.jetty.util.resource.Resource; import org.eclipse.jetty.util.resource.Resource;
import org.eclipse.jetty.util.resource.ResourceFactory; import org.eclipse.jetty.util.resource.ResourceFactory;
/**
/**
* The default servlet. * The default servlet.
* <p> * <p>
* This servlet, normally mapped to /, provides the handling for static * This servlet, normally mapped to /, provides the handling for static
@ -79,9 +77,9 @@ import org.eclipse.jetty.util.resource.ResourceFactory;
* *
* gzip If set to true, then static content will be served as * gzip If set to true, then static content will be served as
* gzip content encoded if a matching resource is * gzip content encoded if a matching resource is
* found ending with ".gz" (default false) * found ending with ".gz" (default false)
* (deprecated: use precompressed) * (deprecated: use precompressed)
* *
* precompressed If set to a comma separated list of encoding types (that may be * precompressed If set to a comma separated list of encoding types (that may be
* listed in a requests Accept-Encoding header) to file * listed in a requests Accept-Encoding header) to file
* extension mappings to look for and serve. For example: * extension mappings to look for and serve. For example:
@ -131,10 +129,10 @@ import org.eclipse.jetty.util.resource.ResourceFactory;
public class DefaultServlet extends HttpServlet implements ResourceFactory, WelcomeFactory public class DefaultServlet extends HttpServlet implements ResourceFactory, WelcomeFactory
{ {
public static final String CONTEXT_INIT = "org.eclipse.jetty.servlet.Default."; public static final String CONTEXT_INIT = "org.eclipse.jetty.servlet.Default.";
private static final Logger LOG = Log.getLogger(DefaultServlet.class); private static final Logger LOG = Log.getLogger(DefaultServlet.class);
private static final long serialVersionUID = 4930458713846881193L; private static final long serialVersionUID = 4930458713846881193L;
private final ResourceService _resourceService; private final ResourceService _resourceService;
private ServletContext _servletContext; private ServletContext _servletContext;
@ -165,7 +163,7 @@ public class DefaultServlet extends HttpServlet implements ResourceFactory, Welc
{ {
this(new ResourceService()); this(new ResourceService());
} }
/* ------------------------------------------------------------ */ /* ------------------------------------------------------------ */
@Override @Override
public void init() public void init()
@ -186,7 +184,7 @@ public class DefaultServlet extends HttpServlet implements ResourceFactory, Welc
_resourceService.setPrecompressedFormats(parsePrecompressedFormats(getInitParameter("precompressed"), getInitBoolean("gzip", false))); _resourceService.setPrecompressedFormats(parsePrecompressedFormats(getInitParameter("precompressed"), getInitBoolean("gzip", false)));
_resourceService.setPathInfoOnly(getInitBoolean("pathInfoOnly",_resourceService.isPathInfoOnly())); _resourceService.setPathInfoOnly(getInitBoolean("pathInfoOnly",_resourceService.isPathInfoOnly()));
_resourceService.setEtags(getInitBoolean("etags",_resourceService.isEtags())); _resourceService.setEtags(getInitBoolean("etags",_resourceService.isEtags()));
if ("exact".equals(getInitParameter("welcomeServlets"))) if ("exact".equals(getInitParameter("welcomeServlets")))
{ {
_welcomeExactServlets=true; _welcomeExactServlets=true;
@ -242,8 +240,8 @@ public class DefaultServlet extends HttpServlet implements ResourceFactory, Welc
String cc=getInitParameter("cacheControl"); String cc=getInitParameter("cacheControl");
if (cc!=null) if (cc!=null)
_resourceService.setCacheControl(new PreEncodedHttpField(HttpHeader.CACHE_CONTROL,cc)); _resourceService.setCacheControl(new PreEncodedHttpField(HttpHeader.CACHE_CONTROL,cc));
String resourceCache = getInitParameter("resourceCache"); String resourceCache = getInitParameter("resourceCache");
int max_cache_size=getInitInt("maxCacheSize", -2); int max_cache_size=getInitInt("maxCacheSize", -2);
int max_cached_file_size=getInitInt("maxCachedFileSize", -2); int max_cached_file_size=getInitInt("maxCachedFileSize", -2);
@ -286,7 +284,7 @@ public class DefaultServlet extends HttpServlet implements ResourceFactory, Welc
} }
_resourceService.setContentFactory(contentFactory); _resourceService.setContentFactory(contentFactory);
_resourceService.setWelcomeFactory(this); _resourceService.setWelcomeFactory(this);
List<String> gzip_equivalent_file_extensions = new ArrayList<String>(); List<String> gzip_equivalent_file_extensions = new ArrayList<String>();
String otherGzipExtensions = getInitParameter("otherGzipFileExtensions"); String otherGzipExtensions = getInitParameter("otherGzipFileExtensions");
if (otherGzipExtensions != null) if (otherGzipExtensions != null)

View File

@ -18,19 +18,6 @@
package org.eclipse.jetty.servlet; package org.eclipse.jetty.servlet;
import static org.eclipse.jetty.http.HttpFieldsMatchers.containsHeader;
import static org.eclipse.jetty.http.HttpFieldsMatchers.containsHeaderValue;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.anyOf;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.endsWith;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.not;
import static org.hamcrest.Matchers.notNullValue;
import static org.hamcrest.Matchers.nullValue;
import static org.hamcrest.Matchers.startsWith;
import static org.junit.jupiter.api.Assumptions.assumeTrue;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.io.OutputStream; import java.io.OutputStream;
@ -46,7 +33,6 @@ import java.util.function.Consumer;
import java.util.regex.Matcher; import java.util.regex.Matcher;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import java.util.stream.Stream; import java.util.stream.Stream;
import javax.servlet.DispatcherType; import javax.servlet.DispatcherType;
import javax.servlet.Filter; import javax.servlet.Filter;
import javax.servlet.FilterChain; import javax.servlet.FilterChain;
@ -83,6 +69,19 @@ import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource; import org.junit.jupiter.params.provider.MethodSource;
import org.junit.jupiter.params.provider.ValueSource; import org.junit.jupiter.params.provider.ValueSource;
import static org.eclipse.jetty.http.HttpFieldsMatchers.containsHeader;
import static org.eclipse.jetty.http.HttpFieldsMatchers.containsHeaderValue;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.anyOf;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.endsWith;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.not;
import static org.hamcrest.Matchers.notNullValue;
import static org.hamcrest.Matchers.nullValue;
import static org.hamcrest.Matchers.startsWith;
import static org.junit.jupiter.api.Assumptions.assumeTrue;
@ExtendWith(WorkDirExtension.class) @ExtendWith(WorkDirExtension.class)
public class DefaultServletTest public class DefaultServletTest
{ {
@ -157,10 +156,14 @@ public class DefaultServletTest
defholder.setInitParameter("gzip", "false"); defholder.setInitParameter("gzip", "false");
/* create some content in the docroot */ /* create some content in the docroot */
FS.ensureDirExists(docRoot.resolve("one")); Path one = docRoot.resolve("one");
FS.ensureDirExists(one);
FS.ensureDirExists(docRoot.resolve("two")); FS.ensureDirExists(docRoot.resolve("two"));
FS.ensureDirExists(docRoot.resolve("three")); FS.ensureDirExists(docRoot.resolve("three"));
Path alert = one.resolve("onmouseclick='alert(oops)'");
FS.touch(alert);
/* /*
* Intentionally bad request URI. Sending a non-encoded URI with typically * Intentionally bad request URI. Sending a non-encoded URI with typically
* encoded characters '<', '>', and '"'. * encoded characters '<', '>', and '"'.
@ -172,6 +175,16 @@ public class DefaultServletTest
String body = response.getContent(); String body = response.getContent();
assertThat(body, not(containsString("<script>"))); assertThat(body, not(containsString("<script>")));
req1 = "GET /context/one/;\"onmouseover='alert(document.location)' HTTP/1.0\r\n" +
"\r\n";
rawResponse = connector.getResponse(req1);
response = HttpTester.parseResponse(rawResponse);
body = response.getContent();
assertThat(body, not(containsString(";\"onmouseover")));
} }
@Test @Test

View File

@ -31,19 +31,23 @@ import java.nio.channels.ReadableByteChannel;
import java.nio.file.Path; import java.nio.file.Path;
import java.text.DateFormat; import java.text.DateFormat;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection; import java.util.Collection;
import java.util.Collections;
import java.util.Date; import java.util.Date;
import java.util.List;
import org.eclipse.jetty.util.B64Code; import org.eclipse.jetty.util.B64Code;
import org.eclipse.jetty.util.IO; import org.eclipse.jetty.util.IO;
import org.eclipse.jetty.util.Loader; import org.eclipse.jetty.util.Loader;
import org.eclipse.jetty.util.MultiMap;
import org.eclipse.jetty.util.StringUtil; import org.eclipse.jetty.util.StringUtil;
import org.eclipse.jetty.util.URIUtil; import org.eclipse.jetty.util.URIUtil;
import org.eclipse.jetty.util.UrlEncoded; import org.eclipse.jetty.util.UrlEncoded;
import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger; import org.eclipse.jetty.util.log.Logger;
import static java.nio.charset.StandardCharsets.UTF_8;
/* ------------------------------------------------------------ */ /* ------------------------------------------------------------ */
/** /**
@ -353,7 +357,7 @@ public abstract class Resource implements ResourceFactory, Closeable
/* ------------------------------------------------------------ */ /* ------------------------------------------------------------ */
/** /**
* Time resource was last modified. * Time resource was last modified.
* *
* @return the last modified time as milliseconds since unix epoch * @return the last modified time as milliseconds since unix epoch
*/ */
public abstract long lastModified(); public abstract long lastModified();
@ -362,7 +366,7 @@ public abstract class Resource implements ResourceFactory, Closeable
/* ------------------------------------------------------------ */ /* ------------------------------------------------------------ */
/** /**
* Length of the resource. * Length of the resource.
* *
* @return the length of the resource * @return the length of the resource
*/ */
public abstract long length(); public abstract long length();
@ -371,7 +375,7 @@ public abstract class Resource implements ResourceFactory, Closeable
/* ------------------------------------------------------------ */ /* ------------------------------------------------------------ */
/** /**
* URL representing the resource. * URL representing the resource.
* *
* @return an URL representing the given resource * @return an URL representing the given resource
* @deprecated use {{@link #getURI()}.toURL() instead. * @deprecated use {{@link #getURI()}.toURL() instead.
*/ */
@ -381,7 +385,7 @@ public abstract class Resource implements ResourceFactory, Closeable
/* ------------------------------------------------------------ */ /* ------------------------------------------------------------ */
/** /**
* URI representing the resource. * URI representing the resource.
* *
* @return an URI representing the given resource * @return an URI representing the given resource
*/ */
public URI getURI() public URI getURI()
@ -400,10 +404,10 @@ public abstract class Resource implements ResourceFactory, Closeable
/* ------------------------------------------------------------ */ /* ------------------------------------------------------------ */
/** /**
* File representing the given resource. * File representing the given resource.
* *
* @return an File representing the given resource or NULL if this * @return an File representing the given resource or NULL if this
* is not possible. * is not possible.
* @throws IOException if unable to get the resource due to permissions * @throws IOException if unable to get the resource due to permissions
*/ */
public abstract File getFile() public abstract File getFile()
throws IOException; throws IOException;
@ -412,7 +416,7 @@ public abstract class Resource implements ResourceFactory, Closeable
/* ------------------------------------------------------------ */ /* ------------------------------------------------------------ */
/** /**
* The name of the resource. * The name of the resource.
* *
* @return the name of the resource * @return the name of the resource
*/ */
public abstract String getName(); public abstract String getName();
@ -421,7 +425,7 @@ public abstract class Resource implements ResourceFactory, Closeable
/* ------------------------------------------------------------ */ /* ------------------------------------------------------------ */
/** /**
* Input stream to the resource * Input stream to the resource
* *
* @return an input stream to the resource * @return an input stream to the resource
* @throws IOException if unable to open the input stream * @throws IOException if unable to open the input stream
*/ */
@ -431,7 +435,7 @@ public abstract class Resource implements ResourceFactory, Closeable
/* ------------------------------------------------------------ */ /* ------------------------------------------------------------ */
/** /**
* Readable ByteChannel for the resource. * Readable ByteChannel for the resource.
* *
* @return an readable bytechannel to the resource or null if one is not available. * @return an readable bytechannel to the resource or null if one is not available.
* @throws IOException if unable to open the readable bytechannel for the resource. * @throws IOException if unable to open the readable bytechannel for the resource.
*/ */
@ -443,7 +447,7 @@ public abstract class Resource implements ResourceFactory, Closeable
* Deletes the given resource * Deletes the given resource
* @return true if resource was found and successfully deleted, false if resource didn't exist or was unable to * @return true if resource was found and successfully deleted, false if resource didn't exist or was unable to
* be deleted. * be deleted.
* @throws SecurityException if unable to delete due to permissions * @throws SecurityException if unable to delete due to permissions
*/ */
public abstract boolean delete() public abstract boolean delete()
throws SecurityException; throws SecurityException;
@ -553,65 +557,229 @@ public abstract class Resource implements ResourceFactory, Closeable
* @return String of HTML * @return String of HTML
* @throws IOException if unable to get the list of resources as HTML * @throws IOException if unable to get the list of resources as HTML
*/ */
public String getListHTML(String base,boolean parent) public String getListHTML(String base, boolean parent) throws IOException
throws IOException {
return getListHTML(base, parent, 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
* @param query query params
* @return String of HTML
*/
public String getListHTML(String base, boolean parent, String query) throws IOException
{ {
base=URIUtil.canonicalPath(base); base=URIUtil.canonicalPath(base);
if (base==null || !isDirectory()) if (base==null || !isDirectory())
return null; 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); String[] rawListing = list();
buf.append("<HTML><HEAD>"); if (rawListing == null)
buf.append("<LINK HREF=\"").append("jetty-dir.css").append("\" REL=\"stylesheet\" TYPE=\"text/css\"/><TITLE>"); {
return null;
}
boolean sortOrderAscending = true;
String sortColumn = "N"; // name (or "M" for Last Modified, or "S" for Size)
// check for query
if (query != null)
{
MultiMap<String> params = new MultiMap<>();
byte[] rawQuery = query.getBytes(UTF_8);
UrlEncoded.decodeUtf8To(rawQuery, 0, query.length(), params);
String paramO = params.getString("O");
String paramC = params.getString("C");
if (StringUtil.isNotBlank(paramO))
{
if (paramO.equals("A"))
{
sortOrderAscending = true;
}
else if (paramO.equals("D"))
{
sortOrderAscending = false;
}
}
if (StringUtil.isNotBlank(paramC))
{
if (paramC.equals("N") || paramC.equals("M") || paramC.equals("S"))
{
sortColumn = paramC;
}
}
}
// Gather up entries
List<Resource> items = new ArrayList<>();
for (String l : rawListing)
{
Resource item = addPath(l);
items.add(item);
}
// Perform sort
if (sortColumn.equals("M"))
{
Collections.sort(items, ResourceCollators.byLastModified(sortOrderAscending));
}
else if (sortColumn.equals("S"))
{
Collections.sort(items, ResourceCollators.bySize(sortOrderAscending));
}
else
{
Collections.sort(items, ResourceCollators.byName(sortOrderAscending));
}
String decodedBase = URIUtil.decodePath(base);
String title = "Directory: " + deTag(decodedBase);
StringBuilder buf = new StringBuilder(4096);
// Doctype Declaration (HTML5)
buf.append("<!DOCTYPE html>\n");
buf.append("<html lang=\"en\">\n");
// HTML Header
buf.append("<head>\n");
buf.append("<meta charset=\"utf-8\">\n");
buf.append("<link href=\"jetty-dir.css\" rel=\"stylesheet\" />\n");
buf.append("<title>");
buf.append(title); buf.append(title);
buf.append("</TITLE></HEAD><BODY>\n<H1>"); buf.append("</title>\n");
buf.append(title); buf.append("</head>\n");
buf.append("</H1>\n<TABLE BORDER=0>\n");
// HTML Body
buf.append("<body>\n");
buf.append("<h1 class=\"title\">").append(title).append("</h1>\n");
// HTML Table
final String ARROW_DOWN = "&nbsp; &#8681;";
final String ARROW_UP = "&nbsp; &#8679;";
String arrow;
String order;
buf.append("<table class=\"listing\">\n");
buf.append("<thead>\n");
arrow = "";
order = "A";
if (sortColumn.equals("N"))
{
if(sortOrderAscending)
{
order = "D";
arrow = ARROW_UP;
}
else
{
order = "A";
arrow = ARROW_DOWN;
}
}
buf.append("<tr><th class=\"name\"><a href=\"?C=N&O=").append(order).append("\">");
buf.append("Name").append(arrow);
buf.append("</a></th>");
arrow = "";
order = "A";
if (sortColumn.equals("M"))
{
if(sortOrderAscending)
{
order = "D";
arrow = ARROW_UP;
}
else
{
order = "A";
arrow = ARROW_DOWN;
}
}
buf.append("<th class=\"lastmodified\"><a href=\"?C=M&O=").append(order).append("\">");
buf.append("Last Modified").append(arrow);
buf.append("</a></th>");
arrow = "";
order = "A";
if (sortColumn.equals("S"))
{
if(sortOrderAscending)
{
order = "D";
arrow = ARROW_UP;
}
else
{
order = "A";
arrow = ARROW_DOWN;
}
}
buf.append("<th class=\"size\"><a href=\"?C=S&O=").append(order).append("\">");
buf.append("Size").append(arrow);
buf.append("</a></th></tr>\n");
buf.append("</thead>\n");
buf.append("<tbody>\n");
String encodedBase = hrefEncodeURI(base);
if (parent) if (parent)
{ {
buf.append("<TR><TD><A HREF=\""); // Name
buf.append(URIUtil.addEncodedPaths(base,"../")); buf.append("<tr><td class=\"name\"><a href=\"");
buf.append("\">Parent Directory</A></TD><TD></TD><TD></TD></TR>\n"); buf.append(URIUtil.addPaths(encodedBase,"../"));
buf.append("\">Parent Directory</a></td>");
// Last Modified
buf.append("<td class=\"lastmodified\">-</td>");
// Size
buf.append("<td>-</td>");
buf.append("</tr>\n");
} }
String encodedBase = hrefEncodeURI(base);
DateFormat dfmt=DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat dfmt=DateFormat.getDateTimeInstance(DateFormat.MEDIUM,
DateFormat.MEDIUM); DateFormat.MEDIUM);
for (int i=0 ; i< ls.length ; i++) for (Resource item: items)
{ {
Resource item = addPath(ls[i]); String name = item.getName();
int slashIdx = name.lastIndexOf('/');
buf.append("\n<TR><TD><A HREF=\""); if (slashIdx != -1)
String path=URIUtil.addEncodedPaths(encodedBase,URIUtil.encodePath(ls[i])); {
name = name.substring(slashIdx + 1);
}
if (item.isDirectory() && !name.endsWith("/"))
{
name += URIUtil.SLASH;
}
// Name
buf.append("<tr><td class=\"name\"><a href=\"");
String path=URIUtil.addPaths(encodedBase,URIUtil.encodePath(name));
buf.append(path); buf.append(path);
if (item.isDirectory() && !path.endsWith("/"))
buf.append(URIUtil.SLASH);
// URIUtil.encodePath(buf,path);
buf.append("\">"); buf.append("\">");
buf.append(deTag(ls[i])); buf.append(deTag(name));
buf.append("&nbsp;"); buf.append("&nbsp;");
buf.append("</A></TD><TD ALIGN=right>"); buf.append("</a></td>");
buf.append(item.length());
buf.append(" bytes&nbsp;</TD><TD>"); // Last Modified
buf.append("<td class=\"lastmodified\">");
buf.append(dfmt.format(new Date(item.lastModified()))); buf.append(dfmt.format(new Date(item.lastModified())));
buf.append("</TD></TR>"); buf.append("</td>");
// Size
buf.append("<td class=\"size\">");
buf.append(String.format("%,d", item.length()));
buf.append(" bytes&nbsp;</td></tr>\n");
} }
buf.append("</TABLE>\n"); buf.append("</tbody>\n");
buf.append("</BODY></HTML>\n"); buf.append("</table>\n");
buf.append("</body></html>\n");
return buf.toString(); return buf.toString();
} }

View File

@ -0,0 +1,105 @@
//
// ========================================================================
// Copyright (c) 1995-2018 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.text.Collator;
import java.util.Collections;
import java.util.Comparator;
import java.util.Locale;
public class ResourceCollators
{
private static Comparator<? super Resource> BY_NAME_ASCENDING =
new Comparator<Resource>()
{
private final Collator collator = Collator.getInstance(Locale.ENGLISH);
@Override
public int compare(Resource o1, Resource o2)
{
return collator.compare(o1.getName(), o2.getName());
}
};
private static Comparator<? super Resource> BY_NAME_DESCENDING =
Collections.reverseOrder(BY_NAME_ASCENDING);
private static Comparator<? super Resource> BY_LAST_MODIFIED_ASCENDING =
new Comparator<Resource>()
{
@Override
public int compare(Resource o1, Resource o2)
{
return Long.compare(o1.lastModified(), o2.lastModified());
}
};
private static Comparator<? super Resource> BY_LAST_MODIFIED_DESCENDING =
Collections.reverseOrder(BY_LAST_MODIFIED_ASCENDING);
private static Comparator<? super Resource> BY_SIZE_ASCENDING =
new Comparator<Resource>()
{
@Override
public int compare(Resource o1, Resource o2)
{
return Long.compare(o1.length(), o2.length());
}
};
private static Comparator<? super Resource> BY_SIZE_DESCENDING =
Collections.reverseOrder(BY_SIZE_ASCENDING);
public static Comparator<? super Resource> byLastModified(boolean sortOrderAscending)
{
if (sortOrderAscending)
{
return BY_LAST_MODIFIED_ASCENDING;
}
else
{
return BY_LAST_MODIFIED_DESCENDING;
}
}
public static Comparator<? super Resource> byName(boolean sortOrderAscending)
{
if (sortOrderAscending)
{
return BY_NAME_ASCENDING;
}
else
{
return BY_NAME_DESCENDING;
}
}
public static Comparator<? super Resource> bySize(boolean sortOrderAscending)
{
if (sortOrderAscending)
{
return BY_SIZE_ASCENDING;
}
else
{
return BY_SIZE_DESCENDING;
}
}
}

View File

@ -1,19 +1,38 @@
body body {
{
background-color: #FFFFFF; background-color: #FFFFFF;
margin: 10px; margin: 10px;
padding: 5px; padding: 5px;
font-family: sans-serif;
} }
h1 h1.title {
{
text-shadow: #000000 -1px -1px 1px; text-shadow: #000000 -1px -1px 1px;
color: #FC390E; color: #FC390E;
font-weight: bold; font-weight: bold;
} }
a table.listing {
{ border: 0px;
}
thead a {
color: blue;
}
thead th {
border-bottom: black 1px solid;
}
.name, .lastmodified {
text-align: left;
padding-right: 15px;
}
.size {
text-align: right;
}
a {
color: #7036be; color: #7036be;
font-weight: bold; font-weight: bold;
font-style: normal; font-style: normal;
@ -21,10 +40,9 @@ a
font-size:inherit; font-size:inherit;
} }
td td {
{
font-style: italic; font-style: italic;
padding: 2px 15px 2px 0px; padding: 2px;
} }

View File

@ -141,7 +141,7 @@ if proceedyn "Are you sure you want to release using above? (y/N)" n; then
# This is equivalent to 'mvn release:prepare' # This is equivalent to 'mvn release:prepare'
if proceedyn "Update project.versions for $VER_RELEASE? (Y/n)" y; then if proceedyn "Update project.versions for $VER_RELEASE? (Y/n)" y; then
mvn org.codehaus.mojo:versions-maven-plugin:2.5:set \ mvn org.codehaus.mojo:versions-maven-plugin:2.7:set \
-DoldVersion="$VER_CURRENT" \ -DoldVersion="$VER_CURRENT" \
-DnewVersion="$VER_RELEASE" \ -DnewVersion="$VER_RELEASE" \
-DprocessAllModules=true -DprocessAllModules=true

View File

@ -22,7 +22,6 @@ import java.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.List; import java.util.List;
import javax.annotation.PostConstruct; import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy; import javax.annotation.PreDestroy;
import javax.annotation.Resource; import javax.annotation.Resource;
@ -209,10 +208,10 @@ public class AnnotationTest extends HttpServlet
boolean fragInitParamResult = "123".equals(config.getInitParameter("extra1")) && "345".equals(config.getInitParameter("extra2")); boolean fragInitParamResult = "123".equals(config.getInitParameter("extra1")) && "345".equals(config.getInitParameter("extra2"));
out.println("<p><b>Result: "+(fragInitParamResult? "<span class=\"pass\">PASS": "<span class=\"fail\">FAIL")+"</span></p>"); out.println("<p><b>Result: "+(fragInitParamResult? "<span class=\"pass\">PASS": "<span class=\"fail\">FAIL")+"</span></p>");
__HandlesTypes = Arrays.asList( "javax.servlet.GenericServlet", __HandlesTypes = Arrays.asList( "javax.servlet.GenericServlet",
"javax.servlet.http.HttpServlet", "javax.servlet.http.HttpServlet",
"com.acme.test.AsyncListenerServlet", "com.acme.test.AsyncListenerServlet",
"com.acme.test.ClassLoaderServlet",
"com.acme.test.AnnotationTest", "com.acme.test.AnnotationTest",
"com.acme.test.RoleAnnotationTest", "com.acme.test.RoleAnnotationTest",
"com.acme.test.MultiPartTest", "com.acme.test.MultiPartTest",