Skip to content

Commit

Permalink
4.x: register routing in weighted order of Server and HTTP Features (h…
Browse files Browse the repository at this point in the history
…elidon-io#8826)

* Correctly handle order of Server Features and HTTP Features when registering non-HTTP Feature elements to the routing.
With the updated version, all elements (filters, routes, services) are ordered depending on the feature's weight.
This is achieved by creating a new HttpFeature for each Server Feature with the same weight, that collects all registrations and applies them once the HTTP Features are ordered by weight.
HttpFeature registered from a Server Feature is left intact and applied on the real builder (as this already works as it should)
* Updated CORS weight to 850 to align with the documented (and intended) ordering
* Added documentation for server features.
* Added documentation for Context feature.
* Reorganized webserver.adoc, as some sections were within wrong chapters; updated TOC
* Added `HttpFeature` documentation.

---------

Co-authored-by: Daniel Kec <daniel.kec@oracle.com>
  • Loading branch information
tomas-langer and danielkec authored Jun 4, 2024
1 parent 1977286 commit 2ff288b
Show file tree
Hide file tree
Showing 10 changed files with 940 additions and 197 deletions.
2 changes: 1 addition & 1 deletion docs-internal/http-features.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ Features
| Context | 1100 |
| Access Log | 1000 |
| Tracing | 900 |
| CORS | 950 |
| CORS | 850 |
| Security | 800 |
| Routing (all handlers) | 100 |
| OpenAPI | 90 |
Expand Down
344 changes: 212 additions & 132 deletions docs/src/main/asciidoc/se/webserver.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,14 @@ include::{rootdir}/includes/se.adoc[]
- <<Configuration, Configuration>>
** <<Configuring the WebServer in Your Code, Configuring the WebServer in Your Code>>
** <<Configuring the WebServer in a Configuration File, Configuring the WebServer in a Configuration File>>
** <<Configuring TLS, Configuring TLS>>
** <<Configuration Options, Configuration Options>>
*** <<Routing, Routing>>
*** <<Request Handling, Request Handling>>
*** <<Error Handling, Error Handling>>
- <<Server Features, Server Features>>
** <<Access Log, Access Log>>
** <<Context, Context>>
- <<Supported Technologies, Supported Technologies>>
** <<HTTP/2 Support, HTTP/2 Support>>
** <<Static Content Support, Static Content Support>>
Expand Down Expand Up @@ -96,6 +100,85 @@ include::{sourcedir}/se/WebServerSnippets.java[tag=snippet_2, indent=0]
just use `Config.create()`
<2> Server expects the configuration tree located on the node of `server`
=== Configuring TLS
Configure TLS either programmatically, or by the Helidon configuration framework.
==== Configuring TLS in Your Code
To configure TLS in WebServer programmatically create your keystore configuration and pass it to the WebServer builder.
[source,java]
----
include::{sourcedir}/se/WebServerSnippets.java[tag=snippet_30, indent=0]
----
==== Configuring TLS in the Config File
It is also possible to configure TLS via the config file.
[source,yaml]
.WebServer TLS configuration file `application.yaml`
----
server:
tls:
#Truststore setup
trust:
keystore:
passphrase: "password"
trust-store: true
resource:
resource-path: "keystore.p12"
# Keystore with private key and server certificate
private-key:
keystore:
passphrase: "password"
resource:
resource-path: "keystore.p12"
----
Then, in your application code, load the configuration from that file.
[source,java]
.WebServer initialization using the `application.yaml` file located on the classpath
----
include::{sourcedir}/se/WebServerSnippets.java[tag=snippet_2, indent=0]
----
<1> `application.yaml` is a default configuration source loaded when YAML support is on classpath, so we can
just use `Config.create()`
<2> Server expects the configuration tree located on the node of `server`
Or you can only create WebServerTls instance based on the config file.
[source,java]
.WebServerTls instance based on `application.yaml` file located on the classpath
----
include::{sourcedir}/se/WebServerSnippets.java[tag=snippet_31, indent=0]
----
This can alternatively be configured with paths to PKCS#8 PEM files rather than KeyStores:
[source,yaml]
.WebServer TLS configuration file `application.yaml`
----
server:
tls:
#Truststore setup
trust:
pem:
certificates:
resource:
resource-path: "ca-bundle.pem"
private-key:
pem:
key:
resource:
resource-path: "key.pem"
cert-chain:
resource:
resource-path: "chain.pem"
----
=== Configuration Options
include::{rootdir}/config/io_helidon_webserver_WebServer.adoc[leveloffset=+2,tag=config]
Expand Down Expand Up @@ -202,6 +285,15 @@ include::{sourcedir}/se/WebServerSnippets.java[tag=snippet_7, indent=0]
----
In this example, the `GET` handler matches requests to `/hello/subpath`.
[[anchor-http-feature]]
=== Using `HttpFeature`
By implementing the `io.helidon.webserver.http.HttpFeature` interface, you can organize multiple routes and/or filters into
a feature, that will be setup according to its defined `io.helidon.common.Weight` (or using `io.helidon.common.Weighted`).
Each service has access to the routing builder. HTTP Features are configured for each routing builder. If there is a need
to configure a feature for multiple sockets, you can use <<Server Features, Server Feature>> instead.
== Request Handling
Implement the logic to handle requests to WebServer in a `Handler`, which is a `FunctionalInterface`.
Expand Down Expand Up @@ -389,6 +481,126 @@ include::{sourcedir}/se/WebServerSnippets.java[tag=snippet_21, indent=0]
* Otherwise, the exceptions are translated to an Internal Server Error HTTP
error code `500`.
=== Configuration Options
include::{rootdir}/config/io_helidon_common_tls_Tls.adoc[leveloffset=+2,tag=config]
== Server Features
Server features provide additional functionality to the WebServer, through modification of the server configuration,
listener configuration, or routing.
A server feature can be added by implementing `io.helidon.webserver.spi.ServerFeature`.
Server features support automated discovery, as long as the implementation is available through Java `ServiceLoader`.
Server features can also be added through configuration, as can be seen above in <<Configuration Options, Configuration Options>>,
configuration key `features`.
All features (both `ServerFeature` and <<anchor-http-feature, HttpFeature>>) honor weight of the feature
(defined either through `@Weight` annotation, or by implementing `Weighted` interface) when registering routes,
`HttpService`, or `Filter` to the routing.
The following table shows available server features and their weight. The highest weight is always registered (and invoked)
first.
|===
|Feature |Weight
|<<Context, Context>>
|1100
|<<Access Log, Access Log>>
|1000
|xref:tracing.adoc[Tracing]
|900
|xref:cors.adoc[CORS]
|850
|xref:security/introduction.adoc[Security]
|800
|Routing (all handlers and filters)
|100
|xref:openapi/openapi.adoc[OpenAPI]
|90
|xref:observability.adoc[Observability]
|80
|===
=== Context
Context feature adds a filter that executes all requests within the context of `io.helidon.common.context.Context`.
A `Context` instance is available on `ServerRequest` even if this feature is not added. This feature adds support for
obtaining request context through `io.helidon.common.context.Contexts.context()`.
This feature will provide the same behavior as previous versions of Helidon. Since Helidon 4.0.0, this feature is not
automatically added.
To enable execution of routes within Context, add the following dependency to project's `pom.xml`:
[source,xml]
----
<dependency>
<groupId>io.helidon.webserver</groupId>
<artifactId>helidon-webserver-context</artifactId>
</dependency>
----
Context feature can be configured, all options shown below are also available both in config, and programmatically
when using builder.
include::{rootdir}/config/io_helidon_webserver_context_ContextFeature.adoc[leveloffset=+1]
=== Access Log
Access logging in Helidon is done by a dedicated module that can be
added to WebServer and configured.
Access logging is a Helidon WebServer `ServerFeature`. Access Log feature has a
very high weight, so it is registered before other features (such as security) that may
terminate a request. This is to ensure the log contains all requests with appropriate status codes.
To enable Access logging add the following dependency to project's `pom.xml`:
[source,xml]
----
<dependency>
<groupId>io.helidon.webserver</groupId>
<artifactId>helidon-webserver-access-log</artifactId>
</dependency>
----
==== Configuring Access Log in Your Code
`AccessLogFeature` is discovered automatically by default, and configured through `server.features.access-log`.
You can also configure this feature in code by registering it with WebServer (which will replace the discovered feature).
[source,java]
----
include::{sourcedir}/se/WebServerSnippets.java[tag=snippet_29, indent=0]
----
==== Configuring Access Log in a Configuration File
Access log can be configured as follows:
[source, yaml]
.Access Log configuration file
----
server:
port: 8080
features:
access-log:
format: "%h %l %u %t %r %s %b %{Referer}i"
----
All options shown below are also available programmatically when using builder.
include::{rootdir}/config/io_helidon_webserver_accesslog_AccessLogConfig.adoc[leveloffset=+1]
== Supported Technologies
== HTTP/2 Support
Expand Down Expand Up @@ -624,138 +836,6 @@ curl --noproxy '*' -X POST -H "Content-Type: application/json" \
{"name":"Joe"}
----
== Access Log
Access logging in Helidon is done by a dedicated module that can be
added to WebServer and configured.
Access logging is a Helidon WebServer `ServerFeature`. Access Log feature has a
very high weight, so it is registered before other features (such as security) that may
terminate a request. This is to ensure the log contains all requests with appropriate status codes.
To enable Access logging add the following dependency to project's `pom.xml`:
[source,xml]
----
<dependency>
<groupId>io.helidon.webserver</groupId>
<artifactId>helidon-webserver-access-log</artifactId>
</dependency>
----
=== Configuring Access Log in Your Code
`AccessLogFeature` is discovered automatically by default, and configured through `server.features.access-log`.
You can also configure this feature in code by registering it with WebServer (which will replace the discovered feature).
[source,java]
----
include::{sourcedir}/se/WebServerSnippets.java[tag=snippet_29, indent=0]
----
=== Configuring Access Log in a Configuration File
Access log can be configured as follows:
[source, yaml]
.Access Log configuration file
----
server:
port: 8080
features:
access-log:
format: "%h %l %u %t %r %s %b %{Referer}i"
----
All options shown below are also available programmatically when using builder.
include::{rootdir}/config/io_helidon_webserver_accesslog_AccessLogConfig.adoc[leveloffset=+1]
== TLS Configuration
Configure TLS either programmatically, or by the Helidon configuration framework.
=== Configuring TLS in Your Code
To configure TLS in WebServer programmatically create your keystore configuration and pass it to the WebServer builder.
[source,java]
----
include::{sourcedir}/se/WebServerSnippets.java[tag=snippet_30, indent=0]
----
=== Configuring TLS in the Config File
It is also possible to configure TLS via the config file.
[source,yaml]
.WebServer TLS configuration file `application.yaml`
----
server:
tls:
#Truststore setup
trust:
keystore:
passphrase: "password"
trust-store: true
resource:
resource-path: "keystore.p12"
# Keystore with private key and server certificate
private-key:
keystore:
passphrase: "password"
resource:
resource-path: "keystore.p12"
----
Then, in your application code, load the configuration from that file.
[source,java]
.WebServer initialization using the `application.yaml` file located on the classpath
----
include::{sourcedir}/se/WebServerSnippets.java[tag=snippet_2, indent=0]
----
<1> `application.yaml` is a default configuration source loaded when YAML support is on classpath, so we can
just use `Config.create()`
<2> Server expects the configuration tree located on the node of `server`
Or you can only create WebServerTls instance based on the config file.
[source,java]
.WebServerTls instance based on `application.yaml` file located on the classpath
----
include::{sourcedir}/se/WebServerSnippets.java[tag=snippet_31, indent=0]
----
This can alternatively be configured with paths to PKCS#8 PEM files rather than KeyStores:
[source,yaml]
.WebServer TLS configuration file `application.yaml`
----
server:
tls:
#Truststore setup
trust:
pem:
certificates:
resource:
resource-path: "ca-bundle.pem"
private-key:
pem:
key:
resource:
resource-path: "key.pem"
cert-chain:
resource:
resource-path: "chain.pem"
----
=== Configuration Options
include::{rootdir}/config/io_helidon_common_tls_Tls.adoc[leveloffset=+2,tag=config]
== HTTP Content Encoding
HTTP encoding can improve bandwidth utilization and transfer speeds in certain scenarios. It
Expand Down
Loading

0 comments on commit 2ff288b

Please sign in to comment.