Add constructors accepting the handler to wrap to all core handler wrappers (#9988)

Add constructors accepting the handler to wrap to all core handler wrappers

Signed-off-by: Ludovic Orban <lorban@bitronix.be>
This commit is contained in:
Ludovic Orban 2023-06-30 13:15:45 +02:00 committed by GitHub
parent c43514f4f5
commit 457d41ccad
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
22 changed files with 218 additions and 135 deletions

View File

@ -31,17 +31,17 @@ There is also an link:#error-handler[Error Handler] that services errors related
_____
[NOTE]
The `DefaultHandler` will also handle serving out the `flav.ico` file should a request make it through all of the other handlers without being resolved.
The `DefaultHandler` will also handle serving out the `favicon.ico` file should a request make it through all of the other handlers without being resolved.
_____
[source, java, subs="{sub-order}"]
----
Server server = new Server(8080);
HandlerList handlers = new HandlerList();
ResourceHandler resourceHandler = new ResourceHandler();
resourceHandler.setBaseResource(Resource.newResource("."));
handlers.setHandlers(new Handler[]
{ resourceHandler, new DefaultHandler() });
resourceHandler.setBaseResource(ResourceFactory.of(resourceHandler).newResource("."));
Handler.Sequence handlers = new Handler.Sequence(
resourceHandler, new DefaultHandler()
);
server.setHandler(handlers);
server.start();
----

View File

@ -46,7 +46,7 @@ The Jetty Server Libraries provides a number of out-of-the-box __Handler__s that
====== ContextHandler
`ContextHandler` is a `Handler` that represents a _context_ for a web application.
It is a `HandlerWrapper` that performs some action before and after delegating to the nested `Handler`.
It is a `Handler.Wrapper` that performs some action before and after delegating to the nested `Handler`.
// TODO: expand on what the ContextHandler does, e.g. ServletContext.
The simplest use of `ContextHandler` is the following:
@ -140,7 +140,7 @@ See also xref:pg-server-http-handler-use-util-default-handler[how to use] `Defau
`GzipHandler` provides supports for automatic decompression of compressed request content and automatic compression of response content.
`GzipHandler` is a `HandlerWrapper` that inspects the request and, if the request matches the `GzipHandler` configuration, just installs the required components to eventually perform decompression of the request content or compression of the response content.
`GzipHandler` is a `Handler.Wrapper` that inspects the request and, if the request matches the `GzipHandler` configuration, just installs the required components to eventually perform decompression of the request content or compression of the response content.
The decompression/compression is not performed until the web application reads request content or writes response content.
`GzipHandler` can be configured at the server level in this way:
@ -291,7 +291,7 @@ include::../../{doc_code}/org/eclipse/jetty/docs/programming/server/http/HTTPSer
* Sends a HTTP `404` response for any other request
* The HTTP `404` response content nicely shows a HTML table with all the contexts deployed on the `Server` instance
`DefaultHandler` is best used as the last `Handler` of a `HandlerList`, for example:
`DefaultHandler` is best used directly set on the server, for example:
[source,java,indent=0]
----
@ -310,7 +310,7 @@ Server
└── DefaultHandler
----
In the example above, `ContextHandlerCollection` will try to match a request to one of the contexts; if the match fails, `HandlerList` will call the next `Handler` which is `DefaultHandler` that will return a HTTP `404` with an HTML page showing the existing contexts deployed on the `Server`.
In the example above, `ContextHandlerCollection` will try to match a request to one of the contexts; if the match fails, `Server` will call the `DefaultHandler` that will return a HTTP `404` with an HTML page showing the existing contexts deployed on the `Server`.
NOTE: `DefaultHandler` just sends a nicer HTTP `404` response in case of wrong requests from clients.
Jetty will send an HTTP `404` response anyway if `DefaultHandler` is not used.

View File

@ -110,53 +110,6 @@ public class HTTPServerDocs
// end::simple[]
}
public void httpChannelListener() throws Exception
{
// tag::httpChannelListener[]
// TODO: HttpChannelState.Listener does not exist anymore.
/*
class TimingHttpChannelListener implements HttpChannelState.Listener
{
private final ConcurrentMap<Request, Long> times = new ConcurrentHashMap<>();
@Override
public void onRequestBegin(Request request)
{
times.put(request, NanoTime.now());
}
@Override
public void onComplete(Request request)
{
long begin = times.remove(request);
long elapsed = NanoTime.since(begin);
System.getLogger("timing").log(INFO, "Request {0} took {1} ns", request, elapsed);
}
}
Server server = new Server();
Connector connector = new ServerConnector(server);
server.addConnector(connector);
// Add the HttpChannel.Listener as bean to the connector.
connector.addBean(new TimingHttpChannelListener());
// Set a simple Handler to handle requests/responses.
server.setHandler(new AbstractHandler()
{
@Override
public void handle(String target, Request jettyRequest, HttpServletRequest request, HttpServletResponse response)
{
jettyRequest.setHandled(true);
}
});
server.start();
*/
// end::httpChannelListener[]
}
public void serverRequestLogSLF4J()
{
// tag::serverRequestLogSLF4J[]
@ -508,14 +461,14 @@ public class HTTPServerDocs
// tag::handlerTree[]
Server server = new Server();
GzipHandler gzipHandler = new GzipHandler();
server.setHandler(gzipHandler);
Handler.Sequence sequence = new Handler.Sequence();
gzipHandler.setHandler(sequence);
sequence.addHandler(new App1Handler());
sequence.addHandler(new App2Handler());
GzipHandler gzipHandler = new GzipHandler(sequence);
server.setHandler(gzipHandler);
// end::handlerTree[]
}
@ -585,6 +538,11 @@ public class HTTPServerDocs
// tag::handlerFilter[]
class FilterHandler extends Handler.Wrapper
{
public FilterHandler(Handler handler)
{
super(handler);
}
@Override
public boolean handle(Request request, Response response, Callback callback) throws Exception
{
@ -617,9 +575,7 @@ public class HTTPServerDocs
server.addConnector(connector);
// Link the Handlers.
FilterHandler filter = new FilterHandler();
filter.setHandler(new HelloWorldHandler());
server.setHandler(filter);
server.setHandler(new FilterHandler(new HelloWorldHandler()));
server.start();
// end::handlerFilter[]
@ -643,9 +599,7 @@ public class HTTPServerDocs
server.addConnector(connector);
// Create a ContextHandler with contextPath.
ContextHandler context = new ContextHandler();
context.setContextPath("/shop");
context.setHandler(new ShopHandler());
ContextHandler context = new ContextHandler(new ShopHandler(), "/shop");
// Link the context to the server.
server.setHandler(context);
@ -683,20 +637,17 @@ public class HTTPServerDocs
// Create a ContextHandlerCollection to hold contexts.
ContextHandlerCollection contextCollection = new ContextHandlerCollection();
// Create the context for the shop web application and add it to ContextHandlerCollection.
contextCollection.addHandler(new ContextHandler(new ShopHandler(), "/shop"));
// Link the ContextHandlerCollection to the Server.
server.setHandler(contextCollection);
// Create the context for the shop web application.
ContextHandler shopContext = new ContextHandler("/shop");
shopContext.setHandler(new ShopHandler());
// Add it to ContextHandlerCollection.
contextCollection.addHandler(shopContext);
server.start();
// Create the context for the API web application.
ContextHandler apiContext = new ContextHandler("/api");
apiContext.setHandler(new RESTHandler());
ContextHandler apiContext = new ContextHandler(new RESTHandler(), "/api");
// Web applications can be deployed after the Server is started.
contextCollection.deployHandler(apiContext, Callback.NOOP);
// end::contextHandlerCollection[]
@ -791,7 +742,7 @@ public class HTTPServerDocs
// tag::multipleResourcesHandler[]
ResourceHandler handler = new ResourceHandler();
// For multiple directories, use ResourceCollection.
// For multiple directories, use ResourceFactory.combine().
Resource resource = ResourceFactory.combine(
ResourceFactory.of(handler).newResource("/path/to/static/resources/"),
ResourceFactory.of(handler).newResource("/another/path/to/static/resources/")
@ -822,8 +773,10 @@ public class HTTPServerDocs
Connector connector = new ServerConnector(server);
server.addConnector(connector);
// Create and configure GzipHandler.
GzipHandler gzipHandler = new GzipHandler();
// Create a ContextHandlerCollection to manage contexts.
ContextHandlerCollection contexts = new ContextHandlerCollection();
// Create and configure GzipHandler linked to the ContextHandlerCollection.
GzipHandler gzipHandler = new GzipHandler(contexts);
// Only compress response content larger than this.
gzipHandler.setMinGzipSize(1024);
// Do not compress these URI paths.
@ -833,10 +786,6 @@ public class HTTPServerDocs
// Do not compress these mime types.
gzipHandler.addExcludedMimeTypes("font/ttf");
// Link a ContextHandlerCollection to manage contexts.
ContextHandlerCollection contexts = new ContextHandlerCollection();
gzipHandler.setHandler(contexts);
// Link the GzipHandler to the Server.
server.setHandler(gzipHandler);
@ -873,26 +822,21 @@ public class HTTPServerDocs
// tag::contextGzipHandler[]
// Create a ContextHandlerCollection to hold contexts.
ContextHandlerCollection contextCollection = new ContextHandlerCollection();
// Link the ContextHandlerCollection to the Server.
server.setHandler(contextCollection);
// Create the context for the shop web application.
ContextHandler shopContext = new ContextHandler("/shop");
shopContext.setHandler(new ShopHandler());
// You want to gzip the shop web application only.
GzipHandler shopGzipHandler = new GzipHandler();
shopGzipHandler.setHandler(shopContext);
// Create the context for the shop web application wrapped with GzipHandler so only the shop will do gzip.
GzipHandler shopGzipHandler = new GzipHandler(new ContextHandler(new ShopHandler(), "/shop"));
// Add it to ContextHandlerCollection.
contextCollection.addHandler(shopGzipHandler);
// Create the context for the API web application.
ContextHandler apiContext = new ContextHandler("/api");
apiContext.setHandler(new RESTHandler());
ContextHandler apiContext = new ContextHandler(new RESTHandler(), "/api");
// Add it to ContextHandlerCollection.
contextCollection.addHandler(apiContext);
// Link the ContextHandlerCollection to the Server.
server.setHandler(contextCollection);
// end::contextGzipHandler[]
server.start();
@ -905,7 +849,10 @@ public class HTTPServerDocs
ServerConnector connector = new ServerConnector(server);
server.addConnector(connector);
RewriteHandler rewriteHandler = new RewriteHandler();
// Create a ContextHandlerCollection to hold contexts.
ContextHandlerCollection contextCollection = new ContextHandlerCollection();
// Link the ContextHandlerCollection to the RewriteHandler.
RewriteHandler rewriteHandler = new RewriteHandler(contextCollection);
// Compacts URI paths with double slashes, e.g. /ctx//path/to//resource.
rewriteHandler.addRule(new CompactPathRule());
// Rewrites */products/* to */p/*.
@ -918,11 +865,6 @@ public class HTTPServerDocs
// Link the RewriteHandler to the Server.
server.setHandler(rewriteHandler);
// Create a ContextHandlerCollection to hold contexts.
ContextHandlerCollection contextCollection = new ContextHandlerCollection();
// Link the ContextHandlerCollection to the RewriteHandler.
rewriteHandler.setHandler(contextCollection);
server.start();
// end::rewriteHandler[]
}
@ -934,16 +876,15 @@ public class HTTPServerDocs
ServerConnector connector = new ServerConnector(server);
server.addConnector(connector);
StatisticsHandler statsHandler = new StatisticsHandler();
// Create a ContextHandlerCollection to hold contexts.
ContextHandlerCollection contextCollection = new ContextHandlerCollection();
// Link the ContextHandlerCollection to the StatisticsHandler.
StatisticsHandler statsHandler = new StatisticsHandler(contextCollection);
// Link the StatisticsHandler to the Server.
server.setHandler(statsHandler);
// Create a ContextHandlerCollection to hold contexts.
ContextHandlerCollection contextCollection = new ContextHandlerCollection();
// Link the ContextHandlerCollection to the StatisticsHandler.
statsHandler.setHandler(contextCollection);
server.start();
// end::statisticsHandler[]
}
@ -955,17 +896,15 @@ public class HTTPServerDocs
ServerConnector connector = new ServerConnector(server);
server.addConnector(connector);
// Create the MinimumDataRateHandler with a minimum read rate of 1KB per second and no minimum write rate.
StatisticsHandler.MinimumDataRateHandler dataRateHandler = new StatisticsHandler.MinimumDataRateHandler(1024L, 0L);
// Create a ContextHandlerCollection to hold contexts.
ContextHandlerCollection contextCollection = new ContextHandlerCollection();
// Create the MinimumDataRateHandler linked the ContextHandlerCollection with a minimum read rate of 1KB per second and no minimum write rate.
StatisticsHandler.MinimumDataRateHandler dataRateHandler = new StatisticsHandler.MinimumDataRateHandler(contextCollection, 1024L, 0L);
// Link the MinimumDataRateHandler to the Server.
server.setHandler(dataRateHandler);
// Create a ContextHandlerCollection to hold contexts.
ContextHandlerCollection contextCollection = new ContextHandlerCollection();
// Link the ContextHandlerCollection to the MinimumDataRateHandler.
dataRateHandler.setHandler(contextCollection);
server.start();
// end::dataRateHandler[]
}
@ -1006,16 +945,15 @@ public class HTTPServerDocs
secureConnector.setPort(8443);
server.addConnector(secureConnector);
SecuredRedirectHandler securedHandler = new SecuredRedirectHandler();
// Create a ContextHandlerCollection to hold contexts.
ContextHandlerCollection contextCollection = new ContextHandlerCollection();
// Link the ContextHandlerCollection to the SecuredRedirectHandler.
SecuredRedirectHandler securedHandler = new SecuredRedirectHandler(contextCollection);
// Link the SecuredRedirectHandler to the Server.
server.setHandler(securedHandler);
// Create a ContextHandlerCollection to hold contexts.
ContextHandlerCollection contextCollection = new ContextHandlerCollection();
// Link the ContextHandlerCollection to the StatisticsHandler.
securedHandler.setHandler(contextCollection);
server.start();
// end::securedHandler[]
}

View File

@ -43,11 +43,22 @@ public class RewriteHandler extends Handler.Wrapper
public RewriteHandler()
{
this(new RuleContainer());
this(null, new RuleContainer());
}
public RewriteHandler(RuleContainer rules)
{
this(null, rules);
}
public RewriteHandler(Handler handler)
{
this(handler, new RuleContainer());
}
public RewriteHandler(Handler handler, RuleContainer rules)
{
super(handler);
_rules = rules;
addBean(_rules);
}

View File

@ -87,6 +87,12 @@ public abstract class SecurityHandler extends Handler.Wrapper implements Configu
protected SecurityHandler()
{
this(null);
}
protected SecurityHandler(Handler handler)
{
super(handler);
addBean(new DumpableCollection("knownAuthenticatorFactories", __knownAuthenticatorFactories));
}
@ -645,6 +651,12 @@ public abstract class SecurityHandler extends Handler.Wrapper implements Configu
public PathMapped()
{
this(null);
}
public PathMapped(Handler handler)
{
super(handler);
}
public Constraint put(String pathSpec, Constraint constraint)

View File

@ -65,6 +65,12 @@ public class BufferedResponseHandler extends Handler.Wrapper
public BufferedResponseHandler()
{
this(null);
}
public BufferedResponseHandler(Handler handler)
{
super(handler);
_methods.include(HttpMethod.GET.asString());
for (String type : MimeTypes.DEFAULTS.getMimeMap().values())
{

View File

@ -77,7 +77,7 @@ public class ConnectHandler extends Handler.Wrapper
public ConnectHandler(Handler handler)
{
setHandler(handler);
super(handler);
}
public Executor getExecutor()

View File

@ -159,11 +159,22 @@ public class ContextHandler extends Handler.Wrapper implements Attributes, Alias
public ContextHandler()
{
this(null);
this(null, null);
}
public ContextHandler(Handler handler)
{
this(handler, null);
}
public ContextHandler(String contextPath)
{
this(null, contextPath);
}
public ContextHandler(Handler handler, String contextPath)
{
super(handler);
_context = newContext();
if (contextPath != null)
setContextPath(contextPath);

View File

@ -41,6 +41,16 @@ public class DebugHandler extends Handler.Wrapper implements Connection.Listener
private OutputStream _out;
private PrintStream _print;
public DebugHandler()
{
this(null);
}
public DebugHandler(Handler handler)
{
super(handler);
}
@Override
public boolean handle(Request request, Response response, Callback callback) throws Exception
{

View File

@ -38,6 +38,16 @@ import org.eclipse.jetty.util.StringUtil;
public class DelayedHandler extends Handler.Wrapper
{
public DelayedHandler()
{
this(null);
}
public DelayedHandler(Handler handler)
{
super(handler);
}
@Override
public boolean handle(Request request, Response response, Callback callback) throws Exception
{

View File

@ -55,6 +55,7 @@ public abstract class EventsHandler extends Handler.Wrapper
public EventsHandler()
{
this(null);
}
public EventsHandler(Handler handler)

View File

@ -39,6 +39,12 @@ public class GracefulHandler extends Handler.Wrapper implements Graceful
public GracefulHandler()
{
this(null);
}
public GracefulHandler(Handler handler)
{
super(handler);
_shutdown = new Shutdown(this)
{
@Override

View File

@ -36,6 +36,16 @@ public class IdleTimeoutHandler extends Handler.Wrapper
private long _idleTimeoutMs = 1000;
private boolean _applyToAsync = false;
public IdleTimeoutHandler()
{
this(null);
}
public IdleTimeoutHandler(Handler handler)
{
super(handler);
}
public boolean isApplyToAsync()
{
return _applyToAsync;

View File

@ -47,6 +47,16 @@ public class InetAccessHandler extends Handler.Wrapper
private final IncludeExcludeSet<PatternTuple, AccessTuple> _set = new IncludeExcludeSet<>(InetAccessSet.class);
public InetAccessHandler()
{
this(null);
}
public InetAccessHandler(Handler handler)
{
super(handler);
}
/**
* Clears all the includes, excludes, included connector names and excluded
* connector names.

View File

@ -63,6 +63,16 @@ public class ResourceHandler extends Handler.Wrapper
private MimeTypes _mimeTypes;
private List<String> _welcomes = List.of("index.html");
public ResourceHandler()
{
this(null);
}
public ResourceHandler(Handler handler)
{
super(handler);
}
protected ResourceService newResourceService()
{
return new HandlerResourceService();

View File

@ -47,7 +47,7 @@ public class SecuredRedirectHandler extends Handler.Wrapper
*/
public SecuredRedirectHandler()
{
this(HttpStatus.MOVED_TEMPORARILY_302);
this(null, HttpStatus.MOVED_TEMPORARILY_302);
}
/**
@ -56,8 +56,29 @@ public class SecuredRedirectHandler extends Handler.Wrapper
* @param code the redirect code to use in the response
* @throws IllegalArgumentException if parameter is an invalid redirect code
*/
public SecuredRedirectHandler(final int code)
public SecuredRedirectHandler(int code)
{
this(null, code);
}
/**
* Uses moved temporarily code (302) as the redirect code.
*/
public SecuredRedirectHandler(Handler handler)
{
this(handler, HttpStatus.MOVED_TEMPORARILY_302);
}
/**
* Use supplied code as the redirect code.
*
* @param handler the handler to wrap
* @param code the redirect code to use in the response
* @throws IllegalArgumentException if parameter is an invalid redirect code
*/
public SecuredRedirectHandler(Handler handler, int code)
{
super(handler);
if (!HttpStatus.isRedirection(code))
throw new IllegalArgumentException("Not a 3xx redirect code");
_redirectCode = code;

View File

@ -91,7 +91,7 @@ public class ShutdownHandler extends Handler.Wrapper
*/
public ShutdownHandler(String shutdownToken)
{
this(null, shutdownToken, false);
this(null, null, shutdownToken, false);
}
/**
@ -102,18 +102,20 @@ public class ShutdownHandler extends Handler.Wrapper
*/
public ShutdownHandler(String shutdownToken, boolean exitJVM)
{
this(null, shutdownToken, exitJVM);
this(null, null, shutdownToken, exitJVM);
}
/**
* Creates a Handler that lets the server be shut down remotely (but only from localhost).
*
* @param handler the handler to wrap
* @param shutdownPath the path to respond to shutdown requests against (default is "{@code /shutdown}")
* @param shutdownToken a secret password to avoid unauthorized shutdown attempts
* @param exitJVM If true, when the shutdown is executed, the handler class System.exit()
*/
public ShutdownHandler(String shutdownPath, String shutdownToken, boolean exitJVM)
public ShutdownHandler(Handler handler, String shutdownPath, String shutdownToken, boolean exitJVM)
{
super(handler);
this._shutdownPath = StringUtil.isBlank(shutdownPath) ? "/shutdown" : shutdownPath;
this._shutdownToken = shutdownToken;
this._exitJvm = exitJVM;

View File

@ -241,17 +241,17 @@ public class StatisticsHandler extends EventsHandler
*/
public MinimumDataRateHandler(long minimumReadRate, long minimumWriteRate)
{
_minimumReadRate = minimumReadRate;
_minimumWriteRate = minimumWriteRate;
this(null, minimumReadRate, minimumWriteRate);
}
/**
* Creates a {@code MinimumDataRateHandler} with the specified read and write rates.
*
* @param handler the handler to wrap.
* @param minimumReadRate the minimum number of bytes to be read per second, or 0 for not checking the read rate.
* @param minimumWriteRate the minimum number of bytes to be written per second, or 0 for not checking the write rate.
* @param handler the handler to wrap.
*/
public MinimumDataRateHandler(long minimumReadRate, long minimumWriteRate, Handler handler)
public MinimumDataRateHandler(Handler handler, long minimumReadRate, long minimumWriteRate)
{
super(handler);
_minimumReadRate = minimumReadRate;

View File

@ -80,17 +80,22 @@ public class ThreadLimitHandler extends Handler.Wrapper
public ThreadLimitHandler()
{
this(null, true);
this(null, null, true);
}
public ThreadLimitHandler(@Name("forwardedHeader") String forwardedHeader)
{
this(forwardedHeader, HttpHeader.FORWARDED.is(forwardedHeader));
this(null, forwardedHeader, HttpHeader.FORWARDED.is(forwardedHeader));
}
public ThreadLimitHandler(@Name("forwardedHeader") String forwardedHeader, @Name("rfc7239") boolean rfc7239)
{
super();
this(null, forwardedHeader, rfc7239);
}
public ThreadLimitHandler(@Name("handler") Handler handler, @Name("forwardedHeader") String forwardedHeader, @Name("rfc7239") boolean rfc7239)
{
super(handler);
_rfc7239 = rfc7239;
_forwardedHeader = forwardedHeader;
_enabled = true;

View File

@ -71,6 +71,16 @@ public class TryPathsHandler extends Handler.Wrapper
private String originalQueryAttribute;
private List<String> paths;
public TryPathsHandler()
{
this(null);
}
public TryPathsHandler(Handler handler)
{
super(handler);
}
/**
* @return the attribute name of the original request path
*/

View File

@ -63,6 +63,16 @@ public class GzipHandler extends Handler.Wrapper implements GzipFactory
*/
public GzipHandler()
{
this(null);
}
/**
* Instantiates a new GzipHandler.
* @param handler the handler to wrap
*/
public GzipHandler(Handler handler)
{
super(handler);
_methods.include(HttpMethod.GET.asString());
_methods.include(HttpMethod.POST.asString());
for (String type : MimeTypes.DEFAULTS.getMimeMap().values())

View File

@ -158,7 +158,7 @@ public class StatisticsHandlerTest
AtomicReference<Throwable> exceptionRef = new AtomicReference<>();
CountDownLatch latch = new CountDownLatch(1);
int expectedContentLength = 1000;
StatisticsHandler.MinimumDataRateHandler mdrh = new StatisticsHandler.MinimumDataRateHandler(0, 1000, new Handler.Abstract.NonBlocking()
StatisticsHandler.MinimumDataRateHandler mdrh = new StatisticsHandler.MinimumDataRateHandler(new Handler.Abstract.NonBlocking()
{
@Override
public boolean handle(Request request, Response response, Callback callback)
@ -217,7 +217,7 @@ public class StatisticsHandlerTest
response.write(true, ByteBuffer.allocate(1), finalCallback);
}
}
});
}, 0, 1000);
_latchHandler.setHandler(mdrh);
_server.start();