Updated the documentation about HttpChannel events (they don't exist anymore replaced by `EventsHandler`).

Signed-off-by: Simone Bordet <simone.bordet@gmail.com>
This commit is contained in:
Simone Bordet 2023-08-24 11:38:18 +02:00
parent be11dfdbab
commit 0eb4f1b7e3
4 changed files with 126 additions and 42 deletions

View File

@ -25,4 +25,4 @@ This section lists the listeners available in the Jetty components, but the even
* xref:pg-arch-bean-listener[] * xref:pg-arch-bean-listener[]
* xref:pg-arch-io-connection-listener[] * xref:pg-arch-io-connection-listener[]
* xref:pg-server-http-channel-events[] * xref:pg-server-http-request-processing-events[]

View File

@ -266,6 +266,75 @@ For instance, `StatisticsHandler.MinimumDataRateHandler` can be used to enforce
include::../../{doc_code}/org/eclipse/jetty/docs/programming/server/http/HTTPServerDocs.java[tags=dataRateHandler] include::../../{doc_code}/org/eclipse/jetty/docs/programming/server/http/HTTPServerDocs.java[tags=dataRateHandler]
---- ----
[[pg-server-http-handler-use-events]]
====== EventsHandler
`EventsHandler` allows applications to be notified of xref:pg-server-http-request-processing-events[request processing] events.
`EventsHandler` must be subclassed, and the relevant `onXYZ()` methods overridden to capture the request processing events you are interested in.
The request processing events can be used in conjunction with `Request` APIs that provide the information you may be interested in.
For example, if you want to use `EventsHandler` to record processing times, you can use the request processing events with the following `Request` APIs:
* `Request.getBeginNanoTime()`, which returns the earliest possible nanoTime the request was received.
* `Request.getHeadersNanoTime()`, which returns the nanoTime at which the parsing of the HTTP headers was completed.
[CAUTION]
====
The `Request` and `Response` objects may be inspected during events, but it is recommended to avoid modifying them, for example by adding/removing headers or by reading/writing content, because any modification may interfere with the processing performed by other ``Handler``s.
====
`EventsHandler` emits the following events:
`beforeHandling`::
Emitted just before `EventsHandler` invokes the `Handler.handle(\...)` method of the next `Handler` in the `Handler` tree.
`afterHandling`::
Emitted just after the invocation to the `Handler.handle(\...)` method of the next `Handler` in the `Handler` tree returns, either normally or by throwing.
`requestRead`::
Emitted every time a chunk of content is read from the `Request`.
`responseBegin`::
Emitted when the response first write happens.
`responseWrite`::
Emitted every time the write of some response content is initiated.
`responseWriteComplete`::
Emitted every time the write of some response content is completed, either successfully or with a failure.
`responseTrailersComplete`::
Emitted when the write of the response trailers is completed.
`complete`::
Emitted when both request and the response have been completely processed.
Your `EventsHandler` subclass should then be linked in the `Handler` tree in the relevant position, typically as the outermost `Handler` after `Server`:
[source,java,indent=0]
----
include::../../{doc_code}/org/eclipse/jetty/docs/programming/server/http/HTTPServerDocs.java[tags=eventsHandler]
----
The `Handler` tree structure looks like the following:
[source,screen]
----
Server
└── MyEventsHandler
└── ContextHandler /app
----
You can link the `EventsHandler` at any point in the `Handler` tree structure, and even have multiple ``EventsHandler``s to be notified of the request processing events at the different stages of the `Handler` tree, for example:
[source,screen]
----
Server
└── TotalEventsHandler
└── SlowHandler
└── AppEventsHandler
└── ContextHandler /app
----
In the example above, `TotalEventsHandler` may record the total times of request processing, from `SlowHandler` all the way to the `ContextHandler`.
On the other hand, `AppEventsHandler` may record both the time it takes for the request to flow from `TotalEventsHandler` to `AppEventsHandler`, therefore effectively measuring the processing time due to `SlowHandler`, and the time it takes to process the request by the `ContextHandler`.
Refere to the `EventsHandler` link:{javadoc-url}/org/eclipse/jetty/server/handler/EventsHandler[javadocs] for further information.
[[pg-server-http-handler-use-limit]] [[pg-server-http-handler-use-limit]]
====== QoSHandler ====== QoSHandler
TODO TODO

View File

@ -16,7 +16,7 @@
Web application development typically involves writing your web applications, packaging them into a web application archive, the `+*.war+` file, and then deploy the `+*.war+` file into a standalone Servlet Container that you have previously installed. Web application development typically involves writing your web applications, packaging them into a web application archive, the `+*.war+` file, and then deploy the `+*.war+` file into a standalone Servlet Container that you have previously installed.
The Eclipse Jetty server libraries allow you to write web applications components using either the Jetty APIs (by writing xref:pg-server-http-handler[Jetty ``Handler``s]) or using the standard xref:pg-server-http-handler-use-servlet[Servlet APIs] (by writing ``Servlet``s and Servlet ``Filter``s). The Jetty server libraries allow you to write web applications components using either the Jetty APIs (by writing xref:pg-server-http-handler[Jetty ``Handler``s]) or using the standard xref:pg-server-http-handler-use-servlet[Servlet APIs] (by writing ``Servlet``s and Servlet ``Filter``s).
These components can then be programmatically assembled together, without the need of creating a `+*.war+` file, added to a Jetty ``Server`` instance that is then started. These components can then be programmatically assembled together, without the need of creating a `+*.war+` file, added to a Jetty ``Server`` instance that is then started.
This result in your web applications to be available to HTTP clients as if you deployed your `+*.war+` files in a standalone Jetty server. This result in your web applications to be available to HTTP clients as if you deployed your `+*.war+` files in a standalone Jetty server.
@ -90,6 +90,7 @@ participant ManagedSelector
participant EndPoint participant EndPoint
participant Connection participant Connection
participant Parser participant Parser
participant HttpStream
participant HttpChannel participant HttpChannel
participant Server participant Server
participant Handlers participant Handlers
@ -99,8 +100,8 @@ EndPoint -> Connection : onFillable()
Connection -> EndPoint : fill() Connection -> EndPoint : fill()
EndPoint --> Connection EndPoint --> Connection
Connection -> Parser : parse() Connection -> Parser : parse()
Parser -> HttpChannel : events Parser -> HttpStream : events
Connection -> HttpChannel : handle() Connection -> HttpChannel : onRequest()
HttpChannel -> Server : handle() HttpChannel -> Server : handle()
Server -> Handlers : handle() Server -> Handlers : handle()
---- ----
@ -110,48 +111,16 @@ This event is converted to a call to `AbstractConnection.onFillable()`, where th
The parser emit events that are protocol specific; the HTTP/2 parser, for example, emits events for each HTTP/2 frame that has been parsed, and similarly does the HTTP/3 parser. The parser emit events that are protocol specific; the HTTP/2 parser, for example, emits events for each HTTP/2 frame that has been parsed, and similarly does the HTTP/3 parser.
The parser events are then converted to protocol independent events such as _"request start"_, _"request headers"_, _"request content chunk"_, etc. 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 `HttpChannelState`.
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. When enough of the HTTP request is arrived, the `Connection` calls `HttpChannel.onRequest()` that calls the `Handler` chain starting from the `Server` instance, that eventually calls the server application code.
[[pg-server-http-channel-events]] [[pg-server-http-request-processing-events]]
===== HttpChannel Events ===== Request Processing Events
The central component processing HTTP requests is `HttpChannelState`. Advanced server applications may be interested in the progress of the processing of an HTTP request/response.
There is a 1-to-1 relationship between an HTTP request/response and an `HttpChannelState`, no matter what is the specific protocol that carries the HTTP request over the network (HTTP/1.1, HTTP/2, HTTP/3 or FastCGI). A typical case is to know exactly _when_ the HTTP request/response processing starts and when it is complete, for example to monitor processing times.
Advanced server applications may be interested in the progress of the processing of an HTTP request/response by `HttpChannelState`. This is conveniently implemented by `org.eclipse.jetty.server.handler.EventsHandler`, described in more details in xref:pg-server-http-handler-use-events[this section].
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.
`HttpChannelState` 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:{javadoc-url}/org/eclipse/jetty/server/HttpChannel.Listener.html[javadocs] for the complete list of events.
Server applications can register `HttpChannel.Listener` by adding them as xref:pg-arch-bean[beans] to the `Connector`:
[source,java,indent=0]
----
include::../../{doc_code}/org/eclipse/jetty/docs/programming/server/http/HTTPServerDocs.java[tags=httpChannelListener]
----
[[pg-server-http-request-logging]] [[pg-server-http-request-logging]]
==== Request Logging ==== Request Logging

View File

@ -63,17 +63,21 @@ import org.eclipse.jetty.server.SslConnectionFactory;
import org.eclipse.jetty.server.handler.ContextHandler; import org.eclipse.jetty.server.handler.ContextHandler;
import org.eclipse.jetty.server.handler.ContextHandlerCollection; import org.eclipse.jetty.server.handler.ContextHandlerCollection;
import org.eclipse.jetty.server.handler.DefaultHandler; import org.eclipse.jetty.server.handler.DefaultHandler;
import org.eclipse.jetty.server.handler.EventsHandler;
import org.eclipse.jetty.server.handler.ResourceHandler; import org.eclipse.jetty.server.handler.ResourceHandler;
import org.eclipse.jetty.server.handler.SecuredRedirectHandler; import org.eclipse.jetty.server.handler.SecuredRedirectHandler;
import org.eclipse.jetty.server.handler.StatisticsHandler; import org.eclipse.jetty.server.handler.StatisticsHandler;
import org.eclipse.jetty.server.handler.gzip.GzipHandler; import org.eclipse.jetty.server.handler.gzip.GzipHandler;
import org.eclipse.jetty.unixdomain.server.UnixDomainServerConnector; import org.eclipse.jetty.unixdomain.server.UnixDomainServerConnector;
import org.eclipse.jetty.util.Callback; import org.eclipse.jetty.util.Callback;
import org.eclipse.jetty.util.NanoTime;
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;
import org.eclipse.jetty.util.ssl.SslContextFactory; import org.eclipse.jetty.util.ssl.SslContextFactory;
import org.eclipse.jetty.util.thread.QueuedThreadPool; import org.eclipse.jetty.util.thread.QueuedThreadPool;
import static java.lang.System.Logger.Level.INFO;
@SuppressWarnings("unused") @SuppressWarnings("unused")
public class HTTPServerDocs public class HTTPServerDocs
{ {
@ -910,6 +914,48 @@ public class HTTPServerDocs
// end::dataRateHandler[] // end::dataRateHandler[]
} }
public void eventsHandler() throws Exception
{
// tag::eventsHandler[]
class MyEventsHandler extends EventsHandler
{
@Override
protected void onBeforeHandling(Request request)
{
// The nanoTime at which the request is first received.
long requestBeginNanoTime = request.getBeginNanoTime();
// The nanoTime just before invoking the next Handler.
request.setAttribute("beforeHandlingNanoTime", NanoTime.now());
}
@Override
protected void onComplete(Request request, Throwable failure)
{
// Retrieve the before handling nanoTime.
long beforeHandlingNanoTime = (long)request.getAttribute("beforeHandlingNanoTime");
// Record the request processing time.
long processingTime = NanoTime.millisSince(beforeHandlingNanoTime);
System.getLogger("trackTime").log(INFO, "processing request %s took %d ms", request, processingTime);
}
}
Server server = new Server();
ServerConnector connector = new ServerConnector(server);
server.addConnector(connector);
// Link the EventsHandler as the outermost Handler after Server.
MyEventsHandler eventsHandler = new MyEventsHandler();
server.setHandler(eventsHandler);
ContextHandler appHandler = new ContextHandler("/app");
eventsHandler.setHandler(appHandler);
server.start();
// end::eventsHandler[]
}
public void securedHandler() throws Exception public void securedHandler() throws Exception
{ {
// tag::securedHandler[] // tag::securedHandler[]