Improvements to the Jetty server documentation.

Using one-line-per-sentence.

Signed-off-by: Simone Bordet <simone.bordet@gmail.com>
This commit is contained in:
Simone Bordet 2020-04-17 16:16:53 +02:00
parent d681f10853
commit bea09425c8
20 changed files with 455 additions and 1186 deletions

View File

@ -19,44 +19,32 @@
[[eg-client-io-arch]] [[eg-client-io-arch]]
=== Client Libraries I/O Architecture === Client Libraries I/O Architecture
The Jetty client libraries provide the basic components and APIs to implement The Jetty client libraries provide the basic components and APIs to implement a network client.
a network client.
They build on the common xref:eg-io-arch[Jetty I/O Architecture] and provide client They build on the common xref:eg-io-arch[Jetty I/O Architecture] and provide client specific concepts (such as establishing a connection to a server).
specific concepts (such as establishing a connection to a server).
There are conceptually two layers that compose the Jetty client libraries: There are conceptually two layers that compose the Jetty client libraries:
. xref:eg-client-io-arch-network[The network layer], that handles the low level . xref:eg-client-io-arch-network[The network layer], that handles the low level I/O and deals with buffers, threads, etc.
I/O and deals with buffers, threads, etc. . xref:eg-client-io-arch-protocol[The protocol layer], that handles the parsing of bytes read from the network and the generation of bytes to write to the network.
. xref:eg-client-io-arch-protocol[The protocol layer], that handles the parsing
of bytes read from the network and the generation of bytes to write to the
network.
[[eg-client-io-arch-network]] [[eg-client-io-arch-network]]
==== Client Libraries Network Layer ==== Client Libraries Network Layer
The Jetty client libraries use the common I/O design described in The Jetty client libraries use the common I/O design described in link:#eg-io-arch[this section].
link:#eg-io-arch[this section]. The main client-side component is the link:{JDURL}/org/eclipse/jetty/io/ClientConnector.html[`ClientConnector`].
The main client-side component is the
link:{JDURL}/org/eclipse/jetty/io/ClientConnector.html[`ClientConnector`].
The `ClientConnector` primarily wraps the The `ClientConnector` primarily wraps the link:{JDURL}/org/eclipse/jetty/io/SelectorManager.html[`SelectorManager`] and aggregates other four components:
link:{JDURL}/org/eclipse/jetty/io/SelectorManager.html[`SelectorManager`]
and aggregates other four components:
* a thread pool (in form of an `java.util.concurrent.Executor`) * a thread pool (in form of an `java.util.concurrent.Executor`)
* a scheduler (in form of `org.eclipse.jetty.util.thread.Scheduler`) * a scheduler (in form of `org.eclipse.jetty.util.thread.Scheduler`)
* a byte buffer pool (in form of `org.eclipse.jetty.io.ByteBufferPool`) * a byte buffer pool (in form of `org.eclipse.jetty.io.ByteBufferPool`)
* a TLS factory (in form of `org.eclipse.jetty.util.ssl.SslContextFactory.Client`) * a TLS factory (in form of `org.eclipse.jetty.util.ssl.SslContextFactory.Client`)
The `ClientConnector` is where you want to set those components after you The `ClientConnector` is where you want to set those components after you have configured them.
have configured them. If you don't explicitly set those components on the `ClientConnector`, then appropriate defaults will be chosen when the `ClientConnector` starts.
If you don't explicitly set those components on the `ClientConnector`, then
appropriate defaults will be chosen when the `ClientConnector` starts.
The simplest example that creates and starts a `ClientConnector` is the The simplest example that creates and starts a `ClientConnector` is the following:
following:
[source,java,indent=0] [source,java,indent=0]
---- ----
@ -70,119 +58,72 @@ A more typical example:
include::../{doc_code}/embedded/client/ClientConnectorDocs.java[tags=typical] include::../{doc_code}/embedded/client/ClientConnectorDocs.java[tags=typical]
---- ----
A more advanced example that customizes the `ClientConnector` by overriding A more advanced example that customizes the `ClientConnector` by overriding some of its methods:
some of its methods:
[source,java,indent=0] [source,java,indent=0]
---- ----
include::../{doc_code}/embedded/client/ClientConnectorDocs.java[tags=advanced] include::../{doc_code}/embedded/client/ClientConnectorDocs.java[tags=advanced]
---- ----
Since `ClientConnector` is the component that handles the low-level network, it Since `ClientConnector` is the component that handles the low-level network, it is also the component where you want to configure the low-level network configuration.
is also the component where you want to configure the low-level network configuration.
The most common parameters are: The most common parameters are:
* `ClientConnector.selectors`: the number of ``java.nio.Selector``s components * `ClientConnector.selectors`: the number of ``java.nio.Selector``s components (defaults to `1`) that are present to handle the ``SocketChannel``s opened by the `ClientConnector`.
(defaults to `1`) that are present to handle the ``SocketChannel``s opened by You typically want to increase the number of selectors only for those use cases where each selector should handle more than few hundreds _concurrent_ socket events.
the `ClientConnector`. You typically want to increase the number of selectors For example, one selector typically runs well for `250` _concurrent_ socket events; as a rule of thumb, you can multiply that number by `10` to obtain the number of opened sockets a selector can handle (`2500`), based on the assumption that not all the `2500` sockets will be active _at the same time_.
only for those use cases where each selector should handle more than few hundreds * `ClientConnector.idleTimeout`: the duration of time after which `ClientConnector` closes a socket due to inactivity (defaults to `30` seconds).
_concurrent_ socket events. This is an important parameter to configure, and you typically want the client idle timeout to be shorter than the server idle timeout, to avoid race conditions where the client attempts to use a socket just before the client-side idle timeout expires, but the server-side idle timeout has already expired and the is already closing the socket.
For example, one selector typically runs well for `250` _concurrent_ socket * `ClientConnector.connectBlocking`: whether the operation of connecting a socket to the server (i.e. `SocketChannel.connect(SocketAddress)`) must be a blocking or a non-blocking operation (defaults to `false`).
events; as a rule of thumb, you can multiply that number by `10` to obtain the
number of opened sockets a selector can handle (`2500`), based on the assumption
that not all the `2500` sockets will be active _at the same time_.
* `ClientConnector.idleTimeout`: the duration of time after which
`ClientConnector` closes a socket due to inactivity (defaults to `30` seconds).
This is an important parameter to configure, and you typically want the client
idle timeout to be shorter than the server idle timeout, to avoid race
conditions where the client attempts to use a socket just before the client-side
idle timeout expires, but the server-side idle timeout has already expired and
the is already closing the socket.
* `ClientConnector.connectBlocking`: whether the operation of connecting a
socket to the server (i.e. `SocketChannel.connect(SocketAddress)`) must be a
blocking or a non-blocking operation (defaults to `false`).
For `localhost` or same datacenter hosts you want to set this parameter to For `localhost` or same datacenter hosts you want to set this parameter to
`true` because DNS resolution will be immediate (and likely never fail). `true` because DNS resolution will be immediate (and likely never fail).
For generic Internet hosts (e.g. when you are implementing a web spider) you For generic Internet hosts (e.g. when you are implementing a web spider) you want to set this parameter to `false`.
want to set this parameter to `false`. * `ClientConnector.connectTimeout`: the duration of time after which `ClientConnector` aborts a connection attempt to the server (defaults to `5` seconds).
* `ClientConnector.connectTimeout`: the duration of time after which
`ClientConnector` aborts a connection attempt to the server (defaults to `5`
seconds).
This time includes the DNS lookup time _and_ the TCP connect time. This time includes the DNS lookup time _and_ the TCP connect time.
Please refer to the `ClientConnector` Please refer to the `ClientConnector` link:{JDURL}/org/eclipse/jetty/io/ClientConnector.html[javadocs] for the complete list of configurable parameters.
link:{JDURL}/org/eclipse/jetty/io/ClientConnector.html[javadocs]
for the complete list of configurable parameters.
[[eg-client-io-arch-protocol]] [[eg-client-io-arch-protocol]]
==== Client Libraries Protocol Layer ==== Client Libraries Protocol Layer
The protocol layer builds on top of the network layer to generate the The protocol layer builds on top of the network layer to generate the bytes to be written to the network and to parse the bytes read from the network.
bytes to be written to the network and to parse the bytes read from the
network.
Recall from link:#eg-io-arch-connection[this section] that Jetty uses the Recall from link:#eg-io-arch-connection[this section] that Jetty uses the `Connection` abstraction to produce and interpret the network bytes.
`Connection` abstraction to produce and interpret the network bytes.
On the client side, a `ClientConnectionFactory` implementation is the On the client side, a `ClientConnectionFactory` implementation is the component that creates `Connection` instances based on the protocol that the client wants to "speak" with the server.
component that creates `Connection` instances based on the protocol that
the client wants to "speak" with the server.
Applications use `ClientConnector.connect(SocketAddress, Map<String, Object>)` Applications use `ClientConnector.connect(SocketAddress, Map<String, Object>)` to establish a TCP connection to the server, and must tell `ClientConnector` how to create the `Connection` for that particular TCP connection, and how to notify back the application when the connection creation succeeds or fails.
to establish a TCP connection to the server, and must tell
`ClientConnector` how to create the `Connection` for that particular
TCP connection, and how to notify back the application when the connection
creation succeeds or fails.
This is done by passing a This is done by passing a link:{JDURL}/org/eclipse/jetty/io/ClientConnectionFactory.html[`ClientConnectionFactory`] (that creates `Connection` instances) and a link:{JDURL}/org/eclipse/jetty/util/Promise.html[`Promise`] (that is notified of connection creation success or failure) in the context `Map` as follows:
link:{JDURL}/org/eclipse/jetty/io/ClientConnectionFactory.html[`ClientConnectionFactory`]
(that creates `Connection` instances) and a
link:{JDURL}/org/eclipse/jetty/util/Promise.html[`Promise`] (that is notified
of connection creation success or failure) in the context `Map` as follows:
[source,java,indent=0] [source,java,indent=0]
---- ----
include::../{doc_code}/embedded/client/ClientConnectorDocs.java[tags=connect] include::../{doc_code}/embedded/client/ClientConnectorDocs.java[tags=connect]
---- ----
When a `Connection` is created successfully, its `onOpen()` method is invoked, When a `Connection` is created successfully, its `onOpen()` method is invoked, and then the promise is completed successfully.
and then the promise is completed successfully.
It is now possible to write a super-simple `telnet` client that reads and writes It is now possible to write a super-simple `telnet` client that reads and writes string lines:
string lines:
[source,java,indent=0] [source,java,indent=0]
---- ----
include::../{doc_code}/embedded/client/ClientConnectorDocs.java[tags=telnet] include::../{doc_code}/embedded/client/ClientConnectorDocs.java[tags=telnet]
---- ----
Note how a very basic "telnet" API that applications could use is implemented Note how a very basic "telnet" API that applications could use is implemented in the form of the `onLine(Consumer<String>)` for the non-blocking receiving side and `writeLine(String, Callback)` for the non-blocking sending side.
in the form of the `onLine(Consumer<String>)` for the non-blocking receiving Note also how the `onFillable()` method implements some basic "parsing" by looking up the `\n` character in the buffer.
side and `writeLine(String, Callback)` for the non-blocking sending side.
Note also how the `onFillable()` method implements some basic "parsing"
by looking up the `\n` character in the buffer.
NOTE: The "telnet" client above looks like a super-simple HTTP client because NOTE: The "telnet" client above looks like a super-simple HTTP client because HTTP/1.0 can be seen as a line-based protocol.
HTTP/1.0 can be seen as a line-based protocol. HTTP/1.0 was used just as an HTTP/1.0 was used just as an example, but we could have used any other line-based protocol such as link:https://en.wikipedia.org/wiki/Simple_Mail_Transfer_Protocol[SMTP], provided that the server was able to understand it.
example, but we could have used any other line-based protocol such as
link:https://en.wikipedia.org/wiki/Simple_Mail_Transfer_Protocol[SMTP],
provided that the server was able to understand it.
This is very similar to what the Jetty client implementation does for real This is very similar to what the Jetty client implementation does for real network protocols.
network protocols. Real network protocols are of course more complicated and so is the implementation code that handles them, but the general ideas are similar.
Real network protocols are of course more complicated and so is the implementation
code that handles them, but the general ideas are similar.
The Jetty client implementation provides a number of `ClientConnectionFactory` The Jetty client implementation provides a number of `ClientConnectionFactory` implementations that can be composed to produce and interpret the network bytes.
implementations that can be composed to produce and interpret the network bytes.
For example, it is simple to modify the above example to use the TLS protocol For example, it is simple to modify the above example to use the TLS protocol so that you will be able to connect to the server on port `443`, typically reserved for the encrypted HTTP protocol.
so that you will be able to connect to the server on port `443`, typically
reserved for the encrypted HTTP protocol.
The differences between the clear-text version and the TLS encrypted version The differences between the clear-text version and the TLS encrypted version are minimal:
are minimal:
[source,java,indent=0] [source,java,indent=0]
---- ----

View File

@ -19,18 +19,11 @@
[[eg-client]] [[eg-client]]
== Client Libraries == Client Libraries
The Eclipse Jetty Project provides also provides client-side libraries The Eclipse Jetty Project provides also provides client-side libraries that allow you to embed a client in your applications.
that allow you to embed a client in your applications. A typical example is a client application that needs to contact a third party service via HTTP (for example a REST service).
A typical example is a client application that needs to contact a third party Another example is a proxy application that receives HTTP requests and forwards them as FCGI requests to a PHP application such as WordPress, or receives HTTP/1.1 requests and converts them to HTTP/2. Yet another example is a client application that needs to received events from a WebSocket server.
service via HTTP (for example a REST service).
Another example is a proxy application that receives HTTP requests and
forwards them as FCGI requests to a PHP application such as WordPress,
or receives HTTP/1.1 requests and converts them to HTTP/2.
Yet another example is a client application that needs to received events
from a WebSocket server.
The client libraries are designed to be non-blocking and offer both synchronous The client libraries are designed to be non-blocking and offer both synchronous and asynchronous APIs and come with a large number of configuration options.
and asynchronous APIs and come with a large number of configuration options.
These are the available client libraries: These are the available client libraries:
@ -38,9 +31,7 @@ These are the available client libraries:
* xref:eg-client-http2[The HTTP/2 Client Library] * xref:eg-client-http2[The HTTP/2 Client Library]
* xref:eg-client-websocket[The WebSocket client library] * xref:eg-client-websocket[The WebSocket client library]
If you are interested in the low-level details of how the Eclipse Jetty If you are interested in the low-level details of how the Eclipse Jetty client libraries work, or are interested in writing a custom protocol, look at the xref:eg-client-io-arch[Client I/O Architecture].
client libraries work, or are interested in writing a custom protocol,
look at the xref:eg-client-io-arch[Client I/O Architecture].
include::http/client-http.adoc[] include::http/client-http.adoc[]
include::http2/client-http2.adoc[] include::http2/client-http2.adoc[]

View File

