Index: 3rdParty_sources/undertow/org/wildfly/extension/undertow/AbstractCookieDefinition.java =================================================================== diff -u --- 3rdParty_sources/undertow/org/wildfly/extension/undertow/AbstractCookieDefinition.java (revision 0) +++ 3rdParty_sources/undertow/org/wildfly/extension/undertow/AbstractCookieDefinition.java (revision e704ad812feb0fa447e5bd63332f753ac1a94b70) @@ -0,0 +1,140 @@ +/* + * Copyright The WildFly Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package org.wildfly.extension.undertow; + +import java.util.Collection; +import java.util.function.UnaryOperator; + +import org.jboss.as.controller.AttributeDefinition; +import org.jboss.as.controller.ExpressionResolver; +import org.jboss.as.controller.OperationContext; +import org.jboss.as.controller.OperationFailedException; +import org.jboss.as.controller.PathAddress; +import org.jboss.as.controller.PathElement; +import org.jboss.as.controller.PersistentResourceDefinition; +import org.jboss.as.controller.RestartParentResourceAddHandler; +import org.jboss.as.controller.RestartParentResourceRemoveHandler; +import org.jboss.as.controller.SimpleAttributeDefinitionBuilder; +import org.jboss.dmr.ModelNode; +import org.jboss.dmr.ModelType; +import org.jboss.msc.service.ServiceName; + +/** + * Resource definition for a Cookie configuration. + * + * @author Radoslav Husar + */ +abstract class AbstractCookieDefinition extends PersistentResourceDefinition { + + enum Attribute implements org.jboss.as.clustering.controller.Attribute { + OPTIONAL_NAME(Constants.NAME, ModelType.STRING), + REQUIRED_NAME(Constants.NAME, ModelType.STRING, ad -> ad.setRequired(true)), + DOMAIN(Constants.DOMAIN, ModelType.STRING), + COMMENT(Constants.COMMENT, ModelType.STRING, ad -> ad.setDeprecated(UndertowSubsystemModel.VERSION_13_0_0.getVersion())), + HTTP_ONLY(Constants.HTTP_ONLY, ModelType.BOOLEAN), + SECURE(Constants.SECURE, ModelType.BOOLEAN), + MAX_AGE(Constants.MAX_AGE, ModelType.INT), + ; + private final AttributeDefinition definition; + + Attribute(String name, ModelType type) { + this(name, type, UnaryOperator.identity()); + } + + Attribute(String name, ModelType type, UnaryOperator builder) { + this.definition = builder.apply(new SimpleAttributeDefinitionBuilder(name, type) + .setRequired(false) + .setRestartAllServices() + .setAllowExpression(true) + ).build(); + } + + @Override + public AttributeDefinition getDefinition() { + return this.definition; + } + } + + Collection attributes; + + public AbstractCookieDefinition(PathElement path, Collection attributes) { + super(path, + UndertowExtension.getResolver(path.getKeyValuePair()), + new SessionCookieAdd(attributes), + new SessionCookieRemove() + ); + this.attributes = attributes; + } + + @Override + public Collection getAttributes() { + return attributes; + } + + static CookieConfig getConfig(final Attribute nameAttribute, final ExpressionResolver context, final ModelNode model) throws OperationFailedException { + if (!model.isDefined()) { + return null; + } + ModelNode nameValue = nameAttribute.getDefinition().resolveModelAttribute(context, model); + ModelNode domainValue = Attribute.DOMAIN.resolveModelAttribute(context, model); + ModelNode secureValue = Attribute.SECURE.resolveModelAttribute(context, model); + ModelNode httpOnlyValue = Attribute.HTTP_ONLY.resolveModelAttribute(context, model); + ModelNode maxAgeValue = Attribute.MAX_AGE.resolveModelAttribute(context, model); + + final String name = nameValue.isDefined() ? nameValue.asString() : null; + final String domain = domainValue.isDefined() ? domainValue.asString() : null; + final Boolean secure = secureValue.isDefined() ? secureValue.asBoolean() : null; + final Boolean httpOnly = httpOnlyValue.isDefined() ? httpOnlyValue.asBoolean() : null; + final Integer maxAge = maxAgeValue.isDefined() ? maxAgeValue.asInt() : null; + + return new CookieConfig(name, domain, httpOnly, secure, maxAge); + } + + private static class SessionCookieAdd extends RestartParentResourceAddHandler { + + private final Collection attributes; + + protected SessionCookieAdd(Collection attributes) { + super(ServletContainerDefinition.PATH_ELEMENT.getKey()); + + this.attributes = attributes; + } + + @Override + protected void populateModel(ModelNode operation, ModelNode model) throws OperationFailedException { + for (AttributeDefinition def : this.attributes) { + def.validateAndSet(operation, model); + } + } + + @Override + protected void recreateParentService(OperationContext context, PathAddress parentAddress, ModelNode parentModel) throws OperationFailedException { + ServletContainerAdd.installRuntimeServices(context.getCapabilityServiceTarget(), context, parentAddress, parentModel); + } + + @Override + protected ServiceName getParentServiceName(PathAddress parentAddress) { + return ServletContainerDefinition.SERVLET_CONTAINER_CAPABILITY.getCapabilityServiceName(parentAddress); + } + } + + private static class SessionCookieRemove extends RestartParentResourceRemoveHandler { + + protected SessionCookieRemove() { + super(ServletContainerDefinition.PATH_ELEMENT.getKey()); + } + + @Override + protected void recreateParentService(OperationContext context, PathAddress parentAddress, ModelNode parentModel) throws OperationFailedException { + ServletContainerAdd.installRuntimeServices(context.getCapabilityServiceTarget(), context, parentAddress, parentModel); + } + + @Override + protected ServiceName getParentServiceName(PathAddress parentAddress) { + return ServletContainerDefinition.SERVLET_CONTAINER_CAPABILITY.getCapabilityServiceName(parentAddress); + } + } +} Index: 3rdParty_sources/undertow/org/wildfly/extension/undertow/AbstractHttpListenerResourceDefinition.java =================================================================== diff -u --- 3rdParty_sources/undertow/org/wildfly/extension/undertow/AbstractHttpListenerResourceDefinition.java (revision 0) +++ 3rdParty_sources/undertow/org/wildfly/extension/undertow/AbstractHttpListenerResourceDefinition.java (revision e704ad812feb0fa447e5bd63332f753ac1a94b70) @@ -0,0 +1,134 @@ +/* + * Copyright The WildFly Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package org.wildfly.extension.undertow; + +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.function.Function; + +import io.undertow.UndertowOptions; +import io.undertow.protocols.http2.Http2Channel; + +import org.jboss.as.controller.AbstractAddStepHandler; +import org.jboss.as.controller.AttributeDefinition; +import org.jboss.as.controller.SimpleAttributeDefinition; +import org.jboss.as.controller.SimpleAttributeDefinitionBuilder; +import org.jboss.as.controller.SimpleResourceDefinition; +import org.jboss.as.controller.client.helpers.MeasurementUnit; +import org.jboss.as.controller.operations.validation.IntRangeValidator; +import org.jboss.as.controller.registry.AttributeAccess; +import org.jboss.dmr.ModelNode; +import org.jboss.dmr.ModelType; +import org.wildfly.extension.io.OptionAttributeDefinition; + +/** + * Common base class for HTTP and HTTPS resource definitions. + * @author Paul Ferraro + */ +abstract class AbstractHttpListenerResourceDefinition extends ListenerResourceDefinition { + + static final OptionAttributeDefinition HTTP2_ENABLE_PUSH = OptionAttributeDefinition.builder("http2-enable-push", UndertowOptions.HTTP2_SETTINGS_ENABLE_PUSH) + .setRequired(false) + .setFlags(AttributeAccess.Flag.RESTART_ALL_SERVICES) + .setAllowExpression(true) + .setDefaultValue(ModelNode.TRUE) + .build(); + + static final OptionAttributeDefinition HTTP2_HEADER_TABLE_SIZE = OptionAttributeDefinition.builder("http2-header-table-size", UndertowOptions.HTTP2_SETTINGS_HEADER_TABLE_SIZE) + .setRequired(false) + .setFlags(AttributeAccess.Flag.RESTART_ALL_SERVICES) + .setAllowExpression(true) + .setMeasurementUnit(MeasurementUnit.BYTES) + .setDefaultValue(new ModelNode(UndertowOptions.HTTP2_SETTINGS_HEADER_TABLE_SIZE_DEFAULT)) + .setValidator(new IntRangeValidator(1)) + .build(); + + static final OptionAttributeDefinition HTTP2_INITIAL_WINDOW_SIZE = OptionAttributeDefinition.builder("http2-initial-window-size", UndertowOptions.HTTP2_SETTINGS_INITIAL_WINDOW_SIZE) + .setRequired(false) + .setFlags(AttributeAccess.Flag.RESTART_ALL_SERVICES) + .setAllowExpression(true) + .setMeasurementUnit(MeasurementUnit.BYTES) + .setDefaultValue(new ModelNode(Http2Channel.DEFAULT_INITIAL_WINDOW_SIZE)) + .setValidator(new IntRangeValidator(1)) + .build(); + + static final OptionAttributeDefinition HTTP2_MAX_CONCURRENT_STREAMS = OptionAttributeDefinition.builder("http2-max-concurrent-streams", UndertowOptions.HTTP2_SETTINGS_MAX_CONCURRENT_STREAMS) + .setRequired(false) + .setFlags(AttributeAccess.Flag.RESTART_ALL_SERVICES) + .setAllowExpression(true) + .setValidator(new IntRangeValidator(1)) + .build(); + + static final OptionAttributeDefinition HTTP2_MAX_HEADER_LIST_SIZE = OptionAttributeDefinition.builder("http2-max-header-list-size", UndertowOptions.HTTP2_SETTINGS_MAX_HEADER_LIST_SIZE) + .setRequired(false) + .setFlags(AttributeAccess.Flag.RESTART_ALL_SERVICES) + .setAllowExpression(true) + .setMeasurementUnit(MeasurementUnit.BYTES) + .setValidator(new IntRangeValidator(1)) + .build(); + + static final OptionAttributeDefinition HTTP2_MAX_FRAME_SIZE = OptionAttributeDefinition.builder("http2-max-frame-size", UndertowOptions.HTTP2_SETTINGS_MAX_FRAME_SIZE) + .setRequired(false) + .setFlags(AttributeAccess.Flag.RESTART_ALL_SERVICES) + .setAllowExpression(true) + .setMeasurementUnit(MeasurementUnit.BYTES) + .setDefaultValue(new ModelNode(Http2Channel.DEFAULT_MAX_FRAME_SIZE)) + .setValidator(new IntRangeValidator(1)) + .build(); + + static final SimpleAttributeDefinition CERTIFICATE_FORWARDING = new SimpleAttributeDefinitionBuilder(Constants.CERTIFICATE_FORWARDING, ModelType.BOOLEAN) + .setRequired(false) + .setFlags(AttributeAccess.Flag.RESTART_RESOURCE_SERVICES) + .setDefaultValue(ModelNode.FALSE) + .setAllowExpression(true) + .build(); + + static final SimpleAttributeDefinition PROXY_ADDRESS_FORWARDING = new SimpleAttributeDefinitionBuilder("proxy-address-forwarding", ModelType.BOOLEAN) + .setRequired(false) + .setFlags(AttributeAccess.Flag.RESTART_RESOURCE_SERVICES) + .setDefaultValue(ModelNode.FALSE) + .setAllowExpression(true) + .build(); + + static final OptionAttributeDefinition REQUIRE_HOST_HTTP11 = OptionAttributeDefinition.builder("require-host-http11", UndertowOptions.REQUIRE_HOST_HTTP11) + .setRequired(false) + .setFlags(AttributeAccess.Flag.RESTART_ALL_SERVICES) + .setAllowExpression(true) + .setDefaultValue(ModelNode.FALSE) + .build(); + + static final SimpleAttributeDefinition PROXY_PROTOCOL = new SimpleAttributeDefinitionBuilder(Constants.PROXY_PROTOCOL, ModelType.BOOLEAN) + .setDefaultValue(ModelNode.FALSE) + .setRequired(false) + .setFlags(AttributeAccess.Flag.RESTART_RESOURCE_SERVICES) + .setAllowExpression(true) + .build(); + + static final OptionAttributeDefinition ENABLE_HTTP2 = OptionAttributeDefinition.builder(Constants.ENABLE_HTTP2, UndertowOptions.ENABLE_HTTP2) + .setRequired(false) + .setFlags(AttributeAccess.Flag.RESTART_ALL_SERVICES) + .setAllowExpression(true) + .setDefaultValue(ModelNode.FALSE) + .build(); + + static final Collection ATTRIBUTES = List.of( + ENABLE_HTTP2, + HTTP2_ENABLE_PUSH, + HTTP2_HEADER_TABLE_SIZE, + HTTP2_INITIAL_WINDOW_SIZE, + HTTP2_MAX_CONCURRENT_STREAMS, + HTTP2_MAX_HEADER_LIST_SIZE, + HTTP2_MAX_FRAME_SIZE, + CERTIFICATE_FORWARDING, + PROXY_ADDRESS_FORWARDING, + REQUIRE_HOST_HTTP11, + PROXY_PROTOCOL); + + AbstractHttpListenerResourceDefinition(SimpleResourceDefinition.Parameters parameters, Function, AbstractAddStepHandler> addHandlerFactory) { + super(parameters, addHandlerFactory, Map.of(WORKER, new HttpListenerWorkerAttributeWriteHandler(WORKER))); + } +} Fisheye: Tag 0c9c83107d623392869f43619926ea6d8ec5beab refers to a dead (removed) revision in file `3rdParty_sources/undertow/org/wildfly/extension/undertow/AbstractPersistentSessionManager.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 0c9c83107d623392869f43619926ea6d8ec5beab refers to a dead (removed) revision in file `3rdParty_sources/undertow/org/wildfly/extension/undertow/AccessLogAdd.java'. Fisheye: No comparison available. Pass `N' to diff? Index: 3rdParty_sources/undertow/org/wildfly/extension/undertow/AccessLogAttribute.java =================================================================== diff -u --- 3rdParty_sources/undertow/org/wildfly/extension/undertow/AccessLogAttribute.java (revision 0) +++ 3rdParty_sources/undertow/org/wildfly/extension/undertow/AccessLogAttribute.java (revision e704ad812feb0fa447e5bd63332f753ac1a94b70) @@ -0,0 +1,106 @@ +/* + * Copyright The WildFly Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package org.wildfly.extension.undertow; + +import java.util.Objects; +import java.util.function.Function; + +import io.undertow.attribute.ExchangeAttribute; +import io.undertow.server.HttpServerExchange; + +/** + * @author James R. Perkins + */ +class AccessLogAttribute implements Comparable { + private final String key; + private final ExchangeAttribute exchangeAttribute; + private final Function valueConverter; + + private AccessLogAttribute(final String key, final ExchangeAttribute exchangeAttribute, final Function valueConverter) { + this.key = key; + this.exchangeAttribute = exchangeAttribute; + this.valueConverter = valueConverter; + } + + /** + * Creates a new attribute. + * + * @param key the key for the attribute + * @param exchangeAttribute the exchange attribute which resolves the value + * + * @return the new attribute + */ + static AccessLogAttribute of(final String key, final ExchangeAttribute exchangeAttribute) { + return new AccessLogAttribute(key, exchangeAttribute, null); + } + + + /** + * Creates a new attribute. + * + * @param key the key for the attribute + * @param exchangeAttribute the exchange attribute which resolves the value + * @param valueConverter the converter used to convert the + * {@linkplain ExchangeAttribute#readAttribute(HttpServerExchange) string} into a different + * type + * + * @return the new attribute + */ + static AccessLogAttribute of(final String key, final ExchangeAttribute exchangeAttribute, final Function valueConverter) { + return new AccessLogAttribute(key, exchangeAttribute, valueConverter); + } + + /** + * Returns the key used for the structured log output. + * + * @return the key + */ + String getKey() { + return key; + } + + /** + * Resolves the value for the attribute. + * + * @param exchange the exchange to resolve the value from + * + * @return the value of the attribute + */ + Object resolveAttribute(final HttpServerExchange exchange) { + if (valueConverter == null) { + return exchangeAttribute.readAttribute(exchange); + } + return valueConverter.apply(exchangeAttribute.readAttribute(exchange)); + } + + @Override + public int compareTo(final AccessLogAttribute o) { + return key.compareTo(o.key); + } + + @Override + public int hashCode() { + return Objects.hash(key); + } + + @Override + public boolean equals(final Object obj) { + if (this == obj) { + return true; + } + if (!(obj instanceof AccessLogAttribute)) { + return false; + } + final AccessLogAttribute other = (AccessLogAttribute) obj; + return key.equals(other.key); + } + + @Override + public String toString() { + return getClass().getSimpleName() + "{key=" + key + ", exchangeAttribute=" + exchangeAttribute + + ", valueConverter=" + valueConverter + "}"; + } +} Fisheye: Tag 0c9c83107d623392869f43619926ea6d8ec5beab refers to a dead (removed) revision in file `3rdParty_sources/undertow/org/wildfly/extension/undertow/AccessLogDefinition.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 0c9c83107d623392869f43619926ea6d8ec5beab refers to a dead (removed) revision in file `3rdParty_sources/undertow/org/wildfly/extension/undertow/AccessLogRemove.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 0c9c83107d623392869f43619926ea6d8ec5beab refers to a dead (removed) revision in file `3rdParty_sources/undertow/org/wildfly/extension/undertow/AccessLogService.java'. Fisheye: No comparison available. Pass `N' to diff? Index: 3rdParty_sources/undertow/org/wildfly/extension/undertow/AffinityCookieDefinition.java =================================================================== diff -u --- 3rdParty_sources/undertow/org/wildfly/extension/undertow/AffinityCookieDefinition.java (revision 0) +++ 3rdParty_sources/undertow/org/wildfly/extension/undertow/AffinityCookieDefinition.java (revision e704ad812feb0fa447e5bd63332f753ac1a94b70) @@ -0,0 +1,38 @@ +/* + * Copyright The WildFly Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package org.wildfly.extension.undertow; + +import java.util.Collection; +import java.util.EnumSet; +import java.util.stream.Collectors; + +import org.jboss.as.controller.AttributeDefinition; +import org.jboss.as.controller.ExpressionResolver; +import org.jboss.as.controller.OperationFailedException; +import org.jboss.as.controller.PathElement; +import org.jboss.dmr.ModelNode; + +/** + * Resource description for the affinity cookie configuration with cookie name being required and no comment being defined. + * + * @author Radoslav Husar + */ +class AffinityCookieDefinition extends AbstractCookieDefinition { + + static final PathElement PATH_ELEMENT = PathElement.pathElement(Constants.SETTING, Constants.AFFINITY_COOKIE); + + static final Collection ATTRIBUTES = EnumSet.complementOf(EnumSet.of(Attribute.OPTIONAL_NAME, Attribute.COMMENT)) + .stream().map(Attribute::getDefinition).collect(Collectors.toUnmodifiableSet()); + + AffinityCookieDefinition() { + super(PATH_ELEMENT, ATTRIBUTES); + } + + static CookieConfig getConfig(final ExpressionResolver context, final ModelNode model) throws OperationFailedException { + return AbstractCookieDefinition.getConfig(Attribute.REQUIRED_NAME, context, model); + } + +} Fisheye: Tag 0c9c83107d623392869f43619926ea6d8ec5beab refers to a dead (removed) revision in file `3rdParty_sources/undertow/org/wildfly/extension/undertow/AjpListenerAdd.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 0c9c83107d623392869f43619926ea6d8ec5beab refers to a dead (removed) revision in file `3rdParty_sources/undertow/org/wildfly/extension/undertow/AjpListenerResourceDefinition.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 0c9c83107d623392869f43619926ea6d8ec5beab refers to a dead (removed) revision in file `3rdParty_sources/undertow/org/wildfly/extension/undertow/AjpListenerService.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 0c9c83107d623392869f43619926ea6d8ec5beab refers to a dead (removed) revision in file `3rdParty_sources/undertow/org/wildfly/extension/undertow/ApplicationSecurityDomainDefinition.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 0c9c83107d623392869f43619926ea6d8ec5beab refers to a dead (removed) revision in file `3rdParty_sources/undertow/org/wildfly/extension/undertow/ApplicationSecurityDomainSingleSignOnDefinition.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 0c9c83107d623392869f43619926ea6d8ec5beab refers to a dead (removed) revision in file `3rdParty_sources/undertow/org/wildfly/extension/undertow/BufferCacheAdd.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 0c9c83107d623392869f43619926ea6d8ec5beab refers to a dead (removed) revision in file `3rdParty_sources/undertow/org/wildfly/extension/undertow/BufferCacheDefinition.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 0c9c83107d623392869f43619926ea6d8ec5beab refers to a dead (removed) revision in file `3rdParty_sources/undertow/org/wildfly/extension/undertow/BufferCacheService.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 0c9c83107d623392869f43619926ea6d8ec5beab refers to a dead (removed) revision in file `3rdParty_sources/undertow/org/wildfly/extension/undertow/ByteBufferPoolDefinition.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 0c9c83107d623392869f43619926ea6d8ec5beab refers to a dead (removed) revision in file `3rdParty_sources/undertow/org/wildfly/extension/undertow/Capabilities.java'. Fisheye: No comparison available. Pass `N' to diff? Index: 3rdParty_sources/undertow/org/wildfly/extension/undertow/ConsoleAccessLogDefinition.java =================================================================== diff -u --- 3rdParty_sources/undertow/org/wildfly/extension/undertow/ConsoleAccessLogDefinition.java (revision 0) +++ 3rdParty_sources/undertow/org/wildfly/extension/undertow/ConsoleAccessLogDefinition.java (revision e704ad812feb0fa447e5bd63332f753ac1a94b70) @@ -0,0 +1,157 @@ +/* + * Copyright The WildFly Authors + * SPDX-License-Identifier: Apache-2.0 + */ +package org.wildfly.extension.undertow; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.function.Supplier; + +import io.undertow.predicate.Predicate; +import io.undertow.predicate.Predicates; +import org.jboss.as.controller.AbstractAddStepHandler; +import org.jboss.as.controller.AbstractRemoveStepHandler; +import org.jboss.as.controller.AttributeDefinition; +import org.jboss.as.controller.OperationContext; +import org.jboss.as.controller.OperationFailedException; +import org.jboss.as.controller.PathAddress; +import org.jboss.as.controller.PathElement; +import org.jboss.as.controller.PersistentResourceDefinition; +import org.jboss.as.controller.PropertiesAttributeDefinition; +import org.jboss.as.controller.SimpleAttributeDefinition; +import org.jboss.as.controller.SimpleAttributeDefinitionBuilder; +import org.jboss.as.controller.SimpleResourceDefinition; +import org.jboss.as.controller.capability.DynamicNameMappers; +import org.jboss.as.controller.capability.RuntimeCapability; +import org.jboss.dmr.ModelNode; +import org.jboss.dmr.ModelType; +import org.jboss.dmr.Property; +import org.jboss.msc.service.ServiceBuilder; +import org.jboss.msc.service.ServiceController; +import org.xnio.XnioWorker; + +/** + * The resource definition for the {@code setting=console-access-log} resource. + * + * @author James R. Perkins + */ +class ConsoleAccessLogDefinition extends PersistentResourceDefinition { + static final PathElement PATH_ELEMENT = PathElement.pathElement(Constants.SETTING, Constants.CONSOLE_ACCESS_LOG); + private static final RuntimeCapability CONSOLE_ACCESS_LOG_CAPABILITY = RuntimeCapability.Builder.of( + Capabilities.CAPABILITY_CONSOLE_ACCESS_LOG, true, EventLoggerService.class) + .setDynamicNameMapper(DynamicNameMappers.GRAND_PARENT) + .build(); + + static final SimpleAttributeDefinition INCLUDE_HOST_NAME = SimpleAttributeDefinitionBuilder.create("include-host-name", ModelType.BOOLEAN, true) + .setAllowExpression(true) + .setDefaultValue(ModelNode.TRUE) + .setRestartAllServices() + .build(); + + static final PropertiesAttributeDefinition METADATA = new PropertiesAttributeDefinition.Builder("metadata", true) + .setAllowExpression(true) + .setRestartAllServices() + .build(); + + static final Collection ATTRIBUTES = Arrays.asList( + ExchangeAttributeDefinitions.ATTRIBUTES, + INCLUDE_HOST_NAME, + AccessLogDefinition.WORKER, + AccessLogDefinition.PREDICATE, + METADATA + ); + + ConsoleAccessLogDefinition() { + super(new SimpleResourceDefinition.Parameters(PATH_ELEMENT, UndertowExtension.getResolver(PATH_ELEMENT.getValue())) + .setAddHandler(AddHandler.INSTANCE) + .setRemoveHandler(RemoveHandler.INSTANCE) + .addCapabilities(CONSOLE_ACCESS_LOG_CAPABILITY) + ); + } + + @Override + public Collection getAttributes() { + return ATTRIBUTES; + } + + private static class AddHandler extends AbstractAddStepHandler { + static final AddHandler INSTANCE = new AddHandler(); + + private AddHandler() { + super(ATTRIBUTES); + } + + @Override + protected void performRuntime(final OperationContext context, final ModelNode operation, final ModelNode model) throws OperationFailedException { + final PathAddress address = context.getCurrentAddress(); + final PathAddress hostAddress = address.getParent(); + final PathAddress serverAddress = hostAddress.getParent(); + + final String worker = AccessLogDefinition.WORKER.resolveModelAttribute(context, model).asString(); + final ModelNode properties = METADATA.resolveModelAttribute(context, model); + final Map metadata = new LinkedHashMap<>(); + if (properties.isDefined()) { + for (Property property : properties.asPropertyList()) { + metadata.put(property.getName(), property.getValue().asString()); + } + } + + Predicate predicate = null; + final ModelNode predicateNode = AccessLogDefinition.PREDICATE.resolveModelAttribute(context, model); + if (predicateNode.isDefined()) { + predicate = Predicates.parse(predicateNode.asString(), getClass().getClassLoader()); + } + + final boolean includeHostName = INCLUDE_HOST_NAME.resolveModelAttribute(context, model).asBoolean(); + + final String serverName = serverAddress.getLastElement().getValue(); + final String hostName = hostAddress.getLastElement().getValue(); + + final ServiceBuilder serviceBuilder = context.getServiceTarget() + .addService(CONSOLE_ACCESS_LOG_CAPABILITY.getCapabilityServiceName(address)); + + final Supplier hostSupplier = serviceBuilder.requires( + context.getCapabilityServiceName(Capabilities.CAPABILITY_HOST, Host.class, serverName, hostName)); + final Supplier workerSupplier = serviceBuilder.requires( + context.getCapabilityServiceName(Capabilities.REF_IO_WORKER, XnioWorker.class, worker)); + + // Get the list of attributes to log + final Collection attributes = parseAttributes(context, model); + + final EventLoggerService service = new EventLoggerService(attributes, predicate, metadata, includeHostName, hostSupplier, + workerSupplier); + serviceBuilder.setInstance(service) + .setInitialMode(ServiceController.Mode.ACTIVE) + .install(); + } + + private Collection parseAttributes(final OperationContext context, final ModelNode model) throws OperationFailedException { + final Collection attributes = new ArrayList<>(); + final ModelNode attributesModel = ExchangeAttributeDefinitions.ATTRIBUTES.resolveModelAttribute(context, model); + for (AttributeDefinition valueType : ExchangeAttributeDefinitions.ATTRIBUTES.getValueTypes()) { + attributes.addAll(ExchangeAttributeDefinitions.resolveAccessLogAttribute(valueType, context, attributesModel)); + } + return attributes; + } + } + + private static class RemoveHandler extends AbstractRemoveStepHandler { + + static final RemoveHandler INSTANCE = new RemoveHandler(); + + @Override + protected void performRuntime(final OperationContext context, final ModelNode operation, final ModelNode model) throws OperationFailedException { + final PathAddress address = context.getCurrentAddress(); + context.removeService(CONSOLE_ACCESS_LOG_CAPABILITY.getCapabilityServiceName(address)); + } + + @Override + protected void recoverServices(final OperationContext context, final ModelNode operation, final ModelNode model) throws OperationFailedException { + AddHandler.INSTANCE.performRuntime(context, operation, model); + } + } +} Fisheye: Tag 0c9c83107d623392869f43619926ea6d8ec5beab refers to a dead (removed) revision in file `3rdParty_sources/undertow/org/wildfly/extension/undertow/ConsoleRedirectService.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 0c9c83107d623392869f43619926ea6d8ec5beab refers to a dead (removed) revision in file `3rdParty_sources/undertow/org/wildfly/extension/undertow/Constants.java'. Fisheye: No comparison available. Pass `N' to diff? Index: 3rdParty_sources/undertow/org/wildfly/extension/undertow/CookieConfig.java =================================================================== diff -u --- 3rdParty_sources/undertow/org/wildfly/extension/undertow/CookieConfig.java (revision 0) +++ 3rdParty_sources/undertow/org/wildfly/extension/undertow/CookieConfig.java (revision e704ad812feb0fa447e5bd63332f753ac1a94b70) @@ -0,0 +1,48 @@ +/* + * Copyright The WildFly Authors + * SPDX-License-Identifier: Apache-2.0 + */ +package org.wildfly.extension.undertow; + +/** + * Configuration object for a Cookie. + * The config can be overridden on a per-app basis, and may not be present. + * + * @author Stuart Douglas + */ +public class CookieConfig { + + private final String name; + private final String domain; + private final Boolean httpOnly; + private final Boolean secure; + private final Integer maxAge; + + public CookieConfig(final String name, final String domain, final Boolean httpOnly, final Boolean secure, final Integer maxAge) { + this.name = name; + this.domain = domain; + this.httpOnly = httpOnly; + this.secure = secure; + this.maxAge = maxAge; + } + + public String getName() { + return name; + } + + public String getDomain() { + return domain; + } + + public Boolean getHttpOnly() { + return httpOnly; + } + + public Boolean getSecure() { + return secure; + } + + public Integer getMaxAge() { + return maxAge; + } +} Fisheye: Tag 0c9c83107d623392869f43619926ea6d8ec5beab refers to a dead (removed) revision in file `3rdParty_sources/undertow/org/wildfly/extension/undertow/CrawlerSessionManagementDefinition.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 0c9c83107d623392869f43619926ea6d8ec5beab refers to a dead (removed) revision in file `3rdParty_sources/undertow/org/wildfly/extension/undertow/DefaultResponseCodeHandler.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 0c9c83107d623392869f43619926ea6d8ec5beab refers to a dead (removed) revision in file `3rdParty_sources/undertow/org/wildfly/extension/undertow/DeploymentDefinition.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 0c9c83107d623392869f43619926ea6d8ec5beab refers to a dead (removed) revision in file `3rdParty_sources/undertow/org/wildfly/extension/undertow/DeploymentServletDefinition.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 0c9c83107d623392869f43619926ea6d8ec5beab refers to a dead (removed) revision in file `3rdParty_sources/undertow/org/wildfly/extension/undertow/DeploymentWebSocketDefinition.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 0c9c83107d623392869f43619926ea6d8ec5beab refers to a dead (removed) revision in file `3rdParty_sources/undertow/org/wildfly/extension/undertow/DiskBasedModularPersistentSessionManager.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 0c9c83107d623392869f43619926ea6d8ec5beab refers to a dead (removed) revision in file `3rdParty_sources/undertow/org/wildfly/extension/undertow/EventInvoker.java'. Fisheye: No comparison available. Pass `N' to diff? Index: 3rdParty_sources/undertow/org/wildfly/extension/undertow/EventLoggerHttpHandler.java =================================================================== diff -u --- 3rdParty_sources/undertow/org/wildfly/extension/undertow/EventLoggerHttpHandler.java (revision 0) +++ 3rdParty_sources/undertow/org/wildfly/extension/undertow/EventLoggerHttpHandler.java (revision e704ad812feb0fa447e5bd63332f753ac1a94b70) @@ -0,0 +1,69 @@ +/* + * Copyright The WildFly Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package org.wildfly.extension.undertow; + +import java.util.Collection; +import java.util.LinkedHashMap; +import java.util.Map; + +import io.undertow.predicate.Predicate; +import io.undertow.server.ExchangeCompletionListener; +import io.undertow.server.HttpHandler; +import io.undertow.server.HttpServerExchange; +import org.wildfly.event.logger.EventLogger; + +/** + * An HTTP handler that writes exchange attributes to an event logger. + * + * @author James R. Perkins + */ +class EventLoggerHttpHandler implements HttpHandler { + + private final HttpHandler next; + private final ExchangeCompletionListener exchangeCompletionListener = new AccessLogCompletionListener(); + private final Predicate predicate; + private final Collection attributes; + private final EventLogger eventLogger; + + /** + * Creates a new instance of the HTTP handler. + * + * @param next the next handler in the chain to invoke to invoke after this handler executes + * @param predicate the predicate used to determine if this handler should execute + * @param attributes the attributes which should be logged + * @param eventLogger the event logger + */ + EventLoggerHttpHandler(final HttpHandler next, final Predicate predicate, + final Collection attributes, final EventLogger eventLogger) { + this.next = next; + this.predicate = predicate; + this.attributes = attributes; + this.eventLogger = eventLogger; + } + + @Override + public void handleRequest(final HttpServerExchange exchange) throws Exception { + exchange.addExchangeCompleteListener(exchangeCompletionListener); + next.handleRequest(exchange); + } + + private class AccessLogCompletionListener implements ExchangeCompletionListener { + @Override + public void exchangeEvent(final HttpServerExchange exchange, final NextListener nextListener) { + try { + if (predicate == null || predicate.resolve(exchange)) { + final Map data = new LinkedHashMap<>(); + for (AccessLogAttribute attribute : attributes) { + data.put(attribute.getKey(), attribute.resolveAttribute(exchange)); + } + eventLogger.log(data); + } + } finally { + nextListener.proceed(); + } + } + } +} Index: 3rdParty_sources/undertow/org/wildfly/extension/undertow/EventLoggerService.java =================================================================== diff -u --- 3rdParty_sources/undertow/org/wildfly/extension/undertow/EventLoggerService.java (revision 0) +++ 3rdParty_sources/undertow/org/wildfly/extension/undertow/EventLoggerService.java (revision e704ad812feb0fa447e5bd63332f753ac1a94b70) @@ -0,0 +1,94 @@ +/* + * Copyright The WildFly Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package org.wildfly.extension.undertow; + +import java.util.Collection; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.CopyOnWriteArraySet; +import java.util.concurrent.Executor; +import java.util.function.Function; +import java.util.function.Supplier; + +import io.undertow.predicate.Predicate; +import io.undertow.predicate.Predicates; +import io.undertow.server.HttpHandler; +import org.jboss.msc.Service; +import org.jboss.msc.service.StartContext; +import org.jboss.msc.service.StartException; +import org.jboss.msc.service.StopContext; +import org.wildfly.event.logger.EventLogger; +import org.wildfly.event.logger.JsonEventFormatter; +import org.wildfly.event.logger.StdoutEventWriter; +import org.wildfly.extension.undertow.logging.UndertowLogger; +import org.xnio.XnioWorker; + +/** + * A service which creates an asynchronous {@linkplain EventLogger event logger} which writes to {@code stdout} in JSON + * structured format. + * + * @author James R. Perkins + */ +class EventLoggerService implements Service { + private final Set attributes; + private final boolean includeHostName; + private final Map metadata; + private final Predicate predicate; + private final Supplier host; + private final Supplier worker; + + /** + * Creates a new service. + * + * @param predicate the predicate that determines if the request should be logged + * @param metadata a map of metadata to be prepended to the structured output + * @param includeHostName {@code true} to include the host name in the structured JSON output + * @param host the host service supplier + * @param worker the worker service supplier for the + * {@linkplain EventLogger#createAsyncLogger(String, Executor) async logger} + */ + EventLoggerService(final Collection attributes, final Predicate predicate, final Map metadata, + final boolean includeHostName, final Supplier host, final Supplier worker) { + this.attributes = new CopyOnWriteArraySet<>(attributes); + this.predicate = predicate == null ? Predicates.truePredicate() : predicate; + this.metadata = metadata; + this.includeHostName = includeHostName; + this.host = host; + this.worker = worker; + } + + @Override + @SuppressWarnings("Convert2Lambda") + public void start(final StartContext context) throws StartException { + final Host host = this.host.get(); + // Create the JSON event formatter + final JsonEventFormatter.Builder formatterBuilder = JsonEventFormatter.builder() + .setIncludeTimestamp(false); + if (includeHostName) { + formatterBuilder.addMetaData("hostName", host.getName()); + } + if (metadata != null && !metadata.isEmpty()) { + formatterBuilder.addMetaData(metadata); + } + final JsonEventFormatter formatter = formatterBuilder.build(); + final EventLogger eventLogger = EventLogger.createAsyncLogger("web-access", + StdoutEventWriter.of(formatter), worker.get()); + UndertowLogger.ROOT_LOGGER.debugf("Adding console-access-log for host %s", host.getName()); + host.setAccessLogHandler(new Function() { + @Override + public HttpHandler apply(final HttpHandler httpHandler) { + return new EventLoggerHttpHandler(httpHandler, predicate, attributes, eventLogger); + } + }); + } + + @Override + public void stop(final StopContext context) { + final Host host = this.host.get(); + UndertowLogger.ROOT_LOGGER.debugf("Removing console-access-log for host %s", host.getName()); + host.setAccessLogHandler(null); + } +} Index: 3rdParty_sources/undertow/org/wildfly/extension/undertow/ExchangeAttributeDefinitions.java =================================================================== diff -u --- 3rdParty_sources/undertow/org/wildfly/extension/undertow/ExchangeAttributeDefinitions.java (revision 0) +++ 3rdParty_sources/undertow/org/wildfly/extension/undertow/ExchangeAttributeDefinitions.java (revision e704ad812feb0fa447e5bd63332f753ac1a94b70) @@ -0,0 +1,697 @@ +/* + * Copyright The WildFly Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package org.wildfly.extension.undertow; + + +import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.VALUE; + +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.TimeZone; +import java.util.concurrent.TimeUnit; +import java.util.function.Function; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamWriter; + +import io.undertow.attribute.AuthenticationTypeExchangeAttribute; +import io.undertow.attribute.BytesSentAttribute; +import io.undertow.attribute.DateTimeAttribute; +import io.undertow.attribute.ExchangeAttribute; +import io.undertow.attribute.HostAndPortAttribute; +import io.undertow.attribute.LocalIPAttribute; +import io.undertow.attribute.LocalPortAttribute; +import io.undertow.attribute.LocalServerNameAttribute; +import io.undertow.attribute.PathParameterAttribute; +import io.undertow.attribute.PredicateContextAttribute; +import io.undertow.attribute.QueryParameterAttribute; +import io.undertow.attribute.QueryStringAttribute; +import io.undertow.attribute.RelativePathAttribute; +import io.undertow.attribute.RemoteHostAttribute; +import io.undertow.attribute.RemoteIPAttribute; +import io.undertow.attribute.RemoteObfuscatedIPAttribute; +import io.undertow.attribute.RemoteUserAttribute; +import io.undertow.attribute.RequestHeaderAttribute; +import io.undertow.attribute.RequestLineAttribute; +import io.undertow.attribute.RequestMethodAttribute; +import io.undertow.attribute.RequestPathAttribute; +import io.undertow.attribute.RequestProtocolAttribute; +import io.undertow.attribute.RequestSchemeAttribute; +import io.undertow.attribute.RequestURLAttribute; +import io.undertow.attribute.ResolvedPathAttribute; +import io.undertow.attribute.ResponseCodeAttribute; +import io.undertow.attribute.ResponseHeaderAttribute; +import io.undertow.attribute.ResponseReasonPhraseAttribute; +import io.undertow.attribute.ResponseTimeAttribute; +import io.undertow.attribute.SecureExchangeAttribute; +import io.undertow.attribute.SslCipherAttribute; +import io.undertow.attribute.SslClientCertAttribute; +import io.undertow.attribute.SslSessionIdAttribute; +import io.undertow.attribute.StoredResponse; +import io.undertow.attribute.ThreadNameAttribute; +import io.undertow.attribute.TransportProtocolAttribute; +import io.undertow.util.HttpString; +import org.jboss.as.controller.AbstractAttributeDefinitionBuilder; +import org.jboss.as.controller.AttributeDefinition; +import org.jboss.as.controller.AttributeMarshaller; +import org.jboss.as.controller.AttributeParser; +import org.jboss.as.controller.ExpressionResolver; +import org.jboss.as.controller.ObjectTypeAttributeDefinition; +import org.jboss.as.controller.OperationContext; +import org.jboss.as.controller.OperationFailedException; +import org.jboss.as.controller.SimpleAttributeDefinition; +import org.jboss.as.controller.SimpleAttributeDefinitionBuilder; +import org.jboss.as.controller.StringListAttributeDefinition; +import org.jboss.as.controller.operations.validation.EnumValidator; +import org.jboss.as.controller.operations.validation.ModelTypeValidator; +import org.jboss.as.controller.parsing.ParseUtils; +import org.jboss.dmr.ModelNode; +import org.jboss.dmr.ModelType; +import org.jboss.staxmapper.XMLExtendedStreamReader; +import org.wildfly.common.function.ExceptionBiFunction; +import org.wildfly.extension.undertow.logging.UndertowLogger; + +/** + * @author James R. Perkins + */ +@SuppressWarnings({"Convert2Lambda", "Anonymous2MethodRef"}) +class ExchangeAttributeDefinitions { + + private static final String KEY_NAME = "key"; + private static final SimpleAttributeDefinitionBuilder KEY_BUILDER = SimpleAttributeDefinitionBuilder.create(KEY_NAME, ModelType.STRING, true); + + private static final Map, OperationFailedException>> ATTRIBUTE_RESOLVERS = + new HashMap<>(); + + private static final SimpleAttributeDefinitionBuilder KEY_PREFIX_BUILDER = SimpleAttributeDefinitionBuilder.create("key-prefix", ModelType.STRING, true); + private static final StringListAttributeDefinition NAMES = StringListAttributeDefinition.Builder.of("names") + .setAllowExpression(true) + .setAttributeMarshaller(new AttributeMarshaller.AttributeElementMarshaller() { + + @Override + public void marshallAsElement(final AttributeDefinition attribute, final ModelNode resourceModel, final boolean marshallDefault, final XMLStreamWriter writer) throws XMLStreamException { + assert attribute instanceof StringListAttributeDefinition; + try { + final List list = ((StringListAttributeDefinition) attribute).unwrap(ExpressionResolver.SIMPLE, resourceModel); + if (list.isEmpty()) { + return; + } + if (resourceModel.hasDefined(attribute.getName())) { + for (ModelNode value : resourceModel.get(attribute.getName()).asList()) { + writer.writeStartElement(attribute.getXmlName()); + writer.writeAttribute(VALUE, value.asString()); + writer.writeEndElement(); + } + } + + } catch (OperationFailedException e) { + throw new XMLStreamException(e); + } + } + }) + .setAttributeParser(new AttributeParser() { + @Override + public boolean isParseAsElement() { + return true; + } + + @Override + public void parseElement(final AttributeDefinition attribute, final XMLExtendedStreamReader reader, final ModelNode operation) throws XMLStreamException { + ParseUtils.requireSingleAttribute(reader, VALUE); + final String value = reader.getAttributeValue(0); + operation.get(attribute.getName()).add(value); + ParseUtils.requireNoContent(reader); + } + }) + .setRequired(true) + .setXmlName("name") + .build(); + + private static final SimpleAttributeDefinition AUTHENTICATION_TYPE_KEY = createKey("authenticationType"); + private static final ObjectTypeAttributeDefinition AUTHENTICATION_TYPE = create( + ObjectTypeAttributeDefinition.create("authentication-type", AUTHENTICATION_TYPE_KEY), + new ExceptionBiFunction, OperationFailedException>() { + @Override + public Collection apply(final OperationContext context, final ModelNode model) throws OperationFailedException { + return createSingleton(AUTHENTICATION_TYPE_KEY, context, model, AuthenticationTypeExchangeAttribute.INSTANCE); + } + }); + + private static final SimpleAttributeDefinition BYTES_SENT_KEY = createKey("bytesSent"); + private static final ObjectTypeAttributeDefinition BYTES_SENT = create( + ObjectTypeAttributeDefinition.create("bytes-sent", BYTES_SENT_KEY), + new ExceptionBiFunction, OperationFailedException>() { + @Override + public Collection apply(final OperationContext context, final ModelNode model) throws OperationFailedException { + return createSingleton(BYTES_SENT_KEY, context, model, + new BytesSentAttribute(false), new Function() { + @Override + public Object apply(final String s) { + return Long.valueOf(s); + } + }); + } + }); + + private static final SimpleAttributeDefinition DATE_TIME_KEY = createKey("dateTime"); + private static final SimpleAttributeDefinition DATE_FORMAT = SimpleAttributeDefinitionBuilder.create("date-format", ModelType.STRING, true) + .setAllowExpression(true) + .setValidator(new ModelTypeValidator(ModelType.STRING, true, true) { + @Override + public void validateParameter(final String parameterName, final ModelNode value) throws OperationFailedException { + super.validateParameter(parameterName, value); + try { + new SimpleDateFormat(value.asString()); + } catch (IllegalArgumentException ignore) { + throw UndertowLogger.ROOT_LOGGER.invalidDateTimeFormatterPattern(value.asString()); + } + } + }) + .build(); + private static final SimpleAttributeDefinition TIME_ZONE = SimpleAttributeDefinitionBuilder.create("time-zone", ModelType.STRING, true) + .setAllowExpression(true) + .setValidator(new ModelTypeValidator(ModelType.STRING, true, true) { + private final List zoneIds = Arrays.asList(TimeZone.getAvailableIDs()); + @Override + public void validateParameter(final String parameterName, final ModelNode value) throws OperationFailedException { + super.validateParameter(parameterName, value); + if (!zoneIds.contains(value.asString())) { + throw UndertowLogger.ROOT_LOGGER.invalidTimeZoneId(value.asString()); + } + } + }) + .build(); + private static final ObjectTypeAttributeDefinition DATE_TIME = create( + ObjectTypeAttributeDefinition.create("date-time", DATE_TIME_KEY, DATE_FORMAT, TIME_ZONE), + new ExceptionBiFunction, OperationFailedException>() { + @Override + public Collection apply(final OperationContext context, final ModelNode model) throws OperationFailedException { + final ExchangeAttribute exchangeAttribute; + if (model.hasDefined(DATE_FORMAT.getName())) { + String timeZone = null; + if (model.hasDefined(TIME_ZONE.getName())) { + timeZone = TIME_ZONE.resolveModelAttribute(context, model).asString(); + } + exchangeAttribute = new DateTimeAttribute(DATE_FORMAT.resolveModelAttribute(context, model).asString(), timeZone); + } else { + exchangeAttribute = DateTimeAttribute.INSTANCE; + } + return createSingleton(DATE_TIME_KEY, context, model, exchangeAttribute); + } + }); + + private static final SimpleAttributeDefinition HOST_AND_PORT_KEY = createKey("hostAndPort"); + private static final ObjectTypeAttributeDefinition HOST_AND_PORT = create( + ObjectTypeAttributeDefinition.create("host-and-port", HOST_AND_PORT_KEY), + new ExceptionBiFunction, OperationFailedException>() { + @Override + public Collection apply(final OperationContext context, final ModelNode model) throws OperationFailedException { + return createSingleton(HOST_AND_PORT_KEY, context, model, HostAndPortAttribute.INSTANCE); + } + }); + + private static final SimpleAttributeDefinition LOCAL_IP_KEY = createKey("localIp"); + private static final ObjectTypeAttributeDefinition LOCAL_IP = create( + ObjectTypeAttributeDefinition.create("local-ip", LOCAL_IP_KEY), + new ExceptionBiFunction, OperationFailedException>() { + @Override + public Collection apply(final OperationContext context, final ModelNode model) throws OperationFailedException { + return createSingleton(LOCAL_IP_KEY, context, model, LocalIPAttribute.INSTANCE); + } + }); + + private static final SimpleAttributeDefinition LOCAL_PORT_KEY = createKey("localPort"); + private static final ObjectTypeAttributeDefinition LOCAL_PORT = create( + ObjectTypeAttributeDefinition.create("local-port", LOCAL_PORT_KEY), + new ExceptionBiFunction, OperationFailedException>() { + @Override + public Collection apply(final OperationContext context, final ModelNode model) throws OperationFailedException { + return createSingleton(LOCAL_PORT_KEY, context, model, LocalPortAttribute.INSTANCE, new Function() { + @Override + public Object apply(final String s) { + return Integer.valueOf(s); + } + }); + } + }); + + private static final SimpleAttributeDefinition LOCAL_SERVER_NAME_KEY = createKey("localServerName"); + private static final ObjectTypeAttributeDefinition LOCAL_SERVER_NAME = create( + ObjectTypeAttributeDefinition.create("local-server-name", LOCAL_SERVER_NAME_KEY), + new ExceptionBiFunction, OperationFailedException>() { + @Override + public Collection apply(final OperationContext context, final ModelNode model) throws OperationFailedException { + return createSingleton(LOCAL_SERVER_NAME_KEY, context, model, LocalServerNameAttribute.INSTANCE); + } + }); + + private static final SimpleAttributeDefinition PATH_PARAMETER_KEY_PREFIX = KEY_PREFIX_BUILDER.build(); + private static final ObjectTypeAttributeDefinition PATH_PARAMETER = create(ObjectTypeAttributeDefinition.Builder.of("path-parameter", + PATH_PARAMETER_KEY_PREFIX, NAMES), + new ExceptionBiFunction, OperationFailedException>() { + @Override + public Collection apply(final OperationContext context, final ModelNode model) throws OperationFailedException { + final Collection result = new ArrayList<>(5); + for (ModelNode m : NAMES.resolveModelAttribute(context, model).asList()) { + final String name = m.asString(); + final String keyName = resolveKeyName(PATH_PARAMETER_KEY_PREFIX.resolveModelAttribute(context, model), name); + result.add(AccessLogAttribute.of(keyName, new PathParameterAttribute(name))); + } + return result; + } + }); + + private static final SimpleAttributeDefinition PREDICATE_KEY_PREFIX = KEY_PREFIX_BUILDER.build(); + private static final ObjectTypeAttributeDefinition PREDICATE = create(ObjectTypeAttributeDefinition.Builder.of("predicate", + PREDICATE_KEY_PREFIX, NAMES), + new ExceptionBiFunction, OperationFailedException>() { + @Override + public Collection apply(final OperationContext context, final ModelNode model) throws OperationFailedException { + final Collection result = new ArrayList<>(5); + for (ModelNode m : NAMES.resolveModelAttribute(context, model).asList()) { + final String predicateName = m.asString(); + final String keyName = resolveKeyName(PREDICATE_KEY_PREFIX.resolveModelAttribute(context, model), predicateName); + result.add(AccessLogAttribute.of(keyName, new PredicateContextAttribute(predicateName))); + } + return result; + } + }); + + private static final SimpleAttributeDefinition QUERY_PARAMETER_KEY_PREFIX = KEY_PREFIX_BUILDER.build(); + private static final ObjectTypeAttributeDefinition QUERY_PARAMETER = create(ObjectTypeAttributeDefinition.Builder.of("query-parameter", + QUERY_PARAMETER_KEY_PREFIX, NAMES), + new ExceptionBiFunction, OperationFailedException>() { + @Override + public Collection apply(final OperationContext context, final ModelNode model) throws OperationFailedException { + final Collection result = new ArrayList<>(5); + for (ModelNode m : NAMES.resolveModelAttribute(context, model).asList()) { + final String paramName = m.asString(); + final String keyName = resolveKeyName(QUERY_PARAMETER_KEY_PREFIX.resolveModelAttribute(context, model), paramName); + result.add(AccessLogAttribute.of(keyName, new QueryParameterAttribute(paramName))); + } + return result; + } + }); + + private static final SimpleAttributeDefinition QUERY_STRING_KEY = createKey("queryString"); + private static final SimpleAttributeDefinition INCLUDE_QUESTION_MARK = SimpleAttributeDefinitionBuilder + .create("include-question-mark", ModelType.BOOLEAN, true) + .setAllowExpression(true) + .setDefaultValue(ModelNode.FALSE) + .build(); + private static final ObjectTypeAttributeDefinition QUERY_STRING = create( + ObjectTypeAttributeDefinition.create("query-string", QUERY_STRING_KEY, INCLUDE_QUESTION_MARK), + new ExceptionBiFunction, OperationFailedException>() { + @Override + public Collection apply(final OperationContext context, final ModelNode model) throws OperationFailedException { + if (INCLUDE_QUESTION_MARK.resolveModelAttribute(context, model).asBoolean()) { + return createSingleton(QUERY_STRING_KEY, context, model, QueryStringAttribute.INSTANCE); + } + return createSingleton(QUERY_STRING_KEY, context, model, QueryStringAttribute.BARE_INSTANCE); + } + }); + + private static final SimpleAttributeDefinition RELATIVE_PATH_KEY = createKey("relativePath"); + private static final ObjectTypeAttributeDefinition RELATIVE_PATH = create( + ObjectTypeAttributeDefinition.create("relative-path", RELATIVE_PATH_KEY), + new ExceptionBiFunction, OperationFailedException>() { + @Override + public Collection apply(final OperationContext context, final ModelNode model) throws OperationFailedException { + return createSingleton(RELATIVE_PATH_KEY, context, model, RelativePathAttribute.INSTANCE); + } + }); + + private static final SimpleAttributeDefinition REMOTE_HOST_KEY = createKey("remoteHost"); + private static final ObjectTypeAttributeDefinition REMOTE_HOST = create( + ObjectTypeAttributeDefinition.create("remote-host", REMOTE_HOST_KEY), + new ExceptionBiFunction, OperationFailedException>() { + @Override + public Collection apply(final OperationContext context, final ModelNode model) throws OperationFailedException { + return createSingleton(REMOTE_HOST_KEY, context, model, RemoteHostAttribute.INSTANCE); + } + }); + + private static final SimpleAttributeDefinition REMOTE_IP_KEY = createKey("remoteIp"); + private static final SimpleAttributeDefinition OBFUSCATED = SimpleAttributeDefinitionBuilder.create("obfuscated", ModelType.BOOLEAN, true) + .setAllowExpression(true) + .setDefaultValue(ModelNode.FALSE) + .build(); + private static final ObjectTypeAttributeDefinition REMOTE_IP = create( + ObjectTypeAttributeDefinition.create("remote-ip", REMOTE_IP_KEY, OBFUSCATED), + new ExceptionBiFunction, OperationFailedException>() { + @Override + public Collection apply(final OperationContext context, final ModelNode model) throws OperationFailedException { + if (OBFUSCATED.resolveModelAttribute(context, model).asBoolean()) { + return createSingleton(REMOTE_IP_KEY, context, model, RemoteObfuscatedIPAttribute.INSTANCE); + } + return createSingleton(REMOTE_IP_KEY, context, model, RemoteIPAttribute.INSTANCE); + } + }); + + private static final SimpleAttributeDefinition REMOTE_USER_KEY = createKey("remoteUser"); + private static final ObjectTypeAttributeDefinition REMOTE_USER = create( + ObjectTypeAttributeDefinition.create("remote-user", REMOTE_USER_KEY), + new ExceptionBiFunction, OperationFailedException>() { + @Override + public Collection apply(final OperationContext context, final ModelNode model) throws OperationFailedException { + return createSingleton(REMOTE_USER_KEY, context, model, RemoteUserAttribute.INSTANCE); + } + }); + + private static final SimpleAttributeDefinition REQUEST_HEADER_KEY_PREFIX = KEY_PREFIX_BUILDER.build(); + private static final ObjectTypeAttributeDefinition REQUEST_HEADER = create(ObjectTypeAttributeDefinition.Builder.of("request-header", + REQUEST_HEADER_KEY_PREFIX, NAMES), + new ExceptionBiFunction, OperationFailedException>() { + @Override + public Collection apply(final OperationContext context, final ModelNode model) throws OperationFailedException { + final Collection result = new ArrayList<>(5); + for (ModelNode m : NAMES.resolveModelAttribute(context, model).asList()) { + final String name = m.asString(); + final String keyName = resolveKeyName(REQUEST_HEADER_KEY_PREFIX.resolveModelAttribute(context, model), name); + result.add(AccessLogAttribute.of(keyName, new RequestHeaderAttribute(HttpString.tryFromString(name)))); + } + return result; + } + }); + + private static final SimpleAttributeDefinition REQUEST_LINE_KEY = createKey("requestLine"); + private static final ObjectTypeAttributeDefinition REQUEST_LINE = create( + ObjectTypeAttributeDefinition.create("request-line", REQUEST_LINE_KEY), + new ExceptionBiFunction, OperationFailedException>() { + @Override + public Collection apply(final OperationContext context, final ModelNode model) throws OperationFailedException { + return createSingleton(REQUEST_LINE_KEY, context, model, RequestLineAttribute.INSTANCE); + } + }); + + private static final SimpleAttributeDefinition REQUEST_METHOD_KEY = createKey("requestMethod"); + private static final ObjectTypeAttributeDefinition REQUEST_METHOD = create( + ObjectTypeAttributeDefinition.create("request-method", REQUEST_METHOD_KEY), + new ExceptionBiFunction, OperationFailedException>() { + @Override + public Collection apply(final OperationContext context, final ModelNode model) throws OperationFailedException { + return createSingleton(REQUEST_METHOD_KEY, context, model, RequestMethodAttribute.INSTANCE); + } + }); + + private static final SimpleAttributeDefinition REQUEST_PATH_KEY = createKey("requestPath"); + private static final ObjectTypeAttributeDefinition REQUEST_PATH = create( + ObjectTypeAttributeDefinition.create("request-path", REQUEST_PATH_KEY), + new ExceptionBiFunction, OperationFailedException>() { + @Override + public Collection apply(final OperationContext context, final ModelNode model) throws OperationFailedException { + return createSingleton(REQUEST_PATH_KEY, context, model, RequestPathAttribute.INSTANCE); + } + }); + + private static final SimpleAttributeDefinition REQUEST_PROTOCOL_KEY = createKey("requestProtocol"); + private static final ObjectTypeAttributeDefinition REQUEST_PROTOCOL = create( + ObjectTypeAttributeDefinition.create("request-protocol", REQUEST_PROTOCOL_KEY), + new ExceptionBiFunction, OperationFailedException>() { + @Override + public Collection apply(final OperationContext context, final ModelNode model) throws OperationFailedException { + return createSingleton(REQUEST_PROTOCOL_KEY, context, model, RequestProtocolAttribute.INSTANCE); + } + }); + + private static final SimpleAttributeDefinition REQUEST_SCHEME_KEY = createKey("requestScheme"); + private static final ObjectTypeAttributeDefinition REQUEST_SCHEME = create( + ObjectTypeAttributeDefinition.create("request-scheme", REQUEST_SCHEME_KEY), + new ExceptionBiFunction, OperationFailedException>() { + @Override + public Collection apply(final OperationContext context, final ModelNode model) throws OperationFailedException { + return createSingleton(REQUEST_SCHEME_KEY, context, model, RequestSchemeAttribute.INSTANCE); + } + }); + + private static final SimpleAttributeDefinition REQUEST_URL_KEY = createKey("requestUrl"); + private static final ObjectTypeAttributeDefinition REQUEST_URL = create( + ObjectTypeAttributeDefinition.create("request-url", REQUEST_URL_KEY), + new ExceptionBiFunction, OperationFailedException>() { + @Override + public Collection apply(final OperationContext context, final ModelNode model) throws OperationFailedException { + return createSingleton(REQUEST_URL_KEY, context, model, RequestURLAttribute.INSTANCE); + } + }); + + private static final SimpleAttributeDefinition RESOLVED_PATH_KEY = createKey("resolvedPath"); + private static final ObjectTypeAttributeDefinition RESOLVED_PATH = create( + ObjectTypeAttributeDefinition.create("resolved-path", RESOLVED_PATH_KEY), + new ExceptionBiFunction, OperationFailedException>() { + @Override + public Collection apply(final OperationContext context, final ModelNode model) throws OperationFailedException { + return createSingleton(RESOLVED_PATH_KEY, context, model, ResolvedPathAttribute.INSTANCE); + } + }); + + private static final SimpleAttributeDefinition RESPONSE_CODE_KEY = createKey("responseCode"); + private static final ObjectTypeAttributeDefinition RESPONSE_CODE = create( + ObjectTypeAttributeDefinition.create("response-code", RESPONSE_CODE_KEY), + new ExceptionBiFunction, OperationFailedException>() { + @Override + public Collection apply(final OperationContext context, final ModelNode model) throws OperationFailedException { + return createSingleton(RESPONSE_CODE_KEY, context, model, ResponseCodeAttribute.INSTANCE, new Function() { + @Override + public Object apply(final String s) { + return Integer.valueOf(s); + } + }); + } + }); + + private static final SimpleAttributeDefinition RESPONSE_HEADER_KEY_PREFIX = KEY_PREFIX_BUILDER.build(); + private static final ObjectTypeAttributeDefinition RESPONSE_HEADER = create(ObjectTypeAttributeDefinition.Builder.of("response-header", + RESPONSE_HEADER_KEY_PREFIX, NAMES), + new ExceptionBiFunction, OperationFailedException>() { + @Override + public Collection apply(final OperationContext context, final ModelNode model) throws OperationFailedException { + final Collection result = new ArrayList<>(5); + for (ModelNode m : NAMES.resolveModelAttribute(context, model).asList()) { + final String name = m.asString(); + final String keyName = resolveKeyName(RESPONSE_HEADER_KEY_PREFIX.resolveModelAttribute(context, model), name); + result.add(AccessLogAttribute.of(keyName, new ResponseHeaderAttribute(HttpString.tryFromString(name)))); + } + return result; + } + }); + + private static final SimpleAttributeDefinition RESPONSE_REASON_PHRASE_KEY = createKey("responseReasonPhrase"); + private static final ObjectTypeAttributeDefinition RESPONSE_REASON_PHRASE = create( + ObjectTypeAttributeDefinition.create("response-reason-phrase", RESPONSE_REASON_PHRASE_KEY), + new ExceptionBiFunction, OperationFailedException>() { + @Override + public Collection apply(final OperationContext context, final ModelNode model) throws OperationFailedException { + return createSingleton(RESPONSE_REASON_PHRASE_KEY, context, model, ResponseReasonPhraseAttribute.INSTANCE); + } + }); + + + private static final SimpleAttributeDefinition RESPONSE_TIME_KEY = createKey("responseTime"); + private static final SimpleAttributeDefinition TIME_UNIT = new SimpleAttributeDefinitionBuilder("time-unit", ModelType.STRING, true) + .setAllowExpression(true) + .setDefaultValue(new ModelNode(TimeUnit.MILLISECONDS.name())) + .setValidator(EnumValidator.create(TimeUnit.class, TimeUnit.SECONDS, TimeUnit.NANOSECONDS, TimeUnit.MILLISECONDS, TimeUnit.MICROSECONDS)) + .build(); + private static final ObjectTypeAttributeDefinition RESPONSE_TIME = create( + ObjectTypeAttributeDefinition.create("response-time", RESPONSE_TIME_KEY, TIME_UNIT), + new ExceptionBiFunction, OperationFailedException>() { + @Override + public Collection apply(final OperationContext context, final ModelNode model) throws OperationFailedException { + return createSingleton(RESPONSE_TIME_KEY, context, model, + new ResponseTimeAttribute(TimeUnit.valueOf(TIME_UNIT.resolveModelAttribute(context, model).asString())), + new Function() { + @Override + public Object apply(final String s) { + if (s == null) { + return null; + } + return Long.valueOf(s); + } + }); + } + }); + + private static final SimpleAttributeDefinition SECURE_EXCHANGE_KEY = createKey("secureExchange"); + private static final ObjectTypeAttributeDefinition SECURE_EXCHANGE = create( + ObjectTypeAttributeDefinition.create("secure-exchange", SECURE_EXCHANGE_KEY), + new ExceptionBiFunction, OperationFailedException>() { + @Override + @SuppressWarnings("Anonymous2MethodRef") + public Collection apply(final OperationContext context, final ModelNode model) throws OperationFailedException { + return createSingleton(SECURE_EXCHANGE_KEY, context, model, SecureExchangeAttribute.INSTANCE, + new Function() { + @Override + public Object apply(final String s) { + return Boolean.valueOf(s); + } + }); + } + }); + + private static final SimpleAttributeDefinition SSL_CIPHER_KEY = createKey("sslCipher"); + private static final ObjectTypeAttributeDefinition SSL_CIPHER = create( + ObjectTypeAttributeDefinition.create("ssl-cipher", SSL_CIPHER_KEY), + new ExceptionBiFunction, OperationFailedException>() { + @Override + public Collection apply(final OperationContext context, final ModelNode model) throws OperationFailedException { + return createSingleton(SSL_CIPHER_KEY, context, model, SslCipherAttribute.INSTANCE); + } + }); + + private static final SimpleAttributeDefinition SSL_CLIENT_CERT_KEY = createKey("sslClientCert"); + private static final ObjectTypeAttributeDefinition SSL_CLIENT_CERT = create( + ObjectTypeAttributeDefinition.create("ssl-client-cert", SSL_CLIENT_CERT_KEY), + new ExceptionBiFunction, OperationFailedException>() { + @Override + public Collection apply(final OperationContext context, final ModelNode model) throws OperationFailedException { + return createSingleton(SSL_CLIENT_CERT_KEY, context, model, SslClientCertAttribute.INSTANCE); + } + }); + + private static final SimpleAttributeDefinition SSL_SESSION_ID_KEY = createKey("sslSessionId"); + private static final ObjectTypeAttributeDefinition SSL_SESSION_ID = create( + ObjectTypeAttributeDefinition.create("ssl-session-id", SSL_SESSION_ID_KEY), + new ExceptionBiFunction, OperationFailedException>() { + @Override + public Collection apply(final OperationContext context, final ModelNode model) throws OperationFailedException { + return createSingleton(SSL_SESSION_ID_KEY, context, model, SslSessionIdAttribute.INSTANCE); + } + }); + + private static final SimpleAttributeDefinition STORED_RESPONSE_KEY = createKey("storedResponse"); + private static final ObjectTypeAttributeDefinition STORED_RESPONSE = create( + ObjectTypeAttributeDefinition.create("stored-response", STORED_RESPONSE_KEY), + new ExceptionBiFunction, OperationFailedException>() { + @Override + public Collection apply(final OperationContext context, final ModelNode model) throws OperationFailedException { + return createSingleton(STORED_RESPONSE_KEY, context, model, StoredResponse.INSTANCE); + } + }); + + private static final SimpleAttributeDefinition THREAD_NAME_KEY = createKey("threadName"); + private static final ObjectTypeAttributeDefinition THREAD_NAME = create( + ObjectTypeAttributeDefinition.create("thread-name", THREAD_NAME_KEY), + new ExceptionBiFunction, OperationFailedException>() { + @Override + public Collection apply(final OperationContext context, final ModelNode model) throws OperationFailedException { + return createSingleton(THREAD_NAME_KEY, context, model, ThreadNameAttribute.INSTANCE); + } + }); + + private static final SimpleAttributeDefinition TRANSPORT_PROTOCOL_KEY = createKey("transportProtocol"); + private static final ObjectTypeAttributeDefinition TRANSPORT_PROTOCOL = create( + ObjectTypeAttributeDefinition.create("transport-protocol", TRANSPORT_PROTOCOL_KEY), + new ExceptionBiFunction, OperationFailedException>() { + @Override + public Collection apply(final OperationContext context, final ModelNode model) throws OperationFailedException { + return createSingleton(TRANSPORT_PROTOCOL_KEY, context, model, TransportProtocolAttribute.INSTANCE); + } + }); + + static final ObjectTypeAttributeDefinition ATTRIBUTES = ObjectTypeAttributeDefinition.create("attributes", + AUTHENTICATION_TYPE, + BYTES_SENT, + DATE_TIME, + HOST_AND_PORT, + LOCAL_IP, + LOCAL_PORT, + LOCAL_SERVER_NAME, + PATH_PARAMETER, + PREDICATE, + QUERY_PARAMETER, + QUERY_STRING, + RELATIVE_PATH, + REMOTE_HOST, + REMOTE_IP, + REMOTE_USER, + REQUEST_HEADER, + REQUEST_LINE, + REQUEST_METHOD, + REQUEST_PATH, + REQUEST_PROTOCOL, + REQUEST_SCHEME, + REQUEST_URL, + RESOLVED_PATH, + RESPONSE_CODE, + RESPONSE_HEADER, + RESPONSE_REASON_PHRASE, + RESPONSE_TIME, + SECURE_EXCHANGE, + SSL_CIPHER, + SSL_CLIENT_CERT, + SSL_SESSION_ID, + STORED_RESPONSE, + THREAD_NAME, + TRANSPORT_PROTOCOL + ) + .setDefaultValue(createDefaultAttribute()) + .setRestartAllServices() + .build(); + + static Collection resolveAccessLogAttribute(final AttributeDefinition attribute, + final OperationContext context, + final ModelNode model) throws OperationFailedException { + final ExceptionBiFunction, OperationFailedException> attributeResolver = + ATTRIBUTE_RESOLVERS.get(attribute); + assert attributeResolver != null; + if (model.hasDefined(attribute.getName())) { + return attributeResolver.apply(context, model.get(attribute.getName())); + } + return Collections.emptyList(); + } + + private static Collection createSingleton(final AttributeDefinition keyAttribute, + final OperationContext context, final ModelNode model, + final ExchangeAttribute exchangeAttribute) throws OperationFailedException { + return Collections.singletonList(AccessLogAttribute.of(keyAttribute.resolveModelAttribute(context, model).asString(), + exchangeAttribute)); + } + + @SuppressWarnings({"SameParameterValue"}) + private static Collection createSingleton(final AttributeDefinition keyAttribute, + final OperationContext context, final ModelNode model, + final ExchangeAttribute exchangeAttribute, + final Function valueConverter) throws OperationFailedException { + return Collections.singletonList(AccessLogAttribute.of(keyAttribute.resolveModelAttribute(context, model).asString(), + exchangeAttribute, valueConverter)); + } + + private static SimpleAttributeDefinition createKey(final String dftValue) { + return KEY_BUILDER.setDefaultValue(new ModelNode(dftValue)).build(); + } + + private static ModelNode createDefaultAttribute() { + final ModelNode result = new ModelNode().setEmptyObject(); + result.get(REMOTE_HOST.getName()).setEmptyObject(); + result.get(REMOTE_USER.getName()).setEmptyObject(); + result.get(DATE_TIME.getName()).setEmptyObject(); + result.get(REQUEST_LINE.getName()).setEmptyObject(); + result.get(RESPONSE_CODE.getName()).setEmptyObject(); + result.get(BYTES_SENT.getName()).setEmptyObject(); + return result; + } + + private static > R create(final B builder, + final ExceptionBiFunction, OperationFailedException> attributeResolver) { + final R result = builder.setRequired(false).build(); + ATTRIBUTE_RESOLVERS.put(result, attributeResolver); + return result; + } + + private static String resolveKeyName(final ModelNode prefix, final String name) { + final StringBuilder result = new StringBuilder(); + if (prefix.isDefined()) { + result.append(prefix.asString()); + } + result.append(name); + return result.toString(); + } +} Fisheye: Tag 0c9c83107d623392869f43619926ea6d8ec5beab refers to a dead (removed) revision in file `3rdParty_sources/undertow/org/wildfly/extension/undertow/FilterLocation.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 0c9c83107d623392869f43619926ea6d8ec5beab refers to a dead (removed) revision in file `3rdParty_sources/undertow/org/wildfly/extension/undertow/Handler.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 0c9c83107d623392869f43619926ea6d8ec5beab refers to a dead (removed) revision in file `3rdParty_sources/undertow/org/wildfly/extension/undertow/Host.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 0c9c83107d623392869f43619926ea6d8ec5beab refers to a dead (removed) revision in file `3rdParty_sources/undertow/org/wildfly/extension/undertow/HostAdd.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 0c9c83107d623392869f43619926ea6d8ec5beab refers to a dead (removed) revision in file `3rdParty_sources/undertow/org/wildfly/extension/undertow/HostDefinition.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 0c9c83107d623392869f43619926ea6d8ec5beab refers to a dead (removed) revision in file `3rdParty_sources/undertow/org/wildfly/extension/undertow/HostRemove.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 0c9c83107d623392869f43619926ea6d8ec5beab refers to a dead (removed) revision in file `3rdParty_sources/undertow/org/wildfly/extension/undertow/HostSingleSignOnDefinition.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 0c9c83107d623392869f43619926ea6d8ec5beab refers to a dead (removed) revision in file `3rdParty_sources/undertow/org/wildfly/extension/undertow/HttpInvokerDefinition.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 0c9c83107d623392869f43619926ea6d8ec5beab refers to a dead (removed) revision in file `3rdParty_sources/undertow/org/wildfly/extension/undertow/HttpInvokerHostService.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 0c9c83107d623392869f43619926ea6d8ec5beab refers to a dead (removed) revision in file `3rdParty_sources/undertow/org/wildfly/extension/undertow/HttpListenerAdd.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 0c9c83107d623392869f43619926ea6d8ec5beab refers to a dead (removed) revision in file `3rdParty_sources/undertow/org/wildfly/extension/undertow/HttpListenerResourceDefinition.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 0c9c83107d623392869f43619926ea6d8ec5beab refers to a dead (removed) revision in file `3rdParty_sources/undertow/org/wildfly/extension/undertow/HttpListenerService.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 0c9c83107d623392869f43619926ea6d8ec5beab refers to a dead (removed) revision in file `3rdParty_sources/undertow/org/wildfly/extension/undertow/HttpListenerWorkerAttributeWriteHandler.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 0c9c83107d623392869f43619926ea6d8ec5beab refers to a dead (removed) revision in file `3rdParty_sources/undertow/org/wildfly/extension/undertow/HttpsListenerAdd.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 0c9c83107d623392869f43619926ea6d8ec5beab refers to a dead (removed) revision in file `3rdParty_sources/undertow/org/wildfly/extension/undertow/HttpsListenerResourceDefinition.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 0c9c83107d623392869f43619926ea6d8ec5beab refers to a dead (removed) revision in file `3rdParty_sources/undertow/org/wildfly/extension/undertow/HttpsListenerService.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 0c9c83107d623392869f43619926ea6d8ec5beab refers to a dead (removed) revision in file `3rdParty_sources/undertow/org/wildfly/extension/undertow/ImportedClassELResolver.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 0c9c83107d623392869f43619926ea6d8ec5beab refers to a dead (removed) revision in file `3rdParty_sources/undertow/org/wildfly/extension/undertow/InMemoryModularPersistentSessionManager.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 0c9c83107d623392869f43619926ea6d8ec5beab refers to a dead (removed) revision in file `3rdParty_sources/undertow/org/wildfly/extension/undertow/JSPConfig.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 0c9c83107d623392869f43619926ea6d8ec5beab refers to a dead (removed) revision in file `3rdParty_sources/undertow/org/wildfly/extension/undertow/JspDefinition.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 0c9c83107d623392869f43619926ea6d8ec5beab refers to a dead (removed) revision in file `3rdParty_sources/undertow/org/wildfly/extension/undertow/ListenerAdd.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 0c9c83107d623392869f43619926ea6d8ec5beab refers to a dead (removed) revision in file `3rdParty_sources/undertow/org/wildfly/extension/undertow/ListenerResourceDefinition.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 0c9c83107d623392869f43619926ea6d8ec5beab refers to a dead (removed) revision in file `3rdParty_sources/undertow/org/wildfly/extension/undertow/ListenerService.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 0c9c83107d623392869f43619926ea6d8ec5beab refers to a dead (removed) revision in file `3rdParty_sources/undertow/org/wildfly/extension/undertow/LocationAdd.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 0c9c83107d623392869f43619926ea6d8ec5beab refers to a dead (removed) revision in file `3rdParty_sources/undertow/org/wildfly/extension/undertow/LocationDefinition.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 0c9c83107d623392869f43619926ea6d8ec5beab refers to a dead (removed) revision in file `3rdParty_sources/undertow/org/wildfly/extension/undertow/LocationService.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 0c9c83107d623392869f43619926ea6d8ec5beab refers to a dead (removed) revision in file `3rdParty_sources/undertow/org/wildfly/extension/undertow/MimeMappingDefinition.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 0c9c83107d623392869f43619926ea6d8ec5beab refers to a dead (removed) revision in file `3rdParty_sources/undertow/org/wildfly/extension/undertow/PersistentSessionsDefinition.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 0c9c83107d623392869f43619926ea6d8ec5beab refers to a dead (removed) revision in file `3rdParty_sources/undertow/org/wildfly/extension/undertow/PredicateValidator.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 0c9c83107d623392869f43619926ea6d8ec5beab refers to a dead (removed) revision in file `3rdParty_sources/undertow/org/wildfly/extension/undertow/RemoteHttpInvokerService.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 0c9c83107d623392869f43619926ea6d8ec5beab refers to a dead (removed) revision in file `3rdParty_sources/undertow/org/wildfly/extension/undertow/ResetConnectorStatisticsHandler.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 0c9c83107d623392869f43619926ea6d8ec5beab refers to a dead (removed) revision in file `3rdParty_sources/undertow/org/wildfly/extension/undertow/Server.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 0c9c83107d623392869f43619926ea6d8ec5beab refers to a dead (removed) revision in file `3rdParty_sources/undertow/org/wildfly/extension/undertow/ServerAdd.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 0c9c83107d623392869f43619926ea6d8ec5beab refers to a dead (removed) revision in file `3rdParty_sources/undertow/org/wildfly/extension/undertow/ServerDefinition.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 0c9c83107d623392869f43619926ea6d8ec5beab refers to a dead (removed) revision in file `3rdParty_sources/undertow/org/wildfly/extension/undertow/ServletContainerAdd.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 0c9c83107d623392869f43619926ea6d8ec5beab refers to a dead (removed) revision in file `3rdParty_sources/undertow/org/wildfly/extension/undertow/ServletContainerDefinition.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 0c9c83107d623392869f43619926ea6d8ec5beab refers to a dead (removed) revision in file `3rdParty_sources/undertow/org/wildfly/extension/undertow/ServletContainerService.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 0c9c83107d623392869f43619926ea6d8ec5beab refers to a dead (removed) revision in file `3rdParty_sources/undertow/org/wildfly/extension/undertow/SessionCookieDefinition.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 0c9c83107d623392869f43619926ea6d8ec5beab refers to a dead (removed) revision in file `3rdParty_sources/undertow/org/wildfly/extension/undertow/SingleSignOnDefinition.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 0c9c83107d623392869f43619926ea6d8ec5beab refers to a dead (removed) revision in file `3rdParty_sources/undertow/org/wildfly/extension/undertow/SingleSignOnManagerServiceNameProvider.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 0c9c83107d623392869f43619926ea6d8ec5beab refers to a dead (removed) revision in file `3rdParty_sources/undertow/org/wildfly/extension/undertow/SingleSignOnSessionFactoryServiceConfigurator.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 0c9c83107d623392869f43619926ea6d8ec5beab refers to a dead (removed) revision in file `3rdParty_sources/undertow/org/wildfly/extension/undertow/SingleSignOnSessionFactoryServiceNameProvider.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 0c9c83107d623392869f43619926ea6d8ec5beab refers to a dead (removed) revision in file `3rdParty_sources/undertow/org/wildfly/extension/undertow/UndertowEventListener.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 0c9c83107d623392869f43619926ea6d8ec5beab refers to a dead (removed) revision in file `3rdParty_sources/undertow/org/wildfly/extension/undertow/UndertowExtension.java'. Fisheye: No comparison available. Pass `N' to diff? Index: 3rdParty_sources/undertow/org/wildfly/extension/undertow/UndertowExtensionTransformerRegistration.java =================================================================== diff -u --- 3rdParty_sources/undertow/org/wildfly/extension/undertow/UndertowExtensionTransformerRegistration.java (revision 0) +++ 3rdParty_sources/undertow/org/wildfly/extension/undertow/UndertowExtensionTransformerRegistration.java (revision e704ad812feb0fa447e5bd63332f753ac1a94b70) @@ -0,0 +1,63 @@ +/* + * Copyright The WildFly Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package org.wildfly.extension.undertow; + +import java.util.EnumSet; +import java.util.Set; + +import org.jboss.as.controller.ModelVersion; +import org.jboss.as.controller.PathElement; +import org.jboss.as.controller.transform.ExtensionTransformerRegistration; +import org.jboss.as.controller.transform.SubsystemTransformerRegistration; +import org.jboss.as.controller.transform.description.AttributeConverter; +import org.jboss.as.controller.transform.description.DiscardAttributeChecker; +import org.jboss.as.controller.transform.description.RejectAttributeChecker; +import org.jboss.as.controller.transform.description.ResourceTransformationDescriptionBuilder; +import org.jboss.as.controller.transform.description.TransformationDescription; +import org.jboss.as.controller.transform.description.TransformationDescriptionBuilder; +import org.kohsuke.MetaInfServices; + +/** + * Registers transformers for the Undertow subsystem. + * @author Paul Ferraro + */ +@MetaInfServices +public class UndertowExtensionTransformerRegistration implements ExtensionTransformerRegistration { + + @Override + public String getSubsystemName() { + return UndertowExtension.SUBSYSTEM_NAME; + } + + @Override + public void registerTransformers(SubsystemTransformerRegistration registration) { + for (UndertowSubsystemModel model : EnumSet.complementOf(EnumSet.of(UndertowSubsystemModel.CURRENT))) { + ModelVersion version = model.getVersion(); + ResourceTransformationDescriptionBuilder subsystem = TransformationDescriptionBuilder.Factory.createSubsystemInstance(); + + ResourceTransformationDescriptionBuilder server = subsystem.addChildResource(ServerDefinition.PATH_ELEMENT); + for (PathElement listenerPath : Set.of(HttpListenerResourceDefinition.PATH_ELEMENT, HttpsListenerResourceDefinition.PATH_ELEMENT, AjpListenerResourceDefinition.PATH_ELEMENT)) { + if (UndertowSubsystemModel.VERSION_13_0_0.requiresTransformation(version)) { + server.addChildResource(listenerPath).getAttributeBuilder() + .setValueConverter(AttributeConverter.DEFAULT_VALUE, ListenerResourceDefinition.WRITE_TIMEOUT, ListenerResourceDefinition.READ_TIMEOUT) + .end(); + } + } + + ResourceTransformationDescriptionBuilder servletContainer = subsystem.addChildResource(ServletContainerDefinition.PATH_ELEMENT); + if (UndertowSubsystemModel.VERSION_13_0_0.requiresTransformation(version)) { + servletContainer.getAttributeBuilder() + .setDiscard(DiscardAttributeChecker.UNDEFINED, ServletContainerDefinition.ORPHAN_SESSION_ALLOWED) + .addRejectCheck(RejectAttributeChecker.DEFINED, ServletContainerDefinition.ORPHAN_SESSION_ALLOWED) + .end(); + + servletContainer.rejectChildResource(AffinityCookieDefinition.PATH_ELEMENT); + } + + TransformationDescription.Tools.register(subsystem.build(), registration, version); + } + } +} Fisheye: Tag 0c9c83107d623392869f43619926ea6d8ec5beab refers to a dead (removed) revision in file `3rdParty_sources/undertow/org/wildfly/extension/undertow/UndertowFilter.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 0c9c83107d623392869f43619926ea6d8ec5beab refers to a dead (removed) revision in file `3rdParty_sources/undertow/org/wildfly/extension/undertow/UndertowListener.java'. Fisheye: No comparison available. Pass `N' to diff? Index: 3rdParty_sources/undertow/org/wildfly/extension/undertow/UndertowPersistentResourceXMLDescriptionFactory.java =================================================================== diff -u --- 3rdParty_sources/undertow/org/wildfly/extension/undertow/UndertowPersistentResourceXMLDescriptionFactory.java (revision 0) +++ 3rdParty_sources/undertow/org/wildfly/extension/undertow/UndertowPersistentResourceXMLDescriptionFactory.java (revision e704ad812feb0fa447e5bd63332f753ac1a94b70) @@ -0,0 +1,260 @@ +/* + * Copyright The WildFly Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package org.wildfly.extension.undertow; + +import static org.jboss.as.controller.PersistentResourceXMLDescription.builder; + +import java.util.Set; +import java.util.function.Function; +import java.util.function.Predicate; +import java.util.stream.Stream; + +import org.jboss.as.clustering.controller.Attribute; +import org.jboss.as.controller.AttributeDefinition; +import org.jboss.as.controller.PersistentResourceXMLDescription; +import org.jboss.as.controller.operations.common.Util; +import org.wildfly.extension.undertow.filters.CustomFilterDefinition; +import org.wildfly.extension.undertow.filters.ErrorPageDefinition; +import org.wildfly.extension.undertow.filters.ExpressionFilterDefinition; +import org.wildfly.extension.undertow.filters.FilterDefinitions; +import org.wildfly.extension.undertow.filters.FilterRefDefinition; +import org.wildfly.extension.undertow.filters.GzipFilterDefinition; +import org.wildfly.extension.undertow.filters.ModClusterDefinition; +import org.wildfly.extension.undertow.filters.NoAffinityResourceDefinition; +import org.wildfly.extension.undertow.filters.RankedAffinityResourceDefinition; +import org.wildfly.extension.undertow.filters.RequestLimitHandlerDefinition; +import org.wildfly.extension.undertow.filters.ResponseHeaderFilterDefinition; +import org.wildfly.extension.undertow.filters.RewriteFilterDefinition; +import org.wildfly.extension.undertow.filters.SingleAffinityResourceDefinition; +import org.wildfly.extension.undertow.handlers.FileHandlerDefinition; +import org.wildfly.extension.undertow.handlers.HandlerDefinitions; +import org.wildfly.extension.undertow.handlers.ReverseProxyHandlerDefinition; +import org.wildfly.extension.undertow.handlers.ReverseProxyHandlerHostDefinition; + +/** + * Factory for creating the {@link org.jboss.as.controller.PersistentResourceXMLDescription} for a given schema. + * @author Paul Ferraro + */ +public enum UndertowPersistentResourceXMLDescriptionFactory implements Function { + INSTANCE; + + @Override + public PersistentResourceXMLDescription apply(UndertowSubsystemSchema schema) { + PersistentResourceXMLDescription.PersistentResourceXMLBuilder builder = builder(UndertowRootDefinition.PATH_ELEMENT, schema.getNamespace()); + + if (schema.since(UndertowSubsystemSchema.VERSION_6_0)) { + builder.addChild(builder(ByteBufferPoolDefinition.PATH_ELEMENT).addAttributes(ByteBufferPoolDefinition.ATTRIBUTES.stream())); + } + builder.addChild(builder(BufferCacheDefinition.PATH_ELEMENT).addAttributes(BufferCacheDefinition.ATTRIBUTES.stream())); + builder.addChild(builder(ServerDefinition.PATH_ELEMENT).addAttributes(ServerDefinition.ATTRIBUTES.stream()) + .addChild(ajpListenerBuilder(schema)) + .addChild(httpListenerBuilder(schema)) + .addChild(httpsListenerBuilder(schema)) + .addChild(hostBuilder(schema)) + ); + builder.addChild(servletContainerBuilder(schema)); + builder.addChild(handlersBuilder(schema)); + builder.addChild(PersistentResourceXMLDescription.builder(FilterDefinitions.PATH_ELEMENT).setXmlElementName(Constants.FILTERS).setNoAddOperation(true) + .addChild(builder(RequestLimitHandlerDefinition.PATH_ELEMENT).addAttributes(RequestLimitHandlerDefinition.ATTRIBUTES.stream())) + .addChild(builder(ResponseHeaderFilterDefinition.PATH_ELEMENT).addAttributes(ResponseHeaderFilterDefinition.ATTRIBUTES.stream())) + .addChild(builder(GzipFilterDefinition.PATH_ELEMENT)) + .addChild(builder(ErrorPageDefinition.PATH_ELEMENT).addAttributes(ErrorPageDefinition.ATTRIBUTES.stream())) + .addChild(modClusterBuilder(schema)) + .addChild(builder(CustomFilterDefinition.PATH_ELEMENT).addAttributes(CustomFilterDefinition.ATTRIBUTES.stream()).setXmlElementName("filter")) + .addChild(builder(ExpressionFilterDefinition.PATH_ELEMENT).addAttributes(ExpressionFilterDefinition.ATTRIBUTES.stream())) + .addChild(builder(RewriteFilterDefinition.PATH_ELEMENT).addAttributes(RewriteFilterDefinition.ATTRIBUTES.stream())) + ); + if (schema.since(UndertowSubsystemSchema.VERSION_4_0)) { + builder.addChild(applicationSecurityDomainBuilder(schema)); + } + //here to make sure we always add filters & handlers path to mgmt model + builder.setAdditionalOperationsGenerator((address, addOperation, operations) -> { + operations.add(Util.createAddOperation(address.append(FilterDefinitions.PATH_ELEMENT))); + operations.add(Util.createAddOperation(address.append(HandlerDefinitions.PATH_ELEMENT))); + }); + + Stream attributes = UndertowRootDefinition.ATTRIBUTES.stream(); + if (!schema.since(UndertowSubsystemSchema.VERSION_12_0)) { + attributes = attributes.filter(Predicate.isEqual(UndertowRootDefinition.OBFUSCATE_SESSION_ROUTE).negate()); + } + attributes.forEach(builder::addAttribute); + return builder.build(); + } + + private static PersistentResourceXMLDescription.PersistentResourceXMLBuilder ajpListenerBuilder(UndertowSubsystemSchema schema) { + PersistentResourceXMLDescription.PersistentResourceXMLBuilder builder = builder(AjpListenerResourceDefinition.PATH_ELEMENT); + Stream attributes = AjpListenerResourceDefinition.ATTRIBUTES.stream(); + Stream.concat(listenerAttributes(schema), attributes).forEach(builder::addAttribute); + return builder; + } + + private static PersistentResourceXMLDescription.PersistentResourceXMLBuilder httpListenerBuilder(UndertowSubsystemSchema schema) { + PersistentResourceXMLDescription.PersistentResourceXMLBuilder builder = builder(HttpListenerResourceDefinition.PATH_ELEMENT); + Stream attributes = HttpListenerResourceDefinition.ATTRIBUTES.stream(); + // Reproduce attribute order of the previous parser implementation + Stream.of(listenerAttributes(schema), attributes, httpListenerAttributes(schema)).flatMap(Function.identity()).forEach(builder::addAttribute); + return builder; + } + + private static PersistentResourceXMLDescription.PersistentResourceXMLBuilder httpsListenerBuilder(UndertowSubsystemSchema schema) { + PersistentResourceXMLDescription.PersistentResourceXMLBuilder builder = builder(HttpsListenerResourceDefinition.PATH_ELEMENT); + Stream attributes = HttpsListenerResourceDefinition.ATTRIBUTES.stream(); + if (!schema.since(UndertowSubsystemSchema.VERSION_4_0)) { + attributes = attributes.filter(Predicate.isEqual(HttpsListenerResourceDefinition.SSL_CONTEXT).negate()); + } + Stream httpListenerAttributes = httpListenerAttributes(schema); + if (!schema.since(UndertowSubsystemSchema.VERSION_4_0)) { + httpListenerAttributes = httpListenerAttributes.filter(Predicate.not(Set.of(AbstractHttpListenerResourceDefinition.CERTIFICATE_FORWARDING, AbstractHttpListenerResourceDefinition.PROXY_ADDRESS_FORWARDING)::contains)); + } + // Reproduce attribute order of the previous parser implementation + Stream.of(listenerAttributes(schema), attributes, httpListenerAttributes).flatMap(Function.identity()).forEach(builder::addAttribute); + return builder; + } + + private static Stream httpListenerAttributes(UndertowSubsystemSchema schema) { + Stream attributes = AbstractHttpListenerResourceDefinition.ATTRIBUTES.stream(); + if (!schema.since(UndertowSubsystemSchema.VERSION_4_0)) { + attributes = attributes.filter(Predicate.isEqual(AbstractHttpListenerResourceDefinition.REQUIRE_HOST_HTTP11).negate()); + } + if (!schema.since(UndertowSubsystemSchema.VERSION_6_0)) { + attributes = attributes.filter(Predicate.isEqual(AbstractHttpListenerResourceDefinition.PROXY_PROTOCOL).negate()); + } + return attributes; + } + + private static Stream listenerAttributes(UndertowSubsystemSchema schema) { + Stream attributes = ListenerResourceDefinition.ATTRIBUTES.stream(); + if (!schema.since(UndertowSubsystemSchema.VERSION_4_0)) { + attributes = attributes.filter(Predicate.isEqual(ListenerResourceDefinition.RFC6265_COOKIE_VALIDATION).negate()); + } + if (!schema.since(UndertowSubsystemSchema.VERSION_6_0)) { + attributes = attributes.filter(Predicate.isEqual(ListenerResourceDefinition.ALLOW_UNESCAPED_CHARACTERS_IN_URL).negate()); + } + return attributes; + } + + private static PersistentResourceXMLDescription.PersistentResourceXMLBuilder hostBuilder(UndertowSubsystemSchema schema) { + PersistentResourceXMLDescription.PersistentResourceXMLBuilder builder = builder(HostDefinition.PATH_ELEMENT); + + builder.addChild(builder(LocationDefinition.PATH_ELEMENT).addAttributes(LocationDefinition.ATTRIBUTES.stream()) + .addChild(filterRefBuilder()) + ); + builder.addChild(builder(AccessLogDefinition.PATH_ELEMENT).addAttributes(AccessLogDefinition.ATTRIBUTES.stream())); + if (schema.since(UndertowSubsystemSchema.VERSION_9_0)) { + builder.addChild(builder(ConsoleAccessLogDefinition.PATH_ELEMENT).addAttributes(ConsoleAccessLogDefinition.ATTRIBUTES.stream())); + } + builder.addChild(filterRefBuilder()); + builder.addChild(builder(SingleSignOnDefinition.PATH_ELEMENT).addAttributes(Attribute.stream(SingleSignOnDefinition.Attribute.class))); + if (schema.since(UndertowSubsystemSchema.VERSION_4_0)) { + builder.addChild(builder(HttpInvokerDefinition.PATH_ELEMENT).addAttributes(HttpInvokerDefinition.ATTRIBUTES.stream())); + } + + Stream attributes = HostDefinition.ATTRIBUTES.stream(); + if (!schema.since(UndertowSubsystemSchema.VERSION_6_0)) { + attributes = attributes.filter(Predicate.isEqual(HostDefinition.QUEUE_REQUESTS_ON_START).negate()); + } + attributes.forEach(builder::addAttribute); + return builder; + } + + private static PersistentResourceXMLDescription.PersistentResourceXMLBuilder filterRefBuilder() { + return builder(FilterRefDefinition.PATH_ELEMENT).addAttributes(FilterRefDefinition.ATTRIBUTES.stream()); + } + + private static PersistentResourceXMLDescription.PersistentResourceXMLBuilder servletContainerBuilder(UndertowSubsystemSchema schema) { + PersistentResourceXMLDescription.PersistentResourceXMLBuilder builder = builder(ServletContainerDefinition.PATH_ELEMENT); + + builder.addChild(builder(JspDefinition.PATH_ELEMENT).addAttributes(JspDefinition.ATTRIBUTES.stream()).setXmlElementName(Constants.JSP_CONFIG)); + if (schema.since(UndertowSubsystemSchema.VERSION_14_0)) { + builder.addChild(builder(AffinityCookieDefinition.PATH_ELEMENT).addAttributes(AffinityCookieDefinition.ATTRIBUTES.stream())); + } + builder.addChild(builder(SessionCookieDefinition.PATH_ELEMENT).addAttributes(SessionCookieDefinition.ATTRIBUTES.stream())); + builder.addChild(builder(PersistentSessionsDefinition.PATH_ELEMENT).addAttributes(PersistentSessionsDefinition.ATTRIBUTES.stream())); + builder.addChild(websocketsBuilder(schema)); + builder.addChild(builder(MimeMappingDefinition.PATH_ELEMENT).addAttributes(MimeMappingDefinition.ATTRIBUTES.stream()).setXmlWrapperElement("mime-mappings")); + builder.addChild(builder(WelcomeFileDefinition.PATH_ELEMENT).setXmlWrapperElement("welcome-files")); + builder.addChild(builder(CrawlerSessionManagementDefinition.PATH_ELEMENT).addAttributes(CrawlerSessionManagementDefinition.ATTRIBUTES.stream())); + + Stream attributes = ServletContainerDefinition.ATTRIBUTES.stream(); + if (!schema.since(UndertowSubsystemSchema.VERSION_4_0)) { + attributes = attributes.filter(Predicate.not(Set.of(ServletContainerDefinition.DISABLE_FILE_WATCH_SERVICE, ServletContainerDefinition.DISABLE_SESSION_ID_REUSE)::contains)); + } + if (!schema.since(UndertowSubsystemSchema.VERSION_5_0)) { + attributes = attributes.filter(Predicate.not(Set.of(ServletContainerDefinition.FILE_CACHE_MAX_FILE_SIZE, ServletContainerDefinition.FILE_CACHE_METADATA_SIZE, ServletContainerDefinition.FILE_CACHE_TIME_TO_LIVE)::contains)); + } + if (!schema.since(UndertowSubsystemSchema.VERSION_6_0)) { + attributes = attributes.filter(Predicate.isEqual(ServletContainerDefinition.DEFAULT_COOKIE_VERSION).negate()); + } + if (!schema.since(UndertowSubsystemSchema.VERSION_10_0)) { + attributes = attributes.filter(Predicate.isEqual(ServletContainerDefinition.PRESERVE_PATH_ON_FORWARD).negate()); + } + attributes.forEach(builder::addAttribute); + return builder; + } + + private static PersistentResourceXMLDescription.PersistentResourceXMLBuilder websocketsBuilder(UndertowSubsystemSchema schema) { + PersistentResourceXMLDescription.PersistentResourceXMLBuilder builder = builder(WebsocketsDefinition.PATH_ELEMENT); + Stream attributes = WebsocketsDefinition.ATTRIBUTES.stream(); + if (!schema.since(UndertowSubsystemSchema.VERSION_4_0)) { + attributes = attributes.filter(Predicate.not(Set.of(WebsocketsDefinition.PER_MESSAGE_DEFLATE, WebsocketsDefinition.DEFLATER_LEVEL)::contains)); + } + attributes.forEach(builder::addAttribute); + return builder; + } + + private static PersistentResourceXMLDescription.PersistentResourceXMLBuilder handlersBuilder(UndertowSubsystemSchema schema) { + PersistentResourceXMLDescription.PersistentResourceXMLBuilder builder = builder(HandlerDefinitions.PATH_ELEMENT).setXmlElementName(Constants.HANDLERS).setNoAddOperation(true); + + builder.addChild(builder(FileHandlerDefinition.PATH_ELEMENT).addAttributes(FileHandlerDefinition.ATTRIBUTES.stream())); + + Stream reverseProxyHandlerAttributes = ReverseProxyHandlerDefinition.ATTRIBUTES.stream(); + if (!schema.since(UndertowSubsystemSchema.VERSION_4_0)) { + reverseProxyHandlerAttributes = reverseProxyHandlerAttributes.filter(Predicate.isEqual(ReverseProxyHandlerDefinition.MAX_RETRIES).negate()); + } + Stream reverseProxyHandlerHostAttributes = ReverseProxyHandlerHostDefinition.ATTRIBUTES.stream(); + if (!schema.since(UndertowSubsystemSchema.VERSION_4_0)) { + reverseProxyHandlerHostAttributes = reverseProxyHandlerHostAttributes.filter(Predicate.not(Set.of(ReverseProxyHandlerHostDefinition.SSL_CONTEXT, ReverseProxyHandlerHostDefinition.ENABLE_HTTP2)::contains)); + } + builder.addChild(builder(ReverseProxyHandlerDefinition.PATH_ELEMENT).addAttributes(reverseProxyHandlerAttributes) + .addChild(builder(ReverseProxyHandlerHostDefinition.PATH_ELEMENT).addAttributes(ReverseProxyHandlerHostDefinition.ATTRIBUTES.stream()).setXmlElementName(Constants.HOST)) + ); + return builder; + } + + private static PersistentResourceXMLDescription.PersistentResourceXMLBuilder modClusterBuilder(UndertowSubsystemSchema schema) { + PersistentResourceXMLDescription.PersistentResourceXMLBuilder builder = builder(ModClusterDefinition.PATH_ELEMENT); + + if (schema.since(UndertowSubsystemSchema.VERSION_10_0)) { + builder.addChild(builder(NoAffinityResourceDefinition.PATH).setXmlElementName(Constants.NO_AFFINITY)); + builder.addChild(builder(SingleAffinityResourceDefinition.PATH).setXmlElementName(Constants.SINGLE_AFFINITY)); + builder.addChild(builder(RankedAffinityResourceDefinition.PATH).addAttributes(Attribute.stream(RankedAffinityResourceDefinition.Attribute.class)).setXmlElementName(Constants.RANKED_AFFINITY)); + } + + Stream attributes = ModClusterDefinition.ATTRIBUTES.stream(); + if (!schema.since(UndertowSubsystemSchema.VERSION_4_0)) { + attributes = attributes.filter(Predicate.not(Set.of(ModClusterDefinition.FAILOVER_STRATEGY, ModClusterDefinition.SSL_CONTEXT, ModClusterDefinition.MAX_RETRIES)::contains)); + } + attributes.forEach(builder::addAttribute); + return builder; + } + + private static PersistentResourceXMLDescription.PersistentResourceXMLBuilder applicationSecurityDomainBuilder(UndertowSubsystemSchema schema) { + PersistentResourceXMLDescription.PersistentResourceXMLBuilder builder = builder(ApplicationSecurityDomainDefinition.PATH_ELEMENT).setXmlWrapperElement(Constants.APPLICATION_SECURITY_DOMAINS); + + Stream ssoAttributes = Stream.concat(Attribute.stream(ApplicationSecurityDomainSingleSignOnDefinition.Attribute.class), Attribute.stream(SingleSignOnDefinition.Attribute.class)); + builder.addChild(builder(SingleSignOnDefinition.PATH_ELEMENT).addAttributes(ssoAttributes)); + + Stream attributes = ApplicationSecurityDomainDefinition.ATTRIBUTES.stream(); + if (!schema.since(UndertowSubsystemSchema.VERSION_7_0)) { + attributes = attributes.filter(Predicate.isEqual(ApplicationSecurityDomainDefinition.SECURITY_DOMAIN).negate()); + } + if (!schema.since(UndertowSubsystemSchema.VERSION_8_0)) { + attributes = attributes.filter(Predicate.not(Set.of(ApplicationSecurityDomainDefinition.ENABLE_JASPI, ApplicationSecurityDomainDefinition.INTEGRATED_JASPI)::contains)); + } + attributes.forEach(builder::addAttribute); + return builder; + } +} Fisheye: Tag 0c9c83107d623392869f43619926ea6d8ec5beab refers to a dead (removed) revision in file `3rdParty_sources/undertow/org/wildfly/extension/undertow/UndertowRootDefinition.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 0c9c83107d623392869f43619926ea6d8ec5beab refers to a dead (removed) revision in file `3rdParty_sources/undertow/org/wildfly/extension/undertow/UndertowService.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 0c9c83107d623392869f43619926ea6d8ec5beab refers to a dead (removed) revision in file `3rdParty_sources/undertow/org/wildfly/extension/undertow/UndertowSubsystemAdd.java'. Fisheye: No comparison available. Pass `N' to diff? Index: 3rdParty_sources/undertow/org/wildfly/extension/undertow/UndertowSubsystemModel.java =================================================================== diff -u --- 3rdParty_sources/undertow/org/wildfly/extension/undertow/UndertowSubsystemModel.java (revision 0) +++ 3rdParty_sources/undertow/org/wildfly/extension/undertow/UndertowSubsystemModel.java (revision e704ad812feb0fa447e5bd63332f753ac1a94b70) @@ -0,0 +1,41 @@ +/* + * Copyright The WildFly Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package org.wildfly.extension.undertow; + +import org.jboss.as.controller.ModelVersion; +import org.jboss.as.controller.SubsystemModel; + +/** + * Enumerates the supported versions of the Undertow subsystem model. + * @author Paul Ferraro + */ +public enum UndertowSubsystemModel implements SubsystemModel { + + VERSION_11_0_0(11), // WildFly 23-26.x, EAP 7.4.x + VERSION_12_0_0(12), // WildFly 27 + VERSION_13_0_0(13), // WildFly 28-present + ; + static final UndertowSubsystemModel CURRENT = VERSION_13_0_0; + + private final ModelVersion version; + + UndertowSubsystemModel(int major) { + this(major, 0, 0); + } + + UndertowSubsystemModel(int major, int minor) { + this(major, minor, 0); + } + + UndertowSubsystemModel(int major, int minor, int micro) { + this.version = ModelVersion.create(major, minor, micro); + } + + @Override + public ModelVersion getVersion() { + return this.version; + } +} Index: 3rdParty_sources/undertow/org/wildfly/extension/undertow/UndertowSubsystemSchema.java =================================================================== diff -u --- 3rdParty_sources/undertow/org/wildfly/extension/undertow/UndertowSubsystemSchema.java (revision 0) +++ 3rdParty_sources/undertow/org/wildfly/extension/undertow/UndertowSubsystemSchema.java (revision e704ad812feb0fa447e5bd63332f753ac1a94b70) @@ -0,0 +1,64 @@ +/* + * Copyright The WildFly Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package org.wildfly.extension.undertow; + +import org.jboss.as.controller.PersistentResourceXMLDescription; +import org.jboss.as.controller.PersistentSubsystemSchema; +import org.jboss.as.controller.SubsystemSchema; +import org.jboss.as.controller.xml.VersionedNamespace; +import org.jboss.staxmapper.IntVersion; + +/** + * Enumerates the supported Undertow subsystem schemas. + * @author Paul Ferraro + */ +public enum UndertowSubsystemSchema implements PersistentSubsystemSchema { +/* Unsupported, for documentation purposes only + VERSION_1_0(1, 0), // WildFly 8.0 + VERSION_1_1(1, 1), // WildFly 8.1 + VERSION_1_2(1, 2), // WildFly 8.2 + VERSION_2_0(2), // WildFly 9 + VERSION_3_0(3, 0), // WildFly 10.0 + */ + VERSION_3_1(3, 1), // WildFly 10.1 + VERSION_4_0(4), // WildFly 11 + VERSION_5_0(5), // WildFly 12 + VERSION_6_0(6), // WildFly 13 + VERSION_7_0(7), // WildFly 14 + VERSION_8_0(8), // WildFly 15-16 + VERSION_9_0(9), // WildFly 17 + VERSION_10_0(10), // WildFly 18-19 + VERSION_11_0(11), // WildFly 20-22 N.B. There were no parser changes between 10.0 and 11.0 !! + VERSION_12_0(12), // WildFly 23-26.1, EAP 7.4 + VERSION_13_0(13), // WildFly 27 N.B. There were no schema changes between 12.0 and 13.0! + VERSION_14_0(14), // WildFly 28-present + ; + static final UndertowSubsystemSchema CURRENT = VERSION_14_0; + + private final VersionedNamespace namespace; + + UndertowSubsystemSchema(int major) { + this(new IntVersion(major)); + } + + UndertowSubsystemSchema(int major, int minor) { + this(new IntVersion(major, minor)); + } + + UndertowSubsystemSchema(IntVersion version) { + this.namespace = SubsystemSchema.createLegacySubsystemURN(UndertowExtension.SUBSYSTEM_NAME, version); + } + + @Override + public VersionedNamespace getNamespace() { + return this.namespace; + } + + @Override + public PersistentResourceXMLDescription getXMLDescription() { + return UndertowPersistentResourceXMLDescriptionFactory.INSTANCE.apply(this); + } +} Fisheye: Tag 0c9c83107d623392869f43619926ea6d8ec5beab refers to a dead (removed) revision in file `3rdParty_sources/undertow/org/wildfly/extension/undertow/WebHostService.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 0c9c83107d623392869f43619926ea6d8ec5beab refers to a dead (removed) revision in file `3rdParty_sources/undertow/org/wildfly/extension/undertow/WebServerService.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 0c9c83107d623392869f43619926ea6d8ec5beab refers to a dead (removed) revision in file `3rdParty_sources/undertow/org/wildfly/extension/undertow/WebsocketsDefinition.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 0c9c83107d623392869f43619926ea6d8ec5beab refers to a dead (removed) revision in file `3rdParty_sources/undertow/org/wildfly/extension/undertow/WelcomeFileDefinition.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 0c9c83107d623392869f43619926ea6d8ec5beab refers to a dead (removed) revision in file `3rdParty_sources/undertow/org/wildfly/extension/undertow/deployment/AuthMethodParser.java'. Fisheye: No comparison available. Pass `N' to diff? Index: 3rdParty_sources/undertow/org/wildfly/extension/undertow/deployment/ComponentStartupCountdownHandler.java =================================================================== diff -u --- 3rdParty_sources/undertow/org/wildfly/extension/undertow/deployment/ComponentStartupCountdownHandler.java (revision 0) +++ 3rdParty_sources/undertow/org/wildfly/extension/undertow/deployment/ComponentStartupCountdownHandler.java (revision e704ad812feb0fa447e5bd63332f753ac1a94b70) @@ -0,0 +1,44 @@ +/* + * Copyright The WildFly Authors + * SPDX-License-Identifier: Apache-2.0 + */ +package org.wildfly.extension.undertow.deployment; + +import io.undertow.server.Connectors; +import io.undertow.server.HttpHandler; +import io.undertow.server.HttpServerExchange; +import io.undertow.server.handlers.ResponseCodeHandler; +import org.jboss.as.ee.component.deployers.StartupCountdown; + +import java.util.concurrent.atomic.AtomicBoolean; + +/** + * Queue up requests until all startup components are initialized successfully. If any of the components failed to + * startup, all queued up and any subsequent requests are terminated with a 500 error code. + * + * Based on {@code io.undertow.server.handlers.RequestLimitingHandler} + * + * @author bspyrkos@redhat.com + */ +public class ComponentStartupCountdownHandler implements HttpHandler { + + private final HttpHandler wrappedHandler; + + private final AtomicBoolean started = new AtomicBoolean(false); + private final HttpHandler startupFailedHandler = ResponseCodeHandler.HANDLE_500; + + public ComponentStartupCountdownHandler(final HttpHandler handler, StartupCountdown countdown) { + this.wrappedHandler = handler; + + countdown.addCallback(()->started.set(true)); + } + + @Override + public void handleRequest(HttpServerExchange exchange) throws Exception { + if (started.get()) { + wrappedHandler.handleRequest(exchange); + } else { + Connectors.executeRootHandler(startupFailedHandler, exchange); + } + } +} Fisheye: Tag 0c9c83107d623392869f43619926ea6d8ec5beab refers to a dead (removed) revision in file `3rdParty_sources/undertow/org/wildfly/extension/undertow/deployment/ConfiguredHandlerWrapper.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 0c9c83107d623392869f43619926ea6d8ec5beab refers to a dead (removed) revision in file `3rdParty_sources/undertow/org/wildfly/extension/undertow/deployment/DefaultDeploymentMappingProvider.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 0c9c83107d623392869f43619926ea6d8ec5beab refers to a dead (removed) revision in file `3rdParty_sources/undertow/org/wildfly/extension/undertow/deployment/DefaultSecurityDomainProcessor.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 0c9c83107d623392869f43619926ea6d8ec5beab refers to a dead (removed) revision in file `3rdParty_sources/undertow/org/wildfly/extension/undertow/deployment/DelegatingResourceManager.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 0c9c83107d623392869f43619926ea6d8ec5beab refers to a dead (removed) revision in file `3rdParty_sources/undertow/org/wildfly/extension/undertow/deployment/DeploymentRootExplodedMountProcessor.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 0c9c83107d623392869f43619926ea6d8ec5beab refers to a dead (removed) revision in file `3rdParty_sources/undertow/org/wildfly/extension/undertow/deployment/EarContextRootProcessor.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 0c9c83107d623392869f43619926ea6d8ec5beab refers to a dead (removed) revision in file `3rdParty_sources/undertow/org/wildfly/extension/undertow/deployment/ExternalTldParsingDeploymentProcessor.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 0c9c83107d623392869f43619926ea6d8ec5beab refers to a dead (removed) revision in file `3rdParty_sources/undertow/org/wildfly/extension/undertow/deployment/GateHandlerWrapper.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 0c9c83107d623392869f43619926ea6d8ec5beab refers to a dead (removed) revision in file `3rdParty_sources/undertow/org/wildfly/extension/undertow/deployment/GlobalRequestControllerHandler.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 0c9c83107d623392869f43619926ea6d8ec5beab refers to a dead (removed) revision in file `3rdParty_sources/undertow/org/wildfly/extension/undertow/deployment/ImmediateSessionManagerFactory.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 0c9c83107d623392869f43619926ea6d8ec5beab refers to a dead (removed) revision in file `3rdParty_sources/undertow/org/wildfly/extension/undertow/deployment/JBossWebParsingDeploymentProcessor.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 0c9c83107d623392869f43619926ea6d8ec5beab refers to a dead (removed) revision in file `3rdParty_sources/undertow/org/wildfly/extension/undertow/deployment/JspApplicationContextWrapper.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 0c9c83107d623392869f43619926ea6d8ec5beab refers to a dead (removed) revision in file `3rdParty_sources/undertow/org/wildfly/extension/undertow/deployment/JspConfigDescriptorImpl.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 0c9c83107d623392869f43619926ea6d8ec5beab refers to a dead (removed) revision in file `3rdParty_sources/undertow/org/wildfly/extension/undertow/deployment/JspInitializationListener.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 0c9c83107d623392869f43619926ea6d8ec5beab refers to a dead (removed) revision in file `3rdParty_sources/undertow/org/wildfly/extension/undertow/deployment/JspPropertyGroupDescriptorImpl.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 0c9c83107d623392869f43619926ea6d8ec5beab refers to a dead (removed) revision in file `3rdParty_sources/undertow/org/wildfly/extension/undertow/deployment/RewriteCorrectingHandlerWrappers.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 0c9c83107d623392869f43619926ea6d8ec5beab refers to a dead (removed) revision in file `3rdParty_sources/undertow/org/wildfly/extension/undertow/deployment/ScisMetaData.java'. Fisheye: No comparison available. Pass `N' to diff? Index: 3rdParty_sources/undertow/org/wildfly/extension/undertow/deployment/SecurityDomainResolvingProcessor.java =================================================================== diff -u --- 3rdParty_sources/undertow/org/wildfly/extension/undertow/deployment/SecurityDomainResolvingProcessor.java (revision 0) +++ 3rdParty_sources/undertow/org/wildfly/extension/undertow/deployment/SecurityDomainResolvingProcessor.java (revision e704ad812feb0fa447e5bd63332f753ac1a94b70) @@ -0,0 +1,128 @@ +/* + * Copyright The WildFly Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package org.wildfly.extension.undertow.deployment; + +import static org.jboss.as.server.security.SecurityMetaData.ATTACHMENT_KEY; +import static org.wildfly.extension.undertow.Capabilities.REF_LEGACY_SECURITY; +import static org.wildfly.extension.undertow.deployment.UndertowAttachments.RESOLVED_SECURITY_DOMAIN; + +import java.util.function.Predicate; + +import org.jboss.as.controller.capability.CapabilityServiceSupport; +import org.jboss.as.server.deployment.Attachments; +import org.jboss.as.server.deployment.DeploymentPhaseContext; +import org.jboss.as.server.deployment.DeploymentUnit; +import org.jboss.as.server.deployment.DeploymentUnitProcessingException; +import org.jboss.as.server.deployment.DeploymentUnitProcessor; +import org.jboss.as.server.security.SecurityMetaData; +import org.jboss.as.web.common.WarMetaData; +import org.jboss.metadata.ear.jboss.JBossAppMetaData; +import org.jboss.metadata.ear.spec.EarMetaData; +import org.jboss.metadata.web.jboss.JBossWebMetaData; +import org.jboss.msc.service.ServiceName; +import org.wildfly.extension.undertow.Capabilities; +import org.wildfly.extension.undertow.Constants; + +/** + * A {@code DeploymentUnitProcessor} to resolve the security domain name for the deployment. + * + * @author Darran Lofthouse + */ +public class SecurityDomainResolvingProcessor implements DeploymentUnitProcessor { + + private static final String JAAS_CONTEXT_ROOT = "java:jboss/jaas/"; + private static final String JASPI_CONTEXT_ROOT = "java:jboss/jbsx/"; + private static final String LEGACY_JAAS_CONTEXT_ROOT = "java:/jaas/"; + + private final String defaultSecurityDomain; + private final Predicate mappedSecurityDomain; + + public SecurityDomainResolvingProcessor(final String defaultSecurityDomain, final Predicate mappedSecurityDomain) { + this.defaultSecurityDomain = defaultSecurityDomain; + this.mappedSecurityDomain = mappedSecurityDomain; + } + + @Override + public void deploy(DeploymentPhaseContext phaseContext) throws DeploymentUnitProcessingException { + final DeploymentUnit deploymentUnit = phaseContext.getDeploymentUnit(); + + final WarMetaData warMetaData = deploymentUnit.getAttachment(WarMetaData.ATTACHMENT_KEY); + if (warMetaData == null) { + return; + } + + final SecurityMetaData securityMetaData = deploymentUnit.getAttachment(ATTACHMENT_KEY); + if (securityMetaData != null && securityMetaData.getSecurityDomain() != null) { + return; // The SecurityDomain is already defined. + } + + final JBossWebMetaData metaData = warMetaData.getMergedJBossWebMetaData(); + + String securityDomain = metaData.getSecurityDomain(); + if (securityDomain == null) { + securityDomain = getJBossAppSecurityDomain(deploymentUnit); + } + securityDomain = securityDomain == null ? defaultSecurityDomain : unprefixSecurityDomain(securityDomain); + + if (securityDomain != null) { + if (mappedSecurityDomain.test(securityDomain)) { + ServiceName securityDomainName = deploymentUnit.getAttachment(Attachments.CAPABILITY_SERVICE_SUPPORT) + .getCapabilityServiceName( + Capabilities.CAPABILITY_APPLICATION_SECURITY_DOMAIN, + securityDomain).append(Constants.SECURITY_DOMAIN); + if (securityMetaData != null) { + securityMetaData.setSecurityDomain(securityDomainName); + } + deploymentUnit.putAttachment(RESOLVED_SECURITY_DOMAIN, securityDomain); + } else if (legacySecurityInstalled(deploymentUnit)) { + deploymentUnit.putAttachment(RESOLVED_SECURITY_DOMAIN, securityDomain); + } + } + } + + private static boolean legacySecurityInstalled(final DeploymentUnit deploymentUnit) { + final CapabilityServiceSupport capabilities = deploymentUnit.getAttachment(Attachments.CAPABILITY_SERVICE_SUPPORT); + + return capabilities.hasCapability(REF_LEGACY_SECURITY); + } + + @Override + public void undeploy(DeploymentUnit deploymentUnit) { + deploymentUnit.removeAttachment(RESOLVED_SECURITY_DOMAIN); + } + + /** + * Try to obtain the security domain configured in jboss-app.xml at the ear level if available + */ + private static String getJBossAppSecurityDomain(final DeploymentUnit deploymentUnit) { + String securityDomain = null; + DeploymentUnit parent = deploymentUnit.getParent(); + if (parent != null) { + final EarMetaData jbossAppMetaData = parent.getAttachment(org.jboss.as.ee.structure.Attachments.EAR_METADATA); + if (jbossAppMetaData instanceof JBossAppMetaData) { + securityDomain = ((JBossAppMetaData) jbossAppMetaData).getSecurityDomain(); + } + } + return securityDomain != null ? securityDomain.trim() : null; + } + + public static String unprefixSecurityDomain(String securityDomain) { + String result = null; + if (securityDomain != null) + { + if (securityDomain.startsWith(JAAS_CONTEXT_ROOT)) + result = securityDomain.substring(JAAS_CONTEXT_ROOT.length()); + else if (securityDomain.startsWith(JASPI_CONTEXT_ROOT)) + result = securityDomain.substring(JASPI_CONTEXT_ROOT.length()); + else if (securityDomain.startsWith(LEGACY_JAAS_CONTEXT_ROOT)) + result = securityDomain.substring(LEGACY_JAAS_CONTEXT_ROOT.length()); + else + result = securityDomain; + } + return result; + } + +} Fisheye: Tag 0c9c83107d623392869f43619926ea6d8ec5beab refers to a dead (removed) revision in file `3rdParty_sources/undertow/org/wildfly/extension/undertow/deployment/ServletContainerInitializerDeploymentProcessor.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 0c9c83107d623392869f43619926ea6d8ec5beab refers to a dead (removed) revision in file `3rdParty_sources/undertow/org/wildfly/extension/undertow/deployment/ServletResource.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 0c9c83107d623392869f43619926ea6d8ec5beab refers to a dead (removed) revision in file `3rdParty_sources/undertow/org/wildfly/extension/undertow/deployment/ServletResourceManager.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 0c9c83107d623392869f43619926ea6d8ec5beab refers to a dead (removed) revision in file `3rdParty_sources/undertow/org/wildfly/extension/undertow/deployment/SharedSessionManagerDeploymentProcessor.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 0c9c83107d623392869f43619926ea6d8ec5beab refers to a dead (removed) revision in file `3rdParty_sources/undertow/org/wildfly/extension/undertow/deployment/TaglibDescriptorImpl.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 0c9c83107d623392869f43619926ea6d8ec5beab refers to a dead (removed) revision in file `3rdParty_sources/undertow/org/wildfly/extension/undertow/deployment/TldParsingDeploymentProcessor.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 0c9c83107d623392869f43619926ea6d8ec5beab refers to a dead (removed) revision in file `3rdParty_sources/undertow/org/wildfly/extension/undertow/deployment/TldsMetaData.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 0c9c83107d623392869f43619926ea6d8ec5beab refers to a dead (removed) revision in file `3rdParty_sources/undertow/org/wildfly/extension/undertow/deployment/UndertowAttachments.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 0c9c83107d623392869f43619926ea6d8ec5beab refers to a dead (removed) revision in file `3rdParty_sources/undertow/org/wildfly/extension/undertow/deployment/UndertowDependencyProcessor.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 0c9c83107d623392869f43619926ea6d8ec5beab refers to a dead (removed) revision in file `3rdParty_sources/undertow/org/wildfly/extension/undertow/deployment/UndertowDeploymentInfoService.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 0c9c83107d623392869f43619926ea6d8ec5beab refers to a dead (removed) revision in file `3rdParty_sources/undertow/org/wildfly/extension/undertow/deployment/UndertowDeploymentProcessor.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 0c9c83107d623392869f43619926ea6d8ec5beab refers to a dead (removed) revision in file `3rdParty_sources/undertow/org/wildfly/extension/undertow/deployment/UndertowDeploymentService.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 0c9c83107d623392869f43619926ea6d8ec5beab refers to a dead (removed) revision in file `3rdParty_sources/undertow/org/wildfly/extension/undertow/deployment/UndertowHandlersDeploymentProcessor.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 0c9c83107d623392869f43619926ea6d8ec5beab refers to a dead (removed) revision in file `3rdParty_sources/undertow/org/wildfly/extension/undertow/deployment/UndertowJSPInstanceManager.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 0c9c83107d623392869f43619926ea6d8ec5beab refers to a dead (removed) revision in file `3rdParty_sources/undertow/org/wildfly/extension/undertow/deployment/UndertowJSRWebSocketDeploymentProcessor.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 0c9c83107d623392869f43619926ea6d8ec5beab refers to a dead (removed) revision in file `3rdParty_sources/undertow/org/wildfly/extension/undertow/deployment/UndertowMetricsCollector.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 0c9c83107d623392869f43619926ea6d8ec5beab refers to a dead (removed) revision in file `3rdParty_sources/undertow/org/wildfly/extension/undertow/deployment/UndertowServletContainerDependencyProcessor.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 0c9c83107d623392869f43619926ea6d8ec5beab refers to a dead (removed) revision in file `3rdParty_sources/undertow/org/wildfly/extension/undertow/deployment/VirtualFileResource.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 0c9c83107d623392869f43619926ea6d8ec5beab refers to a dead (removed) revision in file `3rdParty_sources/undertow/org/wildfly/extension/undertow/deployment/WarAnnotationDeploymentProcessor.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 0c9c83107d623392869f43619926ea6d8ec5beab refers to a dead (removed) revision in file `3rdParty_sources/undertow/org/wildfly/extension/undertow/deployment/WarDeploymentInitializingProcessor.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 0c9c83107d623392869f43619926ea6d8ec5beab refers to a dead (removed) revision in file `3rdParty_sources/undertow/org/wildfly/extension/undertow/deployment/WarMetaDataProcessor.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 0c9c83107d623392869f43619926ea6d8ec5beab refers to a dead (removed) revision in file `3rdParty_sources/undertow/org/wildfly/extension/undertow/deployment/WarStructureDeploymentProcessor.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 0c9c83107d623392869f43619926ea6d8ec5beab refers to a dead (removed) revision in file `3rdParty_sources/undertow/org/wildfly/extension/undertow/deployment/WebComponentProcessor.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 0c9c83107d623392869f43619926ea6d8ec5beab refers to a dead (removed) revision in file `3rdParty_sources/undertow/org/wildfly/extension/undertow/deployment/WebFragmentParsingDeploymentProcessor.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 0c9c83107d623392869f43619926ea6d8ec5beab refers to a dead (removed) revision in file `3rdParty_sources/undertow/org/wildfly/extension/undertow/deployment/WebJBossAllParser.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 0c9c83107d623392869f43619926ea6d8ec5beab refers to a dead (removed) revision in file `3rdParty_sources/undertow/org/wildfly/extension/undertow/deployment/WebParsingDeploymentProcessor.java'. Fisheye: No comparison available. Pass `N' to diff? Index: 3rdParty_sources/undertow/org/wildfly/extension/undertow/filters/AbstractFilterDefinition.java =================================================================== diff -u --- 3rdParty_sources/undertow/org/wildfly/extension/undertow/filters/AbstractFilterDefinition.java (revision 0) +++ 3rdParty_sources/undertow/org/wildfly/extension/undertow/filters/AbstractFilterDefinition.java (revision e704ad812feb0fa447e5bd63332f753ac1a94b70) @@ -0,0 +1,39 @@ +/* + * Copyright The WildFly Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package org.wildfly.extension.undertow.filters; + +import java.util.Collection; +import java.util.Collections; +import java.util.List; + +import org.jboss.as.controller.AttributeDefinition; +import org.jboss.as.controller.PathElement; +import org.jboss.as.controller.PersistentResourceDefinition; +import org.jboss.as.controller.access.constraint.SensitivityClassification; +import org.jboss.as.controller.access.management.AccessConstraintDefinition; +import org.jboss.as.controller.access.management.SensitiveTargetAccessConstraintDefinition; +import org.wildfly.extension.undertow.Constants; +import org.wildfly.extension.undertow.UndertowExtension; + +/** + * @author Tomaz Cerar (c) 2013 Red Hat Inc. + */ +public abstract class AbstractFilterDefinition extends PersistentResourceDefinition { + + protected AbstractFilterDefinition(PathElement path) { + super(path, UndertowExtension.getResolver(Constants.FILTER, path.getKey())); + } + + @Override + public List getAccessConstraints() { + return List.of(new SensitiveTargetAccessConstraintDefinition(new SensitivityClassification(UndertowExtension.SUBSYSTEM_NAME, "undertow-filter", false, false, false))); + } + + @Override + public Collection getAttributes() { + return Collections.emptyList(); + } +} Index: 3rdParty_sources/undertow/org/wildfly/extension/undertow/filters/AffinityResourceDefinition.java =================================================================== diff -u --- 3rdParty_sources/undertow/org/wildfly/extension/undertow/filters/AffinityResourceDefinition.java (revision 0) +++ 3rdParty_sources/undertow/org/wildfly/extension/undertow/filters/AffinityResourceDefinition.java (revision e704ad812feb0fa447e5bd63332f753ac1a94b70) @@ -0,0 +1,46 @@ +/* + * Copyright The WildFly Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package org.wildfly.extension.undertow.filters; + +import java.util.function.UnaryOperator; + +import org.jboss.as.clustering.controller.ChildResourceDefinition; +import org.jboss.as.clustering.controller.ResourceDescriptor; +import org.jboss.as.clustering.controller.RestartParentResourceRegistrar; +import org.jboss.as.controller.PathElement; +import org.jboss.as.controller.registry.ManagementResourceRegistration; +import org.wildfly.extension.undertow.Constants; +import org.wildfly.extension.undertow.UndertowExtension; + +/** + * Base class for affinity resources. + * + * @author Radoslav Husar + */ +public abstract class AffinityResourceDefinition extends ChildResourceDefinition { + + protected static PathElement pathElement(String value) { + return PathElement.pathElement(Constants.AFFINITY, value); + } + static final PathElement WILDCARD_PATH = pathElement(PathElement.WILDCARD_VALUE); + + private final UnaryOperator configurator; + + AffinityResourceDefinition(PathElement path, UnaryOperator configurator) { + super(path, UndertowExtension.getResolver(Constants.FILTER, ModClusterDefinition.PATH_ELEMENT.getKey(), path.getKey(), path.getValue())); + this.configurator = configurator; + } + + @Override + public ManagementResourceRegistration register(ManagementResourceRegistration parent) { + ManagementResourceRegistration registration = parent.registerSubModel(this); + + ResourceDescriptor descriptor = this.configurator.apply(new ResourceDescriptor(this.getResourceDescriptionResolver())); + new RestartParentResourceRegistrar(ModClusterServiceConfigurator::new, descriptor).register(registration); + + return registration; + } +} Fisheye: Tag 0c9c83107d623392869f43619926ea6d8ec5beab refers to a dead (removed) revision in file `3rdParty_sources/undertow/org/wildfly/extension/undertow/filters/BasicAuthHandler.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 0c9c83107d623392869f43619926ea6d8ec5beab refers to a dead (removed) revision in file `3rdParty_sources/undertow/org/wildfly/extension/undertow/filters/CustomFilterDefinition.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 0c9c83107d623392869f43619926ea6d8ec5beab refers to a dead (removed) revision in file `3rdParty_sources/undertow/org/wildfly/extension/undertow/filters/ErrorPageDefinition.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 0c9c83107d623392869f43619926ea6d8ec5beab refers to a dead (removed) revision in file `3rdParty_sources/undertow/org/wildfly/extension/undertow/filters/ExpressionFilterDefinition.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 0c9c83107d623392869f43619926ea6d8ec5beab refers to a dead (removed) revision in file `3rdParty_sources/undertow/org/wildfly/extension/undertow/filters/FailoverStrategy.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 0c9c83107d623392869f43619926ea6d8ec5beab refers to a dead (removed) revision in file `3rdParty_sources/undertow/org/wildfly/extension/undertow/filters/FilterAdd.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 0c9c83107d623392869f43619926ea6d8ec5beab refers to a dead (removed) revision in file `3rdParty_sources/undertow/org/wildfly/extension/undertow/filters/FilterDefinitions.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 0c9c83107d623392869f43619926ea6d8ec5beab refers to a dead (removed) revision in file `3rdParty_sources/undertow/org/wildfly/extension/undertow/filters/FilterRefDefinition.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 0c9c83107d623392869f43619926ea6d8ec5beab refers to a dead (removed) revision in file `3rdParty_sources/undertow/org/wildfly/extension/undertow/filters/FilterService.java'. Fisheye: No comparison available. Pass `N' to diff? Index: 3rdParty_sources/undertow/org/wildfly/extension/undertow/filters/GzipFilterDefinition.java =================================================================== diff -u --- 3rdParty_sources/undertow/org/wildfly/extension/undertow/filters/GzipFilterDefinition.java (revision 0) +++ 3rdParty_sources/undertow/org/wildfly/extension/undertow/filters/GzipFilterDefinition.java (revision e704ad812feb0fa447e5bd63332f753ac1a94b70) @@ -0,0 +1,38 @@ +/* + * Copyright The WildFly Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package org.wildfly.extension.undertow.filters; + +import io.undertow.predicate.Predicate; +import io.undertow.predicate.Predicates; +import io.undertow.server.HttpHandler; +import io.undertow.server.handlers.encoding.ContentEncodingRepository; +import io.undertow.server.handlers.encoding.EncodingHandler; +import io.undertow.server.handlers.encoding.GzipEncodingProvider; + +import org.jboss.as.controller.OperationContext; +import org.jboss.as.controller.PathElement; +import org.jboss.dmr.ModelNode; + +/** + * @author Tomaz Cerar (c) 2014 Red Hat Inc. + */ +public class GzipFilterDefinition extends SimpleFilterDefinition { + public static final PathElement PATH_ELEMENT = PathElement.pathElement("gzip"); + + GzipFilterDefinition() { + super(PATH_ELEMENT, GzipFilterDefinition::createHandlerWrapper); + } + + static PredicateHandlerWrapper createHandlerWrapper(OperationContext context, ModelNode model) { + return new PredicateHandlerWrapper() { + @Override + public HttpHandler wrap(Predicate predicate, HttpHandler next) { + ContentEncodingRepository repository = new ContentEncodingRepository().addEncodingHandler("gzip", new GzipEncodingProvider(), 50, predicate != null ? predicate : Predicates.truePredicate()); + return new EncodingHandler(next, repository); + } + }; + } +} \ No newline at end of file Fisheye: Tag 0c9c83107d623392869f43619926ea6d8ec5beab refers to a dead (removed) revision in file `3rdParty_sources/undertow/org/wildfly/extension/undertow/filters/ModClusterBalancerDefinition.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 0c9c83107d623392869f43619926ea6d8ec5beab refers to a dead (removed) revision in file `3rdParty_sources/undertow/org/wildfly/extension/undertow/filters/ModClusterContextDefinition.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 0c9c83107d623392869f43619926ea6d8ec5beab refers to a dead (removed) revision in file `3rdParty_sources/undertow/org/wildfly/extension/undertow/filters/ModClusterDefinition.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 0c9c83107d623392869f43619926ea6d8ec5beab refers to a dead (removed) revision in file `3rdParty_sources/undertow/org/wildfly/extension/undertow/filters/ModClusterLoadBalancingGroupDefinition.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 0c9c83107d623392869f43619926ea6d8ec5beab refers to a dead (removed) revision in file `3rdParty_sources/undertow/org/wildfly/extension/undertow/filters/ModClusterNodeDefinition.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 0c9c83107d623392869f43619926ea6d8ec5beab refers to a dead (removed) revision in file `3rdParty_sources/undertow/org/wildfly/extension/undertow/filters/ModClusterResource.java'. Fisheye: No comparison available. Pass `N' to diff? Index: 3rdParty_sources/undertow/org/wildfly/extension/undertow/filters/ModClusterServiceConfigurator.java =================================================================== diff -u --- 3rdParty_sources/undertow/org/wildfly/extension/undertow/filters/ModClusterServiceConfigurator.java (revision 0) +++ 3rdParty_sources/undertow/org/wildfly/extension/undertow/filters/ModClusterServiceConfigurator.java (revision e704ad812feb0fa447e5bd63332f753ac1a94b70) @@ -0,0 +1,236 @@ +/* + * Copyright The WildFly Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package org.wildfly.extension.undertow.filters; + +import static org.wildfly.extension.undertow.logging.UndertowLogger.ROOT_LOGGER; + +import java.io.IOException; +import java.net.InetAddress; +import java.util.Map; +import java.util.Set; +import java.util.function.Consumer; +import java.util.function.Function; +import java.util.function.Supplier; + +import javax.net.ssl.SSLContext; + +import io.undertow.UndertowOptions; +import io.undertow.client.UndertowClient; +import io.undertow.protocols.ssl.UndertowXnioSsl; +import io.undertow.server.handlers.proxy.RouteParsingStrategy; +import io.undertow.server.handlers.proxy.mod_cluster.MCMPConfig; +import io.undertow.server.handlers.proxy.mod_cluster.ModCluster; + +import org.jboss.as.clustering.controller.CommonUnaryRequirement; +import org.jboss.as.clustering.controller.ResourceServiceConfigurator; +import org.jboss.as.controller.OperationContext; +import org.jboss.as.controller.OperationFailedException; +import org.jboss.as.controller.PathAddress; +import org.jboss.as.controller.PathElement; +import org.jboss.as.controller.registry.Resource; +import org.jboss.as.network.SocketBinding; +import org.jboss.dmr.ModelNode; +import org.jboss.msc.service.ServiceBuilder; +import org.jboss.msc.service.ServiceName; +import org.jboss.msc.service.ServiceTarget; +import org.wildfly.clustering.service.CompositeDependency; +import org.wildfly.clustering.service.FunctionalService; +import org.wildfly.clustering.service.ServiceConfigurator; +import org.wildfly.clustering.service.ServiceSupplierDependency; +import org.wildfly.clustering.service.SupplierDependency; +import org.wildfly.extension.io.IOServices; +import org.wildfly.extension.undertow.logging.UndertowLogger; +import org.xnio.OptionMap; +import org.xnio.Options; +import org.xnio.XnioWorker; +import org.xnio.ssl.XnioSsl; + +/** + * Configures a service that provides both {@link ModCluster} and {@link MCMPConfig}. + * @author Paul Ferraro + */ +public class ModClusterServiceConfigurator extends ModClusterServiceNameProvider implements ResourceServiceConfigurator, Supplier>, Consumer> { + + private static final Map ROUTE_PARSING_STRATEGIES = Map.of( + NoAffinityResourceDefinition.PATH, RouteParsingStrategy.NONE, + SingleAffinityResourceDefinition.PATH, RouteParsingStrategy.SINGLE, + RankedAffinityResourceDefinition.PATH, RouteParsingStrategy.RANKED); + + private volatile SupplierDependency worker; + private volatile SupplierDependency managementBinding; + private volatile SupplierDependency advertiseBinding; + private volatile SupplierDependency sslContext; + + private volatile OptionMap clientOptions; + private volatile RouteParsingStrategy routeParsingStrategy; + private volatile String routeDelimiter; + private volatile long healthCheckInterval; + private volatile int maxRequestTime; + private volatile long brokenNodeTimeout; + private volatile int advertiseFrequency; + private volatile String advertisePath; + private volatile String advertiseProtocol; + private volatile String securityKey; + private volatile int maxConnections; + private volatile int cachedConnections; + private volatile int connectionIdleTimeout; + private volatile int requestQueueSize; + private volatile boolean useAlias; + private volatile int maxRetries; + private volatile FailoverStrategy failoverStrategy; + + ModClusterServiceConfigurator(PathAddress address) { + super(address); + } + + ServiceName getConfigServiceName() { + return this.getServiceName().append("config"); + } + + @Override + public ServiceConfigurator configure(OperationContext context, ModelNode model) throws OperationFailedException { + + if (ModClusterDefinition.SECURITY_REALM.resolveModelAttribute(context, model).isDefined()) { + ROOT_LOGGER.runtimeSecurityRealmUnsupported(); + } + + String sslContext = ModClusterDefinition.SSL_CONTEXT.resolveModelAttribute(context, model).asStringOrNull(); + this.sslContext = (sslContext != null) ? new ServiceSupplierDependency<>(CommonUnaryRequirement.SSL_CONTEXT.getServiceName(context, sslContext)) : null; + + OptionMap.Builder builder = OptionMap.builder(); + Integer packetSize = ModClusterDefinition.MAX_AJP_PACKET_SIZE.resolveModelAttribute(context, model).asIntOrNull(); + if (packetSize != null) { + builder.set(UndertowOptions.MAX_AJP_PACKET_SIZE, packetSize); + } + builder.set(UndertowOptions.ENABLE_HTTP2, ModClusterDefinition.ENABLE_HTTP2.resolveModelAttribute(context, model).asBoolean()); + ModClusterDefinition.HTTP2_ENABLE_PUSH.resolveOption(context, model, builder); + ModClusterDefinition.HTTP2_HEADER_TABLE_SIZE.resolveOption(context, model, builder); + ModClusterDefinition.HTTP2_INITIAL_WINDOW_SIZE.resolveOption(context, model, builder); + ModClusterDefinition.HTTP2_MAX_CONCURRENT_STREAMS.resolveOption(context, model, builder); + ModClusterDefinition.HTTP2_MAX_FRAME_SIZE.resolveOption(context, model, builder); + ModClusterDefinition.HTTP2_MAX_HEADER_LIST_SIZE.resolveOption(context, model, builder); + this.clientOptions = builder.getMap(); + + Resource resource = context.readResource(PathAddress.EMPTY_ADDRESS); + Set children = resource.getChildren(AffinityResourceDefinition.WILDCARD_PATH.getKey()); + if (children.size() != 1) { + throw new IllegalStateException(); + } + Resource.ResourceEntry entry = children.iterator().next(); + this.routeParsingStrategy = ROUTE_PARSING_STRATEGIES.get(entry.getPathElement()); + this.routeDelimiter = (this.routeParsingStrategy == RouteParsingStrategy.RANKED) ? RankedAffinityResourceDefinition.Attribute.DELIMITER.resolveModelAttribute(context, entry.getModel()).asString() : null; + + String managementBinding = ModClusterDefinition.MANAGEMENT_SOCKET_BINDING.resolveModelAttribute(context, model).asString(); + this.managementBinding = new ServiceSupplierDependency<>(CommonUnaryRequirement.SOCKET_BINDING.getServiceName(context, managementBinding)); + + String advertiseBinding = ModClusterDefinition.ADVERTISE_SOCKET_BINDING.resolveModelAttribute(context, model).asStringOrNull(); + this.advertiseBinding = (advertiseBinding != null) ? new ServiceSupplierDependency<>(CommonUnaryRequirement.SOCKET_BINDING.getServiceName(context, advertiseBinding)) : null; + + String worker = ModClusterDefinition.WORKER.resolveModelAttribute(context, model).asString(); + this.worker = new ServiceSupplierDependency<>(context.getCapabilityServiceName(IOServices.IO_WORKER_CAPABILITY_NAME, XnioWorker.class, worker)); + + this.healthCheckInterval = ModClusterDefinition.HEALTH_CHECK_INTERVAL.resolveModelAttribute(context, model).asInt(); + this.maxRequestTime = ModClusterDefinition.MAX_REQUEST_TIME.resolveModelAttribute(context, model).asInt(); + this.brokenNodeTimeout = ModClusterDefinition.BROKEN_NODE_TIMEOUT.resolveModelAttribute(context, model).asLong(); + this.advertiseFrequency = ModClusterDefinition.ADVERTISE_FREQUENCY.resolveModelAttribute(context, model).asInt(); + this.advertisePath = ModClusterDefinition.ADVERTISE_PATH.resolveModelAttribute(context, model).asString(); + this.advertiseProtocol = ModClusterDefinition.ADVERTISE_PROTOCOL.resolveModelAttribute(context, model).asString(); + this.securityKey = ModClusterDefinition.SECURITY_KEY.resolveModelAttribute(context, model).asStringOrNull(); + this.maxConnections = ModClusterDefinition.CONNECTIONS_PER_THREAD.resolveModelAttribute(context, model).asInt(); + this.cachedConnections = ModClusterDefinition.CACHED_CONNECTIONS_PER_THREAD.resolveModelAttribute(context, model).asInt(); + this.connectionIdleTimeout = ModClusterDefinition.CONNECTION_IDLE_TIMEOUT.resolveModelAttribute(context, model).asInt(); + this.requestQueueSize = ModClusterDefinition.REQUEST_QUEUE_SIZE.resolveModelAttribute(context, model).asInt(); + this.useAlias = ModClusterDefinition.USE_ALIAS.resolveModelAttribute(context, model).asBoolean(); + this.maxRetries = ModClusterDefinition.MAX_RETRIES.resolveModelAttribute(context, model).asInt(); + this.failoverStrategy = Enum.valueOf(FailoverStrategy.class, ModClusterDefinition.FAILOVER_STRATEGY.resolveModelAttribute(context, model).asString()); + return this; + } + + @Override + public ServiceBuilder build(ServiceTarget target) { + ServiceName name = this.getServiceName(); + ServiceBuilder builder = target.addService(name); + Consumer service = new CompositeDependency(this.worker, this.managementBinding, this.advertiseBinding, this.sslContext).register(builder).provides(name); + Consumer config = builder.provides(this.getConfigServiceName()); + Consumer> consumer = new Consumer<>() { + @Override + public void accept(Map.Entry entry) { + service.accept(entry.getKey()); + config.accept(entry.getValue()); + } + }; + return builder.setInstance(new FunctionalService<>(consumer, Function.identity(), this, this)); + } + + @Override + public void accept(Map.Entry entry) { + entry.getKey().stop(); + } + + @Override + public Map.Entry get() { + SSLContext sslContext = this.sslContext != null ? this.sslContext.get() : null; + XnioWorker worker = this.worker.get(); + XnioSsl xnioSsl = (sslContext != null) ? new UndertowXnioSsl(worker.getXnio(), OptionMap.builder().set(Options.USE_DIRECT_BUFFERS, true).getMap(), sslContext) : null; + + //TODO: SSL support for the client + ModCluster.Builder serviceBuilder = ModCluster.builder(worker, UndertowClient.getInstance(), xnioSsl) + .setMaxRetries(this.maxRetries) + .setClientOptions(this.clientOptions) + .setHealthCheckInterval(this.healthCheckInterval) + .setMaxRequestTime(this.maxRequestTime) + .setCacheConnections(this.cachedConnections) + .setQueueNewRequests(this.requestQueueSize > 0) + .setRequestQueueSize(this.requestQueueSize) + .setRemoveBrokenNodes(this.brokenNodeTimeout) + .setTtl(this.connectionIdleTimeout) + .setMaxConnections(this.maxConnections) + .setUseAlias(this.useAlias) + .setRouteParsingStrategy(this.routeParsingStrategy) + .setRankedAffinityDelimiter(this.routeDelimiter) + ; + + if (this.failoverStrategy == FailoverStrategy.DETERMINISTIC) { + serviceBuilder.setDeterministicFailover(true); + } + + ModCluster service = serviceBuilder.build(); + + MCMPConfig.Builder configBuilder = MCMPConfig.builder(); + if (this.advertiseBinding != null) { + SocketBinding advertiseBinding = this.advertiseBinding.get(); + InetAddress multicastAddress = advertiseBinding.getMulticastAddress(); + if (multicastAddress == null) { + throw UndertowLogger.ROOT_LOGGER.advertiseSocketBindingRequiresMulticastAddress(); + } + if (this.advertiseFrequency > 0) { + configBuilder.enableAdvertise() + .setAdvertiseAddress(advertiseBinding.getSocketAddress().getAddress().getHostAddress()) + .setAdvertiseGroup(multicastAddress.getHostAddress()) + .setAdvertisePort(advertiseBinding.getMulticastPort()) + .setAdvertiseFrequency(this.advertiseFrequency) + .setPath(this.advertisePath) + .setProtocol(this.advertiseProtocol) + .setSecurityKey(this.securityKey); + } + } + SocketBinding managementBinding = this.managementBinding.get(); + configBuilder.setManagementHost(managementBinding.getSocketAddress().getHostString()); + configBuilder.setManagementPort(managementBinding.getSocketAddress().getPort()); + + MCMPConfig config = configBuilder.build(); + + if (this.advertiseBinding != null && this.advertiseFrequency > 0) { + try { + service.advertise(config); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + service.start(); + return Map.entry(service, config); + } +} Index: 3rdParty_sources/undertow/org/wildfly/extension/undertow/filters/ModClusterServiceNameProvider.java =================================================================== diff -u --- 3rdParty_sources/undertow/org/wildfly/extension/undertow/filters/ModClusterServiceNameProvider.java (revision 0) +++ 3rdParty_sources/undertow/org/wildfly/extension/undertow/filters/ModClusterServiceNameProvider.java (revision e704ad812feb0fa447e5bd63332f753ac1a94b70) @@ -0,0 +1,21 @@ +/* + * Copyright The WildFly Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package org.wildfly.extension.undertow.filters; + +import org.jboss.as.controller.PathAddress; +import org.wildfly.clustering.service.SimpleServiceNameProvider; +import org.wildfly.extension.undertow.UndertowService; + +/** + * Provides the service name for {@link io.undertow.server.handlers.proxy.mod_cluster.ModCluster}. + * @author Paul Ferraro + */ +public class ModClusterServiceNameProvider extends SimpleServiceNameProvider { + + public ModClusterServiceNameProvider(PathAddress address) { + super(UndertowService.FILTER.append(address.getLastElement().getValue(), "service")); + } +} Index: 3rdParty_sources/undertow/org/wildfly/extension/undertow/filters/NoAffinityResourceDefinition.java =================================================================== diff -u --- 3rdParty_sources/undertow/org/wildfly/extension/undertow/filters/NoAffinityResourceDefinition.java (revision 0) +++ 3rdParty_sources/undertow/org/wildfly/extension/undertow/filters/NoAffinityResourceDefinition.java (revision e704ad812feb0fa447e5bd63332f753ac1a94b70) @@ -0,0 +1,25 @@ +/* + * Copyright The WildFly Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package org.wildfly.extension.undertow.filters; + +import java.util.function.UnaryOperator; + +import org.jboss.as.controller.PathElement; +import org.wildfly.extension.undertow.Constants; + +/** + * Affinity resource configuring no affinity handling. + * + * @author Radoslav Husar + */ +public class NoAffinityResourceDefinition extends AffinityResourceDefinition { + + public static final PathElement PATH = pathElement(Constants.NONE); + + public NoAffinityResourceDefinition() { + super(PATH, UnaryOperator.identity()); + } +} Index: 3rdParty_sources/undertow/org/wildfly/extension/undertow/filters/PredicateHandlerWrapper.java =================================================================== diff -u --- 3rdParty_sources/undertow/org/wildfly/extension/undertow/filters/PredicateHandlerWrapper.java (revision 0) +++ 3rdParty_sources/undertow/org/wildfly/extension/undertow/filters/PredicateHandlerWrapper.java (revision e704ad812feb0fa447e5bd63332f753ac1a94b70) @@ -0,0 +1,30 @@ +/* + * Copyright The WildFly Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package org.wildfly.extension.undertow.filters; + +import io.undertow.Handlers; +import io.undertow.predicate.Predicate; +import io.undertow.server.HandlerWrapper; +import io.undertow.server.HttpHandler; + +/** + * Like {@link io.undertow.server.HandlerWrapper}, but for filters. + * @author Paul Ferraro + */ +public interface PredicateHandlerWrapper { + + HttpHandler wrap(Predicate predicate, HttpHandler next); + + static PredicateHandlerWrapper filter(HandlerWrapper wrapper) { + return new PredicateHandlerWrapper() { + @Override + public HttpHandler wrap(Predicate predicate, HttpHandler next) { + HttpHandler handler = wrapper.wrap(next); + return (predicate != null) ? Handlers.predicate(predicate, handler, next) : handler; + } + }; + } +} Index: 3rdParty_sources/undertow/org/wildfly/extension/undertow/filters/PredicateHandlerWrapperFactory.java =================================================================== diff -u --- 3rdParty_sources/undertow/org/wildfly/extension/undertow/filters/PredicateHandlerWrapperFactory.java (revision 0) +++ 3rdParty_sources/undertow/org/wildfly/extension/undertow/filters/PredicateHandlerWrapperFactory.java (revision e704ad812feb0fa447e5bd63332f753ac1a94b70) @@ -0,0 +1,19 @@ +/* + * Copyright The WildFly Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package org.wildfly.extension.undertow.filters; + +import org.jboss.as.controller.OperationContext; +import org.jboss.as.controller.OperationFailedException; +import org.jboss.dmr.ModelNode; + +/** + * Factory for creating a {@link PredicateHandlerWrapper}. + * @author Paul Ferraro + */ +public interface PredicateHandlerWrapperFactory { + + PredicateHandlerWrapper createHandlerWrapper(OperationContext context, ModelNode model) throws OperationFailedException; +} Index: 3rdParty_sources/undertow/org/wildfly/extension/undertow/filters/RankedAffinityResourceDefinition.java =================================================================== diff -u --- 3rdParty_sources/undertow/org/wildfly/extension/undertow/filters/RankedAffinityResourceDefinition.java (revision 0) +++ 3rdParty_sources/undertow/org/wildfly/extension/undertow/filters/RankedAffinityResourceDefinition.java (revision e704ad812feb0fa447e5bd63332f753ac1a94b70) @@ -0,0 +1,48 @@ +/* + * Copyright The WildFly Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package org.wildfly.extension.undertow.filters; + +import org.jboss.as.clustering.controller.SimpleResourceDescriptorConfigurator; +import org.jboss.as.controller.AttributeDefinition; +import org.jboss.as.controller.PathElement; +import org.jboss.as.controller.SimpleAttributeDefinitionBuilder; +import org.jboss.dmr.ModelNode; +import org.jboss.dmr.ModelType; +import org.wildfly.extension.undertow.Constants; + +/** + * Affinity resource configuring ranked affinity handling which requires a delimiter to be specified. + * + * @author Radoslav Husar + */ +public class RankedAffinityResourceDefinition extends AffinityResourceDefinition { + + public static final PathElement PATH = pathElement(Constants.RANKED); + + public enum Attribute implements org.jboss.as.clustering.controller.Attribute { + DELIMITER(Constants.DELIMITER, ModelType.STRING, new ModelNode(".")), + ; + private final AttributeDefinition definition; + + Attribute(String name, ModelType type, ModelNode defaultValue) { + this.definition = new SimpleAttributeDefinitionBuilder(name, type) + .setRequired(defaultValue == null) + .setAllowExpression(true) + .setDefaultValue(defaultValue) + .setRestartAllServices() + .build(); + } + + @Override + public AttributeDefinition getDefinition() { + return this.definition; + } + } + + public RankedAffinityResourceDefinition() { + super(PATH, new SimpleResourceDescriptorConfigurator<>(Attribute.class)); + } +} Index: 3rdParty_sources/undertow/org/wildfly/extension/undertow/filters/RequestLimitHandlerDefinition.java =================================================================== diff -u --- 3rdParty_sources/undertow/org/wildfly/extension/undertow/filters/RequestLimitHandlerDefinition.java (revision 0) +++ 3rdParty_sources/undertow/org/wildfly/extension/undertow/filters/RequestLimitHandlerDefinition.java (revision e704ad812feb0fa447e5bd63332f753ac1a94b70) @@ -0,0 +1,67 @@ +/* + * Copyright The WildFly Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package org.wildfly.extension.undertow.filters; + +import java.util.Collection; +import java.util.List; + +import io.undertow.server.HandlerWrapper; +import io.undertow.server.HttpHandler; +import io.undertow.server.handlers.RequestLimitingHandler; + +import org.jboss.as.controller.AttributeDefinition; +import org.jboss.as.controller.OperationContext; +import org.jboss.as.controller.OperationFailedException; +import org.jboss.as.controller.PathElement; +import org.jboss.as.controller.SimpleAttributeDefinitionBuilder; +import org.jboss.as.controller.operations.validation.IntRangeValidator; +import org.jboss.dmr.ModelNode; +import org.jboss.dmr.ModelType; + +/** + * @author Tomaz Cerar (c) 2013 Red Hat Inc. + */ +public class RequestLimitHandlerDefinition extends SimpleFilterDefinition { + public static final PathElement PATH_ELEMENT = PathElement.pathElement("request-limit"); + + public static final AttributeDefinition MAX_CONCURRENT_REQUESTS = new SimpleAttributeDefinitionBuilder("max-concurrent-requests", ModelType.INT) + .setValidator(new IntRangeValidator(1, false, true)) + .setAllowExpression(true) + .setRequired(true) + .setRestartAllServices() + .build(); + + + public static final AttributeDefinition QUEUE_SIZE = new SimpleAttributeDefinitionBuilder("queue-size", ModelType.INT) + .setValidator(new IntRangeValidator(0, true, true)) + .setAllowExpression(true) + .setRequired(false) + .setDefaultValue(ModelNode.ZERO) + .setRestartAllServices() + .build(); + + public static final Collection ATTRIBUTES = List.of(MAX_CONCURRENT_REQUESTS, QUEUE_SIZE); + + RequestLimitHandlerDefinition() { + super(PATH_ELEMENT, RequestLimitHandlerDefinition::createHandlerWrapper); + } + + @Override + public Collection getAttributes() { + return ATTRIBUTES; + } + + static PredicateHandlerWrapper createHandlerWrapper(OperationContext context, ModelNode model) throws OperationFailedException { + int maxConcurrentRequests = MAX_CONCURRENT_REQUESTS.resolveModelAttribute(context, model).asInt(); + int queueSize = QUEUE_SIZE.resolveModelAttribute(context, model).asInt(); + return PredicateHandlerWrapper.filter(new HandlerWrapper() { + @Override + public HttpHandler wrap(HttpHandler next) { + return new RequestLimitingHandler(maxConcurrentRequests, queueSize, next); + } + }); + } +} Index: 3rdParty_sources/undertow/org/wildfly/extension/undertow/filters/ResponseHeaderFilterDefinition.java =================================================================== diff -u --- 3rdParty_sources/undertow/org/wildfly/extension/undertow/filters/ResponseHeaderFilterDefinition.java (revision 0) +++ 3rdParty_sources/undertow/org/wildfly/extension/undertow/filters/ResponseHeaderFilterDefinition.java (revision e704ad812feb0fa447e5bd63332f753ac1a94b70) @@ -0,0 +1,61 @@ +/* + * Copyright The WildFly Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package org.wildfly.extension.undertow.filters; + +import java.util.Collection; +import java.util.List; + +import io.undertow.server.HandlerWrapper; +import io.undertow.server.HttpHandler; +import io.undertow.server.handlers.SetHeaderHandler; + +import org.jboss.as.controller.AttributeDefinition; +import org.jboss.as.controller.OperationContext; +import org.jboss.as.controller.OperationFailedException; +import org.jboss.as.controller.PathElement; +import org.jboss.as.controller.SimpleAttributeDefinitionBuilder; +import org.jboss.dmr.ModelNode; +import org.jboss.dmr.ModelType; + +/** + * @author Tomaz Cerar (c) 2013 Red Hat Inc. + */ +public class ResponseHeaderFilterDefinition extends SimpleFilterDefinition { + public static final PathElement PATH_ELEMENT = PathElement.pathElement("response-header"); + + public static final AttributeDefinition NAME = new SimpleAttributeDefinitionBuilder("header-name", ModelType.STRING) + .setRequired(true) + .setAllowExpression(true) + .setRestartAllServices() + .build(); + public static final AttributeDefinition VALUE = new SimpleAttributeDefinitionBuilder("header-value", ModelType.STRING) + .setRequired(true) + .setAllowExpression(true) + .setRestartAllServices() + .build(); + + public static final Collection ATTRIBUTES = List.of(NAME, VALUE); + + ResponseHeaderFilterDefinition() { + super(PATH_ELEMENT, ResponseHeaderFilterDefinition::createHandlerWrapper); + } + + @Override + public Collection getAttributes() { + return ATTRIBUTES; + } + + static PredicateHandlerWrapper createHandlerWrapper(OperationContext context, ModelNode model) throws OperationFailedException { + String name = NAME.resolveModelAttribute(context, model).asString(); + String value = VALUE.resolveModelAttribute(context, model).asString(); + return PredicateHandlerWrapper.filter(new HandlerWrapper() { + @Override + public HttpHandler wrap(HttpHandler next) { + return new SetHeaderHandler(next, name, value); + } + }); + } +} Fisheye: Tag 0c9c83107d623392869f43619926ea6d8ec5beab refers to a dead (removed) revision in file `3rdParty_sources/undertow/org/wildfly/extension/undertow/filters/RewriteFilterDefinition.java'. Fisheye: No comparison available. Pass `N' to diff? Index: 3rdParty_sources/undertow/org/wildfly/extension/undertow/filters/SimpleFilterDefinition.java =================================================================== diff -u --- 3rdParty_sources/undertow/org/wildfly/extension/undertow/filters/SimpleFilterDefinition.java (revision 0) +++ 3rdParty_sources/undertow/org/wildfly/extension/undertow/filters/SimpleFilterDefinition.java (revision e704ad812feb0fa447e5bd63332f753ac1a94b70) @@ -0,0 +1,32 @@ +/* + * Copyright The WildFly Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package org.wildfly.extension.undertow.filters; + +import org.jboss.as.controller.PathElement; +import org.jboss.as.controller.ServiceRemoveStepHandler; +import org.jboss.as.controller.registry.ManagementResourceRegistration; +import org.jboss.as.controller.registry.OperationEntry; +import org.wildfly.extension.undertow.UndertowService; + +/** + * @author Tomaz Cerar (c) 2013 Red Hat Inc. + */ +abstract class SimpleFilterDefinition extends AbstractFilterDefinition { + + private final PredicateHandlerWrapperFactory factory; + + protected SimpleFilterDefinition(PathElement path, PredicateHandlerWrapperFactory factory) { + super(path); + this.factory = factory; + } + + @Override + public void registerOperations(ManagementResourceRegistration resourceRegistration) { + FilterAdd add = new FilterAdd(this.factory, this.getAttributes()); + registerAddOperation(resourceRegistration, add, OperationEntry.Flag.RESTART_RESOURCE_SERVICES); + registerRemoveOperation(resourceRegistration, new ServiceRemoveStepHandler(UndertowService.FILTER, add), OperationEntry.Flag.RESTART_RESOURCE_SERVICES); + } +} Index: 3rdParty_sources/undertow/org/wildfly/extension/undertow/filters/SingleAffinityResourceDefinition.java =================================================================== diff -u --- 3rdParty_sources/undertow/org/wildfly/extension/undertow/filters/SingleAffinityResourceDefinition.java (revision 0) +++ 3rdParty_sources/undertow/org/wildfly/extension/undertow/filters/SingleAffinityResourceDefinition.java (revision e704ad812feb0fa447e5bd63332f753ac1a94b70) @@ -0,0 +1,25 @@ +/* + * Copyright The WildFly Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package org.wildfly.extension.undertow.filters; + +import java.util.function.UnaryOperator; + +import org.jboss.as.controller.PathElement; +import org.wildfly.extension.undertow.Constants; + +/** + * Affinity resource configuring default - single - routing behavior. + * + * @author Radoslav Husar + */ +public class SingleAffinityResourceDefinition extends AffinityResourceDefinition { + + public static final PathElement PATH = pathElement(Constants.SINGLE); + + public SingleAffinityResourceDefinition() { + super(PATH, UnaryOperator.identity()); + } +} Index: 3rdParty_sources/undertow/org/wildfly/extension/undertow/handlers/FileHandlerDefinition.java =================================================================== diff -u --- 3rdParty_sources/undertow/org/wildfly/extension/undertow/handlers/FileHandlerDefinition.java (revision 0) +++ 3rdParty_sources/undertow/org/wildfly/extension/undertow/handlers/FileHandlerDefinition.java (revision e704ad812feb0fa447e5bd63332f753ac1a94b70) @@ -0,0 +1,113 @@ +/* + * Copyright The WildFly Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package org.wildfly.extension.undertow.handlers; + +import java.io.IOException; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.Collection; +import java.util.List; + +import io.undertow.server.HttpHandler; +import io.undertow.server.handlers.resource.PathResourceManager; +import io.undertow.server.handlers.resource.ResourceHandler; +import org.jboss.as.controller.AttributeDefinition; +import org.jboss.as.controller.OperationContext; +import org.jboss.as.controller.OperationFailedException; +import org.jboss.as.controller.PathElement; +import org.jboss.as.controller.SimpleAttributeDefinitionBuilder; +import org.jboss.as.controller.StringListAttributeDefinition; +import org.jboss.as.controller.registry.AttributeAccess; +import org.jboss.dmr.ModelNode; +import org.jboss.dmr.ModelType; +import org.wildfly.extension.undertow.Constants; +import org.wildfly.extension.undertow.logging.UndertowLogger; + +/** + * @author Tomaz Cerar (c) 2013 Red Hat Inc. + */ +public class FileHandlerDefinition extends HandlerDefinition { + public static final PathElement PATH_ELEMENT = PathElement.pathElement(Constants.FILE); + + /**/ + public static final AttributeDefinition PATH = new SimpleAttributeDefinitionBuilder(Constants.PATH, ModelType.STRING) + .setRequired(true) + .setAllowExpression(true) + .setFlags(AttributeAccess.Flag.RESTART_ALL_SERVICES) + .build(); + public static final AttributeDefinition CACHE_BUFFER_SIZE = new SimpleAttributeDefinitionBuilder("cache-buffer-size", ModelType.LONG) + .setRequired(false) + .setAllowExpression(true) + .setDefaultValue(new ModelNode(1024)) + .setFlags(AttributeAccess.Flag.RESTART_ALL_SERVICES) + .build(); + public static final AttributeDefinition CACHE_BUFFERS = new SimpleAttributeDefinitionBuilder("cache-buffers", ModelType.LONG) + .setRequired(false) + .setAllowExpression(true) + .setDefaultValue(new ModelNode(1024)) + .setFlags(AttributeAccess.Flag.RESTART_ALL_SERVICES) + .build(); + public static final AttributeDefinition DIRECTORY_LISTING = new SimpleAttributeDefinitionBuilder(Constants.DIRECTORY_LISTING, ModelType.BOOLEAN) + .setRequired(false) + .setAllowExpression(true) + .setDefaultValue(ModelNode.FALSE) + .setFlags(AttributeAccess.Flag.RESTART_ALL_SERVICES) + .build(); + + public static final AttributeDefinition FOLLOW_SYMLINK = new SimpleAttributeDefinitionBuilder("follow-symlink", ModelType.BOOLEAN) + .setRequired(false) + .setAllowExpression(true) + .setDefaultValue(ModelNode.FALSE) + .setFlags(AttributeAccess.Flag.RESTART_ALL_SERVICES) + .build(); + + public static final StringListAttributeDefinition SAFE_SYMLINK_PATHS = new StringListAttributeDefinition.Builder("safe-symlink-paths") + .setRequired(false) + .setAllowExpression(true) + .setFlags(AttributeAccess.Flag.RESTART_ALL_SERVICES) + .build(); + + public static final AttributeDefinition CASE_SENSITIVE = new SimpleAttributeDefinitionBuilder("case-sensitive", ModelType.BOOLEAN) + .setRequired(false) + .setAllowExpression(true) + .setDefaultValue(ModelNode.TRUE) + .setFlags(AttributeAccess.Flag.RESTART_ALL_SERVICES) + .build(); + + public static final Collection ATTRIBUTES = List.of(PATH, CACHE_BUFFER_SIZE, CACHE_BUFFERS, DIRECTORY_LISTING, FOLLOW_SYMLINK, CASE_SENSITIVE, SAFE_SYMLINK_PATHS); + + FileHandlerDefinition() { + super(PATH_ELEMENT, FileHandlerDefinition::createHandler); + } + + @Override + public Collection getAttributes() { + return ATTRIBUTES; + } + + static HttpHandler createHandler(final OperationContext context, ModelNode model) throws OperationFailedException { + final String path = PATH.resolveModelAttribute(context, model).asString(); + final boolean directoryListing = DIRECTORY_LISTING.resolveModelAttribute(context, model).asBoolean(); + final boolean followSymlink = FOLLOW_SYMLINK.resolveModelAttribute(context, model).asBoolean(); + final boolean caseSensitive = CASE_SENSITIVE.resolveModelAttribute(context, model).asBoolean(); + final long cacheBufferSize = CACHE_BUFFER_SIZE.resolveModelAttribute(context, model).asLong(); + final long cacheBuffers = CACHE_BUFFERS.resolveModelAttribute(context, model).asLong(); + final List safePaths = SAFE_SYMLINK_PATHS.unwrap(context, model); + final String[] paths = safePaths.toArray(new String[safePaths.size()]); + + UndertowLogger.ROOT_LOGGER.creatingFileHandler(path, directoryListing, followSymlink, caseSensitive, safePaths); + Path base; + try { + base = Paths.get(path).normalize().toRealPath(); //workaround for JBEAP-10231 + } catch (IOException e) { + throw new OperationFailedException(UndertowLogger.ROOT_LOGGER.unableAddHandlerForPath(path)); + } + PathResourceManager resourceManager = new PathResourceManager(base, cacheBufferSize * cacheBuffers, caseSensitive, followSymlink, paths); + ResourceHandler handler = new ResourceHandler(resourceManager); + handler.setDirectoryListingEnabled(directoryListing); + return handler; + } +} Fisheye: Tag 0c9c83107d623392869f43619926ea6d8ec5beab refers to a dead (removed) revision in file `3rdParty_sources/undertow/org/wildfly/extension/undertow/handlers/HandlerAdd.java'. Fisheye: No comparison available. Pass `N' to diff? Index: 3rdParty_sources/undertow/org/wildfly/extension/undertow/handlers/HandlerDefinition.java =================================================================== diff -u --- 3rdParty_sources/undertow/org/wildfly/extension/undertow/handlers/HandlerDefinition.java (revision 0) +++ 3rdParty_sources/undertow/org/wildfly/extension/undertow/handlers/HandlerDefinition.java (revision e704ad812feb0fa447e5bd63332f753ac1a94b70) @@ -0,0 +1,57 @@ +/* + * Copyright The WildFly Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package org.wildfly.extension.undertow.handlers; + +import java.util.List; + +import io.undertow.server.HttpHandler; + +import org.jboss.as.controller.PathElement; +import org.jboss.as.controller.PersistentResourceDefinition; +import org.jboss.as.controller.ServiceRemoveStepHandler; +import org.jboss.as.controller.SimpleResourceDefinition; +import org.jboss.as.controller.access.constraint.SensitivityClassification; +import org.jboss.as.controller.access.management.AccessConstraintDefinition; +import org.jboss.as.controller.access.management.SensitiveTargetAccessConstraintDefinition; +import org.jboss.as.controller.capability.RuntimeCapability; +import org.jboss.as.controller.registry.ManagementResourceRegistration; +import org.jboss.as.controller.registry.OperationEntry; +import org.wildfly.extension.undertow.Capabilities; +import org.wildfly.extension.undertow.Constants; +import org.wildfly.extension.undertow.UndertowExtension; +import org.wildfly.extension.undertow.UndertowService; + +/** + * @author Tomaz Cerar (c) 2013 Red Hat Inc. + */ +abstract class HandlerDefinition extends PersistentResourceDefinition { + + static final RuntimeCapability CAPABILITY = RuntimeCapability.Builder.of(Capabilities.CAPABILITY_HANDLER, true, HttpHandler.class).build(); + + private final HandlerFactory factory; + + protected HandlerDefinition(PathElement path, HandlerFactory factory) { + super(new SimpleResourceDefinition.Parameters(path, UndertowExtension.getResolver(Constants.HANDLER, path.getKey()))); + this.factory = factory; + } + + @Override + public void registerOperations(ManagementResourceRegistration resourceRegistration) { + HandlerAdd add = new HandlerAdd(this.factory, this.getAttributes()); + registerAddOperation(resourceRegistration, add, OperationEntry.Flag.RESTART_RESOURCE_SERVICES); + registerRemoveOperation(resourceRegistration, new ServiceRemoveStepHandler(UndertowService.HANDLER, add), OperationEntry.Flag.RESTART_RESOURCE_SERVICES); + } + + @Override + public void registerCapabilities(ManagementResourceRegistration resourceRegistration) { + resourceRegistration.registerCapability(CAPABILITY); + } + + @Override + public List getAccessConstraints() { + return List.of(new SensitiveTargetAccessConstraintDefinition(new SensitivityClassification(UndertowExtension.SUBSYSTEM_NAME, "undertow-handler", false, false, false))); + } +} Fisheye: Tag 0c9c83107d623392869f43619926ea6d8ec5beab refers to a dead (removed) revision in file `3rdParty_sources/undertow/org/wildfly/extension/undertow/handlers/HandlerDefinitions.java'. Fisheye: No comparison available. Pass `N' to diff? Index: 3rdParty_sources/undertow/org/wildfly/extension/undertow/handlers/HandlerFactory.java =================================================================== diff -u --- 3rdParty_sources/undertow/org/wildfly/extension/undertow/handlers/HandlerFactory.java (revision 0) +++ 3rdParty_sources/undertow/org/wildfly/extension/undertow/handlers/HandlerFactory.java (revision e704ad812feb0fa447e5bd63332f753ac1a94b70) @@ -0,0 +1,20 @@ +/* + * Copyright The WildFly Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package org.wildfly.extension.undertow.handlers; + +import io.undertow.server.HttpHandler; + +import org.jboss.as.controller.OperationContext; +import org.jboss.as.controller.OperationFailedException; +import org.jboss.dmr.ModelNode; + +/** + * Factory for creating {@link HttpHandler} implementations from a resource model + * @author Paul Ferraro + */ +public interface HandlerFactory { + HttpHandler createHandler(final OperationContext context, ModelNode model) throws OperationFailedException; +} Fisheye: Tag 0c9c83107d623392869f43619926ea6d8ec5beab refers to a dead (removed) revision in file `3rdParty_sources/undertow/org/wildfly/extension/undertow/handlers/HandlerService.java'. Fisheye: No comparison available. Pass `N' to diff? Index: 3rdParty_sources/undertow/org/wildfly/extension/undertow/handlers/ReverseProxyHandlerDefinition.java =================================================================== diff -u --- 3rdParty_sources/undertow/org/wildfly/extension/undertow/handlers/ReverseProxyHandlerDefinition.java (revision 0) +++ 3rdParty_sources/undertow/org/wildfly/extension/undertow/handlers/ReverseProxyHandlerDefinition.java (revision e704ad812feb0fa447e5bd63332f753ac1a94b70) @@ -0,0 +1,144 @@ +/* + * Copyright The WildFly Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package org.wildfly.extension.undertow.handlers; + +import io.undertow.server.HttpHandler; +import io.undertow.server.handlers.ResponseCodeHandler; +import io.undertow.server.handlers.proxy.LoadBalancingProxyClient; +import io.undertow.server.handlers.proxy.ProxyHandler; +import io.undertow.util.Headers; +import org.jboss.as.controller.AttributeDefinition; +import org.jboss.as.controller.OperationContext; +import org.jboss.as.controller.OperationFailedException; +import org.jboss.as.controller.PathElement; +import org.jboss.as.controller.PersistentResourceDefinition; +import org.jboss.as.controller.SimpleAttributeDefinitionBuilder; +import org.jboss.as.controller.client.helpers.MeasurementUnit; +import org.jboss.as.controller.registry.AttributeAccess; +import org.jboss.dmr.ModelNode; +import org.jboss.dmr.ModelType; +import org.wildfly.extension.undertow.Constants; + +import java.util.Collection; +import java.util.List; + +/** + * @author Stuart Douglas + */ +public class ReverseProxyHandlerDefinition extends HandlerDefinition { + public static final PathElement PATH_ELEMENT =PathElement.pathElement(Constants.REVERSE_PROXY); + + public static final AttributeDefinition PROBLEM_SERVER_RETRY = new SimpleAttributeDefinitionBuilder(Constants.PROBLEM_SERVER_RETRY, ModelType.INT) + .setRequired(false) + .setAllowExpression(true) + .setDefaultValue(new ModelNode(30)) + .setMeasurementUnit(MeasurementUnit.SECONDS) + .setFlags(AttributeAccess.Flag.RESTART_ALL_SERVICES) + .build(); + + public static final AttributeDefinition SESSION_COOKIE_NAMES = new SimpleAttributeDefinitionBuilder(Constants.SESSION_COOKIE_NAMES, ModelType.STRING) + .setRequired(false) + .setAllowExpression(true) + .setDefaultValue(new ModelNode("JSESSIONID")) + .setFlags(AttributeAccess.Flag.RESTART_ALL_SERVICES) + .build(); + public static final AttributeDefinition CONNECTIONS_PER_THREAD = new SimpleAttributeDefinitionBuilder(Constants.CONNECTIONS_PER_THREAD, ModelType.INT) + .setRequired(false) + .setAllowExpression(true) + .setDefaultValue(new ModelNode(40)) + .setFlags(AttributeAccess.Flag.RESTART_ALL_SERVICES) + .build(); + + public static final AttributeDefinition MAX_REQUEST_TIME = new SimpleAttributeDefinitionBuilder(Constants.MAX_REQUEST_TIME, ModelType.INT) + .setRequired(false) + .setAllowExpression(true) + .setDefaultValue(new ModelNode(-1)) + .setMeasurementUnit(MeasurementUnit.MILLISECONDS) + .setFlags(AttributeAccess.Flag.RESTART_ALL_SERVICES) + .build(); + + public static final AttributeDefinition REQUEST_QUEUE_SIZE = new SimpleAttributeDefinitionBuilder(Constants.REQUEST_QUEUE_SIZE, ModelType.INT) + .setRequired(false) + .setAllowExpression(true) + .setDefaultValue(new ModelNode(10)) + .setFlags(AttributeAccess.Flag.RESTART_ALL_SERVICES) + .build(); + + + public static final AttributeDefinition CACHED_CONNECTIONS_PER_THREAD = new SimpleAttributeDefinitionBuilder(Constants.CACHED_CONNECTIONS_PER_THREAD, ModelType.INT) + .setRequired(false) + .setAllowExpression(true) + .setDefaultValue(new ModelNode(5)) + .setFlags(AttributeAccess.Flag.RESTART_ALL_SERVICES) + .build(); + + public static final AttributeDefinition CONNECTION_IDLE_TIMEOUT = new SimpleAttributeDefinitionBuilder(Constants.CONNECTION_IDLE_TIMEOUT, ModelType.INT) + .setRequired(false) + .setAllowExpression(true) + .setDefaultValue(new ModelNode(60000)) + .setMeasurementUnit(MeasurementUnit.MILLISECONDS) + .setFlags(AttributeAccess.Flag.RESTART_ALL_SERVICES) + .build(); + + public static final AttributeDefinition MAX_RETRIES = new SimpleAttributeDefinitionBuilder(Constants.MAX_RETRIES, ModelType.INT) + .setRequired(false) + .setRestartAllServices() + .setAllowExpression(true) + .setDefaultValue(new ModelNode(1L)) + .build(); + + public static final Collection ATTRIBUTES = List.of(CONNECTIONS_PER_THREAD, SESSION_COOKIE_NAMES, PROBLEM_SERVER_RETRY, REQUEST_QUEUE_SIZE, MAX_REQUEST_TIME, CACHED_CONNECTIONS_PER_THREAD, CONNECTION_IDLE_TIMEOUT, MAX_RETRIES); + + ReverseProxyHandlerDefinition() { + super(PATH_ELEMENT, ReverseProxyHandlerDefinition::createHandler); + } + + @Override + public Collection getAttributes() { + return ATTRIBUTES; + } + + @Override + protected List getChildren() { + return List.of(new ReverseProxyHandlerHostDefinition()); + } + + static HttpHandler createHandler(final OperationContext context, ModelNode model) throws OperationFailedException { + + String sessionCookieNames = SESSION_COOKIE_NAMES.resolveModelAttribute(context, model).asString(); + int connectionsPerThread = CONNECTIONS_PER_THREAD.resolveModelAttribute(context, model).asInt(); + int problemServerRetry = PROBLEM_SERVER_RETRY.resolveModelAttribute(context, model).asInt(); + int maxTime = MAX_REQUEST_TIME.resolveModelAttribute(context, model).asInt(); + int requestQueueSize = REQUEST_QUEUE_SIZE.resolveModelAttribute(context, model).asInt(); + int cachedConnectionsPerThread = CACHED_CONNECTIONS_PER_THREAD.resolveModelAttribute(context, model).asInt(); + int connectionIdleTimeout = CONNECTION_IDLE_TIMEOUT.resolveModelAttribute(context, model).asInt(); + int maxRetries = MAX_RETRIES.resolveModelAttribute(context, model).asInt(); + + + final LoadBalancingProxyClient lb = new LoadBalancingProxyClient(exchange -> { + //we always create a new connection for upgrade requests + return exchange.getRequestHeaders().contains(Headers.UPGRADE); + }) + .setConnectionsPerThread(connectionsPerThread) + .setMaxQueueSize(requestQueueSize) + .setSoftMaxConnectionsPerThread(cachedConnectionsPerThread) + .setTtl(connectionIdleTimeout) + .setProblemServerRetry(problemServerRetry); + String[] sessionIds = sessionCookieNames.split(","); + for (String id : sessionIds) { + lb.addSessionCookieName(id); + } + + return ProxyHandler.builder() + .setProxyClient(lb) + .setMaxRequestTime(maxTime) + .setNext(ResponseCodeHandler.HANDLE_404) + .setRewriteHostHeader(false) + .setReuseXForwarded(false) + .setMaxConnectionRetries(maxRetries) + .build(); + } +} Index: 3rdParty_sources/undertow/org/wildfly/extension/undertow/handlers/ReverseProxyHandlerHostDefinition.java =================================================================== diff -u --- 3rdParty_sources/undertow/org/wildfly/extension/undertow/handlers/ReverseProxyHandlerHostDefinition.java (revision 0) +++ 3rdParty_sources/undertow/org/wildfly/extension/undertow/handlers/ReverseProxyHandlerHostDefinition.java (revision e704ad812feb0fa447e5bd63332f753ac1a94b70) @@ -0,0 +1,255 @@ +/* + * Copyright The WildFly Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package org.wildfly.extension.undertow.handlers; + +import static org.wildfly.extension.undertow.Capabilities.REF_OUTBOUND_SOCKET; +import static org.wildfly.extension.undertow.Capabilities.REF_SSL_CONTEXT; +import static org.wildfly.extension.undertow.Capabilities.CAPABILITY_REVERSE_PROXY_HANDLER_HOST; +import static org.wildfly.extension.undertow.logging.UndertowLogger.ROOT_LOGGER; + +import java.net.URI; +import java.net.URISyntaxException; +import java.util.Collection; +import java.util.List; +import java.util.function.Consumer; +import java.util.function.Supplier; +import javax.net.ssl.SSLContext; + +import io.undertow.UndertowOptions; +import io.undertow.protocols.ssl.UndertowXnioSsl; +import io.undertow.server.HttpHandler; +import io.undertow.server.handlers.proxy.LoadBalancingProxyClient; +import io.undertow.server.handlers.proxy.ProxyHandler; +import org.jboss.as.controller.AbstractAddStepHandler; +import org.jboss.as.controller.AttributeDefinition; +import org.jboss.as.controller.CapabilityServiceBuilder; +import org.jboss.as.controller.OperationContext; +import org.jboss.as.controller.OperationFailedException; +import org.jboss.as.controller.PathAddress; +import org.jboss.as.controller.PathElement; +import org.jboss.as.controller.PersistentResourceDefinition; +import org.jboss.as.controller.ServiceRemoveStepHandler; +import org.jboss.as.controller.SimpleAttributeDefinition; +import org.jboss.as.controller.SimpleAttributeDefinitionBuilder; +import org.jboss.as.controller.SimpleResourceDefinition; +import org.jboss.as.controller.access.management.SensitiveTargetAccessConstraintDefinition; +import org.jboss.as.controller.capability.DynamicNameMappers; +import org.jboss.as.controller.capability.RuntimeCapability; +import org.jboss.as.controller.operations.validation.StringLengthValidator; +import org.jboss.as.controller.registry.ManagementResourceRegistration; +import org.jboss.as.controller.registry.OperationEntry; +import org.jboss.as.network.OutboundSocketBinding; +import org.jboss.dmr.ModelNode; +import org.jboss.dmr.ModelType; +import org.jboss.msc.Service; +import org.jboss.msc.service.ServiceName; +import org.jboss.msc.service.StartContext; +import org.jboss.msc.service.StartException; +import org.jboss.msc.service.StopContext; +import org.wildfly.extension.undertow.Capabilities; +import org.wildfly.extension.undertow.Constants; +import org.wildfly.extension.undertow.UndertowExtension; +import org.wildfly.extension.undertow.UndertowSubsystemModel; +import org.wildfly.extension.undertow.deployment.GlobalRequestControllerHandler; +import org.xnio.OptionMap; +import org.xnio.Options; +import org.xnio.Xnio; +import org.xnio.ssl.XnioSsl; + +/** + * @author Stuart Douglas + * @author Tomaz Cerar + * @author Richard Opalka + */ +public class ReverseProxyHandlerHostDefinition extends PersistentResourceDefinition { + public static final PathElement PATH_ELEMENT = PathElement.pathElement(Constants.HOST); + private static final RuntimeCapability REVERSE_PROXY_HOST_RUNTIME_CAPABILITY = + RuntimeCapability.Builder.of(CAPABILITY_REVERSE_PROXY_HANDLER_HOST, true, ReverseProxyHostService.class) + .setDynamicNameMapper(DynamicNameMappers.PARENT) + .build(); + + public static final SimpleAttributeDefinition OUTBOUND_SOCKET_BINDING = new SimpleAttributeDefinitionBuilder("outbound-socket-binding", ModelType.STRING) + .setRequired(true) + .setValidator(new StringLengthValidator(1, false)) + .setAllowExpression(true) + .setRestartAllServices() + .addAccessConstraint(SensitiveTargetAccessConstraintDefinition.SOCKET_BINDING_REF) + .setCapabilityReference(REF_OUTBOUND_SOCKET) + .build(); + + public static final AttributeDefinition SCHEME = new SimpleAttributeDefinitionBuilder("scheme", ModelType.STRING) + .setRequired(false) + .setAllowExpression(true) + .setDefaultValue(new ModelNode("http")) + .setRestartAllServices() + .build(); + + public static final AttributeDefinition PATH = new SimpleAttributeDefinitionBuilder("path", ModelType.STRING) + .setRequired(false) + .setAllowExpression(true) + .setDefaultValue(new ModelNode("/")) + .setRestartAllServices() + .build(); + + public static final AttributeDefinition INSTANCE_ID = new SimpleAttributeDefinitionBuilder(Constants.INSTANCE_ID, ModelType.STRING) + .setRequired(false) + .setAllowExpression(true) + .setRestartAllServices() + .build(); + + public static final SimpleAttributeDefinition SSL_CONTEXT = new SimpleAttributeDefinitionBuilder(Constants.SSL_CONTEXT, ModelType.STRING, true) + .setAlternatives(Constants.SECURITY_REALM) + .setCapabilityReference(REF_SSL_CONTEXT) + .setRestartAllServices() + .setValidator(new StringLengthValidator(1)) + .setAccessConstraints(SensitiveTargetAccessConstraintDefinition.SSL_REF) + .build(); + + public static final SimpleAttributeDefinition SECURITY_REALM = new SimpleAttributeDefinitionBuilder(Constants.SECURITY_REALM, ModelType.STRING) + .setAlternatives(Constants.SSL_CONTEXT) + .setRequired(false) + .setRestartAllServices() + .setValidator(new StringLengthValidator(1)) + .setAccessConstraints(SensitiveTargetAccessConstraintDefinition.SECURITY_REALM_REF) + .setDeprecated(UndertowSubsystemModel.VERSION_12_0_0.getVersion()) + .build(); + + public static final SimpleAttributeDefinition ENABLE_HTTP2 = new SimpleAttributeDefinitionBuilder(Constants.ENABLE_HTTP2, ModelType.BOOLEAN) + .setRequired(false) + .setDefaultValue(ModelNode.FALSE) + .setRestartAllServices() + .build(); + + public static final Collection ATTRIBUTES = List.of(OUTBOUND_SOCKET_BINDING, SCHEME, INSTANCE_ID, PATH, SSL_CONTEXT, SECURITY_REALM, ENABLE_HTTP2); + + ReverseProxyHandlerHostDefinition() { + super(new SimpleResourceDefinition.Parameters(PATH_ELEMENT, UndertowExtension.getResolver(Constants.HANDLER, Constants.REVERSE_PROXY, PATH_ELEMENT.getKey())) + .setCapabilities(REVERSE_PROXY_HOST_RUNTIME_CAPABILITY) + ); + } + + @Override + public Collection getAttributes() { + return ATTRIBUTES; + } + + + @Override + public void registerOperations(ManagementResourceRegistration resourceRegistration) { + super.registerOperations(resourceRegistration); + ReverseProxyHostAdd add = new ReverseProxyHostAdd(this.getAttributes()); + registerAddOperation(resourceRegistration, add, OperationEntry.Flag.RESTART_RESOURCE_SERVICES); + registerRemoveOperation(resourceRegistration, new ServiceRemoveStepHandler(add) { + @Override + protected ServiceName serviceName(String name, final PathAddress address) { + return REVERSE_PROXY_HOST_RUNTIME_CAPABILITY.getCapabilityServiceName(address); + } + }, OperationEntry.Flag.RESTART_RESOURCE_SERVICES); + } + + private static class ReverseProxyHostAdd extends AbstractAddStepHandler { + public ReverseProxyHostAdd(Collection attributes) { + super(attributes); + } + + @Override + protected void performRuntime(OperationContext context, ModelNode operation, ModelNode model) throws OperationFailedException { + final PathAddress address = context.getCurrentAddress(); + final String proxyName = address.getElement(address.size() - 2).getValue(); + final String socketBinding = OUTBOUND_SOCKET_BINDING.resolveModelAttribute(context, model).asString(); + final String scheme = SCHEME.resolveModelAttribute(context, model).asString(); + final String path = PATH.resolveModelAttribute(context, model).asString(); + final boolean enableHttp2 = ENABLE_HTTP2.resolveModelAttribute(context, model).asBoolean(); + final String jvmRoute; + final ModelNode securityRealm = SECURITY_REALM.resolveModelAttribute(context, model); + if (securityRealm.isDefined()) { + throw ROOT_LOGGER.runtimeSecurityRealmUnsupported(); + } + final ModelNode sslContext = SSL_CONTEXT.resolveModelAttribute(context, model); + if (model.hasDefined(Constants.INSTANCE_ID)) { + jvmRoute = INSTANCE_ID.resolveModelAttribute(context, model).asString(); + } else { + jvmRoute = null; + } + final CapabilityServiceBuilder sb = context.getCapabilityServiceTarget().addCapability(REVERSE_PROXY_HOST_RUNTIME_CAPABILITY); + final Consumer serviceConsumer = sb.provides(REVERSE_PROXY_HOST_RUNTIME_CAPABILITY); + final Supplier phSupplier = sb.requiresCapability(Capabilities.CAPABILITY_HANDLER, HttpHandler.class, proxyName); + final Supplier sbSupplier = sb.requiresCapability(Capabilities.REF_OUTBOUND_SOCKET, OutboundSocketBinding.class, socketBinding); + final Supplier scSupplier = sslContext.isDefined() ? sb.requiresCapability(REF_SSL_CONTEXT, SSLContext.class, sslContext.asString()) : null; + sb.setInstance(new ReverseProxyHostService(serviceConsumer, phSupplier, sbSupplier, scSupplier, scheme, jvmRoute, path, enableHttp2)); + sb.install(); + } + } + + private static final class ReverseProxyHostService implements Service { + + private final Consumer serviceConsumer; + private final Supplier proxyHandler; + private final Supplier socketBinding; + private final Supplier sslContext; + private final String instanceId; + private final String scheme; + private final String path; + private final boolean enableHttp2; + + private ReverseProxyHostService(final Consumer serviceConsumer, + final Supplier proxyHandler, + final Supplier socketBinding, + final Supplier sslContext, + String scheme, String instanceId, String path, boolean enableHttp2) { + this.serviceConsumer = serviceConsumer; + this.proxyHandler = proxyHandler; + this.socketBinding = socketBinding; + this.sslContext = sslContext; + this.instanceId = instanceId; + this.scheme = scheme; + this.path = path; + this.enableHttp2 = enableHttp2; + } + private URI getUri() throws URISyntaxException { + OutboundSocketBinding binding = socketBinding.get(); + return new URI(scheme, null, binding.getUnresolvedDestinationAddress(), binding.getDestinationPort(), path, null, null); + } + + @Override + public void start(final StartContext startContext) throws StartException { + //todo: this is a bit of a hack, as the proxy handler may be wrapped by a request controller handler for graceful shutdown + ProxyHandler proxyHandler = (ProxyHandler) (this.proxyHandler.get() instanceof GlobalRequestControllerHandler ? ((GlobalRequestControllerHandler)this.proxyHandler.get()).getNext() : this.proxyHandler.get()); + + final LoadBalancingProxyClient client = (LoadBalancingProxyClient) proxyHandler.getProxyClient(); + try { + SSLContext sslContext = this.sslContext != null ? this.sslContext.get() : null; + + if (sslContext == null) { + client.addHost(getUri(), instanceId, null, OptionMap.create(UndertowOptions.ENABLE_HTTP2, enableHttp2)); + } else { + OptionMap.Builder builder = OptionMap.builder(); + builder.set(Options.USE_DIRECT_BUFFERS, true); + OptionMap combined = builder.getMap(); + + XnioSsl xnioSsl = new UndertowXnioSsl(Xnio.getInstance(), combined, sslContext); + client.addHost(getUri(), instanceId, xnioSsl, OptionMap.create(UndertowOptions.ENABLE_HTTP2, enableHttp2)); + } + serviceConsumer.accept(this); + } catch (URISyntaxException e) { + throw new StartException(e); + } + } + + @Override + public void stop(final StopContext stopContext) { + serviceConsumer.accept(null); + ProxyHandler proxyHandler = (ProxyHandler) (this.proxyHandler.get() instanceof GlobalRequestControllerHandler ? ((GlobalRequestControllerHandler)this.proxyHandler.get()).getNext() : this.proxyHandler.get()); + final LoadBalancingProxyClient client = (LoadBalancingProxyClient) proxyHandler.getProxyClient(); + try { + client.removeHost(getUri()); + } catch (URISyntaxException e) { + throw new RuntimeException(e); //impossible + } + } + } + +} Fisheye: Tag 0c9c83107d623392869f43619926ea6d8ec5beab refers to a dead (removed) revision in file `3rdParty_sources/undertow/org/wildfly/extension/undertow/logging/UndertowLogger.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 0c9c83107d623392869f43619926ea6d8ec5beab refers to a dead (removed) revision in file `3rdParty_sources/undertow/org/wildfly/extension/undertow/security/jacc/JACCAuthorizationManager.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 0c9c83107d623392869f43619926ea6d8ec5beab refers to a dead (removed) revision in file `3rdParty_sources/undertow/org/wildfly/extension/undertow/security/jacc/JACCContextIdHandler.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 0c9c83107d623392869f43619926ea6d8ec5beab refers to a dead (removed) revision in file `3rdParty_sources/undertow/org/wildfly/extension/undertow/security/jacc/WarJACCDeployer.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 0c9c83107d623392869f43619926ea6d8ec5beab refers to a dead (removed) revision in file `3rdParty_sources/undertow/org/wildfly/extension/undertow/security/jacc/WarJACCService.java'. Fisheye: No comparison available. Pass `N' to diff? Index: 3rdParty_sources/undertow/org/wildfly/extension/undertow/session/AffinitySessionConfig.java =================================================================== diff -u --- 3rdParty_sources/undertow/org/wildfly/extension/undertow/session/AffinitySessionConfig.java (revision 0) +++ 3rdParty_sources/undertow/org/wildfly/extension/undertow/session/AffinitySessionConfig.java (revision e704ad812feb0fa447e5bd63332f753ac1a94b70) @@ -0,0 +1,95 @@ +/* + * Copyright The WildFly Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package org.wildfly.extension.undertow.session; + +import java.util.Map; + +import io.undertow.server.HttpServerExchange; +import io.undertow.server.session.SessionConfig; +import org.jboss.as.web.session.AffinityLocator; + +/** + * Decorates {@link SessionConfig} with affinity encoding into a separate a cookie. + * + * @author Radoslav Husar + */ +public class AffinitySessionConfig implements SessionConfig { + + private final SessionConfig sessionConfig; + private final Map affinityConfigMap; + private final AffinityLocator locator; + + public AffinitySessionConfig(SessionConfig sessionConfig, Map affinityConfigMap, AffinityLocator locator) { + this.sessionConfig = sessionConfig; + this.affinityConfigMap = affinityConfigMap; + this.locator = locator; + } + + @Override + public void setSessionId(HttpServerExchange exchange, String sessionId) { + String requestedSessionId = this.sessionConfig.findSessionId(exchange); + if (!sessionId.equals(requestedSessionId)) { + this.sessionConfig.setSessionId(exchange, sessionId); + } + + String affinity = this.locator.locate(sessionId); + if (affinity != null) { + // Always write affinity for every request if using cookies!! + this.sessionConfigInUse(exchange).setSessionId(exchange, affinity); + } + } + + @Override + public void clearSession(HttpServerExchange exchange, String sessionId) { + this.sessionConfig.clearSession(exchange, sessionId); + + SessionConfig sessionConfigInUse = sessionConfigInUse(exchange); + String existingAffinity = sessionConfigInUse.findSessionId(exchange); + if (existingAffinity != null) { + sessionConfigInUse.clearSession(exchange, existingAffinity); + } + } + + @Override + public String findSessionId(HttpServerExchange exchange) { + return this.sessionConfig.findSessionId(exchange); + } + + @Override + public SessionCookieSource sessionCookieSource(HttpServerExchange exchange) { + return this.sessionConfig.sessionCookieSource(exchange); + } + + @Override + public String rewriteUrl(String originalUrl, String sessionId) { + String url = this.sessionConfig.rewriteUrl(originalUrl, sessionId); + String route = this.locator.locate(sessionId); + + if (route != null) { + if (url.equals(originalUrl)) { + // Rewritten URLs is unchanged -> use SessionCookieSource.COOKIE + return this.affinityConfigMap.get(SessionCookieSource.COOKIE).rewriteUrl(url, route); + } else { + // Rewritten URL is different from the original URL -> use SessionCookieSource.URL + return this.affinityConfigMap.get(SessionCookieSource.URL).rewriteUrl(url, route); + } + } + + return url; + } + + private SessionConfig sessionConfigInUse(HttpServerExchange exchange) { + switch (sessionConfig.sessionCookieSource(exchange)) { + case URL: { + return this.affinityConfigMap.get(SessionCookieSource.URL); + } + default: { + return this.affinityConfigMap.get(SessionCookieSource.COOKIE); + } + } + } + +} \ No newline at end of file Index: 3rdParty_sources/undertow/org/wildfly/extension/undertow/session/AffinitySessionConfigWrapper.java =================================================================== diff -u --- 3rdParty_sources/undertow/org/wildfly/extension/undertow/session/AffinitySessionConfigWrapper.java (revision 0) +++ 3rdParty_sources/undertow/org/wildfly/extension/undertow/session/AffinitySessionConfigWrapper.java (revision e704ad812feb0fa447e5bd63332f753ac1a94b70) @@ -0,0 +1,66 @@ +/* + * Copyright The WildFly Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package org.wildfly.extension.undertow.session; + +import java.util.EnumMap; +import java.util.Locale; +import java.util.Map; + +import io.undertow.server.session.PathParameterSessionConfig; +import io.undertow.server.session.SessionConfig; +import io.undertow.server.session.SessionCookieConfig; +import io.undertow.servlet.api.Deployment; +import io.undertow.servlet.api.SessionConfigWrapper; +import org.jboss.as.web.session.AffinityLocator; +import org.wildfly.extension.undertow.CookieConfig; + +/** + * Adds affinity locator handling to a {@link SessionConfig}. + * + * @author Radoslav Husar + */ +public class AffinitySessionConfigWrapper implements SessionConfigWrapper { + + private final Map affinityConfigMap = new EnumMap<>(SessionConfig.SessionCookieSource.class); + private final AffinityLocator locator; + + public AffinitySessionConfigWrapper(CookieConfig config, AffinityLocator locator) { + this.locator = locator; + + // Setup SessionCookieSource->SessionConfig mapping: + + // SessionConfig.SessionCookieSource.COOKIE + SessionCookieConfig cookieSessionConfig = new SessionCookieConfig(); + + cookieSessionConfig.setCookieName(config.getName()); + if (config.getDomain() != null) { + cookieSessionConfig.setDomain(config.getDomain()); + } + if (config.getHttpOnly() != null) { + cookieSessionConfig.setHttpOnly(config.getHttpOnly()); + } + if (config.getSecure() != null) { + cookieSessionConfig.setSecure(config.getSecure()); + } + if (config.getMaxAge() != null) { + cookieSessionConfig.setMaxAge(config.getMaxAge()); + } + + affinityConfigMap.put(SessionConfig.SessionCookieSource.COOKIE, cookieSessionConfig); + + // SessionConfig.SessionCookieSource.URL + + // In this case use the cookie name as the path parameter + String pathParameterName = config.getName().toLowerCase(Locale.ENGLISH); + PathParameterSessionConfig pathParameterSessionConfig = new PathParameterSessionConfig(pathParameterName); + affinityConfigMap.put(SessionConfig.SessionCookieSource.URL, pathParameterSessionConfig); + } + + @Override + public SessionConfig wrap(SessionConfig sessionConfig, Deployment deployment) { + return new AffinitySessionConfig(sessionConfig, this.affinityConfigMap, this.locator); + } +} Fisheye: Tag 0c9c83107d623392869f43619926ea6d8ec5beab refers to a dead (removed) revision in file `3rdParty_sources/undertow/org/wildfly/extension/undertow/session/CodecSessionConfig.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 0c9c83107d623392869f43619926ea6d8ec5beab refers to a dead (removed) revision in file `3rdParty_sources/undertow/org/wildfly/extension/undertow/session/CodecSessionConfigWrapper.java'. Fisheye: No comparison available. Pass `N' to diff? Index: 3rdParty_sources/undertow/org/wildfly/extension/undertow/session/DistributableServerRuntimeHandler.java =================================================================== diff -u --- 3rdParty_sources/undertow/org/wildfly/extension/undertow/session/DistributableServerRuntimeHandler.java (revision 0) +++ 3rdParty_sources/undertow/org/wildfly/extension/undertow/session/DistributableServerRuntimeHandler.java (revision e704ad812feb0fa447e5bd63332f753ac1a94b70) @@ -0,0 +1,16 @@ +/* + * Copyright The WildFly Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package org.wildfly.extension.undertow.session; + +import org.jboss.as.controller.OperationContext; + +/** + * Installs any runtime services necessary to support distributable web applications on a given server. + * @author Paul Ferraro + */ +public interface DistributableServerRuntimeHandler { + void execute(OperationContext context, String serverName); +} Index: 3rdParty_sources/undertow/org/wildfly/extension/undertow/session/NonDistributableSessionManagementProvider.java =================================================================== diff -u --- 3rdParty_sources/undertow/org/wildfly/extension/undertow/session/NonDistributableSessionManagementProvider.java (revision 0) +++ 3rdParty_sources/undertow/org/wildfly/extension/undertow/session/NonDistributableSessionManagementProvider.java (revision e704ad812feb0fa447e5bd63332f753ac1a94b70) @@ -0,0 +1,43 @@ +/* + * Copyright The WildFly Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package org.wildfly.extension.undertow.session; + +import java.util.List; +import java.util.function.Function; + +import org.jboss.as.clustering.controller.CapabilityServiceConfigurator; +import org.jboss.msc.service.ServiceName; +import org.wildfly.clustering.service.ServiceSupplierDependency; +import org.wildfly.clustering.web.container.SessionManagementProvider; +import org.wildfly.clustering.web.container.SessionManagerFactoryConfiguration; +import org.wildfly.clustering.web.container.WebDeploymentConfiguration; + +import io.undertow.servlet.api.SessionManagerFactory; + +/** + * {@link SessionManagementProvider} for non-distributed web deployments. + * @author Paul Ferraro + */ +public class NonDistributableSessionManagementProvider implements SessionManagementProvider { + private final Function factory; + + public NonDistributableSessionManagementProvider(Function factory) { + this.factory = factory; + } + + @Override + public Iterable getSessionManagerFactoryServiceConfigurators(ServiceName name, SessionManagerFactoryConfiguration configuration) { + return List.of(new SessionManagerFactoryServiceConfigurator(name, () -> this.factory.apply(configuration))); + } + + @Override + public Iterable getSessionAffinityServiceConfigurators(ServiceName name, WebDeploymentConfiguration configuration) { + CapabilityServiceConfigurator codecConfigurator = new SimpleSessionIdentifierCodecServiceConfigurator(name.append("codec"), configuration.getServerName()); + CapabilityServiceConfigurator locatorConfigurator = new SimpleAffinityLocatorServiceConfigurator(name.append("locator"), configuration.getServerName()); + CapabilityServiceConfigurator wrapperFactoryConfigurator = new SessionConfigWrapperFactoryServiceConfigurator(name, new ServiceSupplierDependency<>(codecConfigurator), new ServiceSupplierDependency<>(locatorConfigurator)); + return List.of(codecConfigurator, locatorConfigurator, wrapperFactoryConfigurator); + } +} Index: 3rdParty_sources/undertow/org/wildfly/extension/undertow/session/SessionConfigWrapperFactoryServiceConfigurator.java =================================================================== diff -u --- 3rdParty_sources/undertow/org/wildfly/extension/undertow/session/SessionConfigWrapperFactoryServiceConfigurator.java (revision 0) +++ 3rdParty_sources/undertow/org/wildfly/extension/undertow/session/SessionConfigWrapperFactoryServiceConfigurator.java (revision e704ad812feb0fa447e5bd63332f753ac1a94b70) @@ -0,0 +1,52 @@ +/* + * Copyright The WildFly Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package org.wildfly.extension.undertow.session; + +import java.util.function.Consumer; +import java.util.function.Function; + +import io.undertow.servlet.api.SessionConfigWrapper; + +import org.jboss.as.clustering.controller.CapabilityServiceConfigurator; +import org.jboss.as.web.session.AffinityLocator; +import org.jboss.as.web.session.SessionIdentifierCodec; +import org.jboss.msc.Service; +import org.jboss.msc.service.ServiceBuilder; +import org.jboss.msc.service.ServiceName; +import org.jboss.msc.service.ServiceTarget; +import org.wildfly.clustering.service.CompositeDependency; +import org.wildfly.clustering.service.SimpleServiceNameProvider; +import org.wildfly.clustering.service.SupplierDependency; +import org.wildfly.extension.undertow.CookieConfig; + +/** + * Configures a service that provides a {@link SessionConfigWrapper} factory. + * @author Paul Ferraro + */ +public class SessionConfigWrapperFactoryServiceConfigurator extends SimpleServiceNameProvider implements CapabilityServiceConfigurator, Function { + + private final SupplierDependency codecDependency; + private final SupplierDependency locatorDependency; + + public SessionConfigWrapperFactoryServiceConfigurator(ServiceName name, SupplierDependency codecDependency, SupplierDependency locatorDependency) { + super(name); + this.codecDependency = codecDependency; + this.locatorDependency = locatorDependency; + } + + @Override + public ServiceBuilder build(ServiceTarget target) { + ServiceName name = this.getServiceName(); + ServiceBuilder builder = target.addService(name); + Consumer> function = new CompositeDependency(this.codecDependency, this.locatorDependency).register(builder).provides(name); + return builder.setInstance(Service.newInstance(function, this)); + } + + @Override + public SessionConfigWrapper apply(CookieConfig config) { + return (config != null) ? new AffinitySessionConfigWrapper(config, this.locatorDependency.get()) : new CodecSessionConfigWrapper(this.codecDependency.get()); + } +} Index: 3rdParty_sources/undertow/org/wildfly/extension/undertow/session/SessionManagementProviderFactory.java =================================================================== diff -u --- 3rdParty_sources/undertow/org/wildfly/extension/undertow/session/SessionManagementProviderFactory.java (revision 0) +++ 3rdParty_sources/undertow/org/wildfly/extension/undertow/session/SessionManagementProviderFactory.java (revision e704ad812feb0fa447e5bd63332f753ac1a94b70) @@ -0,0 +1,25 @@ +/* + * Copyright The WildFly Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package org.wildfly.extension.undertow.session; + +import org.jboss.as.server.deployment.DeploymentUnit; +import org.jboss.metadata.web.jboss.ReplicationConfig; +import org.wildfly.clustering.web.container.SessionManagementProvider; + +/** + * Returns the appropriate {@link SessionManagementProvider} for the given deployment unit. + * @author Paul Ferraro + */ +public interface SessionManagementProviderFactory { + /** + * Returns the appropriate {@link SessionManagementProvider} for the specified deployment unit, + * generated from the specified {@link ReplicationConfig} if necessary. + * @param unit a deployment unit + * @param config a legacy {@link ReplicationConfig} + * @return a session management provider + */ + SessionManagementProvider createSessionManagementProvider(DeploymentUnit unit, ReplicationConfig config); +} Index: 3rdParty_sources/undertow/org/wildfly/extension/undertow/session/SessionManagerFactoryServiceConfigurator.java =================================================================== diff -u --- 3rdParty_sources/undertow/org/wildfly/extension/undertow/session/SessionManagerFactoryServiceConfigurator.java (revision 0) +++ 3rdParty_sources/undertow/org/wildfly/extension/undertow/session/SessionManagerFactoryServiceConfigurator.java (revision e704ad812feb0fa447e5bd63332f753ac1a94b70) @@ -0,0 +1,39 @@ +/* + * Copyright The WildFly Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package org.wildfly.extension.undertow.session; + +import java.util.function.Consumer; +import java.util.function.Supplier; + +import org.jboss.as.clustering.controller.CapabilityServiceConfigurator; +import org.jboss.msc.Service; +import org.jboss.msc.service.ServiceBuilder; +import org.jboss.msc.service.ServiceName; +import org.jboss.msc.service.ServiceTarget; +import org.wildfly.clustering.service.SimpleServiceNameProvider; + +import io.undertow.servlet.api.SessionManagerFactory; + +/** + * Configures a service providing a {@link SessionManagerFactory}. + * @author Paul Ferraro + */ +public class SessionManagerFactoryServiceConfigurator extends SimpleServiceNameProvider implements CapabilityServiceConfigurator { + + private final Supplier provider; + + public SessionManagerFactoryServiceConfigurator(ServiceName name, Supplier provider) { + super(name); + this.provider = provider; + } + + @Override + public ServiceBuilder build(ServiceTarget target) { + ServiceBuilder builder = target.addService(this.getServiceName()); + Consumer injector = builder.provides(this.getServiceName()); + return builder.setInstance(Service.newInstance(injector, this.provider.get())); + } +} Index: 3rdParty_sources/undertow/org/wildfly/extension/undertow/session/SharedSessionConfigParser.java =================================================================== diff -u --- 3rdParty_sources/undertow/org/wildfly/extension/undertow/session/SharedSessionConfigParser.java (revision 0) +++ 3rdParty_sources/undertow/org/wildfly/extension/undertow/session/SharedSessionConfigParser.java (revision e704ad812feb0fa447e5bd63332f753ac1a94b70) @@ -0,0 +1,42 @@ +/* + * Copyright The WildFly Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package org.wildfly.extension.undertow.session; + +import org.jboss.as.ee.structure.JBossDescriptorPropertyReplacement; +import org.jboss.as.server.deployment.DeploymentUnit; +import org.jboss.as.server.deployment.jbossallxml.JBossAllXMLParser; +import org.jboss.as.web.session.SharedSessionManagerConfig; +import org.jboss.metadata.property.PropertyReplacer; +import org.jboss.staxmapper.XMLExtendedStreamReader; +import org.wildfly.extension.undertow.logging.UndertowLogger; + +import javax.xml.stream.XMLStreamException; + +/** + * Parse shared session manager config + * + * @author Stuart Douglas + */ +public class SharedSessionConfigParser implements JBossAllXMLParser { + + private final SharedSessionConfigSchema schema; + + public SharedSessionConfigParser(SharedSessionConfigSchema schema) { + this.schema = schema; + } + + @Override + public SharedSessionManagerConfig parse(XMLExtendedStreamReader reader, DeploymentUnit unit) throws XMLStreamException { + if (unit.getParent() != null) { + UndertowLogger.ROOT_LOGGER.sharedSessionConfigNotInRootDeployment(unit.getName()); + return null; + } + PropertyReplacer replacer = JBossDescriptorPropertyReplacement.propertyReplacer(unit); + SharedSessionManagerConfig result = new SharedSessionManagerConfig(); + new SharedSessionConfigXMLReader(this.schema, replacer).readElement(reader, result); + return result; + } +} Index: 3rdParty_sources/undertow/org/wildfly/extension/undertow/session/SharedSessionConfigSchema.java =================================================================== diff -u --- 3rdParty_sources/undertow/org/wildfly/extension/undertow/session/SharedSessionConfigSchema.java (revision 0) +++ 3rdParty_sources/undertow/org/wildfly/extension/undertow/session/SharedSessionConfigSchema.java (revision e704ad812feb0fa447e5bd63332f753ac1a94b70) @@ -0,0 +1,47 @@ +/* + * Copyright The WildFly Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package org.wildfly.extension.undertow.session; + +import java.util.List; + +import javax.xml.stream.XMLStreamException; + +import org.jboss.as.controller.xml.IntVersionSchema; +import org.jboss.as.controller.xml.VersionedNamespace; +import org.jboss.as.server.deployment.DeploymentUnit; +import org.jboss.as.server.deployment.jbossallxml.JBossAllSchema; +import org.jboss.as.web.session.SharedSessionManagerConfig; +import org.jboss.staxmapper.IntVersion; +import org.jboss.staxmapper.XMLExtendedStreamReader; + +/** + * @author Paul Ferraro + */ +public enum SharedSessionConfigSchema implements JBossAllSchema { + VERSION_1_0(1, 0), + VERSION_2_0(2, 0), + ; + private final VersionedNamespace namespace; + + SharedSessionConfigSchema(int major, int minor) { + this.namespace = IntVersionSchema.createURN(List.of(IntVersionSchema.JBOSS_IDENTIFIER, this.getLocalName()), new IntVersion(major, minor)); + } + + @Override + public String getLocalName() { + return "shared-session-config"; + } + + @Override + public VersionedNamespace getNamespace() { + return this.namespace; + } + + @Override + public SharedSessionManagerConfig parse(XMLExtendedStreamReader reader, DeploymentUnit unit) throws XMLStreamException { + return new SharedSessionConfigParser(this).parse(reader, unit); + } +} Index: 3rdParty_sources/undertow/org/wildfly/extension/undertow/session/SharedSessionConfigXMLReader.java =================================================================== diff -u --- 3rdParty_sources/undertow/org/wildfly/extension/undertow/session/SharedSessionConfigXMLReader.java (revision 0) +++ 3rdParty_sources/undertow/org/wildfly/extension/undertow/session/SharedSessionConfigXMLReader.java (revision e704ad812feb0fa447e5bd63332f753ac1a94b70) @@ -0,0 +1,77 @@ +/* + * Copyright The WildFly Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package org.wildfly.extension.undertow.session; + +import javax.xml.stream.XMLStreamConstants; +import javax.xml.stream.XMLStreamException; + +import org.jboss.as.controller.parsing.ParseUtils; +import org.jboss.as.web.session.SharedSessionManagerConfig; +import org.jboss.metadata.parser.jbossweb.ReplicationConfigParser; +import org.jboss.metadata.parser.servlet.SessionConfigMetaDataParser; +import org.jboss.metadata.property.PropertyReplacer; +import org.jboss.staxmapper.XMLElementReader; +import org.jboss.staxmapper.XMLExtendedStreamReader; + +/** + * @author Paul Ferraro + */ +public class SharedSessionConfigXMLReader implements XMLElementReader { + + private final SharedSessionConfigSchema schema; + private final PropertyReplacer replacer; + + public SharedSessionConfigXMLReader(SharedSessionConfigSchema schema, PropertyReplacer replacer) { + this.schema = schema; + this.replacer = replacer; + } + + @SuppressWarnings("deprecation") + @Override + public void readElement(XMLExtendedStreamReader reader, SharedSessionManagerConfig result) throws XMLStreamException { + + ParseUtils.requireNoAttributes(reader); + + if (!this.schema.since(SharedSessionConfigSchema.VERSION_2_0)) { + // Prior to 2.0, shared session manager was distributable by default + result.setDistributable(true); + } + + while (reader.hasNext() && reader.nextTag() != XMLStreamConstants.END_ELEMENT) { + switch (reader.getLocalName()) { + case "max-active-sessions": { + int value = Integer.parseInt(this.replacer.replaceProperties(reader.getElementText())); + if (value > 0) { + result.setMaxActiveSessions(value); + } + break; + } + case "replication-config": { + if (this.schema.since(SharedSessionConfigSchema.VERSION_2_0)) { + throw ParseUtils.unexpectedElement(reader); + } + result.setReplicationConfig(ReplicationConfigParser.parse(reader, this.replacer)); + break; + } + case "session-config": { + result.setSessionConfig(SessionConfigMetaDataParser.parse(reader, this.replacer)); + break; + } + case "distributable": { + if (this.schema.since(SharedSessionConfigSchema.VERSION_2_0)) { + ParseUtils.requireNoAttributes(reader); + ParseUtils.requireNoContent(reader); + result.setDistributable(true); + break; + } + } + default: { + throw ParseUtils.unexpectedElement(reader); + } + } + } + } +} Index: 3rdParty_sources/undertow/org/wildfly/extension/undertow/session/SimpleAffinityLocatorServiceConfigurator.java =================================================================== diff -u --- 3rdParty_sources/undertow/org/wildfly/extension/undertow/session/SimpleAffinityLocatorServiceConfigurator.java (revision 0) +++ 3rdParty_sources/undertow/org/wildfly/extension/undertow/session/SimpleAffinityLocatorServiceConfigurator.java (revision e704ad812feb0fa447e5bd63332f753ac1a94b70) @@ -0,0 +1,62 @@ +/* + * Copyright The WildFly Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package org.wildfly.extension.undertow.session; + +import java.util.function.Consumer; +import java.util.function.Function; + +import org.jboss.as.clustering.controller.CapabilityServiceConfigurator; +import org.jboss.as.controller.capability.CapabilityServiceSupport; +import org.jboss.as.web.session.AffinityLocator; +import org.jboss.as.web.session.SimpleAffinityLocator; +import org.jboss.msc.Service; +import org.jboss.msc.service.ServiceBuilder; +import org.jboss.msc.service.ServiceController; +import org.jboss.msc.service.ServiceName; +import org.jboss.msc.service.ServiceTarget; +import org.wildfly.clustering.service.FunctionalService; +import org.wildfly.clustering.service.ServiceConfigurator; +import org.wildfly.clustering.service.ServiceSupplierDependency; +import org.wildfly.clustering.service.SimpleServiceNameProvider; +import org.wildfly.clustering.service.SupplierDependency; +import org.wildfly.extension.undertow.Capabilities; +import org.wildfly.extension.undertow.Server; + +/** + * Configures a {@link Service} providing a non-distributable {@link AffinityLocator} implementation. + * + * @author Radoslav Husar + */ +class SimpleAffinityLocatorServiceConfigurator extends SimpleServiceNameProvider implements CapabilityServiceConfigurator, Function { + + private final String serverName; + + private volatile SupplierDependency server; + + public SimpleAffinityLocatorServiceConfigurator(ServiceName name, String serverName) { + super(name); + this.serverName = serverName; + } + + @Override + public AffinityLocator apply(Server server) { + return new SimpleAffinityLocator(server.getRoute()); + } + + @Override + public ServiceConfigurator configure(CapabilityServiceSupport support) { + this.server = new ServiceSupplierDependency<>(support.getCapabilityServiceName(Capabilities.CAPABILITY_SERVER, this.serverName)); + return this; + } + + @Override + public ServiceBuilder build(ServiceTarget target) { + ServiceBuilder builder = target.addService(this.getServiceName()); + Consumer locator = this.server.register(builder).provides(this.getServiceName()); + Service service = new FunctionalService<>(locator, this, this.server); + return builder.setInstance(service).setInitialMode(ServiceController.Mode.ON_DEMAND); + } +} Fisheye: Tag 0c9c83107d623392869f43619926ea6d8ec5beab refers to a dead (removed) revision in file `3rdParty_sources/undertow/org/wildfly/extension/undertow/session/SimpleSessionIdentifierCodecServiceConfigurator.java'. Fisheye: No comparison available. Pass `N' to diff? Index: 3rdParty_sources/undertow/org/wildfly/extension/undertow/sso/elytron/DefaultSingleSignOnManagerServiceConfigurator.java =================================================================== diff -u --- 3rdParty_sources/undertow/org/wildfly/extension/undertow/sso/elytron/DefaultSingleSignOnManagerServiceConfigurator.java (revision 0) +++ 3rdParty_sources/undertow/org/wildfly/extension/undertow/sso/elytron/DefaultSingleSignOnManagerServiceConfigurator.java (revision e704ad812feb0fa447e5bd63332f753ac1a94b70) @@ -0,0 +1,25 @@ +/* + * Copyright The WildFly Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package org.wildfly.extension.undertow.sso.elytron; + +import java.util.concurrent.ConcurrentHashMap; + +import org.jboss.as.clustering.controller.SimpleCapabilityServiceConfigurator; +import org.jboss.msc.service.ServiceName; +import org.wildfly.clustering.web.container.SecurityDomainSingleSignOnManagementConfiguration; +import org.wildfly.security.http.util.sso.DefaultSingleSignOnManager; +import org.wildfly.security.http.util.sso.SingleSignOnManager; + +/** + * Configures a srevice providing a non-distributable {@link SingleSignOnManager}. + * @author Paul Ferraro + */ +public class DefaultSingleSignOnManagerServiceConfigurator extends SimpleCapabilityServiceConfigurator { + + public DefaultSingleSignOnManagerServiceConfigurator(ServiceName name, SecurityDomainSingleSignOnManagementConfiguration configuration) { + super(name, new DefaultSingleSignOnManager(new ConcurrentHashMap<>(), configuration.getIdentifierGenerator())); + } +} Index: 3rdParty_sources/undertow/org/wildfly/extension/undertow/sso/elytron/NonDistributableSingleSignOnManagementProvider.java =================================================================== diff -u --- 3rdParty_sources/undertow/org/wildfly/extension/undertow/sso/elytron/NonDistributableSingleSignOnManagementProvider.java (revision 0) +++ 3rdParty_sources/undertow/org/wildfly/extension/undertow/sso/elytron/NonDistributableSingleSignOnManagementProvider.java (revision e704ad812feb0fa447e5bd63332f753ac1a94b70) @@ -0,0 +1,24 @@ +/* + * Copyright The WildFly Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package org.wildfly.extension.undertow.sso.elytron; + +import org.jboss.as.clustering.controller.CapabilityServiceConfigurator; +import org.jboss.msc.service.ServiceName; +import org.wildfly.clustering.web.container.SecurityDomainSingleSignOnManagementConfiguration; +import org.wildfly.clustering.web.container.SecurityDomainSingleSignOnManagementProvider; + +/** + * Singleton reference to a non-distributable {@link SecurityDomainSingleSignOnManagementProvider}. + * @author Paul Ferraro + */ +public enum NonDistributableSingleSignOnManagementProvider implements SecurityDomainSingleSignOnManagementProvider { + INSTANCE; + + @Override + public CapabilityServiceConfigurator getServiceConfigurator(ServiceName name, SecurityDomainSingleSignOnManagementConfiguration configuration) { + return new DefaultSingleSignOnManagerServiceConfigurator(name, configuration); + } +} Index: 3rdParty_sources/undertow/org/wildfly/extension/undertow/sso/elytron/SingleSignOnIdentifierFactory.java =================================================================== diff -u --- 3rdParty_sources/undertow/org/wildfly/extension/undertow/sso/elytron/SingleSignOnIdentifierFactory.java (revision 0) +++ 3rdParty_sources/undertow/org/wildfly/extension/undertow/sso/elytron/SingleSignOnIdentifierFactory.java (revision e704ad812feb0fa447e5bd63332f753ac1a94b70) @@ -0,0 +1,33 @@ +/* + * Copyright The WildFly Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package org.wildfly.extension.undertow.sso.elytron; + +import java.util.function.Supplier; + +import io.undertow.server.session.SecureRandomSessionIdGenerator; +import io.undertow.server.session.SessionIdGenerator; + +/** + * Adapts a {@link SessionIdGenerator} to {@link Supplier}. + * @author Paul Ferraro + */ +public class SingleSignOnIdentifierFactory implements Supplier { + + private final SessionIdGenerator generator; + + public SingleSignOnIdentifierFactory() { + this(new SecureRandomSessionIdGenerator()); + } + + public SingleSignOnIdentifierFactory(SessionIdGenerator generator) { + this.generator = generator; + } + + @Override + public String get() { + return this.generator.createSessionId(); + } +}