Skip to content
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
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2021 Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2021, 2022 Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2018 Markus KARG. All rights reserved.
*
* This program and the accompanying materials are made available under the
Expand Down Expand Up @@ -61,7 +61,7 @@ private GrizzlyHttpServer(final GrizzlyHttpContainer container, final JerseySeBo

this.container = container;
this.httpServer = GrizzlyHttpServerFactory.createHttpServer(
configuration.uri(false),
configuration.uri(true),
this.container,
configuration.isHttps(),
configuration.isHttps() ? new SSLEngineConfigurator(sslContext, false,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2021 Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2021, 2022 Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2018 Markus KARG. All rights reserved.
*
* This program and the accompanying materials are made available under the
Expand Down Expand Up @@ -57,7 +57,7 @@ final class JdkHttpServer implements WebServer {

this.container = container;
this.httpServer = JdkHttpServerFactory.createHttpServer(
configuration.uri(false),
configuration.uri(true),
this.container,
configuration.sslContext(),
sslClientAuthentication == OPTIONAL,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2021 Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2021, 2022 Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2018 Markus KARG. All rights reserved.
*
* This program and the accompanying materials are made available under the
Expand Down Expand Up @@ -68,7 +68,7 @@ final class JettyHttpServer implements WebServer {
}
this.container = container;
this.httpServer = JettyHttpContainerFactory.createServer(
configuration.uri(false),
configuration.uri(true),
sslContextFactory,
this.container,
configuration.autoStart());
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2021 Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2021, 2022 Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2018 Markus KARG. All rights reserved.
*
* This program and the accompanying materials are made available under the
Expand Down Expand Up @@ -64,7 +64,7 @@ final class NettyHttpServer implements WebServer {
final SeBootstrap.Configuration.SSLClientAuthentication sslClientAuthentication = configuration
.sslClientAuthentication();

final URI uri = configuration.uri(false);
final URI uri = configuration.uri(true);
this.port = NettyHttpContainerProvider.getPort(uri);

this.container = container;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2021 Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2021, 2022 Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2018 Markus KARG. All rights reserved.
*
* This program and the accompanying materials are made available under the
Expand Down Expand Up @@ -50,7 +50,7 @@ final class SimpleHttpServer implements WebServer {
SimpleHttpServer(final SimpleContainer container, final JerseySeBootstrapConfiguration configuration) {
this.container = container;
this.simpleServer = SimpleContainerFactory.create(
configuration.uri(false),
configuration.uri(true),
configuration.sslContext(),
configuration.sslClientAuthentication(),
this.container,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ public <T> T as(String name, Class<T> clazz) {
}
@Override
public <T> Optional<T> getOptionalProperty(String name, Class<T> clazz) {
return Optional.of(as(name, clazz));
return Optional.ofNullable(as(name, clazz));
}

@Override
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2021 Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2021, 2022 Oracle and/or its affiliates. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0, which is available at
Expand All @@ -18,19 +18,27 @@

import jakarta.ws.rs.SeBootstrap;
import jakarta.ws.rs.core.UriBuilder;
import org.glassfish.jersey.internal.config.ExternalPropertiesConfigurationFactory;
import org.glassfish.jersey.internal.config.SystemPropertiesConfigurationModel;
import org.glassfish.jersey.internal.util.PropertiesClass;
import org.glassfish.jersey.server.internal.LocalizationMessages;
import org.glassfish.jersey.server.spi.Container;
import org.glassfish.jersey.server.spi.WebServer;

import javax.net.ssl.SSLContext;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.URI;
import java.security.NoSuchAlgorithmException;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
import java.util.Random;
import java.util.function.BiFunction;
import java.util.logging.Logger;

import static java.lang.Boolean.FALSE;
import static java.lang.Boolean.TRUE;

/**
Expand All @@ -40,6 +48,7 @@
*/
public final class JerseySeBootstrapConfiguration implements SeBootstrap.Configuration {
private static final Logger LOGGER = Logger.getLogger(JerseySeBootstrapConfiguration.class.getName());
protected static final Random RANDOM = new Random();
private final SeBootstrap.Configuration configuration;

private JerseySeBootstrapConfiguration(SeBootstrap.Configuration configuration) {
Expand All @@ -61,16 +70,60 @@ public Object property(String name) {
public URI uri(boolean resolveDefaultPort) {
final String protocol = configuration.protocol();
final String host = configuration.host();
final int configPort = configuration.port();
final int port = (configPort < 0 && resolveDefaultPort)
? isHttps() ? Container.DEFAULT_HTTPS_PORT : Container.DEFAULT_HTTP_PORT
: configPort;
final int port = resolveDefaultPort ? resolvePort() : configuration.port();
final String rootPath = configuration.rootPath();
final URI uri = UriBuilder.newInstance().scheme(protocol.toLowerCase()).host(host).port(port).path(rootPath)
.build();
return uri;
}

private int resolvePort() {
final int configPort = configuration.port();
final int basePort = allowPrivilegedPorts() ? 0 : 8000;
final int port;
switch (configPort) {
case SeBootstrap.Configuration.DEFAULT_PORT:
port = basePort + (isHttps() ? Container.DEFAULT_HTTPS_PORT : Container.DEFAULT_HTTP_PORT);
break;
case SeBootstrap.Configuration.FREE_PORT:
port = _resolvePort(basePort == 0);
break;
default:
port = configPort;
break;
}
return port;
}

private int _resolvePort(boolean allowPrivilegedPort) {
final int basePort = allowPrivilegedPort ? 0 : 1023;
// Get the initial range parameters
final int lower = basePort;
final int range = 0xFFFF;

// Select a start point in the range
final int initialOffset = RANDOM.nextInt(range - lower);

// Loop the offset through all ports in the range and attempt
// to bind to each
int offset = initialOffset;
ServerSocket socket;
do {
final int port = lower + offset;
try {
socket = new ServerSocket(port);
socket.close();
return port;
} catch (IOException caught) {
// Swallow exceptions until the end
}
offset = (offset + 1) % range;
} while (offset != initialOffset);

// If a port can't be bound, throw the exception
throw new IllegalArgumentException(LocalizationMessages.COULD_NOT_BIND_TO_ANY_PORT());
}

/**
* Return {@link SSLContext} in the configuration if the protocol scheme is {@code HTTPS}.
* @return the SSLContext in the configuration.
Expand Down Expand Up @@ -100,6 +153,16 @@ public boolean autoStart() {
return autoStart;
}

/**
* Defines if the {@link WebServer} should start on a privileged port when port is not set.
* @return true if {@link ServerProperties#WEBSERVER_AUTO_START} is {@code true}, {@code false} otherwise.
*/
public boolean allowPrivilegedPorts() {
return Optional.ofNullable(
(Boolean) configuration.property(ServerProperties.WEBSERVER_ALLOW_PRIVILEGED_PORTS))
.orElse(FALSE);
}

/**
* Factory method creating {@code JerseySeBootstrapConfiguration} wrapper around {@link SeBootstrap.Configuration}.
* @param configuration wrapped configuration
Expand Down Expand Up @@ -129,16 +192,17 @@ public static final class Builder implements SeBootstrap.Configuration.Builder {
PROPERTY_TYPES.put(SeBootstrap.Configuration.ROOT_PATH, String.class);
PROPERTY_TYPES.put(SeBootstrap.Configuration.SSL_CONTEXT, SSLContext.class);
PROPERTY_TYPES.put(SeBootstrap.Configuration.SSL_CLIENT_AUTHENTICATION, SSLClientAuthentication.class);
PROPERTY_TYPES.put(ServerProperties.WEBSERVER_CLASS, Class.class);
PROPERTY_TYPES.put(ServerProperties.WEBSERVER_ALLOW_PRIVILEGED_PORTS, Boolean.class);
PROPERTY_TYPES.put(ServerProperties.WEBSERVER_AUTO_START, Boolean.class);
PROPERTY_TYPES.put(ServerProperties.WEBSERVER_CLASS, Class.class);
}

private final Map<String, Object> properties = new HashMap<>();

private Builder() {
this.properties.put(SeBootstrap.Configuration.PROTOCOL, "HTTP"); // upper case mandated by javadoc
this.properties.put(SeBootstrap.Configuration.HOST, "localhost");
this.properties.put(SeBootstrap.Configuration.PORT, -1); // Auto-select port 80 for HTTP or 443 for HTTPS
this.properties.put(SeBootstrap.Configuration.PORT, -1); // Auto-select port 8080 for HTTP or 8443 for HTTPS
this.properties.put(SeBootstrap.Configuration.ROOT_PATH, "/");
this.properties.put(ServerProperties.WEBSERVER_CLASS, WebServer.class); // Auto-select first provider
try {
Expand All @@ -149,6 +213,15 @@ private Builder() {
this.properties.put(SeBootstrap.Configuration.SSL_CLIENT_AUTHENTICATION,
SeBootstrap.Configuration.SSLClientAuthentication.NONE);
this.properties.put(ServerProperties.WEBSERVER_AUTO_START, TRUE);
this.properties.put(ServerProperties.WEBSERVER_ALLOW_PRIVILEGED_PORTS, FALSE);

SystemPropertiesConfigurationModel propertiesConfigurationModel = new SystemPropertiesConfigurationModel(
Collections.singletonList(Properties.class.getName())
);
from((name, aClass) -> String.class.equals(aClass) || Integer.class.equals(aClass) || Boolean.class.equals(aClass)
? propertiesConfigurationModel.getOptionalProperty(name, aClass)
: Optional.empty()
);
}

@Override
Expand Down Expand Up @@ -208,4 +281,41 @@ public JerseySeBootstrapConfiguration.Builder from(Object externalConfig) {
return this;
}
}

/**
* Name the properties to be internally read from System properties by {@link ExternalPropertiesConfigurationFactory}.
* This is required just when SecurityManager is on, otherwise all system properties are read.
*/
@PropertiesClass
private static class Properties {
/**
* See {@link SeBootstrap.Configuration#PROTOCOL} property.
*/
public static final String SE_BOOTSTRAP_CONFIGURATION_PROTOCOL = SeBootstrap.Configuration.PROTOCOL;

/**
* See {@link SeBootstrap.Configuration#HOST} property.
*/
public static final String SE_BOOTSTRAP_CONFIGURATION_HOST = SeBootstrap.Configuration.HOST;

/**
* See {@link SeBootstrap.Configuration#PORT} property.
*/
public static final String SE_BOOTSTRAP_CONFIGURATION_PORT = SeBootstrap.Configuration.PORT;

/**
* See {@link SeBootstrap.Configuration#ROOT_PATH} property.
*/
public static final String SE_BOOTSTRAP_CONFIGURATION_ROOT_PATH = SeBootstrap.Configuration.ROOT_PATH;

/**
* See {@link ServerProperties#WEBSERVER_ALLOW_PRIVILEGED_PORTS} property.
*/
public static final String WEBSERVER_ALLOW_PRIVILEGED_PORTS = ServerProperties.WEBSERVER_ALLOW_PRIVILEGED_PORTS;

/**
* See {@link ServerProperties#WEBSERVER_AUTO_START} property.
*/
public static final String WEBSERVER_AUTO_START = ServerProperties.WEBSERVER_AUTO_START;
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2012, 2021 Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2012, 2022 Oracle and/or its affiliates. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0, which is available at
Expand All @@ -24,6 +24,7 @@
import org.glassfish.jersey.internal.util.PropertiesClass;
import org.glassfish.jersey.internal.util.PropertiesHelper;
import org.glassfish.jersey.internal.util.PropertyAlias;
import org.glassfish.jersey.server.spi.Container;
import org.glassfish.jersey.server.spi.WebServer;


Expand All @@ -38,25 +39,6 @@
@PropertiesClass
public final class ServerProperties {

/**
* Defines the implementation of {@link WebServer} to bootstrap.
* <p>
* By default auto-selects the first server provider found.
* </p>
* @since 3.1.0
*/
public static final String WEBSERVER_CLASS = "jersey.config.server.webserver.class";

/**
* Whether to automatically startup {@link WebServer} at bootstrap.
* <p>
* By default, servers are immediately listening to connections after bootstrap,
* so no explicit invocation of {@link WebServer#start()} is needed.
* </p>
* @since 3.1.0
*/
public static final String WEBSERVER_AUTO_START = "jersey.config.server.webserver.autostart";

/**
* Defines one or more packages that contain application-specific resources and
* providers.
Expand Down Expand Up @@ -783,6 +765,50 @@ public final class ServerProperties {
public static final String EMPTY_REQUEST_MEDIA_TYPE_MATCHES_ANY_CONSUMES =
"jersey.config.server.empty.request.media.matches.any.consumes";

/**
* Defines whether to allow privileged ports (0-1023) to be used to start the {@link WebServer} implementation
* to be chosen from the unused ports when the {@link jakarta.ws.rs.SeBootstrap.Configuration#PORT} is set to {@code -1}
* or unset.
* <p>
* The default ports are {@link Container#DEFAULT_HTTP_PORT} for HTTP and {@link Container#DEFAULT_HTTPS_PORT}
* for HTTPS when {@code WEBSERVER_ALLOW_PRIVILEGED_PORTS} is {@code true} or 8080 for HTTP and 8443 for HTTPS when
* {@code WEBSERVER_ALLOW_PRIVILEGED_PORTS} is {@code false}.
* </p>
* <p>
* If {@link jakarta.ws.rs.SeBootstrap.Configuration#PORT} is set to {@code 0}, the implementation chooses random ports
* (0-65535) when {@code WEBSERVER_ALLOW_PRIVILEGED_PORTS} is {@code true}, or (1024-65535) when
* {@code WEBSERVER_ALLOW_PRIVILEGED_PORTS} is {@code false.}
* </p>
* <p>
* The default this is {@code false}. Use {@code true} to allow a restricted port number. The name of the configuration
* property is <tt>{@value}</tt>.
* </p>
* @since 3.1.0
*/
public static final String WEBSERVER_ALLOW_PRIVILEGED_PORTS =
"jersey.config.server.bootstrap.webserver.allow.privileged.ports";

/**
* Whether to automatically startup {@link WebServer} at bootstrap.
* <p>
* By default, servers are immediately listening to connections after bootstrap,
* so no explicit invocation of {@link WebServer#start()} is needed. The name of the configuration
* property is <tt>{@value}</tt>.
* </p>
* @since 3.1.0
*/
public static final String WEBSERVER_AUTO_START = "jersey.config.server.bootstrap.webserver.autostart";

/**
* Defines the implementation of {@link WebServer} to bootstrap.
* <p>
* By default auto-selects the first server provider found. The name of the configuration
* property is <tt>{@value}</tt>.
* </p>
* @since 3.1.0
*/
public static final String WEBSERVER_CLASS = "jersey.config.server.bootstrap.webserver.class";

/**
* JVM argument to define the value of
* {@link org.glassfish.jersey.server.internal.monitoring.core.ReservoirConstants#COLLISION_BUFFER_POWER}.
Expand Down
Loading