@ -182,8 +182,7 @@ While the request content is awaited and consequently uploaded by the client app
In this case, `Response.Listener` callbacks will be invoked before the request is fully sent. In this case, `Response.Listener` callbacks will be invoked before the request is fully sent.
This allows fine-grained control of the request/response conversation: for example the server may reject contents that are too big, send a response to the client, which in turn may stop the content upload. This allows fine-grained control of the request/response conversation: for example the server may reject contents that are too big, send a response to the client, which in turn may stop the content upload.
Another way to provide request content is by using an `OutputStreamRequestContent`, Another way to provide request content is by using an `OutputStreamRequestContent`, which allows applications to write request content when it is available to the `OutputStream` provided by `OutputStreamRequestContent`:
which allows applications to write request content when it is available to the `OutputStream` provided by `OutputStreamRequestContent`:
[source,java,indent=0] [source,java,indent=0]
---- ----
@ -222,74 +221,42 @@ include::../../{doc_code}/embedded/client/http/HTTPClientDocs.java[tags=inputStr
Finally, let's look at the advanced usage of the response content handling. Finally, let's look at the advanced usage of the response content handling.
The response content is provided by the `HttpClient` implementation to application The response content is provided by the `HttpClient` implementation to application listeners following a reactive model similar to that of `java.util.concurrent.Flow`.
listeners following a reactive model similar to that of `java.util.concurrent.Flow`.
The listener that follows this model is `Response.DemandedContentListener`. The listener that follows this model is `Response.DemandedContentListener`.
After the response headers have been processed by the `HttpClient` implementation, After the response headers have been processed by the `HttpClient` implementation, `Response.DemandedContentListener.onBeforeContent(response, demand)` is invoked.
`Response.DemandedContentListener.onBeforeContent(response, demand)` is This allows the application to control whether to demand the first content or not.
invoked. This allows the application to control whether to demand the first The default implementation of this method calls `demand.accept(1)`, which demands one chunk of content to the implementation.
content or not. The default implementation of this method calls `demand.accept(1)`,
which demands one chunk of content to the implementation.
The implementation will deliver the chunk of content as soon as it is available. The implementation will deliver the chunk of content as soon as it is available.
The chunks of content are delivered to the application by invoking The chunks of content are delivered to the application by invoking `Response.DemandedContentListener.onContent(response, demand, buffer, callback)`.
`Response.DemandedContentListener.onContent(response, demand, buffer, callback)`.
Applications implement this method to process the content bytes in the `buffer`. Applications implement this method to process the content bytes in the `buffer`.
Succeeding the `callback` signals to the implementation that the application Succeeding the `callback` signals to the implementation that the application has consumed the `buffer` so that the implementation can dispose/recycle the `buffer`.
has consumed the `buffer` so that the implementation can dispose/recycle the Failing the `callback` signals to the implementation to fail the response (no more content will be delivered, and the _response failed_ event will be emitted).
`buffer`. Failing the `callback` signals to the implementation to fail the
response (no more content will be delivered, and the _response failed_ event
will be emitted).
IMPORTANT: Succeeding the `callback` must be done only after the `buffer` IMPORTANT: Succeeding the `callback` must be done only after the `buffer` bytes have been consumed.
bytes have been consumed. When the `callback` is succeeded, the `HttpClient` When the `callback` is succeeded, the `HttpClient` implementation may reuse the `buffer` and overwrite the bytes with different bytes; if the application looks at the `buffer` _after_ having succeeded the `callback` is may see other, unrelated, bytes.
implementation may reuse the `buffer` and overwrite the bytes with different
bytes; if the application looks at the `buffer` _after_ having succeeded
the `callback` is may see other, unrelated, bytes.
The application uses the `demand` object to demand more content chunks. The application uses the `demand` object to demand more content chunks.
Applications will typically demand for just one more content via Applications will typically demand for just one more content via `demand.accept(1)`, but may decide to demand for more via `demand.accept(2)` or demand "infinitely" once via `demand.accept(Long.MAX_VALUE)`.
`demand.accept(1)`, but may decide to demand for more via `demand.accept(2)` Applications that demand for more than 1 chunk of content must be prepared to receive all the content that they have demanded.
or demand "infinitely" once via `demand.accept(Long.MAX_VALUE)`.
Applications that demand for more than 1 chunk of content must be prepared
to receive all the content that they have demanded.
Demanding for content and consuming the content are orthogonal activities. Demanding for content and consuming the content are orthogonal activities.
An application can demand "infinitely" and store aside the pairs An application can demand "infinitely" and store aside the pairs `(buffer, callback)` to consume them later.
`(buffer, callback)` to consume them later. If not done carefully, this may lead to excessive memory consumption, since the ``buffer``s are not consumed.
If not done carefully, this may lead to excessive memory consumption, since Succeeding the ``callback``s will result in the ``buffer``s to be disposed/recycled and may be performed at any time.
the ``buffer``s are not consumed.
Succeeding the ``callback``s will result in the ``buffer``s to be
disposed/recycled and may be performed at any time.
An application can also demand one chunk of content, consume it (by An application can also demand one chunk of content, consume it (by succeeding the associated `callback`) and then _not_ demand for more content until a later time.
succeeding the associated `callback`) and then _not_ demand for more content
until a later time.
Subclass `Response.AsyncContentListener` overrides the behavior of Subclass `Response.AsyncContentListener` overrides the behavior of `Response.DemandedContentListener`; when an application implementing its `onContent(response, buffer, callback)` succeeds the `callback`, it will have _both_ the effect of disposing/recycling the `buffer` _and_ the effect of demanding one more chunk of content.
`Response.DemandedContentListener`; when an application implementing its
`onContent(response, buffer, callback)` succeeds the `callback`, it
will have _both_ the effect of disposing/recycling the `buffer` _and_ the
effect of demanding one more chunk of content.
Subclass `Response.ContentListener` overrides the behavior of Subclass `Response.ContentListener` overrides the behavior of `Response.AsyncContentListener`; when an application implementing its `onContent(response, buffer)` returns from the method itself, it will _both_ the effect of disposing/recycling the `buffer` _and_ the effect of demanding one more chunk of content.
`Response.AsyncContentListener`; when an application implementing its
`onContent(response, buffer)` returns from the method itself, it will
_both_ the effect of disposing/recycling the `buffer` _and_ the effect
of demanding one more chunk of content.
Previous examples of response content handling were inefficient because they Previous examples of response content handling were inefficient because they involved copying the `buffer` bytes, either to accumulate them aside so that the application could use them when the request was completed, or because they were provided to an API such as `InputStream` that made use of `byte[]` (and therefore a copy from `ByteBuffer` to `byte[]` is necessary).
involved copying the `buffer` bytes, either to accumulate them aside so that
the application could use them when the request was completed, or because
they were provided to an API such as `InputStream` that made use of `byte[]`
(and therefore a copy from `ByteBuffer` to `byte[]` is necessary).
An application that implements a forwarder between two servers can be An application that implements a forwarder between two servers can be implemented efficiently by handling the response content without copying the `buffer` bytes as in the following example:
implemented efficiently by handling the response content without copying
the `buffer` bytes as in the following example:
[source,java,indent=0] [source,java,indent=0]
---- ----

View File

@ -19,13 +19,9 @@
[[eg-client-http-authentication]] [[eg-client-http-authentication]]
=== HttpClient Authentication Support === HttpClient Authentication Support
Jetty's `HttpClient` supports the `BASIC` and `DIGEST` authentication Jetty's `HttpClient` supports the `BASIC` and `DIGEST` authentication mechanisms defined by link:https://tools.ietf.org/html/rfc7235[RFC 7235], as well as the SPNEGO authentication mechanism defined in link:https://tools.ietf.org/html/rfc4559[RFC 4559].
mechanisms defined by link:https://tools.ietf.org/html/rfc7235[RFC 7235],
as well as the SPNEGO authentication mechanism defined in
link:https://tools.ietf.org/html/rfc4559[RFC 4559].
The HTTP _conversation_ - the sequence of related HTTP requests - for a The HTTP _conversation_ - the sequence of related HTTP requests - for a request that needs authentication is the following:
request that needs authentication is the following:
[plantuml] [plantuml]
---- ----
@ -43,59 +39,43 @@ HttpClient -> Server : GET + Authentication
Server -> Application : 200 OK Server -> Application : 200 OK
---- ----
Upon receiving a HTTP 401 response code, `HttpClient` looks at the Upon receiving a HTTP 401 response code, `HttpClient` looks at the `WWW-Authenticate` response header (the server _challenge_) and then tries to match configured authentication credentials to produce an `Authentication` header that contains the authentication credentials to access the resource.
`WWW-Authenticate` response header (the server _challenge_) and then tries to
match configured authentication credentials to produce an `Authentication`
header that contains the authentication credentials to access the resource.
You can configure authentication credentials in the `HttpClient` instance as You can configure authentication credentials in the `HttpClient` instance as follows:
follows:
[source,java,indent=0] [source,java,indent=0]
---- ----
include::../../{doc_code}/embedded/client/http/HTTPClientDocs.java[tag=addAuthentication] include::../../{doc_code}/embedded/client/http/HTTPClientDocs.java[tag=addAuthentication]
---- ----
``Authentication``s are matched against the server challenge first by ``Authentication``s are matched against the server challenge first by mechanism (e.g. `BASIC` or `DIGEST`), then by realm and then by URI.
mechanism (e.g. `BASIC` or `DIGEST`), then by realm and then by URI.
If an `Authentication` match is found, the application does not receive events If an `Authentication` match is found, the application does not receive events related to the HTTP 401 response.
related to the HTTP 401 response. These events are handled internally by These events are handled internally by `HttpClient` which produces another (internal) request similar to the original request but with an additional `Authorization` header.
`HttpClient` which produces another (internal) request similar to the original
request but with an additional `Authorization` header.
If the authentication is successful, the server responds with a HTTP 200 and If the authentication is successful, the server responds with a HTTP 200 and `HttpClient` caches the `Authentication.Result` so that subsequent requests for a matching URI will not incur in the additional rountrip caused by the HTTP 401 response.
`HttpClient` caches the `Authentication.Result` so that subsequent requests
for a matching URI will not incur in the additional rountrip caused by the
HTTP 401 response.
It is possible to clear ``Authentication.Result``s in order to force It is possible to clear ``Authentication.Result``s in order to force authentication again:
authentication again:
[source,java,indent=0] [source,java,indent=0]
---- ----
include::../../{doc_code}/embedded/client/http/HTTPClientDocs.java[tag=clearResults] include::../../{doc_code}/embedded/client/http/HTTPClientDocs.java[tag=clearResults]
---- ----
Authentication results may be preempted to avoid the additional roundtrip Authentication results may be preempted to avoid the additional roundtrip due to the server challenge in this way:
due to the server challenge in this way:
[source,java,indent=0] [source,java,indent=0]
---- ----
include::../../{doc_code}/embedded/client/http/HTTPClientDocs.java[tag=preemptedResult] include::../../{doc_code}/embedded/client/http/HTTPClientDocs.java[tag=preemptedResult]
---- ----
In this way, requests for the given URI are enriched immediately with the In this way, requests for the given URI are enriched immediately with the `Authorization` header, and the server should respond with HTTP 200 (and the resource content) rather than with the 401 and the challenge.
`Authorization` header, and the server should respond with HTTP 200 (and the
resource content) rather than with the 401 and the challenge.
It is also possible to preempt the authentication for a single request only, It is also possible to preempt the authentication for a single request only, in this way:
in this way:
[source,java,indent=0] [source,java,indent=0]
---- ----
include::../../{doc_code}/embedded/client/http/HTTPClientDocs.java[tag=requestPreemptedResult] include::../../{doc_code}/embedded/client/http/HTTPClientDocs.java[tag=requestPreemptedResult]
---- ----
See also the xref:eg-client-http-proxy-authentication[proxy authentication section] See also the xref:eg-client-http-proxy-authentication[proxy authentication section] for further information about how authentication works with HTTP proxies.
for further information about how authentication works with HTTP proxies.

View File

@ -20,54 +20,39 @@
=== HttpClient Configuration === HttpClient Configuration
`HttpClient` has a quite large number of configuration parameters. `HttpClient` has a quite large number of configuration parameters.
Please refer to the `HttpClient` Please refer to the `HttpClient` link:{JDURL}/org/eclipse/jetty/client/HttpClient.html[javadocs] for the complete list of configurable parameters.
link:{JDURL}/org/eclipse/jetty/client/HttpClient.html[javadocs]
for the complete list of configurable parameters.
The most common parameters are: The most common parameters are:
* `HttpClient.idleTimeout`: same as `ClientConnector.idleTimeout` * `HttpClient.idleTimeout`: same as `ClientConnector.idleTimeout` described in xref:eg-client-io-arch-network[this section].
described in xref:eg-client-io-arch-network[this section]. * `HttpClient.connectBlocking`: same as `ClientConnector.connectBlocking` described in xref:eg-client-io-arch-network[this section].
* `HttpClient.connectBlocking`: same as `ClientConnector.connectBlocking` * `HttpClient.connectTimeout`: same as `ClientConnector.connectTimeout` described in xref:eg-client-io-arch-network[this section].
described in xref:eg-client-io-arch-network[this section]. * `HttpClient.maxConnectionsPerDestination`: the max number of TCP connections that are opened for a particular destination (defaults to 64).
* `HttpClient.connectTimeout`: same as `ClientConnector.connectTimeout` * `HttpClient.maxRequestsQueuedPerDestination`: the max number of requests queued (defaults to 1024).
described in xref:eg-client-io-arch-network[this section].
* `HttpClient.maxConnectionsPerDestination`: the max number of TCP
connections that are opened for a particular destination (defaults to 64).
* `HttpClient.maxRequestsQueuedPerDestination`: the max number of requests
queued (defaults to 1024).
[[eg-client-http-configuration-tls]] [[eg-client-http-configuration-tls]]
==== HttpClient TLS Configuration ==== HttpClient TLS Configuration
`HttpClient` supports HTTPS requests out-of-the-box like a browser does. `HttpClient` supports HTTPS requests out-of-the-box like a browser does.
The support for HTTPS request is provided by a `SslContextFactory.Client`, The support for HTTPS request is provided by a `SslContextFactory.Client`, typically configured in the `ClientConnector`.
typically configured in the `ClientConnector`. If not explicitly configured, the `ClientConnector` will allocate a default one when started.
If not explicitly configured, the `ClientConnector` will allocate a default
one when started.
[source,java,indent=0] [source,java,indent=0]
---- ----
include::../../{doc_code}/embedded/client/http/HTTPClientDocs.java[tags=tlsExplicit] include::../../{doc_code}/embedded/client/http/HTTPClientDocs.java[tags=tlsExplicit]
---- ----
The default `SslContextFactory.Client` verifies the certificate sent by the The default `SslContextFactory.Client` verifies the certificate sent by the server by verifying the certificate chain.
server by verifying the certificate chain. This means that requests to public websites that have a valid certificate (such as ``https://google.com``) will work out-of-the-box.
This means that requests to public websites that have a valid certificates
(such as ``https://google.com``) will work out-of-the-box.
However, requests made to sites (typically ``localhost``) that have invalid However, requests made to sites (typically ``localhost``) that have an invalid (for example, expired or with a wrong host) or self-signed certificate will fail (like they will in a browser).
(for example, expired or with a wrong host) or self-signed certificates will
fail (like they will in a browser).
Certificate validation is performed at two levels: at the TLS implementation Certificate validation is performed at two levels: at the TLS implementation level (in the JDK) and - optionally - at the application level.
level (in the JDK) and - optionally - at the application level.
By default, certificate validation at the TLS level is enabled, while By default, certificate validation at the TLS level is enabled, while certificate validation at the application level is disabled.
certificate validation at the application level is disabled.
You can configure the `SslContextFactory.Client` to skip certificate validation You can configure the `SslContextFactory.Client` to skip certificate validation at the TLS level:
at the TLS level:
[source,java,indent=0] [source,java,indent=0]
---- ----
@ -81,6 +66,4 @@ You can enable certificate validation at the application level:
include::../../{doc_code}/embedded/client/http/HTTPClientDocs.java[tags=tlsAppValidation] include::../../{doc_code}/embedded/client/http/HTTPClientDocs.java[tags=tlsAppValidation]
---- ----
Please refer to the `SslContextFactory.Client` Please refer to the `SslContextFactory.Client` link:{JDURL}/org/eclipse/jetty/util/ssl/SslContextFactory.Client.html[javadocs] for the complete list of configurable parameters.
link:{JDURL}/org/eclipse/jetty/util/ssl/SslContextFactory.Client.html[javadocs]
for the complete list of configurable parameters.

View File

@ -51,9 +51,8 @@ You can remove cookies that you do not want to be sent in future HTTP requests:
include::../../{doc_code}/embedded/client/http/HTTPClientDocs.java[tag=removeCookie] include::../../{doc_code}/embedded/client/http/HTTPClientDocs.java[tag=removeCookie]
---- ----
If you want to totally disable cookie handling, you can install a If you want to totally disable cookie handling, you can install a `HttpCookieStore.Empty`.
`HttpCookieStore.Empty`. This must be done when `HttpClient` is used in a This must be done when `HttpClient` is used in a proxy application, in this way:
proxy application, in this way:
[source,java,indent=0] [source,java,indent=0]
---- ----
@ -71,6 +70,7 @@ The example above will retain only cookies that come from the `google.com` domai
// TODO: move this section to server-side // TODO: move this section to server-side
==== Special Characters in Cookies ==== Special Characters in Cookies
Jetty is compliant with link:https://tools.ietf.org/html/rfc6265[RFC6265], and as such care must be taken when setting a cookie value that includes special characters such as `;`. Jetty is compliant with link:https://tools.ietf.org/html/rfc6265[RFC6265], and as such care must be taken when setting a cookie value that includes special characters such as `;`.
Previously, Version=1 cookies defined in link:https://tools.ietf.org/html/rfc2109[RFC2109] (and continued in link:https://tools.ietf.org/html/rfc2965[RFC2965]) allowed for special/reserved characters to be enclosed within double quotes when declared in a `Set-Cookie` response header: Previously, Version=1 cookies defined in link:https://tools.ietf.org/html/rfc2109[RFC2109] (and continued in link:https://tools.ietf.org/html/rfc2965[RFC2965]) allowed for special/reserved characters to be enclosed within double quotes when declared in a `Set-Cookie` response header:

View File

@ -24,13 +24,10 @@ The Jetty HTTP client module provides easy-to-use APIs and utility classes to pe
Jetty's HTTP client is non-blocking and asynchronous. Jetty's HTTP client is non-blocking and asynchronous.
It offers an asynchronous API that never blocks for I/O, making it very efficient in thread utilization and well suited for high performance scenarios such as load testing or parallel computation. It offers an asynchronous API that never blocks for I/O, making it very efficient in thread utilization and well suited for high performance scenarios such as load testing or parallel computation.
However, when all you need to do is to perform a `GET` request to a resource, Jetty's HTTP client offers also a synchronous API; a programming interface However, when all you need to do is to perform a `GET` request to a resource, Jetty's HTTP client offers also a synchronous API; a programming interface where the thread that issued the request blocks until the request/response conversation is complete.
where the thread that issued the request blocks until the request/response conversation is complete.
Jetty's HTTP client supports xref:#eg-client-http-transport[different transports]: HTTP/1.1, FastCGI and HTTP/2. Jetty's HTTP client supports xref:#eg-client-http-transport[different transports]: HTTP/1.1, FastCGI and HTTP/2. This means that the semantic of a HTTP request (that is, " `GET` me the resource `/index.html` ") can be carried over the network in different formats.
This means that the semantic of a HTTP request (that is, " `GET` me the resource `/index.html` ") can be carried over the network in different formats. The most common and default format is HTTP/1.1. That said, Jetty's HTTP client can carry the same request using the FastCGI format or the HTTP/2 format.
The most common and default format is HTTP/1.1.
That said, Jetty's HTTP client can carry the same request using the FastCGI format or the HTTP/2 format.
The FastCGI transport is heavily used in Jetty's link:#fastcgi[FastCGI support] that allows Jetty to work as a reverse proxy to PHP (exactly like Apache or Nginx do) and therefore be able to serve - for example - WordPress websites. The FastCGI transport is heavily used in Jetty's link:#fastcgi[FastCGI support] that allows Jetty to work as a reverse proxy to PHP (exactly like Apache or Nginx do) and therefore be able to serve - for example - WordPress websites.
@ -61,8 +58,7 @@ The Maven artifact coordinates are the following:
The main class is named `org.eclipse.jetty.client.HttpClient`. The main class is named `org.eclipse.jetty.client.HttpClient`.
You can think of a `HttpClient` instance as a browser instance. You can think of a `HttpClient` instance as a browser instance.
Like a browser it can make requests to different domains, it manages redirects, cookies and authentication, you can configure it with a proxy, and Like a browser it can make requests to different domains, it manages redirects, cookies and authentication, you can configure it with a proxy, and it provides you with the responses to the requests you make.
it provides you with the responses to the requests you make.
In order to use `HttpClient`, you must instantiate it, configure it, and then start it: In order to use `HttpClient`, you must instantiate it, configure it, and then start it:
@ -78,11 +74,8 @@ There are several reasons for having multiple `HttpClient` instances including,
* You want the two instances to behave like two different browsers and hence have different cookies, different authentication credentials, etc. * You want the two instances to behave like two different browsers and hence have different cookies, different authentication credentials, etc.
* You want to use link:#eg-client-http-transport[different transports]. * You want to use link:#eg-client-http-transport[different transports].
Like browsers, HTTPS requests are supported out-of-the-box, as long as the server Like browsers, HTTPS requests are supported out-of-the-box, as long as the server provides a valid certificate.
provides a valid certificate. In case the server does not provide a valid certificate (or in case it is self-signed) you want to customize ``HttpClient``'s TLS configuration as described in xref:eg-client-http-configuration-tls[this section].
In case the server does not provide a valid certificate (or in case it is self-signed)
you want to customize ``HttpClient``'s TLS configuration as described in
xref:eg-client-http-configuration-tls[this section].
[[eg-client-http-stop]] [[eg-client-http-stop]]
==== Stopping HttpClient ==== Stopping HttpClient
@ -99,64 +92,39 @@ Stopping `HttpClient` makes sure that the memory it holds (for example, authenti
[[eg-client-http-arch]] [[eg-client-http-arch]]
==== HttpClient Architecture ==== HttpClient Architecture
A `HttpClient` instance can be thought as a browser instance, and it manages the A `HttpClient` instance can be thought as a browser instance, and it manages the following components:
following components:
* a `CookieStore` (see xref:eg-client-http-cookie[this section]). * a `CookieStore` (see xref:eg-client-http-cookie[this section]).
* a `AuthenticationStore` (see xref:eg-client-http-authentication[this section]). * a `AuthenticationStore` (see xref:eg-client-http-authentication[this section]).
* a `ProxyConfiguration` (see xref:eg-client-http-proxy[this section]). * a `ProxyConfiguration` (see xref:eg-client-http-proxy[this section]).
* a set of _destinations_. * a set of _destinations_.
A _destination_ is the client-side component that represent an _origin_ on A _destination_ is the client-side component that represent an _origin_ on a server, and manages a queue of requests for that origin, and a xref:eg-client-http-connection-pool[pool of connections] to that origin.
a server, and manages a queue of requests for that origin, and a
xref:eg-client-http-connection-pool[pool of connections] to that origin.
An _origin_ may be simply thought as the tuple `(scheme, host, port)` and it An _origin_ may be simply thought as the tuple `(scheme, host, port)` and it is where the client connects to in order to communicate with the server.
is where the client connects to in order to communicate with the server.
However, this is not enough. However, this is not enough.
If you use `HttpClient` to write a proxy you may have different clients that If you use `HttpClient` to write a proxy you may have different clients that want to contact the same server.
want to contact the same server. In this case, you may not want to use the same proxy-to-server connection to proxy requests for both clients, for example for authentication reasons: the server may associate the connection with authentication credentials and you do not want to use the same connection for two different users that have different credentials.
In this case, you may not want to use the same proxy-to-server connection to Instead, you want to use different connections for different clients and this can be achieved by "tagging" a destination with a tag object that represents the remote client (for example, it could be the remote client IP address).
proxy requests for both clients, for example for authentication reasons: the
server may associate the connection with authentication credentials and you
do not want to use the same connection for two different users that have
different credentials.
Instead, you want to use different connections for different clients and
this can be achieved by "tagging" a destination with a tag object that
represents the remote client (for example, it could be the remote client IP
address).
Two origins with the same `(scheme, host, port)` but different `tag` Two origins with the same `(scheme, host, port)` but different `tag` create two different destinations and therefore two different connection pools.
create two different destinations and therefore two different connection pools.
However, also this is not enough. However, also this is not enough.
It is possible that a server speaks different protocols on the same `port`. It is possible that a server speaks different protocols on the same `port`.
A connection may start by speaking one protocol, for example HTTP/1.1, but A connection may start by speaking one protocol, for example HTTP/1.1, but then be upgraded to speak a different protocol, for example HTTP/2. After a connection has been upgraded to a second protocol, it cannot speak the first protocol anymore, so it can only be used to communicate using the second protocol.
then be upgraded to speak a different protocol, for example HTTP/2.
After a connection has been upgraded to a second protocol, it cannot speak
the first protocol anymore, so it can only be used to communicate using
the second protocol.
Two origins with the same `(scheme, host, port)` but different Two origins with the same `(scheme, host, port)` but different `protocol` create two different destinations and therefore two different connection pools.
`protocol` create two different destinations and therefore two different
connection pools.
Therefore an origin is identified by the tuple Therefore an origin is identified by the tuple `(scheme, host, port, tag, protocol)`.
`(scheme, host, port, tag, protocol)`.
[[eg-client-http-connection-pool]] [[eg-client-http-connection-pool]]
==== HttpClient Connection Pooling ==== HttpClient Connection Pooling
A destination manages a `org.eclipse.jetty.client.ConnectionPool`, where A destination manages a `org.eclipse.jetty.client.ConnectionPool`, where connections to a particular origin are pooled for performance reasons:
connections to a particular origin are pooled for performance reasons: opening a connection is a costly operation and it's better to reuse them for multiple requests.
opening a connection is a costly operation and it's better to reuse them
for multiple requests.
NOTE: Remember that to select a specific destination you must select a NOTE: Remember that to select a specific destination you must select a specific origin, and that an origin is identified by the tuple `(scheme, host, port, tag, protocol)`, so you can have multiple destinations for the same `host` and `port`.
specific origin, and that an origin is identified by the tuple
`(scheme, host, port, tag, protocol)`, so you can have multiple destinations
for the same `host` and `port`.
You can access the `ConnectionPool` in this way: You can access the `ConnectionPool` in this way:
@ -167,17 +135,11 @@ include::../../{doc_code}/embedded/client/http/HTTPClientDocs.java[tags=getConne
Jetty's client library provides the following `ConnectionPool` implementations: Jetty's client library provides the following `ConnectionPool` implementations:
* `DuplexConnectionPool`, historically the first implementation, only used by * `DuplexConnectionPool`, historically the first implementation, only used by the HTTP/1.1 transport.
the HTTP/1.1 transport. * `MultiplexConnectionPool`, the generic implementation valid for any transport where connections are reused with a MRU (most recently used) algorithm (that is, the connections most recently returned to the connection pool are the more likely to be used again).
* `MultiplexConnectionPool`, the generic implementation valid for any transport * `RoundRobinConnectionPool`, similar to `MultiplexConnectionPool` but where connections are reused with a round-robin algorithm.
where connections are reused with a MRU (most recently used) algorithm (that is,
the connections most recently returned to the connection pool are the more
likely to be used again).
* `RoundRobinConnectionPool`, similar to `MultiplexConnectionPool` but where
connections are reused with a round-robin algorithm.
The `ConnectionPool` implementation can be customized for each destination in The `ConnectionPool` implementation can be customized for each destination in by setting a `ConnectionPool.Factory` on the `HttpClientTransport`:
by setting a `ConnectionPool.Factory` on the `HttpClientTransport`:
[source,java,indent=0] [source,java,indent=0]
---- ----
@ -214,40 +176,22 @@ Destination -> Destination : dequeue(Request)
Destination -> Connection : send(Request) Destination -> Connection : send(Request)
---- ----
When a request is sent, an origin is computed from the request; `HttpClient` When a request is sent, an origin is computed from the request; `HttpClient` uses that origin to find (or create if it does not exist) the correspondent destination.
uses that origin to find (or create if it does not exist) the correspondent The request is then queued onto the destination, and this causes the destination to ask its connection pool for a free connection.
destination. If a connection is available, it is returned, otherwise a new connection is created.
The request is then queued onto the destination, and this causes the Once the destination has obtained the connection, it dequeues the request and sends it over the connection.
destination to ask its connection pool for a free connection.
If a connection is available, it is returned, otherwise a new connection is
created.
Once the destination has obtained the connection, it dequeues the request
and sends it over the connection.
The first request to a destination triggers the opening of the first The first request to a destination triggers the opening of the first connection.
connection. A second request with the same origin sent _after_ the first request/response cycle is completed will reuse the same connection.
A second request with the same origin sent _after_ the first request/response A second request with the same origin sent _concurrently_ with the first request will cause the opening of a second connection.
cycle is completed will reuse the same connection. The configuration parameter `HttpClient.maxConnectionsPerDestination` (see also the xref:eg-client-http-configuration[configuration section]) controls the max number of connections that can be opened for a destination.
A second request with the same origin sent _concurrently_ with the first
request will cause the opening of a second connection.
The configuration parameter `HttpClient.maxConnectionsPerDestination`
(see also the xref:eg-client-http-configuration[configuration section]) controls
the max number of connections that can be opened for a destination.
NOTE: If opening connections to a given origin takes a long time, then NOTE: If opening connections to a given origin takes a long time, then requests for that origin will queue up in the corresponding destination.
requests for that origin will queue up in the corresponding destination.
Each connection can handle a limited number of concurrent requests. Each connection can handle a limited number of concurrent requests.
For HTTP/1.1, this number is always `1`: there can only be one outstanding For HTTP/1.1, this number is always `1`: there can only be one outstanding request for each connection.
request for each connection. For HTTP/2 this number is determined by the server `max_concurrent_stream` setting (typically around `100`, i.e. there can be up to `100` outstanding requests for every connection).
For HTTP/2 this number is determined by the server `max_concurrent_stream`
setting (typically around `100`, i.e. there can be up to `100` outstanding
requests for every connection).
When a destination has maxed out its number of connections, and all When a destination has maxed out its number of connections, and all connections have maxed out their number of outstanding requests, more requests sent to that destination will be queued.
connections have maxed out their number of outstanding requests, more requests
sent to that destination will be queued.
When the request queue is full, the request will be failed. When the request queue is full, the request will be failed.
The configuration parameter `HttpClient.maxRequestsQueuedPerDestination` The configuration parameter `HttpClient.maxRequestsQueuedPerDestination` (see also the xref:eg-client-http-configuration[configuration section]) controls the max number of requests that can be queued for a destination.
(see also the xref:eg-client-http-configuration[configuration section]) controls
the max number of requests that can be queued for a destination.

View File

@ -21,9 +21,7 @@
Jetty's `HttpClient` can be configured to use proxies to connect to destinations. Jetty's `HttpClient` can be configured to use proxies to connect to destinations.
Two types of proxies are available out of the box: a HTTP proxy (provided by Two types of proxies are available out of the box: a HTTP proxy (provided by class `org.eclipse.jetty.client.HttpProxy`) and a SOCKS 4 proxy (provided by class `org.eclipse.jetty.client.Socks4Proxy`).
class `org.eclipse.jetty.client.HttpProxy`) and a SOCKS 4 proxy (provided by
class `org.eclipse.jetty.client.Socks4Proxy`).
Other implementations may be written by subclassing `ProxyConfiguration.Proxy`. Other implementations may be written by subclassing `ProxyConfiguration.Proxy`.
The following is a typical configuration: The following is a typical configuration:
@ -33,32 +31,25 @@ The following is a typical configuration:
include::../../{doc_code}/embedded/client/http/HTTPClientDocs.java[tag=proxy] include::../../{doc_code}/embedded/client/http/HTTPClientDocs.java[tag=proxy]
---- ----
You specify the proxy host and proxy port, and optionally also the addresses You specify the proxy host and proxy port, and optionally also the addresses that you do not want to be proxied, and then add the proxy configuration on the `ProxyConfiguration` instance.
that you do not want to be proxied, and then add the proxy configuration on
the `ProxyConfiguration` instance.
Configured in this way, `HttpClient` makes requests to the HTTP proxy (for Configured in this way, `HttpClient` makes requests to the HTTP proxy (for plain-text HTTP requests) or establishes a tunnel via HTTP `CONNECT` (for encrypted HTTPS requests).
plain-text HTTP requests) or establishes a tunnel via HTTP `CONNECT` (for
encrypted HTTPS requests).
Proxying is supported for both HTTP/1.1 and HTTP/2. Proxying is supported for both HTTP/1.1 and HTTP/2.
[[eg-client-http-proxy-authentication]] [[eg-client-http-proxy-authentication]]
==== Proxy Authentication Support ==== Proxy Authentication Support
Jetty's `HttpClient` supports proxy authentication in the same way it supports Jetty's `HttpClient` supports proxy authentication in the same way it supports xref:eg-client-http-authentication[server authentication].
xref:eg-client-http-authentication[server authentication].
In the example below, the proxy requires `BASIC` authentication, but the server In the example below, the proxy requires `BASIC` authentication, but the server requires `DIGEST` authentication, and therefore:
requires `DIGEST` authentication, and therefore:
[source,java,indent=0] [source,java,indent=0]
---- ----
include::../../{doc_code}/embedded/client/http/HTTPClientDocs.java[tag=proxyAuthentication] include::../../{doc_code}/embedded/client/http/HTTPClientDocs.java[tag=proxyAuthentication]
---- ----
The HTTP conversation for successful authentications on both the proxy and the The HTTP conversation for successful authentications on both the proxy and the server is the following:
server is the following:
[plantuml] [plantuml]
---- ----
@ -84,9 +75,6 @@ Proxy -> HttpClient : 200 OK
HttpClient -> Application : 200 OK HttpClient -> Application : 200 OK
---- ----
The application does not receive events related to the responses with code 407 The application does not receive events related to the responses with code 407 and 401 since they are handled internally by `HttpClient`.
and 401 since they are handled internally by `HttpClient`.
Similarly to the xref:eg-client-http-authentication[authentication section], the Similarly to the xref:eg-client-http-authentication[authentication section], the proxy authentication result and the server authentication result can be preempted to avoid, respectively, the 407 and 401 roundtrips.
proxy authentication result and the server authentication result can be
preempted to avoid, respectively, the 407 and 401 roundtrips.

View File

@ -19,20 +19,13 @@
[[eg-client-http-transport]] [[eg-client-http-transport]]
=== HttpClient Pluggable Transports === HttpClient Pluggable Transports
Jetty's `HttpClient` can be configured to use different transports to carry the Jetty's `HttpClient` can be configured to use different transports to carry the semantic of HTTP requests and responses.
semantic of HTTP requests and responses.
This means that the intention of a client to request resource `/index.html` This means that the intention of a client to request resource `/index.html` using the `GET` method can be carried over the network in different formats.
using the `GET` method can be carried over the network in different formats.
A `HttpClient` transport is the component that is in charge of converting a A `HttpClient` transport is the component that is in charge of converting a high-level, semantic, HTTP requests such as "`GET` resource ``/index.html``" into the specific format understood by the server (for example, HTTP/2), and to convert the server response from the specific format (HTTP/2) into high-level, semantic objects that can be used by applications.
high-level, semantic, HTTP requests such as "`GET` resource ``/index.html``"
into the specific format understood by the server (for example, HTTP/2), and to
convert the server response from the specific format (HTTP/2) into high-level,
semantic objects that can be used by applications.
The most common protocol format is HTTP/1.1, a textual protocol with lines The most common protocol format is HTTP/1.1, a textual protocol with lines separated by `\r\n`:
separated by `\r\n`:
[source,screen] [source,screen]
---- ----
@ -56,27 +49,17 @@ x0C x0B D O C U M E
... ...
---- ----
Similarly, HTTP/2 is a binary protocol that transports the same information Similarly, HTTP/2 is a binary protocol that transports the same information in a yet different format.
in a yet different format.
A protocol may be _negotiated_ between client and server. A request for a A protocol may be _negotiated_ between client and server.
resource may be sent using one protocol (for example, HTTP/1.1), but the A request for a resource may be sent using one protocol (for example, HTTP/1.1), but the response may arrive in a different protocol (for example, HTTP/2).
response may arrive in a different protocol (for example, HTTP/2).
`HttpClient` supports 3 static transports, each speaking only one protocol: `HttpClient` supports 3 static transports, each speaking only one protocol: xref:eg-client-http-transport-http11[HTTP/1.1], xref:eg-client-http-transport-http2[HTTP/2] and xref:eg-client-http-transport-fcgi[FastCGI], all of them with 2 variants: clear-text and TLS encrypted.
xref:eg-client-http-transport-http11[HTTP/1.1],
xref:eg-client-http-transport-http2[HTTP/2] and
xref:eg-client-http-transport-fcgi[FastCGI],
all of them with 2 variants: clear-text and TLS encrypted.
`HttpClient` also supports one `HttpClient` also supports one xref:eg-client-http-transport-dynamic[dynamic transport], that can speak different protocols and can select the right protocol by negotiating it with the server or by explicit indication from applications.
xref:eg-client-http-transport-dynamic[dynamic transport],
that can speak different protocols and can select the right protocol by
negotiating it with the server or by explicit indication from applications.
Applications are typically not aware of the actual protocol being used. Applications are typically not aware of the actual protocol being used.
This allows them to write their logic against a high-level API that hides the This allows them to write their logic against a high-level API that hides the details of the specific protocol being used over the network.
details of the specific protocol being used over the network.
[[eg-client-http-transport-http11]] [[eg-client-http-transport-http11]]
==== HTTP/1.1 Transport ==== HTTP/1.1 Transport
@ -88,8 +71,7 @@ HTTP/1.1 is the default transport.
include::../../{doc_code}/embedded/client/http/HTTPClientDocs.java[tag=defaultTransport] include::../../{doc_code}/embedded/client/http/HTTPClientDocs.java[tag=defaultTransport]
---- ----
If you want to customize the HTTP/1.1 transport, you can explicitly configure If you want to customize the HTTP/1.1 transport, you can explicitly configure it in this way:
it in this way:
[source,java,indent=0] [source,java,indent=0]
---- ----
@ -106,12 +88,9 @@ The HTTP/2 transport can be configured in this way:
include::../../{doc_code}/embedded/client/http/HTTPClientDocs.java[tag=http2Transport] include::../../{doc_code}/embedded/client/http/HTTPClientDocs.java[tag=http2Transport]
---- ----
`HTTP2Client` is the lower-level client that provides an API based on HTTP/2 `HTTP2Client` is the lower-level client that provides an API based on HTTP/2 concepts such as _sessions_, _streams_ and _frames_ that are specific to HTTP/2. See xref:eg-client-http2[the HTTP/2 client section] for more information.
concepts such as _sessions_, _streams_ and _frames_ that are specific to HTTP/2.
See xref:eg-client-http2[the HTTP/2 client section] for more information.
`HttpClientTransportOverHTTP2` uses `HTTP2Client` to format high-level semantic `HttpClientTransportOverHTTP2` uses `HTTP2Client` to format high-level semantic HTTP requests (like "GET resource /index.html") into the HTTP/2 specific format.
HTTP requests (like "GET resource /index.html") into the HTTP/2 specific format.
[[eg-client-http-transport-fcgi]] [[eg-client-http-transport-fcgi]]
==== FastCGI Transport ==== FastCGI Transport
@ -123,33 +102,21 @@ The FastCGI transport can be configured in this way:
include::../../{doc_code}/embedded/client/http/HTTPClientDocs.java[tag=fcgiTransport] include::../../{doc_code}/embedded/client/http/HTTPClientDocs.java[tag=fcgiTransport]
---- ----
In order to make requests using the FastCGI transport, you need to have a In order to make requests using the FastCGI transport, you need to have a FastCGI server such as https://en.wikipedia.org/wiki/PHP#PHPFPM[PHP-FPM] (see also http://php.net/manual/en/install.fpm.php).
FastCGI server such as https://en.wikipedia.org/wiki/PHP#PHPFPM[PHP-FPM]
(see also http://php.net/manual/en/install.fpm.php).
The FastCGI transport is primarily used by Jetty's link:#fastcgi[FastCGI support] The FastCGI transport is primarily used by Jetty's link:#fastcgi[FastCGI support] to serve PHP pages (WordPress for example).
to serve PHP pages (WordPress for example).
[[eg-client-http-transport-dynamic]] [[eg-client-http-transport-dynamic]]
==== Dynamic Transport ==== Dynamic Transport
The static transports work well if you know in advance the protocol you want The static transports work well if you know in advance the protocol you want to speak with the server, or if the server only supports one protocol (such as FastCGI).
to speak with the server, or if the server only supports one protocol (such
as FastCGI).
With the advent of HTTP/2, however, servers are now able to support multiple With the advent of HTTP/2, however, servers are now able to support multiple protocols, at least both HTTP/1.1 and HTTP/2.
protocols, at least both HTTP/1.1 and HTTP/2.
The HTTP/2 protocol is typically negotiated between client and server. The HTTP/2 protocol is typically negotiated between client and server.
This negotiation can happen via ALPN, a TLS extension that allows the client This negotiation can happen via ALPN, a TLS extension that allows the client to tell the server the list of protocol that the client supports, so that the server can pick one of the client supported protocols that also the server supports; or via HTTP/1.1 upgrade by means of the `Upgrade` header.
to tell the server the list of protocol that the client supports, so that the
server can pick one of the client supported protocols that also the server
supports; or via HTTP/1.1 upgrade by means of the `Upgrade` header.
Applications can configure the dynamic transport with one or more Applications can configure the dynamic transport with one or more _application_ protocols such as HTTP/1.1 or HTTP/2. The implementation will take care of using TLS for HTTPS URIs, using ALPN, negotiating protocols, upgrading from one protocol to another, etc.
_application_ protocols such as HTTP/1.1 or HTTP/2. The implementation will
take care of using TLS for HTTPS URIs, using ALPN, negotiating protocols,
upgrading from one protocol to another, etc.
By default, the dynamic transport only speaks HTTP/1.1: By default, the dynamic transport only speaks HTTP/1.1:
@ -158,51 +125,37 @@ By default, the dynamic transport only speaks HTTP/1.1:
include::../../{doc_code}/embedded/client/http/HTTPClientDocs.java[tag=dynamicDefault] include::../../{doc_code}/embedded/client/http/HTTPClientDocs.java[tag=dynamicDefault]
---- ----
The dynamic transport can be configured with just one protocol, making it The dynamic transport can be configured with just one protocol, making it equivalent to the corresponding static transport:
equivalent to the corresponding static transport:
[source,java,indent=0] [source,java,indent=0]
---- ----
include::../../{doc_code}/embedded/client/http/HTTPClientDocs.java[tag=dynamicOneProtocol] include::../../{doc_code}/embedded/client/http/HTTPClientDocs.java[tag=dynamicOneProtocol]
---- ----
The dynamic transport, however, has been implemented to support multiple The dynamic transport, however, has been implemented to support multiple transports, in particular both HTTP/1.1 and HTTP/2:
transports, in particular both HTTP/1.1 and HTTP/2:
[source,java,indent=0] [source,java,indent=0]
---- ----
include::../../{doc_code}/embedded/client/http/HTTPClientDocs.java[tag=dynamicH1H2] include::../../{doc_code}/embedded/client/http/HTTPClientDocs.java[tag=dynamicH1H2]
---- ----
IMPORTANT: The order in which the protocols are specified to IMPORTANT: The order in which the protocols are specified to `HttpClientTransportDynamic` indicates what is the client preference.
`HttpClientTransportDynamic` indicates what is the client preference. If the protocol is negotiated via ALPN, it is the server that decides what is the protocol to use for the communication, regardless of the client preference.
If the protocol is negotiated via ALPN, it is the server that decides what is
the protocol to use for the communication, regardless of the client preference.
If the protocol is not negotiated, the client preference is honored. If the protocol is not negotiated, the client preference is honored.
Provided that the server supports both HTTP/1.1 and HTTP/2 clear-text, client Provided that the server supports both HTTP/1.1 and HTTP/2 clear-text, client applications can explicitly hint the version they want to use:
applications can explicitly hint the version they want to use:
[source,java,indent=0] [source,java,indent=0]
---- ----
include::../../{doc_code}/embedded/client/http/HTTPClientDocs.java[tag=dynamicClearText] include::../../{doc_code}/embedded/client/http/HTTPClientDocs.java[tag=dynamicClearText]
---- ----
In case of TLS encrypted communication using the HTTPS scheme, things are a In case of TLS encrypted communication using the HTTPS scheme, things are a little more complicated.
little more complicated.
If the client application explicitly specifies the HTTP version, then ALPN If the client application explicitly specifies the HTTP version, then ALPN is not used on the client.
is not used on the client. By specifying the HTTP version explicitly, the By specifying the HTTP version explicitly, the client application has prior-knowledge of what HTTP version the server supports, and therefore ALPN is not needed.
client application has prior-knowledge of what HTTP version the server If the server does not support the HTTP version chosen by the client, then the communication will fail.
supports, and therefore ALPN is not needed.
If the server does not support the HTTP version chosen by the client, then
the communication will fail.
If the client application does not explicitly specify the HTTP version, If the client application does not explicitly specify the HTTP version, then ALPN will be used on the client.
then ALPN will be used on the client. If the server also supports ALPN, then the protocol will be negotiated via ALPN and the server will choose the protocol to use.
If the server also supports ALPN, then the protocol will be negotiated via If the server does not support ALPN, the client will try to use the first protocol configured in `HttpClientTransportDynamic`, and the communication may succeed or fail depending on whether the server supports the protocol chosen by the client.
ALPN and the server will choose the protocol to use.
If the server does not support ALPN, the client will try to use the first
protocol configured in `HttpClientTransportDynamic`, and the communication
may succeed or fail depending on whether the server supports the protocol
chosen by the client.

View File

@ -19,19 +19,11 @@
[[eg-client-http2]] [[eg-client-http2]]
=== HTTP/2 Client Library === HTTP/2 Client Library
In the vast majority of cases, client applications should use the generic, In the vast majority of cases, client applications should use the generic, high-level, xref:eg-client-http[HTTP client library] that also provides HTTP/2 support via the pluggable xref:eg-client-http-transport-http2[HTTP/2 transport] or the xref:eg-client-http-transport-dynamic[dynamic transport].
high-level, xref:eg-client-http[HTTP client library] that also provides
HTTP/2 support via the pluggable
xref:eg-client-http-transport-http2[HTTP/2 transport] or the
xref:eg-client-http-transport-dynamic[dynamic transport].
The high-level HTTP library supports cookies, authentication, redirection, The high-level HTTP library supports cookies, authentication, redirection, connection pooling and a number of other features that are absent in the low-level HTTP/2 library.
connection pooling and a number of other features that are absent in the
low-level HTTP/2 library.
The HTTP/2 client library has been designed for those applications that need The HTTP/2 client library has been designed for those applications that need low-level access to HTTP/2 features such as _sessions_, _streams_ and _frames_, and this is quite a rare use case.
low-level access to HTTP/2 features such as _sessions_, _streams_ and
_frames_, and this is quite a rare use case.
See also the correspondent xref:eg-server-http2[HTTP/2 server library]. See also the correspondent xref:eg-server-http2[HTTP/2 server library].
@ -49,16 +41,14 @@ The Maven artifact coordinates for the HTTP/2 client library are the following:
</dependency> </dependency>
---- ----
The main class is named `org.eclipse.jetty.http2.client.HTTP2Client`, and The main class is named `org.eclipse.jetty.http2.client.HTTP2Client`, and must be created, configured and started before use:
must be created, configured and started before use:
[source,java,indent=0] [source,java,indent=0]
---- ----
include::../../{doc_code}/embedded/client/http2/HTTP2ClientDocs.java[tags=start] include::../../{doc_code}/embedded/client/http2/HTTP2ClientDocs.java[tags=start]
---- ----
When your application stops, or otherwise does not need `HTTP2Client` anymore, When your application stops, or otherwise does not need `HTTP2Client` anymore, it should stop the `HTTP2Client` instance (or instances) that were started:
it should stop the `HTTP2Client` instance (or instances) that were started:
[source,java,indent=0] [source,java,indent=0]
---- ----
@ -66,13 +56,8 @@ include::../../{doc_code}/embedded/client/http2/HTTP2ClientDocs.java[tags=stop]
---- ----
`HTTP2Client` allows client applications to connect to an HTTP/2 server. `HTTP2Client` allows client applications to connect to an HTTP/2 server.
A _session_ represents a single TCP connection to an HTTP/2 server and is A _session_ represents a single TCP connection to an HTTP/2 server and is defined by class `org.eclipse.jetty.http2.api.Session`.
defined by class `org.eclipse.jetty.http2.api.Session`. A _session_ typically has a long life - once the TCP connection is established, it remains open until it is not used anymore (and therefore it is closed by the idle timeout mechanism), until a fatal error occurs (for example, a network failure), or if one of the peers decides unilaterally to close the TCP connection.
A _session_ typically has a long life - once the TCP connection is established,
it remains open until it is not used anymore (and therefore it is closed by
the idle timeout mechanism), until a fatal error occurs (for example, a network
failure), or if one of the peers decides unilaterally to close the TCP
connection.
include::../../http2.adoc[tag=multiplex] include::../../http2.adoc[tag=multiplex]
@ -81,14 +66,12 @@ include::../../http2.adoc[tag=multiplex]
include::../../http2.adoc[tag=flowControl] include::../../http2.adoc[tag=flowControl]
How a client application should handle HTTP/2 flow control is discussed in How a client application should handle HTTP/2 flow control is discussed in details in xref:eg-client-http2-response[this section].
details in xref:eg-client-http2-response[this section].
[[eg-client-http2-connect]] [[eg-client-http2-connect]]
==== Connecting to the Server ==== Connecting to the Server
The first thing an application should do is to connect to the server and The first thing an application should do is to connect to the server and obtain a `Session`.
obtain a `Session`.
The following example connects to the server on a clear-text port: The following example connects to the server on a clear-text port:
[source,java,indent=0] [source,java,indent=0]
@ -103,46 +86,32 @@ The following example connects to the server on an encrypted port:
include::../../{doc_code}/embedded/client/http2/HTTP2ClientDocs.java[tags=encryptedConnect] include::../../{doc_code}/embedded/client/http2/HTTP2ClientDocs.java[tags=encryptedConnect]
---- ----
IMPORTANT: Applications must know in advance whether they want to connect to a IMPORTANT: Applications must know in advance whether they want to connect to a clear-text or encrypted port, and pass the `SslContextFactory` parameter accordingly to the `connect(...)` method.
clear-text or encrypted port, and pass the `SslContextFactory` parameter
accordingly to the `connect(...)` method.
[[eg-client-http2-configure]] [[eg-client-http2-configure]]
===== Configuring the Session ===== Configuring the Session
The `connect(...)` method takes a `Session.Listener` parameter. The `connect(...)` method takes a `Session.Listener` parameter.
This listener's `onPreface(...)` method is invoked just before establishing the This listener's `onPreface(...)` method is invoked just before establishing the connection to the server to gather the client configuration to send to the server.
connection to the server to gather the client configuration to send to the Client applications can override this method to change the default configuration:
server. Client applications can override this method to change the default
configuration:
[source,java,indent=0] [source,java,indent=0]
---- ----
include::../../{doc_code}/embedded/client/http2/HTTP2ClientDocs.java[tags=configure] include::../../{doc_code}/embedded/client/http2/HTTP2ClientDocs.java[tags=configure]
---- ----
The `Session.Listener` is notified of session events originated by the server The `Session.Listener` is notified of session events originated by the server such as receiving a `SETTINGS` frame from the server, or the server closing the connection, or the client timing out the connection due to idleness.
such as receiving a `SETTINGS` frame from the server, or the server closing Please refer to the `Session.Listener` link:{JDURL}/org/eclipse/jetty/http2/api/Session.Listener.html[javadocs] for the complete list of events.
the connection, or the client timing out the connection due to idleness.
Please refer to the `Session.Listener`
link:{JDURL}/org/eclipse/jetty/http2/api/Session.Listener.html[javadocs] for
the complete list of events.
Once a `Session` has been established, the communication with the server happens Once a `Session` has been established, the communication with the server happens by exchanging _frames_, as specified in the link:https://tools.ietf.org/html/rfc7540#section-4[HTTP/2 specification].
by exchanging _frames_, as specified in the
link:https://tools.ietf.org/html/rfc7540#section-4[HTTP/2 specification].
[[eg-client-http2-request]] [[eg-client-http2-request]]
==== Sending a Request ==== Sending a Request
Sending an HTTP request to the server, and receiving a response, creates a Sending an HTTP request to the server, and receiving a response, creates a _stream_ that encapsulates the exchange of HTTP/2 frames that compose the request and the response.
_stream_ that encapsulates the exchange of HTTP/2 frames that compose the
request and the response.
In order to send an HTTP request to the server, the client must send a In order to send an HTTP request to the server, the client must send a `HEADERS` frame.
`HEADERS` frame. `HEADERS` frames carry the request method, the request URI and the request headers.
`HEADERS` frames carry the request method, the request URI and the request
headers.
Sending the `HEADERS` frame opens the `Stream`: Sending the `HEADERS` frame opens the `Stream`:
[source,java,indent=0,subs=normal] [source,java,indent=0,subs=normal]
@ -151,12 +120,8 @@ include::../../{doc_code}/embedded/client/http2/HTTP2ClientDocs.java[tags=newStr
---- ----
Note how `Session.newStream(...)` takes a `Stream.Listener` parameter. Note how `Session.newStream(...)` takes a `Stream.Listener` parameter.
This listener is notified of stream events originated by the server such as This listener is notified of stream events originated by the server such as receiving `HEADERS` or `DATA` frames that are part of the response, discussed in more details in the xref:eg-client-http2-response[section below].
receiving `HEADERS` or `DATA` frames that are part of the response, discussed Please refer to the `Stream.Listener` link:{JDURL}/org/eclipse/jetty/http2/api/Stream.Listener.html[javadocs] for the complete list of events.
in more details in the xref:eg-client-http2-response[section below].
Please refer to the `Stream.Listener`
link:{JDURL}/org/eclipse/jetty/http2/api/Stream.Listener.html[javadocs] for
the complete list of events.
HTTP requests may have content, which is sent using the `Stream` APIs: HTTP requests may have content, which is sent using the `Stream` APIs:
@ -165,27 +130,19 @@ HTTP requests may have content, which is sent using the `Stream` APIs:
include::../../{doc_code}/embedded/client/http2/HTTP2ClientDocs.java[tags=newStreamWithData] include::../../{doc_code}/embedded/client/http2/HTTP2ClientDocs.java[tags=newStreamWithData]
---- ----
IMPORTANT: When sending two `DATA` frames consecutively, the second call to IMPORTANT: When sending two `DATA` frames consecutively, the second call to `Stream.data(...)` must be done only when the first is completed, or a `WritePendingException` will be thrown.
`Stream.data(...)` must be done only when the first is completed, or a Use the `Callback` APIs or `CompletableFuture` APIs to ensure that the second `Stream.data(...)` call is performed when the first completed successfully.
`WritePendingException` will be thrown.
Use the `Callback` APIs or `CompletableFuture` APIs to ensure that the second
`Stream.data(...)` call is performed when the first completed successfully.
[[eg-client-http2-response]] [[eg-client-http2-response]]
==== Receiving a Response ==== Receiving a Response
Response events are delivered to the `Stream.Listener` passed to Response events are delivered to the `Stream.Listener` passed to `Session.newStream(...)`.
`Session.newStream(...)`.
An HTTP response is typically composed of a `HEADERS` frame containing the An HTTP response is typically composed of a `HEADERS` frame containing the HTTP status code and the response headers, and optionally one or more `DATA` frames containing the response content bytes.
HTTP status code and the response headers, and optionally one or more `DATA`
frames containing the response content bytes.
The HTTP/2 protocol also supports response trailers (that is, headers that are The HTTP/2 protocol also supports response trailers (that is, headers that are sent after the response content) that also are sent using a `HEADERS` frame.
sent after the response content) that also are sent using a `HEADERS` frame.
A client application can therefore receive the HTTP/2 frames sent by the server A client application can therefore receive the HTTP/2 frames sent by the server by implementing the relevant methods in `Stream.Listener`:
by implementing the relevant methods in `Stream.Listener`:
[source,java,indent=0] [source,java,indent=0]
---- ----
@ -197,12 +154,9 @@ include::../../http2.adoc[tag=apiFlowControl]
[[eg-client-http2-reset]] [[eg-client-http2-reset]]
==== Resetting a Request or Response ==== Resetting a Request or Response
In HTTP/2, clients and servers have the ability to tell to the other peer that In HTTP/2, clients and servers have the ability to tell to the other peer that they are not interested anymore in either the request or the response, using a `RST_STREAM` frame.
they are not interested anymore in either the request or the response, using a
`RST_STREAM` frame.
The `HTTP2Client` APIs allow client applications to send and receive this The `HTTP2Client` APIs allow client applications to send and receive this "reset" frame:
"reset" frame:
[source,java,indent=0] [source,java,indent=0]
---- ----
@ -212,14 +166,10 @@ include::../../{doc_code}/embedded/client/http2/HTTP2ClientDocs.java[tags=reset]
[[eg-client-http2-push]] [[eg-client-http2-push]]
==== Receiving HTTP/2 Pushes ==== Receiving HTTP/2 Pushes
HTTP/2 servers have the ability to push resources related to a primary HTTP/2 servers have the ability to push resources related to a primary resource.
resource. When an HTTP/2 server pushes a resource, it sends to the client a `PUSH_PROMISE` frame that contains the request URI and headers that a client would use to request explicitly that resource.
When an HTTP/2 server pushes a resource, it sends to the client a
`PUSH_PROMISE` frame that contains the request URI and headers that a client
would use to request explicitly that resource.
Client applications can be configured to tell the server to never push Client applications can be configured to tell the server to never push resources, see xref:eg-client-http2-configure[this section].
resources, see xref:eg-client-http2-configure[this section].
Client applications can listen to the push events, and act accordingly: Client applications can listen to the push events, and act accordingly:
@ -228,9 +178,7 @@ Client applications can listen to the push events, and act accordingly:
include::../../{doc_code}/embedded/client/http2/HTTP2ClientDocs.java[tags=push] include::../../{doc_code}/embedded/client/http2/HTTP2ClientDocs.java[tags=push]
---- ----
If a client application does not want to handle a particular HTTP/2 push, it If a client application does not want to handle a particular HTTP/2 push, it can just reset the pushed stream to tell the server to stop sending bytes for the pushed stream:
can just reset the pushed stream to tell the server to stop sending bytes for
the pushed stream:
[source,java,indent=0] [source,java,indent=0]
---- ----

View File

@ -19,100 +19,56 @@
// Snippets of HTTP/2 documentation that are common between client and server. // Snippets of HTTP/2 documentation that are common between client and server.
tag::multiplex[] tag::multiplex[]
HTTP/2 is a multiplexed protocol: it allows multiple HTTP/2 requests to be sent HTTP/2 is a multiplexed protocol: it allows multiple HTTP/2 requests to be sent on the same TCP connection.
on the same TCP connection.
Each request/response cycle is represented by a _stream_. Each request/response cycle is represented by a _stream_.
Therefore, a single _session_ manages multiple concurrent _streams_. Therefore, a single _session_ manages multiple concurrent _streams_.
A _stream_ has typically a very short life compared to the _session_: a A _stream_ has typically a very short life compared to the _session_: a _stream_ only exists for the duration of the request/response cycle and then disappears.
_stream_ only exists for the duration of the request/response cycle and then
disappears.
end::multiplex[] end::multiplex[]
tag::flowControl[] tag::flowControl[]
The HTTP/2 protocol is _flow controlled_ (see The HTTP/2 protocol is _flow controlled_ (see link:https://tools.ietf.org/html/rfc7540#section-5.2[the specification]).
link:https://tools.ietf.org/html/rfc7540#section-5.2[the specification]). This means that a sender and a receiver maintain a _flow control window_ that tracks the number of data bytes sent and received, respectively.
This means that a sender and a receiver maintain a _flow control window_ that When a sender sends data bytes, it reduces its flow control window.
tracks the number of data bytes sent and received, respectively. When a receiver receives data bytes, it also reduces its flow control window, and then passes the received data bytes to the application.
When a sender sends data bytes, it reduces its flow control window. When a The application consumes the data bytes and tells back the receiver that it has consumed the data bytes.
receiver receives data bytes, it also reduces its flow control window, and The receiver then enlarges the flow control window, and arranges to send a message to the sender with the number of bytes consumed, so that the sender can enlarge its flow control window.
then passes the received data bytes to the application.
The application consumes the data bytes and tells back the receiver that it
has consumed the data bytes.
The receiver then enlarges the flow control window, and arranges to send a
message to the sender with the number of bytes consumed, so that the sender
can enlarge its flow control window.
A sender can send data bytes up to its whole flow control window, then it must A sender can send data bytes up to its whole flow control window, then it must stop sending until it receives a message from the receiver that the data bytes have been consumed, which enlarges the flow control window, which allows the sender to send more data bytes.
stop sending until it receives a message from the receiver that the data bytes
have been consumed, which enlarges the flow control window, which allows the
sender to send more data bytes.
HTTP/2 defines _two_ flow control windows: one for each _session_, and one HTTP/2 defines _two_ flow control windows: one for each _session_, and one for each _stream_.
for each _stream_. Let's see with an example how they interact, assuming that Let's see with an example how they interact, assuming that in this example the session flow control window is 120 bytes and the stream flow control window is 100 bytes.
in this example the session flow control window is 120 bytes and the stream
flow control window is 100 bytes.
The sender opens a session, and then opens `stream_1` on that session, and The sender opens a session, and then opens `stream_1` on that session, and sends `80` data bytes.
sends `80` data bytes. At this point the session flow control window is `40` bytes (`120 - 80`), and ``stream_1``'s flow control window is `20` bytes (`100 - 80`).
At this point the session flow control window is `40` bytes (`120 - 80`), and
``stream_1``'s flow control window is `20` bytes (`100 - 80`).
The sender now opens `stream_2` on the same session and sends `40` data bytes. The sender now opens `stream_2` on the same session and sends `40` data bytes.
At this point, the session flow control window is `0` bytes (`40 - 40`), At this point, the session flow control window is `0` bytes (`40 - 40`), while ``stream_2``'s flow control window is `60` (`100 - 40`).
while ``stream_2``'s flow control window is `60` (`100 - 40`). Since now the session flow control window is `0`, the sender cannot send more data bytes, neither on `stream_1` nor on `stream_2` despite both have their stream flow control windows greater than `0`.
Since now the session flow control window is `0`, the sender cannot send more
data bytes, neither on `stream_1` nor on `stream_2` despite both have their
stream flow control windows greater than `0`.
The receiver consumes ``stream_2``'s `40` data bytes and sends a message to The receiver consumes ``stream_2``'s `40` data bytes and sends a message to the sender with this information.
the sender with this information. At this point, the session flow control window is `40` (`0 40`), ``stream_1``'s flow control window is still `20` and ``stream_2``'s flow control window is `100` (`60 40`).
At this point, the session flow control window is `40` (`0 + 40`), If the sender opens `stream_3` and would like to send 50 data bytes, it would only be able to send `40` because that is the maximum allowed by the session flow control window at this point.
``stream_1``'s flow control window is still `20` and ``stream_2``'s flow
control window is `100` (`60 + 40`).
If the sender opens `stream_3` and would like to send 50 data bytes, it would
only be able to send `40` because that is the maximum allowed by the session
flow control window at this point.
It is therefore very important that applications notify the fact that they It is therefore very important that applications notify the fact that they have consumed data bytes as soon as possible, so that the implementation (the receiver) can send a message to the sender (in the form of a `WINDOW_UPDATE` frame) with the information to enlarge the flow control window, therefore reducing the possibility that sender stalls due to the flow control windows being reduced to `0`.
have consumed data bytes as soon as possible, so that the implementation
(the receiver) can send a message to the sender (in the form of a
`WINDOW_UPDATE` frame) with the information to enlarge the flow control
window, therefore reducing the possibility that sender stalls due to the flow
control windows being reduced to `0`.
end::flowControl[] end::flowControl[]
tag::apiFlowControl[] tag::apiFlowControl[]
NOTE: Returning from the `onData(...)` method implicitly demands for NOTE: Returning from the `onData(...)` method implicitly demands for more `DATA` frames (unless the one just delivered was the last).
more `DATA` frames (unless the one just delivered was the last). Additional `DATA` frames may be delivered immediately if they are available or later, asynchronously, when they arrive.
Additional `DATA` frames may be delivered immediately if they are available
or later, asynchronously, when they arrive.
Applications that consume the content buffer within `onData(...)` Applications that consume the content buffer within `onData(...)` (for example, writing it to a file, or copying the bytes to another storage) should succeed the callback as soon as they have consumed the content buffer.
(for example, writing it to a file, or copying the bytes to another storage) This allows the implementation to reuse the buffer, reducing the memory requirements needed to handle the content buffers.
should succeed the callback as soon as they have consumed the content buffer.
This allows the implementation to reuse the buffer, reducing the memory
requirements needed to handle the content buffers.
Alternatively, a client application may store away _both_ the buffer and the Alternatively, a client application may store away _both_ the buffer and the callback to consume the buffer bytes later, or pass _both_ the buffer and the callback to another asynchronous API (this is typical in proxy applications).
callback to consume the buffer bytes later, or pass _both_ the buffer and
the callback to another asynchronous API (this is typical in proxy
applications).
IMPORTANT: Completing the `Callback` is very important not only to allow the IMPORTANT: Completing the `Callback` is very important not only to allow the implementation to reuse the buffer, but also tells the implementation to enlarge the stream and session flow control windows so that the sender will be able to send more `DATA` frames without stalling.
implementation to reuse the buffer, but also tells the implementation to
enlarge the stream and session flow control windows so that the sender will
be able to send more `DATA` frames without stalling.
Applications can also precisely control _when_ to demand more `DATA` Applications can also precisely control _when_ to demand more `DATA` frames, by implementing the `onDataDemanded(...)` method instead of `onData(...)`:
frames, by implementing the `onDataDemanded(...)` method instead of
`onData(...)`:
[source,java,indent=0] [source,java,indent=0]
---- ----
include::{doc_code}/embedded/HTTP2Docs.java[tags=dataDemanded] include::{doc_code}/embedded/HTTP2Docs.java[tags=dataDemanded]
---- ----
IMPORTANT: Applications that implement `onDataDemanded(...)` must remember IMPORTANT: Applications that implement `onDataDemanded(...)` must remember to call `Stream.demand(...)`.
to call `Stream.demand(...)`. If they don't, the implementation will not If they don't, the implementation will not deliver `DATA` frames and the application will stall threadlessly until an idle timeout fires to close the stream or the session.
deliver `DATA` frames and the application will stall threadlessly until an
idle timeout fires to close the stream or the session.
end::apiFlowControl[] end::apiFlowControl[]

View File

@ -20,33 +20,22 @@
[[eg-io-arch]] [[eg-io-arch]]
== Jetty I/O Architecture == Jetty I/O Architecture
Jetty libraries (both client and server) use Java NIO to handle I/O, so that Jetty libraries (both client and server) use Java NIO to handle I/O, so that at its core Jetty I/O is completely non-blocking.
at its core Jetty I/O is completely non-blocking.
[[eg-io-arch-selector-manager]] [[eg-io-arch-selector-manager]]
=== Jetty I/O: `SelectorManager` === Jetty I/O: `SelectorManager`
The core class of Jetty I/O is The core class of Jetty I/O is link:{JDURL}/org/eclipse/jetty/io/SelectorManager.html[`SelectorManager`].
link:{JDURL}/org/eclipse/jetty/io/SelectorManager.html[`SelectorManager`].
`SelectorManager` manages internally a configurable number of `SelectorManager` manages internally a configurable number of link:{JDURL}/org/eclipse/jetty/io/ManagedSelector.html[`ManagedSelector`]s.
link:{JDURL}/org/eclipse/jetty/io/ManagedSelector.html[`ManagedSelector`]s. Each `ManagedSelector` wraps an instance of `java.nio.channels.Selector` that in turn manages a number of `java.nio.channels.SocketChannel` instances.
Each `ManagedSelector` wraps an instance of `java.nio.channels.Selector` that
in turn manages a number of `java.nio.channels.SocketChannel` instances.
NOTE: TODO: add image NOTE: TODO: add image
`SocketChannel` instances can be created by network clients when connecting `SocketChannel` instances can be created by network clients when connecting to a server and by a network server when accepting connections from network clients.
to a server and by a network server when accepting connections from network In both cases the `SocketChannel` instance is passed to `SelectorManager` (which passes it to `ManagedSelector` and eventually to `java.nio.channels.Selector`) to be registered for use within Jetty.
clients.
In both cases the `SocketChannel` instance is passed to `SelectorManager`
(which passes it to `ManagedSelector` and eventually to
`java.nio.channels.Selector`) to be registered for use within Jetty.
It is possible for an application to create the `SocketChannel` It is possible for an application to create the `SocketChannel` instances outside Jetty, even perform some initial network traffic also outside Jetty (for example for authentication purposes), and then pass the `SocketChannel` instance to `SelectorManager` for use within Jetty.
instances outside Jetty, even perform some initial network traffic also
outside Jetty (for example for authentication purposes), and then pass the
`SocketChannel` instance to `SelectorManager` for use within Jetty.
This example shows how a client can connect to a server: This example shows how a client can connect to a server:
@ -65,143 +54,81 @@ include::{doc_code}/embedded/SelectorManagerDocs.java[tags=accept]
[[eg-io-arch-endpoint-connection]] [[eg-io-arch-endpoint-connection]]
=== Jetty I/O: `EndPoint` and `Connection` === Jetty I/O: `EndPoint` and `Connection`
``SocketChannel``s that are passed to `SelectorManager` are wrapped into two ``SocketChannel``s that are passed to `SelectorManager` are wrapped into two related components: an link:{JDURL}/org/eclipse/jetty/io/EndPoint.html[`EndPoint`] and a link:{JDURL}/org/eclipse/jetty/io/Connection.html[`Connection`].
related components:
an link:{JDURL}/org/eclipse/jetty/io/EndPoint.html[`EndPoint`] and a
link:{JDURL}/org/eclipse/jetty/io/Connection.html[`Connection`].
`EndPoint` is the Jetty abstraction for a `SocketChannel`: you can read bytes `EndPoint` is the Jetty abstraction for a `SocketChannel`: you can read bytes from an `EndPoint` via `EndPoint.fill(ByteBuffer)`, you can write bytes to an `EndPoint` via `EndPoint.flush(ByteBuffer...)` and `EndPoint.write(Callback, ByteBuffer...)`, you can close an `EndPoint` via `EndPoint.close()`, etc.
from an `EndPoint` via `EndPoint.fill(ByteBuffer)`, you can write bytes to an
`EndPoint` via `EndPoint.flush(ByteBuffer...)` and
`EndPoint.write(Callback, ByteBuffer...)`, you can close an `EndPoint` via
`EndPoint.close()`, etc.
`Connection` is the Jetty abstraction that is responsible to read bytes from `Connection` is the Jetty abstraction that is responsible to read bytes from the `EndPoint` and to deserialize the read bytes into objects.
the `EndPoint` and to deserialize the read bytes into objects. For example, a HTTP/1.1 server-side `Connection` implementation is responsible to deserialize HTTP/1.1 request bytes into a HTTP request object.
For example, a HTTP/1.1 server-side `Connection` implementation is responsible Conversely, a HTTP/1.1 client-side `Connection` implementation is responsible to deserialize HTTP/1.1 response bytes into a HTTP response object.
to deserialize HTTP/1.1 request bytes into a HTTP request object.
Conversely, a HTTP/1.1 client-side `Connection` implementation is responsible
to deserialize HTTP/1.1 response bytes into a HTTP response object.
`Connection` is the abstraction that implements the reading side of a specific `Connection` is the abstraction that implements the reading side of a specific protocol such as HTTP/1.1, or HTTP/2, or WebSocket: it is able to read incoming communication in that protocol.
protocol such as HTTP/1.1, or HTTP/2, or WebSocket: it is able to read incoming
communication in that protocol.
The writing side for a specific protocol _may_ be implemented in the `Connection` The writing side for a specific protocol _may_ be implemented in the `Connection` but may also be implemented in other components, although eventually the bytes to be written will be written through the `EndPoint`.
but may also be implemented in other components, although eventually the bytes
to be written will be written through the `EndPoint`.
While there is primarily just one implementation of `EndPoint`, While there is primarily just one implementation of `EndPoint`,link:{JDURL}/org/eclipse/jetty/io/SocketChannelEndPoint.html[`SocketChannelEndPoint`] (used both on the client-side and on the server-side), there are many implementations of `Connection`, typically two for each protocol (one for the client-side and one for the server-side).
link:{JDURL}/org/eclipse/jetty/io/SocketChannelEndPoint.html[`SocketChannelEndPoint`]
(used both on the client-side and on the server-side), there are many
implementations of `Connection`, typically two for each protocol (one for the
client-side and one for the server-side).
The `EndPoint` and `Connection` pairs can be chained, for example in case of The `EndPoint` and `Connection` pairs can be chained, for example in case of encrypted communication using the TLS protocol.
encrypted communication using the TLS protocol. There is an `EndPoint` and `Connection` TLS pair where the `EndPoint` reads the encrypted bytes from the network and the `Connection` decrypts them; next in the chain there is an `EndPoint` and `Connection` pair where the `EndPoint` "reads" decrypted bytes (provided by the previous `Connection`) and the `Connection` deserializes them into specific protocol objects (for example HTTP/2 frame objects).
There is an `EndPoint` and `Connection` TLS pair where the `EndPoint` reads the
encrypted bytes from the network and the `Connection` decrypts them; next in the
chain there is an `EndPoint` and `Connection` pair where the `EndPoint` "reads"
decrypted bytes (provided by the previous `Connection`) and the `Connection`
deserializes them into specific protocol objects (for example HTTP/2 frame
objects).
Certain protocols, such as WebSocket, start the communication with the server Certain protocols, such as WebSocket, start the communication with the server using one protocol (e.g. HTTP/1.1), but then change the communication to use another protocol (e.g. WebSocket).
using one protocol (e.g. HTTP/1.1), but then change the communication to use `EndPoint` supports changing the `Connection` object on-the-fly via `EndPoint.upgrade(Connection)`.
another protocol (e.g. WebSocket). This allows to use the HTTP/1.1 `Connection` during the initial communication and later to replace it with a WebSocket `Connection`.
`EndPoint` supports changing the `Connection` object on-the-fly via
`EndPoint.upgrade(Connection)`.
This allows to use the HTTP/1.1 `Connection` during the initial communication
and later to replace it with a WebSocket `Connection`.
NOTE: TODO: add a section on `UpgradeFrom` and `UpgradeTo`? NOTE: TODO: add a section on `UpgradeFrom` and `UpgradeTo`?
`SelectorManager` is an abstract class because while it knows how to create `SelectorManager` is an abstract class because while it knows how to create concrete `EndPoint` instances, it does not know how to create protocol specific `Connection` instances.
concrete `EndPoint` instances, it does not know how to create protocol
specific `Connection` instances.
Creating `Connection` instances is performed on the server-side by Creating `Connection` instances is performed on the server-side by link:{JDURL}/org/eclipse/jetty/server/ConnectionFactory.html[`ConnectionFactory`]s and on the client-side by link:{JDURL}/org/eclipse/jetty/io/ClientConnectionFactory.html[`ClientConnectionFactory`]s
link:{JDURL}/org/eclipse/jetty/server/ConnectionFactory.html[`ConnectionFactory`]s.
and on the client-side by
link:{JDURL}/org/eclipse/jetty/io/ClientConnectionFactory.html[`ClientConnectionFactory`]s
On the server-side, the component that aggregates a `SelectorManager` with a On the server-side, the component that aggregates a `SelectorManager` with a set of ``ConnectionFactory``s is link:{JDURL}/org/eclipse/jetty/server/ServerConnector.html[`ServerConnector`]s, see xref:eg-server-io-arch[].
set of ``ConnectionFactory``s is
link:{JDURL}/org/eclipse/jetty/server/ServerConnector.html[`ServerConnector`]s.
NOTE: TODO: add a link to a server-side specific architecture section On the client-side, the components that aggregates a `SelectorManager` with a set of ``ClientConnectionFactory``s are link:{JDURL}/org/eclipse/jetty/client/HttpClientTransport.html[`HttpClientTransport`] subclasses, see xref:eg-client-io-arch[].
On the client-side, the components that aggregates a `SelectorManager` with a
set of ``ClientConnectionFactory``s are
link:{JDURL}/org/eclipse/jetty/client/HttpClientTransport.html[`HttpClientTransport`]
subclasses.
NOTE: TODO: add a link to a client-side specific architecture section
[[eg-io-arch-endpoint]] [[eg-io-arch-endpoint]]
=== Jetty I/O: `EndPoint` === Jetty I/O: `EndPoint`
The Jetty I/O library use Java NIO to handle I/O, so that I/O is non-blocking. The Jetty I/O library use Java NIO to handle I/O, so that I/O is non-blocking.
At the Java NIO level, in order to be notified when a `SocketChannel` has data At the Java NIO level, in order to be notified when a `SocketChannel` has data to be read, the `SelectionKey.OP_READ` flag must be set.
to be read, the `SelectionKey.OP_READ` flag must be set.
In the Jetty I/O library, you can call `EndPoint.fillInterested(Callback)` In the Jetty I/O library, you can call `EndPoint.fillInterested(Callback)` to declare interest in the "read" (or "fill") event, and the `Callback` parameter is the object that is notified when such event occurs.
to declare interest in the "read" (or "fill") event, and the `Callback` parameter
is the object that is notified when such event occurs.
At the Java NIO level, a `SocketChannel` is always writable, unless it becomes At the Java NIO level, a `SocketChannel` is always writable, unless it becomes TCP congested.
TCP congested. In order to be notified when a `SocketChannel` uncongests and it In order to be notified when a `SocketChannel` uncongests and it is therefore writable again, the `SelectionKey.OP_WRITE` flag must be set.
is therefore writable again, the `SelectionKey.OP_WRITE` flag must be set.
In the Jetty I/O library, you can call `EndPoint.write(Callback, ByteBuffer...)` In the Jetty I/O library, you can call `EndPoint.write(Callback, ByteBuffer...)` to write the ``ByteBuffer``s and the `Callback` parameter is the object that is notified when the whole write is finished (i.e. _all_ ``ByteBuffer``s have been fully written, even if they are delayed by TCP congestion/uncongestion).
to write the ``ByteBuffer``s and the `Callback` parameter is the object that is
notified when the whole write is finished (i.e. _all_ ``ByteBuffer``s have been
fully written, even if they are delayed by TCP congestion/uncongestion).
The `EndPoint` APIs abstract out the Java NIO details by providing non-blocking The `EndPoint` APIs abstract out the Java NIO details by providing non-blocking APIs based on `Callback` objects for I/O operations.
APIs based on `Callback` objects for I/O operations. The `EndPoint` APIs are typically called by `Connection` implementations, see xref:eg-io-arch-connection[this section].
The `EndPoint` APIs are typically called by `Connection` implementations, see
xref:eg-io-arch-connection[this section].
[[eg-io-arch-connection]] [[eg-io-arch-connection]]
=== Jetty I/O: `Connection` === Jetty I/O: `Connection`
`Connection` is the abstraction that deserializes incoming bytes into objects, `Connection` is the abstraction that deserializes incoming bytes into objects, for example a HTTP request object or a WebSocket frame object, that can be used by more abstract layers.
for example a HTTP request object or a WebSocket frame object, that can be used
by more abstract layers.
`Connection` instances have two lifecycle methods: `Connection` instances have two lifecycle methods:
* `Connection.onOpen()`, invoked when the `Connection` is associated with the * `Connection.onOpen()`, invoked when the `Connection` is associated with the `EndPoint`
`EndPoint` * `Connection.onClose(Throwable)`, invoked when the `Connection` is disassociated from the `EndPoint`, where the `Throwable` parameter indicates whether the disassociation was normal (when the parameter is `null`) or was due to an error (when the parameter is not `null`)
* `Connection.onClose(Throwable)`, invoked when the `Connection` is disassociated
from the `EndPoint`, where the `Throwable` parameter indicates whether the
disassociation was normal (when the parameter is `null`) or was due to an error
(when the parameter is not `null`)
When a `Connection` is first created, it is not registered for any Java NIO When a `Connection` is first created, it is not registered for any Java NIO event.
event. It is therefore typical to implement `onOpen()` to call `EndPoint.fillInterested(Callback)` so that the `Connection` declares interest for read events and it is invoked (via the `Callback`) when the read event happens.
It is therefore typical to implement `onOpen()` to call
`EndPoint.fillInterested(Callback)` so that the `Connection` declares interest
for read events and it is invoked (via the `Callback`) when the read event
happens.
Abstract class `AbstractConnection` partially implements `Connection` and Abstract class `AbstractConnection` partially implements `Connection` and provides simpler APIs.
provides simpler APIs. The example below shows a typical implementation that The example below shows a typical implementation that extends `AbstractConnection`:
extends `AbstractConnection`:
[source,java,indent=0] [source,java,indent=0]
---- ----
include::{doc_code}/embedded/SelectorManagerDocs.java[tags=connection] include::{doc_code}/embedded/SelectorManagerDocs.java[tags=connection]
---- ----
// TODO: Introduce Connection.Listener
[[eg-io-arch-echo]] [[eg-io-arch-echo]]
=== Jetty I/O: Network Echo === Jetty I/O: Network Echo
With the concepts above it is now possible to write a simple, fully non-blocking, With the concepts above it is now possible to write a simple, fully non-blocking, `Connection` implementation that simply echoes the bytes that it reads back to the other peer.
`Connection` implementation that simply echoes the bytes that it reads back
to the other peer.
A naive, but wrong, implementation may be the following: A naive, but wrong, implementation may be the following:
@ -212,9 +139,7 @@ include::{doc_code}/embedded/SelectorManagerDocs.java[tags=echo-wrong]
WARNING: The implementation above is wrong and leads to `StackOverflowError`. WARNING: The implementation above is wrong and leads to `StackOverflowError`.
The problem with this implementation is that if the writes always complete The problem with this implementation is that if the writes always complete synchronously (i.e. without being delayed by TCP congestion), you end up with this sequence of calls:
synchronously (i.e. without being delayed by TCP congestion), you end up with
this sequence of calls:
---- ----
Connection.onFillable() Connection.onFillable()
@ -228,13 +153,10 @@ Connection.onFillable()
which leads to `StackOverflowError`. which leads to `StackOverflowError`.
This is a typical side effect of asynchronous programming using non-blocking This is a typical side effect of asynchronous programming using non-blocking APIs, and happens in the Jetty I/O library as well.
APIs, and happens in the Jetty I/O library as well.
NOTE: The callback is invoked synchronously for efficiency reasons. NOTE: The callback is invoked synchronously for efficiency reasons.
Submitting the invocation of the callback to an `Executor` to be invoked in Submitting the invocation of the callback to an `Executor` to be invoked in a different thread would cause a context switch and make simple writes extremely inefficient.
a different thread would cause a context switch and make simple writes
extremely inefficient.
A correct implementation is the following: A correct implementation is the following:
@ -243,23 +165,15 @@ A correct implementation is the following:
include::{doc_code}/embedded/SelectorManagerDocs.java[tags=echo-correct] include::{doc_code}/embedded/SelectorManagerDocs.java[tags=echo-correct]
---- ----
The correct implementation performs consecutive reads in a loop (rather than The correct implementation performs consecutive reads in a loop (rather than recursively), but _only_ if the correspondent write is completed successfully.
recursively), but _only_ if the correspondent write is completed successfully.
In order to detect whether the write is completed, a concurrent state machine In order to detect whether the write is completed, a concurrent state machine is used.
is used. This is necessary because the notification of the completion of the This is necessary because the notification of the completion of the write may happen in a different thread, while the original writing thread may still be changing the state.
write may happen in a different thread, while the original writing thread
may still be changing the state.
The original writing thread starts moves the state from `IDLE` to `WRITING`, The original writing thread starts moves the state from `IDLE` to `WRITING`, then issues the actual `write()` call.
then issues the actual `write()` call. The original writing thread then assumes that the `write()` did not complete and tries to move to the `PENDING` state just after the `write()`.
The original writing thread then assumes that the `write()` did not complete If it fails to move from the `WRITING` state to the `PENDING` state, it means that the write was completed.
and tries to move to the `PENDING` state just after the `write()`. Otherwise, the write is now `PENDING` and waiting for the callback to be notified of the completion at a later time.
If it fails to move from the `WRITING` state to the `PENDING` state, it means When the callback is notified of the `write()` completion, it checks whether the `write()` was `PENDING`, and if it was it resumes reading.
that the write was completed.
Otherwise, the write is now `PENDING` and waiting for the callback to be
notified of the completion at a later time.
When the callback is notified of the `write()` completion, it checks whether
the `write()` was `PENDING`, and if it was it resumes reading.
NOTE: TODO: Introduce IteratingCallback? NOTE: TODO: Introduce IteratingCallback?

View File

@ -19,48 +19,34 @@
[[eg-server-http-connector]] [[eg-server-http-connector]]
=== Server Connectors === Server Connectors
A `Connector` is the component that handles incoming requests from clients, A `Connector` is the component that handles incoming requests from clients, and works in conjunction with `ConnectionFactory` instances.
and works in conjunction with `ConnectionFactory` instances.
The primary implementation is `org.eclipse.jetty.server.ServerConnector`. The primary implementation is `org.eclipse.jetty.server.ServerConnector`.`ServerConnector` uses a `java.nio.channels.ServerSocketChannel` to listen to a TCP port and to accept TCP connections.
`ServerConnector` uses a `java.nio.channels.ServerSocketChannel` to listen
to a TCP port and to accept TCP connections.
Since `ServerConnector` wraps a `ServerSocketChannel`, it can be configured Since `ServerConnector` wraps a `ServerSocketChannel`, it can be configured in a similar way, for example the port to listen to, the network address to bind to, etc.:
in a similar way, for example the port to listen to, the network address
to bind to, etc.:
[source,java,indent=0] [source,java,indent=0]
---- ----
include::../../{doc_code}/embedded/server/http/HTTPServerDocs.java[tags=configureConnector] include::../../{doc_code}/embedded/server/http/HTTPServerDocs.java[tags=configureConnector]
---- ----
The _acceptors_ are threads (typically only one) that compete to accept TCP The _acceptors_ are threads (typically only one) that compete to accept TCP connections on the listening port.
connections on the listening port. When a connection is accepted, `ServerConnector` wraps the accepted `SocketChannel` and passes it to the xref:eg-io-arch-selector-manager[`SelectorManager`].
When a connection is accepted, `ServerConnector` wraps the accepted 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 to the `SelectorManager`.
`SocketChannel` and passes it to the Connections that are ready to be accepted but are not accepted yet are queued in a bounded queue (at the OS level) whose capacity can be configured with the `ServerConnector.acceptQueueSize` parameter.
xref:eg-io-arch-selector-manager[`SelectorManager`].
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
to the `SelectorManager`.
Connections that are ready to be accepted but are not accepted yet are queued
in a bounded queue (at the OS level) whose capacity can be configured with the
`ServerConnector.acceptQueueSize` parameter.
If your application must withstand a very high rate of connections opened, If your application must withstand a very high rate of connections opened, configuring more than one acceptor thread may be beneficial: when one acceptor thread accepts one connection, another acceptor thread can take over accepting connections.
configuring more than one acceptor thread may be beneficial: when one acceptor
thread accepts one connection, another acceptor thread can take over accepting
connections.
The _selectors_ are components that manage a set of connected sockets, The _selectors_ are components that manage a set of connected sockets, implemented by xref:eg-io-arch-selector-manager[`ManagedSelector`].
implemented by xref:eg-io-arch-selector-manager[`ManagedSelector`]. Each selector requires one thread and uses the Java NIO mechanism to efficiently handle the set of connected sockets.
Each selector requires one thread and uses the Java NIO mechanism to As a rule of thumb, a single selector can easily manage up to 1000-5000 sockets, although the number may vary greatly depending on the application.
efficiently handle the set of connected sockets.
As a rule of thumb, a single selector can easily manage up to 1000-5000
sockets, although the number may vary greatly depending on the application.
It is possible to configure more than one `ServerConnector`, each listening For example, web site applications tend to use sockets for one or more HTTP requests to retrieve resources and then the socket is idle for most of the time.
on a different port: In this case a single selector may be able to manage many sockets because chances are that they will be idle most of the time.
On the contrary, web messaging applications tend to send many small messages at a very high frequency so that the socket is rarely idle.
In this case a single selector may be able to manage less sockets because chances are that many of them will be active at the same time.
It is possible to configure more than one `ServerConnector`, each listening on a different port:
[source,java,indent=0] [source,java,indent=0]
---- ----
@ -70,20 +56,15 @@ include::../../{doc_code}/embedded/server/http/HTTPServerDocs.java[tags=configur
[[eg-server-http-connector-protocol]] [[eg-server-http-connector-protocol]]
==== Configuring Protocols ==== Configuring Protocols
For each accepted TCP connection, `ServerConnector` asks a `ConnectionFactory` For each accepted TCP connection, `ServerConnector` asks a `ConnectionFactory` to create a `Connection` object that handles the network traffic on that TCP connection, parsing and generating bytes for a specific protocol (see xref:eg-io-arch[this section] for more details about `Connection` objects).
to create a `Connection` object that handles the network traffic on that TCP
connection, parsing and generating bytes for a specific protocol (see
xref:eg-io-arch[this section] for more details about `Connection` objects).
A `ServerConnector` can be configured with one or more ``ConnectionFactory``s. A `ServerConnector` can be configured with one or more ``ConnectionFactory``s.
If no `ConnectionFactory` is specified then `HttpConnectionFactory` is If no `ConnectionFactory` is specified then `HttpConnectionFactory` is implicitly configured.
implicitly configured.
[[eg-server-http-connector-protocol-http11]] [[eg-server-http-connector-protocol-http11]]
===== Configuring HTTP/1.1 ===== Configuring HTTP/1.1
`HttpConnectionFactory` creates `HttpConnection` objects that parse bytes `HttpConnectionFactory` creates `HttpConnection` objects that parse bytes and generate bytes for the HTTP/1.1 protocol.
and generate bytes for the HTTP/1.1 protocol.
This is how you configure Jetty to support clear-text HTTP/1.1: This is how you configure Jetty to support clear-text HTTP/1.1:
@ -92,10 +73,7 @@ This is how you configure Jetty to support clear-text HTTP/1.1:
include::../../{doc_code}/embedded/server/http/HTTPServerDocs.java[tags=http11] include::../../{doc_code}/embedded/server/http/HTTPServerDocs.java[tags=http11]
---- ----
Supporting encrypted HTTP/1.1 (that is, requests with the HTTPS scheme) Supporting encrypted HTTP/1.1 (that is, requests with the HTTPS scheme)is supported by configuring an `SslContextFactory` that has access to the keyStore containing the private server key and public server certificate, in this way:
is supported by configuring an `SslContextFactory` that has access to the
keyStore containing the private server key and public server certificate,
in this way:
[source,java,indent=0] [source,java,indent=0]
---- ----
@ -105,20 +83,11 @@ include::../../{doc_code}/embedded/server/http/HTTPServerDocs.java[tags=tlsHttp1
[[eg-server-http-connector-protocol-proxy-http11]] [[eg-server-http-connector-protocol-proxy-http11]]
===== Configuring Jetty behind a Load Balancer ===== Configuring Jetty behind a Load Balancer
It is often the case that Jetty receives connections from a load balancer It is often the case that Jetty receives connections from a load balancer configured to distribute the load among many Jetty backend servers.
configured to distribute the load among many Jetty backend servers.
From the Jetty point of view, all the connections arrive from the load From the Jetty point of view, all the connections arrive from the load balancer, rather than the real clients, but is possible to configure the load balancer to forward the real client IP address and port to the backend Jetty server using the link:https://www.haproxy.org/download/2.1/doc/proxy-protocol.txt[PROXY protocol].
balancer, rather than the real clients, but is possible to configure the load
balancer to forward the real client IP address and port to the backend Jetty
server using the
link:https://www.haproxy.org/download/2.1/doc/proxy-protocol.txt[PROXY protocol].
NOTE: The PROXY protocol is widely supported by load balancers such as NOTE: The PROXY protocol is widely supported by load balancers such as link:http://cbonte.github.io/haproxy-dconv/2.2/configuration.html#5.2-send-proxy[HAProxy] (via its `send-proxy` directive), link:https://docs.nginx.com/nginx/admin-guide/load-balancer/using-proxy-protocol[Nginx](via its `proxy_protocol on` directive) and others.
link:http://cbonte.github.io/haproxy-dconv/2.2/configuration.html#5.2-send-proxy[HAProxy]
(via its `send-proxy` directive),
link:https://docs.nginx.com/nginx/admin-guide/load-balancer/using-proxy-protocol[Nginx]
(via its `proxy_protocol on` directive) and others.
To support this case, Jetty can be configured in this way: To support this case, Jetty can be configured in this way:
@ -127,57 +96,36 @@ To support this case, Jetty can be configured in this way:
include::../../{doc_code}/embedded/server/http/HTTPServerDocs.java[tags=proxyHTTP] include::../../{doc_code}/embedded/server/http/HTTPServerDocs.java[tags=proxyHTTP]
---- ----
Note how the ``ConnectionFactory``s passed to `ServerConnector` are in order: Note how the ``ConnectionFactory``s passed to `ServerConnector` are in order: first PROXY, then HTTP/1.1.
first PROXY, then HTTP/1.1. Note also how the PROXY `ConnectionFactory` needs to know its _next_ protocol (in this example, HTTP/1.1).
Note also how the PROXY `ConnectionFactory` needs to know its _next_ protocol
(in this example, HTTP/1.1).
Each `ConnectionFactory` is asked to create a `Connection` object for each Each `ConnectionFactory` is asked to create a `Connection` object for each accepted TCP connection; the `Connection` objects will be chained together to handle the bytes, each for its own protocol.
accepted TCP connection; the `Connection` objects will be chained together Therefore the `ProxyConnection` will handle the PROXY protocol bytes and `HttpConnection` will handle the HTTP/1.1 bytes producing a request object and response object that will be processed by ``Handler``s.
to handle the bytes, each for its own protocol.
Therefore the `ProxyConnection` will handle the PROXY protocol bytes and
`HttpConnection` will handle the HTTP/1.1 bytes producing a request object
and response object that will be processed by ``Handler``s.
[[eg-server-http-connector-protocol-http2]] [[eg-server-http-connector-protocol-http2]]
===== Configuring HTTP/2 ===== Configuring HTTP/2
It is well known that the HTTP ports are `80` (for clear-text HTTP) and `443` It is well known that the HTTP ports are `80` (for clear-text HTTP) and `443` for encrypted HTTP.
for encrypted HTTP. By using those ports, a client had _prior knowledge_ that the server would speak, respectively, the HTTP/1.x protocol and the TLS protocol (and, after decryption, the HTTP/1.x protocol).
By using those ports, a client had _prior knowledge_ that the server would
speak, respectively, the HTTP/1.x protocol and the TLS protocol (and, after
decryption, the HTTP/1.x protocol).
HTTP/2 was designed to be a smooth transition from HTTP/1.1 for users and HTTP/2 was designed to be a smooth transition from HTTP/1.1 for users and as such the HTTP ports were not changed.
as such the HTTP ports were not changed. However the HTTP/2 protocol is, on the wire, a binary protocol, completely different from HTTP/1.1.
However the HTTP/2 protocol is, on the wire, a binary protocol, completely Therefore, with HTTP/2, clients that connect to port `80` may speak either HTTP/1.1 or HTTP/2, and the server must figure out which version of the HTTP protocol the client is speaking.
different from HTTP/1.1.
Therefore, with HTTP/2, clients that connect to port `80` may speak either
HTTP/1.1 or HTTP/2, and the server must figure out which version of the HTTP
protocol the client is speaking.
Jetty can support both HTTP/1.1 and HTTP/2 on the same clear-text port by Jetty can support both HTTP/1.1 and HTTP/2 on the same clear-text port by configuring both the HTTP/1.1 and the HTTP/2 ``ConnectionFactory``s:
configuring both the HTTP/1.1 and the HTTP/2 ``ConnectionFactory``s:
[source,java,indent=0] [source,java,indent=0]
---- ----
include::../../{doc_code}/embedded/server/http/HTTPServerDocs.java[tags=http11H2C] include::../../{doc_code}/embedded/server/http/HTTPServerDocs.java[tags=http11H2C]
---- ----
Note how the ``ConnectionFactory``s passed to `ServerConnector` are in order: Note how the ``ConnectionFactory``s passed to `ServerConnector` are in order: first HTTP/1.1, then HTTP/2.
first HTTP/1.1, then HTTP/2. This is necessary to support both protocols on the same port: Jetty will start parsing the incoming bytes as HTTP/1.1, but then realize that they are HTTP/2 bytes and will therefore _upgrade_ from HTTP/1.1 to HTTP/2.
This is necessary to support both protocols on the same port: Jetty will
start parsing the incoming bytes as HTTP/1.1, but then realize that they
are HTTP/2 bytes and will therefore _upgrade_ from HTTP/1.1 to HTTP/2.
This configuration is also typical when Jetty is installed in backend servers This configuration is also typical when Jetty is installed in backend servers behind a load balancer that also takes care of offloading TLS.
behind a load balancer that also takes care of offloading TLS. When Jetty is behind a load balancer, you can always prepend the PROXY protocol as described in xref:eg-server-http-connector-protocol-proxy-http11[this section].
When Jetty is behind a load balancer, you can always prepend the PROXY
protocol as described in
xref:eg-server-http-connector-protocol-proxy-http11[this section].
When using encrypted HTTP/2, the unencrypted protocol is negotiated by client When using encrypted HTTP/2, the unencrypted protocol is negotiated by client and server using an extension to the TLS protocol called ALPN.
and server using an extension to the TLS protocol called ALPN.
Jetty supports ALPN and encrypted HTTP/2 with this configuration: Jetty supports ALPN and encrypted HTTP/2 with this configuration:
@ -186,10 +134,7 @@ Jetty supports ALPN and encrypted HTTP/2 with this configuration:
include::../../{doc_code}/embedded/server/http/HTTPServerDocs.java[tags=tlsALPNHTTP] include::../../{doc_code}/embedded/server/http/HTTPServerDocs.java[tags=tlsALPNHTTP]
---- ----
Note how the ``ConnectionFactory``s passed to `ServerConnector` are in order: Note how the ``ConnectionFactory``s passed to `ServerConnector` are in order: TLS, ALPN, HTTP/1.1, HTTP/2.
TLS, ALPN, HTTP/1.1, HTTP/2.
Jetty starts parsing TLS bytes so that it can obtain the ALPN extension. Jetty starts parsing TLS bytes so that it can obtain the ALPN extension.
With the ALPN extension information, Jetty can negotiate a protocol and With the ALPN extension information, Jetty can negotiate a protocol and pick, among the ``ConnectionFactory``s supported by the `ServerConnector`, the `ConnectionFactory` correspondent to the negotiated protocol.
pick, among the ``ConnectionFactory``s supported by the `ServerConnector`,
the `ConnectionFactory` correspondent to the negotiated protocol.

View File

@ -28,16 +28,10 @@ include::../../{doc_code}/embedded/server/http/HTTPServerDocs.java[tags=handlerA
The `target` parameter is an identifier for the resource. The `target` parameter is an identifier for the resource.
This is normally the URI that is parsed from an HTTP request. This is normally the URI that is parsed from an HTTP request.
However, a request could be forwarded to either a named resource, in which case However, a request could be forwarded to either a named resource, in which case `target` will be the name of the resource, or to a different URI, in which case `target` will be the new URI.
`target` will be the name of the resource, or to a different URI, in which case
`target` will be the new URI.
Applications may wrap the request or response (or both) and forward the wrapped Applications may wrap the request or response (or both) and forward the wrapped request or response to a different URI (which may be possibly handled by a different `Handler`).
request or response to a different URI (which may be possibly handled by a This is the reason why there are two request parameters in the `Handler` APIs: the first is the unwrapped, original, request while the second is the application-wrapped request.
different `Handler`).
This is the reason why there are two request parameters in the `Handler` APIs:
the first is the unwrapped, original, request while the second is the
application-wrapped request.
[[eg-server-http-handler-impl-hello]] [[eg-server-http-handler-impl-hello]]
===== Hello World Handler ===== Hello World Handler
@ -49,23 +43,17 @@ A simple "Hello World" `Handler` is the following:
include::../../{doc_code}/embedded/server/http/HTTPServerDocs.java[tags=handlerHello] include::../../{doc_code}/embedded/server/http/HTTPServerDocs.java[tags=handlerHello]
---- ----
Such a simple `Handler` extends from `AbstractHandler` and can access the Such a simple `Handler` extends from `AbstractHandler` and can access the request and response main features, such as reading request headers and content, or writing response headers and content.
request and response main features, such as reading request headers and
content, or writing response headers and content.
[[eg-server-http-handler-impl-filter]] [[eg-server-http-handler-impl-filter]]
===== Filtering Handler ===== Filtering Handler
A filtering `Handler` is a handler that perform some modification to the A filtering `Handler` is a handler that perform some modification to the request or response, and then either forwards the request to another `Handler` or produces an error response:
request or response, and then either forwards the request to another
`Handler` or produces an error response:
[source,java,indent=0] [source,java,indent=0]
---- ----
include::../../{doc_code}/embedded/server/http/HTTPServerDocs.java[tags=handlerFilter] include::../../{doc_code}/embedded/server/http/HTTPServerDocs.java[tags=handlerFilter]
---- ----
Note how a filtering `Handler` extends from `HandlerWrapper` and as such Note how a filtering `Handler` extends from `HandlerWrapper` and as such needs another handler to forward the request processing to, and how the two ``Handler``s needs to be linked together to work properly.
needs another handler to forward the request processing to, and how the
two ``Handler``s needs to be linked together to work properly.

View File

@ -19,52 +19,31 @@
[[eg-server-http-handler-use]] [[eg-server-http-handler-use]]
==== Using Provided Handlers ==== Using Provided Handlers
Web applications are the unit of deployment in an HTTP server or Servlet Web applications are the unit of deployment in an HTTP server or Servlet container such as Jetty.
container such as Jetty.
Two different web applications are typically deployed on different Two different web applications are typically deployed on different __context path__s, where a _context path_ is the initial segment of the URI path.
__context path__s, where a _context path_ is the initial segment of the URI For example, web application `webappA` that implements a web user interface for an e-commerce site may be deployed to context path `/shop`, while web application `webappB` that implements a REST API for the e-commerce business may be deployed to `/api`.
path.
For example, web application `webappA` that implements a web user interface
for an e-commerce site may be deployed to context path `/shop`, while web
application `webappB` that implements a REST API for the e-commerce business
may be deployed to `/api`.
A client making a request to URI `/shop/cart` is directed by Jetty to A client making a request to URI `/shop/cart` is directed by Jetty to `webappA`, while a request to URI `/api/products` is directed to `webappB`.
`webappA`, while a request to URI `/api/products` is directed to `webappB`.
An alternative way to deploy the two web applications of the example above An alternative way to deploy the two web applications of the example above is to use _virtual hosts_.
is to use _virtual hosts_. A _virtual host_ is a subdomain of the primary domain that shares the same IP address with the primary domain.
A _virtual host_ is a subdomain of the primary domain that shares the same If the e-commerce business primary domain is `domain.com`, then a virtual host for `webappA` could be `shop.domain.com`, while a virtual host for `webappB` could be `api.domain.com`.
IP address with the primary domain.
If the e-commerce business primary domain is `domain.com`, then a virtual
host for `webappA` could be `shop.domain.com`, while a virtual host for
`webappB` could be `api.domain.com`.
Web application `webappA` can now be deployed to virtual host Web application `webappA` can now be deployed to virtual host `shop.domain.com` and context path `/`, while web application `webappB` can be deployed to virtual host `api.domain.com` and context path `/`.
`shop.domain.com` and context path `/`, while web application `webappB` Both applications have the same context path `/`, but they can be distinguished by the subdomain.
can be deployed to virtual host `api.domain.com` and context path `/`.
Both applications have the same context path `/`, but they can be
distinguished by the subdomain.
A client making a request to `+https://shop.domain.com/cart+` is A client making a request to `+https://shop.domain.com/cart+` is directed by Jetty to `webappA`, while a request to `+https://api.domain.com/products+` is directed to `webappB`.
directed by Jetty to `webappA`, while a request to
`+https://api.domain.com/products+` is directed to `webappB`.
Therefore, in general, a web application is deployed to a _context_ Therefore, in general, a web application is deployed to a _context_ which can be seen as the pair `(virtual_host, context_path)`.
which can be seen as the pair `(virtual_host, context_path)`. In the first case the contexts were `(domain.com, /shop)` and `(domain.com, /api)`, while in the second case the contexts were `(shop.domain.com, /)` and `(api.domain.com, /)`.
In the first case the contexts were `(domain.com, /shop)` and Server applications using the Jetty Server Libraries create and configure a _context_ for each web application.
`(domain.com, /api)`, while in the second case the contexts were
`(shop.domain.com, /)` and `(api.domain.com, /)`.
Server applications using the Jetty Server Libraries create and
configure a _context_ for each web application.
[[eg-server-http-handler-use-context]] [[eg-server-http-handler-use-context]]
===== ContextHandler ===== ContextHandler
`ContextHandler` is a `Handler` that represents a _context_ for a web `ContextHandler` is a `Handler` that represents a _context_ for a web application.
application. It is a `HandlerWrapper` that performs some action before It is a `HandlerWrapper` that performs some action before and after delegating to the nested `Handler`.
and after delegating to the nested `Handler`.
// TODO: expand on what the ContextHandler does, e.g. ServletContext. // TODO: expand on what the ContextHandler does, e.g. ServletContext.
The simplest use of `ContextHandler` is the following: The simplest use of `ContextHandler` is the following:
@ -88,22 +67,14 @@ Server
Server applications may need to deploy to Jetty more than one web application. Server applications may need to deploy to Jetty more than one web application.
Recall from the xref:eg-server-http-handler[introduction] that Jetty offers Recall from the xref:eg-server-http-handler[introduction] that Jetty offers `HandlerCollection` and `HandlerList` that may contain a sequence of children ``Handler``s.
`HandlerCollection` and `HandlerList` that may contain a sequence of children However, both of these have no knowledge of the concept of _context_ and just iterate through the sequence of ``Handler``s.
``Handler``s.
However, both of these have no knowledge of the concept of _context_ and just
iterate through the sequence of ``Handler``s.
A better choice for multiple web application is `ContextHandlerCollection`, A better choice for multiple web application is `ContextHandlerCollection`, that matches a _context_ from either its _context path_ or _virtual host_, without iterating through the ``Handler``s.
that matches a _context_ from either its _context path_ or _virtual host_,
without iterating through the ``Handler``s.
If `ContextHandlerCollection` does not find a match, it just returns. If `ContextHandlerCollection` does not find a match, it just returns.
What happens next depends on the `Handler` tree structure: other ``Handler``s What happens next depends on the `Handler` tree structure: other ``Handler``s may be invoked after `ContextHandlerCollection`, for example `DefaultHandler` (see xref:eg-server-http-handler-use-util-default-handler[this section]).
may be invoked after `ContextHandlerCollection`, for example `DefaultHandler` Eventually, if `Request.setHandled(true)` is not called, Jetty returns an HTTP `404` response to the client.
(see xref:eg-server-http-handler-use-util-default-handler[this section]).
Eventually, if `Request.setHandled(true)` is not called, Jetty returns a HTTP
`404` response to the client.
[source,java,indent=0] [source,java,indent=0]
---- ----
@ -125,11 +96,9 @@ Server
[[eg-server-http-handler-use-servlet-context]] [[eg-server-http-handler-use-servlet-context]]
===== ServletContextHandler ===== ServletContextHandler
``Handler``s are easy to write, but often web applications have already been ``Handler``s are easy to write, but often web applications have already been written using the Servlet APIs, using ``Servlet``s and ``Filter``s.
written using the Servlet APIs, using ``Servlet``s and ``Filter``s.
`ServletContextHandler` is a `ContextHandler` that provides support for the `ServletContextHandler` is a `ContextHandler` that provides support for the Servlet APIs and implements the behaviors required by the Servlet specification.
Servlet APIs and implements the behaviors required by the Servlet specification.
The Maven artifact coordinates are: The Maven artifact coordinates are:
@ -157,36 +126,23 @@ Server
└── _CrossOriginFilter /*_ └── _CrossOriginFilter /*_
---- ----
Note how the Servlet components (they are not ``Handler``s) are represented in Note how the Servlet components (they are not ``Handler``s) are represented in _italic_.
_italic_.
Note also how adding a `Servlet` or a `Filter` returns a _holder_ object that Note also how adding a `Servlet` or a `Filter` returns a _holder_ object that can be used to specify additional configuration for that particular `Servlet` or `Filter`.
can be used to specify additional configuration for that particular `Servlet`
or `Filter`.
When a request arrives to `ServletContextHandler` the request URI will be When a request arrives to `ServletContextHandler` the request URI will be matched against the ``Filter``s and ``Servlet`` mappings and only those that match will process the request, as dictated by the Servlet specification.
matched against the ``Filter``s and ``Servlet`` mappings and only those that
match will process the request, as dictated by the Servlet specification.
IMPORTANT: `ServletContextHandler` is a terminal `Handler`, that is it always IMPORTANT: `ServletContextHandler` is a terminal `Handler`, that is it always calls `Request.setHandled(true)` when invoked.
calls `Request.setHandled(true)` when invoked. Server applications must be careful when creating the `Handler` tree to put ``ServletContextHandler``s as last ``Handler``s in a `HandlerList` or as children of `ContextHandlerCollection`.
Server applications must be careful when creating the `Handler`
tree to put ``ServletContextHandler``s as last ``Handler``s in a `HandlerList`
or as children of `ContextHandlerCollection`.
[[eg-server-http-handler-use-webapp-context]] [[eg-server-http-handler-use-webapp-context]]
===== WebAppContext ===== WebAppContext
`WebAppContext` is a `ServletContextHandler` that auto configures itself by `WebAppContext` is a `ServletContextHandler` that auto configures itself by reading a `web.xml` Servlet configuration file.
reading a `web.xml` Servlet configuration file.
Server applications can specify a `+*.war+` file or a directory with the Server applications can specify a `+*.war+` file or a directory with the structure of a `+*.war+` file to `WebAppContext` to deploy a standard Servlet web application packaged as a `war` (as defined by the Servlet specification).
structure of a `+*.war+` file to `WebAppContext` to deploy a standard Servlet
web application packaged as a `war` (as defined by the Servlet specification).
Where server applications using `ServletContextHandler` must manually invoke Where server applications using `ServletContextHandler` must manually invoke methods to add ``Servlet``s and ``Filter``s, `WebAppContext` reads `WEB-INF/web.xml` to add ``Servlet``s and ``Filter``s.
methods to add ``Servlet``s and ``Filter``s, `WebAppContext` reads
`WEB-INF/web.xml` to add ``Servlet``s and ``Filter``s.
[source,java,indent=0] [source,java,indent=0]
---- ----
@ -196,45 +152,24 @@ include::../../{doc_code}/embedded/server/http/HTTPServerDocs.java[tags=webAppCo
[[eg-server-http-handler-use-resource-handler]] [[eg-server-http-handler-use-resource-handler]]
===== ResourceHandler -- Static Content ===== ResourceHandler -- Static Content
Static content such as images or files (HTML, JavaScript, CSS) can be sent Static content such as images or files (HTML, JavaScript, CSS) can be sent by Jetty very efficiently because Jetty can write the content asynchronously, using direct ``ByteBuffer``s to minimize data copy, and using a memory cache for faster access to the data to send.
by Jetty very efficiently because Jetty can write the content asynchronously,
using direct ``ByteBuffer``s to minimize data copy, and using a memory cache
for faster access to the data to send.
Being able to write content asynchronously means that if the network gets Being able to write content asynchronously means that if the network gets congested (for example, the client reads the content very slowly) and the server stalls the send of the requested data, then Jetty will wait to resume the send _without_ blocking a thread to finish the send.
congested (for example, the client reads the content very slowly) and the
server stalls the send of the requested data, then Jetty will wait to resume
the send _without_ blocking a thread to finish the send.
`ResourceHandler` supports the following features: `ResourceHandler` supports the following features:
* Welcome files, for example serving `/index.html` for request URI `/` * Welcome files, for example serving `/index.html` for request URI `/`
* Precompressed resources, serving a precompressed `/document.txt.gz` for * Precompressed resources, serving a precompressed `/document.txt.gz` for request URI `/document.txt`
request URI `/document.txt` * link:https://tools.ietf.org/html/rfc7233[Range requests], for requests containing the `Range` header, which allows clients to pause and resume downloads of large files
* link:https://tools.ietf.org/html/rfc7233[Range requests], for requests * Directory listing, serving a HTML page with the file list of the requested directory
containing the `Range` header, which allows clients to pause and resume * Conditional headers, for requests containing the `If-Match`, `If-None-Match`, `If-Modified-Since`, `If-Unmodified-Since` headers.
downloads of large files
* Directory listing, serving a HTML page with the file list of the requested
directory
* Conditional headers, for requests containing the `If-Match`, `If-None-Match`,
`If-Modified-Since`, `If-Unmodified-Since` headers.
The number of features supported and the efficiency in sending static content The number of features supported and the efficiency in sending static content are on the same level as those of common front-end servers used to serve static content such as Nginx or Apache.
are on the same level as those of common front-end servers used to serve Therefore, the traditional architecture where Nginx/Apache was the front-end server used only to send static content and Jetty was the back-end server used only to send dynamic content is somehow obsolete as Jetty can perform efficiently both tasks.
static content such as Nginx or Apache. This leads to simpler systems (less components to configure and manage) and more performance (no need to proxy dynamic requests from front-end servers to back-end servers).
Therefore, the traditional architecture where Nginx/Apache was the front-end
server used only to send static content and Jetty was the back-end server used
only to send dynamic content is somehow obsolete as Jetty can perform
efficiently both tasks.
This leads to simpler systems (less components to configure and manage) and
more performance (no need to proxy dynamic requests from front-end servers
to back-end servers).
NOTE: It is common to use Nginx/Apache as load balancers, or as rewrite/redirect NOTE: It is common to use Nginx/Apache as load balancers, or as rewrite/redirect servers.
servers. We typically recommend link:https://haproxy.org[HAProxy] as load We typically recommend link:https://haproxy.org[HAProxy] as load balancer, and Jetty has xref:eg-server-http-handler-use-util-rewrite-handler[rewrite/redirect features] as well.
balancer, and Jetty has
xref:eg-server-http-handler-use-util-rewrite-handler[rewrite/redirect features]
as well.
This is how you configure a `ResourceHandler` to create a simple file server: This is how you configure a `ResourceHandler` to create a simple file server:
@ -250,19 +185,14 @@ If you need to serve static resources from multiple directories:
include::../../{doc_code}/embedded/server/http/HTTPServerDocs.java[tags=multipleResourcesHandler] include::../../{doc_code}/embedded/server/http/HTTPServerDocs.java[tags=multipleResourcesHandler]
---- ----
If the resource is not found, `ResourceHandler` will not call If the resource is not found, `ResourceHandler` will not call `Request.setHandled(true)` so what happens next depends on the `Handler` tree structure.
`Request.setHandled(true)` so what happens next depends on the `Handler` See also xref:eg-server-http-handler-use-util-default-handler[how to use] `DefaultHandler`.
tree structure. See also
xref:eg-server-http-handler-use-util-default-handler[how to use] `DefaultHandler`.
[[eg-server-http-handler-use-default-servlet]] [[eg-server-http-handler-use-default-servlet]]
===== DefaultServlet -- Static Content for Servlets ===== DefaultServlet -- Static Content for Servlets
If you have a If you have a xref:eg-server-http-handler-use-servlet-context[Servlet web application], you may want to use a `DefaultServlet` instead of `ResourceHandler`.
xref:eg-server-http-handler-use-servlet-context[Servlet web application], The features are similar, but `DefaultServlet` is more commonly used to serve static files for Servlet web applications.
you may want to use a `DefaultServlet` instead of `ResourceHandler`.
The features are similar, but `DefaultServlet` is more commonly used to
serve static files for Servlet web applications.
[source,java,indent=0] [source,java,indent=0]
---- ----
@ -272,15 +202,10 @@ include::../../{doc_code}/embedded/server/http/HTTPServerDocs.java[tags=defaultS
[[eg-server-http-handler-use-util-gzip-handler]] [[eg-server-http-handler-use-util-gzip-handler]]
===== GzipHandler ===== GzipHandler
`GzipHandler` provides supports for automatic decompression of compressed `GzipHandler` provides supports for automatic decompression of compressed request content and automatic compression of response content.
request content and automatic compression of response content.
`GzipHandler` is a `HandlerWrapper` that inspects the request and, if the `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.
request matches the `GzipHandler` configuration, just installs the required The decompression/compression is not performed until the web application reads request content or writes response content.
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: `GzipHandler` can be configured at the server level in this way:
@ -301,10 +226,7 @@ Server
└── ContextHandler N └── ContextHandler N
---- ----
However, in less common cases, you can configure `GzipHandler` on a However, in less common cases, you can configure `GzipHandler` on a per-context basis, for example because you want to configure `GzipHandler` with different parameters for each context, or because you want only some contexts to have compression support:
per-context basis, for example because you want to configure `GzipHandler`
with different parameters for each context, or because you want only some
contexts to have compression support:
[source,java,indent=0] [source,java,indent=0]
---- ----
@ -330,10 +252,7 @@ Server
[[eg-server-http-handler-use-util-rewrite-handler]] [[eg-server-http-handler-use-util-rewrite-handler]]
===== RewriteHandler ===== RewriteHandler
`RewriteHandler` provides support for URL rewriting, very similarly to `RewriteHandler` provides support for URL rewriting, very similarly to link:https://httpd.apache.org/docs/current/mod/mod_rewrite.html[Apache's mod_rewrite] or link:https://nginx.org/en/docs/http/ngx_http_rewrite_module.html[Nginx rewrite module].
link:https://httpd.apache.org/docs/current/mod/mod_rewrite.html[Apache's mod_rewrite]
or
link:https://nginx.org/en/docs/http/ngx_http_rewrite_module.html[Nginx rewrite module].
The Maven artifact coordinates are: The Maven artifact coordinates are:
@ -346,20 +265,13 @@ The Maven artifact coordinates are:
</dependency> </dependency>
---- ----
`RewriteHandler` can be configured with a set of __rule__s; a _rule_ inspects `RewriteHandler` can be configured with a set of __rule__s; a _rule_ inspects the request and when it matches it performs some change to the request (for example, changes the URI path, adds/removes headers, etc.).
the request and when it matches it performs some change to the request (for
example, changes the URI path, adds/removes headers, etc.).
The Jetty Server Libraries provide rules for the most common usages, but you The Jetty Server Libraries provide rules for the most common usages, but you can write your own rules by extending the `org.eclipse.jetty.rewrite.handler.Rule` class.
can write your own rules by extending the
`org.eclipse.jetty.rewrite.handler.Rule` class.
Please refer to the `jetty-rewrite` module Please refer to the `jetty-rewrite` module link:{JDURL}/org/eclipse/jetty/rewrite/handler/package-summary.html[javadocs] for the complete list of available rules.
link:{JDURL}/org/eclipse/jetty/rewrite/handler/package-summary.html[javadocs]
for the complete list of available rules.
You typically want to configure `RewriteHandler` at the server level, although You typically want to configure `RewriteHandler` at the server level, although it is possible to configure it on a per-context basis.
it is possible to configure it on a per-context basis.
[source,java,indent=0] [source,java,indent=0]
---- ----
@ -381,22 +293,18 @@ Server
[[eg-server-http-handler-use-util-stats-handler]] [[eg-server-http-handler-use-util-stats-handler]]
===== StatisticsHandler ===== StatisticsHandler
`StatisticsHandler` gathers and exposes a number of statistic values related `StatisticsHandler` gathers and exposes a number of statistic values related to request processing such as:
to request processing such as:
* Total number of requests * Total number of requests
* Current number of concurrent requests * Current number of concurrent requests
* Minimum, maximum, average and standard deviation of request processing times * Minimum, maximum, average and standard deviation of request processing times
* Number of responses grouped by HTTP code (i.e. how many `2xx` responses, how * Number of responses grouped by HTTP code (i.e. how many `2xx` responses, how many `3xx` responses, etc.)
many `3xx` responses, etc.)
* Total response content bytes * Total response content bytes
Server applications can read these values and use them internally, or expose Server applications can read these values and use them internally, or expose them via some service, or export them via JMX.
them via some service, or export them via JMX.
// TODO: xref to the JMX section. // TODO: xref to the JMX section.
`StatisticsHandler` can be configured at the server level or at the context `StatisticsHandler` can be configured at the server level or at the context level.
level.
[source,java,indent=0] [source,java,indent=0]
---- ----
@ -418,19 +326,13 @@ Server
[[eg-server-http-handler-use-util-secure-handler]] [[eg-server-http-handler-use-util-secure-handler]]
===== SecuredRedirectHandler -- Redirect from HTTP to HTTPS ===== SecuredRedirectHandler -- Redirect from HTTP to HTTPS
`SecuredRedirectHandler` allows to redirect requests made with the `http` `SecuredRedirectHandler` allows to redirect requests made with the `http` scheme (and therefore to the clear-text port) to the `https` scheme (and therefore to the encrypted port).
scheme (and therefore to the clear-text port) to the `https` scheme (and
therefore to the encrypted port).
For example a request to `+http://domain.com:8080/path?param=value+` is For example a request to `+http://domain.com:8080/path?param=value+` is redirected to `+https://domain.com:8443/path?param=value+`.
redirected to `+https://domain.com:8443/path?param=value+`.
Server applications must configure a `HttpConfiguration` object with the Server applications must configure a `HttpConfiguration` object with the secure scheme and secure port so that `SecuredRedirectHandler` can build the redirect URI.
secure scheme and secure port so that `SecuredRedirectHandler` can build
the redirect URI.
`SecuredRedirectHandler` is typically configured at the server level, `SecuredRedirectHandler` is typically configured at the server level, although it can be configured on a per-context basis.
although it can be configured on a per-context basis.
[source,java,indent=0] [source,java,indent=0]
---- ----
@ -440,16 +342,13 @@ include::../../{doc_code}/embedded/server/http/HTTPServerDocs.java[tags=securedH
[[eg-server-http-handler-use-util-default-handler]] [[eg-server-http-handler-use-util-default-handler]]
===== DefaultHandler ===== DefaultHandler
`DefaultHandler` is a terminal `Handler` that always calls `DefaultHandler` is a terminal `Handler` that always calls `Request.setHandled(true)` and performs the following:
`Request.setHandled(true)` and performs the following:
* Serves the `favicon.ico` Jetty icon when it is requested * Serves the `favicon.ico` Jetty icon when it is requested
* Sends a HTTP `404` response for any other request * Sends a HTTP `404` response for any other request
* The HTTP `404` response content nicely shows a HTML table with all the * The HTTP `404` response content nicely shows a HTML table with all the contexts deployed on the `Server` instance
contexts deployed on the `Server` instance
`DefaultHandler` is best used as the last `Handler` of a `HandlerList`, `DefaultHandler` is best used as the last `Handler` of a `HandlerList`, for example:
for example:
[source,java,indent=0] [source,java,indent=0]
---- ----
@ -469,12 +368,7 @@ Server
└── DefaultHandler └── DefaultHandler
---- ----
In the example above, `ContextHandlerCollection` will try to match a request 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`.
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`.
NOTE: `DefaultHandler` just sends a nicer HTTP `404` response in case of NOTE: `DefaultHandler` just sends a nicer HTTP `404` response in case of wrong requests from clients.
wrong requests from clients. Jetty will send an HTTP `404` response anyway if `DefaultHandler` is not used.
Jetty will send an HTTP `404` response anyway if `DefaultHandler` is not
used.

View File

@ -19,31 +19,21 @@
[[eg-server-http-handler]] [[eg-server-http-handler]]
=== Server Handlers === Server Handlers
An `org.eclipse.jetty.server.Handler` is the component that processes An `org.eclipse.jetty.server.Handler` is the component that processes incoming HTTP requests and eventually produces HTTP responses.
incoming HTTP requests and eventually produces HTTP responses.
``Handler``s can be organized in different ways: ``Handler``s can be organized in different ways:
* in a sequence, where ``Handler``s are invoked one after the other * in a sequence, where ``Handler``s are invoked one after the other
** `HandlerCollection` invokes _all_ ``Handler``s one after the other ** `HandlerCollection` invokes _all_ ``Handler``s one after the other
** `HandlerList` invokes ``Handlers``s until one calls `Request.setHandled(true)` ** `HandlerList` invokes ``Handlers``s until one calls `Request.setHandled(true)` to indicate that the request has been handled and no further `Handler` should be invoked
to indicate that the request has been handled and no further `Handler` should
be invoked
* nested, where one `Handler` invokes the next, nested, `Handler` * nested, where one `Handler` invokes the next, nested, `Handler`
** `HandlerWrapper` implements this behavior ** `HandlerWrapper` implements this behavior
The `HandlerCollection` behavior (invoking _all_ handlers) is useful when The `HandlerCollection` behavior (invoking _all_ handlers) is useful when for example the last `Handler` is a logging `Handler` that logs the request(that may have been modified by previous handlers).
for example the last `Handler` is a logging `Handler` that logs the request
(that may have been modified by previous handlers).
The `HandlerList` behavior (invoking handlers up to the first that calls The `HandlerList` behavior (invoking handlers up to the first that calls `Request.setHandled(true)`) is useful when each handler processes a different URIs or a different virtual hosts: ``Handler``s are invoked one after the other until one matches the URI or virtual host.
`Request.setHandled(true)`) is useful when each handler processes a different
URIs or a different virtual hosts: ``Handler``s are invoked one after the
other until one matches the URI or virtual host.
The nested behavior is useful to enrich the request with additional services The nested behavior is useful to enrich the request with additional services such as HTTP session support (`SessionHandler`), or with specific behaviors dictated by the Servlet specification (`ServletHandler`).
such as HTTP session support (`SessionHandler`), or with specific behaviors
dictated by the Servlet specification (`ServletHandler`).
``Handler``s can be organized in a tree by composing them together: ``Handler``s can be organized in a tree by composing them together:
@ -64,40 +54,12 @@ HandlerCollection
└── LoggingHandler └── LoggingHandler
---- ----
//// Server applications should rarely write custom ``Handler``s, preferring instead to use existing ``Handler``s provided by the Jetty Server Libraries for managing web application contexts, security, HTTP sessions and Servlet support.
PlantUML cannot render a tree left-aligned :( Refer to xref:eg-server-http-handler-use[this section] for more information about how to use the ``Handler``s provided by the Jetty Server Libraries.
[plantuml]
----
skinparam backgroundColor transparent
skinparam monochrome true
skinparam shadowing false
skinparam padding 5
scale 1.5 However, in some cases the additional features are not required, or additional constraints on memory footprint, or performance, or just simplicity must be met.
hide members
hide circle
HandlerCollection -- HandlerList
HandlerCollection -- LoggingHandler
HandlerList -- App1Handler
HandlerList -- App2Handler
App2Handler -- ServletHandler
----
////
Server applications should rarely write custom ``Handler``s, preferring
instead to use existing ``Handler``s provided by the Jetty Server Libraries
for managing web application contexts, security, HTTP sessions and Servlet
support.
Refer to xref:eg-server-http-handler-use[this section] for more information about
how to use the ``Handler``s provided by the Jetty Server Libraries.
However, in some cases the additional features are not required, or additional
constraints on memory footprint, or performance, or just simplicity must be met.
In these cases, implementing your own `Handler` may be a better solution. In these cases, implementing your own `Handler` may be a better solution.
Refer to xref:eg-server-http-handler-implement[this section] for more information Refer to xref:eg-server-http-handler-implement[this section] for more information about how to write your own ``Handler``s.
about how to write your own ``Handler``s.
include::server-http-handler-use.adoc[] include::server-http-handler-use.adoc[]
include::server-http-handler-implement.adoc[] include::server-http-handler-implement.adoc[]

View File

@ -19,8 +19,7 @@
[[eg-server-http]] [[eg-server-http]]
=== HTTP Server Libraries === HTTP Server Libraries
The Eclipse Jetty Project has historically provided libraries to embed an HTTP The Eclipse Jetty Project has historically provided libraries to embed an HTTP server and a Servlet Container.
server and a Servlet Container.
The Maven artifact coordinates are: The Maven artifact coordinates are:
@ -33,9 +32,7 @@ The Maven artifact coordinates are:
</dependency> </dependency>
---- ----
An `org.eclipse.jetty.server.Server` instance is the central component that An `org.eclipse.jetty.server.Server` instance is the central component that links together a collection of ``Connector``s and a collection of ``Handler``s, with threads from a `ThreadPool` doing the work.
links together a collection of ``Connector``s and a collection of
``Handler``s, with threads from a `ThreadPool` doing the work.
[plantuml] [plantuml]
---- ----
@ -54,12 +51,9 @@ Connectors - Server
Server -- Handlers Server -- Handlers
---- ----
The components that accept connections from clients are The components that accept connections from clients are `org.eclipse.jetty.server.Connector` implementations.
`org.eclipse.jetty.server.Connector` implementations.
When a Jetty server interprets the HTTP protocol (both HTTP/1.1 and HTTP/2), When a Jetty server interprets the HTTP protocol (both HTTP/1.1 and HTTP/2), it uses `org.eclipse.jetty.server.Handler` instances to process incoming requests and eventually produce responses.
it uses `org.eclipse.jetty.server.Handler` instances to process incoming
requests and eventually produce responses.
A `Server` must be created, configured and started: A `Server` must be created, configured and started:
@ -68,41 +62,27 @@ A `Server` must be created, configured and started:
include::../../{doc_code}/embedded/server/http/HTTPServerDocs.java[tags=simple] include::../../{doc_code}/embedded/server/http/HTTPServerDocs.java[tags=simple]
---- ----
The example above shows the simplest HTTP/1.1 server; it has no support for The example above shows the simplest HTTP/1.1 server; it has no support for HTTP sessions, for HTTP authentication, or for any of the features required by the Servlet specification.
HTTP sessions, for HTTP authentication, or for any of the features required
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 all the required features, and it is discussed in details in xref:eg-server-http-handler-use[this section].
applications only need to put the required components together to provide
all the required features, and it is discussed in details in
xref:eg-server-http-handler-use[this section].
[[eg-server-http-request-processing]] [[eg-server-http-request-processing]]
==== Server Request Processing ==== Server Request Processing
The Jetty HTTP request processing is outlined below in the diagram below. The Jetty HTTP request processing is outlined below in the diagram below.
Request handing is slightly different for each protocol; in HTTP/2 Jetty 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.
takes into account multiplexing, something that is not present in HTTP/1.1.
However, the diagram below captures the essence of request handling that However, the diagram below captures the essence of request handling that is common among all protocols that carry HTTP requests.
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. 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()`, 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`.
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, 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.
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.
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`. that in turn are converted into method calls to `HttpChannel`.
When enough of the HTTP request is arrived, the `Connection` calls 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.
`HttpChannel.handle()` that calls the `Handler` chain, that eventually
calls the server application code.
[plantuml] [plantuml]
---- ----
@ -133,23 +113,15 @@ Server -> Handlers : handle()
===== HttpChannel Events ===== HttpChannel Events
The central component processing HTTP requests is `HttpChannel`. The central component processing HTTP requests is `HttpChannel`.
There is a 1-to-1 relationship between an HTTP request/response and an 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).
`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 Advanced server applications may be interested in the progress of the processing of an HTTP request/response by `HttpChannel`.
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.
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 NOTE: A `Handler` or a Servlet `Filter` may not report precisely when an HTTP request/response processing is finished.
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.
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 `HttpChannel` notifies ``HttpChannel.Listener``s of the progress of the HTTP request/response handling.
HTTP request/response handling.
Currently, the following events are available: Currently, the following events are available:
* `requestBegin` * `requestBegin`
@ -167,12 +139,9 @@ Currently, the following events are available:
* `responseEnd` * `responseEnd`
* `complete` * `complete`
Please refer to the `HttpChannel.Listener` Please refer to the `HttpChannel.Listener` link:{JDURL}/org/eclipse/jetty/server/HttpChannel.Listener.html[javadocs] for the complete list of events.
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 Server applications can register `HttpChannel.Listener` by adding them as beans to the `Connector`:
beans to the `Connector`:
[source,java,indent=0] [source,java,indent=0]
---- ----

View File

@ -19,14 +19,9 @@
[[eg-server-http2]] [[eg-server-http2]]
=== HTTP/2 Server Library === HTTP/2 Server Library
In the vast majority of cases, server applications should use the generic, In the vast majority of cases, server applications should use the generic, high-level, xref:eg-server-http[HTTP server library] that also provides HTTP/2 support via the HTTP/2 ``ConnectionFactory``s as described in details xref:eg-server-http-connector-protocol-http2[here].
high-level, xref:eg-server-http[HTTP server library] that also provides
HTTP/2 support via the HTTP/2 ``ConnectionFactory``s as described in details
xref:eg-server-http-connector-protocol-http2[here].
The low-level HTTP/2 server library has been designed for those applications The low-level HTTP/2 server library has been designed for those applications that need low-level access to HTTP/2 features such as _sessions_, _streams_ and _frames_, and this is quite a rare use case.
that need low-level access to HTTP/2 features such as _sessions_, _streams_
and _frames_, and this is quite a rare use case.
See also the correspondent xref:eg-client-http2[HTTP/2 client library]. See also the correspondent xref:eg-client-http2[HTTP/2 client library].
@ -51,50 +46,34 @@ include::../../http2.adoc[tag=multiplex]
include::../../http2.adoc[tag=flowControl] include::../../http2.adoc[tag=flowControl]
How a server application should handle HTTP/2 flow control is discussed in How a server application should handle HTTP/2 flow control is discussed in details in xref:eg-server-http2-request[this section].
details in xref:eg-server-http2-request[this section].
[[eg-server-http2-setup]] [[eg-server-http2-setup]]
==== Server Setup ==== Server Setup
The low-level HTTP/2 support is provided by The low-level HTTP/2 support is provided by `org.eclipse.jetty.http2.server.RawHTTP2ServerConnectionFactory` and `org.eclipse.jetty.http2.api.server.ServerSessionListener`:
`org.eclipse.jetty.http2.server.RawHTTP2ServerConnectionFactory` and
`org.eclipse.jetty.http2.api.server.ServerSessionListener`:
[source,java,indent=0] [source,java,indent=0]
---- ----
include::../../{doc_code}/embedded/server/http2/HTTP2ServerDocs.java[tags=setup] include::../../{doc_code}/embedded/server/http2/HTTP2ServerDocs.java[tags=setup]
---- ----
Where server applications using the Where server applications using the xref:eg-server-http[high-level server library] deal with HTTP requests and responses in ``Handler``s, server applications using the low-level HTTP/2 server library deal directly with HTTP/2 __session__s, __stream__s and __frame__s in a `ServerSessionListener` implementation.
xref:eg-server-http[high-level server library] deal with HTTP
requests and responses in ``Handler``s, server applications using the
low-level HTTP/2 server library deal directly with HTTP/2 __session__s,
__stream__s and __frame__s in a `ServerSessionListener` implementation.
The `ServerSessionListener` interface defines a number of methods that are The `ServerSessionListener` interface defines a number of methods that are invoked by the implementation upon the occurrence of HTTP/2 events, and that server applications can override to react to those events.
invoked by the implementation upon the occurrence of HTTP/2 events, and that
server applications can override to react to those events.
Please refer to the `ServerSessionListener` Please refer to the `ServerSessionListener`link:{JDURL}/org/eclipse/jetty/http2/api/server/ServerSessionListener.html[javadocs] for the complete list of events.
link:{JDURL}/org/eclipse/jetty/http2/api/server/ServerSessionListener.html[javadocs]
for the complete list of events.
The first event is the _accept_ event and happens when a client opens a new The first event is the _accept_ event and happens when a client opens a new TCP connection to the server and the server accepts the connection.
TCP connection to the server and the server accepts the connection. This is the first occasion where server applications have access to the HTTP/2 `Session` object:
This is the first occasion where server applications have access to the HTTP/2
`Session` object:
[source,java,indent=0] [source,java,indent=0]
---- ----
include::../../{doc_code}/embedded/server/http2/HTTP2ServerDocs.java[tags=accept] include::../../{doc_code}/embedded/server/http2/HTTP2ServerDocs.java[tags=accept]
---- ----
After connecting to the server, a compliant HTTP/2 client must send the After connecting to the server, a compliant HTTP/2 client must send the link:https://tools.ietf.org/html/rfc7540#section-3.5[HTTP/2 client preface], and when the server receives it, it generates the _preface_ event on the server.
link:https://tools.ietf.org/html/rfc7540#section-3.5[HTTP/2 client preface], This is where server applications can customize the connection settings by returning a map of settings that the implementation will send to the client:
and when the server receives it, it generates the _preface_ event on the server.
This is where server applications can customize the connection settings by
returning a map of settings that the implementation will send to the client:
[source,java,indent=0] [source,java,indent=0]
---- ----
@ -104,13 +83,9 @@ include::../../{doc_code}/embedded/server/http2/HTTP2ServerDocs.java[tags=prefac
[[eg-server-http2-request]] [[eg-server-http2-request]]
==== Receiving a Request ==== Receiving a Request
Receiving an HTTP request from the client, and sending a response, creates Receiving an HTTP request from the client, and sending a response, creates a _stream_ that encapsulates the exchange of HTTP/2 frames that compose the request and the response.
a _stream_ that encapsulates the exchange of HTTP/2 frames that compose the
request and the response.
An HTTP request is made of a `HEADERS` frame, that carries the request method, An HTTP request is made of a `HEADERS` frame, that carries the request method, the request URI and the request headers, and optional `DATA` frames that carry the request content.
the request URI and the request headers, and optional `DATA` frames that carry
the request content.
Receiving the `HEADERS` frame opens the `Stream`: Receiving the `HEADERS` frame opens the `Stream`:
@ -119,11 +94,7 @@ Receiving the `HEADERS` frame opens the `Stream`:
include::../../{doc_code}/embedded/server/http2/HTTP2ServerDocs.java[tags=request] include::../../{doc_code}/embedded/server/http2/HTTP2ServerDocs.java[tags=request]
---- ----
Server applications should return a `Stream.Listener` implementation from Server applications should return a `Stream.Listener` implementation from `onNewStream(...)` to be notified of events generated by the client, such as `DATA` frames carrying request content, or a `RST_STREAM` frame indicating that the client wants to _reset_ the request, or an idle timeout event indicating that the client was supposed to send more frames but it did not.
`onNewStream(...)` to be notified of events generated by the client, such as
`DATA` frames carrying request content, or a `RST_STREAM` frame indicating
that the client wants to _reset_ the request, or an idle timeout event
indicating that the client was supposed to send more frames but it did not.
The example below shows how to receive request content: The example below shows how to receive request content:
@ -137,16 +108,11 @@ include::../../http2.adoc[tag=apiFlowControl]
[[eg-server-http2-response]] [[eg-server-http2-response]]
==== Sending a Response ==== Sending a Response
After receiving an HTTP request, a server application must send an HTTP After receiving an HTTP request, a server application must send an HTTP response.
response.
An HTTP response is typically composed of a `HEADERS` frame containing the An HTTP response is typically composed of a `HEADERS` frame containing the HTTP status code and the response headers, and optionally one or more `DATA` frames containing the response content bytes.
HTTP status code and the response headers, and optionally one or more `DATA`
frames containing the response content bytes.
The HTTP/2 protocol also supports response trailers (that is, headers that The HTTP/2 protocol also supports response trailers (that is, headers that are sent after the response content) that also are sent using a `HEADERS` frame.
are sent after the response content) that also are sent using a `HEADERS`
frame.
A server application can send a response in this way: A server application can send a response in this way:
@ -159,9 +125,7 @@ include::../../{doc_code}/embedded/server/http2/HTTP2ServerDocs.java[tags=respon
==== Resetting a Request ==== Resetting a Request
A server application may decide that it does not want to accept the request. A server application may decide that it does not want to accept the request.
For example, it may throttle the client because it sent too many requests in For example, it may throttle the client because it sent too many requests in a time window, or the request is invalid (and does not deserve a proper HTTP response), etc.
a time window, or the request is invalid (and does not deserve a proper HTTP
response), etc.
A request can be reset in this way: A request can be reset in this way:
@ -173,14 +137,10 @@ include::../../{doc_code}/embedded/server/http2/HTTP2ServerDocs.java[tags=reset;
[[eg-server-http2-push]] [[eg-server-http2-push]]
==== HTTP/2 Push of Resources ==== HTTP/2 Push of Resources
A server application may _push_ secondary resources related to a primary A server application may _push_ secondary resources related to a primary resource.
resource.
A client may inform the server that it does not accept pushed resources A client may inform the server that it does not accept pushed resources(see link:https://tools.ietf.org/html/rfc7540#section-8.2[this section] of the specification) via a `SETTINGS` frame.
(see link:https://tools.ietf.org/html/rfc7540#section-8.2[this section] Server applications must track `SETTINGS` frames and verify whether the client supports HTTP/2 push, and only push if the client supports it:
of the specification) via a `SETTINGS` frame.
Server applications must track `SETTINGS` frames and verify whether the
client supports HTTP/2 push, and only push if the client supports it:
[source,java,indent=0] [source,java,indent=0]
---- ----

View File

@ -19,11 +19,9 @@
[[eg-server-io-arch]] [[eg-server-io-arch]]
=== Server Libraries I/O Architecture === Server Libraries I/O Architecture
The Jetty server libraries provide the basic components and APIs to implement The Jetty server libraries provide the basic components and APIs to implement a network server.
a network server.
They build on the common xref:eg-io-arch[Jetty I/O Architecture] and provide server They build on the common xref:eg-io-arch[Jetty I/O Architecture] and provide server specific concepts.
specific concepts.
The main I/O server-side class is `org.eclipse.jetty.server.ServerConnector`. The main I/O server-side class is `org.eclipse.jetty.server.ServerConnector`.

View File

@ -19,31 +19,19 @@
[[eg-server]] [[eg-server]]
== Server Libraries == Server Libraries
The Eclipse Jetty Project provides server-side libraries The Eclipse Jetty Project provides server-side libraries that allow you to embed an HTTP or WebSocket server in your applications.
that allow you to embed an HTTP or WebSocket server in your applications.
A typical example is a HTTP server that needs to expose a REST endpoint. A typical example is a HTTP server that needs to expose a REST endpoint.
Another example is a proxy application that receives HTTP requests and Another example is a proxy application that receives HTTP requests and forwards them to third party services possibly using also the Jetty xref:eg-client[client libraries].
forwards them to third party services possibly using also the Jetty
xref:eg-client[client libraries].
While historically Jetty is an HTTP server, it is possible to use the Jetty While historically Jetty is an HTTP server, it is possible to use the Jetty server-side libraries to write a generic network server that interprets any network protocol (not only HTTP).
server-side libraries to write a generic network server that interprets
any network protocol (not only HTTP).
If you are interested in the low-level details of how the Eclipse Jetty If you are interested in the low-level details of how the Eclipse Jetty server libraries work, or are interested in writing a custom protocol, look at the xref:eg-server-io-arch[Server I/O Architecture].
server libraries work, or are interested in writing a custom protocol,
look at the xref:eg-server-io-arch[Server I/O Architecture].
The Jetty server-side libraries provide: The Jetty server-side libraries provide:
* HTTP support for HTTP/1.0, HTTP/1.1, HTTP/2, clear-text or encrypted, for * HTTP support for HTTP/1.0, HTTP/1.1, HTTP/2, clear-text or encrypted, for applications that want to embed Jetty as a generic HTTP server or proxy, via the xref:eg-server-http[HTTP libraries]
applications that want to embed Jetty as a generic HTTP server or proxy, * HTTP/2 low-level support, for applications that want to explicitly handle low-level HTTP/2 _sessions_, _streams_ and _frames_, via the xref:eg-server-http2[HTTP/2 libraries]
via the xref:eg-server-http[HTTP libraries] * WebSocket support, for applications that want to embed a WebSocket server, via the xref:eg-server-websocket[WebSocket libraries]
* HTTP/2 low-level support, for applications that want to explicitly handle
low-level HTTP/2 _sessions_, _streams_ and _frames_, via the
xref:eg-server-http2[HTTP/2 libraries]
* WebSocket support, for applications that want to embed a WebSocket server,
via the xref:eg-server-websocket[WebSocket libraries]
// TODO: add a section on lifecycle and the component tree. // TODO: add a section on lifecycle and the component tree.