Improvements to the Jetty server documentation.
Documented HttpChannel.Listener events. Signed-off-by: Simone Bordet <simone.bordet@gmail.com>
This commit is contained in:
parent
474fa8b8e9
commit
79c90402e5
|
@ -40,7 +40,7 @@ connections on the listening port.
|
||||||
When a connection is accepted, `ServerConnector` wraps the accepted
|
When a connection is accepted, `ServerConnector` wraps the accepted
|
||||||
`SocketChannel` and passes it to the
|
`SocketChannel` and passes it to the
|
||||||
xref:eg-io-arch-selector-manager[`SelectorManager`].
|
xref:eg-io-arch-selector-manager[`SelectorManager`].
|
||||||
Therefore there is a little moment where the acceptor thread is not accepting
|
Therefore, there is a little moment where the acceptor thread is not accepting
|
||||||
new connections because it is busy wrapping the just accepted one to pass it
|
new connections because it is busy wrapping the just accepted one to pass it
|
||||||
to the `SelectorManager`.
|
to the `SelectorManager`.
|
||||||
Connections that are ready to be accepted but are not accepted yet are queued
|
Connections that are ready to be accepted but are not accepted yet are queued
|
||||||
|
|
|
@ -74,8 +74,110 @@ by the Servlet specification.
|
||||||
|
|
||||||
All these features are provided by the Jetty Server Libraries and server
|
All these features are provided by the Jetty Server Libraries and server
|
||||||
applications only need to put the required components together to provide
|
applications only need to put the required components together to provide
|
||||||
all the required features.
|
all the required features, and it is discussed in details in
|
||||||
// TODO: link to a place where we discuss the handlers in more details.
|
xref:eg-server-http-handler-use[this section].
|
||||||
|
|
||||||
|
[[eg-server-http-request-processing]]
|
||||||
|
==== Server Request Processing
|
||||||
|
|
||||||
|
The Jetty HTTP request processing is outlined below in the diagram below.
|
||||||
|
|
||||||
|
Request handing is slightly different for each protocol; in HTTP/2 Jetty
|
||||||
|
takes into account multiplexing, something that is not present in HTTP/1.1.
|
||||||
|
|
||||||
|
However, the diagram below captures the essence of request handling that
|
||||||
|
is common among all protocols that carry HTTP requests.
|
||||||
|
|
||||||
|
First, the Jetty I/O layer emits an event that a socket has data to read.
|
||||||
|
This event is converted to a call to `AbstractConnection.onFillable()`,
|
||||||
|
where the `Connection` first reads from the `EndPoint` into a `ByteBuffer`,
|
||||||
|
and then calls a protocol specific parser to parse the bytes in the
|
||||||
|
`ByteBuffer`.
|
||||||
|
|
||||||
|
The parser emit events such that are protocol specific; the HTTP/2 parser,
|
||||||
|
for example, emits events for each HTTP/2 frame that has been parsed.
|
||||||
|
The parser events are then converted to protocol independent events such
|
||||||
|
as _"request start"_, _"request headers"_, _"request content chunk"_, etc.
|
||||||
|
that in turn are converted into method calls to `HttpChannel`.
|
||||||
|
|
||||||
|
When enough of the HTTP request is arrived, the `Connection` calls
|
||||||
|
`HttpChannel.handle()` that calls the `Handler` chain, that eventually
|
||||||
|
calls the server application code.
|
||||||
|
|
||||||
|
[plantuml]
|
||||||
|
----
|
||||||
|
skinparam backgroundColor transparent
|
||||||
|
skinparam monochrome true
|
||||||
|
skinparam shadowing false
|
||||||
|
|
||||||
|
participant ManagedSelector
|
||||||
|
participant EndPoint
|
||||||
|
participant Connection
|
||||||
|
participant Parser
|
||||||
|
participant HttpChannel
|
||||||
|
participant Server
|
||||||
|
participant Handlers
|
||||||
|
|
||||||
|
ManagedSelector -> EndPoint : read ready
|
||||||
|
EndPoint -> Connection : onFillable()
|
||||||
|
Connection -> EndPoint : fill()
|
||||||
|
EndPoint --> Connection
|
||||||
|
Connection -> Parser : parse()
|
||||||
|
Parser -> HttpChannel : events
|
||||||
|
Connection -> HttpChannel : handle()
|
||||||
|
HttpChannel -> Server : handle()
|
||||||
|
Server -> Handlers : handle()
|
||||||
|
----
|
||||||
|
|
||||||
|
[[eg-server-http-channel-events]]
|
||||||
|
===== HttpChannel Events
|
||||||
|
|
||||||
|
The central component processing HTTP requests is `HttpChannel`.
|
||||||
|
There is a 1-to-1 relationship between an HTTP request/response and an
|
||||||
|
`HttpChannel`, no matter what is the specific protocol that carries the
|
||||||
|
HTTP request over the network (HTTP/1.1, HTTP/2 or FastCGI).
|
||||||
|
|
||||||
|
Advanced server applications may be interested in the progress of the
|
||||||
|
processing of an HTTP request/response by `HttpChannel`.
|
||||||
|
A typical case is to know exactly _when_ the HTTP request/response
|
||||||
|
processing is complete, for example to monitor processing times.
|
||||||
|
|
||||||
|
NOTE: A `Handler` or a Servlet `Filter` may not report precisely when
|
||||||
|
an HTTP request/response processing is finished.
|
||||||
|
A server application may write a small enough content that is aggregated
|
||||||
|
by Jetty for efficiency reasons; the write returns immediately, but
|
||||||
|
nothing has been written to the network yet.
|
||||||
|
|
||||||
|
`HttpChannel` notifies ``HttpChannel.Listener``s of the progress of the
|
||||||
|
HTTP request/response handling.
|
||||||
|
Currently, the following events are available:
|
||||||
|
|
||||||
|
* `requestBegin`
|
||||||
|
* `beforeDispatch`
|
||||||
|
* `dispatchFailure`
|
||||||
|
* `afterDispatch`
|
||||||
|
* `requestContent`
|
||||||
|
* `requestContentEnd`
|
||||||
|
* `requestTrailers`
|
||||||
|
* `requestEnd`
|
||||||
|
* `responseBegin`
|
||||||
|
* `responseCommit`
|
||||||
|
* `responseContent`
|
||||||
|
* `responseFailure`
|
||||||
|
* `responseEnd`
|
||||||
|
* `complete`
|
||||||
|
|
||||||
|
Please refer to the `HttpChannel.Listener`
|
||||||
|
link:{JDURL}/org/eclipse/jetty/server/HttpChannel.Listener.html[javadocs]
|
||||||
|
for the complete list of events.
|
||||||
|
|
||||||
|
Server applications can register `HttpChannel.Listener` by adding them as
|
||||||
|
beans to the `Connector`:
|
||||||
|
|
||||||
|
[source,java,indent=0]
|
||||||
|
----
|
||||||
|
include::../../{doc_code}/embedded/server/http/HTTPServerDocs.java[tags=httpChannelListener]
|
||||||
|
----
|
||||||
|
|
||||||
include::server-http-connector.adoc[]
|
include::server-http-connector.adoc[]
|
||||||
include::server-http-handler.adoc[]
|
include::server-http-handler.adoc[]
|
||||||
|
|
|
@ -20,6 +20,8 @@ package embedded.server.http;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.EnumSet;
|
import java.util.EnumSet;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
import java.util.concurrent.ConcurrentMap;
|
||||||
import javax.servlet.DispatcherType;
|
import javax.servlet.DispatcherType;
|
||||||
import javax.servlet.ServletException;
|
import javax.servlet.ServletException;
|
||||||
import javax.servlet.http.HttpServlet;
|
import javax.servlet.http.HttpServlet;
|
||||||
|
@ -37,6 +39,7 @@ import org.eclipse.jetty.rewrite.handler.RedirectRegexRule;
|
||||||
import org.eclipse.jetty.rewrite.handler.RewriteHandler;
|
import org.eclipse.jetty.rewrite.handler.RewriteHandler;
|
||||||
import org.eclipse.jetty.rewrite.handler.RewriteRegexRule;
|
import org.eclipse.jetty.rewrite.handler.RewriteRegexRule;
|
||||||
import org.eclipse.jetty.server.Connector;
|
import org.eclipse.jetty.server.Connector;
|
||||||
|
import org.eclipse.jetty.server.HttpChannel;
|
||||||
import org.eclipse.jetty.server.HttpConfiguration;
|
import org.eclipse.jetty.server.HttpConfiguration;
|
||||||
import org.eclipse.jetty.server.HttpConnectionFactory;
|
import org.eclipse.jetty.server.HttpConnectionFactory;
|
||||||
import org.eclipse.jetty.server.ProxyConnectionFactory;
|
import org.eclipse.jetty.server.ProxyConnectionFactory;
|
||||||
|
@ -68,6 +71,8 @@ import org.eclipse.jetty.util.ssl.SslContextFactory;
|
||||||
import org.eclipse.jetty.util.thread.QueuedThreadPool;
|
import org.eclipse.jetty.util.thread.QueuedThreadPool;
|
||||||
import org.eclipse.jetty.webapp.WebAppContext;
|
import org.eclipse.jetty.webapp.WebAppContext;
|
||||||
|
|
||||||
|
import static java.lang.System.Logger.Level.INFO;
|
||||||
|
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
public class HTTPServerDocs
|
public class HTTPServerDocs
|
||||||
{
|
{
|
||||||
|
@ -104,6 +109,50 @@ public class HTTPServerDocs
|
||||||
// end::simple[]
|
// end::simple[]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void httpChannelListener() throws Exception
|
||||||
|
{
|
||||||
|
// tag::httpChannelListener[]
|
||||||
|
class TimingHttpChannelListener implements HttpChannel.Listener
|
||||||
|
{
|
||||||
|
private final ConcurrentMap<Request, Long> times = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onRequestBegin(Request request)
|
||||||
|
{
|
||||||
|
times.put(request, System.nanoTime());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onComplete(Request request)
|
||||||
|
{
|
||||||
|
long begin = times.remove(request);
|
||||||
|
long elapsed = System.nanoTime() - 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 configureConnector() throws Exception
|
public void configureConnector() throws Exception
|
||||||
{
|
{
|
||||||
// tag::configureConnector[]
|
// tag::configureConnector[]
|
||||||
|
|
Loading…
Reference in New Issue