From 35dce5f31510ce5a5d52010e76f624f3f0f46993 Mon Sep 17 00:00:00 2001 From: Simone Bordet Date: Fri, 10 Apr 2020 15:40:02 +0200 Subject: [PATCH] Improvements to the Jetty server documentation. Written connector and handler sections. Signed-off-by: Simone Bordet --- jetty-documentation/pom.xml | 41 +- .../client/http/client-http-cookie.adoc | 6 +- .../client/http/client-http-intro.adoc | 2 +- .../client/http/client-http-transport.adoc | 4 +- .../client/http2/client-http2.adoc | 4 +- .../embedded-guide/old_docs/server.adoc | 2 +- .../server/http/server-http-connector.adoc | 195 +++++++ .../http/server-http-handler-implement.adoc | 71 +++ .../server/http/server-http-handler-use.adoc | 464 +++++++++++++++++ .../server/http/server-http-handler.adoc | 103 ++++ .../server/http/server-http.adoc | 244 +-------- .../server/http2/server-http2.adoc | 22 + .../embedded-guide/server/server.adoc | 5 +- .../server/websocket/server-websocket.adoc | 22 + .../embedded/server/http/HTTPServerDocs.java | 488 +++++++++++++++++- .../jetty/server/handler/DefaultHandler.java | 2 +- .../handler/SecuredRedirectHandler.java | 4 +- 17 files changed, 1408 insertions(+), 271 deletions(-) create mode 100644 jetty-documentation/src/main/asciidoc/embedded-guide/server/http/server-http-connector.adoc create mode 100644 jetty-documentation/src/main/asciidoc/embedded-guide/server/http/server-http-handler-implement.adoc create mode 100644 jetty-documentation/src/main/asciidoc/embedded-guide/server/http/server-http-handler-use.adoc create mode 100644 jetty-documentation/src/main/asciidoc/embedded-guide/server/http/server-http-handler.adoc create mode 100644 jetty-documentation/src/main/asciidoc/embedded-guide/server/http2/server-http2.adoc create mode 100644 jetty-documentation/src/main/asciidoc/embedded-guide/server/websocket/server-websocket.adoc diff --git a/jetty-documentation/pom.xml b/jetty-documentation/pom.xml index e318d4a57b1..acf0277731c 100644 --- a/jetty-documentation/pom.xml +++ b/jetty-documentation/pom.xml @@ -1,24 +1,4 @@ - - org.eclipse.jetty @@ -63,6 +43,21 @@ jetty-servlet ${project.version} + + org.eclipse.jetty + jetty-servlets + ${project.version} + + + org.eclipse.jetty + jetty-rewrite + ${project.version} + + + org.eclipse.jetty + jetty-webapp + ${project.version} + org.eclipse.jetty jetty-alpn-server @@ -88,6 +83,12 @@ http2-http-client-transport ${project.version} + + org.eclipse.jetty + jetty-slf4j-impl + ${project.version} + compile + diff --git a/jetty-documentation/src/main/asciidoc/embedded-guide/client/http/client-http-cookie.adoc b/jetty-documentation/src/main/asciidoc/embedded-guide/client/http/client-http-cookie.adoc index 8c414de749f..c5b92f7c723 100644 --- a/jetty-documentation/src/main/asciidoc/embedded-guide/client/http/client-http-cookie.adoc +++ b/jetty-documentation/src/main/asciidoc/embedded-guide/client/http/client-http-cookie.adoc @@ -75,14 +75,14 @@ Jetty is compliant with link:https://tools.ietf.org/html/rfc6265[RFC6265], and a 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: -[source,subs="{sub-order}"] +[source,screen] ---- Set-Cookie: foo="bar;baz";Version=1;Path="/secur" ---- This was added to the HTTP Response as follows: -[source,java,subs="{sub-order}"] +[source,java] ---- protected void service(HttpServletRequest request, HttpServletResponse response) { @@ -95,7 +95,7 @@ protected void service(HttpServletRequest request, HttpServletResponse response) The introduction of RFC6265 has rendered this approach no longer possible; users are now required to encode cookie values that use these special characters. This can be done utilizing `javax.servlet.http.Cookie` as follows: -[source,java,subs="{sub-order}"] +[source,java] ---- javax.servlet.http.Cookie cookie = new Cookie("foo", URLEncoder.encode("bar;baz", "UTF-8")); ---- diff --git a/jetty-documentation/src/main/asciidoc/embedded-guide/client/http/client-http-intro.adoc b/jetty-documentation/src/main/asciidoc/embedded-guide/client/http/client-http-intro.adoc index ae1c4a364a3..ab78e59dedc 100644 --- a/jetty-documentation/src/main/asciidoc/embedded-guide/client/http/client-http-intro.adoc +++ b/jetty-documentation/src/main/asciidoc/embedded-guide/client/http/client-http-intro.adoc @@ -49,7 +49,7 @@ Out of the box features that you get with the Jetty HTTP client include: The Jetty artifact that provides the main HTTP client implementation is `jetty-client`. The Maven artifact coordinates are the following: -[source,xml,subs="{sub-order}"] +[source,xml,subs=normal] ---- org.eclipse.jetty diff --git a/jetty-documentation/src/main/asciidoc/embedded-guide/client/http/client-http-transport.adoc b/jetty-documentation/src/main/asciidoc/embedded-guide/client/http/client-http-transport.adoc index e5840c61390..5c59f5f8920 100644 --- a/jetty-documentation/src/main/asciidoc/embedded-guide/client/http/client-http-transport.adoc +++ b/jetty-documentation/src/main/asciidoc/embedded-guide/client/http/client-http-transport.adoc @@ -34,7 +34,7 @@ semantic objects that can be used by applications. The most common protocol format is HTTP/1.1, a textual protocol with lines separated by `\r\n`: -[source,screen,subs="{sub-order}"] +[source,screen] ---- GET /index.html HTTP/1.1\r\n Host: domain.com\r\n @@ -44,7 +44,7 @@ Host: domain.com\r\n However, the same request can be made using FastCGI, a binary protocol: -[source,screen,subs="{sub-order}"] +[source,screen] ---- x01 x01 x00 x01 x00 x08 x00 x00 x00 x01 x01 x00 x00 x00 x00 x00 diff --git a/jetty-documentation/src/main/asciidoc/embedded-guide/client/http2/client-http2.adoc b/jetty-documentation/src/main/asciidoc/embedded-guide/client/http2/client-http2.adoc index 546b61fa9fc..e7c48438eaa 100644 --- a/jetty-documentation/src/main/asciidoc/embedded-guide/client/http2/client-http2.adoc +++ b/jetty-documentation/src/main/asciidoc/embedded-guide/client/http2/client-http2.adoc @@ -38,7 +38,7 @@ _frames_, and this is quite a rare use case. The Maven artifact coordinates for the HTTP/2 client library are the following: -[source,xml,subs="{sub-order}"] +[source,xml,subs=normal] ---- org.eclipse.jetty.http2 @@ -198,7 +198,7 @@ In order to send a HTTP request to the server, the client must send a headers. Sending the `HEADERS` frame opens the `Stream`: -[source,java,indent=0,subs={sub-order}] +[source,java,indent=0,subs=normal] ---- include::../../{doc_code}/embedded/client/http2/HTTP2ClientDocs.java[tags=newStream] ---- diff --git a/jetty-documentation/src/main/asciidoc/embedded-guide/old_docs/server.adoc b/jetty-documentation/src/main/asciidoc/embedded-guide/old_docs/server.adoc index 82d815d7d1b..bfd8444bab5 100644 --- a/jetty-documentation/src/main/asciidoc/embedded-guide/old_docs/server.adoc +++ b/jetty-documentation/src/main/asciidoc/embedded-guide/old_docs/server.adoc @@ -17,7 +17,7 @@ // [[server]] -== Jetty Server Libraries +== OLD DOCUMENTATION include::embedding/chapter.adoc[] include::maven/chapter.adoc[] diff --git a/jetty-documentation/src/main/asciidoc/embedded-guide/server/http/server-http-connector.adoc b/jetty-documentation/src/main/asciidoc/embedded-guide/server/http/server-http-connector.adoc new file mode 100644 index 00000000000..d5598d5adeb --- /dev/null +++ b/jetty-documentation/src/main/asciidoc/embedded-guide/server/http/server-http-connector.adoc @@ -0,0 +1,195 @@ +// +// ======================================================================== +// Copyright (c) 1995-2020 Mort Bay Consulting Pty Ltd and others. +// +// This program and the accompanying materials are made available under +// the terms of the Eclipse Public License 2.0 which is available at +// https://www.eclipse.org/legal/epl-2.0 +// +// This Source Code may also be made available under the following +// Secondary Licenses when the conditions for such availability set +// forth in the Eclipse Public License, v. 2.0 are satisfied: +// the Apache License v2.0 which is available at +// https://www.apache.org/licenses/LICENSE-2.0 +// +// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 +// ======================================================================== +// + +[[eg-server-http-connector]] +=== Server Connectors + +A `Connector` is the component that handles incoming requests from clients, +and works in conjunction with `ConnectionFactory` instances. + +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. + +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.: + +[source,java,indent=0] +---- +include::../../{doc_code}/embedded/server/http/HTTPServerDocs.java[tags=configureConnector] +---- + +The _acceptors_ are threads (typically only one) that compete to accept TCP +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`]. +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, +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, +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. +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 +on a different port: + +[source,java,indent=0] +---- +include::../../{doc_code}/embedded/server/http/HTTPServerDocs.java[tags=configureConnectors] +---- + +[[eg-server-http-connector-protocol]] +==== Configuring Protocols + +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). + +A `ServerConnector` can be configured with one or more ``ConnectionFactory``s. +If no `ConnectionFactory` is specified then `HttpConnectionFactory` is +implicitly configured. + +[[eg-server-http-connector-protocol-http11]] +===== Configuring HTTP/1.1 + +`HttpConnectionFactory` creates `HttpConnection` objects that parse bytes +and generate bytes for the HTTP/1.1 protocol. + +This is how you configure Jetty to support clear-text HTTP/1.1: + +[source,java,indent=0] +---- +include::../../{doc_code}/embedded/server/http/HTTPServerDocs.java[tags=http11] +---- + +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: + +[source,java,indent=0] +---- +include::../../{doc_code}/embedded/server/http/HTTPServerDocs.java[tags=tlsHttp11] +---- + +[[eg-server-http-connector-protocol-proxy-http11]] +===== Configuring Jetty behind 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. + +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]. + +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. + +To support this case, Jetty can be configured in this way: + +[source,java,indent=0] +---- +include::../../{doc_code}/embedded/server/http/HTTPServerDocs.java[tags=proxyHTTP] +---- + +Note how the ``ConnectionFactory``s passed to `ServerConnector` are in order: +first PROXY, then 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 +accepted TCP connection; the `Connection` objects will be chained together +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]] +===== Configuring HTTP/2 + +It is well known that the HTTP ports are `80` (for clear-text HTTP) and `443` +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). + +HTTP/2 was designed to be a smooth transition from HTTP/1.1 for users and +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. +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 +configuring both the HTTP/1.1 and the HTTP/2 ``ConnectionFactory``s: + +[source,java,indent=0] +---- +include::../../{doc_code}/embedded/server/http/HTTPServerDocs.java[tags=http11H2C] +---- + +Note how the ``ConnectionFactory``s passed to `ServerConnector` are in order: +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 configuration is also typical when Jetty is installed in backend servers +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 using encrypted HTTP/2, the unencrypted protocol is negotiated by client +and server using an extension to the TLS protocol called ALPN. + +Jetty supports ALPN and encrypted HTTP/2 with this configuration: + +[source,java,indent=0] +---- +include::../../{doc_code}/embedded/server/http/HTTPServerDocs.java[tags=tlsALPNHTTP] +---- + +Note how the ``ConnectionFactory``s passed to `ServerConnector` are in order: +TLS, ALPN, HTTP/1.1, HTTP/2. + +Jetty starts parsing TLS bytes so that it can obtain the ALPN extension. +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. diff --git a/jetty-documentation/src/main/asciidoc/embedded-guide/server/http/server-http-handler-implement.adoc b/jetty-documentation/src/main/asciidoc/embedded-guide/server/http/server-http-handler-implement.adoc new file mode 100644 index 00000000000..625d206f2e0 --- /dev/null +++ b/jetty-documentation/src/main/asciidoc/embedded-guide/server/http/server-http-handler-implement.adoc @@ -0,0 +1,71 @@ +// +// ======================================================================== +// Copyright (c) 1995-2020 Mort Bay Consulting Pty Ltd and others. +// +// This program and the accompanying materials are made available under +// the terms of the Eclipse Public License 2.0 which is available at +// https://www.eclipse.org/legal/epl-2.0 +// +// This Source Code may also be made available under the following +// Secondary Licenses when the conditions for such availability set +// forth in the Eclipse Public License, v. 2.0 are satisfied: +// the Apache License v2.0 which is available at +// https://www.apache.org/licenses/LICENSE-2.0 +// +// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 +// ======================================================================== +// + +[[eg-server-http-handler-implement]] +==== Implementing Handler + +The `Handler` API consist fundamentally of just one method: + +[source,java,indent=0] +---- +include::../../{doc_code}/embedded/server/http/HTTPServerDocs.java[tags=handlerAPI] +---- + +The `target` parameter is an identifier for the resource. +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 +`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 +request or response to a different URI (which may be possibly handled by a +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]] +===== Hello World Handler + +A simple "Hello World" `Handler` is the following: + +[source,java,indent=0] +---- +include::../../{doc_code}/embedded/server/http/HTTPServerDocs.java[tags=handlerHello] +---- + +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. + +[[eg-server-http-handler-impl-filter]] +===== Filtering Handler + +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: + +[source,java,indent=0] +---- +include::../../{doc_code}/embedded/server/http/HTTPServerDocs.java[tags=handlerFilter] +---- + +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. + diff --git a/jetty-documentation/src/main/asciidoc/embedded-guide/server/http/server-http-handler-use.adoc b/jetty-documentation/src/main/asciidoc/embedded-guide/server/http/server-http-handler-use.adoc new file mode 100644 index 00000000000..50c46854783 --- /dev/null +++ b/jetty-documentation/src/main/asciidoc/embedded-guide/server/http/server-http-handler-use.adoc @@ -0,0 +1,464 @@ +// +// ======================================================================== +// Copyright (c) 1995-2020 Mort Bay Consulting Pty Ltd and others. +// +// This program and the accompanying materials are made available under +// the terms of the Eclipse Public License 2.0 which is available at +// https://www.eclipse.org/legal/epl-2.0 +// +// This Source Code may also be made available under the following +// Secondary Licenses when the conditions for such availability set +// forth in the Eclipse Public License, v. 2.0 are satisfied: +// the Apache License v2.0 which is available at +// https://www.apache.org/licenses/LICENSE-2.0 +// +// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 +// ======================================================================== +// + +[[eg-server-http-handler-use]] +==== Using Provided Handlers + +Web applications are the unit of deployment in an HTTP server or Servlet +container such as Jetty. + +Two different web applications are typically deployed on different +__context path__s, where a _context path_ is the initial segment of the URI +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 +`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 +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. +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 +`shop.domain.com` and context path `/`, while web application `webappB` +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 +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_ +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, /)`. +Server applications using the Jetty Server Libraries create and +configure a _context_ for each web application. + +[[eg-server-http-handler-use-context]] +===== ContextHandler + +`ContextHandler` is a `Handler` that represents a _context_ for a web +application. It is a `HandlerWrapper` that performs some action before +and after delegating to the nested `Handler`. +// TODO: expand on what the ContextHandler does, e.g. ServletContext. + +The simplest use of `ContextHandler` is the following: + +[source,java,indent=0] +---- +include::../../{doc_code}/embedded/server/http/HTTPServerDocs.java[tags=contextHandler] +---- + +The `Handler` tree structure looks like the following: + +[source,screen] +---- +Server +└── ContextHandler /shop + └── ShopHandler +---- + +[[eg-server-http-handler-use-context-collection]] +===== ContextHandlerCollection + +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 +`HandlerCollection` and `HandlerList` that may contain a sequence of children +``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`, +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. +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]). +Eventually, if `Request.setHandled(true)` is not called, Jetty returns a HTTP +`404` response to the client. + +[source,java,indent=0] +---- +include::../../{doc_code}/embedded/server/http/HTTPServerDocs.java[tags=contextHandlerCollection] +---- + +The `Handler` tree structure looks like the following: + +[source,screen] +---- +Server +└── ContextHandlerCollection + ├── ContextHandler /shop + │ └── ShopHandler + └── ContextHandler /api + └── RESTHandler +---- + +[[eg-server-http-handler-use-servlet-context]] +===== ServletContextHandler + +``Handler``s are easy to write, but often web applications have already been +written using the Servlet APIs, using ``Servlet``s and ``Filter``s. + +`ServletContextHandler` is a `ContextHandler` that provides support for the +Servlet APIs and implements the behaviors required by the Servlet specification. + +The Maven artifact coordinates are: + +[source,xml,subs=normal] +---- + + org.eclipse.jetty + jetty-servlet + {version} + +---- + +[source,java,indent=0] +---- +include::../../{doc_code}/embedded/server/http/HTTPServerDocs.java[tags=servletContextHandler] +---- + +The `Handler` and Servlet components tree structure looks like the following: + +[source,screen,subs=normal] +---- +Server +└── ServletContextHandler /shop + ├── _ShopCartServlet /cart/*_ + └── _CrossOriginFilter /*_ +---- + +Note how the Servlet components (they are not ``Handler``s) are represented in +_italic_. + +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`. + +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. + +IMPORTANT: `ServletContextHandler` is a terminal `Handler`, that is it always +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`. + +[[eg-server-http-handler-use-webapp-context]] +===== WebAppContext + +`WebAppContext` is a `ServletContextHandler` that auto configures itself by +reading a `web.xml` Servlet configuration file. + +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). + +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. + +[source,java,indent=0] +---- +include::../../{doc_code}/embedded/server/http/HTTPServerDocs.java[tags=webAppContextHandler] +---- + +[[eg-server-http-handler-use-resource-handler]] +===== ResourceHandler -- Static Content + +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. + +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. + +`ResourceHandler` supports the following features: + +* Welcome files, for example serving `/index.html` for request URI `/` +* Precompressed resources, serving a precompressed `/document.txt.gz` for +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 +* 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 +are on the same level as those of common front-end servers used to serve +static content such as Nginx or Apache. +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 +servers. 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. + +This is how you configure a `ResourceHandler` to create a simple file server: + +[source,java,indent=0] +---- +include::../../{doc_code}/embedded/server/http/HTTPServerDocs.java[tags=resourceHandler] +---- + +If you need to serve static resources from multiple directories: + +[source,java,indent=0] +---- +include::../../{doc_code}/embedded/server/http/HTTPServerDocs.java[tags=multipleResourcesHandler] +---- + +If the resource is not found, `ResourceHandler` will not call +`Request.setHandled(true)` so what happens next depends on the `Handler` +tree structure. See also +xref:eg-server-http-handler-use-util-default-handler[how to use] `DefaultHandler`. + +[[eg-server-http-handler-use-default-servlet]] +===== DefaultServlet -- Static Content for Servlets + +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`. +The features are similar, but `DefaultServlet` is more commonly used to +serve static files for Servlet web applications. + +[source,java,indent=0] +---- +include::../../{doc_code}/embedded/server/http/HTTPServerDocs.java[tags=defaultServlet] +---- + +[[eg-server-http-handler-use-util-gzip-handler]] +===== GzipHandler + +`GzipHandler` provides supports for automatic decompression of compressed +request content and automatic compression of response content. + +`GzipHandler` is a `HandlerWrapper` that inspects the request and, if the +request matches the `GzipHandler` configuration, just installs the required +components to eventually perform decompression of the request content or +compression of the response content. +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: + +[source,java,indent=0] +---- +include::../../{doc_code}/embedded/server/http/HTTPServerDocs.java[tags=serverGzipHandler] +---- + +The `Handler` tree structure looks like the following: + +[source,screen] +---- +Server +└── GzipHandler + └── ContextHandlerCollection + ├── ContextHandler 1 + :── ... + └── ContextHandler N +---- + +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: + +[source,java,indent=0] +---- +include::../../{doc_code}/embedded/server/http/HTTPServerDocs.java[tags=contextGzipHandler] +---- + +The `Handler` tree structure looks like the following: + +[source,screen] +---- +Server +└── ContextHandlerCollection + └── ContextHandlerCollection + ├── GzipHandler + │ └── ContextHandler /shop + │ └── ShopHandler + └── ContextHandler /api + └── RESTHandler +---- + +// TODO: does ServletContextHandler really need a special configuration? + +[[eg-server-http-handler-use-util-rewrite-handler]] +===== RewriteHandler + +`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]. + +The Maven artifact coordinates are: + +[source,xml,subs=normal] +---- + + org.eclipse.jetty + jetty-rewrite + {version} + +---- + +`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 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. + +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. + +You typically want to configure `RewriteHandler` at the server level, although +it is possible to configure it on a per-context basis. + +[source,java,indent=0] +---- +include::../../{doc_code}/embedded/server/http/HTTPServerDocs.java[tags=rewriteHandler] +---- + +The `Handler` tree structure looks like the following: + +[source,screen] +---- +Server +└── RewriteHandler + └── ContextHandlerCollection + ├── ContextHandler 1 + :── ... + └── ContextHandler N +---- + +[[eg-server-http-handler-use-util-stats-handler]] +===== StatisticsHandler + +`StatisticsHandler` gathers and exposes a number of statistic values related +to request processing such as: + +* Total number of requests +* Current number of concurrent requests +* Minimum, maximum, average and standard deviation of request processing times +* Number of responses grouped by HTTP code (i.e. how many `2xx` responses, how +many `3xx` responses, etc.) +* Total response content bytes + +Server applications can read these values and use them internally, or expose +them via some service, or export them via JMX. +// TODO: xref to the JMX section. + +`StatisticsHandler` can be configured at the server level or at the context +level. + +[source,java,indent=0] +---- +include::../../{doc_code}/embedded/server/http/HTTPServerDocs.java[tags=statsHandler] +---- + +The `Handler` tree structure looks like the following: + +[source,screen] +---- +Server +└── StatisticsHandler + └── ContextHandlerCollection + ├── ContextHandler 1 + :── ... + └── ContextHandler N +---- + +[[eg-server-http-handler-use-util-secure-handler]] +===== SecuredRedirectHandler -- Redirect from HTTP to HTTPS + +// TODO: wait for issue #4766 +TODO + +[[eg-server-http-handler-use-util-default-handler]] +===== DefaultHandler + +`DefaultHandler` is a terminal `Handler` that always calls +`Request.setHandled(true)` and performs the following: + +* Serves the `favicon.ico` Jetty icon when it is requested +* Sends a HTTP `404` response for any other request +* The HTTP `404` response content nicely shows a HTML table with all the +contexts deployed on the `Server` instance + +`DefaultHandler` is best used as the last `Handler` of a `HandlerList`, +for example: + +[source,java,indent=0] +---- +include::../../{doc_code}/embedded/server/http/HTTPServerDocs.java[tags=defaultHandler] +---- + +The `Handler` tree structure looks like the following: + +[source,screen] +---- +Server +└── HandlerList + ├── ContextHandlerCollection + │ ├── ContextHandler 1 + │ :── ... + │ └── ContextHandler N + └── DefaultHandler +---- + +In the example above, `ContextHandlerCollection` will try to match a request +to one of the contexts; if the match fails, `HandlerList` will call the next +`Handler` which is `DefaultHandler` that will return a HTTP `404` with an +HTML page showing the existing contexts deployed on the `Server`. + +NOTE: `DefaultHandler` just sends a nicer HTTP `404` response in case of +wrong requests from clients. +Jetty will send an HTTP `404` response anyway if `DefaultHandler` is not +used. diff --git a/jetty-documentation/src/main/asciidoc/embedded-guide/server/http/server-http-handler.adoc b/jetty-documentation/src/main/asciidoc/embedded-guide/server/http/server-http-handler.adoc new file mode 100644 index 00000000000..104f2c50ece --- /dev/null +++ b/jetty-documentation/src/main/asciidoc/embedded-guide/server/http/server-http-handler.adoc @@ -0,0 +1,103 @@ +// +// ======================================================================== +// Copyright (c) 1995-2020 Mort Bay Consulting Pty Ltd and others. +// +// This program and the accompanying materials are made available under +// the terms of the Eclipse Public License 2.0 which is available at +// https://www.eclipse.org/legal/epl-2.0 +// +// This Source Code may also be made available under the following +// Secondary Licenses when the conditions for such availability set +// forth in the Eclipse Public License, v. 2.0 are satisfied: +// the Apache License v2.0 which is available at +// https://www.apache.org/licenses/LICENSE-2.0 +// +// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 +// ======================================================================== +// + +[[eg-server-http-handler]] +=== Server Handlers + +An `org.eclipse.jetty.server.Handler` is the component that processes +incoming HTTP requests and eventually produces HTTP responses. + +``Handler``s can be organized in different ways: + +* in a sequence, where ``Handler``s are invoked one after the other +** `HandlerCollection` invokes _all_ ``Handler``s one after the other +** `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 +* nested, where one `Handler` invokes the next, nested, `Handler` +** `HandlerWrapper` implements this behavior + +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). + +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. + +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`). + +``Handler``s can be organized in a tree by composing them together: + +[source,java,indent=0] +---- +include::../../{doc_code}/embedded/server/http/HTTPServerDocs.java[tags=handlerTree] +---- + +The corresponding `Handler` tree structure looks like the following: + +[source,screen] +---- +HandlerCollection +├── HandlerList +│ ├── App1Handler +│ └── HandlerWrapper +│ └── App2Handler +└── LoggingHandler +---- + +//// +PlantUML cannot render a tree left-aligned :( +[plantuml] +---- +skinparam backgroundColor transparent +skinparam monochrome true +skinparam shadowing false +skinparam padding 5 + +scale 1.5 + +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. +Refer to xref:eg-server-http-handler-implement[this section] for more information +about how to write your own ``Handler``s. + +include::server-http-handler-use.adoc[] +include::server-http-handler-implement.adoc[] diff --git a/jetty-documentation/src/main/asciidoc/embedded-guide/server/http/server-http.adoc b/jetty-documentation/src/main/asciidoc/embedded-guide/server/http/server-http.adoc index 1b2a86adc43..39334067a3b 100644 --- a/jetty-documentation/src/main/asciidoc/embedded-guide/server/http/server-http.adoc +++ b/jetty-documentation/src/main/asciidoc/embedded-guide/server/http/server-http.adoc @@ -22,6 +22,17 @@ The Eclipse Jetty Project has historically provided libraries to embed an HTTP server and a Servlet Container. +The Maven artifact coordinates are: + +[source,xml,subs=normal] +---- + + org.eclipse.jetty + jetty-server + {version} + +---- + 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. @@ -44,7 +55,7 @@ Server -- Handlers ---- The components that accept connections from clients are -`org.eclipse.jetty.server.Connector` instances. +`org.eclipse.jetty.server.Connector` implementations. 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 @@ -66,232 +77,5 @@ applications only need to put the required components together to provide all the required features. // TODO: link to a place where we discuss the handlers in more details. -[[eg-server-connector]] -=== Server Connectors - -A `Connector` is the component that handles incoming requests from clients, -and works in conjunction with `ConnectionFactory` instances. - -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. - -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.: - -[source,java,indent=0] ----- -include::../../{doc_code}/embedded/server/http/HTTPServerDocs.java[tags=configureConnector] ----- - -The _acceptors_ are threads that compete to accept TCP connections on the -listening port, typically only one. -When a connection is accepted, `ServerConnector` wraps it and passes it to -the 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, -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, -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. -As a rule of thumb, a single selector can easily manage 1000-5000 sockets, -although the number may vary greatly depending on the application. - -It is possible to configure more than one `ServerConnector`, each listening -on different ports: - -[source,java,indent=0] ----- -include::../../{doc_code}/embedded/server/http/HTTPServerDocs.java[tags=configureConnectors] ----- - -[[eg-server-connector-protocol]] -==== Configuring Protocols - -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). - -A `ServerConnector` can be configured with one or more ``ConnectionFactory``s. -If no `ConnectionFactory` is specified then `HttpConnectionFactory` is -implicitly configured. - -[[eg-server-connector-protocol-http11]] -===== Configuring HTTP/1.1 - -`HttpConnectionFactory` creates `HttpConnection` objects that parse bytes -and generate bytes for the HTTP/1.1 protocol. - -This is how you configure Jetty to support clear-text HTTP/1.1: - -[source,java,indent=0] ----- -include::../../{doc_code}/embedded/server/http/HTTPServerDocs.java[tags=http11] ----- - -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: - -[source,java,indent=0] ----- -include::../../{doc_code}/embedded/server/http/HTTPServerDocs.java[tags=tlsHttp11] ----- - -[[eg-server-connector-protocol-proxy-http11]] -===== Configuring Jetty behind 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. - -From the Jetty point of view, all the connections arrive from the load -balancer, rather than the real clients, but is possible 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 -link:http://cbonte.github.io/haproxy-dconv/2.2/configuration.html#5.2-send-proxy[HAProxy] -(via its `send-proxy` directive), or -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: - -[source,java,indent=0] ----- -include::../../{doc_code}/embedded/server/http/HTTPServerDocs.java[tags=proxyHTTP] ----- - -Note how the ``ConnectionFactory``s passed to `ServerConnector` are in order: -first PROXY, then 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 -accepted TCP connection; the `Connection` objects will be chained together -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-connector-protocol-http2]] -===== Configuring HTTP/2 - -It is well know that the HTTP ports are `80` (for clear-text HTTP) and `443` -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). - -HTTP/2 was designed to be a smooth transition from HTTP/1.1 for users and -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. -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 -configuring both the HTTP/1.1 and the HTTP/2 ``ConnectionFactory``s: - -[source,java,indent=0] ----- -include::../../{doc_code}/embedded/server/http/HTTPServerDocs.java[tags=http11H2C] ----- - -Note how the ``ConnectionFactory``s passed to `ServerConnector` are in order: -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 configuration is also typical when Jetty is installed in backend servers -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-connector-protocol-proxy-http11[this section]. - -When using encrypted HTTP/2, the unencrypted protocol is negotiated by client -and server using an extension to the TLS protocol called ALPN. - -Jetty supports ALPN and encrypted HTTP/2 with this configuration: - -[source,java,indent=0] ----- -include::../../{doc_code}/embedded/server/http/HTTPServerDocs.java[tags=tlsALPNHTTP] ----- - -[[eg-server-handler]] -=== Server Handlers - -A `Handler` is the component that processes incoming HTTP requests and -eventually produces HTTP responses. - -``Handler``s can be organized in different ways: - -* in a sequence, where ``Handler``s are invoked one after the other -** `HandlerCollection` invokes _all_ ``Handler``s one after the other -** `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. -* nested, where one `Handler` invokes the next `Handler` -** `HandlerWrapper` implements this behavior - -The `HandlerCollection` behavior (invoking _all_ handlers) is useful when -for example the last `Handler` is a logging `Handler` that logs the the -request(that may have been modified by previous handlers). - -The `HandlerList` behavior (invoking handlers up to the first that calls -`Request.setHandled(true)`) is useful when different handlers process different -URIs or different virtual hosts: invoke one after the other until one matches -the URI or virtual host. - -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`). - -``Handler``s can be organized in a tree by composing them together: - -[plantuml] ----- -skinparam backgroundColor transparent -skinparam monochrome true -skinparam shadowing false -skinparam padding 5 - -scale 1.5 - -hide members -hide circle - -HandlerCollection -- HandlerList -HandlerCollection -- LoggingHandler -HandlerList -- App1Handler -HandlerList -- App2Handler -App2Handler -- ServletHandler ----- - -In code it looks like this: - -[source,java,indent=0] ----- -include::../../{doc_code}/embedded/server/http/HTTPServerDocs.java[tags=tree] ----- - -// TODO: old docs introduces briefly ServletHandler but I think it deserves its own section - -// TODO: old docs introduce ContextHandler here and WebAppContext - +include::server-http-connector.adoc[] +include::server-http-handler.adoc[] diff --git a/jetty-documentation/src/main/asciidoc/embedded-guide/server/http2/server-http2.adoc b/jetty-documentation/src/main/asciidoc/embedded-guide/server/http2/server-http2.adoc new file mode 100644 index 00000000000..c6728c6ef0e --- /dev/null +++ b/jetty-documentation/src/main/asciidoc/embedded-guide/server/http2/server-http2.adoc @@ -0,0 +1,22 @@ +// +// ======================================================================== +// Copyright (c) 1995-2020 Mort Bay Consulting Pty Ltd and others. +// +// This program and the accompanying materials are made available under +// the terms of the Eclipse Public License 2.0 which is available at +// https://www.eclipse.org/legal/epl-2.0 +// +// This Source Code may also be made available under the following +// Secondary Licenses when the conditions for such availability set +// forth in the Eclipse Public License, v. 2.0 are satisfied: +// the Apache License v2.0 which is available at +// https://www.apache.org/licenses/LICENSE-2.0 +// +// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 +// ======================================================================== +// + +[[eg-server-http2]] +=== HTTP/2 Server Libraries + +TODO diff --git a/jetty-documentation/src/main/asciidoc/embedded-guide/server/server.adoc b/jetty-documentation/src/main/asciidoc/embedded-guide/server/server.adoc index a6dcc1feb45..a8cc9ceffd2 100644 --- a/jetty-documentation/src/main/asciidoc/embedded-guide/server/server.adoc +++ b/jetty-documentation/src/main/asciidoc/embedded-guide/server/server.adoc @@ -46,6 +46,7 @@ xref:eg-server-http2[HTTP/2 libraries] via the xref:eg-server-websocket[WebSocket libraries] include::http/server-http.adoc[] -include::http/server-http2.adoc[] -include::http/server-websocket.adoc[] +include::http2/server-http2.adoc[] +include::websocket/server-websocket.adoc[] include::server-io-arch.adoc[] +include::../old_docs/server.adoc[] diff --git a/jetty-documentation/src/main/asciidoc/embedded-guide/server/websocket/server-websocket.adoc b/jetty-documentation/src/main/asciidoc/embedded-guide/server/websocket/server-websocket.adoc new file mode 100644 index 00000000000..0ea9473f72b --- /dev/null +++ b/jetty-documentation/src/main/asciidoc/embedded-guide/server/websocket/server-websocket.adoc @@ -0,0 +1,22 @@ +// +// ======================================================================== +// Copyright (c) 1995-2020 Mort Bay Consulting Pty Ltd and others. +// +// This program and the accompanying materials are made available under +// the terms of the Eclipse Public License 2.0 which is available at +// https://www.eclipse.org/legal/epl-2.0 +// +// This Source Code may also be made available under the following +// Secondary Licenses when the conditions for such availability set +// forth in the Eclipse Public License, v. 2.0 are satisfied: +// the Apache License v2.0 which is available at +// https://www.apache.org/licenses/LICENSE-2.0 +// +// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 +// ======================================================================== +// + +[[eg-server-websocket]] +=== WebSocket Server Libraries + +TODO diff --git a/jetty-documentation/src/main/java/embedded/server/http/HTTPServerDocs.java b/jetty-documentation/src/main/java/embedded/server/http/HTTPServerDocs.java index 1fdd72eafcd..263d94484f5 100644 --- a/jetty-documentation/src/main/java/embedded/server/http/HTTPServerDocs.java +++ b/jetty-documentation/src/main/java/embedded/server/http/HTTPServerDocs.java @@ -18,13 +18,24 @@ package embedded.server.http; +import java.io.IOException; +import java.util.EnumSet; +import javax.servlet.DispatcherType; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.eclipse.jetty.alpn.server.ALPNServerConnectionFactory; import org.eclipse.jetty.http.HttpCompliance; +import org.eclipse.jetty.http.HttpStatus; +import org.eclipse.jetty.http.HttpURI; import org.eclipse.jetty.http2.server.HTTP2CServerConnectionFactory; import org.eclipse.jetty.http2.server.HTTP2ServerConnectionFactory; +import org.eclipse.jetty.rewrite.handler.CompactPathRule; +import org.eclipse.jetty.rewrite.handler.RedirectRegexRule; +import org.eclipse.jetty.rewrite.handler.RewriteHandler; +import org.eclipse.jetty.rewrite.handler.RewriteRegexRule; import org.eclipse.jetty.server.Connector; import org.eclipse.jetty.server.HttpConfiguration; import org.eclipse.jetty.server.HttpConnectionFactory; @@ -35,12 +46,26 @@ import org.eclipse.jetty.server.Server; import org.eclipse.jetty.server.ServerConnector; import org.eclipse.jetty.server.SslConnectionFactory; import org.eclipse.jetty.server.handler.AbstractHandler; +import org.eclipse.jetty.server.handler.ContextHandler; +import org.eclipse.jetty.server.handler.ContextHandlerCollection; +import org.eclipse.jetty.server.handler.DefaultHandler; import org.eclipse.jetty.server.handler.HandlerCollection; import org.eclipse.jetty.server.handler.HandlerList; import org.eclipse.jetty.server.handler.HandlerWrapper; -import org.eclipse.jetty.servlet.ServletHandler; +import org.eclipse.jetty.server.handler.ResourceHandler; +import org.eclipse.jetty.server.handler.StatisticsHandler; +import org.eclipse.jetty.server.handler.gzip.GzipHandler; +import org.eclipse.jetty.servlet.DefaultServlet; +import org.eclipse.jetty.servlet.FilterHolder; +import org.eclipse.jetty.servlet.ServletContextHandler; +import org.eclipse.jetty.servlet.ServletHolder; +import org.eclipse.jetty.servlets.CrossOriginFilter; +import org.eclipse.jetty.util.Callback; +import org.eclipse.jetty.util.resource.Resource; +import org.eclipse.jetty.util.resource.ResourceCollection; import org.eclipse.jetty.util.ssl.SslContextFactory; import org.eclipse.jetty.util.thread.QueuedThreadPool; +import org.eclipse.jetty.webapp.WebAppContext; @SuppressWarnings("unused") public class HTTPServerDocs @@ -266,7 +291,7 @@ public class HTTPServerDocs // end::tlsALPNHTTP[] } - public void tree() throws Exception + public void handlerTree() { class LoggingHandler extends AbstractHandler { @@ -292,7 +317,7 @@ public class HTTPServerDocs } } - // tag::tree[] + // tag::handlerTree[] // Create a Server instance. Server server = new Server(); @@ -305,10 +330,459 @@ public class HTTPServerDocs collection.addHandler(new LoggingHandler()); list.addHandler(new App1Handler()); - App2Handler app2Handler = new App2Handler(); - list.addHandler(app2Handler); + HandlerWrapper wrapper = new HandlerWrapper(); + list.addHandler(wrapper); - app2Handler.setHandler(new ServletHandler()); - // end::tree[] + wrapper.setHandler(new App2Handler()); + // end::handlerTree[] + } + + public void handlerAPI() + { + class MyHandler extends AbstractHandler + { + @Override + // tag::handlerAPI[] + public void handle(String target, Request jettyRequest, HttpServletRequest request, HttpServletResponse response) + { + } + // end::handlerAPI[] + } + } + + public void handlerHello() throws Exception + { + // tag::handlerHello[] + class HelloWorldHandler extends AbstractHandler + { + @Override + public void handle(String target, Request jettyRequest, HttpServletRequest request, HttpServletResponse response) throws IOException + { + // Mark the request as handled by this Handler. + jettyRequest.setHandled(true); + + response.setStatus(200); + response.setContentType("text/html; charset=UTF-8"); + + // Write a Hello World response. + response.getWriter().print("" + + "" + + "" + + "" + + " Jetty Hello World Handler" + + "" + + "" + + "

