From 0eb4f1b7e334909930fb154e2d3cfa1929dd4939 Mon Sep 17 00:00:00 2001 From: Simone Bordet Date: Thu, 24 Aug 2023 11:38:18 +0200 Subject: [PATCH] Updated the documentation about HttpChannel events (they don't exist anymore replaced by `EventsHandler`). Signed-off-by: Simone Bordet --- .../programming-guide/arch-listener.adoc | 2 +- .../server/http/server-http-handler-use.adoc | 69 +++++++++++++++++++ .../server/http/server-http.adoc | 51 +++----------- .../server/http/HTTPServerDocs.java | 46 +++++++++++++ 4 files changed, 126 insertions(+), 42 deletions(-) diff --git a/documentation/jetty-documentation/src/main/asciidoc/programming-guide/arch-listener.adoc b/documentation/jetty-documentation/src/main/asciidoc/programming-guide/arch-listener.adoc index a6dbe5596fa..ff54554bf14 100644 --- a/documentation/jetty-documentation/src/main/asciidoc/programming-guide/arch-listener.adoc +++ b/documentation/jetty-documentation/src/main/asciidoc/programming-guide/arch-listener.adoc @@ -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-io-connection-listener[] -* xref:pg-server-http-channel-events[] +* xref:pg-server-http-request-processing-events[] diff --git a/documentation/jetty-documentation/src/main/asciidoc/programming-guide/server/http/server-http-handler-use.adoc b/documentation/jetty-documentation/src/main/asciidoc/programming-guide/server/http/server-http-handler-use.adoc index f972c5ccfaf..36acd0ee0d6 100644 --- a/documentation/jetty-documentation/src/main/asciidoc/programming-guide/server/http/server-http-handler-use.adoc +++ b/documentation/jetty-documentation/src/main/asciidoc/programming-guide/server/http/server-http-handler-use.adoc @@ -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] ---- +[[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]] ====== QoSHandler TODO diff --git a/documentation/jetty-documentation/src/main/asciidoc/programming-guide/server/http/server-http.adoc b/documentation/jetty-documentation/src/main/asciidoc/programming-guide/server/http/server-http.adoc index 7cc0cbfacaa..9773da7da34 100644 --- a/documentation/jetty-documentation/src/main/asciidoc/programming-guide/server/http/server-http.adoc +++ b/documentation/jetty-documentation/src/main/asciidoc/programming-guide/server/http/server-http.adoc @@ -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. -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. 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 Connection participant Parser +participant HttpStream participant HttpChannel participant Server participant Handlers @@ -99,8 +100,8 @@ EndPoint -> Connection : onFillable() Connection -> EndPoint : fill() EndPoint --> Connection Connection -> Parser : parse() -Parser -> HttpChannel : events -Connection -> HttpChannel : handle() +Parser -> HttpStream : events +Connection -> HttpChannel : onRequest() HttpChannel -> Server : 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 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]] -===== HttpChannel Events +[[pg-server-http-request-processing-events]] +===== Request Processing Events -The central component processing HTTP requests is `HttpChannelState`. -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). +Advanced server applications may be interested in the progress of the processing of an HTTP request/response. +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`. -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] ----- +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]. [[pg-server-http-request-logging]] ==== Request Logging diff --git a/documentation/jetty-documentation/src/main/java/org/eclipse/jetty/docs/programming/server/http/HTTPServerDocs.java b/documentation/jetty-documentation/src/main/java/org/eclipse/jetty/docs/programming/server/http/HTTPServerDocs.java index 24b6193a19a..96fca3a7585 100644 --- a/documentation/jetty-documentation/src/main/java/org/eclipse/jetty/docs/programming/server/http/HTTPServerDocs.java +++ b/documentation/jetty-documentation/src/main/java/org/eclipse/jetty/docs/programming/server/http/HTTPServerDocs.java @@ -63,17 +63,21 @@ import org.eclipse.jetty.server.SslConnectionFactory; import org.eclipse.jetty.server.handler.ContextHandler; import org.eclipse.jetty.server.handler.ContextHandlerCollection; 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.SecuredRedirectHandler; import org.eclipse.jetty.server.handler.StatisticsHandler; import org.eclipse.jetty.server.handler.gzip.GzipHandler; import org.eclipse.jetty.unixdomain.server.UnixDomainServerConnector; 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.ResourceFactory; import org.eclipse.jetty.util.ssl.SslContextFactory; import org.eclipse.jetty.util.thread.QueuedThreadPool; +import static java.lang.System.Logger.Level.INFO; + @SuppressWarnings("unused") public class HTTPServerDocs { @@ -910,6 +914,48 @@ public class HTTPServerDocs // 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 { // tag::securedHandler[]