High-performance HTTP server implementation built on Java 21 Virtual Threads for Helidon microservices framework
—
Extension points for custom protocols, features, connection handling, and streaming capabilities. Enables third-party integrations and custom server functionality through well-defined service provider interfaces.
Service provider interface for extending server functionality with custom features.
/**
* SPI for server features and extensions.
*/
interface ServerFeature {
/**
* Setup the server feature.
* @param serverContext server context for configuration
*/
void setup(ServerFeatureContext serverContext);
/**
* Get feature name.
* @return feature name
*/
String name();
/**
* Get feature weight for ordering.
* @return feature weight (higher weight = later initialization)
*/
default double weight() {
return 100.0;
}
/**
* Called before server starts.
* @param server the server instance
*/
default void beforeStart(WebServer server) {
// Default implementation does nothing
}
/**
* Called after server starts.
* @param server the server instance
*/
default void afterStart(WebServer server) {
// Default implementation does nothing
}
/**
* Called before server stops.
* @param server the server instance
*/
default void beforeStop(WebServer server) {
// Default implementation does nothing
}
/**
* Called after server stops.
* @param server the server instance
*/
default void afterStop(WebServer server) {
// Default implementation does nothing
}
}/**
* Provider for server features.
*/
interface ServerFeatureProvider {
/**
* Create server feature instance.
* @param config feature configuration
* @return server feature instance
*/
ServerFeature create(Config config);
/**
* Get configuration type supported by this provider.
* @return configuration class
*/
Class<? extends Config> configType();
/**
* Get provider name.
* @return provider name
*/
String name();
}Usage Examples:
// Custom metrics feature
public class MetricsServerFeature implements ServerFeature {
private final MeterRegistry meterRegistry;
private Timer requestTimer;
public MetricsServerFeature(MeterRegistry meterRegistry) {
this.meterRegistry = meterRegistry;
}
@Override
public void setup(ServerFeatureContext context) {
this.requestTimer = Timer.builder("http.requests")
.description("HTTP request duration")
.register(meterRegistry);
// Add metrics filter to all HTTP routing
context.routing(HttpRouting.class, routing -> {
routing.addFilter(this::metricsFilter);
});
}
private void metricsFilter(FilterChain chain, RoutingRequest req, RoutingResponse res) {
Timer.Sample sample = Timer.start(meterRegistry);
try {
chain.proceed();
} finally {
sample.stop(requestTimer
.tag("method", req.method().text())
.tag("status", String.valueOf(res.status().code())));
}
}
@Override
public String name() {
return "metrics";
}
@Override
public double weight() {
return 50.0; // Early in the chain
}
}
// Feature provider
public class MetricsFeatureProvider implements ServerFeatureProvider {
@Override
public ServerFeature create(Config config) {
MeterRegistry registry = createMeterRegistry(config);
return new MetricsServerFeature(registry);
}
@Override
public Class<? extends Config> configType() {
return MetricsConfig.class;
}
@Override
public String name() {
return "metrics";
}
}Service provider interface for custom protocol implementations.
/**
* Configuration for protocols.
*/
interface ProtocolConfig {
/**
* Get protocol name.
* @return protocol name
*/
String protocolName();
/**
* Get protocol version.
* @return protocol version
*/
String protocolVersion();
/**
* Get protocol configuration type.
* @return configuration type
*/
String configType();
/**
* Get protocol weight for ordering.
* @return protocol weight
*/
default double weight() {
return 100.0;
}
}/**
* Provider for protocol configurations.
*/
interface ProtocolConfigProvider {
/**
* Get configuration type supported by this provider.
* @return configuration class
*/
Class<? extends ProtocolConfig> configType();
/**
* Create protocol configuration from generic config.
* @param config configuration source
* @return protocol configuration
*/
ProtocolConfig create(Config config);
/**
* Get protocol type name.
* @return protocol type
*/
String protocolType();
}Usage Examples:
// Custom HTTP/2 protocol configuration
public class Http2Config implements ProtocolConfig {
private final int maxConcurrentStreams;
private final int initialWindowSize;
private final boolean enablePush;
private Http2Config(Builder builder) {
this.maxConcurrentStreams = builder.maxConcurrentStreams;
this.initialWindowSize = builder.initialWindowSize;
this.enablePush = builder.enablePush;
}
@Override
public String protocolName() {
return "HTTP";
}
@Override
public String protocolVersion() {
return "2.0";
}
@Override
public String configType() {
return "http2";
}
public int maxConcurrentStreams() { return maxConcurrentStreams; }
public int initialWindowSize() { return initialWindowSize; }
public boolean enablePush() { return enablePush; }
public static Builder builder() { return new Builder(); }
public static class Builder {
private int maxConcurrentStreams = 100;
private int initialWindowSize = 65535;
private boolean enablePush = true;
public Builder maxConcurrentStreams(int max) {
this.maxConcurrentStreams = max;
return this;
}
public Builder initialWindowSize(int size) {
this.initialWindowSize = size;
return this;
}
public Builder enablePush(boolean enable) {
this.enablePush = enable;
return this;
}
public Http2Config build() {
return new Http2Config(this);
}
}
}
// HTTP/2 protocol provider
public class Http2ProtocolProvider implements ProtocolConfigProvider {
@Override
public Class<? extends ProtocolConfig> configType() {
return Http2Config.class;
}
@Override
public ProtocolConfig create(Config config) {
return Http2Config.builder()
.maxConcurrentStreams(config.get("max-concurrent-streams").asInt().orElse(100))
.initialWindowSize(config.get("initial-window-size").asInt().orElse(65535))
.enablePush(config.get("enable-push").asBoolean().orElse(true))
.build();
}
@Override
public String protocolType() {
return "http2";
}
}Service provider interfaces for custom connection handling and selection.
/**
* Interface for server connections.
*/
interface ServerConnection {
/**
* Get connection channel.
* @return connection channel
*/
SocketChannel channel();
/**
* Get connection context.
* @return connection context
*/
ConnectionContext context();
/**
* Check if connection is secure.
* @return true if secure (TLS)
*/
boolean isSecure();
/**
* Get local address.
* @return local socket address
*/
SocketAddress localAddress();
/**
* Get remote address.
* @return remote socket address
*/
SocketAddress remoteAddress();
/**
* Close the connection.
*/
void close();
/**
* Check if connection is active.
* @return true if connection is active
*/
boolean isActive();
/**
* Handle connection processing.
*/
void handle();
/**
* Get connection protocol.
* @return protocol name
*/
String protocol();
}/**
* Selector for server connections.
*/
interface ServerConnectionSelector {
/**
* Select appropriate connection for request.
* @param context connection context
* @return selected connection
*/
ServerConnection select(ConnectionContext context);
/**
* Release connection after use.
* @param connection connection to release
*/
void release(ServerConnection connection);
/**
* Close all connections managed by this selector.
*/
void closeAll();
/**
* Get selector statistics.
* @return connection statistics
*/
ConnectionStats statistics();
}/**
* Provider for connection selectors.
*/
interface ServerConnectionSelectorProvider {
/**
* Create connection selector.
* @param config selector configuration
* @return connection selector
*/
ServerConnectionSelector create(ProtocolConfig config);
/**
* Get provider name.
* @return provider name
*/
String name();
/**
* Get configuration type.
* @return configuration class
*/
Class<? extends ProtocolConfig> configType();
/**
* Check if this provider supports the given protocol.
* @param protocol protocol name
* @return true if supported
*/
boolean supports(String protocol);
}Usage Examples:
// Custom WebSocket connection implementation
public class WebSocketConnection implements ServerConnection {
private final SocketChannel channel;
private final ConnectionContext context;
private final WebSocketHandler handler;
private volatile boolean active = true;
public WebSocketConnection(SocketChannel channel, ConnectionContext context,
WebSocketHandler handler) {
this.channel = channel;
this.context = context;
this.handler = handler;
}
@Override
public void handle() {
try {
handler.onConnect(this);
processWebSocketFrames();
} catch (Exception e) {
handler.onError(this, e);
} finally {
handler.onClose(this);
active = false;
}
}
@Override
public String protocol() {
return "websocket";
}
// Implementation of other ServerConnection methods...
}
// WebSocket connection selector
public class WebSocketConnectionSelector implements ServerConnectionSelector {
private final Set<WebSocketConnection> activeConnections = ConcurrentHashMap.newKeySet();
@Override
public ServerConnection select(ConnectionContext context) {
WebSocketConnection connection = new WebSocketConnection(
context.channel(), context, new DefaultWebSocketHandler());
activeConnections.add(connection);
return connection;
}
@Override
public void release(ServerConnection connection) {
if (connection instanceof WebSocketConnection wsConn) {
activeConnections.remove(wsConn);
}
}
@Override
public void closeAll() {
activeConnections.forEach(ServerConnection::close);
activeConnections.clear();
}
}Service provider interface for custom streaming response handlers.
/**
* SPI for handling streaming responses.
*/
interface Sink {
/**
* Write data to sink.
* @param data data to write
*/
void writeData(DataChunk data);
/**
* Signal completion of stream.
*/
void complete();
/**
* Signal error in stream.
* @param throwable error that occurred
*/
void error(Throwable throwable);
/**
* Check if sink is closed.
* @return true if sink is closed
*/
boolean isClosed();
/**
* Close the sink.
*/
void close();
/**
* Get sink type.
* @return sink type identifier
*/
String type();
}/**
* Provider for sink implementations.
*/
interface SinkProvider {
/**
* Create sink for media type.
* @param context sink provider context
* @return sink instance
*/
Sink create(SinkProviderContext context);
/**
* Check if this provider supports the media type.
* @param mediaType media type to check
* @return true if supported
*/
boolean supports(MediaType mediaType);
/**
* Get provider name.
* @return provider name
*/
String name();
/**
* Get provider weight for ordering.
* @return provider weight
*/
default double weight() {
return 100.0;
}
}/**
* Context for sink providers.
*/
interface SinkProviderContext {
/**
* Get target media type.
* @return media type
*/
MediaType mediaType();
/**
* Get response headers.
* @return response headers
*/
WritableHeaders<?> headers();
/**
* Get response output stream.
* @return output stream
*/
OutputStream outputStream();
/**
* Get server response.
* @return server response
*/
ServerResponse response();
/**
* Get request context.
* @return request context
*/
Context context();
}Usage Examples:
// Custom JSON streaming sink
public class JsonStreamingSink implements Sink {
private final OutputStream outputStream;
private final ObjectMapper objectMapper;
private boolean closed = false;
private boolean firstWrite = true;
public JsonStreamingSink(OutputStream outputStream, ObjectMapper objectMapper) {
this.outputStream = outputStream;
this.objectMapper = objectMapper;
try {
outputStream.write('['); // Start JSON array
} catch (IOException e) {
throw new RuntimeException("Failed to initialize JSON stream", e);
}
}
@Override
public void writeData(DataChunk data) {
if (closed) throw new IllegalStateException("Sink is closed");
try {
if (!firstWrite) {
outputStream.write(',');
}
firstWrite = false;
objectMapper.writeValue(outputStream, data.data());
outputStream.flush();
} catch (IOException e) {
error(e);
}
}
@Override
public void complete() {
if (!closed) {
try {
outputStream.write(']'); // End JSON array
outputStream.flush();
} catch (IOException e) {
// Log error but don't throw
} finally {
close();
}
}
}
@Override
public String type() {
return "json-streaming";
}
// Implementation of other Sink methods...
}
// JSON streaming sink provider
public class JsonStreamingSinkProvider implements SinkProvider {
private final ObjectMapper objectMapper = new ObjectMapper();
@Override
public Sink create(SinkProviderContext context) {
context.headers().contentType(MediaType.APPLICATION_JSON);
context.headers().set("Transfer-Encoding", "chunked");
return new JsonStreamingSink(context.outputStream(), objectMapper);
}
@Override
public boolean supports(MediaType mediaType) {
return MediaType.APPLICATION_JSON.test(mediaType);
}
@Override
public String name() {
return "json-streaming";
}
@Override
public double weight() {
return 200.0; // Higher priority than default
}
}Service provider interface for HTTP/1.1 protocol upgrades (WebSocket, HTTP/2, etc.).
/**
* SPI for HTTP/1.1 protocol upgrades.
*/
interface Http1Upgrader {
/**
* Check if this upgrader supports the requested protocol.
* @param protocol protocol name from Upgrade header
* @return true if supported
*/
boolean supports(String protocol);
/**
* Perform protocol upgrade.
* @param request HTTP/1.1 request with upgrade headers
* @param response HTTP/1.1 response for upgrade response
* @param connection underlying connection
* @return upgraded connection handler
*/
UpgradeResult upgrade(Http1ServerRequest request,
Http1ServerResponse response,
Http1Connection connection);
/**
* Get upgrade protocol name.
* @return protocol name
*/
String protocolName();
/**
* Get upgrader weight for selection priority.
* @return upgrader weight
*/
default double weight() {
return 100.0;
}
}/**
* Provider for HTTP/1.1 upgrade implementations.
*/
interface Http1UpgradeProvider {
/**
* Create upgrader instance.
* @param config upgrade configuration
* @return upgrader instance
*/
Http1Upgrader create(Config config);
/**
* Get supported protocol name.
* @return protocol name
*/
String protocolName();
/**
* Get provider name.
* @return provider name
*/
String name();
}Usage Examples:
// WebSocket upgrade implementation
public class WebSocketUpgrader implements Http1Upgrader {
@Override
public boolean supports(String protocol) {
return "websocket".equalsIgnoreCase(protocol);
}
@Override
public UpgradeResult upgrade(Http1ServerRequest request,
Http1ServerResponse response,
Http1Connection connection) {
// Validate WebSocket upgrade headers
Optional<String> key = request.headers().first("Sec-WebSocket-Key");
Optional<String> version = request.headers().first("Sec-WebSocket-Version");
if (key.isEmpty() || !"13".equals(version.orElse(""))) {
return UpgradeResult.failed("Invalid WebSocket upgrade request");
}
// Generate WebSocket accept key
String acceptKey = generateWebSocketAcceptKey(key.get());
// Send upgrade response
response.status(101)
.header("Upgrade", "websocket")
.header("Connection", "Upgrade")
.header("Sec-WebSocket-Accept", acceptKey)
.send();
// Return upgraded connection handler
return UpgradeResult.success(new WebSocketConnectionHandler(connection));
}
@Override
public String protocolName() {
return "websocket";
}
private String generateWebSocketAcceptKey(String key) {
// WebSocket key generation logic
String magic = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
return Base64.getEncoder().encodeToString(
MessageDigest.getInstance("SHA-1")
.digest((key + magic).getBytes()));
}
}
// WebSocket upgrade provider
public class WebSocketUpgradeProvider implements Http1UpgradeProvider {
@Override
public Http1Upgrader create(Config config) {
return new WebSocketUpgrader();
}
@Override
public String protocolName() {
return "websocket";
}
@Override
public String name() {
return "websocket-upgrade";
}
}Helidon WebServer uses Java's ServiceLoader mechanism to discover SPI implementations:
// META-INF/services/io.helidon.webserver.spi.ServerFeatureProvider
com.example.MetricsFeatureProvider
com.example.TracingFeatureProvider
// META-INF/services/io.helidon.webserver.spi.ProtocolConfigProvider
com.example.Http2ProtocolProvider
com.example.GrpcProtocolProvider
// META-INF/services/io.helidon.webserver.http.spi.SinkProvider
com.example.JsonStreamingSinkProvider
com.example.XmlStreamingSinkProvider
// META-INF/services/io.helidon.webserver.http1.spi.Http1UpgradeProvider
com.example.WebSocketUpgradeProvider
com.example.Http2UpgradeProvider// Example: Custom authentication feature
@AutoService(ServerFeatureProvider.class)
public class AuthFeatureProvider implements ServerFeatureProvider {
@Override
public ServerFeature create(Config config) {
return new AuthServerFeature(
config.get("auth.jwt-secret").asString().orElse("default-secret"),
config.get("auth.token-expiry").as(Duration.class).orElse(Duration.ofHours(1))
);
}
@Override
public Class<? extends Config> configType() {
return AuthConfig.class;
}
@Override
public String name() {
return "authentication";
}
}
// Usage in server configuration
WebServerConfig serverConfig = WebServerConfig.builder()
.port(8080)
.routing(HttpRouting.builder()
.get("/secure", (req, res) -> {
// This will be protected by the auth feature
res.send("Secure content");
})
.build())
.build();
// The auth feature is automatically loaded and applied
WebServer server = WebServer.create(serverConfig).start();Install with Tessl CLI
npx tessl i tessl/maven-io-helidon-webserver--helidon-webserver