Hello World

" + + "" + + "" + + ""); + } + } + + Server server = new Server(); + Connector connector = new ServerConnector(server); + server.addConnector(connector); + + // Set the Hello World Handler. + server.setHandler(new HelloWorldHandler()); + + server.start(); + // end::handlerHello[] + } + + public void handlerFilter() throws Exception + { + class HelloWorldHandler extends AbstractHandler + { + @Override + public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) + { + } + } + + // tag::handlerFilter[] + class FilterHandler extends HandlerWrapper + { + @Override + public void handle(String target, Request jettyRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException + { + String path = request.getRequestURI(); + if (path.startsWith("/old_path/")) + { + // Rewrite old paths to new paths. + HttpURI uri = jettyRequest.getHttpURI(); + HttpURI newURI = new HttpURI(uri); + String newPath = "/new_path/" + path.substring("/old_path/".length()); + newURI.setPath(newPath); + // Modify the request object. + jettyRequest.setHttpURI(newURI); + } + + // This Handler is not handling the request, so + // it does not call jettyRequest.setHandled(true). + + // Forward to the next Handler. + super.handle(target, jettyRequest, request, response); + } + } + + Server server = new Server(); + Connector connector = new ServerConnector(server); + server.addConnector(connector); + + // Link the Handlers. + FilterHandler filter = new FilterHandler(); + filter.setHandler(new HelloWorldHandler()); + server.setHandler(filter); + + server.start(); + // end::handlerFilter[] + } + + public void contextHandler() throws Exception + { + // tag::contextHandler[] + class ShopHandler extends AbstractHandler + { + @Override + public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) + { + baseRequest.setHandled(true); + // Implement the shop. + } + } + + Server server = new Server(); + Connector connector = new ServerConnector(server); + server.addConnector(connector); + + // Create a ContextHandler with contextPath. + ContextHandler context = new ContextHandler(); + context.setContextPath("/shop"); + context.setHandler(new ShopHandler()); + + // Link the context to the server. + server.setHandler(context); + + server.start(); + // end::contextHandler[] + } + + public void contextHandlerCollection() throws Exception + { + // tag::contextHandlerCollection[] + class ShopHandler extends AbstractHandler + { + @Override + public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) + { + baseRequest.setHandled(true); + // Implement the shop. + } + } + + class RESTHandler extends AbstractHandler + { + @Override + public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) + { + baseRequest.setHandled(true); + // Implement the REST APIs. + } + } + + Server server = new Server(); + Connector connector = new ServerConnector(server); + server.addConnector(connector); + + // Create a ContextHandlerCollection to hold contexts. + ContextHandlerCollection contextCollection = new ContextHandlerCollection(); + // Link the ContextHandlerCollection to the Server. + server.setHandler(contextCollection); + + // Create the context for the shop web application. + ContextHandler shopContext = new ContextHandler("/shop"); + shopContext.setHandler(new ShopHandler()); + // Add it to ContextHandlerCollection. + contextCollection.addHandler(shopContext); + + server.start(); + + // Create the context for the API web application. + ContextHandler apiContext = new ContextHandler("/api"); + apiContext.setHandler(new RESTHandler()); + // Web applications can be deployed after the Server is started. + contextCollection.deployHandler(apiContext, Callback.NOOP); + // end::contextHandlerCollection[] + } + + public void servletContextHandler() throws Exception + { + // tag::servletContextHandler[] + class ShopCartServlet extends HttpServlet + { + @Override + protected void service(HttpServletRequest request, HttpServletResponse response) + { + // Implement the shop cart functionality. + } + } + + Server server = new Server(); + Connector connector = new ServerConnector(server); + server.addConnector(connector); + + // Create a ServletContextHandler with contextPath. + ServletContextHandler context = new ServletContextHandler(); + context.setContextPath("/shop"); + + // Add the Servlet implementing the cart functionality to the context. + ServletHolder servletHolder = context.addServlet(ShopCartServlet.class, "/cart/*"); + // Configure the Servlet with init-parameters. + servletHolder.setInitParameter("maxItems", "128"); + + // Add the CrossOriginFilter to protect from CSRF attacks. + FilterHolder filterHolder = context.addFilter(CrossOriginFilter.class, "/*", EnumSet.of(DispatcherType.REQUEST)); + // Configure the filter. + filterHolder.setAsyncSupported(true); + + // Link the context to the server. + server.setHandler(context); + + server.start(); + // end::servletContextHandler[] + } + + public void webAppContextHandler() throws Exception + { + // tag::webAppContextHandler[] + Server server = new Server(); + Connector connector = new ServerConnector(server); + server.addConnector(connector); + + // Create a WebAppContext. + WebAppContext context = new WebAppContext(); + // Configure the path of the packaged web application (file or directory). + context.setWar("/path/to/webapp.war"); + // Configure the contextPath. + context.setContextPath("/app"); + + // Link the context to the server. + server.setHandler(context); + + server.start(); + // end::webAppContextHandler[] + } + + public void resourceHandler() throws Exception + { + // tag::resourceHandler[] + Server server = new Server(); + Connector connector = new ServerConnector(server); + server.addConnector(connector); + + // Create and configure a ResourceHandler. + ResourceHandler handler = new ResourceHandler(); + // Configure the directory where static resources are located. + handler.setBaseResource(Resource.newResource("/path/to/static/resources/")); + // Configure directory listing. + handler.setDirectoriesListed(false); + // Configure welcome files. + handler.setWelcomeFiles(new String[]{"index.html"}); + // Configure whether to accept range requests. + handler.setAcceptRanges(true); + + // Link the context to the server. + server.setHandler(handler); + + server.start(); + // end::resourceHandler[] + } + + public void multipleResourcesHandler() throws Exception + { + // tag::multipleResourcesHandler[] + ResourceHandler handler = new ResourceHandler(); + + // For multiple directories, use ResourceCollection. + ResourceCollection directories = new ResourceCollection(); + directories.addPath("/path/to/static/resources/"); + directories.addPath("/another/path/to/static/resources/"); + + handler.setBaseResource(directories); + // end::multipleResourcesHandler[] + } + + public void defaultServlet() + { + // tag::defaultServlet[] + // Create a ServletContextHandler with contextPath. + ServletContextHandler context = new ServletContextHandler(); + context.setContextPath("/app"); + + // Add the DefaultServlet to serve static content. + ServletHolder servletHolder = context.addServlet(DefaultServlet.class, "/"); + // Configure the DefaultServlet with init-parameters. + servletHolder.setInitParameter("resourceBase", "/path/to/static/resources/"); + servletHolder.setAsyncSupported(true); + // end::defaultServlet[] + } + + public void serverGzipHandler() throws Exception + { + // tag::serverGzipHandler[] + Server server = new Server(); + Connector connector = new ServerConnector(server); + server.addConnector(connector); + + // Create and configure GzipHandler. + GzipHandler gzipHandler = new GzipHandler(); + // Only compress response content larger than this. + gzipHandler.setMinGzipSize(1024); + // Do not compress these URI paths. + gzipHandler.setExcludedPaths("/uncompressed"); + // Also compress POST responses. + gzipHandler.addIncludedMethods("POST"); + // Do not compress these mime types. + gzipHandler.addExcludedMimeTypes("font/ttf"); + + // Link a ContextHandlerCollection to manage contexts. + ContextHandlerCollection contexts = new ContextHandlerCollection(); + gzipHandler.setHandler(contexts); + + // Link the GzipHandler to the Server. + server.setHandler(gzipHandler); + + server.start(); + // end::serverGzipHandler[] + } + + public void contextGzipHandler() throws Exception + { + class ShopHandler extends AbstractHandler + { + @Override + public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException + { + baseRequest.setHandled(true); + // Implement the shop. + } + } + + class RESTHandler extends AbstractHandler + { + @Override + public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) + { + baseRequest.setHandled(true); + // Implement the REST APIs. + } + } + + Server server = new Server(); + ServerConnector connector = new ServerConnector(server); + server.addConnector(connector); + + // tag::contextGzipHandler[] + // Create a ContextHandlerCollection to hold contexts. + ContextHandlerCollection contextCollection = new ContextHandlerCollection(); + // Link the ContextHandlerCollection to the Server. + server.setHandler(contextCollection); + + // Create the context for the shop web application. + ContextHandler shopContext = new ContextHandler("/shop"); + shopContext.setHandler(new ShopHandler()); + + // You want to gzip the shop web application only. + GzipHandler shopGzipHandler = new GzipHandler(); + shopGzipHandler.setHandler(shopContext); + + // Add it to ContextHandlerCollection. + contextCollection.addHandler(shopGzipHandler); + + // Create the context for the API web application. + ContextHandler apiContext = new ContextHandler("/api"); + apiContext.setHandler(new RESTHandler()); + + // Add it to ContextHandlerCollection. + contextCollection.addHandler(apiContext); + // end::contextGzipHandler[] + + server.start(); + } + + public void rewriteHandler() throws Exception + { + // tag::rewriteHandler[] + Server server = new Server(); + ServerConnector connector = new ServerConnector(server); + server.addConnector(connector); + + RewriteHandler rewriteHandler = new RewriteHandler(); + // Compacts URI paths with double slashes, e.g. /ctx//path/to//resource. + rewriteHandler.addRule(new CompactPathRule()); + // Rewrites */products/* to */p/*. + rewriteHandler.addRule(new RewriteRegexRule("/(.*)/product/(.*)", "/$1/p/$2")); + // Redirects permanently to a different URI. + RedirectRegexRule redirectRule = new RedirectRegexRule("/documentation/(.*)", "https://docs.domain.com/$1"); + redirectRule.setStatusCode(HttpStatus.MOVED_PERMANENTLY_301); + rewriteHandler.addRule(redirectRule); + + // Link the RewriteHandler to the Server. + server.setHandler(rewriteHandler); + + // Create a ContextHandlerCollection to hold contexts. + ContextHandlerCollection contextCollection = new ContextHandlerCollection(); + // Link the ContextHandlerCollection to the RewriteHandler. + rewriteHandler.setHandler(contextCollection); + + server.start(); + // end::rewriteHandler[] + } + + public void statsHandler() throws Exception + { + // tag::statsHandler[] + Server server = new Server(); + ServerConnector connector = new ServerConnector(server); + server.addConnector(connector); + + StatisticsHandler statsHandler = new StatisticsHandler(); + + // Link the StatisticsHandler to the Server. + server.setHandler(statsHandler); + + // Create a ContextHandlerCollection to hold contexts. + ContextHandlerCollection contextCollection = new ContextHandlerCollection(); + // Link the ContextHandlerCollection to the StatisticsHandler. + statsHandler.setHandler(contextCollection); + + server.start(); + // end::statsHandler[] + } + + public void defaultHandler() throws Exception + { + // tag::defaultHandler[] + Server server = new Server(); + Connector connector = new ServerConnector(server); + server.addConnector(connector); + + // Create a HandlerList. + HandlerList handlerList = new HandlerList(); + + // Add as first a ContextHandlerCollection to manage contexts. + ContextHandlerCollection contexts = new ContextHandlerCollection(); + handlerList.addHandler(contexts); + + // Add as last a DefaultHandler. + DefaultHandler defaultHandler = new DefaultHandler(); + handlerList.addHandler(defaultHandler); + + // Link the HandlerList to the Server. + server.setHandler(handlerList); + + server.start(); + // end::defaultHandler[] } } diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/handler/DefaultHandler.java b/jetty-server/src/main/java/org/eclipse/jetty/server/handler/DefaultHandler.java index 67c7c1b3efb..38f76792078 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/handler/DefaultHandler.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/handler/DefaultHandler.java @@ -47,7 +47,7 @@ import static java.nio.charset.StandardCharsets.UTF_8; * * This handle will deal with unhandled requests in the server. * For requests for favicon.ico, the Jetty icon is served. - * For reqests to '/' a 404 with a list of known contexts is served. + * For requests to '/' a 404 with a list of known contexts is served. * For all other requests a normal 404 is served. */ public class DefaultHandler extends AbstractHandler diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/handler/SecuredRedirectHandler.java b/jetty-server/src/main/java/org/eclipse/jetty/server/handler/SecuredRedirectHandler.java index bef74df7b94..450ced06987 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/handler/SecuredRedirectHandler.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/handler/SecuredRedirectHandler.java @@ -47,6 +47,8 @@ public class SecuredRedirectHandler extends AbstractHandler return; } + baseRequest.setHandled(true); + HttpConfiguration httpConfig = channel.getHttpConfiguration(); if (httpConfig == null) { @@ -68,7 +70,5 @@ public class SecuredRedirectHandler extends AbstractHandler { response.sendError(HttpStatus.FORBIDDEN_403, "Not Secure"); } - - baseRequest.setHandled(true); } }