Skip to content

4.x: register routing in weighted order of Server and HTTP Features #8826

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Jun 4, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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